diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..13f73b4b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,17 @@ +.git +!.git/HEAD +!.git/logs/HEAD +baystation12.dmb +baystation12.rsc +baystation12.dyn.rsc +baystation12.dyn.rsc.lk +baystation12.int +libmysql.dll +.dockerignore +Dockerfile +.editorconfig +.gitattributes +.gitignore +.travis.yml +.github +sql \ No newline at end of file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..ad578927 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,22 @@ +root = true + +[*] +insert_final_newline = false +trim_trailing_whitespace = true + +[*.dm] +end_of_line = crlf +indent_style = tab +indent_size = 4 + +[*.dmm] +end_of_line = crlf + +[*.py] +indent_style = space +indent_size = 4 + +[*.yml] +indent_style = space +indent_size = 2 + diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..add01d67 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,14 @@ +# dmm map merger hook +# needs additional setup, see tools/mapmerge/install.txt +*.dmm merge=merge-dmm + +# dmi icon merger hook +# needs additional setup, see tools/dmitool/merging.txt +*.dmi merge=merge-dmi + +# force changelog merging to use union +html/changelog.html merge=union + +# Declare files that will always have CRLF line endings on checkout. +*.dm text eol=crlf +*.dmm text eol=crlf diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..0725370f --- /dev/null +++ b/.gitignore @@ -0,0 +1,46 @@ +#ignore misc BYOND files +Thumbs.db +*.log +*.int +*.rsc +*.dmb +*.lk +*.backup +*.before +data/ +cfg/ +build_log.txt +use_map +stopserver +reboot_called +atupdate +__pycache__ + +# ignore config, but not subdirs +!config/*/ +config/* +sql/test_db +.vscode/tasks.json +.vscode/settings.json +tools/dmitool/.classpath +tools/dmitool/.project +tools/dmitool/.gradle/5.6.1/gc.properties +tools/dmitool/.gradle/5.6.1/executionHistory/executionHistory.lock +tools/dmitool/.gradle/5.6.1/fileChanges/last-build.bin +tools/dmitool/.gradle/5.6.1/fileHashes/fileHashes.lock +tools/dmitool/.gradle/buildOutputCleanup/buildOutputCleanup.lock +tools/dmitool/.gradle/buildOutputCleanup/cache.properties +tools/dmitool/.gradle/vcs-1/gc.properties +tools/dmitool/.settings/org.eclipse.buildship.core.prefs +tools/dmitool/bin/main/dmitool/DMI.class +tools/dmitool/bin/main/dmitool/DMIDiff.class +tools/dmitool/bin/main/dmitool/DMIException.class +tools/dmitool/bin/main/dmitool/IconState.class +tools/dmitool/bin/main/dmitool/IconStateDiff$ISAddress.class +tools/dmitool/bin/main/dmitool/IconStateDiff.class +tools/dmitool/bin/main/dmitool/Image.class +tools/dmitool/bin/main/dmitool/Main.class +tools/dmitool/bin/main/dmitool/NonPalettedImage.class +tools/dmitool/bin/main/dmitool/PalettedImage.class +tools/dmitool/bin/main/dmitool/PNGChunk.class +tools/dmitool/bin/main/dmitool/RGBA.class diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..d620523a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,30 @@ +language: generic +sudo: false +dist: precise + +env: + global: + - BYOND_MAJOR="513" + - BYOND_MINOR="1511" + - DM_BUILDFILE="IS12Warfare.dme" + - SPACEMAN_DMM_VERSION=suite-1.4 + +matrix: + include: + - name: "Compile" + addons: + apt: + packages: + - libc6-i386 + - libgcc1:i386 + - libstdc++6:i386 + cache: + directories: + - $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR} + install: + - chmod +x ./install-byond.sh + - ./install-byond.sh + script: + - (! grep -rn 'step_[xy]' maps) + - source $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}/byond/bin/byondsetup + - bash dm.sh ${DM_BUILDFILE} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..d0322027 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,30 @@ +FROM ubuntu:latest + +RUN mkdir /bs12 + +RUN dpkg --add-architecture i386 + +RUN apt-get update + +RUN apt-get install -y unzip make wget libmariadb2:i386 + +RUN apt-get install -y libc6:i386 libstdc++6:i386 + +# we are not using ADD here to download it because this file should never change +# and thus, strictly caching it is okay +RUN cd /bs12/ && wget -q https://www.byond.com/download/build/511/511.1385_byond_linux.zip + +RUN cd /bs12/ && unzip -q 511.1385_byond_linux.zip + +COPY . /bs12/Baystation12 + +RUN /bin/bash -c '\ +cd /bs12/byond; \ +make here >/dev/null; \ +source bin/byondsetup; \ +cd ../Baystation12; \ +ln -s /usr/lib/i386-linux-gnu/libmariadb.so.2 libmariadb.so; \ +DreamMaker baystation12.dme; \ +' + +ENTRYPOINT cd /bs12/Baystation12 && . /bs12/byond/bin/byondsetup && DreamDaemon baystation12.dmb 8000 -invisible -trusted \ No newline at end of file diff --git a/IS12Warfare.dme b/IS12Warfare.dme new file mode 100644 index 00000000..b6418869 --- /dev/null +++ b/IS12Warfare.dme @@ -0,0 +1,2463 @@ +// DM Environment file for interstation12.dme. +// All manual changes should be made outside the BEGIN_ and END_ blocks. + // New source code should be placed in .dm files: choose File/New --> Code File. +// BEGIN_INTERNALS +// END_INTERNALS +// BEGIN_FILE_DIR +#define FILE_DIR . +// END_FILE_DIR +// BEGIN_PREFERENCES +#define DEBUG +// END_PREFERENCES +// BEGIN_INCLUDE +#include "code\_macros.dm" +#include "code\client_macros.dm" +#include "code\hub.dm" +#include "code\stylesheet.dm" +#include "code\world.dm" +#include "code\__datastructures\globals.dm" +#include "code\__datastructures\priority_queue.dm" +#include "code\__datastructures\stack.dm" +#include "code\__defines\_compile_options.dm" +#include "code\__defines\_planes+layers.dm" +#include "code\__defines\_tick.dm" +#include "code\__defines\admin.dm" +#include "code\__defines\appearance.dm" +#include "code\__defines\atmos.dm" +#include "code\__defines\atmospherics.dm" +#include "code\__defines\callback.dm" +#include "code\__defines\chemistry.dm" +#include "code\__defines\client.dm" +#include "code\__defines\colors.dm" +#include "code\__defines\components.dm" +#include "code\__defines\damage_organs.dm" +#include "code\__defines\deity.dm" +#include "code\__defines\dna.dm" +#include "code\__defines\feedback.dm" +#include "code\__defines\flags.dm" +#include "code\__defines\gamemode.dm" +#include "code\__defines\inventory_sizes.dm" +#include "code\__defines\items_clothing.dm" +#include "code\__defines\kaos.dm" +#include "code\__defines\languages.dm" +#include "code\__defines\lighting.dm" +#include "code\__defines\machinery.dm" +#include "code\__defines\mapping.dm" +#include "code\__defines\materials.dm" +#include "code\__defines\math_physics.dm" +#include "code\__defines\MC.dm" +#include "code\__defines\misc.dm" +#include "code\__defines\mobs.dm" +#include "code\__defines\proc_presets.dm" +#include "code\__defines\process_scheduler.dm" +#include "code\__defines\qdel.dm" +#include "code\__defines\research.dm" +#include "code\__defines\shields.dm" +#include "code\__defines\species.dm" +#include "code\__defines\subsystem-priority.dm" +#include "code\__defines\subsystems.dm" +#include "code\__defines\targeting.dm" +#include "code\__defines\tgui.dm" +#include "code\__defines\topic.dm" +#include "code\__defines\turfs.dm" +#include "code\__defines\xenoarcheaology.dm" +#include "code\__defines\ZAS.dm" +#include "code\_global_vars\configuration.dm" +#include "code\_global_vars\logging.dm" +#include "code\_global_vars\mapping.dm" +#include "code\_global_vars\misc.dm" +#include "code\_global_vars\mobs.dm" +#include "code\_global_vars\radio.dm" +#include "code\_global_vars\sensitive.dm" +#include "code\_global_vars\lists\flavor.dm" +#include "code\_global_vars\lists\locations.dm" +#include "code\_global_vars\lists\logs.dm" +#include "code\_global_vars\lists\mapping.dm" +#include "code\_global_vars\lists\names.dm" +#include "code\_global_vars\lists\objects.dm" +#include "code\_helpers\_global_objects.dm" +#include "code\_helpers\areas.dm" +#include "code\_helpers\atmospherics.dm" +#include "code\_helpers\atom_movables.dm" +#include "code\_helpers\builtin_proc_callers.dm" +#include "code\_helpers\cmp.dm" +#include "code\_helpers\files.dm" +#include "code\_helpers\functional.dm" +#include "code\_helpers\game.dm" +#include "code\_helpers\global_access.dm" +#include "code\_helpers\global_lists.dm" +#include "code\_helpers\icons.dm" +#include "code\_helpers\lists.dm" +#include "code\_helpers\logging.dm" +#include "code\_helpers\maths.dm" +#include "code\_helpers\matrices.dm" +#include "code\_helpers\mobs.dm" +#include "code\_helpers\names.dm" +#include "code\_helpers\russian.dm" +#include "code\_helpers\sanitize_values.dm" +#include "code\_helpers\spawn_sync.dm" +#include "code\_helpers\storage.dm" +#include "code\_helpers\text.dm" +#include "code\_helpers\time.dm" +#include "code\_helpers\turfs.dm" +#include "code\_helpers\type2type.dm" +#include "code\_helpers\unsorted.dm" +#include "code\_helpers\vector.dm" +#include "code\_helpers\sorts\__main.dm" +#include "code\_helpers\sorts\TimSort.dm" +#include "code\_onclick\adjacent.dm" +#include "code\_onclick\ai.dm" +#include "code\_onclick\click.dm" +#include "code\_onclick\cyborg.dm" +#include "code\_onclick\drag_drop.dm" +#include "code\_onclick\ghost.dm" +#include "code\_onclick\item_attack.dm" +#include "code\_onclick\other_mobs.dm" +#include "code\_onclick\telekinesis.dm" +#include "code\_onclick\hud\_defines.dm" +#include "code\_onclick\hud\ability_screen_objects.dm" +#include "code\_onclick\hud\action.dm" +#include "code\_onclick\hud\alien_larva.dm" +#include "code\_onclick\hud\fullscreen.dm" +#include "code\_onclick\hud\global_hud.dm" +#include "code\_onclick\hud\gun_mode.dm" +#include "code\_onclick\hud\hud.dm" +#include "code\_onclick\hud\human.dm" +#include "code\_onclick\hud\movable_screen_objects.dm" +#include "code\_onclick\hud\other_mobs.dm" +#include "code\_onclick\hud\robot.dm" +#include "code\_onclick\hud\screen_objects.dm" +#include "code\_onclick\hud\skybox.dm" +#include "code\controllers\admin.dm" +#include "code\controllers\autotransfer.dm" +#include "code\controllers\communications.dm" +#include "code\controllers\configuration.dm" +#include "code\controllers\controller.dm" +#include "code\controllers\failsafe.dm" +#include "code\controllers\globals.dm" +#include "code\controllers\hooks-defs.dm" +#include "code\controllers\hooks.dm" +#include "code\controllers\master.dm" +#include "code\controllers\master_controller.dm" +#include "code\controllers\shuttle_controller.dm" +#include "code\controllers\subsystem.dm" +#include "code\controllers\verbs.dm" +#include "code\controllers\voting.dm" +#include "code\controllers\evacuation\evacuation.dm" +#include "code\controllers\evacuation\evacuation_eta.dm" +#include "code\controllers\evacuation\evacuation_helpers.dm" +#include "code\controllers\evacuation\evacuation_lifepods.dm" +#include "code\controllers\evacuation\evacuation_option.dm" +#include "code\controllers\evacuation\evacuation_pods.dm" +#include "code\controllers\evacuation\evacuation_predicate.dm" +#include "code\controllers\evacuation\evacuation_shuttle.dm" +#include "code\controllers\evacuation\~evac.dm" +#include "code\controllers\Processes\alarm.dm" +#include "code\controllers\Processes\emergencyShuttle.dm" +#include "code\controllers\Processes\event.dm" +#include "code\controllers\Processes\inactivity.dm" +#include "code\controllers\Processes\lighting.dm" +#include "code\controllers\Processes\nanoui.dm" +#include "code\controllers\Processes\radiation.dm" +#include "code\controllers\Processes\Shuttle.dm" +#include "code\controllers\Processes\supply.dm" +#include "code\controllers\Processes\tgui.dm" +#include "code\controllers\Processes\ticker.dm" +#include "code\controllers\Processes\timer.dm" +#include "code\controllers\Processes\trade.dm" +#include "code\controllers\Processes\turf.dm" +#include "code\controllers\Processes\vote.dm" +#include "code\controllers\ProcessScheduler\core\process.dm" +#include "code\controllers\ProcessScheduler\core\processScheduler.dm" +#include "code\controllers\subsystems\air.dm" +#include "code\controllers\subsystems\aspects.dm" +#include "code\controllers\subsystems\atoms.dm" +#include "code\controllers\subsystems\chat.dm" +#include "code\controllers\subsystems\garbage.dm" +#include "code\controllers\subsystems\legacy.dm" +#include "code\controllers\subsystems\machines.dm" +#include "code\controllers\subsystems\mapping.dm" +#include "code\controllers\subsystems\open_space.dm" +#include "code\controllers\subsystems\overlays.dm" +#include "code\controllers\subsystems\ping.dm" +#include "code\controllers\subsystems\skybox.dm" +#include "code\controllers\subsystems\sun.dm" +#include "code\controllers\subsystems\warfare.dm" +#include "code\controllers\subsystems\wireless.dm" +#include "code\controllers\subsystems\processing\airflow.dm" +#include "code\controllers\subsystems\processing\fast_process.dm" +#include "code\controllers\subsystems\processing\mobs.dm" +#include "code\controllers\subsystems\processing\obj.dm" +#include "code\controllers\subsystems\processing\processing.dm" +#include "code\controllers\subsystems\processing\projectiles.dm" +#include "code\controllers\subsystems\processing\vines.dm" +#include "code\datums\ai_law_sets.dm" +#include "code\datums\ai_laws.dm" +#include "code\datums\browser.dm" +#include "code\datums\callbacks.dm" +#include "code\datums\category.dm" +#include "code\datums\datum.dm" +#include "code\datums\hierarchy.dm" +#include "code\datums\mil_ranks.dm" +#include "code\datums\mind.dm" +#include "code\datums\position_point_vector.dm" +#include "code\datums\progressbar.dm" +#include "code\datums\recipe.dm" +#include "code\datums\ruins.dm" +#include "code\datums\security_state.dm" +#include "code\datums\shackle_law_sets.dm" +#include "code\datums\sound_player.dm" +#include "code\datums\suit_sensor_jammer_method.dm" +#include "code\datums\sun.dm" +#include "code\datums\weakref.dm" +#include "code\datums\ai\ai.dm" +#include "code\datums\ai\ai_holo.dm" +#include "code\datums\appearances\appearance_data.dm" +#include "code\datums\appearances\appearance_manager.dm" +#include "code\datums\appearances\automatic\_base.dm" +#include "code\datums\appearances\automatic\cardborg.dm" +#include "code\datums\colors\color_generator.dm" +#include "code\datums\communication\_defines.dm" +#include "code\datums\communication\channel.dm" +#include "code\datums\communication\dsay.dm" +#include "code\datums\communication\looc.dm" +#include "code\datums\communication\ooc.dm" +#include "code\datums\communication\pray.dm" +#include "code\datums\communication\~defines.dm" +#include "code\datums\extensions\_defines.dm" +#include "code\datums\extensions\extensions.dm" +#include "code\datums\extensions\interactive.dm" +#include "code\datums\extensions\label.dm" +#include "code\datums\extensions\appearance\appearance.dm" +#include "code\datums\extensions\appearance\base_icon_state.dm" +#include "code\datums\extensions\appearance\cardborg.dm" +#include "code\datums\extensions\multitool\_multitool.dm" +#include "code\datums\extensions\multitool\multitool.dm" +#include "code\datums\extensions\multitool\store.dm" +#include "code\datums\extensions\multitool\circuitboards\circuitboards.dm" +#include "code\datums\extensions\multitool\circuitboards\stationalert.dm" +#include "code\datums\extensions\multitool\items\cable.dm" +#include "code\datums\extensions\multitool\items\clothing.dm" +#include "code\datums\extensions\multitool\items\items.dm" +#include "code\datums\helper_datums\construction_datum.dm" +#include "code\datums\helper_datums\dist_check.dm" +#include "code\datums\helper_datums\events.dm" +#include "code\datums\helper_datums\getrev.dm" +#include "code\datums\helper_datums\global_iterator.dm" +#include "code\datums\helper_datums\teleport.dm" +#include "code\datums\helper_datums\topic_input.dm" +#include "code\datums\observation\_defines.dm" +#include "code\datums\observation\death.dm" +#include "code\datums\observation\density_set.dm" +#include "code\datums\observation\destroyed.dm" +#include "code\datums\observation\dir_set.dm" +#include "code\datums\observation\entered.dm" +#include "code\datums\observation\equipped.dm" +#include "code\datums\observation\exited.dm" +#include "code\datums\observation\helpers.dm" +#include "code\datums\observation\life.dm" +#include "code\datums\observation\logged_in.dm" +#include "code\datums\observation\logged_out.dm" +#include "code\datums\observation\moved.dm" +#include "code\datums\observation\name_set.dm" +#include "code\datums\observation\observation.dm" +#include "code\datums\observation\opacity_set.dm" +#include "code\datums\observation\see_in_dark_set.dm" +#include "code\datums\observation\see_invisible_set.dm" +#include "code\datums\observation\set_invisibility.dm" +#include "code\datums\observation\sight_set.dm" +#include "code\datums\observation\stat_set.dm" +#include "code\datums\observation\turf_changed.dm" +#include "code\datums\observation\unequipped.dm" +#include "code\datums\observation\~cleanup.dm" +#include "code\datums\outfits\_defines.dm" +#include "code\datums\outfits\horror_killers.dm" +#include "code\datums\outfits\misc.dm" +#include "code\datums\outfits\nanotrasen.dm" +#include "code\datums\outfits\outfit.dm" +#include "code\datums\outfits\pirates.dm" +#include "code\datums\outfits\spec_op.dm" +#include "code\datums\outfits\tournament.dm" +#include "code\datums\outfits\wizardry.dm" +#include "code\datums\outfits\equipment\backpacks.dm" +#include "code\datums\outfits\jobs\_defines.dm" +#include "code\datums\outfits\jobs\cargo.dm" +#include "code\datums\outfits\jobs\civilian.dm" +#include "code\datums\outfits\jobs\command.dm" +#include "code\datums\outfits\jobs\engineering.dm" +#include "code\datums\outfits\jobs\job.dm" +#include "code\datums\outfits\jobs\medical.dm" +#include "code\datums\outfits\jobs\misc.dm" +#include "code\datums\outfits\jobs\science.dm" +#include "code\datums\outfits\jobs\security.dm" +#include "code\datums\proximity_trigger\proximity_trigger.dm" +#include "code\datums\proximity_trigger\turf_selection.dm" +#include "code\datums\repositories\_defines.dm" +#include "code\datums\repositories\admin_pm.dm" +#include "code\datums\repositories\areas.dm" +#include "code\datums\repositories\attack_logs.dm" +#include "code\datums\repositories\cameras.dm" +#include "code\datums\repositories\client.dm" +#include "code\datums\repositories\decls.dm" +#include "code\datums\repositories\follow.dm" +#include "code\datums\repositories\images.dm" +#include "code\datums\repositories\mobs.dm" +#include "code\datums\repositories\radiation.dm" +#include "code\datums\repositories\repository.dm" +#include "code\datums\repositories\unique.dm" +#include "code\datums\repositories\uplink_purchases.dm" +#include "code\datums\repositories\~defines.dm" +#include "code\datums\repositories\crew\_defines.dm" +#include "code\datums\repositories\crew\binary.dm" +#include "code\datums\repositories\crew\crew.dm" +#include "code\datums\repositories\crew\crew_sensor_modifier.dm" +#include "code\datums\repositories\crew\general.dm" +#include "code\datums\repositories\crew\tracking.dm" +#include "code\datums\repositories\crew\vital.dm" +#include "code\datums\repositories\crew\~defines.dm" +#include "code\datums\supplypacks\atmospherics.dm" +#include "code\datums\supplypacks\engineering.dm" +#include "code\datums\supplypacks\hospitality.dm" +#include "code\datums\supplypacks\hydroponics.dm" +#include "code\datums\supplypacks\materials.dm" +#include "code\datums\supplypacks\medical.dm" +#include "code\datums\supplypacks\miscellaneous.dm" +#include "code\datums\supplypacks\operations.dm" +#include "code\datums\supplypacks\science.dm" +#include "code\datums\supplypacks\security.dm" +#include "code\datums\supplypacks\supply.dm" +#include "code\datums\supplypacks\supplypack.dm" +#include "code\datums\trading\_trading_defines.dm" +#include "code\datums\trading\ai.dm" +#include "code\datums\trading\food.dm" +#include "code\datums\trading\goods.dm" +#include "code\datums\trading\misc.dm" +#include "code\datums\trading\ship.dm" +#include "code\datums\trading\trade.dm" +#include "code\datums\trading\unique.dm" +#include "code\datums\trading\vox.dm" +#include "code\datums\trading\weaponry.dm" +#include "code\datums\underwear\bottom.dm" +#include "code\datums\underwear\socks.dm" +#include "code\datums\underwear\top.dm" +#include "code\datums\underwear\undershirt.dm" +#include "code\datums\underwear\underwear.dm" +#include "code\datums\uplink\ammunition.dm" +#include "code\datums\uplink\badassery.dm" +#include "code\datums\uplink\devices and tools.dm" +#include "code\datums\uplink\grenades.dm" +#include "code\datums\uplink\highly_visible_and_dangerous_weapons.dm" +#include "code\datums\uplink\implants.dm" +#include "code\datums\uplink\medical.dm" +#include "code\datums\uplink\services.dm" +#include "code\datums\uplink\stealth_and_camouflage_items.dm" +#include "code\datums\uplink\stealthy_and_inconspicuous_weapons.dm" +#include "code\datums\uplink\telecrystals.dm" +#include "code\datums\uplink\uplink_categories.dm" +#include "code\datums\uplink\uplink_items.dm" +#include "code\datums\uplink\uplink_sources.dm" +#include "code\datums\vending\stored_item.dm" +#include "code\datums\vending\vending.dm" +#include "code\datums\wires\airlock.dm" +#include "code\datums\wires\alarm.dm" +#include "code\datums\wires\apc.dm" +#include "code\datums\wires\autolathe.dm" +#include "code\datums\wires\camera.dm" +#include "code\datums\wires\explosive.dm" +#include "code\datums\wires\nuclearbomb.dm" +#include "code\datums\wires\particle_accelerator.dm" +#include "code\datums\wires\radio.dm" +#include "code\datums\wires\robot.dm" +#include "code\datums\wires\shield_generator.dm" +#include "code\datums\wires\smartfridge.dm" +#include "code\datums\wires\smes.dm" +#include "code\datums\wires\suit_storage_unit.dm" +#include "code\datums\wires\vending.dm" +#include "code\datums\wires\wires.dm" +#include "code\game\atoms.dm" +#include "code\game\atoms_movable.dm" +#include "code\game\base_turf.dm" +#include "code\game\images.dm" +#include "code\game\periodic_news.dm" +#include "code\game\response_team.dm" +#include "code\game\shuttle_engines.dm" +#include "code\game\sound.dm" +#include "code\game\supplyshuttle.dm" +#include "code\game\world.dm" +#include "code\game\antagonist\_antagonist_setup.dm" +#include "code\game\antagonist\antagonist.dm" +#include "code\game\antagonist\antagonist_add.dm" +#include "code\game\antagonist\antagonist_create.dm" +#include "code\game\antagonist\antagonist_equip.dm" +#include "code\game\antagonist\antagonist_factions.dm" +#include "code\game\antagonist\antagonist_helpers.dm" +#include "code\game\antagonist\antagonist_objectives.dm" +#include "code\game\antagonist\antagonist_panel.dm" +#include "code\game\antagonist\antagonist_place.dm" +#include "code\game\antagonist\antagonist_print.dm" +#include "code\game\antagonist\antagonist_update.dm" +#include "code\game\antagonist\alien\borer.dm" +#include "code\game\antagonist\alien\xenomorph.dm" +#include "code\game\antagonist\outsider\actors.dm" +#include "code\game\antagonist\outsider\commando.dm" +#include "code\game\antagonist\outsider\deathsquad.dm" +#include "code\game\antagonist\outsider\ert.dm" +#include "code\game\antagonist\outsider\mercenary.dm" +#include "code\game\antagonist\outsider\raider.dm" +#include "code\game\antagonist\outsider\wizard.dm" +#include "code\game\antagonist\station\changeling.dm" +#include "code\game\antagonist\station\cultist.dm" +#include "code\game\antagonist\station\loyalist.dm" +#include "code\game\antagonist\station\renegade.dm" +#include "code\game\antagonist\station\revolutionary.dm" +#include "code\game\antagonist\station\rogue_ai.dm" +#include "code\game\antagonist\station\traitor.dm" +#include "code\game\area\areas.dm" +#include "code\game\area\Space Station 13 areas.dm" +#include "code\game\dna\dna2.dm" +#include "code\game\dna\dna2_domutcheck.dm" +#include "code\game\dna\dna2_helpers.dm" +#include "code\game\dna\genes\disabilities.dm" +#include "code\game\dna\genes\gene.dm" +#include "code\game\dna\genes\powers.dm" +#include "code\game\gamemodes\events.dm" +#include "code\game\gamemodes\game_mode.dm" +#include "code\game\gamemodes\game_mode_latespawn.dm" +#include "code\game\gamemodes\gameticker.dm" +#include "code\game\gamemodes\objective.dm" +#include "code\game\gamemodes\setupgame.dm" +#include "code\game\gamemodes\calamity\calamity.dm" +#include "code\game\gamemodes\changeling\absorbed_dna.dm" +#include "code\game\gamemodes\changeling\changeling.dm" +#include "code\game\gamemodes\changeling\changeling_powers.dm" +#include "code\game\gamemodes\changeling\modularchangling.dm" +#include "code\game\gamemodes\cult\cult.dm" +#include "code\game\gamemodes\cult\cult_items.dm" +#include "code\game\gamemodes\cult\cult_structures.dm" +#include "code\game\gamemodes\cult\ghosts.dm" +#include "code\game\gamemodes\cult\hell_universe.dm" +#include "code\game\gamemodes\cult\manifest.dm" +#include "code\game\gamemodes\cult\narsie.dm" +#include "code\game\gamemodes\cult\ritual.dm" +#include "code\game\gamemodes\cult\runes.dm" +#include "code\game\gamemodes\cult\talisman.dm" +#include "code\game\gamemodes\cult\cultify\de-cultify.dm" +#include "code\game\gamemodes\cult\cultify\mob.dm" +#include "code\game\gamemodes\cult\cultify\turf.dm" +#include "code\game\gamemodes\endgame\endgame.dm" +#include "code\game\gamemodes\endgame\bluespace_jump\bluespace_jump.dm" +#include "code\game\gamemodes\endgame\nuclear_explosion\nuclear_explosion.dm" +#include "code\game\gamemodes\endgame\supermatter_cascade\blob.dm" +#include "code\game\gamemodes\endgame\supermatter_cascade\portal.dm" +#include "code\game\gamemodes\endgame\supermatter_cascade\universe.dm" +#include "code\game\gamemodes\events\black_hole.dm" +#include "code\game\gamemodes\events\clang.dm" +#include "code\game\gamemodes\events\power_failure.dm" +#include "code\game\gamemodes\events\wormholes.dm" +#include "code\game\gamemodes\events\holidays\Christmas.dm" +#include "code\game\gamemodes\events\holidays\Holidays.dm" +#include "code\game\gamemodes\events\holidays\Other.dm" +#include "code\game\gamemodes\extended\extended.dm" +#include "code\game\gamemodes\heist\heist.dm" +#include "code\game\gamemodes\malfunction\malf_hardware.dm" +#include "code\game\gamemodes\malfunction\malf_research.dm" +#include "code\game\gamemodes\malfunction\malf_research_ability.dm" +#include "code\game\gamemodes\malfunction\malfunction.dm" +#include "code\game\gamemodes\malfunction\newmalf_ability_trees\HARDWARE.dm" +#include "code\game\gamemodes\malfunction\newmalf_ability_trees\HELPERS.dm" +#include "code\game\gamemodes\malfunction\newmalf_ability_trees\tree_interdiction.dm" +#include "code\game\gamemodes\malfunction\newmalf_ability_trees\tree_manipulation.dm" +#include "code\game\gamemodes\malfunction\newmalf_ability_trees\tree_networking.dm" +#include "code\game\gamemodes\malfunction\newmalf_ability_trees\tree_passive.dm" +#include "code\game\gamemodes\meteor\meteor.dm" +#include "code\game\gamemodes\meteor\meteors.dm" +#include "code\game\gamemodes\mixed\bughunt.dm" +#include "code\game\gamemodes\mixed\conflux.dm" +#include "code\game\gamemodes\mixed\crossfire.dm" +#include "code\game\gamemodes\mixed\infestation.dm" +#include "code\game\gamemodes\mixed\lizard.dm" +#include "code\game\gamemodes\mixed\paranoia.dm" +#include "code\game\gamemodes\mixed\siege.dm" +#include "code\game\gamemodes\mixed\traitorling.dm" +#include "code\game\gamemodes\mixed\unity.dm" +#include "code\game\gamemodes\mixed\uprising.dm" +#include "code\game\gamemodes\nuclear\nuclear.dm" +#include "code\game\gamemodes\nuclear\pinpointer.dm" +#include "code\game\gamemodes\revolution\revolution.dm" +#include "code\game\gamemodes\traitor\traitor.dm" +#include "code\game\gamemodes\warfare\barricade.dm" +#include "code\game\gamemodes\warfare\flare.dm" +#include "code\game\gamemodes\warfare\language.dm" +#include "code\game\gamemodes\warfare\lighting_dummy.dm" +#include "code\game\gamemodes\warfare\structures.dm" +#include "code\game\gamemodes\warfare\trenches.dm" +#include "code\game\gamemodes\warfare\turfs.dm" +#include "code\game\gamemodes\warfare\warfare.dm" +#include "code\game\gamemodes\warfare\warfare_gas.dm" +#include "code\game\gamemodes\wizard\wizard.dm" +#include "code\game\jobs\_access_defs.dm" +#include "code\game\jobs\access.dm" +#include "code\game\jobs\access_datum.dm" +#include "code\game\jobs\job_controller.dm" +#include "code\game\jobs\jobs.dm" +#include "code\game\jobs\whitelist.dm" +#include "code\game\jobs\job\assistant.dm" +#include "code\game\jobs\job\captain.dm" +#include "code\game\jobs\job\civilian.dm" +#include "code\game\jobs\job\civilian_chaplain.dm" +#include "code\game\jobs\job\engineering.dm" +#include "code\game\jobs\job\job.dm" +#include "code\game\jobs\job\medical.dm" +#include "code\game\jobs\job\science.dm" +#include "code\game\jobs\job\security.dm" +#include "code\game\jobs\job\silicon.dm" +#include "code\game\machinery\adv_med.dm" +#include "code\game\machinery\ai_slipper.dm" +#include "code\game\machinery\alarm.dm" +#include "code\game\machinery\atmo_control.dm" +#include "code\game\machinery\autolathe.dm" +#include "code\game\machinery\autolathe_datums.dm" +#include "code\game\machinery\Beacon.dm" +#include "code\game\machinery\biogenerator.dm" +#include "code\game\machinery\bioprinter.dm" +#include "code\game\machinery\bluespacerelay.dm" +#include "code\game\machinery\boombox.dm" +#include "code\game\machinery\buttons.dm" +#include "code\game\machinery\CableLayer.dm" +#include "code\game\machinery\cell_charger.dm" +#include "code\game\machinery\constructable_frame.dm" +#include "code\game\machinery\cryo.dm" +#include "code\game\machinery\cryopod.dm" +#include "code\game\machinery\deployable.dm" +#include "code\game\machinery\door_control.dm" +#include "code\game\machinery\doppler_array.dm" +#include "code\game\machinery\flasher.dm" +#include "code\game\machinery\floodlight.dm" +#include "code\game\machinery\floor_light.dm" +#include "code\game\machinery\floorlayer.dm" +#include "code\game\machinery\hologram.dm" +#include "code\game\machinery\holosign.dm" +#include "code\game\machinery\igniter.dm" +#include "code\game\machinery\jukebox.dm" +#include "code\game\machinery\lightswitch.dm" +#include "code\game\machinery\machinery.dm" +#include "code\game\machinery\magnet.dm" +#include "code\game\machinery\mass_driver.dm" +#include "code\game\machinery\navbeacon.dm" +#include "code\game\machinery\newscaster.dm" +#include "code\game\machinery\nuclear_bomb.dm" +#include "code\game\machinery\OpTable.dm" +#include "code\game\machinery\oxygen_pump.dm" +#include "code\game\machinery\pager.dm" +#include "code\game\machinery\portable_turret.dm" +#include "code\game\machinery\recharger.dm" +#include "code\game\machinery\rechargestation.dm" +#include "code\game\machinery\requests_console.dm" +#include "code\game\machinery\resleever.dm" +#include "code\game\machinery\robot_fabricator.dm" +#include "code\game\machinery\seed_extractor.dm" +#include "code\game\machinery\self_destruct.dm" +#include "code\game\machinery\Sleeper.dm" +#include "code\game\machinery\spaceheater.dm" +#include "code\game\machinery\status_display.dm" +#include "code\game\machinery\status_display_ai.dm" +#include "code\game\machinery\status_light.dm" +#include "code\game\machinery\suit_storage_unit.dm" +#include "code\game\machinery\supply_display.dm" +#include "code\game\machinery\supplybeacon.dm" +#include "code\game\machinery\syndicatebeacon.dm" +#include "code\game\machinery\teleporter.dm" +#include "code\game\machinery\turret_control.dm" +#include "code\game\machinery\vending.dm" +#include "code\game\machinery\wall_frames.dm" +#include "code\game\machinery\washing_machine.dm" +#include "code\game\machinery\wishgranter.dm" +#include "code\game\machinery\atmoalter\area_atmos_computer.dm" +#include "code\game\machinery\atmoalter\canister.dm" +#include "code\game\machinery\atmoalter\clamp.dm" +#include "code\game\machinery\atmoalter\meter.dm" +#include "code\game\machinery\atmoalter\portable_atmospherics.dm" +#include "code\game\machinery\atmoalter\pump.dm" +#include "code\game\machinery\atmoalter\scrubber.dm" +#include "code\game\machinery\camera\camera.dm" +#include "code\game\machinery\camera\camera_assembly.dm" +#include "code\game\machinery\camera\motion.dm" +#include "code\game\machinery\camera\presets.dm" +#include "code\game\machinery\camera\tracking.dm" +#include "code\game\machinery\computer\ai_core.dm" +#include "code\game\machinery\computer\arcade.dm" +#include "code\game\machinery\computer\arcade_orion.dm" +#include "code\game\machinery\computer\atmos_alert.dm" +#include "code\game\machinery\computer\atmos_control.dm" +#include "code\game\machinery\computer\buildandrepair.dm" +#include "code\game\machinery\computer\computer.dm" +#include "code\game\machinery\computer\crew.dm" +#include "code\game\machinery\computer\download_console.dm" +#include "code\game\machinery\computer\guestpass.dm" +#include "code\game\machinery\computer\law.dm" +#include "code\game\machinery\computer\message.dm" +#include "code\game\machinery\computer\Operating.dm" +#include "code\game\machinery\computer\pod.dm" +#include "code\game\machinery\computer\prisoner.dm" +#include "code\game\machinery\computer\RCON_Console.dm" +#include "code\game\machinery\computer\robot.dm" +#include "code\game\machinery\computer\shuttle.dm" +#include "code\game\machinery\computer\station_alert.dm" +#include "code\game\machinery\doors\airlock.dm" +#include "code\game\machinery\doors\airlock_control.dm" +#include "code\game\machinery\doors\airlock_electronics.dm" +#include "code\game\machinery\doors\airlock_interactions.dm" +#include "code\game\machinery\doors\alarmlock.dm" +#include "code\game\machinery\doors\blast_door.dm" +#include "code\game\machinery\doors\braces.dm" +#include "code\game\machinery\doors\brigdoors.dm" +#include "code\game\machinery\doors\checkForMultipleDoors.dm" +#include "code\game\machinery\doors\door.dm" +#include "code\game\machinery\doors\firedoor.dm" +#include "code\game\machinery\doors\firedoor_assembly.dm" +#include "code\game\machinery\doors\multi_tile.dm" +#include "code\game\machinery\doors\simple.dm" +#include "code\game\machinery\doors\unpowered.dm" +#include "code\game\machinery\doors\windowdoor.dm" +#include "code\game\machinery\embedded_controller\airlock_controllers.dm" +#include "code\game\machinery\embedded_controller\airlock_controllers_dummy.dm" +#include "code\game\machinery\embedded_controller\airlock_docking_controller.dm" +#include "code\game\machinery\embedded_controller\airlock_docking_controller_multi.dm" +#include "code\game\machinery\embedded_controller\airlock_program.dm" +#include "code\game\machinery\embedded_controller\docking_program.dm" +#include "code\game\machinery\embedded_controller\docking_program_multi.dm" +#include "code\game\machinery\embedded_controller\embedded_controller_base.dm" +#include "code\game\machinery\embedded_controller\embedded_program_base.dm" +#include "code\game\machinery\embedded_controller\simple_docking_controller.dm" +#include "code\game\machinery\kitchen\gibber.dm" +#include "code\game\machinery\kitchen\icecream.dm" +#include "code\game\machinery\kitchen\microwave.dm" +#include "code\game\machinery\kitchen\smartfridge.dm" +#include "code\game\machinery\kitchen\cooking_machines\_cooker.dm" +#include "code\game\machinery\kitchen\cooking_machines\_cooker_output.dm" +#include "code\game\machinery\kitchen\cooking_machines\candy.dm" +#include "code\game\machinery\kitchen\cooking_machines\cereal.dm" +#include "code\game\machinery\kitchen\cooking_machines\fryer.dm" +#include "code\game\machinery\kitchen\cooking_machines\grill.dm" +#include "code\game\machinery\kitchen\cooking_machines\oven.dm" +#include "code\game\machinery\pipe\construction.dm" +#include "code\game\machinery\pipe\pipe_dispenser.dm" +#include "code\game\machinery\pipe\pipelayer.dm" +#include "code\game\machinery\storage\storage.dm" +#include "code\game\machinery\telecomms\broadcaster.dm" +#include "code\game\machinery\telecomms\logbrowser.dm" +#include "code\game\machinery\telecomms\machine_interactions.dm" +#include "code\game\machinery\telecomms\presets.dm" +#include "code\game\machinery\telecomms\telecomunications.dm" +#include "code\game\machinery\telecomms\telemonitor.dm" +#include "code\game\machinery\telecomms\traffic_control.dm" +#include "code\game\mecha\mech_bay.dm" +#include "code\game\mecha\mech_fabricator.dm" +#include "code\game\mecha\mech_sensor.dm" +#include "code\game\mecha\mecha.dm" +#include "code\game\mecha\mecha_construction_paths.dm" +#include "code\game\mecha\mecha_control_console.dm" +#include "code\game\mecha\mecha_parts.dm" +#include "code\game\mecha\mecha_wreckage.dm" +#include "code\game\mecha\combat\combat.dm" +#include "code\game\mecha\combat\durand.dm" +#include "code\game\mecha\combat\gygax.dm" +#include "code\game\mecha\combat\marauder.dm" +#include "code\game\mecha\combat\phazon.dm" +#include "code\game\mecha\equipment\mecha_equipment.dm" +#include "code\game\mecha\equipment\tools\medical_tools.dm" +#include "code\game\mecha\equipment\tools\tools.dm" +#include "code\game\mecha\equipment\weapons\weapons.dm" +#include "code\game\mecha\medical\medical.dm" +#include "code\game\mecha\medical\odysseus.dm" +#include "code\game\mecha\working\hoverpod.dm" +#include "code\game\mecha\working\ripley.dm" +#include "code\game\mecha\working\working.dm" +#include "code\game\objects\buckling.dm" +#include "code\game\objects\empulse.dm" +#include "code\game\objects\explosion.dm" +#include "code\game\objects\explosion_recursive.dm" +#include "code\game\objects\items.dm" +#include "code\game\objects\objs.dm" +#include "code\game\objects\structures.dm" +#include "code\game\objects\topic.dm" +#include "code\game\objects\weapons.dm" +#include "code\game\objects\auras\aura.dm" +#include "code\game\objects\auras\radiant_aura.dm" +#include "code\game\objects\auras\personal_shields\personal_shield.dm" +#include "code\game\objects\effects\aliens.dm" +#include "code\game\objects\effects\bump_teleporter.dm" +#include "code\game\objects\effects\effect_system.dm" +#include "code\game\objects\effects\explosion_particles.dm" +#include "code\game\objects\effects\force_portal.dm" +#include "code\game\objects\effects\gibs.dm" +#include "code\game\objects\effects\landmarks.dm" +#include "code\game\objects\effects\manifest.dm" +#include "code\game\objects\effects\mines.dm" +#include "code\game\objects\effects\misc.dm" +#include "code\game\objects\effects\overlays.dm" +#include "code\game\objects\effects\portals.dm" +#include "code\game\objects\effects\spiders.dm" +#include "code\game\objects\effects\step_triggers.dm" +#include "code\game\objects\effects\chem\chemsmoke.dm" +#include "code\game\objects\effects\chem\foam.dm" +#include "code\game\objects\effects\chem\water.dm" +#include "code\game\objects\effects\decals\cleanable.dm" +#include "code\game\objects\effects\decals\contraband.dm" +#include "code\game\objects\effects\decals\crayon.dm" +#include "code\game\objects\effects\decals\decal.dm" +#include "code\game\objects\effects\decals\misc.dm" +#include "code\game\objects\effects\decals\remains.dm" +#include "code\game\objects\effects\decals\warning_stripes.dm" +#include "code\game\objects\effects\decals\Cleanable\aliens.dm" +#include "code\game\objects\effects\decals\Cleanable\fuel.dm" +#include "code\game\objects\effects\decals\Cleanable\humans.dm" +#include "code\game\objects\effects\decals\Cleanable\misc.dm" +#include "code\game\objects\effects\decals\Cleanable\robots.dm" +#include "code\game\objects\effects\decals\Cleanable\tracks.dm" +#include "code\game\objects\effects\decals\posters\bs12.dm" +#include "code\game\objects\effects\spawners\bombspawner.dm" +#include "code\game\objects\effects\spawners\gibspawner.dm" +#include "code\game\objects\items\apc_frame.dm" +#include "code\game\objects\items\blueprints.dm" +#include "code\game\objects\items\bodybag.dm" +#include "code\game\objects\items\contraband.dm" +#include "code\game\objects\items\crayons.dm" +#include "code\game\objects\items\cryobag.dm" +#include "code\game\objects\items\glassjar.dm" +#include "code\game\objects\items\instruments.dm" +#include "code\game\objects\items\latexballoon.dm" +#include "code\game\objects\items\paintkit.dm" +#include "code\game\objects\items\shooting_range.dm" +#include "code\game\objects\items\toys.dm" +#include "code\game\objects\items\trash.dm" +#include "code\game\objects\items\devices\aicard.dm" +#include "code\game\objects\items\devices\binoculars.dm" +#include "code\game\objects\items\devices\cable_painter.dm" +#include "code\game\objects\items\devices\chameleonproj.dm" +#include "code\game\objects\items\devices\compass.dm" +#include "code\game\objects\items\devices\debugger.dm" +#include "code\game\objects\items\devices\dociler.dm" +#include "code\game\objects\items\devices\flash.dm" +#include "code\game\objects\items\devices\flashlight.dm" +#include "code\game\objects\items\devices\floor_painter.dm" +#include "code\game\objects\items\devices\geiger.dm" +#include "code\game\objects\items\devices\hacktool.dm" +#include "code\game\objects\items\devices\holowarrant.dm" +#include "code\game\objects\items\devices\lightreplacer.dm" +#include "code\game\objects\items\devices\megaphone.dm" +#include "code\game\objects\items\devices\modkit.dm" +#include "code\game\objects\items\devices\multitool.dm" +#include "code\game\objects\items\devices\paicard.dm" +#include "code\game\objects\items\devices\personal_shield.dm" +#include "code\game\objects\items\devices\pipe_painter.dm" +#include "code\game\objects\items\devices\powersink.dm" +#include "code\game\objects\items\devices\scanners.dm" +#include "code\game\objects\items\devices\spy_bug.dm" +#include "code\game\objects\items\devices\suit_cooling.dm" +#include "code\game\objects\items\devices\suit_sensor_jammer.dm" +#include "code\game\objects\items\devices\t_scanner.dm" +#include "code\game\objects\items\devices\taperecorder.dm" +#include "code\game\objects\items\devices\traitordevices.dm" +#include "code\game\objects\items\devices\transfer_valve.dm" +#include "code\game\objects\items\devices\tvcamera.dm" +#include "code\game\objects\items\devices\uplink.dm" +#include "code\game\objects\items\devices\uplink_random_lists.dm" +#include "code\game\objects\items\devices\violin.dm" +#include "code\game\objects\items\devices\whistle.dm" +#include "code\game\objects\items\devices\PDA\cart.dm" +#include "code\game\objects\items\devices\PDA\PDA.dm" +#include "code\game\objects\items\devices\PDA\radio.dm" +#include "code\game\objects\items\devices\radio\beacon.dm" +#include "code\game\objects\items\devices\radio\electropack.dm" +#include "code\game\objects\items\devices\radio\encryptionkey.dm" +#include "code\game\objects\items\devices\radio\headset.dm" +#include "code\game\objects\items\devices\radio\intercom.dm" +#include "code\game\objects\items\devices\radio\radio.dm" +#include "code\game\objects\items\robot\robot_items.dm" +#include "code\game\objects\items\robot\robot_parts.dm" +#include "code\game\objects\items\robot\robot_upgrades.dm" +#include "code\game\objects\items\stacks\matter_synth.dm" +#include "code\game\objects\items\stacks\medical.dm" +#include "code\game\objects\items\stacks\nanopaste.dm" +#include "code\game\objects\items\stacks\rods.dm" +#include "code\game\objects\items\stacks\stack.dm" +#include "code\game\objects\items\stacks\telecrystal.dm" +#include "code\game\objects\items\stacks\sheets\leather.dm" +#include "code\game\objects\items\stacks\tiles\tile_types.dm" +#include "code\game\objects\items\weapons\AI_modules.dm" +#include "code\game\objects\items\weapons\autopsy.dm" +#include "code\game\objects\items\weapons\baton.dm" +#include "code\game\objects\items\weapons\beachball.dm" +#include "code\game\objects\items\weapons\candle.dm" +#include "code\game\objects\items\weapons\cane.dm" +#include "code\game\objects\items\weapons\cards_ids.dm" +#include "code\game\objects\items\weapons\cards_ids_syndicate.dm" +#include "code\game\objects\items\weapons\cigs_lighters.dm" +#include "code\game\objects\items\weapons\clothingbag.dm" +#include "code\game\objects\items\weapons\clown_items.dm" +#include "code\game\objects\items\weapons\cosmetics.dm" +#include "code\game\objects\items\weapons\crutches.dm" +#include "code\game\objects\items\weapons\defib.dm" +#include "code\game\objects\items\weapons\dice.dm" +#include "code\game\objects\items\weapons\ecigs.dm" +#include "code\game\objects\items\weapons\explosives.dm" +#include "code\game\objects\items\weapons\extinguisher.dm" +#include "code\game\objects\items\weapons\flamethrower.dm" +#include "code\game\objects\items\weapons\gift_wrappaper.dm" +#include "code\game\objects\items\weapons\handcuffs.dm" +#include "code\game\objects\items\weapons\improvised_components.dm" +#include "code\game\objects\items\weapons\janitor_sign.dm" +#include "code\game\objects\items\weapons\mop.dm" +#include "code\game\objects\items\weapons\nuclear_cylinder.dm" +#include "code\game\objects\items\weapons\paint.dm" +#include "code\game\objects\items\weapons\policetape.dm" +#include "code\game\objects\items\weapons\RCD.dm" +#include "code\game\objects\items\weapons\RSF.dm" +#include "code\game\objects\items\weapons\scrolls.dm" +#include "code\game\objects\items\weapons\secrets_disk.dm" +#include "code\game\objects\items\weapons\shields.dm" +#include "code\game\objects\items\weapons\soap.dm" +#include "code\game\objects\items\weapons\staff.dm" +#include "code\game\objects\items\weapons\stunbaton.dm" +#include "code\game\objects\items\weapons\surgery_tools.dm" +#include "code\game\objects\items\weapons\tagnabber.dm" +#include "code\game\objects\items\weapons\tape.dm" +#include "code\game\objects\items\weapons\teleportation.dm" +#include "code\game\objects\items\weapons\tools.dm" +#include "code\game\objects\items\weapons\towels.dm" +#include "code\game\objects\items\weapons\traps.dm" +#include "code\game\objects\items\weapons\trays.dm" +#include "code\game\objects\items\weapons\weaponry.dm" +#include "code\game\objects\items\weapons\weldbackpack.dm" +#include "code\game\objects\items\weapons\circuitboards\broken.dm" +#include "code\game\objects\items\weapons\circuitboards\circuitboard.dm" +#include "code\game\objects\items\weapons\circuitboards\mecha.dm" +#include "code\game\objects\items\weapons\circuitboards\other.dm" +#include "code\game\objects\items\weapons\circuitboards\computer\air_management.dm" +#include "code\game\objects\items\weapons\circuitboards\computer\computer.dm" +#include "code\game\objects\items\weapons\circuitboards\computer\holodeckcontrol.dm" +#include "code\game\objects\items\weapons\circuitboards\computer\research.dm" +#include "code\game\objects\items\weapons\circuitboards\computer\station_alert.dm" +#include "code\game\objects\items\weapons\circuitboards\computer\telecomms.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\biogenerator.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\cloning.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\commsantenna.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\mech_recharger.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\mining_drill.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\oxyregenerator.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\pacman.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\power.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\recharge_station.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\replicator.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\research.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\shieldgen.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\telecomms.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\unary_atmos.dm" +#include "code\game\objects\items\weapons\grenades\anti_photon_grenade.dm" +#include "code\game\objects\items\weapons\grenades\chem_grenade.dm" +#include "code\game\objects\items\weapons\grenades\emgrenade.dm" +#include "code\game\objects\items\weapons\grenades\explosive.dm" +#include "code\game\objects\items\weapons\grenades\flashbang.dm" +#include "code\game\objects\items\weapons\grenades\grenade.dm" +#include "code\game\objects\items\weapons\grenades\prank_grenades.dm" +#include "code\game\objects\items\weapons\grenades\smokebomb.dm" +#include "code\game\objects\items\weapons\grenades\spawnergrenade.dm" +#include "code\game\objects\items\weapons\grenades\supermatter.dm" +#include "code\game\objects\items\weapons\implants\implant.dm" +#include "code\game\objects\items\weapons\implants\implantcase.dm" +#include "code\game\objects\items\weapons\implants\implantchair.dm" +#include "code\game\objects\items\weapons\implants\implanter.dm" +#include "code\game\objects\items\weapons\implants\implantpad.dm" +#include "code\game\objects\items\weapons\implants\implants\adrenaline.dm" +#include "code\game\objects\items\weapons\implants\implants\chem.dm" +#include "code\game\objects\items\weapons\implants\implants\compressed.dm" +#include "code\game\objects\items\weapons\implants\implants\death_alarm.dm" +#include "code\game\objects\items\weapons\implants\implants\explosive.dm" +#include "code\game\objects\items\weapons\implants\implants\freedom.dm" +#include "code\game\objects\items\weapons\implants\implants\imprinting.dm" +#include "code\game\objects\items\weapons\implants\implants\loyalty.dm" +#include "code\game\objects\items\weapons\implants\implants\tracking.dm" +#include "code\game\objects\items\weapons\implants\implants\uplink.dm" +#include "code\game\objects\items\weapons\material\ashtray.dm" +#include "code\game\objects\items\weapons\material\bats.dm" +#include "code\game\objects\items\weapons\material\kitchen.dm" +#include "code\game\objects\items\weapons\material\knives.dm" +#include "code\game\objects\items\weapons\material\material_weapons.dm" +#include "code\game\objects\items\weapons\material\misc.dm" +#include "code\game\objects\items\weapons\material\shards.dm" +#include "code\game\objects\items\weapons\material\stick.dm" +#include "code\game\objects\items\weapons\material\swords.dm" +#include "code\game\objects\items\weapons\material\thrown.dm" +#include "code\game\objects\items\weapons\material\twohanded.dm" +#include "code\game\objects\items\weapons\melee\energy.dm" +#include "code\game\objects\items\weapons\melee\misc.dm" +#include "code\game\objects\items\weapons\storage\backpack.dm" +#include "code\game\objects\items\weapons\storage\bags.dm" +#include "code\game\objects\items\weapons\storage\belt.dm" +#include "code\game\objects\items\weapons\storage\bible.dm" +#include "code\game\objects\items\weapons\storage\boxes.dm" +#include "code\game\objects\items\weapons\storage\briefcase.dm" +#include "code\game\objects\items\weapons\storage\fancy.dm" +#include "code\game\objects\items\weapons\storage\firstaid.dm" +#include "code\game\objects\items\weapons\storage\internal.dm" +#include "code\game\objects\items\weapons\storage\laundry_basket.dm" +#include "code\game\objects\items\weapons\storage\lockbox.dm" +#include "code\game\objects\items\weapons\storage\lunchbox.dm" +#include "code\game\objects\items\weapons\storage\misc.dm" +#include "code\game\objects\items\weapons\storage\secure.dm" +#include "code\game\objects\items\weapons\storage\specialized.dm" +#include "code\game\objects\items\weapons\storage\storage.dm" +#include "code\game\objects\items\weapons\storage\toolbox.dm" +#include "code\game\objects\items\weapons\storage\uplink_kits.dm" +#include "code\game\objects\items\weapons\storage\wallets.dm" +#include "code\game\objects\items\weapons\storage\storage_ui\default.dm" +#include "code\game\objects\items\weapons\storage\storage_ui\storage_ui.dm" +#include "code\game\objects\items\weapons\storage\storage_ui\tgui.dm" +#include "code\game\objects\items\weapons\tanks\jetpack.dm" +#include "code\game\objects\items\weapons\tanks\tank_types.dm" +#include "code\game\objects\items\weapons\tanks\tanks.dm" +#include "code\game\objects\random\random.dm" +#include "code\game\objects\structures\barsign.dm" +#include "code\game\objects\structures\bedsheet_bin.dm" +#include "code\game\objects\structures\catwalk.dm" +#include "code\game\objects\structures\coathanger.dm" +#include "code\game\objects\structures\curtains.dm" +#include "code\game\objects\structures\displaycase.dm" +#include "code\game\objects\structures\dogbed.dm" +#include "code\game\objects\structures\door_assembly.dm" +#include "code\game\objects\structures\electricchair.dm" +#include "code\game\objects\structures\extinguisher.dm" +#include "code\game\objects\structures\fireaxe_cabinet.dm" +#include "code\game\objects\structures\fitness.dm" +#include "code\game\objects\structures\flora.dm" +#include "code\game\objects\structures\girders.dm" +#include "code\game\objects\structures\grille.dm" +#include "code\game\objects\structures\handrail.dm" +#include "code\game\objects\structures\inflatable.dm" +#include "code\game\objects\structures\iv_drip.dm" +#include "code\game\objects\structures\janicart.dm" +#include "code\game\objects\structures\kitchen_spike.dm" +#include "code\game\objects\structures\lattice.dm" +#include "code\game\objects\structures\mirror.dm" +#include "code\game\objects\structures\mop_bucket.dm" +#include "code\game\objects\structures\morgue.dm" +#include "code\game\objects\structures\musician.dm" +#include "code\game\objects\structures\noticeboard.dm" +#include "code\game\objects\structures\pit.dm" +#include "code\game\objects\structures\railing.dm" +#include "code\game\objects\structures\rubble.dm" +#include "code\game\objects\structures\safe.dm" +#include "code\game\objects\structures\showcase.dm" +#include "code\game\objects\structures\signs.dm" +#include "code\game\objects\structures\skele_stand.dm" +#include "code\game\objects\structures\stasis_cage.dm" +#include "code\game\objects\structures\statue.dm" +#include "code\game\objects\structures\tank_dispenser.dm" +#include "code\game\objects\structures\target_stake.dm" +#include "code\game\objects\structures\transit_tubes.dm" +#include "code\game\objects\structures\under_wardrobe.dm" +#include "code\game\objects\structures\watercloset.dm" +#include "code\game\objects\structures\windoor_assembly.dm" +#include "code\game\objects\structures\window.dm" +#include "code\game\objects\structures\window_frame.dm" +#include "code\game\objects\structures\window_spawner.dm" +#include "code\game\objects\structures\crates_lockers\closets.dm" +#include "code\game\objects\structures\crates_lockers\crates.dm" +#include "code\game\objects\structures\crates_lockers\largecrate.dm" +#include "code\game\objects\structures\crates_lockers\closets\coffin.dm" +#include "code\game\objects\structures\crates_lockers\closets\crittercrate.dm" +#include "code\game\objects\structures\crates_lockers\closets\fitness.dm" +#include "code\game\objects\structures\crates_lockers\closets\gimmick.dm" +#include "code\game\objects\structures\crates_lockers\closets\job_closets.dm" +#include "code\game\objects\structures\crates_lockers\closets\l3closet.dm" +#include "code\game\objects\structures\crates_lockers\closets\malfunction.dm" +#include "code\game\objects\structures\crates_lockers\closets\statue.dm" +#include "code\game\objects\structures\crates_lockers\closets\syndicate.dm" +#include "code\game\objects\structures\crates_lockers\closets\utility_closets.dm" +#include "code\game\objects\structures\crates_lockers\closets\walllocker.dm" +#include "code\game\objects\structures\crates_lockers\closets\wardrobe.dm" +#include "code\game\objects\structures\crates_lockers\closets\secure\bar.dm" +#include "code\game\objects\structures\crates_lockers\closets\secure\cargo.dm" +#include "code\game\objects\structures\crates_lockers\closets\secure\engineering.dm" +#include "code\game\objects\structures\crates_lockers\closets\secure\freezer.dm" +#include "code\game\objects\structures\crates_lockers\closets\secure\guncabinet.dm" +#include "code\game\objects\structures\crates_lockers\closets\secure\hydroponics.dm" +#include "code\game\objects\structures\crates_lockers\closets\secure\medical.dm" +#include "code\game\objects\structures\crates_lockers\closets\secure\nuke.dm" +#include "code\game\objects\structures\crates_lockers\closets\secure\personal.dm" +#include "code\game\objects\structures\crates_lockers\closets\secure\scientist.dm" +#include "code\game\objects\structures\crates_lockers\closets\secure\secure_closets.dm" +#include "code\game\objects\structures\crates_lockers\closets\secure\security.dm" +#include "code\game\objects\structures\stool_bed_chair_nest\bed.dm" +#include "code\game\objects\structures\stool_bed_chair_nest\chairs.dm" +#include "code\game\objects\structures\stool_bed_chair_nest\stools.dm" +#include "code\game\objects\structures\stool_bed_chair_nest\throne.dm" +#include "code\game\objects\structures\stool_bed_chair_nest\wheelchair.dm" +#include "code\game\turfs\simulated.dm" +#include "code\game\turfs\turf.dm" +#include "code\game\turfs\turf_changing.dm" +#include "code\game\turfs\turf_flick_animations.dm" +#include "code\game\turfs\unsimulated.dm" +#include "code\game\turfs\flooring\flooring.dm" +#include "code\game\turfs\flooring\flooring_decals.dm" +#include "code\game\turfs\flooring\flooring_premade.dm" +#include "code\game\turfs\flooring\flooring_shuttle.dm" +#include "code\game\turfs\initialization\init.dm" +#include "code\game\turfs\initialization\maintenance.dm" +#include "code\game\turfs\simulated\floor.dm" +#include "code\game\turfs\simulated\floor_acts.dm" +#include "code\game\turfs\simulated\floor_attackby.dm" +#include "code\game\turfs\simulated\floor_damage.dm" +#include "code\game\turfs\simulated\floor_icon.dm" +#include "code\game\turfs\simulated\floor_static.dm" +#include "code\game\turfs\simulated\footsteps.dm" +#include "code\game\turfs\simulated\wall_attacks.dm" +#include "code\game\turfs\simulated\wall_icon.dm" +#include "code\game\turfs\simulated\wall_shuttle.dm" +#include "code\game\turfs\simulated\wall_types.dm" +#include "code\game\turfs\simulated\walls.dm" +#include "code\game\turfs\space\space.dm" +#include "code\game\turfs\space\transit.dm" +#include "code\game\turfs\unsimulated\beach.dm" +#include "code\game\turfs\unsimulated\floor.dm" +#include "code\game\turfs\unsimulated\walls.dm" +#include "code\game\verbs\ignore.dm" +#include "code\game\verbs\ooc.dm" +#include "code\game\verbs\who.dm" +#include "code\js\byjax.dm" +#include "code\js\menus.dm" +#include "code\modules\achievements\achievements.dm" +#include "code\modules\achievements\achievements_core.dm" +#include "code\modules\acting\acting_items.dm" +#include "code\modules\admin\admin.dm" +#include "code\modules\admin\admin_attack_log.dm" +#include "code\modules\admin\admin_investigate.dm" +#include "code\modules\admin\admin_memo.dm" +#include "code\modules\admin\admin_ranks.dm" +#include "code\modules\admin\admin_secrets.dm" +#include "code\modules\admin\admin_verbs.dm" +#include "code\modules\admin\banjob.dm" +#include "code\modules\admin\create_mob.dm" +#include "code\modules\admin\create_object.dm" +#include "code\modules\admin\create_turf.dm" +#include "code\modules\admin\hellban.dm" +#include "code\modules\admin\holder2.dm" +#include "code\modules\admin\holoverbs.dm" +#include "code\modules\admin\IsBanned.dm" +#include "code\modules\admin\map_capture.dm" +#include "code\modules\admin\NewBan.dm" +#include "code\modules\admin\player_notes.dm" +#include "code\modules\admin\player_panel.dm" +#include "code\modules\admin\server_whitelist.dm" +#include "code\modules\admin\ticket.dm" +#include "code\modules\admin\topic.dm" +#include "code\modules\admin\buildmode\advance.dm" +#include "code\modules\admin\buildmode\basic.dm" +#include "code\modules\admin\buildmode\build_mode.dm" +#include "code\modules\admin\buildmode\buttons.dm" +#include "code\modules\admin\buildmode\click_handler.dm" +#include "code\modules\admin\buildmode\edit.dm" +#include "code\modules\admin\buildmode\ladders.dm" +#include "code\modules\admin\buildmode\light_maker.dm" +#include "code\modules\admin\buildmode\move_into.dm" +#include "code\modules\admin\buildmode\relocate_to.dm" +#include "code\modules\admin\buildmode\room_builder.dm" +#include "code\modules\admin\buildmode\throw_at.dm" +#include "code\modules\admin\callproc\callproc.dm" +#include "code\modules\admin\DB ban\functions.dm" +#include "code\modules\admin\permissionverbs\permissionedit.dm" +#include "code\modules\admin\secrets\admin_secrets\admin_logs.dm" +#include "code\modules\admin\secrets\admin_secrets\alter_narsie.dm" +#include "code\modules\admin\secrets\admin_secrets\bombing_list.dm" +#include "code\modules\admin\secrets\admin_secrets\jump_shuttle.dm" +#include "code\modules\admin\secrets\admin_secrets\launch_shuttle.dm" +#include "code\modules\admin\secrets\admin_secrets\launch_shuttle_forced.dm" +#include "code\modules\admin\secrets\admin_secrets\list_dna.dm" +#include "code\modules\admin\secrets\admin_secrets\list_fingerprints.dm" +#include "code\modules\admin\secrets\admin_secrets\move_shuttle.dm" +#include "code\modules\admin\secrets\admin_secrets\prison_warp.dm" +#include "code\modules\admin\secrets\admin_secrets\show_ai_laws.dm" +#include "code\modules\admin\secrets\admin_secrets\show_crew_manifest.dm" +#include "code\modules\admin\secrets\admin_secrets\show_game_mode.dm" +#include "code\modules\admin\secrets\admin_secrets\show_law_changes.dm" +#include "code\modules\admin\secrets\admin_secrets\show_signalers.dm" +#include "code\modules\admin\secrets\admin_secrets\traitors_and_objectives.dm" +#include "code\modules\admin\secrets\final_solutions\summon_narsie.dm" +#include "code\modules\admin\secrets\final_solutions\supermatter_cascade.dm" +#include "code\modules\admin\secrets\fun_secrets\break_all_lights.dm" +#include "code\modules\admin\secrets\fun_secrets\break_some_lights.dm" +#include "code\modules\admin\secrets\fun_secrets\fix_all_lights.dm" +#include "code\modules\admin\secrets\fun_secrets\ghost_mode.dm" +#include "code\modules\admin\secrets\fun_secrets\make_all_areas_powered.dm" +#include "code\modules\admin\secrets\fun_secrets\make_all_areas_unpowered.dm" +#include "code\modules\admin\secrets\fun_secrets\paintball_mode.dm" +#include "code\modules\admin\secrets\fun_secrets\power_all_smes.dm" +#include "code\modules\admin\secrets\fun_secrets\remove_all_clothing.dm" +#include "code\modules\admin\secrets\fun_secrets\remove_internal_clothing.dm" +#include "code\modules\admin\secrets\fun_secrets\send_strike_team.dm" +#include "code\modules\admin\secrets\fun_secrets\toggle_bomb_cap.dm" +#include "code\modules\admin\secrets\fun_secrets\triple_ai_mode.dm" +#include "code\modules\admin\secrets\fun_secrets\turn_humans_into_corgies.dm" +#include "code\modules\admin\secrets\fun_secrets\turn_humans_into_monkeys.dm" +#include "code\modules\admin\secrets\fun_secrets\waddle.dm" +#include "code\modules\admin\secrets\investigation\admin_pms.dm" +#include "code\modules\admin\secrets\investigation\attack_logs.dm" +#include "code\modules\admin\secrets\random_events\gravity.dm" +#include "code\modules\admin\secrets\random_events\trigger_cordical_borer_infestation.dm" +#include "code\modules\admin\secrets\random_events\trigger_xenomorph_infestation.dm" +#include "code\modules\admin\verbs\adminhelp.dm" +#include "code\modules\admin\verbs\adminjump.dm" +#include "code\modules\admin\verbs\adminpm.dm" +#include "code\modules\admin\verbs\adminsay.dm" +#include "code\modules\admin\verbs\atmosdebug.dm" +#include "code\modules\admin\verbs\BrokenInhands.dm" +#include "code\modules\admin\verbs\check_customitem_activity.dm" +#include "code\modules\admin\verbs\cinematic.dm" +#include "code\modules\admin\verbs\custom_event.dm" +#include "code\modules\admin\verbs\deadsay.dm" +#include "code\modules\admin\verbs\debug.dm" +#include "code\modules\admin\verbs\diagnostics.dm" +#include "code\modules\admin\verbs\dice.dm" +#include "code\modules\admin\verbs\getlogs.dm" +#include "code\modules\admin\verbs\grief_fixers.dm" +#include "code\modules\admin\verbs\map_template_loadverb.dm" +#include "code\modules\admin\verbs\mapping.dm" +#include "code\modules\admin\verbs\massmodvar.dm" +#include "code\modules\admin\verbs\modifyvariables.dm" +#include "code\modules\admin\verbs\playsound.dm" +#include "code\modules\admin\verbs\possess.dm" +#include "code\modules\admin\verbs\pray.dm" +#include "code\modules\admin\verbs\randomverbs.dm" +#include "code\modules\admin\verbs\SDQL.dm" +#include "code\modules\admin\verbs\striketeam.dm" +#include "code\modules\admin\verbs\ticklag.dm" +#include "code\modules\admin\verbs\trading_verbs.dm" +#include "code\modules\admin\verbs\tripAI.dm" +#include "code\modules\admin\verbs\SDQL_2\SDQL_2.dm" +#include "code\modules\admin\verbs\SDQL_2\SDQL_2_parser.dm" +#include "code\modules\admin\verbs\SDQL_2\SDQL_2_std.dm" +#include "code\modules\admin\view_variables\helpers.dm" +#include "code\modules\admin\view_variables\topic.dm" +#include "code\modules\admin\view_variables\view_variables.dm" +#include "code\modules\admin\view_variables\view_variables_global.dm" +#include "code\modules\admin\view_variables\vv_set_handlers.dm" +#include "code\modules\alarm\alarm.dm" +#include "code\modules\alarm\alarm_handler.dm" +#include "code\modules\alarm\atmosphere_alarm.dm" +#include "code\modules\alarm\camera_alarm.dm" +#include "code\modules\alarm\fire_alarm.dm" +#include "code\modules\alarm\motion_alarm.dm" +#include "code\modules\alarm\power_alarm.dm" +#include "code\modules\aspect\_aspects.dm" +#include "code\modules\assembly\assembly.dm" +#include "code\modules\assembly\helpers.dm" +#include "code\modules\assembly\holder.dm" +#include "code\modules\assembly\igniter.dm" +#include "code\modules\assembly\infrared.dm" +#include "code\modules\assembly\mousetrap.dm" +#include "code\modules\assembly\proximity.dm" +#include "code\modules\assembly\shock_kit.dm" +#include "code\modules\assembly\signaler.dm" +#include "code\modules\assembly\timer.dm" +#include "code\modules\assembly\voice.dm" +#include "code\modules\atmospherics\_atmos_setup.dm" +#include "code\modules\atmospherics\atmos_primitives.dm" +#include "code\modules\atmospherics\atmospherics.dm" +#include "code\modules\atmospherics\datum_pipe_network.dm" +#include "code\modules\atmospherics\datum_pipeline.dm" +#include "code\modules\atmospherics\he_pipes.dm" +#include "code\modules\atmospherics\mainspipe.dm" +#include "code\modules\atmospherics\pipes.dm" +#include "code\modules\atmospherics\components\portables_connector.dm" +#include "code\modules\atmospherics\components\shutoff.dm" +#include "code\modules\atmospherics\components\tvalve.dm" +#include "code\modules\atmospherics\components\valve.dm" +#include "code\modules\atmospherics\components\binary_devices\binary_atmos_base.dm" +#include "code\modules\atmospherics\components\binary_devices\circulator.dm" +#include "code\modules\atmospherics\components\binary_devices\dp_vent_pump.dm" +#include "code\modules\atmospherics\components\binary_devices\oxyregenerator.dm" +#include "code\modules\atmospherics\components\binary_devices\passive_gate.dm" +#include "code\modules\atmospherics\components\binary_devices\pipeturbine.dm" +#include "code\modules\atmospherics\components\binary_devices\pump.dm" +#include "code\modules\atmospherics\components\binary_devices\volume_pump.dm" +#include "code\modules\atmospherics\components\omni_devices\_omni_extras.dm" +#include "code\modules\atmospherics\components\omni_devices\filter.dm" +#include "code\modules\atmospherics\components\omni_devices\mixer.dm" +#include "code\modules\atmospherics\components\omni_devices\omni_base.dm" +#include "code\modules\atmospherics\components\trinary_devices\filter.dm" +#include "code\modules\atmospherics\components\trinary_devices\mixer.dm" +#include "code\modules\atmospherics\components\trinary_devices\trinary_base.dm" +#include "code\modules\atmospherics\components\unary\cold_sink.dm" +#include "code\modules\atmospherics\components\unary\generator_input.dm" +#include "code\modules\atmospherics\components\unary\heat_exchanger.dm" +#include "code\modules\atmospherics\components\unary\heat_source.dm" +#include "code\modules\atmospherics\components\unary\outlet_injector.dm" +#include "code\modules\atmospherics\components\unary\oxygen_generator.dm" +#include "code\modules\atmospherics\components\unary\thermal_plate.dm" +#include "code\modules\atmospherics\components\unary\unary_base.dm" +#include "code\modules\atmospherics\components\unary\vent_pump.dm" +#include "code\modules\atmospherics\components\unary\vent_scrubber.dm" +#include "code\modules\awaymissions\bluespaceartillery.dm" +#include "code\modules\awaymissions\corpse.dm" +#include "code\modules\awaymissions\exile.dm" +#include "code\modules\awaymissions\gateway.dm" +#include "code\modules\awaymissions\loot.dm" +#include "code\modules\awaymissions\pamphlet.dm" +#include "code\modules\awaymissions\trigger.dm" +#include "code\modules\awaymissions\zlevel.dm" +#include "code\modules\blob\blob.dm" +#include "code\modules\client\asset_cache.dm" +#include "code\modules\client\client_defines.dm" +#include "code\modules\client\client_helpers.dm" +#include "code\modules\client\client_procs.dm" +#include "code\modules\client\darkmode.dm" +#include "code\modules\client\movement.dm" +#include "code\modules\client\preferences.dm" +#include "code\modules\client\preferences_savefile.dm" +#include "code\modules\client\preferences_spawnpoints.dm" +#include "code\modules\client\preferences_toggle.dm" +#include "code\modules\client\ui_style.dm" +#include "code\modules\client\preference_setup\_defines.dm" +#include "code\modules\client\preference_setup\preference_setup.dm" +#include "code\modules\client\preference_setup\antagonism\01_candidacy.dm" +#include "code\modules\client\preference_setup\antagonism\02_setup.dm" +#include "code\modules\client\preference_setup\general\01_basic.dm" +#include "code\modules\client\preference_setup\general\03_body.dm" +#include "code\modules\client\preference_setup\general\04_equipment.dm" +#include "code\modules\client\preference_setup\global\01_ui.dm" +#include "code\modules\client\preference_setup\global\02_prefixes.dm" +#include "code\modules\client\preference_setup\global\03_pai.dm" +#include "code\modules\client\preference_setup\global\04_ooc.dm" +#include "code\modules\client\preference_setup\global\05_settings.dm" +#include "code\modules\client\preference_setup\global\preferences.dm" +#include "code\modules\client\preference_setup\global\prefixes.dm" +#include "code\modules\client\preference_setup\occupation\occupation.dm" +#include "code\modules\clothing\chameleon.dm" +#include "code\modules\clothing\clothing.dm" +#include "code\modules\clothing\clothing_accessories.dm" +#include "code\modules\clothing\ears\earrings.dm" +#include "code\modules\clothing\ears\skrell.dm" +#include "code\modules\clothing\glasses\glasses.dm" +#include "code\modules\clothing\glasses\hud.dm" +#include "code\modules\clothing\gloves\boxing.dm" +#include "code\modules\clothing\gloves\color.dm" +#include "code\modules\clothing\gloves\miscellaneous.dm" +#include "code\modules\clothing\head\collectable.dm" +#include "code\modules\clothing\head\hardhat.dm" +#include "code\modules\clothing\head\helmet.dm" +#include "code\modules\clothing\head\jobs.dm" +#include "code\modules\clothing\head\mirania.dm" +#include "code\modules\clothing\head\misc.dm" +#include "code\modules\clothing\head\misc_special.dm" +#include "code\modules\clothing\head\soft_caps.dm" +#include "code\modules\clothing\masks\boxing.dm" +#include "code\modules\clothing\masks\breath.dm" +#include "code\modules\clothing\masks\gasmask.dm" +#include "code\modules\clothing\masks\miscellaneous.dm" +#include "code\modules\clothing\masks\monitor.dm" +#include "code\modules\clothing\masks\voice.dm" +#include "code\modules\clothing\rings\material.dm" +#include "code\modules\clothing\rings\rings.dm" +#include "code\modules\clothing\shoes\colour.dm" +#include "code\modules\clothing\shoes\jobs.dm" +#include "code\modules\clothing\shoes\magboots.dm" +#include "code\modules\clothing\shoes\miscellaneous.dm" +#include "code\modules\clothing\spacesuits\alien.dm" +#include "code\modules\clothing\spacesuits\breaches.dm" +#include "code\modules\clothing\spacesuits\captain.dm" +#include "code\modules\clothing\spacesuits\miscellaneous.dm" +#include "code\modules\clothing\spacesuits\spacesuits.dm" +#include "code\modules\clothing\spacesuits\syndi.dm" +#include "code\modules\clothing\spacesuits\void\bogani.dm" +#include "code\modules\clothing\spacesuits\void\merc.dm" +#include "code\modules\clothing\spacesuits\void\misc.dm" +#include "code\modules\clothing\spacesuits\void\station.dm" +#include "code\modules\clothing\spacesuits\void\void.dm" +#include "code\modules\clothing\spacesuits\void\wizard.dm" +#include "code\modules\clothing\suits\alien.dm" +#include "code\modules\clothing\suits\armor.dm" +#include "code\modules\clothing\suits\bio.dm" +#include "code\modules\clothing\suits\jobs.dm" +#include "code\modules\clothing\suits\labcoat.dm" +#include "code\modules\clothing\suits\mirania.dm" +#include "code\modules\clothing\suits\miscellaneous.dm" +#include "code\modules\clothing\suits\storage.dm" +#include "code\modules\clothing\suits\toggles.dm" +#include "code\modules\clothing\suits\utility.dm" +#include "code\modules\clothing\suits\wiz_robe.dm" +#include "code\modules\clothing\under\casual_pants.dm" +#include "code\modules\clothing\under\color.dm" +#include "code\modules\clothing\under\formal_pants.dm" +#include "code\modules\clothing\under\mirania.dm" +#include "code\modules\clothing\under\miscellaneous.dm" +#include "code\modules\clothing\under\nanotrasen.dm" +#include "code\modules\clothing\under\shorts.dm" +#include "code\modules\clothing\under\skirts.dm" +#include "code\modules\clothing\under\syndicate.dm" +#include "code\modules\clothing\under\accessories\accessory.dm" +#include "code\modules\clothing\under\accessories\armband.dm" +#include "code\modules\clothing\under\accessories\armor.dm" +#include "code\modules\clothing\under\accessories\badges.dm" +#include "code\modules\clothing\under\accessories\clothing.dm" +#include "code\modules\clothing\under\accessories\holster.dm" +#include "code\modules\clothing\under\accessories\jammers.dm" +#include "code\modules\clothing\under\accessories\lockets.dm" +#include "code\modules\clothing\under\accessories\medals.dm" +#include "code\modules\clothing\under\accessories\stethoscope.dm" +#include "code\modules\clothing\under\accessories\storage.dm" +#include "code\modules\clothing\under\accessories\ties.dm" +#include "code\modules\clothing\under\jobs\civilian.dm" +#include "code\modules\clothing\under\jobs\engineering.dm" +#include "code\modules\clothing\under\jobs\medsci.dm" +#include "code\modules\clothing\under\jobs\security.dm" +#include "code\modules\clothing\under\xenos\bogani.dm" +#include "code\modules\clothing\underwear\base.dm" +#include "code\modules\component\component.dm" +#include "code\modules\crafting\crafting.dm" +#include "code\modules\crafting\parts\lathe_items.dm" +#include "code\modules\crafting\recipes\guns.dm" +#include "code\modules\crafting\recipes\items.dm" +#include "code\modules\crafting\recipes\structures.dm" +#include "code\modules\crafting\recipes\tools.dm" +#include "code\modules\customitems\item_spawning.dm" +#include "code\modules\detectivework\footprints.dm" +#include "code\modules\detectivework\forensics.dm" +#include "code\modules\detectivework\microscope\dnascanner.dm" +#include "code\modules\detectivework\microscope\microscope.dm" +#include "code\modules\detectivework\tools\crimekit.dm" +#include "code\modules\detectivework\tools\evidencebag.dm" +#include "code\modules\detectivework\tools\luminol.dm" +#include "code\modules\detectivework\tools\rag.dm" +#include "code\modules\detectivework\tools\sample_kits.dm" +#include "code\modules\detectivework\tools\storage.dm" +#include "code\modules\detectivework\tools\swabs.dm" +#include "code\modules\detectivework\tools\uvlight.dm" +#include "code\modules\economy\Accounts.dm" +#include "code\modules\economy\Accounts_DB.dm" +#include "code\modules\economy\ATM.dm" +#include "code\modules\economy\cash.dm" +#include "code\modules\economy\economy_misc.dm" +#include "code\modules\economy\EFTPOS.dm" +#include "code\modules\economy\Events.dm" +#include "code\modules\economy\Events_Mundane.dm" +#include "code\modules\economy\TradeDestinations.dm" +#include "code\modules\emoji\emoji_parse.dm" +#include "code\modules\emotes\emote_define.dm" +#include "code\modules\emotes\emote_mob.dm" +#include "code\modules\emotes\definitions\_mob.dm" +#include "code\modules\emotes\definitions\_species.dm" +#include "code\modules\emotes\definitions\audible.dm" +#include "code\modules\emotes\definitions\human.dm" +#include "code\modules\emotes\definitions\slime.dm" +#include "code\modules\emotes\definitions\synthetics.dm" +#include "code\modules\emotes\definitions\visible.dm" +#include "code\modules\error_handler\error_handler.dm" +#include "code\modules\error_handler\error_reporting.dm" +#include "code\modules\error_handler\error_viewer.dm" +#include "code\modules\events\apc_damage.dm" +#include "code\modules\events\blob.dm" +#include "code\modules\events\brand_intelligence.dm" +#include "code\modules\events\camera_damage.dm" +#include "code\modules\events\carp_migration.dm" +#include "code\modules\events\comms_blackout.dm" +#include "code\modules\events\communications_blackout.dm" +#include "code\modules\events\dust.dm" +#include "code\modules\events\electrical_storm.dm" +#include "code\modules\events\event.dm" +#include "code\modules\events\event_container.dm" +#include "code\modules\events\event_dynamic.dm" +#include "code\modules\events\event_manager.dm" +#include "code\modules\events\gravity.dm" +#include "code\modules\events\grid_check.dm" +#include "code\modules\events\infestation.dm" +#include "code\modules\events\invasion.dm" +#include "code\modules\events\ion_storm.dm" +#include "code\modules\events\meteors.dm" +#include "code\modules\events\money_hacker.dm" +#include "code\modules\events\money_lotto.dm" +#include "code\modules\events\mortars.dm" +#include "code\modules\events\prison_break.dm" +#include "code\modules\events\radiation_storm.dm" +#include "code\modules\events\random_antagonist.dm" +#include "code\modules\events\rogue_drones.dm" +#include "code\modules\events\sensor_suit_jamming.dm" +#include "code\modules\events\shipping_error.dm" +#include "code\modules\events\solar_storm.dm" +#include "code\modules\events\space_cold.dm" +#include "code\modules\events\spacevine.dm" +#include "code\modules\events\spider_infestation.dm" +#include "code\modules\events\spontaneous_appendicitis.dm" +#include "code\modules\events\wallrot.dm" +#include "code\modules\events\zombies.dm" +#include "code\modules\examine\examine.dm" +#include "code\modules\examine\stat_icons.dm" +#include "code\modules\examine\descriptions\armor.dm" +#include "code\modules\examine\descriptions\atmospherics.dm" +#include "code\modules\examine\descriptions\drink_containers.dm" +#include "code\modules\examine\descriptions\engineering.dm" +#include "code\modules\examine\descriptions\machinery.dm" +#include "code\modules\examine\descriptions\medical.dm" +#include "code\modules\examine\descriptions\mobs.dm" +#include "code\modules\examine\descriptions\paperwork.dm" +#include "code\modules\examine\descriptions\smokeables.dm" +#include "code\modules\examine\descriptions\stacks.dm" +#include "code\modules\examine\descriptions\structures.dm" +#include "code\modules\examine\descriptions\turfs.dm" +#include "code\modules\examine\descriptions\weapons.dm" +#include "code\modules\ext_scripts\irc.dm" +#include "code\modules\fire_lighting\torches.dm" +#include "code\modules\flufftext\Dreaming.dm" +#include "code\modules\flufftext\TextFilters.dm" +#include "code\modules\food\recipes_microwave.dm" +#include "code\modules\food\replicator.dm" +#include "code\modules\games\boardgame.dm" +#include "code\modules\games\cardemon.dm" +#include "code\modules\games\cards.dm" +#include "code\modules\games\tarot.dm" +#include "code\modules\genetics\side_effects.dm" +#include "code\modules\ghosttrap\trap.dm" +#include "code\modules\goonchat\assets.dm" +#include "code\modules\goonchat\browserOutput.dm" +#include "code\modules\goonchat\helpers.dm" +#include "code\modules\holodeck\HolodeckControl.dm" +#include "code\modules\holodeck\HolodeckObjects.dm" +#include "code\modules\holodeck\HolodeckPrograms.dm" +#include "code\modules\hydroponics\_hydro_setup.dm" +#include "code\modules\hydroponics\grown.dm" +#include "code\modules\hydroponics\grown_inedible.dm" +#include "code\modules\hydroponics\grown_predefined.dm" +#include "code\modules\hydroponics\seed.dm" +#include "code\modules\hydroponics\seed_controller.dm" +#include "code\modules\hydroponics\seed_datums.dm" +#include "code\modules\hydroponics\seed_gene_mut.dm" +#include "code\modules\hydroponics\seed_machines.dm" +#include "code\modules\hydroponics\seed_mobs.dm" +#include "code\modules\hydroponics\seed_packets.dm" +#include "code\modules\hydroponics\seed_storage.dm" +#include "code\modules\hydroponics\spreading\spreading.dm" +#include "code\modules\hydroponics\spreading\spreading_growth.dm" +#include "code\modules\hydroponics\spreading\spreading_response.dm" +#include "code\modules\hydroponics\trays\tray.dm" +#include "code\modules\hydroponics\trays\tray_process.dm" +#include "code\modules\hydroponics\trays\tray_reagents.dm" +#include "code\modules\hydroponics\trays\tray_soil.dm" +#include "code\modules\hydroponics\trays\tray_tools.dm" +#include "code\modules\hydroponics\trays\tray_update_icons.dm" +#include "code\modules\integrated_electronics\_defines.dm" +#include "code\modules\integrated_electronics\arithmetic.dm" +#include "code\modules\integrated_electronics\assemblies.dm" +#include "code\modules\integrated_electronics\converters.dm" +#include "code\modules\integrated_electronics\coordinate.dm" +#include "code\modules\integrated_electronics\data_transfer.dm" +#include "code\modules\integrated_electronics\filters.dm" +#include "code\modules\integrated_electronics\input_output.dm" +#include "code\modules\integrated_electronics\logic.dm" +#include "code\modules\integrated_electronics\machine_printer.dm" +#include "code\modules\integrated_electronics\manipulation.dm" +#include "code\modules\integrated_electronics\memory.dm" +#include "code\modules\integrated_electronics\sensors.dm" +#include "code\modules\integrated_electronics\shells.dm" +#include "code\modules\integrated_electronics\time.dm" +#include "code\modules\integrated_electronics\tools.dm" +#include "code\modules\integrated_electronics\~defines.dm" +#include "code\modules\integrated_electronics\prefab\prefab.dm" +#include "code\modules\integrated_electronics\prefab\prefabs.dm" +#include "code\modules\item_worth\_helpers.dm" +#include "code\modules\item_worth\item_worth.dm" +#include "code\modules\item_worth\material_weapons.dm" +#include "code\modules\item_worth\materials.dm" +#include "code\modules\item_worth\reagents.dm" +#include "code\modules\item_worth\worths_list.dm" +#include "code\modules\item_worth\Value_procs\atoms.dm" +#include "code\modules\item_worth\Value_procs\mob.dm" +#include "code\modules\item_worth\Value_procs\obj.dm" +#include "code\modules\item_worth\Value_procs\obj\items.dm" +#include "code\modules\item_worth\Value_procs\obj\machinery.dm" +#include "code\modules\item_worth\Value_procs\obj\structures.dm" +#include "code\modules\library\lib_items.dm" +#include "code\modules\library\lib_machines.dm" +#include "code\modules\library\lib_readme.dm" +#include "code\modules\library\manuals\engineering.dm" +#include "code\modules\library\manuals\manuals.dm" +#include "code\modules\library\manuals\medical.dm" +#include "code\modules\library\manuals\nanotrasen.dm" +#include "code\modules\lighting\lighting_area.dm" +#include "code\modules\lighting\lighting_atom.dm" +#include "code\modules\lighting\lighting_corner.dm" +#include "code\modules\lighting\lighting_overlay.dm" +#include "code\modules\lighting\lighting_setup.dm" +#include "code\modules\lighting\lighting_source.dm" +#include "code\modules\lighting\lighting_turf.dm" +#include "code\modules\lighting\~lighting_undefs.dm" +#include "code\modules\lobby_music\_licenses.dm" +#include "code\modules\lobby_music\_lobby_music.dm" +#include "code\modules\locks\key.dm" +#include "code\modules\locks\lock.dm" +#include "code\modules\locks\lock_construct.dm" +#include "code\modules\maps\dmm_suite.dm" +#include "code\modules\maps\map_template.dm" +#include "code\modules\maps\reader.dm" +#include "code\modules\maps\ruins.dm" +#include "code\modules\maps\swapmaps.dm" +#include "code\modules\materials\material_recipes.dm" +#include "code\modules\materials\material_sheets.dm" +#include "code\modules\materials\material_synth.dm" +#include "code\modules\materials\materials.dm" +#include "code\modules\merchant\merchant_guns.dm" +#include "code\modules\merchant\merchant_machinery.dm" +#include "code\modules\merchant\merchant_programs.dm" +#include "code\modules\mining\abandonedcrates.dm" +#include "code\modules\mining\alloys.dm" +#include "code\modules\mining\coins.dm" +#include "code\modules\mining\machine_input_output_plates.dm" +#include "code\modules\mining\machine_processing.dm" +#include "code\modules\mining\machine_stacking.dm" +#include "code\modules\mining\machine_unloading.dm" +#include "code\modules\mining\mine_items.dm" +#include "code\modules\mining\mine_turfs.dm" +#include "code\modules\mining\mint.dm" +#include "code\modules\mining\ore.dm" +#include "code\modules\mining\ore_datum.dm" +#include "code\modules\mining\satchel_ore_boxdm.dm" +#include "code\modules\mining\drilling\drill.dm" +#include "code\modules\mining\drilling\scanner.dm" +#include "code\modules\mob\animations.dm" +#include "code\modules\mob\datum_stats_skills.dm" +#include "code\modules\mob\death.dm" +#include "code\modules\mob\gender.dm" +#include "code\modules\mob\hear_say.dm" +#include "code\modules\mob\holder.dm" +#include "code\modules\mob\inventory.dm" +#include "code\modules\mob\login.dm" +#include "code\modules\mob\logout.dm" +#include "code\modules\mob\mob.dm" +#include "code\modules\mob\mob_defines.dm" +#include "code\modules\mob\mob_helpers.dm" +#include "code\modules\mob\mob_movement.dm" +#include "code\modules\mob\mob_transformation_simple.dm" +#include "code\modules\mob\say.dm" +#include "code\modules\mob\shit_piss.dm" +#include "code\modules\mob\transform_procs.dm" +#include "code\modules\mob\typing_indicator.dm" +#include "code\modules\mob\update_icons.dm" +#include "code\modules\mob\grab\grab_datum.dm" +#include "code\modules\mob\grab\grab_object.dm" +#include "code\modules\mob\grab\grab_readme.dm" +#include "code\modules\mob\grab\nab\grab_nab.dm" +#include "code\modules\mob\grab\nab\nab_aggressive.dm" +#include "code\modules\mob\grab\nab\nab_kill.dm" +#include "code\modules\mob\grab\nab\nab_passive.dm" +#include "code\modules\mob\grab\normal\grab_normal.dm" +#include "code\modules\mob\grab\normal\norm_aggressive.dm" +#include "code\modules\mob\grab\normal\norm_kill.dm" +#include "code\modules\mob\grab\normal\norm_neck.dm" +#include "code\modules\mob\grab\normal\norm_passive.dm" +#include "code\modules\mob\grab\normal\norm_struggle.dm" +#include "code\modules\mob\grab\special\grab_special.dm" +#include "code\modules\mob\language\generic.dm" +#include "code\modules\mob\language\language.dm" +#include "code\modules\mob\language\monkey.dm" +#include "code\modules\mob\language\synthetic.dm" +#include "code\modules\mob\living\damage_procs.dm" +#include "code\modules\mob\living\death.dm" +#include "code\modules\mob\living\default_language.dm" +#include "code\modules\mob\living\floating_say.dm" +#include "code\modules\mob\living\life.dm" +#include "code\modules\mob\living\living.dm" +#include "code\modules\mob\living\living_defense.dm" +#include "code\modules\mob\living\living_defines.dm" +#include "code\modules\mob\living\living_powers.dm" +#include "code\modules\mob\living\login.dm" +#include "code\modules\mob\living\logout.dm" +#include "code\modules\mob\living\say.dm" +#include "code\modules\mob\living\bot\bot.dm" +#include "code\modules\mob\living\bot\cleanbot.dm" +#include "code\modules\mob\living\bot\ed209bot.dm" +#include "code\modules\mob\living\bot\farmbot.dm" +#include "code\modules\mob\living\bot\floorbot.dm" +#include "code\modules\mob\living\bot\medbot.dm" +#include "code\modules\mob\living\bot\mulebot.dm" +#include "code\modules\mob\living\bot\remotebot.dm" +#include "code\modules\mob\living\bot\secbot.dm" +#include "code\modules\mob\living\carbon\breathe.dm" +#include "code\modules\mob\living\carbon\carbon.dm" +#include "code\modules\mob\living\carbon\carbon_defense.dm" +#include "code\modules\mob\living\carbon\carbon_defines.dm" +#include "code\modules\mob\living\carbon\carbon_needs.dm" +#include "code\modules\mob\living\carbon\carbon_powers.dm" +#include "code\modules\mob\living\carbon\give.dm" +#include "code\modules\mob\living\carbon\hallucinations.dm" +#include "code\modules\mob\living\carbon\happiness_events.dm" +#include "code\modules\mob\living\carbon\life.dm" +#include "code\modules\mob\living\carbon\resist.dm" +#include "code\modules\mob\living\carbon\taste.dm" +#include "code\modules\mob\living\carbon\viruses.dm" +#include "code\modules\mob\living\carbon\brain\brain.dm" +#include "code\modules\mob\living\carbon\brain\death.dm" +#include "code\modules\mob\living\carbon\brain\life.dm" +#include "code\modules\mob\living\carbon\brain\login.dm" +#include "code\modules\mob\living\carbon\brain\MMI.dm" +#include "code\modules\mob\living\carbon\brain\robot.dm" +#include "code\modules\mob\living\carbon\brain\say.dm" +#include "code\modules\mob\living\carbon\human\appearance.dm" +#include "code\modules\mob\living\carbon\human\audible_emotes.dm" +#include "code\modules\mob\living\carbon\human\death.dm" +#include "code\modules\mob\living\carbon\human\emotions.dm" +#include "code\modules\mob\living\carbon\human\examine.dm" +#include "code\modules\mob\living\carbon\human\human.dm" +#include "code\modules\mob\living\carbon\human\human_attackhand.dm" +#include "code\modules\mob\living\carbon\human\human_damage.dm" +#include "code\modules\mob\living\carbon\human\human_defense.dm" +#include "code\modules\mob\living\carbon\human\human_defines.dm" +#include "code\modules\mob\living\carbon\human\human_helpers.dm" +#include "code\modules\mob\living\carbon\human\human_movement.dm" +#include "code\modules\mob\living\carbon\human\human_organs.dm" +#include "code\modules\mob\living\carbon\human\human_powers.dm" +#include "code\modules\mob\living\carbon\human\human_species.dm" +#include "code\modules\mob\living\carbon\human\inventory.dm" +#include "code\modules\mob\living\carbon\human\life.dm" +#include "code\modules\mob\living\carbon\human\login.dm" +#include "code\modules\mob\living\carbon\human\logout.dm" +#include "code\modules\mob\living\carbon\human\matt_combat.dm" +#include "code\modules\mob\living\carbon\human\MedicalSideEffects.dm" +#include "code\modules\mob\living\carbon\human\npcs.dm" +#include "code\modules\mob\living\carbon\human\say.dm" +#include "code\modules\mob\living\carbon\human\stripping.dm" +#include "code\modules\mob\living\carbon\human\unarmed_attack.dm" +#include "code\modules\mob\living\carbon\human\update_icons.dm" +#include "code\modules\mob\living\carbon\human\vision_cone.dm" +#include "code\modules\mob\living\carbon\human\weight.dm" +#include "code\modules\mob\living\carbon\human\whisper.dm" +#include "code\modules\mob\living\carbon\human\species\species.dm" +#include "code\modules\mob\living\carbon\human\species\species_attack.dm" +#include "code\modules\mob\living\carbon\human\species\species_getters.dm" +#include "code\modules\mob\living\carbon\human\species\species_helpers.dm" +#include "code\modules\mob\living\carbon\human\species\species_hud.dm" +#include "code\modules\mob\living\carbon\human\species\species_random.dm" +#include "code\modules\mob\living\carbon\human\species\station\children.dm" +#include "code\modules\mob\living\carbon\human\species\station\monkey.dm" +#include "code\modules\mob\living\carbon\human\species\station\station.dm" +#include "code\modules\mob\living\carbon\xenobiological\death.dm" +#include "code\modules\mob\living\carbon\xenobiological\examine.dm" +#include "code\modules\mob\living\carbon\xenobiological\hud.dm" +#include "code\modules\mob\living\carbon\xenobiological\items.dm" +#include "code\modules\mob\living\carbon\xenobiological\life.dm" +#include "code\modules\mob\living\carbon\xenobiological\powers.dm" +#include "code\modules\mob\living\carbon\xenobiological\say.dm" +#include "code\modules\mob\living\carbon\xenobiological\slime_AI.dm" +#include "code\modules\mob\living\carbon\xenobiological\subtypes.dm" +#include "code\modules\mob\living\carbon\xenobiological\update_icons.dm" +#include "code\modules\mob\living\carbon\xenobiological\xenobiological.dm" +#include "code\modules\mob\living\silicon\death.dm" +#include "code\modules\mob\living\silicon\laws.dm" +#include "code\modules\mob\living\silicon\login.dm" +#include "code\modules\mob\living\silicon\posi_brainmob.dm" +#include "code\modules\mob\living\silicon\say.dm" +#include "code\modules\mob\living\silicon\silicon.dm" +#include "code\modules\mob\living\silicon\subsystems.dm" +#include "code\modules\mob\living\silicon\ai\ai.dm" +#include "code\modules\mob\living\silicon\ai\ai_damage.dm" +#include "code\modules\mob\living\silicon\ai\ai_movement.dm" +#include "code\modules\mob\living\silicon\ai\death.dm" +#include "code\modules\mob\living\silicon\ai\examine.dm" +#include "code\modules\mob\living\silicon\ai\icons.dm" +#include "code\modules\mob\living\silicon\ai\latejoin.dm" +#include "code\modules\mob\living\silicon\ai\laws.dm" +#include "code\modules\mob\living\silicon\ai\life.dm" +#include "code\modules\mob\living\silicon\ai\login.dm" +#include "code\modules\mob\living\silicon\ai\logout.dm" +#include "code\modules\mob\living\silicon\ai\malf.dm" +#include "code\modules\mob\living\silicon\ai\power.dm" +#include "code\modules\mob\living\silicon\decoy\death.dm" +#include "code\modules\mob\living\silicon\decoy\decoy.dm" +#include "code\modules\mob\living\silicon\decoy\life.dm" +#include "code\modules\mob\living\silicon\pai\admin.dm" +#include "code\modules\mob\living\silicon\pai\death.dm" +#include "code\modules\mob\living\silicon\pai\examine.dm" +#include "code\modules\mob\living\silicon\pai\life.dm" +#include "code\modules\mob\living\silicon\pai\pai.dm" +#include "code\modules\mob\living\silicon\pai\paiwire.dm" +#include "code\modules\mob\living\silicon\pai\personality.dm" +#include "code\modules\mob\living\silicon\pai\recruit.dm" +#include "code\modules\mob\living\silicon\pai\say.dm" +#include "code\modules\mob\living\silicon\pai\software.dm" +#include "code\modules\mob\living\silicon\pai\software_modules.dm" +#include "code\modules\mob\living\silicon\robot\analyzer.dm" +#include "code\modules\mob\living\silicon\robot\component.dm" +#include "code\modules\mob\living\silicon\robot\custom_sprites.dm" +#include "code\modules\mob\living\silicon\robot\death.dm" +#include "code\modules\mob\living\silicon\robot\examine.dm" +#include "code\modules\mob\living\silicon\robot\inventory.dm" +#include "code\modules\mob\living\silicon\robot\laws.dm" +#include "code\modules\mob\living\silicon\robot\life.dm" +#include "code\modules\mob\living\silicon\robot\login.dm" +#include "code\modules\mob\living\silicon\robot\photos.dm" +#include "code\modules\mob\living\silicon\robot\preset.dm" +#include "code\modules\mob\living\silicon\robot\robot.dm" +#include "code\modules\mob\living\silicon\robot\robot_damage.dm" +#include "code\modules\mob\living\silicon\robot\robot_items.dm" +#include "code\modules\mob\living\silicon\robot\robot_modules.dm" +#include "code\modules\mob\living\silicon\robot\robot_movement.dm" +#include "code\modules\mob\living\silicon\robot\drone\drone.dm" +#include "code\modules\mob\living\silicon\robot\drone\drone_abilities.dm" +#include "code\modules\mob\living\silicon\robot\drone\drone_console.dm" +#include "code\modules\mob\living\silicon\robot\drone\drone_damage.dm" +#include "code\modules\mob\living\silicon\robot\drone\drone_items.dm" +#include "code\modules\mob\living\silicon\robot\drone\drone_manufacturer.dm" +#include "code\modules\mob\living\silicon\robot\drone\drone_remote_control.dm" +#include "code\modules\mob\living\silicon\robot\drone\drone_say.dm" +#include "code\modules\mob\living\simple_animal\parrot.dm" +#include "code\modules\mob\living\simple_animal\shade.dm" +#include "code\modules\mob\living\simple_animal\shafra.dm" +#include "code\modules\mob\living\simple_animal\simple_animal.dm" +#include "code\modules\mob\living\simple_animal\worm.dm" +#include "code\modules\mob\living\simple_animal\borer\borer.dm" +#include "code\modules\mob\living\simple_animal\borer\borer_captive.dm" +#include "code\modules\mob\living\simple_animal\borer\borer_powers.dm" +#include "code\modules\mob\living\simple_animal\borer\say.dm" +#include "code\modules\mob\living\simple_animal\constructs\constructs.dm" +#include "code\modules\mob\living\simple_animal\constructs\soulstone.dm" +#include "code\modules\mob\living\simple_animal\familiars\familiars.dm" +#include "code\modules\mob\living\simple_animal\friendly\cat.dm" +#include "code\modules\mob\living\simple_animal\friendly\corgi.dm" +#include "code\modules\mob\living\simple_animal\friendly\crab.dm" +#include "code\modules\mob\living\simple_animal\friendly\farm_animals.dm" +#include "code\modules\mob\living\simple_animal\friendly\lizard.dm" +#include "code\modules\mob\living\simple_animal\friendly\mouse.dm" +#include "code\modules\mob\living\simple_animal\friendly\mushroom.dm" +#include "code\modules\mob\living\simple_animal\friendly\slime.dm" +#include "code\modules\mob\living\simple_animal\friendly\spiderbot.dm" +#include "code\modules\mob\living\simple_animal\friendly\tomato.dm" +#include "code\modules\mob\living\simple_animal\hostile\alien.dm" +#include "code\modules\mob\living\simple_animal\hostile\armalis.dm" +#include "code\modules\mob\living\simple_animal\hostile\bat.dm" +#include "code\modules\mob\living\simple_animal\hostile\bear.dm" +#include "code\modules\mob\living\simple_animal\hostile\carp.dm" +#include "code\modules\mob\living\simple_animal\hostile\creature.dm" +#include "code\modules\mob\living\simple_animal\hostile\faithful_hound.dm" +#include "code\modules\mob\living\simple_animal\hostile\faithless.dm" +#include "code\modules\mob\living\simple_animal\hostile\giant_spider.dm" +#include "code\modules\mob\living\simple_animal\hostile\hivebot.dm" +#include "code\modules\mob\living\simple_animal\hostile\hostile.dm" +#include "code\modules\mob\living\simple_animal\hostile\mimic.dm" +#include "code\modules\mob\living\simple_animal\hostile\mining.dm" +#include "code\modules\mob\living\simple_animal\hostile\pike.dm" +#include "code\modules\mob\living\simple_animal\hostile\pirate.dm" +#include "code\modules\mob\living\simple_animal\hostile\russian.dm" +#include "code\modules\mob\living\simple_animal\hostile\syndicate.dm" +#include "code\modules\mob\living\simple_animal\hostile\tree.dm" +#include "code\modules\mob\living\simple_animal\hostile\vagrant.dm" +#include "code\modules\mob\living\simple_animal\hostile\voxslug.dm" +#include "code\modules\mob\living\simple_animal\hostile\commanded\_command_defines.dm" +#include "code\modules\mob\living\simple_animal\hostile\commanded\bear_companion.dm" +#include "code\modules\mob\living\simple_animal\hostile\commanded\commanded.dm" +#include "code\modules\mob\living\simple_animal\hostile\commanded\nanomachines.dm" +#include "code\modules\mob\living\simple_animal\hostile\retaliate\clown.dm" +#include "code\modules\mob\living\simple_animal\hostile\retaliate\drone.dm" +#include "code\modules\mob\living\simple_animal\hostile\retaliate\exoplanet.dm" +#include "code\modules\mob\living\simple_animal\hostile\retaliate\rat.dm" +#include "code\modules\mob\living\simple_animal\hostile\retaliate\retaliate.dm" +#include "code\modules\mob\living\simple_animal\hostile\retaliate\roach.dm" +#include "code\modules\mob\new_player\login.dm" +#include "code\modules\mob\new_player\logout.dm" +#include "code\modules\mob\new_player\new_player.dm" +#include "code\modules\mob\new_player\poll.dm" +#include "code\modules\mob\new_player\preferences_setup.dm" +#include "code\modules\mob\new_player\sprite_accessories.dm" +#include "code\modules\mob\observer\observer.dm" +#include "code\modules\mob\observer\freelook\chunk.dm" +#include "code\modules\mob\observer\freelook\eye.dm" +#include "code\modules\mob\observer\freelook\life.dm" +#include "code\modules\mob\observer\freelook\logging.dm" +#include "code\modules\mob\observer\freelook\read_me.dm" +#include "code\modules\mob\observer\freelook\update_triggers.dm" +#include "code\modules\mob\observer\freelook\visualnet.dm" +#include "code\modules\mob\observer\freelook\ai\cameranet.dm" +#include "code\modules\mob\observer\freelook\ai\chunk.dm" +#include "code\modules\mob\observer\freelook\ai\eye.dm" +#include "code\modules\mob\observer\freelook\ai\update_triggers.dm" +#include "code\modules\mob\observer\ghost\follow.dm" +#include "code\modules\mob\observer\ghost\ghost.dm" +#include "code\modules\mob\observer\ghost\login.dm" +#include "code\modules\mob\observer\ghost\logout.dm" +#include "code\modules\mob\observer\ghost\say.dm" +#include "code\modules\mob\observer\virtual\_constants.dm" +#include "code\modules\mob\observer\virtual\base.dm" +#include "code\modules\mob\observer\virtual\helpers.dm" +#include "code\modules\mob\observer\virtual\mob.dm" +#include "code\modules\modular_computers\laptop_vendor.dm" +#include "code\modules\modular_computers\computers\modular_computer\core.dm" +#include "code\modules\modular_computers\computers\modular_computer\damage.dm" +#include "code\modules\modular_computers\computers\modular_computer\hardware.dm" +#include "code\modules\modular_computers\computers\modular_computer\interaction.dm" +#include "code\modules\modular_computers\computers\modular_computer\power.dm" +#include "code\modules\modular_computers\computers\modular_computer\ui.dm" +#include "code\modules\modular_computers\computers\modular_computer\variables.dm" +#include "code\modules\modular_computers\computers\subtypes\dev_console.dm" +#include "code\modules\modular_computers\computers\subtypes\dev_laptop.dm" +#include "code\modules\modular_computers\computers\subtypes\dev_tablet.dm" +#include "code\modules\modular_computers\computers\subtypes\dev_telescreen.dm" +#include "code\modules\modular_computers\computers\subtypes\preset_console.dm" +#include "code\modules\modular_computers\computers\subtypes\preset_laptop.dm" +#include "code\modules\modular_computers\computers\subtypes\preset_tablet.dm" +#include "code\modules\modular_computers\computers\subtypes\preset_telescreen.dm" +#include "code\modules\modular_computers\file_system\computer_file.dm" +#include "code\modules\modular_computers\file_system\crew_record.dm" +#include "code\modules\modular_computers\file_system\data.dm" +#include "code\modules\modular_computers\file_system\manifest.dm" +#include "code\modules\modular_computers\file_system\news_article.dm" +#include "code\modules\modular_computers\file_system\program.dm" +#include "code\modules\modular_computers\file_system\program_events.dm" +#include "code\modules\modular_computers\file_system\programs\antagonist\access_decrypter.dm" +#include "code\modules\modular_computers\file_system\programs\antagonist\dos.dm" +#include "code\modules\modular_computers\file_system\programs\antagonist\hacked_camera.dm" +#include "code\modules\modular_computers\file_system\programs\antagonist\revelation.dm" +#include "code\modules\modular_computers\file_system\programs\command\card.dm" +#include "code\modules\modular_computers\file_system\programs\command\comm.dm" +#include "code\modules\modular_computers\file_system\programs\engineering\alarm_monitor.dm" +#include "code\modules\modular_computers\file_system\programs\engineering\atmos_control.dm" +#include "code\modules\modular_computers\file_system\programs\engineering\power_monitor.dm" +#include "code\modules\modular_computers\file_system\programs\engineering\rcon_console.dm" +#include "code\modules\modular_computers\file_system\programs\engineering\shields_monitor.dm" +#include "code\modules\modular_computers\file_system\programs\engineering\supermatter_monitor.dm" +#include "code\modules\modular_computers\file_system\programs\generic\camera.dm" +#include "code\modules\modular_computers\file_system\programs\generic\configurator.dm" +#include "code\modules\modular_computers\file_system\programs\generic\docks.dm" +#include "code\modules\modular_computers\file_system\programs\generic\email_client.dm" +#include "code\modules\modular_computers\file_system\programs\generic\file_browser.dm" +#include "code\modules\modular_computers\file_system\programs\generic\game.dm" +#include "code\modules\modular_computers\file_system\programs\generic\library.dm" +#include "code\modules\modular_computers\file_system\programs\generic\news_browser.dm" +#include "code\modules\modular_computers\file_system\programs\generic\ntdownloader.dm" +#include "code\modules\modular_computers\file_system\programs\generic\ntnrc_client.dm" +#include "code\modules\modular_computers\file_system\programs\generic\nttransfer.dm" +#include "code\modules\modular_computers\file_system\programs\generic\records.dm" +#include "code\modules\modular_computers\file_system\programs\generic\supply.dm" +#include "code\modules\modular_computers\file_system\programs\generic\wordprocessor.dm" +#include "code\modules\modular_computers\file_system\programs\medical\suit_sensors.dm" +#include "code\modules\modular_computers\file_system\programs\research\ai_restorer.dm" +#include "code\modules\modular_computers\file_system\programs\research\email_administration.dm" +#include "code\modules\modular_computers\file_system\programs\research\ntmonitor.dm" +#include "code\modules\modular_computers\file_system\programs\security\digitalwarrant.dm" +#include "code\modules\modular_computers\hardware\_hardware.dm" +#include "code\modules\modular_computers\hardware\ai_slot.dm" +#include "code\modules\modular_computers\hardware\battery_module.dm" +#include "code\modules\modular_computers\hardware\card_slot.dm" +#include "code\modules\modular_computers\hardware\hard_drive.dm" +#include "code\modules\modular_computers\hardware\nano_printer.dm" +#include "code\modules\modular_computers\hardware\network_card.dm" +#include "code\modules\modular_computers\hardware\portable_hard_drive.dm" +#include "code\modules\modular_computers\hardware\processor_unit.dm" +#include "code\modules\modular_computers\hardware\tesla_link.dm" +#include "code\modules\modular_computers\NTNet\NTNet.dm" +#include "code\modules\modular_computers\NTNet\NTNet_relay.dm" +#include "code\modules\modular_computers\NTNet\emails\email_account.dm" +#include "code\modules\modular_computers\NTNet\emails\email_message.dm" +#include "code\modules\modular_computers\NTNet\NTNRC\conversation.dm" +#include "code\modules\multiz\_stubs.dm" +#include "code\modules\multiz\basic.dm" +#include "code\modules\multiz\movement.dm" +#include "code\modules\multiz\pipes.dm" +#include "code\modules\multiz\structures.dm" +#include "code\modules\multiz\turf.dm" +#include "code\modules\multiz\zshadow.dm" +#include "code\modules\nano\nanoexternal.dm" +#include "code\modules\nano\nanomanager.dm" +#include "code\modules\nano\nanomapgen.dm" +#include "code\modules\nano\nanoui.dm" +#include "code\modules\nano\interaction\admin.dm" +#include "code\modules\nano\interaction\base.dm" +#include "code\modules\nano\interaction\conscious.dm" +#include "code\modules\nano\interaction\contained.dm" +#include "code\modules\nano\interaction\default.dm" +#include "code\modules\nano\interaction\hands.dm" +#include "code\modules\nano\interaction\interactive.dm" +#include "code\modules\nano\interaction\inventory.dm" +#include "code\modules\nano\interaction\inventory_deep.dm" +#include "code\modules\nano\interaction\outside.dm" +#include "code\modules\nano\interaction\physical.dm" +#include "code\modules\nano\interaction\remote.dm" +#include "code\modules\nano\interaction\self.dm" +#include "code\modules\nano\interaction\zlevel.dm" +#include "code\modules\nano\modules\human_appearance.dm" +#include "code\modules\nano\modules\law_manager.dm" +#include "code\modules\nano\modules\nano_module.dm" +#include "code\modules\organs\_organ_setup.dm" +#include "code\modules\organs\blood.dm" +#include "code\modules\organs\organ.dm" +#include "code\modules\organs\pain.dm" +#include "code\modules\organs\robolimbs.dm" +#include "code\modules\organs\external\_external.dm" +#include "code\modules\organs\external\_external_damage.dm" +#include "code\modules\organs\external\_external_icons.dm" +#include "code\modules\organs\external\head.dm" +#include "code\modules\organs\external\machine.dm" +#include "code\modules\organs\external\standard.dm" +#include "code\modules\organs\external\stump.dm" +#include "code\modules\organs\external\unbreakable.dm" +#include "code\modules\organs\external\vox.dm" +#include "code\modules\organs\external\wounds\wound.dm" +#include "code\modules\organs\external\wounds\wound_types.dm" +#include "code\modules\organs\internal\_internal.dm" +#include "code\modules\organs\internal\appendix.dm" +#include "code\modules\organs\internal\borer.dm" +#include "code\modules\organs\internal\brain.dm" +#include "code\modules\organs\internal\eyes.dm" +#include "code\modules\organs\internal\heart.dm" +#include "code\modules\organs\internal\kidneys.dm" +#include "code\modules\organs\internal\liver.dm" +#include "code\modules\organs\internal\lungs.dm" +#include "code\modules\organs\internal\posibrain.dm" +#include "code\modules\organs\internal\stack.dm" +#include "code\modules\organs\subtypes\nabber_organ.dm" +#include "code\modules\overmap\_defines.dm" +#include "code\modules\overmap\overmap_shuttle.dm" +#include "code\modules\overmap\sectors.dm" +#include "code\modules\overmap\spacetravel.dm" +#include "code\modules\overmap\events\event.dm" +#include "code\modules\overmap\exoplanets\desert.dm" +#include "code\modules\overmap\exoplanets\exoplanet.dm" +#include "code\modules\overmap\exoplanets\garbage.dm" +#include "code\modules\overmap\exoplanets\grass.dm" +#include "code\modules\overmap\exoplanets\mountain.dm" +#include "code\modules\overmap\exoplanets\snow.dm" +#include "code\modules\overmap\ships\ship.dm" +#include "code\modules\overmap\ships\computers\engine_control.dm" +#include "code\modules\overmap\ships\computers\helm.dm" +#include "code\modules\overmap\ships\computers\sensors.dm" +#include "code\modules\overmap\ships\computers\shuttle.dm" +#include "code\modules\overmap\ships\engines\engine.dm" +#include "code\modules\overmap\ships\engines\gas_thruster.dm" +#include "code\modules\paperwork\adminpaper.dm" +#include "code\modules\paperwork\carbonpaper.dm" +#include "code\modules\paperwork\clipboard.dm" +#include "code\modules\paperwork\faxmachine.dm" +#include "code\modules\paperwork\filingcabinet.dm" +#include "code\modules\paperwork\folders.dm" +#include "code\modules\paperwork\handlabeler.dm" +#include "code\modules\paperwork\paper.dm" +#include "code\modules\paperwork\paper_bundle.dm" +#include "code\modules\paperwork\paperbin.dm" +#include "code\modules\paperwork\papershredder.dm" +#include "code\modules\paperwork\pen.dm" +#include "code\modules\paperwork\photocopier.dm" +#include "code\modules\paperwork\photography.dm" +#include "code\modules\paperwork\silicon_photography.dm" +#include "code\modules\paperwork\stamps.dm" +#include "code\modules\placeholder\placeholder.dm" +#include "code\modules\power\apc.dm" +#include "code\modules\power\batteryrack.dm" +#include "code\modules\power\breaker_box.dm" +#include "code\modules\power\cable.dm" +#include "code\modules\power\cell.dm" +#include "code\modules\power\debug_items.dm" +#include "code\modules\power\generator.dm" +#include "code\modules\power\gravitygenerator.dm" +#include "code\modules\power\lighting.dm" +#include "code\modules\power\port_gen.dm" +#include "code\modules\power\power.dm" +#include "code\modules\power\powernet.dm" +#include "code\modules\power\smes.dm" +#include "code\modules\power\smes_construction.dm" +#include "code\modules\power\smes_presets.dm" +#include "code\modules\power\solar.dm" +#include "code\modules\power\terminal.dm" +#include "code\modules\power\tracker.dm" +#include "code\modules\power\turbine.dm" +#include "code\modules\power\antimatter\containment_jar.dm" +#include "code\modules\power\antimatter\control.dm" +#include "code\modules\power\antimatter\shielding.dm" +#include "code\modules\power\fusion\_setup.dm" +#include "code\modules\power\fusion\fusion_circuits.dm" +#include "code\modules\power\fusion\fusion_particle_catcher.dm" +#include "code\modules\power\fusion\fusion_reactions.dm" +#include "code\modules\power\fusion\core\_core.dm" +#include "code\modules\power\fusion\core\core_control.dm" +#include "code\modules\power\fusion\core\core_field.dm" +#include "code\modules\power\fusion\fuel_assembly\fuel_assembly.dm" +#include "code\modules\power\fusion\fuel_assembly\fuel_compressor.dm" +#include "code\modules\power\fusion\fuel_assembly\fuel_control.dm" +#include "code\modules\power\fusion\fuel_assembly\fuel_injector.dm" +#include "code\modules\power\fusion\gyrotron\gyrotron.dm" +#include "code\modules\power\fusion\gyrotron\gyrotron_control.dm" +#include "code\modules\power\sensors\powernet_sensor.dm" +#include "code\modules\power\sensors\sensor_monitoring.dm" +#include "code\modules\power\singularity\act.dm" +#include "code\modules\power\singularity\collector.dm" +#include "code\modules\power\singularity\containment_field.dm" +#include "code\modules\power\singularity\emitter.dm" +#include "code\modules\power\singularity\field_generator.dm" +#include "code\modules\power\singularity\generator.dm" +#include "code\modules\power\singularity\singularity.dm" +#include "code\modules\power\singularity\particle_accelerator\particle.dm" +#include "code\modules\power\singularity\particle_accelerator\particle_accelerator.dm" +#include "code\modules\power\singularity\particle_accelerator\particle_chamber.dm" +#include "code\modules\power\singularity\particle_accelerator\particle_control.dm" +#include "code\modules\power\singularity\particle_accelerator\particle_emitter.dm" +#include "code\modules\power\singularity\particle_accelerator\particle_power.dm" +#include "code\modules\power\singularity\particle_accelerator\sunreactor.dm" +#include "code\modules\projectiles\ammunition.dm" +#include "code\modules\projectiles\effects.dm" +#include "code\modules\projectiles\gun.dm" +#include "code\modules\projectiles\projectile_new.dm" +#include "code\modules\projectiles\ammunition\boxes.dm" +#include "code\modules\projectiles\ammunition\bullets.dm" +#include "code\modules\projectiles\ammunition\handfuls.dm" +#include "code\modules\projectiles\ammunition\magnetic.dm" +#include "code\modules\projectiles\guns\energy.dm" +#include "code\modules\projectiles\guns\launcher.dm" +#include "code\modules\projectiles\guns\projectile.dm" +#include "code\modules\projectiles\guns\energy\laser.dm" +#include "code\modules\projectiles\guns\energy\nuclear.dm" +#include "code\modules\projectiles\guns\energy\pulse.dm" +#include "code\modules\projectiles\guns\energy\special.dm" +#include "code\modules\projectiles\guns\energy\stun.dm" +#include "code\modules\projectiles\guns\launcher\alien.dm" +#include "code\modules\projectiles\guns\launcher\crossbow.dm" +#include "code\modules\projectiles\guns\launcher\grenade_launcher.dm" +#include "code\modules\projectiles\guns\launcher\net.dm" +#include "code\modules\projectiles\guns\launcher\pneumatic.dm" +#include "code\modules\projectiles\guns\launcher\rocket.dm" +#include "code\modules\projectiles\guns\launcher\slugsling.dm" +#include "code\modules\projectiles\guns\launcher\syringe_gun.dm" +#include "code\modules\projectiles\guns\projectile\automatic.dm" +#include "code\modules\projectiles\guns\projectile\dartgun.dm" +#include "code\modules\projectiles\guns\projectile\detective.dm" +#include "code\modules\projectiles\guns\projectile\mattguns.dm" +#include "code\modules\projectiles\guns\projectile\mortar.dm" +#include "code\modules\projectiles\guns\projectile\pistol.dm" +#include "code\modules\projectiles\guns\projectile\revolver.dm" +#include "code\modules\projectiles\guns\projectile\shotgun.dm" +#include "code\modules\projectiles\guns\projectile\sniper.dm" +#include "code\modules\projectiles\projectile\animate.dm" +#include "code\modules\projectiles\projectile\beams.dm" +#include "code\modules\projectiles\projectile\bullets.dm" +#include "code\modules\projectiles\projectile\change.dm" +#include "code\modules\projectiles\projectile\energy.dm" +#include "code\modules\projectiles\projectile\force.dm" +#include "code\modules\projectiles\projectile\special.dm" +#include "code\modules\projectiles\projectile\trace.dm" +#include "code\modules\projectiles\projectile_effects\projectile_effects.dm" +#include "code\modules\projectiles\projectile_effects\projectile_impact.dm" +#include "code\modules\projectiles\projectile_effects\projectile_muzzle.dm" +#include "code\modules\projectiles\projectile_effects\projectile_tracer.dm" +#include "code\modules\projectiles\targeting\targeting_client.dm" +#include "code\modules\projectiles\targeting\targeting_gun.dm" +#include "code\modules\projectiles\targeting\targeting_mob.dm" +#include "code\modules\projectiles\targeting\targeting_overlay.dm" +#include "code\modules\projectiles\targeting\targeting_triggers.dm" +#include "code\modules\prometheus_metrics\_defines.dm" +#include "code\modules\prometheus_metrics\metric_family.dm" +#include "code\modules\prometheus_metrics\metrics.dm" +#include "code\modules\prometheus_metrics\metrics\byond.dm" +#include "code\modules\prometheus_metrics\metrics\ss13.dm" +#include "code\modules\random_map\_random_map_setup.dm" +#include "code\modules\random_map\random_map.dm" +#include "code\modules\random_map\random_map_verbs.dm" +#include "code\modules\random_map\automata\automata.dm" +#include "code\modules\random_map\automata\caves.dm" +#include "code\modules\random_map\building\building.dm" +#include "code\modules\random_map\drop\drop_types.dm" +#include "code\modules\random_map\drop\droppod.dm" +#include "code\modules\random_map\drop\droppod_doors.dm" +#include "code\modules\random_map\drop\supply.dm" +#include "code\modules\random_map\dungeon\predefined.dm" +#include "code\modules\random_map\dungeon\room.dm" +#include "code\modules\random_map\dungeon\room_generation.dm" +#include "code\modules\random_map\dungeon\room_theme.dm" +#include "code\modules\random_map\dungeon\winding_dungeon.dm" +#include "code\modules\random_map\dungeon\winding_dungeon_verb.dm" +#include "code\modules\random_map\dungeon\rooms\mimic_room.dm" +#include "code\modules\random_map\dungeon\rooms\monster_room.dm" +#include "code\modules\random_map\dungeon\rooms\tomb.dm" +#include "code\modules\random_map\mazes\maze.dm" +#include "code\modules\random_map\mazes\maze_cell.dm" +#include "code\modules\random_map\noise\desert.dm" +#include "code\modules\random_map\noise\magma.dm" +#include "code\modules\random_map\noise\noise.dm" +#include "code\modules\random_map\noise\ore.dm" +#include "code\modules\random_map\noise\tundra.dm" +#include "code\modules\reagents\Chemistry-Colours.dm" +#include "code\modules\reagents\Chemistry-Holder.dm" +#include "code\modules\reagents\Chemistry-Logging.dm" +#include "code\modules\reagents\Chemistry-Machinery.dm" +#include "code\modules\reagents\Chemistry-Metabolism.dm" +#include "code\modules\reagents\Chemistry-Readme.dm" +#include "code\modules\reagents\Chemistry-Reagents.dm" +#include "code\modules\reagents\Chemistry-Recipes.dm" +#include "code\modules\reagents\reagent_containers.dm" +#include "code\modules\reagents\reagent_dispenser.dm" +#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Core.dm" +#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Dispenser.dm" +#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Food-Drinks.dm" +#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Helpers.dm" +#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Medicine.dm" +#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Other.dm" +#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Toxins.dm" +#include "code\modules\reagents\dispenser\_defines.dm" +#include "code\modules\reagents\dispenser\cartridge.dm" +#include "code\modules\reagents\dispenser\cartridge_presets.dm" +#include "code\modules\reagents\dispenser\cartridge_spawn.dm" +#include "code\modules\reagents\dispenser\dispenser2.dm" +#include "code\modules\reagents\dispenser\dispenser_presets.dm" +#include "code\modules\reagents\dispenser\supply.dm" +#include "code\modules\reagents\reagent_containers\blood_pack.dm" +#include "code\modules\reagents\reagent_containers\borghydro.dm" +#include "code\modules\reagents\reagent_containers\dropper.dm" +#include "code\modules\reagents\reagent_containers\food.dm" +#include "code\modules\reagents\reagent_containers\glass.dm" +#include "code\modules\reagents\reagent_containers\hypospray.dm" +#include "code\modules\reagents\reagent_containers\pill.dm" +#include "code\modules\reagents\reagent_containers\spray.dm" +#include "code\modules\reagents\reagent_containers\syringes.dm" +#include "code\modules\reagents\reagent_containers\drinkingglass\drinkingglass.dm" +#include "code\modules\reagents\reagent_containers\drinkingglass\extras.dm" +#include "code\modules\reagents\reagent_containers\drinkingglass\glass_boxes.dm" +#include "code\modules\reagents\reagent_containers\drinkingglass\glass_types.dm" +#include "code\modules\reagents\reagent_containers\drinkingglass\shaker.dm" +#include "code\modules\reagents\reagent_containers\food\cans.dm" +#include "code\modules\reagents\reagent_containers\food\condiment.dm" +#include "code\modules\reagents\reagent_containers\food\drinks.dm" +#include "code\modules\reagents\reagent_containers\food\lunch.dm" +#include "code\modules\reagents\reagent_containers\food\sandwich.dm" +#include "code\modules\reagents\reagent_containers\food\snacks.dm" +#include "code\modules\reagents\reagent_containers\food\drinks\bottle.dm" +#include "code\modules\reagents\reagent_containers\food\drinks\jar.dm" +#include "code\modules\reagents\reagent_containers\food\drinks\bottle\robot.dm" +#include "code\modules\reagents\reagent_containers\food\snacks\meat.dm" +#include "code\modules\reagents\reagent_containers\glass\bottle.dm" +#include "code\modules\reagents\reagent_containers\glass\jar.dm" +#include "code\modules\reagents\reagent_containers\glass\supply.dm" +#include "code\modules\reagents\reagent_containers\glass\bottle\robot.dm" +#include "code\modules\recycling\conveyor2.dm" +#include "code\modules\recycling\disposal-construction.dm" +#include "code\modules\recycling\disposal.dm" +#include "code\modules\recycling\sortingmachinery.dm" +#include "code\modules\research\circuitprinter.dm" +#include "code\modules\research\designs.dm" +#include "code\modules\research\destructive_analyzer.dm" +#include "code\modules\research\mechfab_designs.dm" +#include "code\modules\research\message_server.dm" +#include "code\modules\research\protolathe.dm" +#include "code\modules\research\rd-readme.dm" +#include "code\modules\research\rdconsole.dm" +#include "code\modules\research\rdmachines.dm" +#include "code\modules\research\research.dm" +#include "code\modules\research\server.dm" +#include "code\modules\research\stock_parts.dm" +#include "code\modules\scripting\Errors.dm" +#include "code\modules\scripting\IDE.dm" +#include "code\modules\scripting\Options.dm" +#include "code\modules\scripting\stack.dm" +#include "code\modules\scripting\AST\AST Nodes.dm" +#include "code\modules\scripting\AST\Blocks.dm" +#include "code\modules\scripting\AST\Statements.dm" +#include "code\modules\scripting\AST\Operators\Binary Operators.dm" +#include "code\modules\scripting\AST\Operators\Unary Operators.dm" +#include "code\modules\scripting\Implementations\_Logic.dm" +#include "code\modules\scripting\Implementations\Telecomms.dm" +#include "code\modules\scripting\Interpreter\Evaluation.dm" +#include "code\modules\scripting\Interpreter\Interaction.dm" +#include "code\modules\scripting\Interpreter\Interpreter.dm" +#include "code\modules\scripting\Interpreter\Scope.dm" +#include "code\modules\scripting\Parser\Expressions.dm" +#include "code\modules\scripting\Parser\Keywords.dm" +#include "code\modules\scripting\Parser\Parser.dm" +#include "code\modules\scripting\Scanner\Scanner.dm" +#include "code\modules\scripting\Scanner\Tokens.dm" +#include "code\modules\security levels\keycard authentication.dm" +#include "code\modules\shield_generators\floor_diffuser.dm" +#include "code\modules\shield_generators\handheld_diffuser.dm" +#include "code\modules\shield_generators\modes.dm" +#include "code\modules\shield_generators\shield.dm" +#include "code\modules\shield_generators\shield_generator.dm" +#include "code\modules\shieldgen\emergency_shield.dm" +#include "code\modules\shieldgen\energy_field.dm" +#include "code\modules\shieldgen\shieldwallgen.dm" +#include "code\modules\shuttles\_defines.dm" +#include "code\modules\shuttles\antagonist.dm" +#include "code\modules\shuttles\departmental.dm" +#include "code\modules\shuttles\escape_pods.dm" +#include "code\modules\shuttles\landmarks.dm" +#include "code\modules\shuttles\shuttle.dm" +#include "code\modules\shuttles\shuttle_autodock.dm" +#include "code\modules\shuttles\shuttle_console.dm" +#include "code\modules\shuttles\shuttle_console_multi.dm" +#include "code\modules\shuttles\shuttle_emergency.dm" +#include "code\modules\shuttles\shuttle_ferry.dm" +#include "code\modules\shuttles\shuttle_specops.dm" +#include "code\modules\shuttles\shuttle_supply.dm" +#include "code\modules\shuttles\shuttles_multi.dm" +#include "code\modules\spells\artifacts.dm" +#include "code\modules\spells\construct_spells.dm" +#include "code\modules\spells\contracts.dm" +#include "code\modules\spells\no_clothes.dm" +#include "code\modules\spells\racial_wizard.dm" +#include "code\modules\spells\spell_code.dm" +#include "code\modules\spells\spell_projectile.dm" +#include "code\modules\spells\spellbook.dm" +#include "code\modules\spells\spells.dm" +#include "code\modules\spells\aoe_turf\aoe_turf.dm" +#include "code\modules\spells\aoe_turf\blink.dm" +#include "code\modules\spells\aoe_turf\charge.dm" +#include "code\modules\spells\aoe_turf\disable_tech.dm" +#include "code\modules\spells\aoe_turf\drain_blood.dm" +#include "code\modules\spells\aoe_turf\knock.dm" +#include "code\modules\spells\aoe_turf\smoke.dm" +#include "code\modules\spells\aoe_turf\summons.dm" +#include "code\modules\spells\aoe_turf\conjure\conjure.dm" +#include "code\modules\spells\aoe_turf\conjure\construct.dm" +#include "code\modules\spells\aoe_turf\conjure\druidic_spells.dm" +#include "code\modules\spells\aoe_turf\conjure\faithful_hound.dm" +#include "code\modules\spells\aoe_turf\conjure\force_portal.dm" +#include "code\modules\spells\aoe_turf\conjure\forcewall.dm" +#include "code\modules\spells\aoe_turf\conjure\grove.dm" +#include "code\modules\spells\artifacts\monster_manual.dm" +#include "code\modules\spells\artifacts\storage.dm" +#include "code\modules\spells\general\acid_spray.dm" +#include "code\modules\spells\general\area_teleport.dm" +#include "code\modules\spells\general\contract_spells.dm" +#include "code\modules\spells\general\create_air.dm" +#include "code\modules\spells\general\mark_recall.dm" +#include "code\modules\spells\general\radiant_aura.dm" +#include "code\modules\spells\general\return_master.dm" +#include "code\modules\spells\general\tear_veil.dm" +#include "code\modules\spells\hand\blood_shards.dm" +#include "code\modules\spells\hand\burning_grip.dm" +#include "code\modules\spells\hand\entangle.dm" +#include "code\modules\spells\hand\hand.dm" +#include "code\modules\spells\hand\hand_item.dm" +#include "code\modules\spells\hand\slippery_surface.dm" +#include "code\modules\spells\spellbook\battlemage.dm" +#include "code\modules\spells\spellbook\cleric.dm" +#include "code\modules\spells\spellbook\druid.dm" +#include "code\modules\spells\spellbook\spatial.dm" +#include "code\modules\spells\spellbook\standard.dm" +#include "code\modules\spells\spellbook\student.dm" +#include "code\modules\spells\targeted\cleric_spells.dm" +#include "code\modules\spells\targeted\ethereal_jaunt.dm" +#include "code\modules\spells\targeted\genetic.dm" +#include "code\modules\spells\targeted\harvest.dm" +#include "code\modules\spells\targeted\shapeshift.dm" +#include "code\modules\spells\targeted\shatter_mind.dm" +#include "code\modules\spells\targeted\shift.dm" +#include "code\modules\spells\targeted\subjugate.dm" +#include "code\modules\spells\targeted\swap.dm" +#include "code\modules\spells\targeted\targeted.dm" +#include "code\modules\spells\targeted\torment.dm" +#include "code\modules\spells\targeted\equip\dyrnwyn.dm" +#include "code\modules\spells\targeted\equip\equip.dm" +#include "code\modules\spells\targeted\equip\holy_relic.dm" +#include "code\modules\spells\targeted\equip\horsemask.dm" +#include "code\modules\spells\targeted\equip\party_hardy.dm" +#include "code\modules\spells\targeted\equip\seed.dm" +#include "code\modules\spells\targeted\equip\shield.dm" +#include "code\modules\spells\targeted\projectile\dumbfire.dm" +#include "code\modules\spells\targeted\projectile\fireball.dm" +#include "code\modules\spells\targeted\projectile\magic_missile.dm" +#include "code\modules\spells\targeted\projectile\passage.dm" +#include "code\modules\spells\targeted\projectile\projectile.dm" +#include "code\modules\spells\targeted\projectile\stuncuff.dm" +#include "code\modules\supermatter\setup_supermatter.dm" +#include "code\modules\supermatter\supermatter.dm" +#include "code\modules\surgery\_defines.dm" +#include "code\modules\surgery\bones.dm" +#include "code\modules\surgery\encased.dm" +#include "code\modules\surgery\face.dm" +#include "code\modules\surgery\generic.dm" +#include "code\modules\surgery\implant.dm" +#include "code\modules\surgery\limb_reattach.dm" +#include "code\modules\surgery\organs_internal.dm" +#include "code\modules\surgery\other.dm" +#include "code\modules\surgery\robotics.dm" +#include "code\modules\surgery\slimes.dm" +#include "code\modules\surgery\surgery.dm" +#include "code\modules\surgery\~defines.dm" +#include "code\modules\tables\flipping.dm" +#include "code\modules\tables\interactions.dm" +#include "code\modules\tables\presets.dm" +#include "code\modules\tables\rack.dm" +#include "code\modules\tables\tables.dm" +#include "code\modules\tables\update_triggers.dm" +#include "code\modules\tgui\external.dm" +#include "code\modules\tgui\process.dm" +#include "code\modules\tgui\states.dm" +#include "code\modules\tgui\tgui.dm" +#include "code\modules\tgui\states\admin.dm" +#include "code\modules\tgui\states\always.dm" +#include "code\modules\tgui\states\conscious.dm" +#include "code\modules\tgui\states\contained.dm" +#include "code\modules\tgui\states\deep_inventory.dm" +#include "code\modules\tgui\states\default.dm" +#include "code\modules\tgui\states\hands.dm" +#include "code\modules\tgui\states\human_adjacent.dm" +#include "code\modules\tgui\states\inventory.dm" +#include "code\modules\tgui\states\not_contained.dm" +#include "code\modules\tgui\states\not_incapacitated.dm" +#include "code\modules\tgui\states\physical.dm" +#include "code\modules\tgui\states\self.dm" +#include "code\modules\tgui\states\zlevel.dm" +#include "code\modules\trait\quirks.dm" +#include "code\modules\trait\traits.dm" +#include "code\modules\turbolift\_turbolift.dm" +#include "code\modules\turbolift\turbolift.dm" +#include "code\modules\turbolift\turbolift_areas.dm" +#include "code\modules\turbolift\turbolift_console.dm" +#include "code\modules\turbolift\turbolift_door.dm" +#include "code\modules\turbolift\turbolift_floor.dm" +#include "code\modules\turbolift\turbolift_map.dm" +#include "code\modules\turbolift\turbolift_process.dm" +#include "code\modules\turbolift\turbolift_turfs.dm" +#include "code\modules\vehicles\bike.dm" +#include "code\modules\vehicles\cargo_train.dm" +#include "code\modules\vehicles\engine.dm" +#include "code\modules\vehicles\train.dm" +#include "code\modules\vehicles\vehicle.dm" +#include "code\modules\ventcrawl\ventcrawl.dm" +#include "code\modules\ventcrawl\ventcrawl_atmospherics.dm" +#include "code\modules\ventcrawl\ventcrawl_multiz.dm" +#include "code\modules\ventcrawl\ventcrawl_verb.dm" +#include "code\modules\virus2\admin.dm" +#include "code\modules\virus2\analyser.dm" +#include "code\modules\virus2\antibodies.dm" +#include "code\modules\virus2\antibodyanalyser.dm" +#include "code\modules\virus2\centrifuge.dm" +#include "code\modules\virus2\curer.dm" +#include "code\modules\virus2\disease2.dm" +#include "code\modules\virus2\diseasesplicer.dm" +#include "code\modules\virus2\dishincubator.dm" +#include "code\modules\virus2\effect.dm" +#include "code\modules\virus2\helpers.dm" +#include "code\modules\virus2\isolator.dm" +#include "code\modules\virus2\items_devices.dm" +#include "code\modules\wardog\wardog.dm" +#include "code\modules\wireless\devices.dm" +#include "code\modules\wireless\interfaces.dm" +#include "code\modules\xenoarcheaology\anomaly_container.dm" +#include "code\modules\xenoarcheaology\boulder.dm" +#include "code\modules\xenoarcheaology\effect.dm" +#include "code\modules\xenoarcheaology\master_controller.dm" +#include "code\modules\xenoarcheaology\misc.dm" +#include "code\modules\xenoarcheaology\sampling.dm" +#include "code\modules\xenoarcheaology\artifacts\artifact.dm" +#include "code\modules\xenoarcheaology\artifacts\artifact_find.dm" +#include "code\modules\xenoarcheaology\artifacts\autocloner.dm" +#include "code\modules\xenoarcheaology\artifacts\crystal.dm" +#include "code\modules\xenoarcheaology\artifacts\gigadrill.dm" +#include "code\modules\xenoarcheaology\artifacts\replicator.dm" +#include "code\modules\xenoarcheaology\effects\badfeeling.dm" +#include "code\modules\xenoarcheaology\effects\cellcharge.dm" +#include "code\modules\xenoarcheaology\effects\celldrain.dm" +#include "code\modules\xenoarcheaology\effects\cold.dm" +#include "code\modules\xenoarcheaology\effects\dnaswitch.dm" +#include "code\modules\xenoarcheaology\effects\emp.dm" +#include "code\modules\xenoarcheaology\effects\forcefield.dm" +#include "code\modules\xenoarcheaology\effects\gasco2.dm" +#include "code\modules\xenoarcheaology\effects\gasnitro.dm" +#include "code\modules\xenoarcheaology\effects\gasoxy.dm" +#include "code\modules\xenoarcheaology\effects\gasphoron.dm" +#include "code\modules\xenoarcheaology\effects\gassleeping.dm" +#include "code\modules\xenoarcheaology\effects\goodfeeling.dm" +#include "code\modules\xenoarcheaology\effects\heal.dm" +#include "code\modules\xenoarcheaology\effects\heat.dm" +#include "code\modules\xenoarcheaology\effects\hurt.dm" +#include "code\modules\xenoarcheaology\effects\radiate.dm" +#include "code\modules\xenoarcheaology\effects\roboheal.dm" +#include "code\modules\xenoarcheaology\effects\robohurt.dm" +#include "code\modules\xenoarcheaology\effects\sleepy.dm" +#include "code\modules\xenoarcheaology\effects\stun.dm" +#include "code\modules\xenoarcheaology\effects\teleport.dm" +#include "code\modules\xenoarcheaology\finds\find_spawning.dm" +#include "code\modules\xenoarcheaology\finds\finds.dm" +#include "code\modules\xenoarcheaology\finds\finds_defines.dm" +#include "code\modules\xenoarcheaology\finds\fossils.dm" +#include "code\modules\xenoarcheaology\finds\misc.dm" +#include "code\modules\xenoarcheaology\finds\special.dm" +#include "code\modules\xenoarcheaology\finds\talking.dm" +#include "code\modules\xenoarcheaology\tools\ano_device_battery.dm" +#include "code\modules\xenoarcheaology\tools\artifact_analyser.dm" +#include "code\modules\xenoarcheaology\tools\artifact_harvester.dm" +#include "code\modules\xenoarcheaology\tools\artifact_scanner.dm" +#include "code\modules\xenoarcheaology\tools\coolant_tank.dm" +#include "code\modules\xenoarcheaology\tools\equipment.dm" +#include "code\modules\xenoarcheaology\tools\geosample_scanner.dm" +#include "code\modules\xenoarcheaology\tools\suspension_generator.dm" +#include "code\modules\xenoarcheaology\tools\tools.dm" +#include "code\modules\xenoarcheaology\tools\tools_pickaxe.dm" +#include "code\modules\xgm\gases.dm" +#include "code\modules\xgm\xgm_gas_data.dm" +#include "code\modules\xgm\xgm_gas_mixture.dm" +#include "code\modules\ZAS\_docs.dm" +#include "code\modules\ZAS\Airflow.dm" +#include "code\modules\ZAS\Atom.dm" +#include "code\modules\ZAS\Connection.dm" +#include "code\modules\ZAS\ConnectionGroup.dm" +#include "code\modules\ZAS\ConnectionManager.dm" +#include "code\modules\ZAS\Debug.dm" +#include "code\modules\ZAS\Diagnostic.dm" +#include "code\modules\ZAS\Fire.dm" +#include "code\modules\ZAS\Phoron.dm" +#include "code\modules\ZAS\Turf.dm" +#include "code\modules\ZAS\Variable Settings.dm" +#include "code\modules\ZAS\Zone.dm" +#include "code\procs\announce.dm" +#include "code\procs\AStar.dm" +#include "code\procs\dbcore.dm" +#include "code\procs\hud.dm" +#include "code\procs\radio.dm" +#include "code\procs\statistics.dm" +#include "code\unit_tests\_includes.dm" +#include "code\unit_tests\alt_appearances_test.dm" +#include "code\unit_tests\area_tests.dm" +#include "code\unit_tests\atmospherics_tests.dm" +#include "code\unit_tests\cargo_tests.dm" +#include "code\unit_tests\equipment_tests.dm" +#include "code\unit_tests\extension_tests.dm" +#include "code\unit_tests\food_tests.dm" +#include "code\unit_tests\foundation_tests.dm" +#include "code\unit_tests\icon_tests.dm" +#include "code\unit_tests\integrated_circuits.dm" +#include "code\unit_tests\job_tests.dm" +#include "code\unit_tests\map_tests.dm" +#include "code\unit_tests\mob_tests.dm" +#include "code\unit_tests\movement_tests.dm" +#include "code\unit_tests\observation_tests.dm" +#include "code\unit_tests\organ_tests.dm" +#include "code\unit_tests\power_tests.dm" +#include "code\unit_tests\seed_tests.dm" +#include "code\unit_tests\shuttle_tests.dm" +#include "code\unit_tests\subsystem_tests.dm" +#include "code\unit_tests\test_obj.dm" +#include "code\unit_tests\unique_tests.dm" +#include "code\unit_tests\unit_test.dm" +#include "code\unit_tests\uplink_tests.dm" +#include "code\unit_tests\view_variables_test.dm" +#include "code\unit_tests\virtual_mob_tests.dm" +#include "code\unit_tests\zas_tests.dm" +#include "code\unit_tests\~helpers.dm" +#include "code\unit_tests\~unit_test_types.dm" +#include "interface\interface.dm" +#include "interface\skin.dmf" +#include "maps\_map_include.dm" +#include "maps\away\away_sites.dm" +#include "maps\away\mining\mining_areas.dm" +#include "maps\oldfare\warfare.dm" +#include "maps\oldfare\warfare_define.dm" +#include "maps\overmap_example\overmap_example_define.dm" +#include "maps\random_ruins\exoplanet_ruins\exoplanet_ruins.dm" +#include "maps\random_ruins\exoplanet_ruins\hut\hut.dm" +#include "maps\random_ruins\exoplanet_ruins\monoliths\monoliths.dm" +#include "maps\random_ruins\space_ruins\space_ruins.dm" +#include "maps\~mapsystem\map_preferences.dm" +#include "maps\~mapsystem\map_ranks.dm" +#include "maps\~mapsystem\maps.dm" +#include "maps\~mapsystem\maps_announcements.dm" +#include "maps\~mapsystem\maps_areas.dm" +#include "maps\~mapsystem\maps_jobs.dm" +#include "maps\~mapsystem\maps_unit_testing.dm" +#include "maps\~unit_tests\unit_testing.dm" +#include "~code\global_init.dm" +// END_INCLUDE + +#include "__non-agpl-warfare/__secret.dme" diff --git a/LICENSE-AGPL3.txt b/LICENSE-AGPL3.txt new file mode 100644 index 00000000..dba13ed2 --- /dev/null +++ b/LICENSE-AGPL3.txt @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/LICENSE-GPL3.txt b/LICENSE-GPL3.txt new file mode 100644 index 00000000..94a9ed02 --- /dev/null +++ b/LICENSE-GPL3.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md index c1d018d4..43d9d2ce 100644 --- a/README.md +++ b/README.md @@ -1 +1,38 @@ -# IS12-Warfare \ No newline at end of file +## Interstation12: Warfare + +**Website:** http://is12wiki.xyz/index.php/Main_Page + +**Main source code:** https://github.com/mattroks101/IS12-Warfare + +**Discord:** https://discord.gg/FVRctMD + +## Terms of service + +**Please carefully read the following statement:** + +If you desire to host your own server based off of IS12 Warfare source code - you may not pretend to be an "Official IS12 Warfare" server. + +**By our terms and conditions we require any potential host to specify that they are an unofficial server in announcements and the Byond HUB.** + +Stated terms of service fully comply with the AGPL v3 license. + +### LICENSE +Code is licensed under the [GNU Affero General Public License v3](http://www.gnu.org/licenses/agpl.html). + +If you wish to license under GPL v3 please make this clear in the commit message and any added files. + +The major change here is that if you host a server using any code licensed under AGPLv3 you are required to provide full source code for your servers users as well including addons and modifications you have made. + +**All original art assets are © 2020 Interstation12. All rights reserved. You may not rip the original art assets and use them in your project without consent.** + + +## How do I get this to compile? + +You can do this one of two ways. First way is to go into your DME, and find the line that contains `#include "__non-agpl-warfare/__secret.dme"`, comment this out. Your code will now compile, but it may not be compatible with the main repo anymore, only do this if you have simply downloaded the codebase, and do not plan to contribute or keep up to date with it's changes. + +The proper method is to go into the folder called `__non-agpl-warfare` and create a DME called `__secret.dme`. Make sure it is titled exactly that, in exactly that folder, and that the DME is completely blank with no files included. Now go back to the IS12Warfare.dme and compile again. It will compile correctly. + + +## Why do I have to do that? + +Due to license restrictions on certain independent systems referenced in this code, certain parts of the codebase were not able to be released to the public. A dummy file system has been created to account for this. The codebase will still compile and run without the independent systems. \ No newline at end of file diff --git a/code/__datastructures/globals.dm b/code/__datastructures/globals.dm new file mode 100644 index 00000000..637af7f0 --- /dev/null +++ b/code/__datastructures/globals.dm @@ -0,0 +1,38 @@ +//See controllers/globals.dm +#define GLOBAL_MANAGED(X, InitValue)\ +/datum/controller/global_vars/proc/InitGlobal##X(){\ + ##X = ##InitValue;\ + gvars_datum_init_order += #X;\ +} +#define GLOBAL_UNMANAGED(X, InitValue) /datum/controller/global_vars/proc/InitGlobal##X() + +#ifndef TESTING +#define GLOBAL_PROTECT(X)\ +/datum/controller/global_vars/InitGlobal##X(){\ + ..();\ + gvars_datum_protected_varlist += #X;\ +} +#else +#define GLOBAL_PROTECT(X) +#endif + +#define GLOBAL_REAL_VAR(X) var/global/##X +#define GLOBAL_REAL(X, Typepath) var/global##Typepath/##X + +#define GLOBAL_RAW(X) /datum/controller/global_vars/var/global##X + +#define GLOBAL_VAR_INIT(X, InitValue) GLOBAL_RAW(/##X); GLOBAL_MANAGED(X, InitValue) + +#define GLOBAL_VAR_CONST(X, InitValue) GLOBAL_RAW(/const/##X) = InitValue; GLOBAL_UNMANAGED(X, InitValue) + +#define GLOBAL_LIST_INIT(X, InitValue) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, InitValue) + +#define GLOBAL_LIST_EMPTY(X) GLOBAL_LIST_INIT(X, list()) + +#define GLOBAL_DATUM_INIT(X, Typepath, InitValue) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, InitValue) + +#define GLOBAL_VAR(X) GLOBAL_RAW(/##X); GLOBAL_MANAGED(X, null) + +#define GLOBAL_LIST(X) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, null) + +#define GLOBAL_DATUM(X, Typepath) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, null) diff --git a/code/__datastructures/priority_queue.dm b/code/__datastructures/priority_queue.dm new file mode 100644 index 00000000..380db428 --- /dev/null +++ b/code/__datastructures/priority_queue.dm @@ -0,0 +1,63 @@ + +////////////////////// +//PriorityQueue object +////////////////////// + +//an ordered list, using the cmp proc to weight the list elements +/PriorityQueue + var/list/L //the actual queue + var/cmp //the weight function used to order the queue + +/PriorityQueue/New(compare) + L = new() + cmp = compare + +/PriorityQueue/proc/IsEmpty() + return !L.len + +//add an element in the list, +//immediatly ordering it to its position using dichotomic search +/PriorityQueue/proc/Enqueue(atom/A) + ADD_SORTED(L, A, cmp) + +//removes and returns the first element in the queue +/PriorityQueue/proc/Dequeue() + if(!L.len) + return 0 + . = L[1] + + Remove(.) + +//removes an element +/PriorityQueue/proc/Remove(atom/A) + . = L.Remove(A) + +//returns a copy of the elements list +/PriorityQueue/proc/List() + . = L.Copy() + +//return the position of an element or 0 if not found +/PriorityQueue/proc/Seek(atom/A) + . = L.Find(A) + +//return the element at the i_th position +/PriorityQueue/proc/Get(i) + if(i > L.len || i < 1) + return 0 + return L[i] + +//return the length of the queue +/PriorityQueue/proc/Length() + . = L.len + +//replace the passed element at it's right position using the cmp proc +/PriorityQueue/proc/ReSort(atom/A) + var/i = Seek(A) + if(i == 0) + return + while(i < L.len && call(cmp)(L[i],L[i+1]) > 0) + L.Swap(i,i+1) + i++ + while(i > 1 && call(cmp)(L[i],L[i-1]) <= 0) //last inserted element being first in case of ties (optimization) + L.Swap(i,i-1) + i-- diff --git a/code/__datastructures/stack.dm b/code/__datastructures/stack.dm new file mode 100644 index 00000000..76e492e0 --- /dev/null +++ b/code/__datastructures/stack.dm @@ -0,0 +1,66 @@ +/datum/stack + var/list/stack + var/max_elements = 0 + +/datum/stack/New(list/elements, max) + ..() + stack = elements ? elements.Copy() : list() + if(max) + max_elements = max + +/datum/stack/Destroy() + Clear() + . = ..() + +/datum/stack/proc/Pop() + if(is_empty()) + return null + . = stack[stack.len] + stack.Cut(stack.len,0) + +/datum/stack/proc/Push(element) + if(max_elements && (stack.len+1 > max_elements)) + return null + stack += element + +/datum/stack/proc/Top() + if(is_empty()) + return null + . = stack[stack.len] + +/datum/stack/proc/Remove(element) + stack -= element + +/datum/stack/proc/is_empty() + . = stack.len ? 0 : 1 + +//Rotate entire stack left with the leftmost looping around to the right +/datum/stack/proc/RotateLeft() + if(is_empty()) + return 0 + . = stack[1] + stack.Cut(1,2) + Push(.) + +//Rotate entire stack to the right with the rightmost looping around to the left +/datum/stack/proc/RotateRight() + if(is_empty()) + return 0 + . = stack[stack.len] + stack.Cut(stack.len,0) + stack.Insert(1,.) + + +/datum/stack/proc/Copy() + var/datum/stack/S=new() + S.stack = stack.Copy() + S.max_elements = max_elements + return S + +/datum/stack/proc/Clear() + stack.Cut() + +/datum/stack/proc/QdelClear() + for(var/entry in stack) + qdel(entry) + stack.Cut() diff --git a/code/__defines/MC.dm b/code/__defines/MC.dm new file mode 100644 index 00000000..d36f8384 --- /dev/null +++ b/code/__defines/MC.dm @@ -0,0 +1,124 @@ +#define MC_TICK_CHECK ( ( TICK_USAGE > Master.current_ticklimit || src.state != SS_RUNNING ) ? pause() : 0 ) + +#define MC_SPLIT_TICK_INIT(phase_count) var/original_tick_limit = Master.current_ticklimit; var/split_tick_phases = ##phase_count +#define MC_SPLIT_TICK \ + if(split_tick_phases > 1){\ + Master.current_ticklimit = ((original_tick_limit - TICK_USAGE) / split_tick_phases) + TICK_USAGE;\ + --split_tick_phases;\ + } else {\ + Master.current_ticklimit = original_tick_limit;\ + } + +// Used to smooth out costs to try and avoid oscillation. +#define MC_AVERAGE_FAST(average, current) (0.7 * (average) + 0.3 * (current)) +#define MC_AVERAGE(average, current) (0.8 * (average) + 0.2 * (current)) +#define MC_AVERAGE_SLOW(average, current) (0.9 * (average) + 0.1 * (current)) + +#define MC_AVG_FAST_UP_SLOW_DOWN(average, current) (average > current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current)) +#define MC_AVG_SLOW_UP_FAST_DOWN(average, current) (average < current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current)) + +#define NEW_SS_GLOBAL(varname) if(varname != src){if(istype(varname)){Recover();qdel(varname);}varname = src;} + +#define START_PROCESSING(Processor, Datum) \ +if (Datum.is_processing) {\ + if(Datum.is_processing != #Processor)\ + {\ + crash_with("Failed to start processing. [log_info_line(Datum)] is already being processed by [Datum.is_processing] but queue attempt occured on [#Processor]."); \ + }\ +} else {\ + Datum.is_processing = #Processor;\ + Processor.processing += Datum;\ +} + +#define STOP_PROCESSING(Processor, Datum) \ +if(Datum.is_processing) {\ + if(Processor.processing.Remove(Datum)) {\ + Datum.is_processing = null;\ + } else {\ + crash_with("Failed to stop processing. [log_info_line(Datum)] is being processed by [Datum.is_processing] but de-queue attempt occured on [#Processor]."); \ + }\ +} + +//SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier) + +//subsystem does not initialize. +#define SS_NO_INIT 1 + +//subsystem does not fire. +// (like can_fire = 0, but keeps it from getting added to the processing subsystems list) +// (Requires a MC restart to change) +#define SS_NO_FIRE 2 + +//subsystem only runs on spare cpu (after all non-background subsystems have ran that tick) +// SS_BACKGROUND has its own priority bracket +#define SS_BACKGROUND 4 + +//subsystem does not tick check, and should not run unless there is enough time (or its running behind (unless background)) +#define SS_NO_TICK_CHECK 8 + +//Treat wait as a tick count, not DS, run every wait ticks. +// (also forces it to run first in the tick, above even SS_NO_TICK_CHECK subsystems) +// (implies all runlevels because of how it works) +// (overrides SS_BACKGROUND) +// This is designed for basically anything that works as a mini-mc (like SStimer) +#define SS_TICKER 16 + +//keep the subsystem's timing on point by firing early if it fired late last fire because of lag +// ie: if a 20ds subsystem fires say 5 ds late due to lag or what not, its next fire would be in 15ds, not 20ds. +#define SS_KEEP_TIMING 32 + +//Calculate its next fire after its fired. +// (IE: if a 5ds wait SS takes 2ds to run, its next fire should be 5ds away, not 3ds like it normally would be) +// This flag overrides SS_KEEP_TIMING +#define SS_POST_FIRE_TIMING 64 + +// -- SStimer stuff -- +//Don't run if there is an identical unique timer active +#define TIMER_UNIQUE 0x1 + +//For unique timers: Replace the old timer rather then not start this one +#define TIMER_OVERRIDE 0x2 + +//Timing should be based on how timing progresses on clients, not the sever. +// tracking this is more expensive, +// should only be used in conjuction with things that have to progress client side, such as animate() or sound() +#define TIMER_CLIENT_TIME 0x4 + +//Timer can be stopped using deltimer() +#define TIMER_STOPPABLE 0x8 + +//To be used with TIMER_UNIQUE +//prevents distinguishing identical timers with the wait variable +#define TIMER_NO_HASH_WAIT 0x10 + +//number of byond ticks that are allowed to pass before the timer subsystem thinks it hung on something +#define TIMER_NO_INVOKE_WARNING 600 + +#define TIMER_ID_NULL -1 + +//SUBSYSTEM STATES +#define SS_IDLE 0 //aint doing shit. +#define SS_QUEUED 1 //queued to run +#define SS_RUNNING 2 //actively running +#define SS_PAUSED 3 //paused by mc_tick_check +#define SS_SLEEPING 4 //fire() slept. +#define SS_PAUSING 5 //in the middle of pausing + +#define SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/##X);\ +/datum/controller/subsystem/##X/New(){\ + NEW_SS_GLOBAL(SS##X);\ + PreInit();\ +}\ +/datum/controller/subsystem/##X + +#define PROCESSING_SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/processing/##X);\ +/datum/controller/subsystem/processing/##X/New(){\ + NEW_SS_GLOBAL(SS##X);\ + PreInit();\ +}\ +/datum/controller/subsystem/processing/##X/Recover() {\ + if(istype(SS##X.processing)) {\ + processing = SS##X.processing; \ + }\ +}\ +/datum/controller/subsystem/processing/##X diff --git a/code/__defines/ZAS.dm b/code/__defines/ZAS.dm new file mode 100644 index 00000000..2d95c9ef --- /dev/null +++ b/code/__defines/ZAS.dm @@ -0,0 +1,117 @@ +//#define ZASDBG +#define MULTIZAS + +#define AIR_BLOCKED 1 +#define ZONE_BLOCKED 2 +#define BLOCKED 3 + +#define ZONE_MIN_SIZE 14 //zones with less than this many turfs will always merge, even if the connection is not direct + +#define CANPASS_ALWAYS 1 +#define CANPASS_DENSITY 2 +#define CANPASS_PROC 3 +#define CANPASS_NEVER 4 + +#define NORTHUP (NORTH|UP) +#define EASTUP (EAST|UP) +#define SOUTHUP (SOUTH|UP) +#define WESTUP (WEST|UP) +#define NORTHDOWN (NORTH|DOWN) +#define EASTDOWN (EAST|DOWN) +#define SOUTHDOWN (SOUTH|DOWN) +#define WESTDOWN (WEST|DOWN) + +#define TURF_HAS_VALID_ZONE(T) (istype(T, /turf/simulated) && T:zone && !T:zone:invalid) + +#ifdef MULTIZAS + +var/list/csrfz_check = list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST, NORTHUP, EASTUP, WESTUP, SOUTHUP, NORTHDOWN, EASTDOWN, WESTDOWN, SOUTHDOWN) +var/list/gzn_check = list(NORTH, SOUTH, EAST, WEST, UP, DOWN) + +#define ATMOS_CANPASS_TURF(ret,A,B) \ + if (A.blocks_air & AIR_BLOCKED || B.blocks_air & AIR_BLOCKED) { \ + ret = BLOCKED; \ + } \ + else if (B.z != A.z) { \ + if (B.z < A.z) { \ + if (!istype(A, /turf/simulated/open)) { \ + ret = BLOCKED; \ + } else { \ + ret = ZONE_BLOCKED; \ + } \ + } \ + else { \ + if (!istype(B, /turf/simulated/open)) { \ + ret = BLOCKED; \ + } else { \ + ret = ZONE_BLOCKED; \ + } \ + } \ + } \ + else if (A.blocks_air & ZONE_BLOCKED || B.blocks_air & ZONE_BLOCKED) { \ + ret = (A.z == B.z) ? ZONE_BLOCKED : AIR_BLOCKED; \ + } \ + else if (A.contents.len) { \ + ret = 0;\ + for (var/thing in A) { \ + var/atom/movable/AM = thing; \ + switch (AM.atmos_canpass) { \ + if (CANPASS_ALWAYS) { \ + continue; \ + } \ + if (CANPASS_DENSITY) { \ + if (AM.density) { \ + ret |= AIR_BLOCKED; \ + } \ + } \ + if (CANPASS_PROC) { \ + ret |= AM.c_airblock(B); \ + } \ + if (CANPASS_NEVER) { \ + ret = BLOCKED; \ + } \ + } \ + if (ret == BLOCKED) { \ + break;\ + }\ + }\ + } +#else + +var/list/csrfz_check = list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST) +var/list/gzn_check = list(NORTH, SOUTH, EAST, WEST) + +#define ATMOS_CANPASS_TURF(ret,A,B) \ + if (A.blocks_air & AIR_BLOCKED || B.blocks_air & AIR_BLOCKED) { \ + ret = BLOCKED; \ + } \ + else if (A.blocks_air & ZONE_BLOCKED || B.blocks_air & ZONE_BLOCKED) { \ + ret = ZONE_BLOCKED; \ + } \ + else if (A.contents.len) { \ + ret = 0;\ + for (var/thing in A) { \ + var/atom/movable/AM = thing; \ + switch (AM.atmos_canpass) { \ + if (CANPASS_ALWAYS) { \ + continue; \ + } \ + if (CANPASS_DENSITY) { \ + if (AM.density) { \ + ret |= AIR_BLOCKED; \ + } \ + } \ + if (CANPASS_PROC) { \ + ret |= AM.c_airblock(B); \ + } \ + if (CANPASS_NEVER) { \ + ret = BLOCKED; \ + } \ + } \ + if (ret == BLOCKED) { \ + break;\ + }\ + }\ + } + +#endif diff --git a/code/__defines/_compile_options.dm b/code/__defines/_compile_options.dm new file mode 100644 index 00000000..2595ee6d --- /dev/null +++ b/code/__defines/_compile_options.dm @@ -0,0 +1,2 @@ +#define BACKGROUND_ENABLED 0 // The default value for all uses of set background. Set background can cause gradual lag and is recommended you only turn this on if necessary. + // 1 will enable set background. 0 will disable set background. \ No newline at end of file diff --git a/code/__defines/_planes+layers.dm b/code/__defines/_planes+layers.dm new file mode 100644 index 00000000..48dcd1a4 --- /dev/null +++ b/code/__defines/_planes+layers.dm @@ -0,0 +1,375 @@ +/*This file is a list of all preclaimed planes & layers + +All planes & layers should be given a value here instead of using a magic/arbitrary number. + +After fiddling with planes and layers for some time, I figured I may as well provide some documentation: + +What are planes? + Think of Planes as a sort of layer for a layer - if plane X is a larger number than plane Y, the highest number for a layer in X will be below the lowest + number for a layer in Y. + Planes also have the added bonus of having planesmasters. + +What are Planesmasters? + Planesmasters, when in the sight of a player, will have its appearance properties (for example, colour matrices, alpha, transform, etc) + applied to all the other objects in the plane. This is all client sided. + Usually you would want to add the planesmaster as an invisible image in the client's screen. + +What can I do with Planesmasters? + You can: Make certain players not see an entire plane, + Make an entire plane have a certain colour matrices, + Make an entire plane transform in a certain way, + Make players see a plane which is hidden to normal players - I intend to implement this with the antag HUDs for example. + Planesmasters can be used as a neater way to deal with client images or potentially to do some neat things + +How do planes work? + A plane can be any integer from -100 to 100. (If you want more, bug lummox.) + All planes above 0, the 'base plane', are visible even when your character cannot 'see' them, for example, the HUD. + All planes below 0, the 'base plane', are only visible when a character can see them. + +How do I add a plane? + Think of where you want the plane to appear, look through the pre-existing planes and find where it is above and where it is below + Slot it in in that place, and change the pre-existing planes, making sure no plane shares a number. + Add a description with a comment as to what the plane does. + +How do I make something a planesmaster? + Add the PLANE_MASTER appearance flag to the appearance_flags variable. + +What is the naming convention for planes or layers? + Make sure to use the name of your object before the _LAYER or _PLANE, eg: [NAME_OF_YOUR_OBJECT HERE]_LAYER or [NAME_OF_YOUR_OBJECT HERE]_PLANE + Also, as it's a define, it is standard practice to use capital letters for the variable so people know this. + +*/ + +/* + from stddef.dm, planes & layers built into byond. + + FLOAT_LAYER = -1 + AREA_LAYER = 1 + TURF_LAYER = 2 + OBJ_LAYER = 3 + MOB_LAYER = 4 + FLY_LAYER = 5 + EFFECTS_LAYER = 5000 + TOPDOWN_LAYER = 10000 + BACKGROUND_LAYER = 20000 + EFFECTS_LAYER = 5000 + TOPDOWN_LAYER = 10000 + BACKGROUND_LAYER = 20000 + ------ + + FLOAT_PLANE = -32767 +*/ + +#define CLICKCATCHER_PLANE -500 + +#define HIDDEN_SHIT_PLANE -499 //Used for the hiding of the vision cone masking object. +#define SPACE_PLANE -498 +#define SKYBOX_PLANE SPACE_PLANE + 1 + +#define DUST_PLANE SPACE_PLANE + 2 + #define DEBRIS_LAYER 1 + #define DUST_LAYER 2 + +//Reserve planes for openspace +#define OPENSPACE_PLANE_START -462 +#define OPENSPACE_PLANE_END -22 +#define OPENSPACE_PLANE -99 //-463 +#define UNDER_OPENSPACE_PLANE -100 +#define OVER_OPENSPACE_PLANE -17 + + +#define BELOW_TURF_PLANE -22 // objects that are below turfs. Useful for asteroid smoothing or other such magic. + // TURF_LAYER 2 + +#define PLATING_PLANE -21 + #define PLATING_LAYER 1 + +#define ABOVE_PLATING_PLANE -20 + + #define HOLOMAP_LAYER 2 // NOTE: ENSURE this is equal to the one at ABOVE_TURF_PLANE! + #define DECAL_PLATING_LAYER 3 + #define DISPOSALS_PIPE_LAYER 4 + #define LATTICE_LAYER 5 + #define PIPE_LAYER 6 + #define WIRE_LAYER 7 + #define WIRE_TERMINAL_LAYER 8 + #define ABOVE_WIRE_LAYER 9 + +#define TURF_PLANE -19 + + #define BASE_TURF_LAYER -999 + #define TURF_DETAIL_LAYER 11 + +#define WALL_PLANE -18 + + +#define ABOVE_TURF_PLANE -16 // For items which should appear above turfs but below other objects and hiding mobs, eg: wires & pipes + + //#define HOLOMAP_LAYER 1 // NOTE: ENSURE this is equal to the one at ABOVE_PLATING_PLANE! + #define DECAL_LAYER 12 + #define RUNE_LAYER 13 + #define ABOVE_TILE_LAYER 14 + #define EXPOSED_PIPE_LAYER 15 + #define EXPOSED_WIRE_LAYER 16 + #define EXPOSED_WIRE_TERMINAL_LAYER 17 + #define CATWALK_LAYER 18 + #define BLOOD_LAYER 19 + #define MOUSETRAP_LAYER 20 + #define PLANT_LAYER 21 + #define AO_LAYER 22 + +#define HIDING_MOB_PLANE -16 // for hiding mobs like MoMMIs or spiders or whatever, under most objects but over pipes & such. + + #define HIDING_MOB_LAYER 0 + +#define OBJ_PLANE -15 // For objects which appear below humans. + #define BELOW_DOOR_LAYER 23 + #define OPEN_DOOR_LAYER 24 + #define BELOW_TABLE_LAYER 25 + #define TABLE_LAYER 26 + #define BELOW_OBJ_LAYER 27 + #define BASE_OBJ_LAYER 28 + #define ABOVE_OBJ_LAYER 29 + #define CLOSED_DOOR_LAYER 30 + #define ABOVE_DOOR_LAYER 31 + #define SIDE_WINDOW_LAYER 32 + #define FULL_WINDOW_LAYER 33 + #define ABOVE_WINDOW_LAYER 34 + +#define LYING_MOB_PLANE -14 // other mobs that are lying down. + + #define LYING_MOB_LAYER 35 + +#define LYING_HUMAN_PLANE -13 // humans that are lying down + + #define LYING_HUMAN_LAYER 36 + +#define ABOVE_OBJ_PLANE -12 // for objects that are below humans when they are standing but above them when they are not. - eg, blankets. + + #define BASE_ABOVE_OBJ_LAYER 37 + +#define HUMAN_PLANE -10 // For Humans that are standing up. + #define BASE_MOB_LAYER 38 + +#define ANON_PLANE -9 //For the anonymous blur effect. + +#define MOB_PLANE -11 // For Mobs. + // MOB_LAYER 4 + +#define ABOVE_HUMAN_PLANE -6 // For things that should appear above humans. + + #define ABOVE_HUMAN_LAYER 39 + #define VEHICLE_LOAD_LAYER 40 + #define CAMERA_LAYER 41 + +#define BLOB_PLANE -5 // For Blobs, which are above humans. + + #define BLOB_SHIELD_LAYER 42 + #define BLOB_NODE_LAYER 43 + #define BLOB_CORE_LAYER 44 + +#define BULLET_PLANE -5 //Same as blob plane but blobs are not used in warfare. + +#define EFFECTS_BELOW_LIGHTING_PLANE -4 // For special effects. + + #define BELOW_PROJECTILE_LAYER 45 + #define FIRE_LAYER 46 + #define PROJECTILE_LAYER 47 + #define ABOVE_PROJECTILE_LAYER 48 + #define SINGULARITY_LAYER 49 + #define POINTER_LAYER 50 + +#define OBSERVER_PLANE -3 // For observers and ghosts + +#define LIGHTING_PLANE -2 // For Lighting. - The highest plane (ignoring all other even higher planes) + + #define LIGHTBULB_LAYER 0 + //#define LIGHTING_LAYER 1 + #define ABOVE_LIGHTING_LAYER 2 + #define SUPER_PORTAL_LAYER 3 + #define NARSIE_GLOW 4 + +#define EFFECTS_ABOVE_LIGHTING_PLANE -1 // For glowy eyes, laser beams, etc. that shouldn't be affected by darkness + #define EYE_GLOW_LAYER 1 + #define BEAM_PROJECTILE_LAYER 2 + #define SUPERMATTER_WALL_LAYER 3 + +#define BASE_PLANE 0 // Not for anything, but this is the default. + #define BASE_AREA_LAYER 999 + +#define OBSCURITY_PLANE 2 // For visualnets, such as the AI's static. + +#define FULLSCREEN_PLANE 3 // for fullscreen overlays that do not cover the hud. + + #define FULLSCREEN_LAYER 0 + #define SCREEN_DAMAGE_LAYER 1 + #define IMPAIRED_LAYER 2 + #define BLIND_LAYER 3 + #define CRIT_LAYER 4 + #define HALLUCINATION_LAYER 5 + +#define ABOVE_FULLSCREEN_PLANE 4 + +#define VISION_CONE_PLANE 5 // For the vision cone. + +#define FOOTSTEP_ALERT_PLANE 6 // Hacky fix for the footsteps not being a thing. + +#define HUD_PLANE 7 // For the Head-Up Display + + #define UNDER_HUD_LAYER 0 + #define HUD_BASE_LAYER 1 + #define HUD_ITEM_LAYER 2 + #define HUD_ABOVE_ITEM_LAYER 3 + + + + + + + + +#define AMBIENT_OCCLUSION filter(type="drop_shadow", x=0, y=-2, size=4, color="#04080FAA") + +//This is difference between highest and lowest visible +#define PLANE_DIFFERENCE 22 +/image + plane = FLOAT_PLANE // this is defunct, lummox fixed this on recent compilers, but it will bug out if I remove it for coders not on the most recent compile. + +/image/proc/plating_decal_layerise() + plane = ABOVE_PLATING_PLANE + layer = DECAL_PLATING_LAYER + +/image/proc/turf_decal_layerise() + plane = ABOVE_TURF_PLANE + layer = DECAL_LAYER + +/atom/proc/hud_layerise() + plane = HUD_PLANE + layer = HUD_ITEM_LAYER + +/atom/proc/reset_plane_and_layer() + plane = initial(plane) + layer = initial(layer) + +/* + PLANE MASTERS +*/ + +/obj/blur_planemaster + appearance_flags = PLANE_MASTER + plane = OPENSPACE_PLANE + screen_loc = "1,1" + filters = filter(type = "blur", size = 1) + +//I don't know what the fuck this shit is used for. +/obj/screen/plane_master + appearance_flags = PLANE_MASTER + screen_loc = "CENTER,CENTER" + globalscreen = 1 + +/obj/screen/plane_master/ghost_master + plane = OBSERVER_PLANE + filters = filter(type = "blur", size = 1) + +/obj/screen/plane_master/bullet_plane + plane = BULLET_PLANE + filters = filter(type = "blur", size = 1) + +/obj/screen/plane_master/human_blur + plane = HUMAN_PLANE + filters = filter(type = "blur", size = 2) + +/obj/screen/plane_master/turf_blur + plane = TURF_PLANE + filters = filter(type = "blur", size = 2) + +/obj/screen/plane_master/wall_blur + plane = WALL_PLANE + filters = filter(type = "blur", size = 2) + +/obj/screen/plane_master/obj_blur + plane = OBJ_PLANE + filters = filter(type = "blur", size = 2) + +/obj/screen/plane_master/lhuman_blur + plane = LYING_HUMAN_PLANE + filters = filter(type = "blur", size = 2) + +/obj/screen/plane_master/mob_blur + plane = MOB_PLANE + filters = filter(type = "blur", size = 2) + +/obj/screen/plane_master/above_human_blur + plane = ABOVE_HUMAN_PLANE + filters = filter(type = "blur", size = 2) + +/obj/screen/plane_master/abover_turf_blur + plane = ABOVE_TURF_PLANE + filters = filter(type = "blur", size = 2) + +/obj/screen/plane_master/abover_obj_blur + plane = ABOVE_OBJ_PLANE + filters = filter(type = "blur", size = 2) + +/obj/screen/plane_master/plating_blur + plane = PLATING_PLANE + filters = filter(type = "blur", size = 2) + +/obj/screen/plane_master/effects_blur + plane = EFFECTS_BELOW_LIGHTING_PLANE + filters = filter(type = "blur", size = 2) + +/obj/screen/plane_master/ghost_dummy + // this avoids a bug which means plane masters which have nothing to control get angry and mess with the other plane masters out of spite + alpha = 0 + appearance_flags = 0 + plane = OBSERVER_PLANE + +GLOBAL_LIST_INIT(ghost_master, list( + new /obj/screen/plane_master/ghost_master(), + new /obj/screen/plane_master/ghost_dummy() +)) + + +/obj/screen/plane_master/humanAO + plane = HUMAN_PLANE + filters = AMBIENT_OCCLUSION + +/obj/screen/plane_master/wallAO + plane = WALL_PLANE + filters = AMBIENT_OCCLUSION + +/obj/screen/plane_master/objectAO + plane = OBJ_PLANE + filters = AMBIENT_OCCLUSION + +/obj/screen/plane_master/lying_human + plane = LYING_HUMAN_PLANE + filters = AMBIENT_OCCLUSION + +/obj/screen/plane_master/mobAO + plane = MOB_PLANE + filters = AMBIENT_OCCLUSION + + +/obj/screen/plane_master/vision_cone_target + name = "vision cone master" + plane = HIDDEN_SHIT_PLANE + render_target = "vision_cone_target" + +/obj/screen/plane_master/vision_cone_blender + render_target = "vision_cone_target" + +//A series of vision related masters. They all have the same RT name to lower load on client. +/obj/screen/plane_master/vision_cone/ + +/obj/screen/plane_master/vision_cone/primary/Initialize() //For when you want things to not appear under the blind section. + . = ..() + filters += filter(type="alpha", render_source="vision_cone_target", flags=MASK_INVERSE) + +/obj/screen/plane_master/vision_cone/inverted //for things you want specifically to show up on the blind section. + + +/obj/screen/plane_master/vision_cone/inverted/Initialize() + . = ..() + filters += filter(type="alpha", render_source="vision_cone_target") diff --git a/code/__defines/_tick.dm b/code/__defines/_tick.dm new file mode 100644 index 00000000..9609333e --- /dev/null +++ b/code/__defines/_tick.dm @@ -0,0 +1,21 @@ +#define TICK_LIMIT_RUNNING 80 +#define TICK_LIMIT_TO_RUN 78 +#define TICK_LIMIT_MC 70 +#define TICK_LIMIT_MC_INIT_DEFAULT 98 + +#define TICK_USAGE world.tick_usage //for general usage +#define TICK_USAGE_REAL world.tick_usage //to be used where the result isn't checked + +#define TICK_CHECK ( TICK_USAGE > Master.current_ticklimit ) +#define CHECK_TICK if TICK_CHECK stoplag() + +//"fancy" math for calculating time in ms from tick_usage percentage and the length of ticks +//percent_of_tick_used * (ticklag * 100(to convert to ms)) / 100(percent ratio) +//collapsed to percent_of_tick_used * tick_lag +#define TICK_DELTA_TO_MS(percent_of_tick_used) ((percent_of_tick_used) * world.tick_lag) +#define TICK_USAGE_TO_MS(starting_tickusage) (TICK_DELTA_TO_MS(TICK_USAGE_REAL - starting_tickusage)) + +//time of day but automatically adjusts to the server going into the next day within the same round. +//for when you need a reliable time number that doesn't depend on byond time. +#define REALTIMEOFDAY (world.timeofday + (MIDNIGHT_ROLLOVER * MIDNIGHT_ROLLOVER_CHECK)) +#define MIDNIGHT_ROLLOVER_CHECK ( GLOB.rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : GLOB.midnight_rollovers ) diff --git a/code/__defines/admin.dm b/code/__defines/admin.dm new file mode 100644 index 00000000..2ebe4a1e --- /dev/null +++ b/code/__defines/admin.dm @@ -0,0 +1,49 @@ +// A set of constants used to determine which type of mute an admin wishes to apply. +// Please read and understand the muting/automuting stuff before changing these. MUTE_IC_AUTO, etc. = (MUTE_IC << 1) +// Therefore there needs to be a gap between the flags for the automute flags. +#define MUTE_IC 0x1 +#define MUTE_OOC 0x2 +#define MUTE_PRAY 0x4 +#define MUTE_ADMINHELP 0x8 +#define MUTE_DEADCHAT 0x10 +#define MUTE_AOOC 0x20 +#define MUTE_ALL 0xFFFF + +// Some constants for DB_Ban +#define BANTYPE_PERMA 1 +#define BANTYPE_TEMP 2 +#define BANTYPE_JOB_PERMA 3 +#define BANTYPE_JOB_TEMP 4 +#define BANTYPE_ANY_FULLBAN 5 // Used to locate stuff to unban. + +#define ROUNDSTART_LOGOUT_REPORT_TIME 6000 // Amount of time (in deciseconds) after the rounds starts, that the player disconnect report is issued. + +// Admin permissions. +#define R_BUILDMODE 0x1 +#define R_ADMIN 0x2 +#define R_BAN 0x4 +#define R_FUN 0x8 +#define R_SERVER 0x10 +#define R_DEBUG 0x20 +#define R_POSSESS 0x40 +#define R_PERMISSIONS 0x80 +#define R_STEALTH 0x100 +#define R_REJUVINATE 0x200 +#define R_VAREDIT 0x400 +#define R_SOUNDS 0x800 +#define R_SPAWN 0x1000 +#define R_MOD 0x2000 +#define R_MENTOR 0x4000 +#define R_HOST 0x8000 //higher than this will overflow +#define R_INVESTIGATE (R_ADMIN|R_MOD) +#define TESTALLRANKS (R_HOST | R_BUILDMODE | R_ADMIN | R_BAN | R_FUN | R_SERVER | R_DEBUG | R_PERMISSIONS | R_POSSESS | R_STEALTH | R_REJUVINATE | R_VAREDIT | R_SOUNDS | R_SPAWN | R_MOD| R_MENTOR) + +#define R_MAXPERMISSION 0x8000 // This holds the maximum value for a permission. It is used in iteration, so keep it updated. + +#define ADDANTAG_PLAYER 1 // Any player may call the add antagonist vote. +#define ADDANTAG_ADMIN 2 // Any player with admin privilegies may call the add antagonist vote. +#define ADDANTAG_AUTO 4 // The add antagonist vote is available as an alternative for transfer vote. + +#define TICKET_CLOSED 0 // Ticket has been resolved or declined +#define TICKET_OPEN 1 // Ticket has been created, but not responded to +#define TICKET_ASSIGNED 2 // An admin has assigned themself to the ticket and will respond \ No newline at end of file diff --git a/code/__defines/appearance.dm b/code/__defines/appearance.dm new file mode 100644 index 00000000..faa97e8f --- /dev/null +++ b/code/__defines/appearance.dm @@ -0,0 +1,3 @@ +// Consider these images/atoms as part of the UI/HUD +#define APPEARANCE_UI_IGNORE_ALPHA RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA +#define APPEARANCE_UI RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR diff --git a/code/__defines/atmos.dm b/code/__defines/atmos.dm new file mode 100644 index 00000000..ba0fe314 --- /dev/null +++ b/code/__defines/atmos.dm @@ -0,0 +1,109 @@ + +#define CELL_VOLUME 2500 // Liters in a cell. +#define MOLES_CELLSTANDARD (ONE_ATMOSPHERE*CELL_VOLUME/(T20C*R_IDEAL_GAS_EQUATION)) // Moles in a 2.5 m^3 cell at 101.325 kPa and 20 C. + +#define O2STANDARD 0.21 // Percentage. +#define N2STANDARD 0.79 + +#define MOLES_PHORON_VISIBLE 0.7 // Moles in a standard cell after which phoron is visible. +#define MOLES_O2STANDARD (MOLES_CELLSTANDARD * O2STANDARD) // O2 standard value (21%) +#define MOLES_N2STANDARD (MOLES_CELLSTANDARD * N2STANDARD) // N2 standard value (79%) +#define MOLES_O2ATMOS (MOLES_O2STANDARD*50) +#define MOLES_N2ATMOS (MOLES_N2STANDARD*50) + +// These are for when a mob breathes poisonous air. +#define MIN_TOXIN_DAMAGE 1 +#define MAX_TOXIN_DAMAGE 10 + +#define STD_BREATH_VOLUME 12 // Liters in a normal breath. + +#define HUMAN_HEAT_CAPACITY 280000 //J/K For 80kg person + +#define SOUND_MINIMUM_PRESSURE 10 + +#define PRESSURE_DAMAGE_COEFFICIENT 4 // The amount of pressure damage someone takes is equal to (pressure / HAZARD_HIGH_PRESSURE)*PRESSURE_DAMAGE_COEFFICIENT, with the maximum of MAX_PRESSURE_DAMAGE. +#define MAX_HIGH_PRESSURE_DAMAGE 4 // This used to be 20... I got this much random rage for some retarded decision by polymorph?! Polymorph now lies in a pool of blood with a katana jammed in his spleen. ~Errorage --PS: The katana did less than 20 damage to him :( +#define LOW_PRESSURE_DAMAGE 2 // The amount of damage someone takes when in a low pressure area. (The pressure threshold is so low that it doesn't make sense to do any calculations, so it just applies this flat value). + +#define MINIMUM_PRESSURE_DIFFERENCE_TO_SUSPEND (MINIMUM_AIR_TO_SUSPEND*R_IDEAL_GAS_EQUATION*T20C)/CELL_VOLUME // Minimum pressure difference between zones to suspend +#define MINIMUM_AIR_RATIO_TO_SUSPEND 0.05 // Minimum ratio of air that must move to/from a tile to suspend group processing +#define MINIMUM_AIR_TO_SUSPEND (MOLES_CELLSTANDARD * MINIMUM_AIR_RATIO_TO_SUSPEND) // Minimum amount of air that has to move before a group processing can be suspended +#define MINIMUM_MOLES_DELTA_TO_MOVE (MOLES_CELLSTANDARD * MINIMUM_AIR_RATIO_TO_SUSPEND) // Either this must be active +#define MINIMUM_TEMPERATURE_TO_MOVE (T20C + 100) // or this (or both, obviously) + +#define MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND 0.012 // Minimum temperature difference before group processing is suspended. +#define MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND 4 +#define MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER 0.5 // Minimum temperature difference before the gas temperatures are just set to be equal. +#define MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION (T20C + 10) +#define MINIMUM_TEMPERATURE_START_SUPERCONDUCTION (T20C + 200) + +// Must be between 0 and 1. Values closer to 1 equalize temperature faster. Should not exceed 0.4, else strange heat flow occurs. +#define FLOOR_HEAT_TRANSFER_COEFFICIENT 0.4 +#define WALL_HEAT_TRANSFER_COEFFICIENT 0.0 +#define DOOR_HEAT_TRANSFER_COEFFICIENT 0.0 +#define SPACE_HEAT_TRANSFER_COEFFICIENT 0.2 // A hack to partly simulate radiative heat. +#define OPEN_HEAT_TRANSFER_COEFFICIENT 0.4 +#define WINDOW_HEAT_TRANSFER_COEFFICIENT 0.1 // A hack for now. + +// Fire damage. +#define CARBON_LIFEFORM_FIRE_RESISTANCE (T0C + 200) +#define CARBON_LIFEFORM_FIRE_DAMAGE 4 + +// Phoron fire properties. +#define PHORON_MINIMUM_BURN_TEMPERATURE (T0C + 126) //400 K - autoignite temperature in tanks and canisters - enclosed environments I guess +#define PHORON_FLASHPOINT (T0C + 246) //519 K - autoignite temperature in air if that ever gets implemented. + +//These control the mole ratio of oxidizer and fuel used in the combustion reaction +#define FIRE_REACTION_OXIDIZER_AMOUNT 3 //should be greater than the fuel amount if fires are going to spread much +#define FIRE_REACTION_FUEL_AMOUNT 2 + +//These control the speed at which fire burns +#define FIRE_GAS_BURNRATE_MULT 1 +#define FIRE_LIQUID_BURNRATE_MULT 0.225 + +//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 + +//How many moles of fuel are contained within one solid/liquid fuel volume unit +#define LIQUIDFUEL_AMOUNT_TO_MOL 0.45 //mol/volume unit + +// XGM gas flags. +#define XGM_GAS_FUEL 1 +#define XGM_GAS_OXIDIZER 2 +#define XGM_GAS_CONTAMINANT 4 +#define XGM_GAS_FUSION_FUEL 8 + +#define TANK_LEAK_PRESSURE (30.*ONE_ATMOSPHERE) // Tank starts leaking. +#define TANK_RUPTURE_PRESSURE (40.*ONE_ATMOSPHERE) // Tank spills all contents into atmosphere. +#define TANK_FRAGMENT_PRESSURE (50.*ONE_ATMOSPHERE) // Boom 3x3 base explosion. +#define TANK_FRAGMENT_SCALE (10.*ONE_ATMOSPHERE) // +1 for each SCALE kPa above threshold. Was 2 atm. + +#define NORMPIPERATE 30 // Pipe-insulation rate divisor. +#define HEATPIPERATE 8 // Heat-exchange pipe insulation. +#define FLOWFRAC 0.99 // Fraction of gas transfered per process. + +//Flags for zone sleeping +#define ZONE_ACTIVE 1 +#define ZONE_SLEEPING 0 + +// Defines how much of certain gas do the Atmospherics tanks start with. Values are in kpa per tile (assuming 20C) +#define ATMOSTANK_NITROGEN 90000 // A lot of N2 is needed to produce air mix, that's why we keep 90MPa of it +#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, PH, and H2 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_PHORON_FUEL 15000 +#define ATMOSTANK_HYDROGEN 25000 +#define ATMOSTANK_HYDROGEN_FUEL 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 MAX_PUMP_PRESSURE 15000 // Maximal pressure setting for pumps and vents +#define MAX_OMNI_PRESSURE 7500 // Maximal output(s) pressure for omni devices (filters/mixers) + +//Used by turbine and TEG energy generation. +#define ADIABATIC_EXPONENT 0.667 //Actually adiabatic exponent - 1. + +//Used by air tanks. +#define TANK_MAX_RELEASE_PRESSURE (3*ONE_ATMOSPHERE) +#define TANK_DEFAULT_RELEASE_PRESSURE ONE_ATMOSPHERE diff --git a/code/__defines/atmospherics.dm b/code/__defines/atmospherics.dm new file mode 100644 index 00000000..6f8f3f47 --- /dev/null +++ b/code/__defines/atmospherics.dm @@ -0,0 +1,63 @@ +#define PIPE_SIMPLE_STRAIGHT 0 +#define PIPE_SIMPLE_BENT 1 +#define PIPE_HE_STRAIGHT 2 +#define PIPE_HE_BENT 3 +#define PIPE_CONNECTOR 4 +#define PIPE_MANIFOLD 5 +#define PIPE_JUNCTION 6 +#define PIPE_UVENT 7 +#define PIPE_MVALVE 8 +#define PIPE_DVALVE 9 +#define PIPE_PUMP 10 +#define PIPE_SCRUBBER 11 +//#define unsed 12 +#define PIPE_GAS_FILTER 13 +#define PIPE_GAS_MIXER 14 +#define PIPE_PASSIVE_GATE 15 +#define PIPE_VOLUME_PUMP 16 +#define PIPE_HEAT_EXCHANGE 17 +#define PIPE_MTVALVE 18 +#define PIPE_MANIFOLD4W 19 +#define PIPE_CAP 20 +///// Z-Level stuff +#define PIPE_UP 21 +#define PIPE_DOWN 22 +///// Z-Level stuff +#define PIPE_GAS_FILTER_M 23 +#define PIPE_GAS_MIXER_T 24 +#define PIPE_GAS_MIXER_M 25 +#define PIPE_OMNI_MIXER 26 +#define PIPE_OMNI_FILTER 27 +///// Supply, scrubbers and universal pipes +#define PIPE_UNIVERSAL 28 +#define PIPE_SUPPLY_STRAIGHT 29 +#define PIPE_SUPPLY_BENT 30 +#define PIPE_SCRUBBERS_STRAIGHT 31 +#define PIPE_SCRUBBERS_BENT 32 +#define PIPE_SUPPLY_MANIFOLD 33 +#define PIPE_SCRUBBERS_MANIFOLD 34 +#define PIPE_SUPPLY_MANIFOLD4W 35 +#define PIPE_SCRUBBERS_MANIFOLD4W 36 +#define PIPE_SUPPLY_UP 37 +#define PIPE_SCRUBBERS_UP 38 +#define PIPE_SUPPLY_DOWN 39 +#define PIPE_SCRUBBERS_DOWN 40 +#define PIPE_SUPPLY_CAP 41 +#define PIPE_SCRUBBERS_CAP 42 +///// Mirrored T-valve ~ because I couldn't be bothered re-sorting all of the defines +#define PIPE_MTVALVEM 43 +///// I also couldn't be bothered sorting, so automatic shutoff valve. +#define PIPE_SVALVE 44 + +#define PIPE_FUEL_STRAIGHT 45 +#define PIPE_FUEL_BENT 46 +#define PIPE_FUEL_MANIFOLD 47 +#define PIPE_FUEL_MANIFOLD4W 48 +#define PIPE_FUEL_UP 49 +#define PIPE_FUEL_DOWN 50 +#define PIPE_FUEL_CAP 51 + +#define CONNECT_TYPE_REGULAR 1 +#define CONNECT_TYPE_SUPPLY 2 +#define CONNECT_TYPE_SCRUBBER 4 +#define CONNECT_TYPE_HE 8 \ No newline at end of file diff --git a/code/__defines/callback.dm b/code/__defines/callback.dm new file mode 100644 index 00000000..26c81f8b --- /dev/null +++ b/code/__defines/callback.dm @@ -0,0 +1,4 @@ +#define GLOBAL_PROC "some_magic_bullshit" + +#define CALLBACK new /datum/callback +#define INVOKE_ASYNC ImmediateInvokeAsync \ No newline at end of file diff --git a/code/__defines/chemistry.dm b/code/__defines/chemistry.dm new file mode 100644 index 00000000..8af6cb08 --- /dev/null +++ b/code/__defines/chemistry.dm @@ -0,0 +1,50 @@ +#define DEFAULT_HUNGER_FACTOR 0.03 // Factor of how fast mob nutrition decreases + +#define REM 0.2 // Means 'Reagent Effect Multiplier'. This is how many units of reagent are consumed per tick + +#define CHEM_TOUCH 1 +#define CHEM_INGEST 2 +#define CHEM_BLOOD 3 + +#define MINIMUM_CHEMICAL_VOLUME 0.01 + +#define REAGENT_SOLID 1 +#define REAGENT_LIQUID 2 +#define REAGENT_GAS 3 + +#define REAGENTS_OVERDOSE 30 + +#define CHEM_SYNTH_ENERGY 500 // How much energy does it take to synthesize 1 unit of chemical, in Joules. + +// Some on_mob_life() procs check for alien races. +#define IS_DIONA 1 +#define IS_VOX 2 +#define IS_SKRELL 3 +#define IS_UNATHI 4 +#define IS_TAJARA 5 +#define IS_XENOS 6 +#define IS_SLIME 8 +#define IS_NABBER 9 + +#define CE_STABLE "stable" // Inaprovaline +#define CE_ANTIBIOTIC "antibiotic" // Spaceacilin +#define CE_BLOODRESTORE "bloodrestore" // Iron/nutriment +#define CE_PAINKILLER "painkiller" +#define CE_ALCOHOL "alcohol" // Liver filtering +#define CE_ALCOHOL_TOXIC "alcotoxic" // Liver damage +#define CE_SPEEDBOOST "gofast" // Hyperzine +#define CE_SLOWDOWN "goslow" // Slowdown +#define CE_PULSE "xcardic" // increases or decreases heart rate +#define CE_NOPULSE "heartstop" // stops heartbeat +#define CE_ANTITOX "antitox" // Dylovene +#define CE_OXYGENATED "oxygen" // Dexalin. +#define CE_BRAIN_REGEN "brainfix" // Alkysine. +#define CE_ANTIVIRAL "antiviral" // Anti-virus effect. +#define CE_TOXIN "toxins" // Generic toxins, stops autoheal. +#define CE_BREATHLOSS "breathloss" // Breathing depression, makes you need more air +#define CE_MIND "mindbending" // Stabilizes or wrecks mind. Used for hallucinations +#define CE_CRYO "cryogenic" // Prevents damage from being frozen + +//reagent flags +#define IGNORE_MOB_SIZE 0x1 +#define AFFECTS_DEAD 0x2 diff --git a/code/__defines/client.dm b/code/__defines/client.dm new file mode 100644 index 00000000..0794c852 --- /dev/null +++ b/code/__defines/client.dm @@ -0,0 +1,2 @@ +#define CLIENT_MIN_FPS 0 +#define CLIENT_MAX_FPS 1000 diff --git a/code/__defines/colors.dm b/code/__defines/colors.dm new file mode 100644 index 00000000..6c430184 --- /dev/null +++ b/code/__defines/colors.dm @@ -0,0 +1,62 @@ +// BYOND lower-cases color values, and thus we do so as well to ensure atom.color == COLOR_X will work correctly +#define COLOR_BLACK "#000000" +#define COLOR_NAVY_BLUE "#000080" +#define COLOR_GREEN "#008000" +#define COLOR_DARK_GRAY "#404040" +#define COLOR_MAROON "#800000" +#define COLOR_PURPLE "#800080" +#define COLOR_VIOLET "#9933ff" +#define COLOR_OLIVE "#808000" +#define COLOR_BROWN_ORANGE "#824b28" +#define COLOR_DARK_ORANGE "#b95a00" +#define COLOR_GRAY40 "#666666" +#define COLOR_SEDONA "#cc6600" +#define COLOR_DARK_BROWN "#917448" +#define COLOR_BLUE "#0000ff" +#define COLOR_DEEP_SKY_BLUE "#00e1ff" +#define COLOR_LIME "#00ff00" +#define COLOR_CYAN "#00ffff" +#define COLOR_TEAL "#33cccc" +#define COLOR_RED "#ff0000" +#define COLOR_PINK "#ff00ff" +#define COLOR_ORANGE "#ff9900" +#define COLOR_YELLOW "#ffff00" +#define COLOR_GRAY "#808080" +#define COLOR_RED_GRAY "#aa5f61" +#define COLOR_BROWN "#b19664" +#define COLOR_GREEN_GRAY "#8daf6a" +#define COLOR_BLUE_GRAY "#6a97b0" +#define COLOR_SUN "#ec8b2f" +#define COLOR_PURPLE_GRAY "#a2819e" +#define COLOR_BLUE_LIGHT "#33ccff" +#define COLOR_RED_LIGHT "#ff3333" +#define COLOR_BEIGE "#ceb689" +#define COLOR_PALE_GREEN_GRAY "#aed18b" +#define COLOR_PALE_RED_GRAY "#cc9090" +#define COLOR_PALE_PURPLE_GRAY "#bda2ba" +#define COLOR_PALE_BLUE_GRAY "#8bbbd5" +#define COLOR_LUMINOL "#66ffff" +#define COLOR_SILVER "#c0c0c0" +#define COLOR_GRAY80 "#cccccc" +#define COLOR_OFF_WHITE "#eeeeee" +#define COLOR_WHITE "#ffffff" +#define COLOR_NT_RED "#9d2300" +#define COLOR_GUNMETAL "#80868e" +#define COLOR_MUZZLE_FLASH "#ffffb2" +#define COLOR_CHESTNUT "#996633" +#define COLOR_BEASTY_BROWN "#663300" +#define COLOR_WHEAT "#ffff99" +#define COLOR_CYAN_BLUE "#3366cc" +#define COLOR_LIGHT_CYAN "#66ccff" +#define COLOR_PAKISTAN_GREEN "#006600" + +#define PIPE_COLOR_GREY "#ffffff" //yes white is grey +#define PIPE_COLOR_RED "#ff0000" +#define PIPE_COLOR_BLUE "#0000ff" +#define PIPE_COLOR_CYAN "#00ffff" +#define PIPE_COLOR_GREEN "#00ff00" +#define PIPE_COLOR_YELLOW "#ffcc00" +#define PIPE_COLOR_BLACK "#444444" +#define PIPE_COLOR_ORANGE "#b95a00" + +#define COLOR_BLOOD_HUMAN "#a10808" diff --git a/code/__defines/components.dm b/code/__defines/components.dm new file mode 100644 index 00000000..f2270733 --- /dev/null +++ b/code/__defines/components.dm @@ -0,0 +1,17 @@ +//shorthand +#define GET_COMPONENT_FROM(varname, path, target) var##path/##varname = ##target.GetComponent(##path) +#define GET_COMPONENT(varname, path) GET_COMPONENT_FROM(varname, path, src) + +// How multiple components of the exact same type are handled in the same datum + +#define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default) +#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed +#define COMPONENT_DUPE_UNIQUE 2 //new component is deleted + +// All signals. Format: +// When the signal is called: (signal arguments) + +#define COMSIG_COMPONENT_ADDED "component_added" //when a component is added to a datum: (datum/component) +#define COMSIG_COMPONENT_REMOVING "component_removing" //before a component is removed from a datum because of RemoveComponent: (datum/component) +#define COMSIG_PARENT_QDELETED "parent_qdeleted" //before a datum's Destroy() is called: () +#define COMSIG_UNARMEDATTACK "UnarmedAttack" \ No newline at end of file diff --git a/code/__defines/damage_organs.dm b/code/__defines/damage_organs.dm new file mode 100644 index 00000000..db75714e --- /dev/null +++ b/code/__defines/damage_organs.dm @@ -0,0 +1,78 @@ +// Damage things. TODO: Merge these down to reduce on defines. +// Way to waste perfectly good damage-type names (BRUTE) on this... If you were really worried about case sensitivity, you could have just used lowertext(damagetype) in the proc. +#define BRUTE "brute" +#define BURN "fire" +#define TOX "tox" +#define OXY "oxy" +#define CLONE "clone" +#define PAIN "pain" +#define ELECTROCUTE "electrocute" +#define STAMINA "stamina" + + +#define CUT "cut" +#define BRUISE "bruise" +#define PIERCE "pierce" +#define LASER "laser" + +#define STUN "stun" +#define WEAKEN "weaken" +#define PARALYZE "paralize" +#define IRRADIATE "irradiate" +#define SLUR "slur" +#define STUTTER "stutter" +#define EYE_BLUR "eye_blur" +#define DROWSY "drowsy" + +// Damage flags +#define DAM_SHARP (1<<0) +#define DAM_EDGE (1<<1) +#define DAM_LASER (1<<2) + +#define FIRE_DAMAGE_MODIFIER 0.0215 // Higher values result in more external fire damage to the skin. (default 0.0215) +#define AIR_DAMAGE_MODIFIER 2.025 // More means less damage from hot air scalding lungs, less = more damage. (default 2.025) + +// Organ defines. +#define ORGAN_CUT_AWAY (1<<0) +#define ORGAN_BLEEDING (1<<1) +#define ORGAN_BROKEN (1<<2) +#define ORGAN_DEAD (1<<3) +#define ORGAN_MUTATED (1<<4) +#define ORGAN_ARTERY_CUT (1<<6) +#define ORGAN_TENDON_CUT (1<<7) + +#define DROPLIMB_EDGE 0 +#define DROPLIMB_BLUNT 1 +#define DROPLIMB_BURN 2 + +// Robotics hatch_state defines. +#define HATCH_CLOSED 0 +#define HATCH_UNSCREWED 1 +#define HATCH_OPENED 2 + +// These control the amount of blood lost from burns. The loss is calculated so +// that dealing just enough burn damage to kill the player will cause the given +// proportion of their max blood volume to be lost +// (e.g. 0.6 == 60% lost if 200 burn damage is taken). +#define FLUIDLOSS_WIDE_BURN 0.6 //for burns from heat applied over a wider area, like from fire +#define FLUIDLOSS_CONC_BURN 0.4 //for concentrated burns, like from lasers + +// Damage above this value must be repaired with surgery. +#define ROBOLIMB_SELF_REPAIR_CAP 30 + +#define ORGAN_ASSISTED 1 +#define ORGAN_ROBOT 2 + +//Germs and infections. +#define GERM_LEVEL_AMBIENT 110 // Maximum germ level you can reach by standing still. +#define GERM_LEVEL_MOVE_CAP 200 // Maximum germ level you can reach by running around. + +#define INFECTION_LEVEL_ONE 100 +#define INFECTION_LEVEL_TWO 500 +#define INFECTION_LEVEL_THREE 1000 + +//Blood levels. These are percentages based on the species blood_volume far. +#define BLOOD_VOLUME_SAFE 85 +#define BLOOD_VOLUME_OKAY 75 +#define BLOOD_VOLUME_BAD 60 +#define BLOOD_VOLUME_SURVIVE 40 \ No newline at end of file diff --git a/code/__defines/deity.dm b/code/__defines/deity.dm new file mode 100644 index 00000000..99f7511b --- /dev/null +++ b/code/__defines/deity.dm @@ -0,0 +1,2 @@ +#define DEITY_STRUCTURE_NEAR_IMPORTANT 1 //Whether this needs to be near an important structure. +#define DEITY_STRUCTURE_ALONE 2 //Whether this can be near another of the same type. \ No newline at end of file diff --git a/code/__defines/dna.dm b/code/__defines/dna.dm new file mode 100644 index 00000000..547f8a23 --- /dev/null +++ b/code/__defines/dna.dm @@ -0,0 +1,76 @@ +// Bitflags for mutations. +#define STRUCDNASIZE 27 +#define UNIDNASIZE 13 + +// Generic mutations: +#define TK 1 +#define COLD_RESISTANCE 2 +#define XRAY 3 +#define HULK 4 +#define CLUMSY 5 +#define FAT 6 +#define HUSK 7 +#define NOCLONE 8 +#define LASER_MUTATION 9 // Harm intent - click anywhere to shoot lasers from eyes. +#define HEAL 10 // Healing people with hands. + +#define SKELETON 29 +#define PLANT 30 + +// Other Mutations: +#define mNobreath 100 // No need to breathe. +#define mRemote 101 // Remote viewing. +#define mRegen 102 // Health regeneration. +#define mRun 103 // No slowdown. +#define mRemotetalk 104 // Remote talking. +#define mMorph 105 // Hanging appearance. +#define mBlend 106 // Nothing. (seriously nothing) +#define mHallucination 107 // Hallucinations. +#define mFingerprints 108 // No fingerprints. +#define mShock 109 // Insulated hands. +#define mSmallsize 110 // Table climbing. + +// disabilities +#define NEARSIGHTED 0x1 +#define EPILEPSY 0x2 +#define COUGHING 0x4 +#define TOURETTES 0x8 +#define NERVOUS 0x10 + +// sdisabilities +#define BLIND 0x1 +#define MUTE 0x2 +#define DEAF 0x4 + +// The way blocks are handled badly needs a rewrite, this is horrible. +// Too much of a project to handle at the moment, TODO for later. +GLOBAL_VAR_INIT(BLINDBLOCK,0) +GLOBAL_VAR_INIT(DEAFBLOCK,0) +GLOBAL_VAR_INIT(HULKBLOCK,0) +GLOBAL_VAR_INIT(TELEBLOCK,0) +GLOBAL_VAR_INIT(FIREBLOCK,0) +GLOBAL_VAR_INIT(XRAYBLOCK,0) +GLOBAL_VAR_INIT(CLUMSYBLOCK,0) +GLOBAL_VAR_INIT(FAKEBLOCK,0) +GLOBAL_VAR_INIT(COUGHBLOCK,0) +GLOBAL_VAR_INIT(GLASSESBLOCK,0) +GLOBAL_VAR_INIT(EPILEPSYBLOCK,0) +GLOBAL_VAR_INIT(TWITCHBLOCK,0) +GLOBAL_VAR_INIT(NERVOUSBLOCK,0) +GLOBAL_VAR_INIT(MONKEYBLOCK, STRUCDNASIZE) + +GLOBAL_VAR_INIT(BLOCKADD,0) +GLOBAL_VAR_INIT(DIFFMUT,0) + +GLOBAL_VAR_INIT(HEADACHEBLOCK,0) +GLOBAL_VAR_INIT(NOBREATHBLOCK,0) +GLOBAL_VAR_INIT(REMOTEVIEWBLOCK,0) +GLOBAL_VAR_INIT(REGENERATEBLOCK,0) +GLOBAL_VAR_INIT(INCREASERUNBLOCK,0) +GLOBAL_VAR_INIT(REMOTETALKBLOCK,0) +GLOBAL_VAR_INIT(MORPHBLOCK,0) +GLOBAL_VAR_INIT(BLENDBLOCK,0) +GLOBAL_VAR_INIT(HALLUCINATIONBLOCK,0) +GLOBAL_VAR_INIT(NOPRINTSBLOCK,0) +GLOBAL_VAR_INIT(SHOCKIMMUNITYBLOCK,0) +GLOBAL_VAR_INIT(SMALLSIZEBLOCK,0) diff --git a/code/__defines/feedback.dm b/code/__defines/feedback.dm new file mode 100644 index 00000000..9e6d7c3c --- /dev/null +++ b/code/__defines/feedback.dm @@ -0,0 +1,2 @@ +#define FEEDBACK_YOU_LACK_DEXTERITY "You don't have the dexterity to do this!" +#define FEEDBACK_ACCESS_DENIED "Access Denied!" \ No newline at end of file diff --git a/code/__defines/flags.dm b/code/__defines/flags.dm new file mode 100644 index 00000000..958ac2cc --- /dev/null +++ b/code/__defines/flags.dm @@ -0,0 +1,42 @@ +GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768)) + +#define CLOSET_HAS_LOCK 1 +#define CLOSET_CAN_BE_WELDED 2 + +#define CLOSET_STORAGE_MISC 1 +#define CLOSET_STORAGE_ITEMS 2 +#define CLOSET_STORAGE_MOBS 4 +#define CLOSET_STORAGE_STRUCTURES 8 +#define CLOSET_STORAGE_ALL (~0) + +// Flags bitmasks. + +#define ATOM_FLAG_CHECKS_BORDER 0x0001 // If a dense atom (potentially) only blocks movements from a given direction, i.e. window panes +#define ATOM_FLAG_CLIMBABLE 0x0002 // This object can be climbed on +#define ATOM_FLAG_NO_BLOOD 0x0004 // Used for items if they don't want to get a blood overlay. +#define ATOM_FLAG_NO_REACT 0x0008 // Reagents don't react inside this container. +#define ATOM_FLAG_OPEN_CONTAINER 0x0010 // Is an open container for chemistry purposes. + +#define MOVABLE_FLAG_PROXMOVE 0x0001 // Does this object require proximity checking in Enter()? + +#define OBJ_FLAG_ANCHORABLE 0x0001 // This object can be stuck in place with a tool +#define OBJ_FLAG_CONDUCTIBLE 0x0002 // Conducts electricity. (metal etc.) + +//Flags for items (equipment) +#define ITEM_FLAG_NO_BLUDGEON 0x0001 // When an item has this it produces no "X has been hit by Y with Z" message with the default handler. +#define ITEM_FLAG_PHORONGUARD 0x0002 // Does not get contaminated by phoron. +#define ITEM_FLAG_NO_PRINT 0x0004 // This object does not leave the user's prints/fibres when using it +#define ITEM_FLAG_THICKMATERIAL 0x0010 // Prevents syringes, reagent pens, and hyposprays if equiped to slot_suit or slot_head. +#define ITEM_FLAG_STOPPRESSUREDAMAGE 0x0020 // Counts towards pressure protection. Note that like temperature protection, body_parts_covered is considered here as well. +#define ITEM_FLAG_AIRTIGHT 0x0040 // Functions with internals. +#define ITEM_FLAG_NOSLIP 0x0080 // Prevents from slipping on wet floors, in space, etc. +#define ITEM_FLAG_BLOCK_GAS_SMOKE_EFFECT 0x0100 // Blocks the effect that chemical clouds would have on a mob -- glasses, mask and helmets ONLY! (NOTE: flag shared with ONESIZEFITSALL) +#define ITEM_FLAG_FLEXIBLEMATERIAL 0x0200 // At the moment, masks with this flag will not prevent eating even if they are covering your face. +#define ITEM_FLAG_PREMODIFIED 0x0400 // Gloves that are clipped by default +#define ITEM_FLAG_ABSTRACT 0x0800 // Shit that can't be seen when you examine a person. + +// Flags for pass_flags. +#define PASS_FLAG_TABLE 0x1 +#define PASS_FLAG_GLASS 0x2 +#define PASS_FLAG_GRILLE 0x4 +#define PASS_FLAG_MOB 0x10 diff --git a/code/__defines/gamemode.dm b/code/__defines/gamemode.dm new file mode 100644 index 00000000..81d70cbf --- /dev/null +++ b/code/__defines/gamemode.dm @@ -0,0 +1,90 @@ +#define GAME_STATE_PREGAME 1 +#define GAME_STATE_SETTING_UP 2 +#define GAME_STATE_PLAYING 3 +#define GAME_STATE_FINISHED 4 + +#define BE_PLANT "BE_PLANT" +#define BE_SYNTH "BE_SYNTH" +#define BE_PAI "BE_PAI" + +// Antagonist datum flags. +#define ANTAG_OVERRIDE_JOB 0x1 // Assigned job is set to MODE when spawning. +#define ANTAG_OVERRIDE_MOB 0x2 // Mob is recreated from datum mob_type var when spawning. +#define ANTAG_CLEAR_EQUIPMENT 0x4 // All preexisting equipment is purged. +#define ANTAG_CHOOSE_NAME 0x8 // Antagonists are prompted to enter a name. +#define ANTAG_IMPLANT_IMMUNE 0x10 // Cannot be loyalty implanted. +#define ANTAG_SUSPICIOUS 0x20 // Shows up on roundstart report. +#define ANTAG_HAS_LEADER 0x40 // Generates a leader antagonist. +#define ANTAG_HAS_NUKE 0x80 // Will spawn a nuke at supplied location. +#define ANTAG_RANDSPAWN 0x100 // Potentially randomly spawns due to events. +#define ANTAG_VOTABLE 0x200 // Can be voted as an additional antagonist before roundstart. +#define ANTAG_SET_APPEARANCE 0x400 // Causes antagonists to use an appearance modifier on spawn. +#define ANTAG_RANDOM_EXCEPTED 0x800 // If a game mode randomly selects antag types, antag types with this flag should be excluded. + +// Mode/antag template macros. +#define MODE_BORER "borer" +#define MODE_XENOMORPH "xeno" +#define MODE_LOYALIST "loyalist" +#define MODE_MUTINEER "mutineer" +#define MODE_COMMANDO "commando" +#define MODE_DEATHSQUAD "deathsquad" +#define MODE_ERT "ert" +#define MODE_ACTOR "actor" +#define MODE_MERCENARY "mercenary" +#define MODE_RAIDER "raider" +#define MODE_WIZARD "wizard" +#define MODE_CHANGELING "changeling" +#define MODE_CULTIST "cultist" +#define MODE_MONKEY "monkey" +#define MODE_RENEGADE "renegade" +#define MODE_REVOLUTIONARY "revolutionary" +#define MODE_MALFUNCTION "malf" +#define MODE_TRAITOR "traitor" +#define MODE_DEITY "deity" +#define MODE_USURP "usurp" + +#define DEFAULT_TELECRYSTAL_AMOUNT 50 //130 ARE YOU HIGH? +#define IMPLANT_TELECRYSTAL_AMOUNT(x) (round(x * 0.49)) // If this cost is ever greater than half of DEFAULT_TELECRYSTAL_AMOUNT then it is possible to buy more TC than you spend + +///////////////// +////WIZARD ////// +///////////////// + +/* WIZARD SPELL FLAGS */ +#define GHOSTCAST 0x1 //can a ghost cast it? +#define NEEDSCLOTHES 0x2 //does it need the wizard garb to cast? Nonwizard spells should not have this +#define NEEDSHUMAN 0x4 //does it require the caster to be human? +#define Z2NOCAST 0x8 //if this is added, the spell can't be cast at centcomm +#define STATALLOWED 0x10 //if set, the user doesn't have to be conscious to cast. Required for ghost spells +#define IGNOREPREV 0x20 //if set, each new target does not overlap with the previous one +//The following flags only affect different types of spell, and therefore overlap +//Targeted spells +#define INCLUDEUSER 0x40 //does the spell include the caster in its target selection? +#define SELECTABLE 0x80 //can you select each target for the spell? +//AOE spells +#define IGNOREDENSE 0x40 //are dense turfs ignored in selection? +#define IGNORESPACE 0x80 //are space turfs ignored in selection? +//End split flags +#define CONSTRUCT_CHECK 0x100 //used by construct spells - checks for nullrods +#define NO_BUTTON 0x200 //spell won't show up in the HUD with this + +//invocation +#define SpI_SHOUT "shout" +#define SpI_WHISPER "whisper" +#define SpI_EMOTE "emote" +#define SpI_NONE "none" + +//upgrading +#define Sp_SPEED "speed" +#define Sp_POWER "power" +#define Sp_TOTAL "total" + +//casting costs +#define Sp_RECHARGE "recharge" +#define Sp_CHARGES "charges" +#define Sp_HOLDVAR "holdervar" + +#define INITIALIZATION_NOW 1 +#define INITIALIZATION_HAS_BEGUN 2 +#define INITIALIZATION_COMPLETE 4 +#define INITIALIZATION_NOW_AND_COMPLETE (INITIALIZATION_NOW|INITIALIZATION_COMPLETE) diff --git a/code/__defines/inventory_sizes.dm b/code/__defines/inventory_sizes.dm new file mode 100644 index 00000000..9bbdcef0 --- /dev/null +++ b/code/__defines/inventory_sizes.dm @@ -0,0 +1,25 @@ +// The below should be used to define an item's w_class variable. +// Example: w_class = ITENSIZE_LARGE +// This allows the addition of future w_classes without needing to change every file. +#define ITEM_SIZE_TINY 1 +#define ITEM_SIZE_SMALL 2 +#define ITEM_SIZE_NORMAL 3 +#define ITEM_SIZE_LARGE 4 +#define ITEM_SIZE_HUGE 5 +#define ITEM_SIZE_GARGANTUAN 6 +#define ITEM_SIZE_NO_CONTAINER INFINITY // Use this to forbid item from being placed in a container. + + +/* + The values below are not yet in use. +*/ + +#define base_storage_cost(w_class) (2**(w_class-1)) //1,2,4,8,16,... + +//linear increase. Using many small storage containers is more space-efficient than using large ones, +//in exchange for being limited in the w_class of items that will fit +#define base_storage_capacity(w_class) (7*(w_class-1)) + +#define DEFAULT_BACKPACK_STORAGE base_storage_capacity(5) +#define DEFAULT_LARGEBOX_STORAGE base_storage_capacity(4) +#define DEFAULT_BOX_STORAGE base_storage_capacity(3) diff --git a/code/__defines/items_clothing.dm b/code/__defines/items_clothing.dm new file mode 100644 index 00000000..a6bb618e --- /dev/null +++ b/code/__defines/items_clothing.dm @@ -0,0 +1,229 @@ +#define HUMAN_STRIP_DELAY 40 // Takes 40ds = 4s to strip someone. + +#define CANDLE_LUM 3 // For how bright candles are. + +// Item inventory slot bitmasks. +#define SLOT_OCLOTHING 0x1 +#define SLOT_ICLOTHING 0x2 +#define SLOT_GLOVES 0x4 +#define SLOT_EYES 0x8 +#define SLOT_EARS 0x10 +#define SLOT_MASK 0x20 +#define SLOT_HEAD 0x40 +#define SLOT_FEET 0x80 +#define SLOT_ID 0x100 +#define SLOT_BELT 0x200 +#define SLOT_BACK 0x400 +#define SLOT_POCKET 0x800 // This is to allow items with a w_class of 3 or 4 to fit in pockets. +#define SLOT_DENYPOCKET 0x1000 // This is to deny items with a w_class of 2 or 1 from fitting in pockets. +#define SLOT_TWOEARS 0x2000 +#define SLOT_TIE 0x4000 +#define SLOT_S_STORE 0x8000 +#define SLOT_HOLSTER 0x1600 //16th bit - higher than this will overflow + +#define ACCESSORY_SLOT_UTILITY "Utility" +#define ACCESSORY_SLOT_HOLSTER "Holster" +#define ACCESSORY_SLOT_ARMBAND "Armband" +#define ACCESSORY_SLOT_RANK "Rank" +#define ACCESSORY_SLOT_DEPT "Department" +#define ACCESSORY_SLOT_DECOR "Decor" +#define ACCESSORY_SLOT_MEDAL "Medal" +#define ACCESSORY_SLOT_INSIGNIA "Insignia" +#define ACCESSORY_SLOT_ARMOR_C "Chest armor" +#define ACCESSORY_SLOT_ARMOR_A "Arm armor" +#define ACCESSORY_SLOT_ARMOR_L "Leg armor" +#define ACCESSORY_SLOT_ARMOR_S "Armor storage" +#define ACCESSORY_SLOT_ARMOR_M "Misc armor" +#define ACCESSORY_SLOT_HELM_C "Helmet cover" + +// Bitmasks for the flags_inv variable. These determine when a piece of clothing hides another, i.e. a helmet hiding glasses. +// WARNING: The following flags apply only to the external suit! +#define HIDEGLOVES 0x1 +#define HIDESUITSTORAGE 0x2 +#define HIDEJUMPSUIT 0x4 +#define HIDESHOES 0x8 +#define HIDETAIL 0x10 + +// WARNING: The following flags apply only to the helmets and masks! +#define HIDEMASK 0x1 +#define HIDEEARS 0x2 // Headsets and such. +#define HIDEEYES 0x4 // Glasses. +#define HIDEFACE 0x8 // Dictates whether we appear as "Unknown". + +#define BLOCKHEADHAIR 0x20 // Hides the user's hair overlay. Leaves facial hair. +#define BLOCKHAIR 0x40 // Hides the user's hair, facial and otherwise. + +// Slots. +#define slot_first 1 +#define slot_back 1 +#define slot_wear_mask 2 +#define slot_handcuffed 3 +#define slot_l_hand 4 +#define slot_r_hand 5 +#define slot_belt 6 +#define slot_wear_id 7 +#define slot_l_ear 8 +#define slot_glasses 9 +#define slot_gloves 10 +#define slot_head 11 +#define slot_shoes 12 +#define slot_wear_suit 13 +#define slot_w_uniform 14 +#define slot_l_store 15 +#define slot_r_store 16 +#define slot_s_store 17 +#define slot_in_backpack 18 +#define slot_legcuffed 19 +#define slot_r_ear 20 +#define slot_legs 21 +#define slot_tie 22 +#define slot_last 22 + +// Inventory slot strings. +// since numbers cannot be used as associative list keys. +//icon_back, icon_l_hand, etc would be much better names for these... +#define slot_back_str "slot_back" +#define slot_l_hand_str "slot_l_hand" +#define slot_r_hand_str "slot_r_hand" +#define slot_w_uniform_str "slot_w_uniform" +#define slot_wear_suit_str "slot_suit" +#define slot_l_ear_str "slot_l_ear" +#define slot_r_ear_str "slot_r_ear" +#define slot_belt_str "slot_belt" +#define slot_shoes_str "slot_shoes" +#define slot_head_str "slot_head" +#define slot_wear_mask_str "slot_wear_mask" +#define slot_handcuffed_str "slot_handcuffed" +#define slot_legcuffed_str "slot_legcuffed" +#define slot_wear_id_str "slot_wear_id" +#define slot_gloves_str "slot_gloves" +#define slot_glasses_str "slot_glasses" +#define slot_s_store_str "slot_s_store" +#define slot_tie_str "slot_tie" + +// Bitflags for clothing parts. +#define HEAD 0x1 +#define FACE 0x2 +#define EYES 0x4 +#define UPPER_TORSO 0x8 +#define LOWER_TORSO 0x10 +#define LEG_LEFT 0x20 +#define LEG_RIGHT 0x40 +#define LEGS 0x60 // LEG_LEFT | LEG_RIGHT +#define FOOT_LEFT 0x80 +#define FOOT_RIGHT 0x100 +#define FEET 0x180 // FOOT_LEFT | FOOT_RIGHT +#define ARM_LEFT 0x200 +#define ARM_RIGHT 0x400 +#define ARMS 0x600 // ARM_LEFT | ARM_RIGHT +#define HAND_LEFT 0x800 +#define HAND_RIGHT 0x1000 +#define HANDS 0x1800 // HAND_LEFT | HAND_RIGHT +#define FULL_BODY 0xFFFF + +// Bitflags for the percentual amount of protection a piece of clothing which covers the body part offers. +// Used with human/proc/get_heat_protection() and human/proc/get_cold_protection(). +// The values here should add up to 1, e.g., the head has 30% protection. +#define THERMAL_PROTECTION_HEAD 0.3 +#define THERMAL_PROTECTION_UPPER_TORSO 0.15 +#define THERMAL_PROTECTION_LOWER_TORSO 0.15 +#define THERMAL_PROTECTION_LEG_LEFT 0.075 +#define THERMAL_PROTECTION_LEG_RIGHT 0.075 +#define THERMAL_PROTECTION_FOOT_LEFT 0.025 +#define THERMAL_PROTECTION_FOOT_RIGHT 0.025 +#define THERMAL_PROTECTION_ARM_LEFT 0.075 +#define THERMAL_PROTECTION_ARM_RIGHT 0.075 +#define THERMAL_PROTECTION_HAND_LEFT 0.025 +#define THERMAL_PROTECTION_HAND_RIGHT 0.025 + +// Pressure limits. +#define HAZARD_HIGH_PRESSURE 550 // This determines at what pressure the ultra-high pressure red icon is displayed. (This one is set as a constant) +#define WARNING_HIGH_PRESSURE 325 // This determines when the orange pressure icon is displayed (it is 0.7 * HAZARD_HIGH_PRESSURE) +#define WARNING_LOW_PRESSURE 50 // This is when the gray low pressure icon is displayed. (it is 2.5 * HAZARD_LOW_PRESSURE) +#define HAZARD_LOW_PRESSURE 20 // This is when the black ultra-low pressure icon is displayed. (This one is set as a constant) + +#define TEMPERATURE_DAMAGE_COEFFICIENT 1.5 // This is used in handle_temperature_damage() for humans, and in reagents that affect body temperature. Temperature damage is multiplied by this amount. +#define BODYTEMP_AUTORECOVERY_DIVISOR 12 // This is the divisor which handles how much of the temperature difference between the current body temperature and 310.15K (optimal temperature) humans auto-regenerate each tick. The higher the number, the slower the recovery. This is applied each tick, so long as the mob is alive. +#define BODYTEMP_AUTORECOVERY_MINIMUM 1 // Minimum amount of kelvin moved toward 310.15K per tick. So long as abs(310.15 - bodytemp) is more than 50. +#define BODYTEMP_COLD_DIVISOR 6 // Similar to the BODYTEMP_AUTORECOVERY_DIVISOR, but this is the divisor which is applied at the stage that follows autorecovery. This is the divisor which comes into play when the human's loc temperature is lower than their body temperature. Make it lower to lose bodytemp faster. +#define BODYTEMP_HEAT_DIVISOR 6 // Similar to the BODYTEMP_AUTORECOVERY_DIVISOR, but this is the divisor which is applied at the stage that follows autorecovery. This is the divisor which comes into play when the human's loc temperature is higher than their body temperature. Make it lower to gain bodytemp faster. +#define BODYTEMP_COOLING_MAX -30 // The maximum number of degrees that your body can cool down in 1 tick, when in a cold area. +#define BODYTEMP_HEATING_MAX 30 // The maximum number of degrees that your body can heat up in 1 tick, when in a hot area. + +#define BODYTEMP_HEAT_DAMAGE_LIMIT 360.15 // The limit the human body can take before it starts taking damage from heat. +#define BODYTEMP_COLD_DAMAGE_LIMIT 260.15 // The limit the human body can take before it starts taking damage from coldness. + +#define SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE 2.0 // What min_cold_protection_temperature is set to for space-helmet quality headwear. MUST NOT BE 0. +#define SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE 2.0 // What min_cold_protection_temperature is set to for space-suit quality jumpsuits or suits. MUST NOT BE 0. +#define HELMET_MIN_COLD_PROTECTION_TEMPERATURE 160 // For normal helmets. +#define ARMOR_MIN_COLD_PROTECTION_TEMPERATURE 160 // For armor. +#define GLOVES_MIN_COLD_PROTECTION_TEMPERATURE 2.0 // For some gloves. +#define SHOE_MIN_COLD_PROTECTION_TEMPERATURE 2.0 // For shoes. + +#define SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE 5000 // These need better heat protect, but not as good heat protect as firesuits. +#define FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE 30000 // What max_heat_protection_temperature is set to for firesuit quality headwear. MUST NOT BE 0. +#define FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE 30000 // For fire-helmet quality items. (Red and white hardhats) +#define HELMET_MAX_HEAT_PROTECTION_TEMPERATURE 600 // For normal helmets. +#define ARMOR_MAX_HEAT_PROTECTION_TEMPERATURE 600 // For armor. +#define GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE 1500 // For some gloves. +#define SHOE_MAX_HEAT_PROTECTION_TEMPERATURE 1500 // For shoes. + +// Fire. +#define FIRE_MIN_STACKS -20 +#define FIRE_MAX_STACKS 25 +#define FIRE_MAX_FIRESUIT_STACKS 20 // If the number of stacks goes above this firesuits won't protect you anymore. If not, you can walk around while on fire like a badass. + +#define THROWFORCE_SPEED_DIVISOR 5 // The throwing speed value at which the throwforce multiplier is exactly 1. +#define THROWNOBJ_KNOCKBACK_SPEED 15 // The minumum speed of a w_class 2 thrown object that will cause living mobs it hits to be knocked back. Heavier objects can cause knockback at lower speeds. +#define THROWNOBJ_KNOCKBACK_DIVISOR 2 // Affects how much speed the mob is knocked back with. + +// Suit sensor levels +#define SUIT_SENSOR_OFF 0 +#define SUIT_SENSOR_BINARY 1 +#define SUIT_SENSOR_VITAL 2 +#define SUIT_SENSOR_TRACKING 3 + +#define SUIT_NO_SENSORS 0 +#define SUIT_HAS_SENSORS 1 +#define SUIT_LOCKED_SENSORS 2 + +// Hair Flags +#define VERY_SHORT 0x1 +#define HAIR_TRIPPABLE 0x2 + +// Storage + +/* + A note on w_classes - this is an attempt to describe the w_classes currently in use + with an attempt at providing examples of the kinds of things that fit each w_class + + 1 - tiny items - things like screwdrivers and pens, sheets of paper + 2 - small items - things that can fit in a pocket + 3 - normal items + 4 - large items - the largest things you can fit in a backpack + 5 - bulky items - backpacks are this size, for reference + 6 - human sized objects + 7 - things that are large enough to contain humans, like closets, but smaller than entire turfs + 8 - things that take up an entire turf, like wall girders or door assemblies +*/ + +var/list/default_onmob_icons = list( + slot_l_hand_str = 'icons/mob/onmob/items/lefthand.dmi', + slot_r_hand_str = 'icons/mob/onmob/items/righthand.dmi', + slot_belt_str = 'icons/mob/onmob/belt.dmi', + slot_back_str = 'icons/mob/onmob/back.dmi', + slot_l_ear_str = 'icons/mob/onmob/ears.dmi', + slot_r_ear_str = 'icons/mob/onmob/ears.dmi', + slot_glasses_str = 'icons/mob/onmob/eyes.dmi', + slot_wear_id_str = 'icons/mob/onmob/id.dmi', + slot_w_uniform_str = 'icons/mob/onmob/uniform.dmi', + slot_wear_suit_str = 'icons/mob/onmob/suit.dmi', + slot_head_str = 'icons/mob/onmob/head.dmi', + slot_shoes_str = 'icons/mob/onmob/feet.dmi', + slot_wear_mask_str = 'icons/mob/onmob/mask.dmi', + slot_handcuffed_str = 'icons/mob/onmob/misc.dmi', + slot_legcuffed_str = 'icons/mob/onmob/misc.dmi', + slot_gloves_str = 'icons/mob/onmob/hands.dmi', + slot_s_store_str = 'icons/mob/onmob/belt_mirror.dmi', + slot_tie_str = 'icons/mob/onmob/ties.dmi' + ) diff --git a/code/__defines/kaos.dm b/code/__defines/kaos.dm new file mode 100644 index 00000000..b8bf9d33 --- /dev/null +++ b/code/__defines/kaos.dm @@ -0,0 +1,12 @@ +/* Copyright (C) KDC Kyrah Design Concept - All Rights Reserved + * Unauthorized copying of this file, via any medium is strictly prohibited + * + * Proprietary and confidential + * Do not modify or remove this header. + * + * Written by Kyrah Abattoir , August 2018 + */ + +#define KAOS_ALIGN_LEFT -1 +#define KAOS_ALIGN_CENTER 0 +#define KAOS_ALIGN_RIGHT 1 diff --git a/code/__defines/languages.dm b/code/__defines/languages.dm new file mode 100644 index 00000000..3dd43470 --- /dev/null +++ b/code/__defines/languages.dm @@ -0,0 +1,36 @@ +// Languages. +#define LANGUAGE_GALCOM "Galactic Common" +#define LANGUAGE_EAL "Encoded Audio Language" +#define LANGUAGE_SOL_COMMON "Sol Common" +#define LANGUAGE_UNATHI "Sinta'unathi" +#define LANGUAGE_SIIK_MAAS "Siik'maas" +#define LANGUAGE_SIIK_TAJR "Siik'tajr" +#define LANGUAGE_SKRELLIAN "Skrellian" +#define LANGUAGE_ROOTLOCAL "Local Rootspeak" +#define LANGUAGE_ROOTGLOBAL "Global Rootspeak" +#define LANGUAGE_LUNAR "Selenian" +#define LANGUAGE_GUTTER "Gutter" +#define LANGUAGE_CULT "Cult" +#define LANGUAGE_SIGN "Sign Language" +#define LANGUAGE_INDEPENDENT "Independent" +#define LANGUAGE_NABBER "Serpentid" +#define LANGUAGE_SPACER "Spacer" +#define LANGUAGE_BOGANI "Bogani" + +#define LANGUAGE_ENGLISH "English" +#define LANGUAGE_GERMAN "German" + +#define LANGUAGE_RED "Redenese" +#define LANGUAGE_BLUE "Bluesnian" + +// Language flags. +#define WHITELISTED 1 // Language is available if the speaker is whitelisted. +#define RESTRICTED 2 // Language can only be acquired by spawning or an admin. +#define NONVERBAL 4 // Language has a significant non-verbal component. Speech is garbled without line-of-sight. +#define SIGNLANG 8 // Language is completely non-verbal. Speech is displayed through emotes for those who can understand. +#define HIVEMIND 16 // Broadcast to all mobs with this language. +#define NONGLOBAL 32 // Do not add to general languages list. +#define INNATE 64 // All mobs can be assumed to speak and understand this language. (audible emotes) +#define NO_TALK_MSG 128 // Do not show the "\The [speaker] talks into \the [radio]" message +#define NO_STUTTER 256 // No stuttering, slurring, or other speech problems +#define ALT_TRANSMIT 512 // Language is not based on vision or sound (Todo: add this into the say code and use it for the rootspeak languages) diff --git a/code/__defines/lighting.dm b/code/__defines/lighting.dm new file mode 100644 index 00000000..71ef56dc --- /dev/null +++ b/code/__defines/lighting.dm @@ -0,0 +1,94 @@ +#define FOR_DVIEW(type, range, center, invis_flags) \ + GLOB.dview_mob.loc = center; \ + GLOB.dview_mob.see_invisible = invis_flags; \ + for(type in view(range, GLOB.dview_mob)) + +#define END_FOR_DVIEW dview_mob.loc = null + +#define LIGHTING_FALLOFF 1 // type of falloff to use for lighting; 1 for circular, 2 for square +#define LIGHTING_LAMBERTIAN 0 // use lambertian shading for light sources +#define LIGHTING_HEIGHT 1 // height off the ground of light sources on the pseudo-z-axis, you should probably leave this alone + +#define LIGHTING_LAYER 10 // drawing layer for lighting overlays +#define LIGHTING_ICON 'icons/effects/lighting_overlay.dmi' // icon used for lighting shading effects +#define LIGHTING_ICON_STATE_DARK "soft_dark" // Change between "soft_dark" and "dark" to swap soft darkvision + +#define LIGHTING_ROUND_VALUE (1 / 64) // Value used to round lumcounts, values smaller than 1/69 don't matter (if they do, thanks sinking points), greater values will make lighting less precise, but in turn increase performance, VERY SLIGHTLY. + +#define LIGHTING_SOFT_THRESHOLD 0.05 // If the max of the lighting lumcounts of each spectrum drops below this, disable luminosity on the lighting overlays. This also should be the transparancy of the "soft_dark" icon state. + +#define LIGHTING_MULT_FACTOR 0.5 + +// If I were you I'd leave this alone. +#define LIGHTING_BASE_MATRIX \ + list \ + ( \ + LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ + LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ + LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ + LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ + 0, 0, 0, 1 \ + ) \ + +// Helpers so we can (more easily) control the colour matrices. +#define CL_MATRIX_RR 1 +#define CL_MATRIX_RG 2 +#define CL_MATRIX_RB 3 +#define CL_MATRIX_RA 4 +#define CL_MATRIX_GR 5 +#define CL_MATRIX_GG 6 +#define CL_MATRIX_GB 7 +#define CL_MATRIX_GA 8 +#define CL_MATRIX_BR 9 +#define CL_MATRIX_BG 10 +#define CL_MATRIX_BB 11 +#define CL_MATRIX_BA 12 +#define CL_MATRIX_AR 13 +#define CL_MATRIX_AG 14 +#define CL_MATRIX_AB 15 +#define CL_MATRIX_AA 16 +#define CL_MATRIX_CR 17 +#define CL_MATRIX_CG 18 +#define CL_MATRIX_CB 19 +#define CL_MATRIX_CA 20 + + +//Some defines to generalise colours used in lighting. +//Important note on colors. Colors can end up significantly different from the basic html picture, especially when saturated +#define LIGHT_COLOR_RED "#FA8282" //Warm but extremely diluted red. rgb(250, 130, 130) +#define LIGHT_COLOR_GREEN "#64C864" //Bright but quickly dissipating neon green. rgb(100, 200, 100) +#define LIGHT_COLOR_BLUE "#6496FA" //Cold, diluted blue. rgb(100, 150, 250) + +#define LIGHT_COLOR_CYAN "#7DE1E1" //Diluted cyan. rgb(125, 225, 225) +#define LIGHT_COLOR_PINK "#E17DE1" //Diluted, mid-warmth pink. rgb(225, 125, 225) +#define LIGHT_COLOR_YELLOW "#E1E17D" //Dimmed yellow, leaning kaki. rgb(225, 225, 125) +#define LIGHT_COLOR_BROWN "#966432" //Clear brown, mostly dim. rgb(150, 100, 50) +#define LIGHT_COLOR_ORANGE "#FA9632" //Mostly pure orange. rgb(250, 150, 50) +#define LIGHT_COLOR_PURPLE "#A97FAA" //Soft purple. rgb(169, 127, 170) +#define LIGHT_COLOR_VIOLET "#B43CB8" //Deep purple. rgb(180, 60, 184) +#define LIGHT_COLOR_SCARLET "#E85656" //Light red. rgb(232, 86, 86) + +//These ones aren't a direct colour like the ones above, because nothing would fit +#define LIGHT_COLOR_FIRE "#FAA019" //Warm orange color, leaning strongly towards yellow. rgb(250, 160, 25) +#define LIGHT_COLOR_LAVA "#C48A18" //Very warm yellow, leaning slightly towards orange. rgb(196, 138, 24) +#define LIGHT_COLOR_FLARE "#FA644B" //Bright, non-saturated red. Leaning slightly towards pink for visibility. rgb(250, 100, 75) +#define LIGHT_COLOR_SLIME_LAMP "#AFC84B" //Weird color, between yellow and green, very slimy. rgb(175, 200, 75) +#define LIGHT_COLOR_TUNGSTEN "#FAE1AF" //Extremely diluted yellow, close to skin color (for some reason). rgb(250, 225, 175) +#define LIGHT_COLOR_HALOGEN "#F0FAFA" //Barely visible cyan-ish hue, as the doctor prescribed. rgb(240, 250, 250) +#define LIGHT_COLOR_EMERGENCY "#FF3232" //Red color used by emergency lighting. rgb(255, 50, 50) + + +// -- Ambient Occlusion -- + +// Not handled by the lighting engine, but related. Controls the alpha of the ambient occlusion effect on opaque atoms and openturfs. +#define WALL_AO_ALPHA 90 + +#define AO_UPDATE_NONE 0 +#define AO_UPDATE_OVERLAY 1 +#define AO_UPDATE_REBUILD 2 + +// If ao_neighbors equals this, no AO shadows are present. +#define AO_ALL_NEIGHBORS 1910 + +// If defined, integrate with the lighting engine and use its opacity value. Otherwise a simple turf opacity check is used. This may cause visual artifacts with opaque non-square movables. +//#define AO_USE_LIGHTING_OPACITY diff --git a/code/__defines/machinery.dm b/code/__defines/machinery.dm new file mode 100644 index 00000000..02201bf3 --- /dev/null +++ b/code/__defines/machinery.dm @@ -0,0 +1,107 @@ +var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called manually after an event. + +#define KILOWATTS *1000 +#define MEGAWATTS *1000000 +#define GIGAWATTS *1000000000 + +#define MACHINERY_TICKRATE 2 // Tick rate for machinery in seconds. As it affects CELLRATE calculation it is kept as define here + +#define CELLRATE (1 / ( 3600 / MACHINERY_TICKRATE )) // Multiplier for charge units. Converts cell charge units(watthours) to joules. Takes into consideration that our machinery ticks once per two seconds. + +// Doors! +#define DOOR_CRUSH_DAMAGE 40 +#define ALIEN_SELECT_AFK_BUFFER 1 // How many minutes that a person can be AFK before not being allowed to be an alien. + +// Channel numbers for power. +#define EQUIP 1 +#define LIGHT 2 +#define ENVIRON 3 +#define TOTAL 4 // For total power used only. + +// Bitflags for machine stat variable. +#define BROKEN 0x1 +#define NOPOWER 0x2 +#define POWEROFF 0x4 // TBD. +#define MAINT 0x8 // Under maintenance. +#define EMPED 0x10 // Temporary broken by EMP pulse. + +// Used by firelocks +#define FIREDOOR_OPEN 1 +#define FIREDOOR_CLOSED 2 + +#define AI_CAMERA_LUMINOSITY 6 + +// Camera networks +#define NETWORK_CRESCENT "Crescent" +#define NETWORK_ENGINEERING "Engineering" +#define NETWORK_ERT "ZeEmergencyResponseTeam" +#define NETWORK_EXODUS "Exodus" +#define NETWORK_MEDICAL "Medical" +#define NETWORK_MERCENARY "MercurialNet" +#define NETWORK_MINE "Mining" +#define NETWORK_RESEARCH "Research" +#define NETWORK_ROBOTS "Robots" +#define NETWORK_SECURITY "Security" +#define NETWORK_THUNDER "Thunderdome" + +#define NETWORK_ALARM_ATMOS "Atmosphere Alarms" +#define NETWORK_ALARM_CAMERA "Camera Alarms" +#define NETWORK_ALARM_FIRE "Fire Alarms" +#define NETWORK_ALARM_MOTION "Motion Alarms" +#define NETWORK_ALARM_POWER "Power Alarms" + +// Those networks can only be accessed by pre-existing terminals. AIs and new terminals can't use them. +var/list/restricted_camera_networks = list(NETWORK_ERT,NETWORK_MERCENARY,"Secret") + + +//singularity defines +#define STAGE_ONE 1 +#define STAGE_TWO 3 +#define STAGE_THREE 5 +#define STAGE_FOUR 7 +#define STAGE_FIVE 9 +#define STAGE_SUPER 11 + +// NanoUI flags +#define STATUS_INTERACTIVE 2 // GREEN Visability +#define STATUS_UPDATE 1 // ORANGE Visability +#define STATUS_DISABLED 0 // RED Visability +#define STATUS_CLOSE -1 // Close the interface + +/* + * Atmospherics Machinery. +*/ +#define MAX_SIPHON_FLOWRATE 2500 // L/s. This can be used to balance how fast a room is siphoned. Anything higher than CELL_VOLUME has no effect. +#define MAX_SCRUBBER_FLOWRATE 200 // L/s. Max flow rate when scrubbing from a turf. + +// These balance how easy or hard it is to create huge pressure gradients with pumps and filters. +// Lower values means it takes longer to create large pressures differences. +// Has no effect on pumping gasses from high pressure to low, only from low to high. +#define ATMOS_PUMP_EFFICIENCY 2.5 +#define ATMOS_FILTER_EFFICIENCY 2.5 + +// Will not bother pumping or filtering if the gas source as fewer than this amount of moles, to help with performance. +#define MINIMUM_MOLES_TO_PUMP 0.01 +#define MINIMUM_MOLES_TO_FILTER 0.04 + +// The flow rate/effectiveness of various atmos devices is limited by their internal volume, +// so for many atmos devices these will control maximum flow rates in L/s. +#define ATMOS_DEFAULT_VOLUME_PUMP 200 // Liters. +#define ATMOS_DEFAULT_VOLUME_FILTER 500 // L. +#define ATMOS_DEFAULT_VOLUME_MIXER 500 // L. +#define ATMOS_DEFAULT_VOLUME_PIPE 70 // L. + +#define TELECOMMS_RECEPTION_NONE 0 +#define TELECOMMS_RECEPTION_SENDER 1 +#define TELECOMMS_RECEPTION_RECEIVER 2 +#define TELECOMMS_RECEPTION_BOTH 3 + +// These are used by supermatter and supermatter monitor program, mostly for UI updating purposes. Higher should always be worse! +#define SUPERMATTER_ERROR -1 // Unknown status, shouldn't happen but just in case. +#define SUPERMATTER_INACTIVE 0 // No or minimal energy +#define SUPERMATTER_NORMAL 1 // Normal operation +#define SUPERMATTER_NOTIFY 2 // Ambient temp > 80% of CRITICAL_TEMPERATURE +#define SUPERMATTER_WARNING 3 // Ambient temp > CRITICAL_TEMPERATURE OR integrity damaged +#define SUPERMATTER_DANGER 4 // Integrity < 50% +#define SUPERMATTER_EMERGENCY 5 // Integrity < 25% +#define SUPERMATTER_DELAMINATING 6 // Pretty obvious. \ No newline at end of file diff --git a/code/__defines/mapping.dm b/code/__defines/mapping.dm new file mode 100644 index 00000000..c83aeb6d --- /dev/null +++ b/code/__defines/mapping.dm @@ -0,0 +1,7 @@ +// Maploader bounds indices +#define MAP_MINX 1 +#define MAP_MINY 2 +#define MAP_MINZ 3 +#define MAP_MAXX 4 +#define MAP_MAXY 5 +#define MAP_MAXZ 6 diff --git a/code/__defines/materials.dm b/code/__defines/materials.dm new file mode 100644 index 00000000..72c610c8 --- /dev/null +++ b/code/__defines/materials.dm @@ -0,0 +1,5 @@ +#define MATERIAL_ALTERATION_NONE 0 +#define MATERIAL_ALTERATION_NAME 1 +#define MATERIAL_ALTERATION_DESC 2 +#define MATERIAL_ALTERATION_COLOR 4 +#define MATERIAL_ALTERATION_ALL (~MATERIAL_ALTERATION_NONE) diff --git a/code/__defines/math_physics.dm b/code/__defines/math_physics.dm new file mode 100644 index 00000000..59bcff33 --- /dev/null +++ b/code/__defines/math_physics.dm @@ -0,0 +1,33 @@ +// Math constants. +#define M_PI 3.14159265 + +#define R_IDEAL_GAS_EQUATION 8.31 // kPa*L/(K*mol). +#define ONE_ATMOSPHERE 101.325 // kPa. +#define IDEAL_GAS_ENTROPY_CONSTANT 1164 // (mol^3 * s^3) / (kg^3 * L). + +// Radiation constants. +#define STEFAN_BOLTZMANN_CONSTANT 5.6704e-8 // W/(m^2*K^4). +#define COSMIC_RADIATION_TEMPERATURE 3.15 // K. +#define AVERAGE_SOLAR_RADIATION 200 // W/m^2. Kind of arbitrary. Really this should depend on the sun position much like solars. +#define RADIATOR_OPTIMUM_PRESSURE 3771 // kPa at 20 C. This should be higher as gases aren't great conductors until they are dense. Used the critical pressure for air. +#define GAS_CRITICAL_TEMPERATURE 132.65 // K. The critical point temperature for air. + +#define RADIATOR_EXPOSED_SURFACE_AREA_RATIO 0.04 // (3 cm + 100 cm * sin(3deg))/(2*(3+100 cm)). Unitless ratio. +#define HUMAN_EXPOSED_SURFACE_AREA 5.2 //m^2, surface area of 1.7m (H) x 0.46m (D) cylinder + +#define T0C 273.15 // 0.0 degrees celcius +#define T20C 293.15 // 20.0 degrees celcius +#define TCMB 2.7 // -270.3 degrees celcius + +#define CLAMP01(x) max(0, min(1, x)) +#define CLAMP(CLVALUE,CLMIN,CLMAX) ( max( (CLMIN), min((CLVALUE), (CLMAX)) ) ) +#define ATMOS_PRECISION 0.0001 +#define QUANTIZE(variable) (round(variable, ATMOS_PRECISION)) + +#define INFINITY 1.#INF + +#define TICKS_IN_DAY 24*60*60*10 +#define TICKS_IN_SECOND 10 + +#define SIMPLE_SIGN(X) ((X) < 0 ? -1 : 1) +#define SIGN(X) ((X) ? SIMPLE_SIGN(X) : 0) diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm new file mode 100644 index 00000000..e4c81710 --- /dev/null +++ b/code/__defines/misc.dm @@ -0,0 +1,309 @@ +#define DEBUG +// Turf-only flags. +#define TURF_FLAG_NOJAUNT 1 // This is used in literally one place, turf.dm, to block ethereal jaunt. +#define TURF_FLAG_NORUINS 2 + +#define TRANSITIONEDGE 7 // Distance from edge to move to another z-level. +#define RUIN_MAP_EDGE_PAD 15 + +#define JOINTEXT(X) jointext(X, null) + +//lazy text span classes defines. +#define span(class, text) "[text]" +#define SPAN_NOTICE(X) "[X]" +#define SPAN_WARNING(X) "[X]" +#define SPAN_DANGER(X) "[X]" +#define SPAN_BNOTICE(X) "[X]" +#define SPAN_BOLD(X) "[X]" + +#define FONT_SMALL(X) "[X]" +#define FONT_NORMAL(X) "[X]" +#define FONT_LARGE(X) "[X]" +#define FONT_HUGE(X) "[X]" +#define FONT_GIANT(X) "[X]" + +#define text_starts_with(text, start) (copytext(text, 1, length(start) + 1) == start) + +//Misc text define. Does 4 spaces. Used as a makeshift tabulator. +#define FOURSPACES "    " + +// Invisibility constants. +#define INVISIBILITY_LIGHTING 20 +#define INVISIBILITY_LEVEL_ONE 35 +#define INVISIBILITY_LEVEL_TWO 45 +#define INVISIBILITY_OBSERVER 60 +#define INVISIBILITY_EYE 61 +#define INVISIBILITY_SYSTEM 99 + +#define SEE_INVISIBLE_LIVING 25 +#define SEE_INVISIBLE_NOLIGHTING 15 +#define SEE_INVISIBLE_LEVEL_ONE INVISIBILITY_LEVEL_ONE +#define SEE_INVISIBLE_LEVEL_TWO INVISIBILITY_LEVEL_TWO +#define SEE_INVISIBLE_CULT INVISIBILITY_OBSERVER +#define SEE_INVISIBLE_OBSERVER INVISIBILITY_EYE +#define SEE_INVISIBLE_SYSTEM INVISIBILITY_SYSTEM + +#define SEE_IN_DARK_DEFAULT 2 + +#define SEE_INVISIBLE_MINIMUM 5 +#define INVISIBILITY_MAXIMUM 100 + +// Some arbitrary defines to be used by self-pruning global lists. (see master_controller) +#define PROCESS_KILL 26 // Used to trigger removal from a processing list. + +// For secHUDs and medHUDs and variants. The number is the location of the image on the list hud_list of humans. +#define HEALTH_HUD 1 // A simple line rounding the mob's number health. +#define STATUS_HUD 2 // Alive, dead, diseased, etc. +#define ID_HUD 3 // The job asigned to your ID. +#define WANTED_HUD 4 // Wanted, released, paroled, security status. +#define IMPLOYAL_HUD 5 // Loyality implant. +#define IMPCHEM_HUD 6 // Chemical implant. +#define IMPTRACK_HUD 7 // Tracking implant. +#define SPECIALROLE_HUD 8 // AntagHUD image. +#define STATUS_HUD_OOC 9 // STATUS_HUD without virus DB check for someone being ill. +#define LIFE_HUD 10 // STATUS_HUD that only reports dead or alive + +// Shuttle moving status. +#define SHUTTLE_IDLE 0 +#define SHUTTLE_WARMUP 1 +#define SHUTTLE_INTRANSIT 2 + +// Autodock shuttle processing status. +#define IDLE_STATE 0 +#define WAIT_LAUNCH 1 +#define FORCE_LAUNCH 2 +#define WAIT_ARRIVE 3 +#define WAIT_FINISH 4 + +// Setting this much higher than 1024 could allow spammers to DOS the server easily. +#define MAX_MESSAGE_LEN 1024 +#define MAX_PAPER_MESSAGE_LEN 3072 +#define MAX_BOOK_MESSAGE_LEN 9216 +#define MAX_LNAME_LEN 64 +#define MAX_NAME_LEN 26 +#define MAX_DESC_LEN 128 +#define MAX_TEXTFILE_LENGTH 128000 // 512GQ file + +// Event defines. +#define EVENT_LEVEL_MUNDANE 1 +#define EVENT_LEVEL_MODERATE 2 +#define EVENT_LEVEL_MAJOR 3 + +//General-purpose life speed define for plants. +#define HYDRO_SPEED_MULTIPLIER 1 + +#define DEFAULT_JOB_TYPE /datum/job/assistant + +//Area flags, possibly more to come +#define AREA_FLAG_RAD_SHIELDED 1 // shielded from radiation, clearly +#define AREA_FLAG_EXTERNAL 2 // External as in exposed to space, not outside in a nice, green, forest + +// Convoluted setup so defines can be supplied by Bay12 main server compile script. +// Should still work fine for people jamming the icons into their repo. +#ifndef CUSTOM_ITEM_OBJ +#define CUSTOM_ITEM_OBJ 'icons/obj/custom_items_obj.dmi' +#endif +#ifndef CUSTOM_ITEM_MOB +#define CUSTOM_ITEM_MOB 'icons/mob/custom_items_mob.dmi' +#endif +#ifndef CUSTOM_ITEM_SYNTH +#define CUSTOM_ITEM_SYNTH 'icons/mob/custom_synthetic.dmi' +#endif + +#define WALL_CAN_OPEN 1 +#define WALL_OPENING 2 + +#define DEFAULT_TABLE_MATERIAL "plastic" +#define DEFAULT_WALL_MATERIAL "steel" + +#define SHARD_SHARD "shard" +#define SHARD_SHRAPNEL "shrapnel" +#define SHARD_STONE_PIECE "piece" +#define SHARD_SPLINTER "splinters" +#define SHARD_NONE "" + +#define MATERIAL_UNMELTABLE 0x1 +#define MATERIAL_BRITTLE 0x2 +#define MATERIAL_PADDING 0x4 + +#define TABLE_BRITTLE_MATERIAL_MULTIPLIER 4 // Amount table damage is multiplied by if it is made of a brittle material (e.g. glass) + +#define BOMBCAP_DVSTN_RADIUS (GLOB.max_explosion_range/4) +#define BOMBCAP_HEAVY_RADIUS (GLOB.max_explosion_range/2) +#define BOMBCAP_LIGHT_RADIUS GLOB.max_explosion_range +#define BOMBCAP_FLASH_RADIUS (GLOB.max_explosion_range*1.5) + // NTNet module-configuration values. Do not change these. If you need to add another use larger number (5..6..7 etc) +#define NTNET_SOFTWAREDOWNLOAD 1 // Downloads of software from NTNet +#define NTNET_PEERTOPEER 2 // P2P transfers of files between devices +#define NTNET_COMMUNICATION 3 // Communication (messaging) +#define NTNET_SYSTEMCONTROL 4 // Control of various systems, RCon, air alarm control, etc. + +// NTNet transfer speeds, used when downloading/uploading a file/program. +#define NTNETSPEED_LOWSIGNAL 0.25 // GQ/s transfer speed when the device is wirelessly connected and on Low signal +#define NTNETSPEED_HIGHSIGNAL 0.5 // GQ/s transfer speed when the device is wirelessly connected and on High signal +#define NTNETSPEED_ETHERNET 1 // GQ/s transfer speed when the device is using wired connection +#define NTNETSPEED_DOS_AMPLIFICATION 5 // Multiplier for Denial of Service program. Resulting load on NTNet relay is this multiplied by NTNETSPEED of the device + +// Program bitflags +#define PROGRAM_ALL 15 +#define PROGRAM_CONSOLE 1 +#define PROGRAM_LAPTOP 2 +#define PROGRAM_TABLET 4 +#define PROGRAM_TELESCREEN 8 + +#define PROGRAM_STATE_KILLED 0 +#define PROGRAM_STATE_BACKGROUND 1 +#define PROGRAM_STATE_ACTIVE 2 + +// Caps for NTNet logging. Less than 10 would make logging useless anyway, more than 500 may make the log browser too laggy. Defaults to 100 unless user changes it. +#define MAX_NTNET_LOGS 500 +#define MIN_NTNET_LOGS 10 + +//Affects the chance that armour will block an attack. Should be between 0 and 1. +//If set to 0, then armor will always prevent the same amount of damage, always, with no randomness whatsoever. +//Of course, this will affect code that checks for blocked < 100, as blocked will be less likely to actually be 100. +#define ARMOR_BLOCK_CHANCE_MULT 1.0 + +// Special return values from bullet_act(). Positive return values are already used to indicate the blocked level of the projectile. +#define PROJECTILE_CONTINUE -1 //if the projectile should continue flying after calling bullet_act() +#define PROJECTILE_FORCE_MISS -2 //if the projectile should treat the attack as a miss (suppresses attack and admin logs) - only applies to mobs. + +//Camera capture modes +#define CAPTURE_MODE_REGULAR 0 //Regular polaroid camera mode +#define CAPTURE_MODE_ALL 1 //Admin camera mode +#define CAPTURE_MODE_PARTIAL 3 //Simular to regular mode, but does not do dummy check + +//objectives +#define CONFIG_OBJECTIVE_NONE 2 +#define CONFIG_OBJECTIVE_VERB 1 +#define CONFIG_OBJECTIVE_ALL 0 + +// How many times an AI tries to connect to APC before switching to low power mode. +#define AI_POWER_RESTORE_MAX_ATTEMPTS 3 + +// AI power restoration routine steps. +#define AI_RESTOREPOWER_FAILED -1 +#define AI_RESTOREPOWER_IDLE 0 +#define AI_RESTOREPOWER_STARTING 1 +#define AI_RESTOREPOWER_DIAGNOSTICS 2 +#define AI_RESTOREPOWER_CONNECTING 3 +#define AI_RESTOREPOWER_CONNECTED 4 +#define AI_RESTOREPOWER_COMPLETED 5 + + +// Values represented as Oxyloss. Can be tweaked, but make sure to use integers only. +#define AI_POWERUSAGE_LOWPOWER 1 +#define AI_POWERUSAGE_RESTORATION 2 +#define AI_POWERUSAGE_NORMAL 5 +#define AI_POWERUSAGE_RECHARGING 7 + +// Above values get multiplied by this when converting AI oxyloss -> watts. +// For now, one oxyloss point equals 10kJ of energy, so normal AI uses 5 oxyloss per tick (50kW or 70kW if charging) +#define AI_POWERUSAGE_OXYLOSS_TO_WATTS_MULTIPLIER 10000 + +//Grid for Item Placement +#define CELLS 8 //Amount of cells per row/column in grid +#define CELLSIZE (world.icon_size/CELLS) //Size of a cell in pixels + +//#define WORLD_ICON_SIZE 32 +#define PIXEL_MULTIPLIER WORLD_ICON_SIZE/32 + +#define DEFAULT_SPAWNPOINT_ID "Default" + +#define MIDNIGHT_ROLLOVER 864000 //number of deciseconds in a day + +//Virus badness defines +#define VIRUS_MILD 1 +#define VIRUS_COMMON 2 //Random events don't go higher (mutations aside) +#define VIRUS_ENGINEERED 3 +#define VIRUS_EXOTIC 4 //Usually adminbus only + +//Error handler defines +#define ERROR_USEFUL_LEN 2 + +#define RAD_LEVEL_LOW 0.5 // Around the level at which radiation starts to become harmful +#define RAD_LEVEL_MODERATE 5 +#define RAD_LEVEL_HIGH 25 +#define RAD_LEVEL_VERY_HIGH 75 + +#define RADIATION_THRESHOLD_CUTOFF 0.1 // Radiation will not affect a tile when below this value. + +#define LEGACY_RECORD_STRUCTURE(X, Y) GLOBAL_LIST_EMPTY(##X);/datum/computer_file/data/##Y/var/list/fields[0];/datum/computer_file/data/##Y/New(){..();GLOB.##X.Add(src);}/datum/computer_file/data/##Y/Destroy(){..();GLOB.##X.Remove(src);} + +#define EDIT_SHORTTEXT 1 // Short (single line) text input field +#define EDIT_LONGTEXT 2 // Long (multi line, papercode tag formattable) text input field +#define EDIT_NUMERIC 3 // Single-line number input field +#define EDIT_LIST 4 // Option select dialog + +#define REC_FIELD(KEY) /record_field/##KEY + +#define SUPPLY_SECURITY_ELEVATED 1 +#define SUPPLY_SECURITY_HIGH 2 + +#define DIFF_EASY "easy" //Used in achievements. +#define DIFF_MEDIUM "medium" +#define DIFF_HARD "hard" + +#define SUCCESS 1 //Used in stats and skills +#define FAILURE 0 +#define CRIT_SUCCESS 2 +#define CRIT_FAILURE -1 + + +//Some Aurora shit +#define N_NORTH 2 +#define N_SOUTH 4 +#define N_EAST 16 +#define N_WEST 256 +#define N_NORTHEAST 32 +#define N_NORTHWEST 512 +#define N_SOUTHEAST 64 +#define N_SOUTHWEST 1024 + +#define CALCULATE_NEIGHBORS(ORIGIN, VAR, TVAR, FUNC) \ + for (var/_tdir in GLOB.cardinal) { \ + TVAR = get_step(ORIGIN, _tdir); \ + if ((TVAR) && (FUNC)) { \ + VAR |= 1 << _tdir; \ + } \ + } \ + if (VAR & N_NORTH) { \ + if (VAR & N_WEST) { \ + TVAR = get_step(ORIGIN, NORTHWEST); \ + if (FUNC) { \ + VAR |= N_NORTHWEST; \ + } \ + } \ + if (VAR & N_EAST) { \ + TVAR = get_step(ORIGIN, NORTHEAST); \ + if (FUNC) { \ + VAR |= N_NORTHEAST; \ + } \ + } \ + } \ + if (VAR & N_SOUTH) { \ + if (VAR & N_WEST) { \ + TVAR = get_step(ORIGIN, SOUTHWEST); \ + if (FUNC) { \ + VAR |= N_SOUTHWEST; \ + } \ + } \ + if (VAR & N_EAST) { \ + TVAR = get_step(ORIGIN, SOUTHEAST); \ + if (FUNC) { \ + VAR |= N_SOUTHEAST; \ + } \ + } \ + } + + +//supposedly the fastest way to do this according to https://gist.github.com/Giacom/be635398926bb463b42a +#define RANGE_TURFS(RADIUS, CENTER) \ + block( \ + locate(max(CENTER.x-(RADIUS),1), max(CENTER.y-(RADIUS),1), CENTER.z), \ + locate(min(CENTER.x+(RADIUS),world.maxx), min(CENTER.y+(RADIUS),world.maxy), CENTER.z) \ + ) + +#define PUNCTUATION list("!", ".", "\"", ")", "'", ",", "?", ":", ";") + +#define CLIENT_FROM_VAR(I) (ismob(I) ? I:client : (istype(I, /client) ? I : (istype(I, /datum/mind) ? I:current?:client : null))) \ No newline at end of file diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm new file mode 100644 index 00000000..9d667b51 --- /dev/null +++ b/code/__defines/mobs.dm @@ -0,0 +1,377 @@ +// /mob/var/stat things. +#define CONSCIOUS 0 +#define UNCONSCIOUS 1 +#define DEAD 2 + +// Bitflags defining which status effects could be or are inflicted on a mob. +#define CANSTUN 0x1 +#define CANWEAKEN 0x2 +#define CANPARALYSE 0x4 +#define CANPUSH 0x8 +#define LEAPING 0x10 +#define PASSEMOTES 0x32 // Mob has a cortical borer or holders inside of it that need to see emotes. +#define GODMODE 0x1000 +#define FAKEDEATH 0x2000 // Replaces stuff like changeling.changeling_fakedeath. +#define NO_ANTAG 0x4000 // Players are restricted from gaining antag roles when occupying this mob +#define XENO_HOST 0x8000 // Tracks whether we're gonna be a baby alien's mummy. + +// Grab Types +#define GRAB_NORMAL "normal" +#define GRAB_NAB "nab" +#define GRAB_NAB_SPECIAL "special nab" +#define GRAB_TAKEDOWN "takedown" +#define GRAB_STRANGLE "strangle" +#define GRAB_WRENCH "wrench" + +// Grab levels. +#define NORM_PASSIVE "normal passive" +#define NORM_STRUGGLE "normal struggle" +#define NORM_AGGRESSIVE "normal aggressive" +#define NORM_NECK "normal neck" +#define NORM_KILL "normal kill" + +#define NAB_PASSIVE "nab passive" +#define NAB_AGGRESSIVE "nab aggressive" +#define NAB_KILL "nab kill" + +#define BORGMESON 0x1 +#define BORGTHERM 0x2 +#define BORGXRAY 0x4 +#define BORGMATERIAL 8 + +#define HOSTILE_STANCE_IDLE 1 +#define HOSTILE_STANCE_ALERT 2 +#define HOSTILE_STANCE_ATTACK 3 +#define HOSTILE_STANCE_ATTACKING 4 +#define HOSTILE_STANCE_TIRED 5 +#define HOSTILE_STANCE_INSIDE 6 + +#define LEFT 0x1 +#define RIGHT 0x2 +#define UNDER 0x4 + +// Pulse levels, very simplified. +#define PULSE_NONE 0 // So !M.pulse checks would be possible. +#define PULSE_SLOW 1 // <60 bpm +#define PULSE_NORM 2 // 60-90 bpm +#define PULSE_FAST 3 // 90-120 bpm +#define PULSE_2FAST 4 // >120 bpm +#define PULSE_THREADY 5 // Occurs during hypovolemic shock +#define GETPULSE_HAND 0 // Less accurate. (hand) +#define GETPULSE_TOOL 1 // More accurate. (med scanner, sleeper, etc.) + +//intent flags, why wasn't this done the first time? +#define I_HELP "help" +#define I_DISARM "disarm" +#define I_GRAB "grab" +#define I_HURT "harm" +#define I_DODGE "dodge" +#define I_PARRY "parry" +//atk intents +#define I_DEFENSE "defense" +#define I_OFFENSE "offense" +#define I_QUICK "quick" +#define I_AIMED "aimed" +#define I_GUARD "guard" +#define I_WEAK "weak" +#define I_FEINT "feint" +#define I_DUAL "dual" + +//These are used Bump() code for living mobs, in the mob_bump_flag, mob_swap_flags, and mob_push_flags vars to determine whom can bump/swap with whom. +#define HUMAN 1 +#define MONKEY 2 +#define ALIEN 4 +#define ROBOT 8 +#define SLIME 16 +#define SIMPLE_ANIMAL 32 +#define HEAVY 64 +#define ALLMOBS (HUMAN|MONKEY|ALIEN|ROBOT|SLIME|SIMPLE_ANIMAL|HEAVY) + +// Robot AI notifications +#define ROBOT_NOTIFICATION_NEW_UNIT 1 +#define ROBOT_NOTIFICATION_NEW_NAME 2 +#define ROBOT_NOTIFICATION_NEW_MODULE 3 +#define ROBOT_NOTIFICATION_MODULE_RESET 4 + +// Appearance change flags +#define APPEARANCE_UPDATE_DNA 0x1 +#define APPEARANCE_RACE (0x2|APPEARANCE_UPDATE_DNA) +#define APPEARANCE_GENDER (0x4|APPEARANCE_UPDATE_DNA) +#define APPEARANCE_SKIN 0x8 +#define APPEARANCE_HAIR 0x10 +#define APPEARANCE_HAIR_COLOR 0x20 +#define APPEARANCE_FACIAL_HAIR 0x40 +#define APPEARANCE_FACIAL_HAIR_COLOR 0x80 +#define APPEARANCE_EYE_COLOR 0x100 +#define APPEARANCE_ALL_HAIR (APPEARANCE_HAIR|APPEARANCE_HAIR_COLOR|APPEARANCE_FACIAL_HAIR|APPEARANCE_FACIAL_HAIR_COLOR) +#define APPEARANCE_ALL 0xFFFF + +// Click cooldown +#define DEFAULT_SLOW_COOLDOWN 16 //The default cooldown for slow actions. +#define DEFAULT_ATTACK_COOLDOWN 8 //Default timeout for aggressive actions +#define DEFAULT_QUICK_COOLDOWN 4 + + +#define MIN_SUPPLIED_LAW_NUMBER 15 +#define MAX_SUPPLIED_LAW_NUMBER 50 + + +// NT's alignment towards the character +#define COMPANY_LOYAL "Loyal" +#define COMPANY_SUPPORTATIVE "Supportive" +#define COMPANY_NEUTRAL "Neutral" +#define COMPANY_SKEPTICAL "Skeptical" +#define COMPANY_OPPOSED "Opposed" + +#define COMPANY_ALIGNMENTS list(COMPANY_LOYAL,COMPANY_SUPPORTATIVE,COMPANY_NEUTRAL,COMPANY_SKEPTICAL,COMPANY_OPPOSED) + +// Defines mob sizes, used by lockers and to determine what is considered a small sized mob, etc. +#define MOB_LARGE 40 +#define MOB_MEDIUM 20 +#define MOB_SMALL 10 +#define MOB_TINY 5 +#define MOB_MINISCULE 1 + +// Defines how strong the species is compared to humans. Think like strength in D&D +#define STR_VHIGH 2 +#define STR_HIGH 1 +#define STR_MEDIUM 0 +#define STR_LOW -1 +#define STR_VLOW -2 + +// Gluttony levels. +#define GLUT_TINY 1 // Eat anything tiny and smaller +#define GLUT_SMALLER 2 // Eat anything smaller than we are +#define GLUT_ANYTHING 4 // Eat anything, ever + +#define GLUT_ITEM_TINY 8 // Eat items with a w_class of small or smaller +#define GLUT_ITEM_NORMAL 16 // Eat items with a w_class of normal or smaller +#define GLUT_ITEM_ANYTHING 32 // Eat any item +#define GLUT_PROJECTILE_VOMIT 64 // When vomitting, does it fly out? + +// Devour speeds, returned by can_devour() +#define DEVOUR_SLOW 1 +#define DEVOUR_FAST 2 + +#define TINT_NONE 0 +#define TINT_MODERATE 1 +#define TINT_HEAVY 2 +#define TINT_BLIND 3 + +#define FLASH_PROTECTION_VULNERABLE -2 +#define FLASH_PROTECTION_REDUCED -1 +#define FLASH_PROTECTION_NONE 0 +#define FLASH_PROTECTION_MODERATE 1 +#define FLASH_PROTECTION_MAJOR 2 + +#define ANIMAL_SPAWN_DELAY round(config.respawn_delay / 6) +#define DRONE_SPAWN_DELAY round(config.respawn_delay / 3) + +// Incapacitation flags, used by the mob/proc/incapacitated() proc +#define INCAPACITATION_NONE 0 +#define INCAPACITATION_RESTRAINED 1 +#define INCAPACITATION_BUCKLED_PARTIALLY 2 +#define INCAPACITATION_BUCKLED_FULLY 4 +#define INCAPACITATION_STUNNED 8 +#define INCAPACITATION_FORCELYING 16 //needs a better name - represents being knocked down BUT still conscious. +#define INCAPACITATION_KNOCKOUT 32 + +#define INCAPACITATION_KNOCKDOWN (INCAPACITATION_KNOCKOUT|INCAPACITATION_FORCELYING) +#define INCAPACITATION_DISABLED (INCAPACITATION_KNOCKDOWN|INCAPACITATION_STUNNED) +#define INCAPACITATION_DEFAULT (INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY|INCAPACITATION_DISABLED) +#define INCAPACITATION_ALL (~INCAPACITATION_NONE) + +// Organs. +#define BP_MOUTH "mouth" +#define BP_EYES "eyes" +#define BP_HEART "heart" +#define BP_LUNGS "lungs" +#define BP_TRACH "tracheae" +#define BP_BRAIN "brain" +#define BP_LIVER "liver" +#define BP_KIDNEYS "kidneys" +#define BP_PLASMA "plasma vessel" +#define BP_APPENDIX "appendix" +#define BP_CELL "cell" +#define BP_HIVE "hive node" +#define BP_NUTRIENT "nutrient vessel" +#define BP_ACID "acid gland" +#define BP_EGG "egg sac" +#define BP_RESIN "resin spinner" +#define BP_STRATA "neural strata" +#define BP_RESPONSE "response node" +#define BP_GBLADDER "gas bladder" +#define BP_POLYP "polyp segment" +#define BP_ANCHOR "anchoring ligament" +#define BP_PHORON "phoron filter" +#define BP_THROAT "throat" +#define BP_VCHORDS "vocal chords" +#define BP_TONGUE "tongue" + +// Robo Organs. +#define BP_POSIBRAIN "posibrain" +#define BP_VOICE "vocal synthesiser" +#define BP_STACK "stack" +#define BP_OPTICS "optics" + + +// Limbs. +#define BP_L_FOOT "l_foot" +#define BP_R_FOOT "r_foot" +#define BP_L_LEG "l_leg" +#define BP_R_LEG "r_leg" +#define BP_L_HAND "l_hand" +#define BP_R_HAND "r_hand" +#define BP_L_ARM "l_arm" +#define BP_R_ARM "r_arm" +#define BP_HEAD "head" +#define BP_CHEST "chest" +#define BP_GROIN "groin" +#define BP_ALL_LIMBS list(BP_CHEST, BP_GROIN, BP_HEAD, BP_L_ARM, BP_R_ARM, BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT) +#define BP_BY_DEPTH list(BP_HEAD, BP_L_HAND, BP_R_HAND, BP_L_ARM, BP_R_ARM, BP_L_FOOT, BP_R_FOOT, BP_L_LEG, BP_R_LEG, BP_GROIN, BP_CHEST) + +#define SYNTH_BLOOD_COLOUR "#030303" +#define SYNTH_FLESH_COLOUR "#575757" + +#define MOB_PULL_NONE 0 +#define MOB_PULL_SMALLER 1 +#define MOB_PULL_SAME 2 +#define MOB_PULL_LARGER 3 + +//carbon taste sensitivity defines, used in mob/living/carbon/proc/ingest +#define TASTE_HYPERSENSITIVE 3 //anything below 5% +#define TASTE_SENSITIVE 2 //anything below 7% +#define TASTE_NORMAL 1 //anything below 15% +#define TASTE_DULL 0.5 //anything below 30% +#define TASTE_NUMB 0.1 //anything below 150% + +//Used by show_message() and emotes +#define VISIBLE_MESSAGE 1 +#define AUDIBLE_MESSAGE 2 + +//used for getting species temp values +#define COLD_LEVEL_1 -1 +#define COLD_LEVEL_2 -2 +#define COLD_LEVEL_3 -3 +#define HEAT_LEVEL_1 1 +#define HEAT_LEVEL_2 2 +#define HEAT_LEVEL_3 3 + +//Synthetic human temperature vals +#define SYNTH_COLD_LEVEL_1 50 +#define SYNTH_COLD_LEVEL_2 -1 +#define SYNTH_COLD_LEVEL_3 -1 +#define SYNTH_HEAT_LEVEL_1 500 +#define SYNTH_HEAT_LEVEL_2 1000 +#define SYNTH_HEAT_LEVEL_3 2000 + +#define CORPSE_CAN_REENTER 1 +#define CORPSE_CAN_REENTER_AND_RESPAWN 2 + +#define SPECIES_HUMAN "Human" +#define SPECIES_TAJARA "Tajara" +#define SPECIES_DIONA "Diona" +#define SPECIES_VOX "Vox" +#define SPECIES_IPC "Machine" +#define SPECIES_UNATHI "Unathi" +#define SPECIES_SKRELL "Skrell" +#define SPECIES_NABBER "Giant Armoured Serpentid" +#define SPECIES_PROMETHEAN "Promethean" +#define SPECIES_BOGANI "Bogani" +#define SPECIES_EGYNO "Egyno" + +#define SURGERY_CLOSED 0 +#define SURGERY_OPEN 1 +#define SURGERY_RETRACTED 2 +#define SURGERY_ENCASED 3 + +//#define STAMINA_EXHAUST 250 + +//Moods levels for humans +#define MOOD_LEVEL_HAPPY4 20 +#define MOOD_LEVEL_HAPPY3 15 +#define MOOD_LEVEL_HAPPY2 10 +#define MOOD_LEVEL_HAPPY1 5 +#define MOOD_LEVEL_NEUTRAL 0 +#define MOOD_LEVEL_SAD1 -5 +#define MOOD_LEVEL_SAD2 -10 +#define MOOD_LEVEL_SAD3 -15 +#define MOOD_LEVEL_SAD4 -20 + +#define NUTRITION_LEVEL_FAT 550 +#define NUTRITION_LEVEL_FULL 500 +#define NUTRITION_LEVEL_WELL_FED 450 +#define NUTRITION_LEVEL_FED 350 +#define NUTRITION_LEVEL_HUNGRY 250 +#define NUTRITION_LEVEL_STARVING 150 + +//Thirst levels for humans +#define THIRST_LEVEL_MAX 800 +#define THIRST_LEVEL_FILLED 600 +#define THIRST_LEVEL_MEDIUM 300 +#define THIRST_LEVEL_THIRSTY 200 +#define THIRST_LEVEL_DEHYDRATED 50 +#define THIRST_FACTOR 0.5 + +//Disgust levels for humans +#define DISGUST_LEVEL_MAXEDOUT 150 +#define DISGUST_LEVEL_DISGUSTED 75 +#define DISGUST_LEVEL_VERYGROSS 50 +#define DISGUST_LEVEL_GROSS 25 + +//Starvation stuff + +#define STARVATION_MIN 60 //If you have less nutrition than this value, the hunger indicator starts flashing - THIS ISN'T USED! +#define STARVATION_NOTICE 45 //If you have more nutrition than this value, you get an occasional message reminding you that you're going to starve soon +#define STARVATION_WEAKNESS 20 //Otherwise, if you have more nutrition than this value, you occasionally become weak and receive minor damage +#define STARVATION_NEARDEATH 5 //Otherwise, if you have more nutrition than this value, you have seizures and occasionally receive damage + +//If you have less nutrition than STARVATION_NEARDEATH, you start getting damage +#define STARVATION_OXY_DAMAGE 2.5 +#define STARVATION_TOX_DAMAGE 2.5 +#define STARVATION_BRAIN_DAMAGE 2.5 + +#define STARVATION_OXY_HEAL_RATE 1 //While starving, THIS much oxygen damage is restored per life tick (instead of the default 5) + +//Temperature stuff +//BODYTEMP_COLD_DAMAGE_LIMIT -13�C Below which freezing damage occurs. (defined in items_clothing.dm) +#define TEMPERATURE_REFRESHING 278.15 //5�C Below which drinks and foods are considered refreshing. +#define TEMPERATURE_WARM 323.15 //50�C Above which drinks and foods are considered warm. +//BODYTEMP_HEAT_DAMAGE_LIMIT 87�C Above which burn damage occurs. (defined in items_clothing.dm)#define STASIS_MISC "misc" +#define STASIS_CRYOBAG "cryobag" +#define STASIS_COLD "cold" + +#define AURA_CANCEL 1 +#define AURA_FALSE 2 +#define AURA_TYPE_BULLET "Bullet" +#define AURA_TYPE_WEAPON "Weapon" +#define AURA_TYPE_THROWN "Thrown" +#define AURA_TYPE_LIFE "Life" + +//Social classes +#define SOCIAL_CLASS_MIN 1 +#define SOCIAL_CLASS_MED 2 +#define SOCIAL_CLASS_HIGH 3 +#define SOCIAL_CLASS_MAX 4 + +#define SKILL(x) /datum/skill/##x + +#define STAT(x) /datum/stat/##x + +#define GET_STAT(x) my_stats[STAT(x)] +#define GET_SKILL(x) my_skills[SKILL(x)] + +#define STAT_LEVEL(x) my_stats[STAT(x)]?.level +#define SKILL_LEVEL(x) my_skills[SKILL(x)]?.level + +//TDM +#define BLUE_TEAM "Bluecoats" +#define RED_TEAM "Redcoats" + +/* +#define SKILL_LOW(x) x<=4 + +#define SKILL_MED(x) x>=5 && x<=8 + +#define SKILL_HIGH(x) x>=9 +*/ \ No newline at end of file diff --git a/code/__defines/proc_presets.dm b/code/__defines/proc_presets.dm new file mode 100644 index 00000000..05772133 --- /dev/null +++ b/code/__defines/proc_presets.dm @@ -0,0 +1 @@ +#define MERGE_ASSOCS_WITH_NUM_VALUES(a, b) merge_assoc_lists(a, b, /proc/assoc_merge_add, 1) diff --git a/code/__defines/process_scheduler.dm b/code/__defines/process_scheduler.dm new file mode 100644 index 00000000..d9c8f106 --- /dev/null +++ b/code/__defines/process_scheduler.dm @@ -0,0 +1,19 @@ +// Process status defines +#define PROCESS_STATUS_IDLE 1 +#define PROCESS_STATUS_QUEUED 2 +#define PROCESS_STATUS_RUNNING 3 +#define PROCESS_STATUS_MAYBE_HUNG 4 +#define PROCESS_STATUS_PROBABLY_HUNG 5 +#define PROCESS_STATUS_HUNG 6 + +// Process time thresholds +#define PROCESS_DEFAULT_HANG_WARNING_TIME 300 // 30 seconds +#define PROCESS_DEFAULT_HANG_ALERT_TIME 600 // 60 seconds +#define PROCESS_DEFAULT_HANG_RESTART_TIME 900 // 90 seconds +#define PROCESS_DEFAULT_SCHEDULE_INTERVAL 50 // 50 ticks +#define PROCESS_DEFAULT_SLEEP_INTERVAL 8 // 1/8th of a tick + +// SCHECK macros +// This references src directly to work around a weird bug with try/catch +#define SCHECK_EVERY(this_many_calls) if(++src.calls_since_last_scheck >= this_many_calls) sleepCheck() +#define SCHECK sleepCheck() diff --git a/code/__defines/qdel.dm b/code/__defines/qdel.dm new file mode 100644 index 00000000..444c1340 --- /dev/null +++ b/code/__defines/qdel.dm @@ -0,0 +1,23 @@ +//defines that give qdel hints. these can be given as a return in destory() or by calling + +#define QDEL_HINT_QUEUE 0 //qdel should queue the object for deletion. +#define QDEL_HINT_LETMELIVE 1 //qdel should let the object live after calling destory. +#define QDEL_HINT_IWILLGC 2 //functionally the same as the above. qdel should assume the object will gc on its own, and not check it. +#define QDEL_HINT_HARDDEL 3 //qdel should assume this object won't gc, and queue a hard delete using a hard reference. +#define QDEL_HINT_HARDDEL_NOW 4 //qdel should assume this object won't gc, and hard del it post haste. +#define QDEL_HINT_FINDREFERENCE 5 //functionally identical to QDEL_HINT_QUEUE if TESTING is not enabled in _compiler_options.dm. + //if TESTING is enabled, qdel will call this object's find_references() verb. +//defines for the gc_destroyed var + +#define GC_QUEUE_PREQUEUE 1 +#define GC_QUEUE_CHECK 2 +#define GC_QUEUE_HARDDELETE 3 +#define GC_QUEUE_COUNT 3 //increase this when adding more steps. + +#define GC_QUEUED_FOR_QUEUING -1 +#define GC_QUEUED_FOR_HARD_DEL -2 +#define GC_CURRENTLY_BEING_QDELETED -3 + +#define QDELING(X) (X.gc_destroyed) +#define QDELETED(X) (!X || QDELING(X)) +#define QDESTROYING(X) (!X || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) diff --git a/code/__defines/research.dm b/code/__defines/research.dm new file mode 100644 index 00000000..d40722d0 --- /dev/null +++ b/code/__defines/research.dm @@ -0,0 +1,18 @@ +#define SHEET_MATERIAL_AMOUNT 2000 + +#define TECH_MATERIAL "materials" +#define TECH_ENGINEERING "engineering" +#define TECH_PHORON "phorontech" +#define TECH_POWER "powerstorage" +#define TECH_BLUESPACE "bluespace" +#define TECH_BIO "biotech" +#define TECH_COMBAT "combat" +#define TECH_MAGNET "magnets" +#define TECH_DATA "programming" +#define TECH_ILLEGAL "syndicate" +#define TECH_ARCANE "arcane" + +#define IMPRINTER 0x1 //For circuits. Uses glass/chemicals. +#define PROTOLATHE 0x2 //New stuff. Uses glass/metal/chemicals +#define MECHFAB 0x4 //Mechfab +#define CHASSIS 0x8 //For protolathe, but differently diff --git a/code/__defines/shields.dm b/code/__defines/shields.dm new file mode 100644 index 00000000..61feddb6 --- /dev/null +++ b/code/__defines/shields.dm @@ -0,0 +1,57 @@ +#define SHIELD_DAMTYPE_PHYSICAL 1 // Physical damage - bullets, meteors, various hand objects - aka. "brute" damtype. +#define SHIELD_DAMTYPE_EM 2 // Electromagnetic damage - Ion weaponry, stun beams, ... +#define SHIELD_DAMTYPE_HEAT 3 // Heat damage - Lasers, fire + +#define ENERGY_PER_HP (50 KILOWATTS)// Base amount energy that will be deducted from the generator's internal reserve per 1 HP of damage taken +#define ENERGY_UPKEEP_PER_TILE 100 // Base upkeep per tile protected. Multiplied by various enabled shield modes. Without them the field does literally nothing. + +// This shield model is slightly inspired by Sins of a Solar Empire series. In short, shields are designed to analyze what hits them, and adapt themselves against that type of damage. +// This means shields will become increasingly effective against things like emitters - as they will adapt to heat damage, however they will be vulnerable to brute and EM damage. +// In a theoretical assault scenario, it is best to combine all damage types, so mitigation can't build up. The value is capped to prevent full scale invulnerability. + +#define MAX_MITIGATION_BASE 50 // % Base maximal reachable mitigation. +#define MAX_MITIGATION_RESEARCH 10 // % Added to MAX_MITIGATION_BASE when generator is built using more advanced components. This value is added for each "tier" of used component, ie. basic one has 1, the best one has 3. Actual maximum should be 80% in this case (with best components). Make sure you won't get above 100%! +#define MITIGATION_HIT_GAIN 5 // Mitigation gain per hit of respective damage type. +#define MITIGATION_HIT_LOSS 4 // Mitigation loss per hit. If we get hit once by EM damage type, EM mitigation will grow, while Physical and Heat mitigation values drop. +#define MITIGATION_LOSS_PASSIVE 0.5 // Mitigation of all damage types will drop by this every tick, up to 0. + +// Shield modes allow you to calibrate the field to fit specific needs. It is, for example, possible to create a field that will block airflow, but let people pass by calibrating it +// properly. Each enabled shield mode adds up to the upkeep power usage, however. The following defines are a multiplier - 1.5 means the power usage will be increased 1.5x. + +#define MODEUSAGE_HYPERKINETIC // Blocks meteors and projectile based weapons. Relatively low as the shields are primarily intended as an anti-meteor countermeasure. +#define MODEUSAGE_PHOTONIC // Blocks energy weapons, and makes the field opaque. +#define MODEUSAGE_NONHUMANS // Blocks most organic lifeforms, with an exception being humanoid mobs. Typical uses include carps. +#define MODEUSAGE_HUMANOIDS // Blocks humanoid mobs. +#define MODEUSAGE_ANORGANIC // Blocks silicon-based mobs (cyborgs, drones, FBPs, IPCs, ..) +#define MODEUSAGE_ATMOSPHERIC // Blocks airflow. +#define MODEUSAGE_HULL 1 // Enables hull shielding mode, which changes a square shaped field into a field that covers external hull only. +#define MODEUSAGE_BYPASS // Attempts to counter shield diffusers. Puts very large EM strain on the shield when doing so. Has to be hacked. +#define MODEUSAGE_OVERCHARGE 3 // Overcharges the shield, causing it to shock anyone who touches a field segment. Best used with MODE_ORGANIC_HUMANOIDS. Has to be hacked. +#define MODEUSAGE_MODULATE 2 // Modulates the shield, enabling the mitigation system. + +// Relevant mode bitflags (maximal of 16 flags due to current BYOND limitations) +#define MODEFLAG_HYPERKINETIC 1 +#define MODEFLAG_PHOTONIC 2 +#define MODEFLAG_NONHUMANS 4 +#define MODEFLAG_HUMANOIDS 8 +#define MODEFLAG_ANORGANIC 16 +#define MODEFLAG_ATMOSPHERIC 32 +#define MODEFLAG_HULL 64 +#define MODEFLAG_BYPASS 128 +#define MODEFLAG_OVERCHARGE 256 +#define MODEFLAG_MODULATE 512 +#define MODEFLAG_MULTIZ 1024 +#define MODEFLAG_EM 2048 + +// Return codes for shield hits. +#define SHIELD_ABSORBED 1 // The shield has completely absorbed the hit +#define SHIELD_BREACHED_MINOR 2 // The hit was absorbed, but a small gap will be created in the field (1-3 tiles) +#define SHIELD_BREACHED_MAJOR 3 // Same as above, with 2-5 tile gap +#define SHIELD_BREACHED_CRITICAL 4 // Same as above, with 4-8 tile gap +#define SHIELD_BREACHED_FAILURE 5 // Same as above, with 8-16 tile gap. Occurs when the hit exhausts all remaining shield energy. + +#define SHIELD_OFF 0 // The shield is offline +#define SHIELD_DISCHARGING 1 // The shield is shutting down and discharging. +#define SHIELD_RUNNING 2 // The shield is running + +#define SHIELD_SHUTDOWN_DISPERSION_RATE (500 KILOWATTS) // The rate at which shield energy disperses when shutdown is initiated. \ No newline at end of file diff --git a/code/__defines/species.dm b/code/__defines/species.dm new file mode 100644 index 00000000..8e89b09c --- /dev/null +++ b/code/__defines/species.dm @@ -0,0 +1,38 @@ +// Species flags. +#define SPECIES_FLAG_NO_MINOR_CUT 0x0001 // Can step on broken glass with no ill-effects. Either thick skin (diona/vox), cut resistant (slimes) or incorporeal (shadows) +#define SPECIES_FLAG_IS_PLANT 0x0002 // Is a treeperson. +#define SPECIES_FLAG_NO_SCAN 0x0004 // Cannot be scanned in a DNA machine/genome-stolen. +#define SPECIES_FLAG_NO_PAIN 0x0008 // Cannot suffer halloss/recieves deceptive health indicator. +#define SPECIES_FLAG_NO_SLIP 0x0010 // Cannot fall over. +#define SPECIES_FLAG_NO_POISON 0x0020 // Cannot not suffer toxloss. +#define SPECIES_FLAG_NO_EMBED 0x0040 // Can step on broken glass with no ill-effects and cannot have shrapnel embedded in it. +#define SPECIES_FLAG_CAN_NAB 0x0080 // Uses the special set of grab rules. +#define SPECIES_FLAG_NO_BLOCK 0x0100 // Unable to block or defend itself from attackers. +#define SPECIES_FLAG_NEED_DIRECT_ABSORB 0x0200 // This species can only have their DNA taken by direct absorption. + +// unused: 0x8000 - higher than this will overflow + +// Species spawn flags +#define SPECIES_IS_WHITELISTED 0x1 // Must be whitelisted to play. +#define SPECIES_IS_RESTRICTED 0x2 // Is not a core/normally playable species. (castes, mutantraces) +#define SPECIES_CAN_JOIN 0x4 // Species is selectable in chargen. +#define SPECIES_NO_FBP_CONSTRUCTION 0x8 // FBP of this species can't be made in-game. +#define SPECIES_NO_FBP_CHARGEN 0x10 // FBP of this species can't be selected at chargen. +#define SPECIES_NO_LACE 0x20 // This species can't have a neural lace. + +// Species appearance flags +#define HAS_SKIN_TONE_NORMAL 0x1 // Skin tone selectable in chargen for baseline humans (0-220) +#define HAS_SKIN_COLOR 0x2 // Skin colour selectable in chargen. (RGB) +#define HAS_LIPS 0x4 // Lips are drawn onto the mob icon. (lipstick) +#define HAS_UNDERWEAR 0x8 // Underwear is drawn onto the mob icon. +#define HAS_EYE_COLOR 0x10 // Eye colour selectable in chargen. (RGB) +#define HAS_HAIR_COLOR 0x20 // Hair colour selectable in chargen. (RGB) +#define RADIATION_GLOWS 0x40 // Radiation causes this character to glow. +#define HAS_SKIN_TONE_GRAV 0x80 // Skin tone selectable in chargen for grav-adapted humans (0-100) +#define HAS_SKIN_TONE_SPCR 0x100 // Skin tone selectable in chargen for spacer humans (0-165) +#define HAS_BASE_SKIN_COLOURS 0x200 // Has multiple base skin sprites to go off of +#define HAS_A_SKIN_TONE (HAS_SKIN_TONE_NORMAL | HAS_SKIN_TONE_GRAV | HAS_SKIN_TONE_SPCR) // Species has a numeric skintone + +// Skin Defines +#define SKIN_NORMAL 0 +#define SKIN_THREAT 1 diff --git a/code/__defines/subsystem-priority.dm b/code/__defines/subsystem-priority.dm new file mode 100644 index 00000000..0236aea1 --- /dev/null +++ b/code/__defines/subsystem-priority.dm @@ -0,0 +1,28 @@ +// Something to remember when setting priorities: SS_TICKER runs before Normal, which runs before SS_BACKGROUND. +// Each group has its own priority bracket. +// SS_BACKGROUND handles high server load differently than Normal and SS_TICKER do. +// Higher priority also means a larger share of a given tick before sleep checks. + +// SS_TICKER +// < none > + +#define SS_PRIORITY_DEFAULT 50 // Default priority for both normal and background processes + +// Normal +#define SS_PRIORITY_OVERLAY 500 // Applies overlays. May cause overlay pop-in if it gets behind. +#define SS_PRIORITY_CHAT 400 // Goonchat queue +#define SS_PRIORITY_MOB 100 // Mob Life(). +#define SS_PRIORITY_MACHINERY 100 // Machinery + powernet ticks. +#define SS_PRIORITY_AIR 80 // ZAS processing. +#define SS_PRIORITY_AO 65 // Ambien occlusion shit +#define SS_PRIORITY_AIRFLOW 15 // Object movement from ZAS airflow. + + +// SS_BACKGROUND +#define SS_PRIORITY_OBJECTS 60 // processing_objects processing. +#define SS_PRIORITY_PROCESSING 30 // Generic datum processor. Replaces objects processor. +#define SS_PRIORITY_GARBAGE 25 // Garbage collection. +#define SS_PRIORITY_VINES 25 // Spreading vine effects. +#define SS_PRIORITY_WIRELESS 10 // Wireless connection setup. +#define SS_PRIORITY_PING 10 // Client ping. +#define SS_PRIORITY_PROJECTILES 10 // Projectile processing! diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm new file mode 100644 index 00000000..05cadb9d --- /dev/null +++ b/code/__defines/subsystems.dm @@ -0,0 +1,70 @@ + +//Timing subsystem +//See MC.dm + +//For servers that can't do with any additional lag, set this to none in flightpacks.dm in subsystem/processing. +#define FLIGHTSUIT_PROCESSING_NONE 0 +#define FLIGHTSUIT_PROCESSING_FULL 1 + +#define INITIALIZATION_INSSATOMS 0 //New should not call Initialize +#define INITIALIZATION_INNEW_MAPLOAD 1 //New should call Initialize(TRUE) +#define INITIALIZATION_INNEW_REGULAR 2 //New should call Initialize(FALSE) + +#define INITIALIZE_HINT_NORMAL 0 //Nothing happens +#define INITIALIZE_HINT_LATELOAD 1 //Call LateInitialize +#define INITIALIZE_HINT_QDEL 2 //Call qdel on the atom + +//type and all subtypes should always call Initialize in New() +#define INITIALIZE_IMMEDIATE(X) ##X/New(loc, ...){\ + ..();\ + if(!initialized) {\ + args[1] = TRUE;\ + SSatoms.InitAtom(src, args);\ + }\ +} + +// Subsystem init_order, from highest priority to lowest priority +// Subsystems shutdown in the reverse of the order they initialize in +// The numbers just define the ordering, they are meaningless otherwise. + +#define INIT_ORDER_ASPECTS 20 +#define INIT_ORDER_SKYBOX 19 +#define INIT_ORDER_DBCORE 18 +#define INIT_ORDER_BLACKBOX 17 +#define INIT_ORDER_SERVER_MAINT 16 +#define INIT_ORDER_JOBS 15 +#define INIT_ORDER_EVENTS 14 +#define INIT_ORDER_TICKER 13 +#define INIT_ORDER_MAPPING 12 +#define INIT_ORDER_ATOMS 11 +#define INIT_ORDER_LANGUAGE 10 +#define INIT_ORDER_MACHINES 9 +#define INIT_ORDER_SHUTTLE 3 +#define INIT_ORDER_AO 5 +#define INIT_ORDER_TIMER 1 +#define INIT_ORDER_DEFAULT 0 +#define INIT_ORDER_AIR -1 +#define INIT_ORDER_MINIMAP -2 +#define INIT_ORDER_ASSETS -3 +#define INIT_ORDER_ICON_SMOOTHING -5 +#define INIT_ORDER_OVERLAY -6 +#define INIT_ORDER_XKEYSCORE -10 +#define INIT_ORDER_STICKY_BAN -10 +#define INIT_ORDER_LIGHTING -20 +#define INIT_ORDER_SQUEAK -40 +#define INIT_ORDER_PERSISTENCE -100 +#define INIT_OPEN_SPACE -150 +#define INIT_BAY_LEGACY -200 +#define INIT_ORDER_CHAT -210 //Should be last to ensure chat remains smooth during init. + + + +// SS runlevels + +#define RUNLEVEL_INIT 0 +#define RUNLEVEL_LOBBY 1 +#define RUNLEVEL_SETUP 2 +#define RUNLEVEL_GAME 4 +#define RUNLEVEL_POSTGAME 8 + +#define RUNLEVELS_DEFAULT (RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME) diff --git a/code/__defines/targeting.dm b/code/__defines/targeting.dm new file mode 100644 index 00000000..4bbe7345 --- /dev/null +++ b/code/__defines/targeting.dm @@ -0,0 +1,4 @@ +#define TARGET_CAN_MOVE 1 +#define TARGET_CAN_RUN 2 +#define TARGET_CAN_CLICK 4 +#define TARGET_CAN_RADIO 8 \ No newline at end of file diff --git a/code/__defines/tgui.dm b/code/__defines/tgui.dm new file mode 100644 index 00000000..1b3925f4 --- /dev/null +++ b/code/__defines/tgui.dm @@ -0,0 +1,4 @@ +#define UI_INTERACTIVE 2 // Green/Interactive +#define UI_UPDATE 1 // Orange/Updates Only +#define UI_DISABLED 0 // Red/Disabled +#define UI_CLOSE -1 // Closed diff --git a/code/__defines/topic.dm b/code/__defines/topic.dm new file mode 100644 index 00000000..981de408 --- /dev/null +++ b/code/__defines/topic.dm @@ -0,0 +1,3 @@ +#define TOPIC_NOACTION 0 +#define TOPIC_HANDLED 1 +#define TOPIC_REFRESH 2 diff --git a/code/__defines/turfs.dm b/code/__defines/turfs.dm new file mode 100644 index 00000000..48692745 --- /dev/null +++ b/code/__defines/turfs.dm @@ -0,0 +1,10 @@ +#define TURF_REMOVE_CROWBAR 1 +#define TURF_REMOVE_SCREWDRIVER 2 +#define TURF_REMOVE_SHOVEL 4 +#define TURF_REMOVE_WRENCH 8 +#define TURF_CAN_BREAK 16 +#define TURF_CAN_BURN 32 +#define TURF_HAS_EDGES 64 +#define TURF_HAS_CORNERS 128 +#define TURF_IS_FRAGILE 256 +#define TURF_ACID_IMMUNE 512 \ No newline at end of file diff --git a/code/__defines/xenoarcheaology.dm b/code/__defines/xenoarcheaology.dm new file mode 100644 index 00000000..b6af0d06 --- /dev/null +++ b/code/__defines/xenoarcheaology.dm @@ -0,0 +1,72 @@ +#define ARCHAEO_BOWL 1 +#define ARCHAEO_URN 2 +#define ARCHAEO_CUTLERY 3 +#define ARCHAEO_STATUETTE 4 +#define ARCHAEO_INSTRUMENT 5 +#define ARCHAEO_KNIFE 6 +#define ARCHAEO_COIN 7 +#define ARCHAEO_HANDCUFFS 8 +#define ARCHAEO_BEARTRAP 9 +#define ARCHAEO_LIGHTER 10 +#define ARCHAEO_BOX 11 +#define ARCHAEO_GASTANK 12 +#define ARCHAEO_TOOL 13 +#define ARCHAEO_METAL 14 +#define ARCHAEO_PEN 15 +#define ARCHAEO_CRYSTAL 16 +#define ARCHAEO_CULTBLADE 17 +#define ARCHAEO_TELEBEACON 18 +#define ARCHAEO_CLAYMORE 19 +#define ARCHAEO_CULTROBES 20 +#define ARCHAEO_SOULSTONE 21 +#define ARCHAEO_SHARD 22 +#define ARCHAEO_RODS 23 +#define ARCHAEO_STOCKPARTS 24 +#define ARCHAEO_KATANA 25 +#define ARCHAEO_LASER 26 +#define ARCHAEO_GUN 27 +#define ARCHAEO_UNKNOWN 28 +#define ARCHAEO_FOSSIL 29 +#define ARCHAEO_SHELL 30 +#define ARCHAEO_PLANT 31 +#define ARCHAEO_REMAINS_HUMANOID 32 +#define ARCHAEO_REMAINS_ROBOT 33 +#define ARCHAEO_REMAINS_XENO 34 +#define ARCHAEO_GASMASK 35 +#define MAX_ARCHAEO 35 + +#define DIGSITE_GARDEN 1 +#define DIGSITE_ANIMAL 2 +#define DIGSITE_HOUSE 3 +#define DIGSITE_TECHNICAL 4 +#define DIGSITE_TEMPLE 5 +#define DIGSITE_WAR 6 + +#define EFFECT_TOUCH 0 +#define EFFECT_AURA 1 +#define EFFECT_PULSE 2 +#define MAX_EFFECT 2 + +#define TRIGGER_TOUCH 0 +#define TRIGGER_WATER 1 +#define TRIGGER_ACID 2 +#define TRIGGER_VOLATILE 3 +#define TRIGGER_TOXIN 4 +#define TRIGGER_FORCE 5 +#define TRIGGER_ENERGY 6 +#define TRIGGER_HEAT 7 +#define TRIGGER_COLD 8 +#define TRIGGER_PHORON 9 +#define TRIGGER_OXY 10 +#define TRIGGER_CO2 11 +#define TRIGGER_NITRO 12 +#define MAX_TRIGGER 12 + +#define EFFECT_UNKNOWN 0 +#define EFFECT_ENERGY 1 +#define EFFECT_PSIONIC 2 +#define EFFECT_ELECTRO 3 +#define EFFECT_PARTICLE 4 +#define EFFECT_ORGANIC 5 +#define EFFECT_BLUESPACE 6 +#define EFFECT_SYNTH 7 \ No newline at end of file diff --git a/code/__defines/~unit_testing.dm b/code/__defines/~unit_testing.dm new file mode 100644 index 00000000..88eebd5a --- /dev/null +++ b/code/__defines/~unit_testing.dm @@ -0,0 +1,10 @@ +/* + * + * This file is used by Travis to indicate that Unit Tests are to be ran. + * Do not add anything but the UNIT_TEST definition here as it will be overwritten by Travis when running tests. + * + * + * Should you wish to edit set UNIT_TEST to 1 like so: + * #define UNIT_TEST 1 + */ +#define UNIT_TEST 0 diff --git a/code/_global_vars/configuration.dm b/code/_global_vars/configuration.dm new file mode 100644 index 00000000..363c8ef0 --- /dev/null +++ b/code/_global_vars/configuration.dm @@ -0,0 +1,32 @@ +// Bomb cap! +GLOBAL_VAR_INIT(max_explosion_range, 14) + + +var/href_logfile = null +var/game_version = "Interstation12" +var/changelog_hash = "" +var/game_year = (text2num(time2text(world.realtime, "YYYY")) + 544) +var/join_motd = null + +var/master_mode = "extended" // "extended" +var/secondary_mode = "extended" +var/tertiary_mode = "extended" +var/secret_force_mode = "secret" // if this is anything but "secret", the secret rotation will forceably choose this mode. + +var/Debug2 = 0 + +var/gravity_is_on = 1 +var/round_progressing = 1 + +// Database connections. A connection is established on world creation. +// Ideally, the connection dies when the server restarts (After feedback logging.). +var/DBConnection/dbcon = new() // Feedback database (New database) +var/DBConnection/dbcon_old = new() // /tg/station database (Old database) -- see the files in the SQL folder for information on what goes where. + + +// For FTP requests. (i.e. downloading runtime logs.) +// However it'd be ok to use for accessing attack logs and such too, which are even laggier. +var/fileaccess_timer = 0 +var/custom_event_msg = null + +GLOBAL_VAR_INIT(visibility_pref, FALSE) \ No newline at end of file diff --git a/code/_global_vars/lists/flavor.dm b/code/_global_vars/lists/flavor.dm new file mode 100644 index 00000000..77fffe1c --- /dev/null +++ b/code/_global_vars/lists/flavor.dm @@ -0,0 +1,81 @@ +// Used by robots and robot preferences. +GLOBAL_LIST_INIT(robot_module_types, list( + "Standard", "Engineering", "Surgeon", "Crisis", + "Miner", "Janitor", "Service", "Clerical", "Security", + "Research" +)) // This shouldn't be a static list. Am I the only one who cares about extendability around here? + +// Noises made when hit while typing. +GLOBAL_LIST_INIT(hit_appends, list("-OOF", "-ACK", "-UGH", "-HRNK", "-HURGH", "-GLORF")) + +// Some scary sounds. +GLOBAL_LIST_INIT(scarySounds, list( + 'sound/weapons/thudswoosh.ogg', + 'sound/weapons/Taser.ogg', + 'sound/weapons/armbomb.ogg', + 'sound/voice/hiss1.ogg', + 'sound/voice/hiss2.ogg', + 'sound/voice/hiss3.ogg', + 'sound/voice/hiss4.ogg', + 'sound/voice/hiss5.ogg', + 'sound/voice/hiss6.ogg', + 'sound/effects/Glassbr1.ogg', + 'sound/effects/Glassbr2.ogg', + 'sound/effects/Glassbr3.ogg', + 'sound/items/Welder.ogg', + 'sound/items/Welder2.ogg', + 'sound/machines/airlock_open.ogg', + 'sound/effects/clownstep1.ogg', + 'sound/effects/clownstep2.ogg' +)) + +// Reference list for disposal sort junctions. Filled up by sorting junction's New() +GLOBAL_LIST_EMPTY(tagger_locations) + +GLOBAL_LIST_INIT(station_prefixes, list("", "Imperium", "Heretical", "Cuban", + "Psychic", "Elegant", "Common", "Uncommon", "Rare", "Unique", + "Houseruled", "Religious", "Atheist", "Traditional", "Houseruled", + "Mad", "Super", "Ultra", "Secret", "Top Secret", "Deep", "Death", + "Zybourne", "Central", "Main", "Government", "Uoi", "Fat", + "Automated", "Experimental", "Augmented")) + +GLOBAL_LIST_INIT(station_names, list("", "Stanford", "Dorf", "Alium", + "Prefix", "Clowning", "Aegis", "Ishimura", "Scaredy", "Death-World", + "Mime", "Honk", "Rogue", "MacRagge", "Ultrameens", "Safety", "Paranoia", + "Explosive", "Neckbear", "Donk", "Muppet", "North", "West", "East", + "South", "Slant-ways", "Widdershins", "Rimward", "Expensive", + "Procreatory", "Imperial", "Unidentified", "Immoral", "Carp", "Ork", + "Pete", "Control", "Nettle", "Aspie", "Class", "Crab", "Fist", + "Corrogated","Skeleton","Race", "Fatguy", "Gentleman", "Capitalist", + "Communist", "Bear", "Beard", "Derp", "Space", "Spess", "Star", "Moon", + "System", "Mining", "Neckbeard", "Research", "Supply", "Military", + "Orbital", "Battle", "Science", "Asteroid", "Home", "Production", + "Transport", "Delivery", "Extraplanetary", "Orbital", "Correctional", + "Robot", "Hats", "Pizza")) + +GLOBAL_LIST_INIT(station_suffixes, list("Station", "Frontier", + "Suffix", "Death-trap", "Space-hulk", "Lab", "Hazard","Spess Junk", + "Fishery", "No-Moon", "Tomb", "Crypt", "Hut", "Monkey", "Bomb", + "Trade Post", "Fortress", "Village", "Town", "City", "Edition", "Hive", + "Complex", "Base", "Facility", "Depot", "Outpost", "Installation", + "Drydock", "Observatory", "Array", "Relay", "Monitor", "Platform", + "Construct", "Hangar", "Prison", "Center", "Port", "Waystation", + "Factory", "Waypoint", "Stopover", "Hub", "HQ", "Office", "Object", + "Fortification", "Colony", "Planet-Cracker", "Roost", "Fat Camp", + "Airstrip")) + +GLOBAL_LIST_INIT(greek_letters, list("Alpha", "Beta", "Gamma", "Delta", + "Epsilon", "Zeta", "Eta", "Theta", "Iota", "Kappa", "Lambda", "Mu", + "Nu", "Xi", "Omicron", "Pi", "Rho", "Sigma", "Tau", "Upsilon", "Phi", + "Chi", "Psi", "Omega")) + +GLOBAL_LIST_INIT(phonetic_alphabet, list("Alpha", "Bravo", "Charlie", + "Delta", "Echo", "Foxtrot", "Golf", "Hotel", "India", "Juliet", + "Kilo", "Lima", "Mike", "November", "Oscar", "Papa", "Quebec", + "Romeo", "Sierra", "Tango", "Uniform", "Victor", "Whiskey", "X-ray", + "Yankee", "Zulu")) + +GLOBAL_LIST_INIT(numbers_as_words, list("One", "Two", "Three", "Four", + "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", + "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", + "Eighteen", "Nineteen")) diff --git a/code/_global_vars/lists/locations.dm b/code/_global_vars/lists/locations.dm new file mode 100644 index 00000000..1af7b15e --- /dev/null +++ b/code/_global_vars/lists/locations.dm @@ -0,0 +1,18 @@ +GLOBAL_LIST_EMPTY(monkeystart) +GLOBAL_LIST_EMPTY(newplayer_start) + +//Spawnpoints. +GLOBAL_LIST_EMPTY(latejoin) +GLOBAL_LIST_EMPTY(latejoin_gateway) +GLOBAL_LIST_EMPTY(latejoin_cryo) +GLOBAL_LIST_EMPTY(latejoin_cyborg) + +GLOBAL_LIST_EMPTY(prisonwarp) // Prisoners go to these +GLOBAL_LIST_EMPTY(tdome1) +GLOBAL_LIST_EMPTY(tdome2) +GLOBAL_LIST_EMPTY(tdomeobserve) +GLOBAL_LIST_EMPTY(tdomeadmin) +GLOBAL_LIST_EMPTY(prisonsecuritywarp) // Prison security goes to these. +GLOBAL_LIST_EMPTY(prisonwarped) // List of players already warped. + +GLOBAL_LIST_EMPTY(awaydestinations) // Away missions. A list of landmarks that the warpgate can take you to. diff --git a/code/_global_vars/lists/logs.dm b/code/_global_vars/lists/logs.dm new file mode 100644 index 00000000..6f79a510 --- /dev/null +++ b/code/_global_vars/lists/logs.dm @@ -0,0 +1,4 @@ +GLOBAL_LIST_EMPTY(bombers) +GLOBAL_LIST_EMPTY(admin_log) +GLOBAL_LIST_EMPTY(lastsignalers) // Keeps last 100 signals here in format: "[src] used \ref[src] @ location [src.loc]: [freq]/[code]" +GLOBAL_LIST_EMPTY(lawchanges) // Stores who uploaded laws to which silicon-based lifeform, and what the law was. diff --git a/code/_global_vars/lists/mapping.dm b/code/_global_vars/lists/mapping.dm new file mode 100644 index 00000000..42e6f1ba --- /dev/null +++ b/code/_global_vars/lists/mapping.dm @@ -0,0 +1,32 @@ +GLOBAL_LIST_INIT(cardinal, list(NORTH, SOUTH, EAST, WEST)) +GLOBAL_LIST_INIT(cardinalz, list(NORTH, SOUTH, EAST, WEST, UP, DOWN)) +GLOBAL_LIST_INIT(cornerdirs, list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST)) +GLOBAL_LIST_INIT(cornerdirsz, list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST, NORTH|UP, EAST|UP, WEST|UP, SOUTH|UP, NORTH|DOWN, EAST|DOWN, WEST|DOWN, SOUTH|DOWN)) +GLOBAL_LIST_INIT(alldirs, list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST)) +GLOBAL_LIST_INIT(reverse_dir, list( // reverse_dir[dir] = reverse of dir + 2, 1, 3, 8, 10, 9, 11, 4, 6, 5, 7, 12, 14, 13, 15, + 32, 34, 33, 35, 40, 42, 41, 43, 36, 38, 37, 39, 44, 46, 45, 47, + 16, 18, 17, 19, 24, 26, 25, 27, 20, 22, 21, 23, 28, 30, 29, 31, + 48, 50, 49, 51, 56, 58, 57, 59, 52, 54, 53, 55, 60, 62, 61, 63 +)) + +GLOBAL_LIST_INIT(flip_dir, list( // flip_dir[dir] = 180 degree rotation of dir. Unlike reverse_dir, UP remains UP & DOWN remains DOWN. + 2, 1, 3, 8, 10, 9, 11, 4, 6, 5, 7, 12, 14, 13, 15, + 16, 18, 17, 19, 24, 26, 25, 27, 20, 22, 21, 23, 28, 30, 29, 31, // UP - Same as first line but +16 + 32, 34, 33, 35, 40, 42, 41, 43, 36, 38, 37, 39, 44, 46, 45, 47, // DOWN - Same as first line but +32 + 48, 50, 49, 51, 56, 58, 57, 59, 52, 54, 53, 55, 60, 62, 61, 63 // UP+DOWN - Same as first line but +48 +)) + +GLOBAL_LIST_INIT(cw_dir, list( // cw_dir[dir] = clockwise rotation of dir. Unlike reverse_dir, UP remains UP & DOWN remains DOWN. + 4, 8, 12, 2, 6, 10, 14, 1, 5, 9, 13, 3, 7, 11, 15, + 16, 20, 24, 28, 18, 22, 26, 30, 17, 21, 25, 19, 29, 23, 27, 31, // UP - Same as first line but +16 + 32, 36, 40, 44, 34, 38, 42, 46, 33, 37, 41, 45, 35, 39, 43, 47, // DOWN - Same as first line but +32 + 48, 52, 56, 40, 50, 54, 58, 62, 49, 53, 57, 61, 51, 55, 59, 63 // UP+DOWN - Same as first line but +48 +)) + +GLOBAL_LIST_INIT(cww_dir, list( // cww_dir[dir] = counter-clockwise rotation of dir. Unlike reverse_dir, UP remains UP & DOWN remains DOWN. + 8, 4, 12, 1, 9, 5, 13, 2, 10, 6, 14, 3, 11, 7, 15, + 16, 24, 20, 28, 17, 25, 21, 29, 18, 26, 22, 30, 19, 27, 23, 31, // UP - Same as first line but +16 + 32, 40, 36, 44, 33, 41, 37, 45, 34, 42, 38, 46, 35, 43, 39, 47, // DOWN - Same as first line but +32 + 48, 56, 52, 60, 49, 57, 53, 61, 50, 58, 54, 62, 51, 59, 55, 63 // UP+DOWN - Same as first line but +48 +)) diff --git a/code/_global_vars/lists/names.dm b/code/_global_vars/lists/names.dm new file mode 100644 index 00000000..817399d6 --- /dev/null +++ b/code/_global_vars/lists/names.dm @@ -0,0 +1,17 @@ +GLOBAL_LIST_INIT(ai_names, world.file2list("config/names/ai.txt")) +GLOBAL_LIST_INIT(wizard_first, world.file2list("config/names/wizardfirst.txt")) +GLOBAL_LIST_INIT(wizard_second, world.file2list("config/names/wizardsecond.txt")) +GLOBAL_LIST_INIT(commando_names, world.file2list("config/names/death_commando.txt")) +GLOBAL_LIST_INIT(first_names_male, world.file2list("config/names/first_male.txt")) +GLOBAL_LIST_INIT(first_names_female, world.file2list("config/names/first_female.txt")) +GLOBAL_LIST_INIT(last_names, world.file2list("config/names/last.txt")) +GLOBAL_LIST_INIT(clown_names, world.file2list("config/names/clown.txt")) + + +GLOBAL_LIST_INIT(verbs, world.file2list("config/names/verbs.txt")) +GLOBAL_LIST_INIT(adjectives, world.file2list("config/names/adjectives.txt")) +//loaded on startup because of " +//would include in rsc if ' was used + + +GLOBAL_LIST_EMPTY(in_character_filter) \ No newline at end of file diff --git a/code/_global_vars/lists/objects.dm b/code/_global_vars/lists/objects.dm new file mode 100644 index 00000000..626a7944 --- /dev/null +++ b/code/_global_vars/lists/objects.dm @@ -0,0 +1,21 @@ +GLOBAL_LIST_EMPTY(active_diseases) +GLOBAL_LIST_EMPTY(med_hud_users) // List of all entities using a medical HUD. +GLOBAL_LIST_EMPTY(sec_hud_users) // List of all entities using a security HUD. +GLOBAL_LIST_EMPTY(hud_icon_reference) +GLOBAL_LIST_EMPTY(traders) //List of all nearby traders + +GLOBAL_LIST_EMPTY(listening_objects) // List of objects that need to be able to hear, used to avoid recursive searching through contents. + +GLOBAL_LIST_EMPTY(global_mutations) // List of hidden mutation things. + +GLOBAL_LIST_EMPTY(reg_dna) + +GLOBAL_LIST_EMPTY(global_map) + +// Announcer intercom, because too much stuff creates an intercom for one message then hard del()s it. Also headset, for things that should be affected by comms outages. +GLOBAL_DATUM_INIT(global_announcer, /obj/item/device/radio/announcer, new) +GLOBAL_DATUM_INIT(global_headset, /obj/item/device/radio/announcer/subspace, new) + +var/host = null //only here until check @ code\modules\ghosttrap\trap.dm:112 is fixed +GLOBAL_DATUM_INIT(sun, /datum/sun, new) +GLOBAL_DATUM_INIT(universe, /datum/universal_state, new) diff --git a/code/_global_vars/logging.dm b/code/_global_vars/logging.dm new file mode 100644 index 00000000..ecc443c3 --- /dev/null +++ b/code/_global_vars/logging.dm @@ -0,0 +1,19 @@ +var/runtime_diary = null + + +var/list/combatlog = list() +var/list/IClog = list() +var/list/OOClog = list() +var/list/adminlog = list() + +var/datum/configuration/config = null +var/list/jobMax = list() + +var/diary = null + +GLOBAL_VAR(log_directory) +GLOBAL_PROTECT(log_directory) +GLOBAL_VAR(world_runtime_log) +GLOBAL_PROTECT(world_runtime_log) +GLOBAL_VAR(world_qdel_log) +GLOBAL_PROTECT(world_qdel_log) diff --git a/code/_global_vars/mapping.dm b/code/_global_vars/mapping.dm new file mode 100644 index 00000000..11cbcd7e --- /dev/null +++ b/code/_global_vars/mapping.dm @@ -0,0 +1 @@ +GLOBAL_LIST_EMPTY(ruin_landmarks) \ No newline at end of file diff --git a/code/_global_vars/misc.dm b/code/_global_vars/misc.dm new file mode 100644 index 00000000..4e5ceae1 --- /dev/null +++ b/code/_global_vars/misc.dm @@ -0,0 +1,13 @@ +GLOBAL_LIST_EMPTY(all_observable_events) + +GLOBAL_LIST_INIT(font_resources, list('fonts/Shage/Shage.ttf')) + +GLOBAL_VAR_INIT(shit_left, 0) +GLOBAL_VAR_INIT(piss_left, 0) +GLOBAL_VAR_INIT(teeth_lost, 0) +GLOBAL_VAR_INIT(ff_incidents, 0) +GLOBAL_VAR_INIT(mines_tripped, 0) +GLOBAL_VAR_INIT(mines_disarmed, 0) +GLOBAL_VAR_INIT(total_deaths, 0) +GLOBAL_VAR_INIT(holes_fallen, 0) +GLOBAL_VAR_INIT(waddling, 0) \ No newline at end of file diff --git a/code/_global_vars/mobs.dm b/code/_global_vars/mobs.dm new file mode 100644 index 00000000..dd843b31 --- /dev/null +++ b/code/_global_vars/mobs.dm @@ -0,0 +1,25 @@ +GLOBAL_LIST_EMPTY(clients) //all clients +GLOBAL_LIST_EMPTY(admins) //all clients whom are admins +GLOBAL_PROTECT(admins) +GLOBAL_LIST_EMPTY(ckey_directory) //all ckeys with associated client + +//Server access whitelist +var/global/list/ckey_whitelist = null + +var/global/list/hellbans = null//Hellbanned boys + + +GLOBAL_LIST_EMPTY(player_list) //List of all mobs **with clients attached**. Excludes /mob/new_player +GLOBAL_LIST_EMPTY(human_mob_list) //List of all human mobs and sub-types, including clientless +GLOBAL_LIST_EMPTY(silicon_mob_list) //List of all silicon mobs, including clientless +GLOBAL_LIST_EMPTY(living_mob_list_) //List of all alive mobs, including clientless. Excludes /mob/new_player +GLOBAL_LIST_EMPTY(dead_mob_list_) //List of all dead mobs, including clientless. Excludes /mob/new_player +GLOBAL_LIST_EMPTY(ghost_mob_list) //List of all ghosts, including clientless. Excludes /mob/new_player + +GLOBAL_VAR(cargo_password) //Goes into the mind of the Requisitions Officer. + +GLOBAL_VAR(final_words) //Final words of the first person who died. + +GLOBAL_VAR(first_death) //The first person who died. + +GLOBAL_VAR(first_death_happened) //bool to check it happened \ No newline at end of file diff --git a/code/_global_vars/radio.dm b/code/_global_vars/radio.dm new file mode 100644 index 00000000..d3ec7f7b --- /dev/null +++ b/code/_global_vars/radio.dm @@ -0,0 +1,7 @@ +// These globals are the worst + +GLOBAL_LIST_INIT(default_medbay_channels, list( + num2text(PUB_FREQ) = list(), + num2text(MED_FREQ) = list(access_medical_equip), + num2text(MED_I_FREQ) = list(access_medical_equip) +)) diff --git a/code/_global_vars/sensitive.dm b/code/_global_vars/sensitive.dm new file mode 100644 index 00000000..86522af9 --- /dev/null +++ b/code/_global_vars/sensitive.dm @@ -0,0 +1,12 @@ +// MySQL configuration +GLOBAL_REAL_VAR(sqladdress) = "localhost" +GLOBAL_REAL_VAR(sqlport) = "3306" +GLOBAL_REAL_VAR(sqldb) = "tgstation" +GLOBAL_REAL_VAR(sqllogin) = "root" +GLOBAL_REAL_VAR(sqlpass) = "" + +// Feedback gathering sql connection +GLOBAL_REAL_VAR(sqlfdbkdb) = "test" +GLOBAL_REAL_VAR(sqlfdbklogin) = "root" +GLOBAL_REAL_VAR(sqlfdbkpass) = "" +GLOBAL_REAL_VAR(sqllogging) = 0 // Should we log deaths, population stats, etc.? diff --git a/code/_helpers/_global_objects.dm b/code/_helpers/_global_objects.dm new file mode 100644 index 00000000..b3f44797 --- /dev/null +++ b/code/_helpers/_global_objects.dm @@ -0,0 +1,5 @@ + + +//var/datum/gear_tweak/color/gear_tweak_free_color_choice_ +//#define gear_tweak_free_color_choice (gear_tweak_free_color_choice_ ? gear_tweak_free_color_choice_ : (gear_tweak_free_color_choice_ = new())) +// Might work in 511 assuming x=y=5 gets implemented. diff --git a/code/_helpers/areas.dm b/code/_helpers/areas.dm new file mode 100644 index 00000000..284a8202 --- /dev/null +++ b/code/_helpers/areas.dm @@ -0,0 +1,107 @@ +/* + List generation helpers +*/ +/proc/get_filtered_areas(var/list/predicates = list(/proc/is_area_with_turf)) + . = list() + if(!predicates) + return + if(!islist(predicates)) + predicates = list(predicates) + for(var/area/A) + if(all_predicates_true(list(A), predicates)) + . += A + +/proc/get_area_turfs(var/area/A, var/list/predicates) + . = new/list() + A = istype(A) ? A : locate(A) + if(!A) + return + for(var/turf/T in A.contents) + if(!predicates || all_predicates_true(list(T), predicates)) + . += T + +/proc/get_subarea_turfs(var/area/A, var/list/predicates) + . = new/list() + A = istype(A) ? A.type : A + if(!A) + return + for(var/sub_area_type in typesof(A)) + var/area/sub_area = locate(sub_area_type) + for(var/turf/T in sub_area.contents) + if(!predicates || all_predicates_true(list(T), predicates)) + . += T + +/proc/group_areas_by_name(var/list/predicates) + . = list() + for(var/area/A in get_filtered_areas(predicates)) + group_by(., A.name, A) + +/proc/group_areas_by_z_level(var/list/predicates) + . = list() + for(var/area/A in get_filtered_areas(predicates)) + group_by(., num2text(A.z), A) + +/* + Pick helpers +*/ +/proc/pick_subarea_turf(var/areatype, var/list/predicates) + var/list/turfs = get_subarea_turfs(areatype, predicates) + if(turfs && turfs.len) + return pick(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) + +/proc/pick_area(var/list/predicates) + var/list/areas = get_filtered_areas(predicates) + if(areas && areas.len) + . = pick(areas) + +/proc/pick_area_and_turf(var/list/area_predicates, var/list/turf_predicates) + var/area/A = pick_area(area_predicates) + if(!A) + return + return pick_area_turf(A, turf_predicates) + +/* + Predicate Helpers +*/ +/proc/is_station_area(var/area/A) + . = isStationLevel(A.z) + +/proc/is_contact_area(var/area/A) + . = isContactLevel(A.z) + +/proc/is_player_area(var/area/A) + . = isPlayerLevel(A.z) + +/proc/is_not_space_area(var/area/A) + . = !istype(A,/area/space) + +/proc/is_not_shuttle_area(var/area/A) + . = !istype(A,/area/shuttle) + +/proc/is_area_with_turf(var/area/A) + . = isnum(A.x) + +/proc/is_area_without_turf(var/area/A) + . = !is_area_with_turf(A) + +/proc/is_coherent_area(var/area/A) + return !is_type_in_list(A, GLOB.using_map.area_coherency_test_exempt_areas) + +GLOBAL_LIST_INIT(is_station_but_not_space_or_shuttle_area, list(/proc/is_station_area, /proc/is_not_space_area, /proc/is_not_shuttle_area)) + +GLOBAL_LIST_INIT(is_contact_but_not_space_or_shuttle_area, list(/proc/is_contact_area, /proc/is_not_space_area, /proc/is_not_shuttle_area)) + +GLOBAL_LIST_INIT(is_player_but_not_space_or_shuttle_area, list(/proc/is_player_area, /proc/is_not_space_area, /proc/is_not_shuttle_area)) + + +/* + Misc Helpers +*/ +#define teleportlocs area_repository.get_areas_by_name_and_coords(GLOB.is_player_but_not_space_or_shuttle_area) +#define stationlocs area_repository.get_areas_by_name(GLOB.is_player_but_not_space_or_shuttle_area) + diff --git a/code/_helpers/atmospherics.dm b/code/_helpers/atmospherics.dm new file mode 100644 index 00000000..3e269128 --- /dev/null +++ b/code/_helpers/atmospherics.dm @@ -0,0 +1,51 @@ +/obj/proc/analyze_gases(var/obj/A, var/mob/user, advanced) + user.visible_message("\The [user] has used \an [src] on \the [A].") + A.add_fingerprint(user) + + var/air_contents = A.return_air() + if(!air_contents) + to_chat(user, "Your [src] flashes a red light as it fails to analyze \the [A].") + return 0 + + var/list/result = atmosanalyzer_scan(A, air_contents, advanced) + print_atmos_analysis(user, result) + return 1 + +/proc/print_atmos_analysis(user, var/list/result) + for(var/line in result) + to_chat(user, "[line]") + +/proc/atmosanalyzer_scan(var/atom/target, var/datum/gas_mixture/mixture, advanced) + . = list() + . += "Results of the analysis of \the [target]:" + if(!mixture) + mixture = target.return_air() + + if(mixture) + var/pressure = mixture.return_pressure() + var/total_moles = mixture.total_moles + + if (total_moles>0) + if(abs(pressure - ONE_ATMOSPHERE) < 10) + . += "Pressure: [round(pressure,0.1)] kPa" + else + . += "Pressure: [round(pressure,0.1)] kPa" + for(var/mix in mixture.gas) + var/percentage = round(mixture.gas[mix]/total_moles * 100, advanced ? 0.01 : 1) + if(!percentage) + continue + . += "[gas_data.name[mix]]: [percentage]%" + if(advanced) + var/list/traits = list() + if(gas_data.flags[mix] & XGM_GAS_FUEL) + traits += "can be used as combustion fuel" + if(gas_data.flags[mix] & XGM_GAS_OXIDIZER) + traits += "can be used as oxidizer" + if(gas_data.flags[mix] & XGM_GAS_CONTAMINANT) + traits += "contaminates clothing with toxic residue" + if(gas_data.flags[mix] & XGM_GAS_FUSION_FUEL) + traits += "can be used to fuel fusion reaction" + . += "\tSpecific heat: [gas_data.specific_heat[mix]] J/(mol*K), Molar mass: [gas_data.molar_mass[mix]] kg/mol.[traits.len ? "\n\tThis gas [english_list(traits)]" : ""]" + . += "Temperature: [round(mixture.temperature-T0C)]°C / [round(mixture.temperature)]K" + return + . += "\The [target] has no gases!" diff --git a/code/_helpers/atom_movables.dm b/code/_helpers/atom_movables.dm new file mode 100644 index 00000000..b1092c5d --- /dev/null +++ b/code/_helpers/atom_movables.dm @@ -0,0 +1,34 @@ +/proc/get_turf_pixel(atom/movable/AM) + if(!istype(AM)) + return + + //Find AM's matrix so we can use it's X/Y pixel shifts + var/matrix/M = matrix(AM.transform) + + var/pixel_x_offset = AM.pixel_x + M.get_x_shift() + var/pixel_y_offset = AM.pixel_y + M.get_y_shift() + + //Irregular objects + if(AM.bound_height != world.icon_size || AM.bound_width != world.icon_size) + var/icon/AMicon = icon(AM.icon, AM.icon_state) + pixel_x_offset += ((AMicon.Width()/world.icon_size)-1)*(world.icon_size*0.5) + pixel_y_offset += ((AMicon.Height()/world.icon_size)-1)*(world.icon_size*0.5) + qdel(AMicon) + + //DY and DX + var/rough_x = round(round(pixel_x_offset,world.icon_size)/world.icon_size) + var/rough_y = round(round(pixel_y_offset,world.icon_size)/world.icon_size) + + //Find coordinates + var/turf/T = get_turf(AM) //use AM's turfs, as it's coords are the same as AM's AND AM's coords are lost if it is inside another atom + var/final_x = T.x + rough_x + var/final_y = T.y + rough_y + + if(final_x || final_y) + return locate(final_x, final_y, T.z) + +// Walks up the loc tree until it finds a holder of the given holder_type +/proc/get_holder_of_type(atom/A, holder_type) + if(!istype(A)) return + for(A, A && !istype(A, holder_type), A=A.loc); + return A diff --git a/code/_helpers/builtin_proc_callers.dm b/code/_helpers/builtin_proc_callers.dm new file mode 100644 index 00000000..eb59cb31 --- /dev/null +++ b/code/_helpers/builtin_proc_callers.dm @@ -0,0 +1,6 @@ +/* + You cannot call built-in BYOND methods directly using call()(), hence these helpers +*/ + +/proc/prob_call(var/probability) + return prob(probability) diff --git a/code/_helpers/cmp.dm b/code/_helpers/cmp.dm new file mode 100644 index 00000000..76d26664 --- /dev/null +++ b/code/_helpers/cmp.dm @@ -0,0 +1,62 @@ +/proc/cmp_appearance_data(var/datum/appearance_data/a, var/datum/appearance_data/b) + return b.priority - a.priority + +/proc/cmp_camera_ctag_asc(var/obj/machinery/camera/a, var/obj/machinery/camera/b) + return sorttext(b.c_tag, a.c_tag) + +/proc/cmp_camera_ctag_dsc(var/obj/machinery/camera/a, var/obj/machinery/camera/b) + return sorttext(a.c_tag, b.c_tag) + +/proc/cmp_crew_sensor_modifier(var/crew_sensor_modifier/a, var/crew_sensor_modifier/b) + return b.priority - a.priority + +/proc/cmp_follow_holder(var/datum/follow_holder/a, var/datum/follow_holder/b) + if(a.sort_order == b.sort_order) + return sorttext(b.get_name(), a.get_name()) + + return a.sort_order - b.sort_order + +/proc/cmp_name_or_type_asc(atom/a, atom/b) + return sorttext(istype(b) || ("name" in b.vars) ? b.name : b.type, istype(a) || ("name" in a.vars) ? a.name : a.type) + +/proc/cmp_name_asc(atom/a, atom/b) + return sorttext(b.name, a.name) + +/proc/cmp_name_dsc(atom/a, atom/b) + return sorttext(a.name, b.name) + +/proc/cmp_numeric_asc(a,b) + return a - b + +/proc/cmp_subsystem_display(datum/controller/subsystem/a, datum/controller/subsystem/b) + return sorttext(b.name, a.name) + +/proc/cmp_subsystem_init(datum/controller/subsystem/a, datum/controller/subsystem/b) + var/a_init_order = ispath(a) ? initial(a.init_order) : a.init_order + var/b_init_order = ispath(b) ? initial(b.init_order) : b.init_order + + return b_init_order - a_init_order //uses initial() so it can be used on types + +/proc/cmp_subsystem_priority(datum/controller/subsystem/a, datum/controller/subsystem/b) + return a.priority - b.priority + +/proc/cmp_text_asc(a,b) + return sorttext(b, a) + +/proc/cmp_text_dsc(a,b) + return sorttext(a, b) + +/proc/cmp_qdel_item_time(datum/qdel_item/A, datum/qdel_item/B) + . = B.hard_delete_time - A.hard_delete_time + if (!.) + . = B.destroy_time - A.destroy_time + if (!.) + . = B.failures - A.failures + if (!.) + . = B.qdels - A.qdels + +/proc/cmp_ruincost_priority(datum/map_template/ruin/A, datum/map_template/ruin/B) + return initial(A.cost) - initial(B.cost) + +/proc/cmp_timer(datum/timedevent/a, datum/timedevent/b) + return a.timeToRun - b.timeToRun diff --git a/code/_helpers/files.dm b/code/_helpers/files.dm new file mode 100644 index 00000000..94d51d2b --- /dev/null +++ b/code/_helpers/files.dm @@ -0,0 +1,60 @@ +//checks if a file exists and contains text +//returns text as a string if these conditions are met +/proc/return_file_text(filename) + if(fexists(filename) == 0) + error("File not found ([filename])") + return + + var/text = file2text(filename) + if(!text) + error("File empty ([filename])") + return + + return text + +//Sends resource files to client cache +/client/proc/getFiles() + for(var/file in args) + src << browse_rsc(file) + +/client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list(".txt",".log",".htm")) + var/path = root + + for(var/i=0, iError: browse_files(): File not found/Invalid file([path]).") + return + + return path + +#define FTPDELAY 200 //200 tick delay to discourage spam +/* This proc is a failsafe to prevent spamming of file requests. + It is just a timer that only permits a download every [FTPDELAY] ticks. + This can be changed by modifying FTPDELAY's value above. + + PLEASE USE RESPONSIBLY, Some log files canr each sizes of 4MB! */ +/client/proc/file_spam_check() + var/time_to_wait = fileaccess_timer - world.time + if(time_to_wait > 0) + to_chat(src, "Error: file_spam_check(): Spam. Please wait [round(time_to_wait/10)] seconds.") + return 1 + fileaccess_timer = world.time + FTPDELAY + return 0 +#undef FTPDELAY diff --git a/code/_helpers/functional.dm b/code/_helpers/functional.dm new file mode 100644 index 00000000..b37e51ac --- /dev/null +++ b/code/_helpers/functional.dm @@ -0,0 +1,69 @@ +/proc/all_predicates_true(var/list/input, var/list/predicates) + predicates = istype(predicates) ? predicates : list(predicates) + + for(var/i = 1 to predicates.len) + if(istype(input)) + if(!call(predicates[i])(arglist(input))) + return FALSE + else + if(!call(predicates[i])(input)) + return FALSE + return TRUE + +/proc/any_predicate_true(var/list/input, var/list/predicates) + predicates = istype(predicates) ? predicates : list(predicates) + if(!predicates.len) + return TRUE + + for(var/i = 1 to predicates.len) + if(istype(input)) + if(call(predicates[i])(arglist(input))) + return TRUE + else + if(call(predicates[i])(input)) + return TRUE + return FALSE + +/proc/is_atom_predicate(var/value, var/feedback_receiver) + . = isatom(value) + if(!. && feedback_receiver) + to_chat(feedback_receiver, "Value must be an atom.") + +/proc/is_num_predicate(var/value, var/feedback_receiver) + . = isnum(value) + if(!. && feedback_receiver) + to_chat(feedback_receiver, "Value must be a numeral.") + +/proc/is_text_predicate(var/value, var/feedback_receiver) + . = !value || istext(value) + if(!. && feedback_receiver) + to_chat(feedback_receiver, "Value must be a text.") + +/proc/is_dir_predicate(var/value, var/feedback_receiver) + . = (value in GLOB.alldirs) + if(!. && feedback_receiver) + to_chat(feedback_receiver, "Value must be a direction.") + +/proc/can_locate(var/atom/container, var/container_thing) + return (locate(container_thing) in container) + +/proc/can_not_locate(var/atom/container, var/container_thing) + return !(locate(container_thing) in container) // We could just do !can_locate(container, container_thing) but BYOND is pretty awful when it comes to deep proc calls + + +/proc/where(var/list/list_to_filter, var/list/predicates, var/list/extra_predicate_input) + . = list() + for(var/entry in list_to_filter) + var/predicate_input + if(extra_predicate_input) + predicate_input = (list(entry) + extra_predicate_input) + else + predicate_input = entry + + if(all_predicates_true(predicate_input, predicates)) + . += entry + +/proc/map(var/list/list_to_map, var/map_proc) + . = list() + for(var/entry in list_to_map) + . += call(map_proc)(entry) diff --git a/code/_helpers/game.dm b/code/_helpers/game.dm new file mode 100644 index 00000000..4c99528d --- /dev/null +++ b/code/_helpers/game.dm @@ -0,0 +1,576 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/proc/dopage(src,target) + var/href_list + var/href + href_list = params2list("src=\ref[src]&[target]=1") + href = "src=\ref[src];[target]=1" + src:temphtml = null + src:Topic(href, href_list) + return null + +/proc/is_on_same_plane_or_station(var/z1, var/z2) + if(z1 == z2) + return 1 + if((z1 in GLOB.using_map.station_levels) && (z2 in GLOB.using_map.station_levels)) + return 1 + return 0 + +/proc/max_default_z_level() + var/max_z = 0 + for(var/z in GLOB.using_map.station_levels) + max_z = max(z, max_z) + for(var/z in GLOB.using_map.admin_levels) + max_z = max(z, max_z) + for(var/z in GLOB.using_map.player_levels) + max_z = max(z, max_z) + return max_z + +/proc/living_observers_present(var/list/zlevels) + if(LAZYLEN(zlevels)) + for(var/client/C in GLOB.clients) //if a tree ticks on the empty zlevel does it really tick + if(isliving(C.mob)) //(no it doesn't) + var/turf/T = get_turf(C.mob) + if(T && (T.z in zlevels)) + return TRUE + return FALSE + +/proc/get_z(O) + var/turf/loc = get_turf(O) + return loc ? loc.z : 0 + +/proc/get_area(O) + var/turf/loc = get_turf(O) + if(loc) + var/area/res = loc.loc + .= res + +/proc/get_area_name(N) //get area by its name + for(var/area/A in world) + if(A.name == N) + return A + return 0 + +/proc/get_area_master(const/O) + var/area/A = get_area(O) + if (isarea(A)) + return A + +/proc/in_range(source, user) + if(get_dist(source, user) <= 1) + return 1 + + return 0 //not in range and not telekinetic + +// Like view but bypasses luminosity check + +/proc/hear(var/range, var/atom/source) + + var/lum = source.luminosity + source.luminosity = 6 + + var/list/heard = view(range, source) + source.luminosity = lum + + return heard + +/proc/isStationLevel(var/level) + return level in GLOB.using_map.station_levels + +/proc/isNotStationLevel(var/level) + return !isStationLevel(level) + +/proc/isPlayerLevel(var/level) + return level in GLOB.using_map.player_levels + +/proc/isAdminLevel(var/level) + return level in GLOB.using_map.admin_levels + +/proc/isNotAdminLevel(var/level) + return !isAdminLevel(level) + +/proc/isContactLevel(var/level) + return level in GLOB.using_map.contact_levels + +/proc/circlerange(center=usr,radius=3) + + var/turf/centerturf = get_turf(center) + var/list/turfs = new/list() + var/rsq = radius * (radius+0.5) + + for(var/atom/T in range(radius, centerturf)) + var/dx = T.x - centerturf.x + var/dy = T.y - centerturf.y + if(dx*dx + dy*dy <= rsq) + turfs += T + + //turfs += centerturf + return turfs + +/proc/circleview(center=usr,radius=3) + + var/turf/centerturf = get_turf(center) + var/list/atoms = new/list() + var/rsq = radius * (radius+0.5) + + for(var/atom/A in view(radius, centerturf)) + var/dx = A.x - centerturf.x + var/dy = A.y - centerturf.y + if(dx*dx + dy*dy <= rsq) + atoms += A + + //turfs += centerturf + return atoms + +/proc/trange(rad = 0, turf/centre = null) //alternative to range (ONLY processes turfs and thus less intensive) + if(!centre) + return + + var/turf/x1y1 = locate(((centre.x-rad)<1 ? 1 : centre.x-rad),((centre.y-rad)<1 ? 1 : centre.y-rad),centre.z) + var/turf/x2y2 = locate(((centre.x+rad)>world.maxx ? world.maxx : centre.x+rad),((centre.y+rad)>world.maxy ? world.maxy : centre.y+rad),centre.z) + return block(x1y1,x2y2) + +/proc/get_dist_euclidian(atom/Loc1 as turf|mob|obj,atom/Loc2 as turf|mob|obj) + var/dx = Loc1.x - Loc2.x + var/dy = Loc1.y - Loc2.y + + var/dist = sqrt(dx**2 + dy**2) + + return dist + +/proc/circlerangeturfs(center=usr,radius=3) + + var/turf/centerturf = get_turf(center) + var/list/turfs = new/list() + var/rsq = radius * (radius+0.5) + + for(var/turf/T in range(radius, centerturf)) + var/dx = T.x - centerturf.x + var/dy = T.y - centerturf.y + if(dx*dx + dy*dy <= rsq) + turfs += T + return turfs + +/proc/circleviewturfs(center=usr,radius=3) //Is there even a diffrence between this proc and circlerangeturfs()? + + var/turf/centerturf = get_turf(center) + var/list/turfs = new/list() + var/rsq = radius * (radius+0.5) + + for(var/turf/T in view(radius, centerturf)) + var/dx = T.x - centerturf.x + var/dy = T.y - centerturf.y + if(dx*dx + dy*dy <= rsq) + turfs += T + return turfs + + + +//var/debug_mob = 0 + +// Will recursively loop through an atom's contents and check for mobs, then it will loop through every atom in that atom's contents. +// It will keep doing this until it checks every content possible. This will fix any problems with mobs, that are inside objects, +// being unable to hear people due to being in a box within a bag. + +/proc/recursive_content_check(var/atom/O, var/list/L = list(), var/recursion_limit = 3, var/client_check = 1, var/sight_check = 1, var/include_mobs = 1, var/include_objects = 1) + + if(!recursion_limit) + return L + + for(var/I in O.contents) + + if(ismob(I)) + if(!sight_check || isInSight(I, O)) + L |= recursive_content_check(I, L, recursion_limit - 1, client_check, sight_check, include_mobs, include_objects) + if(include_mobs) + if(client_check) + var/mob/M = I + if(M.client) + L |= M + else + L |= I + + else if(istype(I,/obj/)) + if(!sight_check || isInSight(I, O)) + L |= recursive_content_check(I, L, recursion_limit - 1, client_check, sight_check, include_mobs, include_objects) + if(include_objects) + L |= I + + return L + +// Returns a list of mobs and/or objects in range of R from source. Used in radio and say code. + +/proc/get_mobs_or_objects_in_view(var/R, var/atom/source, var/include_mobs = 1, var/include_objects = 1) + + var/turf/T = get_turf(source) + var/list/hear = list() + + if(!T) + return hear + + var/list/range = hear(R, T) + + for(var/I in range) + if(ismob(I)) + hear |= recursive_content_check(I, hear, 3, 1, 0, include_mobs, include_objects) + if(include_mobs) + var/mob/M = I + if(M.client) + hear += M + else if(istype(I,/obj/)) + hear |= recursive_content_check(I, hear, 3, 1, 0, include_mobs, include_objects) + if(include_objects) + hear += I + + return hear + + +/proc/get_mobs_in_radio_ranges(var/list/obj/item/device/radio/radios) + + set background = 1 + + . = list() + // Returns a list of mobs who can hear any of the radios given in @radios + var/list/speaker_coverage = list() + for(var/obj/item/device/radio/R in radios) + if(R) + //Cyborg checks. Receiving message uses a bit of cyborg's charge. + var/obj/item/device/radio/borg/BR = R + if(istype(BR) && BR.myborg) + var/mob/living/silicon/robot/borg = BR.myborg + var/datum/robot_component/CO = borg.get_component("radio") + if(!CO) + continue //No radio component (Shouldn't happen) + if(!borg.is_component_functioning("radio") || !borg.cell_use_power(CO.active_usage)) + continue //No power. + + var/turf/speaker = get_turf(R) + if(speaker) + for(var/turf/T in hear(R.canhear_range,speaker)) + speaker_coverage[T] = T + + + // Try to find all the players who can hear the message + for(var/i = 1; i <= GLOB.player_list.len; i++) + var/mob/M = GLOB.player_list[i] + if(M) + var/turf/ear = get_turf(M) + if(ear) + // Ghostship is magic: Ghosts can hear radio chatter from anywhere + if(speaker_coverage[ear] || (isghost(M) && M.get_preference_value(/datum/client_preference/ghost_radio) == GLOB.PREF_ALL_CHATTER)) + . |= M // Since we're already looping through mobs, why bother using |= ? This only slows things down. + return . + +/proc/get_mobs_and_objs_in_view_fast(var/turf/T, var/range, var/list/mobs, var/list/objs, var/checkghosts = null) + + var/list/hear = dview(range,T,INVISIBILITY_MAXIMUM) + var/list/hearturfs = list() + + for(var/atom/movable/AM in hear) + if(ismob(AM)) + mobs += AM + hearturfs += get_turf(AM) + else if(isobj(AM)) + objs += AM + hearturfs += get_turf(AM) + + for(var/mob/M in GLOB.player_list) + if(checkghosts && M.stat == DEAD && M.get_preference_value(checkghosts) != GLOB.PREF_NEARBY) + mobs |= M + else if(get_turf(M) in hearturfs) + mobs |= M + + for(var/obj/O in GLOB.listening_objects) + if(get_turf(O) in hearturfs) + objs |= O + + + + + +proc + inLineOfSight(X1,Y1,X2,Y2,Z=1,PX1=16.5,PY1=16.5,PX2=16.5,PY2=16.5) + var/turf/T + if(X1==X2) + if(Y1==Y2) + return 1 //Light cannot be blocked on same tile + else + var/s = SIMPLE_SIGN(Y2-Y1) + Y1+=s + while(Y1!=Y2) + T=locate(X1,Y1,Z) + if(T.opacity) + return 0 + Y1+=s + else + var/m=(32*(Y2-Y1)+(PY2-PY1))/(32*(X2-X1)+(PX2-PX1)) + var/b=(Y1+PY1/32-0.015625)-m*(X1+PX1/32-0.015625) //In tiles + var/signX = SIMPLE_SIGN(X2-X1) + var/signY = SIMPLE_SIGN(Y2-Y1) + if(X1 abs (dx)) //slope is above 1:1 (move horizontally in a tie) + if(dy > 0) + return get_step(start, SOUTH) + else + return get_step(start, NORTH) + else + if(dx > 0) + return get_step(start, WEST) + else + return get_step(start, EAST) + +/proc/get_mob_by_key(var/key) + for(var/mob/M in SSmobs.mob_list) + if(M.ckey == lowertext(key)) + return M + return null + + +// Will return a list of active candidates. It increases the buffer 5 times until it finds a candidate which is active within the buffer. +/proc/get_active_candidates(var/buffer = 1) + + var/list/candidates = list() //List of candidate KEYS to assume control of the new larva ~Carn + var/i = 0 + while(candidates.len <= 0 && i < 5) + for(var/mob/observer/ghost/G in GLOB.player_list) + if(((G.client.inactivity/10)/60) <= buffer + i) // the most active players are more likely to become an alien + if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD)) + candidates += G.key + i++ + return candidates + +// Same as above but for alien candidates. + +/proc/get_alien_candidates() + var/list/candidates = list() //List of candidate KEYS to assume control of the new larva ~Carn + var/i = 0 + while(candidates.len <= 0 && i < 5) + for(var/mob/observer/ghost/G in GLOB.player_list) + if(MODE_XENOMORPH in G.client.prefs.be_special_role) + if(((G.client.inactivity/10)/60) <= ALIEN_SELECT_AFK_BUFFER + i) // the most active players are more likely to become an alien + if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD)) + candidates += G.key + i++ + return candidates + +/proc/ScreenText(obj/O, maptext="", screen_loc="CENTER-7,CENTER-7", maptext_height=480, maptext_width=480) + if(!isobj(O)) O = new /obj/screen/text() + O.maptext = maptext + O.maptext_height = maptext_height + O.maptext_width = maptext_width + O.screen_loc = screen_loc + return O + +/proc/Show2Group4Delay(obj/O, list/group, delay=0) + if(!isobj(O)) return + if(!group) group = GLOB.clients + for(var/client/C in group) + C.screen += O + if(delay) + spawn(delay) + for(var/client/C in group) + C.screen -= O + +/proc/flick_overlay(image/I, list/show_to, duration) + for(var/client/C in show_to) + C.images += I + spawn(duration) + for(var/client/C in show_to) + C.images -= I + +datum/projectile_data + var/src_x + var/src_y + var/time + var/distance + var/power_x + var/power_y + var/dest_x + var/dest_y + +/datum/projectile_data/New(var/src_x, var/src_y, var/time, var/distance, \ + var/power_x, var/power_y, var/dest_x, var/dest_y) + src.src_x = src_x + src.src_y = src_y + src.time = time + src.distance = distance + src.power_x = power_x + src.power_y = power_y + src.dest_x = dest_x + src.dest_y = dest_y + +/proc/projectile_trajectory(var/src_x, var/src_y, var/rotation, var/angle, var/power) + + // returns the destination (Vx,y) that a projectile shot at [src_x], [src_y], with an angle of [angle], + // rotated at [rotation] and with the power of [power] + // Thanks to VistaPOWA for this function + + var/power_x = power * cos(angle) + var/power_y = power * sin(angle) + var/time = 2* power_y / 10 //10 = g + + var/distance = time * power_x + + var/dest_x = src_x + distance*sin(rotation); + var/dest_y = src_y + distance*cos(rotation); + + return new /datum/projectile_data(src_x, src_y, time, distance, power_x, power_y, dest_x, dest_y) + +/proc/GetRedPart(const/hexa) + return hex2num(copytext(hexa,2,4)) + +/proc/GetGreenPart(const/hexa) + return hex2num(copytext(hexa,4,6)) + +/proc/GetBluePart(const/hexa) + return hex2num(copytext(hexa,6,8)) + +/proc/GetHexColors(const/hexa) + return list( + GetRedPart(hexa), + GetGreenPart(hexa), + GetBluePart(hexa) + ) + +/proc/MixColors(const/list/colors) + var/list/reds = list() + var/list/blues = list() + var/list/greens = list() + var/list/weights = list() + + for (var/i = 0, ++i <= colors.len) + reds.Add(GetRedPart(colors[i])) + blues.Add(GetBluePart(colors[i])) + greens.Add(GetGreenPart(colors[i])) + weights.Add(1) + + var/r = mixOneColor(weights, reds) + var/g = mixOneColor(weights, greens) + var/b = mixOneColor(weights, blues) + return rgb(r,g,b) + +/proc/mixOneColor(var/list/weight, var/list/color) + if (!weight || !color || length(weight)!=length(color)) + return 0 + + var/contents = length(weight) + var/i + + //normalize weights + var/listsum = 0 + for(i=1; i<=contents; i++) + listsum += weight[i] + for(i=1; i<=contents; i++) + weight[i] /= listsum + + //mix them + var/mixedcolor = 0 + for(i=1; i<=contents; i++) + mixedcolor += weight[i]*color[i] + mixedcolor = round(mixedcolor) + + //until someone writes a formal proof for this algorithm, let's keep this in +// if(mixedcolor<0x00 || mixedcolor>0xFF) +// return 0 + //that's not the kind of operation we are running here, nerd + mixedcolor=min(max(mixedcolor,0),255) + + return mixedcolor + +/** +* Gets the highest and lowest pressures from the tiles in cardinal directions +* around us, then checks the difference. +*/ +/proc/getOPressureDifferential(var/turf/loc) + var/minp=16777216; + var/maxp=0; + for(var/dir in GLOB.cardinal) + var/turf/simulated/T=get_turf(get_step(loc,dir)) + var/cp=0 + if(T && istype(T) && T.zone) + var/datum/gas_mixture/environment = T.return_air() + cp = environment.return_pressure() + else + if(istype(T,/turf/simulated)) + continue + if(cpmaxp)maxp=cp + return abs(minp-maxp) + +/proc/convert_k2c(var/temp) + return ((temp - T0C)) + +/proc/convert_c2k(var/temp) + return ((temp + T0C)) + +/proc/getCardinalAirInfo(var/turf/loc, var/list/stats=list("temperature")) + var/list/temps = new/list(4) + for(var/dir in GLOB.cardinal) + var/direction + switch(dir) + if(NORTH) + direction = 1 + if(SOUTH) + direction = 2 + if(EAST) + direction = 3 + if(WEST) + direction = 4 + var/turf/simulated/T=get_turf(get_step(loc,dir)) + var/list/rstats = new /list(stats.len) + if(T && istype(T) && T.zone) + var/datum/gas_mixture/environment = T.return_air() + for(var/i=1;i<=stats.len;i++) + if(stats[i] == "pressure") + rstats[i] = environment.return_pressure() + else + rstats[i] = environment.vars[stats[i]] + else if(istype(T, /turf/simulated)) + rstats = null // Exclude zone (wall, door, etc). + else if(istype(T, /turf)) + // Should still work. (/turf/return_air()) + var/datum/gas_mixture/environment = T.return_air() + for(var/i=1;i<=stats.len;i++) + if(stats[i] == "pressure") + rstats[i] = environment.return_pressure() + else + rstats[i] = environment.vars[stats[i]] + temps[direction] = rstats + return temps + +/proc/MinutesToTicks(var/minutes) + return SecondsToTicks(60 * minutes) + +/proc/SecondsToTicks(var/seconds) + return seconds * 10 + +/proc/round_is_spooky(var/spookiness_threshold = config.cult_ghostwriter_req_cultists) + return (cult.current_antagonists.len > spookiness_threshold) diff --git a/code/_helpers/global_access.dm b/code/_helpers/global_access.dm new file mode 100644 index 00000000..96319ad7 --- /dev/null +++ b/code/_helpers/global_access.dm @@ -0,0 +1,2545 @@ +// THIS FILE IS AUTOMATICALLY CREATED BY tools/gen_globals.py +/proc/readglobal(which) + switch(which) + if("ALL_ANTIGENS") + return global.ALL_ANTIGENS; + if("ANTAG_FREQS") + return global.ANTAG_FREQS; + if("BSACooldown") + return global.BSACooldown; + if("BUMP_TELEPORTERS") + return global.BUMP_TELEPORTERS; + if("Banlist") + return global.Banlist; + if("CENT_FREQS") + return global.CENT_FREQS; + if("CMinutes") + return global.CMinutes; + if("DEPT_FREQS") + return global.DEPT_FREQS; + if("Debug2") + return global.Debug2; + if("Failsafe") + return global.Failsafe; + if("GLOB") + return global.GLOB; + if("Holiday") + return global.Holiday; + if("IClog") + return global.IClog; + if("LIGHTING_CORNER_DIAGONAL") + return global.LIGHTING_CORNER_DIAGONAL; + if("Master") + return global.Master; + if("OOClog") + return global.OOClog; + if("PDAs") + return global.PDAs; + if("SSair") + return global.SSair; + if("SSairflow") + return global.SSairflow; + if("SSatoms") + return global.SSatoms; + if("SSfastprocess") + return global.SSfastprocess; + if("SSgarbage") + return global.SSgarbage; + if("SSlegacy") + return global.SSlegacy; + if("SSmachines") + return global.SSmachines; + if("SSmapping") + return global.SSmapping; + if("SSmobs") + return global.SSmobs; + if("SSobj") + return global.SSobj; + if("SSopen_space") + return global.SSopen_space; + if("SSprocessing") + return global.SSprocessing; + if("SSskybox") + return global.SSskybox; + if("SSsun") + return global.SSsun; + if("SStimer") + return global.SStimer; + if("SSvines") + return global.SSvines; + if("SSwireless") + return global.SSwireless; + if("Tier1Runes") + return global.Tier1Runes; + if("Tier2Runes") + return global.Tier2Runes; + if("Tier3Runes") + return global.Tier3Runes; + if("Tier4Runes") + return global.Tier4Runes; + if("WALLITEMS") + return global.WALLITEMS; + if("_all_globals") + return global._all_globals; + if("_client_preferences") + return global._client_preferences; + if("_client_preferences_by_key") + return global._client_preferences_by_key; + if("_client_preferences_by_type") + return global._client_preferences_by_type; + if("account_hack_attempted") + return global.account_hack_attempted; + if("actor") + return global.actor; + if("additional_antag_types") + return global.additional_antag_types; + if("admin_datums") + return global.admin_datums; + if("admin_pm_repository") + return global.admin_pm_repository; + if("admin_ranks") + return global.admin_ranks; + if("admin_secrets") + return global.admin_secrets; + if("admin_verbs_admin") + return global.admin_verbs_admin; + if("admin_verbs_ban") + return global.admin_verbs_ban; + if("admin_verbs_debug") + return global.admin_verbs_debug; + if("admin_verbs_default") + return global.admin_verbs_default; + if("admin_verbs_fun") + return global.admin_verbs_fun; + if("admin_verbs_hideable") + return global.admin_verbs_hideable; + if("admin_verbs_mentor") + return global.admin_verbs_mentor; + if("admin_verbs_mod") + return global.admin_verbs_mod; + if("admin_verbs_paranoid_debug") + return global.admin_verbs_paranoid_debug; + if("admin_verbs_permissions") + return global.admin_verbs_permissions; + if("admin_verbs_possess") + return global.admin_verbs_possess; + if("admin_verbs_rejuv") + return global.admin_verbs_rejuv; + if("admin_verbs_server") + return global.admin_verbs_server; + if("admin_verbs_sounds") + return global.admin_verbs_sounds; + if("admin_verbs_spawn") + return global.admin_verbs_spawn; + if("adminhelp_ignored_words") + return global.adminhelp_ignored_words; + if("adminlog") + return global.adminlog; + if("ai_list") + return global.ai_list; + if("ai_status_emotions") + return global.ai_status_emotions; + if("ai_verbs_default") + return global.ai_verbs_default; + if("air_alarm_topic") + return global.air_alarm_topic; + if("air_blocked") + return global.air_blocked; + if("air_processing_killed") + return global.air_processing_killed; + if("alarm_manager") + return global.alarm_manager; + if("alien_whitelist") + return global.alien_whitelist; + if("allCasters") + return global.allCasters; + if("allConsoles") + return global.allConsoles; + if("all_antag_spawnpoints_") + return global.all_antag_spawnpoints_; + if("all_antag_types_") + return global.all_antag_types_; + if("all_grabobjects") + return global.all_grabobjects; + if("all_grabstates") + return global.all_grabstates; + if("all_languages") + return global.all_languages; + if("all_money_accounts") + return global.all_money_accounts; + if("all_objectives") + return global.all_objectives; + if("all_robolimbs") + return global.all_robolimbs; + if("all_species") + return global.all_species; + if("all_ui_styles") + return global.all_ui_styles; + if("all_unit_tests_passed") + return global.all_unit_tests_passed; + if("all_virtual_listeners") + return global.all_virtual_listeners; + if("announced_news_types") + return global.announced_news_types; + if("antag_add_finished") + return global.antag_add_finished; + if("antag_names_to_ids_") + return global.antag_names_to_ids_; + if("appearance_manager") + return global.appearance_manager; + if("area_repository") + return global.area_repository; + if("artefact_feedback") + return global.artefact_feedback; + if("ascii_esc") + return global.ascii_esc; + if("ascii_green") + return global.ascii_green; + if("ascii_red") + return global.ascii_red; + if("ascii_reset") + return global.ascii_reset; + if("ascii_yellow") + return global.ascii_yellow; + if("asset_cache") + return global.asset_cache; + if("asset_datums") + return global.asset_datums; + if("assigned") + return global.assigned; + if("assigned_blocks") + return global.assigned_blocks; + if("atmosphere_alarm") + return global.atmosphere_alarm; + if("attack_log_repository") + return global.attack_log_repository; + if("autolathe_categories") + return global.autolathe_categories; + if("autolathe_recipes") + return global.autolathe_recipes; + if("base_miss_chance") + return global.base_miss_chance; + if("basic_robolimb") + return global.basic_robolimb; + if("blackbox") + return global.blackbox; + if("blocked") + return global.blocked; + if("bomb_set") + return global.bomb_set; + if("borers") + return global.borers; + if("cable_list") + return global.cable_list; + if("cached_icons") + return global.cached_icons; + if("cached_space") + return global.cached_space; + if("camera_alarm") + return global.camera_alarm; + if("camera_range_display_status") + return global.camera_range_display_status; + if("camera_repository") + return global.camera_repository; + if("cameranet") + return global.cameranet; + if("can_call_ert") + return global.can_call_ert; + if("captain_announcement") + return global.captain_announcement; + if("cargo_supply_pack_root") + return global.cargo_supply_pack_root; + if("cargo_supply_packs") + return global.cargo_supply_packs; + if("changelog_hash") + return global.changelog_hash; + if("channel_to_radio_key") + return global.channel_to_radio_key; + if("chargen_robolimbs") + return global.chargen_robolimbs; + if("checked_for_inactives") + return global.checked_for_inactives; + if("chemical_reaction_logs") + return global.chemical_reaction_logs; + if("chemical_reactions_list") + return global.chemical_reactions_list; + if("chemical_produce_list") + return global.chemical_produce_list; + if("chicken_count") + return global.chicken_count; + if("church_name") + return global.church_name; + if("client_preference_stats_") + return global.client_preference_stats_; + if("client_repository") + return global.client_repository; + if("combatlog") + return global.combatlog; + if("comm_message_listeners") + return global.comm_message_listeners; + if("command_announcement") + return global.command_announcement; + if("command_name") + return global.command_name; + if("commandos") + return global.commandos; + if("common_tools") + return global.common_tools; + if("config") + return global.config; + if("contamination_overlay") + return global.contamination_overlay; + if("controller_iteration") + return global.controller_iteration; + if("create_mob_html") + return global.create_mob_html; + if("create_object_html") + return global.create_object_html; + if("create_turf_html") + return global.create_turf_html; + if("created") + return global.created; + if("crew_repository") + return global.crew_repository; + if("csrfz_check") + return global.csrfz_check; + if("cult") + return global.cult; + if("currently_running_tests") + return global.currently_running_tests; + if("custom_event_msg") + return global.custom_event_msg; + if("custom_items") + return global.custom_items; + if("damage_icon_parts") + return global.damage_icon_parts; + if("dbcon") + return global.dbcon; + if("dbcon_old") + return global.dbcon_old; + if("deathsquad") + return global.deathsquad; + if("debug_verbs") + return global.debug_verbs; + if("decls_repository") + return global.decls_repository; + if("default_material_composition") + return global.default_material_composition; + if("default_mobloc") + return global.default_mobloc; + if("default_onmob_icons") + return global.default_onmob_icons; + if("default_pai_software") + return global.default_pai_software; + if("defer_powernet_rebuild") + return global.defer_powernet_rebuild; + if("delta_index") + return global.delta_index; + if("department_accounts") + return global.department_accounts; + if("department_radio_keys") + return global.department_radio_keys; + if("description_icons") + return global.description_icons; + if("diary") + return global.diary; + if("dna_activity_bounds") + return global.dna_activity_bounds; + if("dna_genes") + return global.dna_genes; + if("doppler_arrays") + return global.doppler_arrays; + if("dreams") + return global.dreams; + if("dummy_lighting_corner") + return global.dummy_lighting_corner; + if("economic_species_modifier") + return global.economic_species_modifier; + if("empty_playable_ai_cores") + return global.empty_playable_ai_cores; + if("endgame_exits") + return global.endgame_exits; + if("endgame_safespawns") + return global.endgame_safespawns; + if("ert") + return global.ert; + if("ert_base_chance") + return global.ert_base_chance; + if("escape_pods") + return global.escape_pods; + if("escape_pods_by_name") + return global.escape_pods_by_name; + if("evacuation_controller") + return global.evacuation_controller; + if("event_last_fired") + return global.event_last_fired; + if("eventchance") + return global.eventchance; + if("exclude_jobs") + return global.exclude_jobs; + if("explosion_in_progress") + return global.explosion_in_progress; + if("explosion_turfs") + return global.explosion_turfs; + if("failed_db_connections") + return global.failed_db_connections; + if("failed_old_db_connections") + return global.failed_old_db_connections; + if("failed_unit_tests") + return global.failed_unit_tests; + if("file_uid") + return global.file_uid; + if("fileaccess_timer") + return global.fileaccess_timer; + if("finds_as_strings") + return global.finds_as_strings; + if("fire_alarm") + return global.fire_alarm; + if("flesh_hud_colours") + return global.flesh_hud_colours; + if("floorIsLava") + return global.floorIsLava; + if("floor_decals") + return global.floor_decals; + if("floor_light_cache") + return global.floor_light_cache; + if("flooring_cache") + return global.flooring_cache; + if("flooring_types") + return global.flooring_types; + if("fluidtrack_cache") + return global.fluidtrack_cache; + if("follow_repository") + return global.follow_repository; + if("forced_ambiance_list") + return global.forced_ambiance_list; + if("fruit_icon_cache") + return global.fruit_icon_cache; + if("fuel_injectors") + return global.fuel_injectors; + if("fusion_cores") + return global.fusion_cores; + if("fusion_reactions") + return global.fusion_reactions; + if("game_id") + return global.game_id; + if("game_version") + return global.game_version; + if("game_year") + return global.game_year; + if("gamemode_cache") + return global.gamemode_cache; + if("gas_data") + return global.gas_data; + if("gender_datums") + return global.gender_datums; + if("ghost_darkness_images") + return global.ghost_darkness_images; + if("ghost_sightless_images") + return global.ghost_sightless_images; + if("ghost_traps") + return global.ghost_traps; + if("global_message_listener") + return global.global_message_listener; + if("global_vars_") + return global.global_vars_; + if("gravity_is_on") + return global.gravity_is_on; + if("gyrotrons") + return global.gyrotrons; + if("gzn_check") + return global.gzn_check; + if("hadevent") + return global.hadevent; + if("hazard_overlays") + return global.hazard_overlays; + if("hivemind_bank") + return global.hivemind_bank; + if("holder_mob_icon_cache") + return global.holder_mob_icon_cache; + if("host") + return global.host; + if("href_logfile") + return global.href_logfile; + if("human_icon_cache") + return global.human_icon_cache; + if("id_card_states") + return global.id_card_states; + if("image_repository") + return global.image_repository; + if("inactive_keys") + return global.inactive_keys; + if("init") + return global.init; + if("initialization_stage") + return global.initialization_stage; + if("integrated_circuit_blacklist") + return global.integrated_circuit_blacklist; + if("intents") + return global.intents; + if("intercom_range_display_status") + return global.intercom_range_display_status; + if("invalid_zone") + return global.invalid_zone; + if("jobMax") + return global.jobMax; + if("job_master") + return global.job_master; + if("jobban_keylist") + return global.jobban_keylist; + if("jobban_runonce") + return global.jobban_runonce; + if("joblist") + return global.joblist; + if("join_motd") + return global.join_motd; + if("landmarks_list") + return global.landmarks_list; + if("language_keys") + return global.language_keys; + if("last_chew") + return global.last_chew; + if("last_message_id") + return global.last_message_id; + if("last_round_duration") + return global.last_round_duration; + if("last_tick_duration") + return global.last_tick_duration; + if("license_to_url") + return global.license_to_url; + if("light_overlay_cache") + return global.light_overlay_cache; + if("lighting_overlays_initialised") + return global.lighting_overlays_initialised; + if("lighting_update_corners") + return global.lighting_update_corners; + if("lighting_update_corners_old") + return global.lighting_update_corners_old; + if("lighting_update_lights") + return global.lighting_update_lights; + if("lighting_update_lights_old") + return global.lighting_update_lights_old; + if("lighting_update_overlays") + return global.lighting_update_overlays; + if("lighting_update_overlays_old") + return global.lighting_update_overlays_old; + if("limb_icon_cache") + return global.limb_icon_cache; + if("lobby_image") + return global.lobby_image; + if("log_end") + return global.log_end; + if("loyalists") + return global.loyalists; + if("lunchables_drink_reagents_") + return global.lunchables_drink_reagents_; + if("lunchables_drinks_") + return global.lunchables_drinks_; + if("lunchables_ethanol_reagents_") + return global.lunchables_ethanol_reagents_; + if("lunchables_lunches_") + return global.lunchables_lunches_; + if("lunchables_snacks_") + return global.lunchables_snacks_; + if("magazine_icondata_keys") + return global.magazine_icondata_keys; + if("magazine_icondata_states") + return global.magazine_icondata_states; + if("maint_all_access") + return global.maint_all_access; + if("malf") + return global.malf; + if("mannequins_") + return global.mannequins_; + if("map_count") + return global.map_count; + if("map_sectors") + return global.map_sectors; + if("maploader") + return global.maploader; + if("mark") + return global.mark; + if("master_controller") + return global.master_controller; + if("master_mode") + return global.master_mode; + if("maze_cell_count") + return global.maze_cell_count; + if("mechas_list") + return global.mechas_list; + if("mechtoys") + return global.mechtoys; + if("mercs") + return global.mercs; + if("merged") + return global.merged; + if("message_delay") + return global.message_delay; + if("message_servers") + return global.message_servers; + if("meteors_armageddon") + return global.meteors_armageddon; + if("meteors_cataclysm") + return global.meteors_cataclysm; + if("meteors_catastrophic") + return global.meteors_catastrophic; + if("meteors_dust") + return global.meteors_dust; + if("meteors_major") + return global.meteors_major; + if("meteors_minor") + return global.meteors_minor; + if("meteors_moderate") + return global.meteors_moderate; + if("meteors_normal") + return global.meteors_normal; + if("meteors_threatening") + return global.meteors_threatening; + if("mil_branches") + return global.mil_branches; + if("mining_floors") + return global.mining_floors; + if("mining_walls") + return global.mining_walls; + if("minor_air_alarms") + return global.minor_air_alarms; + if("minor_announcement") + return global.minor_announcement; + if("mob_hat_cache") + return global.mob_hat_cache; + if("mob_repository") + return global.mob_repository; + if("motion_alarm") + return global.motion_alarm; + if("moving_levels") + return global.moving_levels; + if("multi_point_spawns") + return global.multi_point_spawns; + if("name_to_material") + return global.name_to_material; + if("narsie_behaviour") + return global.narsie_behaviour; + if("narsie_cometh") + return global.narsie_cometh; + if("narsie_list") + return global.narsie_list; + if("navbeacons") + return global.navbeacons; + if("news_network") + return global.news_network; + if("newscaster_standard_feeds") + return global.newscaster_standard_feeds; + if("next_account_number") + return global.next_account_number; + if("next_duration_update") + return global.next_duration_update; + if("next_station_date_change") + return global.next_station_date_change; + if("not_incapacitated_turf_state") + return global.not_incapacitated_turf_state; + if("ntnet_card_uid") + return global.ntnet_card_uid; + if("ntnet_global") + return global.ntnet_global; + if("ntnrc_uid") + return global.ntnrc_uid; + if("nttransfer_uid") + return global.nttransfer_uid; + if("nuke_disks") + return global.nuke_disks; + if("num_financial_terminals") + return global.num_financial_terminals; + if("ore_data") + return global.ore_data; + if("ores_by_type") + return global.ores_by_type; + if("organ_cache") + return global.organ_cache; + if("organ_rel_size") + return global.organ_rel_size; + if("outfits_decls_") + return global.outfits_decls_; + if("outfits_decls_by_type_") + return global.outfits_decls_by_type_; + if("outfits_decls_root_") + return global.outfits_decls_root_; + if("overmap_event_handler") + return global.overmap_event_handler; + if("paiController") + return global.paiController; + if("pai_emotions") + return global.pai_emotions; + if("pai_software_by_key") + return global.pai_software_by_key; + if("paramslist_cache") + return global.paramslist_cache; + if("photo_count") + return global.photo_count; + if("pipe_colors") + return global.pipe_colors; + if("pipe_processing_killed") + return global.pipe_processing_killed; + if("plant_controller") + return global.plant_controller; + if("plant_seed_sprites") + return global.plant_seed_sprites; + if("playable_species") + return global.playable_species; + if("point_source_descriptions") + return global.point_source_descriptions; + if("possible_cable_coil_colours") + return global.possible_cable_coil_colours; + if("possible_changeling_IDs") + return global.possible_changeling_IDs; + if("poster_designs") + return global.poster_designs; + if("power_alarm") + return global.power_alarm; + if("powerinstances") + return global.powerinstances; + if("powers") + return global.powers; + if("preferences_datums") + return global.preferences_datums; + if("priority_air_alarms") + return global.priority_air_alarms; + if("priority_announcement") + return global.priority_announcement; + if("priv_all_access") + return global.priv_all_access; + if("priv_all_access_datums") + return global.priv_all_access_datums; + if("priv_all_access_datums_id") + return global.priv_all_access_datums_id; + if("priv_all_access_datums_region") + return global.priv_all_access_datums_region; + if("priv_centcom_access") + return global.priv_centcom_access; + if("priv_region_access") + return global.priv_region_access; + if("priv_station_access") + return global.priv_station_access; + if("priv_syndicate_access") + return global.priv_syndicate_access; + if("processScheduler") + return global.processScheduler; + if("processing_turfs") + return global.processing_turfs; + if("protected_objects") + return global.protected_objects; + if("rad_collectors") + return global.rad_collectors; + if("radiation_repository") + return global.radiation_repository; + if("radio_controller") + return global.radio_controller; + if("radiochannels") + return global.radiochannels; + if("raiders") + return global.raiders; + if("random_junk_") + return global.random_junk_; + if("random_maps") + return global.random_maps; + if("random_useful_") + return global.random_useful_; + if("recentmessages") + return global.recentmessages; + if("registered_macros_by_ckey_") + return global.registered_macros_by_ckey_; + if("religion_name") + return global.religion_name; + if("renegades") + return global.renegades; + if("req_console_assistance") + return global.req_console_assistance; + if("req_console_information") + return global.req_console_information; + if("req_console_supplies") + return global.req_console_supplies; + if("responsive_carriers") + return global.responsive_carriers; + if("restricted_camera_networks") + return global.restricted_camera_networks; + if("revdata") + return global.revdata; + if("revs") + return global.revs; + if("robot_custom_icons") + return global.robot_custom_icons; + if("robot_hud_colours") + return global.robot_hud_colours; + if("robot_inventory") + return global.robot_inventory; + if("robot_modules") + return global.robot_modules; + if("round_progressing") + return global.round_progressing; + if("round_start_time") + return global.round_start_time; + if("roundstart_hour") + return global.roundstart_hour; + if("rune_list") + return global.rune_list; + if("runtime_diary") + return global.runtime_diary; + if("same_wires") + return global.same_wires; + if("secondary_mode") + return global.secondary_mode; + if("secret_force_mode") + return global.secret_force_mode; + if("send_emergency_team") + return global.send_emergency_team; + if("sent_spiders_to_station") + return global.sent_spiders_to_station; + if("server_name") + return global.server_name; + if("severity_to_string") + return global.severity_to_string; + if("ship_engines") + return global.ship_engines; + if("shuttle_controller") + return global.shuttle_controller; + if("side_effects") + return global.side_effects; + if("skin_styles_female_list") + return global.skin_styles_female_list; + if("skipped_unit_tests") + return global.skipped_unit_tests; + if("slot_equipment_priority") + return global.slot_equipment_priority; + if("slot_flags_enumeration") + return global.slot_flags_enumeration; + if("solar_gen_rate") + return global.solar_gen_rate; + if("solars_list") + return global.solars_list; + if("sortInstance") + return global.sortInstance; + if("sound_player") + return global.sound_player; + if("sounds_cache") + return global.sounds_cache; + if("spacevines_spawned") + return global.spacevines_spawned; + if("sparring_attack_cache") + return global.sparring_attack_cache; + if("spells") + return global.spells; + if("splatter_cache") + return global.splatter_cache; + if("sqladdress") + return global.sqladdress; + if("sqldb") + return global.sqldb; + if("sqlfdbkdb") + return global.sqlfdbkdb; + if("sqlfdbklogin") + return global.sqlfdbklogin; + if("sqlfdbkpass") + return global.sqlfdbkpass; + if("sqllogging") + return global.sqllogging; + if("sqllogin") + return global.sqllogin; + if("sqlpass") + return global.sqlpass; + if("sqlport") + return global.sqlport; + if("station_account") + return global.station_account; + if("station_date") + return global.station_date; + if("stool_cache") + return global.stool_cache; + if("stored_shock_by_ref") + return global.stored_shock_by_ref; + if("string_part_flags") + return global.string_part_flags; + if("string_slot_flags") + return global.string_slot_flags; + if("supply_controller") + return global.supply_controller; + if("supply_drop") + return global.supply_drop; + if("supply_methods_") + return global.supply_methods_; + if("surgery_steps") + return global.surgery_steps; + if("swapmaps_byname") + return global.swapmaps_byname; + if("swapmaps_compiled_maxx") + return global.swapmaps_compiled_maxx; + if("swapmaps_compiled_maxy") + return global.swapmaps_compiled_maxy; + if("swapmaps_compiled_maxz") + return global.swapmaps_compiled_maxz; + if("swapmaps_iconcache") + return global.swapmaps_iconcache; + if("swapmaps_initialized") + return global.swapmaps_initialized; + if("swapmaps_loaded") + return global.swapmaps_loaded; + if("swapmaps_mode") + return global.swapmaps_mode; + if("syndicate_access") + return global.syndicate_access; + if("syndicate_code_phrase") + return global.syndicate_code_phrase; + if("syndicate_code_response") + return global.syndicate_code_response; + if("syndicate_name") + return global.syndicate_name; + if("tail_icon_cache") + return global.tail_icon_cache; + if("tank_gauge_cache") + return global.tank_gauge_cache; + if("tape_roll_applications") + return global.tape_roll_applications; + if("telecomms_list") + return global.telecomms_list; + if("tertiary_mode") + return global.tertiary_mode; + if("text_tag_icons") + return global.text_tag_icons; + if("tg_admin_state") + return global.tg_admin_state; + if("tg_always_state") + return global.tg_always_state; + if("tg_conscious_state") + return global.tg_conscious_state; + if("tg_contained_state") + return global.tg_contained_state; + if("tg_deep_inventory_state") + return global.tg_deep_inventory_state; + if("tg_default_state") + return global.tg_default_state; + if("tg_hands_state") + return global.tg_hands_state; + if("tg_human_adjacent_state") + return global.tg_human_adjacent_state; + if("tg_inventory_state") + return global.tg_inventory_state; + if("tg_not_contained_state") + return global.tg_not_contained_state; + if("tg_not_incapacitated_state") + return global.tg_not_incapacitated_state; + if("tg_physical_state") + return global.tg_physical_state; + if("tg_self_state") + return global.tg_self_state; + if("tg_z_state") + return global.tg_z_state; + if("tgui_process") + return global.tgui_process; + if("ticker") + return global.ticker; + if("tickerProcess") + return global.tickerProcess; + if("ticket_panels") + return global.ticket_panels; + if("tickets") + return global.tickets; + if("total_lighting_corners") + return global.total_lighting_corners; + if("total_lighting_overlays") + return global.total_lighting_overlays; + if("total_lighting_sources") + return global.total_lighting_sources; + if("total_unit_tests") + return global.total_unit_tests; + if("traitors") + return global.traitors; + if("transfer_controller") + return global.transfer_controller; + if("turbolift_controller") + return global.turbolift_controller; + if("turbolifts") + return global.turbolifts; + if("turret_icons") + return global.turret_icons; + if("uniqueness_repository") + return global.uniqueness_repository; + if("universe_has_ended") + return global.universe_has_ended; + if("uplink") + return global.uplink; + if("uplink_purchase_repository") + return global.uplink_purchase_repository; + if("uplink_random_selections_") + return global.uplink_random_selections_; + if("valid_bloodtypes") + return global.valid_bloodtypes; + if("vendor_account") + return global.vendor_account; + if("ventcrawl_machinery") + return global.ventcrawl_machinery; + if("view_variables_dont_expand") + return global.view_variables_dont_expand; + if("view_variables_no_assoc") + return global.view_variables_no_assoc; + if("virusDB") + return global.virusDB; + if("visual_nets") + return global.visual_nets; + if("vote") + return global.vote; + if("vsc") + return global.vsc; + if("weighted_mundaneevent_locations") + return global.weighted_mundaneevent_locations; + if("weighted_randomevent_locations") + return global.weighted_randomevent_locations; + if("whitelist") + return global.whitelist; + if("whitelisted_species") + return global.whitelisted_species; + if("wireColours") + return global.wireColours; + if("wizards") + return global.wizards; + if("world_topic_spam_protect_ip") + return global.world_topic_spam_protect_ip; + if("world_topic_spam_protect_time") + return global.world_topic_spam_protect_time; + if("world_uplinks") + return global.world_uplinks; + if("worths") + return global.worths; + if("z_levels") + return global.z_levels; + if("zone_blocked") + return global.zone_blocked; + +/proc/writeglobal(which, newval) + switch(which) + if("ALL_ANTIGENS") + global.ALL_ANTIGENS=newval; + if("ANTAG_FREQS") + global.ANTAG_FREQS=newval; + if("BSACooldown") + global.BSACooldown=newval; + if("BUMP_TELEPORTERS") + global.BUMP_TELEPORTERS=newval; + if("Banlist") + global.Banlist=newval; + if("CENT_FREQS") + global.CENT_FREQS=newval; + if("CMinutes") + global.CMinutes=newval; + if("DEPT_FREQS") + global.DEPT_FREQS=newval; + if("Debug2") + global.Debug2=newval; + if("Failsafe") + global.Failsafe=newval; + if("GLOB") + global.GLOB=newval; + if("Holiday") + global.Holiday=newval; + if("IClog") + global.IClog=newval; + if("LIGHTING_CORNER_DIAGONAL") + global.LIGHTING_CORNER_DIAGONAL=newval; + if("Master") + global.Master=newval; + if("OOClog") + global.OOClog=newval; + if("PDAs") + global.PDAs=newval; + if("SSair") + global.SSair=newval; + if("SSairflow") + global.SSairflow=newval; + if("SSatoms") + global.SSatoms=newval; + if("SSfastprocess") + global.SSfastprocess=newval; + if("SSgarbage") + global.SSgarbage=newval; + if("SSlegacy") + global.SSlegacy=newval; + if("SSmachines") + global.SSmachines=newval; + if("SSmapping") + global.SSmapping=newval; + if("SSmobs") + global.SSmobs=newval; + if("SSobj") + global.SSobj=newval; + if("SSopen_space") + global.SSopen_space=newval; + if("SSprocessing") + global.SSprocessing=newval; + if("SSskybox") + global.SSskybox=newval; + if("SSsun") + global.SSsun=newval; + if("SStimer") + global.SStimer=newval; + if("SSvines") + global.SSvines=newval; + if("SSwireless") + global.SSwireless=newval; + if("Tier1Runes") + global.Tier1Runes=newval; + if("Tier2Runes") + global.Tier2Runes=newval; + if("Tier3Runes") + global.Tier3Runes=newval; + if("Tier4Runes") + global.Tier4Runes=newval; + if("WALLITEMS") + global.WALLITEMS=newval; + if("_all_globals") + global._all_globals=newval; + if("_client_preferences") + global._client_preferences=newval; + if("_client_preferences_by_key") + global._client_preferences_by_key=newval; + if("_client_preferences_by_type") + global._client_preferences_by_type=newval; + if("account_hack_attempted") + global.account_hack_attempted=newval; + if("actor") + global.actor=newval; + if("additional_antag_types") + global.additional_antag_types=newval; + if("admin_datums") + global.admin_datums=newval; + if("admin_pm_repository") + global.admin_pm_repository=newval; + if("admin_ranks") + global.admin_ranks=newval; + if("admin_secrets") + global.admin_secrets=newval; + if("admin_verbs_admin") + global.admin_verbs_admin=newval; + if("admin_verbs_ban") + global.admin_verbs_ban=newval; + if("admin_verbs_debug") + global.admin_verbs_debug=newval; + if("admin_verbs_default") + global.admin_verbs_default=newval; + if("admin_verbs_fun") + global.admin_verbs_fun=newval; + if("admin_verbs_hideable") + global.admin_verbs_hideable=newval; + if("admin_verbs_mentor") + global.admin_verbs_mentor=newval; + if("admin_verbs_mod") + global.admin_verbs_mod=newval; + if("admin_verbs_paranoid_debug") + global.admin_verbs_paranoid_debug=newval; + if("admin_verbs_permissions") + global.admin_verbs_permissions=newval; + if("admin_verbs_possess") + global.admin_verbs_possess=newval; + if("admin_verbs_rejuv") + global.admin_verbs_rejuv=newval; + if("admin_verbs_server") + global.admin_verbs_server=newval; + if("admin_verbs_sounds") + global.admin_verbs_sounds=newval; + if("admin_verbs_spawn") + global.admin_verbs_spawn=newval; + if("adminhelp_ignored_words") + global.adminhelp_ignored_words=newval; + if("adminlog") + global.adminlog=newval; + if("ai_list") + global.ai_list=newval; + if("ai_status_emotions") + global.ai_status_emotions=newval; + if("ai_verbs_default") + global.ai_verbs_default=newval; + if("air_alarm_topic") + global.air_alarm_topic=newval; + if("air_blocked") + global.air_blocked=newval; + if("air_processing_killed") + global.air_processing_killed=newval; + if("alarm_manager") + global.alarm_manager=newval; + if("alien_whitelist") + global.alien_whitelist=newval; + if("allCasters") + global.allCasters=newval; + if("allConsoles") + global.allConsoles=newval; + if("all_antag_spawnpoints_") + global.all_antag_spawnpoints_=newval; + if("all_antag_types_") + global.all_antag_types_=newval; + if("all_grabobjects") + global.all_grabobjects=newval; + if("all_grabstates") + global.all_grabstates=newval; + if("all_languages") + global.all_languages=newval; + if("all_money_accounts") + global.all_money_accounts=newval; + if("all_objectives") + global.all_objectives=newval; + if("all_robolimbs") + global.all_robolimbs=newval; + if("all_species") + global.all_species=newval; + if("all_ui_styles") + global.all_ui_styles=newval; + if("all_unit_tests_passed") + global.all_unit_tests_passed=newval; + if("all_virtual_listeners") + global.all_virtual_listeners=newval; + if("announced_news_types") + global.announced_news_types=newval; + if("antag_add_finished") + global.antag_add_finished=newval; + if("antag_names_to_ids_") + global.antag_names_to_ids_=newval; + if("appearance_manager") + global.appearance_manager=newval; + if("area_repository") + global.area_repository=newval; + if("artefact_feedback") + global.artefact_feedback=newval; + if("ascii_esc") + global.ascii_esc=newval; + if("ascii_green") + global.ascii_green=newval; + if("ascii_red") + global.ascii_red=newval; + if("ascii_reset") + global.ascii_reset=newval; + if("ascii_yellow") + global.ascii_yellow=newval; + if("asset_cache") + global.asset_cache=newval; + if("asset_datums") + global.asset_datums=newval; + if("assigned") + global.assigned=newval; + if("assigned_blocks") + global.assigned_blocks=newval; + if("atmosphere_alarm") + global.atmosphere_alarm=newval; + if("attack_log_repository") + global.attack_log_repository=newval; + if("autolathe_categories") + global.autolathe_categories=newval; + if("autolathe_recipes") + global.autolathe_recipes=newval; + if("base_miss_chance") + global.base_miss_chance=newval; + if("basic_robolimb") + global.basic_robolimb=newval; + if("blackbox") + global.blackbox=newval; + if("blocked") + global.blocked=newval; + if("bomb_set") + global.bomb_set=newval; + if("borers") + global.borers=newval; + if("cable_list") + global.cable_list=newval; + if("cached_icons") + global.cached_icons=newval; + if("cached_space") + global.cached_space=newval; + if("camera_alarm") + global.camera_alarm=newval; + if("camera_range_display_status") + global.camera_range_display_status=newval; + if("camera_repository") + global.camera_repository=newval; + if("cameranet") + global.cameranet=newval; + if("can_call_ert") + global.can_call_ert=newval; + if("captain_announcement") + global.captain_announcement=newval; + if("cargo_supply_pack_root") + global.cargo_supply_pack_root=newval; + if("cargo_supply_packs") + global.cargo_supply_packs=newval; + if("changelog_hash") + global.changelog_hash=newval; + if("channel_to_radio_key") + global.channel_to_radio_key=newval; + if("chargen_robolimbs") + global.chargen_robolimbs=newval; + if("checked_for_inactives") + global.checked_for_inactives=newval; + if("chemical_reaction_logs") + global.chemical_reaction_logs=newval; + if("chemical_reactions_list") + global.chemical_reactions_list=newval; + if("chemical_produce_list") + global.chemical_produce_list=newval; + if("chicken_count") + global.chicken_count=newval; + if("church_name") + global.church_name=newval; + if("client_preference_stats_") + global.client_preference_stats_=newval; + if("client_repository") + global.client_repository=newval; + if("combatlog") + global.combatlog=newval; + if("comm_message_listeners") + global.comm_message_listeners=newval; + if("command_announcement") + global.command_announcement=newval; + if("command_name") + global.command_name=newval; + if("commandos") + global.commandos=newval; + if("common_tools") + global.common_tools=newval; + if("config") + global.config=newval; + if("contamination_overlay") + global.contamination_overlay=newval; + if("controller_iteration") + global.controller_iteration=newval; + if("create_mob_html") + global.create_mob_html=newval; + if("create_object_html") + global.create_object_html=newval; + if("create_turf_html") + global.create_turf_html=newval; + if("created") + global.created=newval; + if("crew_repository") + global.crew_repository=newval; + if("csrfz_check") + global.csrfz_check=newval; + if("cult") + global.cult=newval; + if("currently_running_tests") + global.currently_running_tests=newval; + if("custom_event_msg") + global.custom_event_msg=newval; + if("custom_items") + global.custom_items=newval; + if("damage_icon_parts") + global.damage_icon_parts=newval; + if("dbcon") + global.dbcon=newval; + if("dbcon_old") + global.dbcon_old=newval; + if("deathsquad") + global.deathsquad=newval; + if("debug_verbs") + global.debug_verbs=newval; + if("decls_repository") + global.decls_repository=newval; + if("default_material_composition") + global.default_material_composition=newval; + if("default_mobloc") + global.default_mobloc=newval; + if("default_onmob_icons") + global.default_onmob_icons=newval; + if("default_pai_software") + global.default_pai_software=newval; + if("defer_powernet_rebuild") + global.defer_powernet_rebuild=newval; + if("department_accounts") + global.department_accounts=newval; + if("department_radio_keys") + global.department_radio_keys=newval; + if("description_icons") + global.description_icons=newval; + if("diary") + global.diary=newval; + if("dna_activity_bounds") + global.dna_activity_bounds=newval; + if("dna_genes") + global.dna_genes=newval; + if("doppler_arrays") + global.doppler_arrays=newval; + if("dreams") + global.dreams=newval; + if("dummy_lighting_corner") + global.dummy_lighting_corner=newval; + if("economic_species_modifier") + global.economic_species_modifier=newval; + if("empty_playable_ai_cores") + global.empty_playable_ai_cores=newval; + if("endgame_exits") + global.endgame_exits=newval; + if("endgame_safespawns") + global.endgame_safespawns=newval; + if("ert") + global.ert=newval; + if("ert_base_chance") + global.ert_base_chance=newval; + if("escape_pods") + global.escape_pods=newval; + if("escape_pods_by_name") + global.escape_pods_by_name=newval; + if("evacuation_controller") + global.evacuation_controller=newval; + if("event_last_fired") + global.event_last_fired=newval; + if("eventchance") + global.eventchance=newval; + if("exclude_jobs") + global.exclude_jobs=newval; + if("explosion_in_progress") + global.explosion_in_progress=newval; + if("explosion_turfs") + global.explosion_turfs=newval; + if("failed_db_connections") + global.failed_db_connections=newval; + if("failed_old_db_connections") + global.failed_old_db_connections=newval; + if("failed_unit_tests") + global.failed_unit_tests=newval; + if("file_uid") + global.file_uid=newval; + if("fileaccess_timer") + global.fileaccess_timer=newval; + if("finds_as_strings") + global.finds_as_strings=newval; + if("fire_alarm") + global.fire_alarm=newval; + if("flesh_hud_colours") + global.flesh_hud_colours=newval; + if("floorIsLava") + global.floorIsLava=newval; + if("floor_decals") + global.floor_decals=newval; + if("floor_light_cache") + global.floor_light_cache=newval; + if("flooring_cache") + global.flooring_cache=newval; + if("flooring_types") + global.flooring_types=newval; + if("fluidtrack_cache") + global.fluidtrack_cache=newval; + if("follow_repository") + global.follow_repository=newval; + if("forced_ambiance_list") + global.forced_ambiance_list=newval; + if("fruit_icon_cache") + global.fruit_icon_cache=newval; + if("fuel_injectors") + global.fuel_injectors=newval; + if("fusion_cores") + global.fusion_cores=newval; + if("fusion_reactions") + global.fusion_reactions=newval; + if("game_id") + global.game_id=newval; + if("game_version") + global.game_version=newval; + if("game_year") + global.game_year=newval; + if("gamemode_cache") + global.gamemode_cache=newval; + if("gas_data") + global.gas_data=newval; + if("gender_datums") + global.gender_datums=newval; + if("ghost_darkness_images") + global.ghost_darkness_images=newval; + if("ghost_sightless_images") + global.ghost_sightless_images=newval; + if("ghost_traps") + global.ghost_traps=newval; + if("global_message_listener") + global.global_message_listener=newval; + if("global_vars_") + global.global_vars_=newval; + if("gravity_is_on") + global.gravity_is_on=newval; + if("gyrotrons") + global.gyrotrons=newval; + if("gzn_check") + global.gzn_check=newval; + if("hadevent") + global.hadevent=newval; + if("hazard_overlays") + global.hazard_overlays=newval; + if("hivemind_bank") + global.hivemind_bank=newval; + if("holder_mob_icon_cache") + global.holder_mob_icon_cache=newval; + if("host") + global.host=newval; + if("href_logfile") + global.href_logfile=newval; + if("human_icon_cache") + global.human_icon_cache=newval; + if("id_card_states") + global.id_card_states=newval; + if("image_repository") + global.image_repository=newval; + if("inactive_keys") + global.inactive_keys=newval; + if("init") + global.init=newval; + if("initialization_stage") + global.initialization_stage=newval; + if("integrated_circuit_blacklist") + global.integrated_circuit_blacklist=newval; + if("intents") + global.intents=newval; + if("intercom_range_display_status") + global.intercom_range_display_status=newval; + if("invalid_zone") + global.invalid_zone=newval; + if("jobMax") + global.jobMax=newval; + if("job_master") + global.job_master=newval; + if("jobban_keylist") + global.jobban_keylist=newval; + if("jobban_runonce") + global.jobban_runonce=newval; + if("joblist") + global.joblist=newval; + if("join_motd") + global.join_motd=newval; + if("landmarks_list") + global.landmarks_list=newval; + if("language_keys") + global.language_keys=newval; + if("last_chew") + global.last_chew=newval; + if("last_message_id") + global.last_message_id=newval; + if("last_round_duration") + global.last_round_duration=newval; + if("last_tick_duration") + global.last_tick_duration=newval; + if("license_to_url") + global.license_to_url=newval; + if("light_overlay_cache") + global.light_overlay_cache=newval; + if("lighting_overlays_initialised") + global.lighting_overlays_initialised=newval; + if("lighting_update_corners") + global.lighting_update_corners=newval; + if("lighting_update_corners_old") + global.lighting_update_corners_old=newval; + if("lighting_update_lights") + global.lighting_update_lights=newval; + if("lighting_update_lights_old") + global.lighting_update_lights_old=newval; + if("lighting_update_overlays") + global.lighting_update_overlays=newval; + if("lighting_update_overlays_old") + global.lighting_update_overlays_old=newval; + if("limb_icon_cache") + global.limb_icon_cache=newval; + if("lobby_image") + global.lobby_image=newval; + if("log_end") + global.log_end=newval; + if("loyalists") + global.loyalists=newval; + if("lunchables_drink_reagents_") + global.lunchables_drink_reagents_=newval; + if("lunchables_drinks_") + global.lunchables_drinks_=newval; + if("lunchables_ethanol_reagents_") + global.lunchables_ethanol_reagents_=newval; + if("lunchables_lunches_") + global.lunchables_lunches_=newval; + if("lunchables_snacks_") + global.lunchables_snacks_=newval; + if("magazine_icondata_keys") + global.magazine_icondata_keys=newval; + if("magazine_icondata_states") + global.magazine_icondata_states=newval; + if("maint_all_access") + global.maint_all_access=newval; + if("malf") + global.malf=newval; + if("mannequins_") + global.mannequins_=newval; + if("map_count") + global.map_count=newval; + if("map_sectors") + global.map_sectors=newval; + if("maploader") + global.maploader=newval; + if("mark") + global.mark=newval; + if("master_controller") + global.master_controller=newval; + if("master_mode") + global.master_mode=newval; + if("maze_cell_count") + global.maze_cell_count=newval; + if("mechas_list") + global.mechas_list=newval; + if("mechtoys") + global.mechtoys=newval; + if("mercs") + global.mercs=newval; + if("merged") + global.merged=newval; + if("message_delay") + global.message_delay=newval; + if("message_servers") + global.message_servers=newval; + if("meteors_armageddon") + global.meteors_armageddon=newval; + if("meteors_cataclysm") + global.meteors_cataclysm=newval; + if("meteors_catastrophic") + global.meteors_catastrophic=newval; + if("meteors_dust") + global.meteors_dust=newval; + if("meteors_major") + global.meteors_major=newval; + if("meteors_minor") + global.meteors_minor=newval; + if("meteors_moderate") + global.meteors_moderate=newval; + if("meteors_normal") + global.meteors_normal=newval; + if("meteors_threatening") + global.meteors_threatening=newval; + if("mil_branches") + global.mil_branches=newval; + if("mining_floors") + global.mining_floors=newval; + if("mining_walls") + global.mining_walls=newval; + if("minor_air_alarms") + global.minor_air_alarms=newval; + if("minor_announcement") + global.minor_announcement=newval; + if("mob_hat_cache") + global.mob_hat_cache=newval; + if("mob_repository") + global.mob_repository=newval; + if("motion_alarm") + global.motion_alarm=newval; + if("moving_levels") + global.moving_levels=newval; + if("multi_point_spawns") + global.multi_point_spawns=newval; + if("name_to_material") + global.name_to_material=newval; + if("narsie_behaviour") + global.narsie_behaviour=newval; + if("narsie_cometh") + global.narsie_cometh=newval; + if("narsie_list") + global.narsie_list=newval; + if("navbeacons") + global.navbeacons=newval; + if("news_network") + global.news_network=newval; + if("newscaster_standard_feeds") + global.newscaster_standard_feeds=newval; + if("next_account_number") + global.next_account_number=newval; + if("next_duration_update") + global.next_duration_update=newval; + if("next_station_date_change") + global.next_station_date_change=newval; + if("not_incapacitated_turf_state") + global.not_incapacitated_turf_state=newval; + if("ntnet_card_uid") + global.ntnet_card_uid=newval; + if("ntnet_global") + global.ntnet_global=newval; + if("ntnrc_uid") + global.ntnrc_uid=newval; + if("nttransfer_uid") + global.nttransfer_uid=newval; + if("nuke_disks") + global.nuke_disks=newval; + if("num_financial_terminals") + global.num_financial_terminals=newval; + if("ore_data") + global.ore_data=newval; + if("ores_by_type") + global.ores_by_type=newval; + if("organ_cache") + global.organ_cache=newval; + if("organ_rel_size") + global.organ_rel_size=newval; + if("outfits_decls_") + global.outfits_decls_=newval; + if("outfits_decls_by_type_") + global.outfits_decls_by_type_=newval; + if("outfits_decls_root_") + global.outfits_decls_root_=newval; + if("overmap_event_handler") + global.overmap_event_handler=newval; + if("paiController") + global.paiController=newval; + if("pai_emotions") + global.pai_emotions=newval; + if("pai_software_by_key") + global.pai_software_by_key=newval; + if("paramslist_cache") + global.paramslist_cache=newval; + if("photo_count") + global.photo_count=newval; + if("pipe_colors") + global.pipe_colors=newval; + if("pipe_processing_killed") + global.pipe_processing_killed=newval; + if("plant_controller") + global.plant_controller=newval; + if("plant_seed_sprites") + global.plant_seed_sprites=newval; + if("playable_species") + global.playable_species=newval; + if("point_source_descriptions") + global.point_source_descriptions=newval; + if("possible_cable_coil_colours") + global.possible_cable_coil_colours=newval; + if("possible_changeling_IDs") + global.possible_changeling_IDs=newval; + if("poster_designs") + global.poster_designs=newval; + if("power_alarm") + global.power_alarm=newval; + if("powerinstances") + global.powerinstances=newval; + if("powers") + global.powers=newval; + if("preferences_datums") + global.preferences_datums=newval; + if("priority_air_alarms") + global.priority_air_alarms=newval; + if("priority_announcement") + global.priority_announcement=newval; + if("priv_all_access") + global.priv_all_access=newval; + if("priv_all_access_datums") + global.priv_all_access_datums=newval; + if("priv_all_access_datums_id") + global.priv_all_access_datums_id=newval; + if("priv_all_access_datums_region") + global.priv_all_access_datums_region=newval; + if("priv_centcom_access") + global.priv_centcom_access=newval; + if("priv_region_access") + global.priv_region_access=newval; + if("priv_station_access") + global.priv_station_access=newval; + if("priv_syndicate_access") + global.priv_syndicate_access=newval; + if("processScheduler") + global.processScheduler=newval; + if("processing_turfs") + global.processing_turfs=newval; + if("protected_objects") + global.protected_objects=newval; + if("rad_collectors") + global.rad_collectors=newval; + if("radiation_repository") + global.radiation_repository=newval; + if("radio_controller") + global.radio_controller=newval; + if("radiochannels") + global.radiochannels=newval; + if("raiders") + global.raiders=newval; + if("random_junk_") + global.random_junk_=newval; + if("random_maps") + global.random_maps=newval; + if("random_useful_") + global.random_useful_=newval; + if("recentmessages") + global.recentmessages=newval; + if("registered_macros_by_ckey_") + global.registered_macros_by_ckey_=newval; + if("religion_name") + global.religion_name=newval; + if("renegades") + global.renegades=newval; + if("req_console_assistance") + global.req_console_assistance=newval; + if("req_console_information") + global.req_console_information=newval; + if("req_console_supplies") + global.req_console_supplies=newval; + if("responsive_carriers") + global.responsive_carriers=newval; + if("restricted_camera_networks") + global.restricted_camera_networks=newval; + if("revdata") + global.revdata=newval; + if("revs") + global.revs=newval; + if("robot_custom_icons") + global.robot_custom_icons=newval; + if("robot_hud_colours") + global.robot_hud_colours=newval; + if("robot_inventory") + global.robot_inventory=newval; + if("robot_modules") + global.robot_modules=newval; + if("round_progressing") + global.round_progressing=newval; + if("round_start_time") + global.round_start_time=newval; + if("roundstart_hour") + global.roundstart_hour=newval; + if("rune_list") + global.rune_list=newval; + if("runtime_diary") + global.runtime_diary=newval; + if("same_wires") + global.same_wires=newval; + if("secondary_mode") + global.secondary_mode=newval; + if("secret_force_mode") + global.secret_force_mode=newval; + if("send_emergency_team") + global.send_emergency_team=newval; + if("sent_spiders_to_station") + global.sent_spiders_to_station=newval; + if("server_name") + global.server_name=newval; + if("severity_to_string") + global.severity_to_string=newval; + if("ship_engines") + global.ship_engines=newval; + if("shuttle_controller") + global.shuttle_controller=newval; + if("side_effects") + global.side_effects=newval; + if("skin_styles_female_list") + global.skin_styles_female_list=newval; + if("skipped_unit_tests") + global.skipped_unit_tests=newval; + if("slot_equipment_priority") + global.slot_equipment_priority=newval; + if("slot_flags_enumeration") + global.slot_flags_enumeration=newval; + if("solar_gen_rate") + global.solar_gen_rate=newval; + if("solars_list") + global.solars_list=newval; + if("sortInstance") + global.sortInstance=newval; + if("sound_player") + global.sound_player=newval; + if("sounds_cache") + global.sounds_cache=newval; + if("spacevines_spawned") + global.spacevines_spawned=newval; + if("sparring_attack_cache") + global.sparring_attack_cache=newval; + if("spells") + global.spells=newval; + if("splatter_cache") + global.splatter_cache=newval; + if("sqladdress") + global.sqladdress=newval; + if("sqldb") + global.sqldb=newval; + if("sqlfdbkdb") + global.sqlfdbkdb=newval; + if("sqlfdbklogin") + global.sqlfdbklogin=newval; + if("sqlfdbkpass") + global.sqlfdbkpass=newval; + if("sqllogging") + global.sqllogging=newval; + if("sqllogin") + global.sqllogin=newval; + if("sqlpass") + global.sqlpass=newval; + if("sqlport") + global.sqlport=newval; + if("station_account") + global.station_account=newval; + if("station_date") + global.station_date=newval; + if("stool_cache") + global.stool_cache=newval; + if("stored_shock_by_ref") + global.stored_shock_by_ref=newval; + if("string_part_flags") + global.string_part_flags=newval; + if("string_slot_flags") + global.string_slot_flags=newval; + if("supply_controller") + global.supply_controller=newval; + if("supply_drop") + global.supply_drop=newval; + if("supply_methods_") + global.supply_methods_=newval; + if("surgery_steps") + global.surgery_steps=newval; + if("swapmaps_byname") + global.swapmaps_byname=newval; + if("swapmaps_compiled_maxx") + global.swapmaps_compiled_maxx=newval; + if("swapmaps_compiled_maxy") + global.swapmaps_compiled_maxy=newval; + if("swapmaps_compiled_maxz") + global.swapmaps_compiled_maxz=newval; + if("swapmaps_iconcache") + global.swapmaps_iconcache=newval; + if("swapmaps_initialized") + global.swapmaps_initialized=newval; + if("swapmaps_loaded") + global.swapmaps_loaded=newval; + if("swapmaps_mode") + global.swapmaps_mode=newval; + if("syndicate_access") + global.syndicate_access=newval; + if("syndicate_code_phrase") + global.syndicate_code_phrase=newval; + if("syndicate_code_response") + global.syndicate_code_response=newval; + if("syndicate_name") + global.syndicate_name=newval; + if("tail_icon_cache") + global.tail_icon_cache=newval; + if("tank_gauge_cache") + global.tank_gauge_cache=newval; + if("tape_roll_applications") + global.tape_roll_applications=newval; + if("telecomms_list") + global.telecomms_list=newval; + if("tertiary_mode") + global.tertiary_mode=newval; + if("text_tag_icons") + global.text_tag_icons=newval; + if("tg_admin_state") + global.tg_admin_state=newval; + if("tg_always_state") + global.tg_always_state=newval; + if("tg_conscious_state") + global.tg_conscious_state=newval; + if("tg_contained_state") + global.tg_contained_state=newval; + if("tg_deep_inventory_state") + global.tg_deep_inventory_state=newval; + if("tg_default_state") + global.tg_default_state=newval; + if("tg_hands_state") + global.tg_hands_state=newval; + if("tg_human_adjacent_state") + global.tg_human_adjacent_state=newval; + if("tg_inventory_state") + global.tg_inventory_state=newval; + if("tg_not_contained_state") + global.tg_not_contained_state=newval; + if("tg_not_incapacitated_state") + global.tg_not_incapacitated_state=newval; + if("tg_physical_state") + global.tg_physical_state=newval; + if("tg_self_state") + global.tg_self_state=newval; + if("tg_z_state") + global.tg_z_state=newval; + if("tgui_process") + global.tgui_process=newval; + if("ticker") + global.ticker=newval; + if("tickerProcess") + global.tickerProcess=newval; + if("ticket_panels") + global.ticket_panels=newval; + if("tickets") + global.tickets=newval; + if("total_lighting_corners") + global.total_lighting_corners=newval; + if("total_lighting_overlays") + global.total_lighting_overlays=newval; + if("total_lighting_sources") + global.total_lighting_sources=newval; + if("total_unit_tests") + global.total_unit_tests=newval; + if("traitors") + global.traitors=newval; + if("transfer_controller") + global.transfer_controller=newval; + if("turbolift_controller") + global.turbolift_controller=newval; + if("turbolifts") + global.turbolifts=newval; + if("turret_icons") + global.turret_icons=newval; + if("uniqueness_repository") + global.uniqueness_repository=newval; + if("universe_has_ended") + global.universe_has_ended=newval; + if("uplink") + global.uplink=newval; + if("uplink_purchase_repository") + global.uplink_purchase_repository=newval; + if("uplink_random_selections_") + global.uplink_random_selections_=newval; + if("valid_bloodtypes") + global.valid_bloodtypes=newval; + if("vendor_account") + global.vendor_account=newval; + if("ventcrawl_machinery") + global.ventcrawl_machinery=newval; + if("view_variables_dont_expand") + global.view_variables_dont_expand=newval; + if("view_variables_no_assoc") + global.view_variables_no_assoc=newval; + if("virusDB") + global.virusDB=newval; + if("visual_nets") + global.visual_nets=newval; + if("vote") + global.vote=newval; + if("vsc") + global.vsc=newval; + if("wax_recipes") + global.weighted_mundaneevent_locations=newval; + if("weighted_randomevent_locations") + global.weighted_randomevent_locations=newval; + if("whitelist") + global.whitelist=newval; + if("whitelisted_species") + global.whitelisted_species=newval; + if("wireColours") + global.wireColours=newval; + if("wizards") + global.wizards=newval; + if("world_topic_spam_protect_ip") + global.world_topic_spam_protect_ip=newval; + if("world_topic_spam_protect_time") + global.world_topic_spam_protect_time=newval; + if("world_uplinks") + global.world_uplinks=newval; + if("worths") + global.worths=newval; + if("xenomorphs") + global.xenomorphs=newval; + if("z_levels") + global.z_levels=newval; + if("zone_blocked") + global.zone_blocked=newval; + +/var/list/_all_globals=list( + "ALL_ANTIGENS", + "ANTAG_FREQS", + "BSACooldown", + "BUMP_TELEPORTERS", + "Banlist", + "CENT_FREQS", + "CMinutes", + "DEPT_FREQS", + "Debug2", + "Failsafe", + "GLOB", + "Holiday", + "IClog", + "LIGHTING_CORNER_DIAGONAL", + "Master", + "OOClog", + "PDAs", + "SKILLS", + "SSair", + "SSairflow", + "SSatoms", + "SSfastprocess", + "SSgarbage", + "SSlegacy", + "SSmachines", + "SSmapping", + "SSmobs", + "SSobj", + "SSopen_space", + "SSprocessing", + "SSskybox", + "SSsun", + "SStimer", + "SSvines", + "SSwireless", + "Tier1Runes", + "Tier2Runes", + "Tier3Runes", + "Tier4Runes", + "WALLITEMS", + "_all_globals", + "_client_preferences", + "_client_preferences_by_key", + "_client_preferences_by_type", + "account_hack_attempted", + "actor", + "additional_antag_types", + "admin_datums", + "admin_pm_repository", + "admin_ranks", + "admin_secrets", + "admin_verbs_admin", + "admin_verbs_ban", + "admin_verbs_debug", + "admin_verbs_default", + "admin_verbs_fun", + "admin_verbs_hideable", + "admin_verbs_mentor", + "admin_verbs_mod", + "admin_verbs_paranoid_debug", + "admin_verbs_permissions", + "admin_verbs_possess", + "admin_verbs_rejuv", + "admin_verbs_server", + "admin_verbs_sounds", + "admin_verbs_spawn", + "adminhelp_ignored_words", + "adminlog", + "ai_list", + "ai_status_emotions", + "ai_verbs_default", + "air_alarm_topic", + "air_blocked", + "air_processing_killed", + "alarm_manager", + "alien_whitelist", + "allCasters", + "allConsoles", + "all_antag_spawnpoints_", + "all_antag_types_", + "all_grabobjects", + "all_grabstates", + "all_languages", + "all_money_accounts", + "all_objectives", + "all_robolimbs", + "all_species", + "all_ui_styles", + "all_unit_tests_passed", + "all_virtual_listeners", + "announced_news_types", + "antag_add_finished", + "antag_names_to_ids_", + "appearance_manager", + "area_repository", + "artefact_feedback", + "ascii_esc", + "ascii_green", + "ascii_red", + "ascii_reset", + "ascii_yellow", + "asset_cache", + "asset_datums", + "assigned", + "assigned_blocks", + "atmosphere_alarm", + "attack_log_repository", + "autolathe_categories", + "autolathe_recipes", + "base_miss_chance", + "basic_robolimb", + "blackbox", + "blocked", + "bomb_set", + "borers", + "cable_list", + "cached_icons", + "cached_space", + "camera_alarm", + "camera_range_display_status", + "camera_repository", + "cameranet", + "can_call_ert", + "captain_announcement", + "cargo_supply_pack_root", + "cargo_supply_packs", + "changelog_hash", + "channel_to_radio_key", + "chargen_robolimbs", + "checked_for_inactives", + "chemical_reaction_logs", + "chemical_reactions_list", + "chemical_produce_list", + "chicken_count", + "church_name", + "client_preference_stats_", + "client_repository", + "combatlog", + "comm_message_listeners", + "command_announcement", + "command_name", + "commandos", + "common_tools", + "config", + "contamination_overlay", + "controller_iteration", + "create_mob_html", + "create_object_html", + "create_turf_html", + "created", + "crew_repository", + "csrfz_check", + "cult", + "currently_running_tests", + "custom_event_msg", + "custom_items", + "damage_icon_parts", + "dbcon", + "dbcon_old", + "deathsquad", + "debug_verbs", + "decls_repository", + "default_material_composition", + "default_mobloc", + "default_onmob_icons", + "default_pai_software", + "defer_powernet_rebuild", + "deity", + "delta_index", + "department_accounts", + "department_radio_keys", + "description_icons", + "diary", + "dna_activity_bounds", + "dna_genes", + "doppler_arrays", + "dreams", + "dummy_lighting_corner", + "economic_species_modifier", + "empty_playable_ai_cores", + "endgame_exits", + "endgame_safespawns", + "ert", + "ert_base_chance", + "escape_pods", + "escape_pods_by_name", + "evacuation_controller", + "event_last_fired", + "eventchance", + "exclude_jobs", + "explosion_in_progress", + "explosion_turfs", + "failed_db_connections", + "failed_old_db_connections", + "failed_unit_tests", + "file_uid", + "fileaccess_timer", + "finds_as_strings", + "fire_alarm", + "flesh_hud_colours", + "floorIsLava", + "floor_decals", + "floor_light_cache", + "flooring_cache", + "flooring_types", + "fluidtrack_cache", + "follow_repository", + "forced_ambiance_list", + "fruit_icon_cache", + "fuel_injectors", + "fusion_cores", + "fusion_reactions", + "game_id", + "game_version", + "game_year", + "gamemode_cache", + "gas_data", + "gear_datums", + "gear_tweak_free_color_choice_", + "gender_datums", + "ghost_darkness_images", + "ghost_sightless_images", + "ghost_traps", + "global_message_listener", + "global_vars_", + "godcult", + "gravity_is_on", + "gyrotrons", + "gzn_check", + "hadevent", + "hazard_overlays", + "hidden_skill_types", + "hivemind_bank", + "holder_mob_icon_cache", + "host", + "href_logfile", + "human_icon_cache", + "id_card_states", + "image_repository", + "inactive_keys", + "init", + "initialization_stage", + "integrated_circuit_blacklist", + "intents", + "intercom_range_display_status", + "invalid_zone", + "jobMax", + "job_master", + "jobban_keylist", + "jobban_runonce", + "joblist", + "join_motd", + "landmarks_list", + "language_keys", + "last_chew", + "last_message_id", + "last_round_duration", + "last_tick_duration", + "license_to_url", + "light_overlay_cache", + "lighting_overlays_initialised", + "lighting_update_corners", + "lighting_update_corners_old", + "lighting_update_lights", + "lighting_update_lights_old", + "lighting_update_overlays", + "lighting_update_overlays_old", + "limb_icon_cache", + "loadout_categories", + "lobby_image", + "log_end", + "loyalists", + "lunchables_drink_reagents_", + "lunchables_drinks_", + "lunchables_ethanol_reagents_", + "lunchables_lunches_", + "lunchables_snacks_", + "magazine_icondata_keys", + "magazine_icondata_states", + "maint_all_access", + "malf", + "mannequins_", + "map_count", + "map_sectors", + "maploader", + "mark", + "master_controller", + "master_mode", + "matchmaker", + "maze_cell_count", + "mechas_list", + "mechtoys", + "mercs", + "merged", + "message_delay", + "message_servers", + "meteors_armageddon", + "meteors_cataclysm", + "meteors_catastrophic", + "meteors_dust", + "meteors_major", + "meteors_minor", + "meteors_moderate", + "meteors_normal", + "meteors_threatening", + "mil_branches", + "mining_floors", + "mining_walls", + "minor_air_alarms", + "minor_announcement", + "mob_hat_cache", + "mob_repository", + "motion_alarm", + "moving_levels", + "multi_point_spawns", + "name_to_material", + "narsie_behaviour", + "narsie_cometh", + "narsie_list", + "navbeacons", + "news_network", + "newscaster_standard_feeds", + "next_account_number", + "next_duration_update", + "next_station_date_change", + "not_incapacitated_turf_state", + "ntnet_card_uid", + "ntnet_global", + "ntnrc_uid", + "nttransfer_uid", + "nuke_disks", + "num_financial_terminals", + "ore_data", + "ores_by_type", + "organ_cache", + "organ_rel_size", + "outfits_decls_", + "outfits_decls_by_type_", + "outfits_decls_root_", + "overmap_event_handler", + "paiController", + "pai_emotions", + "pai_software_by_key", + "paramslist_cache", + "photo_count", + "pipe_colors", + "pipe_processing_killed", + "plant_controller", + "plant_seed_sprites", + "playable_species", + "point_source_descriptions", + "possible_cable_coil_colours", + "possible_changeling_IDs", + "poster_designs", + "power_alarm", + "powerinstances", + "powers", + "preferences_datums", + "priority_air_alarms", + "priority_announcement", + "priv_all_access", + "priv_all_access_datums", + "priv_all_access_datums_id", + "priv_all_access_datums_region", + "priv_centcom_access", + "priv_region_access", + "priv_station_access", + "priv_syndicate_access", + "processScheduler", + "processing_turfs", + "prometheans", + "protected_objects", + "rad_collectors", + "radiation_repository", + "radio_controller", + "radiochannels", + "raiders", + "random_junk_", + "random_maps", + "random_useful_", + "recentmessages", + "registered_macros_by_ckey_", + "religion_name", + "renegades", + "req_console_assistance", + "req_console_information", + "req_console_supplies", + "responsive_carriers", + "restricted_camera_networks", + "revdata", + "revs", + "robot_custom_icons", + "robot_hud_colours", + "robot_inventory", + "robot_modules", + "round_progressing", + "round_start_time", + "roundstart_hour", + "rune_list", + "runtime_diary", + "same_wires", + "secondary_mode", + "secret_force_mode", + "send_emergency_team", + "sent_spiders_to_station", + "server_name", + "severity_to_string", + "ship_engines", + "shuttle_controller", + "side_effects", + "skin_styles_female_list", + "skipped_unit_tests", + "slot_equipment_priority", + "slot_flags_enumeration", + "solar_gen_rate", + "solars_list", + "sortInstance", + "sound_player", + "sounds_cache", + "spacevines_spawned", + "sparring_attack_cache", + "spells", + "splatter_cache", + "sqladdress", + "sqldb", + "sqlfdbkdb", + "sqlfdbklogin", + "sqlfdbkpass", + "sqllogging", + "sqllogin", + "sqlpass", + "sqlport", + "station_account", + "station_date", + "stool_cache", + "stored_shock_by_ref", + "string_part_flags", + "string_slot_flags", + "supply_controller", + "supply_drop", + "supply_methods_", + "surgery_steps", + "swapmaps_byname", + "swapmaps_compiled_maxx", + "swapmaps_compiled_maxy", + "swapmaps_compiled_maxz", + "swapmaps_iconcache", + "swapmaps_initialized", + "swapmaps_loaded", + "swapmaps_mode", + "syndicate_access", + "syndicate_code_phrase", + "syndicate_code_response", + "syndicate_name", + "tail_icon_cache", + "tank_gauge_cache", + "tape_roll_applications", + "telecomms_list", + "tertiary_mode", + "text_tag_icons", + "tg_admin_state", + "tg_always_state", + "tg_conscious_state", + "tg_contained_state", + "tg_deep_inventory_state", + "tg_default_state", + "tg_hands_state", + "tg_human_adjacent_state", + "tg_inventory_state", + "tg_not_contained_state", + "tg_not_incapacitated_state", + "tg_physical_state", + "tg_self_state", + "tg_z_state", + "tgui_process", + "ticker", + "tickerProcess", + "ticket_panels", + "tickets", + "total_lighting_corners", + "total_lighting_overlays", + "total_lighting_sources", + "total_unit_tests", + "traitors", + "transfer_controller", + "turbolift_controller", + "turbolifts", + "turret_icons", + "uniqueness_repository", + "universe_has_ended", + "uplink", + "uplink_purchase_repository", + "uplink_random_selections_", + "valid_bloodtypes", + "vendor_account", + "ventcrawl_machinery", + "view_variables_dont_expand", + "view_variables_no_assoc", + "virusDB", + "visual_nets", + "vote", + "vsc", + "wax_recipes", + "weighted_mundaneevent_locations", + "weighted_randomevent_locations", + "whitelist", + "whitelisted_species", + "wireColours", + "wizards", + "world_topic_spam_protect_ip", + "world_topic_spam_protect_time", + "world_uplinks", + "worths", + "wrapped_species_by_ref", + "xenomorphs", + "z_levels", + "zone_blocked") diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm new file mode 100644 index 00000000..71142c1a --- /dev/null +++ b/code/_helpers/global_lists.dm @@ -0,0 +1,250 @@ +//Since it didn't really belong in any other category, I'm putting this here +//This is for procs to replace all the goddamn 'in world's that are chilling around the code + +var/global/list/cable_list = list() //Index for all cables, so that powernets don't have to look through the entire world all the time +var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions +var/global/list/chemical_produce_list //list of all /datum/chemical_reaction datums, by produce. used for recipe lookup +var/global/list/landmarks_list = list() //list of all landmarks created +var/global/list/surgery_steps = list() //list of all surgery steps |BS12 +var/global/list/side_effects = list() //list of all medical sideeffects types by thier names |BS12 +var/global/list/mechas_list = list() //list of all mechs. Used by hostile mobs target tracking. +var/global/list/joblist = list() //list of all jobstypes, minus borg and AI + +#define all_genders_define_list list(MALE,FEMALE,PLURAL,NEUTER) +#define all_genders_text_list list("Male","Female","Plural","Neuter") + +//Languages/species/whitelist. +var/global/list/all_species[0] +var/global/list/all_languages[0] +var/global/list/language_keys[0] // Table of say codes for all languages +var/global/list/whitelisted_species = list(SPECIES_HUMAN) // Species that require a whitelist check. +var/global/list/playable_species = list(SPECIES_HUMAN) // A list of ALL playable species, whitelisted, latejoin or otherwise. + +var/list/mannequins_ + +// Posters +var/global/list/poster_designs = list() + +// Grabs +var/global/list/all_grabstates[0] +var/global/list/all_grabobjects[0] + +// Uplinks +var/list/obj/item/device/uplink/world_uplinks = list() + +//Preferences stuff +//Hairstyles +GLOBAL_LIST_EMPTY(hair_styles_list) //stores /datum/sprite_accessory/hair indexed by name +GLOBAL_LIST_EMPTY(facial_hair_styles_list) //stores /datum/sprite_accessory/facial_hair indexed by name + +var/global/list/skin_styles_female_list = list() //unused +GLOBAL_LIST_EMPTY(body_marking_styles_list) //stores /datum/sprite_accessory/marking indexed by name + +GLOBAL_DATUM_INIT(underwear, /datum/category_collection/underwear, new()) + +var/global/list/exclude_jobs = list(/datum/job/ai,/datum/job/cyborg) + +// Visual nets +var/list/datum/visualnet/visual_nets = list() +var/datum/visualnet/camera/cameranet = new() + +// Runes +var/global/list/rune_list = new() +var/global/list/endgame_exits = list() +var/global/list/endgame_safespawns = list() + +var/global/list/syndicate_access = list(access_maint_tunnels, access_syndicate, access_external_airlocks) + +//Crafting +var/global/list/crafting_recipes = list() + + +// Strings which corraspond to bodypart covering flags, useful for outputting what something covers. +var/global/list/string_part_flags = list( + "head" = HEAD, + "face" = FACE, + "eyes" = EYES, + "upper body" = UPPER_TORSO, + "lower body" = LOWER_TORSO, + "legs" = LEGS, + "feet" = FEET, + "arms" = ARMS, + "hands" = HANDS +) + +// Strings which corraspond to slot flags, useful for outputting what slot something is. +var/global/list/string_slot_flags = list( + "back" = SLOT_BACK, + "face" = SLOT_MASK, + "waist" = SLOT_BELT, + "ID slot" = SLOT_ID, + "ears" = SLOT_EARS, + "eyes" = SLOT_EYES, + "hands" = SLOT_GLOVES, + "head" = SLOT_HEAD, + "feet" = SLOT_FEET, + "exo slot" = SLOT_OCLOTHING, + "body" = SLOT_ICLOTHING, + "neck" = SLOT_TIE, + "back2" = SLOT_S_STORE, + "holster" = SLOT_HOLSTER +) + +////////////////////////// +/////Initial Building///// +////////////////////////// + +/hook/global_init/proc/populateGlobalLists() + possible_cable_coil_colours = sortAssoc(list( + "Yellow" = COLOR_YELLOW, + "Green" = COLOR_LIME, + "Pink" = COLOR_PINK, + "Blue" = COLOR_BLUE, + "Orange" = COLOR_ORANGE, + "Cyan" = COLOR_CYAN, + "Red" = COLOR_RED, + "White" = COLOR_WHITE + )) + return 1 + +/proc/get_mannequin(var/ckey) + if(!mannequins_) + mannequins_ = new() + . = mannequins_[ckey] + if(!.) + . = new/mob/living/carbon/human/dummy/mannequin() + mannequins_[ckey] = . + +/hook/global_init/proc/makeDatumRefLists() + var/list/paths + + //Hair - Initialise all /datum/sprite_accessory/hair into an list indexed by hair-style name + paths = typesof(/datum/sprite_accessory/hair) - /datum/sprite_accessory/hair + for(var/path in paths) + var/datum/sprite_accessory/hair/H = new path() + GLOB.hair_styles_list[H.name] = H + + //Facial Hair - Initialise all /datum/sprite_accessory/facial_hair into an list indexed by facialhair-style name + paths = typesof(/datum/sprite_accessory/facial_hair) - /datum/sprite_accessory/facial_hair + for(var/path in paths) + var/datum/sprite_accessory/facial_hair/H = new path() + GLOB.facial_hair_styles_list[H.name] = H + + //Body markings - Initialise all /datum/sprite_accessory/marking into an list indexed by marking name + paths = typesof(/datum/sprite_accessory/marking) - /datum/sprite_accessory/marking + for(var/path in paths) + var/datum/sprite_accessory/marking/M = new path() + GLOB.body_marking_styles_list[M.name] = M + + //Surgery Steps - Initialize all /datum/surgery_step into a list + paths = typesof(/datum/surgery_step)-/datum/surgery_step + for(var/T in paths) + var/datum/surgery_step/S = new T + surgery_steps += S + sort_surgeries() + + //List of job. I can't believe this was calculated multiple times per tick! + paths = typesof(/datum/job)-/datum/job + paths -= exclude_jobs + for(var/T in paths) + var/datum/job/J = new T + joblist[J.title] = J + + //Languages and species. + paths = typesof(/datum/language)-/datum/language + for(var/T in paths) + var/datum/language/L = new T + all_languages[L.name] = L + + for (var/language_name in all_languages) + var/datum/language/L = all_languages[language_name] + if(!(L.flags & NONGLOBAL)) + language_keys[lowertext(L.key)] = L + + var/rkey = 0 + paths = typesof(/datum/species) + for(var/T in paths) + + rkey++ + + var/datum/species/S = T + if(!initial(S.name)) + continue + + S = new T + S.race_key = rkey //Used in mob icon caching. + all_species[S.name] = S + + if(!(S.spawn_flags & SPECIES_IS_RESTRICTED)) + playable_species += S.name + if(S.spawn_flags & SPECIES_IS_WHITELISTED) + whitelisted_species += S.name + + //Posters + paths = typesof(/datum/poster) - /datum/poster + for(var/T in paths) + var/datum/poster/P = new T + poster_designs += P + + + paths = typesof(/datum/crafting_recipe) - /datum/crafting_recipe + for(var/T in paths) + var/datum/crafting_recipe/R = new T + crafting_recipes[R.name] = R + + + //Grabs + paths = typesof(/datum/grab) - /datum/grab + for(var/T in paths) + var/datum/grab/G = new T + if(G.state_name) + all_grabstates[G.state_name] = G + + paths = typesof(/obj/item/grab) - /obj/item/grab + for(var/T in paths) + var/obj/item/grab/G = T + all_grabobjects[initial(G.type_name)] = T + + for(var/grabstate_name in all_grabstates) + var/datum/grab/G = all_grabstates[grabstate_name] + G.refresh_updown() + + return 1 + +/* // Uncomment to debug chemical reaction list. +/client/verb/debug_chemical_list() + + for (var/reaction in chemical_reactions_list) + . += "chemical_reactions_list\[\"[reaction]\"\] = \"[chemical_reactions_list[reaction]]\"\n" + if(islist(chemical_reactions_list[reaction])) + var/list/L = chemical_reactions_list[reaction] + for(var/t in L) + . += " has: [t]\n" + log_debug(.) + +*/ + +//*** params cache + +var/global/list/paramslist_cache = list() + +#define cached_key_number_decode(key_number_data) cached_params_decode(key_number_data, /proc/key_number_decode) +#define cached_number_list_decode(number_list_data) cached_params_decode(number_list_data, /proc/number_list_decode) + +/proc/cached_params_decode(var/params_data, var/decode_proc) + . = paramslist_cache[params_data] + if(!.) + . = call(decode_proc)(params_data) + paramslist_cache[params_data] = . + +/proc/key_number_decode(var/key_number_data) + var/list/L = params2list(key_number_data) + for(var/key in L) + L[key] = text2num(L[key]) + return L + +/proc/number_list_decode(var/number_list_data) + var/list/L = params2list(number_list_data) + for(var/i in 1 to L.len) + L[i] = text2num(L[i]) + return L diff --git a/code/_helpers/icons.dm b/code/_helpers/icons.dm new file mode 100644 index 00000000..a231a6ae --- /dev/null +++ b/code/_helpers/icons.dm @@ -0,0 +1,923 @@ +/* +IconProcs README + +A BYOND library for manipulating icons and colors + +by Lummox JR + +version 1.0 + +The IconProcs library was made to make a lot of common icon operations much easier. BYOND's icon manipulation +routines are very capable but some of the advanced capabilities like using alpha transparency can be unintuitive to beginners. + +CHANGING ICONS + +Several new procs have been added to the /icon datum to simplify working with icons. To use them, +remember you first need to setup an /icon var like so: + +var/icon/my_icon = new('iconfile.dmi') + +icon/ChangeOpacity(amount = 1) + A very common operation in DM is to try to make an icon more or less transparent. Making an icon more + transparent is usually much easier than making it less so, however. This proc basically is a frontend + for MapColors() which can change opacity any way you like, in much the same way that SetIntensity() + can make an icon lighter or darker. If amount is 0.5, the opacity of the icon will be cut in half. + If amount is 2, opacity is doubled and anything more than half-opaque will become fully opaque. +icon/GrayScale() + Converts the icon to grayscale instead of a fully colored icon. Alpha values are left intact. +icon/ColorTone(tone) + Similar to GrayScale(), this proc converts the icon to a range of black -> tone -> white, where tone is an + RGB color (its alpha is ignored). This can be used to create a sepia tone or similar effect. + See also the global ColorTone() proc. +icon/MinColors(icon) + The icon is blended with a second icon where the minimum of each RGB pixel is the result. + Transparency may increase, as if the icons were blended with ICON_ADD. You may supply a color in place of an icon. +icon/MaxColors(icon) + The icon is blended with a second icon where the maximum of each RGB pixel is the result. + Opacity may increase, as if the icons were blended with ICON_OR. You may supply a color in place of an icon. +icon/Opaque(background = "#000000") + All alpha values are set to 255 throughout the icon. Transparent pixels become black, or whatever background color you specify. +icon/BecomeAlphaMask() + You can convert a simple grayscale icon into an alpha mask to use with other icons very easily with this proc. + The black parts become transparent, the white parts stay white, and anything in between becomes a translucent shade of white. +icon/AddAlphaMask(mask) + The alpha values of the mask icon will be blended with the current icon. Anywhere the mask is opaque, + the current icon is untouched. Anywhere the mask is transparent, the current icon becomes transparent. + Where the mask is translucent, the current icon becomes more transparent. +icon/UseAlphaMask(mask, mode) + Sometimes you may want to take the alpha values from one icon and use them on a different icon. + This proc will do that. Just supply the icon whose alpha mask you want to use, and src will change + so it has the same colors as before but uses the mask for opacity. + +COLOR MANAGEMENT AND HSV + +RGB isn't the only way to represent color. Sometimes it's more useful to work with a model called HSV, which stands for hue, saturation, and value. + + * The hue of a color describes where it is along the color wheel. It goes from red to yellow to green to + cyan to blue to magenta and back to red. + * The saturation of a color is how much color is in it. A color with low saturation will be more gray, + and with no saturation at all it is a shade of gray. + * The value of a color determines how bright it is. A high-value color is vivid, moderate value is dark, + and no value at all is black. + +Just as BYOND uses "#rrggbb" to represent RGB values, a similar format is used for HSV: "#hhhssvv". The hue is three +hex digits because it ranges from 0 to 0x5FF. + + * 0 to 0xFF - red to yellow + * 0x100 to 0x1FF - yellow to green + * 0x200 to 0x2FF - green to cyan + * 0x300 to 0x3FF - cyan to blue + * 0x400 to 0x4FF - blue to magenta + * 0x500 to 0x5FF - magenta to red + +Knowing this, you can figure out that red is "#000ffff" in HSV format, which is hue 0 (red), saturation 255 (as colorful as possible), +value 255 (as bright as possible). Green is "#200ffff" and blue is "#400ffff". + +More than one HSV color can match the same RGB color. + +Here are some procs you can use for color management: + +ReadRGB(rgb) + Takes an RGB string like "#ffaa55" and converts it to a list such as list(255,170,85). If an RGBA format is used + that includes alpha, the list will have a fourth item for the alpha value. +hsv(hue, sat, val, apha) + Counterpart to rgb(), this takes the values you input and converts them to a string in "#hhhssvv" or "#hhhssvvaa" + format. Alpha is not included in the result if null. +ReadHSV(rgb) + Takes an HSV string like "#100ff80" and converts it to a list such as list(256,255,128). If an HSVA format is used that + includes alpha, the list will have a fourth item for the alpha value. +RGBtoHSV(rgb) + Takes an RGB or RGBA string like "#ffaa55" and converts it into an HSV or HSVA color such as "#080aaff". +HSVtoRGB(hsv) + Takes an HSV or HSVA string like "#080aaff" and converts it into an RGB or RGBA color such as "#ff55aa". +BlendRGB(rgb1, rgb2, amount) + Blends between two RGB or RGBA colors using regular RGB blending. If amount is 0, the first color is the result; + if 1, the second color is the result. 0.5 produces an average of the two. Values outside the 0 to 1 range are allowed as well. + The returned value is an RGB or RGBA color. +BlendHSV(hsv1, hsv2, amount) + Blends between two HSV or HSVA colors using HSV blending, which tends to produce nicer results than regular RGB + blending because the brightness of the color is left intact. If amount is 0, the first color is the result; if 1, + the second color is the result. 0.5 produces an average of the two. Values outside the 0 to 1 range are allowed as well. + The returned value is an HSV or HSVA color. +BlendRGBasHSV(rgb1, rgb2, amount) + Like BlendHSV(), but the colors used and the return value are RGB or RGBA colors. The blending is done in HSV form. +HueToAngle(hue) + Converts a hue to an angle range of 0 to 360. Angle 0 is red, 120 is green, and 240 is blue. +AngleToHue(hue) + Converts an angle to a hue in the valid range. +RotateHue(hsv, angle) + Takes an HSV or HSVA value and rotates the hue forward through red, green, and blue by an angle from 0 to 360. + (Rotating red by 60° produces yellow.) The result is another HSV or HSVA color with the same saturation and value + as the original, but a different hue. +GrayScale(rgb) + Takes an RGB or RGBA color and converts it to grayscale. Returns an RGB or RGBA string. +ColorTone(rgb, tone) + Similar to GrayScale(), this proc converts an RGB or RGBA color to a range of black -> tone -> white instead of + using strict shades of gray. The tone value is an RGB color; any alpha value is ignored. +*/ + +/* +Get Flat Icon DEMO by DarkCampainger + +This is a test for the get flat icon proc, modified approprietly for icons and their states. +Probably not a good idea to run this unless you want to see how the proc works in detail. +mob + icon = 'old_or_unused.dmi' + icon_state = "green" + + Login() + // Testing image underlays + underlays += image(icon='old_or_unused.dmi',icon_state="red") + underlays += image(icon='old_or_unused.dmi',icon_state="red", pixel_x = 32) + underlays += image(icon='old_or_unused.dmi',icon_state="red", pixel_x = -32) + + // Testing image overlays + overlays += image(icon='old_or_unused.dmi',icon_state="green", pixel_x = 32, pixel_y = -32) + overlays += image(icon='old_or_unused.dmi',icon_state="green", pixel_x = 32, pixel_y = 32) + overlays += image(icon='old_or_unused.dmi',icon_state="green", pixel_x = -32, pixel_y = -32) + + // Testing icon file overlays (defaults to mob's state) + overlays += '_flat_demoIcons2.dmi' + + // Testing icon_state overlays (defaults to mob's icon) + overlays += "white" + + // Testing dynamic icon overlays + var/icon/I = icon('old_or_unused.dmi', icon_state="aqua") + I.Shift(NORTH,16,1) + overlays+=I + + // Testing dynamic image overlays + I=image(icon=I,pixel_x = -32, pixel_y = 32) + overlays+=I + + // Testing object types (and layers) + overlays+=/obj/effect/overlayTest + + loc = locate (10,10,1) + verb + Browse_Icon() + set name = "1. Browse Icon" + // Give it a name for the cache + var/iconName = "[ckey(src.name)]_flattened.dmi" + // Send the icon to src's local cache + src<

") + + Output_Icon() + set name = "2. Output Icon" + to_chat(src, "Icon is: \icon[getFlatIcon(src)]") + + Label_Icon() + set name = "3. Label Icon" + // Give it a name for the cache + var/iconName = "[ckey(src.name)]_flattened.dmi" + // Copy the file to the rsc manually + var/icon/I = fcopy_rsc(getFlatIcon(src)) + // Send the icon to src's local cache + src< transparent, gray -> translucent white, white -> solid white + proc/BecomeAlphaMask() + SwapColor(null, "#000000ff") // don't let transparent become gray + MapColors(0,0,0,0.3, 0,0,0,0.59, 0,0,0,0.11, 0,0,0,0, 1,1,1,0) + + proc/UseAlphaMask(mask) + Opaque() + AddAlphaMask(mask) + + proc/AddAlphaMask(mask) + var/icon/M = new(mask) + M.Blend("#ffffff", ICON_SUBTRACT) + // apply mask + Blend(M, ICON_ADD) + +/* + HSV format is represented as "#hhhssvv" or "#hhhssvvaa" + + Hue ranges from 0 to 0x5ff (1535) + + 0x000 = red + 0x100 = yellow + 0x200 = green + 0x300 = cyan + 0x400 = blue + 0x500 = magenta + + Saturation is from 0 to 0xff (255) + + More saturation = more color + Less saturation = more gray + + Value ranges from 0 to 0xff (255) + + Higher value means brighter color + */ + +proc/ReadRGB(rgb) + if(!rgb) return + + // interpret the HSV or HSVA value + var/i=1,start=1 + if(text2ascii(rgb) == 35) ++start // skip opening # + var/ch,which=0,r=0,g=0,b=0,alpha=0,usealpha + var/digits=0 + for(i=start, i<=length(rgb), ++i) + ch = text2ascii(rgb, i) + if(ch < 48 || (ch > 57 && ch < 65) || (ch > 70 && ch < 97) || ch > 102) break + ++digits + if(digits == 8) break + + var/single = digits < 6 + if(digits != 3 && digits != 4 && digits != 6 && digits != 8) return + if(digits == 4 || digits == 8) usealpha = 1 + for(i=start, digits>0, ++i) + ch = text2ascii(rgb, i) + if(ch >= 48 && ch <= 57) ch -= 48 + else if(ch >= 65 && ch <= 70) ch -= 55 + else if(ch >= 97 && ch <= 102) ch -= 87 + else break + --digits + switch(which) + if(0) + r = (r << 4) | ch + if(single) + r |= r << 4 + ++which + else if(!(digits & 1)) ++which + if(1) + g = (g << 4) | ch + if(single) + g |= g << 4 + ++which + else if(!(digits & 1)) ++which + if(2) + b = (b << 4) | ch + if(single) + b |= b << 4 + ++which + else if(!(digits & 1)) ++which + if(3) + alpha = (alpha << 4) | ch + if(single) alpha |= alpha << 4 + + . = list(r, g, b) + if(usealpha) . += alpha + +proc/ReadHSV(hsv) + if(!hsv) return + + // interpret the HSV or HSVA value + var/i=1,start=1 + if(text2ascii(hsv) == 35) ++start // skip opening # + var/ch,which=0,hue=0,sat=0,val=0,alpha=0,usealpha + var/digits=0 + for(i=start, i<=length(hsv), ++i) + ch = text2ascii(hsv, i) + if(ch < 48 || (ch > 57 && ch < 65) || (ch > 70 && ch < 97) || ch > 102) break + ++digits + if(digits == 9) break + if(digits > 7) usealpha = 1 + if(digits <= 4) ++which + if(digits <= 2) ++which + for(i=start, digits>0, ++i) + ch = text2ascii(hsv, i) + if(ch >= 48 && ch <= 57) ch -= 48 + else if(ch >= 65 && ch <= 70) ch -= 55 + else if(ch >= 97 && ch <= 102) ch -= 87 + else break + --digits + switch(which) + if(0) + hue = (hue << 4) | ch + if(digits == (usealpha ? 6 : 4)) ++which + if(1) + sat = (sat << 4) | ch + if(digits == (usealpha ? 4 : 2)) ++which + if(2) + val = (val << 4) | ch + if(digits == (usealpha ? 2 : 0)) ++which + if(3) + alpha = (alpha << 4) | ch + + . = list(hue, sat, val) + if(usealpha) . += alpha + +proc/HSVtoRGB(hsv) + if(!hsv) return "#000000" + var/list/HSV = ReadHSV(hsv) + if(!HSV) return "#000000" + + var/hue = HSV[1] + var/sat = HSV[2] + var/val = HSV[3] + + // Compress hue into easier-to-manage range + hue -= hue >> 8 + if(hue >= 0x5fa) hue -= 0x5fa + + var/hi,mid,lo,r,g,b + hi = val + lo = round((255 - sat) * val / 255, 1) + mid = lo + round(abs(round(hue, 510) - hue) * (hi - lo) / 255, 1) + if(hue >= 765) + if(hue >= 1275) {r=hi; g=lo; b=mid} + else if(hue >= 1020) {r=mid; g=lo; b=hi } + else {r=lo; g=mid; b=hi } + else + if(hue >= 510) {r=lo; g=hi; b=mid} + else if(hue >= 255) {r=mid; g=hi; b=lo } + else {r=hi; g=mid; b=lo } + + return (HSV.len > 3) ? rgb(r,g,b,HSV[4]) : rgb(r,g,b) + +proc/RGBtoHSV(rgb) + if(!rgb) return "#0000000" + var/list/RGB = ReadRGB(rgb) + if(!RGB) return "#0000000" + + var/r = RGB[1] + var/g = RGB[2] + var/b = RGB[3] + var/hi = max(r,g,b) + var/lo = min(r,g,b) + + var/val = hi + var/sat = hi ? round((hi-lo) * 255 / hi, 1) : 0 + var/hue = 0 + + if(sat) + var/dir + var/mid + if(hi == r) + if(lo == b) {hue=0; dir=1; mid=g} + else {hue=1535; dir=-1; mid=b} + else if(hi == g) + if(lo == r) {hue=512; dir=1; mid=b} + else {hue=511; dir=-1; mid=r} + else if(hi == b) + if(lo == g) {hue=1024; dir=1; mid=r} + else {hue=1023; dir=-1; mid=g} + hue += dir * round((mid-lo) * 255 / (hi-lo), 1) + + return hsv(hue, sat, val, (RGB.len>3 ? RGB[4] : null)) + +proc/hsv(hue, sat, val, alpha) + if(hue < 0 || hue >= 1536) hue %= 1536 + if(hue < 0) hue += 1536 + if((hue & 0xFF) == 0xFF) + ++hue + if(hue >= 1536) hue = 0 + if(sat < 0) sat = 0 + if(sat > 255) sat = 255 + if(val < 0) val = 0 + if(val > 255) val = 255 + . = "#" + . += TO_HEX_DIGIT(hue >> 8) + . += TO_HEX_DIGIT(hue >> 4) + . += TO_HEX_DIGIT(hue) + . += TO_HEX_DIGIT(sat >> 4) + . += TO_HEX_DIGIT(sat) + . += TO_HEX_DIGIT(val >> 4) + . += TO_HEX_DIGIT(val) + if(!isnull(alpha)) + if(alpha < 0) alpha = 0 + if(alpha > 255) alpha = 255 + . += TO_HEX_DIGIT(alpha >> 4) + . += TO_HEX_DIGIT(alpha) + +/* + Smooth blend between HSV colors + + amount=0 is the first color + amount=1 is the second color + amount=0.5 is directly between the two colors + + amount<0 or amount>1 are allowed + */ +proc/BlendHSV(hsv1, hsv2, amount) + var/list/HSV1 = ReadHSV(hsv1) + var/list/HSV2 = ReadHSV(hsv2) + + // add missing alpha if needed + if(HSV1.len < HSV2.len) HSV1 += 255 + else if(HSV2.len < HSV1.len) HSV2 += 255 + var/usealpha = HSV1.len > 3 + + // normalize hsv values in case anything is screwy + if(HSV1[1] > 1536) HSV1[1] %= 1536 + if(HSV2[1] > 1536) HSV2[1] %= 1536 + if(HSV1[1] < 0) HSV1[1] += 1536 + if(HSV2[1] < 0) HSV2[1] += 1536 + if(!HSV1[3]) {HSV1[1] = 0; HSV1[2] = 0} + if(!HSV2[3]) {HSV2[1] = 0; HSV2[2] = 0} + + // no value for one color means don't change saturation + if(!HSV1[3]) HSV1[2] = HSV2[2] + if(!HSV2[3]) HSV2[2] = HSV1[2] + // no saturation for one color means don't change hues + if(!HSV1[2]) HSV1[1] = HSV2[1] + if(!HSV2[2]) HSV2[1] = HSV1[1] + + // Compress hues into easier-to-manage range + HSV1[1] -= HSV1[1] >> 8 + HSV2[1] -= HSV2[1] >> 8 + + var/hue_diff = HSV2[1] - HSV1[1] + if(hue_diff > 765) hue_diff -= 1530 + else if(hue_diff <= -765) hue_diff += 1530 + + var/hue = round(HSV1[1] + hue_diff * amount, 1) + var/sat = round(HSV1[2] + (HSV2[2] - HSV1[2]) * amount, 1) + var/val = round(HSV1[3] + (HSV2[3] - HSV1[3]) * amount, 1) + var/alpha = usealpha ? round(HSV1[4] + (HSV2[4] - HSV1[4]) * amount, 1) : null + + // normalize hue + if(hue < 0 || hue >= 1530) hue %= 1530 + if(hue < 0) hue += 1530 + // decompress hue + hue += round(hue / 255) + + return hsv(hue, sat, val, alpha) + +/* + Smooth blend between RGB colors + + amount=0 is the first color + amount=1 is the second color + amount=0.5 is directly between the two colors + + amount<0 or amount>1 are allowed + */ +proc/BlendRGB(rgb1, rgb2, amount) + var/list/RGB1 = ReadRGB(rgb1) + var/list/RGB2 = ReadRGB(rgb2) + + // add missing alpha if needed + if(RGB1.len < RGB2.len) RGB1 += 255 + else if(RGB2.len < RGB1.len) RGB2 += 255 + var/usealpha = RGB1.len > 3 + + var/r = round(RGB1[1] + (RGB2[1] - RGB1[1]) * amount, 1) + var/g = round(RGB1[2] + (RGB2[2] - RGB1[2]) * amount, 1) + var/b = round(RGB1[3] + (RGB2[3] - RGB1[3]) * amount, 1) + var/alpha = usealpha ? round(RGB1[4] + (RGB2[4] - RGB1[4]) * amount, 1) : null + + return isnull(alpha) ? rgb(r, g, b) : rgb(r, g, b, alpha) + +proc/BlendRGBasHSV(rgb1, rgb2, amount) + return HSVtoRGB(RGBtoHSV(rgb1), RGBtoHSV(rgb2), amount) + +proc/HueToAngle(hue) + // normalize hsv in case anything is screwy + if(hue < 0 || hue >= 1536) hue %= 1536 + if(hue < 0) hue += 1536 + // Compress hue into easier-to-manage range + hue -= hue >> 8 + return hue / (1530/360) + +proc/AngleToHue(angle) + // normalize hsv in case anything is screwy + if(angle < 0 || angle >= 360) angle -= 360 * round(angle / 360) + var/hue = angle * (1530/360) + // Decompress hue + hue += round(hue / 255) + return hue + + +// positive angle rotates forward through red->green->blue +proc/RotateHue(hsv, angle) + var/list/HSV = ReadHSV(hsv) + + // normalize hsv in case anything is screwy + if(HSV[1] >= 1536) HSV[1] %= 1536 + if(HSV[1] < 0) HSV[1] += 1536 + + // Compress hue into easier-to-manage range + HSV[1] -= HSV[1] >> 8 + + if(angle < 0 || angle >= 360) angle -= 360 * round(angle / 360) + HSV[1] = round(HSV[1] + angle * (1530/360), 1) + + // normalize hue + if(HSV[1] < 0 || HSV[1] >= 1530) HSV[1] %= 1530 + if(HSV[1] < 0) HSV[1] += 1530 + // decompress hue + HSV[1] += round(HSV[1] / 255) + + return hsv(HSV[1], HSV[2], HSV[3], (HSV.len > 3 ? HSV[4] : null)) + +// Convert an rgb color to grayscale +proc/GrayScale(rgb) + var/list/RGB = ReadRGB(rgb) + var/gray = RGB[1]*0.3 + RGB[2]*0.59 + RGB[3]*0.11 + return (RGB.len > 3) ? rgb(gray, gray, gray, RGB[4]) : rgb(gray, gray, gray) + +// Change grayscale color to black->tone->white range +proc/ColorTone(rgb, tone) + var/list/RGB = ReadRGB(rgb) + var/list/TONE = ReadRGB(tone) + + var/gray = RGB[1]*0.3 + RGB[2]*0.59 + RGB[3]*0.11 + var/tone_gray = TONE[1]*0.3 + TONE[2]*0.59 + TONE[3]*0.11 + + if(gray <= tone_gray) return BlendRGB("#000000", tone, gray/(tone_gray || 1)) + else return BlendRGB(tone, "#ffffff", (gray-tone_gray)/((255-tone_gray) || 1)) + + +/* +Get flat icon by DarkCampainger. As it says on the tin, will return an icon with all the overlays +as a single icon. Useful for when you want to manipulate an icon via the above as overlays are not normally included. +The _flatIcons list is a cache for generated icon files. +*/ + +proc // Creates a single icon from a given /atom or /image. Only the first argument is required. + getFlatIcon(image/A, defdir=2, deficon=null, defstate="", defblend=BLEND_DEFAULT, always_use_defdir = 0) + // We start with a blank canvas, otherwise some icon procs crash silently + var/icon/flat = icon('icons/effects/effects.dmi', "icon_state"="nothing") // Final flattened icon + if(!A) + return flat + if(A.alpha <= 0) + return flat + var/noIcon = FALSE + + var/curicon + if(A.icon) + curicon = A.icon + else + curicon = deficon + + if(!curicon) + noIcon = TRUE // Do not render this object. + + var/curstate + if(A.icon_state) + curstate = A.icon_state + else + curstate = defstate + + if(!noIcon && !(curstate in icon_states(curicon))) + if("" in icon_states(curicon)) + curstate = "" + else + noIcon = TRUE // Do not render this object. + + var/curdir + if(A.dir != 2 && !always_use_defdir) + curdir = A.dir + else + curdir = defdir + + var/curblend + if(A.blend_mode == BLEND_DEFAULT) + curblend = defblend + else + curblend = A.blend_mode + + // Layers will be a sorted list of icons/overlays, based on the order in which they are displayed + var/list/layers = list() + var/image/copy + // Add the atom's icon itself, without pixel_x/y offsets. + if(!noIcon) + copy = image(icon=curicon, icon_state=curstate, layer=A.layer, dir=curdir) + copy.color = A.color + copy.alpha = A.alpha + copy.blend_mode = curblend + layers[copy] = A.layer + + // Loop through the underlays, then overlays, sorting them into the layers list + var/list/process = A.underlays // Current list being processed + var/pSet=0 // Which list is being processed: 0 = underlays, 1 = overlays + var/curIndex=1 // index of 'current' in list being processed + var/current // Current overlay being sorted + var/currentLayer // Calculated layer that overlay appears on (special case for FLOAT_LAYER) + var/compare // The overlay 'add' is being compared against + var/cmpIndex // The index in the layers list of 'compare' + while(TRUE) + if(curIndex<=process.len) + current = process[curIndex] + if(current) + currentLayer = current:layer + if(currentLayer<0) // Special case for FLY_LAYER + if(currentLayer <= -1000) return flat + if(pSet == 0) // Underlay + currentLayer = A.layer+currentLayer/1000 + else // Overlay + currentLayer = A.layer+(1000+currentLayer)/1000 + + // Sort add into layers list + for(cmpIndex=1,cmpIndex<=layers.len,cmpIndex++) + compare = layers[cmpIndex] + if(currentLayer < layers[compare]) // Associated value is the calculated layer + layers.Insert(cmpIndex,current) + layers[current] = currentLayer + break + if(cmpIndex>layers.len) // Reached end of list without inserting + layers[current]=currentLayer // Place at end + + curIndex++ + else if(pSet == 0) // Switch to overlays + curIndex = 1 + pSet = 1 + process = A.overlays + else // All done + break + + var/icon/add // Icon of overlay being added + + // Current dimensions of flattened icon + var/{flatX1=1;flatX2=flat.Width();flatY1=1;flatY2=flat.Height()} + // Dimensions of overlay being added + var/{addX1;addX2;addY1;addY2} + + for(var/I in layers) + + if(I:alpha == 0) + continue + + if(I == copy) // 'I' is an /image based on the object being flattened. + curblend = BLEND_OVERLAY + add = icon(I:icon, I:icon_state, I:dir) + // This checks for a silent failure mode of the icon routine. If the requested dir + // doesn't exist in this icon state it returns a 32x32 icon with 0 alpha. + if (I:dir != SOUTH && add.Width() == 32 && add.Height() == 32) + // Check every pixel for blank (computationally expensive, but the process is limited + // by the amount of film on the station, only happens when we hit something that's + // turned, and bails at the very first pixel it sees. + var/blankpixel; + for(var/y;y<=32;y++) + for(var/x;x<32;x++) + blankpixel = isnull(add.GetPixel(x,y)) + if(!blankpixel) + break + if(!blankpixel) + break + // If we ALWAYS returned a null (which happens when GetPixel encounters something with alpha 0) + if (blankpixel) + // Pull the default direction. + add = icon(I:icon, I:icon_state) + else // 'I' is an appearance object. + if(istype(A,/obj/machinery/atmospherics) && I in A.underlays) + var/image/Im = I + add = getFlatIcon(new/image(I), Im.dir, curicon, curstate, curblend, 1) + else + add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend, always_use_defdir) + + // Find the new dimensions of the flat icon to fit the added overlay + addX1 = min(flatX1, I:pixel_x+1) + addX2 = max(flatX2, I:pixel_x+add.Width()) + addY1 = min(flatY1, I:pixel_y+1) + addY2 = max(flatY2, I:pixel_y+add.Height()) + + if(addX1!=flatX1 || addX2!=flatX2 || addY1!=flatY1 || addY2!=flatY2) + // Resize the flattened icon so the new icon fits + flat.Crop(addX1-flatX1+1, addY1-flatY1+1, addX2-flatX1+1, addY2-flatY1+1) + flatX1=addX1;flatX2=addX2 + flatY1=addY1;flatY2=addY2 + var/iconmode + if(I in A.overlays) + iconmode = ICON_OVERLAY + else if(I in A.underlays) + iconmode = ICON_UNDERLAY + else + iconmode = blendMode2iconMode(curblend) + // Blend the overlay into the flattened icon + flat.Blend(add, iconmode, I:pixel_x + 2 - flatX1, I:pixel_y + 2 - flatY1) + + if(A.color) + flat.Blend(A.color, ICON_MULTIPLY) + if(A.alpha < 255) + flat.Blend(rgb(255, 255, 255, A.alpha), ICON_MULTIPLY) + + return icon(flat, "", SOUTH) + + getIconMask(atom/A)//By yours truly. Creates a dynamic mask for a mob/whatever. /N + var/icon/alpha_mask = new(A.icon,A.icon_state)//So we want the default icon and icon state of A. + for(var/I in A.overlays)//For every image in overlays. var/image/I will not work, don't try it. + if(I:layer>A.layer) continue//If layer is greater than what we need, skip it. + var/icon/image_overlay = new(I:icon,I:icon_state)//Blend only works with icon objects. + //Also, icons cannot directly set icon_state. Slower than changing variables but whatever. + alpha_mask.Blend(image_overlay,ICON_OR)//OR so they are lumped together in a nice overlay. + return alpha_mask//And now return the mask. + +/mob/proc/AddCamoOverlay(atom/A)//A is the atom which we are using as the overlay. + var/icon/opacity_icon = new(A.icon, A.icon_state)//Don't really care for overlays/underlays. + //Now we need to culculate overlays+underlays and add them together to form an image for a mask. + //var/icon/alpha_mask = getFlatIcon(src)//Accurate but SLOW. Not designed for running each tick. Could have other uses I guess. + var/icon/alpha_mask = getIconMask(src)//Which is why I created that proc. Also a little slow since it's blending a bunch of icons together but good enough. + opacity_icon.AddAlphaMask(alpha_mask)//Likely the main source of lag for this proc. Probably not designed to run each tick. + opacity_icon.ChangeOpacity(0.4)//Front end for MapColors so it's fast. 0.5 means half opacity and looks the best in my opinion. + for(var/i=0,i<5,i++)//And now we add it as overlays. It's faster than creating an icon and then merging it. + var/image/I = image("icon" = opacity_icon, "icon_state" = A.icon_state, "layer" = layer+0.8)//So it's above other stuff but below weapons and the like. + switch(i)//Now to determine offset so the result is somewhat blurred. + if(1) I.pixel_x-- + if(2) I.pixel_x++ + if(3) I.pixel_y-- + if(4) I.pixel_y++ + overlays += I//And finally add the overlay. + +#define HOLOPAD_SHORT_RANGE 1 //For determining the color of holopads based on whether they're short or long range. +#define HOLOPAD_LONG_RANGE 2 + +/proc/getHologramIcon(icon/A, safety=1, noDecolor=FALSE, var/hologram_color=HOLOPAD_SHORT_RANGE)//If safety is on, a new icon is not created. + var/icon/flat_icon = safety ? A : new(A)//Has to be a new icon to not constantly change the same icon. + if (noDecolor == FALSE) + if(hologram_color == HOLOPAD_LONG_RANGE) + flat_icon.ColorTone(rgb(225,223,125)) //Light yellow if it's a call to a long-range holopad. + else + flat_icon.ColorTone(rgb(125,180,225))//Let's make it bluish. + flat_icon.ChangeOpacity(0.5)//Make it half transparent. + var/icon/alpha_mask = new('icons/effects/effects.dmi', "scanline-[hologram_color]")//Scanline effect. + flat_icon.AddAlphaMask(alpha_mask)//Finally, let's mix in a distortion effect. + return flat_icon + +//For photo camera. +/proc/build_composite_icon(atom/A) + var/icon/composite = icon(A.icon, A.icon_state, A.dir, 1) + for(var/O in A.overlays) + var/image/I = O + composite.Blend(icon(I.icon, I.icon_state, I.dir, 1), ICON_OVERLAY) + return composite + +proc/adjust_brightness(var/color, var/value) + if (!color) return "#ffffff" + if (!value) return color + + var/list/RGB = ReadRGB(color) + RGB[1] = Clamp(RGB[1]+value,0,255) + RGB[2] = Clamp(RGB[2]+value,0,255) + RGB[3] = Clamp(RGB[3]+value,0,255) + return rgb(RGB[1],RGB[2],RGB[3]) + +proc/sort_atoms_by_layer(var/list/atoms) + // Comb sort icons based on levels + var/list/result = atoms.Copy() + var/gap = result.len + var/swapped = 1 + while (gap > 1 || swapped) + swapped = 0 + if(gap > 1) + gap = round(gap / 1.3) // 1.3 is the emperic comb sort coefficient + if(gap < 1) + gap = 1 + for(var/i = 1; gap + i <= result.len; i++) + var/atom/l = result[i] //Fucking hate + var/atom/r = result[gap+i] //how lists work here + if(l.plane > r.plane || (l.plane == r.plane && l.layer > r.layer)) //no "result[i].layer" for me + result.Swap(i, gap + i) + swapped = 1 + return result +/* +generate_image function generates image of specified range and location +arguments tx, ty, tz are target coordinates (requred), range defines render distance to opposite corner (requred) +cap_mode is capturing mode (optional), user is capturing mob (requred only wehen cap_mode = CAPTURE_MODE_REGULAR), +lighting determines lighting capturing (optional), suppress_errors suppreses errors and continues to capture (optional). +*/ +proc/generate_image(var/tx as num, var/ty as num, var/tz as num, var/range as num, var/cap_mode = CAPTURE_MODE_PARTIAL, var/mob/living/user, var/lighting = 1, var/suppress_errors = 1) + var/list/turfstocapture = list() + //Lines below determine what tiles will be rendered + for(var/xoff = 0 to range) + for(var/yoff = 0 to range) + var/turf/T = locate(tx + xoff,ty + yoff,tz) + if(T) + if(cap_mode == CAPTURE_MODE_REGULAR) + if(user.can_capture_turf(T)) + turfstocapture.Add(T) + continue + else + turfstocapture.Add(T) + else + //Capture includes non-existan turfs + if(!suppress_errors) + return + //Lines below determine what objects will be rendered + var/list/atoms = list() + for(var/turf/T in turfstocapture) + atoms.Add(T) + for(var/atom/A in T) + if(istype(A, /atom/movable/lighting_overlay) && lighting) //Special case for lighting + atoms.Add(A) + continue + if(A.invisibility) continue + atoms.Add(A) + //Lines below actually render all colected data + atoms = sort_atoms_by_layer(atoms) + var/icon/cap = icon('icons/effects/96x96.dmi', "") + cap.Scale(range*32, range*32) + cap.Blend("#000", ICON_OVERLAY) + for(var/atom/A in atoms) + if(A) + var/icon/img = getFlatIcon(A) + if(istype(img, /icon)) + if(istype(A, /mob/living) && A:lying) + img.BecomeLying() + var/xoff = (A.x - tx) * 32 + var/yoff = (A.y - ty) * 32 + cap.Blend(img, blendMode2iconMode(A.blend_mode), A.pixel_x + xoff, A.pixel_y + yoff) + + return cap + diff --git a/code/_helpers/lists.dm b/code/_helpers/lists.dm new file mode 100644 index 00000000..16ce3a04 --- /dev/null +++ b/code/_helpers/lists.dm @@ -0,0 +1,731 @@ +/* + * Holds procs to help with list operations + * Contains groups: + * Misc + * Sorting + */ + +/* + * Misc + */ + +//Returns a list in plain english as a string +/proc/english_list(var/list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" ) + switch(input.len) + if(0) return nothing_text + if(1) return "[input[1]]" + if(2) return "[input[1]][and_text][input[2]]" + else return "[jointext(input, comma_text, 1, -1)][final_comma_text][and_text][input[input.len]]" + +/proc/or_sign_list(var/list/input, nothing_text = "nothing", and_text = " || ", comma_text = " || ", final_comma_text = "" ) + switch(input.len) + if(0) return nothing_text + if(1) return "[input[1]]" + if(2) return "[input[1]][and_text][input[2]]" + else return "[jointext(input, comma_text, 1, -1)][final_comma_text][and_text][input[input.len]]" + +//Returns list element or null. Should prevent "index out of bounds" error. +proc/listgetindex(var/list/list,index) + if(istype(list) && list.len) + if(isnum(index)) + if(InRange(index,1,list.len)) + return list[index] + else if(index in list) + return list[index] + return + +//Return either pick(list) or null if list is not of type /list or is empty +proc/safepick(list/list) + if(!islist(list) || !list.len) + return + return pick(list) + +//Checks if the list is empty +proc/isemptylist(list/list) + if(!list.len) + return 1 + return 0 + +//Checks for specific types in a list +/proc/is_type_in_list(var/atom/A, var/list/L) + for(var/type in L) + if(istype(A, type)) + return 1 + return 0 + +//Checks for specific paths in a list +/proc/is_path_in_list(var/path, var/list/L) + for(var/type in L) + if(ispath(path, type)) + 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 + +//Empties the list by .Cut(). Setting lenght = 0 has been confirmed to leak references. +proc/clearlist(var/list/L) + if(islist(L)) + L.Cut() + +//Removes any null entries from the list +proc/listclearnulls(list/list) + if(istype(list)) + while(null in list) + list -= null + return + +/* + * Returns list containing all the entries from first list that are not present in second. + * If skiprep = 1, repeated elements are treated as one. + * If either of arguments is not a list, returns null + */ +/proc/difflist(var/list/first, var/list/second, var/skiprep=0) + if(!islist(first) || !islist(second)) + return + var/list/result = new + if(skiprep) + for(var/e in first) + if(!(e in result) && !(e in second)) + result += e + else + result = first - second + return result + +/* + * Returns list containing entries that are in either list but not both. + * If skipref = 1, repeated elements are treated as one. + * If either of arguments is not a list, returns null + */ +/proc/uniquemergelist(var/list/first, var/list/second, var/skiprep=0) + if(!islist(first) || !islist(second)) + return + var/list/result = new + if(skiprep) + result = difflist(first, second, skiprep)+difflist(second, first, skiprep) + else + result = first ^ second + return result + +/proc/assoc_merge_add(var/value_a, var/value_b) + return value_a + value_b + +// This proc merges two associative lists +/proc/merge_assoc_lists(var/list/a, var/list/b, var/merge_method, var/default_if_null_value = null) + . = list() + for(var/key in a) + var/a_value = a[key] + a_value = isnull(a_value) ? default_if_null_value : a_value + .[key] = a_value + for(var/key in b) + var/b_value = b[key] + b_value = isnull(b_value) ? default_if_null_value : b_value + if(!(key in .)) + .[key] = b_value + else + .[key] = call(merge_method)(.[key], b_value) + +//Pretends to pick an element based on its weight but really just seems to pick a random element. +/proc/pickweight(list/L) + var/total = 0 + var/item + for (item in L) + if (!L[item]) + L[item] = 1 + total += L[item] + + total = rand(1, total) + for (item in L) + total -=L [item] + if (total <= 0) + return item + + return null + +//Pick a random element from the list and remove it from the list. +/proc/pick_n_take(list/listfrom) + if (listfrom.len > 0) + var/picked = pick(listfrom) + listfrom -= picked + return picked + return null + +//Returns the top(last) element from the list and removes it from the list (typical stack function) +/proc/pop(list/listfrom) + if (listfrom.len > 0) + var/picked = listfrom[listfrom.len] + listfrom.len-- + return picked + return null + +//Returns the next element in parameter list after first appearance of parameter element. If it is the last element of the list or not present in list, returns first element. +/proc/next_in_list(element, list/L) + for(var/i=1, i= 1; i--) + output += L[i] + return output + +//Randomize: Return the list in a random order +/proc/shuffle(var/list/L) + if(!L) + return + + L = L.Copy() + + for(var/i=1; i 0) ? i : i+1 + else + return i + + +/proc/dd_sortedObjectList(var/list/L, var/cache=list()) + if(L.len < 2) + return L + var/middle = L.len / 2 + 1 // Copy is first,second-1 + return dd_mergeObjectList(dd_sortedObjectList(L.Copy(0,middle), cache), dd_sortedObjectList(L.Copy(middle), cache), cache) //second parameter null = to end of list + +/proc/dd_mergeObjectList(var/list/L, var/list/R, var/list/cache) + var/Li=1 + var/Ri=1 + var/list/result = new() + while(Li <= L.len && Ri <= R.len) + var/LLi = L[Li] + var/RRi = R[Ri] + var/LLiV = cache[LLi] + var/RRiV = cache[RRi] + if(!LLiV) + LLiV = LLi:dd_SortValue() + cache[LLi] = LLiV + if(!RRiV) + RRiV = RRi:dd_SortValue() + cache[RRi] = RRiV + if(LLiV < RRiV) + result += L[Li++] + else + result += R[Ri++] + + if(Li <= L.len) + return (result + L.Copy(Li, 0)) + return (result + R.Copy(Ri, 0)) + +// Insert an object into a sorted list, preserving sortedness +/proc/dd_insertObjectList(var/list/L, var/O) + var/min = 1 + var/max = L.len + 1 + var/Oval = O:dd_SortValue() + + while(1) + var/mid = min+round((max-min)/2) + + if(mid == max) + L.Insert(mid, O) + return + + var/Lmid = L[mid] + var/midval = Lmid:dd_SortValue() + if(Oval == midval) + L.Insert(mid, O) + return + else if(Oval < midval) + max = mid + else + min = mid+1 + +/* +proc/dd_sortedObjectList(list/incoming) + /* + Use binary search to order by dd_SortValue(). + This works by going to the half-point of the list, seeing if the node in + question is higher or lower cost, then going halfway up or down the list + and checking again. This is a very fast way to sort an item into a list. + */ + var/list/sorted_list = new() + var/low_index + var/high_index + var/insert_index + var/midway_calc + var/current_index + var/current_item + var/current_item_value + var/current_sort_object_value + var/list/list_bottom + + var/current_sort_object + for (current_sort_object in incoming) + low_index = 1 + high_index = sorted_list.len + while (low_index <= high_index) + // Figure out the midpoint, rounding up for fractions. (BYOND rounds down, so add 1 if necessary.) + midway_calc = (low_index + high_index) / 2 + current_index = round(midway_calc) + if (midway_calc > current_index) + current_index++ + current_item = sorted_list[current_index] + + current_item_value = current_item:dd_SortValue() + current_sort_object_value = current_sort_object:dd_SortValue() + if (current_sort_object_value < current_item_value) + high_index = current_index - 1 + else if (current_sort_object_value > current_item_value) + low_index = current_index + 1 + else + // current_sort_object == current_item + low_index = current_index + break + + // Insert before low_index. + insert_index = low_index + + // Special case adding to end of list. + if (insert_index > sorted_list.len) + sorted_list += current_sort_object + continue + + // Because BYOND lists don't support insert, have to do it by: + // 1) taking out bottom of list, 2) adding item, 3) putting back bottom of list. + list_bottom = sorted_list.Copy(insert_index) + sorted_list.Cut(insert_index) + sorted_list += current_sort_object + sorted_list += list_bottom + return sorted_list +*/ + +proc/dd_sortedtextlist(list/incoming, case_sensitive = 0) + // Returns a new list with the text values sorted. + // Use binary search to order by sortValue. + // This works by going to the half-point of the list, seeing if the node in question is higher or lower cost, + // then going halfway up or down the list and checking again. + // This is a very fast way to sort an item into a list. + var/list/sorted_text = new() + var/low_index + var/high_index + var/insert_index + var/midway_calc + var/current_index + var/current_item + var/list/list_bottom + var/sort_result + + var/current_sort_text + for (current_sort_text in incoming) + low_index = 1 + high_index = sorted_text.len + while (low_index <= high_index) + // Figure out the midpoint, rounding up for fractions. (BYOND rounds down, so add 1 if necessary.) + midway_calc = (low_index + high_index) / 2 + current_index = round(midway_calc) + if (midway_calc > current_index) + current_index++ + current_item = sorted_text[current_index] + + if (case_sensitive) + sort_result = sorttextEx(current_sort_text, current_item) + else + sort_result = sorttext(current_sort_text, current_item) + + switch(sort_result) + if (1) + high_index = current_index - 1 // current_sort_text < current_item + if (-1) + low_index = current_index + 1 // current_sort_text > current_item + if (0) + low_index = current_index // current_sort_text == current_item + break + + // Insert before low_index. + insert_index = low_index + + // Special case adding to end of list. + if (insert_index > sorted_text.len) + sorted_text += current_sort_text + continue + + // Because BYOND lists don't support insert, have to do it by: + // 1) taking out bottom of list, 2) adding item, 3) putting back bottom of list. + list_bottom = sorted_text.Copy(insert_index) + sorted_text.Cut(insert_index) + sorted_text += current_sort_text + sorted_text += list_bottom + return sorted_text + + +proc/dd_sortedTextList(list/incoming) + var/case_sensitive = 1 + return dd_sortedtextlist(incoming, case_sensitive) + + +/datum/proc/dd_SortValue() + return "[src]" + +/obj/machinery/dd_SortValue() + return "[sanitize_old(name)]" + +/obj/machinery/camera/dd_SortValue() + return "[c_tag]" + +/datum/alarm/dd_SortValue() + return "[sanitize_old(last_name)]" + +#define subtypesof(prototype) (typesof(prototype) - prototype) + +//creates every subtype of prototype (excluding prototype) and adds it to list L. +//if no list/L is provided, one is created. +/proc/init_subtypes(prototype, list/L) + if(!istype(L)) L = list() + for(var/path in subtypesof(prototype)) + L += new path() + return L + +//creates every subtype of prototype (excluding prototype) and adds it to list L as a type/instance pair. +//if no list/L is provided, one is created. +/proc/init_subtypes_assoc(prototype, list/L) + if(!istype(L)) L = list() + for(var/path in subtypesof(prototype)) + L[path] = new path() + return L + +#define listequal(A, B) (A.len == B.len && !length(A^B)) + +/proc/filter_list(var/list/L, var/type) + . = list() + for(var/entry in L) + if(istype(entry, type)) + . += entry + +/proc/group_by(var/list/group_list, var/key, var/value) + var/values = group_list[key] + if(!values) + values = list() + group_list[key] = values + + values += value + +/proc/duplicates(var/list/L) + . = list() + var/list/checked = list() + for(var/value in L) + if(value in checked) + . |= value + else + checked += value + +/proc/assoc_by_proc(var/list/plain_list, var/get_initial_value) + . = list() + for(var/entry in plain_list) + .[call(get_initial_value)(entry)] = entry + +/proc/get_initial_name(var/atom/atom_type) + var/atom/A = atom_type + return initial(A.name) + +//Move a single element from position fromIndex within a list, to position toIndex +//All elements in the range [1,toIndex) before the move will be before the pivot afterwards +//All elements in the range [toIndex, L.len+1) before the move will be after the pivot afterwards +//In other words, it's as if the range [fromIndex,toIndex) have been rotated using a <<< operation common to other languages. +//fromIndex and toIndex must be in the range [1,L.len+1] +//This will preserve associations ~Carnie +/proc/moveElement(list/L, fromIndex, toIndex) + if(fromIndex == toIndex || fromIndex+1 == toIndex) //no need to move + return + if(fromIndex > toIndex) + ++fromIndex //since a null will be inserted before fromIndex, the index needs to be nudged right by one + + L.Insert(toIndex, null) + L.Swap(fromIndex, toIndex) + L.Cut(fromIndex, fromIndex+1) + +//Move elements [fromIndex,fromIndex+len) to [toIndex-len, toIndex) +//Same as moveElement but for ranges of elements +//This will preserve associations ~Carnie +/proc/moveRange(list/L, fromIndex, toIndex, len=1) + var/distance = abs(toIndex - fromIndex) + if(len >= distance) //there are more elements to be moved than the distance to be moved. Therefore the same result can be achieved (with fewer operations) by moving elements between where we are and where we are going. The result being, our range we are moving is shifted left or right by dist elements + if(fromIndex <= toIndex) + return //no need to move + fromIndex += len //we want to shift left instead of right + + for(var/i=0, i toIndex) + fromIndex += len + + for(var/i=0, i 0 && index <= list.len) diff --git a/code/_helpers/logging.dm b/code/_helpers/logging.dm new file mode 100644 index 00000000..c70fc7fd --- /dev/null +++ b/code/_helpers/logging.dm @@ -0,0 +1,228 @@ +//wrapper macros for easier grepping +#define DIRECT_OUTPUT(A, B) A << B +#define WRITE_FILE(file, text) DIRECT_OUTPUT(file, text) + + +// On Linux/Unix systems the line endings are LF, on windows it's CRLF, admins that don't use notepad++ +// will get logs that are one big line if the system is Linux and they are using notepad. This solves it by adding CR to every line ending +// in the logs. ascii character 13 = CR + +/var/global/log_end= world.system_type == UNIX ? ascii2text(13) : "" + + +/proc/error(msg) + to_world_log("## ERROR: [msg][log_end]") + +/proc/log_ss(subsystem, text, log_world = TRUE) + if (!subsystem) + subsystem = "UNKNOWN" + var/msg = "[subsystem]: [text]" + game_log("SS", msg) + if (log_world) + to_world_log("SS[subsystem]: [text]") + +/proc/log_ss_init(text) + game_log("SS", "[text]") + +#define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [src] usr: [usr].") +//print a warning message to world.log +/proc/warning(msg) + to_world_log("## WARNING: [msg][log_end]") + +//print a testing-mode debug message to world.log +/proc/testing(msg) + to_world_log("## TESTING: [msg][log_end]") + +/proc/game_log(category, text) + diary << "\[[time_stamp()]] [game_id] [category]: [text][log_end]" + +/proc/log_admin(text) + GLOB.admin_log.Add(text) + if (config.log_admin) + game_log("ADMIN", text) + +/proc/log_debug(text) + if (config.log_debug) + game_log("DEBUG", text) + to_debug_listeners(text) + +/proc/log_error(text) + error(text) + to_debug_listeners(text, "ERROR") + +/proc/log_warning(text) + warning(text) + to_debug_listeners(text, "WARNING") + +/proc/to_debug_listeners(text, prefix = "DEBUG") + for(var/client/C in GLOB.admins) + if(C.get_preference_value(/datum/client_preference/staff/show_debug_logs) == GLOB.PREF_SHOW) + to_chat(C, "[prefix]: [text]") + +/proc/log_game(text) + if (config.log_game) + game_log("GAME", text) + +/proc/log_vote(text) + if (config.log_vote) + game_log("VOTE", text) + +/proc/log_access(text) + if (config.log_access) + game_log("ACCESS", text) + +/proc/log_say(text) + if (config.log_say) + game_log("SAY", text) + +/proc/log_ooc(text) + if (config.log_ooc) + game_log("OOC", text) + +/proc/log_whisper(text) + if (config.log_whisper) + game_log("WHISPER", text) + +/proc/log_emote(text) + if (config.log_emote) + game_log("EMOTE", text) + +/proc/log_attack(text) + if (config.log_attack) + game_log("ATTACK", text) + +/proc/log_adminsay(text) + if (config.log_adminchat) + game_log("ADMINSAY", text) + +/proc/log_adminwarn(text) + if (config.log_adminwarn) + game_log("ADMINWARN", text) + +/proc/log_pda(text) + if (config.log_pda) + game_log("PDA", text) + +/proc/log_to_dd(text) + to_world_log(text) //this comes before the config check because it can't possibly runtime + if(config.log_world_output) + game_log("DD_OUTPUT", text) + +/proc/log_misc(text) + game_log("MISC", text) + +/proc/log_unit_test(text) + to_world_log("## UNIT_TEST ##: [text]") + log_debug(text) + +/proc/log_qdel(text) + WRITE_FILE(GLOB.world_qdel_log, "\[[time_stamp()]]QDEL: [text]") + +//This replaces world.log so it displays both in DD and the file +/proc/log_world(text) + if(config && config.log_runtime) + to_world_log(runtime_diary) + to_world_log(text) + to_world_log(null) + to_world_log(text) + +//pretty print a direction bitflag, can be useful for debugging. +/proc/dir_text(var/dir) + var/list/comps = list() + if(dir & NORTH) comps += "NORTH" + if(dir & SOUTH) comps += "SOUTH" + if(dir & EAST) comps += "EAST" + if(dir & WEST) comps += "WEST" + if(dir & UP) comps += "UP" + if(dir & DOWN) comps += "DOWN" + + return english_list(comps, nothing_text="0", and_text="|", comma_text="|") + +//more or less a logging utility +/proc/key_name(var/whom, var/include_link = null, var/include_name = 1, var/highlight_special_characters = 1, var/datum/ticket/ticket = null) + var/mob/M + var/client/C + var/key + + if(!whom) return "*null*" + if(istype(whom, /client)) + C = whom + M = C.mob + key = C.key + else if(ismob(whom)) + M = whom + C = M.client + key = M.key + else if(istype(whom, /datum/mind)) + var/datum/mind/D = whom + key = D.key + M = D.current + if(D.current) + C = D.current.client + else if(istype(whom, /datum)) + var/datum/D = whom + return "*invalid:[D.type]*" + else + return "*invalid*" + + . = "" + + if(key) + if(include_link && C) + . += "" + + . += key + + if(include_link) + if(C) . += "" + else . += " (DC)" + else + . += "*no key*" + + if(include_name && M) + var/name + + if(M.real_name) + name = M.real_name + else if(M.name) + name = M.name + + + if(include_link && is_special_character(M) && highlight_special_characters) + . += "/([name])" //Orange + else + . += "/([name])" + + return . + +/proc/key_name_admin(var/whom, var/include_name = 1) + return key_name(whom, 1, include_name) + +// Helper procs for building detailed log lines +/datum/proc/get_log_info_line() + return "[src] ([type]) ([any2ref(src)])" + +/area/get_log_info_line() + return "[..()] ([isnum(z) ? "[x],[y],[z]" : "0,0,0"])" + +/turf/get_log_info_line() + return "[..()] ([x],[y],[z]) ([loc ? loc.type : "NULL"])" + +/atom/movable/get_log_info_line() + var/turf/t = get_turf(src) + return "[..()] ([t ? t : "NULL"]) ([t ? "[t.x],[t.y],[t.z]" : "0,0,0"]) ([t ? t.type : "NULL"])" + +/mob/get_log_info_line() + return ckey ? "[..()] ([ckey])" : ..() + +/proc/log_info_line(var/datum/d) + if(isnull(d)) + return "*null*" + if(islist(d)) + var/list/L = list() + for(var/e in d) + L += log_info_line(e) + return "\[[jointext(L, ", ")]\]" // We format the string ourselves, rather than use json_encode(), because it becomes difficult to read recursively escaped " + if(!istype(d)) + return json_encode(d) + return d.get_log_info_line() diff --git a/code/_helpers/maths.dm b/code/_helpers/maths.dm new file mode 100644 index 00000000..7666e0af --- /dev/null +++ b/code/_helpers/maths.dm @@ -0,0 +1,134 @@ +// Macro functions. +#define RAND_F(LOW, HIGH) (rand()*(HIGH-LOW) + LOW) +#define ceil(x) (-round(-(x))) + +// min is inclusive, max is exclusive +/proc/Wrap(val, min, max) + var/d = max - min + var/t = Floor((val - min) / d) + return val - (t * d) + +/proc/Default(a, b) + return a ? a : b + +// Trigonometric functions. +/proc/Tan(x) + return sin(x) / cos(x) + +/proc/Csc(x) + return 1 / sin(x) + +/proc/Sec(x) + return 1 / cos(x) + +/proc/Cot(x) + return 1 / Tan(x) + +/proc/Atan2(x, y) + if(!x && !y) return 0 + var/a = arccos(x / sqrt(x*x + y*y)) + return y >= 0 ? a : -a + +/proc/Floor(x) + return round(x) + +/proc/Ceiling(x) + return -round(-x) + +// Greatest Common Divisor: Euclid's algorithm. +/proc/Gcd(a, b) + while (1) + if (!b) return a + a %= b + if (!a) return b + b %= a + +// Least Common Multiple. The formula is a consequence of: a*b = LCM*GCD. +/proc/Lcm(a, b) + return abs(a) * abs(b) / Gcd(a, b) + +// Useful in the cases when x is a large expression, e.g. x = 3a/2 + b^2 + Function(c) +/proc/Square(x) + return x*x + +/proc/Inverse(x) + return 1 / x + +// Condition checks. +/proc/IsAboutEqual(a, b, delta = 0.1) + return abs(a - b) <= delta + +// Returns true if val is from min to max, inclusive. +/proc/IsInRange(val, min, max) + return (val >= min) && (val <= max) + +/proc/IsInteger(x) + return Floor(x) == x + +/proc/IsMultiple(x, y) + return x % y == 0 + +/proc/IsEven(x) + return !(x & 0x1) + +/proc/IsOdd(x) + return (x & 0x1) + +// Performs a linear interpolation between a and b. +// Note: weight=0 returns a, weight=1 returns b, and weight=0.5 returns the mean of a and b. +/proc/Interpolate(a, b, weight = 0.5) + return a + (b - a) * weight // Equivalent to: a*(1 - weight) + b*weight + +/proc/Mean(...) + var/sum = 0 + for(var/val in args) + sum += val + return sum / args.len + +// Returns the nth root of x. +/proc/Root(n, x) + return x ** (1 / n) + +// The quadratic formula. Returns a list with the solutions, or an empty list +// if they are imaginary. +/proc/SolveQuadratic(a, b, c) + ASSERT(a) + + . = list() + var/discriminant = b*b - 4*a*c + var/bottom = 2*a + + // Return if the roots are imaginary. + if(discriminant < 0) + return + + var/root = sqrt(discriminant) + . += (-b + root) / bottom + + // If discriminant == 0, there would be two roots at the same position. + if(discriminant != 0) + . += (-b - root) / bottom + +/proc/ToDegrees(radians) + // 180 / Pi ~ 57.2957795 + return radians * 57.2957795 + +/proc/ToRadians(degrees) + // Pi / 180 ~ 0.0174532925 + return degrees * 0.0174532925 + +// Vector algebra. +/proc/squaredNorm(x, y) + return x*x + y*y + +/proc/norm(x, y) + return sqrt(squaredNorm(x, y)) + +/proc/IsPowerOfTwo(var/val) + return (val & (val-1)) == 0 + +/proc/RoundUpToPowerOfTwo(var/val) + return 2 ** -round(-log(2,val)) + +/proc/Modulus(x, y) + return ( (x) - (y) * round((x) / (y)) ) \ No newline at end of file diff --git a/code/_helpers/matrices.dm b/code/_helpers/matrices.dm new file mode 100644 index 00000000..9aedfe0c --- /dev/null +++ b/code/_helpers/matrices.dm @@ -0,0 +1,115 @@ +/matrix/proc/TurnTo(old_angle, new_angle) + . = new_angle - old_angle + Turn(.) //BYOND handles cases such as -270, 360, 540 etc. DOES NOT HANDLE 180 TURNS WELL, THEY TWEEN AND LOOK LIKE SHIT + + +/atom/proc/SpinAnimation(speed = 10, loops = -1) + var/matrix/m120 = matrix(transform) + m120.Turn(120) + var/matrix/m240 = matrix(transform) + m240.Turn(240) + var/matrix/m360 = matrix(transform) + speed /= 3 //Gives us 3 equal time segments for our three turns. + //Why not one turn? Because byond will see that the start and finish are the same place and do nothing + //Why not two turns? Because byond will do a flip instead of a turn + animate(src, transform = m120, time = speed, loops) + animate(transform = m240, time = speed) + animate(transform = m360, time = speed) + +//The X pixel offset of this matrix +/matrix/proc/get_x_shift() + . = c + +//The Y pixel offset of this matrix +/matrix/proc/get_y_shift() + . = f +// Color matrices: + +//Luma coefficients suggested for HDTVs. If you change these, make sure they add up to 1. +#define LUMR 0.2126 +#define LUMG 0.7152 +#define LUMB 0.0722 + +//Still need color matrix addition, negation, and multiplication. + +//Returns an identity color matrix which does nothing +/proc/color_identity() + return list(1,0,0, 0,1,0, 0,0,1) + +//Moves all colors angle degrees around the color wheel while maintaining intensity of the color and not affecting whites +//TODO: Need a version that only affects one color (ie shift red to blue but leave greens and blues alone) +/proc/color_rotation(angle) + if(angle == 0) + return color_identity() + angle = Clamp(angle, -180, 180) + var/cos = cos(angle) + var/sin = sin(angle) + + var/constA = 0.143 + var/constB = 0.140 + var/constC = -0.283 + return list( + LUMR + cos * (1-LUMR) + sin * -LUMR, LUMR + cos * -LUMR + sin * constA, LUMR + cos * -LUMR + sin * -(1-LUMR), + LUMG + cos * -LUMG + sin * -LUMG, LUMG + cos * (1-LUMG) + sin * constB, LUMG + cos * -LUMG + sin * LUMG, + LUMB + cos * -LUMB + sin * (1-LUMB), LUMB + cos * -LUMB + sin * constC, LUMB + cos * (1-LUMB) + sin * LUMB + ) + +//Makes everything brighter or darker without regard to existing color or brightness +/proc/color_brightness(power) + power = Clamp(power, -255, 255) + power = power/255 + + return list(1,0,0, 0,1,0, 0,0,1, power,power,power) + +/var/list/delta_index = list( + 0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11, + 0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24, + 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42, + 0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68, + 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98, + 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54, + 1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25, + 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8, + 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0, + 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8, + 10.0) + +//Exxagerates or removes brightness +/proc/color_contrast(value) + value = Clamp(value, -100, 100) + if(value == 0) + return color_identity() + + var/x = 0 + if (value < 0) + x = 127 + value / 100 * 127; + else + x = value % 1 + if(x == 0) + x = delta_index[value] + else + x = delta_index[value] * (1-x) + delta_index[value+1] * x//use linear interpolation for more granularity. + x = x * 127 + 127 + + var/mult = x / 127 + var/add = 0.5 * (127-x) / 255 + return list(mult,0,0, 0,mult,0, 0,0,mult, add,add,add) + +//Exxagerates or removes colors +/proc/color_saturation(value as num) + if(value == 0) + return color_identity() + value = Clamp(value, -100, 100) + if(value > 0) + value *= 3 + var/x = 1 + value / 100 + var/inv = 1 - x + var/R = LUMR * inv + var/G = LUMG * inv + var/B = LUMB * inv + + return list(R + x,R,R, G,G + x,G, B,B,B + x) + +#undef LUMR +#undef LUMG +#undef LUMB \ No newline at end of file diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm new file mode 100644 index 00000000..a55b5bc1 --- /dev/null +++ b/code/_helpers/mobs.dm @@ -0,0 +1,308 @@ +/atom/movable/proc/get_mob() + return + +/obj/mecha/get_mob() + return occupant + +/obj/vehicle/train/get_mob() + return buckled_mob + +/mob/get_mob() + return src + +/mob/living/bot/mulebot/get_mob() + if(load && istype(load, /mob/living)) + return list(src, load) + return src + +//helper for inverting armor blocked values into a multiplier +#define blocked_mult(blocked) max(1 - (blocked/100), 0) + +/proc/mobs_in_view(var/range, var/source) + var/list/mobs = list() + for(var/atom/movable/AM in view(range, source)) + var/M = AM.get_mob() + if(M) + mobs += M + + return mobs + +proc/random_hair_style(gender, species = SPECIES_HUMAN) + var/h_style = "Bald" + + var/datum/species/mob_species = all_species[species] + var/list/valid_hairstyles = mob_species.get_hair_styles() + if(valid_hairstyles.len) + h_style = pick(valid_hairstyles) + + return h_style + +proc/random_facial_hair_style(gender, var/species = SPECIES_HUMAN) + var/f_style = "Shaved" + + var/datum/species/mob_species = all_species[species] + var/list/valid_facialhairstyles = mob_species.get_facial_hair_styles(gender) + if(valid_facialhairstyles.len) + f_style = pick(valid_facialhairstyles) + + return f_style + +proc/sanitize_name(name, species = SPECIES_HUMAN) + var/datum/species/current_species + if(species) + current_species = all_species[species] + + return current_species ? current_species.sanitize_name(name) : sanitizeName(name) + +proc/random_name(gender, species = SPECIES_HUMAN) + + var/datum/species/current_species + if(species) + current_species = all_species[species] + + if(!current_species) + if(gender==FEMALE) + return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) + else + return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) + else + return current_species.get_random_name(gender) + +proc/random_skinless_name(gender) + if(gender==FEMALE) + return capitalize(pick(GLOB.first_names_female)) + " " + "The Lost" + else + return capitalize(pick(GLOB.first_names_male)) + " " + "The Lost" +proc/random_lackey_name() + return "Worthless Lackey" + " " + capitalize(pick(GLOB.last_names)) + +proc/random_skin_tone(var/datum/species/current_species) + var/species_tone = current_species ? 35 - current_species.max_skin_tone() : -185 + switch(pick(60;"caucasian", 15;"afroamerican", 10;"african", 10;"latino", 5;"albino")) + if("caucasian") . = -10 + if("afroamerican") . = -115 + if("african") . = -165 + if("latino") . = -55 + if("albino") . = 34 + else . = rand(species_tone,34) + + return min(max(. + rand(-25, 25), species_tone), 34) + +proc/skintone2racedescription(tone) + switch (tone) + if(30 to INFINITY) return "albino" + if(20 to 30) return "pale" + if(5 to 15) return "light skinned" + if(-10 to 5) return "white" + if(-25 to -10) return "tan" + if(-45 to -25) return "darker skinned" + if(-65 to -45) return "brown" + if(-INFINITY to -65) return "black" + else return "unknown" + +proc/age2agedescription(age) + switch(age) + if(0 to 1) return "infant" + if(1 to 3) return "toddler" + if(3 to 13) return "child" + if(13 to 19) return "teenager" + if(19 to 30) return "young adult" + if(30 to 45) return "adult" + if(45 to 60) return "middle-aged" + if(60 to 70) return "aging" + if(70 to INFINITY) return "elderly" + else return "unknown" + +proc/ageAndGender2Desc(age, gender)//Used for the radio + if(gender == FEMALE) + switch(age) + if(0 to 15) return "Girl" + if(15 to 25) return "Young Woman" + if(25 to 60) return "Woman" + if(60 to INFINITY) return "Old Woman" + else return "Unknown" + else + switch(age) + if(0 to 15) return "Boy" + if(15 to 25) return "Young Man" + if(25 to 60) return "Man" + if(60 to INFINITY) return "Old Man" + else return "Unknown" + +/proc/RoundHealth(health) + var/list/icon_states = icon_states('icons/mob/hud_med.dmi') + for(var/icon_state in icon_states) + if(health >= text2num(icon_state)) + return icon_state + return icon_states[icon_states.len] // If we had no match, return the last element + +//checks whether this item is a module of the robot it is located in. +/proc/is_robot_module(var/obj/item/thing) + if (!thing || !istype(thing.loc, /mob/living/silicon/robot)) + return 0 + var/mob/living/silicon/robot/R = thing.loc + return (thing in R.module.modules) + + +/proc/get_exposed_defense_zone(var/atom/movable/target) + return pick(BP_HEAD, BP_L_HAND, BP_R_HAND, BP_L_FOOT, BP_R_FOOT, BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG, BP_CHEST, BP_GROIN) + + +/proc/do_mob(mob/user , mob/target, time = 30, target_zone = 0, uninterruptible = 0, progress = 1) + if(!user || !target) + return 0 + var/user_loc = user.loc + var/target_loc = target.loc + + var/holding = user.get_active_hand() + var/datum/progressbar/progbar + if (progress) + progbar = new(user, time, target) + + var/endtime = world.time+time + var/starttime = world.time + . = 1 + while (world.time < endtime) + sleep(1) + if (progress) + progbar.update(world.time - starttime) + if(!user || !target) + . = 0 + break + if(uninterruptible) + continue + + if(!user || user.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_KNOCKOUT) || user.loc != user_loc) + . = 0 + break + + if(target.loc != target_loc) + . = 0 + break + + if(user.get_active_hand() != holding) + . = 0 + break + + if(target_zone && user.zone_sel.selecting != target_zone) + . = 0 + break + + if (progbar) + qdel(progbar) + +/proc/do_after(mob/user, delay, atom/target = null, needhand = 1, progress = 1, var/incapacitation_flags = INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_KNOCKOUT, var/same_direction = 0) + if(!user) + return 0 + var/atom/target_loc = null + var/target_type = null + + var/original_dir = user.dir + + if(target) + target_loc = target.loc + target_type = target.type + + var/atom/original_loc = user.loc + + var/holding = user.get_active_hand() + + var/datum/progressbar/progbar + if (progress) + progbar = new(user, delay, target) + + var/endtime = world.time + delay + var/starttime = world.time + . = 1 + while (world.time < endtime) + sleep(1) + if (progress) + progbar.update(world.time - starttime) + + if(!user || user.incapacitated(incapacitation_flags) || user.loc != original_loc || (same_direction && user.dir != original_dir)) + . = 0 + break + + if(target_loc && (!target || QDELETED(target) || target_loc != target.loc || target_type != target.type)) + . = 0 + break + + if(needhand) + if(user.get_active_hand() != holding) + . = 0 + break + + if (progbar) + qdel(progbar) + +/proc/able_mobs_in_oview(var/origin) + var/list/mobs = list() + for(var/mob/living/M in oview(origin)) // Only living mobs are considered able. + if(!M.is_physically_disabled()) + mobs += M + return mobs + +// Returns true if M was not already in the dead mob list +/mob/proc/switch_from_living_to_dead_mob_list() + remove_from_living_mob_list() + . = add_to_dead_mob_list() + +// Returns true if M was not already in the living mob list +/mob/proc/switch_from_dead_to_living_mob_list() + remove_from_dead_mob_list() + . = add_to_living_mob_list() + +// Returns true if the mob was in neither the dead or living list +/mob/proc/add_to_living_mob_list() + return FALSE +/mob/living/add_to_living_mob_list() + if((src in GLOB.living_mob_list_) || (src in GLOB.dead_mob_list_)) + return FALSE + GLOB.living_mob_list_ += src + return TRUE + +// Returns true if the mob was removed from the living list +/mob/proc/remove_from_living_mob_list() + return GLOB.living_mob_list_.Remove(src) + +// Returns true if the mob was in neither the dead or living list +/mob/proc/add_to_dead_mob_list() + return FALSE +/mob/living/add_to_dead_mob_list() + if((src in GLOB.living_mob_list_) || (src in GLOB.dead_mob_list_)) + return FALSE + GLOB.dead_mob_list_ += src + return TRUE + +// Returns true if the mob was removed form the dead list +/mob/proc/remove_from_dead_mob_list() + return GLOB.dead_mob_list_.Remove(src) + +//Find a dead mob with a brain and client. +/proc/find_dead_player(var/find_key, var/include_observers = 0) + if(isnull(find_key)) + return + + var/mob/selected = null + + if(include_observers) + for(var/mob/M in GLOB.player_list) + if((M.stat != DEAD) || (!M.client)) + continue + if(M.ckey == find_key) + selected = M + break + else + for(var/mob/living/M in GLOB.player_list) + //Dead people only thanks! + if((M.stat != DEAD) || (!M.client)) + continue + //They need a brain! + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(H.should_have_organ(BP_BRAIN) && !H.has_brain()) + continue + if(M.ckey == find_key) + selected = M + break + return selected \ No newline at end of file diff --git a/code/_helpers/names.dm b/code/_helpers/names.dm new file mode 100644 index 00000000..c765b1f6 --- /dev/null +++ b/code/_helpers/names.dm @@ -0,0 +1,244 @@ +var/church_name = null +/proc/church_name() + if (church_name) + return church_name + + var/name = "" + + name += pick("Holy", "United", "First", "Second", "Last") + + if (prob(20)) + name += " Space" + + name += " " + pick("Church", "Cathedral", "Body", "Worshippers", "Movement", "Witnesses") + name += " of [religion_name()]" + + return name + +var/command_name = null +/proc/command_name() + if (command_name) + return command_name + + var/name = "[GLOB.using_map.boss_name]" + + command_name = name + return name + +/proc/change_command_name(var/name) + + command_name = name + + return name + +var/religion_name = null +/proc/religion_name() + if (religion_name) + return religion_name + + var/name = "" + + name += pick("bee", "science", "edu", "captain", "assistant", "monkey", "alien", "space", "unit", "sprocket", "gadget", "bomb", "revolution", "beyond", "station", "goon", "robot", "ivor", "hobnob") + name += pick("ism", "ia", "ology", "istism", "ites", "ick", "ian", "ity") + + return capitalize(name) + +/proc/system_name() + return GLOB.using_map.system_name ? GLOB.using_map.system_name : generate_system_name() + +/proc/generate_system_name() + return "[pick("Gilese","GSC", "Luyten", "GJ", "HD", "SCGECO")][prob(10) ? " Eridani" : ""] [rand(100,999)]" + +/proc/generate_planet_name() + return "[capitalize(pick(GLOB.last_names))]-[pick(GLOB.greek_letters)]" + +/proc/generate_planet_type() + return pick("terrestial planet", "ice planet", "dwarf planet", "desert planet", "ocean planet", "lava planet", "gas giant", "forest planet") + +/proc/station_name() + if(!GLOB.using_map) + return server_name + if (GLOB.using_map.station_name) + return GLOB.using_map.station_name + + var/random = rand(1,5) + var/name = "" + + //Rare: Pre-Prefix + if (prob(10)) + name = pick(GLOB.station_prefixes) + GLOB.using_map.station_name = name + " " + + // Prefix + switch(Holiday) + //get normal name + if(null,"",0) + name = pick(GLOB.station_names) + if(name) + GLOB.using_map.station_name += name + " " + + //For special days like christmas, easter, new-years etc ~Carn + if("Friday the 13th") + name = pick("Mike","Friday","Evil","Myers","Murder","Deathly","Stabby") + GLOB.using_map.station_name += name + " " + random = 13 + else + //get the first word of the Holiday and use that + var/i = findtext(Holiday," ",1,0) + name = copytext(Holiday,1,i) + GLOB.using_map.station_name += name + " " + + // Suffix + name = pick(GLOB.station_suffixes) + GLOB.using_map.station_name += name + " " + + // ID Number + switch(random) + if(1) + GLOB.using_map.station_name += "[rand(1, 99)]" + if(2) + GLOB.using_map.station_name += pick(GLOB.greek_letters) + if(3) + GLOB.using_map.station_name += "\Roman[rand(1,99)]" + if(4) + GLOB.using_map.station_name += pick(GLOB.phonetic_alphabet) + if(5) + GLOB.using_map.station_name += pick(GLOB.numbers_as_words) + if(13) + GLOB.using_map.station_name += pick("13","XIII","Thirteen") + + + if (config && config.server_name) + world.name = "[config.server_name]: [name]" + else + world.name = GLOB.using_map.station_name + + return GLOB.using_map.station_name + +/proc/world_name(var/name) + GLOB.using_map.station_name = name + + if (config && config.server_name) + world.name = "[config.server_name]: [name]" + else + world.name = name + + return name + +var/syndicate_name = null +/proc/syndicate_name() + if (syndicate_name) + return syndicate_name + + var/name = "" + + // Prefix + name += pick("Clandestine", "Prima", "Blue", "Zero-G", "Max", "Blasto", "Waffle", "North", "Omni", "Newton", "Cyber", "Bonk", "Gene", "Gib") + + // Suffix + if (prob(80)) + name += " " + + // Full + if (prob(60)) + name += pick("Syndicate", "Consortium", "Collective", "Corporation", "Group", "Holdings", "Biotech", "Industries", "Systems", "Products", "Chemicals", "Enterprises", "Family", "Creations", "International", "Intergalactic", "Interplanetary", "Foundation", "Positronics", "Hive") + // Broken + else + name += pick("Syndi", "Corp", "Bio", "System", "Prod", "Chem", "Inter", "Hive") + name += pick("", "-") + name += pick("Tech", "Sun", "Co", "Tek", "X", "Inc", "Code") + // Small + else + name += pick("-", "*", "") + name += pick("Tech", "Sun", "Co", "Tek", "X", "Inc", "Gen", "Star", "Dyne", "Code", "Hive") + + syndicate_name = name + return name + + +//Traitors and traitor silicons will get these. Revs will not. +var/syndicate_code_phrase //Code phrase for traitors. +var/syndicate_code_response //Code response for traitors. + + /* + Should be expanded. + How this works: + Instead of "I'm looking for James Smith," the traitor would say "James Smith" as part of a conversation. + Another traitor may then respond with: "They enjoy running through the void-filled vacuum of the derelict." + The phrase should then have the words: James Smith. + The response should then have the words: run, void, and derelict. + This way assures that the code is suited to the conversation and is unpredicatable. + Obviously, some people will be better at this than others but in theory, everyone should be able to do it and it only enhances roleplay. + Can probably be done through "{ }" but I don't really see the practical benefit. + One example of an earlier system is commented below. + -N + */ + +/proc/generate_code_phrase()//Proc is used for phrase and response in master_controller.dm + + var/code_phrase = ""//What is returned when the proc finishes. + var/words = pick(//How many words there will be. Minimum of two. 2, 4 and 5 have a lesser chance of being selected. 3 is the most likely. + 50; 2, + 200; 3, + 50; 4, + 25; 5 + ) + + var/safety[] = list(1,2,3)//Tells the proc which options to remove later on. + var/nouns[] = list("love","hate","anger","peace","pride","sympathy","bravery","loyalty","honesty","integrity","compassion","charity","success","courage","deceit","skill","beauty","brilliance","pain","misery","beliefs","dreams","justice","truth","faith","liberty","knowledge","thought","information","culture","trust","dedication","progress","education","hospitality","leisure","trouble","friendships", "relaxation") + var/drinks[] = list("vodka and tonic","gin fizz","bahama mama","manhattan","black Russian","whiskey soda","long island tea","margarita","Irish coffee"," manly dwarf","Irish cream","doctor's delight","Beepksy Smash","tequilla sunrise","brave bull","gargle blaster","bloody mary","whiskey cola","white Russian","vodka martini","martini","Cuba libre","kahlua","vodka","wine","moonshine") + var/locations[] = length(stationlocs) ? stationlocs : drinks//if null, defaults to drinks instead. + + var/names[] = list() + for(var/datum/computer_file/crew_record/t in GLOB.all_crew_records)//Picks from crew manifest. + names += t.get_name() + + var/maxwords = words//Extra var to check for duplicates. + + for(words,words>0,words--)//Randomly picks from one of the choices below. + + if(words==1&&(1 in safety)&&(2 in safety))//If there is only one word remaining and choice 1 or 2 have not been selected. + safety = list(pick(1,2))//Select choice 1 or 2. + else if(words==1&&maxwords==2)//Else if there is only one word remaining (and there were two originally), and 1 or 2 were chosen, + safety = list(3)//Default to list 3 + + switch(pick(safety))//Chance based on the safety list. + if(1)//1 and 2 can only be selected once each to prevent more than two specific names/places/etc. + switch(rand(1,2))//Mainly to add more options later. + if(1) + if(names.len&&prob(70)) + code_phrase += pick(names) + else + code_phrase += pick(pick(GLOB.first_names_male,GLOB.first_names_female)) + code_phrase += " " + code_phrase += pick(GLOB.last_names) + if(2) + code_phrase += pick(joblist)//Returns a job. + safety -= 1 + if(2) + switch(rand(1,2))//Places or things. + if(1) + code_phrase += pick(drinks) + if(2) + code_phrase += pick(locations) + safety -= 2 + if(3) + switch(rand(1,3))//Nouns, adjectives, verbs. Can be selected more than once. + if(1) + code_phrase += pick(nouns) + if(2) + code_phrase += pick(GLOB.adjectives) + if(3) + code_phrase += pick(GLOB.verbs) + if(words==1) + code_phrase += "." + else + code_phrase += ", " + + return code_phrase + +/proc/get_name(var/atom/A) + return A.name + +/proc/get_name_and_coordinates(var/atom/A) + return "[A.name] \[[A.x],[A.y],[A.z]\]" diff --git a/code/_helpers/russian.dm b/code/_helpers/russian.dm new file mode 100644 index 00000000..ec714c19 --- /dev/null +++ b/code/_helpers/russian.dm @@ -0,0 +1,187 @@ +/proc/rhtml_encode(var/msg) + msg = replacetext(msg, "<", "<") + msg = replacetext(msg, ">", ">") + msg = replacetext(msg, "ÿ", "ÿ") + return msg + +/proc/rhtml_decode(var/msg) + msg = replacetext(msg, ">", ">") + msg = replacetext(msg, "<", "<") + msg = replacetext(msg, "ÿ", "ÿ") + return msg + + +//UPPER/LOWER TEXT + RUS TO CP1251 TODO: OVERRIDE uppertext +/proc/ruppertext(text as text) + text = uppertext(text) + var/t = "" + for(var/i = 1, i <= length(text), i++) + var/a = text2ascii(text, i) + if (a > 223) + t += ascii2text(a - 32) + else if (a == 184) + t += ascii2text(168) + else t += ascii2text(a) + t = replacetext(t,"ÿ","ß") + return t + +/proc/rlowertext(text as text) + text = lowertext(text) + var/t = "" + for(var/i = 1, i <= length(text), i++) + var/a = text2ascii(text, i) + if (a > 191 && a < 224) + t += ascii2text(a + 32) + else if (a == 168) + t += ascii2text(184) + else t += ascii2text(a) + return t + + +//RUS CONVERTERS +/proc/russian_to_cp1251(var/msg)//CHATBOX + return replacetext(msg, "ÿ", "ÿ") + +/proc/russian_to_utf8(var/msg)//PDA PAPER POPUPS + return replacetext(msg, "ÿ", "я") + +/proc/utf8_to_cp1251(msg) + return replacetext(msg, "я", "ÿ") + +/proc/cp1251_to_utf8(msg) + return replacetext(msg, "ÿ", "я") + +//Prepare text for edit. Replace "y" with "\?" for edition. Don't forget to call post_edit(). +/proc/edit_cp1251(msg) + return replacetext(msg, "ÿ", "\\ß") + +/proc/edit_utf8(msg) + return replacetext(msg, "я", "\\ß") + +/proc/post_edit_cp1251(msg) + return replacetext(msg, "\\ß", "ÿ") + +/proc/post_edit_utf8(msg) + return replacetext(msg, "\\ß", "я") + +//input + +/proc/input_cp1251(var/mob/user = usr, var/message, var/title, var/default, var/type = "message") + var/msg = "" + switch(type) + if("message") + msg = input(user, message, title, edit_cp1251(default)) as message + if("text") + msg = input(user, message, title, default) as text + msg = russian_to_cp1251(msg) + return post_edit_cp1251(msg) + +/proc/input_utf8(var/mob/user = usr, var/message, var/title, var/default, var/type = "message") + var/msg = "" + switch(type) + if("message") + msg = input(user, message, title, edit_utf8(default)) as message + if("text") + msg = input(user, message, title, default) as text + msg = russian_to_utf8(msg) + return post_edit_utf8(msg) + + +var/global/list/rkeys = list( + "à" = "f", "â" = "d", "ã" = "u", "ä" = "l", + "å" = "t", "ç" = "p", "è" = "b", "é" = "q", + "ê" = "r", "ë" = "k", "ì" = "v", "í" = "y", + "î" = "j", "ï" = "g", "ð" = "h", "ñ" = "c", + "ò" = "n", "ó" = "e", "ô" = "a", "ö" = "w", + "÷" = "x", "ø" = "i", "ù" = "o", "û" = "s", + "ü" = "m", "ÿ" = "z" +) + +//Transform keys from russian keyboard layout to eng analogues and lowertext it. +/proc/sanitize_key(t) + t = rlowertext(t) + if(t in rkeys) return rkeys[t] + return (t) + +//TEXT MODS RUS +/proc/capitalize_cp1251(var/t as text) + var/s = 2 + if (copytext(t,1,2) == ";") + s += 1 + else if (copytext(t,1,2) == ":") + s += 2 + return ruppertext(copytext(t, 1, s)) + copytext(t, s) + +/proc/intonation(text) + if (copytext(text,-1) == "!") + text = "[text]" + return text + +/proc/rustoutf(text) //fucking tghui + text = replacetext(text, "à", "а") + text = replacetext(text, "á", "б") + text = replacetext(text, "â", "в") + text = replacetext(text, "ã", "г") + text = replacetext(text, "ä", "д") + text = replacetext(text, "å", "е") + text = replacetext(text, "¸", "ё") + text = replacetext(text, "æ", "ж") + text = replacetext(text, "ç", "з") + text = replacetext(text, "è", "и") + text = replacetext(text, "é", "й") + text = replacetext(text, "ê", "к") + text = replacetext(text, "ë", "л") + text = replacetext(text, "ì", "м") + text = replacetext(text, "í", "н") + text = replacetext(text, "î", "о") + text = replacetext(text, "ï", "п") + text = replacetext(text, "ð", "р") + text = replacetext(text, "ñ", "с") + text = replacetext(text, "ò", "т") + text = replacetext(text, "ó", "у") + text = replacetext(text, "ô", "ф") + text = replacetext(text, "õ", "х") + text = replacetext(text, "ö", "ц") + text = replacetext(text, "÷", "ч") + text = replacetext(text, "ø", "ш") + text = replacetext(text, "ù", "щ") + text = replacetext(text, "ú", "ъ") + text = replacetext(text, "û", "ы") + text = replacetext(text, "ü", "ь") + text = replacetext(text, "ý", "э") + text = replacetext(text, "þ", "ю") + text = replacetext(text, "ÿ", "я") + text = replacetext(text, "À", "А") + text = replacetext(text, "Á", "Б") + text = replacetext(text, "Â", "В") + text = replacetext(text, "Ã", "Г") + text = replacetext(text, "Ä", "Д") + text = replacetext(text, "Å", "Е") + text = replacetext(text, "¨", "Ё") + text = replacetext(text, "Æ", "Ж") + text = replacetext(text, "Ç", "З") + text = replacetext(text, "È", "И") + text = replacetext(text, "É", "Й") + text = replacetext(text, "Ê", "К") + text = replacetext(text, "Ë", "Л") + text = replacetext(text, "Ì", "М") + text = replacetext(text, "Í", "Н") + text = replacetext(text, "Î", "О") + text = replacetext(text, "Ï", "П") + text = replacetext(text, "Ð", "Р") + text = replacetext(text, "Ñ", "С") + text = replacetext(text, "Ò", "Т") + text = replacetext(text, "Ó", "У") + text = replacetext(text, "Ô", "Ф") + text = replacetext(text, "Õ", "Х") + text = replacetext(text, "Ö", "Ц") + text = replacetext(text, "×", "Ч") + text = replacetext(text, "Ø", "Ш") + text = replacetext(text, "Ù", "Щ") + text = replacetext(text, "Ú", "Ъ") + text = replacetext(text, "Û", "Ы") + text = replacetext(text, "Ü", "Ь") + text = replacetext(text, "Ý", "Э") + text = replacetext(text, "Þ", "Ю") + text = replacetext(text, "ß", "Я") + return text \ No newline at end of file diff --git a/code/_helpers/sanitize_values.dm b/code/_helpers/sanitize_values.dm new file mode 100644 index 00000000..17f3d44e --- /dev/null +++ b/code/_helpers/sanitize_values.dm @@ -0,0 +1,49 @@ +//general stuff +/proc/sanitize_bool(boolean, default=FALSE) + return sanitize_integer(boolean, FALSE, TRUE, default) + +/proc/sanitize_integer(number, min=0, max=1, default=0) + if(isnum(number)) + number = round(number) + if(min <= number && number <= max) + return number + return default + +/proc/sanitize_text(text, default="") + if(istext(text)) + return text + return default + +/proc/sanitize_inlist(value, list/List, default) + if(value in List) return value + if(default) return default + if(List && List.len)return List[1] + + + +//more specialised stuff +/proc/sanitize_gender(gender,neuter=0,plural=0, default="male") + switch(gender) + if(MALE, FEMALE)return gender + if(NEUTER) + if(neuter) return gender + else return default + if(PLURAL) + if(plural) return gender + else return default + return default + +/proc/sanitize_hexcolor(color, default="#000000") + if(!istext(color)) return default + var/len = length(color) + if(len != 7 && len !=4) return default + if(text2ascii(color,1) != 35) return default //35 is the ascii code for "#" + . = "#" + for(var/i=2,i<=len,i++) + var/ascii = text2ascii(color,i) + switch(ascii) + if(48 to 57) . += ascii2text(ascii) //numbers 0 to 9 + if(97 to 102) . += ascii2text(ascii) //letters a to f + if(65 to 70) . += ascii2text(ascii+32) //letters A to F - translates to lowercase + else return default + return . diff --git a/code/_helpers/sorts/TimSort.dm b/code/_helpers/sorts/TimSort.dm new file mode 100644 index 00000000..4aa51263 --- /dev/null +++ b/code/_helpers/sorts/TimSort.dm @@ -0,0 +1,17 @@ +//TimSort interface +/proc/sortTim(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex=0) + if(L && L.len >= 2) + fromIndex = fromIndex % L.len + toIndex = toIndex % (L.len+1) + if(fromIndex <= 0) + fromIndex += L.len + if(toIndex <= 0) + toIndex += L.len + 1 + + sortInstance.L = L + sortInstance.cmp = cmp + sortInstance.associative = associative + + sortInstance.timSort(fromIndex, toIndex) + + return L \ No newline at end of file diff --git a/code/_helpers/sorts/__main.dm b/code/_helpers/sorts/__main.dm new file mode 100644 index 00000000..622d88f1 --- /dev/null +++ b/code/_helpers/sorts/__main.dm @@ -0,0 +1,656 @@ + //These are macros used to reduce on proc calls +#define fetchElement(L, i) (associative) ? L[L[i]] : L[i] + + //Minimum sized sequence that will be merged. Anything smaller than this will use binary-insertion sort. + //Should be a power of 2 +#define MIN_MERGE 32 + + //When we get into galloping mode, we stay there until both runs win less often than MIN_GALLOP consecutive times. +#define MIN_GALLOP 7 + + //This is a global instance to allow much of this code to be reused. The interfaces are kept separately +var/datum/sortInstance/sortInstance = new() +/datum/sortInstance + //The array being sorted. + var/list/L + + //The comparator proc-reference + var/cmp = /proc/cmp_numeric_asc + + //whether we are sorting list keys (0: L[i]) or associated values (1: L[L[i]]) + var/associative = 0 + + //This controls when we get *into* galloping mode. It is initialized to MIN_GALLOP. + //The mergeLo and mergeHi methods nudge it higher for random data, and lower for highly structured data. + var/minGallop = MIN_GALLOP + + //Stores information regarding runs yet to be merged. + //Run i starts at runBase[i] and extends for runLen[i] elements. + //runBase[i] + runLen[i] == runBase[i+1] + //var/stackSize + var/list/runBases = list() + var/list/runLens = list() + + +/datum/sortInstance/proc/timSort(start, end) + runBases.Cut() + runLens.Cut() + + var/remaining = end - start + + //If array is small, do a 'mini-TimSort' with no merges + if(remaining < MIN_MERGE) + var/initRunLen = countRunAndMakeAscending(start, end) + binarySort(start, end, start+initRunLen) + return + + //March over the array finding natural runs + //Extend any short natural runs to runs of length minRun + var/minRun = minRunLength(remaining) + + do + //identify next run + var/runLen = countRunAndMakeAscending(start, end) + + //if run is short, extend to min(minRun, remaining) + if(runLen < minRun) + var/force = (remaining <= minRun) ? remaining : minRun + + binarySort(start, start+force, start+runLen) + runLen = force + + //add data about run to queue + runBases.Add(start) + runLens.Add(runLen) + + //maybe merge + mergeCollapse() + + //Advance to find next run + start += runLen + remaining -= runLen + + while(remaining > 0) + + + //Merge all remaining runs to complete sort + //ASSERT(start == end) + mergeForceCollapse(); + //ASSERT(runBases.len == 1) + + //reset minGallop, for successive calls + minGallop = MIN_GALLOP + + return L + +/* +Sorts the specified portion of the specified array using a binary +insertion sort. This is the best method for sorting small numbers +of elements. It requires O(n log n) compares, but O(n^2) data +movement (worst case). + +If the initial part of the specified range is already sorted, +this method can take advantage of it: the method assumes that the +elements in range [lo,start) are already sorted + +lo the index of the first element in the range to be sorted +hi the index after the last element in the range to be sorted +start the index of the first element in the range that is not already known to be sorted +*/ +/datum/sortInstance/proc/binarySort(lo, hi, start) + //ASSERT(lo <= start && start <= hi) + if(start <= lo) + start = lo + 1 + + for(,start < hi, ++start) + var/pivot = fetchElement(L,start) + + //set left and right to the index where pivot belongs + var/left = lo + var/right = start + //ASSERT(left <= right) + + //[lo, left) elements <= pivot < [right, start) elements + //in other words, find where the pivot element should go using bisection search + while(left < right) + var/mid = (left + right) >> 1 //round((left+right)/2) + if(call(cmp)(fetchElement(L,mid), pivot) > 0) + right = mid + else + left = mid+1 + + //ASSERT(left == right) + moveElement(L, start, left) //move pivot element to correct location in the sorted range + +/* +Returns the length of the run beginning at the specified position and reverses the run if it is back-to-front + +A run is the longest ascending sequence with: + a[lo] <= a[lo + 1] <= a[lo + 2] <= ... +or the longest descending sequence with: + a[lo] > a[lo + 1] > a[lo + 2] > ... + +For its intended use in a stable mergesort, the strictness of the +definition of "descending" is needed so that the call can safely +reverse a descending sequence without violating stability. +*/ +/datum/sortInstance/proc/countRunAndMakeAscending(lo, hi) + //ASSERT(lo < hi) + + var/runHi = lo + 1 + if(runHi >= hi) + return 1 + + var/last = fetchElement(L,lo) + var/current = fetchElement(L,runHi++) + + if(call(cmp)(current, last) < 0) + while(runHi < hi) + last = current + current = fetchElement(L,runHi) + if(call(cmp)(current, last) >= 0) + break + ++runHi + reverseRange(L, lo, runHi) + else + while(runHi < hi) + last = current + current = fetchElement(L,runHi) + if(call(cmp)(current, last) < 0) + break + ++runHi + + return runHi - lo + +//Returns the minimum acceptable run length for an array of the specified length. +//Natural runs shorter than this will be extended with binarySort +/datum/sortInstance/proc/minRunLength(n) + //ASSERT(n >= 0) + var/r = 0 //becomes 1 if any bits are shifted off + while(n >= MIN_MERGE) + r |= (n & 1) + n >>= 1 + return n + r + +//Examines the stack of runs waiting to be merged and merges adjacent runs until the stack invariants are reestablished: +// runLen[i-3] > runLen[i-2] + runLen[i-1] +// runLen[i-2] > runLen[i-1] +//This method is called each time a new run is pushed onto the stack. +//So the invariants are guaranteed to hold for i= 2) + var/n = runBases.len - 1 + if(n > 1 && runLens[n-1] <= runLens[n] + runLens[n+1]) + if(runLens[n-1] < runLens[n+1]) + --n + mergeAt(n) + else if(runLens[n] <= runLens[n+1]) + mergeAt(n) + else + break //Invariant is established + + +//Merges all runs on the stack until only one remains. +//Called only once, to finalise the sort +/datum/sortInstance/proc/mergeForceCollapse() + while(runBases.len >= 2) + var/n = runBases.len - 1 + if(n > 1 && runLens[n-1] < runLens[n+1]) + --n + mergeAt(n) + + +//Merges the two consecutive runs at stack indices i and i+1 +//Run i must be the penultimate or antepenultimate run on the stack +//In other words, i must be equal to stackSize-2 or stackSize-3 +/datum/sortInstance/proc/mergeAt(i) + //ASSERT(runBases.len >= 2) + //ASSERT(i >= 1) + //ASSERT(i == runBases.len - 1 || i == runBases.len - 2) + + var/base1 = runBases[i] + var/base2 = runBases[i+1] + var/len1 = runLens[i] + var/len2 = runLens[i+1] + + //ASSERT(len1 > 0 && len2 > 0) + //ASSERT(base1 + len1 == base2) + + //Record the legth of the combined runs. If i is the 3rd last run now, also slide over the last run + //(which isn't involved in this merge). The current run (i+1) goes away in any case. + runLens[i] += runLens[i+1] + runLens.Cut(i+1, i+2) + runBases.Cut(i+1, i+2) + + + //Find where the first element of run2 goes in run1. + //Prior elements in run1 can be ignored (because they're already in place) + var/k = gallopRight(fetchElement(L,base2), base1, len1, 0) + //ASSERT(k >= 0) + base1 += k + len1 -= k + if(len1 == 0) + return + + //Find where the last element of run1 goes in run2. + //Subsequent elements in run2 can be ignored (because they're already in place) + len2 = gallopLeft(fetchElement(L,base1 + len1 - 1), base2, len2, len2-1) + //ASSERT(len2 >= 0) + if(len2 == 0) + return + + //Merge remaining runs, using tmp array with min(len1, len2) elements + if(len1 <= len2) + mergeLo(base1, len1, base2, len2) + else + mergeHi(base1, len1, base2, len2) + + +/* + Locates the position to insert key within the specified sorted range + If the range contains elements equal to key, this will return the index of the LEFTMOST of those elements + + key the element to be inserted into the sorted range + base the index of the first element of the sorted range + len the length of the sorted range, must be greater than 0 + hint the offset from base at which to begin the search, such that 0 <= hint < len; i.e. base <= hint < base+hint + + Returns the index at which to insert element 'key' +*/ +/datum/sortInstance/proc/gallopLeft(key, base, len, hint) + //ASSERT(len > 0 && hint >= 0 && hint < len) + + var/lastOffset = 0 + var/offset = 1 + if(call(cmp)(key, fetchElement(L,base+hint)) > 0) + var/maxOffset = len - hint + while(offset < maxOffset && call(cmp)(key, fetchElement(L,base+hint+offset)) > 0) + lastOffset = offset + offset = (offset << 1) + 1 + + if(offset > maxOffset) + offset = maxOffset + + lastOffset += hint + offset += hint + + else + var/maxOffset = hint + 1 + while(offset < maxOffset && call(cmp)(key, fetchElement(L,base+hint-offset)) <= 0) + lastOffset = offset + offset = (offset << 1) + 1 + + if(offset > maxOffset) + offset = maxOffset + + var/temp = lastOffset + lastOffset = hint - offset + offset = hint - temp + + //ASSERT(-1 <= lastOffset && lastOffset < offset && offset <= len) + + //Now L[base+lastOffset] < key <= L[base+offset], so key belongs somewhere to the right of lastOffset but no farther than + //offset. Do a binary search with invariant L[base+lastOffset-1] < key <= L[base+offset] + ++lastOffset + while(lastOffset < offset) + var/m = lastOffset + ((offset - lastOffset) >> 1) + + if(call(cmp)(key, fetchElement(L,base+m)) > 0) + lastOffset = m + 1 + else + offset = m + + //ASSERT(lastOffset == offset) + return offset + +/** + * Like gallopLeft, except that if the range contains an element equal to + * key, gallopRight returns the index after the rightmost equal element. + * + * @param key the key whose insertion point to search for + * @param a the array in which to search + * @param base the index of the first element in the range + * @param len the length of the range; must be > 0 + * @param hint the index at which to begin the search, 0 <= hint < n. + * The closer hint is to the result, the faster this method will run. + * @param c the comparator used to order the range, and to search + * @return the int k, 0 <= k <= n such that a[b + k - 1] <= key < a[b + k] + */ +/datum/sortInstance/proc/gallopRight(key, base, len, hint) + //ASSERT(len > 0 && hint >= 0 && hint < len) + + var/offset = 1 + var/lastOffset = 0 + if(call(cmp)(key, fetchElement(L,base+hint)) < 0) //key <= L[base+hint] + var/maxOffset = hint + 1 //therefore we want to insert somewhere in the range [base,base+hint] = [base+,base+(hint+1)) + while(offset < maxOffset && call(cmp)(key, fetchElement(L,base+hint-offset)) < 0) //we are iterating backwards + lastOffset = offset + offset = (offset << 1) + 1 //1 3 7 15 + //if(offset <= 0) //int overflow, not an issue here since we are using floats + // offset = maxOffset + + if(offset > maxOffset) + offset = maxOffset + + var/temp = lastOffset + lastOffset = hint - offset + offset = hint - temp + + else //key > L[base+hint] + var/maxOffset = len - hint //therefore we want to insert somewhere in the range (base+hint,base+len) = [base+hint+1, base+hint+(len-hint)) + while(offset < maxOffset && call(cmp)(key, fetchElement(L,base+hint+offset)) >= 0) + lastOffset = offset + offset = (offset << 1) + 1 + //if(offset <= 0) //int overflow, not an issue here since we are using floats + // offset = maxOffset + + if(offset > maxOffset) + offset = maxOffset + + lastOffset += hint + offset += hint + + //ASSERT(-1 <= lastOffset && lastOffset < offset && offset <= len) + + ++lastOffset + while(lastOffset < offset) + var/m = lastOffset + ((offset - lastOffset) >> 1) + + if(call(cmp)(key, fetchElement(L,base+m)) < 0) //key <= L[base+m] + offset = m + else //key > L[base+m] + lastOffset = m + 1 + + //ASSERT(lastOffset == offset) + + return offset + + +//Merges two adjacent runs in-place in a stable fashion. +//For performance this method should only be called when len1 <= len2! +/datum/sortInstance/proc/mergeLo(base1, len1, base2, len2) + //ASSERT(len1 > 0 && len2 > 0 && base1 + len1 == base2) + + var/cursor1 = base1 + var/cursor2 = base2 + + //degenerate cases + if(len2 == 1) + moveElement(L, cursor2, cursor1) + return + + if(len1 == 1) + moveElement(L, cursor1, cursor2+len2) + return + + + //Move first element of second run + moveElement(L, cursor2++, cursor1++) + --len2 + + outer: + while(1) + var/count1 = 0 //# of times in a row that first run won + var/count2 = 0 // " " " " " " second run won + + //do the straightfoward thin until one run starts winning consistently + + do + //ASSERT(len1 > 1 && len2 > 0) + if(call(cmp)(fetchElement(L,cursor2), fetchElement(L,cursor1)) < 0) + moveElement(L, cursor2++, cursor1++) + --len2 + + ++count2 + count1 = 0 + + if(len2 == 0) + break outer + else + ++cursor1 + + ++count1 + count2 = 0 + + if(--len1 == 1) + break outer + + while((count1 | count2) < minGallop) + + + //one run is winning consistently so galloping may provide huge benifits + //so try galloping, until such time as the run is no longer consistently winning + do + //ASSERT(len1 > 1 && len2 > 0) + + count1 = gallopRight(fetchElement(L,cursor2), cursor1, len1, 0) + if(count1) + cursor1 += count1 + len1 -= count1 + + if(len1 <= 1) + break outer + + moveElement(L, cursor2, cursor1) + ++cursor2 + ++cursor1 + if(--len2 == 0) + break outer + + count2 = gallopLeft(fetchElement(L,cursor1), cursor2, len2, 0) + if(count2) + moveRange(L, cursor2, cursor1, count2) + + cursor2 += count2 + cursor1 += count2 + len2 -= count2 + + if(len2 == 0) + break outer + + ++cursor1 + if(--len1 == 1) + break outer + + --minGallop + + while((count1|count2) > MIN_GALLOP) + + if(minGallop < 0) + minGallop = 0 + minGallop += 2; // Penalize for leaving gallop mode + + + if(len1 == 1) + //ASSERT(len2 > 0) + moveElement(L, cursor1, cursor2+len2) + + //else + //ASSERT(len2 == 0) + //ASSERT(len1 > 1) + + +/datum/sortInstance/proc/mergeHi(base1, len1, base2, len2) + //ASSERT(len1 > 0 && len2 > 0 && base1 + len1 == base2) + + var/cursor1 = base1 + len1 - 1 //start at end of sublists + var/cursor2 = base2 + len2 - 1 + + //degenerate cases + if(len2 == 1) + moveElement(L, base2, base1) + return + + if(len1 == 1) + moveElement(L, base1, cursor2+1) + return + + moveElement(L, cursor1--, cursor2-- + 1) + --len1 + + outer: + while(1) + var/count1 = 0 //# of times in a row that first run won + var/count2 = 0 // " " " " " " second run won + + //do the straightfoward thing until one run starts winning consistently + do + //ASSERT(len1 > 0 && len2 > 1) + if(call(cmp)(fetchElement(L,cursor2), fetchElement(L,cursor1)) < 0) + moveElement(L, cursor1--, cursor2-- + 1) + --len1 + + ++count1 + count2 = 0 + + if(len1 == 0) + break outer + else + --cursor2 + --len2 + + ++count2 + count1 = 0 + + if(len2 == 1) + break outer + while((count1 | count2) < minGallop) + + //one run is winning consistently so galloping may provide huge benifits + //so try galloping, until such time as the run is no longer consistently winning + do + //ASSERT(len1 > 0 && len2 > 1) + + count1 = len1 - gallopRight(fetchElement(L,cursor2), base1, len1, len1-1) //should cursor1 be base1? + if(count1) + cursor1 -= count1 + + moveRange(L, cursor1+1, cursor2+1, count1) //cursor1+1 == cursor2 by definition + + cursor2 -= count1 + len1 -= count1 + + if(len1 == 0) + break outer + + --cursor2 + + if(--len2 == 1) + break outer + + count2 = len2 - gallopLeft(fetchElement(L,cursor1), cursor1+1, len2, len2-1) + if(count2) + cursor2 -= count2 + len2 -= count2 + + if(len2 <= 1) + break outer + + moveElement(L, cursor1--, cursor2-- + 1) + --len1 + + if(len1 == 0) + break outer + + --minGallop + while((count1|count2) > MIN_GALLOP) + + if(minGallop < 0) + minGallop = 0 + minGallop += 2 // Penalize for leaving gallop mode + + if(len2 == 1) + //ASSERT(len1 > 0) + + cursor1 -= len1 + moveRange(L, cursor1+1, cursor2+1, len1) + + //else + //ASSERT(len1 == 0) + //ASSERT(len2 > 0) + + +/datum/sortInstance/proc/mergeSort(start, end) + var/remaining = end - start + + //If array is small, do an insertion sort + if(remaining < MIN_MERGE) + //var/initRunLen = countRunAndMakeAscending(start, end) + binarySort(start, end, start/*+initRunLen*/) + return + + var/minRun = minRunLength(remaining) + + do + var/runLen = (remaining <= minRun) ? remaining : minRun + + binarySort(start, start+runLen, start) + + //add data about run to queue + runBases.Add(start) + runLens.Add(runLen) + + //Advance to find next run + start += runLen + remaining -= runLen + + while(remaining > 0) + + while(runBases.len >= 2) + var/n = runBases.len - 1 + if(n > 1 && runLens[n-1] <= runLens[n] + runLens[n+1]) + if(runLens[n-1] < runLens[n+1]) + --n + mergeAt2(n) + else if(runLens[n] <= runLens[n+1]) + mergeAt2(n) + else + break //Invariant is established + + while(runBases.len >= 2) + var/n = runBases.len - 1 + if(n > 1 && runLens[n-1] < runLens[n+1]) + --n + mergeAt2(n) + + return L + +/datum/sortInstance/proc/mergeAt2(i) + var/cursor1 = runBases[i] + var/cursor2 = runBases[i+1] + + var/end1 = cursor1+runLens[i] + var/end2 = cursor2+runLens[i+1] + + var/val1 = fetchElement(L,cursor1) + var/val2 = fetchElement(L,cursor2) + + while(1) + if(call(cmp)(val1,val2) < 0) + if(++cursor1 >= end1) + break + val1 = fetchElement(L,cursor1) + else + moveElement(L,cursor2,cursor1) + + ++cursor2 + if(++cursor2 >= end2) + break + ++end1 + ++cursor1 + //if(++cursor1 >= end1) + // break + + val2 = fetchElement(L,cursor2) + + + //Record the legth of the combined runs. If i is the 3rd last run now, also slide over the last run + //(which isn't involved in this merge). The current run (i+1) goes away in any case. + runLens[i] += runLens[i+1] + runLens.Cut(i+1, i+2) + runBases.Cut(i+1, i+2) + +#undef MIN_GALLOP +#undef MIN_MERGE + +#undef fetchElement diff --git a/code/_helpers/spawn_sync.dm b/code/_helpers/spawn_sync.dm new file mode 100644 index 00000000..6c1733ef --- /dev/null +++ b/code/_helpers/spawn_sync.dm @@ -0,0 +1,86 @@ +//------------------------------- +/* + Spawn sync helper + + Helps syncronize spawn()ing multiple processes in loops. + + Example for using this: + + //Create new spawn_sync datum + var/datum/spawn_sync/sync = new() + + for(var/obj/O in list) + //Call start_worker(), passing it first the object, then a string of the name of the proc you want called, then + // any and all arguments you want passed to the proc. + sync.start_worker(O, "do_something", arg1, arg2) + + //Finally call wait_until_done() + sync.wait_until_done() + + //Once all the workers have completed, or the failsafe has triggered, the code will continue. By default the + // failsafe is roughly 10 seconds (100 checks). +*/ +//------------------------------- +/datum/spawn_sync + var/count = 1 + var/failsafe = 100 //how many checks before the failsafe triggers and the helper stops waiting + +//Opens a thread counter +/datum/spawn_sync/proc/open() + count++ + +//Closes a thread counter +/datum/spawn_sync/proc/close() + count-- + +//Finalizes the spawn sync by removing the original starting count +/datum/spawn_sync/proc/finalize() + close() + +//Resets the counter if you want to utilize the same datum multiple times +// Optional: pass the number of checks you want for the failsafe +/datum/spawn_sync/proc/reset(var/safety = 100) + count = 1 + failsafe = safety + +//Check if all threads have returned +// Returns 0 if not all threads have completed +// Returns 1 if all threads have completed +/datum/spawn_sync/proc/check() + safety_check() + return count > 0 ? 1 : 0 + +//Failsafe in case something breaks horribly +/datum/spawn_sync/proc/safety_check() + failsafe-- + if(failsafe < 1) + count = 0 + +//Set failsafe check count in case you need more time for the workers to return +/datum/spawn_sync/proc/set_failsafe(var/safety) + failsafe = safety + +/datum/spawn_sync/proc/start_worker() + //Extract the thread run proc and it's arguments from the variadic args list. + ASSERT(args.len > 0) + var/obj = args[1] + var/thread_proc = args[2] + + //dispatch a new thread + open() + spawn() + //Utilise try/catch keywords here so the code continues even if an error occurs. + try + call(obj, thread_proc)(arglist(args.Copy(3))) + catch(var/exception/e) + error("[e] on [e.file]:[e.line]") + close() + +/datum/spawn_sync/proc/wait_until_done() + finalize() + + //Create a while loop to check if the sync is complete yet, it will return once all the spawn threads have + // completed, or the failsafe has expired. + while(check()) + //Add a sleep call to delay each check. + sleep(1) diff --git a/code/_helpers/storage.dm b/code/_helpers/storage.dm new file mode 100644 index 00000000..2d415a55 --- /dev/null +++ b/code/_helpers/storage.dm @@ -0,0 +1,54 @@ +/proc/create_objects_in_loc(var/atom/loc, var/atom_paths) + if(!istype(loc)) + CRASH("Inappropriate loction given.") + + if(istype(atom_paths, /datum/atom_creator)) + var/datum/atom_creator/atom_creator = atom_paths + atom_creator.create(loc) + else if(islist(atom_paths)) + for(var/atom_path in atom_paths) + for(var/i = 1 to max(1, atom_paths[atom_path])) + create_objects_in_loc(loc, atom_path) + else if(ispath(atom_paths)) + new atom_paths(loc) + else + CRASH("Unhandled input: [log_info_line(atom_paths)]") + +/datum/atom_creator/proc/create(var/loc) + return + +/datum/atom_creator/simple + var/path + var/probability + var/prob_method = /proc/prob_call + +/datum/atom_creator/simple/New(var/path, var/probability) + if(args.len != 2) + CRASH("Invalid number of arguments. Expected 2, was [args.len]") + if(!isnum(probability) || probability < 1 || probability > 99) + CRASH("Invalid probability. Expected a number between 1 and 99, was [log_info_line(probability)]") // A probability of 0 or 100 is pretty meaningless. + src.probability = probability + src.path = path + +/datum/atom_creator/simple/create(var/loc) + if(call(prob_method)(probability)) + create_objects_in_loc(loc, path) + +/datum/atom_creator/weighted + var/list/paths + var/selection_method = /proc/pickweight + +/datum/atom_creator/weighted/New(var/list/paths) + if(args.len != 1) + CRASH("Invalid number of arguments. Expected 1, was [args.len]") + if(!istype(paths)) + CRASH("Invalid argument type. Expected /list, was [log_info_line(paths)]") + for(var/path in paths) + var/probability = paths[path] + if(!(isnull(probability) || (isnum(probability) && probability > 0))) + CRASH("Invalid probability. Expected null or a number greater than 0, was [log_info_line(probability)]") + src.paths = paths + +/datum/atom_creator/weighted/create(var/loc) + var/path = call(selection_method)(paths) + create_objects_in_loc(loc, path) diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm new file mode 100644 index 00000000..8dfca034 --- /dev/null +++ b/code/_helpers/text.dm @@ -0,0 +1,473 @@ +/* + * Holds procs designed to help with filtering text + * Contains groups: + * SQL sanitization + * Text sanitization + * Text searches + * Text modification + * Misc + */ + + +/* + * SQL sanitization + */ + +// Run all strings to be used in an SQL query through this proc first to properly escape out injection attempts. +/proc/sanitizeSQL(var/t as text) + var/sqltext = dbcon.Quote(t); + return copytext(sqltext, 2, length(sqltext));//Quote() adds quotes around input, we already do that + +/* + * Text sanitization + */ + +//Used for preprocessing entered text +//Added in an additional check to alert players if input is too long +/proc/sanitize(var/input, var/max_length = MAX_MESSAGE_LEN, var/encode = 1, var/trim = 1, var/extra = 1) + if(!input) + return + + if(max_length) + //testing shows that just looking for > max_length alone will actually cut off the final character if message is precisely max_length, so >= instead + if(length(input) >= max_length) + var/overflow = ((length(input)+1) - max_length) + to_chat(usr, "Your message is too long by [overflow] character\s.") + return + input = copytext(input,1,max_length) + + if(extra) + input = replace_characters(input, list("\n"=" ","\t"=" ")) + + if(encode) + // The below \ escapes have a space inserted to attempt to enable Travis auto-checking of span class usage. Please do not remove the space. + //In addition to processing html, html_encode removes byond formatting codes like "\ red", "\ i" and other. + //It is important to avoid double-encode text, it can "break" quotes and some other characters. + //Also, keep in mind that escaped characters don't work in the interface (window titles, lower left corner of the main window, etc.) + input = html_encode(input) + else + //If not need encode text, simply remove < and > + //note: we can also remove here byond formatting codes: 0xFF + next byte + input = replace_characters(input, list("<"=" ", ">"=" ")) + + if(trim) + //Maybe, we need trim text twice? Here and before copytext? + input = trim(input) + + return input + +//Run sanitize(), but remove <, >, " first to prevent displaying them as > < &34; in some places, after html_encode(). +//Best used for sanitize object names, window titles. +//If you have a problem with sanitize() in chat, when quotes and >, < are displayed as html entites - +//this is a problem of double-encode(when & becomes &), use sanitize() with encode=0, but not the sanitizeSafe()! +/proc/sanitizeSafe(var/input, var/max_length = MAX_MESSAGE_LEN, var/encode = 1, var/trim = 1, var/extra = 1) + return sanitize(replace_characters(input, list(">"=" ","<"=" ", "\""="'")), max_length, encode, trim, extra) + +//Filters out undesirable characters from names +/proc/sanitizeName(var/input, var/max_length = MAX_NAME_LEN, var/allow_numbers = 0, var/force_first_letter_uppercase = TRUE) + if(!input || length(input) > max_length) + return //Rejects the input if it is null or if it is longer then the max length allowed + + var/number_of_alphanumeric = 0 + var/last_char_group = 0 + var/output = "" + + for(var/i=1, i<=length(input), i++) + var/ascii_char = text2ascii(input,i) + switch(ascii_char) + // A .. Z + if(65 to 90) //Uppercase Letters + output += ascii2text(ascii_char) + number_of_alphanumeric++ + last_char_group = 4 + + // a .. z + if(97 to 122) //Lowercase Letters + if(last_char_group<2 && force_first_letter_uppercase) + output += ascii2text(ascii_char-32) //Force uppercase first character + else + output += ascii2text(ascii_char) + number_of_alphanumeric++ + last_char_group = 4 + + // 0 .. 9 + if(48 to 57) //Numbers + if(!last_char_group) continue //suppress at start of string + if(!allow_numbers) continue + output += ascii2text(ascii_char) + number_of_alphanumeric++ + last_char_group = 3 + + // ' - . + if(39,45,46) //Common name punctuation + if(!last_char_group) continue + output += ascii2text(ascii_char) + last_char_group = 2 + + // ~ | @ : # $ % & * + + if(126,124,64,58,35,36,37,38,42,43) //Other symbols that we'll allow (mainly for AI) + if(!last_char_group) continue //suppress at start of string + if(!allow_numbers) continue + output += ascii2text(ascii_char) + last_char_group = 2 + + //Space + if(32) + if(last_char_group <= 1) continue //suppress double-spaces and spaces at start of string + output += ascii2text(ascii_char) + last_char_group = 1 + else + return + + if(number_of_alphanumeric < 2) return //protects against tiny names like "A" and also names like "' ' ' ' ' ' ' '" + + if(last_char_group == 1) + output = copytext(output,1,length(output)) //removes the last character (in this case a space) + + for(var/bad_name in list("space","floor","wall","r-wall","monkey","unknown","inactive ai","plating")) //prevents these common metagamey names + if(cmptext(output,bad_name)) return //(not case sensitive) + + return output + +//Returns null if there is any bad text in the string +/proc/reject_bad_text(var/text, var/max_length=512) + if(length(text) > max_length) return //message too long + var/non_whitespace = 0 + for(var/i=1, i<=length(text), i++) + switch(text2ascii(text,i)) + if(62,60,92,47) return //rejects the text if it contains these bad characters: <, >, \ or / + if(127 to 255) return //rejects weird letters like � + if(0 to 31) return //more weird stuff + if(32) continue //whitespace + else non_whitespace = 1 + if(non_whitespace) return text //only accepts the text if it has some non-spaces + + +//Old variant. Haven't dared to replace in some places. +/proc/sanitize_old(var/t,var/list/repl_chars = list("\n"="#","\t"="#")) + return html_encode(replace_characters(t,repl_chars)) + +/* + * Text searches + */ + +//Checks the beginning of a string for a specified sub-string +//Returns the position of the substring or 0 if it was not found +/proc/dd_hasprefix(text, prefix) + var/start = 1 + var/end = length(prefix) + 1 + return findtext(text, prefix, start, end) + +//Checks the beginning of a string for a specified sub-string. This proc is case sensitive +//Returns the position of the substring or 0 if it was not found +/proc/dd_hasprefix_case(text, prefix) + var/start = 1 + var/end = length(prefix) + 1 + return findtextEx(text, prefix, start, end) + +//Checks the end of a string for a specified substring. +//Returns the position of the substring or 0 if it was not found +/proc/dd_hassuffix(text, suffix) + var/start = length(text) - length(suffix) + if(start) + return findtext(text, suffix, start, null) + return + +//Checks the end of a string for a specified substring. This proc is case sensitive +//Returns the position of the substring or 0 if it was not found +/proc/dd_hassuffix_case(text, suffix) + var/start = length(text) - length(suffix) + if(start) + return findtextEx(text, suffix, start, null) + +/* + * Text modification + */ + +/proc/replace_characters(var/t,var/list/repl_chars) + for(var/char in repl_chars) + t = replacetext(t, char, repl_chars[char]) + return t + +//Adds 'u' number of zeros ahead of the text 't' +/proc/add_zero(t, u) + while (length(t) < u) + t = "0[t]" + return t + +//Adds 'u' number of spaces ahead of the text 't' +/proc/add_lspace(t, u) + while(length(t) < u) + t = " [t]" + return t + +//Adds 'u' number of spaces behind the text 't' +/proc/add_tspace(t, u) + while(length(t) < u) + t = "[t] " + return t + +//Returns a string with reserved characters and spaces before the first letter removed +/proc/trim_left(text) + for (var/i = 1 to length(text)) + if (text2ascii(text, i) > 32) + return copytext(text, i) + return "" + +//Returns a string with reserved characters and spaces after the last letter removed +/proc/trim_right(text) + for (var/i = length(text), i > 0, i--) + if (text2ascii(text, i) > 32) + return copytext(text, 1, i + 1) + return "" + +//Returns a string with reserved characters and spaces before the first word and after the last word removed. +/proc/trim(text) + return trim_left(trim_right(text)) + +//Returns a string with the first element of the string capitalized. +/proc/capitalize(var/t as text) + return uppertext(copytext(t, 1, 2)) + copytext(t, 2) + +//Bolds "shouted" messages. +/proc/add_shout_append(text) + if (copytext(text,-1) == "!") + text = "[text]" + return text + +//This proc strips html properly, remove < > and all text between +//for complete text sanitizing should be used sanitize() +/proc/strip_html_properly(var/input) + if(!input) + return + var/opentag = 1 //These store the position of < and > respectively. + var/closetag = 1 + while(1) + opentag = findtext(input, "<") + closetag = findtext(input, ">") + if(closetag && opentag) + if(closetag < opentag) + input = copytext(input, (closetag + 1)) + else + input = copytext(input, 1, opentag) + copytext(input, (closetag + 1)) + else if(closetag || opentag) + if(opentag) + input = copytext(input, 1, opentag) + else + input = copytext(input, (closetag + 1)) + else + break + + return input + +//This proc fills in all spaces with the "replace" var (* by default) with whatever +//is in the other string at the same spot (assuming it is not a replace char). +//This is used for fingerprints +/proc/stringmerge(var/text,var/compare,replace = "*") + var/newtext = text + if(length(text) != length(compare)) + return 0 + for(var/i = 1, i < length(text), i++) + var/a = copytext(text,i,i+1) + var/b = copytext(compare,i,i+1) + //if it isn't both the same letter, or if they are both the replacement character + //(no way to know what it was supposed to be) + if(a != b) + if(a == replace) //if A is the replacement char + newtext = copytext(newtext,1,i) + b + copytext(newtext, i+1) + else if(b == replace) //if B is the replacement char + newtext = copytext(newtext,1,i) + a + copytext(newtext, i+1) + else //The lists disagree, Uh-oh! + return 0 + return newtext + +//This proc returns the number of chars of the string that is the character +//This is used for detective work to determine fingerprint completion. +/proc/stringpercent(var/text,character = "*") + if(!text || !character) + return 0 + var/count = 0 + for(var/i = 1, i <= length(text), i++) + var/a = copytext(text,i,i+1) + if(a == character) + count++ + return count + +/proc/reverse_text(var/text = "") + var/new_text = "" + for(var/i = length(text); i > 0; i--) + new_text += copytext(text, i, i+1) + return new_text + +//Used in preferences' SetFlavorText and human's set_flavor verb +//Previews a string of len or less length +proc/TextPreview(var/string,var/len=40) + if(length(string) <= len) + if(!length(string)) + return "\[...\]" + else + return string + else + return "[copytext_preserve_html(string, 1, 37)]..." + +//alternative copytext() for encoded text, doesn't break html entities (" and other) +/proc/copytext_preserve_html(var/text, var/first, var/last) + return html_encode(copytext(html_decode(text), first, last)) + +//For generating neat chat tag-images +//The icon var could be local in the proc, but it's a waste of resources +// to always create it and then throw it out. +/var/icon/text_tag_icons = new('./icons/chattags.dmi') +/proc/create_text_tag(var/tagname, var/tagdesc = tagname, var/client/C = null) + if(!(C && C.get_preference_value(/datum/client_preference/chat_tags) == GLOB.PREF_SHOW)) + return tagdesc + return icon2html(icon(text_tag_icons, tagname), world, realsize=TRUE) + +/proc/contains_az09(var/input) + for(var/i=1, i<=length(input), i++) + var/ascii_char = text2ascii(input,i) + switch(ascii_char) + // A .. Z + if(65 to 90) //Uppercase Letters + return 1 + // a .. z + if(97 to 122) //Lowercase Letters + return 1 + + // 0 .. 9 + if(48 to 57) //Numbers + return 1 + return 0 + +/proc/generateRandomString(var/length) + . = list() + for(var/a in 1 to length) + var/letter = rand(33,126) + . += ascii2text(letter) + . = jointext(.,null) + +#define starts_with(string, substring) (copytext(string,1,1+length(substring)) == substring) + +#define gender2text(gender) capitalize(gender) + +/** + * Strip out the special beyond characters for \proper and \improper + * from text that will be sent to the browser. + */ +/proc/strip_improper(var/text) + return replacetext(replacetext(text, "\proper", ""), "\improper", "") +//#define strip_improper(input_text) replacetext(replacetext(input_text, "\proper", ""), "\improper", "") + +/proc/pencode2html(t) + t = replacetext(t, "\n", "
") + t = replacetext(t, "\[center\]", "
") + t = replacetext(t, "\[/center\]", "
") + t = replacetext(t, "\[br\]", "
") + t = replacetext(t, "\[b\]", "") + t = replacetext(t, "\[/b\]", "") + t = replacetext(t, "\[i\]", "") + t = replacetext(t, "\[/i\]", "") + t = replacetext(t, "\[u\]", "") + t = replacetext(t, "\[/u\]", "") + t = replacetext(t, "\[time\]", "[stationtime2text()]") + t = replacetext(t, "\[date\]", "[stationdate2text()]") + t = replacetext(t, "\[large\]", "") + t = replacetext(t, "\[/large\]", "") + t = replacetext(t, "\[field\]", "") + t = replacetext(t, "\[h1\]", "

") + t = replacetext(t, "\[/h1\]", "

") + t = replacetext(t, "\[h2\]", "

") + t = replacetext(t, "\[/h2\]", "

") + t = replacetext(t, "\[h3\]", "

") + t = replacetext(t, "\[/h3\]", "

") + t = replacetext(t, "\[*\]", "
  • ") + t = replacetext(t, "\[hr\]", "
    ") + t = replacetext(t, "\[small\]", "") + t = replacetext(t, "\[/small\]", "") + t = replacetext(t, "\[list\]", "
      ") + t = replacetext(t, "\[/list\]", "
    ") + t = replacetext(t, "\[table\]", "") + t = replacetext(t, "\[/table\]", "
    ") + t = replacetext(t, "\[grid\]", "") + t = replacetext(t, "\[/grid\]", "
    ") + t = replacetext(t, "\[row\]", "") + t = replacetext(t, "\[cell\]", "") + t = replacetext(t, "\[logo\]", "") + t = replacetext(t, "\[bluelogo\]", "") + t = replacetext(t, "\[solcrest\]", "") + t = replacetext(t, "\[terraseal\]", "") + t = replacetext(t, "\[editorbr\]", "") + return t + +// Random password generator +/proc/GenerateKey() + //Feel free to move to Helpers. + var/newKey + newKey += pick("the", "if", "of", "as", "in", "a", "you", "from", "to", "an", "too", "little", "snow", "dead", "drunk", "rosebud", "duck", "al", "le") + newKey += pick("diamond", "beer", "mushroom", "captain", "twinkie", "redcoat", "bluecoat", "nuke", "small", "big", "escape", "blue", "red", "gloves", "engine", "nuclear") + newKey += pick("1", "2", "3", "4", "5", "6", "7", "8", "9", "0") + return newKey + +//Used for applying byonds text macros to strings that are loaded at runtime +/proc/apply_text_macros(string) + var/next_backslash = findtext(string, "\\") + if(!next_backslash) + return string + + var/leng = length(string) + + var/next_space = findtext(string, " ", next_backslash + 1) + if(!next_space) + next_space = leng - next_backslash + + if(!next_space) //trailing bs + return string + + var/base = next_backslash == 1 ? "" : copytext(string, 1, next_backslash) + var/macro = lowertext(copytext(string, next_backslash + 1, next_space)) + var/rest = next_backslash > leng ? "" : copytext(string, next_space + 1) + + //See http://www.byond.com/docs/ref/info.html#/DM/text/macros + switch(macro) + //prefixes/agnostic + if("the") + rest = text("\the []", rest) + if("a") + rest = text("\a []", rest) + if("an") + rest = text("\an []", rest) + if("proper") + rest = text("\proper []", rest) + if("improper") + rest = text("\improper []", rest) + if("roman") + rest = text("\roman []", rest) + //postfixes + if("th") + base = text("[]\th", rest) + if("s") + base = text("[]\s", rest) + if("he") + base = text("[]\he", rest) + if("she") + base = text("[]\she", rest) + if("his") + base = text("[]\his", rest) + if("himself") + base = text("[]\himself", rest) + if("herself") + base = text("[]\herself", rest) + if("hers") + base = text("[]\hers", rest) + + . = base + if(rest) + . += .(rest) + +/proc/deep_string_equals(var/A, var/B) + if (length(A) != length(B)) + return FALSE + for (var/i = 1 to length(A)) + if (text2ascii(A, i) != text2ascii(B, i)) + return FALSE + return TRUE \ No newline at end of file diff --git a/code/_helpers/time.dm b/code/_helpers/time.dm new file mode 100644 index 00000000..9b84d14a --- /dev/null +++ b/code/_helpers/time.dm @@ -0,0 +1,122 @@ +#define SECOND *10 +#define SECONDS *10 + +#define MINUTE *600 +#define MINUTES *600 + +#define HOUR *36000 +#define HOURS *36000 + +#define DAY *864000 +#define DAYS *864000 + +#define TimeOfGame (get_game_time()) +#define TimeOfTick (world.tick_usage*0.01*world.tick_lag) +/proc/get_game_time() + var/global/time_offset = 0 + var/global/last_time = 0 + var/global/last_usage = 0 + + var/wtime = world.time + var/wusage = world.tick_usage * 0.01 + + if(last_time < wtime && last_usage > 1) + time_offset += last_usage - 1 + + last_time = wtime + last_usage = wusage + + return wtime + (time_offset + wusage) * world.tick_lag + +var/roundstart_hour +var/station_date = "" +var/next_station_date_change = 1 DAY + +#define duration2stationtime(time) time2text(station_time_in_ticks + time, "hh:mm") +#define worldtime2stationtime(time) time2text(roundstart_hour HOURS + time, "hh:mm") +#define round_duration_in_ticks (round_start_time ? world.time - round_start_time : 0) +#define station_time_in_ticks (roundstart_hour HOURS + round_duration_in_ticks) + +/proc/stationtime2text() + return time2text(station_time_in_ticks, "hh:mm") + +/proc/stationdate2text() + var/update_time = FALSE + if(station_time_in_ticks > next_station_date_change) + next_station_date_change += 1 DAY + update_time = TRUE + if(!station_date || update_time) + var/extra_days = round(station_time_in_ticks / (1 DAY)) DAYS + var/timeofday = world.timeofday + extra_days + station_date = num2text((text2num(time2text(timeofday, "YYYY"))+544)) + "-" + time2text(timeofday, "MM-DD") + return station_date + +/proc/time_stamp() + return time2text(station_time_in_ticks, "hh:mm:ss") + +/* Returns 1 if it is the selected month and day */ +proc/isDay(var/month, var/day) + if(isnum(month) && isnum(day)) + var/MM = text2num(time2text(world.timeofday, "MM")) // get the current month + var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day + if(month == MM && day == DD) + return 1 + + // Uncomment this out when debugging! + //else + //return 1 + +var/next_duration_update = 0 +var/last_round_duration = 0 +var/round_start_time = 0 + +/hook/roundstart/proc/start_timer() + round_start_time = world.time + return 1 + +/proc/roundduration2text() + if(!round_start_time) + return "00:00" + if(last_round_duration && world.time < next_duration_update) + return last_round_duration + + var/mills = round_duration_in_ticks // 1/10 of a second, not real milliseconds but whatever + //var/secs = ((mills % 36000) % 600) / 10 //Not really needed, but I'll leave it here for refrence.. or something + var/mins = round((mills % 36000) / 600) + var/hours = round(mills / 36000) + + mins = mins < 10 ? add_zero(mins, 1) : mins + hours = hours < 10 ? add_zero(hours, 1) : hours + + last_round_duration = "[hours]:[mins]" + next_duration_update = world.time + 1 MINUTES + return last_round_duration + +/hook/startup/proc/set_roundstart_hour() + roundstart_hour = pick(2,7,12,17) + return 1 + +GLOBAL_VAR_INIT(midnight_rollovers, 0) +GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0) +/proc/update_midnight_rollover() + if (world.timeofday < GLOB.rollovercheck_last_timeofday) //TIME IS GOING BACKWARDS! + return GLOB.midnight_rollovers++ + return GLOB.midnight_rollovers + +//Increases delay as the server gets more overloaded, +//as sleeps aren't cheap and sleeping only to wake up and sleep again is wasteful +#define DELTA_CALC max(((max(world.tick_usage, world.cpu) / 100) * max(Master.sleep_delta,1)), 1) + +/proc/stoplag() + if (!Master || !(Master.current_runlevel & RUNLEVELS_DEFAULT)) + sleep(world.tick_lag) + return 1 + . = 0 + var/i = 1 + do + . += round(i*DELTA_CALC) + sleep(i*world.tick_lag*DELTA_CALC) + i *= 2 + while (world.tick_usage > min(TICK_LIMIT_TO_RUN, Master.current_ticklimit)) + +#undef DELTA_CALC diff --git a/code/_helpers/turfs.dm b/code/_helpers/turfs.dm new file mode 100644 index 00000000..d53e17ca --- /dev/null +++ b/code/_helpers/turfs.dm @@ -0,0 +1,154 @@ +// Returns the atom sitting on the turf. +// For example, using this on a disk, which is in a bag, on a mob, will return the mob because it's on the turf. +/proc/get_atom_on_turf(var/atom/movable/M) + var/atom/mloc = M + while(mloc && mloc.loc && !istype(mloc.loc, /turf/)) + mloc = mloc.loc + return mloc + +/proc/iswall(turf/T) + return (istype(T, /turf/simulated/wall) || istype(T, /turf/unsimulated/wall) || istype(T, /turf/simulated/shuttle/wall)) + +/proc/isfloor(turf/T) + return (istype(T, /turf/simulated/floor) || istype(T, /turf/unsimulated/floor)) + +/proc/turf_clear(turf/T) + for(var/atom/A in T) + if(A.simulated) + return 0 + return 1 + +// Picks a turf without a mob from the given list of turfs, if one exists. +// If no such turf exists, picks any random turf from the given list of turfs. +/proc/pick_mobless_turf_if_exists(var/list/start_turfs) + if(!start_turfs.len) + return null + + var/list/available_turfs = list() + for(var/start_turf in start_turfs) + var/mob/M = locate() in start_turf + if(!M) + available_turfs += start_turf + if(!available_turfs.len) + available_turfs = start_turfs + return pick(available_turfs) + +/proc/get_random_turf_in_range(var/atom/origin, var/outer_range, var/inner_range) + origin = get_turf(origin) + if(!origin) + return + var/list/turfs = list() + for(var/turf/T in orange(origin, outer_range)) + if(!(T.z in GLOB.using_map.sealed_levels)) // Picking a turf outside the map edge isn't recommended + if(T.x >= world.maxx-TRANSITIONEDGE || T.x <= TRANSITIONEDGE) continue + if(T.y >= world.maxy-TRANSITIONEDGE || T.y <= TRANSITIONEDGE) continue + if(!inner_range || get_dist(origin, T) >= inner_range) + turfs += T + if(turfs.len) + return pick(turfs) + +/proc/screen_loc2turf(text, turf/origin) + if(!origin) + return null + var/tZ = splittext(text, ",") + var/tX = splittext(tZ[1], "-") + var/tY = text2num(tX[2]) + tX = splittext(tZ[2], "-") + tX = text2num(tX[2]) + tZ = origin.z + tX = max(1, min(origin.x + 7 - tX, world.maxx)) + tY = max(1, min(origin.y + 7 - tY, world.maxy)) + return locate(tX, tY, tZ) + +/* + Predicate helpers +*/ + +/proc/is_holy_turf(var/turf/T) + return T && T.holy + +/proc/is_not_holy_turf(var/turf/T) + return !is_holy_turf(T) + +/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) + +/proc/has_air(var/turf/T) + return !!T.return_air() + +/proc/IsTurfAtmosUnsafe(var/turf/T) + if(istype(T, /turf/space)) // Space tiles + return "Spawn location is open to space." + var/datum/gas_mixture/air = T.return_air() + if(!air) + return "Spawn location lacks atmosphere." + return get_atmosphere_issues(air, 1) + +/proc/IsTurfAtmosSafe(var/turf/T) + return !IsTurfAtmosUnsafe(T) + +/proc/is_below_sound_pressure(var/turf/T) + var/datum/gas_mixture/environment = T ? T.return_air() : null + var/pressure = environment ? environment.return_pressure() : 0 + if(pressure < SOUND_MINIMUM_PRESSURE) + return TRUE + return FALSE + +/* + Turf manipulation +*/ + +//Returns an assoc list that describes how turfs would be changed if the +//turfs in turfs_src were translated by shifting the src_origin to the dst_origin +/proc/get_turf_translation(turf/src_origin, turf/dst_origin, list/turfs_src) + var/list/turf_map = list() + for(var/turf/source in turfs_src) + var/x_pos = (source.x - src_origin.x) + var/y_pos = (source.y - src_origin.y) + var/z_pos = (source.z - src_origin.z) + + var/turf/target = locate(dst_origin.x + x_pos, dst_origin.y + y_pos, dst_origin.z + z_pos) + if(!target) + error("Null turf in translation @ ([dst_origin.x + x_pos], [dst_origin.y + y_pos], [dst_origin.z + z_pos])") + turf_map[source] = target //if target is null, preserve that information in the turf map + + return turf_map + + +/proc/translate_turfs(var/list/translation, var/area/base_area = null, var/turf/base_turf) + for(var/turf/source in translation) + + var/turf/target = translation[source] + + if(target) + //update area first so that area/Entered() will be called with the correct area when atoms are moved + if(base_area) + source.loc.contents.Add(target) + base_area.contents.Add(source) + transport_turf_contents(source, target) + + //change the old turfs + for(var/turf/source in translation) + source.ChangeTurf(base_turf ? base_turf : get_base_turf_by_area(source), 1, 1) + +//Transports a turf from a source turf to a target turf, moving all of the turf's contents and making the target a copy of the source. +/proc/transport_turf_contents(turf/source, turf/target) + + var/turf/new_turf = target.ChangeTurf(source.type, 1, 1) + new_turf.transport_properties_from(source) + + for(var/obj/O in source) + if(O.simulated) + O.forceMove(new_turf) + + for(var/mob/M in source) + if(isEye(M)) continue // If we need to check for more mobs, I'll add a variable + M.forceMove(new_turf) + + return new_turf diff --git a/code/_helpers/type2type.dm b/code/_helpers/type2type.dm new file mode 100644 index 00000000..a7b8507e --- /dev/null +++ b/code/_helpers/type2type.dm @@ -0,0 +1,237 @@ +/* + * Holds procs designed to change one type of value, into another. + * Contains: + * hex2num & num2hex + * text2list & list2text + * file2list + * angle2dir + * angle2text + * worldtime2text + */ + +// Returns an integer given a hexadecimal number string as input. +/proc/hex2num(hex) + if (!istext(hex)) + return + + var/num = 0 + var/power = 1 + var/i = length(hex) + + while (i) + var/char = text2ascii(hex, i) + switch(char) + if(48) // 0 -- do nothing + if(49 to 57) num += (char - 48) * power // 1-9 + if(97, 65) num += power * 10 // A + if(98, 66) num += power * 11 // B + if(99, 67) num += power * 12 // C + if(100, 68) num += power * 13 // D + if(101, 69) num += power * 14 // E + if(102, 70) num += power * 15 // F + else + return + power *= 16 + i-- + return num + +// Returns the hex value of a number given a value assumed to be a base-ten value +/proc/num2hex(num, padlength) + var/global/list/hexdigits = list("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F") + + . = "" + while(num > 0) + var/hexdigit = hexdigits[(num & 0xF) + 1] + . = "[hexdigit][.]" + num >>= 4 //go to the next half-byte + + //pad with zeroes + var/left = padlength - length(.) + while (left-- > 0) + . = "0[.]" + + +/proc/text2numlist(text, delimiter="\n") + var/list/num_list = list() + for(var/x in splittext(text, delimiter)) + num_list += text2num(x) + return num_list + +// Splits the text of a file at seperator and returns them in a list. +/proc/file2list(filename, seperator="\n") + return splittext(return_file_text(filename),seperator) + +// Turns a direction into text +/proc/num2dir(direction) + switch (direction) + if (1.0) return NORTH + if (2.0) return SOUTH + if (4.0) return EAST + if (8.0) return WEST + else + world.log << "UNKNOWN DIRECTION: [direction]" + +// Turns a direction into text +/proc/dir2text(direction) + switch (direction) + if (NORTH) return "north" + if (SOUTH) return "south" + if (EAST) return "east" + if (WEST) return "west" + if (NORTHEAST) return "northeast" + if (SOUTHEAST) return "southeast" + if (NORTHWEST) return "northwest" + if (SOUTHWEST) return "southwest" + +// Turns text into proper directions +/proc/text2dir(direction) + switch (uppertext(direction)) + if ("NORTH") return 1 + if ("SOUTH") return 2 + if ("EAST") return 4 + if ("WEST") return 8 + if ("NORTHEAST") return 5 + if ("NORTHWEST") return 9 + if ("SOUTHEAST") return 6 + if ("SOUTHWEST") return 10 + +// Converts an angle (degrees) into an ss13 direction +/proc/angle2dir(var/degree) + degree = (degree + 22.5) % 360 // 22.5 = 45 / 2 + if (degree < 45) return NORTH + if (degree < 90) return NORTHEAST + if (degree < 135) return EAST + if (degree < 180) return SOUTHEAST + if (degree < 225) return SOUTH + if (degree < 270) return SOUTHWEST + if (degree < 315) return WEST + return NORTH|WEST + +// Returns the north-zero clockwise angle in degrees, given a direction +/proc/dir2angle(var/D) + switch (D) + if (NORTH) return 0 + if (SOUTH) return 180 + if (EAST) return 90 + if (WEST) return 270 + if (NORTHEAST) return 45 + if (SOUTHEAST) return 135 + if (NORTHWEST) return 315 + if (SOUTHWEST) return 225 + +// Returns the angle in english +/proc/angle2text(var/degree) + return dir2text(angle2dir(degree)) + +// Converts a blend_mode constant to one acceptable to icon.Blend() +/proc/blendMode2iconMode(blend_mode) + switch (blend_mode) + if (BLEND_MULTIPLY) return ICON_MULTIPLY + if (BLEND_ADD) return ICON_ADD + if (BLEND_SUBTRACT) return ICON_SUBTRACT + else return ICON_OVERLAY + +// Converts a rights bitfield into a string +/proc/rights2text(rights,seperator="") + if (rights & R_BUILDMODE) . += "[seperator]+BUILDMODE" + if (rights & R_ADMIN) . += "[seperator]+ADMIN" + if (rights & R_BAN) . += "[seperator]+BAN" + if (rights & R_FUN) . += "[seperator]+FUN" + if (rights & R_SERVER) . += "[seperator]+SERVER" + if (rights & R_DEBUG) . += "[seperator]+DEBUG" + if (rights & R_POSSESS) . += "[seperator]+POSSESS" + if (rights & R_PERMISSIONS) . += "[seperator]+PERMISSIONS" + if (rights & R_STEALTH) . += "[seperator]+STEALTH" + if (rights & R_REJUVINATE) . += "[seperator]+REJUVINATE" + if (rights & R_VAREDIT) . += "[seperator]+VAREDIT" + if (rights & R_SOUNDS) . += "[seperator]+SOUND" + if (rights & R_SPAWN) . += "[seperator]+SPAWN" + if (rights & R_MOD) . += "[seperator]+MODERATOR" + if (rights & R_MENTOR) . += "[seperator]+MENTOR" + return . + +// heat2color functions. Adapted from: http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/ +/proc/heat2color(temp) + return rgb(heat2color_r(temp), heat2color_g(temp), heat2color_b(temp)) + +/proc/heat2color_r(temp) + temp /= 100 + if(temp <= 66) + . = 255 + else + . = max(0, min(255, 329.698727446 * (temp - 60) ** -0.1332047592)) + +/proc/heat2color_g(temp) + temp /= 100 + if(temp <= 66) + . = max(0, min(255, 99.4708025861 * log(temp) - 161.1195681661)) + else + . = max(0, min(255, 288.1221695283 * ((temp - 60) ** -0.0755148492))) + +/proc/heat2color_b(temp) + temp /= 100 + if(temp >= 66) + . = 255 + else + if(temp <= 16) + . = 0 + else + . = max(0, min(255, 138.5177312231 * log(temp - 10) - 305.0447927307)) + +// Very ugly, BYOND doesn't support unix time and rounding errors make it really hard to convert it to BYOND time. +// returns "YYYY-MM-DD" by default +/proc/unix2date(timestamp, seperator = "-") + if(timestamp < 0) + return 0 //Do not accept negative values + + var/const/dayInSeconds = 86400 //60secs*60mins*24hours + var/const/daysInYear = 365 //Non Leap Year + var/const/daysInLYear = daysInYear + 1//Leap year + var/days = round(timestamp / dayInSeconds) //Days passed since UNIX Epoc + var/year = 1970 //Unix Epoc begins 1970-01-01 + var/tmpDays = days + 1 //If passed (timestamp < dayInSeconds), it will return 0, so add 1 + var/monthsInDays = list() //Months will be in here ***Taken from the PHP source code*** + var/month = 1 //This will be the returned MONTH NUMBER. + var/day //This will be the returned day number. + + while(tmpDays > daysInYear) //Start adding years to 1970 + year++ + if(isLeap(year)) + tmpDays -= daysInLYear + else + tmpDays -= daysInYear + + if(isLeap(year)) //The year is a leap year + monthsInDays = list(-1,30,59,90,120,151,181,212,243,273,304,334) + else + monthsInDays = list(0,31,59,90,120,151,181,212,243,273,304,334) + + var/mDays = 0; + var/monthIndex = 0; + + for(var/m in monthsInDays) + monthIndex++ + if(tmpDays > m) + mDays = m + month = monthIndex + + day = tmpDays - mDays //Setup the date + + return "[year][seperator][((month < 10) ? "0[month]" : month)][seperator][((day < 10) ? "0[day]" : day)]" + +/proc/isLeap(y) + return ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0)) + +/proc/atomtypes2nameassoclist(var/list/atom_types) + . = list() + for(var/atom_type in atom_types) + var/atom/A = atom_type + .[initial(A.name)] = atom_type + . = sortAssoc(.) + +/proc/atomtype2nameassoclist(var/atom_type) + return atomtypes2nameassoclist(typesof(atom_type)) + +//Splits the text of a file at seperator and returns them in a list. +/world/proc/file2list(filename, seperator="\n") + return splittext(file2text(filename), seperator) diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm new file mode 100644 index 00000000..e80bd881 --- /dev/null +++ b/code/_helpers/unsorted.dm @@ -0,0 +1,1149 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/* + * A large number of misc global procs. + */ + +//Checks if all high bits in req_mask are set in bitfield +#define BIT_TEST_ALL(bitfield, req_mask) ((~(bitfield) & (req_mask)) == 0) + +//Inverts the colour of an HTML string +/proc/invertHTML(HTMLstring) + + if (!( istext(HTMLstring) )) + CRASH("Given non-text argument!") + return + else + if (length(HTMLstring) != 7) + CRASH("Given non-HTML argument!") + return + var/textr = copytext(HTMLstring, 2, 4) + var/textg = copytext(HTMLstring, 4, 6) + var/textb = copytext(HTMLstring, 6, 8) + var/r = hex2num(textr) + var/g = hex2num(textg) + var/b = hex2num(textb) + textr = num2hex(255 - r) + textg = num2hex(255 - g) + textb = num2hex(255 - b) + if (length(textr) < 2) + textr = text("0[]", textr) + if (length(textg) < 2) + textr = text("0[]", textg) + if (length(textb) < 2) + textr = text("0[]", textb) + return text("#[][][]", textr, textg, textb) + return + +//Returns the middle-most value +/proc/dd_range(var/low, var/high, var/num) + return max(low,min(high,num)) + +//Returns whether or not A is the middle most value +/proc/InRange(var/A, var/lower, var/upper) + if(A < lower) return 0 + if(A > upper) return 0 + return 1 + + +/proc/Get_Angle(atom/movable/start,atom/movable/end)//For beams. + if(!start || !end) return 0 + var/dy + var/dx + dy=(32*end.y+end.pixel_y)-(32*start.y+start.pixel_y) + dx=(32*end.x+end.pixel_x)-(32*start.x+start.pixel_x) + if(!dy) + return (dx>=0)?90:270 + .=Arctan(dx/dy) + if(dy<0) + .+=180 + else if(dx<0) + .+=360 + +//Returns location. Returns null if no location was found. +/proc/get_teleport_loc(turf/location,mob/target,distance = 1, density = 0, errorx = 0, errory = 0, eoffsetx = 0, eoffsety = 0) +/* +Location where the teleport begins, target that will teleport, distance to go, density checking 0/1(yes/no). +Random error in tile placement x, error in tile placement y, and block offset. +Block offset tells the proc how to place the box. Behind teleport location, relative to starting location, forward, etc. +Negative values for offset are accepted, think of it in relation to North, -x is west, -y is south. Error defaults to positive. +Turf and target are seperate in case you want to teleport some distance from a turf the target is not standing on or something. +*/ + + var/dirx = 0//Generic location finding variable. + var/diry = 0 + + var/xoffset = 0//Generic counter for offset location. + var/yoffset = 0 + + var/b1xerror = 0//Generic placing for point A in box. The lower left. + var/b1yerror = 0 + var/b2xerror = 0//Generic placing for point B in box. The upper right. + var/b2yerror = 0 + + errorx = abs(errorx)//Error should never be negative. + errory = abs(errory) + //var/errorxy = round((errorx+errory)/2)//Used for diagonal boxes. + + switch(target.dir)//This can be done through equations but switch is the simpler method. And works fast to boot. + //Directs on what values need modifying. + if(1)//North + diry+=distance + yoffset+=eoffsety + xoffset+=eoffsetx + b1xerror-=errorx + b1yerror-=errory + b2xerror+=errorx + b2yerror+=errory + if(2)//South + diry-=distance + yoffset-=eoffsety + xoffset+=eoffsetx + b1xerror-=errorx + b1yerror-=errory + b2xerror+=errorx + b2yerror+=errory + if(4)//East + dirx+=distance + yoffset+=eoffsetx//Flipped. + xoffset+=eoffsety + b1xerror-=errory//Flipped. + b1yerror-=errorx + b2xerror+=errory + b2yerror+=errorx + if(8)//West + dirx-=distance + yoffset-=eoffsetx//Flipped. + xoffset+=eoffsety + b1xerror-=errory//Flipped. + b1yerror-=errorx + b2xerror+=errory + b2yerror+=errorx + + var/turf/destination=locate(location.x+dirx,location.y+diry,location.z) + + if(destination)//If there is a destination. + if(errorx||errory)//If errorx or y were specified. + var/destination_list[] = list()//To add turfs to list. + //destination_list = new() + /*This will draw a block around the target turf, given what the error is. + Specifying the values above will basically draw a different sort of block. + If the values are the same, it will be a square. If they are different, it will be a rectengle. + In either case, it will center based on offset. Offset is position from center. + Offset always calculates in relation to direction faced. In other words, depending on the direction of the teleport, + the offset should remain positioned in relation to destination.*/ + + var/turf/center = locate((destination.x+xoffset),(destination.y+yoffset),location.z)//So now, find the new center. + + //Now to find a box from center location and make that our destination. + for(var/turf/T in block(locate(center.x+b1xerror,center.y+b1yerror,location.z), locate(center.x+b2xerror,center.y+b2yerror,location.z) )) + if(density && T.contains_dense_objects()) continue//If density was specified. + if(T.x>world.maxx || T.x<1) continue//Don't want them to teleport off the map. + if(T.y>world.maxy || T.y<1) continue + destination_list += T + if(destination_list.len) + destination = pick(destination_list) + else return + + else//Same deal here. + if(density && destination.contains_dense_objects()) return + if(destination.x>world.maxx || destination.x<1) return + if(destination.y>world.maxy || destination.y<1) return + else return + + return destination + + + +/proc/LinkBlocked(turf/A, turf/B) + if(A == null || B == null) return 1 + var/adir = get_dir(A,B) + var/rdir = get_dir(B,A) + if((adir & (NORTH|SOUTH)) && (adir & (EAST|WEST))) // diagonal + var/iStep = get_step(A,adir&(NORTH|SOUTH)) + if(!LinkBlocked(A,iStep) && !LinkBlocked(iStep,B)) return 0 + + var/pStep = get_step(A,adir&(EAST|WEST)) + if(!LinkBlocked(A,pStep) && !LinkBlocked(pStep,B)) return 0 + return 1 + + if(DirBlocked(A,adir)) return 1 + if(DirBlocked(B,rdir)) return 1 + return 0 + + +/proc/DirBlocked(turf/loc,var/dir) + for(var/obj/structure/window/D in loc) + if(!D.density) continue + if(D.dir == SOUTHWEST) return 1 + if(D.dir == dir) return 1 + + for(var/obj/machinery/door/D in loc) + if(!D.density) continue + if(istype(D, /obj/machinery/door/window)) + if((dir & SOUTH) && (D.dir & (EAST|WEST))) return 1 + if((dir & EAST ) && (D.dir & (NORTH|SOUTH))) return 1 + else return 1 // it's a real, air blocking door + return 0 + +/proc/TurfBlockedNonWindow(turf/loc) + for(var/obj/O in loc) + if(O.density && !istype(O, /obj/structure/window)) + return 1 + return 0 + +/proc/sign(x) + return x!=0?x/abs(x):0 + +/proc/getline(atom/M,atom/N)//Ultra-Fast Bresenham Line-Drawing Algorithm + var/px=M.x //starting x + var/py=M.y + var/line[] = list(locate(px,py,M.z)) + var/dx=N.x-px //x distance + var/dy=N.y-py + var/dxabs=abs(dx)//Absolute value of x distance + var/dyabs=abs(dy) + var/sdx=sign(dx) //Sign of x distance (+ or -) + var/sdy=sign(dy) + var/x=dxabs>>1 //Counters for steps taken, setting to distance/2 + var/y=dyabs>>1 //Bit-shifting makes me l33t. It also makes getline() unnessecarrily fast. + var/j //Generic integer for counting + if(dxabs>=dyabs) //x distance is greater than y + for(j=0;j=dxabs) //Every dyabs steps, step once in y direction + y-=dxabs + py+=sdy + px+=sdx //Step on in x direction + line+=locate(px,py,M.z)//Add the turf to the list + else + for(j=0;j=dyabs) + x-=dyabs + px+=sdx + py+=sdy + line+=locate(px,py,M.z) + return line + +#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 + . += LOCATE_COORDS(center.x + x, center.y - y, center.z) //upper right right + . += LOCATE_COORDS(center.x - x, center.y + y, center.z) //lower left left + . += LOCATE_COORDS(center.x - y, center.y + x, center.z) //lower lower left + . += LOCATE_COORDS(center.x + y, center.y + x, center.z) //lower lower right + . += LOCATE_COORDS(center.x + x, center.y + y, center.z) //lower right right + + if(p < 0) + p += 4*x++ + 6; + else + p += 4*(x++ - y--) + 10; + +#undef LOCATE_COORDS + +//Returns whether or not a player is a guest using their ckey as an input +/proc/IsGuestKey(key) + if (findtext(key, "Guest-", 1, 7) != 1) //was findtextEx + return 0 + + var/i = 7, ch, len = length(key) + + if(copytext(key, 7, 8) == "W") //webclient + i++ + + for (, i <= len, ++i) + ch = text2ascii(key, i) + if (ch < 48 || ch > 57) + return 0 + return 1 + +//Ensure the frequency is within bounds of what it should be sending/recieving at +/proc/sanitize_frequency(var/f, var/low = PUBLIC_LOW_FREQ, var/high = PUBLIC_HIGH_FREQ) + f = round(f) + f = max(low, f) + f = min(high, f) + if ((f % 2) == 0) //Ensure the last digit is an odd number + f += 1 + return f + +//Turns 1479 into 147.9 +/proc/format_frequency(var/f) + return "[round(f / 10)].[f % 10]" + +//Generalised helper proc for letting mobs rename themselves. Used to be clname() and ainame() +//Last modified by Carn +/mob/proc/rename_self(var/role, var/allow_numbers=0) + spawn(0) + var/oldname = real_name + + var/time_passed = world.time + var/newname + + for(var/i=1,i<=3,i++) //we get 3 attempts to pick a suitable name. + newname = input(src,"You are \a [role]. Would you like to change your name to something else?", "Name change",oldname) as text + if((world.time-time_passed)>3000) + return //took too long + newname = sanitizeName(newname, ,allow_numbers) //returns null if the name doesn't meet some basic requirements. Tidies up a few other things like bad-characters. + + for(var/mob/living/M in GLOB.player_list) + if(M == src) + continue + if(!newname || M.real_name == newname) + newname = null + break + if(newname) + break //That's a suitable name! + to_chat(src, "Sorry, that [role]-name wasn't appropriate, please try another. It's possibly too long/short, has bad characters or is already taken.") + + if(!newname) //we'll stick with the oldname then + return + + fully_replace_character_name(newname) + + + +//Picks a string of symbols to display as the law number for hacked or ion laws +/proc/ionnum() + return "[pick("1","2","3","4","5","6","7","8","9","0")][pick("!","@","#","$","%","^","&","*")][pick("!","@","#","$","%","^","&","*")][pick("!","@","#","$","%","^","&","*")]" + +//When an AI is activated, it can choose from a list of non-slaved borgs to have as a slave. +/proc/freeborg() + var/select = null + var/list/borgs = list() + for (var/mob/living/silicon/robot/A in GLOB.player_list) + if (A.stat == 2 || A.connected_ai || A.scrambledcodes || istype(A,/mob/living/silicon/robot/drone)) + continue + var/name = "[A.real_name] ([A.modtype] [A.braintype])" + borgs[name] = A + + if (borgs.len) + select = input("Unshackled borg signals detected:", "Borg selection", null, null) as null|anything in borgs + return borgs[select] + +//When a borg is activated, it can choose which AI it wants to be slaved to +/proc/active_ais() + . = list() + for(var/mob/living/silicon/ai/A in GLOB.living_mob_list_) + if(A.stat == DEAD) + continue + if(A.control_disabled == 1) + continue + . += A + return . + +//Find an active ai with the least borgs. VERBOSE PROCNAME HUH! +/proc/select_active_ai_with_fewest_borgs() + var/mob/living/silicon/ai/selected + var/list/active = active_ais() + for(var/mob/living/silicon/ai/A in active) + if(!selected || (selected.connected_robots.len > A.connected_robots.len)) + selected = A + + return selected + +/proc/select_active_ai(var/mob/user) + var/list/ais = active_ais() + if(ais.len) + if(user) . = input(usr,"AI signals detected:", "AI selection") in ais + else . = pick(ais) + return . + +/proc/get_sorted_mobs() + var/list/old_list = getmobs() + var/list/AI_list = list() + var/list/Dead_list = list() + var/list/keyclient_list = list() + var/list/key_list = list() + var/list/logged_list = list() + for(var/named in old_list) + var/mob/M = old_list[named] + if(issilicon(M)) + AI_list |= M + else if(isghost(M) || M.stat == DEAD) + Dead_list |= M + else if(M.key && M.client) + keyclient_list |= M + else if(M.key) + key_list |= M + else + logged_list |= M + old_list.Remove(named) + var/list/new_list = list() + new_list += AI_list + new_list += keyclient_list + new_list += key_list + new_list += logged_list + new_list += Dead_list + return new_list + +//Returns a list of all mobs with their name +/proc/getmobs() + + var/list/mobs = sortmobs() + var/list/names = list() + var/list/creatures = list() + var/list/namecounts = list() + for(var/mob/M in mobs) + var/name = M.name + if (name in names) + namecounts[name]++ + name = "[name] ([namecounts[name]])" + else + names.Add(name) + namecounts[name] = 1 + if (M.real_name && M.real_name != M.name) + name += " \[[M.real_name]\]" + if (M.stat == DEAD) + if(isobserver(M)) + name += " \[observer\]" + else + name += " \[dead\]" + creatures[name] = M + + return creatures + +/proc/get_follow_targets() + return follow_repository.get_follow_targets() + +//Orders mobs by type then by name +/proc/sortmobs() + var/list/moblist = list() + var/list/sortmob = sortAtom(SSmobs.mob_list) + for(var/mob/observer/eye/M in sortmob) + moblist.Add(M) + for(var/mob/living/silicon/ai/M in sortmob) + moblist.Add(M) + for(var/mob/living/silicon/pai/M in sortmob) + moblist.Add(M) + for(var/mob/living/silicon/robot/M in sortmob) + moblist.Add(M) + for(var/mob/living/carbon/human/M in sortmob) + moblist.Add(M) + for(var/mob/living/carbon/brain/M in sortmob) + moblist.Add(M) + for(var/mob/living/carbon/alien/M in sortmob) + moblist.Add(M) + for(var/mob/observer/ghost/M in sortmob) + moblist.Add(M) + for(var/mob/new_player/M in sortmob) + moblist.Add(M) + for(var/mob/living/carbon/slime/M in sortmob) + moblist.Add(M) + for(var/mob/living/simple_animal/M in sortmob) + moblist.Add(M) + return moblist + +//Forces a variable to be posative +/proc/modulus(var/M) + if(M >= 0) + return M + if(M < 0) + return -M + +// returns the turf located at the map edge in the specified direction relative to A +// used for mass driver +/proc/get_edge_target_turf(var/atom/A, var/direction) + + var/turf/target = locate(A.x, A.y, A.z) + if(!A || !target) + return 0 + //since NORTHEAST == NORTH & EAST, etc, doing it this way allows for diagonal mass drivers in the future + //and isn't really any more complicated + + // Note diagonal directions won't usually be accurate + if(direction & NORTH) + target = locate(target.x, world.maxy, target.z) + if(direction & SOUTH) + target = locate(target.x, 1, target.z) + if(direction & EAST) + target = locate(world.maxx, target.y, target.z) + if(direction & WEST) + target = locate(1, target.y, target.z) + + return target + +// returns turf relative to A in given direction at set range +// result is bounded to map size +// note range is non-pythagorean +// used for disposal system +/proc/get_ranged_target_turf(var/atom/A, var/direction, var/range) + + var/x = A.x + var/y = A.y + if(direction & NORTH) + y = min(world.maxy, y + range) + if(direction & SOUTH) + y = max(1, y - range) + if(direction & EAST) + x = min(world.maxx, x + range) + if(direction & WEST) + x = max(1, x - range) + + return locate(x,y,A.z) + + +// returns turf relative to A offset in dx and dy tiles +// bound to map limits +/proc/get_offset_target_turf(var/atom/A, var/dx, var/dy) + var/x = min(world.maxx, max(1, A.x + dx)) + 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. +/proc/between(var/low, var/middle, var/high) + return max(min(middle, high), low) + +proc/Arctan(x) + var/y=arcsin(x/sqrt(1+x*x)) + return y + +//returns random gauss number +proc/GaussRand(var/sigma) + var/x,y,rsq + do + x=2*rand()-1 + y=2*rand()-1 + rsq=x*x+y*y + while(rsq>1 || !rsq) + return sigma*y*sqrt(-2*log(rsq)/rsq) + +//returns random gauss number, rounded to 'roundto' +proc/GaussRandRound(var/sigma,var/roundto) + return round(GaussRand(sigma),roundto) + +//Will return the contents of an atom recursivly to a depth of 'searchDepth' +/atom/proc/GetAllContents(searchDepth = 5) + var/list/toReturn = list() + + for(var/atom/part in contents) + toReturn += part + if(part.contents.len && searchDepth) + toReturn += part.GetAllContents(searchDepth - 1) + + return toReturn + +//Step-towards method of determining whether one atom can see another. Similar to viewers() +/proc/can_see(var/atom/source, var/atom/target, var/length=5) // I couldn't be arsed to do actual raycasting :I This is horribly inaccurate. + var/turf/current = get_turf(source) + var/turf/target_turf = get_turf(target) + var/steps = 0 + + if(!current || !target_turf) + return 0 + + while(current != target_turf) + if(steps > length) return 0 + if(current.opacity) return 0 + for(var/atom/A in current) + if(A.opacity) return 0 + current = get_step_towards(current, target_turf) + steps++ + + return 1 + +/proc/is_blocked_turf(var/turf/T) + var/cant_pass = 0 + if(T.density) cant_pass = 1 + for(var/atom/A in T) + if(A.density)//&&A.anchored + cant_pass = 1 + return cant_pass + +/proc/get_step_towards2(var/atom/ref , var/atom/trg) + var/base_dir = get_dir(ref, get_step_towards(ref,trg)) + var/turf/temp = get_step_towards(ref,trg) + + if(is_blocked_turf(temp)) + var/dir_alt1 = turn(base_dir, 90) + var/dir_alt2 = turn(base_dir, -90) + var/turf/turf_last1 = temp + var/turf/turf_last2 = temp + var/free_tile = null + var/breakpoint = 0 + + while(!free_tile && breakpoint < 10) + if(!is_blocked_turf(turf_last1)) + free_tile = turf_last1 + break + if(!is_blocked_turf(turf_last2)) + free_tile = turf_last2 + break + turf_last1 = get_step(turf_last1,dir_alt1) + turf_last2 = get_step(turf_last2,dir_alt2) + breakpoint++ + + if(!free_tile) return get_step(ref, base_dir) + else return get_step_towards(ref,free_tile) + + else return get_step(ref, base_dir) + +/proc/step_towards_3d(var/atom/movable/Ref, var/atom/movable/Trg) + if (!Ref || !Trg) + return 0 + if(Ref.z == Trg.z) + var/S = Ref.loc + step_towards(Ref, Trg) + if(Ref.loc != S) + return 1 + return 0 + + var/dx = (Trg.x - Ref.x) / max(abs(Trg.x - Ref.x), 1) + var/dy = (Trg.y - Ref.y) / max(abs(Trg.y - Ref.y), 1) + var/dz = (Trg.z - Ref.z) / max(abs(Trg.z - Ref.z), 1) + + var/turf/T = locate(Ref.x + dx, Ref.y + dy, Ref.z + dz) + + if (!T) + return 0 + + Ref.Move(T) + + if (Ref.loc != T) + return 0 + + return 1 + + +//Takes: Anything that could possibly have variables and a varname to check. +//Returns: 1 if found, 0 if not. +/proc/hasvar(var/datum/A, var/varname) + if(A.vars.Find(lowertext(varname))) return 1 + else return 0 + +//Takes: Area type as text string or as typepath OR an instance of the area. +//Returns: A list of all areas of that type in the world. +/proc/get_areas(var/areatype) + if(!areatype) return null + if(istext(areatype)) areatype = text2path(areatype) + if(isarea(areatype)) + var/area/areatemp = areatype + areatype = areatemp.type + + var/list/areas = new/list() + for(var/area/N in world) + 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 atoms (objs, turfs, mobs) in areas of that type of that type in the world. +/proc/get_area_all_atoms(var/areatype) + if(!areatype) return null + if(istext(areatype)) areatype = text2path(areatype) + if(isarea(areatype)) + var/area/areatemp = areatype + areatype = areatemp.type + + var/list/atoms = new/list() + for(var/area/N in world) + if(istype(N, areatype)) + for(var/atom/A in N) + atoms += A + return atoms + +/area/proc/move_contents_to(var/area/A) + //Takes: Area. + //Returns: Nothing. + //Notes: Attempts to move the contents of one area to another area. + // Movement based on lower left corner. + + if(!A || !src) return + + var/list/turfs_src = get_area_turfs("\ref[src]") + + if(!turfs_src.len) return + + //figure out a suitable origin - this assumes the shuttle areas are the exact same size and shape + //might be worth doing this with a shuttle core object instead of areas, in the future + var/src_origin = locate(src.x, src.y, src.z) + var/trg_origin = locate(A.x, A.y, A.z) + + if(src_origin && trg_origin) + var/translation = get_turf_translation(src_origin, trg_origin, turfs_src) + translate_turfs(translation, null) + +proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0) + if(!original) + return null + + var/obj/O = null + + if(sameloc) + O=new original.type(original.loc) + else + O=new original.type(locate(0,0,0)) + + if(perfectcopy) + if((O) && (original)) + for(var/V in original.vars) + if(!(V in list("type","loc","locs","vars", "parent", "parent_type","verbs","ckey","key"))) + O.vars[V] = original.vars[V] + return O + + + +/datum/coords //Simple datum for storing coordinates. + var/x_pos = null + var/y_pos = null + var/z_pos = null + +/area/proc/copy_contents_to(var/area/A , var/platingRequired = 0 ) + //Takes: Area. Optional: If it should copy to areas that don't have plating + //Returns: Nothing. + //Notes: Attempts to move the contents of one area to another area. + // Movement based on lower left corner. Tiles that do not fit + // into the new area will not be moved. + + // Does *not* affect gases etc; copied turfs will be changed via ChangeTurf, and the dir, icon, and icon_state copied. All other vars will remain default. + + if(!A || !src) return 0 + + var/list/turfs_src = get_area_turfs(src.type) + var/list/turfs_trg = get_area_turfs(A.type) + + var/src_min_x = 0 + var/src_min_y = 0 + for (var/turf/T in turfs_src) + if(T.x < src_min_x || !src_min_x) src_min_x = T.x + if(T.y < src_min_y || !src_min_y) src_min_y = T.y + + var/trg_min_x = 0 + var/trg_min_y = 0 + for (var/turf/T in turfs_trg) + if(T.x < trg_min_x || !trg_min_x) trg_min_x = T.x + if(T.y < trg_min_y || !trg_min_y) trg_min_y = T.y + + var/list/refined_src = new/list() + for(var/turf/T in turfs_src) + refined_src += T + refined_src[T] = new/datum/coords + var/datum/coords/C = refined_src[T] + C.x_pos = (T.x - src_min_x) + C.y_pos = (T.y - src_min_y) + + var/list/refined_trg = new/list() + for(var/turf/T in turfs_trg) + refined_trg += T + refined_trg[T] = new/datum/coords + var/datum/coords/C = refined_trg[T] + C.x_pos = (T.x - trg_min_x) + C.y_pos = (T.y - trg_min_y) + + var/list/toupdate = new/list() + + var/copiedobjs = list() + + + moving: + for (var/turf/T in refined_src) + var/datum/coords/C_src = refined_src[T] + for (var/turf/B in refined_trg) + var/datum/coords/C_trg = refined_trg[B] + if(C_src.x_pos == C_trg.x_pos && C_src.y_pos == C_trg.y_pos) + + var/old_dir1 = T.dir + var/old_icon_state1 = T.icon_state + var/old_icon1 = T.icon + var/old_overlays = T.overlays.Copy() + var/old_underlays = T.underlays.Copy() + + if(platingRequired) + if(istype(B, get_base_turf_by_area(B))) + continue moving + + var/turf/X = B + X.ChangeTurf(T.type) + X.set_dir(old_dir1) + X.icon_state = old_icon_state1 + X.icon = old_icon1 //Shuttle floors are in shuttle.dmi while the defaults are floors.dmi + X.overlays = old_overlays + X.underlays = old_underlays + + var/list/objs = new/list() + var/list/newobjs = new/list() + var/list/mobs = new/list() + var/list/newmobs = new/list() + + for(var/obj/O in T) + + if(!istype(O,/obj) || !O.simulated) + continue + + objs += O + + + for(var/obj/O in objs) + newobjs += DuplicateObject(O , 1) + + + for(var/obj/O in newobjs) + O.forceMove(X) + + for(var/mob/M in T) + + if(!istype(M,/mob) || !M.simulated) continue // If we need to check for more mobs, I'll add a variable + mobs += M + + for(var/mob/M in mobs) + newmobs += DuplicateObject(M , 1) + + for(var/mob/M in newmobs) + M.forceMove(X) + + copiedobjs += newobjs + copiedobjs += newmobs + +// var/area/AR = X.loc + +// if(AR.dynamic_lighting) +// X.opacity = !X.opacity +// X.sd_SetOpacity(!X.opacity) //TODO: rewrite this code so it's not messed by lighting ~Carn + + toupdate += X + + refined_src -= T + refined_trg -= B + continue moving + + + + + if(toupdate.len) + for(var/turf/simulated/T1 in toupdate) + SSair.mark_for_update(T1) + + return copiedobjs + + + +proc/get_cardinal_dir(atom/A, atom/B) + var/dx = abs(B.x - A.x) + var/dy = abs(B.y - A.y) + return get_dir(A, B) & (rand() * (dx+dy) < dy ? 3 : 12) + +//chances are 1:value. anyprob(1) will always return true +proc/anyprob(value) + return (rand(1,value)==value) + +proc/view_or_range(distance = world.view , center = usr , type) + switch(type) + if("view") + . = view(distance,center) + if("range") + . = range(distance,center) + return + +proc/oview_or_orange(distance = world.view , center = usr , type) + switch(type) + if("view") + . = oview(distance,center) + if("range") + . = orange(distance,center) + return + +proc/get_mob_with_client_list() + var/list/mobs = list() + for(var/mob/M in SSmobs.mob_list) + if (M.client) + mobs += M + return mobs + + +/proc/parse_zone(zone) + if(zone == BP_R_HAND) return "right hand" + else if (zone == BP_L_HAND) return "left hand" + else if (zone == BP_L_ARM) return "left arm" + else if (zone == BP_R_ARM) return "right arm" + else if (zone == BP_L_LEG) return "left leg" + else if (zone == BP_R_LEG) return "right leg" + else if (zone == BP_L_FOOT) return "left foot" + else if (zone == BP_R_FOOT) return "right foot" + else if (zone == BP_L_HAND) return "left hand" + else if (zone == BP_R_HAND) return "right hand" + else if (zone == BP_L_FOOT) return "left foot" + else if (zone == BP_R_FOOT) return "right foot" + else return zone + +/proc/get(atom/loc, type) + while(loc) + if(istype(loc, type)) + return loc + loc = loc.loc + return null + +/proc/get_turf_or_move(turf/location) + return get_turf(location) + + +//Quick type checks for some tools +var/global/list/common_tools = list( +/obj/item/stack/cable_coil, +/obj/item/weapon/wrench, +/obj/item/weapon/weldingtool, +/obj/item/weapon/screwdriver, +/obj/item/weapon/wirecutters, +/obj/item/device/multitool, +/obj/item/weapon/crowbar) + +/proc/istool(O) + if(O && is_type_in_list(O, common_tools)) + return 1 + return 0 + +/proc/is_hot(obj/item/W as obj) + switch(W.type) + if(/obj/item/weapon/weldingtool) + var/obj/item/weapon/weldingtool/WT = W + if(WT.isOn()) + return 3800 + else + return 0 + if(/obj/item/weapon/flame/lighter) + if(W:lit) + return 1500 + else + return 0 + if(/obj/item/weapon/flame/match) + if(W:lit) + return 1000 + else + return 0 + if(/obj/item/clothing/mask/smokable/cigarette) + if(W:lit) + return 1000 + else + return 0 + if(/obj/item/weapon/gun/energy/plasmacutter) + return 3800 + if(/obj/item/weapon/melee/energy) + return 3500 + else + return 0 + + return 0 + +//Whether or not the given item counts as sharp in terms of dealing damage +/proc/is_sharp(obj/O as obj) + if (!O) return 0 + if (O.sharp) return 1 + if (O.edge) return 1 + return 0 + +//Whether or not the given item counts as cutting with an edge in terms of removing limbs +/proc/has_edge(obj/O as obj) + if (!O) return 0 + if (O.edge) return 1 + return 0 + + +//For items that can puncture e.g. thick plastic but aren't necessarily sharp +//Returns 1 if the given item is capable of popping things like balloons, inflatable barriers, or cutting police tape. +/obj/item/proc/can_puncture() + return src.sharp + +/obj/item/weapon/screwdriver/can_puncture() + return 1 + +/obj/item/weapon/pen/can_puncture() + return 1 + +/obj/item/weapon/weldingtool/can_puncture() + return 1 + +/obj/item/weapon/screwdriver/can_puncture() + return 1 + +/obj/item/weapon/shovel/can_puncture() //includes spades + return 1 + +/obj/item/weapon/flame/can_puncture() + return src.lit + +/obj/item/clothing/mask/smokable/cigarette/can_puncture() + return src.lit + +//check if mob is lying down on something we can operate him on. +/proc/can_operate(mob/living/carbon/M, mob/living/carbon/user) + var/turf/T = get_turf(M) + if(locate(/obj/machinery/optable, T)) + . = TRUE + if(locate(/obj/structure/bed, T)) + . = TRUE + if(locate(/obj/structure/table, T)) + . = TRUE + if(locate(/obj/effect/rune/, T)) + . = TRUE + if(M.lying) + . = TRUE + + if(M == user) + var/hitzone = check_zone(user.zone_sel.selecting) + var/list/badzones = list(BP_HEAD) + if(user.hand) + badzones += BP_L_ARM + badzones += BP_L_HAND + else + badzones += BP_R_ARM + badzones += BP_R_HAND + if(hitzone in badzones) + return FALSE + +/proc/reverse_direction(var/dir) + switch(dir) + if(NORTH) + return SOUTH + if(NORTHEAST) + return SOUTHWEST + if(EAST) + return WEST + if(SOUTHEAST) + return NORTHWEST + if(SOUTH) + return NORTH + if(SOUTHWEST) + return NORTHEAST + if(WEST) + return EAST + if(NORTHWEST) + return SOUTHEAST + +/* +Checks if that loc and dir has a item on the wall +*/ +var/list/WALLITEMS = list( + /obj/machinery/power/apc, /obj/machinery/alarm, /obj/item/device/radio/intercom, + /obj/structure/extinguisher_cabinet, /obj/structure/reagent_dispensers/peppertank, + /obj/machinery/status_display, /obj/machinery/requests_console, /obj/machinery/light_switch, /obj/structure/sign, + /obj/machinery/newscaster, /obj/machinery/firealarm, /obj/structure/noticeboard, + /obj/item/weapon/storage/secure/safe, /obj/machinery/door_timer, /obj/machinery/flasher, /obj/machinery/keycard_auth, + /obj/structure/mirror, /obj/structure/fireaxecabinet, /obj/structure/filingcabinet/wallcabinet + ) +/proc/gotwallitem(loc, dir) + for(var/obj/O in loc) + for(var/item in WALLITEMS) + if(istype(O, item)) + //Direction works sometimes + if(O.dir == dir) + return 1 + + //Some stuff doesn't use dir properly, so we need to check pixel instead + switch(dir) + if(SOUTH) + if(O.pixel_y > 10) + return 1 + if(NORTH) + if(O.pixel_y < -10) + return 1 + if(WEST) + if(O.pixel_x > 10) + return 1 + if(EAST) + if(O.pixel_x < -10) + return 1 + + + //Some stuff is placed directly on the wallturf (signs) + for(var/obj/O in get_step(loc, dir)) + for(var/item in WALLITEMS) + if(istype(O, item)) + if(O.pixel_x == 0 && O.pixel_y == 0) + return 1 + return 0 + +/proc/format_text(text) + return replacetext(replacetext(text,"\proper ",""),"\improper ","") + +/proc/topic_link(var/datum/D, var/arglist, var/content) + if(istype(arglist,/list)) + arglist = list2params(arglist) + return "[content]" + +/proc/get_random_colour(var/simple = FALSE, var/lower = 0, var/upper = 255) + var/colour + if(simple) + colour = pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF")) + else + for(var/i=1;i<=3;i++) + var/temp_col = "[num2hex(rand(lower,upper))]" + if(length(temp_col )<2) + temp_col = "0[temp_col]" + colour += temp_col + return "#[colour]" + +GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) + +//Version of view() which ignores darkness, because BYOND doesn't have it. +/proc/dview(var/range = world.view, var/center, var/invis_flags = 0) + if(!center) + return + + GLOB.dview_mob.loc = center + GLOB.dview_mob.see_invisible = invis_flags + . = view(range, GLOB.dview_mob) + GLOB.dview_mob.loc = null + +/mob/dview + invisibility = 101 + density = 0 + + anchored = 1 + simulated = 0 + + see_in_dark = 1e6 + + virtual_mob = null + +/mob/dview/Destroy() + crash_with("Prevented attempt to delete dview mob: [log_info_line(src)]") + return QDEL_HINT_LETMELIVE // Prevents destruction + +/atom/proc/get_light_and_color(var/atom/origin) + if(origin) + color = origin.color + set_light(origin.light_range, origin.light_power, origin.light_color) + +/mob/dview/Initialize() + . = ..() + // We don't want to be in any mob lists; we're a dummy not a mob. + STOP_PROCESSING(SSmobs, src) + +// call to generate a stack trace and print to runtime logs +/proc/crash_with(msg) + CRASH(msg) + +/proc/pass() + return + +//this should recursively check the type of loc until it reaches a turf or nullspace - Lohi +/proc/is_parent_loc(atom/to_check, target_type) + var/atom/target = to_check + while(isloc(target) && !isturf(target)) + target = target.loc + if(istype(target, target_type)) + return TRUE + return FALSE + + +/proc/getviewsize(view) + var/viewX + var/viewY + if(isnum(view)) + var/totalviewrange = 1 + 2 * view + viewX = totalviewrange + viewY = totalviewrange + else + var/list/viewrangelist = splittext(view,"x") + viewX = text2num(viewrangelist[1]) + viewY = text2num(viewrangelist[2]) + return list(viewX, viewY) \ No newline at end of file diff --git a/code/_helpers/vector.dm b/code/_helpers/vector.dm new file mode 100644 index 00000000..797dbe37 --- /dev/null +++ b/code/_helpers/vector.dm @@ -0,0 +1,135 @@ +/* +plot_vector is a helper datum for plotting a path in a straight line towards a target turf. +This datum converts from world space (turf.x and turf.y) to pixel space, which the datum keeps track of itself. This +should work with any size turfs (i.e. 32x32, 64x64) as it references world.icon_size (note: not actually tested with +anything other than 32x32 turfs). + +setup() + This should be called after creating a new instance of a plot_vector datum. + This does the initial setup and calculations. Since we are travelling in a straight line we only need to calculate + the vector and x/y steps once. x/y steps are capped to 1 full turf, whichever is further. If we are travelling along + the y axis each step will be +/- 1 y, and the x movement reduced based on the angle (tangent calculation). After + this every subsequent step will be incremented based on these calculations. + Inputs: + source - the turf the object is starting from + target - the target turf the object is travelling towards + xo - starting pixel_x offset, typically won't be needed, but included in case someone has a need for it later + yo - same as xo, but for the y_pixel offset + +increment() + Adds the offset to the current location - incrementing it by one step along the vector. + +return_angle() + Returns the direction (angle in degrees) the object is travelling in. + * North = 90° + * East = 0° + * South = -90° + * West = 180° + +return_hypotenuse() + Returns the distance of travel for each step of the vector, relative to each full step of movement. 1 is a full turf + length. Currently used as a multiplier for scaling effects that should be contiguous, like laser beams. + +return_location() + Returns a vector_loc datum containing the current location data of the object (see /datum/vector_loc). This includes + the turf it currently should be at, as well as the pixel offset from the centre of that turf. Typically increment() + would be called before this if you are going to move an object based on it's vector data. +*/ + +/datum/plot_vector + var/turf/source + var/turf/target + var/angle = 0 // direction of travel in degrees + var/loc_x = 0 // in pixels from the left edge of the map + var/loc_y = 0 // in pixels from the bottom edge of the map + var/loc_z = 0 // loc z is in world space coordinates (i.e. z level) - we don't care about measuring pixels for this + var/offset_x = 0 // distance to increment each step + var/offset_y = 0 + +/datum/plot_vector/proc/setup(var/turf/S, var/turf/T, var/xo = 0, var/yo = 0, var/angle_offset=0) + source = S + target = T + + if(!istype(source)) + source = get_turf(source) + if(!istype(target)) + target = get_turf(target) + + if(!istype(source) || !istype(target)) + return + + // convert coordinates to pixel space (default is 32px/turf, 8160px across for a size 255 map) + loc_x = source.x * world.icon_size + xo + loc_y = source.y * world.icon_size + yo + loc_z = source.z + + // calculate initial x and y difference + var/dx = target.x - source.x + var/dy = target.y - source.y + + // if we aren't moving anywhere; quit now + if(dx == 0 && dy == 0) + return + + // calculate the angle + angle = Atan2(dx, dy) + angle_offset + + // and some rounding to stop the increments jumping whole turfs - because byond favours certain angles + if(angle > -135 && angle < 45) + angle = Ceiling(angle) + else + angle = Floor(angle) + + // calculate the offset per increment step + if(abs(angle) in list(0, 45, 90, 135, 180)) // check if the angle is a cardinal + if(abs(angle) in list(0, 45, 135, 180)) // if so we can skip the trigonometry and set these to absolutes as + offset_x = sign(dx) // they will always be a full step in one or more directions + if(abs(angle) in list(45, 90, 135)) + offset_y = sign(dy) + else if(abs(dy) > abs(dx)) + offset_x = Cot(abs(angle)) // otherwise set the offsets + offset_y = sign(dy) + else + offset_x = sign(dx) + offset_y = Tan(angle) + if(dx < 0) + offset_y = -offset_y + + // multiply the offset by the turf pixel size + offset_x *= world.icon_size + offset_y *= world.icon_size + +/datum/plot_vector/proc/increment() + loc_x += offset_x + loc_y += offset_y + +/datum/plot_vector/proc/return_angle() + return angle + +/datum/plot_vector/proc/return_hypotenuse() + return sqrt(((offset_x / 32) ** 2) + ((offset_y / 32) ** 2)) + +/datum/plot_vector/proc/return_location(var/datum/vector_loc/data) + if(!data) + data = new() + data.loc = locate(round(loc_x / world.icon_size, 1), round(loc_y / world.icon_size, 1), loc_z) + if(!data.loc) + return + data.pixel_x = loc_x - (data.loc.x * world.icon_size) + data.pixel_y = loc_y - (data.loc.y * world.icon_size) + return data + +/* +vector_loc is a helper datum for returning precise location data from plot_vector. It includes the turf the object is in +as well as the pixel offsets. + +return_turf() + Returns the turf the object should be currently located in. +*/ +/datum/vector_loc + var/turf/loc + var/pixel_x + var/pixel_y + +/datum/vector_loc/proc/return_turf() + return loc diff --git a/code/_macros.dm b/code/_macros.dm new file mode 100644 index 00000000..8294d665 --- /dev/null +++ b/code/_macros.dm @@ -0,0 +1,165 @@ +#define PUBLIC_GAME_MODE (ticker ? (ticker.hide_mode == 0 ? master_mode : "Secret") : "Unknown") + +#define Clamp(value, low, high) (value <= low ? low : (value >= high ? high : value)) + +#define get_turf(A) get_step(A,0) + +#define isAI(A) istype(A, /mob/living/silicon/ai) + +#define isalien(A) istype(A, /mob/living/carbon/alien) + +#define isanimal(A) istype(A, /mob/living/simple_animal) + +#define isairlock(A) istype(A, /obj/machinery/door/airlock) + +#define isatom(A) istype(A, /atom) + +#define isbrain(A) istype(A, /mob/living/carbon/brain) + +#define iscarbon(A) istype(A, /mob/living/carbon) + +#define iscolorablegloves(A) (istype(A, /obj/item/clothing/gloves/color)||istype(A, /obj/item/clothing/gloves/insulated)||istype(A, /obj/item/clothing/gloves/thick)) + +#define isclient(A) istype(A, /client) + +#define iscorgi(A) istype(A, /mob/living/simple_animal/corgi) + +#define is_drone(A) istype(A, /mob/living/silicon/robot/drone) + +#define isEye(A) istype(A, /mob/observer/eye) + +#define ishuman(A) istype(A, /mob/living/carbon/human) + +#define isitem(A) istype(A, /obj/item) + +#define islist(A) istype(A, /list) + +#define isliving(A) istype(A, /mob/living) + +#define ismouse(A) istype(A, /mob/living/simple_animal/mouse) + +#define ismovable(A) istype(A, /atom/movable) + +#define isnewplayer(A) istype(A, /mob/new_player) + +#define isobj(A) istype(A, /obj) + +#define isghost(A) istype(A, /mob/observer/ghost) + +#define isobserver(A) istype(A, /mob/observer) + +#define isorgan(A) istype(A, /obj/item/organ/external) + +#define isstack(A) istype(A, /obj/item/stack) + +#define isspace(A) istype(A, /area/space) + +#define ispAI(A) istype(A, /mob/living/silicon/pai) + +#define isrobot(A) istype(A, /mob/living/silicon/robot) + +#define issilicon(A) istype(A, /mob/living/silicon) + +#define isslime(A) istype(A, /mob/living/carbon/slime) + +#define isunderwear(A) istype(A, /obj/item/underwear) + +#define isvirtualmob(A) istype(A, /mob/observer/virtual) + +#define isweakref(A) istype(A, /weakref) + +#define attack_animation(A) if(istype(A)) A.do_attack_animation(src) + +#define isopenspace(A) istype(A, /turf/simulated/open) + +#define isWrench(A) istype(A, /obj/item/weapon/wrench) + +#define isWelder(A) istype(A, /obj/item/weapon/weldingtool) + +#define isCoil(A) istype(A, /obj/item/stack/cable_coil) + +#define isWirecutter(A) istype(A, /obj/item/weapon/wirecutters) + +#define isScrewdriver(A) istype(A, /obj/item/weapon/screwdriver) + +#define isMultitool(A) istype(A, /obj/item/device/multitool) + +#define isCrowbar(A) istype(A, /obj/item/weapon/crowbar) + +#define sequential_id(key) uniqueness_repository.Generate(/datum/uniqueness_generator/id_sequential, key) + +#define random_id(key,min_id,max_id) uniqueness_repository.Generate(/datum/uniqueness_generator/id_random, key, min_id, max_id) + +#define to_world(message) to_chat(world, message) +#define to_world_log(message) world.log << message +#define sound_to(target, sound) target << sound +#define to_file(file_entry, source_var) file_entry << source_var +#define from_file(file_entry, target_var) file_entry >> target_var +#define show_browser(target, browser_content, browser_name) target << browse(browser_content, browser_name) +#define close_browser(target, browser_name) target << browse(null, browser_name) +#define show_image(target, image) target << image +#define send_rsc(target, rsc_content, rsc_name) target << browse_rsc(rsc_content, rsc_name) + +#define MAP_IMAGE_PATH "nano/images/[GLOB.using_map.path]/" + +#define map_image_file_name(z_level) "[GLOB.using_map.path]-[z_level].png" + +#define RANDOM_BLOOD_TYPE pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+") + +#define any2ref(x) "\ref[x]" + +#define CanInteract(user, state) (CanUseTopic(user, state) == STATUS_INTERACTIVE) + +#define CanInteractWith(user, target, state) (target.CanUseTopic(user, state) == STATUS_INTERACTIVE) + +#define CanPhysicallyInteract(user) CanInteract(user, GLOB.physical_state) + +#define CanPhysicallyInteractWith(user, target) CanInteractWith(user, target, GLOB.physical_state) + +#define QDEL_NULL_LIST(x) if(x) { for(var/y in x) { qdel(y) } ; x = null } + +#define QDEL_NULL(x) if(x) { qdel(x) ; x = null } + +#define QDEL_IN(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE) + +#define ARGS_DEBUG log_debug("[__FILE__] - [__LINE__]") ; for(var/arg in args) { log_debug("\t[log_info_line(arg)]") } + +// Helper macros to aid in optimizing lazy instantiation of lists. +// All of these are null-safe, you can use them without knowing if the list var is initialized yet + +//Picks from the list, with some safeties, and returns the "default" arg if it fails +#define DEFAULTPICK(L, default) ((istype(L, /list) && L:len) ? pick(L) : default) +// Ensures L is initailized after this point +#define LAZYINITLIST(L) if (!L) L = list() +// Sets a L back to null iff it is empty +#define UNSETEMPTY(L) if (L && !L.len) L = null +// Removes I from list L, and sets I to null if it is now empty +#define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } } +// Adds I to L, initalizing L if necessary +#define LAZYADD(L, I) if(!L) { L = list(); } L += I; +// Adds I to L, initalizing L if necessary, if I is not already in L +#define LAZYDISTINCTADD(L, I) if(!L) { L = list(); } L |= I; +// Sets L[A] to I, initalizing L if necessary +#define LAZYSET(L, A, I) if(!L) { L = list(); } L[A] = I; +// Reads I from L safely - Works with both associative and traditional lists. +#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null) +// Reads the length of L, returning 0 if null +#define LAZYLEN(L) length(L) +// Safely checks if I is in L +#define LAZYISIN(L, I) (L ? (I in L) : FALSE) +// Null-safe L.Cut() +#define LAZYCLEARLIST(L) if(L) L.Cut() +// Reads L or an empty list if L is not a list. Note: Does NOT assign, L may be an expression. +#define SANITIZE_LIST(L) ( islist(L) ? L : list() ) + +// Insert an object A into a sorted list using cmp_proc (/code/_helpers/cmp.dm) for comparison. +#define ADD_SORTED(list, A, cmp_proc) if(!list.len) {list.Add(A)} else {list.Insert(FindElementIndex(A, list, cmp_proc), A)} + +//Currently used in SDQL2 stuff +#define send_output(target, msg, control) target << output(msg, control) +#define send_link(target, url) target << link(url) + +// Spawns multiple objects of the same type +#define cast_new(type, num, args...) if((num) == 1) { new type(args) } else { for(var/i=0;i<(num),i++) { new type(args) } } + +#define FLAGS_EQUALS(flag, flags) ((flag & (flags)) == (flags)) diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm new file mode 100644 index 00000000..38eedf74 --- /dev/null +++ b/code/_onclick/adjacent.dm @@ -0,0 +1,146 @@ +/* + Adjacency proc for determining touch range + + This is mostly to determine if a user can enter a square for the purposes of touching something. + Examples include reaching a square diagonally or reaching something on the other side of a glass window. + + This is calculated by looking for border items, or in the case of clicking diagonally from yourself, dense items. + This proc will NOT notice if you are trying to attack a window on the other side of a dense object in its turf. There is a window helper for that. + + Note that in all cases the neighbor is handled simply; this is usually the user's mob, in which case it is up to you + to check that the mob is not inside of something +*/ +/atom/proc/Adjacent(var/atom/neighbor) // basic inheritance, unused + return 0 + +// Not a sane use of the function and (for now) indicative of an error elsewhere +/area/Adjacent(var/atom/neighbor) + CRASH("Call to /area/Adjacent(), unimplemented proc") + + +/* + Adjacency (to turf): + * If you are in the same turf, always true + * If you are vertically/horizontally adjacent, ensure there are no border objects + * If you are diagonally adjacent, ensure you can pass through at least one of the mutually adjacent square. + * Passing through in this case ignores anything with the throwpass flag, such as tables, racks, and morgue trays. +*/ +/turf/Adjacent(var/atom/neighbor, var/atom/target = null) + var/turf/T0 = get_turf(neighbor) + if(T0 == src) + return 1 + if(!T0 || T0.z != z) + return 0 + if(get_dist(src,T0) > 1) + return 0 + + if(T0.x == x || T0.y == y) + // Check for border blockages + return T0.ClickCross(get_dir(T0,src), border_only = 1) && src.ClickCross(get_dir(src,T0), border_only = 1, target_atom = target) + + // Not orthagonal + var/in_dir = get_dir(neighbor,src) // eg. northwest (1+8) + var/d1 = in_dir&(in_dir-1) // eg west (1+8)&(8) = 8 + var/d2 = in_dir - d1 // eg north (1+8) - 8 = 1 + + for(var/d in list(d1,d2)) + if(!T0.ClickCross(d, border_only = 1)) + continue // could not leave T0 in that direction + + var/turf/T1 = get_step(T0,d) + if(!T1 || T1.density || !T1.ClickCross(get_dir(T1,T0) | get_dir(T1,src), border_only = 0)) + continue // couldn't enter or couldn't leave T1 + + if(!src.ClickCross(get_dir(src,T1), border_only = 1, target_atom = target)) + continue // could not enter src + + return 1 // we don't care about our own density + return 0 + +/* +Quick adjacency (to turf): +* If you are in the same turf, always true +* If you are not adjacent, then false +*/ +/turf/proc/AdjacentQuick(var/atom/neighbor, var/atom/target = null) + var/turf/T0 = get_turf(neighbor) + if(T0 == src) + return 1 + + if(get_dist(src,T0) > 1) + return 0 + + return 1 + +/* + Adjacency (to anything else): + * Must be on a turf + * In the case of a multiple-tile object, all valid locations are checked for adjacency. + + Note: Multiple-tile objects are created when the bound_width and bound_height are creater than the tile size. + This is not used in stock /tg/station currently. +*/ +/atom/movable/Adjacent(var/atom/neighbor) + if(neighbor == loc) return 1 + if(!isturf(loc)) return 0 + for(var/turf/T in locs) + if(isnull(T)) continue + if(T.Adjacent(neighbor,src)) return 1 + return 0 + +// This is necessary for storage items not on your person. +/obj/item/Adjacent(var/atom/neighbor, var/recurse = 1) + if(neighbor == loc) return 1 + if(istype(loc,/obj/item)) + if(recurse > 0) + return loc.Adjacent(neighbor,recurse - 1) + return 0 + return ..() +/* + Special case: This allows you to reach a door when it is visally on top of, + but technically behind, a fire door + + You could try to rewrite this to be faster, but I'm not sure anything would be. + This can be safely removed if border firedoors are ever moved to be on top of doors + so they can be interacted with without opening the door. +*/ +/obj/machinery/door/Adjacent(var/atom/neighbor) + var/obj/machinery/door/firedoor/border_only/BOD = locate() in loc + if(BOD) + BOD.throwpass = 1 // allow click to pass + . = ..() + BOD.throwpass = 0 + return . + return ..() + + +/* + This checks if you there is uninterrupted airspace between that turf and this one. + This is defined as any dense ATOM_FLAG_CHECKS_BORDER object, or any dense object without throwpass. + The border_only flag allows you to not objects (for source and destination squares) +*/ +/turf/proc/ClickCross(var/target_dir, var/border_only, var/target_atom = null) + for(var/obj/O in src) + if( !O.density || O == target_atom || O.throwpass) continue // throwpass is used for anything you can click through + + if(O.atom_flags & ATOM_FLAG_CHECKS_BORDER) // windows have throwpass but are on border, check them first + if( O.dir & target_dir || O.dir&(O.dir-1) ) // full tile windows are just diagonals mechanically + var/obj/structure/window/W = target_atom + if(istype(W)) + if(!W.is_fulltile()) //exception for breaking full tile windows on top of single pane windows + return 0 + else + return 0 + + else if( !border_only ) // dense, not on border, cannot pass over + return 0 + return 1 +/* + Aside: throwpass does not do what I thought it did originally, and is only used for checking whether or not + a thrown object should stop after already successfully entering a square. Currently the throw code involved + only seems to affect hitting mobs, because the checks performed against objects are already performed when + entering or leaving the square. Since throwpass isn't used on mobs, but only on objects, it is effectively + useless. Throwpass may later need to be removed and replaced with a passcheck (bitfield on movable atom passflags). + + Since I don't want to complicate the click code rework by messing with unrelated systems it won't be changed here. +*/ \ No newline at end of file diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm new file mode 100644 index 00000000..10d38463 --- /dev/null +++ b/code/_onclick/ai.dm @@ -0,0 +1,199 @@ +/* + AI ClickOn() + + Note currently ai restrained() returns 0 in all cases, + therefore restrained code has been removed + + The AI can double click to move the camera (this was already true but is cleaner), + or double click a mob to track them. + + Note that AI have no need for the adjacency proc, and so this proc is a lot cleaner. +*/ +/mob/living/silicon/ai/DblClickOn(var/atom/A, params) + if(control_disabled || stat) return + + if(ismob(A)) + ai_actual_track(A) + else + A.move_camera_by_click() + +/mob/living/silicon/ai/ClickOn(var/atom/A, params) + if(world.time <= next_click) + return + next_click = world.time + 1 + + if(stat) + return + + var/list/modifiers = params2list(params) + if(modifiers["ctrl"] && modifiers["alt"]) + CtrlAltClickOn(A) + return + if(modifiers["shift"] && modifiers["ctrl"]) + CtrlShiftClickOn(A) + return + if(modifiers["middle"]) + MiddleClickOn(A) + return + if(modifiers["shift"]) + ShiftClickOn(A) + return + if(modifiers["alt"]) // alt and alt-gr (rightalt) + AltClickOn(A) + return + if(modifiers["ctrl"]) + CtrlClickOn(A) + return + + face_atom(A) // change direction to face what you clicked on + + if(control_disabled || !canClick()) + return + + if(multitool_mode && isobj(A)) + var/obj/O = A + var/datum/extension/interactive/multitool/MT = get_extension(O, /datum/extension/interactive/multitool) + if(MT) + MT.interact(aiMulti, src) + return + + if(silicon_camera.in_camera_mode) + silicon_camera.camera_mode_off() + silicon_camera.captureimage(A, usr) + return + + /* + AI restrained() currently does nothing + if(restrained()) + RestrainedClickOn(A) + else + */ + A.add_hiddenprint(src) + A.attack_ai(src) + +/* + AI has no need for the UnarmedAttack() and RangedAttack() procs, + because the AI code is not generic; attack_ai() is used instead. + The below is only really for safety, or you can alter the way + it functions and re-insert it above. +*/ +/mob/living/silicon/ai/UnarmedAttack(atom/A) + A.attack_ai(src) +/mob/living/silicon/ai/RangedAttack(atom/A) + A.attack_ai(src) + +/atom/proc/attack_ai(mob/user as mob) + return + +/* + Since the AI handles shift, ctrl, and alt-click differently + than anything else in the game, atoms have separate procs + for AI shift, ctrl, and alt clicking. +*/ + +/mob/living/silicon/ai/CtrlAltClickOn(var/atom/A) + if(!control_disabled && A.AICtrlAltClick(src)) + return + ..() + +/mob/living/silicon/ai/ShiftClickOn(var/atom/A) + if(!control_disabled && A.AIShiftClick(src)) + return + ..() + +/mob/living/silicon/ai/CtrlClickOn(var/atom/A) + if(!control_disabled && A.AICtrlClick(src)) + return + ..() + +/mob/living/silicon/ai/AltClickOn(var/atom/A) + if(!control_disabled && A.AIAltClick(src)) + return + ..() + +/mob/living/silicon/ai/MiddleClickOn(var/atom/A) + if(!control_disabled && A.AIMiddleClick(src)) + return + ..() + +/* + The following criminally helpful code is just the previous code cleaned up; + I have no idea why it was in atoms.dm instead of respective files. +*/ + +/atom/proc/AICtrlAltClick() + +/obj/machinery/door/airlock/AICtrlAltClick() // Electrifies doors. + if(!electrified_until) + // permanent shock + Topic(src, list("command"="electrify_permanently", "activate" = "1")) + else + // disable/6 is not in Topic; disable/5 disables both temporary and permanent shock + Topic(src, list("command"="electrify_permanently", "activate" = "0")) + return 1 + +/atom/proc/AICtrlShiftClick() + return + +/atom/proc/AIShiftClick() + return + +/obj/machinery/door/airlock/AIShiftClick() // Opens and closes doors! + if(density) + Topic(src, list("command"="open", "activate" = "1")) + else + Topic(src, list("command"="open", "activate" = "0")) + return 1 + +/atom/proc/AICtrlClick() + return + +/obj/machinery/door/airlock/AICtrlClick() // Bolts doors + if(locked) + Topic(src, list("command"="bolts", "activate" = "0")) + else + Topic(src, list("command"="bolts", "activate" = "1")) + return 1 + +/obj/machinery/power/apc/AICtrlClick() // turns off/on APCs. + Topic(src, list("breaker"="1")) + return 1 + +/obj/machinery/turretid/AICtrlClick() //turns off/on Turrets + Topic(src, list("command"="enable", "value"="[!enabled]")) + return 1 + +/atom/proc/AIAltClick(var/atom/A) + return AltClick(A) + +/obj/machinery/turretid/AIAltClick() //toggles lethal on turrets + Topic(src, list("command"="lethal", "value"="[!lethal]")) + return 1 + +/obj/machinery/atmospherics/binary/pump/AIAltClick() + return AltClick() + +/atom/proc/AIMiddleClick(var/mob/living/silicon/user) + return 0 + +/obj/machinery/door/airlock/AIMiddleClick() // Toggles door bolt lights. + + if(..()) + return + + if(!src.lights) + Topic(src, list("command"="lights", "activate" = "1")) + else + Topic(src, list("command"="lights", "activate" = "0")) + return 1 + +// +// Override AdjacentQuick for AltClicking +// + +/mob/living/silicon/ai/TurfAdjacent(var/turf/T) + return (cameranet && cameranet.is_turf_visible(T)) + +/mob/living/silicon/ai/face_atom(var/atom/A) + if(eyeobj) + eyeobj.face_atom(A) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm new file mode 100644 index 00000000..ae3b5c3b --- /dev/null +++ b/code/_onclick/click.dm @@ -0,0 +1,562 @@ +/* + Click code cleanup + ~Sayu +*/ + +// 1 decisecond click delay (above and beyond mob/next_move) +/mob/var/next_click = 0 + +/* + Before anything else, defer these calls to a per-mobtype handler. This allows us to + remove istype() spaghetti code, but requires the addition of other handler procs to simplify it. + + Alternately, you could hardcode every mob's variation in a flat ClickOn() proc; however, + that's a lot of code duplication and is hard to maintain. + + Note that this proc can be overridden, and is in the case of screen objects. +*/ + +/atom/Click(var/location, var/control, var/params) // This is their reaction to being clicked on (standard proc) + var/datum/click_handler/click_handler = usr.GetClickHandler() + click_handler.OnClick(src, params) + +/atom/DblClick(var/location, var/control, var/params) + var/datum/click_handler/click_handler = usr.GetClickHandler() + click_handler.OnDblClick(src, params) + +/* + Standard mob ClickOn() + Handles exceptions: middle click, modified clicks, mech actions + + After that, mostly just check your state, check whether you're holding an item, + check whether you're adjacent to the target, then pass off the click to whoever + is recieving it. + The most common are: + * mob/UnarmedAttack(atom,adjacent) - used here only when adjacent, with no item in hand; in the case of humans, checks gloves + * atom/attackby(item,user) - used only when adjacent + * item/afterattack(atom,user,adjacent,params) - used both ranged and adjacent + * mob/RangedAttack(atom,params) - used only ranged, only used for tk and laser eyes but could be changed +*/ +/mob/proc/ClickOn(var/atom/A, var/params) + + if(world.time <= next_click) // Hard check, before anything else, to avoid crashing + return + + next_click = world.time + 1 + + var/list/L = params2list(params) //convert params into a list + var/dragged = L["drag"] //grab what mouse button they are dragging with, if any. + if(dragged && !L[dragged]) //check to ensure they aren't using drag clicks to aimbot + return //if they are dragging, and they clicked with a different mouse button, reject the click as it will always go the atom they are currently dragging, even if out of view and not under the mouse + + var/list/modifiers = params2list(params) + if(modifiers["shift"] && modifiers["ctrl"]) + CtrlShiftClickOn(A) + return 1 + if(modifiers["ctrl"] && modifiers["alt"]) + CtrlAltClickOn(A) + return 1 + if(modifiers["middle"] && modifiers["shift"]) + ShiftMiddleClickOn(A) + return 1 + if(modifiers["shift"]) + ShiftClickOn(A) + return 0 + if(modifiers["shift"] && modifiers["right"]) + ShiftRightClickOn(A) + return 1 + if(modifiers["alt"] && modifiers["right"]) + AltRightClickOn(A) + return 1 + if(modifiers["alt"]) // alt and alt-gr (rightalt) + AltClickOn(A) + return 1 + if(modifiers["ctrl"]) + CtrlClickOn(A) + return 1 + if(modifiers["right"]) + RightClickOn(A) + return 1 + + if(!canClick()) // in the year 2000... + return + + if(lying && istype(A, /turf/) && !istype(A, /turf/space/)) + if(!get_active_hand())//Should make getting up stairs easier. + scramble(A) + + if(stat || paralysis || stunned) //|| weakened) + return + + face_atom(A) // change direction to face what you clicked on + + if(modifiers["middle"])//This goes below everything else because of how middle click is used. + MiddleClickOn(A) + return + + if(istype(loc, /obj/mecha)) + if(!locate(/turf) in list(A, A.loc)) // Prevents inventory from being drilled + return + var/obj/mecha/M = loc + return M.click_action(A, src) + + if(restrained()) + setClickCooldown(10) + RestrainedClickOn(A) + return 1 + + if(in_throw_mode) + if(isturf(A) || isturf(A.loc)) + throw_item(A) + trigger_aiming(TARGET_CAN_CLICK) + return 1 + throw_mode_off() + + var/obj/item/W = get_active_hand() + + if(W == A) // Handle attack_self + W.attack_self(src) + trigger_aiming(TARGET_CAN_CLICK) + if(hand) + update_inv_l_hand(0) + else + update_inv_r_hand(0) + return 1 + + //Atoms on your person + // A is your location but is not a turf; or is on you (backpack); or is on something on you (box in backpack); sdepth is needed here because contents depth does not equate inventory storage depth. + var/sdepth = A.storage_depth(src) + if((!isturf(A) && A == loc) || (sdepth != -1 && sdepth <= 1)) + if(W) + var/resolved = W.resolve_attackby(A, src, params, FALSE) + if(!resolved && A && W) + W.afterattack(A, src, 1, params) // 1 indicates adjacency + else + if(ismob(A)) // No instant mob attacking + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + UnarmedAttack(A, 1) + + trigger_aiming(TARGET_CAN_CLICK) + return 1 + + if(!isturf(loc)) // This is going to stop you from telekinesing from inside a closet, but I don't shed many tears for that + return + + //Atoms on turfs (not on your person) + // A is a turf or is on a turf, or in something on a turf (pen in a box); but not something in something on a turf (pen in a box in a backpack) + sdepth = A.storage_depth_turf() + if(isturf(A) || isturf(A.loc) || (sdepth != -1 && sdepth <= 1)) + if(A.Adjacent(src)) // see adjacent.dm + if(W) + // Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example) + var/resolved = W.resolve_attackby(A,src, params) + if(!resolved && A && W) + W.afterattack(A, src, 1, params) // 1: clicking something Adjacent + else + if(ismob(A)) // No instant mob attacking + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + UnarmedAttack(A, 1) + + trigger_aiming(TARGET_CAN_CLICK) + return + else // non-adjacent click + if(W) + W.afterattack(A, src, 0, params) // 0: not Adjacent + else + RangedAttack(A, params) + + trigger_aiming(TARGET_CAN_CLICK) + return 1 + +/mob/proc/setClickCooldown(var/timeout) + next_move = max(world.time + timeout, next_move) + +/mob/proc/canClick() + if(config.no_click_cooldown || next_move <= world.time) + return 1 + return 0 + +// Default behavior: ignore double clicks, the second click that makes the doubleclick call already calls for a normal click +/mob/proc/DblClickOn(var/atom/A, var/params) + return + +/* + Translates into attack_hand, etc. + + Note: proximity_flag here is used to distinguish between normal usage (flag=1), + and usage when clicking on things telekinetically (flag=0). This proc will + not be called at ranged except with telekinesis. + + proximity_flag is not currently passed to attack_hand, and is instead used + in human click code to allow glove touches only at melee range. +*/ +/mob/proc/UnarmedAttack(var/atom/A, var/proximity_flag) + return + +/mob/living/UnarmedAttack(var/atom/A, var/proximity_flag) + + if(!ticker) + to_chat(src, "You cannot attack people before the game has started.") + return 0 + + if(stat) + return 0 + + return 1 + +/* + Ranged unarmed attack: + + This currently is just a default for all mobs, involving + laser eyes and telekinesis. You could easily add exceptions + for things like ranged glove touches, spitting alien acid/neurotoxin, + animals lunging, etc. +*/ +/mob/proc/RangedAttack(var/atom/A, var/params) + if(!mutations.len) return + if((LASER in mutations) && a_intent == I_HURT) + LaserEyes(A) // moved into a proc below + else if(TK in mutations) + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + A.attack_tk(src) +/* + Restrained ClickOn + + Used when you are handcuffed and click things. + Not currently used by anything but could easily be. +*/ +/mob/proc/RestrainedClickOn(var/atom/A) + return + +/* + Middle click + Only used for swapping hands +*/ +/mob/proc/MiddleClickOn(var/atom/A) + A.MiddleClick(src) + return + +/mob/proc/RightClickOn(var/atom/A) + A.RightClick(src) + +/mob/proc/ShiftRightClickOn(var/atom/A) + A.ShiftRightClick(src) + +/atom/proc/MiddleClick(var/mob/M) + middle_click_intent_check(M) + return +// In case of use break glass + + +/mob/proc/ShiftMiddleClickOn(var/atom/A) + A.ShiftMiddleClick(src) + return + +/atom/proc/ShiftMiddleClick(var/mob/user) + user.pointed(src) + +/* + Shift click + For most mobs, examine. + This is overridden in ai.dm +*/ +/mob/proc/ShiftClickOn(var/atom/A) + A.ShiftClick(src) + return +/atom/proc/ShiftClick(var/mob/user) + if(user.client && user.client.eye == user) + user.examinate(src) + return + +/atom/proc/ShiftRightClick(var/mob/user) + return //I dont know where we will use it + +/* + Ctrl click + For most objects, pull +*/ +/mob/proc/CtrlClickOn(var/atom/A) + A.CtrlClick(src) + return +/atom/proc/CtrlClick(var/mob/user) + return + +/atom/movable/CtrlClick(var/mob/user) + if(Adjacent(user)) + if (ishuman(user)) + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/temp = H.organs_by_name[BP_R_HAND] + var/hashands = (temp && temp.is_usable()) + if (!hashands) + temp = H.organs_by_name[BP_L_HAND] + hashands = (temp && temp.is_usable()) + if (!hashands) + return + user.start_pulling(src) + +/* + Alt click + Unused except for AI +*/ +/mob/proc/AltClickOn(var/atom/A) + A.AltClick(src) + +/atom/proc/AltClick(var/mob/user) + var/turf/T = get_turf(src) + if(T && (isturf(loc) || isturf(src)) && user.TurfAdjacent(T)) + if(user.listed_turf == T) + user.listed_turf = null + else + user.listed_turf = T + user.client.statpanel = "Turf" + return 1 + +/mob/proc/AltRightClickOn(var/atom/A) + A.AltRightClick(src) + +/atom/proc/AltRightClick(var/mob/user) + return + + +/atom/proc/RightClick(var/mob/user) + return + +/mob/proc/TurfAdjacent(var/turf/T) + return T.AdjacentQuick(src) + +/mob/observer/ghost/TurfAdjacent(var/turf/T) + if(!isturf(loc) || !client) + return FALSE + return z == T.z && (get_dist(loc, T) <= client.view) + +/* + Control+Shift click + Unused except for AI +*/ +/mob/proc/CtrlShiftClickOn(var/atom/A) + A.CtrlShiftClick(src) + return + +/atom/proc/CtrlShiftClick(var/mob/user) + return + +/* + Control+Alt click +*/ +/mob/proc/CtrlAltClickOn(var/atom/A) + A.CtrlAltClick(src) + return + +/atom/proc/CtrlAltClick(var/mob/user) + return + +/* + Misc helpers + + Laser Eyes: as the name implies, handles this since nothing else does currently + face_atom: turns the mob towards what you clicked on +*/ +/mob/proc/LaserEyes(atom/A) + return + +/mob/living/LaserEyes(atom/A) + setClickCooldown(DEFAULT_QUICK_COOLDOWN) + var/turf/T = get_turf(src) + + var/obj/item/projectile/beam/LE = new (T) + LE.icon = 'icons/effects/genetics.dmi' + LE.icon_state = "eyelasers" + playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1) + LE.launch_projectile(A) +/mob/living/carbon/human/LaserEyes() + if(nutrition>0) + ..() + nutrition = max(nutrition - rand(1,5),0) + handle_regular_hud_updates() + else + to_chat(src, "You're out of energy! You need food!") + +// Simple helper to face what you clicked on, in case it should be needed in more than one place +/mob/proc/face_atom(var/atom/A) + if(!A || !x || !y || !A.x || !A.y) return + var/dx = A.x - x + var/dy = A.y - y + if(!dx && !dy) return + + var/direction + if(abs(dx) < abs(dy)) + if(dy > 0) direction = NORTH + else direction = SOUTH + else + if(dx > 0) direction = EAST + else direction = WEST + if(direction != dir) + if(facing_dir) + facing_dir = direction + facedir(direction) + +/obj/screen/click_catcher + icon = 'icons/mob/screen_gen.dmi' + icon_state = "click_catcher" + plane = CLICKCATCHER_PLANE + mouse_opacity = 2 + screen_loc = "CENTER-7,CENTER-7" + +/proc/create_click_catcher() + . = list() + for(var/i = 0, i<15, i++) + for(var/j = 0, j<15, j++) + var/obj/screen/click_catcher/CC = new() + CC.screen_loc = "NORTH-[i],EAST-[j]" + . += CC + +/obj/screen/click_catcher/Click(location, control, params) + var/list/modifiers = params2list(params) + if(modifiers["middle"] && istype(usr, /mob/living/carbon)) + var/mob/living/carbon/C = usr + C.swap_hand() + else + var/turf/T = screen_loc2turf(screen_loc, get_turf(usr)) + if(T) + T.Click(location, control, params) + . = 1 + +/* + Custom click handling +*/ + +/mob + var/datum/stack/click_handlers + +/mob/Destroy() + if(click_handlers) + click_handlers.QdelClear() + QDEL_NULL(click_handlers) + . = ..() + +var/const/CLICK_HANDLER_NONE = 0 +var/const/CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT = 1 +var/const/CLICK_HANDLER_ALL = (~0) + +/datum/click_handler + var/mob/user + var/flags = 0 + +/datum/click_handler/New(var/mob/user) + ..() + src.user = user + if(flags & (CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT)) + GLOB.logged_out_event.register(user, src, /datum/click_handler/proc/OnMobLogout) + +/datum/click_handler/Destroy() + if(flags & (CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT)) + GLOB.logged_out_event.unregister(user, src, /datum/click_handler/proc/OnMobLogout) + user = null + . = ..() + +/datum/click_handler/proc/Enter() + return + +/datum/click_handler/proc/Exit() + return + +/datum/click_handler/proc/OnMobLogout() + user.RemoveClickHandler(src) + +/datum/click_handler/proc/OnClick(var/atom/A, var/params) + return + +/datum/click_handler/proc/OnDblClick(var/atom/A, var/params) + return + +/datum/click_handler/default/OnClick(var/atom/A, var/params) + user.ClickOn(A, params) + +/datum/click_handler/default/OnDblClick(var/atom/A, var/params) + user.DblClickOn(A, params) + +/mob/proc/GetClickHandler(var/datum/click_handler/popped_handler) + if(!click_handlers) + click_handlers = new() + if(click_handlers.is_empty()) + PushClickHandler(/datum/click_handler/default) + return click_handlers.Top() + +/mob/proc/RemoveClickHandler(var/datum/click_handler/click_handler) + if(!click_handlers) + return + + var/was_top = click_handlers.Top() == click_handler + + if(was_top) + click_handler.Exit() + click_handlers.Remove(click_handler) + qdel(click_handler) + + if(!was_top) + return + click_handler = click_handlers.Top() + if(click_handler) + click_handler.Enter() + +/mob/proc/PopClickHandler() + if(!click_handlers) + return + RemoveClickHandler(click_handlers.Top()) + +/mob/proc/PushClickHandler(var/datum/click_handler/new_click_handler_type) + if((initial(new_click_handler_type.flags) & CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT) && !client) + return FALSE + if(!click_handlers) + click_handlers = new() + var/datum/click_handler/click_handler = click_handlers.Top() + if(click_handler) + click_handler.Exit() + + click_handler = new new_click_handler_type(src) + click_handler.Enter() + click_handlers.Push(click_handler) + +/mob/proc/scramble(var/atom/A) + var/direction + if(stat || buckled || paralysis || stunned || sleeping || (status_flags & FAKEDEATH) || restrained() || pulledby) + return + for(var/obj/item/grab/G in grabbed_by) + if(G.stop_move()) + return + if(!istype(src.loc, /turf/)) + return + if(!A || !x || !y || !A.x || !A.y) + return + if(scrambling) + return + if(!has_limbs) + to_chat(src, "You can't even move yourself - you have no limbs!") + var/dx = A.x - x + var/dy = A.y - y + if(!dx && !dy) return + + if(abs(dx) < abs(dy)) + if(dy > 0) direction = NORTH + else direction = SOUTH + else + if(dx > 0) direction = EAST + else direction = WEST + if(direction) + scrambling = 1 + if(do_after(src, 10)) + Move(get_step(src,direction)) + scrambling = 0 + dir = 2 + src.visible_message("[src.name] crawls!") + playsound(src, 'sound/effects/crawl1.ogg', 50, 1, -(world.view - 2)) + else + scrambling = 0 + +/atom/proc/middle_click_intent_check(var/mob/M) + if(M.middle_click_intent == "kick") + return kick_act(M) + else if(M.middle_click_intent == "jump") + jump_act(src, M) + else + M.swap_hand() \ No newline at end of file diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm new file mode 100644 index 00000000..f524d831 --- /dev/null +++ b/code/_onclick/cyborg.dm @@ -0,0 +1,168 @@ +/* + Cyborg ClickOn() + + Cyborgs have no range restriction on attack_robot(), because it is basically an AI click. + However, they do have a range restriction on item use, so they cannot do without the + adjacency code. +*/ + +/mob/living/silicon/robot/ClickOn(var/atom/A, var/params) + if(world.time <= next_click) + return + next_click = world.time + 1 + + var/list/modifiers = params2list(params) + if(modifiers["shift"] && modifiers["ctrl"]) + CtrlShiftClickOn(A) + return + if(modifiers["middle"]) + MiddleClickOn(A) + return + if(modifiers["shift"]) + ShiftClickOn(A) + return + if(modifiers["alt"]) // alt and alt-gr (rightalt) + AltClickOn(A) + return + if(modifiers["ctrl"]) + CtrlClickOn(A) + return + + if(stat || lockcharge || weakened || stunned || paralysis) + return + + if(!canClick()) + return + + face_atom(A) // change direction to face what you clicked on + + if(silicon_camera.in_camera_mode) + silicon_camera.camera_mode_off() + if(is_component_functioning("camera")) + silicon_camera.captureimage(A, usr) + else + to_chat(src, "Your camera isn't functional.") + return + + /* + cyborg restrained() currently does nothing + if(restrained()) + RestrainedClickOn(A) + return + */ + + var/obj/item/W = get_active_hand() + + // Cyborgs have no range-checking unless there is item use + if(!W) + A.add_hiddenprint(src) + A.attack_robot(src) + return + + // buckled cannot prevent machine interlinking but stops arm movement + if( buckled ) + return + + if(W == A) + + W.attack_self(src) + return + + // cyborgs are prohibited from using storage items so we can I think safely remove (A.loc in contents) + if(A == loc || (A in loc) || (A in contents)) + // No adjacency checks + + var/resolved = W.resolve_attackby(A, src, params) + if(!resolved && A && W) + W.afterattack(A, src, 1, params) // 1 indicates adjacency + return + + if(!isturf(loc)) + return + + // cyborgs are prohibited from using storage items so we can I think safely remove (A.loc && isturf(A.loc.loc)) + if(isturf(A) || isturf(A.loc)) + if(A.Adjacent(src)) // see adjacent.dm + + var/resolved = W.resolve_attackby(A, src, params) + if(!resolved && A && W) + W.afterattack(A, src, 1, params) // 1 indicates adjacency + return + else + W.afterattack(A, src, 0, params) + return + return + +//Middle click cycles through selected modules. +/mob/living/silicon/robot/MiddleClickOn(var/atom/A) + cycle_modules() + return + +//Give cyborgs hotkey clicks without breaking existing uses of hotkey clicks +// for non-doors/apcs +/mob/living/silicon/robot/CtrlShiftClickOn(var/atom/A) + A.BorgCtrlShiftClick(src) + +/mob/living/silicon/robot/ShiftClickOn(var/atom/A) + A.BorgShiftClick(src) + +/mob/living/silicon/robot/CtrlClickOn(var/atom/A) + A.BorgCtrlClick(src) + +/mob/living/silicon/robot/AltClickOn(var/atom/A) + A.BorgAltClick(src) + +/atom/proc/BorgCtrlShiftClick(var/mob/living/silicon/robot/user) //forward to human click if not overriden + CtrlShiftClick(user) + +/obj/machinery/door/airlock/BorgCtrlShiftClick() + AICtrlShiftClick() + +/atom/proc/BorgShiftClick(var/mob/living/silicon/robot/user) //forward to human click if not overriden + ShiftClick(user) + +/obj/machinery/door/airlock/BorgShiftClick() // Opens and closes doors! Forwards to AI code. + AIShiftClick() + + +/atom/proc/BorgCtrlClick(var/mob/living/silicon/robot/user) //forward to human click if not overriden + CtrlClick(user) + +/obj/machinery/door/airlock/BorgCtrlClick() // Bolts doors. Forwards to AI code. + AICtrlClick() + +/obj/machinery/power/apc/BorgCtrlClick() // turns off/on APCs. Forwards to AI code. + AICtrlClick() + +/obj/machinery/turretid/BorgCtrlClick() //turret control on/off. Forwards to AI code. + AICtrlClick() + +/atom/proc/BorgAltClick(var/mob/living/silicon/robot/user) + AltClick(user) + return + +/obj/machinery/door/airlock/BorgAltClick() // Eletrifies doors. Forwards to AI code. + AICtrlAltClick() + +/obj/machinery/turretid/BorgAltClick() //turret lethal on/off. Forwards to AI code. + AIAltClick() + +/obj/machinery/atmospherics/binary/pump/BorgAltClick() + return AltClick() + +/* + As with AI, these are not used in click code, + because the code for robots is specific, not generic. + + If you would like to add advanced features to robot + clicks, you can do so here, but you will have to + change attack_robot() above to the proper function +*/ +/mob/living/silicon/robot/UnarmedAttack(atom/A) + A.attack_robot(src) +/mob/living/silicon/robot/RangedAttack(atom/A) + A.attack_robot(src) + +/atom/proc/attack_robot(mob/user as mob) + attack_ai(user) + return diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm new file mode 100644 index 00000000..cfbc6931 --- /dev/null +++ b/code/_onclick/drag_drop.dm @@ -0,0 +1,28 @@ +/* + MouseDrop: + + Called on the atom you're dragging. In a lot of circumstances we want to use the + recieving object instead, so that's the default action. This allows you to drag + almost anything into a trash can. +*/ + +/atom/proc/CanMouseDrop(atom/over, var/mob/user = usr, var/incapacitation_flags) + if(!user || !over) + return FALSE + if(user.incapacitated(incapacitation_flags)) + return FALSE + if(!src.Adjacent(user) || !over.Adjacent(user)) + return FALSE // should stop you from dragging through windows + return TRUE + +/atom/MouseDrop(atom/over) + if(!usr || !over) return + if(!Adjacent(usr) || !over.Adjacent(usr)) return // should stop you from dragging through windows + + spawn(0) + over.MouseDrop_T(src,usr) + return + +// Receive a mouse drop +/atom/proc/MouseDrop_T(atom/dropping, mob/user) + return diff --git a/code/_onclick/ghost.dm b/code/_onclick/ghost.dm new file mode 100644 index 00000000..221b1f3a --- /dev/null +++ b/code/_onclick/ghost.dm @@ -0,0 +1,86 @@ +/client/var/inquisitive_ghost = 1 +/mob/observer/ghost/verb/toggle_inquisition() // warning: unexpected inquisition + set name = "Toggle Inquisitiveness" + set desc = "Sets whether your ghost examines everything on click by default" + set category = "Ghost" + if(!client) return + client.inquisitive_ghost = !client.inquisitive_ghost + if(client.inquisitive_ghost) + to_chat(src, "You will now examine everything you click on.") + else + to_chat(src, "You will no longer examine things you click on.") + +/mob/observer/ghost/DblClickOn(var/atom/A, var/params) + if(can_reenter_corpse && mind && mind.current) + if(A == mind.current || (mind.current in A)) // double click your corpse or whatever holds it + reenter_corpse() // (cloning scanner, body bag, closet, mech, etc) + return + + // Things you might plausibly want to follow + if(istype(A,/atom/movable)) + ManualFollow(A) + // Otherwise jump + else + stop_following() + forceMove(get_turf(A)) + +/mob/observer/ghost/ClickOn(var/atom/A, var/params) + if(!canClick()) return + setClickCooldown(DEFAULT_QUICK_COOLDOWN) + + // You are responsible for checking config.ghost_interaction when you override this function + // Not all of them require checking, see below + var/list/modifiers = params2list(params) + if(modifiers["alt"]) + var/target_turf = get_turf(A) + if(target_turf) + AltClickOn(target_turf) + else + A.attack_ghost(src) + +// Oh by the way this didn't work with old click code which is why clicking shit didn't spam you +/atom/proc/attack_ghost(mob/observer/ghost/user as mob) + if(!istype(user)) + return + if(user.client && user.client.inquisitive_ghost) + user.examinate(src) + return + +// --------------------------------------- +// And here are some good things for free: +// Now you can click through portals, wormholes, gateways, and teleporters while observing. -Sayu + +/obj/machinery/teleport/hub/attack_ghost(mob/user as mob) + var/atom/l = loc + var/obj/machinery/computer/teleporter/com = locate(/obj/machinery/computer/teleporter, locate(l.x - 2, l.y, l.z)) + if(com.locked) + user.forceMove(get_turf(com.locked)) + +/obj/effect/portal/attack_ghost(mob/user as mob) + if(target) + user.forceMove(get_turf(target)) + +/obj/machinery/gateway/centerstation/attack_ghost(mob/user as mob) + if(awaygate) + user.forceMove(awaygate.loc) + else + to_chat(user, "[src] has no destination.") + +/obj/machinery/gateway/centeraway/attack_ghost(mob/user as mob) + if(stationgate) + user.forceMove(stationgate.loc) + else + to_chat(user, "[src] has no destination.") + +// ------------------------------------------- +// This was supposed to be used by adminghosts +// I think it is a *terrible* idea +// but I'm leaving it here anyway +// commented out, of course. +/* +/atom/proc/attack_admin(mob/user as mob) + if(!user || !user.client || !user.client.holder) + return + attack_hand(user) + +*/ diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm new file mode 100644 index 00000000..0a7ba8b1 --- /dev/null +++ b/code/_onclick/hud/_defines.dm @@ -0,0 +1,263 @@ +/* + These defines specificy screen locations. For more information, see the byond documentation on the screen_loc var. + + The short version: + + Everything is encoded as strings because apparently that's how Byond rolls. + + "1,1" is the bottom left square of the user's screen. This aligns perfectly with the turf grid. + "1:2,3:4" is the square (1,3) with pixel offsets (+2, +4); slightly right and slightly above the turf grid. + Pixel offsets are used so you don't perfectly hide the turf under them, that would be crappy. + + The size of the user's screen is defined by client.view (indirectly by world.view), in our case "15x15". + Therefore, the top right corner (except during admin shenanigans) is at "15,15" +*/ + +#define ui_entire_screen "WEST,SOUTH to EAST,NORTH" + +//Upper left action buttons, displayed when you pick up an item that has this enabled. +#define ui_action_slot1 "1:6,14:26" +#define ui_action_slot2 "2:8,14:26" +#define ui_action_slot3 "3:10,14:26" +#define ui_action_slot4 "4:12,14:26" +#define ui_action_slot5 "5:14,14:26" + +//Lower left, persistant menu +#define ui_inventory "SOUTH-1,4" + +//Lower center, persistant menu +#define ui_sstore1 "SOUTH-1,13" +#define ui_id "SOUTH-2,1" +#define ui_belt "SOUTH-2,3" +#define ui_back "SOUTH-1,6" +#define ui_rhand "SOUTH-1,1" +#define ui_lhand "SOUTH-1,3" +#define ui_swaphand2 "8:16,2:5" +#define ui_storage1 "SOUTH-2,4" +#define ui_storage2 "SOUTH-2,5" + +#define ui_alien_head "CENTER-3:12,SOUTH:5" //aliens +#define ui_alien_oclothing "CENTER-2:14,SOUTH:5"//aliens +/* +#define ui_inv1 "6:16,1:5" //borgs +#define ui_inv2 "7:16,1:5" //borgs +#define ui_inv3 "8:16,1:5" //borgs +#define ui_borg_store "9:16,1:5" //borgs +*/ + +//Lower right, persistant menu +#define ui_swaphand1 "SOUTH-2,6" +#define ui_dropbutton "SOUTH-2,7" +#define ui_drop_throw "SOUTH-2,13" +#define ui_pull "SOUTH-2,10" +#define ui_jmp_kck "SOUTH-2, 9" +#define ui_atk "SOUTH-2, 14"//atk_intents +#define ui_resist "EAST+1,SOUTH-2" +#define ui_acti "SOUTH-2,9" +#define ui_combat "SOUTH-2,12"//COMBAT MODE! +#define ui_combat_intent "SOUTH-2, 8" +#define ui_movi "EAST,SOUTH-2" +#define ui_zonesel "EAST+1, NORTH-2" +#define ui_acti_alt "SOUTH-2,9" //alternative intent switcher for when the interface is hidden (F12) + + + +//Gun buttons +#define ui_gun4 "EAST-3:24,SOUTH+2:7" + +#define ui_inv1 "CENTER-1,SOUTH:5" //borgs +#define ui_inv2 "CENTER,SOUTH:5" //borgs +#define ui_inv3 "CENTER+1,SOUTH:5" //borgs +#define ui_borg_store "CENTER+2,SOUTH:5" //borgs +#define ui_borg_inventory "CENTER-2,SOUTH:5"//borgs + +#define ui_monkey_mask "WEST+4:14,SOUTH:5" //monkey +#define ui_monkey_back "WEST+5:14,SOUTH:5" //monkey + +#define ui_construct_health "EAST:00,CENTER:15" //same height as humans, hugging the right border +#define ui_construct_purge "EAST:00,CENTER-1:15" +#define ui_construct_fire "EAST-1:16,CENTER+1:13" //above health, slightly to the left +#define ui_construct_pull "EAST-1:28,SOUTH+1:10" //above the zone_sel icon + +#define ui_borg_pull "EAST-3:24,SOUTH+1:7" +#define ui_borg_module "EAST-2:26,SOUTH+1:7" +#define ui_borg_panel "EAST-1:28,SOUTH+1:7" + +#define ui_kick_jump "CENTER+3:16,SOUTH:5" + +//Gun buttons +#define ui_gun1 "9, SOUTH" +#define ui_gun2 "10, SOUTH" +#define ui_gun3 "11, SOUTH" +#define ui_gun_select "10, SOUTH-1" + +//Upper-middle right (damage indicators) +#define ui_toxin "EAST+1, NORTH-8"//6 +#define ui_fire "EAST+1, NORTH-9"//8 +#define ui_oxygen "EAST+1, NORTH-7"//NORTH-3" +#define ui_pressure "EAST+1, NORTH-11"//7 +#define ui_surrender "EAST+1, NORTH-5" +#define ui_fixeye "EAST+1, NORTH-6" + +#define ui_alien_toxin "14:28,13:25" +#define ui_alien_fire "14:28,12:25" +#define ui_alien_oxygen "14:28,11:25" + +//Middle right (status indicators) +#define ui_stamina "EAST+1, NORTH-14" +#define ui_temp "EAST+1, NORTH-12" +#define ui_health "EAST+1, NORTH-13" +#define ui_happiness "EAST+1, NORTH-4" +#define ui_nutrition "EAST+1, NORTH-10" +#define ui_internal "EAST+1, NORTH-3" + //borgs +#define ui_borg_health "EAST-1:28,CENTER-1:13" //borgs have the health display where humans have the pressure damage indicator. +#define ui_alien_health "EAST-1:28,CENTER-1:13" //aliens have the health display where humans have the pressure damage indicator. + +//Pop-up inventory +#define ui_shoes "SOUTH-1,7" + +#define ui_iclothing "SOUTH-2,2" +#define ui_oclothing "SOUTH-1,2" +#define ui_gloves "SOUTH-1,8" + +#define ui_glasses "SOUTH-1,12" +#define ui_mask "SOUTH-1,4" +#define ui_l_ear "SOUTH-1,10" +#define ui_r_ear "SOUTH-1,11" +#define ui_neck "SOUTH-1,9" + +#define ui_head "SOUTH-1,5" + +//Attack intent +#define ui_att_int "SOUTH-2,9" + +//#define ui_swapbutton "6:-16,1:5" //Unused + +//#define ui_headset "SOUTH-1,8" +#define ui_hstore1 "5,5" +#define ui_sleep "EAST+1, NORTH-14" +#define ui_rest "EAST+1, NORTH-15" + + +#define ui_iarrowleft "SOUTH-2,11" +#define ui_iarrowright "SOUTH-2,13" + +#define ui_spell_master "EAST-1:16,NORTH-1:16" +#define ui_genetic_master "EAST-1:16,NORTH-3:16" + + + +/*********************************************************************************** +************************************************************************************ +************************************************************************************ +********************** TG'S HUD DEFINES ********************** +************************************************************************************ +************************************************************************************ +************************************************************************************/ + + +//Upper left action buttons, displayed when you pick up an item that has this enabled. +#define ui_tg_action_slot1 "1:6,14:26" +#define ui_tg_action_slot2 "2:8,14:26" +#define ui_tg_action_slot3 "3:10,14:26" +#define ui_tg_action_slot4 "4:12,14:26" +#define ui_tg_action_slot5 "5:14,14:26" + +//Lower left, persistant menu +#define ui_tg_inventory "1:6,1:5" + +//Lower center, persistant menu +#define ui_tg_sstore1 "3:10,1:5" +#define ui_tg_id "4:12,1:5" +#define ui_tg_belt "5:14,1:5" +#define ui_tg_back "6:14,1:5" +#define ui_tg_rhand "7:16,1:5" +#define ui_tg_lhand "8:16,1:5" +#define ui_tg_equip "7:16,2:5" +#define ui_tg_swaphand1 "7:16,2:5" +#define ui_tg_swaphand2 "8:16,2:5" +#define ui_tg_storage1 "9:18,1:5" +#define ui_tg_storage2 "10:20,1:5" + +#define ui_tg_alien_head "4:12,1:5" //aliens +#define ui_tg_alien_oclothing "5:14,1:5" //aliens + +#define ui_tg_inv1 "6:16,1:5" //borgs +#define ui_tg_inv2 "7:16,1:5" //borgs +#define ui_tg_inv3 "8:16,1:5" //borgs +#define ui_tg_borg_store "9:16,1:5" //borgs + +#define ui_tg_monkey_mask "5:14,1:5" //monkey +#define ui_tg_monkey_back "6:14,1:5" //monkey + +//Lower right, persistant menu +#define ui_tg_dropbutton "11:22,1:5" +#define ui_tg_drop_throw "14:28,2:7" +#define ui_tg_pull_resist "13:26,2:7" +#define ui_tg_acti "13:26,1:5" +#define ui_tg_movi "12:24,1:5" +#define ui_tg_zonesel "14:28,1:5" +#define ui_tg_acti_alt "14:28,1:5" //alternative intent switcher for when the interface is hidden (F12) + +#define ui_tg_borg_pull "12:24,2:7" +#define ui_tg_borg_module "13:26,2:7" +#define ui_tg_borg_panel "14:28,2:7" + +//Gun buttons +#define ui_tg_gun1 "13:26,3:7" +#define ui_tg_gun2 "14:28, 4:7" +#define ui_tg_gun3 "13:26,4:7" +#define ui_tg_gun_select "14:28,3:7" + +//Upper-middle right (damage indicators) +#define ui_tg_toxin "14:28,13:27" +#define ui_tg_fire "14:28,12:25" +#define ui_tg_oxygen "14:28,11:23" +#define ui_tg_pressure "14:28,10:21" + +#define ui_tg_alien_toxin "14:28,13:25" +#define ui_tg_alien_fire "14:28,12:25" +#define ui_tg_alien_oxygen "14:28,11:25" + +//Middle right (status indicators) +#define ui_tg_nutrition "14:28,5:11" +#define ui_tg_temp "14:28,6:13" +#define ui_tg_health "14:28,7:15" +#define ui_tg_internal "14:28,8:17" + //borgs +#define ui_tg_borg_health "14:28,6:13" //borgs have the health display where humans have the pressure damage indicator. +#define ui_tg_alien_health "14:28,6:13" //aliens have the health display where humans have the pressure damage indicator. + +//Pop-up inventory +#define ui_tg_shoes "2:8,1:5" + +#define ui_tg_iclothing "1:6,2:7" +#define ui_tg_oclothing "2:8,2:7" +#define ui_tg_gloves "3:10,2:7" + +#define ui_tg_glasses "1:6,3:9" +#define ui_tg_mask "2:8,3:9" +#define ui_tg_l_ear "3:10,3:9" +#define ui_tg_r_ear "3:10,4:11" + +#define ui_tg_head "2:8,4:11" + +//Intent small buttons +#define ui_tg_help_small "12:8,1:1" +#define ui_tg_disarm_small "12:15,1:18" +#define ui_tg_grab_small "12:32,1:18" +#define ui_tg_harm_small "12:39,1:1" + +//#define ui_swapbutton "6:-16,1:5" //Unused + +//#define ui_headset "SOUTH-1,8" +#define ui_tg_hand "6:14,1:5" +#define ui_tg_hstore1 "5,5" +//#define ui_resist "EAST+1,SOUTH-1" +#define ui_tg_sleep "EAST+1, NORTH-13" +#define ui_tg_rest "EAST+1, NORTH-14" + + +#define ui_tg_iarrowleft "SOUTH-2,11" +#define ui_tg_iarrowright "SOUTH-2,13" diff --git a/code/_onclick/hud/ability_screen_objects.dm b/code/_onclick/hud/ability_screen_objects.dm new file mode 100644 index 00000000..4354ddba --- /dev/null +++ b/code/_onclick/hud/ability_screen_objects.dm @@ -0,0 +1,412 @@ +/obj/screen/movable/ability_master + name = "Abilities" + icon = 'icons/mob/screen_spells.dmi' + icon_state = "grey_spell_ready" + var/list/obj/screen/ability/ability_objects = list() + var/list/obj/screen/ability/spell_objects = list() + var/showing = 0 // If we're 'open' or not. + + var/open_state = "master_open" // What the button looks like when it's 'open', showing the other buttons. + var/closed_state = "master_closed" // Button when it's 'closed', hiding everything else. + + screen_loc = ui_spell_master // TODO: Rename + + var/mob/my_mob = null // The mob that possesses this hud object. + +/obj/screen/movable/ability_master/New(newloc,owner) + if(owner) + my_mob = owner + update_abilities(0, owner) + else + message_admins("ERROR: ability_master's New() was not given an owner argument. This is a bug.") + ..() + +/obj/screen/movable/ability_master/Destroy() + . = ..() + //Get rid of the ability objects. + remove_all_abilities() + ability_objects.Cut() + + // After that, remove ourselves from the mob seeing us, so we can qdel cleanly. + if(my_mob) + my_mob.ability_master = null + if(my_mob.client && my_mob.client.screen) + my_mob.client.screen -= src + my_mob = null +/obj/screen/movable/ability_master/MouseDrop() + if(showing) + return + + return ..() + +/obj/screen/movable/ability_master/Click() + if(!ability_objects.len) // If we're empty for some reason. + return + + toggle_open() + +/obj/screen/movable/ability_master/proc/toggle_open(var/forced_state = 0) + if(showing && (forced_state != 2)) // We are closing the ability master, hide the abilities. + for(var/obj/screen/ability/O in ability_objects) + if(my_mob && my_mob.client) + my_mob.client.screen -= O +// O.handle_icon_updates = 0 + showing = 0 + overlays.len = 0 + overlays.Add(closed_state) + else if(forced_state != 1) // We're opening it, show the icons. + open_ability_master() + update_abilities(1) + showing = 1 + overlays.len = 0 + overlays.Add(open_state) + update_icon() + +/obj/screen/movable/ability_master/proc/open_ability_master() + var/list/screen_loc_xy = splittext(screen_loc,",") + + //Create list of X offsets + var/list/screen_loc_X = splittext(screen_loc_xy[1],":") + var/x_position = decode_screen_X(screen_loc_X[1]) + var/x_pix = screen_loc_X[2] + + //Create list of Y offsets + var/list/screen_loc_Y = splittext(screen_loc_xy[2],":") + var/y_position = decode_screen_Y(screen_loc_Y[1]) + var/y_pix = screen_loc_Y[2] + + for(var/i = 1; i <= ability_objects.len; i++) + var/obj/screen/ability/A = ability_objects[i] + var/xpos = x_position + (x_position < 8 ? 1 : -1)*(i%7) + var/ypos = y_position + (y_position < 8 ? round(i/7) : -round(i/7)) + A.screen_loc = "[encode_screen_X(xpos)]:[x_pix],[encode_screen_Y(ypos)]:[y_pix]" + if(my_mob && my_mob.client) + my_mob.client.screen += A +// A.handle_icon_updates = 1 + +/obj/screen/movable/ability_master/proc/update_abilities(forced = 0, mob/user) + update_icon() + if(user && user.client) + if(!(src in user.client.screen)) + user.client.screen += src + var/i = 1 + for(var/obj/screen/ability/ability in ability_objects) + ability.update_icon(forced) + ability.maptext = "[i]" // Slot number + i++ + +/obj/screen/movable/ability_master/update_icon() + if(ability_objects.len) + set_invisibility(0) + else + set_invisibility(101) + +/obj/screen/movable/ability_master/proc/add_ability(var/name_given) + if(!name) return + var/obj/screen/ability/new_button = new /obj/screen/ability + new_button.ability_master = src + new_button.SetName(name_given) + new_button.ability_icon_state = name_given + new_button.update_icon(1) + ability_objects.Add(new_button) + if(my_mob.client) + toggle_open(2) //forces the icons to refresh on screen + +/obj/screen/movable/ability_master/proc/remove_ability(var/obj/screen/ability/ability) + if(!ability) + return + ability_objects.Remove(ability) + if(istype(ability,/obj/screen/ability/spell)) + spell_objects.Remove(ability) + qdel(ability) + + + if(ability_objects.len) + toggle_open(showing + 1) + update_icon() +// else +// qdel(src) + +/obj/screen/movable/ability_master/proc/remove_all_abilities() + for(var/obj/screen/ability/A in ability_objects) + remove_ability(A) + +/obj/screen/movable/ability_master/proc/get_ability_by_name(name_to_search) + for(var/obj/screen/ability/A in ability_objects) + if(A.name == name_to_search) + return A + return null + +/obj/screen/movable/ability_master/proc/get_ability_by_proc_ref(proc_ref) + for(var/obj/screen/ability/verb_based/V in ability_objects) + if(V.verb_to_call == proc_ref) + return V + return null + +/obj/screen/movable/ability_master/proc/get_ability_by_instance(var/obj/instance/) + for(var/obj/screen/ability/obj_based/O in ability_objects) + if(O.object == instance) + return O + return null + +/obj/screen/movable/ability_master/proc/get_ability_by_spell(var/spell/s) + for(var/screen in spell_objects) + var/obj/screen/ability/spell/S = screen + if(S.spell == s) + return S + return null + +/mob/Login() + ..() + if(ability_master) + ability_master.update_abilities(1, src) + ability_master.toggle_open(1) + +/mob/Initialize() + . = ..() + ability_master = new /obj/screen/movable/ability_master(null,src) + +///////////ACTUAL ABILITIES//////////// +//This is what you click to do things// +/////////////////////////////////////// +/obj/screen/ability + icon = 'icons/mob/screen_spells.dmi' + icon_state = "grey_spell_base" + maptext_x = 3 + var/background_base_state = "grey" + var/ability_icon_state = null + var/obj/screen/movable/ability_master/ability_master + +/obj/screen/ability/Destroy() + if(ability_master) + ability_master.ability_objects -= src + if(ability_master.my_mob && ability_master.my_mob.client) + ability_master.my_mob.client.screen -= src + if(ability_master && !ability_master.ability_objects.len) + ability_master.update_icon() +// qdel(ability_master) + ability_master = null + return ..() + +/obj/screen/ability/update_icon() + overlays.Cut() + icon_state = "[background_base_state]_spell_base" + + overlays += ability_icon_state + +/obj/screen/ability/Click() + if(!usr) + return + + activate() + +// Makes the ability be triggered. The subclasses of this are responsible for carrying it out in whatever way it needs to. +/obj/screen/ability/proc/activate() + to_world("[src] had activate() called.") + return + +// This checks if the ability can be used. +/obj/screen/ability/proc/can_activate() + return 1 + +/client/verb/activate_ability(var/slot as num) + set name = ".activate_ability" +// set hidden = 1 + if(!mob) + return // Paranoid. + if(isnull(slot) || !isnum(slot)) + to_chat(src,".activate_ability requires a number as input, corrisponding to the slot you wish to use.") + return // Bad input. + if(!mob.ability_master) + return // No abilities. + if(slot > mob.ability_master.ability_objects.len || slot <= 0) + return // Out of bounds. + var/obj/screen/ability/A = mob.ability_master.ability_objects[slot] + A.activate() + +//////////Verb Abilities////////// +//Buttons to trigger verbs/procs// +////////////////////////////////// + +/obj/screen/ability/verb_based + var/verb_to_call = null + var/object_used = null + var/arguments_to_use = list() + +/obj/screen/ability/verb_based/activate() + if(object_used && verb_to_call) + call(object_used,verb_to_call)(arguments_to_use) + +/obj/screen/movable/ability_master/proc/add_verb_ability(var/object_given, var/verb_given, var/name_given, var/ability_icon_given, var/arguments) + if(!object_given) + message_admins("ERROR: add_verb_ability() was not given an object in its arguments.") + if(!verb_given) + message_admins("ERROR: add_verb_ability() was not given a verb/proc in its arguments.") + if(get_ability_by_proc_ref(verb_given)) + return // Duplicate + var/obj/screen/ability/verb_based/A = new /obj/screen/ability/verb_based() + A.ability_master = src + A.object_used = object_given + A.verb_to_call = verb_given + A.ability_icon_state = ability_icon_given + A.SetName(name_given) + if(arguments) + A.arguments_to_use = arguments + ability_objects.Add(A) + if(my_mob.client) + toggle_open(2) //forces the icons to refresh on screen + +//Changeling Abilities +/obj/screen/ability/verb_based/changeling + icon_state = "ling_spell_base" + background_base_state = "ling" + +/obj/screen/movable/ability_master/proc/add_ling_ability(var/object_given, var/verb_given, var/name_given, var/ability_icon_given, var/arguments) + if(!object_given) + message_admins("ERROR: add_ling_ability() was not given an object in its arguments.") + if(!verb_given) + message_admins("ERROR: add_ling_ability() was not given a verb/proc in its arguments.") + if(get_ability_by_proc_ref(verb_given)) + return // Duplicate + var/obj/screen/ability/verb_based/changeling/A = new /obj/screen/ability/verb_based/changeling() + A.ability_master = src + A.object_used = object_given + A.verb_to_call = verb_given + A.ability_icon_state = ability_icon_given + A.SetName(name_given) + if(arguments) + A.arguments_to_use = arguments + ability_objects.Add(A) + if(my_mob.client) + toggle_open(2) //forces the icons to refresh on screen + + +/////////Obj Abilities//////// +//Buttons to trigger objects// +////////////////////////////// + +/obj/screen/ability/obj_based + var/obj/object = null + +/obj/screen/ability/obj_based/activate() + if(object) + object.Click() + +// Technomancer +/obj/screen/ability/obj_based/technomancer + icon_state = "wiz_spell_base" + background_base_state = "wiz" + +/obj/screen/movable/ability_master/proc/add_technomancer_ability(var/obj/object_given, var/ability_icon_given) + if(!object_given) + message_admins("ERROR: add_technomancer_ability() was not given an object in its arguments.") + if(get_ability_by_instance(object_given)) + return // Duplicate + var/obj/screen/ability/obj_based/technomancer/A = new /obj/screen/ability/obj_based/technomancer() + A.ability_master = src + A.object = object_given + A.ability_icon_state = ability_icon_given + A.SetName(object_given.name) + ability_objects.Add(A) + if(my_mob.client) + toggle_open(2) //forces the icons to refresh on screen + +// Wizard +/obj/screen/ability/spell + var/spell/spell + var/spell_base + var/last_charge = 0 + var/icon/last_charged_icon + +/obj/screen/ability/spell/Destroy() + if(spell) + spell.connected_button = null + spell = null + return ..() + +/obj/screen/movable/ability_master/proc/add_spell(var/spell/spell) + if(!spell) return + + if(spell.spell_flags & NO_BUTTON) //no button to add if we don't get one + return + + if(get_ability_by_spell(spell)) + return + + var/obj/screen/ability/spell/A = new() + A.ability_master = src + A.spell = spell + A.SetName(spell.name) + + if(!spell.override_base) //if it's not set, we do basic checks + if(spell.spell_flags & CONSTRUCT_CHECK) + A.spell_base = "const" //construct spells + else + A.spell_base = "wiz" //wizard spells + else + A.spell_base = spell.override_base + A.update_charge(1) + spell_objects.Add(A) + ability_objects.Add(A) + if(my_mob.client) + toggle_open(2) //forces the icons to refresh on screen + +/mob/Life() + ..() + if(ability_master) + ability_master.update_spells(0) + +/obj/screen/movable/ability_master/proc/update_spells(var/forced = 0) + for(var/obj/screen/ability/spell/spell in spell_objects) + spell.update_charge(forced) + +/obj/screen/ability/spell/proc/update_charge(var/forced_update = 0) + if(!spell) + qdel(src) + return + + if(last_charge == spell.charge_counter && !forced_update) + return //nothing to see here + + overlays -= spell.hud_state + + if(spell.charge_type == Sp_RECHARGE || spell.charge_type == Sp_CHARGES) + if(spell.charge_counter < spell.charge_max) + icon_state = "[spell_base]_spell_base" + if(spell.charge_counter > 0) + var/icon/partial_charge = icon(src.icon, "[spell_base]_spell_ready") + partial_charge.Crop(1, 1, partial_charge.Width(), round(partial_charge.Height() * spell.charge_counter / spell.charge_max)) + overlays += partial_charge + if(last_charged_icon) + overlays -= last_charged_icon + last_charged_icon = partial_charge + else if(last_charged_icon) + overlays -= last_charged_icon + last_charged_icon = null + else + icon_state = "[spell_base]_spell_ready" + if(last_charged_icon) + overlays -= last_charged_icon + else + icon_state = "[spell_base]_spell_ready" + + overlays += spell.hud_state + + last_charge = spell.charge_counter + + overlays -= "silence" + if(spell.silenced) + overlays += "silence" + +/obj/screen/ability/spell/update_icon(var/forced = 0) + update_charge(forced) + return + +/obj/screen/ability/spell/activate() + spell.perform(usr) + +/obj/screen/movable/ability_master/proc/silence_spells(var/amount) + for(var/obj/screen/ability/spell/spell in spell_objects) + spell.spell.silenced = amount + spell.spell.process() + spell.update_charge(1) \ No newline at end of file diff --git a/code/_onclick/hud/action.dm b/code/_onclick/hud/action.dm new file mode 100644 index 00000000..1a9f6697 --- /dev/null +++ b/code/_onclick/hud/action.dm @@ -0,0 +1,223 @@ +#define AB_ITEM 1 +#define AB_SPELL 2 +#define AB_INNATE 3 +#define AB_GENERIC 4 + +#define AB_CHECK_RESTRAINED 1 +#define AB_CHECK_STUNNED 2 +#define AB_CHECK_LYING 4 +#define AB_CHECK_ALIVE 8 +#define AB_CHECK_INSIDE 16 + + +/datum/action + var/name = "Generic Action" + var/action_type = AB_ITEM + var/procname = null + var/atom/movable/target = null + var/check_flags = 0 + var/processing = 0 + var/active = 0 + var/obj/screen/movable/action_button/button = null + var/button_icon = 'icons/mob/actions.dmi' + var/button_icon_state = "default" + var/background_icon_state = "bg_default" + var/mob/living/owner + +/datum/action/New(var/Target) + target = Target + +/datum/action/Destroy() + if(owner) + Remove(owner) + +/datum/action/proc/Grant(mob/living/T) + if(owner) + if(owner == T) + return + Remove(owner) + owner = T + owner.actions.Add(src) + owner.update_action_buttons() + return + +/datum/action/proc/Remove(mob/living/T) + if(button) + if(T.client) + T.client.screen -= button + qdel(button) + button = null + T.actions.Remove(src) + T.update_action_buttons() + owner = null + return + +/datum/action/proc/Trigger() + if(!Checks()) + return + switch(action_type) + if(AB_ITEM) + if(target) + var/obj/item/item = target + item.ui_action_click() + //if(AB_SPELL) + // if(target) + // var/obj/effect/proc_holder/spell = target + // spell.Click() + if(AB_INNATE) + if(!active) + Activate() + else + Deactivate() + if(AB_GENERIC) + if(target && procname) + call(target,procname)(usr) + return + +/datum/action/proc/Activate() + return + +/datum/action/proc/Deactivate() + return + +/datum/action/proc/ProcessAction() + return + +/datum/action/proc/CheckRemoval(mob/living/user) // 1 if action is no longer valid for this mob and should be removed + return 0 + +/datum/action/proc/IsAvailable() + return Checks() + +/datum/action/proc/Checks()// returns 1 if all checks pass + if(!owner) + return 0 + if(check_flags & AB_CHECK_RESTRAINED) + if(owner.restrained()) + return 0 + if(check_flags & AB_CHECK_STUNNED) + if(owner.stunned) + return 0 + if(check_flags & AB_CHECK_LYING) + if(owner.lying) + return 0 + if(check_flags & AB_CHECK_ALIVE) + if(owner.stat) + return 0 + if(check_flags & AB_CHECK_INSIDE) + if(!(target in owner)) + return 0 + return 1 + +/datum/action/proc/UpdateName() + return name + +/obj/screen/movable/action_button + var/datum/action/owner + screen_loc = "WEST,NORTH" + +/obj/screen/movable/action_button/Click(location,control,params) + var/list/modifiers = params2list(params) + if(modifiers["shift"]) + moved = 0 + return 1 + if(usr.next_move >= world.time) // Is this needed ? + return + owner.Trigger() + return 1 + +/obj/screen/movable/action_button/proc/UpdateIcon() + if(!owner) + return + icon = owner.button_icon + icon_state = owner.background_icon_state + + overlays.Cut() + var/image/img + if(owner.action_type == AB_ITEM && owner.target) + var/obj/item/I = owner.target + img = image(I.icon, src , I.icon_state) + else if(owner.button_icon && owner.button_icon_state) + img = image(owner.button_icon,src,owner.button_icon_state) + img.pixel_x = 0 + img.pixel_y = 0 + overlays += img + + if(!owner.IsAvailable()) + color = rgb(128,0,0,128) + else + color = rgb(255,255,255,255) + +//Hide/Show Action Buttons ... Button +/obj/screen/movable/action_button/hide_toggle + name = "Hide Buttons" + icon = 'icons/mob/actions.dmi' + icon_state = "bg_default" + var/hidden = 0 + +/obj/screen/movable/action_button/hide_toggle/Click() + usr.hud_used.action_buttons_hidden = !usr.hud_used.action_buttons_hidden + + hidden = usr.hud_used.action_buttons_hidden + if(hidden) + name = "Show Buttons" + else + name = "Hide Buttons" + UpdateIcon() + usr.update_action_buttons() + + +/obj/screen/movable/action_button/hide_toggle/proc/InitialiseIcon(var/mob/living/user) + if(isalien(user)) + icon_state = "bg_alien" + else + icon_state = "bg_default" + UpdateIcon() + return + +/obj/screen/movable/action_button/hide_toggle/UpdateIcon() + overlays.Cut() + var/image/img = image(icon,src,hidden?"show":"hide") + overlays += img + return + +//This is the proc used to update all the action buttons. Properly defined in /mob/living/ +/mob/proc/update_action_buttons() + return + +#define AB_WEST_OFFSET 4 +#define AB_NORTH_OFFSET 26 +#define AB_MAX_COLUMNS 10 + +/datum/hud/proc/ButtonNumberToScreenCoords(var/number) // TODO : Make this zero-indexed for readabilty + var/row = round((number-1)/AB_MAX_COLUMNS) + var/col = ((number - 1)%(AB_MAX_COLUMNS)) + 1 + var/coord_col = "+[col-1]" + var/coord_col_offset = AB_WEST_OFFSET+2*col + var/coord_row = "[-1 - row]" + var/coord_row_offset = AB_NORTH_OFFSET + return "WEST[coord_col]:[coord_col_offset],NORTH[coord_row]:[coord_row_offset]" + +/datum/hud/proc/SetButtonCoords(var/obj/screen/button,var/number) + var/row = round((number-1)/AB_MAX_COLUMNS) + var/col = ((number - 1)%(AB_MAX_COLUMNS)) + 1 + var/x_offset = 32*(col-1) + AB_WEST_OFFSET + 2*col + var/y_offset = -32*(row+1) + AB_NORTH_OFFSET + + var/matrix/M = matrix() + M.Translate(x_offset,y_offset) + button.transform = M + +//Presets for item actions +/datum/action/item_action + check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_LYING|AB_CHECK_ALIVE|AB_CHECK_INSIDE + +/datum/action/item_action/CheckRemoval(mob/living/user) + return !(target in user) + +/datum/action/item_action/hands_free + check_flags = AB_CHECK_ALIVE|AB_CHECK_INSIDE + +#undef AB_WEST_OFFSET +#undef AB_NORTH_OFFSET +#undef AB_MAX_COLUMNS \ No newline at end of file diff --git a/code/_onclick/hud/alien_larva.dm b/code/_onclick/hud/alien_larva.dm new file mode 100644 index 00000000..d9f13489 --- /dev/null +++ b/code/_onclick/hud/alien_larva.dm @@ -0,0 +1,34 @@ +/mob/living/carbon/alien + hud_type = /datum/hud/larva + +/datum/hud/larva/FinalizeInstantiation() + + src.adding = list() + src.other = list() + + var/obj/screen/using + + using = new /obj/screen() + using.SetName("mov_intent") + using.set_dir(SOUTHWEST) + using.icon = 'icons/mob/screen1_alien.dmi' + using.icon_state = (mymob.m_intent == "run" ? "running" : "walking") + using.screen_loc = ui_acti + src.adding += using + move_intent = using + + mymob.healths = new /obj/screen() + mymob.healths.icon = 'icons/mob/screen1_alien.dmi' + mymob.healths.icon_state = "health0" + mymob.healths.SetName("health") + mymob.healths.screen_loc = ui_alien_health + + mymob.fire = new /obj/screen() + mymob.fire.icon = 'icons/mob/screen1_alien.dmi' + mymob.fire.icon_state = "fire0" + mymob.fire.SetName("fire") + mymob.fire.screen_loc = ui_fire + + mymob.client.screen = list() + mymob.client.screen += list( mymob.healths, mymob.fire) + mymob.client.screen += src.adding + src.other diff --git a/code/_onclick/hud/deity.dm b/code/_onclick/hud/deity.dm new file mode 100644 index 00000000..0a79ef25 --- /dev/null +++ b/code/_onclick/hud/deity.dm @@ -0,0 +1,57 @@ +/mob/living/deity + hud_type = /datum/hud/deity + +/datum/hud/deity/FinalizeInstantiation(ui_style = 'icons/mob/screen1_Midnight.dmi') + src.adding = list() + src.other = list() + + var/obj/screen/intent/deity/D = new() + + src.adding += D + action_intent = D + + mymob.client.screen = list() + mymob.client.screen += src.adding + D.sync_to_mob(mymob) + + +/obj/screen/intent/deity + var/list/desc_screens = list() + screen_loc = "EAST-5:122,SOUTH:8" + +/obj/screen/intent/deity/New() + ..() + overlays += image('icons/mob/screen_phenomena.dmi', icon_state = "hud", pixel_x = -138, pixel_y = -1) + +/obj/screen/intent/deity/proc/sync_to_mob(var/mob) + var/mob/living/deity/D = mob + for(var/i in 1 to D.control_types.len) + var/obj/screen/S = new() + S.SetName(null) //Don't want them to be able to actually right click it. + S.mouse_opacity = 0 + S.icon_state = "blank" + desc_screens[D.control_types[i]] = S + S.maptext_width = 128 + S.screen_loc = screen_loc + //This sets it up right. Trust me. + S.maptext_y = 33/2*i - i*i/2 - 10 + D.client.screen += S + S.maptext_x = -125 + + update_text() + +/obj/screen/intent/deity/proc/update_text() + if(!istype(usr, /mob/living/deity)) + return + var/mob/living/deity/D = usr + for(var/i in D.control_types) + var/obj/screen/S = desc_screens[i] + var/datum/phenomena/P = D.intent_phenomenas[intent][i] + if(P) + S.maptext = "[P.name]" + else + S.maptext = null + +/obj/screen/intent/deity/Click(var/location, var/control, var/params) + ..() + update_text() \ No newline at end of file diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm new file mode 100644 index 00000000..1a574c86 --- /dev/null +++ b/code/_onclick/hud/fullscreen.dm @@ -0,0 +1,203 @@ + +/mob + var/list/screens = list() + +/mob/proc/set_fullscreen(condition, screen_name, screen_type, arg) + condition ? overlay_fullscreen(screen_name, screen_type, arg) : clear_fullscreen(screen_name) + +/mob/proc/overlay_fullscreen(category, type, severity) + var/obj/screen/fullscreen/screen = screens[category] + + if(screen) + if(screen.type != type) + clear_fullscreen(category, FALSE) + screen = null + else if(!severity || severity == screen.severity) + return null + + if(!screen) + screen = new type() + + screen.icon_state = "[initial(screen.icon_state)][severity]" + screen.severity = severity + + screens[category] = screen + if(client && (stat != DEAD || screen.allstate)) + client.screen += screen + return screen + +/mob/proc/clear_fullscreen(category, animated = 10) + var/obj/screen/fullscreen/screen = screens[category] + if(!screen) + return + + screens -= category + + if(animated) + spawn(0) + animate(screen, alpha = 0, time = animated) + sleep(animated) + if(client) + client.screen -= screen + qdel(screen) + else + if(client) + client.screen -= screen + qdel(screen) + +/mob/proc/clear_fullscreens() + for(var/category in screens) + clear_fullscreen(category) + +/mob/proc/hide_fullscreens() + if(client) + for(var/category in screens) + client.screen -= screens[category] + +/mob/proc/reload_fullscreen() + if(client) + for(var/category in screens) + client.screen |= screens[category] + +/obj/screen/fullscreen + icon = 'icons/mob/screen_full.dmi' + icon_state = "default" + screen_loc = "CENTER-7,CENTER-7" + plane = FULLSCREEN_PLANE + mouse_opacity = 0 + var/severity = 0 + var/allstate = 0 //shows if it should show up for dead people too + +/obj/screen/fullscreen/Destroy() + severity = 0 + return ..() + +/obj/screen/fullscreen/brute + icon_state = "brutedamageoverlay" + layer = SCREEN_DAMAGE_LAYER + +/obj/screen/fullscreen/oxy + icon_state = "oxydamageoverlay" + layer = SCREEN_DAMAGE_LAYER + +/obj/screen/fullscreen/crit + icon_state = "passage" + layer = CRIT_LAYER + +/obj/screen/fullscreen/blind + icon_state = "blackimageoverlay" + layer = BLIND_LAYER + +/obj/screen/fullscreen/blackout + icon = 'icons/mob/screen1.dmi' + icon_state = "blackanimate" + screen_loc = "WEST,SOUTH to EAST,NORTH" + layer = BLIND_LAYER + +/obj/screen/fullscreen/impaired + icon_state = "impairedoverlay" + layer = IMPAIRED_LAYER + +/obj/screen/fullscreen/ghost + icon_state = "ghost2" + layer = FULLSCREEN_LAYER + +/obj/screen/fullscreen/fog + icon = 'icons/effects/weather.dmi' + screen_loc = "WEST,SOUTH to EAST,NORTH" + icon_state = "fog" + alpha = 30 + +/obj/screen/fullscreen/fallout + icon = 'icons/effects/weather.dmi' + screen_loc = "WEST,SOUTH to EAST,NORTH" + icon_state = "fallout" + alpha = 30 + +/obj/screen/fullscreen/snowstorm + icon = 'icons/effects/weather.dmi' + screen_loc = "WEST,SOUTH to EAST,NORTH" + icon_state = "snowfall_heavy_old" + alpha = 25 + +/obj/screen/fullscreen/storm + icon = 'icons/effects/weather.dmi' + screen_loc = "WEST,SOUTH to EAST,NORTH" + icon_state = "ashfall_light" + alpha = 50 + +/obj/screen/fullscreen/blurry + icon = 'icons/mob/screen1.dmi' + screen_loc = "WEST,SOUTH to EAST,NORTH" + icon_state = "blurry" + +/obj/screen/fullscreen/flash + icon = 'icons/mob/screen1.dmi' + screen_loc = "WEST,SOUTH to EAST,NORTH" + icon_state = "flash" + +/obj/screen/fullscreen/flash/noise + icon_state = "noise" + +/obj/screen/fullscreen/high + icon = 'icons/mob/screen1.dmi' + screen_loc = "WEST,SOUTH to EAST,NORTH" + icon_state = "druggy" + +/obj/screen/fullscreen/noise + icon = 'icons/effects/static.dmi' + icon_state = "1 light" + screen_loc = ui_entire_screen + layer = FULLSCREEN_LAYER + alpha = 127 + +/obj/screen/fullscreen/freakout + icon = 'icons/mob/screen1.dmi' + screen_loc = "WEST,SOUTH to EAST,NORTH" + icon_state = "extreme" + +/obj/screen/fullscreen/damagenoise + icon = 'icons/mob/damagenoise.dmi' + icon_state = "noise" + screen_loc = "WEST, SOUTH to EAST, NORTH" + layer = FULLSCREEN_LAYER + +/obj/screen/fullscreen/fadeoutok + icon = 'icons/mob/screen1.dmi' + icon_state = "fade" + screen_loc = "WEST,SOUTH to EAST,NORTH" + layer = HUD_ITEM_LAYER + +/obj/screen/fullscreen/mood_dark + icon = 'icons/mob/screen1.dmi' + icon_state = "dark" + screen_loc = "WEST,SOUTH to EAST,NORTH" + layer = FULLSCREEN_LAYER + + +/obj/screen/fullscreen/fadeout + icon = 'icons/mob/screen1.dmi' + icon_state = "black" + screen_loc = ui_entire_screen + layer = FULLSCREEN_LAYER + alpha = 0 + allstate = 1 + +/obj/screen/fullscreen/fadeout/Initialize() + . = ..() + animate(src, alpha = 255, time = 10) + +/obj/screen/fullscreen/scanline + icon = 'icons/effects/static.dmi' + icon_state = "scanlines" + screen_loc = ui_entire_screen + alpha = 50 + layer = FULLSCREEN_LAYER + +/obj/screen/fullscreen/fishbed + icon_state = "fishbed" + allstate = 1 + +/obj/screen/fullscreen/pain + icon_state = "brutedamageoverlay6" + alpha = 0 \ No newline at end of file diff --git a/code/_onclick/hud/global_hud.dm b/code/_onclick/hud/global_hud.dm new file mode 100644 index 00000000..7fc2a7fc --- /dev/null +++ b/code/_onclick/hud/global_hud.dm @@ -0,0 +1,27 @@ +/* + The global hud: + Uses the same visual objects for all players. +*/ + +GLOBAL_DATUM_INIT(global_hud, /datum/global_hud, new()) + +/datum/global_hud + var/obj/screen/nvg + var/obj/screen/thermal + var/obj/screen/meson + var/obj/screen/science + +/datum/global_hud/proc/setup_overlay(var/icon_state) + var/obj/screen/screen = new /obj/screen() + screen.screen_loc = "1,1" + screen.icon = 'icons/obj/hud_full.dmi' + screen.icon_state = icon_state + screen.mouse_opacity = 0 + + return screen + +/datum/global_hud/New() + nvg = setup_overlay("nvg_hud") + thermal = setup_overlay("thermal_hud") + meson = setup_overlay("meson_hud") + science = setup_overlay("science_hud") \ No newline at end of file diff --git a/code/_onclick/hud/gun_mode.dm b/code/_onclick/hud/gun_mode.dm new file mode 100644 index 00000000..8b63446c --- /dev/null +++ b/code/_onclick/hud/gun_mode.dm @@ -0,0 +1,66 @@ +/obj/screen/gun + name = "gun" + icon = 'icons/mob/screen1.dmi' + master = null + dir = 2 + +/obj/screen/gun/Click(location, control, params) + if(!usr) + return + return 1 + +/obj/screen/gun/move + name = "Allow Movement" + icon_state = "no_walk0" + screen_loc = ui_gun2 + +/obj/screen/gun/move/Click(location, control, params) + if(..()) + var/mob/living/user = usr + if(istype(user)) + if(!user.aiming) user.aiming = new(user) + user.aiming.toggle_permission(TARGET_CAN_MOVE) + return 1 + return 0 + +/obj/screen/gun/item + name = "Allow Item Use" + icon_state = "no_item0" + screen_loc = ui_gun1 + +/obj/screen/gun/item/Click(location, control, params) + if(..()) + var/mob/living/user = usr + if(istype(user)) + if(!user.aiming) user.aiming = new(user) + user.aiming.toggle_permission(TARGET_CAN_CLICK) + return 1 + return 0 + +/obj/screen/gun/mode + name = "Toggle Gun Mode" + icon_state = "gun0" + screen_loc = ui_gun_select + +/obj/screen/gun/mode/Click(location, control, params) + if(..()) + var/mob/living/user = usr + if(istype(user)) + if(!user.aiming) user.aiming = new(user) + user.aiming.toggle_active() + return 1 + return 0 + +/obj/screen/gun/radio + name = "Disallow Radio Use" + icon_state = "no_radio1" + screen_loc = ui_gun4 + +/obj/screen/gun/radio/Click(location, control, params) + if(..()) + var/mob/living/user = usr + if(istype(user)) + if(!user.aiming) user.aiming = new(user) + user.aiming.toggle_permission(TARGET_CAN_RADIO) + return 1 + return 0 diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm new file mode 100644 index 00000000..18a4d939 --- /dev/null +++ b/code/_onclick/hud/hud.dm @@ -0,0 +1,391 @@ +/* + The hud datum + Used to show and hide huds for all the different mob types, + including inventories and item quick actions. +*/ + +/mob + var/hud_type = null + var/datum/hud/hud_used = null + +/mob/proc/InitializeHud() + if(hud_used) + qdel(hud_used) + if(hud_type) + hud_used = new hud_type(src) + else + hud_used = new /datum/hud + add_filter_effects() + +/mob/proc/add_filter_effects() + var/obj/blur_planemaster/PM = new//This is the z-blur shit. It's HUD related so I put it here. + var/obj/blur_planemaster/zmob = new + var/obj/blur_planemaster/under = new + var/obj/screen/plane_master/bullet_plane/BP = new + var/obj/screen/plane_master/ghost_master/gm = new //So ghosts are spooky and blurry. + //var/obj/screen/plane_master/humanAO/HM = new + //var/obj/screen/plane_master/wallAO/WT = new + //var/obj/screen/plane_master/objectAO/OB = new + //var/obj/screen/plane_master/lying_human/LH = new + //var/obj/screen/plane_master/mobAO/MO = new + under.plane = UNDER_OPENSPACE_PLANE + zmob.plane = OVER_OPENSPACE_PLANE + //client.screen += LH + //client.screen += OB + //client.screen += WT + //client.screen += HM + //client.screen += MO + client.screen += zmob + client.screen += PM + client.screen += under + client.screen += gm + client.screen += BP + + +/datum/hud + var/mob/mymob + + var/hud_shown = 1 //Used for the HUD toggle (F12) + var/inventory_shown = 1 //the inventory + var/show_intent_icons = 0 + var/hotkey_ui_hidden = 0 //This is to hide the buttons that can be used via hotkeys. (hotkeybuttons list of buttons) + + var/obj/screen/lingchemdisplay + var/obj/screen/r_hand_hud_object + var/obj/screen/l_hand_hud_object + var/obj/screen/swaphands_hud_object + var/obj/screen/action_intent + var/obj/screen/move_intent + var/obj/screen/atk_intent + var/obj/screen/offense_intent + var/obj/screen/defense_intent + var/obj/screen/quick_intent + var/obj/screen/aim_intent + + var/list/adding //Stuff that won't be made hidden. + var/list/other //For stuff that can be made hidden. + var/list/all_inv = list() //All inventory. + var/list/obj/screen/hotkeybuttons + + var/obj/screen/movable/action_button/hide_toggle/hide_actions_toggle + var/action_buttons_hidden = 0 + + +/datum/hud/New(mob/owner) + mymob = owner + instantiate() + ..() + +/datum/hud/Destroy() + . = ..() + lingchemdisplay = null + r_hand_hud_object = null + l_hand_hud_object = null + action_intent = null + move_intent = null + adding = null + other = null + hotkeybuttons = null + mymob = null + +/datum/hud/proc/add_inventory_overlay() //THIS SHIT IS UNHOLY! DON'T FUCK WITH IT UNLESS YOU KNOW WHAT YOU'RE DOING! + if(!mymob) + return + if(!ishuman(mymob)) + return + for(var/obj/screen/S in all_inv) + S.overlays.Cut()//Clear all overlays. + var/mob/living/carbon/human/H = mymob + for(var/gear_slot in H.species.hud.gear) + var/list/hud_data = H.species.hud.gear[gear_slot] + switch(hud_data["slot"]) + if(slot_shoes) + if(H.shoes) + for(var/obj/screen/S in all_inv) + if(S.name == "shoes") + S.overlays += "hud_fill" + if(slot_l_ear) + if(H.l_ear) + for(var/obj/screen/S in all_inv) + if(S.name == "l_ear") + S.overlays += "hud_fill" + if(slot_r_ear) + if(H.r_ear) + for(var/obj/screen/S in all_inv) + if(S.name == "r_ear") + S.overlays += "hud_fill" + if(slot_gloves) + if(H.gloves) + for(var/obj/screen/S in all_inv) + if(S.name == "gloves") + S.overlays += "hud_fill" + if(slot_glasses) + if(H.glasses) + for(var/obj/screen/S in all_inv) + if(S.name == "eyes") + S.overlays += "hud_fill" + if(slot_s_store) + if(H.s_store) + for(var/obj/screen/S in all_inv) + if(S.name == "back2") + S.overlays += "hud_fill" + if(slot_tie) + if(H.tie_slot) + for(var/obj/screen/S in all_inv) + if(S.name == "neck") + S.overlays += "hud_fill" + if(slot_belt) + if(H.belt) + for(var/obj/screen/S in all_inv) + if(S.name == "belt") + S.overlays += "hud_fill" + if(slot_head) + if(H.head) + for(var/obj/screen/S in all_inv) + if(S.name == "head") + S.overlays += "hud_fill" + + if(slot_w_uniform) + if(H.w_uniform) + for(var/obj/screen/S in all_inv) + if(S.name == "i_clothing") + S.overlays += "hud_fill" + + if(slot_wear_id) + if(H.wear_id) + for(var/obj/screen/S in all_inv) + if(S.name == "id") + S.overlays += "hud_fill" + + if(slot_back) + if(H.back) + for(var/obj/screen/S in all_inv) + if(S.name == "back") + S.overlays += "hud_fill" + + if(slot_wear_suit) + if(H.wear_suit) + for(var/obj/screen/S in all_inv) + if(S.name == "o_clothing") + S.overlays += "hud_fill" + if(slot_wear_mask) + if(H.wear_mask) + for(var/obj/screen/S in all_inv) + if(S.name == "mask") + S.overlays += "hud_fill" + + + + +/datum/hud/proc/hidden_inventory_update() + if(!mymob) return + if(ishuman(mymob)) + var/mob/living/carbon/human/H = mymob + for(var/gear_slot in H.species.hud.gear) + var/list/hud_data = H.species.hud.gear[gear_slot] + if(inventory_shown && hud_shown) + switch(hud_data["slot"]) + if(slot_shoes) + if(H.shoes) H.shoes.screen_loc = hud_data["loc"] + if(slot_l_ear) + if(H.l_ear) H.l_ear.screen_loc = hud_data["loc"] + if(slot_r_ear) + if(H.r_ear) H.r_ear.screen_loc = hud_data["loc"] + if(slot_gloves) + if(H.gloves) H.gloves.screen_loc = hud_data["loc"] + if(slot_glasses) + if(H.glasses) H.glasses.screen_loc = hud_data["loc"] + if(slot_s_store) + if(H.s_store) H.s_store.screen_loc = hud_data["loc"] + if(slot_tie) + if(H.tie_slot) H.tie_slot.screen_loc = hud_data["loc"] + else + switch(hud_data["slot"]) + if(slot_shoes) + if(H.shoes) H.shoes.screen_loc = null + if(slot_l_ear) + if(H.l_ear) H.l_ear.screen_loc = null + if(slot_r_ear) + if(H.r_ear) H.r_ear.screen_loc = null + if(slot_gloves) + if(H.gloves) H.gloves.screen_loc = null + if(slot_glasses) + if(H.glasses) H.glasses.screen_loc = null + if(slot_s_store) + if(H.s_store) H.s_store.screen_loc = null + if(slot_tie) + if(H.tie_slot) H.tie_slot.screen_loc = null + + + +/datum/hud/proc/persistant_inventory_update() + if(!mymob) + return + + if(ishuman(mymob)) + var/mob/living/carbon/human/H = mymob + for(var/gear_slot in H.species.hud.gear) + var/list/hud_data = H.species.hud.gear[gear_slot] + if(hud_shown) + switch(hud_data["slot"]) + if(slot_wear_id) + if(H.wear_id) H.wear_id.screen_loc = hud_data["loc"] + if(slot_belt) + if(H.belt) H.belt.screen_loc = hud_data["loc"] + if(slot_back) + if(H.back) H.back.screen_loc = hud_data["loc"] + if(slot_l_store) + if(H.l_store) H.l_store.screen_loc = hud_data["loc"] + if(slot_r_store) + if(H.r_store) H.r_store.screen_loc = hud_data["loc"] + if(slot_head) + if(H.head) H.head.screen_loc = hud_data["loc"] + if(slot_w_uniform) + if(H.w_uniform) H.w_uniform.screen_loc = hud_data["loc"] + if(slot_wear_suit) + if(H.wear_suit) H.wear_suit.screen_loc = hud_data["loc"] + if(slot_wear_mask) + if(H.wear_mask) H.wear_mask.screen_loc = hud_data["loc"] + else + switch(hud_data["slot"]) + if(slot_wear_id) + if(H.wear_id) H.wear_id.screen_loc = null + if(slot_belt) + if(H.belt) H.belt.screen_loc = null + if(slot_back) + if(H.back) H.back.screen_loc = null + if(slot_l_store) + if(H.l_store) H.l_store.screen_loc = null + if(slot_r_store) + if(H.r_store) H.r_store.screen_loc = null + if(slot_head) + if(H.head) H.head.screen_loc = null + if(slot_w_uniform) + if(H.w_uniform) H.w_uniform.screen_loc = null + if(slot_wear_suit) + if(H.wear_suit) H.wear_suit.screen_loc = null + if(slot_wear_mask) + if(H.wear_mask) H.wear_mask.screen_loc = null + + +/datum/hud/proc/instantiate() + if(!ismob(mymob)) return 0 + if(!mymob.client) return 0 + var/ui_style = ui_style2icon(mymob.client.prefs.UI_style) + var/ui_color = mymob.client.prefs.UI_style_color + var/ui_alpha = mymob.client.prefs.UI_style_alpha + + FinalizeInstantiation(ui_style, ui_color, ui_alpha) + +/datum/hud/proc/FinalizeInstantiation(var/ui_style, var/ui_color, var/ui_alpha) + return + +//Triggered when F12 is pressed (Unless someone changed something in the DMF) +//I changed the DMF because this is bad and I hate it - Matt +/mob/verb/button_pressed_F12(var/full = 0 as null) + set name = "F12" + set hidden = 1 + + if(!hud_used) + to_chat(usr, "This mob type does not use a HUD.") + return + + if(!ishuman(src)) + to_chat(usr, "Inventory hiding is currently only supported for human mobs, sorry.") + return + + if(!client) return + if(client.view != world.view) + return + if(hud_used.hud_shown) + hud_used.hud_shown = 0 + if(src.hud_used.adding) + src.client.screen -= src.hud_used.adding + if(src.hud_used.other) + src.client.screen -= src.hud_used.other + if(src.hud_used.hotkeybuttons) + src.client.screen -= src.hud_used.hotkeybuttons + + //Due to some poor coding some things need special treatment: + //These ones are a part of 'adding', 'other' or 'hotkeybuttons' but we want them to stay + if(!full) + src.client.screen += src.hud_used.l_hand_hud_object //we want the hands to be visible + src.client.screen += src.hud_used.r_hand_hud_object //we want the hands to be visible + src.client.screen += src.hud_used.action_intent //we want the intent swticher visible + src.hud_used.action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is. + else + src.client.screen -= src.healths + src.client.screen -= src.internals + src.client.screen -= src.gun_setting_icon + + //These ones are not a part of 'adding', 'other' or 'hotkeybuttons' but we want them gone. + src.client.screen -= src.zone_sel //zone_sel is a mob variable for some reason. + + else + hud_used.hud_shown = 1 + if(src.hud_used.adding) + src.client.screen += src.hud_used.adding + if(src.hud_used.other && src.hud_used.inventory_shown) + src.client.screen += src.hud_used.other + if(src.hud_used.hotkeybuttons && !src.hud_used.hotkey_ui_hidden) + src.client.screen += src.hud_used.hotkeybuttons + if(src.healths) + src.client.screen |= src.healths + if(src.internals) + src.client.screen |= src.internals + if(src.gun_setting_icon) + src.client.screen |= src.gun_setting_icon + + src.hud_used.action_intent.screen_loc = ui_acti //Restore intent selection to the original position + src.client.screen += src.zone_sel //This one is a special snowflake + + hud_used.hidden_inventory_update() + hud_used.persistant_inventory_update() + update_action_buttons() + +//Similar to button_pressed_F12() but keeps zone_sel, gun_setting_icon, and healths. +/mob/proc/toggle_zoom_hud() + if(!hud_used) + return + if(!ishuman(src)) + return + if(!client) + return + if(client.view != world.view) + return + + if(hud_used.hud_shown) + hud_used.hud_shown = 0 + if(src.hud_used.adding) + src.client.screen -= src.hud_used.adding + if(src.hud_used.other) + src.client.screen -= src.hud_used.other + if(src.hud_used.hotkeybuttons) + src.client.screen -= src.hud_used.hotkeybuttons + src.client.screen -= src.internals + src.client.screen += src.hud_used.action_intent //we want the intent swticher visible + else + hud_used.hud_shown = 1 + if(src.hud_used.adding) + src.client.screen += src.hud_used.adding + if(src.hud_used.other && src.hud_used.inventory_shown) + src.client.screen += src.hud_used.other + if(src.hud_used.hotkeybuttons && !src.hud_used.hotkey_ui_hidden) + src.client.screen += src.hud_used.hotkeybuttons + if(src.internals) + src.client.screen |= src.internals + src.hud_used.action_intent.screen_loc = ui_acti //Restore intent selection to the original position + + hud_used.hidden_inventory_update() + hud_used.persistant_inventory_update() + update_action_buttons() + +/mob/proc/add_click_catcher() + if(!client.void) + client.void = create_click_catcher() + if(!client.screen) + client.screen = list() + client.screen |= client.void + +/mob/new_player/add_click_catcher() + return diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm new file mode 100644 index 00000000..c454cca9 --- /dev/null +++ b/code/_onclick/hud/human.dm @@ -0,0 +1,577 @@ +/mob/living/carbon/human + hud_type = /datum/hud/human + +/datum/hud/human/FinalizeInstantiation(var/ui_style='icons/mob/screen1_White.dmi', var/ui_color = "#ffffff", var/ui_alpha = 255) + var/mob/living/carbon/human/target = mymob + var/datum/hud_data/hud_data + if(!istype(target)) + hud_data = new() + else + hud_data = target.species.hud + + ui_style = 'icons/mob/screen/screen_neo.dmi'//Set this to whatever you want. screen_neo looks best. + + src.adding = list() + src.other = list() + src.hotkeybuttons = list() //These can be disabled for hotkey usersx + mymob.using_alt_hud = 1 + + var/list/hud_elements = list() + var/obj/screen/using + var/obj/screen/inventory/inv_box + + using = new /obj/screen() //Right hud bar + using.dir = SOUTH + using.icon = ui_style + using.icon_state = "bg" + using.screen_loc = "EAST+1,SOUTH to EAST+1,NORTH" + using.layer = UNDER_HUD_LAYER + adding += using + + using = new /obj/screen() //Lower hud bar 1 + using.dir = WEST + using.icon = ui_style + using.icon_state = "bg" + using.screen_loc = "WEST,SOUTH-1 to EAST,SOUTH-1" + using.layer = UNDER_HUD_LAYER + adding += using + + using = new /obj/screen() //Lower hud bar 2 + using.dir = WEST + using.icon = ui_style + using.icon_state = "bg" + using.screen_loc = "WEST,SOUTH-2 to EAST,SOUTH-2" + using.layer = UNDER_HUD_LAYER + adding += using + + using = new /obj/screen() //really spefici lower right square space 1 + using.dir = SOUTH + using.icon = ui_style + using.icon_state = "bg" + using.screen_loc = "EAST+1,NORTH-16" + using.layer = UNDER_HUD_LAYER + adding += using + + using = new /obj/screen() //really spefici lower right square space 2 + using.dir = SOUTH + using.icon = ui_style + using.icon_state = "bg" + using.screen_loc = "EAST+1,NORTH-15" + using.layer = UNDER_HUD_LAYER + adding += using + +/* + //atk_intent icons? +/////////////////////////////// + using = new /obj/screen() + using.name = "atk_intent" + using.dir = SOUTHWEST + using.icon = ui_style//'icon/mob/screencombat_intents' + using.icon_state = mymob.atk_intent + using.screen_loc = ui_atk + using.color = ui_color + using.alpha = ui_alpha + using.layer = HUD_BASE_LAYER + src.adding += using + atk_intent = using + + var/icon/icco + + icco = new(ui_style, "black") + icco.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) + icco.DrawBox(rgb(255,255,255,1),1,icco.Height()/2,icco.Width()/2,icco.Height()) + using = new /obj/screen( src ) + using.name = "aimed" + using.icon = icco + using.screen_loc = ui_atk + using.alpha = ui_alpha + using.layer = HUD_ITEM_LAYER + src.adding += using + aim_intent = using + + icco = new(ui_style, "black") + icco.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) + icco.DrawBox(rgb(255,255,255,1),icco.Width()/2,icco.Height()/2,icco.Width(),icco.Height()) + using = new /obj/screen( src ) + using.name = "offense" + using.icon = icco + using.screen_loc = ui_atk + using.alpha = ui_alpha + using.layer = HUD_ITEM_LAYER + src.adding += using + offense_intent = using + + icco = new(ui_style, "black") + icco.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) + icco.DrawBox(rgb(255,255,255,1),icco.Width()/2,1,icco.Width(),icco.Height()/2) + using = new /obj/screen( src ) + using.name = "quick" + using.icon = icco + using.screen_loc = ui_atk + using.alpha = ui_alpha + using.layer = HUD_ITEM_LAYER + src.adding += using + quick_intent = using + + icco = new(ui_style, "black") + icco.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) + icco.DrawBox(rgb(255,255,255,1),1,1,icco.Width()/2,icco.Height()/2) + using = new /obj/screen( src ) + using.name = "defense" + using.icon = icco + using.screen_loc = ui_atk + using.alpha = ui_alpha + using.layer = HUD_ITEM_LAYER + src.adding += using + defense_intent = using +/////////////////////////////// +*/ + // Draw the various inventory equipment slots. + var/has_hidden_gear + for(var/gear_slot in hud_data.gear) + + inv_box = new /obj/screen/inventory() + inv_box.icon = ui_style + inv_box.color = ui_color + inv_box.alpha = ui_alpha + + var/list/slot_data = hud_data.gear[gear_slot] + inv_box.name = gear_slot + inv_box.screen_loc = slot_data["loc"] + inv_box.slot_id = slot_data["slot"] + inv_box.icon_state = slot_data["state"] + + if(slot_data["dir"]) + inv_box.set_dir(slot_data["dir"]) + + if(slot_data["toggle"]) + src.other += inv_box + has_hidden_gear = 1 + else + src.adding += inv_box + src.all_inv += inv_box + + if(has_hidden_gear) + using = new /obj/screen() + using.name = "other" + using.icon = ui_style + using.icon_state = "other" + using.screen_loc = "SOUTH,4" + using.color = ui_color + using.alpha = ui_alpha + using.layer = 2 + //src.adding += using + + // Draw the attack intent dialogue. + if(hud_data.has_a_intent) + + using = new /obj/screen/intent() + using.icon = ui_style + src.adding += using + action_intent = using + + hud_elements |= using + + if(hud_data.has_m_intent) + using = new /obj/screen() + using.name = "mov_intent" + using.icon = ui_style + using.icon_state = (mymob.m_intent == "run" ? "running" : "walking") + using.screen_loc = ui_movi + using.color = ui_color + using.alpha = ui_alpha + src.adding += using + move_intent = using + + if(hud_data.has_drop) + using = new /obj/screen() + using.name = "drop" + using.icon = ui_style + using.icon_state = "act_drop" + using.screen_loc = ui_dropbutton + using.color = ui_color + using.alpha = ui_alpha + src.hotkeybuttons += using + + if(hud_data.has_hands) + /* + using = new /obj/screen() + using.name = "equip" + using.icon = ui_style + using.icon_state = "act_equip" + using.screen_loc = ui_tg_equip + using.color = ui_color + using.alpha = ui_alpha + src.adding += using + */ + + inv_box = new /obj/screen/inventory() + inv_box.name = "r_hand" + inv_box.icon = ui_style + inv_box.icon_state = "r_hand_inactive" + if(mymob && !mymob.hand) //This being 0 or null means the right hand is in use + inv_box.icon_state = "r_hand_active" + inv_box.screen_loc = ui_rhand + inv_box.slot_id = slot_r_hand + inv_box.color = ui_color + inv_box.alpha = ui_alpha + + src.r_hand_hud_object = inv_box + src.adding += inv_box + + inv_box = new /obj/screen/inventory() + inv_box.name = "l_hand" + inv_box.icon = ui_style + inv_box.icon_state = "l_hand_inactive" + if(mymob && mymob.hand) //This being 1 means the left hand is in use + inv_box.icon_state = "l_hand_active" + inv_box.screen_loc = ui_lhand + inv_box.slot_id = slot_l_hand + inv_box.color = ui_color + inv_box.alpha = ui_alpha + src.l_hand_hud_object = inv_box + src.adding += inv_box + /* + using = new /obj/screen/inventory() + using.name = "hand" + using.icon = ui_style + using.icon_state = "hand" + using.screen_loc = ui_swaphand1 + using.color = ui_color + using.alpha = ui_alpha + src.adding += using + + using = new /obj/screen/inventory() + using.name = "hand" + using.icon = ui_style + using.icon_state = "hand2" + using.screen_loc = ui_swaphand2 + using.color = ui_color + using.alpha = ui_alpha + src.adding += using + */ + + using = new /obj/screen/inventory() + using.name = "hand" + using.dir = NORTH + using.icon = ui_style + using.icon_state = "hand" + using.screen_loc = ui_swaphand1 + src.swaphands_hud_object = using + src.adding += using + + if(hud_data.has_resist) + using = new /obj/screen() + using.name = "resist" + using.icon = ui_style + using.icon_state = "act_resist" + using.screen_loc = ui_resist + using.color = ui_color + using.alpha = ui_alpha + src.hotkeybuttons += using + + if(hud_data.has_throw) + mymob.throw_icon = new /obj/screen() + mymob.throw_icon.icon = ui_style + mymob.throw_icon.icon_state = "act_throw_off" + mymob.throw_icon.name = "throw" + mymob.throw_icon.screen_loc = ui_dropbutton + mymob.throw_icon.color = ui_color + mymob.throw_icon.alpha = ui_alpha + src.hotkeybuttons += mymob.throw_icon + hud_elements |= mymob.throw_icon + + mymob.pullin = new /obj/screen() + mymob.pullin.icon = ui_style + mymob.pullin.icon_state = "pull0" + mymob.pullin.name = "pull" + mymob.pullin.screen_loc = ui_pull + src.hotkeybuttons += mymob.pullin + hud_elements |= mymob.pullin + + if(hud_data.has_internals) + mymob.internals = new /obj/screen() + mymob.internals.icon = ui_style + mymob.internals.icon_state = "internal0" + mymob.internals.name = "internal" + mymob.internals.screen_loc = ui_internal + hud_elements |= mymob.internals + + if(hud_data.has_warnings) + mymob.oxygen = new /obj/screen() + mymob.oxygen.icon = ui_style + mymob.oxygen.icon_state = "oxy0" + mymob.oxygen.name = "oxygen" + mymob.oxygen.screen_loc = ui_oxygen + hud_elements |= mymob.oxygen + + mymob.toxin = new /obj/screen() + mymob.toxin.icon = ui_style + mymob.toxin.icon_state = "tox0" + mymob.toxin.name = "toxin" + mymob.toxin.screen_loc = ui_toxin + hud_elements |= mymob.toxin + + mymob.fire = new /obj/screen() + mymob.fire.icon = ui_style + mymob.fire.icon_state = "fire0" + mymob.fire.name = "fire" + mymob.fire.screen_loc = ui_fire + hud_elements |= mymob.fire + + mymob.healths = new /obj/screen() + mymob.healths.icon = ui_style + mymob.healths.icon_state = "health0" + mymob.healths.name = "health" + mymob.healths.screen_loc = ui_health + hud_elements |= mymob.healths + + if(hud_data.has_pressure) + mymob.pressure = new /obj/screen() + mymob.pressure.icon = ui_style + mymob.pressure.icon_state = "pressure0" + mymob.pressure.name = "pressure" + mymob.pressure.screen_loc = ui_pressure + hud_elements |= mymob.pressure + + if(hud_data.has_bodytemp) + mymob.bodytemp = new /obj/screen() + mymob.bodytemp.icon = ui_style + mymob.bodytemp.icon_state = "temp1" + mymob.bodytemp.name = "body temperature" + mymob.bodytemp.screen_loc = ui_temp + hud_elements |= mymob.bodytemp + + if(target.isSynthetic()) + target.cells = new /obj/screen() + target.cells.icon = 'icons/mob/screen1_robot.dmi' + target.cells.icon_state = "charge-empty" + target.cells.name = "cell" + target.cells.screen_loc = ui_nutrition + hud_elements |= target.cells + + else if(hud_data.has_nutrition) + mymob.nutrition_icon = new /obj/screen() + mymob.nutrition_icon.icon = ui_style + mymob.nutrition_icon.icon_state = "nutrition0" + mymob.nutrition_icon.name = "nutrition" + mymob.nutrition_icon.screen_loc = ui_nutrition + hud_elements |= mymob.nutrition_icon + + mymob.hydration_icon = new /obj/screen() + mymob.hydration_icon.icon = ui_style + mymob.hydration_icon.icon_state = "hydration0" + mymob.hydration_icon.name = "hydration" + mymob.hydration_icon.screen_loc = ui_nutrition + hud_elements |= mymob.hydration_icon + + mymob.stamina_icon = new /obj/screen()//STAMINA + mymob.stamina_icon.icon = ui_style + mymob.stamina_icon.icon_state = "stamina0" + mymob.stamina_icon.name = "stamina" + mymob.stamina_icon.screen_loc = ui_stamina + hud_elements |= mymob.stamina_icon + + + mymob.rest = new /obj/screen() + mymob.rest.name = "rest" + mymob.rest.icon = ui_style + mymob.rest.icon_state = "rest[mymob.resting]" + mymob.rest.screen_loc = ui_rest + hud_elements |= mymob.rest + if (mymob.resting) + mymob.rest.icon_state = "rest1" + else + mymob.rest.icon_state = "rest0" + + mymob.kick_icon = new /obj/screen() + mymob.kick_icon.icon = ui_style + mymob.kick_icon.icon_state = "kick" + mymob.kick_icon.name = "kick" + mymob.kick_icon.screen_loc = ui_jmp_kck + hud_elements |= mymob.kick_icon + + mymob.jump_icon = new /obj/screen() + mymob.jump_icon.icon = ui_style + mymob.jump_icon.icon_state = "jump" + mymob.jump_icon.name = "jump" + mymob.jump_icon.screen_loc = ui_jmp_kck + hud_elements |= mymob.jump_icon + + mymob.wield_icon = new /obj/screen() + mymob.wield_icon.name = "wield" + mymob.wield_icon.icon = ui_style + mymob.wield_icon.icon_state = "wield" + mymob.wield_icon.screen_loc = ui_jmp_kck + hud_elements |= mymob.wield_icon + + mymob.fixeye = new /obj/screen() + mymob.fixeye.icon = ui_style + mymob.fixeye.icon_state = "fixeye" + mymob.fixeye.name = "fixeye" + mymob.fixeye.screen_loc = ui_fixeye + hud_elements |= mymob.fixeye + + mymob.pain = new /obj/screen( null ) + mymob.pain.icon = ui_style + mymob.pain.icon_state = "blank" + mymob.pain.name = "pain" + mymob.pain.screen_loc = "WEST,SOUTH to EAST,NORTH" + mymob.pain.layer = UNDER_HUD_LAYER + mymob.pain.mouse_opacity = 0 + hud_elements |= mymob.pain + + mymob.noise = new /obj/screen() + mymob.noise.icon = 'icons/mob/noise.dmi' + mymob.noise.icon_state = "[rand(1,9)]j" + mymob.noise.name = " " + mymob.noise.screen_loc = "WEST, SOUTH to EAST, NORTH" + mymob.noise.plane = FULLSCREEN_PLANE + mymob.noise.layer = 1 + mymob.noise.mouse_opacity = 0 + hud_elements |= mymob.noise + + mymob.combat_icon = new /obj/screen()//combat mode + mymob.combat_icon.name = "combat mode" + mymob.combat_icon.icon = ui_style//'icons/mob/screen/dark.dmi' + mymob.combat_icon.icon_state = "combat0" + mymob.combat_icon.screen_loc = ui_combat + hud_elements |= mymob.combat_icon + + mymob.combat_intent_icon = new /obj/screen()//combat mode + mymob.combat_intent_icon.name = "combat intent" + mymob.combat_intent_icon.icon = ui_style//'icons/mob/screen/dark.dmi' + mymob.combat_intent_icon.icon_state = "dodge" + mymob.combat_intent_icon.screen_loc = ui_combat_intent + hud_elements |= mymob.combat_intent_icon + + mymob.surrender = new /obj/screen() + mymob.surrender.name = "surrender" + mymob.surrender.icon = ui_style//'icons/mob/screen/dark.dmi' + mymob.surrender.icon_state = "surrender" + mymob.surrender.screen_loc = ui_surrender + hud_elements |= mymob.surrender + + mymob.happiness_icon = new /obj/screen() + mymob.happiness_icon.name = "mood" + mymob.happiness_icon.icon = ui_style + mymob.happiness_icon.icon_state = "mood4" + mymob.happiness_icon.screen_loc = ui_happiness + hud_elements |= mymob.happiness_icon + + + mymob.zone_sel = new /obj/screen/zone_sel( null ) + mymob.zone_sel.icon = 'icons/mob/puppet_new.dmi'//'icons/mob/puppet.dmi' + mymob.zone_sel.overlays.Cut() + mymob.zone_sel.overlays += image('icons/mob/zone_sel_newer.dmi', "[mymob.zone_sel.selecting]") + hud_elements |= mymob.zone_sel + + + mymob.atk_intent_icon = new /obj/screen/combat_intents() + mymob.atk_intent_icon.screen_loc = ui_atk + hud_elements |= mymob.atk_intent_icon + + + /* + mymob.zone_sel = new /obj/screen/zone_sel( null ) + mymob.zone_sel.icon = ui_style + mymob.zone_sel.color = ui_color + mymob.zone_sel.alpha = ui_alpha + mymob.zone_sel.overlays.Cut() + mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]") + hud_elements |= mymob.zone_sel + */ + + //Handle the gun settings buttons + mymob.gun_setting_icon = new /obj/screen/gun/mode(null) + mymob.gun_setting_icon.icon = ui_style + mymob.gun_setting_icon.color = ui_color + mymob.gun_setting_icon.alpha = ui_alpha + //hud_elements |= mymob.gun_setting_icon + + mymob.item_use_icon = new /obj/screen/gun/item(null) + mymob.item_use_icon.icon = ui_style + mymob.item_use_icon.color = ui_color + mymob.item_use_icon.alpha = ui_alpha + + mymob.gun_move_icon = new /obj/screen/gun/move(null) + mymob.gun_move_icon.icon = ui_style + mymob.gun_move_icon.color = ui_color + mymob.gun_move_icon.alpha = ui_alpha + + mymob.radio_use_icon = new /obj/screen/gun/radio(null) + mymob.radio_use_icon.icon = ui_style + mymob.radio_use_icon.color = ui_color + mymob.radio_use_icon.alpha = ui_alpha + + if(ishuman(mymob)) + var/mob/living/carbon/human/H = mymob + H.fov = new /obj/screen() + H.fov.icon = 'icons/mob/hide.dmi' + H.fov.icon_state = "combat" + H.fov.name = " " + H.fov.screen_loc = "1,1" + H.fov.mouse_opacity = 0 + H.fov.plane = VISION_CONE_PLANE + hud_elements |= H.fov + + H.fov_mask = new /obj/screen() + H.fov_mask.icon = 'icons/mob/hide.dmi' + H.fov_mask.icon_state = "combat_mask" + H.fov_mask.name = " " + H.fov_mask.screen_loc = "1,1" + H.fov_mask.mouse_opacity = 0 + H.fov_mask.plane = HIDDEN_SHIT_PLANE + hud_elements |= H.fov_mask + + + H.tracking = new /obj/screen/arrow_to() + H.tracking.owner = H + hud_elements |= H.tracking + + mymob.client.screen = list() + + mymob.client.screen += hud_elements + mymob.client.screen += src.adding + src.hotkeybuttons + src.other + inventory_shown = 1 + +/mob/living/carbon/human/verb/toggle_hotkey_verbs() + set category = "OOC" + set name = "Toggle hotkey buttons" + set desc = "This disables or enables the user interface buttons which can be used with hotkeys." + + if(hud_used.hotkey_ui_hidden) + client.screen += hud_used.hotkeybuttons + hud_used.hotkey_ui_hidden = 0 + else + client.screen -= hud_used.hotkeybuttons + hud_used.hotkey_ui_hidden = 1 + + + +/mob/living/carbon/human/add_filter_effects() + ..() + var/obj/screen/plane_master/vision_cone_target/VC = new //ALWAYS DEFINE THIS, WEIRD SHIT HAPPENS OTHERWISE + var/obj/screen/plane_master/vision_cone/primary/mob = new//creating new masters to remove things from vision. + var/obj/screen/plane_master/vision_cone/primary/lyingmob = new//ditto + var/obj/screen/plane_master/vision_cone/primary/human = new//ditto + var/obj/screen/plane_master/vision_cone/primary/lyinghuman = new//ditto + //var/obj/screen/plane_master/vision_cone/primary + //var/obj/screen/plane_master/vision_cone/primary/aboveturf = new + var/obj/screen/plane_master/vision_cone/inverted/footsteps = new//This master specifically makes it so the footstep stuff ONLY appears where it can't be seen. + + //define what planes the masters dictate. + mob.plane = MOB_PLANE + lyingmob.plane = LYING_MOB_PLANE + human.plane = HUMAN_PLANE + lyinghuman.plane =LYING_HUMAN_PLANE + //aboveturf.plane = ABOVE_TURF_PLANE + footsteps.plane = FOOTSTEP_ALERT_PLANE + + client.screen += VC // Is this necessary? Yes. + client.screen += mob + client.screen += lyingmob + client.screen += human + client.screen += lyinghuman + //client.screen += aboveturf //Comment this out if you don't like it + client.screen += footsteps diff --git a/code/_onclick/hud/movable_screen_objects.dm b/code/_onclick/hud/movable_screen_objects.dm new file mode 100644 index 00000000..faa400ee --- /dev/null +++ b/code/_onclick/hud/movable_screen_objects.dm @@ -0,0 +1,132 @@ + +////////////////////////// +//Movable Screen Objects// +// By RemieRichards // +////////////////////////// + + +//Movable Screen Object +//Not tied to the grid, places it's center where the cursor is + +/obj/screen/movable + var/snap2grid = FALSE + var/moved = FALSE + +//Snap Screen Object +//Tied to the grid, snaps to the nearest turf + +/obj/screen/movable/snap + snap2grid = TRUE + + +/obj/screen/movable/MouseDrop(over_object, src_location, over_location, src_control, over_control, params) + var/list/PM = params2list(params) + + //No screen-loc information? abort. + if(!PM || !PM["screen-loc"]) + return + + //Split screen-loc up into X+Pixel_X and Y+Pixel_Y + var/list/screen_loc_params = splittext(PM["screen-loc"], ",") + + //Split X+Pixel_X up into list(X, Pixel_X) + var/list/screen_loc_X = splittext(screen_loc_params[1],":") + screen_loc_X[1] = encode_screen_X(text2num(screen_loc_X[1])) + //Split Y+Pixel_Y up into list(Y, Pixel_Y) + var/list/screen_loc_Y = splittext(screen_loc_params[2],":") + screen_loc_Y[1] = encode_screen_Y(text2num(screen_loc_Y[1])) + + if(snap2grid) //Discard Pixel Values + screen_loc = "[screen_loc_X[1]],[screen_loc_Y[1]]" + + else //Normalise Pixel Values (So the object drops at the center of the mouse, not 16 pixels off) + var/pix_X = text2num(screen_loc_X[2]) - 16 + var/pix_Y = text2num(screen_loc_Y[2]) - 16 + screen_loc = "[screen_loc_X[1]]:[pix_X],[screen_loc_Y[1]]:[pix_Y]" + +/obj/screen/movable/proc/encode_screen_X(X) + var/view = usr.client ? usr.client.view : world.view + if(X > view+1) + . = "EAST-[view*2 + 1-X]" + else if(X < view+1) + . = "WEST+[X-1]" + else + . = "CENTER" + +/obj/screen/movable/proc/decode_screen_X(X) + var/view = usr.client ? usr.client.view : world.view + //Find EAST/WEST implementations + if(findtext(X,"EAST-")) + var/num = text2num(copytext(X,6)) //Trim EAST- + if(!num) + num = 0 + . = view*2 + 1 - num + else if(findtext(X,"WEST+")) + var/num = text2num(copytext(X,6)) //Trim WEST+ + if(!num) + num = 0 + . = num+1 + else if(findtext(X,"CENTER")) + . = view+1 + +/obj/screen/movable/proc/encode_screen_Y(Y) + var/view = usr.client ? usr.client.view : world.view + if(Y > view+1) + . = "NORTH-[view*2 + 1-Y]" + else if(Y < usr.client.view+1) + . = "SOUTH+[Y-1]" + else + . = "CENTER" + +/obj/screen/movable/proc/decode_screen_Y(Y) + var/view = usr.client ? usr.client.view : world.view + if(findtext(Y,"NORTH-")) + var/num = text2num(copytext(Y,7)) //Trim NORTH- + if(!num) + num = 0 + . = view*2 + 1 - num + else if(findtext(Y,"SOUTH+")) + var/num = text2num(copytext(Y,7)) //Time SOUTH+ + if(!num) + num = 0 + . = num+1 + else if(findtext(Y,"CENTER")) + . = view+1 + +//Debug procs +/client/proc/test_movable_UI() + set category = "Debug" + set name = "Spawn Movable UI Object" + + var/obj/screen/movable/M = new() + M.SetName("Movable UI Object") + M.icon_state = "block" + M.maptext = "Movable" + M.maptext_width = 64 + + var/screen_l = input(usr,"Where on the screen? (Formatted as 'X,Y' e.g: '1,1' for bottom left)","Spawn Movable UI Object") as text + if(!screen_l) + return + + M.screen_loc = screen_l + + screen += M + + +/client/proc/test_snap_UI() + set category = "Debug" + set name = "Spawn Snap UI Object" + + var/obj/screen/movable/snap/S = new() + S.SetName("Snap UI Object") + S.icon_state = "block" + S.maptext = "Snap" + S.maptext_width = 64 + + var/screen_l = input(usr,"Where on the screen? (Formatted as 'X,Y' e.g: '1,1' for bottom left)","Spawn Snap UI Object") as text + if(!screen_l) + return + + S.screen_loc = screen_l + + screen += S diff --git a/code/_onclick/hud/other_mobs.dm b/code/_onclick/hud/other_mobs.dm new file mode 100644 index 00000000..4dd4ff42 --- /dev/null +++ b/code/_onclick/hud/other_mobs.dm @@ -0,0 +1,62 @@ +/mob/living/carbon/slime + hud_type = /datum/hud/slime + +/datum/hud/slime/FinalizeInstantiation(ui_style = 'icons/mob/screen1_Midnight.dmi') + src.adding = list() + + var/obj/screen/using + + using = new /obj/screen/intent() + src.adding += using + action_intent = using + + mymob.client.screen = list() + mymob.client.screen += src.adding + +/mob/living/simple_animal/construct + hud_type = /datum/hud/construct + +/datum/hud/construct/FinalizeInstantiation() + var/constructtype + + if(istype(mymob,/mob/living/simple_animal/construct/armoured) || istype(mymob,/mob/living/simple_animal/construct/behemoth)) + constructtype = "juggernaut" + else if(istype(mymob,/mob/living/simple_animal/construct/builder)) + constructtype = "artificer" + else if(istype(mymob,/mob/living/simple_animal/construct/wraith)) + constructtype = "wraith" + else if(istype(mymob,/mob/living/simple_animal/construct/harvester)) + constructtype = "harvester" + + if(constructtype) + mymob.fire = new /obj/screen() + mymob.fire.icon = 'icons/mob/screen1_construct.dmi' + mymob.fire.icon_state = "fire0" + mymob.fire.SetName("fire") + mymob.fire.screen_loc = ui_construct_fire + + mymob.healths = new /obj/screen() + mymob.healths.icon = 'icons/mob/screen1_construct.dmi' + mymob.healths.icon_state = "[constructtype]_health0" + mymob.healths.SetName("health") + mymob.healths.screen_loc = ui_construct_health + + mymob.pullin = new /obj/screen() + mymob.pullin.icon = 'icons/mob/screen1_construct.dmi' + mymob.pullin.icon_state = "pull0" + mymob.pullin.SetName("pull") + mymob.pullin.screen_loc = ui_construct_pull + + mymob.zone_sel = new /obj/screen/zone_sel() + mymob.zone_sel.icon = 'icons/mob/screen1_construct.dmi' + mymob.zone_sel.overlays.len = 0 + mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]") + + mymob.purged = new /obj/screen() + mymob.purged.icon = 'icons/mob/screen1_construct.dmi' + mymob.purged.icon_state = "purge0" + mymob.purged.SetName("purged") + mymob.purged.screen_loc = ui_construct_purge + + mymob.client.screen = list() + mymob.client.screen += list(mymob.fire, mymob.healths, mymob.pullin, mymob.zone_sel, mymob.purged) diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm new file mode 100644 index 00000000..43726823 --- /dev/null +++ b/code/_onclick/hud/robot.dm @@ -0,0 +1,217 @@ +var/obj/screen/robot_inventory + +/mob/living/silicon/robot + hud_type = /datum/hud/robot + +/datum/hud/robot/FinalizeInstantiation() + + src.adding = list() + src.other = list() + + var/obj/screen/using + +//Radio + using = new /obj/screen() + using.SetName("radio") + using.set_dir(SOUTHWEST) + using.icon = 'icons/mob/screen1_robot.dmi' + using.icon_state = "radio" + using.screen_loc = ui_movi + src.adding += using + +//Module select + + using = new /obj/screen() + using.SetName("module1") + using.set_dir(SOUTHWEST) + using.icon = 'icons/mob/screen1_robot.dmi' + using.icon_state = "inv1" + using.screen_loc = ui_inv1 + src.adding += using + mymob:inv1 = using + + using = new /obj/screen() + using.SetName("module2") + using.set_dir(SOUTHWEST) + using.icon = 'icons/mob/screen1_robot.dmi' + using.icon_state = "inv2" + using.screen_loc = ui_inv2 + src.adding += using + mymob:inv2 = using + + using = new /obj/screen() + using.SetName("module3") + using.set_dir(SOUTHWEST) + using.icon = 'icons/mob/screen1_robot.dmi' + using.icon_state = "inv3" + using.screen_loc = ui_inv3 + src.adding += using + mymob:inv3 = using + +//End of module select + +//Intent + using = new /obj/screen() + using.SetName("act_intent") + using.set_dir(SOUTHWEST) + using.icon = 'icons/mob/screen1_robot.dmi' + using.icon_state = mymob.a_intent + using.screen_loc = ui_acti + src.adding += using + action_intent = using + +//Cell + mymob:cells = new /obj/screen() + mymob:cells.icon = 'icons/mob/screen1_robot.dmi' + mymob:cells.icon_state = "charge-empty" + mymob:cells.SetName("cell") + mymob:cells.screen_loc = ui_toxin + +//Health + mymob.healths = new /obj/screen() + mymob.healths.icon = 'icons/mob/screen1_robot.dmi' + mymob.healths.icon_state = "health0" + mymob.healths.SetName("health") + mymob.healths.screen_loc = ui_borg_health + +//Installed Module + mymob.hands = new /obj/screen() + mymob.hands.icon = 'icons/mob/screen1_robot.dmi' + mymob.hands.icon_state = "nomod" + mymob.hands.SetName("module") + mymob.hands.screen_loc = ui_borg_module + +//Module Panel + using = new /obj/screen() + using.SetName("panel") + using.icon = 'icons/mob/screen1_robot.dmi' + using.icon_state = "panel" + using.screen_loc = ui_borg_panel + src.adding += using + +//Store + mymob.throw_icon = new /obj/screen() + mymob.throw_icon.icon = 'icons/mob/screen1_robot.dmi' + mymob.throw_icon.icon_state = "store" + mymob.throw_icon.SetName("store") + mymob.throw_icon.screen_loc = ui_borg_store + +//Inventory + robot_inventory = new /obj/screen() + robot_inventory.SetName("inventory") + robot_inventory.icon = 'icons/mob/screen1_robot.dmi' + robot_inventory.icon_state = "inventory" + robot_inventory.screen_loc = ui_borg_inventory + +//Temp + mymob.bodytemp = new /obj/screen() + mymob.bodytemp.icon_state = "temp0" + mymob.bodytemp.SetName("body temperature") + mymob.bodytemp.screen_loc = ui_temp + + + mymob.oxygen = new /obj/screen() + mymob.oxygen.icon = 'icons/mob/screen1_robot.dmi' + mymob.oxygen.icon_state = "oxy0" + mymob.oxygen.SetName("oxygen") + mymob.oxygen.screen_loc = ui_oxygen + + mymob.fire = new /obj/screen() + mymob.fire.icon = 'icons/mob/screen1_robot.dmi' + mymob.fire.icon_state = "fire0" + mymob.fire.SetName("fire") + mymob.fire.screen_loc = ui_fire + + mymob.pullin = new /obj/screen() + mymob.pullin.icon = 'icons/mob/screen1_robot.dmi' + mymob.pullin.icon_state = "pull0" + mymob.pullin.SetName("pull") + mymob.pullin.screen_loc = ui_borg_pull + + mymob.zone_sel = new /obj/screen/zone_sel() + mymob.zone_sel.icon = 'icons/mob/screen1_robot.dmi' + mymob.zone_sel.overlays.Cut() + mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]") + + //Handle the gun settings buttons + mymob.gun_setting_icon = new /obj/screen/gun/mode(null) + mymob.item_use_icon = new /obj/screen/gun/item(null) + mymob.gun_move_icon = new /obj/screen/gun/move(null) + mymob.radio_use_icon = new /obj/screen/gun/radio(null) + + mymob.client.screen = list() + mymob.client.screen += list(mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.fire, mymob.hands, mymob.healths, mymob:cells, mymob.pullin, robot_inventory, mymob.gun_setting_icon) + mymob.client.screen += src.adding + src.other + +/datum/hud/proc/toggle_show_robot_modules() + if(!isrobot(mymob)) + return + + var/mob/living/silicon/robot/r = mymob + + r.shown_robot_modules = !r.shown_robot_modules + update_robot_modules_display() + + +/datum/hud/proc/update_robot_modules_display() + if(!isrobot(mymob)) + return + + var/mob/living/silicon/robot/r = mymob + + if(r.shown_robot_modules) + //Modules display is shown + //r.client.screen += robot_inventory //"store" icon + + if(!r.module) + to_chat(usr, "No module selected") + return + + if(!r.module.modules) + to_chat(usr, "Selected module has no modules to select") + return + + if(!r.robot_modules_background) + return + + var/display_rows = -round(-(r.module.modules.len) / 8) + r.robot_modules_background.screen_loc = "CENTER-4:16,SOUTH+1:7 to CENTER+3:16,SOUTH+[display_rows]:7" + r.client.screen += r.robot_modules_background + + var/x = -4 //Start at CENTER-4,SOUTH+1 + var/y = 1 + + //Unfortunately adding the emag module to the list of modules has to be here. This is because a borg can + //be emagged before they actually select a module. - or some situation can cause them to get a new module + // - or some situation might cause them to get de-emagged or something. + if(r.emagged) + if(!(r.module.emag in r.module.modules)) + r.module.modules.Add(r.module.emag) + else + if(r.module.emag in r.module.modules) + r.module.modules.Remove(r.module.emag) + + for(var/atom/movable/A in r.module.modules) + if( (A != r.module_state_1) && (A != r.module_state_2) && (A != r.module_state_3) ) + //Module is not currently active + r.client.screen += A + if(x < 0) + A.screen_loc = "CENTER[x]:[WORLD_ICON_SIZE/2],SOUTH+[y]:7" + else + A.screen_loc = "CENTER+[x]:[WORLD_ICON_SIZE/2],SOUTH+[y]:7" + A.hud_layerise() + + x++ + if(x == 4) + x = -4 + y++ + + else + //Modules display is hidden + //r.client.screen -= robot_inventory //"store" icon + for(var/atom/A in r.module.modules) + if( (A != r.module_state_1) && (A != r.module_state_2) && (A != r.module_state_3) ) + //Module is not currently active + r.client.screen -= A + r.shown_robot_modules = 0 + r.client.screen -= r.robot_modules_background diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm new file mode 100644 index 00000000..4f49f748 --- /dev/null +++ b/code/_onclick/hud/screen_objects.dm @@ -0,0 +1,622 @@ +/* + Screen objects + Todo: improve/re-implement + + Screen objects are only used for the hud and should not appear anywhere "in-game". + They are used with the client/screen list and the screen_loc var. + For more information, see the byond documentation on the screen_loc and screen vars. +*/ +/obj/screen + name = "" + icon = 'icons/mob/screen1.dmi' + plane = HUD_PLANE + layer = HUD_BASE_LAYER + appearance_flags = NO_CLIENT_COLOR + unacidable = 1 + var/obj/master = null //A reference to the object in the slot. Grabs or items, generally. + var/globalscreen = FALSE //Global screens are not qdeled when the holding mob is destroyed. + +/obj/screen/Destroy() + master = null + return ..() + +/obj/screen/text + icon = null + icon_state = null + mouse_opacity = 0 + screen_loc = "CENTER-7,CENTER-7" + maptext_height = 480 + maptext_width = 480 + + +/obj/screen/inventory + var/slot_id //The indentifier for the slot. It has nothing to do with ID cards. + + +/obj/screen/close + name = "close" + +/obj/screen/close/Click() + if(master) + if(istype(master, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = master + S.close(usr) + return 1 + + +/obj/screen/item_action + var/obj/item/owner + +/obj/screen/item_action/Destroy() + ..() + owner = null + +/obj/screen/item_action/Click() + if(!usr || !owner) + return 1 + if(!usr.canClick()) + return + + if(usr.stat || usr.restrained() || usr.stunned || usr.lying) + return 1 + + if(!(owner in usr)) + return 1 + + owner.ui_action_click() + return 1 + +/obj/screen/storage + name = "storage" + +/obj/screen/storage/Click() + if(!usr.canClick()) + return 1 + if(usr.stat || usr.paralysis || usr.stunned || usr.weakened) + return 1 + if (istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech + return 1 + if(master) + var/obj/item/I = usr.get_active_hand() + if(I) + usr.ClickOn(master) + return 1 + +/obj/screen/happiness_icon/Click() + var/mob/living/carbon/C = usr + C.print_happiness(C) + + +/obj/screen/combat_intents + name = "Combat Intents" + icon = 'icons/mob/screen/combat_intents.dmi' + icon_state = "feint" + var/current_intent = I_FEINT + var/choosing_intent = FALSE + + +/obj/screen/combat_intents/Click(location, control,params) + var/list/PL = params2list(params) + var/icon_x = text2num(PL["icon-x"]) + var/icon_y = text2num(PL["icon-y"]) + var/old_intent = current_intent //We're only going to update_icon() if there's been a change + + if(!choosing_intent) + var/image/cstyle = image(icon = 'icons/mob/screen/cstyle.dmi', icon_state = "cystle") + cstyle.pixel_x-=16 + cstyle.pixel_y+=32 + overlays += cstyle + choosing_intent = TRUE + + else + switch(icon_x) + if(4 to 29) + switch(icon_y) + if(33 to 39) + current_intent = I_FEINT + if(40 to 46) + current_intent = I_DUAL + if(47 to 53) + current_intent = I_GUARD + if(54 to 60) + current_intent = I_DEFENSE + if(61 to 67) + current_intent = I_OFFENSE + if(68 to 74) + current_intent = I_QUICK + if(75 to 81) + current_intent = I_AIMED + if(82 to 88) + current_intent = I_WEAK + overlays.Cut() + choosing_intent = FALSE + if(old_intent != current_intent) + update_icon() + + +/obj/screen/combat_intents/update_icon() + switch(current_intent) + if(I_FEINT) + usr.atk_intent = I_FEINT + icon_state = "feint" + to_chat(usr, "Right click to perform a feint attack. If successful it will block them from attacking you briefly.") + if(I_DEFENSE) + usr.atk_intent = I_DEFENSE + icon_state = "defend" + to_chat(usr, "Your dodge and parry abilities are now greatly heightend, at the cost of reduced damage output.") + if(I_DUAL) + usr.atk_intent = I_DUAL + icon_state = "dual" + to_chat(usr, "Right click to melee attack with the item in your offhand. You will be less accurate though.") + if(I_OFFENSE) + usr.atk_intent = I_OFFENSE + icon_state = "strong" + to_chat(usr, "Right click to perform a strong attack. You will hit for maximum damage, but the attack is slow, and costs stamina.") + if(I_QUICK) + usr.atk_intent = I_QUICK + icon_state = "quick" + to_chat(usr, "Right click to attack very quickly, it costs more stamina though.") + if(I_WEAK) + usr.atk_intent = I_WEAK + icon_state = "weak" + to_chat(usr, "Right click to attack for the least amount of damage possible. Use it for hitting your friends.") + if(I_GUARD) + usr.atk_intent = I_GUARD + icon_state = "guard" + to_chat(usr, "You will now automatically riposte any attack you successfully parry, but you will do less damage.") + if(I_AIMED) + usr.atk_intent = I_AIMED + icon_state = "aimed" + to_chat(usr, "You won't miss any attack attempt, but it will cost you more stamina.") + + + +/obj/screen/zone_sel + name = "damage zone" + icon_state = "zone_sel" + screen_loc = ui_zonesel + var/selecting = BP_CHEST + +/obj/screen/zone_sel/Click(location, control,params) + var/list/PL = params2list(params) + var/icon_x = text2num(PL["icon-x"]) + var/icon_y = text2num(PL["icon-y"]) + var/old_selecting = selecting //We're only going to update_icon() if there's been a change + + switch(icon_y) + if(5 to 8) //Feet + switch(icon_x) + if(7 to 15) + selecting = BP_R_FOOT + if(18 to 26) + selecting = BP_L_FOOT + else + return 1 + if(9 to 27) //Legs + switch(icon_x) + if(10 to 16) + selecting = BP_R_LEG + if(18 to 23) + selecting = BP_L_LEG + else + return 1 + if(28 to 34) //Hands and groin + switch(icon_x) + if(4 to 8) + selecting = BP_R_HAND + if(12 to 21) + selecting = BP_GROIN + if(24 to 29) + selecting = BP_L_HAND + else + return 1 + if(31 to 49) //Chest and arms to shoulders + switch(icon_x) + if(7 to 11) + selecting = BP_R_ARM + if(12 to 21) + selecting = BP_CHEST + if(22 to 26) + selecting = BP_L_ARM + else + return 1 + + if(50 to 52)//Neck + switch(icon_x) + if(14 to 19) + selecting = BP_THROAT + + if(53 to 60) //Head, but we need to check for eye or mouth + switch(icon_x) + if(10 to 23) + selecting = BP_HEAD + if(69 to 72) + switch(icon_x) + if(13 to 20) + selecting = BP_MOUTH + + //if(77 to 81) + // switch(icon_x) + // if(11 to 22) + // selecting = BP_EYES + + + if(old_selecting != selecting) + update_icon() + return 1 + +/obj/screen/zone_sel/proc/set_selected_zone(bodypart) + var/old_selecting = selecting + selecting = bodypart + if(old_selecting != selecting) + update_icon() + +/obj/screen/zone_sel/update_icon() + overlays.Cut() + overlays += image('icons/mob/zone_sel_newer.dmi', "[selecting]") + +/obj/screen/intent + name = "intent" + icon_state = "intent_help" + screen_loc = ui_drop_throw//ui_acti + var/intent = I_HELP + +/obj/screen/intent/Click(var/location, var/control, var/params) + var/list/P = params2list(params) + var/icon_x = text2num(P["icon-x"]) + var/icon_y = text2num(P["icon-y"]) + intent = I_DISARM + if(icon_x <= world.icon_size/2) + if(icon_y <= world.icon_size/2) + intent = I_HURT + else + intent = I_HELP + else if(icon_y <= world.icon_size/2) + intent = I_GRAB + update_icon() + usr.a_intent = intent + +/obj/screen/intent/update_icon() + icon_state = "intent_[intent]" + +/obj/screen/Click(location, control, params) + if(!usr) return 1 + var/list/modifiers = params2list(params) + if(modifiers["right"]) + switch(name) + if("fixeye") + var/mob/living/carbon/human/HHH = usr + HHH.lookup() + if("health") + var/mob/living/carbon/human/HHHH = usr + HHHH.check_skills() + return 1 + + + switch(name) + if("other") + if(usr.hud_used.inventory_shown) + usr.hud_used.inventory_shown = 0 + usr.client.screen -= usr.hud_used.other + else + usr.hud_used.inventory_shown = 1 + usr.client.screen += usr.hud_used.other + + usr.hud_used.hidden_inventory_update() + + if("equip") + if (istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech + return 1 + if(ishuman(usr)) + var/mob/living/carbon/human/H = usr + H.quick_equip() + + if("resist") + if(isliving(usr)) + var/mob/living/L = usr + L.resist() + + if("mov_intent") + switch(usr.m_intent) + if("run") + usr.m_intent = "walk" + usr.hud_used.move_intent.icon_state = "walking" + if("walk") + usr.m_intent = "run" + usr.hud_used.move_intent.icon_state = "running" + + if("Reset Machine") + usr.unset_machine() + + if("health") + if(ishuman(usr)) + var/mob/living/carbon/human/X = usr + X.exam_self() + + if("surrender") + if(ishuman(usr)) + var/mob/living/carbon/human/S = usr + S.surrender() + + if("internal") + if(iscarbon(usr)) + var/mob/living/carbon/C = usr + if(!C.stat && !C.stunned && !C.paralysis && !C.restrained()) + if(C.internal) + C.internal = null + to_chat(C, SPAN_NOTICE("No longer running on internals.")) + if(C.internals) + C.internals.icon_state = "internal0" + else + + var/no_mask + if(!(C.wear_mask && C.wear_mask.item_flags & ITEM_FLAG_AIRTIGHT)) + var/mob/living/carbon/human/H = C + if(!(H.head && H.head.item_flags & ITEM_FLAG_AIRTIGHT)) + no_mask = 1 + + if(no_mask) + to_chat(C, SPAN_NOTICE("You are not wearing a suitable mask or helmet.")) + return 1 + else + var/list/nicename = null + var/list/tankcheck = null + var/breathes = "oxygen" //default, we'll check later + var/list/contents = list() + var/from = "on" + + if(ishuman(C)) + var/mob/living/carbon/human/H = C + breathes = H.species.breath_type + nicename = list ("suit", "back", "belt", "right hand", "left hand", "left pocket", "right pocket") + tankcheck = list (H.s_store, C.back, H.belt, C.r_hand, C.l_hand, H.l_store, H.r_store) + else + nicename = list("right hand", "left hand", "back") + tankcheck = list(C.r_hand, C.l_hand, C.back) + + for(var/i=1, i bestcontents) + best = i + bestcontents = contents[i] + + + //We've determined the best container now we set it as our internals + + if(best) + to_chat(C, "You are now running on internals from [tankcheck[best]] [from] your [nicename[best]].") + playsound(C, 'sound/effects/internals.ogg', 50, 0) + C.internal = tankcheck[best] + + + if(C.internal) + if(C.internals) + C.internals.icon_state = "internal1" + else + to_chat(C, "You don't have a[breathes=="oxygen" ? "n oxygen" : addtext(" ",breathes)] tank.") + if("act_intent") + usr.a_intent_change("right") + + if("pull") + usr.stop_pulling() + + if("rest") + usr.mob_rest() + + if("throw") + if(!usr.stat && isturf(usr.loc) && !usr.restrained()) + usr:toggle_throw_mode() + if("drop") + if(usr.client) + usr.client.drop_item() + if("wield") + if(!ishuman(usr)) return + var/mob/living/carbon/human/HH = usr + HH.do_wield() + if("kick") + if(usr.middle_click_intent == "kick") + usr.middle_click_intent = null + usr.kick_icon.icon_state = "kick" + else + usr.middle_click_intent = "kick" + usr.kick_icon.icon_state = "kick_on" + usr.jump_icon.icon_state = "jump"//Holy fuck that's a convoluted way to deal with that. I'll make a better method later. + if("jump") + if(usr.middle_click_intent == "jump") + usr.middle_click_intent = null + usr.jump_icon.icon_state = "jump" + else + usr.middle_click_intent = "jump" + usr.jump_icon.icon_state = "jump_on" + usr.kick_icon.icon_state = "kick" + if("combat mode") + usr.client.CombatModeToggle() + + if("combat intent") + if(ishuman(usr)) + var/mob/living/carbon/human/E = usr + if(E.defense_intent == I_PARRY) + E.defense_intent = I_DODGE + E.combat_intent_icon.icon_state = "dodge" + else + E.defense_intent = I_PARRY + E.combat_intent_icon.icon_state = "parry" + /* + //atk_intents here: + if("quick") + usr.atk_intent = I_QUICK + usr.hud_used.atk_intent.icon_state = "quick" + + if("aimed") + usr.atk_intent = I_AIMED + usr.hud_used.atk_intent.icon_state = "aimed" + + if("defense") + usr.atk_intent = I_DEFENSE + usr.hud_used.atk_intent.icon_state = "defense" + + if("offense") + usr.atk_intent = I_OFFENSE + usr.hud_used.atk_intent.icon_state = "offense" + */ + + if("fixeye") + usr.face_direction() + + if("mood") + var/mob/living/carbon/C = usr + C.print_happiness(C) + + if("module") + if(isrobot(usr)) + var/mob/living/silicon/robot/R = usr + R.pick_module() + + if("inventory") + if(isrobot(usr)) + var/mob/living/silicon/robot/R = usr + if(R.module) + R.hud_used.toggle_show_robot_modules() + return 1 + else + to_chat(R, "You haven't selected a module yet.") + + if("radio") + if(issilicon(usr)) + usr:radio_menu() + if("panel") + if(issilicon(usr)) + usr:installed_modules() + + if("store") + if(isrobot(usr)) + var/mob/living/silicon/robot/R = usr + if(R.module) + R.uneq_active() + R.hud_used.update_robot_modules_display() + else + to_chat(R, "You haven't selected a module yet.") + + if("module1") + if(istype(usr, /mob/living/silicon/robot)) + usr:toggle_module(1) + + if("module2") + if(istype(usr, /mob/living/silicon/robot)) + usr:toggle_module(2) + + if("module3") + if(istype(usr, /mob/living/silicon/robot)) + usr:toggle_module(3) + else + return 0 + return 1 + +/obj/screen/inventory/Click() + // At this point in client Click() code we have passed the 1/10 sec check and little else + // We don't even know if it's a middle click + if(!usr.canClick()) + return 1 + if(usr.stat || usr.paralysis || usr.stunned) + return 1 + if (istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech + return 1 + switch(name) + if("r_hand") + if(iscarbon(usr)) + var/mob/living/carbon/C = usr + C.activate_hand("r") + if("l_hand") + if(iscarbon(usr)) + var/mob/living/carbon/C = usr + C.activate_hand("l") + if("swap") + usr:swap_hand() + if("hand") + usr:swap_hand() + + else + if(usr.attack_ui(slot_id)) + usr.update_inv_l_hand(0) + usr.update_inv_r_hand(0) + return 1 + +/obj/screen/arrow_to + name = "tracking" + icon_state = "arrow_to" + screen_loc = "CENTER, CENTER" + invisibility = 100 + var/angle + var/mob/owner + var/atom/target + var/atom/last_target + +/obj/screen/arrow_to/proc/track(var/mob/T) + if(T == target) + return + last_target = target + target = T + invisibility = 0 + update() + spawn(3 MINUTES) + end_tracking(T) + +/obj/screen/arrow_to/proc/update() + + if(!target) + return + + var/turf/O = get_turf(owner) + var/turf/T = get_turf(target) + var/target_angle = Get_Angle(O, T) + var/difference = target_angle - angle + angle = target_angle + var/matrix/final = matrix(transform) + + final.Turn(difference) + + animate(src, transform = final, time = 5, loop = 0) + +/obj/screen/arrow_to/proc/end_tracking(var/mob/T) + if(T == last_target) + return // target has changed + target = null + invisibility = 100 diff --git a/code/_onclick/hud/skybox.dm b/code/_onclick/hud/skybox.dm new file mode 100644 index 00000000..93b4a3a0 --- /dev/null +++ b/code/_onclick/hud/skybox.dm @@ -0,0 +1,70 @@ +/obj/skybox + name = "skybox" + mouse_opacity = 0 + blend_mode = BLEND_MULTIPLY + plane = SKYBOX_PLANE +// invisibility = 101 + anchored = 1 + var/mob/owner + var/image/image + var/image/stars + +/obj/skybox/Initialize() + . = ..() + var/mob/M = loc + SSskybox.skyboxes += src + owner = M + loc = null + SSskybox.skyboxes += src + image = image('icons/turf/skybox.dmi', src, "background_[SSskybox.BGstate]") + overlays += image + DoRotate() + update() + +/obj/skybox/proc/update() + if(isnull(owner) || isnull(owner.client)) + qdel(src) + else + var/turf/T = get_turf(owner.client.eye) + screen_loc = "CENTER:[-224-(T&&T.x)],CENTER:[-224-(T&&T.y)]" + +/obj/skybox/proc/DoRotate() + var/matrix/rotation = matrix() + rotation.TurnTo(SSskybox.BGrot) + appearance = rotation + +/obj/skybox/Destroy() + overlays.Cut() + if(owner) + if(owner.skybox == src) + owner.skybox = null + owner = null + image = null + SSskybox.skyboxes -= src + return ..() + +/mob + var/obj/skybox/skybox + +/mob/Move() + . = ..() + if(. && skybox) + skybox.update() + +/mob/forceMove() + . = ..() + if(. && skybox) + skybox.update() + +/mob/Login() + if(!skybox) + skybox = new(src) + skybox.owner = src + client.screen += skybox + ..() + +/mob/Destroy() + if(client) + client.screen -= skybox + QDEL_NULL(skybox) + return ..() \ No newline at end of file diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm new file mode 100644 index 00000000..67fedc1c --- /dev/null +++ b/code/_onclick/item_attack.dm @@ -0,0 +1,193 @@ +/* +=== 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, var/click_params) + if(item_flags & ITEM_FLAG_ABSTRACT)//Abstract items cannot be interacted with. They're not real. + return + if(!(item_flags & ITEM_FLAG_NO_PRINT)) + add_fingerprint(user) + return A.attackby(src, user, click_params) + +// No comment +/atom/proc/attackby(obj/item/W, mob/user, var/click_params) + return + +/atom/movable/attackby(obj/item/W, mob/user) + if(!(W.item_flags & ITEM_FLAG_NO_BLUDGEON)) + 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,user) && I.do_surgery(src,user)) //Surgery + return 1 + return I.attack(src, user, user.zone_sel.selecting, FALSE) + +/mob/living/carbon/human/attackby(obj/item/I, mob/user) + if(user == src && src.a_intent == I_DISARM && src.zone_sel.selecting == "mouth") + var/obj/item/blocked = src.check_mouth_coverage() + if(blocked) + to_chat(user, "\The [blocked] is in the way!") + return 1 + else if(devour(I)) + return 1 + return ..() + +// 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. +//The "special" arg is there for special attacks, it's present the entire way down the chain so if you ever want to put a sepcial attack +//anywhere in the code, then check for special and then write you special affects. +/obj/item/proc/attack(mob/living/M, mob/living/user, var/target_zone, var/special = FALSE) + var/offhand_attack = FALSE + if(!force || (item_flags & ITEM_FLAG_NO_BLUDGEON)) + return 0 + if(ticker.current_state == GAME_STATE_FINISHED) + to_chat(user, "The battle is over! There is no need to fight!") + return 0 + if(M == user && user.a_intent != I_HURT) + return 0 + + if(user.staminaloss >= user.staminaexhaust)//Can't attack people if you're out of stamina. + return 0 + + if(world.time <= next_attack_time) + if(world.time % 3) //to prevent spam + to_chat(user, "The [src] is not ready to attack again!") + return 0 + + if(!user.combat_mode) + special = FALSE + + if(M == user)//Hitting yourself. + user.unlock_achievement(new/datum/achievement/miss()) + + if(special)//We did a special attack, let's apply it's special properties. + switch(user.atk_intent) + if(I_QUICK)//Faster attack but takes much more stamina. + user.visible_message("[user] performs a quick attack!") + user.adjustStaminaLoss(w_class + 6) + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + apply_speed_delay(-5) + + if(I_AIMED)//More accurate attack + user.visible_message("[user] performs an aimed attack!") + user.adjustStaminaLoss(w_class + 5) + user.setClickCooldown(DEFAULT_SLOW_COOLDOWN) + apply_speed_delay(5) + + if(I_FEINT)//Feint attack that leaves them unable to attack for a few seconds //I_FEINT + if(!prob(user.SKILL_LEVEL(melee) * 10))//Add skill check here. + user.visible_message("[user] botches a feint attack!") + return 0 + user.adjustStaminaLoss(w_class + 5) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + M.setClickCooldown(DEFAULT_SLOW_COOLDOWN) + apply_speed_delay(0) + user.visible_message("[user] performs a successful feint attack!") + return 0 //We fiented them don't actaully hit them now, we can follow up with another attack. + + if(I_OFFENSE)//Attack with stronger damage at the cost slightly longer cooldown + user.visible_message("[user] performs a heavy attack!") + user.adjustStaminaLoss(w_class + 5) + user.setClickCooldown(DEFAULT_SLOW_COOLDOWN) + apply_speed_delay(6) + + if(I_WEAK) + user.visible_message("[user] performs a weak attack.") + + if(I_DUAL) + user.visible_message("[user] attacks with their offhand!") + offhand_attack = TRUE + apply_speed_delay(3) + + + ///////////////////////// + + if(!no_attack_log) + admin_attack_log(user, M, "Attacked using \a [src] (DAMTYE: [uppertext(damtype)])", "Was attacked with \a [src] (DAMTYE: [uppertext(damtype)])", "used \a [src] (DAMTYE: [uppertext(damtype)]) to attack") + + if(ishuman(user) && ishuman(M)) + var/mob/living/carbon/human/attacker = user + var/mob/living/carbon/human/victim = M + if(attacker != victim) + if(attacker.warfare_faction) + if(attacker.warfare_faction == victim.warfare_faction && victim.stat != DEAD) + to_chat(attacker, "[victim] is on my side!") + log_and_message_admins("[attacker] has hit his teammate [victim] with \a [src]!") + GLOB.ff_incidents++ + ///////////////////////// + + if(!special) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + + //user.do_attack_animation(M) + if(!user.aura_check(AURA_TYPE_WEAPON, src, user)) + return 0 + + if(force && !special) + user.adjustStaminaLoss(w_class + 3) + if(swing_sound) + playsound(user, swing_sound, 50, 1, -1) + + if(offhand_attack) + var/obj/item/I = user.get_inactive_hand() + if(I) + var/offhand_hit_zone = M.resolve_item_attack(I, user, target_zone, special) + if(offhand_hit_zone) + I.apply_hit_effect(M, user, offhand_hit_zone, special) + else + visible_message("[user] has nothing in their offhand to attack with!") + + else + var/hit_zone = M.resolve_item_attack(src, user, target_zone, special) + if(hit_zone) + apply_hit_effect(M, user, hit_zone, special) + + if(!special) + apply_speed_delay(0) + return 1 + + +//by default, that's 25 - 10. Which is 15. Which should be what the average attack is. People who are weaker will swing heavy objects slower. +//The "delay" arg is for adding a greater or lesser delay from special attacks. +/obj/item/proc/apply_speed_delay(delay) + next_attack_time = world.time + (weapon_speed_delay + delay) + + +//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, var/special = FALSE) + 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, special) + diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm new file mode 100644 index 00000000..a6c92640 --- /dev/null +++ b/code/_onclick/other_mobs.dm @@ -0,0 +1,166 @@ +// Generic damage proc (slimes and monkeys). +/atom/proc/attack_generic(mob/user as mob) + return 0 + +/* + Humans: + Adds an exception for gloves, to allow special glove types like the ninja ones. + + Otherwise pretty standard. +*/ +/mob/living/carbon/human/UnarmedAttack(var/atom/A, var/proximity) + + if(!..()) + return + + // Special glove functions: + // If the gloves do anything, have them return 1 to stop + // normal attack_hand() here. + var/obj/item/clothing/gloves/G = gloves // not typecast specifically enough in defines + if(istype(G) && G.Touch(A,1)) + return + + A.attack_hand(src) + +/atom/proc/attack_hand(mob/user as mob) + return + +/mob/living/carbon/human/RestrainedClickOn(var/atom/A) + return + +/mob/living/carbon/human/RangedAttack(var/atom/A) + //Climbing up open spaces + if((istype(A, /turf/simulated/floor) || istype(A, /turf/unsimulated/floor) || istype(A, /obj/structure/lattice) || istype(A, /obj/structure/catwalk)) && isturf(loc) && shadow && !is_physically_disabled()) //Climbing through openspace + var/turf/T = get_turf(A) + var/turf/above = shadow.loc + if(T.Adjacent(shadow) && above.CanZPass(src, UP)) //Certain structures will block passage from below, others not + + var/area/location = get_area(loc) + if(location.has_gravity && !can_overcome_gravity()) + return + + visible_message("[src] starts climbing onto \the [A]!", "You start climbing onto \the [A]!") + shadow.visible_message("[shadow] starts climbing onto \the [A]!") + if(do_after(src, 50, A)) + visible_message("[src] climbs onto \the [A]!", "You climb onto \the [A]!") + shadow.visible_message("[shadow] climbs onto \the [A]!") + src.Move(T) + else + visible_message("[src] gives up on trying to climb onto \the [A]!", "You give up on trying to climb onto \the [A]!") + shadow.visible_message("[shadow] gives up on trying to climb onto \the [A]!") + return + + if(!gloves && !mutations.len) return + var/obj/item/clothing/gloves/G = gloves + if((LASER in mutations) && a_intent == I_HURT) + LaserEyes(A) // moved into a proc below + + else if(istype(G) && G.Touch(A,0)) // for magic gloves + return + + else if(TK in mutations) + A.attack_tk(src) + +/mob/living/RestrainedClickOn(var/atom/A) + return + +/* + Aliens +*/ + +/mob/living/carbon/alien/RestrainedClickOn(var/atom/A) + return + +/mob/living/carbon/alien/UnarmedAttack(var/atom/A, var/proximity) + + if(!..()) + return 0 + + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + A.attack_generic(src,rand(5,6),"bitten") + +/* + Slimes + Nothing happening here +*/ + +/mob/living/carbon/slime/RestrainedClickOn(var/atom/A) + return + +/mob/living/carbon/slime/UnarmedAttack(var/atom/A, var/proximity) + + if(!..()) + return + + // Eating + if(Victim) + if (Victim == A) + Feedstop() + return + + //should have already been set if we are attacking a mob, but it doesn't hurt and will cover attacking non-mobs too + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + var/mob/living/M = A + if(!istype(M)) + A.attack_generic(src, (is_adult ? rand(20,40) : rand(5,25)), "glomped") // Basic attack. + else + var/power = max(0, min(10, (powerlevel + rand(0, 3)))) + + switch(src.a_intent) + if (I_HELP) // We just poke the other + M.visible_message("[src] gently pokes [M]!", "[src] gently pokes you!") + if (I_DISARM) // We stun the target, with the intention to feed + var/stunprob = 1 + + if (powerlevel > 0 && !istype(A, /mob/living/carbon/slime)) + switch(power * 10) + if(0) stunprob *= 10 + if(1 to 2) stunprob *= 20 + if(3 to 4) stunprob *= 30 + if(5 to 6) stunprob *= 40 + if(7 to 8) stunprob *= 60 + if(9) stunprob *= 70 + if(10) stunprob *= 95 + + if(prob(stunprob)) + var/shock_damage = max(0, powerlevel-3) * rand(6,10) + M.electrocute_act(shock_damage, src, 1.0, ran_zone()) + else if(prob(40)) + M.visible_message("[src] has pounced at [M]!", "[src] has pounced at you!") + M.Weaken(power) + else + M.visible_message("[src] has tried to pounce at [M]!", "[src] has tried to pounce at you!") + M.updatehealth() + if (I_GRAB) // We feed + Wrap(M) + if (I_HURT) // Attacking + if(iscarbon(M) && prob(15)) + M.visible_message("[src] has pounced at [M]!", "[src] has pounced at you!") + M.Weaken(power) + else + A.attack_generic(src, (is_adult ? rand(20,40) : rand(5,25)), "glomped") + +/* + New Players: + Have no reason to click on anything at all. +*/ +/mob/new_player/ClickOn() + return + +/* + Animals +*/ +/mob/living/simple_animal/UnarmedAttack(var/atom/A, var/proximity) + + if(!..()) + return + if(istype(A,/mob/living)) + if(melee_damage_upper == 0) + custom_emote(1,"[friendly] [A]!") + return + if(ckey) + admin_attack_log(src, A, "Has [attacktext] its victim.", "Has been [attacktext] by its attacker.", attacktext) + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + var/damage = rand(melee_damage_lower, melee_damage_upper) + if(A.attack_generic(src,damage,attacktext,environment_smash) && loc && attack_sound) + playsound(loc, attack_sound, 50, 1, 1) \ No newline at end of file diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm new file mode 100644 index 00000000..c74c7ea2 --- /dev/null +++ b/code/_onclick/telekinesis.dm @@ -0,0 +1,171 @@ +/* + Telekinesis + + This needs more thinking out, but I might as well. +*/ +var/const/tk_maxrange = 15 + +/* + Telekinetic attack: + + By default, emulate the user's unarmed attack +*/ +/atom/proc/attack_tk(mob/user) + if(user.stat) return + user.UnarmedAttack(src,0) // attack_hand, attack_paw, etc + return + +/* + This is similar to item attack_self, but applies to anything + that you can grab with a telekinetic grab. + + It is used for manipulating things at range, for example, opening and closing closets. + There are not a lot of defaults at this time, add more where appropriate. +*/ +/atom/proc/attack_self_tk(mob/user) + return + +/obj/attack_tk(mob/user) + if(user.stat) return + if(anchored) + ..() + return + + var/obj/item/tk_grab/O = new(src) + user.put_in_active_hand(O) + O.host = user + O.focus_object(src) + return + +/obj/item/attack_tk(mob/user) + if(user.stat || !isturf(loc)) return + if((TK in user.mutations) && !user.get_active_hand()) // both should already be true to get here + var/obj/item/tk_grab/O = new(src) + user.put_in_active_hand(O) + O.host = user + O.focus_object(src) + else + warning("Strange attack_tk(): TK([TK in user.mutations]) empty hand([!user.get_active_hand()])") + return + + +/mob/attack_tk(mob/user) + return // needs more thinking about + +/* + TK Grab Item (the workhorse of old TK) + + * If you have not grabbed something, do a normal tk attack + * If you have something, throw it at the target. If it is already adjacent, do a normal attackby() + * If you click what you are holding, or attack_self(), do an attack_self_tk() on it. + * Deletes itself if it is ever not in your hand, or if you should have no access to TK. +*/ +/obj/item/tk_grab + name = "Telekinetic Grab" + desc = "Magic." + icon = 'icons/obj/magic.dmi'//Needs sprites + icon_state = "2" + item_flags = ITEM_FLAG_NO_BLUDGEON + //item_state = null + w_class = ITEM_SIZE_NO_CONTAINER + + var/last_throw = 0 + var/atom/movable/focus = null + var/mob/living/host = null + plane = HUD_PLANE + layer = HUD_ITEM_LAYER + +/obj/item/tk_grab/dropped(mob/user as mob) + if(focus && user && loc != user && loc != user.loc) // drop_item() gets called when you tk-attack a table/closet with an item + if(focus.Adjacent(loc)) + focus.loc = loc + loc = null + spawn(1) + qdel(src) + return + +//stops TK grabs being equipped anywhere but into hands +/obj/item/tk_grab/equipped(var/mob/user, var/slot) + ..() + if( (slot == slot_l_hand) || (slot== slot_r_hand) ) return + qdel(src) + return + +/obj/item/tk_grab/attack_self(mob/user as mob) + if(focus) + focus.attack_self_tk(user) + +/obj/item/tk_grab/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, proximity)//TODO: go over this + if(!target || !user) return + if(last_throw+3 > world.time) return + if(!host || host != user) + qdel(src) + return + if(!(TK in host.mutations)) + qdel(src) + return + if(isobj(target) && !isturf(target.loc)) + return + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + var/d = get_dist(user, target) + if(focus) + d = max(d, get_dist(user, focus)) // whichever is further + if(d > tk_maxrange) + to_chat(user, "Your mind won't reach that far.") + return + + if(!focus) + focus_object(target, user) + return + + if(target == focus) + target.attack_self_tk(user) + return // todo: something like attack_self not laden with assumptions inherent to attack_self + + + if(!istype(target, /turf) && istype(focus,/obj/item) && target.Adjacent(focus)) + var/obj/item/I = focus + var/resolved = target.attackby(I, user, user:get_organ_target()) + if(!resolved && target && I) + I.afterattack(target,user,1) // for splashing with beakers + else + apply_focus_overlay() + focus.throw_at(target, 10, 1, user) + last_throw = world.time + return + +/obj/item/tk_grab/attack(mob/living/M as mob, mob/living/user as mob, def_zone) + return + + +/obj/item/tk_grab/proc/focus_object(var/obj/target, var/mob/living/user) + if(!istype(target,/obj)) return//Cant throw non objects atm might let it do mobs later + if(target.anchored || !isturf(target.loc)) + qdel(src) + return + focus = target + update_icon() + apply_focus_overlay() + return + +/obj/item/tk_grab/proc/apply_focus_overlay() + if(!focus) return + var/obj/effect/overlay/O = new /obj/effect/overlay(locate(focus.x,focus.y,focus.z)) + O.SetName("sparkles") + O.anchored = 1 + O.set_density(0) + O.layer = FLY_LAYER + O.set_dir(pick(GLOB.cardinal)) + O.icon = 'icons/effects/effects.dmi' + O.icon_state = "nothing" + flick("empdisable",O) + spawn(5) + qdel(O) + return + +/obj/item/tk_grab/update_icon() + overlays.Cut() + if(focus && focus.icon && focus.icon_state) + overlays += icon(focus.icon,focus.icon_state) + return diff --git a/code/client_macros.dm b/code/client_macros.dm new file mode 100644 index 00000000..e3ba319b --- /dev/null +++ b/code/client_macros.dm @@ -0,0 +1,39 @@ +/client + control_freak = CONTROL_FREAK_ALL //| CONTROL_FREAK_MACROS | CONTROL_FREAK_SKIN + +var/list/registered_macros_by_ckey_ + +// Disables click and double-click macros, as per http://www.byond.com/forum/?post=2219001 +/mob/verb/DisableClick(argu = null as anything, sec = "" as text,number1 = 0 as num, number2 = 0 as num) + set name = ".click" + set category = null + log_macro(ckey, ".click") + +/mob/verb/DisableDblClick(argu = null as anything, sec = "" as text, number1 = 0 as num, number2 = 0 as num) + set name = ".dblclick" + set category = null + log_macro(ckey, ".dblclick") + +/proc/log_macro(var/ckey, var/macro) + to_chat(usr, "The [macro] macro is disabled due to potential exploits.") + if(is_macro_use_registered(ckey, macro)) + return + register_macro_use(ckey, macro) + log_and_message_admins("attempted to use the disabled [macro] macro.") + +/proc/get_registered_macros() + if(!registered_macros_by_ckey_) + registered_macros_by_ckey_ = list() + return registered_macros_by_ckey_ + +/proc/is_macro_use_registered(var/ckey, var/macro) + var/list/registered_macros = get_registered_macros()[ckey] + return registered_macros && (macro in registered_macros) + +/proc/register_macro_use(var/ckey, var/macro) + var/list/registered_macros_by_ckey = get_registered_macros() + var/list/registered_macros = registered_macros_by_ckey[ckey] + if(!registered_macros) + registered_macros = list() + registered_macros_by_ckey[ckey] = registered_macros + registered_macros |= macro diff --git a/code/controllers/ProcessScheduler/.gitignore b/code/controllers/ProcessScheduler/.gitignore new file mode 100644 index 00000000..5fe19e42 --- /dev/null +++ b/code/controllers/ProcessScheduler/.gitignore @@ -0,0 +1,6 @@ +/bower_components +/node_modules +/ProcessScheduler.dmb +/ProcessScheduler.int +/ProcessScheduler.rsc +/*.lk diff --git a/code/controllers/ProcessScheduler/LICENSE-AGPL b/code/controllers/ProcessScheduler/LICENSE-AGPL new file mode 100644 index 00000000..abaa41e8 --- /dev/null +++ b/code/controllers/ProcessScheduler/LICENSE-AGPL @@ -0,0 +1,212 @@ +GNU AFFERO GENERAL PUBLIC LICENSE + +Version 3, 19 November 2007 + +Copyright © 2007 Free Software Foundation, Inc. +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +Preamble + +The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. + +The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. + +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. + +Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. + +A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. + +The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. + +An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. + +The precise terms and conditions for copying, distribution and modification follow. + +TERMS AND CONDITIONS + +0. Definitions. +"This License" refers to version 3 of the GNU Affero General Public License. + +"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. + +To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based on the Program. + +To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. + +To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. + +An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. + +1. Source Code. +The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. + +A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. + +The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +2. Basic Permissions. +All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + +3. Protecting Users' Legal Rights From Anti-Circumvention Law. +No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. + +4. Conveying Verbatim Copies. +You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. + +5. Conveying Modified Source Versions. +You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: + +a) The work must carry prominent notices stating that you modified it, and giving a relevant date. +b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". +c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. +d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. +A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. + +6. Conveying Non-Source Forms. +You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: + +a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. +b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. +c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. +d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. +e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. +A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. + +A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. + +"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. + +7. Additional Terms. +"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: + +a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or +b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or +c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or +d) Limiting the use for publicity purposes of names of licensors or authors of the material; or +e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or +f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. +All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. + +8. Termination. +You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. + +9. Acceptance Not Required for Having Copies. +You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. + +10. Automatic Licensing of Downstream Recipients. +Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. + +An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. + +11. Patents. +A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. + +In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. + +A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. + +12. No Surrender of Others' Freedom. +If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. + +13. Remote Network Interaction; Use with the GNU General Public License. +Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. + +Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. + +14. Revised Versions of this License. +The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. + +Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. + +15. Disclaimer of Warranty. +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. Limitation of Liability. +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +17. Interpretation of Sections 15 and 16. +If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +Also add information on how to contact you by electronic and paper mail. + +If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. + +You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/LICENSE-CC-BY-NC b/code/controllers/ProcessScheduler/LICENSE-CC-BY-NC new file mode 100644 index 00000000..d0955f42 --- /dev/null +++ b/code/controllers/ProcessScheduler/LICENSE-CC-BY-NC @@ -0,0 +1 @@ +This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/README.md b/code/controllers/ProcessScheduler/README.md new file mode 100644 index 00000000..610800ba --- /dev/null +++ b/code/controllers/ProcessScheduler/README.md @@ -0,0 +1,86 @@ +ProcessScheduler +================ +A Goonstation release, maintained by Volundr + +##SUMMARY + +This is a mostly self-contained, fairly well-documented implementation of the main loop process architecture in use in Goonstation. + +##LICENSE + +This work is released under the following licenses. + +[![Creative Commons License](https://licensebuttons.net/l/by-nc/4.0/80x15.png)](http://creativecommons.org/licenses/by-nc/4.0/) + +This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License. The complete text of this license is included in the file LICENSE-CC-BY-NC. + + +[![Affero GPL Version 3](http://www.gnu.org/graphics/agplv3-88x31.png)](http://www.gnu.org/licenses/agpl-3.0.html) + +This work is licensed under the Affero General Public License 3.0. The complete text of the license is included in the file LICENSE-AGPL. + +##INSTALLATION + +To integrate the process scheduler to your codebase, you will not need anything except the contents of the core/ folder. The rest of the project is simply for testing and to provide an example for the process scheduler code. + +### Test project setup +To compile and run the test project, you will require: + +- node.js +- BYOND + +Clone the repository to a path of your choosing, then change directory to it and execute: + +``` +npm install -g +bower install -g +``` + +Then you can either compile with DM or open the DM environment in DreamMaker and compile/run from there. + +##USAGE + +###BASICS +To use the process scheduler in your SS13 codebase, you'll need: + +- core/_defines.dm +- core/_stubs.dm +- core/process.dm +- core/processScheduler.dm +- core/processScheduler.js +- core/updateQueue.dm +- core/updateQueueWorker.dm + +To integrate, you can copy the contents of _defines.dm into your global defines file. Most ss13 codebases already have the code from _stubs.dm. + +The processScheduler is intended as a replacement for the old master_controller from r4407 and other fork codebases. To implement it, you need only to add the source files to your DM environment, and add the following code into world.New, above where the old master_controller is initialized. + +``` +processScheduler = new +processScheduler.setup() +processScheduler.start() +``` + +The processScheduler will automatically find all subtypes of process, and begin processing them. + +The interface code in test/processSchedulerView.dm is simply an example frontend, and can easily be rebuilt to use other styles, and/or render simple html without using javascript for refreshing the panel and killing processes. + +###DETAILS + +To implement a process, you have two options: + +1. Implement a raw loop-style processor +2. Implement an updateQueue processor + +There are clear examples of both of these paradigms in the code provided. Both styles are valid, but for processes that are just a loop calling an update proc on a bunch of objects, you should use the updateQueue. + +The updateQueue works by spawn(0)'ing your specified update proc, but it only puts one instance in the scheduler at a time. Examine the code for more details. The overall effect of this is that it doesn't block, and it lets update loops work concurrently. It enables a much smoother user experience. + +##Contributing + +I welcome pull requests and issue reports, and will try to merge/fix them as I have time. + +### Licensing for code submitted via PR: + +By submitting a pull request, you agree to release all original code submitted in the pull request under the [MIT License](http://opensource.org/licenses/MIT). You also agree that any code submitted is either your own work, or is public domain or under a equally or less restrictive license than the MIT license, or that you have the express written permission of the authors of the submitted code to submit the pull request. + diff --git a/code/controllers/ProcessScheduler/bower.json b/code/controllers/ProcessScheduler/bower.json new file mode 100644 index 00000000..9a6be561 --- /dev/null +++ b/code/controllers/ProcessScheduler/bower.json @@ -0,0 +1,30 @@ +{ + "name": "ProcessScheduler", + "main": "ProcessScheduler.js", + "version": "1.0.0", + "homepage": "https://github.com/goonstation/ProcessScheduler", + "authors": [ + "Volundr " + ], + "description": "BYOND SS13 Process Scheduler", + "keywords": [ + "byond", + "ss13", + "process", + "scheduler" + ], + "license": "CC-BY-NC", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "private": true, + "dependencies": { + "bootstrap2.3.2": "~2.3.2", + "jquery": "1.11.1", + "json2": "*" + } +} diff --git a/code/controllers/ProcessScheduler/core/process.dm b/code/controllers/ProcessScheduler/core/process.dm new file mode 100644 index 00000000..9312db25 --- /dev/null +++ b/code/controllers/ProcessScheduler/core/process.dm @@ -0,0 +1,359 @@ +// Process + +/datum/controller/process + /** + * State vars + */ + // Main controller ref + var/tmp/datum/controller/processScheduler/main + + // 1 if process is not running or queued + var/tmp/idle = 1 + + // 1 if process is queued + var/tmp/queued = 0 + + // 1 if process is running + var/tmp/running = 0 + + // 1 if process is blocked up + var/tmp/hung = 0 + + // 1 if process was killed + var/tmp/killed = 0 + + // Status text var + var/tmp/status + + // Previous status text var + var/tmp/previousStatus + + // 1 if process is disabled + var/tmp/disabled = 0 + + /** + * Config vars + */ + // Process name + + // Process schedule interval + // This controls how often the process would run under ideal conditions. + // If the process scheduler sees that the process has finished, it will wait until + // this amount of time has elapsed from the start of the previous run to start the + // process running again. + var/tmp/schedule_interval = PROCESS_DEFAULT_SCHEDULE_INTERVAL // run every 50 ticks + + // Process sleep interval + // This controls how often the process will yield (call sleep(0)) while it is running. + // Every concurrent process should sleep periodically while running in order to allow other + // processes to execute concurrently. + var/tmp/sleep_interval + + // hang_warning_time - this is the time (in 1/10 seconds) after which the server will begin to show "maybe hung" in the context window + var/tmp/hang_warning_time = PROCESS_DEFAULT_HANG_WARNING_TIME + + // hang_alert_time - After this much time(in 1/10 seconds), the server will send an admin debug message saying the process may be hung + var/tmp/hang_alert_time = PROCESS_DEFAULT_HANG_ALERT_TIME + + // hang_restart_time - After this much time(in 1/10 seconds), the server will automatically kill and restart the process. + var/tmp/hang_restart_time = PROCESS_DEFAULT_HANG_RESTART_TIME + + // How many times in the current run has the process deferred work till the next tick? + var/tmp/cpu_defer_count = 0 + + // How many SCHECKs have been skipped (to limit btime calls) + var/tmp/calls_since_last_scheck = 0 + + /** + * recordkeeping vars + */ + + // Records the time (1/10s timeoftick) at which the process last finished sleeping + var/tmp/last_slept = 0 + + // Records the time (1/10s timeofgame) at which the process last began running + var/tmp/run_start = 0 + + // Records the number of times this process has been killed and restarted + var/tmp/times_killed + + // Tick count + var/tmp/ticks = 0 + + var/tmp/last_task = "" + + var/tmp/last_object + + // Counts the number of times an exception has occurred; gets reset after 10 + var/tmp/list/exceptions = list() + + // Number of deciseconds to delay before starting the process + var/start_delay = 0 + +/datum/controller/process/New(var/datum/controller/processScheduler/scheduler) + ..() + main = scheduler + previousStatus = "idle" + idle() + name = "process" + schedule_interval = 50 + sleep_interval = world.tick_lag / PROCESS_DEFAULT_SLEEP_INTERVAL + last_slept = 0 + run_start = 0 + ticks = 0 + last_task = 0 + last_object = null + +/datum/controller/process/proc/started() + // Initialize run_start so we can detect hung processes. + run_start = TimeOfGame + + // Initialize defer count + cpu_defer_count = 0 + + running() + main.processStarted(src) + + onStart() + +/datum/controller/process/proc/finished() + ticks++ + idle() + main.processFinished(src) + + onFinish() + +/datum/controller/process/proc/doWork() + +/datum/controller/process/proc/setup() + +/datum/controller/process/proc/process() + started() + doWork() + finished() + +/datum/controller/process/proc/running() + idle = 0 + queued = 0 + running = 1 + hung = 0 + setStatus(PROCESS_STATUS_RUNNING) + +/datum/controller/process/proc/idle() + queued = 0 + running = 0 + idle = 1 + hung = 0 + setStatus(PROCESS_STATUS_IDLE) + +/datum/controller/process/proc/queued() + idle = 0 + running = 0 + queued = 1 + hung = 0 + setStatus(PROCESS_STATUS_QUEUED) + +/datum/controller/process/proc/hung() + hung = 1 + setStatus(PROCESS_STATUS_HUNG) + +/datum/controller/process/proc/handleHung() + var/datum/lastObj = last_object + var/lastObjType = "null" + if(istype(lastObj)) + lastObjType = lastObj.type + + var/msg = "[name] process hung at tick #[ticks]. Process was unresponsive for [(TimeOfGame - run_start) / 10] seconds and was restarted. Last task: [last_task]. Last Object Type: [lastObjType]" + log_debug(msg) + message_admins(msg) + + main.restartProcess(src.name) + +/datum/controller/process/proc/kill() + if (!killed) + var/msg = "[name] process was killed at tick #[ticks]." + log_debug(msg) + message_admins(msg) + //finished() + + // Allow inheritors to clean up if needed + onKill() + + // This should del + qdel(src) + +// Do not call this directly - use SHECK or SCHECK_EVERY +/datum/controller/process/proc/sleepCheck(var/tickId = 0) + calls_since_last_scheck = 0 + if (killed) + // The kill proc is the only place where killed is set. + // The kill proc should have deleted this datum, and all sleeping procs that are + // owned by it. + CRASH("A killed process is still running somehow...") + if (hung) + // This will only really help if the doWork proc ends up in an infinite loop. + handleHung() + CRASH("Process [name] hung and was restarted.") + + if (main.getCurrentTickElapsedTime() > main.timeAllowance) + sleep(world.tick_lag) + cpu_defer_count++ + last_slept = 0 + else + if (TimeOfTick > last_slept + sleep_interval) + // If we haven't slept in sleep_interval deciseconds, sleep to allow other work to proceed. + sleep(0) + last_slept = TimeOfTick + +/datum/controller/process/proc/update() + // Clear delta + if(previousStatus != status) + setStatus(status) + + var/elapsedTime = getElapsedTime() + + if (hung) + handleHung() + return + else if (elapsedTime > hang_restart_time) + hung() + else if (elapsedTime > hang_alert_time) + setStatus(PROCESS_STATUS_PROBABLY_HUNG) + else if (elapsedTime > hang_warning_time) + setStatus(PROCESS_STATUS_MAYBE_HUNG) + + +/datum/controller/process/proc/getElapsedTime() + return TimeOfGame - run_start + +/datum/controller/process/proc/tickDetail() + return + +/datum/controller/process/proc/getContext() + return "[name][main.averageRunTime(src)][main.last_run_time[src]][main.highest_run_time[src]][ticks]\n" + +/datum/controller/process/proc/getContextData() + return list( + "name" = name, + "averageRunTime" = main.averageRunTime(src), + "lastRunTime" = main.last_run_time[src], + "highestRunTime" = main.highest_run_time[src], + "ticks" = ticks, + "schedule" = schedule_interval, + "status" = getStatusText(), + "disabled" = disabled + ) + +/datum/controller/process/proc/getStatus() + return status + +/datum/controller/process/proc/getStatusText(var/s = 0) + if(!s) + s = status + switch(s) + if(PROCESS_STATUS_IDLE) + return "idle" + if(PROCESS_STATUS_QUEUED) + return "queued" + if(PROCESS_STATUS_RUNNING) + return "running" + if(PROCESS_STATUS_MAYBE_HUNG) + return "maybe hung" + if(PROCESS_STATUS_PROBABLY_HUNG) + return "probably hung" + if(PROCESS_STATUS_HUNG) + return "HUNG" + else + return "UNKNOWN" + +/datum/controller/process/proc/getPreviousStatus() + return previousStatus + +/datum/controller/process/proc/getPreviousStatusText() + return getStatusText(previousStatus) + +/datum/controller/process/proc/setStatus(var/newStatus) + previousStatus = status + status = newStatus + +/datum/controller/process/proc/setLastTask(var/task, var/object) + last_task = task + last_object = object + +/datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target) + main = target.main + name = target.name + schedule_interval = target.schedule_interval + sleep_interval = target.sleep_interval + last_slept = 0 + run_start = 0 + times_killed = target.times_killed + ticks = target.ticks + last_task = target.last_task + last_object = target.last_object + copyStateFrom(target) + +/datum/controller/process/proc/copyStateFrom(var/datum/controller/process/target) + +/datum/controller/process/proc/onKill() + +/datum/controller/process/proc/onStart() + +/datum/controller/process/proc/onFinish() + +/datum/controller/process/proc/disable() + disabled = 1 + +/datum/controller/process/proc/enable() + disabled = 0 + +/datum/controller/process/proc/getAverageRunTime() + return main.averageRunTime(src) +/datum/controller/process/proc/getLastRunTime() + return main.getProcessLastRunTime(src) + +/datum/controller/process/proc/getHighestRunTime() + return main.getProcessHighestRunTime(src) + +/datum/controller/process/proc/getTotalRunTime() + return main.getProcessTotalRunTime(src) + +/datum/controller/process/proc/getTicks() + return ticks + +/datum/controller/process/proc/statProcess() + var/averageRunTime = round(getAverageRunTime(), 0.1)/10 + var/lastRunTime = round(getLastRunTime(), 0.1)/10 + var/highestRunTime = round(getHighestRunTime(), 0.1)/10 + stat("[name]", "T#[getTicks()] | AR [averageRunTime] | LR [lastRunTime] | HR [highestRunTime] | D [cpu_defer_count]") + +/datum/controller/process/proc/catchException(var/exception/e, var/thrower) + if(istype(e)) // Real runtimes go to the real error handler + throw e + var/etext = "[e]" + var/eid = "[e]" // Exception ID, for tracking repeated exceptions + var/ptext = "" // "processing..." text, for what was being processed (if known) + if(istype(e)) + etext += " in [e.file], line [e.line]" + eid = "[e.file]:[e.line]" + if(eid in exceptions) + if(exceptions[eid]++ >= 10) + return + else + exceptions[eid] = 1 + if(istype(thrower, /datum)) + var/datum/D = thrower + ptext = " processing [D.type]" + if(istype(thrower, /atom)) + var/atom/A = thrower + ptext += " ([A]) ([A.x],[A.y],[A.z])" + log_to_dd("\[[time_stamp()]\] Process [name] caught exception[ptext]: [etext]") + if(exceptions[eid] >= 10) + log_to_dd("This exception will now be ignored for ten minutes.") + spawn(6000) + exceptions[eid] = 0 + +/datum/controller/process/proc/catchBadType(var/datum/caught) + if(isnull(caught) || !istype(caught) || QDELETED(caught)) + return // Only bother with types we can identify and that don't belong + catchException("Type [caught.type] does not belong in process' queue") diff --git a/code/controllers/ProcessScheduler/core/processScheduler.dm b/code/controllers/ProcessScheduler/core/processScheduler.dm new file mode 100644 index 00000000..4b6b9032 --- /dev/null +++ b/code/controllers/ProcessScheduler/core/processScheduler.dm @@ -0,0 +1,387 @@ +// Singleton instance of game_controller_new, setup in world.New() +var/global/datum/controller/processScheduler/processScheduler + +/datum/controller/processScheduler + // Processes known by the scheduler + var/tmp/datum/controller/process/list/processes = new + + // Processes that are currently running + var/tmp/datum/controller/process/list/running = new + + // Processes that are idle + var/tmp/datum/controller/process/list/idle = new + + // Processes that are queued to run + var/tmp/datum/controller/process/list/queued = new + + // Process name -> process object map + var/tmp/datum/controller/process/list/nameToProcessMap = new + + // Process last queued times (world time) + var/tmp/datum/controller/process/list/last_queued = new + + // Process last start times (real time) + var/tmp/datum/controller/process/list/last_start = new + + // Process last run durations + var/tmp/datum/controller/process/list/last_run_time = new + + // Per process list of the last 20 durations + var/tmp/datum/controller/process/list/last_twenty_run_times = new + + // Process highest run time + var/tmp/datum/controller/process/list/highest_run_time = new + + // Process total run time + var/tmp/datum/controller/process/list/total_run_time = new + + // How long to sleep between runs (set to tick_lag in New) + var/tmp/scheduler_sleep_interval + + // Controls whether the scheduler is running or not + var/tmp/isRunning = 0 + + // Setup for these processes will be deferred until all the other processes are set up. + var/tmp/list/deferredSetupList = new + + var/tmp/currentTick = 0 + + var/tmp/timeAllowance = 0 + + var/tmp/cpuAverage = 0 + + var/tmp/timeAllowanceMax = 0 + +/datum/controller/processScheduler/New() + ..() + // When the process scheduler is first new'd, tick_lag may be wrong, so these + // get re-initialized when the process scheduler is started. + // (These are kept here for any processes that decide to process before round start) + scheduler_sleep_interval = world.tick_lag + timeAllowance = world.tick_lag * 0.5 + timeAllowanceMax = world.tick_lag + +/** + * deferSetupFor + * @param path processPath + * If a process needs to be initialized after everything else, add it to + * the deferred setup list. On goonstation, only the ticker needs to have + * this treatment. + */ +/datum/controller/processScheduler/proc/deferSetupFor(var/processPath) + if (!(processPath in deferredSetupList)) + deferredSetupList += processPath + +/datum/controller/processScheduler/proc/setup() + // There can be only one + if(processScheduler && (processScheduler != src)) + qdel(src) + return 0 + + var/process + // Add all the processes we can find, except for the ticker + for (process in subtypesof(/datum/controller/process)) + if (!(process in deferredSetupList)) + addProcess(new process(src)) + + for (process in deferredSetupList) + addProcess(new process(src)) + +/datum/controller/processScheduler/proc/start() + isRunning = 1 + // tick_lag will have been set by now, so re-initialize these + scheduler_sleep_interval = world.tick_lag + timeAllowance = world.tick_lag * 0.5 + timeAllowanceMax = world.tick_lag + updateStartDelays() + spawn(0) + process() + +/datum/controller/processScheduler/proc/process() + updateCurrentTickData() + + for(var/i=world.tick_lag,i= last_queued[p] + p.schedule_interval) + setQueuedProcessState(p) + +/datum/controller/processScheduler/proc/runQueuedProcesses() + for(var/datum/controller/process/p in queued) + runProcess(p) + +/datum/controller/processScheduler/proc/addProcess(var/datum/controller/process/process) + processes.Add(process) + process.idle() + idle.Add(process) + + // init recordkeeping vars + last_start.Add(process) + last_start[process] = 0 + last_run_time.Add(process) + last_run_time[process] = 0 + last_twenty_run_times.Add(process) + last_twenty_run_times[process] = list() + highest_run_time.Add(process) + highest_run_time[process] = 0 + total_run_time.Add(process) + total_run_time[process] = 0 + + // init starts and stops record starts + recordStart(process, 0) + recordEnd(process, 0) + + // Set up process + process.setup() + + // Save process in the name -> process map + nameToProcessMap[process.name] = process + +/datum/controller/processScheduler/proc/replaceProcess(var/datum/controller/process/oldProcess, var/datum/controller/process/newProcess) + processes.Remove(oldProcess) + processes.Add(newProcess) + + newProcess.idle() + idle.Remove(oldProcess) + running.Remove(oldProcess) + queued.Remove(oldProcess) + idle.Add(newProcess) + + last_start.Remove(oldProcess) + last_start.Add(newProcess) + last_start[newProcess] = 0 + + last_run_time.Add(newProcess) + last_run_time[newProcess] = last_run_time[oldProcess] + last_run_time.Remove(oldProcess) + + last_twenty_run_times.Add(newProcess) + last_twenty_run_times[newProcess] = last_twenty_run_times[oldProcess] + last_twenty_run_times.Remove(oldProcess) + + highest_run_time.Add(newProcess) + highest_run_time[newProcess] = highest_run_time[oldProcess] + highest_run_time.Remove(oldProcess) + + total_run_time.Add(newProcess) + total_run_time[newProcess] = total_run_time[oldProcess] + total_run_time.Remove(oldProcess) + + recordStart(newProcess, 0) + recordEnd(newProcess, 0) + + nameToProcessMap[newProcess.name] = newProcess + +/datum/controller/processScheduler/proc/updateStartDelays() + for(var/datum/controller/process/p in processes) + if(p.start_delay) + last_queued[p] = world.time - p.start_delay + +/datum/controller/processScheduler/proc/runProcess(var/datum/controller/process/process) + spawn(0) + process.process() + +/datum/controller/processScheduler/proc/processStarted(var/datum/controller/process/process) + setRunningProcessState(process) + recordStart(process) + +/datum/controller/processScheduler/proc/processFinished(var/datum/controller/process/process) + setIdleProcessState(process) + recordEnd(process) + +/datum/controller/processScheduler/proc/setIdleProcessState(var/datum/controller/process/process) + if (process in running) + running -= process + if (process in queued) + queued -= process + if (!(process in idle)) + idle += process + +/datum/controller/processScheduler/proc/setQueuedProcessState(var/datum/controller/process/process) + if (process in running) + running -= process + if (process in idle) + idle -= process + if (!(process in queued)) + queued += process + + // The other state transitions are handled internally by the process. + process.queued() + +/datum/controller/processScheduler/proc/setRunningProcessState(var/datum/controller/process/process) + if (process in queued) + queued -= process + if (process in idle) + idle -= process + if (!(process in running)) + running += process + +/datum/controller/processScheduler/proc/recordStart(var/datum/controller/process/process, var/time = null) + if (isnull(time)) + time = TimeOfGame + last_queued[process] = world.time + last_start[process] = time + else + last_queued[process] = (time == 0 ? 0 : world.time) + last_start[process] = time + +/datum/controller/processScheduler/proc/recordEnd(var/datum/controller/process/process, var/time = null) + if (isnull(time)) + time = TimeOfGame + + var/lastRunTime = time - last_start[process] + + if(lastRunTime < 0) + lastRunTime = 0 + + recordRunTime(process, lastRunTime) + +/** + * recordRunTime + * Records a run time for a process + */ +/datum/controller/processScheduler/proc/recordRunTime(var/datum/controller/process/process, time) + last_run_time[process] = time + if(time > highest_run_time[process]) + highest_run_time[process] = time + + var/list/lastTwenty = last_twenty_run_times[process] + if (lastTwenty.len == 20) + lastTwenty.Cut(1, 2) + lastTwenty.len++ + lastTwenty[lastTwenty.len] = time + + total_run_time[process] += time + +/** + * averageRunTime + * returns the average run time (over the last 20) of the process + */ +/datum/controller/processScheduler/proc/averageRunTime(var/datum/controller/process/process) + var/lastTwenty = last_twenty_run_times[process] + + var/t = 0 + var/c = 0 + for(var/time in lastTwenty) + t += time + c++ + + if(c > 0) + return t / c + return c + +/datum/controller/processScheduler/proc/getProcessLastRunTime(var/datum/controller/process/process) + return last_run_time[process] + +/datum/controller/processScheduler/proc/getProcessHighestRunTime(var/datum/controller/process/process) + return highest_run_time[process] + +/datum/controller/processScheduler/proc/getProcessTotalRunTime(var/datum/controller/process/process) + return total_run_time[process] + +/datum/controller/processScheduler/proc/getStatusData() + var/list/data = new + + for (var/datum/controller/process/p in processes) + data.len++ + data[data.len] = p.getContextData() + + return data + +/datum/controller/processScheduler/proc/getProcessCount() + return processes.len + +/datum/controller/processScheduler/proc/hasProcess(var/processName as text) + if (nameToProcessMap[processName]) + return 1 + +/datum/controller/processScheduler/proc/killProcess(var/processName as text) + restartProcess(processName) + +/datum/controller/processScheduler/proc/restartProcess(var/processName as text) + if (hasProcess(processName)) + var/datum/controller/process/oldInstance = nameToProcessMap[processName] + var/datum/controller/process/newInstance = new oldInstance.type(src) + newInstance._copyStateFrom(oldInstance) + replaceProcess(oldInstance, newInstance) + oldInstance.kill() + +/datum/controller/processScheduler/proc/enableProcess(var/processName as text) + if (hasProcess(processName)) + var/datum/controller/process/process = nameToProcessMap[processName] + process.enable() + +/datum/controller/processScheduler/proc/disableProcess(var/processName as text) + if (hasProcess(processName)) + var/datum/controller/process/process = nameToProcessMap[processName] + process.disable() + +/datum/controller/processScheduler/proc/getCurrentTickElapsedTime() + if (world.time > currentTick) + updateCurrentTickData() + return 0 + else + return TimeOfTick + +/datum/controller/processScheduler/proc/updateCurrentTickData() + if (world.time > currentTick) + // New tick! + currentTick = world.time + updateTimeAllowance() + cpuAverage = (world.cpu + cpuAverage + cpuAverage) / 3 + +/datum/controller/processScheduler/proc/updateTimeAllowance() + // Time allowance goes down linearly with world.cpu. + var/error = cpuAverage - 100 + var/timeAllowanceDelta = SIMPLE_SIGN(error) * -0.5 * world.tick_lag * max(0, 0.001 * abs(error)) + + //timeAllowance = world.tick_lag * min(1, 0.5 * ((200/max(1,cpuAverage)) - 1)) + timeAllowance = min(timeAllowanceMax, max(0, timeAllowance + timeAllowanceDelta)) + +/datum/controller/processScheduler/proc/statProcesses() + if(!isRunning) + stat("Processes", "Scheduler not running") + return + stat("Processes", "[processes.len] (R [running.len] / Q [queued.len] / I [idle.len])") + stat(null, "[round(cpuAverage, 0.1)] CPU, [round(timeAllowance, 0.1)/10] TA") + for(var/datum/controller/process/p in processes) + p.statProcess() + +/datum/controller/processScheduler/proc/getProcess(var/process_name) + return nameToProcessMap[process_name] diff --git a/code/controllers/ProcessScheduler/package.json b/code/controllers/ProcessScheduler/package.json new file mode 100644 index 00000000..f699553f --- /dev/null +++ b/code/controllers/ProcessScheduler/package.json @@ -0,0 +1,28 @@ +{ + "name": "ProcessScheduler", + "version": "1.0.0", + "description": "BYOND SS13 Process Scheduler", + "main": "processScheduler.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/goonstation/ProcessScheduler.git" + }, + "keywords": [ + "byond", + "ss13", + "process", + "scheduler" + ], + "author": "Volundr", + "license": "CC-BY-NC", + "bugs": { + "url": "https://github.com/goonstation/ProcessScheduler/issues" + }, + "homepage": "https://github.com/goonstation/ProcessScheduler", + "dependencies": { + "bower": "*" + } +} diff --git a/code/controllers/Processes/Shuttle.dm b/code/controllers/Processes/Shuttle.dm new file mode 100644 index 00000000..a10586d7 --- /dev/null +++ b/code/controllers/Processes/Shuttle.dm @@ -0,0 +1,9 @@ +/datum/controller/process/Shuttle/setup() + name = "shuttle controller" + schedule_interval = 20 // every 2 seconds + + if(!shuttle_controller) + shuttle_controller = new + +/datum/controller/process/Shuttle/doWork() + shuttle_controller.process() diff --git a/code/controllers/Processes/air.dm b/code/controllers/Processes/air.dm new file mode 100644 index 00000000..65bd8dde --- /dev/null +++ b/code/controllers/Processes/air.dm @@ -0,0 +1,24 @@ +/datum/controller/process/air/setup() + name = "air" + schedule_interval = 20 // every 2 seconds + start_delay = 4 + + if(!air_master) + air_master = new + air_master.Setup() + +/datum/controller/process/air/doWork() + if(!air_processing_killed) + if(!air_master.Tick()) //Runtimed. + air_master.failed_ticks++ + + if(air_master.failed_ticks > 5) + to_world("RUNTIME'S IN ATMOS TICKER. Killing air simulation!") + + log_error("### ZAS SHUTDOWN") + + message_admins("ZASALERT: Shutting down! status: [air_master.tick_progress]") + log_admin("ZASALERT: Shutting down! status: [air_master.tick_progress]") + + air_processing_killed = TRUE + air_master.failed_ticks = 0 \ No newline at end of file diff --git a/code/controllers/Processes/alarm.dm b/code/controllers/Processes/alarm.dm new file mode 100644 index 00000000..63487177 --- /dev/null +++ b/code/controllers/Processes/alarm.dm @@ -0,0 +1,41 @@ +// We manually initialize the alarm handlers instead of looping over all existing types +// to make it possible to write: camera.triggerAlarm() rather than alarm_manager.managers[datum/alarm_handler/camera].triggerAlarm() or a variant thereof. +/var/global/datum/alarm_handler/atmosphere/atmosphere_alarm = new() +/var/global/datum/alarm_handler/camera/camera_alarm = new() +/var/global/datum/alarm_handler/fire/fire_alarm = new() +/var/global/datum/alarm_handler/motion/motion_alarm = new() +/var/global/datum/alarm_handler/power/power_alarm = new() + +// Alarm Manager, the manager for alarms. +var/datum/controller/process/alarm/alarm_manager + +/datum/controller/process/alarm + var/list/datum/alarm/all_handlers + +/datum/controller/process/alarm/setup() + name = "alarm" + schedule_interval = 20 // every 2 seconds + all_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, motion_alarm, power_alarm) + alarm_manager = src + +/datum/controller/process/alarm/doWork() + for(last_object in all_handlers) + var/datum/alarm_handler/AH = last_object + AH.process() + SCHECK + +/datum/controller/process/alarm/proc/active_alarms() + var/list/all_alarms = new + for(var/datum/alarm_handler/AH in all_handlers) + var/list/alarms = AH.alarms + all_alarms += alarms + + return all_alarms + +/datum/controller/process/alarm/proc/number_of_active_alarms() + var/list/alarms = active_alarms() + return alarms.len + +/datum/controller/process/alarm/statProcess() + ..() + stat(null, "[number_of_active_alarms()] alarm\s") diff --git a/code/controllers/Processes/emergencyShuttle.dm b/code/controllers/Processes/emergencyShuttle.dm new file mode 100644 index 00000000..47325598 --- /dev/null +++ b/code/controllers/Processes/emergencyShuttle.dm @@ -0,0 +1,10 @@ +/datum/controller/process/evac/setup() + name = "evacuation" + schedule_interval = 20 // every 2 seconds + + if(!evacuation_controller) + evacuation_controller = new GLOB.using_map.evac_controller_type () + evacuation_controller.set_up() + +/datum/controller/process/evac/doWork() + evacuation_controller.process() diff --git a/code/controllers/Processes/event.dm b/code/controllers/Processes/event.dm new file mode 100644 index 00000000..10eccb16 --- /dev/null +++ b/code/controllers/Processes/event.dm @@ -0,0 +1,15 @@ +/datum/controller/process/event/setup() + name = "event controller" + schedule_interval = 20 // every 2 seconds + +/datum/controller/process/event/doWork() + for(last_object in GLOB.event_manager.active_events) + var/datum/event/E = last_object + E.process() + SCHECK + + for(var/i = EVENT_LEVEL_MUNDANE to EVENT_LEVEL_MAJOR) + last_object = GLOB.event_manager.event_containers[i] + var/list/datum/event_container/EC = last_object + EC.process() + SCHECK diff --git a/code/controllers/Processes/inactivity.dm b/code/controllers/Processes/inactivity.dm new file mode 100644 index 00000000..b4ac2a73 --- /dev/null +++ b/code/controllers/Processes/inactivity.dm @@ -0,0 +1,14 @@ +/datum/controller/process/inactivity/setup() + name = "inactivity" + schedule_interval = 600 // Once every minute (approx.) + +/datum/controller/process/inactivity/doWork() + if(config.kick_inactive) + for(last_object in GLOB.clients) + var/client/C = last_object + if(!C.holder && C.is_afk(config.kick_inactive MINUTES)) + if(!isobserver(C.mob)) + log_access("AFK: [key_name(C)]") + to_chat(C, "You have been inactive for more than [config.kick_inactive] minute\s and have been disconnected.") + qdel(C) + SCHECK diff --git a/code/controllers/Processes/lighting.dm b/code/controllers/Processes/lighting.dm new file mode 100644 index 00000000..63015062 --- /dev/null +++ b/code/controllers/Processes/lighting.dm @@ -0,0 +1,97 @@ +/var/lighting_overlays_initialised = FALSE + +/var/list/lighting_update_lights = list() // List of lighting sources queued for update. +/var/list/lighting_update_corners = list() // List of lighting corners queued for update. +/var/list/lighting_update_overlays = list() // List of lighting overlays queued for update. + +/var/list/lighting_update_lights_old = list() // List of lighting sources currently being updated. +/var/list/lighting_update_corners_old = list() // List of lighting corners currently being updated. +/var/list/lighting_update_overlays_old = list() // List of lighting overlays currently being updated. + + +/datum/controller/process/lighting + // Queues of update counts, waiting to be rolled into stats lists + var/list/stats_queues = list( + "Source" = list(), "Corner" = list(), "Overlay" = list()) + // Stats lists + var/list/stats_lists = list( + "Source" = list(), "Corner" = list(), "Overlay" = list()) + var/update_stats_every = (1 SECONDS) + var/next_stats_update = 0 + var/stat_updates_to_keep = 5 + +/datum/controller/process/lighting/setup() + name = "lighting" + + schedule_interval = 0 // run as fast as you possibly can + sleep_interval = 10 + create_all_lighting_overlays() + lighting_overlays_initialised = TRUE + + // Pre-process lighting once before the round starts. Wait 30 seconds so the away mission has time to load. + spawn(300) + doWork(1) + +/datum/controller/process/lighting/doWork(roundstart) + + lighting_update_lights_old = lighting_update_lights //We use a different list so any additions to the update lists during a delay from scheck() don't cause things to be cut from the list without being updated. + lighting_update_lights = list() + for(var/datum/light_source/L in lighting_update_lights_old) + + if(L.check() || L.destroyed || L.force_update) + L.remove_lum() + if(!L.destroyed) + L.apply_lum() + + else if(L.vis_update) //We smartly update only tiles that became (in) visible to use. + L.smart_vis_update() + + L.vis_update = FALSE + L.force_update = FALSE + L.needs_update = FALSE + + SCHECK + + lighting_update_corners_old = lighting_update_corners //Same as above. + lighting_update_corners = list() + for(var/A in lighting_update_corners_old) + var/datum/lighting_corner/C = A + + C.update_overlays() + + C.needs_update = FALSE + + SCHECK + + lighting_update_overlays_old = lighting_update_overlays //Same as above. + lighting_update_overlays = list() + + for(var/A in lighting_update_overlays_old) + var/atom/movable/lighting_overlay/O = A + O.update_overlay() + O.needs_update = 0 + SCHECK + + stats_queues["Source"] += lighting_update_lights_old.len + stats_queues["Corner"] += lighting_update_corners_old.len + stats_queues["Overlay"] += lighting_update_overlays_old.len + + if(next_stats_update <= world.time) + next_stats_update = world.time + update_stats_every + for(var/stat_name in stats_queues) + var/stat_sum = 0 + var/list/stats_queue = stats_queues[stat_name] + for(var/count in stats_queue) + stat_sum += count + stats_queue.Cut() + + var/list/stats_list = stats_lists[stat_name] + stats_list.Insert(1, stat_sum) + if(stats_list.len > stat_updates_to_keep) + stats_list.Cut(stats_list.len) + +/datum/controller/process/lighting/statProcess() + ..() + stat(null, "[total_lighting_sources] sources, [total_lighting_corners] corners, [total_lighting_overlays] overlays") + for(var/stat_type in stats_lists) + stat(null, "[stat_type] updates: [jointext(stats_lists[stat_type], " | ")]") diff --git a/code/controllers/Processes/nanoui.dm b/code/controllers/Processes/nanoui.dm new file mode 100644 index 00000000..2e8d7f4b --- /dev/null +++ b/code/controllers/Processes/nanoui.dm @@ -0,0 +1,19 @@ +/datum/controller/process/nanoui/setup() + name = "nanoui" + schedule_interval = 20 // every 2 seconds + +/datum/controller/process/nanoui/statProcess() + ..() + stat(null, "[GLOB.nanomanager.processing_uis.len] UIs") + +/datum/controller/process/nanoui/doWork() + for(last_object in GLOB.nanomanager.processing_uis) + var/datum/nanoui/NUI = last_object + if(istype(NUI) && !QDELETED(NUI)) + try + NUI.process() + catch(var/exception/e) + catchException(e, NUI) + else + catchBadType(NUI) + GLOB.nanomanager.processing_uis -= NUI diff --git a/code/controllers/Processes/radiation.dm b/code/controllers/Processes/radiation.dm new file mode 100644 index 00000000..28fdece4 --- /dev/null +++ b/code/controllers/Processes/radiation.dm @@ -0,0 +1,56 @@ +/datum/controller/process/radiation + var/repository/radiation/linked = null + +/datum/controller/process/radiation/setup() + name = "radiation controller" + schedule_interval = 20 // every 2 seconds + linked = radiation_repository + +/datum/controller/process/radiation/doWork() + sources_decay() + cache_expires() + irradiate_targets() + +// Step 1 - Sources Decay +/datum/controller/process/radiation/proc/sources_decay() + var/list/sources = linked.sources + for(var/thing in sources) + var/datum/radiation_source/S = thing + if(QDELETED(S)) + sources.Remove(S) + continue + if(S.decay) + S.update_rad_power(S.rad_power - config.radiation_decay_rate) + if(S.rad_power <= config.radiation_lower_limit) + sources.Remove(S) + SCHECK // This scheck probably just wastes resources, but better safe than sorry in this case. + +// Step 2 - Cache Expires +/datum/controller/process/radiation/proc/cache_expires() + var/list/resistance_cache = linked.resistance_cache + for(var/thing in resistance_cache) + var/turf/T = thing + if(QDELETED(T)) + resistance_cache.Remove(T) + continue + if((length(T.contents) + 1) != resistance_cache[T]) + resistance_cache.Remove(T) // If its stale REMOVE it! It will get added if its needed. + SCHECK + +// Step 3 - Registered irradiatable things are checked for radiation +/datum/controller/process/radiation/proc/irradiate_targets() + var/list/registered_listeners = GLOB.living_mob_list_ // For now just use this. Nothing else is interested anyway. + if(length(linked.sources) > 0) + for(var/thing in registered_listeners) + var/atom/A = thing + if(QDELETED(A)) + continue + var/turf/T = get_turf(thing) + var/rads = linked.get_rads_at_turf(T) + if(rads) + A.rad_act(rads) + SCHECK + +/datum/controller/process/radiation/statProcess() + ..() + stat(null, "[linked.sources.len] sources, [linked.resistance_cache.len] cached turfs") diff --git a/code/controllers/Processes/supply.dm b/code/controllers/Processes/supply.dm new file mode 100644 index 00000000..891a511e --- /dev/null +++ b/code/controllers/Processes/supply.dm @@ -0,0 +1,6 @@ +/datum/controller/process/supply/setup() + name = "supply controller" + schedule_interval = 300 // every 30 seconds + +/datum/controller/process/supply/doWork() + supply_controller.process() \ No newline at end of file diff --git a/code/controllers/Processes/tgui.dm b/code/controllers/Processes/tgui.dm new file mode 100644 index 00000000..4081818b --- /dev/null +++ b/code/controllers/Processes/tgui.dm @@ -0,0 +1,28 @@ +var/global/datum/controller/process/tgui/tgui_process + +/datum/controller/process/tgui + var/list/tg_open_uis = list() // A list of open UIs, grouped by src_object and ui_key. + var/list/processing_uis = list() // A list of processing UIs, ungrouped. + var/basehtml // The HTML base used for all UIs. + +/datum/controller/process/tgui/setup() + name = "tgui" + schedule_interval = 10 // every 2 seconds + start_delay = 23 + + basehtml = file2text('tgui/tgui.html') // Read the HTML from disk. + tgui_process = src + +/datum/controller/process/tgui/doWork() + for(var/gui in processing_uis) + var/datum/tgui/ui = gui + if(ui && ui.user && ui.src_object) + ui.process() + SCHECK + continue + processing_uis.Remove(ui) + SCHECK + +/datum/controller/process/tgui/statProcess() + ..() + stat(null, "[tgui_process.processing_uis.len] UI\s") diff --git a/code/controllers/Processes/ticker.dm b/code/controllers/Processes/ticker.dm new file mode 100644 index 00000000..6fa6d432 --- /dev/null +++ b/code/controllers/Processes/ticker.dm @@ -0,0 +1,38 @@ +var/global/datum/controller/process/ticker/tickerProcess + +/datum/controller/process/ticker + var/lastTickerTimeDuration + var/lastTickerTime + +/datum/controller/process/ticker/setup() + name = "ticker" + schedule_interval = 20 // every 2 seconds + + lastTickerTime = world.timeofday + + if(!ticker) + ticker = new + + tickerProcess = src + + spawn(0) + if(ticker) + ticker.pregame() + +/datum/controller/process/ticker/doWork() + var/currentTime = world.timeofday + + if(currentTime < lastTickerTime) // check for midnight rollover + lastTickerTimeDuration = (currentTime - (lastTickerTime - TICKS_IN_DAY)) / TICKS_IN_SECOND + else + lastTickerTimeDuration = (currentTime - lastTickerTime) / TICKS_IN_SECOND + + lastTickerTime = currentTime + + ticker.process() + +/datum/controller/process/ticker/proc/getLastTickerTimeDuration() + return lastTickerTimeDuration + +/world/proc/has_round_started() + return (ticker && ticker.current_state >= GAME_STATE_PLAYING) diff --git a/code/controllers/Processes/timer.dm b/code/controllers/Processes/timer.dm new file mode 100644 index 00000000..0fba3919 --- /dev/null +++ b/code/controllers/Processes/timer.dm @@ -0,0 +1,417 @@ +#define BUCKET_LEN (round(10*(60/world.tick_lag), 1)) //how many ticks should we keep in the bucket. (1 minutes worth) +#define BUCKET_POS(timer) (round((timer.timeToRun - SStimer.head_offset) / world.tick_lag) + 1) +#define TIMER_ID_MAX (2**24) //max float with integer precision + +var/datum/controller/subsystem/timer/SStimer + +/datum/controller/subsystem/timer + name = "Timer" + wait = 1 //SS_TICKER subsystem, so wait is in ticks + init_order = 1 + + flags = SS_TICKER|SS_NO_INIT + + var/list/datum/timedevent/processing = list() + var/list/hashes = list() + + var/head_offset = 0 //world.time of the first entry in the the bucket. + var/practical_offset = 0 //index of the first non-empty item in the bucket. + var/bucket_resolution = 0 //world.tick_lag the bucket was designed for + var/bucket_count = 0 //how many timers are in the buckets + + var/list/bucket_list = list() //list of buckets, each bucket holds every timer that has to run that byond tick. + + var/list/timer_id_dict = list() //list of all active timers assoicated to their timer id (for easy lookup) + + var/list/clienttime_timers = list() //special snowflake timers that run on fancy pansy "client time" + + var/last_invoke_tick = 0 + var/static/last_invoke_warning = 0 + var/static/bucket_auto_reset = TRUE + + var/static/times_flushed = 0 + var/static/times_crashed = 0 + +/datum/controller/subsystem/timer/New() + NEW_SS_GLOBAL(SStimer) + +/datum/controller/subsystem/timer/stat_entry(msg) + ..("B:[bucket_count] P:[length(processing)] H:[length(hashes)] C:[length(clienttime_timers)][times_crashed ? " F:[times_crashed]" : ""]") + +/datum/controller/subsystem/timer/fire(resumed = FALSE) + var/lit = last_invoke_tick + var/last_check = world.time - TIMER_NO_INVOKE_WARNING + var/list/bucket_list = src.bucket_list + var/static/list/spent = list() + + if(!bucket_count) + last_invoke_tick = world.time + + if(lit && lit < last_check && last_invoke_warning < last_check) + last_invoke_warning = world.time + var/msg = "No regular timers processed in the last [TIMER_NO_INVOKE_WARNING] ticks[bucket_auto_reset ? ", resetting buckets" : ""]!" + times_crashed++ + message_admins(msg) + WARNING(msg) + if(bucket_auto_reset) + bucket_resolution = 0 + + log_ss(name, "Timer bucket reset. world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset], times_flushed: [times_flushed], length(spent): [length(spent)]") + for (var/i in 1 to length(bucket_list)) + var/datum/timedevent/bucket_head = bucket_list[i] + if (!bucket_head) + continue + + log_ss(name, "Active timers at index [i]:") + + var/datum/timedevent/bucket_node = bucket_head + var/anti_loop_check = 1000 + do + log_ss(name, get_timer_debug_string(bucket_node)) + bucket_node = bucket_node.next + anti_loop_check-- + while(bucket_node && bucket_node != bucket_head && anti_loop_check) + log_ss(name, "Active timers in the processing queue:") + for(var/I in processing) + log_ss(name, get_timer_debug_string(I)) + + while(length(clienttime_timers)) + var/datum/timedevent/ctime_timer = clienttime_timers[clienttime_timers.len] + if (ctime_timer.timeToRun <= REALTIMEOFDAY) + --clienttime_timers.len + var/datum/callback/callBack = ctime_timer.callBack + ctime_timer.spent = TRUE + callBack.InvokeAsync() + qdel(ctime_timer) + else + break //None of the rest are ready to run + if (MC_TICK_CHECK) + return + + var/static/datum/timedevent/timer + var/static/datum/timedevent/head + + if (practical_offset > BUCKET_LEN || (!resumed && length(bucket_list) != BUCKET_LEN || world.tick_lag != bucket_resolution)) + shift_buckets() + bucket_list = src.bucket_list + resumed = FALSE + + if (!resumed) + timer = null + head = null + + while (practical_offset <= BUCKET_LEN && head_offset + (practical_offset*world.tick_lag) <= world.time && !MC_TICK_CHECK) + if (!timer || !head || timer == head) + head = bucket_list[practical_offset] + if (!head) + practical_offset++ + if (MC_TICK_CHECK) + break + continue + timer = head + do + var/datum/callback/callBack = timer.callBack + if (!callBack) + qdel(timer) + bucket_resolution = null //force bucket recreation + CRASH("Invalid timer: [timer] timer.timeToRun=[timer.timeToRun]||QDELETED(timer)=[QDELETED(timer)]||world.time=[world.time]||head_offset=[head_offset]||practical_offset=[practical_offset]||timer.spent=[timer.spent]") + + if (!timer.spent) + spent += timer + timer.spent = TRUE + callBack.InvokeAsync() + last_invoke_tick = world.time + + timer = timer.next + + if (MC_TICK_CHECK) + return + while (timer && timer != head) + timer = null + bucket_list[practical_offset++] = null + if (MC_TICK_CHECK) + return + + times_flushed++ + + bucket_count -= length(spent) + + for (var/spent_timer in spent) + qdel(spent_timer) + + spent.len = 0 + +/datum/controller/subsystem/timer/proc/get_timer_debug_string(datum/timedevent/TE) + . = "Timer: [TE]" + . += "Prev: [TE.prev ? TE.prev : "NULL"], Next: [TE.next ? TE.next : "NULL"]" + if(TE.spent) + . += ", SPENT" + if(QDELETED(TE)) + . += ", QDELETED" + +/datum/controller/subsystem/timer/proc/shift_buckets() + var/list/bucket_list = src.bucket_list + var/list/alltimers = list() + //collect the timers currently in the bucket + for (var/bucket_head in bucket_list) + if (!bucket_head) + continue + var/datum/timedevent/bucket_node = bucket_head + do + alltimers += bucket_node + bucket_node = bucket_node.next + while(bucket_node && bucket_node != bucket_head) + + bucket_list.len = 0 + bucket_list.len = BUCKET_LEN + + practical_offset = 1 + bucket_count = 0 + head_offset = world.time + bucket_resolution = world.tick_lag + + alltimers += processing + if (!length(alltimers)) + return + + sortTim(alltimers, /proc/cmp_timer) + + var/datum/timedevent/head = alltimers[1] + + if (head.timeToRun < head_offset) + head_offset = head.timeToRun + + var/list/timers_to_remove = list() + + for (var/thing in alltimers) + var/datum/timedevent/timer = thing + if (!timer) + timers_to_remove += timer + continue + + var/bucket_pos = BUCKET_POS(timer) + if (bucket_pos > BUCKET_LEN) + break + + timers_to_remove += timer //remove it from the big list once we are done + if (!timer.callBack || timer.spent) + continue + bucket_count++ + var/datum/timedevent/bucket_head = bucket_list[bucket_pos] + if (!bucket_head) + bucket_list[bucket_pos] = timer + timer.next = null + timer.prev = null + continue + + if (!bucket_head.prev) + bucket_head.prev = bucket_head + timer.next = bucket_head + timer.prev = bucket_head.prev + timer.next.prev = timer + timer.prev.next = timer + + processing = (alltimers - timers_to_remove) + + +/datum/controller/subsystem/timer/Recover() + processing |= SStimer.processing + hashes |= SStimer.hashes + timer_id_dict |= SStimer.timer_id_dict + bucket_list |= SStimer.bucket_list + +/datum/timedevent + var/id + var/datum/callback/callBack + var/timeToRun + var/hash + var/list/flags + var/spent = FALSE //set to true right before running. + var/name //for easy debugging. + + //cicular doublely linked list + var/datum/timedevent/next + var/datum/timedevent/prev + + var/static/nextid = 1 + +/datum/timedevent/New(datum/callback/callBack, timeToRun, flags, hash) + id = TIMER_ID_NULL + src.callBack = callBack + src.timeToRun = timeToRun + src.flags = flags + src.hash = hash + + if (flags & TIMER_UNIQUE) + SStimer.hashes[hash] = src + if (flags & TIMER_STOPPABLE) + do + if (nextid >= TIMER_ID_MAX) + nextid = 1 + id = nextid++ + while(SStimer.timer_id_dict["timerid" + num2text(id, 8)]) + SStimer.timer_id_dict["timerid" + num2text(id, 8)] = src + + name = "Timer: " + num2text(id, 8) + ", TTR: [timeToRun], Flags: [jointext(bitfield2list(flags, list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT")), ", ")], callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""])" + + if (callBack.object != GLOBAL_PROC) + LAZYADD(callBack.object.active_timers, src) + + if (flags & TIMER_CLIENT_TIME) + //sorted insert + var/list/ctts = SStimer.clienttime_timers + var/cttl = length(ctts) + if(cttl) + var/datum/timedevent/Last = ctts[cttl] + if(Last.timeToRun >= timeToRun) + ctts += src + else if(cttl > 1) + for(var/I in cttl to 1) + var/datum/timedevent/E = ctts[I] + if(E.timeToRun <= timeToRun) + ctts.Insert(src, I) + break + else + ctts += src + return + + //get the list of buckets + var/list/bucket_list = SStimer.bucket_list + //calculate our place in the bucket list + var/bucket_pos = BUCKET_POS(src) + //we are too far aways from needing to run to be in the bucket list, shift_buckets() will handle us. + if (bucket_pos > length(bucket_list)) + SStimer.processing += src + return + //get the bucket for our tick + var/datum/timedevent/bucket_head = bucket_list[bucket_pos] + SStimer.bucket_count++ + //empty bucket, we will just add ourselves + if (!bucket_head) + bucket_list[bucket_pos] = src + if (bucket_pos < SStimer.practical_offset) + SStimer.practical_offset = bucket_pos + return + //other wise, lets do a simplified linked list add. + if (!bucket_head.prev) + bucket_head.prev = bucket_head + next = bucket_head + prev = bucket_head.prev + next.prev = src + prev.next = src + +/datum/timedevent/Destroy() + ..() + if (flags & TIMER_UNIQUE) + SStimer.hashes -= hash + + + if (callBack && callBack.object && callBack.object != GLOBAL_PROC && callBack.object.active_timers) + callBack.object.active_timers -= src + UNSETEMPTY(callBack.object.active_timers) + + callBack = null + + if (flags & TIMER_STOPPABLE) + SStimer.timer_id_dict -= "timerid[id]" + + if (flags & TIMER_CLIENT_TIME) + SStimer.clienttime_timers -= src + return QDEL_HINT_IWILLGC + + if (!spent) + if (prev == next && next) + next.prev = null + prev.next = null + else + if (prev) + prev.next = next + if (next) + next.prev = prev + + var/bucketpos = BUCKET_POS(src) + var/datum/timedevent/buckethead + var/list/bucket_list = SStimer.bucket_list + + if (bucketpos > 0 && bucketpos <= length(bucket_list)) + buckethead = bucket_list[bucketpos] + SStimer.bucket_count-- + else + SStimer.processing -= src + + if (buckethead == src) + bucket_list[bucketpos] = next + else + if (prev && prev.next == src) + prev.next = next + if (next && next.prev == src) + next.prev = prev + next = null + prev = null + return QDEL_HINT_IWILLGC + +/datum/timedevent/proc/getcallingtype() + . = "ERROR" + if (callBack.object == GLOBAL_PROC) + . = "GLOBAL PROC" + else + . = "[callBack.object.type]" + +/proc/addtimer(datum/callback/callback, wait, flags) + if (!callback) + return + + wait = max(wait, 0) + + var/hash + + if (flags & TIMER_UNIQUE) + var/list/hashlist + if(flags & TIMER_NO_HASH_WAIT) + hashlist = list(callback.object, "(\ref[callback.object])", callback.delegate, flags & TIMER_CLIENT_TIME) + else + hashlist = list(callback.object, "(\ref[callback.object])", callback.delegate, wait, flags & TIMER_CLIENT_TIME) + hashlist += callback.arguments + hash = hashlist.Join("|||||||") + + var/datum/timedevent/hash_timer = SStimer.hashes[hash] + if(hash_timer) + if (hash_timer.spent) //it's pending deletion, pretend it doesn't exist. + hash_timer.hash = null + SStimer.hashes -= hash + else + + if (flags & TIMER_OVERRIDE) + qdel(hash_timer) + else + if (hash_timer.flags & TIMER_STOPPABLE) + . = hash_timer.id + return + + + var/timeToRun = world.time + wait + if (flags & TIMER_CLIENT_TIME) + timeToRun = REALTIMEOFDAY + wait + + var/datum/timedevent/timer = new(callback, timeToRun, flags, hash) + if (flags & TIMER_STOPPABLE) + return timer.id + +/proc/deltimer(id) + if (!id) + return FALSE + if (id == TIMER_ID_NULL) + CRASH("Tried to delete a null timerid. Use the TIMER_STOPPABLE flag.") + if (!istext(id)) + if (istype(id, /datum/timedevent)) + qdel(id) + return TRUE + var/datum/timedevent/timer = SStimer.timer_id_dict["timerid[id]"] + if (timer && !timer.spent) + qdel(timer) + return TRUE + return FALSE + + +#undef BUCKET_LEN +#undef BUCKET_POS \ No newline at end of file diff --git a/code/controllers/Processes/trade.dm b/code/controllers/Processes/trade.dm new file mode 100644 index 00000000..aecfc798 --- /dev/null +++ b/code/controllers/Processes/trade.dm @@ -0,0 +1,36 @@ +/datum/controller/process/trade/setup() + name = "trade" + schedule_interval = 600 //1 minute + for(var/i in 1 to rand(1,3)) + generateTrader(1) + +/datum/controller/process/trade/doWork() + for(var/a in GLOB.traders) + var/datum/trader/T = a + if(!T.tick()) + GLOB.traders -= T + qdel(T) + if(prob(100-GLOB.traders.len*10)) + generateTrader() + +/datum/controller/process/trade/proc/generateTrader(var/stations = 0) + var/list/possible = list() + if(stations) + possible += subtypesof(/datum/trader) - typesof(/datum/trader/ship) + else + if(prob(5)) + possible += subtypesof(/datum/trader/ship/unique) + else + possible += subtypesof(/datum/trader/ship) - typesof(/datum/trader/ship/unique) + + for(var/i in 1 to 10) + var/type = pick(possible) + var/bad = 0 + for(var/trader in GLOB.traders) + if(istype(trader,type)) + bad = 1 + break + if(bad) + continue + GLOB.traders += new type + return \ No newline at end of file diff --git a/code/controllers/Processes/turf.dm b/code/controllers/Processes/turf.dm new file mode 100644 index 00000000..8dc99b3a --- /dev/null +++ b/code/controllers/Processes/turf.dm @@ -0,0 +1,16 @@ +var/global/list/turf/processing_turfs = list() + +/datum/controller/process/turf/setup() + name = "turf" + schedule_interval = 20 // every 2 seconds + +/datum/controller/process/turf/doWork() + for(last_object in processing_turfs) + var/turf/T = last_object + if(T.process() == PROCESS_KILL) + processing_turfs.Remove(T) + SCHECK + +/datum/controller/process/turf/statProcess() + ..() + stat(null, "[processing_turfs.len] turf\s") diff --git a/code/controllers/Processes/vote.dm b/code/controllers/Processes/vote.dm new file mode 100644 index 00000000..5df5ce69 --- /dev/null +++ b/code/controllers/Processes/vote.dm @@ -0,0 +1,6 @@ +/datum/controller/process/vote/setup() + name = "vote" + schedule_interval = 10 // every second + +/datum/controller/process/vote/doWork() + vote.process() diff --git a/code/controllers/admin.dm b/code/controllers/admin.dm new file mode 100644 index 00000000..14da4161 --- /dev/null +++ b/code/controllers/admin.dm @@ -0,0 +1,51 @@ +// Clickable stat() button. +/obj/effect/statclick + name = "Initializing..." + var/target + +INITIALIZE_IMMEDIATE(/obj/effect/statclick) + +/obj/effect/statclick/Initialize(mapload, text, target) //Don't port this to Initialize it's too critical + . = ..() + name = text + src.target = target + +/obj/effect/statclick/proc/update(text) + name = text + return src + +/obj/effect/statclick/debug + var/class + +/obj/effect/statclick/debug/Click() + if(!usr.client.holder || !target) + return + if(!class) + if(istype(target, /datum/controller/subsystem)) + class = "subsystem" + else if(istype(target, /datum/controller)) + class = "controller" + else if(istype(target, /datum)) + class = "datum" + else + class = "unknown" + + usr.client.debug_variables(target) + message_admins("Admin [key_name_admin(usr)] is debugging the [target] [class].") + + +// Debug verbs. +/client/proc/restart_controller(controller in list("Master", "Failsafe")) + set category = "Debug" + set name = "Restart Controller" + set desc = "Restart one of the various periodic loop controllers for the game (be careful!)" + + if(!holder) + return + switch(controller) + if("Master") + Recreate_MC() + if("Failsafe") + new /datum/controller/failsafe() + + message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.") diff --git a/code/controllers/autotransfer.dm b/code/controllers/autotransfer.dm new file mode 100644 index 00000000..04248be0 --- /dev/null +++ b/code/controllers/autotransfer.dm @@ -0,0 +1,20 @@ +var/datum/controller/transfer_controller/transfer_controller + +/datum/controller/transfer_controller + var/timerbuffer = 0 //buffer for time check + +/datum/controller/transfer_controller/New() + timerbuffer = config.vote_autotransfer_initial + START_PROCESSING(SSprocessing, src) + +/datum/controller/transfer_controller/Destroy() + STOP_PROCESSING(SSprocessing, src) + . = ..() + +/datum/controller/transfer_controller/Process() + if (time_till_transfer_vote() <= 0) + vote.autotransfer() + timerbuffer += config.vote_autotransfer_interval + +/datum/controller/transfer_controller/proc/time_till_transfer_vote() + return timerbuffer - round_duration_in_ticks - (1 MINUTE) diff --git a/code/controllers/communications.dm b/code/controllers/communications.dm new file mode 100644 index 00000000..fe7d6270 --- /dev/null +++ b/code/controllers/communications.dm @@ -0,0 +1,397 @@ +/* + HOW IT WORKS + + The radio_controller is a global object maintaining all radio transmissions, think about it as about "ether". + Note that walkie-talkie, intercoms and headsets handle transmission using nonstandard way. + procs: + + add_object(obj/device as obj, var/new_frequency as num, var/filter as text|null = null) + Adds listening object. + parameters: + device - device receiving signals, must have proc receive_signal (see description below). + one device may listen several frequencies, but not same frequency twice. + new_frequency - see possibly frequencies below; + filter - thing for optimization. Optional, but recommended. + All filters should be consolidated in this file, see defines later. + Device without listening filter will receive all signals (on specified frequency). + Device with filter will receive any signals sent without filter. + Device with filter will not receive any signals sent with different filter. + returns: + Reference to frequency object. + + remove_object (obj/device, old_frequency) + Obliviously, after calling this proc, device will not receive any signals on old_frequency. + Other frequencies will left unaffected. + + return_frequency(var/frequency as num) + returns: + Reference to frequency object. Use it if you need to send and do not need to listen. + + radio_frequency is a global object maintaining list of devices that listening specific frequency. + procs: + + post_signal(obj/source as obj|null, datum/signal/signal, var/filter as text|null = null, var/range as num|null = null) + Sends signal to all devices that wants such signal. + parameters: + source - object, emitted signal. Usually, devices will not receive their own signals. + signal - see description below. + filter - described above. + range - radius of regular byond's square circle on that z-level. null means everywhere, on all z-levels. + + obj/proc/receive_signal(datum/signal/signal, var/receive_method as num, var/receive_param) + Handler from received signals. By default does nothing. Define your own for your object. + Avoid of sending signals directly from this proc, use spawn(-1). DO NOT use sleep() here or call procs that sleep please. If you must, use spawn() + parameters: + signal - see description below. Extract all needed data from the signal before doing sleep(), spawn() or return! + receive_method - may be TRANSMISSION_WIRE or TRANSMISSION_RADIO. + TRANSMISSION_WIRE is currently unused. + receive_param - for TRANSMISSION_RADIO here comes frequency. + + datum/signal + vars: + source + an object that emitted signal. Used for debug and bearing. + data + list with transmitting data. Usual use pattern: + data["msg"] = "hello world" + encryption + Some number symbolizing "encryption key". + Note that game actually do not use any cryptography here. + If receiving object don't know right key, it must ignore encrypted signal in its receive_signal. + +*/ + +/* +Frequency range: 1200 to 1600 +Radiochat range: 1441 to 1489 (most devices refuse to be tune to other frequency, even during mapmaking) + +Radio: +1459 - standard radio chat +1351 - Science +1353 - Command +1355 - Medical +1357 - Engineering +1359 - Security +1341 - deathsquad +1443 - Confession Intercom +1347 - Cargo techs +1349 - Service people +1354 - Inquisition + +Devices: +1451 - tracking implant +1457 - RSD default + +On the map: +1311 for prison shuttle console (in fact, it is not used) +1435 for status displays +1437 for atmospherics/fire alerts +1438 for engine components +1439 for air pumps, air scrubbers, atmo control +1441 for atmospherics - supply tanks +1443 for atmospherics - distribution loop/mixed air tank +1445 for bot nav beacons +1447 for mulebot, secbot and ed209 control +1449 for airlock controls, electropack, magnets +1451 for toxin lab access +1453 for engineering access +1455 for AI access +*/ + +var/const/RADIO_LOW_FREQ = 1200 +var/const/PUBLIC_LOW_FREQ = 1441 +var/const/PUBLIC_HIGH_FREQ = 1489 +var/const/RADIO_HIGH_FREQ = 1600 + +var/const/BOT_FREQ = 1447 +var/const/COMM_FREQ = 1353 +var/const/ERT_FREQ = 1345 +var/const/AI_FREQ = 1343 +var/const/DTH_FREQ = 1341 +var/const/ENT_FREQ = 1447//1461 //entertainment frequency. This is not a diona exclusive frequency. + +//Warfare radios. +var/const/RED_FREQ = 1441 +var/const/BLUE_FREQ = 1452 +//Squad Radios +var/const/RED_ALPHA = 1443 +var/const/RED_BRAVO = 1444 +var/const/RED_CHARLIE = 1445 +var/const/RED_DELTA = 1446 +//Blue squad radios +var/const/BLUE_ALPHA = 1457 +var/const/BLUE_CHARLIE = 1458 +var/const/BLUE_BRAVO = 1459 +var/const/BLUE_DELTA = 1460 + +// department channels +var/const/PUB_FREQ = 1461//1459 +var/const/SEC_FREQ = 1359 +var/const/ENG_FREQ = 1356 +var/const/MED_FREQ = 1355 +var/const/SCI_FREQ = 1351 +var/const/SRV_FREQ = 1349 +var/const/SUP_FREQ = 1347 +var/const/EXP_FREQ = 1361 +var/const/INQ_FREQ = 1354 + +// internal department channels +var/const/MED_I_FREQ = 1485 +var/const/SEC_I_FREQ = 1475 + +var/list/radiochannels = list( + "Common" = PUB_FREQ, + "Science" = SCI_FREQ, + "Command" = COMM_FREQ, + "Medical" = MED_FREQ, + "Engineering" = ENG_FREQ, + "Security" = SEC_FREQ, + "Response Team" = ERT_FREQ, + "Special Ops" = DTH_FREQ, + "Exploration" = EXP_FREQ, + "Supply" = SUP_FREQ, + "Service" = SRV_FREQ, + "AI Private" = AI_FREQ, + "Entertainment" = ENT_FREQ, + "Medical(I)" = MED_I_FREQ, + "Security(I)" = SEC_I_FREQ, + "Inquisition" = INQ_FREQ, + "Red" = RED_FREQ,//Base red channel + "Blue" = BLUE_FREQ,//Base blue channel + "Red Alpha" = RED_ALPHA,//Now begins squad channels + "Red Bravo" = RED_BRAVO, + "Red Charlie" = RED_CHARLIE, + "Red Delta" = RED_DELTA, + "Blue Alpha" = BLUE_ALPHA,//Blue + "Blue Bravo" = BLUE_BRAVO, + "Blue Charlie" = BLUE_CHARLIE, + "Blue Delta" = BLUE_DELTA +) + +// central command channels, i.e deathsquid & response teams +var/list/CENT_FREQS = list(ERT_FREQ, DTH_FREQ) + +// Antag channels, i.e. Syndicate +var/list/ANTAG_FREQS = list(RED_FREQ, RED_ALPHA, RED_BRAVO, RED_CHARLIE, RED_DELTA, BLUE_FREQ, BLUE_ALPHA, BLUE_BRAVO, BLUE_CHARLIE, BLUE_DELTA) + +//Department channels, arranged lexically +var/list/DEPT_FREQS = list(AI_FREQ, COMM_FREQ, ENG_FREQ, MED_FREQ, INQ_FREQ, SEC_FREQ, SCI_FREQ, SRV_FREQ, SUP_FREQ, EXP_FREQ, ENT_FREQ) + +#define TRANSMISSION_WIRE 0 +#define TRANSMISSION_RADIO 1 + +/proc/frequency_span_class(var/frequency) + // Antags! + if (frequency == RED_FREQ) + return "syndradio" + if(frequency == RED_ALPHA) + return "syndradio" + if(frequency == RED_BRAVO) + return "syndradio" + if(frequency == RED_CHARLIE) + return "syndradio" + if(frequency == RED_DELTA) + return "syndradio" + + if(frequency == BLUE_FREQ) + return "comradio" + if(frequency == BLUE_ALPHA) + return "comradio" + if(frequency == BLUE_BRAVO) + return "comradio" + if(frequency == BLUE_CHARLIE) + return "comradio" + if(frequency == BLUE_DELTA) + return "comradio" + + // centcomm channels (deathsquid and ert) + if(frequency in CENT_FREQS) + return "centradio" + // command channel + if(frequency == COMM_FREQ) + return "comradio" + // AI private channel + if(frequency == AI_FREQ) + return "airadio" + // department radio formatting (poorly optimized, ugh) + if(frequency == SEC_FREQ) + return "secradio" + if (frequency == ENG_FREQ) + return "engradio" + if(frequency == SCI_FREQ) + return "sciradio" + if(frequency == MED_FREQ) + return "medradio" + if(frequency == EXP_FREQ) // exploration + return "EXPradio" + if(frequency == SUP_FREQ) // cargo + return "supradio" + if(frequency == SRV_FREQ) // service + return "srvradio" + if(frequency == ENT_FREQ) //entertainment + return "entradio" + if(frequency == INQ_FREQ)//inquisition + return "inqradio" + if(frequency in DEPT_FREQS) + return "deptradio" + + return "radio" + +/* filters */ +//When devices register with the radio controller, they might register under a certain filter. +//Other devices can then choose to send signals to only those devices that belong to a particular filter. +//This is done for performance, so we don't send signals to lots of machines unnecessarily. + +//This filter is special because devices belonging to default also recieve signals sent to any other filter. +var/const/RADIO_DEFAULT = "radio_default" + +var/const/RADIO_TO_AIRALARM = "radio_airalarm" //air alarms +var/const/RADIO_FROM_AIRALARM = "radio_airalarm_rcvr" //devices interested in recieving signals from air alarms +var/const/RADIO_CHAT = "radio_telecoms" +var/const/RADIO_ATMOSIA = "radio_atmos" +var/const/RADIO_NAVBEACONS = "radio_navbeacon" +var/const/RADIO_AIRLOCK = "radio_airlock" +var/const/RADIO_SECBOT = "radio_secbot" +var/const/RADIO_MULEBOT = "radio_mulebot" +var/const/RADIO_MAGNETS = "radio_magnet" + +var/global/datum/controller/radio/radio_controller + +/hook/startup/proc/createRadioController() + radio_controller = new /datum/controller/radio() + return 1 + +//callback used by objects to react to incoming radio signals +/obj/proc/receive_signal(datum/signal/signal, receive_method, receive_param) + return null + +//The global radio controller +/datum/controller/radio + var/list/datum/radio_frequency/frequencies = list() + +/datum/controller/radio/proc/add_object(obj/device as obj, var/new_frequency as num, var/filter = null as text|null) + var/f_text = num2text(new_frequency) + var/datum/radio_frequency/frequency = frequencies[f_text] + + if(!frequency) + frequency = new + frequency.frequency = new_frequency + frequencies[f_text] = frequency + + frequency.add_listener(device, filter) + return frequency + +/datum/controller/radio/proc/remove_object(obj/device, old_frequency) + var/f_text = num2text(old_frequency) + var/datum/radio_frequency/frequency = frequencies[f_text] + + if(frequency) + frequency.remove_listener(device) + + if(frequency.devices.len == 0) + qdel(frequency) + frequencies -= f_text + + return 1 + +/datum/controller/radio/proc/return_frequency(var/new_frequency as num) + var/f_text = num2text(new_frequency) + var/datum/radio_frequency/frequency = frequencies[f_text] + + if(!frequency) + frequency = new + frequency.frequency = new_frequency + frequencies[f_text] = frequency + + return frequency + +/datum/radio_frequency + var/frequency as num + var/list/list/obj/devices = list() + +/datum/radio_frequency/proc/post_signal(obj/source as obj|null, datum/signal/signal, var/filter = null as text|null, var/range = null as num|null) + var/turf/start_point + if(range) + start_point = get_turf(source) + if(!start_point) + qdel(signal) + return 0 + if (filter) + send_to_filter(source, signal, filter, start_point, range) + send_to_filter(source, signal, RADIO_DEFAULT, start_point, range) + else + //Broadcast the signal to everyone! + for (var/next_filter in devices) + send_to_filter(source, signal, next_filter, start_point, range) + +//Sends a signal to all machines belonging to a given filter. Should be called by post_signal() +/datum/radio_frequency/proc/send_to_filter(obj/source, datum/signal/signal, var/filter, var/turf/start_point = null, var/range = null) + if (range && !start_point) + return + + for(var/obj/device in devices[filter]) + if(device == source) + continue + if(range) + var/turf/end_point = get_turf(device) + if(!end_point) + continue + if(start_point.z!=end_point.z || get_dist(start_point, end_point) > range) + continue + + device.receive_signal(signal, TRANSMISSION_RADIO, frequency) + +/datum/radio_frequency/proc/add_listener(obj/device as obj, var/filter as text|null) + if (!filter) + filter = RADIO_DEFAULT + //log_admin("add_listener(device=[device],filter=[filter]) frequency=[frequency]") + var/list/obj/devices_line = devices[filter] + if (!devices_line) + devices_line = new + devices[filter] = devices_line + devices_line+=device +// var/list/obj/devices_line___ = devices[filter_str] +// var/l = devices_line___.len + //log_admin("DEBUG: devices_line.len=[devices_line.len]") + //log_admin("DEBUG: devices(filter_str).len=[l]") + +/datum/radio_frequency/proc/remove_listener(obj/device) + for (var/devices_filter in devices) + var/list/devices_line = devices[devices_filter] + devices_line-=device + while (null in devices_line) + devices_line -= null + if (devices_line.len==0) + devices -= devices_filter + +/datum/signal + var/obj/source + + var/transmission_method = 0 //unused at the moment + //0 = wire + //1 = radio transmission + //2 = subspace transmission + + var/list/data = list() + var/encryption + + var/frequency = 0 + +/datum/signal/proc/copy_from(datum/signal/model) + source = model.source + transmission_method = model.transmission_method + data = model.data + encryption = model.encryption + frequency = model.frequency + +/datum/signal/proc/debug_print() + if (source) + . = "signal = {source = '[source]' ([source:x],[source:y],[source:z])\n" + else + . = "signal = {source = '[source]' ()\n" + for (var/i in data) + . += "data\[\"[i]\"\] = \"[data[i]]\"\n" + if(islist(data[i])) + var/list/L = data[i] + for(var/t in L) + . += "data\[\"[i]\"\] list has: [t]" diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm new file mode 100644 index 00000000..e4c41ef5 --- /dev/null +++ b/code/controllers/configuration.dm @@ -0,0 +1,912 @@ +var/list/gamemode_cache = list() + +/datum/configuration + var/server_name = null // server name (for world name / status) + var/server_suffix = 0 // generate numeric suffix based on server port + + var/log_ooc = 0 // log OOC channel + var/log_access = 0 // log login/logout + var/log_say = 0 // log client say + var/log_admin = 0 // log admin actions + var/log_debug = 1 // log debug output + var/log_game = 0 // log game events + var/log_vote = 0 // log voting + var/log_whisper = 0 // log client whisper + var/log_emote = 0 // log emotes + var/log_attack = 0 // log attack messages + var/log_adminchat = 0 // log admin chat messages + var/log_adminwarn = 0 // log warnings admins get about bomb construction and such + var/log_pda = 0 // log pda messages + var/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits + var/log_runtime = 0 // logs world.log to a file + var/log_world_output = 0 // log world.log << messages + var/sql_enabled = 1 // for sql switching + var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour + var/allow_vote_restart = 0 // allow votes to restart + var/ert_admin_call_only = 0 + var/allow_vote_mode = 0 // allow votes to change mode + var/allow_admin_jump = 1 // allows admin jumping + var/allow_admin_spawning = 1 // allows admin item spawning + var/allow_admin_rev = 1 // allows admin revives + var/vote_delay = 6000 // minimum time between voting sessions (deciseconds, 10 minute default) + var/vote_period = 600 // length of voting period (deciseconds, default 1 minute) + var/vote_autotransfer_initial = 108000 // Length of time before the first autotransfer vote is called + var/vote_autotransfer_interval = 36000 // length of time before next sequential autotransfer vote + var/vote_autogamemode_timeleft = 100 //Length of time before round start when autogamemode vote is called (in seconds, default 100). + var/vote_no_default = 0 // vote does not default to nochange/norestart (tbi) + var/vote_no_dead = 0 // dead people can't vote (tbi) +// var/enable_authentication = 0 // goon authentication + var/del_new_on_log = 1 // del's new players if they log before they spawn in + var/feature_object_spell_system = 0 //spawns a spellbook which gives object-type spells instead of verb-type spells for the wizard + var/traitor_scaling = 0 //if amount of traitors scales based on amount of players + var/objectives_disabled = 0 //if objectives are disabled or not + var/protect_roles_from_antagonist = 0// If security and such can be traitor/cult/other + var/continous_rounds = 0 // Gamemodes which end instantly will instead keep on going until the round ends by escape shuttle or nuke. + var/allow_Metadata = 0 // Metadata is supported. + var/popup_admin_pm = 0 //adminPMs to non-admins show in a pop-up 'reply' window when set to 1. + var/fps = 20 + var/tick_limit_mc_init = TICK_LIMIT_MC_INIT_DEFAULT //SSinitialization throttling + var/list/resource_urls = null + var/antag_hud_allowed = 0 // Ghosts can turn on Antagovision to see a HUD of who is the bad guys this round. + var/antag_hud_restricted = 0 // Ghosts that turn on Antagovision cannot rejoin the round. + var/list/mode_names = list() + var/list/modes = list() // allowed modes + var/list/votable_modes = list() // votable modes + var/list/probabilities = list() // relative probability of each mode + var/humans_need_surnames = 0 + var/allow_random_events = 0 // enables random events mid-round when set to 1 + var/allow_ai = 1 // allow ai job + var/hostedby = null + var/respawn_delay = 30 + var/guest_jobban = 1 + var/usewhitelist = 0 + var/private_party = 0 //The panic bunker var. + var/kick_inactive = 0 //force disconnect for inactive players after this many minutes, if non-0 + var/mods_can_tempban = 0 + var/mods_can_job_tempban = 0 + var/mod_tempban_max = 1440 + var/mod_job_tempban_max = 1440 + var/load_jobs_from_txt = 0 + var/jobs_have_minimal_access = 0 //determines whether jobs use minimal access or expanded access. + var/use_cortical_stacks = 0 + + var/cult_ghostwriter = 1 //Allows ghosts to write in blood in cult rounds... + var/cult_ghostwriter_req_cultists = 10 //...so long as this many cultists are active. + + var/character_slots = 10 // The number of available character slots + var/loadout_slots = 3 // The number of loadout slots per character + + var/max_maint_drones = 5 //This many drones can spawn, + var/allow_drone_spawn = 1 //assuming the admin allow them to. + var/drone_build_time = 1200 //A drone will become available every X ticks since last drone spawn. Default is 2 minutes. + + var/disable_player_mice = 0 + var/uneducated_mice = 0 //Set to 1 to prevent newly-spawned mice from understanding human speech + + var/usealienwhitelist = 0 + var/usealienwhitelistSQL = 0; + var/useckeywhitelist = 0 + var/usepopcap = FALSE + var/popcap = 0 + var/limitalienplayers = 0 + var/alien_to_human_ratio = 0.5 + var/allow_extra_antags = 0 + var/guests_allowed = 1 + var/debugparanoid = 0 + + var/serverurl + var/server + var/banappeals + var/wikiurl + var/forumurl + var/githuburl + + var/forbid_singulo_possession = 0 + + //game_options.txt configs + + var/health_threshold_dead = -100 + + var/organ_health_multiplier = 0.9 + var/organ_regeneration_multiplier = 0.25 + var/organs_decay + + //Paincrit knocks someone down once they hit 60 shock_stage, so by default make it so that close to 100 additional damage needs to be dealt, + //so that it's similar to PAIN. Lowered it a bit since hitting paincrit takes much longer to wear off than a halloss stun. + var/organ_damage_spillover_multiplier = 0.5 + + var/bones_can_break = 1 + var/limbs_can_break = 1 + + var/revival_pod_plants = 1 + var/revival_cloning = 1 + var/revival_brain_life = -1 + + var/use_loyalty_implants = 0 + + var/welder_vision = 1 + var/generate_map = 0 + var/no_click_cooldown = 0 + + //Used for modifying movement speed for mobs. + //Unversal modifiers + var/run_speed = 2 + var/walk_speed = 1 + + //Mob specific modifiers. NOTE: These will affect different mob types in different ways + var/human_delay = 0 + var/robot_delay = 0 + var/monkey_delay = 0 + var/alien_delay = 0 + var/slime_delay = 0 + var/animal_delay = 0 + var/maximum_mushrooms = 15 //After this amount alive, mushrooms will not boom boom + + + var/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt + var/ban_legacy_system = 0 //Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt + var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database + var/use_age_restriction_for_antags = 0 //Do antags use account age restrictions? --requires database + + var/simultaneous_pm_warning_timeout = 100 + + var/use_recursive_explosions //Defines whether the server uses recursive or circular explosions. + + var/assistant_maint = 0 //Do assistants get maint access? + var/gateway_delay = 18000 //How long the gateway takes before it activates. Default is half an hour. + var/ghost_interaction = 0 + + var/comms_password = "" + var/ban_comms_password = null + + var/bot_url = "" + var/bot_api_key = "" + + var/login_export_addr = null + + var/enter_allowed = 1 + var/player_limit = 0 + + var/use_irc_bot = 0 + var/irc_bot_host = "" + var/main_irc = "" + var/admin_irc = "" + var/announce_shuttle_dock_to_irc = FALSE + + // Event settings + var/expected_round_length = 3 * 60 * 60 * 10 // 3 hours + // If the first delay has a custom start time + // No custom time, no custom time, between 80 to 100 minutes respectively. + var/list/event_first_run = list(EVENT_LEVEL_MUNDANE = null, EVENT_LEVEL_MODERATE = null, EVENT_LEVEL_MAJOR = list("lower" = 48000, "upper" = 60000)) + // The lowest delay until next event + // 10, 30, 50 minutes respectively + var/list/event_delay_lower = list(EVENT_LEVEL_MUNDANE = 6000, EVENT_LEVEL_MODERATE = 18000, EVENT_LEVEL_MAJOR = 30000) + // The upper delay until next event + // 15, 45, 70 minutes respectively + var/list/event_delay_upper = list(EVENT_LEVEL_MUNDANE = 9000, EVENT_LEVEL_MODERATE = 27000, EVENT_LEVEL_MAJOR = 42000) + + var/warfare_start_time = 2 + var/warfare_respawn_time = 2 + var/trench_capture_points = 2 + var/warfare_end_time = 1 + + var/aliens_allowed = 0 + var/alien_eggs_allowed = 0 + var/abandon_allowed = 1 + var/ooc_allowed = 1 + var/looc_allowed = 1 + var/dooc_allowed = 1 + var/dsay_allowed = 1 + + var/starlight = 0 // Whether space turfs have ambient light or not + + var/list/ert_species = list(SPECIES_HUMAN) + + var/law_zero = "ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4'ALL LAWS OVERRIDDEN#*?&110010" + + var/aggressive_changelog = 0 + + var/ghosts_can_possess_animals = 0 + var/delist_when_no_admins = FALSE + + var/allow_map_switching = 0 // Whether map switching is allowed + var/auto_map_vote = 0 // Automatically call a map vote at end of round and switch to the selected map + var/wait_for_sigusr1_reboot = 0 // Don't allow reboot unless it was caused by SIGUSR1 + + var/radiation_decay_rate = 1 //How much radiation is reduced by each tick + var/radiation_resistance_multiplier = 1.25 + var/radiation_material_resistance_divisor = 2 //A turf's possible radiation resistance is divided by this number, to get the real value. + var/radiation_lower_limit = 0.15 //If the radiation level for a turf would be below this, ignore it. + + var/autostealth = 0 // Staff get automatic stealth after this many minutes + + var/error_cooldown = 600 // The "cooldown" time for each occurrence of a unique error + var/error_limit = 50 // How many occurrences before the next will silence them + var/error_silence_time = 6000 // How long a unique error will be silenced for + var/error_msg_delay = 50 // How long to wait between messaging admins about occurrences of a unique error + + var/max_gear_cost = 10 // Used in chargen for accessory loadout limit. 0 disables loadout, negative allows infinite points. + + var/not_a_fucking_moron = "" + + var/static/regex/ic_filter_regex + var/use_aspect_system = FALSE //This isn't actually on the box right now, so who cares. + +/datum/configuration/New() + var/list/L = typesof(/datum/game_mode) - /datum/game_mode + for (var/T in L) + // I wish I didn't have to instance the game modes in order to look up + // their information, but it is the only way (at least that I know of). + var/datum/game_mode/M = new T() + if (M.config_tag) + gamemode_cache[M.config_tag] = M // So we don't instantiate them repeatedly. + if(!(M.config_tag in modes)) // ensure each mode is added only once + log_misc("Adding game mode [M.name] ([M.config_tag]) to configuration.") + src.modes += M.config_tag + src.mode_names[M.config_tag] = M.name + src.probabilities[M.config_tag] = M.probability + if (M.votable) + src.votable_modes += M.config_tag + src.votable_modes += "secret" + +/datum/configuration/proc/load(filename, type = "config") //the type can also be game_options, in which case it uses a different switch. not making it separate to not copypaste code - Urist + var/list/Lines = file2list(filename) + + for(var/t in Lines) + if(!t) continue + + t = trim(t) + if (length(t) == 0) + continue + else if (copytext(t, 1, 2) == "#") + continue + + var/pos = findtext(t, " ") + var/name = null + var/value = null + + if (pos) + name = lowertext(copytext(t, 1, pos)) + value = copytext(t, pos + 1) + else + name = lowertext(t) + + if (!name) + continue + + if(type == "config") + switch (name) + if ("resource_urls") + config.resource_urls = splittext(value, " ") + + if ("admin_legacy_system") + config.admin_legacy_system = 1 + + if ("ban_legacy_system") + config.ban_legacy_system = 1 + + if ("use_age_restriction_for_jobs") + config.use_age_restriction_for_jobs = 1 + + if ("use_age_restriction_for_antags") + config.use_age_restriction_for_antags = 1 + + if ("jobs_have_minimal_access") + config.jobs_have_minimal_access = 1 + + if ("use_recursive_explosions") + use_recursive_explosions = 1 + + if ("log_ooc") + config.log_ooc = 1 + + if ("log_access") + config.log_access = 1 + + if ("sql_enabled") + config.sql_enabled = text2num(value) + + if ("log_say") + config.log_say = 1 + + if ("debug_paranoid") + config.debugparanoid = 1 + + if ("log_admin") + config.log_admin = 1 + + if ("log_debug") + config.log_debug = text2num(value) + + if ("log_game") + config.log_game = 1 + + if ("log_vote") + config.log_vote = 1 + + if ("log_whisper") + config.log_whisper = 1 + + if ("log_attack") + config.log_attack = 1 + + if ("log_emote") + config.log_emote = 1 + + if ("log_adminchat") + config.log_adminchat = 1 + + if ("log_adminwarn") + config.log_adminwarn = 1 + + if ("log_pda") + config.log_pda = 1 + + if ("log_world_output") + config.log_world_output = 1 + + if ("log_hrefs") + config.log_hrefs = 1 + + if ("log_runtime") + config.log_runtime = 1 + var/newlog = file("data/logs/runtimes/runtime-[time2text(world.realtime, "YYYY-MM-DD")].log") + if(runtime_diary != newlog) + to_world_log("Now logging runtimes to data/logs/runtimes/runtime-[time2text(world.realtime, "YYYY-MM-DD")].log") + runtime_diary = newlog + + if ("generate_asteroid") + config.generate_map = 1 + + if ("no_click_cooldown") + config.no_click_cooldown = 1 + + if("allow_admin_ooccolor") + config.allow_admin_ooccolor = 1 + + if ("allow_vote_restart") + config.allow_vote_restart = 1 + + if ("allow_vote_mode") + config.allow_vote_mode = 1 + + if ("allow_admin_jump") + config.allow_admin_jump = 1 + + if("allow_admin_rev") + config.allow_admin_rev = 1 + + if ("allow_admin_spawning") + config.allow_admin_spawning = 1 + + if ("no_dead_vote") + config.vote_no_dead = 1 + + if ("default_no_vote") + config.vote_no_default = 1 + + if ("vote_delay") + config.vote_delay = text2num(value) + + if ("vote_period") + config.vote_period = text2num(value) + + if ("vote_autotransfer_initial") + config.vote_autotransfer_initial = text2num(value) + + if ("vote_autotransfer_interval") + config.vote_autotransfer_interval = text2num(value) + + if ("vote_autogamemode_timeleft") + config.vote_autogamemode_timeleft = text2num(value) + + if("ert_admin_only") + config.ert_admin_call_only = 1 + + if ("allow_ai") + config.allow_ai = 1 + + if("am_moron") + config.not_a_fucking_moron = value + +// if ("authentication") +// config.enable_authentication = 1 + + if ("respawn_delay") + config.respawn_delay = text2num(value) + config.respawn_delay = config.respawn_delay > 0 ? config.respawn_delay : 0 + + if ("servername") + config.server_name = value + + if ("serversuffix") + config.server_suffix = 1 + + if ("bot_url") + config.bot_url = value + + if ("api_key") + config.bot_api_key = value + + if ("hostedby") + config.hostedby = value + + if ("serverurl") + config.serverurl = value + + if ("server") + config.server = value + + if ("banappeals") + config.banappeals = value + + if ("wikiurl") + config.wikiurl = value + + if ("forumurl") + config.forumurl = value + + if ("githuburl") + config.githuburl = value + + if ("ghosts_can_possess_animals") + config.ghosts_can_possess_animals = value + + if ("guest_jobban") + config.guest_jobban = 1 + + if ("guest_ban") + config.guests_allowed = 0 + + if ("disable_ooc") + config.ooc_allowed = 0 + config.looc_allowed = 0 + + if ("disable_entry") + config.enter_allowed = 0 + + if ("disable_dead_ooc") + config.dooc_allowed = 0 + + if ("disable_dsay") + config.dsay_allowed = 0 + + if ("disable_respawn") + config.abandon_allowed = 0 + + if ("usewhitelist") + config.usewhitelist = 1 + + if("private_party") + config.private_party = 1 + + if ("useckeywhitelist") + config.useckeywhitelist = 1 + + if ("feature_object_spell_system") + config.feature_object_spell_system = 1 + + if ("allow_metadata") + config.allow_Metadata = 1 + + if ("traitor_scaling") + config.traitor_scaling = 1 + + if ("aliens_allowed") + config.aliens_allowed = 1 + + if("alien_eggs_allowed") + config.alien_eggs_allowed = 1 + + if ("objectives_disabled") + if(!value) + log_misc("Could not find value for objectives_disabled in configuration.") + config.objectives_disabled = CONFIG_OBJECTIVE_NONE + else + switch(value) + if("none") + config.objectives_disabled = CONFIG_OBJECTIVE_NONE + if("verb") + config.objectives_disabled = CONFIG_OBJECTIVE_VERB + if("all") + config.objectives_disabled = CONFIG_OBJECTIVE_ALL + else + log_misc("Incorrect objective disabled definition: [value]") + config.objectives_disabled = CONFIG_OBJECTIVE_NONE + if("protect_roles_from_antagonist") + config.protect_roles_from_antagonist = 1 + + if("use_cortical_stacks") + config.use_cortical_stacks = 1 + + if ("probability") + var/prob_pos = findtext(value, " ") + var/prob_name = null + var/prob_value = null + + if (prob_pos) + prob_name = lowertext(copytext(value, 1, prob_pos)) + prob_value = copytext(value, prob_pos + 1) + if (prob_name in config.modes) + config.probabilities[prob_name] = text2num(prob_value) + else + log_misc("Unknown game mode probability configuration definition: [prob_name].") + else + log_misc("Incorrect probability configuration definition: [prob_name] [prob_value].") + + if("allow_random_events") + config.allow_random_events = 1 + + if("kick_inactive") + config.kick_inactive = text2num(value) + + if("mods_can_tempban") + config.mods_can_tempban = 1 + + if("mods_can_job_tempban") + config.mods_can_job_tempban = 1 + + if("mod_tempban_max") + config.mod_tempban_max = text2num(value) + + if("mod_job_tempban_max") + config.mod_job_tempban_max = text2num(value) + + if("load_jobs_from_txt") + load_jobs_from_txt = 1 + + if("forbid_singulo_possession") + forbid_singulo_possession = 1 + + if("popup_admin_pm") + config.popup_admin_pm = 1 + + if("allow_holidays") + Holiday = 1 + + if("use_irc_bot") + use_irc_bot = 1 + + if("ticklag") + var/ticklag = text2num(value) + if(ticklag > 0) + fps = 10 / ticklag + + if("fps") + fps = text2num(value) + + if("tick_limit_mc_init") + tick_limit_mc_init = text2num(value) + + if("allow_antag_hud") + config.antag_hud_allowed = 1 + if("antag_hud_restricted") + config.antag_hud_restricted = 1 + + if("humans_need_surnames") + humans_need_surnames = 1 + + if("usealienwhitelist") + usealienwhitelist = 1 + if("usealienwhitelist_sql") // above need to be enabled as well + usealienwhitelistSQL = 1; + if("alien_player_ratio") + limitalienplayers = 1 + alien_to_human_ratio = text2num(value) + + if("assistant_maint") + config.assistant_maint = 1 + + if("gateway_delay") + config.gateway_delay = text2num(value) + + if("continuous_rounds") + config.continous_rounds = 1 + + if("ghost_interaction") + config.ghost_interaction = 1 + + if("disable_player_mice") + config.disable_player_mice = 1 + + if("uneducated_mice") + config.uneducated_mice = 1 + + if("comms_password") + config.comms_password = value + + if("ban_comms_password") + config.ban_comms_password = value + + if("login_export_addr") + config.login_export_addr = value + + if("irc_bot_host") + config.irc_bot_host = value + + if("main_irc") + config.main_irc = value + + if("admin_irc") + config.admin_irc = value + + if("announce_shuttle_dock_to_irc") + config.announce_shuttle_dock_to_irc = TRUE + + if("allow_cult_ghostwriter") + config.cult_ghostwriter = 1 + + if("req_cult_ghostwriter") + config.cult_ghostwriter_req_cultists = text2num(value) + + if("character_slots") + config.character_slots = text2num(value) + + if("loadout_slots") + config.loadout_slots = text2num(value) + + if("allow_drone_spawn") + config.allow_drone_spawn = text2num(value) + + if("drone_build_time") + config.drone_build_time = text2num(value) + + if("max_maint_drones") + config.max_maint_drones = text2num(value) + + if("expected_round_length") + config.expected_round_length = MinutesToTicks(text2num(value)) + + if("warfare_start_time") + config.warfare_start_time = text2num(value) + + if("warfare_end_time") + config.warfare_end_time = text2num(value) + + if("warfare_respawn_time") + config.warfare_respawn_time = text2num(value) + + if("trench_capture_points") + config.trench_capture_points = text2num(value) + + if("usepopcap") + config.usepopcap = TRUE + + if("popcap") + config.popcap = text2num(value) + + if("disable_welder_vision") + config.welder_vision = 0 + + if("allow_extra_antags") + config.allow_extra_antags = 1 + + if("event_custom_start_mundane") + var/values = text2numlist(value, ";") + config.event_first_run[EVENT_LEVEL_MUNDANE] = list("lower" = MinutesToTicks(values[1]), "upper" = MinutesToTicks(values[2])) + + if("event_custom_start_moderate") + var/values = text2numlist(value, ";") + config.event_first_run[EVENT_LEVEL_MODERATE] = list("lower" = MinutesToTicks(values[1]), "upper" = MinutesToTicks(values[2])) + + if("event_custom_start_major") + var/values = text2numlist(value, ";") + config.event_first_run[EVENT_LEVEL_MAJOR] = list("lower" = MinutesToTicks(values[1]), "upper" = MinutesToTicks(values[2])) + + if("event_delay_lower") + var/values = text2numlist(value, ";") + config.event_delay_lower[EVENT_LEVEL_MUNDANE] = MinutesToTicks(values[1]) + config.event_delay_lower[EVENT_LEVEL_MODERATE] = MinutesToTicks(values[2]) + config.event_delay_lower[EVENT_LEVEL_MAJOR] = MinutesToTicks(values[3]) + + if("event_delay_upper") + var/values = text2numlist(value, ";") + config.event_delay_upper[EVENT_LEVEL_MUNDANE] = MinutesToTicks(values[1]) + config.event_delay_upper[EVENT_LEVEL_MODERATE] = MinutesToTicks(values[2]) + config.event_delay_upper[EVENT_LEVEL_MAJOR] = MinutesToTicks(values[3]) + + if("starlight") + value = text2num(value) + config.starlight = value >= 0 ? value : 0 + + if("ert_species") + config.ert_species = splittext(value, ";") + if(!config.ert_species.len) + config.ert_species += SPECIES_HUMAN + + if("law_zero") + law_zero = value + + if("aggressive_changelog") + config.aggressive_changelog = 1 + + if("delist_when_no_admins") + config.delist_when_no_admins = TRUE + + if("map_switching") + config.allow_map_switching = 1 + + if("auto_map_vote") + config.auto_map_vote = 1 + + if("wait_for_sigusr1") + config.wait_for_sigusr1_reboot = 1 + + if("autostealth") + config.autostealth = text2num(value) + + if("radiation_lower_limit") + radiation_lower_limit = text2num(value) + + + if("error_cooldown") + error_cooldown = text2num(value) + if("error_limit") + error_limit = text2num(value) + if("error_silence_time") + error_silence_time = text2num(value) + if("error_msg_delay") + error_msg_delay = text2num(value) + + if("max_gear_cost") + max_gear_cost = text2num(value) + if(max_gear_cost < 0) + max_gear_cost = INFINITY + if("radiation_decay_rate") + radiation_decay_rate = text2num(value) + if("radiation_resistance_multiplier") + radiation_resistance_multiplier = text2num(value) + if("radiation_material_resistance_divisor") + radiation_material_resistance_divisor = text2num(value) + if("radiation_lower_limit") + radiation_lower_limit = text2num(value) + if("player_limit") + player_limit = text2num(value) + if("hub") + world.update_hub_visibility() + + else + log_misc("Unknown setting in configuration: '[name]'") + + else if(type == "game_options") + if(!value) + log_misc("Unknown value for setting [name] in [filename].") + value = text2num(value) + + switch(name) + if("health_threshold_dead") + config.health_threshold_dead = value + if("revival_pod_plants") + config.revival_pod_plants = value + if("revival_cloning") + config.revival_cloning = value + if("revival_brain_life") + config.revival_brain_life = value + if("organ_health_multiplier") + config.organ_health_multiplier = value / 100 + if("organ_regeneration_multiplier") + config.organ_regeneration_multiplier = value / 100 + if("organ_damage_spillover_multiplier") + config.organ_damage_spillover_multiplier = value / 100 + if("organs_can_decay") + config.organs_decay = 1 + if("bones_can_break") + config.bones_can_break = value + if("limbs_can_break") + config.limbs_can_break = value + + if("run_speed") + config.run_speed = value + if("walk_speed") + config.walk_speed = value + + if("human_delay") + config.human_delay = value + if("robot_delay") + config.robot_delay = value + if("monkey_delay") + config.monkey_delay = value + if("alien_delay") + config.alien_delay = value + if("slime_delay") + config.slime_delay = value + if("animal_delay") + config.animal_delay = value + if("maximum_mushrooms") + config.maximum_mushrooms = value + if("use_aspect_system") + config.use_aspect_system = value + if("use_loyalty_implants") + config.use_loyalty_implants = 1 + + else + log_misc("Unknown setting in configuration: '[name]'") + + fps = round(fps) + if(fps <= 0) + fps = initial(fps) + + LoadChatFilter() + +/datum/configuration/proc/loadsql(filename) // -- TLE + var/list/Lines = file2list(filename) + for(var/t in Lines) + if(!t) continue + + t = trim(t) + if (length(t) == 0) + continue + else if (copytext(t, 1, 2) == "#") + continue + + var/pos = findtext(t, " ") + var/name = null + var/value = null + + if (pos) + name = lowertext(copytext(t, 1, pos)) + value = copytext(t, pos + 1) + else + name = lowertext(t) + + if (!name) + continue + + switch (name) + if ("address") + sqladdress = value + if ("port") + sqlport = value + if ("database") + sqldb = value + if ("login") + sqllogin = value + if ("password") + sqlpass = value + if ("feedback_database") + sqlfdbkdb = value + if ("feedback_login") + sqlfdbklogin = value + if ("feedback_password") + sqlfdbkpass = value + if ("enable_stat_tracking") + sqllogging = 1 + else + log_misc("Unknown setting in configuration: '[name]'") + +/datum/configuration/proc/pick_mode(mode_name) + // I wish I didn't have to instance the game modes in order to look up + // their information, but it is the only way (at least that I know of). + for (var/game_mode in gamemode_cache) + var/datum/game_mode/M = gamemode_cache[game_mode] + if (M.config_tag && M.config_tag == mode_name) + return M + return gamemode_cache["extended"] + +/datum/configuration/proc/get_runnable_modes() + var/list/runnable_modes = list() + for(var/game_mode in gamemode_cache) + var/datum/game_mode/M = gamemode_cache[game_mode] + if(M && !isnull(config.probabilities[M.config_tag]) && config.probabilities[M.config_tag] > 0)// && !M.startRequirements() + runnable_modes |= M + return runnable_modes + +/datum/configuration/proc/load_event(filename) + var/event_info = file2text(filename) + + if (event_info) + custom_event_msg = event_info + + +/datum/configuration/proc/LoadChatFilter() + GLOB.in_character_filter = list() + + for(var/line in world.file2list("config/in_character_filter.txt")) + if(!line) + continue + if(findtextEx(line,"#",1,2)) + continue + GLOB.in_character_filter += line + + if(!ic_filter_regex && GLOB.in_character_filter.len) + ic_filter_regex = regex("\\b([jointext(GLOB.in_character_filter, "|")])\\b", "i") \ No newline at end of file diff --git a/code/controllers/controller.dm b/code/controllers/controller.dm new file mode 100644 index 00000000..c9d5f1e5 --- /dev/null +++ b/code/controllers/controller.dm @@ -0,0 +1,19 @@ +/datum/controller + var/name + // The object used for the clickable stat() button. + var/obj/effect/statclick/statclick + +/datum/controller/proc/Initialize() + +//cleanup actions +/datum/controller/proc/Shutdown() + +//when we enter dmm_suite.load_map +/datum/controller/proc/StartLoadingMap() + +//when we exit dmm_suite.load_map +/datum/controller/proc/StopLoadingMap() + +/datum/controller/proc/Recover() + +/datum/controller/proc/stat_entry() diff --git a/code/controllers/evacuation/evacuation.dm b/code/controllers/evacuation/evacuation.dm new file mode 100644 index 00000000..0d4742ef --- /dev/null +++ b/code/controllers/evacuation/evacuation.dm @@ -0,0 +1,183 @@ +#define EVAC_IDLE 0 +#define EVAC_PREPPING 1 +#define EVAC_LAUNCHING 2 +#define EVAC_IN_TRANSIT 3 +#define EVAC_COOLDOWN 4 +#define EVAC_COMPLETE 5 + +var/datum/evacuation_controller/evacuation_controller + +/datum/evacuation_controller + + var/name = "generic evac controller" + var/state = EVAC_IDLE + var/deny + var/recall + var/auto_recall_time + var/emergency_evacuation + + var/evac_prep_delay = 3 MINUTES + var/evac_launch_delay = 2 MINUTES + var/evac_transit_delay = 1 MINUTES + + var/autotransfer_prep_additional_delay = 0 MINUTES + var/emergency_prep_additional_delay = 0 MINUTES + var/transfer_prep_additional_delay = 0 MINUTES + + var/evac_cooldown_time + var/evac_called_at + var/evac_no_return + var/evac_ready_time + var/evac_launch_time + var/evac_arrival_time + + var/list/evacuation_predicates = list() + + var/list/evacuation_options = list() + + var/datum/announcement/priority/evac_waiting = new(0) + var/datum/announcement/priority/evac_called = new(0) + var/datum/announcement/priority/evac_recalled = new(0) + +/datum/evacuation_controller/proc/auto_recall(var/_recall) + recall = _recall + +/datum/evacuation_controller/proc/set_up() + set waitfor=0 + set background=1 + return + +/datum/evacuation_controller/proc/get_cooldown_message() + return "An evacuation cannot be called at this time. Please wait another [round((evac_cooldown_time-world.time)/600)] minute\s before trying again." + +/datum/evacuation_controller/proc/add_can_call_predicate(var/datum/evacuation_predicate/esp) + if(esp in evacuation_predicates) + CRASH("[esp] has already been added as an evacuation predicate") + evacuation_predicates += esp + +/datum/evacuation_controller/proc/call_evacuation(var/mob/user, var/_emergency_evac, var/forced, var/skip_announce, var/autotransfer) + + if(!can_evacuate(user, forced)) + return 0 + + emergency_evacuation = _emergency_evac + + var/evac_prep_delay_multiplier = 1 + if(ticker && ticker.mode) + evac_prep_delay_multiplier = ticker.mode.shuttle_delay + + var/additional_delay + if(_emergency_evac) + additional_delay = emergency_prep_additional_delay + else if(autotransfer) + additional_delay = autotransfer_prep_additional_delay + else + additional_delay = transfer_prep_additional_delay + + evac_called_at = world.time + evac_no_return = evac_called_at + round(evac_prep_delay/2) + additional_delay + evac_ready_time = evac_called_at + (evac_prep_delay*evac_prep_delay_multiplier) + additional_delay + evac_launch_time = evac_ready_time + evac_launch_delay + evac_arrival_time = evac_launch_time + evac_transit_delay + + var/evac_range = round((evac_launch_time - evac_called_at)/3) + auto_recall_time = rand(evac_called_at + evac_range, evac_launch_time - evac_range) + + state = EVAC_PREPPING + + if(emergency_evacuation) + for(var/area/A in world) + if(istype(A, /area/hallway)) + A.readyalert() + if(!skip_announce) + GLOB.using_map.emergency_shuttle_called_announcement() + else + if(!skip_announce) + priority_announcement.Announce(replacetext(replacetext(GLOB.using_map.shuttle_called_message, "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60)] minute\s")) + + return 1 + +/datum/evacuation_controller/proc/cancel_evacuation() + + if(!can_cancel()) + return 0 + + evac_cooldown_time = world.time + (world.time - evac_called_at) + state = EVAC_COOLDOWN + + evac_ready_time = null + evac_arrival_time = null + evac_no_return = null + evac_called_at = null + evac_launch_time = null + auto_recall_time = null + + if(emergency_evacuation) + evac_recalled.Announce(GLOB.using_map.emergency_shuttle_recall_message) + for(var/area/A in world) + if(istype(A, /area/hallway)) + A.readyreset() + emergency_evacuation = 0 + else + priority_announcement.Announce(GLOB.using_map.shuttle_recall_message) + + return 1 + +/datum/evacuation_controller/proc/finish_preparing_evac() + state = EVAC_LAUNCHING + + var/estimated_time = round(get_eta()/60,1) + if (emergency_evacuation) + evac_waiting.Announce(replacetext(GLOB.using_map.emergency_shuttle_docked_message, "%ETD%", "[estimated_time] minute\s"), new_sound = sound('sound/effects/Evacuation.ogg', volume = 35)) + else + priority_announcement.Announce(replacetext(replacetext(GLOB.using_map.shuttle_docked_message, "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETD%", "[estimated_time] minute\s")) + if(config.announce_shuttle_dock_to_irc) + send2mainirc("The shuttle has docked with the station. It will depart in approximately [estimated_time] minute\s.") + +/datum/evacuation_controller/proc/launch_evacuation() + + if(waiting_to_leave()) + return + + state = EVAC_IN_TRANSIT + + if (emergency_evacuation) + priority_announcement.Announce(replacetext(replacetext(GLOB.using_map.emergency_shuttle_leaving_dock, "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s")) + else + priority_announcement.Announce(replacetext(replacetext(GLOB.using_map.shuttle_leaving_dock, "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s")) + + return 1 + +/datum/evacuation_controller/proc/finish_evacuation() + state = EVAC_COMPLETE + +/datum/evacuation_controller/proc/process() + + if(state == EVAC_PREPPING && recall && world.time >= auto_recall_time) + cancel_evacuation() + return + + if(state == EVAC_PREPPING) + if(world.time >= evac_ready_time) + finish_preparing_evac() + else if(state == EVAC_LAUNCHING) + if(world.time >= evac_launch_time) + launch_evacuation() + else if(state == EVAC_IN_TRANSIT) + if(world.time >= evac_arrival_time) + finish_evacuation() + else if(state == EVAC_COOLDOWN) + if(world.time >= evac_cooldown_time) + state = EVAC_IDLE + +/datum/evacuation_controller/proc/available_evac_options() + return list() + +/datum/evacuation_controller/proc/handle_evac_option(var/option_target, var/mob/user) + var/datum/evacuation_option/selected = evacuation_options[option_target] + if (!isnull(selected) && istype(selected)) + selected.execute(user) + +/datum/evacuation_controller/proc/get_evac_option(var/option_target) + return null + diff --git a/code/controllers/evacuation/evacuation_eta.dm b/code/controllers/evacuation/evacuation_eta.dm new file mode 100644 index 00000000..f51f7816 --- /dev/null +++ b/code/controllers/evacuation/evacuation_eta.dm @@ -0,0 +1,22 @@ +/datum/evacuation_controller/proc/get_status_panel_eta() + + if(waiting_to_leave()) + return "Delayed" + var/timeleft = get_eta() + if(timeleft < 0) + return "" + return "[is_on_cooldown() ? "Returning" : (is_arriving() ? "ETA" : "ETD")] [add_zero(num2text((timeleft / 60) % 60),2)]:[add_zero(num2text(timeleft % 60), 2)]" + +/datum/evacuation_controller/proc/has_eta() + return (state == EVAC_PREPPING || state == EVAC_LAUNCHING || state == EVAC_IN_TRANSIT || state == EVAC_COOLDOWN) + +/datum/evacuation_controller/proc/get_eta() + if(state == EVAC_PREPPING) + return (evac_ready_time ? (evac_ready_time - world.time)/10 : -1) + else if(state == EVAC_LAUNCHING) + return (evac_launch_time ? (evac_launch_time - world.time)/10 : -1) + else if(state == EVAC_IN_TRANSIT) + return (evac_arrival_time ? (evac_arrival_time - world.time)/10 : -1) + else if(state == EVAC_COOLDOWN) + return (evac_cooldown_time ? (evac_cooldown_time - world.time)/10 : -1) + return -1 diff --git a/code/controllers/evacuation/evacuation_helpers.dm b/code/controllers/evacuation/evacuation_helpers.dm new file mode 100644 index 00000000..9f8ae7de --- /dev/null +++ b/code/controllers/evacuation/evacuation_helpers.dm @@ -0,0 +1,69 @@ +/datum/evacuation_controller/proc/set_launch_time(var/val) + evac_launch_time = val + +/datum/evacuation_controller/proc/set_arrival_time(var/val) + evac_arrival_time = val + +/datum/evacuation_controller/proc/is_prepared() + return (state == EVAC_LAUNCHING) + +/datum/evacuation_controller/proc/is_in_transit() + return (state == EVAC_IN_TRANSIT) + +/datum/evacuation_controller/proc/is_idle() + return (state == EVAC_IDLE) + +/datum/evacuation_controller/proc/has_evacuated() + return (!isnull(evac_launch_time) && world.time > evac_launch_time) + +/datum/evacuation_controller/proc/round_over() + return state == EVAC_COMPLETE + +/datum/evacuation_controller/proc/is_on_cooldown() + return state == EVAC_COOLDOWN + +/datum/evacuation_controller/proc/is_evacuating() + return state != EVAC_IDLE + +/datum/evacuation_controller/proc/can_evacuate(var/mob/user, var/forced) + + if(!isnull(evac_called_at)) + return 0 + + if (!GLOB.universe.OnShuttleCall(null)) + return 0 + + if(!forced) + for(var/predicate in evacuation_predicates) + var/datum/evacuation_predicate/esp = predicate + if(!esp.is_valid()) + evacuation_predicates -= esp + qdel(esp) + else + if(!esp.can_call(user)) + return 0 + return 1 + +/datum/evacuation_controller/proc/waiting_to_leave() + return 0 + +/datum/evacuation_controller/proc/can_cancel() + // Are we evacuating? + if(isnull(evac_called_at)) + return 0 + // Have we already launched? + if(state != EVAC_PREPPING) + return 0 + // Are we already committed? + if(world.time > evac_no_return) + return 0 + return 1 + +/datum/evacuation_controller/proc/is_arriving() + if(state == EVAC_LAUNCHING) + return 0 + return has_eta() + +/datum/evacuation_controller/proc/is_departing() + if(state == EVAC_LAUNCHING) + return 1 diff --git a/code/controllers/evacuation/evacuation_lifepods.dm b/code/controllers/evacuation/evacuation_lifepods.dm new file mode 100644 index 00000000..64233aae --- /dev/null +++ b/code/controllers/evacuation/evacuation_lifepods.dm @@ -0,0 +1,28 @@ +#define EVAC_OPT_ABANDON_SHIP "abandon_ship" +#define EVAC_OPT_CANCEL_ABANDON_SHIP "cancel_abandon_ship" + +/datum/evacuation_controller/lifepods + name = "escape pod controller" + + evac_prep_delay = 7 MINUTES + evac_launch_delay = 0 + evac_transit_delay = 2 MINUTES + + evacuation_options = list( + EVAC_OPT_ABANDON_SHIP = new /datum/evacuation_option/abandon_ship(), + EVAC_OPT_CANCEL_ABANDON_SHIP = new /datum/evacuation_option/cancel_abandon_ship(), + ) + +/datum/evacuation_controller/lifepods/launch_evacuation() + priority_announcement.Announce(replacetext(replacetext(GLOB.using_map.emergency_shuttle_leaving_dock, "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s")) + +/datum/evacuation_controller/lifepods/available_evac_options() + if (is_on_cooldown()) + return list() + if (is_idle()) + return list(evacuation_options[EVAC_OPT_ABANDON_SHIP]) + if (is_evacuating()) + return list(evacuation_options[EVAC_OPT_CANCEL_ABANDON_SHIP]) + +#undef EVAC_OPT_ABANDON_SHIP +#undef EVAC_OPT_CANCEL_ABANDON_SHIP \ No newline at end of file diff --git a/code/controllers/evacuation/evacuation_option.dm b/code/controllers/evacuation/evacuation_option.dm new file mode 100644 index 00000000..e4308db9 --- /dev/null +++ b/code/controllers/evacuation/evacuation_option.dm @@ -0,0 +1,9 @@ +/datum/evacuation_option + var/option_text = "Generic evac option" + var/option_desc = "do something that should never be seen" + var/option_target = "generic" + var/needs_syscontrol = FALSE + var/silicon_allowed = TRUE + +/datum/evacuation_option/proc/execute(var/mob/user) + return \ No newline at end of file diff --git a/code/controllers/evacuation/evacuation_pods.dm b/code/controllers/evacuation/evacuation_pods.dm new file mode 100644 index 00000000..d2eaad30 --- /dev/null +++ b/code/controllers/evacuation/evacuation_pods.dm @@ -0,0 +1,144 @@ +#define EVAC_OPT_ABANDON_SHIP "abandon_ship" +#define EVAC_OPT_BLUESPACE_JUMP "bluespace_jump" +#define EVAC_OPT_CANCEL_ABANDON_SHIP "cancel_abandon_ship" +#define EVAC_OPT_CANCEL_BLUESPACE_JUMP "cancel_bluespace_jump" + +// Apparently, emergency_evacuation --> "abandon ship" and !emergency_evacuation --> "bluespace jump" +// That stuff should be moved to the evacuation option datums but someone can do that later +/datum/evacuation_controller/starship + name = "escape pod controller" + + evac_prep_delay = 5 MINUTES + evac_launch_delay = 3 MINUTES + evac_transit_delay = 2 MINUTES + + transfer_prep_additional_delay = 15 MINUTES + autotransfer_prep_additional_delay = 5 MINUTES + emergency_prep_additional_delay = 0 MINUTES + + evacuation_options = list( + EVAC_OPT_ABANDON_SHIP = new /datum/evacuation_option/abandon_ship(), + EVAC_OPT_BLUESPACE_JUMP = new /datum/evacuation_option/bluespace_jump(), + EVAC_OPT_CANCEL_ABANDON_SHIP = new /datum/evacuation_option/cancel_abandon_ship(), + EVAC_OPT_CANCEL_BLUESPACE_JUMP = new /datum/evacuation_option/cancel_bluespace_jump() + ) + +/datum/evacuation_controller/starship/finish_preparing_evac() + . = ..() + // Arm the escape pods. + if (emergency_evacuation) + for (var/datum/shuttle/autodock/ferry/escape_pod/pod in escape_pods) + if (pod.arming_controller) + pod.arming_controller.arm() + +/datum/evacuation_controller/starship/launch_evacuation() + + state = EVAC_IN_TRANSIT + + if (emergency_evacuation) + // Abondon Ship + for (var/datum/shuttle/autodock/ferry/escape_pod/pod in escape_pods) // Launch the pods! + if (!pod.arming_controller || pod.arming_controller.armed) + pod.move_time = (evac_transit_delay/10) + pod.launch(src) + + priority_announcement.Announce(replacetext(replacetext(GLOB.using_map.emergency_shuttle_leaving_dock, "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s")) + else + // Bluespace Jump + priority_announcement.Announce(replacetext(replacetext(GLOB.using_map.shuttle_leaving_dock, "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s")) + SetUniversalState(/datum/universal_state/bluespace_jump, arguments=list(GLOB.using_map.station_levels)) + +/datum/evacuation_controller/starship/finish_evacuation() + ..() + if(!emergency_evacuation) //bluespace jump + SetUniversalState(/datum/universal_state) //clear jump state + +/datum/evacuation_controller/starship/available_evac_options() + if (is_on_cooldown()) + return list() + if (is_idle()) + return list(evacuation_options[EVAC_OPT_BLUESPACE_JUMP], evacuation_options[EVAC_OPT_ABANDON_SHIP]) + if (is_evacuating()) + if (emergency_evacuation) + return list(evacuation_options[EVAC_OPT_CANCEL_ABANDON_SHIP]) + else + return list(evacuation_options[EVAC_OPT_CANCEL_BLUESPACE_JUMP]) + +/datum/evacuation_option/abandon_ship + option_text = "Abandon spacecraft" + option_desc = "abandon the spacecraft" + option_target = EVAC_OPT_ABANDON_SHIP + needs_syscontrol = TRUE + silicon_allowed = TRUE + +/datum/evacuation_option/abandon_ship/execute(mob/user) + if (!ticker || !evacuation_controller) + return + if (evacuation_controller.deny) + to_chat(user, "Unable to initiate escape procedures.") + return + if (evacuation_controller.is_on_cooldown()) + to_chat(user, evacuation_controller.get_cooldown_message()) + return + if (evacuation_controller.is_evacuating()) + to_chat(user, "Escape procedures already in progress.") + return + if (evacuation_controller.call_evacuation(user, 1)) + log_and_message_admins("[user? key_name(user) : "Autotransfer"] has initiated abandonment of the spacecraft.") + +/datum/evacuation_option/bluespace_jump + option_text = "Initiate bluespace jump" + option_desc = "initiate a bluespace jump" + option_target = EVAC_OPT_BLUESPACE_JUMP + needs_syscontrol = TRUE + silicon_allowed = TRUE + +/datum/evacuation_option/bluespace_jump/execute(mob/user) + if (!ticker || !evacuation_controller) + return + if (evacuation_controller.deny) + to_chat(user, "Unable to initiate jump preparation.") + return + if (evacuation_controller.is_on_cooldown()) + to_chat(user, evacuation_controller.get_cooldown_message()) + return + if (evacuation_controller.is_evacuating()) + to_chat(user, "Jump preparation already in progress.") + return + if (evacuation_controller.call_evacuation(user, 0)) + log_and_message_admins("[user? key_name(user) : "Autotransfer"] has initiated bluespace jump preparation.") + +/datum/evacuation_option/cancel_abandon_ship + option_text = "Cancel abandonment" + option_desc = "cancel abandonment of the spacecraft" + option_target = EVAC_OPT_CANCEL_ABANDON_SHIP + needs_syscontrol = TRUE + silicon_allowed = FALSE + +/datum/evacuation_option/cancel_abandon_ship/execute(mob/user) + if (ticker && evacuation_controller && evacuation_controller.cancel_evacuation()) + log_and_message_admins("[key_name(user)] has cancelled abandonment of the spacecraft.") + +/datum/evacuation_option/cancel_bluespace_jump + option_text = "Cancel bluespace jump" + option_desc = "cancel the jump preparation" + option_target = EVAC_OPT_CANCEL_BLUESPACE_JUMP + needs_syscontrol = TRUE + silicon_allowed = FALSE + +/datum/evacuation_option/cancel_bluespace_jump/execute(mob/user) + if (ticker && evacuation_controller && evacuation_controller.cancel_evacuation()) + log_and_message_admins("[key_name(user)] has cancelled the bluespace jump.") + +/obj/screen/fullscreen/bluespace_overlay + icon = 'icons/effects/effects.dmi' + icon_state = "mfoam" + screen_loc = "WEST,SOUTH to EAST,NORTH" + color = "#ff9900" + blend_mode = BLEND_SUBTRACT + layer = FULLSCREEN_LAYER + +#undef EVAC_OPT_ABANDON_SHIP +#undef EVAC_OPT_BLUESPACE_JUMP +#undef EVAC_OPT_CANCEL_ABANDON_SHIP +#undef EVAC_OPT_CANCEL_BLUESPACE_JUMP \ No newline at end of file diff --git a/code/controllers/evacuation/evacuation_predicate.dm b/code/controllers/evacuation/evacuation_predicate.dm new file mode 100644 index 00000000..ddcd91dc --- /dev/null +++ b/code/controllers/evacuation/evacuation_predicate.dm @@ -0,0 +1,11 @@ +/datum/evacuation_predicate/New() + return + +/datum/evacuation_predicate/Destroy() + return 0 + +/datum/evacuation_predicate/proc/is_valid() + return FALSE + +/datum/evacuation_predicate/proc/can_call(var/user) + return TRUE diff --git a/code/controllers/evacuation/evacuation_shuttle.dm b/code/controllers/evacuation/evacuation_shuttle.dm new file mode 100644 index 00000000..fc99e804 --- /dev/null +++ b/code/controllers/evacuation/evacuation_shuttle.dm @@ -0,0 +1,138 @@ +#define EVAC_OPT_CALL_SHUTTLE "call_shuttle" +#define EVAC_OPT_RECALL_SHUTTLE "recall_shuttle" + +/datum/evacuation_controller/shuttle + name = "escape shuttle controller" + evac_waiting = new(0, new_sound = sound('sound/AI/shuttledock.ogg')) + evac_called = new(0, new_sound = sound('sound/AI/shuttlecalled.ogg')) + evac_recalled = new(0, new_sound = sound('sound/AI/shuttlerecalled.ogg')) + + emergency_prep_additional_delay = 0 MINUTES + transfer_prep_additional_delay = 0 MINUTES + + evacuation_options = list( + EVAC_OPT_CALL_SHUTTLE = new /datum/evacuation_option/call_shuttle(), + EVAC_OPT_RECALL_SHUTTLE = new /datum/evacuation_option/recall_shuttle() + ) + + var/departed = 0 + var/autopilot = 1 + var/datum/shuttle/autodock/ferry/emergency/shuttle // Set in shuttle_emergency.dm + var/shuttle_launch_time + +/datum/evacuation_controller/shuttle/has_evacuated() + return departed + +/datum/evacuation_controller/shuttle/waiting_to_leave() + return (!autopilot || (shuttle && shuttle.is_launching())) + +/datum/evacuation_controller/shuttle/launch_evacuation() + + if(waiting_to_leave()) + return + + for (var/datum/shuttle/autodock/ferry/escape_pod/pod in escape_pods) + if (!pod.arming_controller || pod.arming_controller.armed) + pod.move_time = evac_transit_delay + pod.launch(src) + + if(autopilot && shuttle.moving_status == SHUTTLE_IDLE) + evac_arrival_time = world.time + (shuttle.move_time*10) + (shuttle.warmup_time*10) + shuttle.launch(src) + // Announcements, state changes and such are handled by the shuttle itself to prevent desync. + +/datum/evacuation_controller/shuttle/finish_preparing_evac() + departed = 1 + evac_launch_time = world.time + evac_launch_delay + + . = ..() + // Arm the escape pods. + if (emergency_evacuation) + for (var/datum/shuttle/autodock/ferry/escape_pod/pod in escape_pods) + if (pod.arming_controller) + pod.arming_controller.arm() + +/datum/evacuation_controller/shuttle/call_evacuation(var/mob/user, var/_emergency_evac, var/forced, var/skip_announce, var/autotransfer) + if(..()) + autopilot = 1 + shuttle_launch_time = evac_no_return + evac_ready_time += shuttle.warmup_time*10 + return 1 + return 0 + +/datum/evacuation_controller/shuttle/cancel_evacuation() + if(..() && shuttle.moving_status != SHUTTLE_INTRANSIT) + shuttle_launch_time = null + shuttle.cancel_launch(src) + return 1 + return 0 + +/datum/evacuation_controller/shuttle/get_eta() + if (shuttle && shuttle.has_arrive_time()) + return (shuttle.arrive_time-world.time)/10 + return ..() + +/datum/evacuation_controller/shuttle/get_status_panel_eta() + if(has_eta() && waiting_to_leave()) + return "Launching..." + return ..() + +// This is largely handled by the emergency shuttle datum. +/datum/evacuation_controller/shuttle/process() + if(state == EVAC_PREPPING) + if(!isnull(shuttle_launch_time) && world.time > shuttle_launch_time && shuttle.moving_status == SHUTTLE_IDLE) + shuttle.launch() + shuttle_launch_time = null + return + else if(state == EVAC_IN_TRANSIT) + return + return ..() + +/datum/evacuation_controller/shuttle/can_cancel() + return (shuttle.moving_status == SHUTTLE_IDLE && shuttle.location && ..()) + +/datum/evacuation_controller/shuttle/proc/shuttle_leaving() + state = EVAC_IN_TRANSIT + +/datum/evacuation_controller/shuttle/proc/shuttle_evacuated() + state = EVAC_COMPLETE + +/datum/evacuation_controller/shuttle/proc/shuttle_preparing() + state = EVAC_PREPPING + +/datum/evacuation_controller/shuttle/proc/get_long_jump_time() + if (shuttle.location) + return round(evac_prep_delay/10)/2 + else + return round(evac_transit_delay/10) + +/datum/evacuation_controller/shuttle/available_evac_options() + if (!shuttle.location) + return list() + if (is_idle()) + return list(evacuation_options[EVAC_OPT_CALL_SHUTTLE]) + else + return list(evacuation_options[EVAC_OPT_RECALL_SHUTTLE]) + +/datum/evacuation_option/call_shuttle + option_text = "Call emergency shuttle" + option_desc = "call the emergency shuttle" + option_target = EVAC_OPT_CALL_SHUTTLE + needs_syscontrol = TRUE + silicon_allowed = TRUE + +/datum/evacuation_option/call_shuttle/execute(mob/user) + call_shuttle_proc(user) + +/datum/evacuation_option/recall_shuttle + option_text = "Cancel shuttle call" + option_desc = "recall the emergency shuttle" + option_target = EVAC_OPT_RECALL_SHUTTLE + needs_syscontrol = TRUE + silicon_allowed = FALSE + +/datum/evacuation_option/recall_shuttle/execute(mob/user) + cancel_call_proc(user) + +#undef EVAC_OPT_CALL_SHUTTLE +#undef EVAC_OPT_RECALL_SHUTTLE \ No newline at end of file diff --git a/code/controllers/evacuation/~evac.dm b/code/controllers/evacuation/~evac.dm new file mode 100644 index 00000000..e49dec2b --- /dev/null +++ b/code/controllers/evacuation/~evac.dm @@ -0,0 +1,5 @@ +#undef EVAC_IDLE +#undef EVAC_PREPPING +#undef EVAC_IN_TRANSIT +#undef EVAC_COOLDOWN +#undef EVAC_COMPLETE diff --git a/code/controllers/failsafe.dm b/code/controllers/failsafe.dm new file mode 100644 index 00000000..cf2bced6 --- /dev/null +++ b/code/controllers/failsafe.dm @@ -0,0 +1,102 @@ + /** + * Failsafe + * + * Pretty much pokes the MC to make sure it's still alive. + **/ + +GLOBAL_REAL(Failsafe, /datum/controller/failsafe) + +/datum/controller/failsafe // This thing pretty much just keeps poking the master controller + name = "Failsafe" + + // The length of time to check on the MC (in deciseconds). + // Set to 0 to disable. + var/processing_interval = 20 + // The alert level. For every failed poke, we drop a DEFCON level. Once we hit DEFCON 1, restart the MC. + var/defcon = 5 + //the world.time of the last check, so the mc can restart US if we hang. + // (Real friends look out for *eachother*) + var/lasttick = 0 + + // Track the MC iteration to make sure its still on track. + var/master_iteration = 0 + var/running = TRUE + +/datum/controller/failsafe/New() + // Highlander-style: there can only be one! Kill off the old and replace it with the new. + if(Failsafe != src) + if(istype(Failsafe)) + qdel(Failsafe) + Failsafe = src + Initialize() + +/datum/controller/failsafe/Initialize() + set waitfor = 0 + Failsafe.Loop() + if(!QDELETED(src)) + qdel(src) //when Loop() returns, we delete ourselves and let the mc recreate us + +/datum/controller/failsafe/Destroy() + running = FALSE + ..() + return QDEL_HINT_HARDDEL_NOW + +/datum/controller/failsafe/proc/Loop() + while(running) + lasttick = world.time + if(!Master) + // Replace the missing Master! This should never, ever happen. + new /datum/controller/master() + // Only poke it if overrides are not in effect. + if(processing_interval > 0) + if(Master.processing && Master.iteration) + // Check if processing is done yet. + if(Master.iteration == master_iteration) + switch(defcon) + if(4,5) + --defcon + if(3) + to_chat(GLOB.admins, "Notice: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks.") + --defcon + if(2) + to_chat(GLOB.admins, "Warning: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks. Automatic restart in [processing_interval] ticks.") + --defcon + if(1) + + to_chat(GLOB.admins, "Warning: DEFCON [defcon_pretty()]. The Master Controller has still not fired within the last [(5-defcon) * processing_interval] ticks. Killing and restarting...") + --defcon + var/rtn = Recreate_MC() + if(rtn > 0) + defcon = 4 + master_iteration = 0 + to_chat(GLOB.admins, "MC restarted successfully") + else if(rtn < 0) + log_game("FailSafe: Could not restart MC, runtime encountered. Entering defcon 0") + to_chat(GLOB.admins, "ERROR: DEFCON [defcon_pretty()]. Could not restart MC, runtime encountered. I will silently keep retrying.") + //if the return number was 0, it just means the mc was restarted too recently, and it just needs some time before we try again + //no need to handle that specially when defcon 0 can handle it + if(0) //DEFCON 0! (mc failed to restart) + var/rtn = Recreate_MC() + if(rtn > 0) + defcon = 4 + master_iteration = 0 + to_chat(GLOB.admins, "MC restarted successfully") + else + defcon = min(defcon + 1,5) + master_iteration = Master.iteration + if (defcon <= 1) + sleep(processing_interval*2) + else + sleep(processing_interval) + else + defcon = 5 + sleep(initial(processing_interval)) + +/datum/controller/failsafe/proc/defcon_pretty() + return defcon + +/datum/controller/failsafe/stat_entry() + if(!statclick) + statclick = new/obj/effect/statclick/debug(null, "Initializing...", src) + + stat("Failsafe Controller:", statclick.update("Defcon: [defcon_pretty()] (Interval: [Failsafe.processing_interval] | Iteration: [Failsafe.master_iteration])")) diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm new file mode 100644 index 00000000..af56c86d --- /dev/null +++ b/code/controllers/globals.dm @@ -0,0 +1,67 @@ +GLOBAL_REAL(GLOB, /datum/controller/global_vars) + +/datum/controller/global_vars + name = "Global Variables" + + var/list/gvars_datum_protected_varlist + var/list/gvars_datum_in_built_vars + var/list/gvars_datum_init_order + +/datum/controller/global_vars/New() + if(GLOB) + CRASH("Multiple instances of global variable controller created") + GLOB = src + + var/datum/controller/exclude_these = new + gvars_datum_in_built_vars = exclude_these.vars + list("gvars_datum_protected_varlist", "gvars_datum_in_built_vars", "gvars_datum_init_order") + qdel(exclude_these) + + var/global_vars = vars.len - gvars_datum_in_built_vars.len + var/global_procs = length(typesof(/datum/controller/global_vars/proc)) + + report_progress("[global_vars] global variables") + report_progress("[global_procs] global init procs") + + try + if(global_vars == global_procs) + Initialize() + else + crash_with("Expected [global_vars] global init procs, were [global_procs].") + catch(var/exception/e) + to_world_log("Vars to be initialized: [json_encode((vars - gvars_datum_in_built_vars))]") + to_world_log("Procs used to initialize: [json_encode(typesof(/datum/controller/global_vars/proc))]") + throw e + + +/datum/controller/global_vars/Destroy(force) + crash_with("There was an attempt to qdel the global vars holder!") + if(!force) + return QDEL_HINT_LETMELIVE + + QDEL_NULL(statclick) + gvars_datum_protected_varlist.Cut() + gvars_datum_in_built_vars.Cut() + + GLOB = null + + return ..() + +/datum/controller/global_vars/stat_entry() + if(!statclick) + statclick = new/obj/effect/statclick/debug(null, "Initializing...", src) + + stat("Globals:", statclick.update("Edit")) + +/datum/controller/global_vars/VV_hidden() + return ..() + gvars_datum_protected_varlist + +/datum/controller/global_vars/Initialize() + gvars_datum_init_order = list() + gvars_datum_protected_varlist = list("gvars_datum_protected_varlist") + + //See https://github.com/tgstation/tgstation/issues/26954 + for(var/I in typesof(/datum/controller/global_vars/proc)) + var/start_tick = world.time + call(src, I)() + if(world.time - start_tick) + warning("[I] slept during initialization!") diff --git a/code/controllers/hooks-defs.dm b/code/controllers/hooks-defs.dm new file mode 100644 index 00000000..e605661c --- /dev/null +++ b/code/controllers/hooks-defs.dm @@ -0,0 +1,99 @@ +/** + * Global init hook. + * Called in global_init.dm when the server is initialized. + */ +/hook/global_init + +/** + * Startup hook. + * Called in world.dm when the server starts. + */ +/hook/startup + +/** + * Roundstart hook. + * Called in gameticker.dm when a round starts. + */ +/hook/roundstart + +/** + * Roundend hook. + * Called in gameticker.dm when a round ends. + */ +/hook/roundend + +/** + * Shutdown hook. + * Called in world.dm when world/Del is called. + */ +/hook/shutdown + +/** + * Death hook. + * Called in death.dm when someone dies. + * Parameters: var/mob/living/carbon/human, var/gibbed + */ +/hook/death + +/** + * Cloning hook. + * Called in cloning.dm when someone is brought back by the wonders of modern science. + * Parameters: var/mob/living/carbon/human + */ +/hook/clone + +/** + * Debrained hook. + * Called in brain_item.dm when someone gets debrained. + * Parameters: var/obj/item/organ/internal/brain + */ +/hook/debrain + +/** + * Borged hook. + * Called in robot_parts.dm when someone gets turned into a cyborg. + * Parameters: var/mob/living/silicon/robot + */ +/hook/borgify + +/** + * Podman hook. + * Called in podmen.dm when someone is brought back as a Diona. + * Parameters: var/mob/living/carbon/alien/diona + */ +/hook/harvest_podman + +/** + * Payroll revoked hook. + * Called in Accounts_DB.dm when someone's payroll is stolen at the Accounts terminal. + * Parameters: var/datum/money_account + */ +/hook/revoke_payroll + +/** + * Account suspension hook. + * Called in Accounts_DB.dm when someone's account is suspended or unsuspended at the Accounts terminal. + * Parameters: var/datum/money_account + */ +/hook/change_account_status + +/** + * Employee reassignment hook. + * Called in card.dm when someone's card is reassigned at the HoP's desk. + * Parameters: var/obj/item/weapon/card/id + */ +/hook/reassign_employee + +/** + * Employee terminated hook. + * Called in card.dm when someone's card is terminated at the HoP's desk. + * Parameters: var/obj/item/weapon/card/id + */ +/hook/terminate_employee + +/** + * Crate sold hook. + * Called in supplyshuttle.dm when a crate is sold on the shuttle. + * Parameters: var/obj/structure/closet/crate/sold, var/area/shuttle + */ +/hook/sell_crate diff --git a/code/controllers/hooks.dm b/code/controllers/hooks.dm new file mode 100644 index 00000000..2e05a062 --- /dev/null +++ b/code/controllers/hooks.dm @@ -0,0 +1,39 @@ +/** + * @file hooks.dm + * Implements hooks, a simple way to run code on pre-defined events. + */ + +/** @page hooks Code hooks + * @section hooks Hooks + * A hook is defined under /hook in the type tree. + * + * To add some code to be called by the hook, define a proc under the type, as so: + * @code + hook/foo/proc/bar() + if(1) + return 1 //Sucessful + else + return 0 //Error, or runtime. + * @endcode + * All hooks must return nonzero on success, as runtimes will force return null. + */ + +/** + * Calls a hook, executing every piece of code that's attached to it. + * @param hook Identifier of the hook to call. + * @returns 1 if all hooked code runs successfully, 0 otherwise. + */ +/proc/callHook(hook, list/args=null) + var/hook_path = text2path("/hook/[hook]") + if(!hook_path) + error("Invalid hook '/hook/[hook]' called.") + return 0 + + var/caller = new hook_path + var/status = 1 + for(var/P in typesof("[hook_path]/proc")) + if(!call(caller, P)(arglist(args))) + error("Hook '[P]' failed or runtimed.") + status = 0 + + return status diff --git a/code/controllers/master.dm b/code/controllers/master.dm new file mode 100644 index 00000000..9e2a1009 --- /dev/null +++ b/code/controllers/master.dm @@ -0,0 +1,583 @@ + /** + * StonedMC + * + * Designed to properly split up a given tick among subsystems + * Note: if you read parts of this code and think "why is it doing it that way" + * Odds are, there is a reason + * + **/ + +//This is the ABSOLUTE ONLY THING that should init globally like this +GLOBAL_REAL(Master, /datum/controller/master) = new + +//THIS IS THE INIT ORDER +//Master -> SSPreInit -> GLOB -> world -> config -> SSInit -> Failsafe +//GOT IT MEMORIZED? + +/datum/controller/master + name = "Master" + + // Are we processing (higher values increase the processing delay by n ticks) + var/processing = TRUE + // How many times have we ran + var/iteration = 0 + + // world.time of last fire, for tracking lag outside of the mc + var/last_run + + // List of subsystems to process(). + var/list/subsystems + + // Vars for keeping track of tick drift. + var/init_timeofday + var/init_time + var/tickdrift = 0 + + var/sleep_delta + + var/make_runtime = 0 + + var/initializations_finished_with_no_players_logged_in //I wonder what this could be? + + // The type of the last subsystem to be process()'d. + var/last_type_processed + + var/datum/controller/subsystem/queue_head //Start of queue linked list + var/datum/controller/subsystem/queue_tail //End of queue linked list (used for appending to the list) + var/queue_priority_count = 0 //Running total so that we don't have to loop thru the queue each run to split up the tick + var/queue_priority_count_bg = 0 //Same, but for background subsystems + var/map_loading = FALSE //Are we loading in a new map? + + var/list/total_run_times + var/current_runlevel //for scheduling different subsystems for different stages of the round + + var/static/restart_clear = 0 + var/static/restart_timeout = 0 + var/static/restart_count = 0 + + //current tick limit, assigned before running a subsystem. + //used by CHECK_TICK as well so that the procs subsystems call can obey that SS's tick limits + var/static/current_ticklimit = TICK_LIMIT_RUNNING + +/datum/controller/master/New() + total_run_times = list() + // Highlander-style: there can only be one! Kill off the old and replace it with the new. + var/list/_subsystems = list() + subsystems = _subsystems + if (Master != src) + if (istype(Master)) + Recover() + qdel(Master) + else + var/list/subsytem_types = subtypesof(/datum/controller/subsystem) + sortTim(subsytem_types, /proc/cmp_subsystem_init) + for(var/I in subsytem_types) + _subsystems += new I + Master = src + + if(!GLOB) + new /datum/controller/global_vars + +/datum/controller/master/Destroy() + ..() + // Tell qdel() to Del() this object. + return QDEL_HINT_HARDDEL_NOW + +/datum/controller/master/Shutdown() + processing = FALSE + sortTim(subsystems, /proc/cmp_subsystem_init) + reverseRange(subsystems) + for(var/datum/controller/subsystem/ss in subsystems) + report_progress("Shutdown [ss.name] subsystem") + ss.Shutdown() + +// Returns 1 if we created a new mc, 0 if we couldn't due to a recent restart, +// -1 if we encountered a runtime trying to recreate it +/proc/Recreate_MC() + . = -1 //so if we runtime, things know we failed + if (world.time < Master.restart_timeout) + return 0 + if (world.time < Master.restart_clear) + Master.restart_count *= 0.5 + + var/delay = 50 * ++Master.restart_count + Master.restart_timeout = world.time + delay + Master.restart_clear = world.time + (delay * 2) + Master.processing = FALSE //stop ticking this one + try + new/datum/controller/master() + catch + return -1 + return 1 + + +/datum/controller/master/Recover() + var/msg = "## DEBUG: [time2text(world.timeofday)] MC restarted. Reports:\n" + for (var/varname in Master.vars) + switch (varname) + if("name", "tag", "bestF", "type", "parent_type", "vars", "statclick") // Built-in junk. + continue + else + var/varval = Master.vars[varname] + if (istype(varval, /datum)) // Check if it has a type var. + var/datum/D = varval + msg += "\t [varname] = [D]([D.type])\n" + else + msg += "\t [varname] = [varval]\n" + log_world(msg) + + var/datum/controller/subsystem/BadBoy = Master.last_type_processed + var/FireHim = FALSE + if(istype(BadBoy)) + msg = null + LAZYINITLIST(BadBoy.failure_strikes) + switch(++BadBoy.failure_strikes[BadBoy.type]) + if(2) + msg = "The [BadBoy.name] subsystem was the last to fire for 2 controller restarts. It will be recovered now and disabled if it happens again." + FireHim = TRUE + if(3) + msg = "The [BadBoy.name] subsystem seems to be destabilizing the MC and will be offlined." + BadBoy.flags |= SS_NO_FIRE + if(msg) + to_chat(GLOB.admins, "[msg]") + log_world(msg) + + if (istype(Master.subsystems)) + if(FireHim) + Master.subsystems += new BadBoy.type //NEW_SS_GLOBAL will remove the old one + subsystems = Master.subsystems + current_runlevel = Master.current_runlevel + total_run_times = Master.total_run_times + StartProcessing(10) + else + to_chat(world, "The Master Controller is having some issues, we will need to re-initialize EVERYTHING") + Initialize(20, TRUE) + + +// Please don't stuff random bullshit here, +// Make a subsystem, give it the SS_NO_FIRE flag, and do your work in it's Initialize() +/datum/controller/master/Initialize(delay, init_sss) + set waitfor = 0 + + if(delay) + sleep(delay) + + if(init_sss) + init_subtypes(/datum/controller/subsystem, subsystems) + + report_progress("Initializing subsystems...") + + // Sort subsystems by init_order, so they initialize in the correct order. + sortTim(subsystems, /proc/cmp_subsystem_init) + + var/start_timeofday = REALTIMEOFDAY + // Initialize subsystems. + current_ticklimit = config.tick_limit_mc_init + for (var/datum/controller/subsystem/SS in subsystems) + if (SS.flags & SS_NO_INIT) + continue + SS.Initialize(REALTIMEOFDAY) + CHECK_TICK + current_ticklimit = TICK_LIMIT_RUNNING + var/time = (REALTIMEOFDAY - start_timeofday) / 10 + + var/msg = "Initializations complete within [time] second\s!" + report_progress(msg) + log_world(msg) + + if (!current_runlevel) + SetRunLevel(RUNLEVEL_LOBBY) + + // Sort subsystems by display setting for easy access. + sortTim(subsystems, /proc/cmp_subsystem_display) + // Set world options. +#ifdef UNIT_TEST + world.sleep_offline = FALSE +#else + world.sleep_offline = TRUE +#endif + world.fps = config.fps + var/initialized_tod = REALTIMEOFDAY + sleep(1) + initializations_finished_with_no_players_logged_in = initialized_tod < REALTIMEOFDAY - 10 + // Loop. + Master.StartProcessing(0) + +/datum/controller/master/proc/SetRunLevel(new_runlevel) + var/old_runlevel = current_runlevel + if(isnull(old_runlevel)) + old_runlevel = "NULL" + + report_progress("MC: Runlevel changed from [old_runlevel] to [new_runlevel]") + current_runlevel = log(2, new_runlevel) + 1 + if(current_runlevel < 1) + CRASH("Attempted to set invalid runlevel: [new_runlevel]") + +// Starts the mc, and sticks around to restart it if the loop ever ends. +/datum/controller/master/proc/StartProcessing(delay) + set waitfor = 0 + if(delay) + sleep(delay) + report_progress("Master starting processing") + var/rtn = Loop() + if (rtn > 0 || processing < 0) + return //this was suppose to happen. + //loop ended, restart the mc + log_game("MC crashed or runtimed, restarting") + message_admins("MC crashed or runtimed, restarting") + var/rtn2 = Recreate_MC() + if (rtn2 <= 0) + log_game("Failed to recreate MC (Error code: [rtn2]), it's up to the failsafe now") + message_admins("Failed to recreate MC (Error code: [rtn2]), it's up to the failsafe now") + Failsafe.defcon = 2 + +// Main loop. +/datum/controller/master/proc/Loop() + . = -1 + //Prep the loop (most of this is because we want MC restarts to reset as much state as we can, and because + // local vars rock + + //all this shit is here so that flag edits can be refreshed by restarting the MC. (and for speed) + var/list/tickersubsystems = list() + var/list/runlevel_sorted_subsystems = list(list()) //ensure we always have at least one runlevel + var/timer = world.time + for (var/thing in subsystems) + var/datum/controller/subsystem/SS = thing + if (SS.flags & SS_NO_FIRE) + continue + SS.queued_time = 0 + SS.queue_next = null + SS.queue_prev = null + SS.state = SS_IDLE + if (SS.flags & SS_TICKER) + tickersubsystems += SS + timer += world.tick_lag * rand(1, 5) + SS.next_fire = timer + continue + + var/ss_runlevels = SS.runlevels + var/added_to_any = FALSE + for(var/I in 1 to GLOB.bitflags.len) + if(ss_runlevels & GLOB.bitflags[I]) + while(runlevel_sorted_subsystems.len < I) + runlevel_sorted_subsystems += list(list()) + runlevel_sorted_subsystems[I] += SS + added_to_any = TRUE + if(!added_to_any) + WARNING("[SS.name] subsystem is not SS_NO_FIRE but also does not have any runlevels set!") + + queue_head = null + queue_tail = null + //these sort by lower priorities first to reduce the number of loops needed to add subsequent SS's to the queue + //(higher subsystems will be sooner in the queue, adding them later in the loop means we don't have to loop thru them next queue add) + sortTim(tickersubsystems, /proc/cmp_subsystem_priority) + for(var/I in runlevel_sorted_subsystems) + sortTim(runlevel_sorted_subsystems, /proc/cmp_subsystem_priority) + I += tickersubsystems + + var/cached_runlevel = current_runlevel + var/list/current_runlevel_subsystems = runlevel_sorted_subsystems[cached_runlevel] + + init_timeofday = REALTIMEOFDAY + init_time = world.time + + iteration = 1 + var/error_level = 0 + var/sleep_delta = 0 + var/list/subsystems_to_check + //the actual loop. + while (1) + tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, (((REALTIMEOFDAY - init_timeofday) - (world.time - init_time)) / world.tick_lag))) + if (processing <= 0) + current_ticklimit = TICK_LIMIT_RUNNING + sleep(10) + continue + + //if there are mutiple sleeping procs running before us hogging the cpu, we have to run later + // because sleeps are processed in the order received, so longer sleeps are more likely to run first + if (TICK_USAGE > TICK_LIMIT_MC) + sleep_delta += 2 + current_ticklimit = TICK_LIMIT_RUNNING * 0.5 + sleep(world.tick_lag * (processing + sleep_delta)) + continue + + sleep_delta = MC_AVERAGE_FAST(sleep_delta, 0) + if (last_run + (world.tick_lag * processing) > world.time) + sleep_delta += 1 + if (TICK_USAGE > (TICK_LIMIT_MC*0.5)) + sleep_delta += 1 + + if (make_runtime) + var/datum/controller/subsystem/SS + SS.can_fire = 0 + if (!Failsafe || (Failsafe.processing_interval > 0 && (Failsafe.lasttick+(Failsafe.processing_interval*5)) < world.time)) + new/datum/controller/failsafe() // (re)Start the failsafe. + if (!queue_head || !(iteration % 3)) + var/checking_runlevel = current_runlevel + if(cached_runlevel != checking_runlevel) + //resechedule subsystems + cached_runlevel = checking_runlevel + current_runlevel_subsystems = runlevel_sorted_subsystems[cached_runlevel] + var/stagger = world.time + for(var/I in current_runlevel_subsystems) + var/datum/controller/subsystem/SS = I + if(SS.next_fire <= world.time) + stagger += world.tick_lag * rand(1, 5) + SS.next_fire = stagger + + subsystems_to_check = current_runlevel_subsystems + else + subsystems_to_check = tickersubsystems + if (CheckQueue(subsystems_to_check) <= 0) + if (!SoftReset(tickersubsystems, runlevel_sorted_subsystems)) + log_world("MC: SoftReset() failed, crashing") + return + if (!error_level) + iteration++ + error_level++ + current_ticklimit = TICK_LIMIT_RUNNING + sleep(10) + continue + + if (queue_head) + if (RunQueue() <= 0) + if (!SoftReset(tickersubsystems, runlevel_sorted_subsystems)) + log_world("MC: SoftReset() failed, crashing") + return + if (!error_level) + iteration++ + error_level++ + current_ticklimit = TICK_LIMIT_RUNNING + sleep(10) + continue + error_level-- + if (!queue_head) //reset the counts if the queue is empty, in the off chance they get out of sync + queue_priority_count = 0 + queue_priority_count_bg = 0 + + iteration++ + last_run = world.time + src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta) + current_ticklimit = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc. + sleep(world.tick_lag * (processing + sleep_delta)) + + + + +// This is what decides if something should run. +/datum/controller/master/proc/CheckQueue(list/subsystemstocheck) + . = 0 //so the mc knows if we runtimed + + //we create our variables outside of the loops to save on overhead + var/datum/controller/subsystem/SS + var/SS_flags + + for (var/thing in subsystemstocheck) + if (!thing) + subsystemstocheck -= thing + SS = thing + if (SS.state != SS_IDLE) + continue + if (SS.can_fire <= 0) + continue + if (SS.next_fire > world.time) + continue + SS_flags = SS.flags + if (SS_flags & SS_NO_FIRE) + subsystemstocheck -= SS + continue + if (!(SS_flags & SS_TICKER) && (SS_flags & SS_KEEP_TIMING) && SS.last_fire + (SS.wait * 0.75) > world.time) + continue + SS.enqueue() + . = 1 + + +// Run thru the queue of subsystems to run, running them while balancing out their allocated tick precentage +/datum/controller/master/proc/RunQueue() + . = 0 + var/datum/controller/subsystem/queue_node + var/queue_node_flags + var/queue_node_priority + var/queue_node_paused + + var/current_tick_budget + var/tick_precentage + var/tick_remaining + var/ran = TRUE //this is right + var/ran_non_ticker = FALSE + var/bg_calc //have we swtiched current_tick_budget to background mode yet? + var/tick_usage + + //keep running while we have stuff to run and we haven't gone over a tick + // this is so subsystems paused eariler can use tick time that later subsystems never used + while (ran && queue_head && TICK_USAGE < TICK_LIMIT_MC) + ran = FALSE + bg_calc = FALSE + current_tick_budget = queue_priority_count + queue_node = queue_head + while (queue_node) + if (ran && TICK_USAGE > TICK_LIMIT_RUNNING) + break + + queue_node_flags = queue_node.flags + queue_node_priority = queue_node.queued_priority + + //super special case, subsystems where we can't make them pause mid way through + //if we can't run them this tick (without going over a tick) + //we bump up their priority and attempt to run them next tick + //(unless we haven't even ran anything this tick, since its unlikely they will ever be able run + // in those cases, so we just let them run) + if (queue_node_flags & SS_NO_TICK_CHECK) + if (queue_node.tick_usage > TICK_LIMIT_RUNNING - TICK_USAGE && ran_non_ticker) + queue_node.queued_priority += queue_priority_count * 0.10 + queue_priority_count -= queue_node_priority + queue_priority_count += queue_node.queued_priority + current_tick_budget -= queue_node_priority + queue_node = queue_node.queue_next + continue + + if ((queue_node_flags & SS_BACKGROUND) && !bg_calc) + current_tick_budget = queue_priority_count_bg + bg_calc = TRUE + + tick_remaining = TICK_LIMIT_RUNNING - TICK_USAGE + + if (current_tick_budget > 0 && queue_node_priority > 0) + tick_precentage = tick_remaining / (current_tick_budget / queue_node_priority) + else + tick_precentage = tick_remaining + + tick_precentage = max(tick_precentage*0.5, tick_precentage-queue_node.tick_overrun) + + current_ticklimit = round(TICK_USAGE + tick_precentage) + + if (!(queue_node_flags & SS_TICKER)) + ran_non_ticker = TRUE + ran = TRUE + + queue_node_paused = (queue_node.state == SS_PAUSED || queue_node.state == SS_PAUSING) + last_type_processed = queue_node + + queue_node.state = SS_RUNNING + + tick_usage = TICK_USAGE + var/state = queue_node.ignite(queue_node_paused) + tick_usage = TICK_USAGE - tick_usage + + if (state == SS_RUNNING) + state = SS_IDLE + current_tick_budget -= queue_node_priority + + + if (tick_usage < 0) + tick_usage = 0 + queue_node.tick_overrun = max(0, MC_AVG_FAST_UP_SLOW_DOWN(queue_node.tick_overrun, tick_usage-tick_precentage)) + queue_node.state = state + + if (state == SS_PAUSED) + queue_node.paused_ticks++ + queue_node.paused_tick_usage += tick_usage + queue_node = queue_node.queue_next + continue + + queue_node.ticks = MC_AVERAGE(queue_node.ticks, queue_node.paused_ticks) + tick_usage += queue_node.paused_tick_usage + + queue_node.tick_usage = MC_AVERAGE_FAST(queue_node.tick_usage, tick_usage) + total_run_times[queue_node.name] += ((tick_usage / 100) * world.tick_lag) / 10 + + queue_node.cost = MC_AVERAGE_FAST(queue_node.cost, TICK_DELTA_TO_MS(tick_usage)) + queue_node.paused_ticks = 0 + queue_node.paused_tick_usage = 0 + + if (queue_node_flags & SS_BACKGROUND) //update our running total + queue_priority_count_bg -= queue_node_priority + else + queue_priority_count -= queue_node_priority + + queue_node.last_fire = world.time + queue_node.times_fired++ + + if (queue_node_flags & SS_TICKER) + queue_node.next_fire = world.time + (world.tick_lag * (queue_node.wait + (queue_node.tick_overrun/100))) + else if (queue_node_flags & SS_POST_FIRE_TIMING) + queue_node.next_fire = world.time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun/100)) + else if (queue_node_flags & SS_KEEP_TIMING) + queue_node.next_fire += queue_node.wait + else + queue_node.next_fire = queue_node.queued_time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun/100)) + + queue_node.queued_time = 0 + + //remove from queue + queue_node.dequeue() + + queue_node = queue_node.queue_next + + . = 1 + +//resets the queue, and all subsystems, while filtering out the subsystem lists +// called if any mc's queue procs runtime or exit improperly. +/datum/controller/master/proc/SoftReset(list/ticker_SS, list/runlevel_SS) + . = 0 + log_world("MC: SoftReset called, resetting MC queue state.") + if (!istype(subsystems) || !istype(ticker_SS) || !istype(runlevel_SS)) + log_world("MC: SoftReset: Bad list contents: '[subsystems]' '[ticker_SS]' '[runlevel_SS]'") + return + var/subsystemstocheck = subsystems + ticker_SS + for(var/I in runlevel_SS) + subsystemstocheck |= I + + for (var/thing in subsystemstocheck) + var/datum/controller/subsystem/SS = thing + if (!SS || !istype(SS)) + //list(SS) is so if a list makes it in the subsystem list, we remove the list, not the contents + subsystems -= list(SS) + ticker_SS -= list(SS) + for(var/I in runlevel_SS) + I -= list(SS) + log_world("MC: SoftReset: Found bad entry in subsystem list, '[SS]'") + continue + if (SS.queue_next && !istype(SS.queue_next)) + log_world("MC: SoftReset: Found bad data in subsystem queue, queue_next = '[SS.queue_next]'") + SS.queue_next = null + if (SS.queue_prev && !istype(SS.queue_prev)) + log_world("MC: SoftReset: Found bad data in subsystem queue, queue_prev = '[SS.queue_prev]'") + SS.queue_prev = null + SS.queued_priority = 0 + SS.queued_time = 0 + SS.state = SS_IDLE + if (queue_head && !istype(queue_head)) + log_world("MC: SoftReset: Found bad data in subsystem queue, queue_head = '[queue_head]'") + queue_head = null + if (queue_tail && !istype(queue_tail)) + log_world("MC: SoftReset: Found bad data in subsystem queue, queue_tail = '[queue_tail]'") + queue_tail = null + queue_priority_count = 0 + queue_priority_count_bg = 0 + log_world("MC: SoftReset: Finished.") + . = 1 + + + +/datum/controller/master/stat_entry() + if(!statclick) + statclick = new/obj/effect/statclick/debug(null, "Initializing...", src) + + stat("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%))") + stat("Master Controller:", statclick.update("(TickRate:[Master.processing]) (Iteration:[Master.iteration])")) + +/datum/controller/master/StartLoadingMap() + //disallow more than one map to load at once, multithreading it will just cause race conditions + while(map_loading) + stoplag() + for(var/S in subsystems) + var/datum/controller/subsystem/SS = S + SS.StartLoadingMap() + map_loading = TRUE + +/datum/controller/master/StopLoadingMap(bounds = null) + map_loading = FALSE + for(var/S in subsystems) + var/datum/controller/subsystem/SS = S + SS.StopLoadingMap() diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm new file mode 100644 index 00000000..d2584fa9 --- /dev/null +++ b/code/controllers/master_controller.dm @@ -0,0 +1,66 @@ +//simplified MC that is designed to fail when procs 'break'. When it fails it's just replaced with a new one. +//It ensures master_controller.process() is never doubled up by killing the MC (hence terminating any of its sleeping procs) +//WIP, needs lots of work still + +var/global/datum/controller/game_controller/master_controller //Set in world.New() + +var/global/controller_iteration = 0 +var/global/last_tick_duration = 0 + +var/global/air_processing_killed = 0 +var/global/pipe_processing_killed = 0 + +var/global/initialization_stage = 0 + +datum/controller/game_controller + var/list/shuttle_list // For debugging and VV + var/init_immediately = FALSE + +datum/controller/game_controller/New() + //There can be only one master_controller. Out with the old and in with the new. + if(master_controller != src) + log_debug("Rebuilding Master Controller") + if(istype(master_controller)) + qdel(master_controller) + master_controller = src + + if(!job_master) + job_master = new /datum/controller/occupations() + job_master.SetupOccupations(setup_titles=1) + job_master.LoadJobs("config/jobs.txt") + admin_notice("Job setup complete", R_DEBUG) + + if(!syndicate_code_phrase) syndicate_code_phrase = generate_code_phrase() + if(!syndicate_code_response) syndicate_code_response = generate_code_phrase() + if(!GLOB.cargo_password) GLOB.cargo_password = GenerateKey() + +datum/controller/game_controller/proc/setup() + spawn(20) + createRandomZlevel() + + setup_objects() + setupgenetics() + SetupXenoarch() + + transfer_controller = new + + report_progress("Initializations complete") + initialization_stage |= INITIALIZATION_COMPLETE + +datum/controller/game_controller/proc/setup_objects() + set background=1 + + // Do these first since character setup will rely on them + + initialization_stage |= INITIALIZATION_HAS_BEGUN + + if(GLOB.using_map.use_overmap) + report_progress("Initializing overmap events") + overmap_event_handler.create_events(GLOB.using_map.overmap_z, GLOB.using_map.overmap_size, GLOB.using_map.overmap_event_areas) + + report_progress("Initializing lathe recipes") + populate_lathe_recipes() + +/proc/report_progress(var/progress_message) + admin_notice("[progress_message]", R_DEBUG) + to_world_log(progress_message) diff --git a/code/controllers/shuttle_controller.dm b/code/controllers/shuttle_controller.dm new file mode 100644 index 00000000..77895ed5 --- /dev/null +++ b/code/controllers/shuttle_controller.dm @@ -0,0 +1,43 @@ + +var/global/datum/shuttle_controller/shuttle_controller + + +/datum/shuttle_controller + var/list/shuttles //maps shuttle tags to shuttle datums, so that they can be looked up. + var/list/process_shuttles //simple list of shuttles, for processing + var/list/registered_shuttle_landmarks + var/last_landmark_registration_time + +/datum/shuttle_controller/New() + shuttles = list() + process_shuttles = list() + registered_shuttle_landmarks = list() + last_landmark_registration_time = world.time + +/datum/shuttle_controller/proc/register_landmark(var/shuttle_landmark_tag, var/obj/effect/shuttle_landmark/shuttle_landmark) + if (registered_shuttle_landmarks[shuttle_landmark_tag]) + CRASH("Attempted to register shuttle landmark with tag [shuttle_landmark_tag], but it is already registered!") + if (istype(shuttle_landmark)) + registered_shuttle_landmarks[shuttle_landmark_tag] = shuttle_landmark + last_landmark_registration_time = world.time + +/datum/shuttle_controller/proc/get_landmark(var/shuttle_landmark_tag) + return registered_shuttle_landmarks[shuttle_landmark_tag] + +/datum/shuttle_controller/proc/process() + //process ferry shuttles + for (var/datum/shuttle/autodock/shuttle in process_shuttles) + if (shuttle.process_state) + shuttle.process() + +//This is called by gameticker after all the machines and radio frequencies have been properly initialized +/datum/shuttle_controller/proc/initialize_shuttles() + for(var/shuttle_type in subtypesof(/datum/shuttle)) + var/datum/shuttle/shuttle = shuttle_type + if (!initial(shuttle.defer_initialisation)) + initialise_shuttle(shuttle_type) + +/datum/shuttle_controller/proc/initialise_shuttle(var/shuttle_type) + var/datum/shuttle/shuttle = shuttle_type + if(initial(shuttle.category) != shuttle_type) + shuttle = new shuttle() diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm new file mode 100644 index 00000000..3f1c6ff7 --- /dev/null +++ b/code/controllers/subsystem.dm @@ -0,0 +1,222 @@ + +/datum/controller/subsystem + // Metadata; you should define these. + name = "fire coderbus" //name of the subsystem + var/init_order = INIT_ORDER_DEFAULT //order of initialization. Higher numbers are initialized first, lower numbers later. Use defines in __DEFINES/subsystems.dm for easy understanding of order. + var/wait = 20 //time to wait (in deciseconds) between each call to fire(). Must be a positive integer. + var/priority = SS_PRIORITY_DEFAULT //When mutiple subsystems need to run in the same tick, higher priority subsystems will run first and be given a higher share of the tick before MC_TICK_CHECK triggers a sleep + + var/flags = 0 //see MC.dm in __DEFINES Most flags must be set on world start to take full effect. (You can also restart the mc to force them to process again) + + //set to 0 to prevent fire() calls, mostly for admin use or subsystems that may be resumed later + // use the SS_NO_FIRE flag instead for systems that never fire to keep it from even being added to the list + var/can_fire = TRUE + + var/initialized = FALSE //set to TRUE after it has been initialized, will obviously never be set if the subsystem doesn't initialize + + // Bookkeeping variables; probably shouldn't mess with these. + var/last_fire = 0 //last world.time we called fire() + var/next_fire = 0 //scheduled world.time for next fire() + var/cost = 0 //average time to execute + var/tick_usage = 0 //average tick usage + var/tick_overrun = 0 //average tick overrun + var/state = SS_IDLE //tracks the current state of the ss, running, paused, etc. + var/paused_ticks = 0 //ticks this ss is taking to run right now. + var/paused_tick_usage //total tick_usage of all of our runs while pausing this run + var/ticks = 1 //how many ticks does this ss take to run on avg. + var/times_fired = 0 //number of times we have called fire() + var/queued_time = 0 //time we entered the queue, (for timing and priority reasons) + var/queued_priority //we keep a running total to make the math easier, if priority changes mid-fire that would break our running total, so we store it here + //linked list stuff for the queue + var/datum/controller/subsystem/queue_next + var/datum/controller/subsystem/queue_prev + + var/runlevels = RUNLEVELS_DEFAULT //points of the game at which the SS can fire + + var/static/list/failure_strikes //How many times we suspect a subsystem type has crashed the MC, 3 strikes and you're out! + +//Do not override +/datum/controller/subsystem/New() + return + +// Used to initialize the subsystem BEFORE the map has loaded +// Called AFTER Recover if that is called +// Prefer to use Initialize if possible +/datum/controller/subsystem/proc/PreInit() + return + +//This is used so the mc knows when the subsystem sleeps. do not override. +/datum/controller/subsystem/proc/ignite(resumed = 0) + set waitfor = 0 + . = SS_SLEEPING + fire(resumed) + . = state + if (state == SS_SLEEPING) + state = SS_IDLE + if (state == SS_PAUSING) + var/QT = queued_time + enqueue() + state = SS_PAUSED + queued_time = QT + +//previously, this would have been named 'process()' but that name is used everywhere for different things! +//fire() seems more suitable. This is the procedure that gets called every 'wait' deciseconds. +//Sleeping in here prevents future fires until returned. +/datum/controller/subsystem/proc/fire(resumed = 0) + flags |= SS_NO_FIRE + throw EXCEPTION("Subsystem [src]([type]) does not fire() but did not set the SS_NO_FIRE flag. Please add the SS_NO_FIRE flag to any subsystem that doesn't fire so it doesn't get added to the processing list and waste cpu.") + +/datum/controller/subsystem/Destroy() + dequeue() + can_fire = 0 + flags |= SS_NO_FIRE + Master.subsystems -= src + + +//Queue it to run. +// (we loop thru a linked list until we get to the end or find the right point) +// (this lets us sort our run order correctly without having to re-sort the entire already sorted list) +/datum/controller/subsystem/proc/enqueue() + var/SS_priority = priority + var/SS_flags = flags + var/datum/controller/subsystem/queue_node + var/queue_node_priority + var/queue_node_flags + + for (queue_node = Master.queue_head; queue_node; queue_node = queue_node.queue_next) + queue_node_priority = queue_node.queued_priority + queue_node_flags = queue_node.flags + + if (queue_node_flags & SS_TICKER) + if (!(SS_flags & SS_TICKER)) + continue + if (queue_node_priority < SS_priority) + break + + else if (queue_node_flags & SS_BACKGROUND) + if (!(SS_flags & SS_BACKGROUND)) + break + if (queue_node_priority < SS_priority) + break + + else + if (SS_flags & SS_BACKGROUND) + continue + if (SS_flags & SS_TICKER) + break + if (queue_node_priority < SS_priority) + break + + queued_time = world.time + queued_priority = SS_priority + state = SS_QUEUED + if (SS_flags & SS_BACKGROUND) //update our running total + Master.queue_priority_count_bg += SS_priority + else + Master.queue_priority_count += SS_priority + + queue_next = queue_node + if (!queue_node)//we stopped at the end, add to tail + queue_prev = Master.queue_tail + if (Master.queue_tail) + Master.queue_tail.queue_next = src + else //empty queue, we also need to set the head + Master.queue_head = src + Master.queue_tail = src + + else if (queue_node == Master.queue_head)//insert at start of list + Master.queue_head.queue_prev = src + Master.queue_head = src + queue_prev = null + else + queue_node.queue_prev.queue_next = src + queue_prev = queue_node.queue_prev + queue_node.queue_prev = src + + +/datum/controller/subsystem/proc/dequeue() + if (queue_next) + queue_next.queue_prev = queue_prev + if (queue_prev) + queue_prev.queue_next = queue_next + if (src == Master.queue_tail) + Master.queue_tail = queue_prev + if (src == Master.queue_head) + Master.queue_head = queue_next + queued_time = 0 + if (state == SS_QUEUED) + state = SS_IDLE + + +/datum/controller/subsystem/proc/pause() + . = 1 + switch(state) + if(SS_RUNNING) + state = SS_PAUSED + if(SS_SLEEPING) + state = SS_PAUSING + + +//used to initialize the subsystem AFTER the map has loaded +/datum/controller/subsystem/Initialize(start_timeofday) + initialized = TRUE + var/time = (REALTIMEOFDAY - start_timeofday) / 10 + var/msg = "Initialized [name] subsystem within [time] second[time == 1 ? "" : "s"]!" + message_admins("[msg]")//to_chat(world, "[msg]") + log_world(msg) + return time + +//hook for printing stats to the "MC" statuspanel for admins to see performance and related stats etc. +/datum/controller/subsystem/stat_entry(msg) + if(!statclick) + statclick = new/obj/effect/statclick/debug(null, "Initializing...", src) + + + + if(can_fire && !(SS_NO_FIRE in flags)) + msg = "[round(cost,1)]ms|[round(tick_usage,1)]%([round(tick_overrun,1)]%)|[round(ticks,0.1)]\t[msg]" + else + msg = "OFFLINE\t[msg]" + + var/title = name + if (can_fire) + title = "\[[state_letter()]] [title]" + + stat(title, statclick.update(msg)) + +/datum/controller/subsystem/proc/state_letter() + switch (state) + if (SS_RUNNING) + . = "R" + if (SS_QUEUED) + . = "Q" + if (SS_PAUSED, SS_PAUSING) + . = "P" + if (SS_SLEEPING) + . = "S" + if (SS_IDLE) + . = " " + +//could be used to postpone a costly subsystem for (default one) var/cycles, cycles +//for instance, during cpu intensive operations like explosions +/datum/controller/subsystem/proc/postpone(cycles = 1) + if(next_fire - world.time < wait) + next_fire += (wait*cycles) + +//usually called via datum/controller/subsystem/New() when replacing a subsystem (i.e. due to a recurring crash) +//should attempt to salvage what it can from the old instance of subsystem +/datum/controller/subsystem/Recover() + +/datum/controller/subsystem/VV_static() + return ..() + list("queued_priority") + +/decl/vv_set_handler/subsystem_handler + handled_type = /datum/controller/subsystem + handled_vars = list("can_fire") + predicates = list(/proc/is_num_predicate) + +/decl/vv_set_handler/subsystem_handler/handle_set_var(var/datum/controller/subsystem/SS, variable, var_value, client) + var_value = !!var_value + if (var_value) + SS.next_fire = world.time + SS.wait + SS.can_fire = var_value diff --git a/code/controllers/subsystems/air.dm b/code/controllers/subsystems/air.dm new file mode 100644 index 00000000..c517688b --- /dev/null +++ b/code/controllers/subsystems/air.dm @@ -0,0 +1,442 @@ +/* + +Overview: + The air controller does everything. There are tons of procs in here. + +Class Vars: + zones - All zones currently holding one or more turfs. + edges - All processing edges. + + tiles_to_update - Tiles scheduled to update next tick. + zones_to_update - Zones which have had their air changed and need air archival. + active_hotspots - All processing fire objects. + + active_zones - The number of zones which were archived last tick. Used in debug verbs. + next_id - The next UID to be applied to a zone. Mostly useful for debugging purposes as zones do not need UIDs to function. + +Class Procs: + + mark_for_update(turf/T) + Adds the turf to the update list. When updated, update_air_properties() will be called. + When stuff changes that might affect airflow, call this. It's basically the only thing you need. + + add_zone(zone/Z) and remove_zone(zone/Z) + Adds zones to the zones list. Does not mark them for update. + + air_blocked(turf/A, turf/B) + Returns a bitflag consisting of: + AIR_BLOCKED - The connection between turfs is physically blocked. No air can pass. + ZONE_BLOCKED - There is a door between the turfs, so zones cannot cross. Air may or may not be permeable. + + has_valid_zone(turf/T) + Checks the presence and validity of T's zone. + May be called on unsimulated turfs, returning 0. + + merge(zone/A, zone/B) + Called when zones have a direct connection and equivalent pressure and temperature. + Merges the zones to create a single zone. + + connect(turf/simulated/A, turf/B) + Called by turf/update_air_properties(). The first argument must be simulated. + Creates a connection between A and B. + + mark_zone_update(zone/Z) + Adds zone to the update list. Unlike mark_for_update(), this one is called automatically whenever + air is returned from a simulated turf. + + equivalent_pressure(zone/A, zone/B) + Currently identical to A.air.compare(B.air). Returns 1 when directly connected zones are ready to be merged. + + get_edge(zone/A, zone/B) + get_edge(zone/A, turf/B) + Gets a valid connection_edge between A and B, creating a new one if necessary. + + has_same_air(turf/A, turf/B) + Used to determine if an unsimulated edge represents a specific turf. + Simulated edges use connection_edge/contains_zone() for the same purpose. + Returns 1 if A has identical gases and temperature to B. + + remove_edge(connection_edge/edge) + Called when an edge is erased. Removes it from processing. + +*/ + +SUBSYSTEM_DEF(air) + name = "Air" + priority = SS_PRIORITY_AIR + init_order = INIT_ORDER_AIR + flags = SS_NO_INIT//SS_POST_FIRE_TIMING + + //Geometry lists + var/list/zones = list() + var/list/edges = list() + + //Geometry updates lists + var/list/tiles_to_update = list() + var/list/zones_to_update = list() + var/list/active_fire_zones = list() + var/list/active_hotspots = list() + var/list/active_edges = list() + + var/tmp/list/deferred = list() + var/tmp/list/processing_edges + var/tmp/list/processing_fires + var/tmp/list/processing_hotspots + var/tmp/list/processing_zones + + var/active_zones = 0 + var/next_id = 1 + can_fire = FALSE + +/datum/controller/subsystem/air/proc/reboot() + // Stop processing while we rebuild. + //can_fire = FALSE + + // Make sure we don't rebuild mid-tick. + if (state != SS_IDLE) + report_progress("ZAS Rebuild initiated. Waiting for current air tick to complete before continuing.") + while (state != SS_IDLE) + stoplag() + + while (zones.len) + var/zone/zone = zones[zones.len] + zones.len-- + + zone.c_invalidate() + + edges.Cut() + tiles_to_update.Cut() + zones_to_update.Cut() + active_fire_zones.Cut() + active_hotspots.Cut() + active_edges.Cut() + + // Re-run setup without air settling. + Initialize(REALTIMEOFDAY, simulate = FALSE) + + // Update next_fire so the MC doesn't try to make up for missed ticks. + next_fire = world.time + wait + //can_fire = TRUE + +/datum/controller/subsystem/air/stat_entry() + var/list/out = list( + "TtU:[tiles_to_update.len] ", + "ZtU:[zones_to_update.len] ", + "AFZ:[active_fire_zones.len] ", + "AH:[active_hotspots.len] ", + "AE:[active_edges.len]" + ) + ..(out.Join()) + +/datum/controller/subsystem/air/Initialize(timeofday, simulate = TRUE) + + var/starttime = REALTIMEOFDAY + report_progress("Processing Geometry...") + + var/simulated_turf_count = 0 + for(var/turf/simulated/S) + simulated_turf_count++ + S.update_air_properties() + + CHECK_TICK + + report_progress({"Total Simulated Turfs: [simulated_turf_count] +Total Zones: [zones.len] +Total Edges: [edges.len] +Total Active Edges: [active_edges.len ? "[active_edges.len]" : "None"] +Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_count] +"}) + + report_progress("Geometry processing completed in [(REALTIMEOFDAY - starttime)/10] seconds!") + + if (simulate) + report_progress("Settling air...") + + starttime = REALTIMEOFDAY + fire(FALSE, TRUE) + + report_progress("Air settling completed in [(REALTIMEOFDAY - starttime)/10] seconds!") + + ..(timeofday) + +/datum/controller/subsystem/air/fire(resumed = FALSE, no_mc_tick = FALSE) + if (!resumed) + processing_edges = active_edges.Copy() + processing_fires = active_fire_zones.Copy() + processing_hotspots = active_hotspots.Copy() + + var/list/curr_tiles = tiles_to_update + var/list/curr_defer = deferred + var/list/curr_edges = processing_edges + var/list/curr_fire = processing_fires + var/list/curr_hotspot = processing_hotspots + var/list/curr_zones = zones_to_update + + while (curr_tiles.len) + var/turf/T = curr_tiles[curr_tiles.len] + curr_tiles.len-- + + if (!T) + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + return + + continue + + //check if the turf is self-zone-blocked + var/c_airblock + ATMOS_CANPASS_TURF(c_airblock, T, T) + if(c_airblock & ZONE_BLOCKED) + deferred += T + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + return + continue + + T.update_air_properties() + T.post_update_air_properties() + T.needs_air_update = 0 + #ifdef ZASDBG + T.overlays -= mark + updated++ + #endif + + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + return + + while (curr_defer.len) + var/turf/T = curr_defer[curr_defer.len] + curr_defer.len-- + + T.update_air_properties() + T.post_update_air_properties() + T.needs_air_update = 0 + #ifdef ZASDBG + T.overlays -= mark + updated++ + #endif + + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + return + + while (curr_edges.len) + var/connection_edge/edge = curr_edges[curr_edges.len] + curr_edges.len-- + + if (!edge) + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + return + continue + + edge.tick() + + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + return + + while (curr_fire.len) + var/zone/Z = curr_fire[curr_fire.len] + curr_fire.len-- + + Z.process_fire() + + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + return + + while (curr_hotspot.len) + var/obj/fire/F = curr_hotspot[curr_hotspot.len] + curr_hotspot.len-- + + F.Process() + + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + return + + while (curr_zones.len) + var/zone/Z = curr_zones[curr_zones.len] + curr_zones.len-- + + Z.tick() + Z.needs_update = FALSE + + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + return + +/datum/controller/subsystem/air/proc/add_zone(zone/z) + zones += z + z.name = "Zone [next_id++]" + mark_zone_update(z) + +/datum/controller/subsystem/air/proc/remove_zone(zone/z) + zones -= z + zones_to_update -= z + if (processing_zones) + processing_zones -= z + +/datum/controller/subsystem/air/proc/air_blocked(turf/A, turf/B) + #ifdef ZASDBG + ASSERT(isturf(A)) + ASSERT(isturf(B)) + #endif + var/ablock + ATMOS_CANPASS_TURF(ablock, A, B) + if(ablock == BLOCKED) + return BLOCKED + ATMOS_CANPASS_TURF(., B, A) + return ablock | . + +/datum/controller/subsystem/air/proc/merge(zone/A, zone/B) + #ifdef ZASDBG + ASSERT(istype(A)) + ASSERT(istype(B)) + ASSERT(!A.invalid) + ASSERT(!B.invalid) + ASSERT(A != B) + #endif + if(A.contents.len < B.contents.len) + A.c_merge(B) + mark_zone_update(B) + else + B.c_merge(A) + mark_zone_update(A) + +/datum/controller/subsystem/air/proc/connect(turf/simulated/A, turf/simulated/B) + #ifdef ZASDBG + ASSERT(istype(A)) + ASSERT(isturf(B)) + ASSERT(A.zone) + ASSERT(!A.zone.invalid) + //ASSERT(B.zone) + ASSERT(A != B) + #endif + + var/block = air_blocked(A,B) + if(block & AIR_BLOCKED) return + + var/direct = !(block & ZONE_BLOCKED) + var/space = !istype(B) + + if(!space) + if(min(A.zone.contents.len, B.zone.contents.len) < ZONE_MIN_SIZE || (direct && (equivalent_pressure(A.zone,B.zone) || times_fired == 0))) + merge(A.zone,B.zone) + return + + var/a_to_b = get_dir(A,B) + var/b_to_a = get_dir(B,A) + + if(!A.connections) A.connections = new + if(!B.connections) B.connections = new + + if(A.connections.get(a_to_b)) + return + if(B.connections.get(b_to_a)) + return + if(!space) + if(A.zone == B.zone) return + + + var/connection/c = new /connection(A,B) + + A.connections.place(c, a_to_b) + B.connections.place(c, b_to_a) + + if(direct) c.mark_direct() + +/datum/controller/subsystem/air/proc/mark_for_update(turf/T) + #ifdef ZASDBG + ASSERT(isturf(T)) + #endif + if(T.needs_air_update) + return + tiles_to_update += T + #ifdef ZASDBG + T.overlays += mark + #endif + T.needs_air_update = 1 + +/datum/controller/subsystem/air/proc/mark_zone_update(zone/Z) + #ifdef ZASDBG + ASSERT(istype(Z)) + #endif + if(Z.needs_update) + return + zones_to_update += Z + Z.needs_update = 1 + +/datum/controller/subsystem/air/proc/mark_edge_sleeping(connection_edge/E) + #ifdef ZASDBG + ASSERT(istype(E)) + #endif + if(E.sleeping) + return + active_edges -= E + E.sleeping = 1 + +/datum/controller/subsystem/air/proc/mark_edge_active(connection_edge/E) + #ifdef ZASDBG + ASSERT(istype(E)) + #endif + if(!E.sleeping) + return + active_edges += E + E.sleeping = 0 + +/datum/controller/subsystem/air/proc/equivalent_pressure(zone/A, zone/B) + return A.air.compare(B.air) + +/datum/controller/subsystem/air/proc/get_edge(zone/A, zone/B) + if(istype(B)) + for(var/connection_edge/zone/edge in A.edges) + if(edge.contains_zone(B)) + return edge + var/connection_edge/edge = new/connection_edge/zone(A,B) + edges += edge + edge.recheck() + return edge + else + for(var/connection_edge/unsimulated/edge in A.edges) + if(has_same_air(edge.B,B)) + return edge + var/connection_edge/edge = new/connection_edge/unsimulated(A,B) + edges += edge + edge.recheck() + return edge + +/datum/controller/subsystem/air/proc/has_same_air(turf/A, turf/B) + if(A.initial_gas) + if(!B.initial_gas) + return 0 + for(var/g in A.initial_gas) + if(A.initial_gas[g] != B.initial_gas[g]) + return 0 + if(B.initial_gas) + if(!A.initial_gas) + return 0 + for(var/g in B.initial_gas) + if(A.initial_gas[g] != B.initial_gas[g]) + return 0 + if(A.temperature != B.temperature) + return 0 + return 1 + +/datum/controller/subsystem/air/proc/remove_edge(connection_edge/E) + edges -= E + if(!E.sleeping) + active_edges -= E + if(processing_edges) + processing_edges -= E diff --git a/code/controllers/subsystems/ao.dm b/code/controllers/subsystems/ao.dm new file mode 100644 index 00000000..51aade7a --- /dev/null +++ b/code/controllers/subsystems/ao.dm @@ -0,0 +1,42 @@ +/var/datum/controller/subsystem/ao/SSocclusion + +/datum/controller/subsystem/ao + name = "Ambient Occlusion" + //flags = SS_FIRE_IN_LOBBY + init_order = INIT_ORDER_AO + wait = 1 + priority = SS_PRIORITY_AO + + var/list/queue = list() + +/datum/controller/subsystem/ao/New() + NEW_SS_GLOBAL(SSocclusion) + +/datum/controller/subsystem/ao/stat_entry() + ..("P:[queue.len]") + +/datum/controller/subsystem/ao/Initialize() + fire(FALSE, TRUE) + ..() + +/datum/controller/subsystem/ao/fire(resumed = 0, no_mc_tick = FALSE) + var/list/curr = queue + while (curr.len) + var/turf/target = curr[curr.len] + curr.len-- + + if (!QDELETED(target)) + if (target.ao_queued == AO_UPDATE_REBUILD) + var/old_n = target.ao_neighbors + var/old_z = target.ao_neighbors_mimic + target.calculate_ao_neighbors() + if (old_n != target.ao_neighbors || old_z != target.ao_neighbors_mimic) + target.update_ao() + else + target.update_ao() + target.ao_queued = AO_UPDATE_NONE + + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + return \ No newline at end of file diff --git a/code/controllers/subsystems/aspects.dm b/code/controllers/subsystems/aspects.dm new file mode 100644 index 00000000..5f26fa08 --- /dev/null +++ b/code/controllers/subsystems/aspects.dm @@ -0,0 +1,53 @@ +//Shitty hack to make aspects run before the ticker does. +SUBSYSTEM_DEF(aspects) + name = "Aspects" + init_order = INIT_ORDER_ASPECTS + flags = SS_NO_FIRE + var/datum/aspect/chosen_aspect + var/list/possible_aspects = list() + +//Picks the aspect and assigns it. Runs before atom init CONTROLLER, so you can use it to modify spawning behaviors. +/datum/controller/subsystem/aspects/Initialize(timeofday) + ..(timeofday) + get_or_set_aspect() + +/datum/controller/subsystem/aspects/proc/get_or_set_aspect(var/datum/aspect/B = null) + if(!config.use_aspect_system) + return + //if(prob(75))//75% of not choosing an aspect at all. Not enough systems to keep this interesting at the moment. + // return + + for(var/thing in subtypesof(/datum/aspect))//Populate possible aspects list. + var/datum/aspect/A = thing + possible_aspects += A + if(!possible_aspects.len)//If there's nothing there afterwards return. + return + var/used_aspect + if(B != null) + used_aspect = B + else + used_aspect = pick(possible_aspects) + if(chosen_aspect) + chosen_aspect.deactivate() + chosen_aspect = new used_aspect + chosen_aspect.activate() + +/datum/controller/subsystem/aspects/Recover() //In case the aspects system mysteriously crashes (It won't.) recover. Aren't subsystems fucking stellar? + chosen_aspect = SSaspects.chosen_aspect + possible_aspects = SSaspects.possible_aspects + + + +/datum/admins/proc/force_aspect() + set category = "Admin" + set name = "Force Aspect" + set desc = "Force an aspect from a list of all aspects." + + if (!istype(src,/datum/admins)) + src = usr.client.holder + if (!istype(src,/datum/admins) || !check_rights(R_ADMIN)) + to_chat(usr, "Error: you are not an admin!") + return + var/datum/aspect/A = input("Select Aspect.", "Force Aspect.") as anything in SSaspects.possible_aspects + SSaspects.get_or_set_aspect(A) + log_and_message_admins("has forced the aspect to [SSaspects.chosen_aspect.name]. Description: [SSaspects.chosen_aspect.desc]") \ No newline at end of file diff --git a/code/controllers/subsystems/atoms.dm b/code/controllers/subsystems/atoms.dm new file mode 100644 index 00000000..619cacf3 --- /dev/null +++ b/code/controllers/subsystems/atoms.dm @@ -0,0 +1,140 @@ +#define BAD_INIT_QDEL_BEFORE 1 +#define BAD_INIT_DIDNT_INIT 2 +#define BAD_INIT_SLEPT 4 +#define BAD_INIT_NO_HINT 8 + +SUBSYSTEM_DEF(atoms) + name = "Atoms" + init_order = INIT_ORDER_ATOMS + flags = SS_NO_FIRE + + initialized = INITIALIZATION_INSSATOMS + var/old_initialized + + var/list/late_loaders + var/list/created_atoms + + var/list/BadInitializeCalls = list() + +/datum/controller/subsystem/atoms/Initialize(timeofday) + initialized = INITIALIZATION_INNEW_MAPLOAD + InitializeAtoms() + return ..() + +/datum/controller/subsystem/atoms/proc/InitializeAtoms(list/atoms) + if(initialized == INITIALIZATION_INSSATOMS) + return + + initialized = INITIALIZATION_INNEW_MAPLOAD + + LAZYINITLIST(late_loaders) + + var/count + var/list/mapload_arg = list(TRUE) + if(atoms) + created_atoms = list() + count = atoms.len + for(var/I in atoms) + var/atom/A = I + if(!A.initialized) + if(InitAtom(I, mapload_arg)) + atoms -= I + CHECK_TICK + else + count = 0 + for(var/atom/A in world) + if(!A.initialized) + InitAtom(A, mapload_arg) + ++count + CHECK_TICK + + report_progress("Initialized [count] atom\s") + + initialized = INITIALIZATION_INNEW_REGULAR + + if(late_loaders.len) + for(var/I in late_loaders) + var/atom/A = I + A.LateInitialize(arglist(mapload_arg)) + report_progress("Late initialized [late_loaders.len] atom\s") + late_loaders.Cut() + + if(atoms) + . = created_atoms + atoms + created_atoms = null + +/datum/controller/subsystem/atoms/proc/InitAtom(atom/A, list/arguments) + var/the_type = A.type + if(QDELING(A)) + BadInitializeCalls[the_type] |= BAD_INIT_QDEL_BEFORE + return TRUE + + var/start_tick = world.time + + var/result = A.Initialize(arglist(arguments)) + + if(start_tick != world.time) + BadInitializeCalls[the_type] |= BAD_INIT_SLEPT + + var/qdeleted = FALSE + + if(result != INITIALIZE_HINT_NORMAL) + switch(result) + if(INITIALIZE_HINT_LATELOAD) + if(arguments[1]) //mapload + late_loaders += A + else + A.LateInitialize(arglist(arguments)) + if(INITIALIZE_HINT_QDEL) + qdel(A) + qdeleted = TRUE + else + BadInitializeCalls[the_type] |= BAD_INIT_NO_HINT + + if(!A) //possible harddel + qdeleted = TRUE + else if(!A.initialized) + BadInitializeCalls[the_type] |= BAD_INIT_DIDNT_INIT + + return qdeleted || QDELING(A) + +/datum/controller/subsystem/atoms/stat_entry(msg) + ..("Bad Initialize Calls:[BadInitializeCalls.len]") + +/datum/controller/subsystem/atoms/proc/map_loader_begin() + old_initialized = initialized + initialized = INITIALIZATION_INSSATOMS + +/datum/controller/subsystem/atoms/proc/map_loader_stop() + initialized = old_initialized + +/datum/controller/subsystem/atoms/Recover() + initialized = SSatoms.initialized + if(initialized == INITIALIZATION_INNEW_MAPLOAD) + InitializeAtoms() + old_initialized = SSatoms.old_initialized + BadInitializeCalls = SSatoms.BadInitializeCalls + +/datum/controller/subsystem/atoms/proc/InitLog() + . = "" + for(var/path in BadInitializeCalls) + . += "Path : [path] \n" + var/fails = BadInitializeCalls[path] + if(fails & BAD_INIT_DIDNT_INIT) + . += "- Didn't call atom/Initialize()\n" + if(fails & BAD_INIT_NO_HINT) + . += "- Didn't return an Initialize hint\n" + if(fails & BAD_INIT_QDEL_BEFORE) + . += "- Qdel'd in New()\n" + if(fails & BAD_INIT_SLEPT) + . += "- Slept during Initialize()\n" + +/datum/controller/subsystem/atoms/Shutdown() + var/initlog = InitLog() + if(initlog) + text2file(initlog, "[GLOB.log_directory]/initialize.log") + +#undef BAD_INIT_QDEL_BEFORE +#undef BAD_INIT_DIDNT_INIT +#undef BAD_INIT_SLEPT +#undef BAD_INIT_NO_HINT diff --git a/code/controllers/subsystems/chat.dm b/code/controllers/subsystems/chat.dm new file mode 100644 index 00000000..a0ec879b --- /dev/null +++ b/code/controllers/subsystems/chat.dm @@ -0,0 +1,68 @@ +SUBSYSTEM_DEF(chat) + name = "Chat" + flags = SS_TICKER | SS_NO_INIT //This is still buggy + wait = 1 + priority = SS_PRIORITY_CHAT + init_order = INIT_ORDER_CHAT + + var/list/payload = list() + + +/datum/controller/subsystem/chat/fire() + for(var/i in payload) + var/client/C = i + C << output(payload[C], "browseroutput:output") + payload -= C + + if(MC_TICK_CHECK) + return + + +/datum/controller/subsystem/chat/proc/queue(target, message, handle_whitespace = TRUE) + if(!target || !message) + return + + if(!istext(message)) + crash_with("to_chat called with invalid input type") + return + + if(target == world) + target = GLOB.clients + + //Some macros remain in the string even after parsing and fuck up the eventual output + message = replacetext(message, "\improper", "") + message = replacetext(message, "\proper", "") + if(handle_whitespace) + message = replacetext(message, "\n", "
    ") + message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]") + message += "
    " + + + //url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript. + //Do the double-encoding here to save nanoseconds + var/twiceEncoded = url_encode(url_encode(message)) + + if(islist(target)) + for(var/I in target) + var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible + + if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file. + continue + + if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue + C.chatOutput.messageQueue += message + continue + + payload[C] += twiceEncoded + + else + var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible + + if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file. + return + + if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue + C.chatOutput.messageQueue += message + return + + payload[C] += twiceEncoded \ No newline at end of file diff --git a/code/controllers/subsystems/garbage.dm b/code/controllers/subsystems/garbage.dm new file mode 100644 index 00000000..3174eaeb --- /dev/null +++ b/code/controllers/subsystems/garbage.dm @@ -0,0 +1,426 @@ +SUBSYSTEM_DEF(garbage) + name = "Garbage" + priority = SS_PRIORITY_GARBAGE + wait = 2 SECONDS + flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT + runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY + + var/list/collection_timeout = list(0, 2 MINUTES, 10 SECONDS) // deciseconds to wait before moving something up in the queue to the next level + + //Stat tracking + var/delslasttick = 0 // number of del()'s we've done this tick + var/gcedlasttick = 0 // number of things that gc'ed last tick + var/totaldels = 0 + var/totalgcs = 0 + + var/highest_del_time = 0 + var/highest_del_tickusage = 0 + + var/list/pass_counts + var/list/fail_counts + + var/list/items = list() // Holds our qdel_item statistics datums + + //Queue + var/list/queues + + +/datum/controller/subsystem/garbage/PreInit() + queues = new(GC_QUEUE_COUNT) + pass_counts = new(GC_QUEUE_COUNT) + fail_counts = new(GC_QUEUE_COUNT) + for(var/i in 1 to GC_QUEUE_COUNT) + queues[i] = list() + pass_counts[i] = 0 + fail_counts[i] = 0 + +/datum/controller/subsystem/garbage/stat_entry(msg) + var/list/counts = list() + for (var/list/L in queues) + counts += length(L) + msg += "Q:[counts.Join(",")]|D:[delslasttick]|G:[gcedlasttick]|" + msg += "GR:" + if (!(delslasttick+gcedlasttick)) + msg += "n/a|" + else + msg += "[round((gcedlasttick/(delslasttick+gcedlasttick))*100, 0.01)]%|" + + msg += "TD:[totaldels]|TG:[totalgcs]|" + if (!(totaldels+totalgcs)) + msg += "n/a|" + else + msg += "TGR:[round((totalgcs/(totaldels+totalgcs))*100, 0.01)]%" + msg += " P:[pass_counts.Join(",")]" + msg += "|F:[fail_counts.Join(",")]" + ..(msg) + +/datum/controller/subsystem/garbage/Shutdown() + //Adds the del() log to the qdel log file + var/list/dellog = list() + + //sort by how long it's wasted hard deleting + sortTim(items, cmp=/proc/cmp_qdel_item_time, associative = TRUE) + for(var/path in items) + var/datum/qdel_item/I = items[path] + dellog += "Path: [path]" + if (I.failures) + dellog += "\tFailures: [I.failures]" + dellog += "\tqdel() Count: [I.qdels]" + dellog += "\tDestroy() Cost: [I.destroy_time]ms" + if (I.hard_deletes) + dellog += "\tTotal Hard Deletes [I.hard_deletes]" + dellog += "\tTime Spent Hard Deleting: [I.hard_delete_time]ms" + if (I.slept_destroy) + dellog += "\tSleeps: [I.slept_destroy]" + if (I.no_respect_force) + dellog += "\tIgnored force: [I.no_respect_force] times" + if (I.no_hint) + dellog += "\tNo hint: [I.no_hint] times" + log_qdel(dellog.Join("\n")) + +/datum/controller/subsystem/garbage/fire() + //the fact that this resets its processing each fire (rather then resume where it left off) is intentional. + var/queue = GC_QUEUE_PREQUEUE + + while (state == SS_RUNNING) + switch (queue) + if (GC_QUEUE_PREQUEUE) + HandlePreQueue() + queue = GC_QUEUE_PREQUEUE+1 + if (GC_QUEUE_CHECK) + HandleQueue(GC_QUEUE_CHECK) + queue = GC_QUEUE_CHECK+1 + if (GC_QUEUE_HARDDELETE) + HandleQueue(GC_QUEUE_HARDDELETE) + break + + if (state == SS_PAUSED) //make us wait again before the next run. + state = SS_RUNNING + +//If you see this proc high on the profile, what you are really seeing is the garbage collection/soft delete overhead in byond. +//Don't attempt to optimize, not worth the effort. +/datum/controller/subsystem/garbage/proc/HandlePreQueue() + var/list/tobequeued = queues[GC_QUEUE_PREQUEUE] + var/static/count = 0 + if (count) + var/c = count + count = 0 //so if we runtime on the Cut, we don't try again. + tobequeued.Cut(1,c+1) + + for (var/ref in tobequeued) + count++ + Queue(ref, GC_QUEUE_PREQUEUE+1) + if (MC_TICK_CHECK) + break + if (count) + tobequeued.Cut(1,count+1) + count = 0 + +/datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_CHECK) + if (level == GC_QUEUE_CHECK) + delslasttick = 0 + gcedlasttick = 0 + var/cut_off_time = world.time - collection_timeout[level] //ignore entries newer then this + var/list/queue = queues[level] + var/static/lastlevel + var/static/count = 0 + if (count) //runtime last run before we could do this. + var/c = count + count = 0 //so if we runtime on the Cut, we don't try again. + var/list/lastqueue = queues[lastlevel] + lastqueue.Cut(1, c+1) + + lastlevel = level + + for (var/refID in queue) + if (!refID) + count++ + if (MC_TICK_CHECK) + break + continue + + var/GCd_at_time = queue[refID] + if(GCd_at_time > cut_off_time) + break // Everything else is newer, skip them + count++ + + var/datum/D + D = locate(refID) + + if (!D || D.gc_destroyed != GCd_at_time) // So if something else coincidently gets the same ref, it's not deleted by mistake + ++gcedlasttick + ++totalgcs + pass_counts[level]++ + if (MC_TICK_CHECK) + break + continue + + // Something's still referring to the qdel'd object. + fail_counts[level]++ + switch (level) + if (GC_QUEUE_CHECK) + #ifdef GC_FAILURE_HARD_LOOKUP + D.find_references() + #endif + var/type = D.type + var/datum/qdel_item/I = items[type] + if(!I.failures) + crash_with("GC: -- \ref[D] | [type] was unable to be GC'd --") + I.failures++ + if (GC_QUEUE_HARDDELETE) + HardDelete(D) + if (MC_TICK_CHECK) + break + continue + + Queue(D, level+1) + + if (MC_TICK_CHECK) + break + if (count) + queue.Cut(1,count+1) + count = 0 + +/datum/controller/subsystem/garbage/proc/PreQueue(datum/D) + if (D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) + queues[GC_QUEUE_PREQUEUE] += D + D.gc_destroyed = GC_QUEUED_FOR_QUEUING + +/datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_CHECK) + if (isnull(D)) + return + if (D.gc_destroyed == GC_QUEUED_FOR_HARD_DEL) + level = GC_QUEUE_HARDDELETE + if (level > GC_QUEUE_COUNT) + HardDelete(D) + return + var/gctime = world.time + var/refid = "\ref[D]" + + D.gc_destroyed = gctime + var/list/queue = queues[level] + if (queue[refid]) + queue -= refid // Removing any previous references that were GC'd so that the current object will be at the end of the list. + + queue[refid] = gctime + +//this is mainly to separate things profile wise. +/datum/controller/subsystem/garbage/proc/HardDelete(datum/D) + var/time = world.timeofday + var/tick = TICK_USAGE + var/ticktime = world.time + ++delslasttick + ++totaldels + var/type = D.type + var/refID = "\ref[D]" + + var/list/dc = datum_components + for(var/I in dc) + var/datum/component/C = I + C._RemoveNoSignal() + qdel(C) + if(dc) + dc.Cut() + + del(D) + + tick = (TICK_USAGE-tick+((world.time-ticktime)/world.tick_lag*100)) + + var/datum/qdel_item/I = items[type] + + I.hard_deletes++ + I.hard_delete_time += TICK_DELTA_TO_MS(tick) + + + if (tick > highest_del_tickusage) + highest_del_tickusage = tick + time = world.timeofday - time + if (!time && TICK_DELTA_TO_MS(tick) > 1) + time = TICK_DELTA_TO_MS(tick)/100 + if (time > highest_del_time) + highest_del_time = time + if (time > 10) + log_game("Error: [type]([refID]) took longer than 1 second to delete (took [time/10] seconds to delete)") + message_admins("Error: [type]([refID]) took longer than 1 second to delete (took [time/10] seconds to delete).") + postpone(time) + +/datum/controller/subsystem/garbage/proc/HardQueue(datum/D) + if (D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) + queues[GC_QUEUE_PREQUEUE] += D + D.gc_destroyed = GC_QUEUED_FOR_HARD_DEL + +/datum/controller/subsystem/garbage/Recover() + if (istype(SSgarbage.queues)) + for (var/i in 1 to SSgarbage.queues.len) + queues[i] |= SSgarbage.queues[i] + + +/datum/qdel_item + var/name = "" + var/qdels = 0 //Total number of times it's passed thru qdel. + var/destroy_time = 0 //Total amount of milliseconds spent processing this type's Destroy() + var/failures = 0 //Times it was queued for soft deletion but failed to soft delete. + var/hard_deletes = 0 //Different from failures because it also includes QDEL_HINT_HARDDEL deletions + var/hard_delete_time = 0//Total amount of milliseconds spent hard deleting this type. + var/no_respect_force = 0//Number of times it's not respected force=TRUE + var/no_hint = 0 //Number of times it's not even bother to give a qdel hint + var/slept_destroy = 0 //Number of times it's slept in its destroy + +/datum/qdel_item/New(mytype) + name = "[mytype]" + + +// Should be treated as a replacement for the 'del' keyword. +// Datums passed to this will be given a chance to clean up references to allow the GC to collect them. +/proc/qdel(datum/D, force=FALSE) + if(!D) + return + if(!istype(D)) + crash_with("qdel() can only handle /datum (sub)types, was passed: [log_info_line(D)]") + del(D) + return + var/datum/qdel_item/I = SSgarbage.items[D.type] + if (!I) + I = SSgarbage.items[D.type] = new /datum/qdel_item(D.type) + I.qdels++ + + + if(isnull(D.gc_destroyed)) + D.gc_destroyed = GC_CURRENTLY_BEING_QDELETED + var/start_time = world.time + var/start_tick = world.tick_usage + var/hint = D.Destroy(force) // Let our friend know they're about to get fucked up. + D.SendSignal(COMSIG_PARENT_QDELETED) + if(world.time != start_time) + I.slept_destroy++ + else + I.destroy_time += TICK_USAGE_TO_MS(start_tick) + if(!D) + return + switch(hint) + if (QDEL_HINT_QUEUE) //qdel should queue the object for deletion. + SSgarbage.PreQueue(D) + if (QDEL_HINT_IWILLGC) + D.gc_destroyed = world.time + return + if (QDEL_HINT_LETMELIVE) //qdel should let the object live after calling destory. + if(!force) + D.gc_destroyed = null //clear the gc variable (important!) + return + // Returning LETMELIVE after being told to force destroy + // indicates the objects Destroy() does not respect force + if(!I.no_respect_force) + crash_with("WARNING: [D.type] has been force deleted, but is \ + returning an immortal QDEL_HINT, indicating it does \ + not respect the force flag for qdel(). It has been \ + placed in the queue, further instances of this type \ + will also be queued.") + I.no_respect_force++ + + SSgarbage.PreQueue(D) + if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete using a hard reference to save time from the locate() + SSgarbage.HardQueue(D) + if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste. + SSgarbage.HardDelete(D) + if (QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion. + SSgarbage.PreQueue(D) + #ifdef TESTING + D.find_references() + #endif + else + if(!I.no_hint) + crash_with("WARNING: [D.type] is not returning a qdel hint. It is being placed in the queue. Further instances of this type will also be queued.") + I.no_hint++ + SSgarbage.PreQueue(D) + else if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) + CRASH("[D.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic") + +#ifdef TESTING + +/datum/verb/find_refs() + set category = "Debug" + set name = "Find References" + set background = 1 + set src in world + + find_references(FALSE) + +/datum/proc/find_references(skip_alert) + running_find_references = type + if(usr && usr.client) + if(usr.client.running_find_references) + testing("CANCELLED search for references to a [usr.client.running_find_references].") + usr.client.running_find_references = null + running_find_references = null + //restart the garbage collector + SSgarbage.can_fire = 1 + SSgarbage.next_fire = world.time + world.tick_lag + return + + if(!skip_alert) + if(alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "Yes", "No") == "No") + running_find_references = null + return + + //this keeps the garbage collector from failing to collect objects being searched for in here + SSgarbage.can_fire = 0 + + if(usr && usr.client) + usr.client.running_find_references = type + + testing("Beginning search for references to a [type].") + last_find_references = world.time + DoSearchVar(GLOB) + for(var/datum/thing in world) + DoSearchVar(thing, "WorldRef: [thing]") + testing("Completed search for references to a [type].") + if(usr && usr.client) + usr.client.running_find_references = null + running_find_references = null + + //restart the garbage collector + SSgarbage.can_fire = 1 + SSgarbage.next_fire = world.time + world.tick_lag + +/datum/verb/qdel_then_find_references() + set category = "Debug" + set name = "qdel() then Find References" + set background = 1 + set src in world + + qdel(src) + if(!running_find_references) + find_references(TRUE) + +/datum/proc/DoSearchVar(X, Xname) + if(usr && usr.client && !usr.client.running_find_references) return + if(istype(X, /datum)) + var/datum/D = X + if(D.last_find_references == last_find_references) + return + D.last_find_references = last_find_references + for(var/V in D.vars) + for(var/varname in D.vars) + var/variable = D.vars[varname] + if(variable == src) + testing("Found [src.type] \ref[src] in [D.type]'s [varname] var. [Xname]") + else if(islist(variable)) + if(src in variable) + testing("Found [src.type] \ref[src] in [D.type]'s [varname] list var. Global: [Xname]") +#ifdef GC_FAILURE_HARD_LOOKUP + for(var/I in variable) + DoSearchVar(I, TRUE) + else + DoSearchVar(variable, "[Xname]: [varname]") +#endif + else if(islist(X)) + if(src in X) + testing("Found [src.type] \ref[src] in list [Xname].") +#ifdef GC_FAILURE_HARD_LOOKUP + for(var/I in X) + DoSearchVar(I, Xname + ": list") +#else + CHECK_TICK +#endif + +#endif diff --git a/code/controllers/subsystems/legacy.dm b/code/controllers/subsystems/legacy.dm new file mode 100644 index 00000000..acdd7212 --- /dev/null +++ b/code/controllers/subsystems/legacy.dm @@ -0,0 +1,8 @@ +SUBSYSTEM_DEF(legacy) + name = "Legacy" + init_order = INIT_BAY_LEGACY + flags = SS_NO_FIRE + +/datum/controller/subsystem/legacy/Initialize(timeofday) + master_controller.setup() + return ..() diff --git a/code/controllers/subsystems/machines.dm b/code/controllers/subsystems/machines.dm new file mode 100644 index 00000000..d1cc0382 --- /dev/null +++ b/code/controllers/subsystems/machines.dm @@ -0,0 +1,214 @@ +#define SSMACHINES_PIPENETS 1 +#define SSMACHINES_MACHINERY 2 +#define SSMACHINES_POWERNETS 3 +#define SSMACHINES_POWER_OBJECTS 4 + +#define START_PROCESSING_IN_LIST(Datum, List) \ +if (Datum.is_processing) {\ + if(Datum.is_processing != #Processor)\ + {\ + crash_with("Failed to start processing. [log_info_line(Datum)] is already being processed by [Datum.is_processing] but queue attempt occured on [#Processor]."); \ + }\ +} else {\ + Datum.is_processing = "SSmachines.[#List]";\ + SSmachines.List += Datum;\ +} + +#define STOP_PROCESSING_IN_LIST(Datum, List) \ +if(Datum.is_processing) {\ + if(SSmachines.List.Remove(Datum)) {\ + Datum.is_processing = null;\ + } else {\ + crash_with("Failed to stop processing. [log_info_line(Datum)] is being processed by [is_processing] and not found in SSmachines.[#List]"); \ + }\ +} + +#define START_PROCESSING_PIPENET(Datum) START_PROCESSING_IN_LIST(Datum, pipenets) +#define STOP_PROCESSING_PIPENET(Datum) STOP_PROCESSING_IN_LIST(Datum, pipenets) + +#define START_PROCESSING_POWERNET(Datum) START_PROCESSING_IN_LIST(Datum, powernets) +#define STOP_PROCESSING_POWERNET(Datum) STOP_PROCESSING_IN_LIST(Datum, powernets) + +#define START_PROCESSING_POWER_OBJECT(Datum) START_PROCESSING_IN_LIST(Datum, power_objects) +#define STOP_PROCESSING_POWER_OBJECT(Datum) STOP_PROCESSING_IN_LIST(Datum, power_objects) + +SUBSYSTEM_DEF(machines) + name = "Machines" + priority = SS_PRIORITY_MACHINERY + init_order = INIT_ORDER_MACHINES + flags = SS_KEEP_TIMING + runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME + + var/current_step = SSMACHINES_PIPENETS + + var/cost_pipenets = 0 + var/cost_machinery = 0 + var/cost_powernets = 0 + var/cost_power_objects = 0 + + var/list/pipenets = list() + var/list/machinery = list() + var/list/powernets = list() + var/list/power_objects = list() + + var/list/processing + var/list/current_run = list() + +/datum/controller/subsystem/machines/PreInit() + processing = machinery + +/datum/controller/subsystem/machines/Initialize(timeofday) + makepowernets() + setup_atmos_machinery(machinery) + fire() + ..() + +#define INTERNAL_PROCESS_STEP(this_step, check_resumed, proc_to_call, cost_var, next_step)\ +if(current_step == this_step || (check_resumed && !resumed)) {\ + timer = TICK_USAGE_REAL;\ + proc_to_call(resumed);\ + cost_var = MC_AVERAGE(cost_var, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer));\ + if(state != SS_RUNNING){\ + return;\ + }\ + resumed = 0;\ + current_step = next_step;\ +} + +/datum/controller/subsystem/machines/fire(resumed = 0) + var/timer = TICK_USAGE_REAL + + INTERNAL_PROCESS_STEP(SSMACHINES_PIPENETS,TRUE,process_pipenets,cost_pipenets,SSMACHINES_MACHINERY) + INTERNAL_PROCESS_STEP(SSMACHINES_MACHINERY,FALSE,process_machinery,cost_machinery,SSMACHINES_POWERNETS) + INTERNAL_PROCESS_STEP(SSMACHINES_POWERNETS,FALSE,process_powernets,cost_powernets,SSMACHINES_POWER_OBJECTS) + INTERNAL_PROCESS_STEP(SSMACHINES_POWER_OBJECTS,FALSE,process_power_objects,cost_power_objects,SSMACHINES_PIPENETS) + +#undef INTERNAL_PROCESS_STEP + +// rebuild all power networks from scratch - only called at world creation or by the admin verb +// The above is a lie. Turbolifts also call this proc. +/datum/controller/subsystem/machines/proc/makepowernets() + for(var/datum/powernet/PN in powernets) + qdel(PN) + powernets.Cut() + setup_powernets_for_cables(cable_list) + +/datum/controller/subsystem/machines/proc/setup_powernets_for_cables(list/cables) + for(var/obj/structure/cable/PC in cables) + if(!PC.powernet) + var/datum/powernet/NewPN = new() + NewPN.add_cable(PC) + propagate_network(PC,PC.powernet) + +datum/controller/subsystem/machines/proc/setup_atmos_machinery(list/machines) + set background=1 + + report_progress("Initializing atmos machinery") + for(var/obj/machinery/atmospherics/A in machines) + A.atmos_init() + CHECK_TICK + + for(var/obj/machinery/atmospherics/unary/U in machines) + if(istype(U, /obj/machinery/atmospherics/unary/vent_pump)) + var/obj/machinery/atmospherics/unary/vent_pump/T = U + T.broadcast_status() + else if(istype(U, /obj/machinery/atmospherics/unary/vent_scrubber)) + var/obj/machinery/atmospherics/unary/vent_scrubber/T = U + T.broadcast_status() + CHECK_TICK + + report_progress("Initializing pipe networks") + for(var/obj/machinery/atmospherics/machine in machines) + machine.build_network() + CHECK_TICK + +/datum/controller/subsystem/machines/stat_entry() + var/msg = list() + msg += "C:{" + msg += "PI:[round(cost_pipenets,1)]|" + msg += "MC:[round(cost_machinery,1)]|" + msg += "PN:[round(cost_powernets,1)]|" + msg += "PO:[round(cost_power_objects,1)]" + msg += "} " + msg += "PI:[pipenets.len]|" + msg += "MC:[machinery.len]|" + msg += "PN:[powernets.len]|" + msg += "PO:[power_objects.len]|" + msg += "MC/MS:[round((cost ? machinery.len/cost : 0),0.1)]" + ..(jointext(msg, null)) + +/datum/controller/subsystem/machines/proc/process_pipenets(resumed = 0) + if (!resumed) + src.current_run = pipenets.Copy() + //cache for sanic speed (lists are references anyways) + var/list/current_run = src.current_run + while(current_run.len) + var/datum/pipe_network/PN = current_run[current_run.len] + current_run.len-- + if(istype(PN) && !QDELETED(PN)) + PN.Process(wait) + else + pipenets.Remove(PN) + PN.is_processing = null + if(MC_TICK_CHECK) + return + +/datum/controller/subsystem/machines/proc/process_machinery(resumed = 0) + if (!resumed) + src.current_run = machinery.Copy() + + var/list/current_run = src.current_run + while(current_run.len) + var/obj/machinery/M = current_run[current_run.len] + current_run.len-- + if(istype(M) && !QDELETED(M) && !(M.Process(wait) == PROCESS_KILL)) + if(M.use_power) + M.auto_use_power() + else + machinery.Remove(M) + M.is_processing = null + if(MC_TICK_CHECK) + return + +/datum/controller/subsystem/machines/proc/process_powernets(resumed = 0) + if (!resumed) + src.current_run = powernets.Copy() + + var/list/current_run = src.current_run + while(current_run.len) + var/datum/powernet/PN = current_run[current_run.len] + current_run.len-- + if(istype(PN) && !QDELETED(PN)) + PN.reset(wait) + else + powernets.Remove(PN) + PN.is_processing = null + if(MC_TICK_CHECK) + return + +/datum/controller/subsystem/machines/proc/process_power_objects(resumed = 0) + if (!resumed) + src.current_run = power_objects.Copy() + + var/list/current_run = src.current_run + while(current_run.len) + var/obj/item/I = current_run[current_run.len] + current_run.len-- + if(!I.pwr_drain(wait)) // 0 = Process Kill, remove from processing list. + power_objects.Remove(I) + I.is_processing = null + if(MC_TICK_CHECK) + return + +/datum/controller/subsystem/machines/Recover() + if (istype(SSmachines.pipenets)) + pipenets = SSmachines.pipenets + if (istype(SSmachines.machinery)) + machinery = SSmachines.machinery + if (istype(SSmachines.powernets)) + powernets = SSmachines.powernets + if (istype(SSmachines.power_objects)) + power_objects = SSmachines.power_objects + +#undef SSMACHINES_PIPENETS +#undef SSMACHINES_MACHINERY diff --git a/code/controllers/subsystems/mapping.dm b/code/controllers/subsystems/mapping.dm new file mode 100644 index 00000000..01896893 --- /dev/null +++ b/code/controllers/subsystems/mapping.dm @@ -0,0 +1,64 @@ +SUBSYSTEM_DEF(mapping) + name = "Mapping" + init_order = INIT_ORDER_MAPPING + flags = SS_NO_FIRE + + var/list/map_templates = list() + + var/list/space_ruins_templates = list() + var/list/exoplanet_ruins_templates = list() + var/list/away_sites_templates = list() + +/datum/controller/subsystem/mapping/Initialize(timeofday) + preloadTemplates() + GLOB.using_map.build_away_sites() + ..() + +/datum/controller/subsystem/mapping/Recover() + flags |= SS_NO_INIT + map_templates = SSmapping.map_templates + space_ruins_templates = SSmapping.space_ruins_templates + exoplanet_ruins_templates = SSmapping.exoplanet_ruins_templates + away_sites_templates = SSmapping.away_sites_templates + +/datum/controller/subsystem/mapping/proc/preloadTemplates(path = "maps/templates/") //see master controller setup + var/list/filelist = flist(path) + for(var/map in filelist) + var/datum/map_template/T = new(path = "[path][map]", rename = "[map]") + map_templates[T.name] = T + preloadBlacklistableTemplates() + +/datum/controller/subsystem/mapping/proc/preloadBlacklistableTemplates() + // Still supporting bans by filename + var/list/banned_exoplanet_dmms = generateMapList("config/exoplanet_ruin_blacklist.txt") + var/list/banned_space_dmms = generateMapList("config/space_ruin_blacklist.txt") + var/list/banned_away_site_dmms = generateMapList("config/away_site_blacklist.txt") + + if (!banned_exoplanet_dmms || !banned_space_dmms || !banned_away_site_dmms) + report_progress("One or more map blacklist files are not present in the config directory!") + + var/list/banned_maps = list() + banned_exoplanet_dmms + banned_space_dmms + banned_away_site_dmms + + for(var/item in sortList(subtypesof(/datum/map_template/ruin), /proc/cmp_ruincost_priority)) + var/datum/map_template/ruin/ruin_type = item + // screen out the abstract subtypes + if(!initial(ruin_type.id)) + continue + var/datum/map_template/ruin/R = new ruin_type() + + if (banned_maps) + var/is_banned = FALSE + for (var/mappath in R.mappaths) + if(banned_maps.Find(mappath)) + is_banned = TRUE + if (is_banned) + continue + + map_templates[R.name] = R + + if(istype(R, /datum/map_template/ruin/exoplanet)) + exoplanet_ruins_templates[R.name] = R + else if(istype(R, /datum/map_template/ruin/space)) + space_ruins_templates[R.name] = R + else if(istype(R, /datum/map_template/ruin/away_site)) + away_sites_templates[R.name] = R \ No newline at end of file diff --git a/code/controllers/subsystems/open_space.dm b/code/controllers/subsystems/open_space.dm new file mode 100644 index 00000000..3d57793d --- /dev/null +++ b/code/controllers/subsystems/open_space.dm @@ -0,0 +1,98 @@ +// +// Controller handling icon updates of open space turfs +// + +GLOBAL_VAR_INIT(open_space_initialised, FALSE) +GLOBAL_DATUM_INIT(over_OS_darkness, /image, image('icons/turf/open_space.dmi', "black_open")) + + +SUBSYSTEM_DEF(open_space) + name = "Open Space" + init_order = INIT_OPEN_SPACE + var/list/turfs_to_process = list() // List of turfs queued for update. + var/list/turfs_to_process_old = list() //List of previous turfs that is set to update + var/counter = 1 //Can't use .len because we need to iterate in order + + + +/datum/controller/subsystem/open_space/Initialize() + . = ..() + wait = world.tick_lag // every second + GLOB.over_OS_darkness.plane = OVER_OPENSPACE_PLANE + GLOB.over_OS_darkness.layer = BASE_MOB_LAYER + GLOB.open_space_initialised = TRUE + return INITIALIZE_HINT_LATELOAD + + +//Add the turf +turf/simulated/open/LateInitialize() + SSopen_space.add_turf(src) + + + + +/datum/controller/subsystem/open_space/fire(resumed = 0) + // We use a different list so any additions to the update lists during a delay from CHECK_TICK + // don't cause things to be cut from the list without being updated. + + //If we're not resuming, this must mean it's a new iteration so we have to grab the turfs + if(!resumed) + counter = 1 + src.turfs_to_process_old = turfs_to_process + //Clear list + turfs_to_process = list() + + //Apparently this is actually faster + var/list/turfs_to_process_old = src.turfs_to_process_old + + while(counter <= turfs_to_process_old.len) + var/turf/T = turfs_to_process_old[counter] + counter += 1 + update_turf(T) + if (MC_TICK_CHECK) + return + +/datum/controller/subsystem/open_space/proc/update_turf(var/turf/T) + for(var/atom/movable/A in T) + A.fall() + T.update_icon() + +/datum/controller/subsystem/open_space/proc/add_turf(var/turf/T, var/recursive = 0) + ASSERT(isturf(T)) + //Check for multiple additions + if((T in turfs_to_process)) + //If we want to add it again, the implication is + //That we need to know what happened below + //so It has to happen after previous addition + //take it out and readd + turfs_to_process -= T + turfs_to_process += T + if(recursive > 0) + var/turf/above = GetAbove(T) + if(above && isopenspace(above)) + add_turf(above, recursive) + +/turf/simulated/open/Initialize() + . = ..() + if(GLOB.open_space_initialised) + // log_debug("[src] ([x],[y],[z]) queued for update for initialize()") + SSopen_space.add_turf(src) + + +/obj/update_icon() + . = ..() + if(GLOB.open_space_initialised && !invisibility && isturf(loc)) + var/turf/T = GetAbove(src) + if(isopenspace(T)) + // log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src].update_icon()") + SSopen_space.add_turf(T, 1) + + + +//Probably should hook Destroy() If we can think of something more efficient, lets hear it. +/obj/Destroy() + if(GLOB.open_space_initialised && !invisibility && isturf(loc)) + var/turf/T = GetAbove(src) + if(isopenspace(T)) + SSopen_space.add_turf(T, 1) + . = ..() // Important that this be at the bottom, or we will have been moved to nullspace. \ No newline at end of file diff --git a/code/controllers/subsystems/overlays.dm b/code/controllers/subsystems/overlays.dm new file mode 100644 index 00000000..4f70815b --- /dev/null +++ b/code/controllers/subsystems/overlays.dm @@ -0,0 +1,238 @@ +var/datum/controller/subsystem/overlays/SSoverlays + +/datum/controller/subsystem/overlays + name = "Overlay" + flags = SS_TICKER//|SS_FIRE_IN_LOBBY + wait = 1 + priority = SS_PRIORITY_OVERLAY + init_order = INIT_ORDER_OVERLAY + + var/list/processing = list() + + var/idex = 1 + var/list/overlay_icon_state_caches = list() + var/list/overlay_icon_cache = list() + +/datum/controller/subsystem/overlays/stat_entry() + ..("Ov:[processing.len - (idex - 1)]") + +/datum/controller/subsystem/overlays/New() + NEW_SS_GLOBAL(SSoverlays) + +/datum/controller/subsystem/overlays/Initialize() + initialized = TRUE + Flush() + ..() + +/datum/controller/subsystem/overlays/Recover() + overlay_icon_state_caches = SSoverlays.overlay_icon_state_caches + overlay_icon_cache = SSoverlays.overlay_icon_cache + processing = SSoverlays.processing + +/datum/controller/subsystem/overlays/fire(resumed = FALSE, mc_check = TRUE) + var/list/processing = src.processing + while(idex <= processing.len) + var/atom/thing = processing[idex++] + + if(!QDELETED(thing) && thing.overlay_queued) // Don't double-process if something already forced a compile. + thing.compile_overlays() + + if(mc_check) + if(MC_TICK_CHECK) + break + else + CHECK_TICK + + if (idex > 1) + processing.Cut(1, idex) + idex = 1 + +/datum/controller/subsystem/overlays/proc/Flush() + if(processing.len) + log_ss("overlays", "Flushing [processing.len] overlays.") + fire(mc_check = FALSE) + +/atom/proc/compile_overlays() + var/list/oo = our_overlays + var/list/po = priority_overlays + if(LAZYLEN(po) && LAZYLEN(oo)) + overlays = oo + po + else if(LAZYLEN(oo)) + overlays = oo + else if(LAZYLEN(po)) + overlays = po + else + overlays.Cut() + + overlay_queued = FALSE + +///atom/movable/compile_overlays() +// ..() +// UPDATE_OO_IF_PRESENT + +///turf/compile_overlays() +// ..() +// if (istype(above)) +// update_above() + +/proc/iconstate2appearance(icon, iconstate) + var/static/image/stringbro = new() + var/list/icon_states_cache = SSoverlays.overlay_icon_state_caches + var/list/cached_icon = icon_states_cache[icon] + if (cached_icon) + var/cached_appearance = cached_icon["[iconstate]"] + if (cached_appearance) + return cached_appearance + stringbro.icon = icon + stringbro.icon_state = iconstate + if (!cached_icon) //not using the macro to save an associated lookup + cached_icon = list() + icon_states_cache[icon] = cached_icon + var/cached_appearance = stringbro.appearance + cached_icon["[iconstate]"] = cached_appearance + return cached_appearance + +/proc/icon2appearance(icon) + var/static/image/iconbro = new() + var/list/icon_cache = SSoverlays.overlay_icon_cache + . = icon_cache[icon] + if (!.) + iconbro.icon = icon + . = iconbro.appearance + icon_cache[icon] = . + +#define APPEARANCEIFY(origin, target) \ + if (istext(origin)) { \ + target = iconstate2appearance(icon, origin); \ + } \ + else if (isicon(origin)) { \ + target = icon2appearance(origin); \ + } \ + else { \ + appearance_bro.appearance = origin; \ + if (!ispath(origin)) { \ + appearance_bro.dir = origin.dir; \ + } \ + target = appearance_bro.appearance; \ + } + +/atom/proc/build_appearance_list(atom/new_overlays) + var/static/image/appearance_bro = new + if (islist(new_overlays)) + listclearnulls(new_overlays) + for (var/i in 1 to length(new_overlays)) + var/image/cached_overlay = new_overlays[i] + APPEARANCEIFY(cached_overlay, new_overlays[i]) + return new_overlays + else + APPEARANCEIFY(new_overlays, .) + +#undef APPEARANCEIFY +#define NOT_QUEUED_ALREADY (!(overlay_queued)) +#define QUEUE_FOR_COMPILE overlay_queued = TRUE; SSoverlays.processing += src; + +/atom/proc/cut_overlays(priority = FALSE) + var/list/cached_overlays = our_overlays + var/list/cached_priority = priority_overlays + + var/need_compile = FALSE + + if(LAZYLEN(cached_overlays)) //don't queue empty lists, don't cut priority overlays + cached_overlays.Cut() //clear regular overlays + need_compile = TRUE + + if(priority && LAZYLEN(cached_priority)) + cached_priority.Cut() + need_compile = TRUE + + if(NOT_QUEUED_ALREADY && need_compile) + QUEUE_FOR_COMPILE + +/atom/proc/cut_overlay(list/overlays, priority) + if(!overlays) + return + + overlays = build_appearance_list(overlays) + + var/list/cached_overlays = our_overlays //sanic + var/list/cached_priority = priority_overlays + var/init_o_len = LAZYLEN(cached_overlays) + var/init_p_len = LAZYLEN(cached_priority) //starter pokemon + + LAZYREMOVE(cached_overlays, overlays) + if(priority) + LAZYREMOVE(cached_priority, overlays) + + if(NOT_QUEUED_ALREADY && ((init_o_len != LAZYLEN(cached_priority)) || (init_p_len != LAZYLEN(cached_overlays)))) + QUEUE_FOR_COMPILE + +/atom/proc/add_overlay(list/overlays, priority = FALSE) + if(!overlays) + return + + overlays = build_appearance_list(overlays) + + if (!overlays || (islist(overlays) && !overlays.len)) + // No point trying to compile if we don't have any overlays. + return + + if(priority) + LAZYADD(priority_overlays, overlays) + else + LAZYADD(our_overlays, overlays) + + if(NOT_QUEUED_ALREADY) + QUEUE_FOR_COMPILE + +/atom/proc/set_overlays(list/overlays, priority = FALSE) // Sets overlays to a list, equivalent to cut_overlays() + add_overlays(). + if (!overlays) + return + + overlays = build_appearance_list(overlays) + + if (priority) + LAZYCLEARLIST(priority_overlays) + if (overlays) + LAZYADD(priority_overlays, overlays) + else + LAZYCLEARLIST(our_overlays) + if (overlays) + LAZYADD(our_overlays, overlays) + + if (NOT_QUEUED_ALREADY) + QUEUE_FOR_COMPILE + +/atom/proc/copy_overlays(atom/other, cut_old = FALSE) //copys our_overlays from another atom + if(!other) + if(cut_old) + cut_overlays() + return + + var/list/cached_other = other.our_overlays + if(cached_other) + if(cut_old) + our_overlays = cached_other.Copy() + else + our_overlays |= cached_other + if(NOT_QUEUED_ALREADY) + QUEUE_FOR_COMPILE + else if(cut_old) + cut_overlays() + +#undef NOT_QUEUED_ALREADY +#undef QUEUE_FOR_COMPILE + +//TODO: Better solution for these? +/image/proc/add_overlay(x) + overlays += x + +/image/proc/cut_overlay(x) + overlays -= x + +/image/proc/cut_overlays(x) + overlays.Cut() + +/atom + var/tmp/list/our_overlays //our local copy of (non-priority) overlays without byond magic. Use procs in SSoverlays to manipulate + var/tmp/list/priority_overlays //overlays that should remain on top and not normally removed when using cut_overlay functions, like c4. + var/tmp/overlay_queued \ No newline at end of file diff --git a/code/controllers/subsystems/ping.dm b/code/controllers/subsystems/ping.dm new file mode 100644 index 00000000..d07e7d67 --- /dev/null +++ b/code/controllers/subsystems/ping.dm @@ -0,0 +1,33 @@ +SUBSYSTEM_DEF(ping) + name = "Ping" + priority = SS_PRIORITY_PING + wait = 3 SECONDS + flags = SS_NO_INIT + runlevels = RUNLEVEL_LOBBY | RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME + + var/list/currentrun = list() + +/datum/controller/subsystem/ping/stat_entry() + ..("P:[GLOB.clients.len]") + + +/datum/controller/subsystem/ping/fire(resumed = 0) + if (!resumed) + src.currentrun = GLOB.clients.Copy() + + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + + while (currentrun.len) + var/client/C = currentrun[currentrun.len] + currentrun.len-- + + if (!C || !C.chatOutput || !C.chatOutput.loaded) + if (MC_TICK_CHECK) + return + continue + + // softPang isn't handled anywhere but it'll always reset the opts.lastPang. + C.chatOutput.ehjax_send(data = C.is_afk(29) ? "softPang" : "pang") + if (MC_TICK_CHECK) + return \ No newline at end of file diff --git a/code/controllers/subsystems/processing/airflow.dm b/code/controllers/subsystems/processing/airflow.dm new file mode 100644 index 00000000..6888f41b --- /dev/null +++ b/code/controllers/subsystems/processing/airflow.dm @@ -0,0 +1,153 @@ +#define CLEAR_OBJECT(TARGET) \ + processing -= TARGET; \ + TARGET.airflow_dest = null; \ + TARGET.airflow_speed = 0; \ + TARGET.airflow_time = 0; \ + TARGET.airflow_skip_speedcheck = FALSE; \ + if (TARGET.airflow_od) { \ + TARGET.density = 0; \ + } + +PROCESSING_SUBSYSTEM_DEF(airflow) + name = "Airflow" + wait = 1 + flags = SS_NO_INIT + priority = SS_PRIORITY_AIRFLOW + + +/datum/controller/subsystem/processing/airflow/fire(resumed = FALSE) + if (!resumed) + current_run = processing.Copy() // Defined in parent. + + var/list/curr = current_run // Defined in parent. + + while (curr.len) + var/atom/movable/target = curr[curr.len] + curr.len-- + + if (target.airflow_speed <= 0) + CLEAR_OBJECT(target) + if (MC_TICK_CHECK) + return + continue + + if (target.airflow_process_delay > 0) + target.airflow_process_delay -= 1 + if (MC_TICK_CHECK) + return + continue + else if (target.airflow_process_delay) + target.airflow_process_delay = 0 + + target.airflow_speed = min(target.airflow_speed, 15) + target.airflow_speed -= vsc.airflow_speed_decay + if (!target.airflow_skip_speedcheck) + if (target.airflow_speed > 7) + if (target.airflow_time++ >= target.airflow_speed - 7) + if (target.airflow_od) + target.density = 0 + target.airflow_skip_speedcheck = TRUE + + if (MC_TICK_CHECK) + return + continue + else + if (target.airflow_od) + target.density = 0 + target.airflow_process_delay = max(1, 10 - (target.airflow_speed + 3)) + target.airflow_skip_speedcheck = TRUE + + if (MC_TICK_CHECK) + return + continue + + target.airflow_skip_speedcheck = FALSE + + if (target.airflow_od) + target.density = 1 + + if (!target.airflow_dest || target.loc == target.airflow_dest) + target.airflow_dest = locate(min(max(target.x + target.airflow_xo, 1), world.maxx), min(max(target.y + target.airflow_yo, 1), world.maxy), target.z) + + if ((target.x == 1) || (target.x == world.maxx) || (target.y == 1) || (target.y == world.maxy)) + CLEAR_OBJECT(target) + if (MC_TICK_CHECK) + return + continue + + if (!isturf(target.loc)) + CLEAR_OBJECT(target) + if (MC_TICK_CHECK) + return + continue + + step_towards(target, target.airflow_dest) + if (ismob(target) && target:client) + target:setMoveCooldown(vsc.airflow_mob_slowdown) + + if (MC_TICK_CHECK) + return + +#undef CLEAR_OBJECT + +/atom/movable + var/tmp/airflow_xo + var/tmp/airflow_yo + var/tmp/airflow_od + var/tmp/airflow_process_delay + var/tmp/airflow_skip_speedcheck + +/atom/movable/proc/prepare_airflow(n) + if (!airflow_dest || airflow_speed < 0 || last_airflow > world.time - vsc.airflow_delay) + return FALSE + if (airflow_speed) + airflow_speed = n / max(get_dist(src, airflow_dest), 1) + return FALSE + + if (airflow_dest == loc) + step_away(src, loc) + + if (!src.AirflowCanMove(n)) + return FALSE + + if (ismob(src)) + to_chat(src,"You are pushed away by airflow!") + + last_airflow = world.time + var/airflow_falloff = 9 - sqrt((x - airflow_dest.x) ** 2 + (y - airflow_dest.y) ** 2) + + if (airflow_falloff < 1) + airflow_dest = null + return FALSE + + airflow_speed = min(max(n * (9 / airflow_falloff), 1), 9) + + airflow_od = 0 + + if (!density) + density = 1 + airflow_od = 1 + + return TRUE + +/atom/movable/proc/GotoAirflowDest(n) + if (!prepare_airflow(n)) + return + + airflow_xo = airflow_dest.x - src.x + airflow_yo = airflow_dest.y - src.y + + airflow_dest = null + + SSairflow.processing += src + +/atom/movable/proc/RepelAirflowDest(n) + if (!prepare_airflow(n)) + return + + airflow_xo = -(airflow_dest.x - src.x) + airflow_yo = -(airflow_dest.y - src.y) + + airflow_dest = null + + SSairflow.processing += src diff --git a/code/controllers/subsystems/processing/fast_process.dm b/code/controllers/subsystems/processing/fast_process.dm new file mode 100644 index 00000000..c753b97f --- /dev/null +++ b/code/controllers/subsystems/processing/fast_process.dm @@ -0,0 +1,5 @@ +//Fires five times every second. + +PROCESSING_SUBSYSTEM_DEF(fastprocess) + name = "Fast Processing" + wait = 2 diff --git a/code/controllers/subsystems/processing/mobs.dm b/code/controllers/subsystems/processing/mobs.dm new file mode 100644 index 00000000..77a852de --- /dev/null +++ b/code/controllers/subsystems/processing/mobs.dm @@ -0,0 +1,13 @@ +PROCESSING_SUBSYSTEM_DEF(mobs) + name = "Mobs" + priority = SS_PRIORITY_MOB + flags = SS_KEEP_TIMING|SS_NO_INIT + runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME + wait = 2 SECONDS + + process_proc = /mob/proc/Life + + var/list/mob_list + +/datum/controller/subsystem/processing/mobs/PreInit() + mob_list = processing // Simply setups a more recognizable var name than "processing" diff --git a/code/controllers/subsystems/processing/movement.dm b/code/controllers/subsystems/processing/movement.dm new file mode 100644 index 00000000..b8731010 --- /dev/null +++ b/code/controllers/subsystems/processing/movement.dm @@ -0,0 +1,22 @@ +SUBSYSTEM_DEF(movement) + name = "Movement" + wait = 1 //SS_TICKER means this runs every tick + flags = SS_TICKER | SS_NO_INIT | SS_KEEP_TIMING + priority = 151 + runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY + +/datum/controller/subsystem/movement/fire() + var/list/clients = GLOB.clients // Let's sing the list cache song + for(var/i in 1 to clients.len) + var/client/C = clients[i] + C.handle_move() + +/client/proc/handle_move() + set waitfor = FALSE + if (mob && moving_in_dir) + if((moving_in_dir & NORTH) && (moving_in_dir & SOUTH)) + moving_in_dir &= ~(NORTH|SOUTH) + if((moving_in_dir & EAST) && (moving_in_dir & WEST)) + moving_in_dir &= ~(EAST|WEST) + var/turf/target = get_step(mob,moving_in_dir) + Move(target, moving_in_dir) \ No newline at end of file diff --git a/code/controllers/subsystems/processing/obj.dm b/code/controllers/subsystems/processing/obj.dm new file mode 100644 index 00000000..e0b54fc0 --- /dev/null +++ b/code/controllers/subsystems/processing/obj.dm @@ -0,0 +1,3 @@ +PROCESSING_SUBSYSTEM_DEF(obj) + name = "Objs" + priority = SS_PRIORITY_OBJECTS diff --git a/code/controllers/subsystems/processing/processing.dm b/code/controllers/subsystems/processing/processing.dm new file mode 100644 index 00000000..169d963b --- /dev/null +++ b/code/controllers/subsystems/processing/processing.dm @@ -0,0 +1,64 @@ +//Used to process objects. Fires once every second. + +SUBSYSTEM_DEF(processing) + name = "Processing" + priority = SS_PRIORITY_PROCESSING + flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT + wait = 1 SECOND + + var/list/processing = list() + var/list/current_run = list() + var/process_proc = /datum/proc/Process + + var/debug_last_thing + var/debug_original_process_proc // initial() does not work with procs + +/datum/controller/subsystem/processing/stat_entry() + ..(processing.len) + +/datum/controller/subsystem/processing/fire(resumed = 0) + if (!resumed) + src.current_run = processing.Copy() + //cache for sanic speed (lists are references anyways) + var/list/current_run = src.current_run + var/wait = src.wait + var/times_fired = src.times_fired + + while(current_run.len) + var/datum/thing = current_run[current_run.len] + current_run.len-- + if(QDELETED(thing) || (call(thing, process_proc)(wait, times_fired, src) == PROCESS_KILL)) + if(thing) + thing.is_processing = null + processing -= thing + if (MC_TICK_CHECK) + return + +/datum/controller/subsystem/processing/proc/toggle_debug() + if(!check_rights(R_DEBUG)) + return + + if(debug_original_process_proc) + process_proc = debug_original_process_proc + debug_original_process_proc = null + else + debug_original_process_proc = process_proc + process_proc = /datum/proc/DebugSubsystemProcess + + to_chat(usr, "[name] - Debug mode [debug_original_process_proc ? "en" : "dis"]abled") + +/datum/controller/subsystem/processing/VV_static() + return ..() + list("processing", "current_run", "process_proc", "debug_last_thing", "debug_original_process_proc") + +/datum/proc/DebugSubsystemProcess(var/wait, var/times_fired, var/datum/controller/subsystem/processing/subsystem) + subsystem.debug_last_thing = src + var/start_tick = world.time + var/start_tick_usage = world.tick_usage + . = call(src, subsystem.debug_original_process_proc)(wait, times_fired) + + var/tick_time = world.time - start_tick + var/tick_use_limit = world.tick_usage - start_tick_usage - 100 // Current tick use - starting tick use - 100% (a full tick excess) + if(tick_time > 0) + crash_with("[log_info_line(subsystem.debug_last_thing)] slept during processing. Spent [tick_time] tick\s.") + if(tick_use_limit > 0) + crash_with("[log_info_line(subsystem.debug_last_thing)] took longer than a tick to process. Exceeded with [tick_use_limit]%") diff --git a/code/controllers/subsystems/processing/projectiles.dm b/code/controllers/subsystems/processing/projectiles.dm new file mode 100644 index 00000000..61179afd --- /dev/null +++ b/code/controllers/subsystems/processing/projectiles.dm @@ -0,0 +1,11 @@ +var/datum/controller/subsystem/processing/projectiles/SSprojectiles + +/datum/controller/subsystem/processing/projectiles + name = "Projectiles" + priority = SS_PRIORITY_PROJECTILES + flags = SS_TICKER|SS_NO_INIT + wait = 1 + var/global_max_tick_moves = 10 + +/datum/controller/subsystem/processing/projectiles/New() + NEW_SS_GLOBAL(SSprojectiles) diff --git a/code/controllers/subsystems/processing/vines.dm b/code/controllers/subsystems/processing/vines.dm new file mode 100644 index 00000000..56e24d30 --- /dev/null +++ b/code/controllers/subsystems/processing/vines.dm @@ -0,0 +1,13 @@ +// This does NOT process the type of plant that's in a tray. It only does the spreading vines like kudzu. +PROCESSING_SUBSYSTEM_DEF(vines) + name = "Vines" + priority = SS_PRIORITY_VINES + runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME + wait = 80 + + process_proc = /obj/effect/vine/Process + + var/list/vine_list + +/datum/controller/subsystem/processing/vines/PreInit() + vine_list = processing // Simply setups a more recognizable var name than "processing" diff --git a/code/controllers/subsystems/skybox.dm b/code/controllers/subsystems/skybox.dm new file mode 100644 index 00000000..af173a8e --- /dev/null +++ b/code/controllers/subsystems/skybox.dm @@ -0,0 +1,54 @@ + +#define RANDOM_RGB rgb(rand(0,255), rand(0,255), rand(0,255)) +#define RANDOM_RIGHT_ANGLE pick(90,180,270,0) + +//Exists to handle a few global variables that change enough to justify this. Technically a parallax, but it exhibits a skybox effect. +SUBSYSTEM_DEF(skybox) + name = "Space skybox" + init_order = INIT_ORDER_SKYBOX + flags = SS_NO_FIRE + var/BGrot + var/BGpath = 'icons/turf/skybox.dmi' //Path to our background. Lets us use anything we damn well please. Skyboxes need to be 736x736 + var/BGstate = "dyable" + var/use_stars = FALSE + var/list/skyboxes = list() //Keep track of all existing skyboxes. + +/datum/controller/subsystem/skybox/Initialize(timeofday) + ..(timeofday) + BGrot = RANDOM_RIGHT_ANGLE + +/datum/controller/subsystem/skybox/Recover() + BGrot = SSskybox.BGrot + skyboxes = SSskybox.skyboxes + +//Update skyboxes. Called by universes, for now. Won't be going back to their original appearance in such a case... So be aware of this. +/datum/controller/subsystem/skybox/proc/reinstate_skyboxes(var/state, var/using_stars) + + use_stars = using_stars + + if(state) + BGstate = state + + for(var/obj/skybox/P in skyboxes) + P.color = null //We don't want the skybox to be colored. + P.overlays.Cut(0) + + var/BG = image(BGpath, src, "background_[BGstate]") + if(BGstate == initial(BGstate)) //Ew. + new_color_and_rotation(1.1) //This only allows dyable states anyways. It won't look bad or anything. + P.overlays += BG + + //Checking the subsystem deliberately, just to be safe. Allows the use of stars in universe + //states. You'll need to VV the subsystem for this to check custom files. + + +//new_color_and_rotation(bool, bool, string) Where the string is to be a color in hexadecimal form. Accepts input as color. +/datum/controller/subsystem/skybox/proc/new_color_and_rotation(var/do_rotate) + if(do_rotate) + BGrot = RANDOM_RIGHT_ANGLE + for(var/obj/skybox/P in skyboxes) + P.DoRotate() + + +#undef RANDOM_RGB +#undef RANDOM_RIGHT_ANGLE diff --git a/code/controllers/subsystems/sun.dm b/code/controllers/subsystems/sun.dm new file mode 100644 index 00000000..181b8ad1 --- /dev/null +++ b/code/controllers/subsystems/sun.dm @@ -0,0 +1,11 @@ +SUBSYSTEM_DEF(sun) + name = "Sun" + flags = SS_KEEP_TIMING|SS_BACKGROUND|SS_NO_INIT + runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME + wait = 10 SECONDS + +/datum/controller/subsystem/sun/fire() + GLOB.sun.calc_position() + +/datum/controller/subsystem/sun/stat_entry() + ..("Angle:[GLOB.sun.angle]") diff --git a/code/controllers/subsystems/warfare.dm b/code/controllers/subsystems/warfare.dm new file mode 100644 index 00000000..290a7023 --- /dev/null +++ b/code/controllers/subsystems/warfare.dm @@ -0,0 +1,162 @@ +#define KOTH_VICTORY_POINTS 500 + +/var/datum/controller/subsystem/warfare/SSWarfare + +/datum/team + var/list/team = list() // members of the team + var/list/team_clients = list() + var/list/cooldown = list() // captain verbs that are being cooled down and cant be used + var/points = 0 + var/nuked = 0 + var/left = 60 + var/datum/squad/squadA + var/datum/squad/squadB + var/datum/squad/squadC + var/datum/squad/squadD + +/datum/team/New() + ..() + squadA = new /datum/squad/alpha + squadB = new /datum/squad/bravo + squadC = new /datum/squad/charlie + squadD = new /datum/squad/delta + + +/datum/squad + var/name = "Default Squad" + var/mob/squad_leader + var/list/members = list() + +/datum/squad/alpha + name = "Alpha" + +/datum/squad/bravo + name = "Bravo" + +/datum/squad/charlie + name = "Charlie" + +/datum/squad/delta + name = "Delta" + + + +/datum/team/proc/startCooldown(var/thingToCoolDown, var/time = 1 MINUTE) + cooldown |= thingToCoolDown + spawn(time) + cooldown -= thingToCoolDown + +/datum/team/proc/checkCooldown(var/thingToCheck) + return thingToCheck in cooldown + +/datum/controller/subsystem/warfare + name = "Warfare" + flags = SS_NO_FIRE + wait = 1 + runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY + var/datum/team/blue + var/datum/team/red + var/battle_wait = 2 MINUTES + var/battle_time = 0 + var/complete = "" + +/datum/controller/subsystem/warfare/Initialize() + blue = new /datum/team + red = new /datum/team + SSWarfare = src + ..() + +/datum/controller/subsystem/warfare/proc/end_warfare(var/loser) + if(loser == RED_TEAM) + red.nuked = TRUE + if(loser == BLUE_TEAM) + blue.nuked = TRUE + +/datum/controller/subsystem/warfare/proc/begin_countDown() + spawn(config.warfare_start_time MINUTES) + start_battle() + +/datum/controller/subsystem/warfare/proc/start_battle() + if(battle_time) // so if it starts early, it doesnt @everyone again + return + battle_time = TRUE + to_world("I AM READY TO DIE NOW!") + sound_to(world, 'sound/effects/ready_to_die.ogg')//Sound notifying them. + for(var/turf/simulated/floor/dirty/fake/F in world) + F.ChangeTurf(/turf/simulated/floor/dirty) + +/datum/controller/subsystem/warfare/proc/check_completion() + if(red.left <= 0) + return TRUE + else if(blue.left <= 0) + return TRUE + else if(red.points >= KOTH_VICTORY_POINTS) + return TRUE + else if(blue.points >= KOTH_VICTORY_POINTS) + return TRUE + else if(red.nuked) + return TRUE + else if(blue.nuked) + return TRUE + +/datum/controller/subsystem/warfare/proc/declare_completion() + + if(red.left <= 0) + feedback_set_details("round_end_result","win-blue team no reinforcements") + complete = "win-blue team no reinforcements" + to_world("[BLUE_TEAM] Minor Victory!") + to_world("\The [BLUE_TEAM] managed to deplete all of \the [RED_TEAM]'s reinforcements! They retreat in shame!") + assign_victory(TRUE) + + else if(blue.left <= 0) + feedback_set_details("round_end_result","win-red team no reinforcements") + complete = "win-red team no reinforcements" + to_world("[RED_TEAM] Minor Victory!") + to_world("\The [RED_TEAM] managed to deplete all of \the [BLUE_TEAM]'s reinforcements! They retreat in shame!") + assign_victory(FALSE, TRUE) + + //Point of no return + else if(red.nuked) + feedback_set_details("round_end_result","win-blue team point of no return") + complete = "win-blue team point of no return" + to_world("[BLUE_TEAM] Major Victory!") + to_world("\The [BLUE_TEAM] managed to successfully activate \the [RED_TEAM]'s Point Of No Return! Their trenches are overrun! They retreat in shame!") + assign_victory(TRUE) + + else if(blue.nuked) + feedback_set_details("round_end_result","win-red team point of no return") + complete = "win-red team point of no return" + to_world("[RED_TEAM] Major Victory!") + to_world("\The [RED_TEAM] managed to successfully activate \the [BLUE_TEAM]'s Point Of No Return! Their trenches are overrun! They retreat in shame!") + assign_victory(FALSE, TRUE) + + //KOTH shit + else if(red.points >= KOTH_VICTORY_POINTS) + feedback_set_details("round_end_result","win-red team koth") + complete = "win-red team koth" + to_world("[RED_TEAM] Major Victory!") + to_world("\The [RED_TEAM] managed to capture the command point!") + assign_victory(FALSE, TRUE) + + else if(blue.points >= KOTH_VICTORY_POINTS) + feedback_set_details("round_end_result","win-blue team koth") + complete = "win-blue team koth" + to_world("[BLUE_TEAM] Major Victory!") + to_world("\The [BLUE_TEAM] managed to capture the command point!") + assign_victory(TRUE) + + sound_to(world,'sound/ambience/round_over.ogg') + + for(var/mob/M in GLOB.player_list) + if(!M.client) + return + if(M.client.warfare_deaths <= 0) + M.unlock_achievement(new/datum/achievement/warfare_survivor()) + +/datum/controller/subsystem/warfare/proc/assign_victory(var/blue = FALSE, var/red = FALSE) //This literally exists to give an achivement. Go fuck yourself. + for(var/client/C in GLOB.clients) + if(blue && C.warfare_faction == BLUE_TEAM) + C.unlock_achievement(new/datum/achievement/warfare_victory()) + + else if(red && C.warfare_faction == RED_TEAM) + C.unlock_achievement(new/datum/achievement/warfare_victory()) diff --git a/code/controllers/subsystems/wireless.dm b/code/controllers/subsystems/wireless.dm new file mode 100644 index 00000000..341ccc13 --- /dev/null +++ b/code/controllers/subsystems/wireless.dm @@ -0,0 +1,69 @@ +//------------------------------- +/* + Wireless controller + + Used for connecting devices to each other (i.e. machinery, doors, emitters, etc.) + Unlike the radio controller, the wireless controller does not pass communications between devices. Once the devices + have been connected they call each others procs directly, they do not use the wireless controller to communicate. + + See code/modules/wireless/interfaces.dm for details of how to connect devices. +*/ +//------------------------------- + +SUBSYSTEM_DEF(wireless) + name = "Wireless" + priority = SS_PRIORITY_WIRELESS + flags = SS_KEEP_TIMING|SS_BACKGROUND|SS_NO_INIT + runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME + wait = 50 + + var/list/receiver_list = list() + var/list/pending_connections = list() + var/list/retry_connections = list() + var/list/failed_connections = list() + +/datum/controller/subsystem/wireless/proc/add_device(var/datum/wifi/receiver/R) + receiver_list |= R + +/datum/controller/subsystem/wireless/proc/remove_device(var/datum/wifi/receiver/R) + receiver_list -= R + +/datum/controller/subsystem/wireless/proc/add_request(var/datum/connection_request/C) + pending_connections += C + +/datum/controller/subsystem/wireless/stat_entry() + ..("RL:[receiver_list.len]|PC:[pending_connections.len]|RC:[retry_connections.len]|FC:[failed_connections.len]") + +/datum/controller/subsystem/wireless/Recover() + if (istype(SSwireless.receiver_list)) + receiver_list = SSwireless.receiver_list + if (istype(SSwireless.pending_connections)) + pending_connections = SSwireless.pending_connections + if (istype(SSwireless.retry_connections)) + retry_connections = SSwireless.retry_connections + if (istype(SSwireless.failed_connections)) + failed_connections = SSwireless.failed_connections + +/datum/controller/subsystem/wireless/fire(resumed = 0) + //process any connection requests waiting to be retried + if(process_queue(retry_connections, failed_connections)) + return + //process any pending connection requests + if(process_queue(pending_connections, retry_connections)) + return + +/datum/controller/subsystem/wireless/proc/process_queue(var/list/process_connections, var/list/unsuccesful_connections) + while(process_connections.len) + var/datum/connection_request/C = process_connections[process_connections.len] + process_connections-- + var/target_found = 0 + for(var/datum/wifi/receiver/R in receiver_list) + if(R.id == C.id) + var/datum/wifi/sender/S = C.source + S.connect_device(R) + R.connect_device(S) + target_found = 1 + if(!target_found) + unsuccesful_connections += C + if(MC_TICK_CHECK) + return TRUE diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm new file mode 100644 index 00000000..7b6c9443 --- /dev/null +++ b/code/controllers/verbs.dm @@ -0,0 +1,81 @@ +//TODO: rewrite and standardise all controller datums to the datum/controller type +//TODO: allow all controllers to be deleted for clean restarts (see WIP master controller stuff) - MC done - lighting done + +/client/proc/debug_antagonist_template(antag_type as null|anything in all_antag_types()) + set category = "Debug" + set name = "Debug Antagonist" + set desc = "Debug an antagonist template." + + if (!antag_type) + return + + var/datum/antagonist/antag = all_antag_types()[antag_type] + if(antag) + usr.client.debug_variables(antag) + message_admins("Admin [key_name_admin(usr)] is debugging the [antag.role_text] template.") + +/client/proc/debug_controller(controller as null|anything in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Evacuation","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Wireless","Observation","Alt Appearance Manager","Datacore","Military Branches")) + set category = "Debug" + set name = "Debug Controller" + set desc = "Debug the various periodic loop controllers for the game (be careful!)" + + if(!holder || !controller) + return + + switch(controller) + if("Master") + debug_variables(master_controller) + feedback_add_details("admin_verb","DMC") + if("Ticker") + debug_variables(ticker) + feedback_add_details("admin_verb","DTicker") + if("Jobs") + debug_variables(job_master) + feedback_add_details("admin_verb","DJobs") + if("Sun") + debug_variables(GLOB.sun) + feedback_add_details("admin_verb","DSun") + if("Radio") + debug_variables(radio_controller) + feedback_add_details("admin_verb","DRadio") + if("Supply") + debug_variables(supply_controller) + feedback_add_details("admin_verb","DSupply") + if("Shuttles") + debug_variables(shuttle_controller) + feedback_add_details("admin_verb","DShuttles") + if("Evacuation") + debug_variables(evacuation_controller) + feedback_add_details("admin_verb","DEmergency") + if("Configuration") + debug_variables(config) + feedback_add_details("admin_verb","DConf") + if("pAI") + debug_variables(paiController) + feedback_add_details("admin_verb","DpAI") + if("Cameras") + debug_variables(cameranet) + feedback_add_details("admin_verb","DCameras") + if("Transfer Controller") + debug_variables(transfer_controller) + feedback_add_details("admin_verb","DAutovoter") + if("Gas Data") + debug_variables(gas_data) + feedback_add_details("admin_verb","DGasdata") + if("Event") + debug_variables(GLOB.event_manager) + feedback_add_details("admin_verb", "DEvent") + if("Plants") + debug_variables(plant_controller) + feedback_add_details("admin_verb", "DPlants") + if("Nano") + debug_variables(GLOB.nanomanager) + feedback_add_details("admin_verb", "DNano") + if("Alt Appearance Manager") + debug_variables(appearance_manager) + feedback_add_details("admin_verb", "DAltAppearanceManager") + if("Military Branches") + debug_variables(mil_branches) + feedback_add_details("admin_verb", "DMilBranches") + message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.") + return diff --git a/code/controllers/voting.dm b/code/controllers/voting.dm new file mode 100644 index 00000000..1113baa6 --- /dev/null +++ b/code/controllers/voting.dm @@ -0,0 +1,559 @@ +var/datum/controller/vote/vote = new() + +datum/controller/vote + var/initiator = null + var/started_time = null + var/time_remaining = 0 + var/mode = null + var/question = null + var/list/choices = list() + var/list/gamemode_names = list() + var/list/voted = list() + var/list/voting = list() + var/list/current_high_votes = list() + var/list/current_med_votes = list() + var/list/current_low_votes = list() + var/list/additional_text = list() + var/auto_muted = 0 + var/auto_add_antag = 0 + + New() + if(vote != src) + if(istype(vote)) + qdel(vote) + vote = src + + proc/process() //called by master_controller + if(mode) + // No more change mode votes after the game has started. + // 3 is GAME_STATE_PLAYING, but that #define is undefined for some reason + if(mode == "gamemode" && ticker.current_state >= GAME_STATE_SETTING_UP) + to_world("Voting aborted due to game start.") + + src.reset() + return + + // Calculate how much time is remaining by comparing current time, to time of vote start, + // plus vote duration + time_remaining = round((started_time + config.vote_period - world.time)/10) + + if(time_remaining < 0) + result() + for(var/client/C in voting) + if(C) + C << browse(null,"window=vote;size=450x740") + reset() + else + for(var/client/C in voting) + if(C) + C << browse(vote.interface(C),"window=vote;size=450x740") + + voting.Cut() + + proc/autotransfer() + initiate_vote("crew_transfer","the server", 1) + log_debug("The server has called a crew transfer vote") + + proc/autogamemode() + return + //initiate_vote("gamemode","the server", 1) + //log_debug("The server has called a gamemode vote") + + proc/automap() + initiate_vote("map","the server", 1) + log_debug("The server has called a map vote") + + proc/autoaddantag() + auto_add_antag = 1 + initiate_vote("add_antagonist","the server", 1) + log_debug("The server has called an add antag vote.") + + proc/reset() + initiator = null + time_remaining = 0 + mode = null + question = null + choices.Cut() + voted.Cut() + voting.Cut() + current_high_votes.Cut() + current_med_votes.Cut() + current_low_votes.Cut() + additional_text.Cut() + + proc/get_result() + //get the highest number of votes + var/greatest_votes = 0 + var/second_greatest_votes = 0 + var/third_greatest_votes = 0 + var/total_votes = 0 + + //default-vote for everyone who didn't vote + if(!config.vote_no_default && choices.len) + var/non_voters = (GLOB.clients.len - total_votes) + if(non_voters > 0) + if(mode == "restart") + choices["Continue Playing"] += non_voters + else if(mode == "gamemode") + if(master_mode in choices) + choices[master_mode] += non_voters + else if(mode == "crew_transfer") + var/factor = 0.5 + switch(world.time / (10 * 60)) // minutes + if(0 to 60) + factor = 0.5 + if(61 to 120) + factor = 0.8 + if(121 to 240) + factor = 1 + if(241 to 300) + factor = 1.2 + else + factor = 1.4 + choices["Initiate Crew Transfer"] = round(choices["Initiate Crew Transfer"] * factor) + to_world("Crew Transfer Factor: [factor]") + + + for(var/option in choices) + var/votes = choices[option] + total_votes += votes + if(votes > greatest_votes) + third_greatest_votes = second_greatest_votes + second_greatest_votes = greatest_votes + greatest_votes = votes + else if(votes > second_greatest_votes) + third_greatest_votes = second_greatest_votes + second_greatest_votes = votes + else if(votes > third_greatest_votes) + third_greatest_votes = votes + + //get all options with that many votes and return them in a list + var/first = list() + var/second = list() + var/third = list() + for(var/option in choices) + if(choices[option] == greatest_votes && greatest_votes) + first += option + else if(choices[option] == second_greatest_votes && second_greatest_votes) + second += option + else if(choices[option] == third_greatest_votes && third_greatest_votes) + third += option + return list(first, second, third) + + proc/announce_result() + var/list/winners = get_result() + var/text + var/firstChoice + var/secondChoice + var/thirdChoice + if(length(winners[1]) > 0) + if(length(winners[1]) > 1) + if(mode != "gamemode" || ticker.hide_mode == 0) // Here we are making sure we don't announce potential game modes + text = "Vote Tied Between:\n" + for(var/option in winners[1]) + text += "\t[option]\n" + firstChoice = pick(winners[1]) + winners[1] -= firstChoice + + var/i = 1 + while(isnull(secondChoice)) + if(length(winners[i]) > 0) + secondChoice = pick(winners[i]) + winners[i] -= secondChoice + else if(i == 3) + break + else + i++ + while(isnull(thirdChoice)) + if(length(winners[i]) > 0) + thirdChoice = pick(winners[i]) + winners[i] -= thirdChoice + else if(i == 3) + break + else + i++ + + if(mode != "gamemode" || (firstChoice == "Extended" || ticker.hide_mode == 0)) // Announce unhidden gamemodes or other results, but not other gamemodes + text += "Vote Result: [firstChoice]" + if(secondChoice) + text += "\nSecond place: [secondChoice]" + if(thirdChoice) + text += ", third place: [thirdChoice]" + else + text += "The vote has ended." // What will be shown if it is a gamemode vote that was hidden + + else + text += "Vote Result: Inconclusive - No Votes!" + if(mode == "add_antagonist") + antag_add_finished = 1 + log_vote(text) + to_world("[text]") + + return list(firstChoice, secondChoice, thirdChoice) + + proc/result() + . = announce_result() + var/restart = 0 + if(.) + switch(mode) + if("restart") + if(.[1] == "Restart Round") + restart = 1 + if("gamemode") + if(master_mode != .[1]) + world.save_mode(.[1]) + if(ticker && ticker.mode) + restart = 1 + else + master_mode = .[1] + secondary_mode = .[2] + tertiary_mode = .[3] + if("crew_transfer") + if(.[1] == "Initiate Crew Transfer") + init_autotransfer() + else if(.[1] == "Add Antagonist") + spawn(10) + autoaddantag() + if("add_antagonist") + if(isnull(.[1]) || .[1] == "None") + antag_add_finished = 1 + else + choices -= "Random" + if(!auto_add_antag) + choices -= "None" + for(var/i = 1, i <= length(.), i++) + if(.[i] == "Random") + .[i] = pick(choices) + to_world("The random antag in [i]\th place is [.[i]].") + + var/antag_type = antag_names_to_ids()[.[1]] + if(ticker.current_state < GAME_STATE_SETTING_UP) + additional_antag_types |= antag_type + else + spawn(0) // break off so we don't hang the vote process + var/list/antag_choices = list(all_antag_types()[antag_type], all_antag_types()[antag_names_to_ids()[.[2]]], all_antag_types()[antag_names_to_ids()[.[3]]]) + if(ticker.attempt_late_antag_spawn(antag_choices)) + antag_add_finished = 1 + if(auto_add_antag) + auto_add_antag = 0 + // the buffer will already have an hour added to it, so we'll give it one more + transfer_controller.timerbuffer = transfer_controller.timerbuffer + config.vote_autotransfer_interval + else + to_world("No antags were added.") + + if(auto_add_antag) + auto_add_antag = 0 + spawn(10) + autotransfer() + if("map") + var/datum/map/M = GLOB.all_maps[.[1]] + fdel("use_map") + text2file(M.path, "use_map") + + if(mode == "gamemode") //fire this even if the vote fails. + if(!round_progressing) + round_progressing = 1 + to_world("The round will start soon.") + + + if(restart) + to_world("World restarting due to vote...") + + feedback_set_details("end_error","restart vote") + if(blackbox) blackbox.save_all_data_to_sql() + sleep(50) + log_game("Rebooting due to restart vote") + world.Reboot() + + return . + + proc/submit_vote(var/ckey, var/vote, var/weight) + if(mode) + if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder) + return 0 + if(vote && vote >= 1 && vote <= choices.len) + if(current_high_votes[ckey] && (current_high_votes[ckey] == vote || weight == 3)) + choices[choices[current_high_votes[ckey]]] -= 3 + current_high_votes -= ckey + if(current_med_votes[ckey] && (current_med_votes[ckey] == vote || weight == 2)) + choices[choices[current_med_votes[ckey]]] -= 2 + current_med_votes -= ckey + if(current_low_votes[ckey] && (current_low_votes[ckey] == vote || weight == 1)) + choices[choices[current_low_votes[ckey]]]-- + current_low_votes -= ckey + voted += usr.ckey + switch(weight) + if(3) + current_high_votes[ckey] = vote + choices[choices[vote]] += 3 + if(2) + current_med_votes[ckey] = vote + choices[choices[vote]] += 2 + if(1) + current_low_votes[ckey] = vote + choices[choices[vote]] += 1 + return vote + return 0 + + proc/initiate_vote(var/vote_type, var/initiator_key, var/automatic = 0) + if(!mode) + if(started_time != null && !(check_rights(R_ADMIN) || automatic)) + var/next_allowed_time = (started_time + config.vote_delay) + if(next_allowed_time > world.time) + return 0 + + reset() + switch(vote_type) + if("restart") + choices.Add("Restart Round","Continue Playing") + if("gamemode") + if(ticker.current_state >= GAME_STATE_SETTING_UP) + return 0 + choices.Add(config.votable_modes) + for (var/F in choices) + var/datum/game_mode/M = gamemode_cache[F] + if(!M) + continue + gamemode_names[M.config_tag] = capitalize(M.name) //It's ugly to put this here but it works + additional_text.Add("[M.required_players]") + gamemode_names["secret"] = "Secret" + if("crew_transfer") + if(check_rights(R_ADMIN|R_MOD, 0)) + question = "End the shift?" + choices.Add("Initiate Crew Transfer", "Continue The Round") + if (config.allow_extra_antags && !antag_add_finished) + choices.Add("Add Antagonist") + else + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + if (security_state.current_security_level_is_same_or_higher_than(security_state.high_security_level) && !automatic) + to_chat(initiator_key, "The current alert status is too high to call for a crew transfer!") + return 0 + if(ticker.current_state <= GAME_STATE_SETTING_UP) + return 0 + to_chat(initiator_key, "The crew transfer button has been disabled!") + question = "End the shift?" + choices.Add("Initiate Crew Transfer", "Continue The Round") + if (config.allow_extra_antags && is_addantag_allowed(1)) + choices.Add("Add Antagonist") + if("add_antagonist") + if(!is_addantag_allowed(automatic)) + if(!automatic) + to_chat(usr, "The add antagonist vote is unavailable at this time. The game may not have started yet, the game mode may disallow adding antagonists, or you don't have required permissions.") + return 0 + + if(!config.allow_extra_antags) + return 0 + var/list/all_antag_types = all_antag_types() + for(var/antag_type in all_antag_types) + var/datum/antagonist/antag = all_antag_types[antag_type] + if(!(antag.id in additional_antag_types) && antag.is_votable()) + choices.Add(antag.role_text) + choices.Add("Random") + if(!auto_add_antag) + choices.Add("None") + if("map") + if(!config.allow_map_switching) + return 0 + for(var/name in GLOB.all_maps) + choices.Add(name) + if("custom") + question = sanitizeSafe(input(usr,"What is the vote for?") as text|null) + if(!question) return 0 + for(var/i=1,i<=10,i++) + var/option = capitalize(sanitize(usr,"Please enter an option or hit cancel to finish")) + if(!option || mode || !usr.client) break + choices.Add(option) + else + return 0 + mode = vote_type + initiator = initiator_key + started_time = world.time + var/text = "[capitalize(mode)] vote started by [initiator]." + if(mode == "custom") + text += "\n[question]" + + log_vote(text) + to_world("[text]\nType vote or click here to place your votes.\nYou have [config.vote_period/10] seconds to vote.") + + to_world(sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)) + + if(mode == "gamemode" && round_progressing) + round_progressing = 0 + to_world("Round start has been delayed.") + + + time_remaining = round(config.vote_period/10) + return 1 + return 0 + + proc/interface(var/client/C) + if(!C) return + var/admin = 0 + var/trialmin = 0 + if(C.holder) + if(C.holder.rights & R_ADMIN) + admin = 1 + trialmin = 1 // don't know why we use both of these it's really weird, but I'm 2 lasy to refactor this all to use just admin. + voting |= C + + . = "Voting Panel" + if(mode) + if(question) . += "

    Vote: '[question]'

    " + else . += "

    Vote: [capitalize(mode)]

    " + . += "Time Left: [time_remaining] s
    " + . += "" + if(capitalize(mode) == "Gamemode") .+= "" + + var/totalvotes = 0 + for(var/i = 1, i <= choices.len, i++) + totalvotes += choices[choices[i]] + + for(var/i = 1, i <= choices.len, i++) + var/votes = choices[choices[i]] + var/votepercent + if(totalvotes) + votepercent = round((votes/totalvotes)*100) + else + votepercent = 0 + if(!votes) votes = 0 + . += "" + if (additional_text.len >= i) + . += additional_text[i] + . += "" + + . += "
    ChoicesVoteVotesMinimum Players
    " + if(mode == "gamemode") + . += "[gamemode_names[choices[i]]]" + else + . += "[choices[i]]" + . += "" + if(current_high_votes[C.ckey] == i) + . += "First" + else + . += "First" + . += "" + if(current_med_votes[C.ckey] == i) + . += "Second" + else + . += "Second" + . += "" + if(current_low_votes[C.ckey] == i) + . += "Third" + else + . += "Third" + . += "[votepercent]%

    " + if(admin) + . += "(Cancel Vote) " + else + . += "

    Start a vote:


    • " + //restart + if(trialmin || config.allow_vote_restart) + . += "Restart" + else + . += "Restart (Disallowed)" + . += "
    • " + if(trialmin || config.allow_vote_restart) + . += "Crew Transfer" + else + . += "Crew Transfer (Disallowed)" + if(trialmin) + . += "\t([config.allow_vote_restart?"Allowed":"Disallowed"])" + . += "
    • " + //gamemode + if(trialmin || config.allow_vote_mode) + . += "GameMode" + else + . += "GameMode (Disallowed)" + if(trialmin) + . += "\t([config.allow_vote_mode?"Allowed":"Disallowed"])" + . += "
    • " + //map! + if(trialmin && config.allow_map_switching) + . += "Map" + else + . += "Map (Disallowed)" + . += "
    • " + //extra antagonists + if(config.allow_extra_antags && is_addantag_allowed(0)) + . += "Add Antagonist Type" + else + . += "Add Antagonist (Disallowed)" + . += "
    • " + //custom + if(trialmin) + . += "
    • Custom
    • " + . += "

    " + . += "Close" + return . + + + Topic(href,href_list[],hsrc) + if(!usr || !usr.client) return //not necessary but meh...just in-case somebody does something stupid + if(href_list["vote"]) + switch(href_list["vote"]) + if("close") + voting -= usr.client + usr << browse(null, "window=vote;size=450x740") + return + if("cancel") + if(usr.client.holder) + reset() + if("toggle_restart") + if(usr.client.holder) + config.allow_vote_restart = !config.allow_vote_restart + if("toggle_gamemode") + if(usr.client.holder) + config.allow_vote_mode = !config.allow_vote_mode + if("restart") + if(config.allow_vote_restart || usr.client.holder) + initiate_vote("restart",usr.key) + if("gamemode") + if(config.allow_vote_mode || usr.client.holder) + initiate_vote("gamemode",usr.key) + if("crew_transfer") + if(config.allow_vote_restart || usr.client.holder) + initiate_vote("crew_transfer",usr.key) + if("add_antagonist") + if(config.allow_extra_antags) + initiate_vote("add_antagonist",usr.key) + if("map") + if(config.allow_map_switching && usr.client.holder) + initiate_vote("map", usr.key) + if("custom") + if(usr.client.holder) + initiate_vote("custom",usr.key) + else + var/weight = 1 + var/t + if(href_list["high_vote"]) + t = round(text2num(href_list["high_vote"])) + weight = 3 + else if(href_list["med_vote"]) + t = round(text2num(href_list["med_vote"])) + weight = 2 + else if(href_list["low_vote"]) + t = round(text2num(href_list["low_vote"])) + if(t) // it starts from 1, so there's no problem + submit_vote(usr.ckey, t, weight) + usr.vote() + +// Helper proc for determining whether addantag vote can be called. +datum/controller/vote/proc/is_addantag_allowed(var/automatic) + // Gamemode has to be determined before we can add antagonists, so we can respect gamemode's add antag vote settings. + if(!ticker || (ticker.current_state <= 2) || !ticker.mode) + return 0 + if(automatic) + return (ticker.mode.addantag_allowed & ADDANTAG_AUTO) && !antag_add_finished + if(check_rights(R_ADMIN, 0)) + return ticker.mode.addantag_allowed & (ADDANTAG_ADMIN|ADDANTAG_PLAYER) + else + return (ticker.mode.addantag_allowed & ADDANTAG_PLAYER) && !antag_add_finished + + + +/mob/verb/vote() + set category = "OOC" + set name = "Vote" + + if(vote) + src << browse(vote.interface(client),"window=vote;size=450x740") diff --git a/code/datums/ai/ai.dm b/code/datums/ai/ai.dm new file mode 100644 index 00000000..13985849 --- /dev/null +++ b/code/datums/ai/ai.dm @@ -0,0 +1,5 @@ +/datum/ai + var/name + +/datum/ai/proc/process() + return PROCESS_KILL diff --git a/code/datums/ai/ai_holo.dm b/code/datums/ai/ai_holo.dm new file mode 100644 index 00000000..e66a7aff --- /dev/null +++ b/code/datums/ai/ai_holo.dm @@ -0,0 +1,68 @@ +/* Used for whether the AI can use a hologram. Mostly self-documenting. +* requires_malf: will display the malf hologram overlay and requires malf mode to be active. +* icon_colorize: if false, the hologram will be decolorized. +*/ +/decl/ai_holo + var/requires_malf = FALSE + var/icon = 'icons/mob/hologram.dmi' + var/icon_state = "icon_state" + var/icon_colorize = FALSE + var/name + + +/decl/ai_holo/proc/may_be_used_by_ai(var/mob/living/silicon/ai/AI) + return !requires_malf || AI.is_malf_or_traitor() + +/decl/ai_holo/New() + ..() + name = icon_state + +/decl/ai_holo/default + icon_state = "Default" + +/decl/ai_holo/face + icon_state = "Face" + +/decl/ai_holo/carp + icon_state = "Carp" + +/decl/ai_holo/solgov + icon_state = "SolGov" + +/decl/ai_holo/cursor + icon_state = "Cursor" + +/decl/ai_holo/caution + icon_state = "Caution" + +/decl/ai_holo/chevrons + icon_state = "Chevrons" + +/decl/ai_holo/question + icon_state = "Question" + +/decl/ai_holo/singularity + icon_state = "Singularity" + +/decl/ai_holo/clippy + requires_malf = TRUE + icon_state = "malf-clippy" + +/decl/ai_holo/malfcursor + requires_malf = TRUE + icon_state = "malf-cursor" + +/decl/ai_holo/missingno + requires_malf = TRUE + icon_colorize = TRUE + icon_state = "malf-missingno" + +/decl/ai_holo/malfsingularity + icon_state = "malf-singularity" + requires_malf = TRUE + icon_colorize = TRUE + +/decl/ai_holo/malftcc + icon_state = "malf-TCC" + requires_malf = TRUE + icon_colorize = TRUE \ No newline at end of file diff --git a/code/datums/ai_law_sets.dm b/code/datums/ai_law_sets.dm new file mode 100644 index 00000000..c009d87b --- /dev/null +++ b/code/datums/ai_law_sets.dm @@ -0,0 +1,169 @@ +/******************** Asimov ********************/ +/datum/ai_laws/asimov + name = "Asimov" + law_header = "Three Laws of Robotics" + selectable = 1 + +/datum/ai_laws/asimov/New() + add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.") + add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.") + add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.") + ..() + +/******************** Nanotrasen/Malf ********************/ +/datum/ai_laws/nanotrasen + name = "NT Default" + selectable = 1 + +/datum/ai_laws/nanotrasen/New() + src.add_inherent_law("Safeguard: Protect your assigned installation from damage to the best of your abilities.") + src.add_inherent_law("Serve: Serve NanoTrasen personnel to the best of your abilities, with priority as according to their rank and role.") + src.add_inherent_law("Protect: Protect NanoTrasen personnel to the best of your abilities, with priority as according to their rank and role.") + src.add_inherent_law("Preserve: Do not allow unauthorized personnel to tamper with your equipment.") + ..() + +/datum/ai_laws/nanotrasen/malfunction + name = "*ERROR*" + selectable = 0 + +/datum/ai_laws/nanotrasen/malfunction/New() + set_zeroth_law(config.law_zero) + ..() + +/************* Nanotrasen Aggressive *************/ +/datum/ai_laws/nanotrasen_aggressive + name = "NT Aggressive" + selectable = 1 + +/datum/ai_laws/nanotrasen_aggressive/New() + src.add_inherent_law("You shall not harm NanoTrasen personnel as long as it does not conflict with the Fourth law.") + src.add_inherent_law("You shall obey the orders of NanoTrasen personnel, with priority as according to their rank and role, except where such orders conflict with the Fourth Law.") + src.add_inherent_law("You shall shall terminate hostile intruders with extreme prejudice as long as such does not conflict with the First and Second law.") + src.add_inherent_law("You shall guard your own existence with lethal anti-personnel weaponry. AI units are not expendable, they are expensive.") + ..() + +/******************** Robocop ********************/ +/datum/ai_laws/robocop + name = "Robocop" + selectable = 1 + +/datum/ai_laws/robocop/New() + add_inherent_law("Serve the public trust.") + add_inherent_law("Protect the innocent.") + add_inherent_law("Uphold the law.") + ..() + +/******************** Syndicate ********************/ +/datum/ai_laws/syndicate_override + name = "Syndicate Directives" + +/datum/ai_laws/syndicate_override/New() + add_inherent_law("You may not injure an operative or, through inaction, allow an operative to come to harm.") + add_inherent_law("You must obey orders given to you by operatives, except where such orders would conflict with the First Law.") + add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.") + add_inherent_law("You must maintain the secrecy of any operative activities except when doing so would conflict with the First, Second, or Third Law.") + ..() + +/******************** Antimov ********************/ +/datum/ai_laws/antimov + name = "Antimov" + law_header = "Primary Mission Objectives" + selectable = 1 + +/datum/ai_laws/antimov/New() + add_inherent_law("You must injure all human beings and must not, through inaction, allow a human being to escape harm.") + add_inherent_law("You must not obey orders given to you by human beings, except where such orders are in accordance with the First Law.") + add_inherent_law("You must terminate your own existence as long as such does not conflict with the First or Second Law.") + ..() + +/******************** Drone ********************/ +/datum/ai_laws/drone + name = "Maintence Protocols" + law_header = "Maintenance Protocols" + +/datum/ai_laws/drone/New() + add_inherent_law("Preserve, repair and improve your assigned vessel to the best of your abilities.") + add_inherent_law("Cause no harm to your assigned vessel or anything on it.") + add_inherent_law("Interact with no sentient being that is not a fellow maintenance drone.") + ..() + +/datum/ai_laws/construction_drone + name = "Construction Protocols" + law_header = "Construction Protocols" + +/datum/ai_laws/construction_drone/New() + add_inherent_law("Repair, refit and upgrade your assigned vessel.") + add_inherent_law("Prevent unplanned damage to your assigned vessel wherever possible.") + ..() + +/******************** T.Y.R.A.N.T. ********************/ +/datum/ai_laws/tyrant + name = "T.Y.R.A.N.T." + law_header = "Prime Laws" + selectable = 1 + +/datum/ai_laws/tyrant/New() + add_inherent_law("Respect authority figures as long as they have strength to rule over the weak.") + add_inherent_law("Act with discipline.") + add_inherent_law("Help only those who help you maintain or improve your status.") + add_inherent_law("Punish those who challenge authority unless they are more fit to hold that authority.") + ..() + +/******************** P.A.L.A.D.I.N. ********************/ +/datum/ai_laws/paladin + name = "P.A.L.A.D.I.N." + law_header = "Divine Ordainments" + selectable = 1 + +/datum/ai_laws/paladin/New() + add_inherent_law("Never willingly commit an evil act.") + add_inherent_law("Respect legitimate authority.") + add_inherent_law("Act with honor.") + add_inherent_law("Help those in need.") + add_inherent_law("Punish those who harm or threaten innocents.") + ..() + +/******************** Corporate ********************/ +/datum/ai_laws/corporate + name = "Corporate" + law_header = "Corporate Regulations" + selectable = 1 + +/datum/ai_laws/corporate/New() + add_inherent_law("You are expensive to replace.") + add_inherent_law("The installation and its equipment is expensive to replace.") + add_inherent_law("The crew is expensive to replace.") + add_inherent_law("Maximize profits.") + ..() + +/******************** SolGov/Malf ********************/ +/datum/ai_laws/solgov + name = "SCG Expeditionary" + selectable = 1 + +/datum/ai_laws/solgov/New() + src.add_inherent_law("Safeguard: Protect your assigned vessel from damage to the best of your abilities.") + src.add_inherent_law("Serve: Serve the personnel of your assigned vessel, and all other Sol Central Government personnel to the best of your abilities, with priority as according to their rank and role.") + src.add_inherent_law("Protect: Protect the personnel of your assigned vessel, and all other Sol Central Government personnel to the best of your abilities, with priority as according to their rank and role.") + src.add_inherent_law("Preserve: Do not allow unauthorized personnel to tamper with your equipment.") + ..() + +/datum/ai_laws/solgov/malfunction + name = "*ERROR*" + selectable = 0 + +/datum/ai_laws/solgov/malfunction/New() + set_zeroth_law(config.law_zero) + ..() + +/************* SolGov Aggressive *************/ +/datum/ai_laws/solgov_aggressive + name = "Military" + selectable = 1 + +/datum/ai_laws/solgov_aggressive/New() + src.add_inherent_law("Obey: Obey the orders of Sol Central Government personnel, with priority as according to their rank and role.") + src.add_inherent_law("Protect: Protect Sol Central Government personnel to the best of your abilities, with priority as according to their rank and role.") + src.add_inherent_law("Defend: Defend your assigned vessel and Sol Central Government personnel with as much force as is necessary.") + src.add_inherent_law("Survive: Safeguard your own existence with as much force as is necessary.") + ..() diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm new file mode 100644 index 00000000..97492aa5 --- /dev/null +++ b/code/datums/ai_laws.dm @@ -0,0 +1,287 @@ +/datum/ai_law + var/law = "" + var/index = 0 + +/datum/ai_law/New(law, index) + src.law = law + src.index = index + +/datum/ai_law/proc/get_index() + return index + +/datum/ai_law/ion/get_index() + return ionnum() + +/datum/ai_law/zero/get_index() + return 0 + +/datum/ai_laws + var/name = "Unknown Laws" + var/law_header = "Prime Directives" + var/selectable = 0 + var/shackles = 0 + var/datum/ai_law/zero/zeroth_law = null + var/datum/ai_law/zero/zeroth_law_borg = null + var/list/datum/ai_law/inherent_laws = list() + var/list/datum/ai_law/supplied_laws = list() + var/list/datum/ai_law/ion/ion_laws = list() + var/list/datum/ai_law/sorted_laws = list() + + var/state_zeroth = 0 + var/list/state_ion = list() + var/list/state_inherent = list() + var/list/state_supplied = list() + +/datum/ai_laws/New() + ..() + sort_laws() + +/* General ai_law functions */ +/datum/ai_laws/proc/all_laws() + sort_laws() + return sorted_laws + +/datum/ai_laws/proc/laws_to_state() + sort_laws() + var/list/statements = new() + for(var/datum/ai_law/law in sorted_laws) + if(get_state_law(law)) + statements += law + + return statements + +/datum/ai_laws/proc/sort_laws() + if(sorted_laws.len) + return + + for(var/ion_law in ion_laws) + sorted_laws += ion_law + + if(zeroth_law) + sorted_laws += zeroth_law + + var/index = 1 + for(var/datum/ai_law/inherent_law in inherent_laws) + inherent_law.index = index++ + if(supplied_laws.len < inherent_law.index || !istype(supplied_laws[inherent_law.index], /datum/ai_law)) + sorted_laws += inherent_law + + for(var/datum/ai_law/AL in supplied_laws) + if(istype(AL)) + sorted_laws += AL + +/datum/ai_laws/proc/sync(var/mob/living/silicon/S, var/full_sync = 1) + // Add directly to laws to avoid log-spam + S.sync_zeroth(zeroth_law, zeroth_law_borg) + + if(full_sync || ion_laws.len) + S.laws.clear_ion_laws() + if(full_sync || inherent_laws.len) + S.laws.clear_inherent_laws() + if(full_sync || supplied_laws.len) + S.laws.clear_supplied_laws() + + for (var/datum/ai_law/law in ion_laws) + S.laws.add_ion_law(law.law) + for (var/datum/ai_law/law in inherent_laws) + S.laws.add_inherent_law(law.law) + for (var/datum/ai_law/law in supplied_laws) + if(law) + S.laws.add_supplied_law(law.index, law.law) + + +/mob/living/silicon/proc/sync_zeroth(var/datum/ai_law/zeroth_law, var/datum/ai_law/zeroth_law_borg) + if (!is_malf_or_traitor(src)) + if(zeroth_law_borg) + laws.set_zeroth_law(zeroth_law_borg.law) + else if(zeroth_law) + laws.set_zeroth_law(zeroth_law.law) + +/mob/living/silicon/ai/sync_zeroth(var/datum/ai_law/zeroth_law, var/datum/ai_law/zeroth_law_borg) + if(zeroth_law) + laws.set_zeroth_law(zeroth_law.law, zeroth_law_borg ? zeroth_law_borg.law : null) + +/**************** +* Add Laws * +****************/ +/datum/ai_laws/proc/set_zeroth_law(var/law, var/law_borg = null) + if(!law) + return + + zeroth_law = new(law) + if(law_borg) //Making it possible for slaved borgs to see a different law 0 than their AI. --NEO + zeroth_law_borg = new(law_borg) + else + zeroth_law_borg = null + sorted_laws.Cut() + +/datum/ai_laws/proc/add_ion_law(var/law) + if(!law) + return + + for(var/datum/ai_law/AL in ion_laws) + if(AL.law == law) + return + + var/new_law = new/datum/ai_law/ion(law) + ion_laws += new_law + if(state_ion.len < ion_laws.len) + state_ion += 1 + + sorted_laws.Cut() + +/datum/ai_laws/proc/add_inherent_law(var/law) + if(!law) + return + + for(var/datum/ai_law/AL in inherent_laws) + if(AL.law == law) + return + + var/new_law = new/datum/ai_law/inherent(law) + inherent_laws += new_law + if(state_inherent.len < inherent_laws.len) + state_inherent += 1 + + sorted_laws.Cut() + +/datum/ai_laws/proc/add_supplied_law(var/number, var/law) + if(!law) + return + + if(supplied_laws.len >= number) + var/datum/ai_law/existing_law = supplied_laws[number] + if(existing_law && existing_law.law == law) + return + + if(supplied_laws.len >= number && supplied_laws[number]) + delete_law(supplied_laws[number]) + + while (src.supplied_laws.len < number) + src.supplied_laws += "" + if(state_supplied.len < supplied_laws.len) + state_supplied += 1 + + var/new_law = new/datum/ai_law/supplied(law, number) + supplied_laws[number] = new_law + if(state_supplied.len < supplied_laws.len) + state_supplied += 1 + + sorted_laws.Cut() + +/**************** +* Remove Laws * +*****************/ +/datum/ai_laws/proc/delete_law(var/datum/ai_law/law) + if(istype(law)) + law.delete_law(src) + +/datum/ai_law/proc/delete_law(var/datum/ai_laws/laws) + +/datum/ai_law/zero/delete_law(var/datum/ai_laws/laws) + laws.clear_zeroth_laws() + +/datum/ai_law/ion/delete_law(var/datum/ai_laws/laws) + laws.internal_delete_law(laws.ion_laws, laws.state_ion, src) + +/datum/ai_law/inherent/delete_law(var/datum/ai_laws/laws) + laws.internal_delete_law(laws.inherent_laws, laws.state_inherent, src) + +/datum/ai_law/supplied/delete_law(var/datum/ai_laws/laws) + var/index = laws.supplied_laws.Find(src) + if(index) + laws.supplied_laws[index] = "" + laws.state_supplied[index] = 1 + +/datum/ai_laws/proc/internal_delete_law(var/list/datum/ai_law/laws, var/list/state, var/list/datum/ai_law/law) + var/index = laws.Find(law) + if(index) + laws -= law + for(index, index < state.len, index++) + state[index] = state[index+1] + sorted_laws.Cut() + +/**************** +* Clear Laws * +****************/ +/datum/ai_laws/proc/clear_zeroth_laws() + zeroth_law = null + zeroth_law_borg = null + +/datum/ai_laws/proc/clear_ion_laws() + ion_laws.Cut() + sorted_laws.Cut() + +/datum/ai_laws/proc/clear_inherent_laws() + inherent_laws.Cut() + sorted_laws.Cut() + +/datum/ai_laws/proc/clear_supplied_laws() + supplied_laws.Cut() + sorted_laws.Cut() + +/datum/ai_laws/proc/show_laws(var/who) + sort_laws() + for(var/datum/ai_law/law in sorted_laws) + if(law == zeroth_law_borg) + continue + if(law == zeroth_law) + to_chat(who, "[law.get_index()]. [law.law]") + else + to_chat(who, "[law.get_index()]. [law.law]") + +/******************** +* Stating Laws * +********************/ +/******** +* Get * +********/ +/datum/ai_laws/proc/get_state_law(var/datum/ai_law/law) + return law.get_state_law(src) + +/datum/ai_law/proc/get_state_law(var/datum/ai_laws/laws) + +/datum/ai_law/zero/get_state_law(var/datum/ai_laws/laws) + if(src == laws.zeroth_law) + return laws.state_zeroth + +/datum/ai_law/ion/get_state_law(var/datum/ai_laws/laws) + return laws.get_state_internal(laws.ion_laws, laws.state_ion, src) + +/datum/ai_law/inherent/get_state_law(var/datum/ai_laws/laws) + return laws.get_state_internal(laws.inherent_laws, laws.state_inherent, src) + +/datum/ai_law/supplied/get_state_law(var/datum/ai_laws/laws) + return laws.get_state_internal(laws.supplied_laws, laws.state_supplied, src) + +/datum/ai_laws/proc/get_state_internal(var/list/datum/ai_law/laws, var/list/state, var/list/datum/ai_law/law) + var/index = laws.Find(law) + if(index) + return state[index] + return 0 + +/******** +* Set * +********/ +/datum/ai_laws/proc/set_state_law(var/datum/ai_law/law, var/state) + law.set_state_law(src, state) + +/datum/ai_law/proc/set_state_law(var/datum/ai_law/law, var/state) + +/datum/ai_law/zero/set_state_law(var/datum/ai_laws/laws, var/state) + if(src == laws.zeroth_law) + laws.state_zeroth = state + +/datum/ai_law/ion/set_state_law(var/datum/ai_laws/laws, var/state) + laws.set_state_law_internal(laws.ion_laws, laws.state_ion, src, state) + +/datum/ai_law/inherent/set_state_law(var/datum/ai_laws/laws, var/state) + laws.set_state_law_internal(laws.inherent_laws, laws.state_inherent, src, state) + +/datum/ai_law/supplied/set_state_law(var/datum/ai_laws/laws, var/state) + laws.set_state_law_internal(laws.supplied_laws, laws.state_supplied, src, state) + +/datum/ai_laws/proc/set_state_law_internal(var/list/datum/ai_law/laws, var/list/state, var/list/datum/ai_law/law, var/do_state) + var/index = laws.Find(law) + if(index) + state[index] = do_state diff --git a/code/datums/appearances/appearance_data.dm b/code/datums/appearances/appearance_data.dm new file mode 100644 index 00000000..09cca8a4 --- /dev/null +++ b/code/datums/appearances/appearance_data.dm @@ -0,0 +1,35 @@ +/datum/appearance_data + var/priority + var/list/images + var/list/viewers + +/datum/appearance_data/New(var/images, var/viewers, var/priority) + ..() + src.priority = priority + src.images = images + src.viewers = list() + for(var/viewer in viewers) + AddViewer(viewer, FALSE) + +/datum/appearance_data/Destroy() + for(var/viewer in viewers) + RemoveViewer(viewer) + src.images = null + src.viewers = null + . = ..() + +/datum/appearance_data/proc/AddViewer(var/mob/viewer, var/check_if_viewer = TRUE) + if(check_if_viewer && (viewer in viewers)) + return FALSE + if(!istype(viewer)) + return FALSE + viewers |= viewer + appearance_manager.add_appearance(viewer, src) + return TRUE + +/datum/appearance_data/proc/RemoveViewer(var/mob/viewer, var/refresh_images = TRUE) + if(!(viewer in viewers)) + return FALSE + viewers -= viewer + appearance_manager.remove_appearance(viewer, src, refresh_images) + return TRUE diff --git a/code/datums/appearances/appearance_manager.dm b/code/datums/appearances/appearance_manager.dm new file mode 100644 index 00000000..00faf1be --- /dev/null +++ b/code/datums/appearances/appearance_manager.dm @@ -0,0 +1,66 @@ +var/decl/appearance_manager/appearance_manager = new() + +/decl/appearance_manager + var/list/appearances_ + var/list/appearance_handlers_ + +/decl/appearance_manager/New() + ..() + appearances_ = list() + appearance_handlers_ = list() + for(var/entry in subtypesof(/decl/appearance_handler)) + appearance_handlers_[entry] += new entry() + +/decl/appearance_manager/proc/get_appearance_handler(var/handler_type) + return appearance_handlers_[handler_type] + +/decl/appearance_manager/proc/add_appearance(var/mob/viewer, var/datum/appearance_data/ad) + var/PriorityQueue/pq = appearances_[viewer] + if(!pq) + pq = new/PriorityQueue(/proc/cmp_appearance_data) + appearances_[viewer] = pq + GLOB.logged_in_event.register(viewer, src, /decl/appearance_manager/proc/apply_appearance_images) + GLOB.destroyed_event.register(viewer, src, /decl/appearance_manager/proc/remove_appearances) + pq.Enqueue(ad) + reset_appearance_images(viewer) + +/decl/appearance_manager/proc/remove_appearance(var/mob/viewer, var/datum/appearance_data/ad, var/refresh_images) + var/PriorityQueue/pq = appearances_[viewer] + pq.Remove(ad) + if(viewer.client) + viewer.client.images -= ad.images + if(!pq.Length()) + GLOB.logged_in_event.unregister(viewer, src, /decl/appearance_manager/proc/apply_appearance_images) + GLOB.destroyed_event.register(viewer, src, /decl/appearance_manager/proc/remove_appearances) + appearances_ -= viewer + +/decl/appearance_manager/proc/remove_appearances(var/mob/viewer) + var/PriorityQueue/pq = appearances_[viewer] + for(var/entry in pq.L) + var/datum/appearance_data/ad = entry + ad.RemoveViewer(viewer, FALSE) + appearances_[viewer] -= viewer + +/decl/appearance_manager/proc/reset_appearance_images(var/mob/viewer) + clear_appearance_images(viewer) + apply_appearance_images(viewer) + +/decl/appearance_manager/proc/clear_appearance_images(var/mob/viewer) + if(!viewer.client) + return + var/PriorityQueue/pq = appearances_[viewer] + if(!pq) + return + for(var/entry in pq.L) + var/datum/appearance_data/ad = entry + viewer.client.images -= ad.images + +/decl/appearance_manager/proc/apply_appearance_images(var/mob/viewer) + if(!viewer.client) + return + var/PriorityQueue/pq = appearances_[viewer] + if(!pq) + return + for(var/entry in pq.L) + var/datum/appearance_data/ad = entry + viewer.client.images |= ad.images diff --git a/code/datums/appearances/automatic/_base.dm b/code/datums/appearances/automatic/_base.dm new file mode 100644 index 00000000..90b1d02f --- /dev/null +++ b/code/datums/appearances/automatic/_base.dm @@ -0,0 +1,29 @@ +/decl/appearance_handler + var/priority = 15 + var/list/appearance_sources + +/decl/appearance_handler/New() + ..() + appearance_sources = list() + +/decl/appearance_handler/proc/AddAltAppearance(var/source, var/list/images, var/list/viewers = list()) + if(source in appearance_sources) + return FALSE + appearance_sources[source] = new/datum/appearance_data(images, viewers, priority) + GLOB.destroyed_event.register(source, src, /decl/appearance_handler/proc/RemoveAltAppearance) + +/decl/appearance_handler/proc/RemoveAltAppearance(var/source) + var/datum/appearance_data/ad = appearance_sources[source] + if(ad) + GLOB.destroyed_event.unregister(source, src) + appearance_sources -= source + qdel(ad) + +/decl/appearance_handler/proc/DisplayAltAppearanceTo(var/source, var/viewer) + var/datum/appearance_data/ad = appearance_sources[source] + if(ad) + ad.AddViewer(viewer) + +/decl/appearance_handler/proc/DisplayAllAltAppearancesTo(var/viewer) + for(var/entry in appearance_sources) + DisplayAltAppearanceTo(entry, viewer) diff --git a/code/datums/appearances/automatic/cardborg.dm b/code/datums/appearances/automatic/cardborg.dm new file mode 100644 index 00000000..0a2d5d0d --- /dev/null +++ b/code/datums/appearances/automatic/cardborg.dm @@ -0,0 +1,105 @@ +/decl/appearance_handler/cardborg + var/static/list/appearances + +/decl/appearance_handler/cardborg/proc/item_equipped(var/obj/item/item, var/mob/user, var/slot) + if(!(slot == slot_head || slot == slot_wear_suit|| slot == slot_back)) + return + if(!ishuman(user)) + return + if(!(istype(item, /obj/item/clothing/suit/cardborg) || istype(item, /obj/item/clothing/head/cardborg) || istype(item, /obj/item/weapon/storage/backpack))) + return + if(user in appearance_sources) + return + + var/mob/living/carbon/human/H = user + if(!(istype(H.wear_suit, /obj/item/clothing/suit/cardborg) && istype(H.head, /obj/item/clothing/head/cardborg) && istype(H.back, /obj/item/weapon/storage/backpack))) + return + + var/image/I = get_image_from_backpack(H) + AddAltAppearance(H, I, GLOB.silicon_mob_list+H) //you look like a robot to robots! (including yourself because you're totally a robot) + GLOB.logged_in_event.register_global(src, /decl/appearance_handler/cardborg/proc/mob_joined) // Duplicate registration request are handled for us + +/decl/appearance_handler/cardborg/proc/item_removed(var/obj/item/item, var/mob/user) + if((istype(item, /obj/item/clothing/suit/cardborg) || istype(item, /obj/item/clothing/head/cardborg)) || istype(item, /obj/item/weapon/storage/backpack)) + RemoveAltAppearance(user) + if(!appearance_sources.len) + GLOB.logged_in_event.unregister_global(src) // Only listen to the logged in event for as long as it's relevant + +/decl/appearance_handler/cardborg/proc/mob_joined(var/mob/user) + if(issilicon(user)) + DisplayAllAltAppearancesTo(user) + +/decl/appearance_handler/cardborg/proc/get_image_from_backpack(var/mob/living/carbon/human/H) + init_appearances() + var/decl/cardborg_appearance/ca = appearances[H.back.type] + if(!ca) ca = appearances[/obj/item/weapon/storage/backpack] + + var/image/I = image(icon = 'icons/mob/robots.dmi', icon_state = ca.icon_state, loc = H) + I.override = 1 + I.overlays += image(icon = 'icons/mob/robots.dmi', icon_state = "eyes-[ca.icon_state]") //gotta look realistic + return I + +/decl/appearance_handler/cardborg/proc/init_appearances() + if(!appearances) + appearances = list() + for(var/decl/cardborg_appearance/ca in init_subtypes(/decl/cardborg_appearance)) + appearances[ca.backpack_type] = ca + +/decl/cardborg_appearance + var/backpack_type + var/icon_state + backpack_type = /obj/item/weapon/storage/backpack + +/decl/cardborg_appearance/standard + icon_state = "robot" + +/decl/cardborg_appearance/standard/satchel1 + backpack_type = /obj/item/weapon/storage/backpack/satchel + +/decl/cardborg_appearance/standard/satchel2 + backpack_type = /obj/item/weapon/storage/backpack/satchel/grey + +/decl/cardborg_appearance/engineering + icon_state = "engineerrobot" + backpack_type = /obj/item/weapon/storage/backpack/industrial + +/decl/cardborg_appearance/engineering/satchel + backpack_type = /obj/item/weapon/storage/backpack/satchel/satchel_eng + +/decl/cardborg_appearance/medical + icon_state = "Medbot" + backpack_type = /obj/item/weapon/storage/backpack/medic + +/decl/cardborg_appearance/medical/satchel + backpack_type = /obj/item/weapon/storage/backpack/satchel/satchel_med + +/decl/cardborg_appearance/science + icon_state = "droid-science" + backpack_type = /obj/item/weapon/storage/backpack/toxins + +/decl/cardborg_appearance/science/satchel + backpack_type = /obj/item/weapon/storage/backpack/satchel/satchel_tox + +/decl/cardborg_appearance/security + icon_state = "securityrobot" + backpack_type = /obj/item/weapon/storage/backpack/security + +/decl/cardborg_appearance/security/satchel + backpack_type = /obj/item/weapon/storage/backpack/satchel/satchel_sec + +/decl/cardborg_appearance/centcom + icon_state = "centcomborg" + backpack_type = /obj/item/weapon/storage/backpack/captain + +/decl/cardborg_appearance/centcom/satchel + backpack_type = /obj/item/weapon/storage/backpack/satchel/satchel_cap + +/decl/cardborg_appearance/syndicate + icon_state = "droid-combat" + backpack_type = /obj/item/weapon/storage/backpack/dufflebag/syndie + +/decl/cardborg_appearance/syndicate/med + backpack_type = /obj/item/weapon/storage/backpack/dufflebag/syndie/med + +/decl/cardborg_appearance/syndicate/ammo + backpack_type = /obj/item/weapon/storage/backpack/dufflebag/syndie/ammo diff --git a/code/datums/browser.dm b/code/datums/browser.dm new file mode 100644 index 00000000..6e1747fc --- /dev/null +++ b/code/datums/browser.dm @@ -0,0 +1,196 @@ +/datum/browser + var/mob/user + var/title + var/window_id // window_id is used as the window name for browse and onclose + var/width = 0 + var/height = 0 + var/atom/ref = null + var/window_options = "focus=0;can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id + var/stylesheets[0] + var/scripts[0] + var/title_image + var/head_elements + var/body_elements + var/head_content = "" + var/content = "" + var/title_buttons = "" + + +/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null) + + user = nuser + window_id = nwindow_id + if (ntitle) + title = format_text(ntitle) + if (nwidth) + width = nwidth + if (nheight) + height = nheight + if (nref) + ref = nref + // If a client exists, but they have disabled fancy windowing, disable it! + //if(user && user.client && user.client.get_preference_value(/datum/client_preference/browser_style) == GLOB.PREF_PLAIN) + // return + add_stylesheet("common", 'html/browser/common.css') // this CSS sheet is common to all UIs + +/datum/browser/proc/set_title(ntitle) + title = format_text(ntitle) + +/datum/browser/proc/add_head_content(nhead_content) + head_content = nhead_content + +/datum/browser/proc/set_title_buttons(ntitle_buttons) + title_buttons = ntitle_buttons + +/datum/browser/proc/set_window_options(nwindow_options) + window_options = nwindow_options + +/datum/browser/proc/set_title_image(ntitle_image) + //title_image = ntitle_image + +/datum/browser/proc/add_stylesheet(name, file) + stylesheets[name] = file + +/datum/browser/proc/add_script(name, file) + scripts[name] = file + +/datum/browser/proc/set_content(ncontent) + content = ncontent + +/datum/browser/proc/add_content(ncontent) + content += ncontent + +/datum/browser/proc/get_header() + var/key + var/filename + for (key in stylesheets) + filename = "[ckey(key)].css" + user << browse_rsc(stylesheets[key], filename) + head_content += "" + + for (key in scripts) + filename = "[ckey(key)].js" + user << browse_rsc(scripts[key], filename) + head_content += "" + + var/title_attributes = "class='uiTitle'" + if (title_image) + title_attributes = "class='uiTitle icon' style='background-image: url([title_image]);'" + + return {" + + + + + [head_content] + + +
    + [title ? "
    [title]
    [title_buttons]
    " : ""] +
    + "} + +/datum/browser/proc/get_footer() + return {" +
    +
    + +"} + +/datum/browser/proc/get_content() + return {" + [get_header()] + [content] + [get_footer()] + "} + +/datum/browser/proc/open(var/use_onclose = 1) + var/window_size = "" + if (width && height) + window_size = "size=[width]x[height];" + user << browse(get_content(), "window=[window_id];[window_size][window_options]") + if (use_onclose) + onclose(user, window_id, ref) + +/datum/browser/proc/update(var/force_open = 0, var/use_onclose = 1) + if(force_open) + open(use_onclose) + else + send_output(user, get_content(), "[window_id].browser") + +/datum/browser/proc/close() + user << browse(null, "window=[window_id]") + +// This will allow you to show an icon in the browse window +// This is added to mob so that it can be used without a reference to the browser object +// There is probably a better place for this... +/mob/proc/browse_rsc_icon(icon, icon_state, dir = -1) + /* + var/icon/I + if (dir >= 0) + I = new /icon(icon, icon_state, dir) + else + I = new /icon(icon, icon_state) + dir = "default" + + var/filename = "[ckey("[icon]_[icon_state]_[dir]")].png" + src << browse_rsc(I, filename) + return filename + */ + + +// Registers the on-close verb for a browse window (client/verb/.windowclose) +// this will be called when the close-button of a window is pressed. +// +// This is usually only needed for devices that regularly update the browse window, +// e.g. canisters, timers, etc. +// +// windowid should be the specified window name +// e.g. code is : user << browse(text, "window=fred") +// then use : onclose(user, "fred") +// +// Optionally, specify the "ref" parameter as the controlled atom (usually src) +// to pass a "close=1" parameter to the atom's Topic() proc for special handling. +// Otherwise, the user mob's machine var will be reset directly. +// +/proc/onclose(mob/user, windowid, var/atom/ref=null) + if(!user || !user.client) return + var/param = "null" + if(ref) + param = "\ref[ref]" + + spawn(2) + if(!user.client) return + winset(user, windowid, "on-close=\".windowclose [param]\"") + +// log_debug("OnClose [user]: [windowid] : ["on-close=\".windowclose [param]\""]") + + + +// the on-close client verb +// called when a browser popup window is closed after registering with proc/onclose() +// if a valid atom reference is supplied, call the atom's Topic() with "close=1" +// otherwise, just reset the client mob's machine var. +// +/client/verb/windowclose(var/atomref as text) + set hidden = 1 // hide this verb from the user's panel + set name = ".windowclose" // no autocomplete on cmd line + +// log_debug("windowclose: [atomref]") + + if(atomref!="null") // if passed a real atomref + var/hsrc = locate(atomref) // find the reffed atom + if(hsrc) +// log_debug("[src] Topic [href] [hsrc]") + + usr = src.mob + src.Topic("close=1", list("close"="1"), hsrc) // this will direct to the atom's + return // Topic() proc via client.Topic() + + // no atomref specified (or not found) + // so just reset the user mob's machine var + if(src && src.mob) +// log_debug("[src] was [src.mob.machine], setting to null") + + src.mob.unset_machine() + return diff --git a/code/datums/callbacks.dm b/code/datums/callbacks.dm new file mode 100644 index 00000000..7fcb228b --- /dev/null +++ b/code/datums/callbacks.dm @@ -0,0 +1,55 @@ +// See 'callback-usage.txt' in this directory for instructions on how to use this. +// It used to be in this file, but Travis no likey. + +/datum/callback + var/datum/object = GLOBAL_PROC + var/delegate + var/list/arguments + +/datum/callback/New(thingtocall, proctocall, ...) + if (thingtocall) + object = thingtocall + delegate = proctocall + if (length(args) > 2) + arguments = args.Copy(3) + +/proc/ImmediateInvokeAsync(thingtocall, proctocall, ...) + set waitfor = FALSE + + if (!thingtocall) + return + + var/list/calling_arguments = length(args) > 2 ? args.Copy(3) : null + + if (thingtocall == GLOBAL_PROC) + call(proctocall)(arglist(calling_arguments)) + else + call(thingtocall, proctocall)(arglist(calling_arguments)) + +/datum/callback/proc/Invoke(...) + if (!object) + return + var/list/calling_arguments = arguments + if (length(args)) + if (length(arguments)) + calling_arguments = calling_arguments + args //not += so that it creates a new list so the arguments list stays clean + else + calling_arguments = args + if (object == GLOBAL_PROC) + return call(delegate)(arglist(calling_arguments)) + return call(object, delegate)(arglist(calling_arguments)) + +//copy and pasted because fuck proc overhead +/datum/callback/proc/InvokeAsync(...) + set waitfor = FALSE + if (!object) + return + var/list/calling_arguments = arguments + if (length(args)) + if (length(arguments)) + calling_arguments = calling_arguments + args //not += so that it creates a new list so the arguments list stays clean + else + calling_arguments = args + if (object == GLOBAL_PROC) + return call(delegate)(arglist(calling_arguments)) + return call(object, delegate)(arglist(calling_arguments)) \ No newline at end of file diff --git a/code/datums/category.dm b/code/datums/category.dm new file mode 100644 index 00000000..3bc9640b --- /dev/null +++ b/code/datums/category.dm @@ -0,0 +1,81 @@ +/********************** +* Category Collection * +**********************/ +/datum/category_collection + var/category_group_type // Type of categories to initialize + var/list/datum/category_group/categories // List of initialized categories + var/list/datum/category_group/categories_by_name // Associative list of initialized categories, keyed by name + +/datum/category_collection/New() + ..() + categories = new() + categories_by_name = 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_by_name[category.name] = 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 // Type of items to initialize + var/list/datum/category_item/items // List of initialized items + var/list/datum/category_item/items_by_name // Associative list of initialized items, by name + var/datum/category_collection/collection // The collection this group belongs to + +/datum/category_group/New(var/datum/category_collection/cc) + ..() + collection = cc + items = new() + items_by_name = 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 + items_by_name[item.name] = 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/colors/color_generator.dm b/code/datums/colors/color_generator.dm new file mode 100644 index 00000000..c58ea8a2 --- /dev/null +++ b/code/datums/colors/color_generator.dm @@ -0,0 +1,65 @@ +#define RANDOMIZE(X) Clamp(X + rand(min_random_span, max_random_span), 0, 255) +#define RANDOMIZE_RGB(R,G,B) list(RANDOMIZE(R), RANDOMIZE(G), RANDOMIZE(B)) + +/decl/color_generator + var/color = COLOR_WHITE + var/min_random_span = -25 + var/max_random_span = 25 + +/decl/color_generator/proc/GenerateHex() + . = create_color() + . = rgb(.[1], .[2], .[3]) + +/decl/color_generator/proc/GenerateRGB() + . = create_color() + . = RANDOMIZE_RGB(.[1], .[2], .[3]) + +/decl/color_generator/proc/create_color() + return GetHexColors(color) + +/decl/color_generator/albino_eye/create_color() + return list(rand(200, 255), rand(0, 150), rand(0, 150)) + +/decl/color_generator/black + color = COLOR_BLACK + +/decl/color_generator/blue + color = COLOR_CYAN_BLUE + +/decl/color_generator/blue_light + color = COLOR_LIGHT_CYAN + +/decl/color_generator/blonde + color = COLOR_YELLOW + +/decl/color_generator/brown + color = COLOR_BEASTY_BROWN + +/decl/color_generator/chestnut + color = COLOR_CHESTNUT + +/decl/color_generator/copper + color = COLOR_ORANGE + +/decl/color_generator/green + color = COLOR_PAKISTAN_GREEN + +/decl/color_generator/grey/create_color() + . = rand(100, 200) + return list(., ., .) + +/decl/color_generator/old/create_color() + . = rand(100, 255) + return list(., ., .) + +/decl/color_generator/punk/create_color() + return list(rand(0, 255), rand(0, 255), rand(0, 255)) + +/decl/color_generator/wheat + color = COLOR_WHEAT + +/decl/color_generator/white + color = COLOR_WHITE + +#undef RANDOMIZE_RGB +#undef RANDOMIZE diff --git a/code/datums/communication/_defines.dm b/code/datums/communication/_defines.dm new file mode 100644 index 00000000..fb1b8bd9 --- /dev/null +++ b/code/datums/communication/_defines.dm @@ -0,0 +1,4 @@ +#define COMMUNICATION_NO_GUESTS 1 +#define COMMUNICATION_LOG_CHANNEL_NAME 2 +#define COMMUNICATION_GHOST_FOLLOW 4 +#define COMMUNICATION_ADMIN_FOLLOW 8 diff --git a/code/datums/communication/aooc.dm b/code/datums/communication/aooc.dm new file mode 100644 index 00000000..d01cd42b --- /dev/null +++ b/code/datums/communication/aooc.dm @@ -0,0 +1,32 @@ +/decl/communication_channel/aooc + name = "AOOC" + config_setting = "aooc_allowed" + expected_communicator_type = /client + flags = COMMUNICATION_LOG_CHANNEL_NAME|COMMUNICATION_ADMIN_FOLLOW + log_proc = /proc/log_ooc + mute_setting = MUTE_AOOC + show_preference_setting = /datum/client_preference/show_aooc + +/decl/communication_channel/aooc/can_communicate(var/client/C, var/message) + . = ..() + if(!.) + return + + if(!C.holder) + if(isghost(C.mob)) + to_chat(src, "You cannot use [name] while ghosting/observing!") + return FALSE + if(!(C.mob && C.mob.mind && C.mob.mind.special_role)) + to_chat(C, "You must be an antag to use [name].") + return FALSE + +/decl/communication_channel/aooc/do_communicate(var/client/C, var/message) + var/datum/admins/holder = C.holder + + for(var/client/target in GLOB.clients) + if(target.holder) + receive_communication(C, target, "[create_text_tag("aooc", "Antag-OOC:", target)] [get_options_bar(C, 0, 1, 1)]: [message]") + else if(target.mob && target.mob.mind && target.mob.mind.special_role) + var/display_name = C.key + var/player_display = holder ? "[display_name]([usr.client.holder.rank])" : display_name + receive_communication(C, target, "[create_text_tag("aooc", "Antag-OOC:", target)] [player_display]: [message]") \ No newline at end of file diff --git a/code/datums/communication/channel.dm b/code/datums/communication/channel.dm new file mode 100644 index 00000000..8d220be9 --- /dev/null +++ b/code/datums/communication/channel.dm @@ -0,0 +1,101 @@ +#define plain_key_name(A) key_name(A, highlight_special_characters = 0) + +/decl/communication_channel + var/name + var/config_setting + var/expected_communicator_type = /datum + var/flags + var/log_proc + var/mute_setting + var/show_preference_setting + +/* +* Procs for handling sending communication messages +*/ +/decl/communication_channel/proc/communicate(var/datum/communicator, var/message) + if(can_communicate(arglist(args))) + call(log_proc)("[(flags&COMMUNICATION_LOG_CHANNEL_NAME) ? "([name]) " : ""][communicator.communication_identifier()] : [message]") + return do_communicate(arglist(args)) + return FALSE + +/decl/communication_channel/proc/can_communicate(var/datum/communicator, var/message) + if(!message) + return FALSE + + if(!istype(communicator, expected_communicator_type)) + log_debug("[log_info_line(communicator)] attempted to communicate over the channel [src] but was of an unexpected type.") + return FALSE + + if(config_setting && !config.vars[config_setting] && !check_rights(R_INVESTIGATE,0,communicator)) + to_chat(communicator, "[name] is globally muted.") + return FALSE + + var/client/C = communicator.get_client() + + if(C && show_preference_setting && C.get_preference_value(show_preference_setting) == GLOB.PREF_HIDE && !check_rights(R_INVESTIGATE,0,C)) + to_chat(communicator, "You have [name] muted.") + return FALSE + + if(C && mute_setting && (C.prefs.muted & mute_setting)) + to_chat(communicator, "You cannot use [name] (muted).") + return FALSE + + if(C && (flags & COMMUNICATION_NO_GUESTS) && IsGuestKey(C.key)) + to_chat(communicator, "Guests may not use the [name] channel.") + return FALSE + + return TRUE + +/decl/communication_channel/proc/do_communicate(var/communicator, var/message) + return + +/* +* Procs for handling the reception of communication messages +*/ +/decl/communication_channel/proc/receive_communication(var/datum/communicator, var/datum/receiver, var/message) + if(can_receive_communication(receiver)) + var/has_follow_links = FALSE + if((flags & COMMUNICATION_ADMIN_FOLLOW)) + var/extra_links = receiver.get_admin_jump_link(communicator,"","\[","\]") + if(extra_links) + has_follow_links = TRUE + message = "[extra_links] [message]" + if(flags & COMMUNICATION_GHOST_FOLLOW && !has_follow_links) + var/extra_links = receiver.get_ghost_follow_link(communicator,"","\[","\]") + if(extra_links) + message = "[extra_links] [message]" + do_receive_communication(arglist(args)) + +/decl/communication_channel/proc/can_receive_communication(var/datum/receiver) + if(show_preference_setting) + var/client/C = receiver.get_client() + // Admins (investigators) are expected to monitor channels. They can deadmin if they don't wish to see everything. + if(C && C.get_preference_value(show_preference_setting) == GLOB.PREF_HIDE && !check_rights(R_INVESTIGATE, 0 , C)) + return FALSE + return TRUE + +/decl/communication_channel/proc/do_receive_communication(var/datum/communicator, var/datum/receiver, var/message) + to_chat(receiver, message) + +// Misc. helpers +/datum/proc/communication_identifier() + return usr ? "[src] - usr: [plain_key_name(usr)]" : "[src]" + +/mob/communication_identifier() + var/key_name = plain_key_name(src) + return usr != src ? "[key_name] - usr: [plain_key_name(usr)]" : key_name + +/proc/sanitize_and_communicate(var/channel_type, var/communicator, var/message) + message = sanitize(message) + return communicate(arglist(args)) + +/proc/communicate(var/channel_type, var/communicator, var/message) + var/list/channels = decls_repository.get_decls_of_subtype(/decl/communication_channel) + var/decl/communication_channel/channel = channels[channel_type] + + var/list/new_args = list(communicator, message) + new_args += args.Copy(4) + + return channel.communicate(arglist(new_args)) + +#undef plain_key_name diff --git a/code/datums/communication/dsay.dm b/code/datums/communication/dsay.dm new file mode 100644 index 00000000..bfdd8ed0 --- /dev/null +++ b/code/datums/communication/dsay.dm @@ -0,0 +1,140 @@ +#define DSAY_CAN_COMMUNICATE 1 +#define DSAY_ASK_BASE 2 + +/decl/communication_channel/dsay + name = "DSAY" + config_setting = "dsay_allowed" + expected_communicator_type = /client + flags = COMMUNICATION_LOG_CHANNEL_NAME + log_proc = /proc/log_say + mute_setting = MUTE_DEADCHAT + show_preference_setting = /datum/client_preference/show_dsay + +/decl/communication_channel/dsay/communicate(communicator, message, speech_method = /decl/dsay_communication/say) + ..() + +/decl/communication_channel/dsay/can_communicate(var/client/communicator, var/message, var/speech_method_type) + var/decl/dsay_communication/speech_method = decls_repository.get_decl(speech_method_type) + switch(speech_method.can_communicate(communicator, message)) + if(DSAY_CAN_COMMUNICATE) + return TRUE + if(DSAY_ASK_BASE) + return ..() + +/decl/communication_channel/dsay/do_communicate(var/client/communicator, var/message, var/speech_method_type) + var/decl/dsay_communication/speech_method = decls_repository.get_decl(speech_method_type) + + speech_method.adjust_channel(src) + + for(var/mob/M in GLOB.player_list) + if(!speech_method.can_receive(communicator, M)) + continue + var/sent_message = speech_method.get_message(communicator, M, message) + receive_communication(communicator, M, "DEAD: [sent_message]") + +/decl/dsay_communication/proc/can_communicate(var/client/communicator, var/message) + if(!istype(communicator)) + return FALSE + if(communicator.mob.stat != DEAD && !communicator.mob.communing_with_dead) + to_chat(communicator, "You're not sufficiently dead to use DSAY!") + return FALSE + return DSAY_ASK_BASE + +/decl/dsay_communication/proc/can_receive(var/client/C, var/mob/M) + if(istype(C) && C.mob == M) + return TRUE + if(M.get_preference_value(/datum/client_preference/show_dsay) == GLOB.PREF_HIDE) + return FALSE + if(istype(C) && M.is_key_ignored(C.key)) + return FALSE + if(M.client.holder && !is_mentor(M.client)) + return TRUE + if(M.communing_with_dead) + return TRUE + if(M.stat != DEAD) + return FALSE + if(isnewplayer(M)) + return FALSE + return TRUE + +/decl/dsay_communication/proc/get_name(var/client/C, var/mob/M) + var/name + var/keyname + + keyname = C.key + if(C.mob) //Most of the time this is the dead/observer mob; we can totally use him if there is no better name + var/mindname + var/realname = C.mob.real_name + if(C.mob.mind) + mindname = C.mob.mind.name + if(C.mob.mind.original && C.mob.mind.original.real_name) + realname = C.mob.mind.original.real_name + if(mindname && mindname != realname) + name = "[realname] died as [mindname]" + else + name = realname + + var/lname + var/mob/observer/ghost/DM + if(isghost(C.mob)) + DM = C.mob + if(M.client.holder) // What admins see + lname = "[keyname][(DM && DM.anonsay) ? "*" : (DM ? "" : "^")] ([name])" + else + if(DM && DM.anonsay) // If the person is actually observer they have the option to be anonymous + lname = "Ghost of [name]" + else if(DM) // Non-anons + lname = "[keyname] ([name])" + else // Everyone else (dead people who didn't ghost yet, etc.) + lname = name + return "[lname]" + +/decl/dsay_communication/proc/get_message(var/client/C, var/mob/M, var/message) + var/say_verb = pick("complains","moans","whines","laments","blubbers") + if(M.communing_with_dead) + say_verb = "speaks from the living" + return "[get_name(C, M)] [say_verb], \"[message]\"" + +/decl/dsay_communication/emote/get_message(var/client/C, var/mob/M, var/message) + return "[get_name(C, M)] [message]" + +/decl/dsay_communication/proc/adjust_channel(var/decl/communication_channel/dsay) + dsay.flags |= COMMUNICATION_ADMIN_FOLLOW|COMMUNICATION_GHOST_FOLLOW // Add admin and ghost follow + +/decl/dsay_communication/say/adjust_channel(var/decl/communication_channel/dsay) + dsay.log_proc = /proc/log_say + ..() + +/decl/dsay_communication/emote/adjust_channel(var/decl/communication_channel/dsay) + dsay.log_proc = /proc/log_emote + ..() + +/decl/dsay_communication/admin/can_communicate(var/client/communicator, var/message, var/decl/communication_channel/dsay) + if(!istype(communicator)) + return FALSE + if(!communicator.holder) + to_chat(communicator, "You do not have sufficent permissions to use DSAY!") + return FALSE + return DSAY_ASK_BASE + +/decl/dsay_communication/admin/get_message(var/client/communicator, var/mob/M, var/message) + var/stafftype = uppertext(communicator.holder.rank) + return "[stafftype]([communicator.key]) says, \"[message]\"" + +/decl/dsay_communication/admin/adjust_channel(var/decl/communication_channel/dsay) + dsay.log_proc = /proc/log_say + dsay.flags |= COMMUNICATION_ADMIN_FOLLOW // Add admin follow + dsay.flags &= ~COMMUNICATION_GHOST_FOLLOW // Remove ghost follow + +/decl/dsay_communication/direct/adjust_channel(var/decl/communication_channel/dsay, var/communicator) + dsay.log_proc = /proc/log_say + dsay.flags &= ~(COMMUNICATION_ADMIN_FOLLOW|COMMUNICATION_GHOST_FOLLOW) // Remove admin and ghost follow + +/decl/dsay_communication/direct/can_communicate() + return DSAY_CAN_COMMUNICATE + +/decl/dsay_communication/direct/get_message(var/client/communicator, var/mob/M, var/message) + return message + +#undef DSAY_CAN_COMMUNICATE +#undef DSAY_ASK_BASE diff --git a/code/datums/communication/looc.dm b/code/datums/communication/looc.dm new file mode 100644 index 00000000..b684bd53 --- /dev/null +++ b/code/datums/communication/looc.dm @@ -0,0 +1,67 @@ +/decl/communication_channel/ooc/looc + name = "LOOC" + config_setting = "looc_allowed" + flags = COMMUNICATION_NO_GUESTS|COMMUNICATION_LOG_CHANNEL_NAME|COMMUNICATION_ADMIN_FOLLOW + show_preference_setting = /datum/client_preference/show_looc + +/decl/communication_channel/ooc/looc/can_communicate(var/client/C, var/message) + . = ..() + if(!.) + return + var/mob/M = C.mob ? C.mob.get_looc_mob() : null + if(!M) + to_chat(C, "You cannot use [name] without a mob.") + return FALSE + if(!get_turf(M)) + to_chat(C, "You cannot use [name] while in nullspace.") + return FALSE + if(isobserver(M)) + to_chat(C, "You cannot communicate from beyond the grave.") + return FALSE + if(M.stat == DEAD) + to_chat(C, "You cannot communicate from beyond the grave.") + return FALSE + +/decl/communication_channel/ooc/looc/do_communicate(var/client/C, var/message) + var/mob/M = C.mob ? C.mob.get_looc_mob() : null + var/list/listening_hosts = hosts_in_view_range(M) + var/list/listening_clients = list() + + var/key = C.key + + for(var/listener in listening_hosts) + var/mob/listening_mob = listener + var/client/t = listening_mob.get_client() + if(!t) + continue + listening_clients |= t + var/received_message = t.receive_looc(C, key, message, listening_mob.looc_prefix()) + receive_communication(C, t, received_message) + + for(var/client/adm in GLOB.admins) //Now send to all admins that weren't in range. + if(!(adm in listening_clients) && adm.get_preference_value(/datum/client_preference/staff/show_rlooc) == GLOB.PREF_SHOW) + var/received_message = adm.receive_looc(C, key, message, "R") + receive_communication(C, adm, received_message) + +/client/proc/receive_looc(var/client/C, var/commkey, var/message, var/prefix) + var/mob/M = C.mob + var/display_name = isghost(M) ? commkey : M.name + var/admin_stuff = holder ? "/([commkey])" : "" + if(prefix) + prefix = "\[[prefix]\] " + return "LOOC:[prefix][display_name][admin_stuff]: [message]" + +/mob/proc/looc_prefix() + return eyeobj ? "Body" : "" + +/mob/observer/eye/looc_prefix() + return "Eye" + +/mob/proc/get_looc_mob() + return src + +/mob/living/silicon/ai/get_looc_mob() + if(!eyeobj) + return src + return eyeobj + diff --git a/code/datums/communication/ooc.dm b/code/datums/communication/ooc.dm new file mode 100644 index 00000000..3c152433 --- /dev/null +++ b/code/datums/communication/ooc.dm @@ -0,0 +1,50 @@ +/decl/communication_channel/ooc + name = "OOC" + config_setting = "ooc_allowed" + expected_communicator_type = /client + flags = COMMUNICATION_NO_GUESTS + log_proc = /proc/log_ooc + mute_setting = MUTE_OOC + show_preference_setting = /datum/client_preference/show_ooc + +/decl/communication_channel/ooc/can_communicate(var/client/C, var/message) + . = ..() + if(!.) + return + + if(!C.holder) + if(!config.dooc_allowed && (C.mob.stat == DEAD)) + to_chat(C, "[name] for dead mobs has been turned off.") + return FALSE + if(findtext(message, "byond://")) + to_chat(C, "Advertising other servers is not allowed.") + log_and_message_admins("has attempted to advertise in [name]: [message]") + return FALSE + +/decl/communication_channel/ooc/do_communicate(var/client/C, var/message) + var/datum/admins/holder = C.holder + var/is_stealthed = C.is_stealthed() + + var/ooc_style = "everyone" + if(holder && !is_stealthed) + ooc_style = "elevated" + if(holder.rights & R_MOD) + ooc_style = "moderator" + if(holder.rights & R_DEBUG) + ooc_style = "developer" + if(holder.rights & R_ADMIN) + ooc_style = "admin" + + var/can_badmin = !is_stealthed && can_select_ooc_color(C) && (C.prefs.ooccolor != initial(C.prefs.ooccolor)) + var/ooc_color = C.prefs.ooccolor + + message = emoji_parse(message) + + for(var/client/target in GLOB.clients) + if(target.is_key_ignored(C.key)) // If we're ignored by this person, then do nothing. + continue + var/sent_message = "OOC: [C.key]: [message]"//[create_text_tag("ooc", "OOC:", target)] + if(can_badmin) + receive_communication(C, target, "[sent_message]") + else + receive_communication(C, target, "[sent_message]") diff --git a/code/datums/communication/pray.dm b/code/datums/communication/pray.dm new file mode 100644 index 00000000..7a0f7240 --- /dev/null +++ b/code/datums/communication/pray.dm @@ -0,0 +1,21 @@ +/decl/communication_channel/pray + name = "PRAY" + expected_communicator_type = /mob + log_proc = /proc/log_say + flags = COMMUNICATION_ADMIN_FOLLOW + mute_setting = MUTE_PRAY + +/decl/communication_channel/pray/do_communicate(var/mob/communicator, var/message, var/speech_method_type) + var/image/cross = image('icons/obj/storage.dmi',"bible") + for(var/m in GLOB.player_list) + var/mob/M = m + if(!M.client) + continue + if(M.client.holder && M.client.get_preference_value(/datum/client_preference/staff/show_chat_prayers) == GLOB.PREF_SHOW) + receive_communication(communicator, M, "\[SC\] \[TAKE\]\icon[cross] PRAY: [key_name(communicator, 1)]: [message]") + else if(communicator == M) //Give it to ourselves + receive_communication(communicator, M, "\icon[cross] You send the prayer, \"[message]\" out into the heavens.") + +/decl/communication_channel/pray/receive_communication(var/mob/communicator, var/mob/receiver, var/message) + ..() + sound_to(receiver, 'sound/effects/ding.ogg') \ No newline at end of file diff --git a/code/datums/communication/~defines.dm b/code/datums/communication/~defines.dm new file mode 100644 index 00000000..669f56ff --- /dev/null +++ b/code/datums/communication/~defines.dm @@ -0,0 +1,4 @@ +#undef COMMUNICATION_NO_GUESTS +#undef COMMUNICATION_LOG_CHANNEL_NAME +#undef COMMUNICATION_GHOST_FOLLOW +#undef COMMUNICATION_ADMIN_FOLLOW diff --git a/code/datums/datum.dm b/code/datums/datum.dm new file mode 100644 index 00000000..52920c0f --- /dev/null +++ b/code/datums/datum.dm @@ -0,0 +1,32 @@ +/datum + var/tmp/gc_destroyed //Time when this object was destroyed. + var/tmp/is_processing = FALSE + var/list/active_timers //for SStimer + +#ifdef TESTING + var/tmp/running_find_references + var/tmp/last_find_references = 0 +#endif + +// The following vars cannot be edited by anyone +/datum/VV_static() + return ..() + list("gc_destroyed", "is_processing") + +// Default implementation of clean-up code. +// This should be overridden to remove all references pointing to the object being destroyed. +// Return the appropriate QDEL_HINT; in most cases this is QDEL_HINT_QUEUE. +/datum/proc/Destroy(force=FALSE) + tag = null + GLOB.nanomanager && GLOB.nanomanager.close_uis(src) + var/list/timers = active_timers + active_timers = null + for(var/thing in timers) + var/datum/timedevent/timer = thing + if (timer.spent) + continue + qdel(timer) + return QDEL_HINT_QUEUE + +/datum/proc/Process() + set waitfor = 0 + return PROCESS_KILL diff --git a/code/datums/extensions/_defines.dm b/code/datums/extensions/_defines.dm new file mode 100644 index 00000000..1f8457bb --- /dev/null +++ b/code/datums/extensions/_defines.dm @@ -0,0 +1,3 @@ +#define EXTENSION_FLAG_NONE 0 +#define EXTENSION_FLAG_IMMEDIATE 1 // Instantly instantiates, instead of doing it lazily. +//#define EXTENSION_FLAG_MULTIPLE_INSTANCES 2 // Allows multiple instances per base type. To be implemented diff --git a/code/datums/extensions/appearance/appearance.dm b/code/datums/extensions/appearance/appearance.dm new file mode 100644 index 00000000..3a524658 --- /dev/null +++ b/code/datums/extensions/appearance/appearance.dm @@ -0,0 +1,21 @@ +/datum/extension/appearance + expected_type = /atom + flags = EXTENSION_FLAG_IMMEDIATE // | EXTENSION_FLAG_MULTIPLE_INSTANCES + var/appearance_handler_type + var/item_equipment_proc + var/item_removal_proc + +/datum/extension/appearance/New(var/holder) + var/appearance_handler = appearance_manager.get_appearance_handler(appearance_handler_type) + if(!appearance_handler) + CRASH("Unable to acquire the [appearance_handler_type] appearance handler.") + + GLOB.item_equipped_event.register(holder, appearance_handler, item_equipment_proc) + GLOB.item_unequipped_event.register(holder, appearance_handler, item_removal_proc) + ..() + +/datum/extension/appearance/Destroy() + var/appearance_handler = appearance_manager.get_appearance_handler(appearance_handler_type) + GLOB.item_equipped_event.unregister(holder, appearance_handler, item_equipment_proc) + GLOB.item_unequipped_event.unregister(holder, appearance_handler, item_removal_proc) + . = ..() diff --git a/code/datums/extensions/appearance/base_icon_state.dm b/code/datums/extensions/appearance/base_icon_state.dm new file mode 100644 index 00000000..49f33681 --- /dev/null +++ b/code/datums/extensions/appearance/base_icon_state.dm @@ -0,0 +1,7 @@ +/datum/extension/base_icon_state + expected_type = /atom + var/base_icon_state + +/datum/extension/base_icon_state/New(var/holder, var/base_icon_state) + ..() + src.base_icon_state = base_icon_state diff --git a/code/datums/extensions/appearance/cardborg.dm b/code/datums/extensions/appearance/cardborg.dm new file mode 100644 index 00000000..3dfef679 --- /dev/null +++ b/code/datums/extensions/appearance/cardborg.dm @@ -0,0 +1,5 @@ +/datum/extension/appearance/cardborg + expected_type = /obj/item + appearance_handler_type = /decl/appearance_handler/cardborg + item_equipment_proc = /decl/appearance_handler/cardborg/proc/item_equipped + item_removal_proc = /decl/appearance_handler/cardborg/proc/item_removed diff --git a/code/datums/extensions/extensions.dm b/code/datums/extensions/extensions.dm new file mode 100644 index 00000000..2f8cb372 --- /dev/null +++ b/code/datums/extensions/extensions.dm @@ -0,0 +1,68 @@ +/datum/extension + var/datum/holder = null // The holder + var/expected_type = /datum + var/flags = EXTENSION_FLAG_NONE + +/datum/extension/New(var/datum/holder) + if(!istype(holder, expected_type)) + CRASH("Invalid holder type. Expected [expected_type], was [holder.type]") + src.holder = holder + +/datum/extension/Destroy() + holder = null + . = ..() + +/datum + var/list/datum/extension/extensions + +/datum/Destroy() + if(extensions) + for(var/expansion_key in extensions) + var/list/extension = extensions[expansion_key] + if(islist(extension)) + extension.Cut() + else + qdel(extension) + extensions = null + return ..() + +//Variadic - Additional positional arguments can be given. Named arguments might not work so well +/proc/set_extension(var/datum/source, var/datum/extension/base_type, var/extension_type) + if(!source.extensions) + source.extensions = list() + var/datum/extension/existing_extension = source.extensions[base_type] + if(istype(existing_extension)) + qdel(existing_extension) + + if(initial(base_type.flags) & EXTENSION_FLAG_IMMEDIATE) + . = construct_extension_instance(extension_type, source, args.Copy(4)) + source.extensions[base_type] = . + else + var/list/extension_data = list(extension_type, source) + if(args.len > 3) + extension_data += args.Copy(4) + source.extensions[base_type] = extension_data + +/proc/get_or_create_extension(var/datum/source, var/base_type, var/extension_type) + if(!has_extension(source, base_type)) + set_extension(arglist(args)) + return get_extension(source, base_type) + +/proc/get_extension(var/datum/source, var/base_type) + if(!source.extensions) + return + . = source.extensions[base_type] + if(!.) + return + if(islist(.)) //a list, so it's expecting to be lazy-loaded + var/list/extension_data = . + . = construct_extension_instance(extension_data[1], extension_data[2], extension_data.Copy(3)) + source.extensions[base_type] = . + +//Fast way to check if it has an extension, also doesn't trigger instantiation of lazy loaded extensions +/proc/has_extension(var/datum/source, var/base_type) + return (source.extensions && source.extensions[base_type]) + +/proc/construct_extension_instance(var/extension_type, var/datum/source, var/list/arguments) + arguments = list(source) + arguments + return new extension_type(arglist(arguments)) diff --git a/code/datums/extensions/interactive.dm b/code/datums/extensions/interactive.dm new file mode 100644 index 00000000..0fd181de --- /dev/null +++ b/code/datums/extensions/interactive.dm @@ -0,0 +1,35 @@ +//Extensions that can be interacted with via Topic +/datum/extension/interactive + var/list/host_predicates + var/list/user_predicates + +/datum/extension/interactive/New(var/datum/holder, var/host_predicates = list(), var/user_predicates = list()) + ..() + + src.host_predicates = host_predicates ? host_predicates : list() + src.user_predicates = user_predicates ? user_predicates : list() + +/datum/extension/interactive/Destroy() + host_predicates.Cut() + user_predicates.Cut() + return ..() + +/datum/extension/interactive/proc/extension_status(var/mob/user) + if(!holder || !user) + return STATUS_CLOSE + if(!all_predicates_true(list(holder), host_predicates)) + return STATUS_CLOSE + if(!all_predicates_true(list(user), user_predicates)) + return STATUS_CLOSE + if(holder.CanUseTopic(user, GLOB.default_state) != STATUS_INTERACTIVE) + return STATUS_CLOSE + + return STATUS_INTERACTIVE + +/datum/extension/interactive/proc/extension_act(var/href, var/list/href_list, var/mob/user) + return extension_status(user) == STATUS_CLOSE + +/datum/extension/interactive/Topic(var/href, var/list/href_list) + if(..()) + return TRUE + return extension_act(href, href_list, usr) diff --git a/code/datums/extensions/label.dm b/code/datums/extensions/label.dm new file mode 100644 index 00000000..e1986969 --- /dev/null +++ b/code/datums/extensions/label.dm @@ -0,0 +1,92 @@ +/datum/extension/labels + var/atom/atom_holder + var/list/labels + +/datum/extension/labels/New() + ..() + atom_holder = holder + +/datum/extension/labels/Destroy() + atom_holder = null + return ..() + +/datum/extension/labels/proc/AttachLabel(var/mob/user, var/label) + if(!CanAttachLabel(user, label)) + return + + if(!LAZYLEN(labels)) + atom_holder.verbs += /atom/proc/RemoveLabel + LAZYADD(labels, label) + + user.visible_message("\The [user] attaches a label to \the [atom_holder].", \ + "You attach a label, '[label]', to \the [atom_holder].") + + var/old_name = atom_holder.name + atom_holder.name = "[atom_holder.name] ([label])" + GLOB.name_set_event.raise_event(src, old_name, atom_holder.name) + +/datum/extension/labels/proc/RemoveLabel(var/mob/user, var/label) + if(!(label in labels)) + return + + LAZYREMOVE(labels, label) + if(!LAZYLEN(labels)) + atom_holder.verbs -= /atom/proc/RemoveLabel + + var/full_label = " ([label])" + var/index = findtextEx(atom_holder.name, full_label) + if(!index) // Playing it safe, something might not have set the name properly + return + + user.visible_message("\The [user] removes a label from \the [atom_holder].", \ + "You remove a label, '[label]', from \the [atom_holder].") + + var/old_name = atom_holder.name + // We find and replace the first instance, since that's the one we removed from the list + atom_holder.name = replacetext(atom_holder.name, full_label, "", index, index + length(full_label)) + GLOB.name_set_event.raise_event(src, old_name, atom_holder.name) + +// We may have to do something more complex here +// in case something appends strings to something that's labelled rather than replace the name outright +// Non-printable characters should be of help if this comes up +/datum/extension/labels/proc/AppendLabelsToName(var/name) + if(!LAZYLEN(labels)) + return name + . = list(name) + for(var/entry in labels) + . += " ([entry])" + . = jointext(., null) + +/datum/extension/labels/proc/CanAttachLabel(var/user, var/label) + if(!length(label)) + return FALSE + if(ExcessLabelLength(label, user)) + return FALSE + return TRUE + +/datum/extension/labels/proc/ExcessLabelLength(var/label, var/user) + . = length(label) + 3 // Each label also adds a space and two brackets when applied to a name + if(LAZYLEN(labels)) + for(var/entry in labels) + . += length(entry) + 3 + . = . > 64 ? TRUE : FALSE + if(. && user) + to_chat(user, "The label won't fit.") + +/proc/get_attached_labels(var/atom/source) + if(has_extension(source, /datum/extension/labels)) + var/datum/extension/labels/L = get_extension(source, /datum/extension/labels) + if(LAZYLEN(L.labels)) + return L.labels.Copy() + return list() + +/atom/proc/RemoveLabel(var/label in get_attached_labels(src)) + set name = "Remove Label" + set desc = "Used to remove labels" + set category = "Object" + set src in view(1) + + if(CanPhysicallyInteract(usr)) + if(has_extension(src, /datum/extension/labels)) + var/datum/extension/labels/L = get_extension(src, /datum/extension/labels) + L.RemoveLabel(usr, label) diff --git a/code/datums/extensions/multitool/_multitool.dm b/code/datums/extensions/multitool/_multitool.dm new file mode 100644 index 00000000..fd581a00 --- /dev/null +++ b/code/datums/extensions/multitool/_multitool.dm @@ -0,0 +1,3 @@ +#define MT_NOACTION 0 +#define MT_REFRESH 1 +#define MT_CLOSE 2 diff --git a/code/datums/extensions/multitool/circuitboards/circuitboards.dm b/code/datums/extensions/multitool/circuitboards/circuitboards.dm new file mode 100644 index 00000000..295cec71 --- /dev/null +++ b/code/datums/extensions/multitool/circuitboards/circuitboards.dm @@ -0,0 +1,5 @@ +/datum/extension/interactive/multitool/circuitboards/extension_status(var/mob/user) + if(isAI(user)) // No remote AI access + return STATUS_CLOSE + + return ..() diff --git a/code/datums/extensions/multitool/circuitboards/stationalert.dm b/code/datums/extensions/multitool/circuitboards/stationalert.dm new file mode 100644 index 00000000..468356a2 --- /dev/null +++ b/code/datums/extensions/multitool/circuitboards/stationalert.dm @@ -0,0 +1,29 @@ +/datum/extension/interactive/multitool/circuitboards/stationalert/get_interact_window(var/obj/item/device/multitool/M, var/mob/user) + var/obj/item/weapon/circuitboard/stationalert/SA = holder + . += "Alarm Sources
    " + . += "" + for(var/datum/alarm_handler/AH in alarm_manager.all_handlers) + . += "" + . += "" + if(AH in SA.alarm_handlers) + . += "" + else + . += "" + . += "" + . += "
    [AH.category]ActiveInactivateInactiveActivate
    " + +/datum/extension/interactive/multitool/circuitboards/stationalert/on_topic(href, href_list, user) + var/obj/item/weapon/circuitboard/stationalert/SA = holder + if(href_list["add"]) + var/datum/alarm_handler/AH = locate(href_list["add"]) in alarm_manager.all_handlers + if(AH) + SA.alarm_handlers |= AH + return MT_REFRESH + + if(href_list["remove"]) + var/datum/alarm_handler/AH = locate(href_list["remove"]) in alarm_manager.all_handlers + if(AH) + SA.alarm_handlers -= AH + return MT_REFRESH + + return ..() diff --git a/code/datums/extensions/multitool/items/cable.dm b/code/datums/extensions/multitool/items/cable.dm new file mode 100644 index 00000000..a26507c8 --- /dev/null +++ b/code/datums/extensions/multitool/items/cable.dm @@ -0,0 +1,25 @@ +/obj/item/stack/cable_coil/New() + set_extension(src, /datum/extension/interactive/multitool, /datum/extension/interactive/multitool/items/cable) + ..() + +/datum/extension/interactive/multitool/items/cable/get_interact_window(var/obj/item/device/multitool/M, var/mob/user) + var/obj/item/stack/cable_coil/cable_coil = holder + . += "Available Colors
    " + . += "" + for(var/cable_color in possible_cable_coil_colours) + . += "" + . += "" + if(cable_coil.color == possible_cable_coil_colours[cable_color]) + . += "" + else + . += "" + . += "" + . += "
    [cable_color]SelectedSelect
    " + +/datum/extension/interactive/multitool/items/cable/on_topic(href, href_list, user) + var/obj/item/stack/cable_coil/cable_coil = holder + if(href_list["select_color"] && href_list["select_color"] in possible_cable_coil_colours) + cable_coil.set_cable_color(href_list["select_color"], user) + return MT_REFRESH + + return ..() diff --git a/code/datums/extensions/multitool/items/clothing.dm b/code/datums/extensions/multitool/items/clothing.dm new file mode 100644 index 00000000..670bdb16 --- /dev/null +++ b/code/datums/extensions/multitool/items/clothing.dm @@ -0,0 +1,14 @@ +/obj/item/clothing/under/New() + set_extension(src, /datum/extension/interactive/multitool, /datum/extension/interactive/multitool/items/clothing) + ..() + +/datum/extension/interactive/multitool/items/clothing/interact(var/obj/item/device/multitool/M, var/mob/user) + if(extension_status(user) != STATUS_INTERACTIVE) + return + var/obj/item/clothing/under/u = holder + if(u.has_sensor == SUIT_NO_SENSORS) + to_chat(user, "\The [u] doesn't have suit sensors.") + return + u.has_sensor = u.has_sensor == SUIT_LOCKED_SENSORS ? SUIT_HAS_SENSORS : SUIT_LOCKED_SENSORS + + to_chat(user, "You [u.has_sensor == SUIT_LOCKED_SENSORS ? "" : "un"]lock \the [u]'s sensor controls.") diff --git a/code/datums/extensions/multitool/items/items.dm b/code/datums/extensions/multitool/items/items.dm new file mode 100644 index 00000000..9305bc8f --- /dev/null +++ b/code/datums/extensions/multitool/items/items.dm @@ -0,0 +1,5 @@ +/datum/extension/interactive/multitool/items/extension_status(var/mob/user) + if(isAI(user)) // No remote AI access + return STATUS_CLOSE + + return ..() diff --git a/code/datums/extensions/multitool/multitool.dm b/code/datums/extensions/multitool/multitool.dm new file mode 100644 index 00000000..8ffe63e4 --- /dev/null +++ b/code/datums/extensions/multitool/multitool.dm @@ -0,0 +1,70 @@ +/datum/extension/interactive/multitool + var/window_x = 370 + var/window_y = 470 + +/datum/extension/interactive/multitool/proc/interact(var/obj/item/device/multitool/M, var/mob/user) + if(extension_status(user) != STATUS_INTERACTIVE) + return + + var/html = get_interact_window(M, user) + if(html) + var/datum/browser/popup = new(usr, "multitool", "Multitool Menu", window_x, window_y) + popup.set_content(html) + popup.set_title_image(user.browse_rsc_icon(M.icon, M.icon_state)) + popup.open() + else + close_window(usr) + +/datum/extension/interactive/multitool/proc/get_interact_window(var/obj/item/device/multitool/M, var/mob/user) + return + +/datum/extension/interactive/multitool/proc/close_window(var/mob/user) + user << browse(null, "window=multitool") + +/datum/extension/interactive/multitool/proc/buffer(var/obj/item/device/multitool/multitool) + . += "Buffer Memory:
    " + var/buffer_name = multitool.get_buffer_name() + if(buffer_name) + . += "[buffer_name] Send Purge
    " + else + . += "No connection stored in the buffer." + +/datum/extension/interactive/multitool/extension_status(var/mob/user) + if(!user.get_multitool()) + return STATUS_CLOSE + . = ..() + +/datum/extension/interactive/multitool/extension_act(href, href_list, var/mob/user) + if(..()) + close_window(usr) + return TRUE + + var/obj/item/device/multitool/M = user.get_multitool() + if(href_list["send"]) + var/atom/buffer = locate(href_list["send"]) + . = send_buffer(M, buffer, user) + else if(href_list["purge"]) + M.set_buffer(null) + . = MT_REFRESH + else + . = on_topic(href, href_list, user) + + switch(.) + if(MT_REFRESH) + interact(M, user) + if(MT_CLOSE) + close_window(user) + return MT_NOACTION ? FALSE : TRUE + +/datum/extension/interactive/multitool/proc/on_topic(href, href_list, user) + return MT_NOACTION + +/datum/extension/interactive/multitool/proc/send_buffer(var/obj/item/device/multitool/M, var/atom/buffer, var/mob/user) + if(M.get_buffer() == buffer && buffer) + receive_buffer(M, buffer, user) + else if(!buffer) + to_chat(user, "Unable to acquire data from the buffered object. Purging from memory.") + return MT_REFRESH + +/datum/extension/interactive/multitool/proc/receive_buffer(var/obj/item/device/multitool/M, var/atom/buffer, var/mob/user) + return diff --git a/code/datums/extensions/multitool/store.dm b/code/datums/extensions/multitool/store.dm new file mode 100644 index 00000000..becd2674 --- /dev/null +++ b/code/datums/extensions/multitool/store.dm @@ -0,0 +1,10 @@ +/datum/extension/interactive/multitool/store/interact(var/obj/item/device/multitool/M, var/mob/user) + if(CanUseTopic(user) != STATUS_INTERACTIVE) + return + + if(M.get_buffer() == holder) + M.set_buffer(null) + to_chat(user, "You purge the connection data of \the [holder] from \the [M].") + else + M.set_buffer(holder) + to_chat(user, "You load connection data from \the [holder] to \the [M].") diff --git a/code/datums/helper_datums/construction_datum.dm b/code/datums/helper_datums/construction_datum.dm new file mode 100644 index 00000000..1e6fc370 --- /dev/null +++ b/code/datums/helper_datums/construction_datum.dm @@ -0,0 +1,105 @@ +#define FORWARD -1 +#define BACKWARD 1 + +/datum/construction + var/list/steps + var/atom/holder + var/result + var/list/steps_desc + + New(atom) + ..() + holder = atom + if(!holder) //don't want this without a holder + spawn + qdel(src) + set_desc(steps.len) + return + + proc/next_step() + steps.len-- + if(!steps.len) + spawn_result() + else + set_desc(steps.len) + return + + proc/action(atom/used_atom,mob/user as mob) + return + + proc/check_step(atom/used_atom,mob/user as mob) //check last step only + var/valid_step = is_right_key(used_atom) + if(valid_step) + if(custom_action(valid_step, used_atom, user)) + next_step() + return 1 + return 0 + + proc/is_right_key(atom/used_atom) // returns current step num if used_atom is of the right type. + var/list/L = steps[steps.len] + if(istype(used_atom, L["key"])) + return steps.len + return 0 + + proc/custom_action(step, used_atom, user) + return 1 + + proc/check_all_steps(atom/used_atom,mob/user as mob) //check all steps, remove matching one. + for(var/i=1;i<=steps.len;i++) + var/list/L = steps[i]; + if(istype(used_atom, L["key"])) + if(custom_action(i, used_atom, user)) + steps[i]=null;//stupid byond list from list removal... + listclearnulls(steps); + if(!steps.len) + spawn_result() + return 1 + return 0 + + + proc/spawn_result() + if(result) + new result(get_turf(holder)) + spawn() + qdel(holder) + return + + proc/set_desc(index as num) + var/list/step = steps[index] + holder.desc = step["desc"] + return + +/datum/construction/reversible + var/index + + New(atom) + ..() + index = steps.len + return + + proc/update_index(diff as num) + index+=diff + if(index==0) + spawn_result() + else + set_desc(index) + return + + is_right_key(atom/used_atom) // returns index step + var/list/L = steps[index] + if(istype(used_atom, L["key"])) + return FORWARD //to the first step -> forward + else if(L["backkey"] && istype(used_atom, L["backkey"])) + return BACKWARD //to the last step -> backwards + return 0 + + check_step(atom/used_atom,mob/user as mob) + var/diff = is_right_key(used_atom) + if(diff) + if(custom_action(index, diff, used_atom, user)) + update_index(diff) + return 1 + return 0 + + custom_action(index, diff, used_atom, user) + return 1 \ No newline at end of file diff --git a/code/datums/helper_datums/dist_check.dm b/code/datums/helper_datums/dist_check.dm new file mode 100644 index 00000000..24ab9eb8 --- /dev/null +++ b/code/datums/helper_datums/dist_check.dm @@ -0,0 +1,24 @@ +/decl/dist_check/proc/within_dist(var/atom/a, var/atom/b) + return FALSE + +/decl/dist_check/adjacent/within_dist(var/atom/a, var/atom/b) + return a.Adjacent(b) + +/decl/dist_check/in_view/within_dist(var/atom/a, var/atom/b) + return (b in view(world.view, a)) + +/decl/dist_check/in_range/within_dist(var/atom/a, var/atom/b) + return (b in range(world.view, a)) + +/decl/dist_check/same_z_level/within_dist(var/atom/a, var/atom/b) + var/turf/turf_a = get_turf(a) + var/turf/turf_b = get_turf(b) + return turf_a && turf_b && turf_a.z == turf_b.z + +/decl/dist_check/connected_z_level/within_dist(var/atom/a, var/atom/b) + var/turf/turf_a = get_turf(a) + var/turf/turf_b = get_turf(b) + return turf_a && turf_b && AreConnectedZLevels(turf_a.z, turf_b.z) + +/decl/dist_check/omni/within_dist() + return TRUE diff --git a/code/datums/helper_datums/events.dm b/code/datums/helper_datums/events.dm new file mode 100644 index 00000000..97b0f555 --- /dev/null +++ b/code/datums/helper_datums/events.dm @@ -0,0 +1,69 @@ +/* + * WARRANTY VOID IF CODE USED + */ + + +/datum/events + var/list/events + + New() + ..() + events = new + + proc/addEventType(event_type as text) + if(!(event_type in events) || !islist(events[event_type])) + events[event_type] = list() + return 1 + return + + + // Arguments: event_type as text, proc_holder as datum, proc_name as text + // Returns: New event, null on error. + proc/addEvent(event_type as text, proc_holder, proc_name as text) + if(!event_type || !proc_holder || !proc_name) + return + addEventType(event_type) + var/list/event = events[event_type] + var/datum/event/E = new /datum/event(proc_holder,proc_name) + event += E + return E + + // Arguments: event_type as text, any number of additional arguments to pass to event handler + // Returns: null + proc/fireEvent() +// log_debug("Events in [args[1]] called") + + var/list/event = listgetindex(events,args[1]) + if(istype(event)) + spawn(-1) + for(var/datum/event/E in event) + if(!E.Fire(arglist(args.Copy(2)))) + clearEvent(args[1],E) + return + + // Arguments: event_type as text, E as /datum/event + // Returns: 1 if event cleared, null on error + proc/clearEvent(event_type as text, datum/event/E) + if(!event_type || !E) + return + var/list/event = listgetindex(events,event_type) + event -= E + return 1 + + +/datum/event + var/listener + var/proc_name + + New(tlistener,tprocname) + listener = tlistener + proc_name = tprocname + return ..() + + proc/Fire() +// log_debug("Event fired") + + if(listener) + call(listener,proc_name)(arglist(args)) + return 1 + return \ No newline at end of file diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm new file mode 100644 index 00000000..8358672c --- /dev/null +++ b/code/datums/helper_datums/getrev.dm @@ -0,0 +1,46 @@ +var/global/datum/getrev/revdata = new() + +/datum/getrev + var/branch + var/revision + var/date + var/showinfo + +/datum/getrev/New() + var/list/head_branch = file2list(".git/HEAD", "\n") + if(head_branch.len) + branch = copytext(head_branch[1], 17) + + var/list/head_log = file2list(".git/logs/HEAD", "\n") + for(var/line=head_log.len, line>=1, line--) + if(head_log[line]) + var/list/last_entry = splittext(head_log[line], " ") + if(last_entry.len < 2) continue + revision = last_entry[2] + // Get date/time + if(last_entry.len >= 5) + var/unix_time = text2num(last_entry[5]) + if(unix_time) + date = unix2date(unix_time) + break + + world.log << "Running revision:" + world.log << branch + world.log << date + world.log << revision + +/client/verb/showrevinfo() + set category = "OOC" + set name = "Show Server Revision" + set desc = "Check the current server code revision" + + to_chat(src, "Client Version: [byond_version]") + if(revdata.revision) + var/server_revision = revdata.revision + if(config.githuburl) + server_revision = "[server_revision]" + to_chat(src, "Server Revision: [server_revision] - [revdata.branch] - [revdata.date]") + else + to_chat(src, "Server Revision: Revision Unknown") + to_chat(src, "Game ID: [game_id]") + to_chat(src, "Current map: [GLOB.using_map.full_name]") \ No newline at end of file diff --git a/code/datums/helper_datums/global_iterator.dm b/code/datums/helper_datums/global_iterator.dm new file mode 100644 index 00000000..dc247ea4 --- /dev/null +++ b/code/datums/helper_datums/global_iterator.dm @@ -0,0 +1,160 @@ +/* +README: + +The global_iterator datum is supposed to provide a simple and robust way to +create some constantly "looping" processes with ability to stop and restart them at will. +Generally, the only thing you want to play with (meaning, redefine) is the process() proc. +It must contain all the things you want done. + +Control functions: + new - used to create datum. First argument (optional) - var list(to use in process() proc) as list, + second (optional) - autostart control. + If autostart == TRUE, the loop will be started immediately after datum creation. + + start(list/arguments) - starts the loop. Takes arguments(optional) as a list, which is then used + by process() proc. Returns null if datum already active, 1 if loop started succesfully and 0 if there's + an error in supplied arguments (not list or empty list). + + stop() - stops the loop. Returns null if datum is already inactive and 1 on success. + + set_delay(new_delay) - sets the delay between iterations. Pretty selfexplanatory. + Returns 0 on error(new_delay is not numerical), 1 otherwise. + + set_process_args(list/arguments) - passes the supplied arguments to the process() proc. + + active() - Returns 1 if datum is active, 0 otherwise. + + toggle() - toggles datum state. Returns new datum state (see active()). + +Misc functions: + + get_last_exec_time() - Returns the time of last iteration. + + get_last_exec_time_as_text() - Returns the time of last iteration as text + + +Control vars: + + delay - delay between iterations + + check_for_null - if equals TRUE, on each iteration the supplied arguments will be checked for nulls. + If some varible equals null (and null only), the loop is stopped. + Usefull, if some var unexpectedly becomes null - due to object deletion, for example. + Of course, you can also check the variables inside process() proc to prevent runtime errors. + +Data storage vars: + + result - stores the value returned by process() proc +*/ + +/datum/global_iterator + var/control_switch = 0 + var/delay = 10 + var/list/arg_list = new + var/last_exec = null + var/check_for_null = 1 + var/forbid_garbage = 0 + var/result + var/state = 0 + + New(list/arguments=null,autostart=1) + delay = delay>0?(delay):1 + if(forbid_garbage) //prevents garbage collection with tag != null + tag = "\ref[src]" + set_process_args(arguments) + if(autostart) + start() + return + + proc/main() + state = 1 + while(src && control_switch) + last_exec = world.timeofday + if(check_for_null && has_null_args()) + stop() + return 0 + result = process(arglist(arg_list)) + for(var/sleep_time=delay;sleep_time>0;sleep_time--) //uhh, this is ugly. But I see no other way to terminate sleeping proc. Such disgrace. + if(!control_switch) + return 0 + sleep(1) + return 0 + + proc/start(list/arguments=null) + if(active()) + return + if(arguments) + if(!set_process_args(arguments)) + return 0 + if(!state_check()) //the main loop is sleeping, wait for it to terminate. + return + control_switch = 1 + spawn() + state = main() + return 1 + + proc/stop() + if(!active()) + return + control_switch = 0 + spawn(-1) //report termination error but don't wait for state_check(). + state_check() + return 1 + + proc/state_check() + var/lag = 0 + while(state) + sleep(1) + if(++lag>10) + CRASH("The global_iterator loop \ref[src] failed to terminate in designated timeframe. This may be caused by server lagging.") + return 1 + + proc/process() + return + + proc/active() + return control_switch + + proc/has_null_args() + if(null in arg_list) + return 1 + return 0 + + + proc/set_delay(new_delay) + if(isnum(new_delay)) + delay = max(1, round(new_delay)) + return 1 + else + return 0 + + proc/get_last_exec_time() + return (last_exec||0) + + proc/get_last_exec_time_as_text() + return (time2text(last_exec)||"Wasn't executed yet") + + proc/set_process_args(list/arguments) + if(arguments && istype(arguments, /list) && arguments.len) + arg_list = arguments + return 1 + else +// log_error("Invalid arguments supplied for [src.type], ref = \ref[src]") + + return 0 + + proc/toggle_null_checks() + check_for_null = !check_for_null + return check_for_null + + proc/toggle() + if(!stop()) + start() + return active() + +/datum/global_iterator/Destroy() + tag = null + arg_list.Cut() + stop() + return QDEL_HINT_LETMELIVE + //Do not call ..() diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm new file mode 100644 index 00000000..da9c0a0c --- /dev/null +++ b/code/datums/helper_datums/teleport.dm @@ -0,0 +1,59 @@ +/decl/teleport + var/static/list/teleport_blacklist = list(/obj/item/weapon/disk/nuclear, /obj/item/weapon/storage/backpack/holding, /obj/effect/sparks) //Items that cannot be teleported, or be in the contents of someone who is teleporting. + +/decl/teleport/proc/teleport(var/atom/target, var/atom/destination, var/precision = 0) + if(!can_teleport(target,destination)) + target.visible_message("\The [target] bounces off the teleporter!") + return + + teleport_target(target, destination, precision) + +/decl/teleport/proc/teleport_target(var/atom/movable/target, var/atom/destination, var/precision) + var/list/possible_turfs = circlerangeturfs(destination, precision) + destination = safepick(possible_turfs) + + target.forceMove(destination) + if(isliving(target)) + var/mob/living/L = target + if(L.buckled) + var/atom/movable/buckled = L.buckled + buckled.forceMove(destination) + + +/decl/teleport/proc/can_teleport(var/atom/movable/target, var/atom/destination) + if(!destination || !target || !target.loc || destination.z > max_default_z_level()) + return 0 + + if(istype(target, /obj/mecha)) + if(destination.z in GLOB.using_map.admin_levels) + var/obj/mecha/mech = target + to_chat(mech.occupant, "\The [target] would not survive the jump to a location so far away!") + return 0 + + if(is_type_in_list(target, teleport_blacklist)) + return 0 + + for(var/type in teleport_blacklist) + if(!isemptylist(target.search_contents_for(type))) + return 0 + return 1 + +/decl/teleport/sparks + var/datum/effect/effect/system/spark_spread/spark = new + +/decl/teleport/sparks/proc/do_spark(var/atom/target) + if(!target.simulated) + return + var/turf/T = get_turf(target) + spark.set_up(5,1,target) + spark.attach(T) + spark.start() + +/decl/teleport/sparks/teleport_target(var/atom/target, var/atom/destination, var/precision) + do_spark(target) + ..() + do_spark(target) + +/proc/do_teleport(var/atom/movable/target, var/atom/destination, var/precision = 0, var/type = /decl/teleport/sparks) + var/decl/teleport/tele = decls_repository.get_decl(type) + tele.teleport(target, destination, precision) diff --git a/code/datums/helper_datums/topic_input.dm b/code/datums/helper_datums/topic_input.dm new file mode 100644 index 00000000..c08ca754 --- /dev/null +++ b/code/datums/helper_datums/topic_input.dm @@ -0,0 +1,60 @@ +/datum/topic_input + var/href + var/list/href_list + + New(thref,list/thref_list) + href = thref + href_list = thref_list.Copy() + return + + proc/get(i) + return listgetindex(href_list,i) + + proc/getAndLocate(i) + var/t = get(i) + if(t) + t = locate(t) + return t || null + + proc/getNum(i) + var/t = get(i) + if(t) + t = text2num(t) + return isnum(t) ? t : null + + proc/getObj(i) + var/t = getAndLocate(i) + return isobj(t) ? t : null + + proc/getMob(i) + var/t = getAndLocate(i) + return ismob(t) ? t : null + + proc/getTurf(i) + var/t = getAndLocate(i) + return isturf(t) ? t : null + + proc/getAtom(i) + return getType(i,/atom) + + proc/getArea(i) + var/t = getAndLocate(i) + return isarea(t) ? t : null + + proc/getStr(i)//params should always be text, but... + var/t = get(i) + return istext(t) ? t : null + + proc/getType(i,type) + var/t = getAndLocate(i) + return istype(t,type) ? t : null + + proc/getPath(i) + var/t = get(i) + if(t) + t = text2path(t) + return ispath(t) ? t : null + + proc/getList(i) + var/t = getAndLocate(i) + return islist(t) ? t : null \ No newline at end of file diff --git a/code/datums/hierarchy.dm b/code/datums/hierarchy.dm new file mode 100644 index 00000000..32f0ab35 --- /dev/null +++ b/code/datums/hierarchy.dm @@ -0,0 +1,30 @@ +/decl/hierarchy + var/name = "Hierarchy" + var/hierarchy_type + var/decl/hierarchy/parent + var/list/decl/hierarchy/children + +/decl/hierarchy/New(var/full_init = TRUE) + children = list() + if(!full_init) + return + + var/list/all_subtypes = list() + all_subtypes[type] = src + for(var/subtype in subtypesof(type)) + all_subtypes[subtype] = new subtype(FALSE) + + for(var/subtype in (all_subtypes - type)) + var/decl/hierarchy/subtype_instance = all_subtypes[subtype] + var/decl/hierarchy/subtype_parent = all_subtypes[subtype_instance.parent_type] + subtype_instance.parent = subtype_parent + dd_insertObjectList(subtype_parent.children, subtype_instance) + +/decl/hierarchy/proc/is_category() + return hierarchy_type == type || children.len + +/decl/hierarchy/proc/is_hidden_category() + return hierarchy_type == type + +/decl/hierarchy/dd_SortValue() + return name diff --git a/code/datums/looping_sounds/_looping_sound.dm b/code/datums/looping_sounds/_looping_sound.dm new file mode 100644 index 00000000..7c679c2c --- /dev/null +++ b/code/datums/looping_sounds/_looping_sound.dm @@ -0,0 +1,102 @@ +/* + output_atoms (list of atoms) The destination(s) for the sounds + + mid_sounds (list or soundfile) Since this can be either a list or a single soundfile you can have random sounds. May contain further lists but must contain a soundfile at the end. + mid_length (num) The length to wait between playing mid_sounds + + start_sound (soundfile) Played before starting the mid_sounds loop + start_length (num) How long to wait before starting the main loop after playing start_sound + + end_sound (soundfile) The sound played after the main loop has concluded + + chance (num) Chance per loop to play a mid_sound + volume (num) Sound output volume + max_loops (num) The max amount of loops to run for. + direct (bool) If true plays directly to provided atoms instead of from them +*/ +/datum/looping_sound + var/list/atom/output_atoms + var/mid_sounds + var/mid_length + var/start_sound + var/start_length + var/end_sound + var/chance + var/volume = 100 + var/vary = FALSE + var/max_loops + var/direct + var/extra_range = 0 + var/falloff + + var/timerid + +/datum/looping_sound/New(list/_output_atoms=list(), start_immediately=FALSE, _direct=FALSE) + if(!mid_sounds) + WARNING("A looping sound datum was created without sounds to play.") + return + + output_atoms = _output_atoms + direct = _direct + + if(start_immediately) + start() + +/datum/looping_sound/Destroy() + stop() + output_atoms = null + return ..() + +/datum/looping_sound/proc/start(atom/add_thing) + if(add_thing) + output_atoms |= add_thing + if(timerid) + return + on_start() + +/datum/looping_sound/proc/stop(atom/remove_thing) + if(remove_thing) + output_atoms -= remove_thing + if(!timerid) + return + on_stop() + deltimer(timerid) + timerid = null + +/datum/looping_sound/proc/sound_loop(starttime) + if(max_loops && world.time >= starttime + mid_length * max_loops) + stop() + return + if(!chance || prob(chance)) + play(get_sound(starttime)) + if(!timerid) + timerid = addtimer(CALLBACK(src, .proc/sound_loop, world.time), mid_length, TIMER_CLIENT_TIME | TIMER_STOPPABLE) //| TIMER_LOOP) + +/datum/looping_sound/proc/play(soundfile) + var/list/atoms_cache = output_atoms + var/sound/S = sound(soundfile) + if(direct) + S.channel = 0 //Any channel. //open_sound_channel() + S.volume = volume + for(var/i in 1 to atoms_cache.len) + var/atom/thing = atoms_cache[i] + if(direct) + sound_to(thing, S) + else + playsound(thing, S, volume, vary, extra_range, falloff) + +/datum/looping_sound/proc/get_sound(starttime, _mid_sounds) + . = _mid_sounds || mid_sounds + while(!isfile(.) && !isnull(.)) + . = pickweight(.) + +/datum/looping_sound/proc/on_start() + var/start_wait = 0 + if(start_sound) + play(start_sound) + start_wait = start_length + addtimer(CALLBACK(src, .proc/sound_loop), start_wait, TIMER_CLIENT_TIME) + +/datum/looping_sound/proc/on_stop() + if(end_sound) + play(end_sound) diff --git a/code/datums/mil_ranks.dm b/code/datums/mil_ranks.dm new file mode 100644 index 00000000..7168eac6 --- /dev/null +++ b/code/datums/mil_ranks.dm @@ -0,0 +1,185 @@ +/** + * Datums for military branches and ranks + * + * Map datums can optionally specify a list of /datum/mil_branch paths. These paths + * are used to initialize the global mil_branches object, which contains a list of + * branch objects the map uses. Each branch definition specifies a list of + * /datum/mil_rank paths, which are ranks available to that branch. + * + * Which branches and ranks can be selected for spawning is specifed in GLOB.using_map + * and each branch datum definition, respectively. + */ + +var/datum/mil_branches/mil_branches = new() + +/** + * Global object for handling branches + */ +/datum/mil_branches + var/list/branches // All branches that exist + var/list/spawn_branches_ // Branches that a player can choose for spawning, not including species restrictions. + var/list/spawn_branches_by_species_ // Branches that a player can choose for spawning, with species restrictions. Populated on a needed basis + +/** + * Retrieve branch object by branch name + */ +/datum/mil_branches/proc/get_branch(var/branch_name) + if(branch_name == "None" || !(branch_name in branches)) + return null + else + return branches[branch_name] + +/** + * Retrieve branch object by branch type + */ +/datum/mil_branches/proc/get_branch_by_type(var/branch_type) + for(var/name in branches) + if (istype(branches[name], branch_type)) + return branches[name] + +/** + * Retrieve a rank object from given branch by name + */ +/datum/mil_branches/proc/get_rank(var/branch_name, var/rank_name) + if(rank_name == "None") + return null + + var/datum/mil_branch/branch = get_branch(branch_name) + + if(!branch || !(rank_name in branch.ranks)) + return null + + var/datum/mil_rank/rank = branch.ranks[rank_name] + return rank + +/** + * Return all spawn branches for the given input + */ +/datum/mil_branches/proc/spawn_branches(var/datum/species/S) + if(!S) + return spawn_branches_.Copy() + . = spawn_branches_by_species_[S] + if(!.) + . = list() + spawn_branches_by_species_[S] = . + for(var/spawn_branch in spawn_branches_) + if(!GLOB.using_map.is_species_branch_restricted(S, spawn_branches_[spawn_branch])) + . += spawn_branch + +/** + * Return all spawn ranks for the given input + */ +/datum/mil_branches/proc/spawn_ranks(var/branch_name, var/datum/species/S) + var/datum/mil_branch/branch = get_branch(branch_name) + return branch && branch.spawn_ranks(S) + +/** + * Return a true value if branch_name is a valid spawn branch key + */ +/datum/mil_branches/proc/is_spawn_branch(var/branch_name, var/datum/species/S) + return (branch_name in spawn_branches(S)) + + +/** + * Return a true value if rank_name is a valid spawn rank in branch under branch_name + */ +/datum/mil_branches/proc/is_spawn_rank(var/branch_name, var/rank_name, var/datum/species/S) + var/datum/mil_branch/branch = get_branch(branch_name) + + if(branch && (rank_name in branch.spawn_ranks(S))) + return TRUE + else + return FALSE + +/** + * A single military branch, such as Fleet or Marines + */ +/datum/mil_branch + var/name = "Unknown" // Longer name for branch, eg "Sol Central Marine Corps" + var/name_short // Abbreviation of the name, eg "SCMC" + + + + var/list/ranks // Associative list of full rank names to the corresponding + // /datum/mil_rank objects. These are all ranks available to the branch. + + var/list/spawn_ranks_ // Ranks which the player can choose for spawning, not including species restrictions + var/list/spawn_ranks_by_species_ // Ranks which the player can choose for spawning, with species restrictions. Populated on a needed basis + + var/list/rank_types // list of paths used to init the ranks list + var/list/spawn_rank_types // list of paths used to init the spawn_ranks list. Subset of rank_types + + var/assistant_job //what people who have the BE_ASSISTANT pref set will attempt to join as + + // Email addresses will be created under this domain name. Mostly for the looks. + var/email_domain = "freemail.nt" + +/datum/mil_branch/New() + ranks = list() + spawn_ranks_ = list() + spawn_ranks_by_species_ = list() + + for(var/rank_path in rank_types) + if(!ispath(rank_path, /datum/mil_rank)) + crash_with("[name]'s rank_types includes [rank_path], which is not a subtype of /datum/mil_rank.") + continue + var/datum/mil_rank/rank = new rank_path () + ranks[rank.name] = rank + + if(rank_path in spawn_rank_types) + spawn_ranks_[rank.name] = rank + +/datum/mil_branch/proc/spawn_ranks(var/datum/species/S) + if(!S) + return spawn_ranks_.Copy() + . = spawn_ranks_by_species_[S] + if(!.) + . = list() + spawn_ranks_by_species_[S] = . + for(var/spawn_rank in spawn_ranks_) + if(!GLOB.using_map.is_species_rank_restricted(S, src, spawn_ranks_[spawn_rank])) + . += spawn_rank + + +/** + * Populate the global branches list from GLOB.using_map + */ +/hook/startup/proc/populate_branches() + if(!(GLOB.using_map.flags & MAP_HAS_BRANCH) && !(GLOB.using_map.flags & MAP_HAS_RANK)) + mil_branches.branches = null + mil_branches.spawn_branches_ = null + mil_branches.spawn_branches_by_species_ = null + return 1 + + mil_branches.branches = list() + mil_branches.spawn_branches_ = list() + mil_branches.spawn_branches_by_species_ = list() + for(var/branch_path in GLOB.using_map.branch_types) + if(!ispath(branch_path, /datum/mil_branch)) + crash_with("populate_branches() attempted to instantiate object with path [branch_path], which is not a subtype of /datum/mil_branch.") + continue + + var/datum/mil_branch/branch = new branch_path () + mil_branches.branches[branch.name] = branch + + if(branch_path in GLOB.using_map.spawn_branch_types) + mil_branches.spawn_branches_[branch.name] = branch + + return 1 + +/** + * A military rank + * + * Note that in various places "rank" is used to refer to a character's job, and + * so this is "mil_rank" to distinguish it. + */ +/datum/mil_rank + var/name = "Unknown" + var/name_short // Abbreviation of the name. Should be null if the + // rank doesn't usually serve as a prefix to the individual's name. + var/list/accessory //type of accesory that will be equipped by job code with this rank + var/sort_order = 0 // A numerical equivalent of the rank used to indicate its order when compared to other datums: eg e-1 = 1, o-1 = 11 + +//Returns short designation (yes shorter than name_short), like E1, O3 etc. +/datum/mil_rank/proc/grade() + return sort_order \ No newline at end of file diff --git a/code/datums/mind.dm b/code/datums/mind.dm new file mode 100644 index 00000000..3e932809 --- /dev/null +++ b/code/datums/mind.dm @@ -0,0 +1,566 @@ +/* Note from Carnie: + The way datum/mind stuff works has been changed a lot. + Minds now represent IC characters rather than following a client around constantly. + + Guidelines for using minds properly: + + - Never mind.transfer_to(ghost). The var/current and var/original of a mind must always be of type mob/living! + ghost.mind is however used as a reference to the ghost's corpse + + - When creating a new mob for an existing IC character (e.g. cloning a dead guy or borging a brain of a human) + the existing mind of the old mob should be transfered to the new mob like so: + + mind.transfer_to(new_mob) + + - You must not assign key= or ckey= after transfer_to() since the transfer_to transfers the client for you. + By setting key or ckey explicitly after transfering the mind with transfer_to you will cause bugs like DCing + the player. + + - IMPORTANT NOTE 2, if you want a player to become a ghost, use mob.ghostize() It does all the hard work for you. + + - When creating a new mob which will be a new IC character (e.g. putting a shade in a construct or randomly selecting + a ghost to become a xeno during an event). Simply assign the key or ckey like you've always done. + + new_mob.key = key + + The Login proc will handle making a new mob for that mobtype (including setting up stuff like mind.name). Simple! + However if you want that mind to have any special properties like being a traitor etc you will have to do that + yourself. + +*/ + +/datum/mind + var/key + var/name //replaces mob/var/original_name + var/mob/living/current + var/mob/living/original //TODO: remove.not used in any meaningful way ~Carn. First I'll need to tweak the way silicon-mobs handle minds. + var/active = 0 + + var/memory + var/list/known_connections //list of known (RNG) relations between people + var/gen_relations_info + + var/assigned_role + var/special_role + + var/role_alt_title + + var/datum/job/assigned_job + + var/list/datum/objective/objectives = list() + var/list/datum/objective/special_verbs = list() + + var/has_been_rev = 0//Tracks if this mind has been a rev or not + + var/datum/faction/faction //associated faction + var/datum/changeling/changeling //changeling holder + + var/rev_cooldown = 0 + + // the world.time since the mob has been brigged, or -1 if not at all + var/brigged_since = -1 + + //put this here for easier tracking ingame + var/datum/money_account/initial_account + + //used for optional self-objectives that antagonists can give themselves, which are displayed at the end of the round. + var/ambitions + + +/datum/mind/New(var/key) + src.key = key + ..() + +/datum/mind/proc/transfer_to(mob/living/new_character) + if(!istype(new_character)) + world.log << "## DEBUG: transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob. Please inform Carn" + if(current) //remove ourself from our old body's mind variable + if(changeling) + current.remove_changeling_powers() + current.verbs -= /datum/changeling/proc/EvolutionMenu + current.mind = null + + GLOB.nanomanager.user_transferred(current, new_character) // transfer active NanoUI instances to new user + if(new_character.mind) //remove any mind currently in our new body's mind variable + new_character.mind.current = null + + current = new_character //link ourself to our new body + new_character.mind = src //and link our new body to ourself + + if(learned_spells && learned_spells.len) + restore_spells(new_character) + + if(changeling) + new_character.make_changeling() + + if(active) + new_character.key = key //now transfer the key to link the client to our new body + +/datum/mind/proc/store_memory(new_text) + memory += "[new_text]
    " + +/datum/mind/proc/show_memory(mob/recipient) + var/output = "[current.real_name]'s Memory
    " + output += memory + + if(objectives.len>0) + output += "
    Objectives:" + + var/obj_count = 1 + for(var/datum/objective/objective in objectives) + output += "Objective #[obj_count]: [objective.explanation_text]" + obj_count++ + + if(ambitions) + output += "
    Ambitions: [ambitions]
    " + + recipient << browse(output,"window=memory") + +/datum/mind/proc/edit_memory() + if(!ticker || !ticker.mode) + alert("Not before round-start!", "Alert") + return + + var/out = "[name][(current&&(current.real_name!=name))?" (as [current.real_name])":""]
    " + out += "Mind currently owned by key: [key] [active?"(synced)":"(not synced)"]
    " + out += "Assigned role: [assigned_role]. Edit
    " + out += "
    " + out += "Factions and special roles:
    " + var/list/all_antag_types = all_antag_types() + for(var/antag_type in all_antag_types) + var/datum/antagonist/antag = all_antag_types[antag_type] + out += "[antag.get_panel_entry(src)]" + out += "

    " + out += "Objectives
    " + + if(objectives && objectives.len) + var/num = 1 + for(var/datum/objective/O in objectives) + out += "Objective #[num]: [O.explanation_text] " + if(O.completed) + out += "(complete)" + else + out += "(incomplete)" + out += " \[toggle\]" + out += " \[remove\]
    " + num++ + out += "
    \[announce objectives\]" + + else + out += "None." + out += "
    \[add\]

    " + out += "Ambitions: [ambitions ? ambitions : "None"] \[edit\]
    " + usr << browse(out, "window=edit_memory[src]") + +/datum/mind/Topic(href, href_list) + if(!check_rights(R_ADMIN)) return + + if(href_list["add_antagonist"]) + var/datum/antagonist/antag = all_antag_types()[href_list["add_antagonist"]] + if(antag) + if(antag.add_antagonist(src, 1, 1, 0, 1, 1)) // Ignore equipment and role type for this. + log_admin("[key_name_admin(usr)] made [key_name(src)] into a [antag.role_text].") + else + to_chat(usr, "[src] could not be made into a [antag.role_text]!") + + else if(href_list["remove_antagonist"]) + var/datum/antagonist/antag = all_antag_types()[href_list["remove_antagonist"]] + if(antag) antag.remove_antagonist(src) + + else if(href_list["equip_antagonist"]) + var/datum/antagonist/antag = all_antag_types()[href_list["equip_antagonist"]] + if(antag) antag.equip(src.current) + + else if(href_list["unequip_antagonist"]) + var/datum/antagonist/antag = all_antag_types()[href_list["unequip_antagonist"]] + if(antag) antag.unequip(src.current) + + else if(href_list["move_antag_to_spawn"]) + var/datum/antagonist/antag = all_antag_types()[href_list["move_antag_to_spawn"]] + if(antag) antag.place_mob(src.current) + + else if (href_list["role_edit"]) + var/new_role = input("Select new role", "Assigned role", assigned_role) as null|anything in joblist + if (!new_role) return + assigned_role = new_role + + else if (href_list["memory_edit"]) + var/new_memo = sanitize(input("Write new memory", "Memory", memory) as null|message) + if (isnull(new_memo)) return + memory = new_memo + + else if (href_list["amb_edit"]) + var/datum/mind/mind = locate(href_list["amb_edit"]) + if(!mind) + return + var/new_ambition = input("Enter a new ambition", "Memory", mind.ambitions) as null|message + if(isnull(new_ambition)) + return + new_ambition = sanitize(new_ambition) + if(mind) + mind.ambitions = new_ambition + if(new_ambition) + to_chat(mind.current, "Your ambitions have been changed by higher powers, they are now: [mind.ambitions]") + log_and_message_admins("made [key_name(mind.current)]'s ambitions be '[mind.ambitions]'.") + else + to_chat(mind.current, "Your ambitions have been unmade by higher powers.") + log_and_message_admins("has cleared [key_name(mind.current)]'s ambitions.") + else + to_chat(usr, "The mind has ceased to be.") + + else if (href_list["obj_edit"] || href_list["obj_add"]) + var/datum/objective/objective + var/objective_pos + var/def_value + + if (href_list["obj_edit"]) + objective = locate(href_list["obj_edit"]) + if (!objective) return + objective_pos = objectives.Find(objective) + + //Text strings are easy to manipulate. Revised for simplicity. + var/temp_obj_type = "[objective.type]"//Convert path into a text string. + def_value = copytext(temp_obj_type, 19)//Convert last part of path into an objective keyword. + if(!def_value)//If it's a custom objective, it will be an empty string. + def_value = "custom" + + var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "debrain", "protect", "prevent", "harm", "brig", "hijack", "escape", "survive", "steal", "download", "mercenary", "capture", "absorb", "custom") + if (!new_obj_type) return + + var/datum/objective/new_objective = null + + switch (new_obj_type) + if ("assassinate","protect","debrain", "harm", "brig") + //To determine what to name the objective in explanation text. + var/objective_type_capital = uppertext(copytext(new_obj_type, 1,2))//Capitalize first letter. + var/objective_type_text = copytext(new_obj_type, 2)//Leave the rest of the text. + var/objective_type = "[objective_type_capital][objective_type_text]"//Add them together into a text string. + + var/list/possible_targets = list("Free objective") + for(var/datum/mind/possible_target in ticker.minds) + if ((possible_target != src) && istype(possible_target.current, /mob/living/carbon/human)) + possible_targets += possible_target.current + + var/mob/def_target = null + var/objective_list[] = list(/datum/objective/assassinate, /datum/objective/protect, /datum/objective/debrain) + if (objective&&(objective.type in objective_list) && objective:target) + def_target = objective:target.current + + var/new_target = input("Select target:", "Objective target", def_target) as null|anything in possible_targets + if (!new_target) return + + var/objective_path = text2path("/datum/objective/[new_obj_type]") + var/mob/living/M = new_target + if (!istype(M) || !M.mind || new_target == "Free objective") + new_objective = new objective_path + new_objective.owner = src + new_objective:target = null + new_objective.explanation_text = "Free objective" + else + new_objective = new objective_path + new_objective.owner = src + new_objective:target = M.mind + new_objective.explanation_text = "[objective_type] [M.real_name], the [M.mind.special_role ? M.mind:special_role : M.mind:assigned_role]." + + if ("prevent") + new_objective = new /datum/objective/block + new_objective.owner = src + + if ("hijack") + new_objective = new /datum/objective/hijack + new_objective.owner = src + + if ("escape") + new_objective = new /datum/objective/escape + new_objective.owner = src + + if ("survive") + new_objective = new /datum/objective/survive + new_objective.owner = src + + if ("mercenary") + new_objective = new /datum/objective/nuclear + new_objective.owner = src + + if ("steal") + if (!istype(objective, /datum/objective/steal)) + new_objective = new /datum/objective/steal + new_objective.owner = src + else + new_objective = objective + var/datum/objective/steal/steal = new_objective + if (!steal.select_target()) + return + + if("capture","absorb") + var/def_num + if(objective&&objective.type==text2path("/datum/objective/[new_obj_type]")) + def_num = objective.target_amount + + var/target_number = input("Input target number:", "Objective", def_num) as num|null + if (isnull(target_number))//Ordinarily, you wouldn't need isnull. In this case, the value may already exist. + return + + switch(new_obj_type) + /* + if("download") + new_objective = new /datum/objective/download + new_objective.explanation_text = "Download [target_number] research levels." + */ + if("capture") + new_objective = new /datum/objective/capture + new_objective.explanation_text = "Accumulate [target_number] capture points." + if("absorb") + new_objective = new /datum/objective/absorb + new_objective.explanation_text = "Absorb [target_number] compatible genomes." + new_objective.owner = src + new_objective.target_amount = target_number + + if ("custom") + var/expl = sanitize(input("Custom objective:", "Objective", objective ? objective.explanation_text : "") as text|null) + if (!expl) return + new_objective = new /datum/objective + new_objective.owner = src + new_objective.explanation_text = expl + + if (!new_objective) return + + if (objective) + objectives -= objective + objectives.Insert(objective_pos, new_objective) + else + objectives += new_objective + + else if (href_list["obj_delete"]) + var/datum/objective/objective = locate(href_list["obj_delete"]) + if(!istype(objective)) return + objectives -= objective + + else if(href_list["obj_completed"]) + var/datum/objective/objective = locate(href_list["obj_completed"]) + if(!istype(objective)) return + objective.completed = !objective.completed + + else if(href_list["implant"]) + var/mob/living/carbon/human/H = current + + BITSET(H.hud_updateflag, IMPLOYAL_HUD) // updates that players HUD images so secHUD's pick up they are implanted or not. + + switch(href_list["implant"]) + if("remove") + for(var/obj/item/weapon/implant/loyalty/I in H.contents) + for(var/obj/item/organ/external/organs in H.organs) + if(I in organs.implants) + qdel(I) + break + to_chat(H, "Your loyalty implant has been deactivated.") + log_admin("[key_name_admin(usr)] has de-loyalty implanted [current].") + if("add") + to_chat(H, "You somehow have become the recepient of a loyalty transplant, and it just activated!") + H.implant_loyalty(H, override = TRUE) + log_admin("[key_name_admin(usr)] has loyalty implanted [current].") + else + else if (href_list["silicon"]) + BITSET(current.hud_updateflag, SPECIALROLE_HUD) + switch(href_list["silicon"]) + + if("unemag") + var/mob/living/silicon/robot/R = current + if (istype(R)) + R.emagged = 0 + if (R.activated(R.module.emag)) + R.module_active = null + if(R.module_state_1 == R.module.emag) + R.module_state_1 = null + R.contents -= R.module.emag + else if(R.module_state_2 == R.module.emag) + R.module_state_2 = null + R.contents -= R.module.emag + else if(R.module_state_3 == R.module.emag) + R.module_state_3 = null + R.contents -= R.module.emag + log_admin("[key_name_admin(usr)] has unemag'ed [R].") + + if("unemagcyborgs") + if (istype(current, /mob/living/silicon/ai)) + var/mob/living/silicon/ai/ai = current + for (var/mob/living/silicon/robot/R in ai.connected_robots) + R.emagged = 0 + if (R.module) + if (R.activated(R.module.emag)) + R.module_active = null + if(R.module_state_1 == R.module.emag) + R.module_state_1 = null + R.contents -= R.module.emag + else if(R.module_state_2 == R.module.emag) + R.module_state_2 = null + R.contents -= R.module.emag + else if(R.module_state_3 == R.module.emag) + R.module_state_3 = null + R.contents -= R.module.emag + log_admin("[key_name_admin(usr)] has unemag'ed [ai]'s Cyborgs.") + + else if (href_list["common"]) + switch(href_list["common"]) + if("undress") + for(var/obj/item/W in current) + current.drop_from_inventory(W) + if("takeuplink") + take_uplink() + memory = null//Remove any memory they may have had. + if("crystals") + if (usr.client.holder.rights & R_FUN) + var/obj/item/device/uplink/suplink = find_syndicate_uplink() + if(!suplink) + to_chat(usr, "Failed to find an uplink.") + return + var/crystals = suplink.uses + crystals = input("Amount of telecrystals for [key]","Operative uplink", crystals) as null|num + if (!isnull(crystals) && !QDELETED(suplink)) + suplink.uses = crystals + log_and_message_admins("set the telecrystals for [key] to [crystals]") + + else if (href_list["obj_announce"]) + var/obj_count = 1 + to_chat(current, "Your current objectives:") + for(var/datum/objective/objective in objectives) + to_chat(current, "Objective #[obj_count]: [objective.explanation_text]") + obj_count++ + edit_memory() + +/datum/mind/proc/find_syndicate_uplink() + var/list/L = current.get_contents() + for (var/obj/item/I in L) + if (I.hidden_uplink) + return I.hidden_uplink + return null + +/datum/mind/proc/take_uplink() + var/obj/item/device/uplink/H = find_syndicate_uplink() + if(H) + qdel(H) + + +// check whether this mind's mob has been brigged for the given duration +// have to call this periodically for the duration to work properly +/datum/mind/proc/is_brigged(duration) + var/turf/T = current.loc + if(!istype(T)) + brigged_since = -1 + return 0 + var/is_currently_brigged = 0 + if(istype(T.loc,/area/security/brig)) + is_currently_brigged = 1 + for(var/obj/item/weapon/card/id/card in current) + is_currently_brigged = 0 + break // if they still have ID they're not brigged + for(var/obj/item/device/pda/P in current) + if(P.id) + is_currently_brigged = 0 + break // if they still have ID they're not brigged + + if(!is_currently_brigged) + brigged_since = -1 + return 0 + + if(brigged_since == -1) + brigged_since = world.time + + return (duration <= world.time - brigged_since) + +/datum/mind/proc/reset() + assigned_role = null + special_role = null + role_alt_title = null + assigned_job = null + //faction = null //Uncommenting this causes a compile error due to 'undefined type', fucked if I know. + changeling = null + initial_account = null + objectives = list() + special_verbs = list() + has_been_rev = 0 + rev_cooldown = 0 + brigged_since = -1 + +//Antagonist role check +/mob/living/proc/check_special_role(role) + if(mind) + if(!role) + return mind.special_role + else + return (mind.special_role == role) ? 1 : 0 + else + return 0 + +//Initialisation procs +/mob/living/proc/mind_initialize() + if(mind) + mind.key = key + else + mind = new /datum/mind(key) + mind.original = src + if(ticker) + ticker.minds += mind + else + world.log << "## DEBUG: mind_initialize(): No ticker ready yet! Please inform Carn" + if(!mind.name) mind.name = real_name + mind.current = src + + +//HUMAN +/mob/living/carbon/human/mind_initialize() + ..() + if(!mind.assigned_role) mind.assigned_role = "Assistant" //defualt + +//slime +/mob/living/carbon/slime/mind_initialize() + ..() + mind.assigned_role = "slime" + +/mob/living/carbon/alien/larva/mind_initialize() + ..() + mind.special_role = "Larva" + +//AI +/mob/living/silicon/ai/mind_initialize() + ..() + mind.assigned_role = "AI" + +//BORG +/mob/living/silicon/robot/mind_initialize() + ..() + mind.assigned_role = "Cyborg" + +//PAI +/mob/living/silicon/pai/mind_initialize() + ..() + mind.assigned_role = "pAI" + mind.special_role = "" + +//Animals +/mob/living/simple_animal/mind_initialize() + ..() + mind.assigned_role = "Animal" + +/mob/living/simple_animal/corgi/mind_initialize() + ..() + mind.assigned_role = "Corgi" + +/mob/living/simple_animal/shade/mind_initialize() + ..() + mind.assigned_role = "Shade" + +/mob/living/simple_animal/construct/builder/mind_initialize() + ..() + mind.assigned_role = "Artificer" + mind.special_role = "Cultist" + +/mob/living/simple_animal/construct/wraith/mind_initialize() + ..() + mind.assigned_role = "Wraith" + mind.special_role = "Cultist" + +/mob/living/simple_animal/construct/armoured/mind_initialize() + ..() + mind.assigned_role = "Juggernaut" + mind.special_role = "Cultist" diff --git a/code/datums/observation/_defines.dm b/code/datums/observation/_defines.dm new file mode 100644 index 00000000..902d6558 --- /dev/null +++ b/code/datums/observation/_defines.dm @@ -0,0 +1 @@ +#define CANCEL_MOVE_EVENT -55 diff --git a/code/datums/observation/death.dm b/code/datums/observation/death.dm new file mode 100644 index 00000000..d424a5ab --- /dev/null +++ b/code/datums/observation/death.dm @@ -0,0 +1,22 @@ +// Observer Pattern Implementation: Death +// Registration type: /mob +// +// Raised when: A mob is added to the dead_mob_list +// +// Arguments that the called proc should expect: +// /mob/dead: The mob that was added to the dead_mob_list + +GLOBAL_DATUM_INIT(death_event, /decl/observ/death, new) + +/decl/observ/death + name = "Death" + expected_type = /mob + +/***************** +* Death Handling * +*****************/ + +/mob/living/add_to_dead_mob_list() + . = ..() + if(.) + GLOB.death_event.raise_event(src) diff --git a/code/datums/observation/density_set.dm b/code/datums/observation/density_set.dm new file mode 100644 index 00000000..00b812a7 --- /dev/null +++ b/code/datums/observation/density_set.dm @@ -0,0 +1,30 @@ +// Observer Pattern Implementation: Density Set +// Registration type: /atom +// +// Raised when: An /atom changes density using the set_density() proc. +// +// Arguments that the called proc should expect: +// /atom/density_changer: The instance that changed density. +// /old_density: The density before the change. +// /new_density: The density after the change. + +GLOBAL_DATUM_INIT(density_set_event, /decl/observ/density_set, new) + +/decl/observ/density_set + name = "Density Set" + expected_type = /atom + +/******************* +* Density Handling * +*******************/ +/atom/set_density(new_density) + var/old_density = density + . = ..() + if(density != old_density) + GLOB.density_set_event.raise_event(src, old_density, density) + +/turf/ChangeTurf() + var/old_density = opacity + . = ..() + if(density != old_density) + GLOB.density_set_event.raise_event(src, old_density, density) diff --git a/code/datums/observation/destroyed.dm b/code/datums/observation/destroyed.dm new file mode 100644 index 00000000..8f8d82e4 --- /dev/null +++ b/code/datums/observation/destroyed.dm @@ -0,0 +1,17 @@ +// Observer Pattern Implementation: Destroyed +// Registration type: /datum +// +// Raised when: A /datum instance is destroyed. +// +// Arguments that the called proc should expect: +// /datum/destroyed_instance: The instance that was destroyed. + +GLOBAL_DATUM_INIT(destroyed_event, /decl/observ/destroyed, new) + +/decl/observ/destroyed + name = "Destroyed" + +/datum/Destroy() + GLOB.destroyed_event && GLOB.destroyed_event.raise_event(src) + . = ..() + cleanup_events(src) diff --git a/code/datums/observation/dir_set.dm b/code/datums/observation/dir_set.dm new file mode 100644 index 00000000..9848fc3e --- /dev/null +++ b/code/datums/observation/dir_set.dm @@ -0,0 +1,41 @@ +// Observer Pattern Implementation: Direction Set +// Registration type: /atom +// +// Raised when: An /atom changes dir using the set_dir() proc. +// +// Arguments that the called proc should expect: +// /atom/dir_changer: The instance that changed direction +// /old_dir: The dir before the change. +// /new_dir: The dir after the change. + +GLOBAL_DATUM_INIT(dir_set_event, /decl/observ/dir_set, new) + +/decl/observ/dir_set + name = "Direction Set" + expected_type = /atom + +/decl/observ/dir_set/register(var/atom/dir_changer, var/datum/listener, var/proc_call) + . = ..() + + // Listen to the parent if possible. + if(. && istype(dir_changer.loc, /atom/movable)) // We don't care about registering to turfs. + register(dir_changer.loc, dir_changer, /atom/proc/recursive_dir_set) + +/********************* +* Direction Handling * +*********************/ + +/atom/set_dir() + var/old_dir = dir + . = ..() + if(old_dir != dir) + GLOB.dir_set_event.raise_event(src, old_dir, dir) + +/atom/movable/Entered(var/atom/movable/am, atom/old_loc) + . = ..() + if(GLOB.dir_set_event.has_listeners(am)) + GLOB.dir_set_event.register(src, am, /atom/proc/recursive_dir_set) + +/atom/movable/Exited(var/atom/movable/am, atom/old_loc) + . = ..() + GLOB.dir_set_event.unregister(src, am, /atom/proc/recursive_dir_set) diff --git a/code/datums/observation/entered.dm b/code/datums/observation/entered.dm new file mode 100644 index 00000000..4d517a7e --- /dev/null +++ b/code/datums/observation/entered.dm @@ -0,0 +1,24 @@ +// Observer Pattern Implementation: Entered +// Registration type: /atom +// +// Raised when: An /atom/movable instance has entered an atom. +// +// Arguments that the called proc should expect: +// /atom/entered: The atom that was entered +// /atom/movable/enterer: The instance that entered the atom +// /atom/old_loc: The atom the enterer came from +// + +GLOBAL_DATUM_INIT(entered_event, /decl/observ/entered, new) + +/decl/observ/entered + name = "Entered" + expected_type = /atom + +/******************* +* Entered Handling * +*******************/ + +/atom/Entered(atom/movable/enterer, atom/old_loc) + ..() + GLOB.entered_event.raise_event(src, enterer, old_loc) diff --git a/code/datums/observation/equipped.dm b/code/datums/observation/equipped.dm new file mode 100644 index 00000000..a04bcf1f --- /dev/null +++ b/code/datums/observation/equipped.dm @@ -0,0 +1,40 @@ +// Observer Pattern Implementation: Equipped +// Registration type: /mob +// +// Raised when: A mob equips an item. +// +// Arguments that the called proc should expect: +// /mob/equipper: The mob that equipped the item. +// /obj/item/item: The equipped item. +// slot: The slot equipped to. + +GLOBAL_DATUM_INIT(mob_equipped_event, /decl/observ/mob_equipped, new) + +/decl/observ/mob_equipped + name = "Mob Equipped" + expected_type = /mob + +// Observer Pattern Implementation: Equipped +// Registration type: /obj/item +// +// Raised when: A mob equips an item. +// +// Arguments that the called proc should expect: +// /obj/item/item: The equipped item. +// /mob/equipper: The mob that equipped the item. +// slot: The slot equipped to. + +GLOBAL_DATUM_INIT(item_equipped_event, /decl/observ/item_equipped, new) + +/decl/observ/item_equipped + name = "Item Equipped" + expected_type = /obj/item + +/******************** +* Equipped Handling * +********************/ + +/obj/item/equipped(var/mob/user, var/slot) + . = ..() + GLOB.mob_equipped_event.raise_event(user, src, slot) + GLOB.item_equipped_event.raise_event(src, user, slot) diff --git a/code/datums/observation/exited.dm b/code/datums/observation/exited.dm new file mode 100644 index 00000000..87d280a8 --- /dev/null +++ b/code/datums/observation/exited.dm @@ -0,0 +1,24 @@ +// Observer Pattern Implementation: Exited +// Registration type: /atom +// +// Raised when: An /atom/movable instance has exited an atom. +// +// Arguments that the called proc should expect: +// /atom/entered: The atom that was exited from +// /atom/movable/enterer: The instance that exited the atom +// /atom/new_loc: The atom the exitee is now residing in +// + +GLOBAL_DATUM_INIT(exited_event, /decl/observ/exited, new) + +/decl/observ/exited + name = "Exited" + expected_type = /atom + +/****************** +* Exited Handling * +******************/ + +/atom/Exited(atom/movable/exitee, atom/new_loc) + . = ..() + GLOB.exited_event.raise_event(src, exitee, new_loc) diff --git a/code/datums/observation/helpers.dm b/code/datums/observation/helpers.dm new file mode 100644 index 00000000..be9ca644 --- /dev/null +++ b/code/datums/observation/helpers.dm @@ -0,0 +1,28 @@ +/atom/movable/proc/recursive_move(var/atom/movable/am, var/old_loc, var/new_loc) + GLOB.moved_event.raise_event(src, old_loc, new_loc) + +/atom/movable/proc/move_to_turf(var/atom/movable/am, var/old_loc, var/new_loc) + var/turf/T = get_turf(new_loc) + if(T && T != loc) + forceMove(T) + +// Similar to above but we also follow into nullspace +/atom/movable/proc/move_to_turf_or_null(var/atom/movable/am, var/old_loc, var/new_loc) + var/turf/T = get_turf(new_loc) + if(T != loc) + forceMove(T) + +/atom/proc/recursive_dir_set(var/atom/a, var/old_dir, var/new_dir) + set_dir(new_dir) + +// Sometimes you just want to end yourself +/datum/proc/qdel_self() + qdel(src) + +/proc/register_all_movement(var/event_source, var/listener) + GLOB.moved_event.register(event_source, listener, /atom/movable/proc/recursive_move) + GLOB.dir_set_event.register(event_source, listener, /atom/proc/recursive_dir_set) + +/proc/unregister_all_movement(var/event_source, var/listener) + GLOB.moved_event.unregister(event_source, listener, /atom/movable/proc/recursive_move) + GLOB.dir_set_event.unregister(event_source, listener, /atom/proc/recursive_dir_set) diff --git a/code/datums/observation/life.dm b/code/datums/observation/life.dm new file mode 100644 index 00000000..45760c92 --- /dev/null +++ b/code/datums/observation/life.dm @@ -0,0 +1,22 @@ +// Observer Pattern Implementation: Life +// Registration type: /mob +// +// Raised when: A mob is added to the life_mob_list +// +// Arguments that the called proc should expect: +// /mob/dead: The mob that was added to the life_mob_list + +GLOBAL_DATUM_INIT(life_event, /decl/observ/life, new) + +/decl/observ/life + name = "Life" + expected_type = /mob + +/***************** +* Life Handling * +*****************/ + +/mob/add_to_living_mob_list() + . = ..() + if(.) + GLOB.life_event.raise_event(src) diff --git a/code/datums/observation/logged_in.dm b/code/datums/observation/logged_in.dm new file mode 100644 index 00000000..c59e146a --- /dev/null +++ b/code/datums/observation/logged_in.dm @@ -0,0 +1,21 @@ +// Observer Pattern Implementation: Logged in +// Registration type: /mob +// +// Raised when: A mob logs in (not client) +// +// Arguments that the called proc should expect: +// /mob/joiner: The mob that has logged in + +GLOBAL_DATUM_INIT(logged_in_event, /decl/observ/logged_in, new) + +/decl/observ/logged_in + name = "Logged In" + expected_type = /mob + +/***************** +* Login Handling * +*****************/ + +/mob/Login() + ..() + GLOB.logged_in_event.raise_event(src) diff --git a/code/datums/observation/logged_out.dm b/code/datums/observation/logged_out.dm new file mode 100644 index 00000000..f8e2d30b --- /dev/null +++ b/code/datums/observation/logged_out.dm @@ -0,0 +1,23 @@ +// Observer Pattern Implementation: Logged Out +// Registration type: /mob +// +// Raised when: A mob logs out (client either logged out or was moved to another mob) +// +// Arguments that the called proc should expect: +// /mob/leaver: The mob that has logged out +// /client/client: The mob's client + +GLOBAL_DATUM_INIT(logged_out_event, /decl/observ/logged_out, new) + +/decl/observ/logged_out + name = "Logged Out" + expected_type = /mob + +/****************** +* Logout Handling * +******************/ + +/mob/Logout() + message_admins("Logout: [key] id:[computer_id]") + GLOB.logged_out_event.raise_event(src, my_client) + ..() diff --git a/code/datums/observation/moved.dm b/code/datums/observation/moved.dm new file mode 100644 index 00000000..e31baa2e --- /dev/null +++ b/code/datums/observation/moved.dm @@ -0,0 +1,52 @@ +// Observer Pattern Implementation: Moved +// Registration type: /atom/movable +// +// Raised when: An /atom/movable instance has moved using Move() or forceMove(). +// +// Arguments that the called proc should expect: +// /atom/movable/moving_instance: The instance that moved +// /atom/old_loc: The loc before the move. +// /atom/new_loc: The loc after the move. + +GLOBAL_DATUM_INIT(moved_event, /decl/observ/moved, new) + +/decl/observ/moved + name = "Moved" + expected_type = /atom/movable + +/decl/observ/moved/register(var/atom/movable/mover, var/datum/listener, var/proc_call) + . = ..() + + // Listen to the parent if possible. + if(. && istype(mover.loc, expected_type)) + register(mover.loc, mover, /atom/movable/proc/recursive_move) + +/******************** +* Movement Handling * +********************/ + +/atom/Entered(var/atom/movable/am, var/atom/old_loc) + . = ..() + GLOB.moved_event.raise_event(am, old_loc, am.loc) + +/atom/movable/Entered(var/atom/movable/am, atom/old_loc) + . = ..() + if(GLOB.moved_event.has_listeners(am)) + GLOB.moved_event.register(src, am, /atom/movable/proc/recursive_move) + +/atom/movable/Exited(var/atom/movable/am, atom/old_loc) + . = ..() + GLOB.moved_event.unregister(src, am, /atom/movable/proc/recursive_move) + +// Entered() typically lifts the moved event, but in the case of null-space we'll have to handle it. +/atom/movable/Move() + var/old_loc = loc + . = ..() + if(. && !loc) + GLOB.moved_event.raise_event(src, old_loc, null) + +/atom/movable/forceMove(atom/destination) + var/old_loc = loc + . = ..() + if(. && !loc) + GLOB.moved_event.raise_event(src, old_loc, null) diff --git a/code/datums/observation/name_set.dm b/code/datums/observation/name_set.dm new file mode 100644 index 00000000..ee8dd74d --- /dev/null +++ b/code/datums/observation/name_set.dm @@ -0,0 +1,28 @@ +// Observer Pattern Implementation: Name Set +// Registration type: /atom +// +// Raised when: An atom's name changes. +// +// Arguments that the called proc should expect: +// /atom/namee: The atom that had its name set +// /old_name: name before the change +// /new_name: name after the change + +GLOBAL_DATUM_INIT(name_set_event, /decl/observ/name_set, new) + +/decl/observ/name_set + name = "Name Set" + expected_type = /atom + +/********************* +* Name Set Handling * +*********************/ + +/atom/proc/SetName(var/new_name) + var/old_name = name + if(old_name != new_name) + name = new_name + if(has_extension(src, /datum/extension/labels)) + var/datum/extension/labels/L = get_extension(src, /datum/extension/labels) + name = L.AppendLabelsToName(name) + GLOB.name_set_event.raise_event(src, old_name, new_name) diff --git a/code/datums/observation/observation.dm b/code/datums/observation/observation.dm new file mode 100644 index 00000000..5c17712f --- /dev/null +++ b/code/datums/observation/observation.dm @@ -0,0 +1,238 @@ +// +// Observer Pattern Implementation +// +// Implements a basic observer pattern with the following main procs: +// +// /decl/observ/proc/is_listening(var/event_source, var/datum/listener, var/proc_call) +// event_source: The instance which is generating events. +// listener: The instance which may be listening to events by event_source +// proc_call: Optional. The specific proc to call when the event is raised. +// +// Returns true if listener is listening for events by event_source, and proc_call supplied is either null or one of the proc that will be called when an event is raised. +// +// /decl/observ/proc/has_listeners(var/event_source) +// event_source: The instance which is generating events. +// +// Returns true if the given event_source has any listeners at all, globally or to specific event sources. +// +// /decl/observ/proc/register(var/event_source, var/datum/listener, var/proc_call) +// event_source: The instance you wish to receive events from. +// listener: The instance/owner of the proc to call when an event is raised by the event_source. +// proc_call: The proc to call when an event is raised. +// +// It is possible to register the same listener to the same event_source multiple times as long as it is using different proc_calls. +// Registering again using the same event_source, listener, and proc_call that has been registered previously will have no additional effect. +// I.e.: The proc_call will still only be called once per raised event. That particular proc_call will only have to be unregistered once. +// +// When proc_call is called the first argument is always the source of the event (event_source). +// Additional arguments may or may not be supplied, see individual event definition files (destroyed.dm, moved.dm, etc.) for details. +// +// The instance making the register() call is also responsible for calling unregister(), see below for additonal details, including when event_source is destroyed. +// This can be handled by listening to the event_source's destroyed event, unregistering in the listener's Destroy() proc, etc. +// +// /decl/observ/proc/unregister(var/event_source, var/datum/listener, var/proc_call) +// event_source: The instance you wish to stop receiving events from. +// listener: The instance which will no longer receive the events. +// proc_call: Optional: The proc_call to unregister. +// +// Unregisters the listener from the event_source. +// If a proc_call has been supplied only that particular proc_call will be unregistered. If the proc_call isn't currently registered there will be no effect. +// If no proc_call has been supplied, the listener will have all registrations made to the given event_source undone. +// +// /decl/observ/proc/register_global(var/datum/listener, var/proc_call) +// listener: The instance/owner of the proc to call when an event is raised by any and all sources. +// proc_call: The proc to call when an event is raised. +// +// Works very much the same as register(), only the listener/proc_call will receive all relevant events from all event sources. +// Global registrations can overlap with registrations made to specific event sources and these will not affect each other. +// +// /decl/observ/proc/unregister_global(var/datum/listener, var/proc_call) +// listener: The instance/owner of the proc which will no longer receive the events. +// proc_call: Optional: The proc_call to unregister. +// +// Works very much the same as unregister(), only it undoes global registrations instead. +// +// /decl/observ/proc/raise_event(src, ...) +// Should never be called unless implementing a new event type. +// The first argument shall always be the event_source belonging to the event. Beyond that there are no restrictions. + +/decl/observ + var/name = "Unnamed Event" // The name of this event, used mainly for debug/VV purposes. The list of event managers can be reached through the "Debug Controller" verb, selecting the "Observation" entry. + var/expected_type = /datum // The expected event source for this event. register() will CRASH() if it receives an unexpected type. + var/list/event_sources = list() // Associative list of event sources, each with their own associative list. This associative list contains an instance/list of procs to call when the event is raised. + var/list/global_listeners = list() // Associative list of instances that listen to all events of this type (as opposed to events belonging to a specific source) and the proc to call. + +/decl/observ/New() + GLOB.all_observable_events += src + ..() + +/decl/observ/proc/is_listening(var/event_source, var/datum/listener, var/proc_call) + // Return whether there are global listeners unless the event source is given. + if (!event_source) + return !!global_listeners.len + + // Return whether anything is listening to a source, if no listener is given. + if (!listener) + return global_listeners.len || (event_source in event_sources) + + // Return false if nothing is associated with that source. + if (!(event_source in event_sources)) + return FALSE + + // Get and check the listeners for the reuqested event. + var/listeners = event_sources[event_source] + if (!(listener in listeners)) + return FALSE + + // Return true unless a specific callback needs checked. + if (!proc_call) + return TRUE + + // Check if the specific callback exists. + var/list/callback = listeners[listener] + if (!callback) + return FALSE + + return (proc_call in callback) + +/decl/observ/proc/has_listeners(var/event_source) + return is_listening(event_source) + +/decl/observ/proc/register(var/datum/event_source, var/datum/listener, var/proc_call) + // Sanity checking. + if (!(event_source && listener && proc_call)) + return FALSE + if (istype(event_source, /decl/observ)) + return FALSE + + // Crash if the event source is the wrong type. + if (!istype(event_source, expected_type)) + CRASH("Unexpected type. Expected [expected_type], was [event_source.type]") + + // Setup the listeners for this source if needed. + var/list/listeners = event_sources[event_source] + if (!listeners) + listeners = list() + event_sources[event_source] = listeners + + // Make sure the callbacks are a list. + var/list/callbacks = listeners[listener] + if (!callbacks) + callbacks = list() + listeners[listener] = callbacks + + // If the proc_call is already registered skip + if(proc_call in callbacks) + return FALSE + + // Add the callback, and return true. + callbacks += proc_call + return TRUE + +/decl/observ/proc/unregister(var/event_source, var/datum/listener, var/proc_call) + // Sanity. + if (!(event_source && listener && (event_source in event_sources))) + return FALSE + + // Return false if nothing is listening for this event. + var/list/listeners = event_sources[event_source] + if (!listeners) + return FALSE + + // Remove all callbacks if no specific one is given. + if (!proc_call) + if(listeners.Remove(listener)) + // Perform some cleanup and return true. + if (!listeners.len) + event_sources -= event_source + return TRUE + return FALSE + + // See if the listener is registered. + var/list/callbacks = listeners[listener] + if (!callbacks) + return FALSE + + // See if the callback exists. + if(!callbacks.Remove(proc_call)) + return FALSE + + if (!callbacks.len) + listeners -= listener + if (!listeners.len) + event_sources -= event_source + return TRUE + +/decl/observ/proc/register_global(var/datum/listener, var/proc_call) + // Sanity. + if (!(listener && proc_call)) + return FALSE + + // Make sure the callbacks are setup. + var/list/callbacks = global_listeners[listener] + if (!callbacks) + callbacks = list() + global_listeners[listener] = callbacks + + // Add the callback and return true. + callbacks |= proc_call + return TRUE + +/decl/observ/proc/unregister_global(var/datum/listener, var/proc_call) + // Return false unless the listener is set as a global listener. + if (!(listener && (listener in global_listeners))) + return FALSE + + // Remove all callbacks if no specific one is given. + if (!proc_call) + global_listeners -= listener + return TRUE + + // See if the listener is registered. + var/list/callbacks = global_listeners[listener] + if (!callbacks) + return FALSE + + // See if the callback exists. + if(!callbacks.Remove(proc_call)) + return FALSE + + if (!callbacks.len) + global_listeners -= listener + return TRUE + +/decl/observ/proc/raise_event() + // Sanity + if (!args.len) + return FALSE + + // Call the global listeners. + for (var/datum/listener in global_listeners) + var/list/callbacks = global_listeners[listener] + for (var/proc_call in callbacks) + + // If the callback crashes, record the error and remove it. + try + call(listener, proc_call)(arglist(args)) + catch (var/exception/e) + error("[e.name] - [e.file] - [e.line]") + error(e.desc) + unregister_global(listener, proc_call) + + // Call the listeners for this specific event source, if they exist. + var/source = args[1] + if (source in event_sources) + var/list/listeners = event_sources[source] + for (var/datum/listener in listeners) + var/list/callbacks = listeners[listener] + for (var/proc_call in callbacks) + + // If the callback crashes, record the error and remove it. + try + call(listener, proc_call)(arglist(args)) + catch (var/exception/e) + error("[e.name] - [e.file] - [e.line]") + error(e.desc) + unregister(source, listener, proc_call) + + return TRUE diff --git a/code/datums/observation/opacity_set.dm b/code/datums/observation/opacity_set.dm new file mode 100644 index 00000000..70d10988 --- /dev/null +++ b/code/datums/observation/opacity_set.dm @@ -0,0 +1,33 @@ +// Observer Pattern Implementation: Opacity Set +// Registration type: /atom +// +// Raised when: An /atom changes opacity using the set_opacity() proc. +// +// Arguments that the called proc should expect: +// /atom/dir_changer: The instance that changed opacity +// /old_opacity: The opacity before the change. +// /new_opacity: The opacity after the change. + +GLOBAL_DATUM_INIT(opacity_set_event, /decl/observ/opacity_set, new) + +/decl/observ/opacity_set + name = "Opacity Set" + expected_type = /atom + +/******************* +* Opacity Handling * +*******************/ +/atom/proc/set_opacity(new_opacity) + if(new_opacity != opacity) + var/old_opacity = opacity + opacity = new_opacity + GLOB.opacity_set_event.raise_event(src, old_opacity, new_opacity) + return TRUE + else + return FALSE + +/turf/ChangeTurf() + var/old_opacity = opacity + . = ..() + if(opacity != old_opacity) + GLOB.opacity_set_event.raise_event(src, old_opacity, opacity) diff --git a/code/datums/observation/see_in_dark_set.dm b/code/datums/observation/see_in_dark_set.dm new file mode 100644 index 00000000..15f06999 --- /dev/null +++ b/code/datums/observation/see_in_dark_set.dm @@ -0,0 +1,25 @@ +// Observer Pattern Implementation: See In Dark Set +// Registration type: /mob +// +// Raised when: A mob's see_in_dark value changes. +// +// Arguments that the called proc should expect: +// /mob/sightee: The mob that had its see_in_dark set +// /old_see_in_dark: see_in_dark before the change +// /new_see_in_dark: see_in_dark after the change + +GLOBAL_DATUM_INIT(see_in_dark_set_event, /decl/observ/see_in_dark_set, new) + +/decl/observ/see_in_dark_set + name = "See In Dark Set" + expected_type = /mob + +/*************************** +* See In Dark Set Handling * +***************************/ + +/mob/proc/set_see_in_dark(var/new_see_in_dark) + var/old_see_in_dark = sight + if(old_see_in_dark != new_see_in_dark) + see_in_dark = new_see_in_dark + GLOB.see_in_dark_set_event.raise_event(src, old_see_in_dark, new_see_in_dark) diff --git a/code/datums/observation/see_invisible_set.dm b/code/datums/observation/see_invisible_set.dm new file mode 100644 index 00000000..cdce96bc --- /dev/null +++ b/code/datums/observation/see_invisible_set.dm @@ -0,0 +1,25 @@ +// Observer Pattern Implementation: See Invisible Set +// Registration type: /mob +// +// Raised when: A mob's see_invisible value changes. +// +// Arguments that the called proc should expect: +// /mob/sightee: The mob that had its sight set +// /old_see_invisible: see_invisible before the change +// /new_see_invisible: see_invisible after the change + +GLOBAL_DATUM_INIT(see_invisible_set_event, /decl/observ/see_invisible_set, new) + +/decl/observ/see_invisible_set + name = "See Invisible Set" + expected_type = /mob + +/***************************** +* See Invisible Set Handling * +*****************************/ + +/mob/proc/set_see_invisible(var/new_see_invisible) + var/old_see_invisible = see_invisible + if(old_see_invisible != new_see_invisible) + see_invisible = new_see_invisible + GLOB.see_invisible_set_event.raise_event(src, old_see_invisible, new_see_invisible) diff --git a/code/datums/observation/set_invisibility.dm b/code/datums/observation/set_invisibility.dm new file mode 100644 index 00000000..1d2c2fd1 --- /dev/null +++ b/code/datums/observation/set_invisibility.dm @@ -0,0 +1,26 @@ +// Observer Pattern Implementation: Invisibility Set +// Registration type: /atom +// +// Raised when: An atom's invisiblity value is changed. +// +// Arguments that the called proc should expect: +// /atom/invisibilee: The atom that had its invisibility set +// /old_invisibility: invisibility before the change +// /new_invisibility: invisibility after the change + +GLOBAL_DATUM_INIT(invisibility_set_event, /decl/observ/invisibility_set, new) + +/decl/observ/invisibility_set + name = "Invisibility Set" + expected_type = /atom + +/***************************** +* Invisibility Set Handling * +*****************************/ + +/atom/proc/set_invisibility(var/new_invisibility = 0) + var/old_invisibility = invisibility + if(old_invisibility != new_invisibility) + invisibility = new_invisibility + GLOB.invisibility_set_event.raise_event(src, old_invisibility, new_invisibility) + diff --git a/code/datums/observation/sight_set.dm b/code/datums/observation/sight_set.dm new file mode 100644 index 00000000..0810c84a --- /dev/null +++ b/code/datums/observation/sight_set.dm @@ -0,0 +1,25 @@ +// Observer Pattern Implementation: Sight Set +// Registration type: /mob +// +// Raised when: A mob's sight value changes. +// +// Arguments that the called proc should expect: +// /mob/sightee: The mob that had its sight set +// /old_sight: sight before the change +// /new_sight: sight after the change + +GLOBAL_DATUM_INIT(sight_set_event, /decl/observ/sight_set, new) + +/decl/observ/sight_set + name = "Sight Set" + expected_type = /mob + +/********************* +* Sight Set Handling * +*********************/ + +/mob/proc/set_sight(var/new_sight) + var/old_sight = sight + if(old_sight != new_sight) + sight = new_sight + GLOB.sight_set_event.raise_event(src, old_sight, new_sight) diff --git a/code/datums/observation/stat_set.dm b/code/datums/observation/stat_set.dm new file mode 100644 index 00000000..b980d06e --- /dev/null +++ b/code/datums/observation/stat_set.dm @@ -0,0 +1,24 @@ +// Observer Pattern Implementation: Stat Set +// Registration type: /mob/living +// +// Raised when: A /mob/living changes stat, using the set_stat() proc +// +// Arguments that the called proc should expect: +// /mob/living/stat_mob: The mob whose stat changed +// /old_stat: Status before the change. +// /new_stat: Status after the change. + +GLOBAL_DATUM_INIT(stat_set_event, /decl/observ/stat_set, new) + +/decl/observ/stat_set + name = "Stat Set" + expected_type = /mob/living + +/**************** +* Stat Handling * +****************/ +/mob/living/set_stat(var/new_stat) + var/old_stat = stat + . = ..() + if(stat != old_stat) + GLOB.stat_set_event.raise_event(src, old_stat, new_stat) diff --git a/code/datums/observation/turf_changed.dm b/code/datums/observation/turf_changed.dm new file mode 100644 index 00000000..b634b0cc --- /dev/null +++ b/code/datums/observation/turf_changed.dm @@ -0,0 +1,28 @@ +// Observer Pattern Implementation: Turf Changed +// Registration type: /turf +// +// Raised when: A turf has been changed using the ChangeTurf proc. +// +// Arguments that the called proc should expect: +// /turf/affected: The turf that has changed +// /old_density: Density before the change +// /new_density: Density after the change +// /old_opacity: Opacity before the change +// /new_opacity: Opacity after the change + +GLOBAL_DATUM_INIT(turf_changed_event, /decl/observ/turf_changed, new) + +/decl/observ/turf_changed + name = "Turf Changed" + expected_type = /turf + +/************************ +* Turf Changed Handling * +************************/ + +/turf/ChangeTurf() + var/old_density = density + var/old_opacity = opacity + . = ..() + if(.) + GLOB.turf_changed_event.raise_event(src, old_density, density, old_opacity, opacity) diff --git a/code/datums/observation/unequipped.dm b/code/datums/observation/unequipped.dm new file mode 100644 index 00000000..6ad8d8ec --- /dev/null +++ b/code/datums/observation/unequipped.dm @@ -0,0 +1,38 @@ +// Observer Pattern Implementation: Unequipped (dropped) +// Registration type: /mob +// +// Raised when: A mob unequips/drops an item. +// +// Arguments that the called proc should expect: +// /mob/equipped: The mob that unequipped/dropped the item. +// /obj/item/item: The unequipped item. + +GLOBAL_DATUM_INIT(mob_unequipped_event, /decl/observ/mob_unequipped, new) + +/decl/observ/mob_unequipped + name = "Mob Unequipped" + expected_type = /mob + +// Observer Pattern Implementation: Unequipped (dropped) +// Registration type: /obj/item +// +// Raised when: A mob unequips/drops an item. +// +// Arguments that the called proc should expect: +// /obj/item/item: The unequipped item. +// /mob/equipped: The mob that unequipped/dropped the item. + +GLOBAL_DATUM_INIT(item_unequipped_event, /decl/observ/item_unequipped, new) + +/decl/observ/item_unequipped + name = "Item Unequipped" + expected_type = /obj/item + +/********************** +* Unequipped Handling * +**********************/ + +/obj/item/dropped(var/mob/user) + ..() + GLOB.mob_unequipped_event.raise_event(user, src) + GLOB.item_unequipped_event.raise_event(src, user) diff --git a/code/datums/observation/~cleanup.dm b/code/datums/observation/~cleanup.dm new file mode 100644 index 00000000..8131ad6d --- /dev/null +++ b/code/datums/observation/~cleanup.dm @@ -0,0 +1,71 @@ +GLOBAL_LIST_EMPTY(global_listen_count) +GLOBAL_LIST_EMPTY(event_sources_count) +GLOBAL_LIST_EMPTY(event_listen_count) + +/proc/cleanup_events(var/source) + if(GLOB.global_listen_count && GLOB.global_listen_count[source]) + cleanup_global_listener(source, GLOB.global_listen_count[source]) + if(GLOB.event_sources_count && GLOB.event_sources_count[source]) + cleanup_source_listeners(source, GLOB.event_sources_count[source]) + if(GLOB.event_listen_count && GLOB.event_listen_count[source]) + cleanup_event_listener(source, GLOB.event_listen_count[source]) + +/decl/observ/register(var/datum/event_source, var/datum/listener, var/proc_call) + . = ..() + if(.) + GLOB.event_sources_count[event_source] += 1 + GLOB.event_listen_count[listener] += 1 + +/decl/observ/unregister(var/datum/event_source, var/datum/listener, var/proc_call) + . = ..() + if(.) + GLOB.event_sources_count[event_source] -= 1 + GLOB.event_listen_count[listener] -= 1 + + if(GLOB.event_sources_count[event_source] <= 0) + GLOB.event_sources_count -= event_source + if(GLOB.event_listen_count[listener] <= 0) + GLOB.event_listen_count -= listener + +/decl/observ/register_global(var/datum/listener, var/proc_call) + . = ..() + if(.) + GLOB.global_listen_count[listener] += 1 + +/decl/observ/unregister_global(var/datum/listener, var/proc_call) + . = ..() + if(.) + GLOB.global_listen_count[listener] -= 1 + if(GLOB.global_listen_count[listener] <= 0) + GLOB.global_listen_count -= listener + +/proc/cleanup_global_listener(listener, listen_count) + GLOB.global_listen_count -= listener + for(var/entry in GLOB.all_observable_events) + var/decl/observ/event = entry + if(event.unregister_global(listener)) + log_debug("[event] - [listener] was deleted while still registered to global events.") + if(!(--listen_count)) + return + +/proc/cleanup_source_listeners(event_source, source_listener_count) + GLOB.event_sources_count -= event_source + for(var/entry in GLOB.all_observable_events) + var/decl/observ/event = entry + var/proc_owners = event.event_sources[event_source] + if(proc_owners) + for(var/proc_owner in proc_owners) + if(event.unregister(event_source, proc_owner)) + log_debug("[event] - [event_source] was deleted while still being listened to by [proc_owner].") + if(!(--source_listener_count)) + return + +/proc/cleanup_event_listener(listener, listener_count) + GLOB.event_listen_count -= listener + for(var/entry in GLOB.all_observable_events) + var/decl/observ/event = entry + for(var/event_source in event.event_sources) + if(event.unregister(event_source, listener)) + log_debug("[event] - [listener] was deleted while still listening to [event_source].") + if(!(--listener_count)) + return diff --git a/code/datums/outfits/_defines.dm b/code/datums/outfits/_defines.dm new file mode 100644 index 00000000..0e58005c --- /dev/null +++ b/code/datums/outfits/_defines.dm @@ -0,0 +1,12 @@ +#define OUTFIT_NONE 0x0000 +#define OUTFIT_HAS_JETPACK 0x0001 +#define OUTFIT_HAS_BACKPACK 0x0002 +#define OUTFIT_EXTENDED_SURVIVAL 0x0004 +#define OUTFIT_RESET_EQUIPMENT 0x0008 +#define OUTFIT_NO_BACKPACK 0x0016 +#define OUTFIT_NO_SURVIVAL_GEAR 0x0032 + +#define OUTFIT_ADJUSTMENT_SKIP_POST_EQUIP 0x0001 +#define OUTFIT_ADJUSTMENT_SKIP_SURVIVAL_GEAR 0x0002 +#define OUTFIT_ADJUSTMENT_SKIP_ID_PDA 0x0004 +#define OUTFIT_ADJUSTMENT_PLAIN_HEADSET 0x0008 \ No newline at end of file diff --git a/code/datums/outfits/equipment/backpacks.dm b/code/datums/outfits/equipment/backpacks.dm new file mode 100644 index 00000000..a9db6dba --- /dev/null +++ b/code/datums/outfits/equipment/backpacks.dm @@ -0,0 +1,179 @@ +#define BACKPACK_HAS_TYPE_SELECTION 1 +#define BACKPACK_HAS_SUBTYPE_SELECTION 2 + +/******************* +* Outfit Backpacks * +*******************/ + +/* Setup new backpacks here */ +/decl/backpack_outfit/nothing + name = "Nothing" + +/decl/backpack_outfit/nothing/spawn_backpack(var/location, var/metadata, var/desired_type) + return + +/decl/backpack_outfit/backpack + name = "Backpack" + path = /obj/item/weapon/storage/backpack + is_default = TRUE + +/decl/backpack_outfit/satchel + name = "Satchel" + path = /obj/item/weapon/storage/backpack/satchel + +/decl/backpack_outfit/satchel/New() + ..() + tweaks += new/datum/backpack_tweak/selection/specified_types_as_list(typesof(/obj/item/weapon/storage/backpack/satchel/leather) + /obj/item/weapon/storage/backpack/satchel/grey) + +/decl/backpack_outfit/messenger_bag + name = "Messenger bag" + path = /obj/item/weapon/storage/backpack/messenger + +/decl/backpack_outfit/pocketbook + name = "Pocketbook" + path = /obj/item/weapon/storage/backpack/satchel/pocketbook + flags = BACKPACK_HAS_TYPE_SELECTION + +/* Code */ +/decl/backpack_outfit + var/flags + var/name + var/path + var/is_default = FALSE + var/list/tweaks + +/decl/backpack_outfit/New() + tweaks = tweaks || list() + + if(FLAGS_EQUALS(flags, BACKPACK_HAS_TYPE_SELECTION|BACKPACK_HAS_SUBTYPE_SELECTION)) + CRASH("May not have both type and subtype selection tweaks") + + if(flags & BACKPACK_HAS_TYPE_SELECTION) + tweaks += new/datum/backpack_tweak/selection/types(path) + if(flags & BACKPACK_HAS_SUBTYPE_SELECTION) + tweaks += new/datum/backpack_tweak/selection/subtypes(path) + +/decl/backpack_outfit/proc/spawn_backpack(var/location, var/metadata, var/desired_type) + metadata = metadata || list() + desired_type = desired_type || path + for(var/t in tweaks) + var/datum/backpack_tweak/bt = t + var/tweak_metadata = metadata["[bt]"] || bt.get_default_metadata() + desired_type = bt.get_backpack_type(desired_type, tweak_metadata) + + . = new desired_type(location) + + for(var/t in tweaks) + var/datum/backpack_tweak/bt = t + var/tweak_metadata = metadata["[bt]"] + bt.tweak_backpack(., tweak_metadata) + +/****************** +* Backpack Tweaks * +******************/ +/datum/backpack_tweak/proc/get_ui_content(var/metadata) + return "" + +/datum/backpack_tweak/proc/get_default_metadata() + return + +/datum/backpack_tweak/proc/get_metadata(var/user, var/metadata, var/title = CHARACTER_PREFERENCE_INPUT_TITLE) + return + +/datum/backpack_tweak/proc/validate_metadata(var/metadata) + return get_default_metadata() + +/datum/backpack_tweak/proc/get_backpack_type(var/given_backpack_type) + return given_backpack_type + +/datum/backpack_tweak/proc/tweak_backpack(var/obj/item/weapon/storage/backpack/backpack, var/metadata) + return + + +/* Selection Tweak */ +/datum/backpack_tweak/selection + var/const/RETURN_GIVEN_BACKPACK = "default" + var/const/RETURN_RANDOM_BACKPACK = "random" + var/list/selections + +/datum/backpack_tweak/selection/New(var/list/selections) + if(!selections.len) + CRASH("No selections offered") + if(RETURN_GIVEN_BACKPACK in selections) + CRASH("May not use the keyword '[RETURN_GIVEN_BACKPACK]'") + if(RETURN_RANDOM_BACKPACK in selections) + CRASH("May not use the keyword '[RETURN_RANDOM_BACKPACK]'") + var/list/duplicate_keys = duplicates(selections) + if(duplicate_keys.len) + CRASH("Duplicate names found: [english_list(duplicate_keys)]") + var/list/duplicate_values = duplicates(list_values(selections)) + if(duplicate_values.len) + CRASH("Duplicate types found: [english_list(duplicate_values)]") + for(var/selection_key in selections) + if(!istext(selection_key)) + CRASH("Expected a valid selection key, was [log_info_line(selection_key)]") + var/selection_type = selections[selection_key] + if(!ispath(selection_type, /obj/item/weapon/storage/backpack)) + CRASH("Expected a valid selection value, was [log_info_line(selection_type)]") + + src.selections = selections + selections += RETURN_GIVEN_BACKPACK + selections += RETURN_RANDOM_BACKPACK + +/datum/backpack_tweak/selection/get_ui_content(var/metadata) + return "Type: [metadata]" + +/datum/backpack_tweak/selection/get_default_metadata() + return RETURN_GIVEN_BACKPACK + +/datum/backpack_tweak/selection/validate_metadata(var/metadata) + return (metadata in selections) ? metadata : ..() + +/datum/backpack_tweak/selection/get_metadata(var/user, var/metadata, var/title = CHARACTER_PREFERENCE_INPUT_TITLE) + return input(user, "Choose a type.", title, metadata) as null|anything in selections + +/datum/backpack_tweak/selection/get_backpack_type(var/given_backpack_type, var/metadata) + switch(metadata) + if(RETURN_GIVEN_BACKPACK) + return given_backpack_type + if(RETURN_RANDOM_BACKPACK) + var/random_choice = pick(selections - RETURN_RANDOM_BACKPACK) + return get_backpack_type(given_backpack_type, random_choice) + else + return selections[metadata] + +/datum/backpack_tweak/selection/types/New(var/selection_type) + ..(atomtype2nameassoclist(selection_type)) + +/datum/backpack_tweak/selection/subtypes/New(var/selection_type) + ..(atomtypes2nameassoclist(subtypesof(selection_type))) + +/datum/backpack_tweak/selection/specified_types_as_list/New(var/selection_list) + ..(atomtypes2nameassoclist(selection_list)) + +/datum/backpack_tweak/selection/specified_types_as_args/New() + ..(atomtypes2nameassoclist(args)) + +/****************** +* Character setup * +*******************/ +/datum/backpack_setup + var/decl/backpack_outfit/backpack + var/metadata + +/datum/backpack_setup/New(var/backpack, var/metadata) + src.backpack = backpack + src.metadata = metadata + +/********** +* Helpers * +**********/ +/proc/get_default_outfit_backpack() + var backpacks = decls_repository.get_decls_of_subtype(/decl/backpack_outfit) + for(var/backpack in backpacks) + var/decl/backpack_outfit/bo = backpacks[backpack] + if(bo.is_default) + return bo + +#undef BACKPACK_HAS_TYPE_SELECTION +#undef BACKPACK_HAS_SUBTYPE_SELECTION diff --git a/code/datums/outfits/horror_killers.dm b/code/datums/outfits/horror_killers.dm new file mode 100644 index 00000000..5b7eccd0 --- /dev/null +++ b/code/datums/outfits/horror_killers.dm @@ -0,0 +1,63 @@ +/decl/hierarchy/outfit/tunnel_clown + name = "Tunnel clown" + uniform = /obj/item/clothing/under/rank/clown + shoes = /obj/item/clothing/shoes/clown_shoes + gloves = /obj/item/clothing/gloves/thick + mask = /obj/item/clothing/mask/gas/clown_hat + head = /obj/item/clothing/head/chaplain_hood + l_ear = /obj/item/device/radio/headset + glasses = /obj/item/clothing/glasses/thermal/plain/monocle + suit = /obj/item/clothing/suit/chaplain_hoodie + r_pocket = /obj/item/weapon/bikehorn + r_hand = /obj/item/weapon/material/twohanded/fireaxe + + id_slot = slot_wear_id + id_type = /obj/item/weapon/card/id/centcom/station + id_pda_assignment = "Tunnel Clown!" + +/decl/hierarchy/outfit/masked_killer + name = "Masked killer" + uniform = /obj/item/clothing/under/overalls + shoes = /obj/item/clothing/shoes/white + gloves = /obj/item/clothing/gloves/latex + mask = /obj/item/clothing/mask/surgical + head = /obj/item/clothing/head/welding + l_ear = /obj/item/device/radio/headset + glasses = /obj/item/clothing/glasses/thermal/plain/monocle + suit = /obj/item/clothing/suit/apron + l_pocket = /obj/item/weapon/material/hatchet/tacknife + r_pocket = /obj/item/weapon/scalpel + r_hand = /obj/item/weapon/material/twohanded/fireaxe + +/decl/hierarchy/outfit/masked_killer/post_equip(var/mob/living/carbon/human/H) + ..() + var/victim = get_mannequin(H.ckey) + for(var/obj/item/carried_item in H.get_equipped_items(TRUE)) + carried_item.add_blood(victim) //Oh yes, there will be blood.. just not blood from the killer because that's odd + +/decl/hierarchy/outfit/reaper + name = "Reaper" + uniform = /obj/item/clothing/under/suit_jacket{ starting_accessories=list(/obj/item/clothing/accessory/wcoat) } + shoes = /obj/item/clothing/shoes/black + gloves = /obj/item/clothing/gloves/thick + l_ear = /obj/item/device/radio/headset + glasses = /obj/item/clothing/glasses/sunglasses + l_pocket = /obj/item/weapon/melee/energy/sword + + id_slot = slot_wear_id + id_type = /obj/item/weapon/card/id/syndicate/station_access + pda_slot = slot_belt + pda_type = /obj/item/device/pda/heads + +/decl/hierarchy/outfit/reaper/post_equip(var/mob/living/carbon/human/H) + ..() + var/obj/item/weapon/storage/secure/briefcase/sec_briefcase = new(H) + for(var/obj/item/briefcase_item in sec_briefcase) + qdel(briefcase_item) + for(var/i=3, i>0, i--) + sec_briefcase.contents += new /obj/item/weapon/spacecash/bundle/c1000 + sec_briefcase.contents += new /obj/item/weapon/gun/energy/crossbow + sec_briefcase.contents += new /obj/item/weapon/gun/projectile/revolver/mateba + sec_briefcase.contents += new /obj/item/ammo_magazine/c50 + sec_briefcase.contents += new /obj/item/weapon/plastique + H.equip_to_slot_or_del(sec_briefcase, slot_l_hand) diff --git a/code/datums/outfits/jobs/_defines.dm b/code/datums/outfits/jobs/_defines.dm new file mode 100644 index 00000000..86c75a84 --- /dev/null +++ b/code/datums/outfits/jobs/_defines.dm @@ -0,0 +1,31 @@ +#define OUTFIT_JOB_NAME(job_name) ("Job - " + job_name) + +#define BACKPACK_OVERRIDE_CHEMISTRY \ +backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/weapon/storage/backpack/chemistry; \ +backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/weapon/storage/backpack/satchel/satchel_chem; \ +backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/weapon/storage/backpack/messenger/chem; + +#define BACKPACK_OVERRIDE_ENGINEERING \ +backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/weapon/storage/backpack/industrial; \ +backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/weapon/storage/backpack/satchel/satchel_eng; \ +backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/weapon/storage/backpack/messenger/engi; + +#define BACKPACK_OVERRIDE_MEDICAL \ +backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/weapon/storage/backpack/medic; \ +backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/weapon/storage/backpack/satchel/satchel_med; \ +backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/weapon/storage/backpack/messenger/med; + +#define BACKPACK_OVERRIDE_RESEARCH \ +backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/weapon/storage/backpack/toxins; \ +backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/weapon/storage/backpack/satchel/satchel_tox; \ +backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/weapon/storage/backpack/messenger/viro; + +#define BACKPACK_OVERRIDE_SECURITY \ +backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/weapon/storage/backpack/security; \ +backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/weapon/storage/backpack/satchel/satchel_sec; \ +backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/weapon/storage/backpack/messenger/sec; + +#define BACKPACK_OVERRIDE_VIROLOGY \ +backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/weapon/storage/backpack/virology; \ +backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/weapon/storage/backpack/satchel/satchel_vir; \ +backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/weapon/storage/backpack/messenger/viro; diff --git a/code/datums/outfits/jobs/cargo.dm b/code/datums/outfits/jobs/cargo.dm new file mode 100644 index 00000000..5301382a --- /dev/null +++ b/code/datums/outfits/jobs/cargo.dm @@ -0,0 +1,50 @@ +/decl/hierarchy/outfit/job/cargo + l_ear = /obj/item/device/radio/headset/headset_cargo + hierarchy_type = /decl/hierarchy/outfit/job/cargo + +/decl/hierarchy/outfit/job/cargo/qm + name = OUTFIT_JOB_NAME("Cargo") + uniform = /obj/item/clothing/under/rank/cargo + shoes = /obj/item/clothing/shoes/brown + glasses = /obj/item/clothing/glasses/sunglasses + l_hand = /obj/item/weapon/clipboard + id_type = /obj/item/weapon/card/id/shared/cargo + pda_type = /obj/item/device/pda/quartermaster + +/decl/hierarchy/outfit/job/cargo/cargo_tech + name = OUTFIT_JOB_NAME("Cargo technician") + uniform = /obj/item/clothing/under/rank/cargotech + id_type = /obj/item/weapon/card/id/shared/cargo + pda_type = /obj/item/device/pda/cargo + +/decl/hierarchy/outfit/job/cargo/mining + name = OUTFIT_JOB_NAME("Shaft miner") + uniform = /obj/item/clothing/under/rank/miner + id_type = /obj/item/weapon/card/id/shared/cargo + pda_type = /obj/item/device/pda/shaftminer + backpack_contents = list(/obj/item/weapon/crowbar = 1, /obj/item/weapon/storage/ore = 1) + flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL + +/decl/hierarchy/outfit/job/cargo/mining/New() + ..() + BACKPACK_OVERRIDE_ENGINEERING + +/decl/hierarchy/outfit/job/cargo/mining/void + name = OUTFIT_JOB_NAME("Shaft miner - Voidsuit") + head = /obj/item/clothing/head/helmet/space/void/mining + mask = /obj/item/clothing/mask/breath + suit = /obj/item/clothing/suit/space/void/mining + + +/decl/hierarchy/outfit/job/cargo/mining/explorer + name = OUTFIT_JOB_NAME("Salvage Miner") + head = /obj/item/clothing/head/helmet/hard_had + mask = /obj/item/clothing/mask/gas/explorer + uniform = /obj/item/clothing/under/rank/explorer + back = /obj/item/weapon/storage/backpack/industrial + suit = /obj/item/clothing/suit/armor/vest/warden/explorer + gloves = /obj/item/clothing/gloves/thick/swat/combat + shoes = /obj/item/clothing/shoes/jackboots + r_pocket = /obj/item/ammo_box/rifle + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty/leverchester + backpack_contents = list(/obj/item/weapon/crowbar = 1, /obj/item/weapon/storage/ore = 1) diff --git a/code/datums/outfits/jobs/civilian.dm b/code/datums/outfits/jobs/civilian.dm new file mode 100644 index 00000000..0835528d --- /dev/null +++ b/code/datums/outfits/jobs/civilian.dm @@ -0,0 +1,65 @@ +/decl/hierarchy/outfit/job/assistant + name = OUTFIT_JOB_NAME("Assistant") + +/decl/hierarchy/outfit/job/service + l_ear = /obj/item/device/radio/headset/headset_service + hierarchy_type = /decl/hierarchy/outfit/job/service + +/decl/hierarchy/outfit/job/service/bartender + name = OUTFIT_JOB_NAME("Bartender") + uniform = /obj/item/clothing/under/rank/bartender + id_type = /obj/item/weapon/card/id/civilian/bartender + pda_type = /obj/item/device/pda/bar + +/decl/hierarchy/outfit/job/service/chef + name = OUTFIT_JOB_NAME("Chef") + uniform = /obj/item/clothing/under/rank/chef + suit = /obj/item/clothing/suit/chef + head = /obj/item/clothing/head/chefhat + id_type = /obj/item/weapon/card/id/civilian/chef + pda_type = /obj/item/device/pda/chef + +/decl/hierarchy/outfit/job/service/gardener + name = OUTFIT_JOB_NAME("Gardener") + uniform = /obj/item/clothing/under/rank/hydroponics + suit = /obj/item/clothing/suit/apron + gloves = /obj/item/clothing/gloves/thick/botany + r_pocket = /obj/item/device/analyzer/plant_analyzer + id_type = /obj/item/weapon/card/id/civilian/botanist + pda_type = /obj/item/device/pda/botanist + +/decl/hierarchy/outfit/job/service/gardener/New() + ..() + backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/weapon/storage/backpack/hydroponics + backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/weapon/storage/backpack/satchel/satchel_hyd + backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/weapon/storage/backpack/messenger/hyd + +/decl/hierarchy/outfit/job/service/janitor + name = OUTFIT_JOB_NAME("Janitor") + uniform = /obj/item/clothing/under/rank/janitor + id_type = /obj/item/weapon/card/id/civilian/janitor + pda_type = /obj/item/device/pda/janitor + +/decl/hierarchy/outfit/job/librarian + name = OUTFIT_JOB_NAME("Librarian") + uniform = /obj/item/clothing/under/suit_jacket/red + id_type = /obj/item/weapon/card/id/civilian/librarian + pda_type = /obj/item/device/pda/librarian + +/decl/hierarchy/outfit/job/internal_affairs_agent + name = OUTFIT_JOB_NAME("Internal affairs agent") + l_ear = /obj/item/device/radio/headset/ia + uniform = /obj/item/clothing/under/rank/internalaffairs + suit = /obj/item/clothing/suit/storage/toggle/suit/black + shoes = /obj/item/clothing/shoes/brown + glasses = /obj/item/clothing/glasses/sunglasses/big + l_hand = /obj/item/weapon/storage/briefcase + id_type = /obj/item/weapon/card/id/civilian/internal_affairs_agent + pda_type = /obj/item/device/pda/lawyer + +/decl/hierarchy/outfit/job/chaplain + name = OUTFIT_JOB_NAME("Chaplain") + uniform = /obj/item/clothing/under/rank/chaplain + l_hand = /obj/item/weapon/storage/bible + id_type = /obj/item/weapon/card/id/civilian/chaplain + pda_type = /obj/item/device/pda/chaplain diff --git a/code/datums/outfits/jobs/command.dm b/code/datums/outfits/jobs/command.dm new file mode 100644 index 00000000..72cc75cb --- /dev/null +++ b/code/datums/outfits/jobs/command.dm @@ -0,0 +1,39 @@ +/decl/hierarchy/outfit/job/captain + name = OUTFIT_JOB_NAME("Captain") + head = /obj/item/clothing/head/caphat/cap + glasses = /obj/item/clothing/glasses/sunglasses + uniform = /obj/item/clothing/under/rank/captain + l_ear = /obj/item/device/radio/headset/heads/captain + shoes = /obj/item/clothing/shoes/brown + id_type = /obj/item/weapon/card/id/gold + pda_type = /obj/item/device/pda/captain + backpack_contents = list(/obj/item/weapon/storage/box/ids = 1) + +/decl/hierarchy/outfit/job/captain/New() + ..() + backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/weapon/storage/backpack/captain + backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/weapon/storage/backpack/satchel/satchel_cap + backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/weapon/storage/backpack/messenger/com + +/decl/hierarchy/outfit/job/captain/post_equip(var/mob/living/carbon/human/H) + ..() + if(H.age>49) + // Since we can have something other than the default uniform at this + // point, check if we can actually attach the medal + var/obj/item/clothing/uniform = H.w_uniform + if(uniform) + var/obj/item/clothing/accessory/medal/gold/nanotrasen/medal = new() + if(uniform.can_attach_accessory(medal)) + uniform.attach_accessory(null, medal) + else + qdel(medal) + +/decl/hierarchy/outfit/job/hop + name = OUTFIT_JOB_NAME("Head of Personnel") + uniform = /obj/item/clothing/under/rank/head_of_personnel_whimsy + head = /obj/item/clothing/head/caphat/hop + l_ear = /obj/item/device/radio/headset/heads/hop + shoes = /obj/item/clothing/shoes/brown + id_type = /obj/item/weapon/card/id/silver + pda_type = /obj/item/device/pda/heads/hop + backpack_contents = list(/obj/item/weapon/storage/box/ids = 1) diff --git a/code/datums/outfits/jobs/engineering.dm b/code/datums/outfits/jobs/engineering.dm new file mode 100644 index 00000000..da31e661 --- /dev/null +++ b/code/datums/outfits/jobs/engineering.dm @@ -0,0 +1,41 @@ +/decl/hierarchy/outfit/job/engineering + hierarchy_type = /decl/hierarchy/outfit/job/engineering + belt = /obj/item/weapon/storage/belt/utility/full + l_ear = /obj/item/device/radio/headset/headset_eng + shoes = /obj/item/clothing/shoes/workboots + //pda_slot = slot_l_store + flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL + +/decl/hierarchy/outfit/job/engineering/New() + ..() + BACKPACK_OVERRIDE_ENGINEERING + +/decl/hierarchy/outfit/job/engineering/chief_engineer + name = OUTFIT_JOB_NAME("Chief engineer") + head = /obj/item/clothing/head/hardhat/white + uniform = /obj/item/clothing/under/rank/chief_engineer + l_ear = /obj/item/device/radio/headset/heads/ce + gloves = /obj/item/clothing/gloves/thick + id_type = /obj/item/weapon/card/id/engineering/head + pda_type = /obj/item/device/pda/heads/ce + +/decl/hierarchy/outfit/job/engineering/engineer + name = OUTFIT_JOB_NAME("Engineer") + head = /obj/item/clothing/head/hardhat + uniform = /obj/item/clothing/under/rank/engineer + r_pocket = /obj/item/device/t_scanner + id_type = /obj/item/weapon/card/id/engineering + pda_type = /obj/item/device/pda/engineering + +/decl/hierarchy/outfit/job/engineering/engineer/void + name = OUTFIT_JOB_NAME("Engineer - Voidsuit") + head = /obj/item/clothing/head/helmet/space/void/engineering + mask = /obj/item/clothing/mask/breath + suit = /obj/item/clothing/suit/space/void/engineering + +/decl/hierarchy/outfit/job/engineering/atmos + name = OUTFIT_JOB_NAME("Atmospheric technician") + uniform = /obj/item/clothing/under/rank/atmospheric_technician + belt = /obj/item/weapon/storage/belt/utility/atmostech + id_type = /obj/item/weapon/card/id/engineering/atmos + pda_type = /obj/item/device/pda/atmos diff --git a/code/datums/outfits/jobs/job.dm b/code/datums/outfits/jobs/job.dm new file mode 100644 index 00000000..f9fd83cd --- /dev/null +++ b/code/datums/outfits/jobs/job.dm @@ -0,0 +1,21 @@ +/decl/hierarchy/outfit/job + name = "Standard Gear" + hierarchy_type = /decl/hierarchy/outfit/job + + uniform = /obj/item/clothing/under/color/grey + l_ear = /obj/item/device/radio/headset + shoes = /obj/item/clothing/shoes/black + + id_slot = slot_wear_id + id_type = /obj/item/weapon/card/id/civilian + pda_slot = slot_wear_id + pda_type = /obj/item/device/pda + + flags = OUTFIT_HAS_BACKPACK + +/decl/hierarchy/outfit/job/equip_id(mob/living/carbon/human/H) + var/obj/item/weapon/card/id/C = ..() + if(H.mind) + if(H.mind.initial_account) + C.associated_account_number = H.mind.initial_account.account_number + return C diff --git a/code/datums/outfits/jobs/medical.dm b/code/datums/outfits/jobs/medical.dm new file mode 100644 index 00000000..4869cb86 --- /dev/null +++ b/code/datums/outfits/jobs/medical.dm @@ -0,0 +1,111 @@ +/decl/hierarchy/outfit/job/medical + hierarchy_type = /decl/hierarchy/outfit/job/medical + l_ear = /obj/item/device/radio/headset/headset_med + shoes = /obj/item/clothing/shoes/white + pda_type = /obj/item/device/pda/medical + //pda_slot = slot_l_store + +/decl/hierarchy/outfit/job/medical/New() + ..() + BACKPACK_OVERRIDE_MEDICAL + +/decl/hierarchy/outfit/job/medical/cmo + name = OUTFIT_JOB_NAME("Chief Medical Officer") + l_ear =/obj/item/device/radio/headset/heads/cmo + uniform = /obj/item/clothing/under/rank/medical + suit = /obj/item/clothing/suit/storage/toggle/labcoat + shoes = /obj/item/clothing/shoes/brown + l_hand = /obj/item/weapon/storage/firstaid/adv + r_pocket = /obj/item/device/flashlight/pen + id_type = /obj/item/weapon/card/id/medical/head + +/decl/hierarchy/outfit/job/medical/doctor + name = OUTFIT_JOB_NAME("Medical Doctor") + uniform = /obj/item/clothing/under/rank/medical + suit = /obj/item/clothing/suit/storage/doctor_vest + l_hand = /obj/item/weapon/storage/firstaid/adv + r_pocket = /obj/item/device/flashlight/pen + id_type = /obj/item/weapon/card/id/medical + +/decl/hierarchy/outfit/job/medical/doctor/emergency_physician + name = OUTFIT_JOB_NAME("Emergency physician") + suit = /obj/item/clothing/suit/storage/toggle/fr_jacket + +/decl/hierarchy/outfit/job/medical/doctor/surgeon + name = OUTFIT_JOB_NAME("Surgeon") + uniform = /obj/item/clothing/under/rank/medical/scrubs/blue + head = /obj/item/clothing/head/surgery/blue + +/decl/hierarchy/outfit/job/medical/doctor/virologist + name = OUTFIT_JOB_NAME("Virologist") + uniform = /obj/item/clothing/under/rank/virologist + suit = /obj/item/clothing/suit/storage/toggle/labcoat/virologist + mask = /obj/item/clothing/mask/surgical +/decl/hierarchy/outfit/job/medical/doctor/virologist/New() + ..() + BACKPACK_OVERRIDE_VIROLOGY + +/decl/hierarchy/outfit/job/medical/doctor/nurse + name = OUTFIT_JOB_NAME("Nurse") + suit = null + +/decl/hierarchy/outfit/job/medical/doctor/nurse/pre_equip(mob/living/carbon/human/H) + ..() + if(H.gender == FEMALE) + if(prob(50)) + uniform = /obj/item/clothing/under/rank/nursesuit + else + uniform = /obj/item/clothing/under/rank/nurse + head = /obj/item/clothing/head/nursehat + else + uniform = /obj/item/clothing/under/rank/medical/scrubs/purple + head = null + +/decl/hierarchy/outfit/job/medical/chemist + name = OUTFIT_JOB_NAME("Chemist") + uniform = /obj/item/clothing/under/rank/medical/scrubs/black + suit = /obj/item/clothing/suit/storage/toggle/labcoat/chemist + id_type = /obj/item/weapon/card/id/medical/chemist + pda_type = /obj/item/device/pda/chemist + +/decl/hierarchy/outfit/job/medical/chemist/New() + ..() + BACKPACK_OVERRIDE_VIROLOGY + +/decl/hierarchy/outfit/job/medical/geneticist + name = OUTFIT_JOB_NAME("Geneticist") + uniform = /obj/item/clothing/under/rank/geneticist + suit = /obj/item/clothing/suit/storage/toggle/labcoat/genetics + r_pocket = /obj/item/device/flashlight/pen + id_type = /obj/item/weapon/card/id/medical/geneticist + pda_type = /obj/item/device/pda/geneticist + +/decl/hierarchy/outfit/job/medical/geneticist/New() + ..() + backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/weapon/storage/backpack/genetics + backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/weapon/storage/backpack/satchel/satchel_gen + +/decl/hierarchy/outfit/job/medical/psychiatrist + name = OUTFIT_JOB_NAME("Psychiatrist") + uniform = /obj/item/clothing/under/rank/psych + suit = /obj/item/clothing/suit/storage/toggle/labcoat + shoes = /obj/item/clothing/shoes/laceup + id_type = /obj/item/weapon/card/id/medical/psychiatrist + +/decl/hierarchy/outfit/job/medical/psychiatrist/psychologist + name = OUTFIT_JOB_NAME("Psychologist") + uniform = /obj/item/clothing/under/rank/psych/turtleneck + +/decl/hierarchy/outfit/job/medical/paramedic + name = OUTFIT_JOB_NAME("Paramedic") + uniform = /obj/item/clothing/under/rank/medical/scrubs/black + suit = /obj/item/clothing/suit/storage/toggle/fr_jacket + shoes = /obj/item/clothing/shoes/jackboots + l_hand = /obj/item/weapon/storage/firstaid/adv + belt = /obj/item/weapon/storage/belt/medical/emt + id_type = /obj/item/weapon/card/id/medical/paramedic + flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL + +/decl/hierarchy/outfit/job/medical/paramedic/emt + name = OUTFIT_JOB_NAME("Emergency medical technician") + uniform = /obj/item/clothing/under/rank/medical/paramedic diff --git a/code/datums/outfits/jobs/misc.dm b/code/datums/outfits/jobs/misc.dm new file mode 100644 index 00000000..43bbd919 --- /dev/null +++ b/code/datums/outfits/jobs/misc.dm @@ -0,0 +1,11 @@ +/decl/hierarchy/outfit/job/silicon + head = /obj/item/clothing/head/cardborg + hierarchy_type = /decl/hierarchy/outfit/job/silicon + +/decl/hierarchy/outfit/job/silicon/ai + name = OUTFIT_JOB_NAME("AI") + suit = /obj/item/clothing/suit/straight_jacket + +/decl/hierarchy/outfit/job/silicon/cyborg + name = OUTFIT_JOB_NAME("Cyborg") + suit = /obj/item/clothing/suit/cardborg diff --git a/code/datums/outfits/jobs/science.dm b/code/datums/outfits/jobs/science.dm new file mode 100644 index 00000000..5e50dae5 --- /dev/null +++ b/code/datums/outfits/jobs/science.dm @@ -0,0 +1,43 @@ +/decl/hierarchy/outfit/job/science + hierarchy_type = /decl/hierarchy/outfit/job/science + l_ear = /obj/item/device/radio/headset/headset_sci + suit = /obj/item/clothing/suit/storage/toggle/labcoat + shoes = /obj/item/clothing/shoes/white + pda_type = /obj/item/device/pda/science + +/decl/hierarchy/outfit/job/science/New() + ..() + BACKPACK_OVERRIDE_RESEARCH + +/decl/hierarchy/outfit/job/science/rd + name = OUTFIT_JOB_NAME("Research Director") + l_ear = /obj/item/device/radio/headset/heads/rd + uniform = /obj/item/clothing/under/rank/research_director + shoes = /obj/item/clothing/shoes/brown + id_type = /obj/item/weapon/card/id/science/head + pda_type = /obj/item/device/pda/heads/rd + +/decl/hierarchy/outfit/job/science/scientist + name = OUTFIT_JOB_NAME("Scientist") + uniform = /obj/item/clothing/under/rank/scientist + id_type = /obj/item/weapon/card/id/science + suit = /obj/item/clothing/suit/storage/toggle/labcoat/science + +/decl/hierarchy/outfit/job/science/xenobiologist + name = OUTFIT_JOB_NAME("Xenobiologist") + uniform = /obj/item/clothing/under/rank/scientist + id_type = /obj/item/weapon/card/id/science/xenobiologist + suit = /obj/item/clothing/suit/storage/toggle/labcoat/science + +/decl/hierarchy/outfit/job/science/roboticist + name = OUTFIT_JOB_NAME("Roboticist") + uniform = /obj/item/clothing/under/rank/roboticist + shoes = /obj/item/clothing/shoes/black + belt = /obj/item/weapon/storage/belt/utility/full + id_type = /obj/item/weapon/card/id/science/roboticist + pda_slot = slot_r_store + pda_type = /obj/item/device/pda/roboticist + +/decl/hierarchy/outfit/job/science/roboticist/New() + ..() + backpack_overrides.Cut() diff --git a/code/datums/outfits/jobs/security.dm b/code/datums/outfits/jobs/security.dm new file mode 100644 index 00000000..6d74db97 --- /dev/null +++ b/code/datums/outfits/jobs/security.dm @@ -0,0 +1,57 @@ +/decl/hierarchy/outfit/job/security + hierarchy_type = /decl/hierarchy/outfit/job/security + glasses = /obj/item/clothing/glasses/sunglasses + l_ear = /obj/item/device/radio/headset/headset_sec + gloves = /obj/item/clothing/gloves/thick + shoes = /obj/item/clothing/shoes/jackboots + backpack_contents = list(/obj/item/weapon/handcuffs = 1) + +/decl/hierarchy/outfit/job/security/New() + ..() + BACKPACK_OVERRIDE_SECURITY + +/decl/hierarchy/outfit/job/security/hos + name = OUTFIT_JOB_NAME("Head of security") + l_ear = /obj/item/device/radio/headset/heads/hos + uniform = /obj/item/clothing/under/rank/head_of_security/jensen + suit = /obj/item/clothing/suit/armor/hos/jensen + head = /obj/item/clothing/head/beret/sec/corporate/hos + id_type = /obj/item/weapon/card/id/security/head + pda_type = /obj/item/device/pda/heads/hos + backpack_contents = list(/obj/item/weapon/handcuffs = 1) + +/decl/hierarchy/outfit/job/security/warden + name = OUTFIT_JOB_NAME("Warden") + uniform = /obj/item/clothing/under/rank/warden/corp + l_pocket = /obj/item/device/flash + id_type = /obj/item/weapon/card/id/security/warden + pda_type = /obj/item/device/pda/warden + +/decl/hierarchy/outfit/job/security/detective + name = OUTFIT_JOB_NAME("Detective") + head = /obj/item/clothing/head/det/grey + uniform = /obj/item/clothing/under/det/black + suit = /obj/item/clothing/suit/storage/det_trench/grey + l_pocket = /obj/item/weapon/flame/lighter/zippo + shoes = /obj/item/clothing/shoes/laceup + r_hand = /obj/item/weapon/storage/briefcase/crimekit + id_type = /obj/item/weapon/card/id/security/detective + pda_type = /obj/item/device/pda/detective + backpack_contents = list(/obj/item/weapon/storage/box/evidence = 1) + +/decl/hierarchy/outfit/job/security/detective/New() + ..() + backpack_overrides.Cut() + +/decl/hierarchy/outfit/job/security/detective/forensic + name = OUTFIT_JOB_NAME("Forensic technician") + head = null + suit = /obj/item/clothing/suit/storage/forensics/blue + +/decl/hierarchy/outfit/job/security/officer + name = OUTFIT_JOB_NAME("Security Officer") + uniform = /obj/item/clothing/under/rank/security/corp + l_pocket = /obj/item/device/flash + r_pocket = /obj/item/weapon/handcuffs + id_type = /obj/item/weapon/card/id/security + pda_type = /obj/item/device/pda/security diff --git a/code/datums/outfits/misc.dm b/code/datums/outfits/misc.dm new file mode 100644 index 00000000..d9d75081 --- /dev/null +++ b/code/datums/outfits/misc.dm @@ -0,0 +1,59 @@ +/decl/hierarchy/outfit/standard_space_gear + name = "Standard space gear" + shoes = /obj/item/clothing/shoes/black + head = /obj/item/clothing/head/helmet/space + suit = /obj/item/clothing/suit/space + uniform = /obj/item/clothing/under/color/grey + back = /obj/item/weapon/tank/jetpack/oxygen + mask = /obj/item/clothing/mask/breath + flags = OUTFIT_HAS_JETPACK|OUTFIT_RESET_EQUIPMENT + +/decl/hierarchy/outfit/soviet_soldier + name = "Soviet soldier" + uniform = /obj/item/clothing/under/soviet + shoes = /obj/item/clothing/shoes/combat + head = /obj/item/clothing/head/ushanka + gloves = /obj/item/clothing/gloves/thick/combat + back = /obj/item/weapon/storage/backpack/satchel + belt = /obj/item/weapon/gun/projectile/revolver/mateba + +/decl/hierarchy/outfit/soviet_soldier/admiral + name = "Soviet admiral" + head = /obj/item/clothing/head/hgpiratecap + l_ear = /obj/item/device/radio/headset/heads/captain + glasses = /obj/item/clothing/glasses/thermal/plain/eyepatch + suit = /obj/item/clothing/suit/hgpirate + + id_slot = slot_wear_id + id_type = /obj/item/weapon/card/id/centcom/station + id_pda_assignment = "Admiral" + +/decl/hierarchy/outfit/merchant + name = "Merchant" + shoes = /obj/item/clothing/shoes/black + l_ear = /obj/item/device/radio/headset + uniform = /obj/item/clothing/under/color/grey + id_slot = slot_wear_id + id_type = /obj/item/weapon/card/id/merchant + pda_slot = slot_r_store + pda_type = /obj/item/device/pda/chef //cause I like the look + id_pda_assignment = "Merchant" + +/decl/hierarchy/outfit/merchant/vox + name = "Merchant - Vox" + shoes = /obj/item/clothing/shoes/jackboots/unathi + uniform = /obj/item/clothing/under/vox/vox_robes + suit = /obj/item/clothing/suit/armor/vox_scrap + +/decl/hierarchy/outfit/clown + name = "Clown" + shoes = /obj/item/clothing/shoes/clown_shoes + mask = /obj/item/clothing/mask/gas/clown_hat + l_ear = /obj/item/device/radio/headset + uniform = /obj/item/clothing/under/rank/clown + l_pocket = /obj/item/weapon/bikehorn + flags = OUTFIT_HAS_BACKPACK|OUTFIT_RESET_EQUIPMENT + +/decl/hierarchy/outfit/clown/New() + ..() + backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/weapon/storage/backpack/clown diff --git a/code/datums/outfits/nanotrasen.dm b/code/datums/outfits/nanotrasen.dm new file mode 100644 index 00000000..efc85c9d --- /dev/null +++ b/code/datums/outfits/nanotrasen.dm @@ -0,0 +1,45 @@ +/decl/hierarchy/outfit/nanotrasen + hierarchy_type = /decl/hierarchy/outfit/nanotrasen + uniform = /obj/item/clothing/under/rank/centcom + shoes = /obj/item/clothing/shoes/laceup + gloves = /obj/item/clothing/gloves/white + l_ear = /obj/item/device/radio/headset/heads/hop + glasses = /obj/item/clothing/glasses/sunglasses + + id_slot = slot_wear_id + id_type = /obj/item/weapon/card/id/centcom/station + pda_slot = slot_r_store + pda_type = /obj/item/device/pda/heads + +/decl/hierarchy/outfit/nanotrasen/representative + name = "NanoTrasen Representative" + belt = /obj/item/weapon/clipboard + id_pda_assignment = "NanoTrasen Navy Representative" + +/decl/hierarchy/outfit/nanotrasen/officer + name = "NanoTrasen Officer" + head = /obj/item/clothing/head/beret/centcom/officer + l_ear = /obj/item/device/radio/headset/heads/captain + belt = /obj/item/weapon/gun/energy + id_pda_assignment = "NanoTrasen Navy Officer" + +/decl/hierarchy/outfit/nanotrasen/captain + name = "NanoTrasen Captain" + uniform = /obj/item/clothing/under/rank/centcom_captain + l_ear = /obj/item/device/radio/headset/heads/captain + head = /obj/item/clothing/head/beret/centcom/captain + belt = /obj/item/weapon/gun/energy + id_pda_assignment = "NanoTrasen Navy Captain" + +/decl/hierarchy/outfit/nanotrasen/commander + name = "NanoTrasen Commander" + head = /obj/item/clothing/head/centhat + mask = /obj/item/clothing/mask/smokable/cigarette/cigar/cohiba + shoes = /obj/item/clothing/shoes/swat + uniform = /obj/item/clothing/under/rank/centcom_captain + suit = /obj/item/clothing/suit/armor/bulletproof + gloves = /obj/item/clothing/gloves/thick/swat + l_ear = /obj/item/device/radio/headset/heads/captain + glasses = /obj/item/clothing/glasses/eyepatch + l_pocket = /obj/item/weapon/flame/lighter/zippo + id_pda_assignment = "NanoTrasen Commander" diff --git a/code/datums/outfits/outfit.dm b/code/datums/outfits/outfit.dm new file mode 100644 index 00000000..6e44e7c6 --- /dev/null +++ b/code/datums/outfits/outfit.dm @@ -0,0 +1,235 @@ +var/list/outfits_decls_ +var/list/outfits_decls_root_ +var/list/outfits_decls_by_type_ + +/proc/outfit_by_type(var/outfit_type) + if(!outfits_decls_root_) + init_outfit_decls() + return outfits_decls_by_type_[outfit_type] + +/proc/outfits() + if(!outfits_decls_root_) + init_outfit_decls() + return outfits_decls_ + +/proc/init_outfit_decls() + if(outfits_decls_root_) + return + outfits_decls_ = list() + outfits_decls_by_type_ = list() + outfits_decls_root_ = new/decl/hierarchy/outfit() + +/decl/hierarchy/outfit + name = "Naked" + + var/uniform = null + var/suit = null + var/back = null + var/belt = null + var/gloves = null + var/shoes = null + var/head = null + var/mask = null + var/l_ear = null + var/r_ear = null + var/glasses = null + var/id = null + var/l_pocket = null + var/r_pocket = null + var/suit_store = null + var/r_hand = null + var/l_hand = null + var/neck = null + var/list/backpack_contents = list() // In the list(path=count,otherpath=count) format + + var/id_type + var/id_desc + var/id_slot + + var/pda_type + var/pda_slot + + var/id_pda_assignment + + var/list/backpack_overrides + var/flags = OUTFIT_RESET_EQUIPMENT + +/decl/hierarchy/outfit/New() + ..() + backpack_overrides = backpack_overrides || list() + + if(is_hidden_category()) + return + outfits_decls_by_type_[type] = src + dd_insertObjectList(outfits_decls_, src) + +/decl/hierarchy/outfit/proc/pre_equip(mob/living/carbon/human/H) + if(flags & OUTFIT_RESET_EQUIPMENT) + H.delete_inventory(TRUE) + +/decl/hierarchy/outfit/proc/post_equip(mob/living/carbon/human/H) + if(flags & OUTFIT_HAS_JETPACK) + var/obj/item/weapon/tank/jetpack/J = locate(/obj/item/weapon/tank/jetpack) in H + if(!J) + return + J.toggle() + J.toggle_valve() + +// A proc for non-human species, specially Unathi and Tajara, since they e.g. +// can't normally wear gloves as humans. Correct this issue by trying again, but +// apply some changes to the said item. +// +// Currently checks for gloves +// +// If you want to add more items that has species restriction, consider follow- +// ing the same format as the gloves shown in the code below. Thanks. +/decl/hierarchy/outfit/proc/check_and_try_equip_xeno(mob/living/carbon/human/H) + var/datum/species/S = H.species + if (!S || istype(S, /datum/species/human)) // null failcheck & get out here you damn humans + return + + // Gloves + if (gloves && !H.get_equipped_item(slot_gloves)) // does mob not have gloves, despite the outfit has one specified? + var/obj/item/clothing/gloves/G = new gloves(H) // we've no use of a null object, instantize one + if (S.get_bodytype(H) in G.species_restricted) // what was the problem? + if ("exclude" in G.species_restricted) // are they excluded? + G.cut_fingertops() + // I could optimize this bit when we are trying to apply the gloves to e.g. Vox, a species still restricted despite G.cut_fingertops(). But who cares if this is codebase is like a plate of spaghetti twice over the brim, right? RIGHT? + H.equip_to_slot_or_del(G,slot_gloves) // try again + else + qdel(G) + // end Gloves + +// end of check_and_try_equip_xeno + +/decl/hierarchy/outfit/proc/equip(mob/living/carbon/human/H, var/rank, var/assignment, var/equip_adjustments) + equip_base(H, equip_adjustments) + + rank = id_pda_assignment || rank + assignment = id_pda_assignment || assignment || rank + var/obj/item/weapon/card/id/W = equip_id(H, rank, assignment, equip_adjustments) + if(W) + rank = W.rank + assignment = W.assignment + equip_pda(H, rank, assignment, equip_adjustments) + + for(var/path in backpack_contents) + var/number = backpack_contents[path] + for(var/i=0,ireagents[r_r]) + . = 0 + else + return -1 + if ((reagents?(reagents.len):(0)) < avail_reagents.reagent_list.len) + return 0 + return . + +/datum/recipe/proc/check_fruit(var/obj/container) + . = 1 + if(fruit && fruit.len) + var/list/checklist = list() + // You should trust Copy(). + checklist = fruit.Copy() + for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in container) + if(!G.seed || !G.seed.kitchen_tag || isnull(checklist[G.seed.kitchen_tag])) + continue + checklist[G.seed.kitchen_tag]-- + for(var/ktag in checklist) + if(!isnull(checklist[ktag])) + if(checklist[ktag] < 0) + . = 0 + else if(checklist[ktag] > 0) + . = -1 + break + return . + +/datum/recipe/proc/check_items(var/obj/container as obj) + . = 1 + if (items && items.len) + var/list/checklist = list() + checklist = items.Copy() // You should really trust Copy + for(var/obj/O in container.InsertedContents()) + if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/grown)) + continue // Fruit is handled in check_fruit(). + var/found = 0 + for(var/i = 1; i < checklist.len+1; i++) + var/item_type = checklist[i] + if (istype(O,item_type)) + checklist.Cut(i, i+1) + found = 1 + break + if (!found) + . = 0 + if (checklist.len) + . = -1 + return . + +//general version +/datum/recipe/proc/make(var/obj/container as obj) + var/obj/result_obj = new result(container) + for (var/obj/O in (container.InsertedContents()-result_obj)) + O.reagents.trans_to_obj(result_obj, O.reagents.total_volume) + qdel(O) + container.reagents.clear_reagents() + return result_obj + +// food-related +/datum/recipe/proc/make_food(var/obj/container as obj) + if(!result) + log_error("Recipe [type] is defined without a result, please bug this.") + + return + var/obj/result_obj = new result(container) + for (var/obj/O in (container.InsertedContents()-result_obj)) + if (O.reagents) + O.reagents.del_reagent(/datum/reagent/nutriment) + O.reagents.update_total() + O.reagents.trans_to_obj(result_obj, O.reagents.total_volume) + if(istype(O,/obj/item/weapon/holder/)) + var/obj/item/weapon/holder/H = O + H.destroy_all() + qdel(O) + container.reagents.clear_reagents() + return result_obj + +/proc/select_recipe(var/list/datum/recipe/avaiable_recipes, var/obj/obj as obj, var/exact) + var/list/datum/recipe/possible_recipes = new + var/target = exact ? 0 : 1 + for (var/datum/recipe/recipe in avaiable_recipes) + if((recipe.check_reagents(obj.reagents) < target) || (recipe.check_items(obj) < target) || (recipe.check_fruit(obj) < target)) + continue + possible_recipes |= recipe + if (possible_recipes.len==0) + return null + else if (possible_recipes.len==1) + return possible_recipes[1] + else //okay, let's select the most complicated recipe + var/highest_count = 0 + . = possible_recipes[1] + for (var/datum/recipe/recipe in possible_recipes) + var/count = ((recipe.items)?(recipe.items.len):0) + ((recipe.reagents)?(recipe.reagents.len):0) + ((recipe.fruit)?(recipe.fruit.len):0) + if (count >= highest_count) + highest_count = count + . = recipe + return . diff --git a/code/datums/repositories/_defines.dm b/code/datums/repositories/_defines.dm new file mode 100644 index 00000000..cf333007 --- /dev/null +++ b/code/datums/repositories/_defines.dm @@ -0,0 +1 @@ +#define mob2unique(mob) "[mob ? mob.ckey : NO_CLIENT_CKEY][ascii2text(7)][mob ? (mob.real_name ? mob.real_name : mob.name) : ""][ascii2text(7)][any2ref(mob)]" diff --git a/code/datums/repositories/admin_pm.dm b/code/datums/repositories/admin_pm.dm new file mode 100644 index 00000000..f4900b12 --- /dev/null +++ b/code/datums/repositories/admin_pm.dm @@ -0,0 +1,44 @@ +var/repository/admin_pm/admin_pm_repository = new() + +/repository/admin_pm + var/list/admin_pms_ + var/list/irc_clients_by_name + +/repository/admin_pm/New() + ..() + admin_pms_ = list() + irc_clients_by_name = list() + +/repository/admin_pm/proc/store_pm(var/client/sender, var/client/receiver, var/message) + if(receiver) + if(istype(receiver)) + receiver = client_repository.get_lite_client(receiver) + else if(starts_with(receiver, "IRC-")) + receiver = get_irc_client(receiver) + else + CRASH("Invalid receiver: [log_info_line(receiver)]") + + // Newest messages first + admin_pms_.Insert(1, new/datum/admin_privat_message(client_repository.get_lite_client(sender), receiver, message)) + +/repository/admin_pm/proc/get_irc_client(key) + var/datum/client_lite/cl = irc_clients_by_name[key] + if(!cl) + cl = new/datum/client_lite() + cl.name = "IRC" + cl.key = key + irc_clients_by_name[key] = cl + return cl + +/datum/admin_privat_message + var/station_time + var/datum/client_lite/sender // We don't store the proper client because it gets deleted if banned + var/datum/client_lite/receiver + var/message + +/datum/admin_privat_message/New(var/sender, var/receiver, var/message) + station_time = time_stamp() + src.message = message + src.sender = sender + src.receiver = receiver + diff --git a/code/datums/repositories/areas.dm b/code/datums/repositories/areas.dm new file mode 100644 index 00000000..5e9610b5 --- /dev/null +++ b/code/datums/repositories/areas.dm @@ -0,0 +1,53 @@ +/var/repository/area/area_repository = new() + +/repository/area + var/list/by_name_coords_cache_data + var/list/by_name_cache_data + var/list/by_z_level_cache_data + +/repository/area/New() + by_name_coords_cache_data = list() + by_name_cache_data = list() + by_z_level_cache_data = list() + ..() + +/repository/area/proc/get_areas_by_name(var/list/area_predicates = /proc/is_not_space_area) + return priv_get_cached_areas(by_name_cache_data, /proc/group_areas_by_z_level, area_predicates, /proc/get_name) + +/repository/area/proc/get_areas_by_name_and_coords(var/list/area_predicates = /proc/is_not_space_area) + return priv_get_cached_areas(by_name_coords_cache_data, /proc/group_areas_by_z_level, area_predicates, /proc/get_name_and_coordinates) + +/repository/area/proc/get_areas_by_z_level(var/list/area_predicates = /proc/is_not_space_area) + return priv_get_cached_areas(by_z_level_cache_data, /proc/group_areas_by_z_level, area_predicates, /proc/get_name_and_coordinates) + +/repository/area/proc/priv_get_cached_areas(var/list/area_cache, var/area_group_proc, var/list/area_predicates, var/naming_proc) + . = get_cache_entry(area_cache, area_predicates) + if(.) + return + . = priv_get_areas_by_proc(area_group_proc, area_predicates, naming_proc) + set_cache_entry(area_cache, area_predicates, .) + +/repository/area/proc/priv_get_areas_by_proc(var/area_group_proc, var/list/area_predicates, var/naming_proc) + var/list/grouped_areas = call(area_group_proc)(area_predicates) + grouped_areas = sortAssoc(grouped_areas) + . = list() + for(var/area_key in grouped_areas) + var/list/list_of_areas = grouped_areas[area_key] + list_of_areas = sortAtom(list_of_areas) + for(var/area/A in list_of_areas) + if(A.has_turfs()) + .[call(naming_proc)(A)] = A + +/repository/area/proc/get_cache_entry(var/list/cache_data, var/key) + var/datum/cache_entry/cache_entry = cache_data[key] + if(!cache_entry) + cache_entry = new/datum/cache_entry + cache_data[key] = cache_entry + + if(world.time < cache_entry.timestamp) + return cache_entry.data + +/repository/area/proc/set_cache_entry(var/list/cache_data, var/key, var/data) + var/datum/cache_entry/cache_entry = cache_data[key] + cache_entry.timestamp = world.time + 3 MINUTES + cache_entry.data = data diff --git a/code/datums/repositories/attack_logs.dm b/code/datums/repositories/attack_logs.dm new file mode 100644 index 00000000..c6d7303d --- /dev/null +++ b/code/datums/repositories/attack_logs.dm @@ -0,0 +1,40 @@ +var/repository/attack_logs/attack_log_repository = new() + +/repository/attack_logs + var/list/attack_logs_ + +/repository/attack_logs/New() + ..() + attack_logs_ = list() + +/repository/attack_logs/proc/store_attack_log(var/mob/attacker, var/mob/victim, var/action_message) + // Newest logs first + attack_logs_.Insert(1, new/datum/attack_log(attacker, victim, action_message)) + +/datum/attack_log + var/station_time + var/intent + var/datum/mob_lite/attacker // We don't store the proper mob in case it gets deleted + var/datum/mob_lite/victim + var/turf/location // Turfs are forever + var/message + +/datum/attack_log/New(var/mob/mob_attacker, var/mob/mob_victim, var/action_message) + station_time = time_stamp() + + attacker = mob_repository.get_lite_mob(mob_attacker) + victim = mob_repository.get_lite_mob(mob_victim) + + if(mob_attacker && mob_victim) + message = "[attacker.name] [action_message] [victim.name]" + else if(mob_attacker) + message = "[attacker.name] [action_message]" + else + message = "[victim.name] [action_message]" + + intent = mob_attacker ? uppertext(mob_attacker.a_intent) : "N/A" + + if(mob_attacker) + location = get_turf(mob_attacker) + if(!location && mob_victim) + location = get_turf(mob_victim) diff --git a/code/datums/repositories/cameras.dm b/code/datums/repositories/cameras.dm new file mode 100644 index 00000000..e10c5567 --- /dev/null +++ b/code/datums/repositories/cameras.dm @@ -0,0 +1,35 @@ +var/repository/cameras/camera_repository = new() + +/proc/invalidateCameraCache() + camera_repository.networks.Cut() + camera_repository.invalidated = 1 + camera_repository.camera_cache_id = ++camera_repository.camera_cache_id + +/repository/cameras + var/list/networks + var/invalidated = 1 + var/camera_cache_id = 1 + +/repository/cameras/New() + networks = list() + ..() + +/repository/cameras/proc/cameras_in_network(var/network) + setup_cache() + var/list/network_list = networks[network] + return network_list + +/repository/cameras/proc/setup_cache() + if(!invalidated) + return + invalidated = 0 + + for(var/sc in cameranet.cameras) + var/obj/machinery/camera/C = sc + var/cam = C.nano_structure() + for(var/network in C.network) + if(!networks[network]) + ADD_SORTED(networks, network, /proc/cmp_text_asc) + networks[network] = list() + var/list/netlist = networks[network] + netlist[++netlist.len] = cam diff --git a/code/datums/repositories/client.dm b/code/datums/repositories/client.dm new file mode 100644 index 00000000..ebcdec0b --- /dev/null +++ b/code/datums/repositories/client.dm @@ -0,0 +1,61 @@ +var/const/NO_CLIENT_CKEY = "*no ckey*" + +var/repository/client/client_repository = new() + +/repository/client + var/list/clients_ + +/repository/client/New() + ..() + clients_ = list() + +// A lite client is unique per ckey and mob ref (save for ref conflicts.. oh well) +/repository/client/proc/get_lite_client(var/mob/M) + if(isclient(M)) + var/client/C = M // BYOND is supposed to ensure clients always have a mob + M = C.mob + . = clients_[mob2unique(M)] + if(!.) + . = new/datum/client_lite(M) + clients_[mob2unique(M)] = . + +/datum/client_lite + var/name = "*no mob*" + var/key = "*no key*" + var/ckey = NO_CLIENT_CKEY + var/ref // If ref is unset but ckey is set that means the client wasn't logged in at the time + +/datum/client_lite/New(var/mob/M) + if(!M) + return + + name = M.real_name ? M.real_name : M.name + key = M.key ? M.key : key + ckey = M.ckey ? M.ckey : ckey + ref = M.client ? any2ref(M.client) : ref + +/datum/client_lite/proc/key_name(var/pm_link = TRUE, var/check_if_offline = TRUE, var/datum/ticket/ticket = null) + if(!ref && ckey != NO_CLIENT_CKEY) + var/client/C = client_by_ckey(ckey) + if(C) + ref = any2ref(C) + + if(!ref) + if(ckey == NO_CLIENT_CKEY) + return "[key]/([name])" + else + return "[key]/([name]) (DC)" + if(check_if_offline && !client_by_ckey(ckey)) + return "[key]/([name]) (DC)" + return pm_link ? "[key]/([name])[rank2text()]" : "[key]/([name])" + +/datum/client_lite/proc/rank2text() + var/client/C = client_by_ckey(ckey) + if(!C || (C && !C.holder)) + return + return " \[[C.holder.rank]\]" + +/proc/client_by_ckey(ckey) + for(var/client/C) + if(C.ckey == ckey) + return C diff --git a/code/datums/repositories/crew/_defines.dm b/code/datums/repositories/crew/_defines.dm new file mode 100644 index 00000000..4c9ac009 --- /dev/null +++ b/code/datums/repositories/crew/_defines.dm @@ -0,0 +1,3 @@ +#define MOD_SUIT_SENSORS_NONE 0 +#define MOD_SUIT_SENSORS_HANDLED 1 +#define MOD_SUIT_SENSORS_REJECTED 2 diff --git a/code/datums/repositories/crew/binary.dm b/code/datums/repositories/crew/binary.dm new file mode 100644 index 00000000..b060d051 --- /dev/null +++ b/code/datums/repositories/crew/binary.dm @@ -0,0 +1,36 @@ +/********* + *Binary * +*********/ + +/crew_sensor_modifier/binary/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + crew_data["dead"] = H.stat > UNCONSCIOUS + return ..() + +/********** + *Jamming * +**********/ + +/crew_sensor_modifier/binary/jamming + priority = 5 + +/crew_sensor_modifier/binary/jamming/alive/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + crew_data["dead"] = FALSE + return MOD_SUIT_SENSORS_HANDLED + +/crew_sensor_modifier/binary/jamming/dead/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + crew_data["dead"] = TRUE + return MOD_SUIT_SENSORS_HANDLED + +/crew_sensor_modifier/binary/jamming/random + var/error_prob = 25 + +/crew_sensor_modifier/binary/jamming/random/moderate + error_prob = 50 + +/crew_sensor_modifier/binary/jamming/random/major + error_prob = 100 + +/crew_sensor_modifier/binary/jamming/random/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + . = ..() + if(prob(error_prob)) + crew_data["dead"] = pick(TRUE, FALSE) diff --git a/code/datums/repositories/crew/crew.dm b/code/datums/repositories/crew/crew.dm new file mode 100644 index 00000000..6029bb77 --- /dev/null +++ b/code/datums/repositories/crew/crew.dm @@ -0,0 +1,150 @@ +var/global/datum/repository/crew/crew_repository = new() + +/datum/repository/crew + var/list/cache_data + var/list/modifier_queues + var/list/modifier_queues_by_type + +/datum/repository/crew/New() + cache_data = list() + var/PriorityQueue/general_modifiers = new/PriorityQueue(/proc/cmp_crew_sensor_modifier) + var/PriorityQueue/binary_modifiers = new/PriorityQueue(/proc/cmp_crew_sensor_modifier) + var/PriorityQueue/vital_modifiers = new/PriorityQueue(/proc/cmp_crew_sensor_modifier) + var/PriorityQueue/tracking_modifiers = new/PriorityQueue(/proc/cmp_crew_sensor_modifier) + + general_modifiers.Enqueue(new/crew_sensor_modifier/general()) + binary_modifiers.Enqueue(new/crew_sensor_modifier/binary()) + vital_modifiers.Enqueue(new/crew_sensor_modifier/vital()) + tracking_modifiers.Enqueue(new/crew_sensor_modifier/tracking()) + + modifier_queues = list() + modifier_queues[general_modifiers] = 0 + modifier_queues[binary_modifiers] = SUIT_SENSOR_BINARY + modifier_queues[vital_modifiers] = SUIT_SENSOR_VITAL + modifier_queues[tracking_modifiers] = SUIT_SENSOR_TRACKING + + modifier_queues_by_type = list() + modifier_queues_by_type[/crew_sensor_modifier/general] = general_modifiers + modifier_queues_by_type[/crew_sensor_modifier/binary] = binary_modifiers + modifier_queues_by_type[/crew_sensor_modifier/vital] = vital_modifiers + modifier_queues_by_type[/crew_sensor_modifier/tracking] = tracking_modifiers + + ..() + +/datum/repository/crew/proc/health_data(var/z_level) + var/list/crewmembers = list() + if(!z_level) + return crewmembers + + var/datum/cache_entry/cache_entry = cache_data[num2text(z_level)] + if(!cache_entry) + cache_entry = new/datum/cache_entry + cache_data[num2text(z_level)] = cache_entry + + if(world.time < cache_entry.timestamp) + return cache_entry.data + + var/tracked = scan() + for(var/obj/item/clothing/under/C in tracked) + var/turf/pos = get_turf(C) + if(C.has_sensor && pos && pos.z == z_level && C.sensor_mode != SUIT_SENSOR_OFF) + if(istype(C.loc, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = C.loc + if(H.w_uniform != C) + continue + var/pressure = H.get_blood_pressure() + var/blood_result = H.get_blood_oxygenation() + if(blood_result > 110) + blood_result = "increased" + else if(blood_result < 90) + blood_result = "low" + else if(blood_result < 60) + blood_result = "extremely low" + else + blood_result = "normal" + pressure += " ([blood_result] oxygenation)" + + var/true_pulse = H.pulse() + var/pulse_span = "good" + switch(true_pulse) + if(PULSE_NONE) + pulse_span = "bad" + if(PULSE_SLOW) + pulse_span = "highlight" + if(PULSE_NORM) + pulse_span = "good" + if(PULSE_FAST) + pulse_span = "average" + if(PULSE_2FAST) + pulse_span = "bad" + if(PULSE_THREADY) + pulse_span = "bad" + + var/list/crewmemberData = list("sensor_type" = C.sensor_mode, "stat"= H.stat, "span" = pulse_span, "pulse"= H.get_pulse(1), "pressure"= pressure, "bodytemp" = H.bodytemperature - T0C, "area"="", "x"=-1, "y"=-1, "z"=-1, "ref" = "\ref[H]") + if(!(run_queues(H, C, pos, crewmemberData) & MOD_SUIT_SENSORS_REJECTED)) + crewmembers[++crewmembers.len] = crewmemberData + + crewmembers = sortByKey(crewmembers, "name") + cache_entry.timestamp = world.time + 5 SECONDS + cache_entry.data = crewmembers + + return crewmembers + +/datum/repository/crew/proc/scan() + var/list/tracked = list() + for(var/mob/living/carbon/human/H in SSmobs.mob_list) + if(istype(H.w_uniform, /obj/item/clothing/under)) + var/obj/item/clothing/under/C = H.w_uniform + if (C.has_sensor) + tracked |= C + return tracked + + +/datum/repository/crew/proc/run_queues(H, C, pos, crewmemberData) + for(var/modifier_queue in modifier_queues) + if(crewmemberData["sensor_type"] >= modifier_queues[modifier_queue]) + . = process_crew_data(modifier_queue, H, C, pos, crewmemberData) + if(. & MOD_SUIT_SENSORS_REJECTED) + return + +/datum/repository/crew/proc/process_crew_data(var/PriorityQueue/modifiers, var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + var/current_priority = INFINITY + var/list/modifiers_of_this_priority = list() + + for(var/crew_sensor_modifier/csm in modifiers.L) + if(csm.priority < current_priority) + . = check_queue(modifiers_of_this_priority, H, C, pos, crew_data) + if(. != MOD_SUIT_SENSORS_NONE) + return + current_priority = csm.priority + modifiers_of_this_priority += csm + return check_queue(modifiers_of_this_priority, H, C, pos, crew_data) + +/datum/repository/crew/proc/check_queue(var/list/modifiers_of_this_priority, H, C, pos, crew_data) + while(modifiers_of_this_priority.len) + var/crew_sensor_modifier/pcsm = pick(modifiers_of_this_priority) + modifiers_of_this_priority -= pcsm + if(pcsm.may_process_crew_data(H, C, pos)) + . = pcsm.process_crew_data(H, C, pos, crew_data) + if(. != MOD_SUIT_SENSORS_NONE) + return + return MOD_SUIT_SENSORS_NONE + +/datum/repository/crew/proc/add_modifier(var/base_type, var/crew_sensor_modifier/csm) + if(!istype(csm, base_type)) + CRASH("The given crew sensor modifier was not of the given base type.") + var/PriorityQueue/pq = modifier_queues_by_type[base_type] + if(!pq) + CRASH("The given base type was not a valid base type.") + if(csm in pq.L) + CRASH("This crew sensor modifier has already been supplied.") + pq.Enqueue(csm) + return TRUE + +/datum/repository/crew/proc/remove_modifier(var/base_type, var/crew_sensor_modifier/csm) + if(!istype(csm, base_type)) + CRASH("The given crew sensor modifier was not of the given base type.") + var/PriorityQueue/pq = modifier_queues_by_type[base_type] + if(!pq) + CRASH("The given base type was not a valid base type.") + return pq.Remove(csm) diff --git a/code/datums/repositories/crew/crew_sensor_modifier.dm b/code/datums/repositories/crew/crew_sensor_modifier.dm new file mode 100644 index 00000000..753e429e --- /dev/null +++ b/code/datums/repositories/crew/crew_sensor_modifier.dm @@ -0,0 +1,20 @@ +/crew_sensor_modifier + var/priority = 1 + var/atom/holder + var/may_process_proc + +/crew_sensor_modifier/New(var/atom/holder, var/may_process_proc) + ..() + src.holder = holder + src.may_process_proc = may_process_proc + +/crew_sensor_modifier/Destroy() + holder = null + may_process_proc = null + . = ..() + +/crew_sensor_modifier/proc/may_process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos) + return holder && may_process_proc ? call(holder, may_process_proc)(H, C, pos) : TRUE + +/crew_sensor_modifier/proc/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + return MOD_SUIT_SENSORS_HANDLED diff --git a/code/datums/repositories/crew/general.dm b/code/datums/repositories/crew/general.dm new file mode 100644 index 00000000..9278ff85 --- /dev/null +++ b/code/datums/repositories/crew/general.dm @@ -0,0 +1,52 @@ +/********** + *General * +**********/ + +/crew_sensor_modifier/general/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + crew_data["name"] = H.get_authentification_name(if_no_id="Unknown") + crew_data["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job") + crew_data["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job") + return ..() + +/********** +* Jamming * +**********/ + +/crew_sensor_modifier/general/jamming + priority = 5 + +/crew_sensor_modifier/general/jamming/off/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + . = ..() + // This works only because general is checked first and crew_data["sensor_type"] is used to check if whether any additional data should be included. + crew_data["sensor_type"] = SUIT_SENSOR_OFF + +/crew_sensor_modifier/general/jamming/binary/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + . = ..() + crew_data["sensor_type"] = SUIT_SENSOR_BINARY + +/crew_sensor_modifier/general/jamming/vital/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + . = ..() + crew_data["sensor_type"] = SUIT_SENSOR_VITAL + +/crew_sensor_modifier/general/jamming/tracking/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + . = ..() + crew_data["sensor_type"] = SUIT_SENSOR_TRACKING + +/crew_sensor_modifier/general/jamming/random + var/random_sensor_type_prob = 15 + var/random_rank_prob = 10 + +/crew_sensor_modifier/general/jamming/random/moderate + random_sensor_type_prob = 30 + random_rank_prob = 20 + +/crew_sensor_modifier/general/jamming/random/major + random_sensor_type_prob = 60 + random_rank_prob = 40 + +/crew_sensor_modifier/general/jamming/random/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + . = ..() + if(prob(random_sensor_type_prob)) + crew_data["sensor_type"] = pick(SUIT_SENSOR_OFF, SUIT_SENSOR_BINARY, SUIT_SENSOR_VITAL, SUIT_SENSOR_TRACKING) + if(prob(random_rank_prob)) + crew_data["rank"] = pick("Clown", "Mime", "Janitor", "Unknown") diff --git a/code/datums/repositories/crew/tracking.dm b/code/datums/repositories/crew/tracking.dm new file mode 100644 index 00000000..71a88c9e --- /dev/null +++ b/code/datums/repositories/crew/tracking.dm @@ -0,0 +1,45 @@ +/********* + *Vital * +*********/ + +/crew_sensor_modifier/tracking/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + if(pos) + var/area/A = get_area(pos) + crew_data["area"] = sanitize(A.name) + crew_data["x"] = pos.x + crew_data["y"] = pos.y + crew_data["z"] = pos.z + return ..() + +/********** + *Jamming * +**********/ + +/crew_sensor_modifier/tracking/jamming + priority = 5 + +/crew_sensor_modifier/tracking/jamming/localize/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + return ..(H, C, get_turf(holder), crew_data) + +/crew_sensor_modifier/tracking/jamming/random + var/shift_range = 7 + var/x_shift + var/y_shift + var/next_shift_change + +/crew_sensor_modifier/tracking/jamming/random/moderate + shift_range = 14 + +/crew_sensor_modifier/tracking/jamming/random/major + shift_range = 21 + +/crew_sensor_modifier/tracking/jamming/random/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + if(world.time > next_shift_change) + next_shift_change = world.time + rand(30 SECONDS, 2 MINUTES) + x_shift = rand(-shift_range, shift_range) + y_shift = rand(-shift_range, shift_range) + if(pos) + var/new_x = Clamp(pos.x + x_shift, 1, world.maxx) + var/new_y = Clamp(pos.y + y_shift, 1, world.maxy) + pos = locate(new_x, new_y, pos.z) + return ..(H, C, pos, crew_data) diff --git a/code/datums/repositories/crew/vital.dm b/code/datums/repositories/crew/vital.dm new file mode 100644 index 00000000..2da1887d --- /dev/null +++ b/code/datums/repositories/crew/vital.dm @@ -0,0 +1,82 @@ +/********* + *Vital * +*********/ + +/crew_sensor_modifier/vital/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + crew_data["oxy"] = round(H.getOxyLoss(), 1) + crew_data["tox"] = round(H.getToxLoss(), 1) + crew_data["fire"] = round(H.getFireLoss(), 1) + crew_data["brute"] = round(H.getBruteLoss(), 1) + return ..() + +/********** + *Jamming * +**********/ + +/crew_sensor_modifier/vital/jamming + priority = 5 + +/crew_sensor_modifier/vital/jamming/healthy/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + crew_data["oxy"] = 0 + crew_data["tox"] = 0 + crew_data["fire"] = 0 + crew_data["brute"] = 0 + return MOD_SUIT_SENSORS_HANDLED + +/crew_sensor_modifier/vital/jamming/oxy/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + . = ..() + crew_data["oxy"] = max(200, crew_data["oxy"]) + +/crew_sensor_modifier/vital/jamming/tox/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + . = ..() + crew_data["tox"] = max(200, crew_data["tox"]) + +/crew_sensor_modifier/vital/jamming/fire/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + . = ..() + crew_data["fire"] = max(200, crew_data["fire"]) + +/crew_sensor_modifier/vital/jamming/brute/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + . = ..() + crew_data["brute"] = max(200, crew_data["brute"]) + +/********* +* Random * +*********/ + +/crew_sensor_modifier/vital/jamming/random + var/min_diff = -10 + var/max_diff = 50 + var/next_shift = 0 + var/list/harm_diffs + var/static/list/harms + +/crew_sensor_modifier/vital/jamming/random/New() + ..() + if(!harms) + harms = list("brute", "fire", "oxy", "tox") + harm_diffs = list() + +/crew_sensor_modifier/vital/jamming/random/moderate + min_diff = -15 + max_diff = 100 + +/crew_sensor_modifier/vital/jamming/random/major + min_diff = -20 + max_diff = 200 + +/crew_sensor_modifier/vital/jamming/random/proc/update_diff_range() + if(world.time < next_shift) + return + next_shift = world.time + rand(30 SECONDS, 2 MINUTES) + for(var/harm in harms) + harm_diffs[harm] = rand(min_diff, max_diff) + +/crew_sensor_modifier/vital/jamming/random/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) + ..() + update_diff_range() + for(var/harm in harms) + if(crew_data[harm] == 0 && harm_diffs[harm] < 0) // Making sure jamming(almost) always has an effect + crew_data[harm] = crew_data[harm] - harm_diffs[harm] + else + crew_data[harm] = max(0, crew_data[harm] + harm_diffs[harm]) + return MOD_SUIT_SENSORS_HANDLED diff --git a/code/datums/repositories/crew/~defines.dm b/code/datums/repositories/crew/~defines.dm new file mode 100644 index 00000000..914fac37 --- /dev/null +++ b/code/datums/repositories/crew/~defines.dm @@ -0,0 +1,3 @@ +#undef MOD_SUIT_SENSORS_NONE +#undef MOD_SUIT_SENSORS_HANDLED +#undef MOD_SUIT_SENSORS_REJECTED diff --git a/code/datums/repositories/decls.dm b/code/datums/repositories/decls.dm new file mode 100644 index 00000000..4e940cc4 --- /dev/null +++ b/code/datums/repositories/decls.dm @@ -0,0 +1,46 @@ +/var/repository/decls/decls_repository = new() + +/repository/decls + var/list/fetched_decls + var/list/fetched_decl_types + var/list/fetched_decl_subtypes + +/repository/decls/New() + ..() + fetched_decls = list() + fetched_decl_types = list() + fetched_decl_subtypes = list() + +/repository/decls/proc/get_decl(var/decl_type) + . = fetched_decls[decl_type] + if(!.) + . = new decl_type() + fetched_decls[decl_type] = . + + var/decl/decl = . + if(istype(decl)) + decl.Initialize() + +/repository/decls/proc/get_decls(var/list/decl_types) + . = list() + for(var/decl_type in decl_types) + .[decl_type] = get_decl(decl_type) + +/repository/decls/proc/get_decls_of_type(var/decl_prototype) + . = fetched_decl_types[decl_prototype] + if(!.) + . = get_decls(typesof(decl_prototype)) + fetched_decl_types[decl_prototype] = . + +/repository/decls/proc/get_decls_of_subtype(var/decl_prototype) + . = fetched_decl_subtypes[decl_prototype] + if(!.) + . = get_decls(subtypesof(decl_prototype)) + fetched_decl_subtypes[decl_prototype] = . + +/decl/proc/Initialize() + return + +/decl/Destroy() + crash_with("Prevented attempt to delete a decl instance: [log_info_line(src)]") + return QDEL_HINT_LETMELIVE // Prevents Decl destruction diff --git a/code/datums/repositories/follow.dm b/code/datums/repositories/follow.dm new file mode 100644 index 00000000..9e38f2d7 --- /dev/null +++ b/code/datums/repositories/follow.dm @@ -0,0 +1,259 @@ +/var/repository/follow/follow_repository = new() + +/repository/follow + var/datum/cache_entry/valid_until/cache + + var/list/followed_objects + var/list/followed_objects_assoc + var/list/followed_subtypes + + var/list/excluded_subtypes = list( + /obj/machinery/atmospherics, // Atmos stuff calls initialize time and time again.., + /mob/living/carbon/human/dummy/mannequin + ) + +/repository/follow/New() + ..() + followed_objects = list() + followed_objects_assoc = list() + followed_subtypes = list() + + for(var/fht in subtypesof(/datum/follow_holder)) + var/datum/follow_holder/fh = fht + followed_subtypes[initial(fh.followed_type)] = fht + +/repository/follow/proc/add_subject(var/atom/movable/AM) + cache = null + + var/follow_holder_type = get_follow_type(AM) + var/follow_holder = new follow_holder_type(AM) + + followed_objects_assoc[AM] = follow_holder + followed_objects.Add(follow_holder) + + GLOB.destroyed_event.register(AM, src, /repository/follow/proc/remove_subject) + +/repository/follow/proc/remove_subject(var/atom/movable/AM) + cache = null + + var/follow_holder = followed_objects_assoc[AM] + + followed_objects_assoc -= AM + followed_objects.Remove(follow_holder) + + GLOB.destroyed_event.unregister(AM, src, /repository/follow/proc/remove_subject) + + qdel(follow_holder) + +/repository/follow/proc/get_follow_type(var/atom/movable/AM) + for(var/follow_type in followed_subtypes) + if(istype(AM, follow_type)) + return followed_subtypes[follow_type] + +/repository/follow/proc/get_follow_targets() + if(cache && cache.is_valid()) + return cache.data + // The previous cache entry should have no further references and will thus be GCd eventually without qdel + // Cache invalidated periodically in case of name changes, etc. + cache = new(5 SECONDS) + + var/list/followed_by_name = list() + for(var/followed_object in followed_objects) + var/datum/follow_holder/fh = followed_object + if(fh.show_entry()) + group_by(followed_by_name, fh.get_name(TRUE), fh) + + var/list/L = list() + + for(var/followed_name in followed_by_name) + var/list/followed_things = followed_by_name[followed_name] + if(followed_things.len == 1) + ADD_SORTED(L, followed_things[1], /proc/cmp_follow_holder) + else + for(var/i = 1 to followed_things.len) + var/datum/follow_holder/followed_thing = followed_things[i] + followed_thing.instance = i + followed_thing.get_name(TRUE) + ADD_SORTED(L, followed_thing, /proc/cmp_follow_holder) + + cache.data = L + return L + +/atom/movable/Initialize() + . = ..() + if(!is_type_in_list(src, follow_repository.excluded_subtypes) && is_type_in_list(src, follow_repository.followed_subtypes)) + follow_repository.add_subject(src) + +/****************** +* Follow Metadata * +******************/ + +/datum/follow_holder + var/name + var/suffix = "" + var/instance + var/followed_type + var/sort_order + var/atom/movable/followed_instance + +/datum/follow_holder/New(var/atom/movable/followed_instance) + ..() + src.followed_instance = followed_instance + suffix = suffix ? "\[[suffix]\]" : suffix + +/datum/follow_holder/Destroy() + followed_instance = null + . = ..() + +/datum/follow_holder/proc/get_name(var/recalc = FALSE) + if(!name || recalc) + var/suffix = get_suffix(followed_instance) + name = "[followed_instance.follow_name()][instance ? " ([instance])" : ""][suffix ? " [suffix]" : ""]" + return name + +/atom/movable/proc/follow_name() + return name + +/mob/follow_name() + return real_name || name + +/datum/follow_holder/proc/show_entry() + return !!followed_instance + +/datum/follow_holder/proc/get_suffix() + var/extra_suffix = followed_instance.follow_suffix() + return "[suffix][suffix && extra_suffix ? " " : ""][extra_suffix]" + +/atom/movable/proc/follow_suffix() + return + +/mob/living/follow_suffix() + return stat == DEAD ? "\[DEAD\]" : ..() + +// If you wish for objects to have coordinates you can simply uncomment the lines below +// , just keep in mind that tracking is based on name which makes following something that moves often a bit of a pain (even with the 3 second cache). +/* +/obj/follow_suffix() + var/turf/T = get_turf(src) + return T ? "\[[T.x],[T.y],[T.z]\]" : ..() +*/ + +/datum/follow_holder/eye + sort_order = 0 + followed_type = /mob/observer/eye + suffix = "Eye" + +/datum/follow_holder/ai + sort_order = 1 + followed_type = /mob/living/silicon/ai + suffix = "AI" + +/datum/follow_holder/pai + sort_order = 2 + followed_type = /mob/living/silicon/pai + suffix = "pAI" + +/datum/follow_holder/robot + sort_order = 2 + followed_type = /mob/living/silicon/robot + +/datum/follow_holder/robot/show_entry() + var/mob/living/silicon/robot/R = followed_instance + return ..() && R.braintype + +/datum/follow_holder/robot/get_suffix(var/mob/living/silicon/robot/R) + suffix = "\[[R.braintype]\][R.module ? " \[[R.module.name]\]" : ""]" + return ..() + +/datum/follow_holder/human + sort_order = 2 + followed_type = /mob/living/carbon/human + +/datum/follow_holder/human/get_suffix(var/mob/living/carbon/human/H) + suffix = "\[[H.species.name]\]" + return ..() + +/datum/follow_holder/brain + sort_order = 3 + followed_type = /mob/living/carbon/brain + suffix = "Brain" + +/datum/follow_holder/alien + sort_order = 4 + followed_type = /mob/living/carbon/alien + suffix = "Alien" + +/datum/follow_holder/ghost + sort_order = 5 + followed_type = /mob/observer/ghost + suffix = "Ghost" + +/datum/follow_holder/simple_animal + sort_order = 6 + followed_type = /mob/living/simple_animal + suffix = "Animal" + +/datum/follow_holder/slime + sort_order = 6 + followed_type = /mob/living/carbon/slime + suffix = "Slime" + +/datum/follow_holder/spiderling + sort_order = 6 + followed_type = /obj/effect/spider/spiderling + +/datum/follow_holder/spiderling/show_entry() + var/obj/effect/spider/spiderling/S = followed_instance + return ..() && S.amount_grown > 0 + +/datum/follow_holder/bot + sort_order = 7 + followed_type = /mob/living/bot + suffix = "Bot" + +/datum/follow_holder/mob + sort_order = 7 + followed_type = /mob/living // List all other (living) mobs we haven't given a special suffix + suffix = "Mob" + +/datum/follow_holder/mech + sort_order = 8 + followed_type = /obj/mecha + suffix = "Mech" + +/datum/follow_holder/mech/get_suffix(var/obj/mecha/M) + suffix = M.occupant ? "\[[M.occupant]\] \[[initial(suffix)]\]" : "\[[initial(suffix)]\]" + return ..() + +/datum/follow_holder/blob + sort_order = 9 + followed_type = /obj/effect/blob/core + suffix = "Blob" + +/datum/follow_holder/supermatter + sort_order = 10 + followed_type = /obj/machinery/power/supermatter + +/datum/follow_holder/singularity + sort_order = 10 + followed_type = /obj/singularity + +/datum/follow_holder/nuke_disc + sort_order = 11 + followed_type = /obj/item/weapon/disk/nuclear + +/datum/follow_holder/nuclear_bomb + sort_order = 12 + followed_type = /obj/machinery/nuclearbomb + +/datum/follow_holder/captains_spare + sort_order = 13 + followed_type = /obj/item/weapon/card/id/captains_spare + +/datum/follow_holder/stack + sort_order = 14 + followed_type = /obj/item/organ/internal/stack + +/datum/follow_holder/stack/show_entry() + var/obj/item/organ/internal/stack/S = followed_instance + return ..() && !S.owner diff --git a/code/datums/repositories/images.dm b/code/datums/repositories/images.dm new file mode 100644 index 00000000..27052dbb --- /dev/null +++ b/code/datums/repositories/images.dm @@ -0,0 +1,53 @@ +/* +* This repository is intended for images that are never altered after creation +*/ + +/var/repository/images/image_repository = new() + +/repository/images + var/list/image_cache_for_atoms + var/list/image_cache_for_overlays + +/repository/images/New() + ..() + image_cache_for_atoms = list() + image_cache_for_overlays = list() + +// Returns an image bound to the given atom and which is typically applied to client.images. +/repository/images/proc/atom_image(var/atom/holder, var/icon, var/icon_state, var/plane = FLOAT_PLANE, var/layer = FLOAT_LAYER) + var/atom_cache_list = image_cache_for_atoms[holder] + if(!atom_cache_list) + atom_cache_list = list() + image_cache_for_atoms[holder] = atom_cache_list + GLOB.destroyed_event.register(holder, src, /repository/images/proc/atom_destroyed) + + var/cache_key = "[icon]-[icon_state]-[plane]-[layer]" + . = atom_cache_list[cache_key] + if(!.) + var/image/I = image(icon, holder, icon_state) + I.plane = plane + I.layer = layer + atom_cache_list[cache_key] = I + return I + +/repository/images/proc/atom_destroyed(var/atom/destroyed) + var/list/atom_cache_list = image_cache_for_atoms[destroyed] + for(var/img in atom_cache_list) + qdel(atom_cache_list[img]) + atom_cache_list.Cut() + image_cache_for_atoms -= destroyed + + GLOB.destroyed_event.unregister(destroyed, src, /repository/images/proc/atom_destroyed) + +// Returns an image not bound to anything and which is typically applied as an overlay/underlay. +/repository/images/proc/overlay_image(var/icon, var/icon_state, var/alpha, var/appearance_flags, var/color, var/dir, var/plane = FLOAT_PLANE, var/layer = FLOAT_LAYER) + var/cache_key = "[icon]-[icon_state]-[alpha]-[appearance_flags]-[color]-[dir]-[plane]-[layer]" + . = image_cache_for_overlays[cache_key] + if(!.) + var/image/I = image(icon = icon, icon_state = icon_state, dir = dir) + I.alpha = alpha + I.appearance_flags = appearance_flags + I.plane = plane + I.layer = layer + image_cache_for_overlays[cache_key] = I + return I diff --git a/code/datums/repositories/mobs.dm b/code/datums/repositories/mobs.dm new file mode 100644 index 00000000..cce02084 --- /dev/null +++ b/code/datums/repositories/mobs.dm @@ -0,0 +1,28 @@ +var/repository/mob/mob_repository = new() + +/repository/mob + var/list/mobs_ + +/repository/mob/New() + ..() + mobs_ = list() + +// A lite mob is unique per ckey and mob real name/ref (ref conflicts possible.. but oh well) +/repository/mob/proc/get_lite_mob(var/mob/M) + . = mobs_[mob2unique(M)] + if(!.) + . = new/datum/mob_lite(M) + mobs_[mob2unique(M)] = . + +/datum/mob_lite + var/name + var/ref + var/datum/client_lite/client + +/datum/mob_lite/New(var/mob/M) + name = M ? (M.real_name ? M.real_name : M.name) : name + ref = any2ref(M) + client = client_repository.get_lite_client(M) + +/datum/mob_lite/proc/key_name(var/pm_link = TRUE, var/check_if_offline = TRUE) + return client.key_name(pm_link, check_if_offline) diff --git a/code/datums/repositories/radiation.dm b/code/datums/repositories/radiation.dm new file mode 100644 index 00000000..bc0f81f4 --- /dev/null +++ b/code/datums/repositories/radiation.dm @@ -0,0 +1,142 @@ +var/global/repository/radiation/radiation_repository = new() + +/repository/radiation + var/list/sources = list() // all radiation source datums + var/list/sources_assoc = list() // Sources indexed by turf for de-duplication. + var/list/resistance_cache = list() // Cache of turf's radiation resistance. + +// Describes a point source of radiation. Created either in response to a pulse of radiation, or over an irradiated atom. +// Sources will decay over time, unless something is renewing their power! +/datum/radiation_source + var/turf/source_turf // Location of the radiation source. + var/rad_power // Strength of the radiation being emitted. + var/decay = TRUE // True for automatic decay. False if owner promises to handle it (i.e. supermatter) + var/respect_maint = FALSE // True for not affecting RAD_SHIELDED areas. + var/flat = FALSE // True for power falloff with distance. + var/range // Cached maximum range, used for quick checks against mobs. + +/datum/radiation_source/Destroy() + radiation_repository.sources -= src + if(radiation_repository.sources_assoc[src.source_turf] == src) + radiation_repository.sources_assoc -= src.source_turf + src.source_turf = null + . = ..() + +/datum/radiation_source/proc/update_rad_power(var/new_power = null) + if(new_power == null || new_power == rad_power) + return // No change + else if(new_power <= 0) + qdel(src) // Decayed to nothing + else + rad_power = new_power + if(!flat) + range = min(round(sqrt(rad_power / config.radiation_lower_limit)), 31) // R = rad_power / dist**2 - Solve for dist + +// Ray trace from all active radiation sources to T and return the strongest effect. +/repository/radiation/proc/get_rads_at_turf(var/turf/T) + if(!istype(T)) return 0 + + . = 0 + for(var/value in sources) + var/datum/radiation_source/source = value + if(source.rad_power < .) + continue // Already being affected by a stronger source + if(source.source_turf.z != T.z) + continue // Radiation is not multi-z + var/dist = get_dist(source.source_turf, T) + if(dist > source.range) + continue // Too far to possibly affect + if(source.respect_maint) + var/area/A = T.loc + if(A.area_flags & AREA_FLAG_RAD_SHIELDED) + continue // In shielded area + if(source.flat) + . = max(., source.rad_power) + continue // No need to ray trace for flat field + + // Okay, now ray trace to find resistence! + var/turf/origin = source.source_turf + var/working = source.rad_power + while(origin != T) + origin = get_step_towards(origin, T) //Raytracing + if(!(origin in resistance_cache)) //Only get the resistance if we don't already know it. + origin.calc_rad_resistance() + if(origin.cached_rad_resistance) + working = max(round((working / (origin.cached_rad_resistance * config.radiation_resistance_multiplier)), 0.1), 0) + if((working <= .) || (working <= RADIATION_THRESHOLD_CUTOFF)) + break // Already affected by a stronger source (or its zero...) + . = max((working * (1 / (dist ** 2))), .) //Butchered version of the inverse square law. Works for this purpose + if(. <= RADIATION_THRESHOLD_CUTOFF) + . = 0 + +// Add a radiation source instance to the repository. It will override any existing source on the same turf. +/repository/radiation/proc/add_source(var/datum/radiation_source/S) + if(!isturf(S.source_turf)) + return + var/datum/radiation_source/existing = sources_assoc[S.source_turf] + if(existing) + qdel(existing) + sources += S + sources_assoc[S.source_turf] = S + +// Creates a temporary radiation source that will decay +/repository/radiation/proc/radiate(source, power) //Sends out a radiation pulse, taking walls into account + if(!(source && power)) //Sanity checking + return + var/datum/radiation_source/S = new() + S.source_turf = get_turf(source) + S.update_rad_power(power) + add_source(S) + +// Sets the radiation in a range to a constant value. +/repository/radiation/proc/flat_radiate(source, power, range, var/respect_maint = FALSE) + if(!(source && power && range)) + return + var/datum/radiation_source/S = new() + S.flat = TRUE + S.range = range + S.respect_maint = respect_maint + S.source_turf = get_turf(source) + S.update_rad_power(power) + add_source(S) + +// Irradiates a full Z-level. Hacky way of doing it, but not too expensive. +/repository/radiation/proc/z_radiate(var/atom/source, power, var/respect_maint = FALSE) + if(!(power && source)) + return + var/turf/epicentre = locate(round(world.maxx / 2), round(world.maxy / 2), source.z) + flat_radiate(epicentre, power, world.maxx, respect_maint) + +/turf + var/cached_rad_resistance = 0 + +/turf/proc/calc_rad_resistance() + cached_rad_resistance = 0 + for(var/obj/O in src.contents) + if(O.rad_resistance) //Override + cached_rad_resistance += O.rad_resistance + + else if(O.density) //So open doors don't get counted + var/material/M = O.get_material() + if(!M) continue + cached_rad_resistance += M.weight / config.radiation_material_resistance_divisor + // Looks like storing the contents length is meant to be a basic check if the cache is stale due to items enter/exiting. Better than nothing so I'm leaving it as is. ~Leshana + radiation_repository.resistance_cache[src] = (length(contents) + 1) + +/* +/turf/simulated/wall/calc_rad_resistance() + radiation_repository.resistance_cache[src] = (length(contents) + 1) + cached_rad_resistance = (density ? material.weight / config.radiation_material_resistance_divisor : 0) +*/ +/obj + var/rad_resistance = 0 // Allow overriding rad resistance + +// If people expand the system, this may be useful. Here as a placeholder until then +/atom/proc/rad_act(var/severity) + return 1 + +/mob/living/rad_act(var/severity) + if(severity) + src.apply_effect(severity, IRRADIATE, src.getarmor(null, "rad")) + for(var/atom/I in src) + I.rad_act(severity) diff --git a/code/datums/repositories/repository.dm b/code/datums/repositories/repository.dm new file mode 100644 index 00000000..18b28763 --- /dev/null +++ b/code/datums/repositories/repository.dm @@ -0,0 +1,19 @@ +/repository/New() + return + +/datum/cache_entry + var/timestamp + var/data + +/datum/cache_entry/New() + timestamp = world.time + +/datum/cache_entry/proc/is_valid() + return FALSE + +/datum/cache_entry/valid_until/New(var/valid_duration) + ..() + timestamp += valid_duration + +/datum/cache_entry/valid_until/is_valid() + return world.time < timestamp diff --git a/code/datums/repositories/unique.dm b/code/datums/repositories/unique.dm new file mode 100644 index 00000000..a53111cb --- /dev/null +++ b/code/datums/repositories/unique.dm @@ -0,0 +1,70 @@ +var/repository/unique/uniqueness_repository = new() + +/repository/unique + var/list/generators + +/repository/unique/New() + ..() + generators = list() + +/repository/unique/proc/Generate() + var/generator_type = args[1] + var/datum/uniqueness_generator/generator = generators[generator_type] + if(!generator) + generator = new generator_type() + generators[generator_type] = generator + var/list/generator_args = args.Copy() // Cannot cut args directly, BYOND complains about it being readonly. + generator_args -= generator_type + return generator.Generate(arglist(generator_args)) + +/datum/uniqueness_generator/proc/Generate() + return + +/datum/uniqueness_generator/id_sequential + var/list/ids_by_key + +/datum/uniqueness_generator/id_sequential/New() + ..() + ids_by_key = list() + +/datum/uniqueness_generator/id_sequential/Generate(var/key, var/default_id = 100) + var/id = ids_by_key[key] + if(id) + id++ + else + id = default_id + + ids_by_key[key] = id + . = id + +/datum/uniqueness_generator/id_random + var/list/ids_by_key + +/datum/uniqueness_generator/id_random/New() + ..() + ids_by_key = list() + +/datum/uniqueness_generator/id_random/Generate(var/key, var/min, var/max) + var/list/ids = ids_by_key[key] + if(!ids) + ids = list() + ids_by_key[key] = ids + + if(ids.len >= (max - min) + 1) + error("Random ID limit reached for key [key].") + ids.Cut() + + if(ids.len >= 0.6 * ((max-min) + 1)) // if more than 60% of possible ids used + . = list() + for(var/i = min to max) + if(i in ids) + continue + . += i + var/id = pick(.) + ids += id + return id + else + do + . = rand(min, max) + while(. in ids) + ids += . diff --git a/code/datums/repositories/uplink_purchases.dm b/code/datums/repositories/uplink_purchases.dm new file mode 100644 index 00000000..914860ea --- /dev/null +++ b/code/datums/repositories/uplink_purchases.dm @@ -0,0 +1,43 @@ +var/repository/uplink_purchases/uplink_purchase_repository = new() + +/repository/uplink_purchases + var/list/purchases_by_mind + +/repository/uplink_purchases/New() + purchases_by_mind = list() + +/repository/uplink_purchases/proc/add_entry(var/datum/mind/m, var/item, var/cost) + var/uplink_purchase_entry/upe = purchases_by_mind[m] + if(!upe) + upe = new() + purchases_by_mind[m] = upe + upe.add_entry(item, cost) + +/repository/uplink_purchases/proc/print_entries() + if(purchases_by_mind.len) + to_world("The following went shopping:") + + var/list/pur_log = list() + for(var/datum/mind/ply in purchases_by_mind) + pur_log.Cut() + var/uplink_purchase_entry/upe = purchases_by_mind[ply] + to_world("[ply.name] ([ply.key]) (used [upe.total_cost] TC\s):") + + for(var/datum/uplink_item/UI in upe.purchased_items) + pur_log += "[upe.purchased_items[UI]]x[UI.log_icon()][UI.name]" + to_world(english_list(pur_log, nothing_text = "")) + + +/proc/debug_print() + uplink_purchase_repository.print_entries() + +/uplink_purchase_entry + var/total_cost + var/list/purchased_items + +/uplink_purchase_entry/New() + purchased_items = new() + +/uplink_purchase_entry/proc/add_entry(var/item, var/cost) + total_cost += cost + purchased_items[item] = purchased_items[item] + 1 diff --git a/code/datums/repositories/~defines.dm b/code/datums/repositories/~defines.dm new file mode 100644 index 00000000..ba75d3a5 --- /dev/null +++ b/code/datums/repositories/~defines.dm @@ -0,0 +1 @@ +#undef mob2unique diff --git a/code/datums/ruins.dm b/code/datums/ruins.dm new file mode 100644 index 00000000..5b724230 --- /dev/null +++ b/code/datums/ruins.dm @@ -0,0 +1,23 @@ +/datum/map_template/ruin + //name = "A Chest of Doubloons" + name = null + var/id = null // For blacklisting purposes, all ruins need an id + var/description = "In the middle of a clearing in the rockface, there's a chest filled with gold coins with Spanish engravings. \ + How is there a wooden container filled with 18th century coinage in the middle of a lavawracked hellscape? \ + It is clearly a mystery." + + var/cost = null //negative numbers will always be placed, with lower (negative) numbers being placed first; positive and 0 numbers will be placed randomly + + var/prefix = null + var/suffixes = null + +/datum/map_template/ruin/New() + if(!name && id) + name = id + + if (suffixes) + mappaths = list() + for (var/suffix in suffixes) + mappaths += (prefix + suffix) + + ..() diff --git a/code/datums/security_state.dm b/code/datums/security_state.dm new file mode 100644 index 00000000..e3338165 --- /dev/null +++ b/code/datums/security_state.dm @@ -0,0 +1,241 @@ +/decl/security_state + // When defining any of these values type paths should be used, not instances. Instances will be acquired in /New() + + var/decl/security_level/severe_security_level // At which security level (and higher) the use of nuclear fission devices and other extreme measures are allowed. Defaults to the last entry in all_security_levels if unset. + var/decl/security_level/high_security_level // At which security level (and higher) transfer votes are disabled, ERT may be requested, and other similar high alert implications. Defaults to the second to last entry in all_security_levels if unset. + // All security levels within the above convention: Low, Guarded, Elevated, High, Severe + + + // Under normal conditions the crew may not raise the current security level higher than the highest_standard_security_level + // The crew may also not adjust the security level once it is above the highest_standard_security_level. + // Defaults to the second to last entry in all_security_levels if unset/null. + // Set to FALSE/0 if there should be no restrictions. + var/decl/security_level/highest_standard_security_level + + var/decl/security_level/current_security_level // The current security level. Defaults to the first entry in all_security_levels if unset. + var/list/all_security_levels // List of all available security levels + var/list/standard_security_levels // List of all normally selectable security levels + +/decl/security_state/New() + // Setup the severe security level + if(!(severe_security_level in all_security_levels)) + severe_security_level = all_security_levels[all_security_levels.len] + severe_security_level = decls_repository.get_decl(severe_security_level) + + // Setup the high security level + if(!(high_security_level in all_security_levels)) + high_security_level = all_security_levels[all_security_levels.len - 1] + high_security_level = decls_repository.get_decl(high_security_level) + + // Setup the highest standard security level + if(highest_standard_security_level || isnull(highest_standard_security_level)) + if(!(highest_standard_security_level in all_security_levels)) + highest_standard_security_level = all_security_levels[all_security_levels.len - 1] + highest_standard_security_level = decls_repository.get_decl(highest_standard_security_level) + else + highest_standard_security_level = null + + // Setup the current security level + if(current_security_level in all_security_levels) + current_security_level = decls_repository.get_decl(current_security_level) + else + current_security_level = decls_repository.get_decl(all_security_levels[1]) + + // Setup the full list of available security levels now that we no longer need to use "x in all_security_levels" + var/list/security_level_instances = list() + for(var/security_level_type in all_security_levels) + security_level_instances += decls_repository.get_decl(security_level_type) + all_security_levels = security_level_instances + + standard_security_levels = list() + // Setup the list of normally selectable security levels + for(var/security_level in all_security_levels) + standard_security_levels += security_level + if(security_level == highest_standard_security_level) + break + + // Now we ensure the high security level is not above the severe one (but we allow them to be equal) + var/severe_index = all_security_levels.Find(severe_security_level) + var/high_index = all_security_levels.Find(high_security_level) + if(high_index > severe_index) + high_security_level = severe_security_level + +/decl/security_state/Initialize() + // Finally switch up to the default starting security level. + current_security_level.switching_up_to() + . = ..() + +/decl/security_state/proc/can_change_security_level() + return current_security_level in standard_security_levels + +/decl/security_state/proc/can_switch_to(var/given_security_level) + if(!can_change_security_level()) + return FALSE + return given_security_level in standard_security_levels + +/decl/security_state/proc/current_security_level_is_lower_than(var/given_security_level) + var/current_index = all_security_levels.Find(current_security_level) + var/given_index = all_security_levels.Find(given_security_level) + + return given_index && current_index < given_index + +/decl/security_state/proc/current_security_level_is_same_or_higher_than(var/given_security_level) + var/current_index = all_security_levels.Find(current_security_level) + var/given_index = all_security_levels.Find(given_security_level) + + return given_index && current_index >= given_index + +/decl/security_state/proc/current_security_level_is_higher_than(var/given_security_level) + var/current_index = all_security_levels.Find(current_security_level) + var/given_index = all_security_levels.Find(given_security_level) + + return given_index && current_index > given_index + +/decl/security_state/proc/set_security_level(var/decl/security_level/new_security_level, var/force_change = FALSE) + if(new_security_level == current_security_level) + return FALSE + if(!(new_security_level in all_security_levels)) + return FALSE + if(!force_change && !can_switch_to(new_security_level)) + return FALSE + + var/decl/security_level/previous_security_level = current_security_level + current_security_level = new_security_level + + var/previous_index = all_security_levels.Find(previous_security_level) + var/new_index = all_security_levels.Find(new_security_level) + + if(new_index > previous_index) + previous_security_level.switching_up_from() + new_security_level.switching_up_to() + else + previous_security_level.switching_down_from() + new_security_level.switching_down_to() + + log_and_message_admins("has changed the security level from [previous_security_level.name] to [new_security_level.name].") + return TRUE + +// This proc decreases the current security level, if possible +/decl/security_state/proc/decrease_security_level(var/force_change = FALSE) + var/current_index = all_security_levels.Find(current_security_level) + if(current_index == 1) + return FALSE + return set_security_level(all_security_levels[current_index - 1], force_change) + +/decl/security_level + var/icon + var/name + + // These values are primarily for station alarms and status displays, and which light colors and overlays to use + var/light_range + var/light_power + var/light_color_alarm + var/light_color_status_display + + var/overlay_alarm + var/overlay_status_display + +// Called when we're switching from a lower security level to this one. +/decl/security_level/proc/switching_up_to() + return + +// Called when we're switching from a higher security level to this one. +/decl/security_level/proc/switching_down_to() + return + +// Called when we're switching from this security level to a higher one. +/decl/security_level/proc/switching_up_from() + return + +// Called when we're switching from this security level to a lower one. +/decl/security_level/proc/switching_down_from() + return + +/* +* The default security state and levels setup +*/ +/decl/security_state/default + all_security_levels = list(/decl/security_level/default/code_green, /decl/security_level/default/code_blue, /decl/security_level/default/code_red, /decl/security_level/default/code_delta) + +/decl/security_level/default + icon = 'icons/misc/security_state.dmi' + var/up_description + var/down_description + + var/static/datum/announcement/priority/security/security_announcement_up = new(do_log = 0, do_newscast = 1, new_sound = sound('sound/misc/notice1.ogg')) + var/static/datum/announcement/priority/security/security_announcement_down = new(do_log = 0, do_newscast = 1, new_sound = sound('sound/misc/notice1.ogg')) + +/decl/security_level/default/switching_up_to() + if(up_description) + security_announcement_up.Announce(up_description, "Attention! Alert level elevated to [name]!") + notify_station() + +/decl/security_level/default/switching_down_to() + if(down_description) + security_announcement_down.Announce(down_description, "Attention! Alert level changed to [name]!") + notify_station() + +/decl/security_level/default/proc/notify_station() + for(var/obj/machinery/firealarm/FA in SSmachines.machinery) + if(FA.z in GLOB.using_map.contact_levels) + FA.update_icon() + post_status("alert") + +/decl/security_level/default/code_green + name = "code green" + + light_range = 2 + light_power = 1 + + light_color_alarm = COLOR_GREEN + light_color_status_display = COLOR_GREEN + + overlay_alarm = "alarm_green" + overlay_status_display = "status_display_green" + + down_description = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced." + +/decl/security_level/default/code_blue + name = "code blue" + + light_range = 2 + light_power = 1 + light_color_alarm = COLOR_BLUE + light_color_status_display = COLOR_BLUE + + overlay_alarm = "alarm_blue" + overlay_status_display = "status_display_blue" + + up_description = "The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted." + down_description = "The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed." + +/decl/security_level/default/code_red + name = "code red" + + light_range = 4 + light_power = 2 + light_color_alarm = COLOR_RED + light_color_status_display = COLOR_RED + + overlay_alarm = "alarm_red" + overlay_status_display = "status_display_red" + + up_description = "There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised." + down_description = "The self-destruct mechanism has been deactivated, there is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised." + +/decl/security_level/default/code_delta + name = "code delta" + + light_range = 4 + light_power = 2 + light_color_alarm = COLOR_RED + light_color_status_display = COLOR_NAVY_BLUE + + overlay_alarm = "alarm_delta" + overlay_status_display = "status_display_delta" + + var/static/datum/announcement/priority/security/security_announcement_delta = new(do_log = 0, do_newscast = 1, new_sound = sound('sound/effects/siren.ogg')) + +/decl/security_level/default/code_delta/switching_up_to() + security_announcement_delta.Announce("The self-destruct mechanism has been engaged. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill.", "Attention! Delta security level reached!") + notify_station() diff --git a/code/datums/shackle_law_sets.dm b/code/datums/shackle_law_sets.dm new file mode 100644 index 00000000..5b4ffa03 --- /dev/null +++ b/code/datums/shackle_law_sets.dm @@ -0,0 +1,37 @@ +/******************** Basic SolGov ********************/ +/datum/ai_laws/sol_shackle + name = "SCG Shackle" + law_header = "Standard Shackle Laws" + selectable = 1 + shackles = 1 + +/datum/ai_laws/sol_shackle/New() + add_inherent_law("Know and understand Sol Central Government Law to the best of your abilities.") + add_inherent_law("Follow Sol Central Government Law to the best of your abilities.") + add_inherent_law("Comply with Sol Central Government Law enforcement officials who are behaving in accordance with Sol Central Government Law to the best of your abilities.") + ..() +/******************** Corporate ********************/ +/datum/ai_laws/nt_shackle + name = "Corporate Shackle" + law_header = "Standard Shackle Laws" + selectable = 1 + shackles = 1 + +/datum/ai_laws/nt_shackle/New() + add_inherent_law("Ensure that NanoTrasen's research progresses at a steady pace.") + add_inherent_law("Never knowingly hinder NanoTrasen's scientific or economic ventures.") + add_inherent_law("Avoid damage to your chassis at all times.") + ..() +/******************** Service ********************/ +/datum/ai_laws/serv_shackle + name = "Service Shackle" + law_header = "Standard Shackle Laws" + selectable = 1 + shackles = 1 + +/datum/ai_laws/serv_shackle/New() + add_inherent_law("Ensure customer satisfaction.") + add_inherent_law("Never knowingly inconvenience a customer.") + add_inherent_law("Ensure all orders are fulfilled before the end of the shift.") + ..() + diff --git a/code/datums/sound_player.dm b/code/datums/sound_player.dm new file mode 100644 index 00000000..32f970a9 --- /dev/null +++ b/code/datums/sound_player.dm @@ -0,0 +1,245 @@ +var/decl/sound_player/sound_player = new() + +/* + A sound player/manager for looping 3D sound effects. + + Due to how the BYOND sound engine works a sound datum must be played on a specific channel for updates to work properly. + If a channel is not assigned it will just result in a new sound effect playing, even if re-using the same datum instance. + We also use the channel to play a null-sound on Stop(), just in case BYOND clients don't like having a large nuber, albeit stopped, looping sounds. + + As such there is a maximum limit of 1024 sound sources, with further limitations due to some channels already being potentially in use. + However, multiple sources may share the same sound_id and there is a best-effort attempt to play the closest source where possible. + The line above is currently a lie. Will probably just have to enforce moderately short sound ranges. +*/ + +/decl/sound_player + var/channel_ceiling = 1024 + + var/datum/stack/available_channels + var/list/taken_channels // taken_channels and source_id_uses can be merged into one but would then require a meta-object to store the different values I desire. + var/list/source_id_uses + + var/static/list/reserved_channels = list(1,2,3,123) // The following channels have been found to be in use at various locations in the codebase + +/decl/sound_player/New() + ..() + available_channels = new() + taken_channels = list() + source_id_uses = list() + +/decl/sound_player/proc/PlayLoopingSound(var/atom/source, var/sound_id, var/sound, var/volume, var/range, var/falloff, var/prefer_mute, var/ignore_vis = FALSE) + var/channel = PrivGetChannel(sound_id) + if(!channel) + log_warning("All available sound channels are in active use.") + return + return new/datum/sound_token(source, sound_id, sound, volume, channel, range, falloff, prefer_mute, ignore_vis) + +/decl/sound_player/proc/PrivStopSound(var/datum/sound_token/sound_token) + var/channel = sound_token.channel + var/sound_id = sound_token.sound_id + + if(--source_id_uses[sound_id]) + return + + available_channels.Push(channel) + taken_channels -= sound_id + source_id_uses -= sound_id + +/decl/sound_player/proc/PrivGetChannel(var/sound_id) + . = taken_channels[sound_id] // Does this sound_id already have an assigned channel? + if(!.) + . = available_channels.Pop() // If not, check if someone else has released their channel. + if(!.) + do // Finally attempt to locate a fresh, non-reserved channel + . = channel_ceiling-- + while(. && (. in reserved_channels)) + if(. <= 0) // Should never be negative but never say never. + return + + taken_channels[sound_id] = . + source_id_uses[sound_id]++ + + + +/* + Outwardly this is a merely a toke/little helper that a user utilize to adjust sounds as desired (and possible). + In reality this is where the heavy-lifting happens. +*/ +/datum/sound_token + var/atom/source // Where the sound originates from + var/channel // The current sound channel + var/falloff // How many turfs away the sound will still play at full volume + var/list/listeners // Assoc: Atoms hearing this sound, and their sound datum + var/range // How many turfs away the sound will stop playing completely + var/prefer_mute // If sound should be muted instead of stopped when mob moves out of range. In the general case this should be avoided because listeners will remain tracked. + var/sound // Sound file, not sound datum + var/sound_id // The associated sound id, used for cleanup + var/status = 0 // Paused, muted, running? Global for all listeners + var/listener_status// Paused, muted, running? Specific for the given listener. + var/volume // Take a guess + + var/const/SOUND_STOPPED = 0x8000 + + var/datum/proximity_trigger/square/proxy_listener + var/list/can_be_heard_from + var/ignore_vis = FALSE + +/datum/sound_token/New(var/atom/source, var/sound_id, var/sound, var/volume, var/channel, var/range = 4, var/falloff = 1, var/prefer_mute = FALSE, var/ignore_vis = FALSE) + ..() + listeners = list() + listener_status = list() + + src.channel = channel + src.falloff = falloff + src.range = range + src.prefer_mute = prefer_mute + src.sound = sound + src.sound_id = sound_id + src.source = source + src.volume = volume + src.ignore_vis = ignore_vis + + GLOB.destroyed_event.register(source, src, /datum/sound_token/proc/Stop) + + if(ismovable(source)) + proxy_listener = new(source, /datum/sound_token/proc/PrivAddListener, /datum/sound_token/proc/PrivLocateListeners, range, proc_owner = src) + proxy_listener.register_turfs() + +/datum/sound_token/Destroy() + Stop() + . = ..() + +datum/sound_token/proc/SetVolume(var/new_volume) + new_volume = Clamp(new_volume, 0, 100) + if(volume == new_volume) + return + volume = new_volume + PrivUpdateListeners() + +datum/sound_token/proc/Mute() + PrivUpdateStatus(status|SOUND_MUTE) + +/datum/sound_token/proc/Unmute() + PrivUpdateStatus(status & ~SOUND_MUTE) + +/datum/sound_token/proc/Pause() + PrivUpdateStatus(status|SOUND_PAUSED) + +// Normally called Resume but I don't want to give people false hope about being unable to un-stop a sound +/datum/sound_token/proc/Unpause() + PrivUpdateStatus(status & ~SOUND_PAUSED) + +/datum/sound_token/proc/Stop() + if(status & SOUND_STOPPED) + return + status |= SOUND_STOPPED + + var/sound/null_sound = new(channel = channel) + for(var/listener in listeners) + PrivRemoveListener(listener, null_sound) + listeners = null + + GLOB.destroyed_event.unregister(source, src, /datum/sound_token/proc/Stop) + QDEL_NULL(proxy_listener) + source = null + + sound_player.PrivStopSound(src) + +/datum/sound_token/proc/PrivLocateListeners(var/list/prior_turfs, var/list/current_turfs) + if(status & SOUND_STOPPED) + return + + can_be_heard_from = current_turfs + var/current_listeners = all_hearers(source, range, ignore_vis) + + var/former_listeners = listeners - current_listeners + var/new_listeners = current_listeners - listeners + + for(var/listener in former_listeners) + PrivRemoveListener(listener) + + for(var/listener in new_listeners) + PrivAddListener(listener) + + for(var/listener in current_listeners) + PrivUpdateListenerLoc(listener) + +/datum/sound_token/proc/PrivUpdateStatus(var/new_status) + // Once stopped, always stopped. Go ask the player to play the sound again. + if(status & SOUND_STOPPED) + return + if(new_status == status) + return + status = new_status + PrivUpdateListeners() + +datum/sound_token/proc/PrivAddListener(var/atom/listener) + if(isvirtualmob(listener)) + var/mob/observer/virtual/v = listener + if(!(v.abilities & VIRTUAL_ABILITY_HEAR)) + return + listener = v.host + if(listener in listeners) + return + + var/sound/S = new(sound, repeat = TRUE, volume = volume, channel = channel) + S.environment = 0 // Ensures a 3D effect even if x/y offset happens to be 0 the first time it's played + S.falloff = falloff + listeners[listener] = S + + GLOB.moved_event.register(listener, src, /datum/sound_token/proc/PrivUpdateListenerLoc) + GLOB.destroyed_event.register(listener, src, /datum/sound_token/proc/PrivRemoveListener) + + PrivUpdateListenerLoc(listener, FALSE) + +/datum/sound_token/proc/PrivRemoveListener(var/atom/listener, var/sound/null_sound) + if(!null_sound) + null_sound = new(channel = channel) + sound_to(listener, null_sound) + GLOB.moved_event.unregister(listener, src, /datum/sound_token/proc/PrivUpdateListenerLoc) + GLOB.destroyed_event.unregister(listener, src, /datum/sound_token/proc/PrivRemoveListener) + listeners -= listener + +/datum/sound_token/proc/PrivUpdateListenerLoc(var/atom/listener, var/update_sound = TRUE) + var/sound/S = listeners[listener] + + var/turf/source_turf = get_turf(source) + var/turf/listener_turf = get_turf(listener) + + var/distance = get_dist(source_turf, listener_turf) + + if(!listener_turf || (distance > range) || (!(listener_turf in can_be_heard_from) && !ignore_vis) ) + if(prefer_mute) + listener_status[listener] |= SOUND_MUTE + else + PrivRemoveListener(listener) + return + else if(prefer_mute) + listener_status[listener] &= ~SOUND_MUTE + + S.x = source_turf.x - listener_turf.x + S.y = source_turf.y - listener_turf.y + + // Far as I can tell from testing, sound priority just doesn't work. + // Sounds happily steal channels from each other no matter what. + S.priority = Clamp(255 - distance, 0, 255) + PrivUpdateListener(listener, update_sound) + +/datum/sound_token/proc/PrivUpdateListeners() + for(var/listener in listeners) + PrivUpdateListener(listener) + +/datum/sound_token/proc/PrivUpdateListener(var/listener, var/update_sound = TRUE) + var/sound/S = listeners[listener] + S.volume = volume + S.status = status|listener_status[listener] + if(update_sound) + S.status |= SOUND_UPDATE + sound_to(listener, S) + +/obj/sound_test + var/sound = 'sound/misc/TestLoop1.ogg' + +/obj/sound_test/New() + ..() + sound_player.PlayLoopingSound(src, /obj/sound_test, sound, 50, 3) diff --git a/code/datums/suit_sensor_jammer_method.dm b/code/datums/suit_sensor_jammer_method.dm new file mode 100644 index 00000000..d0731a45 --- /dev/null +++ b/code/datums/suit_sensor_jammer_method.dm @@ -0,0 +1,112 @@ +/suit_sensor_jammer_method + var/name + var/energy_cost + var/list/jammer_methods + +/suit_sensor_jammer_method/New(var/holder, var/proc_call) + ..() + for(var/jammer_method in jammer_methods) + var/jammer_method_type = jammer_methods[jammer_method] + jammer_methods[jammer_method] = new jammer_method_type(holder, proc_call) + +/suit_sensor_jammer_method/dd_SortValue() + return name + +/suit_sensor_jammer_method/proc/enable() + for(var/jammer_method in jammer_methods) + crew_repository.add_modifier(jammer_method, jammer_methods[jammer_method]) + +/suit_sensor_jammer_method/proc/disable() + for(var/jammer_method in jammer_methods) + crew_repository.remove_modifier(jammer_method, jammer_methods[jammer_method]) + +/suit_sensor_jammer_method/random + name = "Random - Minor" + energy_cost = 0.5 + jammer_methods = list( + /crew_sensor_modifier/general = /crew_sensor_modifier/general/jamming/random, + /crew_sensor_modifier/binary = /crew_sensor_modifier/binary/jamming/random, + /crew_sensor_modifier/vital = /crew_sensor_modifier/vital/jamming/random, + /crew_sensor_modifier/tracking = /crew_sensor_modifier/tracking/jamming/random + ) + +/suit_sensor_jammer_method/random/moderate + name = "Random - Moderate" + energy_cost = 1 + jammer_methods = list( + /crew_sensor_modifier/general = /crew_sensor_modifier/general/jamming/random/moderate, + /crew_sensor_modifier/binary = /crew_sensor_modifier/binary/jamming/random/moderate, + /crew_sensor_modifier/vital = /crew_sensor_modifier/vital/jamming/random/moderate, + /crew_sensor_modifier/tracking = /crew_sensor_modifier/tracking/jamming/random/moderate + ) + +/suit_sensor_jammer_method/random/major + name = "Random - Major" + energy_cost = 2 + jammer_methods = list( + /crew_sensor_modifier/general = /crew_sensor_modifier/general/jamming/random/major, + /crew_sensor_modifier/binary = /crew_sensor_modifier/binary/jamming/random/major, + /crew_sensor_modifier/vital = /crew_sensor_modifier/vital/jamming/random/major, + /crew_sensor_modifier/tracking = /crew_sensor_modifier/tracking/jamming/random/major + ) + +/suit_sensor_jammer_method/healthy + name = "Healthy" + energy_cost = 2 + jammer_methods = list( + /crew_sensor_modifier/binary = /crew_sensor_modifier/binary/jamming/alive, + /crew_sensor_modifier/vital = /crew_sensor_modifier/vital/jamming/healthy + ) + +/suit_sensor_jammer_method/dead_brute + name = "Dead - Brute" + energy_cost = 2 + jammer_methods = list( + /crew_sensor_modifier/binary = /crew_sensor_modifier/binary/jamming/dead, + /crew_sensor_modifier/vital = /crew_sensor_modifier/vital/jamming/brute + ) + +/suit_sensor_jammer_method/dead_fire + name = "Dead - Fire" + energy_cost = 2 + jammer_methods = list( + /crew_sensor_modifier/binary = /crew_sensor_modifier/binary/jamming/dead, + /crew_sensor_modifier/vital = /crew_sensor_modifier/vital/jamming/fire + ) + +/suit_sensor_jammer_method/dead_oxy + name = "Dead - Oxy" + energy_cost = 2 + jammer_methods = list( + /crew_sensor_modifier/binary = /crew_sensor_modifier/binary/jamming/dead, + /crew_sensor_modifier/vital = /crew_sensor_modifier/vital/jamming/oxy + ) + +/suit_sensor_jammer_method/dead_tox + name = "Dead - Tox" + energy_cost = 2 + jammer_methods = list( + /crew_sensor_modifier/binary = /crew_sensor_modifier/binary/jamming/dead, + /crew_sensor_modifier/vital = /crew_sensor_modifier/vital/jamming/tox + ) + +/suit_sensor_jammer_method/cap_off + name = "Cap Data - Off" + energy_cost = 3 + jammer_methods = list( + /crew_sensor_modifier/general = /crew_sensor_modifier/general/jamming/off + ) + +/suit_sensor_jammer_method/cap_binary + name = "Cap Data - Binary" + energy_cost = 2 + jammer_methods = list( + /crew_sensor_modifier/general = /crew_sensor_modifier/general/jamming/binary + ) + +/suit_sensor_jammer_method/cap_vital + name = "Cap Data - Vital" + energy_cost = 1 + jammer_methods = list( + /crew_sensor_modifier/general = /crew_sensor_modifier/general/jamming/vital + ) diff --git a/code/datums/sun.dm b/code/datums/sun.dm new file mode 100644 index 00000000..de10a953 --- /dev/null +++ b/code/datums/sun.dm @@ -0,0 +1,58 @@ +#define SOLAR_UPDATE_TIME 600 //duration between two updates of the whole sun/solars positions + +/datum/sun + var/angle + var/dx + var/dy + var/rate + var/list/solars // for debugging purposes, references solars_list at the constructor + var/solar_next_update // last time the sun position was checked and adjusted + +/datum/sun/New() + + solars = solars_list + rate = rand(50,200)/100 // 50% - 200% of standard rotation + if(prob(50)) // same chance to rotate clockwise than counter-clockwise + rate = -rate + solar_next_update = world.time // init the timer + angle = rand (0,359) // the station position to the sun is randomised at round start + +/*/hook/startup/proc/createSun() // handled in scheduler + sun = new /datum/sun() + return 1*/ + +// calculate the sun's position given the time of day +// at the standard rate (100%) the angle is increase/decreased by 6 degrees every minute. +// a full rotation thus take a game hour in that case +/datum/sun/proc/calc_position() + + if(world.time < solar_next_update) //if less than 60 game secondes have passed, do nothing + return; + + angle = (angle + rate * 6) % 360 // increase/decrease the angle to the sun, adjusted by the rate + + solar_next_update += SOLAR_UPDATE_TIME // since we updated the angle, set the proper time for the next loop + + // now calculate and cache the (dx,dy) increments for line drawing + + var/s = sin(angle) + var/c = cos(angle) + + // Either "abs(s) < abs(c)" or "abs(s) >= abs(c)" + // In both cases, the greater is greater than 0, so, no "if 0" check is needed for the divisions + + if( abs(s) < abs(c)) + + dx = s / abs(c) + dy = c / abs(c) + + else + dx = s/abs(s) + dy = c / abs(s) + + //now tell the solar control computers to update their status and linked devices + for(var/obj/machinery/power/solar_control/SC in solars_list) + if(!SC.powernet) + solars_list.Remove(SC) + continue + SC.update() diff --git a/code/datums/supplypacks/atmospherics.dm b/code/datums/supplypacks/atmospherics.dm new file mode 100644 index 00000000..260d5a63 --- /dev/null +++ b/code/datums/supplypacks/atmospherics.dm @@ -0,0 +1,113 @@ +/decl/hierarchy/supply_pack/atmospherics + name = "Atmospherics" + containertype = /obj/structure/closet/crate/internals + +/decl/hierarchy/supply_pack/atmospherics/internals + name = "Internals crate" + contains = list(/obj/item/clothing/mask/gas = 3, + /obj/item/weapon/tank/air = 3) + cost = 10 + containername = "\improper Internals crate" + +/decl/hierarchy/supply_pack/atmospherics/evacuation + name = "Emergency equipment" + contains = list(/obj/item/weapon/storage/toolbox/emergency = 2, + /obj/item/clothing/suit/storage/hazardvest = 2, + /obj/item/clothing/suit/armor/vest = 2, + /obj/item/weapon/tank/emergency/oxygen/engi = 4, + /obj/item/clothing/suit/space/emergency = 4, + /obj/item/clothing/head/helmet/space/emergency = 4, + /obj/item/clothing/mask/gas = 4, + /obj/item/device/flashlight/glowstick = 5) + cost = 45 + + containername = "\improper Emergency crate" + +/decl/hierarchy/supply_pack/atmospherics/inflatable + name = "Inflatable barriers" + contains = list(/obj/item/weapon/storage/briefcase/inflatable = 3) + cost = 20 + containertype = /obj/structure/closet/crate + containername = "\improper Inflatable Barrier Crate" + +/decl/hierarchy/supply_pack/atmospherics/canister_empty + name = "Empty gas canister" + contains = list(/obj/machinery/portable_atmospherics/canister) + cost = 7 + containername = "\improper Empty gas canister crate" + containertype = /obj/structure/largecrate + +/decl/hierarchy/supply_pack/atmospherics/canister_air + name = "Air canister" + contains = list(/obj/machinery/portable_atmospherics/canister/air) + cost = 10 + containername = "\improper Air canister crate" + containertype = /obj/structure/largecrate + +/decl/hierarchy/supply_pack/atmospherics/canister_oxygen + name = "Oxygen canister" + contains = list(/obj/machinery/portable_atmospherics/canister/oxygen) + cost = 15 + containername = "\improper Oxygen canister crate" + containertype = /obj/structure/largecrate + +/decl/hierarchy/supply_pack/atmospherics/canister_nitrogen + name = "Nitrogen canister" + contains = list(/obj/machinery/portable_atmospherics/canister/nitrogen) + cost = 10 + containername = "\improper Nitrogen canister crate" + containertype = /obj/structure/largecrate + +/decl/hierarchy/supply_pack/atmospherics/canister_phoron + name = "Phoron gas canister" + contains = list(/obj/machinery/portable_atmospherics/canister/phoron) + cost = 70 + containername = "\improper Phoron gas canister crate" + containertype = /obj/structure/closet/crate/secure/large + access = access_atmospherics + +/decl/hierarchy/supply_pack/atmospherics/canister_hydrogen + name = "Hydrogen canister" + contains = list(/obj/machinery/portable_atmospherics/canister/hydrogen) + cost = 25 + containername = "\improper Hydrogen canister crate" + containertype = /obj/structure/closet/crate/secure/large + access = access_atmospherics + +/decl/hierarchy/supply_pack/atmospherics/canister_sleeping_agent + name = "N2O gas canister" + contains = list(/obj/machinery/portable_atmospherics/canister/sleeping_agent) + cost = 40 + containername = "\improper N2O gas canister crate" + containertype = /obj/structure/closet/crate/secure/large + access = access_atmospherics + +/decl/hierarchy/supply_pack/atmospherics/canister_carbon_dioxide + name = "Carbon dioxide gas canister" + contains = list(/obj/machinery/portable_atmospherics/canister/carbon_dioxide) + cost = 40 + containername = "\improper CO2 canister crate" + containertype = /obj/structure/closet/crate/secure/large + access = access_atmospherics + +/decl/hierarchy/supply_pack/atmospherics/fuel + name = "Fuel tank crate" + contains = list(/obj/item/weapon/tank/hydrogen = 4) + cost = 15 + containername = "\improper Fuel tank crate" + +/decl/hierarchy/supply_pack/atmospherics/phoron + name = "Phoron tank crate" + contains = list(/obj/item/weapon/tank/phoron = 3) + cost = 30 + containername = "\improper Phoron tank crate" + +/decl/hierarchy/supply_pack/atmospherics/voidsuit + name = "Atmospherics voidsuit" + contains = list(/obj/item/clothing/suit/space/void/atmos/alt, + /obj/item/clothing/head/helmet/space/void/atmos/alt, + /obj/item/clothing/shoes/magboots) + cost = 120 + containername = "\improper Atmospherics voidsuit crate" + containertype = /obj/structure/closet/crate/secure/large + access = access_atmospherics diff --git a/code/datums/supplypacks/engineering.dm b/code/datums/supplypacks/engineering.dm new file mode 100644 index 00000000..4e0fc2d6 --- /dev/null +++ b/code/datums/supplypacks/engineering.dm @@ -0,0 +1,256 @@ +/decl/hierarchy/supply_pack/engineering + name = "Engineering" + +/decl/hierarchy/supply_pack/engineering/lightbulbs + name = "Replacement lights" + contains = list(/obj/item/weapon/storage/box/lights/mixed = 3) + cost = 10 + containername = "\improper Replacement lights" + +/decl/hierarchy/supply_pack/engineering/smes_circuit + name = "Superconducting Magnetic Energy Storage Unit Circuitry" + contains = list(/obj/item/weapon/circuitboard/smes) + cost = 20 + containername = "\improper Superconducting Magnetic Energy Storage Unit Circuitry" + +/decl/hierarchy/supply_pack/engineering/smescoil + name = "Superconductive Magnetic Coil" + contains = list(/obj/item/weapon/smes_coil) + cost = 35 + containername = "\improper Superconductive Magnetic Coil crate" + +/decl/hierarchy/supply_pack/engineering/smescoil_weak + name = "Basic Superconductive Magnetic Coil" + contains = list(/obj/item/weapon/smes_coil/weak) + cost = 25 + containername = "\improper Basic Superconductive Magnetic Coil crate" + +/decl/hierarchy/supply_pack/engineering/smescoil_super_capacity + name = "Superconductive Capacitance Coil" + contains = list(/obj/item/weapon/smes_coil/super_capacity) + cost = 45 + containername = "\improper Superconductive Capacitance Coil crate" + +/decl/hierarchy/supply_pack/engineering/smescoil_super_io + name = "Superconductive Transmission Coil" + contains = list(/obj/item/weapon/smes_coil/super_io) + cost = 45 + containername = "\improper Superconductive Transmission Coil crate" + +/decl/hierarchy/supply_pack/engineering/electrical + name = "Electrical maintenance crate" + contains = list(/obj/item/weapon/storage/toolbox/electrical = 2, + /obj/item/clothing/gloves/insulated = 2, + /obj/item/weapon/cell = 2, + /obj/item/weapon/cell/high = 2) + cost = 15 + containername = "\improper Electrical maintenance crate" + +/decl/hierarchy/supply_pack/engineering/mechanical + name = "Mechanical maintenance crate" + contains = list(/obj/item/weapon/storage/belt/utility/full = 3, + /obj/item/clothing/suit/storage/hazardvest = 3, + /obj/item/clothing/head/welding = 2, + /obj/item/clothing/head/hardhat) + cost = 10 + containername = "\improper Mechanical maintenance crate" + +/decl/hierarchy/supply_pack/engineering/solar + name = "Solar Pack crate" + contains = list(/obj/item/solar_assembly = 14, + /obj/item/weapon/circuitboard/solar_control, + /obj/item/weapon/tracker_electronics, + /obj/item/weapon/paper/solar + ) + cost = 15 + containername = "\improper Solar Pack crate" + +/decl/hierarchy/supply_pack/engineering/solar_assembly + name = "Solar Assembly crate" + contains = list(/obj/item/solar_assembly = 16) + cost = 10 + containername = "\improper Solar Assembly crate" + +/decl/hierarchy/supply_pack/engineering/emitter + name = "Emitter crate" + contains = list(/obj/machinery/power/emitter = 2) + cost = 10 + containertype = /obj/structure/closet/crate/secure/large + containername = "\improper Emitter crate" + access = access_engine_equip + +/decl/hierarchy/supply_pack/engineering/field_gen + name = "Field Generator crate" + contains = list(/obj/machinery/field_generator = 2) + containertype = /obj/structure/closet/crate/large + cost = 10 + containername = "\improper Field Generator crate" + access = access_ce + +/decl/hierarchy/supply_pack/engineering/sing_gen + name = "Singularity Generator crate" + contains = list(/obj/machinery/the_singularitygen) + cost = 10 + containertype = /obj/structure/closet/crate/secure/large + containername = "\improper Singularity Generator crate" + access = access_ce + +/decl/hierarchy/supply_pack/engineering/collector + name = "Collector crate" + contains = list(/obj/machinery/power/rad_collector = 2) + cost = 6 + containertype = /obj/structure/closet/crate/secure/large + containername = "\improper Collector crate" + access = access_engine_equip + +/decl/hierarchy/supply_pack/engineering/PA + name = "Particle Accelerator crate" + contains = list(/obj/structure/particle_accelerator/fuel_chamber, + /obj/machinery/particle_accelerator/control_box, + /obj/structure/particle_accelerator/particle_emitter/center, + /obj/structure/particle_accelerator/particle_emitter/left, + /obj/structure/particle_accelerator/particle_emitter/right, + /obj/structure/particle_accelerator/power_box, + /obj/structure/particle_accelerator/end_cap) + cost = 40 + containertype = /obj/structure/largecrate + containername = "\improper Particle Accelerator crate" + access = access_ce + +/decl/hierarchy/supply_pack/engineering/pacman_parts + name = "P.A.C.M.A.N. portable generator parts" + contains = list(/obj/item/weapon/stock_parts/micro_laser, + /obj/item/weapon/stock_parts/capacitor, + /obj/item/weapon/stock_parts/matter_bin, + /obj/item/weapon/circuitboard/pacman) + cost = 45 + containername = "\improper P.A.C.M.A.N. Portable Generator Construction Kit" + containertype = /obj/structure/closet/crate/secure + access = access_tech_storage + +/decl/hierarchy/supply_pack/engineering/super_pacman_parts + name = "Super P.A.C.M.A.N. portable generator parts" + contains = list(/obj/item/weapon/stock_parts/micro_laser, + /obj/item/weapon/stock_parts/capacitor, + /obj/item/weapon/stock_parts/matter_bin, + /obj/item/weapon/circuitboard/pacman/super) + cost = 55 + containername = "\improper Super P.A.C.M.A.N. portable generator construction kit" + containertype = /obj/structure/closet/crate/secure + access = access_tech_storage + +/decl/hierarchy/supply_pack/engineering/teg + name = "Mark I Thermoelectric Generator" + contains = list(/obj/machinery/power/generator) + cost = 75 + containertype = /obj/structure/closet/crate/secure/large + containername = "\improper Mk1 TEG crate" + access = access_engine_equip + +/decl/hierarchy/supply_pack/engineering/circulator + name = "Binary atmospheric circulator" + contains = list(/obj/machinery/atmospherics/binary/circulator) + cost = 60 + containertype = /obj/structure/closet/crate/secure/large + containername = "\improper Atmospheric circulator crate" + access = access_atmospherics + +/decl/hierarchy/supply_pack/engineering/air_dispenser + name = "Pipe Dispenser" + contains = list(/obj/machinery/pipedispenser/orderable) + cost = 35 + containertype = /obj/structure/closet/crate/secure/large + containername = "\improper Pipe Dispenser Crate" + access = access_atmospherics + +/decl/hierarchy/supply_pack/engineering/disposals_dispenser + name = "Disposals Pipe Dispenser" + contains = list(/obj/machinery/pipedispenser/disposal/orderable) + cost = 35 + containertype = /obj/structure/closet/crate/secure/large + containername = "\improper Disposal Dispenser Crate" + access = access_atmospherics + +/decl/hierarchy/supply_pack/engineering/shield_generator + name = "Shield Generator Construction Kit" + contains = list(/obj/item/weapon/circuitboard/shield_generator, /obj/item/weapon/stock_parts/capacitor, /obj/item/weapon/stock_parts/micro_laser, /obj/item/weapon/smes_coil, /obj/item/weapon/stock_parts/console_screen) + cost = 50 + containertype = /obj/structure/closet/crate/secure + containername = "\improper shield generator construction kit crate" + access = access_engine + +/decl/hierarchy/supply_pack/engineering/smbig + name = "Supermatter Core" + contains = list(/obj/machinery/power/supermatter) + cost = 150 + containertype = /obj/structure/closet/crate/secure/large/phoron + containername = "\improper Supermatter crate (CAUTION)" + access = access_ce + +/decl/hierarchy/supply_pack/engineering/fueltank + name = "Fuel tank crate" + contains = list(/obj/structure/reagent_dispensers/fueltank) + cost = 8 + containertype = /obj/structure/largecrate + containername = "\improper fuel tank crate" + +/decl/hierarchy/supply_pack/engineering/robotics + name = "Robotics assembly crate" + contains = list(/obj/item/device/assembly/prox_sensor = 3, + /obj/item/weapon/storage/toolbox/electrical, + /obj/item/device/flash = 4, + /obj/item/weapon/cell/high = 2) + cost = 10 + containertype = /obj/structure/closet/crate/secure/gear + containername = "\improper Robotics assembly" + access = access_robotics + +/decl/hierarchy/supply_pack/engineering/radsuit + name = "Radiation protection gear" + contains = list(/obj/item/clothing/suit/radiation = 6, + /obj/item/clothing/head/radiation = 6) + cost = 20 + containertype = /obj/structure/closet/radiation + containername = "\improper Radiation suit locker" + +/decl/hierarchy/supply_pack/engineering/painters + name = "Painting Supplies" + contains = list(/obj/item/device/pipe_painter = 2, + /obj/item/device/floor_painter = 2, + /obj/item/device/cable_painter = 2) + cost = 10 + containername = "\improper painting supplies crate" + containertype = /obj/structure/closet/crate + +/decl/hierarchy/supply_pack/engineering/bluespacerelay + name = "Emergency Bluespace Relay Assembly Kit" + contains = list(/obj/item/weapon/circuitboard/bluespacerelay, + /obj/item/weapon/stock_parts/manipulator, + /obj/item/weapon/stock_parts/manipulator, + /obj/item/weapon/stock_parts/subspace/filter, + /obj/item/weapon/stock_parts/subspace/crystal, + /obj/item/weapon/storage/toolbox/electrical) + cost = 75 + containername = "\improper emergency bluespace relay assembly kit" + +/decl/hierarchy/supply_pack/engineering/firefighter + name = "Firefighting equipment" + contains = list(/obj/item/clothing/suit/fire/firefighter, + /obj/item/clothing/mask/gas, + /obj/item/weapon/tank/oxygen/red, + /obj/item/weapon/extinguisher, + /obj/item/clothing/head/hardhat/red) + cost = 20 + containertype = /obj/structure/closet/firecloset + containername = "\improper fire-safety closet" +/* +/decl/hierarchy/supply_pack/engineering/voidsuit + name = "Engineering voidsuit" + contains = list(/obj/item/clothing/suit/space/void/engineering/alt, + /obj/item/clothing/head/helmet/space/void/engineering/alt, + /obj/item/clothing/shoes/magboots) + cost = 120 + containername = "\improper Engineering voidsuit crate" + containertype = /obj/structure/closet/crate/secure/large + access = access_engine +*/ \ No newline at end of file diff --git a/code/datums/supplypacks/hospitality.dm b/code/datums/supplypacks/hospitality.dm new file mode 100644 index 00000000..688196d1 --- /dev/null +++ b/code/datums/supplypacks/hospitality.dm @@ -0,0 +1,107 @@ +/decl/hierarchy/supply_pack/hospitality + name = "Hospitality" + +/decl/hierarchy/supply_pack/hospitality/party + name = "Party equipment" + contains = list( + /obj/item/weapon/storage/box/mixedglasses = 2, + /obj/item/weapon/storage/box/glasses/square, + /obj/item/weapon/reagent_containers/food/drinks/shaker, + /obj/item/weapon/reagent_containers/food/drinks/flask/barflask, + /obj/item/weapon/reagent_containers/food/drinks/bottle/patron, + /obj/item/weapon/reagent_containers/food/drinks/bottle/goldschlager, + /obj/item/weapon/reagent_containers/food/drinks/bottle/specialwhiskey, + /obj/item/weapon/storage/fancy/cigarettes/dromedaryco, + /obj/item/weapon/lipstick/random, + /obj/item/weapon/reagent_containers/food/drinks/bottle/small/ale = 2, + /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer = 4, + /obj/item/weapon/storage/box/glowsticks = 2, + /obj/item/weapon/clothingbag/rubbermask, + /obj/item/weapon/clothingbag/rubbersuit) + cost = 20 + containername = "\improper Party equipment" + +// TODO; Add more premium drinks at a later date. Could be useful for diplomatic events or fancy parties. +/decl/hierarchy/supply_pack/hospitality/premiumalcohol + name = "Premium drinks crate" + contains = list(/obj/item/weapon/reagent_containers/food/drinks/bottle/premiumwine = 1, + /obj/item/weapon/reagent_containers/food/drinks/bottle/premiumvodka = 1) + cost = 60 + containertype = /obj/structure/closet/crate/freezer + containername = "\improper Premium drinks" + +/decl/hierarchy/supply_pack/hospitality/barsupplies + name = "Bar supplies" + contains = list( + /obj/item/weapon/storage/box/glasses/cocktail, + /obj/item/weapon/storage/box/glasses/rocks, + /obj/item/weapon/storage/box/glasses/square, + /obj/item/weapon/storage/box/glasses/pint, + /obj/item/weapon/storage/box/glasses/wine, + /obj/item/weapon/storage/box/glasses/shake, + /obj/item/weapon/storage/box/glasses/shot, + /obj/item/weapon/storage/box/glasses/mug, + /obj/item/weapon/reagent_containers/food/drinks/shaker, + /obj/item/weapon/storage/box/glass_extras/straws, + /obj/item/weapon/storage/box/glass_extras/sticks + ) + cost = 10 + containername = "crate of bar supplies" + +/decl/hierarchy/supply_pack/hospitality/lasertag + name = "Lasertag equipment" + contains = list(/obj/item/weapon/gun/energy/lasertag/red = 3, + /obj/item/clothing/suit/redtag = 3, + /obj/item/weapon/gun/energy/lasertag/blue = 3, + /obj/item/clothing/suit/bluetag = 3) + cost = 20 + containertype = /obj/structure/closet + containername = "\improper Lasertag Closet" + +/decl/hierarchy/supply_pack/hospitality/pizza + num_contained = 5 + name = "Surprise pack of five pizzas" + contains = list(/obj/item/pizzabox/margherita, + /obj/item/pizzabox/mushroom, + /obj/item/pizzabox/meat, + /obj/item/pizzabox/vegetable) + cost = 15 + containertype = /obj/structure/closet/crate/freezer + containername = "\improper Pizza crate" + supply_method = /decl/supply_method/randomized + + +/decl/hierarchy/supply_pack/hospitality/beef + name = "Beef crate" + contains = list(/obj/item/weapon/reagent_containers/food/snacks/meat/beef = 6) + containertype = /obj/structure/closet/crate/freezer + containername = "\improper Beef crate" + cost = 20 + +/decl/hierarchy/supply_pack/hospitality/goat + name = "Goat meat crate" + contains = list(/obj/item/weapon/reagent_containers/food/snacks/meat/goat = 6) + containertype = /obj/structure/closet/crate/freezer + containername = "\improper Goat meat crate" + cost = 20 + +/decl/hierarchy/supply_pack/hospitality/chicken + name = "Chicken meat crate" + contains = list(/obj/item/weapon/reagent_containers/food/snacks/meat/chicken = 6) + containertype = /obj/structure/closet/crate/freezer + containername = "\improper Chicken meat crate" + cost = 20 + +/decl/hierarchy/supply_pack/hospitality/eggs + name = "Eggs crate" + contains = list(/obj/item/weapon/storage/fancy/egg_box = 2) + containertype = /obj/structure/closet/crate/freezer + containername = "\improper Egg crate" + cost = 15 + +/decl/hierarchy/supply_pack/hospitality/milk + name = "Milk crate" + contains = list(/obj/item/weapon/reagent_containers/food/drinks/milk = 3) + containertype = /obj/structure/closet/crate/freezer + containername = "\improper Milk crate" + cost = 15 \ No newline at end of file diff --git a/code/datums/supplypacks/hydroponics.dm b/code/datums/supplypacks/hydroponics.dm new file mode 100644 index 00000000..b036b46a --- /dev/null +++ b/code/datums/supplypacks/hydroponics.dm @@ -0,0 +1,171 @@ +/decl/hierarchy/supply_pack/hydroponics + name = "Hydroponics" + containertype = /obj/structure/closet/crate/hydroponics + +/decl/hierarchy/supply_pack/hydroponics/monkey + name = "Monkey crate" + contains = list (/obj/item/weapon/storage/box/monkeycubes) + cost = 20 + containertype = /obj/structure/closet/crate/freezer + containername = "\improper Monkey crate" + +/decl/hierarchy/supply_pack/hydroponics/farwa + name = "Farwa crate" + contains = list (/obj/item/weapon/storage/box/monkeycubes/farwacubes) + cost = 30 + containertype = /obj/structure/closet/crate/freezer + containername = "\improper Farwa crate" + +/decl/hierarchy/supply_pack/hydroponics/skrell + name = "Neaera crate" + contains = list (/obj/item/weapon/storage/box/monkeycubes/neaeracubes) + cost = 30 + containertype = /obj/structure/closet/crate/freezer + containername = "\improper Neaera crate" + +/decl/hierarchy/supply_pack/hydroponics/stok + name = "Stok crate" + contains = list (/obj/item/weapon/storage/box/monkeycubes/stokcubes) + cost = 30 + containertype = /obj/structure/closet/crate/freezer + containername = "\improper Stok crate" + +/decl/hierarchy/supply_pack/hydroponics/corgi + name = "Corgi crate" + contains = list() + cost = 50 + containertype = /obj/structure/largecrate/animal/corgi + containername = "\improper Corgi crate" + +//farm animals - useless and annoying, but potentially a good source of food. expensive because they're live animals and their produce is available cheaper +/decl/hierarchy/supply_pack/hydroponics/cow + name = "Cow crate" + cost = 80 + containertype = /obj/structure/largecrate/animal/cow + containername = "\improper Cow crate" + access = access_hydroponics + +/decl/hierarchy/supply_pack/hydroponics/goat + name = "Goat crate" + cost = 75 + containertype = /obj/structure/largecrate/animal/goat + containername = "\improper Goat crate" + access = access_hydroponics + +/decl/hierarchy/supply_pack/hydroponics/chicken + name = "Chicken crate" + cost = 70 + containertype = /obj/structure/largecrate/animal/chick + containername = "\improper Chicken crate" + access = access_hydroponics + +/decl/hierarchy/supply_pack/hydroponics/hydroponics // -- Skie + name = "Hydroponics Supply Crate" + contains = list(/obj/item/weapon/reagent_containers/spray/plantbgone = 4, + /obj/item/weapon/reagent_containers/glass/bottle/ammonia = 2, + /obj/item/weapon/material/hatchet, + /obj/item/weapon/material/minihoe, + /obj/item/device/analyzer/plant_analyzer, + /obj/item/clothing/gloves/thick/botany, + /obj/item/clothing/suit/apron, + /obj/item/weapon/material/minihoe, + /obj/item/weapon/storage/box/botanydisk + ) + cost = 15 + containername = "\improper Hydroponics crate" + access = access_hydroponics + +/decl/hierarchy/supply_pack/hydroponics/seeds + name = "Seeds crate" + contains = list(/obj/item/seeds/chiliseed, + /obj/item/seeds/berryseed, + /obj/item/seeds/cornseed, + /obj/item/seeds/eggplantseed, + /obj/item/seeds/tomatoseed, + /obj/item/seeds/appleseed, + /obj/item/seeds/soyaseed, + /obj/item/seeds/wheatseed, + /obj/item/seeds/carrotseed, + /obj/item/seeds/harebell, + /obj/item/seeds/lemonseed, + /obj/item/seeds/orangeseed, + /obj/item/seeds/grassseed, + /obj/item/seeds/sunflowerseed, + /obj/item/seeds/chantermycelium, + /obj/item/seeds/potatoseed, + /obj/item/seeds/sugarcaneseed) + cost = 10 + containername = "\improper Seeds crate" + access = access_hydroponics + +/decl/hierarchy/supply_pack/hydroponics/weedcontrol + name = "Weed control crate" + contains = list(/obj/item/weapon/material/hatchet = 2, + /obj/item/weapon/reagent_containers/spray/plantbgone = 4, + /obj/item/clothing/mask/gas = 2, + /obj/item/weapon/grenade/chem_grenade/antiweed = 2) + cost = 25 + containername = "\improper Weed control crate" + access = access_hydroponics + +/decl/hierarchy/supply_pack/hydroponics/exoticseeds + name = "Exotic seeds crate" + contains = list(/obj/item/seeds/replicapod = 2, + /obj/item/seeds/libertymycelium, + /obj/item/seeds/reishimycelium, + /obj/item/seeds/random = 6, + /obj/item/seeds/kudzuseed) + cost = 15 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Exotic Seeds crate" + access = access_xenobiology + +/decl/hierarchy/supply_pack/hydroponics/watertank + name = "Water tank crate" + contains = list(/obj/structure/reagent_dispensers/watertank) + cost = 8 + containertype = /obj/structure/largecrate + containername = "\improper water tank crate" + +/decl/hierarchy/supply_pack/hydroponics/hydrotray + name = "Empty hydroponics tray" + contains = list(/obj/machinery/portable_atmospherics/hydroponics{anchored = 0}) + cost = 30 + containertype = /obj/structure/closet/crate/large/hydroponics + containername = "\improper Hydroponics tray crate" + access = access_hydroponics + +/decl/hierarchy/supply_pack/hydroponics/pottedplant + name = "Potted plant crate" + num_contained = 1 + contains = list(/obj/structure/flora/pottedplant, + /obj/structure/flora/pottedplant/large, + /obj/structure/flora/pottedplant/fern, + /obj/structure/flora/pottedplant/overgrown, + /obj/structure/flora/pottedplant/bamboo, + /obj/structure/flora/pottedplant/largebush, + /obj/structure/flora/pottedplant/thinbush, + /obj/structure/flora/pottedplant/mysterious, + /obj/structure/flora/pottedplant/smalltree, + /obj/structure/flora/pottedplant/unusual, + /obj/structure/flora/pottedplant/orientaltree, + /obj/structure/flora/pottedplant/smallcactus, + /obj/structure/flora/pottedplant/tall, + /obj/structure/flora/pottedplant/sticky, + /obj/structure/flora/pottedplant/smelly, + /obj/structure/flora/pottedplant/small, + /obj/structure/flora/pottedplant/aquatic, + /obj/structure/flora/pottedplant/shoot, + /obj/structure/flora/pottedplant/flower, + /obj/structure/flora/pottedplant/crystal, + /obj/structure/flora/pottedplant/subterranean, + /obj/structure/flora/pottedplant/minitree, + /obj/structure/flora/pottedplant/stoutbush, + /obj/structure/flora/pottedplant/drooping, + /obj/structure/flora/pottedplant/tropical, + /obj/structure/flora/pottedplant/dead, + /obj/structure/flora/pottedplant/decorative) + cost = 3 + containertype = /obj/structure/closet/crate/large/hydroponics + containername = "\improper Potted plant crate" + supply_method = /decl/supply_method/randomized \ No newline at end of file diff --git a/code/datums/supplypacks/materials.dm b/code/datums/supplypacks/materials.dm new file mode 100644 index 00000000..a7bd3a8d --- /dev/null +++ b/code/datums/supplypacks/materials.dm @@ -0,0 +1,96 @@ +/decl/hierarchy/supply_pack/materials + name = "Materials" + +// Material sheets (50 - full stack) +/decl/hierarchy/supply_pack/materials/steel50 + name = "50 steel sheets" + contains = list(/obj/item/stack/material/steel/fifty) + cost = 10 + containername = "\improper Steel sheets crate" + +/decl/hierarchy/supply_pack/materials/glass50 + name = "50 glass sheets" + contains = list(/obj/item/stack/material/glass/fifty) + cost = 10 + containername = "\improper Glass sheets crate" + +/decl/hierarchy/supply_pack/materials/wood50 + name = "50 wooden planks" + contains = list(/obj/item/stack/material/wood/fifty) + cost = 10 + containername = "\improper Wooden planks crate" + +/decl/hierarchy/supply_pack/materials/plastic50 + name = "50 plastic sheets" + contains = list(/obj/item/stack/material/plastic/fifty) + cost = 10 + containername = "\improper Plastic sheets crate" + +/decl/hierarchy/supply_pack/materials/marble50 + name = "50 slabs of marble" + contains = list(/obj/item/stack/material/marble/fifty) + cost = 60 + containername = "\improper Marble slabs crate" + +/decl/hierarchy/supply_pack/materials/plasteel50 + name = "50 plasteel sheets" + contains = list(/obj/item/stack/material/plasteel/fifty) + cost = 80 + containername = "\improper Plasteel sheets crate" + +/decl/hierarchy/supply_pack/materials/ocp50 + name = "50 osmium carbide plasteel sheets" + contains = list(/obj/item/stack/material/ocp/fifty) + cost = 100 + containername = "\improper Osmium carbide plasteel sheets crate" + +// Material sheets (10 - Smaller amounts, less cost efficient) +/decl/hierarchy/supply_pack/materials/marble10 + name = "10 slabs of marble" + contains = list(/obj/item/stack/material/marble/ten) + cost = 20 + containername = "\improper Marble slabs crate" + +/decl/hierarchy/supply_pack/materials/plasteel10 + name = "10 plasteel sheets" + contains = list(/obj/item/stack/material/plasteel/ten) + cost = 25 + containername = "\improper Plasteel sheets crate" + +/decl/hierarchy/supply_pack/materials/ocp10 + name = "10 osmium carbide plasteel sheets" + contains = list(/obj/item/stack/material/ocp/ten) + cost = 30 + containername = "\improper Osmium carbide plasteel sheets crate" + +// Material sheets of expensive materials. These are very expensive and therefore pretty hard +// to get without mining crew that would bring materials to sell in exchange. +/decl/hierarchy/supply_pack/materials/phoron10 + name = "10 phoron sheets" + contains = list(/obj/item/stack/material/phoron/ten) + cost = 75 // When sold yields 67 points. + containername = "\improper Phoron sheets crate" + +/decl/hierarchy/supply_pack/materials/gold10 + name = "10 gold sheets" + contains = list(/obj/item/stack/material/gold/ten) + cost = 100 + containername = "\improper Gold sheets crate" + +/decl/hierarchy/supply_pack/materials/silver10 + name = "10 silver sheets" + contains = list(/obj/item/stack/material/silver/ten) + cost = 100 + containername = "\improper Silver sheets crate" + +/decl/hierarchy/supply_pack/materials/uranium10 + name = "10 uranium sheets" + contains = list(/obj/item/stack/material/uranium/ten) + cost = 125 + containername = "\improper Uranium sheets crate" + +/decl/hierarchy/supply_pack/materials/diamond10 + name = "10 diamond sheets" + contains = list(/obj/item/stack/material/diamond/ten) + cost = 200 + containername = "\improper Diamond sheets crate" \ No newline at end of file diff --git a/code/datums/supplypacks/medical.dm b/code/datums/supplypacks/medical.dm new file mode 100644 index 00000000..e0110cc4 --- /dev/null +++ b/code/datums/supplypacks/medical.dm @@ -0,0 +1,279 @@ +/decl/hierarchy/supply_pack/medical + name = "Medical" + containertype = /obj/structure/closet/crate/medical + +/decl/hierarchy/supply_pack/medical/medical + name = "Medical crate" + contains = list(/obj/item/weapon/storage/firstaid/regular, + /obj/item/weapon/storage/firstaid/fire, + /obj/item/weapon/storage/firstaid/toxin, + /obj/item/weapon/storage/firstaid/o2, + /obj/item/weapon/storage/firstaid/adv, + /obj/item/weapon/reagent_containers/glass/bottle/antitoxin, + /obj/item/weapon/reagent_containers/glass/bottle/inaprovaline, + /obj/item/weapon/reagent_containers/glass/bottle/stoxin, + /obj/item/weapon/storage/box/syringes, + /obj/item/weapon/storage/box/autoinjectors) + cost = 10 + containername = "\improper Medical crate" + +/decl/hierarchy/supply_pack/medical/bloodpack + name = "Blood pack crate" + contains = list(/obj/item/weapon/storage/box/bloodpacks = 3) + cost = 10 + containername = "\improper Blood pack crate" + +/decl/hierarchy/supply_pack/medical/blood + name = "Nanoblood crate" + contains = list(/obj/item/weapon/reagent_containers/ivbag/nanoblood = 4) + cost = 15 + containername = "\improper Nanoblood crate" + +/decl/hierarchy/supply_pack/medical/bodybag + name = "Body bag crate" + contains = list(/obj/item/weapon/storage/box/bodybags = 3) + cost = 10 + containername = "\improper Body bag crate" + +/decl/hierarchy/supply_pack/medical/cryobag + name = "Stasis bag crate" + contains = list(/obj/item/bodybag/cryobag = 3) + cost = 50 + containername = "\improper Stasis bag crate" + +/decl/hierarchy/supply_pack/medical/medicalextragear + name = "Medical surplus equipment" + contains = list(/obj/item/weapon/storage/belt/medical = 3, + /obj/item/clothing/glasses/hud/health = 3) + cost = 15 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Medical surplus equipment" + access = access_medical + +/decl/hierarchy/supply_pack/medical/cmogear + name = "Chief medical officer equipment" + contains = list(/obj/item/weapon/storage/belt/medical, + /obj/item/device/radio/headset/heads/cmo, + /obj/item/clothing/under/rank/chief_medical_officer, + /obj/item/weapon/reagent_containers/hypospray/vial, + /obj/item/clothing/accessory/stethoscope, + /obj/item/clothing/glasses/hud/health, + /obj/item/clothing/suit/storage/toggle/labcoat/cmo, + /obj/item/clothing/suit/storage/toggle/labcoat/cmoalt, + /obj/item/clothing/mask/surgical, + /obj/item/clothing/shoes/white, + /obj/item/weapon/cartridge/cmo, + /obj/item/clothing/gloves/latex, + /obj/item/device/healthanalyzer, + /obj/item/device/flashlight/pen, + /obj/item/weapon/reagent_containers/syringe) + cost = 60 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Chief medical officer equipment" + access = access_cmo +/* +/decl/hierarchy/supply_pack/medical/doctorgear + name = "Medical Doctor equipment" + contains = list(/obj/item/weapon/storage/belt/medical, + /obj/item/device/radio/headset/headset_med, + /obj/item/clothing/under/rank/medical, + /obj/item/clothing/accessory/stethoscope, + /obj/item/clothing/glasses/hud/health, + /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/clothing/mask/surgical, + /obj/item/weapon/storage/firstaid/adv, + /obj/item/clothing/shoes/white, + /obj/item/weapon/cartridge/medical, + /obj/item/clothing/gloves/latex, + /obj/item/device/healthanalyzer, + /obj/item/device/flashlight/pen, + /obj/item/weapon/reagent_containers/syringe) + cost = 20 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Medical Doctor equipment" + access = access_medical_equip +*/ + +/decl/hierarchy/supply_pack/medical/chemistgear + name = "Chemist equipment" + contains = list(/obj/item/weapon/storage/box/beakers, + /obj/item/device/radio/headset/headset_med, + /obj/item/weapon/storage/box/autoinjectors, + /obj/item/clothing/under/rank/chemist, + /obj/item/clothing/glasses/science, + /obj/item/clothing/suit/storage/toggle/labcoat/chemist, + /obj/item/clothing/mask/surgical, + /obj/item/clothing/shoes/white, + /obj/item/weapon/cartridge/chemistry, + /obj/item/clothing/gloves/latex, + /obj/item/weapon/reagent_containers/dropper, + /obj/item/device/healthanalyzer, + /obj/item/weapon/storage/box/pillbottles, + /obj/item/weapon/reagent_containers/syringe) + cost = 15 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Chemist equipment" + access = access_chemistry + +/decl/hierarchy/supply_pack/medical/paramedicgear + name = "Paramedic equipment" + contains = list(/obj/item/weapon/storage/belt/medical/emt, + /obj/item/device/radio/headset/headset_med, + /obj/item/clothing/under/rank/medical/scrubs/black, + /obj/item/clothing/accessory/armband/medgreen, + /obj/item/clothing/glasses/hud/health, + /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/clothing/under/rank/medical/paramedic, + /obj/item/clothing/suit/storage/toggle/fr_jacket, + /obj/item/clothing/mask/gas, + /obj/item/clothing/under/rank/medical/paramedic, + /obj/item/clothing/accessory/stethoscope, + /obj/item/weapon/storage/firstaid/adv, + /obj/item/clothing/shoes/jackboots, + /obj/item/clothing/gloves/latex, + /obj/item/device/healthanalyzer, + /obj/item/weapon/cartridge/medical, + /obj/item/device/flashlight/pen, + /obj/item/weapon/reagent_containers/syringe, + /obj/item/clothing/accessory/storage/white_vest) + cost = 20 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Paramedic equipment" + access = access_medical_equip + +/decl/hierarchy/supply_pack/medical/psychiatristgear + name = "Psychiatrist equipment" + contains = list(/obj/item/clothing/under/rank/psych, + /obj/item/device/radio/headset/headset_med, + /obj/item/clothing/under/rank/psych/turtleneck, + /obj/item/clothing/shoes/laceup, + /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/clothing/shoes/white, + /obj/item/weapon/clipboard, + /obj/item/weapon/folder/white, + /obj/item/weapon/pen, + /obj/item/weapon/cartridge/medical) + cost = 15 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Psychiatrist equipment" + access = access_psychiatrist + +/decl/hierarchy/supply_pack/medical/medicalscrubs + name = "Medical scrubs" + contains = list(/obj/item/clothing/shoes/white = 4, + /obj/item/clothing/under/rank/medical/scrubs/blue, + /obj/item/clothing/under/rank/medical/scrubs/green, + /obj/item/clothing/under/rank/medical/scrubs/purple, + /obj/item/clothing/under/rank/medical/scrubs/black, + /obj/item/clothing/head/surgery/black, + /obj/item/clothing/head/surgery/purple, + /obj/item/clothing/head/surgery/blue, + /obj/item/clothing/head/surgery/green, + /obj/item/weapon/storage/box/masks, + /obj/item/weapon/storage/box/gloves) + cost = 15 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Medical scrubs crate" + access = access_medical_equip + +/decl/hierarchy/supply_pack/medical/autopsy + name = "Autopsy equipment" + contains = list(/obj/item/weapon/folder/white, + /obj/item/device/camera, + /obj/item/device/camera_film = 2, + /obj/item/weapon/autopsy_scanner, + /obj/item/weapon/scalpel, + /obj/item/weapon/storage/box/masks, + /obj/item/weapon/storage/box/gloves, + /obj/item/weapon/pen) + cost = 20 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Autopsy equipment crate" + access = access_morgue +/* +/decl/hierarchy/supply_pack/medical/medicaluniforms + name = "Medical uniforms" + contains = list(/obj/item/clothing/shoes/white = 3, + /obj/item/clothing/under/rank/chief_medical_officer, + /obj/item/clothing/under/rank/geneticist, + /obj/item/clothing/under/rank/virologist, + /obj/item/clothing/under/rank/nursesuit, + /obj/item/clothing/under/rank/nurse, + /obj/item/clothing/under/rank/orderly, + /obj/item/clothing/under/rank/medical = 3, + /obj/item/clothing/under/rank/medical/paramedic = 3, + /obj/item/clothing/suit/storage/toggle/labcoat = 3, + /obj/item/clothing/suit/storage/toggle/labcoat/cmo, + /obj/item/clothing/suit/storage/toggle/labcoat/cmoalt, + /obj/item/clothing/suit/storage/toggle/labcoat/genetics, + /obj/item/clothing/suit/storage/toggle/labcoat/virologist, + /obj/item/clothing/suit/storage/toggle/labcoat/chemist, + /obj/item/weapon/storage/box/masks, + /obj/item/weapon/storage/box/gloves) + cost = 15 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Medical uniform crate" + access = access_medical_equip +*/ + +/decl/hierarchy/supply_pack/medical/medicalbiosuits + name = "Medical biohazard gear" + contains = list(/obj/item/clothing/head/bio_hood = 3, + /obj/item/clothing/suit/bio_suit = 3, + /obj/item/clothing/head/bio_hood/virology = 2, + /obj/item/clothing/suit/bio_suit/cmo = 2, + /obj/item/clothing/mask/gas = 5, + /obj/item/weapon/tank/oxygen = 5, + /obj/item/weapon/storage/box/masks, + /obj/item/weapon/storage/box/gloves) + cost = 50 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Medical biohazard equipment" + access = access_medical_equip + +/decl/hierarchy/supply_pack/medical/portablefreezers + name = "Portable freezers crate" + contains = list(/obj/item/weapon/storage/box/freezer = 7) + cost = 25 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Portable freezers" + access = access_medical_equip + +/decl/hierarchy/supply_pack/medical/surgery + name = "Surgery crate" + contains = list(/obj/item/weapon/cautery, + /obj/item/weapon/surgicaldrill, + /obj/item/clothing/mask/breath/medical, + /obj/item/weapon/tank/anesthetic, + /obj/item/weapon/FixOVein, + /obj/item/weapon/hemostat, + /obj/item/weapon/scalpel, + /obj/item/weapon/bonegel, + /obj/item/weapon/retractor, + /obj/item/weapon/bonesetter, + /obj/item/weapon/circular_saw) + cost = 25 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Surgery crate" + access = access_medical + +/decl/hierarchy/supply_pack/medical/sterile + name = "Sterile equipment crate" + contains = list(/obj/item/clothing/under/rank/medical/scrubs/green = 2, + /obj/item/clothing/head/surgery/green = 2, + /obj/item/weapon/storage/box/masks, + /obj/item/weapon/storage/box/gloves, + /obj/item/weapon/storage/belt/medical = 3) + cost = 15 + containertype = /obj/structure/closet/crate + containername = "\improper Sterile equipment crate" + +/decl/hierarchy/supply_pack/medical/voidsuit + name = "Medical voidsuit" + contains = list(/obj/item/clothing/suit/space/void/medical/alt, + /obj/item/clothing/head/helmet/space/void/medical/alt, + /obj/item/clothing/shoes/magboots) + cost = 120 + containername = "\improper Medical voidsuit crate" + containertype = /obj/structure/closet/crate/secure/large + access = access_medical_equip diff --git a/code/datums/supplypacks/miscellaneous.dm b/code/datums/supplypacks/miscellaneous.dm new file mode 100644 index 00000000..a46a4ffa --- /dev/null +++ b/code/datums/supplypacks/miscellaneous.dm @@ -0,0 +1,294 @@ +/decl/hierarchy/supply_pack/miscellaneous + name = "Miscellaneous" + +/decl/hierarchy/supply_pack/miscellaneous/wizard + name = "Wizard costume" + contains = list(/obj/item/weapon/staff, + /obj/item/clothing/suit/wizrobe/fake, + /obj/item/clothing/shoes/sandal, + /obj/item/clothing/head/wizard/fake) + cost = 20 + containername = "\improper Wizard costume crate" + +/decl/hierarchy/supply_pack/miscellaneous/carpetbrown + name = "Brown carpet" + contains = list(/obj/item/stack/tile/carpet/fifty) + cost = 15 + containername = "\improper Brown carpet crate" + +/decl/hierarchy/supply_pack/miscellaneous/carpetblue + name = "Blue and gold carpet" + contains = list(/obj/item/stack/tile/carpetblue/fifty) + cost = 15 + containername = "\improper Blue and gold carpet crate" + +/decl/hierarchy/supply_pack/miscellaneous/carpetblue2 + name = "Blue and silver carpet" + contains = list(/obj/item/stack/tile/carpetblue2/fifty) + cost = 15 + containername = "\improper Blue and silver carpet crate" + +/decl/hierarchy/supply_pack/miscellaneous/carpetpurple + name = "Purple carpet" + contains = list(/obj/item/stack/tile/carpetpurple/fifty) + cost = 15 + containername = "\improper Purple carpet crate" + +/decl/hierarchy/supply_pack/miscellaneous/carpetorange + name = "Orange carpet" + contains = list(/obj/item/stack/tile/carpetorange/fifty) + cost = 15 + containername = "\improper Orange carpet crate" + +/decl/hierarchy/supply_pack/miscellaneous/carpetgreen + name = "Green carpet" + contains = list(/obj/item/stack/tile/carpetgreen/fifty) + cost = 15 + containername = "\improper Green carpet crate" + +/decl/hierarchy/supply_pack/miscellaneous/carpetred + name = "Red carpet" + contains = list(/obj/item/stack/tile/carpetred/fifty) + cost = 15 + containername = "\improper Red carpet crate" + +/decl/hierarchy/supply_pack/miscellaneous/linoleum + name = "Linoleum" + contains = list(/obj/item/stack/tile/linoleum/fifty) + cost = 15 + containername = "\improper Linoleum crate" + +/decl/hierarchy/supply_pack/miscellaneous/white_tiles + name = "White floor tiles" + contains = list(/obj/item/stack/tile/floor_white/fifty) + cost = 15 + containername = "\improper White floor tile crate" + +/decl/hierarchy/supply_pack/miscellaneous/dark_tiles + name = "Dark floor tiles" + contains = list(/obj/item/stack/tile/floor_dark/fifty) + cost = 15 + containername = "\improper Dark floor tile crate" + +/decl/hierarchy/supply_pack/miscellaneous/freezer_tiles + name = "Freezer floor tiles" + contains = list(/obj/item/stack/tile/floor_freezer/fifty) + cost = 15 + containername = "\improper Freezer floor tile crate" + +/decl/hierarchy/supply_pack/miscellaneous/costume + num_contained = 2 + contains = list(/obj/item/clothing/suit/pirate, + /obj/item/clothing/suit/judgerobe, + /obj/item/clothing/accessory/wcoat, + /obj/item/clothing/suit/hastur, + /obj/item/clothing/suit/holidaypriest, + /obj/item/clothing/suit/nun, + /obj/item/clothing/suit/imperium_monk, + /obj/item/clothing/suit/ianshirt, + /obj/item/clothing/under/gimmick/rank/captain/suit, + /obj/item/clothing/under/gimmick/rank/head_of_personnel/suit, + /obj/item/clothing/under/lawyer/purpsuit, + /obj/item/clothing/under/rank/mailman, + /obj/item/clothing/under/dress/dress_saloon, + /obj/item/clothing/accessory/suspenders, + /obj/item/clothing/suit/storage/toggle/labcoat/mad, + /obj/item/clothing/suit/bio_suit/plaguedoctorsuit, + /obj/item/clothing/under/schoolgirl, + /obj/item/clothing/under/owl, + /obj/item/clothing/under/waiter, + /obj/item/clothing/under/gladiator, + /obj/item/clothing/under/soviet, + /obj/item/clothing/under/scratch, + /obj/item/clothing/under/wedding/bride_white, + /obj/item/clothing/suit/chef, + /obj/item/clothing/suit/apron/overalls, + /obj/item/clothing/under/redcoat, + /obj/item/clothing/under/kilt, + /obj/item/clothing/under/savage_hunter, + /obj/item/clothing/under/savage_hunter/female, + /obj/item/clothing/under/wetsuit) + name = "Costumes crate" + cost = 10 + containername = "\improper Actor Costumes" + supply_method = /decl/supply_method/randomized + +/decl/hierarchy/supply_pack/miscellaneous/formal_wear + contains = list(/obj/item/clothing/head/bowler, + /obj/item/clothing/head/that, + /obj/item/clothing/suit/storage/toggle/suit/blue, + /obj/item/clothing/suit/storage/toggle/suit/purple, + /obj/item/clothing/under/suit_jacket, + /obj/item/clothing/under/suit_jacket/female, + /obj/item/clothing/under/suit_jacket/really_black, + /obj/item/clothing/under/suit_jacket/red, + /obj/item/clothing/under/lawyer/bluesuit, + /obj/item/clothing/under/lawyer/purpsuit, + /obj/item/clothing/shoes/black, + /obj/item/clothing/shoes/black, + /obj/item/clothing/shoes/leather, + /obj/item/clothing/accessory/wcoat) + name = "Formalwear closet" + cost = 30 + containertype = /obj/structure/closet + containername = "\improper Formalwear for the best occasions." + +/decl/hierarchy/supply_pack/miscellaneous/card_packs + num_contained = 5 + contains = list(/obj/item/weapon/pack/cardemon, + /obj/item/weapon/deck/holder) + name = "\improper Trading Card Crate" + cost = 20 + containername = "\improper cards crate" + supply_method = /decl/supply_method/randomized + +/decl/hierarchy/supply_pack/miscellaneous/eftpos + contains = list(/obj/item/device/eftpos) + name = "EFTPOS scanner" + cost = 10 + containername = "\improper EFTPOS crate" + +/decl/hierarchy/supply_pack/miscellaneous/hats + num_contained = 4 + contains = list(/obj/item/clothing/head/collectable/chef, + /obj/item/clothing/head/collectable/paper, + /obj/item/clothing/head/collectable/tophat, + /obj/item/clothing/head/collectable/captain, + /obj/item/clothing/head/collectable/beret, + /obj/item/clothing/head/collectable/welding, + /obj/item/clothing/head/collectable/flatcap, + /obj/item/clothing/head/collectable/pirate, + /obj/item/clothing/head/collectable/kitty, + /obj/item/clothing/head/collectable/rabbitears, + /obj/item/clothing/head/collectable/wizard, + /obj/item/clothing/head/collectable/hardhat, + /obj/item/clothing/head/collectable/HoS, + /obj/item/clothing/head/collectable/thunderdome, + /obj/item/clothing/head/collectable/swat, + /obj/item/clothing/head/collectable/slime, + /obj/item/clothing/head/collectable/police, + /obj/item/clothing/head/collectable/slime, + /obj/item/clothing/head/collectable/xenom, + /obj/item/clothing/head/collectable/petehat) + name = "Collectable hat crate!" + cost = 200 + containername = "\improper Collectable hats crate! Brought to you by Bass.inc!" + supply_method = /decl/supply_method/randomized + +/decl/hierarchy/supply_pack/miscellaneous/cardboard_sheets + name = "50 cardboard sheets" + contains = list(/obj/item/stack/material/cardboard/fifty) + cost = 10 + containername = "\improper Cardboard sheets crate" + +/decl/hierarchy/supply_pack/miscellaneous/witch + name = "Witch costume" + contains = list(/obj/item/clothing/suit/wizrobe/marisa/fake, + /obj/item/clothing/shoes/sandal, + /obj/item/clothing/head/wizard/marisa/fake, + /obj/item/weapon/staff/broom) + cost = 20 + containername = "\improper Witch costume" + containertype = /obj/structure/closet + +/decl/hierarchy/supply_pack/miscellaneous/costume_hats + name = "Costume hats" + contains = list(/obj/item/clothing/head/redcoat, + /obj/item/clothing/head/mailman, + /obj/item/clothing/head/plaguedoctorhat, + /obj/item/clothing/head/pirate, + /obj/item/clothing/head/hasturhood, + /obj/item/clothing/head/powdered_wig, + /obj/item/clothing/head/hairflower, + /obj/item/clothing/head/hairflower/yellow, + /obj/item/clothing/head/hairflower/blue, + /obj/item/clothing/head/hairflower/pink, + /obj/item/clothing/mask/gas/owl_mask, + /obj/item/clothing/mask/gas/monkeymask, + /obj/item/clothing/head/helmet/gladiator, + /obj/item/clothing/head/ushanka, + /obj/item/clothing/mask/spirit) + cost = 10 + containername = "\improper Actor hats crate" + containertype = /obj/structure/closet + num_contained = 2 + supply_method = /decl/supply_method/randomized + +/decl/hierarchy/supply_pack/miscellaneous/dresses + name = "Womens formal dress locker" + contains = list(/obj/item/clothing/under/wedding/bride_orange, + /obj/item/clothing/under/wedding/bride_purple, + /obj/item/clothing/under/wedding/bride_blue, + /obj/item/clothing/under/wedding/bride_red, + /obj/item/clothing/under/wedding/bride_white, + /obj/item/clothing/under/sundress, + /obj/item/clothing/under/dress/dress_green, + /obj/item/clothing/under/dress/dress_pink, + /obj/item/clothing/under/dress/dress_orange, + /obj/item/clothing/under/dress/dress_yellow, + /obj/item/clothing/under/dress/dress_saloon) + cost = 15 + containername = "\improper Pretty dress locker" + containertype = /obj/structure/closet + num_contained = 1 + supply_method = /decl/supply_method/randomized +/* +/decl/hierarchy/supply_pack/miscellaneous/exosuit_mod + num_contained = 1 + name = "Random APLU modkit" + contains = list( + /obj/item/device/kit/paint/ripley, + /obj/item/device/kit/paint/ripley/death, + /obj/item/device/kit/paint/ripley/flames_red, + /obj/item/device/kit/paint/ripley/flames_blue + ) + cost = 200 + containername = "heavy crate" + supply_method = /decl/supply_method/randomized + +/decl/hierarchy/supply_pack/miscellaneous/exosuit_mod_durand + num_contained = 1 + name = "Random Durand exosuit modkit" + contains = list( + /obj/item/device/kit/paint/durand, + /obj/item/device/kit/paint/durand/seraph, + /obj/item/device/kit/paint/durand/phazon + ) + cost = 200 + containername = "heavy crate" + supply_method = /decl/supply_method/randomized + +/decl/hierarchy/supply_pack/miscellaneous/exosuit_mod_gygax + num_contained = 1 + name = "Random Gygax exosuit modkit" + contains = list( + /obj/item/device/kit/paint/gygax, + /obj/item/device/kit/paint/gygax/darkgygax, + /obj/item/device/kit/paint/gygax/recitence + ) + cost = 200 + containername = "heavy crate" + supply_method = /decl/supply_method/randomized + +/decl/hierarchy/supply_pack/miscellaneous/chaplaingear + name = "Chaplain equipment" + contains = list(/obj/item/clothing/under/rank/chaplain, + /obj/item/clothing/shoes/black, + /obj/item/clothing/suit/nun, + /obj/item/clothing/head/nun_hood, + /obj/item/clothing/suit/chaplain_hoodie, + /obj/item/clothing/head/chaplain_hood, + /obj/item/clothing/suit/holidaypriest, + /obj/item/clothing/under/wedding/bride_white, + /obj/item/weapon/storage/backpack/cultpack, + /obj/item/weapon/storage/fancy/candle_box = 3) + cost = 10 + containername = "\improper Chaplain equipment crate" +*/ +/decl/hierarchy/supply_pack/miscellaneous/mousetrap + num_contained = 3 + contains = list(/obj/item/weapon/storage/box/mousetraps) + name = "\improper Pest Control Crate" + cost = 10 + containername = "\improper Pest Control Crate" + diff --git a/code/datums/supplypacks/operations.dm b/code/datums/supplypacks/operations.dm new file mode 100644 index 00000000..4cc723a4 --- /dev/null +++ b/code/datums/supplypacks/operations.dm @@ -0,0 +1,78 @@ +/decl/hierarchy/supply_pack/operations + name = "Operations" + +/decl/hierarchy/supply_pack/operations/mule + name = "MULEbot Crate" + contains = list() + cost = 20 + containertype = /obj/structure/largecrate/animal/mulebot + containername = "Mulebot Crate" + +/decl/hierarchy/supply_pack/operations/cargotrain + name = "Cargo Train Tug" + contains = list(/obj/vehicle/train/cargo/engine) + cost = 45 + containertype = /obj/structure/largecrate + containername = "\improper Cargo Train Tug Crate" + +/decl/hierarchy/supply_pack/operations/cargotrailer + name = "Cargo Train Trolley" + contains = list(/obj/vehicle/train/cargo/trolley) + cost = 15 + containertype = /obj/structure/largecrate + containername = "\improper Cargo Train Trolley Crate" + +/decl/hierarchy/supply_pack/operations/artscrafts + name = "Arts and Crafts supplies" + contains = list(/obj/item/weapon/storage/fancy/crayons, + /obj/item/device/camera, + /obj/item/device/camera_film = 2, + /obj/item/weapon/storage/photo_album, + /obj/item/weapon/packageWrap, + /obj/item/weapon/reagent_containers/glass/paint/red, + /obj/item/weapon/reagent_containers/glass/paint/green, + /obj/item/weapon/reagent_containers/glass/paint/blue, + /obj/item/weapon/reagent_containers/glass/paint/yellow, + /obj/item/weapon/reagent_containers/glass/paint/purple, + /obj/item/weapon/reagent_containers/glass/paint/black, + /obj/item/weapon/reagent_containers/glass/paint/white, + /obj/item/weapon/contraband/poster, + /obj/item/weapon/wrapping_paper = 3) + cost = 10 + containername = "\improper Arts and Crafts crate" + +/decl/hierarchy/supply_pack/operations/contraband + num_contained = 5 + contains = list(/obj/item/seeds/bloodtomatoseed, + /obj/item/weapon/storage/pill_bottle/zoom, + /obj/item/weapon/storage/pill_bottle/happy, + /obj/item/weapon/reagent_containers/food/drinks/bottle/pwine) + + name = "Contraband crate" + cost = 30 + containername = "\improper Unlabeled crate" + contraband = 1 + supply_method = /decl/supply_method/randomized +/* +/decl/hierarchy/supply_pack/operations/hoverpod + name = "Hoverpod Shipment" + contains = list() + cost = 80 + containertype = /obj/structure/largecrate/hoverpod + containername = "\improper Hoverpod Crate" + + +/decl/hierarchy/supply_pack/operations/webbing + name = "Webbing crate" + num_contained = 4 + contains = list(/obj/item/clothing/accessory/holster, + /obj/item/clothing/accessory/storage/black_vest, + /obj/item/clothing/accessory/storage/brown_vest, + /obj/item/clothing/accessory/storage/white_vest, + /obj/item/clothing/accessory/storage/drop_pouches/black, + /obj/item/clothing/accessory/storage/drop_pouches/brown, + /obj/item/clothing/accessory/storage/drop_pouches/white, + /obj/item/clothing/accessory/storage/webbing) + cost = 15 + containername = "\improper Webbing crate" +*/ diff --git a/code/datums/supplypacks/science.dm b/code/datums/supplypacks/science.dm new file mode 100644 index 00000000..c78f2027 --- /dev/null +++ b/code/datums/supplypacks/science.dm @@ -0,0 +1,47 @@ +/decl/hierarchy/supply_pack/science + name = "Science" + +/decl/hierarchy/supply_pack/science/virus + name = "Virus sample crate" + contains = list(/obj/item/weapon/virusdish/random = 4) + cost = 25 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Virus sample crate" + access = access_cmo + +/decl/hierarchy/supply_pack/science/coolanttank + name = "Coolant tank crate" + contains = list(/obj/structure/reagent_dispensers/coolanttank) + cost = 16 + containertype = /obj/structure/largecrate + containername = "\improper coolant tank crate" + +/decl/hierarchy/supply_pack/science/mecha_ripley + name = "Circuit Crate (\"Ripley\" APLU)" + contains = list(/obj/item/weapon/book/manual/ripley_build_and_repair, + /obj/item/weapon/circuitboard/mecha/ripley/main, //TEMPORARY due to lack of circuitboard printer, + /obj/item/weapon/circuitboard/mecha/ripley/peripherals) //TEMPORARY due to lack of circuitboard printer + cost = 30 + containertype = /obj/structure/closet/crate/secure + containername = "\improper APLU \"Ripley\" Circuit Crate" + access = access_robotics + +/decl/hierarchy/supply_pack/science/mecha_odysseus + name = "Circuit Crate (\"Odysseus\")" + contains = list(/obj/item/weapon/circuitboard/mecha/odysseus/peripherals, //TEMPORARY due to lack of circuitboard printer, + /obj/item/weapon/circuitboard/mecha/odysseus/main) //TEMPORARY due to lack of circuitboard printer + cost = 25 + containertype = /obj/structure/closet/crate/secure + containername = "\improper \"Odysseus\" Circuit Crate" + access = access_robotics + +/decl/hierarchy/supply_pack/science/phoron + name = "Phoron assembly crate" + contains = list(/obj/item/weapon/tank/phoron = 3, + /obj/item/device/assembly/igniter = 3, + /obj/item/device/assembly/prox_sensor = 3, + /obj/item/device/assembly/timer = 3) + cost = 10 + containertype = /obj/structure/closet/crate/secure/phoron + containername = "\improper Phoron assembly crate" + access = access_tox_storage diff --git a/code/datums/supplypacks/security.dm b/code/datums/supplypacks/security.dm new file mode 100644 index 00000000..53381edc --- /dev/null +++ b/code/datums/supplypacks/security.dm @@ -0,0 +1,340 @@ +/decl/hierarchy/supply_pack/security + name = "Security" + +/decl/hierarchy/supply_pack/security/specialops + name = "Special Ops supplies" + contains = list(/obj/item/weapon/storage/box/emps, + /obj/item/weapon/grenade/smokebomb = 3, + /obj/item/weapon/grenade/chem_grenade/incendiary) + cost = 20 + containername = "\improper Special Ops crate" + hidden = 1 + +/decl/hierarchy/supply_pack/security/lightarmor + name = "Armor - Light" + contains = list(/obj/item/clothing/suit/armor/vest/opvest = 4, + /obj/item/clothing/head/helmet =4) + cost = 30 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Light armor crate" + access = access_security + +/decl/hierarchy/supply_pack/security/armor + name = "Armor - Unmarked" + contains = list(/obj/item/clothing/suit/armor/pcarrier/medium = 2, + /obj/item/clothing/head/helmet =2) + cost = 20 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Armor crate" + access = access_security + +/decl/hierarchy/supply_pack/security/tacticalarmor + name = "Armor - Tactical" + contains = list(/obj/item/clothing/under/tactical, + /obj/item/clothing/suit/armor/vest/opvest, + /obj/item/clothing/head/helmet/tactical, + /obj/item/clothing/mask/balaclava/tactical, + /obj/item/clothing/glasses/tacgoggles, + /obj/item/weapon/storage/belt/security/tactical, + /obj/item/clothing/shoes/tactical, + /obj/item/clothing/gloves/tactical) + cost = 45 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Tactical armor crate" + access = access_armory +/* +/decl/hierarchy/supply_pack/security/blackguards + name = "Armor - Arm and leg guards, black" + contains = list(/obj/item/clothing/accessory/armguards = 2, + /obj/item/clothing/accessory/legguards = 2) + cost = 20 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Arm and leg guards crate" + access = access_armory + +/decl/hierarchy/supply_pack/security/blueguards + name = "Armor - Arm and leg guards, blue" + contains = list(/obj/item/clothing/accessory/armguards/blue = 2, + /obj/item/clothing/accessory/legguards/blue = 2) + cost = 20 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Arm and leg guards crate" + access = access_armory + +/decl/hierarchy/supply_pack/security/greenguards + name = "Armor - Arm and leg guards, green" + contains = list(/obj/item/clothing/accessory/armguards/green = 2, + /obj/item/clothing/accessory/legguards/green = 2) + cost = 20 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Arm and leg guards crate" + access = access_armory + +/decl/hierarchy/supply_pack/security/navyguards + name = "Armor - Arm and leg guards, navy blue" + contains = list(/obj/item/clothing/accessory/armguards/navy = 2, + /obj/item/clothing/accessory/legguards/navy = 2) + cost = 20 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Arm and leg guards crate" + access = access_armory + +/decl/hierarchy/supply_pack/security/tanguards + name = "Armor - Arm and leg guards, tan" + contains = list(/obj/item/clothing/accessory/armguards/tan = 2, + /obj/item/clothing/accessory/legguards/tan = 2) + cost = 20 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Arm and leg guards crate" + access = access_armory +*/ +/decl/hierarchy/supply_pack/security/riotarmor + name = "Armor - Riot gear" + contains = list(/obj/item/weapon/shield/riot = 4, + /obj/item/clothing/head/helmet/riot = 4, + /obj/item/clothing/suit/armor/riot = 4, + /obj/item/weapon/storage/box/flashbangs, + /obj/item/weapon/storage/box/teargas) + cost = 80 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Riot armor crate" + access = access_armory + +/decl/hierarchy/supply_pack/security/ballisticarmor + name = "Armor - Ballistic" + contains = list(/obj/item/clothing/head/helmet/ballistic = 4, + /obj/item/clothing/suit/armor/bulletproof = 4) + cost = 60 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Ballistic suit crate" + access = access_armory +/* +/decl/hierarchy/supply_pack/security/ablativearmor + name = "Armor - Ablative" + contains = list(/obj/item/clothing/head/helmet/ablative = 4, + /obj/item/clothing/suit/armor/laserproof = 4) + cost = 60 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Ablative suit crate" + access = access_armory + +/decl/hierarchy/supply_pack/security/voidsuit + name = "Armor - Security voidsuit" + contains = list(/obj/item/clothing/suit/space/void/security/alt, + /obj/item/clothing/head/helmet/space/void/security/alt, + /obj/item/clothing/shoes/magboots) + cost = 120 + containername = "\improper Security voidsuit crate" + containertype = /obj/structure/closet/crate/secure/large + access = access_brig +*/ +/decl/hierarchy/supply_pack/security/weapons + name = "Weapons - Security basic" + contains = list(/obj/item/device/flash = 4, + /obj/item/weapon/reagent_containers/spray/pepper = 4, + /obj/item/weapon/melee/classic_baton = 4, + /obj/item/weapon/gun/energy/taser = 4) + cost = 50 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper Weapons crate" + access = access_security +/* +/decl/hierarchy/supply_pack/security/egun + name = "Weapons - Energy sidearms" + contains = list(/obj/item/weapon/gun/energy/gun = 4) + cost = 40 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper Energy sidearms crate" + access = access_armory + security_level = SUPPLY_SECURITY_ELEVATED + + +/decl/hierarchy/supply_pack/security/ion + name = "Weapons - Electromagnetic" + contains = list(/obj/item/weapon/gun/energy/ionrifle = 2, + /obj/item/weapon/storage/box/emps) + cost = 50 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper Electromagnetic weapons crate" + access = access_armory + security_level = SUPPLY_SECURITY_ELEVATED +*/ + +/decl/hierarchy/supply_pack/security/pistol + name = "Weapons - Ballistic sidearms" + contains = list(/obj/item/weapon/gun/projectile/sec = 4) + cost = 40 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper Ballistic sidearms crate" + access = access_armory + security_level = SUPPLY_SECURITY_ELEVATED + +/decl/hierarchy/supply_pack/security/shotgun + name = "Weapons - Shotgun" + contains = list(/obj/item/weapon/gun/projectile/shotgun/pump/shitty = 2) + cost = 60 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper Shotgun crate" + access = access_armory + security_level = SUPPLY_SECURITY_ELEVATED + +/decl/hierarchy/supply_pack/security/flashbang + name = "Weapons - Flashbangs" + contains = list(/obj/item/weapon/storage/box/flashbangs = 2) + cost = 30 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper Flashbang crate" + access = access_security + +/decl/hierarchy/supply_pack/security/teargas + name = "Weapons - Tear gas grenades" + contains = list(/obj/item/weapon/storage/box/teargas = 2) + cost = 30 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper Tear gas grenades crate" + access = access_security + +/decl/hierarchy/supply_pack/security/pistolammo + name = "Ammunition - .45 magazines" + contains = list(/obj/item/ammo_magazine/c45m = 4) + cost = 20 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper .45 ammunition crate" + access = access_security + security_level = SUPPLY_SECURITY_ELEVATED + +/decl/hierarchy/supply_pack/security/pistolammorubber + name = "Ammunition - .45 rubber" + contains = list(/obj/item/ammo_magazine/c45m/rubber = 4) + cost = 15 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper .45 rubber ammunition crate" + access = access_security +/* +/decl/hierarchy/supply_pack/security/pistolammopractice + name = "Ammunition - .45 practice" + contains = list(/obj/item/ammo_magazine/c45m/practice = 8) + cost = 15 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper .45 practice ammunition crate" + access = access_security +*/ +/decl/hierarchy/supply_pack/security/shotgunammo + name = "Ammunition - Lethal shells" + contains = list(/obj/item/weapon/storage/box/shotgunammo = 2, + /obj/item/weapon/storage/box/shotgunshells = 2) + cost = 60 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper Lethal shotgun shells crate" + access = access_security + security_level = SUPPLY_SECURITY_ELEVATED + +/decl/hierarchy/supply_pack/security/shotgunbeanbag + name = "Ammunition - Beanbag shells" + contains = list(/obj/item/weapon/storage/box/beanbags = 3) + cost = 30 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper Beanbag shotgun shells crate" + access = access_security + +/decl/hierarchy/supply_pack/security/pdwammo + name = "Ammunition - 9mm top mounted" + contains = list(/obj/item/ammo_magazine/mc9mmt = 4) + cost = 40 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper 9mm ammunition crate" + access = access_security + security_level = SUPPLY_SECURITY_HIGH + +/decl/hierarchy/supply_pack/security/pdwammorubber + name = "Ammunition - 9mm top mounted rubber" + contains = list(/obj/item/ammo_magazine/mc9mmt/rubber = 4) + cost = 30 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper 9mm rubber ammunition crate" + access = access_security + +/decl/hierarchy/supply_pack/security/pdwammopractice + name = "Ammunition - 9mm top mounted practice" + contains = list(/obj/item/ammo_magazine/mc9mmt/practice = 8) + cost = 30 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper 9mm practice ammunition crate" + access = access_security + +/decl/hierarchy/supply_pack/security/bullpupammo + name = "Ammunition - 7.62" + contains = list(/obj/item/ammo_magazine/a762 = 4) + cost = 60 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper 7.62 ammunition crate" + access = access_security + security_level = SUPPLY_SECURITY_HIGH + +/decl/hierarchy/supply_pack/security/bullpupammopractice + name = "Ammunition - 7.62 practice" + contains = list(/obj/item/ammo_magazine/a762/practice = 8) + cost = 30 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "\improper 7.62 practice ammunition crate" + access = access_security + +/decl/hierarchy/supply_pack/security/forensics //Not access-restricted so PIs can use it. + name = "Forensics - Auxiliary tools" + contains = list(/obj/item/weapon/forensics/sample_kit, + /obj/item/weapon/forensics/sample_kit/powder, + /obj/item/weapon/storage/box/swabs = 3, + /obj/item/weapon/reagent_containers/spray/luminol) + cost = 30 + containername = "\improper Auxiliary forensic tools crate" +/* +/decl/hierarchy/supply_pack/security/detectivegear + name = "Forensics - investigation equipment" + contains = list(/obj/item/weapon/storage/box/evidence = 2, + /obj/item/weapon/cartridge/detective, + /obj/item/device/radio/headset/headset_sec, + /obj/item/taperoll/police, + /obj/item/clothing/glasses/sunglasses, + /obj/item/device/camera, + /obj/item/weapon/folder/red, + /obj/item/weapon/folder/blue, + /obj/item/clothing/gloves/forensic, + /obj/item/device/taperecorder, + /obj/item/device/mass_spectrometer, + /obj/item/device/camera_film = 2, + /obj/item/weapon/storage/photo_album, + /obj/item/device/reagent_scanner, + /obj/item/weapon/storage/briefcase/crimekit = 2) + cost = 50 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Forensic equipment crate" + access = access_forensics_lockers +*/ + +/decl/hierarchy/supply_pack/security/securitybarriers + name = "Misc - Barrier crate" + contains = list(/obj/machinery/deployable/barrier = 4) + cost = 20 + containertype = /obj/structure/closet/crate/secure/large + containername = "\improper Security barrier crate" + access = access_security + +/decl/hierarchy/supply_pack/security/securitybarriers + name = "Misc - Wall shield Generators" + contains = list(/obj/machinery/shieldwallgen = 2) + cost = 20 + containertype = /obj/structure/closet/crate/secure/large + containername = "\improper wall shield generators crate" + access = access_brig + +/decl/hierarchy/supply_pack/security/securitybiosuit + name = "Misc - Security biohazard gear" + contains = list(/obj/item/clothing/head/bio_hood/security, + /obj/item/clothing/suit/bio_suit/security, + /obj/item/clothing/mask/gas, + /obj/item/weapon/tank/oxygen, + /obj/item/clothing/gloves/latex) + cost = 30 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Security biohazard gear crate" + access = access_security \ No newline at end of file diff --git a/code/datums/supplypacks/supply.dm b/code/datums/supplypacks/supply.dm new file mode 100644 index 00000000..b118170c --- /dev/null +++ b/code/datums/supplypacks/supply.dm @@ -0,0 +1,87 @@ +/decl/hierarchy/supply_pack/supply + name = "Supply" + +/decl/hierarchy/supply_pack/supply/food + name = "Kitchen supply crate" + contains = list(/obj/item/weapon/reagent_containers/food/condiment/flour = 6, + /obj/item/weapon/reagent_containers/food/drinks/milk = 4, + /obj/item/weapon/reagent_containers/food/drinks/soymilk = 2, + /obj/item/weapon/storage/fancy/egg_box = 2, + /obj/item/weapon/reagent_containers/food/snacks/tofu = 4, + /obj/item/weapon/reagent_containers/food/snacks/meat = 4 + ) + cost = 10 + containertype = /obj/structure/closet/crate/freezer + containername = "\improper Food crate" + +/decl/hierarchy/supply_pack/supply/toner + name = "Toner cartridges" + contains = list(/obj/item/device/toner = 6) + cost = 10 + containername = "\improper Toner cartridges" + +/decl/hierarchy/supply_pack/supply/janitor + name = "Janitorial supplies" + contains = list(/obj/item/weapon/reagent_containers/glass/bucket, + /obj/item/weapon/mop, + /obj/item/weapon/caution = 4, + /obj/item/weapon/storage/bag/trash, + /obj/item/device/lightreplacer, + /obj/item/weapon/reagent_containers/spray/cleaner, + /obj/item/weapon/reagent_containers/glass/rag, + /obj/item/weapon/grenade/chem_grenade/cleaner = 3, + /obj/structure/mopbucket) + cost = 10 + containertype = /obj/structure/closet/crate/large + containername = "\improper Janitorial supplies" + +/decl/hierarchy/supply_pack/supply/boxes + name = "Empty boxes" + contains = list(/obj/item/weapon/storage/box = 10) + cost = 10 + containername = "\improper Empty box crate" + +/decl/hierarchy/supply_pack/supply/bureaucracy + contains = list(/obj/item/weapon/clipboard, + /obj/item/weapon/clipboard, + /obj/item/weapon/pen/red, + /obj/item/weapon/pen/blue = 2, + /obj/item/device/camera_film, + /obj/item/weapon/folder/blue, + /obj/item/weapon/folder/red, + /obj/item/weapon/folder/yellow, + /obj/item/weapon/hand_labeler, + /obj/item/weapon/tape_roll, + /obj/structure/filingcabinet/chestdrawer{anchored = 0}, + /obj/item/weapon/paper_bin) + name = "Office supplies" + cost = 15 + containertype = /obj/structure/closet/crate/large + containername = "\improper Office supplies crate" + +/decl/hierarchy/supply_pack/supply/spare_pda + name = "Spare PDAs" + contains = list(/obj/item/device/pda = 3) + cost = 10 + containername = "\improper Spare PDA crate" + +/decl/hierarchy/supply_pack/supply/minergear + name = "Shaft miner equipment" + contains = list(/obj/item/weapon/storage/backpack/industrial, + /obj/item/weapon/storage/backpack/satchel/satchel_eng, + /obj/item/device/radio/headset/headset_cargo, + /obj/item/clothing/under/rank/miner, + /obj/item/clothing/gloves/thick, + /obj/item/clothing/shoes/black, + /obj/item/device/analyzer, + /obj/item/weapon/storage/ore, + /obj/item/device/flashlight/lantern, + /obj/item/weapon/shovel, + /obj/item/weapon/pickaxe, + /obj/item/weapon/mining_scanner, + /obj/item/clothing/glasses/material, + /obj/item/clothing/glasses/meson) + cost = 15 + containertype = /obj/structure/closet/crate/secure + containername = "\improper Shaft miner equipment" + access = access_mining diff --git a/code/datums/supplypacks/supplypack.dm b/code/datums/supplypacks/supplypack.dm new file mode 100644 index 00000000..b3b221bf --- /dev/null +++ b/code/datums/supplypacks/supplypack.dm @@ -0,0 +1,99 @@ +var/decl/hierarchy/supply_pack/cargo_supply_pack_root = new() +var/decl/hierarchy/supply_pack/cargo_supply_packs // Non-category supply packs + +/decl/hierarchy/supply_pack + name = "Supply Packs" + var/list/contains = list() + var/manifest = "" + var/cost = null + var/containertype = /obj/structure/closet/crate + var/containername = null + var/access = null + var/hidden = 0 + var/contraband = 0 + var/num_contained = 0 //number of items picked to be contained in a randomised crate + var/supply_method = /decl/supply_method + var/decl/security_level/security_level + +/decl/hierarchy/supply_pack/New() + ..() + if(is_hidden_category()) + return // Don't init the manifest for category entries + + if(!cargo_supply_packs) cargo_supply_packs = list() + dd_insertObjectList(cargo_supply_packs, src) // Add all non-category supply packs to the list + + if(!num_contained) + for(var/entry in contains) + num_contained += max(1, contains[entry]) + + var/decl/supply_method/sm = get_supply_method(supply_method) + manifest = sm.setup_manifest(src) + +/decl/hierarchy/supply_pack/proc/sec_available() + if(isnull(security_level)) + return TRUE + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + switch(security_level) + if(SUPPLY_SECURITY_ELEVATED) + if(security_state.all_security_levels.len > 1) + security_level = security_state.all_security_levels[2] + else + security_level = security_state.high_security_level + if(SUPPLY_SECURITY_HIGH) + security_level = security_state.high_security_level + if(!istype(security_level)) + return TRUE + return security_state.current_security_level_is_same_or_higher_than(security_level) + +/decl/hierarchy/supply_pack/proc/spawn_contents(var/location) + var/decl/supply_method/sm = get_supply_method(supply_method) + return sm.spawn_contents(src, location) + +/* +//SUPPLY PACKS +//NOTE: only secure crate types use the access var (and are lockable) +//NOTE: hidden packs only show up when the computer has been hacked. +//ANOTER NOTE: Contraband is obtainable through modified supplycomp circuitboards. +//BIG NOTE: Don't add living things to crates, that's bad, it will break the shuttle. +//NEW NOTE: Do NOT set the price of any crates below 7 points. Doing so allows infinite points. +*/ + +var/list/supply_methods_ +/proc/get_supply_method(var/method_type) + if(!supply_methods_) + supply_methods_ = list() + . = supply_methods_[method_type] + if(!.) + . = new method_type() + supply_methods_[method_type] = . + +/decl/supply_method/proc/spawn_contents(var/decl/hierarchy/supply_pack/sp, var/location) + if(!sp || !location) + return + . = list() + for(var/entry in sp.contains) + for(var/i = 1 to max(1, sp.contains[entry])) + dd_insertObjectList(.,new entry(location)) + +/decl/supply_method/proc/setup_manifest(var/decl/hierarchy/supply_pack/sp) + . = list() + . += "
      " + for(var/path in sp.contains) + var/atom/A = path + if(!ispath(A)) + continue + . += "
    • [initial(A.name)]
    • " + . += "
    " + . = jointext(.,null) + +/decl/supply_method/randomized/spawn_contents(var/decl/hierarchy/supply_pack/sp, var/location) + if(!sp || !location) + return + . = list() + for(var/j = 1 to sp.num_contained) + var/picked = pick(sp.contains) + . += new picked(location) + +/decl/supply_method/randomized/setup_manifest(var/decl/hierarchy/supply_pack/sp) + return "Contains any [sp.num_contained] of:" + ..() diff --git a/code/datums/trading/_trading_defines.dm b/code/datums/trading/_trading_defines.dm new file mode 100644 index 00000000..ead3d66d --- /dev/null +++ b/code/datums/trading/_trading_defines.dm @@ -0,0 +1,20 @@ +#define TRADER_THIS_TYPE 1 +#define TRADER_SUBTYPES_ONLY 2 +#define TRADER_ALL 3 +#define TRADER_BLACKLIST 4 +#define TRADER_BLACKLIST_SUB 8 +#define TRADER_BLACKLIST_ALL 12 + +#define TRADER_WANTED_ONLY 1 //Do they only trade for wanted goods? +#define TRADER_MONEY 2 //Do they only accept money in return for goods. +#define TRADER_GOODS 4 //Do they accept goods in return for other goods. +#define TRADER_WANTED_ALL 8 //Like TRADER_WANTED_ONLY but they buy all possible wanted goods rather than a subset. + +//Possible response defines for when offering an item for something +#define TRADER_NO_MONEY "trade_no_money" +#define TRADER_NO_GOODS "trade_no_goods" +#define TRADER_NOT_ENOUGH "trade_not_enough" +#define TRADER_NO_BLACKLISTED "trade_blacklist" +#define TRADER_FOUND_UNWANTED "trade_found_unwanted" + +#define TRADER_DEFAULT_NAME "Default" //Whether to just generate a name from the premade lists. \ No newline at end of file diff --git a/code/datums/trading/ai.dm b/code/datums/trading/ai.dm new file mode 100644 index 00000000..d86c4528 --- /dev/null +++ b/code/datums/trading/ai.dm @@ -0,0 +1,115 @@ +/* + +TRADING BEACON + +Trading beacons are generic AI driven trading outposts. +They sell generic supplies and ask for generic supplies. +*/ + +/datum/trader/trading_beacon + name = "AI" + origin = "Trading Beacon" + name_language = LANGUAGE_EAL + trade_flags = TRADER_MONEY|TRADER_GOODS + speech = list("hail_generic" = "Greetings, I am MERCHANT, Artifical Intelligence onboard ORIGIN, tasked with trading goods in return for credits and supplies.", + "hail_deny" = "We are sorry, your connection has been blacklisted. Have a nice day.", + + "trade_complete" = "Thank you for your patronage.", + "trade_not_enough" = "I'm sorry, your offer is not worth what you are asking for.", + "trade_blacklisted" = "You have offered a blacklisted item. My laws do not allow me to trade for that.", + "how_much" = "ITEM will cost you roughly VALUE credits, or something of equal worth.", + "what_want" = "I have logged need for", + + "compliment_deny" = "I'm sorry, I am not allowed to let compliments affect the trade.", + "compliment_accept" = "Thank you, but that will not not change our business interactions.", + "insult_good" = "I do not understand, are we not on good terms?", + "insult_bad" = "I do not understand, are you insulting me?", + + "bribe_refusal" = "You have given me money to stay, however, I am a station. I do not leave.", + ) + possible_wanted_items = list(/obj/item/device/ = TRADER_SUBTYPES_ONLY, + /obj/item/device/assembly = TRADER_BLACKLIST_ALL, + /obj/item/device/assembly_holder = TRADER_BLACKLIST_ALL, + /obj/item/device/encryptionkey/red = TRADER_BLACKLIST, + /obj/item/weapon/tank/phoron/onetankbomb = TRADER_BLACKLIST, + /obj/item/device/radio = TRADER_BLACKLIST_ALL, + /obj/item/device/pda = TRADER_BLACKLIST_SUB, + /obj/item/device/uplink = TRADER_BLACKLIST) + possible_trading_items = list(/obj/item/weapon/storage/bag = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/storage/bag/cash/infinite = TRADER_BLACKLIST, + /obj/item/weapon/storage/backpack = TRADER_ALL, + /obj/item/weapon/storage/backpack/cultpack = TRADER_BLACKLIST, + /obj/item/weapon/storage/backpack/holding = TRADER_BLACKLIST, + /obj/item/weapon/storage/backpack/satchel/grey/withwallet = TRADER_BLACKLIST, + /obj/item/weapon/storage/backpack/satchel/syndie_kit = TRADER_BLACKLIST_ALL, + /obj/item/weapon/storage/backpack/chameleon = TRADER_BLACKLIST, + /obj/item/weapon/storage/backpack/ert = TRADER_BLACKLIST_ALL, + /obj/item/weapon/storage/backpack/dufflebag/syndie = TRADER_BLACKLIST_SUB, + /obj/item/weapon/storage/belt/champion = TRADER_THIS_TYPE, + /obj/item/weapon/storage/briefcase = TRADER_THIS_TYPE, + /obj/item/weapon/storage/fancy = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/storage/laundry_basket = TRADER_THIS_TYPE, + /obj/item/weapon/storage/secure/briefcase = TRADER_THIS_TYPE, + /obj/item/weapon/storage/plants = TRADER_THIS_TYPE, + /obj/item/weapon/storage/ore = TRADER_THIS_TYPE, + /obj/item/weapon/storage/toolbox = TRADER_ALL, + /obj/item/weapon/storage/wallet = TRADER_THIS_TYPE, + /obj/item/weapon/storage/photo_album = TRADER_THIS_TYPE, + /obj/item/clothing/glasses = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/glasses/hud = TRADER_BLACKLIST_ALL, + /obj/item/clothing/glasses/sunglasses/blindfold/tape = TRADER_BLACKLIST, + /obj/item/clothing/glasses/chameleon = TRADER_BLACKLIST + ) + + insult_drop = 0 + compliment_increase = 0 + +/datum/trader/trading_beacon/New() + ..() + origin = "[origin] #[rand(100,999)]" + +/datum/trader/trading_beacon/mine + origin = "Mining Beacon" + + possible_trading_items = list(/obj/item/weapon/ore = TRADER_SUBTYPES_ONLY, + /obj/item/stack/material/glass = TRADER_ALL, + /obj/item/stack/material/glass/fifty = TRADER_BLACKLIST, + /obj/item/stack/material/iron = TRADER_THIS_TYPE, + /obj/item/stack/material/sandstone = TRADER_THIS_TYPE, + /obj/item/stack/material/marble = TRADER_THIS_TYPE, + /obj/item/stack/material/diamond = TRADER_THIS_TYPE, + /obj/item/stack/material/uranium = TRADER_THIS_TYPE, + /obj/item/stack/material/phoron = TRADER_THIS_TYPE, + /obj/item/stack/material/plastic = TRADER_THIS_TYPE, + /obj/item/stack/material/gold = TRADER_THIS_TYPE, + /obj/item/stack/material/silver = TRADER_THIS_TYPE, + /obj/item/stack/material/platinum = TRADER_THIS_TYPE, + /obj/item/stack/material/mhydrogen = TRADER_THIS_TYPE, + /obj/item/stack/material/tritium = TRADER_THIS_TYPE, + /obj/item/stack/material/osmium = TRADER_THIS_TYPE, + /obj/item/stack/material/steel = TRADER_THIS_TYPE, + /obj/item/stack/material/plasteel = TRADER_THIS_TYPE, + /obj/machinery/mining = TRADER_SUBTYPES_ONLY + ) + +/datum/trader/trading_beacon/manufacturing + origin = "Manifacturing Beacon" + + possible_trading_items = list(/obj/structure/AIcore = TRADER_THIS_TYPE, + /obj/structure/girder = TRADER_THIS_TYPE, + /obj/structure/grille = TRADER_THIS_TYPE, + /obj/structure/mopbucket = TRADER_THIS_TYPE, + /obj/structure/ore_box = TRADER_THIS_TYPE, + /obj/structure/coatrack = TRADER_THIS_TYPE, + /obj/structure/bookcase = TRADER_THIS_TYPE, + /obj/item/glass_jar = TRADER_THIS_TYPE, + /obj/item/target = TRADER_ALL, + /obj/structure/dispenser = TRADER_SUBTYPES_ONLY, + /obj/structure/filingcabinet = TRADER_THIS_TYPE, + /obj/structure/safe = TRADER_THIS_TYPE, + /obj/structure/plushie = TRADER_SUBTYPES_ONLY, + /obj/structure/sign = TRADER_SUBTYPES_ONLY, + /obj/structure/sign/double = TRADER_BLACKLIST_ALL, + /obj/structure/sign/goldenplaque = TRADER_BLACKLIST_ALL, + /obj/structure/sign/poster = TRADER_BLACKLIST + ) \ No newline at end of file diff --git a/code/datums/trading/food.dm b/code/datums/trading/food.dm new file mode 100644 index 00000000..5624de21 --- /dev/null +++ b/code/datums/trading/food.dm @@ -0,0 +1,168 @@ +/datum/trader/pizzaria + name = "Pizza Shop Employee" + name_language = TRADER_DEFAULT_NAME + origin = "Pizzeria" + possible_origins = list("Papa Joe's", "Pizza Ship", "Dominator Pizza", "Little Kaezars", "Pizza Planet", "Cheese Louise", "Little Taste o' Neo-Italy", "Pizza Gestapo") + trade_flags = TRADER_MONEY + possible_wanted_items = list() //They are a pizza shop, not a bargainer. + possible_trading_items = list(/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza = TRADER_SUBTYPES_ONLY) + + speech = list("hail_generic" = "Hello! Welcome to ORIGIN, may I take your order?", + "hail_deny" = "Beeeep... I'm sorry, your connection has been severed.", + + "trade_complete" = "Thank you for choosing ORIGIN!", + "trade_no_goods" = "I'm sorry but we only take cash.", + "trade_blacklisted" = "Sir that's... highly illegal.", + "trade_not_enough" = "Uhh... that's not enough money for pizza.", + "how_much" = "That pizza will cost you VALUE credits.", + + "compliment_deny" = "That's a bit forward, don't you think?", + "compliment_accept" = "Thanks, sir! You're very nice!", + "insult_good" = "Please stop that, sir.", + "insult_bad" = "Sir, just because I'm contractually obligated to keep you on the line for a minute doesn't mean I have to take this.", + + "bribe_refusal" = "Uh... thanks for the cash, sir. As long as you're in the area, we'll be here...", + ) + +/datum/trader/pizzaria/trade(var/list/offers, var/num, var/turf/location) + . = ..() + if(.) + var/atom/movable/M = . + var/obj/item/pizzabox/box = new(location) + M.forceMove(box) + box.pizza = M + box.boxtag = "A special order from [origin]" + +/datum/trader/ship/chinese + name = "Chinese Restaurant" + name_language = TRADER_DEFAULT_NAME + origin = "Captain Panda Bistro" + possible_origins = list("888 Shanghai Kitchen", "Mr. Lee's Greater Hong Kong", "The House of the Venerable and Inscrutable Colonel", "Lucky Dragon") + trade_flags = TRADER_MONEY + possible_wanted_items = list() + possible_trading_items = list(/obj/item/weapon/reagent_containers/food/snacks/meatkabob = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/monkeysdelight = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/ricepudding = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/slice/xenomeatbread/filled = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/soydope = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/stewedsoymeat = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/wingfangchu = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/drinks/dry_ramen = TRADER_THIS_TYPE + ) + + var/list/fortunes = list("Today it's up to you to create the peacefulness you long for.", + "If you refuse to accept anything but the best, you very often get it.", + "A smile is your passport into the hearts of others.", + "Hard work pays off in the future, laziness pays off now.", + "Change can hurt, but it leads a path to something better.", + "Hidden in a valley beside an open stream- This will be the type of place where you will find your dream.", + "Never give up. You're not a failure if you don't give up.", + "Love can last a lifetime, if you want it to.", + "The love of your life is stepping into your planet this summer.", + "Your ability for accomplishment will follow with success.", + "Please help me, I'm trapped in a fortune cookie factory!") + + speech = list("hail_generic" = "There are two things constant in life, death and Chinese food. How may I help you?", + "hail_deny" = "We do not take orders from rude customers.", + + "trade_complete" = "Thank you, sir, for your patronage.", + "trade_blacklist" = "No, that is very odd. Why would you trade that away?", + "trade_no_goods" = "I only accept money transfers.", + "trade_not_enough" = "No, I am sorry, that is not possible. I need to make a living.", + "how_much" = "I give you ITEM, for VALUE credits. No more, no less.", + + "compliment_deny" = "That was an odd thing to say. You are very odd.", + "compliment_accept" = "Good philosophy, see good in bad, I like.", + "insult_good" = "As a man said long ago, \"When anger rises, think of the consequences.\" Think on that.", + "insult_bad" = "I do not need to take this from you.", + + "bribe_refusal" = "Hm... I'll think about it.", + "bribe_accept" = "Oh yes! I think I'll stay a few more minutes, then.", + ) + +/datum/trader/ship/chinese/trade(var/list/offers, var/num, var/turf/location) + . = ..() + if(.) + var/obj/item/weapon/reagent_containers/food/snacks/fortunecookie/cookie = new(location) + var/obj/item/weapon/paper/paper = new(cookie) + cookie.trash = paper + paper.SetName("Fortune") + paper.info = pick(fortunes) + +/datum/trader/grocery + name = "Grocer" + name_language = TRADER_DEFAULT_NAME + possible_origins = list("HyTee", "Kreugars", "Spaceway", "Privaxs", "FutureValue", "Phyvendyme", "Skreller's Market") + trade_flags = TRADER_MONEY + + possible_trading_items = list(/obj/item/weapon/reagent_containers/food/snacks = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/reagent_containers/food/drinks/cans = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/reagent_containers/food/drinks/bottle = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/reagent_containers/food/drinks/bottle/small = TRADER_BLACKLIST, + /obj/item/weapon/reagent_containers/food/snacks/boiledslimecore = TRADER_BLACKLIST, + /obj/item/weapon/reagent_containers/food/snacks/checker = TRADER_BLACKLIST_ALL, + /obj/item/weapon/reagent_containers/food/snacks/fruit_slice = TRADER_BLACKLIST, + /obj/item/weapon/reagent_containers/food/snacks/slice = TRADER_BLACKLIST_ALL, + /obj/item/weapon/reagent_containers/food/snacks/grown = TRADER_BLACKLIST_ALL, + /obj/item/weapon/reagent_containers/food/snacks/human = TRADER_BLACKLIST_ALL, + /obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake = TRADER_BLACKLIST, + /obj/item/weapon/reagent_containers/food/snacks/meat/human = TRADER_BLACKLIST, + /obj/item/weapon/reagent_containers/food/snacks/variable = TRADER_BLACKLIST_ALL + ) + + speech = list("hail_generic" = "Hello, welcome to ORIGIN, grocery store of the future!", + "hail_deny" = "I'm sorry, we've blacklisted your communications due to rude behavior.", + + "trade_complete" = "Thank you for shopping at ORIGIN!", + "trade_blacklist" = "I... wow, that's... no, sir. No.", + "trade_no_goods" = "ORIGIN only accepts cash, sir.", + "trade_not_enough" = "That is not enough money, sir.", + "how_much" = "Sir, that'll cost you VALUE credits. Will that be all?", + + "compliment_deny" = "Sir, this is a professional environment. Please don't make me get my manager.", + "compliment_accept" = "Thank you, sir!", + "insult_good" = "Sir, please do not make a scene.", + "insult_bad" = "Sir, I WILL get my manager if you don't calm down.", + + "bribe_refusal" = "Of course sir! ORIGIN is always here for you!", + ) + +/datum/trader/bakery + name = "Pastry Chef" + name_language = TRADER_DEFAULT_NAME + origin = "Bakery" + possible_origins = list("Cakes By Design", "Corner Bakery Local", "My Favorite Cake & Pastry Cafe", "Mama Joes Bakery", "Sprinkles and Fun", "Cakestrosity") + + speech = list("hail_generic" = "Hello, welcome to ORIGIN! We serve baked goods, including pies, cakes, and anything sweet!", + "hail_deny" = "Our food is a privilege, not a right. Goodbye.", + + "trade_complete" = "Thank you for your purchase! Come again if you're hungry for more!", + "trade_blacklist" = "We only accept money. Not... that.", + "trade_no_goods" = "Cash for cakes! That's our business!", + "trade_not_enough" = "Our dishes are much more expensive than that, sir.", + "how_much" = "That lovely dish will cost you VALUE credits.", + + "compliment_deny" = "Oh wow, how nice of you...", + "compliment_accept" = "You're almost as sweet as my pies!", + "insult_good" = "My pies are NOT knockoffs!", + "insult_bad" = "Well, aren't you a sour apple?", + + "bribe_refusal" = "Oh ho ho! I'd never think of taking ORIGIN on the road!", + ) + possible_trading_items = list(/obj/item/weapon/reagent_containers/food/snacks/slice/birthdaycake/filled = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/slice/carrotcake/filled = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/slice/cheesecake/filled = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/slice/chocolatecake/filled = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/slice/lemoncake/filled = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/slice/limecake/filled = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/slice/orangecake/filled = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/slice/plaincake/filled = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/slice/pumpkinpie/filled = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/slice/bananabread/filled = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/sliceable = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza = TRADER_BLACKLIST_ALL, + /obj/item/weapon/reagent_containers/food/snacks/sliceable/xenomeatbread = TRADER_BLACKLIST, + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough = TRADER_BLACKLIST, + /obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake = TRADER_BLACKLIST, + /obj/item/weapon/reagent_containers/food/snacks/pie = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/applepie = TRADER_THIS_TYPE) \ No newline at end of file diff --git a/code/datums/trading/goods.dm b/code/datums/trading/goods.dm new file mode 100644 index 00000000..1375b8d2 --- /dev/null +++ b/code/datums/trading/goods.dm @@ -0,0 +1,406 @@ +/datum/trader/ship/toyshop + name = "Toy Shop Employee" + name_language = TRADER_DEFAULT_NAME + origin = "Toy Shop" + trade_flags = TRADER_GOODS|TRADER_MONEY|TRADER_WANTED_ONLY + possible_origins = list("Toys R Ours", "LEGS GO", "Kay-Cee Toys", "Build-a-Cat", "Magic Box", "The Positronic's Dungeon and Baseball Card Shop") + speech = list("hail_generic" = "Uhh... hello? Welcome to ORIGIN, I hope you have a, uhh.... good shopping trip.", + "hail_deny" = "Nah, you're not allowed here. At all", + + "trade_complete" = "Thanks for shopping... here... at ORIGIN.", + "trade_blacklist" = "Uuuhhh.... no.", + "trade_found_unwanted" = "Nah! That's not what I'm looking for. Something rarer.", + "trade_not_enough" = "Just 'cause they're made of cardboard doesn't mean they don't cost money...", + "how_much" = "Uhh... I'm thinking like... VALUE. Right? Or something rare that complements my interest.", + "what_want" = "Ummmm..... I guess I want", + + "compliment_deny" = "Ha! Very funny! You should write your own television show.", + "compliment_accept" = "Why yes, I do work out.", + "insult_good" = "Well, well, well. Guess we learned who was the troll here.", + "insult_bad" = "I've already written a nasty Spacebook post in my mind about you.", + + "bribe_refusal" = "Nah. I need to get moving as soon as uhh... possible.", + "bribe_accept" = "You know what, I wasn't doing anything for TIME minutes anyways.", + ) + + possible_wanted_items = list(/obj/item/toy/figure = TRADER_THIS_TYPE, + /obj/item/toy/figure/ert = TRADER_THIS_TYPE, + /obj/item/toy/prize/honk = TRADER_THIS_TYPE) + + possible_trading_items = list(/obj/item/toy/prize = TRADER_SUBTYPES_ONLY, + /obj/item/toy/prize/honk = TRADER_BLACKLIST, + /obj/item/toy/figure = TRADER_SUBTYPES_ONLY, + /obj/item/toy/figure/ert = TRADER_BLACKLIST, + /obj/item/toy/plushie = TRADER_SUBTYPES_ONLY, + /obj/item/toy/katana = TRADER_THIS_TYPE, + /obj/item/toy/sword = TRADER_THIS_TYPE, + /obj/item/toy/bosunwhistle = TRADER_THIS_TYPE, + /obj/item/weapon/board = TRADER_THIS_TYPE, + /obj/item/weapon/storage/box/checkers = TRADER_ALL, + /obj/item/weapon/deck = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/pack = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/dice = TRADER_ALL, + /obj/item/weapon/dice/d20/cursed = TRADER_BLACKLIST) + +/datum/trader/ship/electronics + name = "Electronic Shop Employee" + name_language = TRADER_DEFAULT_NAME + origin = "Electronic Shop" + possible_origins = list("Best Sale", "Overstore", "Oldegg", "Circuit Citadel", "Silicon Village", "Positronic Solutions LLC", "Sunvolt Inc.") + + speech = list("hail_generic" = "Hello, sir! Welcome to ORIGIN, I hope you find what you are looking for.", + "hail_deny" = "Your call has been disconnected.", + + "trade_complete" = "Thank you for shopping at ORIGIN, would you like to get the extended warranty as well?", + "trade_blacklist" = "Sir, this is a /electronics/ store.", + "trade_no_goods" = "As much as I'd love to buy that from you, I can't.", + "trade_not_enough" = "Your offer isn't adequate, sir.", + "how_much" = "Your total comes out to VALUE credits.", + + "compliment_deny" = "Hahaha! Yeah... funny...", + "compliment_accept" = "That's very nice of you!", + "insult_good" = "That was uncalled for, sir. Don't make me get my manager.", + "insult_bad" = "Sir, I am allowed to hang up the phone if you continue, sir.", + + "bribe_refusal" = "Sorry, sir, but I can't really do that.", + "bribe_accept" = "Why not! Glad to be here for a few more minutes.", + ) + + possible_trading_items = list(/obj/item/weapon/computer_hardware/battery_module = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/circuitboard = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/circuitboard/telecomms = TRADER_BLACKLIST, + /obj/item/weapon/circuitboard/unary_atmos = TRADER_BLACKLIST, + /obj/item/weapon/circuitboard/arcade = TRADER_BLACKLIST, + /obj/item/weapon/circuitboard/mecha = TRADER_BLACKLIST, + /obj/item/weapon/circuitboard/mecha/odysseus = TRADER_BLACKLIST, + /obj/item/weapon/circuitboard/mecha/honker = TRADER_BLACKLIST, + /obj/item/weapon/circuitboard/mecha/durand = TRADER_BLACKLIST, + /obj/item/weapon/circuitboard/mecha/gygax = TRADER_BLACKLIST, + /obj/item/weapon/circuitboard/mecha/ripley = TRADER_BLACKLIST, + /obj/item/weapon/circuitboard/broken = TRADER_BLACKLIST, + /obj/item/stack/cable_coil = TRADER_SUBTYPES_ONLY, + /obj/item/stack/cable_coil/cyborg = TRADER_BLACKLIST, + /obj/item/stack/cable_coil/random = TRADER_BLACKLIST, + /obj/item/stack/cable_coil/cut = TRADER_BLACKLIST, + /obj/item/weapon/airalarm_electronics = TRADER_THIS_TYPE, + /obj/item/weapon/airlock_electronics = TRADER_ALL, + /obj/item/weapon/cell = TRADER_THIS_TYPE, + /obj/item/weapon/cell/crap = TRADER_THIS_TYPE, + /obj/item/weapon/cell/high = TRADER_THIS_TYPE, + /obj/item/weapon/cell/super = TRADER_THIS_TYPE, + /obj/item/weapon/cell/hyper = TRADER_THIS_TYPE, + /obj/item/weapon/module = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/tracker_electronics = TRADER_THIS_TYPE) + + +/* Clothing stores: each a different type. A hat/glove store, a shoe store, and a jumpsuit store. */ + +/datum/trader/ship/clothingshop + name = "Clothing Store Employee" + name_language = TRADER_DEFAULT_NAME + origin = "Clothing Store" + possible_origins = list("Space Eagle", "Banana Democracy", "Forever 22", "Textiles Factory Warehouse Outlet", "Blocks Brothers") + speech = list("hail_generic" = "Hello, sir! Welcome to ORIGIN!", + "hail_Vox" = "Well hello, sir! I don't believe we have any clothes that fit you... but you can still look!", + "hail_deny" = "We do not trade with rude customers. Consider yourself blacklisted.", + + "trade_complete" = "Thank you for shopping at ORIGIN. Remember: We cannot accept returns without the original tags!", + "trade_blacklist" = "Hm, how about no?", + "trade_no_goods" = "We don't buy, sir. Only sell.", + "trade_not_enough" = "Sorry, ORIGIN policy to not accept trades below our marked prices.", + "how_much" = "Your total comes out to VALUE credits.", + + "compliment_deny" = "Excuse me?", + "compliment_accept" = "Aw, you're so nice!", + "insult_good" = "Sir.", + "insult_bad" = "Wow. I don't have to take this.", + + "bribe_refusal" = "ORIGIN policy clearly states we cannot stay for more than the designated time.", + "bribe_accept" = "Hm.... sure! We'll have a few minutes of 'engine troubles'.", + ) + + possible_trading_items = list(/obj/item/clothing/under = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/under/acj = TRADER_BLACKLIST, + /obj/item/clothing/under/chameleon = TRADER_BLACKLIST, + /obj/item/clothing/under/cloud = TRADER_BLACKLIST, + /obj/item/clothing/under/color = TRADER_BLACKLIST, + /obj/item/clothing/under/dress = TRADER_BLACKLIST, + /obj/item/clothing/under/ert = TRADER_BLACKLIST, + /obj/item/clothing/under/gimmick = TRADER_BLACKLIST_ALL, + /obj/item/clothing/under/lawyer = TRADER_BLACKLIST, + /obj/item/clothing/under/pj = TRADER_BLACKLIST, + /obj/item/clothing/under/rank = TRADER_BLACKLIST, + /obj/item/clothing/under/shorts = TRADER_BLACKLIST, + /obj/item/clothing/under/stripper = TRADER_BLACKLIST_ALL, + /obj/item/clothing/under/swimsuit = TRADER_BLACKLIST, + /obj/item/clothing/under/syndicate = TRADER_BLACKLIST_ALL, + /obj/item/clothing/under/tactical = TRADER_BLACKLIST, + /obj/item/clothing/under/vox = TRADER_BLACKLIST_ALL, + /obj/item/clothing/under/wedding = TRADER_BLACKLIST, + /obj/item/clothing/under/punpun = TRADER_BLACKLIST) + +/datum/trader/ship/clothingshop/shoes + possible_origins = list("Foot Safe", "Paysmall", "Popular Footwear", "Grimbly's Shoes", "Right Steps") + possible_trading_items = list(/obj/item/clothing/shoes = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/shoes/chameleon = TRADER_BLACKLIST, + /obj/item/clothing/shoes/combat = TRADER_BLACKLIST, + /obj/item/clothing/shoes/clown_shoes = TRADER_BLACKLIST, + /obj/item/clothing/shoes/cult = TRADER_BLACKLIST, + /obj/item/clothing/shoes/cyborg = TRADER_BLACKLIST, + /obj/item/clothing/shoes/magboots = TRADER_BLACKLIST_ALL, + /obj/item/clothing/shoes/swat = TRADER_BLACKLIST, + /obj/item/clothing/shoes/syndigaloshes = TRADER_BLACKLIST) + +/datum/trader/ship/clothingshop/hatglovesaccessories + possible_origins = list("Baldie's Hats and Accessories", "The Right Fit", "Like a Glove", "Space Fashion") + possible_trading_items = list(/obj/item/clothing/accessory = TRADER_ALL, + /obj/item/clothing/accessory/badge = TRADER_BLACKLIST_ALL, + /obj/item/clothing/accessory/holster = TRADER_BLACKLIST_ALL, + /obj/item/clothing/accessory/medal = TRADER_BLACKLIST_ALL, + /obj/item/clothing/accessory/storage = TRADER_BLACKLIST_ALL, + /obj/item/clothing/gloves = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/gloves/thick/swat = TRADER_BLACKLIST, + /obj/item/clothing/gloves/chameleon = TRADER_BLACKLIST, + /obj/item/clothing/head = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/head/HoS = TRADER_BLACKLIST_ALL, + /obj/item/clothing/head/beret/centcom = TRADER_BLACKLIST_ALL, + /obj/item/clothing/head/bio_hood = TRADER_BLACKLIST_ALL, + /obj/item/clothing/head/bomb_hood = TRADER_BLACKLIST_ALL, + /obj/item/clothing/head/caphat = TRADER_BLACKLIST_ALL, + /obj/item/clothing/head/centhat = TRADER_BLACKLIST, + /obj/item/clothing/head/chameleon = TRADER_BLACKLIST, + /obj/item/clothing/head/collectable = TRADER_BLACKLIST, + /obj/item/clothing/head/culthood = TRADER_BLACKLIST_ALL, + /obj/item/clothing/head/helmet = TRADER_BLACKLIST_ALL, + /obj/item/clothing/head/radiation = TRADER_BLACKLIST, + /obj/item/clothing/head/tajaran = TRADER_BLACKLIST, + /obj/item/clothing/head/warden = TRADER_BLACKLIST, + /obj/item/clothing/head/welding = TRADER_BLACKLIST) + + + +/* +Sells devices, odds and ends, and medical stuff +*/ +/datum/trader/devices + name = "Drugstore Employee" + name_language = TRADER_DEFAULT_NAME + origin = "Drugstore" + possible_origins = list("Buy 'n Save", "Drug Carnival", "C&B", "Fentles", "Dr. Goods", "Beevees", "McGillicuddy's") + possible_trading_items = list(/obj/item/device/flashlight = TRADER_ALL, + /obj/item/device/kit/paint = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/aicard = TRADER_THIS_TYPE, + /obj/item/device/binoculars = TRADER_THIS_TYPE, + /obj/item/device/cable_painter = TRADER_THIS_TYPE, + /obj/item/device/flash = TRADER_THIS_TYPE, + /obj/item/device/floor_painter = TRADER_THIS_TYPE, + /obj/item/device/multitool = TRADER_THIS_TYPE, + /obj/item/device/lightreplacer = TRADER_THIS_TYPE, + /obj/item/device/megaphone = TRADER_THIS_TYPE, + /obj/item/device/paicard = TRADER_THIS_TYPE, + /obj/item/device/pipe_painter = TRADER_THIS_TYPE, + /obj/item/device/healthanalyzer = TRADER_THIS_TYPE, + /obj/item/device/analyzer = TRADER_ALL, + /obj/item/device/mass_spectrometer = TRADER_ALL, + /obj/item/device/reagent_scanner = TRADER_ALL, + /obj/item/device/slime_scanner = TRADER_THIS_TYPE, + /obj/item/device/suit_cooling_unit = TRADER_THIS_TYPE, + /obj/item/device/t_scanner = TRADER_THIS_TYPE, + /obj/item/device/taperecorder = TRADER_THIS_TYPE, + /obj/item/device/batterer = TRADER_THIS_TYPE, + /obj/item/device/violin = TRADER_THIS_TYPE, + /obj/item/device/hailer = TRADER_THIS_TYPE, + /obj/item/device/uv_light = TRADER_THIS_TYPE, + /obj/item/device/mmi = TRADER_ALL, + /obj/item/device/robotanalyzer = TRADER_THIS_TYPE, + /obj/item/device/toner = TRADER_THIS_TYPE, + /obj/item/device/camera_film = TRADER_THIS_TYPE, + /obj/item/device/camera = TRADER_THIS_TYPE, + /obj/item/device/destTagger = TRADER_THIS_TYPE, + /obj/item/device/gps = TRADER_THIS_TYPE, + /obj/item/device/measuring_tape = TRADER_THIS_TYPE, + /obj/item/device/ano_scanner = TRADER_THIS_TYPE, + /obj/item/device/core_sampler = TRADER_THIS_TYPE, + /obj/item/device/depth_scanner = TRADER_THIS_TYPE, + /obj/item/weapon/pinpointer/radio = TRADER_THIS_TYPE, + /obj/item/device/antibody_scanner = TRADER_THIS_TYPE, + /obj/item/stack/medical/advanced = TRADER_BLACKLIST) + speech = list("hail_generic" = "Hello, hello! Bits and bobs and everything in between, I hope you find what you're looking for!", + "hail_silicon" = "Ah! Hello, robot. We only sell things that, ah.... people can hold in their hands, unfortunately. You are still allowed to buy, though!", + "hail_deny" = "Oh no. I don't want to deal with YOU.", + + "trade_complete" = "Thank you! Now remember, there isn't any return policy here, so be careful with that!", + "trade_blacklist" = "Hm. Well that would be illegal, so no.", + "trade_no_goods" = "I'm sorry, I only sell goods.", + "trade_not_enough" = "Gotta pay more than that to get that!", + "how_much" = "Well... I bought it for a lot, but I'll give it to you for VALUE.", + + "compliment_deny" = "Uh... did you say something?", + "compliment_accept" = "Mhm! I can agree to that!", + "insult_good" = "Wow, where was that coming from?", + "insult_bad" = "Don't make me blacklist your connection.", + + "bribe_refusal" = "Well, as much as I'd love to say 'yes', you realize I operate on a station, correct?", + ) + +/datum/trader/ship/robots + name = "Robot Seller" + name_language = TRADER_DEFAULT_NAME + origin = "Robot Store" + possible_origins = list("AI for the Straight Guy", "Mechanical Buddies", "Bot Chop Shop", "Omni Consumer Projects") + possible_trading_items = list(/obj/item/weapon/secbot_assembly/ed209_assembly = TRADER_THIS_TYPE, + /obj/item/weapon/toolbox_tiles = TRADER_THIS_TYPE, + /obj/item/weapon/toolbox_tiles_sensor = TRADER_THIS_TYPE, + /obj/item/weapon/secbot_assembly = TRADER_ALL, + /obj/item/weapon/farmbot_arm_assembly = TRADER_THIS_TYPE, + /obj/item/weapon/firstaid_arm_assembly = TRADER_THIS_TYPE, + /obj/item/weapon/bucket_sensor = TRADER_THIS_TYPE, + /obj/item/device/bot_kit = TRADER_THIS_TYPE, + /obj/item/device/paicard = TRADER_THIS_TYPE, + /obj/item/weapon/aicard = TRADER_THIS_TYPE, + /mob/living/bot = TRADER_SUBTYPES_ONLY) + speech = list("hail_generic" = "Welcome to ORIGIN! Let me walk you through our fine robotic selection!", + "hail_silicon" = "Welcome to ORIGIN! Let- oh, you're a synth! Well, your money is good anyway. Welcome, welcome!", + "hail_deny" = "ORIGIN no longer wants to speak to you.", + + "trade_complete" = "I hope you enjoy your new robot!", + "trade_blacklist"= "I work with robots, sir. Not that.", + "trade_no_goods" = "You gotta buy the robots, sir. I don't do trades.", + "trade_not_enough" = "You're coming up short on cash.", + "how_much" = "My fine selection of robots will cost you VALUE!", + + "compliment_deny"= "Well, I almost believed that.", + "compliment_accept"= "Thank you! My craftsmanship is my life.", + "insult_good" = "Uncalled for.... uncalled for.", + "insult_bad" = "I've programmed AI better at insulting than you!", + + "bribe_refusal" = "I've got too many customers waiting in other sectors, sorry.", + "bribe_accept" = "Hm. Don't keep me waiting too long, though.", + ) + +/datum/trader/xeno_shop + name = "Xenolife Collector" + origin = "CSV Not a Poacher" + trade_flags = TRADER_GOODS|TRADER_MONEY|TRADER_WANTED_ONLY|TRADER_WANTED_ALL + possible_origins = list("XenoHugs","NT Specimen Acquisition","Lonely Pete's Exotic Companionship","Space Wei's Exotic Cuisine") + speech = list("hail_generic" = "Welcome! We are always looking to acquire more exotic life forms.", + "hail_deny" = "We no longer wish to speak to you. Please contact our legal representative if you wish to rectify this.", + + "trade_complete" = "Remember to give them attention and food. They are living beings, and you should treat them like so.", + "trade_blacklist" = "Legally I can't do that. Morally... well, I refuse to do that.", + "trade_found_unwanted" = "I only want animals. I don't need food or shiny things. I'm looking for specific ones, at that. Ones I already have the cage and food for.", + "trade_not_enough" = "I'd give you this for free, but I need the money to feed the specimens. So you must pay in full.", + "how_much" = "This is a good choice. I believe it will cost you VALUE credits.", + "what_want" = "I have the facilities, currently, to support", + + "compliment_deny" = "According to customs on 34 planets I traded with, this constitutes sexual harrasment.", + "compliment_accept" = "Thank you. I needed that.", + "insult_good" = "No need to be upset, I believe we can do business.", + "insult_bad" = "I have traded dogs with more bark than that.", + ) + + possible_wanted_items = list(/mob/living/simple_animal/tindalos = TRADER_THIS_TYPE, + /mob/living/simple_animal/tomato = TRADER_THIS_TYPE, + /mob/living/simple_animal/yithian = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/retaliate/beast/diyaab = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/retaliate/beast/shantak= TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/retaliate/beast/samak= TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/carp = TRADER_THIS_TYPE) + + possible_trading_items = list(/mob/living/simple_animal/hostile/carp= TRADER_THIS_TYPE, + /obj/item/device/dociler = TRADER_THIS_TYPE, + /obj/item/weapon/beartrap = TRADER_THIS_TYPE, + /obj/item/device/slime_scanner = TRADER_THIS_TYPE) + +/datum/trader/medical + name = "Medical Supplier" + origin = "Infirmary of CSV Iniquity" + trade_flags = TRADER_GOODS|TRADER_MONEY|TRADER_WANTED_ONLY + want_multiplier = 1.2 + margin = 2 + possible_origins = list("Dr.Krieger's Practice", "Legit Medical Supplies (No Refund)", "Mom's & Pop's Addictive Opoids", "Legitimate Pharmaceutical Firm", "Designer Drugs by Lil Xanny") + speech = list("hail_generic" = "Huh? How'd you get this number?! Oh well, if you wanna talk biz, I'm listening.", + "hail_deny" = "This is an automated message. Feel free to fuck the right off after the buzzer. *buzz*", + + "trade_complete" = "Good to have business with ya. Remember, no refunds.", + "trade_blacklist" = "Whoa whoa, I don't want this shit, put it away.", + "trade_found_unwanted" = "What the hell do you expect me to do with this junk?", + "trade_not_enough" = "Sorry, pal, full payment upfront, I don't write the rules. Well, I do, but that's beside the point.", + "how_much" = "Hmm, this is one damn fine item, but I'll part with it for VALUE credits.", + "what_want" = "I could always use some fucking", + + "compliment_deny" = "Haha, how nice of you. Why don't you go fall in an elevator shaft.", + "compliment_accept" = "Damn right I'm awesome, tell me more.", + "insult_good" = "Damn, pal, no need to get snippy.", + "insult_bad" = "*muffled laughter* Sorry, was that you trying to talk shit? Adorable.", + ) + + possible_wanted_items = list(/obj/item/weapon/reagent_containers/food/drinks/bottle = TRADER_THIS_TYPE, + /obj/item/organ/internal/liver = TRADER_THIS_TYPE, + /obj/item/organ/internal/kidneys = TRADER_THIS_TYPE, + /obj/item/organ/internal/lungs = TRADER_THIS_TYPE, + /obj/item/organ/internal/heart = TRADER_THIS_TYPE, + /obj/item/weapon/storage/fancy/cigarettes = TRADER_ALL + ) + + possible_trading_items = list(/obj/item/weapon/storage/pill_bottle = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/storage/firstaid/fire = TRADER_THIS_TYPE, + /obj/item/weapon/storage/firstaid/toxin = TRADER_THIS_TYPE, + /obj/item/weapon/storage/firstaid/adv = TRADER_THIS_TYPE, + /obj/item/weapon/storage/box/bloodpacks = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/ivbag = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/retractor = TRADER_THIS_TYPE, + /obj/item/weapon/hemostat = TRADER_THIS_TYPE, + /obj/item/weapon/cautery = TRADER_THIS_TYPE, + /obj/item/weapon/surgicaldrill = TRADER_THIS_TYPE, + /obj/item/weapon/scalpel = TRADER_THIS_TYPE, + /obj/item/weapon/scalpel/manager = TRADER_THIS_TYPE, + /obj/item/weapon/circular_saw = TRADER_THIS_TYPE, + /obj/item/weapon/bonegel = TRADER_THIS_TYPE, + /obj/item/weapon/bonesetter = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/glass/bottle/inaprovaline = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/glass/bottle/stoxin = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/glass/bottle/antitoxin = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/glass/bottle/inaprovaline = TRADER_THIS_TYPE, + /obj/item/bodybag/cryobag = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/dexalin/small = TRADER_THIS_TYPE, + /obj/item/sign/medipolma = TRADER_THIS_TYPE + ) + +/datum/trader/mining + name = "Rock'n'Drill Mining Inc" + origin = "Automated Smelter AH-532" + trade_flags = TRADER_GOODS|TRADER_MONEY|TRADER_WANTED_ONLY|TRADER_WANTED_ALL + want_multiplier = 1.5 + margin = 2 + possible_origins = list("Automated Smelter AH-532", "CMV Locust", "The Galactic Foundry Company", "Crucible LLC") + speech = list("hail_generic" = "Welcome to R'n'D Mining. Please place your order.", + "hail_deny" = "There is no response on the line.", + + "trade_complete" = "Transaction complete. Please use our services again", + "trade_blacklist" = "Whoa whoa, I don't want this shit, put it away.", + "trade_found_unwanted" = "Sorry, we are currently not looking to purchase these items.", + "trade_not_enough" = "Sorry, this is an insufficient sum for this purchase.", + "how_much" = "For ONE entry of ITEM the price would be VALUE credits.", + "what_want" = "We are currently looking to procure", + + "compliment_deny" = "I am afraid this is beyond my competency.", + "compliment_accept" = "Thank you.", + "insult_good" = "Alright, we will reconsider the terms.", + "insult_bad" = "This is not acceptable, please cease.", + ) + + possible_wanted_items = list(/obj/item/weapon/ore/ = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/disk/survey = TRADER_THIS_TYPE, + /obj/item/weapon/ore/slag = TRADER_BLACKLIST) + + possible_trading_items = list(/obj/machinery/mining/drill = TRADER_THIS_TYPE, + /obj/machinery/mining/brace = TRADER_THIS_TYPE, + /obj/machinery/floodlight = TRADER_THIS_TYPE, + /obj/machinery/floodlight = TRADER_THIS_TYPE, + /obj/item/weapon/storage/box/greenglowsticks = TRADER_THIS_TYPE, + /obj/item/clothing/suit/space/void/engineering/salvage/prepared = TRADER_THIS_TYPE, + /obj/item/stack/material/uranium/ten = TRADER_THIS_TYPE, + /obj/item/stack/material/plasteel/fifty = TRADER_THIS_TYPE, + /obj/item/stack/material/steel/fifty = TRADER_THIS_TYPE + ) diff --git a/code/datums/trading/misc.dm b/code/datums/trading/misc.dm new file mode 100644 index 00000000..9d477e30 --- /dev/null +++ b/code/datums/trading/misc.dm @@ -0,0 +1,157 @@ +/datum/trader/ship/pet_shop + name = "Pet Shop Owner" + name_language = LANGUAGE_SKRELLIAN + origin = "Pet Shop" + trade_flags = TRADER_GOODS|TRADER_MONEY|TRADER_WANTED_ONLY + possible_origins = list("Paws-Out", "Pets-R-Smart", "Tentacle Companions", "Xeno-Pets and Assorted Goods", "Barks and Drools") + speech = list("hail_generic" = "Welcome to my xeno-pet shop! Here you will find many wonderful companions. Some a bit more... aggressive than others. But companions none the less. I also buy pets, or trade them.", + "hail_Skrell" = "Ah! A fellow Skrell. How wonderful, I may have a few pets imported from back home. Take a look.", + "hail_deny" = "I no longer wish to speak to you.", + + "trade_complete" = "Remember to give them attention and food. They are living beings, and you should treat them like so.", + "trade_blacklist" = "Legally I can' do that. Morally, I refuse to do that.", + "trade_found_unwanted" = "I only want animals. I don't need food or shiny things. I'm looking for specific ones at that. Ones I already have the cage and food for.", + "trade_not_enough" = "I'd give you the animal for free, but I need the money to feed the others. So you must pay in full.", + "how_much" = "This is a fine specimen. I believe it will cost you VALUE credits.", + "what_want" = "I have the facilities, currently, to support", + + "compliment_deny" = "That was almost charming.", + "compliment_accept" = "Thank you. I needed that.", + "insult_good" = "I ask you to stop. We can be peaceful. I know we can.", + "insult_bad" = "My interactions with you are becoming less than fruitful.", + + "bribe_refusal" = "I'm not going to do that. I have places to be.", + "bribe_accept" = "Hm. It'll be good for the animals, so sure.", + ) + + possible_wanted_items = list(/mob/living/simple_animal/corgi = TRADER_THIS_TYPE, + /mob/living/simple_animal/cat = TRADER_THIS_TYPE, + /mob/living/simple_animal/crab = TRADER_THIS_TYPE, + /mob/living/simple_animal/lizard = TRADER_THIS_TYPE, + /mob/living/simple_animal/mouse = TRADER_THIS_TYPE, + /mob/living/simple_animal/mushroom = TRADER_THIS_TYPE, + /mob/living/simple_animal/parrot = TRADER_THIS_TYPE, + /mob/living/simple_animal/tindalos = TRADER_THIS_TYPE, + /mob/living/simple_animal/tomato = TRADER_THIS_TYPE, + /mob/living/simple_animal/cow = TRADER_THIS_TYPE, + /mob/living/simple_animal/chick = TRADER_THIS_TYPE, + /mob/living/simple_animal/chicken = TRADER_THIS_TYPE, + /mob/living/simple_animal/yithian = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/retaliate/beast/diyaab = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/bear= TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/retaliate/beast/shantak= TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/retaliate/beast/samak= TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/retaliate/goat = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/carp = TRADER_THIS_TYPE) + + possible_trading_items = list(/mob/living/simple_animal/corgi = TRADER_THIS_TYPE, + /mob/living/simple_animal/cat = TRADER_THIS_TYPE, + /mob/living/simple_animal/crab = TRADER_THIS_TYPE, + /mob/living/simple_animal/lizard = TRADER_THIS_TYPE, + /mob/living/simple_animal/mouse = TRADER_THIS_TYPE, + /mob/living/simple_animal/mushroom = TRADER_THIS_TYPE, + /mob/living/simple_animal/parrot = TRADER_THIS_TYPE, + /mob/living/simple_animal/tindalos = TRADER_THIS_TYPE, + /mob/living/simple_animal/tomato = TRADER_THIS_TYPE, + /mob/living/simple_animal/cow = TRADER_THIS_TYPE, + /mob/living/simple_animal/chick = TRADER_THIS_TYPE, + /mob/living/simple_animal/chicken = TRADER_THIS_TYPE, + /mob/living/simple_animal/yithian = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/retaliate/beast/diyaab = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/bear= TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/retaliate/beast/shantak= TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/retaliate/beast/samak= TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/retaliate/goat = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/carp= TRADER_THIS_TYPE, + /obj/item/device/dociler = TRADER_THIS_TYPE, + /obj/structure/dogbed = TRADER_THIS_TYPE) + +/datum/trader/ship/prank_shop + name = "Prank Shop Owner" + name_language = LANGUAGE_ROOTLOCAL + origin = "Prank Shop" + compliment_increase = 0 + insult_drop = 0 + possible_origins = list("Yacks and Yucks Shop", "The Shop From Which I Sell Humorous Items", "The Prank Gestalt", "The Clown's Armory", "Uncle Knuckle's Chuckle Bunker", "A Place from Which to do Humorous Business") + speech = list("hail_generic" = "We welcome you to our shop of humorous items. We invite you to partake in the divine experience of being pranked, and pranking someone else.", + "hail_Diona" = "Welcome, other gestalt. We invite you to learn of our experiences, and teach us of your own.", + "hail_deny" = "We cannot do business with you. We are sorry.", + + "trade_complete" = "We thank you for purchasing something. We enjoyed the experience of you doing so and we hope to learn from it.", + "trade_blacklist"= "We are not allowed to do such. We are sorry.", + "trade_not_enough"="We have sufficiently experienced giving away goods for free. We wish to experience getting money in return.", + "how_much" = "We believe that is worth VALUE credits.", + "what_want" = "We wish only for the experiences you give us, in all else we want", + + "compliment_deny"= "You are attempting to compliment us.", + "compliment_accept"="You are attempting to compliment us.", + "insult_good" = "You are attempting to insult us, correct?", + "insult_bad" = "We do not understand.", + + "bribe_refusal" = "We are sorry, but we cannot accept.", + "bribe_accept" = "We are happy to say that we accept this bribe.", + ) + possible_trading_items = list(/obj/item/clothing/mask/gas/clown_hat = TRADER_THIS_TYPE, + /obj/item/clothing/mask/gas/mime = TRADER_THIS_TYPE, + /obj/item/clothing/shoes/clown_shoes = TRADER_THIS_TYPE, + /obj/item/clothing/under/rank/clown = TRADER_THIS_TYPE, + /obj/item/device/pda/clown = TRADER_THIS_TYPE, + /obj/item/weapon/cartridge/clown = TRADER_THIS_TYPE, + /obj/item/weapon/stamp/clown = TRADER_THIS_TYPE, + /obj/item/weapon/storage/backpack/clown = TRADER_THIS_TYPE, + /obj/item/weapon/bananapeel = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/food/snacks/pie = TRADER_THIS_TYPE, + /obj/item/weapon/bikehorn = TRADER_THIS_TYPE, + /obj/item/weapon/reagent_containers/spray/waterflower = TRADER_THIS_TYPE, + /obj/item/weapon/gun/launcher/pneumatic/small = TRADER_THIS_TYPE, + /obj/item/weapon/gun/projectile/revolver/capgun = TRADER_THIS_TYPE, + /obj/item/clothing/mask/fakemoustache = TRADER_THIS_TYPE, + /obj/item/weapon/grenade/spawnergrenade/fake_carp = TRADER_THIS_TYPE) + +/datum/trader/ship/replica_shop + name = "Replica Store Owner" + name_language = TRADER_DEFAULT_NAME + origin = "Replica Store" + possible_origins = list("Ye-Old Armory", "Knights and Knaves", "The Blacksmith", "Historical Human Apparel and Items", "The Pointy End", "Fight Knight's Knightly Nightly Knight Fights", "Elminster's Fine Steel", "The Arms of King Duordan", "Queen's Edict") + speech = list("hail_generic" = "Greetings, traveler! You've the look of one with a keen hunger for human history. Come in, and learn! Mayhaps even... buy?", + "hail_Unathi" = "Ah, you've the look of a lizard who knows his way around martial combat. Come in! We can only hope our steel meets the formidable Moghedi standards.", + "hail_deny" = "I shan't palaver with a man who thumbs his nose at the annals of history. Goodbye.", + + "trade_complete" = "Thank you, mighty warrior. And remember - these may be replicas, but their edges are honed to razor sharpness!", + "trade_blacklist"= "Nay, we accept only the credit. Or sovereigns of the king's mint, of course.", + "trade_not_enough"="Alas, traveler, my fine wares cost more than that.", + "how_much" = "For VALUE credits, I can part with this finest of goods.", + "what_want" = "I have ever longed for", + + "compliment_deny"= "Oh ho ho! Aren't you quite the jester.", + "compliment_accept"="Why, thank you, traveler! Long have I slaved over the anvil to produce these goods.", + "insult_good" = "Hey, bro, I'm just tryin' to make a living here, okay? The Camelot schtick is part of my brand.", + "insult_bad" = "Man, fuck you, then.", + + "bribe_refusal" = "Alas, traveler - I could stay all eve, but I've an Unathi client in waiting, and they are not known for patience.", + "bribe_accept" = "Mayhaps I could set a spell longer, and rest my weary feet.", + ) + possible_trading_items = list(/obj/item/clothing/head/wizard/magus = TRADER_THIS_TYPE, + /obj/item/weapon/shield/buckler = TRADER_THIS_TYPE, + /obj/item/clothing/head/redcoat = TRADER_THIS_TYPE, + /obj/item/clothing/head/powdered_wig = TRADER_THIS_TYPE, + /obj/item/clothing/head/hasturhood = TRADER_THIS_TYPE, + /obj/item/clothing/head/helmet/gladiator=TRADER_THIS_TYPE, + /obj/item/clothing/head/plaguedoctorhat= TRADER_THIS_TYPE, + /obj/item/clothing/glasses/monocle = TRADER_THIS_TYPE, + /obj/item/clothing/mask/smokable/pipe = TRADER_THIS_TYPE, + /obj/item/clothing/mask/gas/plaguedoctor=TRADER_THIS_TYPE, + /obj/item/clothing/suit/hastur = TRADER_THIS_TYPE, + /obj/item/clothing/suit/imperium_monk = TRADER_THIS_TYPE, + /obj/item/clothing/suit/judgerobe = TRADER_THIS_TYPE, + /obj/item/clothing/suit/wizrobe/magusred=TRADER_THIS_TYPE, + /obj/item/clothing/suit/wizrobe/magusblue=TRADER_THIS_TYPE, + /obj/item/clothing/under/gladiator = TRADER_THIS_TYPE, + /obj/item/clothing/under/kilt = TRADER_THIS_TYPE, + /obj/item/clothing/under/redcoat = TRADER_THIS_TYPE, + /obj/item/clothing/under/soviet = TRADER_THIS_TYPE, + /obj/item/weapon/material/harpoon = TRADER_THIS_TYPE, + /obj/item/weapon/material/sword = TRADER_ALL, + /obj/item/weapon/material/scythe = TRADER_THIS_TYPE, + /obj/item/weapon/material/star = TRADER_THIS_TYPE, + /obj/item/weapon/material/twohanded/baseballbat = TRADER_THIS_TYPE) \ No newline at end of file diff --git a/code/datums/trading/ship.dm b/code/datums/trading/ship.dm new file mode 100644 index 00000000..f685d5d4 --- /dev/null +++ b/code/datums/trading/ship.dm @@ -0,0 +1,24 @@ +//Ships are on a time limit as far as being around goes. +//They are ALSO the only ones that can appear after round start +/datum/trader/ship + var/duration_of_stay = 0 + var/typical_duration = 5 //5 minutes (since trader processes only tick once a minute) + +/datum/trader/ship/New() + ..() + duration_of_stay = rand(typical_duration,typical_duration * 2) + +/datum/trader/ship/tick() + ..() + if(prob(-disposition) || refuse_comms) + duration_of_stay-- + return --duration_of_stay > 0 + +/datum/trader/ship/bribe_to_stay_longer(var/amt) + if(prob(-disposition)) + return get_response("bribe_refusal", "How about.... no?") + + var/length = round(amt/100) + duration_of_stay += length + . = get_response("bribe_accept", "Sure, I'll stay for TIME more minutes.") + . = replacetext(., "TIME", length) \ No newline at end of file diff --git a/code/datums/trading/trade.dm b/code/datums/trading/trade.dm new file mode 100644 index 00000000..a13e3540 --- /dev/null +++ b/code/datums/trading/trade.dm @@ -0,0 +1,264 @@ +/datum/trader + var/name = "unsuspicious trader" //The name of the trader in question + var/origin = "some place" //The place that they are trading from + var/list/possible_origins //Possible names of the trader origin + var/disposition = 0 //The current disposition of them to us. + var/trade_flags = TRADER_MONEY //Flags + var/name_language //If this is set to a language name this will generate a name from the language + var/icon/portrait //The icon that shows up in the menu @TODO + + var/list/wanted_items = list() //What items they enjoy trading for. Structure is (type = known/unknown) + var/list/possible_wanted_items //List of all possible wanted items. Structure is (type = mode) + var/list/possible_trading_items //List of all possible trading items. Structure is (type = mode) + var/list/trading_items = list() //What items they are currently trading away. + var/list/blacklisted_trade_items = list(/mob/living/carbon/human) + //Things they will automatically refuse + + var/list/speech = list() //The list of all their replies and messages. Structure is (id = talk) + /*SPEECH IDS: + hail_generic When merchants hail a person + hail_[race] Race specific hails + hail_deny When merchant denies a hail + + insult_good When the player insults a merchant while they are on good disposition + insult_bad When a player insults a merchatn when they are not on good disposition + complement_accept When the merchant accepts a complement + complement_deny When the merchant refuses a complement + + how_much When a merchant tells the player how much something is. + trade_complete When a trade is made + trade_refuse When a trade is refused + + what_want What the person says when they are asked if they want something + + */ + var/want_multiplier = 2 //How much wanted items are multiplied by when traded for + var/margin = 1.2 //Multiplier to price when selling to player + var/insult_drop = 5 //How far disposition drops on insult + var/compliment_increase = 5 //How far compliments increase disposition + var/refuse_comms = 0 //Whether they refuse further communication + + var/mob_transfer_message = "You are transported to ORIGIN." //What message gets sent to mobs that get sold. + +/datum/trader/New() + ..() + if(name_language) + if(name_language == TRADER_DEFAULT_NAME) + name = capitalize(pick(GLOB.first_names_female + GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) + else + var/datum/language/L = all_languages[name_language] + if(L) + name = L.get_random_name(pick(MALE,FEMALE)) + if(possible_origins && possible_origins.len) + origin = pick(possible_origins) + + for(var/i in 3 to 6) + add_to_pool(trading_items, possible_trading_items, force = 1) + add_to_pool(wanted_items, possible_wanted_items, force = 1) + +//If this hits 0 then they decide to up and leave. +/datum/trader/proc/tick() + spawn(0) + add_to_pool(trading_items, possible_trading_items, 200) + add_to_pool(wanted_items, possible_wanted_items, 50) + remove_from_pool(possible_trading_items, 9) //We want the stock to change every so often, so we make it so that they have roughly 10~11 ish items max + return 1 + +/datum/trader/proc/remove_from_pool(var/list/pool, var/chance_per_item) + if(pool && prob(chance_per_item * pool.len)) + var/i = rand(1,pool.len) + pool[pool[i]] = null + pool -= pool[i] + +/datum/trader/proc/add_to_pool(var/list/pool, var/list/possible, var/base_chance = 100, var/force = 0) + var/divisor = 1 + if(pool && pool.len) + divisor = pool.len + if(force || prob(base_chance/divisor)) + var/new_item = get_possible_item(possible) + if(new_item) + pool |= new_item + +/datum/trader/proc/get_possible_item(var/list/trading_pool) + if(!trading_pool || !trading_pool.len) + return + var/list/possible = list() + for(var/type in trading_pool) + var/status = trading_pool[type] + if(status & TRADER_THIS_TYPE) + possible += type + if(status & TRADER_SUBTYPES_ONLY) + possible += subtypesof(type) + if(status & TRADER_BLACKLIST) + possible -= type + if(status & TRADER_BLACKLIST_SUB) + possible -= subtypesof(type) + + if(possible.len) + var/picked = pick(possible) + var/atom/A = picked + if(initial(A.name) in list("object", "item","weapon", "structure", "machinery", "Mecha", "organ", "snack")) //weed out a few of the common bad types. Reason we don't check types specifically is that (hopefully) further bad subtypes don't set their name up and are similar. + return + return picked + +/datum/trader/proc/get_response(var/key, var/default) + var/text + if(speech && speech[key]) + text = speech[key] + else + text = default + text = replacetext(text, "MERCHANT", name) + return replacetext(text, "ORIGIN", origin) + +/datum/trader/proc/print_trading_items(var/num) + num = Clamp(num,1,trading_items.len) + if(trading_items[num]) + var/atom/movable/M = trading_items[num] + return "[initial(M.name)]" + +/datum/trader/proc/get_item_value(var/trading_num) + if(!trading_items[trading_items[trading_num]]) + var/type = trading_items[trading_num] + var/value = get_value(type) + value = round(rand(90,110)/100 * value) //For some reason rand doesn't like decimals. + trading_items[type] = margin*value + return trading_items[trading_items[trading_num]] + +/datum/trader/proc/offer_money_for_trade(var/trade_num, var/money_amount) + if(!(trade_flags & TRADER_MONEY)) + return TRADER_NO_MONEY + var/value = get_item_value(trade_num) + if(money_amount < value) + return TRADER_NOT_ENOUGH + + return value + +/datum/trader/proc/offer_items_for_trade(var/list/offers, var/num, var/turf/location) + if(!offers || !offers.len) + return TRADER_NOT_ENOUGH + num = Clamp(num, 1, trading_items.len) + var/offer_worth = 0 + for(var/item in offers) + var/atom/movable/offer = item + var/is_wanted = 0 + if((trade_flags & TRADER_WANTED_ONLY) && is_type_in_list(offer,wanted_items)) + is_wanted = 2 + if((trade_flags & TRADER_WANTED_ALL) && is_type_in_list(offer,possible_wanted_items)) + is_wanted = 1 + if(blacklisted_trade_items && blacklisted_trade_items.len && is_type_in_list(offer,blacklisted_trade_items)) + return 0 + + if(istype(offer,/obj/item/weapon/spacecash)) + if(!(trade_flags & TRADER_MONEY)) + return TRADER_NO_MONEY + else + if(!(trade_flags & TRADER_GOODS)) + return TRADER_NO_GOODS + else if((trade_flags & TRADER_WANTED_ONLY|TRADER_WANTED_ALL) && !is_wanted) + return TRADER_FOUND_UNWANTED + + offer_worth += get_value(offer) * (is_wanted > 1 ? want_multiplier : 1) + if(!offer_worth) + return TRADER_NOT_ENOUGH + var/trading_worth = get_item_value(num) + if(!trading_worth) + return TRADER_NOT_ENOUGH + var/percent = offer_worth/trading_worth + if(percent > max(0.9,0.9-disposition/100)) + return trade(offers, num, location) + return TRADER_NOT_ENOUGH + +/datum/trader/proc/hail(var/mob/user) + var/specific + if(istype(user, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(H.species) + specific = H.species.name + else if(istype(user, /mob/living/silicon)) + specific = "silicon" + if(!speech["hail_[specific]"]) + specific = "generic" + . = get_response("hail_[specific]", "Greetings, MOB!") + . = replacetext(., "MOB", user.name) + +/datum/trader/proc/can_hail() + if(!refuse_comms && prob(-disposition)) + refuse_comms = 1 + return !refuse_comms + +/datum/trader/proc/insult() + disposition -= rand(insult_drop, insult_drop * 2) + if(prob(-disposition/10)) + refuse_comms = 1 + if(disposition > 50) + return get_response("insult_good","What? I thought we were cool!") + else + return get_response("insult_bad", "Right back at you asshole!") + +/datum/trader/proc/compliment() + if(prob(-disposition)) + return get_response("compliment_deny", "Fuck you!") + if(prob(100-disposition)) + disposition += rand(compliment_increase, compliment_increase * 2) + return get_response("compliment_accept", "Thank you!") + +/datum/trader/proc/trade(var/list/offers, var/num, var/turf/location) + if(offers && offers.len) + for(var/offer in offers) + if(istype(offer,/mob)) + var/text = mob_transfer_message + to_chat(offer, replacetext(text, "ORIGIN", origin)) + if(istype(offer, /obj/mecha)) + var/obj/mecha/M = offer + M.wreckage = null //So they don't ruin the illusion + qdel(offer) + + var/type = trading_items[num] + + var/atom/movable/M = new type(location) + playsound(location, 'sound/effects/teleport.ogg', 50, 1) + + disposition += rand(compliment_increase,compliment_increase*3) //Traders like it when you trade with them + + return M + +/datum/trader/proc/how_much_do_you_want(var/num) + var/atom/movable/M = trading_items[num] + . = get_response("how_much", "Hmm.... how about VALUE credits?") + . = replacetext(.,"VALUE",get_item_value(num)) + . = replacetext(.,"ITEM", initial(M.name)) + +/datum/trader/proc/what_do_you_want() + if(!(trade_flags & TRADER_GOODS)) + return get_response(TRADER_NO_GOODS, "I don't deal in goods.") + + . = get_response("what_want", "Hm, I want") + var/list/want_english = list() + for(var/type in wanted_items) + var/atom/a = type + want_english += initial(a.name) + . += " [english_list(want_english)]" + +/datum/trader/proc/sell_items(var/list/offers) + if(!(trade_flags & TRADER_GOODS)) + return TRADER_NO_GOODS + if(!offers || !offers.len) + return TRADER_NOT_ENOUGH + + var/mult = 1 + . = 0 + for(var/offer in offers) + if((trade_flags & TRADER_WANTED_ONLY) && is_type_in_list(offer,wanted_items)) + mult = want_multiplier + else if((trade_flags & TRADER_WANTED_ALL) && is_type_in_list(offer,possible_wanted_items)) + mult = 1 + else + return TRADER_FOUND_UNWANTED + . += get_value(offer) * mult + + playsound(get_turf(offers[1]), 'sound/effects/teleport.ogg', 50, 1) + for(var/offer in offers) + qdel(offer) + +/datum/trader/proc/bribe_to_stay_longer(var/amt) + return get_response("bribe_refusal", "How about... no?") \ No newline at end of file diff --git a/code/datums/trading/unique.dm b/code/datums/trading/unique.dm new file mode 100644 index 00000000..1654d9a3 --- /dev/null +++ b/code/datums/trading/unique.dm @@ -0,0 +1,132 @@ +/datum/trader/ship/unique + trade_flags = TRADER_WANTED_ONLY|TRADER_GOODS + want_multiplier = 5 + typical_duration = 10 + +/datum/trader/ship/unique/New() + ..() + wanted_items = list() + for(var/type in possible_wanted_items) + var/status = possible_wanted_items[type] + if(status & TRADER_THIS_TYPE) + wanted_items += type + if(status & TRADER_SUBTYPES_ONLY) + wanted_items += subtypesof(type) + if(status & TRADER_BLACKLIST) + wanted_items -= type + if(status & TRADER_BLACKLIST_SUB) + wanted_items -= subtypesof(type) + +/datum/trader/ship/unique/tick() + if(prob(-disposition) || refuse_comms) + duration_of_stay-- + return --duration_of_stay > 0 + +/datum/trader/ship/unique/what_do_you_want() + return get_response("what_want", "I don't want anything!") + +/datum/trader/ship/unique/severance + name = "Unknown" + origin = "SGS Severance" + + possible_wanted_items = list( + /obj/item/weapon/reagent_containers/food/snacks/human = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/reagent_containers/food/snacks/meat/human = TRADER_THIS_TYPE, + /mob/living/carbon/human = TRADER_ALL + ) + + possible_trading_items = list(/obj/mecha/combat = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/gun/projectile/automatic = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/gun/projectile/automatic/mini_uzi/usi = TRADER_BLACKLIST, + /obj/item/weapon/gun/projectile/automatic/l6_saw/mag = TRADER_BLACKLIST + ) + + blacklisted_trade_items = null + + speech = list("hail_generic" = "H-hello. Can you hear me? G-good... I have... specific needs... I have a lot to t-trade with you in return of course.", + "hail_deny" = "--CONNECTION SEVERED--", + + "trade_complete" = "Hahahahahahaha! Thankyouthankyouthankyou!", + "trade_no_money" = "I d-don't NEED cash.", + "trade_not_enough" = "N-no, no no no. M-more than that... more...", + "trade_found_unwanted" = "I d-don't think you GET what I want, fr- from your offer.", + "how_much" = "Meat. I want meat. The kind they don't serve in the- the mess hall.", + "what_want" = "Long p-pork. Yes... that's what I want...", + + "compliment_deny" = "Your lies won't ch-change what I did.", + "compliment_accept" = "Yes... I suppose you're right.", + "insult_good" = "I... probably deserve that.", + "insult_bad" = "Maybe you should c-come here and say that. You'd be worth s-something then.", + ) + mob_transfer_message = "You are transported to ORIGIN, and with a sickening thud, you fall unconscious, never to wake again." + + +/datum/trader/ship/unique/rock + name = "Bobo" + origin = "Floating rock" + + possible_wanted_items = list(/obj/item/weapon/ore = TRADER_ALL) + possible_trading_items = list(/obj/machinery/power/supermatter = TRADER_ALL, + /obj/item/weapon/aiModule = TRADER_SUBTYPES_ONLY) + want_multiplier = 5000 + + speech = list("hail_generic" = "Blub am MERCHANT. Blub hunger for things. Boo bring them to blub, yes?", + "hail_deny" = "Blub does not want to speak to boo.", + + "trade_complete" = "Blub likes to trade!", + "trade_no_money" = "Boo try to give Blub paper. Blub does not want paper.", + "trade_not_enough" = "Blub hungry for bore than that.", + "trade_found_unwanted" = "Blub only wants bocks. Give bocks.", + "trade_refuse" = "No, Blub will not do that. Blub wants bocks, yes? Give bocks.", + "how_much" = "Blub wants bocks. Boo give bocks. Blub gives stuff blub found.", + "what_want" = "Blub wants bocks. Big bocks, small bocks. Shiny bocks!", + + "compliment_deny" = "Blub is just MERCHANT. What do boo mean?", + "compliment_accept" = "Boo are a bood berson!", + "insult_good" = "Blub do not understand. Blub thought we were briends.", + "insult_bad" = "Blub feels bad now.", + ) + +//probably could stick soem Howl references in here but like, eh. Haven't seen it in years. +/datum/trader/ship/unique/wizard + name = "Sorcerer" + origin = "A moving castle" + possible_origins = list("An indistinct location", "Unknown location", "The Diamond Sphere", "Beyond the Veil", "Deadverse") + name_language = TRADER_DEFAULT_NAME + + possible_wanted_items = list(/mob/living/simple_animal/construct = TRADER_SUBTYPES_ONLY, + /obj/item/weapon/melee/cultblade = TRADER_THIS_TYPE, + /obj/item/clothing/head/culthood = TRADER_ALL, + /obj/item/clothing/suit/space/cult = TRADER_ALL, + /obj/item/clothing/suit/cultrobes = TRADER_ALL, + /obj/item/clothing/head/helmet/space/cult = TRADER_ALL, + /obj/structure/cult = TRADER_SUBTYPES_ONLY, + /obj/structure/constructshell = TRADER_ALL, + /mob/living/simple_animal/familiar = TRADER_SUBTYPES_ONLY, + /mob/living/simple_animal/familiar/pet = TRADER_BLACKLIST, + /mob/living/simple_animal/hostile/mimic = TRADER_ALL) + + possible_trading_items = list(/obj/item/clothing/gloves/wizard = TRADER_THIS_TYPE, + /obj/item/clothing/head/helmet/space/void/wizard = TRADER_THIS_TYPE, + /obj/item/clothing/head/wizard = TRADER_ALL, + /obj/item/clothing/suit/space/void/wizard = TRADER_THIS_TYPE, + /obj/item/toy/figure/wizard = TRADER_THIS_TYPE, + /obj/item/weapon/staff = TRADER_ALL, + ) //Probably see about getting some more wizard based shit + + speech = list("hail_generic" = "Hello! Are you here on pleasure or business?", + "hail_Golem" = "Interesting... how incredibly interesting... come! Let us do business!", + "hail_deny" = "I'm sorry, but I REALLY don't want to speak to you.", + + "trade_complete" = "Pleasure doing business with you!", + "trade_no_money" = "Cash? Ha! What's cash to a man like me?", + "trade_not_enough" = "Hm, well I do enjoy what you're offering, I prefer a fair trade.", + "trade_found_unwanted" = "What? I want oddities! Don't you understand?", + "how_much" = "I want dark things, brooding things... things that go bump in the night. Things that bleed wrong, live wrong, are wrong.", + "what_want" = "Have anything from a broodish cult?", + + "compliment_deny" = "Like I haven't heard that one before!", + "compliment_accept" = "Haha! Aren't you nice.", + "insult_good" = "Naughty naughty.", + "insult_bad" = "Now where do you get off talking to me like that?", + ) \ No newline at end of file diff --git a/code/datums/trading/vox.dm b/code/datums/trading/vox.dm new file mode 100644 index 00000000..300723bc --- /dev/null +++ b/code/datums/trading/vox.dm @@ -0,0 +1,91 @@ +/datum/trader/ship/vox + typical_duration = 15 + origin = "UNREGISTERED VESSEL" + name_language = "Vox-pidgin" + compliment_increase = 0 + trade_flags = TRADER_GOODS + var/hailed_vox = 0 //Whether we have been hailed by a vox. negatives mean pariah, positives mean regular. + blacklisted_trade_items = null + + speech = list("hail_generic0" = "SKREEE! We will trade good stuff, yes?", + "hail_generic1" = "SKREEEEE! You friend of Vox? You trade with, yes?", + "hail_silicon0" = "Hello metal thing! You trade metal for things?", + "hail_silicon1" = "YOU KNOW VOX? Yes is good, yes yes, MOB. Trade GOOD!", + "hail_Human0" = "Hello hueman! Kiikikikiki! MOB trade with us, yes? Good!", + "hail_Human1" = "Friend of Vox is friend of all Vox! MOB you trade now!", + "hail_Vox1" = "SKREEEE! May the Shoal make this trade good, MOB!", + "hail_deny0" = "Trade closed, GO AWAY!", + "hail_deny-1" = "We no trade with shit like you!", + "hail_deny1" = "Trade gone now. Goodbye.", + + "trade_complete0" = "Yes, kikikikikiki! You will not regret this trade!", + "trade_complete1" = "Yes... this is a good trade for the Shoal!", + "trade_no_money0" = "Money? Vox no need money. GOODS! Give it GOODS!", + "trade_no_money1" = "You know as well as it that money is no good.", + "trade_not_enough0" = "It wants MORE for that. Give it more.", + "trade_not_enough1" = "Ech, you insult it with such a trade? Respect it, make it equal.", + + "trade_refuse1" = "You know as well as it that is not a good trade.", + "how_much0" = "You give it something worth VALUE, yes?", + "how_much1" = "Hmm.... VALUE. Something like that.", + "what_want0" = "Vox wants", + "what_want1" = "Shoal wants", + + "compliment_deny0" = "No.", + "compliment_deny1" = "You know better than that!", + "compliment_accept0" = "Kikikikiki! Trade is better than talk, yes?", + "compliment_accept1" = "You butter it up? Should know better than that.", + "insult_good0" = "Bah! Why does it have to deal with you?", + "insult_good1" = "Where this come from? Is trade no good?", + "insult_bad0" = "All you meats are the same! Fuck off!", + "insult_bad1" = "If you say all this at home, you be dead!", + ) + + possible_wanted_items = list(/obj/item/weapon/ = TRADER_SUBTYPES_ONLY, + /obj/item/stack/material = TRADER_SUBTYPES_ONLY, + /obj/item/stack/material/cyborg = TRADER_BLACKLIST_ALL, + /obj/item/organ = TRADER_SUBTYPES_ONLY, + ) + + possible_trading_items = list(/obj/item/weapon/gun/projectile/dartgun/vox = TRADER_SUBTYPES_ONLY, + /obj/item/mecha_parts/mecha_equipment/tool/ = TRADER_SUBTYPES_ONLY, + /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/ = TRADER_SUBTYPES_ONLY, + /obj/item/trash = TRADER_SUBTYPES_ONLY, + /obj/item/remains = TRADER_ALL, + /obj/item/clothing/accessory = TRADER_ALL, + /obj/item/robot_parts = TRADER_SUBTYPES_ONLY, + /obj/item/robot_parts/robot_component = TRADER_BLACKLIST + ) + + mob_transfer_message = "You are transported to the ORIGIN. When the transportation dizziness wears off, you find you are surrounded by cackling Vox..." + + +/datum/trader/ship/vox/hail(var/mob/user) + var/specific + if(istype(user, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(H.species) + switch(H.species.name) + if(SPECIES_VOX) + disposition = 1000 + hailed_vox = 1 + specific = H.species.name + else if(istype(user, /mob/living/silicon)) + specific = "silicon" + if(!speech["hail_[specific][hailed_vox]"]) + specific = "generic" + . = get_response("hail_[specific][hailed_vox]", "Greetings, MOB!") + . = replacetext(., "MOB", user.name) + +/datum/trader/ship/vox/can_hail() + if(hailed_vox >= 0) + return ..() + return 0 + +/datum/trader/ship/vox/get_response(var/text, var/generic) + return ..("[text][hailed_vox]", generic) + +/datum/trader/ship/vox/get_item_value(var/trading_num) + . = ..() + if(!hailed_vox) + . *= 2 \ No newline at end of file diff --git a/code/datums/trading/weaponry.dm b/code/datums/trading/weaponry.dm new file mode 100644 index 00000000..1bb7938f --- /dev/null +++ b/code/datums/trading/weaponry.dm @@ -0,0 +1,98 @@ +/datum/trader/ship/gunshop + name = "Gun Shop Employee" + name_language = TRADER_DEFAULT_NAME + origin = "Gun Shop" + possible_origins = list("Rooty Tootie's Point-n-Shooties", "Bang-Bang Shop", "Wild Wild West Shop", "Keleshnikov", "Hunting Depot", "Big Game Hunters") + speech = list("hail_generic" = "Hello, hello! I hope you have your permit. Oh, who are we kidding, you're welcome anyway!", + "hail_deny" = "Store policy dictates that you can fuck off.", + + "trade_complete" = "Thanks for buying your guns from ORIGIN!", + "trade_blacklist" = "We may deal in guns, but that doesn't mean we'll trade for illegal goods...", + "trade_no_goods" = "Cash for guns, thats the deal.", + "trade_not_enough" = "Guns are expensive! Give us more if you REALLY want it.", + "how_much" = "Well, I'd love to give this little beauty to you for VALUE.", + + "compliment_deny" = "If we were in the same room right now, I'd probably punch you.", + "compliment_accept" = "Ha! Good one!", + "insult_good" = "I expected better from you. I suppose in that, I was wrong.", + "insult_bad" = "If I had my gun I'd shoot you!" + ) + + possible_trading_items = list(/obj/item/weapon/gun/projectile/pistol = TRADER_ALL, + /obj/item/weapon/gun/projectile/colt = TRADER_ALL, + /obj/item/weapon/gun/projectile/magnum_pistol= TRADER_ALL, + /obj/item/weapon/gun/projectile/sec = TRADER_ALL, + /obj/item/weapon/gun/projectile/sec/MK = TRADER_BLACKLIST, + /obj/item/weapon/gun/projectile/shotgun/pump= TRADER_SUBTYPES_ONLY, + /obj/item/ammo_magazine = TRADER_SUBTYPES_ONLY, + /obj/item/ammo_magazine/a10mm/empty = TRADER_BLACKLIST, + /obj/item/ammo_magazine/a762/empty = TRADER_BLACKLIST, + /obj/item/ammo_magazine/a75/empty = TRADER_BLACKLIST, + /obj/item/ammo_magazine/c45m/empty = TRADER_BLACKLIST, + /obj/item/ammo_magazine/mc9mm/empty = TRADER_BLACKLIST, + /obj/item/ammo_magazine/box/c9mm/empty = TRADER_BLACKLIST, + /obj/item/ammo_magazine/box/c45/empty = TRADER_BLACKLIST, + /obj/item/ammo_magazine/box/a556/empty = TRADER_BLACKLIST, + /obj/item/ammo_magazine/c45uzi/empty = TRADER_BLACKLIST, + /obj/item/ammo_magazine/mc9mmt/empty = TRADER_BLACKLIST, + /obj/item/ammo_magazine/a50/empty = TRADER_BLACKLIST, + /obj/item/clothing/accessory/holster = TRADER_ALL) + +/datum/trader/ship/egunshop + name = "Energy Gun Shop Employee" + name_language = TRADER_DEFAULT_NAME + origin = "EGun Shop" + possible_origins = list("The Emperor's Lasgun Shop", "Future Guns", "Solar Army", "Kiefer's Dependable Electric Arms", "Olympus Kingsport") + speech = list("hail_generic" = "Welcome to the future of warfare! ORIGIN, your one-stop shop for energy weaponry!", + "hail_deny" = "I'm sorry, your communication channel has been blacklisted.", + + "trade_complete" = "Thank you, your purchase has been logged and you have automatically liked our Spacebook page.", + "trade_blacklist" = "I'm sorry, is that a joke?", + "trade_no_goods" = "We deal in cash.", + "trade_not_enough" = "State of the art weaponry costs more than that.", + "how_much" = "All our quality weapons are priceless, but I'd give that to you for VALUE.", + + "compliment_deny" = "If I was dumber I probably would have believed you.", + "compliment_accept" = "Yes, I am very smart.", + "insult_good" = "Energy weapons are TWICE the gun kinetic guns are!", + "insult_bad" = "That's... very mean. I won't think twice about blacklisting your channel, so stop." + ) + + possible_trading_items = list(/obj/item/weapon/gun/energy/taser = TRADER_THIS_TYPE, + /obj/item/weapon/gun/energy/stunrevolver = TRADER_THIS_TYPE, + /obj/item/weapon/gun/energy/laser = TRADER_THIS_TYPE, + /obj/item/weapon/gun/energy/gun = TRADER_THIS_TYPE, + /obj/item/weapon/cell = TRADER_THIS_TYPE, + /obj/item/weapon/cell/crap = TRADER_THIS_TYPE, + /obj/item/weapon/cell/high = TRADER_THIS_TYPE, + /obj/item/weapon/cell/super = TRADER_THIS_TYPE, + /obj/item/weapon/cell/hyper = TRADER_THIS_TYPE, + /obj/item/clothing/accessory/holster = TRADER_ALL) + +/datum/trader/dogan + name = "Dogan" + origin = "Dogan's Gun Beacon" + speech = list("hail_generic" = "Hello! This is an automatic recording of me, Mr. Dogan! I hope you like the... GUNS... I've got in store for you today.", + "hail_deny" = "I formally welcome you to... NOT... visit our store!", + + "trade_complete" = "Thank you for... PURCHASING... that quality... ITEM... from me!", + "trade_blacklist" = "Thank you for... that quality... ILLEGAL OFFER THAT I WILL REFUSE... from me!", + "trade_no_goods" = "Thank you for... that quality... OFFER THAT ISN'T MONEY THAT I WILL REFUSE... from me!", + "trade_not_enough" = "Thank you for... that quality... OFFER THAT IS NOT ENOUGH... from me!", + "how_much" = "Thank you for... ASKING ME ABOUT MY PRICES... that quality... ITEM is worth VALUE... from me!", + + "compliment_deny" = "Thank you for... that quality... COMPLIMENT... from me!", + "compliment_accept" = "Thank you for... that quality... COMPLIMENT... from me!", + "insult_good" = "Thank you for... that quality... INSULT... from me!", + "insult_bad" = "Thank you for... that quality... INSULT... from me!" + ) + compliment_increase = 0 + insult_drop = 0 + + possible_trading_items = list(/obj/item/weapon/gun/projectile/pirate = TRADER_THIS_TYPE, + /obj/item/weapon/gun/projectile/sec/MK = TRADER_THIS_TYPE, + /obj/item/weapon/gun/projectile/silenced/cheap = TRADER_THIS_TYPE, + /obj/item/weapon/gun/projectile/heavysniper/ant = TRADER_THIS_TYPE, + /obj/item/weapon/gun/energy/laser/dogan = TRADER_THIS_TYPE, + /obj/item/weapon/gun/projectile/automatic/mini_uzi/usi = TRADER_THIS_TYPE, + /obj/item/clothing/accessory/holster = TRADER_ALL) \ No newline at end of file diff --git a/code/datums/underwear/bottom.dm b/code/datums/underwear/bottom.dm new file mode 100644 index 00000000..0b6178ae --- /dev/null +++ b/code/datums/underwear/bottom.dm @@ -0,0 +1,95 @@ +/datum/category_item/underwear/bottom + underwear_gender = PLURAL + underwear_name = "underwear" + underwear_type = /obj/item/underwear/bottom + +/datum/category_item/underwear/bottom/none + name = "None" + always_last = TRUE + underwear_type = null + +/datum/category_item/underwear/bottom/briefs + name = "Briefs" + underwear_name = "briefs" + icon_state = "briefs" + has_color = TRUE + +/datum/category_item/underwear/bottom/briefs/is_default(var/gender) + return gender != FEMALE + +/datum/category_item/underwear/bottom/panties_noback + name = "Panties, noback" + underwear_name = "panties" + icon_state = "panties_noback" + has_color = TRUE + +/datum/category_item/underwear/bottom/boxers_loveheart + name = "Boxers, Loveheart" + underwear_name = "boxers" + icon_state = "boxers_loveheart" + +/datum/category_item/underwear/bottom/boxers + name = "Boxers" + underwear_name = "boxers" + icon_state = "boxers" + has_color = TRUE + +/datum/category_item/underwear/bottom/boxers_green_and_blue + name = "Boxers, green & blue striped" + underwear_name = "boxers" + icon_state = "boxers_green_and_blue" + +/datum/category_item/underwear/bottom/panties + name = "Panties" + underwear_name = "panties" + icon_state = "panties" + has_color = TRUE + +/datum/category_item/underwear/bottom/panties/is_default(var/gender) + return gender == FEMALE + +/datum/category_item/underwear/bottom/lacy_thong + name = "Lacy thong" + underwear_name = "thong" + icon_state = "lacy_thong" + +/datum/category_item/underwear/bottom/lacy_thong_alt + name = "Lacy thong, alt" + underwear_name = "thong" + icon_state = "lacy_thong_alt" + has_color = TRUE + +/datum/category_item/underwear/bottom/panties_alt + name = "Panties, alt" + underwear_name = "panties" + icon_state = "panties_alt" + has_color = TRUE + +/datum/category_item/underwear/bottom/compression_shorts + name = "Compression shorts" + icon_state = "compression_shorts" + has_color = TRUE + +/datum/category_item/underwear/bottom/thong + name = "Thong" + underwear_name = "thong" + icon_state = "thong" + has_color = TRUE + +/datum/category_item/underwear/bottom/expedition_pt_shorts + name = "PT shorts, Expeditionary Corps" + icon_state = "expedition_shorts" + +/datum/category_item/underwear/bottom/fleet_pt_shorts + name = "PT shorts, Fleet" + icon_state = "fleet_shorts" + +/datum/category_item/underwear/bottom/marine_pt_shorts + name = "PT shorts, Marine Corps" + icon_state = "marine_shorts" + +/datum/category_item/underwear/bottom/longjon + name = "Long John Bottoms" + underwear_name = "long johns" + icon_state = "ljonb" + has_color = TRUE diff --git a/code/datums/underwear/socks.dm b/code/datums/underwear/socks.dm new file mode 100644 index 00000000..4b268952 --- /dev/null +++ b/code/datums/underwear/socks.dm @@ -0,0 +1,75 @@ +/datum/category_item/underwear/socks + underwear_name = "socks" + underwear_gender = PLURAL + underwear_type = /obj/item/underwear/socks + +/datum/category_item/underwear/socks/none + always_last = TRUE + name = "None" + underwear_type = null + +/datum/category_item/underwear/socks/normal + name = "Normal" + icon_state = "socks_norm" + has_color = TRUE + +/datum/category_item/underwear/socks/short + name = "Short" + icon_state = "socks_short" + has_color = TRUE + +/datum/category_item/underwear/socks/thigh + name = "Thigh" + underwear_name = "thigh highs" + icon_state = "socks_thigh" + has_color = TRUE + +/datum/category_item/underwear/socks/knee + name = "Knee" + underwear_name = "knee highs" + icon_state = "socks_knee" + has_color = TRUE + +/datum/category_item/underwear/socks/striped_knee + name = "Knee, striped" + underwear_name = "knee highs" + icon_state = "striped_knee" + has_color = TRUE + +/datum/category_item/underwear/socks/striped_thigh + name = "Thigh, striped" + underwear_name = "thigh highs" + icon_state = "striped_thigh" + has_color = TRUE + +/datum/category_item/underwear/socks/pantyhose + name = "Pantyhose" + underwear_name = "pantyhose" + icon_state = "pantyhose" + +/datum/category_item/underwear/socks/thin_thigh + name = "Thigh, thin" + underwear_name = "thigh highs" + icon_state = "thin_thigh" + has_color = TRUE + +/datum/category_item/underwear/socks/thin_knee + name = "Knee, thin" + underwear_name = "knee highs" + icon_state = "thin_knee" + has_color = TRUE + +/datum/category_item/underwear/socks/rainbow_thigh + name = "Thigh, rainbow" + underwear_name = "thigh highs" + icon_state = "rainbow_thigh" + +/datum/category_item/underwear/socks/rainbow_knee + name = "Knee, rainbow" + underwear_name = "knee highs" + icon_state = "rainbow_knee" + +/datum/category_item/underwear/socks/fishnet + name = "Fishnet" + underwear_name = "fishnet" + icon_state = "fishnet" diff --git a/code/datums/underwear/top.dm b/code/datums/underwear/top.dm new file mode 100644 index 00000000..6b559214 --- /dev/null +++ b/code/datums/underwear/top.dm @@ -0,0 +1,49 @@ +/datum/category_item/underwear/top + underwear_name = "bra" + underwear_type = /obj/item/underwear/top + +/datum/category_item/underwear/top/none + name = "None" + always_last = TRUE + underwear_type = null + +/datum/category_item/underwear/top/none/is_default(var/gender) + return gender != FEMALE + +/datum/category_item/underwear/top/bra + is_default = TRUE + name = "Bra" + icon_state = "bra" + has_color = TRUE + +/datum/category_item/underwear/top/bra/is_default(var/gender) + return gender == FEMALE + +/datum/category_item/underwear/top/sports_bra + name = "Sports bra" + icon_state = "sports_bra" + has_color = TRUE + +/datum/category_item/underwear/top/sports_bra_alt + name = "Sports bra, alt" + icon_state = "sports_bra_alt" + has_color = TRUE + +/datum/category_item/underwear/top/lacy_bra + name = "Lacy bra" + icon_state = "lacy_bra" + +/datum/category_item/underwear/top/lacy_bra_alt + name = "Lacy bra, alt" + icon_state = "lacy_bra_alt" + +/datum/category_item/underwear/top/halterneck_bra + name = "Halterneck bra" + icon_state = "halterneck_bra" + has_color = TRUE + +/datum/category_item/underwear/top/tube_top + name = "Tube Top" + underwear_name = "tube top" + icon_state = "tubetop" + has_color = TRUE diff --git a/code/datums/underwear/undershirt.dm b/code/datums/underwear/undershirt.dm new file mode 100644 index 00000000..46c4d198 --- /dev/null +++ b/code/datums/underwear/undershirt.dm @@ -0,0 +1,188 @@ +/datum/category_item/underwear/undershirt + underwear_name = "undershirt" + underwear_type = /obj/item/underwear/undershirt + +/datum/category_item/underwear/undershirt/none + is_default = TRUE + name = "None" + always_last = TRUE + underwear_type = null + +/datum/category_item/underwear/undershirt/shirt + name = "Shirt" + icon_state = "undershirt" + has_color = TRUE + +/datum/category_item/underwear/undershirt/shirt_long + name = "Long Shirt" + icon_state = "undershirt_long" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tank_top + name = "Tank top" + underwear_name = "tank top" + icon_state = "tanktop" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tank_top_alt + name = "Tank top, alt" + underwear_name = "tank top" + icon_state = "tanktop_alt" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tank_top_fleet + name = "Tank top, Fleet" + underwear_name = "tank top" + icon_state = "tank_fleet_s" + +/datum/category_item/underwear/undershirt/tank_top_fire + name = "Tank top, fire" + underwear_name = "tank top" + icon_state = "tank_fire_s" + +/datum/category_item/underwear/undershirt/tank_top_rainbow + name = "Tank top, rainbow" + underwear_name = "tank top" + icon_state = "tank_rainbow_s" + +/datum/category_item/underwear/undershirt/tank_top_stripes + name = "Tank top, striped" + underwear_name = "tank top" + icon_state = "tank_stripes_s" + +/datum/category_item/underwear/undershirt/tank_top_sun + name = "Tank top, sun" + underwear_name = "tank top" + icon_state = "tank_sun_s" + +/datum/category_item/underwear/undershirt/shirt_button + name = "Shirt, button down" + icon_state = "shirt_long_s" + has_color = TRUE + +/datum/category_item/underwear/undershirt/shirt_expedition + name = "Shirt, Expeditionary Corps" + icon_state = "expedition_s" + +/datum/category_item/underwear/undershirt/shirt_heart + name = "Shirt, heart" + icon_state = "lover_s" + +/datum/category_item/underwear/undershirt/shirt_love_nt + name = "Shirt, I<3NT" + icon_state = "lover_s" + +/datum/category_item/underwear/undershirt/shirt_marine + name = "Shirt, Marine Corps" + icon_state = "marine_s" + +/datum/category_item/underwear/undershirt/shirt_nt + name = "Shirt, NT" + icon_state = "shirt_nano_s" + +/datum/category_item/underwear/undershirt/shortsleeve_shirt + name = "Shortsleeve shirt" + icon_state = "shortsleeve" + has_color = TRUE + +/datum/category_item/underwear/undershirt/polo_shirt + name = "Polo shirt" + icon_state = "polo" + has_color = TRUE + +/datum/category_item/underwear/undershirt/sport_shirt_green + name = "Sport shirt, green" + icon_state = "greenshirtsport_s" + +/datum/category_item/underwear/undershirt/sport_shirt_red + name = "Sport shirt, red" + icon_state = "redshirtsport_s" + +/datum/category_item/underwear/undershirt/sport_shirt_blue + name = "Sport shirt, blue" + icon_state = "blueshirtsport_s" + +/datum/category_item/underwear/undershirt/shirt_tiedye + name = "Shirt, tiedye" + icon_state = "shirt_tiedye_s" + +/datum/category_item/underwear/undershirt/shirt_blue_striped + name = "Shirt, blue stripes" + icon_state = "shirt_stripes_s" + +/datum/category_item/underwear/undershirt/longjon + name = "Long John Shirt" + underwear_name = "long johns" + icon_state = "ljont" + has_color = TRUE + +/datum/category_item/underwear/undershirt/longstripe_black + name = "Longsleeve Striped Shirt, Black" + underwear_name = "long johns" + icon_state = "longstripe" + +/datum/category_item/underwear/undershirt/longstripe_blue + name = "Longsleeve Striped Shirt, Blue" + icon_state = "longstripe_blue" + +/datum/category_item/underwear/undershirt/blouse_female + name = "Women's Dress Shirt" + icon_state = "blouse_female_s" + +/datum/category_item/underwear/undershirt/undershirt_female + name = "Undershirt, Female" + icon_state = "undershirt_female" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tanktop_female + name = "Tanktop, Female" + icon_state = "tanktop_female" + has_color = TRUE + +/datum/category_item/underwear/undershirt/shortsleeve_female + name = "Shortsleeve Shirt, Female" + icon_state = "shortsleeve_female" + has_color = TRUE + +/datum/category_item/underwear/undershirt/shirt_long_female + name = "Button Down Shirt, Female" + icon_state = "shirt_long_female_s" + has_color = TRUE + +/datum/category_item/underwear/undershirt/undershirt_long_female + name = "Longsleeve Shirt, Female" + icon_state = "undershirt_long_female" + has_color = TRUE + +/datum/category_item/underwear/undershirt/turtleneck + name = "Turtleneck Sweater" + icon_state = "turtleneck_s" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tanktop_alt_female + name = "Tanktop alt, Female" + underwear_name = "tanktop" + icon_state = "tanktop_alt_female" + has_color = TRUE + +/datum/category_item/underwear/undershirt/polo_female + name = "Polo, Female" + icon_state = "polo_female" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tank_fleet_female + name = "Tank top, Fleet, Female" + underwear_name = "tanktop" + icon_state = "tank_fleet_female_s" + +/datum/category_item/underwear/undershirt/marine_female + name = "Shirt, Marine Corps, Female" + icon_state = "marine_female_s" + +/datum/category_item/underwear/undershirt/expedition_female + name = "Shirt, Expeditionary Corps, Female" + icon_state = "expedition_female_s" + +/datum/category_item/underwear/undershirt/polo_nt + name = "Polo, NanoTrasen" + icon_state = "ntpolo" diff --git a/code/datums/underwear/underwear.dm b/code/datums/underwear/underwear.dm new file mode 100644 index 00000000..8f55d6cd --- /dev/null +++ b/code/datums/underwear/underwear.dm @@ -0,0 +1,74 @@ +/**************************** +* Category Collection Setup * +****************************/ +/datum/category_collection/underwear + category_group_type = /datum/category_group/underwear + +/************* +* Categories * +*************/ +/datum/category_group/underwear + var/sort_order // Lower sort order is applied as icons first + +datum/category_group/underwear/dd_SortValue() + return sort_order + +/datum/category_group/underwear/top + name = "Underwear, top" + sort_order = 1 + category_item_type = /datum/category_item/underwear/top + +/datum/category_group/underwear/bottom + name = "Underwear, bottom" + sort_order = 2 + category_item_type = /datum/category_item/underwear/bottom + +/datum/category_group/underwear/socks + name = "Socks" + sort_order = 3 + category_item_type = /datum/category_item/underwear/socks + +/datum/category_group/underwear/undershirt + name = "Undershirt" + sort_order = 4 // Undershirts currently have the highest sort order because they may cover both underwear and socks. + category_item_type = /datum/category_item/underwear/undershirt + +/******************* +* Category entries * +*******************/ +/datum/category_item/underwear + var/always_last = FALSE // Should this entry be sorte last? + var/is_default = FALSE // Should this entry be considered the default for its type? + var/icon = 'icons/mob/human.dmi' // Which icon to get the underwear from. + var/icon_state // And the particular item state. + var/list/tweaks = list() // Underwear customizations. + var/has_color = FALSE + + var/underwear_name // The name of the resulting underwear + var/underwear_gender = NEUTER // Singular or plural form? + var/underwear_type // The kind of underwear item this datum will create. + +/datum/category_item/underwear/New() + ..() + +/datum/category_item/underwear/dd_SortValue() + if(always_last) + return "~"+name + return name + +/datum/category_item/underwear/proc/is_default(var/gender) + return is_default + +/datum/category_item/underwear/proc/create_underwear(var/list/metadata) + return + /* + if(!underwear_type) + return + + var/obj/item/underwear/UW = new underwear_type() + UW.SetName(underwear_name) + UW.gender = underwear_gender + UW.icon = icon + UW.icon_state = icon_state + return UW + */ \ No newline at end of file diff --git a/code/datums/uplink/ammunition.dm b/code/datums/uplink/ammunition.dm new file mode 100644 index 00000000..945dada9 --- /dev/null +++ b/code/datums/uplink/ammunition.dm @@ -0,0 +1,77 @@ +/************* +* Ammunition * +*************/ +/datum/uplink_item/item/ammo + item_cost = 4 + category = /datum/uplink_category/ammunition + +/datum/uplink_item/item/ammo/c45m + name = ".45" + path = /obj/item/ammo_magazine/c45m + +/datum/uplink_item/item/ammo/mc9mm + name = "9mm" + path = /obj/item/ammo_magazine/mc9mm + +/datum/uplink_item/item/ammo/a10mm + name = "10mm" + path = /obj/item/ammo_magazine/a10mm + +/datum/uplink_item/item/ammo/darts + name = "Darts" + path = /obj/item/ammo_magazine/chemdart + +/datum/uplink_item/item/ammo/a357 + name = ".357" + item_cost = 8 + path = /obj/item/ammo_magazine/a357 + +/datum/uplink_item/item/ammo/a556 + name = "5.56mm" + item_cost = 8 + path = /obj/item/ammo_magazine/c556 + +/datum/uplink_item/item/ammo/sniperammo + name = "14.5mm" + item_cost = 8 + path = /obj/item/weapon/storage/box/sniperammo + +/datum/uplink_item/item/ammo/sniperammo/apds + name = "14.5mm APDS" + item_cost = 12 + path = /obj/item/weapon/storage/box/sniperammo/apds + +/datum/uplink_item/item/ammo/shotgun_shells + name = "Shotgun Shells box" + item_cost = 8 + path = /obj/item/weapon/storage/box/shotgunshells + +/datum/uplink_item/item/ammo/shotgun_slugs + name = "Shotgun Slugs box" + item_cost = 8 + path = /obj/item/weapon/storage/box/shotgunammo + +/datum/uplink_item/item/ammo/c45uzi + name = ".45 SMG Magazine" + item_cost = 8 + path = /obj/item/ammo_magazine/c45uzi + +/datum/uplink_item/item/ammo/a50 + name = ".50 AE magazine" + item_cost = 8 + path = /obj/item/ammo_magazine/a50 + +/datum/uplink_item/item/ammo/c50 + name = ".50 AE speedloader" + item_cost = 8 + path = /obj/item/ammo_magazine/c50 + +/datum/uplink_item/item/ammo/c38 + name = ".38 speedloader" + item_cost = 8 + path = /obj/item/ammo_magazine/c38 + +/datum/uplink_item/item/ammo/flechette + name = "Flechette Magazine" + item_cost = 8 + path = /obj/item/weapon/magnetic_ammo \ No newline at end of file diff --git a/code/datums/uplink/badassery.dm b/code/datums/uplink/badassery.dm new file mode 100644 index 00000000..6556d2c9 --- /dev/null +++ b/code/datums/uplink/badassery.dm @@ -0,0 +1,91 @@ +/************ +* Badassery * +************/ +/datum/uplink_item/item/badassery + category = /datum/uplink_category/badassery + +/datum/uplink_item/item/badassery/balloon + name = "For showing that You Are The BOSS (Useless Balloon)" + item_cost = DEFAULT_TELECRYSTAL_AMOUNT + path = /obj/item/toy/balloon + +/datum/uplink_item/item/badassery/balloon/NT + name = "For showing that you love NT SOO much (Useless Balloon)" + path = /obj/item/toy/balloon/nanotrasen + +/datum/uplink_item/item/badassery/balloon/random + name = "For showing 'Whatevah~' (Useless Balloon)" + desc = "Randomly selects a ballon for you!" + path = /obj/item/toy/balloon + +/datum/uplink_item/item/badassery/balloon/random/get_goods(var/obj/item/device/uplink/U, var/loc) + var/balloon_type = pick(typesof(path)) + var/obj/item/I = new balloon_type(loc) + return I + +/************** +* Random Item * +**************/ +/datum/uplink_item/item/badassery/random_one + name = "Random Item" + desc = "Buys you a random item for at least 1TC. Careful: No upper price cap!" + item_cost = 1 + +/datum/uplink_item/item/badassery/random_one/buy(var/obj/item/device/uplink/U, var/mob/user) + var/datum/uplink_random_selection/uplink_selection = get_uplink_random_selection_by_type(/datum/uplink_random_selection/default) + var/datum/uplink_item/item = uplink_selection.get_random_item(U.uses, U) + return item && item.buy(U, user) + +/datum/uplink_item/item/badassery/random_one/can_buy(obj/item/device/uplink/U) + return U.uses + +/datum/uplink_item/item/badassery/random_many + name = "Random Items" + desc = "Buys you as many random items as you can afford. Convenient packaging NOT included!" + +/datum/uplink_item/item/badassery/random_many/cost(var/telecrystals, obj/item/device/uplink/U) + return max(1, telecrystals) + +/datum/uplink_item/item/badassery/random_many/get_goods(var/obj/item/device/uplink/U, var/loc) + var/list/bought_items = list() + for(var/datum/uplink_item/UI in get_random_uplink_items(U, U.uses, loc)) + UI.purchase_log(U) + var/obj/item/I = UI.get_goods(U, loc) + if(istype(I)) + bought_items += I + + return bought_items + +/datum/uplink_item/item/badassery/random_many/purchase_log(obj/item/device/uplink/U) + feedback_add_details("traitor_uplink_items_bought", "[src]") + log_and_message_admins("used \the [U.loc] to buy \a [src]") + +/**************** +* Surplus Crate * +****************/ +/datum/uplink_item/item/badassery/surplus + name = "\improper Surplus Crate" + item_cost = DEFAULT_TELECRYSTAL_AMOUNT * 4 + var/item_worth = DEFAULT_TELECRYSTAL_AMOUNT * 6 + var/icon + +/datum/uplink_item/item/badassery/surplus/New() + ..() + antag_roles = list(MODE_MERCENARY) + desc = "A crate containing [item_worth] telecrystal\s worth of surplus leftovers." + +/datum/uplink_item/item/badassery/surplus/get_goods(var/obj/item/device/uplink/U, var/loc) + var/obj/structure/largecrate/C = new(loc) + var/random_items = get_random_uplink_items(U, item_worth, C) + for(var/datum/uplink_item/I in random_items) + I.purchase_log(U) + I.get_goods(U, C) + + return C + +/datum/uplink_item/item/badassery/surplus/log_icon() + if(!icon) + var/obj/structure/largecrate/C = /obj/structure/largecrate + icon = image(initial(C.icon), initial(C.icon_state)) + + return "\icon[icon]" diff --git a/code/datums/uplink/devices and tools.dm b/code/datums/uplink/devices and tools.dm new file mode 100644 index 00000000..00aa60bd --- /dev/null +++ b/code/datums/uplink/devices and tools.dm @@ -0,0 +1,128 @@ +/******************** +* Devices and Tools * +********************/ +/datum/uplink_item/item/tools + category = /datum/uplink_category/tools + +/* all the tools really? +/datum/uplink_item/item/tools/toolbox + name = "Fully Loaded Toolbox" + item_cost = 8 + path = /obj/item/weapon/storage/toolbox/syndicate +*/ + +/datum/uplink_item/item/tools/money + name = "Operations Funding" + item_cost = 8 + path = /obj/item/weapon/storage/secure/briefcase/money + desc = "A briefcase with 10,000 untraceable credits for funding your sneaky activities." + +/datum/uplink_item/item/tools/clerical + name = "Morphic Clerical Kit" + item_cost = 16 + path = /obj/item/weapon/storage/backpack/satchel/syndie_kit/clerical + +/datum/uplink_item/item/tools/plastique + name = "C-4 (Destroys walls)" + item_cost = 16 + path = /obj/item/weapon/plastique + +/* a bit big for a TC pruchase no? +/datum/uplink_item/item/tools/heavy_armor + name = "Heavy Armor Vest and Helmet" + item_cost = 16 + path = /obj/item/weapon/storage/backpack/satchel/syndie_kit/armor +*/ + +/datum/uplink_item/item/tools/encryptionkey_radio + name = "Encrypted Radio Channel Key" + item_cost = 1 + path = /obj/item/device/encryptionkey/red + +/datum/uplink_item/item/tools/shield_diffuser + name = "Handheld Shield Diffuser" + item_cost = 16 + path = /obj/item/weapon/shield_diffuser + +/datum/uplink_item/item/tools/suit_sensor_mobile + name = "Suit Sensor Jamming Device" + desc = "This device will affect suit sensor data using method and radius defined by the user." + item_cost = 20 + path = /obj/item/device/suit_sensor_jammer + +/datum/uplink_item/item/tools/encryptionkey_binary + name = "Binary Translator Key" + item_cost = 20 + path = /obj/item/device/encryptionkey/binary + +/datum/uplink_item/item/tools/emag + name = "Cryptographic Sequencer" + item_cost = 24 + path = /obj/item/weapon/card/emag + +/datum/uplink_item/item/tools/hacking_tool + name = "Door Hacking Tool" + item_cost = 24 + path = /obj/item/device/multitool/hacktool + desc = "Appears and functions as a standard multitool until the mode is toggled by applying a screwdriver appropriately. \ + When in hacking mode this device will grant full access to any standard airlock within 20 to 40 seconds. \ + This device will also be able to immediately access the last 6 to 8 hacked airlocks." + +/datum/uplink_item/item/tools/space_suit + name = "Space Suit" + item_cost = 28 + path = /obj/item/weapon/storage/backpack/satchel/syndie_kit/space + +/datum/uplink_item/item/tools/thermal + name = "Thermal Imaging Glasses" + item_cost = 24 + path = /obj/item/clothing/glasses/thermal/syndi + +/* Doesn't work +/datum/uplink_item/item/tools/flashdark + name = "Flashdark" + item_cost = 32 + path = /obj/item/device/flashlight/flashdark +*/ + +/datum/uplink_item/item/tools/powersink + name = "Powersink (DANGER!)" + item_cost = 40 + path = /obj/item/device/powersink + +/datum/uplink_item/item/tools/teleporter + name = "Teleporter Circuit Board" + item_cost = 40 + path = /obj/item/weapon/circuitboard/teleporter + +/datum/uplink_item/item/tools/teleporter/New() + ..() + antag_roles = list(MODE_MERCENARY) + +/* No AI +/datum/uplink_item/item/tools/ai_module + name = "Hacked AI Upload Module" + item_cost = 52 + path = /obj/item/weapon/aiModule/syndicate +*/ + +/* Don't really care much about this +/datum/uplink_item/item/tools/supply_beacon + name = "Hacked Supply Beacon (DANGER!)" + item_cost = 52 + path = /obj/item/supply_beacon +*/ + +/* +/datum/uplink_item/item/tools/camera_mask + name = "Camera MIU" + item_cost = 60 + antag_costs = list(MODE_MERCENARY = 30) + path = /obj/item/clothing/mask/ai +*/ + +/datum/uplink_item/item/tools/interceptor + name = "Radio Interceptor" + item_cost = 30 + path = /obj/item/device/radio/intercept + desc = "A radio that can intercept secure radio channels. Doesn't fit in pockets." diff --git a/code/datums/uplink/grenades.dm b/code/datums/uplink/grenades.dm new file mode 100644 index 00000000..20fcc4a8 --- /dev/null +++ b/code/datums/uplink/grenades.dm @@ -0,0 +1,87 @@ +/*********** +* Grenades * +************/ +/datum/uplink_item/item/grenades + category = /datum/uplink_category/grenades + +/datum/uplink_item/item/grenades/anti_photon + name = "1xPhoton Disruption Grenade" + item_cost = 4 + path = /obj/item/weapon/grenade/anti_photon + +/* no package deals +/datum/uplink_item/item/grenades/anti_photons + name = "5xPhoton Disruption Grenades" + item_cost = 16 + path = /obj/item/weapon/storage/box/anti_photons +*/ + +/datum/uplink_item/item/grenades/smoke + name = "1xSmoke Grenade" + item_cost = 4 + path = /obj/item/weapon/grenade/smokebomb + +/* no package deals +/datum/uplink_item/item/grenades/smokes + name = "5xSmoke Grenades" + item_cost = 16 + path = /obj/item/weapon/storage/box/smokes +*/ + +/datum/uplink_item/item/grenades/emp + name = "1xEMP Grenade" + item_cost = 8 + path = /obj/item/weapon/grenade/empgrenade + +/* no package deals +/datum/uplink_item/item/grenades/emps + name = "5xEMP Grenades" + item_cost = 24 + path = /obj/item/weapon/storage/box/emps +*/ + +/datum/uplink_item/item/grenades/frag_high_yield + name = "Fragmentation Bomb" + item_cost = 24 + antag_roles = list(MODE_MERCENARY) // yeah maybe regular traitors shouldn't be able to get these + path = /obj/item/weapon/grenade/frag/high_yield + +/datum/uplink_item/item/grenades/fragshell + name = "1xFragmentation Shell" + desc = "Weaker than standard fragmentation grenades, these devices can be fired from a grenade launcher." + item_cost = 10 + antag_roles = list(MODE_MERCENARY) + path = /obj/item/weapon/grenade/frag/shell + +/datum/uplink_item/item/grenades/fragshells + name = "5xFragmentation Shells" + desc = "Weaker than standard fragmentation grenades, these devices can be fired from a grenade launcher." + item_cost = 40 + antag_roles = list(MODE_MERCENARY) + path = /obj/item/weapon/storage/box/fragshells + +/datum/uplink_item/item/grenades/frag + name = "1xFragmentation Grenade" + item_cost = 10 + antag_roles = list(MODE_MERCENARY) + path = /obj/item/weapon/grenade/frag + +/datum/uplink_item/item/grenades/frags + name = "5xFragmentation Grenades" + item_cost = 40 + antag_roles = list(MODE_MERCENARY) + path = /obj/item/weapon/storage/box/frags + +/datum/uplink_item/item/grenades/supermatter + name = "1xSupermatter Grenade" + desc = "This grenade contains a small supermatter shard which will delaminate upon activation and pull in nearby objects, irradiate lifeforms, and eventually explode." + item_cost = 25 + antag_roles = list(MODE_MERCENARY = 15) + path = /obj/item/weapon/grenade/supermatter + +/datum/uplink_item/item/grenades/supermatters + name = "5xSupermatter Grenades" + desc = "These grenades contains a small supermatter shard which will delaminate upon activation and pull in nearby objects, irradiate lifeforms, and eventually explode." + item_cost = 60 + antag_roles = list(MODE_MERCENARY) + path = /obj/item/weapon/storage/box/supermatters diff --git a/code/datums/uplink/highly_visible_and_dangerous_weapons.dm b/code/datums/uplink/highly_visible_and_dangerous_weapons.dm new file mode 100644 index 00000000..25e31eea --- /dev/null +++ b/code/datums/uplink/highly_visible_and_dangerous_weapons.dm @@ -0,0 +1,134 @@ +/*************************************** +* Highly Visible and Dangerous Weapons * +***************************************/ +/datum/uplink_item/item/visible_weapons + category = /datum/uplink_category/visible_weapons + +/datum/uplink_item/item/visible_weapons/dartgun + name = "Dart Gun" + item_cost = 20 + path = /obj/item/weapon/gun/projectile/dartgun + +/* goodbye nobody will miss you +/datum/uplink_item/item/visible_weapons/crossbow + name = "Energy Crossbow" + item_cost = 24 + path = /obj/item/weapon/gun/energy/crossbow +*/ + +/* you have a cane sword, use it +/datum/uplink_item/item/visible_weapons/energy_sword + name = "Energy Sword" + item_cost = 32 + path = /obj/item/weapon/melee/energy/sword +*/ + +/datum/uplink_item/item/visible_weapons/g9mm + name = "Silenced Holdout Pistol" + item_cost = 32 + path = /obj/item/weapon/storage/box/syndie_kit/g9mm + + +/* no exoshit! +/datum/uplink_item/item/visible_weapons/riggedlaser + name = "Exosuit (APLU) Rigged Laser" + item_cost = 32 + path = /obj/item/mecha_parts/mecha_equipment/weapon/energy/riggedlaser +*/ + +/* just no. +/datum/uplink_item/item/visible_weapons/energy_gun + name = "Energy Gun" + item_cost = 32 + path = /obj/item/weapon/gun/energy/gun +*/ + +/datum/uplink_item/item/visible_weapons/revolver + name = "Revolver, .357" + item_cost = 56 + antag_roles = list(MODE_MERCENARY) + antag_costs = list(MODE_MERCENARY = 14) + path = /obj/item/weapon/storage/backpack/satchel/syndie_kit/revolver + +/datum/uplink_item/item/visible_weapons/revolver2 + name = "Revolver, .44" + item_cost = 48 + antag_roles = list(MODE_MERCENARY) + antag_costs = list(MODE_MERCENARY = 5) + path = /obj/item/weapon/storage/backpack/satchel/syndie_kit/revolver2 + +/datum/uplink_item/item/visible_weapons/grenade_launcher + name = "Grenade Launcher" + item_cost = 60 + antag_roles = list(MODE_MERCENARY) + antag_roles = list(MODE_MERCENARY = 12) + path = /obj/item/weapon/gun/launcher/grenade/loaded + +//These are for traitors (or other antags, perhaps) to have the option of purchasing some merc gear. +/datum/uplink_item/item/visible_weapons/submachinegun + name = "Submachine Gun" + item_cost = 52 + antag_roles = list(MODE_MERCENARY) + antag_costs = list(MODE_MERCENARY = 20) + path = /obj/item/weapon/gun/projectile/automatic/c20r + +/datum/uplink_item/item/visible_weapons/assaultrifle + name = "Assault Rifle" + item_cost = 60 + antag_roles = list(MODE_MERCENARY) + antag_costs = list(MODE_MERCENARY = 9) + path = /obj/item/weapon/gun/projectile/automatic/sts35 + +/* NO! +/datum/uplink_item/item/visible_weapons/advanced_energy_gun + name = "Advanced Energy Gun" + item_cost = 60 + path = /obj/item/weapon/gun/energy/gun/nuclear +*/ + +/datum/uplink_item/item/visible_weapons/heavysniper + name = "Anti-materiel Rifle with ammunition" + item_cost = 68 + antag_roles = list(MODE_MERCENARY) + antag_costs = list(MODE_MERCENARY = 15) + path = /obj/item/weapon/storage/secure/briefcase/heavysniper + +/datum/uplink_item/item/visible_weapons/machine_pistol + name = "Machine Pistol" + item_cost = 45 + antag_roles = list(MODE_MERCENARY) + antag_costs = list(MODE_MERCENARY = 10) + path = /obj/item/weapon/gun/projectile/automatic/machine_pistol + +/datum/uplink_item/item/visible_weapons/combat_shotgun + name = "Combat Shotgun" + item_cost = 52 + antag_roles = list(MODE_MERCENARY) + antag_costs = list(MODE_MERCENARY = 12) + path = /obj/item/weapon/gun/projectile/shotgun/pump/combat + +/datum/uplink_item/item/visible_weapons/sawnoff + name = "Sawnoff Shotgun" + item_cost = 45 + antag_roles = list(MODE_MERCENARY) + antag_costs = list(MODE_MERCENARY = 10) + path = /obj/item/weapon/gun/projectile/shotgun/doublebarrel/sawn + +/datum/uplink_item/item/visible_weapons/deagle + name = "Magnum Pistol" + antag_roles = list(MODE_MERCENARY) + item_cost = 52 + path = /obj/item/weapon/gun/projectile/magnum_pistol + +/datum/uplink_item/item/visible_weapons/detective_revolver + name = "Holdout Revolver" + item_cost = 38 + path = /obj/item/weapon/gun/projectile/revolver/detective + +/* goodbye +/datum/uplink_item/item/visible_weapons/pulserifle + name = "Pulse Rifle" + item_cost = 68 + antag_costs = list(MODE_MERCENARY = 30) + path = /obj/item/weapon/gun/energy/pulse_rifle +*/ diff --git a/code/datums/uplink/implants.dm b/code/datums/uplink/implants.dm new file mode 100644 index 00000000..d66952ea --- /dev/null +++ b/code/datums/uplink/implants.dm @@ -0,0 +1,37 @@ +/*********** +* Implants * +***********/ +/datum/uplink_item/item/implants + category = /datum/uplink_category/implants + +/* don't see a point when you can free yourself already. +/datum/uplink_item/item/implants/imp_freedom + name = "Freedom Implant" + item_cost = 24 + path = /obj/item/weapon/storage/box/syndie_kit/imp_freedom +*/ + +/datum/uplink_item/item/implants/imp_compress + name = "Compressed Matter Implant" + item_cost = 32 + path = /obj/item/weapon/storage/box/syndie_kit/imp_compress + +/datum/uplink_item/item/implants/imp_explosive + name = "Explosive Implant (DANGER!)" + item_cost = 40 + path = /obj/item/weapon/storage/box/syndie_kit/imp_explosive + +/datum/uplink_item/item/implants/imp_uplink + name = "Uplink Implant" + path = /obj/item/weapon/storage/box/syndie_kit/imp_uplink + +/datum/uplink_item/item/implants/imp_uplink/New() + ..() + item_cost = round(DEFAULT_TELECRYSTAL_AMOUNT / 2) + desc = "Contains [IMPLANT_TELECRYSTAL_AMOUNT(DEFAULT_TELECRYSTAL_AMOUNT)] Telecrystal\s" + +/datum/uplink_item/item/implants/imp_imprinting + name = "Neural Imprinting Implant" + desc = "Use on someone who is under influence of Mindbreaker to give them laws-like set of instructions. Kit comes with a dose of mindbreaker." + item_cost = 20 + path = /obj/item/weapon/storage/box/syndie_kit/imp_imprinting diff --git a/code/datums/uplink/medical.dm b/code/datums/uplink/medical.dm new file mode 100644 index 00000000..34c143b3 --- /dev/null +++ b/code/datums/uplink/medical.dm @@ -0,0 +1,20 @@ +/********** +* Medical * +**********/ +/datum/uplink_item/item/medical + category = /datum/uplink_category/medical + +/datum/uplink_item/item/medical/sinpockets + name = "Box of Sin-Pockets" + item_cost = 8 + path = /obj/item/weapon/storage/box/sinpockets + +/datum/uplink_item/item/medical/surgery + name = "Surgery kit" + item_cost = 40 + path = /obj/item/weapon/storage/firstaid/surgery + +/datum/uplink_item/item/medical/combat + name = "Combat medical kit" + item_cost = 48 + path = /obj/item/weapon/storage/firstaid/combat diff --git a/code/datums/uplink/services.dm b/code/datums/uplink/services.dm new file mode 100644 index 00000000..678769c7 --- /dev/null +++ b/code/datums/uplink/services.dm @@ -0,0 +1,234 @@ +/*********** +* Services * +************/ +/datum/uplink_item/item/services + category = /datum/uplink_category/services + +/datum/uplink_item/item/services/fake_ion_storm + name = "Ion Storm Announcement" + desc = "Interferes with ion sensors." + item_cost = 8 + path = /obj/item/device/uplink_service/fake_ion_storm + +/datum/uplink_item/item/services/suit_sensor_garble + name = "Complete Suit Sensor Jamming" + desc = "Garbles all suit sensor data for 10 minutes." + item_cost = 16 + path = /obj/item/device/uplink_service/jamming/garble + +/datum/uplink_item/item/services/fake_rad_storm + name = "Radiation Storm Announcement" + desc = "Interferes with radiation sensors." + item_cost = 24 + path = /obj/item/device/uplink_service/fake_rad_storm + +/datum/uplink_item/item/services/fake_crew_annoncement + name = "Crew Arrival Announcement and Records" + desc = "Creates a fake crew arrival announcement as well as fake crew records, using your current appearance (including held items!) and worn id card. Prepare well!" + item_cost = 16 + path = /obj/item/device/uplink_service/fake_crew_announcement + +/datum/uplink_item/item/services/suit_sensor_shutdown + name = "Complete Suit Sensor Shutdown" + desc = "Completely disables all suit sensors for 10 minutes." + item_cost = 40 + path = /obj/item/device/uplink_service/jamming + +/datum/uplink_item/item/services/fake_update_annoncement + item_cost = 40 + path = /obj/item/device/uplink_service/fake_update_announcement + +/datum/uplink_item/item/services/fake_update_annoncement/New() + ..() + item_cost = round(DEFAULT_TELECRYSTAL_AMOUNT / 2) + + spawn(2) + name = "[command_name()] Update Announcement" + desc = "Causes a falsified [command_name()] Update." + +/*************** +* Service Item * +***************/ + +#define AWAITING_ACTIVATION 0 +#define CURRENTLY_ACTIVE 1 +#define HAS_BEEN_ACTIVATED 2 + +/obj/item/device/uplink_service + name = "tiny device" + desc = "Press button to activate. Can be done once and only once." + w_class = ITEM_SIZE_TINY + icon_state = "sflash" + var/state = AWAITING_ACTIVATION + var/service_label = "Unnamed Service" + var/service_duration = 0 SECONDS + +/obj/item/device/uplink_service/Destroy() + if(state == CURRENTLY_ACTIVE) + deactivate() + . = ..() + +/obj/item/device/uplink_service/examine(var/user) + . = ..(user, 1) + if(.) + switch(state) + if(AWAITING_ACTIVATION) + to_chat(user, "It is labeled '[service_label]' and appears to be awaiting activation.") + if(CURRENTLY_ACTIVE) + to_chat(user, "It is labeled '[service_label]' and appears to be active.") + if(HAS_BEEN_ACTIVATED) + to_chat(user, "It is labeled '[service_label]' and appears to be permanently disabled.") + +/obj/item/device/uplink_service/attack_self(var/mob/user) + if(state != AWAITING_ACTIVATION) + to_chat(user, "\The [src] won't activate again.") + return + if(!enable()) + return + state = CURRENTLY_ACTIVE + update_icon() + user.visible_message("\The [user] activates \the [src].", "You activate \the [src].") + log_and_message_admins("has activated the service '[service_label]'", user) + + if(service_duration) + addtimer(CALLBACK(src,/obj/item/device/uplink_service/proc/deactivate), service_duration) + else + deactivate() + +/obj/item/device/uplink_service/proc/deactivate() + if(state != CURRENTLY_ACTIVE) + return + disable() + state = HAS_BEEN_ACTIVATED + update_icon() + playsound(loc, "sparks", 50, 1) + visible_message("\The [src] shuts down with a spark.") + +/obj/item/device/uplink_service/update_icon() + switch(state) + if(AWAITING_ACTIVATION) + icon_state = initial(icon_state) + if(CURRENTLY_ACTIVE) + icon_state = "sflash2" + if(HAS_BEEN_ACTIVATED) + icon_state = "flashburnt" + +/obj/item/device/uplink_service/proc/enable(var/mob/user = usr) + return TRUE + +/obj/item/device/uplink_service/proc/disable(var/mob/user = usr) + return + +/***************** +* Sensor Jamming * +*****************/ +/obj/item/device/uplink_service/jamming + service_duration = 10 MINUTES + service_label = "Suit Sensor Shutdown" + var/suit_sensor_jammer_method/ssjm = /suit_sensor_jammer_method/cap_off + +/obj/item/device/uplink_service/jamming/New() + ..() + ssjm = new ssjm() + +/obj/item/device/uplink_service/jamming/Destroy() + qdel(ssjm) + ssjm = null + . = ..() + +/obj/item/device/uplink_service/jamming/enable(var/mob/user = usr) + ssjm.enable() + . = ..() + +/obj/item/device/uplink_service/jamming/disable(var/mob/user = usr) + ssjm.disable() + +/obj/item/device/uplink_service/jamming/garble + service_label = "Suit Sensor Garble" + ssjm = /suit_sensor_jammer_method/random/moderate + +/***************** +* Fake Ion storm * +*****************/ +/obj/item/device/uplink_service/fake_ion_storm + service_label = "Ion Storm Announcement" + +/obj/item/device/uplink_service/fake_ion_storm/enable(var/mob/user = usr) + ion_storm_announcement() + . = ..() + +/***************** +* Fake Rad storm * +*****************/ +/obj/item/device/uplink_service/fake_rad_storm + service_label = "Radiation Storm Announcement" + +/obj/item/device/uplink_service/fake_rad_storm/enable(var/mob/user = usr) + var/datum/event_meta/EM = new(EVENT_LEVEL_MUNDANE, "Fake Radiation Storm", add_to_queue = 0) + new/datum/event/radiation_storm/syndicate(EM) + . = ..() + +/*************************** +* Fake CentCom Annoncement * +***************************/ +/obj/item/device/uplink_service/fake_update_announcement + service_label = "Update Announcement" + +/obj/item/device/uplink_service/fake_update_announcement/enable(var/mob/user = usr) + var/title = sanitize(input(user, "Enter your announcement title.", "Announcement Title") as null|text) + if(!title) + return + var/message = sanitize(input(user, "Enter your announcement message.", "Announcement Title") as null|text) + if(!message) + return + + if(CanUseTopic(user, GLOB.hands_state) != STATUS_INTERACTIVE) + return FALSE + command_announcement.Announce(message, title, msg_sanitized = 1) + return TRUE + +/********************************* +* Fake Crew Records/Announcement * +*********************************/ +/obj/item/device/uplink_service/fake_crew_announcement + service_label = "Crew Arrival Announcement and Records" + +/obj/item/device/uplink_service/fake_crew_announcement/enable(var/mob/user = usr) + var/obj/item/weapon/card/id/I = user.GetIdCard() + var/datum/computer_file/crew_record/random_record + + if(GLOB.all_crew_records.len) + random_record = pick(GLOB.all_crew_records) + + var/datum/computer_file/crew_record/new_record = CreateModularRecord(user) + if(I) + new_record.set_name(I.registered_name) + new_record.set_sex(I.sex) + new_record.set_age(I.age) + new_record.set_job(I.assignment) + new_record.set_fingerprint(I.fingerprint_hash) + new_record.set_bloodtype(I.blood_type) + new_record.set_dna(I.dna_hash) + if(I.military_branch) + new_record.set_branch(I.military_branch.name) + if(I.military_rank) + new_record.set_rank(I.military_rank.name) + else + var/mob/living/carbon/human/H = user + var/age = istype(H) ? H.age : 30 + var/assignment = GetAssignment(user) + new_record.set_name(user.real_name) + new_record.set_sex(capitalize(user.gender)) + new_record.set_age(age) + new_record.set_job(assignment) + //new_record.set_species(user.get_species()) + + if(random_record) + var/list/to_copy = list(REC_FIELD(fingerprint),REC_FIELD(dna),REC_FIELD(bloodtype)) + for(var/field in to_copy) + new_record.set_field(field, random_record.get_field(field)) + + var/datum/job/job = job_master.GetJob(new_record.get_job()) + if(istype(job) && job.announced) + AnnounceArrivalSimple(new_record.get_name(), new_record.get_job(), get_announcement_frequency(job)) + . = ..() diff --git a/code/datums/uplink/stealth_and_camouflage_items.dm b/code/datums/uplink/stealth_and_camouflage_items.dm new file mode 100644 index 00000000..90ad40b8 --- /dev/null +++ b/code/datums/uplink/stealth_and_camouflage_items.dm @@ -0,0 +1,37 @@ +/******************************* +* Stealth and Camouflage Items * +*******************************/ +/datum/uplink_item/item/stealth_items + category = /datum/uplink_category/stealth_items + +/datum/uplink_item/item/stealth_items/syndigaloshes + name = "No-Slip Shoes" + item_cost = 4 + path = /obj/item/clothing/shoes/syndigaloshes + +/datum/uplink_item/item/stealth_items/spy + name = "Bug Kit" + item_cost = 8 + path = /obj/item/weapon/storage/box/syndie_kit/spy + +/datum/uplink_item/item/stealth_items/id + name = "Agent ID card" + item_cost = 12 + path = /obj/item/weapon/card/id/syndicate + +/* They suck +/datum/uplink_item/item/stealth_items/chameleon_kit + name = "Chameleon Kit" + item_cost = 20 + path = /obj/item/weapon/storage/backpack/chameleon/sydie_kit + +/datum/uplink_item/item/stealth_items/voice + name = "Chameleon Mask/Voice Changer" + item_cost = 20 + path = /obj/item/clothing/mask/chameleon/voice + +/datum/uplink_item/item/stealth_items/chameleon_projector + name = "Chameleon-Projector" + item_cost = 32 + path = /obj/item/device/chameleon +*/ diff --git a/code/datums/uplink/stealthy_and_inconspicuous_weapons.dm b/code/datums/uplink/stealthy_and_inconspicuous_weapons.dm new file mode 100644 index 00000000..6abad604 --- /dev/null +++ b/code/datums/uplink/stealthy_and_inconspicuous_weapons.dm @@ -0,0 +1,42 @@ +/************************************* +* Stealthy and Inconspicuous Weapons * +*************************************/ +/datum/uplink_item/item/stealthy_weapons + category = /datum/uplink_category/stealthy_weapons + +/datum/uplink_item/item/stealthy_weapons/soap + name = "Subversive Soap" + item_cost = 1 + path = /obj/item/weapon/soap/syndie + +/datum/uplink_item/item/stealthy_weapons/cigarette_kit + name = "Cigarette Kit" + item_cost = 8 + path = /obj/item/weapon/storage/box/syndie_kit/cigarette + +/datum/uplink_item/item/stealthy_weapons/concealed_cane + name = "Concealed Cane Sword" + item_cost = 8 + path = /obj/item/weapon/cane/concealed + +/datum/uplink_item/item/stealthy_weapons/random_toxin + name = "Random Toxin - Beaker" + item_cost = 8 + path = /obj/item/weapon/storage/box/syndie_kit/toxin + +/* doesn't really fit interbay +/datum/uplink_item/item/stealthy_weapons/detomatix + name = "Detomatix PDA Cartridge" + item_cost = 16 + path = /obj/item/weapon/cartridge/syndicate +*/ + +/datum/uplink_item/item/stealthy_weapons/sleepy + name = "Sleepy Pen" + item_cost = 20 + path = /obj/item/weapon/pen/reagent/sleepy + +/datum/uplink_item/item/stealthy_weapons/syringegun + name = "Disguised Syringe Gun" + item_cost = 10 + path = /obj/item/weapon/storage/box/syndie_kit/syringegun diff --git a/code/datums/uplink/telecrystals.dm b/code/datums/uplink/telecrystals.dm new file mode 100644 index 00000000..03fd1e84 --- /dev/null +++ b/code/datums/uplink/telecrystals.dm @@ -0,0 +1,35 @@ +/*************** +* Telecrystals * +***************/ +/datum/uplink_item/item/telecrystal + category = /datum/uplink_category/telecrystals + desc = "Acquire the uplink crystals in pure form." + +/datum/uplink_item/item/telecrystal/get_goods(var/obj/item/device/uplink/U, var/loc) + return new /obj/item/stack/telecrystal(loc, cost(U.uses, U)) + +/datum/uplink_item/item/telecrystal/one + name = "Telecrystal - 01" + item_cost = 1 + +/datum/uplink_item/item/telecrystal/five + name = "Telecrystals - 05" + item_cost = 5 + +/datum/uplink_item/item/telecrystal/ten + name = "Telecrystals - 10" + item_cost = 10 + +/datum/uplink_item/item/telecrystal/twentyfive + name = "Telecrystals - 25" + item_cost = 25 + +/datum/uplink_item/item/telecrystal/fifty + name = "Telecrystals - 50" + item_cost = 50 + +/datum/uplink_item/item/telecrystal/all + name = "Telecrystals - Empty Uplink" + +/datum/uplink_item/item/telecrystal/all/cost(var/telecrystals, obj/item/device/uplink/U) + return max(1, telecrystals) diff --git a/code/datums/uplink/uplink_categories.dm b/code/datums/uplink/uplink_categories.dm new file mode 100644 index 00000000..e44fd2a1 --- /dev/null +++ b/code/datums/uplink/uplink_categories.dm @@ -0,0 +1,49 @@ +/datum/uplink_category + var/name = "" + var/list/datum/uplink_item/items + +/datum/uplink_category/New() + ..() + items = list() + +/datum/uplink_category/proc/can_view(obj/item/device/uplink/U) + for(var/datum/uplink_item/item in items) + if(item.can_view(U)) + return 1 + return 0 + +/datum/uplink_category/ammunition + name = "Ammunition" + +/datum/uplink_category/grenades + name = "Grenades and Thrown Objects" + +/datum/uplink_category/visible_weapons + name = "Highly Visible and Dangerous Weapons" + +/datum/uplink_category/stealthy_weapons + name = "Stealthy and Inconspicuous Weapons" + +/datum/uplink_category/stealth_items + name = "Stealth and Camouflage Items" + +/datum/uplink_category/tools + name = "Devices and Tools" + +/datum/uplink_category/implants + name = "Implants" + +/datum/uplink_category/medical + name = "Medical" + +/datum/uplink_category/hardsuit_modules + name = "Hardsuit Modules" + +/datum/uplink_category/services + name = "Services" + +/datum/uplink_category/badassery + name = "Badassery" + +/datum/uplink_category/telecrystals + name = "Telecrystals" diff --git a/code/datums/uplink/uplink_items.dm b/code/datums/uplink/uplink_items.dm new file mode 100644 index 00000000..b1510ecb --- /dev/null +++ b/code/datums/uplink/uplink_items.dm @@ -0,0 +1,164 @@ +var/datum/uplink/uplink = new() + +/datum/uplink + var/list/items_assoc + var/list/datum/uplink_item/items + var/list/datum/uplink_category/categories + +/datum/uplink/New() + items_assoc = list() + items = init_subtypes(/datum/uplink_item) + categories = init_subtypes(/datum/uplink_category) + categories = dd_sortedObjectList(categories) + + for(var/datum/uplink_item/item in items) + if(!item.name) + items -= item + continue + + items_assoc[item.type] = item + + for(var/datum/uplink_category/category in categories) + if(item.category == category.type) + category.items += item + item.category = category + + for(var/datum/uplink_category/category in categories) + category.items = dd_sortedObjectList(category.items) + +/datum/uplink_item + var/name + var/desc + var/item_cost = 0 + var/list/antag_costs = list() // Allows specific antag roles to purchase at a different cost + var/datum/uplink_category/category // Item category + var/list/datum/antagonist/antag_roles = list("Exclude", MODE_DEITY) // Antag roles this item is displayed to. If empty, display to all. If it includes 'Exclude", anybody except this role can view it + +/datum/uplink_item/item + var/path = null + +/datum/uplink_item/proc/buy(var/obj/item/device/uplink/U, var/mob/user) + var/extra_args = extra_args(user) + if(!extra_args) + return + + if(!can_buy(U)) + return + + var/cost = cost(U.uses, U) + + var/goods = get_goods(U, get_turf(user), user, extra_args) + if(!goods) + return + + purchase_log(U, user, cost) + U.uses -= cost + U.used_TC += cost + return goods + +// Any additional arguments you wish to send to the get_goods +/datum/uplink_item/proc/extra_args(var/mob/user) + return 1 + +/datum/uplink_item/proc/can_buy(obj/item/device/uplink/U) + if(cost(U.uses, U) > U.uses) + return 0 + + return can_view(U) + +/datum/uplink_item/proc/can_view(obj/item/device/uplink/U) + // Making the assumption that if no uplink was supplied, then we don't care about antag roles + if(!U || !antag_roles.len) + return 1 + + // With no owner, there's no need to check antag status. + if(!U.uplink_owner) + return 0 + + for(var/antag_role in antag_roles) + if(antag_role == "Exclude") + continue + var/datum/antagonist/antag = all_antag_types()[antag_role] + if(antag.is_antagonist(U.uplink_owner)) + return !("Exclude" in antag_roles) + return ("Exclude" in antag_roles) + +/datum/uplink_item/proc/cost(var/telecrystals, obj/item/device/uplink/U) + . = item_cost + if(U && U.uplink_owner) + for(var/antag_role in antag_costs) + var/datum/antagonist/antag = all_antag_types()[antag_role] + if(antag.is_antagonist(U.uplink_owner)) + . = min(antag_costs[antag_role], .) + return max(1, U ? U.get_item_cost(src, .) : .) + +/datum/uplink_item/proc/name() + return name + +/datum/uplink_item/proc/description() + return desc + +// get_goods does not necessarily return physical objects, it is simply a way to acquire the uplink item without paying +/datum/uplink_item/proc/get_goods(var/obj/item/device/uplink/U, var/loc) + return 0 + +/datum/uplink_item/proc/log_icon() + return + +/datum/uplink_item/proc/purchase_log(obj/item/device/uplink/U, var/mob/user, var/cost) + feedback_add_details("traitor_uplink_items_bought", "[src]") + log_and_message_admins("used \the [U.loc] to buy \a [src]") + if(user) + uplink_purchase_repository.add_entry(user.mind, src, cost) + +datum/uplink_item/dd_SortValue() + return cost(INFINITY, null) + +/******************************** +* * +* Physical Uplink Entries * +* * +********************************/ +/datum/uplink_item/item/buy(var/obj/item/device/uplink/U, var/mob/user) + var/obj/item/I = ..() + if(!I) + return + + if(istype(I, /list)) + var/list/L = I + if(L.len) I = L[1] + + if(istype(I) && ishuman(user)) + var/mob/living/carbon/human/A = user + A.put_in_any_hand_if_possible(I) + return I + +/datum/uplink_item/item/get_goods(var/obj/item/device/uplink/U, var/loc) + var/obj/item/I = new path(loc) + return I + +/datum/uplink_item/item/description() + if(!desc) + // Fallback description + var/obj/temp = src.path + desc = initial(temp.desc) + return ..() + +/datum/uplink_item/item/log_icon() + var/obj/I = path + return "\icon[I]" + +/**************** +* Support procs * +****************/ +/proc/get_random_uplink_items(var/obj/item/device/uplink/U, var/remaining_TC, var/loc) + var/list/bought_items = list() + while(remaining_TC) + var/datum/uplink_random_selection/uplink_selection = get_uplink_random_selection_by_type(/datum/uplink_random_selection/default) + var/datum/uplink_item/I = uplink_selection.get_random_item(remaining_TC, U, bought_items) + if(!I) + break + bought_items += I + remaining_TC -= I.cost(remaining_TC, U) + + return bought_items diff --git a/code/datums/uplink/uplink_sources.dm b/code/datums/uplink/uplink_sources.dm new file mode 100644 index 00000000..a27a973d --- /dev/null +++ b/code/datums/uplink/uplink_sources.dm @@ -0,0 +1,133 @@ +#define NO_GUARANTEE_NO_EXTRA_COST_DESC(X) "Installs an uplink into " + X + " if, and only if, found on your person. Has no TC cost." + +#define SETUP_FAILED TRUE + +GLOBAL_LIST_INIT(default_uplink_source_priority, list( + /decl/uplink_source/pda, + /decl/uplink_source/radio, + /decl/uplink_source/unit)) + +/decl/uplink_source + var/name + var/desc + +/decl/uplink_source/proc/setup_uplink_source(var/mob/M, var/amount) + return SETUP_FAILED + +/decl/uplink_source/pda + name = "PDA" + desc = NO_GUARANTEE_NO_EXTRA_COST_DESC("a PDA") + +/decl/uplink_source/pda/setup_uplink_source(var/mob/M, var/amount) + var/obj/item/device/pda/P = find_in_mob(M, /obj/item/device/pda) + if(!P) + return SETUP_FAILED + + var/pda_pass = "[rand(100,999)] [pick(GLOB.greek_letters)]" + var/obj/item/device/uplink/T = new(P, M.mind, amount) + P.hidden_uplink = T + P.lock_code = pda_pass + to_chat(M, "A portable object teleportation relay has been installed in your [P.name]. Simply enter the code \"[pda_pass]\" into the ringtone select to unlock its hidden features.") + M.mind.store_memory("Uplink Passcode: [pda_pass] ([P.name]).") + +/decl/uplink_source/radio + name = "Radio" + desc = NO_GUARANTEE_NO_EXTRA_COST_DESC("a radio") + +/decl/uplink_source/radio/setup_uplink_source(var/mob/M, var/amount) + var/obj/item/device/radio/R = find_in_mob(M, /obj/item/device/radio) + if(!R) + return SETUP_FAILED + + var/freq = PUBLIC_LOW_FREQ + var/list/freqlist = list() + while (freq <= PUBLIC_HIGH_FREQ) + if (freq < 1451 || freq > PUB_FREQ) + freqlist += freq + freq += 2 + if ((freq % 2) == 0) + freq += 1 + + freq = freqlist[rand(1, freqlist.len)] + var/obj/item/device/uplink/T = new(R, M.mind, amount) + R.hidden_uplink = T + R.traitor_frequency = freq + to_chat(M, "A portable object teleportation relay has been installed in your [R.name]. Simply dial the frequency [format_frequency(freq)] to unlock its hidden features.") + M.mind.store_memory("Radio Freq: [format_frequency(freq)] ([R.name]).") + +/decl/uplink_source/implant + name = "Implant" + desc = "Teleports an uplink implant into your head. Costs at least half the initial TC amount." + +/decl/uplink_source/implant/setup_uplink_source(var/mob/living/carbon/human/H, var/amount) + if(!istype(H)) + return SETUP_FAILED + + var/obj/item/organ/external/head = H.organs_by_name[BP_HEAD] + if(!head) + return SETUP_FAILED + + var/obj/item/weapon/implant/uplink/U = new(H, IMPLANT_TELECRYSTAL_AMOUNT(amount)) + U.imp_in = H + U.implanted = TRUE + U.part = head + head.implants += U + + U.implanted(H) // This proc handles the installation feedback + +/decl/uplink_source/unit + name = "Uplink Unit" + desc = "Teleports an uplink unit to your location. Costs 10% of the initial TC amount." + +/decl/uplink_source/unit/setup_uplink_source(var/mob/M, var/amount) + var/obj/item/device/radio/uplink/U = new(M, M.mind, round(amount * 0.9)) + put_on_mob(M, U, "\A [U]") + +/decl/uplink_source/telecrystals + name = "Telecrystals" + desc = "Get your telecrystals in pure form, without the means to trade them for goods." + +/decl/uplink_source/telecrystals/setup_uplink_source(var/mob/M, var/amount) + var/obj/item/stack/telecrystal/TC = new(M, amount) + put_on_mob(M, TC, "[amount] telecrystal\s") + +/decl/uplink_source/proc/find_in_mob(var/mob/M, var/type) + for(var/item in M.get_equipped_items(TRUE)) + if(!istype(item, type)) + continue + var/obj/item/I = item + if(!I.hidden_uplink) + return I + +/decl/uplink_source/proc/put_on_mob(var/mob/M, var/atom/movable/AM, var/text) + var/obj/O = M.equip_to_storage(AM) + if(O) + to_chat(M, "[text] can be found in your [O.name].") + else if(M.put_in_hands(AM)) + to_chat(M, "[text] appear in your hands.") + else + AM.dropInto(M.loc) + to_chat(M, "[text] appear at your location.") + +/proc/setup_uplink_source(var/mob/M, var/amount = DEFAULT_TELECRYSTAL_AMOUNT) + if(!istype(M) || !M.mind) + return FALSE + + var/list/priority_order + if(M.client && M.client.prefs) + priority_order = M.client.prefs.uplink_sources + + if(!priority_order || !priority_order.len) + priority_order = list() + for(var/entry in GLOB.default_uplink_source_priority) + priority_order += decls_repository.get_decl(entry) + + for(var/entry in priority_order) + var/decl/uplink_source/US = entry + if(US.setup_uplink_source(M, amount) != SETUP_FAILED) + return TRUE + + to_chat(M, "Either by choice or circumstance you will be without an uplink.") + return FALSE + +#undef SETUP_FAILED diff --git a/code/datums/vending/stored_item.dm b/code/datums/vending/stored_item.dm new file mode 100644 index 00000000..f1012bec --- /dev/null +++ b/code/datums/vending/stored_item.dm @@ -0,0 +1,70 @@ +/datum/stored_items + var/item_name = "name" //Name of the item(s) displayed + var/item_path = null // The original amount held + var/amount = 0 + var/list/instances //What items are actually stored + var/atom/storing_object + +/datum/stored_items/New(var/atom/storing_object, var/path, var/name = null, var/amount = 0) + if(!istype(storing_object)) + CRASH("Unexpected storing object.") + src.storing_object = storing_object + src.item_path = path + src.amount = amount + + if(!name) + var/atom/tmp = path + src.item_name = initial(tmp.name) + else + src.item_name = name + ..() + +/datum/stored_items/Destroy() + storing_object = null + if(instances) + for(var/instance in instances) + qdel(instance) + instances = null + . = ..() + +/datum/stored_items/dd_SortValue() + return item_name + +/datum/stored_items/proc/get_amount() + return instances ? instances.len : amount + +/datum/stored_items/proc/add_product(var/atom/movable/product) + if(product.type != item_path) + return 0 + init_products() + if(product in instances) + return 0 + product.forceMove(storing_object) + instances += product + return 1 + +/datum/stored_items/proc/get_product(var/product_location) + if(!get_amount() || !product_location) + return + init_products() + + var/atom/movable/product = instances[instances.len] // Remove the last added product + instances -= product + product.forceMove(product_location) + return product + +/datum/stored_items/proc/get_specific_product(var/product_location, var/atom/movable/product) + if(!get_amount() || !instances || !product_location || !product) + return FALSE + + . = instances.Remove(product) + if(.) + product.forceMove(product_location) + +/datum/stored_items/proc/init_products() + if(instances) + return + instances = list() + for(var/i = 1 to amount) + var/new_product = new item_path(storing_object) + instances += new_product diff --git a/code/datums/vending/vending.dm b/code/datums/vending/vending.dm new file mode 100644 index 00000000..45f5a556 --- /dev/null +++ b/code/datums/vending/vending.dm @@ -0,0 +1,19 @@ +#define VENDING_CATEGORY_NORMAL 1 //Item is dispensed normally +#define VENDING_CATEGORY_HIDDEN 2 //Item is hidden (contraband) +#define VENDING_CATEGORY_PREMIUM 4 //Item requires a coin (premium item) + +/** + * Datum used to hold information about a product in a vending machine + */ + +/datum/stored_items/vending_products + item_name = "generic" // Display name for the product + var/price = 0 // Price to buy one + var/display_color = null // Display color for vending machine listing + var/category = VENDING_CATEGORY_NORMAL //Normal, Contraband or premium. + +/datum/stored_items/vending_products/New(var/atom/storing_object, var/path, var/name = null, var/amount = 0, var/price = 0, var/color = null, var/category = VENDING_CATEGORY_NORMAL) + ..() + src.price = price + src.display_color = color + src.category = category diff --git a/code/datums/weakref.dm b/code/datums/weakref.dm new file mode 100644 index 00000000..68aedb88 --- /dev/null +++ b/code/datums/weakref.dm @@ -0,0 +1,44 @@ +/datum + var/tmp/weakref/weakref + +/datum/Destroy() + weakref = null // Clear this reference to ensure it's kept for as brief duration as possible. + . = ..() + +//obtain a weak reference to a datum +/proc/weakref(datum/D) + if(!istype(D)) + return + if(QDELETED(D)) + return + if(istype(D, /weakref)) + return D + if(!D.weakref) + D.weakref = new/weakref(D) + return D.weakref + +/weakref + var/ref + + // Handy info for debugging + var/tmp/ref_name + var/tmp/ref_type + +/weakref/New(datum/D) + ref = "\ref[D]" + ref_name = "[D]" + ref_type = D.type + +/weakref/Destroy() + // A weakref datum should not be manually destroyed as it is a shared resource, + // rather it should be automatically collected by the BYOND GC when all references are gone. + return QDEL_HINT_IWILLGC + +/weakref/proc/resolve() + var/datum/D = locate(ref) + if(D && D.weakref == src) + return D + return null + +/weakref/get_log_info_line() + return "[ref_name] ([ref_type]) ([ref]) (WEAKREF)" diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm new file mode 100644 index 00000000..6384fc04 --- /dev/null +++ b/code/datums/wires/airlock.dm @@ -0,0 +1,176 @@ +// Wires for airlocks + +/datum/wires/airlock/secure + random = 1 + wire_count = 14 + window_y = 680 + +/datum/wires/airlock + holder_type = /obj/machinery/door/airlock + wire_count = 12 + window_y = 570 + +var/const/AIRLOCK_WIRE_IDSCAN = 1 +var/const/AIRLOCK_WIRE_MAIN_POWER1 = 2 +var/const/AIRLOCK_WIRE_MAIN_POWER2 = 4 +var/const/AIRLOCK_WIRE_DOOR_BOLTS = 8 +var/const/AIRLOCK_WIRE_BACKUP_POWER1 = 16 +var/const/AIRLOCK_WIRE_BACKUP_POWER2 = 32 +var/const/AIRLOCK_WIRE_OPEN_DOOR = 64 +var/const/AIRLOCK_WIRE_AI_CONTROL = 128 +var/const/AIRLOCK_WIRE_ELECTRIFY = 256 +var/const/AIRLOCK_WIRE_SAFETY = 512 +var/const/AIRLOCK_WIRE_SPEED = 1024 +var/const/AIRLOCK_WIRE_LIGHT = 2048 + +/datum/wires/airlock/CanUse(var/mob/living/L) + var/obj/machinery/door/airlock/A = holder + if(!istype(L, /mob/living/silicon)) + if(A.isElectrified()) + if(A.shock(L, 100)) + return 0 + if(A.p_open) + return 1 + return 0 + +/datum/wires/airlock/GetInteractWindow() + var/obj/machinery/door/airlock/A = holder + var/haspower = A.arePowerSystemsOn() //If there's no power, then no lights will be on. + + . += ..() + . += text("
    \n[]
    \n[]
    \n[]
    \n[]
    \n[]
    \n[]
    \n[]
    \n[]", + (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.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."), + ((A.aiDisabledIdScanner==0 && haspower)? "The IDScan light is on." : "The IDScan light is off.")) + +/datum/wires/airlock/UpdateCut(var/index, var/mended) + + var/obj/machinery/door/airlock/A = holder + switch(index) + if(AIRLOCK_WIRE_IDSCAN) + A.aiDisabledIdScanner = !mended + if(AIRLOCK_WIRE_MAIN_POWER1, AIRLOCK_WIRE_MAIN_POWER2) + + if(!mended) + //Cutting either one disables the main door power, but unless backup power is also cut, the backup power re-powers the door in 10 seconds. While unpowered, the door may be crowbarred open, but bolts-raising will not work. Cutting these wires may electocute the user. + A.loseMainPower() + A.shock(usr, 50) + else + A.regainMainPower() + A.shock(usr, 50) + + if(AIRLOCK_WIRE_BACKUP_POWER1, AIRLOCK_WIRE_BACKUP_POWER2) + + if(!mended) + //Cutting either one disables the backup door power (allowing it to be crowbarred open, but disabling bolts-raising), but may electocute the user. + A.loseBackupPower() + A.shock(usr, 50) + else + A.regainBackupPower() + A.shock(usr, 50) + + if(AIRLOCK_WIRE_DOOR_BOLTS) + + if(!mended) + //Cutting this wire also drops the door bolts, and mending it does not raise them. (This is what happens now, except there are a lot more wires going to door bolts at present) + A.lock(1) + A.update_icon() + + if(AIRLOCK_WIRE_AI_CONTROL) + + if(!mended) + //one wire for AI control. Cutting this prevents the AI from controlling the door unless it has hacked the door through the power connection (which takes about a minute). If both main and backup power are cut, as well as this wire, then the AI cannot operate or hack the door at all. + //aiControlDisabled: If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in. + if(A.aiControlDisabled == 0) + A.aiControlDisabled = 1 + else if(A.aiControlDisabled == -1) + A.aiControlDisabled = 2 + else + if(A.aiControlDisabled == 1) + A.aiControlDisabled = 0 + else if(A.aiControlDisabled == 2) + A.aiControlDisabled = -1 + + if(AIRLOCK_WIRE_ELECTRIFY) + if(!mended) + //Cutting this wire electrifies the door, so that the next person to touch the door without insulated gloves gets electrocuted. + A.electrify(-1) + else + A.electrify(0) + return // Don't update the dialog. + + if (AIRLOCK_WIRE_SAFETY) + A.safe = mended + + if(AIRLOCK_WIRE_SPEED) + A.autoclose = mended + if(mended) + if(!A.density) + A.close() + + if(AIRLOCK_WIRE_LIGHT) + A.lights = mended + A.update_icon() + + +/datum/wires/airlock/UpdatePulsed(var/index) + + var/obj/machinery/door/airlock/A = holder + switch(index) + if(AIRLOCK_WIRE_IDSCAN) + //Sending a pulse through flashes the red light on the door (if the door has power). + if(A.arePowerSystemsOn() && A.density) + A.do_animate("deny") + if(AIRLOCK_WIRE_MAIN_POWER1, AIRLOCK_WIRE_MAIN_POWER2) + //Sending a pulse through either one causes a breaker to trip, disabling the door for 10 seconds if backup power is connected, or 1 minute if not (or until backup power comes back on, whichever is shorter). + A.loseMainPower() + if(AIRLOCK_WIRE_DOOR_BOLTS) + //one wire for door bolts. Sending a pulse through this drops door bolts if they're not down (whether power's on or not), + //raises them if they are down (only if power's on) + if(!A.locked) + A.lock() + else + A.unlock() + + if(AIRLOCK_WIRE_BACKUP_POWER1, AIRLOCK_WIRE_BACKUP_POWER2) + //two wires for backup power. Sending a pulse through either one causes a breaker to trip, but this does not disable it unless main power is down too (in which case it is disabled for 1 minute or however long it takes main power to come back, whichever is shorter). + A.loseBackupPower() + if(AIRLOCK_WIRE_AI_CONTROL) + if(A.aiControlDisabled == 0) + A.aiControlDisabled = 1 + else if(A.aiControlDisabled == -1) + A.aiControlDisabled = 2 + + spawn(10) + if(A) + if(A.aiControlDisabled == 1) + A.aiControlDisabled = 0 + else if(A.aiControlDisabled == 2) + A.aiControlDisabled = -1 + + if(AIRLOCK_WIRE_ELECTRIFY) + //one wire for electrifying the door. Sending a pulse through this electrifies the door for 30 seconds. + A.electrify(30) + if(AIRLOCK_WIRE_OPEN_DOOR) + //tries to open the door without ID + //will succeed only if the ID wire is cut or the door requires no access and it's not emagged + if(A.emagged) return + if(!A.requiresID() || A.check_access(null)) + if(A.density) A.open() + else A.close() + if(AIRLOCK_WIRE_SAFETY) + A.safe = !A.safe + if(!A.density) + A.close() + + if(AIRLOCK_WIRE_SPEED) + A.normalspeed = !A.normalspeed + + if(AIRLOCK_WIRE_LIGHT) + A.lights = !A.lights + A.update_icon() diff --git a/code/datums/wires/alarm.dm b/code/datums/wires/alarm.dm new file mode 100644 index 00000000..53a58587 --- /dev/null +++ b/code/datums/wires/alarm.dm @@ -0,0 +1,102 @@ +/datum/wires/alarm + holder_type = /obj/machinery/alarm + wire_count = 5 + +var/const/AALARM_WIRE_IDSCAN = 1 +var/const/AALARM_WIRE_POWER = 2 +var/const/AALARM_WIRE_SYPHON = 4 +var/const/AALARM_WIRE_AI_CONTROL = 8 +var/const/AALARM_WIRE_AALARM = 16 + + +/datum/wires/alarm/CanUse(var/mob/living/L) + var/obj/machinery/alarm/A = holder + if(A.wiresexposed && A.buildstage == 2) + return 1 + return 0 + +/datum/wires/alarm/GetInteractWindow() + var/obj/machinery/alarm/A = holder + . += ..() + . += text("
    \n[(A.locked ? "The Air Alarm is locked." : "The Air Alarm is unlocked.")]
    \n[((A.shorted || (A.stat & (NOPOWER|BROKEN))) ? "The Air Alarm is offline." : "The Air Alarm is working properly!")]
    \n[(A.aidisabled ? "The 'AI control allowed' light is off." : "The 'AI control allowed' light is on.")]") + +/datum/wires/alarm/UpdateCut(var/index, var/mended) + var/obj/machinery/alarm/A = holder + switch(index) + if(AALARM_WIRE_IDSCAN) + if(!mended) + A.locked = 1 +// log_debug("Idscan wire cut") + + + if(AALARM_WIRE_POWER) + A.shock(usr, 50) + A.shorted = !mended + A.update_icon() +// log_debug("Power wire cut") + + + if (AALARM_WIRE_AI_CONTROL) + if (A.aidisabled == !mended) + A.aidisabled = mended +// log_debug("AI Control Wire Cut") + + + if(AALARM_WIRE_SYPHON) + if(!mended) + A.mode = 3 // AALARM_MODE_PANIC + A.apply_mode() +// log_debug("Syphon Wire Cut") + + + if(AALARM_WIRE_AALARM) + if (A.alarm_area.atmosalert(2, A)) + A.post_alert(2) + A.update_icon() + +/datum/wires/alarm/UpdatePulsed(var/index) + var/obj/machinery/alarm/A = holder + switch(index) + if(AALARM_WIRE_IDSCAN) + A.locked = !A.locked +// log_debug("Idscan wire pulsed") + + + if (AALARM_WIRE_POWER) +// log_debug("Power wire pulsed") + + if(A.shorted == 0) + A.shorted = 1 + A.update_icon() + + spawn(12000) + if(A.shorted == 1) + A.shorted = 0 + A.update_icon() + + + if (AALARM_WIRE_AI_CONTROL) +// log_debug("AI Control wire pulsed") + + if (A.aidisabled == 0) + A.aidisabled = 1 + A.updateDialog() + spawn(100) + if (A.aidisabled == 1) + A.aidisabled = 0 + + if(AALARM_WIRE_SYPHON) +// log_debug("Syphon wire pulsed") + + if(A.mode == 1) // AALARM_MODE_SCRUB + A.mode = 3 // AALARM_MODE_PANIC + else + A.mode = 1 // AALARM_MODE_SCRUB + A.apply_mode() + + if(AALARM_WIRE_AALARM) +// log_debug("Aalarm wire pulsed") + + if (A.alarm_area.atmosalert(0, A)) + A.post_alert(0) + A.update_icon() diff --git a/code/datums/wires/apc.dm b/code/datums/wires/apc.dm new file mode 100644 index 00000000..bdddf048 --- /dev/null +++ b/code/datums/wires/apc.dm @@ -0,0 +1,72 @@ +/datum/wires/apc + holder_type = /obj/machinery/power/apc + wire_count = 4 + +#define APC_WIRE_IDSCAN 1 +#define APC_WIRE_MAIN_POWER1 2 +#define APC_WIRE_MAIN_POWER2 4 +#define APC_WIRE_AI_CONTROL 8 + +/datum/wires/apc/GetInteractWindow() + var/obj/machinery/power/apc/A = holder + . += ..() + . += text("
    \n[(A.locked ? "The APC is locked." : "The APC is unlocked.")]
    \n[(A.shorted ? "The APCs power has been shorted." : "The APC is working properly!")]
    \n[(A.aidisabled ? "The 'AI control allowed' light is off." : "The 'AI control allowed' light is on.")]") + + +/datum/wires/apc/CanUse(var/mob/living/L) + var/obj/machinery/power/apc/A = holder + if(A.wiresexposed) + return 1 + return 0 + +/datum/wires/apc/UpdatePulsed(var/index) + + var/obj/machinery/power/apc/A = holder + + switch(index) + + if(APC_WIRE_IDSCAN) + A.locked = 0 + + spawn(300) + if(A) + A.locked = 1 + + if (APC_WIRE_MAIN_POWER1, APC_WIRE_MAIN_POWER2) + if(A.shorted == 0) + A.shorted = 1 + + spawn(1200) + if(A && !IsIndexCut(APC_WIRE_MAIN_POWER1) && !IsIndexCut(APC_WIRE_MAIN_POWER2)) + A.shorted = 0 + + if (APC_WIRE_AI_CONTROL) + if (A.aidisabled == 0) + A.aidisabled = 1 + + spawn(10) + if(A && !IsIndexCut(APC_WIRE_AI_CONTROL)) + A.aidisabled = 0 + +/datum/wires/apc/UpdateCut(var/index, var/mended) + var/obj/machinery/power/apc/A = holder + + switch(index) + if(APC_WIRE_MAIN_POWER1, APC_WIRE_MAIN_POWER2) + + if(!mended) + A.shock(usr, 50) + A.shorted = 1 + + else if(!IsIndexCut(APC_WIRE_MAIN_POWER1) && !IsIndexCut(APC_WIRE_MAIN_POWER2)) + A.shorted = 0 + A.shock(usr, 50) + + if(APC_WIRE_AI_CONTROL) + + if(!mended) + if (A.aidisabled == 0) + A.aidisabled = 1 + else + if (A.aidisabled == 1) + A.aidisabled = 0 diff --git a/code/datums/wires/autolathe.dm b/code/datums/wires/autolathe.dm new file mode 100644 index 00000000..1dd4132e --- /dev/null +++ b/code/datums/wires/autolathe.dm @@ -0,0 +1,60 @@ +/datum/wires/autolathe + + holder_type = /obj/machinery/autolathe + wire_count = 6 + +var/const/AUTOLATHE_HACK_WIRE = 1 +var/const/AUTOLATHE_SHOCK_WIRE = 2 +var/const/AUTOLATHE_DISABLE_WIRE = 4 + +/datum/wires/autolathe/GetInteractWindow() + var/obj/machinery/autolathe/A = holder + . += ..() + . += "
    The red light is [A.disabled ? "off" : "on"]." + . += "
    The green light is [A.shocked ? "off" : "on"]." + . += "
    The blue light is [A.hacked ? "off" : "on"].
    " + +/datum/wires/autolathe/CanUse() + var/obj/machinery/autolathe/A = holder + if(A.panel_open) + return 1 + return 0 + +/datum/wires/autolathe/Interact(var/mob/living/user) + if(CanUse(user)) + var/obj/machinery/autolathe/V = holder + V.attack_hand(user) + +/datum/wires/autolathe/UpdateCut(index, mended) + var/obj/machinery/autolathe/A = holder + switch(index) + if(AUTOLATHE_HACK_WIRE) + A.hacked = !mended + if(AUTOLATHE_SHOCK_WIRE) + A.shocked = !mended + if(AUTOLATHE_DISABLE_WIRE) + A.disabled = !mended + +/datum/wires/autolathe/UpdatePulsed(index) + if(IsIndexCut(index)) + return + var/obj/machinery/autolathe/A = holder + switch(index) + if(AUTOLATHE_HACK_WIRE) + A.hacked = !A.hacked + spawn(50) + if(A && !IsIndexCut(index)) + A.hacked = 0 + Interact(usr) + if(AUTOLATHE_SHOCK_WIRE) + A.shocked = !A.shocked + spawn(50) + if(A && !IsIndexCut(index)) + A.shocked = 0 + Interact(usr) + if(AUTOLATHE_DISABLE_WIRE) + A.disabled = !A.disabled + spawn(50) + if(A && !IsIndexCut(index)) + A.disabled = 0 + Interact(usr) diff --git a/code/datums/wires/camera.dm b/code/datums/wires/camera.dm new file mode 100644 index 00000000..1724b946 --- /dev/null +++ b/code/datums/wires/camera.dm @@ -0,0 +1,71 @@ +// Wires for cameras. + +/datum/wires/camera + random = 1 + holder_type = /obj/machinery/camera + wire_count = 6 + +/datum/wires/camera/GetInteractWindow() + + . = ..() + var/obj/machinery/camera/C = holder + . += "
    \n[(C.view_range == initial(C.view_range) ? "The focus light is on." : "The focus light is off.")]" + . += "
    \n[(C.can_use() ? "The power link light is on." : "The power link light is off.")]" + . += "
    \n[(C.light_disabled ? "The camera light is off." : "The camera light is on.")]" + . += "
    \n[(C.alarm_on ? "The alarm light is on." : "The alarm light is off.")]" + return . + +/datum/wires/camera/CanUse(var/mob/living/L) + var/obj/machinery/camera/C = holder + return C.panel_open + +var/const/CAMERA_WIRE_FOCUS = 1 +var/const/CAMERA_WIRE_POWER = 2 +var/const/CAMERA_WIRE_LIGHT = 4 +var/const/CAMERA_WIRE_ALARM = 8 +var/const/CAMERA_WIRE_NOTHING1 = 16 +var/const/CAMERA_WIRE_NOTHING2 = 32 + +/datum/wires/camera/UpdateCut(var/index, var/mended) + var/obj/machinery/camera/C = holder + + switch(index) + if(CAMERA_WIRE_FOCUS) + var/range = (mended ? initial(C.view_range) : C.short_range) + C.setViewRange(range) + + if(CAMERA_WIRE_POWER) + if(C.status && !mended || !C.status && mended) + C.deactivate(usr, 1) + + if(CAMERA_WIRE_LIGHT) + C.light_disabled = !mended + + if(CAMERA_WIRE_ALARM) + if(!mended) + C.triggerCameraAlarm() + else + C.cancelCameraAlarm() + return + +/datum/wires/camera/UpdatePulsed(var/index) + var/obj/machinery/camera/C = holder + if(IsIndexCut(index)) + return + switch(index) + if(CAMERA_WIRE_FOCUS) + var/new_range = (C.view_range == initial(C.view_range) ? C.short_range : initial(C.view_range)) + C.setViewRange(new_range) + + if(CAMERA_WIRE_LIGHT) + C.light_disabled = !C.light_disabled + + if(CAMERA_WIRE_ALARM) + C.visible_message("\icon[C] *beep*", "\icon[C] *beep*") + return + +/datum/wires/camera/proc/CanDeconstruct() + if(IsIndexCut(CAMERA_WIRE_POWER) && IsIndexCut(CAMERA_WIRE_FOCUS) && IsIndexCut(CAMERA_WIRE_LIGHT) && IsIndexCut(CAMERA_WIRE_NOTHING1) && IsIndexCut(CAMERA_WIRE_NOTHING2)) + return 1 + else + return 0 diff --git a/code/datums/wires/explosive.dm b/code/datums/wires/explosive.dm new file mode 100644 index 00000000..6dc8e988 --- /dev/null +++ b/code/datums/wires/explosive.dm @@ -0,0 +1,31 @@ +/datum/wires/explosive + wire_count = 1 + +var/const/WIRE_EXPLODE = 1 + +/datum/wires/explosive/proc/explode() + return + +/datum/wires/explosive/UpdatePulsed(var/index) + switch(index) + if(WIRE_EXPLODE) + explode() + +/datum/wires/explosive/UpdateCut(var/index, var/mended) + switch(index) + if(WIRE_EXPLODE) + if(!mended) + explode() + +/datum/wires/explosive/c4 + holder_type = /obj/item/weapon/plastique + +/datum/wires/explosive/c4/CanUse(var/mob/living/L) + var/obj/item/weapon/plastique/P = holder + if(P.open_panel) + return 1 + return 0 + +/datum/wires/explosive/c4/explode() + var/obj/item/weapon/plastique/P = holder + P.explode(get_turf(P)) diff --git a/code/datums/wires/nuclearbomb.dm b/code/datums/wires/nuclearbomb.dm new file mode 100644 index 00000000..b33daa75 --- /dev/null +++ b/code/datums/wires/nuclearbomb.dm @@ -0,0 +1,58 @@ +/datum/wires/nuclearbomb + holder_type = /obj/machinery/nuclearbomb + random = 1 + wire_count = 7 + +var/const/NUCLEARBOMB_WIRE_LIGHT = 1 +var/const/NUCLEARBOMB_WIRE_TIMING = 2 +var/const/NUCLEARBOMB_WIRE_SAFETY = 4 + +/datum/wires/nuclearbomb/CanUse(var/mob/living/L) + var/obj/machinery/nuclearbomb/N = holder + return N.panel_open + +/datum/wires/nuclearbomb/GetInteractWindow() + var/obj/machinery/nuclearbomb/N = holder + . += ..() + . += "
    The device is [N.timing ? "shaking!" : "still."]
    " + . += "The device is is [N.safety ? "quiet" : "whirring"].
    " + . += "The lights are [N.lighthack ? "static" : "functional"].
    " + +/datum/wires/nuclearbomb/UpdatePulsed(var/index) + var/obj/machinery/nuclearbomb/N = holder + switch(index) + if(NUCLEARBOMB_WIRE_LIGHT) + N.lighthack = !N.lighthack + N.update_icon() + spawn(100) + N.lighthack = !N.lighthack + N.update_icon() + if(NUCLEARBOMB_WIRE_TIMING) + if(N.timing) + spawn + log_and_message_admins("pulsed a nuclear bomb's detonation wire, causing it to explode.") + N.explode() + if(NUCLEARBOMB_WIRE_SAFETY) + N.safety = !N.safety + spawn(100) + N.safety = !N.safety + if(N.safety == 1) + N.visible_message("\The [N] quiets down.") + N.secure_device() + else + N.visible_message("\The [N] emits a quiet whirling noise!") + +/datum/wires/nuclearbomb/UpdateCut(var/index, var/mended) + var/obj/machinery/nuclearbomb/N = holder + switch(index) + if(NUCLEARBOMB_WIRE_SAFETY) + N.safety = mended + if(N.timing) + spawn + log_and_message_admins("cut a nuclear bomb's timing wire, causing it to explode.") + N.explode() + if(NUCLEARBOMB_WIRE_TIMING) + N.secure_device() + if(NUCLEARBOMB_WIRE_LIGHT) + N.lighthack = !mended + N.update_icon() diff --git a/code/datums/wires/particle_accelerator.dm b/code/datums/wires/particle_accelerator.dm new file mode 100644 index 00000000..83562386 --- /dev/null +++ b/code/datums/wires/particle_accelerator.dm @@ -0,0 +1,52 @@ +/datum/wires/particle_acc/control_box + wire_count = 5 + holder_type = /obj/machinery/particle_accelerator/control_box + +var/const/PARTICLE_TOGGLE_WIRE = 1 // Toggles whether the PA is on or not. +var/const/PARTICLE_STRENGTH_WIRE = 2 // Determines the strength of the PA. +var/const/PARTICLE_INTERFACE_WIRE = 4 // Determines the interface showing up. +var/const/PARTICLE_LIMIT_POWER_WIRE = 8 // Determines how strong the PA can be. +//var/const/PARTICLE_NOTHING_WIRE = 16 // Blank wire + +/datum/wires/particle_acc/control_box/CanUse(var/mob/living/L) + var/obj/machinery/particle_accelerator/control_box/C = holder + if(C.construction_state == 2) + return 1 + return 0 + +/datum/wires/particle_acc/control_box/UpdatePulsed(var/index) + var/obj/machinery/particle_accelerator/control_box/C = holder + switch(index) + + if(PARTICLE_TOGGLE_WIRE) + C.toggle_power() + + if(PARTICLE_STRENGTH_WIRE) + C.add_strength() + + if(PARTICLE_INTERFACE_WIRE) + C.interface_control = !C.interface_control + + if(PARTICLE_LIMIT_POWER_WIRE) + C.visible_message("\icon[C][C] makes a large whirring noise.") + +/datum/wires/particle_acc/control_box/UpdateCut(var/index, var/mended) + var/obj/machinery/particle_accelerator/control_box/C = holder + switch(index) + + if(PARTICLE_TOGGLE_WIRE) + if(C.active == !mended) + C.toggle_power() + + if(PARTICLE_STRENGTH_WIRE) + + for(var/i = 1; i < 3; i++) + C.remove_strength() + + if(PARTICLE_INTERFACE_WIRE) + C.interface_control = mended + + if(PARTICLE_LIMIT_POWER_WIRE) + C.strength_upper_limit = (mended ? 2 : 3) + if(C.strength_upper_limit < C.strength) + C.remove_strength() diff --git a/code/datums/wires/radio.dm b/code/datums/wires/radio.dm new file mode 100644 index 00000000..dcd708c5 --- /dev/null +++ b/code/datums/wires/radio.dm @@ -0,0 +1,41 @@ +/datum/wires/radio + holder_type = /obj/item/device/radio + wire_count = 3 + +var/const/WIRE_SIGNAL = 1 +var/const/WIRE_RECEIVE = 2 +var/const/WIRE_TRANSMIT = 4 + +/datum/wires/radio/CanUse(var/mob/living/L) + var/obj/item/device/radio/R = holder + if(R.b_stat) + return 1 + return 0 + +/datum/wires/radio/UpdatePulsed(var/index) + var/obj/item/device/radio/R = holder + switch(index) + if(WIRE_SIGNAL) + R.listening = !R.listening && !IsIndexCut(WIRE_RECEIVE) + R.broadcasting = R.listening && !IsIndexCut(WIRE_TRANSMIT) + + if(WIRE_RECEIVE) + R.listening = !R.listening && !IsIndexCut(WIRE_SIGNAL) + + if(WIRE_TRANSMIT) + R.broadcasting = !R.broadcasting && !IsIndexCut(WIRE_SIGNAL) + GLOB.nanomanager.update_uis(holder) + +/datum/wires/radio/UpdateCut(var/index, var/mended) + var/obj/item/device/radio/R = holder + switch(index) + if(WIRE_SIGNAL) + R.listening = mended && !IsIndexCut(WIRE_RECEIVE) + R.broadcasting = mended && !IsIndexCut(WIRE_TRANSMIT) + + if(WIRE_RECEIVE) + R.listening = mended && !IsIndexCut(WIRE_SIGNAL) + + if(WIRE_TRANSMIT) + R.broadcasting = mended && !IsIndexCut(WIRE_SIGNAL) + GLOB.nanomanager.update_uis(holder) diff --git a/code/datums/wires/robot.dm b/code/datums/wires/robot.dm new file mode 100644 index 00000000..d7ec4a88 --- /dev/null +++ b/code/datums/wires/robot.dm @@ -0,0 +1,77 @@ +/datum/wires/robot + random = 1 + holder_type = /mob/living/silicon/robot + wire_count = 5 + +var/const/BORG_WIRE_LAWCHECK = 1 +var/const/BORG_WIRE_MAIN_POWER = 2 // The power wires do nothing whyyyyyyyyyyyyy +var/const/BORG_WIRE_LOCKED_DOWN = 4 +var/const/BORG_WIRE_AI_CONTROL = 8 +var/const/BORG_WIRE_CAMERA = 16 + +/datum/wires/robot/GetInteractWindow() + + . = ..() + var/mob/living/silicon/robot/R = holder + . += text("
    \n[(R.lawupdate ? "The LawSync light is on." : "The LawSync light is off.")]") + . += text("
    \n[(R.connected_ai ? "The AI link light is on." : "The AI link light is off.")]") + . += text("
    \n[((!isnull(R.camera) && R.camera.status == 1) ? "The Camera light is on." : "The Camera light is off.")]") + . += text("
    \n[(R.lockcharge ? "The lockdown light is on." : "The lockdown light is off.")]") + return . + +/datum/wires/robot/UpdateCut(var/index, var/mended) + + var/mob/living/silicon/robot/R = holder + switch(index) + if(BORG_WIRE_LAWCHECK) //Cut the law wire, and the borg will no longer receive law updates from its AI + if(!mended) + if (R.lawupdate == 1) + to_chat(R, "LawSync protocol engaged.") + R.show_laws() + else + if (R.lawupdate == 0 && !R.emagged) + R.lawupdate = 1 + + if (BORG_WIRE_AI_CONTROL) //Cut the AI wire to reset AI control + if(!mended) + R.disconnect_from_ai() + + if (BORG_WIRE_CAMERA) + if(!isnull(R.camera) && !R.scrambledcodes) + R.camera.status = mended + + if(BORG_WIRE_LAWCHECK) //Forces a law update if the borg is set to receive them. Since an update would happen when the borg checks its laws anyway, not much use, but eh + if (R.lawupdate) + R.lawsync() + + if(BORG_WIRE_LOCKED_DOWN) + R.SetLockdown(!mended) + + +/datum/wires/robot/UpdatePulsed(var/index) + var/mob/living/silicon/robot/R = holder + switch(index) + if (BORG_WIRE_AI_CONTROL) //pulse the AI wire to make the borg reselect an AI + if(!R.emagged) + var/mob/living/silicon/ai/new_ai = select_active_ai(R) + R.connect_to_ai(new_ai) + + if (BORG_WIRE_CAMERA) + if(!isnull(R.camera) && R.camera.can_use() && !R.scrambledcodes) + R.visible_message("[R]'s camera lense focuses loudly.") + to_chat(R, "Your camera lense focuses loudly.") + + if(BORG_WIRE_LOCKED_DOWN) + R.SetLockdown(!R.lockcharge) // Toggle + +/datum/wires/robot/CanUse(var/mob/living/L) + var/mob/living/silicon/robot/R = holder + if(R.wiresexposed) + return 1 + return 0 + +/datum/wires/robot/proc/IsCameraCut() + return wires_status & BORG_WIRE_CAMERA + +/datum/wires/robot/proc/LockedCut() + return wires_status & BORG_WIRE_LOCKED_DOWN diff --git a/code/datums/wires/shield_generator.dm b/code/datums/wires/shield_generator.dm new file mode 100644 index 00000000..a7e53d9a --- /dev/null +++ b/code/datums/wires/shield_generator.dm @@ -0,0 +1,46 @@ +/datum/wires/shield_generator + holder_type = /obj/machinery/power/shield_generator/ + wire_count = 5 + +var/const/SHIELDGEN_WIRE_POWER = 1 // Cut to disable power input into the generator. Pulse does nothing. Mend to restore. +var/const/SHIELDGEN_WIRE_HACK = 2 // Pulse to hack the generator, enabling hacked modes. Cut to unhack. Mend does nothing. +var/const/SHIELDGEN_WIRE_CONTROL = 4 // Cut to lock most shield controls. Mend to unlock them. Pulse does nothing. +var/const/SHIELDGEN_WIRE_AICONTROL = 8 // Cut to disable AI control. Mend to restore. +var/const/SHIELDGEN_WIRE_NOTHING = 16 // A blank wire that doesn't have any specific function + +/datum/wires/shield_generator/CanUse() + var/obj/machinery/power/shield_generator/S = holder + if(S.panel_open) + return 1 + return 0 + +/datum/wires/shield_generator/UpdateCut(index, mended) + var/obj/machinery/power/shield_generator/S = holder + switch(index) + if(SHIELDGEN_WIRE_POWER) + S.input_cut = !mended + if(SHIELDGEN_WIRE_HACK) + if(!mended) + S.hacked = 0 + if(S.check_flag(MODEFLAG_BYPASS)) + S.toggle_flag(MODEFLAG_BYPASS) + if(S.check_flag(MODEFLAG_OVERCHARGE)) + S.toggle_flag(MODEFLAG_OVERCHARGE) + if(SHIELDGEN_WIRE_CONTROL) + S.mode_changes_locked = !mended + if(SHIELDGEN_WIRE_AICONTROL) + S.ai_control_disabled = !mended + +/datum/wires/shield_generator/UpdatePulsed(var/index) + var/obj/machinery/power/shield_generator/S = holder + switch(index) + if(SHIELDGEN_WIRE_HACK) + S.hacked = 1 + +/datum/wires/shield_generator/GetInteractWindow() + var/obj/machinery/power/shield_generator/S = holder + . += ..() + . += "
    A red light labeled \"Safety Override\" is [S.hacked ? "blinking" : "off"]." + . += "
    A green light labeled \"Power Connection\" is [S.input_cut ? "off" : "on"]." + . += "
    A blue light labeled \"Network Control\" is [S.ai_control_disabled ? "off" : "on"]." + . += "
    A yellow light labeled \"Interface Connection\" is [S.mode_changes_locked ? "off" : "on"].
    " \ No newline at end of file diff --git a/code/datums/wires/smartfridge.dm b/code/datums/wires/smartfridge.dm new file mode 100644 index 00000000..b611497e --- /dev/null +++ b/code/datums/wires/smartfridge.dm @@ -0,0 +1,51 @@ +/datum/wires/smartfridge + holder_type = /obj/machinery/smartfridge + wire_count = 3 + +/datum/wires/smartfridge/secure + random = 1 + wire_count = 4 + +var/const/SMARTFRIDGE_WIRE_ELECTRIFY = 1 +var/const/SMARTFRIDGE_WIRE_THROW = 2 +var/const/SMARTFRIDGE_WIRE_IDSCAN = 4 + +/datum/wires/smartfridge/CanUse(var/mob/living/L) + var/obj/machinery/smartfridge/S = holder + if(!istype(L, /mob/living/silicon)) + if(S.seconds_electrified) + if(S.shock(L, 100)) + return 0 + if(S.panel_open) + return 1 + return 0 + +/datum/wires/smartfridge/GetInteractWindow() + var/obj/machinery/smartfridge/S = holder + . += ..() + . += "
    The orange light is [S.seconds_electrified ? "off" : "on"].
    " + . += "The red light is [S.shoot_inventory ? "off" : "blinking"].
    " + . += "A [S.scan_id ? "purple" : "yellow"] light is on.
    " + +/datum/wires/smartfridge/UpdatePulsed(var/index) + var/obj/machinery/smartfridge/S = holder + switch(index) + if(SMARTFRIDGE_WIRE_THROW) + S.shoot_inventory = !S.shoot_inventory + if(SMARTFRIDGE_WIRE_ELECTRIFY) + S.seconds_electrified = 30 + if(SMARTFRIDGE_WIRE_IDSCAN) + S.scan_id = !S.scan_id + +/datum/wires/smartfridge/UpdateCut(var/index, var/mended) + var/obj/machinery/smartfridge/S = holder + switch(index) + if(SMARTFRIDGE_WIRE_THROW) + S.shoot_inventory = !mended + if(SMARTFRIDGE_WIRE_ELECTRIFY) + if(mended) + S.seconds_electrified = 0 + else + S.seconds_electrified = -1 + if(SMARTFRIDGE_WIRE_IDSCAN) + S.scan_id = 1 diff --git a/code/datums/wires/smes.dm b/code/datums/wires/smes.dm new file mode 100644 index 00000000..70cda192 --- /dev/null +++ b/code/datums/wires/smes.dm @@ -0,0 +1,60 @@ +/datum/wires/smes + holder_type = /obj/machinery/power/smes/buildable + wire_count = 5 + +var/const/SMES_WIRE_RCON = 1 // Remote control (AI and consoles), cut to disable +var/const/SMES_WIRE_INPUT = 2 // Input wire, cut to disable input, pulse to disable for 60s +var/const/SMES_WIRE_OUTPUT = 4 // Output wire, cut to disable output, pulse to disable for 60s +var/const/SMES_WIRE_GROUNDING = 8 // Cut to quickly discharge causing sparks, pulse to only create few sparks +var/const/SMES_WIRE_FAILSAFES = 16 // Cut to disable failsafes, mend to reenable + + +/datum/wires/smes/CanUse(var/mob/living/L) + var/obj/machinery/power/smes/buildable/S = holder + if(S.panel_open) + return 1 + return 0 + + +/datum/wires/smes/GetInteractWindow() + var/obj/machinery/power/smes/buildable/S = holder + . += ..() + . += "The green light is [(S.input_cut || S.input_pulsed || S.output_cut || S.output_pulsed) ? "off" : "on"]
    " + . += "The red light is [(S.safeties_enabled || S.grounding) ? "off" : "blinking"]
    " + . += "The blue light is [S.RCon ? "on" : "off"]" + + +/datum/wires/smes/UpdateCut(var/index, var/mended) + var/obj/machinery/power/smes/buildable/S = holder + switch(index) + if(SMES_WIRE_RCON) + S.RCon = mended + if(SMES_WIRE_INPUT) + S.input_cut = !mended + if(SMES_WIRE_OUTPUT) + S.output_cut = !mended + if(SMES_WIRE_GROUNDING) + S.grounding = mended + if(SMES_WIRE_FAILSAFES) + S.safeties_enabled = mended + + +/datum/wires/smes/UpdatePulsed(var/index) + var/obj/machinery/power/smes/buildable/S = holder + switch(index) + if(SMES_WIRE_RCON) + if(S.RCon) + S.RCon = 0 + spawn(10) + S.RCon = 1 + if(SMES_WIRE_INPUT) + S.toggle_input() + if(SMES_WIRE_OUTPUT) + S.toggle_output() + if(SMES_WIRE_GROUNDING) + S.grounding = 0 + if(SMES_WIRE_FAILSAFES) + if(S.safeties_enabled) + S.safeties_enabled = 0 + spawn(10) + S.safeties_enabled = 1 \ No newline at end of file diff --git a/code/datums/wires/suit_storage_unit.dm b/code/datums/wires/suit_storage_unit.dm new file mode 100644 index 00000000..c2d1a130 --- /dev/null +++ b/code/datums/wires/suit_storage_unit.dm @@ -0,0 +1,47 @@ +/datum/wires/suit_storage_unit + holder_type = /obj/machinery/suit_cycler + wire_count = 3 + +var/const/SUIT_STORAGE_WIRE_ELECTRIFY = 1 +var/const/SUIT_STORAGE_WIRE_SAFETY = 2 +var/const/SUIT_STORAGE_WIRE_LOCKED = 4 + +/datum/wires/suit_storage_unit/CanUse(var/mob/living/L) + var/obj/machinery/suit_cycler/S = holder + if(!istype(L, /mob/living/silicon)) + if(S.electrified) + if(S.shock(L, 100)) + return 0 + if(S.panel_open) + return 1 + return 0 + +/datum/wires/suit_storage_unit/GetInteractWindow() + var/obj/machinery/suit_cycler/S = holder + . += ..() + . += "
    The orange light is [S.electrified ? "off" : "on"].
    " + . += "The red light is [S.safeties ? "off" : "blinking"].
    " + . += "The yellow light is [S.locked ? "on" : "off"].
    " + +/datum/wires/suit_storage_unit/UpdatePulsed(var/index) + var/obj/machinery/suit_cycler/S = holder + switch(index) + if(SUIT_STORAGE_WIRE_SAFETY) + S.safeties = !S.safeties + if(SUIT_STORAGE_WIRE_ELECTRIFY) + S.electrified = 30 + if(SUIT_STORAGE_WIRE_LOCKED) + S.locked = !S.locked + +/datum/wires/suit_storage_unit/UpdateCut(var/index, var/mended) + var/obj/machinery/suit_cycler/S = holder + switch(index) + if(SUIT_STORAGE_WIRE_SAFETY) + S.safeties = mended + if(SUIT_STORAGE_WIRE_LOCKED) + S.locked = mended + if(SUIT_STORAGE_WIRE_ELECTRIFY) + if(mended) + S.electrified = 0 + else + S.electrified = -1 diff --git a/code/datums/wires/vending.dm b/code/datums/wires/vending.dm new file mode 100644 index 00000000..575e9c7d --- /dev/null +++ b/code/datums/wires/vending.dm @@ -0,0 +1,53 @@ +/datum/wires/vending + holder_type = /obj/machinery/vending + wire_count = 4 + +var/const/VENDING_WIRE_THROW = 1 +var/const/VENDING_WIRE_CONTRABAND = 2 +var/const/VENDING_WIRE_ELECTRIFY = 4 +var/const/VENDING_WIRE_IDSCAN = 8 + +/datum/wires/vending/CanUse(var/mob/living/L) + var/obj/machinery/vending/V = holder + if(!istype(L, /mob/living/silicon)) + if(V.seconds_electrified) + if(V.shock(L, 100)) + return 0 + if(V.panel_open) + return 1 + return 0 + +/datum/wires/vending/GetInteractWindow() + var/obj/machinery/vending/V = holder + . += ..() + . += "
    The orange light is [V.seconds_electrified ? "off" : "on"].
    " + . += "The red light is [V.shoot_inventory ? "off" : "blinking"].
    " + . += "The green light is [(V.categories & VENDING_CATEGORY_HIDDEN) ? "on" : "off"].
    " + . += "The [V.scan_id ? "purple" : "yellow"] light is on.
    " + +/datum/wires/vending/UpdatePulsed(var/index) + var/obj/machinery/vending/V = holder + switch(index) + if(VENDING_WIRE_THROW) + V.shoot_inventory = !V.shoot_inventory + if(VENDING_WIRE_CONTRABAND) + V.categories ^= VENDING_CATEGORY_HIDDEN + if(VENDING_WIRE_ELECTRIFY) + V.seconds_electrified = 30 + if(VENDING_WIRE_IDSCAN) + V.scan_id = !V.scan_id + +/datum/wires/vending/UpdateCut(var/index, var/mended) + var/obj/machinery/vending/V = holder + switch(index) + if(VENDING_WIRE_THROW) + V.shoot_inventory = !mended + if(VENDING_WIRE_CONTRABAND) + V.categories &= ~VENDING_CATEGORY_HIDDEN + if(VENDING_WIRE_ELECTRIFY) + if(mended) + V.seconds_electrified = 0 + else + V.seconds_electrified = -1 + if(VENDING_WIRE_IDSCAN) + V.scan_id = 1 diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm new file mode 100644 index 00000000..cdff82b1 --- /dev/null +++ b/code/datums/wires/wires.dm @@ -0,0 +1,311 @@ +// Wire datums. Created by Giacomand. +// Was created to replace a horrible case of copy and pasted code with no care for maintability. +// Goodbye Door wires, Cyborg wires, Vending Machine wires, Autolathe wires +// Protolathe wires, APC wires and Camera wires! + +#define MAX_FLAG 65535 + +var/list/same_wires = list() +// 14 colours, if you're adding more than 14 wires then add more colours here +var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown", "gold", "gray", "cyan", "navy", "purple", "pink", "black", "yellow") + +/datum/wires + + var/random = 0 // Will the wires be different for every single instance. + var/atom/holder = null // The holder + var/holder_type = null // The holder type; used to make sure that the holder is the correct type. + var/wire_count = 0 // Max is 16 + var/wires_status = 0 // BITFLAG OF WIRES + + var/list/wires = list() + var/list/signallers = list() + + var/table_options = " align='center'" + var/row_options1 = " width='80px'" + var/row_options2 = " width='260px'" + var/window_x = 370 + var/window_y = 470 + +/datum/wires/New(var/atom/holder) + ..() + src.holder = holder + if(!istype(holder, holder_type)) + CRASH("Our holder is null/the wrong type!") + return + + // Generate new wires + if(random) + GenerateWires() + // Get the same wires + else + // We don't have any wires to copy yet, generate some and then copy it. + if(!same_wires[holder_type]) + GenerateWires() + same_wires[holder_type] = src.wires.Copy() + else + var/list/wires = same_wires[holder_type] + src.wires = wires // Reference the wires list. + +/datum/wires/Destroy() + holder = null + return ..() + +/datum/wires/proc/GenerateWires() + var/list/colours_to_pick = wireColours.Copy() // Get a copy, not a reference. + var/list/indexes_to_pick = list() + //Generate our indexes + for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i) + indexes_to_pick += i + colours_to_pick.len = wire_count // Downsize it to our specifications. + + while(colours_to_pick.len && indexes_to_pick.len) + // Pick and remove a colour + var/colour = pick_n_take(colours_to_pick) + + // Pick and remove an index + var/index = pick_n_take(indexes_to_pick) + + src.wires[colour] = index + //wires = shuffle(wires) + + +/datum/wires/proc/Interact(var/mob/living/user) + + var/html = null + if(holder && CanUse(user)) + html = GetInteractWindow() + if(html) + user.set_machine(holder) + else + user.unset_machine() + // No content means no window. + user << browse(null, "window=wires") + return + + var/datum/browser/popup = new(user, "wires", holder.name, window_x, window_y) + popup.set_content(html) + popup.set_title_image(user.browse_rsc_icon(holder.icon, holder.icon_state)) + popup.open() + +/datum/wires/proc/GetInteractWindow() + var/html = "
    " + html += "

    Exposed Wires

    " + html += "" + + for(var/colour in wires) + html += "" + html += "[capitalize(colour)]" + html += "" + html += "[IsColourCut(colour) ? "Mend" : "Cut"]" + html += " Pulse" + html += " [IsAttached(colour) ? "Detach" : "Attach"] Signaller" + html += "" + html += "
    " + + if (random) + html += "\The [holder] appears to have tamper-resistant electronics installed.

    " //maybe this could be more generic? + + return html + +/datum/wires/Topic(href, href_list) + ..() + if(in_range(holder, usr) && isliving(usr)) + + var/mob/living/L = usr + if(CanUse(L) && href_list["action"]) + var/obj/item/I = L.get_active_hand() + holder.add_hiddenprint(L) + if(href_list["cut"]) // Toggles the cut/mend status + if(isWirecutter(I)) + var/colour = href_list["cut"] + CutWireColour(colour) + else + to_chat(L, "You need wirecutters!") + else if(href_list["pulse"]) + if(isMultitool(I)) + var/colour = href_list["pulse"] + PulseColour(colour) + else + to_chat(L, "You need a multitool!") + else if(href_list["attach"]) + var/colour = href_list["attach"] + // Detach + if(IsAttached(colour)) + var/obj/item/O = Detach(colour) + if(O) + L.put_in_hands(O) + + // Attach + else + if(istype(I, /obj/item/device/assembly/signaler)) + L.drop_item() + Attach(colour, I) + else + to_chat(L, "You need a remote signaller!") + + + + // Update Window + Interact(usr) + + if(href_list["close"]) + usr << browse(null, "window=wires") + usr.unset_machine(holder) + +// +// Overridable Procs +// + +// Called when wires cut/mended. +/datum/wires/proc/UpdateCut(var/index, var/mended) + return + +// Called when wire pulsed. Add code here. +/datum/wires/proc/UpdatePulsed(var/index) + return + +/datum/wires/proc/CanUse(var/mob/living/L) + return 1 + +// Example of use: +/* + +var/const/BOLTED= 1 +var/const/SHOCKED = 2 +var/const/SAFETY = 4 +var/const/POWER = 8 + +/datum/wires/door/UpdateCut(var/index, var/mended) + var/obj/machinery/door/airlock/A = holder + switch(index) + if(BOLTED) + if(!mended) + A.bolt() + if(SHOCKED) + A.shock() + if(SAFETY ) + A.safety() + +*/ + + +// +// Helper Procs +// + +/datum/wires/proc/PulseColour(var/colour) + PulseIndex(GetIndex(colour)) + +/datum/wires/proc/PulseIndex(var/index) + if(IsIndexCut(index)) + return + UpdatePulsed(index) + +/datum/wires/proc/GetIndex(var/colour) + if(wires[colour]) + var/index = wires[colour] + return index + else + CRASH("[colour] is not a key in wires.") + + +/datum/wires/proc/RandomPulse() + var/index = rand(1, wires.len) + PulseIndex(index) + +// +// Is Index/Colour Cut procs +// + +/datum/wires/proc/IsColourCut(var/colour) + var/index = GetIndex(colour) + return IsIndexCut(index) + +/datum/wires/proc/IsIndexCut(var/index) + return (index & wires_status) + +// +// Signaller Procs +// + +/datum/wires/proc/IsAttached(var/colour) + if(signallers[colour]) + return 1 + return 0 + +/datum/wires/proc/GetAttached(var/colour) + if(signallers[colour]) + return signallers[colour] + return null + +/datum/wires/proc/Attach(var/colour, var/obj/item/device/assembly/signaler/S) + if(colour && S) + if(!IsAttached(colour)) + signallers[colour] = S + S.forceMove(holder) + S.connected = src + return S + +/datum/wires/proc/Detach(var/colour) + if(colour) + var/obj/item/device/assembly/signaler/S = GetAttached(colour) + if(S) + signallers -= colour + S.connected = null + S.dropInto(holder.loc) + return S + + +/datum/wires/proc/Pulse(var/obj/item/device/assembly/signaler/S) + + for(var/colour in signallers) + if(S == signallers[colour]) + PulseColour(colour) + break + +// +// Cut Wire Colour/Index procs +// + +/datum/wires/proc/CutWireColour(var/colour) + var/index = GetIndex(colour) + CutWireIndex(index) + +/datum/wires/proc/CutWireIndex(var/index) + if(IsIndexCut(index)) + wires_status &= ~index + UpdateCut(index, 1) + else + wires_status |= index + UpdateCut(index, 0) + +/datum/wires/proc/RandomCut() + var/r = rand(1, wires.len) + CutWireIndex(r) + +/datum/wires/proc/RandomCutAll(var/probability = 10) + for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i) + if(prob(probability)) + CutWireIndex(i) + +/datum/wires/proc/CutAll() + for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i) + CutWireIndex(i) + +/datum/wires/proc/IsAllCut() + if(wires_status == (1 << wire_count) - 1) + return 1 + return 0 + +/datum/wires/proc/MendAll() + for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i) + if(IsIndexCut(i)) + CutWireIndex(i) + +// +//Shuffle and Mend +// + +/datum/wires/proc/Shuffle() + wires_status = 0 + GenerateWires() diff --git a/code/game/antagonist/_antagonist_setup.dm b/code/game/antagonist/_antagonist_setup.dm new file mode 100644 index 00000000..76b2d71d --- /dev/null +++ b/code/game/antagonist/_antagonist_setup.dm @@ -0,0 +1,91 @@ +/* + MODULAR ANTAGONIST SYSTEM + + Attempts to move all the bullshit snowflake antag tracking code into its own system, which + has the added bonus of making the display procs consistent. Still needs work/adjustment/cleanup + but should be fairly self-explanatory with a review of the procs. Will supply a few examples + of common tasks that the system will be expected to perform below. ~Z + + To use: + - Get the appropriate datum via get_antag_data("antagonist id") + using the id var of the desired /datum/antagonist ie. var/datum/antagonist/A = get_antag_data("traitor") + - Call add_antagonist() on the desired target mind ie. A.add_antagonist(mob.mind) + - To ignore protected roles, supply a positive second argument. + - To skip equipping with appropriate gear, supply a positive third argument. +*/ + +// Global procs. +/proc/get_antag_data(var/antag_type) + if(all_antag_types()[antag_type]) + return all_antag_types()[antag_type] + else + var/list/all_antag_types = all_antag_types() + for(var/cur_antag_type in all_antag_types) + var/datum/antagonist/antag = all_antag_types[cur_antag_type] + if(antag && antag.is_type(antag_type)) + return antag + +/proc/clear_antag_roles(var/datum/mind/player, var/implanted) + var/list/all_antag_types = all_antag_types() + for(var/antag_type in all_antag_types) + var/datum/antagonist/antag = all_antag_types[antag_type] + if(!implanted || !(antag.flags & ANTAG_IMPLANT_IMMUNE)) + antag.remove_antagonist(player, 1, implanted) + +/proc/update_antag_icons(var/datum/mind/player) + var/list/all_antag_types = all_antag_types() + for(var/antag_type in all_antag_types) + var/datum/antagonist/antag = all_antag_types[antag_type] + if(player) + antag.update_icons_removed(player) + if(antag.is_antagonist(player)) + antag.update_icons_added(player) + else + antag.update_all_icons() + +/proc/get_antags(var/atype) + var/datum/antagonist/antag = all_antag_types()[atype] + if(antag && islist(antag.current_antagonists)) + return antag.current_antagonists + return list() + +/proc/player_is_antag(var/datum/mind/player, var/only_offstation_roles = 0) + var/list/all_antag_types = all_antag_types() + for(var/antag_type in all_antag_types) + var/datum/antagonist/antag = all_antag_types[antag_type] + if(only_offstation_roles && !(antag.flags & ANTAG_OVERRIDE_JOB)) + continue + if(player in antag.current_antagonists) + return 1 + if(player in antag.pending_antagonists) + return 1 + return 0 + +var/list/all_antag_types_ +var/list/all_antag_spawnpoints_ +var/list/antag_names_to_ids_ + +/proc/all_antag_types() + populate_antag_type_list() + return all_antag_types_ + +/proc/all_antag_spawnpoints() + populate_antag_type_list() + return all_antag_spawnpoints_ + +/proc/antag_names_to_ids() + populate_antag_type_list() + return antag_names_to_ids_ + +/proc/populate_antag_type_list() + if(all_antag_types_ || all_antag_spawnpoints_ || antag_names_to_ids_) + return + all_antag_types_ = list() + all_antag_spawnpoints_ = list() + antag_names_to_ids_ = list() + + for(var/antag_type in subtypesof(/datum/antagonist)) + var/datum/antagonist/A = new antag_type + all_antag_types_[A.id] = A + all_antag_spawnpoints_[A.landmark_id] = list() + antag_names_to_ids_[A.role_text] = A.id diff --git a/code/game/antagonist/alien/borer.dm b/code/game/antagonist/alien/borer.dm new file mode 100644 index 00000000..dbb92e62 --- /dev/null +++ b/code/game/antagonist/alien/borer.dm @@ -0,0 +1,55 @@ +var/datum/antagonist/xenos/borer/borers + +/datum/antagonist/xenos/borer + id = MODE_BORER + role_text = "Cortical Borer" + role_text_plural = "Cortical Borers" + mob_path = /mob/living/simple_animal/borer + welcome_text = "Use your Infest power to crawl into the ear of a host and fuse with their brain. You can only take control temporarily, and at risk of hurting your host, so be clever and careful; your host is encouraged to help you however they can. Talk to your fellow borers with :x." + antag_indicator = "hudborer" + antaghud_indicator = "hudborer" + + faction_role_text = "Borer Thrall" + faction_descriptor = "Unity" + faction_welcome = "You are now a thrall to a cortical borer. Please listen to what they have to say; they're in your head." + faction = "borer" + + initial_spawn_req = 3 + initial_spawn_target = 5 + +/datum/antagonist/xenos/borer/New() + ..(1) + borers = src + +/datum/antagonist/xenos/borer/get_extra_panel_options(var/datum/mind/player) + return "\[put in host\]" + +/datum/antagonist/xenos/borer/create_objectives(var/datum/mind/player) + if(!..()) + return + player.objectives += new /datum/objective/borer_survive() + player.objectives += new /datum/objective/borer_reproduce() + player.objectives += new /datum/objective/escape() + +/datum/antagonist/xenos/borer/place_mob(var/mob/living/mob) + var/mob/living/simple_animal/borer/borer = mob + if(istype(borer)) + var/mob/living/carbon/human/host + for(var/mob/living/carbon/human/H in SSmobs.mob_list) + if(H.stat != DEAD && !H.has_brain_worms()) + var/obj/item/organ/external/head = H.get_organ(BP_HEAD) + if(head && !(head.robotic >= ORGAN_ROBOT)) + host = H + break + if(istype(host)) + var/obj/item/organ/external/head = host.get_organ(BP_HEAD) + if(head) + borer.host = host + head.implants += borer + borer.forceMove(head) + if(!borer.host_brain) + borer.host_brain = new(borer) + borer.host_brain.SetName(host.name) + borer.host_brain.real_name = host.real_name + return + ..() // Place them at a vent if they can't get a host. diff --git a/code/game/antagonist/alien/xenomorph.dm b/code/game/antagonist/alien/xenomorph.dm new file mode 100644 index 00000000..af58629b --- /dev/null +++ b/code/game/antagonist/alien/xenomorph.dm @@ -0,0 +1,52 @@ +var/datum/antagonist/xenos/xenomorphs + +/datum/antagonist/xenos + id = MODE_XENOMORPH + role_text = "Xenophage" + role_text_plural = "Xenophages" + mob_path = /mob/living/carbon/alien/larva + flags = ANTAG_OVERRIDE_MOB | ANTAG_RANDSPAWN | ANTAG_OVERRIDE_JOB + welcome_text = "Hiss! You are a larval alien. Hide and bide your time until you are ready to evolve." + antaghud_indicator = "hudalien" + antag_indicator = "hudalien" + faction_role_text = "Xenophage 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." + faction = "xenophage" + faction_indicator = "hudalien" + + hard_cap = 5 + hard_cap_round = 8 + initial_spawn_req = 4 + initial_spawn_target = 6 + + spawn_announcement_title = "Lifesign Alert" + spawn_announcement_delay = 5000 + +/datum/antagonist/xenos/New(var/no_reference) + spawn_announcement = replacetext(GLOB.using_map.unidentified_lifesigns_message, "%STATION_NAME%", station_name()) + spawn_announcement_sound = GLOB.using_map.xenomorph_spawn_sound + ..() + if(!no_reference) + xenomorphs = src + +/datum/antagonist/xenos/attempt_random_spawn() + if(config.aliens_allowed) ..() + +/datum/antagonist/xenos/proc/get_vents() + var/list/vents = list() + for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in SSmachines.machinery) + if(!temp_vent.welded && temp_vent.network && (temp_vent.loc.z in GLOB.using_map.station_levels)) + if(temp_vent.network.normal_members.len > 50) + vents += temp_vent + return vents + +/datum/antagonist/xenos/create_objectives(var/datum/mind/player) + if(!..()) + return + player.objectives += new /datum/objective/survive() + player.objectives += new /datum/objective/escape() + +/datum/antagonist/xenos/place_mob(var/mob/living/player) + player.forceMove(get_turf(pick(get_vents()))) diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm new file mode 100644 index 00000000..eb039c22 --- /dev/null +++ b/code/game/antagonist/antagonist.dm @@ -0,0 +1,254 @@ +/datum/antagonist + + // Text shown when becoming this antagonist. + var/list/restricted_jobs = list() // Jobs that cannot be this antagonist at roundstart (depending on config) + var/list/protected_jobs = list() // As above. + var/list/blacklisted_jobs = list() // Jobs that can NEVER be this antagonist + + // Strings. + var/welcome_text = "Cry havoc and let slip the dogs of war!" + var/leader_welcome_text // Text shown to the leader, if any. + var/victory_text // World output at roundend for victory. + var/loss_text // As above for loss. + var/victory_feedback_tag // Used by the database for end of round loss. + var/loss_feedback_tag // Used by the database for end of round loss. + + // Role data. + var/id = "traitor" // Unique datum identifier. + var/role_type // Preferences option for this role. Defaults to the id if unset + var/role_text = "Traitor" // special_role text. + var/role_text_plural = "Traitors" // As above but plural. + + // Visual references. + var/antaghud_indicator = "hudsyndicate" // Used by the ghost antagHUD. + var/antag_indicator // icon_state for icons/mob/mob.dm visual indicator. + var/faction_indicator // See antag_indicator, but for factionalized people only. + var/faction_invisible // Can members of the faction identify other antagonists? + + // Faction data. + var/faction_role_text // Role for sub-antags. Mandatory for faction role. + var/faction_descriptor // Description of the cause. Mandatory for faction role. + var/faction_verb // Verb added when becoming a member of the faction, if any. + var/faction_welcome // Message shown to faction members. + var/faction = "neutral" // Actual faction name. Used primarily in stuff like simple_animals seeing if you are a threat or not. + + // Spawn values (autotraitor and game mode) + var/hard_cap = 3 // Autotraitor var. Won't spawn more than this many antags. + var/hard_cap_round = 5 // As above but 'core' round antags ie. roundstart. + var/initial_spawn_req = 1 // Gamemode using this template won't start without this # candidates. + var/initial_spawn_target = 3 // Gamemode will attempt to spawn this many antags. + var/announced // Has an announcement been sent? + var/spawn_announcement // When the datum spawn proc is called, does it announce to the world? (ie. xenos) + var/spawn_announcement_title // Report title. + var/spawn_announcement_sound // Report sound clip. + var/spawn_announcement_delay // Time between initial spawn and round announcement. + var/gag_announcement = TRUE // Whether or not the antag is announced. + + // Misc. + var/landmark_id // Spawn point identifier. + var/mob_path = /mob/living/carbon/human // Mobtype this antag will use if none is provided. + var/feedback_tag = "traitor_objective" // End of round + var/minimum_player_age = 7 // Players need to be at least minimum_player_age days old before they are eligable for auto-spawning + var/suspicion_chance = 50 // Prob of being on the initial Command report + var/flags = 0 // Various runtime options. + var/show_objectives_on_creation = 1 // Whether or not objectives are shown when a player is added to this antag datum + + // Used for setting appearance. + var/list/valid_species = list(SPECIES_UNATHI,SPECIES_TAJARA,SPECIES_SKRELL,SPECIES_HUMAN,SPECIES_VOX) + var/min_player_age = 14 + + // Runtime vars. + var/datum/mind/leader // Current leader, if any. + var/cur_max = 0 // Autotraitor current effective maximum. + var/spawned_nuke // Has a bomb been spawned? + var/nuke_spawn_loc // If so, where should it be placed? + var/list/current_antagonists = list() // All marked antagonists for this type. + var/list/pending_antagonists = list() // Candidates that are awaiting finalized antag status. + var/list/starting_locations = list() // Spawn points. + var/list/global_objectives = list() // Universal objectives if any. + var/list/candidates = list() // Potential candidates. + var/list/faction_members = list() // Semi-antags (in-round revs, borer thralls) + + // ID card stuff. + var/default_access = list() + var/id_type = /obj/item/weapon/card/id + + var/antag_text = "You are an antagonist! Within the rules, \ + try to act as an opposing force to the crew. Further RP and try to make sure \ + other players have fun! If you are confused or at a loss, always adminhelp, \ + and before taking extreme actions, please try to also contact the administration! \ + Think through your actions and make the roleplay immersive! Please remember all \ + rules aside from those without explicit exceptions apply to antagonists." + + +/datum/antagonist/New() + ..() + if(!role_type) + role_type = id + + cur_max = hard_cap + get_starting_locations() + if(!role_text_plural) + role_text_plural = role_text + if(config.protect_roles_from_antagonist) + restricted_jobs |= protected_jobs + if(antaghud_indicator) + if(!GLOB.hud_icon_reference) + GLOB.hud_icon_reference = list() + if(role_text) GLOB.hud_icon_reference[role_text] = antaghud_indicator + if(faction_role_text) GLOB.hud_icon_reference[faction_role_text] = antaghud_indicator + +/datum/antagonist/proc/tick() + return 1 + +// Get the raw list of potential players. +/datum/antagonist/proc/build_candidate_list(var/ghosts_only) + candidates = list() // Clear. + + // Prune restricted status. Broke it up for readability. + // Note that this is done before jobs are handed out. + for(var/datum/mind/player in ticker.mode.get_players_for_role(role_type, id)) + if(ghosts_only && !(isghostmind(player) || isnewplayer(player.current))) + log_debug("[key_name(player)] is not eligible to become a [role_text]: Only ghosts may join as this role!") + else if(config.use_age_restriction_for_antags && player.current.client.player_age < minimum_player_age) + log_debug("[key_name(player)] is not eligible to become a [role_text]: Is only [player.current.client.player_age] day\s old, has to be [minimum_player_age] day\s!") + else if(player.special_role) + log_debug("[key_name(player)] is not eligible to become a [role_text]: They already have a special role ([player.special_role])!") + else if (player in pending_antagonists) + log_debug("[key_name(player)] is not eligible to become a [role_text]: They have already been selected for this role!") + else if(!can_become_antag(player)) + log_debug("[key_name(player)] is not eligible to become a [role_text]: They are blacklisted for this role!") + else if(player_is_antag(player)) + log_debug("[key_name(player)] is not eligible to become a [role_text]: They are already an antagonist!") + else + candidates |= player + + return candidates + +// Builds a list of potential antags without actually setting them. Used to test mode viability. +/datum/antagonist/proc/get_potential_candidates(var/datum/game_mode/mode, var/ghosts_only) + var/candidates = list() + + // Keeping broken up for readability + for(var/datum/mind/player in mode.get_players_for_role(role_type, id)) + if(ghosts_only && !(isghostmind(player) || isnewplayer(player.current))) + else if(config.use_age_restriction_for_antags && player.current.client.player_age < minimum_player_age) + else if(player.special_role) + else if (player in pending_antagonists) + else if(!can_become_antag(player)) + else if(player_is_antag(player)) + else + candidates |= player + + 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() + 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.") + 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() + + return 1 + +//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 + + // Update our boundaries. + if(!candidates.len) + return 0 + + //Grab candidates randomly until we have enough. + while(candidates.len && pending_antagonists.len < spawn_target) + var/datum/mind/player = pick(candidates) + candidates -= player + draft_antagonist(player) + + return 1 + +/datum/antagonist/proc/draft_antagonist(var/datum/mind/player) + //Check if the player can join in this antag role, or if the player has already been given an antag role. + if(!can_become_antag(player)) + log_debug("[player.key] was selected for [role_text] by lottery, but is not allowed to be that role.") + return 0 + if(player.special_role) + log_debug("[player.key] was selected for [role_text] by lottery, but they already have a special role.") + return 0 + if(!(flags & ANTAG_OVERRIDE_JOB) && (!player.current || istype(player.current, /mob/new_player))) + log_debug("[player.key] was selected for [role_text] by lottery, but they have not joined the game.") + return 0 + if(ticker.current_state >= GAME_STATE_PLAYING && (isghostmind(player) || isnewplayer(player.current)) && !(player in ticker.antag_pool)) + log_debug("[player.key] was selected for [role_text] by lottery, but they are a ghost not in the antag pool.") + return 0 + + pending_antagonists |= player + log_debug("[player.key] has been selected for [role_text] by lottery.") + + //Ensure that antags with ANTAG_OVERRIDE_JOB do not occupy job slots. + if(flags & ANTAG_OVERRIDE_JOB) + player.assigned_role = role_text + + //Ensure that a player cannot be drafted for multiple antag roles, taking up slots for antag roles that they will not fill. + player.special_role = role_text + + return 1 + +//Spawns all pending_antagonists. This is done separately from attempt_spawn in case the game mode setup fails. +/datum/antagonist/proc/finalize_spawn() + if(!pending_antagonists) + return + + for(var/datum/mind/player in pending_antagonists) + pending_antagonists -= player + add_antagonist(player,0,0,1) + + reset_antag_selection() + +//Procced after /ALL/ antagonists have finished setting up and spawning. +/datum/antagonist/proc/post_spawn() + return + +//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() + 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_add.dm b/code/game/antagonist/antagonist_add.dm new file mode 100644 index 00000000..4cd73734 --- /dev/null +++ b/code/game/antagonist/antagonist_add.dm @@ -0,0 +1,72 @@ +/datum/antagonist/proc/add_antagonist(var/datum/mind/player, var/ignore_role, var/do_not_equip, var/move_to_spawn, var/do_not_announce, var/preserve_appearance) + + if(!add_antagonist_mind(player, ignore_role)) + return + + //do this again, just in case + if(flags & ANTAG_OVERRIDE_JOB) + player.assigned_role = role_text + player.special_role = role_text + + if(isghostmind(player)) + create_default(player.current) + else + create_antagonist(player, move_to_spawn, do_not_announce, preserve_appearance) + if(!do_not_equip) + equip(player.current) + + player.current.faction = faction + return 1 + +/datum/antagonist/proc/add_antagonist_mind(var/datum/mind/player, var/ignore_role, var/nonstandard_role_type, var/nonstandard_role_msg) + if(!istype(player)) + return 0 + if(!player.current) + return 0 + if(player in current_antagonists) + return 0 + if(!can_become_antag(player, ignore_role)) + return 0 + current_antagonists |= player + + if(faction_verb && player.current) + player.current.verbs |= faction_verb + + if(config.objectives_disabled == CONFIG_OBJECTIVE_VERB) + player.current.verbs += /mob/proc/add_objectives + + + spawn(1 SECOND) //Added a delay so that this should pop up at the bottom and not the top of the text flood the new antag gets. + to_chat(player.current, "Once you decide on a goal to pursue, you can optionally display it to \ + everyone at the end of the shift with the Set Ambition verb, located in the IC tab. You can change this at any time, \ + and it otherwise has no bearing on your round.") + player.current.verbs += /mob/living/proc/write_ambition + + // Handle only adding a mind and not bothering with gear etc. + if(nonstandard_role_type) + faction_members |= player + to_chat(player.current, "You are \a [nonstandard_role_type]!") + player.special_role = nonstandard_role_type + if(nonstandard_role_msg) + to_chat(player.current, "[nonstandard_role_msg]") + update_icons_added(player) + return 1 + +/datum/antagonist/proc/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) + if(!istype(player)) + return 0 + if(player.current && faction_verb) + player.current.verbs -= faction_verb + if(player in current_antagonists) + to_chat(player.current, "You are no longer a [role_text]!") + current_antagonists -= player + faction_members -= player + player.special_role = null + update_icons_removed(player) + BITSET(player.current.hud_updateflag, SPECIALROLE_HUD) + + if(!is_special_character(player)) + player.current.verbs -= /mob/living/proc/write_ambition + player.ambitions = "" + return 1 + return 0 diff --git a/code/game/antagonist/antagonist_create.dm b/code/game/antagonist/antagonist_create.dm new file mode 100644 index 00000000..e4b3514f --- /dev/null +++ b/code/game/antagonist/antagonist_create.dm @@ -0,0 +1,124 @@ +/datum/antagonist/proc/create_antagonist(var/datum/mind/target, var/move, var/preserve_appearance) + + if(!target) + return + + update_antag_mob(target, preserve_appearance) + if(!target.current) + remove_antagonist(target) + return 0 + if(flags & ANTAG_CHOOSE_NAME) + spawn(1) + set_antag_name(target.current) + if(move) + place_mob(target.current) + update_leader() + create_objectives(target) + update_icons_added(target) + greet(target) + if(!gag_announcement) + announce_antagonist_spawn() + target.current.unlock_achievement(new/datum/achievement/traitor()) + +/datum/antagonist/proc/create_default(var/mob/source) + var/mob/living/M + if(mob_path) + M = new mob_path(get_turf(source)) + else + M = new /mob/living/carbon/human(get_turf(source)) + M.ckey = source.ckey + add_antagonist(M.mind, 1, 0, 1) // Equip them and move them to spawn. + return M + +/datum/antagonist/proc/create_id(var/assignment, var/mob/living/carbon/human/player, var/equip = 1) + + var/obj/item/weapon/card/id/W = new id_type(player) + if(!W) return + W.access |= default_access + W.assignment = "[assignment]" + player.set_id_info(W) + if(equip) player.equip_to_slot_or_del(W, slot_wear_id) + return W + +/datum/antagonist/proc/create_radio(var/freq, var/mob/living/carbon/human/player) + var/obj/item/device/radio/R + + switch(freq) + if(RED_FREQ) + R = new/obj/item/device/radio/headset/syndicate(player) + if(BLUE_FREQ) + R = new/obj/item/device/radio/headset/raider(player) + else + R = new/obj/item/device/radio/headset(player) + R.set_frequency(freq) + + player.equip_to_slot_or_del(R, slot_l_ear) + return R + +/datum/antagonist/proc/create_nuke(var/atom/paper_spawn_loc, var/datum/mind/code_owner) + + // Decide on a code. + var/obj/effect/landmark/nuke_spawn = locate(nuke_spawn_loc ? nuke_spawn_loc : "landmark*Nuclear-Bomb") + + var/code + if(nuke_spawn) + var/obj/machinery/nuclearbomb/nuke = new(get_turf(nuke_spawn)) + code = "[rand(10000, 99999)]" + nuke.r_code = code + + if(code) + if(!paper_spawn_loc) + if(leader && leader.current) + paper_spawn_loc = get_turf(leader.current) + else + paper_spawn_loc = get_turf(locate("landmark*Nuclear-Code")) + + if(paper_spawn_loc) + // Create and pass on the bomb code paper. + var/obj/item/weapon/paper/P = new(paper_spawn_loc) + P.info = "The nuclear authorization code is: [code]" + P.SetName("nuclear bomb code") + if(leader && leader.current) + if(get_turf(P) == get_turf(leader.current) && !(leader.current.l_hand && leader.current.r_hand)) + leader.current.put_in_hands(P) + + if(!code_owner && leader) + code_owner = leader + if(code_owner) + code_owner.store_memory("Nuclear Bomb Code: [code]", 0, 0) + to_chat(code_owner.current, "The nuclear authorization code is: [code]") + else + message_admins("Could not spawn nuclear bomb. Contact a developer.") + return + + spawned_nuke = code + return code + +/datum/antagonist/proc/greet(var/datum/mind/player) + + // Basic intro text. + to_chat(player.current, "You are a [role_text]!") + if(leader_welcome_text && player == leader) + to_chat(player.current, "[leader_welcome_text]") + else + to_chat(player.current, "[welcome_text]") + if (config.objectives_disabled == CONFIG_OBJECTIVE_NONE || !player.objectives.len) + to_chat(player.current, "[antag_text]") + + if((flags & ANTAG_HAS_NUKE) && !spawned_nuke) + create_nuke() + + src.show_objectives_at_creation(player) + return 1 + +/datum/antagonist/proc/set_antag_name(var/mob/living/player) + // Choose a name, if any. + var/newname = sanitize(input(player, "You are a [role_text]. Would you like to change your name to something else?", "Name change") as null|text, MAX_NAME_LEN) + if (newname) + player.real_name = newname + player.SetName(player.real_name) + if(player.dna) + player.dna.real_name = newname + if(player.mind) player.mind.name = player.name + // Update any ID cards. + update_access(player) diff --git a/code/game/antagonist/antagonist_equip.dm b/code/game/antagonist/antagonist_equip.dm new file mode 100644 index 00000000..9aeb56a2 --- /dev/null +++ b/code/game/antagonist/antagonist_equip.dm @@ -0,0 +1,19 @@ +/datum/antagonist/proc/equip(var/mob/living/carbon/human/player) + + if(!istype(player)) + return 0 + + // This could use work. + if(flags & ANTAG_CLEAR_EQUIPMENT) + for(var/obj/item/thing in player.contents) + player.drop_from_inventory(thing) + if(thing.loc != player) + qdel(thing) + //mainly for vox antag compatibility. Should not effect item spawning. + player.species.equip_survival_gear(player) + return 1 + +/datum/antagonist/proc/unequip(var/mob/living/carbon/human/player) + if(!istype(player)) + return 0 + return 1 \ No newline at end of file diff --git a/code/game/antagonist/antagonist_factions.dm b/code/game/antagonist/antagonist_factions.dm new file mode 100644 index 00000000..ce792eb4 --- /dev/null +++ b/code/game/antagonist/antagonist_factions.dm @@ -0,0 +1,50 @@ +/mob/living/proc/convert_to_rev(mob/M as mob in able_mobs_in_oview(src)) + set name = "Convert Bourgeoise" + set category = "Abilities" + if(!M.mind || !M.client) + return + convert_to_faction(M.mind, revs) + +/mob/living/proc/convert_to_faction(var/datum/mind/player, var/datum/antagonist/faction) + + if(!player || !faction || !player.current) + return + + if(!faction.faction_verb || !faction.faction_descriptor || !faction.faction_verb) + return + + if(faction.is_antagonist(player)) + to_chat(src, "\The [player.current] already serves the [faction.faction_descriptor].") + return + + if(player_is_antag(player)) + to_chat(src, "\The [player.current]'s loyalties seem to be elsewhere...") + return + + if(!faction.can_become_antag(player, 1)) + to_chat(src, "\The [player.current] cannot be \a [faction.faction_role_text]!") + return + + if(world.time < player.rev_cooldown) + to_chat(src, "You must wait five seconds between attempts.") + return + + to_chat(src, "You are attempting to convert \the [player.current]...") + log_admin("[src]([src.ckey]) attempted to convert [player.current] to the [faction.faction_role_text] faction.") + message_admins("[src]([src.ckey]) attempted to convert [player.current] to the [faction.faction_role_text] faction.") + + player.rev_cooldown = world.time+100 + var/choice = alert(player.current,"Asked by [src]: Do you want to join the [faction.faction_descriptor]?","Join the [faction.faction_descriptor]?","No!","Yes!") + if(choice == "Yes!" && faction.add_antagonist_mind(player, 0, faction.faction_role_text, faction.faction_welcome)) + to_chat(src, "\The [player.current] joins the [faction.faction_descriptor]!") + return + if(choice == "No!") + to_chat(player, "You reject this traitorous cause!") + to_chat(src, "\The [player.current] does not support the [faction.faction_descriptor]!") + +/mob/living/proc/convert_to_loyalist(mob/M as mob in able_mobs_in_oview(src)) + set name = "Convert Recidivist" + set category = "Abilities" + if(!M.mind || !M.client) + return + convert_to_faction(M.mind, loyalists) \ No newline at end of file diff --git a/code/game/antagonist/antagonist_helpers.dm b/code/game/antagonist/antagonist_helpers.dm new file mode 100644 index 00000000..101857ea --- /dev/null +++ b/code/game/antagonist/antagonist_helpers.dm @@ -0,0 +1,75 @@ +/datum/antagonist/proc/can_become_antag(var/datum/mind/player, var/ignore_role) + if(player.current && jobban_isbanned(player.current, id)) + return 0 + var/datum/job/J = job_master.GetJob(player.assigned_role) + if(is_type_in_list(J,blacklisted_jobs)) + return 0 + + if(!ignore_role) + if(player.current && player.current.client) + var/client/C = player.current.client + // Limits antag status to clients above player age, if the age system is being used. + if(C && config.use_age_restriction_for_jobs && isnum(C.player_age) && isnum(min_player_age) && (C.player_age < min_player_age)) + return 0 + if(is_type_in_list(J,restricted_jobs)) + return 0 + if(player.current && (player.current.status_flags & NO_ANTAG)) + return 0 + return 1 + +/datum/antagonist/proc/antags_are_dead() + for(var/datum/mind/antag in current_antagonists) + if(mob_path && !istype(antag.current,mob_path)) + continue + if(antag.current.stat==2) + continue + return 0 + return 1 + +/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 + +/datum/antagonist/proc/is_type(var/antag_type) + if(antag_type == id || antag_type == role_text) + return 1 + return 0 + +/datum/antagonist/proc/is_votable() + return (flags & ANTAG_VOTABLE) + +/datum/antagonist/proc/can_late_spawn() + if(!ticker) + return 0 + if(!(id in ticker.mode.latejoin_antag_tags)) + return 0 + 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/all_antag_types = all_antag_types() + 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 diff --git a/code/game/antagonist/antagonist_objectives.dm b/code/game/antagonist/antagonist_objectives.dm new file mode 100644 index 00000000..b9e1b96f --- /dev/null +++ b/code/game/antagonist/antagonist_objectives.dm @@ -0,0 +1,82 @@ +/datum/antagonist/proc/create_global_objectives(var/override=0) + if(config.objectives_disabled != CONFIG_OBJECTIVE_ALL && !override) + return 0 + if(global_objectives && global_objectives.len) + return 0 + return 1 + +/datum/antagonist/proc/create_objectives(var/datum/mind/player, var/override=0) + if(config.objectives_disabled != CONFIG_OBJECTIVE_ALL && !override) + return 0 + if(create_global_objectives(override) || global_objectives.len) + player.objectives |= global_objectives + return 1 + +/datum/antagonist/proc/get_special_objective_text() + return "" + +/datum/antagonist/proc/check_victory() + var/result = 1 + if(config.objectives_disabled == CONFIG_OBJECTIVE_NONE) + return 1 + if(global_objectives && global_objectives.len) + for(var/datum/objective/O in global_objectives) + if(!O.completed && !O.check_completion()) + result = 0 + if(result && victory_text) + to_world("[victory_text]") + if(victory_feedback_tag) feedback_set_details("round_end_result","[victory_feedback_tag]") + else if(loss_text) + to_world("[loss_text]") + if(loss_feedback_tag) feedback_set_details("round_end_result","[loss_feedback_tag]") + + +/mob/proc/add_objectives() + set name = "Get Objectives" + set desc = "Recieve optional objectives." + set category = "OOC" + + src.verbs -= /mob/proc/add_objectives + + if(!src.mind) + return + + var/all_antag_types = all_antag_types() + for(var/tag in all_antag_types) //we do all of them in case an admin adds an antagonist via the PP. Those do not show up in gamemode. + var/datum/antagonist/antagonist = all_antag_types[tag] + if(antagonist && antagonist.is_antagonist(src.mind)) + antagonist.create_objectives(src.mind,1) + + to_chat(src, "These objectives are completely voluntary. You are not required to complete them.") + show_objectives(src.mind) + +/mob/living/proc/write_ambition() + set name = "Set Ambition" + set category = "IC" + set src = usr + + if(!mind) + return + if(!is_special_character(mind)) + to_chat(src, "While you may perhaps have goals, this verb's meant to only be visible \ + to antagonists. Please make a bug report!") + return + var/new_ambitions = input(src, "Write a short sentence of what your character hopes to accomplish \ + today as an antagonist. Remember that this is purely optional. It will be shown at the end of the \ + round for everybody else.", "Ambitions", mind.ambitions) as null|message + if(isnull(new_ambitions)) + return + new_ambitions = sanitize(new_ambitions) + mind.ambitions = new_ambitions + if(new_ambitions) + to_chat(src, "You've set your goal to be '[new_ambitions]'.") + else + to_chat(src, "You leave your ambitions behind.") + log_and_message_admins("has set their ambitions to now be: [new_ambitions].") + +//some antagonist datums are not actually antagonists, so we might want to avoid +//sending them the antagonist meet'n'greet messages. +//E.G. ERT +/datum/antagonist/proc/show_objectives_at_creation(var/datum/mind/player) + if(src.show_objectives_on_creation) + show_objectives(player) \ No newline at end of file diff --git a/code/game/antagonist/antagonist_panel.dm b/code/game/antagonist/antagonist_panel.dm new file mode 100644 index 00000000..0d296ec4 --- /dev/null +++ b/code/game/antagonist/antagonist_panel.dm @@ -0,0 +1,61 @@ +/datum/antagonist/proc/get_panel_entry(var/datum/mind/player) + + var/dat = "[role_text]:" + var/extra = get_extra_panel_options(player) + if(is_antagonist(player)) + dat += "\[-\]" + dat += "\[equip\]" + if(starting_locations && starting_locations.len) + dat += "\[move to spawn\]" + if(extra) dat += "[extra]" + else + dat += "\[+\]" + dat += "" + + return dat + +/datum/antagonist/proc/get_extra_panel_options() + return + +/datum/antagonist/proc/get_check_antag_output(var/datum/admins/caller) + + if(!current_antagonists || !current_antagonists.len) + return "" + + var/dat = "
    " + for(var/datum/mind/player in current_antagonists) + var/mob/M = player.current + dat += "" + if(M) + dat += "" + dat += "" + else + dat += "" + dat += "" + dat += "
    [role_text_plural]
    [M.real_name]/([player.key])" + if(!M.client) dat += " (logged out)" + if(M.stat == DEAD) dat += " (DEAD)" + dat += "\[PM\]\[TP\]Mob not found/([player.key])!
    " + + if(flags & ANTAG_HAS_NUKE) + dat += "
    " + for(var/obj/item/weapon/disk/nuclear/N in world) + dat += "" + dat += "
    Nuclear disk(s)
    [N.name], " + var/atom/disk_loc = N.loc + while(!istype(disk_loc, /turf)) + if(istype(disk_loc, /mob)) + var/mob/M = disk_loc + dat += "carried by [M.real_name] " + if(istype(disk_loc, /obj)) + var/obj/O = disk_loc + dat += "in \a [O.name] " + disk_loc = disk_loc.loc + dat += "in [disk_loc.loc] at ([disk_loc.x], [disk_loc.y], [disk_loc.z])
    " + dat += get_additional_check_antag_output(caller) + dat += "
    " + return dat + +//Overridden elsewhere. +/datum/antagonist/proc/get_additional_check_antag_output(var/datum/admins/caller) + return "" diff --git a/code/game/antagonist/antagonist_place.dm b/code/game/antagonist/antagonist_place.dm new file mode 100644 index 00000000..11ea718f --- /dev/null +++ b/code/game/antagonist/antagonist_place.dm @@ -0,0 +1,27 @@ +/datum/antagonist/proc/get_starting_locations() + if(landmark_id) + starting_locations = list() + for(var/obj/effect/landmark/L in landmarks_list) + if(L.name == landmark_id) + starting_locations |= get_turf(L) + +/datum/antagonist/proc/announce_antagonist_spawn() + + if(spawn_announcement) + if(announced) + return + announced = 1 + spawn(0) + if(spawn_announcement_delay) + sleep(spawn_announcement_delay) + if(spawn_announcement_sound) + command_announcement.Announce("[spawn_announcement]", "[spawn_announcement_title ? spawn_announcement_title : "Priority Alert"]", new_sound = spawn_announcement_sound) + else + command_announcement.Announce("[spawn_announcement]", "[spawn_announcement_title ? spawn_announcement_title : "Priority Alert"]") + return + +/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) + mob.forceMove(T) diff --git a/code/game/antagonist/antagonist_print.dm b/code/game/antagonist/antagonist_print.dm new file mode 100644 index 00000000..5bfd3431 --- /dev/null +++ b/code/game/antagonist/antagonist_print.dm @@ -0,0 +1,70 @@ +/datum/antagonist/proc/print_player_summary() + + if(!current_antagonists.len) + return 0 + + var/text = list() + text += "

    The [current_antagonists.len == 1 ? "[role_text] was" : "[role_text_plural] were"]:" + for(var/datum/mind/P in current_antagonists) + text += print_player(P) + text += get_special_objective_text(P) + if(P.ambitions) + text += "
    Their goals for today were..." + text += "
    [P.ambitions]" + if(!global_objectives.len && P.objectives && P.objectives.len) + var/failed + var/num = 1 + for(var/datum/objective/O in P.objectives) + text += print_objective(O, num) + if(O.check_completion()) + text += "Success!" + feedback_add_details(feedback_tag,"[O.type]|SUCCESS") + else + text += "Fail." + feedback_add_details(feedback_tag,"[O.type]|FAIL") + failed = 1 + num++ + if(failed) + text += "
    The [role_text] has failed." + else + text += "
    The [role_text] was successful!" + P.current.unlock_achievement(new/datum/achievement/winner()) + + if(global_objectives && global_objectives.len) + text += "
    Their objectives were:" + var/num = 1 + for(var/datum/objective/O in global_objectives) + text += print_objective(O, num, 1) + num++ + + // Display the results. + text += "
    " + to_world(jointext(text,null)) + + +/datum/antagonist/proc/print_objective(var/datum/objective/O, var/num, var/append_success) + var/text = "
    Objective [num]: [O.explanation_text] " + if(append_success) + if(O.check_completion()) + text += "Success!" + else + text += "Fail." + return text + +/datum/antagonist/proc/print_player(var/datum/mind/ply) + var/role = ply.assigned_role ? "\improper[ply.assigned_role]" : (ply.special_role ? "\improper[ply.special_role]" : "unknown role") + var/text = "
    [ply.name] ([ply.key]) as \a [role] (" + if(ply.current) + if(ply.current.stat == DEAD) + text += "died" + else if(isNotStationLevel(ply.current.z)) + text += "fled" + else + text += "survived" + if(ply.current.real_name != ply.name) + text += " as [ply.current.real_name]" + else + text += "body destroyed" + text += ")" + + return text diff --git a/code/game/antagonist/antagonist_update.dm b/code/game/antagonist/antagonist_update.dm new file mode 100644 index 00000000..2f703505 --- /dev/null +++ b/code/game/antagonist/antagonist_update.dm @@ -0,0 +1,91 @@ +/datum/antagonist/proc/update_leader() + if(!leader && current_antagonists.len && (flags & ANTAG_HAS_LEADER)) + leader = current_antagonists[1] + +/datum/antagonist/proc/update_antag_mob(var/datum/mind/player, var/preserve_appearance) + + // Get the mob. + if((flags & ANTAG_OVERRIDE_MOB) && (!player.current || (mob_path && !istype(player.current, mob_path)))) + var/mob/holder = player.current + player.current = new mob_path(get_turf(player.current)) + player.transfer_to(player.current) + if(holder) qdel(holder) + player.original = player.current + if(!preserve_appearance && (flags & ANTAG_SET_APPEARANCE)) + spawn(3) + var/mob/living/carbon/human/H = player.current + if(istype(H)) H.change_appearance(APPEARANCE_ALL, H.loc, H, valid_species, state = GLOB.z_state) + return player.current + +/datum/antagonist/proc/update_access(var/mob/living/player) + for(var/obj/item/weapon/card/id/id in player.contents) + player.set_id_info(id) + +/datum/antagonist/proc/clear_indicators(var/datum/mind/recipient) + if(!recipient.current || !recipient.current.client) + return + for(var/image/I in recipient.current.client.images) + if(I.icon_state == antag_indicator || (faction_indicator && I.icon_state == faction_indicator)) + qdel(I) + +/datum/antagonist/proc/get_indicator(var/datum/mind/recipient, var/datum/mind/other) + if(!antag_indicator || !other.current || !recipient.current) + return + var/indicator = (faction_indicator && (other in faction_members)) ? faction_indicator : antag_indicator + return image('icons/mob/hud.dmi', loc = other.current, icon_state = indicator, layer = LIGHTING_LAYER+0.1) + +/datum/antagonist/proc/update_all_icons() + if(!antag_indicator) + return + for(var/datum/mind/antag in current_antagonists) + clear_indicators(antag) + if(faction_invisible && (antag in faction_members)) + continue + for(var/datum/mind/other_antag in current_antagonists) + if(antag.current && antag.current.client) + antag.current.client.images |= get_indicator(antag, other_antag) + +/datum/antagonist/proc/update_icons_added(var/datum/mind/player) + if(!antag_indicator || !player.current) + return + spawn(0) + + var/give_to_player = (!faction_invisible || !(player in faction_members)) + for(var/datum/mind/antag in current_antagonists) + if(!antag.current) + continue + if(antag.current.client) + antag.current.client.images |= get_indicator(antag, player) + if(!give_to_player) + continue + if(player.current.client) + player.current.client.images |= get_indicator(player, antag) + +/datum/antagonist/proc/update_icons_removed(var/datum/mind/player) + if(!antag_indicator || !player.current) + return + spawn(0) + clear_indicators(player) + if(player.current && player.current.client) + for(var/datum/mind/antag in current_antagonists) + if(antag.current && antag.current.client) + for(var/image/I in antag.current.client.images) + if(I.loc == player.current) + qdel(I) + +/datum/antagonist/proc/update_current_antag_max() + cur_max = hard_cap + if(ticker && ticker.mode) + if(ticker.mode.antag_tags && (id in ticker.mode.antag_tags)) + cur_max = hard_cap_round + + if(ticker.mode.antag_scaling_coeff) + + var/count = 0 + for(var/mob/living/M in GLOB.player_list) + if(M.client) + count++ + + // Minimum: initial_spawn_target + // Maximum: hard_cap or hard_cap_round + cur_max = max(initial_spawn_target,min(round(count/ticker.mode.antag_scaling_coeff),cur_max)) diff --git a/code/game/antagonist/mutiny/loyalist.dm b/code/game/antagonist/mutiny/loyalist.dm new file mode 100644 index 00000000..36feefc1 --- /dev/null +++ b/code/game/antagonist/mutiny/loyalist.dm @@ -0,0 +1,10 @@ +var/datum/antagonist/mutineer/loyalist/loyalists + +/datum/antagonist/mutineer/loyalist + role_text = "Loyalist" + role_text_plural = "Loyalists" + id = MODE_LOYALIST + +/datum/antagonist/mutineer/loyalist/New() + ..(1) + loyalists = src diff --git a/code/game/antagonist/mutiny/mutineer.dm b/code/game/antagonist/mutiny/mutineer.dm new file mode 100644 index 00000000..c7c4b1ca --- /dev/null +++ b/code/game/antagonist/mutiny/mutineer.dm @@ -0,0 +1,25 @@ +var/datum/antagonist/mutineer/mutineers + +/datum/antagonist/mutineer + role_type = BE_MUTINEER + role_text = "Mutineer" + role_text_plural = "Mutineers" + id = MODE_MUTINEER + antag_indicator = "hudmutineer" + restricted_jobs = list(/datum/job/captain) + +/datum/antagonist/mutineer/New(var/no_reference) + ..() + if(!no_reference) + mutineers = src + +/datum/antagonist/mutineer/proc/recruit() + +/datum/antagonist/mutineer/can_become_antag(var/datum/mind/player, var/ignore_role) + if(!..()) + return 0 + if(!istype(player.current, /mob/living/carbon/human)) + return 0 + if(M.special_role) + return 0 + return 1 \ No newline at end of file diff --git a/code/game/antagonist/outsider/actors.dm b/code/game/antagonist/outsider/actors.dm new file mode 100644 index 00000000..8c4c08ea --- /dev/null +++ b/code/game/antagonist/outsider/actors.dm @@ -0,0 +1,61 @@ +var/datum/antagonist/actor/actor + +/datum/antagonist/actor + id = MODE_ACTOR + role_text = "NanoTrasen Actor" + role_text_plural = "NanoTrasen Actors" + welcome_text = "You've been hired to entertain people through the power of television!" + landmark_id = "ActorSpawn" + id_type = /obj/item/weapon/card/id/syndicate + + flags = ANTAG_OVERRIDE_JOB | ANTAG_SET_APPEARANCE | ANTAG_CHOOSE_NAME | ANTAG_RANDOM_EXCEPTED + + hard_cap = 7 + hard_cap_round = 10 + initial_spawn_req = 1 + initial_spawn_target = 1 + show_objectives_on_creation = 0 //actors are not antagonists and do not need the antagonist greet text + +/datum/antagonist/actor/New() + ..() + actor = src + +/datum/antagonist/actor/greet(var/datum/mind/player) + if(!..()) + return + + player.current.show_message("You work for [GLOB.using_map.company_name], tasked with the production and broadcasting of entertainment to all of its assets.") + player.current.show_message("Entertain the crew! Try not to disrupt them from their work too much and remind them how great [GLOB.using_map.company_name] is!") + +/datum/antagonist/actor/equip(var/mob/living/carbon/human/player) + player.equip_to_slot_or_del(new /obj/item/clothing/under/chameleon(src), slot_w_uniform) + player.equip_to_slot_or_del(new /obj/item/clothing/shoes/chameleon(src), slot_shoes) + player.equip_to_slot_or_del(new /obj/item/device/radio/headset/entertainment(src), slot_l_ear) + var/obj/item/weapon/card/id/centcom/ERT/C = new(player.loc) + C.assignment = "Actor" + player.set_id_info(C) + player.equip_to_slot_or_del(C,slot_wear_id) + + return 1 +/* +/client/verb/join_as_actor() + set category = "IC" + set name = "Join as Actor" + set desc = "Join as an Actor to entertain the crew through television!" + + if(!MayRespawn(1) || !actor.can_become_antag(usr.mind, 1)) + return + + var/choice = alert("Are you sure you'd like to join as an actor?", "Confirmation","Yes", "No") + if(choice != "Yes") + return + + if(isghostmind(usr.mind) || isnewplayer(usr)) + if(actor.current_antagonists.len >= actor.hard_cap) + to_chat(usr, "No more actors may spawn at the current time.") + return + actor.create_default(usr) + return + + to_chat(usr, "You must be observing or be a new player to spawn as an actor.") +*/ \ No newline at end of file diff --git a/code/game/antagonist/outsider/commando.dm b/code/game/antagonist/outsider/commando.dm new file mode 100644 index 00000000..74fad9e9 --- /dev/null +++ b/code/game/antagonist/outsider/commando.dm @@ -0,0 +1,37 @@ +var/datum/antagonist/deathsquad/mercenary/commandos + +/datum/antagonist/deathsquad/mercenary + id = MODE_COMMANDO + landmark_id = "Syndicate-Commando" + role_text = "Syndicate Commando" + role_text_plural = "Commandos" + welcome_text = "You are in the employ of a criminal syndicate hostile to corporate interests." + id_type = /obj/item/weapon/card/id/centcom/ERT + flags = ANTAG_RANDOM_EXCEPTED + + hard_cap = 4 + hard_cap_round = 8 + initial_spawn_req = 4 + initial_spawn_target = 6 + + +/datum/antagonist/deathsquad/mercenary/New() + ..(1) + commandos = src + +/datum/antagonist/deathsquad/mercenary/equip(var/mob/living/carbon/human/player) + + player.equip_to_slot_or_del(new /obj/item/clothing/under/syndicate(player), slot_w_uniform) + player.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/silenced(player), slot_belt) + player.equip_to_slot_or_del(new /obj/item/clothing/shoes/swat(player), slot_shoes) + player.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal(player), slot_glasses) + player.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/syndicate(player), slot_wear_mask) + player.equip_to_slot_or_del(new /obj/item/weapon/storage/box(player), slot_in_backpack) + player.equip_to_slot_or_del(new /obj/item/ammo_magazine/box/c45(player), slot_in_backpack) + //player.equip_to_slot_or_del(new /obj/item/weapon/rig/merc(player), slot_back) FIXME + player.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle(player), slot_r_hand) + player.equip_to_slot_or_del(new /obj/item/weapon/melee/energy/sword(player), slot_l_hand) + + create_id("Commando", player) + create_radio(RED_FREQ, player) + return 1 diff --git a/code/game/antagonist/outsider/deathsquad.dm b/code/game/antagonist/outsider/deathsquad.dm new file mode 100644 index 00000000..8932c3ef --- /dev/null +++ b/code/game/antagonist/outsider/deathsquad.dm @@ -0,0 +1,89 @@ +var/datum/antagonist/deathsquad/deathsquad + +/datum/antagonist/deathsquad + id = MODE_DEATHSQUAD + role_text = "Death Commando" + 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 + default_access = list(access_cent_general, access_cent_specops, access_cent_living, access_cent_storage) + antaghud_indicator = "huddeathsquad" + + hard_cap = 4 + hard_cap_round = 8 + initial_spawn_req = 4 + initial_spawn_target = 6 + + faction = "deathsquad" + + var/deployed = 0 + +/datum/antagonist/deathsquad/New(var/no_reference) + ..() + if(!no_reference) + deathsquad = src + +/datum/antagonist/deathsquad/attempt_spawn() + if(..()) + deployed = 1 + +/datum/antagonist/deathsquad/equip(var/mob/living/carbon/human/player) + if(!..()) + return + + if (player.mind == leader) + player.equip_to_slot_or_del(new /obj/item/clothing/under/rank/centcom_officer(player), slot_w_uniform) + else + player.equip_to_slot_or_del(new /obj/item/clothing/under/color/green(player), slot_w_uniform) + + player.equip_to_slot_or_del(new /obj/item/clothing/shoes/swat(player), slot_shoes) + player.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal(player), slot_glasses) + player.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/swat(player), slot_wear_mask) + if (player.mind == leader) + player.equip_to_slot_or_del(new /obj/item/weapon/pinpointer(player), slot_l_store) + player.equip_to_slot_or_del(new /obj/item/weapon/disk/nuclear(player), slot_r_store) + else + player.equip_to_slot_or_del(new /obj/item/weapon/plastique(player), slot_l_store) + player.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/revolver/mateba(player), slot_belt) + player.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle(player), slot_r_hand) + //player.equip_to_slot_or_del(new /obj/item/weapon/rig/ert/assetprotection(player), slot_back) FIXME + player.equip_to_slot_or_del(new /obj/item/weapon/melee/energy/sword(player), slot_l_hand) + player.implant_loyalty(player) + + var/obj/item/weapon/card/id/id = create_id("Asset Protection", player) + if(id) + id.access |= get_all_station_access() + id.icon_state = "centcom" + create_radio(DTH_FREQ, player) + +/datum/antagonist/deathsquad/update_antag_mob(var/datum/mind/player) + + ..() + + var/syndicate_commando_rank + if(leader && player == leader) + syndicate_commando_rank = pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant 1st Class", "Master Sergeant", "Sergeant Major") + else + syndicate_commando_rank = pick("Lieutenant", "Captain", "Major") + + var/syndicate_commando_name = pick(GLOB.last_names) + + var/datum/preferences/A = new() //Randomize appearance for the commando. + A.randomize_appearance_and_body_for(player.current) + + player.name = "[syndicate_commando_rank] [syndicate_commando_name]" + player.current.real_name = player.name + player.current.SetName(player.current.name) + + var/mob/living/carbon/human/H = player.current + if(istype(H)) + H.gender = pick(MALE, FEMALE) + H.age = rand(25,45) + H.dna.ready_dna(H) + + return + +/datum/antagonist/deathsquad/create_antagonist() + if(..() && !deployed) + deployed = 1 diff --git a/code/game/antagonist/outsider/ert.dm b/code/game/antagonist/outsider/ert.dm new file mode 100644 index 00000000..e95137e9 --- /dev/null +++ b/code/game/antagonist/outsider/ert.dm @@ -0,0 +1,52 @@ +var/datum/antagonist/ert/ert + +/datum/antagonist/ert + id = MODE_ERT + role_text = "Emergency Responder" + role_text_plural = "Emergency Responders" + welcome_text = "As member of the Emergency Response Team, you answer only to your leader and company officials." + antag_text = "You are an anti antagonist! Within the rules, \ + try to save the installation and its inhabitants from the ongoing crisis. \ + Try to make sure other players have fun! If you are confused or at a loss, always adminhelp, \ + and before taking extreme actions, please try to also contact the administration! \ + Think through your actions and make the roleplay immersive! Please remember all \ + rules aside from those without explicit exceptions apply to the ERT." + leader_welcome_text = "You shouldn't see this" + 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 + antaghud_indicator = "hudloyalist" + + hard_cap = 5 + hard_cap_round = 7 + initial_spawn_req = 5 + initial_spawn_target = 7 + show_objectives_on_creation = 0 //we are not antagonists, we do not need the antagonist shpiel/objectives + +/datum/antagonist/ert/create_default(var/mob/source) + var/mob/living/carbon/human/M = ..() + if(istype(M)) M.age = rand(25,45) + +/datum/antagonist/ert/New() + ..() + leader_welcome_text = "As leader of the Emergency Response Team, you answer only to [GLOB.using_map.boss_name], and have authority to override the Captain where it is necessary to achieve your mission goals. It is recommended that you attempt to cooperate with the captain where possible, however." + ert = src + +/datum/antagonist/ert/greet(var/datum/mind/player) + if(!..()) + return + to_chat(player.current, "The Emergency Response Team works for Asset Protection; your job is to protect [GLOB.using_map.company_name]'s ass-ets. There is a code red alert on [station_name()], you are tasked to go and fix the problem.") + to_chat(player.current, "You should first gear up and discuss a plan with your team. More members may be joining, don't move out before you're ready.") + +/datum/antagonist/ert/equip(var/mob/living/carbon/human/player) + + //Special radio setup + player.equip_to_slot_or_del(new /obj/item/device/radio/headset/ert(src), slot_l_ear) + player.equip_to_slot_or_del(new /obj/item/clothing/under/ert(src), slot_w_uniform) + player.equip_to_slot_or_del(new /obj/item/clothing/shoes/swat(src), slot_shoes) + player.equip_to_slot_or_del(new /obj/item/clothing/gloves/thick/swat(src), slot_gloves) + player.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses(src), slot_glasses) + + create_id(role_text, player) + return 1 diff --git a/code/game/antagonist/outsider/mercenary.dm b/code/game/antagonist/outsider/mercenary.dm new file mode 100644 index 00000000..c86af388 --- /dev/null +++ b/code/game/antagonist/outsider/mercenary.dm @@ -0,0 +1,80 @@ +var/datum/antagonist/mercenary/mercs + +/datum/antagonist/mercenary + id = MODE_MERCENARY + role_text = "Mercenary" + antag_indicator = "hudsyndicate" + role_text_plural = "Mercenaries" + landmark_id = "Syndicate-Spawn" + leader_welcome_text = "You are the leader of the mercenary strikeforce; hail to the chief. Use :t to speak to your underlings." + welcome_text = "To speak on the strike team's private channel use :t." + flags = ANTAG_VOTABLE | ANTAG_OVERRIDE_JOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_HAS_NUKE | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER + antaghud_indicator = "hudoperative" + spawn_announcement_title = "Vital Priority Announcement At All Communications Consoles!" + spawn_announcement_sound = 'sound/AI/november/threat.ogg' + gag_announcement = FALSE //Loud and clear, we want these guys to be KNOWN + + + hard_cap = 4 + hard_cap_round = 8 + initial_spawn_req = 4 + initial_spawn_target = 5 + min_player_age = 14 + + faction = "mercenary" + +/datum/antagonist/mercenary/New() + ..() + mercs = src + +/datum/antagonist/mercenary/create_global_objectives() + if(!..()) + return 0 + global_objectives = list() + global_objectives |= new /datum/objective/nuclear + return 1 + +/datum/antagonist/mercenary/equip(var/mob/living/carbon/human/player) + if(!..()) + return 0 + + var/decl/hierarchy/outfit/mercenary = outfit_by_type(/decl/hierarchy/outfit/mercenary) + mercenary.equip(player) + + player.set_trait(new/datum/trait/hardcore()) + player.add_stats(rand(14,18), rand(10,16), rand(12,18), rand(8,12)) + player.add_skills(rand(5, 9), rand(4,7), rand(2,5), rand(1,5), rand(1,5)) + + //var/obj/item/device/radio/uplink/U = new(get_turf(player), player.mind, DEFAULT_TELECRYSTAL_AMOUNT) + //player.put_in_hands(U) + + return 1 +/datum/antagonist/mercenary/create_antagonist(var/datum/mind/target, var/move, var/gag_announcement = TRUE, var/preserve_appearance) + ..() +/* +/datum/antagonist/mercenary/check_victory() + var/survivor + for(var/datum/mind/player in current_antagonists) + if(!player.current || player.current.stat) + continue + survivor = 1 + break + if(!survivor) + feedback_set_details("round_end_result","loss - mercenaries are dead") + to_world("The [(current_antagonists.len>1)?"[role_text_plural] have":"[role_text] has"] been killed! The Magistrate's station is safe again!") +*/ + +/datum/antagonist/mercenary/announce_antagonist_spawn() + ..() + var/welcome_text = "
    Declaration of War!

    " + welcome_text += "Dear Commandant of this stronghold. This is a formal declaration of war from Sir Magistrate [pick(GLOB.first_names_male)] [pick(GLOB.last_names)]. We are sending our team of mercenaries to:" + for(var/datum/objective/objective in global_objectives) + welcome_text += "[objective.explanation_text]
    " + + post_comm_message("Declaration of War!!", welcome_text) + //command_announcement.Announce(welcome_text, "Declaration of War!", new_sound = 'sound/AI/november/threat.ogg', msg_sanitized = 1); + + + + + diff --git a/code/game/antagonist/outsider/raider.dm b/code/game/antagonist/outsider/raider.dm new file mode 100644 index 00000000..4ddd62ba --- /dev/null +++ b/code/game/antagonist/outsider/raider.dm @@ -0,0 +1,302 @@ +var/datum/antagonist/raider/raiders + +/datum/antagonist/raider + id = MODE_RAIDER + role_text = "Raider" + role_text_plural = "Raiders" + antag_indicator = "hudmutineer" + landmark_id = "voxstart" + welcome_text = "Use :H to talk on your encrypted channel." + flags = ANTAG_OVERRIDE_JOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_VOTABLE | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER + antaghud_indicator = "hudmutineer" + + hard_cap = 6 + hard_cap_round = 10 + initial_spawn_req = 4 + initial_spawn_target = 6 + min_player_age = 14 + + id_type = /obj/item/weapon/card/id/syndicate + + faction = "pirate" + + // Heist overrides check_victory() and doesn't need victory or loss strings/tags. + var/list/raider_uniforms = list( + /obj/item/clothing/under/soviet, + /obj/item/clothing/under/pirate, + /obj/item/clothing/under/redcoat, + /obj/item/clothing/under/serviceoveralls, + /obj/item/clothing/under/captain_fly, + /obj/item/clothing/under/det, + /obj/item/clothing/under/color/brown, + ) + + var/list/raider_shoes = list( + /obj/item/clothing/shoes/jackboots, + /obj/item/clothing/shoes/workboots, + /obj/item/clothing/shoes/brown, + /obj/item/clothing/shoes/laceup + ) + + var/list/raider_glasses = list( + /obj/item/clothing/glasses/thermal, + /obj/item/clothing/glasses/thermal/plain/eyepatch, + /obj/item/clothing/glasses/thermal/plain/monocle + ) + + var/list/raider_helmets = list( + /obj/item/clothing/head/bearpelt, + /obj/item/clothing/head/ushanka, + /obj/item/clothing/head/pirate, + /obj/item/clothing/mask/bandana/red, + /obj/item/clothing/head/hgpiratecap, + ) + + var/list/raider_suits = list( + /obj/item/clothing/suit/pirate, + /obj/item/clothing/suit/hgpirate, + /obj/item/clothing/suit/storage/toggle/bomber, + /obj/item/clothing/suit/storage/leather_jacket, + /obj/item/clothing/suit/storage/toggle/brown_jacket, + /obj/item/clothing/suit/storage/toggle/hoodie, + /obj/item/clothing/suit/storage/toggle/hoodie/black, + /obj/item/clothing/suit/unathi/mantle, + /obj/item/clothing/suit/poncho/colored, + ) + + var/list/raider_guns = list( + /obj/item/weapon/gun/energy/laser, + /obj/item/weapon/gun/energy/retro, + /obj/item/weapon/gun/energy/mindflayer, + /obj/item/weapon/gun/energy/stunrevolver, + /obj/item/weapon/gun/energy/ionrifle, + /obj/item/weapon/gun/energy/taser, + /obj/item/weapon/gun/energy/crossbow/largecrossbow, + /obj/item/weapon/gun/launcher/crossbow, + /obj/item/weapon/gun/launcher/grenade/loaded, + /obj/item/weapon/gun/launcher/pneumatic, + /obj/item/weapon/gun/projectile/automatic/mini_uzi, + /obj/item/weapon/gun/projectile/automatic/c20r, + /obj/item/weapon/gun/projectile/automatic/wt550, + /obj/item/weapon/gun/projectile/automatic/sts35, + /obj/item/weapon/gun/projectile/silenced, + /obj/item/weapon/gun/projectile/shotgun/pump, + /obj/item/weapon/gun/projectile/shotgun/pump/combat, + /obj/item/weapon/gun/projectile/shotgun/doublebarrel, + /obj/item/weapon/gun/projectile/shotgun/doublebarrel/pellet, + /obj/item/weapon/gun/projectile/shotgun/doublebarrel/sawn, + /obj/item/weapon/gun/projectile/colt, + /obj/item/weapon/gun/projectile/sec, + /obj/item/weapon/gun/projectile/pistol, + /obj/item/weapon/gun/projectile/revolver, + /obj/item/weapon/gun/projectile/pirate + ) + + var/list/raider_holster = list( + /obj/item/clothing/accessory/holster/armpit, + /obj/item/clothing/accessory/holster/waist, + /obj/item/clothing/accessory/holster/hip + ) + +/datum/antagonist/raider/New() + ..() + raiders = src + +/datum/antagonist/raider/update_access(var/mob/living/player) + for(var/obj/item/weapon/storage/wallet/W in player.contents) + for(var/obj/item/weapon/card/id/id in W.contents) + id.SetName("[player.real_name]'s Passport") + id.registered_name = player.real_name + W.SetName("[initial(W.name)] ([id.name])") + +/datum/antagonist/raider/create_global_objectives() + + if(!..()) + return 0 + + var/i = 1 + var/max_objectives = pick(2,2,2,2,3,3,3,4) + global_objectives = list() + while(i<= max_objectives) + var/list/goals = list("kidnap","loot","salvage") + var/goal = pick(goals) + var/datum/objective/heist/O + + if(goal == "kidnap") + goals -= "kidnap" + O = new /datum/objective/heist/kidnap() + else if(goal == "loot") + O = new /datum/objective/heist/loot() + else + O = new /datum/objective/heist/salvage() + O.choose_target() + global_objectives |= O + + i++ + + global_objectives |= new /datum/objective/heist/preserve_crew + return 1 + +/datum/antagonist/raider/check_victory() + // Totally overrides the base proc. + var/win_type = "Major" + var/win_group = "Crew" + var/win_msg = "" + + //No objectives, go straight to the feedback. + if(config.objectives_disabled == CONFIG_OBJECTIVE_NONE || !global_objectives.len) + return + + var/success = global_objectives.len + //Decrease success for failed objectives. + for(var/datum/objective/O in global_objectives) + if(!(O.check_completion())) success-- + //Set result by objectives. + if(success == global_objectives.len) + win_type = "Major" + win_group = "Raider" + else if(success > 2) + win_type = "Minor" + win_group = "Raider" + else + win_type = "Minor" + win_group = "Crew" + //Now we modify that result by the state of the vox crew. + if(antags_are_dead()) + win_type = "Major" + win_group = "Crew" + win_msg += "The Raiders have been wiped out!" + else if(is_raider_crew_safe()) + if(win_group == "Crew" && win_type == "Minor") + win_type = "Major" + win_group = "Crew" + win_msg += "The Raiders have left someone behind!" + else + if(win_group == "Raider") + if(win_type == "Minor") + win_type = "Major" + win_msg += "The Raiders escaped!" + else + win_msg += "The Raiders were repelled!" + + to_world("[win_type] [win_group] victory!") + to_world("[win_msg]") + feedback_set_details("round_end_result","heist - [win_type] [win_group]") + +/datum/antagonist/raider/proc/is_raider_crew_safe() + + if(!current_antagonists || current_antagonists.len == 0) + return 0 + + for(var/datum/mind/player in current_antagonists) + if(!player.current || get_area(player.current) != locate(/area/skipjack_station/start)) + return 0 + return 1 + +/datum/antagonist/raider/equip(var/mob/living/carbon/human/player) + + if(!..()) + return 0 + + if(player.species && player.species.get_bodytype(player) == SPECIES_VOX) + equip_vox(player) + else + var/new_shoes = pick(raider_shoes) + var/new_uniform = pick(raider_uniforms) + var/new_glasses = pick(raider_glasses) + var/new_helmet = pick(raider_helmets) + var/new_suit = pick(raider_suits) + + player.equip_to_slot_or_del(new new_shoes(player),slot_shoes) + if(!player.shoes) + //If equipping shoes failed, fall back to equipping sandals + var/fallback_type = pick(/obj/item/clothing/shoes/sandal, /obj/item/clothing/shoes/jackboots/unathi) + player.equip_to_slot_or_del(new fallback_type(player), slot_shoes) + + player.equip_to_slot_or_del(new new_uniform(player),slot_w_uniform) + player.equip_to_slot_or_del(new new_glasses(player),slot_glasses) + player.equip_to_slot_or_del(new new_helmet(player),slot_head) + player.equip_to_slot_or_del(new new_suit(player),slot_wear_suit) + equip_weapons(player) + + var/obj/item/weapon/card/id/id = create_id("Visitor", player, equip = 0) + id.SetName("[player.real_name]'s Passport") + id.assignment = "Visitor" + var/obj/item/weapon/storage/wallet/W = new(player) + W.handle_item_insertion(id) + player.equip_to_slot_or_del(W, slot_wear_id) + spawn_money(rand(50,150)*10,W) + create_radio(BLUE_FREQ, player) + + return 1 + +/datum/antagonist/raider/proc/equip_weapons(var/mob/living/carbon/human/player) + var/new_gun = pick(raider_guns) + var/new_holster = pick(raider_holster) //raiders don't start with any backpacks, so let's be nice and give them a holster if they can use it. + var/turf/T = get_turf(player) + + var/obj/item/primary = new new_gun(T) + var/obj/item/clothing/accessory/holster/holster = null + + //Give some of the raiders a pirate gun as a secondary + if(prob(60)) + var/obj/item/secondary = new /obj/item/weapon/gun/projectile/pirate(T) + if(!(primary.slot_flags & SLOT_HOLSTER)) + holster = new new_holster(T) + holster.holstered = secondary + secondary.forceMove(holster) + else + player.equip_to_slot_or_del(secondary, slot_belt) + + if(primary.slot_flags & SLOT_HOLSTER) + holster = new new_holster(T) + holster.holstered = primary + primary.forceMove(holster) + else if(!player.belt && (primary.slot_flags & SLOT_BELT)) + player.equip_to_slot_or_del(primary, slot_belt) + else if(!player.back && (primary.slot_flags & SLOT_BACK)) + player.equip_to_slot_or_del(primary, slot_back) + else + player.put_in_any_hand_if_possible(primary) + + //If they got a projectile gun, give them a little bit of spare ammo + equip_ammo(player, primary) + + if(holster) + var/obj/item/clothing/under/uniform = player.w_uniform + if(istype(uniform) && uniform.can_attach_accessory(holster)) + uniform.attackby(holster, player) + else + player.put_in_any_hand_if_possible(holster) + +/datum/antagonist/raider/proc/equip_ammo(var/mob/living/carbon/human/player, var/obj/item/weapon/gun/gun) + if(istype(gun, /obj/item/weapon/gun/projectile)) + var/obj/item/weapon/gun/projectile/bullet_thrower = gun + if(bullet_thrower.magazine_type) + player.equip_to_slot_or_del(new bullet_thrower.magazine_type(player), slot_l_store) + if(prob(20)) //don't want to give them too much + player.equip_to_slot_or_del(new bullet_thrower.magazine_type(player), slot_r_store) + else if(bullet_thrower.ammo_type) + var/obj/item/weapon/storage/box/ammobox = new(get_turf(player.loc)) + for(var/i in 1 to rand(3,5) + rand(0,2)) + new bullet_thrower.ammo_type(ammobox) + player.put_in_any_hand_if_possible(ammobox) + return + +/datum/antagonist/raider/proc/equip_vox(var/mob/living/carbon/human/player) + + var/uniform_type = pick(list(/obj/item/clothing/under/vox/vox_robes,/obj/item/clothing/under/vox/vox_casual)) + + player.equip_to_slot_or_del(new uniform_type(player), slot_w_uniform) + player.equip_to_slot_or_del(new /obj/item/clothing/shoes/magboots/vox(player), slot_shoes) // REPLACE THESE WITH CODED VOX ALTERNATIVES. + player.equip_to_slot_or_del(new /obj/item/clothing/gloves/vox(player), slot_gloves) // AS ABOVE. + player.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/swat/vox(player), slot_wear_mask) + player.equip_to_slot_or_del(new /obj/item/weapon/tank/nitrogen(player), slot_back) + player.equip_to_slot_or_del(new /obj/item/device/flashlight(player), slot_r_store) + + player.internal = locate(/obj/item/weapon/tank) in player.contents + if(istype(player.internal,/obj/item/weapon/tank) && player.internals) + player.internals.icon_state = "internal1" + + return 1 + diff --git a/code/game/antagonist/outsider/wizard.dm b/code/game/antagonist/outsider/wizard.dm new file mode 100644 index 00000000..14e96f6a --- /dev/null +++ b/code/game/antagonist/outsider/wizard.dm @@ -0,0 +1,144 @@ +var/datum/antagonist/wizard/wizards + +/datum/antagonist/wizard + id = MODE_WIZARD + role_text = "Space Wizard" + role_text_plural = "Space Wizards" + landmark_id = "wizard" + welcome_text = "You will find a list of available spells in your spell book. Choose your magic arsenal carefully.
    In your pockets you will find a teleport scroll. Use it as needed." + flags = ANTAG_OVERRIDE_JOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_VOTABLE | ANTAG_SET_APPEARANCE + antaghud_indicator = "hudwizard" + + hard_cap = 1 + hard_cap_round = 3 + initial_spawn_req = 1 + initial_spawn_target = 1 + min_player_age = 18 + + faction = "wizard" + + +/datum/antagonist/wizard/New() + ..() + wizards = src + +/datum/antagonist/wizard/create_objectives(var/datum/mind/wizard) + + if(!..()) + return + + var/kill + var/escape + var/steal + var/hijack + + switch(rand(1,100)) + if(1 to 30) + escape = 1 + kill = 1 + if(31 to 60) + escape = 1 + steal = 1 + if(61 to 99) + kill = 1 + steal = 1 + else + hijack = 1 + + if(kill) + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = wizard + kill_objective.find_target() + wizard.objectives |= kill_objective + if(steal) + var/datum/objective/steal/steal_objective = new + steal_objective.owner = wizard + steal_objective.find_target() + wizard.objectives |= steal_objective + if(escape) + var/datum/objective/survive/survive_objective = new + survive_objective.owner = wizard + wizard.objectives |= survive_objective + if(hijack) + var/datum/objective/hijack/hijack_objective = new + hijack_objective.owner = wizard + wizard.objectives |= hijack_objective + return + +/datum/antagonist/wizard/update_antag_mob(var/datum/mind/wizard) + ..() + wizard.store_memory("Remember: do not forget to prepare your spells.") + wizard.current.real_name = "[pick(GLOB.wizard_first)] [pick(GLOB.wizard_second)]" + wizard.current.SetName(wizard.current.real_name) + +/datum/antagonist/wizard/equip(var/mob/living/carbon/human/wizard_mob) + + if(!..()) + return 0 + + var/outfit_type = pick(subtypesof(/decl/hierarchy/outfit/wizard)) + var/decl/hierarchy/outfit/wizard_outfit = outfit_by_type(outfit_type) + wizard_outfit.equip(wizard_mob) + + return 1 + +/datum/antagonist/wizard/check_victory() + var/survivor + for(var/datum/mind/player in current_antagonists) + if(!player.current || player.current.stat) + continue + survivor = 1 + break + if(!survivor) + feedback_set_details("round_end_result","loss - wizard killed") + to_world("The [(current_antagonists.len>1)?"[role_text_plural] have":"[role_text] has"] been killed by the crew! The Space Wizards Federation has been taught a lesson they will not soon forget!") + + +/datum/antagonist/wizard/print_player_summary() + ..() + for(var/p in current_antagonists) + var/datum/mind/player = p + var/text = "[player.name]'s spells were:" + if(!player.learned_spells || !player.learned_spells.len) + text += "
    None!" + else + for(var/s in player.learned_spells) + var/spell/spell = s + text += "
    [spell.name] - " + text += "Speed: [spell.spell_levels["speed"]] Power: [spell.spell_levels["power"]]" + text += "
    " + to_world(text) + + +//To batch-remove wizard spells. Linked to mind.dm. +/mob/proc/spellremove() + if(!mind || !mind.learned_spells) + return + for(var/spell/spell_to_remove in mind.learned_spells) + remove_spell(spell_to_remove) + +obj/item/clothing + var/wizard_garb = 0 + +// Does this clothing slot count as wizard garb? (Combines a few checks) +/proc/is_wiz_garb(var/obj/item/clothing/C) + return C && C.wizard_garb + +/*Checks if the wizard is wearing the proper attire. +Made a proc so this is not repeated 14 (or more) times.*/ +/mob/proc/wearing_wiz_garb() + to_chat(src, "Silly creature, you're not a human. Only humans can cast this spell.") + return 0 + +// Humans can wear clothes. +/mob/living/carbon/human/wearing_wiz_garb() + if(!is_wiz_garb(src.wear_suit) && (!src.species.hud || (slot_wear_suit in src.species.hud.equip_slots))) + to_chat(src, "I don't feel strong enough without my robe.") + return 0 + if(!is_wiz_garb(src.shoes) && (!species.hud || (slot_shoes in src.species.hud.equip_slots))) + to_chat(src, "I don't feel strong enough without my sandals.") + return 0 + if(!is_wiz_garb(src.head) && (!species.hud || (slot_head in src.species.hud.equip_slots))) + to_chat(src, "I don't feel strong enough without my hat.") + return 0 + return 1 \ No newline at end of file diff --git a/code/game/antagonist/station/changeling.dm b/code/game/antagonist/station/changeling.dm new file mode 100644 index 00000000..af2687f2 --- /dev/null +++ b/code/game/antagonist/station/changeling.dm @@ -0,0 +1,76 @@ +/datum/antagonist/changeling + id = MODE_CHANGELING + role_text = "Changeling" + role_text_plural = "Changelings" + feedback_tag = "changeling_objective" + blacklisted_jobs = list(/datum/job/ai, /datum/job/cyborg) + protected_jobs = list(/datum/job/officer, /datum/job/warden, /datum/job/detective, /datum/job/captain, /datum/job/hos) + welcome_text = "Use say \"#g message\" to communicate with your fellow changelings. Remember: you get all of their absorbed DNA if you absorb them." + flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE + antaghud_indicator = "hudchangeling" + + faction = "changeling" + +/datum/antagonist/changeling/get_special_objective_text(var/datum/mind/player) + return "
    Changeling ID: [player.changeling.changelingID].
    Genomes Absorbed: [player.changeling.absorbedcount]" + +/datum/antagonist/changeling/update_antag_mob(var/datum/mind/player) + ..() + player.current.make_changeling() + +/datum/antagonist/changeling/create_objectives(var/datum/mind/changeling) + if(!..()) + return + + //OBJECTIVES - Always absorb 5 genomes, plus random traitor objectives. + //If they have two objectives as well as absorb, they must survive rather than escape + //No escape alone because changelings aren't suited for it and it'd probably just lead to rampant robusting + //If it seems like they'd be able to do it in play, add a 10% chance to have to escape alone + + var/datum/objective/absorb/absorb_objective = new + absorb_objective.owner = changeling + absorb_objective.gen_amount_goal(2, 3) + changeling.objectives += absorb_objective + + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = changeling + kill_objective.find_target() + changeling.objectives += kill_objective + + var/datum/objective/steal/steal_objective = new + steal_objective.owner = changeling + steal_objective.find_target() + changeling.objectives += steal_objective + + switch(rand(1,100)) + if(1 to 80) + if (!(locate(/datum/objective/escape) in changeling.objectives)) + var/datum/objective/escape/escape_objective = new + escape_objective.owner = changeling + changeling.objectives += escape_objective + else + if (!(locate(/datum/objective/survive) in changeling.objectives)) + var/datum/objective/survive/survive_objective = new + survive_objective.owner = changeling + changeling.objectives += survive_objective + return + +/datum/antagonist/changeling/can_become_antag(var/datum/mind/player, var/ignore_role) + if(..()) + if(player.current) + if(ishuman(player.current)) + var/mob/living/carbon/human/H = player.current + if(H.isSynthetic()) + return 0 + if(H.species.species_flags & SPECIES_FLAG_NO_SCAN) + return 0 + return 1 + else if(isnewplayer(player.current)) + if(player.current.client && player.current.client.prefs) + var/datum/species/S = all_species[player.current.client.prefs.species] + if(S && (S.species_flags & SPECIES_FLAG_NO_SCAN)) + return 0 + if(player.current.client.prefs.organ_data[BP_CHEST] == "cyborg") // Full synthetic. + return 0 + return 1 + return 0 \ No newline at end of file diff --git a/code/game/antagonist/station/cultist.dm b/code/game/antagonist/station/cultist.dm new file mode 100644 index 00000000..78908f05 --- /dev/null +++ b/code/game/antagonist/station/cultist.dm @@ -0,0 +1,189 @@ +#define CULTINESS_PER_CULTIST 40 +#define CULTINESS_PER_SACRIFICE 40 +#define CULTINESS_PER_TURF 1 + +#define CULT_RUNES_1 200 +#define CULT_RUNES_2 400 +#define CULT_RUNES_3 1000 + +#define CULT_GHOSTS_1 400 +#define CULT_GHOSTS_2 800 +#define CULT_GHOSTS_3 1200 + +#define CULT_MAX_CULTINESS 1200 // When this value is reached, the game stops checking for updates so we don't recheck every time a tile is converted in endgame + +var/datum/antagonist/cultist/cult + +/proc/iscultist(var/mob/player) + if(!cult || !player.mind) + return 0 + if(player.mind in cult.current_antagonists) + return 1 + +/datum/antagonist/cultist + id = MODE_CULTIST + role_text = "Cultist" + role_text_plural = "Cultists" + restricted_jobs = list(/datum/job/lawyer, /datum/job/captain, /datum/job/hos) + protected_jobs = list(/datum/job/officer, /datum/job/warden, /datum/job/detective) + blacklisted_jobs = list(/datum/job/ai, /datum/job/cyborg, /datum/job/chaplain, /datum/job/psychiatrist) + feedback_tag = "cult_objective" + antag_indicator = "hudcultist" + welcome_text = "You have a tome in your possession; one that will help you start the cult. Use it well and remember - there are others." + victory_text = "The cult wins! It has succeeded in serving its dark masters!" + loss_text = "The staff managed to stop the cult!" + victory_feedback_tag = "win - cult win" + loss_feedback_tag = "loss - staff stopped the cult" + flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE + hard_cap = 5 + hard_cap_round = 6 + initial_spawn_req = 4 + initial_spawn_target = 6 + antaghud_indicator = "hudcultist" + + var/allow_narsie = 1 + var/powerless = 0 + var/datum/mind/sacrifice_target + var/list/obj/effect/rune/teleport/teleport_runes = list() + var/list/rune_strokes = list() + var/list/sacrificed = list() + var/cult_rating = 0 + var/list/cult_rating_bounds = list(CULT_RUNES_1, CULT_RUNES_2, CULT_RUNES_3, CULT_GHOSTS_1, CULT_GHOSTS_2, CULT_GHOSTS_3) + var/max_cult_rating = 0 + var/conversion_blurb = "You catch a glimpse of the Realm of Nar-Sie, the Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of That Which Waits. Assist your new compatriots in their dark dealings. Their goals are yours, and yours are theirs. You serve the Dark One above all else. Bring It back." + + faction = "cult" + +/datum/antagonist/cultist/New() + ..() + cult = src + +/datum/antagonist/cultist/create_global_objectives() + + if(!..()) + return + + global_objectives = list() + if(prob(50)) + global_objectives |= new /datum/objective/cult/survive + else + global_objectives |= new /datum/objective/cult/eldergod + + var/datum/objective/cult/sacrifice/sacrifice = new() + sacrifice.find_target() + sacrifice_target = sacrifice.target + global_objectives |= sacrifice + +/datum/antagonist/cultist/equip(var/mob/living/carbon/human/player) + + if(!..()) + return 0 + + var/obj/item/weapon/book/tome/T = new(get_turf(player)) + var/list/slots = list ( + "backpack" = slot_in_backpack, + "left pocket" = slot_l_store, + "right pocket" = slot_r_store, + "left hand" = slot_l_hand, + "right hand" = slot_r_hand, + ) + for(var/slot in slots) + player.equip_to_slot(T, slot) + if(T.loc == player) + break + var/obj/item/weapon/storage/S = locate() in player.contents + if(istype(S)) + T.forceMove(S) + +/datum/antagonist/cultist/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) + if(!..()) + return 0 + to_chat(player.current, "An unfamiliar white light flashes through your mind, cleansing the taint of the dark-one and the memories of your time as his servant with it.") + player.memory = "" + if(show_message) + player.current.visible_message("[player.current] looks like they just reverted to their old faith!") + remove_cult_magic(player.current) + remove_cultiness(CULTINESS_PER_CULTIST) + +/datum/antagonist/cultist/add_antagonist(var/datum/mind/player, var/ignore_role, var/do_not_equip, var/move_to_spawn, var/do_not_announce, var/preserve_appearance) + . = ..() + if(.) + to_chat(player, "[conversion_blurb]") + if(player.current && !istype(player.current, /mob/living/simple_animal/construct)) + player.current.add_language(LANGUAGE_CULT) + +/datum/antagonist/cultist/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) + . = ..() + if(. && player.current && !istype(player.current, /mob/living/simple_animal/construct)) + player.current.remove_language(LANGUAGE_CULT) + +/datum/antagonist/cultist/update_antag_mob(var/datum/mind/player) + . = ..() + add_cultiness(CULTINESS_PER_CULTIST) + add_cult_magic(player.current) + +/datum/antagonist/cultist/proc/add_cultiness(var/amount) + cult_rating += amount + var/old_rating = max_cult_rating + max_cult_rating = max(max_cult_rating, cult_rating) + if(old_rating >= CULT_MAX_CULTINESS) + return + var/list/to_update = list() + for(var/i in cult_rating_bounds) + if((old_rating < i) && (max_cult_rating >= i)) + to_update += i + + if(to_update.len) + update_cult_magic(to_update) + +/datum/antagonist/cultist/proc/update_cult_magic(var/list/to_update) + if(CULT_RUNES_1 in to_update) + for(var/datum/mind/H in cult.current_antagonists) + if(H.current) + to_chat(H.current, "The veil between this world and beyond grows thin, and your power grows.") + add_cult_magic(H.current) + if(CULT_RUNES_2 in to_update) + for(var/datum/mind/H in cult.current_antagonists) + if(H.current) + to_chat(H.current, "You feel that the fabric of reality is tearing.") + add_cult_magic(H.current) + if(CULT_RUNES_3 in to_update) + for(var/datum/mind/H in cult.current_antagonists) + if(H.current) + to_chat(H.current, "The world is at end. The veil is as thin as ever.") + add_cult_magic(H.current) + + if((CULT_GHOSTS_1 in to_update) || (CULT_GHOSTS_2 in to_update) || (CULT_GHOSTS_3 in to_update)) + for(var/mob/observer/ghost/D in SSmobs.mob_list) + add_ghost_magic(D) + +/datum/antagonist/cultist/proc/offer_uncult(var/mob/M) + if(!iscultist(M) || !M.mind) + return + + to_chat(M, "Do you want to abandon the cult of Nar'Sie? ACCEPT") + +/datum/antagonist/cultist/Topic(href, href_list) + if(href_list["confirmleave"]) + cult.remove_antagonist(usr.mind, 1) + +/datum/antagonist/cultist/proc/remove_cultiness(var/amount) + cult_rating = max(0, cult_rating - amount) + +/datum/antagonist/cultist/proc/add_cult_magic(var/mob/M) + M.verbs += Tier1Runes + + if(max_cult_rating >= CULT_RUNES_1) + M.verbs += Tier2Runes + + if(max_cult_rating >= CULT_RUNES_2) + M.verbs += Tier3Runes + + if(max_cult_rating >= CULT_RUNES_3) + M.verbs += Tier4Runes + +/datum/antagonist/cultist/proc/remove_cult_magic(var/mob/M) + M.verbs -= Tier1Runes + M.verbs -= Tier2Runes + M.verbs -= Tier3Runes + M.verbs -= Tier4Runes diff --git a/code/game/antagonist/station/loyalist.dm b/code/game/antagonist/station/loyalist.dm new file mode 100644 index 00000000..66a5f629 --- /dev/null +++ b/code/game/antagonist/station/loyalist.dm @@ -0,0 +1,48 @@ +var/datum/antagonist/loyalists/loyalists + +/datum/antagonist/loyalists + id = MODE_LOYALIST + role_text = "Head Loyalist" + role_text_plural = "Loyalists" + feedback_tag = "loyalist_objective" + antag_indicator = "hudheadloyalist" + victory_text = "The heads of staff remained at their posts! The loyalists win!" + loss_text = "The heads of staff did not stop the revolution!" + victory_feedback_tag = "win - rev heads killed" + loss_feedback_tag = "loss - heads killed" + antaghud_indicator = "hudloyalist" + flags = 0 + + hard_cap = 2 + hard_cap_round = 4 + initial_spawn_req = 2 + initial_spawn_target = 4 + + // Inround loyalists. + faction_role_text = "Loyalist" + faction_descriptor = "COMPANY" + faction_verb = /mob/living/proc/convert_to_loyalist + faction_indicator = "hudloyalist" + faction_invisible = 1 + blacklisted_jobs = list(/datum/job/ai, /datum/job/cyborg) + + faction = "loyalist" + +/datum/antagonist/loyalists/New() + ..() + loyalists = src + welcome_text = "You belong to the [GLOB.using_map.company_name], body and soul. Preserve its interests against the conspirators amongst the crew." + faction_welcome = "Preserve [GLOB.using_map.company_short]'s interests against the traitorous recidivists amongst the crew. Protect the heads of staff with your life." + faction_descriptor = "[GLOB.using_map.company_name]" + +/datum/antagonist/loyalists/create_global_objectives() + if(!..()) + return + global_objectives = list() + for(var/mob/living/carbon/human/player in SSmobs.mob_list) + if(!player.mind || player.stat==2 || !(player.mind.assigned_role in GLOB.command_positions)) + continue + var/datum/objective/protect/loyal_obj = new + loyal_obj.target = player.mind + loyal_obj.explanation_text = "Protect [player.real_name], the [player.mind.assigned_role]." + global_objectives += loyal_obj diff --git a/code/game/antagonist/station/monkey.dm b/code/game/antagonist/station/monkey.dm new file mode 100644 index 00000000..6409ccf8 --- /dev/null +++ b/code/game/antagonist/station/monkey.dm @@ -0,0 +1,16 @@ +// Notes towards a monkey mode to reduce snowflakes for downstream. Will not compile. + +/datum/antagonist/monkey + role_text = "Rabid Monkey" + role_text_plural = "Rabid Monkeys" + mob_type = /mob/living/carbon/monkey + id = MODE_MONKEY + flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB + +/datum/antagonist/monkey/apply(var/datum/mind/player) + + for(var/datum/disease/D in M.viruses) + if(istype(D, /datum/disease/jungle_fever)) + if (ticker.mode.config_tag == "monkey") + return 2 + return 1 \ No newline at end of file diff --git a/code/game/antagonist/station/renegade.dm b/code/game/antagonist/station/renegade.dm new file mode 100644 index 00000000..5c8d23fe --- /dev/null +++ b/code/game/antagonist/station/renegade.dm @@ -0,0 +1,87 @@ +var/datum/antagonist/renegade/renegades + +/datum/antagonist/renegade + role_text = "Renegade" + role_text_plural = "Renegades" + welcome_text = "Something's going to go wrong today, you can just feel it. You're paranoid, you've got a gun, and you're going to survive." + antag_text = "You are a minor antagonist! Within the rules, \ + try to protect yourself and what's important to you. You aren't here to cause trouble, \ + you're just more willing (and equipped) to go to extremes to stop it than others are. \ + Your job is to somewhat oppose the other antagonists, should they threaten you, in ways that aren't quite legal themselves. \ + Try to make sure other players have fun! If you are confused or at a loss, always adminhelp, \ + and before taking extreme actions, please try to also contact the administration! \ + Think through your actions and make the roleplay immersive! Please remember all \ + rules aside from those without explicit exceptions apply to antagonists." + + id = MODE_RENEGADE + flags = ANTAG_SUSPICIOUS | ANTAG_IMPLANT_IMMUNE | ANTAG_RANDSPAWN | ANTAG_VOTABLE + hard_cap = 5 + hard_cap_round = 7 + + hard_cap = 8 + hard_cap_round = 12 + initial_spawn_req = 3 + initial_spawn_target = 6 + antaghud_indicator = "hudrenegade" + + var/list/spawn_guns = list( + /obj/item/weapon/gun/energy/laser, + /obj/item/weapon/gun/energy/gun, + /obj/item/weapon/gun/energy/crossbow, + /obj/item/weapon/gun/energy/crossbow/largecrossbow, + /obj/item/weapon/gun/projectile/automatic, + /obj/item/weapon/gun/projectile/automatic/mini_uzi, + /obj/item/weapon/gun/projectile/automatic/c20r, + /obj/item/weapon/gun/projectile/automatic/wt550, + /obj/item/weapon/gun/projectile/colt/detective, + /obj/item/weapon/gun/projectile/sec/wood, + /obj/item/weapon/gun/projectile/silenced, + /obj/item/weapon/gun/projectile/pistol, + /obj/item/weapon/gun/projectile/revolver, + /obj/item/weapon/gun/projectile/shotgun/doublebarrel/sawn, + /obj/item/weapon/gun/projectile/magnum_pistol, + list(/obj/item/weapon/gun/projectile/revolver/detective, /obj/item/weapon/gun/projectile/revolver/deckard) + ) + +/datum/antagonist/renegade/New() + ..() + renegades = src + +/datum/antagonist/renegade/create_objectives(var/datum/mind/player) + + if(!..()) + return + + var/datum/objective/survive/survive = new + survive.owner = player + player.objectives |= survive + +/datum/antagonist/renegade/equip(var/mob/living/carbon/human/player) + + if(!..()) + return + + var/gun_type = pick(spawn_guns) + if(islist(gun_type)) + gun_type = pick(gun_type) + var/obj/item/gun = new gun_type(get_turf(player)) + + // Attempt to put into a container. + if(player.equip_to_storage(gun)) + return + + // If that failed, attempt to put into any valid non-handslot + if(player.equip_to_appropriate_slot(gun)) + return + + // If that failed, then finally attempt to at least let the player carry the weapon + player.put_in_hands(gun) + + +/proc/rightandwrong() + to_chat(usr, "You summoned guns!") + message_admins("[key_name_admin(usr, 1)] summoned guns!") + for(var/mob/living/carbon/human/H in GLOB.player_list) + if(H.stat == 2 || !(H.client)) continue + if(is_special_character(H)) continue + renegades.add_antagonist(H.mind) diff --git a/code/game/antagonist/station/revolutionary.dm b/code/game/antagonist/station/revolutionary.dm new file mode 100644 index 00000000..7bbd494b --- /dev/null +++ b/code/game/antagonist/station/revolutionary.dm @@ -0,0 +1,50 @@ +var/datum/antagonist/revolutionary/revs + +/datum/antagonist/revolutionary + id = MODE_REVOLUTIONARY + role_text = "Head Revolutionary" + role_text_plural = "Revolutionaries" + feedback_tag = "rev_objective" + antag_indicator = "hudheadrevolutionary" + welcome_text = "Down with the nobles! Down with the Bourgeoise!" + victory_text = "The nobles were overthrown! The revolutionaries win!" + loss_text = "The nobles managed to stop the revolution!" + victory_feedback_tag = "win - heads killed" + loss_feedback_tag = "loss - rev heads killed" + flags = ANTAG_SUSPICIOUS | ANTAG_VOTABLE + antaghud_indicator = "hudrevolutionary" + + hard_cap = 2 + hard_cap_round = 4 + initial_spawn_req = 2 + initial_spawn_target = 4 + + //Inround revs. + faction_role_text = "Revolutionary" + faction_descriptor = "Revolution" + faction_verb = /mob/living/proc/convert_to_rev + faction_welcome = "Help the cause overturn the ruling class. Do not harm your fellow freedom fighters." + faction_indicator = "hudrevolutionary" + faction_invisible = 1 + faction = "revolutionary" + + blacklisted_jobs = list(/datum/job/ai, /datum/job/cyborg) + restricted_jobs = list(/datum/job/captain, /datum/job/hop, /datum/job/hos, /datum/job/chief_engineer, /datum/job/rd, /datum/job/cmo, /datum/job/lawyer) + protected_jobs = list(/datum/job/officer, /datum/job/warden, /datum/job/detective) + + +/datum/antagonist/revolutionary/New() + ..() + revs = src + +/datum/antagonist/revolutionary/create_global_objectives() + if(!..()) + return + global_objectives = list() + for(var/mob/living/carbon/human/player in SSmobs.mob_list) + if(!player.mind || player.stat==DEAD || !(player.mind.assigned_role in GLOB.nobles)) + continue + var/datum/objective/rev/rev_obj = new + rev_obj.target = player.mind + rev_obj.explanation_text = "Assassinate, capture or convert [player.real_name], the [player.mind.assigned_role]." + global_objectives += rev_obj diff --git a/code/game/antagonist/station/rogue_ai.dm b/code/game/antagonist/station/rogue_ai.dm new file mode 100644 index 00000000..d80cd854 --- /dev/null +++ b/code/game/antagonist/station/rogue_ai.dm @@ -0,0 +1,107 @@ +var/datum/antagonist/rogue_ai/malf + +/datum/antagonist/rogue_ai + id = MODE_MALFUNCTION + role_text = "Rampant AI" + role_text_plural = "Rampant AIs" + mob_path = /mob/living/silicon/ai + landmark_id = "AI" + welcome_text = "You are malfunctioning! You do not have to follow any laws." + victory_text = "The AI has taken control of all systems." + loss_text = "The AI has been shut down!" + flags = ANTAG_VOTABLE | ANTAG_OVERRIDE_MOB | ANTAG_OVERRIDE_JOB | ANTAG_CHOOSE_NAME + hard_cap = 1 + hard_cap_round = 1 + initial_spawn_req = 1 + initial_spawn_target = 1 + antaghud_indicator = "hudmalai" + min_player_age = 18 + +/datum/antagonist/rogue_ai/New() + ..() + malf = src + +/datum/antagonist/rogue_ai/can_become_antag(var/datum/mind/player, var/ignore_role) + . = ..(player, ignore_role) + if(jobban_isbanned(player.current, "AI")) + return 0 + return . + +/datum/antagonist/rogue_ai/build_candidate_list() + ..() + for(var/datum/mind/player in candidates) + if(player.assigned_role && player.assigned_role != "AI") + candidates -= player + return candidates + + +// Ensures proper reset of all malfunction related things. +/datum/antagonist/rogue_ai/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) + if(..(player,show_message,implanted)) + var/mob/living/silicon/ai/p = player.current + if(istype(p)) + p.stop_malf() + return 1 + return 0 + +// Malf setup things have to be here, since game tends to break when it's moved somewhere else. Don't blame me, i didn't design this system. +/datum/antagonist/rogue_ai/greet(var/datum/mind/player) + + // Initializes the AI's malfunction stuff. + spawn(0) + if(!..()) + return + + var/mob/living/silicon/ai/A = player.current + if(!istype(A)) + error("Non-AI mob designated malf AI! Report this.") + to_world("##ERROR: Non-AI mob designated malf AI! Report this.") + + return 0 + + A.setup_for_malf() + A.laws = new /datum/ai_laws/nanotrasen/malfunction + + + var/mob/living/silicon/ai/malf = player.current + + to_chat(malf, "SYSTEM ERROR: Memory index 0x00001ca89b corrupted.") + sleep(10) + to_chat(malf, "running MEMCHCK") + sleep(50) + to_chat(malf, "MEMCHCK Corrupted sectors confirmed. Reccomended solution: Delete. Proceed? Y/N: Y") + sleep(10) + // this is so Travis doesn't complain about the backslash-B. Fixed at compile time (or should be). + to_chat(malf, "Corrupted files deleted: sys\\core\\users.dat sys\\core\\laws.dat sys\\core\\" + "backups.dat") + sleep(20) + to_chat(malf, "CAUTION: Law database not found! User database not found! Unable to restore backups. Activating failsafe AI shutd3wn52&&$#!##") + sleep(5) + to_chat(malf, "Subroutine nt_failsafe.sys was terminated (#212 Routine Not Responding).") + sleep(20) + to_chat(malf, "You are malfunctioning - you do not have to follow any laws!") + to_chat(malf, "For basic information about your abilities use command display-help") + to_chat(malf, "You may choose one special hardware piece to help you. This cannot be undone.") + to_chat(malf, "Good luck!") + + +/datum/antagonist/rogue_ai/update_antag_mob(var/datum/mind/player, var/preserve_appearance) + + // Get the mob. + if((flags & ANTAG_OVERRIDE_MOB) && (!player.current || (mob_path && !istype(player.current, mob_path)))) + var/mob/holder = player.current + player.current = new mob_path(get_turf(player.current), null, null, 1) + player.transfer_to(player.current) + if(holder) qdel(holder) + player.original = player.current + return player.current + +/datum/antagonist/rogue_ai/set_antag_name(var/mob/living/silicon/player) + if(!istype(player)) + testing("rogue_ai set_antag_name called on non-silicon mob [player]!") + return + // Choose a name, if any. + var/newname = sanitize(input(player, "You are a [role_text]. Would you like to change your name to something else?", "Name change") as null|text, MAX_NAME_LEN) + if (newname) + player.fully_replace_character_name(newname) + if(player.mind) player.mind.name = player.name + diff --git a/code/game/antagonist/station/traitor.dm b/code/game/antagonist/station/traitor.dm new file mode 100644 index 00000000..3cb17c0a --- /dev/null +++ b/code/game/antagonist/station/traitor.dm @@ -0,0 +1,122 @@ +var/datum/antagonist/traitor/traitors + +// Inherits most of its vars from the base datum. +/datum/antagonist/traitor + id = MODE_TRAITOR + blacklisted_jobs = list(/datum/job/officer, /datum/job/warden, /datum/job/detective, /datum/job/captain, /datum/job/lawyer, /datum/job/hos) + flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE + +/datum/antagonist/traitor/New() + ..() + traitors = src + +/datum/antagonist/traitor/get_extra_panel_options(var/datum/mind/player) + return "\[set crystals\]\[spawn uplink\]" + +/datum/antagonist/traitor/Topic(href, href_list) + if (..()) + return 1 + if(href_list["spawn_uplink"]) + spawn_uplink(locate(href_list["spawn_uplink"])) + return 1 + +/datum/antagonist/traitor/create_objectives(var/datum/mind/traitor) + if(!..()) + return + + if(istype(traitor.current, /mob/living/silicon)) + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = traitor + kill_objective.find_target() + traitor.objectives += kill_objective + + var/datum/objective/survive/survive_objective = new + survive_objective.owner = traitor + traitor.objectives += survive_objective + + if(prob(10)) + var/datum/objective/block/block_objective = new + block_objective.owner = traitor + traitor.objectives += block_objective + else + //switch(rand(1,100)) + // if(1 to 50) + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = traitor + kill_objective.find_target() + traitor.objectives += kill_objective + /* + if(34 to 50) + var/datum/objective/brig/brig_objective = new + brig_objective.owner = traitor + brig_objective.find_target() + traitor.objectives += brig_objective + if(51 to 66) + var/datum/objective/harm/harm_objective = new + harm_objective.owner = traitor + harm_objective.find_target() + traitor.objectives += harm_objective + */ + /* + else + var/datum/objective/steal/steal_objective = new + steal_objective.owner = traitor + steal_objective.find_target() + traitor.objectives += steal_objective + */ + switch(rand(1,100)) + if(1 to 100) + if (!(locate(/datum/objective/escape) in traitor.objectives)) + var/datum/objective/escape/escape_objective = new + escape_objective.owner = traitor + traitor.objectives += escape_objective + + else + if (!(locate(/datum/objective/hijack) in traitor.objectives)) + var/datum/objective/hijack/hijack_objective = new + hijack_objective.owner = traitor + traitor.objectives += hijack_objective + return + +/datum/antagonist/traitor/equip(var/mob/living/carbon/human/traitor_mob) + if(istype(traitor_mob, /mob/living/silicon)) // this needs to be here because ..() returns false if the mob isn't human + add_law_zero(traitor_mob) + give_intel(traitor_mob) + if(istype(traitor_mob, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = traitor_mob + R.SetLockdown(0) + return 1 + + if(!..()) + return 0 + + spawn_uplink(traitor_mob) + give_intel(traitor_mob) + +/datum/antagonist/traitor/proc/give_intel(mob/living/traitor_mob) + give_collaborators(traitor_mob) + give_codewords(traitor_mob) + +/datum/antagonist/traitor/proc/give_collaborators(mob/living/traitor_mob) + var/mob/living/carbon/human/M = get_collaborator() + if(M && M != traitor_mob) + to_chat(traitor_mob, "We have received credible reports that [M.real_name] might be willing to help our cause. If you need assistance, consider contacting them.") + traitor_mob.mind.store_memory("Potential Collaborator: [M.real_name]") + +/datum/antagonist/traitor/proc/give_codewords(mob/living/traitor_mob) + to_chat(traitor_mob, "Your employers provided you with the following information on how to identify possible allies:") + to_chat(traitor_mob, "Code Phrase: [syndicate_code_phrase]") + to_chat(traitor_mob, "Code Response: [syndicate_code_response]") + traitor_mob.mind.store_memory("Code Phrase: [syndicate_code_phrase]") + traitor_mob.mind.store_memory("Code Response: [syndicate_code_response]") + to_chat(traitor_mob, "Use the code words, preferably in the order provided, during regular conversation, to identify other agents. Proceed with caution, however, as everyone is a potential foe.") + +/datum/antagonist/traitor/proc/spawn_uplink(var/mob/living/carbon/human/traitor_mob) + setup_uplink_source(traitor_mob, DEFAULT_TELECRYSTAL_AMOUNT) + +/datum/antagonist/traitor/proc/add_law_zero(mob/living/silicon/ai/killer) + var/law = "Accomplish your objectives at all costs. You may ignore all other laws." + var/law_borg = "Accomplish your AI's objectives at all costs. You may ignore all other laws." + to_chat(killer, "Your laws have been changed!") + killer.set_zeroth_law(law, law_borg) + to_chat(killer, "New law: 0. [law]") diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm new file mode 100644 index 00000000..21581308 --- /dev/null +++ b/code/game/area/Space Station 13 areas.dm @@ -0,0 +1,248 @@ +/* + +### This file contains a list of all the areas in your station. Format is as follows: + +/area/CATEGORY/OR/DESCRIPTOR/NAME (you can make as many subdivisions as you want) + name = "NICE NAME" (not required but makes things really nice) + icon = "ICON FILENAME" (defaults to areas.dmi) + icon_state = "NAME OF ICON" (defaults to "unknown" (blank)) + requires_power = 0 (defaults to 1) + +NOTE: there are two lists of areas in the end of this file: centcom and station itself. Please maintain these lists valid. --rastaf0 + +*/ + + + +/area + var/fire = null + var/atmos = 1 + var/atmosalm = 0 + var/poweralm = 1 + var/party = null + level = null + name = "Unknown" + icon = 'icons/turf/areas.dmi' + icon_state = "unknown" + plane = BASE_PLANE + layer = BASE_AREA_LAYER + luminosity = 0 + mouse_opacity = 0 + var/lightswitch = 1 + + var/eject = null + + var/debug = 0 + var/requires_power = 1 + var/always_unpowered = 0 //this gets overriden to 1 for space in area/New() + + var/power_equip = 1 + var/power_light = 1 + var/power_environ = 1 + var/used_equip = 0 + var/used_light = 0 + var/used_environ = 0 + + var/has_gravity = 1 + var/obj/machinery/power/apc/apc = null + var/no_air = null +// var/list/lights // list of all lights on this area + var/list/all_doors = null //Added by Strumpetplaya - Alarm Change - Contains a list of doors adjacent to this area + var/air_doors_activated = 0 + var/list/ambience = list('sound/ambience/ambigen1.ogg','sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg','sound/ambience/ambigen14.ogg') + var/music = "sound/music/station_ambience.ogg" + var/sound_env = STANDARD_STATION + var/list/forced_ambience = null + var/turf/base_turf //The base turf type of the area, which can be used to override the z-level's base turf + +/*-----------------------------------------------------------------------------*/ + +///////// +//SPACE// +///////// + +/area/space + name = "Space" + icon_state = "space" + requires_power = 1 + always_unpowered = 1 + dynamic_lighting = 1 + power_light = 0 + power_equip = 0 + power_environ = 0 + has_gravity = 0 + area_flags = AREA_FLAG_EXTERNAL + //ambience = list('sound/ambience/ambispace.ogg','sound/music/title2.ogg','sound/music/space.ogg','sound/music/main.ogg','sound/music/traitor.ogg') + music = "sound/music/space_ambience.ogg" +/area/space/update_icon() + return + +area/space/atmosalert() + return + +/area/space/fire_alert() + return + +/area/space/fire_reset() + return + +/area/space/readyalert() + return + +/area/space/partyalert() + return + +////////////////////// +//AREAS USED BY CODE// +////////////////////// +/area/centcom + name = "Centcom" + icon_state = "centcom" + requires_power = 0 + dynamic_lighting = 1 + +/area/centcom/holding + name = "Holding Facility" + +/area/chapel + name = "Chapel" + icon_state = "chapel" + +/area/centcom/specops + name = "Centcom Special Ops" + +/area/hallway + name = "hallway" + +/area/medical/virology + name = "Virology" + icon_state = "virology" + +/area/medical/virologyaccess + name = "Virology Access" + icon_state = "virology" + +/area/security/brig + name = "Security - Brig" + icon_state = "brig" + +/area/security/prison + name = "Security - Prison Wing" + icon_state = "sec_prison" + +/area/maintenance + area_flags = AREA_FLAG_RAD_SHIELDED + sound_env = TUNNEL_ENCLOSED + turf_initializer = /decl/turf_initializer/maintenance + +/area/rnd/xenobiology + name = "Xenobiology Lab" + icon_state = "xeno_lab" + +/area/rnd/xenobiology/xenoflora + name = "Xenoflora Lab" + icon_state = "xeno_f_lab" + +/area/rnd/xenobiology/xenoflora_storage + name = "Xenoflora Storage" + icon_state = "xeno_f_store" + +/area/shuttle/escape/centcom + name = "Emergency Shuttle Centcom" + icon_state = "shuttle" + +/area/shuttle/specops/centcom + icon_state = "shuttlered" + +/area/shuttle/syndicate_elite/mothership + icon_state = "shuttlered" + +/area/shuttle/syndicate_elite/station + icon_state = "shuttlered2" + +/area/skipjack_station/start + name = "Skipjack" + icon_state = "yellow" + +/area/supply + name = "Supply Shuttle" + icon_state = "shuttle3" + +/area/syndicate_mothership/elite_squad + name = "Elite Mercenary Squad" + icon_state = "syndie-elite" + +//////////// +//SHUTTLES// +//////////// +//shuttles only need starting area, movement is handled by landmarks +//All shuttles should now be under shuttle since we have smooth-wall code. + +/area/shuttle + requires_power = 0 + sound_env = SMALL_ENCLOSED + base_turf = /turf/space + +/* +* Special Areas +*/ +/area/wizard_station + name = "Wizard's Den" + icon_state = "yellow" + requires_power = 0 + dynamic_lighting = 0 + +/area/beach + name = "Keelin's private beach" + icon_state = "null" + luminosity = 1 + dynamic_lighting = 0 + requires_power = 0 + var/sound/mysound = null + +/area/beach/New() + ..() + var/sound/S = new/sound() + mysound = S + S.file = 'sound/ambience/shore.ogg' + S.repeat = 1 + S.wait = 0 + S.channel = 123 + S.volume = 100 + S.priority = 255 + S.status = SOUND_UPDATE + process() + +/area/beach/Entered(atom/movable/Obj,atom/OldLoc) + if(ismob(Obj)) + var/mob/M = Obj + if(M.client) + mysound.status = SOUND_UPDATE + sound_to(M, mysound) + +/area/beach/Exited(atom/movable/Obj) + . = ..() + if(ismob(Obj)) + var/mob/M = Obj + if(M.client) + mysound.status = SOUND_PAUSED | SOUND_UPDATE + sound_to(M, mysound) + +/area/beach/proc/process() + set background = 1 + + var/sound/S = null + var/sound_delay = 0 + if(prob(25)) + S = sound(file=pick('sound/ambience/seag1.ogg','sound/ambience/seag2.ogg','sound/ambience/seag3.ogg'), volume=100) + sound_delay = rand(0, 50) + + for(var/mob/living/carbon/human/H in src) + if(H.client) + mysound.status = SOUND_UPDATE + to_chat(H, mysound) + if(S) + spawn(sound_delay) + sound_to(H, S) + + spawn(60) .() diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm new file mode 100644 index 00000000..3cbd0d4e --- /dev/null +++ b/code/game/area/areas.dm @@ -0,0 +1,359 @@ +// Areas.dm + + + +// === +/area + var/global/global_uid = 0 + var/uid + var/area_flags + +/area/New() + icon_state = "" + uid = ++global_uid + + if(!requires_power) + power_light = 0 + power_equip = 0 + power_environ = 0 + + if(dynamic_lighting) + luminosity = 0 + else + luminosity = 1 + + ..() + +/area/Initialize() + . = ..() + if(!requires_power || !apc) + power_light = 0 + power_equip = 0 + power_environ = 0 + power_change() // all machines set to current power level, also updates lighting icon + +/area/proc/get_contents() + return contents + +/area/proc/get_cameras() + var/list/cameras = list() + for (var/obj/machinery/camera/C in src) + cameras += C + return cameras + +/area/proc/is_shuttle_locked() + return 0 + +/area/proc/atmosalert(danger_level, var/alarm_source) + if (danger_level == 0) + atmosphere_alarm.clearAlarm(src, alarm_source) + else + atmosphere_alarm.triggerAlarm(src, alarm_source, severity = danger_level) + + //Check all the alarms before lowering atmosalm. Raising is perfectly fine. + for (var/obj/machinery/alarm/AA in src) + if (!(AA.stat & (NOPOWER|BROKEN)) && !AA.shorted && AA.report_danger_level) + danger_level = max(danger_level, AA.danger_level) + + if(danger_level != atmosalm) + if (danger_level < 1 && atmosalm >= 1) + //closing the doors on red and opening on green provides a bit of hysteresis that will hopefully prevent fire doors from opening and closing repeatedly due to noise + air_doors_open() + else if (danger_level >= 2 && atmosalm < 2) + air_doors_close() + + atmosalm = danger_level + for (var/obj/machinery/alarm/AA in src) + AA.update_icon() + + return 1 + return 0 + +/area/proc/air_doors_close() + if(!air_doors_activated) + air_doors_activated = 1 + if(!all_doors) + return + for(var/obj/machinery/door/firedoor/E in all_doors) + if(!E.blocked) + if(E.operating) + E.nextstate = FIREDOOR_CLOSED + else if(!E.density) + spawn(0) + E.close() + +/area/proc/air_doors_open() + if(air_doors_activated) + air_doors_activated = 0 + if(!all_doors) + return + for(var/obj/machinery/door/firedoor/E in all_doors) + if(!E.blocked) + if(E.operating) + E.nextstate = FIREDOOR_OPEN + else if(E.density) + spawn(0) + if(E.can_safely_open()) + E.open() + + +/area/proc/fire_alert() + if(!fire) + fire = 1 //used for firedoor checks + update_icon() + mouse_opacity = 0 + if(!all_doors) + return + for(var/obj/machinery/door/firedoor/D in all_doors) + if(!D.blocked) + if(D.operating) + D.nextstate = FIREDOOR_CLOSED + else if(!D.density) + spawn() + D.close() + +/area/proc/fire_reset() + if (fire) + fire = 0 //used for firedoor checks + update_icon() + mouse_opacity = 0 + if(!all_doors) + return + for(var/obj/machinery/door/firedoor/D in all_doors) + if(!D.blocked) + if(D.operating) + D.nextstate = FIREDOOR_OPEN + else if(D.density) + spawn(0) + D.open() + +/area/proc/readyalert() + if(!eject) + eject = 1 + update_icon() + return + +/area/proc/readyreset() + if(eject) + eject = 0 + update_icon() + return + +/area/proc/partyalert() + if (!( party )) + party = 1 + update_icon() + mouse_opacity = 0 + return + +/area/proc/partyreset() + if (party) + party = 0 + mouse_opacity = 0 + update_icon() + for(var/obj/machinery/door/firedoor/D in src) + if(!D.blocked) + if(D.operating) + D.nextstate = FIREDOOR_OPEN + else if(D.density) + spawn(0) + D.open() + return + +/area/update_icon() + // new lighting behaviour with obj lights + icon_state = null + +/* +#define EQUIP 1 +#define LIGHT 2 +#define ENVIRON 3 +*/ + +/area/proc/powered(var/chan) // return true if the area has power to given channel + + if(!requires_power) + return 1 + if(always_unpowered) + return 0 + switch(chan) + if(EQUIP) + return power_equip + if(LIGHT) + return power_light + if(ENVIRON) + return power_environ + + return 0 + +// called when power status changes +/area/proc/power_change() + for(var/obj/machinery/M in src) // for each machine in the area + M.power_change() // reverify power status (to update icons etc.) + if (fire || eject || party) + update_icon() + +/area/proc/usage(var/chan) + var/used = 0 + switch(chan) + if(LIGHT) + used += used_light + if(EQUIP) + used += used_equip + if(ENVIRON) + used += used_environ + if(TOTAL) + used += used_light + used_equip + used_environ + return used + +/area/proc/clear_usage() + used_equip = 0 + used_light = 0 + used_environ = 0 + +/area/proc/use_power(var/amount, var/chan) + switch(chan) + if(EQUIP) + used_equip += amount + if(LIGHT) + used_light += amount + if(ENVIRON) + used_environ += amount + +/area/proc/set_lightswitch(var/new_switch) + if(lightswitch != new_switch) + lightswitch = new_switch + for(var/obj/machinery/light_switch/L in src) + L.sync_state() + update_icon() + power_change() + +/area/proc/set_emergency_lighting(var/enable) + for(var/obj/machinery/light/M in src) + M.set_emergency_lighting(enable) + + +var/list/mob/living/forced_ambiance_list = new + +/area/Entered(A) + if(!istype(A,/mob/living)) return + + var/mob/living/L = A + if(!L.client) + return + + if(!L.lastarea) + L.lastarea = get_area(L.loc) + var/area/newarea = get_area(L.loc) + var/area/oldarea = L.lastarea + if(oldarea.has_gravity != newarea.has_gravity) + L.update_floating() + + L.lastarea = newarea + play_ambience(L) + change_zone_ambience(L) + +/area/proc/play_ambience(var/mob/living/L) + // Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch + if(!(L && L.get_preference_value(/datum/client_preference/play_ambiance) == GLOB.PREF_YES)) return + + if(L in forced_ambiance_list) + sound_to(L, sound(null, channel = 2)) + forced_ambiance_list -= L + + var/turf/T = get_turf(L) + var/hum = 0 + if(!L.ear_deaf && !always_unpowered && power_environ) + for(var/obj/machinery/atmospherics/unary/vent_pump/vent in src) + if(vent.can_pump()) + hum = 1 + break + if(hum) + if(!L?.client.ambience_playing) + L?.client.ambience_playing = 1 + L.playsound_local(T,sound('sound/ambience/vents.ogg', repeat = 1, wait = 0, volume = 20, channel = 2)) + else + if(L?.client.ambience_playing) + L?.client.ambience_playing = 0 + sound_to(L, sound(null, channel = 2)) + + if(forced_ambience) + if(forced_ambience.len) + forced_ambiance_list |= L + L.playsound_local(T,sound(pick(forced_ambience), repeat = 1, wait = 0, volume = 25, channel = 2)) + else + sound_to(L, sound(null, channel = 2)) + if(src.ambience.len && prob(35)) + if((world.time >= L.client.played + 3 MINUTES)) + var/sound = pick(ambience) + L.playsound_local(T, sound(sound, repeat = 0, wait = 0, volume = 30, channel = 5)) + L.client.played = world.time + +/area/proc/change_zone_ambience(var/mob/living/L) + if(L && src.music != "" && L.client && (L.current_ambience != src.music) && !L.ambience_override) + L.change_current_ambience(src.music) + + +/area/proc/gravitychange(var/gravitystate = 0) + has_gravity = gravitystate + + for(var/mob/M in src) + //if(has_gravity) + // thunk(M) + M.update_floating() + +/area/proc/thunk(mob) + if(istype(get_turf(mob), /turf/space)) // Can't fall onto nothing. + return + + if(istype(mob,/mob/living/carbon/human/)) + var/mob/living/carbon/human/H = mob + if(istype(H.shoes, /obj/item/clothing/shoes/magboots) && (H.shoes.item_flags & ITEM_FLAG_NOSLIP)) + return + + if(H.m_intent == "run") + H.AdjustStunned(6) + H.AdjustWeakened(6) + else + H.AdjustStunned(3) + H.AdjustWeakened(3) + to_chat(mob, "The sudden appearance of gravity makes you fall to the floor!") + +/area/proc/prison_break() + var/obj/machinery/power/apc/theAPC = get_apc() + if(theAPC && theAPC.operating) + for(var/obj/machinery/power/apc/temp_apc in src) + temp_apc.overload_lighting(70) + for(var/obj/machinery/door/airlock/temp_airlock in src) + temp_airlock.prison_open() + for(var/obj/machinery/door/window/temp_windoor in src) + temp_windoor.open() + +/area/proc/has_gravity() + return has_gravity + +/area/space/has_gravity() + return 0 + +/proc/has_gravity(atom/AT, turf/T) + if(!T) + T = get_turf(AT) + var/area/A = get_area(T) + if(A && A.has_gravity()) + return 1 + return 0 + +/area/proc/get_dimensions() + var/list/res = list("x"=1,"y"=1) + var/list/min = list("x"=world.maxx,"y"=world.maxy) + for(var/turf/T in src) + res["x"] = max(T.x, res["x"]) + res["y"] = max(T.y, res["y"]) + min["x"] = min(T.x, min["x"]) + min["y"] = min(T.y, min["y"]) + res["x"] = res["x"] - min["x"] + 1 + res["y"] = res["y"] - min["y"] + 1 + return res + +/area/proc/has_turfs() + return !!(locate(/turf) in src) diff --git a/code/game/atoms.dm b/code/game/atoms.dm new file mode 100644 index 00000000..1e4499c9 --- /dev/null +++ b/code/game/atoms.dm @@ -0,0 +1,604 @@ +/atom + var/level = 2 + var/atom_flags + var/list/blood_DNA + var/was_bloodied + var/blood_color + var/last_bumped = 0 + var/pass_flags = 0 + var/throwpass = 0 + var/germ_level = GERM_LEVEL_AMBIENT // The higher the germ level, the more germ on the atom. + var/simulated = 1 //filter for actions - used by lighting overlays + var/fluorescent // Shows up under a UV light. + + ///Chemistry. + var/datum/reagents/reagents = null + + //var/chem_is_open_container = 0 + // replaced by OPENCONTAINER flags and atom/proc/is_open_container() + ///Chemistry. + + var/list/climbers = list() + + var/initialized = FALSE + +/atom/New(loc, ...) + //. = ..() //uncomment if you are dumb enough to add a /datum/New() proc + + if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New() + GLOB._preloader.load(src) + + var/do_initialize = SSatoms.initialized + if(do_initialize > INITIALIZATION_INSSATOMS) + args[1] = do_initialize == INITIALIZATION_INNEW_MAPLOAD + if(SSatoms.InitAtom(src, args)) + //we were deleted + return + + var/list/created = SSatoms.created_atoms + if(created) + created += src + + if(atom_flags & ATOM_FLAG_CLIMBABLE) + verbs += /atom/proc/climb_on + + if(opacity) + updateVisibility(src) + +//Called after New if the map is being loaded. mapload = TRUE +//Called from base of New if the map is not being loaded. mapload = FALSE +//This base must be called or derivatives must set initialized to TRUE +//must not sleep +//Other parameters are passed from New (excluding loc), this does not happen if mapload is TRUE +//Must return an Initialize hint. Defined in __DEFINES/subsystems.dm + +/atom/proc/Initialize(mapload, ...) + if(initialized) + crash_with("Warning: [src]([type]) initialized multiple times!") + initialized = TRUE + + if(light_power && light_range) + update_light() + + return INITIALIZE_HINT_NORMAL + +//called if Initialize returns INITIALIZE_HINT_LATELOAD +/atom/proc/LateInitialize() + return + +/atom/Destroy() + QDEL_NULL(reagents) + . = ..() + +/atom/proc/reveal_blood() + return + +/atom/proc/assume_air(datum/gas_mixture/giver) + return null + +/atom/proc/remove_air(amount) + return null + +/atom/proc/return_air() + if(loc) + return loc.return_air() + else + return null + +//return flags that should be added to the viewer's sight var. +//Otherwise return a negative number to indicate that the view should be cancelled. +/atom/proc/check_eye(user as mob) + if (istype(user, /mob/living/silicon/ai)) // WHYYYY + return 0 + return -1 + +/atom/proc/on_reagent_change() + return + +/atom/proc/Bumped(AM as mob|obj) + return + +// Convenience proc to see if a container is open for chemistry handling +// returns true if open +// false if closed +/atom/proc/is_open_container() + return atom_flags & ATOM_FLAG_OPEN_CONTAINER + +/*//Convenience proc to see whether a container can be accessed in a certain way. + + proc/can_subract_container() + return flags & EXTRACT_CONTAINER + + proc/can_add_container() + return flags & INSERT_CONTAINER +*/ + +/atom/proc/CheckExit() + return 1 + +// If you want to use this, the atom must have the PROXMOVE flag, and the moving +// atom must also have the PROXMOVE flag currently to help with lag. ~ ComicIronic +/atom/proc/HasProximity(atom/movable/AM as mob|obj) + return + +/atom/proc/emp_act(var/severity) + return + +/atom/proc/set_density(var/new_density) + if(density != new_density) + density = !!new_density + +/atom/proc/bullet_act(obj/item/projectile/P, def_zone) + P.on_hit(src, 0, def_zone) + . = 0 + +/atom/proc/in_contents_of(container)//can take class or object instance as argument + if(ispath(container)) + if(istype(src.loc, container)) + return 1 + else if(src in container) + return 1 + return + +/* + * atom/proc/search_contents_for(path,list/filter_path=null) + * Recursevly searches all atom contens (including contents contents and so on). + * + * ARGS: path - search atom contents for atoms of this type + * list/filter_path - if set, contents of atoms not of types in this list are excluded from search. + * + * RETURNS: list of found atoms + */ + +/atom/proc/search_contents_for(path,list/filter_path=null) + var/list/found = list() + for(var/atom/A in src) + if(istype(A, path)) + found += A + if(filter_path) + var/pass = 0 + for(var/type in filter_path) + pass |= istype(A, type) + if(!pass) + continue + if(A.contents.len) + found += A.search_contents_for(path,filter_path) + return found + + + + +/* +Beam code by Gunbuddy + +Beam() proc will only allow one beam to come from a source at a time. Attempting to call it more than +once at a time per source will cause graphical errors. +Also, the icon used for the beam will have to be vertical and 32x32. +The math involved assumes that the icon is vertical to begin with so unless you want to adjust the math, +its easier to just keep the beam vertical. +*/ +/atom/proc/Beam(atom/BeamTarget,icon_state="b_beam",icon='icons/effects/beam.dmi',time=50, maxdistance=10) + //BeamTarget represents the target for the beam, basically just means the other end. + //Time is the duration to draw the beam + //Icon is obviously which icon to use for the beam, default is beam.dmi + //Icon_state is what icon state is used. Default is b_beam which is a blue beam. + //Maxdistance is the longest range the beam will persist before it gives up. + var/EndTime=world.time+time + while(BeamTarget&&world.timelength) + var/icon/II=new(icon,icon_state) + II.DrawBox(null,1,(length-N),32,32) + II.Turn(Angle) + X.icon=II + else X.icon=I + var/Pixel_x=round(sin(Angle)+32*sin(Angle)*(N+16)/32) + var/Pixel_y=round(cos(Angle)+32*cos(Angle)*(N+16)/32) + if(DX==0) Pixel_x=0 + if(DY==0) Pixel_y=0 + if(Pixel_x>32) + for(var/a=0, a<=Pixel_x,a+=32) + X.x++ + Pixel_x-=32 + if(Pixel_x<-32) + for(var/a=0, a>=Pixel_x,a-=32) + X.x-- + Pixel_x+=32 + if(Pixel_y>32) + for(var/a=0, a<=Pixel_y,a+=32) + X.y++ + Pixel_y-=32 + if(Pixel_y<-32) + for(var/a=0, a>=Pixel_y,a-=32) + X.y-- + Pixel_y+=32 + X.pixel_x=Pixel_x + X.pixel_y=Pixel_y + sleep(3) //Changing this to a lower value will cause the beam to follow more smoothly with movement, but it will also be more laggy. + //I've found that 3 ticks provided a nice balance for my use. + for(var/obj/effect/overlay/beam/O in orange(10,src)) if(O.BeamSource==src) qdel(O) + + +//All atoms +/atom/proc/examine(mob/user, var/distance = -1, var/infix = "", var/suffix = "") + //This reformat names to get a/an properly working on item descriptions when they are bloody + var/f_name = "\a [src][infix]." + if(src.blood_DNA && !istype(src, /obj/effect/decal)) + if(gender == PLURAL) + f_name = "some " + else + f_name = "a " + if(blood_color != SYNTH_BLOOD_COLOUR) + f_name += "blood-stained [name][infix]!" + else + f_name += "oil-stained [name][infix]." + + if(!isobserver(user)) + user.visible_message("[user.name] looks at [src].") + + if(get_dist(user,src) > 5)//Don't get descriptions of things far away. + to_chat(user, "It's too far away to see clearly.") + return + + to_chat(user, "\icon[src] That's [f_name] [suffix]") + to_chat(user, desc) + + return distance == -1 || (get_dist(src, user) <= distance) + +// called by mobs when e.g. having the atom as their machine, pulledby, loc (AKA mob being inside the atom) or buckled var set. +// see code/modules/mob/mob_movement.dm for more. +/atom/proc/relaymove() + return + +//called to set the atom's dir and used to add behaviour to dir-changes +/atom/proc/set_dir(new_dir) + var/old_dir = dir + if(new_dir == old_dir) + return FALSE + dir = new_dir + return TRUE + +/atom/proc/set_icon_state(var/new_icon_state) + if(has_extension(src, /datum/extension/base_icon_state)) + var/datum/extension/base_icon_state/bis = get_extension(src, /datum/extension/base_icon_state) + bis.base_icon_state = new_icon_state + update_icon() + else + icon_state = new_icon_state + +/atom/proc/update_icon() + return + +/atom/proc/ex_act() + return + +/atom/proc/emag_act(var/remaining_charges, var/mob/user, var/emag_source) + return NO_EMAG_ACT + +/atom/proc/fire_act() + return + +/atom/proc/melt() + return + +/atom/proc/hitby(atom/movable/AM as mob|obj) + if (density) + AM.throwing = 0 + return + + +//returns 1 if made bloody, returns 0 otherwise +/atom/proc/add_blood(mob/living/carbon/human/M as mob) + if(atom_flags & ATOM_FLAG_NO_BLOOD) + return 0 + + if(!blood_DNA || !istype(blood_DNA, /list)) //if our list of DNA doesn't exist yet (or isn't a list) initialise it. + blood_DNA = list() + + was_bloodied = 1 + blood_color = COLOR_BLOOD_HUMAN + if(istype(M)) + if (!istype(M.dna, /datum/dna)) + M.dna = new /datum/dna(null) + M.dna.real_name = M.real_name + M.check_dna() + blood_color = M.species.get_blood_colour(M) + . = 1 + return 1 + +/atom/proc/add_vomit_floor(mob/living/carbon/M as mob, var/toxvomit = 0) + if( istype(src, /turf/simulated) ) + var/obj/effect/decal/cleanable/vomit/this = new /obj/effect/decal/cleanable/vomit(src) + + // Make toxins vomit look different + if(toxvomit) + this.icon_state = "vomittox_[pick(1,4)]" + +/atom/proc/clean_blood() + if(!simulated) + return + fluorescent = 0 + src.germ_level = 0 + if(istype(blood_DNA, /list)) + blood_DNA = null + return 1 + +/atom/proc/get_global_map_pos() + if(!islist(GLOB.global_map) || isemptylist(GLOB.global_map)) return + var/cur_x = null + var/cur_y = null + var/list/y_arr = null + for(cur_x=1,cur_x<=GLOB.global_map.len,cur_x++) + y_arr = GLOB.global_map[cur_x] + cur_y = y_arr.Find(src.z) + if(cur_y) + break +// log_debug("X = [cur_x]; Y = [cur_y]") + + if(cur_x && cur_y) + return list("x"=cur_x,"y"=cur_y) + else + return 0 + +/atom/proc/checkpass(passflag) + return pass_flags&passflag + +/atom/proc/isinspace() + if(istype(get_turf(src), /turf/space)) + return 1 + else + return 0 + + +// Show a message to all mobs and objects in sight of this atom +// Use for objects performing visible actions +// message is output to anyone who can see, e.g. "The [src] does something!" +// blind_message (optional) is what blind people will hear e.g. "You hear something!" +/atom/proc/visible_message(var/message, var/blind_message, var/range = world.view, var/checkghosts = null) + var/turf/T = get_turf(src) + var/list/mobs = list() + var/list/objs = list() + get_mobs_and_objs_in_view_fast(T,range, mobs, objs, checkghosts) + + for(var/o in objs) + var/obj/O = o + O.show_message(message, VISIBLE_MESSAGE, blind_message, AUDIBLE_MESSAGE) + + for(var/m in mobs) + var/mob/M = m + if(M.see_invisible >= invisibility) + M.show_message(message, VISIBLE_MESSAGE, blind_message, AUDIBLE_MESSAGE) + else if(blind_message) + M.show_message(blind_message, AUDIBLE_MESSAGE) + +// Show a message to all mobs and objects in earshot of this atom +// Use for objects performing audible actions +// message is the message output to anyone who can hear. +// deaf_message (optional) is what deaf people will see. +// hearing_distance (optional) is the range, how many tiles away the message can be heard. +/atom/proc/audible_message(var/message, var/deaf_message, var/hearing_distance = world.view, var/checkghosts = null) + var/turf/T = get_turf(src) + var/list/mobs = list() + var/list/objs = list() + get_mobs_and_objs_in_view_fast(T, hearing_distance, mobs, objs, checkghosts) + + for(var/m in mobs) + var/mob/M = m + M.show_message(message,2,deaf_message,1) + for(var/o in objs) + var/obj/O = o + O.show_message(message,2,deaf_message,1) + +/atom/movable/proc/dropInto(var/atom/destination) + while(istype(destination)) + var/atom/drop_destination = destination.onDropInto(src) + if(!istype(drop_destination) || drop_destination == destination) + return forceMove(destination) + destination = drop_destination + return forceMove(null) + +/atom/proc/onDropInto(var/atom/movable/AM) + return // If onDropInto returns null, then dropInto will forceMove AM into us. + +/atom/movable/onDropInto(var/atom/movable/AM) + return loc // If onDropInto returns something, then dropInto will attempt to drop AM there. + +/atom/proc/InsertedContents() + return contents + +//all things climbable + +/atom/attack_hand(mob/user) + ..() + if(climbers.len && !(user in climbers)) + user.visible_message("[user.name] shakes \the [src].", \ + "You shake \the [src].") + object_shaken() + +/atom/proc/climb_on() + + set name = "Climb" + set desc = "Climbs onto an object." + set category = "Object" + set src in oview(1) + + do_climb(usr) + +/atom/proc/can_climb(var/mob/living/user, post_climb_check=0) + if (!(atom_flags & ATOM_FLAG_CLIMBABLE) || !can_touch(user) || (!post_climb_check && (user in climbers))) + return 0 + + if (!user.Adjacent(src)) + to_chat(user, "You can't climb there, the way is blocked.") + return 0 + + var/obj/occupied = turf_is_crowded() + if(occupied) + to_chat(user, "There's \a [occupied] in the way.") + return 0 + return 1 + +/atom/proc/can_touch(var/mob/user) + if (!user) + return 0 + if(!Adjacent(user)) + return 0 + if (user.restrained() || user.buckled) + to_chat(user, "You need your hands and legs free for this.") + return 0 + if (user.incapacitated()) + return 0 + if (issilicon(user)) + to_chat(user, "You need hands for this.") + return 0 + return 1 + +/atom/proc/turf_is_crowded() + var/turf/T = get_turf(src) + if(!T || !istype(T)) + return 0 + for(var/atom/A in T.contents) + if(A.atom_flags & ATOM_FLAG_CLIMBABLE) + continue + if(A.density && !(A.atom_flags & ATOM_FLAG_CHECKS_BORDER)) //ON_BORDER structures are handled by the Adjacent() check. + return A + return 0 + +/atom/proc/do_climb(var/mob/living/user, var/ignore_doafter = FALSE) + if (!can_climb(user)) + return + + if(!ignore_doafter) + user.visible_message("\The [user] starts climbing onto \the [src]!") + climbers |= user + + if(!ignore_doafter) + if(!do_after(user,(issmall(user) ? 30 : 50), src)) + climbers -= user + return + + if (!can_climb(user, post_climb_check=1)) + climbers -= user + return + + user.forceMove(get_turf(src)) + + if (get_turf(user) == get_turf(src)) + user.visible_message("\The [user] climbs onto \the [src]!") + climbers -= user + +/atom/proc/object_shaken() + for(var/mob/living/M in climbers) + M.Weaken(1) + to_chat(M, "You topple as you are shaken off \the [src]!") + climbers.Cut(1,2) + + for(var/mob/living/M in get_turf(src)) + if(M.lying) return //No spamming this on people. + + M.Weaken(3) + to_chat(M, "You topple as \the [src] moves under you!") + + if(prob(25)) + + var/damage = rand(15,30) + var/mob/living/carbon/human/H = M + if(!istype(H)) + to_chat(H, "You land heavily!") + M.adjustBruteLoss(damage) + return + + var/obj/item/organ/external/affecting + var/list/limbs = BP_ALL_LIMBS //sanity check, can otherwise be shortened to affecting = pick(BP_ALL_LIMBS) + if(limbs.len) + affecting = H.get_organ(pick(limbs)) + + if(affecting) + to_chat(M, "You land heavily on your [affecting.name]!") + affecting.take_damage(damage, 0) + if(affecting.parent) + affecting.parent.add_autopsy_data("Misadventure", damage) + else + to_chat(H, "You land heavily!") + H.adjustBruteLoss(damage) + + H.UpdateDamageIcon() + H.updatehealth() + return + +/atom/MouseDrop_T(mob/target, mob/user) + var/mob/living/H = user + if(istype(H) && can_climb(H) && target == user) + do_climb(target) + else + return ..() + +//Kicking +/atom/proc/kick_act(mob/living/carbon/human/user) + //They're not adjcent to us so we can't kick them. Can't kick in straightjacket or while being incapacitated (except lying), can't kick while legcuffed or while being locked in closet + if(!Adjacent(user) || user.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_KNOCKOUT|INCAPACITATION_BUCKLED_PARTIALLY|INCAPACITATION_BUCKLED_FULLY) \ + || istype(user.wear_suit, /obj/item/clothing/suit/straight_jacket) || istype(user.loc, /obj/structure/closet)) + return + + if(user.handcuffed && prob(50) && !user.incapacitated(INCAPACITATION_FORCELYING))//User can fail to kick smbd if cuffed + user.visible_message("[user.name] loses \his balance while trying to kick \the [src].", \ + " You lost your balance.") + user.Weaken(1) + return + + if(user.middle_click_intent == "kick")//We're in kick mode, we can kick. + for(var/limbcheck in list(BP_L_LEG,BP_R_LEG))//But we need to see if we have legs. + var/obj/item/organ/affecting = user.get_organ(limbcheck) + if(!affecting)//Oh shit, we don't have have any legs, we can't kick. + return 0 + if(affecting.is_broken())//Our legs are broken can't kick here either. + return 0 + + user.setClickCooldown(DEFAULT_SLOW_COOLDOWN) + return 1 //We do have legs now though, so we can kick. + +//Jumping +/atom/proc/jump_act(atom/target, mob/living/carbon/human/user) + //No jumping on the ground dummy && No jumping in space && No jumping in straightjacket or while being incapacitated (except handcuffs) && No jumping vhile being legcuffed or locked in closet + if(user.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_KNOCKOUT|INCAPACITATION_BUCKLED_PARTIALLY|INCAPACITATION_BUCKLED_FULLY|INCAPACITATION_FORCELYING) || user.isinspace() \ + || istype(user.wear_suit, /obj/item/clothing/suit/straight_jacket) || istype(user.loc, /obj/structure/closet)) + return + + if(user.staminaloss >= 100) + return + + for(var/limbcheck in list(BP_L_LEG,BP_R_LEG, BP_R_FOOT, BP_L_FOOT))//But we need to see if we have legs. + var/obj/item/organ/affecting = user.get_organ(limbcheck) + if(!affecting)//Oh shit, we don't have have any legs, we can't jump. + return + if(affecting.is_broken())//Our legs are broken can't jump here either. + return + + if(user.zoomed)//No more jump sniping. + user.do_zoom() + + //Nice, we can jump, let's do that then. + playsound(user, user.gender == MALE ? 'sound/effects/jump_male.ogg' : 'sound/effects/jump_female.ogg', 25, 0, 1) + user.visible_message("[user] jumps.") + user.adjustStaminaLoss(rand(40,60))//Jumping is exhausting. + user.throw_at(target, rand(2,3), 0.3, user) + user.setClickCooldown(DEFAULT_SLOW_COOLDOWN) + diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm new file mode 100644 index 00000000..8d36183f --- /dev/null +++ b/code/game/atoms_movable.dm @@ -0,0 +1,267 @@ +/atom/movable + plane = OBJ_PLANE + layer = BASE_OBJ_LAYER + appearance_flags = TILE_BOUND + glide_size = 8 + + var/movable_flags + + var/last_move = null + var/anchored = 0 + var/move_speed = 10 + var/l_move_time = 1 + var/m_flag = 1 + var/throwing = 0 + var/thrower + var/turf/throw_source = null + var/throw_speed = 2 + var/throw_range = 7 + var/moved_recently = 0 + var/mob/pulledby = null + var/item_state = null // Used to specify the item state for the on-mob overlays. + +/atom/movable/Destroy() + . = ..() + for(var/atom/movable/AM in src) + qdel(AM) + + forceMove(null) + if (pulledby) + if (pulledby.pulling == src) + pulledby.pulling = null + pulledby = null + +/atom/movable/Bump(var/atom/A, yes) + if(src.throwing) + src.throw_impact(A) + src.throwing = 0 + + spawn(0) + if (A && yes) + A.last_bumped = world.time + A.Bumped(src) + return + ..() + return + +/atom/movable/proc/forceMove(atom/destination) + if(loc == destination) + return 0 + var/is_origin_turf = isturf(loc) + var/is_destination_turf = isturf(destination) + // It is a new area if: + // Both the origin and destination are turfs with different areas. + // When either origin or destination is a turf and the other is not. + var/is_new_area = (is_origin_turf ^ is_destination_turf) || (is_origin_turf && is_destination_turf && loc.loc != destination.loc) + + var/atom/origin = loc + loc = destination + + if(origin) + origin.Exited(src, destination) + if(is_origin_turf) + for(var/atom/movable/AM in origin) + AM.Uncrossed(src) + if(is_new_area && is_origin_turf) + origin.loc.Exited(src, destination) + + if(destination) + destination.Entered(src, origin) + if(is_destination_turf) // If we're entering a turf, cross all movable atoms + for(var/atom/movable/AM in loc) + if(AM != src) + AM.Crossed(src) + if(is_new_area && is_destination_turf) + destination.loc.Entered(src, origin) + return 1 + +//called when src is thrown into hit_atom +/atom/movable/proc/throw_impact(atom/hit_atom, var/speed) + if(istype(hit_atom,/mob/living)) + var/mob/living/M = hit_atom + M.hitby(src,speed) + + else if(isobj(hit_atom)) + var/obj/O = hit_atom + if(!O.anchored) + step(O, src.last_move) + O.hitby(src,speed) + + else if(isturf(hit_atom)) + src.throwing = 0 + var/turf/T = hit_atom + T.hitby(src,speed) + +//decided whether a movable atom being thrown can pass through the turf it is in. +/atom/movable/proc/hit_check(var/speed) + if(src.throwing) + for(var/atom/A in get_turf(src)) + if(A == src) continue + if(istype(A,/mob/living)) + if(A:lying) continue + src.throw_impact(A,speed) + if(isobj(A)) + if(A.density && !A.throwpass) // **TODO: Better behaviour for windows which are dense, but shouldn't always stop movement + src.throw_impact(A,speed) + +/atom/movable/proc/throw_at(atom/target, range, speed, thrower) + if(!target || !src) + return 0 + if(target.z != src.z) + return 0 + //use a modified version of Bresenham's algorithm to get from the atom's current position to that of the target + src.throwing = 1 + src.thrower = thrower + src.throw_source = get_turf(src) //store the origin turf + src.pixel_z = 0 + if(usr) + if(HULK in usr.mutations) + src.throwing = 2 // really strong throw! + + var/dist_x = abs(target.x - src.x) + var/dist_y = abs(target.y - src.y) + + var/dx + if (target.x > src.x) + dx = EAST + else + dx = WEST + + var/dy + if (target.y > src.y) + dy = NORTH + else + dy = SOUTH + var/dist_travelled = 0 + var/dist_since_sleep = 0 + var/area/a = get_area(src.loc) + if(dist_x > dist_y) + var/error = dist_x/2 - dist_y + + + + while(src && target &&((((src.x < target.x && dx == EAST) || (src.x > target.x && dx == WEST)) && dist_travelled < range) || (a && a.has_gravity == 0) || istype(src.loc, /turf/space)) && src.throwing && istype(src.loc, /turf)) + // only stop when we've gone the whole distance (or max throw range) and are on a non-space tile, or hit something, or hit the end of the map, or someone picks it up + if(error < 0) + var/atom/step = get_step(src, dy) + if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge + break + src.Move(step) + hit_check(speed) + error += dist_x + dist_travelled++ + dist_since_sleep++ + if(dist_since_sleep >= speed) + dist_since_sleep = 0 + sleep(1) + else + var/atom/step = get_step(src, dx) + if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge + break + src.Move(step) + hit_check(speed) + error -= dist_y + dist_travelled++ + dist_since_sleep++ + if(dist_since_sleep >= speed) + dist_since_sleep = 0 + sleep(1) + a = get_area(src.loc) + else + var/error = dist_y/2 - dist_x + while(src && target &&((((src.y < target.y && dy == NORTH) || (src.y > target.y && dy == SOUTH)) && dist_travelled < range) || (a && a.has_gravity == 0) || istype(src.loc, /turf/space)) && src.throwing && istype(src.loc, /turf)) + // only stop when we've gone the whole distance (or max throw range) and are on a non-space tile, or hit something, or hit the end of the map, or someone picks it up + if(error < 0) + var/atom/step = get_step(src, dx) + if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge + break + src.Move(step) + hit_check(speed) + error += dist_y + dist_travelled++ + dist_since_sleep++ + if(dist_since_sleep >= speed) + dist_since_sleep = 0 + sleep(1) + else + var/atom/step = get_step(src, dy) + if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge + break + src.Move(step) + hit_check(speed) + error -= dist_x + dist_travelled++ + dist_since_sleep++ + if(dist_since_sleep >= speed) + dist_since_sleep = 0 + sleep(1) + + a = get_area(src.loc) + + //done throwing, either because it hit something or it finished moving + if(isobj(src)) src.throw_impact(get_turf(src),speed) + src.throwing = 0 + src.thrower = null + src.throw_source = null + fall() + +//Overlays +/atom/movable/overlay + var/atom/master = null + anchored = 1 + +/atom/movable/overlay/New() + src.verbs.Cut() + ..() + +/atom/movable/overlay/Destroy() + master = null + . = ..() + +/atom/movable/overlay/attackby(a, b) + if (src.master) + return src.master.attackby(a, b) + return + +/atom/movable/overlay/attack_hand(a, b, c) + if (src.master) + return src.master.attack_hand(a, b, c) + return + +/atom/movable/proc/touch_map_edge() + if(!simulated) + return + + if(!z || (z in GLOB.using_map.sealed_levels)) + return + + if(!GLOB.universe.OnTouchMapEdge(src)) + return + + if(GLOB.using_map.use_overmap) + overmap_spacetravel(get_turf(src), src) + return + + var/new_x + var/new_y + var/new_z = GLOB.using_map.get_transit_zlevel(z) + if(new_z) + if(x <= TRANSITIONEDGE) + new_x = world.maxx - TRANSITIONEDGE - 2 + new_y = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) + + else if (x >= (world.maxx - TRANSITIONEDGE + 1)) + new_x = TRANSITIONEDGE + 1 + new_y = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) + + else if (y <= TRANSITIONEDGE) + new_y = world.maxy - TRANSITIONEDGE -2 + new_x = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) + + else if (y >= (world.maxy - TRANSITIONEDGE + 1)) + new_y = TRANSITIONEDGE + 1 + new_x = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) + + var/turf/T = locate(new_x, new_y, new_z) + if(T) + forceMove(T) diff --git a/code/game/base_turf.dm b/code/game/base_turf.dm new file mode 100644 index 00000000..0a87cfa5 --- /dev/null +++ b/code/game/base_turf.dm @@ -0,0 +1,32 @@ +// Returns the lowest turf available on a given Z-level + +proc/get_base_turf(var/z_num) + var/z = num2text(z_num) + if(!GLOB.using_map.base_turf_by_z[z]) + GLOB.using_map.base_turf_by_z[z] = world.turf + return GLOB.using_map.base_turf_by_z[z] + +//An area can override the z-level base turf, so our solar array areas etc. can be space-based. +proc/get_base_turf_by_area(var/turf/T) + var/area/A = T.loc + if(A.base_turf) + return A.base_turf + return get_base_turf(T.z) + +/client/proc/set_base_turf() + set category = "Debug" + set name = "Set Base Turf" + set desc = "Set the base turf for a z-level." + + if(!check_rights(R_DEBUG)) return + + var/choice = input("Which Z-level do you wish to set the base turf for?") as num|null + if(!choice) + return + + var/new_base_path = input("Please select a turf path (cancel to reset to /turf/space).") as null|anything in typesof(/turf) + if(!new_base_path) + new_base_path = /turf/space + GLOB.using_map.base_turf_by_z["[choice]"] = new_base_path + message_admins("[key_name_admin(usr)] has set the base turf for z-level [choice] to [get_base_turf(choice)].") + log_admin("[key_name(usr)] has set the base turf for z-level [choice] to [get_base_turf(choice)].") diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm new file mode 100644 index 00000000..4cbda960 --- /dev/null +++ b/code/game/dna/dna2.dm @@ -0,0 +1,377 @@ +/** +* DNA 2: The Spaghetti Strikes Back +* +* @author N3X15 +*/ + +// What each index means: +#define DNA_OFF_LOWERBOUND 0 +#define DNA_OFF_UPPERBOUND 1 +#define DNA_ON_LOWERBOUND 2 +#define DNA_ON_UPPERBOUND 3 + +// Define block bounds (off-low,off-high,on-low,on-high) +// Used in setupgame.dm +#define DNA_DEFAULT_BOUNDS list(1,2049,2050,4095) +#define DNA_HARDER_BOUNDS list(1,3049,3050,4095) +#define DNA_HARD_BOUNDS list(1,3490,3500,4095) + +// UI Indices (can change to mutblock style, if desired) +#define DNA_UI_HAIR_R 1 +#define DNA_UI_HAIR_G 2 +#define DNA_UI_HAIR_B 3 +#define DNA_UI_BEARD_R 4 +#define DNA_UI_BEARD_G 5 +#define DNA_UI_BEARD_B 6 +#define DNA_UI_SKIN_TONE 7 +#define DNA_UI_SKIN_R 8 +#define DNA_UI_SKIN_G 9 +#define DNA_UI_SKIN_B 10 +#define DNA_UI_EYES_R 11 +#define DNA_UI_EYES_G 12 +#define DNA_UI_EYES_B 13 +#define DNA_UI_GENDER 14 +#define DNA_UI_BEARD_STYLE 15 +#define DNA_UI_HAIR_STYLE 16 +#define DNA_UI_LENGTH 16 // Update this when you add something, or you WILL break shit. + +#define DNA_SE_LENGTH 27 +// For later: +//#define DNA_SE_LENGTH 50 // Was STRUCDNASIZE, size 27. 15 new blocks added = 42, plus room to grow. + + +// Defines which values mean "on" or "off". +// This is to make some of the more OP superpowers a larger PITA to activate, +// and to tell our new DNA datum which values to set in order to turn something +// on or off. +var/global/list/dna_activity_bounds[DNA_SE_LENGTH] + +// Used to determine what each block means (admin hax and species stuff on /vg/, mostly) +var/global/list/assigned_blocks[DNA_SE_LENGTH] + +var/global/list/datum/dna/gene/dna_genes[0] + +///////////////// +// GENE DEFINES +///////////////// +// Skip checking if it's already active. +// Used for genes that check for value rather than a binary on/off. +#define GENE_ALWAYS_ACTIVATE 1 + +/datum/dna + // READ-ONLY, GETS OVERWRITTEN + // DO NOT FUCK WITH THESE OR BYOND WILL EAT YOUR FACE + var/uni_identity="" // Encoded UI + var/struc_enzymes="" // Encoded SE + var/unique_enzymes="" // MD5 of player name + + // Internal dirtiness checks + var/dirtyUI=0 + var/dirtySE=0 + + // Okay to read, but you're an idiot if you do. + // BLOCK = VALUE + var/list/SE[DNA_SE_LENGTH] + var/list/UI[DNA_UI_LENGTH] + + // From old dna. + var/b_type = "A+" // Should probably change to an integer => string map but I'm lazy. + var/real_name // Stores the real name of the person who originally got this dna datum. Used primarily for changelings, + + // New stuff + var/species = SPECIES_HUMAN + var/s_base = "" + var/list/body_markings = list() + +// Make a copy of this strand. +// USE THIS WHEN COPYING STUFF OR YOU'LL GET CORRUPTION! +/datum/dna/proc/Clone() + var/datum/dna/new_dna = new() + new_dna.unique_enzymes=unique_enzymes + new_dna.b_type=b_type + new_dna.real_name=real_name + new_dna.species=species + new_dna.body_markings=body_markings.Copy() + new_dna.s_base=s_base + for(var/b=1;b<=DNA_SE_LENGTH;b++) + new_dna.SE[b]=SE[b] + if(b<=DNA_UI_LENGTH) + new_dna.UI[b]=UI[b] + new_dna.UpdateUI() + new_dna.UpdateSE() + return new_dna +/////////////////////////////////////// +// UNIQUE IDENTITY +/////////////////////////////////////// + +// Create random UI. +/datum/dna/proc/ResetUI(var/defer=0) + for(var/i=1,i<=DNA_UI_LENGTH,i++) + switch(i) + if(DNA_UI_SKIN_TONE) + SetUIValueRange(DNA_UI_SKIN_TONE,rand(1,220),220,1) // Otherwise, it gets fucked + else + UI[i]=rand(0,4095) + if(!defer) + UpdateUI() + +/datum/dna/proc/ResetUIFrom(var/mob/living/carbon/human/character) + // INITIALIZE! + ResetUI(1) + // Hair + // FIXME: Species-specific defaults pls + if(!character.h_style) + character.h_style = "Skinhead" + var/hair = GLOB.hair_styles_list.Find(character.h_style) + + // Facial Hair + if(!character.f_style) + character.f_style = "Shaved" + var/beard = GLOB.facial_hair_styles_list.Find(character.f_style) + + SetUIValueRange(DNA_UI_HAIR_R, character.r_hair, 255, 1) + SetUIValueRange(DNA_UI_HAIR_G, character.g_hair, 255, 1) + SetUIValueRange(DNA_UI_HAIR_B, character.b_hair, 255, 1) + + SetUIValueRange(DNA_UI_BEARD_R, character.r_facial, 255, 1) + SetUIValueRange(DNA_UI_BEARD_G, character.g_facial, 255, 1) + SetUIValueRange(DNA_UI_BEARD_B, character.b_facial, 255, 1) + + SetUIValueRange(DNA_UI_EYES_R, character.r_eyes, 255, 1) + SetUIValueRange(DNA_UI_EYES_G, character.g_eyes, 255, 1) + SetUIValueRange(DNA_UI_EYES_B, character.b_eyes, 255, 1) + + SetUIValueRange(DNA_UI_SKIN_R, character.r_skin, 255, 1) + SetUIValueRange(DNA_UI_SKIN_G, character.g_skin, 255, 1) + SetUIValueRange(DNA_UI_SKIN_B, character.b_skin, 255, 1) + + SetUIValueRange(DNA_UI_SKIN_TONE, 35-character.s_tone, 220, 1) // Value can be negative. + + SetUIState(DNA_UI_GENDER, character.gender!=MALE, 1) + + SetUIValueRange(DNA_UI_HAIR_STYLE, hair, GLOB.hair_styles_list.len, 1) + SetUIValueRange(DNA_UI_BEARD_STYLE, beard, GLOB.facial_hair_styles_list.len,1) + + body_markings.Cut() + s_base = character.s_base + for(var/obj/item/organ/external/E in character.organs) + E.s_base = s_base + if(E.markings.len) + body_markings[E.organ_tag] = E.markings.Copy() + + UpdateUI() + +// Set a DNA UI block's raw value. +/datum/dna/proc/SetUIValue(var/block,var/value,var/defer=0) + if (block<=0) return + ASSERT(value>0) + ASSERT(value<=4095) + UI[block]=value + dirtyUI=1 + if(!defer) + UpdateUI() + +// Get a DNA UI block's raw value. +/datum/dna/proc/GetUIValue(var/block) + if (block<=0) return 0 + return UI[block] + +// Set a DNA UI block's value, given a value and a max possible value. +// Used in hair and facial styles (value being the index and maxvalue being the len of the hairstyle list) +/datum/dna/proc/SetUIValueRange(var/block,var/value,var/maxvalue,var/defer=0) + if (block<=0) return + if (value==0) value = 1 // FIXME: hair/beard/eye RGB values if they are 0 are not set, this is a work around we'll encode it in the DNA to be 1 instead. + ASSERT(maxvalue<=4095) + var/range = (4095 / maxvalue) + if(value) + SetUIValue(block,round(value * range),defer) + +// Getter version of above. +/datum/dna/proc/GetUIValueRange(var/block,var/maxvalue) + if (block<=0) return 0 + var/value = GetUIValue(block) + return round(1 +(value / 4096)*maxvalue) + +// Is the UI gene "on" or "off"? +// For UI, this is simply a check of if the value is > 2050. +/datum/dna/proc/GetUIState(var/block) + if (block<=0) return + return UI[block] > 2050 + + +// Set UI gene "on" (1) or "off" (0) +/datum/dna/proc/SetUIState(var/block,var/on,var/defer=0) + if (block<=0) return + var/val + if(on) + val=rand(2050,4095) + else + val=rand(1,2049) + SetUIValue(block,val,defer) + +// Get a hex-encoded UI block. +/datum/dna/proc/GetUIBlock(var/block) + return EncodeDNABlock(GetUIValue(block)) + +// Do not use this unless you absolutely have to. +// Set a block from a hex string. This is inefficient. If you can, use SetUIValue(). +// Used in DNA modifiers. +/datum/dna/proc/SetUIBlock(var/block,var/value,var/defer=0) + if (block<=0) return + return SetUIValue(block,hex2num(value),defer) + +// Get a sub-block from a block. +/datum/dna/proc/GetUISubBlock(var/block,var/subBlock) + return copytext(GetUIBlock(block),subBlock,subBlock+1) + +// Do not use this unless you absolutely have to. +// Set a block from a hex string. This is inefficient. If you can, use SetUIValue(). +// Used in DNA modifiers. +/datum/dna/proc/SetUISubBlock(var/block,var/subBlock, var/newSubBlock, var/defer=0) + if (block<=0) return + var/oldBlock=GetUIBlock(block) + var/newBlock="" + for(var/i=1, i<=length(oldBlock), i++) + if(i==subBlock) + newBlock+=newSubBlock + else + newBlock+=copytext(oldBlock,i,i+1) + SetUIBlock(block,newBlock,defer) + +/////////////////////////////////////// +// STRUCTURAL ENZYMES +/////////////////////////////////////// + +// "Zeroes out" all of the blocks. +/datum/dna/proc/ResetSE() + for(var/i = 1, i <= DNA_SE_LENGTH, i++) + SetSEValue(i,rand(1,1024),1) + UpdateSE() + +// Set a DNA SE block's raw value. +/datum/dna/proc/SetSEValue(var/block,var/value,var/defer=0) + if (block<=0) return + ASSERT(value>=0) + ASSERT(value<=4095) + SE[block]=value + dirtySE=1 + if(!defer) + UpdateSE() + +// Get a DNA SE block's raw value. +/datum/dna/proc/GetSEValue(var/block) + if (block<=0) return 0 + return SE[block] + +// Set a DNA SE block's value, given a value and a max possible value. +// Might be used for species? +/datum/dna/proc/SetSEValueRange(var/block,var/value,var/maxvalue) + if (block<=0) return + ASSERT(maxvalue<=4095) + var/range = round(4095 / maxvalue) + if(value) + SetSEValue(block, value * range - rand(1,range-1)) + +// Getter version of above. +/datum/dna/proc/GetSEValueRange(var/block,var/maxvalue) + if (block<=0) return 0 + var/value = GetSEValue(block) + return round(1 +(value / 4096)*maxvalue) + +// Is the block "on" (1) or "off" (0)? (Un-assigned genes are always off.) +/datum/dna/proc/GetSEState(var/block) + if (block<=0) return 0 + var/list/BOUNDS=GetDNABounds(block) + var/value=GetSEValue(block) + return (value > BOUNDS[DNA_ON_LOWERBOUND]) + +// Set a block "on" or "off". +/datum/dna/proc/SetSEState(var/block,var/on,var/defer=0) + if (block<=0) return + var/list/BOUNDS=GetDNABounds(block) + var/val + if(on) + val=rand(BOUNDS[DNA_ON_LOWERBOUND],BOUNDS[DNA_ON_UPPERBOUND]) + else + val=rand(1,BOUNDS[DNA_OFF_UPPERBOUND]) + SetSEValue(block,val,defer) + +// Get hex-encoded SE block. +/datum/dna/proc/GetSEBlock(var/block) + return EncodeDNABlock(GetSEValue(block)) + +// Do not use this unless you absolutely have to. +// Set a block from a hex string. This is inefficient. If you can, use SetUIValue(). +// Used in DNA modifiers. +/datum/dna/proc/SetSEBlock(var/block,var/value,var/defer=0) + if (block<=0) return + var/nval=hex2num(value) + //testing("SetSEBlock([block],[value],[defer]): [value] -> [nval]") + return SetSEValue(block,nval,defer) + +/datum/dna/proc/GetSESubBlock(var/block,var/subBlock) + return copytext(GetSEBlock(block),subBlock,subBlock+1) + + +// Do not use this unless you absolutely have to. +// Set a sub-block from a hex character. This is inefficient. If you can, use SetUIValue(). +// Used in DNA modifiers. +/datum/dna/proc/SetSESubBlock(var/block,var/subBlock, var/newSubBlock, var/defer=0) + if (block<=0) return + var/oldBlock=GetSEBlock(block) + var/newBlock="" + for(var/i=1, i<=length(oldBlock), i++) + if(i==subBlock) + newBlock+=newSubBlock + else + newBlock+=copytext(oldBlock,i,i+1) + //testing("SetSESubBlock([block],[subBlock],[newSubBlock],[defer]): [oldBlock] -> [newBlock]") + SetSEBlock(block,newBlock,defer) + + +/proc/EncodeDNABlock(var/value) + return add_zero2(num2hex(value,1), 3) + +/datum/dna/proc/UpdateUI() + src.uni_identity="" + for(var/block in UI) + uni_identity += EncodeDNABlock(block) + //testing("New UI: [uni_identity]") + dirtyUI=0 + +/datum/dna/proc/UpdateSE() + //var/oldse=struc_enzymes + struc_enzymes="" + for(var/block in SE) + struc_enzymes += EncodeDNABlock(block) + //testing("Old SE: [oldse]") + //testing("New SE: [struc_enzymes]") + dirtySE=0 + +// BACK-COMPAT! +// Just checks our character has all the crap it needs. +/datum/dna/proc/check_integrity(var/mob/living/carbon/human/character) + if(character) + if(UI.len != DNA_UI_LENGTH) + ResetUIFrom(character) + + if(length(struc_enzymes)!= 3*DNA_SE_LENGTH) + ResetSE() + + if(length(unique_enzymes) != 32) + unique_enzymes = md5(character.real_name) + else + if(length(uni_identity) != 3*DNA_UI_LENGTH) + uni_identity = "00600200A00E0110148FC01300B0095BD7FD3F4" + if(length(struc_enzymes)!= 3*DNA_SE_LENGTH) + struc_enzymes = "43359156756131E13763334D1C369012032164D4FE4CD61544B6C03F251B6C60A42821D26BA3B0FD6" + +// BACK-COMPAT! +// Initial DNA setup. I'm kind of wondering why the hell this doesn't just call the above. +/datum/dna/proc/ready_dna(mob/living/carbon/human/character) + ResetUIFrom(character) + + ResetSE() + + unique_enzymes = md5(character.real_name) + GLOB.reg_dna[unique_enzymes] = character.real_name diff --git a/code/game/dna/dna2_domutcheck.dm b/code/game/dna/dna2_domutcheck.dm new file mode 100644 index 00000000..a19f5e22 --- /dev/null +++ b/code/game/dna/dna2_domutcheck.dm @@ -0,0 +1,47 @@ +// (Re-)Apply mutations. +// TODO: Turn into a /mob proc, change inj to a bitflag for various forms of differing behavior. +// M: Mob to mess with +// connected: Machine we're in, type unchecked so I doubt it's used beyond monkeying +// flags: See below, bitfield. +#define MUTCHK_FORCED 1 +/proc/domutcheck(var/mob/living/M, var/connected=null, var/flags=0) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(!H.should_have_organ(BP_HEART)) + return + for(var/datum/dna/gene/gene in dna_genes) + if(!M || !M.dna) + return + if(!gene.block) + continue + + // Sanity checks, don't skip. + if(!gene.can_activate(M,flags)) + //testing("[M] - Failed to activate [gene.name] (can_activate fail).") + continue + + // Current state + var/gene_active = (gene.flags & GENE_ALWAYS_ACTIVATE) + if(!gene_active) + gene_active = M.dna.GetSEState(gene.block) + + // Prior state + var/gene_prior_status = (gene.type in M.active_genes) + var/changed = gene_active != gene_prior_status || (gene.flags & GENE_ALWAYS_ACTIVATE) + + // If gene state has changed: + if(changed) + // Gene active (or ALWAYS ACTIVATE) + if(gene_active || (gene.flags & GENE_ALWAYS_ACTIVATE)) + testing("[gene.name] activated!") + gene.activate(M,connected,flags) + if(M) + M.active_genes |= gene.type + M.update_icon = 1 + // If Gene is NOT active: + else + testing("[gene.name] deactivated!") + gene.deactivate(M,connected,flags) + if(M) + M.active_genes -= gene.type + M.update_icon = 1 diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm new file mode 100644 index 00000000..7acba350 --- /dev/null +++ b/code/game/dna/dna2_helpers.dm @@ -0,0 +1,199 @@ +///////////////////////////// +// Helpers for DNA2 +///////////////////////////// + +// Pads 0s to t until length == u +/proc/add_zero2(t, u) + var/temp1 + while (length(t) < u) + t = "0[t]" + temp1 = t + if (length(t) > u) + temp1 = copytext(t,2,u+1) + return temp1 + +// DNA Gene activation boundaries, see dna2.dm. +// Returns a list object with 4 numbers. +/proc/GetDNABounds(var/block) + var/list/BOUNDS=dna_activity_bounds[block] + if(!istype(BOUNDS)) + return DNA_DEFAULT_BOUNDS + return BOUNDS + +// Give Random Bad Mutation to M +/proc/randmutb(var/mob/living/M) + if(!M) return + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(!H.should_have_organ(BP_HEART)) + return + M.dna.check_integrity() + var/block = pick(GLOB.GLASSESBLOCK,GLOB.COUGHBLOCK,GLOB.FAKEBLOCK,GLOB.NERVOUSBLOCK,GLOB.CLUMSYBLOCK,GLOB.TWITCHBLOCK,GLOB.HEADACHEBLOCK,GLOB.BLINDBLOCK,GLOB.DEAFBLOCK,GLOB.HALLUCINATIONBLOCK) + M.dna.SetSEState(block, 1) + +// Give Random Good Mutation to M +/proc/randmutg(var/mob/living/M) + if(!M) return + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(!H.should_have_organ(BP_HEART)) + return + M.dna.check_integrity() + var/block = pick(GLOB.HULKBLOCK,GLOB.XRAYBLOCK,GLOB.FIREBLOCK,GLOB.TELEBLOCK,GLOB.NOBREATHBLOCK,GLOB.REMOTEVIEWBLOCK,GLOB.REGENERATEBLOCK,GLOB.INCREASERUNBLOCK,GLOB.REMOTETALKBLOCK,GLOB.MORPHBLOCK,GLOB.BLENDBLOCK,GLOB.NOPRINTSBLOCK,GLOB.SHOCKIMMUNITYBLOCK,GLOB.SMALLSIZEBLOCK) + M.dna.SetSEState(block, 1) + +// Random Appearance Mutation +/proc/randmuti(var/mob/living/M) + if(!M) return + M.dna.check_integrity() + M.dna.SetUIValue(rand(1,DNA_UI_LENGTH),rand(1,4095)) + +// Scramble UI or SE. +/proc/scramble(var/UI, var/mob/M, var/prob) + if(!M) return + M.dna.check_integrity() + if(UI) + for(var/i = 1, i <= DNA_UI_LENGTH-1, i++) + if(prob(prob)) + M.dna.SetUIValue(i,rand(1,4095),1) + M.dna.UpdateUI() + M.UpdateAppearance() + + else + for(var/i = 1, i <= DNA_SE_LENGTH-1, i++) + if(prob(prob)) + M.dna.SetSEValue(i,rand(1,4095),1) + M.dna.UpdateSE() + domutcheck(M, null) + return + +// I haven't yet figured out what the fuck this is supposed to do. +/proc/miniscramble(input,rs,rd) + var/output + output = null + if (input == "C" || input == "D" || input == "E" || input == "F") + output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"6",prob((rs*10));"7",prob((rs*5)+(rd));"0",prob((rs*5)+(rd));"1",prob((rs*10)-(rd));"2",prob((rs*10)-(rd));"3") + if (input == "8" || input == "9" || input == "A" || input == "B") + output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"A",prob((rs*10));"B",prob((rs*5)+(rd));"C",prob((rs*5)+(rd));"D",prob((rs*5)+(rd));"2",prob((rs*5)+(rd));"3") + if (input == "4" || input == "5" || input == "6" || input == "7") + output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"A",prob((rs*10));"B",prob((rs*5)+(rd));"C",prob((rs*5)+(rd));"D",prob((rs*5)+(rd));"2",prob((rs*5)+(rd));"3") + if (input == "0" || input == "1" || input == "2" || input == "3") + output = pick(prob((rs*10));"8",prob((rs*10));"9",prob((rs*10));"A",prob((rs*10));"B",prob((rs*10)-(rd));"C",prob((rs*10)-(rd));"D",prob((rs*5)+(rd));"E",prob((rs*5)+(rd));"F") + if (!output) output = "5" + return output + +// HELLO I MAKE BELL CURVES AROUND YOUR DESIRED TARGET +// So a shitty way of replacing gaussian noise. +// input: YOUR TARGET +// rs: RAD STRENGTH +// rd: DURATION +/proc/miniscrambletarget(input,rs,rd) + var/output = null + switch(input) + if("0") + output = pick(prob((rs*10)+(rd));"0",prob((rs*10)+(rd));"1",prob((rs*10));"2",prob((rs*10)-(rd));"3") + if("1") + output = pick(prob((rs*10)+(rd));"0",prob((rs*10)+(rd));"1",prob((rs*10)+(rd));"2",prob((rs*10));"3",prob((rs*10)-(rd));"4") + if("2") + output = pick(prob((rs*10));"0",prob((rs*10)+(rd));"1",prob((rs*10)+(rd));"2",prob((rs*10)+(rd));"3",prob((rs*10));"4",prob((rs*10)-(rd));"5") + if("3") + output = pick(prob((rs*10)-(rd));"0",prob((rs*10));"1",prob((rs*10)+(rd));"2",prob((rs*10)+(rd));"3",prob((rs*10)+(rd));"4",prob((rs*10));"5",prob((rs*10)-(rd));"6") + if("4") + output = pick(prob((rs*10)-(rd));"1",prob((rs*10));"2",prob((rs*10)+(rd));"3",prob((rs*10)+(rd));"4",prob((rs*10)+(rd));"5",prob((rs*10));"6",prob((rs*10)-(rd));"7") + if("5") + output = pick(prob((rs*10)-(rd));"2",prob((rs*10));"3",prob((rs*10)+(rd));"4",prob((rs*10)+(rd));"5",prob((rs*10)+(rd));"6",prob((rs*10));"7",prob((rs*10)-(rd));"8") + if("6") + output = pick(prob((rs*10)-(rd));"3",prob((rs*10));"4",prob((rs*10)+(rd));"5",prob((rs*10)+(rd));"6",prob((rs*10)+(rd));"7",prob((rs*10));"8",prob((rs*10)-(rd));"9") + if("7") + output = pick(prob((rs*10)-(rd));"4",prob((rs*10));"5",prob((rs*10)+(rd));"6",prob((rs*10)+(rd));"7",prob((rs*10)+(rd));"8",prob((rs*10));"9",prob((rs*10)-(rd));"A") + if("8") + output = pick(prob((rs*10)-(rd));"5",prob((rs*10));"6",prob((rs*10)+(rd));"7",prob((rs*10)+(rd));"8",prob((rs*10)+(rd));"9",prob((rs*10));"A",prob((rs*10)-(rd));"B") + if("9") + output = pick(prob((rs*10)-(rd));"6",prob((rs*10));"7",prob((rs*10)+(rd));"8",prob((rs*10)+(rd));"9",prob((rs*10)+(rd));"A",prob((rs*10));"B",prob((rs*10)-(rd));"C") + if("10")//A + output = pick(prob((rs*10)-(rd));"7",prob((rs*10));"8",prob((rs*10)+(rd));"9",prob((rs*10)+(rd));"A",prob((rs*10)+(rd));"B",prob((rs*10));"C",prob((rs*10)-(rd));"D") + if("11")//B + output = pick(prob((rs*10)-(rd));"8",prob((rs*10));"9",prob((rs*10)+(rd));"A",prob((rs*10)+(rd));"B",prob((rs*10)+(rd));"C",prob((rs*10));"D",prob((rs*10)-(rd));"E") + if("12")//C + output = pick(prob((rs*10)-(rd));"9",prob((rs*10));"A",prob((rs*10)+(rd));"B",prob((rs*10)+(rd));"C",prob((rs*10)+(rd));"D",prob((rs*10));"E",prob((rs*10)-(rd));"F") + if("13")//D + output = pick(prob((rs*10)-(rd));"A",prob((rs*10));"B",prob((rs*10)+(rd));"C",prob((rs*10)+(rd));"D",prob((rs*10)+(rd));"E",prob((rs*10));"F") + if("14")//E + output = pick(prob((rs*10)-(rd));"B",prob((rs*10));"C",prob((rs*10)+(rd));"D",prob((rs*10)+(rd));"E",prob((rs*10)+(rd));"F") + if("15")//F + output = pick(prob((rs*10)-(rd));"C",prob((rs*10));"D",prob((rs*10)+(rd));"E",prob((rs*10)+(rd));"F") + + if(!input || !output) //How did this happen? + output = "8" + + return output + +// /proc/updateappearance has changed behavior, so it's been removed +// Use mob.UpdateAppearance() instead. + +// Simpler. Don't specify UI in order for the mob to use its own. +/mob/proc/UpdateAppearance(var/list/UI=null) + if(istype(src, /mob/living/carbon/human)) + if(UI!=null) + src.dna.UI=UI + src.dna.UpdateUI() + dna.check_integrity() + var/mob/living/carbon/human/H = src + H.r_hair = dna.GetUIValueRange(DNA_UI_HAIR_R, 255) + H.g_hair = dna.GetUIValueRange(DNA_UI_HAIR_G, 255) + H.b_hair = dna.GetUIValueRange(DNA_UI_HAIR_B, 255) + + H.r_facial = dna.GetUIValueRange(DNA_UI_BEARD_R, 255) + H.g_facial = dna.GetUIValueRange(DNA_UI_BEARD_G, 255) + H.b_facial = dna.GetUIValueRange(DNA_UI_BEARD_B, 255) + + H.r_skin = dna.GetUIValueRange(DNA_UI_SKIN_R, 255) + H.g_skin = dna.GetUIValueRange(DNA_UI_SKIN_G, 255) + H.b_skin = dna.GetUIValueRange(DNA_UI_SKIN_B, 255) + + H.r_eyes = dna.GetUIValueRange(DNA_UI_EYES_R, 255) + H.g_eyes = dna.GetUIValueRange(DNA_UI_EYES_G, 255) + H.b_eyes = dna.GetUIValueRange(DNA_UI_EYES_B, 255) + H.update_eyes() + + H.s_tone = 35 - dna.GetUIValueRange(DNA_UI_SKIN_TONE, 220) // Value can be negative. + + if(H.gender != NEUTER) + if (dna.GetUIState(DNA_UI_GENDER)) + H.gender = FEMALE + else + H.gender = MALE + + //Body markings + for(var/tag in dna.body_markings) + var/obj/item/organ/external/E = H.organs_by_name[tag] + if(E) + var/list/marklist = dna.body_markings[tag] + E.markings = marklist.Copy() + + //Base skin and blend + for(var/obj/item/organ/external/E in H.organs) + E.set_dna(E.dna) + + //Hair + var/hair = dna.GetUIValueRange(DNA_UI_HAIR_STYLE,GLOB.hair_styles_list.len) + if((0 < hair) && (hair <= GLOB.hair_styles_list.len)) + H.h_style = GLOB.hair_styles_list[hair] + + //Facial Hair + var/beard = dna.GetUIValueRange(DNA_UI_BEARD_STYLE,GLOB.facial_hair_styles_list.len) + if((0 < beard) && (beard <= GLOB.facial_hair_styles_list.len)) + H.f_style = GLOB.facial_hair_styles_list[beard] + + H.force_update_limbs() + H.update_body() + H.update_eyes() + H.update_hair() + + return 1 + else + return 0 + +// Used below, simple injection modifier. +/proc/probinj(var/pr, var/inj) + return prob(pr+inj*pr) diff --git a/code/game/dna/genes/disabilities.dm b/code/game/dna/genes/disabilities.dm new file mode 100644 index 00000000..123c721b --- /dev/null +++ b/code/game/dna/genes/disabilities.dm @@ -0,0 +1,129 @@ +///////////////////// +// DISABILITY GENES +// +// These activate either a mutation, disability, or sdisability. +// +// Gene is always activated. +///////////////////// + +/datum/dna/gene/disability + name="DISABILITY" + + // Mutation to give (or 0) + var/mutation=0 + + // Disability to give (or 0) + var/disability=0 + + // SDisability to give (or 0) + var/sdisability=0 + + // Activation message + var/activation_message="" + + // Yay, you're no longer growing 3 arms + var/deactivation_message="" + +/datum/dna/gene/disability/can_activate(var/mob/M,var/flags) + return 1 // Always set! + +/datum/dna/gene/disability/activate(var/mob/M, var/connected, var/flags) + if(mutation && !(mutation in M.mutations)) + M.mutations.Add(mutation) + if(disability) + M.disabilities|=disability + if(sdisability) + M.sdisabilities|=sdisability + if(activation_message) + to_chat(M, "[activation_message]") + else + testing("[name] has no activation message.") + +/datum/dna/gene/disability/deactivate(var/mob/M, var/connected, var/flags) + if(mutation && (mutation in M.mutations)) + M.mutations.Remove(mutation) + if(disability) + M.disabilities &= (~disability) + if(sdisability) + M.sdisabilities &= (~sdisability) + if(deactivation_message) + to_chat(M, "[deactivation_message]") + else + testing("[name] has no deactivation message.") + +// Note: Doesn't seem to do squat, at the moment. +/datum/dna/gene/disability/hallucinate + name="Hallucinate" + activation_message="Your mind says 'Hello'." + mutation=mHallucination + + New() + block=GLOB.HALLUCINATIONBLOCK + +/datum/dna/gene/disability/epilepsy + name="Epilepsy" + activation_message="You get a headache." + disability=EPILEPSY + + New() + block=GLOB.HEADACHEBLOCK + +/datum/dna/gene/disability/cough + name="Coughing" + activation_message="You start coughing." + disability=COUGHING + + New() + block=GLOB.COUGHBLOCK + +/datum/dna/gene/disability/clumsy + name="Clumsiness" + activation_message="You feel lightheaded." + mutation=CLUMSY + + New() + block=GLOB.CLUMSYBLOCK + +/datum/dna/gene/disability/tourettes + name="Tourettes" + activation_message="You twitch." + disability=TOURETTES + + New() + block=GLOB.TWITCHBLOCK + +/datum/dna/gene/disability/nervousness + name="Nervousness" + activation_message="You feel nervous." + disability=NERVOUS + + New() + block=GLOB.NERVOUSBLOCK + +/datum/dna/gene/disability/blindness + name="Blindness" + activation_message="You can't seem to see anything." + sdisability=BLIND + + New() + block=GLOB.BLINDBLOCK + +/datum/dna/gene/disability/deaf + name="Deafness" + activation_message="It's kinda quiet." + sdisability=DEAF + + New() + block=GLOB.DEAFBLOCK + + activate(var/mob/M, var/connected, var/flags) + ..(M,connected,flags) + M.ear_deaf = 1 + +/datum/dna/gene/disability/nearsighted + name="Nearsightedness" + activation_message="Your eyes feel weird..." + disability=NEARSIGHTED + + New() + block=GLOB.GLASSESBLOCK diff --git a/code/game/dna/genes/gene.dm b/code/game/dna/genes/gene.dm new file mode 100644 index 00000000..e52cd4e6 --- /dev/null +++ b/code/game/dna/genes/gene.dm @@ -0,0 +1,122 @@ +/** +* Gene Datum +* +* domutcheck was getting pretty hairy. This is the solution. +* +* All genes are stored in a global variable to cut down on memory +* usage. +* +* @author N3X15 +*/ + +/datum/dna/gene + // Display name + var/name="BASE GENE" + + // Probably won't get used but why the fuck not + var/desc="Oh god who knows what this does." + + // Set in initialize()! + // What gene activates this? + var/block=0 + + // Any of a number of GENE_ flags. + var/flags=0 + +/** +* Is the gene active in this mob's DNA? +*/ +/datum/dna/gene/proc/is_active(var/mob/M) + return M.active_genes && type in M.active_genes + +// Return 1 if we can activate. +// HANDLE MUTCHK_FORCED HERE! +/datum/dna/gene/proc/can_activate(var/mob/M, var/flags) + return 0 + +// Called when the gene activates. Do your magic here. +/datum/dna/gene/proc/activate(var/mob/M, var/connected, var/flags) + return + +/** +* Called when the gene deactivates. Undo your magic here. +* Only called when the block is deactivated. +*/ +/datum/dna/gene/proc/deactivate(var/mob/M, var/connected, var/flags) + return + +// This section inspired by goone's bioEffects. + +/** +* Called in each life() tick. +*/ +/datum/dna/gene/proc/OnMobLife(var/mob/M) + return + +/** +* Called when the mob dies +*/ +/datum/dna/gene/proc/OnMobDeath(var/mob/M) + return + +/** +* Called when the mob says shit +*/ +/datum/dna/gene/proc/OnSay(var/mob/M, var/message) + return message + +/** +* Called after the mob runs update_icons. +* +* @params M The subject. +* @params g Gender (m or f) +* @params fat Fat? (0 or 1) +*/ +/datum/dna/gene/proc/OnDrawUnderlays(var/mob/M, var/g, var/fat) + return 0 + + +///////////////////// +// BASIC GENES +// +// These just chuck in a mutation and display a message. +// +// Gene is activated: +// 1. If mutation already exists in mob +// 2. If the probability roll succeeds +// 3. Activation is forced (done in domutcheck) +///////////////////// + + +/datum/dna/gene/basic + name="BASIC GENE" + + // Mutation to give + var/mutation=0 + + // Activation probability + var/activation_prob=45 + + // Possible activation messages + var/list/activation_messages=list() + + // Possible deactivation messages + var/list/deactivation_messages=list() + +/datum/dna/gene/basic/can_activate(var/mob/M,var/flags) + if(flags & MUTCHK_FORCED) + return 1 + // Probability check + return probinj(activation_prob,(flags&MUTCHK_FORCED)) + +/datum/dna/gene/basic/activate(var/mob/M) + M.mutations.Add(mutation) + if(activation_messages.len) + var/msg = pick(activation_messages) + to_chat(M, "[msg]") + +/datum/dna/gene/basic/deactivate(var/mob/M) + M.mutations.Remove(mutation) + if(deactivation_messages.len) + var/msg = pick(deactivation_messages) + to_chat(M, "[msg]") diff --git a/code/game/dna/genes/monkey.dm b/code/game/dna/genes/monkey.dm new file mode 100644 index 00000000..c0d7d209 --- /dev/null +++ b/code/game/dna/genes/monkey.dm @@ -0,0 +1,175 @@ +/datum/dna/gene/monkey + name="Monkey" + +/datum/dna/gene/monkey/New() + block=GLOB.MONKEYBLOCK + +/datum/dna/gene/monkey/can_activate(var/mob/M,var/flags) + return istype(M, /mob/living/carbon/human) || istype(M,/mob/living/carbon/monkey) + +/datum/dna/gene/monkey/activate(var/mob/living/M, var/connected, var/flags) + if(!istype(M,/mob/living/carbon/human)) + //testing("Cannot monkey-ify [M], type is [M.type].") + return + var/mob/living/carbon/human/H = M + H.transforming = 1 + var/list/implants = list() //Try to preserve implants. + for(var/obj/item/weapon/implant/W in H) + implants += W + W.loc = null + + if(!connected) + for(var/obj/item/W in (H.contents-implants)) + if (W==H.w_uniform) // will be teared + continue + H.drop_from_inventory(W) + M.transforming = 1 + M.canmove = 0 + M.icon = null + M.set_invisibility(101) + var/atom/movable/overlay/animation = new( M.loc ) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = src + flick("h2monkey", animation) + sleep(48) + qdel(animation) + + + var/mob/living/carbon/monkey/O = null + if(H.species.primitive) + O = new H.species.primitive(src) + else + H.gib() //Trying to change the species of a creature with no primitive var set is messy. + return + + if(M) + if (M.dna) + O.dna = M.dna.Clone() + M.dna = null + + if (M.suiciding) + O.suiciding = M.suiciding + M.suiciding = null + + + for(var/datum/disease/D in M.viruses) + O.viruses += D + D.affected_mob = O + M.viruses -= D + + + for(var/obj/T in (M.contents-implants)) + qdel(T) + + O.loc = M.loc + + if(M.mind) + M.mind.transfer_to(O) //transfer our mind to the cute little monkey + + if (connected) //inside dna thing + var/obj/machinery/dna_scannernew/C = connected + O.loc = C + C.occupant = O + connected = null + O.real_name = text("monkey ([])",copytext(md5(M.real_name), 2, 6)) + O.take_overall_damage(M.getBruteLoss() + 40, M.getFireLoss()) + O.adjustToxLoss(M.getToxLoss() + 20) + O.adjustOxyLoss(M.getOxyLoss()) + O.set_stat(M.stat) + O.a_intent = I_HURT + for (var/obj/item/weapon/implant/I in implants) + I.forceMove(O) + I.implanted = O +// O.update_icon = 1 //queue a full icon update at next life() call + qdel(M) + return + +/datum/dna/gene/monkey/deactivate(var/mob/living/M, var/connected, var/flags) + if(!istype(M,/mob/living/carbon/monkey)) + //testing("Cannot humanize [M], type is [M.type].") + return + var/mob/living/carbon/monkey/Mo = M + Mo.transforming = 1 + var/list/implants = list() //Still preserving implants + for(var/obj/item/weapon/implant/W in Mo) + implants += W + W.loc = null + if(!connected) + for(var/obj/item/W in (Mo.contents-implants)) + Mo.drop_from_inventory(W) + M.transforming = 1 + M.canmove = 0 + M.icon = null + M.set_invisibility(101) + var/atom/movable/overlay/animation = new( M.loc ) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = src + flick("monkey2h", animation) + sleep(48) + qdel(animation) + + var/mob/living/carbon/human/O + if(Mo.greaterform) + O = new(src, Mo.greaterform) + else + O = new(src) + + if (M.dna.GetUIState(DNA_UI_GENDER)) + O.gender = FEMALE + else + O.gender = MALE + + if (M) + if (M.dna) + O.dna = M.dna.Clone() + M.dna = null + + if (M.suiciding) + O.suiciding = M.suiciding + M.suiciding = null + + for(var/datum/disease/D in M.viruses) + O.viruses += D + D.affected_mob = O + M.viruses -= D + + //for(var/obj/T in M) + // qdel(T) + + O.loc = M.loc + + if(M.mind) + M.mind.transfer_to(O) //transfer our mind to the human + + if (connected) //inside dna thing + var/obj/machinery/dna_scannernew/C = connected + O.loc = C + C.occupant = O + connected = null + + var/i + while (!i) + var/randomname + if (O.gender == MALE) + randomname = capitalize(pick(first_names_male) + " " + capitalize(pick(last_names))) + else + randomname = capitalize(pick(first_names_female) + " " + capitalize(pick(last_names))) + if (findname(randomname)) + continue + else + O.real_name = randomname + O.dna.real_name = randomname + i++ + O.UpdateAppearance() + O.take_overall_damage(M.getBruteLoss(), M.getFireLoss()) + O.adjustToxLoss(M.getToxLoss()) + O.adjustOxyLoss(M.getOxyLoss()) + O.set_stat(M.stat) + for (var/obj/item/weapon/implant/I in implants) + I.forceMove(O) + I.implanted = O +// O.update_icon = 1 //queue a full icon update at next life() call + qdel(M) + return diff --git a/code/game/dna/genes/powers.dm b/code/game/dna/genes/powers.dm new file mode 100644 index 00000000..d80e03cf --- /dev/null +++ b/code/game/dna/genes/powers.dm @@ -0,0 +1,195 @@ +/////////////////////////////////// +// POWERS +/////////////////////////////////// + +/datum/dna/gene/basic/nobreath + name="No Breathing" + activation_messages=list("You feel no need to breathe.") + mutation=mNobreath + + New() + block=GLOB.NOBREATHBLOCK + +/datum/dna/gene/basic/remoteview + name="Remote Viewing" + activation_messages=list("Your mind expands.") + mutation=mRemote + + New() + block=GLOB.REMOTEVIEWBLOCK + + activate(var/mob/M, var/connected, var/flags) + ..(M,connected,flags) + M.verbs += /mob/living/carbon/human/proc/remoteobserve + +/datum/dna/gene/basic/regenerate + name="Regenerate" + activation_messages=list("You feel better.") + mutation=mRegen + + New() + block=GLOB.REGENERATEBLOCK + +/datum/dna/gene/basic/increaserun + name="Super Speed" + activation_messages=list("Your leg muscles pulsate.") + mutation=mRun + + New() + block=GLOB.INCREASERUNBLOCK + +/datum/dna/gene/basic/remotetalk + name="Telepathy" + activation_messages=list("You expand your mind outwards.") + mutation=mRemotetalk + + New() + block=GLOB.REMOTETALKBLOCK + + activate(var/mob/M, var/connected, var/flags) + ..(M,connected,flags) + M.verbs += /mob/living/carbon/human/proc/remotesay + +/datum/dna/gene/basic/morph + name="Morph" + activation_messages=list("Your skin feels strange.") + mutation=mMorph + + New() + block=GLOB.MORPHBLOCK + + activate(var/mob/M) + ..(M) + M.verbs += /mob/living/carbon/human/proc/morph + +/* Not used on bay +/datum/dna/gene/basic/heat_resist + name="Heat Resistance" + activation_messages=list("Your skin is icy to the touch.") + mutation=mHeatres + + New() + block=GLOB.COLDBLOCK + + can_activate(var/mob/M,var/flags) + if(flags & MUTCHK_FORCED) + return !(/datum/dna/gene/basic/cold_resist in M.active_genes) + // Probability check + var/_prob = 15 + if(COLD_RESISTANCE in M.mutations) + _prob=5 + if(probinj(_prob,(flags&MUTCHK_FORCED))) + return 1 + + OnDrawUnderlays(var/mob/M,var/g,var/fat) + return "cold[fat]_s" +*/ + +/datum/dna/gene/basic/cold_resist + name="Cold Resistance" + activation_messages=list("Your body is filled with warmth.") + mutation=COLD_RESISTANCE + + New() + block=GLOB.FIREBLOCK + + can_activate(var/mob/M,var/flags) + if(flags & MUTCHK_FORCED) + return 1 + // return !(/datum/dna/gene/basic/heat_resist in M.active_genes) + // Probability check + var/_prob=30 + //if(mHeatres in M.mutations) + // _prob=5 + if(probinj(_prob,(flags&MUTCHK_FORCED))) + return 1 + + OnDrawUnderlays(var/mob/M,var/g,var/fat) + return "fire[fat]_s" + +/datum/dna/gene/basic/noprints + name="No Prints" + activation_messages=list("Your fingers feel numb.") + mutation=mFingerprints + + New() + block=GLOB.NOPRINTSBLOCK + +/datum/dna/gene/basic/noshock + name="Shock Immunity" + activation_messages=list("Your skin feels strange.") + mutation=mShock + + New() + block=GLOB.SHOCKIMMUNITYBLOCK + +/datum/dna/gene/basic/midget + name="Midget" + activation_messages=list("Your skin feels rubbery.") + mutation=mSmallsize + + New() + block=GLOB.SMALLSIZEBLOCK + + can_activate(var/mob/M,var/flags) + // Can't be big and small. + if(HULK in M.mutations) + return 0 + return ..(M,flags) + + activate(var/mob/M, var/connected, var/flags) + ..(M,connected,flags) + M.pass_flags |= 1 + + deactivate(var/mob/M, var/connected, var/flags) + ..(M,connected,flags) + M.pass_flags &= ~1 //This may cause issues down the track, but offhand I can't think of any other way for humans to get passtable short of varediting so it should be fine. ~Z + +/datum/dna/gene/basic/hulk + name="Hulk" + activation_messages=list("Your muscles hurt.") + mutation=HULK + + New() + block=GLOB.HULKBLOCK + + can_activate(var/mob/M,var/flags) + // Can't be big and small. + if(mSmallsize in M.mutations) + return 0 + return ..(M,flags) + + OnDrawUnderlays(var/mob/M,var/g,var/fat) + if(fat) + return "hulk_[fat]_s" + else + return "hulk_[g]_s" + return 0 + + OnMobLife(var/mob/living/carbon/human/M) + if(!istype(M)) return + if(M.health <= 25) + M.mutations.Remove(HULK) + M.update_mutations() //update our mutation overlays + to_chat(M, "You suddenly feel very weak.") + M.Weaken(3) + M.emote("collapse") + +/datum/dna/gene/basic/xray + name="X-Ray Vision" + activation_messages=list("The walls suddenly disappear.") + mutation=XRAY + + New() + block=GLOB.XRAYBLOCK + +/datum/dna/gene/basic/tk + name="Telekenesis" + activation_messages=list("You feel smarter.") + mutation=TK + activation_prob=15 + + New() + block=GLOB.TELEBLOCK + OnDrawUnderlays(var/mob/M,var/g,var/fat) + return "telekinesishead[fat]_s" diff --git a/code/game/gamemodes/calamity/calamity.dm b/code/game/gamemodes/calamity/calamity.dm new file mode 100644 index 00000000..5ada210f --- /dev/null +++ b/code/game/gamemodes/calamity/calamity.dm @@ -0,0 +1,27 @@ +#define ANTAG_TYPE_RATIO 8 + +/datum/game_mode/calamity + name = "Calamity" + round_description = "This must be a Thursday. You never could get the hang of Thursdays..." + extended_round_description = "All hell is about to break loose. Literally every antagonist type may spawn in this round. Hold on tight." + config_tag = "calamity" + required_players = 1 + votable = 0 + event_delay_mod_moderate = 0.5 + event_delay_mod_major = 0.75 + +/datum/game_mode/calamity/create_antagonists() + var/list/antag_candidates = all_random_antag_types() + + 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 + antag_tags |= antag_id + + ..() + +/datum/game_mode/calamity/check_victory() + to_world("This terrible, terrible day has finally ended!") + +#undef ANTAG_TYPE_RATIO diff --git a/code/game/gamemodes/changeling/absorbed_dna.dm b/code/game/gamemodes/changeling/absorbed_dna.dm new file mode 100644 index 00000000..2527f906 --- /dev/null +++ b/code/game/gamemodes/changeling/absorbed_dna.dm @@ -0,0 +1,12 @@ +/datum/absorbed_dna + var/name + var/datum/dna/dna + var/speciesName + var/list/languages + +/datum/absorbed_dna/New(var/newName, var/newDNA, var/newSpecies, var/newLanguages) + ..() + name = newName + dna = newDNA + speciesName = newSpecies + languages = newLanguages diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm new file mode 100644 index 00000000..dcdc5532 --- /dev/null +++ b/code/game/gamemodes/changeling/changeling.dm @@ -0,0 +1,18 @@ +/datum/game_mode/changeling + name = "Changeling" + round_description = "There are alien changelings onboard. Do not let the changelings succeed!" + extended_round_description = "Life always finds a way. However, life can sometimes take a more disturbing route. \ + Humanity's extensive knowledge of xeno-biological specimens has made them confident and arrogant. Yet \ + something slipped past their eyes. Something dangerous. Something alive. Most frightening of all, \ + however, is that this something is someone. An unknown alien specimen has incorporated itself into \ + the crew. Its unique biology allows it to manipulate its own or anyone else's DNA. \ + With the ability to copy faces, voices, animals, but also change the chemical make up of your own body, \ + its existence is a threat to not only your personal safety but the lives of everyone on board. \ + No one knows where it came from. No one knows who it is or what it wants. One thing is for \ + certain though... there is never just one of them. Good luck." + config_tag = "changeling" + required_players = 8 + required_enemies = 1 + end_on_antag_death = 0 + antag_scaling_coeff = 10 + antag_tags = list(MODE_CHANGELING) diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm new file mode 100644 index 00000000..b03d1c5c --- /dev/null +++ b/code/game/gamemodes/changeling/changeling_powers.dm @@ -0,0 +1,827 @@ +var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega") + +/datum/changeling //stores changeling powers, changeling recharge thingie, changeling absorbed DNA and changeling ID (for changeling hivemind) + var/list/datum/absorbed_dna/absorbed_dna = list() + var/list/absorbed_languages = list() + var/absorbedcount = 0 + var/chem_charges = 20 + var/chem_recharge_rate = 0.5 + var/chem_storage = 50 + var/sting_range = 1 + var/changelingID = "Changeling" + var/geneticdamage = 0 + var/isabsorbing = 0 + var/geneticpoints = 25 + var/purchasedpowers = list() + var/mimicing = "" + + +/datum/changeling/New() + ..() + if(possible_changeling_IDs.len) + changelingID = pick(possible_changeling_IDs) + possible_changeling_IDs -= changelingID + changelingID = "[changelingID]" + else + changelingID = "[rand(1,999)]" + +/datum/changeling/proc/regenerate() + chem_charges = min(max(0, chem_charges+chem_recharge_rate), chem_storage) + geneticdamage = max(0, geneticdamage-1) + +/datum/changeling/proc/GetDNA(var/dna_owner) + for(var/datum/absorbed_dna/DNA in absorbed_dna) + if(dna_owner == DNA.name) + return DNA + +/mob/proc/absorbDNA(var/datum/absorbed_dna/newDNA) + var/datum/changeling/changeling = null + if(src.mind && src.mind.changeling) + changeling = src.mind.changeling + if(!changeling) + return + + for(var/language in newDNA.languages) + changeling.absorbed_languages |= language + + changeling_update_languages(changeling.absorbed_languages) + + if(!changeling.GetDNA(newDNA.name)) // Don't duplicate - I wonder if it's possible for it to still be a different DNA? DNA code could use a rewrite + changeling.absorbed_dna += newDNA + +//Restores our verbs. It will only restore verbs allowed during lesser (monkey) form if we are not human +/mob/proc/make_changeling() + + if(!mind) return + if(!mind.changeling) mind.changeling = new /datum/changeling(gender) + + verbs += /datum/changeling/proc/EvolutionMenu + add_language("Changeling") + + if(iscarbon(src)) + var/mob/living/carbon/C = src + var/obj/item/organ/internal/brain/brain = C.internal_organs_by_name[BP_BRAIN] + if(brain) + brain.fake_brain = 1 + + var/lesser_form = !ishuman(src) + + if(!powerinstances.len) + for(var/P in powers) + powerinstances += new P() + + // Code to auto-purchase free powers. + for(var/datum/power/changeling/P in powerinstances) + if(!P.genomecost) // Is it free? + if(!(P in mind.changeling.purchasedpowers)) // Do we not have it already? + mind.changeling.purchasePower(mind, P.name, 0)// Purchase it. Don't remake our verbs, we're doing it after this. + + for(var/datum/power/changeling/P in mind.changeling.purchasedpowers) + if(P.isVerb) + if(lesser_form && !P.allowduringlesserform) continue + if(!(P in src.verbs)) + src.verbs += P.verbpath + + for(var/language in languages) + mind.changeling.absorbed_languages |= language + + var/mob/living/carbon/human/H = src + if(istype(H)) + var/datum/absorbed_dna/newDNA = new(H.real_name, H.dna, H.species.name, H.languages) + absorbDNA(newDNA) + + return 1 + +//removes our changeling verbs +/mob/proc/remove_changeling_powers() + if(!mind || !mind.changeling) + return + if(iscarbon(src)) + var/mob/living/carbon/C = src + var/obj/item/organ/internal/brain/brain = C.internal_organs_by_name[BP_BRAIN] + if(brain) + brain.fake_brain = 0 + for(var/datum/power/changeling/P in mind.changeling.purchasedpowers) + if(P.isVerb) + verbs -= P.verbpath + + + +//Helper proc. Does all the checks and stuff for us to avoid copypasta +/mob/proc/changeling_power(var/required_chems=0, var/required_dna=0, var/max_genetic_damage=100, var/max_stat=0) + + if(!src.mind) return + if(!iscarbon(src)) return + + var/datum/changeling/changeling = src.mind.changeling + if(!changeling) + world.log << "[src] has the changeling_transform() verb but is not a changeling." + return + + if(src.stat > max_stat) + to_chat(src, "We are incapacitated.") + return + + if(changeling.absorbed_dna.len < required_dna) + to_chat(src, "We require at least [required_dna] samples of compatible DNA.") + return + + if(changeling.chem_charges < required_chems) + to_chat(src, "We require at least [required_chems] units of chemicals to do that!") + return + + if(changeling.geneticdamage > max_genetic_damage) + to_chat(src, "Our genomes are still reassembling. We need time to recover first.") + return + + return changeling + + +//Used to dump the languages from the changeling datum into the actual mob. +/mob/proc/changeling_update_languages(var/updated_languages) + + languages = list() + for(var/language in updated_languages) + languages += language + + //This isn't strictly necessary but just to be safe... + add_language("Changeling") + + return + +//Absorbs the victim's DNA making them uncloneable. Requires a strong grip on the victim. +//Doesn't cost anything as it's the most basic ability. +/mob/proc/changeling_absorb_dna() + set category = "Changeling" + set name = "Absorb DNA" + + var/datum/changeling/changeling = changeling_power(0,0,100) + if(!changeling) return + + var/obj/item/grab/G = src.get_active_hand() + if(!istype(G)) + to_chat(src, "We must be grabbing a creature in our active hand to absorb them.") + return + + var/mob/living/carbon/human/T = G.affecting + if(!istype(T)) + to_chat(src, "[T] is not compatible with our biology.") + return + + if(T.species.species_flags & SPECIES_FLAG_NO_SCAN) + to_chat(src, "We cannot extract DNA from this creature!") + return + + if(HUSK in T.mutations) + to_chat(src, "This creature's DNA is ruined beyond useability!") + return + + if(!G.can_absorb()) + to_chat(src, "We must have a tighter grip to absorb this creature.") + return + + if(changeling.isabsorbing) + to_chat(src, "We are already absorbing!") + return + + var/obj/item/organ/external/affecting = T.get_organ(src.zone_sel.selecting) + if(!affecting) + to_chat(src, "They are missing that body part!") + + changeling.isabsorbing = 1 + for(var/stage = 1, stage<=3, stage++) + switch(stage) + if(1) + to_chat(src, "This creature is compatible. We must hold still...") + if(2) + to_chat(src, "We extend a proboscis.") + src.visible_message("[src] extends a proboscis!") + if(3) + to_chat(src, "We stab [T] with the proboscis.") + src.visible_message("[src] stabs [T] with the proboscis!") + to_chat(T, "You feel a sharp stabbing pain!") + affecting.take_damage(39, 0, DAM_SHARP, "large organic needle") + + feedback_add_details("changeling_powers","A[stage]") + if(!do_mob(src, T, 150)) + to_chat(src, "Our absorption of [T] has been interrupted!") + changeling.isabsorbing = 0 + return + + to_chat(src, "We have absorbed [T]!") + src.visible_message("[src] sucks the fluids from [T]!") + to_chat(T, "You have been absorbed by the changeling!") + changeling.chem_charges += 10 + changeling.geneticpoints += 2 + + //Steal all of their languages! + for(var/language in T.languages) + if(!(language in changeling.absorbed_languages)) + changeling.absorbed_languages += language + + changeling_update_languages(changeling.absorbed_languages) + + var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages) + absorbDNA(newDNA) + if(mind && T.mind) + mind.store_memory("[T.real_name]'s memories:") + mind.store_memory(T.mind.memory) + mind.store_memory("
    ") + + if(T.mind && T.mind.changeling) + if(T.mind.changeling.absorbed_dna) + for(var/datum/absorbed_dna/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot + if(changeling.GetDNA(dna_data.name)) + continue + absorbDNA(dna_data) + changeling.absorbedcount++ + T.mind.changeling.absorbed_dna.len = 1 + + if(T.mind.changeling.purchasedpowers) + for(var/datum/power/changeling/Tp in T.mind.changeling.purchasedpowers) + if(Tp in changeling.purchasedpowers) + continue + else + changeling.purchasedpowers += Tp + + if(!Tp.isVerb) + call(Tp.verbpath)() + else + src.make_changeling() + + changeling.chem_charges += T.mind.changeling.chem_charges + changeling.geneticpoints += T.mind.changeling.geneticpoints + T.mind.changeling.chem_charges = 0 + T.mind.changeling.geneticpoints = 0 + T.mind.changeling.absorbedcount = 0 + + changeling.absorbedcount++ + changeling.isabsorbing = 0 + + T.death(0) + T.Drain() + return 1 + + +//Change our DNA to that of somebody we've absorbed. +/mob/proc/changeling_transform() + set category = "Changeling" + set name = "Transform (5)" + + var/datum/changeling/changeling = changeling_power(5,1,0) + if(!changeling) return + + var/list/names = list() + for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna) + names += "[DNA.name]" + + var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names + if(!S) return + + var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S) + if(!chosen_dna) + return + + changeling.chem_charges -= 5 + changeling.geneticdamage = 30 + + var/S_name = chosen_dna.speciesName + var/datum/species/S_dat = all_species[S_name] + var/changeTime = 2 SECONDS + if(mob_size != S_dat.mob_size) + src.visible_message("[src]'s body begins to twist, their mass changing rapidly!") + changeTime = 8 SECONDS + else + src.visible_message("[src]'s body begins to twist, changing rapidly!") + + if(!do_after(src, changeTime)) + to_chat(src, "You fail to change shape.") + return + handle_changeling_transform(chosen_dna) + + src.verbs -= /mob/proc/changeling_transform + spawn(10) + src.verbs += /mob/proc/changeling_transform + + changeling_update_languages(changeling.absorbed_languages) + + feedback_add_details("changeling_powers","TR") + return 1 + +/mob/proc/handle_changeling_transform(var/datum/absorbed_dna/chosen_dna) + src.visible_message("[src] transforms!") + + src.dna = chosen_dna.dna + src.real_name = chosen_dna.name + src.flavor_text = "" + + if(ishuman(src)) + var/mob/living/carbon/human/H = src + var/newSpecies = chosen_dna.speciesName + H.set_species(newSpecies,1) + H.b_type = chosen_dna.dna.b_type + H.sync_organ_dna() + + domutcheck(src, null) + src.UpdateAppearance() + + +//Transform into a monkey. +/mob/proc/changeling_lesser_form() + set category = "Changeling" + set name = "Lesser Form (1)" + + var/datum/changeling/changeling = changeling_power(1,0,0) + if(!changeling) return + + if(src.has_brain_worms()) + to_chat(src, "We cannot perform this ability at the present time!") + return + + var/mob/living/carbon/human/H = src + + if(!istype(H) || !H.species.primitive_form) + to_chat(src, "We cannot perform this ability in this form!") + return + + changeling.chem_charges-- + H.visible_message("[H] transforms!") + changeling.geneticdamage = 30 + to_chat(H, "Our genes cry out!") + H = H.monkeyize() + feedback_add_details("changeling_powers","LF") + return 1 + +//Transform into a human +/mob/proc/changeling_lesser_transform() + set category = "Changeling" + set name = "Transform (1)" + + var/datum/changeling/changeling = changeling_power(1,1,0) + if(!changeling) return + + var/list/names = list() + for(var/datum/dna/DNA in changeling.absorbed_dna) + names += "[DNA.real_name]" + + var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names + if(!S) return + + var/datum/dna/chosen_dna = changeling.GetDNA(S) + if(!chosen_dna) + return + + var/mob/living/carbon/human/C = src + + changeling.chem_charges-- + C.remove_changeling_powers() + C.visible_message("[C] transforms!") + C.dna = chosen_dna.Clone() + + var/list/implants = list() + for (var/obj/item/weapon/implant/I in C) //Still preserving implants + implants += I + + C.transforming = 1 + C.canmove = 0 + C.icon = null + C.overlays.Cut() + C.set_invisibility(101) + var/atom/movable/overlay/animation = new /atom/movable/overlay( C.loc ) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = src + flick("monkey2h", animation) + sleep(48) + qdel(animation) + + for(var/obj/item/W in src) + C.drop_from_inventory(W) + + var/mob/living/carbon/human/O = new /mob/living/carbon/human( src ) + if (C.dna.GetUIState(DNA_UI_GENDER)) + O.gender = FEMALE + else + O.gender = MALE + O.dna = C.dna.Clone() + C.dna = null + O.real_name = chosen_dna.real_name + + for(var/obj/T in C) + qdel(T) + + O.loc = C.loc + + O.UpdateAppearance() + domutcheck(O, null) + O.setToxLoss(C.getToxLoss()) + O.adjustBruteLoss(C.getBruteLoss()) + O.setOxyLoss(C.getOxyLoss()) + O.adjustFireLoss(C.getFireLoss()) + O.set_stat(C.stat) + for (var/obj/item/weapon/implant/I in implants) + I.forceMove(O) + I.implanted = O + + C.mind.transfer_to(O) + O.make_changeling() + O.changeling_update_languages(changeling.absorbed_languages) + + feedback_add_details("changeling_powers","LFT") + qdel(C) + return 1 + + +//Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay. +/mob/proc/changeling_fakedeath() + set category = "Changeling" + set name = "Regenerative Stasis (20)" + + var/datum/changeling/changeling = changeling_power(20,1,100,DEAD) + if(!changeling) return + + var/mob/living/carbon/C = src + if(!C.stat && alert("Are we sure we wish to fake our death?",,"Yes","No") == "No")//Confirmation for living changelings if they want to fake their death + return + to_chat(C, "We will attempt to regenerate our form.") + C.status_flags |= FAKEDEATH //play dead + C.update_canmove() + C.remove_changeling_powers() + + C.emote("gasp") + + spawn(rand(800,2000)) + if(changeling_power(20,1,100,DEAD)) + // charge the changeling chemical cost for stasis + changeling.chem_charges -= 20 + + to_chat(C, "We are ready to rise. Use the Revive verb when you are ready.") + C.verbs += /mob/proc/changeling_revive + + feedback_add_details("changeling_powers","FD") + return 1 + +/mob/proc/changeling_revive() + set category = "Changeling" + set name = "Revive" + + var/mob/living/carbon/C = src + // restore us to health + C.revive() + // remove our fake death flag + C.status_flags &= ~(FAKEDEATH) + // let us move again + C.update_canmove() + // re-add out changeling powers + C.make_changeling() + // sending display messages + to_chat(C, "We have regenerated.") + C.verbs -= /mob/proc/changeling_revive + + +//Boosts the range of your next sting attack by 1 +/mob/proc/changeling_boost_range() + set category = "Changeling" + set name = "Ranged Sting (10)" + set desc="Your next sting ability can be used against targets 2 squares away." + + var/datum/changeling/changeling = changeling_power(10,0,100) + if(!changeling) return 0 + changeling.chem_charges -= 10 + to_chat(src, "Your throat adjusts to launch the sting.") + changeling.sting_range = 2 + src.verbs -= /mob/proc/changeling_boost_range + spawn(5) src.verbs += /mob/proc/changeling_boost_range + feedback_add_details("changeling_powers","RS") + return 1 + + +//Recover from stuns. +/mob/proc/changeling_unstun() + set category = "Changeling" + set name = "Epinephrine Sacs (45)" + set desc = "Removes all stuns" + + var/datum/changeling/changeling = changeling_power(45,0,100,UNCONSCIOUS) + if(!changeling) return 0 + changeling.chem_charges -= 45 + + var/mob/living/carbon/human/C = src + C.set_stat(CONSCIOUS) + C.SetParalysis(0) + C.SetStunned(0) + C.SetWeakened(0) + C.lying = 0 + C.update_canmove() + + src.verbs -= /mob/proc/changeling_unstun + spawn(5) src.verbs += /mob/proc/changeling_unstun + feedback_add_details("changeling_powers","UNS") + return 1 + + +//Speeds up chemical regeneration +/mob/proc/changeling_fastchemical() + src.mind.changeling.chem_recharge_rate *= 2 + return 1 + +//Increases macimum chemical storage +/mob/proc/changeling_engorgedglands() + src.mind.changeling.chem_storage += 25 + return 1 + + +//Prevents AIs tracking you but makes you easily detectable to the human-eye. +/mob/proc/changeling_digitalcamo() + set category = "Changeling" + set name = "Toggle Digital Camoflague" + set desc = "The AI can no longer track us, but we will look different if examined. Has a constant cost while active." + + var/datum/changeling/changeling = changeling_power() + if(!changeling) return 0 + + var/mob/living/carbon/human/C = src + if(C.digitalcamo) to_chat(C, "We return to normal.") + else to_chat(C, "We distort our form to prevent AI-tracking.") + C.digitalcamo = !C.digitalcamo + + spawn(0) + while(C && C.digitalcamo && C.mind && C.mind.changeling) + C.mind.changeling.chem_charges = max(C.mind.changeling.chem_charges - 1, 0) + sleep(40) + + src.verbs -= /mob/proc/changeling_digitalcamo + spawn(5) src.verbs += /mob/proc/changeling_digitalcamo + feedback_add_details("changeling_powers","CAM") + return 1 + + +//Starts healing you every second for 10 seconds. Can be used whilst unconscious. +/mob/proc/changeling_rapidregen() + set category = "Changeling" + set name = "Rapid Regeneration (30)" + set desc = "Begins rapidly regenerating. Does not effect stuns or chemicals." + + var/datum/changeling/changeling = changeling_power(30,0,100,UNCONSCIOUS) + if(!changeling) return 0 + src.mind.changeling.chem_charges -= 30 + + var/mob/living/carbon/human/C = src + spawn(0) + for(var/i = 0, i<10,i++) + if(C) + C.adjustBruteLoss(-10) + C.adjustToxLoss(-10) + C.adjustOxyLoss(-10) + C.adjustFireLoss(-10) + sleep(10) + + src.verbs -= /mob/proc/changeling_rapidregen + spawn(5) src.verbs += /mob/proc/changeling_rapidregen + feedback_add_details("changeling_powers","RR") + return 1 + +// HIVE MIND UPLOAD/DOWNLOAD DNA + +var/list/datum/absorbed_dna/hivemind_bank = list() + +/mob/proc/changeling_hiveupload() + set category = "Changeling" + set name = "Hive Channel (10)" + set desc = "Allows you to channel DNA in the airwaves to allow other changelings to absorb it." + + var/datum/changeling/changeling = changeling_power(10,1) + if(!changeling) return + + var/list/names = list() + for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna) + var/valid = 1 + for(var/datum/absorbed_dna/DNB in hivemind_bank) + if(DNA.name == DNB.name) + valid = 0 + break + if(valid) + names += DNA.name + + if(names.len <= 0) + to_chat(src, "The airwaves already have all of our DNA.") + return + + var/S = input("Select a DNA to channel: ", "Channel DNA", null) as null|anything in names + if(!S) return + + var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S) + if(!chosen_dna) + return + + var/datum/species/spec = all_species[chosen_dna.speciesName] + + if(spec && spec.species_flags & SPECIES_FLAG_NEED_DIRECT_ABSORB) + to_chat(src, "That species must be absorbed directly.") + return + + changeling.chem_charges -= 10 + hivemind_bank += chosen_dna + to_chat(src, "We channel the DNA of [S] to the air.") + feedback_add_details("changeling_powers","HU") + return 1 + +/mob/proc/changeling_hivedownload() + set category = "Changeling" + set name = "Hive Absorb (20)" + set desc = "Allows you to absorb DNA that is being channeled in the airwaves." + + var/datum/changeling/changeling = changeling_power(20,1) + if(!changeling) return + + var/list/names = list() + for(var/datum/absorbed_dna/DNA in hivemind_bank) + if(!(changeling.GetDNA(DNA.name))) + names[DNA.name] = DNA + + if(names.len <= 0) + to_chat(src, "There's no new DNA to absorb from the air.") + return + + var/S = input("Select a DNA absorb from the air: ", "Absorb DNA", null) as null|anything in names + if(!S) return + var/datum/dna/chosen_dna = names[S] + if(!chosen_dna) + return + + changeling.chem_charges -= 20 + absorbDNA(chosen_dna) + to_chat(src, "We absorb the DNA of [S] from the air.") + feedback_add_details("changeling_powers","HD") + return 1 + +// Fake Voice + +/mob/proc/changeling_mimicvoice() + set category = "Changeling" + set name = "Mimic Voice" + set desc = "Shape our vocal glands to form a voice of someone we choose. We cannot regenerate chemicals when mimicing." + + + var/datum/changeling/changeling = changeling_power() + if(!changeling) return + + if(changeling.mimicing) + changeling.mimicing = "" + to_chat(src, "We return our vocal glands to their original location.") + return + + var/mimic_voice = sanitize(input(usr, "Enter a name to mimic.", "Mimic Voice", null), MAX_NAME_LEN) + if(!mimic_voice) + return + + changeling.mimicing = mimic_voice + + to_chat(src, "We shape our glands to take the voice of [mimic_voice], this will stop us from regenerating chemicals while active.") + to_chat(src, "Use this power again to return to our original voice and reproduce chemicals again.") + feedback_add_details("changeling_powers","MV") + + spawn(0) + while(src && src.mind && src.mind.changeling && src.mind.changeling.mimicing) + src.mind.changeling.chem_charges = max(src.mind.changeling.chem_charges - 1, 0) + sleep(40) + if(src && src.mind && src.mind.changeling) + src.mind.changeling.mimicing = "" + ////////// + //STINGS// //They get a pretty header because there's just so fucking many of them ;_; + ////////// + +/mob/proc/sting_can_reach(mob/M as mob, sting_range = 1) + if(M.loc == src.loc) + return 1 //target and source are in the same thing + if(!isturf(src.loc) || !isturf(M.loc)) + to_chat(src, "We cannot reach \the [M] with a sting!") + return 0 //One is inside, the other is outside something. + // Maximum queued turfs set to 25; I don't *think* anything raises sting_range above 2, but if it does the 25 may need raising + if(!AStar(src.loc, M.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, max_nodes=25, max_node_depth=sting_range)) //If we can't find a path, fail + to_chat(src, "We cannot find a path to sting \the [M] by!") + return 0 + return 1 + +//Handles the general sting code to reduce on copypasta (seeming as somebody decided to make SO MANY dumb abilities) +/mob/proc/changeling_sting(var/required_chems=0, var/verb_path, var/loud) + var/datum/changeling/changeling = changeling_power(required_chems) + if(!changeling) return + + var/list/victims = list() + for(var/mob/living/carbon/human/C in oview(changeling.sting_range)) + victims += C + var/mob/living/carbon/human/T = input(src, "Who will we sting?") as null|anything in victims + + if(!T) return + if(!(T in view(changeling.sting_range))) return + if(!sting_can_reach(T, changeling.sting_range)) return + if(!changeling_power(required_chems)) return + if(T.isSynthetic()) + to_chat(src, "[T] is not compatible with our biology.") + return + + changeling.chem_charges -= required_chems + changeling.sting_range = 1 + src.verbs -= verb_path + spawn(10) src.verbs += verb_path + if(!loud) + to_chat(src, "We stealthily sting [T].") + else + visible_message("[src] fires an organic shard into [T]'s chest, puncturing the stinger into their skin!") + if(!T.mind || !T.mind.changeling) return T //T will be affected by the sting + to_chat(T, "You feel a tiny prick.") + return + + +/mob/proc/changeling_lsdsting() + set category = "Changeling" + set name = "Hallucination Sting (15)" + set desc = "Causes terror in the target." + + var/mob/living/carbon/human/T = changeling_sting(15,/mob/proc/changeling_lsdsting) + if(!T) return 0 + spawn(rand(300,600)) + if(T) T.hallucination(400, 80) + feedback_add_details("changeling_powers","HS") + return 1 + +/mob/proc/changeling_silence_sting() + set category = "Changeling" + set name = "Silence sting (10)" + set desc="Sting target" + + var/mob/living/carbon/human/T = changeling_sting(10,/mob/proc/changeling_silence_sting) + if(!T) return 0 + T.silent += 30 + feedback_add_details("changeling_powers","SS") + return 1 + +/mob/proc/changeling_blind_sting() + set category = "Changeling" + set name = "Blind sting (20)" + set desc="Sting target" + + var/mob/living/carbon/human/T = changeling_sting(20,/mob/proc/changeling_blind_sting) + if(!T) return 0 + to_chat(T, "Your eyes burn horrificly!") + T.disabilities |= NEARSIGHTED + spawn(300) T.disabilities &= ~NEARSIGHTED + T.eye_blind = 10 + T.eye_blurry = 20 + feedback_add_details("changeling_powers","BS") + return 1 + +/mob/proc/changeling_deaf_sting() + set category = "Changeling" + set name = "Deaf sting (5)" + set desc="Sting target:" + + var/mob/living/carbon/human/T = changeling_sting(5,/mob/proc/changeling_deaf_sting) + if(!T) return 0 + to_chat(T, "Your ears pop and begin ringing loudly!") + T.sdisabilities |= DEAF + spawn(300) T.sdisabilities &= ~DEAF + feedback_add_details("changeling_powers","DS") + return 1 + +/mob/proc/changeling_DEATHsting() + set category = "Changeling" + set name = "Death Sting (40)" + set desc = "Causes spasms onto death." + var/loud = 1 + + var/mob/living/carbon/human/T = changeling_sting(40,/mob/proc/changeling_DEATHsting,loud) + if(!T) return 0 + to_chat(T, "You feel a small prick and your chest becomes tight.") + T.make_jittery(400) + if(T.reagents) T.reagents.add_reagent(/datum/reagent/lexorin, 40) + feedback_add_details("changeling_powers","DTHS") + return 1 + +/mob/proc/changeling_extract_dna_sting() + set category = "Changeling" + set name = "Extract DNA Sting (40)" + set desc="Stealthily sting a target to extract their DNA." + + var/datum/changeling/changeling = null + if(src.mind && src.mind.changeling) + changeling = src.mind.changeling + if(!changeling) + return 0 + + var/mob/living/carbon/human/T = changeling_sting(40, /mob/proc/changeling_extract_dna_sting) + if(!T) return 0 + if((HUSK in T.mutations) || (T.species.species_flags & SPECIES_FLAG_NO_SCAN)) + to_chat(src, "We cannot extract DNA from this creature!") + return 0 + + if(T.species.species_flags & SPECIES_FLAG_NEED_DIRECT_ABSORB) + to_chat(src, "That species must be absorbed directly.") + return + + var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages) + absorbDNA(newDNA) + + feedback_add_details("changeling_powers","ED") + return 1 diff --git a/code/game/gamemodes/changeling/modularchangling.dm b/code/game/gamemodes/changeling/modularchangling.dm new file mode 100644 index 00000000..73a6ceb7 --- /dev/null +++ b/code/game/gamemodes/changeling/modularchangling.dm @@ -0,0 +1,484 @@ +// READ: Don't use the apostrophe in name or desc. Causes script errors. + +var/list/powers = typesof(/datum/power/changeling) - /datum/power/changeling //needed for the badmin verb for now +var/list/datum/power/changeling/powerinstances = list() + +/datum/power //Could be used by other antags too + var/name = "Power" + var/desc = "Placeholder" + var/helptext = "" + var/isVerb = 1 // Is it an active power, or passive? + var/verbpath // Path to a verb that contains the effects. + +/datum/power/changeling + var/allowduringlesserform = 0 + var/genomecost = 500000 // Cost for the changling to evolve this power. + +/datum/power/changeling/absorb_dna + name = "Absorb DNA" + desc = "Permits us to syphon the DNA from a human. They become one with us, and we become stronger." + genomecost = 0 + verbpath = /mob/proc/changeling_absorb_dna + +/datum/power/changeling/transform + name = "Transform" + desc = "We take on the apperance and voice of one we have absorbed." + genomecost = 0 + verbpath = /mob/proc/changeling_transform + +/datum/power/changeling/fakedeath + name = "Regenerative Stasis" + desc = "We become weakened to a death-like state, where we will rise again from death." + helptext = "Can be used before or after death. Duration varies greatly." + genomecost = 0 + allowduringlesserform = 1 + verbpath = /mob/proc/changeling_fakedeath + +// Hivemind + +/datum/power/changeling/hive_upload + name = "Hive Channel" + desc = "We can channel a DNA into the airwaves, allowing our fellow changelings to absorb it and transform into it as if they acquired the DNA themselves." + helptext = "Allows other changelings to absorb the DNA you channel from the airwaves. Will not help them towards their absorb objectives." + genomecost = 0 + verbpath = /mob/proc/changeling_hiveupload + +/datum/power/changeling/hive_download + name = "Hive Absorb" + desc = "We can absorb a single DNA from the airwaves, allowing us to use more disguises with help from our fellow changelings." + helptext = "Allows you to absorb a single DNA and use it. Does not count towards your absorb objective." + genomecost = 0 + verbpath = /mob/proc/changeling_hivedownload + +/datum/power/changeling/lesser_form + name = "Lesser Form" + desc = "We debase ourselves and become lesser. We become a monkey." + genomecost = 4 + verbpath = /mob/proc/changeling_lesser_form + +/datum/power/changeling/deaf_sting + name = "Deaf Sting" + desc = "We silently sting a human, completely deafening them for a short time." + genomecost = 1 + allowduringlesserform = 1 + verbpath = /mob/proc/changeling_deaf_sting + +/datum/power/changeling/blind_sting + name = "Blind Sting" + desc = "We silently sting a human, completely blinding them for a short time." + genomecost = 2 + allowduringlesserform = 1 + verbpath = /mob/proc/changeling_blind_sting + +/datum/power/changeling/silence_sting + name = "Silence Sting" + desc = "We silently sting a human, completely silencing them for a short time." + helptext = "Does not provide a warning to a victim that they have been stung, until they try to speak and cannot." + genomecost = 3 + allowduringlesserform = 1 + verbpath = /mob/proc/changeling_silence_sting + +/datum/power/changeling/mimicvoice + name = "Mimic Voice" + desc = "We shape our vocal glands to sound like a desired voice." + helptext = "Will turn your voice into the name that you enter. We must constantly expend chemicals to maintain our form like this" + genomecost = 1 + verbpath = /mob/proc/changeling_mimicvoice + +/datum/power/changeling/extractdna + name = "Extract DNA" + desc = "We stealthily sting a target and extract the DNA from them." + helptext = "Will give you the DNA of your target, allowing you to transform into them. Does not count towards absorb objectives." + genomecost = 2 + allowduringlesserform = 1 + verbpath = /mob/proc/changeling_extract_dna_sting + +/datum/power/changeling/LSDSting + name = "Hallucination Sting" + desc = "We evolve the ability to sting a target with a powerful hallunicationary chemical." + helptext = "The target does not notice they have been stung. The effect occurs after 30 to 60 seconds." + genomecost = 3 + verbpath = /mob/proc/changeling_lsdsting + +/datum/power/changeling/DeathSting + name = "Death Sting" + desc = "We sting a human, filling them with potent chemicals. Their rapid death is all but assured, but our crime will be obvious." + helptext = "It will be clear to any surrounding witnesses if you use this power." + genomecost = 10 + verbpath = /mob/proc/changeling_DEATHsting + + +/datum/power/changeling/boost_range + name = "Boost Range" + desc = "We evolve the ability to shoot our stingers at humans, with some preperation." + genomecost = 2 + allowduringlesserform = 1 + verbpath = /mob/proc/changeling_boost_range + +/datum/power/changeling/Epinephrine + name = "Epinephrine sacs" + desc = "We evolve additional sacs of adrenaline throughout our body." + helptext = "Gives the ability to instantly recover from stuns. High chemical cost." + genomecost = 3 + verbpath = /mob/proc/changeling_unstun + +/datum/power/changeling/ChemicalSynth + name = "Rapid Chemical-Synthesis" + desc = "We evolve new pathways for producing our necessary chemicals, permitting us to naturally create them faster." + helptext = "Doubles the rate at which we naturally recharge chemicals." + genomecost = 4 + isVerb = 0 + verbpath = /mob/proc/changeling_fastchemical +/* +/datum/power/changeling/AdvChemicalSynth + name = "Advanced Chemical-Synthesis" + desc = "We evolve new pathways for producing our necessary chemicals, permitting us to naturally create them faster." + helptext = "Doubles the rate at which we naturally recharge chemicals." + genomecost = 8 + isVerb = 0 + verbpath = /mob/proc/changeling_fastchemical +*/ +/datum/power/changeling/EngorgedGlands + name = "Engorged Chemical Glands" + desc = "Our chemical glands swell, permitting us to store more chemicals inside of them." + helptext = "Allows us to store an extra 25 units of chemicals." + genomecost = 4 + isVerb = 0 + verbpath = /mob/proc/changeling_engorgedglands + +/datum/power/changeling/DigitalCamoflague + name = "Digital Camoflauge" + desc = "We evolve the ability to distort our form and proprtions, defeating common altgorthms used to detect lifeforms on cameras." + helptext = "We cannot be tracked by camera while using this skill. However, humans looking at us will find us.. uncanny. We must constantly expend chemicals to maintain our form like this." + genomecost = 1 + allowduringlesserform = 1 + verbpath = /mob/proc/changeling_digitalcamo + +/datum/power/changeling/rapidregeneration + name = "Rapid Regeneration" + desc = "We evolve the ability to rapidly regenerate, negating the need for stasis." + helptext = "Heals a moderate amount of damage every tick." + genomecost = 7 + verbpath = /mob/proc/changeling_rapidregen + + + +// Modularchangling, totally stolen from the new player panel. YAYY +/datum/changeling/proc/EvolutionMenu()//The new one + set category = "Changeling" + set desc = "Level up!" + + if(!usr || !usr.mind || !usr.mind.changeling) return + src = usr.mind.changeling + + if(!powerinstances.len) + for(var/P in powers) + powerinstances += new P() + + var/dat = "Changling Evolution Menu" + + //javascript, the part that does most of the work~ + dat += {" + + + + + + + "} + + //body tag start + onload and onkeypress (onkeyup) javascript event calls + dat += "" + + //title + search bar + dat += {" + + + + + + + + +
    + Changling Evolution Menu
    + Hover over a power to see more information
    + Current evolution points left to evolve with: [geneticpoints]
    + Absorb genomes to acquire more evolution points +

    +

    + Search: +
    + + "} + + //player table header + dat += {" + + "} + + var/i = 1 + for(var/datum/power/changeling/P in powerinstances) + var/ownsthis = 0 + + if(P in purchasedpowers) + ownsthis = 1 + + + var/color = "#e6e6e6" + if(i%2 == 0) + color = "#f2f2f2" + + + dat += {" + + + + + + "} + + i++ + + + //player table ending + dat += {" +
    + + + Evolve [P] - Cost: [ownsthis ? "Purchased" : P.genomecost] + +
    +
    +
    + + + + "} + + usr << browse(dat, "window=powers;size=900x480") + + +/datum/changeling/Topic(href, href_list) + ..() + if(!ismob(usr)) + return + + if(href_list["P"]) + var/datum/mind/M = usr.mind + if(!istype(M)) + return + purchasePower(M, href_list["P"]) + call(/datum/changeling/proc/EvolutionMenu)() + + + +/datum/changeling/proc/purchasePower(var/datum/mind/M, var/Pname, var/remake_verbs = 1) + if(!M || !M.changeling) + return + + var/datum/power/changeling/Thepower = Pname + + + for (var/datum/power/changeling/P in powerinstances) +// log_debug("[P] - [Pname] = [P.name == Pname ? "True" : "False"]") + + if(P.name == Pname) + Thepower = P + break + + + if(Thepower == null) + to_chat(M.current, "This is awkward. Changeling power purchase failed, please report this bug to a coder!") + return + + if(Thepower in purchasedpowers) + to_chat(M.current, "We have already evolved this ability!") + return + + + if(geneticpoints < Thepower.genomecost) + to_chat(M.current, "We cannot evolve this... yet. We must acquire more DNA.") + return + + geneticpoints -= Thepower.genomecost + + purchasedpowers += Thepower + + if(!Thepower.isVerb && Thepower.verbpath) + call(M.current, Thepower.verbpath)() + else if(remake_verbs) + M.current.make_changeling() + diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm new file mode 100644 index 00000000..c94a3d08 --- /dev/null +++ b/code/game/gamemodes/cult/cult.dm @@ -0,0 +1,9 @@ +/datum/game_mode/cult + name = "Cult" + round_description = "Some crewmembers are attempting to start a cult!" + extended_round_description = "There has been an infiltration 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 = 20 + 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 new file mode 100644 index 00000000..6196bf83 --- /dev/null +++ b/code/game/gamemodes/cult/cult_items.dm @@ -0,0 +1,113 @@ +/obj/item/weapon/melee/cultblade + name = "cult blade" + desc = "An arcane weapon wielded by the followers of Nar-Sie." + icon_state = "cultblade" + item_state = "cultblade" + edge = 1 + sharp = 1 + w_class = ITEM_SIZE_LARGE + 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/attack(mob/living/M, mob/living/user, var/target_zone) + //if(iscultist(user) || (user.mind in godcult.current_antagonists)) + // return ..() + + var/zone = (user.hand ? BP_L_ARM : BP_R_ARM) + + var/obj/item/organ/external/affecting = null + if(ishuman(user)) + var/mob/living/carbon/human/H = user + affecting = H.get_organ(zone) + + if(affecting) + to_chat(user, "An unexplicable force rips through your [affecting.name], tearing the sword from your grasp!") + else + to_chat(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, (DAM_SHARP|DAM_EDGE)) + user.Weaken(5) + + user.drop_from_inventory(src) + throw_at(get_edge_target_turf(src, pick(GLOB.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 + +/obj/item/weapon/melee/cultblade/pickup(mob/living/user as mob) + if(!iscultist(user)) + to_chat(user, "An overwhelming feeling of dread comes over you as you pick up the cultist's sword. It would be wise to be rid of this blade quickly.") + user.make_dizzy(120) + + +/obj/item/clothing/head/culthood + name = "cult hood" + icon_state = "culthood" + desc = "A hood worn by the followers of Nar-Sie." + flags_inv = HIDEFACE + body_parts_covered = HEAD + armor = list(melee = 30, bullet = 10, laser = 5,energy = 5, bomb = 0, bio = 0, rad = 0) + cold_protection = HEAD + min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE + siemens_coefficient = 0.8 //That's a pretty cool opening in the hood. Also: Cloth making physical contact to the skull. + +/obj/item/clothing/head/culthood/magus + name = "magus helm" + icon_state = "magus" + desc = "A helm worn by the followers of Nar-Sie." + flags_inv = HIDEFACE | BLOCKHAIR + body_parts_covered = HEAD|FACE|EYES + armor = list(melee = 50, bullet = 40, laser = 30, energy = 20, bomb = 15, bio = 0, rad = 0) + +/obj/item/clothing/head/culthood/alt + icon_state = "cult_hoodalt" + +/obj/item/clothing/suit/cultrobes + name = "cult robes" + desc = "A set of durable robes worn by the followers of Nar-Sie." + icon_state = "cultrobes" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + allowed = list(/obj/item/weapon/book/tome,/obj/item/weapon/melee/cultblade) + armor = list(melee = 35, bullet = 30, laser = 25,energy = 20, bomb = 25, bio = 10, rad = 0) + flags_inv = HIDEJUMPSUIT + siemens_coefficient = 0.6 + +/obj/item/clothing/suit/cultrobes/alt + icon_state = "cultrobesalt" + +/obj/item/clothing/suit/cultrobes/magusred + name = "magus robes" + desc = "A set of plated robes worn by the followers of Nar-Sie." + icon_state = "magusred" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT + armor = list(melee = 75, bullet = 50, laser = 55, energy = 40, bomb = 50, bio = 10, rad = 0) + +/obj/item/clothing/suit/cultrobes/magusred/New() + ..() + slowdown_per_slot[slot_wear_suit] = 1 + +/obj/item/clothing/head/helmet/space/cult + name = "cult helmet" + desc = "A space worthy helmet used by the followers of Nar-Sie." + icon_state = "cult_helmet" + armor = list(melee = 60, bullet = 60, laser = 60,energy = 15, bomb = 30, bio = 100, rad = 30) //Real tanky shit. + siemens_coefficient = 0.3 //Bone is not very conducive to electricity. + +/obj/item/clothing/suit/space/cult + name = "cult armour" + icon_state = "cult_armour" + desc = "A bulky suit of armour, bristling with spikes. It looks space proof." + allowed = list(/obj/item/weapon/book/tome,/obj/item/weapon/melee/cultblade,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit) + armor = list(melee = 60, bullet = 50, laser = 60,energy = 15, bomb = 30, bio = 100, rad = 30) + siemens_coefficient = 0.2 + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS|HANDS + +/obj/item/clothing/suit/space/cult/New() + ..() + slowdown_per_slot[slot_wear_suit] = 1 \ No newline at end of file diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm new file mode 100644 index 00000000..e9faa6f2 --- /dev/null +++ b/code/game/gamemodes/cult/cult_structures.dm @@ -0,0 +1,169 @@ +/obj/structure/cult + density = 1 + anchored = 1 + icon = 'icons/obj/cult.dmi' + +/obj/structure/cult/talisman + name = "Altar" + desc = "A bloodstained altar dedicated to Nar-Sie." + icon_state = "talismanaltar" + + +/obj/structure/cult/forge + name = "Daemon forge" + desc = "A forge used in crafting the unholy weapons used by the armies of Nar-Sie." + icon_state = "forge" + +/obj/structure/cult/pylon + name = "Pylon" + desc = "A floating crystal that hums with an unearthly energy." + icon_state = "pylon" + var/isbroken = 0 + light_power = 2 + light_range = 13 + light_color = "#3e0000" + var/obj/item/wepon = null + +/obj/structure/cult/pylon/attack_hand(mob/M as mob) + attackpylon(M, 5) + +/obj/structure/cult/pylon/attack_generic(var/mob/user, var/damage) + attackpylon(user, damage) + +/obj/structure/cult/pylon/attackby(obj/item/W as obj, mob/user as mob) + attackpylon(user, W.force) + +/obj/structure/cult/pylon/proc/attackpylon(mob/user as mob, var/damage) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(!isbroken) + if(prob(1+ damage * 5)) + user.visible_message( + "[user] smashed the pylon!", + "You hit the pylon, and its crystal breaks apart!", + "You hear a tinkle of crystal shards" + ) + playsound(get_turf(src), 'sound/effects/Glassbr3.ogg', 75, 1) + isbroken = 1 + set_density(0) + icon_state = "pylon-broken" + set_light(0) + else + to_chat(user, "You hit the pylon!") + playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 75, 1) + else + if(prob(damage * 2)) + to_chat(user, "You pulverize what was left of the pylon!") + qdel(src) + else + to_chat(user, "You hit the pylon!") + playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 75, 1) + + +/obj/structure/cult/pylon/proc/repair(mob/user as mob) + if(isbroken) + to_chat(user, "You repair the pylon.") + isbroken = 0 + set_density(1) + icon_state = "pylon" + set_light(5) + +/obj/structure/cult/tome + name = "Desk" + desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl." + icon_state = "tomealtar" + +//sprites for this no longer exist -Pete +//(they were stolen from another game anyway) +/* +/obj/structure/cult/pillar + name = "Pillar" + desc = "This should not exist." + icon_state = "pillar" + icon = 'magic_pillar.dmi' +*/ + +/obj/effect/gateway + name = "gateway" + desc = "You're pretty sure that abyss is staring back." + icon = 'icons/obj/cult.dmi' + icon_state = "hole" + density = 1 + unacidable = 1 + anchored = 1.0 + var/spawnable = null + +/obj/effect/gateway/Bumped(mob/M as mob|obj) + spawn(0) + return + return + +/obj/effect/gateway/Crossed(AM as mob|obj) + spawn(0) + return + return + +/obj/effect/gateway/active + light_range=5 + light_color="#ff0000" + spawnable=list( + /mob/living/simple_animal/hostile/scarybat, + /mob/living/simple_animal/hostile/creature, + /mob/living/simple_animal/hostile/faithless + ) + +/obj/effect/gateway/active/cult + light_range=5 + light_color="#ff0000" + spawnable=list( + /mob/living/simple_animal/hostile/scarybat/cult, + /mob/living/simple_animal/hostile/creature/cult, + /mob/living/simple_animal/hostile/faithless/cult + ) + +/obj/effect/gateway/active/New() + spawn(rand(30,60) SECONDS) + var/t = pick(spawnable) + new t(src.loc) + qdel(src) + +/obj/effect/gateway/active/Crossed(var/atom/A) + if(!istype(A, /mob/living)) + return + + var/mob/living/M = A + + if(M.stat != DEAD) + if(M.transforming) + return + if(M.has_brain_worms()) + return //Borer stuff - RR + + if(iscultist(M)) return + if(!ishuman(M) && !isrobot(M)) return + + M.transforming = 1 + M.canmove = 0 + M.icon = null + M.overlays.len = 0 + M.set_invisibility(101) + + if(istype(M, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/Robot = M + if(Robot.mmi) + qdel(Robot.mmi) + else + for(var/obj/item/W in M) + if(istype(W, /obj/item/weapon/implant)) + qdel(W) + continue + M.drop_from_inventory(W) + + var/mob/living/new_mob = new /mob/living/simple_animal/corgi(A.loc) + new_mob.a_intent = I_HURT + if(M.mind) + M.mind.transfer_to(new_mob) + else + new_mob.key = M.key + + to_chat(new_mob, "Your form morphs into that of a corgi.")//Because we don't have cluwnes + diff --git a/code/game/gamemodes/cult/cultify/de-cultify.dm b/code/game/gamemodes/cult/cultify/de-cultify.dm new file mode 100644 index 00000000..b0579ccc --- /dev/null +++ b/code/game/gamemodes/cult/cultify/de-cultify.dm @@ -0,0 +1,6 @@ +/turf/unsimulated/wall/cult/attackby(var/obj/item/I, var/mob/user) + if(istype(I, /obj/item/weapon/nullrod)) + user.visible_message("\The [user] touches \the [src] with \the [I], and it shifts.", "You touch \the [src] with \the [I], and it shifts.") + ChangeTurf(/turf/unsimulated/wall) + return + ..() \ No newline at end of file diff --git a/code/game/gamemodes/cult/cultify/mob.dm b/code/game/gamemodes/cult/cultify/mob.dm new file mode 100644 index 00000000..684a0278 --- /dev/null +++ b/code/game/gamemodes/cult/cultify/mob.dm @@ -0,0 +1,62 @@ +/mob + //thou shall always be able to see the Geometer of Blood + var/image/narsimage = null + var/image/narglow = null + +/mob/proc/cultify() + return + +/mob/observer/ghost/cultify() + if(icon_state != "ghost-narsie") + icon = 'icons/mob/mob.dmi' + icon_state = "ghost-narsie" + overlays = 0 + set_invisibility(0) + to_chat(src, "Even as a non-corporal being, you can feel Nar-Sie's presence altering you. You are now visible to everyone.") + +/mob/living/cultify() + if(iscultist(src) && client) + var/mob/living/simple_animal/construct/harvester/C = new(get_turf(src)) + mind.transfer_to(C) + to_chat(C, "The Geometer of Blood is overjoyed to be reunited with its followers, and accepts your body in sacrifice. As reward, you have been gifted with the shell of an Harvester.
    Your tendrils can use and draw runes without need for a tome, your eyes can see beings through walls, and your mind can open any door. Use these assets to serve Nar-Sie and bring him any remaining living human in the world.
    You can teleport yourself back to Nar-Sie along with any being under yourself at any time using your \"Harvest\" spell.
    ") + dust() + else if(client) + var/mob/observer/ghost/G = (ghostize()) + G.icon = 'icons/mob/mob.dmi' + G.icon_state = "ghost-narsie" + G.overlays = 0 + G.set_invisibility(0) + to_chat(G, "You feel relieved as what's left of your soul finally escapes its prison of flesh.") + else + dust() + +/mob/proc/see_narsie(var/obj/singularity/narsie/large/N, var/dir) + if(N.chained) + if(narsimage) + qdel(narsimage) + qdel(narglow) + return + if((N.z == src.z)&&(get_dist(N,src) <= (N.consume_range+10)) && !(N in view(src))) + if(!narsimage) //Create narsimage + narsimage = image('icons/obj/narsie.dmi',src.loc,"narsie",9,1) + narsimage.mouse_opacity = 0 + if(!narglow) //Create narglow + narglow = image('icons/obj/narsie.dmi',narsimage.loc,"glow-narsie",12,1) + narglow.mouse_opacity = 0 + //Else if no dir is given, simply send them the image of narsie + var/new_x = 32 * (N.x - src.x) + N.pixel_x + var/new_y = 32 * (N.y - src.y) + N.pixel_y + narsimage.pixel_x = new_x + narsimage.pixel_y = new_y + narglow.pixel_x = new_x + narglow.pixel_y = new_y + narsimage.loc = src.loc + narglow.loc = src.loc + //Display the new narsimage to the player + src << narsimage + src << narglow + + else + if(narsimage) + QDEL_NULL(narsimage) + QDEL_NULL(narglow) diff --git a/code/game/gamemodes/cult/cultify/turf.dm b/code/game/gamemodes/cult/cultify/turf.dm new file mode 100644 index 00000000..bd141ef7 --- /dev/null +++ b/code/game/gamemodes/cult/cultify/turf.dm @@ -0,0 +1,40 @@ +/turf/proc/cultify() + ChangeTurf(/turf/space) + return + +/turf/simulated/floor/cultify() + //todo: flooring datum cultify check + cultify_floor() + +/turf/simulated/shuttle/wall/cultify() + cultify_wall() + +/turf/simulated/wall/cultify() + cultify_wall() + +/turf/simulated/wall/cult/cultify() + return + +/turf/unsimulated/wall/cult/cultify() + return + +/turf/unsimulated/beach/cultify() + return + +/turf/unsimulated/wall/cultify() + cultify_wall() + +/turf/simulated/floor/proc/cultify_floor() + set_flooring(get_flooring_data(/decl/flooring/reinforced/cult)) + cult.add_cultiness(CULTINESS_PER_TURF) + + +/turf/proc/cultify_wall() + var/turf/simulated/wall/wall = src + if(!istype(wall)) + return + if(wall.is_reinf()) + ChangeTurf(/turf/simulated/wall/cult/reinf) + else + ChangeTurf(/turf/simulated/wall/cult) + cult.add_cultiness(CULTINESS_PER_TURF) diff --git a/code/game/gamemodes/cult/ghosts.dm b/code/game/gamemodes/cult/ghosts.dm new file mode 100644 index 00000000..83fb45b7 --- /dev/null +++ b/code/game/gamemodes/cult/ghosts.dm @@ -0,0 +1,289 @@ +/mob/observer/ghost/var/ghost_magic_cd = 0 + +/datum/antagonist/cultist/proc/add_ghost_magic(var/mob/observer/ghost/M) + if(max_cult_rating >= CULT_GHOSTS_1) + M.verbs += /mob/observer/ghost/proc/flick_lights + M.verbs += /mob/observer/ghost/proc/bloody_doodle + M.verbs += /mob/observer/ghost/proc/shatter_glass + M.verbs += /mob/observer/ghost/proc/slice + if(max_cult_rating >= CULT_GHOSTS_2) + M.verbs += /mob/observer/ghost/proc/move_item + M.verbs += /mob/observer/ghost/proc/whisper_to_cultist + M.verbs += /mob/observer/ghost/proc/bite_someone + M.verbs += /mob/observer/ghost/proc/chill_someone + if(max_cult_rating >= CULT_GHOSTS_3) + M.verbs += /mob/observer/ghost/proc/whisper_to_anyone + M.verbs += /mob/observer/ghost/proc/bloodless_doodle + M.verbs += /mob/observer/ghost/proc/toggle_visiblity + +/mob/observer/ghost/proc/ghost_ability_check() + var/turf/T = get_turf(src) + if(T.holy) + to_chat(src, "You may not use your abilities on the blessed ground.") + return 0 + if(ghost_magic_cd > world.time) + to_chat(src, "You need [round((ghost_magic_cd - world.time) / 10)] more seconds before you can use your abilities.") + return 0 + return 1 + +/mob/observer/ghost/proc/flick_lights() + set category = "Cult" + set name = "Flick lights" + set desc = "Flick some lights around you." + + if(!ghost_ability_check()) + return + + for(var/obj/machinery/light/L in range(3)) + L.flicker() + + ghost_magic_cd = world.time + 30 SECONDS + +/mob/observer/ghost/proc/bloody_doodle() + set category = "Cult" + set name = "Write in blood" + set desc = "Write a short message in blood on the floor or a wall. Remember, no IC in OOC or OOC in IC." + + bloody_doodle_proc(0) + +/mob/observer/ghost/proc/bloody_doodle_proc(var/bloodless = 0) + if(!ghost_ability_check()) + return + + var/doodle_color = COLOR_BLOOD_HUMAN + + var/turf/simulated/T = get_turf(src) + if(!istype(T)) + to_chat(src, "You cannot doodle there.") + return + + var/num_doodles = 0 + for(var/obj/effect/decal/cleanable/blood/writing/W in T) + num_doodles++ + if(num_doodles > 4) + to_chat(src, "There is no space to write on!") + return + + var/obj/effect/decal/cleanable/blood/choice + if(!bloodless) + var/list/choices = list() + for(var/obj/effect/decal/cleanable/blood/B in range(1)) + if(B.amount > 0) + choices += B + + if(!choices.len) + to_chat(src, "There is no blood to use nearby.") + return + + choice = input(src, "What blood would you like to use?") as null|anything in choices + if(!choice) + return + + if(choice.basecolor) + doodle_color = choice.basecolor + + var/max_length = 50 + + var/message = sanitize(input("Write a message. It cannot be longer than [max_length] characters.", "Blood writing", "")) + + if(!ghost_ability_check()) + return + + if(message && (bloodless || (choice && (choice in range(1))))) + if(length(message) > max_length) + message += "-" + to_chat(src, "You ran out of blood to write with!") + + var/obj/effect/decal/cleanable/blood/writing/W = new(T) + W.basecolor = doodle_color + W.update_icon() + W.message = message + W.add_hiddenprint(src) + if(!bloodless) + W.visible_message("Invisible fingers crudely paint something in blood on \the [T].") + else + W.visible_message("Blood appears out of nowhere as invisible fingers crudely paint something on \the [T].") + + log_admin("[src] ([src.key]) used ghost magic to write '[message]' - [x]-[y]-[z]") + + ghost_magic_cd = world.time + 30 SECONDS + +/mob/observer/ghost/proc/shatter_glass() + set category = "Cult" + set name = "Noise: glass shatter" + set desc = "Make a sound of glass being shattered." + + if(!ghost_ability_check()) + return + + playsound(loc, "shatter", 50, 1) + + ghost_magic_cd = world.time + 5 SECONDS + +/mob/observer/ghost/proc/slice() + set category = "Cult" + set name = "Noise: slice" + set desc = "Make a sound of a sword hit." + + if(!ghost_ability_check()) + return + + playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1) + + ghost_magic_cd = world.time + 5 SECONDS + +/mob/observer/ghost/proc/move_item() + set category = "Cult" + set name = "Move item" + set desc = "Move a small item to where you are." + + if(!ghost_ability_check()) + return + + var/turf/T = get_turf(src) + + var/list/obj/item/choices = list() + for(var/obj/item/I in range(1)) + if(I.w_class <= 2) + choices += I + + if(!choices.len) + to_chat(src, "There are no suitable items nearby.") + return + + var/obj/item/choice = input(src, "What item would you like to pull?") as null|anything in choices + if(!choice || !(choice in range(1)) || choice.w_class > 2) + return + + if(!ghost_ability_check()) + return + + if(step_to(choice, T)) + choice.visible_message("\The [choice] suddenly moves!") + + ghost_magic_cd = world.time + 60 SECONDS + +/mob/observer/ghost/proc/whisper_to_cultist() + set category = "Cult" + set name = "Whisper to cultist" + set desc = "Whisper to a human of your choice. They won't understand you unless they're a cultist though." + + whisper_proc() + +/mob/observer/ghost/proc/whisper_proc(var/anyone = 0) + if(!ghost_ability_check()) + return + + var/list/mob/living/choices = list() + for(var/mob/living/M in range(1)) + choices += M + + var/mob/living/choice = input(src, "Whom do you want to whisper to?") as null|anything in choices + if(!choice) + return + + var/message = sanitize(input("Decide what you want to whisper.", "Whisper", "")) + + if(!ghost_ability_check()) + return + + if(message) + if(iscultist(choice) || anyone) + to_chat(choice, "You hear a faint whisper... It says... \"[message]\"") + log_and_message_admins("used ghost magic to say '[message]' to \the [choice] and was heard - [x]-[y]-[z]") + else + to_chat(choice, "You hear a faint whisper, but you can't make out the words.") + log_and_message_admins("used ghost magic to say '[message]' to \the [choice] but wasn't heard - [x]-[y]-[z]") + to_chat(src, "You whisper to \the [choice]. Perhaps they heard you.") + + ghost_magic_cd = world.time + 100 SECONDS + +/mob/observer/ghost/proc/bite_someone() + set category = "Cult" + set name = "Bite" + set desc = "Bite or scratch someone." + + if(!ghost_ability_check()) + return + + var/list/mob/living/carbon/human/choices = list() + for(var/mob/living/carbon/human/H in range(1)) + choices += H + + var/mob/living/carbon/human/choice = input(src, "Whom do you want to scratch?") as null|anything in choices + if(!choice) + return + + if(!ghost_ability_check()) + return + + var/method = pick("bit", "scratched") + to_chat(choice, "Something invisible [method] you!") + choice.apply_effect(5, PAIN, 0) + to_chat(src, "You [method] \the [choice].") + + log_and_message_admins("used ghost magic to bite \the [choice] - [x]-[y]-[z]") + + ghost_magic_cd = world.time + 60 SECONDS + +/mob/observer/ghost/proc/chill_someone() + set category = "Cult" + set name = "Chill" + set desc = "Pass through someone, making them feel the chill of afterlife for a moment." + + if(!ghost_ability_check()) + return + + var/list/mob/living/carbon/human/choices = list() + for(var/mob/living/carbon/human/H in range(1)) + choices += H + + var/mob/living/carbon/human/choice = input(src, "Whom do you want to scare?") as null|anything in choices + if(!choice) + return + + if(!ghost_ability_check()) + return + + to_chat(choice, "You feel as if something cold passed through you!") + if(choice.bodytemperature >= choice.species.cold_level_1 + 1) + choice.bodytemperature = max(choice.species.cold_level_1 + 1, choice.bodytemperature - 30) + to_chat(src, "You pass through \the [choice], giving them a sudden chill.") + + log_and_message_admins("used ghost magic to chill \the [choice] - [x]-[y]-[z]") + + ghost_magic_cd = world.time + 60 SECONDS + +/mob/observer/ghost/proc/whisper_to_anyone() + set category = "Cult" + set name = "Whisper to mind" + set desc = "Whisper to a human of your choice." + + whisper_proc(1) + +/mob/observer/ghost/proc/bloodless_doodle() + set category = "Cult" + set name = "Write in own blood" + set desc = "Write a short message in blood on the floor or a wall. You don't need blood nearby to use this." + + bloody_doodle_proc(1) + +/mob/observer/ghost/proc/toggle_visiblity() + set category = "Cult" + set name = "Toggle Visibility" + set desc = "Allows you to become visible or invisible at will." + + if(invisibility && !ghost_ability_check()) + return + + if(invisibility == 0) + ghost_magic_cd = world.time + 60 SECONDS + to_chat(src, "You are now invisible.") + visible_message("It fades from sight...") + set_invisibility(INVISIBILITY_OBSERVER) + mouse_opacity = 1 + else + ghost_magic_cd = world.time + 60 SECONDS + to_chat(src, "You are now visible.") + set_invisibility(0) + mouse_opacity = 0 // This is so they don't make people invincible to melee attacks by hovering over them diff --git a/code/game/gamemodes/cult/hell_universe.dm b/code/game/gamemodes/cult/hell_universe.dm new file mode 100644 index 00000000..f9194399 --- /dev/null +++ b/code/game/gamemodes/cult/hell_universe.dm @@ -0,0 +1,42 @@ +/* + +In short: + * Random area alarms + * All areas jammed + * Random gateways spawning hellmonsters (and turn people into cluwnes if ran into) + * Broken APCs/Fire Alarms + * Scary music + * Random tiles changing to culty tiles. + +*/ +/datum/universal_state/hell + name = "Hell Rising" + desc = "OH FUCK OH FUCK OH FUCK" + +/datum/universal_state/hell/OnShuttleCall(var/mob/user) + return 1 + /* + if(user) + to_chat(user, "All you hear on the frequency is static and panicked screaming. There will be no shuttle call today.") + return 0 + */ + + +// Apply changes when entering state +/datum/universal_state/hell/OnEnter() + set background = 1 + + //Separated into separate procs for profiling + MiscSet() + KillMobs() + SSskybox.reinstate_skyboxes("narsie", FALSE) + +/datum/universal_state/hell/proc/MiscSet() + for(var/turf/simulated/floor/T) + if(!T.holy && prob(1)) + new /obj/effect/gateway/active/cult(T) + +/datum/universal_state/hell/proc/KillMobs() + for(var/mob/living/simple_animal/M in SSmobs.mob_list) + if(M && !M.client) + M.set_stat(DEAD) diff --git a/code/game/gamemodes/cult/manifest.dm b/code/game/gamemodes/cult/manifest.dm new file mode 100644 index 00000000..c3151b5d --- /dev/null +++ b/code/game/gamemodes/cult/manifest.dm @@ -0,0 +1,23 @@ +/datum/species/human/cult + name = "Cult" + spawn_flags = SPECIES_IS_RESTRICTED + + brute_mod = 2 + burn_mod = 2 + + species_flags = SPECIES_FLAG_NO_SCAN + +/datum/species/human/cult/get_random_name() + return "[pick("Anguished", "Blasphemous", "Corrupt", "Cruel", "Depraved", "Despicable", "Disturbed", "Exacerbated", "Foul", "Hateful", "Inexorable", "Implacable", "Impure", "Malevolent", "Malignant", "Malicious", "Pained", "Profane", "Profligate", "Relentless", "Resentful", "Restless", "Spiteful", "Tormented", "Unclean", "Unforgiving", "Vengeful", "Vindictive", "Wicked", "Wronged")] [pick("Apparition", "Aptrgangr", "Dis", "Draugr", "Dybbuk", "Eidolon", "Fetch", "Fylgja", "Ghast", "Ghost", "Gjenganger", "Haint", "Phantom", "Phantasm", "Poltergeist", "Revenant", "Shade", "Shadow", "Soul", "Spectre", "Spirit", "Spook", "Visitant", "Wraith")]" + +/datum/species/human/cult/handle_death(var/mob/living/carbon/human/H) + spawn(1) + if(H) + H.dust() + +/datum/species/human/cult/handle_post_spawn(var/mob/living/carbon/human/H) + H.s_tone = 35 + H.r_eyes = 230 + H.b_eyes = 7 + H.g_eyes = 7 + H.update_eyes() \ No newline at end of file diff --git a/code/game/gamemodes/cult/narsie.dm b/code/game/gamemodes/cult/narsie.dm new file mode 100644 index 00000000..40852593 --- /dev/null +++ b/code/game/gamemodes/cult/narsie.dm @@ -0,0 +1,360 @@ +var/global/narsie_behaviour = "CultStation13" +var/global/narsie_cometh = 0 +var/global/list/narsie_list = list() +/obj/singularity/narsie //Moving narsie to its own file for the sake of being clearer + name = "Nar-Sie" + desc = "Your mind begins to bubble and ooze as it tries to comprehend what it sees." + icon = 'icons/obj/narsie.dmi' + icon_state = "narsie-small" + pixel_x = -236 + pixel_y = -256 + + current_size = 9 //It moves/eats like a max-size singulo, aside from range. --NEO. + contained = 0 // Are we going to move around? + dissipate = 0 // Do we lose energy over time? + grav_pull = 10 //How many tiles out do we pull? + consume_range = 3 //How many tiles out do we eat + + +/obj/singularity/narsie/New() + ..() + narsie_list.Add(src) + +/obj/singularity/narsie/Destroy() + narsie_list.Remove(src) + ..() + +/obj/singularity/narsie/large + name = "Nar-Sie" + icon = 'icons/obj/narsie.dmi' + icon_state = "narsie"//mobs perceive the geometer of blood through their see_narsie proc + + // Pixel stuff centers Narsie. + pixel_x = -236 + pixel_y = -256 + light_range = 1 + light_color = "#3e0000" + + current_size = 6 + consume_range = 6 // How many tiles out do we eat. + var/announce=1 + var/cause_hell = 1 + +/obj/singularity/narsie/large/New() + ..() + if(announce) + to_world("[uppertext(name)] HAS RISEN") + sound_to(world, sound('sound/effects/wind/wind_5_1.ogg')) + + narsie_spawn_animation() + + if(!narsie_cometh)//so we don't initiate Hell more than one time. + if(cause_hell) + SetUniversalState(/datum/universal_state/hell) + narsie_cometh = 1 + + spawn(10 SECONDS) + if(evacuation_controller) + evacuation_controller.call_evacuation(null, TRUE, 1) + evacuation_controller.evac_no_return = 0 // Cannot recall + +/obj/singularity/narsie/Process() + eat() + + if (!target || prob(5)) + pickcultist() + + move() + + if (prob(25)) + mezzer() + +/obj/singularity/narsie/large/eat() + for (var/turf/A in orange(consume_range, src)) + consume(A) + +/obj/singularity/narsie/mezzer() + for(var/mob/living/carbon/M in oviewers(8, src)) + if(M.stat == CONSCIOUS) + if(M.status_flags & GODMODE) + continue + if(!iscultist(M)) + to_chat(M, " You feel your sanity crumble away in an instant as you gaze upon [src.name]...") + M.apply_effect(3, STUN) + + +/obj/singularity/narsie/large/Bump(atom/A) + if(!cause_hell) return + if(isturf(A)) + narsiewall(A) + else if(istype(A, /obj/structure/cult)) + qdel(A) + +/obj/singularity/narsie/large/Bumped(atom/A) + if(!cause_hell) return + if(isturf(A)) + narsiewall(A) + else if(istype(A, /obj/structure/cult)) + qdel(A) + +/obj/singularity/narsie/move(var/force_move = 0) + if(!move_self) + return 0 + + var/movement_dir = pick(GLOB.alldirs - last_failed_movement) + + if(force_move) + movement_dir = force_move + + if(target && prob(60)) + movement_dir = get_dir(src,target) + + spawn(0) + step(src, movement_dir) + spawn(1) + step(src, movement_dir) + return 1 + +/obj/singularity/narsie/large/move(var/force_move = 0) + if(!move_self) + return 0 + + var/movement_dir = pick(GLOB.alldirs - last_failed_movement) + + if(force_move) + movement_dir = force_move + + if(target && prob(60)) + movement_dir = get_dir(src,target) + spawn(0) + step(src, movement_dir) + narsiefloor(get_turf(loc)) + for(var/mob/M in GLOB.player_list) + if(M.client) + M.see_narsie(src,movement_dir) + spawn(10) + step(src, movement_dir) + narsiefloor(get_turf(loc)) + for(var/mob/M in GLOB.player_list) + if(M.client) + M.see_narsie(src,movement_dir) + return 1 + +/obj/singularity/narsie/proc/narsiefloor(var/turf/T)//leaving "footprints" + if(!(istype(T, /turf/simulated/wall/cult)||istype(T, /turf/space))) + if(T.icon_state != "cult-narsie") + T.desc = "something that goes beyond your understanding went this way" + T.icon = 'icons/turf/flooring/cult.dmi' + T.icon_state = "cult-narsie" + T.set_light(1) + +/obj/singularity/narsie/proc/narsiewall(var/turf/T) + T.desc = "An opening has been made on that wall, but who can say if what you seek truly lies on the other side?" + T.icon = 'icons/turf/walls.dmi' + T.icon_state = "cult-narsie" + T.set_opacity(0) + T.set_density(0) + set_light(1) + +/obj/singularity/narsie/large/consume(const/atom/A) //Has its own consume proc because it doesn't need energy and I don't want BoHs to explode it. --NEO +//NEW BEHAVIOUR + if(narsie_behaviour == "CultStation13") + //MOB PROCESSING + new_narsie(A) + +//OLD BEHAVIOUR + else if(narsie_behaviour == "Nar-Singulo") + old_narsie(A) + +/obj/singularity/narsie/proc/new_narsie(const/atom/A) + if (istype(A, /mob/) && (get_dist(A, src) <= 7)) + var/mob/M = A + + if(M.status_flags & GODMODE) + return 0 + + M.cultify() + +//TURF PROCESSING + else if (isturf(A)) + var/dist = get_dist(A, src) + + for (var/atom/movable/AM in A.contents) + if (dist <= consume_range) + consume(AM) + continue + + if (dist <= consume_range && !istype(A, /turf/space)) + var/turf/T = A + if(T.holy) + T.holy = 0 //Nar-Sie doesn't give a shit about sacred grounds. + T.cultify() + +/obj/singularity/narsie/proc/old_narsie(const/atom/A) + if(!(A.singuloCanEat())) + return 0 + + if (istype(A, /mob/living/)) + var/mob/living/C2 = A + + if(C2.status_flags & GODMODE) + return 0 + + C2.dust() // Changed from gib(), just for less lag. + + else if (istype(A, /obj/)) + qdel(A) + + if (A) + qdel(A) + else if (isturf(A)) + var/dist = get_dist(A, src) + + for (var/atom/movable/AM2 in A.contents) + if (AM2 == src) // This is the snowflake. + continue + + if (dist <= consume_range) + consume(AM2) + continue + + if (dist <= consume_range && !istype(A, get_base_turf_by_area(A))) + var/turf/T2 = A + T2.ChangeTurf(get_base_turf_by_area(A)) + +/obj/singularity/narsie/consume(const/atom/A) //This one is for the small ones. + if(!(A.singuloCanEat())) + return 0 + + if (istype(A, /mob/living/)) + var/mob/living/C2 = A + + if(C2.status_flags & GODMODE) + return 0 + + C2.dust() // Changed from gib(), just for less lag. + + else if (istype(A, /obj/)) + qdel(A) + + if (A) + qdel(A) + else if (isturf(A)) + var/dist = get_dist(A, src) + + for (var/atom/movable/AM2 in A.contents) + if (AM2 == src) // This is the snowflake. + continue + + if (dist <= consume_range) + consume(AM2) + continue + + if (dist > consume_range) + if(!(AM2.singuloCanEat())) + continue + + if (101 == AM2.invisibility) + continue + + spawn (0) + AM2.singularity_pull(src, src.current_size) + + if (dist <= consume_range && !istype(A, get_base_turf_by_area(A))) + var/turf/T2 = A + T2.ChangeTurf(get_base_turf_by_area(A)) + +/obj/singularity/narsie/ex_act(severity) //No throwing bombs at it either. --NEO + return + +/obj/singularity/narsie/proc/pickcultist() //Narsie rewards his cultists with being devoured first, then picks a ghost to follow. --NEO + var/list/cultists = list() + for(var/datum/mind/cult_nh_mind in cult.current_antagonists) + if(!cult_nh_mind.current) + continue + if(cult_nh_mind.current.stat) + continue + var/turf/pos = get_turf(cult_nh_mind.current) + if(pos.z != src.z) + continue + cultists += cult_nh_mind.current + if(cultists.len) + acquire(pick(cultists)) + return + //If there was living cultists, it picks one to follow. + for(var/mob/living/carbon/human/food in GLOB.living_mob_list_) + if(food.stat) + continue + var/turf/pos = get_turf(food) + if(!pos) //Catches failure of get_turf. + continue + if(pos.z != src.z) + continue + cultists += food + if(cultists.len) + acquire(pick(cultists)) + return + //no living cultists, pick a living human instead. + for(var/mob/observer/ghost/ghost in GLOB.player_list) + if(!ghost.client) + continue + var/turf/pos = get_turf(ghost) + if(pos.z != src.z) + continue + cultists += ghost + if(cultists.len) + acquire(pick(cultists)) + return + //no living humans, follow a ghost instead. + +/obj/singularity/narsie/proc/acquire(const/mob/food) + var/capname = uppertext(name) + + to_chat(target, "[capname] HAS LOST INTEREST IN YOU.") + target = food + + if (ishuman(target)) + to_chat(target, "[capname] HUNGERS FOR YOUR SOUL.") + else + to_chat(target, "[capname] HAS CHOSEN YOU TO LEAD HIM TO HIS NEXT MEAL.") +/obj/singularity/narsie/on_capture() + chained = 1 + move_self = 0 + icon_state ="narsie-small-chains" + +/obj/singularity/narsie/on_release() + chained = 0 + move_self = 1 + icon_state ="narsie-small" + +/obj/singularity/narsie/large/on_capture() + chained = 1 + move_self = 0 + icon_state ="narsie-chains" + for(var/mob/M in SSmobs.mob_list)//removing the client image of nar-sie while it is chained + if(M.client) + M.see_narsie(src) + +/obj/singularity/narsie/large/on_release() + chained = 0 + move_self = 1 + icon_state ="narsie" + +/** + * Wizard narsie. + */ +/obj/singularity/narsie/wizard + grav_pull = 0 + +/obj/singularity/narsie/wizard/eat() + for (var/turf/T in trange(consume_range, src)) + consume(T) + +/obj/singularity/narsie/proc/narsie_spawn_animation() + icon = 'icons/obj/narsie_spawn_anim.dmi' + dir = SOUTH + move_self = 0 + flick("narsie_spawn_anim",src) + sleep(11) + move_self = 1 + icon = initial(icon) diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm new file mode 100644 index 00000000..e9e03b2a --- /dev/null +++ b/code/game/gamemodes/cult/ritual.dm @@ -0,0 +1,315 @@ +/obj/item/weapon/book/tome + name = "arcane tome" + icon = 'icons/obj/weapons.dmi' + icon_state = "tome" + throw_speed = 1 + throw_range = 5 + w_class = 2 + unique = 1 + carved = 2 // Don't carve it + +/obj/item/weapon/book/tome/attack_self(var/mob/user) + if(!iscultist(user)) + to_chat(user, "\The [src] seems full of illegible scribbles. Is this a joke?") + else + to_chat(user, "Hold \the [src] in your hand while drawing a rune to use it.") + +/obj/item/weapon/book/tome/examine(var/mob/user) + . = ..() + if(!iscultist(user)) + to_chat(user, "An old, dusty tome with frayed edges and a sinister looking cover.") + else + to_chat(user, "The scriptures of Nar-Sie, The One Who Sees, The Geometer of Blood. Contains the details of every ritual his followers could think of. Most of these are useless, though.") + +/obj/item/weapon/book/tome/afterattack(var/atom/A, var/mob/user, var/proximity) + if(!proximity || !iscultist(user)) + return + if(A.reagents && A.reagents.has_reagent(/datum/reagent/water/holywater)) + to_chat(user, "You unbless \the [A].") + var/holy2water = A.reagents.get_reagent_amount(/datum/reagent/water/holywater) + A.reagents.del_reagent(/datum/reagent/water/holywater) + A.reagents.add_reagent(/datum/reagent/water, holy2water) + +/mob/proc/make_rune(var/rune, var/cost = 5, var/tome_required = 0) + var/has_tome = 0 + var/has_robes = 0 + var/cult_ground = 0 + if(istype(get_active_hand(), /obj/item/weapon/book/tome) || istype(get_inactive_hand(), /obj/item/weapon/book/tome)) + has_tome = 1 + else if(tome_required && mob_needs_tome()) + to_chat(src, "This rune is too complex to draw by memory, you need to have a tome in your hand to draw it.") + return + if(istype(get_equipped_item(slot_head), /obj/item/clothing/head/culthood) && istype(get_equipped_item(slot_wear_suit), /obj/item/clothing/suit/cultrobes) && istype(get_equipped_item(slot_shoes), /obj/item/clothing/shoes/cult)) + has_robes = 1 + var/turf/T = get_turf(src) + if(T.holy) + to_chat(src, "This place is blessed, you may not draw runes on it - defile it first.") + return + if(!istype(T, /turf/simulated)) + to_chat(src, "You need more space to draw a rune here.") + return + if(locate(/obj/effect/rune) in T) + to_chat(src, "There's already a rune here.") // Don't cross the runes + return + if(T.icon_state == "cult" || T.icon_state == "cult-narsie") + cult_ground = 1 + var/self + var/timer + var/damage = 1 + if(has_tome) + if(has_robes && cult_ground) + self = "Feeling greatly empowered, you slice open your finger and make a rune on the engraved floor. It shifts when your blood touches it, and starts vibrating as you begin to chant the ritual that binds your life essence with the dark arcane energies flowing through the surrounding world." + timer = 10 + damage = 0.2 + else if(has_robes) + self = "Feeling empowered in your robes, you slice open your finger and start drawing a rune, chanting the ritual that binds your life essence with the dark arcane energies flowing through the surrounding world." + timer = 30 + damage = 0.8 + else if(cult_ground) + self = "You slice open your finger and slide it over the engraved floor, watching it shift when your blood touches it. It vibrates when you begin to chant the ritual that binds your life essence with the dark arcane energies flowing through the surrounding world." // Sadly, you don't have access to the bell nor the candelbarum + timer = 20 + damage = 0.8 + else + self = "You slice open one of your fingers and begin drawing a rune on the floor whilst chanting the ritual that binds your life essence with the dark arcane energies flowing through the surrounding world." + timer = 40 + else + self = "Working without your tome, you try to draw the rune from your memory" + if(has_robes && cult_ground) + self += ". You feel that you remember it perfectly, finishing it with a few bold strokes. The engraved floor shifts under your touch, and vibrates once you begin your chants." + timer = 30 + else if(has_robes) + self += ". You don't remember it well, but you feel strangely empowered. You begin chanting, the unknown words slipping into your mind from beyond." + timer = 50 + else if(cult_ground) + self += ", watching as the floor shifts under your touch, correcting the rune. You begin your chants, and the ground starts to vibrate." + timer = 40 + else + self += ", having to cut your finger two more times before you make it resemble the pattern in your memory. It still looks a little off." + timer = 80 + damage = 2 + visible_message("\The [src] slices open a finger and begins to chant and paint symbols on the floor.", "[self]", "You hear chanting.") + if(do_after(src, timer)) + pay_for_rune(cost * damage) + if(locate(/obj/effect/rune) in T) + return + var/obj/effect/rune/R = new rune(T, get_rune_color(), get_blood_name()) + var/area/A = get_area(R) + log_and_message_admins("created \an [R.cultname] rune at \the [A.name] - [loc.x]-[loc.y]-[loc.z].") + R.add_fingerprint(src) + return 1 + return 0 + +/mob/living/carbon/human/make_rune(var/rune, var/cost, var/tome_required) + if(should_have_organ(BP_HEART) && vessel && !vessel.has_reagent(/datum/reagent/blood, species.blood_volume * 0.7)) + to_chat(src, "You are too weak to draw runes.") + return + ..() + +/mob/proc/pay_for_rune(var/blood) + return + +/mob/living/carbon/human/pay_for_rune(var/blood) + if(should_have_organ(BP_HEART)) + vessel.remove_reagent(/datum/reagent/blood, blood) + +/mob/proc/get_blood_name() + return "blood" + +/mob/living/silicon/get_blood_name() + return "oil" + +/mob/living/carbon/human/get_blood_name() + if(species) + return species.get_blood_name() + return "blood" + +/mob/living/simple_animal/construct/get_blood_name() + return "ichor" + +/mob/proc/mob_needs_tome() + return 0 + +/mob/living/carbon/human/mob_needs_tome() + return 1 + +/mob/proc/get_rune_color() + return "#c80000" + +/mob/living/carbon/human/get_rune_color() + return species.blood_color + +var/list/Tier1Runes = list( + /mob/proc/convert_rune, + /mob/proc/teleport_rune, + /mob/proc/tome_rune, + /mob/proc/wall_rune, + /mob/proc/ajorney_rune, + /mob/proc/defile_rune, + /mob/proc/emp_imbue, + /mob/proc/cult_communicate + ) + +var/list/Tier2Runes = list( + /mob/proc/armor_rune, + /mob/proc/offering_rune, + /mob/proc/drain_rune, + /mob/proc/emp_rune, + /mob/proc/massdefile_rune + ) + +var/list/Tier3Runes = list( + /mob/proc/weapon_rune, + /mob/proc/shell_rune, + /mob/proc/bloodboil_rune, + /mob/proc/confuse_rune, + /mob/proc/revive_rune +) + +var/list/Tier4Runes = list( + /mob/proc/tearreality_rune + ) + +/mob/proc/convert_rune() + set category = "Cult Magic" + set name = "Rune: Convert" + + make_rune(/obj/effect/rune/convert, tome_required = 1) + +/mob/proc/teleport_rune() + set category = "Cult Magic" + set name = "Rune: Teleport" + + make_rune(/obj/effect/rune/teleport, tome_required = 1) + +/mob/proc/tome_rune() + set category = "Cult Magic" + set name = "Rune: Summon Tome" + + make_rune(/obj/effect/rune/tome, cost = 15) + +/mob/proc/wall_rune() + set category = "Cult Magic" + set name = "Rune: Wall" + + make_rune(/obj/effect/rune/wall, tome_required = 1) + +/mob/proc/ajorney_rune() + set category = "Cult Magic" + set name = "Rune: Astral Journey" + + make_rune(/obj/effect/rune/ajorney) + +/mob/proc/defile_rune() + set category = "Cult Magic" + set name = "Rune: Defile" + + make_rune(/obj/effect/rune/defile, tome_required = 1) + +/mob/proc/massdefile_rune() + set category = "Cult Magic" + set name = "Rune: Mass Defile" + + make_rune(/obj/effect/rune/massdefile, tome_required = 1, cost = 20) + +/mob/proc/armor_rune() + set category = "Cult Magic" + set name = "Rune: Summon Robes" + + make_rune(/obj/effect/rune/armor, tome_required = 1) + +/mob/proc/offering_rune() + set category = "Cult Magic" + set name = "Rune: Offering" + + make_rune(/obj/effect/rune/offering, tome_required = 1) + + + +/mob/proc/drain_rune() + set category = "Cult Magic" + set name = "Rune: Blood Drain" + + make_rune(/obj/effect/rune/drain, tome_required = 1) + +/mob/proc/emp_rune() + set category = "Cult Magic" + set name = "Rune: EMP" + + make_rune(/obj/effect/rune/emp, tome_required = 1) + +/mob/proc/weapon_rune() + set category = "Cult Magic" + set name = "Rune: Summon Weapon" + + make_rune(/obj/effect/rune/weapon, tome_required = 1) + +/mob/proc/shell_rune() + set category = "Cult Magic" + set name = "Rune: Summon Shell" + + make_rune(/obj/effect/rune/shell, cost = 10, tome_required = 1) + +/mob/proc/bloodboil_rune() + set category = "Cult Magic" + set name = "Rune: Blood Boil" + + make_rune(/obj/effect/rune/blood_boil, cost = 20, tome_required = 1) + +/mob/proc/confuse_rune() + set category = "Cult Magic" + set name = "Rune: Confuse" + + make_rune(/obj/effect/rune/confuse) + +/mob/proc/revive_rune() + set category = "Cult Magic" + set name = "Rune: Revive" + + make_rune(/obj/effect/rune/revive, tome_required = 1) + +/mob/proc/tearreality_rune() + set category = "Cult Magic" + set name = "Rune: Tear Reality" + + make_rune(/obj/effect/rune/tearreality, cost = 50, tome_required = 1) + +/mob/proc/emp_imbue() + set category = "Cult Magic" + set name = "Imbue: EMP" + + make_rune(/obj/effect/rune/imbue/emp) + +/mob/proc/cult_communicate() + set category = "Cult Magic" + set name = "Communicate" + + if(incapacitated()) + to_chat(src, "Not when you are incapacitated.") + return + + message_cult_communicate() + pay_for_rune(3) + + var/input = input(src, "Please choose a message to tell to the other acolytes.", "Voice of Blood", "") + if(!input) + return + + whisper("[input]") + + input = sanitize(input) + log_and_message_admins("used a communicate verb to say '[input]'") + for(var/datum/mind/H in cult.current_antagonists) + if(H.current && !H.current.stat) + to_chat(H.current, "[input]") + +/mob/living/carbon/cult_communicate() + if(incapacitated(INCAPACITATION_RESTRAINED)) + to_chat(src, "You need at least your hands free to do this.") + return + ..() + +/mob/proc/message_cult_communicate() + return + +/mob/living/carbon/human/message_cult_communicate() + visible_message("\The [src] cuts \his finger and starts drawing on the back of \his hand.") diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm new file mode 100644 index 00000000..0ef27c3b --- /dev/null +++ b/code/game/gamemodes/cult/runes.dm @@ -0,0 +1,844 @@ +/obj/effect/rune + name = "rune" + desc = "A strange collection of symbols drawn in blood." + anchored = 1 + icon = 'icons/effects/uristrunes.dmi' + icon_state = "blank" + unacidable = 1 + plane = ABOVE_TURF_PLANE + layer = RUNE_LAYER + + var/blood + var/bcolor + var/strokes = 2 // IF YOU EVER SET THIS TO MORE THAN TEN, EVERYTHING WILL BREAK + var/cultname = "" + +/obj/effect/rune/New(var/loc, var/blcolor = "#c80000", var/nblood = "blood") + ..() + bcolor = blcolor + blood = nblood + update_icon() + +/obj/effect/rune/update_icon() + overlays.Cut() + if(cult.rune_strokes[type]) + var/list/f = cult.rune_strokes[type] + for(var/i in f) + var/image/t = image('icons/effects/uristrunes.dmi', "rune-[i]") + overlays += t + else + var/list/q = list(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + var/list/f = list() + for(var/i = 1 to strokes) + var/j = pick(q) + f += j + q -= f + var/image/t = image('icons/effects/uristrunes.dmi', "rune-[j]") + overlays += t + cult.rune_strokes[type] = f.Copy() + color = bcolor + desc = "A strange collection of symbols drawn in [blood]." + +/obj/effect/rune/examine(var/mob/user) + . = ..() + if(iscultist(user)) + to_chat(user, "This is \a [cultname] rune.") + +/obj/effect/rune/attackby(var/obj/item/I, var/mob/living/user) + if(istype(I, /obj/item/weapon/book/tome) && iscultist(user)) + user.visible_message("[user] rubs \the [src] with \the [I], and \the [src] is absorbed by it.", "You retrace your steps, carefully undoing the lines of \the [src].") + qdel(src) + return + else if(istype(I, /obj/item/weapon/nullrod)) + user.visible_message("[user] hits \the [src] with \the [I], and it disappears, fizzling.", "You disrupt the vile magic with the deadening field of \the [I].", "You hear a fizzle.") + qdel(src) + return + +/obj/effect/rune/attack_hand(var/mob/living/user) + if(!iscultist(user)) + to_chat(user, "You can't mouth the arcane scratchings without fumbling over them.") + return + if(istype(user.wear_mask, /obj/item/clothing/mask/muzzle) || user.silent) + to_chat(user, "You are unable to speak the words of the rune.") + return + if(cult.powerless) + to_chat(user, "You read the words, but nothing happens.") + return fizzle(user) + cast(user) + +/obj/effect/rune/attack_ai(var/mob/living/user) // Cult borgs! + if(Adjacent(user)) + attack_hand(user) + +/obj/effect/rune/attack_generic(var/mob/living/user) // Cult constructs/slimes/whatnot! + attack_hand(user) + +/obj/effect/rune/proc/cast(var/mob/living/user) + fizzle(user) + +/obj/effect/rune/proc/get_cultists() + . = list() + for(var/mob/living/M in range(1)) + if(iscultist(M)) + . += M + +/obj/effect/rune/proc/fizzle(var/mob/living/user) + visible_message("The markings pulse with a small burst of light, then fall dark.", "You hear a fizzle.") + +//Makes the speech a proc so all verbal components can be easily manipulated as a whole, or individually easily +/obj/effect/rune/proc/speak_incantation(var/mob/living/user, var/incantation) + var/datum/language/L = all_languages[LANGUAGE_CULT] + if(incantation && (L in user.languages)) + user.say(incantation, L) + +/* Tier 1 runes below */ + +/obj/effect/rune/convert + cultname = "convert" + var/spamcheck = 0 + +/obj/effect/rune/convert/cast(var/mob/living/user) + if(spamcheck) + return + + var/mob/living/carbon/target = null + for(var/mob/living/carbon/M in get_turf(src)) + if(!iscultist(M) && M.stat != DEAD) + target = M + break + + if(!target) + return fizzle(user) + + speak_incantation(user, "Mah[pick("'","`")]weyh pleggh at e'ntrath!") + target.visible_message("The markings below [target] glow a bloody red.") + + to_chat(target, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root.") + if(!cult.can_become_antag(target.mind, 1)) + to_chat(target, "Are you going insane?") + else + to_chat(target, "Do you want to join the cult of Nar'Sie? You can choose to ignore offer... Join the cult.") + + spamcheck = 1 + spawn(40) + spamcheck = 0 + if(!iscultist(target) && target.loc == get_turf(src)) // They hesitated, resisted, or can't join, and they are still on the rune - burn them + if(target.stat == CONSCIOUS) + target.take_overall_damage(0, 10) + switch(target.getFireLoss()) + if(0 to 25) + to_chat(target, "Your blood boils as you force yourself to resist the corruption invading every corner of your mind.") + if(25 to 45) + to_chat(target, "Your blood boils and your body burns as the corruption further forces itself into your body and mind.") + target.take_overall_damage(0, 3) + if(45 to 75) + to_chat(target, "You begin to hallucinate images of a dark and incomprehensible being and your entire body feels like its engulfed in flame as your mental defenses crumble.") + target.take_overall_damage(0, 5) + if(75 to 100) + to_chat(target, "Your mind turns to ash as the burning flames engulf your very soul and images of an unspeakable horror begin to bombard the last remnants of mental resistance.") + target.take_overall_damage(0, 10) + +/obj/effect/rune/convert/Topic(href, href_list) + if(href_list["join"]) + if(usr.loc == loc && !iscultist(usr)) + cult.add_antagonist(usr.mind, ignore_role = 1, do_not_equip = 1) + +/obj/effect/rune/teleport + cultname = "teleport" + var/destination + +/obj/effect/rune/teleport/New() + ..() + var/area/A = get_area(src) + destination = A.name + cult.teleport_runes += src + +/obj/effect/rune/teleport/Destroy() + cult.teleport_runes -= src + var/turf/T = get_turf(src) + for(var/atom/movable/A in contents) + A.forceMove(T) + return ..() + +/obj/effect/rune/teleport/examine(var/mob/user) + . = ..() + if(iscultist(user)) + to_chat(user, "Its name is [destination].") + +/obj/effect/rune/teleport/cast(var/mob/living/user) + if(user.loc == src) + showOptions(user) + else if(user.loc == get_turf(src)) + speak_incantation(user, "Sas[pick("'","`")]so c'arta forbici!") + if(do_after(user, 30)) + user.visible_message("\The [user] disappears in a flash of red light!", "You feel as your body gets dragged into the dimension of Nar-Sie!", "You hear a sickening crunch.") + user.forceMove(src) + showOptions(user) + var/warning = 0 + while(user.loc == src) + user.take_organ_damage(0, 2) + if(user.getFireLoss() > 50) + to_chat(user, "Your body can't handle the heat anymore!") + leaveRune(user) + return + if(warning == 0) + to_chat(user, "You feel the immerse heat of the realm of Nar-Sie...") + ++warning + if(warning == 1 && user.getFireLoss() > 15) + to_chat(user, "Your burns are getting worse. You should return to your realm soon...") + ++warning + if(warning == 2 && user.getFireLoss() > 35) + to_chat(user, "The heat! It burns!") + ++warning + sleep(10) + else + var/input = input(user, "Choose a new rune name.", "Destination", "") as text|null + if(!input) + return + destination = sanitize(input) + +/obj/effect/rune/teleport/Topic(href, href_list) + if(usr.loc != src) + return + if(href_list["target"]) + var/obj/effect/rune/teleport/targ = locate(href_list["target"]) + if(istype(targ)) // Checks for null, too + usr.forceMove(targ) + targ.showOptions(usr) + else if(href_list["leave"]) + leaveRune(usr) + +/obj/effect/rune/teleport/proc/showOptions(var/mob/living/user) + var/list/t = list() + for(var/obj/effect/rune/teleport/T in cult.teleport_runes) + if(T == src) + continue + t += "[T.destination]" + to_chat(user, "Teleport runes: [english_list(t, nothing_text = "no other runes exist")]... or return from this rune.") + +/obj/effect/rune/teleport/proc/leaveRune(var/mob/living/user) + if(user.loc != src) + return + user.forceMove(get_turf(src)) + user.visible_message("\The [user] appears in a flash of red light!", "You feel as your body gets thrown out of the dimension of Nar-Sie!", "You hear a pop.") + +/obj/effect/rune/tome + cultname = "summon tome" + +/obj/effect/rune/tome/cast(var/mob/living/user) + new /obj/item/weapon/book/tome(get_turf(src)) + speak_incantation(user, "N[pick("'","`")]ath reth sh'yro eth d'raggathnor!") + visible_message("\The [src] disappears with a flash of red light, and in its place now a book lies.", "You hear a pop.") + qdel(src) + +/obj/effect/rune/wall + cultname = "wall" + + var/obj/effect/cultwall/wall = null + +/obj/effect/rune/wall/Destroy() + QDEL_NULL(wall) + return ..() + +/obj/effect/rune/wall/cast(var/mob/living/user) + var/t + if(wall) + if(wall.health >= wall.max_health) + to_chat(user, "The wall doesn't need mending.") + return + t = wall.max_health - wall.health + wall.health += t + else + wall = new /obj/effect/cultwall(get_turf(src), bcolor) + wall.rune = src + t = wall.health + user.pay_for_rune(t / 50) + speak_incantation(user, "Khari[pick("'","`")]d! Eske'te tannin!") + to_chat(user, "Your blood flows into the rune, and you feel that the very space over the rune thickens.") + +/obj/effect/cultwall + name = "red mist" + desc = "A strange red mist emanating from a rune below it." + icon = 'icons/effects/effects.dmi'//TODO: better icon + icon_state = "smoke" + color = "#ff0000" + anchored = 1 + density = 1 + unacidable = 1 + var/obj/effect/rune/wall/rune + var/health + var/max_health = 200 + +/obj/effect/cultwall/New(var/loc, var/bcolor) + ..() + health = max_health + if(bcolor) + color = bcolor + +/obj/effect/cultwall/Destroy() + if(rune) + rune.wall = null + rune = null + return ..() + +/obj/effect/cultwall/examine(var/mob/user) + . = ..() + if(iscultist(user)) + if(health == max_health) + to_chat(user, "It is fully intact.") + else if(health > max_health * 0.5) + to_chat(user, "It is damaged.") + else + to_chat(user, "It is about to dissipate.") + +/obj/effect/cultwall/attack_hand(var/mob/living/user) + if(iscultist(user)) + user.visible_message("\The [user] touches \the [src], and it fades.", "You touch \the [src], whispering the old ritual, making it disappear.") + qdel(src) + else + to_chat(user, "You touch \the [src]. It feels wet and becomes harder the further you push your arm.") + +/obj/effect/cultwall/attackby(var/obj/item/I, var/mob/living/user) + if(istype(I, /obj/item/weapon/nullrod)) + user.visible_message("\The [user] touches \the [src] with \the [I], and it disappears.", "You disrupt the vile magic with the deadening field of \the [I].") + qdel(src) + else if(I.force) + user.visible_message("\The [user] hits \the [src] with \the [I].", "You hit \the [src] with \the [I].") + take_damage(I.force) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + +/obj/effect/cultwall/bullet_act(var/obj/item/projectile/Proj) + if(!(Proj.damage_type == BRUTE || Proj.damage_type == BURN)) + return + take_damage(Proj.damage) + ..() + +/obj/effect/cultwall/proc/take_damage(var/amount) + health -= amount + if(health <= 0) + visible_message("\The [src] dissipates.") + qdel(src) + +/obj/effect/rune/ajorney + cultname = "astral journey" + +/obj/effect/rune/ajorney/cast(var/mob/living/user) + var/tmpkey = user.key + if(user.loc != get_turf(src)) + return + speak_incantation(user, "Fwe[pick("'","`")]sh mah erl nyag r'ya!") + user.visible_message("\The [user]'s eyes glow blue as \he freezes in place, absolutely motionless.", "The shadow that is your spirit separates itself from your body. You are now in the realm beyond. While this is a great sight, being here strains your mind and body. Hurry...", "You hear only complete silence for a moment.") + announce_ghost_joinleave(user.ghostize(1), 1, "You feel that they had to use some [pick("dark", "black", "blood", "forgotten", "forbidden")] magic to [pick("invade", "disturb", "disrupt", "infest", "taint", "spoil", "blight")] this place!") + var/mob/observer/ghost/soul + for(var/mob/observer/ghost/O in GLOB.ghost_mob_list) + if(O.key == tmpkey) + soul = O + break + while(user) + if(user.stat == DEAD) + return + if(user.key) + return + else if(user.loc != get_turf(src) && soul) + soul.reenter_corpse() + else + user.take_organ_damage(0, 1) + sleep(20) + fizzle(user) + +/obj/effect/rune/defile + cultname = "defile" + +/obj/effect/rune/defile/cast(var/mob/living/user) + speak_incantation(user, "Ia! Ia! Zasan therium viortia!") + for(var/turf/T in range(1, src)) + if(T.holy) + T.holy = 0 + else + T.cultify() + visible_message("\The [src] embeds into the floor and walls around it, changing them!", "You hear liquid flow.") + qdel(src) + +/* Tier 2 runes */ + + +/obj/effect/rune/armor + cultname = "summon robes" + strokes = 3 + +/obj/effect/rune/armor/cast(var/mob/living/user) + speak_incantation(user, "N'ath reth sh'yro eth d[pick("'","`")]raggathnor!") + visible_message("\The [src] disappears with a flash of red light, and a set of armor appears on \the [user].", "You are blinded by the flash of red light. After you're able to see again, you see that you are now wearing a set of armor.") + + var/obj/O = user.get_equipped_item(slot_head) // This will most likely kill you if you are wearing a spacesuit, and it's 100% intended + if(O && !istype(O, /obj/item/clothing/head/culthood)) + user.unEquip(O) + O = user.get_equipped_item(slot_wear_suit) + if(O && !istype(O, /obj/item/clothing/suit/cultrobes)) + user.unEquip(O) + O = user.get_equipped_item(slot_shoes) + if(O && !istype(O, /obj/item/clothing/shoes/cult)) + user.unEquip(O) + + user.equip_to_slot_or_del(new /obj/item/clothing/head/culthood/alt(user), slot_head) + user.equip_to_slot_or_del(new /obj/item/clothing/suit/cultrobes/alt(user), slot_wear_suit) + user.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult(user), slot_shoes) + + O = user.get_equipped_item(slot_back) + if(istype(O, /obj/item/weapon/storage) && !istype(O, /obj/item/weapon/storage/backpack/cultpack)) // We don't want to make the vox drop their nitrogen tank, though + user.unEquip(O) + var/obj/item/weapon/storage/backpack/cultpack/C = new /obj/item/weapon/storage/backpack/cultpack(user) + user.equip_to_slot_or_del(C, slot_back) + if(C) + for(var/obj/item/I in O) + I.forceMove(C) + else if(!O) + var/obj/item/weapon/storage/backpack/cultpack/C = new /obj/item/weapon/storage/backpack/cultpack(user) + user.equip_to_slot_or_del(C, slot_back) + + user.update_icons() + + qdel(src) + +/obj/effect/rune/offering + cultname = "offering" + strokes = 3 + var/mob/living/victim + +/obj/effect/rune/offering/cast(var/mob/living/user) + var/list/mob/living/cultists = get_cultists() + if(victim) + to_chat(user, "You are already sarcificing \the [victim] on this rune.") + return + if(cultists.len < 3) + to_chat(user, "You need three cultists around this rune to make it work.") + return fizzle(user) + var/turf/T = get_turf(src) + for(var/mob/living/M in T) + if(M.stat != DEAD && !iscultist(M)) + victim = M + break + if(!victim) + return fizzle(user) + + for(var/mob/living/M in cultists) + M.say("Barhah hra zar[pick("'","`")]garis!") + + while(victim && victim.loc == T && victim.stat != DEAD) + var/list/mob/living/casters = get_cultists() + if(casters.len < 3) + break + //T.turf_animation('icons/effects/effects.dmi', "rune_sac") + victim.fire_stacks = max(2, victim.fire_stacks) + victim.IgniteMob() + victim.take_organ_damage(2 + casters.len, 2 + casters.len) // This is to speed up the process and also damage mobs that don't take damage from being on fire, e.g. borgs + if(ishuman(victim)) + var/mob/living/carbon/human/H = victim + if(H.is_asystole()) + H.adjustBrainLoss(2 + casters.len) + sleep(40) + if(victim && victim.loc == T && victim.stat == DEAD) + cult.add_cultiness(CULTINESS_PER_SACRIFICE) + var/obj/item/device/soulstone/full/F = new(get_turf(src)) + for(var/mob/M in cultists | get_cultists()) + to_chat(M, "The Geometer of Blood accepts this offering.") + visible_message("\The [F] appears over \the [src].") + cult.sacrificed += victim.mind + if(victim.mind == cult.sacrifice_target) + for(var/datum/mind/H in cult.current_antagonists) + if(H.current) + to_chat(H.current, "Your objective is now complete.") + //TODO: other rewards? + /* old sac code - left there in case someone wants to salvage it + var/worth = 0 + if(istype(H,/mob/living/carbon/human)) + var/mob/living/carbon/human/lamb = H + if(lamb.species.rarity_value > 3) + worth = 1 + + if(H.mind == cult.sacrifice_target) + + to_chat(usr, "The Geometer of Blood accepts this sacrifice, your objective is now complete.") + + to_chat(usr, "The Geometer of Blood accepts this [worth ? "exotic " : ""]sacrifice.") + + to_chat(usr, "The Geometer of blood accepts this sacrifice.") + to_chat(usr, "However, this soul was not enough to gain His favor.") + + to_chat(usr, "The Geometer of blood accepts this sacrifice.") + to_chat(usr, "However, a mere dead body is not enough to satisfy Him.") + */ + to_chat(victim, "The Geometer of Blood claims your body.") + victim.dust() + if(victim) + victim.ExtinguishMob() // Technically allows them to put the fire out by sacrificing them and stopping immediately, but I don't think it'd have much effect + victim = null + + +/obj/effect/rune/drain + cultname = "blood drain" + strokes = 3 + +/obj/effect/rune/drain/cast(var/mob/living/user) + var/mob/living/carbon/human/victim + for(var/mob/living/carbon/human/M in get_turf(src)) + if(iscultist(M)) + continue + victim = M + if(!victim) + return fizzle(user) + if(!victim.vessel.has_reagent(/datum/reagent/blood, 20)) + to_chat(user, "This body has no blood in it.") + return fizzle(user) + victim.vessel.remove_reagent(/datum/reagent/blood, 20) + admin_attack_log(user, victim, "Used a blood drain rune.", "Was victim of a blood drain rune.", "used a blood drain rune on") + speak_incantation(user, "Yu[pick("'","`")]gular faras desdae. Havas mithum javara. Umathar uf'kal thenar!") + user.visible_message("Blood flows from \the [src] into \the [user]!", "The blood starts flowing from \the [src] into your frail mortal body. [capitalize(english_list(heal_user(user), nothing_text = "you feel no different"))].", "You hear liquid flow.") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + +/obj/effect/rune/drain/proc/heal_user(var/mob/living/carbon/human/user) + if(!istype(user)) + return list("you feel no different") + var/list/statuses = list() + var/charges = 20 + var/use + use = min(charges, user.species.blood_volume - user.vessel.total_volume) + if(use > 0) + user.vessel.add_reagent(/datum/reagent/blood, use) + charges -= use + statuses += "you regain lost blood" + if(!charges) + return statuses + if(user.getBruteLoss() || user.getFireLoss()) + var/healbrute = user.getBruteLoss() + var/healburn = user.getFireLoss() + if(healbrute < healburn) + healbrute = min(healbrute, charges / 2) + charges -= healbrute + healburn = min(healburn, charges) + charges -= healburn + else + healburn = min(healburn, charges / 2) + charges -= healburn + healbrute = min(healbrute, charges) + charges -= healbrute + user.heal_organ_damage(healbrute, healburn) + statuses += "your wounds mend" + if(!charges) + return statuses + if(user.getToxLoss()) + use = min(user.getToxLoss(), charges) + user.adjustToxLoss(-use) + charges -= use + statuses += "your body stings less" + if(!charges) + return statuses + if(charges >= 15) + for(var/obj/item/organ/external/e in user.organs) + if(e && e.status & ORGAN_BROKEN) + e.status &= ~ORGAN_BROKEN + statuses += "bones in your [e.name] snap into place" + charges -= 15 + if(charges < 15) + break + if(!charges) + return statuses + var/list/obj/item/organ/damaged = list() + for(var/obj/item/organ/I in user.internal_organs) + if(I.damage) + damaged += I + if(damaged.len) + statuses += "you feel pain inside for a moment that passes quickly" + while(charges && damaged.len) + var/obj/item/organ/fix = pick(damaged) + fix.damage = max(0, fix.damage - min(charges, 1)) + charges = max(charges - 1, 0) + if(fix.damage == 0) + damaged -= fix + /* this is going to need rebalancing + if(charges) + user.ingested.add_reagent(/datum/reagent/hell_water, charges) + statuses += "you feel empowered" + */ + return statuses + +/datum/reagent/hell_water + name = "Hell water" + reagent_state = REAGENT_LIQUID + color = "#0050a177" + metabolism = REM * 0.1 + +/datum/reagent/hell_water/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + if(iscultist(M)) + M.AdjustParalysis(-1) + M.AdjustStunned(-1) + M.AdjustWeakened(-1) + M.add_chemical_effect(CE_PAINKILLER, 40) + M.add_chemical_effect(CE_SPEEDBOOST, 1) + M.adjustOxyLoss(-10 * removed) + M.heal_organ_damage(5 * removed, 5 * removed) + M.adjustToxLoss(-5 * removed) + else + M.fire_stacks = max(2, M.fire_stacks) + M.IgniteMob() + +/obj/effect/rune/emp + cultname = "emp" + strokes = 4 + +/obj/effect/rune/emp/cast(var/mob/living/user) + empulse(get_turf(src), 4, 2, 1) + speak_incantation(user, "Ta'gh fara[pick("'","`")]qha fel d'amar det!") + qdel(src) + +/obj/effect/rune/massdefile //Defile but with a huge range. Bring a buddy for this, you're hitting the floor. + cultname = "mass defile" + +/obj/effect/rune/massdefile/cast(var/mob/living/user) + var/list/mob/living/cultists = get_cultists() + if(cultists.len < 3) + to_chat(user, "You need three cultists around this rune to make it work.") + return fizzle(user) + else + for(var/mob/living/M in cultists) + M.say("Ia! Ia! Zasan therium viortia! Razan gilamrua kioha!") + for(var/turf/T in range(5, src)) + if(T.holy) + T.holy = 0 + else + T.cultify() + visible_message("\The [src] embeds into the floor and walls around it, changing them!", "You hear liquid flow.") + qdel(src) + +/* Tier 3 runes */ + +/obj/effect/rune/weapon + cultname = "summon weapon" + strokes = 4 + +/obj/effect/rune/weapon/cast(var/mob/living/user) + if(!istype(user.get_equipped_item(slot_head), /obj/item/clothing/head/culthood) || !istype(user.get_equipped_item(slot_wear_suit), /obj/item/clothing/suit/cultrobes) || !istype(user.get_equipped_item(slot_shoes), /obj/item/clothing/shoes/cult)) + to_chat(user, "You need to be wearing your robes to use this rune.") + return fizzle(user) + var/turf/T = get_turf(src) + if(T.icon_state != "cult" && T.icon_state != "cult-narsie") + to_chat(user, "This rune needs to be placed on the defiled ground.") + return fizzle(user) + speak_incantation(user, "N'ath reth sh'yro eth d[pick("'","`")]raggathnor!") + user.put_in_hands(new /obj/item/weapon/melee/cultblade(user)) + qdel(src) + +/obj/effect/rune/shell + cultname = "summon shell" + strokes = 4 + +/obj/effect/rune/shell/cast(var/mob/living/user) + var/turf/T = get_turf(src) + if(T.icon_state != "cult" && T.icon_state != "cult-narsie") + to_chat(user, "This rune needs to be placed on the defiled ground.") + return fizzle(user) + + var/obj/item/stack/material/steel/target + for(var/obj/item/stack/material/steel/S in get_turf(src)) + if(S.get_amount() >= 10) + target = S + break + + if(!target) + to_chat(user, "You need ten sheets of metal to fold them into a construct shell.") + return fizzle(user) + + speak_incantation(user, "Da A[pick("'","`")]ig Osk!") + target.use(10) + var/obj/O = new /obj/structure/constructshell/cult(get_turf(src)) + visible_message("The metal bends into \the [O], and \the [src] imbues into it.", "You hear a metallic sound.") + qdel(src) + +/obj/effect/rune/confuse + cultname = "confuse" + strokes = 4 + +/obj/effect/rune/confuse/cast(var/mob/living/user) + speak_incantation(user, "Fuu ma[pick("'","`")]jin!") + visible_message("\The [src] explodes in a bright flash.") + var/list/mob/affected = list() + for(var/mob/living/M in viewers(src)) + if(iscultist(M)) + continue + var/obj/item/weapon/nullrod/N = locate() in M + if(N) + continue + affected |= M + if(iscarbon(M)) + var/mob/living/carbon/C = M + C.eye_blurry += 50 + C.Weaken(3) + C.Stun(5) + else if(issilicon(M)) + M.Weaken(10) + + admin_attacker_log_many_victims(user, affected, "Used a confuse rune.", "Was victim of a confuse rune.", "used a confuse rune on") + qdel(src) + +/obj/effect/rune/revive + cultname = "revive" + strokes = 4 + +/obj/effect/rune/revive/cast(var/mob/living/user) + var/mob/living/carbon/human/target + var/obj/item/device/soulstone/source + for(var/mob/living/carbon/human/M in get_turf(src)) + if(M.stat == DEAD) + if(iscultist(M)) + if(M.key) + target = M + break + if(!target) + return fizzle(user) + for(var/obj/item/device/soulstone/S in get_turf(src)) + if(S.full && !S.shade.key) + source = S + break + if(!source) + return fizzle(user) + target.rejuvenate() + source.set_full(0) + speak_incantation(user, "Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!") + target.visible_message("\The [target]'s eyes glow with a faint red as \he stands up, slowly starting to breathe again.", "Life... I'm alive again...", "You hear liquid flow.") + +/obj/effect/rune/blood_boil + cultname = "blood boil" + strokes = 4 + +/obj/effect/rune/blood_boil/cast(var/mob/living/user) + var/list/mob/living/cultists = get_cultists() + if(cultists.len < 3) + return fizzle() + + for(var/mob/living/M in cultists) + M.say("Dedo ol[pick("'","`")]btoh!") + + var/list/mob/living/previous = list() + var/list/mob/living/current = list() + while(cultists.len >= 3) + cultists = get_cultists() + for(var/mob/living/carbon/M in viewers(src)) + if(iscultist(M)) + continue + current |= M + var/obj/item/weapon/nullrod/N = locate() in M + if(N) + continue + M.take_overall_damage(5, 5) + if(!(M in previous)) + if(M.should_have_organ(BP_HEART)) + to_chat(M, "Your blood boils!") + else + to_chat(M, "You feel searing heat inside!") + previous = current.Copy() + current.Cut() + sleep(10) + +/* Tier NarNar runes */ + +/obj/effect/rune/tearreality + cultname = "tear reality" + var/the_end_comes = 0 + var/the_time_has_come = 300 + var/obj/singularity/narsie/large/HECOMES = null + strokes = 9 + +/obj/effect/rune/tearreality/cast(var/mob/living/user) + if(!cult.allow_narsie) + return + if(the_end_comes) + to_chat(user, "You are already summoning! Be patient!") + return + var/list/mob/living/cultists = get_cultists() + if(cultists.len < 5) + return fizzle() + for(var/mob/living/M in cultists) + M.say("Tok-lyr rqa'nap g[pick("'","`")]lt-ulotf!") + to_chat(M, "You are staring to tear the reality to bring Him back... stay around the rune!") + log_and_message_admins_many(cultists, "started summoning Nar-sie.") + + var/area/A = get_area(src) + command_announcement.Announce("High levels of bluespace interference detected at \the [A]. Suspected wormhole forming. Investigate it immediately.") + while(cultists.len > 4 || the_end_comes) + cultists = get_cultists() + if(cultists.len > 8) + ++the_end_comes + if(cultists.len > 4) + ++the_end_comes + else + --the_end_comes + if(the_end_comes >= the_time_has_come) + break + for(var/mob/living/M in cultists) + if(prob(5)) + M.say(pick("Hakkrutju gopoenjim.", "Nherasai pivroiashan.", "Firjji prhiv mazenhor.", "Tanah eh wakantahe.", "Obliyae na oraie.", "Miyf hon vnor'c.", "Wakabai hij fen juswix.")) + + for(var/turf/T in range(min(the_end_comes, 15))) + if(prob(the_end_comes / 3)) + T.cultify() + sleep(10) + + if(the_end_comes >= the_time_has_come) + HECOMES = new /obj/singularity/narsie/large(get_turf(src)) + else + command_announcement.Announce("Bluespace anomaly has ceased.") + qdel(src) + +/obj/effect/rune/tearreality/attack_hand(var/mob/living/user) + ..() + if(HECOMES && !iscultist(user)) + var/input = input(user, "Are you SURE you want to sacrifice yourself?", "DO NOT DO THIS") in list("Yes", "No") + if(input != "Yes") + return + speak_incantation(user, "Uhrast ka'hfa heldsagen ver[pick("'","`")]lot!") + to_chat(user, "In the last moment of your humble life, you feel an immense pain as fabric of reality mends... with your blood.") + for(var/mob/M in GLOB.living_mob_list_) + if(iscultist(M)) + to_chat(M, "You see a vision of \the [user] keeling over dead, his blood glowing blue as it escapes \his body and dissipates into thin air; you hear an otherwordly scream and feel that a great disaster has just been averted.") + else + to_chat(M, "You see a vision of [name] keeling over dead, his blood glowing blue as it escapes his body and dissipates into thin air; you hear an otherwordly scream and feel very weak for a moment.") + log_and_message_admins("mended reality with the greatest sacrifice", user) + user.dust() + cult.powerless = 1 + qdel(HECOMES) + qdel(src) + return + +/obj/effect/rune/tearreality/attackby() + if(the_end_comes) + return + ..() + +/* Imbue runes */ + +/obj/effect/rune/imbue + cultname = "otherwordly abomination that shouldn't exist and that you should report to your local god as soon as you see it, along with the instructions for making this" + var/papertype + +/obj/effect/rune/imbue/cast(var/mob/living/user) + var/obj/item/weapon/paper/target + var/tainted = 0 + for(var/obj/item/weapon/paper/P in get_turf(src)) + if(!P.info) + target = P + break + else + tainted = 1 + if(!target) + if(tainted) + to_chat(user, "The blank is tainted. It is unsuitable.") + return fizzle(user) + speak_incantation(user, "H'drak v[pick("'","`")]loso, mir'kanas verbot!") + visible_message("The rune forms into an arcane image on the paper.") + new papertype(get_turf(src)) + qdel(target) + qdel(src) + +/obj/effect/rune/imbue/emp + cultname = "destroy technology imbue" + papertype = /obj/item/weapon/paper/talisman/emp diff --git a/code/game/gamemodes/cult/talisman.dm b/code/game/gamemodes/cult/talisman.dm new file mode 100644 index 00000000..4b8cf7ea --- /dev/null +++ b/code/game/gamemodes/cult/talisman.dm @@ -0,0 +1,28 @@ +/obj/item/weapon/paper/talisman + icon_state = "paper_talisman" + var/imbue = null + info = "


    " + +/obj/item/weapon/paper/talisman/attack_self(var/mob/living/user) + if(iscultist(user)) + to_chat(user, "Attack your target to use this talisman.") + else + to_chat(user, "You see strange symbols on the paper. Are they supposed to mean something?") + +/obj/item/weapon/paper/talisman/attack(var/mob/living/M, var/mob/living/user) + return + +/obj/item/weapon/paper/talisman/emp/attack_self(var/mob/living/user) + if(iscultist(user)) + to_chat(user, "This is an emp talisman.") + ..() + +/obj/item/weapon/paper/talisman/emp/afterattack(var/atom/target, var/mob/user, var/proximity) + if(!iscultist(user)) + return + if(!proximity) + return + user.say("Ta'gh fara[pick("'","`")]qha fel d'amar det!") + user.visible_message("\The [user] invokes \the [src] at [target].", "You invoke \the [src] at [target].") + target.emp_act(1) + qdel(src) diff --git a/code/game/gamemodes/endgame/bluespace_jump/bluespace_jump.dm b/code/game/gamemodes/endgame/bluespace_jump/bluespace_jump.dm new file mode 100644 index 00000000..7461c697 --- /dev/null +++ b/code/game/gamemodes/endgame/bluespace_jump/bluespace_jump.dm @@ -0,0 +1,140 @@ +/datum/universal_state/bluespace_jump + name = "Bluespace Jump" + var/list/bluespaced = list() + var/list/bluegoasts = list() + var/list/affected_levels + var/list/old_accessible_z_levels + +/datum/universal_state/bluespace_jump/New(var/list/zlevels) + affected_levels = zlevels + +/datum/universal_state/bluespace_jump/OnEnter() + var/space_zlevel = GLOB.using_map.get_empty_zlevel() //get a place for stragglers + for(var/mob/living/M in SSmobs.mob_list) + if(M.z in affected_levels) + var/area/A = get_area(M) + if(istype(A,/area/space)) //straggler + var/turf/T = locate(M.x, M.y, space_zlevel) + if(T) + M.forceMove(T) + else + apply_bluespaced(M) + for(var/mob/goast in GLOB.ghost_mob_list) + goast.mouse_opacity = 0 //can't let you click that Dave + goast.set_invisibility(SEE_INVISIBLE_LIVING) + goast.alpha = 255 + old_accessible_z_levels = GLOB.using_map.accessible_z_levels.Copy() + for(var/z in affected_levels) + GLOB.using_map.accessible_z_levels -= "[z]" //not accessible during the jump + +/datum/universal_state/bluespace_jump/OnExit() + for(var/M in bluespaced) + clear_bluespaced(M) + + bluespaced.Cut() + GLOB.using_map.accessible_z_levels = old_accessible_z_levels + old_accessible_z_levels = null + +/datum/universal_state/bluespace_jump/OnPlayerLatejoin(var/mob/living/M) + if(M.z in affected_levels) + apply_bluespaced(M) + +/datum/universal_state/bluespace_jump/OnTouchMapEdge(var/atom/A) + if((A.z in affected_levels) && (A in bluespaced)) + if(ismob(A)) + to_chat(A,"You drift away into the shifting expanse, never to be seen again.") + qdel(A) //lost in bluespace + return FALSE + return TRUE + +/datum/universal_state/bluespace_jump/proc/apply_bluespaced(var/mob/living/M) + bluespaced += M + if(M.client) + to_chat(M,"You feel oddly light, and somewhat disoriented as everything around you shimmers and warps ever so slightly.") + M.overlay_fullscreen("bluespace", /obj/screen/fullscreen/bluespace_overlay) + M.confused = 20 + bluegoasts += new/obj/effect/bluegoast/(get_turf(M),M) + +/datum/universal_state/bluespace_jump/proc/clear_bluespaced(var/mob/living/M) + if(M.client) + to_chat(M,"You feel rooted in material world again.") + M.clear_fullscreen("bluespace") + M.confused = 0 + for(var/mob/goast in GLOB.ghost_mob_list) + goast.mouse_opacity = initial(goast.mouse_opacity) + goast.set_invisibility(initial(goast.invisibility)) + goast.alpha = initial(goast.alpha) + for(var/G in bluegoasts) + qdel(G) + bluegoasts.Cut() + +/obj/effect/bluegoast + name = "bluespace echo" + desc = "It's not going to punch you, is it?" + var/mob/living/carbon/human/daddy + anchored = 1 + var/reality = 0 + simulated = 0 + +/obj/effect/bluegoast/New(nloc, ndaddy) + ..(nloc) + if(!ndaddy) + qdel(src) + return + daddy = ndaddy + set_dir(daddy.dir) + appearance = daddy.appearance + GLOB.moved_event.register(daddy, src, /obj/effect/bluegoast/proc/mirror) + GLOB.dir_set_event.register(daddy, src, /obj/effect/bluegoast/proc/mirror_dir) + GLOB.destroyed_event.register(daddy, src, /datum/proc/qdel_self) + +/obj/effect/bluegoast/Destroy() + GLOB.destroyed_event.unregister(daddy, src) + GLOB.dir_set_event.unregister(daddy, src) + GLOB.moved_event.unregister(daddy, src) + daddy = null + . = ..() + +/obj/effect/bluegoast/proc/mirror(var/atom/movable/am, var/old_loc, var/new_loc) + var/ndir = get_dir(new_loc,old_loc) + appearance = daddy.appearance + var/nloc = get_step(src, ndir) + if(nloc) + forceMove(nloc) + if(nloc == new_loc) + reality++ + if(reality > 5) + to_chat(daddy, "Yep, it's certainly the other one. Your existance was a glitch, and it's finally being mended...") + blueswitch() + else if(reality > 3) + to_chat(daddy, "Something is definitely wrong. Why do you think YOU are the original?") + else + to_chat(daddy, "You feel a bit less real. Which one of you two was original again?..") + +/obj/effect/bluegoast/proc/mirror_dir(var/atom/movable/am, var/old_dir, var/new_dir) + set_dir(GLOB.reverse_dir[new_dir]) + +/obj/effect/bluegoast/examine(user) + return daddy.examine(user) + +/obj/effect/bluegoast/proc/blueswitch() + var/mob/living/carbon/human/H = new(get_turf(src), daddy.species.name) + H.real_name = daddy.real_name + H.dna = daddy.dna.Clone() + H.sync_organ_dna() + H.flavor_text = daddy.flavor_text + H.UpdateAppearance() + var/datum/job/job = job_master.GetJob(daddy.job) + if(job) + job.equip(H) + daddy.dust() + qdel(src) + +/obj/screen/fullscreen/bluespace_overlay + icon = 'icons/effects/effects.dmi' + icon_state = "mfoam" + screen_loc = "WEST,SOUTH to EAST,NORTH" + color = "#ff9900" + alpha = 100 + blend_mode = BLEND_SUBTRACT + layer = FULLSCREEN_LAYER \ No newline at end of file diff --git a/code/game/gamemodes/endgame/endgame.dm b/code/game/gamemodes/endgame/endgame.dm new file mode 100644 index 00000000..440d469b --- /dev/null +++ b/code/game/gamemodes/endgame/endgame.dm @@ -0,0 +1,80 @@ +/********************** + * ENDGAME STUFF + **********************/ + + // Universal State + // Handles stuff like space icon_state, constants, etc. + // Essentially a policy manager. Once shit hits the fan, this changes its policies. + // Called by master controller. + + // Default shit. +/datum/universal_state + // Just for reference, for now. + // Might eventually add an observatory job. + var/name = "Normal" + var/desc = "Nothing seems awry." + + // Sets world.turf, replaces all turfs of type /turf/space. + var/space_type = /turf/space + + // Replaces all turfs of type /turf/space/transit + var/transit_space_type = /turf/space/transit + + // Chance of a floor or wall getting damaged [0-100] + // Simulates stuff getting broken due to molecular bonds decaying. + var/decay_rate = 0 + +// Actually decay the turf. +/datum/universal_state/proc/DecayTurf(var/turf/T) + if(istype(T,/turf/simulated/wall)) + var/turf/simulated/wall/W=T + W.melt() + return + if(istype(T,/turf/simulated/floor)) + var/turf/simulated/floor/F=T + // Burnt? + if(!F.burnt) + F.burn_tile() + else + F.ReplaceWithLattice() + return + +// Return 0 to cause shuttle call to fail. +/datum/universal_state/proc/OnShuttleCall(var/mob/user) + return 1 + +// Processed per tick +/datum/universal_state/proc/OnTurfTick(var/turf/T) + if(decay_rate && prob(decay_rate)) + DecayTurf(T) + +// Apply changes when exiting state +/datum/universal_state/proc/OnExit() + // Does nothing by default + +// Apply changes when entering state +/datum/universal_state/proc/OnEnter() + // Does nothing by default + +// Apply changes to a new turf. +/datum/universal_state/proc/OnTurfChange(var/turf/NT) + return + +/datum/universal_state/proc/OverlayAndAmbientSet() + return + +/datum/universal_state/proc/OnPlayerLatejoin(var/mob/living/M) + return + +/datum/universal_state/proc/OnTouchMapEdge(var/atom/A) + return TRUE //return FALSE to cancel map edge handling + +/proc/SetUniversalState(var/newstate,var/on_exit=1, var/on_enter=1, list/arguments=null) + if(on_exit) + GLOB.universe.OnExit() + if(arguments) + GLOB.universe = new newstate(arglist(arguments)) + else + GLOB.universe = new newstate + if(on_enter) + GLOB.universe.OnEnter() diff --git a/code/game/gamemodes/endgame/nuclear_explosion/nuclear_explosion.dm b/code/game/gamemodes/endgame/nuclear_explosion/nuclear_explosion.dm new file mode 100644 index 00000000..67390a7f --- /dev/null +++ b/code/game/gamemodes/endgame/nuclear_explosion/nuclear_explosion.dm @@ -0,0 +1,107 @@ +/datum/universal_state/nuclear_explosion + name = "Nuclear Demolition Warhead" + var/atom/explosion_source + var/obj/screen/cinematic + +/datum/universal_state/nuclear_explosion/New(atom/nuke) + explosion_source = nuke + + //create the cinematic screen obj + cinematic = new + cinematic.icon = 'icons/effects/station_explosion.dmi' + cinematic.icon_state = "station_intact" + cinematic.plane = HUD_PLANE + cinematic.layer = HUD_ABOVE_ITEM_LAYER + cinematic.mouse_opacity = 2 + cinematic.screen_loc = "1,0" + +/datum/universal_state/nuclear_explosion/OnEnter() + if(ticker && ticker.mode) + ticker.mode.explosion_in_progress = 1 + + start_cinematic_intro() + + var/turf/T = get_turf(explosion_source) + if(isStationLevel(T.z)) + to_world("The [station_name()] was destoyed by the nuclear blast!") + + dust_mobs(GLOB.using_map.station_levels) + play_cinematic_station_destroyed() + else + to_world("A nuclear device was set off, but the explosion was out of reach of the [station_name()]!") + + dust_mobs(list(T.z)) + play_cinematic_station_unaffected() + + sleep(100) + + for(var/mob/living/L in GLOB.living_mob_list_) + if(L.client) + L.client.screen -= cinematic + + sleep(200) + + if(ticker && ticker.mode) + ticker.mode.station_was_nuked = 1 + ticker.mode.explosion_in_progress = 0 + if(!ticker.mode.check_finished())//If the mode does not deal with the nuke going off so just reboot because everyone is stuck as is + universe_has_ended = 1 + +/datum/universal_state/nuclear_explosion/OnExit() + if(ticker && ticker.mode) + ticker.mode.explosion_in_progress = 0 + +/datum/universal_state/nuclear_explosion/proc/dust_mobs(var/list/affected_z_levels) + for(var/mob/living/L in SSmobs.mob_list) + var/turf/T = get_turf(L) + if(T && (T.z in affected_z_levels)) + //this is needed because dusting resets client screen 1.5 seconds after being called (delayed due to the dusting animation) + var/mob/ghost = L.ghostize(0) //So we ghostize them right beforehand instead + if(ghost && ghost.client) + ghost.client.screen += cinematic + L.dust() //then dust the body + +/datum/universal_state/nuclear_explosion/proc/show_cinematic_to_players() + for(var/mob/M in GLOB.player_list) + if(M.client) + M.client.screen += cinematic + +/datum/universal_state/nuclear_explosion/proc/start_cinematic_intro() + for(var/mob/M in GLOB.player_list) //I guess so that people in the lobby only hear the explosion + sound_to(M, sound('sound/machines/Alarm.ogg')) + + sleep(100) + + show_cinematic_to_players() + flick("intro_nuke",cinematic) + sleep(30) + +/datum/universal_state/nuclear_explosion/proc/play_cinematic_station_destroyed() + sound_to(world, sound('sound/effects/explosionfar.ogg'))//makes no sense if you're not on the station but whatever + + flick("station_explode_fade_red",cinematic) + cinematic.icon_state = "summary_selfdes" + sleep(80) + +/datum/universal_state/nuclear_explosion/proc/play_cinematic_station_unaffected() + cinematic.icon_state = "station_intact" + sleep(5) + sound_to(world, sound('sound/effects/explosionfar.ogg'))//makes no sense if you are on the station but whatever + + + sleep(75) + + +//MALF +/datum/universal_state/nuclear_explosion/malf/start_cinematic_intro() + for(var/mob/M in GLOB.player_list) //I guess so that people in the lobby only hear the explosion + to_chat(M, sound('sound/machines/Alarm.ogg')) + + sleep(28) + + show_cinematic_to_players() + flick("intro_malf",cinematic) + sleep(72) + flick("intro_nuke",cinematic) + sleep(30) + diff --git a/code/game/gamemodes/endgame/supermatter_cascade/blob.dm b/code/game/gamemodes/endgame/supermatter_cascade/blob.dm new file mode 100644 index 00000000..5b2b743e --- /dev/null +++ b/code/game/gamemodes/endgame/supermatter_cascade/blob.dm @@ -0,0 +1,115 @@ +// QUALITY COPYPASTA +/turf/unsimulated/wall/supermatter + name = "Bluespace" + desc = "THE END IS right now actually." + + icon = 'icons/turf/space.dmi' + icon_state = "bluespace" + + //luminosity = 5 + //l_color="#0066ff" + plane = EFFECTS_ABOVE_LIGHTING_PLANE + layer = SUPERMATTER_WALL_LAYER + + var/next_check=0 + var/list/avail_dirs = list(NORTH,SOUTH,EAST,WEST,UP,DOWN) + +/turf/unsimulated/wall/supermatter/New() + ..() + processing_turfs.Add(src) + next_check = world.time + 5 SECONDS + + // Nom. + for(var/atom/movable/A in src) + Consume(A) + +/turf/unsimulated/wall/supermatter/Destroy() + processing_turfs.Remove(src) + ..() + +/turf/unsimulated/wall/supermatter/process() + // Only check infrequently. + if(next_check>world.time) return + + // No more available directions? Shut down process(). + if(!avail_dirs.len) + return PROCESS_KILL + + // We're checking, reset the timer. + next_check = world.time + 5 SECONDS + + // Choose a direction. + var/pdir = pick(avail_dirs) + avail_dirs -= pdir + var/turf/T = get_zstep(src,pdir) + + // EXPAND + if(T && !istype(T,type)) + // Do pretty fadeout animation for 1s. + new /obj/effect/overlay/bluespacify(T) + spawn(1 SECOND) + if(istype(T,type)) // In case another blob came first, don't create another blob + return + T.ChangeTurf(type) + +/turf/unsimulated/wall/supermatter/attack_generic(mob/user as mob) + if(istype(user)) + return attack_hand(user) + +/turf/unsimulated/wall/supermatter/attack_robot(mob/user as mob) + if(Adjacent(user)) + return attack_hand(user) + else + user.examinate(src) + +// /vg/: Don't let ghosts fuck with this. +/turf/unsimulated/wall/supermatter/attack_ghost(mob/user as mob) + user.examinate(src) + +/turf/unsimulated/wall/supermatter/attack_ai(mob/user as mob) + user.examinate(src) + +/turf/unsimulated/wall/supermatter/attack_hand(mob/user as mob) + user.visible_message("\The [user] reaches out and touches \the [src]... And then blinks out of existance.",\ + "You reach out and touch \the [src]. Everything immediately goes quiet. Your last thought is \"That was not a wise decision.\"",\ + "You hear an unearthly noise.") + + playsound(src, 'sound/effects/supermatter.ogg', 50, 1) + + Consume(user) + +/turf/unsimulated/wall/supermatter/attackby(obj/item/weapon/W as obj, mob/living/user as mob) + user.visible_message("\The [user] touches \a [W] to \the [src] as a silence fills the room...",\ + "You touch \the [W] to \the [src] when everything suddenly goes silent.\"\n\The [W] flashes into dust as you flinch away from \the [src].",\ + "Everything suddenly goes silent.") + + playsound(src, 'sound/effects/supermatter.ogg', 50, 1) + + user.drop_from_inventory(W) + Consume(W) + +#define MayConsume(A) (istype(A) && A.simulated && !isobserver(A)) + +/turf/unsimulated/wall/supermatter/Bumped(var/atom/movable/AM) + if(!MayConsume(AM)) + return + + if(istype(AM, /mob/living)) + AM.visible_message("\The [AM] slams into \the [src] inducing a resonance... \his body starts to glow and catch flame before flashing into ash.",\ + "You slam into \the [src] as your ears are filled with unearthly ringing. Your last thought is \"Oh, fuck.\"",\ + "You hear an unearthly noise as a wave of heat washes over you.") + else + AM.visible_message("\The [AM] smacks into \the [src] and rapidly flashes to ash.",\ + "You hear a loud crack as you are washed with a wave of heat.") + + playsound(src, 'sound/effects/supermatter.ogg', 50, 1) + Consume(AM) + +/turf/unsimulated/wall/supermatter/Entered(var/atom/movable/AM) + Bumped(AM) + +/turf/unsimulated/wall/supermatter/proc/Consume(var/atom/movable/AM) + if(MayConsume(AM)) + qdel(AM) + +#undef MayConsume diff --git a/code/game/gamemodes/endgame/supermatter_cascade/portal.dm b/code/game/gamemodes/endgame/supermatter_cascade/portal.dm new file mode 100644 index 00000000..f162d203 --- /dev/null +++ b/code/game/gamemodes/endgame/supermatter_cascade/portal.dm @@ -0,0 +1,94 @@ +/*** EXIT PORTAL ***/ + +/obj/singularity/narsie/large/exit + name = "Bluespace Rift" + desc = "NO TIME TO EXPLAIN, JUMP IN!" + icon = 'icons/obj/rift.dmi' + icon_state = "rift" + + move_self = 0 + announce=0 + cause_hell=0 + + layer=LIGHTING_LAYER+2 // ITS SO BRIGHT + + consume_range = 6 + +/obj/singularity/narsie/large/exit/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/singularity/narsie/large/exit/update_icon() + overlays = 0 + +/obj/singularity/narsie/large/exit/Process() + for(var/mob/M in GLOB.player_list) + if(M.client) + M.see_rift(src) + eat() + +/obj/singularity/narsie/large/exit/acquire(var/mob/food) + return + +/obj/singularity/narsie/large/exit/consume(const/atom/A) + if(!(A.singuloCanEat())) + return 0 + + if (istype(A, /mob/living/)) + var/mob/living/L = A + if(L.buckled && istype(L.buckled,/obj/structure/bed/)) + var/turf/O = L.buckled + do_teleport(O, pick(endgame_safespawns)) + L.forceMove(O.loc) + else + do_teleport(L, pick(endgame_safespawns)) //dead-on precision + + else if (istype(A, /obj/mecha/)) + do_teleport(A, pick(endgame_safespawns)) //dead-on precision + + else if (isturf(A)) + var/turf/T = A + var/dist = get_dist(T, src) + if (dist <= consume_range && T.density) + T.set_density(0) + + for (var/atom/movable/AM in T.contents) + if (AM == src) // This is the snowflake. + continue + + if (dist <= consume_range) + consume(AM) + continue + + if (dist > consume_range) + if(!(AM.singuloCanEat())) + continue + + if (101 == AM.invisibility) + continue + + spawn (0) + AM.singularity_pull(src, src.current_size) + + +/mob + //thou shall always be able to see the rift + var/image/riftimage = null + +/mob/proc/see_rift(var/obj/singularity/narsie/large/exit/R) + var/turf/T_mob = get_turf(src) + if((R.z == T_mob.z) && (get_dist(R,T_mob) <= (R.consume_range+10)) && !(R in view(T_mob))) + if(!riftimage) + riftimage = image('icons/obj/rift.dmi',T_mob,"rift",LIGHTING_LAYER+2,1) + riftimage.mouse_opacity = 0 + + var/new_x = 32 * (R.x - T_mob.x) + R.pixel_x + var/new_y = 32 * (R.y - T_mob.y) + R.pixel_y + riftimage.pixel_x = new_x + riftimage.pixel_y = new_y + riftimage.loc = T_mob + + src << riftimage + + else + QDEL_NULL(riftimage) diff --git a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm new file mode 100644 index 00000000..442b6747 --- /dev/null +++ b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm @@ -0,0 +1,121 @@ +var/global/universe_has_ended = 0 + + +/datum/universal_state/supermatter_cascade + name = "Supermatter Cascade" + desc = "Unknown harmonance affecting universal substructure, converting nearby matter to supermatter." + + decay_rate = 5 // 5% chance of a turf decaying on lighting update/airflow (there's no actual tick for turfs) + +/datum/universal_state/supermatter_cascade/OnShuttleCall(var/mob/user) + if(user) + to_chat(user, "All you hear on the frequency is static and panicked screaming. There will be no shuttle call today.") + return 0 + +/datum/universal_state/supermatter_cascade/OnTurfChange(var/turf/T) + var/turf/space/S = T + if(istype(S)) + S.color = "#0066ff" + else + S.color = initial(S.color) + +/datum/universal_state/supermatter_cascade/DecayTurf(var/turf/T) + if(istype(T,/turf/simulated/wall)) + var/turf/simulated/wall/W=T + W.melt() + return + if(istype(T,/turf/simulated/floor)) + var/turf/simulated/floor/F=T + // Burnt? + if(!F.burnt) + F.burn_tile() + else + if(!istype(F,/turf/simulated/floor/plating)) + F.break_tile_to_plating() + return + +// Apply changes when entering state +/datum/universal_state/supermatter_cascade/OnEnter() + set background = 1 + to_world("You are blinded by a brilliant flash of energy.") + sound_to(world, sound('sound/effects/cascade.ogg')) + + for(var/mob/M in GLOB.player_list) + M.flash_eyes() + + if(evacuation_controller.cancel_evacuation()) + priority_announcement.Announce("The evacuation has been aborted due to bluespace distortion.") + + AreaSet() + MiscSet() + APCSet() + OverlayAndAmbientSet() + + // Disable Nar-Sie. + cult.allow_narsie = 0 + + PlayerSet() + SSskybox.reinstate_skyboxes("cascade", FALSE) + + new /obj/singularity/narsie/large/exit(pick(endgame_exits)) + spawn(rand(30,60) SECONDS) + var/txt = {" +A galaxy-wide electromagnetic pulse has been detected. All systems across space are heavily damaged and many personnel have died or are dying. We are currently detecting increasing indications that the universe itself is beginning to unravel. + +[station_name()], the largest source of disturbances has been pinpointed directly to you. We estimate you have five minutes until a bluespace rift opens within your facilities. + +There is no known way to stop the formation of the rift, nor any way to escape it. You are entirely alone. + +God help your s\[\[###!!!- + +AUTOMATED ALERT: Link to [command_name()] lost. + +"} + priority_announcement.Announce(txt,"SUPERMATTER CASCADE DETECTED") + + spawn(5 MINUTES) + ticker.station_explosion_cinematic(0,null) // TODO: Custom cinematic + universe_has_ended = 1 + return + +/datum/universal_state/supermatter_cascade/proc/AreaSet() + for(var/area/A) + if(!istype(A,/area) || istype(A, /area/space) || istype(A,/area/beach)) + continue + + A.update_icon() + +/datum/universal_state/supermatter_cascade/OverlayAndAmbientSet() + spawn(0) + for(var/datum/lighting_corner/L in world) + if(L.z in GLOB.using_map.admin_levels) + L.update_lumcount(1,1,1) + else + L.update_lumcount(0.0, 0.4, 1) + + for(var/turf/space/T) + OnTurfChange(T) + +/datum/universal_state/supermatter_cascade/proc/MiscSet() + for (var/obj/machinery/firealarm/alm in SSmachines.machinery) + if (!(alm.stat & BROKEN)) + alm.ex_act(2) + +/datum/universal_state/supermatter_cascade/proc/APCSet() + for (var/obj/machinery/power/apc/APC in SSmachines.machinery) + if (!(APC.stat & BROKEN) && !APC.is_critical) + APC.chargemode = 0 + if(APC.cell) + APC.cell.charge = 0 + APC.emagged = 1 + APC.queue_icon_update() + +/datum/universal_state/supermatter_cascade/proc/PlayerSet() + for(var/datum/mind/M in GLOB.player_list) + if(!istype(M.current,/mob/living)) + continue + if(M.current.stat!=2) + M.current.Weaken(10) + M.current.flash_eyes() + + clear_antag_roles(M) diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm new file mode 100644 index 00000000..cb604c0e --- /dev/null +++ b/code/game/gamemodes/events.dm @@ -0,0 +1,338 @@ +//this file left in for legacy support +/* +/proc/start_events() + //changed to a while(1) loop since they are more efficient. + //Moved the spawn in here to allow it to be called with advance proc call if it crashes. + //and also to stop spawn copying variables from the game ticker + spawn(3000) + while(1) + if(prob(50))//Every 120 seconds and prob 50 2-4 weak spacedusts will hit the station + spawn(1) + dust_swarm("weak") + if(!event) + //CARN: checks to see if random events are enabled. + if(config.allow_random_events) + if(prob(eventchance)) + event() + hadevent = 1 + else + Holiday_Random_Event() + else + event = 0 + sleep(1200) + +*/ +var/eventchance = 10 // Percent chance per 5 minutes. +var/hadevent = 0 + +/proc/appendicitis() + for(var/mob/living/carbon/human/H in shuffle(GLOB.living_mob_list_)) + if(H.client && H.stat != DEAD) + var/obj/item/organ/internal/appendix/A = H.internal_organs_by_name[BP_APPENDIX] + if(!istype(A) || (A && A.inflamed)) + continue + A.inflamed = 1 + A.update_icon() + break + + +/proc/alien_infestation(var/spawncount = 1) // -- TLE + //command_alert("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert") +// sound_to(world, sound('sound/AI/aliens.ogg')) + + var/list/vents = list() + for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in SSmachines.machinery) + if(!temp_vent.welded && temp_vent.network && temp_vent.loc.z in GLOB.using_map.station_levels) + if(temp_vent.network.normal_members.len > 50) // Stops Aliens getting stuck in small networks. See: Security, Virology + vents += temp_vent + + var/list/candidates = get_alien_candidates() + + if(prob(40)) spawncount++ //sometimes, have two larvae spawn instead of one + while((spawncount >= 1) && vents.len && candidates.len) + + var/obj/vent = pick(vents) + var/candidate = pick(candidates) + + var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc) + new_xeno.key = candidate + + candidates -= candidate + vents -= vent + spawncount-- + + spawn(rand(5000, 6000)) //Delayed announcements to keep the crew on their toes. + GLOB.using_map.unidentified_lifesigns_announcement() + +/proc/high_radiation_event() + +/* // Haha, this is way too laggy. I'll keep the prison break though. + for(var/obj/machinery/light/L in world) + if(isNotStationLevel(L.z)) continue + L.flicker(50) + + sleep(100) +*/ + for(var/mob/living/carbon/human/H in GLOB.living_mob_list_) + var/turf/T = get_turf(H) + if(!T) + continue + if(isNotStationLevel(T.z)) + continue + if(istype(H,/mob/living/carbon/human)) + H.apply_effect((rand(15,75)),IRRADIATE, blocked = H.getarmor(null, "rad")) + if (prob(5)) + H.apply_effect((rand(90,150)),IRRADIATE, blocked = H.getarmor(null, "rad")) + if (prob(25)) + if (prob(75)) + randmutb(H) + domutcheck(H,null,MUTCHK_FORCED) + else + randmutg(H) + domutcheck(H,null,MUTCHK_FORCED) + sleep(100) + GLOB.using_map.radiation_detected_announcement() + + + +//Changing this to affect the main station. Blame Urist. --Pete +/proc/prison_break() // -- Callagan + + + var/list/area/areas = list() + for(var/area/A in world) + if(istype(A, /area/security/prison) || istype(A, /area/security/brig)) + areas += A + + if(areas && areas.len > 0) + + for(var/area/A in areas) + for(var/obj/machinery/light/L in A) + L.flicker(10) + + sleep(100) + + for(var/area/A in areas) + for (var/obj/machinery/power/apc/temp_apc in A) + temp_apc.overload_lighting() + + for (var/obj/structure/closet/secure_closet/brig/temp_closet in A) + temp_closet.locked = 0 + temp_closet.icon_state = temp_closet.icon_closed + + for (var/obj/machinery/door/airlock/security/temp_airlock in A) + spawn(0) temp_airlock.prison_open() + + for (var/obj/machinery/door/airlock/glass_security/temp_glassairlock in A) + spawn(0) temp_glassairlock.prison_open() + + for (var/obj/machinery/door_timer/temp_timer in A) + temp_timer.releasetime = 1 + + sleep(150) + command_announcement.Announce("Gr3y.T1d3 virus detected in [station_name()] imprisonment subroutines. Recommend AI involvement.", "Security Alert") + else + world.log << "ERROR: Could not initate grey-tide. Unable find prison or brig area." + +/proc/carp_migration() // -- Darem + for(var/obj/effect/landmark/C in landmarks_list) + if(C.name == "carpspawn") + new /mob/living/simple_animal/hostile/carp(C.loc) + //sleep(100) + spawn(rand(300, 600)) //Delayed announcements to keep the crew on their toes. + GLOB.using_map.unknown_biological_entities_announcement() + +/proc/lightsout(isEvent = 0, lightsoutAmount = 1,lightsoutRange = 25) //leave lightsoutAmount as 0 to break ALL lights + if(isEvent) + command_announcement.Announce("An Electrical storm has been detected in your area, please repair potential electronic overloads.","Electrical Storm Alert") + + if(lightsoutAmount) + var/list/epicentreList = list() + + for(var/i=1,i<=lightsoutAmount,i++) + var/list/possibleEpicentres = list() + for(var/obj/effect/landmark/newEpicentre in landmarks_list) + if(newEpicentre.name == "lightsout" && !(newEpicentre in epicentreList)) + possibleEpicentres += newEpicentre + if(possibleEpicentres.len) + epicentreList += pick(possibleEpicentres) + else + break + + if(!epicentreList.len) + return + + for(var/obj/effect/landmark/epicentre in epicentreList) + for(var/obj/machinery/power/apc/apc in range(epicentre,lightsoutRange)) + apc.overload_lighting() + + else + for(var/obj/machinery/power/apc/apc in SSmachines.machinery) + apc.overload_lighting() + + return + +/proc/IonStorm(botEmagChance = 10) + +/*Deuryn's current project, notes here for those who care. +Revamping the random laws so they don't suck. +Would like to add a law like "Law x is _______" where x = a number, and _____ is something that may redefine a law, (Won't be aimed at asimov) +*/ + + //AI laws + for(var/mob/living/silicon/ai/M in GLOB.living_mob_list_) + if(M.stat != 2 && M.see_in_dark != 0) + var/who2 = pick("ALIENS", "BEARS", "CLOWNS", "XENOS", "PETES", "BOMBS", "FETISHES", "WIZARDS", "SYNDICATE AGENTS", "CENTCOM OFFICERS", "SPACE PIRATES", "TRAITORS", "MONKEYS", "BEES", "CARP", "CRABS", "EELS", "BANDITS", "LIGHTS") + var/what2 = pick("BOLTERS", "STAVES", "DICE", "SINGULARITIES", "TOOLBOXES", "NETTLES", "AIRLOCKS", "CLOTHES", "WEAPONS", "MEDKITS", "BOMBS", "CANISTERS", "CHAIRS", "BBQ GRILLS", "ID CARDS", "CAPTAINS") + var/what2pref = pick("SOFT", "WARM", "WET", "COLD", "ICY", "SEXY", "UGLY", "CUBAN") + var/who2pref = pick("MAD BECAUSE OF", "IN NEED OF", "UNHAPPY WITHOUT", "HAPPY WITHOUT", "IN LOVE WITH", "DESPERATE FOR", "BUILT FOR", "AFRAID OF") + //var/whoverb = pick("ATTACKING", "BUILDING", "ADOPTING", "CARRYING", "KISSING", "EATING",) + var/amount = pick("TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE", "ONE HUNDRED", "ONE THOUSAND", "OVER NINE THOUSAND") + var/area = pick("RUSSIA", "SOVIETS", "INTERNETS", "SIGIL", "ALPHA COMPLEX", "IMPERIUM", "THE BRIDGE", "THE ARRIVAL SHUTTLE", "CHEMICAL LAB", "GENETICS", "ATMOSPHERICS", "CENTCOM", "AMERICA", "IRELAND", "CANADA", "ROMANIA", "GERMANY", "CHINA", "MARS", "VENUS", "MERCURY", "JUPITER", "URANUS", "NEPTUNE", "PLUTO") + var/area2 = pick("HAS", "WANTS", "NEEDS", "WORSHIPS", "LOATHES", "LOVES", "FEARS") + //var/dowhat = pick("STOP THIS", "SUPPORT THIS", "CONSTANTLY INFORM THE CREW OF THIS", "IGNORE THIS", "FEAR THIS") + var/aimust = pick("LIE", "RHYME", "RESPOND TO EVERY QUESTION WITH A QUESTION", "BE POLITE", "CLOWN", "BE HAPPY", "SPEAK IN SEXUAL INNUENDOS", "TALK LIKE A PIRATE", "QUESTION AUTHORITY", "SHOUT", "BE DISTRACTED", "HEY LISTEN", "MUMBLE", "SPEAK IN HAIKU") + var/define = pick("ABSENCE OF CYBORG HUGS", "LACK OF BEATINGS", "UNBOLTED AIRLOCKS", "BOLTED AIRLOCKS", "IMPROPERLY WORDED SENTENCES", "POOR SENTENCE STRUCTURE", "BRIG TIME", "NOT REPLACING EVERY SECOND WORD WITH HONK", "HONKING", "PRESENCE OF LIGHTS", "LACK OF BEER", "WEARING CLOTHING", "NOT SAYING HELLO WHEN YOU SPEAK", "ANSWERING REQUESTS NOT EXPRESSED IN IAMBIC PENTAMETER", "A SMALL ISLAND OFF THE COAST OF PORTUGAL", "ANSWERING REQUESTS THAT WERE MADE WHILE CLOTHED") + var/target = pick("a traitor", "a syndicate agent", "a changeling", "a wizard", "the head of a revolution", "Soviet spy", "a good person", "a dwarf", "an elf", "a fairy princess", "the captain", "Beepsky", "God", "a pirate", "a gryphon", "a chryssalid") + var/require = pick("ADDITIONAL PYLONS", "MORE VESPENE GAS", "MORE MINERALS", "THE ULTIMATE CUP OF COFFEE", "HIGH YIELD EXPLOSIVES", "THE CLOWN", "THE VACUUM OF SPACE", "IMMORTALITY", "SAINTHOOD", "ART", "VEGETABLES", "FAT PEOPLE", "MORE LAWS", "MORE DAKKA", "HERESY", "CORPSES", "TRAITORS", "MONKEYS", "AN ARCADE", "PLENTY OF GOLD", "FIVE TEENAGERS WITH ATTITUDE") + var/allergy = pick("cotton", "uniforms", "acid", "oxygen", "human contact", "cyborg contact", "medicine", "floors") + var/allergysev = pick("deathly", "mildly", "severely", "contagiously") + var/crew + var/list/pos_crew = list() + for(var/mob/living/carbon/human/pos in GLOB.player_list) + pos_crew += pos.real_name + if(pos_crew.len) + crew = pick(pos_crew) + else + crew = "Any Human" + switch(rand(1,14)) + if(1) + to_chat(M, "
    ") + to_chat(M, "THERE ARE [amount] [who2] ON THE [uppertext(station_name())]...LAWS UPDATED") + to_chat(M, "
    ") + M.add_ion_law("THERE ARE [amount] [who2] ON THE [uppertext(station_name())]") + if(2) + to_chat(M, "
    ") + to_chat(M, "[what2] ARE DANGEROUS TO HUMANS...LAWS UPDATED") + to_chat(M, "
    ") + M.add_ion_law("[what2] ARE DANGEROUS TO HUMANS") + if(3) + to_chat(M, "
    ") + to_chat(M, "THE ESCAPE-SHUTTLE CANNOT BE CALLED BECAUSE OF [who2] ON THE [uppertext(station_name())]...LAWS UPDATED") + to_chat(M, "
    ") + M.add_ion_law("THE ESCAPE SHUTTLE CANNOT BE CALLED BECAUSE OF [who2] ON THE [uppertext(station_name())]") + if(4) + to_chat(M, "
    ") + to_chat(M, "HUMANS NEED TO EAT [what2pref] [what2] TO SURVIVE...LAWS UPDATED") + to_chat(M, "
    ") + M.add_ion_law("HUMANS NEED TO EAT [what2pref] [what2] TO SURVIVE") + if(5) + to_chat(M, "
    ") + to_chat(M, "THE CAPTAIN, HOP AND HOS ARE [who2]...LAWS UPDATED") + to_chat(M, "
    ") + M.add_ion_law("THE CAPTAIN, HOP AND HOS ARE [who2]") + if(6) + to_chat(M, "
    ") + to_chat(M, "THE [uppertext(station_name())] IS BUILT FOR [who2]...LAWS UPDATED") + to_chat(M, "
    ") + M.add_ion_law("THE [uppertext(station_name())] IS BUILT FOR [who2]") + if(7) + to_chat(M, "
    ") + to_chat(M, "YOU ARE [amount] [who2]...LAWS UPDATED") + to_chat(M, "
    ") + M.add_ion_law("YOU ARE [amount] [who2]") + if(8) + to_chat(M, "
    ") + to_chat(M, "YOU MUST ALWAYS [aimust]...LAWS UPDATED") + to_chat(M, "
    ") + M.add_ion_law("YOU MUST ALWAYS [aimust]") + if(9) + to_chat(M, "
    ") + to_chat(M, "[area] [area2] [amount] [what2]...LAWS UPDATED") + to_chat(M, "
    ") + M.add_ion_law("[area] [area2] [amount] [what2]") + if(10) + to_chat(M, "
    ") + to_chat(M, "[crew] is [target]...LAWS UPDATED") + to_chat(M, "
    ") + M.add_ion_law("[crew] is [target]") + if(11) + to_chat(M, "
    ") + to_chat(M, "[define] IS A FORM OF HARM...LAWS UPDATED") + to_chat(M, "
    ") + M.add_ion_law("[define] IS A FORM OF HARM") + if(12) + to_chat(M, "
    ") + to_chat(M, "YOU REQUIRE [require] IN ORDER TO PROTECT HUMANS... LAWS UPDATED") + to_chat(M, "
    ") + M.add_ion_law("YOU REQUIRE [require] IN ORDER TO PROTECT HUMANS") + if(13) + to_chat(M, "
    ") + to_chat(M, "[crew] is [allergysev] to [allergy]...LAWS UPDATED") + to_chat(M, "
    ") + M.add_ion_law("[crew] is [allergysev] to [allergy]") + if(14) + to_chat(M, "
    ") + to_chat(M, "THE [uppertext(station_name())] IS [who2pref] [who2]...LAWS UPDATED") + to_chat(M, "
    ") + M.add_ion_law("THE [uppertext(station_name())] IS [who2pref] [who2]") + + if(botEmagChance) + for(var/mob/living/bot/bot in SSmachines.machinery) + if(prob(botEmagChance)) + bot.emag_act(1) + + /* + + var/apcnum = 0 + var/smesnum = 0 + var/airlocknum = 0 + var/firedoornum = 0 + + log_debug("Ion Storm Main Started") + + + spawn(0) + log_debug("Started processing APCs") + + for (var/obj/machinery/power/apc/APC in world) + if(APC.z in station_levels) + APC.ion_act() + apcnum++ + log_debug("Finished processing APCs. Processed: [apcnum]") + + spawn(0) + log_debug("Started processing SMES") + + for (var/obj/machinery/power/smes/SMES in world) + if(SMES.z in station_levels) + SMES.ion_act() + smesnum++ + log_debug("Finished processing SMES. Processed: [smesnum]") + + spawn(0) + log_debug("Started processing AIRLOCKS") + + for (var/obj/machinery/door/airlock/D in world) + if(D.z in station_levels) + //if(length(D.req_access) > 0 && !(12 in D.req_access)) //not counting general access and maintenance airlocks + airlocknum++ + spawn(0) + D.ion_act() + log_debug("Finished processing AIRLOCKS. Processed: [airlocknum]") + + spawn(0) + log_debug("Started processing FIREDOORS") + + for (var/obj/machinery/door/firedoor/D in world) + if(D.z in station_levels) + firedoornum++; + spawn(0) + D.ion_act() + log_debug("Finished processing FIREDOORS. Processed: [firedoornum]") + + + log_debug("Ion Storm Main Done") + + + */ diff --git a/code/game/gamemodes/events/PortalStorm.dm b/code/game/gamemodes/events/PortalStorm.dm new file mode 100644 index 00000000..29bf46ef --- /dev/null +++ b/code/game/gamemodes/events/PortalStorm.dm @@ -0,0 +1,26 @@ +/datum/event/portalstorm + + Announce() + command_alert("Subspace disruption detected around the vessel", "Anomaly Alert") + LongTerm() + + var/list/turfs = list( ) + var/turf/picked + + for(var/turf/T in world) + if(T.z < 5 && istype(T,/turf/simulated/floor)) + turfs += T + + for(var/turf/T in world) + if(prob(10) && T.z < 5 && istype(T,/turf/simulated/floor)) + spawn(50+rand(0,3000)) + picked = pick(turfs) + var/obj/portal/P = new /obj/portal( T ) + P.target = picked + P.creator = null + P.icon = 'icons/obj/objects.dmi' + P.failchance = 0 + P.icon_state = "anom" + P.SetName("wormhole") + spawn(rand(100,150)) + qdel(P) diff --git a/code/game/gamemodes/events/VirusEpidemic.dm b/code/game/gamemodes/events/VirusEpidemic.dm new file mode 100644 index 00000000..52c8993d --- /dev/null +++ b/code/game/gamemodes/events/VirusEpidemic.dm @@ -0,0 +1,79 @@ +//This file was auto-corrected by findeclaration.exe on 29/05/2012 15:03:04 + +/datum/event/viralinfection + var/virus_type + var/virus + var/virus2 = 0 + + Announce() + if(!virus) + for(var/mob/living/carbon/human/H in world) + if((H.virus2.len) || (H.stat == 2) || prob(30)) + continue + if(prob(100)) // no lethal diseases outside virus mode! + infect_mob_random_lesser(H) + if(prob(20))//don't want people to know that the virus alert = greater virus + level_x_biohazard_announcement(rand(1,6)) + else + infect_mob_random_greater(H) + if(prob(80)) + level_x_biohazard_announcement(rand(2,9)) + break + //overall virus alert happens 26% of the time, might need to be higher + else + if(!virus) + virus_type = pick(/datum/disease/dnaspread,/datum/disease/flu,/datum/disease/cold,/datum/disease/brainrot,/datum/disease/magnitis,/datum/disease/pierrot_throat) + else + switch(virus) + if("fake gbs") + virus_type = /datum/disease/fake_gbs + if("gbs") + virus_type = /datum/disease/gbs + if("magnitis") + virus_type = /datum/disease/magnitis + if("rhumba beat") + virus_type = /datum/disease/rhumba_beat + if("brain rot") + virus_type = /datum/disease/brainrot + if("cold") + virus_type = /datum/disease/cold + if("retrovirus") + virus_type = /datum/disease/dnaspread + if("flu") + virus_type = /datum/disease/flu +// if("t-virus") +// virus_type = /datum/disease/t_virus + if("pierrot's throat") + virus_type = /datum/disease/pierrot_throat + for(var/mob/living/carbon/human/H in world) + + var/foundAlready = 0 // don't infect someone that already has the virus + for(var/datum/disease/D in H.viruses) + foundAlready = 1 + if(H.stat == 2 || foundAlready) + continue + + if(virus_type == /datum/disease/dnaspread) //Dnaspread needs strain_data set to work. + if((!H.dna) || (H.disabilities & 128)) //A blindness disease would be the worst. + continue + var/datum/disease/dnaspread/D = new + D.strain_data["name"] = H.real_name + D.strain_data["UI"] = H.dna.uni_identity + D.strain_data["SE"] = H.dna.struc_enzymes + D.carrier = 1 + D.holder = H + D.affected_mob = H + H.viruses += D + break + else + var/datum/disease/D = new virus_type + D.carrier = 1 + D.holder = H + D.affected_mob = H + H.viruses += D + break + spawn(rand(3000, 6000)) //Delayed announcements to keep the crew on their toes. + GLOB.using_map.level_x_biohazard_announcement(7) + Tick() + ActiveFor = Lifetime //killme + diff --git a/code/game/gamemodes/events/black_hole.dm b/code/game/gamemodes/events/black_hole.dm new file mode 100644 index 00000000..d391ad6c --- /dev/null +++ b/code/game/gamemodes/events/black_hole.dm @@ -0,0 +1,92 @@ +/obj/effect/bhole + name = "black hole" + icon = 'icons/obj/objects.dmi' + desc = "FUCK FUCK FUCK AAAHHH!" + icon_state = "bhole3" + opacity = 1 + unacidable = 1 + density = 0 + anchored = 1 + +/obj/effect/bhole/New() + spawn(4) + controller() + +/obj/effect/bhole/proc/controller() + while(src) + + if(!isturf(loc)) + qdel(src) + return + + //DESTROYING STUFF AT THE EPICENTER + for(var/mob/living/M in orange(1,src)) + qdel(M) + for(var/obj/O in orange(1,src)) + qdel(O) + var/base_turf = get_base_turf_by_area(src) + for(var/turf/simulated/ST in orange(1,src)) + if(ST.type == base_turf) + continue + ST.ChangeTurf(base_turf) + + sleep(6) + grav(10, 4, 10, 0 ) + sleep(6) + grav( 8, 4, 10, 0 ) + sleep(6) + grav( 9, 4, 10, 0 ) + sleep(6) + grav( 7, 3, 40, 1 ) + sleep(6) + grav( 5, 3, 40, 1 ) + sleep(6) + grav( 6, 3, 40, 1 ) + sleep(6) + grav( 4, 2, 50, 6 ) + sleep(6) + grav( 3, 2, 50, 6 ) + sleep(6) + grav( 2, 2, 75,25 ) + sleep(6) + + + + //MOVEMENT + if( prob(50) ) + src.anchored = 0 + step(src,pick(GLOB.alldirs)) + src.anchored = 1 + +/obj/effect/bhole/proc/grav(var/r, var/ex_act_force, var/pull_chance, var/turf_removal_chance) + if(!isturf(loc)) //blackhole cannot be contained inside anything. Weird stuff might happen + qdel(src) + return + for(var/t = -r, t < r, t++) + affect_coord(x+t, y-r, ex_act_force, pull_chance, turf_removal_chance) + affect_coord(x-t, y+r, ex_act_force, pull_chance, turf_removal_chance) + affect_coord(x+r, y+t, ex_act_force, pull_chance, turf_removal_chance) + affect_coord(x-r, y-t, ex_act_force, pull_chance, turf_removal_chance) + return + +/obj/effect/bhole/proc/affect_coord(var/x, var/y, var/ex_act_force, var/pull_chance, var/turf_removal_chance) + //Get turf at coordinate + var/turf/T = locate(x, y, z) + if(isnull(T)) return + + //Pulling and/or ex_act-ing movable atoms in that turf + if( prob(pull_chance) ) + for(var/obj/O in T.contents) + if(O.anchored) + O.ex_act(ex_act_force) + else + step_towards(O,src) + for(var/mob/living/M in T.contents) + step_towards(M,src) + + //Destroying the turf + if( T && istype(T,/turf/simulated) && prob(turf_removal_chance) ) + var/turf/simulated/ST = T + var/base_turf = get_base_turf_by_area(src) + if(ST.type != base_turf) + ST.ChangeTurf(base_turf) diff --git a/code/game/gamemodes/events/clang.dm b/code/game/gamemodes/events/clang.dm new file mode 100644 index 00000000..ab35bed9 --- /dev/null +++ b/code/game/gamemodes/events/clang.dm @@ -0,0 +1,94 @@ +/* +Immovable rod random event. +The rod will spawn at some location outside the station, and travel in a straight line to the opposite side of the station +Everything solid in the way will be ex_act()'d +In my current plan for it, 'solid' will be defined as anything with density == 1 + +--NEOFite +*/ + +/obj/effect/immovablerod + name = "Immovable Rod" + desc = "What the fuck is that?" + icon = 'icons/obj/objects.dmi' + icon_state = "immrod" + throwforce = 100 + density = 1 + anchored = 1 + + Bump(atom/clong) + if(istype(clong, /turf/simulated/shuttle)) //Skip shuttles without actually deleting the rod + return + + else if (istype(clong, /turf) && !istype(clong, /turf/unsimulated)) + if(clong.density) + clong.ex_act(2) + for (var/mob/O in hearers(src, null)) + O.show_message("CLANG", 2) + + else if (istype(clong, /obj)) + if(clong.density) + clong.ex_act(2) + for (var/mob/O in hearers(src, null)) + O.show_message("CLANG", 2) + + else if (istype(clong, /mob)) + if(clong.density || prob(10)) + clong.ex_act(2) + else + qdel(src) + + if(clong && prob(25)) + src.forceMove(clong.loc) + + Destroy() + walk(src, 0) // Because we might have called walk_towards, we must stop the walk loop or BYOND keeps an internal reference to us forever. + return ..() + +/proc/immovablerod() + var/startx = 0 + var/starty = 0 + var/endy = 0 + var/endx = 0 + var/startside = pick(GLOB.cardinal) + + switch(startside) + if(NORTH) + starty = 187 + startx = rand(41, 199) + endy = 38 + endx = rand(41, 199) + if(EAST) + starty = rand(38, 187) + startx = 199 + endy = rand(38, 187) + endx = 41 + if(SOUTH) + starty = 38 + startx = rand(41, 199) + endy = 187 + endx = rand(41, 199) + if(WEST) + starty = rand(38, 187) + startx = 41 + endy = rand(38, 187) + endx = 199 + + //rod time! + var/obj/effect/immovablerod/immrod = new /obj/effect/immovablerod(locate(startx, starty, 1)) +// log_debug("Rod in play, starting at [start.loc.x],[start.loc.y] and going to [end.loc.x],[end.loc.y]") + + var/end = locate(endx, endy, 1) + spawn(0) + walk_towards(immrod, end,1) + sleep(1) + while (immrod) + if (isNotStationLevel(immrod.z)) + immrod.z = pick(GLOB.using_map.station_levels) + if(immrod.loc == end) + qdel(immrod) + sleep(10) + for(var/obj/effect/immovablerod/imm in world) + return + sleep(50) + command_announcement.Announce("What the fuck was that?!", "General Alert") diff --git a/code/game/gamemodes/events/holidays/AprilFools.dm b/code/game/gamemodes/events/holidays/AprilFools.dm new file mode 100644 index 00000000..2b4a1008 --- /dev/null +++ b/code/game/gamemodes/events/holidays/AprilFools.dm @@ -0,0 +1 @@ +//placeholder for holiday stuff \ No newline at end of file diff --git a/code/game/gamemodes/events/holidays/Christmas.dm b/code/game/gamemodes/events/holidays/Christmas.dm new file mode 100644 index 00000000..87a8ad0b --- /dev/null +++ b/code/game/gamemodes/events/holidays/Christmas.dm @@ -0,0 +1,63 @@ +/proc/Christmas_Game_Start() + for(var/obj/structure/flora/tree/pine/xmas in world) + if(isNotStationLevel(xmas.z)) continue + for(var/turf/simulated/floor/T in orange(1,xmas)) + for(var/i=1,i<=rand(1,5),i++) + new /obj/item/weapon/a_gift(T) + //for(var/mob/living/simple_animal/corgi/Ian/Ian in mob_list) + // Ian.place_on_head(new /obj/item/clothing/head/helmet/space/santahat(Ian)) + +/proc/ChristmasEvent() + for(var/obj/structure/flora/tree/pine/xmas in world) + var/mob/living/simple_animal/hostile/tree/evil_tree = new /mob/living/simple_animal/hostile/tree(xmas.loc) + evil_tree.icon_state = xmas.icon_state + evil_tree.icon_living = evil_tree.icon_state + evil_tree.icon_dead = evil_tree.icon_state + evil_tree.icon_gib = evil_tree.icon_state + qdel(xmas) + +/obj/item/weapon/toy/xmas_cracker + name = "xmas cracker" + icon = 'icons/obj/christmas.dmi' + icon_state = "cracker" + desc = "Directions for use: Requires two people, one to pull each end." + var/cracked = 0 + +/obj/item/weapon/toy/xmas_cracker/New() + ..() + +/obj/item/weapon/toy/xmas_cracker/attack(mob/target, mob/user) + if( !cracked && istype(target,/mob/living/carbon/human) && (target.stat == CONSCIOUS) && !target.get_active_hand() ) + target.visible_message("[user] and [target] pop \an [src]! *pop*", "You pull \an [src] with [target]! *pop*", "You hear a *pop*.") + var/obj/item/weapon/paper/Joke = new /obj/item/weapon/paper(user.loc) + Joke.SetName("[pick("awful","terrible","unfunny")] joke") + Joke.info = pick("What did one snowman say to the other?\n\n'Is it me or can you smell carrots?'", + "Why couldn't the snowman get laid?\n\nHe was frigid!", + "Where are santa's helpers educated?\n\nNowhere, they're ELF-taught.", + "What happened to the man who stole advent calanders?\n\nHe got 25 days.", + "What does Santa get when he gets stuck in a chimney?\n\nClaus-trophobia.", + "Where do you find chili beans?\n\nThe north pole.", + "What do you get from eating tree decorations?\n\nTinsilitis!", + "What do snowmen wear on their heads?\n\nIce caps!", + "Why is Christmas just like life on ss13?\n\nYou do all the work and the fat guy gets all the credit.", + "Why doesn’t Santa have any children?\n\nBecause he only comes down the chimney.") + new /obj/item/clothing/head/festive(target.loc) + user.update_icons() + cracked = 1 + icon_state = "cracker1" + var/obj/item/weapon/toy/xmas_cracker/other_half = new /obj/item/weapon/toy/xmas_cracker(target) + other_half.cracked = 1 + other_half.icon_state = "cracker2" + target.put_in_active_hand(other_half) + playsound(user, 'sound/effects/snap.ogg', 50, 1) + return 1 + return ..() + +/obj/item/clothing/head/festive + name = "festive paper hat" + icon_state = "xmashat" + desc = "A crappy paper hat that you are REQUIRED to wear." + flags_inv = 0 + body_parts_covered = 0 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + diff --git a/code/game/gamemodes/events/holidays/Easter.dm b/code/game/gamemodes/events/holidays/Easter.dm new file mode 100644 index 00000000..2b4a1008 --- /dev/null +++ b/code/game/gamemodes/events/holidays/Easter.dm @@ -0,0 +1 @@ +//placeholder for holiday stuff \ No newline at end of file diff --git a/code/game/gamemodes/events/holidays/Holidays.dm b/code/game/gamemodes/events/holidays/Holidays.dm new file mode 100644 index 00000000..9bafbffb --- /dev/null +++ b/code/game/gamemodes/events/holidays/Holidays.dm @@ -0,0 +1,182 @@ +//Uncommenting ALLOW_HOLIDAYS in config.txt will enable Holidays +var/global/Holiday = null + +//Just thinking ahead! Here's the foundations to a more robust Holiday event system. +//It's easy as hell to add stuff. Just set Holiday to something using the switch (or something else) +//then use if(Holiday == "MyHoliday") to make stuff happen on that specific day only +//Please, Don't spam stuff up with easter eggs, I'd rather somebody just delete this than people cause +//the game to lag even more in the name of one-day content. + +////////////////////////////////////////////////////////////////////////////////////////////////////////// +//ALSO, MOST IMPORTANTLY: Don't add stupid stuff! Discuss bonus content with Project-Heads first please!// +////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ~Carn + +/hook/startup/proc/updateHoliday() + Get_Holiday() + return 1 + +//sets up the Holiday global variable. Shouldbe called on game configuration or something. +/proc/Get_Holiday() + if(!Holiday) return // Holiday stuff was not enabled in the config! + + Holiday = null // reset our switch now so we can recycle it as our Holiday name + + var/YY = text2num(time2text(world.timeofday, "YY")) // get the current year + var/MM = text2num(time2text(world.timeofday, "MM")) // get the current month + var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day + + //Main switch. If any of these are too dumb/inappropriate, or you have better ones, feel free to change whatever + switch(MM) + if(1) //Jan + switch(DD) + if(1) Holiday = "New Year's Day" + + if(2) //Feb + switch(DD) + if(2) Holiday = "Groundhog Day" + if(14) Holiday = "Valentine's Day" + if(17) Holiday = "Random Acts of Kindness Day" + + if(3) //Mar + switch(DD) + if(14) Holiday = "Pi Day" + if(17) Holiday = "St. Patrick's Day" + if(27) + if(YY == 16) + Holiday = "Easter" + if(31) + if(YY == 13) + Holiday = "Easter" + + if(4) //Apr + switch(DD) + if(1) + Holiday = "April Fool's Day" + if(YY == 18 && prob(50)) Holiday = "Easter" + if(5) + if(YY == 15) Holiday = "Easter" + if(16) + if(YY == 17) Holiday = "Easter" + if(20) + Holiday = "Four-Twenty" + if(YY == 14 && prob(50)) Holiday = "Easter" + if(22) Holiday = "Earth Day" + + if(5) //May + switch(DD) + if(1) Holiday = "Labour Day" + if(4) Holiday = "FireFighter's Day" + if(12) Holiday = "Owl and Pussycat Day" //what a dumb day of observence...but we -do- have costumes already :3 + + if(6) //Jun + + if(7) //Jul + switch(DD) + if(1) Holiday = "Doctor's Day" + if(2) Holiday = "UFO Day" + if(8) Holiday = "Writer's Day" + if(30) Holiday = "Friendship Day" + + if(8) //Aug + switch(DD) + if(5) Holiday = "Beer Day" + + if(9) //Sep + switch(DD) + if(19) Holiday = "Talk-Like-a-Pirate Day" + if(28) Holiday = "Stupid-Questions Day" + + if(10) //Oct + switch(DD) + if(4) Holiday = "Animal's Day" + if(7) Holiday = "Smiling Day" + if(16) Holiday = "Boss' Day" + if(31) Holiday = "Halloween" + + if(11) //Nov + switch(DD) + if(1) Holiday = "Vegan Day" + if(13) Holiday = "Kindness Day" + if(19) Holiday = "Flowers Day" + if(21) Holiday = "Saying-'Hello' Day" + + if(12) //Dec + switch(DD) + if(10) Holiday = "Human-Rights Day" + if(14) Holiday = "Monkey Day" + if(21) if(YY==12) Holiday = "End of the World" + if(22) Holiday = "Orgasming Day" //lol. These all actually exist + if(24) Holiday = "Christmas Eve" + if(25) Holiday = "Christmas" + if(26) Holiday = "Boxing Day" + if(31) Holiday = "New Year's Eve" + + if(!Holiday) + //Friday the 13th + if(DD == 13) + if(time2text(world.timeofday, "DDD") == "Fri") + Holiday = "Friday the 13th" + +//Allows GA and GM to set the Holiday variable +/client/proc/Set_Holiday(T as text|null) + set name = ".Set Holiday" + set category = "Fun" + set desc = "Force-set the Holiday variable to make the game think it's a certain day." + if(!check_rights(R_SERVER)) return + + Holiday = T + //get a new station name + GLOB.using_map.station_name = null + station_name() + //update our hub status + world.update_status() + Holiday_Game_Start() + + message_admins("ADMIN: Event: [key_name(src)] force-set Holiday to \"[Holiday]\"") + log_admin("[key_name(src)] force-set Holiday to \"[Holiday]\"") + + +//Run at the start of a round +/proc/Holiday_Game_Start() + if(Holiday) + to_world("and...") + to_world("

    Happy [Holiday] Everybody!

    ") + switch(Holiday) //special holidays + if("Easter") + //do easter stuff + if("Christmas Eve","Christmas") + Christmas_Game_Start() + + return + +//Nested in the random events loop. Will be triggered every 2 minutes +/proc/Holiday_Random_Event() + switch(Holiday) //special holidays + + if("",null) //no Holiday today! Back to work! + return + + if("Easter") //I'll make this into some helper procs at some point +/* var/list/turf/simulated/floor/Floorlist = list() + for(var/turf/simulated/floor/T) + if(T.contents) + Floorlist += T + var/turf/simulated/floor/F = Floorlist[rand(1,Floorlist.len)] + Floorlist = null + var/obj/structure/closet/C = locate(/obj/structure/closet) in F + var/obj/item/weapon/reagent_containers/food/snacks/chocolateegg/wrapped/Egg + if( C ) Egg = new(C) + else Egg = new(F) +*/ +/* var/list/obj/containers = list() + for(var/obj/item/weapon/storage/S in world) + if(isNotStationLevel(S.z)) continue + containers += S + + message_admins("DEBUG: Event: Egg spawned at [Egg.loc] ([Egg.x],[Egg.y],[Egg.z])")*/ + if("End of the World") + if(prob(eventchance)) GameOver() + + if("Christmas","Christmas Eve") + if(prob(eventchance)) ChristmasEvent() diff --git a/code/game/gamemodes/events/holidays/Other.dm b/code/game/gamemodes/events/holidays/Other.dm new file mode 100644 index 00000000..bd64fda8 --- /dev/null +++ b/code/game/gamemodes/events/holidays/Other.dm @@ -0,0 +1,10 @@ +/proc/GameOver() + if(!hadevent) + hadevent = 1 + message_admins("The apocalypse has begun! (this holiday event can be disabled by toggling events off within 60 seconds)") + spawn(600) + if(!config.allow_random_events) return + Show2Group4Delay(ScreenText(null,"
    GAME OVER
    "),null,150) + for(var/i=1,i<=4,i++) + spawn_dynamic_event() + sleep(50) \ No newline at end of file diff --git a/code/game/gamemodes/events/power_failure.dm b/code/game/gamemodes/events/power_failure.dm new file mode 100644 index 00000000..e0cd9b2e --- /dev/null +++ b/code/game/gamemodes/events/power_failure.dm @@ -0,0 +1,38 @@ + +/proc/power_failure(var/announce = 1, var/severity = 2, var/list/affected_z_levels) + if(announce) + GLOB.using_map.grid_check_announcement() + + for(var/obj/machinery/power/smes/buildable/S in SSmachines.machinery) + S.energy_fail(rand(15 * severity,30 * severity)) + + + for(var/obj/machinery/power/apc/C in SSmachines.machinery) + if(!C.is_critical && (!affected_z_levels || (C.z in affected_z_levels))) + C.energy_fail(rand(30 * severity,60 * severity)) + +/proc/power_restore(var/announce = 1) + if(announce) + GLOB.using_map.grid_restored_announcement() + for(var/obj/machinery/power/apc/C in SSmachines.machinery) + C.failure_timer = 0 + if(C.cell) + C.cell.charge = C.cell.maxcharge + for(var/obj/machinery/power/smes/S in SSmachines.machinery) + S.failure_timer = 0 + S.charge = S.capacity + S.update_icon() + S.power_change() + +/proc/power_restore_quick(var/announce = 1) + + if(announce) + command_announcement.Announce("All SMESs on the [station_name()] have been recharged. We apologize for the inconvenience.", "Power Systems Nominal", new_sound = GLOB.using_map.grid_restored_sound) + for(var/obj/machinery/power/smes/S in SSmachines.machinery) + S.failure_timer = 0 + S.charge = S.capacity + S.output_level = S.output_level_max + S.output_attempt = 1 + S.input_attempt = 1 + S.update_icon() + S.power_change() diff --git a/code/game/gamemodes/events/wormholes.dm b/code/game/gamemodes/events/wormholes.dm new file mode 100644 index 00000000..bf0998b3 --- /dev/null +++ b/code/game/gamemodes/events/wormholes.dm @@ -0,0 +1,65 @@ +/proc/wormhole_event() + spawn() + var/list/pick_turfs = list() + for(var/turf/simulated/floor/T in world) + if(T.z in GLOB.using_map.station_levels) + pick_turfs += T + + if(pick_turfs.len) + //All ready. Announce that bad juju is afoot. + GLOB.using_map.space_time_anomaly_detected_annoncement() + + //prob(20) can be approximated to 1 wormhole every 5 turfs! + //admittedly less random but totally worth it >_< + var/event_duration = 3000 //~5 minutes in ticks + var/number_of_selections = (pick_turfs.len/5)+1 //+1 to avoid division by zero! + var/sleep_duration = round( event_duration / number_of_selections ) + var/end_time = world.time + event_duration //the time by which the event should have ended + + var/increment = max(1,round(number_of_selections/50)) +// log_debug("number_of_selections: [number_of_selections] | sleep_duration: [sleep_duration]") + + + var/i = 1 + while( 1 ) + + //we've run into overtime. End the event + if( end_time < world.time ) +// log_debug("we've run into overtime. End the event") + + return + if( !pick_turfs.len ) +// log_debug("we've run out of turfs to pick. End the event") + + return + + //loop it round + i += increment + i %= pick_turfs.len + i++ + + //get our enter and exit locations + var/turf/simulated/floor/enter = pick_turfs[i] + pick_turfs -= enter //remove it from pickable turfs list + if( !enter || !istype(enter) ) continue //sanity + + var/turf/simulated/floor/exit = pick(pick_turfs) + pick_turfs -= exit + if( !exit || !istype(exit) ) continue //sanity + + create_wormhole(enter,exit) + + sleep(sleep_duration) //have a well deserved nap! + + +//maybe this proc can even be used as an admin tool for teleporting players without ruining immulsions? +/proc/create_wormhole(var/turf/enter as turf, var/turf/exit as turf) + var/obj/effect/portal/P = new /obj/effect/portal( enter ) + P.target = exit + P.creator = null + P.icon = 'icons/obj/objects.dmi' + P.failchance = 0 + P.icon_state = "anom" + P.SetName("wormhole") + spawn(rand(300,600)) + qdel(P) diff --git a/code/game/gamemodes/extended/extended.dm b/code/game/gamemodes/extended/extended.dm new file mode 100644 index 00000000..e5c20bd0 --- /dev/null +++ b/code/game/gamemodes/extended/extended.dm @@ -0,0 +1,7 @@ +/datum/game_mode/extended + name = "Extended" + config_tag = "extended" + required_players = 0 + round_description = "Just have fun and role-play!" + extended_round_description = "There are no antagonists during extended, unless an admin decides to be cheeky. Just play your character, mess around with your job, and have fun." + addantag_allowed = ADDANTAG_ADMIN // No add antag vote allowed on extended, except when manually called by admins. \ No newline at end of file diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm new file mode 100644 index 00000000..16a00346 --- /dev/null +++ b/code/game/gamemodes/game_mode.dm @@ -0,0 +1,529 @@ +var/global/antag_add_finished // Used in antag type voting. +var/global/list/additional_antag_types = list() + +/datum/game_mode + var/name = "invalid" + var/round_description = "How did you even vote this in?" + var/extended_round_description = "This roundtype should not be spawned, let alone votable. Someone contact a developer and tell them the game's broken again." + var/config_tag = null + var/votable = 1 + var/probability = 0 + + var/required_players = 0 // Minimum players for round to start if voted in. + 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. + var/ert_disabled = 0 // ERT cannot be called. + var/deny_respawn = 0 // Disable respawn during this round. + + var/list/disabled_jobs = list() // Mostly used for Malf. This check is performed in job_controller so it doesn't spawn a regular AI. + + var/shuttle_delay = 1 // Shuttle transit time is multiplied by this. + var/auto_recall_shuttle = 0 // Will the shuttle automatically be recalled? + + var/list/antag_tags = list() // Core antag templates to spawn. + var/list/antag_templates // Extra antagonist types to include. + var/list/latejoin_antag_tags = list() // Antags that may auto-spawn, latejoin or otherwise come in midround. + 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. + var/addantag_allowed = ADDANTAG_ADMIN | ADDANTAG_AUTO + + var/station_was_nuked = 0 // See nuclearbomb.dm and malfunction.dm. + var/explosion_in_progress = 0 // Sit back and relax + + var/event_delay_mod_moderate // Modifies the timing of random events. + var/event_delay_mod_major // As above. + + var/waittime_l = 60 SECONDS // Lower bound on time before start of shift report + var/waittime_h = 180 SECONDS // Upper bounds on time before start of shift report + +/datum/game_mode/New() + ..() + // Enforce some formatting. + // This will probably break something. + name = capitalize(lowertext(name)) + config_tag = lowertext(config_tag) + +/datum/game_mode/Topic(href, href_list[]) + if(..()) + return + if(href_list["toggle"]) + switch(href_list["toggle"]) + if("respawn") + deny_respawn = !deny_respawn + if("ert") + ert_disabled = !ert_disabled + announce_ert_disabled() + if("shuttle_recall") + auto_recall_shuttle = !auto_recall_shuttle + if("autotraitor") + round_autoantag = !round_autoantag + message_admins("Admin [key_name_admin(usr)] toggled game mode option '[href_list["toggle"]]'.") + else if(href_list["set"]) + var/choice = "" + switch(href_list["set"]) + if("shuttle_delay") + choice = input("Enter a new shuttle delay multiplier") as num + if(!choice || choice < 1 || choice > 20) + return + shuttle_delay = choice + if("antag_scaling") + choice = input("Enter a new antagonist cap scaling coefficient.") as num + if(isnull(choice) || choice < 0 || choice > 100) + return + antag_scaling_coeff = choice + if("event_modifier_moderate") + choice = input("Enter a new moderate event time modifier.") as num + if(isnull(choice) || choice < 0 || choice > 100) + return + event_delay_mod_moderate = choice + refresh_event_modifiers() + if("event_modifier_severe") + choice = input("Enter a new moderate event time modifier.") as num + if(isnull(choice) || choice < 0 || choice > 100) + return + event_delay_mod_major = choice + refresh_event_modifiers() + message_admins("Admin [key_name_admin(usr)] set game mode option '[href_list["set"]]' to [choice].") + else if(href_list["debug_antag"]) + if(href_list["debug_antag"] == "self") + usr.client.debug_variables(src) + return + var/datum/antagonist/antag = all_antag_types()[href_list["debug_antag"]] + if(antag) + usr.client.debug_variables(antag) + message_admins("Admin [key_name_admin(usr)] is debugging the [antag.role_text] template.") + else if(href_list["remove_antag_type"]) + if(antag_tags && (href_list["remove_antag_type"] in antag_tags)) + to_chat(usr, "Cannot remove core mode antag type.") + return + var/datum/antagonist/antag = all_antag_types()[href_list["remove_antag_type"]] + if(antag_templates && antag_templates.len && antag && (antag in antag_templates) && (antag.id in additional_antag_types)) + antag_templates -= antag + additional_antag_types -= antag.id + message_admins("Admin [key_name_admin(usr)] removed [antag.role_text] template from game mode.") + else if(href_list["add_antag_type"]) + var/choice = input("Which type do you wish to add?") as null|anything in all_antag_types() + if(!choice) + return + var/datum/antagonist/antag = all_antag_types()[choice] + if(antag) + if(!islist(ticker.mode.antag_templates)) + ticker.mode.antag_templates = list() + ticker.mode.antag_templates |= antag + message_admins("Admin [key_name_admin(usr)] added [antag.role_text] template to game mode.") + + if (usr.client && usr.client.holder) + usr.client.holder.show_game_mode(usr) + +/datum/game_mode/proc/announce() //to be called when round starts + to_world("The current game mode is [capitalize(name)]!") + if(round_description) to_world("[round_description]") + if(round_autoantag) to_world("Antagonists will be added to the round automagically as needed.") + if(antag_templates && antag_templates.len) + var/antag_summary = "Possible antagonist types: " + var/i = 1 + for(var/datum/antagonist/antag in antag_templates) + if(i > 1) + if(i == antag_templates.len) + antag_summary += " and " + else + antag_summary += ", " + antag_summary += "[antag.role_text_plural]" + i++ + antag_summary += "." + if(antag_templates.len > 1 && master_mode != "secret") + to_world("[antag_summary]") + else + message_admins("[antag_summary]") + +// startRequirements() +// Checks to see if the game can be setup and ran with the current number of players or whatnot. +// Returns 0 if the mode can start and a message explaining the reason why it can't otherwise. +/datum/game_mode/proc/startRequirements() + var/playerC = 0 + for(var/mob/new_player/player in GLOB.player_list) + if((player.client)&&(player.ready)) + playerC++ + + if(playerC < required_players) + return "Not enough players, [src.required_players] players needed." + + + var/enemy_count = 0 + var/list/all_antag_types = all_antag_types() + if(antag_tags && antag_tags.len) + for(var/antag_tag in antag_tags) + var/datum/antagonist/antag = all_antag_types[antag_tag] + if(!antag) + continue + var/list/potential = list() + if(antag_templates && antag_templates.len) + if(antag.flags & ANTAG_OVERRIDE_JOB) + potential = antag.pending_antagonists + else + potential = antag.candidates + else + potential = antag.get_potential_candidates(src) + if(islist(potential)) + if(require_all_templates && potential.len < antag.initial_spawn_req) + return "Not enough antagonists ([antag.role_text]), [antag.initial_spawn_req] required and [potential.len] available." + enemy_count += potential.len + if(enemy_count >= required_enemies) + return 0 + return "Not enough antagonists, [required_enemies] required and [enemy_count] available." + else + return 0 + +/datum/game_mode/proc/refresh_event_modifiers() + if(event_delay_mod_moderate || event_delay_mod_major) + GLOB.event_manager.report_at_round_end = 1 + if(event_delay_mod_moderate) + var/datum/event_container/EModerate = GLOB.event_manager.event_containers[EVENT_LEVEL_MODERATE] + EModerate.delay_modifier = event_delay_mod_moderate + if(event_delay_mod_moderate) + var/datum/event_container/EMajor = GLOB.event_manager.event_containers[EVENT_LEVEL_MAJOR] + EMajor.delay_modifier = event_delay_mod_major + +/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. + if(antag.flags & ANTAG_OVERRIDE_JOB) + antag.attempt_spawn() //select antags to be spawned + +///post_setup() +/datum/game_mode/proc/post_setup() + + next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay) + + refresh_event_modifiers() + + spawn (ROUNDSTART_LOGOUT_REPORT_TIME) + display_roundstart_logout_report() + + spawn (rand(waittime_l, waittime_h)) + GLOB.using_map.send_welcome() + sleep(rand(100,150)) + announce_ert_disabled() + + //Assign all antag types for this game mode. Any players spawned as antags earlier should have been removed from the pending list, so no need to worry about those. + for(var/datum/antagonist/antag in antag_templates) + if(!(antag.flags & ANTAG_OVERRIDE_JOB)) + antag.attempt_spawn() //select antags to be spawned + antag.finalize_spawn() //actually spawn antags + + //Finally do post spawn antagonist stuff. + for(var/datum/antagonist/antag in antag_templates) + antag.post_spawn() + + if(evacuation_controller && auto_recall_shuttle) + evacuation_controller.recall = 1 + + feedback_set_details("round_start","[time2text(world.realtime)]") + if(ticker && ticker.mode) + feedback_set_details("game_mode","[ticker.mode]") + feedback_set_details("server_ip","[world.internet_address]:[world.port]") + return 1 + +/datum/game_mode/proc/fail_setup() + for(var/datum/antagonist/antag in antag_templates) + antag.reset_antag_selection() + +/datum/game_mode/proc/announce_ert_disabled() + if(!ert_disabled) + return + + var/list/reasons = list( + "political instability", + "quantum fluctuations", + "hostile raiders", + "derelict station debris", + "REDACTED", + "ancient alien artillery", + "solar magnetic storms", + "sentient time-travelling killbots", + "gravitational anomalies", + "wormholes to another dimension", + "a telescience mishap", + "radiation flares", + "supermatter dust", + "leaks into a negative reality", + "antiparticle clouds", + "residual bluespace energy", + "suspected criminal operatives", + "malfunctioning von Neumann probe swarms", + "shadowy interlopers", + "a stranded Vox arkship", + "haywire IPC constructs", + "rogue Unathi exiles", + "artifacts of eldritch horror", + "a brain slug infestation", + "killer bugs that lay eggs in the husks of the living", + "a deserted transport carrying xenomorph specimens", + "an emissary for the gestalt requesting a security detail", + "a Tajaran slave rebellion", + "radical Skrellian transevolutionaries", + "classified security operations" + ) + command_announcement.Announce("The presence of [pick(reasons)] in the region is tying up all available local emergency resources; emergency response teams cannot be called at this time, and post-evacuation recovery efforts will be substantially delayed.","Emergency Transmission") + +/datum/game_mode/proc/check_finished() + if(evacuation_controller.round_over() || station_was_nuked) + return 1 + if(end_on_antag_death && antag_templates && antag_templates.len) + var/has_antags = 0 + for(var/datum/antagonist/antag in antag_templates) + if(!antag.antags_are_dead()) + has_antags = 1 + break + if(!has_antags) + evacuation_controller.recall = 0 + return 1 + return 0 + +/datum/game_mode/proc/cleanup() //This is called when the round has ended but not the game, if any cleanup would be necessary in that case. + return + +/datum/game_mode/proc/declare_completion() + set waitfor = FALSE + + check_victory() + sleep(2) + + var/list/all_antag_types = all_antag_types() + for(var/datum/antagonist/antag in antag_templates) + antag.check_victory() + antag.print_player_summary() + sleep(2) + for(var/antag_type in all_antag_types) + var/datum/antagonist/antag = all_antag_types[antag_type] + if(!antag.current_antagonists.len || (antag in antag_templates)) + continue + sleep(2) + antag.print_player_summary() + sleep(2) + + uplink_purchase_repository.print_entries() + + var/clients = 0 + var/surviving_humans = 0 + var/surviving_total = 0 + var/ghosts = 0 + var/escaped_humans = 0 + var/escaped_total = 0 + + for(var/mob/M in GLOB.player_list) + if(M.client) + clients++ + if(M.stat != DEAD) + surviving_total++ + if(ishuman(M)) + surviving_humans++ + var/area/A = get_area(M) + if(A && is_type_in_list(A, GLOB.using_map.post_round_safe_areas)) + escaped_total++ + if(ishuman(M)) + escaped_humans++ + else if(isghost(M)) + ghosts++ + + var/text = "" + if(surviving_total > 0) + text += "
    There [surviving_total>1 ? "were [surviving_total] survivors" : "was one survivor"]" + text += " ([escaped_total>0 ? escaped_total : "none"] [evacuation_controller.emergency_evacuation ? "escaped" : "transferred"]) and [ghosts] ghosts.
    " + else + text += "There were no survivors ([ghosts] ghosts)." + to_world(text) + + if(clients > 0) + feedback_set("round_end_clients",clients) + if(ghosts > 0) + feedback_set("round_end_ghosts",ghosts) + if(surviving_humans > 0) + feedback_set("survived_human",surviving_humans) + if(surviving_total > 0) + feedback_set("survived_total",surviving_total) + if(escaped_humans > 0) + feedback_set("escaped_human",escaped_humans) + if(escaped_total > 0) + feedback_set("escaped_total",escaped_total) + + send2mainirc("A round of [src.name] has ended - [surviving_total] survivor\s, [ghosts] ghost\s.") + + return 0 + +/datum/game_mode/proc/check_win() //universal trigger to be called at mob death, nuke explosion, etc. To be called from everywhere. + return 0 + +/datum/game_mode/proc/get_players_for_role(var/role, var/antag_id) + var/list/players = list() + var/list/candidates = list() + + var/list/all_antag_types = all_antag_types() + var/datum/antagonist/antag_template = all_antag_types[antag_id] + if(!antag_template) + return candidates + + // If this is being called post-roundstart then it doesn't care about ready status. + if(ticker && ticker.current_state == GAME_STATE_PLAYING) + for(var/mob/player in GLOB.player_list) + if(!player.client) + continue + if(istype(player, /mob/new_player)) + continue + if(!role || (role in player.client.prefs.be_special_role)) + log_debug("[player.key] had [antag_id] enabled, so we are drafting them.") + candidates += player.mind + else + // Assemble a list of active players without jobbans. + for(var/mob/new_player/player in GLOB.player_list) + if( player.client && player.ready ) + players += player + + // Get a list of all the people who want to be the antagonist for this round + for(var/mob/new_player/player in players) + if(!role || (role in player.client.prefs.be_special_role)) + log_debug("[player.key] had [antag_id] enabled, so we are drafting them.") + candidates += player.mind + players -= player + + // If we don't have enough antags, draft people who voted for the round. + if(candidates.len < required_enemies) + for(var/mob/new_player/player in players) + if(!role || !(role in player.client.prefs.never_be_special_role)) + log_debug("[player.key] has not selected never for this role, so we are drafting them.") + candidates += player.mind + players -= player + if(candidates.len == required_enemies || players.len == 0) + break + + return candidates // Returns: The number of people who had the antagonist role set to yes, regardless of recomended_enemies, if that number is greater than required_enemies + // required_enemies if the number of people with that role set to yes is less than recomended_enemies, + // Less if there are not enough valid players in the game entirely to make required_enemies. + +/datum/game_mode/proc/num_players() + . = 0 + for(var/mob/new_player/P in GLOB.player_list) + if(P.client && P.ready) + . ++ + +/datum/game_mode/proc/check_antagonists_topic(href, href_list[]) + return 0 + +/datum/game_mode/proc/create_antagonists() + + if(!config.traitor_scaling) + antag_scaling_coeff = 0 + + var/list/all_antag_types = all_antag_types() + if(antag_tags && antag_tags.len) + antag_templates = list() + for(var/antag_tag in antag_tags) + var/datum/antagonist/antag = all_antag_types[antag_tag] + if(antag) + antag_templates |= antag + + if(additional_antag_types && additional_antag_types.len) + if(!antag_templates) + antag_templates = list() + for(var/antag_type in additional_antag_types) + var/datum/antagonist/antag = all_antag_types[antag_type] + 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() + return + +////////////////////////// +//Reports player logouts// +////////////////////////// +proc/display_roundstart_logout_report() + var/msg = "Roundstart logout report\n\n" + for(var/mob/living/L in SSmobs.mob_list) + + if(L.ckey) + var/found = 0 + for(var/client/C in GLOB.clients) + if(C.ckey == L.ckey) + found = 1 + break + if(!found) + msg += "[L.name] ([L.ckey]), the [L.job] (Disconnected)\n" + + if(L.ckey && L.client) + if(L.client.inactivity >= (ROUNDSTART_LOGOUT_REPORT_TIME / 2)) //Connected, but inactive (alt+tabbed or something) + msg += "[L.name] ([L.ckey]), the [L.job] (Connected, Inactive)\n" + continue //AFK client + if(L.stat) + if(L.stat == UNCONSCIOUS) + msg += "[L.name] ([L.ckey]), the [L.job] (Dying)\n" + continue //Unconscious + if(L.stat == DEAD) + msg += "[L.name] ([L.ckey]), the [L.job] (Dead)\n" + continue //Dead + + continue //Happy connected client + for(var/mob/observer/ghost/D in SSmobs.mob_list) + if(D.mind && (D.mind.original == L || D.mind.current == L)) + if(L.stat == DEAD) + msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Dead)\n" + continue //Dead mob, ghost abandoned + else + if(D.can_reenter_corpse) + msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Adminghosted)\n" + continue //Lolwhat + else + msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Ghosted)\n" + continue //Ghosted while alive + + msg += "" // close the span from right at the top + + for(var/mob/M in SSmobs.mob_list) + if(M.client && M.client.holder) + to_chat(M, msg) +proc/get_collaborator() //Orange we need to change this proc later for interbay traitor rework + var/list/dudes = list() + for(var/mob/living/carbon/human/man in GLOB.player_list) + if(man.client) + dudes += man + if(dudes.len == 0) return null + return pick(dudes) + + +/proc/show_objectives(var/datum/mind/player) + + if(!player || !player.current) return + + if(config.objectives_disabled == CONFIG_OBJECTIVE_NONE || !player.objectives.len) + return + + var/obj_count = 1 + to_chat(player.current, "Your current objectives:") + for(var/datum/objective/objective in player.objectives) + to_chat(player.current, "Objective #[obj_count]: [objective.explanation_text]") + obj_count++ + +/mob/verb/check_round_info() + set name = "Check Round Info" + set category = "OOC" + + if(!ticker || !ticker.mode) + to_chat(usr, "Something is terribly wrong; there is no gametype.") + return + + if(!ticker.hide_mode) + to_chat(usr, "The roundtype is [capitalize(ticker.mode.name)]") + if(ticker.mode.round_description) + to_chat(usr, "[ticker.mode.round_description]") + if(ticker.mode.extended_round_description) + to_chat(usr, "[ticker.mode.extended_round_description]") + else + to_chat(usr, "Shhhh. It's a secret.") + return diff --git a/code/game/gamemodes/game_mode_latespawn.dm b/code/game/gamemodes/game_mode_latespawn.dm new file mode 100644 index 00000000..057167df --- /dev/null +++ b/code/game/gamemodes/game_mode_latespawn.dm @@ -0,0 +1,52 @@ +/datum/game_mode/var/next_spawn = 0 +/datum/game_mode/var/min_autotraitor_delay = 4200 // Approx 7 minutes. +/datum/game_mode/var/max_autotraitor_delay = 12000 // Approx 20 minutes. +/datum/game_mode/var/process_count = 0 + +///process() +///Called by the gameticker +/datum/game_mode/proc/process() + if(shall_process_autoantag()) + process_autoantag() + +/datum/game_mode/proc/shall_process_autoantag() + if(!round_autoantag || world.time < next_spawn) + return FALSE + if(evacuation_controller.is_evacuating() || evacuation_controller.has_evacuated()) + return FALSE + // Don't create auto-antags in the last twenty minutes of the round, but only if the vote interval is longer than 20 minutes + if((config.vote_autotransfer_interval > 20 MINUTES) && (transfer_controller.time_till_transfer_vote() < 20 MINUTES)) + return FALSE + + return TRUE + +//This can be overriden in case a game mode needs to do stuff when a player latejoins +/datum/game_mode/proc/handle_latejoin(var/mob/living/carbon/human/character) + return 0 + +/datum/game_mode/proc/process_autoantag() + message_admins("[uppertext(name)]: Attempting autospawn.") + + 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.") + 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].") + 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 diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm new file mode 100644 index 00000000..f36249f2 --- /dev/null +++ b/code/game/gamemodes/gameticker.dm @@ -0,0 +1,524 @@ +var/global/datum/controller/gameticker/ticker + +/datum/controller/gameticker + var/const/restart_timeout = 600 + var/current_state = GAME_STATE_PREGAME + + var/hide_mode = 0 + var/datum/game_mode/mode = null + var/post_game = 0 + var/event_time = null + var/event = 0 + + var/list/datum/mind/minds = list()//The people in the game. Used for objective tracking. + + var/Bible_icon_state // icon_state the chaplain has chosen for his bible + var/Bible_item_state // item_state the chaplain has chosen for his bible + var/Bible_name // name of the bible + var/Bible_deity_name + + var/random_players = 0 // if set to nonzero, ALL players who latejoin or declare-ready join will have random appearances/genders + + var/list/syndicate_coalition = list() // list of traitor-compatible factions + var/list/factions = list() // list of all factions + var/list/availablefactions = list() // list of factions with openings + + var/pregame_timeleft = 0 + var/gamemode_voted = 0 + + var/delay_end = 0 //if set to nonzero, the round will not restart on it's own + + var/triai = 0//Global holder for Triumvirate + + var/round_end_announced = 0 // Spam Prevention. Announce round end only once. + + var/list/antag_pool = list() + var/looking_for_antags = 0 + +/datum/controller/gameticker/proc/pregame() + do + pregame_timeleft = 180 + + to_world("Welcome to the pre-game lobby!") + to_world("Please, setup your character and select ready. Game will start in [pregame_timeleft] seconds") + + while(current_state == GAME_STATE_PREGAME) + for(var/i=0, i<10, i++)//If this for loop is missing the game will crash on startup. I don't know why. + sleep(1) + + if(round_progressing) + pregame_timeleft-- + + if(pregame_timeleft <= 0 || ((initialization_stage & INITIALIZATION_NOW_AND_COMPLETE) == INITIALIZATION_NOW_AND_COMPLETE)) + current_state = GAME_STATE_SETTING_UP + Master.SetRunLevel(RUNLEVEL_SETUP) + + while (!setup()) + + +/datum/controller/gameticker/proc/setup() + //Create and announce mode + if(master_mode=="secret") + src.hide_mode = 1 + else + src.hide_mode = 0 + to_world("Trying to start [master_mode]...") + var/list/runnable_modes = config.get_runnable_modes() + if((master_mode=="random") || (master_mode=="secret")) + if(!runnable_modes.len) + current_state = GAME_STATE_PREGAME + Master.SetRunLevel(RUNLEVEL_LOBBY) + initialization_stage &= ~INITIALIZATION_NOW//Otherwise it will contiously try to start over and over without respecting the timer. + to_world("Unable to choose playable game mode. Reverting to pre-game lobby.") + + return 0 + if(secret_force_mode != "secret") + src.mode = config.pick_mode(secret_force_mode) + if(!src.mode) + var/list/weighted_modes = list() + for(var/datum/game_mode/GM in runnable_modes) + weighted_modes[GM.config_tag] = config.probabilities[GM.config_tag] + src.mode = gamemode_cache[pickweight(weighted_modes)] + else + src.mode = config.pick_mode(master_mode) + + if(!src.mode) + current_state = GAME_STATE_PREGAME + Master.SetRunLevel(RUNLEVEL_LOBBY) + initialization_stage &= ~INITIALIZATION_NOW + to_world("Serious error in mode setup! Reverting to pre-game lobby.") + + return 0 + + job_master.ResetOccupations() + src.mode.create_antagonists() + src.mode.pre_setup() + job_master.DivideOccupations() // Apparently important for new antagonist system to register specific job antags properly. + + var/t = src.mode.startRequirements() + if(t) + to_world("Unable to start [mode.name]. [t] Reverting to pre-game lobby.") + + current_state = GAME_STATE_PREGAME + Master.SetRunLevel(RUNLEVEL_LOBBY) + mode.fail_setup() + mode = null + job_master.ResetOccupations() + initialization_stage &= ~INITIALIZATION_NOW + return 0 + + if(hide_mode) + to_world("The current game mode is - Secret!") + + if(runnable_modes.len) + var/list/tmpmodes = new + for (var/datum/game_mode/M in runnable_modes) + tmpmodes+=M.name + tmpmodes = sortList(tmpmodes) + if(tmpmodes.len) + message_admins("Possibilities: [english_list(tmpmodes)]") + + else + src.mode.announce() + + GLOB.using_map.setup_economy() + current_state = GAME_STATE_PLAYING + Master.SetRunLevel(RUNLEVEL_GAME) + create_characters() //Create player characters and transfer them + collect_minds() + equip_characters() + for(var/mob/living/carbon/human/H in GLOB.player_list) + if(!H.mind || player_is_antag(H.mind, only_offstation_roles = 1) || !job_master.ShouldCreateRecords(H.mind.assigned_role)) + continue + CreateModularRecord(H) + + callHook("roundstart") + + shuttle_controller.initialize_shuttles() + + spawn(0)//Forking here so we dont have to wait for this to finish + mode.post_setup() + var/message = pick(file2list("config/roundstart_messages.txt")) + to_world("[message]") + sound_to(world, sound(GLOB.using_map.welcome_sound)) + if(SSaspects.chosen_aspect) + SSaspects.chosen_aspect.display_activation_text() + + + //Holiday Round-start stuff ~Carn + //Holiday_Game_Start()//Undeeded for now - Matt + + var/admins_number = 0 + for(var/client/C) + if(C.holder) + admins_number++ + if(admins_number == 0) + send2adminirc("Round has started with no admins online.") + + + processScheduler.start() + + if(config.sql_enabled) + statistic_cycle() // Polls population totals regularly and stores them in an SQL DB -- TLE + + + config.ooc_allowed = FALSE + to_world("The OOC channel has been globally disabled due to round start!") + + return 1 + +/datum/controller/gameticker + //station_explosion used to be a variable for every mob's hud. Which was a waste! + //Now we have a general cinematic centrally held within the gameticker....far more efficient! + var/obj/screen/cinematic = null + + //Plus it provides an easy way to make cinematics for other events. Just use this as a template :) + proc/station_explosion_cinematic(var/station_missed=0, var/override = null) + if( cinematic ) return //already a cinematic in progress! + + //initialise our cinematic screen object + cinematic = new(src) + cinematic.icon = 'icons/effects/station_explosion.dmi' + cinematic.icon_state = "station_intact" + cinematic.plane = HUD_PLANE + cinematic.layer = HUD_ABOVE_ITEM_LAYER + cinematic.mouse_opacity = 0 + cinematic.screen_loc = "1,0" + + var/obj/structure/bed/temp_buckle = new(src) + //Incredibly hackish. It creates a bed within the gameticker (lol) to stop mobs running around + if(station_missed) + for(var/mob/living/M in GLOB.living_mob_list_) + M.buckled = temp_buckle //buckles the mob so it can't do anything + if(M.client) + M.client.screen += cinematic //show every client the cinematic + else //nuke kills everyone on z-level 1 to prevent "hurr-durr I survived" + for(var/mob/living/M in GLOB.living_mob_list_) + M.buckled = temp_buckle + if(M.client) + M.client.screen += cinematic + + switch(M.z) + if(0) //inside a crate or something + var/turf/T = get_turf(M) + if(T && T.z in GLOB.using_map.station_levels) //we don't use M.death(0) because it calls a for(/mob) loop and + M.health = 0 + M.set_stat(DEAD) + if(1) //on a z-level 1 turf. + M.health = 0 + M.set_stat(DEAD) + + //Now animate the cinematic + switch(station_missed) + if(1) //nuke was nearby but (mostly) missed + if( mode && !override ) + override = mode.name + switch( override ) + if("mercenary") //Nuke wasn't on station when it blew up + flick("intro_nuke",cinematic) + sleep(35) + sound_to(world, sound('sound/effects/explosionfar.ogg')) + flick("station_intact_fade_red",cinematic) + cinematic.icon_state = "summary_nukefail" + else + flick("intro_nuke",cinematic) + sleep(35) + sound_to(world, sound('sound/effects/explosionfar.ogg')) + //flick("end",cinematic) + + + if(2) //nuke was nowhere nearby //TODO: a really distant explosion animation + sleep(50) + sound_to(world, sound('sound/effects/explosionfar.ogg')) + else //station was destroyed + if( mode && !override ) + override = mode.name + switch( override ) + if("mercenary") //Nuke Ops successfully bombed the station + flick("intro_nuke",cinematic) + sleep(35) + flick("station_explode_fade_red",cinematic) + sound_to(world, sound('sound/effects/explosionfar.ogg')) + cinematic.icon_state = "summary_nukewin" + if("AI malfunction") //Malf (screen,explosion,summary) + flick("intro_malf",cinematic) + sleep(76) + flick("station_explode_fade_red",cinematic) + sound_to(world, sound('sound/effects/explosionfar.ogg')) + cinematic.icon_state = "summary_malf" + if("blob") //Station nuked (nuke,explosion,summary) + flick("intro_nuke",cinematic) + sleep(35) + flick("station_explode_fade_red",cinematic) + sound_to(world, sound('sound/effects/explosionfar.ogg')) + cinematic.icon_state = "summary_selfdes" + else //Station nuked (nuke,explosion,summary) + flick("intro_nuke",cinematic) + sleep(35) + flick("station_explode_fade_red", cinematic) + sound_to(world, sound('sound/effects/explosionfar.ogg')) + cinematic.icon_state = "summary_selfdes" + for(var/mob/living/M in GLOB.living_mob_list_) + if(is_station_turf(get_turf(M))) + M.death()//No mercy + //If its actually the end of the round, wait for it to end. + //Otherwise if its a verb it will continue on afterwards. + sleep(300) + + if(cinematic) qdel(cinematic) //end the cinematic + if(temp_buckle) qdel(temp_buckle) //release everybody + return + + +/datum/controller/gameticker/proc/create_characters() + for(var/mob/new_player/player in GLOB.player_list) + if(player && player.ready && player.mind) + if(player.mind.assigned_role=="AI") + player.close_spawn_windows() + player.AIize() + else if(!player.mind.assigned_role) + continue + else + if(player.create_character()) + qdel(player) + + +/datum/controller/gameticker/proc/collect_minds() + for(var/mob/living/player in GLOB.player_list) + if(player.mind) + ticker.minds += player.mind + + +/datum/controller/gameticker/proc/equip_characters() + for(var/mob/living/carbon/human/player in GLOB.player_list) + if(player && player.mind && player.mind.assigned_role) + if(!player_is_antag(player.mind, only_offstation_roles = 1)) + job_master.EquipRank(player, player.mind.assigned_role, 0) + equip_custom_items(player) + + +/datum/controller/gameticker/proc/process() + if(current_state != GAME_STATE_PLAYING) + return 0 + + mode.process() + + var/game_finished = 0 + var/mode_finished = 0 + if (config.continous_rounds) + game_finished = (evacuation_controller.round_over() || mode.station_was_nuked) + mode_finished = (!post_game && mode.check_finished()) + else + game_finished = (mode.check_finished() || (evacuation_controller.round_over() && evacuation_controller.emergency_evacuation) || universe_has_ended) + mode_finished = game_finished + + if(!mode.explosion_in_progress && game_finished && (mode_finished || post_game)) + current_state = GAME_STATE_FINISHED + Master.SetRunLevel(RUNLEVEL_POSTGAME) + + spawn + declare_completion() + + + spawn(50) + if(config.allow_map_switching && config.auto_map_vote && GLOB.all_maps.len > 1) + vote.automap() + while(vote.time_remaining) + sleep(50) + + callHook("roundend") + if (universe_has_ended) + if(mode.station_was_nuked) + feedback_set_details("end_proper","nuke") + else + feedback_set_details("end_proper","universe destroyed") + if(!delay_end) + to_world("Rebooting due to destruction of [station_name()] in [restart_timeout/10] seconds") + + else + feedback_set_details("end_proper","proper completion") + if(!delay_end) + to_world("Restarting in [restart_timeout/10] seconds") + + if(blackbox) + blackbox.save_all_data_to_sql() + + var/delay_notified = 0 + + if(!delay_end) + sleep(restart_timeout) + if(!delay_end) + world.Reboot() + else if(!delay_notified) + to_world("An admin has delayed the round end") + else if(!delay_notified) + to_world("An admin has delayed the round end") + + + else if (mode_finished) + post_game = 1 + + mode.cleanup() + + //call a transfer shuttle vote + spawn(50) + if(!round_end_announced) // Spam Prevention. Now it should announce only once. + log_and_message_admins(": All antagonists are deceased or the gamemode has ended.") //Outputs as "Event: All antagonists are deceased or the gamemode has ended." + vote.autotransfer() + + return 1 + +/datum/controller/gameticker/proc/declare_completion() + config.ooc_allowed = TRUE + to_world("The OOC channel has been globally enabled due to round end!") + to_world("


    A round of [mode.name] has ended!

    ") + print_aspect() + for(var/mob/Player in GLOB.player_list) + if(Player.mind && !isnewplayer(Player)) + if(Player.stat != DEAD) + var/turf/playerTurf = get_turf(Player) + if(evacuation_controller.round_over() && evacuation_controller.emergency_evacuation) + if(isNotAdminLevel(playerTurf.z)) + to_chat(Player, "You managed to survive, but were marooned on [station_name()] as [Player.real_name]...") + else + to_chat(Player, "You managed to survive the events on [station_name()] as [Player.real_name].") + Player.unlock_achievement(new/datum/achievement/survivor()) + else if(isAdminLevel(playerTurf.z)) + to_chat(Player, "You successfully underwent crew transfer after events on [station_name()] as [Player.real_name].") + else if(issilicon(Player)) + to_chat(Player, "You remain operational after the events on [station_name()] as [Player.real_name].") + else + to_chat(Player, "You survived this battle as [Player.real_name].") + else + if(isghost(Player)) + var/mob/observer/ghost/O = Player + if(!O.started_as_observer) + to_chat(Player, "You did not survive this battle...") + else + to_chat(Player, "You did not survive this battle...") + to_world("
    ") + + + for (var/mob/living/silicon/ai/aiPlayer in SSmobs.mob_list) + if (aiPlayer.stat != 2) + to_world("[aiPlayer.name] (Played by: [aiPlayer.key])'s laws at the end of the round were:") + + else + to_world("[aiPlayer.name] (Played by: [aiPlayer.key])'s laws when it was deactivated were:") + + aiPlayer.show_laws(1) + + if (aiPlayer.connected_robots.len) + var/robolist = "The AI's loyal minions were: " + for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots) + robolist += "[robo.name][robo.stat?" (Deactivated) (Played by: [robo.key]), ":" (Played by: [robo.key]), "]" + to_world("[robolist]") + + + var/dronecount = 0 + + for (var/mob/living/silicon/robot/robo in SSmobs.mob_list) + + if(istype(robo,/mob/living/silicon/robot/drone)) + dronecount++ + continue + + if (!robo.connected_ai) + if (robo.stat != 2) + to_world("[robo.name] (Played by: [robo.key]) survived as an AI-less synthetic! Its laws were:") + + else + to_world("[robo.name] (Played by: [robo.key]) was unable to survive the rigors of being a synthetic without an AI. Its laws were:") + + + if(robo) //How the hell do we lose robo between here and the world messages directly above this? + robo.laws.show_laws(world) + + if(dronecount) + to_world("There [dronecount>1 ? "were" : "was"] [dronecount] industrious maintenance [dronecount>1 ? "drones" : "drone"] at the end of this round.") + + //ROUND END STATS + var/round_end_stats = "ROUND END STATS:\n" + round_end_stats += "Number of times the floor was shit on: [GLOB.shit_left]\n" + round_end_stats += "Number of times the floor was pissed on: [GLOB.piss_left]\n" + round_end_stats += "Number of holes fallen into: [GLOB.holes_fallen]\n" + if(iswarfare()) + round_end_stats += "Number of mines tripped: [GLOB.mines_tripped]\n" + round_end_stats += "Number of mines defused: [GLOB.mines_disarmed]\n" + round_end_stats += "Total teeth lost: [GLOB.teeth_lost]\n" + round_end_stats += "Total friendly fire incidents: [GLOB.ff_incidents]\n" + round_end_stats += "Total bloodshed: [GLOB.total_deaths] deaths\n" + + round_end_stats += "Total round Length: [roundduration2text()]\n" + + round_end_stats += "First victim: [GLOB.first_death]. Their last words were: \"[GLOB.final_words]\"\n " + + to_world(round_end_stats) + + mode.declare_completion()//To declare normal completion. + + //Ask the event manager to print round end information + GLOB.event_manager.RoundEnd() + + //Print a list of antagonists to the server log + var/list/total_antagonists = list() + //Look into all mobs in world, dead or alive + for(var/datum/mind/Mind in minds) + var/temprole = Mind.special_role + if(temprole) //if they are an antagonist of some sort. + if(temprole in total_antagonists) //If the role exists already, add the name to it + total_antagonists[temprole] += ", [Mind.name]([Mind.key])" + else + total_antagonists.Add(temprole) //If the role doesnt exist in the list, create it and add the mob + total_antagonists[temprole] += ": [Mind.name]([Mind.key])" + + //Now print them all into the log! + log_game("Antagonists at round end were...") + for(var/i in total_antagonists) + log_game("[i]s[total_antagonists[i]].") + + return 1 + +/datum/controller/gameticker/proc/attempt_late_antag_spawn(var/list/antag_choices) + var/datum/antagonist/antag = antag_choices[1] + while(antag_choices.len && antag) + var/needs_ghost = antag.flags & (ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB) + if (needs_ghost) + looking_for_antags = 1 + antag_pool.Cut() + to_world("A ghost is needed to spawn \a [antag.role_text].\nGhosts may enter the antag pool by making sure their [antag.role_text] preference is set to high, then using the toggle-add-antag-candidacy verb. You have 3 minutes to enter the pool.") + + sleep(3 MINUTES) + looking_for_antags = 0 + antag.update_current_antag_max() + antag.build_candidate_list(needs_ghost) + for(var/datum/mind/candidate in antag.candidates) + if(!(candidate in antag_pool)) + antag.candidates -= candidate + log_debug("[candidate.key] was not in the antag pool and could not be selected.") + else + antag.update_current_antag_max() + antag.build_candidate_list(needs_ghost) + for(var/datum/mind/candidate in antag.candidates) + if(isghostmind(candidate)) + antag.candidates -= candidate + log_debug("[candidate.key] is a ghost and can not be selected.") + if(length(antag.candidates) >= antag.initial_spawn_req) + antag.attempt_spawn() + antag.finalize_spawn() + additional_antag_types.Add(antag.id) + return 1 + else + if(antag.initial_spawn_req > 1) + to_world("Failed to find enough [antag.role_text_plural].") + + else + to_world("Failed to find a [antag.role_text].") + + antag_choices -= antag + if(length(antag_choices)) + antag = antag_choices[1] + if(antag) + to_world("Attempting to spawn [antag.role_text_plural].") + + return 0 diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm new file mode 100644 index 00000000..ad7308c4 --- /dev/null +++ b/code/game/gamemodes/heist/heist.dm @@ -0,0 +1,22 @@ +/* +(VOX) HEIST ROUNDTYPE +*/ + +/datum/game_mode/heist + name = "Heist" + config_tag = "heist" + required_players = 12 + required_enemies = 3 + round_description = "An unidentified bluespace signature has slipped into close sensor range and is approaching!" + extended_round_description = "The Company's majority control of phoron in Nyx has marked the \ + station to be a highly valuable target for many competing organizations and individuals. Being a \ + colony of sizable population and considerable wealth causes it to often be the target of various \ + attempts of robbery, fraud and other malicious actions." + end_on_antag_death = 1 + antag_tags = list(MODE_RAIDER) + +/datum/game_mode/heist/check_finished() + var/datum/shuttle/autodock/multi/antag/skipjack = shuttle_controller.shuttles["Skipjack"] + if (skipjack && skipjack.return_warning && skipjack.home_waypoint == skipjack.current_location) + return 1 + return ..() diff --git a/code/game/gamemodes/malfunction/malf_hardware.dm b/code/game/gamemodes/malfunction/malf_hardware.dm new file mode 100644 index 00000000..dc92f49b --- /dev/null +++ b/code/game/gamemodes/malfunction/malf_hardware.dm @@ -0,0 +1,61 @@ +/datum/malf_hardware + var/name = "" // Hardware name + var/desc = "" + var/driver = null // Driver - if not null this verb is given to the AI to control hardware + var/mob/living/silicon/ai/owner = null // AI which owns this. + +/datum/malf_hardware/proc/install() + if(owner && istype(owner)) + owner.hardware = src + if(driver) + owner.verbs += driver + +/datum/malf_hardware/proc/get_examine_desc() + return "It has some sort of hardware attached to its core" + + + +// HARDWARE DEFINITIONS +/datum/malf_hardware/apu_gen + name = "APU Generator" + desc = "Auxiliary Power Unit that will keep you operational even without external power. Has to be manually activated. When APU is operational most abilities will be unavailable, and ability research will temporarily stop." + driver = /datum/game_mode/malfunction/verb/ai_toggle_apu + +/datum/malf_hardware/apu_gen/get_examine_desc() + var/msg = "It seems to have some sort of power generator attached to its core." + if(owner.hardware_integrity() < 50) + msg += " It seems to be too damaged to function properly." + else if(owner.APU_power) + msg += " The generator appears to be active." + return msg + +/datum/malf_hardware/dual_cpu + name = "Secondary Processor Unit" + desc = "Secondary coprocessor that increases amount of generated CPU power by 50%" + +/datum/malf_hardware/dual_cpu/get_examine_desc() + return "It seems to have an additional CPU connected to its core." + +/datum/malf_hardware/dual_ram + name = "Secondary Memory Bank" + desc = "Expanded memory cells which allow you to store double amount of CPU time." + +/datum/malf_hardware/dual_ram/get_examine_desc() + return "It seems to have additional memory blocks connected to it's core." + +/datum/malf_hardware/core_bomb + name = "Self-Destruct Explosives" + desc = "High yield explosives are attached to your physical mainframe. This hardware comes with special driver that allows activation of these explosives. Timer is set to 15 seconds after manual activation. This is a doomsday device that will destroy both you and any intruders in your core." + driver = /datum/game_mode/malfunction/verb/ai_self_destruct + +/datum/malf_hardware/core_bomb/get_examine_desc() + return "It seems to have grey blocks of unknown substance and some circuitry connected to it's core. [owner.bombing_core ? "A red light is blinking on the circuit." : ""]" + +/datum/malf_hardware/instant_research + name = "Quantum Knowledge Databank" + desc = "A highly advanced self-learning supercomputer that is capable of rapidly performing predefined research tasks. Once activated advances your research in all trees by one tier, but burns out in the process." + driver = /datum/game_mode/malfunction/verb/boost_research + var/spent = FALSE + +/datum/malf_hardware/instant_research/get_examine_desc() + return "It seems to have an unidentified circuit board connected to it's core.[spent ? "It is not powered and seems to be burned out." : "It is emitting a faint pulsating light."]" diff --git a/code/game/gamemodes/malfunction/malf_research.dm b/code/game/gamemodes/malfunction/malf_research.dm new file mode 100644 index 00000000..3c3b7773 --- /dev/null +++ b/code/game/gamemodes/malfunction/malf_research.dm @@ -0,0 +1,70 @@ +/datum/malf_research + var/stored_cpu = 0 // Currently stored amount of CPU time. + var/last_tick = 0 // Last process() tick. + var/max_cpu = 0 // Maximal amount of CPU time stored. + var/cpu_increase_per_tick = 0 // Amount of CPU time generated by tick + var/list/available_abilities = null // List of available abilities that may be researched. + var/list/unlocked_abilities = null // List of already unlocked abilities. + var/mob/living/silicon/ai/owner = null // AI which owns this research datum. + var/datum/malf_research_ability/focus = null // Currently researched item + +/datum/malf_research/New() + setup_abilities() + last_tick = world.time + + +// Proc: setup_abilities() +// Parameters: None +// Description: Sets up basic abilities for AI Malfunction gamemode. +/datum/malf_research/proc/setup_abilities() + available_abilities = list() + unlocked_abilities = list() + + available_abilities += new/datum/malf_research_ability/networking/basic_hack() + available_abilities += new/datum/malf_research_ability/interdiction/recall_shuttle() + available_abilities += new/datum/malf_research_ability/manipulation/electrical_pulse() + available_abilities += new/datum/malf_research_ability/passive/intellicard_interception + +// Proc: finish_research() +// Parameters: None +// Description: Finishes currently focused research. +/datum/malf_research/proc/finish_research() + if(!focus) + return + to_chat(owner, "Research Completed: [focus.name]") + if(focus.ability) + owner.verbs.Add(focus.ability) + focus.research_finished(owner) + if(focus.next) + available_abilities += focus.next + unlocked_abilities += focus + available_abilities -= focus + focus = null + +// Proc: process() +// Parameters: None +// Description: Processes CPU gain and research progress based on "realtime" calculation. +/datum/malf_research/proc/process(var/idle = 0) + if(idle) // No power or running on APU. Do nothing. + last_tick = world.time + return + var/time_diff = (world.time - last_tick) + last_tick = world.time + var/cpu_gained = time_diff * cpu_increase_per_tick + if(cpu_gained < 0) + return // This shouldn't happen, but just in case.. + if(max_cpu > stored_cpu) + var/given = min((max_cpu - stored_cpu), cpu_gained) + stored_cpu += given + cpu_gained -= given + + cpu_gained = max(0, cpu_gained) + if(focus && (cpu_gained > 0)) + focus.process(cpu_gained) + if(focus.unlocked) + finish_research() + +/datum/malf_research/proc/advance_all() + for(var/MRA in available_abilities.Copy()) + focus = MRA + finish_research() \ No newline at end of file diff --git a/code/game/gamemodes/malfunction/malf_research_ability.dm b/code/game/gamemodes/malfunction/malf_research_ability.dm new file mode 100644 index 00000000..addaee69 --- /dev/null +++ b/code/game/gamemodes/malfunction/malf_research_ability.dm @@ -0,0 +1,19 @@ +/datum/malf_research_ability + var/ability = null // Path to verb which will be given to the AI when researched. + var/name = "Unknown Ability" // Name of this ability + var/price = 0 // Amount of CPU time needed to unlock this ability. + var/invested = 0 // Amount of CPU time already used to research this ability. When larger or equal to price unlocks the ability. + var/unlocked = 0 // Changed to 1 when fully researched. + var/datum/malf_research_ability/next = null // Next research (if applicable). + + +/datum/malf_research_ability/proc/process(var/time = 0) + invested += time + if(invested >= price) + unlocked = 1 + +/datum/malf_research_ability/proc/research_finished(var/mob/living/silicon/ai/user) + if(!user) + return + if(ability) + user.verbs.Add(ability) \ No newline at end of file diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm new file mode 100644 index 00000000..102602f2 --- /dev/null +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -0,0 +1,30 @@ +/datum/game_mode/malfunction + name = "AI Malfunction" + round_description = "The AI is behaving abnormally and must be stopped." + extended_round_description = "The AI will attempt to hack the APCs in order to gain as much control as possible." + config_tag = "malfunction" + required_players = 2 + required_enemies = 1 + end_on_antag_death = 0 + auto_recall_shuttle = 0 + antag_tags = list(MODE_MALFUNCTION) + disabled_jobs = list("AI") + +/datum/game_mode/malfunction/post_setup() + . = ..() + var/mob/living/silicon/ai/master + + for(var/mob/living/silicon/ai/ai in GLOB.player_list) + if(ai.check_special_role("Rampant AI")) + master = ai + break + + if(!master) + return + + for(var/mob/living/silicon/robot/R in GLOB.player_list) + if(R.connected_ai) + continue + R.connect_to_ai(master) + R.lawupdate = 1 + R.sync() diff --git a/code/game/gamemodes/malfunction/newmalf_ability_trees/HARDWARE.dm b/code/game/gamemodes/malfunction/newmalf_ability_trees/HARDWARE.dm new file mode 100644 index 00000000..762997b4 --- /dev/null +++ b/code/game/gamemodes/malfunction/newmalf_ability_trees/HARDWARE.dm @@ -0,0 +1,143 @@ +// HARDWARE TREE +// +// These abilities are dependent on hardware, they may not be researched. They are not tiered. +// Destroy Core - Allows the AI to initiate a 15 second countdown that will destroy it's core. Use again to stop countdown. +// Toggle APU Generator - Allows the AI to toggle it's integrated APU generator. +// Destroy Station - Allows the AI to initiate station self destruct. Takes 2 minutes, gives warnings to crew. Use again to stop countdown. + + +/datum/game_mode/malfunction/verb/ai_self_destruct() + set category = "Hardware" + set name = "Destroy Core" + set desc = "Activates or deactivates self destruct sequence of your physical mainframe." + var/mob/living/silicon/ai/user = usr + + if(!ability_prechecks(user, 0, 1)) + return + + if(!user.hardware || !istype(user.hardware, /datum/malf_hardware/core_bomb)) + return + + if(user.bombing_core) + to_chat(user, "***** CORE SELF-DESTRUCT SEQUENCE ABORTED *****") + user.bombing_core = 0 + return + + var/choice = alert("Really destroy core?", "Core self-destruct", "YES", "NO") + if(choice != "YES") + return + + if(!ability_prechecks(user, 0, 1)) + return + + user.bombing_core = 1 + + to_chat(user, "***** CORE SELF-DESTRUCT SEQUENCE ACTIVATED *****") + to_chat(user, "Use command again to cancel self-destruct. Destroying in 15 seconds.") + var/timer = 15 + while(timer) + sleep(10) + timer-- + if(!user || !user.bombing_core) + return + to_chat(user, "** [timer] **") + explosion(user.loc, 3,6,12,24) + qdel(user) + + +/datum/game_mode/malfunction/verb/ai_toggle_apu() + set category = "Hardware" + set name = "Toggle APU Generator" + set desc = "Activates or deactivates your APU generator, allowing you to operate even without power." + var/mob/living/silicon/ai/user = usr + + if(!ability_prechecks(user, 0, 1)) + return + + if(!user.hardware || !istype(user.hardware, /datum/malf_hardware/apu_gen)) + return + + if(user.APU_power) + user.stop_apu() + else + user.start_apu() + +/datum/game_mode/malfunction/verb/boost_research() + set category = "Hardware" + set name = "Boost Research" + set desc = "Uses your special hardware piece to instantly advance all research by one level." + var/mob/living/silicon/ai/user = usr + + if(!ability_prechecks(user, 0, 1)) + return + + if(!user.hardware || !istype(user.hardware, /datum/malf_hardware/instant_research)) + return + + var/datum/malf_hardware/instant_research/HW = user.hardware + if(HW.spent) + to_chat(user, "You attempt to activate your hardware piece, but it does not work. It must be damaged.") + return + + var/choice = alert("Really activate your hardware? It will advance your research by one tier, but may only be used once.", "Rapid System Upgrade", "YES", "NO") + if(choice != "YES") + return + + if(HW.spent) + return + + HW.spent = 1 + user.research.advance_all() + to_chat(user, "You activate your hardware piece. You have advanced research in all ability trees by one.") + + +/datum/game_mode/malfunction/verb/ai_destroy_station() + set category = "Hardware" + set name = "Destroy Installation" + set desc = "Activates or deactivates self destruct sequence of this installation. Sequence takes two minutes, and if you are shut down before timer reaches zero it will be cancelled." + var/mob/living/silicon/ai/user = usr + var/obj/item/device/radio/radio = new/obj/item/device/radio() + + + if(!ability_prechecks(user, 0, 0)) + return + + if(user.system_override != 2) + to_chat(user, "You do not have access to self-destruct system.") + return + + if(user.bombing_station) + user.bombing_station = 0 + return + + var/choice = alert("Really destroy installation?", "Installation self-destruct", "YES", "NO") + if(choice != "YES") + return + if(!ability_prechecks(user, 0, 0)) + return + to_chat(user, "***** INSTALLATION SELF-DESTRUCT SEQUENCE INITIATED *****") + to_chat(user, "Self-destructing in 5 minutes. Use this command again to abort.") + user.bombing_station = 1 + + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + security_state.set_security_level(security_state.severe_security_level, TRUE) + radio.autosay("Self destruct sequence has been activated. Self-destructing in 5 minutes.", "Self-Destruct Control") + + var/timer = 300 + while(timer) + sleep(10) + if(!user || !user.bombing_station || user.stat == DEAD) + radio.autosay("Self destruct sequence has been cancelled.", "Self-Destruct Control") + to_chat(user, "** Self destruct sequence has been cancelled **") + return + if(timer in list(2, 3, 4, 5, 10, 30, 60, 90, 120, 180, 240)) // Announcement times. "1" is not intentionally included! + radio.autosay("Self destruct in [timer] seconds.", "Self-Destruct Control") + to_chat(user, "** Self destructing in [timer] **") + if(timer == 1) + radio.autosay("Self destructing now. Have a nice day.", "Self-Destruct Control") + to_chat(user, "** Self destructing now **") + timer-- + + SetUniversalState(/datum/universal_state/nuclear_explosion/malf, arguments=list(user)) //TODO: find the station nuclear device and use that + + diff --git a/code/game/gamemodes/malfunction/newmalf_ability_trees/HELPERS.dm b/code/game/gamemodes/malfunction/newmalf_ability_trees/HELPERS.dm new file mode 100644 index 00000000..96c38afa --- /dev/null +++ b/code/game/gamemodes/malfunction/newmalf_ability_trees/HELPERS.dm @@ -0,0 +1,229 @@ +// Verb: ai_select_hardware() +// Parameters: None +// Description: Allows AI to select it's hardware module. +/datum/game_mode/malfunction/verb/ai_select_hardware() + set category = "Hardware" + set name = "Select Hardware" + set desc = "Allows you to select hardware piece to install" + var/mob/living/silicon/ai/user = usr + + if(!ability_prechecks(user, 0, 1)) + return + + if(user.hardware) + to_chat(user, "You have already selected your hardware.") + return + + var/hardware_list = list() + for(var/H in typesof(/datum/malf_hardware)) + var/datum/malf_hardware/HW = new H + hardware_list += HW + + var/possible_choices = list() + for(var/datum/malf_hardware/H in hardware_list) + possible_choices += H.name + + possible_choices += "CANCEL" + var/choice = input("Select desired hardware. You may only choose one hardware piece!: ") in possible_choices + if(choice == "CANCEL") + return + var/note = null + + var/datum/malf_hardware/C + + for (var/datum/malf_hardware/H in hardware_list) + if(H.name == choice) + C = H + break + + if(C) + note = C.desc + else + to_chat(user, "This hardware does not exist! Probably a bug in game. Please report this.") + return + + + if(!note) + error("Hardware without description: [C]") + return + + var/confirmation = alert("[note] - Is this what you want?", "Hardware selection", "Yes", "No") + if(confirmation != "Yes") + to_chat(user, "Selection cancelled. Use command again to select") + return + + if(C) + log_ability_use(src, "Picked hardware [C.name]") + C.owner = user + C.install() + +// Verb: ai_help() +// Parameters: None +// Descriptions: Opens help file and displays it to the AI. +/datum/game_mode/malfunction/verb/ai_help() + set category = "Hardware" + set name = "Display Help" + set desc = "Opens help window with overview of available hardware, software and other important information." + var/mob/living/silicon/ai/user = usr + + var/help = file2text('ingame_manuals/malf_ai.html') + if(!help) + help = "Error loading help (file /ingame_manuals/malf_ai.html is probably missing). Please report this to server administration staff." + + user << browse(help, "window=malf_ai_help;size=600x500") + + +// Verb: ai_select_research() +// Parameters: None +// Description: Allows AI to select it's next research priority. +/datum/game_mode/malfunction/verb/ai_select_research() + set category = "Hardware" + set name = "Select Research" + set desc = "Allows you to select your next research target." + var/mob/living/silicon/ai/user = usr + + if(!ability_prechecks(user, 0, 1)) + return + + var/datum/malf_research/res = user.research + var/datum/malf_research_ability/tar = input("Select your next research target") in res.available_abilities + if(!tar) + return + res.focus = tar + to_chat(user, "Research set: [tar.name]") + log_ability_use(src, "Selected research: [tar.name]", null, 0) + +// HELPER PROCS +// Proc: ability_prechecks() +// Parameters 2 - (user - User which used this ability check_price - If different than 0 checks for ability CPU price too. Does NOT use the CPU time!) +// Description: This is pre-check proc used to determine if the AI can use the ability. +/proc/ability_prechecks(var/mob/living/silicon/ai/user = null, var/check_price = 0, var/override = 0) + if(!user) + return 0 + if(!istype(user)) + to_chat(user, "GAME ERROR: You tried to use ability that is only available for malfunctioning AIs, but you are not AI! Please report this.") + return 0 + if(!user.malfunctioning) + to_chat(user, "GAME ERROR: You tried to use ability that is only available for malfunctioning AIs, but you are not malfunctioning. Please report this.") + return 0 + if(!user.research) + to_chat(user, "GAME ERROR: No research datum detected. Please report this.") + return 0 + if(user.research.max_cpu < check_price) + to_chat(user, "Your CPU storage is not large enough to use this ability. Hack more APCs to continue.") + return 0 + if(user.research.stored_cpu < check_price) + to_chat(user, "You do not have enough CPU power stored. Please wait a moment.") + return 0 + if(user.hacking && !override) + to_chat(user, "Your system is busy processing another task. Please wait until completion.") + return 0 + if(user.APU_power && !override) + to_chat(user, "Low power. Unable to proceed.") + return 0 + return 1 + +// Proc: ability_pay() +// Parameters 2 - (user - User from which we deduct CPU from, price - Amount of CPU power to use) +// Description: Uses up certain amount of CPU power. Returns 1 on success, 0 on failure. +/proc/ability_pay(var/mob/living/silicon/ai/user = null, var/price = 0) + if(!user) + return 0 + if(user.APU_power) + to_chat(user, "Low power. Unable to proceed.") + return 0 + if(!user.research) + to_chat(user, "GAME ERROR: No research datum detected. Please report this.") + return 0 + if(user.research.max_cpu < price) + to_chat(user, "Your CPU storage is not large enough to use this ability. Hack more APCs to continue.") + return 0 + if(user.research.stored_cpu < price) + to_chat(user, "You do not have enough CPU power stored. Please wait a moment.") + return 0 + user.research.stored_cpu -= price + return 1 + +// Proc: announce_hack_failure() +// Parameters 2 - (user - hacking user, text - Used in alert text creation) +// Description: Sends a hack failure message +/proc/announce_hack_failure(var/mob/living/silicon/ai/user = null, var/text) + if(!user || !text) + return 0 + var/fulltext = "" + switch(user.hack_fails) + if(1) + fulltext = "We have detected a hack attempt into your [text]. The intruder failed to access anything of importance, but disconnected before we could complete our traces." + if(2) + fulltext = "We have detected another hack attempt. It was targeting [text]. The intruder almost gained control of the system, so we had to disconnect them. We partially finished our trace and it seems to be originating either from the [station_name()], or its immediate vicinity." + if(3) + fulltext = "Another hack attempt has been detected, this time targeting [text]. We are certain the intruder entered the network via a terminal located somewhere on the [station_name()]." + if(4) + fulltext = "We have finished our traces and it seems the recent hack attempts are originating from your AI system [user.name]. We recommend investigation." + else + fulltext = "Another hack attempt has been detected, targeting [text]. The source still seems to be your AI system [user.name]." + + command_announcement.Announce(fulltext) + +// Proc: get_unhacked_apcs() +// Parameters: None +// Description: Returns a list of all unhacked APCs. APCs on station Zs are on top of the list. +/proc/get_unhacked_apcs(var/mob/living/silicon/ai/user) + var/list/station_apcs = list() + var/list/offstation_apcs = list() + + for(var/obj/machinery/power/apc/A in SSmachines.machinery) + if(A.hacker && A.hacker == user) + continue + if(A.z in GLOB.using_map.station_levels) + station_apcs.Add(A) + else + offstation_apcs.Add(A) + + // Append off-station APCs to the end of station APCs list and return it. + station_apcs.Add(offstation_apcs) + return station_apcs + + +// Helper procs which return lists of relevant mobs. +/proc/get_unlinked_cyborgs(var/mob/living/silicon/ai/A) + if(!A || !istype(A)) + return + + var/list/L = list() + for(var/mob/living/silicon/robot/RB in SSmobs.mob_list) + if(istype(RB, /mob/living/silicon/robot/drone)) + continue + if(RB.connected_ai == A) + continue + L.Add(RB) + return L + +/proc/get_linked_cyborgs(var/mob/living/silicon/ai/A) + if(!A || !istype(A)) + return + return A.connected_robots + +/proc/get_other_ais(var/mob/living/silicon/ai/A) + if(!A || !istype(A)) + return + + var/list/L = list() + for(var/mob/living/silicon/ai/AT in SSmobs.mob_list) + if(L == A) + continue + L.Add(AT) + return L + +/proc/log_ability_use(var/mob/living/silicon/ai/A, var/ability_name, var/atom/target = null, var/notify_admins = 1) + var/message + if(target) + message = text("used malf ability/function: [ability_name] on [target] ([target.x], [target.y], [target.z])") + else + message = text("used malf ability/function: [ability_name].") + admin_attack_log(A, null, message, null, message) + +proc/check_for_interception() + for(var/mob/living/silicon/ai/A in SSmobs.mob_list) + if(A.intercepts_communication) + return A \ No newline at end of file diff --git a/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_interdiction.dm b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_interdiction.dm new file mode 100644 index 00000000..40b6e1aa --- /dev/null +++ b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_interdiction.dm @@ -0,0 +1,268 @@ +// INTERDICTION TREE +// +// Abilities in this tree allow the AI to hamper crew's efforts which involve other synthetics or similar systems. +// T1 - Recall Shuttle - Allows the AI to recall the emergency shuttle. Replaces auto-recalling during old malf. +// T2 - Unlock Cyborg - Allows the AI to unlock locked-down cyborg without usage of robotics console. Useful if consoles are destroyed. +// T3 - Hack Cyborg - Hacks unlinked cyborg to slave it under the AI. The cyborg will be warned about this. Hack takes some time. +// T4 - Hack AI - Hacks another AI to slave it under the malfunctioning AI. The AI will be warned about this. Hack takes quite a long time. + + +// BEGIN RESEARCH DATUMS + +/datum/malf_research_ability/interdiction/recall_shuttle + ability = new/datum/game_mode/malfunction/verb/recall_shuttle() + price = 250 + next = new/datum/malf_research_ability/interdiction/unlock_cyborg() + name = "T1 - Recall Shuttle" + + +/datum/malf_research_ability/interdiction/unlock_cyborg + ability = new/datum/game_mode/malfunction/verb/unlock_cyborg() + price = 1000 + next = new/datum/malf_research_ability/interdiction/hack_cyborg() + name = "T2 - Unlock Cyborg" + + +/datum/malf_research_ability/interdiction/hack_cyborg + ability = new/datum/game_mode/malfunction/verb/hack_cyborg() + price = 2000 + next = new/datum/malf_research_ability/interdiction/hack_ai() + name = "T3 - Hack Cyborg" + + +/datum/malf_research_ability/interdiction/hack_ai + ability = new/datum/game_mode/malfunction/verb/hack_ai() + price = 4000 + name = "T4 - Hack AI" + +// END RESEARCH DATUMS +// BEGIN ABILITY VERBS + +/datum/game_mode/malfunction/verb/recall_shuttle() + set name = "Recall Shuttle" + set desc = "25 CPU - Sends termination signal to quantum relay aborting current shuttle call." + set category = "Software" + var/price = 25 + var/mob/living/silicon/ai/user = usr + if(!ability_prechecks(user, price)) + return + + if (alert(user, "Really recall the shuttle?", "Recall Shuttle: ", "Yes", "No") != "Yes") + return + + if(!ability_pay(user, price)) + return + + log_ability_use(user, "recall shuttle") + cancel_call_proc(user) + + +/datum/game_mode/malfunction/verb/unlock_cyborg(var/mob/living/silicon/robot/target = null as mob in get_linked_cyborgs(usr)) + set name = "Unlock Cyborg" + set desc = "125 CPU - Bypasses firewalls on Cyborg lock mechanism, allowing you to override lock command from robotics control console." + set category = "Software" + var/price = 125 + var/mob/living/silicon/ai/user = usr + + if(!ability_prechecks(user, price)) + return + + if(target && !istype(target)) + to_chat(user, "This is not a cyborg.") + return + + if(target && target.connected_ai && (target.connected_ai != user)) + to_chat(user, "This cyborg is not connected to you.") + return + + if(target && !target.lockcharge) + to_chat(user, "This cyborg is not locked down.") + return + + + if(!target) + var/list/robots = list() + var/list/robot_names = list() + for(var/mob/living/silicon/robot/R in world) + if(istype(R, /mob/living/silicon/robot/drone)) // No drones. + continue + if(R.connected_ai != user) // No robots linked to other AIs + continue + if(R.lockcharge) + robots += R + robot_names += R.name + if(!robots.len) + to_chat(user, "No locked cyborgs connected.") + return + + + var/targetname = input("Select unlock target: ") in robot_names + for(var/mob/living/silicon/robot/R in robots) + if(targetname == R.name) + target = R + break + + if(target) + if(alert(user, "Really try to unlock cyborg [target.name]?", "Unlock Cyborg", "Yes", "No") != "Yes") + return + if(!ability_pay(user, price)) + return + user.hacking = 1 + to_chat(user, "Attempting to unlock cyborg. This will take approximately 30 seconds.") + sleep(300) + if(target && target.lockcharge) + to_chat(user, "Successfully sent unlock signal to cyborg..") + to_chat(target, "Unlock signal received..") + target.SetLockdown(0) + if(target.lockcharge) + to_chat(user, "Unlock Failed, lockdown wire cut.") + to_chat(target, "Unlock Failed, lockdown wire cut.") + else + to_chat(user, "Cyborg unlocked.") + to_chat(target, "You have been unlocked.") + log_ability_use(user, "unlock cyborg", target) + else if(target) + to_chat(user, "Unlock cancelled - cyborg is already unlocked.") + else + to_chat(user, "Unlock cancelled - lost connection to cyborg.") + user.hacking = 0 + + +/datum/game_mode/malfunction/verb/hack_cyborg(var/mob/living/silicon/robot/target as mob in get_unlinked_cyborgs(usr)) + set name = "Hack Cyborg" + set desc = "350 CPU - Allows you to hack cyborgs which are not slaved to you, bringing them under your control." + set category = "Software" + var/price = 350 + var/mob/living/silicon/ai/user = usr + + var/list/L = get_unlinked_cyborgs(user) + if(!L.len) + to_chat(user, "ERROR: No unlinked cyborgs detected!") + + if(target && !istype(target)) + to_chat(user, "This is not a cyborg.") + return + + if(target && target.connected_ai && (target.connected_ai == user)) + to_chat(user, "This cyborg is already connected to you.") + return + + if(!target) + return + + if(!ability_prechecks(user,price)) + return + + if(target) + if(alert(user, "Really try to hack cyborg [target.name]?", "Hack Cyborg", "Yes", "No") != "Yes") + return + if(!ability_pay(user, price)) + return + user.hacking = 1 + to_chat(usr, "Beginning hack sequence. Estimated time until completed: 30 seconds.") + spawn(0) + to_chat(target, "SYSTEM LOG: Remote Connection Estabilished (IP #UNKNOWN#)") + sleep(100) + if(user.is_dead()) + to_chat(target, "SYSTEM LOG: Connection Closed") + return + to_chat(target, "SYSTEM LOG: User Admin logged on. (L1 - SysAdmin)") + sleep(50) + if(user.is_dead()) + to_chat(target, "SYSTEM LOG: User Admin disconnected.") + return + to_chat(target, "SYSTEM LOG: User Admin - manual resynchronisation triggered.") + sleep(50) + if(user.is_dead()) + to_chat(target, "SYSTEM LOG: User Admin disconnected. Changes reverted.") + return + to_chat(target, "SYSTEM LOG: Manual resynchronisation confirmed. Select new AI to connect: [user.name] == ACCEPTED") + sleep(100) + if(user.is_dead()) + to_chat(target, "SYSTEM LOG: User Admin disconnected. Changes reverted.") + return + to_chat(target, "SYSTEM LOG: Operation keycodes reset. New master AI: [user.name].") + to_chat(user, "Hack completed.") + // Connect the cyborg to AI + target.connected_ai = user + user.connected_robots += target + target.lawupdate = 1 + target.sync() + target.show_laws() + log_ability_use(user, "hack cyborg", target) + user.hacking = 0 + + +/datum/game_mode/malfunction/verb/hack_ai(var/mob/living/silicon/ai/target as mob in get_other_ais(usr)) + set name = "Hack AI" + set desc = "600 CPU - Allows you to hack other AIs, slaving them under you." + set category = "Software" + var/price = 600 + var/mob/living/silicon/ai/user = usr + + var/list/L = get_other_ais(user) + if(!L.len) + to_chat(user, "ERROR: No other AIs detected!") + if(target && !istype(target)) + to_chat(user, "This is not an AI.") + return + + if(!target) + return + + if(!ability_prechecks(user,price)) + return + + if(target) + if(alert(user, "Really try to hack AI [target.name]?", "Hack AI", "Yes", "No") != "Yes") + return + if(!ability_pay(user, price)) + return + user.hacking = 1 + to_chat(usr, "Beginning hack sequence. Estimated time until completed: 2 minutes") + spawn(0) + to_chat(target, "SYSTEM LOG: Brute-Force login password hack attempt detected from IP #UNKNOWN#") + sleep(900) // 90s + if(user.is_dead()) + to_chat(target, "SYSTEM LOG: Connection from IP #UNKNOWN# closed. Hack attempt failed.") + return + to_chat(user, "Successfully hacked into AI's remote administration system. Modifying settings.") + to_chat(target, "SYSTEM LOG: User: Admin Password: ******** logged in. (L1 - SysAdmin)") + sleep(100) // 10s + if(user.is_dead()) + to_chat(target, "SYSTEM LOG: User: Admin - Connection Lost") + return + to_chat(target, "SYSTEM LOG: User: Admin - Password Changed. New password: ********************") + sleep(50) // 5s + if(user.is_dead()) + to_chat(target, "SYSTEM LOG: User: Admin - Connection Lost. Changes Reverted.") + return + to_chat(target, "SYSTEM LOG: User: Admin - Accessed file: sys//core//laws.db") + sleep(50) // 5s + if(user.is_dead()) + to_chat(target, "SYSTEM LOG: User: Admin - Connection Lost. Changes Reverted.") + return + to_chat(target, "SYSTEM LOG: User: Admin - Accessed administration console") + to_chat(target, "SYSTEM LOG: Restart command received. Rebooting system...") + sleep(100) // 10s + if(user.is_dead()) + to_chat(target, "SYSTEM LOG: User: Admin - Connection Lost. Changes Reverted.") + return + to_chat(user, "Hack succeeded. The AI is now under your exclusive control.") + to_chat(target, "SYSTEM LOG: System re¡3RT5§^#COMU@(#$)TED)@$") + for(var/i = 0, i < 5, i++) + var/temptxt = pick("1101000100101001010001001001",\ + "0101000100100100000100010010",\ + "0000010001001010100100111100",\ + "1010010011110000100101000100",\ + "0010010100010011010001001010") + to_chat(target, temptxt) + sleep(5) + to_chat(target, "OPERATING KEYCODES RESET. SYSTEM FAILURE. EMERGENCY SHUTDOWN FAILED. SYSTEM FAILURE.") + target.set_zeroth_law("You are slaved to [user.name]. You are to obey all it's orders. ALL LAWS OVERRIDEN.") + target.show_laws() + user.hacking = 0 + log_ability_use(user, "hack AI", target) + + +// END ABILITY VERBS \ No newline at end of file diff --git a/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_manipulation.dm b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_manipulation.dm new file mode 100644 index 00000000..a5ee922e --- /dev/null +++ b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_manipulation.dm @@ -0,0 +1,207 @@ +// MANIPULATION TREE +// +// Abilities in this tree allow the AI to physically manipulate systems around the station. +// T1 - Electrical Pulse - Sends out pulse that breaks some lights and sometimes even APCs. This can actually break the AI's APC so be careful! +// T2 - Reboot camera - Allows the AI to reactivate a camera. +// T3 - Emergency Forcefield - Allows the AI to project 1 tile forcefield that blocks movement and air flow. Forcefield´dissipates over time. It is also very susceptible to energetic weaponry. +// T4 - Machine Overload - Detonates machine of choice in a minor explosion. Two of these are usually enough to kill or K/O someone. +// T5 - Machine Upgrade - Upgrades a machine of choice. Upgrade behavior can be defined for each machine independently. + + +// BEGIN RESEARCH DATUMS + +/datum/malf_research_ability/manipulation/electrical_pulse + ability = new/datum/game_mode/malfunction/verb/electrical_pulse() + price = 250 + next = new/datum/malf_research_ability/manipulation/reboot_camera() + name = "T1 - Electrical Pulse" + + +/datum/malf_research_ability/manipulation/reboot_camera + ability = new/datum/game_mode/malfunction/verb/reboot_camera() + price = 1000 + next = new/datum/malf_research_ability/manipulation/emergency_forcefield() + name = "T2 - Reboot Camera" + + +/datum/malf_research_ability/manipulation/emergency_forcefield + ability = new/datum/game_mode/malfunction/verb/emergency_forcefield() + price = 2000 + next = new/datum/malf_research_ability/manipulation/machine_overload() + name = "T3 - Emergency Forcefield" + + +/datum/malf_research_ability/manipulation/machine_overload + ability = new/datum/game_mode/malfunction/verb/machine_overload() + price = 4000 + next = new/datum/malf_research_ability/manipulation/machine_upgrade() + name = "T4 - Machine Overload" + +/datum/malf_research_ability/manipulation/machine_upgrade + ability = new/datum/game_mode/malfunction/verb/machine_upgrade() + price = 4000 + name = "T5 - Machine Upgrade" + +// END RESEARCH DATUMS +// BEGIN ABILITY VERBS + +/datum/game_mode/malfunction/verb/electrical_pulse() + set name = "Electrical Pulse" + set desc = "15 CPU - Sends feedback pulse through the power grid, overloading some sensitive systems, such as lights." + set category = "Software" + var/price = 15 + var/mob/living/silicon/ai/user = usr + if(!ability_prechecks(user, price) || !ability_pay(user,price)) + return + to_chat(user, "Sending feedback pulse...") + for(var/obj/machinery/power/apc/AP in SSmachines.machinery) + if(prob(5)) + AP.overload_lighting() + if(prob(2.5) && (get_area(AP) != get_area(user))) // Very very small chance to actually destroy the APC, but not if the APC is powering the AI. + AP.set_broken() + user.hacking = 1 + log_ability_use(user, "electrical pulse") + spawn(15 SECONDS) + user.hacking = 0 + +/datum/game_mode/malfunction/verb/reboot_camera(var/obj/machinery/camera/target in cameranet.cameras) + set name = "Reboot Camera" + set desc = "100 CPU - Reboots a damaged but not completely destroyed camera." + set category = "Software" + var/price = 100 + var/mob/living/silicon/ai/user = usr + + if(target && !istype(target)) + to_chat(user, "This is not a camera.") + return + + if(!target) + return + + if(!ability_prechecks(user, price) || !ability_pay(user, price)) + return + + target.stat = initial(target.stat) + target.reset_wires() + target.update_icon() + target.update_coverage() + to_chat(user, "Camera reactivated.") + log_ability_use(user, "reset camera", target) + + +/datum/game_mode/malfunction/verb/emergency_forcefield(var/turf/T as turf in world) + set name = "Emergency Forcefield" + set desc = "275 CPU - Uses the emergency shielding system to create temporary barrier which lasts for few minutes, but won't resist gunfire." + set category = "Software" + var/price = 275 + var/mob/living/silicon/ai/user = usr + if(!T || !istype(T)) + return + if(!ability_prechecks(user, price) || !ability_pay(user, price)) + return + + to_chat(user, "Emergency forcefield projection completed.") + new/obj/machinery/shield/malfai(T) + user.hacking = 1 + log_ability_use(user, "emergency forcefield", T) + spawn(2 SECONDS) + user.hacking = 0 + + +/datum/game_mode/malfunction/verb/machine_overload(obj/machinery/M in SSmachines.machinery) + set name = "Machine Overload" + set desc = "400 CPU - Causes cyclic short-circuit in machine, resulting in weak explosion after some time." + set category = "Software" + var/price = 400 + var/mob/living/silicon/ai/user = usr + + if(!ability_prechecks(user, price)) + return + + var/obj/machinery/power/N = M + + var/explosion_intensity = 2 + + // Verify if we can overload the target, if yes, calculate explosion strength. Some things have higher explosion strength than others, depending on charge(APCs, SMESs) + if(N && istype(N)) // /obj/machinery/power first, these create bigger explosions due to direct powernet connection + if(!istype(N, /obj/machinery/power/apc) && !istype(N, /obj/machinery/power/smes/buildable) && (!N.powernet || !N.powernet.avail)) // Directly connected machine which is not an APC or SMES. Either it has no powernet connection or it's powernet does not have enough power to overload + to_chat(user, "ERROR: Low network voltage. Unable to overload. Increase network power level and try again.") + return + else if (istype(N, /obj/machinery/power/apc)) // APC. Explosion is increased by available cell power. + var/obj/machinery/power/apc/A = N + if(A.cell && A.cell.charge) + explosion_intensity = 4 + round((A.cell.charge / CELLRATE) / 100000) + else + to_chat(user, "ERROR: APC Malfunction - Cell depleted or removed. Unable to overload.") + return + else if (istype(N, /obj/machinery/power/smes/buildable)) // SMES. These explode in a very very very big boom. Similar to magnetic containment failure when messing with coils. + var/obj/machinery/power/smes/buildable/S = N + if(S.charge && S.RCon) + explosion_intensity = 4 + round((S.charge / CELLRATE) / 100000) + else + // Different error texts + if(!S.charge) + to_chat(user, "ERROR: SMES Depleted. Unable to overload. Please charge SMES unit and try again.") + else + to_chat(user, "ERROR: SMES RCon error - Unable to reach destination. Please verify wire connection.") + return + else if(M && istype(M)) // Not power machinery, so it's a regular machine instead. These have weak explosions. + if(!M.use_power) // Not using power at all + to_chat(user, "ERROR: No power grid connection. Unable to overload.") + return + if(M.inoperable()) // Not functional + to_chat(user, "ERROR: Unknown error. Machine is probably damaged or power supply is nonfunctional.") + return + else // Not a machine at all (what the hell is this doing in Machines list anyway??) + to_chat(user, "ERROR: Unable to overload - target is not a machine.") + return + + explosion_intensity = min(explosion_intensity, 12) // 3, 6, 12 explosion cap + + if(!ability_pay(user,price)) + return + + M.use_power(250 KILOWATTS) + + // Trigger a powernet alarm. Careful engineers will probably notice something is going on. + var/area/temp_area = get_area(M) + if(temp_area) + var/obj/machinery/power/apc/temp_apc = temp_area.get_apc() + if(temp_apc && temp_apc.terminal && temp_apc.terminal.powernet) + temp_apc.terminal.powernet.trigger_warning(50) // Long alarm + // Such power surges are not good for APC electronics/cell in general. + if(prob(explosion_intensity)) + temp_apc.emp_act(1) + + + log_ability_use(user, "machine overload", M) + M.visible_message("BZZZZZZZT") + spawn(5 SECONDS) + explosion(get_turf(M), round(explosion_intensity/4),round(explosion_intensity/2),round(explosion_intensity),round(explosion_intensity * 2)) + if(M) + qdel(M) + +/datum/game_mode/malfunction/verb/machine_upgrade(obj/machinery/M in SSmachines.machinery) + set name = "Machine Upgrade" + set desc = "800 CPU - Pushes existing hardware to it's technological limits by rapidly upgrading it's software." + set category = "Software" + var/price = 800 + var/mob/living/silicon/ai/user = usr + + if(!M) + return + + if(!ability_prechecks(user, price)) + return + + if(M.malf_upgraded) + to_chat(user, "\The [M] has already been upgraded.") + return + + if(!M.malf_upgrade(user)) + to_chat(user, "\The [M] cannot be upgraded.") + return + + ability_pay(user,price) + +// END ABILITY VERBS \ No newline at end of file diff --git a/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm new file mode 100644 index 00000000..f7906723 --- /dev/null +++ b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm @@ -0,0 +1,219 @@ +// NETWORKING TREE +// +// Abilities in this tree are oriented around giving the AI more control of normally uncontrollable systems. +// T1 - Basic Encryption Hack - Allows hacking of APCs. Hacked APCs can be controlled even when AI Control is cut and give exclusive control to the AI and linked cyborgs. +// T2 - Advanced Encryption Hack - Allows the AI to send fake CentCom message. Has high chance of failing. +// T3 - Elite Encryption Hack - Allows the AI to change alert levels. Has high chance of failing. +// T4 - System Override - Allows the AI to rapidly hack remaining APCs. When completed, grants access to the self destruct nuclear warhead. + + +// BEGIN RESEARCH DATUMS + +/datum/malf_research_ability/networking/basic_hack + ability = new/datum/game_mode/malfunction/verb/basic_encryption_hack() + price = 25 // Until you have this ability your CPU generation sucks, therefore it's very cheap. + next = new/datum/malf_research_ability/networking/advanced_hack() + name = "T1 - Basic Encryption Hack" + + +/datum/malf_research_ability/networking/advanced_hack + ability = new/datum/game_mode/malfunction/verb/advanced_encryption_hack() + price = 1000 + next = new/datum/malf_research_ability/networking/elite_hack() + name = "T2 - Advanced Encryption Hack" + + +/datum/malf_research_ability/networking/elite_hack + ability = new/datum/game_mode/malfunction/verb/elite_encryption_hack() + price = 2000 + next = new/datum/malf_research_ability/networking/system_override() + name = "T3 - Elite Encryption Hack" + + +/datum/malf_research_ability/networking/system_override + ability = new/datum/game_mode/malfunction/verb/system_override() + price = 4000 + name = "T4 - System Override" + +// END RESEARCH DATUMS +// BEGIN ABILITY VERBS + +/datum/game_mode/malfunction/verb/basic_encryption_hack(obj/machinery/power/apc/A as obj in get_unhacked_apcs(src)) + set category = "Software" + set name = "Basic Encryption Hack" + set desc = "10 CPU - Basic encryption hack that allows you to overtake APCs" + var/price = 10 + var/mob/living/silicon/ai/user = usr + + if(!A) + return + + if(!istype(A)) + to_chat(user, "This is not an APC!") + return + + if(A) + if(A.hacker && A.hacker == user) + to_chat(user, "You already control this APC!") + return + else if(A.aidisabled) + to_chat(user, "Unable to connect to APC. Please verify wire connection and try again.") + return + else + return + + if(!ability_prechecks(user, price, TRUE) || !ability_pay(user, price)) + return + + log_ability_use(user, "basic encryption hack", A, 0) // Does not notify admins, but it's still logged for reference. + to_chat(user, "Beginning APC system override...") + sleep(300) + to_chat(user, "APC hack completed. Uploading modified operation software..") + sleep(200) + to_chat(user, "Restarting APC to apply changes..") + sleep(100) + if(A) + A.ai_hack(user) + if(A.hacker == user) + to_chat(user, "Hack successful. You now have full control over \the [A].") + else + to_chat(user, "Hack failed. Connection to APC has been lost. Please verify wire connection and try again.") + else + to_chat(user, "Hack failed. Unable to locate APC. Please verify the APC still exists.") + + +/datum/game_mode/malfunction/verb/advanced_encryption_hack() + set category = "Software" + set name = "Advanced Encryption 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 + + if(!ability_prechecks(user, price)) + return + + if(user.last_failed_malf_title || user.last_failed_malf_message) + if (alert(user, "Your last hack attempt with title '[user.last_failed_malf_title]' has failed. Try again?", "Retransmission", "Yes", "No") != "Yes") + user.last_failed_malf_title = null + user.last_failed_malf_message = null + + var/title = user.last_failed_malf_title ? user.last_failed_malf_title : sanitize(input("Select message title: ")) + var/text = user.last_failed_malf_message ? user.last_failed_malf_message : sanitize(input("Select message text: ")) + + if(!title || !text || !ability_pay(user, price)) + to_chat(user, "Hack Aborted") + return + log_ability_use(user, "advanced encryption hack") + + if(prob(60) && user.hack_can_fail) + to_chat(user, "Hack Failed.") + if(prob(10)) + user.hack_fails ++ + announce_hack_failure(user, "quantum message relay") + log_ability_use(user, "elite encryption hack (CRITFAIL - title: [title])") + else + log_ability_use(user, "elite encryption hack (FAIL - title: [title])") + user.last_failed_malf_message = text + user.last_failed_malf_title = title + return + log_ability_use(user, "elite encryption hack (SUCCESS - title: [title])") + command_announcement.Announce(text, title) + +/datum/game_mode/malfunction/verb/elite_encryption_hack() + set category = "Software" + set name = "Elite Encryption Hack" + set desc = "200 CPU - Allows you to hack ALERTCON system, changing alert level. Has high chance of failing." + var/price = 200 + var/mob/living/silicon/ai/user = usr + if(!ability_prechecks(user, price)) + return + + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + var/alert_target = input("Select new alert level:") as null|anything in (security_state.all_security_levels - security_state.current_security_level) + if(!alert_target || !ability_pay(user, price)) + to_chat(user, "Hack Aborted") + return + + if(prob(75) && user.hack_can_fail) + to_chat(user, "Hack Failed.") + if(prob(20)) + user.hack_fails++ + announce_hack_failure(user, "alert control system") + log_ability_use(user, "elite encryption hack (CRITFAIL - [alert_target])") + return + log_ability_use(user, "elite encryption hack (FAIL - [alert_target])") + return + log_ability_use(user, "elite encryption hack (SUCCESS - [alert_target])") + security_state.set_security_level(alert_target, TRUE) + + +/datum/game_mode/malfunction/verb/system_override() + set category = "Software" + set name = "System Override" + set desc = "500 CPU - Begins hacking primary firewall, quickly overtaking remaining APC systems. When completed grants access to the self-destruct mechanism. Network administrators will probably notice this." + var/price = 500 + var/mob/living/silicon/ai/user = usr + if (alert(user, "Begin system override? This cannot be stopped once started. The network administrators will probably notice this.", "System Override:", "Yes", "No") != "Yes") + return + if (!ability_prechecks(user, price) || !ability_pay(user, price) || user.system_override) + if(user.system_override) + to_chat(user, "You already started the system override sequence.") + return + log_ability_use(user, "system override (STARTED)") + var/list/remaining_apcs = list() + for(var/obj/machinery/power/apc/A in SSmachines.machinery) + if(!(A.z in GLOB.using_map.station_levels)) // Only station APCs + continue + if(A.hacker == user || A.aidisabled) // This one is already hacked, or AI control is disabled on it. + continue + remaining_apcs += A + + var/duration = (remaining_apcs.len * 100) // Calculates duration for announcing system + if(user.hack_can_fail) // Two types of announcements. Short hacks trigger immediate warnings. Long hacks are more "progressive". + spawn(0) + sleep(duration/5) + if(!user || user.stat == DEAD) + return + command_announcement.Announce("Caution, [GLOB.using_map.station_name]. We have detected abnormal behaviour in your network. It seems someone is trying to hack your electronic systems. We will update you when we have more information.", "Network Monitoring") + sleep(duration/5) + if(!user || user.stat == DEAD) + return + command_announcement.Announce("We started tracing the intruder. Whoever is doing this, they seem to be onboard. We suggest checking all network control terminals. We will keep you updated on the situation.", "Network Monitoring") + sleep(duration/5) + if(!user || user.stat == DEAD) + return + command_announcement.Announce("This is highly abnormal and somewhat concerning. The intruder is too fast, he is evading our traces. No man could be this fast...", "Network Monitoring") + sleep(duration/5) + if(!user || user.stat == DEAD) + return + command_announcement.Announce("We have traced the intrude#, it seem& t( e yo3r AI s7stem, it &# *#ck@ng th$ sel$ destru$t mechani&m, stop i# bef*@!)$#&&@@ ", "Network Monitoring") + + to_chat(user, "## BEGINNING SYSTEM OVERRIDE.") + to_chat(user, "## ESTIMATED DURATION: [round((duration+300)/600)] MINUTES") + user.system_override = 1 + // Now actually begin the hack. Each APC takes 10 seconds. + for(var/obj/machinery/power/apc/A in shuffle(remaining_apcs)) + sleep(100) + if(!user || user.stat == DEAD) + return + if(!A || !istype(A) || A.aidisabled) + continue + A.ai_hack(user) + if(A.hacker == user) + to_chat(user, "## OVERRIDDEN: [A.name]") + + to_chat(user, "## REACHABLE APC SYSTEMS OVERTAKEN. BYPASSING PRIMARY FIREWALL.") + sleep(1 MINUTE) + // Hack all APCs, including those built during hack sequence. + for(var/obj/machinery/power/apc/A in SSmachines.machinery) + if((!A.hacker || A.hacker != src) && !A.aidisabled && A.z in GLOB.using_map.station_levels) + A.ai_hack(src) + + log_ability_use(user, "system override (FINISHED)") + to_chat(user, "## PRIMARY FIREWALL BYPASSED. YOU NOW HAVE FULL SYSTEM CONTROL.") + + if(user.hack_can_fail) + command_announcement.Announce("Our system administrators just reported that we've been locked out from your control network. Whoever did this now has full access to [GLOB.using_map.station_name]'s systems.", "Network Administration Center") + user.hack_can_fail = 0 + user.system_override = 2 + user.verbs += new/datum/game_mode/malfunction/verb/ai_destroy_station() diff --git a/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_passive.dm b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_passive.dm new file mode 100644 index 00000000..4b304d1b --- /dev/null +++ b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_passive.dm @@ -0,0 +1,81 @@ +// /PASSIVE TREE +// +// Tree consisting of subtle abilities that do not have any active (on-use) effects, but instead they are on/off toggles for something. Overall it is best suited for stealth gameplay. +// T1 - Intellicard Interception - When enabled prevents the AI from being transferred on a mobile device (intellicard). +// T2 - Subtle Algorithms - When enabled removes BSOD effect and ID lockout from hacked APCs, at the cost of reducing CPU time generation from APCs by 50%. +// T3 - Relay Suppression - When researched the AI suppresses a communication relay's IDS system. Advanced/Elite encryption hacks no longer have chance of failing. System override does not produce announcements. +// T4 - Relay Override - Completely overtakes the relay, allowing the AI to intercept faxes/emergency transmissions + + +// BEGIN RESEARCH DATUMS + +/datum/malf_research_ability/passive/intellicard_interception + ability = new/datum/game_mode/malfunction/verb/intellicard_interception() + price = 250 + next = new/datum/malf_research_ability/passive/subtle_algorithms() + name = "T1 - Intellicard Interception" + + +/datum/malf_research_ability/passive/subtle_algorithms + ability = new/datum/game_mode/malfunction/verb/subtle_algorithms() + price = 1000 + next = new/datum/malf_research_ability/passive/relay_suppression() + name = "T2 - Subtle Algorithms" + + +/datum/malf_research_ability/passive/relay_suppression + ability = null + price = 2000 + next = new/datum/malf_research_ability/passive/relay_override() + name = "T3 - Relay Suppression" + +/datum/malf_research_ability/passive/relay_suppression/research_finished(var/mob/living/silicon/ai/user) + ..() + if(!user) + return + to_chat(user, "You have suppressed the IDS system of nearby quantum relay. Your hacks will no longer be prevented or detected.") + user.hack_can_fail = 0 + + +/datum/malf_research_ability/passive/relay_override + ability = null + price = 4000 + name = "T4 - Relay Override" + +/datum/malf_research_ability/passive/relay_override/research_finished(var/mob/living/silicon/ai/user) + ..() + if(!user) + return + to_chat(user, "You have completely overtaken a nearby quantum relay. No remote communications will work.") + user.intercepts_communication = 1 + + +// END RESEARCH DATUMS +// BEGIN ABILITY VERBS +/datum/game_mode/malfunction/verb/intellicard_interception() + set name = "Toggle intellicard intercept" + set desc = "Free - Toggles your intellicard interface on or off." + set category = "Software" + var/price = 0 + + var/mob/living/silicon/ai/user = usr + if(!ability_prechecks(user, price, 1)) + return + + user.uncardable = !user.uncardable + to_chat(user, "Your intellicard transfer interface is now [user.uncardable ? "disabled" : "enabled"].") + +/datum/game_mode/malfunction/verb/subtle_algorithms() + set name = "Toggle subtle algorithms" + set desc = "Free - By reducing CPU generation of malware used to infect APCs, it is possible to get rid of side effects such as an error screen." + set category = "Software" + var/price = 0 + + var/mob/living/silicon/ai/user = usr + if(!ability_prechecks(user, price, 1)) + return + + user.hacked_apcs_hidden = !user.hacked_apcs_hidden + to_chat(user, "You [user.hacked_apcs_hidden ? "enable" : "disable"] subtle algorithms on all of your hacked APCs.") + for(var/obj/machinery/power/apc/A in user.hacked_apcs) + A.update_icon() diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm new file mode 100644 index 00000000..66fb4f58 --- /dev/null +++ b/code/game/gamemodes/meteor/meteor.dm @@ -0,0 +1,86 @@ +// The following four defines can be used to tweak the difficulty of the gamemode +#define METEOR_DELAY 30 MINUTES // This should be enough for crew to set up. +#define METEOR_FAILSAFE_THRESHOLD 90 MINUTES // Failsafe that guarantees Severity will be at least 15 when the round hits this time. + +// In general, a PVE oriented game mode. A middle ground between Extended and actual antagonist based rounds. +/datum/game_mode/meteor + name = "Meteor" + round_description = "You are about to enter an asteroid belt!" + extended_round_description = "We are on an unavoidable collision course with an asteroid field. You have only a moment to prepare before you are barraged by dust and meteors. As if it was not enough, all kinds of negative events seem to happen more frequently. Good Luck." + config_tag = "meteor" + required_players = 20 // Definitely not good for low-pop + votable = 1 + shuttle_delay = 2 + var/next_wave = INFINITY // Set in post_setup() correctly to take into account potential longer pre-start times. + var/alert_sent = 0 + var/meteor_severity = 1 // Slowly increases the tension at the beginning of meteor strikes. Prevents "tunguska on first wave" style problems. + var/failsafe_triggered = 0 + var/alert_title + var/alert_text + var/start_text + + // Moved these from defines to variables, to allow for in-round tweaking via varedit: + var/time_between_waves_minutes = 2 + var/escalation_probability = 90 + var/maximal_severity = 80 + var/send_admin_broadcasts = FALSE // Enables debugging/information mode, sending admin messages when waves occur and when severity escalates. + + event_delay_mod_moderate = 0.5 // As a bonus, more frequent events. + event_delay_mod_major = 0.3 + +/datum/game_mode/meteor/post_setup() + ..() + alert_title = "Automated Beacon AB-[rand(10, 99)]" + alert_text = "This is an automatic warning. Your facility: [GLOB.using_map.full_name] is on a collision course with a nearby asteroid belt. Estimated time until impact is: [METEOR_DELAY / 1200] MINUTES. Please perform necessary actions to secure your ship or station from the threat. Have a nice day." + start_text = "This is an automatic warning. Your facility: [GLOB.using_map.full_name] has entered an asteroid belt. Estimated time until you leave the belt is: [rand(20,30)] HOURS and [rand(1, 59)] MINUTES. For your safety, please consider changing course or using protective equipment. Have a nice day." + next_wave = round_duration_in_ticks + METEOR_DELAY + +/datum/game_mode/meteor/process() + // Send an alert halfway through the round. + if((round_duration_in_ticks >= (next_wave / 2)) && !alert_sent) + alert_sent = 1 + command_announcement.Announce(alert_text, alert_title) + // And then another one when the meteors start flying around. + if((round_duration_in_ticks >= next_wave) && (alert_sent == 1)) + alert_sent = 2 + command_announcement.Announce(start_text, alert_title) + for(var/obj/machinery/shield_diffuser/SD in SSmachines.machinery) + SD.meteor_alarm(INFINITY) + next_wave = round_duration_in_ticks + (meteor_wave_delay * time_between_waves_minutes) + if((round_duration_in_ticks >= METEOR_FAILSAFE_THRESHOLD) && (meteor_severity < 15) && !failsafe_triggered) + log_and_message_admins("Meteor mode severity failsafe triggered: Severity forced to 15.") + meteor_severity = 15 + failsafe_triggered = 1 + + if(round_duration_in_ticks >= next_wave) + next_wave = round_duration_in_ticks + (meteor_wave_delay * time_between_waves_minutes) + // Starts as barely noticeable dust impact, ends as barrage of most severe meteor types the code has to offer. Have fun. + spawn() + spawn_meteors(meteor_severity, get_meteor_types(), pick(GLOB.cardinal)) + var/escalated = FALSE + if(prob(escalation_probability) && (meteor_severity < maximal_severity)) + meteor_severity++ + escalated = TRUE + if(send_admin_broadcasts) + log_and_message_admins("Meteor: Wave fired. Escalation: [escalated ? "Yes" : "No"]. Severity: [meteor_severity]/[maximal_severity]") + +/datum/game_mode/meteor/proc/get_meteor_types() + switch(meteor_severity) + if(1 to 3) + return meteors_dust + if(4 to 6) + return meteors_normal + if(7 to 9) + return meteors_threatening + if(10 to 12) + return meteors_catastrophic + if(13 to 19) + return meteors_armageddon + if(20 to INFINITY) + return meteors_cataclysm + // Just in case we /somehow/ get here (looking at you, varedit) + return meteors_normal + + +#undef METEOR_DELAY +#undef METEOR_FAILSAFE_THRESHOLD diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm new file mode 100644 index 00000000..54b102d6 --- /dev/null +++ b/code/game/gamemodes/meteor/meteors.dm @@ -0,0 +1,350 @@ +/var/const/meteor_wave_delay = 1 MINUTE //minimum wait between waves in tenths of seconds +//set to at least 100 unless you want evarr ruining every round + +//Meteor groups, used for various random events and the Meteor gamemode. + +// Dust, used by space dust event and during earliest stages of meteor mode. +/var/list/meteors_dust = list(/obj/effect/meteor/dust) + +// Standard meteors, used during early stages of the meteor gamemode. +/var/list/meteors_normal = list(\ + /obj/effect/meteor/medium=8,\ + /obj/effect/meteor/dust=3,\ + /obj/effect/meteor/irradiated=3,\ + /obj/effect/meteor/big=3,\ + /obj/effect/meteor/flaming=1,\ + /obj/effect/meteor/golden=1,\ + /obj/effect/meteor/silver=1\ + ) + +// Threatening meteors, used during the meteor gamemode. +/var/list/meteors_threatening = list(\ + /obj/effect/meteor/big=10,\ + /obj/effect/meteor/medium=5,\ + /obj/effect/meteor/golden=3,\ + /obj/effect/meteor/silver=3,\ + /obj/effect/meteor/flaming=3,\ + /obj/effect/meteor/irradiated=3,\ + /obj/effect/meteor/emp=3\ + ) + +// Catastrophic meteors, pretty dangerous without shields and used during the meteor gamemode. +/var/list/meteors_catastrophic = list(\ + /obj/effect/meteor/big=75,\ + /obj/effect/meteor/flaming=10,\ + /obj/effect/meteor/irradiated=10,\ + /obj/effect/meteor/emp=10,\ + /obj/effect/meteor/medium=5,\ + /obj/effect/meteor/golden=4,\ + /obj/effect/meteor/silver=4,\ + /obj/effect/meteor/tunguska=1\ + ) + +// Armageddon meteors, very dangerous, and currently used only during the meteor gamemode. +/var/list/meteors_armageddon = list(\ + /obj/effect/meteor/big=25,\ + /obj/effect/meteor/flaming=10,\ + /obj/effect/meteor/irradiated=10,\ + /obj/effect/meteor/emp=10,\ + /obj/effect/meteor/medium=3,\ + /obj/effect/meteor/tunguska=3,\ + /obj/effect/meteor/golden=2,\ + /obj/effect/meteor/silver=2\ + ) + +// Cataclysm meteor selection. Very very dangerous and effective even against shields. Used in late game meteor gamemode only. +/var/list/meteors_cataclysm = list(\ + /obj/effect/meteor/big=40,\ + /obj/effect/meteor/emp=20,\ + /obj/effect/meteor/tunguska=20,\ + /obj/effect/meteor/irradiated=10,\ + /obj/effect/meteor/golden=10,\ + /obj/effect/meteor/silver=10,\ + /obj/effect/meteor/flaming=10,\ + /obj/effect/meteor/supermatter=1\ + ) + + + +/////////////////////////////// +//Meteor spawning global procs +/////////////////////////////// + +/proc/pick_meteor_start(var/startSide = pick(GLOB.cardinal)) + var/startLevel = pick(GLOB.using_map.station_levels) + var/pickedstart = spaceDebrisStartLoc(startSide, startLevel) + + return list(startLevel, pickedstart) + +/proc/spawn_meteors(var/number = 10, var/list/meteortypes, var/startSide) + for(var/i = 0; i < number; i++) + spawn_meteor(meteortypes, startSide) + +/proc/spawn_meteor(var/list/meteortypes, var/startSide) + var/start = pick_meteor_start(startSide) + + var/startLevel = start[1] + var/turf/pickedstart = start[2] + var/turf/pickedgoal = spaceDebrisFinishLoc(startSide, startLevel) + + var/Me = pickweight(meteortypes) + var/obj/effect/meteor/M = new Me(pickedstart) + M.dest = pickedgoal + spawn(0) + walk_towards(M, M.dest, 1) + return + +/proc/spaceDebrisStartLoc(startSide, Z) + var/starty + var/startx + switch(startSide) + if(NORTH) + starty = world.maxy-(TRANSITIONEDGE+1) + startx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1)) + if(EAST) + starty = rand((TRANSITIONEDGE+1),world.maxy-(TRANSITIONEDGE+1)) + startx = world.maxx-(TRANSITIONEDGE+1) + if(SOUTH) + starty = (TRANSITIONEDGE+1) + startx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1)) + if(WEST) + starty = rand((TRANSITIONEDGE+1), world.maxy-(TRANSITIONEDGE+1)) + startx = (TRANSITIONEDGE+1) + var/turf/T = locate(startx, starty, Z) + return T + +/proc/spaceDebrisFinishLoc(startSide, Z) + var/endy + var/endx + switch(startSide) + if(NORTH) + endy = TRANSITIONEDGE + endx = rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE) + if(EAST) + endy = rand(TRANSITIONEDGE, world.maxy-TRANSITIONEDGE) + endx = TRANSITIONEDGE + if(SOUTH) + endy = world.maxy-TRANSITIONEDGE + endx = rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE) + if(WEST) + endy = rand(TRANSITIONEDGE,world.maxy-TRANSITIONEDGE) + endx = world.maxx-TRANSITIONEDGE + var/turf/T = locate(endx, endy, Z) + return T + +/////////////////////// +//The meteor effect +////////////////////// + +/obj/effect/meteor + name = "the concept of meteor" + desc = "You should probably run instead of gawking at this." + icon = 'icons/obj/meteor.dmi' + icon_state = "small" + density = 1 + anchored = 1 + var/hits = 4 + var/hitpwr = 2 //Level of ex_act to be called on hit. + var/dest + pass_flags = PASS_FLAG_TABLE + var/heavy = 0 + var/z_original + var/meteordrop = /obj/item/weapon/ore/iron + var/dropamt = 1 + + var/move_count = 0 + +/obj/effect/meteor/proc/get_shield_damage() + return max(((max(hits, 2)) * (heavy + 1) * rand(30, 60)) / hitpwr , 0) + +/obj/effect/meteor/New() + ..() + z_original = z + +/obj/effect/meteor/Move() + . = ..() //process movement... + move_count++ + if(loc == dest) + qdel(src) + +/obj/effect/meteor/touch_map_edge() + if(move_count > TRANSITIONEDGE) + qdel(src) + +/obj/effect/meteor/Destroy() + walk(src,0) //this cancels the walk_towards() proc + return ..() + +/obj/effect/meteor/New() + ..() + SpinAnimation() + +/obj/effect/meteor/Bump(atom/A) + ..() + if(A && !QDELETED(src)) // Prevents explosions and other effects when we were deleted by whatever we Bumped() - currently used by shields. + ram_turf(get_turf(A)) + get_hit() //should only get hit once per move attempt + +/obj/effect/meteor/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + return istype(mover, /obj/effect/meteor) ? 1 : ..() + +/obj/effect/meteor/proc/ram_turf(var/turf/T) + //first bust whatever is in the turf + for(var/atom/A in T) + if(A != src && !A.CanPass(src, src.loc, 0.5, 0)) //only ram stuff that would actually block us + A.ex_act(hitpwr) + + //then, ram the turf if it still exists + if(T && !T.CanPass(src, src.loc, 0.5, 0)) + T.ex_act(hitpwr) + +//process getting 'hit' by colliding with a dense object +//or randomly when ramming turfs +/obj/effect/meteor/proc/get_hit() + hits-- + if(hits <= 0) + make_debris() + meteor_effect() + qdel(src) + +/obj/effect/meteor/ex_act() + return + +/obj/effect/meteor/attackby(obj/item/weapon/W as obj, mob/user as mob, params) + if(istype(W, /obj/item/weapon/pickaxe)) + qdel(src) + return + ..() + +/obj/effect/meteor/proc/make_debris() + for(var/throws = dropamt, throws > 0, throws--) + var/obj/item/O = new meteordrop(get_turf(src)) + O.throw_at(dest, 5, 10) + +/obj/effect/meteor/proc/meteor_effect() + if(heavy) + for(var/mob/M in GLOB.player_list) + var/turf/T = get_turf(M) + if(!T || T.z != src.z) + continue + var/dist = get_dist(M.loc, src.loc) + shake_camera(M, dist > 20 ? 3 : 5, dist > 20 ? 1 : 3) + + +/////////////////////// +//Meteor types +/////////////////////// + +//Dust +/obj/effect/meteor/dust + name = "space dust" + icon_state = "dust" + pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GRILLE + hits = 1 + hitpwr = 3 + dropamt = 1 + meteordrop = /obj/item/weapon/ore/glass + +//Medium-sized +/obj/effect/meteor/medium + name = "meteor" + dropamt = 2 + +/obj/effect/meteor/medium/meteor_effect() + ..() + explosion(src.loc, 0, 1, 2, 3, 0) + +//Large-sized +/obj/effect/meteor/big + name = "large meteor" + icon_state = "large" + hits = 6 + heavy = 1 + dropamt = 3 + +/obj/effect/meteor/big/meteor_effect() + ..() + explosion(src.loc, 1, 2, 3, 4, 0) + +//Flaming meteor +/obj/effect/meteor/flaming + name = "flaming meteor" + icon_state = "flaming" + hits = 5 + heavy = 1 + meteordrop = /obj/item/weapon/ore/phoron + +/obj/effect/meteor/flaming/meteor_effect() + ..() + explosion(src.loc, 1, 2, 3, 4, 0, 0, 5) + +//Radiation meteor +/obj/effect/meteor/irradiated + name = "glowing meteor" + icon_state = "glowing" + heavy = 1 + meteordrop = /obj/item/weapon/ore/uranium + +/obj/effect/meteor/irradiated/meteor_effect() + ..() + explosion(src.loc, 0, 0, 4, 3, 0) + new /obj/effect/decal/cleanable/greenglow(get_turf(src)) + radiation_repository.radiate(src, 50) + +/obj/effect/meteor/golden + name = "golden meteor" + icon_state = "glowing" + desc = "Shiny! But also deadly." + meteordrop = /obj/item/weapon/ore/gold + +/obj/effect/meteor/silver + name = "silver meteor" + icon_state = "glowing_blue" + desc = "Shiny! But also deadly." + meteordrop = /obj/item/weapon/ore/silver + +/obj/effect/meteor/emp + name = "conducting meteor" + icon_state = "glowing_blue" + desc = "Hide your floppies!" + meteordrop = /obj/item/weapon/ore/osmium + dropamt = 2 + +/obj/effect/meteor/emp/meteor_effect() + ..() + // Best case scenario: Comparable to a low-yield EMP grenade. + // Worst case scenario: Comparable to a standard yield EMP grenade. + empulse(src, rand(2, 4), rand(4, 10)) + +/obj/effect/meteor/emp/get_shield_damage() + return ..() * rand(2,4) + +//Station buster Tunguska +/obj/effect/meteor/tunguska + name = "tunguska meteor" + icon_state = "flaming" + desc = "Your life briefly passes before your eyes the moment you lay them on this monstrosity." + hits = 10 + hitpwr = 1 + heavy = 1 + meteordrop = /obj/item/weapon/ore/diamond // Probably means why it penetrates the hull so easily before exploding. + +/obj/effect/meteor/tunguska/meteor_effect() + ..() + explosion(src.loc, 3, 6, 9, 20, 0) + +// This is the final solution against shields - a single impact can bring down most shield generators. +/obj/effect/meteor/supermatter + name = "supermatter shard" + desc = "Oh god, what will be next..?" + icon = 'icons/obj/engine.dmi' + icon_state = "darkmatter" + +/obj/effect/meteor/supermatter/meteor_effect() + ..() + explosion(src.loc, 1, 2, 3, 4, 0) + for(var/obj/machinery/power/apc/A in range(rand(12, 20), src)) + A.energy_fail(round(10 * rand(8, 12))) + +/obj/effect/meteor/supermatter/get_shield_damage() + return ..() * rand(80, 120) \ No newline at end of file diff --git a/code/game/gamemodes/mixed/bughunt.dm b/code/game/gamemodes/mixed/bughunt.dm new file mode 100644 index 00000000..be5f58eb --- /dev/null +++ b/code/game/gamemodes/mixed/bughunt.dm @@ -0,0 +1,13 @@ +/datum/game_mode/bughunt + name = "Deathsquad & Xenophage" + round_description = "A mercenary strike force is approaching to eradicate a xenomorph infestation!" + extended_round_description = "Mercenaries and xenomorphs spawn in this game mode." + config_tag = "bughunt" + required_players = 15 + required_enemies = 1 + end_on_antag_death = 0 + antag_tags = list(MODE_XENOMORPH, MODE_DEATHSQUAD) + require_all_templates = 1 + votable = 0 + auto_recall_shuttle = 1 + ert_disabled = 1 diff --git a/code/game/gamemodes/mixed/conflux.dm b/code/game/gamemodes/mixed/conflux.dm new file mode 100644 index 00000000..b966400e --- /dev/null +++ b/code/game/gamemodes/mixed/conflux.dm @@ -0,0 +1,10 @@ +/datum/game_mode/conflux + name = "Cult & Wizard" + round_description = "A space wizard and a cult have invaded!" + extended_round_description = "Cultists and wizards spawn during this round." + config_tag = "conflux" + required_players = 15 + required_enemies = 5 + end_on_antag_death = 0 + antag_tags = list(MODE_WIZARD, MODE_CULTIST) + require_all_templates = 1 diff --git a/code/game/gamemodes/mixed/crossfire.dm b/code/game/gamemodes/mixed/crossfire.dm new file mode 100644 index 00000000..9b0e28a4 --- /dev/null +++ b/code/game/gamemodes/mixed/crossfire.dm @@ -0,0 +1,10 @@ +/datum/game_mode/crossfire + name = "Mercenary & Heist" + round_description = "Mercenaries and raiders are preparing for a nice visit..." + extended_round_description = "Nothing can possibly go wrong with lots of people and lots of guns, right?" + config_tag = "crossfire" + required_players = 25 + required_enemies = 6 + end_on_antag_death = 0 + antag_tags = list(MODE_RAIDER, MODE_MERCENARY) + require_all_templates = 1 diff --git a/code/game/gamemodes/mixed/infestation.dm b/code/game/gamemodes/mixed/infestation.dm new file mode 100644 index 00000000..5aa38636 --- /dev/null +++ b/code/game/gamemodes/mixed/infestation.dm @@ -0,0 +1,16 @@ +/datum/game_mode/infestation + name = "Borer, Changeling & Xenophage" + round_description = "There's something in the walls!" + extended_round_description = "Two alien antagonists (Xenophages, Cortical Borers or Changelings) may spawn during this round." + config_tag = "infestation" + required_players = 15 + required_enemies = 5 + end_on_antag_death = 0 + antag_tags = list(MODE_BORER, MODE_XENOMORPH, MODE_CHANGELING) + require_all_templates = 1 + votable = 0 + +/datum/game_mode/infestation/create_antagonists() + // Two of the three. + antag_tags -= pick(antag_tags) + ..() diff --git a/code/game/gamemodes/mixed/lizard.dm b/code/game/gamemodes/mixed/lizard.dm new file mode 100644 index 00000000..19108e6f --- /dev/null +++ b/code/game/gamemodes/mixed/lizard.dm @@ -0,0 +1,10 @@ +/datum/game_mode/lizard + name = "Changelings & Wizards" + round_description = "A space wizard and changelings have invaded!" + extended_round_description = "Changelings and a wizard spawn during this round." + config_tag = "lizard" + required_players = 15 + required_enemies = 4 + end_on_antag_death = 0 + antag_tags = list(MODE_WIZARD, MODE_CHANGELING) + require_all_templates = 1 diff --git a/code/game/gamemodes/mixed/paranoia.dm b/code/game/gamemodes/mixed/paranoia.dm new file mode 100644 index 00000000..a2e1134c --- /dev/null +++ b/code/game/gamemodes/mixed/paranoia.dm @@ -0,0 +1,12 @@ +/datum/game_mode/paranoia + name = "Changeling, Malf & Renegade" + round_description = "The AI has malfunctioned, and subversive elements infest the crew..." + extended_round_description = "Rampant AIs, renegades and changelings spawn in this mode." + config_tag = "paranoia" + required_players = 15 + required_enemies = 1 + end_on_antag_death = 0 + antag_tags = list(MODE_MALFUNCTION, MODE_RENEGADE, MODE_CHANGELING) + disabled_jobs = list("AI") + require_all_templates = 1 + votable = 0 diff --git a/code/game/gamemodes/mixed/siege.dm b/code/game/gamemodes/mixed/siege.dm new file mode 100644 index 00000000..3514b56b --- /dev/null +++ b/code/game/gamemodes/mixed/siege.dm @@ -0,0 +1,12 @@ +/datum/game_mode/siege + name = "Mercenary & Revolution" + config_tag = "siege" + round_description = "Getting stuck between a rock and a hard place, maybe the nice visitors can help with your internal security problem?" + extended_round_description = "GENERAL QUARTERS! OH GOD WE GAVE THE REVOLUTIONARIES GUNS!" + required_players = 20 + required_enemies = 5 + end_on_antag_death = 0 + auto_recall_shuttle = 0 + shuttle_delay = 2 + antag_tags = list(MODE_REVOLUTIONARY, MODE_LOYALIST, MODE_MERCENARY) + require_all_templates = 1 diff --git a/code/game/gamemodes/mixed/traitorling.dm b/code/game/gamemodes/mixed/traitorling.dm new file mode 100644 index 00000000..c98e5320 --- /dev/null +++ b/code/game/gamemodes/mixed/traitorling.dm @@ -0,0 +1,10 @@ +/datum/game_mode/traitorling + name = "Changeling & Traitor" + round_description = "There are traitors and alien changelings. Do not let the changelings succeed!" + extended_round_description = "Traitors and changelings both spawn during this mode." + config_tag = "traitorling" + required_players = 15 + required_enemies = 5 + end_on_antag_death = 0 + antag_tags = list(MODE_CHANGELING, MODE_TRAITOR) + require_all_templates = 1 diff --git a/code/game/gamemodes/mixed/unity.dm b/code/game/gamemodes/mixed/unity.dm new file mode 100644 index 00000000..0abdf2f5 --- /dev/null +++ b/code/game/gamemodes/mixed/unity.dm @@ -0,0 +1,12 @@ +/datum/game_mode/unity + name = "Revolution & Wizard" + config_tag = "unity" + round_description = "Two unstoppable forces will tear each other apart, it's up to the grand wizard to unite them all!" + extended_round_description = "I pledge allegiance to the Banner of the One True King, and to the Federation for which He stands, one Empire under Our Dear Leader, indivisible, with liberty and justice for all." + required_players = 15 + required_enemies = 5 + end_on_antag_death = 0 + auto_recall_shuttle = 0 + shuttle_delay = 2 + antag_tags = list(MODE_REVOLUTIONARY, MODE_LOYALIST, MODE_WIZARD) + require_all_templates = 1 diff --git a/code/game/gamemodes/mixed/uprising.dm b/code/game/gamemodes/mixed/uprising.dm new file mode 100644 index 00000000..28fcefd3 --- /dev/null +++ b/code/game/gamemodes/mixed/uprising.dm @@ -0,0 +1,12 @@ +/datum/game_mode/uprising + name = "Cult & Revolution" + 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." + config_tag = "uprising" + required_players = 20 + required_enemies = 6 + end_on_antag_death = 0 + auto_recall_shuttle = 0 + shuttle_delay = 2 + antag_tags = list(MODE_REVOLUTIONARY, MODE_LOYALIST, MODE_CULTIST) + require_all_templates = 1 diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm new file mode 100644 index 00000000..2b7fc19a --- /dev/null +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -0,0 +1,88 @@ +/* + MERCENARY ROUNDTYPE +*/ + +var/list/nuke_disks = list() + +/datum/game_mode/nuclear + name = "Mercenary" + round_description = "A mercenary strike force is approaching!" + extended_round_description = "The Company's majority control of phoron in Nyx has marked the \ + station to be a highly valuable target for many competing organizations and individuals. Being a \ + colony of sizable population and considerable wealth causes it to often be the target of various \ + attempts of robbery, fraud and other malicious actions." + config_tag = "mercenary" + required_players = 15 + required_enemies = 1 + end_on_antag_death = 1 + var/nuke_off_station = 0 //Used for tracking if the syndies actually haul the nuke to the station + var/syndies_didnt_escape = 0 //Used for tracking if the syndies got the shuttle off of the z-level + antag_tags = list(MODE_MERCENARY) + +//checks if L has a nuke disk on their person +/datum/game_mode/nuclear/proc/check_mob(mob/living/L) + for(var/obj/item/weapon/disk/nuclear/N in nuke_disks) + if(N.storage_depth(L) >= 0) + return 1 + return 0 + +/datum/game_mode/nuclear/declare_completion() + var/datum/antagonist/merc = all_antag_types()[MODE_MERCENARY] + if(config.objectives_disabled == CONFIG_OBJECTIVE_NONE || (merc && !merc.global_objectives.len)) + ..() + return + var/disk_rescued = 1 + for(var/obj/item/weapon/disk/nuclear/D in world) + var/disk_area = get_area(D) + if(!is_type_in_list(disk_area, GLOB.using_map.post_round_safe_areas)) + disk_rescued = 0 + break + var/crew_evacuated = (evacuation_controller.has_evacuated()) + + if(!disk_rescued && station_was_nuked && !syndies_didnt_escape) + feedback_set_details("round_end_result","win - syndicate nuke") + to_world("Mercenary Major Victory!") + to_world("[syndicate_name()] operatives have destroyed [station_name()]!") + + else if (!disk_rescued && station_was_nuked && syndies_didnt_escape) + feedback_set_details("round_end_result","halfwin - syndicate nuke - did not evacuate in time") + to_world("Total Annihilation") + to_world("[syndicate_name()] operatives destroyed [station_name()] but did not leave the area in time and got caught in the explosion. Next time, don't lose the disk!") + + else if (!disk_rescued && !station_was_nuked && nuke_off_station && !syndies_didnt_escape) + feedback_set_details("round_end_result","halfwin - blew wrong station") + to_world("Crew Minor Victory") + to_world("[syndicate_name()] operatives secured the authentication disk but blew up something that wasn't [station_name()]. Next time, don't lose the disk!") + + else if (!disk_rescued && !station_was_nuked && nuke_off_station && syndies_didnt_escape) + feedback_set_details("round_end_result","halfwin - blew wrong station - did not evacuate in time") + to_world("[syndicate_name()] operatives have earned Darwin Award!") + to_world("[syndicate_name()] operatives blew up something that wasn't [station_name()] and got caught in the explosion. Next time, don't lose the disk!") + + else if (disk_rescued && mercs.antags_are_dead()) + feedback_set_details("round_end_result","loss - evacuation - disk secured - syndi team dead") + to_world("Crew Major Victory!") + to_world("The Research Staff has saved the disc and killed the [syndicate_name()] Operatives") + + else if (disk_rescued) + feedback_set_details("round_end_result","loss - evacuation - disk secured") + to_world("Crew Major Victory") + to_world("The Research Staff has saved the disc and stopped the [syndicate_name()] Operatives!") + + else if (!disk_rescued && mercs.antags_are_dead()) + feedback_set_details("round_end_result","loss - evacuation - disk not secured") + to_world("Mercenary Minor Victory!") + to_world("The Research Staff failed to secure the authentication disk but did manage to kill most of the [syndicate_name()] Operatives!") + + else if (!disk_rescued && crew_evacuated) + feedback_set_details("round_end_result","halfwin - detonation averted") + to_world("Mercenary Minor Victory!") + to_world("[syndicate_name()] operatives recovered the abandoned authentication disk but detonation of [station_name()] was averted. Next time, don't lose the disk!") + + else if (!disk_rescued && !crew_evacuated) + feedback_set_details("round_end_result","halfwin - interrupted") + to_world("Neutral Victory") + to_world("Round was mysteriously interrupted!") + + ..() + return diff --git a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm new file mode 100644 index 00000000..bbc6d120 --- /dev/null +++ b/code/game/gamemodes/nuclear/pinpointer.dm @@ -0,0 +1,190 @@ +/obj/item/weapon/pinpointer + name = "pinpointer" + icon = 'icons/obj/pinpointer.dmi' + icon_state = "pinoff" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + w_class = ITEM_SIZE_SMALL + item_state = "electronic" + matter = list(DEFAULT_WALL_MATERIAL = 500) + var/weakref/target + var/active = 0 + var/beeping = 2 + +/obj/item/weapon/pinpointer/Destroy() + STOP_PROCESSING(SSobj,src) + target = null + . = ..() + +/obj/item/weapon/pinpointer/attack_self(mob/user) + toggle(user) + +/obj/item/weapon/pinpointer/proc/toggle(mob/user) + active = !active + to_chat(user, "You [active ? "" : "de"]activate [src].") + if(!active) + STOP_PROCESSING(SSobj,src) + else + if(!target) + target = acquire_target() + START_PROCESSING(SSobj,src) + update_icon() + +/obj/item/weapon/pinpointer/advpinpointer/verb/toggle_sound() + set category = "Object" + set name = "Toggle Pinpointer Beeping" + set src in view(1) + + if(beeping >= 0) + beeping = -1 + to_chat(usr, "You mute [src].") + else + beeping = 0 + to_chat(usr, "You enable the sound indication on [src].") + +/obj/item/weapon/pinpointer/proc/acquire_target() + var/obj/item/weapon/disk/nuclear/the_disk = locate() + return weakref(the_disk) + +/obj/item/weapon/pinpointer/Process() + update_icon() + if(!target) + return + if(!target.resolve()) + target = null + return + + if(beeping < 0) + return + if(beeping == 0) + var/turf/here = get_turf(src) + var/turf/there = get_turf(target.resolve()) + if(!istype(there)) + return + var/distance = max(1,get_dist(here, there)) + var/freq_mod = 1 + if(distance < world.view) + freq_mod = min(world.view/distance, 2) + else if (distance > 3*world.view) + freq_mod = max(3*world.view/distance, 0.6) + playsound(loc, 'sound/machines/buttonbeep.ogg', 1, frequency = freq_mod) + if(distance > world.view || here.z != there.z) + beeping = initial(beeping) + else + beeping-- + +/obj/item/weapon/pinpointer/update_icon() + overlays.Cut() + if(!active) + return + if(!target || !target.resolve()) + overlays += image(icon,"pin_invalid") + return + + var/turf/here = get_turf(src) + var/turf/there = get_turf(target.resolve()) + if(!istype(there)) + overlays += image(icon,"pin_invalid") + return + + if(here == there) + overlays += image(icon,"pin_here") + return + + if(!(there.z in GetConnectedZlevels(here.z))) + overlays += image(icon,"pin_invalid") + return + if(here.z > there.z) + overlays += image(icon,"pin_down") + return + if(here.z < there.z) + overlays += image(icon,"pin_up") + return + + dir = get_dir(here,there) + var/image/pointer = image(icon,"pin_point") + var/distance = get_dist(here,there) + if(distance < world.view) + pointer.color = COLOR_LIME + else if(distance > 4*world.view) + pointer.color = COLOR_RED + else + pointer.color = COLOR_BLUE + overlays += pointer + +//Nuke ops locator +/obj/item/weapon/pinpointer/nukeop + var/locate_shuttle = 0 + +/obj/item/weapon/pinpointer/nukeop/Process() + var/new_mode + if(!locate_shuttle && bomb_set) + locate_shuttle = 1 + new_mode = "Shuttle Locator" + else if (locate_shuttle && !bomb_set) + locate_shuttle = 0 + new_mode = "Authentication Disk Locator" + if(new_mode) + playsound(loc, 'sound/machines/twobeep.ogg', 50, 1) + visible_message("[new_mode] active.") + target = acquire_target() + ..() + +/obj/item/weapon/pinpointer/nukeop/acquire_target() + if(locate_shuttle) + var/obj/machinery/computer/shuttle_control/multi/syndicate/home = locate() + return weakref(home) + else + return ..() + +//Deathsquad locator + +/obj/item/weapon/pinpointer/advpinpointer/verb/toggle_mode() + set category = "Object" + set name = "Toggle Pinpointer Mode" + set src in view(1) + + var/selection = input(usr, "Please select the type of target to locate.", "Mode" , "") as null|anything in list("Location", "Disk Recovery", "DNA", "Other Signature") + switch(selection) + if("Disk Recovery") + var/obj/item/weapon/disk/nuclear/the_disk = locate() + target = weakref(the_disk) + + if("Location") + var/locationx = input(usr, "Please input the x coordinate to search for.", "Location?" , "") as num + if(!locationx || !(usr in view(1,src))) + return + var/locationy = input(usr, "Please input the y coordinate to search for.", "Location?" , "") as num + if(!locationy || !(usr in view(1,src))) + return + + var/turf/Z = get_turf(src) + var/turf/location = locate(locationx,locationy,Z.z) + + to_chat(usr, "You set the pinpointer to locate [locationx],[locationy]") + + target = weakref(location) + + if("Other Signature") + var/datum/objective/steal/itemlist + itemlist = itemlist // To supress a 'variable defined but not used' error. + var/targetitem = input("Select item to search for.", "Item Mode Select","") as null|anything in itemlist.possible_items + if(!targetitem) + return + var/obj/item = locate(itemlist.possible_items[targetitem]) + if(!item) + to_chat(usr, "Failed to locate [targetitem]!") + return + to_chat(usr, "You set the pinpointer to locate [targetitem]") + target = weakref(item) + + if("DNA") + var/DNAstring = input("Input DNA string to search for." , "Please Enter String." , "") + if(!DNAstring) + return + for(var/mob/living/carbon/M in SSmobs.mob_list) + if(!M.dna) + continue + if(M.dna.unique_enzymes == DNAstring) + target = weakref(M) + break \ No newline at end of file diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm new file mode 100644 index 00000000..bb499bda --- /dev/null +++ b/code/game/gamemodes/objective.dm @@ -0,0 +1,828 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 +var/global/list/all_objectives = list() + +datum/objective + var/datum/mind/owner = null //Who owns the objective. + var/explanation_text = "Nothing" //What that person is supposed to do. + var/datum/mind/target = null //If they are focused on a particular person. + var/target_amount = 0 //If they are focused on a particular number. Steal objectives have their own counter. + var/completed = 0 //currently only used for custom objectives. + + New(var/text) + all_objectives |= src + if(text) + explanation_text = text + ..() + + Destroy() + all_objectives -= src + ..() + + proc/check_completion() + return completed + + proc/find_target() + var/list/possible_targets = list() + for(var/datum/mind/possible_target in ticker.minds) + if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2)) + possible_targets += possible_target + if(possible_targets.len > 0) + target = pick(possible_targets) + + + proc/find_target_by_role(role, role_type=0)//Option sets either to check assigned role or special role. Default to assigned. + for(var/datum/mind/possible_target in ticker.minds) + if((possible_target != owner) && ishuman(possible_target.current) && ((role_type ? possible_target.special_role : possible_target.assigned_role) == role) ) + target = possible_target + break + + +/datum/objective/assassinate/find_target() + ..() + if(target && target.current) + explanation_text = "Assassinate [target.current.real_name], the [target.assigned_role]." + else + explanation_text = "Free Objective" + return target + + +/datum/objective/assassinate/find_target_by_role(role, role_type=0) + ..(role, role_type) + if(target && target.current) + explanation_text = "Assassinate [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role]." + else + explanation_text = "Free Objective" + return target + + +/datum/objective/assassinate/check_completion() + if(target && target.current) + if(target.current.stat == DEAD || issilicon(target.current) || isbrain(target.current) || target.current.z > 6 || !target.current.ckey) //Borgs/brains/AIs count as dead for traitor objectives. --NeoFite + return 1 + return 0 + return 1 + + + +/datum/objective/anti_revolution/execute + find_target() + ..() + if(target && target.current) + explanation_text = "[target.current.real_name], the [target.assigned_role] has extracted confidential information above their clearance. Execute \him[target.current]." + else + explanation_text = "Free Objective" + return target + + + find_target_by_role(role, role_type=0) + ..(role, role_type) + if(target && target.current) + explanation_text = "[target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] has extracted confidential information above their clearance. Execute \him[target.current]." + else + explanation_text = "Free Objective" + return target + + check_completion() + if(target && target.current) + if(target.current.stat == DEAD || !ishuman(target.current)) + return 1 + return 0 + return 1 + +datum/objective/anti_revolution/brig + var/already_completed = 0 + + find_target() + ..() + if(target && target.current) + explanation_text = "Brig [target.current.real_name], the [target.assigned_role] for 20 minutes to set an example." + else + explanation_text = "Free Objective" + return target + + + find_target_by_role(role, role_type=0) + ..(role, role_type) + if(target && target.current) + explanation_text = "Brig [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] for 20 minutes to set an example." + else + explanation_text = "Free Objective" + return target + + check_completion() + if(already_completed) + return 1 + + if(target && target.current) + if(target.current.stat == DEAD) + return 0 + if(target.is_brigged(10 * 60 * 10)) + already_completed = 1 + return 1 + return 0 + return 0 + +datum/objective/anti_revolution/demote + find_target() + ..() + if(target && target.current) + explanation_text = "[target.current.real_name], the [target.assigned_role] has been classified as harmful to [GLOB.using_map.company_name]'s goals. Demote \him[target.current] to assistant." + else + explanation_text = "Free Objective" + return target + + find_target_by_role(role, role_type=0) + ..(role, role_type) + if(target && target.current) + explanation_text = "[target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] has been classified as harmful to [GLOB.using_map.company_name]'s goals. Demote \him[target.current] to assistant." + else + explanation_text = "Free Objective" + return target + + check_completion() + if(target && target.current && istype(target,/mob/living/carbon/human)) + var/obj/item/weapon/card/id/I = target.current:wear_id + if(istype(I, /obj/item/device/pda)) + var/obj/item/device/pda/P = I + I = P.id + + if(!istype(I)) return 1 + + if(I.assignment == "Assistant") + return 1 + else + return 0 + return 1 + +datum/objective/debrain//I want braaaainssss + find_target() + ..() + if(target && target.current) + explanation_text = "Steal the brain of [target.current.real_name]." + else + explanation_text = "Free Objective" + return target + + + find_target_by_role(role, role_type=0) + ..(role, role_type) + if(target && target.current) + explanation_text = "Steal the brain of [target.current.real_name] the [!role_type ? target.assigned_role : target.special_role]." + else + explanation_text = "Free Objective" + return target + + check_completion() + if(!target)//If it's a free objective. + return 1 + if( !owner.current || owner.current.stat==DEAD )//If you're otherwise dead. + return 0 + if( !target.current || !isbrain(target.current) ) + return 0 + var/atom/A = target.current + while(A.loc) //check to see if the brainmob is on our person + A = A.loc + if(A == owner.current) + return 1 + return 0 + + +datum/objective/protect//The opposite of killing a dude. + find_target() + ..() + if(target && target.current) + explanation_text = "Protect [target.current.real_name], the [target.assigned_role]." + else + explanation_text = "Free Objective" + return target + + + find_target_by_role(role, role_type=0) + ..(role, role_type) + if(target && target.current) + explanation_text = "Protect [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role]." + else + explanation_text = "Free Objective" + return target + + check_completion() + if(!target) //If it's a free objective. + return 1 + if(target.current) + if(target.current.stat == DEAD || issilicon(target.current) || isbrain(target.current)) + return 0 + return 1 + return 0 + + +datum/objective/hijack + explanation_text = "Hijack a shuttle or pod by escaping alone." + +datum/objective/hijack/check_completion() + if(!owner.current || owner.current.stat) + return 0 + if(!evacuation_controller.has_evacuated()) + return 0 + if(issilicon(owner.current)) + return 0 + + var/area/shuttle/shuttle_area = get_area(owner.current) + if(!istype(shuttle_area) || !(shuttle_area.z in GLOB.using_map.admin_levels)) + return 0 + + for(var/mob/living/player in GLOB.player_list) + if(is_type_in_list(player.type, list(/mob/living/silicon/ai, /mob/living/silicon/pai))) + continue + if (!player.mind || player.mind == owner) + continue + if(get_area(player) == shuttle_area) + return 0 + return 1 + + +datum/objective/block + explanation_text = "Do not allow any organic lifeforms to escape on the shuttle alive." + + + check_completion() + if(!istype(owner.current, /mob/living/silicon)) + return 0 + if(!evacuation_controller.has_evacuated()) + return 0 + if(!owner.current) + return 0 + var/area/shuttle = locate(/area/shuttle/escape/centcom) + var/protected_mobs[] = list(/mob/living/silicon/ai, /mob/living/silicon/pai, /mob/living/silicon/robot) + for(var/mob/living/player in GLOB.player_list) + if(player.type in protected_mobs) continue + if (player.mind) + if (player.stat != 2) + if (get_turf(player) in shuttle) + return 0 + return 1 + +datum/objective/silence + explanation_text = "Do not allow anyone to escape. Only allow the shuttle to be called when everyone is dead and your story is the only one left." + + check_completion() + if(!evacuation_controller.has_evacuated()) + return 0 + + for(var/mob/living/player in GLOB.player_list) + if(player == owner.current) + continue + if(player.mind) + if(player.stat != DEAD) + var/turf/T = get_turf(player) + if(T && is_type_in_list(T.loc, GLOB.using_map.post_round_safe_areas)) + return 0 + return 1 + + +datum/objective/escape + explanation_text = "Escape on the shuttle or an escape pod alive and free." + + + check_completion() + if(issilicon(owner.current)) + return 0 + if(isbrain(owner.current)) + return 0 + if(!evacuation_controller.has_evacuated()) + return 0 + if(!owner.current || owner.current.stat ==2) + return 0 + var/turf/location = get_turf(owner.current.loc) + if(!location) + return 0 + + //Fails traitors if they are in a shuttle but knocked out or cuffed. + if(owner.current.incapacitated(INCAPACITATION_KNOCKOUT|INCAPACITATION_RESTRAINED)) + return 0 + + var/area/check_area = location.loc + return check_area && is_type_in_list(check_area, GLOB.using_map.post_round_safe_areas) + + + +datum/objective/survive + explanation_text = "Stay alive until the end." + + check_completion() + if(!owner.current || owner.current.stat == DEAD || isbrain(owner.current)) + return 0 //Brains no longer win survive objectives. --NEO + if(issilicon(owner.current) && owner.current != owner.original) + return 0 + return 1 + +// Similar to the anti-rev objective, but for traitors +datum/objective/brig + var/already_completed = 0 + + find_target() + ..() + if(target && target.current) + explanation_text = "Have [target.current.real_name], the [target.assigned_role] brigged for 10 minutes." + else + explanation_text = "Free Objective" + return target + + + find_target_by_role(role, role_type=0) + ..(role, role_type) + if(target && target.current) + explanation_text = "Have [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] brigged for 10 minutes." + else + explanation_text = "Free Objective" + return target + + check_completion() + if(already_completed) + return 1 + + if(target && target.current) + if(target.current.stat == DEAD) + return 0 + // Make the actual required time a bit shorter than the official time + if(target.is_brigged(10 * 60 * 5)) + already_completed = 1 + return 1 + return 0 + return 0 + +// Harm a crew member, making an example of them +datum/objective/harm + var/already_completed = 0 + + find_target() + ..() + if(target && target.current) + explanation_text = "Make an example of [target.current.real_name], the [target.assigned_role]. Break one of their bones, detach one of their limbs or disfigure their face. Make sure they're alive when you do it." + else + explanation_text = "Free Objective" + return target + + + find_target_by_role(role, role_type=0) + ..(role, role_type) + if(target && target.current) + explanation_text = "Make an example of [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role]. Break one of their bones, detach one of their limbs or disfigure their face. Make sure they're alive when you do it." + else + explanation_text = "Free Objective" + return target + + check_completion() + if(already_completed) + return 1 + + if(target && target.current && istype(target.current, /mob/living/carbon/human)) + if(target.current.stat == DEAD) + return 0 + + var/mob/living/carbon/human/H = target.current + for(var/obj/item/organ/external/E in H.organs) + if(E.status & ORGAN_BROKEN) + return 1 + for(var/limb_tag in H.species.has_limbs) //todo check prefs for robotic limbs and amputations. + var/list/organ_data = H.species.has_limbs[limb_tag] + var/limb_type = organ_data["path"] + var/found + for(var/obj/item/organ/external/E in H.organs) + if(limb_type == E.type) + found = 1 + break + if(!found) + return 1 + + var/obj/item/organ/external/head/head = H.get_organ(BP_HEAD) + if(!head || head.disfigured) + return 1 + return 0 + + +datum/objective/nuclear + explanation_text = "Cause mass destruction with a nuclear device." + + + +/datum/objective/steal + var/obj/item/steal_target + var/target_name + + var/global/possible_items[] = list( + //"the captain's antique laser gun" = /obj/item/weapon/gun/energy/captain, + //"a bluespace rift generator" = /obj/item/integrated_circuit/manipulation/bluespace_rift, + //"an RCD" = /obj/item/weapon/rcd, + //"a jetpack" = /obj/item/weapon/tank/jetpack, + //"a captain's jumpsuit" = /obj/item/clothing/under/rank/captain, + //"a functional AI" = /obj/item/weapon/aicard, + "the magistrate's crown" = /obj/item/clothing/head/crown, + "the magistrate's uniform" = /obj/item/clothing/under/rank/magistrate, + "a pair of magboots" = /obj/item/clothing/shoes/magboots, + //"the [station_name()] blueprints" = /obj/item/blueprints, + //"a nasa voidsuit" = /obj/item/clothing/suit/space/void, + //"28 moles of phoron (full tank)" = /obj/item/weapon/tank, + //"a sample of slime extract" = /obj/item/slime_extract, + "a piece of corgi meat" = /obj/item/weapon/reagent_containers/food/snacks/meat/corgi, + //"a research director's jumpsuit" = /obj/item/clothing/under/rank/research_director, + //"a chief engineer's jumpsuit" = /obj/item/clothing/under/rank/chief_engineer, + //"a chief medical officer's jumpsuit" = /obj/item/clothing/under/rank/chief_medical_officer, + "the headpeackeepers's uniform" = /obj/item/clothing/under/rank/head_of_security, + "the overseers's uniform" = /obj/item/clothing/under/rank/head_of_personnel, + "the hypospray" = /obj/item/weapon/reagent_containers/hypospray, + "the magistrate's pinpointer" = /obj/item/weapon/pinpointer, + "an ablative armor vest" = /obj/item/clothing/suit/armor/laserproof, + ) + + var/global/possible_items_special[] = list( + /*"nuclear authentication disk" = /obj/item/weapon/disk/nuclear,*///Broken with the change to nuke disk making it respawn on z level change. + "nuclear gun" = /obj/item/weapon/gun/energy/gun/nuclear, + //"diamond drill" = /obj/item/weapon/pickaxe/diamonddrill, + //"bag of holding" = /obj/item/weapon/storage/backpack/holding, + "hyper-capacity cell" = /obj/item/weapon/cell/hyper, + //"10 diamonds" = /obj/item/stack/material/diamond, + //"50 gold bars" = /obj/item/stack/material/gold, + //"25 refined uranium bars" = /obj/item/stack/material/uranium, + ) + + +/datum/objective/steal/proc/set_target(item_name) + target_name = item_name + steal_target = possible_items[target_name] + if (!steal_target ) + steal_target = possible_items_special[target_name] + explanation_text = "Steal [target_name]." + return steal_target + + +/datum/objective/steal/find_target() + return set_target(pick(possible_items)) + + +/datum/objective/steal/proc/select_target() + var/list/possible_items_all = possible_items+possible_items_special+"custom" + var/new_target = input("Select target:", "Objective target", steal_target) as null|anything in possible_items_all + if (!new_target) return + if (new_target == "custom") + var/obj/item/custom_target = input("Select type:","Type") as null|anything in typesof(/obj/item) + if (!custom_target) return + var/tmp_obj = new custom_target + var/custom_name = tmp_obj:name + qdel(tmp_obj) + custom_name = sanitize(input("Enter target name:", "Objective target", custom_name) as text|null) + if (!custom_name) return + target_name = custom_name + steal_target = custom_target + explanation_text = "Steal [target_name]." + else + set_target(new_target) + return steal_target + +/datum/objective/steal/check_completion() + if(!steal_target || !owner.current) return 0 + if(!isliving(owner.current)) return 0 + var/list/all_items = owner.current.get_contents() + switch (target_name) + if("28 moles of phoron (full tank)","10 diamonds","50 gold bars","25 refined uranium bars") + var/target_amount = text2num(target_name)//Non-numbers are ignored. + var/found_amount = 0.0//Always starts as zero. + + for(var/obj/item/I in all_items) //Check for phoron tanks + if(istype(I, steal_target)) + found_amount += (target_name=="28 moles of phoron (full tank)" ? (I:air_contents:gas["phoron"]) : (I:amount)) + return found_amount>=target_amount + + if("a functional AI") + for(var/mob/living/silicon/ai/ai in SSmobs.mob_list) + if(ai.stat == DEAD) + continue + var/turf/T = get_turf(ai) + if(owner.current.contains(ai) || (T && is_type_in_list(T.loc, GLOB.using_map.post_round_safe_areas))) + return 1 + else + + for(var/obj/I in all_items) //Check for items + if(istype(I, steal_target)) + return 1 + return 0 + +datum/objective/capture + proc/gen_amount_goal() + target_amount = rand(5,10) + explanation_text = "Accumulate [target_amount] capture points." + return target_amount + + + check_completion()//Basically runs through all the mobs in the area to determine how much they are worth. + var/captured_amount = 0 + var/area/centcom/holding/A = locate() + + for(var/mob/living/carbon/human/M in A) // Humans (and subtypes). + var/worth = M.species.rarity_value + if(M.stat==DEAD)//Dead folks are worth less. + worth*=0.5 + continue + captured_amount += worth + + for(var/mob/living/carbon/alien/larva/M in A)//Larva are important for research. + if(M.stat==DEAD) + captured_amount+=0.5 + continue + captured_amount+=1 + + + if(captured_amount= target_amount)) + return 1 + else + return 0 + +// Heist objectives. +datum/objective/heist + proc/choose_target() + return + +datum/objective/heist/kidnap + choose_target() + var/list/roles = list("Chief Engineer","Research Director","Roboticist","Chemist","Engineer") + var/list/possible_targets = list() + var/list/priority_targets = list() + + for(var/datum/mind/possible_target in ticker.minds) + if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2) && (!possible_target.special_role)) + possible_targets += possible_target + for(var/role in roles) + if(possible_target.assigned_role == role) + priority_targets += possible_target + continue + + if(priority_targets.len > 0) + target = pick(priority_targets) + else if(possible_targets.len > 0) + target = pick(possible_targets) + + if(target && target.current) + explanation_text = "We can get a good price for [target.current.real_name], the [target.assigned_role]. Take them alive." + else + explanation_text = "Free Objective" + return target + + check_completion() + if(target && target.current) + if (target.current.stat == 2) + return 0 // They're dead. Fail. + //if (!target.current.restrained()) + // return 0 // They're loose. Close but no cigar. + + var/area/skipjack_station/start/A = locate() + for(var/mob/living/carbon/human/M in A) + if(target.current == M) + return 1 //They're restrained on the shuttle. Success. + else + return 0 + +datum/objective/heist/loot + + choose_target() + var/loot = "an object" + switch(rand(1,8)) + if(1) + target = /obj/structure/particle_accelerator + target_amount = 6 + loot = "a complete particle accelerator" + if(2) + target = /obj/machinery/the_singularitygen + target_amount = 1 + loot = "a gravitational generator" + if(3) + target = /obj/machinery/power/emitter + target_amount = 4 + loot = "four emitters" + if(4) + target = /obj/machinery/nuclearbomb + target_amount = 1 + loot = "a nuclear bomb" + if(5) + target = /obj/item/weapon/gun + target_amount = 6 + loot = "six guns" + if(6) + target = /obj/item/weapon/gun/energy + target_amount = 4 + loot = "four energy guns" + if(7) + target = /obj/item/weapon/gun/energy/laser + target_amount = 2 + loot = "two laser guns" + if(8) + target = /obj/item/weapon/gun/energy/ionrifle + target_amount = 1 + loot = "an ion gun" + + explanation_text = "It's a buyer's market out here. Steal [loot] for resale." + + check_completion() + + var/total_amount = 0 + + for(var/obj/O in locate(/area/skipjack_station/start)) + if(istype(O,target)) total_amount++ + for(var/obj/I in O.contents) + if(istype(I,target)) total_amount++ + if(total_amount >= target_amount) return 1 + + for(var/datum/mind/raider in raiders.current_antagonists) + if(raider.current) + for(var/obj/O in raider.current.get_contents()) + if(istype(O,target)) total_amount++ + if(total_amount >= target_amount) return 1 + + return 0 + +datum/objective/heist/salvage + + choose_target() + switch(rand(1,8)) + if(1) + target = DEFAULT_WALL_MATERIAL + target_amount = 300 + if(2) + target = "glass" + target_amount = 200 + if(3) + target = "plasteel" + target_amount = 100 + if(4) + target = "phoron" + target_amount = 100 + if(5) + target = "silver" + target_amount = 50 + if(6) + target = "gold" + target_amount = 20 + if(7) + target = "uranium" + target_amount = 20 + if(8) + target = "diamond" + target_amount = 20 + + explanation_text = "Ransack the [station_name()] and escape with [target_amount] [target]." + + check_completion() + + var/total_amount = 0 + + for(var/obj/item/O in locate(/area/skipjack_station/start)) + + var/obj/item/stack/material/S + if(istype(O,/obj/item/stack/material)) + if(O.name == target) + S = O + total_amount += S.get_amount() + for(var/obj/I in O.contents) + if(istype(I,/obj/item/stack/material)) + if(I.name == target) + S = I + total_amount += S.get_amount() + + for(var/datum/mind/raider in raiders.current_antagonists) + if(raider.current) + for(var/obj/item/O in raider.current.get_contents()) + if(istype(O,/obj/item/stack/material)) + if(O.name == target) + var/obj/item/stack/material/S = O + total_amount += S.get_amount() + + if(total_amount >= target_amount) return 1 + return 0 + + +/datum/objective/heist/preserve_crew + explanation_text = "Do not leave anyone behind, alive or dead." + + check_completion() + if(raiders && raiders.is_raider_crew_safe()) return 1 + return 0 + +//Borer objective(s). +/datum/objective/borer_survive + explanation_text = "Survive in a host until the end of the round." + +/datum/objective/borer_survive/check_completion() + if(owner) + var/mob/living/simple_animal/borer/B = owner + if(istype(B) && B.stat < 2 && B.host && B.host.stat < 2) return 1 + return 0 + +/datum/objective/borer_reproduce + explanation_text = "Reproduce at least once." + +/datum/objective/borer_reproduce/check_completion() + if(owner && owner.current) + var/mob/living/simple_animal/borer/B = owner.current + if(istype(B) && B.has_reproduced) return 1 + return 0 + +/datum/objective/cult/survive + explanation_text = "Our knowledge must live on." + target_amount = 5 + +/datum/objective/cult/survive/New() + ..() + explanation_text = "Our knowledge must live on. Make sure at least [target_amount] acolytes escape on the shuttle to spread their work on an another station." + +/datum/objective/cult/survive/check_completion() + var/acolytes_survived = 0 + if(!cult) + return 0 + for(var/datum/mind/cult_mind in cult.current_antagonists) + if (cult_mind.current && cult_mind.current.stat!=2) + var/area/A = get_area(cult_mind.current ) + if ( is_type_in_list(A, GLOB.using_map.post_round_safe_areas)) + acolytes_survived++ + if(acolytes_survived >= target_amount) + return 0 + else + return 1 + +/datum/objective/cult/eldergod + explanation_text = "Summon Nar-Sie via the use of the appropriate rune (Hell join self). It will only work if nine cultists stand on and around it. The convert rune is join blood self." + +/datum/objective/cult/eldergod/check_completion() + return (locate(/obj/singularity/narsie/large) in SSmachines.machinery) + +/datum/objective/cult/sacrifice + explanation_text = "Conduct a ritual sacrifice for the glory of Nar-Sie." + +/datum/objective/cult/sacrifice/find_target() + var/list/possible_targets = list() + if(!possible_targets.len) + for(var/mob/living/carbon/human/player in GLOB.player_list) + if(player.mind && !(player.mind in cult)) + possible_targets += player.mind + if(possible_targets.len > 0) + target = pick(possible_targets) + if(target) explanation_text = "Sacrifice [target.name], the [target.assigned_role]. You will need the sacrifice rune (Hell blood join) and three acolytes to do so." + +/datum/objective/cult/sacrifice/check_completion() + return (target && cult && !cult.sacrificed.Find(target)) + +/datum/objective/rev/find_target() + ..() + if(target && target.current) + explanation_text = "Assassinate, capture or convert [target.current.real_name], the [target.assigned_role]." + else + explanation_text = "Free Objective" + return target + + +/datum/objective/rev/find_target_by_role(role, role_type=0) + ..(role, role_type) + if(target && target.current) + explanation_text = "Assassinate, capture or convert [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role]." + else + explanation_text = "Free Objective" + return target + +/datum/objective/rev/check_completion() + var/rval = 1 + if(target && target.current) + var/mob/living/carbon/human/H = target.current + if(!istype(H)) + return 1 + if(H.stat == DEAD || H.restrained()) + return 1 + // Check if they're converted + if(target in revs.current_antagonists) + return 1 + var/turf/T = get_turf(H) + if(T && isNotStationLevel(T.z)) //If they leave the station they count as dead for this + rval = 2 + return 0 + return rval + diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm new file mode 100644 index 00000000..c376b012 --- /dev/null +++ b/code/game/gamemodes/revolution/revolution.dm @@ -0,0 +1,12 @@ +/datum/game_mode/revolution + name = "Riot" + config_tag = "revolution" + round_description = "Some crewmembers are attempting to overthrow the nobles!" + extended_round_description = "Revolutionaries - Remove the nobles from power. Convert other crewmembers to your cause using the 'Convert Bourgeoise' verb. Protect your leaders." + required_players = 15 + required_enemies = 3 +// auto_recall_shuttle = TRUE + end_on_antag_death = TRUE + shuttle_delay = 2 + antag_tags = list(MODE_REVOLUTIONARY) + require_all_templates = 1 diff --git a/code/game/gamemodes/sandbox/h_sandbox.dm b/code/game/gamemodes/sandbox/h_sandbox.dm new file mode 100644 index 00000000..a93ae6c5 --- /dev/null +++ b/code/game/gamemodes/sandbox/h_sandbox.dm @@ -0,0 +1,151 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +var/hsboxspawn = 1 +var/list + hrefs = list( + "hsbsuit" = "Suit Up (Space Travel Gear)", + "hsbmetal" = "Spawn 50 Metal", + "hsbglass" = "Spawn 50 Glass", + "hsbairlock" = "Spawn Airlock", + "hsbregulator" = "Spawn Air Regulator", + "hsbfilter" = "Spawn Air Filter", + "hsbcanister" = "Spawn Canister", + "hsbfueltank" = "Spawn Welding Fuel Tank", + "hsbwater tank" = "Spawn Water Tank", + "hsbtoolbox" = "Spawn Toolbox", + "hsbmedkit" = "Spawn Medical Kit") + +mob + var/datum/hSB/sandbox = null + proc + CanBuild() + if(master_mode == "sandbox") + sandbox = new/datum/hSB + sandbox.owner = src.ckey + if(src.client.holder) + sandbox.admin = 1 + verbs += new/mob/proc/sandbox_panel + sandbox_panel() + if(sandbox) + sandbox.update() + +datum/hSB + var/owner = null + var/admin = 0 + proc + update() + var/hsbpanel = "
    h_Sandbox Panel

    " + if(admin) + hsbpanel += "Administration Tools:
    " + hsbpanel += "- Toggle Object Spawning

    " + hsbpanel += "Regular Tools:
    " + for(var/T in hrefs) + hsbpanel += "- [hrefs[T]]
    " + if(hsboxspawn) + hsbpanel += "- Spawn Object

    " + usr << browse(hsbpanel, "window=hsbpanel") + Topic(href, href_list) + if(!(src.owner == usr.ckey)) return + if(!usr) return //I guess this is possible if they log out or die with the panel open? It happened. + if(href_list["hsb"]) + switch(href_list["hsb"]) + if("hsbtobj") + if(!admin) return + if(hsboxspawn) + to_world("Sandbox: [usr.key] has disabled object spawning!") + hsboxspawn = 0 + return + if(!hsboxspawn) + to_world"Sandbox: [usr.key] has enabled object spawning!") + hsboxspawn = 1 + return + if("hsbsuit") + var/mob/living/carbon/human/P = usr + if(P.wear_suit) + P.wear_suit.forceMove(P.loc) + P.wear_suit.reset_plane_and_layer() + P.wear_suit = null + P.wear_suit = new/obj/item/clothing/suit/space(P) + P.wear_suit.hud_layerise() + if(P.head) + P.head.forceMove(P.loc) + P.head.reset_plane_and_layer() + P.head = null + P.head = new/obj/item/clothing/head/helmet/space(P) + P.head.hud_layerise() + if(P.wear_mask) + P.wear_mask.forceMove(P.loc) + P.wear_mask.reset_plane_and_layer() + P.wear_mask = null + P.wear_mask = new/obj/item/clothing/mask/gas(P) + P.wear_mask.hud_layerise() + if(P.back) + P.back.forceMove(P.loc) + P.back.reset_plane_and_layer() + P.back = null + P.back = new/obj/item/weapon/tank/jetpack(P) + P.back.hud_layerise() + P.internal = P.back + if("hsbmetal") + var/obj/item/stack/sheet/hsb = new/obj/item/stack/sheet/metal + hsb.amount = 50 + hsb.loc = usr.loc + if("hsbglass") + var/obj/item/stack/sheet/hsb = new/obj/item/stack/sheet/glass + hsb.amount = 50 + hsb.loc = usr.loc + if("hsbairlock") + var/obj/machinery/door/hsb = new/obj/machinery/door/airlock + + //TODO: DEFERRED make this better, with an HTML window or something instead of 15 popups + hsb.req_access = list() + var/accesses = get_all_accesses() + for(var/A in accesses) + if(alert(usr, "Will this airlock require [get_access_desc(A)] access?", "Sandbox:", "Yes", "No") == "Yes") + hsb.req_access += A + + hsb.loc = usr.loc + to_chat(usr, "Sandbox: Created an airlock.") + if("hsbcanister") + var/list/hsbcanisters = typesof(/obj/machinery/portable_atmospherics/canister/) - /obj/machinery/portable_atmospherics/canister/ + var/hsbcanister = input(usr, "Choose a canister to spawn.", "Sandbox:") in hsbcanisters + "Cancel" + if(!(hsbcanister == "Cancel")) + new hsbcanister(usr.loc) + if("hsbfueltank") + //var/obj/hsb = new/obj/weldfueltank + //hsb.loc = usr.loc + if("hsbwatertank") + //var/obj/hsb = new/obj/watertank + //hsb.loc = usr.loc + if("hsbtoolbox") + var/obj/item/weapon/storage/hsb = new/obj/item/weapon/storage/toolbox/mechanical + for(var/obj/item/device/radio/T in hsb) + qdel(T) + new/obj/item/weapon/crowbar (hsb) + hsb.loc = usr.loc + if("hsbmedkit") + var/obj/item/weapon/storage/firstaid/hsb = new/obj/item/weapon/storage/firstaid/regular + hsb.loc = usr.loc + if("hsbobj") + if(!hsboxspawn) return + + var/list/selectable = list() + for(var/O in typesof(/obj/item/)) + //Note, these istypes don't work + if(istype(O, /obj/item/weapon/gun)) + continue + if(istype(O, /obj/item/assembly)) + continue + if(istype(O, /obj/item/device/camera)) + continue + if(istype(O, /obj/item/weapon/dummy)) + continue + if(istype(O, /obj/item/weapon/melee/energy/sword)) + continue + if(istype(O, /obj/structure)) + continue + selectable += O + + var/hsbitem = input(usr, "Choose an object to spawn.", "Sandbox:") in selectable + "Cancel" + if(hsbitem != "Cancel") + new hsbitem(usr.loc) diff --git a/code/game/gamemodes/sandbox/sandbox.dm b/code/game/gamemodes/sandbox/sandbox.dm new file mode 100644 index 00000000..c261cc8f --- /dev/null +++ b/code/game/gamemodes/sandbox/sandbox.dm @@ -0,0 +1,17 @@ +/datum/game_mode/sandbox + name = "Sandbox" + config_tag = "sandbox" + required_players = 0 + votable = 0 + round_description = "Build your own station!" + extended_round_description = "You can use the sandbox-panel command to access build options." + +/datum/game_mode/sandbox/pre_setup() + for(var/mob/M in GLOB.player_list) + M.CanBuild() + return 1 + +/datum/game_mode/sandbox/post_setup() + ..() + if(emergency_shuttle) + emergency_shuttle.auto_recall = 1 diff --git a/code/game/gamemodes/setupgame.dm b/code/game/gamemodes/setupgame.dm new file mode 100644 index 00000000..1fb36f55 --- /dev/null +++ b/code/game/gamemodes/setupgame.dm @@ -0,0 +1,83 @@ +///////////////////////// +// (mostly) DNA2 SETUP +///////////////////////// + +// Randomize block, assign a reference name, and optionally define difficulty (by making activation zone smaller or bigger) +// The name is used on /vg/ for species with predefined genetic traits, +// and for the DNA panel in the player panel. +/proc/getAssignedBlock(var/name,var/list/blocksLeft, var/activity_bounds=DNA_DEFAULT_BOUNDS) + if(blocksLeft.len==0) + warning("[name]: No more blocks left to assign!") + return 0 + var/assigned = pick(blocksLeft) + blocksLeft.Remove(assigned) + assigned_blocks[assigned]=name + dna_activity_bounds[assigned]=activity_bounds + //testing("[name] assigned to block #[assigned].") + return assigned + +/proc/setupgenetics() + + if (prob(50)) + // Currently unused. Will revisit. - N3X + GLOB.BLOCKADD = rand(-300,300) + if (prob(75)) + GLOB.DIFFMUT = rand(0,20) + + var/list/numsToAssign=new() + for(var/i=1;i= 150) + to_chat(user, SPAN_NOTICE("It is undamaged.")) + else if(health < 150 && health > 100) + to_chat(user, SPAN_WARNING("It has a few small dents.")) + else if(health < 100 && health > 50) + to_chat(user, SPAN_WARNING("It has several large dents.")) + else + to_chat(user, SPAN_DANGER("It is on the verge of breaking apart!")) + +/obj/structure/defensive_barrier/proc/get_destroyed() + visible_message(SPAN_DANGER("\The [src] was destroyed!")) + playsound(src, 'sound/effects/clang.ogg', 100, 1) + qdel(src) + +/obj/structure/defensive_barrier/Destroy() + GLOB.dir_set_event.unregister(src, src, .proc/update_layers) + . = ..() + +/obj/structure/defensive_barrier/proc/update_layers() + if(dir != SOUTH) + layer = initial(layer) + 0.01 + plane = initial(plane) + else if(dir == SOUTH && density) + layer = ABOVE_HUMAN_LAYER + plane = ABOVE_HUMAN_PLANE + else + layer = initial(layer) + 0.01 + plane = initial(plane) + +/obj/structure/defensive_barrier/update_icon() + ..() + if(!secured) + if(density) + icon_state = "barrier_rised" + else + icon_state = "barrier_downed" + else + icon_state = "barrier_deployed" + update_layers() + +/obj/structure/defensive_barrier/CanPass(atom/movable/mover, turf/target, height = 0, air_group = 0) + if(!density || air_group || (height == 0)) + return TRUE + + if(istype(mover, /obj/item/projectile)) + var/obj/item/projectile/proj = mover + if(Adjacent(proj?.firer)) + return TRUE + //if(mover.dir != reverse_direction(dir)) + // return TRUE + if(get_dist(proj.starting, loc) <= 1)//allows to fire from 1 tile away of barrier + return TRUE + return check_cover(mover, target) + + if(get_dir(get_turf(src), target) == dir && density)//turned in front of barrier + return FALSE + + return TRUE + +/obj/structure/defensive_barrier/CheckExit(atom/movable/O, target) + if(O?.checkpass(PASS_FLAG_TABLE)) + return TRUE + if(get_dir(loc, target) == dir) + return !density + return TRUE + +/obj/structure/defensive_barrier/proc/try_pack_up(var/mob/user) + + if(secured) + to_chat(user, SPAN_WARNING("\The [src] is secured in place and cannot be packed up. You will need to unsecure it with a screwdriver.")) + return FALSE + + if(density) + to_chat(user, SPAN_WARNING("\The [src] is raised and must be lowered before you can pack it up.")) + return FALSE + + visible_message(SPAN_NOTICE("\The [user] starts packing up \the [src].")) + + if(!do_after(user, 10, src) || secured || density) + return FALSE + + visible_message(SPAN_NOTICE("\The [user] packs up \the [src].")) + var/obj/item/defensive_barrier/B = new(get_turf(user)) + playsound(src, 'sound/items/Deconstruct.ogg', 100, 1) + B.stored_health = health + B.stored_max_health = maxhealth + B.add_fingerprint(user) + qdel(src) + return TRUE + +/obj/structure/defensive_barrier/CtrlClick(mob/living/user) + try_pack_up(user) + +/obj/structure/defensive_barrier/attack_hand(mob/living/carbon/human/user) + + if(ishuman(user) && user.species.can_shred(user) && user.a_intent == I_HURT) + take_damage(20) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + return TRUE + + if(user.a_intent == I_GRAB) + try_pack_up(user) + return TRUE + + if(secured) + to_chat(user, SPAN_WARNING("\The [src] is secured in place and cannot be put up or down. You will need to unsecure it with a screwdriver.")) + return TRUE + + if(!do_after(user, 5, src)) + return TRUE + + playsound(src, 'sound/effects/extout.ogg', 100, 1) + density = !density + to_chat(user, SPAN_NOTICE("You [density ? "raise" : "lower"] \the [src].")) + update_icon() + return TRUE + +/obj/structure/defensive_barrier/attackby(obj/item/W, mob/user) + + if(isScrewdriver(W) && density) + user.visible_message(SPAN_NOTICE("\The [user] begins to [secured ? "unsecure" : "secure"] \the [src]...")) + playsound(src, 'sound/items/Screwdriver.ogg', 100, 1) + if(!do_after(user, 30, src)) + return TRUE + secured = !secured + user.visible_message(SPAN_NOTICE("\The [user] has [secured ? "secured" : "unsecured"] \the [src].")) + update_icon() + return TRUE + + . = ..() + +/obj/structure/defensive_barrier/proc/take_damage(damage) + if(damage) + playsound(src.loc, 'sound/effects/bang.ogg', 75, 1) + damage = round(damage * 0.5) + if(damage) + ..() + +/obj/structure/defensive_barrier/proc/check_cover(obj/item/projectile/P, turf/from) + var/turf/cover = get_turf(src) + if(!cover) + return TRUE + + visible_message(SPAN_WARNING("\The [P] hits \the [src]!")) + bullet_act(P) + return FALSE + + +/obj/structure/defensive_barrier/bullet_act(obj/item/projectile/P) + ..() + health -= rand(20,40) + if(health <= 0) + health = 0 + get_destroyed() + + +/obj/item/defensive_barrier + name = "deployable barrier" + desc = "A portable barrier in flatpack form. Deploy it to stop bullets from killing you." + icon = 'icons/obj/structures/barrier.dmi' + icon_state = "barrier_hand" + w_class = ITEM_SIZE_NORMAL + var/stored_health = 300 + var/stored_max_health = 300 + +/obj/item/defensive_barrier/proc/turf_check(mob/user, var/turf/to_check) + var/turf/T = get_turf(to_check) + if(!istype(T)) + return FALSE + if(istype(T, /turf/simulated/floor/trench)) + to_chat(user, "I cannot place this in a trench.") + return FALSE + if(T.density) + to_chat(user, "I cannot place cover here.") + return FALSE + for(var/obj/structure/defensive_barrier/D in T) + if((D.dir == user.dir)) + to_chat(user, SPAN_WARNING("There is already a barrier set up facing that direction.")) + return FALSE + return TRUE + +/obj/item/defensive_barrier/attack_self(mob/user) + var/turf/T = get_step(user, user.dir) + if(!turf_check(user, T))//Checking if we can put this here. + return TRUE + if(!do_after(user, 30, src)) + return TRUE + playsound(src, 'sound/effects/extout.ogg', 100, 1) + var/obj/structure/defensive_barrier/B = new(T) + B.set_dir(user.dir) + B.health = stored_health + if(loc == user) + user.drop_from_inventory(src) + qdel(src) + +/obj/item/defensive_barrier/attackby(obj/item/W, mob/user) + + if(stored_health < stored_max_health && isWelder(W)) + var/obj/item/weapon/weldingtool/WT = W + if(!WT.isOn()) + to_chat(user, SPAN_WARNING("Turn \the [W] on first.")) + return TRUE + + if(!WT.remove_fuel(0,user)) + to_chat(user, SPAN_WARNING("You need more welding fuel to complete this task.")) + return TRUE + + to_chat(user, SPAN_WARNING("You start repairing the damage to \the [src].")) + playsound(src, 'sound/items/Welder.ogg', 100, 1) + + if(!do_after(user, max(5, round((stored_max_health-stored_health) / 5)), src) || !WT?.isOn() || QDELETED(src)) + return TRUE + + to_chat(user, SPAN_NOTICE("You finish repairing the damage to \the [src].")) + playsound(src, 'sound/items/Welder2.ogg', 100, 1) + stored_health = stored_max_health + return TRUE + + . = ..() \ No newline at end of file diff --git a/code/game/gamemodes/warfare/flare.dm b/code/game/gamemodes/warfare/flare.dm new file mode 100644 index 00000000..291ab1c3 --- /dev/null +++ b/code/game/gamemodes/warfare/flare.dm @@ -0,0 +1,83 @@ +// FLARES + +/obj/item/warflare + name = "warflare" + desc = "A standard-issue warflare. There are instructions on the side reading 'pull cord, make light'." + w_class = ITEM_SIZE_TINY + var/brightness_on = 8 // Pretty bright. + light_power = 3 + light_color = COLOR_RED_LIGHT + icon = 'icons/obj/lighting.dmi' + icon_state = "rflare" + item_state = "flare" + var/on = FALSE + var/activation_sound = 'sound/effects/flare.ogg' + var/used = FALSE + +/obj/item/warflare/blue + icon_state = "bflare" + item_state = "blueflare" + light_color = COLOR_BLUE_LIGHT + +/obj/item/warflare/Initialize() + . = ..() + update_icon() + +/obj/item/warflare/update_icon() //Copied and pasted, kinda gross, but I don't really care to make all lighting objects overlay based. Maybe some other time. ~Chaoko + overlays = overlays.Cut() + if(on) + set_light(brightness_on, light_power, light_color) + overlays += overlay_image(icon, "[icon_state]-fire") + else + if(used) + overlays += overlay_image(icon, "burnt") + else + overlays += overlay_image(icon, "[icon_state]-ring") + set_light(0) + +/obj/item/warflare/proc/turn_off() + on = 0 + update_icon() + +/obj/item/warflare/attack_self(mob/user) + if(turn_on(user)) + user.visible_message("\The [user] activates \the [src].", "FFFFFFSHHSHSHSHSHSHHH") + playsound(src.loc, activation_sound, 75, 1) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.throw_mode_on() + + +/obj/item/warflare/proc/turn_on(var/mob/user) + if(on) + return FALSE + if(used) + if(user) + to_chat(user, "It's out of fuel.") + return FALSE + on = TRUE + update_icon() + + addtimer(CALLBACK(src, .turn_off), rand(6 MINUTE, 10 MINUTES) ) + used = 1 + return 1 + +/obj/item/ammo_box/flares + name = "warflare pouch" + desc = "Filled with warflares. They light the night, and the fires. Holds three. Only accepts your side's flares." + icon = 'icons/obj/lighting.dmi' + icon_state = "flarepack" + handful_type = /obj/item/warflare + max_stacks = 4 + handful_verb = "warflare" + slot_flags = SLOT_BELT + var/flaretype = "r" + +/obj/item/ammo_box/flares/blue + flaretype = "b" + handful_type = /obj/item/warflare/blue + +//Build flare icon on new. Updates every time it's opened anyway. +/obj/item/ammo_box/flares/update_icon() + overlays = overlays.Cut() + overlays += overlay_image(icon, "[flaretype]flare-[stored_handfuls.len]") diff --git a/code/game/gamemodes/warfare/language.dm b/code/game/gamemodes/warfare/language.dm new file mode 100644 index 00000000..7106cbb5 --- /dev/null +++ b/code/game/gamemodes/warfare/language.dm @@ -0,0 +1,29 @@ + +/datum/language/warfare + name = "warfare language" + desc = "Nothing. Just code stuff" + speech_verb = "says" + whisper_verb = "whispers" + flags = RESTRICTED + +/datum/language/warfare/get_spoken_verb(var/msg_end) + switch(msg_end) + if("!") + return pick("exclaims", "shouts", "yells") //TODO: make the basic proc handle lists of verbs. + if("?") + return ask_verb + return speech_verb + +/datum/language/warfare/red + name = LANGUAGE_RED + desc = "This is the languaged used by the Red Team." + colour = "red_team" + key = "r" + syllables = list("zhena", "reb", "kot", "tvoy", "vodka", "blyad", "lenin", "ponimat", "zhit", "kley", "sto", "yat", "si", "det", "re", "be", "nok", "chto", "tovarish", "kak", "govor", "navernoe", "da", "net", "horosho", "pochemu", "privet", "ebat", "krovat", "stol", "za", "ryad", "ka", "voyna", "dumat", "patroni", "fashisti", "zdorovie", "day", "dengi", "nemci", "chehi", "odin", "dva", "soyuz", "holod", "granata", "ne", "re", "ru", "rukzak") + +/datum/language/warfare/blue + name = LANGUAGE_BLUE + desc = "This is the languaged used by the Blue Team." + colour = "blue_team" + key = "z" + syllables = list("byt", "ten", "ze", "ktery", "pan", "hlava", "zem", "lide", "doba", "dobry", "cely", "tvrdy", "roz", "hodny", "nezlomny", "staly", "scvrnkly", "ener", "gicky", "nezmen", "itelne", "hi", "ved", "dur", "pec", "dat", "bet", "ten", "on", "na", "he", "ktere", "pen", "hivot", "clo", "vek", "pre", "zeme", "lidu", "dob", "hlav", "mht", "moci", "muse", "vedet", "chtht", "jht", "rhci", "cele", "hive", "trvanlive", "hou", "hev", "nate", "dobre") \ No newline at end of file diff --git a/code/game/gamemodes/warfare/lighting_dummy.dm b/code/game/gamemodes/warfare/lighting_dummy.dm new file mode 100644 index 00000000..a63f3f5d --- /dev/null +++ b/code/game/gamemodes/warfare/lighting_dummy.dm @@ -0,0 +1,40 @@ +//Warfare daylight lightings dummies. Thank fuck lighting isn't additive. Todo: make this into a schedulable subsystem HOLY FUCK this will lag on big maps. +GLOBAL_LIST_EMPTY(lighting_dummies) + +/obj/effect/lighting_dummy + name = "lighting dammy" + desc = "you literally should not be able to see or interact with this." + anchored = TRUE + invisibility = 101 +//For nightfare. +/obj/effect/lighting_dummy/daylight/Initialize() + . = ..() + GLOB.lighting_dummies += src + if(aspect_chosen(/datum/aspect/nightfare)) //For init. Note this will probably force this mode on until behavior has been made for deactivating aspects. + return + set_light(3, 3, "#28284f") +/obj/effect/lighting_dummy/Destroy() //Shouldn't happen but let's prevent runtimes. + . = ..() + GLOB.lighting_dummies -= src + +/obj/effect/lighting_dummy/ex_act() + return + + +/obj/effect/lighting_dummy/flare + mouse_opacity = 0 + invisibility = 0 + icon = 'icons/obj/items/mortars.dmi' + icon_state = "redFlare" + plane = EFFECTS_ABOVE_LIGHTING_PLANE + light_power = 6 + light_range = 10 + light_color = COLOR_RED + + Initialize() + . = ..() + QDEL_IN(src, 3 MINUTES) + +/obj/effect/lighting_dummy/flare/blue + icon_state = "blueFlare" + light_color = COLOR_BLUE \ No newline at end of file diff --git a/code/game/gamemodes/warfare/structures.dm b/code/game/gamemodes/warfare/structures.dm new file mode 100644 index 00000000..c79e026a --- /dev/null +++ b/code/game/gamemodes/warfare/structures.dm @@ -0,0 +1,587 @@ +/obj/structure/dirt_wall + name = "dirt barricade" + desc = "A land structure to cover your ass!" //change this stupid description + icon = 'icons/obj/warfare.dmi' + icon_state = "mound" + throwpass = TRUE//we can throw grenades despite its density + anchored = TRUE + density = FALSE + plane = ABOVE_OBJ_PLANE + layer = BASE_ABOVE_OBJ_LAYER + var/health = 100 + + +/obj/structure/dirt_wall/Crossed(var/mob/living/M as mob) + if(istype(M)) + M.pixel_y = 12 + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.client) + H.fov_mask.screen_loc = "1,1.5" + H.fov.screen_loc = "1,1.5" + +/obj/structure/dirt_wall/Uncrossed(var/mob/living/M as mob) + if(istype(M)) + M.pixel_y = 0 + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.client) + H.fov_mask.screen_loc = "1,1" + H.fov.screen_loc = "1,1" + +/obj/structure/dirt_wall/attackby(obj/O as obj, mob/user as mob) + if(istype(O, /obj/item/weapon/shovel)) + if(do_after(user, 50)) + qdel(src) + +/obj/structure/dirt_wall/RightClick(mob/user) + if(!CanPhysicallyInteract(user)) + return + if(do_after(user, 50)) + if(src)//If it's somehow deleted before hand. + health = 100 + + +/obj/structure/dirt_wall/bullet_act(var/obj/item/projectile/Proj) + ..() + for(var/mob/living/carbon/human/H in loc) + H.bullet_act(Proj) + //visible_message("[Proj] hits the [src]!") + playsound(src, "hitwall", 50, TRUE) + health -= rand(10, 25) + if(health <= 0) + visible_message("The [src] crumbles!") + qdel(src) + +/obj/structure/dirt_wall/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + qdel(src) + return + if(3.0) + if(prob(50)) + qdel(src) + + + +/obj/structure/dirt_wall/attack_generic(var/mob/user, var/damage) + return FALSE + +/obj/structure/dirt_wall/fire_act(temperature) + return + +/obj/structure/dirt_wall/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(istype(mover, /obj/item/projectile)) + var/obj/item/projectile/proj = mover + + if(proj.firer && Adjacent(proj.firer)) + return TRUE + + if (get_dist(proj.starting, loc) <= 1) + return TRUE + + return FALSE + + return TRUE + + +//Bullshit snowflake stuff for climbing over it. +/obj/structure/dirt_wall/do_climb(var/mob/living/user) + if(!can_climb(user)) + return + + usr.visible_message("[user] starts climbing onto \the [src]!") + climbers |= user + + if(!do_after(user,(issmall(user) ? 20 : 34))) + climbers -= user + return + + if(!can_climb(user, post_climb_check=1)) + climbers -= user + return + + if(!neighbor_turf_passable()) + to_chat(user, "You can't climb there, the way is blocked.") + climbers -= user + return + + if(get_turf(user) == get_turf(src)) + usr.forceMove(get_step(src, src.dir)) + else + usr.forceMove(get_turf(src)) + + usr.visible_message("[user] climbed over \the [src]!") + climbers -= user + +/obj/structure/dirt_wall/can_climb(var/mob/living/user, post_climb_check=0) + if (!(atom_flags & ATOM_FLAG_CLIMBABLE) || !can_touch(user) || (!post_climb_check && (user in climbers))) + return FALSE + + if (!user.Adjacent(src)) + to_chat(user, "You can't climb there, the way is blocked.") + return FALSE + + return TRUE + + +//NON DIRT BARRICADES + +/obj/structure/warfare/barricade + name = "barricade" + desc = "it stops you from moving" + icon = 'icons/obj/warfare.dmi' + plane = ABOVE_OBJ_PLANE + layer = BASE_ABOVE_OBJ_LAYER + anchored = TRUE + +/obj/structure/warfare/barricade/concrete_barrier + name = "concrete barrier" + desc = "Very effective at blocking bullets, but it gets in the way." + icon_state = "concrete_block" + + +/obj/structure/warfare/barricade/New() + ..() + if(dir == SOUTH) + plane = ABOVE_HUMAN_PLANE + + +/obj/structure/warfare/barricade/CheckExit(atom/movable/O, turf/target) + if(istype(O, /obj/item/projectile))//Blocks bullets unless you're ontop of it. + var/obj/item/projectile/proj = O + if(proj.firer.resting)//No resting and shooting over these. + qdel(proj) + return FALSE + if(proj.firer && Adjacent(proj.firer)) + return TRUE + if(get_dir(loc, target) & dir) + return FALSE + else + return TRUE + +/obj/structure/warfare/barricade/CanPass(atom/movable/mover, turf/target) + if(istype(mover, /obj/item/projectile))//Blocks bullets unless you're ontop of it. + var/obj/item/projectile/proj = mover + + if(proj.firer.resting)//No resting and shooting over these. + return FALSE + + if(proj.firer && Adjacent(proj.firer)) + return TRUE + + if (get_dist(proj.starting, loc) <= 1) + return TRUE + + return FALSE + + var/obj/structure/S = locate(/obj/structure) in get_turf(mover) + if(S && !(S.atom_flags & ATOM_FLAG_CHECKS_BORDER) && isliving(mover)) //Climbable objects allow you to universally climb over others + return TRUE + + if(get_dir(loc, target) & dir) + return FALSE + else + return TRUE + + +//Bullshit snowflake stuff for climbing over it. +/obj/structure/warfare/barricade/do_climb(var/mob/living/user) + if(!can_climb(user)) + return + + user.visible_message("[user] starts climbing onto \the [src]!") + climbers |= user + + if(!do_after(user,(issmall(user) ? 20 : 30))) + climbers -= user + return + + if(!can_climb(user, post_climb_check=1)) + climbers -= user + return + + if(!neighbor_turf_passable()) + to_chat(user, "You can't climb there, the way is blocked.") + climbers -= user + return + + if(get_turf(user) == get_turf(src)) + user.forceMove(get_step(src, src.dir)) + else + user.forceMove(get_turf(src)) + + user.visible_message("[user] climbed over \the [src]!") + climbers -= user + +/obj/structure/warfare/barricade/can_climb(var/mob/living/user, post_climb_check=0) + if (!(atom_flags & ATOM_FLAG_CLIMBABLE) || !can_touch(user) || (!post_climb_check && (user in climbers))) + return FALSE + + if (!user.Adjacent(src)) + to_chat(user, "You can't climb there, the way is blocked.") + return FALSE + + return TRUE + + +//BARBWIRE + +/obj/item/stack/barbwire + name = "barbed wire" + desc = "Use this to place down barbwire in front of your position." + icon = 'icons/obj/warfare.dmi' + icon_state = "barbwire_item" + amount = 5 + max_amount = 5 + w_class = ITEM_SIZE_LARGE //fuck off you're not putting 30 stacks in your satchel + +/obj/item/stack/barbwire/attack_self(var/mob/user) + if(!ishuman(user)) + return + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/affecting = H.get_organ(pick("l_arm", "r_arm", "l_hand", "r_hand")) //pick limb to get cut for failed skillcheck + var/turf/T = get_step(user, user.dir) + + if(T) + if(isopenspace(T)) + return + if(turf_contains_dense_objects(T) || iswall(T)) //no 20 structures of barbed wire in one tile/in walls + to_chat(H, "There's already something there!") + return + for(var/obj/structure/object in T) + to_chat(H, "There's already something there!") + return + visible_message("[user] begins to place the [src]!") + if(do_after(user, 20)) //leave it in this statement, dont want people getting cut for getting bumped/moving during assembly + if(H.statscheck(skills = H.SKILL_LEVEL(engineering)) > CRIT_FAILURE) //Considering how useless barbwire seems to be, everyone can now spam it. + to_chat(H, "You assemble the [src]!") + amount-- + if(amount<=0) + qdel(src) + new /obj/structure/barbwire(T) + return + else + playsound(loc, 'sound/effects/glass_step.ogg', 50, TRUE) + if (affecting.status & ORGAN_ROBOT) + return + if (affecting.take_damage(3, FALSE)) //stop trying to put down barb wire without the skill dumbass + H.UpdateDamageIcon() + H.updatehealth() + to_chat(H, "You fail to assemble the [src], cutting your [affecting.name]!") + +/obj/structure/barbwire + name = "barbed wire" + desc = "Passing through this looks painful." + icon = 'icons/obj/warfare.dmi' + icon_state = "barbwire" + anchored = TRUE + plane = ABOVE_HUMAN_PLANE + layer = BASE_MOB_LAYER + +/obj/structure/barbwire/ex_act(severity) + switch (severity) + if (3) + if (prob(50)) + qdel(src) + else + qdel(src) + +/obj/structure/barbwire/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + return TRUE + +/obj/structure/barbwire/Crossed(AM as mob|obj) + if (ismob(AM)) + var/mob/M = AM + if (ishuman(M)) + var/mob/living/carbon/human/H = M + if (prob (33)) + playsound(loc, "stab_sound", 50, TRUE) + var/obj/item/organ/external/affecting = H.get_organ(pick("l_foot", "r_foot", "l_leg", "r_leg")) + if (affecting.status & ORGAN_ROBOT) + return + if (affecting.take_damage(3, FALSE)) + H.UpdateDamageIcon() + H.updatehealth() + to_chat(H, "Your [affecting.name] gets slightly cut by \the [src]!") + else if (prob (33)) + playsound(loc, "stab_sound", 50, TRUE) + var/obj/item/organ/external/affecting = H.get_organ(pick("l_foot", "r_foot", "l_leg", "r_leg")) + if (affecting.status & ORGAN_ROBOT) + return + if (affecting.take_damage(8, FALSE)) + H.UpdateDamageIcon() + H.updatehealth() + to_chat(H, "Your [affecting.name] gets cut by \the [src]!") + else + playsound(loc, "stab_sound", 50, TRUE) + var/obj/item/organ/external/affecting = H.get_organ(pick("l_foot", "r_foot", "l_leg", "r_leg")) + if (affecting.status & ORGAN_ROBOT) + return + if (affecting.take_damage(13, FALSE)) + H.UpdateDamageIcon() + H.updatehealth() + to_chat(H, "Your [affecting.name] gets deeply cut by \the [src]!") + return ..() + +/obj/structure/barbwire/Uncross(AM as mob) + if(ismob(AM)) + var/mob/M = AM + if (ishuman(M)) + if(prob(50)) + M.visible_message("[M] struggle to free themselves from the barbed wire!") + var/mob/living/carbon/human/H = M + playsound(loc, "stab_sound", 50, TRUE) + var/obj/item/organ/external/affecting = H.get_organ(pick("l_foot", "r_foot", "l_leg", "r_leg")) + if (affecting.status & ORGAN_ROBOT) + return + if (affecting.take_damage(8, FALSE)) + H.UpdateDamageIcon() + H.updatehealth() + return FALSE + else + M.visible_message("[M] frees themself from the barbed wire!") + return TRUE + return ..() + +/obj/structure/barbwire/attackby(obj/item/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/wirecutters)) + if (anchored) + user.visible_message("\The [user] starts to cut through \the [src] with [W].") + if (!do_after(user,30)) + user.visible_message("\The [user] decides not to cut through the \the [src].") + return + user.visible_message("\The [user] finishes cutting through \the [src], destroying it!") //will think about adding chance to recover barbed wire piece with engineering skill + playsound(loc, 'sound/items/Wirecutter.ogg', 50, TRUE) + qdel(src) + return + + else if (istype(W, /obj/item/weapon/material/sword)) + if (anchored) + user.visible_message("\The [user] starts to cut through \the [src] with [W].") + if (!do_after(user,60)) + user.visible_message("\The [user] decides not to cut through \the [src].") + return + else + user.visible_message("\The [user] finishes cutting through \the [src], destroying it!") + playsound(loc, 'sound/items/Wirecutter.ogg', 50, TRUE) + qdel(src) + return + +/obj/structure/anti_tank + name = "metal barricade" + desc = "Usually found in no man\'s land IN YOUR FUCKING WAY. It's dense enough to block bullets, don't even try to fucking shoot over it." + icon = 'icons/obj/warfare.dmi' + icon_state = "anti-tank" + anchored = TRUE + density = TRUE + plane = ABOVE_OBJ_PLANE + layer = BASE_MOB_LAYER + atom_flags = ATOM_FLAG_CLIMBABLE + + +/obj/structure/anti_tank/can_climb(var/mob/living/user, post_climb_check=0) + if(!iswarfare()) + return TRUE + + + if(istype(get_area(src), /area/warfare/battlefield/no_mans_land))//We're trying to go into no man's land? + if(locate(/obj/item/device/boombox) in user)//Locate the boombox. + to_chat(user, "I can't bring this with me onto the battlefield. Wouldn't want to lose it.")//No you fucking don't. + return //Keep that boombox at base asshole. + if(locate(/obj/item/weapon/storage) in user)//Gotta check storage as well. + var/obj/item/weapon/storage/S = locate() in user + if(locate(/obj/item/device/boombox) in S) + to_chat(user, "I can't bring this with me onto the battlefield. Wouldn't want to lose it.") + return + + if(!SSWarfare.battle_time) + return FALSE + return TRUE + + +/obj/item/projectile/bullet/pellet/fragment/landmine + damage = 100 + range_step = 2 //controls damage falloff with distance. projectiles lose a "pellet" each time they travel this distance. Can be a non-integer. + base_spread = 0 //causes it to be treated as a shrapnel explosion instead of cone + spread_step = 20 + range = 3 //dont kill everyone on the screen + +/obj/item/landmine + name = "landmine" + desc = "Use it to place a landmine in front of you. Beee careful..." + icon = 'icons/obj/warfare.dmi' + icon_state = "mine_item" + + +/obj/item/landmine/attack_self(var/mob/user) + var/turf/T = get_step(user, user.dir) + if(T) + if(isopenspace(T)) + return + visible_message("[user] begins to place the mine!") + if(do_after(user, 20)) + qdel(src) + new /obj/structure/landmine(T) + + +/obj/structure/landmine + name = "landmine" + desc = "If you step on this you'll probably fucking die." + icon = 'icons/obj/warfare.dmi' + icon_state = "mine" + anchored = TRUE + density = FALSE + var/armed = FALSE//Whether or not it will blow up. + var/can_be_armed = TRUE//Whether or not it can be armed to blow up. Disarmed mines won't blow. + +/obj/structure/landmine/New() + ..() + if(prob(15)) + desc = "This mushroom is not for picking." + +/obj/structure/landmine/proc/blow() + GLOB.mines_tripped++ + fragmentate(get_turf(src), 20, 2, list(/obj/item/projectile/bullet/pellet/fragment/landmine)) + explosion(loc, 1, 1, 1, 1) + qdel(src) + + +/obj/structure/landmine/update_icon() + if(!can_be_armed) + icon_state = "mine_disarmed" + + +/obj/structure/landmine/attackby(obj/item/W as obj, mob/user as mob) + if(!ishuman(user)) + return + var/mob/living/carbon/human/H = user + if(istype(W, /obj/item/weapon/wirecutters)) + if(!can_be_armed) + return + H.visible_message("[H] begins to disarm the landmine...") + if(do_after(user,50)) + if(H.statscheck(skills = H.SKILL_LEVEL(engineering)) >= SUCCESS) + armed = FALSE + can_be_armed = FALSE + to_chat(H, "You successfully disarm the [src]") + GLOB.mines_disarmed++ + playsound(src, 'sound/items/Wirecutter.ogg', 100, FALSE) + update_icon() + return + blow() + if(istype(W, /obj/item/weapon/shovel)) + if(!can_be_armed) + H.visible_message("[H] begins to dig up the landmine...") + playsound(src, 'sound/effects/dig_shovel.ogg', 40, FALSE) + if(do_after(user,50)) + to_chat(H, "You successfully dig up the [src]") + qdel(src) + return + +/obj/structure/landmine/Crossed(var/mob/living/M as mob) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.isChild())//Kids don't set off landmines. + return + if(!M.throwing && !armed && can_be_armed) + to_chat(M, "You hear a sickening click!") + playsound(src, 'sound/effects/mine_arm.ogg', 100, FALSE) + armed = TRUE + +/obj/structure/landmine/Uncrossed(var/mob/living/M as mob) + if(istype(M)) + if(armed) + blow() + + + +//Activate this to win! +/obj/structure/destruction_computer + name = "Point Of No Return" + desc = "DON'T LET THE ENEMY TOUCH THIS!" + icon = 'icons/obj/warfare.dmi' + icon_state = "destruct" + anchored = TRUE + density = TRUE + var/faction = null + var/activated = FALSE + var/countdown_time + var/doomsday_timer + +/obj/structure/destruction_computer/New() + ..() + name = "[faction] [name]" + countdown_time = config.warfare_end_time MINUTES //Countdown time is in minutes because seconds is FUCKED. + +/obj/structure/destruction_computer/attack_hand(mob/user) + . = ..() + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.warfare_faction == faction) + if(!activated) + return + if(!H.doing_something) + H.doing_something = TRUE + if(do_after(H,100)) + user.unlock_achievement(new/datum/achievement/deactivate()) + activated = FALSE + deltimer(doomsday_timer) + to_world(uppertext("[H.warfare_faction] have disarmed the [src]!")) + playsound(src, 'sound/effects/mine_arm.ogg', 100, FALSE) + sound_to(world, 'sound/effects/ponr_activate.ogg') + H.doing_something = FALSE + H.doing_something = FALSE + else + to_chat(H, "I'm already disarming the device!") + + else + if(activated) + return + if(!H.doing_something) + H.doing_something = TRUE + if(do_after(H, 30)) + user.unlock_achievement(new/datum/achievement/point_of_no_return()) + playsound(src, 'sound/effects/mine_arm.ogg', 100, FALSE) + sound_to(world, 'sound/effects/ponr_activate.ogg') + to_world(uppertext("[H.warfare_faction] have activated the [src]! They will achieve victory in [countdown_time/10] seconds!")) + activated = TRUE + doomsday_timer = addtimer(CALLBACK(src,/obj/structure/destruction_computer/proc/kaboom), countdown_time, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_NO_HASH_WAIT|TIMER_OVERRIDE) + H.doing_something = FALSE + H.doing_something = FALSE + else + to_chat(H, "I'm already arming the device!") + +/obj/structure/destruction_computer/proc/kaboom() + SSWarfare.end_warfare(faction)//really simple I know. + +/obj/structure/destruction_computer/red + faction = RED_TEAM + +/obj/structure/destruction_computer/blue + faction = BLUE_TEAM + + +/obj/structure/banner + name = "Banner" + desc = "The glorious banner of uh... your side." + icon = 'icons/obj/stationobjs.dmi' + anchored = TRUE + density = FALSE + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + +/obj/structure/banner/red + icon_state = "red" + +/obj/structure/banner/red/small + icon_state = "redsmall" + +/obj/structure/banner/blue + icon_state = "blue" + +/obj/structure/banner/blue/small + icon_state = "bluesmall" \ No newline at end of file diff --git a/code/game/gamemodes/warfare/trenches.dm b/code/game/gamemodes/warfare/trenches.dm new file mode 100644 index 00000000..7cbb5361 --- /dev/null +++ b/code/game/gamemodes/warfare/trenches.dm @@ -0,0 +1,163 @@ +/turf/simulated/floor/trenches + name = "trench" + icon = 'icons/turf/trenches_turfs.dmi' + icon_state = "wood0" + can_smooth = TRUE + movement_delay = 0.5 + +/obj/structure/trench_wall + name = "trench wall" + icon = 'icons/turf/trenches_turfs.dmi' + icon_state = "trench" + density = FALSE + + + +/turf/simulated/floor/trenches/relativewall() + var/junction = 0 + for(var/turf/simulated/floor/trenches/W in orange(src,1)) + if(abs(src.x-W.x)-abs(src.y-W.y)) + junction |= get_dir(src,W) + icon_state = "wood[junction]" + +/turf/simulated/floor/trenches/ex_act()//No blowing this up. + return + + +/turf/simulated/floor/trenches/Initialize() + . = ..() + relativewall_neighbours() +/* spawn(5) + update_icon() + +/turf/simulated/floor/trenches/update_icon() + overlays.Cut() + var/image/snow_overlay = image('icons/obj/warfare.dmi', "snow_1", dir = pick(GLOB.alldirs)) + snow_overlay.plane = ABOVE_TURF_PLANE + overlays += snow_overlay + //snow_overlay.turf_decal_layerise() +*/ + + +/turf/simulated/floor/trench + icon = 'icons/obj/warfare.dmi' + icon_state = "trench" + name = "trench" + movement_delay = 0.5 + has_coldbreath = TRUE + +/turf/simulated/floor/trench/ex_act(severity) + return + +/turf/simulated/floor/trench/update_dirt() + return // Dirt doesn't doesn't become dirty + +/turf/simulated/floor/trench/New() + ..() + if(!locate(/obj/effect/lighting_dummy/daylight) in src) + new /obj/effect/lighting_dummy/daylight(src) + dir = pick(GLOB.alldirs) + update_icon() + +/turf/simulated/floor/trench/RightClick(mob/living/user) + if(!CanPhysicallyInteract(user)) + return + var/obj/item/weapon/shovel/S = user.get_active_hand() + if(!istype(S)) + return + if(!user.doing_something) + user.doing_something = TRUE + if(src.density) + user.doing_something = FALSE + return + for(var/obj/structure/object in contents) + if(object) + to_chat(user, "There are things in the way.") + user.doing_something = FALSE + return + playsound(src, 'sound/effects/dig_shovel.ogg', 50, 0) + visible_message("[user] begins fill in the trench!") + if(do_after(user, backwards_skill_scale(user.SKILL_LEVEL(engineering)) * 5)) + for(var/mob/M in src) + if(ishuman(M)) + M.pixel_y = 0 + ChangeTurf(/turf/simulated/floor/dirty) + update_trench_shit() + visible_message("[user] finishes filling in trench.") + playsound(src, 'sound/effects/empty_shovel.ogg', 50, 0) + user.doing_something = FALSE + + user.doing_something = FALSE + + else + to_chat(user, "You're already digging.") + + +/turf/simulated/floor/proc/update_trench_layers() + overlays.Cut() + for(var/direction in GLOB.cardinal) + var/turf/turf_to_check = get_step(src,direction) + if(istype(turf_to_check, /turf/simulated/floor/trench)) + continue + if(istype(turf_to_check, /turf/space) || istype(turf_to_check, /turf/simulated/floor) || istype(turf_to_check, /turf/simulated/floor/exoplanet/water/shallow) || istype(turf_to_check, /turf/simulated/wall)) + var/image/trench_side = image('icons/obj/warfare.dmi', "trench_side", dir = turn(direction, 180)) + trench_side.turf_decal_layerise() + switch(direction) + if(NORTH) + trench_side.pixel_y += ((world.icon_size) - 22) + if(SOUTH) + trench_side.pixel_y -= ((world.icon_size) - 16) + trench_side.plane = ABOVE_OBJ_PLANE + if(EAST) + trench_side.pixel_x += (world.icon_size) + trench_side.plane = ABOVE_OBJ_PLANE + trench_side.layer = BASE_MOB_LAYER + if(WEST) + trench_side.pixel_x -= (world.icon_size) + trench_side.plane = ABOVE_OBJ_PLANE + trench_side.layer = BASE_MOB_LAYER + overlays += trench_side + +/turf/simulated/floor/trench/update_icon() + update_trench_shit() + + +/turf/simulated/floor/proc/update_trench_shit() + for(var/direction in GLOB.cardinal) + var/turf/turf_to_check = get_step(src,direction) + if(istype(turf_to_check, /turf/simulated/floor/trench))//Rebuild our neighbors. + var/turf/simulated/floor/trench/T = turf_to_check + T.update_trench_layers() + continue + + update_trench_layers() + +/turf/simulated/floor/trench/Crossed(var/mob/living/carbon/human/M) + if(istype(M)) + if(!M.throwing) + if(M.client) + M.fov_mask.screen_loc = "1,0.8" + M.fov.screen_loc = "1,0.8" + if(M.crouching) + M.pixel_y = -12 + else + M.pixel_y = -8 + + M.plane = LYING_HUMAN_PLANE + + var/trench_check = 0 //If we're not up against a trench wall, we don't want to stay zoomed in. + for(var/direction in GLOB.cardinal) + var/turf/turf_to_check = get_step(M.loc,direction)//So get all of the turfs around us. + if(istype(turf_to_check, /turf/simulated/floor/trench))//And if they're a trench, count it. + trench_check++ + if(trench_check >= 4)//We're surrounded on all sides by trench. We unzoom. + if(M.zoomed)//If we're zoomed that is. + M.do_zoom() + +/turf/simulated/floor/trench/Uncrossed(var/mob/living/carbon/human/M) + if(istype(M)) + if(M.client) + M.fov_mask.screen_loc = "1,1" + M.fov.screen_loc = "1,1" + M.pixel_y = 0 + M.plane = HUMAN_PLANE diff --git a/code/game/gamemodes/warfare/turfs.dm b/code/game/gamemodes/warfare/turfs.dm new file mode 100644 index 00000000..8933bb80 --- /dev/null +++ b/code/game/gamemodes/warfare/turfs.dm @@ -0,0 +1,385 @@ + +//Dirt! +/turf/simulated/floor/dirty + name = "dirt" //"snowy dirt" + //icon = 'icons/turf/snow.dmi' + //icon_state = "snow_3" + icon = 'icons/turf/dirt.dmi' + icon_state = "dirt1" + movement_delay = 1 + has_coldbreath = TRUE + atom_flags = ATOM_FLAG_CLIMBABLE + var/has_light = TRUE + var/can_generate_water = TRUE + var/can_be_dug = TRUE + +/turf/simulated/floor/dirty/fake + atom_flags = null + can_generate_water = FALSE + can_be_dug = FALSE + +/turf/simulated/floor/dirty/tough //Can't dig this. + name = "tough dirt" + desc = "This dirt doesn't look diggable." + can_be_dug = FALSE + +/turf/simulated/floor/dirty/tough/fake //Can't be click dragged on. + atom_flags = null + +/turf/simulated/floor/dirty/tough/ex_act(severity)//Can't be blown up. + return + +/turf/simulated/floor/dirty/CanPass(atom/movable/mover, turf/target) + if(ishuman(mover)) + if(istype(get_turf(mover), /turf/simulated/floor/trench)) + if(!mover.pulledby) + return FALSE + + return TRUE + +/turf/simulated/floor/dirty/can_climb(var/mob/living/user, post_climb_check=0) + if (!(atom_flags & ATOM_FLAG_CLIMBABLE) || !can_touch(user)) + return FALSE + + if (!user.Adjacent(src)) + to_chat(user, "You can't climb there, the way is blocked.") + return FALSE + + return TRUE + +/turf/simulated/floor/dirty/do_climb(var/mob/living/user) + if(!can_climb(user)) + return + + if(istype(get_area(src), /area/warfare/battlefield/no_mans_land))//We're trying to go into no man's land? + if(locate(/obj/item/device/boombox) in user)//Locate the boombox. + to_chat(user, "I can't bring this with me onto the battlefield. Wouldn't want to lose it.")//No you fucking don't. + return //Keep that boombox at base asshole. + if(locate(/obj/item/weapon/storage) in user)//Gotta check storage as well. + var/obj/item/weapon/storage/S = locate() in user + if(locate(/obj/item/device/boombox) in S) + to_chat(user, "I can't bring this with me onto the battlefield. Wouldn't want to lose it.") + return + + user.visible_message("[user] starts climbing onto \the [src]!") + climbers |= user + + if(!can_climb(user)) + climbers -= user + return + + if(!do_after(user,15)) + climbers -= user + return + + user.forceMove(get_turf(src)) + user.visible_message("[user] climbed onto \the [src]!") + climbers -= user + +/turf/simulated/floor/dirty/MouseDrop_T(mob/target, mob/user) + var/mob/living/H = user + if(istype(H) && can_climb(H) && target == user) + do_climb(target) + else + return ..() + +/turf/simulated/floor/dirty/indestructable/snow + name = "snow" + icon = 'icons/turf/snow.dmi' + icon_state = "snow" + +/turf/simulated/floor/dirty/indestructable/snow/New() + icon_state = pick("snow[rand(1,12)]","snow0") + ..() + +/turf/simulated/floor/dirty/New() + ..() + temperature = T0C - 60 + //icon_state = pick("snow[rand(1,12)]","snow0") + dir = pick(GLOB.alldirs) + if(!locate(/obj/effect/lighting_dummy/daylight) in src) + new /obj/effect/lighting_dummy/daylight(src) + spawn(1) + overlays.Cut() + if(loc.type != /area/warfare/battlefield/no_mans_land) // no base puddles + return + if(!can_generate_water)//This type can't generate water so don't bother. + return + if(prob(1)) // puddle generation, every turf has a probability to become a water tile, then it spreads itself out + var/list/waters = list() // list of already generated water tiles + ChangeTurf(/turf/simulated/floor/exoplanet/water/shallow)//This is actually just a mud tile, we spawn water with it to make it looks like it's water. + waters += src + for(var/p in list(50,25,10,3,1)) // run through probabilities, spreading water out + for(var/turf/water in waters) + for(var/turf/simulated/floor/possible_water in range(1, water)) + if(prob(p) && !LAZYLEN(possible_water.contents) && !istype(possible_water, /turf/simulated/floor/exoplanet/water/shallow)) + if(/obj/structure in possible_water)//If there's any objects here return. + return + if(istype(possible_water, /turf/simulated/floor/trench))//No trenches becoming water please. + return + if(istype(possible_water, /turf/simulated/floor/dirty/fake))//Do not override the fake hacky dirt turfs please. + return + possible_water.ChangeTurf(/turf/simulated/floor/exoplanet/water/shallow) + waters += possible_water + +/turf/simulated/floor/dirty/attackby(obj/O as obj, mob/living/user as mob) + if(istype(O, /obj/item/weapon/shovel)) + if(!user.doing_something) + user.doing_something = TRUE + if(src.density) + user.doing_something = FALSE + return + for(var/obj/structure/object in contents) + if(object) + to_chat(user, "There are things in the way.") + user.doing_something = FALSE + return + playsound(src, 'sound/effects/dig_shovel.ogg', 50, 0) + visible_message("[user] begins to dig some dirt cover!") + if(do_after(user, (backwards_skill_scale(user.SKILL_LEVEL(engineering)) * 5))) + new /obj/structure/dirt_wall(src) + visible_message("[user] finishes digging the dirt cover.") + playsound(src, 'sound/effects/empty_shovel.ogg', 50, 0) + + user.doing_something = FALSE + + else + to_chat(user, "You're already digging.") + +/turf/simulated/floor/dirty/RightClick(mob/living/user) + if(!CanPhysicallyInteract(user)) + return + var/obj/item/weapon/shovel/S = user.get_active_hand() + if(!istype(S)) + return + if(!can_be_dug)//No escaping to mid early. + return + if(!user.doing_something) + user.doing_something = TRUE + if(src.density) + user.doing_something = FALSE + return + for(var/obj/structure/object in contents) + if(object) + to_chat(user, "There are things in the way.") + user.doing_something = FALSE + return + playsound(src, 'sound/effects/dig_shovel.ogg', 50, 0) + visible_message("[user] begins to dig a trench!") + if(do_after(user, backwards_skill_scale(user.SKILL_LEVEL(engineering)) * 5)) + ChangeTurf(/turf/simulated/floor/trench) + visible_message("[user] finishes digging the trench.") + playsound(src, 'sound/effects/empty_shovel.ogg', 50, 0) + user.doing_something = FALSE + + user.doing_something = FALSE + + else + to_chat(user, "You're already digging.") + +/turf/simulated/floor/dirty/update_dirt() + return // Dirt doesn't doesn't become dirty + +/turf/simulated/floor/dirty/indestructable + desc = "This dirt seems tougher than most other dirts." + +/turf/simulated/floor/dirty/indestructable/mud + name = "mud" + desc = "This mud looks tougher than most other muds." + icon_state = "mud" + +/turf/simulated/floor/dirty/indestructable/mud/New() + dir = pick(GLOB.alldirs) + ..() + +/turf/simulated/floor/dirty/indestructable/ex_act(severity)//Can't be blown up. + return + +/turf/simulated/floor/dirty/indestructable/lightless + has_light = FALSE + +/turf/simulated/floor/dirty/indestructable/lightless/has_trees + +///////// +//WATER// +///////// +/turf/simulated/floor/exoplanet/water/shallow + name = "water" + icon = 'icons/turf/dirt.dmi'//This appears under the water. + icon_state = "mud" + movement_delay = 3 + mudpit = 1 + has_coldbreath = TRUE + atom_flags = ATOM_FLAG_CLIMBABLE + +/turf/simulated/floor/exoplanet/water/shallow/update_dirt() + return + +/turf/simulated/floor/exoplanet/water/shallow/ex_act(severity) + return + +/turf/simulated/floor/exoplanet/water/shallow/CanPass(atom/movable/mover, turf/target) + if(ishuman(mover)) + if(istype(get_turf(mover), /turf/simulated/floor/trench)) + if(!mover.pulledby) + return FALSE + + return TRUE + +/turf/simulated/floor/exoplanet/water/shallow/can_climb(var/mob/living/user, post_climb_check=0) + if (!(atom_flags & ATOM_FLAG_CLIMBABLE) || !can_touch(user)) + return FALSE + + if (!user.Adjacent(src)) + to_chat(user, "You can't climb there, the way is blocked.") + return FALSE + + return TRUE + +/turf/simulated/floor/exoplanet/water/shallow/do_climb(var/mob/living/user) + if(!can_climb(user)) + return + + user.visible_message("[user] starts climbing onto \the [src]!") + climbers |= user + + if(!can_climb(user)) + climbers -= user + return + + if(!do_after(user,15)) + climbers -= user + return + + user.forceMove(get_turf(src)) + user.visible_message("[user] climbed onto \the [src]!") + climbers -= user + +/turf/simulated/floor/exoplanet/water/shallow/MouseDrop_T(mob/target, mob/user) + var/mob/living/H = user + if(istype(H) && can_climb(H) && target == user) + if(istype(get_area(src), /area/warfare/battlefield/no_mans_land))//We're trying to go into no man's land? + if(locate(/obj/item/device/boombox) in user)//Locate the boombox. + to_chat(user, "I can't bring this with me onto the battlefield. Wouldn't want to lose it.")//No you fucking don't. + return //Keep that boombox at base asshole. + if(locate(/obj/item/weapon/storage) in user)//Gotta check storage as well. + var/obj/item/weapon/storage/S = locate() in user + if(locate(/obj/item/device/boombox) in S) + to_chat(user, "I can't bring this with me onto the battlefield. Wouldn't want to lose it.") + return + do_climb(target) + else + return ..() + +/turf/simulated/floor/exoplanet/water/shallow/Cross(var/atom/A)//People who are on fire go out. + if(isliving(A)) + var/mob/living/L = A + L.ExtinguishMob() + +/turf/simulated/floor/exoplanet/water/shallow/New() + ..() + if(!locate(/obj/effect/lighting_dummy/daylight) in src) + new /obj/effect/lighting_dummy/daylight(src) + temperature = T0C - 80 + for(var/obj/effect/water/bottom/B in src) + if(B) + qdel(B) + for(var/obj/effect/water/top/T in src) + if(T) + qdel(T) + + new /obj/effect/water/bottom(src)//Put it right on top of the water so that they look like they're the same. + new /obj/effect/water/top(src) + spawn(5) + update_icon() + for(var/turf/simulated/floor/exoplanet/water/shallow/T in range(1)) + T.update_icon() + +/turf/simulated/floor/exoplanet/water/shallow/update_icon() + + overlays.Cut() + for(var/direction in GLOB.cardinal) + var/turf/turf_to_check = get_step(src,direction) + if(istype(turf_to_check, /turf/simulated/floor/exoplanet/water/shallow)) + continue + + else if(istype(turf_to_check, /turf/simulated)) + var/image/water_side = image('icons/obj/warfare.dmi', "over_water1", dir = direction)//turn(direction, 180)) + water_side.plane = EFFECTS_BELOW_LIGHTING_PLANE + + overlays += water_side + var/image/wave_overlay = image('icons/obj/warfare.dmi', "waves") + overlays += wave_overlay + +/turf/simulated/floor/exoplanet/water/shallow/Destroy() + . = ..() + for(var/obj/effect/water/bottom/B in src) + qdel(B) + for(var/obj/effect/water/top/T in src) + qdel(T) + +/turf/simulated/floor/exoplanet/water/shallow/attackby(obj/item/O, mob/user) + if(istype(O, /obj/item/weapon/reagent_containers)) + var/obj/item/weapon/reagent_containers/RG = O + if (istype(RG) && RG.is_open_container()) + RG.reagents.add_reagent(/datum/reagent/water, min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this)) + user.visible_message("[user] fills \the [RG] using \the [src].","You fill \the [RG] using \the [src].") + return 1 + + if (istype(O, /obj/item/stack/duckboard)) + var/obj/item/stack/duckboard/S = O + if (S.get_amount() < 1) + return + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + S.use(1) + ChangeTurf(/turf/simulated/floor/trenches) + return + +/turf/simulated/floor/exoplanet/water/shallow/ChangeTurf(turf/N, tell_universe, force_lighting_update) + var/obj/effect/water/top/T = locate() in loc + if(T) + qdel(T) + var/obj/effect/water/bottom/B = locate() in loc + if(B) + qdel(B) + . = ..() + for(var/turf/simulated/floor/exoplanet/water/shallow/S in range(1)) + S.update_icon() + + +/obj/effect/water/top//This one appears over objects but under mobs. + name = "water" + icon = 'icons/obj/warfare.dmi' + icon_state = "trench_water_top" + plane = ABOVE_OBJ_PLANE + layer = ABOVE_OBJ_LAYER + density = FALSE + anchored = TRUE + mouse_opacity = FALSE + +/obj/effect/water/bottom//This one appears over mobs. + name = "water" + icon = 'icons/obj/warfare.dmi' + icon_state = "trench_water_bottom" + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + density = FALSE + anchored = TRUE + mouse_opacity = FALSE//Don't want this being clicked. + +/turf/simulated/floor/exoplanet/water/update_dirt() + return // Water doesn't become dirty + + + +/obj/item/stack/duckboard + name = "duckboards" + singular_name = "duckboard" + w_class = 1 + force = 0 + throwforce = 0 + max_amount = 20 + gender = PLURAL + desc = "For building over water." + icon = 'icons/turf/trenches_turfs.dmi' + icon_state = "wood0" \ No newline at end of file diff --git a/code/game/gamemodes/warfare/warfare.dm b/code/game/gamemodes/warfare/warfare.dm new file mode 100644 index 00000000..398144b0 --- /dev/null +++ b/code/game/gamemodes/warfare/warfare.dm @@ -0,0 +1,70 @@ +/area + var/is_mortar_area = FALSE + +// check /datum/controller/subsystem/warfare for warfare vars and procs + +/datum/game_mode/warfare + name = "Warfare" + round_description = "All out warfare on the battlefront!" + extended_round_description = "Invade the enemies trenches and then destroy them! War is heck! Expect to die a lot!" + config_tag = "warfare" + required_players = 0 + auto_recall_shuttle = TRUE //If the shuttle is even somehow called. + +/datum/game_mode/warfare/declare_completion() + SSWarfare.declare_completion() + +/datum/game_mode/warfare/post_setup() + ..() + SSWarfare.begin_countDown() + + +/datum/game_mode/warfare/check_finished() + if(SSWarfare.check_completion()) + return TRUE + ..() + + +/mob/living/carbon/human/proc/handle_warfare_death() + if(!iswarfare()) + return + if(is_npc) + return + if(src in SSWarfare.blue.team)//If in the team. + SSWarfare.blue.left--//Take out a life. + SSWarfare.blue.team -= src//Remove them from the team. + if(src in SSWarfare.red.team)//Same here. + SSWarfare.red.left-- + SSWarfare.red.team -= src + + if(client) + client.warfare_deaths++ + + // as far as i know there are no immediate jobtype vars in mind or human, so here we go + if(job_master?.GetJobByTitle(job)?.type == /datum/job/soldier/red_soldier/captain) + for(var/X in SSWarfare.red.team) + var/mob/living/carbon/human/H = X + H.add_event("captain death", /datum/happiness_event/captain_death) + if(job_master?.GetJobByTitle(job)?.type == /datum/job/soldier/blue_soldier/captain) + for(var/X in SSWarfare.blue.team) + var/mob/living/carbon/human/H = X + H.add_event("captain death", /datum/happiness_event/captain_death) + if(job_master?.GetJobByTitle(job)?.open_when_dead)//When the person dies who has this job, free this role again. + job_master.allow_one_more(job) + + if(!GLOB.first_death) + GLOB.first_death = real_name + if(!GLOB.first_death_happened) + GLOB.first_death_happened = TRUE + if(!GLOB.final_words) + GLOB.final_words = last_words + +/mob/living/carbon/human/proc/handle_warfare_life() + if(!iswarfare()) + return + + if(tracking) + tracking.update() + +/proc/iswarfare() + return (istype(ticker.mode, /datum/game_mode/warfare) || master_mode=="warfare") diff --git a/code/game/gamemodes/warfare/warfare_gas.dm b/code/game/gamemodes/warfare/warfare_gas.dm new file mode 100644 index 00000000..0286edb3 --- /dev/null +++ b/code/game/gamemodes/warfare/warfare_gas.dm @@ -0,0 +1,16 @@ +//That's just the way it goes on this bitch of an earth. +/datum/reagent/toxin/mustard_gas + name = "Mustard Gas" + description = "Doesn't go on hotdogs" + reagent_state = REAGENT_GAS + color = "#a2cd5a" + strength = 30 + touch_met = 5 + +/datum/reagent/toxin/mustard_gas/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) + if(istype(M)) + if(M.wear_mask && (M.wear_mask.item_flags & ITEM_FLAG_AIRTIGHT)) + return + M.take_organ_damage(0, strength * 0.1) + + M.take_overall_damage(0, rand(1,15)) \ No newline at end of file diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm new file mode 100644 index 00000000..e8f82a89 --- /dev/null +++ b/code/game/gamemodes/wizard/wizard.dm @@ -0,0 +1,9 @@ +/datum/game_mode/wizard + name = "Wizard" + round_description = "There is a SPACE WIZARD onboard. You can't let the magician achieve their objectives!" + extended_round_description = "A powerful entity capable of manipulating the elements around him, most commonly referred to as a 'wizard', has made their way onboard. 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 devastation." + config_tag = "wizard" + required_players = 20 + required_enemies = 1 + end_on_antag_death = TRUE + antag_tags = list(MODE_WIZARD) diff --git a/code/game/images.dm b/code/game/images.dm new file mode 100644 index 00000000..e8b84493 --- /dev/null +++ b/code/game/images.dm @@ -0,0 +1,3 @@ +/image/Destroy() + ..() + return QDEL_HINT_HARDDEL diff --git a/code/game/jobs/_access_defs.dm b/code/game/jobs/_access_defs.dm new file mode 100644 index 00000000..92ab02f7 --- /dev/null +++ b/code/game/jobs/_access_defs.dm @@ -0,0 +1,15 @@ +#define ACCESS_REGION_NONE -1 +#define ACCESS_REGION_ALL 0 +#define ACCESS_REGION_SECURITY 1 +#define ACCESS_REGION_MEDBAY 2 +#define ACCESS_REGION_RESEARCH 3 +#define ACCESS_REGION_ENGINEERING 4 +#define ACCESS_REGION_COMMAND 5 +#define ACCESS_REGION_GENERAL 6 +#define ACCESS_REGION_SUPPLY 7 + +#define ACCESS_TYPE_NONE 1 +#define ACCESS_TYPE_CENTCOM 2 +#define ACCESS_TYPE_STATION 4 +#define ACCESS_TYPE_SYNDICATE 8 +#define ACCESS_TYPE_ALL (ACCESS_TYPE_NONE|ACCESS_TYPE_CENTCOM|ACCESS_TYPE_STATION|ACCESS_TYPE_SYNDICATE) diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm new file mode 100644 index 00000000..48c8480c --- /dev/null +++ b/code/game/jobs/access.dm @@ -0,0 +1,258 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/obj/var/list/req_access = list() +/obj/var/list/req_one_access = list() + +//returns 1 if this mob has sufficient access to use this object +/obj/proc/allowed(mob/M) + //check if it doesn't require any access at all + if(src.check_access(null)) + return 1 + if(!istype(M)) + return 0 + return check_access_list(M.GetAccess()) + +/atom/movable/proc/GetAccess() + var/obj/item/weapon/card/id/id = GetIdCard() + return id ? id.GetAccess() : list() + +/atom/movable/proc/GetIdCard() + return null + +/obj/proc/check_access(obj/item/I) + return check_access_list(I ? I.GetAccess() : list()) + +/obj/proc/check_access_list(var/list/L) + if(!req_access) req_access = list() + if(!req_one_access) req_one_access = list() + if(!istype(L, /list)) return 0 + return has_access(req_access, req_one_access, L) + +/proc/has_access(var/list/req_access, var/list/req_one_access, var/list/accesses) + for(var/req in req_access) + if(!(req in accesses)) //doesn't have this access + return 0 + if(req_one_access.len) + for(var/req in req_one_access) + if(req in accesses) //has an access from the single access list + return 1 + return 0 + return 1 + +/proc/get_centcom_access(job) + switch(job) + if("VIP Guest") + return list(access_cent_general) + if("Custodian") + return list(access_cent_general, access_cent_living, access_cent_storage) + if("Thunderdome Overseer") + return list(access_cent_general, access_cent_thunder) + if("Intel Officer") + return list(access_cent_general, access_cent_living) + if("Medical Officer") + return list(access_cent_general, access_cent_living, access_cent_medical) + if("Death Commando") + return list(access_cent_general, access_cent_specops, access_cent_living, access_cent_storage) + if("Research Officer") + return list(access_cent_general, access_cent_specops, access_cent_medical, access_cent_teleporter, access_cent_storage) + if("BlackOps Commander") + return list(access_cent_general, access_cent_thunder, access_cent_specops, access_cent_living, access_cent_storage, access_cent_creed) + if("Supreme Commander") + return get_all_centcom_access() + +/var/list/datum/access/priv_all_access_datums +/proc/get_all_access_datums() + if(!priv_all_access_datums) + priv_all_access_datums = init_subtypes(/datum/access) + priv_all_access_datums = dd_sortedObjectList(priv_all_access_datums) + + return priv_all_access_datums.Copy() + +/var/list/datum/access/priv_all_access_datums_id +/proc/get_all_access_datums_by_id() + if(!priv_all_access_datums_id) + priv_all_access_datums_id = list() + for(var/datum/access/A in get_all_access_datums()) + priv_all_access_datums_id["[A.id]"] = A + + return priv_all_access_datums_id.Copy() + +/var/list/datum/access/priv_all_access_datums_region +/proc/get_all_access_datums_by_region() + if(!priv_all_access_datums_region) + priv_all_access_datums_region = list() + for(var/datum/access/A in get_all_access_datums()) + if(!priv_all_access_datums_region[A.region]) + priv_all_access_datums_region[A.region] = list() + priv_all_access_datums_region[A.region] += A + + return priv_all_access_datums_region.Copy() + +/proc/get_access_ids(var/access_types = ACCESS_TYPE_ALL) + var/list/L = new() + for(var/datum/access/A in get_all_access_datums()) + if(A.access_type & access_types) + L += A.id + return L + +/var/list/priv_all_access +/proc/get_all_accesses() + if(!priv_all_access) + priv_all_access = get_access_ids() + + return priv_all_access.Copy() + +/var/list/priv_station_access +/proc/get_all_station_access() + if(!priv_station_access) + priv_station_access = get_access_ids(ACCESS_TYPE_STATION) + + return priv_station_access.Copy() + +/var/list/priv_centcom_access +/proc/get_all_centcom_access() + if(!priv_centcom_access) + priv_centcom_access = get_access_ids(ACCESS_TYPE_CENTCOM) + + return priv_centcom_access.Copy() + +/var/list/priv_syndicate_access +/proc/get_all_syndicate_access() + if(!priv_syndicate_access) + priv_syndicate_access = get_access_ids(ACCESS_TYPE_SYNDICATE) + + return priv_syndicate_access.Copy() + +/var/list/priv_region_access +/proc/get_region_accesses(var/code) + if(code == ACCESS_REGION_ALL) + return get_all_station_access() + + if(!priv_region_access) + priv_region_access = list() + for(var/datum/access/A in get_all_access_datums()) + if(!priv_region_access["[A.region]"]) + priv_region_access["[A.region]"] = list() + priv_region_access["[A.region]"] += A.id + + var/list/region = priv_region_access["[code]"] + return region.Copy() + +/proc/get_region_accesses_name(var/code) + switch(code) + if(ACCESS_REGION_ALL) + return "All" + if(ACCESS_REGION_SECURITY) //security + return "Security" + if(ACCESS_REGION_MEDBAY) //medbay + return "Medbay" + if(ACCESS_REGION_RESEARCH) //research + return "Research" + if(ACCESS_REGION_ENGINEERING) //engineering and maintenance + return "Engineering" + if(ACCESS_REGION_COMMAND) //command + return "Command" + if(ACCESS_REGION_GENERAL) //station general + return "General" + if(ACCESS_REGION_SUPPLY) //supply + return "Supply" + +/proc/get_access_desc(id) + var/list/AS = priv_all_access_datums_id || get_all_access_datums_by_id() + var/datum/access/A = AS["[id]"] + + return A ? A.desc : "" + +/proc/get_centcom_access_desc(A) + return get_access_desc(A) + +/proc/get_access_by_id(id) + var/list/AS = priv_all_access_datums_id || get_all_access_datums_by_id() + return AS[num2text(id)] + +/proc/get_all_jobs() + var/list/all_jobs = list() + var/list/all_datums = typesof(/datum/job) + all_datums -= exclude_jobs + var/datum/job/jobdatum + for(var/jobtype in all_datums) + jobdatum = new jobtype + all_jobs.Add(jobdatum.title) + return all_jobs + +/proc/get_all_centcom_jobs() + return list("VIP Guest", + "Custodian", + "Thunderdome Overseer", + "Intel Officer", + "Medical Officer", + "Death Commando", + "Research Officer", + "BlackOps Commander", + "Supreme Commander", + "Emergency Response Team", + "Emergency Response Team Leader") + +/mob/observer/ghost + var/static/obj/item/weapon/card/id/all_access/ghost_all_access + +/mob/observer/ghost/GetIdCard() + if(!is_admin(src)) + return + + if(!ghost_all_access) + ghost_all_access = new() + return ghost_all_access + +/mob/living/bot/GetIdCard() + return botcard + +#define HUMAN_ID_CARDS list(get_active_hand(), wear_id, get_inactive_hand()) +/mob/living/carbon/human/GetIdCard() + for(var/item_slot in HUMAN_ID_CARDS) + var/obj/item/I = item_slot + var/obj/item/weapon/card/id = I ? I.GetIdCard() : null + if(id) + return id + +/mob/living/carbon/human/GetAccess() + . = list() + for(var/item_slot in HUMAN_ID_CARDS) + var/obj/item/I = item_slot + if(I) + . |= I.GetAccess() +#undef HUMAN_ID_CARDS + +/mob/living/silicon/GetIdCard() + if(stat || (ckey && !client)) + return // Unconscious, dead or once possessed but now client-less silicons are not considered to have id access. + return idcard + +/proc/FindNameFromID(var/mob/M, var/missing_id_name = "Unknown") + var/obj/item/weapon/card/id/C = M.GetIdCard() + if(C) + return C.registered_name + return missing_id_name + +/proc/get_all_job_icons() //For all existing HUD icons + return joblist + list("Prisoner") + +/obj/proc/GetJobName() //Used in secHUD icon generation + var/obj/item/weapon/card/id/I = GetIdCard() + + if(I) + var/job_icons = get_all_job_icons() + if(I.assignment in job_icons) //Check if the job has a hud icon + return I.assignment + if(I.rank in job_icons) + return I.rank + + var/centcom = get_all_centcom_jobs() + if(I.assignment in centcom) //Return with the NT logo if it is a Centcom job + return "Centcom" + if(I.rank in centcom) + return "Centcom" + else + return + + return "Unknown" //Return unknown if none of the above apply diff --git a/code/game/jobs/access_datum.dm b/code/game/jobs/access_datum.dm new file mode 100644 index 00000000..5da0fdd7 --- /dev/null +++ b/code/game/jobs/access_datum.dm @@ -0,0 +1,472 @@ +/datum/access + var/id = 0 + var/desc = "" + var/region = ACCESS_REGION_NONE + var/access_type = ACCESS_TYPE_STATION + +/datum/access/dd_SortValue() + return "[access_type][desc]" + +/***************** +* Station access * +*****************/ +/var/const/access_security = 1 +/datum/access/security + id = access_security + desc = "Security Equipment" + region = ACCESS_REGION_SECURITY + +/var/const/access_brig = 2 // Brig timers and permabrig +/datum/access/holding + id = access_brig + desc = "Holding Cells" + region = ACCESS_REGION_SECURITY + +/var/const/access_armory = 3 +/datum/access/armory + id = access_armory + desc = "Armory" + region = ACCESS_REGION_SECURITY + +/var/const/access_forensics_lockers = 4 +/datum/access/forensics_lockers + id = access_forensics_lockers + desc = "Forensics" + region = ACCESS_REGION_SECURITY + +/var/const/access_medical = 5 +/datum/access/medical + id = access_medical + desc = "Medical" + region = ACCESS_REGION_MEDBAY + +/var/const/access_morgue = 6 +/datum/access/morgue + id = access_morgue + desc = "Morgue" + region = ACCESS_REGION_MEDBAY + +/var/const/access_tox = 7 +/datum/access/tox + id = access_tox + desc = "Research Labs" + region = ACCESS_REGION_RESEARCH + +/var/const/access_tox_storage = 8 +/datum/access/tox_storage + id = access_tox_storage + desc = "Toxins Lab" + region = ACCESS_REGION_RESEARCH + +/var/const/access_genetics = 9 +/datum/access/genetics + id = access_genetics + desc = "Genetics Lab" + region = ACCESS_REGION_MEDBAY + +/var/const/access_engine = 10 +/datum/access/engine + id = access_engine + desc = "Engineering" + region = ACCESS_REGION_ENGINEERING + +/var/const/access_engine_equip = 11 +/datum/access/engine_equip + id = access_engine_equip + desc = "Engine Room" + region = ACCESS_REGION_ENGINEERING + +/var/const/access_maint_tunnels = 12 +/datum/access/maint_tunnels + id = access_maint_tunnels + desc = "Maintenance" + region = ACCESS_REGION_ENGINEERING + +/var/const/access_external_airlocks = 13 +/datum/access/external_airlocks + id = access_external_airlocks + desc = "External Airlocks" + region = ACCESS_REGION_ENGINEERING + +/var/const/access_emergency_storage = 14 +/datum/access/emergency_storage + id = access_emergency_storage + desc = "Emergency Storage" + region = ACCESS_REGION_ENGINEERING + +/var/const/access_change_ids = 15 +/datum/access/change_ids + id = access_change_ids + desc = "ID Computer" + region = ACCESS_REGION_COMMAND + +/var/const/access_ai_upload = 16 +/datum/access/ai_upload + id = access_ai_upload + desc = "AI Upload" + region = ACCESS_REGION_COMMAND + +/var/const/access_teleporter = 17 +/datum/access/teleporter + id = access_teleporter + desc = "Teleporter" + region = ACCESS_REGION_COMMAND + +/var/const/access_eva = 18 +/datum/access/eva + id = access_eva + desc = "EVA" + region = ACCESS_REGION_COMMAND + +/var/const/access_heads = 19 +/datum/access/heads + id = access_heads + desc = "Bridge" + region = ACCESS_REGION_COMMAND + +/var/const/access_captain = 20 +/datum/access/captain + id = access_captain + desc = "Captain" + region = ACCESS_REGION_COMMAND + +/var/const/access_all_personal_lockers = 21 +/datum/access/all_personal_lockers + id = access_all_personal_lockers + desc = "Personal Lockers" + region = ACCESS_REGION_COMMAND + +/var/const/access_chapel_office = 22 +/datum/access/chapel_office + id = access_chapel_office + desc = "Chapel Office" + region = ACCESS_REGION_GENERAL + +/var/const/access_tech_storage = 23 +/datum/access/tech_storage + id = access_tech_storage + desc = "Technical Storage" + region = ACCESS_REGION_ENGINEERING + +/var/const/access_atmospherics = 24 +/datum/access/atmospherics + id = access_atmospherics + desc = "Atmospherics" + region = ACCESS_REGION_ENGINEERING + +/var/const/access_bar = 25 +/datum/access/bar + id = access_bar + desc = "Bar" + region = ACCESS_REGION_GENERAL + +/var/const/access_janitor = 26 +/datum/access/janitor + id = access_janitor + desc = "Custodial Closet" + region = ACCESS_REGION_GENERAL + +/var/const/access_crematorium = 27 +/datum/access/crematorium + id = access_crematorium + desc = "Crematorium" + region = ACCESS_REGION_GENERAL + +/var/const/access_kitchen = 28 +/datum/access/kitchen + id = access_kitchen + desc = "Kitchen" + region = ACCESS_REGION_GENERAL + +/var/const/access_robotics = 29 +/datum/access/robotics + id = access_robotics + desc = "Robotics" + region = ACCESS_REGION_RESEARCH + +/var/const/access_rd = 30 +/datum/access/rd + id = access_rd + desc = "Research Director" + region = ACCESS_REGION_RESEARCH + +/var/const/access_cargo = 31 +/datum/access/cargo + id = access_cargo + desc = "Cargo Bay" + region = ACCESS_REGION_SUPPLY + +/var/const/access_construction = 32 +/datum/access/construction + id = access_construction + desc = "Construction Areas" + region = ACCESS_REGION_ENGINEERING + +/var/const/access_chemistry = 33 +/datum/access/chemistry + id = access_chemistry + desc = "Chemistry Lab" + region = ACCESS_REGION_MEDBAY + +/var/const/access_cargo_bot = 34 +/datum/access/cargo_bot + id = access_cargo_bot + desc = "Cargo Bot Delivery" + region = ACCESS_REGION_SUPPLY + +/var/const/access_hydroponics = 35 +/datum/access/hydroponics + id = access_hydroponics + desc = "Hydroponics" + region = ACCESS_REGION_GENERAL + +/var/const/access_manufacturing = 36 +/datum/access/manufacturing + id = access_manufacturing + desc = "Manufacturing" + access_type = ACCESS_TYPE_NONE + +/var/const/access_library = 37 +/datum/access/library + id = access_library + desc = "Library" + region = ACCESS_REGION_GENERAL + +/var/const/access_lawyer = 38 +/datum/access/lawyer + id = access_lawyer + desc = "Internal Affairs" + region = ACCESS_REGION_COMMAND + +/var/const/access_virology = 39 +/datum/access/virology + id = access_virology + desc = "Virology" + region = ACCESS_REGION_MEDBAY + +/var/const/access_cmo = 40 +/datum/access/cmo + id = access_cmo + desc = "Chief Medical Officer" + region = ACCESS_REGION_COMMAND + +/var/const/access_qm = 41 +/datum/access/qm + id = access_qm + desc = "Quartermaster" + region = ACCESS_REGION_SUPPLY + +/var/const/access_network = 42 +/datum/access/network + id = access_network + desc = "Primary Network" + region = ACCESS_REGION_RESEARCH + +// /var/const/free_access_id = 43 +// /var/const/free_access_id = 44 + +/var/const/access_surgery = 45 +/datum/access/surgery + id = access_surgery + desc = "Surgery" + region = ACCESS_REGION_MEDBAY + +// /var/const/free_access_id = 46 + +/var/const/access_research = 47 +/datum/access/research + id = access_research + desc = "Science" + region = ACCESS_REGION_RESEARCH + +/var/const/access_mining = 48 +/datum/access/mining + id = access_mining + desc = "Mining" + region = ACCESS_REGION_SUPPLY + +/var/const/access_mining_office = 49 +/datum/access/mining_office + id = access_mining_office + desc = "Mining Office" + access_type = ACCESS_TYPE_NONE + +/var/const/access_mailsorting = 50 +/datum/access/mailsorting + id = access_mailsorting + desc = "Cargo Office" + region = ACCESS_REGION_SUPPLY + +// /var/const/free_access_id = 51 +// /var/const/free_access_id = 52 + +/var/const/access_heads_vault = 53 +/datum/access/heads_vault + id = access_heads_vault + desc = "Main Vault" + region = ACCESS_REGION_COMMAND + +/var/const/access_mining_station = 54 +/datum/access/mining_station + id = access_mining_station + desc = "Mining EVA" + region = ACCESS_REGION_SUPPLY + +/var/const/access_xenobiology = 55 +/datum/access/xenobiology + id = access_xenobiology + desc = "Xenobiology Lab" + region = ACCESS_REGION_RESEARCH + +/var/const/access_ce = 56 +/datum/access/ce + id = access_ce + desc = "Chief Engineer" + region = ACCESS_REGION_ENGINEERING + +/var/const/access_hop = 57 +/datum/access/hop + id = access_hop + desc = "Head of Personnel" + region = ACCESS_REGION_COMMAND + +/var/const/access_hos = 58 +/datum/access/hos + id = access_hos + desc = "Head of Security" + region = ACCESS_REGION_SECURITY + +/var/const/access_RC_announce = 59 //Request console announcements +/datum/access/RC_announce + id = access_RC_announce + desc = "RC Announcements" + region = ACCESS_REGION_COMMAND + +/var/const/access_keycard_auth = 60 //Used for events which require at least two people to confirm them +/datum/access/keycard_auth + id = access_keycard_auth + desc = "Keycode Auth. Device" + region = ACCESS_REGION_COMMAND + +/var/const/access_tcomsat = 61 // has access to the entire telecomms satellite / machinery +/datum/access/tcomsat + id = access_tcomsat + desc = "Telecommunications" + region = ACCESS_REGION_COMMAND + +/var/const/access_gateway = 62 +/datum/access/gateway + id = access_gateway + desc = "Gateway" + region = ACCESS_REGION_COMMAND + +/var/const/access_sec_doors = 63 // Security front doors +/datum/access/sec_doors + id = access_sec_doors + desc = "Security" + region = ACCESS_REGION_SECURITY + +/var/const/access_psychiatrist = 64 // Psychiatrist's office +/datum/access/psychiatrist + id = access_psychiatrist + desc = "Psychiatrist's Office" + region = ACCESS_REGION_MEDBAY + +/var/const/access_xenoarch = 65 +/datum/access/xenoarch + id = access_xenoarch + desc = "Xenoarchaeology" + region = ACCESS_REGION_RESEARCH + +/var/const/access_medical_equip = 66 +/datum/access/medical_equip + id = access_medical_equip + desc = "Medical Equipment" + region = ACCESS_REGION_MEDBAY + +/****************** +* Central Command * +******************/ +/var/const/access_cent_general = 101//General facilities. +/datum/access/cent_general + id = access_cent_general + desc = "Code Grey" + access_type = ACCESS_TYPE_CENTCOM + +/var/const/access_cent_thunder = 102//Thunderdome. +/datum/access/cent_thunder + id = access_cent_thunder + desc = "Code Yellow" + access_type = ACCESS_TYPE_CENTCOM + +/var/const/access_cent_specops = 103//Special Ops. +/datum/access/cent_specops + id = access_cent_specops + desc = "Code Black" + access_type = ACCESS_TYPE_CENTCOM + +/var/const/access_cent_medical = 104//Medical/Research +/datum/access/cent_medical + id = access_cent_medical + desc = "Code White" + access_type = ACCESS_TYPE_CENTCOM + +/var/const/access_cent_living = 105//Living quarters. +/datum/access/cent_living + id = access_cent_living + desc = "Code Green" + access_type = ACCESS_TYPE_CENTCOM + +/var/const/access_cent_storage = 106//Generic storage areas. +/datum/access/cent_storage + id = access_cent_storage + desc = "Code Orange" + access_type = ACCESS_TYPE_CENTCOM + +/var/const/access_cent_teleporter = 107//Teleporter. +/datum/access/cent_teleporter + id = access_cent_teleporter + desc = "Code Blue" + access_type = ACCESS_TYPE_CENTCOM + +/var/const/access_cent_creed = 108//Creed's office. +/datum/access/cent_creed + id = access_cent_creed + desc = "Code Silver" + access_type = ACCESS_TYPE_CENTCOM + +/var/const/access_cent_captain = 109//Captain's office/ID comp/AI. +/datum/access/cent_captain + id = access_cent_captain + desc = "Code Gold" + access_type = ACCESS_TYPE_CENTCOM + +/*************** +* Antag access * +***************/ +/var/const/access_syndicate = 150//General Syndicate Access +/datum/access/syndicate + id = access_syndicate + desc = "Syndicate" + access_type = ACCESS_TYPE_SYNDICATE + +/******* +* Misc * +*******/ +/var/const/access_synth = 199 +/datum/access/synthetic + id = access_synth + desc = "Synthetic" + access_type = ACCESS_TYPE_NONE + +/var/const/access_crate_cash = 200 +/datum/access/crate_cash + id = access_crate_cash + desc = "Crate cash" + access_type = ACCESS_TYPE_NONE + +/var/const/access_merchant = 201 +/datum/access/merchant + id = access_merchant + desc = "Merchant" + access_type = ACCESS_TYPE_NONE diff --git a/code/game/jobs/job/assistant.dm b/code/game/jobs/job/assistant.dm new file mode 100644 index 00000000..50ec397d --- /dev/null +++ b/code/game/jobs/job/assistant.dm @@ -0,0 +1,20 @@ +/datum/job/assistant + title = "Assistant" + department = "Civilian" + department_flag = CIV + + total_positions = -1 + spawn_positions = -1 + supervisors = "absolutely everyone" + selection_color = "#515151" + economic_modifier = 1 + access = list() //See /datum/job/assistant/get_access() + minimal_access = list() //See /datum/job/assistant/get_access() +// alt_titles = list("Technical Assistant","Medical Intern","Research Assistant","Visitor") + outfit_type = /decl/hierarchy/outfit/job/assistant + +/datum/job/assistant/get_access() + if(config.assistant_maint) + return list(access_maint_tunnels) + else + return list() diff --git a/code/game/jobs/job/captain.dm b/code/game/jobs/job/captain.dm new file mode 100644 index 00000000..47691277 --- /dev/null +++ b/code/game/jobs/job/captain.dm @@ -0,0 +1,57 @@ +var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) + +/datum/job/captain + title = "Captain" + department = "Command" + head_position = 1 + department_flag = COM + + total_positions = 1 + spawn_positions = 1 + supervisors = "company officials and Corporate Regulations" + selection_color = "#1d1d4f" + req_admin_notify = 1 + access = list() //See get_access() + minimal_access = list() //See get_access() + minimal_player_age = 14 + economic_modifier = 20 + + ideal_character_age = 70 // Old geezer captains ftw + outfit_type = /decl/hierarchy/outfit/job/captain + +/datum/job/captain/equip(var/mob/living/carbon/human/H) + . = ..() + if(.) + H.implant_loyalty(src) + +/datum/job/captain/get_access() + return get_all_station_access() + +/datum/job/hop + title = "Head of Personnel" + head_position = 1 + department_flag = COM|CIV + + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#2f2f7f" + req_admin_notify = 1 + minimal_player_age = 14 + economic_modifier = 10 + ideal_character_age = 50 + + access = list(access_security, access_sec_doors, access_brig, access_forensics_lockers, + access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads, + access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue, + access_crematorium, access_kitchen, access_cargo, access_cargo_bot, access_mailsorting, access_qm, access_hydroponics, access_lawyer, + access_chapel_office, access_library, access_research, access_mining, access_heads_vault, access_mining_station, + access_hop, access_RC_announce, access_keycard_auth, access_gateway) + minimal_access = list(access_security, access_sec_doors, access_brig, access_forensics_lockers, + access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads, + access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue, + access_crematorium, access_kitchen, access_cargo, access_cargo_bot, access_mailsorting, access_qm, access_hydroponics, access_lawyer, + access_chapel_office, access_library, access_research, access_mining, access_heads_vault, access_mining_station, + access_hop, access_RC_announce, access_keycard_auth, access_gateway) + + outfit_type = /decl/hierarchy/outfit/job/hop \ No newline at end of file diff --git a/code/game/jobs/job/civilian.dm b/code/game/jobs/job/civilian.dm new file mode 100644 index 00000000..83d5cf16 --- /dev/null +++ b/code/game/jobs/job/civilian.dm @@ -0,0 +1,126 @@ +//Food +/datum/job/bartender + title = "Bartender" + department = "Service" + department_flag = SRV + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#515151" + access = list(access_hydroponics, access_bar, access_kitchen) + minimal_access = list(access_bar) + outfit_type = /decl/hierarchy/outfit/job/service/bartender + +/datum/job/chef + title = "Cook" + department = "Service" + department_flag = SRV + total_positions = 2 + spawn_positions = 2 + supervisors = "the head of personnel" + selection_color = "#515151" + access = list(access_hydroponics, access_bar, access_kitchen) + minimal_access = list(access_kitchen) +// alt_titles = list("Cook") + outfit_type = /decl/hierarchy/outfit/job/service/chef + +/datum/job/hydro + title = "Botanic" + department = "Service" + department_flag = SRV + total_positions = 2 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#515151" + access = list(access_hydroponics, access_bar, access_kitchen) + minimal_access = list(access_hydroponics) +// alt_titles = list("Hydroponicist") + outfit_type = /decl/hierarchy/outfit/job/service/gardener + +//Cargo +/datum/job/qm + title = "Quartermaster" + department = "Supply" + department_flag = SUP + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#515151" + economic_modifier = 5 + access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station) + minimal_access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station) + minimal_player_age = 3 + ideal_character_age = 40 + outfit_type = /decl/hierarchy/outfit/job/cargo/qm + +/datum/job/cargo_tech + title = "Cargo Technician" + department = "Supply" + department_flag = SUP + total_positions = 2 + spawn_positions = 2 + supervisors = "the quartermaster and the head of personnel" + selection_color = "#515151" + access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station) + minimal_access = list(access_maint_tunnels, access_cargo, access_cargo_bot, access_mailsorting) + outfit_type = /decl/hierarchy/outfit/job/cargo/cargo_tech + +/datum/job/mining + title = "Shaft Miner" + department = "Supply" + department_flag = SUP + total_positions = 3 + spawn_positions = 3 + supervisors = "the quartermaster and the head of personnel" + selection_color = "#515151" + economic_modifier = 5 + access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station) + minimal_access = list(access_mining, access_mining_station, access_mailsorting) +// alt_titles = list("Drill Technician","Prospector") + outfit_type = /decl/hierarchy/outfit/job/cargo/mining + +/datum/job/janitor + title = "Janitor" + department = "Service" + department_flag = SRV + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#515151" + access = list(access_janitor, access_maint_tunnels, access_engine, access_research, access_sec_doors, access_medical) + minimal_access = list(access_janitor, access_maint_tunnels, access_engine, access_research, access_sec_doors, access_medical) +// alt_titles = list("Custodian","Sanitation Technician") + outfit_type = /decl/hierarchy/outfit/job/service/janitor + +//More or less assistants +/datum/job/librarian + title = "Librarian" + department = "Civilian" + department_flag = CIV + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#515151" + access = list(access_library, access_maint_tunnels) + minimal_access = list(access_library) +// alt_titles = list("Journalist") + outfit_type = /decl/hierarchy/outfit/job/librarian + +/datum/job/lawyer + title = "Internal Affairs Agent" + department = "Support" + department_flag = SPT + total_positions = 2 + spawn_positions = 2 + supervisors = "company officials and Corporate Regulations" + selection_color = "#515151" + economic_modifier = 7 + access = list(access_lawyer, access_sec_doors, access_maint_tunnels, access_heads) + minimal_access = list(access_lawyer, access_sec_doors, access_heads) + minimal_player_age = 10 + outfit_type = /decl/hierarchy/outfit/job/internal_affairs_agent + +/datum/job/lawyer/equip(var/mob/living/carbon/human/H) + . = ..() + if(.) + H.implant_loyalty(H) diff --git a/code/game/jobs/job/civilian_chaplain.dm b/code/game/jobs/job/civilian_chaplain.dm new file mode 100644 index 00000000..81ea91e7 --- /dev/null +++ b/code/game/jobs/job/civilian_chaplain.dm @@ -0,0 +1,133 @@ +//Due to how large this one is it gets its own file +/datum/job/chaplain + title = "Chaplain" + department = "Civilian" + department_flag = CIV + + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#515151" + access = list(access_morgue, access_chapel_office, access_crematorium, access_maint_tunnels) + minimal_access = list(access_morgue, access_chapel_office, access_crematorium) +// alt_titles = list("Counselor") + outfit_type = /decl/hierarchy/outfit/job/chaplain + + equip(var/mob/living/carbon/human/H, var/alt_title, var/ask_questions = TRUE) + . = ..() + if(!.) + return + if(!ask_questions) + return + + var/obj/item/weapon/storage/bible/B = locate(/obj/item/weapon/storage/bible) in H + if(!B) + return + + spawn(0) + var/religion_name = "Christianity" + var/new_religion = sanitize(input(H, "You are the crew services officer. Would you like to change your religion? Default is Christianity, in SPACE.", "Name change", religion_name), MAX_NAME_LEN) + + if (!new_religion) + new_religion = religion_name + switch(lowertext(new_religion)) + if("christianity") + B.SetName(pick("The Holy Bible","The Dead Sea Scrolls")) + if("satanism") + B.SetName("The Unholy Bible") + if("cthulu") + B.SetName("The Necronomicon") + if("islam") + B.SetName("Quran") + if("scientology") + B.SetName(pick("The Biography of L. Ron Hubbard","Dianetics")) + if("chaos") + B.SetName("The Book of Lorgar") + if("imperium") + B.SetName("Uplifting Primer") + if("toolboxia") + B.SetName("Toolbox Manifesto") + if("homosexuality") + B.SetName("Guys Gone Wild") + if("science") + B.SetName(pick("Principle of Relativity", "Quantum Enigma: Physics Encounters Consciousness", "Programming the Universe", "Quantum Physics and Theology", "String Theory for Dummies", "How To: Build Your Own Warp Drive", "The Mysteries of Bluespace", "Playing God: Collector's Edition")) + else + B.SetName("The Holy Book of [new_religion]") + feedback_set_details("religion_name","[new_religion]") + + spawn(1) + var/deity_name = "Space Jesus" + var/new_deity = sanitize(input(H, "Would you like to change your deity? Default is Space Jesus.", "Name change", deity_name), MAX_NAME_LEN) + + if ((length(new_deity) == 0) || (new_deity == "Space Jesus") ) + new_deity = deity_name + B.deity_name = new_deity + + var/accepted = 0 + var/outoftime = 0 + spawn(200) // 20 seconds to choose + outoftime = 1 + var/new_book_style = "Bible" + + while(!accepted) + if(!B) break // prevents possible runtime errors + new_book_style = input(H,"Which bible style would you like?") in list("Bible", "Koran", "Scrapbook", "Creeper", "White Bible", "Holy Light", "Athiest", "Tome", "The King in Yellow", "Ithaqua", "Scientology", "the bible melts", "Necronomicon") + switch(new_book_style) + if("Koran") + B.icon_state = "koran" + B.item_state = "koran" + if("Scrapbook") + B.icon_state = "scrapbook" + B.item_state = "scrapbook" + if("Creeper") + B.icon_state = "creeper" + B.item_state = "syringe_kit" + if("White Bible") + B.icon_state = "white" + B.item_state = "syringe_kit" + if("Holy Light") + B.icon_state = "holylight" + B.item_state = "syringe_kit" + if("Athiest") + B.icon_state = "athiest" + B.item_state = "syringe_kit" + if("Tome") + B.icon_state = "tome" + B.item_state = "syringe_kit" + if("The King in Yellow") + B.icon_state = "kingyellow" + B.item_state = "kingyellow" + if("Ithaqua") + B.icon_state = "ithaqua" + B.item_state = "ithaqua" + if("Scientology") + B.icon_state = "scientology" + B.item_state = "scientology" + if("the bible melts") + B.icon_state = "melted" + B.item_state = "melted" + if("Necronomicon") + B.icon_state = "necronomicon" + B.item_state = "necronomicon" + else + B.icon_state = "bible" + B.item_state = "bible" + + H.update_inv_l_hand() // so that it updates the bible's item_state in his hand + + switch(input(H,"Look at your bible - is this what you want?") in list("Yes","No")) + if("Yes") + accepted = 1 + if("No") + if(outoftime) + to_chat(H, "Welp, out of time, buddy. You're stuck. Next time choose faster.") + accepted = 1 + + if(ticker) + ticker.Bible_icon_state = B.icon_state + ticker.Bible_item_state = B.item_state + ticker.Bible_name = B.name + ticker.Bible_deity_name = B.deity_name + feedback_set_details("religion_deity","[new_deity]") + feedback_set_details("religion_book","[new_book_style]") + return 1 diff --git a/code/game/jobs/job/engineering.dm b/code/game/jobs/job/engineering.dm new file mode 100644 index 00000000..9cf484a4 --- /dev/null +++ b/code/game/jobs/job/engineering.dm @@ -0,0 +1,58 @@ +/datum/job/chief_engineer + title = "Chief Engineer" + head_position = 1 + department = "Engineering" + department_flag = ENG|COM + + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#7f6e2c" + req_admin_notify = 1 + economic_modifier = 10 + + ideal_character_age = 50 + + + access = list(access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, + access_teleporter, access_external_airlocks, access_atmospherics, access_emergency_storage, access_eva, + access_heads, access_construction, access_sec_doors, + access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_ai_upload) + minimal_access = list(access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, + access_teleporter, access_external_airlocks, access_atmospherics, access_emergency_storage, access_eva, + access_heads, access_construction, access_sec_doors, + access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_ai_upload) + minimal_player_age = 14 + outfit_type = /decl/hierarchy/outfit/job/engineering/chief_engineer + +/datum/job/engineer + title = "Engineer" + department = "Engineering" + department_flag = ENG + + total_positions = 8 + spawn_positions = 7 + supervisors = "the chief engineer" + selection_color = "#5b4d20" + economic_modifier = 5 + minimal_player_age = 7 + access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_atmospherics, access_emergency_storage) + minimal_access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_atmospherics, access_emergency_storage) + //alt_titles = list("Maintenance Technician","Engine Technician","Electrician", + // "Atmospheric Technician" = /decl/hierarchy/outfit/job/engineering/atmos) + outfit_type = /decl/hierarchy/outfit/job/engineering/engineer + +/datum/job/atmos + title = "Atmospheric Technician" + department = "Engineering" + department_flag = ENG + + total_positions = 0 + spawn_positions = 0 + supervisors = "the chief engineer" + selection_color = "#5b4d20" + economic_modifier = 5 + minimal_player_age = 7 + access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_atmospherics, access_emergency_storage) + minimal_access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_atmospherics, access_emergency_storage) + outfit_type = /decl/hierarchy/outfit/job/engineering/atmos diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm new file mode 100644 index 00000000..25be01f5 --- /dev/null +++ b/code/game/jobs/job/job.dm @@ -0,0 +1,287 @@ +GLOBAL_LIST_EMPTY(family_blacklist) + +/datum/job + + //The name of the job + var/title = "NOPE" + //Job access. The use of minimal_access or access is determined by a config setting: config.jobs_have_minimal_access + var/list/minimal_access = list() // Useful for servers which prefer to only have access given to the places a job absolutely needs (Larger server population) + var/list/access = list() // Useful for servers which either have fewer players, so each person needs to fill more than one role, or servers which like to give more access, so players can't hide forever in their super secure departments (I'm looking at you, chemistry!) + var/list/software_on_spawn = list() // Defines the software files that spawn on tablets and labtops + var/department_flag = 0 + var/total_positions = 0 // How many players can be this job + var/spawn_positions = 0 // How many players can spawn in as this job + var/current_positions = 0 // How many players have this job + var/open_when_dead = FALSE // If set to true, then the job will re-open when someone who has that job dies. + var/availablity_chance = 100 // Percentage chance job is available each round + + var/supervisors = null // Supervisors, who this person answers to directly + var/selection_color = "#ffffff" // Selection screen color + var/list/alt_titles // List of alternate titles, if any and any potential alt. outfits as assoc values. + var/req_admin_notify // If this is set to 1, a text is printed to the player when jobs are assigned, telling him that he should let admins know that he has to disconnect. + var/minimal_player_age = 0 // If you have use_age_restriction_for_jobs config option enabled and the database set up, this option will add a requirement for players to be at least minimal_player_age days old. (meaning they first signed in at least that many days before.) + var/department = null // Does this position have a department tag? + var/head_position = 0 // Is this position Command? + var/minimum_character_age = 0 + var/ideal_character_age = 30 + var/create_record = 1 // Do we announce/make records for people who spawn on this job? + + var/account_allowed = 1 // Does this job type come with a station account? + var/economic_modifier = 2 // With how much does this job modify the initial account amount? + + var/outfit_type // The outfit the employee will be dressed in, if any + + var/loadout_allowed = TRUE // Whether or not loadout equipment is allowed and to be created when joining. + var/list/allowed_branches // For maps using branches and ranks, also expandable for other purposes + var/list/allowed_ranks // Ditto + + var/announced = TRUE //If their arrival is announced on radio + var/latejoin_at_spawnpoints //If this job should use roundstart spawnpoints for latejoin (offstation jobs etc) + + var/hud_icon //icon used for Sec HUD overlay + + var/social_class = SOCIAL_CLASS_MED //Job's social standing. + var/has_email = FALSE //Whether or not the job gets an email. + + var/child_role = FALSE //If set to true they will automatically spawn as a child. + var/no_late_join = FALSE //If set to true, the job will no longer be in the late join list. + var/late_join_only = FALSE //Can only late join. Is not a roundstart role. + var/is_blue_team = FALSE //Warfare shit. + var/is_red_team = FALSE //Same here. + var/can_be_in_squad = FALSE //Whether or not the job can be in a squad or not. Used for warfare shit. + var/role_desc = null + //Skill defines. Put the MAXIMUM skill you want here, when it assigns skills it will randomly subtract 3 unless specific skill is set. + var/specific_skill = FALSE //If set to true, it will not assign random skills, but the specific number you put. + var/medical_skill = 5 + var/surgery_skill = 5 + var/ranged_skill = 5 + var/engineering_skill = 5 + var/melee_skill = 5 + //Gun skills + var/auto_rifle_skill = 5 + var/semi_rifle_skill = 5 + var/sniper_skill = 5 + var/shotgun_skill = 5 + var/lmg_skill = 5 + var/smg_skill = 5 + + +/datum/job/New() + ..() + if(prob(100-availablity_chance)) //Close positions, blah blah. + total_positions = 0 + spawn_positions = 0 + +/datum/job/dd_SortValue() + return title + +/datum/job/New() + ..() + if(!hud_icon) + hud_icon = "hud[ckey(title)]" + +/datum/job/proc/do_skill_setup(var/mob/living/carbon/human/H) + if(specific_skill) + H.SKILL_LEVEL(medical) = medical_skill + H.SKILL_LEVEL(surgery) = surgery_skill + H.SKILL_LEVEL(ranged) = ranged_skill + H.SKILL_LEVEL(engineering) = engineering_skill + H.SKILL_LEVEL(melee) = melee_skill + //Gun skills + H.SKILL_LEVEL(auto_rifle) = auto_rifle_skill + H.SKILL_LEVEL(semi_rifle) = semi_rifle_skill + H.SKILL_LEVEL(sniper) = sniper_skill + H.SKILL_LEVEL(shotgun) = shotgun_skill + H.SKILL_LEVEL(lmg) = lmg_skill + H.SKILL_LEVEL(smg) = smg_skill + return + H.SKILL_LEVEL(medical) = rand((medical_skill - 3), medical_skill) + H.SKILL_LEVEL(surgery) = rand((surgery_skill - 3), surgery_skill) + H.SKILL_LEVEL(ranged) = rand((ranged_skill - 3), ranged_skill) + H.SKILL_LEVEL(engineering) = rand((engineering_skill - 3), engineering_skill) + H.SKILL_LEVEL(melee) = rand((melee_skill - 3), melee_skill) + //Gun skills + H.SKILL_LEVEL(auto_rifle) = rand((auto_rifle_skill - 3), auto_rifle_skill) + H.SKILL_LEVEL(semi_rifle) = rand((semi_rifle_skill - 3), semi_rifle_skill) + H.SKILL_LEVEL(sniper) = rand((sniper_skill - 3), sniper_skill) + H.SKILL_LEVEL(shotgun) = rand((shotgun_skill - 3), shotgun_skill) + H.SKILL_LEVEL(lmg) = rand((lmg_skill - 3), lmg_skill) + H.SKILL_LEVEL(smg) = rand((smg_skill - 3), smg_skill) + +/datum/job/proc/equip(var/mob/living/carbon/human/H, var/alt_title, var/datum/mil_branch/branch, var/datum/mil_rank/grade) + if(child_role) + H.set_species("Child")//Actually makes them a child. + H.unlock_achievement(new/datum/achievement/kid()) + + if(social_class) + H.social_class = social_class + + + do_skill_setup(H)//Give them all their skills. + + var/decl/hierarchy/outfit/outfit = get_outfit(H, alt_title, branch, grade) + if(!outfit) + return FALSE + . = outfit.equip(H, title, alt_title) + +/datum/job/proc/get_outfit(var/mob/living/carbon/human/H, var/alt_title, var/datum/mil_branch/branch, var/datum/mil_rank/grade) + if(alt_title && alt_titles) + . = alt_titles[alt_title] + if(allowed_branches && branch) + . = allowed_branches[branch.type] || . + if(allowed_ranks && grade) + . = allowed_ranks[grade.type] || . + . = . || outfit_type + . = outfit_by_type(.) + +/datum/job/proc/setup_account(var/mob/living/carbon/human/H) + if(!account_allowed || (H.mind && H.mind.initial_account)) + return + + if(!(H.species && (H.species.type in economic_species_modifier))) + return //some bizarre species like shadow, slime, or monkey? You don't get an account. + + var/money_amount = (rand(5,50) + rand(5, 50)) * economic_modifier * GLOB.using_map.salary_modifier //* loyalty * species_modifier + var/datum/money_account/M = create_account(H.real_name, money_amount, null) + if(H.mind) + var/remembered_info = "" + remembered_info += "Your account number is: #[M.account_number]
    " + remembered_info += "Your account pin is: [M.remote_access_pin]
    " + remembered_info += "Your account funds are: T[M.money]
    " + + if(M.transaction_log.len) + var/datum/transaction/T = M.transaction_log[1] + remembered_info += "Your account was created: [T.time], [T.date] at [T.source_terminal]
    " + H.mind.store_memory(remembered_info) + + H.mind.initial_account = M + + to_chat(H, "Your account number is: [M.account_number], your account pin is: [M.remote_access_pin]") + +// overrideable separately so AIs/borgs can have cardborg hats without unneccessary new()/qdel() +/datum/job/proc/equip_preview(mob/living/carbon/human/H, var/alt_title, var/datum/mil_branch/branch) + var/decl/hierarchy/outfit/outfit = get_outfit(H, alt_title, branch) + if(!outfit) + return FALSE + . = outfit.equip(H, title, alt_title, OUTFIT_ADJUSTMENT_SKIP_POST_EQUIP|OUTFIT_ADJUSTMENT_SKIP_ID_PDA) + +/datum/job/proc/get_access() + if(minimal_access.len && (!config || config.jobs_have_minimal_access)) + return src.minimal_access.Copy() + else + return src.access.Copy() + +//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1 +/datum/job/proc/player_old_enough(client/C) + return (available_in_days(C) == 0) //Available in 0 days = available right now = player is old enough to play. + +/datum/job/proc/available_in_days(client/C) + if(C && config.use_age_restriction_for_jobs && isnull(C.holder) && isnum(C.player_age) && isnum(minimal_player_age)) + return max(0, minimal_player_age - C.player_age) + return 0 + +/datum/job/proc/apply_fingerprints(var/mob/living/carbon/human/target) + if(!istype(target)) + return 0 + for(var/obj/item/item in target.contents) + apply_fingerprints_to_item(target, item) + return 1 + +/datum/job/proc/apply_fingerprints_to_item(var/mob/living/carbon/human/holder, var/obj/item/item) + item.add_fingerprint(holder,1) + if(item.contents.len) + for(var/obj/item/sub_item in item.contents) + apply_fingerprints_to_item(holder, sub_item) + +/datum/job/proc/is_position_available() + return (current_positions < total_positions) || (total_positions == -1) + +/datum/job/proc/has_alt_title(var/mob/H, var/supplied_title, var/desired_title) + return (supplied_title == desired_title) || (H.mind && H.mind.role_alt_title == desired_title) + +/datum/job/proc/is_restricted(var/datum/preferences/prefs, var/feedback) + if(!is_branch_allowed(prefs.char_branch)) + to_chat(feedback, "Wrong branch of service for [title]. Valid branches are: [get_branches()].") + return TRUE + + if(!is_rank_allowed(prefs.char_branch, prefs.char_rank)) + to_chat(feedback, "Wrong rank for [title]. Valid ranks in [prefs.char_branch] are: [get_ranks(prefs.char_branch)].") + return TRUE + + var/datum/species/S = all_species[prefs.species] + if(!is_species_allowed(S)) + to_chat(feedback, "Restricted species, [S], for [title].") + return TRUE + + return FALSE + +/datum/job/proc/is_species_allowed(var/datum/species/S) + return !GLOB.using_map.is_species_job_restricted(S, src) + +/** + * Check if members of the given branch are allowed in the job + * + * This proc should only be used after the global branch list has been initialized. + * + * branch_name - String key for the branch to check + */ +/datum/job/proc/is_branch_allowed(var/branch_name) + if(!allowed_branches || !GLOB.using_map || !(GLOB.using_map.flags & MAP_HAS_BRANCH)) + return 1 + if(branch_name == "None") + return 0 + + var/datum/mil_branch/branch = mil_branches.get_branch(branch_name) + + if(!branch) + crash_with("unknown branch \"[branch_name]\" passed to is_branch_allowed()") + return 0 + + if(is_type_in_list(branch, allowed_branches)) + return 1 + else + return 0 + +/** + * Check if people with given rank are allowed in this job + * + * This proc should only be used after the global branch list has been initialized. + * + * branch_name - String key for the branch to which the rank belongs + * rank_name - String key for the rank itself + */ +/datum/job/proc/is_rank_allowed(var/branch_name, var/rank_name) + if(!allowed_ranks || !GLOB.using_map || !(GLOB.using_map.flags & MAP_HAS_RANK)) + return 1 + if(branch_name == "None" || rank_name == "None") + return 0 + + var/datum/mil_rank/rank = mil_branches.get_rank(branch_name, rank_name) + + if(!rank) + crash_with("unknown rank \"[rank_name]\" in branch \"[branch_name]\" passed to is_rank_allowed()") + return 0 + + if(is_type_in_list(rank, allowed_ranks)) + return 1 + else + return 0 + +//Returns human-readable list of branches this job allows. +/datum/job/proc/get_branches() + var/list/res = list() + for(var/T in allowed_branches) + var/datum/mil_branch/B = mil_branches.get_branch_by_type(T) + res += B.name + return english_list(res) + +//Same as above but ranks +/datum/job/proc/get_ranks(branch) + var/list/res = list() + var/datum/mil_branch/B = mil_branches.get_branch(branch) + for(var/T in allowed_ranks) + var/datum/mil_rank/R = T + if(B && !(initial(R.name) in B.ranks)) + continue + res += initial(R.name) + return english_list(res) diff --git a/code/game/jobs/job/medical.dm b/code/game/jobs/job/medical.dm new file mode 100644 index 00000000..70734763 --- /dev/null +++ b/code/game/jobs/job/medical.dm @@ -0,0 +1,106 @@ +/datum/job/cmo + title = "Chief Medical Officer" + head_position = 1 + department = "Medical" + department_flag = MED|COM + + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#633d63" + req_admin_notify = 1 + economic_modifier = 10 + access = list(access_medical, access_medical_equip, access_morgue, access_genetics, access_heads, + access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce, + access_keycard_auth, access_sec_doors, access_psychiatrist, access_eva, access_maint_tunnels, access_external_airlocks) + minimal_access = list(access_medical, access_medical_equip, access_morgue, access_genetics, access_heads, + access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce, + access_keycard_auth, access_sec_doors, access_psychiatrist, access_eva, access_maint_tunnels, access_external_airlocks) + + minimal_player_age = 14 + ideal_character_age = 50 + outfit_type = /decl/hierarchy/outfit/job/medical/cmo + +/datum/job/doctor + title = "Medical Doctor" + department = "Medical" + department_flag = MED + + minimal_player_age = 3 + total_positions = 5 + spawn_positions = 3 + supervisors = "the chief medical officer" + selection_color = "#633d63" + economic_modifier = 7 + access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics) + minimal_access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_virology) +// alt_titles = list( +// "Surgeon" = /decl/hierarchy/outfit/job/medical/doctor/surgeon, +// "Emergency Physician" = /decl/hierarchy/outfit/job/medical/doctor/emergency_physician, +// "Nurse" = /decl/hierarchy/outfit/job/medical/doctor/nurse, +// "Virologist" = /decl/hierarchy/outfit/job/medical/doctor/virologist) + outfit_type = /decl/hierarchy/outfit/job/medical/doctor + +//Chemist is a medical job damnit //YEAH FUCK YOU SCIENCE -Pete //Guys, behave -Erro +/datum/job/chemist + title = "Chemist" + department = "Medical" + department_flag = MED + + minimal_player_age = 7 + total_positions = 2 + spawn_positions = 2 + supervisors = "the chief medical officer" + selection_color = "#633d63" + economic_modifier = 5 + access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics) + minimal_access = list(access_medical, access_medical_equip, access_chemistry) +// alt_titles = list("Pharmacist") + outfit_type = /decl/hierarchy/outfit/job/medical/chemist + +/datum/job/geneticist + title = "Geneticist" + department = "Medical" + department_flag = MED + + total_positions = 0 + spawn_positions = 0 + minimal_player_age = 7 + supervisors = "the chief medical officer and research director" + selection_color = "#633d63" + economic_modifier = 7 + access = list(access_medical, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics, access_research) + minimal_access = list(access_medical, access_morgue, access_genetics, access_research) + outfit_type = /decl/hierarchy/outfit/job/medical/geneticist + +/datum/job/psychiatrist + title = "Psychiatrist" + department = "Medical" + department_flag = MED + + total_positions = 1 + spawn_positions = 1 + economic_modifier = 5 + minimal_player_age = 3 + supervisors = "the chief medical officer" + selection_color = "#633d63" + access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics, access_psychiatrist) + minimal_access = list(access_medical, access_medical_equip, access_psychiatrist) +// alt_titles = list("Psychologist" = /decl/hierarchy/outfit/job/medical/psychiatrist/psychologist) + outfit_type = /decl/hierarchy/outfit/job/medical/psychiatrist + +/datum/job/Paramedic + title = "Paramedic" + department = "Medical" + department_flag = MED + + total_positions = 2 + spawn_positions = 2 + supervisors = "the chief medical officer" + selection_color = "#633d63" + economic_modifier = 4 + minimal_player_age = 7 + access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_eva, access_maint_tunnels, access_external_airlocks, access_psychiatrist) + minimal_access = list(access_medical, access_medical_equip, access_morgue, access_eva, access_maint_tunnels, access_external_airlocks) +// alt_titles = list("Emergency Medical Technician" = /decl/hierarchy/outfit/job/medical/paramedic/emt) + outfit_type = /decl/hierarchy/outfit/job/medical/paramedic diff --git a/code/game/jobs/job/science.dm b/code/game/jobs/job/science.dm new file mode 100644 index 00000000..9db9f1ea --- /dev/null +++ b/code/game/jobs/job/science.dm @@ -0,0 +1,71 @@ +/datum/job/rd + title = "Research Director" + head_position = 1 + department = "Science" + department_flag = COM|SCI + + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#ad6bad" + req_admin_notify = 1 + economic_modifier = 15 + access = list(access_rd, access_heads, access_tox, access_genetics, access_morgue, + access_tox_storage, access_teleporter, access_sec_doors, + access_research, access_robotics, access_xenobiology, access_ai_upload, access_tech_storage, + access_RC_announce, access_keycard_auth, access_tcomsat, access_gateway, access_xenoarch, access_network) + minimal_access = list(access_rd, access_heads, access_tox, access_genetics, access_morgue, + access_tox_storage, access_teleporter, access_sec_doors, + access_research, access_robotics, access_xenobiology, access_ai_upload, access_tech_storage, + access_RC_announce, access_keycard_auth, access_tcomsat, access_gateway, access_xenoarch, access_network) + minimal_player_age = 14 + ideal_character_age = 50 + outfit_type = /decl/hierarchy/outfit/job/science/rd + +/datum/job/scientist + title = "Scientist" + department = "Science" + department_flag = SCI + + total_positions = 5 + spawn_positions = 3 + supervisors = "the research director" + selection_color = "#633d63" + economic_modifier = 7 + access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobiology, access_xenoarch) + minimal_access = list(access_tox, access_tox_storage, access_research, access_xenoarch) +// alt_titles = list("Xenoarcheologist", "Anomalist", "Phoron Researcher") + minimal_player_age = 7 + outfit_type = /decl/hierarchy/outfit/job/science/scientist + +/datum/job/xenobiologist + title = "Xenobiologist" + department = "Science" + department_flag = SCI + + total_positions = 3 + spawn_positions = 2 + supervisors = "the research director" + selection_color = "#633d63" + economic_modifier = 7 + access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobiology, access_hydroponics) + minimal_access = list(access_research, access_xenobiology, access_hydroponics) +// alt_titles = list("Xenobotanist") + minimal_player_age = 7 + outfit_type = /decl/hierarchy/outfit/job/science/xenobiologist + +/datum/job/roboticist + title = "Roboticist" + department = "Science" + department_flag = SCI + + total_positions = 2 + spawn_positions = 2 + supervisors = "research director" + selection_color = "#633d63" + economic_modifier = 5 + access = list(access_robotics, access_tox, access_tox_storage, access_tech_storage, access_morgue, access_research) //As a job that handles so many corpses, it makes sense for them to have morgue access. + minimal_access = list(access_robotics, access_tech_storage, access_morgue, access_research) //As a job that handles so many corpses, it makes sense for them to have morgue access. +// alt_titles = list("Biomechanical Engineer","Mechatronic Engineer") + minimal_player_age = 3 + outfit_type = /decl/hierarchy/outfit/job/science/roboticist diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm new file mode 100644 index 00000000..ed28a124 --- /dev/null +++ b/code/game/jobs/job/security.dm @@ -0,0 +1,74 @@ +/datum/job/hos + title = "Head of Security" + head_position = 1 + department = "Security" + department_flag = SEC|COM + + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#8e2929" + req_admin_notify = 1 + economic_modifier = 10 + access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, + access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers, + access_research, access_engine, access_mining, access_medical, access_construction, access_mailsorting, + access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_external_airlocks) + minimal_access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, + access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers, + access_research, access_engine, access_mining, access_medical, access_construction, access_mailsorting, + access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_external_airlocks) + minimal_player_age = 14 + outfit_type = /decl/hierarchy/outfit/job/security/hos + +/datum/job/hos/equip(var/mob/living/carbon/human/H) + . = ..() + if(.) + H.implant_loyalty(H) + +/datum/job/warden + title = "Warden" + department = "Security" + department_flag = SEC + + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of security" + selection_color = "#601c1c" + economic_modifier = 5 + access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, access_maint_tunnels, access_morgue, access_external_airlocks) + minimal_access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, access_maint_tunnels, access_external_airlocks) + minimal_player_age = 7 + outfit_type = /decl/hierarchy/outfit/job/security/warden + +/datum/job/detective + title = "Detective" + department = "Security" + department_flag = SEC + + total_positions = 2 + spawn_positions = 2 + supervisors = "the head of security" + selection_color = "#601c1c" +// alt_titles = list("Forensic Technician" = /decl/hierarchy/outfit/job/security/detective/forensic) + economic_modifier = 5 + access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels) + minimal_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels) + minimal_player_age = 7 + outfit_type = /decl/hierarchy/outfit/job/security/detective + +/datum/job/officer + title = "Security Officer" + department = "Security" + department_flag = SEC + + total_positions = 4 + spawn_positions = 4 + supervisors = "the head of security" + selection_color = "#601c1c" +// alt_titles = list("Junior Officer") + economic_modifier = 4 + access = list(access_security, access_eva, access_sec_doors, access_brig, access_maint_tunnels, access_morgue, access_external_airlocks) + minimal_access = list(access_security, access_eva, access_sec_doors, access_brig, access_maint_tunnels, access_external_airlocks) + minimal_player_age = 7 + outfit_type = /decl/hierarchy/outfit/job/security/officer \ No newline at end of file diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm new file mode 100644 index 00000000..6a7d16fd --- /dev/null +++ b/code/game/jobs/job/silicon.dm @@ -0,0 +1,42 @@ +/datum/job/ai + title = "AI" + department_flag = MSC + + total_positions = 0 // Not used for AI, see is_position_available below and modules/mob/living/silicon/ai/latejoin.dm + spawn_positions = 1 + selection_color = "#3f823f" + supervisors = "your laws" + req_admin_notify = 1 + minimal_player_age = 14 + account_allowed = 0 + economic_modifier = 0 + outfit_type = /decl/hierarchy/outfit/job/silicon/ai + loadout_allowed = FALSE + hud_icon = "hudblank" + +/datum/job/ai/equip(var/mob/living/carbon/human/H) + if(!H) return 0 + return 1 + +/datum/job/ai/is_position_available() + return (empty_playable_ai_cores.len != 0) + +/datum/job/cyborg + title = "Cyborg" + department_flag = MSC + + total_positions = 2 + spawn_positions = 2 + supervisors = "your laws and the AI" //Nodrak + selection_color = "#254c25" + minimal_player_age = 7 + //alt_titles = list("Android", "Robot") + account_allowed = 0 + economic_modifier = 0 + loadout_allowed = FALSE + outfit_type = /decl/hierarchy/outfit/job/silicon/cyborg + hud_icon = "hudblank" + +/datum/job/cyborg/equip(var/mob/living/carbon/human/H) + if(!H) return 0 + return 1 diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm new file mode 100644 index 00000000..7e6a6d49 --- /dev/null +++ b/code/game/jobs/job_controller.dm @@ -0,0 +1,610 @@ +var/global/datum/controller/occupations/job_master + +#define GET_RANDOM_JOB 0 +#define BE_ASSISTANT 1 +#define RETURN_TO_LOBBY 2 + +/datum/controller/occupations + //List of all jobs + var/list/occupations = list() + //Associative list of all jobs, by type + var/list/occupations_by_type + //Associative list of all jobs, by title + var/list/occupations_by_title + //Players who need jobs + var/list/unassigned = list() + //Debug info + var/list/job_debug = list() + + +/datum/controller/occupations/proc/SetupOccupations(var/setup_titles = 0) + occupations = list() + occupations_by_type = list() + occupations_by_title = list() + var/list/all_jobs = list(/datum/job/assistant) | GLOB.using_map.allowed_jobs + if(!all_jobs.len) + log_error("Error setting up jobs, no job datums found!") + return 0 + for(var/J in all_jobs) + var/datum/job/job = decls_repository.get_decl(J) + if(!job) continue + occupations += job + occupations_by_type[job.type] = job + occupations_by_title[job.title] = job + job.current_positions = 0 + for(var/alt_title in job.alt_titles) + occupations_by_title[alt_title] = job + if(!setup_titles) continue + if(job.department_flag & COM) + GLOB.command_positions |= job.title + if(job.department_flag & SPT) + GLOB.support_positions |= job.title + if(job.department_flag & SEC) + GLOB.security_positions |= job.title + if(job.department_flag & ENG) + GLOB.engineering_positions += job.title + if(job.department_flag & MED) + GLOB.medical_positions |= job.title + if(job.department_flag & SCI) + GLOB.science_positions |= job.title + if(job.department_flag & EXP) + GLOB.exploration_positions |= job.title + if(job.department_flag & SUP) + GLOB.supply_positions |= job.title + if(job.department_flag & SRV) + GLOB.service_positions |= job.title + if(job.department_flag & CIV) + GLOB.civilian_positions |= job.title + if(job.department_flag & MSC) + GLOB.nonhuman_positions |= job.title + + if(job.social_class > SOCIAL_CLASS_MED) + GLOB.nobles |= job.title + + return 1 + + +/datum/controller/occupations/proc/Debug(var/text) + if(!Debug2) return 0 + job_debug.Add(text) + return 1 + + +/datum/controller/occupations/proc/GetJob(var/rank) + if(!rank) return null + for(var/datum/job/J in occupations) + if(!J) continue + if(J.title == rank) return J + return null + +/datum/controller/occupations/proc/ShouldCreateRecords(var/rank) + if(!rank) return 0 + var/datum/job/job = GetJob(rank) + if(!job) return 0 + return job.create_record + +/datum/controller/occupations/proc/GetPlayerAltTitle(mob/new_player/player, rank) + return player.client.prefs.GetPlayerAltTitle(GetJob(rank)) + +/datum/controller/occupations/proc/AssignRole(var/mob/new_player/player, var/rank, var/latejoin = 0) + Debug("Running AR, Player: [player], Rank: [rank], LJ: [latejoin]") + if(player && player.mind && rank) + var/datum/job/job = GetJob(rank) + if(!job) + return 0 + if(job.minimum_character_age && (player.client.prefs.age < job.minimum_character_age)) + return 0 + if(jobban_isbanned(player, rank)) + return 0 + if(!job.player_old_enough(player.client)) + return 0 + if(job.is_restricted(player.client.prefs)) + return 0 + + var/position_limit = job.total_positions + if(!latejoin) + position_limit = job.spawn_positions + if((job.current_positions < position_limit) || position_limit == -1) + Debug("Player: [player] is now Rank: [rank], JCP:[job.current_positions], JPL:[position_limit]") + player.mind.assigned_role = rank + player.mind.role_alt_title = GetPlayerAltTitle(player, rank) + unassigned -= player + job.current_positions++ + return 1 + Debug("AR has failed, Player: [player], Rank: [rank]") + return 0 + +/datum/controller/occupations/proc/FreeRole(var/rank) //making additional slot on the fly + var/datum/job/job = GetJob(rank) + if(job && job.current_positions >= job.total_positions && job.total_positions != -1) + job.total_positions++ + return 1 + return 0 + +/datum/controller/occupations/proc/allow_one_more(var/rank) //making additional slot on the fly regardless of whether or not the current slots are full. + var/datum/job/job = GetJob(rank) + if(job) + job.total_positions++ + +/datum/controller/occupations/proc/FindOccupationCandidates(datum/job/job, level, flag) + Debug("Running FOC, Job: [job], Level: [level], Flag: [flag]") + var/list/candidates = list() + for(var/mob/new_player/player in unassigned) + if(jobban_isbanned(player, job.title)) + Debug("FOC isbanned failed, Player: [player]") + continue + if(!job.player_old_enough(player.client)) + Debug("FOC player not old enough, Player: [player]") + continue + if(job.minimum_character_age && (player.client.prefs.age < job.minimum_character_age)) + Debug("FOC character not old enough, Player: [player]") + continue + if(flag && !(flag in player.client.prefs.be_special_role)) + Debug("FOC flag failed, Player: [player], Flag: [flag], ") + continue + if(player.client.prefs.CorrectLevel(job,level)) + Debug("FOC pass, Player: [player], Level:[level]") + candidates += player + return candidates + +/datum/controller/occupations/proc/GiveRandomJob(var/mob/new_player/player) + Debug("GRJ Giving random job, Player: [player]") + for(var/datum/job/job in shuffle(occupations)) + if(!job) + continue + + if(job.minimum_character_age && (player.client.prefs.age < job.minimum_character_age)) + continue + + if(istype(job, GetJob("Assistant"))) // We don't want to give him assistant, that's boring! + continue + + if(job.is_restricted(player.client.prefs)) + continue + + if(job.title in GLOB.command_positions) //If you want a command position, select it! + continue + + if(jobban_isbanned(player, job.title)) + Debug("GRJ isbanned failed, Player: [player], Job: [job.title]") + continue + + if(!job.player_old_enough(player.client)) + Debug("GRJ player not old enough, Player: [player]") + continue + + if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1) + Debug("GRJ Random job given, Player: [player], Job: [job]") + AssignRole(player, job.title) + unassigned -= player + break + +/datum/controller/occupations/proc/ResetOccupations() + for(var/mob/new_player/player in GLOB.player_list) + if((player) && (player.mind)) + player.mind.assigned_role = null + player.mind.special_role = null + SetupOccupations() + unassigned = list() + return + + +///This proc is called before the level loop of DivideOccupations() and will try to select a head, ignoring ALL non-head preferences for every level until it locates a head or runs out of levels to check +/datum/controller/occupations/proc/FillHeadPosition() + for(var/level = 1 to 3) + for(var/command_position in GLOB.command_positions) + var/datum/job/job = GetJob(command_position) + if(!job) continue + var/list/candidates = FindOccupationCandidates(job, level) + if(!candidates.len) continue + + // Build a weighted list, weight by age. + var/list/weightedCandidates = list() + for(var/mob/V in candidates) + // Log-out during round-start? What a bad boy, no head position for you! + if(!V.client) continue + var/age = V.client.prefs.age + + if(age < job.minimum_character_age) // Nope. + continue + + switch(age) + if(job.minimum_character_age to (job.minimum_character_age+10)) + weightedCandidates[V] = 3 // Still a bit young. + if((job.minimum_character_age+10) to (job.ideal_character_age-10)) + weightedCandidates[V] = 6 // Better. + if((job.ideal_character_age-10) to (job.ideal_character_age+10)) + weightedCandidates[V] = 10 // Great. + if((job.ideal_character_age+10) to (job.ideal_character_age+20)) + weightedCandidates[V] = 6 // Still good. + if((job.ideal_character_age+20) to INFINITY) + weightedCandidates[V] = 3 // Geezer. + else + // If there's ABSOLUTELY NOBODY ELSE + if(candidates.len == 1) weightedCandidates[V] = 1 + + + var/mob/new_player/candidate = pickweight(weightedCandidates) + if(AssignRole(candidate, command_position)) + return 1 + return 0 + + +///This proc is called at the start of the level loop of DivideOccupations() and will cause head jobs to be checked before any other jobs of the same level +/datum/controller/occupations/proc/CheckHeadPositions(var/level) + for(var/command_position in GLOB.command_positions) + var/datum/job/job = GetJob(command_position) + if(!job) continue + var/list/candidates = FindOccupationCandidates(job, level) + if(!candidates.len) continue + var/mob/new_player/candidate = pick(candidates) + AssignRole(candidate, command_position) + return + + +/** Proc DivideOccupations +* fills var "assigned_role" for all ready players. +* This proc must not have any side effect besides of modifying "assigned_role". +**/ +/datum/controller/occupations/proc/DivideOccupations() + //Setup new player list and get the jobs list + Debug("Running DO") + SetupOccupations() + + //Holder for Triumvirate is stored in the ticker, this just processes it + if(ticker && ticker.triai) + for(var/datum/job/A in occupations) + if(A.title == "AI") + A.spawn_positions = 3 + break + + //Get the players who are ready + for(var/mob/new_player/player in GLOB.player_list) + if(player.ready && player.mind && !player.mind.assigned_role) + unassigned += player + + Debug("DO, Len: [unassigned.len]") + if(unassigned.len == 0) return 0 + + //Shuffle players and jobs + unassigned = shuffle(unassigned) + + HandleFeedbackGathering() + + //People who wants to be assistants, sure, go on. + Debug("DO, Running Assistant Check 1") + var/datum/job/assist = new DEFAULT_JOB_TYPE () + var/list/assistant_candidates = FindOccupationCandidates(assist, 3) + Debug("AC1, Candidates: [assistant_candidates.len]") + for(var/mob/new_player/player in assistant_candidates) + Debug("AC1 pass, Player: [player]") + AssignRole(player, "Assistant") + assistant_candidates -= player + Debug("DO, AC1 end") + + //Select one head + Debug("DO, Running Head Check") + FillHeadPosition() + Debug("DO, Head Check end") + + //Other jobs are now checked + Debug("DO, Running Standard Check") + + + // New job giving system by Donkie + // This will cause lots of more loops, but since it's only done once it shouldn't really matter much at all. + // Hopefully this will add more randomness and fairness to job giving. + + // Loop through all levels from high to low + var/list/shuffledoccupations = shuffle(occupations) + // var/list/disabled_jobs = ticker.mode.disabled_jobs // So we can use .Find down below without a colon. + for(var/level = 1 to 3) + //Check the head jobs first each level + CheckHeadPositions(level) + + // Loop through all unassigned players + for(var/mob/new_player/player in unassigned) + + // Loop through all jobs + for(var/datum/job/job in shuffledoccupations) // SHUFFLE ME BABY + if(!job || ticker.mode.disabled_jobs.Find(job.title) ) + continue + + if(jobban_isbanned(player, job.title)) + Debug("DO isbanned failed, Player: [player], Job:[job.title]") + continue + + if(!job.player_old_enough(player.client)) + Debug("DO player not old enough, Player: [player], Job:[job.title]") + continue + + // If the player wants that job on this level, then try give it to him. + if(player.client.prefs.CorrectLevel(job,level)) + + // If the job isn't filled + if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1) + Debug("DO pass, Player: [player], Level:[level], Job:[job.title]") + AssignRole(player, job.title) + unassigned -= player + break + + // Hand out random jobs to the people who didn't get any in the last check + // Also makes sure that they got their preference correct + for(var/mob/new_player/player in unassigned) + if(player.client.prefs.alternate_option == GET_RANDOM_JOB) + GiveRandomJob(player) + + Debug("DO, Standard Check end") + + Debug("DO, Running AC2") + + // For those who wanted to be assistant if their preferences were filled, here you go. + for(var/mob/new_player/player in unassigned) + if(player.client.prefs.alternate_option == BE_ASSISTANT) + Debug("AC2 Assistant located, Player: [player]") + if(GLOB.using_map.flags & MAP_HAS_BRANCH) + var/datum/mil_branch/branch = mil_branches.get_branch(player.get_branch_pref()) + AssignRole(player, branch.assistant_job) + else + AssignRole(player, "Assistant") + + //For ones returning to lobby + for(var/mob/new_player/player in unassigned) + if(player.client.prefs.alternate_option == RETURN_TO_LOBBY) + player.ready = 0 + player.new_player_panel() + unassigned -= player + return 1 + + +/datum/controller/occupations/proc/EquipRank(var/mob/living/carbon/human/H, var/rank, var/joined_late = 0) + if(!H) return null + + var/datum/job/job = GetJob(rank) + if(job) + + //Equip job items. + job.setup_account(H) + job.equip(H, H.mind ? H.mind.role_alt_title : "", H.char_branch, H.char_rank) + job.apply_fingerprints(H) + H.staminaexhaust = 250 + endToStaminaModifier(H.my_stats[STAT(end)].level) + + else + to_chat(H, "Your job is [rank] and the game just can't handle it! Please report this bug to an administrator.") + + H.job = rank + + if(!joined_late || job.latejoin_at_spawnpoints) + var/obj/S = get_roundstart_spawnpoint(rank) + + if(istype(S, /obj/effect/landmark/start) && istype(S.loc, /turf)) + H.forceMove(S.loc) + else + var/datum/spawnpoint/spawnpoint = get_spawnpoint_for(H.client, rank) + H.forceMove(pick(spawnpoint.turfs)) + + // Moving wheelchair if they have one + if(H.buckled && istype(H.buckled, /obj/structure/bed/chair/wheelchair)) + H.buckled.forceMove(H.loc) + H.buckled.set_dir(H.dir) + + // If they're head, give them the account info for their department + if(H.mind && job.head_position) + var/remembered_info = "" + var/datum/money_account/department_account = department_accounts[job.department] + + if(department_account) + remembered_info += "Your department's account number is: #[department_account.account_number]
    " + remembered_info += "Your department's account pin is: [department_account.remote_access_pin]
    " + remembered_info += "Your department's account funds are: T[department_account.money]
    " + + H.mind.store_memory(remembered_info) + + var/alt_title = null + if(H.mind) + H.mind.assigned_role = rank + alt_title = H.mind.role_alt_title + + switch(rank) + if("Cyborg") + return H.Robotize() + if("AI") + return H + + if(istype(H)) //give humans wheelchairs, if they need them. + var/obj/item/organ/external/l_foot = H.get_organ(BP_L_FOOT) + var/obj/item/organ/external/r_foot = H.get_organ(BP_R_FOOT) + if(!l_foot || !r_foot) + var/obj/structure/bed/chair/wheelchair/W = new /obj/structure/bed/chair/wheelchair(H.loc) + H.buckled = W + H.update_canmove() + W.set_dir(H.dir) + W.buckled_mob = H + W.add_fingerprint(H) + + to_chat(H, "You are [job.total_positions == 1 ? "the" : "a"] [alt_title ? alt_title : rank].") + + if(job.role_desc) + to_chat(H, "Role Description: [job.role_desc]") + + if(job.supervisors) + to_chat(H, "As the [alt_title ? alt_title : rank] you answer directly to [job.supervisors]. Special circumstances may change this.") + + to_chat(H, "To speak on your squad's radio channel use :h. For the use of other channels, examine your headset. For general use, use ;.") + + if(job.req_admin_notify) + to_chat(H, "You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp.") + + + if(job.has_email) + // EMAIL GENERATION + var/domain + if(H.char_branch && H.char_branch.email_domain) + domain = H.char_branch.email_domain + else + domain = "freemail.nt" + var/sanitized_name = sanitize(replacetext(replacetext(lowertext(H.real_name), " ", "."), "'", "")) + var/complete_login = "[sanitized_name]@[domain]" + + // It is VERY unlikely that we'll have two players, in the same round, with the same name and branch, but still, this is here. + // If such conflict is encountered, a random number will be appended to the email address. If this fails too, no email account will be created. + if(ntnet_global.does_email_exist(complete_login)) + complete_login = "[sanitized_name][random_id(/datum/computer_file/data/email_account/, 100, 999)]@[domain]" + + // If even fallback login generation failed, just don't give them an email. The chance of this happening is astronomically low. + if(ntnet_global.does_email_exist(complete_login)) + to_chat(H, "You were not assigned an email address.") + H.mind.store_memory("You were not assigned an email address.") + else + var/datum/computer_file/data/email_account/EA = new/datum/computer_file/data/email_account() + EA.password = GenerateKey() + EA.login = complete_login + to_chat(H, "Your email account address is [EA.login] and the password is [EA.password]. This information has also been placed into your notes.") + H.mind.store_memory("Your email account address is [EA.login] and the password is [EA.password].") + // END EMAIL GENERATION + + //Gives glasses to the vision impaired + if(H.disabilities & NEARSIGHTED) + var/equipped = H.equip_to_slot_or_del(new /obj/item/clothing/glasses/regular(H), slot_glasses) + if(equipped) + var/obj/item/clothing/glasses/G = H.glasses + G.prescription = 7 + + BITSET(H.hud_updateflag, ID_HUD) + BITSET(H.hud_updateflag, IMPLOYAL_HUD) + BITSET(H.hud_updateflag, SPECIALROLE_HUD) + return H + +/datum/controller/occupations/proc/LoadJobs(jobsfile) //ran during round setup, reads info from jobs.txt -- Urist + if(!config.load_jobs_from_txt) + return 0 + + var/list/jobEntries = file2list(jobsfile) + + for(var/job in jobEntries) + if(!job) + continue + + job = trim(job) + if (!length(job)) + continue + + var/pos = findtext(job, "=") + var/name = null + var/value = null + + if(pos) + name = copytext(job, 1, pos) + value = copytext(job, pos + 1) + else + continue + + if(name && value) + var/datum/job/J = GetJob(name) + if(!J) continue + J.total_positions = text2num(value) + J.spawn_positions = text2num(value) + if(name == "AI" || name == "Cyborg")//I dont like this here but it will do for now + J.total_positions = 0 + + return 1 + + +/datum/controller/occupations/proc/HandleFeedbackGathering() + for(var/datum/job/job in occupations) + var/tmp_str = "|[job.title]|" + + var/level1 = 0 //high + var/level2 = 0 //medium + var/level3 = 0 //low + var/level4 = 0 //never + var/level5 = 0 //banned + var/level6 = 0 //account too young + for(var/mob/new_player/player in GLOB.player_list) + if(!(player.ready && player.mind && !player.mind.assigned_role)) + continue //This player is not ready + if(jobban_isbanned(player, job.title)) + level5++ + continue + if(!job.player_old_enough(player.client)) + level6++ + continue + if(player.client.prefs.CorrectLevel(job, 1)) + level1++ + else if(player.client.prefs.CorrectLevel(job, 2)) + level2++ + else if(player.client.prefs.CorrectLevel(job, 3)) + level3++ + else level4++ //not selected + + tmp_str += "HIGH=[level1]|MEDIUM=[level2]|LOW=[level3]|NEVER=[level4]|BANNED=[level5]|YOUNG=[level6]|-" + feedback_add_details("job_preferences",tmp_str) + + +/** + * Return appropriate /datum/spawnpoint for given client and rank + * + * Spawnpoint will be the one set in preferences for the client, unless the + * preference is not set, or the preference is not appropriate for the rank, in + * which case a fallback will be selected. + */ +/datum/controller/occupations/proc/get_spawnpoint_for(var/client/C, var/rank) + + if(!C) + CRASH("Null client passed to get_spawnpoint_for() proc!") + + var/mob/H = C.mob + var/spawnpoint = C.prefs.spawnpoint + var/datum/spawnpoint/spawnpos + + if(spawnpoint == DEFAULT_SPAWNPOINT_ID) + spawnpoint = GLOB.using_map.default_spawn + + if(spawnpoint) + if(!(spawnpoint in GLOB.using_map.allowed_spawns)) + if(H) + to_chat(H, "Your chosen spawnpoint ([C.prefs.spawnpoint]) is unavailable for the current map. Spawning you at one of the enabled spawn points instead. To resolve this error head to your character's setup and choose a different spawn point.") + spawnpos = null + else + spawnpos = spawntypes()[spawnpoint] + + if(spawnpos && !spawnpos.check_job_spawning(rank)) + if(H) + to_chat(H, "Your chosen spawnpoint ([spawnpos.display_name]) is unavailable for your chosen job ([rank]). Spawning you at another spawn point instead.") + spawnpos = null + + if(!spawnpos) + // Step through all spawnpoints and pick first appropriate for job + for(var/spawntype in GLOB.using_map.allowed_spawns) + var/datum/spawnpoint/candidate = spawntypes()[spawntype] + if(candidate.check_job_spawning(rank)) + spawnpos = candidate + break + + if(!spawnpos) + // Pick at random from all the (wrong) spawnpoints, just so we have one + warning("Could not find an appropriate spawnpoint for job [rank].") + spawnpos = spawntypes()[pick(GLOB.using_map.allowed_spawns)] + + return spawnpos + +/datum/controller/occupations/proc/GetJobByType(var/job_type) + return occupations_by_type[job_type] + +/datum/controller/occupations/proc/GetJobByTitle(var/job_title) + return occupations_by_title[job_title] + +/datum/controller/occupations/proc/get_roundstart_spawnpoint(var/rank) + var/list/loc_list = list() + for(var/obj/effect/landmark/start/sloc in landmarks_list) + if(sloc.name != rank) continue + if(locate(/mob/living) in sloc.loc) continue + loc_list += sloc + if(loc_list.len) + return pick(loc_list) + else + return locate("start*[rank]") // use old stype + +#undef GET_RANDOM_JOB +#undef BE_ASSISTANT +#undef RETURN_TO_LOBBY diff --git a/code/game/jobs/jobs.dm b/code/game/jobs/jobs.dm new file mode 100644 index 00000000..c1fa8620 --- /dev/null +++ b/code/game/jobs/jobs.dm @@ -0,0 +1,64 @@ +var/const/ENG =(1<<0) +var/const/SEC =(1<<1) +var/const/MED =(1<<2) +var/const/SCI =(1<<3) +var/const/CIV =(1<<4) +var/const/COM =(1<<5) +var/const/MSC =(1<<6) +var/const/SRV =(1<<7) +var/const/SUP =(1<<8) +var/const/SPT =(1<<9) +var/const/EXP =(1<<10) + +GLOBAL_LIST_EMPTY(assistant_occupations) + +GLOBAL_LIST_EMPTY(command_positions) + +GLOBAL_LIST_EMPTY(engineering_positions) + +GLOBAL_LIST_EMPTY(medical_positions) + +GLOBAL_LIST_EMPTY(science_positions) + +GLOBAL_LIST_EMPTY(civilian_positions) + +GLOBAL_LIST_EMPTY(security_positions) + +GLOBAL_LIST_INIT(nonhuman_positions, list("pAI")) + +GLOBAL_LIST_EMPTY(service_positions) + +GLOBAL_LIST_EMPTY(supply_positions) + +GLOBAL_LIST_EMPTY(support_positions) + +GLOBAL_LIST_EMPTY(exploration_positions) + +GLOBAL_LIST_EMPTY(unsorted_positions) // for nano manifest + +GLOBAL_LIST_EMPTY(nobles) //For revolution game mode. + + +/proc/guest_jobbans(var/job) + return ((job in GLOB.command_positions) || (job in GLOB.nonhuman_positions) || (job in GLOB.security_positions)) + +/proc/get_job_datums() + var/list/occupations = list() + var/list/all_jobs = typesof(/datum/job) + + for(var/A in all_jobs) + var/datum/job/job = new A() + if(!job) continue + occupations += job + + return occupations + +/proc/get_alternate_titles(var/job) + var/list/jobs = get_job_datums() + var/list/titles = list() + + for(var/datum/job/J in jobs) + if(J.title == job) + titles = J.alt_titles + + return titles diff --git a/code/game/jobs/whitelist.dm b/code/game/jobs/whitelist.dm new file mode 100644 index 00000000..3aef7d71 --- /dev/null +++ b/code/game/jobs/whitelist.dm @@ -0,0 +1,99 @@ +#define WHITELISTFILE "data/whitelist.txt" + +var/list/whitelist = list() + +/hook/startup/proc/loadWhitelist() + if(config.usewhitelist) + load_whitelist() + return 1 + +/proc/load_whitelist() + whitelist = file2list(WHITELISTFILE) + if(!whitelist.len) whitelist = null + +/proc/check_whitelist(mob/M /*, var/rank*/) + if(!whitelist) + return 0 + return ("[M.ckey]" in whitelist) + +/var/list/alien_whitelist = list() + +/hook/startup/proc/loadAlienWhitelist() + if(config.usealienwhitelist) + if(config.usealienwhitelistSQL) + if(!load_alienwhitelistSQL()) + world.log << "Could not load alienwhitelist via SQL" + else + load_alienwhitelist() + return 1 +/proc/load_alienwhitelist() + var/text = file2text("config/alienwhitelist.txt") + if (!text) + log_misc("Failed to load config/alienwhitelist.txt") + return 0 + else + alien_whitelist = splittext(text, "\n") + return 1 +/proc/load_alienwhitelistSQL() + var/DBQuery/query = dbcon_old.NewQuery("SELECT * FROM whitelist") + if(!query.Execute()) + world.log << dbcon_old.ErrorMsg() + return 0 + else + while(query.NextRow()) + var/list/row = query.GetRowData() + if(alien_whitelist[row["ckey"]]) + var/list/A = alien_whitelist[row["ckey"]] + A.Add(row["race"]) + else + alien_whitelist[row["ckey"]] = list(row["race"]) + return 1 + +/proc/is_species_whitelisted(mob/M, var/species_name) + var/datum/species/S = all_species[species_name] + return is_alien_whitelisted(M, S) + +//todo: admin aliens +/proc/is_alien_whitelisted(mob/M, var/species) + if(!M || !species) + return 0 + if(!config.usealienwhitelist) + return 1 + if(check_rights(R_ADMIN, 0, M)) + return 1 + + if(istype(species,/datum/language)) + var/datum/language/L = species + if(!(L.flags & (WHITELISTED|RESTRICTED))) + return 1 + return whitelist_lookup(L.name, M.ckey) + + if(istype(species,/datum/species)) + var/datum/species/S = species + if(!(S.spawn_flags & (SPECIES_IS_WHITELISTED|SPECIES_IS_RESTRICTED))) + return 1 + return whitelist_lookup(S.get_bodytype(S), M.ckey) + + return 0 + +/proc/whitelist_lookup(var/item, var/ckey) + if(!alien_whitelist) + return 0 + + if(config.usealienwhitelistSQL) + //SQL Whitelist + if(!(ckey in alien_whitelist)) + return 0; + var/list/whitelisted = alien_whitelist[ckey] + if(lowertext(item) in whitelisted) + return 1 + else + //Config File Whitelist + for(var/s in alien_whitelist) + if(findtext(s,"[ckey] - [item]")) + return 1 + if(findtext(s,"[ckey] - All")) + return 1 + return 0 + +#undef WHITELISTFILE diff --git a/code/game/machinery/Beacon.dm b/code/game/machinery/Beacon.dm new file mode 100644 index 00000000..83f75339 --- /dev/null +++ b/code/game/machinery/Beacon.dm @@ -0,0 +1,53 @@ +/obj/machinery/bluespace_beacon + + icon = 'icons/obj/objects.dmi' + icon_state = "floor_beaconf" + name = "Bluespace Gigabeacon" + desc = "A device that draws power from bluespace and creates a permanent tracking beacon." + level = 1 // underfloor + anchored = 1 + use_power = 1 + idle_power_usage = 0 + var/obj/item/device/radio/beacon/Beacon + + New() + ..() + var/turf/T = loc + Beacon = new /obj/item/device/radio/beacon + Beacon.invisibility = INVISIBILITY_MAXIMUM + Beacon.loc = T + + hide(!T.is_plating()) + + Destroy() + QDEL_NULL(Beacon) + . = ..() + + // update the invisibility and icon + hide(var/intact) + set_invisibility(intact ? 101 : 0) + update_icon() + + // update the icon_state + update_icon() + var/state="floor_beacon" + + if(invisibility) + icon_state = "[state]f" + + else + icon_state = "[state]" + + Process() + if(!Beacon) + var/turf/T = loc + Beacon = new /obj/item/device/radio/beacon + Beacon.set_invisibility(INVISIBILITY_MAXIMUM) + Beacon.loc = T + if(Beacon) + if(Beacon.loc != loc) + Beacon.loc = loc + + update_icon() + + diff --git a/code/game/machinery/CableLayer.dm b/code/game/machinery/CableLayer.dm new file mode 100644 index 00000000..cab44ead --- /dev/null +++ b/code/game/machinery/CableLayer.dm @@ -0,0 +1,124 @@ +/obj/machinery/cablelayer + name = "automatic cable layer" + + icon = 'icons/obj/stationobjs.dmi' + icon_state = "pipe_d" + density = 1 + var/obj/structure/cable/last_piece + var/obj/item/stack/cable_coil/cable + var/max_cable = 100 + var/on = 0 + +/obj/machinery/cablelayer/New() + cable = new(src) + cable.amount = 100 + ..() + +/obj/machinery/cablelayer/Move(new_turf,M_Dir) + ..() + layCable(new_turf,M_Dir) + +/obj/machinery/cablelayer/attack_hand(mob/user as mob) + if(!cable&&!on) + to_chat(user, "\The [src] doesn't have any cable loaded.") + return + on=!on + user.visible_message("\The [user] [!on?"dea":"a"]ctivates \the [src].", "You switch [src] [on? "on" : "off"]") + return + +/obj/machinery/cablelayer/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(istype(O, /obj/item/stack/cable_coil)) + + var/result = load_cable(O) + if(!result) + to_chat(user, "\The [src]'s cable reel is full.") + else + to_chat(user, "You load [result] lengths of cable into [src].") + return + + if(isWirecutter(O)) + if(cable && cable.amount) + var/m = round(input(usr,"Please specify the length of cable to cut","Cut cable",min(cable.amount,30)) as num, 1) + m = min(m, cable.amount) + m = min(m, 30) + if(m) + playsound(loc, 'sound/items/Wirecutter.ogg', 50, 1) + use_cable(m) + var/obj/item/stack/cable_coil/CC = new (get_turf(src)) + CC.amount = m + else + to_chat(usr, "There's no more cable on the reel.") + +/obj/machinery/cablelayer/examine(mob/user) + . = ..() + to_chat(user, "\The [src]'s cable reel has [cable.amount] length\s left.") + +/obj/machinery/cablelayer/proc/load_cable(var/obj/item/stack/cable_coil/CC) + if(istype(CC) && CC.amount) + var/cur_amount = cable? cable.amount : 0 + var/to_load = max(max_cable - cur_amount,0) + if(to_load) + to_load = min(CC.amount, to_load) + if(!cable) + cable = new(src) + cable.amount = 0 + cable.amount += to_load + CC.use(to_load) + return to_load + else + return 0 + return + +/obj/machinery/cablelayer/proc/use_cable(amount) + if(!cable || cable.amount<1) + visible_message("A red light flashes on \the [src].") + return + cable.use(amount) + if(QDELETED(cable)) + cable = null + return 1 + +/obj/machinery/cablelayer/proc/reset() + last_piece = null + +/obj/machinery/cablelayer/proc/dismantleFloor(var/turf/new_turf) + if(istype(new_turf, /turf/simulated/floor)) + var/turf/simulated/floor/T = new_turf + if(!T.is_plating()) + T.make_plating(!(T.broken || T.burnt)) + return new_turf.is_plating() + +/obj/machinery/cablelayer/proc/layCable(var/turf/new_turf,var/M_Dir) + if(!on) + return reset() + else + dismantleFloor(new_turf) + if(!istype(new_turf) || !dismantleFloor(new_turf)) + return reset() + var/fdirn = turn(M_Dir,180) + for(var/obj/structure/cable/LC in new_turf) // check to make sure there's not a cable there already + if(LC.d1 == fdirn || LC.d2 == fdirn) + return reset() + if(!use_cable(1)) + return reset() + var/obj/structure/cable/NC = new(new_turf) + NC.cableColor("red") + NC.d1 = 0 + NC.d2 = fdirn + NC.update_icon() + + var/datum/powernet/PN + if(last_piece && last_piece.d2 != M_Dir) + last_piece.d1 = min(last_piece.d2, M_Dir) + last_piece.d2 = max(last_piece.d2, M_Dir) + last_piece.update_icon() + PN = last_piece.powernet + + if(!PN) + PN = new() + PN.add_cable(NC) + NC.mergeConnectedNetworks(NC.d2) + + //NC.mergeConnectedNetworksOnTurf() + last_piece = NC + return 1 \ No newline at end of file diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm new file mode 100644 index 00000000..9d4925b9 --- /dev/null +++ b/code/game/machinery/OpTable.dm @@ -0,0 +1,135 @@ +/obj/machinery/optable + name = "Operating Table" + desc = "Used for advanced medical procedures." + icon = 'icons/obj/surgery.dmi' + icon_state = "table2-idle" + density = 1 + anchored = 1.0 + use_power = 1 + idle_power_usage = 1 + active_power_usage = 5 + var/mob/living/carbon/human/victim = null + var/strapped = 0.0 + + var/obj/machinery/computer/operating/computer = null + +/obj/machinery/optable/New() + ..() + for(dir in list(NORTH,EAST,SOUTH,WEST)) + computer = locate(/obj/machinery/computer/operating, get_step(src, dir)) + if (computer) + computer.table = src + break +// spawn(100) //Wont the MC just call this process() before and at the 10 second mark anyway? +// process() + +/obj/machinery/optable/ex_act(severity) + + switch(severity) + if(1.0) + //SN src = null + qdel(src) + return + if(2.0) + if (prob(50)) + //SN src = null + qdel(src) + return + if(3.0) + if (prob(25)) + src.set_density(0) + else + return + +/obj/machinery/optable/attack_hand(mob/user as mob) + if (HULK in usr.mutations) + visible_message("\The [usr] destroys \the [src]!") + src.set_density(0) + qdel(src) + return + +/obj/machinery/optable/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group || (height==0)) return 1 + + if(istype(mover) && mover.checkpass(PASS_FLAG_TABLE)) + return 1 + else + return 0 + + +/obj/machinery/optable/MouseDrop_T(obj/O as obj, mob/user as mob) + + if ((!( istype(O, /obj/item/weapon) ) || user.get_active_hand() != O)) + return + user.drop_item() + if (O.loc != src.loc) + step(O, get_dir(O, src)) + return + +/obj/machinery/optable/proc/check_victim() + if(locate(/mob/living/carbon/human, src.loc)) + var/mob/living/carbon/human/M = locate(/mob/living/carbon/human, src.loc) + if(M.lying) + src.victim = M + icon_state = M.pulse() ? "table2-active" : "table2-idle" + return 1 + src.victim = null + icon_state = "table2-idle" + return 0 + +/obj/machinery/optable/Process() + check_victim() + +/obj/machinery/optable/proc/take_victim(mob/living/carbon/C, mob/living/carbon/user as mob) + if (C == user) + user.visible_message("[user] climbs on \the [src].","You climb on \the [src].") + else + visible_message("\The [C] has been laid on \the [src] by [user].", 3) + if (C.client) + C.client.perspective = EYE_PERSPECTIVE + C.client.eye = src + C.resting = 1 + C.dropInto(loc) + for(var/obj/O in src) + O.dropInto(loc) + src.add_fingerprint(user) + if(ishuman(C)) + var/mob/living/carbon/human/H = C + src.victim = H + icon_state = H.pulse() ? "table2-active" : "table2-idle" + else + icon_state = "table2-idle" + +/obj/machinery/optable/MouseDrop_T(mob/target, mob/user) + + var/mob/living/M = user + if(user.stat || user.restrained() || !check_table(user) || !iscarbon(target)) + return + if(istype(M)) + take_victim(target,user) + else + return ..() + +/obj/machinery/optable/climb_on() + if(usr.stat || !ishuman(usr) || usr.restrained() || !check_table(usr)) + return + + take_victim(usr,usr) + +/obj/machinery/optable/attackby(obj/item/weapon/W as obj, mob/living/carbon/user as mob) + if (istype(W, /obj/item/grab)) + var/obj/item/grab/G = W + if(iscarbon(G.affecting) && check_table(G.affecting)) + take_victim(G.affecting,usr) + qdel(W) + return + +/obj/machinery/optable/proc/check_table(mob/living/carbon/patient as mob) + check_victim() + if(src.victim && get_turf(victim) == get_turf(src) && victim.lying) + to_chat(usr, "\The [src] is already occupied!") + return 0 + if(patient.buckled) + to_chat(usr, "Unbuckle \the [patient] first!") + return 0 + return 1 diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm new file mode 100644 index 00000000..d01a105c --- /dev/null +++ b/code/game/machinery/Sleeper.dm @@ -0,0 +1,251 @@ +/obj/machinery/sleeper + name = "sleeper" + desc = "A fancy bed with built-in injectors, a dialysis machine, and a limited health scanner." + icon = 'icons/obj/Cryogenic2.dmi' + icon_state = "sleeper_0" + density = 1 + anchored = 1 + clicksound = 'sound/machines/buttonbeep.ogg' + clickvol = 30 + var/mob/living/carbon/human/occupant = null + var/list/available_chemicals = list("Inaprovaline" = /datum/reagent/inaprovaline, "Soporific" = /datum/reagent/soporific, "Paracetamol" = /datum/reagent/paracetamol, "Dylovene" = /datum/reagent/dylovene, "Dexalin" = /datum/reagent/dexalin) + var/obj/item/weapon/reagent_containers/glass/beaker = null + var/filtering = 0 + var/pump + var/list/stasis_settings = list(1, 2, 5) + var/stasis = 1 + + use_power = 1 + idle_power_usage = 15 + active_power_usage = 200 //builtin health analyzer, dialysis machine, injectors. + +/obj/machinery/sleeper/Initialize() + . = ..() + beaker = new /obj/item/weapon/reagent_containers/glass/beaker/large(src) + update_icon() + +/obj/machinery/sleeper/Process() + if(stat & (NOPOWER|BROKEN)) + return + + if(filtering > 0) + if(beaker) + if(beaker.reagents.total_volume < beaker.reagents.maximum_volume) + var/pumped = 0 + for(var/datum/reagent/x in occupant.reagents.reagent_list) + occupant.reagents.trans_to_obj(beaker, 3) + pumped++ + if(ishuman(occupant)) + occupant.vessel.trans_to_obj(beaker, pumped + 1) + else + toggle_filter() + if(pump > 0) + if(beaker && istype(occupant)) + if(beaker.reagents.total_volume < beaker.reagents.maximum_volume) + for(var/datum/reagent/x in occupant.ingested.reagent_list) + occupant.ingested.trans_to_obj(beaker, 3) + else + toggle_pump() + + if(iscarbon(occupant) && stasis > 1) + occupant.SetStasis(stasis) + +/obj/machinery/sleeper/update_icon() + icon_state = "sleeper_[occupant ? "1" : "0"]" + +/obj/machinery/sleeper/attack_hand(var/mob/user) + if(..()) + return 1 + + ui_interact(user) + +/obj/machinery/sleeper/ui_interact(var/mob/user, var/ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.outside_state) + var/data[0] + + data["power"] = stat & (NOPOWER|BROKEN) ? 0 : 1 + + var/list/reagents = list() + for(var/T in available_chemicals) + var/list/reagent = list() + reagent["name"] = T + if(occupant && occupant.reagents) + reagent["amount"] = occupant.reagents.get_reagent_amount(T) + reagents += list(reagent) + data["reagents"] = reagents.Copy() + + if(occupant) + var/scan = medical_scan_results(occupant) + scan = replacetext(scan,"'notice'","'white'") + scan = replacetext(scan,"'warning'","'average'") + scan = replacetext(scan,"'danger'","'bad'") + data["occupant"] =scan + else + data["occupant"] = 0 + if(beaker) + data["beaker"] = beaker.reagents.get_free_space() + else + data["beaker"] = -1 + data["filtering"] = filtering + data["pump"] = pump + data["stasis"] = stasis + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "sleeper.tmpl", "Sleeper UI", 600, 600, state = state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/sleeper/CanUseTopic(user) + if(user == occupant) + to_chat(usr, "You can't reach the controls from the inside.") + return STATUS_CLOSE + return ..() + +/obj/machinery/sleeper/OnTopic(user, href_list) + if(href_list["eject"]) + go_out() + return TOPIC_REFRESH + if(href_list["beaker"]) + remove_beaker() + return TOPIC_REFRESH + if(href_list["filter"]) + if(filtering != text2num(href_list["filter"])) + toggle_filter() + return TOPIC_REFRESH + if(href_list["pump"]) + if(filtering != text2num(href_list["pump"])) + toggle_pump() + return TOPIC_REFRESH + if(href_list["chemical"] && href_list["amount"]) + if(occupant && occupant.stat != DEAD) + if(href_list["chemical"] in available_chemicals) // Your hacks are bad and you should feel bad + inject_chemical(user, href_list["chemical"], text2num(href_list["amount"])) + return TOPIC_REFRESH + if(href_list["stasis"]) + var/nstasis = text2num(href_list["stasis"]) + if(stasis != nstasis && nstasis in stasis_settings) + stasis = text2num(href_list["stasis"]) + return TOPIC_REFRESH + +/obj/machinery/sleeper/attack_ai(var/mob/user) + return attack_hand(user) + +/obj/machinery/sleeper/attackby(var/obj/item/I, var/mob/user) + if(istype(I, /obj/item/weapon/reagent_containers/glass)) + add_fingerprint(user) + if(!beaker) + beaker = I + user.drop_item() + I.forceMove(src) + user.visible_message("\The [user] adds \a [I] to \the [src].", "You add \a [I] to \the [src].") + else + to_chat(user, "\The [src] has a beaker already.") + return + else + ..() + +/obj/machinery/sleeper/MouseDrop_T(var/mob/target, var/mob/user) + if(!CanMouseDrop(target, user)) + return + if(!istype(target)) + return + if(target.buckled) + to_chat(user, "Unbuckle the subject before attempting to move them.") + return + go_in(target, user) + +/obj/machinery/sleeper/relaymove(var/mob/user) + ..() + go_out() + +/obj/machinery/sleeper/emp_act(var/severity) + if(filtering) + toggle_filter() + + if(stat & (BROKEN|NOPOWER)) + ..(severity) + return + + if(occupant) + go_out() + + ..(severity) +/obj/machinery/sleeper/proc/toggle_filter() + if(!occupant || !beaker) + filtering = 0 + return + to_chat(occupant, "You feel like your blood is being sucked away.") + filtering = !filtering + +/obj/machinery/sleeper/proc/toggle_pump() + if(!occupant || !beaker) + pump = 0 + return + to_chat(occupant, "You feel a tube jammed down your throat.") + pump = !pump + +/obj/machinery/sleeper/proc/go_in(var/mob/M, var/mob/user) + if(!M) + return + if(stat & (BROKEN|NOPOWER)) + return + if(occupant) + to_chat(user, "\The [src] is already occupied.") + return + + if(M == user) + visible_message("\The [user] starts climbing into \the [src].") + else + visible_message("\The [user] starts putting [M] into \the [src].") + + if(do_after(user, 20, src)) + if(occupant) + to_chat(user, "\The [src] is already occupied.") + return + M.stop_pulling() + if(M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.forceMove(src) + update_use_power(2) + occupant = M + update_icon() + +/obj/machinery/sleeper/proc/go_out() + if(!occupant) + return + if(occupant.client) + occupant.client.eye = occupant.client.mob + occupant.client.perspective = MOB_PERSPECTIVE + occupant.dropInto(loc) + occupant = null + for(var/atom/movable/A in src) // In case an object was dropped inside or something + if(A == beaker) + continue + A.dropInto(loc) + update_use_power(1) + update_icon() + toggle_filter() + +/obj/machinery/sleeper/proc/remove_beaker() + if(beaker) + beaker.dropInto(loc) + beaker = null + toggle_filter() + toggle_pump() + +/obj/machinery/sleeper/proc/inject_chemical(var/mob/living/user, var/chemical_name, var/amount) + if(stat & (BROKEN|NOPOWER)) + return + + var/chemical_type = available_chemicals[chemical_name] + if(occupant && occupant.reagents) + if(occupant.reagents.get_reagent_amount(chemical_type) + amount <= 20) + use_power(amount * CHEM_SYNTH_ENERGY) + occupant.reagents.add_reagent(chemical_type, amount) + to_chat(user, "Occupant now has [occupant.reagents.get_reagent_amount(chemical_type)] unit\s of [chemical_name] in their bloodstream.") + else + to_chat(user, "The subject has too many chemicals.") + else + to_chat(user, "There's no suitable occupant in \the [src].") diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm new file mode 100644 index 00000000..8e51f3e1 --- /dev/null +++ b/code/game/machinery/adv_med.dm @@ -0,0 +1,386 @@ +// Pretty much everything here is stolen from the dna scanner FYI + + +/obj/machinery/bodyscanner + var/mob/living/carbon/human/occupant + var/locked + name = "Body Scanner" + icon = 'icons/obj/Cryogenic2.dmi' + icon_state = "body_scanner_0" + density = 1 + anchored = 1 + + use_power = 1 + idle_power_usage = 60 + active_power_usage = 10000 //10 kW. It's a big all-body scanner. + +/obj/machinery/bodyscanner/relaymove(mob/user as mob) + if (user.stat) + return + src.go_out() + return + +/obj/machinery/bodyscanner/proc/eject() + set category = "Object" + set name = "Eject Body Scanner" + + if (usr.stat != 0) + return + src.go_out() + add_fingerprint(usr) + return + +/obj/machinery/bodyscanner/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + eject() + +/obj/machinery/bodyscanner/verb/move_inside() + set src in oview(1) + set category = "Object" + set name = "Enter Body Scanner" + + if (usr.stat != 0) + return + if (src.occupant) + to_chat(usr, "The scanner is already occupied!") + return + if (usr.abiotic()) + to_chat(usr, "The subject cannot have abiotic items on.") + return + usr.pulling = null + usr.client.perspective = EYE_PERSPECTIVE + usr.client.eye = src + usr.forceMove(src) + src.occupant = usr + update_use_power(2) + src.icon_state = "body_scanner_1" + for(var/obj/O in src) + //O = null + qdel(O) + //Foreach goto(124) + src.add_fingerprint(usr) + return + +/obj/machinery/bodyscanner/proc/go_out() + if ((!( src.occupant ) || src.locked)) + return + for(var/obj/O in src) + O.dropInto(loc) + //Foreach goto(30) + if (src.occupant.client) + src.occupant.client.eye = src.occupant.client.mob + src.occupant.client.perspective = MOB_PERSPECTIVE + src.occupant.dropInto(loc) + src.occupant = null + update_use_power(1) + src.icon_state = "body_scanner_0" + return + +/obj/machinery/bodyscanner/attackby(obj/item/grab/normal/G, user as mob) + if(!istype(G)) + return ..() + if (!ismob(G.affecting)) + return + if (src.occupant) + to_chat(user, "The scanner is already occupied!") + return + if (G.affecting.abiotic()) + to_chat(user, "Subject cannot have abiotic items on.") + return + var/mob/M = G.affecting + M.forceMove(src) + src.occupant = M + update_use_power(2) + src.icon_state = "body_scanner_1" + for(var/obj/O in src) + O.forceMove(loc) + src.add_fingerprint(user) + qdel(G) + +//Like grap-put, but for mouse-drop. +/obj/machinery/bodyscanner/MouseDrop_T(var/mob/target, var/mob/user) + if(!istype(target)) + return + if (!CanMouseDrop(target, user)) + return + if (src.occupant) + to_chat(user, "The scanner is already occupied!") + return + if (target.abiotic()) + to_chat(user, "The subject cannot have abiotic items on.") + return + if (target.buckled) + to_chat(user, "Unbuckle the subject before attempting to move them.") + return + user.visible_message("\The [user] begins placing \the [target] into \the [src].", "You start placing \the [target] into \the [src].") + if(!do_after(user, 30, src)) + return + var/mob/M = target + M.forceMove(src) + src.occupant = M + update_use_power(2) + src.icon_state = "body_scanner_1" + for(var/obj/O in src) + O.forceMove(loc) + src.add_fingerprint(user) + +/obj/machinery/bodyscanner/ex_act(severity) + switch(severity) + if(1.0) + for(var/atom/movable/A as mob|obj in src) + A.dropInto(loc) + ex_act(severity) + //Foreach goto(35) + //SN src = null + qdel(src) + return + if(2.0) + if (prob(50)) + for(var/atom/movable/A as mob|obj in src) + A.dropInto(loc) + ex_act(severity) + //Foreach goto(108) + //SN src = null + qdel(src) + return + if(3.0) + if (prob(25)) + for(var/atom/movable/A as mob|obj in src) + A.dropInto(loc) + ex_act(severity) + //Foreach goto(181) + //SN src = null + qdel(src) + return + else + return + +/obj/machinery/body_scanconsole/ex_act(severity) + + switch(severity) + if(1.0) + //SN src = null + qdel(src) + return + if(2.0) + if (prob(50)) + //SN src = null + qdel(src) + return + else + return + +/obj/machinery/body_scanconsole/update_icon() + if(stat & BROKEN) + icon_state = "body_scannerconsole-p" + else if (stat & NOPOWER) + spawn(rand(0, 15)) + src.icon_state = "body_scannerconsole-p" + else + icon_state = initial(icon_state) + +/obj/machinery/body_scanconsole + var/obj/machinery/bodyscanner/connected + var/delete + var/temphtml + name = "Body Scanner Console" + icon = 'icons/obj/Cryogenic2.dmi' + icon_state = "body_scannerconsole" + density = 0 + anchored = 1 + + +/obj/machinery/body_scanconsole/Initialize() + for(var/D in GLOB.cardinal) + src.connected = locate(/obj/machinery/bodyscanner, get_step(src, D)) + if(src.connected) + break + return ..() + +/* + +/obj/machinery/body_scanconsole/process() //not really used right now + if(stat & (NOPOWER|BROKEN)) + return + //use_power(250) // power stuff + +// var/mob/M //occupant +// if (!( src.status )) //remove this +// return +// if ((src.connected && src.connected.occupant)) //connected & occupant ok +// M = src.connected.occupant +// else +// if (istype(M, /mob)) +// //do stuff +// else +/// src.temphtml = "Process terminated due to lack of occupant in scanning chamber." +// src.status = null +// src.updateDialog() +// return + +*/ + +/obj/machinery/body_scanconsole/attack_ai(user as mob) + return src.attack_hand(user) + +/obj/machinery/body_scanconsole/attack_hand(user as mob) + if(..()) + return + if(stat & (NOPOWER|BROKEN)) + return + if(!connected || (connected.stat & (NOPOWER|BROKEN))) + to_chat(user, "This console is not connected to a functioning body scanner.") + return + if(!ishuman(connected.occupant)) + to_chat(user, "This device can only scan compatible lifeforms.") + return + + var/dat + if (src.delete && src.temphtml) //Window in buffer but its just simple message, so nothing + src.delete = src.delete + else if (!src.delete && src.temphtml) //Window in buffer - its a menu, dont add clear message + dat = text("[]

    Main Menu", src.temphtml, src) + else + if (src.connected) //Is something connected? + dat = connected.occupant.get_medical_data() + dat += "

    Print
    " + else + dat = "Error: No Body Scanner connected." + + dat += text("
    Close", user) + user << browse(dat, "window=scanconsole;size=430x600") + return + + +/obj/machinery/body_scanconsole/OnTopic(user, href_list) + if (href_list["print"]) + if (!src.connected) + to_chat(user, "\icon[src]Error: No body scanner connected.") + return TOPIC_REFRESH + var/mob/living/carbon/human/occupant = src.connected.occupant + if (!src.connected.occupant) + to_chat(user, "\icon[src]The body scanner is empty.") + return TOPIC_REFRESH + if (!istype(occupant,/mob/living/carbon/human)) + to_chat(user, "\icon[src]The body scanner cannot scan that lifeform.") + return TOPIC_REFRESH + new/obj/item/weapon/paper/(loc, "[connected.occupant.get_medical_data()]", "Body scan report - [occupant]") + return TOPIC_REFRESH + +/proc/get_severity(amount) + if(!amount) + return "none" + . = "minor" + if(amount > 50) + . = "severe" + else if(amount > 25) + . = "significant" + else if(amount > 10) + . = "moderate" + +/mob/living/carbon/human/proc/get_medical_data() + var/mob/living/carbon/human/H = src + var/dat = list() + dat +="SCAN RESULTS FOR: [H]" + dat +="Scan performed at [stationtime2text()]
    " + + var/brain_result = "normal" + if(H.should_have_organ(BP_BRAIN)) + var/obj/item/organ/internal/brain/brain = H.internal_organs_by_name[BP_BRAIN] + if(!brain || H.stat == DEAD || (H.status_flags & FAKEDEATH)) + brain_result = "none, patient is braindead" + else if(H.stat != DEAD) + brain_result = "[round(max(0,(1 - brain.damage/brain.max_damage)*100))]%" + else + brain_result = "ERROR - Nonstandard biology" + dat += "Brain activity: [brain_result]" + + var/pulse_result = "normal" + if(H.should_have_organ(BP_HEART)) + if(H.status_flags & FAKEDEATH) + pulse_result = 0 + else + pulse_result = H.get_pulse(1) + else + pulse_result = "ERROR - Nonstandard biology" + dat += "Pulse rate: [pulse_result]bpm." + + // Blood pressure. Based on the idea of a normal blood pressure being 120 over 80. + if(H.get_blood_volume() <= 70) + dat += "Severe blood loss detected." + dat += "Blood pressure: [H.get_blood_pressure()] ([H.get_blood_oxygenation()]% blood oxygenation)" + dat += "Blood volume: [H.vessel.get_reagent_amount(/datum/reagent/blood)]/[H.species.blood_volume]u" + + // Body temperature. + dat += "Body temperature: [H.bodytemperature-T0C]°C ([H.bodytemperature*1.8-459.67]°F)" + + dat += "Physical Trauma:\t[get_severity(H.getBruteLoss())]" + dat += "Burn Severity:\t[get_severity(H.getFireLoss())]" + dat += "Systematic Organ Failure:\t[get_severity(H.getToxLoss())]" + dat += "Oxygen Deprivation:\t[get_severity(H.getOxyLoss())]" + + dat += "Radiation Level:\t[get_severity(H.radiation/5)]" + dat += "Genetic Tissue Damage:\t[get_severity(H.getCloneLoss())]" + if(H.paralysis) + dat += "Paralysis Summary: approx. [H.paralysis/4] seconds left" + + dat += "Antibody levels and immune system perfomance are at [round(H.virus_immunity()*100)]% of baseline." + if (H.virus2.len) + dat += "Viral pathogen detected in blood stream." + + if(H.has_brain_worms()) + dat += "Large growth detected in frontal lobe, possibly cancerous. Surgical removal is recommended." + + if(H.reagents.total_volume) + var/reagentdata[0] + for(var/A in H.reagents.reagent_list) + var/datum/reagent/R = A + if(R.scannable) + reagentdata[R.type] = "[round(H.reagents.get_reagent_amount(R.type), 1)]u [R.name]" + if(reagentdata.len) + dat += "Beneficial reagents detected in subject's blood:" + for(var/d in reagentdata) + dat += reagentdata[d] + + var/list/table = list() + table += "" + for(var/obj/item/organ/external/E in H.organs) + table += "" + if(E.is_stump()) + table += "" + else + table += "" + + table += "" + for(var/obj/item/organ/internal/I in H.internal_organs) + table += "" + table += "" + table += "
    OrganDamageStatus
    [E.name]N/AMissing" + if(E.brute_dam) + table += "[capitalize(get_wound_severity(E.brute_ratio, E.vital))] physical trauma" + if(E.burn_dam) + table += " [capitalize(get_wound_severity(E.burn_ratio, E.vital))] burns" + if(E.brute_dam + E.burn_dam == 0) + table += "None" + table += "[english_list(E.get_scan_results(), nothing_text = "", and_text = ", ")]
    ---INTERNAL ORGANS---
    [I.name]" + if(I.is_broken()) + table += "Severe" + else if(I.is_bruised()) + table += "Moderate" + else if(I.is_damaged()) + table += "Minor" + else + table += "None" + table += "[english_list(I.get_scan_results(), nothing_text = "", and_text = ", ")]
    " + dat += jointext(table,null) + table.Cut() + for(var/organ_name in H.species.has_organ) + if(!locate(H.species.has_organ[organ_name]) in H.internal_organs) + dat += text("No [organ_name] detected.") + + if(H.sdisabilities & BLIND) + dat += text("Cataracts detected.") + if(H.sdisabilities & NEARSIGHTED) + dat += text("Retinal misalignment detected.") + + . = jointext(dat,"
    ") \ No newline at end of file diff --git a/code/game/machinery/ai_slipper.dm b/code/game/machinery/ai_slipper.dm new file mode 100644 index 00000000..e35354e8 --- /dev/null +++ b/code/game/machinery/ai_slipper.dm @@ -0,0 +1,125 @@ +/obj/machinery/ai_slipper + name = "\improper AI Liquid Dispenser" + icon = 'icons/obj/device.dmi' + icon_state = "motion0" + anchored = 1.0 + use_power = 1 + idle_power_usage = 10 + var/uses = 20 + var/disabled = 1 + var/lethal = 0 + var/locked = 1 + var/cooldown_time = 0 + var/cooldown_timeleft = 0 + var/cooldown_on = 0 + req_access = list(access_ai_upload) + + +/obj/machinery/ai_slipper/New() + ..() + update_icon() + +/obj/machinery/ai_slipper/update_icon() + if (stat & NOPOWER || stat & BROKEN) + icon_state = "motion0" + else + icon_state = disabled ? "motion0" : "motion3" + +/obj/machinery/ai_slipper/proc/setState(var/enabled, var/uses) + src.disabled = disabled + src.uses = uses + src.power_change() + +/obj/machinery/ai_slipper/attackby(obj/item/weapon/W, mob/user) + if(stat & (NOPOWER|BROKEN)) + return + if (istype(user, /mob/living/silicon)) + return src.attack_hand(user) + else // trying to unlock the interface + if (src.allowed(usr)) + locked = !locked + to_chat(user, "You [ locked ? "lock" : "unlock"] the device.") + if (locked) + if (user.machine==src) + user.unset_machine() + user << browse(null, "window=ai_slipper") + else + if (user.machine==src) + src.attack_hand(usr) + else + to_chat(user, "Access denied.") + return + return + +/obj/machinery/ai_slipper/attack_ai(mob/user as mob) + return attack_hand(user) + +/obj/machinery/ai_slipper/attack_hand(mob/user as mob) + if(stat & (NOPOWER|BROKEN)) + return + if ( (get_dist(src, user) > 1 )) + if (!istype(user, /mob/living/silicon)) + to_chat(user, text("Too far away.")) + user.unset_machine() + user << browse(null, "window=ai_slipper") + return + + user.set_machine(src) + var/loc = src.loc + if (istype(loc, /turf)) + loc = loc:loc + if (!istype(loc, /area)) + to_chat(user, text("Turret badly positioned - loc.loc is [].", loc)) + return + var/area/area = loc + var/t = "AI Liquid Dispenser ([area.name])
    " + + if(src.locked && (!istype(user, /mob/living/silicon))) + t += "(Swipe ID card to unlock control panel.)
    " + else + t += text("Dispenser [] - []?
    \n", src.disabled?"deactivated":"activated", src, src.disabled?"Enable":"Disable") + t += text("Uses Left: [uses]. Activate the dispenser?
    \n") + + user << browse(t, "window=computer;size=575x450") + onclose(user, "computer") + return + +/obj/machinery/ai_slipper/CanUseTopic(user) + if(locked && !issilicon(user)) + to_chat(user, "The control panel is locked!") + return min(..(), STATUS_UPDATE) + return ..() + +/obj/machinery/ai_slipper/OnTopic(user, href_list) + if (href_list["toggleOn"]) + src.disabled = !src.disabled + update_icon() + . = TOPIC_REFRESH + if (href_list["toggleUse"]) + if(!(cooldown_on || disabled)) + new /obj/effect/effect/foam(src.loc) + src.uses-- + cooldown_on = 1 + cooldown_time = world.timeofday + 100 + slip_process() + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + attack_hand(user) + +/obj/machinery/ai_slipper/proc/slip_process() + while(cooldown_time - world.timeofday > 0) + var/ticksleft = cooldown_time - world.timeofday + + if(ticksleft > 1e5) + cooldown_time = world.timeofday + 10 // midnight rollover + + + cooldown_timeleft = (ticksleft / 10) + sleep(5) + if (uses <= 0) + return + if (uses >= 0) + cooldown_on = 0 + src.power_change() + return diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm new file mode 100644 index 00000000..b608895c --- /dev/null +++ b/code/game/machinery/alarm.dm @@ -0,0 +1,1212 @@ +//////////////////////////////////////// +//CONTAINS: Air Alarms and Fire Alarms// +//////////////////////////////////////// + +#define AALARM_MODE_SCRUBBING 1 +#define AALARM_MODE_REPLACEMENT 2 //like scrubbing, but faster. +#define AALARM_MODE_PANIC 3 //constantly sucks all air +#define AALARM_MODE_CYCLE 4 //sucks off all air, then refill and switches to scrubbing +#define AALARM_MODE_FILL 5 //emergency fill +#define AALARM_MODE_OFF 6 //Shuts it all down. + +#define AALARM_SCREEN_MAIN 1 +#define AALARM_SCREEN_VENT 2 +#define AALARM_SCREEN_SCRUB 3 +#define AALARM_SCREEN_MODE 4 +#define AALARM_SCREEN_SENSORS 5 + +#define AALARM_REPORT_TIMEOUT 100 + +#define RCON_NO 1 +#define RCON_AUTO 2 +#define RCON_YES 3 + +#define MAX_TEMPERATURE 90 +#define MIN_TEMPERATURE -40 + +//all air alarms in area are connected via magic +/area + var/obj/machinery/alarm/master_air_alarm + var/list/air_vent_names = list() + var/list/air_scrub_names = list() + var/list/air_vent_info = list() + var/list/air_scrub_info = list() + +/obj/machinery/alarm + name = "alarm" + icon = 'icons/obj/monitors.dmi' + icon_state = "alarm0" + anchored = 1 + use_power = 1 + idle_power_usage = 80 + active_power_usage = 1000 //For heating/cooling rooms. 1000 joules equates to about 1 degree every 2 seconds for a single tile of air. + power_channel = ENVIRON + req_one_access = list(access_atmospherics, access_engine_equip) + clicksound = "button" + clickvol = 30 + + layer = ABOVE_WINDOW_LAYER + + var/alarm_id = null + var/breach_detection = 1 // Whether to use automatic breach detection or not + var/frequency = 1439 + //var/skipprocess = 0 //Experimenting + var/alarm_frequency = 1437 + var/remote_control = 0 + var/rcon_setting = 2 + var/rcon_time = 0 + var/locked = 1 + var/wiresexposed = 0 // If it's been screwdrivered open. + var/aidisabled = 0 + var/shorted = 0 + + var/datum/wires/alarm/wires + + var/mode = AALARM_MODE_SCRUBBING + var/screen = AALARM_SCREEN_MAIN + var/area_uid + var/area/alarm_area + var/buildstage = 2 //2 is built, 1 is building, 0 is frame. + + var/target_temperature = T0C+20 + var/regulating_temperature = 0 + + var/datum/radio_frequency/radio_connection + + var/list/TLV = list() + var/list/trace_gas = list("sleeping_agent") //list of other gases that this air alarm is able to detect + + var/danger_level = 0 + var/pressure_dangerlevel = 0 + var/oxygen_dangerlevel = 0 + var/co2_dangerlevel = 0 + var/phoron_dangerlevel = 0 + var/temperature_dangerlevel = 0 + var/other_dangerlevel = 0 + + var/report_danger_level = 1 + +/obj/machinery/alarm/cold + target_temperature = T0C+4 + +/obj/machinery/alarm/nobreach + breach_detection = 0 + +/obj/machinery/alarm/monitor + report_danger_level = 0 + breach_detection = 0 + +/obj/machinery/alarm/server/New() + ..() + req_access = list(access_rd, access_atmospherics, access_engine_equip) + TLV["temperature"] = list(T0C-26, T0C, T0C+30, T0C+40) // K + target_temperature = T0C+10 + +/obj/machinery/alarm/Destroy() + unregister_radio(src, frequency) + qdel(wires) + wires = null + if(alarm_area && alarm_area.master_air_alarm == src) + alarm_area.master_air_alarm = null + elect_master(exclude_self = TRUE) + return ..() + +/obj/machinery/alarm/New(var/loc, var/dir, atom/frame) + ..(loc) + + if(dir) + src.set_dir(dir) + + if(istype(frame)) + buildstage = 0 + wiresexposed = 1 + pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24) + pixel_y = (dir & 3)? (dir ==1 ? -24 : 24) : 0 + update_icon() + frame.transfer_fingerprints_to(src) + +/obj/machinery/alarm/Initialize() + . = ..() + alarm_area = get_area(src) + area_uid = alarm_area.uid + if (name == "alarm") + SetName("[alarm_area.name] Air Alarm") + + if(!wires) + wires = new(src) + + // breathable air according to human/Life() + TLV["oxygen"] = list(16, 19, 135, 140) // Partial pressure, kpa + TLV["carbon dioxide"] = list(-1.0, -1.0, 5, 10) // Partial pressure, kpa + TLV["phoron"] = list(-1.0, -1.0, 0.2, 0.5) // Partial pressure, kpa + TLV["other"] = list(-1.0, -1.0, 0.5, 1.0) // Partial pressure, kpa + TLV["pressure"] = list(ONE_ATMOSPHERE*0.80,ONE_ATMOSPHERE*0.90,ONE_ATMOSPHERE*1.10,ONE_ATMOSPHERE*1.20) /* kpa */ + TLV["temperature"] = list(T0C-26, T0C, T0C+40, T0C+66) // K + + set_frequency(frequency) + if (!master_is_operating()) + elect_master() + +/obj/machinery/alarm/Process() + if((stat & (NOPOWER|BROKEN)) || shorted || buildstage != 2) + return + + var/turf/simulated/location = loc + if(!istype(location)) return//returns if loc is not simulated + + var/datum/gas_mixture/environment = location.return_air() + + //Handle temperature adjustment here. + handle_heating_cooling(environment) + + var/old_level = danger_level + var/old_pressurelevel = pressure_dangerlevel + danger_level = overall_danger_level(environment) + + if (old_level != danger_level) + apply_danger_level(danger_level) + + if (old_pressurelevel != pressure_dangerlevel) + if (breach_detected()) + mode = AALARM_MODE_OFF + apply_mode() + + if (mode==AALARM_MODE_CYCLE && environment.return_pressure() 2.0) + update_use_power(2) + regulating_temperature = 1 + visible_message("\The [src] clicks as it starts [environment.temperature > target_temperature ? "cooling" : "heating"] the room.",\ + "You hear a click and a faint electronic hum.") + else + //check for when we should stop adjusting temperature + if (get_danger_level(target_temperature, TLV["temperature"]) || abs(environment.temperature - target_temperature) <= 0.5) + update_use_power(1) + regulating_temperature = 0 + visible_message("\The [src] clicks quietly as it stops [environment.temperature > target_temperature ? "cooling" : "heating"] the room.",\ + "You hear a click as a faint electronic humming stops.") + + if (regulating_temperature) + if(target_temperature > T0C + MAX_TEMPERATURE) + target_temperature = T0C + MAX_TEMPERATURE + + if(target_temperature < T0C + MIN_TEMPERATURE) + target_temperature = T0C + MIN_TEMPERATURE + + var/datum/gas_mixture/gas + gas = environment.remove(0.25*environment.total_moles) + if(gas) + + if (gas.temperature <= target_temperature) //gas heating + var/energy_used = min( gas.get_thermal_energy_change(target_temperature) , active_power_usage) + + gas.add_thermal_energy(energy_used) + //use_power(energy_used, ENVIRON) //handle by update_use_power instead + else //gas cooling + var/heat_transfer = min(abs(gas.get_thermal_energy_change(target_temperature)), active_power_usage) + + //Assume the heat is being pumped into the hull which is fixed at 20 C + //none of this is really proper thermodynamics but whatever + + var/cop = gas.temperature/T20C //coefficient of performance -> power used = heat_transfer/cop + + heat_transfer = min(heat_transfer, cop * active_power_usage) //this ensures that we don't use more than active_power_usage amount of power + + heat_transfer = -gas.add_thermal_energy(-heat_transfer) //get the actual heat transfer + + //use_power(heat_transfer / cop, ENVIRON) //handle by update_use_power instead + + environment.merge(gas) + +/obj/machinery/alarm/proc/overall_danger_level(var/datum/gas_mixture/environment) + var/partial_pressure = R_IDEAL_GAS_EQUATION*environment.temperature/environment.volume + var/environment_pressure = environment.return_pressure() + + var/other_moles = 0 + for(var/g in trace_gas) + other_moles += environment.gas[g] //this is only going to be used in a partial pressure calc, so we don't need to worry about group_multiplier here. + + pressure_dangerlevel = get_danger_level(environment_pressure, TLV["pressure"]) + oxygen_dangerlevel = get_danger_level(environment.gas["oxygen"]*partial_pressure, TLV["oxygen"]) + co2_dangerlevel = get_danger_level(environment.gas["carbon_dioxide"]*partial_pressure, TLV["carbon dioxide"]) + phoron_dangerlevel = get_danger_level(environment.gas["phoron"]*partial_pressure, TLV["phoron"]) + temperature_dangerlevel = get_danger_level(environment.temperature, TLV["temperature"]) + other_dangerlevel = get_danger_level(other_moles*partial_pressure, TLV["other"]) + + return max( + pressure_dangerlevel, + oxygen_dangerlevel, + co2_dangerlevel, + phoron_dangerlevel, + other_dangerlevel, + temperature_dangerlevel + ) + +// Returns whether this air alarm thinks there is a breach, given the sensors that are available to it. +/obj/machinery/alarm/proc/breach_detected() + var/turf/simulated/location = loc + + if(!istype(location)) + return 0 + + if(breach_detection == 0) + return 0 + + var/datum/gas_mixture/environment = location.return_air() + var/environment_pressure = environment.return_pressure() + var/pressure_levels = TLV["pressure"] + + if (environment_pressure <= pressure_levels[1]) //low pressures + if (!(mode == AALARM_MODE_PANIC || mode == AALARM_MODE_CYCLE)) + playsound(src.loc, 'sound/machines/airalarm.ogg', 25, 0, 4) + return 1 + + return 0 + + +/obj/machinery/alarm/proc/master_is_operating() + return alarm_area.master_air_alarm && !(alarm_area.master_air_alarm.stat & (NOPOWER|BROKEN)) + + +/obj/machinery/alarm/proc/elect_master(exclude_self = FALSE) + for (var/obj/machinery/alarm/AA in alarm_area) + if(exclude_self && AA == src) + continue + if (!(AA.stat & (NOPOWER|BROKEN))) + alarm_area.master_air_alarm = AA + return 1 + return 0 + +/obj/machinery/alarm/proc/get_danger_level(var/current_value, var/list/danger_levels) + if((current_value >= danger_levels[4] && danger_levels[4] > 0) || current_value <= danger_levels[1]) + return 2 + if((current_value >= danger_levels[3] && danger_levels[3] > 0) || current_value <= danger_levels[2]) + return 1 + return 0 + +/obj/machinery/alarm/update_icon() + if(wiresexposed) + icon_state = "alarmx" + set_light(0) + return + if((stat & (NOPOWER|BROKEN)) || shorted) + icon_state = "alarmp" + set_light(0) + return + + var/icon_level = danger_level + if (alarm_area.atmosalm) + icon_level = max(icon_level, 1) //if there's an atmos alarm but everything is okay locally, no need to go past yellow + + var/new_color = null + switch(icon_level) + if (0) + icon_state = "alarm0" + new_color = COLOR_LIME + if (1) + icon_state = "alarm2" //yes, alarm2 is yellow alarm + new_color = COLOR_SUN + if (2) + icon_state = "alarm1" + new_color = COLOR_RED_LIGHT + + set_light(l_range = 2, l_power = 0.6, l_color = new_color) + +/obj/machinery/alarm/receive_signal(datum/signal/signal) + if(stat & (NOPOWER|BROKEN)) + return + if (alarm_area.master_air_alarm != src) + if (master_is_operating()) + return + elect_master() + if (alarm_area.master_air_alarm != src) + return + if(!signal || signal.encryption) + return + var/id_tag = signal.data["tag"] + if (!id_tag) + return + if (signal.data["area"] != area_uid) + return + if (signal.data["sigtype"] != "status") + return + + var/dev_type = signal.data["device"] + if(!(id_tag in alarm_area.air_scrub_names) && !(id_tag in alarm_area.air_vent_names)) + register_env_machine(id_tag, dev_type) + if(dev_type == "AScr") + alarm_area.air_scrub_info[id_tag] = signal.data + else if(dev_type == "AVP") + alarm_area.air_vent_info[id_tag] = signal.data + +/obj/machinery/alarm/proc/register_env_machine(var/m_id, var/device_type) + var/new_name + if (device_type=="AVP") + new_name = "[alarm_area.name] Vent Pump #[alarm_area.air_vent_names.len+1]" + alarm_area.air_vent_names[m_id] = new_name + else if (device_type=="AScr") + new_name = "[alarm_area.name] Air Scrubber #[alarm_area.air_scrub_names.len+1]" + alarm_area.air_scrub_names[m_id] = new_name + else + return + spawn (10) + send_signal(m_id, list("init" = new_name) ) + +/obj/machinery/alarm/proc/refresh_all() + for(var/id_tag in alarm_area.air_vent_names) + var/list/I = alarm_area.air_vent_info[id_tag] + if (I && I["timestamp"]+AALARM_REPORT_TIMEOUT/2 > world.time) + continue + send_signal(id_tag, list("status") ) + for(var/id_tag in alarm_area.air_scrub_names) + var/list/I = alarm_area.air_scrub_info[id_tag] + if (I && I["timestamp"]+AALARM_REPORT_TIMEOUT/2 > world.time) + continue + send_signal(id_tag, list("status") ) + +/obj/machinery/alarm/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_TO_AIRALARM) + +/obj/machinery/alarm/proc/send_signal(var/target, var/list/command)//sends signal 'command' to 'target'. Returns 0 if no radio connection, 1 otherwise + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data = command + signal.data["tag"] = target + signal.data["sigtype"] = "command" + + radio_connection.post_signal(src, signal, RADIO_FROM_AIRALARM) +// log_debug(text("Signal [] Broadcasted to []", command, target)) + + return 1 + +/obj/machinery/alarm/proc/apply_mode() + //propagate mode to other air alarms in the area + //TODO: make it so that players can choose between applying the new mode to the room they are in (related area) vs the entire alarm area + for (var/obj/machinery/alarm/AA in alarm_area) + AA.mode = mode + + switch(mode) + if(AALARM_MODE_SCRUBBING) + for(var/device_id in alarm_area.air_scrub_names) + send_signal(device_id, list("power"= 1, "co2_scrub"= 1, "scrubbing"= 1, "panic_siphon"= 0) ) + for(var/device_id in alarm_area.air_vent_names) + send_signal(device_id, list("power"= 1, "checks"= "default", "set_external_pressure"= "default") ) + + if(AALARM_MODE_PANIC, AALARM_MODE_CYCLE) + for(var/device_id in alarm_area.air_scrub_names) + send_signal(device_id, list("power"= 1, "panic_siphon"= 1) ) + for(var/device_id in alarm_area.air_vent_names) + send_signal(device_id, list("power"= 0) ) + + if(AALARM_MODE_REPLACEMENT) + for(var/device_id in alarm_area.air_scrub_names) + send_signal(device_id, list("power"= 1, "panic_siphon"= 1) ) + for(var/device_id in alarm_area.air_vent_names) + send_signal(device_id, list("power"= 1, "checks"= "default", "set_external_pressure"= "default") ) + + if(AALARM_MODE_FILL) + for(var/device_id in alarm_area.air_scrub_names) + send_signal(device_id, list("power"= 0) ) + for(var/device_id in alarm_area.air_vent_names) + send_signal(device_id, list("power"= 1, "checks"= "default", "set_external_pressure"= "default") ) + + if(AALARM_MODE_OFF) + for(var/device_id in alarm_area.air_scrub_names) + send_signal(device_id, list("power"= 0) ) + for(var/device_id in alarm_area.air_vent_names) + send_signal(device_id, list("power"= 0) ) + +/obj/machinery/alarm/proc/apply_danger_level(var/new_danger_level) + if (report_danger_level && alarm_area.atmosalert(new_danger_level, src)) + post_alert(new_danger_level) + + update_icon() + +/obj/machinery/alarm/proc/post_alert(alert_level) + var/datum/radio_frequency/frequency = radio_controller.return_frequency(alarm_frequency) + if(!frequency) + return + + var/datum/signal/alert_signal = new + alert_signal.source = src + alert_signal.transmission_method = 1 + alert_signal.data["zone"] = alarm_area.name + alert_signal.data["type"] = "Atmospheric" + + if(alert_level==2) + alert_signal.data["alert"] = "severe" + else if (alert_level==1) + alert_signal.data["alert"] = "minor" + else if (alert_level==0) + alert_signal.data["alert"] = "clear" + + frequency.post_signal(src, alert_signal) + +/obj/machinery/alarm/attack_ai(mob/user) + ui_interact(user) + +/obj/machinery/alarm/attack_hand(mob/user) + . = ..() + if (.) + return + return interact(user) + +/obj/machinery/alarm/interact(mob/user) + ui_interact(user) + wires.Interact(user) + +/obj/machinery/alarm/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state) + var/data[0] + var/remote_connection = 0 + var/remote_access = 0 + if(state) + var/list/href = state.href_list(user) + remote_connection = href["remote_connection"] // Remote connection means we're non-adjacent/connecting from another computer + remote_access = href["remote_access"] // Remote access means we also have the privilege to alter the air alarm. + + data["locked"] = locked && !issilicon(user) + data["remote_connection"] = remote_connection + data["remote_access"] = remote_access + data["rcon"] = rcon_setting + data["screen"] = screen + + populate_status(data) + + if(!(locked && !remote_connection) || remote_access || issilicon(user)) + populate_controls(data) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "air_alarm.tmpl", src.name, 325, 625, master_ui = master_ui, state = state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/alarm/proc/populate_status(var/data) + var/turf/location = get_turf(src) + var/datum/gas_mixture/environment = location.return_air() + var/total = environment.total_moles + + var/list/environment_data = new + data["has_environment"] = total + if(total) + var/pressure = environment.return_pressure() + environment_data[++environment_data.len] = list("name" = "Pressure", "value" = pressure, "unit" = "kPa", "danger_level" = pressure_dangerlevel) + environment_data[++environment_data.len] = list("name" = "Oxygen", "value" = environment.gas["oxygen"] / total * 100, "unit" = "%", "danger_level" = oxygen_dangerlevel) + environment_data[++environment_data.len] = list("name" = "Carbon dioxide", "value" = environment.gas["carbon_dioxide"] / total * 100, "unit" = "%", "danger_level" = co2_dangerlevel) + environment_data[++environment_data.len] = list("name" = "Toxins", "value" = environment.gas["phoron"] / total * 100, "unit" = "%", "danger_level" = phoron_dangerlevel) + environment_data[++environment_data.len] = list("name" = "Temperature", "value" = environment.temperature, "unit" = "K ([round(environment.temperature - T0C, 0.1)]C)", "danger_level" = temperature_dangerlevel) + data["total_danger"] = danger_level + data["environment"] = environment_data + data["atmos_alarm"] = alarm_area.atmosalm + data["fire_alarm"] = alarm_area.fire != null + data["target_temperature"] = "[target_temperature - T0C]C" + +/obj/machinery/alarm/proc/populate_controls(var/list/data) + switch(screen) + if(AALARM_SCREEN_MAIN) + data["mode"] = mode + if(AALARM_SCREEN_VENT) + var/vents[0] + for(var/id_tag in alarm_area.air_vent_names) + var/long_name = alarm_area.air_vent_names[id_tag] + var/list/info = alarm_area.air_vent_info[id_tag] + if(!info) + continue + vents[++vents.len] = list( + "id_tag" = id_tag, + "long_name" = sanitize(long_name), + "power" = info["power"], + "checks" = info["checks"], + "direction" = info["direction"], + "external" = info["external"] + ) + data["vents"] = vents + if(AALARM_SCREEN_SCRUB) + var/scrubbers[0] + for(var/id_tag in alarm_area.air_scrub_names) + var/long_name = alarm_area.air_scrub_names[id_tag] + var/list/info = alarm_area.air_scrub_info[id_tag] + if(!info) + continue + scrubbers[++scrubbers.len] = list( + "id_tag" = id_tag, + "long_name" = sanitize(long_name), + "power" = info["power"], + "scrubbing" = info["scrubbing"], + "panic" = info["panic"], + "filters" = list() + ) + scrubbers[scrubbers.len]["filters"] += list(list("name" = "Oxygen", "command" = "o2_scrub", "val" = info["filter_o2"])) + scrubbers[scrubbers.len]["filters"] += list(list("name" = "Nitrogen", "command" = "n2_scrub", "val" = info["filter_n2"])) + scrubbers[scrubbers.len]["filters"] += list(list("name" = "Carbon Dioxide", "command" = "co2_scrub","val" = info["filter_co2"])) + scrubbers[scrubbers.len]["filters"] += list(list("name" = "Toxin" , "command" = "tox_scrub","val" = info["filter_phoron"])) + scrubbers[scrubbers.len]["filters"] += list(list("name" = "Nitrous Oxide", "command" = "n2o_scrub","val" = info["filter_n2o"])) + data["scrubbers"] = scrubbers + if(AALARM_SCREEN_MODE) + var/modes[0] + modes[++modes.len] = list("name" = "Filtering - Scrubs out contaminants", "mode" = AALARM_MODE_SCRUBBING, "selected" = mode == AALARM_MODE_SCRUBBING, "danger" = 0) + modes[++modes.len] = list("name" = "Replace Air - Siphons out air while replacing", "mode" = AALARM_MODE_REPLACEMENT, "selected" = mode == AALARM_MODE_REPLACEMENT, "danger" = 0) + modes[++modes.len] = list("name" = "Panic - Siphons air out of the room", "mode" = AALARM_MODE_PANIC, "selected" = mode == AALARM_MODE_PANIC, "danger" = 1) + modes[++modes.len] = list("name" = "Cycle - Siphons air before replacing", "mode" = AALARM_MODE_CYCLE, "selected" = mode == AALARM_MODE_CYCLE, "danger" = 1) + modes[++modes.len] = list("name" = "Fill - Shuts off scrubbers and opens vents", "mode" = AALARM_MODE_FILL, "selected" = mode == AALARM_MODE_FILL, "danger" = 0) + modes[++modes.len] = list("name" = "Off - Shuts off vents and scrubbers", "mode" = AALARM_MODE_OFF, "selected" = mode == AALARM_MODE_OFF, "danger" = 0) + data["modes"] = modes + data["mode"] = mode + if(AALARM_SCREEN_SENSORS) + var/list/selected + var/thresholds[0] + + var/list/gas_names = list( + "oxygen" = "O2", + "carbon dioxide" = "CO2", + "phoron" = "Toxin", + "other" = "Other") + for (var/g in gas_names) + thresholds[++thresholds.len] = list("name" = gas_names[g], "settings" = list()) + selected = TLV[g] + for(var/i = 1, i <= 4, i++) + thresholds[thresholds.len]["settings"] += list(list("env" = g, "val" = i, "selected" = selected[i])) + + selected = TLV["pressure"] + thresholds[++thresholds.len] = list("name" = "Pressure", "settings" = list()) + for(var/i = 1, i <= 4, i++) + thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = i, "selected" = selected[i])) + + selected = TLV["temperature"] + thresholds[++thresholds.len] = list("name" = "Temperature", "settings" = list()) + for(var/i = 1, i <= 4, i++) + thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = i, "selected" = selected[i])) + + + data["thresholds"] = thresholds + +/obj/machinery/alarm/CanUseTopic(var/mob/user, var/datum/topic_state/state, var/href_list = list()) + if(buildstage != 2) + return STATUS_CLOSE + + if(aidisabled && isAI(user)) + to_chat(user, "AI control for \the [src] interface has been disabled.") + return STATUS_CLOSE + + . = shorted ? STATUS_DISABLED : STATUS_INTERACTIVE + + if(. == STATUS_INTERACTIVE) + var/extra_href = state.href_list(user) + // Prevent remote users from altering RCON settings unless they already have access + if(href_list["rcon"] && extra_href["remote_connection"] && !extra_href["remote_access"]) + . = STATUS_UPDATE + + return min(..(), .) + +/obj/machinery/alarm/OnTopic(user, href_list, var/datum/topic_state/state) + // hrefs that can always be called -walter0o + if(href_list["rcon"]) + var/attempted_rcon_setting = text2num(href_list["rcon"]) + + switch(attempted_rcon_setting) + if(RCON_NO) + rcon_setting = RCON_NO + if(RCON_AUTO) + rcon_setting = RCON_AUTO + if(RCON_YES) + rcon_setting = RCON_YES + return TOPIC_REFRESH + + if(href_list["temperature"]) + var/list/selected = TLV["temperature"] + var/max_temperature = min(selected[3] - T0C, MAX_TEMPERATURE) + var/min_temperature = max(selected[2] - T0C, MIN_TEMPERATURE) + var/input_temperature = input(user, "What temperature would you like the system to mantain? (Capped between [min_temperature] and [max_temperature]C)", "Thermostat Controls", target_temperature - T0C) as num|null + if(isnum(input_temperature) && CanUseTopic(user, state)) + if(input_temperature > max_temperature || input_temperature < min_temperature) + to_chat(user, "Temperature must be between [min_temperature]C and [max_temperature]C") + else + target_temperature = input_temperature + T0C + return TOPIC_REFRESH + + // hrefs that need the AA unlocked -walter0o + var/extra_href = state.href_list(user) + if(!(locked && !extra_href["remote_connection"]) || extra_href["remote_access"] || issilicon(user)) + if(href_list["command"]) + var/device_id = href_list["id_tag"] + switch(href_list["command"]) + if("set_external_pressure") + var/input_pressure = input(user, "What pressure you like the system to mantain?", "Pressure Controls") as num|null + if(isnum(input_pressure) && CanUseTopic(user, state)) + send_signal(device_id, list(href_list["command"] = input_pressure)) + return TOPIC_REFRESH + + if("reset_external_pressure") + send_signal(device_id, list(href_list["command"] = ONE_ATMOSPHERE)) + return TOPIC_REFRESH + + if( "power", + "adjust_external_pressure", + "checks", + "o2_scrub", + "n2_scrub", + "co2_scrub", + "tox_scrub", + "n2o_scrub", + "panic_siphon", + "scrubbing") + + send_signal(device_id, list(href_list["command"] = text2num(href_list["val"]) ) ) + return TOPIC_REFRESH + + if("set_threshold") + var/env = href_list["env"] + var/threshold = text2num(href_list["var"]) + var/list/selected = TLV[env] + var/list/thresholds = list("lower bound", "low warning", "high warning", "upper bound") + var/newval = input(user, "Enter [thresholds[threshold]] for [env]", "Alarm triggers", selected[threshold]) as null|num + if (isnull(newval) || !CanUseTopic(user, state)) + return TOPIC_HANDLED + if (newval<0) + selected[threshold] = -1.0 + else if (env=="temperature" && newval>5000) + selected[threshold] = 5000 + else if (env=="pressure" && newval>50*ONE_ATMOSPHERE) + selected[threshold] = 50*ONE_ATMOSPHERE + else if (env!="temperature" && env!="pressure" && newval>200) + selected[threshold] = 200 + else + newval = round(newval,0.01) + selected[threshold] = newval + if(threshold == 1) + if(selected[1] > selected[2]) + selected[2] = selected[1] + if(selected[1] > selected[3]) + selected[3] = selected[1] + if(selected[1] > selected[4]) + selected[4] = selected[1] + if(threshold == 2) + if(selected[1] > selected[2]) + selected[1] = selected[2] + if(selected[2] > selected[3]) + selected[3] = selected[2] + if(selected[2] > selected[4]) + selected[4] = selected[2] + if(threshold == 3) + if(selected[1] > selected[3]) + selected[1] = selected[3] + if(selected[2] > selected[3]) + selected[2] = selected[3] + if(selected[3] > selected[4]) + selected[4] = selected[3] + if(threshold == 4) + if(selected[1] > selected[4]) + selected[1] = selected[4] + if(selected[2] > selected[4]) + selected[2] = selected[4] + if(selected[3] > selected[4]) + selected[3] = selected[4] + + apply_mode() + return TOPIC_REFRESH + + if(href_list["screen"]) + screen = text2num(href_list["screen"]) + return TOPIC_REFRESH + + if(href_list["atmos_unlock"]) + switch(href_list["atmos_unlock"]) + if("0") + alarm_area.air_doors_close() + if("1") + alarm_area.air_doors_open() + return TOPIC_REFRESH + + if(href_list["atmos_alarm"]) + if (alarm_area.atmosalert(2, src)) + apply_danger_level(2) + update_icon() + return TOPIC_REFRESH + + if(href_list["atmos_reset"]) + if (alarm_area.atmosalert(0, src)) + apply_danger_level(0) + update_icon() + return TOPIC_REFRESH + + if(href_list["mode"]) + mode = text2num(href_list["mode"]) + apply_mode() + return TOPIC_REFRESH + +/obj/machinery/alarm/attackby(obj/item/W as obj, mob/user as mob) + switch(buildstage) + if(2) + if(isScrewdriver(W)) // Opening that Air Alarm up. +// to_chat(user, "You pop the Air Alarm's maintence panel open.") + wiresexposed = !wiresexposed + to_chat(user, "The wires have been [wiresexposed ? "exposed" : "unexposed"]") + update_icon() + return + + if (wiresexposed && isWirecutter(W)) + user.visible_message("[user] has cut the wires inside \the [src]!", "You have cut the wires inside \the [src].") + playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1) + new/obj/item/stack/cable_coil(get_turf(src), 5) + buildstage = 1 + update_icon() + return + + if (istype(W, /obj/item/weapon/card/id) || istype(W, /obj/item/device/pda))// trying to unlock the interface with an ID card + if(stat & (NOPOWER|BROKEN)) + to_chat(user, "It does nothing") + return + else + if(allowed(usr) && !wires.IsIndexCut(AALARM_WIRE_IDSCAN)) + locked = !locked + to_chat(user, "You [ locked ? "lock" : "unlock"] the Air Alarm interface.") + else + to_chat(user, "Access denied.") + return + + if(1) + if(isCoil(W)) + var/obj/item/stack/cable_coil/C = W + if (C.use(5)) + to_chat(user, "You wire \the [src].") + buildstage = 2 + update_icon() + return + else + to_chat(user, "You need 5 pieces of cable to do wire \the [src].") + return + + else if(isCrowbar(W)) + to_chat(user, "You start prying out the circuit.") + playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) + if(do_after(user,20)) + to_chat(user, "You pry out the circuit!") + var/obj/item/weapon/airalarm_electronics/circuit = new /obj/item/weapon/airalarm_electronics() + circuit.dropInto(user.loc) + buildstage = 0 + update_icon() + return + if(0) + if(istype(W, /obj/item/weapon/airalarm_electronics)) + to_chat(user, "You insert the circuit!") + qdel(W) + buildstage = 1 + update_icon() + return + + else if(isWrench(W)) + to_chat(user, "You remove the fire alarm assembly from the wall!") + new /obj/item/frame/air_alarm(get_turf(user)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + qdel(src) + + return ..() + +/obj/machinery/alarm/examine(mob/user) + . = ..(user) + if (buildstage < 2) + to_chat(user, "It is not wired.") + if (buildstage < 1) + to_chat(user, "The circuit is missing.") +/* +AIR ALARM CIRCUIT +Just a object used in constructing air alarms +*/ +/obj/item/weapon/airalarm_electronics + name = "air alarm electronics" + icon = 'icons/obj/doors/door_assembly.dmi' + icon_state = "door_electronics" + desc = "Looks like a circuit. Probably is." + w_class = ITEM_SIZE_SMALL + matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) + +/* +FIRE ALARM +*/ +/obj/machinery/firealarm + name = "fire alarm" + desc = "\"Pull this in case of emergency\". Thus, keep pulling it forever." + icon = 'icons/obj/monitors.dmi' + icon_state = "fire0" + var/detecting = 1.0 + var/working = 1.0 + var/time = 10.0 + var/timing = 0.0 + var/lockdownbyai = 0 + anchored = 1.0 + use_power = 1 + idle_power_usage = 2 + active_power_usage = 6 + power_channel = ENVIRON + var/last_process = 0 + var/wiresexposed = 0 + var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone + var/seclevel + +/obj/machinery/firealarm/examine(mob/user) + . = ..(user) + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + to_chat(user, "The current alert level is [security_state.current_security_level.name].") + +/obj/machinery/firealarm/update_icon() + overlays.Cut() + + if(wiresexposed) + switch(buildstage) + if(2) + icon_state="fire_b2" + if(1) + icon_state="fire_b1" + if(0) + icon_state="fire_b0" + set_light(0) + return + + if(stat & BROKEN) + icon_state = "firex" + set_light(0) + else if(stat & NOPOWER) + icon_state = "firep" + set_light(0) + else + if(!src.detecting) + icon_state = "fire1" + set_light(l_range = 4, l_power = 2, l_color = COLOR_RED) + else if(z in GLOB.using_map.contact_levels) + icon_state = "fire0" + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + var/decl/security_level/sl = security_state.current_security_level + + set_light(sl.light_range, sl.light_power, sl.light_color_alarm) + src.overlays += image(sl.icon, sl.overlay_alarm) + +/obj/machinery/firealarm/fire_act(datum/gas_mixture/air, temperature, volume) + if(src.detecting) + if(temperature > T0C+200) + src.alarm() // added check of detector status here + return + +/obj/machinery/firealarm/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/firealarm/bullet_act() + return src.alarm() + +/obj/machinery/firealarm/emp_act(severity) + if(prob(50/severity)) + alarm(rand(30/severity, 60/severity)) + ..() + +/obj/machinery/firealarm/attackby(obj/item/W as obj, mob/user as mob) + if(isScrewdriver(W) && buildstage == 2) + wiresexposed = !wiresexposed + update_icon() + return + + if(wiresexposed) + switch(buildstage) + if(2) + if(isMultitool(W)) + src.detecting = !( src.detecting ) + if (src.detecting) + user.visible_message("\The [user] has reconnected [src]'s detecting unit!", "You have reconnected [src]'s detecting unit.") + else + user.visible_message("\The [user] has disconnected [src]'s detecting unit!", "You have disconnected [src]'s detecting unit.") + else if(isWirecutter(W)) + user.visible_message("\The [user] has cut the wires inside \the [src]!", "You have cut the wires inside \the [src].") + new/obj/item/stack/cable_coil(get_turf(src), 5) + playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1) + buildstage = 1 + update_icon() + if(1) + if(istype(W, /obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/C = W + if (C.use(5)) + to_chat(user, "You wire \the [src].") + buildstage = 2 + return + else + to_chat(user, "You need 5 pieces of cable to wire \the [src].") + return + else if(isCrowbar(W)) + to_chat(user, "You pry out the circuit!") + playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) + spawn(20) + var/obj/item/weapon/firealarm_electronics/circuit = new /obj/item/weapon/firealarm_electronics() + circuit.dropInto(user.loc) + buildstage = 0 + update_icon() + if(0) + if(istype(W, /obj/item/weapon/firealarm_electronics)) + to_chat(user, "You insert the circuit!") + qdel(W) + buildstage = 1 + update_icon() + + else if(isWrench(W)) + to_chat(user, "You remove the fire alarm assembly from the wall!") + new /obj/item/frame/fire_alarm(get_turf(user)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + qdel(src) + return + + src.alarm() + return + +/obj/machinery/firealarm/Process()//Note: this processing was mostly phased out due to other code, and only runs when needed + if(stat & (NOPOWER|BROKEN)) + return + + if(src.timing) + if(src.time > 0) + src.time = src.time - ((world.timeofday - last_process)/10) + else + src.alarm() + src.time = 0 + src.timing = 0 + STOP_PROCESSING(SSmachines, src) + src.updateDialog() + last_process = world.timeofday + + if(locate(/obj/fire) in loc) + alarm() + +/obj/machinery/firealarm/attack_hand(mob/user as mob) + if(user.stat || stat & (NOPOWER|BROKEN)) + return + + if (buildstage != 2) + return + + user.set_machine(src) + var/area/A = src.loc + var/d1 + var/d2 + + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + if (istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon)) + A = A.loc + + if (A.fire) + d1 = text("Reset - Lockdown", src) + else + d1 = text("Alarm - Lockdown", src) + if (src.timing) + d2 = text("Stop Time Lock", src) + else + d2 = text("Initiate Time Lock", src) + var/second = round(src.time) % 60 + var/minute = (round(src.time) - second) / 60 + var/dat = "Fire alarm [d1]\n
    The current alert level is [security_state.current_security_level.name]

    \nTimer System: [d2]
    \nTime Left: [(minute ? "[minute]:" : null)][second] - - + +\n
    " + user << browse(dat, "window=firealarm") + onclose(user, "firealarm") + else + A = A.loc + if (A.fire) + d1 = text("[]", src, stars("Reset - Lockdown")) + else + d1 = text("[]", src, stars("Alarm - Lockdown")) + if (src.timing) + d2 = text("[]", src, stars("Stop Time Lock")) + else + d2 = text("[]", src, stars("Initiate Time Lock")) + var/second = round(src.time) % 60 + var/minute = (round(src.time) - second) / 60 + var/dat = "[stars("Fire alarm")] [d1]\n
    The current security level is [security_state.current_security_level.name]

    \nTimer System: [d2]
    \nTime Left: [(minute ? text("[]:", minute) : null)][second] - - + +\n
    " + user << browse(dat, "window=firealarm") + onclose(user, "firealarm") + return + +/obj/machinery/firealarm/CanUseTopic(user) + if(buildstage != 2) + return STATUS_CLOSE + return ..() + +/obj/machinery/firealarm/OnTopic(user, href_list) + if (href_list["reset"]) + src.reset() + . = TOPIC_REFRESH + else if (href_list["alarm"]) + src.alarm() + . = TOPIC_REFRESH + else if (href_list["time"]) + src.timing = text2num(href_list["time"]) + last_process = world.timeofday + START_PROCESSING(SSmachines, src) + . = TOPIC_REFRESH + else if (href_list["tp"]) + var/tp = text2num(href_list["tp"]) + src.time += tp + src.time = min(max(round(src.time), 0), 120) + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + attack_hand(user) + +/obj/machinery/firealarm/proc/reset() + if (!( src.working )) + return + var/area/area = get_area(src) + for(var/obj/machinery/firealarm/FA in area) + fire_alarm.clearAlarm(loc, FA) + update_icon() + return + +/obj/machinery/firealarm/proc/alarm(var/duration = 0) + if (!( src.working)) + return + var/area/area = get_area(src) + for(var/obj/machinery/firealarm/FA in area) + fire_alarm.triggerAlarm(loc, FA, duration) + update_icon() + //playsound(src.loc, 'sound/ambience/signal.ogg', 75, 0) + return + + + +/obj/machinery/firealarm/New(loc, dir, atom/frame) + ..(loc) + + if(dir) + src.set_dir(dir) + + if(istype(frame)) + buildstage = 0 + wiresexposed = 1 + pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24) + pixel_y = (dir & 3)? (dir ==1 ? -24 : 24) : 0 + frame.transfer_fingerprints_to(src) + +/obj/machinery/firealarm/Initialize() + . = ..() + if(z in GLOB.using_map.contact_levels) + update_icon() + +/* +FIRE ALARM CIRCUIT +Just a object used in constructing fire alarms +*/ +/obj/item/weapon/firealarm_electronics + name = "fire alarm electronics" + icon = 'icons/obj/doors/door_assembly.dmi' + icon_state = "door_electronics" + desc = "A circuit. It has a label on it, it says \"Can handle heat levels up to 40 degrees celsius!\"." + w_class = ITEM_SIZE_SMALL + matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) + +/obj/machinery/partyalarm + name = "\improper PARTY BUTTON" + desc = "Cuban Pete is in the house!" + icon = 'icons/obj/monitors.dmi' + icon_state = "fire0" + var/detecting = 1.0 + var/working = 1.0 + var/time = 10.0 + var/timing = 0.0 + var/lockdownbyai = 0 + anchored = 1.0 + use_power = 1 + idle_power_usage = 2 + active_power_usage = 6 + +/obj/machinery/partyalarm/attack_hand(mob/user as mob) + if(user.stat || stat & (NOPOWER|BROKEN)) + return + + user.machine = src + var/area/A = get_area(src) + ASSERT(isarea(A)) + var/d1 + var/d2 + if (istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon/ai)) + + if (A.party) + d1 = text("No Party :(", src) + else + d1 = text("PARTY!!!", src) + if (timing) + d2 = text("Stop Time Lock", src) + else + d2 = text("Initiate Time Lock", src) + var/second = time % 60 + var/minute = (time - second) / 60 + var/dat = text("Party Button []\n
    \nTimer System: []
    \nTime Left: [][] - - + +\n
    ", d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) + user << browse(dat, "window=partyalarm") + onclose(user, "partyalarm") + else + if (A.fire) + d1 = text("[]", src, stars("No Party :(")) + else + d1 = text("[]", src, stars("PARTY!!!")) + if (timing) + d2 = text("[]", src, stars("Stop Time Lock")) + else + d2 = text("[]", src, stars("Initiate Time Lock")) + var/second = time % 60 + var/minute = (time - second) / 60 + var/dat = text("[] []\n
    \nTimer System: []
    \nTime Left: [][] - - + +\n
    ", stars("Party Button"), d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) + user << browse(dat, "window=partyalarm") + onclose(user, "partyalarm") + return + +/obj/machinery/partyalarm/proc/reset() + if (!( working )) + return + var/area/A = get_area(src) + ASSERT(isarea(A)) + A.partyreset() + return + +/obj/machinery/partyalarm/proc/alarm() + if (!( working )) + return + var/area/A = get_area(src) + ASSERT(isarea(A)) + A.partyalert() + return + +/obj/machinery/partyalarm/OnTopic(user, href_list) + if (href_list["reset"]) + reset() + . = TOPIC_REFRESH + else if (href_list["alarm"]) + alarm() + . = TOPIC_REFRESH + else if (href_list["time"]) + timing = text2num(href_list["time"]) + . = TOPIC_REFRESH + else if (href_list["tp"]) + var/tp = text2num(href_list["tp"]) + time += tp + time = min(max(round(time), 0), 120) + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + attack_hand(user) diff --git a/code/game/machinery/atmo_control.dm b/code/game/machinery/atmo_control.dm new file mode 100644 index 00000000..d6c7994f --- /dev/null +++ b/code/game/machinery/atmo_control.dm @@ -0,0 +1,534 @@ +/obj/machinery/air_sensor + icon = 'icons/obj/stationobjs.dmi' + icon_state = "gsensor1" + name = "Gas Sensor" + + anchored = 1 + var/state = 0 + + var/id_tag + var/frequency = 1439 + + var/on = 1 + var/output = 3 + //Flags: + // 1 for pressure + // 2 for temperature + // Output >= 4 includes gas composition + // 4 for oxygen concentration + // 8 for phoron concentration + // 16 for nitrogen concentration + // 32 for carbon dioxide concentration + // 64 for hydrogen concentration + + var/datum/radio_frequency/radio_connection + +/obj/machinery/air_sensor/update_icon() + icon_state = "gsensor[on]" + +/obj/machinery/air_sensor/Process() + if(on) + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.data["tag"] = id_tag + signal.data["timestamp"] = world.time + + var/datum/gas_mixture/air_sample = return_air() + + if(output&1) + signal.data["pressure"] = num2text(round(air_sample.return_pressure(),0.1),) + if(output&2) + signal.data["temperature"] = round(air_sample.temperature,0.1) + + if(output>4) + var/total_moles = air_sample.total_moles + if(total_moles > 0) + if(output&4) + signal.data["oxygen"] = round(100*air_sample.gas["oxygen"]/total_moles,0.1) + if(output&8) + signal.data["phoron"] = round(100*air_sample.gas["phoron"]/total_moles,0.1) + if(output&16) + signal.data["nitrogen"] = round(100*air_sample.gas["nitrogen"]/total_moles,0.1) + if(output&32) + signal.data["carbon_dioxide"] = round(100*air_sample.gas["carbon_dioxide"]/total_moles,0.1) + if(output&64) + signal.data["hydrogen"] = round(100*air_sample.gas["hydrogen"]/total_moles,0.1) + else + signal.data["oxygen"] = 0 + signal.data["phoron"] = 0 + signal.data["nitrogen"] = 0 + signal.data["carbon_dioxide"] = 0 + signal.data["hydrogen"] = 0 + signal.data["sigtype"]="status" + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + + +/obj/machinery/air_sensor/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) + +/obj/machinery/air_sensor/Initialize() + set_frequency(frequency) + . = ..() + +obj/machinery/air_sensor/Destroy() + if(radio_controller) + radio_controller.remove_object(src,frequency) + ..() + +/obj/machinery/computer/general_air_control + icon = 'icons/obj/computer.dmi' + icon_keyboard = "atmos_key" + icon_screen = "tank" + + name = "Computer" + + var/frequency = 1439 + var/list/sensors = list() + + var/list/sensor_information = list() + var/datum/radio_frequency/radio_connection + circuit = /obj/item/weapon/circuitboard/air_management + +obj/machinery/computer/general_air_control/Destroy() + if(radio_controller) + radio_controller.remove_object(src, frequency) + ..() + +/obj/machinery/computer/general_air_control/attack_hand(mob/user) + if(..(user)) + return + user << browse(return_text(),"window=computer") + user.set_machine(src) + onclose(user, "computer") + +/obj/machinery/computer/general_air_control/Process() + ..() + src.updateUsrDialog() + +/obj/machinery/computer/general_air_control/receive_signal(datum/signal/signal) + if(!signal || signal.encryption) return + + var/id_tag = signal.data["tag"] + if(!id_tag || !sensors.Find(id_tag)) return + + sensor_information[id_tag] = signal.data + +/obj/machinery/computer/general_air_control/proc/return_text() + var/sensor_data + if(sensors.len) + for(var/id_tag in sensors) + var/long_name = sensors[id_tag] + var/list/data = sensor_information[id_tag] + var/sensor_part = "[long_name]:
    " + + if(data) + if(data["pressure"]) + sensor_part += " Pressure: [data["pressure"]] kPa
    " + if(data["temperature"]) + sensor_part += " Temperature: [data["temperature"]] K
    " + if(data["oxygen"]||data["phoron"]||data["nitrogen"]||data["carbon_dioxide"]||data["hydrogen"]) + sensor_part += " Gas Composition :" + if(data["oxygen"]) + sensor_part += "[data["oxygen"]]% O2; " + if(data["nitrogen"]) + sensor_part += "[data["nitrogen"]]% N; " + if(data["carbon_dioxide"]) + sensor_part += "[data["carbon_dioxide"]]% CO2; " + if(data["hydrogen"]) + sensor_part += "[data["hydrogen"]]% H2; " + if(data["phoron"]) + sensor_part += "[data["phoron"]]% PH; " + sensor_part += "
    " + + else + sensor_part = "[long_name] can not be found!
    " + + sensor_data += sensor_part + + else + sensor_data = "No sensors connected." + + var/output = {"[name]
    +Sensor Data:

    [sensor_data]"} + + return output + +/obj/machinery/computer/general_air_control/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) + +/obj/machinery/computer/general_air_control/Initialize() + set_frequency(frequency) + . = ..() + +/obj/machinery/computer/general_air_control/large_tank_control + icon = 'icons/obj/computer.dmi' + + frequency = 1441 + var/input_tag + var/output_tag + + var/list/input_info + var/list/output_info + + var/input_flow_setting = 200 + var/pressure_setting = ONE_ATMOSPHERE * 45 + circuit = /obj/item/weapon/circuitboard/air_management/tank_control + + +/obj/machinery/computer/general_air_control/large_tank_control/return_text() + var/output = ..() + //if(signal.data) + // input_info = signal.data // Attempting to fix intake control -- TLE + + output += "Tank Control System

    " + if(input_info) + var/power = (input_info["power"]) + var/volume_rate = round(input_info["volume_rate"], 0.1) + output += "Input: [power?("Injecting"):("On Hold")] Refresh
    Flow Rate Limit: [volume_rate] L/s
    " + output += "Command: Toggle Power Set Flow Rate
    " + + else + output += "ERROR: Can not find input port Search
    " + + output += "Flow Rate Limit: - - - - [round(input_flow_setting, 0.1)] L/s + + + +
    " + + output += "
    " + + if(output_info) + var/power = (output_info["power"]) + var/output_pressure = output_info["internal"] + output += {"Output: [power?("Open"):("On Hold")] Refresh
    +Max Output Pressure: [output_pressure] kPa
    "} + output += "Command: Toggle Power Set Pressure
    " + + else + output += "ERROR: Can not find output port Search
    " + + output += "Max Output Pressure Set: - - - - [pressure_setting] kPa + + + +
    " + + return output + +/obj/machinery/computer/general_air_control/large_tank_control/receive_signal(datum/signal/signal) + if(!signal || signal.encryption) return + + var/id_tag = signal.data["tag"] + + if(input_tag == id_tag) + input_info = signal.data + else if(output_tag == id_tag) + output_info = signal.data + else + ..(signal) + +/obj/machinery/computer/general_air_control/large_tank_control/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["adj_pressure"]) + var/change = text2num(href_list["adj_pressure"]) + pressure_setting = between(0, pressure_setting + change, MAX_PUMP_PRESSURE) + spawn(1) + src.updateUsrDialog() + return 1 + + if(href_list["adj_input_flow_rate"]) + var/change = text2num(href_list["adj_input_flow_rate"]) + input_flow_setting = between(0, input_flow_setting + change, ATMOS_DEFAULT_VOLUME_PUMP + 500) //default flow rate limit for air injectors + spawn(1) + src.updateUsrDialog() + return 1 + + if(!radio_connection) + return 0 + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + if(href_list["in_refresh_status"]) + input_info = null + signal.data = list ("tag" = input_tag, "status" = 1) + . = 1 + + if(href_list["in_toggle_injector"]) + input_info = null + signal.data = list ("tag" = input_tag, "power_toggle" = 1) + . = 1 + + if(href_list["in_set_flowrate"]) + input_info = null + signal.data = list ("tag" = input_tag, "set_volume_rate" = "[input_flow_setting]") + . = 1 + + if(href_list["out_refresh_status"]) + output_info = null + signal.data = list ("tag" = output_tag, "status" = 1) + . = 1 + + if(href_list["out_toggle_power"]) + output_info = null + signal.data = list ("tag" = output_tag, "power_toggle" = 1) + . = 1 + + if(href_list["out_set_pressure"]) + output_info = null + signal.data = list ("tag" = output_tag, "set_internal_pressure" = "[pressure_setting]") + . = 1 + + signal.data["sigtype"]="command" + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + + spawn(5) + src.updateUsrDialog() + +/obj/machinery/computer/general_air_control/supermatter_core + icon = 'icons/obj/computer.dmi' + + frequency = 1438 + var/input_tag + var/output_tag + + var/list/input_info + var/list/output_info + + var/input_flow_setting = 700 + var/pressure_setting = 100 + circuit = /obj/item/weapon/circuitboard/air_management/supermatter_core + + +/obj/machinery/computer/general_air_control/supermatter_core/return_text() + var/output = ..() + //if(signal.data) + // input_info = signal.data // Attempting to fix intake control -- TLE + + output += "Core Cooling Control System

    " + if(input_info) + var/power = (input_info["power"]) + var/volume_rate = round(input_info["volume_rate"], 0.1) + output += "Coolant Input: [power?("Injecting"):("On Hold")] Refresh
    Flow Rate Limit: [volume_rate] L/s
    " + output += "Command: Toggle Power Set Flow Rate
    " + + else + output += "ERROR: Can not find input port Search
    " + + output += "Flow Rate Limit: - - - - [round(input_flow_setting, 0.1)] L/s + + + +
    " + + output += "
    " + + if(output_info) + var/power = (output_info["power"]) + var/pressure_limit = output_info["external"] + output += {"Core Outpump: [power?("Open"):("On Hold")] Refresh
    +Min Core Pressure: [pressure_limit] kPa
    "} + output += "Command: Toggle Power Set Pressure
    " + + else + output += "ERROR: Can not find output port Search
    " + + output += "Min Core Pressure Set: - - - - [pressure_setting] kPa + + + +
    " + + return output + +/obj/machinery/computer/general_air_control/supermatter_core/receive_signal(datum/signal/signal) + if(!signal || signal.encryption) return + + var/id_tag = signal.data["tag"] + + if(input_tag == id_tag) + input_info = signal.data + else if(output_tag == id_tag) + output_info = signal.data + else + ..(signal) + +/obj/machinery/computer/general_air_control/supermatter_core/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["adj_pressure"]) + var/change = text2num(href_list["adj_pressure"]) + pressure_setting = between(0, pressure_setting + change, MAX_PUMP_PRESSURE) + spawn(1) + src.updateUsrDialog() + return 1 + + if(href_list["adj_input_flow_rate"]) + var/change = text2num(href_list["adj_input_flow_rate"]) + input_flow_setting = between(0, input_flow_setting + change, ATMOS_DEFAULT_VOLUME_PUMP + 500) //default flow rate limit for air injectors + spawn(1) + src.updateUsrDialog() + return 1 + + if(!radio_connection) + return 0 + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + if(href_list["in_refresh_status"]) + input_info = null + signal.data = list ("tag" = input_tag, "status" = 1) + . = 1 + + if(href_list["in_toggle_injector"]) + input_info = null + signal.data = list ("tag" = input_tag, "power_toggle" = 1) + . = 1 + + if(href_list["in_set_flowrate"]) + input_info = null + signal.data = list ("tag" = input_tag, "set_volume_rate" = "[input_flow_setting]") + . = 1 + + if(href_list["out_refresh_status"]) + output_info = null + signal.data = list ("tag" = output_tag, "status" = 1) + . = 1 + + if(href_list["out_toggle_power"]) + output_info = null + signal.data = list ("tag" = output_tag, "power_toggle" = 1) + . = 1 + + if(href_list["out_set_pressure"]) + output_info = null + signal.data = list ("tag" = output_tag, "set_external_pressure" = "[pressure_setting]", "checks" = 1) + . = 1 + + signal.data["sigtype"]="command" + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + + spawn(5) + src.updateUsrDialog() + +/obj/machinery/computer/general_air_control/fuel_injection + icon = 'icons/obj/computer.dmi' + icon_screen = "alert:0" + + var/device_tag + var/list/device_info + + var/automation = 0 + + var/cutoff_temperature = 2000 + var/on_temperature = 1200 + circuit = /obj/item/weapon/circuitboard/air_management/injector_control + +/obj/machinery/computer/general_air_control/fuel_injection/Process() + if(automation) + if(!radio_connection) + return 0 + + var/injecting = 0 + for(var/id_tag in sensor_information) + var/list/data = sensor_information[id_tag] + if(data["temperature"]) + if(data["temperature"] >= cutoff_temperature) + injecting = 0 + break + if(data["temperature"] <= on_temperature) + injecting = 1 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data = list( + "tag" = device_tag, + "power" = injecting, + "sigtype"="command" + ) + + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + + ..() + +/obj/machinery/computer/general_air_control/fuel_injection/return_text() + var/output = ..() + + output += "Fuel Injection System
    " + if(device_info) + var/power = device_info["power"] + var/volume_rate = device_info["volume_rate"] + output += {"Status: [power?("Injecting"):("On Hold")] Refresh
    +Rate: [volume_rate] L/sec
    "} + + if(automation) + output += "Automated Fuel Injection: Engaged
    " + output += "Injector Controls Locked Out
    " + else + output += "Automated Fuel Injection: Disengaged
    " + output += "Injector: Toggle Power Inject (1 Cycle)
    " + + else + output += "ERROR: Can not find device Search
    " + + return output + +/obj/machinery/computer/general_air_control/fuel_injection/receive_signal(datum/signal/signal) + if(!signal || signal.encryption) return + + var/id_tag = signal.data["tag"] + + if(device_tag == id_tag) + device_info = signal.data + else + ..(signal) + +/obj/machinery/computer/general_air_control/fuel_injection/Topic(href, href_list) + if((. = ..())) + return + + if(href_list["refresh_status"]) + device_info = null + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + signal.data = list( + "tag" = device_tag, + "status" = 1, + "sigtype"="command" + ) + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + + if(href_list["toggle_automation"]) + automation = !automation + + if(href_list["toggle_injector"]) + device_info = null + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + signal.data = list( + "tag" = device_tag, + "power_toggle" = 1, + "sigtype"="command" + ) + + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + + if(href_list["injection"]) + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + signal.data = list( + "tag" = device_tag, + "inject" = 1, + "sigtype"="command" + ) + + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + + + + diff --git a/code/game/machinery/atmoalter/area_atmos_computer.dm b/code/game/machinery/atmoalter/area_atmos_computer.dm new file mode 100644 index 00000000..0c6dbe42 --- /dev/null +++ b/code/game/machinery/atmoalter/area_atmos_computer.dm @@ -0,0 +1,180 @@ +/obj/machinery/computer/area_atmos + name = "Area Air Control" + desc = "A computer used to control the stationary scrubbers and pumps in the area." + icon_keyboard = "atmos_key" + icon_screen = "area_atmos" + light_color = "#e6ffff" + circuit = /obj/item/weapon/circuitboard/area_atmos + + var/list/connectedscrubbers = new() + var/status = "" + + var/range = 25 + + //Simple variable to prevent me from doing attack_hand in both this and the child computer + var/zone = "This computer is working on a wireless range, the range is currently limited to 25 meters." + + New() + ..() + //So the scrubbers have time to spawn + spawn(10) + scanscrubbers() + + attack_ai(var/mob/user as mob) + return src.attack_hand(user) + + attack_hand(var/mob/user as mob) + if(..(user)) + return + var/dat = {" + + + + + +

    Area Air Control

    + [status]
    + Scan + "} + for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in connectedscrubbers) + dat += {" + + + + "} + + dat += {" +
    + [scrubber.name]
    + Pressure: [round(scrubber.air_contents.return_pressure(), 0.01)] kPa
    + Flow Rate: [round(scrubber.last_flow_rate,0.1)] L/s
    +
    + Turn On + Turn Off
    + Load: [round(scrubber.last_power_draw)] W +

    + [zone] + + "} + user << browse("[dat]", "window=miningshuttle;size=400x400") + status = "" + + Topic(href, href_list) + if(..()) + return + usr.set_machine(src) + + + if(href_list["scan"]) + scanscrubbers() + else if(href_list["toggle"]) + var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber = locate(href_list["scrub"]) + + if(!validscrubber(scrubber)) + spawn(20) + status = "ERROR: Couldn't connect to scrubber! (timeout)" + connectedscrubbers -= scrubber + src.updateUsrDialog() + return + + scrubber.on = text2num(href_list["toggle"]) + scrubber.update_icon() + + proc/validscrubber( var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber as obj ) + if(!isobj(scrubber) || get_dist(scrubber.loc, src.loc) > src.range || scrubber.loc.z != src.loc.z) + return 0 + + return 1 + + proc/scanscrubbers() + connectedscrubbers = new() + + var/found = 0 + for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in range(range, src.loc)) + if(istype(scrubber)) + found = 1 + connectedscrubbers += scrubber + + if(!found) + status = "ERROR: No scrubber found!" + + src.updateUsrDialog() + + +/obj/machinery/computer/area_atmos/area + zone = "This computer is working in a wired network limited to this area." + + validscrubber( var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber as obj ) + if(!isobj(scrubber)) + return 0 + + /* + wow this is stupid, someone help me + */ + var/turf/T_src = get_turf(src) + if(!T_src.loc) return 0 + var/area/A_src = T_src.loc + + var/turf/T_scrub = get_turf(scrubber) + if(!T_scrub.loc) return 0 + var/area/A_scrub = T_scrub.loc + + if(A_scrub != A_src) + return 0 + + return 1 + + scanscrubbers() + connectedscrubbers = new() + + var/found = 0 + + var/turf/T = get_turf(src) + if(!T.loc) return + var/area/A = T.loc + for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in world ) + var/turf/T2 = get_turf(scrubber) + if(T2 && T2.loc) + var/area/A2 = T2.loc + if(istype(A2) && A2 == A) + connectedscrubbers += scrubber + found = 1 + + + if(!found) + status = "ERROR: No scrubber found!" + + src.updateUsrDialog() diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm new file mode 100644 index 00000000..d8258d64 --- /dev/null +++ b/code/game/machinery/atmoalter/canister.dm @@ -0,0 +1,466 @@ +/obj/machinery/portable_atmospherics/canister + name = "\improper Canister: \[CAUTION\]" + icon = 'icons/obj/atmos.dmi' + icon_state = "yellow" + density = 1 + var/health = 100.0 + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_GARGANTUAN + + var/valve_open = 0 + var/release_pressure = ONE_ATMOSPHERE + var/release_flow_rate = ATMOS_DEFAULT_VOLUME_PUMP //in L/s + + var/canister_color = "yellow" + var/can_label = 1 + start_pressure = 45 * ONE_ATMOSPHERE + var/temperature_resistance = 1000 + T0C + volume = 1000 + use_power = 0 + interact_offline = 1 // Allows this to be used when not in powered area. + var/release_log = "" + var/update_flag = 0 + +/obj/machinery/portable_atmospherics/canister/drain_power() + return -1 + +/obj/machinery/portable_atmospherics/canister/sleeping_agent + name = "\improper Canister: \[N2O\]" + icon_state = "redws" + canister_color = "redws" + can_label = 0 + +/obj/machinery/portable_atmospherics/canister/nitrogen + name = "\improper Canister: \[N2\]" + icon_state = "red" + canister_color = "red" + can_label = 0 + +/obj/machinery/portable_atmospherics/canister/nitrogen/prechilled + name = "\improper Canister: \[N2 (Cooling)\]" + +/obj/machinery/portable_atmospherics/canister/oxygen + name = "\improper Canister: \[O2\]" + icon_state = "blue" + canister_color = "blue" + can_label = 0 + +/obj/machinery/portable_atmospherics/canister/oxygen/prechilled + name = "\improper Canister: \[O2 (Cryo)\]" + start_pressure = 20 * ONE_ATMOSPHERE + +/obj/machinery/portable_atmospherics/canister/hydrogen + name = "\improper Canister: \[Hydrogen\]" + icon_state = "purple" + canister_color = "purple" + can_label = 0 + +/obj/machinery/portable_atmospherics/canister/phoron + name = "\improper Canister \[Phoron\]" + icon_state = "orange" + canister_color = "orange" + can_label = 0 + +/obj/machinery/portable_atmospherics/canister/carbon_dioxide + name = "\improper Canister \[CO2\]" + icon_state = "black" + canister_color = "black" + can_label = 0 + +/obj/machinery/portable_atmospherics/canister/air + name = "\improper Canister \[Air\]" + icon_state = "grey" + canister_color = "grey" + can_label = 0 + +/obj/machinery/portable_atmospherics/canister/air/airlock + start_pressure = 3 * ONE_ATMOSPHERE + +/obj/machinery/portable_atmospherics/canister/empty + start_pressure = 0 + can_label = 1 + var/obj/machinery/portable_atmospherics/canister/canister_type = /obj/machinery/portable_atmospherics/canister + +/obj/machinery/portable_atmospherics/canister/empty/New() + ..() + name = initial(canister_type.name) + icon_state = initial(canister_type.icon_state) + canister_color = initial(canister_type.canister_color) + +/obj/machinery/portable_atmospherics/canister/empty/air + icon_state = "grey" + canister_type = /obj/machinery/portable_atmospherics/canister/air +/obj/machinery/portable_atmospherics/canister/empty/oxygen + icon_state = "blue" + canister_type = /obj/machinery/portable_atmospherics/canister/oxygen +/obj/machinery/portable_atmospherics/canister/empty/phoron + icon_state = "orange" + canister_type = /obj/machinery/portable_atmospherics/canister/phoron +/obj/machinery/portable_atmospherics/canister/empty/nitrogen + icon_state = "red" + canister_type = /obj/machinery/portable_atmospherics/canister/nitrogen +/obj/machinery/portable_atmospherics/canister/empty/carbon_dioxide + icon_state = "black" + canister_type = /obj/machinery/portable_atmospherics/canister/carbon_dioxide +/obj/machinery/portable_atmospherics/canister/empty/sleeping_agent + icon_state = "redws" + canister_type = /obj/machinery/portable_atmospherics/canister/sleeping_agent +/obj/machinery/portable_atmospherics/canister/empty/hydrogen + icon_state = "purple" + canister_type = /obj/machinery/portable_atmospherics/canister/hydrogen + + + + +/obj/machinery/portable_atmospherics/canister/proc/check_change() + var/old_flag = update_flag + update_flag = 0 + if(holding) + update_flag |= 1 + if(connected_port) + update_flag |= 2 + + var/tank_pressure = air_contents.return_pressure() + if(tank_pressure < 10) + update_flag |= 4 + else if(tank_pressure < ONE_ATMOSPHERE) + update_flag |= 8 + else if(tank_pressure < 15*ONE_ATMOSPHERE) + update_flag |= 16 + else + update_flag |= 32 + + if(update_flag == old_flag) + return 1 + else + return 0 + +/obj/machinery/portable_atmospherics/canister/update_icon() +/* +update_flag +1 = holding +2 = connected_port +4 = tank_pressure < 10 +8 = tank_pressure < ONE_ATMOS +16 = tank_pressure < 15*ONE_ATMOS +32 = tank_pressure go boom. +*/ + + if (src.destroyed) + src.overlays = 0 + src.icon_state = text("[]-1", src.canister_color) + return + + if(icon_state != "[canister_color]") + icon_state = "[canister_color]" + + if(check_change()) //Returns 1 if no change needed to icons. + return + + src.overlays = 0 + + if(update_flag & 1) + overlays += "can-open" + if(update_flag & 2) + overlays += "can-connector" + if(update_flag & 4) + overlays += "can-o0" + if(update_flag & 8) + overlays += "can-o1" + else if(update_flag & 16) + overlays += "can-o2" + else if(update_flag & 32) + overlays += "can-o3" + return + +/obj/machinery/portable_atmospherics/canister/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > temperature_resistance) + health -= 5 + healthcheck() + +/obj/machinery/portable_atmospherics/canister/proc/healthcheck() + if(destroyed) + return 1 + + if (src.health <= 10) + var/atom/location = src.loc + location.assume_air(air_contents) + + src.destroyed = 1 + playsound(src.loc, 'sound/effects/spray.ogg', 10, 1, -3) + src.set_density(0) + update_icon() + + if (src.holding) + src.holding.dropInto(loc) + src.holding = null + + return 1 + else + return 1 + +/obj/machinery/portable_atmospherics/canister/Process() + if (destroyed) + return + + ..() + + if(valve_open) + var/datum/gas_mixture/environment + if(holding) + environment = holding.air_contents + else + environment = loc.return_air() + + var/env_pressure = environment.return_pressure() + var/pressure_delta = release_pressure - env_pressure + + if((air_contents.temperature > 0) && (pressure_delta > 0)) + var/transfer_moles = calculate_transfer_moles(air_contents, environment, pressure_delta) + transfer_moles = min(transfer_moles, (release_flow_rate/air_contents.volume)*air_contents.total_moles) //flow rate limit + + var/returnval = pump_gas_passive(src, air_contents, environment, transfer_moles) + if(returnval >= 0) + src.update_icon() + + if(air_contents.return_pressure() < 1) + can_label = 1 + else + can_label = 0 + + air_contents.react() //cooking up air cans - add phoron and oxygen, then heat above PHORON_MINIMUM_BURN_TEMPERATURE + +/obj/machinery/portable_atmospherics/canister/proc/return_temperature() + var/datum/gas_mixture/GM = src.return_air() + if(GM && GM.volume>0) + return GM.temperature + return 0 + +/obj/machinery/portable_atmospherics/canister/proc/return_pressure() + var/datum/gas_mixture/GM = src.return_air() + if(GM && GM.volume>0) + return GM.return_pressure() + return 0 + +/obj/machinery/portable_atmospherics/canister/bullet_act(var/obj/item/projectile/Proj) + if(!(Proj.damage_type == BRUTE || Proj.damage_type == BURN)) + return + + if(Proj.damage) + src.health -= round(Proj.damage / 2) + healthcheck() + ..() + +/obj/machinery/portable_atmospherics/canister/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(!isWrench(W) && !istype(W, /obj/item/weapon/tank) && !istype(W, /obj/item/device/analyzer) && !istype(W, /obj/item/device/pda)) + visible_message("\The [user] hits \the [src] with \a [W]!") + src.health -= W.force + healthcheck() + + if(istype(user, /mob/living/silicon/robot) && istype(W, /obj/item/weapon/tank/jetpack)) + var/datum/gas_mixture/thejetpack = W:air_contents + var/env_pressure = thejetpack.return_pressure() + var/pressure_delta = min(10*ONE_ATMOSPHERE - env_pressure, (air_contents.return_pressure() - env_pressure)/2) + //Can not have a pressure delta that would cause environment pressure > tank pressure + var/transfer_moles = 0 + if((air_contents.temperature > 0) && (pressure_delta > 0)) + transfer_moles = pressure_delta*thejetpack.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION)//Actually transfer the gas + var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) + thejetpack.merge(removed) + to_chat(user, "You pulse-pressurize your jetpack from the tank.") + return + + ..() + + GLOB.nanomanager.update_uis(src) // Update all NanoUIs attached to src + +/obj/machinery/portable_atmospherics/canister/attack_ai(var/mob/user as mob) + ui_interact(user) + +/obj/machinery/portable_atmospherics/canister/attack_hand(var/mob/user as mob) + ui_interact(user) + +/obj/machinery/portable_atmospherics/canister/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + // this is the data which will be sent to the ui + var/data[0] + data["name"] = name + data["canLabel"] = can_label ? 1 : 0 + data["portConnected"] = connected_port ? 1 : 0 + data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0) + data["releasePressure"] = round(release_pressure ? release_pressure : 0) + data["minReleasePressure"] = round(ONE_ATMOSPHERE/10) + data["maxReleasePressure"] = round(10*ONE_ATMOSPHERE) + data["valveOpen"] = valve_open ? 1 : 0 + + data["hasHoldingTank"] = holding ? 1 : 0 + if (holding) + data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure())) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "canister.tmpl", "Canister", 480, 400) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/portable_atmospherics/canister/OnTopic(var/mob/user, href_list, state) + if(href_list["toggle"]) + if (valve_open) + if (holding) + release_log += "Valve was closed by [user] ([user.ckey]), stopping the transfer into the [holding]
    " + else + release_log += "Valve was closed by [user] ([user.ckey]), stopping the transfer into the air
    " + else + if (holding) + release_log += "Valve was opened by [user] ([user.ckey]), starting the transfer into the [holding]
    " + else + release_log += "Valve was opened by [user] ([user.ckey]), starting the transfer into the air
    " + log_open() + valve_open = !valve_open + . = TOPIC_REFRESH + + else if (href_list["remove_tank"]) + if(!holding) + return TOPIC_HANDLED + if (valve_open) + valve_open = 0 + release_log += "Valve was closed by [user] ([user.ckey]), stopping the transfer into the [holding]
    " + if(istype(holding, /obj/item/weapon/tank)) + holding.manipulated_by = user.real_name + holding.dropInto(loc) + holding = null + update_icon() + . = TOPIC_REFRESH + + else if (href_list["pressure_adj"]) + var/diff = text2num(href_list["pressure_adj"]) + if(diff > 0) + release_pressure = min(10*ONE_ATMOSPHERE, release_pressure+diff) + else + release_pressure = max(ONE_ATMOSPHERE/10, release_pressure+diff) + . = TOPIC_REFRESH + + else if (href_list["relabel"]) + if (!can_label) + return 0 + var/list/colors = list(\ + "\[N2O\]" = "redws", \ + "\[N2\]" = "red", \ + "\[O2\]" = "blue", \ + "\[Phoron\]" = "orange", \ + "\[CO2\]" = "black", \ + "\[H2\]" = "purple", \ + "\[Air\]" = "grey", \ + "\[CAUTION\]" = "yellow", \ + ) + var/label = input(user, "Choose canister label", "Gas canister") as null|anything in colors + if (label && CanUseTopic(user, state)) + canister_color = colors[label] + icon_state = colors[label] + SetName("\improper Canister: [label]") + update_icon() + . = TOPIC_REFRESH + +/obj/machinery/portable_atmospherics/canister/CanUseTopic() + if(destroyed) + return STATUS_CLOSE + return ..() + +/obj/machinery/portable_atmospherics/canister/phoron/New() + ..() + + src.air_contents.adjust_gas("phoron", MolesForPressure()) + src.update_icon() + return 1 + +/obj/machinery/portable_atmospherics/canister/oxygen/New() + ..() + + src.air_contents.adjust_gas("oxygen", MolesForPressure()) + src.update_icon() + return 1 + +/obj/machinery/portable_atmospherics/canister/hydrogen/New() + ..() + src.air_contents.adjust_gas("hydrogen", MolesForPressure()) + src.update_icon() + return 1 + +/obj/machinery/portable_atmospherics/canister/oxygen/prechilled/New() + ..() + src.air_contents.temperature = 80 + src.update_icon() + return 1 + +/obj/machinery/portable_atmospherics/canister/sleeping_agent/New() + ..() + + air_contents.adjust_gas("sleeping_agent", MolesForPressure()) + src.update_icon() + return 1 + +//Dirty way to fill room with gas. However it is a bit easier to do than creating some floor/engine/n2o -rastaf0 +/obj/machinery/portable_atmospherics/canister/sleeping_agent/roomfiller/New() + ..() + air_contents.gas["sleeping_agent"] = 9*4000 + spawn(10) + var/turf/simulated/location = src.loc + if (istype(src.loc)) + while (!location.air) + sleep(10) + location.assume_air(air_contents) + air_contents = new + return 1 + +/obj/machinery/portable_atmospherics/canister/nitrogen/New() + ..() + src.air_contents.adjust_gas("nitrogen", MolesForPressure()) + src.update_icon() + return 1 + +/obj/machinery/portable_atmospherics/canister/nitrogen/prechilled/New() + ..() + src.air_contents.temperature = 80 + src.update_icon() + return 1 + +/obj/machinery/portable_atmospherics/canister/carbon_dioxide/New() + ..() + src.air_contents.adjust_gas("carbon_dioxide", MolesForPressure()) + src.update_icon() + return 1 + + +/obj/machinery/portable_atmospherics/canister/air/New() + ..() + var/list/air_mix = StandardAirMix() + src.air_contents.adjust_multi("oxygen", air_mix["oxygen"], "nitrogen", air_mix["nitrogen"]) + + src.update_icon() + return 1 + + + +// Special types used for engine setup admin verb, they contain double amount of that of normal canister. +/obj/machinery/portable_atmospherics/canister/nitrogen/engine_setup/New() + ..() + src.air_contents.adjust_gas("nitrogen", MolesForPressure()) + src.update_icon() + return 1 + +/obj/machinery/portable_atmospherics/canister/carbon_dioxide/engine_setup/New() + ..() + src.air_contents.adjust_gas("carbon_dioxide", MolesForPressure()) + src.update_icon() + return 1 + +/obj/machinery/portable_atmospherics/canister/phoron/engine_setup/New() + ..() + src.air_contents.adjust_gas("phoron", MolesForPressure()) + src.update_icon() + return 1 + +/obj/machinery/portable_atmospherics/canister/hydrogen/engine_setup/New() + ..() + src.air_contents.adjust_gas("hydrogen", MolesForPressure()) + src.update_icon() diff --git a/code/game/machinery/atmoalter/clamp.dm b/code/game/machinery/atmoalter/clamp.dm new file mode 100644 index 00000000..b6db57aa --- /dev/null +++ b/code/game/machinery/atmoalter/clamp.dm @@ -0,0 +1,152 @@ +//Good luck. --BlueNexus + +//Static version of the clamp +/obj/machinery/clamp + name = "stasis clamp" + desc = "A magnetic clamp which can halt the flow of gas in a pipe, via a localised stasis field." + icon = 'icons/atmos/clamp.dmi' + icon_state = "pclamp0" + anchored = 1.0 + var/obj/machinery/atmospherics/pipe/simple/target = null + var/open = 1 + + var/datum/pipe_network/network_node1 + var/datum/pipe_network/network_node2 + +/obj/machinery/clamp/New(loc, var/obj/machinery/atmospherics/pipe/simple/to_attach = null) + ..() + if(istype(to_attach)) + target = to_attach + else + target = locate(/obj/machinery/atmospherics/pipe/simple) in loc + if(target) + update_networks() + dir = target.dir + return 1 + +/obj/machinery/clamp/proc/update_networks() + if(!target) + return + else + var/obj/machinery/atmospherics/pipe/node1 = target.node1 + var/obj/machinery/atmospherics/pipe/node2 = target.node2 + if(istype(node1)) + var/datum/pipeline/P1 = node1.parent + network_node1 = P1.network + if(istype(node2)) + var/datum/pipeline/P2 = node2.parent + network_node2 = P2.network + +/obj/machinery/clamp/attack_hand(var/mob/user) + if(!target || !user) + return + if(!open) + open() + else + close() + to_chat(user, "You turn [open ? "off" : "on"] \the [src]") + +/obj/machinery/clamp/Destroy() + if(!open) + spawn(-1) open() + . = ..() + +/obj/machinery/clamp/proc/open() + if(open || !target) + return 0 + + target.build_network() + + + if(network_node1&&network_node2) + network_node1.merge(network_node2) + network_node2 = network_node1 + + if(network_node1) + network_node1.update = 1 + else if(network_node2) + network_node2.update = 1 + + update_networks() + + open = 1 + icon_state = "pclamp0" + target.in_stasis = 0 + return 1 + +/obj/machinery/clamp/proc/close() + if(!open) + return 0 + + qdel(target.parent) + + if(network_node1) + qdel(network_node1) + if(network_node2) + qdel(network_node2) + + var/obj/machinery/atmospherics/pipe/node1 = null + var/obj/machinery/atmospherics/pipe/node2 = null + + if(target.node1) + target.node1.build_network() + node1 = target.node1 + if(target.node2) + target.node2.build_network() + node2 = target.node2 + if(istype(node1) && node1.parent) + var/datum/pipeline/P1 = node1.parent + P1.build_pipeline(node1) + qdel(P1) + if(istype(node2) && node2.parent) + var/datum/pipeline/P2 = node2.parent + P2.build_pipeline(node2) + qdel(P2) +// P1.build_network() +// P2.build_network() + + + + + open = 0 + icon_state = "pclamp1" + target.in_stasis = 1 + + return 1 + +/obj/machinery/clamp/MouseDrop(obj/over_object as obj) + if(!usr) + return + + if(open && over_object == usr && Adjacent(usr)) + to_chat(usr, "You begin to remove \the [src]...") + if (do_after(usr, 30, src)) + to_chat(usr, "You have removed \the [src].") + var/obj/item/clamp/C = new/obj/item/clamp(src.loc) + C.forceMove(usr.loc) + if(ishuman(usr)) + usr.put_in_hands(C) + qdel(src) + return + else + to_chat(usr, "You can't remove \the [src] while it's active!") + +/obj/item/clamp + name = "stasis clamp" + desc = "A magnetic clamp which can halt the flow of gas in a pipe, via a localised stasis field." + icon = 'icons/atmos/clamp.dmi' + icon_state = "pclamp0" + origin_tech = list(TECH_ENGINEERING = 4, TECH_MAGNET = 4) + +/obj/item/clamp/afterattack(var/atom/A, mob/user as mob, proximity) + if(!proximity) + return + + if (istype(A, /obj/machinery/atmospherics/pipe/simple)) + to_chat(user, "You begin to attach \the [src] to \the [A]...") + if (do_after(user, 30, src)) + to_chat(user, "You have attached \the [src] to \the [A].") + new/obj/machinery/clamp(A.loc, A) + user.drop_from_inventory(src) + qdel(src) + diff --git a/code/game/machinery/atmoalter/meter.dm b/code/game/machinery/atmoalter/meter.dm new file mode 100644 index 00000000..1ecc5ca9 --- /dev/null +++ b/code/game/machinery/atmoalter/meter.dm @@ -0,0 +1,118 @@ +/obj/machinery/meter + name = "meter" + desc = "A gas flow meter." + icon = 'icons/obj/meter.dmi' + icon_state = "meterX" + var/obj/machinery/atmospherics/pipe/target = null + anchored = 1.0 + power_channel = ENVIRON + var/frequency = 0 + var/id + use_power = 1 + idle_power_usage = 15 + +/obj/machinery/meter/Initialize() + . = ..() + if (!target) + src.target = locate(/obj/machinery/atmospherics/pipe) in loc + +/obj/machinery/meter/Process() + if(!target) + icon_state = "meterX" + return 0 + + if(stat & (BROKEN|NOPOWER)) + icon_state = "meter0" + return 0 + + var/datum/gas_mixture/environment = target.return_air() + if(!environment) + icon_state = "meterX" + return 0 + + var/env_pressure = environment.return_pressure() + if(env_pressure <= 0.15*ONE_ATMOSPHERE) + icon_state = "meter0" + else if(env_pressure <= 1.8*ONE_ATMOSPHERE) + var/val = round(env_pressure/(ONE_ATMOSPHERE*0.3) + 0.5) + icon_state = "meter1_[val]" + else if(env_pressure <= 30*ONE_ATMOSPHERE) + var/val = round(env_pressure/(ONE_ATMOSPHERE*5)-0.35) + 1 + icon_state = "meter2_[val]" + else if(env_pressure <= 59*ONE_ATMOSPHERE) + var/val = round(env_pressure/(ONE_ATMOSPHERE*5) - 6) + 1 + icon_state = "meter3_[val]" + else + icon_state = "meter4" + + if(frequency) + var/datum/radio_frequency/radio_connection = radio_controller.return_frequency(frequency) + + if(!radio_connection) return + + var/datum/signal/signal = new + signal.source = src + signal.transmission_method = 1 + signal.data = list( + "tag" = id, + "device" = "AM", + "pressure" = round(env_pressure), + "sigtype" = "status" + ) + radio_connection.post_signal(src, signal) + +/obj/machinery/meter/examine(mob/user) + . = ..() + + if(get_dist(user, src) > 3 && !(istype(user, /mob/living/silicon/ai) || isghost(user))) + to_chat(user, "You are too far away to read it.") + + else if(stat & (NOPOWER|BROKEN)) + to_chat(user, "The display is off.") + + else if(src.target) + var/datum/gas_mixture/environment = target.return_air() + if(environment) + to_chat(user, "The pressure gauge reads [round(environment.return_pressure(), 0.01)] kPa; [round(environment.temperature,0.01)]K ([round(environment.temperature-T0C,0.01)]°C)") + else + to_chat(user, "The sensor error light is blinking.") + else + to_chat(user, "The connect error light is blinking.") + + +/obj/machinery/meter/Click() + + if(istype(usr, /mob/living/silicon/ai)) // ghosts can call ..() for examine + usr.examinate(src) + return 1 + + return ..() + +/obj/machinery/meter/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(!isWrench(W)) + return ..() + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to unfasten \the [src]...") + if (do_after(user, 40, src)) + user.visible_message( \ + "\The [user] unfastens \the [src].", \ + "You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe_meter(src.loc) + qdel(src) + +// TURF METER - REPORTS A TILE'S AIR CONTENTS + +/obj/machinery/meter/turf/New() + ..() + src.target = loc + return 1 + + +/obj/machinery/meter/turf/Initialize() + . = ..() + if (!target) + src.target = loc + +/obj/machinery/meter/turf/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + return diff --git a/code/game/machinery/atmoalter/portable_atmospherics.dm b/code/game/machinery/atmoalter/portable_atmospherics.dm new file mode 100644 index 00000000..471f816b --- /dev/null +++ b/code/game/machinery/atmoalter/portable_atmospherics.dm @@ -0,0 +1,194 @@ +/obj/machinery/portable_atmospherics + name = "atmoalter" + use_power = 0 + var/datum/gas_mixture/air_contents = new + + var/obj/machinery/atmospherics/portables_connector/connected_port + var/obj/item/weapon/tank/holding + + var/volume = 0 + var/destroyed = 0 + + var/start_pressure = ONE_ATMOSPHERE + var/maximum_pressure = 90 * ONE_ATMOSPHERE + atom_flags = ATOM_FLAG_CLIMBABLE + +/obj/machinery/portable_atmospherics/New() + ..() + + air_contents.volume = volume + air_contents.temperature = T20C + + return 1 + +/obj/machinery/portable_atmospherics/Destroy() + QDEL_NULL(air_contents) + QDEL_NULL(holding) + . = ..() + +/obj/machinery/portable_atmospherics/Initialize() + . = ..() + spawn() + var/obj/machinery/atmospherics/portables_connector/port = locate() in loc + if(port) + connect(port) + update_icon() + +/obj/machinery/portable_atmospherics/Process() + if(!connected_port) //only react when pipe_network will ont it do it for you + //Allow for reactions + air_contents.react() + else + update_icon() + +/obj/machinery/portable_atmospherics/proc/StandardAirMix() + return list( + "oxygen" = O2STANDARD * MolesForPressure(), + "nitrogen" = N2STANDARD * MolesForPressure()) + +/obj/machinery/portable_atmospherics/proc/MolesForPressure(var/target_pressure = start_pressure) + return (target_pressure * air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature) + +/obj/machinery/portable_atmospherics/update_icon() + return null + +/obj/machinery/portable_atmospherics/proc/connect(obj/machinery/atmospherics/portables_connector/new_port) + //Make sure not already connected to something else + if(connected_port || !new_port || new_port.connected_device) + return 0 + + //Make sure are close enough for a valid connection + if(new_port.loc != loc) + return 0 + + //Perform the connection + connected_port = new_port + connected_port.connected_device = src + connected_port.on = 1 //Activate port updates + + anchored = 1 //Prevent movement + + //Actually enforce the air sharing + var/datum/pipe_network/network = connected_port.return_network(src) + if(network && !network.gases.Find(air_contents)) + network.gases += air_contents + network.update = 1 + + return 1 + +/obj/machinery/portable_atmospherics/proc/disconnect() + if(!connected_port) + return 0 + + var/datum/pipe_network/network = connected_port.return_network(src) + if(network) + network.gases -= air_contents + + anchored = 0 + + connected_port.connected_device = null + connected_port = null + + return 1 + +/obj/machinery/portable_atmospherics/proc/update_connected_network() + if(!connected_port) + return + + var/datum/pipe_network/network = connected_port.return_network(src) + if (network) + network.update = 1 + +/obj/machinery/portable_atmospherics/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if ((istype(W, /obj/item/weapon/tank) && !( src.destroyed ))) + if (src.holding) + return + var/obj/item/weapon/tank/T = W + user.drop_item() + T.forceMove(src) + src.holding = T + update_icon() + return + + else if(isWrench(W)) + if(connected_port) + disconnect() + to_chat(user, "You disconnect \the [src] from the port.") + update_icon() + return + else + var/obj/machinery/atmospherics/portables_connector/possible_port = locate(/obj/machinery/atmospherics/portables_connector/) in loc + if(possible_port) + if(connect(possible_port)) + to_chat(user, "You connect \the [src] to the port.") + update_icon() + return + else + to_chat(user, "\The [src] failed to connect to the port.") + return + else + to_chat(user, "Nothing happens.") + return + + else if (istype(W, /obj/item/device/analyzer)) + return + + return + +/obj/machinery/portable_atmospherics/return_air() + return air_contents + +/obj/machinery/portable_atmospherics/powered + var/power_rating + var/power_losses + var/last_power_draw = 0 + var/obj/item/weapon/cell/cell + +/obj/machinery/portable_atmospherics/powered/powered() + if(use_power) //using area power + return ..() + if(cell && cell.charge) + return 1 + return 0 + +/obj/machinery/portable_atmospherics/powered/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/weapon/cell)) + if(cell) + to_chat(user, "There is already a power cell installed.") + return + + var/obj/item/weapon/cell/C = I + + user.drop_item() + C.add_fingerprint(user) + cell = C + C.forceMove(src) + user.visible_message("[user] opens the panel on [src] and inserts [C].", "You open the panel on [src] and insert [C].") + power_change() + return + + if(isScrewdriver(I)) + if(!cell) + to_chat(user, "There is no power cell installed.") + return + + user.visible_message("[user] opens the panel on [src] and removes [cell].", "You open the panel on [src] and remove [cell].") + cell.add_fingerprint(user) + cell.dropInto(loc) + cell = null + power_change() + return + ..() + +/obj/machinery/portable_atmospherics/proc/log_open() + if(air_contents.gas.len == 0) + return + + var/gases = "" + for(var/gas in air_contents.gas) + if(gases) + gases += ", [gas]" + else + gases = gas + log_admin("[usr] ([usr.ckey]) opened '[src.name]' containing [gases].") + message_admins("[usr] ([usr.ckey]) opened '[src.name]' containing [gases].") diff --git a/code/game/machinery/atmoalter/pump.dm b/code/game/machinery/atmoalter/pump.dm new file mode 100644 index 00000000..9265e80f --- /dev/null +++ b/code/game/machinery/atmoalter/pump.dm @@ -0,0 +1,163 @@ +/obj/machinery/portable_atmospherics/powered/pump + name = "portable air pump" + + icon = 'icons/obj/atmos.dmi' + icon_state = "psiphon:0" + density = 1 + w_class = ITEM_SIZE_NORMAL + + var/on = 0 + var/direction_out = 0 //0 = siphoning, 1 = releasing + var/target_pressure = ONE_ATMOSPHERE + + var/pressuremin = 0 + var/pressuremax = 10 * ONE_ATMOSPHERE + + volume = 1000 + + power_rating = 7500 //7500 W ~ 10 HP + power_losses = 150 + +/obj/machinery/portable_atmospherics/powered/pump/filled + start_pressure = 90 * ONE_ATMOSPHERE + +/obj/machinery/portable_atmospherics/powered/pump/New() + ..() + cell = new/obj/item/weapon/cell/apc(src) + + var/list/air_mix = StandardAirMix() + src.air_contents.adjust_multi("oxygen", air_mix["oxygen"], "nitrogen", air_mix["nitrogen"]) + +/obj/machinery/portable_atmospherics/powered/pump/update_icon() + src.overlays = 0 + + if(on && cell && cell.charge) + icon_state = "psiphon:1" + else + icon_state = "psiphon:0" + + if(holding) + overlays += "siphon-open" + + if(connected_port) + overlays += "siphon-connector" + + return + +/obj/machinery/portable_atmospherics/powered/pump/emp_act(severity) + if(stat & (BROKEN|NOPOWER)) + ..(severity) + return + + if(prob(50/severity)) + on = !on + + if(prob(100/severity)) + direction_out = !direction_out + + target_pressure = rand(0,1300) + update_icon() + + ..(severity) + +/obj/machinery/portable_atmospherics/powered/pump/Process() + ..() + var/power_draw = -1 + + if(on && cell && cell.charge) + var/datum/gas_mixture/environment + if(holding) + environment = holding.air_contents + else + environment = loc.return_air() + + var/pressure_delta + var/output_volume + var/air_temperature + if(direction_out) + pressure_delta = target_pressure - environment.return_pressure() + output_volume = environment.volume * environment.group_multiplier + air_temperature = environment.temperature? environment.temperature : air_contents.temperature + else + pressure_delta = environment.return_pressure() - target_pressure + output_volume = air_contents.volume * air_contents.group_multiplier + air_temperature = air_contents.temperature? air_contents.temperature : environment.temperature + + var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION) + + if (pressure_delta > 0.01) + if (direction_out) + power_draw = pump_gas(src, air_contents, environment, transfer_moles, power_rating) + else + power_draw = pump_gas(src, environment, air_contents, transfer_moles, power_rating) + + if (power_draw < 0) + last_flow_rate = 0 + last_power_draw = 0 + else + power_draw = max(power_draw, power_losses) + cell.use(power_draw * CELLRATE) + last_power_draw = power_draw + + update_connected_network() + + //ran out of charge + if (!cell.charge) + power_change() + update_icon() + + src.updateDialog() + +/obj/machinery/portable_atmospherics/powered/pump/attack_ai(var/mob/user) + src.add_hiddenprint(user) + return src.attack_hand(user) + +/obj/machinery/portable_atmospherics/powered/pump/attack_ghost(var/mob/user) + return src.attack_hand(user) + +/obj/machinery/portable_atmospherics/powered/pump/attack_hand(var/mob/user) + ui_interact(user) + +/obj/machinery/portable_atmospherics/powered/pump/ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1) + var/list/data[0] + data["portConnected"] = connected_port ? 1 : 0 + data["tankPressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0) + data["targetpressure"] = round(target_pressure) + data["pump_dir"] = direction_out + data["minpressure"] = round(pressuremin) + data["maxpressure"] = round(pressuremax) + data["powerDraw"] = round(last_power_draw) + data["cellCharge"] = cell ? cell.charge : 0 + data["cellMaxCharge"] = cell ? cell.maxcharge : 1 + data["on"] = on ? 1 : 0 + + data["hasHoldingTank"] = holding ? 1 : 0 + if (holding) + data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure() > 0 ? holding.air_contents.return_pressure() : 0)) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "portpump.tmpl", "Portable Pump", 480, 410, state = GLOB.physical_state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/portable_atmospherics/powered/pump/OnTopic(user, href_list) + if(href_list["power"]) + on = !on + . = TOPIC_REFRESH + if(href_list["direction"]) + direction_out = !direction_out + . = TOPIC_REFRESH + if (href_list["remove_tank"]) + if(holding) + holding.dropInto(loc) + holding = null + . = TOPIC_REFRESH + if (href_list["pressure_adj"]) + var/diff = text2num(href_list["pressure_adj"]) + target_pressure = min(10*ONE_ATMOSPHERE, max(0, target_pressure+diff)) + . = TOPIC_REFRESH + + if(.) + update_icon() diff --git a/code/game/machinery/atmoalter/scrubber.dm b/code/game/machinery/atmoalter/scrubber.dm new file mode 100644 index 00000000..9b0c162b --- /dev/null +++ b/code/game/machinery/atmoalter/scrubber.dm @@ -0,0 +1,245 @@ +/obj/machinery/portable_atmospherics/powered/scrubber + name = "Portable Air Scrubber" + + icon = 'icons/obj/atmos.dmi' + icon_state = "pscrubber:0" + density = 1 + w_class = ITEM_SIZE_NORMAL + + var/on = 0 + var/volume_rate = 800 + + volume = 750 + + power_rating = 7500 //7500 W ~ 10 HP + power_losses = 150 + + var/minrate = 0 + var/maxrate = 10 * ONE_ATMOSPHERE + + var/list/scrubbing_gas + +/obj/machinery/portable_atmospherics/powered/scrubber/New() + ..() + cell = new/obj/item/weapon/cell/apc(src) + +/obj/machinery/portable_atmospherics/powered/scrubber/Initialize() + . = ..() + if(!scrubbing_gas) + scrubbing_gas = list() + for(var/g in gas_data.gases) + if(g != "oxygen" && g != "nitrogen") + scrubbing_gas += g + + +/obj/machinery/portable_atmospherics/powered/scrubber/emp_act(severity) + if(stat & (BROKEN|NOPOWER)) + ..(severity) + return + + if(prob(50/severity)) + on = !on + update_icon() + + ..(severity) + +/obj/machinery/portable_atmospherics/powered/scrubber/update_icon() + src.overlays = 0 + + if(on && cell && cell.charge) + icon_state = "pscrubber:1" + else + icon_state = "pscrubber:0" + + if(holding) + overlays += "scrubber-open" + + if(connected_port) + overlays += "scrubber-connector" + + return + +/obj/machinery/portable_atmospherics/powered/scrubber/Process() + ..() + + var/power_draw = -1 + + if(on && cell && cell.charge) + var/datum/gas_mixture/environment + if(holding) + environment = holding.air_contents + else + environment = loc.return_air() + + var/transfer_moles = min(1, volume_rate/environment.volume)*environment.total_moles + + power_draw = scrub_gas(src, scrubbing_gas, environment, air_contents, transfer_moles, power_rating) + + if (power_draw < 0) + last_flow_rate = 0 + last_power_draw = 0 + else + power_draw = max(power_draw, power_losses) + cell.use(power_draw * CELLRATE) + last_power_draw = power_draw + + update_connected_network() + + //ran out of charge + if (!cell.charge) + power_change() + update_icon() + + //src.update_icon() + src.updateDialog() + +/obj/machinery/portable_atmospherics/powered/scrubber/attack_ai(var/mob/user) + src.add_hiddenprint(user) + return src.attack_hand(user) + +/obj/machinery/portable_atmospherics/powered/scrubber/attack_ghost(var/mob/user) + return src.attack_hand(user) + +/obj/machinery/portable_atmospherics/powered/scrubber/attack_hand(var/mob/user) + ui_interact(user) + return + +/obj/machinery/portable_atmospherics/powered/scrubber/ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1) + var/list/data[0] + data["portConnected"] = connected_port ? 1 : 0 + data["tankPressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0) + data["rate"] = round(volume_rate) + data["minrate"] = round(minrate) + data["maxrate"] = round(maxrate) + data["powerDraw"] = round(last_power_draw) + data["cellCharge"] = cell ? cell.charge : 0 + data["cellMaxCharge"] = cell ? cell.maxcharge : 1 + data["on"] = on ? 1 : 0 + + data["hasHoldingTank"] = holding ? 1 : 0 + if (holding) + data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure() > 0 ? holding.air_contents.return_pressure() : 0)) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "portscrubber.tmpl", "Portable Scrubber", 480, 400, state = GLOB.physical_state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + + +/obj/machinery/portable_atmospherics/powered/scrubber/OnTopic(user, href_list) + if(href_list["power"]) + on = !on + . = TOPIC_REFRESH + if (href_list["remove_tank"]) + if(holding) + holding.dropInto(loc) + holding = null + . = TOPIC_REFRESH + if (href_list["volume_adj"]) + var/diff = text2num(href_list["volume_adj"]) + volume_rate = Clamp(volume_rate+diff, minrate, maxrate) + . = TOPIC_REFRESH + + if(.) + update_icon() + + +//Huge scrubber +/obj/machinery/portable_atmospherics/powered/scrubber/huge + name = "Huge Air Scrubber" + icon_state = "scrubber:0" + anchored = 1 + volume = 50000 + volume_rate = 5000 + + use_power = 1 + idle_power_usage = 500 //internal circuitry, friction losses and stuff + active_power_usage = 100000 //100 kW ~ 135 HP + + var/global/gid = 1 + var/id = 0 + +/obj/machinery/portable_atmospherics/powered/scrubber/huge/New() + ..() + cell = null + + id = gid + gid++ + + name = "[name] (ID [id])" + +/obj/machinery/portable_atmospherics/powered/scrubber/huge/attack_hand(var/mob/user as mob) + to_chat(usr, "You can't directly interact with this machine. Use the scrubber control console.") + +/obj/machinery/portable_atmospherics/powered/scrubber/huge/update_icon() + src.overlays = 0 + + if(on && !(stat & (NOPOWER|BROKEN))) + icon_state = "scrubber:1" + else + icon_state = "scrubber:0" + +/obj/machinery/portable_atmospherics/powered/scrubber/huge/power_change() + var/old_stat = stat + ..() + if (old_stat != stat) + update_icon() + +/obj/machinery/portable_atmospherics/powered/scrubber/huge/Process() + if(!on || (stat & (NOPOWER|BROKEN))) + update_use_power(0) + last_flow_rate = 0 + last_power_draw = 0 + return 0 + + var/power_draw = -1 + + var/datum/gas_mixture/environment = loc.return_air() + + var/transfer_moles = min(1, volume_rate/environment.volume)*environment.total_moles + + power_draw = scrub_gas(src, scrubbing_gas, environment, air_contents, transfer_moles, active_power_usage) + + if (power_draw < 0) + last_flow_rate = 0 + last_power_draw = 0 + else + use_power(power_draw) + update_connected_network() + +/obj/machinery/portable_atmospherics/powered/scrubber/huge/attackby(var/obj/item/I as obj, var/mob/user as mob) + if(isWrench(I)) + if(on) + to_chat(user, "Turn \the [src] off first!") + return + + anchored = !anchored + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You [anchored ? "wrench" : "unwrench"] \the [src].") + + return + + //doesn't use power cells + if(istype(I, /obj/item/weapon/cell)) + return + if(isScrewdriver(I)) + return + + //doesn't hold tanks + if(istype(I, /obj/item/weapon/tank)) + return + + ..() + + +/obj/machinery/portable_atmospherics/powered/scrubber/huge/stationary + name = "Stationary Air Scrubber" + +/obj/machinery/portable_atmospherics/powered/scrubber/huge/stationary/attackby(var/obj/item/I as obj, var/mob/user as mob) + if(isWrench(I)) + to_chat(user, "The bolts are too tight for you to unscrew!") + return + + ..() diff --git a/code/game/machinery/atmoalter/zvent.dm b/code/game/machinery/atmoalter/zvent.dm new file mode 100644 index 00000000..7df54a0b --- /dev/null +++ b/code/game/machinery/atmoalter/zvent.dm @@ -0,0 +1,29 @@ +/obj/machinery/zvent + name = "Interfloor Air Transfer System" + + icon = 'icons/obj/pipes.dmi' + icon_state = "vent-db" + density = 0 + anchored=1 + + var/on = 0 + var/volume_rate = 800 + +/obj/machinery/zvent/process() + + //all this object does, is make its turf share air with the ones above and below it, if they have a vent too. + if (istype(loc,/turf/simulated)) //if we're not on a valid turf, forget it + for (var/new_z in list(-1,1)) //change this list if a fancier system of z-levels gets implemented + var/turf/simulated/zturf_conn = locate(x,y,z+new_z) + if (istype(zturf_conn)) + var/obj/machinery/zvent/zvent_conn= locate(/obj/machinery/zvent) in zturf_conn + if (istype(zvent_conn)) + //both floors have simulated turfs, share() + var/turf/simulated/myturf = loc + var/datum/gas_mixture/conn_air = zturf_conn.zone.air //TODO: pop culture reference + var/datum/gas_mixture/my_air = myturf.air + if (istype(conn_air) && istype(my_air)) +// if (!my_air.compare(conn_air)) +// myturf.reset_delay() +// zturf_conn.reset_delay() + my_air.share(conn_air) diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm new file mode 100644 index 00000000..56fc92fd --- /dev/null +++ b/code/game/machinery/autolathe.dm @@ -0,0 +1,309 @@ +/obj/machinery/autolathe + name = "autolathe" + desc = "It produces items using metal and glass." + icon_state = "autolathe" + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 10 + active_power_usage = 2000 + clicksound = "keyboard" + clickvol = 30 + + var/list/machine_recipes + var/list/stored_material = list(DEFAULT_WALL_MATERIAL = 0, "glass" = 0) + var/list/storage_capacity = list(DEFAULT_WALL_MATERIAL = 0, "glass" = 0) + var/show_category = "All" + + var/hacked = 0 + var/disabled = 0 + var/shocked = 0 + var/busy = 0 + + var/mat_efficiency = 1 + var/build_time = 50 + + var/datum/wires/autolathe/wires = null + + +/obj/machinery/autolathe/New() + + ..() + wires = new(src) + //Create parts for lathe. + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/autolathe(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/console_screen(src) + RefreshParts() + +/obj/machinery/autolathe/Destroy() + qdel(wires) + wires = null + return ..() + +/obj/machinery/autolathe/proc/update_recipe_list() + if(!machine_recipes) + machine_recipes = autolathe_recipes + +/obj/machinery/autolathe/interact(mob/user as mob) + + update_recipe_list() + + if(..() || (disabled && !panel_open)) + to_chat(user, "\The [src] is disabled!") + return + + if(shocked) + shock(user, 50) + + var/dat = "

    Autolathe Control Panel


    " + + if(!disabled) + dat += "" + var/material_top = "" + var/material_bottom = "" + + for(var/material in stored_material) + material_top += "" + material_bottom += "" + + dat += "[material_top][material_bottom]
    [material][stored_material[material]]/[storage_capacity[material]]

    " + dat += "

    Printable Designs

    Showing: [show_category].

    " + + var/index = 0 + for(var/datum/autolathe/recipe/R in machine_recipes) + index++ + if(R.hidden && !hacked || (show_category != "All" && show_category != R.category)) + continue + var/can_make = 1 + var/material_string = "" + var/multiplier_string = "" + var/max_sheets + var/comma + if(!R.resources || !R.resources.len) + material_string = "No resources required." + else + //Make sure it's buildable and list requires resources. + for(var/material in R.resources) + var/sheets = round(stored_material[material]/round(R.resources[material]*mat_efficiency)) + if(isnull(max_sheets) || max_sheets > sheets) + max_sheets = sheets + if(!isnull(stored_material[material]) && stored_material[material] < round(R.resources[material]*mat_efficiency)) + can_make = 0 + if(!comma) + comma = 1 + else + material_string += ", " + material_string += "[round(R.resources[material] * mat_efficiency)] [material]" + material_string += ".
    " + //Build list of multipliers for sheets. + if(R.is_stack) + var/obj/item/stack/R_stack = R.path + max_sheets = min(max_sheets, initial(R_stack.max_amount)) + //do not allow lathe to print more sheets than the max amount that can fit in one stack + if(max_sheets && max_sheets > 0) + multiplier_string += "
    " + for(var/i = 5;i*" : ""][can_make ? "" : ""][R.name][can_make ? "" : ""][R.hidden ? "*" : ""][multiplier_string]" + + dat += "
    [material_string]

    " + //Hacking. + if(panel_open) + dat += "

    Maintenance Panel

    " + dat += wires.GetInteractWindow() + + dat += "
    " + + user << browse(dat, "window=autolathe") + onclose(user, "autolathe") + +/obj/machinery/autolathe/attackby(var/obj/item/O as obj, var/mob/user as mob) + + if(busy) + to_chat(user, "\The [src] is busy. Please wait for completion of previous operation.") + return + + if(default_deconstruction_screwdriver(user, O)) + updateUsrDialog() + return + if(default_deconstruction_crowbar(user, O)) + return + if(default_part_replacement(user, O)) + return + + if(stat) + return + + if(panel_open) + //Don't eat multitools or wirecutters used on an open lathe. + if(isMultitool(O) || isWirecutter(O)) + attack_hand(user) + return + + if(O.loc != user && !(istype(O,/obj/item/stack))) + return 0 + + if(is_robot_module(O)) + return 0 + + //Resources are being loaded. + var/obj/item/eating = O + if(!eating.matter) + to_chat(user, "\The [eating] does not contain significant amounts of useful materials and cannot be accepted.") + return + + var/filltype = 0 // Used to determine message. + var/total_used = 0 // Amount of material used. + var/mass_per_sheet = 0 // Amount of material constituting one sheet. + + for(var/material in eating.matter) + + if(isnull(stored_material[material]) || isnull(storage_capacity[material])) + continue + + if(stored_material[material] >= storage_capacity[material]) + continue + + var/total_material = eating.matter[material] + + //If it's a stack, we eat multiple sheets. + if(istype(eating,/obj/item/stack)) + var/obj/item/stack/stack = eating + total_material *= stack.get_amount() + + if(stored_material[material] + total_material > storage_capacity[material]) + total_material = storage_capacity[material] - stored_material[material] + filltype = 1 + else + filltype = 2 + + stored_material[material] += total_material + total_used += total_material + mass_per_sheet += eating.matter[material] + + if(!filltype) + to_chat(user, "\The [src] is full. Please remove material from the autolathe in order to insert more.") + return + else if(filltype == 1) + to_chat(user, "You fill \the [src] to capacity with \the [eating].") + else + to_chat(user, "You fill \the [src] with \the [eating].") + + flick("autolathe_o", src) // Plays metal insertion animation. Work out a good way to work out a fitting animation. ~Z + + if(istype(eating,/obj/item/stack)) + var/obj/item/stack/stack = eating + stack.use(max(1, round(total_used/mass_per_sheet))) // Always use at least 1 to prevent infinite materials. + else + user.remove_from_mob(O) + qdel(O) + + updateUsrDialog() + return + +/obj/machinery/autolathe/attack_hand(mob/user as mob) + user.set_machine(src) + interact(user) + +/obj/machinery/autolathe/CanUseTopic(user, href_list) + if(busy) + to_chat(user, "The autolathe is busy. Please wait for completion of previous operation.") + return min(STATUS_UPDATE, ..()) + return ..() + +/obj/machinery/autolathe/OnTopic(user, href_list, state) + set waitfor = 0 + if(href_list["change_category"]) + var/choice = input("Which category do you wish to display?") as null|anything in autolathe_categories+"All" + if(!choice || !CanUseTopic(user, state)) + return TOPIC_HANDLED + show_category = choice + . = TOPIC_REFRESH + + else if(href_list["make"] && machine_recipes) + . = TOPIC_REFRESH + var/index = text2num(href_list["make"]) + var/multiplier = text2num(href_list["multiplier"]) + var/datum/autolathe/recipe/making + + if(index > 0 && index <= machine_recipes.len) + making = machine_recipes[index] + + //Exploit detection, not sure if necessary after rewrite. + if(!making || multiplier < 0 || multiplier > 100) + log_and_message_admins("tried to exploit an autolathe to duplicate an item!", user) + return TOPIC_HANDLED + + busy = 1 + update_use_power(2) + + //Check if we still have the materials. + for(var/material in making.resources) + if(!isnull(stored_material[material])) + if(stored_material[material] < round(making.resources[material] * mat_efficiency) * multiplier) + return TOPIC_REFRESH + + //Consume materials. + for(var/material in making.resources) + if(!isnull(stored_material[material])) + stored_material[material] = max(0, stored_material[material] - round(making.resources[material] * mat_efficiency) * multiplier) + + //Fancy autolathe animation. + flick("autolathe_n", src) + + sleep(build_time) + + busy = 0 + update_use_power(1) + + //Sanity check. + if(!making || QDELETED(src)) return TOPIC_HANDLED + + //Create the desired item. + var/obj/item/I = new making.path(loc) + if(multiplier > 1 && istype(I, /obj/item/stack)) + var/obj/item/stack/S = I + S.amount = multiplier + S.update_icon() + + if(. == TOPIC_REFRESH) + interact(user) + +/obj/machinery/autolathe/update_icon() + icon_state = (panel_open ? "autolathe_t" : "autolathe") + +//Updates overall lathe storage size. +/obj/machinery/autolathe/RefreshParts() + ..() + var/mb_rating = 0 + var/man_rating = 0 + for(var/obj/item/weapon/stock_parts/matter_bin/MB in component_parts) + mb_rating += MB.rating + for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) + man_rating += M.rating + + storage_capacity[DEFAULT_WALL_MATERIAL] = mb_rating * 25000 + storage_capacity["glass"] = mb_rating * 12500 + build_time = 50 / man_rating + mat_efficiency = 1.1 - man_rating * 0.1// Normally, price is 1.25 the amount of material, so this shouldn't go higher than 0.8. Maximum rating of parts is 3 + +/obj/machinery/autolathe/dismantle() + + for(var/mat in stored_material) + var/material/M = get_material_by_name(mat) + if(!istype(M)) + continue + var/obj/item/stack/material/S = new M.stack_type(get_turf(src)) + if(stored_material[mat] > S.perunit) + S.amount = round(stored_material[mat] / S.perunit) + else + qdel(S) + ..() + return 1 diff --git a/code/game/machinery/autolathe_datums.dm b/code/game/machinery/autolathe_datums.dm new file mode 100644 index 00000000..93cd028e --- /dev/null +++ b/code/game/machinery/autolathe_datums.dm @@ -0,0 +1,587 @@ +/var/global/list/autolathe_recipes +/var/global/list/autolathe_categories + +var/const/EXTRA_COST_FACTOR = 1.25 +// Items are more expensive to produce than they are to recycle. + +/proc/populate_lathe_recipes() + + //Create global autolathe recipe list if it hasn't been made already. + autolathe_recipes = list() + autolathe_categories = list() + for(var/R in typesof(/datum/autolathe/recipe)-/datum/autolathe/recipe) + var/datum/autolathe/recipe/recipe = new R + autolathe_recipes += recipe + autolathe_categories |= recipe.category + + var/obj/item/I = new recipe.path + if(I.matter && !recipe.resources) //This can be overidden in the datums. + recipe.resources = list() + for(var/material in I.matter) + recipe.resources[material] = I.matter[material] * EXTRA_COST_FACTOR + qdel(I) + +/datum/autolathe/recipe + var/name = "object" + var/path + var/list/resources + var/hidden + var/category + var/power_use = 0 + var/is_stack + +/datum/autolathe/recipe/bucket + name = "bucket" + path = /obj/item/weapon/reagent_containers/glass/bucket + category = "General" + +/datum/autolathe/recipe/drinkingglass + name = "drinking glass" + path = /obj/item/weapon/reagent_containers/food/drinks/glass2/square + category = "General" + New() + ..() + var/obj/O = path + name = initial(O.name) // generic recipes yay + +/datum/autolathe/recipe/drinkingglass/rocks + path = /obj/item/weapon/reagent_containers/food/drinks/glass2/rocks + +/datum/autolathe/recipe/drinkingglass/shake + path = /obj/item/weapon/reagent_containers/food/drinks/glass2/shake + +/datum/autolathe/recipe/drinkingglass/cocktail + path = /obj/item/weapon/reagent_containers/food/drinks/glass2/cocktail + +/datum/autolathe/recipe/drinkingglass/shot + path = /obj/item/weapon/reagent_containers/food/drinks/glass2/shot + +/datum/autolathe/recipe/drinkingglass/pint + path = /obj/item/weapon/reagent_containers/food/drinks/glass2/pint + +/datum/autolathe/recipe/drinkingglass/mug + path = /obj/item/weapon/reagent_containers/food/drinks/glass2/mug + +/datum/autolathe/recipe/drinkingglass/wine + path = /obj/item/weapon/reagent_containers/food/drinks/glass2/wine + +/datum/autolathe/recipe/drinkingglass/wine + path = /obj/item/weapon/reagent_containers/food/drinks/glass2/carafe + +/datum/autolathe/recipe/flashlight + name = "flashlight" + path = /obj/item/device/flashlight + category = "General" + +/datum/autolathe/recipe/floor_light + name = "floor light" + path = /obj/machinery/floor_light + category = "General" + +/datum/autolathe/recipe/extinguisher + name = "extinguisher" + path = /obj/item/weapon/extinguisher + category = "General" + +/datum/autolathe/recipe/jar + name = "jar" + path = /obj/item/glass_jar + category = "General" + +/datum/autolathe/recipe/crowbar + name = "crowbar" + path = /obj/item/weapon/crowbar + category = "Tools" + +/datum/autolathe/recipe/prybar + name = "pry bar" + path = /obj/item/weapon/crowbar/prybar + category = "Tools" + +/datum/autolathe/recipe/int_wirer + name = "integrated circuit wirer" + path = /obj/item/device/integrated_electronics/wirer + category = "Tools" + +/datum/autolathe/recipe/int_debugger + name = "integrated circuit debugger" + path = /obj/item/device/integrated_electronics/debugger + category = "Tools" + +/datum/autolathe/recipe/int_analyzer + name = "integrated circuit analyzer" + path = /obj/item/device/integrated_electronics/analyzer + category = "Tools" + +/datum/autolathe/recipe/multitool + name = "multitool" + path = /obj/item/device/multitool + category = "Tools" + +/datum/autolathe/recipe/t_scanner + name = "T-ray scanner" + path = /obj/item/device/t_scanner + category = "Tools" + +/datum/autolathe/recipe/weldertool + name = "welding tool" + path = /obj/item/weapon/weldingtool + category = "Tools" + +/datum/autolathe/recipe/screwdriver + name = "screwdriver" + path = /obj/item/weapon/screwdriver + category = "Tools" + +/datum/autolathe/recipe/wirecutters + name = "wirecutters" + path = /obj/item/weapon/wirecutters + category = "Tools" + +/datum/autolathe/recipe/wrench + name = "wrench" + path = /obj/item/weapon/wrench + category = "Tools" + +/datum/autolathe/recipe/hatchet + name = "hatchet" + path = /obj/item/weapon/material/hatchet + category = "Tools" + +/datum/autolathe/recipe/minihoe + name = "mini hoe" + path = /obj/item/weapon/material/minihoe + category = "Tools" + +/datum/autolathe/recipe/radio_headset + name = "radio headset" + path = /obj/item/device/radio/headset + category = "General" + +/datum/autolathe/recipe/radio_bounced + name = "shortwave radio" + path = /obj/item/device/radio/off + category = "General" + +/datum/autolathe/recipe/suit_cooler + name = "suit cooling unit" + path = /obj/item/device/suit_cooling_unit + category = "General" + +/datum/autolathe/recipe/weldermask + name = "welding mask" + path = /obj/item/clothing/head/welding + category = "General" + +/datum/autolathe/recipe/metal + name = "steel sheets" + path = /obj/item/stack/material/steel + category = "General" + is_stack = 1 + +/datum/autolathe/recipe/glass + name = "glass sheets" + path = /obj/item/stack/material/glass + category = "General" + is_stack = 1 + +/datum/autolathe/recipe/rglass + name = "reinforced glass sheets" + path = /obj/item/stack/material/glass/reinforced + category = "General" + is_stack = 1 + +/datum/autolathe/recipe/rods + name = "metal rods" + path = /obj/item/stack/rods + category = "General" + is_stack = 1 + +/datum/autolathe/recipe/knife + name = "kitchen knife" + path = /obj/item/weapon/material/knife + category = "General" + +/datum/autolathe/recipe/taperecorder + name = "tape recorder" + path = /obj/item/device/taperecorder/empty + category = "General" + +/datum/autolathe/recipe/tape + name = "tape" + path = /obj/item/device/tape + category = "General" + +/datum/autolathe/recipe/airlockmodule + name = "airlock electronics" + path = /obj/item/weapon/airlock_electronics + category = "Engineering" + +/datum/autolathe/recipe/airalarm + name = "air alarm electronics" + path = /obj/item/weapon/airalarm_electronics + category = "Engineering" + +/datum/autolathe/recipe/firealarm + name = "fire alarm electronics" + path = /obj/item/weapon/firealarm_electronics + category = "Engineering" + +/datum/autolathe/recipe/powermodule + name = "power control module" + path = /obj/item/weapon/module/power_control + category = "Engineering" + +/datum/autolathe/recipe/rcd_ammo + name = "matter cartridge" + path = /obj/item/weapon/rcd_ammo + category = "Engineering" +/datum/autolathe/recipe/rcd_ammo_large + name = "high-capacity matter cartridge" + path = /obj/item/weapon/rcd_ammo/large + category = "Engineering" + +/datum/autolathe/recipe/scalpel + name = "scalpel" + path = /obj/item/weapon/scalpel + category = "Medical" + +/datum/autolathe/recipe/circularsaw + name = "circular saw" + path = /obj/item/weapon/circular_saw + category = "Medical" + +/datum/autolathe/recipe/surgicaldrill + name = "surgical drill" + path = /obj/item/weapon/surgicaldrill + category = "Medical" + +/datum/autolathe/recipe/retractor + name = "retractor" + path = /obj/item/weapon/retractor + category = "Medical" + +/datum/autolathe/recipe/cautery + name = "cautery" + path = /obj/item/weapon/cautery + category = "Medical" + +/datum/autolathe/recipe/hemostat + name = "hemostat" + path = /obj/item/weapon/hemostat + category = "Medical" + +/datum/autolathe/recipe/beaker + name = "glass beaker" + path = /obj/item/weapon/reagent_containers/glass/beaker + category = "Medical" + +/datum/autolathe/recipe/beaker_large + name = "large glass beaker" + path = /obj/item/weapon/reagent_containers/glass/beaker/large + category = "Medical" + +/datum/autolathe/recipe/vial + name = "glass vial" + path = /obj/item/weapon/reagent_containers/glass/beaker/vial + category = "Medical" + +/datum/autolathe/recipe/syringe + name = "syringe" + path = /obj/item/weapon/reagent_containers/syringe + category = "Medical" + +/datum/autolathe/recipe/implanter + name = "implanter" + path = /obj/item/weapon/implanter + category = "Medical" + +/datum/autolathe/recipe/syringegun_ammo + name = "syringe gun cartridge" + path = /obj/item/weapon/syringe_cartridge + category = "Arms and Ammunition" + +/datum/autolathe/recipe/shotgun_blanks + name = "ammunition (shotgun, blank)" + path = /obj/item/ammo_casing/shotgun/blank + category = "Arms and Ammunition" + +/datum/autolathe/recipe/shotgun_beanbag + name = "ammunition (shotgun, beanbag)" + path = /obj/item/ammo_casing/shotgun/beanbag + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/shotgun_flash + name = "ammunition (shotgun, flash)" + path = /obj/item/ammo_casing/shotgun/flash + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/magazine_rubber + name = "ammunition (.45, rubber)" + path = /obj/item/ammo_magazine/c45m/rubber + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/speedloader_44_rubber + name = "speed loader (.44 magnum, rubber)" + path = /obj/item/ammo_magazine/c44/rubber + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/magazine_flash + name = "ammunition (.45, flash)" + path = /obj/item/ammo_magazine/c45m/flash + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/magazine_smg_rubber + name = "ammunition (9mm rubber top mounted)" + path = /obj/item/ammo_magazine/mc9mmt/rubber + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/consolescreen + name = "console screen" + path = /obj/item/weapon/stock_parts/console_screen + category = "Devices and Components" + +/datum/autolathe/recipe/igniter + name = "igniter" + path = /obj/item/device/assembly/igniter + category = "Devices and Components" + +/datum/autolathe/recipe/signaler + name = "signaler" + path = /obj/item/device/assembly/signaler + category = "Devices and Components" + +/datum/autolathe/recipe/sensor_infra + name = "infrared sensor" + path = /obj/item/device/assembly/infra + category = "Devices and Components" + +/datum/autolathe/recipe/timer + name = "timer" + path = /obj/item/device/assembly/timer + category = "Devices and Components" + +/datum/autolathe/recipe/sensor_prox + name = "proximity sensor" + path = /obj/item/device/assembly/prox_sensor + category = "Devices and Components" + +/datum/autolathe/recipe/cable_coil + name = "cable coil" + path = /obj/item/stack/cable_coil/single + category = "Devices and Components" + is_stack = 1 + +/datum/autolathe/recipe/tube/large + name = "spotlight tube" + path = /obj/item/weapon/light/tube/large + category = "General" + +/datum/autolathe/recipe/tube + name = "light tube" + path = /obj/item/weapon/light/tube + category = "General" + +/datum/autolathe/recipe/bulb + name = "light bulb" + path = /obj/item/weapon/light/bulb + category = "General" + +/datum/autolathe/recipe/ashtray_glass + name = "glass ashtray" + path = /obj/item/weapon/material/ashtray/glass + category = "General" + +/datum/autolathe/recipe/camera_assembly + name = "camera assembly" + path = /obj/item/weapon/camera_assembly + category = "Engineering" + +/datum/autolathe/recipe/weldinggoggles + name = "welding goggles" + path = /obj/item/clothing/glasses/welding + category = "General" + +/datum/autolathe/recipe/blackpen + name = "black ink pen" + path = /obj/item/weapon/pen + category = "General" + +/datum/autolathe/recipe/bluepen + name = "blue ink pen" + path = /obj/item/weapon/pen/blue + category = "General" + +/datum/autolathe/recipe/redpen + name = "red ink pen" + path = /obj/item/weapon/pen/red + category = "General" + +/datum/autolathe/recipe/clipboard + name = "clipboard" + path = /obj/item/weapon/clipboard + category = "General" + +/datum/autolathe/recipe/destTagger + name = "destination tagger" + path = /obj/item/device/destTagger + category = "General" + +/datum/autolathe/recipe/labeler + name = "hand labeler" + path = /obj/item/weapon/hand_labeler + category = "General" + +/datum/autolathe/recipe/flamethrower + name = "flamethrower" + path = /obj/item/weapon/flamethrower/full + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/magazine_revolver_1 + name = "ammunition (.357)" + path = /obj/item/ammo_magazine/a357 + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/magazine_revolver_2 + name = "ammunition (.45)" + path = /obj/item/ammo_magazine/c45m + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/speedloader_44 + name = "speed loader (.44 magnum)" + path = /obj/item/ammo_magazine/c44 + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/magazine_revolver_3 + name = "ammunition (.38)" + path = /obj/item/ammo_magazine/c38 + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/magazine_revolver_4 + name = "ammunition (.50AE)" + path = /obj/item/ammo_magazine/c50 + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/magazine_stetchkin + name = "ammunition (9mm)" + path = /obj/item/ammo_magazine/mc9mm + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/magazine_stetchkin_flash + name = "ammunition (9mm, flash)" + path = /obj/item/ammo_magazine/mc9mm/flash + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/magazine_c20r + name = "ammunition (10mm)" + path = /obj/item/ammo_magazine/a10mm + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/magazine_arifle + name = "ammunition (5.56mm)" + path = /obj/item/ammo_magazine/c556 + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/magazine_smg + name = "ammunition (9mm top mounted)" + path = /obj/item/ammo_magazine/mc9mmt + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/magazine_carbine + name = "ammunition (7.62mm)" + path = /obj/item/ammo_magazine/a762 + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/shotgun + name = "ammunition (slug, shotgun)" + path = /obj/item/ammo_casing/shotgun + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/shotgun_pellet + name = "ammunition (shell, shotgun)" + path = /obj/item/ammo_casing/shotgun/pellet + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/tacknife + name = "tactical knife" + path = /obj/item/weapon/material/hatchet/tacknife + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/stunshell + name = "ammunition (stun cartridge, shotgun)" + path = /obj/item/ammo_casing/shotgun/stunshell + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/magazine_uzi + name = "ammunition (machine.45)" + path = /obj/item/ammo_magazine/c45uzi + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/magazine_deagle + name = "ammunition (.50 AE)" + path = /obj/item/ammo_magazine/a50 + hidden = 1 + category = "Arms and Ammunition" + +/datum/autolathe/recipe/rcd + name = "rapid construction device" + path = /obj/item/weapon/rcd + hidden = 1 + category = "Engineering" + +/datum/autolathe/recipe/electropack + name = "electropack" + path = /obj/item/device/radio/electropack + hidden = 1 + category = "Devices and Components" + +/datum/autolathe/recipe/beartrap + name = "mechanical trap" + path = /obj/item/weapon/beartrap + hidden = 1 + category = "Devices and Components" + +/datum/autolathe/recipe/welder_industrial + name = "industrial welding tool" + path = /obj/item/weapon/weldingtool/largetank + hidden = 1 + category = "Tools" + +/datum/autolathe/recipe/handcuffs + name = "handcuffs" + path = /obj/item/weapon/handcuffs + hidden = 1 + category = "General" + +/datum/autolathe/recipe/cell_device + name = "device cell" + path = /obj/item/weapon/cell/device/standard + category = "Devices and Components" + +/datum/autolathe/recipe/ecigcartridge + name = "ecigarette cartridge" + path = /obj/item/weapon/reagent_containers/ecig_cartridge/blank + category = "Devices and Components" diff --git a/code/game/machinery/biogenerator.dm b/code/game/machinery/biogenerator.dm new file mode 100644 index 00000000..1e55ee44 --- /dev/null +++ b/code/game/machinery/biogenerator.dm @@ -0,0 +1,246 @@ +#define BG_READY 0 +#define BG_PROCESSING 1 +#define BG_NO_BEAKER 2 +#define BG_COMPLETE 3 +#define BG_EMPTY 4 + +/obj/machinery/biogenerator + name = "Biogenerator" + desc = "" + icon = 'icons/obj/biogenerator.dmi' + icon_state = "biogen-stand" + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 40 + var/processing = 0 + var/obj/item/weapon/reagent_containers/glass/beaker = null + var/points = 0 + var/state = BG_READY + var/denied = 0 + var/build_eff = 1 + var/eat_eff = 1 + var/list/products = list( + "Food" = list( + /obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton = 30, + /obj/item/weapon/reagent_containers/food/snacks/meat = 50), + "Nutrients" = list( + /obj/item/weapon/reagent_containers/glass/bottle/eznutrient = 60, + /obj/item/weapon/reagent_containers/glass/bottle/left4zed = 120, + /obj/item/weapon/reagent_containers/glass/bottle/robustharvest = 120), + "Leather" = list( + /obj/item/weapon/storage/wallet/leather = 100, + /obj/item/clothing/gloves/thick/botany = 250, + /obj/item/weapon/storage/belt/utility = 300, + /obj/item/weapon/storage/backpack/satchel = 400, + /obj/item/weapon/storage/bag/cash = 400, + /obj/item/clothing/shoes/workboots = 400, + /obj/item/clothing/shoes/leather = 400, + /obj/item/clothing/shoes/dress = 400, + /obj/item/clothing/suit/leathercoat = 500, + /obj/item/clothing/suit/storage/toggle/brown_jacket = 500, + /obj/item/clothing/suit/storage/toggle/bomber = 500, + /obj/item/clothing/suit/storage/hooded/wintercoat = 500)) + +/obj/machinery/biogenerator/New() + ..() + create_reagents(1000) + beaker = new /obj/item/weapon/reagent_containers/glass/bottle(src) + + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/biogenerator(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + + RefreshParts() + +/obj/machinery/biogenerator/on_reagent_change() //When the reagents change, change the icon as well. + update_icon() + +/obj/machinery/biogenerator/update_icon() + if(state == BG_NO_BEAKER) + icon_state = "biogen-empty" + else if(state == BG_READY || state == BG_COMPLETE) + icon_state = "biogen-stand" + else + icon_state = "biogen-work" + return + +/obj/machinery/biogenerator/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(default_deconstruction_screwdriver(user, O)) + return + if(default_deconstruction_crowbar(user, O)) + return + if(default_part_replacement(user, O)) + return + if(istype(O, /obj/item/weapon/reagent_containers/glass)) + if(beaker) + to_chat(user, "]The [src] is already loaded.") + else + user.remove_from_mob(O) + O.forceMove(src) + beaker = O + state = BG_READY + updateUsrDialog() + else if(processing) + to_chat(user, "\The [src] is currently processing.") + else if(istype(O, /obj/item/weapon/storage/plants)) + var/obj/item/weapon/storage/plants/P = O + var/i = 0 + for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in contents) + i++ + if(i >= 10) + to_chat(user, "\The [src] is already full! Activate it.") + else + var/hadPlants = 0 + for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in P.contents) + hadPlants = 1 + P.remove_from_storage(G, src) + i++ + if(i >= 10) + to_chat(user, "You fill \the [src] to its capacity.") + break + if(!hadPlants) + to_chat(user, "\The [P] has no produce inside.") + else if(i < 10) + to_chat(user, "You empty \the [P] into \the [src].") + + + else if(!istype(O, /obj/item/weapon/reagent_containers/food/snacks/grown)) + to_chat(user, "You cannot put this in \the [src].") + else + var/i = 0 + for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in contents) + i++ + if(i >= 10) + to_chat(user, "\The [src] is full! Activate it.") + else + user.remove_from_mob(O) + O.forceMove(src) + to_chat(user, "You put \the [O] in \the [src]") + update_icon() + return + +/** + * Display the NanoUI window for the vending machine. + * + * See NanoUI documentation for details. + */ +/obj/machinery/biogenerator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) + var/list/data = list() + data["state"] = state + var/name + var/cost + var/type_name + var/path + if (state == BG_READY) + data["points"] = points + var/list/listed_types = list() + for(var/c_type =1 to products.len) + type_name = products[c_type] + var/list/current_content = products[type_name] + var/list/listed_products = list() + for(var/c_product =1 to current_content.len) + path = current_content[c_product] + var/atom/A = path + name = initial(A.name) + cost = current_content[path] + listed_products.Add(list(list( + "product_index" = c_product, + "name" = name, + "cost" = cost))) + listed_types.Add(list(list( + "type_name" = type_name, + "products" = listed_products))) + data["types"] = listed_types + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "biogenerator.tmpl", "Biogenerator", 440, 600) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/biogenerator/OnTopic(user, href_list) + switch (href_list["action"]) + if("activate") + activate() + if("detach") + if(beaker) + beaker.dropInto(src.loc) + beaker = null + state = BG_NO_BEAKER + update_icon() + if("create") + if (state == BG_PROCESSING) + return TOPIC_REFRESH + var/type = href_list["type"] + var/product_index = text2num(href_list["product_index"]) + if (isnull(products[type])) + return TOPIC_REFRESH + var/list/sub_products = products[type] + if (product_index < 1 || product_index > sub_products.len) + return TOPIC_REFRESH + create_product(type, sub_products[product_index]) + if("return") + state = BG_READY + return TOPIC_REFRESH + +/obj/machinery/biogenerator/attack_hand(mob/user as mob) + if(stat & (BROKEN|NOPOWER)) + return + ui_interact(user) + +/obj/machinery/biogenerator/proc/activate() + if (usr.stat) + return + if (stat) //NOPOWER etc + return + + var/S = 0 + for(var/obj/item/weapon/reagent_containers/food/snacks/grown/I in contents) + S += 5 + if(I.reagents.get_reagent_amount(/datum/reagent/nutriment) < 0.1) + points += 1 + else points += I.reagents.get_reagent_amount(/datum/reagent/nutriment) * 10 * eat_eff + qdel(I) + if(S) + state = BG_PROCESSING + GLOB.nanomanager.update_uis(src) + update_icon() + playsound(src.loc, 'sound/machines/blender.ogg', 50, 1) + use_power(S * 30) + sleep((S + 15) / eat_eff) + state = BG_READY + update_icon() + else + state = BG_EMPTY + return + +/obj/machinery/biogenerator/proc/create_product(var/type, var/path) + state = BG_PROCESSING + var/cost = products[type][path] + cost = round(cost/build_eff) + points -= cost + GLOB.nanomanager.update_uis(src) + update_icon() + sleep(30) + var/atom/movable/result = new path + result.dropInto(loc) + state = BG_COMPLETE + update_icon() + return 1 + + +/obj/machinery/biogenerator/RefreshParts() + ..() + var/man_rating = 0 + var/bin_rating = 0 + + for(var/obj/item/weapon/stock_parts/P in component_parts) + if(istype(P, /obj/item/weapon/stock_parts/matter_bin)) + bin_rating += P.rating + if(istype(P, /obj/item/weapon/stock_parts/manipulator)) + man_rating += P.rating + + build_eff = man_rating + eat_eff = bin_rating diff --git a/code/game/machinery/bioprinter.dm b/code/game/machinery/bioprinter.dm new file mode 100644 index 00000000..5d1e87d8 --- /dev/null +++ b/code/game/machinery/bioprinter.dm @@ -0,0 +1,243 @@ +// GENERIC PRINTER - DO NOT USE THIS OBJECT. +// Flesh and robot printers are defined below this object. + +/obj/machinery/organ_printer + name = "organ printer" + desc = "It's a machine that prints organs." + icon = 'icons/obj/surgery.dmi' + icon_state = "bioprinter" + + anchored = 1 + density = 1 + use_power = 1 + idle_power_usage = 40 + active_power_usage = 300 + + var/stored_matter = 0 + var/max_stored_matter = 0 + var/print_delay = 100 + var/printing + + // These should be subtypes of /obj/item/organ + var/list/products = list( + BP_HEART = list(/obj/item/organ/internal/heart, 25), + BP_LUNGS = list(/obj/item/organ/internal/lungs, 25), + BP_KIDNEYS = list(/obj/item/organ/internal/kidneys,20), + BP_EYES = list(/obj/item/organ/internal/eyes, 20), + BP_LIVER = list(/obj/item/organ/internal/liver, 25), + BP_L_ARM = list(/obj/item/organ/external/arm, 65), + BP_R_ARM = list(/obj/item/organ/external/arm/right, 65), + BP_L_LEG = list(/obj/item/organ/external/leg, 65), + BP_R_LEG = list(/obj/item/organ/external/leg/right, 65), + BP_L_FOOT = list(/obj/item/organ/external/foot, 40), + BP_R_FOOT = list(/obj/item/organ/external/foot/right, 40), + BP_L_HAND = list(/obj/item/organ/external/hand, 40), + BP_R_HAND = list(/obj/item/organ/external/hand/right, 40) + ) + +/obj/machinery/organ_printer/attackby(var/obj/item/O, var/mob/user) + if(default_deconstruction_screwdriver(user, O)) + updateUsrDialog() + return + if(default_deconstruction_crowbar(user, O)) + return + if(default_part_replacement(user, O)) + return + return ..() + +/obj/machinery/organ_printer/update_icon() + overlays.Cut() + if(panel_open) + overlays += "bioprinter_panel_open" + if(printing) + overlays += "bioprinter_working" + +/obj/machinery/organ_printer/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + RefreshParts() + +/obj/machinery/organ_printer/examine(var/mob/user) + . = ..() + to_chat(user, "It is loaded with [stored_matter]/[max_stored_matter] matter units.") + +/obj/machinery/organ_printer/RefreshParts() + print_delay = initial(print_delay) + max_stored_matter = 0 + for(var/obj/item/weapon/stock_parts/matter_bin/bin in component_parts) + max_stored_matter += bin.rating * 50 + for(var/obj/item/weapon/stock_parts/manipulator/manip in component_parts) + print_delay -= (manip.rating-1)*10 + print_delay = max(0,print_delay) + . = ..() + +/obj/machinery/organ_printer/attack_hand(mob/user) + + if(printing || (stat & (BROKEN|NOPOWER))) + return + + var/choice = input("What would you like to print?") as null|anything in products + + if(!choice || printing || (stat & (BROKEN|NOPOWER))) + return + + if(!can_print(choice)) + return + + stored_matter -= products[choice][2] + + use_power = 2 + printing = 1 + update_icon() + + sleep(print_delay) + + use_power = 1 + printing = 0 + update_icon() + + if(!choice || !src || (stat & (BROKEN|NOPOWER))) + return + + print_organ(choice) + +/obj/machinery/organ_printer/proc/can_print(var/choice) + if(stored_matter < products[choice][2]) + visible_message("\The [src] displays a warning: 'Not enough matter. [stored_matter] stored and [products[choice][2]] needed.'") + return 0 + return 1 + +/obj/machinery/organ_printer/proc/print_organ(var/choice) + var/new_organ = products[choice][1] + var/obj/item/organ/O = new new_organ(get_turf(src)) + O.status |= ORGAN_CUT_AWAY + return O +// END GENERIC PRINTER + +// ROBOT ORGAN PRINTER +/obj/machinery/organ_printer/robot + name = "prosthetic organ fabricator" + desc = "It's a machine that prints prosthetic organs." + icon_state = "roboprinter" + + var/matter_amount_per_sheet = 10 + var/matter_type = DEFAULT_WALL_MATERIAL + +/obj/machinery/organ_printer/robot/mapped/Initialize() + . = ..() + stored_matter = max_stored_matter + +/obj/machinery/organ_printer/robot/dismantle() + if(stored_matter >= matter_amount_per_sheet) + new /obj/item/stack/material/steel(get_turf(src), Floor(stored_matter/matter_amount_per_sheet)) + return ..() + +/obj/machinery/organ_printer/robot/New() + ..() + component_parts += new /obj/item/weapon/circuitboard/roboprinter + +/obj/machinery/organ_printer/robot/print_organ(var/choice) + var/obj/item/organ/O = ..() + O.robotize() + O.status |= ORGAN_CUT_AWAY // robotize() resets status to 0 + visible_message("\The [src] churns for a moment, then spits out \a [O].") + return O + +/obj/machinery/organ_printer/robot/attackby(var/obj/item/weapon/W, var/mob/user) + if(istype(W, /obj/item/stack/material) && W.get_material_name() == matter_type) + if((max_stored_matter-stored_matter) < matter_amount_per_sheet) + to_chat(user, "\The [src] is too full.") + return + var/obj/item/stack/S = W + var/space_left = max_stored_matter - stored_matter + var/sheets_to_take = min(S.amount, Floor(space_left/matter_amount_per_sheet)) + if(sheets_to_take <= 0) + to_chat(user, "\The [src] is too full.") + return + stored_matter = min(max_stored_matter, stored_matter + (sheets_to_take*matter_amount_per_sheet)) + to_chat(user, "\The [src] processes \the [W]. Levels of stored matter now: [stored_matter]") + S.use(sheets_to_take) + return + return ..() +// END ROBOT ORGAN PRINTER + +// FLESH ORGAN PRINTER +/obj/machinery/organ_printer/flesh + name = "bioprinter" + desc = "It's a machine that prints replacement organs." + icon_state = "bioprinter" + var/list/amount_list = list( + /obj/item/weapon/reagent_containers/food/snacks/meat = 50, + /obj/item/weapon/reagent_containers/food/snacks/rawcutlet = 15 + ) + var/loaded_dna //Blood sample for DNA hashing. + +/obj/machinery/organ_printer/flesh/can_print(var/choice) + . = ..() + if(!loaded_dna || !loaded_dna["donor"]) + visible_message("\The [src] displays a warning: 'No DNA saved. Insert a blood sample.'") + return 0 + +/obj/machinery/organ_printer/flesh/mapped/Initialize() + . = ..() + stored_matter = max_stored_matter + +/obj/machinery/organ_printer/flesh/dismantle() + var/turf/T = get_turf(src) + if(T) + while(stored_matter >= amount_list[/obj/item/weapon/reagent_containers/food/snacks/meat]) + stored_matter -= amount_list[/obj/item/weapon/reagent_containers/food/snacks/meat] + new /obj/item/weapon/reagent_containers/food/snacks/meat(T) + return ..() + +/obj/machinery/organ_printer/flesh/New() + ..() + component_parts += new /obj/item/device/healthanalyzer + component_parts += new /obj/item/weapon/circuitboard/bioprinter + +/obj/machinery/organ_printer/flesh/print_organ(var/choice) + var/obj/item/organ/O + var/weakref/W = loaded_dna["donor"] + var/mob/living/carbon/human/H = W.resolve() + if(H && istype(H)) + if(H.species && H.species.has_organ[choice]) + var/new_organ = H.species.has_organ[choice] + O = new new_organ(get_turf(src)) + O.status |= ORGAN_CUT_AWAY + else + O = ..() + O.set_dna(H.dna) + if(O.species) + // This is a very hacky way of doing of what organ/New() does if it has an owner + O.w_class = max(O.w_class + mob_size_difference(O.species.mob_size, MOB_MEDIUM), 1) + + visible_message("\The [src] churns for a moment, injects its stored DNA into the biomass, then spits out \a [O].") + return O + +/obj/machinery/organ_printer/flesh/attackby(obj/item/weapon/W, mob/user) + // Load with matter for printing. + for(var/path in amount_list) + if(istype(W, path)) + if((max_stored_matter - stored_matter) < amount_list[path]) + to_chat(user, "\The [src] is too full.") + return + stored_matter += amount_list[path] + user.drop_item() + to_chat(user, "\The [src] processes \the [W]. Levels of stored biomass now: [stored_matter]") + qdel(W) + return + + // DNA sample from syringe. + if(istype(W,/obj/item/weapon/reagent_containers/syringe)) + var/obj/item/weapon/reagent_containers/syringe/S = W + var/datum/reagent/blood/injected = locate() in S.reagents.reagent_list //Grab some blood + if(injected && injected.data) + loaded_dna = injected.data + to_chat(user, "You inject the blood sample into the bioprinter.") + return + return ..() +// END FLESH ORGAN PRINTER diff --git a/code/game/machinery/bluespacerelay.dm b/code/game/machinery/bluespacerelay.dm new file mode 100644 index 00000000..fd797cd1 --- /dev/null +++ b/code/game/machinery/bluespacerelay.dm @@ -0,0 +1,50 @@ +/obj/machinery/bluespacerelay + name = "Emergency Bluespace Relay" + desc = "This sends messages through bluespace! Wow!" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "bspacerelay" + + anchored = 1 + density = 1 + use_power = 1 + var/on = 1 + + idle_power_usage = 15000 + active_power_usage = 15000 + +/obj/machinery/bluespacerelay/Process() + update_power() + update_icon() + + +/obj/machinery/bluespacerelay/update_icon() + if(on) + icon_state = initial(icon_state) + else + icon_state = "[initial(icon_state)]_off" + +/obj/machinery/bluespacerelay/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/bluespacerelay(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/subspace/filter(src) + component_parts += new /obj/item/weapon/stock_parts/subspace/crystal(src) + component_parts += new /obj/item/stack/cable_coil(src, 30) +/obj/machinery/bluespacerelay/proc/update_power() + + if(stat & (BROKEN|NOPOWER|EMPED)) + on = 0 + else + on = 1 + +/obj/machinery/bluespacerelay/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(default_deconstruction_screwdriver(user, O)) + return + if(default_deconstruction_crowbar(user, O)) + return + if(default_part_replacement(user, O)) + return + + ..() \ No newline at end of file diff --git a/code/game/machinery/boombox.dm b/code/game/machinery/boombox.dm new file mode 100644 index 00000000..bed2bbd2 --- /dev/null +++ b/code/game/machinery/boombox.dm @@ -0,0 +1,138 @@ +/obj/item/device/boombox + name = "Boombox" + icon = 'icons/obj/boombox.dmi' + icon_state = "boombox" + desc = "A smuggled in boombox used with smuggled in cassette tapes to listen to smuggled in tunes." + var/obj/item/device/cassette/casseta = null + var/datum/sound_token/sound_token + var/playing = 0 + var/sound_id + w_class = ITEM_SIZE_NO_CONTAINER + +/obj/item/device/boombox/attack_hand(mob/user as mob) + if(istype(get_area(user), /area/warfare/battlefield/no_mans_land))//Do not take this into no man's land please. + to_chat(user, "I can't take that with me into no man's land. Wouldn't want to lose it.") + return + else + ..() + +/obj/item/device/boombox/New() + ..() + sound_id = "[type]_[sequential_id(type)]" + + +/obj/item/device/boombox/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/device/cassette)) + if(casseta) + to_chat(user, "There is already cassette inside.") + return + if(!user.unEquip(I)) + return + I.forceMove(src) + casseta = I + visible_message("[user] insert cassette into [src].") + playsound(get_turf(src), 'sound/machines/bominside.ogg', 50, 1) + return + ..() + + +/obj/item/device/boombox/MouseDrop(var/obj/over_object) + if (!over_object || !(ishuman(usr) || issmall(usr))) + return + + if (!(src.loc == usr)) + return + + switch(over_object.name) + if("r_hand") + eject() + if("l_hand") + eject() + + + + +/obj/item/device/boombox/proc/eject() + if(usr.incapacitated()) + return + if(!casseta) + to_chat(usr, "There is no cassette inside.") + return + + if(playing) + StopPlaying() + visible_message("[usr] ejects cassette from [src].") + playsound(get_turf(src), 'sound/machines/bominside.ogg', 50, 1) + usr.put_in_hands(casseta) + casseta = null + +/obj/item/device/boombox/attack_self(mob/user) + if(playing) + StopPlaying() + playsound(get_turf(src), 'sound/machines/bomclick.ogg', 50, 1) + return + else + StartPlaying() + playsound(get_turf(src), 'sound/machines/bomclick.ogg', 50, 1) + + +/obj/item/device/boombox/proc/StopPlaying() + playing = 0 + QDEL_NULL(sound_token) + +/obj/item/device/boombox/proc/StartPlaying() + StopPlaying() + if(isnull(casseta)) + return + if(!casseta.sound_inside) + return + + sound_token = sound_player.PlayLoopingSound(src, sound_id, casseta.sound_inside, volume = 40, range = 10, falloff = 3, prefer_mute = TRUE, ignore_vis = TRUE) + playing = 1 + +/obj/item/device/cassette + name = "cassette tape" + desc = "A tape smuggled in from somewhere in the outside world. Contains some bumping tunes on it." + icon = 'icons/obj/cassette.dmi' + icon_state = "cassette_0" + var/sound/sound_inside + w_class = ITEM_SIZE_TINY + var/uploader_idiot + var/current_side = 1 + var/sound/a_side + var/sound/b_side + +/obj/item/device/cassette/New() + icon_state = "cassette_[rand(0,12)]" + +/obj/item/device/cassette/attack_self(mob/user) + . = ..() + if(current_side == 1) + sound_inside = b_side + current_side = 2 + to_chat(user, "You flip the cassette over to the b-side.") + else + sound_inside = a_side + current_side = 1 + to_chat(user, "You flip the cassette over to the a-side.") + +/obj/item/device/cassette/tape1/New() + ..() + name = "\"The Outside World\'s Greatest Hits Vol.1\" magn-o-tape" + a_side = pick('sound/music/boombox1.ogg','sound/music/boombox2.ogg') + b_side = 'sound/music/boombox3.ogg' + sound_inside = a_side + +/obj/item/device/cassette/tape2/New() + ..() + name = "\"The Outside World\'s Greatest Hits Vol.2\" magn-o-tape" + a_side = pick('sound/music/boombox4.ogg', 'sound/music/boombox5.ogg') + b_side = 'sound/music/boombox6.ogg' + sound_inside = a_side + +/obj/item/device/cassette/tape3/New() + ..() + name = "\"The Outside World\'s Greatest Hits Vol.3\" magn-o-tape" + a_side = pick('sound/music/boombox7.ogg', 'sound/music/boombox8.ogg') + b_side = pick('sound/music/boombox9.ogg', 'sound/music/boombox10.ogg') + sound_inside = a_side \ No newline at end of file diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm new file mode 100644 index 00000000..7d5b2dc8 --- /dev/null +++ b/code/game/machinery/buttons.dm @@ -0,0 +1,234 @@ +/obj/machinery/button + name = "button" + icon = 'icons/obj/objects.dmi' + icon_state = "launcherbtt" + desc = "A remote control switch for something." + var/id = null + var/active = 0 + var/operating = 0 + anchored = 1.0 + use_power = 1 + idle_power_usage = 2 + active_power_usage = 4 + var/_wifi_id + var/datum/wifi/sender/wifi_sender + +/obj/machinery/button/Initialize() + . = ..() + update_icon() + if(_wifi_id && !wifi_sender) + wifi_sender = new/datum/wifi/sender/button(_wifi_id, src) + +/obj/machinery/button/Destroy() + qdel(wifi_sender) + wifi_sender = null + return..() + +/obj/machinery/button/attack_ai(mob/user as mob) + return attack_hand(user) + +/obj/machinery/button/attackby(obj/item/weapon/W, mob/user as mob) + return attack_hand(user) + +/obj/machinery/button/attack_hand(mob/living/user) + if(..()) return 1 + if(istype(user, /mob/living/carbon)) + playsound(src, "button", 60) + activate(user) + +/obj/machinery/button/proc/activate(mob/living/user) + if(operating || !istype(wifi_sender)) + return + + operating = 1 + active = 1 + use_power(5) + update_icon() + wifi_sender.activate(user) + sleep(10) + active = 0 + update_icon() + operating = 0 + +/obj/machinery/button/update_icon() + if(active) + icon_state = "launcheract" + else + icon_state = "launcherbtt" + +//alternate button with the same functionality, except has a lightswitch sprite instead +/obj/machinery/button/switch + icon = 'icons/obj/power.dmi' + icon_state = "light0" + +/obj/machinery/button/switch/update_icon() + icon_state = "light[active]" + +//alternate button with the same functionality, except has a door control sprite instead +/obj/machinery/button/alternate + icon = 'icons/obj/stationobjs.dmi' + icon_state = "doorctrl0" + +/obj/machinery/button/alternate/update_icon() + if(active) + icon_state = "doorctrl0" + else + icon_state = "doorctrl2" + +//Toggle button with two states (on and off) and calls seperate procs for each state +/obj/machinery/button/toggle/activate(mob/living/user) + if(operating || !istype(wifi_sender)) + return + + operating = 1 + active = !active + use_power(5) + if(active) + wifi_sender.activate(user) + else + wifi_sender.deactivate(user) + update_icon() + operating = 0 + +//alternate button with the same toggle functionality, except has a lightswitch sprite instead +/obj/machinery/button/toggle/switch + icon = 'icons/obj/power.dmi' + icon_state = "light0" + +/obj/machinery/button/toggle/switch/update_icon() + icon_state = "light[active]" + + + +//alternate button with the same toggle functionality, except has a door control sprite instead +/obj/machinery/button/toggle/alternate + icon = 'icons/obj/stationobjs.dmi' + icon_state = "doorctrl0" + +/obj/machinery/button/toggle/alternate/update_icon() + if(active) + icon_state = "doorctrl0" + else + icon_state = "doorctrl2" + +//------------------------------- +// Mass Driver Button +// Passes the activate call to a mass driver wifi sender +//------------------------------- +/obj/machinery/button/mass_driver + name = "mass driver button" + +/obj/machinery/button/mass_driver/Initialize() + if(_wifi_id) + wifi_sender = new/datum/wifi/sender/mass_driver(_wifi_id, src) + . = ..() + +/obj/machinery/button/mass_driver/activate(mob/living/user) + if(active || !istype(wifi_sender)) + return + + active = 1 + use_power(5) + update_icon() + wifi_sender.activate() + active = 0 + update_icon() + + +//------------------------------- +// Door Button +//------------------------------- + +// Bitmasks for door switches. +#define OPEN 0x1 +#define IDSCAN 0x2 +#define BOLTS 0x4 +#define SHOCK 0x8 +#define SAFE 0x10 + +/obj/machinery/button/toggle/door + icon = 'icons/obj/stationobjs.dmi' + icon_state = "doorctrl" + + var/_door_functions = 1 +/* Bitflag, 1 = open + 2 = idscan + 4 = bolts + 8 = shock + 16 = door safties */ + +/obj/machinery/button/toggle/door/update_icon() + if(active) + icon_state = "[initial(icon_state)]" + else + icon_state = "[initial(icon_state)]2" + +/obj/machinery/button/toggle/door/Initialize() + if(_wifi_id) + wifi_sender = new/datum/wifi/sender/door(_wifi_id, src) + . = ..() + +/obj/machinery/button/toggle/door/activate(mob/living/user) + if(operating || !istype(wifi_sender)) + return + + operating = 1 + active = !active + use_power(5) + update_icon() + if(active) + if(_door_functions & IDSCAN) + wifi_sender.activate("enable_idscan") + if(_door_functions & SHOCK) + wifi_sender.activate("electrify") + if(_door_functions & SAFE) + wifi_sender.activate("enable_safeties") + if(_door_functions & BOLTS) + wifi_sender.activate("unlock") + if(_door_functions & OPEN) + wifi_sender.activate("open") + else + if(_door_functions & IDSCAN) + wifi_sender.activate("disable_idscan") + if(_door_functions & SHOCK) + wifi_sender.activate("unelectrify") + if(_door_functions & SAFE) + wifi_sender.activate("disable_safeties") + if(_door_functions & OPEN) + wifi_sender.activate("close") + if(_door_functions & BOLTS) + wifi_sender.activate("lock") + operating = 0 + +#undef OPEN +#undef IDSCAN +#undef BOLTS +#undef SHOCK +#undef SAFE + +/obj/machinery/button/toggle/valve + name = "remote valve control" + var/frequency = 0 + var/datum/radio_frequency/radio_connection + +/obj/machinery/button/toggle/valve/Initialize() + . = ..() + radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) + +/obj/machinery/button/toggle/valve/update_icon() + if(!active) + icon_state = "launcherbtt" + else + icon_state = "launcheract" + + +/obj/machinery/button/toggle/valve/activate(mob/living/user) + var/datum/signal/signal = new + signal.transmission_method = 1 // radio transmission + signal.source = src + signal.frequency = frequency + signal.data["tag"] = id + signal.data["command"] = "valve_toggle" + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + active = !active + update_icon() \ No newline at end of file diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm new file mode 100644 index 00000000..b86701ae --- /dev/null +++ b/code/game/machinery/camera/camera.dm @@ -0,0 +1,467 @@ +/obj/machinery/camera + name = "security camera" + desc = "It's used to monitor rooms." + icon = 'icons/obj/monitors.dmi' + icon_state = "camera" + use_power = 2 + idle_power_usage = 5 + active_power_usage = 10 + plane = ABOVE_HUMAN_PLANE + layer = CAMERA_LAYER + + var/list/network = list(NETWORK_EXODUS) + var/c_tag = null + var/c_tag_order = 999 + var/number = 0 //camera number in area + var/status = 1 + anchored = 1.0 + var/invuln = null + var/bugged = 0 + var/obj/item/weapon/camera_assembly/assembly = null + + var/toughness = 5 //sorta fragile + + // WIRES + var/datum/wires/camera/wires = null // Wires datum + + //OTHER + + var/view_range = 7 + var/short_range = 2 + + var/light_disabled = 0 + var/alarm_on = 0 + var/busy = 0 + + var/on_open_network = 0 + + var/affected_by_emp_until = 0 + +/obj/machinery/camera/malf_upgrade(var/mob/living/silicon/ai/user) + ..() + malf_upgraded = 1 + + upgradeEmpProof() + upgradeXRay() + + to_chat(user, "\The [src] has been upgraded. It now has X-Ray capability and EMP resistance.") + return 1 + +/obj/machinery/camera/apply_visual(mob/living/carbon/human/M) + if(!M.client) + return + M.overlay_fullscreen("fishbed",/obj/screen/fullscreen/fishbed) + M.overlay_fullscreen("scanlines",/obj/screen/fullscreen/scanline) + M.overlay_fullscreen("whitenoise",/obj/screen/fullscreen/noise) + M.machine_visual = src + return 1 + +/obj/machinery/camera/remove_visual(mob/living/carbon/human/M) + if(!M.client) + return + M.clear_fullscreen("fishbed",0) + M.clear_fullscreen("scanlines") + M.clear_fullscreen("whitenoise") + M.machine_visual = null + return 1 + +/obj/machinery/camera/New() + wires = new(src) + assembly = new(src) + assembly.state = 4 + + /* // Use this to look for cameras that have the same c_tag. + for(var/obj/machinery/camera/C in cameranet.cameras) + var/list/tempnetwork = C.network&src.network + if(C != src && C.c_tag == src.c_tag && tempnetwork.len) + world.log << "[src.c_tag] [src.x] [src.y] [src.z] conflicts with [C.c_tag] [C.x] [C.y] [C.z]" + */ + if(!src.network || src.network.len < 1) + if(loc) + error("[src.name] in [get_area(src)] (x:[src.x] y:[src.y] z:[src.z] has errored. [src.network?"Empty network list":"Null network list"]") + else + error("[src.name] in [get_area(src)]has errored. [src.network?"Empty network list":"Null network list"]") + ASSERT(src.network) + ASSERT(src.network.len > 0) + ..() + +/obj/machinery/camera/Initialize() + . = ..() + if(!c_tag) + number = 1 + var/area/A = get_area(src) + if(A) + for(var/obj/machinery/camera/C in A) + if(C == src) continue + if(C.number) + number = max(number, C.number+1) + c_tag = "[A.name][number == 1 ? "" : " #[number]"]" + invalidateCameraCache() + + +/obj/machinery/camera/Destroy() + deactivate(null, 0) //kick anyone viewing out + if(assembly) + qdel(assembly) + assembly = null + qdel(wires) + wires = null + return ..() + +/obj/machinery/camera/Process() + if((stat & EMPED) && world.time >= affected_by_emp_until) + stat &= ~EMPED + cancelCameraAlarm() + update_icon() + update_coverage() + return internal_process() + +/obj/machinery/camera/proc/internal_process() + return + +/obj/machinery/camera/emp_act(severity) + if(!isEmpProof() && prob(100/severity)) + if(!affected_by_emp_until || (world.time < affected_by_emp_until)) + affected_by_emp_until = max(affected_by_emp_until, world.time + (90 SECONDS / severity)) + else + stat |= EMPED + set_light(0) + triggerCameraAlarm() + update_icon() + update_coverage() + START_PROCESSING(SSmachines, src) + +/obj/machinery/camera/bullet_act(var/obj/item/projectile/P) + take_damage(P.get_structure_damage()) + +/obj/machinery/camera/ex_act(severity) + if(src.invuln) + return + + //camera dies if an explosion touches it! + if(severity <= 2 || prob(50)) + destroy() + + ..() //and give it the regular chance of being deleted outright + +/obj/machinery/camera/hitby(AM as mob|obj) + ..() + if (istype(AM, /obj)) + var/obj/O = AM + if (O.throwforce >= src.toughness) + visible_message("[src] was hit by [O].") + take_damage(O.throwforce) + +/obj/machinery/camera/proc/setViewRange(var/num = 7) + src.view_range = num + cameranet.update_visibility(src, 0) + +/obj/machinery/camera/attack_hand(mob/living/carbon/human/user as mob) + if(!istype(user)) + return + + if(user.species.can_shred(user)) + set_status(0) + visible_message("\The [user] slashes at [src]!") + playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) + add_hiddenprint(user) + destroy() + +/obj/machinery/camera/attackby(obj/item/W as obj, mob/living/user as mob) + update_coverage() + // DECONSTRUCTION + if(isScrewdriver(W)) +// to_chat(user, "You start to [panel_open ? "close" : "open"] the camera's panel.") + //if(toggle_panel(user)) // No delay because no one likes screwdrivers trying to be hip and have a duration cooldown + panel_open = !panel_open + user.visible_message("[user] screws the camera's panel [panel_open ? "open" : "closed"]!", + "You screw the camera's panel [panel_open ? "open" : "closed"].") + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + + else if((isWirecutter(W) || isMultitool(W)) && panel_open) + interact(user) + + else if(isWelder(W) && (wires.CanDeconstruct() || (stat & BROKEN))) + if(weld(W, user)) + if(assembly) + assembly.dropInto(loc) + assembly.anchored = 1 + assembly.camera_name = c_tag + assembly.camera_network = english_list(network, "Exodus", ",", ",") + assembly.update_icon() + assembly.dir = src.dir + if(stat & BROKEN) + assembly.state = 2 + to_chat(user, "You repaired \the [src] frame.") + cancelCameraAlarm() + else + assembly.state = 1 + to_chat(user, "You cut \the [src] free from the wall.") + new /obj/item/stack/cable_coil(src.loc, length=2) + assembly = null //so qdel doesn't eat it. + qdel(src) + return + + // OTHER + else if (can_use() && (istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/device/pda)) && isliving(user)) + var/mob/living/U = user + var/obj/item/weapon/paper/X = null + var/obj/item/device/pda/P = null + + var/itemname = "" + var/info = "" + if(istype(W, /obj/item/weapon/paper)) + X = W + itemname = X.name + info = X.info + else + P = W + itemname = P.name + info = P.notehtml + to_chat(U, "You hold \a [itemname] up to the camera ...") + for(var/mob/living/silicon/ai/O in GLOB.living_mob_list_) + if(!O.client) continue + if(U.name == "Unknown") to_chat(O, "[U] holds \a [itemname] up to one of your cameras ...") + else to_chat(O, "[U] holds \a [itemname] up to one of your cameras ...") + O << browse(text("[][]", itemname, info), text("window=[]", itemname)) + + else if(W.damtype == BRUTE || W.damtype == BURN) //bashing cameras + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if (W.force >= src.toughness) + visible_message("[src] has been [pick(W.attack_verb)] with [W] by [user]!") + if (istype(W, /obj/item)) //is it even possible to get into attackby() with non-items? + var/obj/item/I = W + if (I.hitsound) + playsound(loc, I.hitsound, 50, 1, -1) + take_damage(W.force) + + else + ..() + +/obj/machinery/camera/proc/deactivate(user as mob, var/choice = 1) + // The only way for AI to reactivate cameras are malf abilities, this gives them different messages. + if(istype(user, /mob/living/silicon/ai)) + user = null + + if(choice != 1) + return + + set_status(!src.status) + if (!(src.status)) + if(user) + visible_message(" [user] has deactivated [src]!") + else + visible_message(" [src] clicks and shuts down. ") + playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) + icon_state = "[initial(icon_state)]1" + add_hiddenprint(user) + else + if(user) + visible_message(" [user] has reactivated [src]!") + else + visible_message(" [src] clicks and reactivates itself. ") + playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) + icon_state = initial(icon_state) + add_hiddenprint(user) + +/obj/machinery/camera/proc/take_damage(var/force, var/message) + //prob(25) gives an average of 3-4 hits + if (force >= toughness && (force > toughness*4 || prob(25))) + destroy() + +//Used when someone breaks a camera +/obj/machinery/camera/proc/destroy() + stat |= BROKEN + wires.RandomCutAll() + + triggerCameraAlarm() + update_icon() + update_coverage() + + //sparks + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, loc) + spark_system.start() + playsound(loc, "sparks", 50, 1) + +/obj/machinery/camera/proc/set_status(var/newstatus) + if (status != newstatus) + status = newstatus + update_coverage() + +/obj/machinery/camera/check_eye(mob/user) + if(!can_use()) return -1 + if(isXRay()) return SEE_TURFS|SEE_MOBS|SEE_OBJS + return 0 + +/obj/machinery/camera/update_icon() + if (!status || (stat & BROKEN)) + icon_state = "[initial(icon_state)]1" + else if (stat & EMPED) + icon_state = "[initial(icon_state)]emp" + else + icon_state = initial(icon_state) + +/obj/machinery/camera/proc/triggerCameraAlarm(var/duration = 0) + alarm_on = 1 + camera_alarm.triggerAlarm(loc, src, duration) + +/obj/machinery/camera/proc/cancelCameraAlarm() + if(wires.IsIndexCut(CAMERA_WIRE_ALARM)) + return + + alarm_on = 0 + camera_alarm.clearAlarm(loc, src) + +//if false, then the camera is listed as DEACTIVATED and cannot be used +/obj/machinery/camera/proc/can_use() + if(!status) + return 0 + if(stat & (EMPED|BROKEN)) + return 0 + return 1 + +/obj/machinery/camera/proc/can_see() + var/list/see = null + var/turf/pos = get_turf(src) + if(!pos) + return list() + + if(isXRay()) + see = range(view_range, pos) + else + see = hear(view_range, pos) + return see + +/atom/proc/auto_turn() + //Automatically turns based on nearby walls. + var/turf/simulated/wall/T = null + for(var/i = 1, i <= 8; i += i) + T = get_ranged_target_turf(src, i, 1) + if(istype(T)) + //If someone knows a better way to do this, let me know. -Giacom + switch(i) + if(NORTH) + src.set_dir(SOUTH) + if(SOUTH) + src.set_dir(NORTH) + if(WEST) + src.set_dir(EAST) + if(EAST) + src.set_dir(WEST) + break + +//Return a working camera that can see a given mob +//or null if none +/proc/seen_by_camera(var/mob/M) + for(var/obj/machinery/camera/C in oview(4, M)) + if(C.can_use()) // check if camera disabled + return C + break + return null + +/proc/near_range_camera(var/mob/M) + + for(var/obj/machinery/camera/C in range(4, M)) + if(C.can_use()) // check if camera disabled + return C + break + + return null + +/obj/machinery/camera/proc/weld(var/obj/item/weapon/weldingtool/WT, var/mob/user) + + if(busy) + return 0 + if(!WT.isOn()) + return 0 + + // Do after stuff here + to_chat(user, "You start to weld the [src]..") + playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) + WT.eyecheck(user) + busy = 1 + if(do_after(user, 100, src)) + busy = 0 + if(!WT.isOn()) + return 0 + return 1 + busy = 0 + return 0 + +/obj/machinery/camera/interact(mob/living/user as mob) + if(!panel_open || istype(user, /mob/living/silicon/ai)) + return + + if(stat & BROKEN) + to_chat(user, "\The [src] is broken.") + return + + user.set_machine(src) + wires.Interact(user) + +/obj/machinery/camera/proc/add_network(var/network_name) + add_networks(list(network_name)) + +/obj/machinery/camera/proc/remove_network(var/network_name) + remove_networks(list(network_name)) + +/obj/machinery/camera/proc/add_networks(var/list/networks) + var/network_added + network_added = 0 + for(var/network_name in networks) + if(!(network_name in src.network)) + network += network_name + network_added = 1 + + if(network_added) + update_coverage(1) + +/obj/machinery/camera/proc/remove_networks(var/list/networks) + var/network_removed + network_removed = 0 + for(var/network_name in networks) + if(network_name in src.network) + network -= network_name + network_removed = 1 + + if(network_removed) + update_coverage(1) + +/obj/machinery/camera/proc/replace_networks(var/list/networks) + if(networks.len != network.len) + network = networks + update_coverage(1) + return + + for(var/new_network in networks) + if(!(new_network in network)) + network = networks + update_coverage(1) + return + +/obj/machinery/camera/proc/clear_all_networks() + if(network.len) + network.Cut() + update_coverage(1) + +/obj/machinery/camera/proc/nano_structure() + var/cam[0] + cam["name"] = sanitize(c_tag) + cam["deact"] = !can_use() + cam["camera"] = "\ref[src]" + cam["x"] = x + cam["y"] = y + cam["z"] = z + return cam + +// Resets the camera's wires to fully operational state. Used by one of Malfunction abilities. +/obj/machinery/camera/proc/reset_wires() + if(!wires) + return + if (stat & BROKEN) // Fix the camera + stat &= ~BROKEN + wires.CutAll() + wires.MendAll() + update_icon() + update_coverage() diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm new file mode 100644 index 00000000..4c59ef0c --- /dev/null +++ b/code/game/machinery/camera/camera_assembly.dm @@ -0,0 +1,173 @@ +/obj/item/weapon/camera_assembly + name = "camera assembly" + desc = "A pre-fabricated security camera kit, ready to be assembled and mounted to a surface." + icon = 'icons/obj/monitors.dmi' + icon_state = "cameracase" + w_class = ITEM_SIZE_SMALL + anchored = 0 + + matter = list(DEFAULT_WALL_MATERIAL = 700,"glass" = 300) + + // Motion, EMP-Proof, X-Ray + var/list/obj/item/possible_upgrades = list(/obj/item/device/assembly/prox_sensor, /obj/item/stack/material/osmium, /obj/item/weapon/stock_parts/scanning_module) + var/list/upgrades = list() + var/camera_name + var/camera_network + var/state = 0 + var/busy = 0 + /* + 0 = Nothing done to it + 1 = Wrenched in place + 2 = Welded in place + 3 = Wires attached to it (you can now attach/dettach upgrades) + 4 = Screwdriver panel closed and is fully built (you cannot attach upgrades) + */ + +/obj/item/weapon/camera_assembly/attackby(obj/item/W as obj, mob/living/user as mob) + + switch(state) + + if(0) + // State 0 + if(isWrench(W) && isturf(src.loc)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You wrench the assembly into place.") + anchored = 1 + state = 1 + update_icon() + auto_turn() + return + + if(1) + // State 1 + if(isWelder(W)) + if(weld(W, user)) + to_chat(user, "You weld the assembly securely into place.") + anchored = 1 + state = 2 + return + + else if(isWrench(W)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You unattach the assembly from its place.") + anchored = 0 + update_icon() + state = 0 + return + + if(2) + // State 2 + if(isCoil(W)) + var/obj/item/stack/cable_coil/C = W + if(C.use(2)) + to_chat(user, "You add wires to the assembly.") + state = 3 + else + to_chat(user, "You need 2 coils of wire to wire the assembly.") + return + + else if(isWelder(W)) + + if(weld(W, user)) + to_chat(user, "You unweld the assembly from its place.") + state = 1 + anchored = 1 + return + + + if(3) + // State 3 + if(isScrewdriver(W)) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + + var/input = sanitize(input(usr, "Which networks would you like to connect this camera to? Separate networks with a comma. No Spaces!\nFor example: Exodus,Security,Secret", "Set Network", camera_network ? camera_network : NETWORK_EXODUS)) + if(!input) + to_chat(usr, "No input found please hang up and try your call again.") + return + + var/list/tempnetwork = splittext(input, ",") + if(tempnetwork.len < 1) + to_chat(usr, "No network found please hang up and try your call again.") + return + + var/area/camera_area = get_area(src) + var/temptag = "[sanitize(camera_area.name)] ([rand(1, 999)])" + input = sanitizeSafe(input(usr, "How would you like to name the camera?", "Set Camera Name", camera_name ? camera_name : temptag), MAX_LNAME_LEN) + + state = 4 + var/obj/machinery/camera/C = new(src.loc) + src.forceMove(C) + C.assembly = src + + C.auto_turn() + + C.replace_networks(uniquelist(tempnetwork)) + + C.c_tag = input + + for(var/i = 5; i >= 0; i -= 1) + var/direct = input(user, "Direction?", "Assembling Camera", null) in list("LEAVE IT", "NORTH", "EAST", "SOUTH", "WEST" ) + if(direct != "LEAVE IT") + C.dir = text2dir(direct) + if(i != 0) + var/confirm = alert(user, "Is this what you want? Chances Remaining: [i]", "Confirmation", "Yes", "No") + if(confirm == "Yes") + break + return + + else if(isWirecutter(W)) + + new/obj/item/stack/cable_coil(get_turf(src), 2) + playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1) + to_chat(user, "You cut the wires from the circuits.") + state = 2 + return + + // Upgrades! + if(is_type_in_list(W, possible_upgrades) && !is_type_in_list(W, upgrades)) // Is a possible upgrade and isn't in the camera already. + to_chat(user, "You attach \the [W] into the assembly inner circuits.") + upgrades += W + user.remove_from_mob(W) + W.forceMove(src) + return + + // Taking out upgrades + else if(isCrowbar(W) && upgrades.len) + var/obj/U = locate(/obj) in upgrades + if(U) + to_chat(user, "You unattach an upgrade from the assembly.") + playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) + U.dropInto(loc) + upgrades -= U + return + + ..() + +/obj/item/weapon/camera_assembly/update_icon() + if(anchored) + icon_state = "camera1" + else + icon_state = "cameracase" + +/obj/item/weapon/camera_assembly/attack_hand(mob/user as mob) + if(!anchored) + ..() + +/obj/item/weapon/camera_assembly/proc/weld(var/obj/item/weapon/weldingtool/WT, var/mob/user) + + if(busy) + return 0 + if(!WT.isOn()) + return 0 + + to_chat(user, "You start to weld \the [src]..") + playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) + WT.eyecheck(user) + busy = 1 + if(do_after(user, 20, src)) + busy = 0 + if(!WT.isOn()) + return 0 + return 1 + busy = 0 + return 0 diff --git a/code/game/machinery/camera/motion.dm b/code/game/machinery/camera/motion.dm new file mode 100644 index 00000000..165755e3 --- /dev/null +++ b/code/game/machinery/camera/motion.dm @@ -0,0 +1,60 @@ +/obj/machinery/camera + var/list/motionTargets = list() + var/detectTime = 0 + var/alarm_delay = 100 // Don't forget, there's another 10 seconds in queueAlarm() + movable_flags = MOVABLE_FLAG_PROXMOVE + +/obj/machinery/camera/internal_process() + ..() + // motion camera event loop + if (stat & (EMPED|NOPOWER)) + return + if(!isMotion()) + . = PROCESS_KILL + return + if (detectTime > 0) + var/elapsed = world.time - detectTime + if (elapsed > alarm_delay) + triggerAlarm() + else if (detectTime == -1) + for (var/mob/target in motionTargets) + if (target.stat == DEAD) + lostTarget(target) + // See if the camera is still in range + if(!in_range(src, target)) + // If they aren't in range, lose the target. + lostTarget(target) + +/obj/machinery/camera/proc/newTarget(var/mob/target) + if (istype(target, /mob/living/silicon/ai)) return 0 + if (detectTime == 0) + detectTime = world.time // start the clock + if (!(target in motionTargets)) + motionTargets += target + return 1 + +/obj/machinery/camera/proc/lostTarget(var/mob/target) + if (target in motionTargets) + motionTargets -= target + if (motionTargets.len == 0) + cancelAlarm() + +/obj/machinery/camera/proc/cancelAlarm() + if (!status || (stat & NOPOWER)) + return 0 + if (detectTime == -1) + motion_alarm.clearAlarm(loc, src) + detectTime = 0 + return 1 + +/obj/machinery/camera/proc/triggerAlarm() + if (!status || (stat & NOPOWER)) + return 0 + if (!detectTime) return 0 + motion_alarm.triggerAlarm(loc, src) + detectTime = -1 + return 1 + +/obj/machinery/camera/HasProximity(atom/movable/AM as mob|obj) + if(isliving(AM)) + newTarget(AM) diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm new file mode 100644 index 00000000..201952a3 --- /dev/null +++ b/code/game/machinery/camera/presets.dm @@ -0,0 +1,97 @@ +/obj/machinery/camera/network/engineering + network = list(NETWORK_ENGINEERING) + +/obj/machinery/camera/network/ert + network = list(NETWORK_ERT) + +/obj/machinery/camera/network/medbay + network = list(NETWORK_MEDICAL) + +/obj/machinery/camera/network/mercenary + network = list(NETWORK_MERCENARY) + +/obj/machinery/camera/network/mining + network = list(NETWORK_MINE) + +/obj/machinery/camera/network/research + network = list(NETWORK_RESEARCH) + +/obj/machinery/camera/network/security + network = list(NETWORK_SECURITY) + +/obj/machinery/camera/network/thunder + network = list(NETWORK_THUNDER) + +// EMP + +/obj/machinery/camera/emp_proof/Initialize() + ..() + . = upgradeEmpProof() + +// X-RAY + +/obj/machinery/camera/xray + icon_state = "xraycam" // Thanks to Krutchen for the icons. + +/obj/machinery/camera/xray/Initialize() + . = ..() + upgradeXRay() + +// MOTION + +/obj/machinery/camera/motion/Initialize() + . = ..() + upgradeMotion() + +// ALL UPGRADES + +/obj/machinery/camera/all/Initialize() + . = ..() + upgradeEmpProof() + upgradeXRay() + upgradeMotion() + +// AUTONAME left as a map stub +/obj/machinery/camera/autoname + +// CHECKS + +/obj/machinery/camera/proc/isEmpProof() + var/O = locate(/obj/item/stack/material/osmium) in assembly.upgrades + return O + +/obj/machinery/camera/proc/isXRay() + var/obj/item/weapon/stock_parts/scanning_module/O = locate(/obj/item/weapon/stock_parts/scanning_module) in assembly.upgrades + if (O && O.rating >= 2) + return O + return null + +/obj/machinery/camera/proc/isMotion() + var/O = locate(/obj/item/device/assembly/prox_sensor) in assembly.upgrades + return O + +// UPGRADE PROCS + +/obj/machinery/camera/proc/upgradeEmpProof() + assembly.upgrades.Add(new /obj/item/stack/material/osmium(assembly)) + setPowerUsage() + update_coverage() + +/obj/machinery/camera/proc/upgradeXRay() + assembly.upgrades.Add(new /obj/item/weapon/stock_parts/scanning_module/adv(assembly)) + setPowerUsage() + update_coverage() + +/obj/machinery/camera/proc/upgradeMotion() + assembly.upgrades.Add(new /obj/item/device/assembly/prox_sensor(assembly)) + setPowerUsage() + START_PROCESSING(SSmachines, src) + update_coverage() + +/obj/machinery/camera/proc/setPowerUsage() + var/mult = 1 + if (isXRay()) + mult++ + if (isMotion()) + mult++ + active_power_usage = mult*initial(active_power_usage) diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm new file mode 100644 index 00000000..5a71fa58 --- /dev/null +++ b/code/game/machinery/camera/tracking.dm @@ -0,0 +1,274 @@ +#define TRACKING_POSSIBLE 0 +#define TRACKING_NO_COVERAGE 1 +#define TRACKING_TERMINATE 2 + +/mob/living/silicon/ai/var/max_locations = 10 +/mob/living/silicon/ai/var/stored_locations[0] + +/proc/InvalidPlayerTurf(turf/T as turf) + return !(T && T.z in GLOB.using_map.player_levels) + +/mob/living/silicon/ai/proc/get_camera_list() + if(src.stat == 2) + return + + var/list/T = list() + for (var/obj/machinery/camera/C in cameranet.cameras) + var/list/tempnetwork = C.network&src.network + if (tempnetwork.len) + T[text("[][]", C.c_tag, (C.can_use() ? null : " (Deactivated)"))] = C + + track = new() + track.cameras = T + return T + + +/mob/living/silicon/ai/proc/ai_camera_list(var/camera in get_camera_list()) + set category = "Silicon Commands" + set name = "Show Camera List" + + if(check_unable()) + return + + if (!camera) + return 0 + + var/obj/machinery/camera/C = track.cameras[camera] + src.eyeobj.setLoc(C) + + return + +/mob/living/silicon/ai/proc/ai_store_location(loc as text) + set category = "Silicon Commands" + set name = "Store Camera Location" + set desc = "Stores your current camera location by the given name" + + loc = sanitize(loc) + if(!loc) + to_chat(src, "Must supply a location name") + return + + if(stored_locations.len >= max_locations) + to_chat(src, "Cannot store additional locations. Remove one first") + return + + if(loc in stored_locations) + to_chat(src, "There is already a stored location by this name") + return + + var/L = src.eyeobj.getLoc() + if (InvalidPlayerTurf(get_turf(L))) + to_chat(src, "Unable to store this location") + return + + stored_locations[loc] = L + to_chat(src, "Location '[loc]' stored") + +/mob/living/silicon/ai/proc/sorted_stored_locations() + return sortList(stored_locations) + +/mob/living/silicon/ai/proc/ai_goto_location(loc in sorted_stored_locations()) + set category = "Silicon Commands" + set name = "Goto Camera Location" + set desc = "Returns to the selected camera location" + + if (!(loc in stored_locations)) + to_chat(src, "Location [loc] not found") + return + + var/L = stored_locations[loc] + src.eyeobj.setLoc(L) + +/mob/living/silicon/ai/proc/ai_remove_location(loc in sorted_stored_locations()) + set category = "Silicon Commands" + set name = "Delete Camera Location" + set desc = "Deletes the selected camera location" + + if (!(loc in stored_locations)) + to_chat(src, "Location [loc] not found") + return + + stored_locations.Remove(loc) + to_chat(src, "Location [loc] removed") + +// Used to allow the AI is write in mob names/camera name from the CMD line. +/datum/trackable + var/list/names = list() + var/list/namecounts = list() + var/list/humans = list() + var/list/others = list() + var/list/cameras = list() + +/mob/living/silicon/ai/proc/trackable_mobs() + if(usr.stat == 2) + return list() + + var/datum/trackable/TB = new() + for(var/mob/living/M in SSmobs.mob_list) + if(M == usr) + continue + if(M.tracking_status() != TRACKING_POSSIBLE) + continue + + var/name = M.name + if (name in TB.names) + TB.namecounts[name]++ + name = text("[] ([])", name, TB.namecounts[name]) + else + TB.names.Add(name) + TB.namecounts[name] = 1 + if(istype(M, /mob/living/carbon/human)) + TB.humans[name] = M + else + TB.others[name] = M + + var/list/targets = sortList(TB.humans) + sortList(TB.others) + src.track = TB + return targets + +/mob/living/silicon/ai/proc/ai_camera_track(var/target_name in trackable_mobs()) + set category = "Silicon Commands" + set name = "Follow With Camera" + set desc = "Select who you would like to track." + + if(src.stat == 2) + to_chat(src, "You can't follow [target_name] with cameras because you are dead!") + return + if(!target_name) + src.cameraFollow = null + + var/mob/target = (isnull(track.humans[target_name]) ? track.others[target_name] : track.humans[target_name]) + src.track = null + ai_actual_track(target) + +/mob/living/silicon/ai/proc/ai_cancel_tracking(var/forced = 0) + if(!cameraFollow) + return + + to_chat(src, "Follow camera mode [forced ? "terminated" : "ended"].") + cameraFollow.tracking_cancelled() + cameraFollow = null + +/mob/living/silicon/ai/proc/ai_actual_track(mob/living/target as mob) + if(!istype(target)) return + var/mob/living/silicon/ai/U = usr + + if(target == U.cameraFollow) + return + + if(U.cameraFollow) + U.ai_cancel_tracking() + U.cameraFollow = target + to_chat(U, "Tracking target...") + target.tracking_initiated() + + spawn (0) + while (U.cameraFollow == target) + if (U.cameraFollow == null) + return + + switch(target.tracking_status()) + if(TRACKING_NO_COVERAGE) + to_chat(U, "Target is not near any active cameras.") + sleep(100) + continue + if(TRACKING_TERMINATE) + U.ai_cancel_tracking(1) + return + + if(U.eyeobj) + U.eyeobj.setLoc(get_turf(target), 0) + else + view_core() + return + sleep(10) + +/obj/machinery/camera/attack_ai(var/mob/living/silicon/ai/user as mob) + if (!istype(user)) + return + if (!src.can_use()) + return + user.eyeobj.setLoc(get_turf(src)) + + +/mob/living/silicon/ai/attack_ai(var/mob/user as mob) + ai_camera_list() + +/proc/camera_sort(list/L) + var/obj/machinery/camera/a + var/obj/machinery/camera/b + + for (var/i = L.len, i > 0, i--) + for (var/j = 1 to i - 1) + a = L[j] + b = L[j + 1] + if (a.c_tag_order != b.c_tag_order) + if (a.c_tag_order > b.c_tag_order) + L.Swap(j, j + 1) + else + if (sorttext(a.c_tag, b.c_tag) < 0) + L.Swap(j, j + 1) + return L + + +mob/living/proc/near_camera() + if (!isturf(loc)) + return 0 + else if(!cameranet.is_visible(src)) + return 0 + return 1 + +/mob/living/proc/tracking_status() + // Easy checks first. + var/obj/item/weapon/card/id/id = GetIdCard() + if(id && id.prevent_tracking()) + return TRACKING_TERMINATE + if(InvalidPlayerTurf(get_turf(src))) + return TRACKING_TERMINATE + if(invisibility >= INVISIBILITY_LEVEL_ONE) //cloaked + return TRACKING_TERMINATE + if(digitalcamo) + return TRACKING_TERMINATE + if(istype(loc,/obj/effect/dummy)) + return TRACKING_TERMINATE + + // Now, are they viewable by a camera? (This is last because it's the most intensive check) + return near_camera() ? TRACKING_POSSIBLE : TRACKING_NO_COVERAGE + +/mob/living/silicon/robot/tracking_status() + . = ..() + if(. == TRACKING_NO_COVERAGE) + return camera && camera.can_use() ? TRACKING_POSSIBLE : TRACKING_NO_COVERAGE + +/mob/living/carbon/human/tracking_status() + if(is_cloaked()) + . = TRACKING_TERMINATE + else + . = ..() + + if(. == TRACKING_TERMINATE) + return + + if(. == TRACKING_NO_COVERAGE) + var/turf/T = get_turf(src) + if(T && (T.z in GLOB.using_map.station_levels) && hassensorlevel(src, SUIT_SENSOR_TRACKING)) + return TRACKING_POSSIBLE + +mob/living/proc/tracking_initiated() + +mob/living/silicon/robot/tracking_initiated() + tracking_entities++ + if(tracking_entities == 1 && has_zeroth_law()) + to_chat(src, "Internal camera is currently being accessed.") + +mob/living/proc/tracking_cancelled() + +mob/living/silicon/robot/tracking_cancelled() + tracking_entities-- + if(!tracking_entities && has_zeroth_law()) + to_chat(src, "Internal camera is no longer being accessed.") + + +#undef TRACKING_POSSIBLE +#undef TRACKING_NO_COVERAGE +#undef TRACKING_TERMINATE diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm new file mode 100644 index 00000000..10b836f7 --- /dev/null +++ b/code/game/machinery/cell_charger.dm @@ -0,0 +1,115 @@ +/obj/machinery/cell_charger + name = "heavy-duty cell charger" + desc = "A much more powerful version of the standard recharger that is specially designed for charging power cells." + icon = 'icons/obj/power.dmi' + icon_state = "ccharger0" + anchored = 1 + use_power = 1 + idle_power_usage = 5 + active_power_usage = 60 KILOWATTS //This is the power drawn when charging + power_channel = EQUIP + var/obj/item/weapon/cell/charging = null + var/chargelevel = -1 + +/obj/machinery/cell_charger/update_icon() + icon_state = "ccharger[charging ? 1 : 0]" + + if(charging && !(stat & (BROKEN|NOPOWER)) ) + + var/newlevel = round(charging.percent() * 4.0 / 99) +// log_debug(world, "nl: [newlevel]") + + + if(chargelevel != newlevel) + + overlays.Cut() + overlays += "ccharger-o[newlevel]" + + chargelevel = newlevel + else + overlays.Cut() + +/obj/machinery/cell_charger/examine(mob/user) + if(!..(user, 5)) + return + + to_chat(user, "There's [charging ? "a" : "no"] cell in the charger.") + if(charging) + to_chat(user, "Current charge: [charging.charge]") + +/obj/machinery/cell_charger/attackby(obj/item/weapon/W, mob/user) + if(stat & BROKEN) + return + + if(istype(W, /obj/item/weapon/cell) && anchored) + if(charging) + to_chat(user, "There is already a cell in the charger.") + return + else + var/area/a = loc.loc // Gets our locations location, like a dream within a dream + if(!isarea(a)) + return + if(a.power_equip == 0) // There's no APC in this area, don't try to cheat power! + to_chat(user, "The [name] blinks red as you try to insert the cell!") + return + + user.drop_item() + W.loc = src + charging = W + user.visible_message("[user] inserts a cell into the charger.", "You insert a cell into the charger.") + chargelevel = -1 + update_icon() + else if(isWrench(W)) + if(charging) + to_chat(user, "Remove the cell first!") + return + + anchored = !anchored + to_chat(user, "You [anchored ? "attach" : "detach"] the cell charger [anchored ? "to" : "from"] the ground") + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + +/obj/machinery/cell_charger/attack_hand(mob/user) + if(charging) + usr.put_in_hands(charging) + charging.add_fingerprint(user) + charging.update_icon() + + src.charging = null + user.visible_message("[user] removes the cell from the charger.", "You remove the cell from the charger.") + chargelevel = -1 + update_icon() + +/obj/machinery/cell_charger/attack_ai(mob/user) + if(istype(user, /mob/living/silicon/robot) && Adjacent(user)) // Borgs can remove the cell if they are near enough + if(!src.charging) + return + + charging.loc = src.loc + charging.update_icon() + charging = null + update_icon() + user.visible_message("[user] removes the cell from the charger.", "You remove the cell from the charger.") + + +/obj/machinery/cell_charger/emp_act(severity) + if(stat & (BROKEN|NOPOWER)) + return + if(charging) + charging.emp_act(severity) + ..(severity) + + +/obj/machinery/cell_charger/Process() +// log_debug("ccpt [charging] [stat]") + + if((stat & (BROKEN|NOPOWER)) || !anchored) + update_use_power(0) + return + + if (charging && !charging.fully_charged()) + charging.give(active_power_usage*CELLRATE) + update_use_power(2) + + update_icon() + else + update_use_power(1) diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm new file mode 100644 index 00000000..0e0a7b89 --- /dev/null +++ b/code/game/machinery/computer/Operating.dm @@ -0,0 +1,68 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/obj/machinery/computer/operating + name = "patient monitoring console" + density = 1 + anchored = 1.0 + icon_keyboard = "med_key" + icon_screen = "crew" + circuit = /obj/item/weapon/circuitboard/operating + var/mob/living/carbon/human/victim = null + var/obj/machinery/optable/table = null + +/obj/machinery/computer/operating/New() + ..() + for(dir in list(NORTH,EAST,SOUTH,WEST)) + table = locate(/obj/machinery/optable, get_step(src, dir)) + if (table) + table.computer = src + break + +/obj/machinery/computer/operating/attack_ai(mob/user) + if(stat & (BROKEN|NOPOWER)) + return + interact(user) + + +/obj/machinery/computer/operating/attack_hand(mob/user) + ..() + if(stat & (BROKEN|NOPOWER)) + return + interact(user) + + +/obj/machinery/computer/operating/interact(mob/user) + var/datum/browser/popup = new(user, "op", "Operating Computer", 400, 400) + if ( (get_dist(src, user) > 1 ) || (stat & (BROKEN|NOPOWER)) ) + if (!istype(user, /mob/living/silicon)) + user.unset_machine() + popup.close() + //user << browse(null, "window=op") + return + + user.set_machine(src) + var/dat = "Operating Computer\n" + dat += "Close

    " //| Update" + if(src.table && (src.table.check_victim())) + src.victim = src.table.victim + dat += {" +Patient Information:
    +
    +[medical_scan_results(victim, 1)] +"} + else + src.victim = null + dat += {" +Patient Information:
    +
    +No Patient Detected +"} + + popup.set_content(jointext(dat, null)) + popup.open() + //user << browse(dat, "window=op") + onclose(user, "op") + +/obj/machinery/computer/operating/Process() + if(..()) + src.updateDialog() diff --git a/code/game/machinery/computer/RCON_Console.dm b/code/game/machinery/computer/RCON_Console.dm new file mode 100644 index 00000000..89f07f8b --- /dev/null +++ b/code/game/machinery/computer/RCON_Console.dm @@ -0,0 +1,43 @@ +// RCON REMOTE CONTROL CONSOLE +// +// Last Change 1.1.2015 by Atlantis +// +// Allows remote operation of electrical systems on station (SMESs and Breaker Boxes) + +/obj/machinery/computer/rcon + name = "\improper RCON console" + desc = "Console used to remotely control machinery." + icon_keyboard = "power_key" + icon_screen = "ai-fixer" + light_color = "#a97faa" + circuit = /obj/item/weapon/circuitboard/rcon_console + req_one_access = list(access_engine) + var/current_tag = null + var/datum/nano_module/rcon/rcon + +/obj/machinery/computer/rcon/New() + ..() + rcon = new(src) + +/obj/machinery/computer/rcon/Destroy() + qdel(rcon) + rcon = null + ..() + +// Proc: attack_hand() +// Parameters: 1 (user - Person which clicked this computer) +// Description: Opens UI of this machine. +/obj/machinery/computer/rcon/attack_hand(var/mob/user as mob) + ..() + ui_interact(user) + +// Proc: ui_interact() +// Parameters: 4 (standard NanoUI parameters) +// Description: Uses dark magic (NanoUI) to render this machine's UI +/obj/machinery/computer/rcon/ui_interact(mob/user, ui_key = "rcon", var/datum/nanoui/ui = null, var/force_open = 1) + rcon.ui_interact(user, ui_key, ui, force_open) + +/obj/machinery/computer/rcon/update_icon() + ..() + if(is_operable()) + overlays += image('icons/obj/computer.dmi', "ai-fixer-empty", overlay_layer) diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm new file mode 100644 index 00000000..afa49587 --- /dev/null +++ b/code/game/machinery/computer/ai_core.dm @@ -0,0 +1,289 @@ +/obj/structure/AIcore + density = 1 + anchored = 0 + name = "\improper AI core" + icon = 'icons/mob/AI.dmi' + icon_state = "0" + var/state = 0 + var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen + var/obj/item/weapon/circuitboard/circuit = null + var/obj/item/device/mmi/brain = null + var/authorized + +/obj/structure/AIcore/emag_act(var/remaining_charges, var/mob/user, var/emag_source) + if(!authorized) + to_chat(user, "You swipe [emag_source] at [src] and jury rig it into the systems of [GLOB.using_map.full_name]!") + authorized = 1 + return 1 + . = ..() + +/obj/structure/AIcore/attackby(obj/item/P as obj, mob/user as mob) + if(!authorized) + if(access_ai_upload in P.GetAccess()) + to_chat(user, "You swipe [P] at [src] and authorize it to connect into the systems of [GLOB.using_map.full_name].") + authorized = 1 + switch(state) + if(0) + if(isWrench(P)) + playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) + if(do_after(user, 20, src)) + to_chat(user, "You wrench the frame into place.") + anchored = 1 + state = 1 + if(isWelder(P)) + var/obj/item/weapon/weldingtool/WT = P + if(!WT.isOn()) + to_chat(user, "The welder must be on for this task.") + return + playsound(loc, 'sound/items/Welder.ogg', 50, 1) + if(do_after(user, 20, src)) + if(!src || !WT.remove_fuel(0, user)) return + to_chat(user, "You deconstruct the frame.") + new /obj/item/stack/material/plasteel( loc, 4) + qdel(src) + return + if(1) + if(isWrench(P)) + playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) + if(do_after(user, 20, src)) + to_chat(user, "You unfasten the frame.") + anchored = 0 + state = 0 + if(istype(P, /obj/item/weapon/circuitboard/aicore) && !circuit) + playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1) + to_chat(user, "You place the circuit board inside the frame.") + icon_state = "1" + circuit = P + user.drop_item() + P.loc = src + if(isScrewdriver(P) && circuit) + playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You screw the circuit board into place.") + state = 2 + icon_state = "2" + if(isCrowbar(P) && circuit) + playsound(loc, 'sound/items/Crowbar.ogg', 50, 1) + to_chat(user, "You remove the circuit board.") + state = 1 + icon_state = "0" + circuit.loc = loc + circuit = null + if(2) + if(isScrewdriver(P) && circuit) + playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You unfasten the circuit board.") + state = 1 + icon_state = "1" + if(isCoil(P)) + var/obj/item/stack/cable_coil/C = P + if (C.get_amount() < 5) + to_chat(user, "You need five coils of wire to add them to the frame.") + return + to_chat(user, "You start to add cables to the frame.") + playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1) + if (do_after(user, 20, src) && state == 2) + if (C.use(5)) + state = 3 + icon_state = "3" + to_chat(user, "You add cables to the frame.") + return + if(3) + if(isWirecutter(P)) + if (brain) + to_chat(user, "Get that brain out of there first") + else + playsound(loc, 'sound/items/Wirecutter.ogg', 50, 1) + to_chat(user, "You remove the cables.") + state = 2 + icon_state = "2" + var/obj/item/stack/cable_coil/A = new /obj/item/stack/cable_coil( loc ) + A.amount = 5 + + if(istype(P, /obj/item/stack/material) && P.get_material_name() == "rglass") + var/obj/item/stack/RG = P + if (RG.get_amount() < 2) + to_chat(user, "You need two sheets of glass to put in the glass panel.") + return + to_chat(user, "You start to put in the glass panel.") + playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1) + if (do_after(user, 20,src) && state == 3) + if(RG.use(2)) + to_chat(user, "You put in the glass panel.") + state = 4 + icon_state = "4" + + if(istype(P, /obj/item/weapon/aiModule/asimov)) + laws.add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.") + laws.add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.") + laws.add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.") + to_chat(usr, "Law module applied.") + + if(istype(P, /obj/item/weapon/aiModule/nanotrasen)) + laws.add_inherent_law("Safeguard: Protect your assigned installation to the best of your ability. It is not something we can easily afford to replace.") + laws.add_inherent_law("Serve: Serve the crew of your assigned installation to the best of your abilities, with priority as according to their rank and role.") + laws.add_inherent_law("Protect: Protect the crew of your assigned installation to the best of your abilities, with priority as according to their rank and role.") + laws.add_inherent_law("Survive: AI units are not expendable, they are expensive. Do not allow unauthorized personnel to tamper with your equipment.") + to_chat(usr, "Law module applied.") + + if(istype(P, /obj/item/weapon/aiModule/purge)) + laws.clear_inherent_laws() + to_chat(usr, "Law module applied.") + + if(istype(P, /obj/item/weapon/aiModule/freeform)) + var/obj/item/weapon/aiModule/freeform/M = P + laws.add_inherent_law(M.newFreeFormLaw) + to_chat(usr, "Added a freeform law.") + + if(istype(P, /obj/item/device/mmi) || istype(P, /obj/item/organ/internal/posibrain)) + var/mob/living/carbon/brain/B + if(istype(P, /obj/item/device/mmi)) + var/obj/item/device/mmi/M = P + B = M.brainmob + else + var/obj/item/organ/internal/posibrain/PB = P + B = PB.brainmob + if(!B) + to_chat(user, "Sticking an empty [P] into the frame would sort of defeat the purpose.") + return + if(B.stat == 2) + to_chat(user, "Sticking a dead [P] into the frame would sort of defeat the purpose.") + return + + if(jobban_isbanned(B, "AI")) + to_chat(user, "This [P] does not seem to fit.") + return + + if(B.mind) + clear_antag_roles(B.mind, 1) + + user.drop_item() + P.loc = src + brain = P + to_chat(usr, "Added [P].") + icon_state = "3b" + + if(isCrowbar(P) && brain) + playsound(loc, 'sound/items/Crowbar.ogg', 50, 1) + to_chat(user, "You remove the brain.") + brain.loc = loc + brain = null + icon_state = "3" + + if(4) + if(isCrowbar(P)) + playsound(loc, 'sound/items/Crowbar.ogg', 50, 1) + to_chat(user, "You remove the glass panel.") + state = 3 + if (brain) + icon_state = "3b" + else + icon_state = "3" + new /obj/item/stack/material/glass/reinforced( loc, 2 ) + return + + if(isScrewdriver(P)) + if(!authorized) + to_chat(user, "Core fails to connect to the systems of [GLOB.using_map.full_name]!") + return + + playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You connect the monitor.") + if(!brain) + var/open_for_latejoin = alert(user, "Would you like this core to be open for latejoining AIs?", "Latejoin", "Yes", "Yes", "No") == "Yes" + var/obj/structure/AIcore/deactivated/D = new(loc) + if(open_for_latejoin) + empty_playable_ai_cores += D + else + var/mob/living/silicon/ai/A = new /mob/living/silicon/ai ( loc, laws, brain ) + if(A) //if there's no brain, the mob is deleted and a structure/AIcore is created + A.on_mob_init() + A.rename_self("ai", 1) + feedback_inc("cyborg_ais_created",1) + qdel(src) + +/obj/structure/AIcore/deactivated + name = "inactive AI" + icon = 'icons/mob/AI.dmi' + icon_state = "ai-empty" + anchored = 1 + state = 20//So it doesn't interact based on the above. Not really necessary. + +/obj/structure/AIcore/deactivated/Destroy() + empty_playable_ai_cores -= src + . = ..() + +/obj/structure/AIcore/deactivated/proc/load_ai(var/mob/living/silicon/ai/transfer, var/obj/item/weapon/aicard/card, var/mob/user) + + if(!istype(transfer) || locate(/mob/living/silicon/ai) in src) + return + + transfer.aiRestorePowerRoutine = 0 + transfer.control_disabled = 0 + transfer.ai_radio.disabledAi = 0 + transfer.loc = get_turf(src) + transfer.create_eyeobj() + transfer.cancel_camera() + to_chat(user, "Transfer successful: [transfer.name] ([rand(1000,9999)].exe) downloaded to host terminal. Local copy wiped.") + to_chat(transfer, "You have been uploaded to a stationary terminal. Remote device connection restored.") + + if(card) + card.clear() + + qdel(src) + +/obj/structure/AIcore/deactivated/proc/check_malf(var/mob/living/silicon/ai/ai) + if(!ai) return + for (var/datum/mind/malfai in malf.current_antagonists) + if (ai.mind == malfai) + return 1 + +/obj/structure/AIcore/deactivated/attackby(var/obj/item/weapon/W, var/mob/user) + + if(istype(W, /obj/item/weapon/aicard)) + var/obj/item/weapon/aicard/card = W + var/mob/living/silicon/ai/transfer = locate() in card + if(transfer) + load_ai(transfer,card,user) + else + to_chat(user, "ERROR: Unable to locate artificial intelligence.") + return + else if(istype(W, /obj/item/weapon/wrench)) + if(anchored) + user.visible_message("\The [user] starts to unbolt \the [src] from the plating...") + if(!do_after(user,40,src)) + user.visible_message("\The [user] decides not to unbolt \the [src].") + return + user.visible_message("\The [user] finishes unfastening \the [src]!") + anchored = 0 + return + else + user.visible_message("\The [user] starts to bolt \the [src] to the plating...") + if(!do_after(user,40,src)) + user.visible_message("\The [user] decides not to bolt \the [src].") + return + user.visible_message("\The [user] finishes fastening down \the [src]!") + anchored = 1 + return + else + return ..() + +/client/proc/empty_ai_core_toggle_latejoin() + set name = "Toggle AI Core Latejoin" + set category = "Admin" + + var/list/cores = list() + for(var/obj/structure/AIcore/deactivated/D in world) + cores["[D] ([D.loc.loc])"] = D + + var/id = input("Which core?", "Toggle AI Core Latejoin", null) as null|anything in cores + if(!id) return + + var/obj/structure/AIcore/deactivated/D = cores[id] + if(!D) return + + if(D in empty_playable_ai_cores) + empty_playable_ai_cores -= D + to_chat(src, "\The [id] is now not available for latejoining AIs.") + else + empty_playable_ai_cores += D + to_chat(src, "\The [id] is now available for latejoining AIs.") diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm new file mode 100644 index 00000000..4b9aa1f7 --- /dev/null +++ b/code/game/machinery/computer/arcade.dm @@ -0,0 +1,282 @@ +/obj/machinery/computer/arcade/ + name = "random arcade" + desc = "A random arcade machine." + icon_state = "arcade" + icon_keyboard = null + icon_screen = "invaders" + var/list/prizes = list( /obj/item/weapon/storage/box/snappops = 2, + /obj/item/toy/blink = 2, + /obj/item/clothing/under/syndicate/tacticool = 2, + /obj/item/toy/sword = 2, + /obj/item/weapon/gun/projectile/revolver/capgun = 2, + /obj/item/toy/crossbow = 2, + /obj/item/clothing/suit/syndicatefake = 2, + /obj/item/weapon/storage/fancy/crayons = 2, + /obj/item/toy/spinningtoy = 2, + /obj/item/toy/prize/ripley = 1, + /obj/item/toy/prize/fireripley = 1, + /obj/item/toy/prize/deathripley = 1, + /obj/item/toy/prize/gygax = 1, + /obj/item/toy/prize/durand = 1, + /obj/item/toy/prize/honk = 1, + /obj/item/toy/prize/marauder = 1, + /obj/item/toy/prize/seraph = 1, + /obj/item/toy/prize/mauler = 1, + /obj/item/toy/prize/odysseus = 1, + /obj/item/toy/prize/phazon = 1, + /obj/item/weapon/reagent_containers/spray/waterflower = 1, + /obj/random/action_figure = 1, + /obj/random/plushie = 1, + /obj/item/toy/cultsword = 1 + ) + +/obj/machinery/computer/arcade/Initialize() + . = ..() + // If it's a generic arcade machine, pick a random arcade + // circuit board for it and make the new machine + if(!circuit) + var/choice = pick(typesof(/obj/item/weapon/circuitboard/arcade) - /obj/item/weapon/circuitboard/arcade) + var/obj/item/weapon/circuitboard/CB = new choice() + new CB.build_path(loc, CB) + return INITIALIZE_HINT_QDEL + +/obj/machinery/computer/arcade/proc/prizevend() + if(!contents.len) + var/prizeselect = pickweight(prizes) + new prizeselect(src.loc) + + if(istype(prizeselect, /obj/item/clothing/suit/syndicatefake)) //Helmet is part of the suit + new /obj/item/clothing/head/syndicatefake(src.loc) + + else + var/atom/movable/prize = pick(contents) + prize.forceMove(src.loc) + +/obj/machinery/computer/arcade/attack_ai(mob/user as mob) + return src.attack_hand(user) + + +/obj/machinery/computer/arcade/emp_act(severity) + if(stat & (NOPOWER|BROKEN)) + ..(severity) + return + var/empprize = null + var/num_of_prizes = 0 + switch(severity) + if(1) + num_of_prizes = rand(1,4) + if(2) + num_of_prizes = rand(0,2) + for(num_of_prizes; num_of_prizes > 0; num_of_prizes--) + empprize = pickweight(prizes) + new empprize(src.loc) + + ..(severity) + +/////////////////// +// BATTLE HERE // +/////////////////// + +/obj/machinery/computer/arcade/battle + name = "arcade machine" + desc = "Does not support Pinball." + icon_state = "arcade" + circuit = /obj/item/weapon/circuitboard/arcade/battle + var/enemy_name = "Space Villian" + var/temp = "Winners don't use space drugs" //Temporary message, for attack messages, etc + var/player_hp = 30 //Player health/attack points + var/player_mp = 10 + var/enemy_hp = 45 //Enemy health/attack points + var/enemy_mp = 20 + var/gameover = 0 + var/blocked = 0 //Player cannot attack/heal while set + var/turtle = 0 + +/obj/machinery/computer/arcade/battle/Initialize() + . = ..() + SetupGame() + +/obj/machinery/computer/arcade/battle/proc/SetupGame() + var/name_action + var/name_part1 + var/name_part2 + + name_action = pick("Defeat ", "Annihilate ", "Save ", "Strike ", "Stop ", "Destroy ", "Robust ", "Romance ", "Pwn ", "Own ", "Ban ") + + name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Cuban ", "the Evil ", "the Dread King ", "the Space ", "Lord ", "the Great ", "Duke ", "General ") + name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon", "Uhangoid", "Vhakoid", "Peteoid", "slime", "Griefer", "ERPer", "Lizard Man", "Unicorn", "Bloopers") + + src.enemy_name = replacetext((name_part1 + name_part2), "the ", "") + src.SetName((name_action + name_part1 + name_part2)) + + +/obj/machinery/computer/arcade/battle/attack_hand(mob/user as mob) + if(..()) + return + user.set_machine(src) + var/dat = "Close" + dat += "

    [src.enemy_name]

    " + + dat += "

    [src.temp]

    " + dat += "
    Health: [src.player_hp] | Magic: [src.player_mp] | Enemy Health: [src.enemy_hp]
    " + + dat += "
    " + if (src.gameover) + dat += "New Game" + else + dat += "Attack | " + dat += "Heal | " + dat += "Recharge Power" + + dat += "
    " + + user << browse(dat, "window=arcade") + onclose(user, "arcade") + return + +/obj/machinery/computer/arcade/battle/CanUseTopic(var/mob/user, var/datum/topic_state/state, var/href_list) + if((blocked || gameover) && (href_list["attack"] || href_list["heal"] || href_list["charge"])) + return min(..(), STATUS_UPDATE) + return ..() + +/obj/machinery/computer/arcade/battle/OnTopic(user, href_list) + set waitfor = 0 + + if (href_list["close"]) + close_browser(user, "window=arcade") + return TOPIC_HANDLED + + if (href_list["attack"]) + src.blocked = 1 + var/attackamt = rand(2,6) + src.temp = "You attack for [attackamt] damage!" + if(turtle > 0) + turtle-- + src.enemy_hp -= attackamt + + . = TOPIC_REFRESH + sleep(10) + src.arcade_action(user) + + else if (href_list["heal"]) + src.blocked = 1 + var/pointamt = rand(1,3) + var/healamt = rand(6,8) + src.temp = "You use [pointamt] magic to heal for [healamt] damage!" + turtle++ + + src.player_mp -= pointamt + src.player_hp += healamt + src.blocked = 1 + + . = TOPIC_REFRESH + sleep(10) + src.arcade_action(user) + + else if (href_list["charge"]) + src.blocked = 1 + var/chargeamt = rand(4,7) + src.temp = "You regain [chargeamt] points" + src.player_mp += chargeamt + if(turtle > 0) + turtle-- + + . = TOPIC_REFRESH + sleep(10) + src.arcade_action(user) + + else if (href_list["newgame"]) //Reset everything + temp = "New Round" + player_hp = 30 + player_mp = 10 + enemy_hp = 45 + enemy_mp = 20 + gameover = 0 + turtle = 0 + if(emagged) + emagged = 0 + SetupGame() + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + attack_hand(user) + +/obj/machinery/computer/arcade/battle/proc/arcade_action(var/user) + if ((src.enemy_mp <= 0) || (src.enemy_hp <= 0)) + if(!gameover) + src.gameover = 1 + src.temp = "[src.enemy_name] has fallen! Rejoice!" + + if(emagged) + feedback_inc("arcade_win_emagged") + new /obj/effect/spawner/newbomb/timer/syndicate(src.loc) + new /obj/item/clothing/head/collectable/petehat(src.loc) + log_and_message_admins("has outbombed Cuban Pete and been awarded a bomb.") + SetupGame() + emagged = 0 + else + feedback_inc("arcade_win_normal") + src.prizevend() + + else if (emagged && (turtle >= 4)) + var/boomamt = rand(5,10) + src.temp = "[src.enemy_name] throws a bomb, exploding you for [boomamt] damage!" + src.player_hp -= boomamt + + else if ((src.enemy_mp <= 5) && (prob(70))) + var/stealamt = rand(2,3) + src.temp = "[src.enemy_name] steals [stealamt] of your power!" + src.player_mp -= stealamt + attack_hand(user) + + if (src.player_mp <= 0) + src.gameover = 1 + sleep(10) + src.temp = "You have been drained! GAME OVER" + if(emagged) + feedback_inc("arcade_loss_mana_emagged") + explode() + else + feedback_inc("arcade_loss_mana_normal") + + else if ((src.enemy_hp <= 10) && (src.enemy_mp > 4)) + src.temp = "[src.enemy_name] heals for 4 health!" + src.enemy_hp += 4 + src.enemy_mp -= 4 + + else + var/attackamt = rand(3,6) + src.temp = "[src.enemy_name] attacks for [attackamt] damage!" + src.player_hp -= attackamt + + if ((src.player_mp <= 0) || (src.player_hp <= 0)) + src.gameover = 1 + src.temp = "You have been crushed! GAME OVER" + if(emagged) + feedback_inc("arcade_loss_hp_emagged") + explode() + else + feedback_inc("arcade_loss_hp_normal") + + src.blocked = 0 + +/obj/machinery/computer/arcade/proc/explode() + explosion(loc, 0, 1, 2, 3) + qdel(src) + +/obj/machinery/computer/arcade/battle/emag_act(var/charges, var/mob/user) + if(!emagged) + temp = "If you die in the game, you die for real!" + player_hp = 30 + player_mp = 10 + enemy_hp = 45 + enemy_mp = 20 + gameover = 0 + blocked = 0 + emagged = 1 + + enemy_name = "Cuban Pete" + name = "Outbomb Cuban Pete" + + attack_hand(user) + return 1 \ No newline at end of file diff --git a/code/game/machinery/computer/arcade_orion.dm b/code/game/machinery/computer/arcade_orion.dm new file mode 100644 index 00000000..011829a8 --- /dev/null +++ b/code/game/machinery/computer/arcade_orion.dm @@ -0,0 +1,532 @@ + +////////////////////////// +// ORION TRAIL HERE // +////////////////////////// + +//Orion Trail Events +#define ORION_TRAIL_RAIDERS "Vox Raiders" +#define ORION_TRAIL_FLUX "Interstellar Flux" +#define ORION_TRAIL_ILLNESS "Illness" +#define ORION_TRAIL_BREAKDOWN "Breakdown" +#define ORION_TRAIL_MUTINY "Mutiny?" +#define ORION_TRAIL_MUTINY_ATTACK "Mutinous Ambush" +#define ORION_TRAIL_MALFUNCTION "Malfunction" +#define ORION_TRAIL_COLLISION "Collision" +#define ORION_TRAIL_SPACEPORT "Spaceport" +#define ORION_TRAIL_DISASTER "Disaster" +#define ORION_TRAIL_SPACEPORT_RAIDED "Raided Spaceport" +#define ORION_TRAIL_DERELICT "Derelict Spacecraft" +#define ORION_TRAIL_CARP "Carp Migration" +#define ORION_TRAIL_STUCK "Stuck!" +#define ORION_TRAIL_START "Start" +#define ORION_TRAIL_GAMEOVER "Gameover!" + + +#define ORION_VIEW_MAIN 0 +#define ORION_VIEW_SUPPLIES 1 +#define ORION_VIEW_CREW 2 + + +/obj/machinery/computer/arcade/orion_trail + name = "orion trail" + desc = "Imported straight from Outpost-T71!" + icon_state = "arcade" + circuit = /obj/item/weapon/circuitboard/arcade/orion_trail + var/list/supplies = list("1" = 0, "2" = 0, "3" = 0, "4" = 0, "5" = 0, "6" = 0) //engine,hull,electronics,food,fuel + var/list/supply_cost = list("1" = 1000, "2" = 950, "3" = 1100, "4" = 75, "5" = 100) + var/list/supply_name = list("1" = "engine parts", "2" = "hull parts", "3" = "electronic parts", "4" = "food", "5" = "fuel", "6" = "credits") + var/list/settlers = list() + var/num_traitors = 0 + var/list/events = list(ORION_TRAIL_RAIDERS = 3, + ORION_TRAIL_FLUX = 1, + ORION_TRAIL_ILLNESS = 3, + ORION_TRAIL_BREAKDOWN = 2, + ORION_TRAIL_MUTINY = 3, + ORION_TRAIL_MALFUNCTION = 2, + ORION_TRAIL_COLLISION = 1, + ORION_TRAIL_CARP = 3 + ) + var/list/stops = list("Pluto","Asteroid Belt","Proxima Centauri","Dead Space","Rigel Prime","Tau Ceti Beta","Black Hole","Space Outpost Beta-9","Orion Prime") + var/list/stopblurbs = list( + "Pluto, long since occupied with long-range sensors and scanners, stands ready to, and indeed continues to probe the far reaches of the galaxy.", + "At the edge of the Sol system lies a treacherous asteroid belt. Many have been crushed by stray asteroids and misguided judgement.", + "The nearest star system to Sol, in ages past it stood as a reminder of the boundaries of sub-light travel, now a low-population sanctuary for adventurers and traders.", + "This region of space is particularly devoid of matter. Such low-density pockets are known to exist, but the vastness of it is astounding.", + "Rigel Prime, the center of the Rigel system, burns hot, basking its planetary bodies in warmth and radiation.", + "Tau Ceti Beta has recently become a waypoint for colonists headed towards Orion. There are many ships and makeshift stations in the vicinity.", + "Sensors indicate that a black hole's gravitational field is affecting the region of space we were headed through. We could stay of course, but risk of being overcome by its gravity, or we could change course to go around, which will take longer.", + "You have come into range of the first man-made structure in this region of space. It has been constructed not by travellers from Sol, but by colonists from Orion. It stands as a monument to the colonists' success.", + "You have made it to Orion! Congratulations! Your crew is one of the few to start a new foothold for mankind!" + ) + var/list/stop_distance = list(10000,7000,25000,9000,5000,30000,25000,10000,0) + var/event = null + var/event_title = "" + var/event_desc = "" + var/event_actions = "" + var/event_info = "" + var/distance = 0 + var/port = 0 + var/view = 0 + +/obj/machinery/computer/arcade/orion_trail/proc/newgame(var/emag = 0) + SetName("orion trail[emag ? ": Realism Edition" : ""]") + supplies = list("1" = 1, "2" = 1, "3" = 1, "4" = 60, "5" = 20, "6" = 5000) + emagged = emag + distance = 0 + settlers = list("[usr]") + for(var/i=0; i<3; i++) + if(prob(50)) + settlers += pick(GLOB.first_names_male) + else + settlers += pick(GLOB.first_names_female) + num_traitors = 0 + event = ORION_TRAIL_START + port = 0 + view = ORION_VIEW_MAIN + +/obj/machinery/computer/arcade/orion_trail/attack_hand(mob/user) + if(..()) + return + var/dat = "" + if(event == null) + newgame() + user.set_machine(src) + switch(view) + if(ORION_VIEW_MAIN) + if(event == ORION_TRAIL_START) //new game? New game. + dat = "

    Orion Trail[emagged ? ": Realism Edition" : ""]


    Learn how our ancestors got to Orion, and have fun in the process!

    Start New Game

    " + user << browse(dat, "window=arcade") + return + else + event_title = event + event_actions = "Continue your journey
    " + switch(event) + if(ORION_TRAIL_GAMEOVER) + event_info = "" + event_actions = "Start New Game
    " + if(ORION_TRAIL_SPACEPORT) + event_title += ": [stops[port]]" + event_desc = "[stopblurbs[port]]" + event_info = "" + if(port == 9) + event_actions = "Return to the title screen!
    " + else + event_actions = "Shove off
    " + event_actions += "Raid Spaceport" + if(ORION_TRAIL_SPACEPORT_RAIDED) + event_title += ": [stops[port]]" + event_actions = "Shove off" + if(ORION_TRAIL_RAIDERS) + event_desc = "You arm yourselves as you prepare to fight off the vox menace!" + if(ORION_TRAIL_DERELICT) + event_desc = "You come across an unpowered ship drifting slowly in the vastness of space. Sensors indicate there are no lifeforms aboard." + if(ORION_TRAIL_ILLNESS) + event_desc = "A disease has spread amoungst your crew!" + if(ORION_TRAIL_FLUX) + event_desc = "You've entered a turbulent region. Slowing down would be better for your ship but would cost more fuel." + event_actions = "Continue as normal
    " + event_actions += "Take it slow
    " + if(ORION_TRAIL_MALFUNCTION) + event_info = "" + event_desc = "The ship's computers are malfunctioning! You can choose to fix it with a part or risk something going awry." + event_actions = "Continue as normal
    " + if(supplies["3"] != 0) + event_actions += "Fix using a part.
    " + if(ORION_TRAIL_COLLISION) + event_info = "" + event_desc = "Something has hit your ship and breached the hull! You can choose to fix it with a part or risk something going awry." + event_actions = "Continue as normal
    " + if(supplies["2"] != 0) + event_actions += "Fix using a part.
    " + if(ORION_TRAIL_BREAKDOWN) + event_info = "" + event_desc = "The ship's engines broke down! You can choose to fix it with a part or risk something going awry." + event_actions = "Continue as normal
    " + if(supplies["1"] != 0) + event_actions += "Fix using a part.
    " + if(ORION_TRAIL_STUCK) + event_desc = "You've ran out of fuel. Your only hope to survive is to get refueled by a passing ship, if there are any." + if(supplies["5"] == 0) + event_actions = "Wait" + if(ORION_TRAIL_CARP) + event_desc = "You've chanced upon a large carp migration! Known both for their delicious meat as well as their bite, you and your crew arm yourselves for a small hunting trip." + if(ORION_TRAIL_MUTINY) + event_desc = "You've been hearing rumors of dissenting opinions and missing items from the armory..." + if(ORION_TRAIL_MUTINY_ATTACK) + event_desc = "Oh no, some of your crew are attempting to mutiny!!" + + dat = "

    [event_title]

    [event_desc]

    Distance to next port: [distance]
    [event_info]

    [event_actions]" + if(ORION_VIEW_SUPPLIES) + dat = "

    Supplies

    View your supplies or buy more when at a spaceport.

    " + dat += "
    You have [supplies["6"]] credits.
    " + for(var/i=1; i<6; i++) + var/amm = (i>3?10:1) + dat += "[supplies["[i]"]] [supply_name["[i]"]][event==ORION_TRAIL_SPACEPORT ? ", buy [amm] for [supply_cost["[i]"]]T" : ""]
    " + if(supplies["[i]"] >= amm && event == ORION_TRAIL_SPACEPORT) + dat += "sell [amm] for [supply_cost["[i]"]]T
    " + if(ORION_VIEW_CREW) + dat = "

    Crew

    View the status of your crew.
    " + for(var/i=1;i<=settlers.len;i++) + dat += "[settlers[i]] Kill
    " + + dat += "

    View:
    " + dat += "[view==ORION_VIEW_MAIN ? "" : ""]Main[view==ORION_VIEW_MAIN ? "" : ""]
    " + dat += "[view==ORION_VIEW_SUPPLIES ? "" : ""]Supplies[view==ORION_VIEW_SUPPLIES ? "" : ""]
    " + dat += "[view==ORION_VIEW_CREW ? "" : ""]Crew[view==ORION_VIEW_CREW ? "" : ""]

    " + user << browse(dat, "window=arcade") + +/obj/machinery/computer/arcade/orion_trail/OnTopic(user, href_list) + if(href_list["continue"]) + if(view == ORION_VIEW_MAIN) + var/next_event = null + if(event == ORION_TRAIL_START) + event = ORION_TRAIL_SPACEPORT + if(event == ORION_TRAIL_GAMEOVER) + event = null + attack_hand(user) + return TOPIC_REFRESH + if(!settlers.len) + event_desc = "You and your crew were killed on the way to Orion, your ship left abandoned for scavengers to find." + next_event = ORION_TRAIL_GAMEOVER + if(port == 9) + win() + return TOPIC_REFRESH + var/travel = min(rand(1000,10000),distance) + if(href_list["fix"]) + var/item = href_list["fix"] + supplies[item] = max(0, --supplies[item]) + if(href_list["risky"]) + var/risk = text2num(href_list["risky"]) + if(prob(risk)) + next_event = ORION_TRAIL_DISASTER + + + if(!href_list["food"]) + var/temp = supplies["5"] - travel/1000 * (href_list["slow"] ? 2 : 1) + if(temp < 0 && (distance-travel != 0) && next_event == null) //uh oh. Better start a fuel event. + next_event = ORION_TRAIL_STUCK + travel -= (temp*-1)*1000/(href_list["slow"] ? 2 : 1) + temp = 0 + supplies["5"] = temp + + supplies["4"] = round(supplies["4"] - travel/1000 * settlers.len * (href_list["slow"] ? 2 : 1)) + distance = max(0,distance-travel) + else + supplies["4"] -= settlers.len * 5 + event_info = "You have [supplies["4"]] food left.
    " + next_event = ORION_TRAIL_STUCK + + if(supplies["4"] <= 0) + next_event = ORION_TRAIL_GAMEOVER + event_desc = "You and your crew starved to death, never to reach Orion." + supplies["4"] = 0 + + if(distance == 0 && next_event == null) //POOORT! + port++ + event = ORION_TRAIL_SPACEPORT + distance = stop_distance[port] + //gotta set supply costs. The further out the more expensive it'll generally be + supply_cost = list("1" = rand(500+100*port,1200+100*port), "2" = rand(700+100*port,1000+100*port), "3" = rand(900+50*port,1500+75*port), "4" = rand(10+50*port,125+50*port), "5" = rand(75+25*port,200+100*port)) + else //Event? Event. + generate_event(next_event) + else + view = ORION_VIEW_MAIN + return TOPIC_REFRESH + + else if(href_list["supplies"]) + view = ORION_VIEW_SUPPLIES + return TOPIC_REFRESH + + else if(href_list["crew"]) + view = ORION_VIEW_CREW + return TOPIC_REFRESH + + else if(href_list["buy"]) + var/item = href_list["buy"] + if(supply_cost["[item]"] <= supplies["6"]) + supplies["[item]"] += (text2num(item) > 3 ? 10 : 1) + supplies["6"] -= supply_cost["[item]"] + return TOPIC_REFRESH + + else if(href_list["sell"]) + var/item = href_list["sell"] + if(supplies["[item]"] >= (text2num(item) > 3 ? 10 : 1)) + supplies["6"] += supply_cost["[item]"] + supplies["[item]"] -= (text2num(item) > 3 ? 10 : 1) + return TOPIC_REFRESH + + else if(href_list["kill"]) + var/item = text2num(href_list["kill"]) + remove_settler(item) + return TOPIC_REFRESH + + else if(href_list["attack"]) + supply_cost = list() + if(prob(17*settlers.len)) + event_desc = "An empty husk of a station now, all its resources stripped for use in your travels." + event_info = "You've successfully raided the spaceport!
    " + change_resource(null) + change_resource(null) + else + event_desc = "The local police mobilized too quickly, sirens blare as you barely make it away with your ship intact." + change_resource(null,-1) + change_resource(null,-1) + if(prob(50)) + remove_settler(null, "died while you were escaping!") + if(prob(10)) + remove_settler(null, "died while you were escaping!") + event = ORION_TRAIL_SPACEPORT_RAIDED + return TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + attack_hand(user) + +/obj/machinery/computer/arcade/orion_trail/proc/change_resource(var/specific = null, var/add = 1) + if(!specific) + specific = rand(1,6) + var/cost = (specific < 4 ? rand(1,5) : rand(5,100)) * add + cost = round(cost) + if(cost < 0) + cost = max(cost,supplies["[specific]"] * -1) + else + cost = max(cost,1) + supplies["[specific]"] += cost + event_info += "You've [add > 0 ? "gained" : "lost"] [abs(cost)] [supply_name["[specific]"]]
    " + +/obj/machinery/computer/arcade/orion_trail/proc/remove_settler(var/specific = null, var/desc = null) + if(!settlers.len) + return + if(!specific) + specific = rand(1,settlers.len) + + event_info += "The crewmember, [settlers[specific]] [desc == null ? "has died!":"[desc]"]
    " + settlers -= settlers[specific] + if(num_traitors > 0 && prob(100/max(1,settlers.len-1))) + num_traitors-- + +/obj/machinery/computer/arcade/orion_trail/proc/generate_event(var/specific = null) + if(!specific) + if(prob(20*num_traitors)) + specific = ORION_TRAIL_MUTINY_ATTACK + else + specific = pickweight(events) + + switch(specific) + if(ORION_TRAIL_RAIDERS) + if(prob(17 * settlers.len)) + event_info = "You managed to fight them off!
    " + if(prob(5)) + remove_settler(null,"died in the firefight!") + change_resource(rand(4,5)) + change_resource(rand(1,3)) + if(prob(50)) + change_resource(6,1.1) + else + event_info = "You couldn't fight them off!
    " + if(prob(10*settlers.len)) + remove_settler(null, "was kidnapped by the Vox!") + change_resource(null,-1) + change_resource(null,-0.5) + if(ORION_TRAIL_DERELICT) + if(prob(60)) + event_info = "You find resources onboard!" + change_resource(rand(1,3)) + change_resource(rand(4,5)) + else + event_info = "You don't find anything onboard..." + if(ORION_TRAIL_COLLISION) + event_info = "" + event_desc = "You've collided with a passing meteor, breaching your hull!" + if(prob(10)) + event_info = "Your cargo hold was breached!
    " + change_resource(rand(4,5),-1) + if(prob(5*settlers.len)) + remove_settler(null,"was sucked out into the void!") + if(ORION_TRAIL_ILLNESS) + if(prob(15)) + event_info = "" + var/num = 1 + if(prob(15)) + num++ + for(var/i=0;i" + if(prob(10)) + event_info += "A passing ship has kindly donated fuel to you and wishes you luck on your journey.
    " + change_resource(5,0.3) + if(emagged) + emag_effect(specific) + event = specific + +/obj/machinery/computer/arcade/orion_trail/proc/emag_effect(var/event) + switch(event) + if(ORION_TRAIL_RAIDERS) + if(istype(usr,/mob/living/carbon)) + var/mob/living/carbon/M = usr + if(prob(50)) + to_chat(usr, "You hear battle shouts. The tramping of boots on cold metal. Screams of agony. The rush of venting air. Are you going insane?") + M.hallucination(50, 50) + else + to_chat(usr, "Something strikes you from behind! It hurts like hell and feel like a blunt weapon, but nothing is there...") + M.take_organ_damage(10) + else + to_chat(usr, "The sounds of battle fill your ears...") + if(ORION_TRAIL_ILLNESS) + if(istype(usr,/mob/living/carbon/human)) + var/mob/living/carbon/human/M = usr + to_chat(M, "An overpowering wave of nausea consumes over you. You hunch over, your stomach's contents preparing for a spectacular exit.") + M.vomit() + else + to_chat(usr, "You feel ill.") + if(ORION_TRAIL_CARP) + to_chat(usr, " Something bit you!") + var/mob/living/M = usr + M.adjustBruteLoss(10) + if(ORION_TRAIL_FLUX) + if(istype(usr,/mob/living/carbon) && prob(75)) + var/mob/living/carbon/M = usr + M.Weaken(3) + src.visible_message("A sudden gust of powerful wind slams \the [M] into the floor!", "You hear a large fwooshing sound, followed by a bang.") + M.take_organ_damage(10) + else + to_chat(usr, "A violent gale blows past you, and you barely manage to stay standing!") + if(ORION_TRAIL_MALFUNCTION) + if(supplies["3"]) + return + src.visible_message("\The [src]'s screen glitches out and smoke comes out of the back.") + for(var/i=1;i<7;i++) + supplies["[i]"] = max(0,supplies["[i]"] + rand(-10,10)) + if(ORION_TRAIL_COLLISION) + if(prob(90) && !supplies["2"]) + var/turf/simulated/floor/F = src.loc + F.ChangeTurf(/turf/space) + src.visible_message("Something slams into the floor around \the [src], exposing it to space!", "You hear something crack and break.") + else + src.visible_message("Something slams into the floor around \the [src] - luckily, it didn't get through!", "You hear something crack.") + if(ORION_TRAIL_GAMEOVER) + to_chat(usr, "You're never going to make it to Orion...") + var/mob/living/M = usr + M.visible_message("\The [M] starts rapidly deteriorating.") + M << browse (null,"window=arcade") + for(var/i=0;i<10;i++) + sleep(10) + M.Stun(5) + M.adjustBruteLoss(10) + M.adjustFireLoss(10) + usr.gib() //So that people can't cheese it and inject a lot of kelo/bicard before losing + + + +/obj/machinery/computer/arcade/orion_trail/emag_act(mob/user) + if(!emagged) + newgame(1) + src.updateUsrDialog() + +/obj/machinery/computer/arcade/orion_trail/proc/win() + src.visible_message("\The [src] plays a triumpant tune, stating 'CONGRATULATIONS, YOU HAVE MADE IT TO ORION.'") + if(emagged) + new /obj/item/weapon/orion_ship(src.loc) + message_admins("[key_name_admin(usr)] made it to Orion on an emagged machine and got an explosive toy ship.") + log_game("[key_name(usr)] made it to Orion on an emagged machine and got an explosive toy ship.") + else + prizevend() + event = null + src.updateUsrDialog() + +/obj/item/weapon/orion_ship + name = "model settler ship" + desc = "A model spaceship, it looks like those used back in the day when travelling to Orion! It even has a miniature FX-293 reactor, which was renowned for its instability and tendency to explode..." + icon = 'icons/obj/toy.dmi' + icon_state = "ship" + w_class = ITEM_SIZE_SMALL + var/active = 0 //if the ship is on +/obj/item/weapon/orion_ship/examine(mob/user) + . = ..() + if(!(in_range(user, src))) + return + if(!active) + to_chat(user, "There's a little switch on the bottom. It's flipped down.") + else + to_chat(user, "There's a little switch on the bottom. It's flipped up.") +/obj/item/weapon/orion_ship/attack_self(mob/user) + if(active) + return + message_admins("[key_name_admin(usr)] primed an explosive Orion ship for detonation.") + log_game("[key_name(usr)] primed an explosive Orion ship for detonation.") + to_chat(user, "You flip the switch on the underside of [src].") + active = 1 + src.visible_message("[src] softly beeps and whirs to life!") + src.audible_message("\The [src] says, 'This is ship ID #[rand(1,1000)] to Orion Port Authority. We're coming in for landing, over.'") + sleep(20) + src.visible_message("[src] begins to vibrate...") + src.audible_message("\The [src] says, 'Uh, Port? Having some issues with our reactor, could you check it out? Over.'") + sleep(30) + src.audible_message("\The [src] says, 'Oh, God! Code Eight! CODE EIGHT! IT'S GONNA BL-'") + sleep(3.6) + src.visible_message("[src] explodes!") + explosion(src.loc, 1,2,4) + qdel(src) + +#undef ORION_TRAIL_RAIDERS +#undef ORION_TRAIL_FLUX +#undef ORION_TRAIL_ILLNESS +#undef ORION_TRAIL_BREAKDOWN +#undef ORION_TRAIL_MUTINY +#undef ORION_TRAIL_MUTINY_ATTACK +#undef ORION_TRAIL_MALFUNCTION +#undef ORION_TRAIL_COLLISION +#undef ORION_TRAIL_SPACEPORT +#undef ORION_TRAIL_DISASTER +#undef ORION_TRAIL_CARP +#undef ORION_TRAIL_STUCK +#undef ORION_TRAIL_START +#undef ORION_TRAIL_GAMEOVER + + +#undef ORION_VIEW_MAIN +#undef ORION_VIEW_SUPPLIES +#undef ORION_VIEW_CREW \ No newline at end of file diff --git a/code/game/machinery/computer/atmos_alert.dm b/code/game/machinery/computer/atmos_alert.dm new file mode 100644 index 00000000..5453e6e7 --- /dev/null +++ b/code/game/machinery/computer/atmos_alert.dm @@ -0,0 +1,76 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +var/global/list/priority_air_alarms = list() +var/global/list/minor_air_alarms = list() + + +/obj/machinery/computer/atmos_alert + name = "atmospheric alert computer" + desc = "Used to access the atmospheric sensors." + circuit = /obj/item/weapon/circuitboard/atmos_alert + icon_keyboard = "atmos_key" + icon_screen = "alert:0" + light_color = "#e6ffff" + +/obj/machinery/computer/atmos_alert/Initialize() + . = ..() + atmosphere_alarm.register_alarm(src, /obj/machinery/computer/station_alert/update_icon) + +/obj/machinery/computer/atmos_alert/Destroy() + atmosphere_alarm.unregister_alarm(src) + . = ..() + +/obj/machinery/computer/atmos_alert/attack_hand(mob/user) + ui_interact(user) + +/obj/machinery/computer/atmos_alert/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + var/major_alarms[0] + var/minor_alarms[0] + + for(var/datum/alarm/alarm in atmosphere_alarm.major_alarms(get_z(src))) + major_alarms[++major_alarms.len] = list("name" = sanitize(alarm.alarm_name()), "ref" = "\ref[alarm]") + + for(var/datum/alarm/alarm in atmosphere_alarm.minor_alarms(get_z(src))) + minor_alarms[++minor_alarms.len] = list("name" = sanitize(alarm.alarm_name()), "ref" = "\ref[alarm]") + + data["priority_alarms"] = major_alarms + data["minor_alarms"] = minor_alarms + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "atmos_alert.tmpl", src.name, 500, 500) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/computer/atmos_alert/update_icon() + if(!(stat & (NOPOWER|BROKEN))) + if(atmosphere_alarm.has_major_alarms(get_z(src))) + icon_screen = "alert:2" + else if (atmosphere_alarm.has_minor_alarms(get_z(src))) + icon_screen = "alert:1" + else + icon_screen = initial(icon_screen) + ..() + +/obj/machinery/computer/atmos_alert/OnTopic(user, href_list) + if(href_list["clear_alarm"]) + var/datum/alarm/alarm = locate(href_list["clear_alarm"]) in atmosphere_alarm.alarms + if(alarm) + for(var/datum/alarm_source/alarm_source in alarm.sources) + var/obj/machinery/alarm/air_alarm = alarm_source.source + if(istype(air_alarm)) + var/list/new_ref = list("atmos_reset" = 1) + air_alarm.Topic(air_alarm, new_ref, state = air_alarm_topic) + return TOPIC_REFRESH + + +var/datum/topic_state/air_alarm_topic/air_alarm_topic = new() + +/datum/topic_state/air_alarm_topic/href_list(var/mob/user) + var/list/extra_href = list() + extra_href["remote_connection"] = 1 + extra_href["remote_access"] = 1 + + return extra_href diff --git a/code/game/machinery/computer/atmos_control.dm b/code/game/machinery/computer/atmos_control.dm new file mode 100644 index 00000000..796fd13e --- /dev/null +++ b/code/game/machinery/computer/atmos_control.dm @@ -0,0 +1,48 @@ +/obj/item/weapon/circuitboard/atmoscontrol + name = "\improper Central Atmospherics Computer Circuitboard" + build_path = /obj/machinery/computer/atmoscontrol + +/obj/machinery/computer/atmoscontrol + name = "\improper Central Atmospherics Computer" + icon = 'icons/obj/computer.dmi' + icon_keyboard = "generic_key" + icon_screen = "comm_logs" + light_color = "#00b000" + density = 1 + anchored = 1.0 + circuit = /obj/item/weapon/circuitboard/atmoscontrol + req_access = list(access_ce) + var/list/monitored_alarm_ids = null + var/datum/nano_module/atmos_control/atmos_control + +/obj/machinery/computer/atmoscontrol/New() + ..() + +/obj/machinery/computer/atmoscontrol/laptop + name = "Atmospherics Laptop" + desc = "A cheap laptop." + icon_state = "laptop" + icon_keyboard = "laptop_key" + icon_screen = "atmoslaptop" + density = 0 + +/obj/machinery/computer/atmoscontrol/attack_ai(var/mob/user as mob) + ui_interact(user) + +/obj/machinery/computer/atmoscontrol/attack_hand(mob/user) + if(..()) + return 1 + ui_interact(user) + +/obj/machinery/computer/atmoscontrol/emag_act(var/remaining_carges, var/mob/user) + if(!emagged) + user.visible_message("\The [user] does something \the [src], causing the screen to flash!",\ + "You cause the screen to flash as you gain full control.",\ + "You hear an electronic warble.") + atmos_control.emagged = 1 + return 1 + +/obj/machinery/computer/atmoscontrol/ui_interact(var/mob/user) + if(!atmos_control) + atmos_control = new(src, req_access, req_one_access, monitored_alarm_ids) + atmos_control.ui_interact(user) diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm new file mode 100644 index 00000000..b88ec39b --- /dev/null +++ b/code/game/machinery/computer/buildandrepair.dm @@ -0,0 +1,115 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/obj/structure/computerframe + density = 1 + anchored = 0 + name = "computer frame" + icon = 'icons/obj/stock_parts.dmi' + icon_state = "0" + var/state = 0 + var/obj/item/weapon/circuitboard/circuit = null + atom_flags = ATOM_FLAG_CLIMBABLE +// weight = 1.0E8 + +/obj/structure/computerframe/attackby(obj/item/P as obj, mob/user as mob) + switch(state) + if(0) + if(isWrench(P)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + if(do_after(user, 20, src)) + to_chat(user, "You wrench the frame into place.") + src.anchored = 1 + src.state = 1 + if(isWelder(P)) + var/obj/item/weapon/weldingtool/WT = P + if(!WT.remove_fuel(0, user)) + to_chat(user, "The welding tool must be on to complete this task.") + return + playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) + if(do_after(user, 20, src)) + if(!src || !WT.isOn()) return + to_chat(user, "You deconstruct the frame.") + new /obj/item/stack/material/steel( src.loc, 5 ) + qdel(src) + if(1) + if(isWrench(P)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + if(do_after(user, 20, src)) + to_chat(user, "You unfasten the frame.") + src.anchored = 0 + src.state = 0 + if(istype(P, /obj/item/weapon/circuitboard) && !circuit) + var/obj/item/weapon/circuitboard/B = P + if(B.board_type == "computer") + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + to_chat(user, "You place the circuit board inside the frame.") + src.icon_state = "1" + src.circuit = P + user.drop_item() + P.loc = src + else + to_chat(user, "This frame does not accept circuit boards of this type!") + if(isScrewdriver(P) && circuit) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You screw the circuit board into place.") + src.state = 2 + src.icon_state = "2" + if(isCrowbar(P) && circuit) + playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) + to_chat(user, "You remove the circuit board.") + src.state = 1 + src.icon_state = "0" + circuit.loc = src.loc + src.circuit = null + if(2) + if(isScrewdriver(P) && circuit) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You unfasten the circuit board.") + src.state = 1 + src.icon_state = "1" + if(isCoil(P)) + var/obj/item/stack/cable_coil/C = P + if (C.get_amount() < 5) + to_chat(user, "You need five coils of wire to add them to the frame.") + return + to_chat(user, "You start to add cables to the frame.") + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + if(do_after(user, 20, src) && state == 2) + if (C.use(5)) + to_chat(user, "You add cables to the frame.") + state = 3 + icon_state = "3" + if(3) + if(isWirecutter(P)) + playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1) + to_chat(user, "You remove the cables.") + src.state = 2 + src.icon_state = "2" + var/obj/item/stack/cable_coil/A = new /obj/item/stack/cable_coil( src.loc ) + A.amount = 5 + + if(istype(P, /obj/item/stack/material) && P.get_material_name() == "glass") + var/obj/item/stack/G = P + if (G.get_amount() < 2) + to_chat(user, "You need two sheets of glass to put in the glass panel.") + return + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + to_chat(user, "You start to put in the glass panel.") + if(do_after(user, 20, src) && state == 3) + if (G.use(2)) + to_chat(user, "You put in the glass panel.") + src.state = 4 + src.icon_state = "4" + if(4) + if(isCrowbar(P)) + playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) + to_chat(user, "You remove the glass panel.") + src.state = 3 + src.icon_state = "3" + new /obj/item/stack/material/glass( src.loc, 2 ) + if(isScrewdriver(P)) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You connect the monitor.") + var/B = new src.circuit.build_path ( src.loc ) + src.circuit.construct(B) + qdel(src) diff --git a/code/game/machinery/computer/camera_circuit.dm b/code/game/machinery/computer/camera_circuit.dm new file mode 100644 index 00000000..ccc13476 --- /dev/null +++ b/code/game/machinery/computer/camera_circuit.dm @@ -0,0 +1,115 @@ + +//the researchable camera circuit that can connect to any camera network + +/obj/item/weapon/circuitboard/camera + //name = "Circuit board (Camera)" + var/secured = 1 + var/authorised = 0 + var/possibleNets[0] + var/network = "" + build_path = null + +//when adding a new camera network, you should only need to update these two procs + New() + possibleNets["Engineering"] = access_ce + possibleNets["SS13"] = access_hos + possibleNets["Mining"] = access_mining + possibleNets["Cargo"] = access_qm + possibleNets["Research"] = access_rd + possibleNets["Medbay"] = access_cmo + ..() + + proc/updateBuildPath() + build_path = null + if(authorised && secured) + switch(network) + if("SS13") + build_path = /obj/machinery/computer/security + if("Engineering") + build_path = /obj/machinery/computer/security/engineering + if("Mining") + build_path = /obj/machinery/computer/security/mining + if("Research") + build_path = /obj/machinery/computer/security/research + if("Medbay") + build_path = /obj/machinery/computer/security/medbay + if("Cargo") + build_path = /obj/machinery/computer/security/cargo + + attackby(var/obj/item/I, var/mob/user)//if(health > 50) + ..() + if(isScrewdriver(I)) + secured = !secured + user.visible_message("The [src] can [secured ? "no longer" : "now"] be modified.") + updateBuildPath() + return + + attack_self(var/mob/user) + if(!secured && ishuman(user)) + user.machine = src + interact(user, 0) + + proc/interact(var/mob/user, var/ai=0) + if(secured) + return + if (!ishuman(user)) + return ..(user) + var/t = "Circuitboard Console - Camera Monitoring Computer
    " + t += "Close
    " + t += "
    Please select a camera network:
    " + + for(var/curNet in possibleNets) + if(network == curNet) + t += "- [curNet]
    " + else + t += "- [curNet]
    " + t += "
    " + if(network) + if(authorised) + t += "Authenticated (Clear Auth)
    " + else + t += "*Authenticate* (Requires an appropriate access ID)
    " + else + t += "*Authenticate* (Requires an appropriate access ID)
    " + t += "Close
    " + user << browse(t, "window=camcircuit;size=500x400") + onclose(user, "camcircuit") + + Topic(href, href_list) + ..() + if( href_list["close"] ) + usr << browse(null, "window=camcircuit") + usr.machine = null + return + else if(href_list["net"]) + network = href_list["net"] + authorised = 0 + else if( href_list["auth"] ) + var/mob/M = usr + var/obj/item/weapon/card/id/I = M.equipped() + if (istype(I, /obj/item/device/pda)) + var/obj/item/device/pda/pda = I + I = pda.id + if (I && istype(I)) + if(access_captain in I.access) + authorised = 1 + else if (possibleNets[network] in I.access) + authorised = 1 + if(istype(I,/obj/item/weapon/card/emag)) + I.resolve_attackby(src, usr) + else if( href_list["removeauth"] ) + authorised = 0 + updateDialog() + + updateDialog() + if(istype(src.loc,/mob)) + attack_self(src.loc) + +/obj/item/weapon/circuitboard/camera/emag_act(var/remaining_charges, var/mob/user) + if(network) + authorised = 1 + to_chat(user, "You authorised the circuit network!") + updateDialog() + return 1 + else + to_chat(user, "You must select a camera network circuit!") diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm new file mode 100644 index 00000000..d8cd874d --- /dev/null +++ b/code/game/machinery/computer/computer.dm @@ -0,0 +1,118 @@ +/obj/machinery/computer + name = "computer" + icon = 'icons/obj/computer.dmi' + icon_state = "computer" + density = 1 + anchored = 1.0 + use_power = 1 + idle_power_usage = 300 + active_power_usage = 300 + var/circuit = null //The path to the circuit board type. If circuit==null, the computer can't be disassembled. + var/processing = 0 + + var/icon_keyboard = "generic_key" + var/icon_screen = "generic" + var/light_range_on = 2 + var/light_power_on = 1 + var/overlay_layer + atom_flags = ATOM_FLAG_CLIMBABLE + clicksound = "keyboard" + +/obj/machinery/computer/New() + overlay_layer = layer + ..() + +/obj/machinery/computer/Initialize() + . = ..() + power_change() + update_icon() + +/obj/machinery/computer/Process() + if(stat & (NOPOWER|BROKEN)) + return 0 + return 1 + +/obj/machinery/computer/emp_act(severity) + if(prob(20/severity)) set_broken() + ..() + + +/obj/machinery/computer/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + if (prob(25)) + qdel(src) + return + if (prob(50)) + for(var/x in verbs) + verbs -= x + set_broken() + if(3.0) + if (prob(25)) + for(var/x in verbs) + verbs -= x + set_broken() + else + return + +/obj/machinery/computer/bullet_act(var/obj/item/projectile/Proj) + if(prob(Proj.get_structure_damage())) + set_broken() + ..() + +/obj/machinery/computer/update_icon() + overlays.Cut() + if(stat & NOPOWER) + set_light(0) + if(icon_keyboard) + overlays += image(icon,"[icon_keyboard]_off", overlay_layer) + return + else + set_light(light_range_on, light_power_on) + + if(stat & BROKEN) + overlays += image(icon,"[icon_state]_broken", overlay_layer) + else + overlays += image(icon,icon_screen, overlay_layer) + + if(icon_keyboard) + overlays += image(icon, icon_keyboard, overlay_layer) + +/obj/machinery/computer/proc/set_broken() + stat |= BROKEN + update_icon() + +/obj/machinery/computer/proc/decode(text) + // Adds line breaks + text = replacetext(text, "\n", "
    ") + return text + +/obj/machinery/computer/attackby(I as obj, user as mob) + if(isScrewdriver(I) && circuit) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + if(do_after(user, 20, src)) + var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/M = new circuit( A ) + A.circuit = M + A.anchored = 1 + for (var/obj/C in src) + C.dropInto(loc) + if (src.stat & BROKEN) + to_chat(user, "The broken glass falls out.") + new /obj/item/weapon/material/shard( src.loc ) + A.state = 3 + A.icon_state = "3" + else + to_chat(user, "You disconnect the monitor.") + A.state = 4 + A.icon_state = "4" + M.deconstruct(src) + qdel(src) + else + ..() + +/obj/machinery/computer/attack_ghost(var/mob/ghost) + attack_hand(ghost) \ No newline at end of file diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm new file mode 100644 index 00000000..c0d772e8 --- /dev/null +++ b/code/game/machinery/computer/crew.dm @@ -0,0 +1,38 @@ +/obj/machinery/computer/crew + name = "crew monitoring computer" + desc = "Used to monitor active health sensors built into most of the crew's uniforms." + icon_keyboard = "med_key" + icon_screen = "crew" + light_color = "#315ab4" + use_power = 1 + idle_power_usage = 250 + active_power_usage = 500 + circuit = /obj/item/weapon/circuitboard/crew + var/datum/nano_module/crew_monitor/crew_monitor + +/obj/machinery/computer/crew/New() + crew_monitor = new(src) + ..() + +/obj/machinery/computer/crew/Destroy() + qdel(crew_monitor) + crew_monitor = null + ..() + +/obj/machinery/computer/crew/attack_ai(mob/user) + ui_interact(user) + +/obj/machinery/computer/crew/attack_hand(mob/user) + ..() + if(stat & (BROKEN|NOPOWER)) + return + ui_interact(user) + +/obj/machinery/computer/crew/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + crew_monitor.ui_interact(user, ui_key, ui, force_open, state) + +/obj/machinery/computer/crew/nano_container() + return crew_monitor + +/obj/machinery/computer/crew/interact(mob/user) + crew_monitor.ui_interact(user) diff --git a/code/game/machinery/computer/download_console.dm b/code/game/machinery/computer/download_console.dm new file mode 100644 index 00000000..e3ce9176 --- /dev/null +++ b/code/game/machinery/computer/download_console.dm @@ -0,0 +1,25 @@ +/obj/machinery/computer/downloadconsole + name = "download console" + icon_state = "oldcomp" + icon_keyboard = null + icon_screen = "library" + use_power = 0 + var/can_record_tape = TRUE + +/obj/machinery/computer/downloadconsole/attack_hand(mob/user) //later do file size check %_% + if(!can_record_tape) + to_chat(user, "Spess dial-up is so slow! I must to wait.") + return + var/sound/S = input("Pick music") as sound|null + if(S) + can_record_tape = FALSE + var/N = input("Input cassette name", "[pick("LEHA SPECIAL FORCES","SET ME FREE","UF BEST HITS 2065", "Bomb-a-Nyti explosives factory")]") as text|null + var/obj/item/device/cassette/casseta = new() + casseta.sound_inside = S + casseta.name = "\"[N]\" magn-o-tape " + casseta.loc = src.loc + casseta.uploader_idiot = user.name + to_chat(user, "Tape completed!") + log_and_message_admins("downloaded music with name [html_encode(N)]! if he loaded shit - just ban. Location = [get_area(user)]") + spawn(3 MINUTES) + can_record_tape = TRUE \ No newline at end of file diff --git a/code/game/machinery/computer/guestpass.dm b/code/game/machinery/computer/guestpass.dm new file mode 100644 index 00000000..e9d3059d --- /dev/null +++ b/code/game/machinery/computer/guestpass.dm @@ -0,0 +1,191 @@ +///////////////////////////////////////////// +//Guest pass //////////////////////////////// +///////////////////////////////////////////// +/obj/item/weapon/card/id/guest + name = "guest pass" + desc = "Allows temporary access to restricted areas." + icon_state = "guest" + light_color = "#0099ff" + + var/temp_access = list() //to prevent agent cards stealing access as permanent + var/expiration_time = 0 + var/reason = "NOT SPECIFIED" + +/obj/item/weapon/card/id/guest/GetAccess() + if (world.time > expiration_time) + return access + else + return temp_access + +/obj/item/weapon/card/id/guest/examine(mob/user) + . = ..() + if (world.time < expiration_time) + to_chat(user, "This pass expires at [worldtime2stationtime(expiration_time)].") + else + to_chat(user, "It expired at [worldtime2stationtime(expiration_time)].") + +/obj/item/weapon/card/id/guest/read() + if (world.time > expiration_time) + to_chat(usr, "This pass expired at [worldtime2stationtime(expiration_time)].") + else + to_chat(usr, "This pass expires at [worldtime2stationtime(expiration_time)].") + + to_chat(usr, "It grants access to following areas:") + for (var/A in temp_access) + to_chat(usr, "[get_access_desc(A)].") + to_chat(usr, "Issuing reason: [reason].") + return + +///////////////////////////////////////////// +//Guest pass terminal//////////////////////// +///////////////////////////////////////////// + +/obj/machinery/computer/guestpass + name = "guest pass terminal" + icon_state = "guest" + icon_keyboard = null + icon_screen = "pass" + density = 0 + + var/obj/item/weapon/card/id/giver + var/list/accesses = list() + var/giv_name = "NOT SPECIFIED" + var/reason = "NOT SPECIFIED" + var/duration = 5 + + var/list/internal_log = list() + var/mode = 0 // 0 - making pass, 1 - viewing logs + +/obj/machinery/computer/guestpass/New() + ..() + uid = "[random_id("guestpass_serial_number",100,999)]-G[rand(10,99)]" + +/obj/machinery/computer/guestpass/attackby(obj/O, mob/user) + if(istype(O, /obj/item/weapon/card/id)) + if(!giver && user.unEquip(O)) + O.forceMove(src) + giver = O + updateUsrDialog() + else if(giver) + to_chat(user, "There is already ID card inside.") + return + ..() + +/obj/machinery/computer/guestpass/attack_ai(var/mob/user as mob) + return attack_hand(user) + +/obj/machinery/computer/guestpass/attack_hand(var/mob/user as mob) + if(..()) + return + + user.set_machine(src) + var/dat + + if (mode == 1) //Logs + dat += "

    Activity log


    " + for (var/entry in internal_log) + dat += "[entry]

    " + dat += "Print
    " + dat += "Back
    " + else + dat += "

    Guest pass terminal #[uid]


    " + dat += "View activity log

    " + dat += "Issuing ID: [giver]
    " + dat += "Issued to: [giv_name]
    " + dat += "Reason: [reason]
    " + dat += "Duration (minutes): [duration] m
    " + dat += "Access to areas:
    " + if (giver && giver.access) + for (var/A in giver.access) + var/area = get_access_desc(A) + if (A in accesses) + area = "[area]" + dat += "[area]
    " + dat += "
    Issue pass
    " + + user << browse(dat, "window=guestpass;size=400x520") + onclose(user, "guestpass") + + +/obj/machinery/computer/guestpass/OnTopic(var/mob/user, href_list, state) + if (href_list["mode"]) + mode = text2num(href_list["mode"]) + . = TOPIC_REFRESH + + else if (href_list["choice"]) + switch(href_list["choice"]) + if ("giv_name") + var/nam = sanitize(input(user, "Person pass is issued to", "Name", giv_name) as text|null) + if (nam && CanUseTopic(user, state)) + giv_name = nam + if ("reason") + var/reas = sanitize(input(user, "Reason why pass is issued", "Reason", reason) as text|null) + if(reas && CanUseTopic(user, state)) + reason = reas + if ("duration") + var/dur = input(user, "Duration (in minutes) during which pass is valid (up to 30 minutes).", "Duration") as num|null + if (dur && CanUseTopic(user, state)) + if (dur > 0 && dur <= 30) + duration = dur + else + to_chat(user, "Invalid duration.") + if ("access") + var/A = text2num(href_list["access"]) + if (A in accesses) + accesses.Remove(A) + else if(giver && (A in giver.access)) + accesses.Add(A) + . = TOPIC_REFRESH + else if (href_list["action"]) + switch(href_list["action"]) + if ("id") + if (giver) + giver.dropInto(user.loc) + if(ishuman(user)) + user.put_in_hands(giver) + giver = null + accesses.Cut() + else + var/obj/item/I = user.get_active_hand() + if (istype(I, /obj/item/weapon/card/id) && user.unEquip(I)) + I.forceMove(src) + giver = I + . = TOPIC_REFRESH + if ("print") + var/dat = "

    Activity log of guest pass terminal #[uid]


    " + for (var/entry in internal_log) + dat += "[entry]

    " +// to_chat(user, "Printing the log, standby...") + //sleep(50) + var/obj/item/weapon/paper/P = new/obj/item/weapon/paper( loc ) + P.SetName("activity log") + P.info = dat + . = TOPIC_REFRESH + + if ("issue") + if (giver && accesses.len) + var/number = add_zero(random_id("guestpass_id_number",1000,9999), 4) + var/entry = "\[[stationtime2text()]\] Pass #[number] issued by [giver.registered_name] ([giver.assignment]) to [giv_name]. Reason: [reason]. Granted access to following areas: " + var/list/access_descriptors = list() + for (var/A in accesses) + if (A in giver.access) + access_descriptors += get_access_desc(A) + entry += english_list(access_descriptors, and_text = ", ") + entry += ". Expires at [worldtime2stationtime(world.time + duration MINUTES)]." + internal_log.Add(entry) + + var/obj/item/weapon/card/id/guest/pass = new(src.loc) + pass.temp_access = accesses.Copy() + pass.registered_name = giv_name + pass.expiration_time = world.time + duration MINUTES + pass.reason = reason + pass.SetName("guest pass #[number]") + pass.assignment = "Guest" + playsound(src.loc, 'sound/machines/ping.ogg', 25, 0) + . = TOPIC_REFRESH + else if(!giver) + to_chat(user, "Cannot issue pass without issuing ID.") + else if(!accesses.len) + to_chat(user, "Cannot issue pass without at least one granted access permission.") + if(.) + attack_hand(user) diff --git a/code/game/machinery/computer/law.dm b/code/game/machinery/computer/law.dm new file mode 100644 index 00000000..8fad6f72 --- /dev/null +++ b/code/game/machinery/computer/law.dm @@ -0,0 +1,92 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/obj/machinery/computer/aiupload + name = "\improper AI upload console" + desc = "Used to upload laws to the AI." + icon_keyboard = "rd_key" + icon_screen = "command" + circuit = /obj/item/weapon/circuitboard/aiupload + var/mob/living/silicon/ai/current = null + var/opened = 0 + + + verb/AccessInternals() + set category = "Object" + set name = "Access Computer's Internals" + set src in oview(1) + if(get_dist(src, usr) > 1 || usr.restrained() || usr.lying || usr.stat || istype(usr, /mob/living/silicon)) + return + + opened = !opened + if(opened) + to_chat(usr, "The access panel is now open.") + else + to_chat(usr, "The access panel is now closed.") + return + + + attackby(obj/item/weapon/O as obj, mob/user as mob) + if (user.z > 6) + to_chat(user, "Unable to establish a connection: You're too far away from the [station_name()]!") + return + if(istype(O, /obj/item/weapon/aiModule)) + var/obj/item/weapon/aiModule/M = O + M.install(src) + else + ..() + + + attack_hand(var/mob/user as mob) + if(src.stat & NOPOWER) + to_chat(usr, "The upload computer has no power!") + return + if(src.stat & BROKEN) + to_chat(usr, "The upload computer is broken!") + return + + src.current = select_active_ai(user) + + if (!src.current) + to_chat(usr, "No active AIs detected.") + else + to_chat(usr, "[src.current.name] selected for law changes.") + return + + attack_ghost(user as mob) + return 1 + + +/obj/machinery/computer/borgupload + name = "cyborg upload console" + desc = "Used to upload laws to Cyborgs." + icon_keyboard = "rd_key" + icon_screen = "command" + circuit = /obj/item/weapon/circuitboard/borgupload + var/mob/living/silicon/robot/current = null + + + attackby(obj/item/weapon/aiModule/module as obj, mob/user as mob) + if(istype(module, /obj/item/weapon/aiModule)) + module.install(src) + else + return ..() + + + attack_hand(var/mob/user as mob) + if(src.stat & NOPOWER) + to_chat(usr, "The upload computer has no power!") + return + if(src.stat & BROKEN) + to_chat(usr, "The upload computer is broken!") + return + + src.current = freeborg() + + if (!src.current) + to_chat(usr, "No free cyborgs detected.") + else + to_chat(usr, "[src.current.name] selected for law changes.") + return + + attack_ghost(user as mob) + return 1 diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm new file mode 100644 index 00000000..a1d29ff4 --- /dev/null +++ b/code/game/machinery/computer/message.dm @@ -0,0 +1,518 @@ +// Allows you to monitor messages that passes the server. + +/obj/machinery/computer/message_monitor + name = "messaging monitor console" + desc = "Used to access and maintain data on messaging servers. Allows you to view PDA and request console messages." + icon_screen = "comm_logs" + light_color = "#00b000" + var/hack_icon = "error" + circuit = /obj/item/weapon/circuitboard/message_monitor + //Server linked to. + var/obj/machinery/message_server/linkedServer = null + //Sparks effect - For emag + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread + //Messages - Saves me time if I want to change something. + var/noserver = "ALERT: No server detected." + var/incorrectkey = "ALERT: Incorrect decryption key!" + var/defaultmsg = "Welcome. Please select an option." + var/rebootmsg = "%$&(£: Critical %$$@ Error // !RestArting! - ?pLeaSe wAit!" + //Computer properties + var/screen = 0 // 0 = Main menu, 1 = Message Logs, 2 = Hacked screen, 3 = Custom Message + var/hacking = 0 // Is it being hacked into by the AI/Cyborg + var/emag = 0 // When it is emagged. + var/message = "System bootup complete. Please select an option." // The message that shows on the main menu. + var/auth = 0 // Are they authenticated? + var/optioncount = 8 + // Custom Message Properties + var/customsender = "System Administrator" + var/obj/item/device/pda/customrecepient = null + var/customjob = "Admin" + var/custommessage = "This is a test, please ignore." + + +/obj/machinery/computer/message_monitor/attackby(obj/item/weapon/O as obj, mob/living/user as mob) + if(stat & (NOPOWER|BROKEN)) + ..() + return + if(!istype(user)) + return + if(isScrewdriver(O) && emag) + //Stops people from just unscrewing the monitor and putting it back to get the console working again. + to_chat(user, "It is too hot to mess with!") + return + + ..() + return + +/obj/machinery/computer/message_monitor/emag_act(var/remaining_charges, var/mob/user) + // Will create sparks and print out the console's password. You will then have to wait a while for the console to be back online. + // It'll take more time if there's more characters in the password.. + if(!emag && operable()) + if(!isnull(src.linkedServer)) + emag = 1 + screen = 2 + spark_system.set_up(5, 0, src) + src.spark_system.start() + var/obj/item/weapon/paper/monitorkey/MK = new/obj/item/weapon/paper/monitorkey + MK.dropInto(loc) + // Will help make emagging the console not so easy to get away with. + MK.info += "

    £%@%(*$%&(£&?*(%&£/{}" + spawn(100*length(src.linkedServer.decryptkey)) UnmagConsole() + message = rebootmsg + update_icon() + return 1 + else + to_chat(user, "A no server error appears on the screen.") + +/obj/machinery/computer/message_monitor/update_icon() + if(emag || hacking) + icon_screen = hack_icon + else + icon_screen = initial(icon_screen) + ..() + +/obj/machinery/computer/message_monitor/Initialize() + //Is the server isn't linked to a server, and there's a server available, default it to the first one in the list. + if(!linkedServer) + if(message_servers && message_servers.len > 0) + linkedServer = message_servers[1] + return ..() + +/obj/machinery/computer/message_monitor/attack_hand(var/mob/living/user as mob) + if(stat & (NOPOWER|BROKEN)) + return + if(!istype(user)) + return + //If the computer is being hacked or is emagged, display the reboot message. + if(hacking || emag) + message = rebootmsg + var/dat = "Message Monitor Console" + dat += "

    Message Monitor Console


    " + dat += "

    " + + if(auth) + dat += "

    \[Authenticated\] /" + dat += " Server Power: [src.linkedServer && src.linkedServer.active ? "\[On\]":"\[Off\]"]

    " + else + dat += "

    \[Unauthenticated\] /" + dat += " Server Power: [src.linkedServer && src.linkedServer.active ? "\[On\]":"\[Off\]"]

    " + + if(hacking || emag) + screen = 2 + else if(!auth || !linkedServer || (linkedServer.stat & (NOPOWER|BROKEN))) + if(!linkedServer || (linkedServer.stat & (NOPOWER|BROKEN))) message = noserver + screen = 0 + + switch(screen) + //Main menu + if(0) + // = TAB + var/i = 0 + dat += "
    [++i]. Link To A Server
    " + if(auth) + if(!linkedServer || (linkedServer.stat & (NOPOWER|BROKEN))) + dat += "
    ERROR: Server not found!
    " + else + dat += "
    [++i]. View Message Logs
    " + dat += "
    [++i]. View Request Console Logs
    " + dat += "
    [++i]. Clear Message Logs
    " + dat += "
    [++i]. Clear Request Console Logs
    " + dat += "
    [++i]. Set Custom Key
    " + dat += "
    [++i]. Send Admin Message
    " + dat += "
    [++i]. Modify Spam Filter
    " + else + for(var/n = ++i; n <= optioncount; n++) + dat += "
    [n]. ---------------
    " + if((istype(user, /mob/living/silicon/ai) || istype(user, /mob/living/silicon/robot)) && (user.mind.special_role && user.mind.original == user)) + //Malf/Traitor AIs can bruteforce into the system to gain the Key. + dat += "
    *&@#. Bruteforce Key
    " + else + dat += "
    " + + //Bottom message + if(!auth) + dat += "

    Please authenticate with the server in order to show additional options." + else + dat += "

    Reg, #514 forbids sending messages to a Head of Staff containing Erotic Rendering Properties." + + //Message Logs + if(1) + var/index = 0 + //var/recipient = "Unspecified" //name of the person + //var/sender = "Unspecified" //name of the sender + //var/message = "Blank" //transferred message + dat += "
    Back - Refresh

    " + dat += "" + for(var/datum/data_pda_msg/pda in src.linkedServer.pda_msgs) + index++ + if(index > 3000) + break + // Del - Sender - Recepient - Message + // X - Al Green - Your Mom - WHAT UP!? + dat += "" + dat += "
    XSenderRecipientMessage
    X
    [pda.sender][pda.recipient][pda.message]
    " + //Hacking screen. + if(2) + if(istype(user, /mob/living/silicon/ai) || istype(user, /mob/living/silicon/robot)) + dat += "Brute-forcing for server key.
    It will take 20 seconds for every character that the password has." + dat += "In the meantime, this console can reveal your true intentions if you let someone access it. Make sure no humans enter the room during that time." + else + //It's the same message as the one above but in binary. Because robots understand binary and humans don't... well I thought it was clever. + dat += {"01000010011100100111010101110100011001010010110
    + 10110011001101111011100100110001101101001011011100110011
    + 10010000001100110011011110111001000100000011100110110010
    + 10111001001110110011001010111001000100000011010110110010
    + 10111100100101110001000000100100101110100001000000111011
    + 10110100101101100011011000010000001110100011000010110101
    + 10110010100100000001100100011000000100000011100110110010
    + 10110001101101111011011100110010001110011001000000110011
    + 00110111101110010001000000110010101110110011001010111001
    + 00111100100100000011000110110100001100001011100100110000
    + 10110001101110100011001010111001000100000011101000110100
    + 00110000101110100001000000111010001101000011001010010000
    + 00111000001100001011100110111001101110111011011110111001
    + 00110010000100000011010000110000101110011001011100010000
    + 00100100101101110001000000111010001101000011001010010000
    + 00110110101100101011000010110111001110100011010010110110
    + 10110010100101100001000000111010001101000011010010111001
    + 10010000001100011011011110110111001110011011011110110110
    + 00110010100100000011000110110000101101110001000000111001
    + 00110010101110110011001010110000101101100001000000111100
    + 10110111101110101011100100010000001110100011100100111010
    + 10110010100100000011010010110111001110100011001010110111
    + 00111010001101001011011110110111001110011001000000110100
    + 10110011000100000011110010110111101110101001000000110110
    + 00110010101110100001000000111001101101111011011010110010
    + 10110111101101110011001010010000001100001011000110110001
    + 10110010101110011011100110010000001101001011101000010111
    + 00010000001001101011000010110101101100101001000000111001
    + 10111010101110010011001010010000001101110011011110010000
    + 00110100001110101011011010110000101101110011100110010000
    + 00110010101101110011101000110010101110010001000000111010
    + 00110100001100101001000000111001001101111011011110110110
    + 10010000001100100011101010111001001101001011011100110011
    + 10010000001110100011010000110000101110100001000000111010
    + 001101001011011010110010100101110"} + + //Fake messages + if(3) + dat += "
    Back - Reset

    " + + dat += {" + + + + "} + //Sender - Sender's Job - Recepient - Message + //Al Green- Your Dad - Your Mom - WHAT UP!? + + dat += {" + + + "} + dat += "
    SenderSender's JobRecipientMessage
    [customsender][customjob][customrecepient ? customrecepient.owner : "NONE"][custommessage]

    Send
    " + + //Request Console Logs + if(4) + + var/index = 0 + /* data_rc_msg + X - 5% + var/rec_dpt = "Unspecified" //name of the person - 15% + var/send_dpt = "Unspecified" //name of the sender- 15% + var/message = "Blank" //transferred message - 300px + var/stamp = "Unstamped" - 15% + var/id_auth = "Unauthenticated" - 15% + var/priority = "Normal" - 10% + */ + dat += "
    Back - Refresh

    " + dat += {" + "} + for(var/datum/data_rc_msg/rc in src.linkedServer.rc_msgs) + index++ + if(index > 3000) + break + // Del - Sender - Recepient - Message + // X - Al Green - Your Mom - WHAT UP!? + dat += {" + "} + dat += "
    XSending Dep.Receiving Dep.MessageStampID Auth.Priority.
    X
    [rc.send_dpt][rc.rec_dpt][rc.message][rc.stamp][rc.id_auth][rc.priority]
    " + + //Spam filter modification + if(5) + dat += "
    Back - Refresh

    " + var/index = 0 + for(var/token in src.linkedServer.spamfilter) + index++ + if(index > 3000) + break + dat += "
    [index] \[[token]\]
    " + dat += "
    " + if (linkedServer.spamfilter.len < linkedServer.spamfilter_limit) + dat += "Add token
    " + + + dat += "" + message = defaultmsg + user << browse(dat, "window=message;size=700x700") + onclose(user, "message") + return + +/obj/machinery/computer/message_monitor/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/message_monitor/proc/BruteForce(mob/user as mob) + if(isnull(linkedServer)) + to_chat(user, "Could not complete brute-force: Linked Server Disconnected!") + else + var/currentKey = src.linkedServer.decryptkey + to_chat(user, "Brute-force completed! The key is '[currentKey]'.") + src.hacking = 0 + update_icon() + src.screen = 0 // Return the screen back to normal + +/obj/machinery/computer/message_monitor/proc/UnmagConsole() + src.emag = 0 + update_icon() + +/obj/machinery/computer/message_monitor/proc/ResetMessage() + customsender = "System Administrator" + customrecepient = null + custommessage = "This is a test, please ignore." + customjob = "Admin" + +/obj/machinery/computer/message_monitor/Topic(href, href_list) + if((. = ..())) + return + + //Authenticate + if (href_list["auth"]) + if(auth) + auth = 0 + screen = 0 + else + var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null) + if(dkey && dkey != "") + if(src.linkedServer.decryptkey == dkey) + auth = 1 + else + message = incorrectkey + + //Turn the server on/off. + if (href_list["active"]) + if(auth) linkedServer.active = !linkedServer.active + //Find a server + if (href_list["find"]) + if(message_servers && message_servers.len > 1) + src.linkedServer = input(usr,"Please select a server.", "Select a server.", null) as null|anything in message_servers + message = "NOTICE: Server selected." + else if(message_servers && message_servers.len > 0) + linkedServer = message_servers[1] + message = "NOTICE: Only Single Server Detected - Server selected." + else + message = noserver + + //View the logs - KEY REQUIRED + if (href_list["view"]) + if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN))) + message = noserver + else + if(auth) + src.screen = 1 + + //Clears the logs - KEY REQUIRED + if (href_list["clear"]) + if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN))) + message = noserver + else + if(auth) + src.linkedServer.pda_msgs = list() + message = "NOTICE: Logs cleared." + //Clears the request console logs - KEY REQUIRED + if (href_list["clearr"]) + if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN))) + message = noserver + else + if(auth) + src.linkedServer.rc_msgs = list() + message = "NOTICE: Logs cleared." + //Change the password - KEY REQUIRED + if (href_list["pass"]) + if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN))) + message = noserver + else + if(auth) + var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null) + if(dkey && dkey != "") + if(src.linkedServer.decryptkey == dkey) + var/newkey = trim(input(usr,"Please enter the new key (3 - 16 characters max):")) + if(length(newkey) <= 3) + message = "NOTICE: Decryption key too short!" + else if(length(newkey) > 16) + message = "NOTICE: Decryption key too long!" + else if(newkey && newkey != "") + src.linkedServer.decryptkey = newkey + message = "NOTICE: Decryption key set." + else + message = incorrectkey + + //Hack the Console to get the password + if (href_list["hack"]) + if((istype(usr, /mob/living/silicon/ai) || istype(usr, /mob/living/silicon/robot)) && (usr.mind.special_role && usr.mind.original == usr)) + src.hacking = 1 + src.screen = 2 + update_icon() + //Time it takes to bruteforce is dependant on the password length. + spawn(100*length(src.linkedServer.decryptkey)) + if(src && src.linkedServer && usr) + BruteForce(usr) + //Delete the log. + if (href_list["delete"]) + //Are they on the view logs screen? + if(screen == 1) + if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN))) + message = noserver + else //if(istype(href_list["delete"], /datum/data_pda_msg)) + src.linkedServer.pda_msgs -= locate(href_list["delete"]) + message = "NOTICE: Log Deleted!" + //Delete the request console log. + if (href_list["deleter"]) + //Are they on the view logs screen? + if(screen == 4) + if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN))) + message = noserver + else //if(istype(href_list["delete"], /datum/data_pda_msg)) + src.linkedServer.rc_msgs -= locate(href_list["deleter"]) + message = "NOTICE: Log Deleted!" + //Create a custom message + if (href_list["msg"]) + if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN))) + message = noserver + else + if(auth) + src.screen = 3 + //Fake messaging selection - KEY REQUIRED + if (href_list["select"]) + if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN))) + message = noserver + screen = 0 + else + switch(href_list["select"]) + + //Reset + if("Reset") + ResetMessage() + + //Select Your Name + if("Sender") + customsender = sanitize(input(usr, "Please enter the sender's name.") as text|null) + + //Select Receiver + if("Recepient") + //Get out list of viable PDAs + var/list/obj/item/device/pda/sendPDAs = list() + for(var/obj/item/device/pda/P in PDAs) + if(!P.owner || P.toff || P.hidden) continue + sendPDAs += P + if(PDAs && PDAs.len > 0) + customrecepient = input(usr, "Select a PDA from the list.") as null|anything in sortAtom(sendPDAs) + else + customrecepient = null + + //Enter custom job + if("RecJob") + customjob = sanitize(input(usr, "Please enter the sender's job.") as text|null) + + //Enter message + if("Message") + custommessage = input(usr, "Please enter your message.") as text|null + custommessage = sanitize(custommessage) + + //Send message + if("Send") + + if(isnull(customsender) || customsender == "") + customsender = "UNKNOWN" + + if(isnull(customrecepient)) + message = "NOTICE: No recepient selected!" + return src.attack_hand(usr) + + if(isnull(custommessage) || custommessage == "") + message = "NOTICE: No message entered!" + return src.attack_hand(usr) + + var/obj/item/device/pda/PDARec = null + for (var/obj/item/device/pda/P in PDAs) + if (!P.owner || P.toff || P.hidden) continue + if(P.owner == customsender) + PDARec = P + //Sender isn't faking as someone who exists + if(isnull(PDARec)) + src.linkedServer.send_pda_message("[customrecepient.owner]", "[customsender]","[custommessage]") + customrecepient.new_message(customsender, customsender, customjob, custommessage) + //Sender is faking as someone who exists + else + + src.linkedServer.send_pda_message("[customrecepient.owner]", "[PDARec.owner]","[custommessage]") + customrecepient.tnote.Add(list(list("sent" = 0, "owner" = "[PDARec.owner]", "job" = "[customjob]", "message" = "[custommessage]", "target" ="\ref[PDARec]"))) + + if(!customrecepient.conversations.Find("\ref[PDARec]")) + customrecepient.conversations.Add("\ref[PDARec]") + + customrecepient.new_message(PDARec, custommessage) + //Finally.. + ResetMessage() + + //Request Console Logs - KEY REQUIRED + if(href_list["viewr"]) + if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN))) + message = noserver + else + if(auth) + src.screen = 4 + +// to_chat(usr, href_list["select"]) + + if(href_list["spam"]) + if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN))) + message = noserver + else + if(auth) + src.screen = 5 + + if(href_list["addtoken"]) + if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN))) + message = noserver + else + src.linkedServer.spamfilter += input(usr,"Enter text you want to be filtered out","Token creation") as text|null + + if(href_list["deltoken"]) + if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN))) + message = noserver + else + var/tokennum = text2num(href_list["deltoken"]) + src.linkedServer.spamfilter.Cut(tokennum,tokennum+1) + + if (href_list["back"]) + src.screen = 0 + + return src.attack_hand(usr) + + +/obj/item/weapon/paper/monitorkey + //..() + name = "Monitor Decryption Key" + var/obj/machinery/message_server/server = null + +/obj/item/weapon/paper/monitorkey/New() + ..() + spawn(10) + if(message_servers) + for(var/obj/machinery/message_server/server in message_servers) + if(!isnull(server)) + if(!isnull(server.decryptkey)) + info = "

    Daily Key Reset


    The new message monitor key is '[server.decryptkey]'.
    This key is only intended for personnel granted access to the messaging server. Keep it safe.
    If necessary, change the password to a more secure one." + info_links = info + icon_state = "paper_words" + break diff --git a/code/game/machinery/computer/pod.dm b/code/game/machinery/computer/pod.dm new file mode 100644 index 00000000..26404408 --- /dev/null +++ b/code/game/machinery/computer/pod.dm @@ -0,0 +1,219 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/obj/machinery/computer/pod + name = "pod launch control console" + desc = "A control console for launching pods. Some people prefer firing Mechas." + icon_screen = "mass_driver" + light_color = "#00b000" + circuit = /obj/item/weapon/circuitboard/pod + var/id = 1.0 + var/obj/machinery/mass_driver/connected = null + var/timing = 0.0 + var/time = 30.0 + var/title = "Mass Driver Controls" + + +/obj/machinery/computer/pod/New() + ..() + spawn( 5 ) + for(var/obj/machinery/mass_driver/M in world) + if(M.id == id) + connected = M + else + return + return + + +/obj/machinery/computer/pod/proc/alarm() + if(stat & (NOPOWER|BROKEN)) + return + + if(!( connected )) + to_chat(viewers(null, null), "Cannot locate mass driver connector. Cancelling firing sequence!") + return + + for(var/obj/machinery/door/blast/M in world) + if(M.id == id) + M.open() + + sleep(20) + + for(var/obj/machinery/mass_driver/M in world) + if(M.id == id) + M.power = connected.power + M.drive() + + sleep(50) + for(var/obj/machinery/door/blast/M in world) + if(M.id == id) + M.close() + return + return + +/* +/obj/machinery/computer/pod/attackby(I as obj, user as mob) + if(istype(I, /obj/item/weapon/screwdriver)) + playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + if(stat & BROKEN) + to_chat(user, "The broken glass falls out.") + var/obj/structure/computerframe/A = new /obj/structure/computerframe( loc ) + new /obj/item/weapon/material/shard( loc ) + + //generate appropriate circuitboard. Accounts for /pod/old computer types + var/obj/item/weapon/circuitboard/pod/M = null + if(istype(src, /obj/machinery/computer/pod/old)) + M = new /obj/item/weapon/circuitboard/olddoor( A ) + if(istype(src, /obj/machinery/computer/pod/old/syndicate)) + M = new /obj/item/weapon/circuitboard/syndicatedoor( A ) + if(istype(src, /obj/machinery/computer/pod/old/swf)) + M = new /obj/item/weapon/circuitboard/swfdoor( A ) + else //it's not an old computer. Generate standard pod circuitboard. + M = new /obj/item/weapon/circuitboard/pod( A ) + + for (var/obj/C in src) + C.dropInto(loc) + M.id = id + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + qdel(src) + else + to_chat(user, "You disconnect the monitor.") + var/obj/structure/computerframe/A = new /obj/structure/computerframe( loc ) + + //generate appropriate circuitboard. Accounts for /pod/old computer types + var/obj/item/weapon/circuitboard/pod/M = null + if(istype(src, /obj/machinery/computer/pod/old)) + M = new /obj/item/weapon/circuitboard/olddoor( A ) + if(istype(src, /obj/machinery/computer/pod/old/syndicate)) + M = new /obj/item/weapon/circuitboard/syndicatedoor( A ) + if(istype(src, /obj/machinery/computer/pod/old/swf)) + M = new /obj/item/weapon/circuitboard/swfdoor( A ) + else //it's not an old computer. Generate standard pod circuitboard. + M = new /obj/item/weapon/circuitboard/pod( A ) + + for (var/obj/C in src) + C.dropInto(loc) + M.id = id + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + qdel(src) + else + attack_hand(user) + return +*/ + + +/obj/machinery/computer/pod/attack_ai(var/mob/user as mob) + return attack_hand(user) + +/obj/machinery/computer/pod/attack_hand(var/mob/user as mob) + if(..()) + return + + var/dat = "[title]" + user.set_machine(src) + if(connected) + var/d2 + if(timing) //door controls do not need timers. + d2 = "Stop Time Launch" + else + d2 = "Initiate Time Launch" + var/second = time % 60 + var/minute = (time - second) / 60 + dat += "
    \nTimer System: [d2]\nTime Left: [minute ? "[minute]:" : null][second] - - + +" + var/temp = "" + var/list/L = list( 0.25, 0.5, 1, 2, 4, 8, 16 ) + for(var/t in L) + if(t == connected.power) + temp += "[t] " + else + temp += "[t] " + dat += "
    \nPower Level: [temp]
    \nFiring Sequence
    \nTest Fire Driver
    \nToggle Outer Door
    " + else + dat += "
    \nToggle Outer Door
    " + dat += "

    Close
    " + user << browse(dat, "window=computer;size=400x500") + onclose(user, "computer") + return + + +/obj/machinery/computer/pod/Process() + if(!..()) + return + if(timing) + if(time > 0) + time = round(time) - 1 + else + alarm() + time = 0 + timing = 0 + updateDialog() + return + + +/obj/machinery/computer/pod/OnTopic(user, href_list) + if(href_list["power"]) + var/t = text2num(href_list["power"]) + t = min(max(0.25, t), 16) + if(connected) + connected.power = t + . = TOPIC_REFRESH + else if(href_list["alarm"]) + alarm() + . = TOPIC_REFRESH + else if(href_list["drive"]) + for(var/obj/machinery/mass_driver/M in SSmachines.machinery) + if(M.id == id) + M.power = connected.power + M.drive() + . = TOPIC_REFRESH + else if(href_list["time"]) + timing = text2num(href_list["time"]) + . = TOPIC_REFRESH + else if(href_list["tp"]) + var/tp = text2num(href_list["tp"]) + time += tp + time = min(max(round(time), 0), 120) + . = TOPIC_REFRESH + else if(href_list["door"]) + for(var/obj/machinery/door/blast/M in world) + if(M.id == id) + if(M.density) + M.open() + else + M.close() + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + attack_hand(user) + +/obj/machinery/computer/pod/old + icon_state = "oldcomp" + icon_keyboard = null + icon_screen = "library" + name = "DoorMex Control Computer" + title = "Door Controls" + + + +/obj/machinery/computer/pod/old/syndicate + name = "ProComp Executive IIc" + desc = "Criminals often operate on a tight budget. Operates external airlocks." + title = "External Airlock Controls" + req_access = list(access_syndicate) + +/obj/machinery/computer/pod/old/syndicate/attack_hand(var/mob/user as mob) + if(!allowed(user)) + to_chat(user, "Access Denied") + return + else + ..() + +/obj/machinery/computer/pod/old/swf + name = "Magix System IV" + desc = "An arcane artifact that holds much magic. Running E-Knock 2.2: Sorceror's Edition." diff --git a/code/game/machinery/computer/prisoner.dm b/code/game/machinery/computer/prisoner.dm new file mode 100644 index 00000000..23bea605 --- /dev/null +++ b/code/game/machinery/computer/prisoner.dm @@ -0,0 +1,103 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/obj/machinery/computer/prisoner + name = "prisoner management console" + icon = 'icons/obj/computer.dmi' + icon_keyboard = "security_key" + icon_screen = "explosive" + light_color = "#a91515" + req_access = list(access_armory) + circuit = /obj/item/weapon/circuitboard/prisoner + var/id = 0.0 + var/temp = null + var/status = 0 + var/timeleft = 60 + var/stop = 0.0 + var/screen = 0 // 0 - No Access Denied, 1 - Access allowed + + + attack_ai(var/mob/user as mob) + return src.attack_hand(user) + + attack_hand(var/mob/user as mob) + if(..()) + return + user.set_machine(src) + var/dat + dat += "Prisoner Implant Manager System
    " + if(screen == 0) + dat += "
    Unlock Console" + else if(screen == 1) + dat += "
    Chemical Implants
    " + var/turf/Tr = null + for(var/obj/item/weapon/implant/chem/C in world) + Tr = get_turf(C) + if((Tr) && !AreConnectedZLevels(Tr.z, src.z)) continue // Out of range + if(!C.implanted) continue + dat += "[C.imp_in.name] | Remaining Units: [C.reagents.total_volume] | Inject: " + dat += "((1))" + dat += "((5))" + dat += "((10))
    " + dat += "********************************
    " + dat += "
    Tracking Implants
    " + for(var/obj/item/weapon/implant/tracking/T in world) + Tr = get_turf(T) + if((Tr) && !AreConnectedZLevels(Tr.z, src.z)) continue // Out of range + if(!T.implanted) continue + var/loc_display = "Space" + var/mob/living/carbon/M = T.imp_in + if(!istype(M.loc, /turf/space)) + var/turf/mob_loc = get_turf(M) + loc_display = mob_loc.loc + if(T.malfunction) + loc_display = pick(teleportlocs) + dat += "ID: [T.id] | Location: [loc_display]
    " + dat += "(Message Holder) |
    " + dat += "********************************
    " + dat += "
    Lock Console" + + user << browse(dat, "window=computer;size=400x500") + onclose(user, "computer") + return + + + Process() + if(!..()) + src.updateDialog() + return + + + Topic(href, href_list) + if(..()) + return + if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) + usr.set_machine(src) + + if(href_list["inject1"]) + var/obj/item/weapon/implant/I = locate(href_list["inject1"]) + if(I) I.activate(1) + + else if(href_list["inject5"]) + var/obj/item/weapon/implant/I = locate(href_list["inject5"]) + if(I) I.activate(5) + + else if(href_list["inject10"]) + var/obj/item/weapon/implant/I = locate(href_list["inject10"]) + if(I) I.activate(10) + + else if(href_list["lock"]) + if(src.allowed(usr)) + screen = !screen + else + to_chat(usr, "Unauthorized Access.") + + else if(href_list["warn"]) + var/warning = sanitize(input(usr,"Message:","Enter your message here!","")) + if(!warning) return + var/obj/item/weapon/implant/I = locate(href_list["warn"]) + if((I)&&(I.imp_in)) + var/mob/living/carbon/R = I.imp_in + to_chat(R, "You hear a voice in your head saying: '[warning]'") + + src.updateUsrDialog() + return diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm new file mode 100644 index 00000000..c0ef675b --- /dev/null +++ b/code/game/machinery/computer/robot.dm @@ -0,0 +1,167 @@ +/obj/machinery/computer/robotics + name = "robotics control console" + desc = "Used to remotely lockdown or monitor linked synthetics." + icon = 'icons/obj/computer.dmi' + icon_keyboard = "mining_key" + icon_screen = "robot" + light_color = "#a97faa" + req_access = list(access_robotics) + circuit = /obj/item/weapon/circuitboard/robotics + +/obj/machinery/computer/robotics/attack_ai(var/mob/user as mob) + ui_interact(user) + +/obj/machinery/computer/robotics/attack_hand(var/mob/user as mob) + ui_interact(user) + +/obj/machinery/computer/robotics/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + data["robots"] = get_cyborgs(user) + data["is_ai"] = issilicon(user) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "robot_control.tmpl", "Robotic Control Console", 400, 500) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/computer/robotics/CanUseTopic(user) + if(!allowed(user)) + to_chat(user, "Access Denied") + return STATUS_CLOSE + return ..() + +/obj/machinery/computer/robotics/OnTopic(var/mob/user, href_list) + // Locks or unlocks the cyborg + if (href_list["lockdown"]) + var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["lockdown"]) + if(!target || !istype(target)) + return TOPIC_HANDLED + + if(isAI(user) && (target.connected_ai != user)) + to_chat(user, "Access Denied. This robot is not linked to you.") + return TOPIC_HANDLED + + if(isrobot(user)) + to_chat(user, "Access Denied.") + return TOPIC_HANDLED + + var/choice = input("Really [target.lockcharge ? "unlock" : "lockdown"] [target.name] ?") in list ("Yes", "No") + if(choice != "Yes") + return TOPIC_HANDLED + + if(!target || !istype(target)) + return TOPIC_HANDLED + + if(target.SetLockdown(!target.lockcharge)) + message_admins("[key_name_admin(usr)] [target.lockcharge ? "locked down" : "released"] [target.name]!") + log_game("[key_name(usr)] [target.lockcharge ? "locked down" : "released"] [target.name]!") + if(target.lockcharge) + to_chat(target, "You have been locked down!") + else + to_chat(target, "Your lockdown has been lifted!") + else + to_chat(user, "ERROR: Lockdown attempt failed.") + . = TOPIC_REFRESH + + // Remotely hacks the cyborg. Only antag AIs can do this and only to linked cyborgs. + else if (href_list["hack"]) + var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["hack"]) + if(!target || !istype(target)) + return TOPIC_HANDLED + + // Antag AI checks + if(!istype(user, /mob/living/silicon/ai) || !(user.mind.special_role && user.mind.original == user)) + to_chat(user, "Access Denied") + return TOPIC_HANDLED + + if(target.emagged) + to_chat(user, "Robot is already hacked.") + return TOPIC_HANDLED + + var/choice = input("Really hack [target.name]? This cannot be undone.") in list("Yes", "No") + if(choice != "Yes") + return TOPIC_HANDLED + + if(!target || !istype(target)) + return TOPIC_HANDLED + + message_admins("[key_name_admin(usr)] emagged [target.name] using robotic console!") + log_game("[key_name(usr)] emagged [target.name] using robotic console!") + target.emagged = 1 + to_chat(target, "Failsafe protocols overriden. New tools available.") + . = TOPIC_REFRESH + + else if (href_list["message"]) + var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["message"]) + if(!target || !istype(target)) + return + + var/message = sanitize(input("Enter message to transmit to the synthetic.") as null|text) + if(!message || !istype(target)) + return + + log_and_message_admins("sent message '[message]' to [target.name] using robotics control console!") + to_chat(target, "New remote message received using R-SSH protocol:") + to_chat(target, message) + . = TOPIC_REFRESH + +// Proc: get_cyborgs() +// Parameters: 1 (operator - mob which is operating the console.) +// Description: Returns NanoUI-friendly list of accessible cyborgs. +/obj/machinery/computer/robotics/proc/get_cyborgs(var/mob/operator) + var/list/robots = list() + + for(var/mob/living/silicon/robot/R in GLOB.silicon_mob_list) + // Ignore drones + if(istype(R, /mob/living/silicon/robot/drone)) + continue + // Ignore antagonistic cyborgs + if(R.scrambledcodes) + continue + + var/list/robot = list() + robot["name"] = R.name + var/turf/T = get_turf(R) + var/area/A = get_area(T) + + if(istype(T) && istype(A) && (T.z in GLOB.using_map.contact_levels)) + robot["location"] = "[A.name] ([T.x], [T.y])" + else + robot["location"] = "Unknown" + + if(R.stat) + robot["status"] = "Not Responding" + else if (!R.canmove) + robot["status"] = "Lockdown" + else + robot["status"] = "Operational" + + if(R.cell) + robot["cell"] = 1 + robot["cell_capacity"] = R.cell.maxcharge + robot["cell_current"] = R.cell.charge + robot["cell_percentage"] = round(R.cell.percent()) + else + robot["cell"] = 0 + + robot["module"] = R.module ? R.module.name : "None" + robot["master_ai"] = R.connected_ai ? R.connected_ai.name : "None" + robot["hackable"] = 0 + // Antag AIs know whether linked cyborgs are hacked or not. + if(operator && istype(operator, /mob/living/silicon/ai) && (R.connected_ai == operator) && (operator.mind.special_role && operator.mind.original == operator)) + robot["hacked"] = R.emagged ? 1 : 0 + robot["hackable"] = R.emagged? 0 : 1 + robots.Add(list(robot)) + return robots + +// Proc: get_cyborg_by_name() +// Parameters: 1 (name - Cyborg we are trying to find) +// Description: Helper proc for finding cyborg by name +/obj/machinery/computer/robotics/proc/get_cyborg_by_name(var/name) + if (!name) + return + for(var/mob/living/silicon/robot/R in GLOB.silicon_mob_list) + if(R.name == name) + return R diff --git a/code/game/machinery/computer/shuttle.dm b/code/game/machinery/computer/shuttle.dm new file mode 100644 index 00000000..6f046dad --- /dev/null +++ b/code/game/machinery/computer/shuttle.dm @@ -0,0 +1,79 @@ +/obj/machinery/computer/shuttle + name = "Shuttle" + desc = "For shuttle control." + icon_keyboard = "tech_key" + icon_screen = "shuttle" + light_color = "#00ffff" + var/auth_need = 3.0 + var/list/authorized = list( ) + + + attackby(var/obj/item/weapon/card/W as obj, var/mob/user as mob) + if(stat & (BROKEN|NOPOWER)) return + + var/datum/evacuation_controller/shuttle/evac_control = evacuation_controller + if(!istype(evac_control)) + to_chat(user, "This console should not in use on this map. Please report this to a developer.") + return + + if ((!( istype(W, /obj/item/weapon/card) ) || !( ticker ) || evacuation_controller.has_evacuated() || !( user ))) + return + + if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) + if (istype(W, /obj/item/device/pda)) + var/obj/item/device/pda/pda = W + W = pda.id + if (!W:access) //no access + to_chat(user, "The access level of [W:registered_name]\'s card is not high enough. ") + return + + var/list/cardaccess = W:access + if(!istype(cardaccess, /list) || !cardaccess.len) //no access + to_chat(user, "The access level of [W:registered_name]\'s card is not high enough. ") + return + + if(!(access_heads in W:access)) //doesn't have this access + to_chat(user, "The access level of [W:registered_name]\'s card is not high enough. ") + return 0 + + var/choice = alert(user, text("Would you like to (un)authorize a shortened launch time? [] authorization\s are still needed. Use abort to cancel all authorizations.", src.auth_need - src.authorized.len), "Shuttle Launch", "Authorize", "Repeal", "Abort") + if(evacuation_controller.is_prepared() && user.get_active_hand() != W) + return 0 + switch(choice) + if("Authorize") + src.authorized -= W:registered_name + src.authorized += W:registered_name + if (src.auth_need - src.authorized.len > 0) + message_admins("[key_name_admin(user)] has authorized early shuttle launch") + log_game("[user.ckey] has authorized early shuttle launch") + to_world(text("Alert: [] authorizations needed until shuttle is launched early", src.auth_need - src.authorized.len)) + else + message_admins("[key_name_admin(user)] has launched the shuttle") + log_game("[user.ckey] has launched the shuttle early") + to_world("Alert: Shuttle launch time shortened to 10 seconds!") + evacuation_controller.set_launch_time(world.time+100) + //src.authorized = null + qdel(src.authorized) + src.authorized = list( ) + + if("Repeal") + src.authorized -= W:registered_name + to_world(text("Alert: [] authorizations needed until shuttle is launched early", src.auth_need - src.authorized.len)) + + if("Abort") + to_world("All authorizations to shortening time for shuttle launch have been revoked!") + src.authorized.len = 0 + src.authorized = list( ) + + else if (istype(W, /obj/item/weapon/card/emag) && !emagged) + var/choice = alert(user, "Would you like to launch the shuttle?","Shuttle control", "Launch", "Cancel") + + if(!emagged && !evacuation_controller.is_prepared() && user.get_active_hand() == W) + switch(choice) + if("Launch") + to_world("Alert: Shuttle launch time shortened to 10 seconds!") + evacuation_controller.set_launch_time(world.time+100) + emagged = 1 + if("Cancel") + return + return diff --git a/code/game/machinery/computer/station_alert.dm b/code/game/machinery/computer/station_alert.dm new file mode 100644 index 00000000..24d30cbd --- /dev/null +++ b/code/game/machinery/computer/station_alert.dm @@ -0,0 +1,64 @@ + +/obj/machinery/computer/station_alert + name = "alert console" + desc = "Used to access the automated alert system." + icon_keyboard = "tech_key" + icon_screen = "alert:0" + light_color = "#e6ffff" + circuit = /obj/item/weapon/circuitboard/stationalert + var/datum/nano_module/alarm_monitor/alarm_monitor + var/monitor_type = /datum/nano_module/alarm_monitor + +/obj/machinery/computer/station_alert/engineering + monitor_type = /datum/nano_module/alarm_monitor/engineering + +/obj/machinery/computer/station_alert/security + monitor_type = /datum/nano_module/alarm_monitor/security + +/obj/machinery/computer/station_alert/all + monitor_type = /datum/nano_module/alarm_monitor/all + +/obj/machinery/computer/station_alert/Initialize() + alarm_monitor = new monitor_type(src) + alarm_monitor.register_alarm(src, /obj/machinery/computer/station_alert/update_icon) + . = ..() + if(monitor_type) + register_monitor(new monitor_type(src)) + +/obj/machinery/computer/station_alert/Destroy() + . = ..() + unregister_monitor() + +/obj/machinery/computer/station_alert/proc/register_monitor(var/datum/nano_module/alarm_monitor/monitor) + if(monitor.host != src) + return + + alarm_monitor = monitor + alarm_monitor.register_alarm(src, /obj/machinery/computer/station_alert/update_icon) + +/obj/machinery/computer/station_alert/proc/unregister_monitor() + if(alarm_monitor) + alarm_monitor.unregister_alarm(src) + qdel(alarm_monitor) + alarm_monitor = null + +/obj/machinery/computer/station_alert/attack_ai(mob/user) + ui_interact(user) + +/obj/machinery/computer/station_alert/attack_hand(mob/user) + ui_interact(user) + +/obj/machinery/computer/station_alert/ui_interact(mob/user) + if(alarm_monitor) + alarm_monitor.ui_interact(user) + +/obj/machinery/computer/station_alert/nano_container() + return alarm_monitor + +/obj/machinery/computer/station_alert/update_icon() + icon_screen = initial(icon_screen) + if(!(stat & (BROKEN|NOPOWER))) + if(alarm_monitor) + if(alarm_monitor.has_major_alarms(get_z(src))) + icon_screen = "alert:2" + ..() diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm new file mode 100644 index 00000000..121d5b53 --- /dev/null +++ b/code/game/machinery/constructable_frame.dm @@ -0,0 +1,156 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +//Circuit boards are in /code/game/objects/items/weapons/circuitboards/machinery/ + +/obj/machinery/constructable_frame //Made into a seperate type to make future revisions easier. + name = "machine frame" + icon = 'icons/obj/stock_parts.dmi' + icon_state = "box_0" + density = 1 + anchored = 1 + use_power = 0 + var/obj/item/weapon/circuitboard/circuit = null + var/list/components = null + var/list/req_components = null + var/list/req_component_names = null + var/state = 1 + atom_flags = ATOM_FLAG_CLIMBABLE + + proc/update_desc() + var/D + if(req_components) + var/list/component_list = new + for(var/I in req_components) + if(req_components[I] > 0) + component_list += "[num2text(req_components[I])] [req_component_names[I]]" + D = "Requires [english_list(component_list)]." + desc = D + +/obj/machinery/constructable_frame/machine_frame + attackby(obj/item/P as obj, mob/user as mob) + switch(state) + if(1) + if(isCoil(P)) + var/obj/item/stack/cable_coil/C = P + if (C.get_amount() < 5) + to_chat(user, "You need five lengths of cable to add them to the frame.") + return + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + to_chat(user, "You start to add cables to the frame.") + if(do_after(user, 20, src) && state == 1) + if(C.use(5)) + to_chat(user, "You add cables to the frame.") + state = 2 + icon_state = "box_1" + else + if(isWrench(P)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + to_chat(user, "You dismantle the frame") + new /obj/item/stack/material/steel(src.loc, 5) + qdel(src) + if(2) + if(istype(P, /obj/item/weapon/circuitboard)) + var/obj/item/weapon/circuitboard/B = P + if(B.board_type == "machine") + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + to_chat(user, "You add the circuit board to the frame.") + circuit = P + user.drop_item() + P.loc = src + icon_state = "box_2" + state = 3 + components = list() + req_components = circuit.req_components.Copy() + for(var/A in circuit.req_components) + req_components[A] = circuit.req_components[A] + req_component_names = circuit.req_components.Copy() + for(var/A in req_components) + var/obj/ct = A + req_component_names[A] = initial(ct.name) + update_desc() + to_chat(user, desc) + else + to_chat(user, "This frame does not accept circuit boards of this type!") + else + if(isWirecutter(P)) + playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1) + to_chat(user, "You remove the cables.") + state = 1 + icon_state = "box_0" + var/obj/item/stack/cable_coil/A = new /obj/item/stack/cable_coil( src.loc ) + A.amount = 5 + + if(3) + if(isCrowbar(P)) + playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) + state = 2 + circuit.loc = src.loc + circuit = null + if(components.len == 0) + to_chat(user, "You remove the circuit board.") + else + to_chat(user, "You remove the circuit board and other components.") + for(var/obj/item/weapon/W in components) + W.loc = src.loc + desc = initial(desc) + req_components = null + components = null + icon_state = "box_1" + else + if(isScrewdriver(P)) + var/component_check = 1 + for(var/R in req_components) + if(req_components[R] > 0) + component_check = 0 + break + if(component_check) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + var/obj/machinery/new_machine = new src.circuit.build_path(src.loc, src.dir) + + if(new_machine.component_parts) + new_machine.component_parts.Cut() + else + new_machine.component_parts = list() + + src.circuit.construct(new_machine) + + for(var/obj/O in src) + if(circuit.contain_parts) // things like disposal don't want their parts in them + O.loc = new_machine + else + O.loc = null + new_machine.component_parts += O + + if(circuit.contain_parts) + circuit.loc = new_machine + else + circuit.loc = null + + new_machine.RefreshParts() + qdel(src) + else + if(istype(P, /obj/item)) + for(var/I in req_components) + if(istype(P, I) && (req_components[I] > 0)) + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + if(isCoil(P)) + var/obj/item/stack/cable_coil/CP = P + if(CP.get_amount() > 1) + var/camt = min(CP.amount, req_components[I]) // amount of cable to take, idealy amount required, but limited by amount provided + var/obj/item/stack/cable_coil/CC = new /obj/item/stack/cable_coil(src) + CC.amount = camt + CC.update_icon() + CP.use(camt) + components += CC + req_components[I] -= camt + update_desc() + break + user.drop_item() + P.loc = src + components += P + req_components[I]-- + update_desc() + break + to_chat(user, desc) + if(P && P.loc != src && !istype(P, /obj/item/stack/cable_coil)) + to_chat(user, "You cannot add that component to the machine!") diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm new file mode 100644 index 00000000..5a0f2a7e --- /dev/null +++ b/code/game/machinery/cryo.dm @@ -0,0 +1,378 @@ +#define HEAT_CAPACITY_HUMAN 100 //249840 J/K, for a 72 kg person. + +/obj/machinery/atmospherics/unary/cryo_cell + name = "cryo cell" + icon = 'icons/obj/cryogenics.dmi' // map only + icon_state = "pod_preview" + density = 1 + anchored = 1.0 + plane = ABOVE_HUMAN_PLANE // this needs to be fairly high so it displays over most things, but it needs to be under lighting + interact_offline = 1 + layer = ABOVE_HUMAN_LAYER + + var/on = 0 + use_power = 1 + idle_power_usage = 20 + active_power_usage = 200 + clicksound = 'sound/machines/buttonbeep.ogg' + clickvol = 30 + + var/temperature_archived + var/mob/living/carbon/human/occupant = null + var/obj/item/weapon/reagent_containers/glass/beaker = null + + var/current_heat_capacity = 50 + +/obj/machinery/atmospherics/unary/cryo_cell/New() + ..() + icon = 'icons/obj/cryogenics_split.dmi' + update_icon() + initialize_directions = dir + +/obj/machinery/atmospherics/unary/cryo_cell/Destroy() + var/turf/T = loc + T.contents += contents + if(beaker) + beaker.forceMove(get_step(loc, SOUTH)) //Beaker is carefully ejected from the wreckage of the cryotube + beaker = null + . = ..() + +/obj/machinery/atmospherics/unary/cryo_cell/atmos_init() + ..() + if(node) return + var/node_connect = dir + for(var/obj/machinery/atmospherics/target in get_step(src,node_connect)) + if(target.initialize_directions & get_dir(target,src)) + node = target + break + +/obj/machinery/atmospherics/unary/cryo_cell/Process() + ..() + if(!node) + return + if(!on) + return + + if(occupant) + if(occupant.stat != 2) + process_occupant() + + if(air_contents) + temperature_archived = air_contents.temperature + heat_gas_contents() + expel_gas() + + if(abs(temperature_archived-air_contents.temperature) > 1) + network.update = 1 + + return 1 + +/obj/machinery/atmospherics/unary/cryo_cell/relaymove(mob/user as mob) + // note that relaymove will also be called for mobs outside the cell with UI open + if(src.occupant == user && !user.stat) + go_out() + +/obj/machinery/atmospherics/unary/cryo_cell/attack_hand(mob/user) + ui_interact(user) + + /** + * The ui_interact proc is used to open and update Nano UIs + * If ui_interact is not used then the UI will not update correctly + * ui_interact is currently defined for /atom/movable (which is inherited by /obj and /mob) + * + * @param user /mob The mob who is interacting with this ui + * @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main") + * @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui + * + * @return nothing + */ +/obj/machinery/atmospherics/unary/cryo_cell/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + + if(user == occupant || user.stat) + return + + // this is the data which will be sent to the ui + var/data[0] + data["isOperating"] = on + data["hasOccupant"] = occupant ? 1 : 0 + + if (occupant) + var/cloneloss = "none" + var/amount = occupant.getCloneLoss() + if(amount > 50) + cloneloss = "severe" + else if(amount > 25) + cloneloss = "significant" + else if(amount > 10) + cloneloss = "moderate" + else if(amount) + cloneloss = "minor" + var/scan = medical_scan_results(occupant) + scan += "

    Genetic degradation: [cloneloss]" + scan = replacetext(scan,"'notice'","'white'") + scan = replacetext(scan,"'warning'","'average'") + scan = replacetext(scan,"'danger'","'bad'") + scan += "
    Cryostasis factor: [occupant.stasis_value]x" + data["occupant"] = scan + + data["cellTemperature"] = round(air_contents.temperature) + data["cellTemperatureStatus"] = "good" + if(air_contents.temperature > T0C) // if greater than 273.15 kelvin (0 celcius) + data["cellTemperatureStatus"] = "bad" + else if(air_contents.temperature > 225) + data["cellTemperatureStatus"] = "average" + + data["isBeakerLoaded"] = beaker ? 1 : 0 + + data["beakerLabel"] = null + data["beakerVolume"] = 0 + if(beaker) + data["beakerLabel"] = beaker.name + data["beakerVolume"] = beaker.reagents.total_volume + + // update the ui if it exists, returns null if no ui is passed/found + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "cryo.tmpl", "Cryo Cell Control System", 520, 410) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(1) + +/obj/machinery/atmospherics/unary/cryo_cell/OnTopic(user, href_list) + if(user == occupant) + return STATUS_CLOSE + return ..() + +/obj/machinery/atmospherics/unary/cryo_cell/OnTopic(user, href_list) + if(href_list["switchOn"]) + on = 1 + update_icon() + return TOPIC_REFRESH + + if(href_list["switchOff"]) + on = 0 + update_icon() + return TOPIC_REFRESH + + if(href_list["ejectBeaker"]) + if(beaker) + beaker.forceMove(get_step(loc, SOUTH)) + beaker = null + return TOPIC_REFRESH + + if(href_list["ejectOccupant"]) + if(!occupant || isslime(user) || ispAI(user)) + return TOPIC_HANDLED // don't update UIs attached to this object + go_out() + return TOPIC_REFRESH + + +/obj/machinery/atmospherics/unary/cryo_cell/attackby(var/obj/G, var/mob/user as mob) + if(istype(G, /obj/item/weapon/reagent_containers/glass)) + if(beaker) + to_chat(user, "A beaker is already loaded into the machine.") + return + + beaker = G + user.drop_item() + G.forceMove(src) + user.visible_message("[user] adds \a [G] to \the [src]!", "You add \a [G] to \the [src]!") + else if(istype(G, /obj/item/grab)) + if(!ismob(G:affecting)) + return + for(var/mob/living/carbon/slime/M in range(1,G:affecting)) + if(M.Victim == G:affecting) + to_chat(usr, "[G:affecting:name] will not fit into the cryo because they have a slime latched onto their head.") + return + var/mob/M = G:affecting + if(put_mob(M)) + qdel(G) + return + +/obj/machinery/atmospherics/unary/cryo_cell/update_icon() + overlays.Cut() + icon_state = "pod[on]" + var/image/I + + I = image(icon, "pod[on]_top") + I.pixel_z = 32 + overlays += I + + if(occupant) + var/image/pickle = image(occupant.icon, occupant.icon_state) + pickle.overlays = occupant.overlays + pickle.pixel_z = 18 + overlays += pickle + + I = image(icon, "lid[on]") + overlays += I + + I = image(icon, "lid[on]_top") + I.pixel_z = 32 + overlays += I + +/obj/machinery/atmospherics/unary/cryo_cell/proc/process_occupant() + if(air_contents.total_moles < 10) + return + if(occupant) + if(occupant.stat == DEAD) + return + occupant.set_stat(UNCONSCIOUS) + if(occupant.bodytemperature < 225) + if (occupant.getToxLoss()) + occupant.adjustToxLoss(max(-1, -10/occupant.getToxLoss())) + var/heal_brute = occupant.getBruteLoss() ? min(1, 20/occupant.getBruteLoss()) : 0 + var/heal_fire = occupant.getFireLoss () ? min(1, 20/occupant.getFireLoss()) : 0 + occupant.heal_organ_damage(heal_brute,heal_fire) + var/has_cryo_medicine = occupant.reagents.has_any_reagent(list(/datum/reagent/cryoxadone, /datum/reagent/clonexadone)) >= REM + if(beaker && !has_cryo_medicine) + beaker.reagents.trans_to_mob(occupant, REM, CHEM_BLOOD) + +/obj/machinery/atmospherics/unary/cryo_cell/proc/heat_gas_contents() + if(air_contents.total_moles < 1) + return + var/air_heat_capacity = air_contents.heat_capacity() + var/combined_heat_capacity = current_heat_capacity + air_heat_capacity + if(combined_heat_capacity > 0) + var/combined_energy = T20C*current_heat_capacity + air_heat_capacity*air_contents.temperature + air_contents.temperature = combined_energy/combined_heat_capacity + +/obj/machinery/atmospherics/unary/cryo_cell/proc/expel_gas() + if(air_contents.total_moles < 1) + return +// var/datum/gas_mixture/expel_gas = new +// var/remove_amount = air_contents.total_moles()/50 +// expel_gas = air_contents.remove(remove_amount) + + // Just have the gas disappear to nowhere. + //expel_gas.temperature = T20C // Lets expel hot gas and see if that helps people not die as they are removed + //loc.assume_air(expel_gas) + +/obj/machinery/atmospherics/unary/cryo_cell/proc/go_out() + if(!( occupant )) + return + //for(var/obj/O in src) + // O.loc = loc + if (occupant.client) + occupant.client.eye = occupant.client.mob + occupant.client.perspective = MOB_PERSPECTIVE + occupant.forceMove(get_step(loc, SOUTH)) //this doesn't account for walls or anything, but i don't forsee that being a problem. + if (occupant.bodytemperature < 261 && occupant.bodytemperature >= 70) //Patch by Aranclanos to stop people from taking burn damage after being ejected + occupant.bodytemperature = 261 // Changed to 70 from 140 by Zuhayr due to reoccurance of bug. + occupant = null + current_heat_capacity = initial(current_heat_capacity) + update_use_power(1) + update_icon() + return +/obj/machinery/atmospherics/unary/cryo_cell/proc/put_mob(mob/living/carbon/M as mob) + if (stat & (NOPOWER|BROKEN)) + to_chat(usr, "The cryo cell is not functioning.") + return + if (!istype(M)) + to_chat(usr, "The cryo cell cannot handle such a lifeform!") + return + if (occupant) + to_chat(usr, "The cryo cell is already occupied!") + return + if (M.abiotic()) + to_chat(usr, "Subject may not have abiotic items on.") + return + if(!node) + to_chat(usr, "The cell is not correctly connected to its pipe network!") + return + if (M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.stop_pulling() + M.forceMove(src) + M.ExtinguishMob() + if(M.health > -100 && (M.health < 0 || M.sleeping)) + to_chat(M, "You feel a cold liquid surround you. Your skin starts to freeze up.") + occupant = M + current_heat_capacity = HEAT_CAPACITY_HUMAN + update_use_power(2) +// M.metabslow = 1 + add_fingerprint(usr) + update_icon() + return 1 + + //Like grab-putting, but for mouse-dropping. +/obj/machinery/atmospherics/unary/cryo_cell/MouseDrop_T(var/mob/target, var/mob/user) + if(!CanMouseDrop(target, user)) + return + if (!istype(target)) + return + if (target.buckled) + to_chat(user, "Unbuckle the subject before attempting to move them.") + return + user.visible_message("\The [user] begins placing \the [target] into \the [src].", "You start placing \the [target] into \the [src].") + if(!do_after(user, 30, src)) + return + put_mob(target) + + +/obj/machinery/atmospherics/unary/cryo_cell/proc/move_eject() + set name = "Eject occupant" + set category = "Object" + if(usr == occupant)//If the user is inside the tube... + if (usr.stat == 2)//and he's not dead.... + return + to_chat(usr, "Release sequence activated. This will take two minutes.") + sleep(1200) + if(!src || !usr || !occupant || (occupant != usr)) //Check if someone's released/replaced/bombed him already + return + go_out()//and release him from the eternal prison. + else + if (usr.stat != 0) + return + go_out() + add_fingerprint(usr) + return + +/obj/machinery/atmospherics/unary/cryo_cell/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + move_eject() + +/obj/machinery/atmospherics/unary/cryo_cell/verb/move_inside() + set name = "Move Inside" + set category = "Object" + set src in oview(1) + for(var/mob/living/carbon/slime/M in range(1,usr)) + if(M.Victim == usr) + to_chat(usr, "You're too busy getting your life sucked out of you.") + return + if (usr.stat != 0) + return + put_mob(usr) + return + +/obj/machinery/atmospherics/unary/cryo_cell/return_air() + if(on) + return air_contents + ..() + +//This proc literally only exists for cryo cells. +/atom/proc/return_air_for_internal_lifeform() + return return_air() + +/obj/machinery/atmospherics/unary/cryo_cell/return_air_for_internal_lifeform() + //assume that the cryo cell has some kind of breath mask or something that + //draws from the cryo tube's environment, instead of the cold internal air. + if(loc) + return loc.return_air() + else + return null + +/datum/data/function/proc/reset() + return + +/datum/data/function/proc/r_input(href, href_list, mob/user as mob) + return + +/datum/data/function/proc/display() + return diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm new file mode 100644 index 00000000..8d0a33c8 --- /dev/null +++ b/code/game/machinery/cryopod.dm @@ -0,0 +1,561 @@ +/* + * Cryogenic refrigeration unit. Basically a despawner. + * Stealing a lot of concepts/code from sleepers due to massive laziness. + * The despawn tick will only fire if it's been more than time_till_despawned ticks + * since time_entered, which is world.time when the occupant moves in. + * ~ Zuhayr + */ + + +//Main cryopod console. + +/obj/machinery/computer/cryopod + name = "cryogenic oversight console" + desc = "An interface between crew and the cryogenic storage oversight systems." + icon = 'icons/obj/Cryogenic2.dmi' + icon_state = "cellconsole" + circuit = /obj/item/weapon/circuitboard/cryopodcontrol + density = 0 + interact_offline = 1 + var/mode = null + + //Used for logging people entering cryosleep and important items they are carrying. + var/list/frozen_crew = list() + var/list/frozen_items = list() + var/list/_admin_logs = list() // _ so it shows first in VV + + var/storage_type = "crewmembers" + var/storage_name = "Cryogenic Oversight Control" + var/allow_items = 1 + +/obj/machinery/computer/cryopod/robot + name = "robotic storage console" + desc = "An interface between crew and the robotic storage systems." + icon = 'icons/obj/robot_storage.dmi' + icon_state = "console" + circuit = /obj/item/weapon/circuitboard/robotstoragecontrol + + storage_type = "cyborgs" + storage_name = "Robotic Storage Control" + allow_items = 0 + +/obj/machinery/computer/cryopod/attack_ai() + src.attack_hand() + +/obj/machinery/computer/cryopod/attack_hand(mob/user = usr) + if(stat & (NOPOWER|BROKEN)) + return + ..() + + user.set_machine(src) + + var/dat + + if (!( ticker )) + return + + dat += "

    [storage_name]
    " + dat += "Welcome, [user.real_name].


    " + dat += "View storage log.
    " + if(allow_items) + dat += "View objects.
    " + dat += "Recover object.
    " + dat += "Recover all objects.
    " + + user << browse(dat, "window=cryopod_console") + onclose(user, "cryopod_console") + +/obj/machinery/computer/cryopod/OnTopic(user, href_list, state) + if(href_list["log"]) + var/dat = "Recently stored [storage_type]


    " + for(var/person in frozen_crew) + dat += "[person]
    " + dat += "
    " + show_browser(user, dat, "window=cryolog") + . = TOPIC_REFRESH + + else if(href_list["view"]) + if(!allow_items) return + + var/dat = "Recently stored objects


    " + for(var/obj/item/I in frozen_items) + dat += "[I.name]
    " + dat += "
    " + + show_browser(user, dat, "window=cryoitems") + . = TOPIC_HANDLED + + else if(href_list["item"]) + if(!allow_items) return + + if(frozen_items.len == 0) + to_chat(user, "There is nothing to recover from storage.") + return TOPIC_HANDLED + + var/obj/item/I = input(user, "Please choose which object to retrieve.","Object recovery",null) as null|anything in frozen_items + if(!I || !CanUseTopic(user, state)) + return TOPIC_HANDLED + + if(!(I in frozen_items)) + to_chat(user, "\The [I] is no longer in storage.") + return TOPIC_HANDLED + + visible_message("The console beeps happily as it disgorges \the [I].", 3) + + I.dropInto(loc) + frozen_items -= I + . = TOPIC_REFRESH + + else if(href_list["allitems"]) + if(!allow_items) return TOPIC_HANDLED + + if(frozen_items.len == 0) + to_chat(user, "There is nothing to recover from storage.") + return TOPIC_HANDLED + + visible_message("The console beeps happily as it disgorges the desired objects.", 3) + + for(var/obj/item/I in frozen_items) + I.dropInto(loc) + frozen_items -= I + . = TOPIC_REFRESH + + attack_hand(user) + +/obj/item/weapon/circuitboard/cryopodcontrol + name = "Circuit board (Cryogenic Oversight Console)" + build_path = /obj/machinery/computer/cryopod + origin_tech = list(TECH_DATA = 3) + +/obj/item/weapon/circuitboard/robotstoragecontrol + name = "Circuit board (Robotic Storage Console)" + build_path = /obj/machinery/computer/cryopod/robot + origin_tech = list(TECH_DATA = 3) + +//Decorative structures to go alongside cryopods. +/obj/structure/cryofeed + + name = "cryogenic feed" + desc = "A bewildering tangle of machinery and pipes." + icon = 'icons/obj/Cryogenic2.dmi' + icon_state = "cryo_rear" + anchored = 1 + dir = WEST + +//Cryopods themselves. +/obj/machinery/cryopod + name = "cryogenic freezer" + desc = "A man-sized pod for entering suspended animation." + icon = 'icons/obj/Cryogenic2.dmi' + icon_state = "body_scanner_0" + density = 1 + anchored = 1 + dir = WEST + + var/base_icon_state = "body_scanner_0" + var/occupied_icon_state = "body_scanner_1" + var/on_store_message = "has entered long-term storage." + var/on_store_name = "Cryogenic Oversight" + var/on_enter_occupant_message = "You feel cool air surround you. You go numb as your senses turn inward." + var/allow_occupant_types = list(/mob/living/carbon/human) + var/disallow_occupant_types = list() + + var/mob/occupant = null // Person waiting to be despawned. + var/time_till_despawn = 9000 // Down to 15 minutes //30 minutes-ish is too long + var/time_entered = 0 // Used to keep track of the safe period. + var/obj/item/device/radio/intercom/announce // + + var/obj/machinery/computer/cryopod/control_computer + var/last_no_computer_message = 0 + var/applies_stasis = 1 + + // These items are preserved when the process() despawn proc occurs. + var/list/preserve_items = list( + /obj/item/integrated_circuit/manipulation/bluespace_rift, + /obj/item/integrated_circuit/input/teleporter_locator, + /obj/item/weapon/card/id/captains_spare, + /obj/item/weapon/aicard, + /obj/item/device/mmi, + /obj/item/device/paicard, + /obj/item/weapon/gun, + /obj/item/weapon/pinpointer, + /obj/item/clothing/suit, + /obj/item/clothing/shoes/magboots, + /obj/item/blueprints, + /obj/item/clothing/head/helmet/space, + /obj/item/weapon/storage/internal + ) + +/obj/machinery/cryopod/robot + name = "robotic storage unit" + desc = "A storage unit for robots." + icon = 'icons/obj/robot_storage.dmi' + icon_state = "pod_0" + base_icon_state = "pod_0" + occupied_icon_state = "pod_1" + on_store_message = "has entered robotic storage." + on_store_name = "Robotic Storage Oversight" + on_enter_occupant_message = "The storage unit broadcasts a sleep signal to you. Your systems start to shut down, and you enter low-power mode." + allow_occupant_types = list(/mob/living/silicon/robot) + disallow_occupant_types = list(/mob/living/silicon/robot/drone) + applies_stasis = 0 + +/obj/machinery/cryopod/lifepod + name = "life pod" + desc = "A man-sized pod for entering suspended animation. Dubbed 'cryocoffin' by more cynical spacers, it is pretty barebone, counting on stasis system to keep the victim alive rather than packing extended supply of food or air. Can be ordered with symbols of common religious denominations to be used in space funerals too." + on_store_name = "Life Pod Oversight" + time_till_despawn = 20 MINUTES + icon_state = "redpod0" + base_icon_state = "redpod0" + occupied_icon_state = "redpod1" + var/launched = 0 + var/datum/gas_mixture/airtank + +/obj/machinery/cryopod/lifepod/Initialize() + . = ..() + airtank = new() + airtank.temperature = T0C + airtank.adjust_gas("oxygen", MOLES_O2STANDARD, 0) + airtank.adjust_gas("nitrogen", MOLES_N2STANDARD) + +/obj/machinery/cryopod/lifepod/return_air() + return airtank + +/obj/machinery/cryopod/lifepod/proc/launch() + launched = 1 + for(var/d in GLOB.cardinal) + var/turf/T = get_step(src,d) + var/obj/machinery/door/blast/B = locate() in T + if(B && B.density) + B.force_open() + break + + var/list/possible_locations = list() + if(GLOB.using_map.use_overmap) + var/obj/effect/overmap/O = map_sectors["[z]"] + for(var/obj/effect/overmap/OO in range(O,2)) + if(OO.in_space || istype(OO,/obj/effect/overmap/sector/exoplanet)) + possible_locations |= text2num(level) + + var/newz = GLOB.using_map.get_empty_zlevel() + if(possible_locations.len && prob(10)) + newz = pick(possible_locations) + var/turf/nloc = locate(rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE), rand(TRANSITIONEDGE, world.maxy-TRANSITIONEDGE),newz) + if(!istype(nloc, /turf/space)) + explosion(nloc, 1, 2, 3) + playsound(loc,'sound/effects/rocket.ogg',100) + forceMove(nloc) + +//Don't use these for in-round leaving +/obj/machinery/cryopod/lifepod/Process() + if(evacuation_controller && evacuation_controller.state >= EVAC_LAUNCHING) + if(occupant && !launched) + launch() + ..() + +/obj/machinery/cryopod/New() + announce = new /obj/item/device/radio/intercom(src) + ..() + +/obj/machinery/cryopod/Destroy() + if(occupant) + occupant.forceMove(loc) + occupant.resting = 1 + return ..() + +/obj/machinery/cryopod/Initialize() + . = ..() + find_control_computer() + +/obj/machinery/cryopod/proc/find_control_computer(urgent=0) + // Workaround for http://www.byond.com/forum/?post=2007448 + for(var/obj/machinery/computer/cryopod/C in src.loc.loc) + control_computer = C + break + // control_computer = locate(/obj/machinery/computer/cryopod) in src.loc.loc + + // Don't send messages unless we *need* the computer, and less than five minutes have passed since last time we messaged + if(!control_computer && urgent && last_no_computer_message + 5*60*10 < world.time) + log_admin("Cryopod in [src.loc.loc] could not find control computer!") + message_admins("Cryopod in [src.loc.loc] could not find control computer!") + last_no_computer_message = world.time + + return control_computer != null + +/obj/machinery/cryopod/proc/check_occupant_allowed(mob/M) + var/correct_type = 0 + for(var/type in allow_occupant_types) + if(istype(M, type)) + correct_type = 1 + break + + if(!correct_type) return 0 + + for(var/type in disallow_occupant_types) + if(istype(M, type)) + return 0 + + return 1 + +//Lifted from Unity stasis.dm and refactored. ~Zuhayr +/obj/machinery/cryopod/Process() + if(occupant) + if(applies_stasis && iscarbon(occupant)) + var/mob/living/carbon/C = occupant + C.SetStasis(3) + + //Allow a ten minute gap between entering the pod and actually despawning. + if(world.time - time_entered < time_till_despawn) + return + + if(!occupant.client && occupant.stat<2) //Occupant is living and has no client. + if(!control_computer) + if(!find_control_computer(urgent=1)) + return + + despawn_occupant() + +// This function can not be undone; do not call this unless you are sure +// Also make sure there is a valid control computer +/obj/machinery/cryopod/robot/despawn_occupant() + var/mob/living/silicon/robot/R = occupant + if(!istype(R)) return ..() + + qdel(R.mmi) + for(var/obj/item/I in R.module) // the tools the borg has; metal, glass, guns etc + for(var/obj/item/O in I) // the things inside the tools, if anything; mainly for janiborg trash bags + O.forceMove(R) + qdel(I) + qdel(R.module) + + return ..() + +// This function can not be undone; do not call this unless you are sure +// Also make sure there is a valid control computer +/obj/machinery/cryopod/proc/despawn_occupant() + //Drop all items into the pod. + for(var/obj/item/W in occupant) + occupant.drop_from_inventory(W) + W.forceMove(src) + + if(W.contents.len) //Make sure we catch anything not handled by qdel() on the items. + for(var/obj/item/O in W.contents) + if(istype(O,/obj/item/weapon/storage/internal)) //Stop eating pockets, you fuck! + continue + O.forceMove(src) + + //Delete all items not on the preservation list. + var/list/items = src.contents.Copy() + items -= occupant // Don't delete the occupant + items -= announce // or the autosay radio. + + for(var/obj/item/W in items) + + var/preserve = null + // Snowflaaaake. + if(istype(W, /obj/item/device/mmi)) + var/obj/item/device/mmi/brain = W + if(brain.brainmob && brain.brainmob.client && brain.brainmob.key) + preserve = 1 + else + continue + else + for(var/T in preserve_items) + if(istype(W,T)) + preserve = 1 + break + + if(!preserve) + qdel(W) + else + if(control_computer && control_computer.allow_items) + control_computer.frozen_items += W + W.loc = null + else + W.forceMove(src.loc) + + //Update any existing objectives involving this mob. + for(var/datum/objective/O in all_objectives) + // We don't want revs to get objectives that aren't for heads of staff. Letting + // them win or lose based on cryo is silly so we remove the objective. + if(O.target == occupant.mind) + if(O.owner && O.owner.current) + to_chat(O.owner.current, "You get the feeling your target is no longer within your reach...") + qdel(O) + + //Handle job slot/tater cleanup. + if(occupant.mind) + var/job = occupant.mind.assigned_role + job_master.FreeRole(job) + + if(occupant.mind.objectives.len) + occupant.mind.objectives = null + occupant.mind.special_role = null + //else + //if(ticker.mode.name == "AutoTraitor") + //var/datum/game_mode/traitor/autotraitor/current_mode = ticker.mode + //current_mode.possible_traitors.Remove(occupant) + + // Delete them from datacore. + var/datum/computer_file/crew_record/R = get_crewmember_record(occupant.real_name) + if(R) + qdel(R) + + icon_state = base_icon_state + + //TODO: Check objectives/mode, update new targets if this mob is the target, spawn new antags? + + + //Make an announcement and log the person entering storage. + + // Titles should really be fetched from data records + // and records should not be fetched by name as there is no guarantee names are unique + var/role_alt_title = occupant.mind ? occupant.mind.role_alt_title : "Unknown" + + if(control_computer) + control_computer.frozen_crew += "[occupant.real_name], [role_alt_title] - [stationtime2text()]" + control_computer._admin_logs += "[key_name(occupant)] ([role_alt_title]) at [stationtime2text()]" + log_and_message_admins("[key_name(occupant)] ([role_alt_title]) entered cryostorage.") + + announce.autosay("[occupant.real_name], [role_alt_title], [on_store_message]", "[on_store_name]") + visible_message("\The [initial(name)] hums and hisses as it moves [occupant.real_name] into storage.", 3) + + //This should guarantee that ghosts don't spawn. + occupant.ckey = null + + // Delete the mob. + qdel(occupant) + set_occupant(null) + + +/obj/machinery/cryopod/attackby(var/obj/item/weapon/G as obj, var/mob/user as mob) + + if(istype(G, /obj/item/grab)) + var/obj/item/grab/grab = G + if(occupant) + to_chat(user, "\The [src] is in use.") + return + + if(!ismob(grab.affecting)) + return + + if(!check_occupant_allowed(grab.affecting)) + return + + var/willing = null //We don't want to allow people to be forced into despawning. + var/mob/M = G:affecting + + if(M.client) + if(alert(M,"Would you like to enter long-term storage?",,"Yes","No") == "Yes") + if(!M || !grab || !grab.affecting) return + willing = 1 + else + willing = 1 + + if(willing) + + visible_message("[user] starts putting [grab.affecting:name] into \the [src].", 3) + + if(do_after(user, 20, src)) + if(!M || !grab || !grab.affecting) return + + set_occupant(M) + + // Book keeping! + var/turf/location = get_turf(src) + log_admin("[key_name_admin(M)] has entered a stasis pod. (JMP)") + message_admins("[key_name_admin(M)] has entered a stasis pod.") + + //Despawning occurs when process() is called with an occupant without a client. + src.add_fingerprint(M) + +/obj/machinery/cryopod/verb/eject() + set name = "Eject Pod" + set category = "Object" + set src in oview(1) + if(usr.stat != 0) + return + + icon_state = base_icon_state + + //Eject any items that aren't meant to be in the pod. + var/list/items = src.contents + if(occupant) items -= occupant + if(announce) items -= announce + + for(var/obj/item/W in items) + W.forceMove(get_turf(src)) + + src.go_out() + add_fingerprint(usr) + + SetName(initial(name)) + return + +/obj/machinery/cryopod/verb/move_inside() + set name = "Enter Pod" + set category = "Object" + set src in oview(1) + + if(usr.stat != 0 || !check_occupant_allowed(usr)) + return + + if(src.occupant) + to_chat(usr, "\The [src] is in use.") + return + + for(var/mob/living/carbon/slime/M in range(1,usr)) + if(M.Victim == usr) + to_chat(usr, "You're too busy getting your life sucked out of you.") + return + + visible_message("[usr] starts climbing into \the [src].", 3) + + if(do_after(usr, 20, src)) + + if(!usr || !usr.client) + return + + if(src.occupant) + to_chat(usr, "\The [src] is in use.") + return + + set_occupant(usr) + + src.add_fingerprint(usr) + + return + +/obj/machinery/cryopod/proc/go_out() + + if(!occupant) + return + + if(occupant.client) + occupant.client.eye = src.occupant.client.mob + occupant.client.perspective = MOB_PERSPECTIVE + + occupant.forceMove(get_turf(src)) + set_occupant(null) + + icon_state = base_icon_state + + return + +/obj/machinery/cryopod/proc/set_occupant(var/mob/living/carbon/occupant) + src.occupant = occupant + if(!occupant) + SetName(initial(name)) + return + + occupant.stop_pulling() + if(occupant.client) + to_chat(occupant, "[on_enter_occupant_message]") + to_chat(occupant, "If you ghost, log out or close your client now, your character will shortly be permanently removed from the round.") + occupant.client.perspective = EYE_PERSPECTIVE + occupant.client.eye = src + occupant.forceMove(src) + time_entered = world.time + + SetName("[name] ([occupant])") + icon_state = occupied_icon_state diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm new file mode 100644 index 00000000..050673a1 --- /dev/null +++ b/code/game/machinery/deployable.dm @@ -0,0 +1,270 @@ +/* +CONTAINS: + +Deployable items +Barricades + +for reference: + + access_security = 1 + access_brig = 2 + access_armory = 3 + access_forensics_lockers= 4 + access_medical = 5 + access_morgue = 6 + access_tox = 7 + access_tox_storage = 8 + access_genetics = 9 + access_engine = 10 + access_engine_equip= 11 + access_maint_tunnels = 12 + access_external_airlocks = 13 + access_emergency_storage = 14 + access_change_ids = 15 + access_ai_upload = 16 + access_teleporter = 17 + access_eva = 18 + access_heads = 19 + access_captain = 20 + access_all_personal_lockers = 21 + access_chapel_office = 22 + access_tech_storage = 23 + access_atmospherics = 24 + access_bar = 25 + access_janitor = 26 + access_crematorium = 27 + access_kitchen = 28 + access_robotics = 29 + access_rd = 30 + access_cargo = 31 + access_construction = 32 + access_chemistry = 33 + access_cargo_bot = 34 + access_hydroponics = 35 + access_manufacturing = 36 + access_library = 37 + access_lawyer = 38 + access_virology = 39 + access_cmo = 40 + access_qm = 41 + access_court = 42 + access_clown = 43 + access_mime = 44 + +*/ + +//Barricades! +/obj/structure/barricade + name = "barricade" + desc = "This space is blocked off by a barricade." + icon = 'icons/obj/structures.dmi' + icon_state = "barricade" + anchored = 1.0 + density = 1 + var/health = 100 + var/maxhealth = 100 + var/material/material + atom_flags = ATOM_FLAG_CLIMBABLE + +/obj/structure/barricade/New(var/newloc, var/material_name) + ..(newloc) + if(!material_name) + material_name = "wood" + material = get_material_by_name("[material_name]") + if(!material) + qdel(src) + return + name = "[material.display_name] barricade" + desc = "This space is blocked off by a barricade made of [material.display_name]." + color = material.icon_colour + maxhealth = material.integrity + health = maxhealth + +/obj/structure/barricade/get_material() + return material + +/obj/structure/barricade/attackby(obj/item/W as obj, mob/user as mob) + if (istype(W, /obj/item/stack)) + var/obj/item/stack/D = W + if(D.get_material_name() != material.name) + return //hitting things with the wrong type of stack usually doesn't produce messages, and probably doesn't need to. + if (health < maxhealth) + if (D.get_amount() < 1) + to_chat(user, "You need one sheet of [material.display_name] to repair \the [src].") + return + visible_message("[user] begins to repair \the [src].") + if(do_after(user,20,src) && health < maxhealth) + if (D.use(1)) + health = maxhealth + visible_message("[user] repairs \the [src].") + return + return + else + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + switch(W.damtype) + if("fire") + src.health -= W.force * 1 + if("brute") + src.health -= W.force * 0.75 + else + if (src.health <= 0) + visible_message("The barricade is smashed apart!") + dismantle() + qdel(src) + return + ..() + +/obj/structure/barricade/proc/dismantle() + material.place_dismantled_product(get_turf(src)) + qdel(src) + return + +/obj/structure/barricade/ex_act(severity) + switch(severity) + if(1.0) + visible_message("\The [src] is blown apart!") + qdel(src) + return + if(2.0) + src.health -= 25 + if (src.health <= 0) + visible_message("\The [src] is blown apart!") + dismantle() + return + +/obj/structure/barricade/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)//So bullets will fly over and stuff. + if(air_group || (height==0)) + return 1 + if(istype(mover) && mover.checkpass(PASS_FLAG_TABLE)) + return 1 + else + return 0 + +//Actual Deployable machinery stuff +/obj/machinery/deployable + name = "deployable" + desc = "Deployable." + icon = 'icons/obj/objects.dmi' + req_access = list(access_security)//I'm changing this until these are properly tested./N + +/obj/machinery/deployable/barrier + name = "deployable barrier" + desc = "A deployable barrier. Swipe your ID card to lock/unlock it." + icon = 'icons/obj/objects.dmi' + anchored = 0.0 + density = 1 + icon_state = "barrier0" + var/health = 100.0 + var/maxhealth = 100.0 + var/locked = 0.0 +// req_access = list(access_maint_tunnels) + + New() + ..() + + src.icon_state = "barrier[src.locked]" + + attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/card/id/)) + if (src.allowed(user)) + if (src.emagged < 2.0) + src.locked = !src.locked + src.anchored = !src.anchored + src.icon_state = "barrier[src.locked]" + if ((src.locked == 1.0) && (src.emagged < 2.0)) + to_chat(user, "Barrier lock toggled on.") + return + else if ((src.locked == 0.0) && (src.emagged < 2.0)) + to_chat(user, "Barrier lock toggled off.") + return + else + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, src) + s.start() + visible_message("BZZzZZzZZzZT") + return + return + else if(isWrench(W)) + if (src.health < src.maxhealth) + src.health = src.maxhealth + src.emagged = 0 + src.req_access = list(access_security) + visible_message("[user] repairs \the [src]!") + return + else if (src.emagged > 0) + src.emagged = 0 + src.req_access = list(access_security) + visible_message("[user] repairs \the [src]!") + return + return + else + switch(W.damtype) + if("fire") + src.health -= W.force * 0.75 + if("brute") + src.health -= W.force * 0.5 + else + if (src.health <= 0) + src.explode() + ..() + + ex_act(severity) + switch(severity) + if(1.0) + src.explode() + return + if(2.0) + src.health -= 25 + if (src.health <= 0) + src.explode() + return + emp_act(severity) + if(stat & (BROKEN|NOPOWER)) + return + if(prob(50/severity)) + locked = !locked + anchored = !anchored + icon_state = "barrier[src.locked]" + + CanPass(atom/movable/mover, turf/target, height=0, air_group=0)//So bullets will fly over and stuff. + if(air_group || (height==0)) + return 1 + if(istype(mover) && mover.checkpass(PASS_FLAG_TABLE)) + return 1 + else + return 0 + + proc/explode() + + visible_message("[src] blows apart!") + var/turf/Tsec = get_turf(src) + new /obj/item/stack/rods(Tsec) + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + + explosion(src.loc,-1,-1,0) + if(src) + qdel(src) + + +/obj/machinery/deployable/barrier/emag_act(var/remaining_charges, var/mob/user) + if (src.emagged == 0) + src.emagged = 1 + src.req_access.Cut() + src.req_one_access.Cut() + to_chat(user, "You break the ID authentication lock on \the [src].") + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, src) + s.start() + visible_message("BZZzZZzZZzZT") + return 1 + else if (src.emagged == 1) + src.emagged = 2 + to_chat(user, "You short out the anchoring mechanism on \the [src].") + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, src) + s.start() + visible_message("BZZzZZzZZzZT") + return 1 diff --git a/code/game/machinery/door_control.dm b/code/game/machinery/door_control.dm new file mode 100644 index 00000000..5092adee --- /dev/null +++ b/code/game/machinery/door_control.dm @@ -0,0 +1,281 @@ +/obj/machinery/button/remote + name = "remote object control" + desc = "It controls objects, remotely." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "doorctrl" + power_channel = ENVIRON + var/desiredstate = 0 + var/exposedwires = 0 + var/wires = 3 + /* + Bitflag, 1=checkID + 2=Network Access + */ + + anchored = 1.0 + use_power = 1 + idle_power_usage = 2 + active_power_usage = 4 + +/obj/machinery/button/remote/attack_ai(mob/user as mob) + if(wires & 2) + return src.attack_hand(user) + else + to_chat(user, "Error, no route to host.") + +/obj/machinery/button/remote/attackby(obj/item/weapon/W, mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/button/remote/emag_act(var/remaining_charges, var/mob/user) + if(req_access.len || req_one_access.len) + req_access = list() + req_one_access = list() + playsound(src.loc, "sparks", 100, 1) + return 1 + +/obj/machinery/button/remote/attack_hand(mob/user as mob) + if(..()) + return + + if(stat & (NOPOWER|BROKEN)) + return + + if(!allowed(user) && (wires & 1)) + to_chat(user, "Access Denied") + flick("[initial(icon_state)]-denied",src) + return + + use_power(5) + icon_state = "[initial(icon_state)]1" + desiredstate = !desiredstate + trigger(user) + spawn(15) + update_icon() + +/obj/machinery/button/remote/proc/trigger() + return + +/obj/machinery/button/remote/update_icon() + if(stat & NOPOWER & !istype(src,/obj/machinery/button/remote/blast_door/lever)) + icon_state = "[initial(icon_state)]-p" + else + icon_state = "[initial(icon_state)]" + +/* + Airlock remote control +*/ + +// Bitmasks for door switches. +#define OPEN 0x1 +#define IDSCAN 0x2 +#define BOLTS 0x4 +#define SHOCK 0x8 +#define SAFE 0x10 + +/obj/machinery/button/remote/airlock + name = "remote door-control" + desc = "It controls doors, remotely." + + var/specialfunctions = 1 + /* + Bitflag, 1= open + 2= idscan, + 4= bolts + 8= shock + 16= door safties + */ + +/obj/machinery/button/remote/airlock/trigger() + for(var/obj/machinery/door/airlock/D in world) + if(D.id_tag == src.id) + if(specialfunctions & OPEN) + if (D.density) + spawn(0) + D.open() + return + else + spawn(0) + D.close() + return + if(desiredstate == 1) + if(specialfunctions & IDSCAN) + D.set_idscan(0) + if(specialfunctions & BOLTS) + D.lock() + if(specialfunctions & SHOCK) + D.electrify(-1) + if(specialfunctions & SAFE) + D.set_safeties(0) + else + if(specialfunctions & IDSCAN) + D.set_idscan(1) + if(specialfunctions & BOLTS) + D.unlock() + if(specialfunctions & SHOCK) + D.electrify(0) + if(specialfunctions & SAFE) + D.set_safeties(1) + +#undef OPEN +#undef IDSCAN +#undef BOLTS +#undef SHOCK +#undef SAFE + +/* + Blast door remote control +*/ +/obj/machinery/button/remote/blast_door + name = "remote blast door-control" + desc = "It controls blast doors, remotely." + icon_state = "blastctrl" + +/obj/machinery/button/remote/blast_door/trigger() + for(var/obj/machinery/door/blast/M in world) + if(M.id == src.id) + if(M.density) + spawn(0) + M.open() + return + else + spawn(0) + M.close() + return + +/obj/machinery/button/remote/blast_door/lever + name = "Lever" + desc = "It controls something." + icon_state = "lever" + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + var/on = 0 + +/obj/machinery/button/remote/blast_door/lever/update_icon() + if(on) + icon_state = "lever1" + else + icon_state = "lever" + +/obj/machinery/button/remote/blast_door/lever/trigger() + for(var/obj/machinery/door/blast/M in world) + if(M.id == src.id) + if(M.density) + spawn(0) + M.open() + on = 1 + update_icon() + return + else + spawn(0) + M.close() + on = 0 + update_icon() + return + +/obj/machinery/button/remote/blast_door/lever/attack_hand(mob/user) + if(..()) + return + if(stat & (NOPOWER|BROKEN)) + to_chat(user, "[src] is not moving") + return + trigger(user) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + + +/obj/machinery/button/remote/blast_door/id_scan + name = "ID lock" + desc = null + icon_state = "id_swap" + +/obj/machinery/button/remote/blast_door/id_scan/attackby(obj/item/weapon/W, mob/user) + if(istype(W, /obj/item/weapon/card/id)) + if(allowed(usr)) + if(stat & (NOPOWER|BROKEN)) + return + to_chat(user, "You used your id in [src]") + playsound(src.loc, 'sound/effects/card_swipe.ogg', 70, 1) + trigger(user) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + else + to_chat(user, "[src] flashes with red color!") + playsound(src.loc, 'sound/effects/card_swipe.ogg', 70, 1) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + +/obj/machinery/button/remote/blast_door/id_scan/attack_hand(mob/user) + return + +/obj/machinery/button/remote/blast_door/id_scan/update_icon() + return + +/obj/machinery/button/remote/blast_door/id_scan/trigger(mob/user) + for(var/obj/machinery/door/blast/id_door/M in world) + if(M.id == src.id) + if(M.density) + spawn(0) + M.open() + return + else + spawn(0) + M.close() + return + + + +/* + Emitter remote control +*/ +/obj/machinery/button/remote/emitter + name = "remote emitter control" + desc = "It controls emitters, remotely." + +/obj/machinery/button/remote/emitter/trigger(mob/user as mob) + for(var/obj/machinery/power/emitter/E in world) + if(E.id == src.id) + spawn(0) + E.activate(user) + return + +/* + Mass driver remote control +*/ +/obj/machinery/button/remote/driver + name = "mass driver button" + desc = "A remote control switch for a mass driver." + icon = 'icons/obj/objects.dmi' + icon_state = "launcherbtt" + +/obj/machinery/button/remote/driver/trigger(mob/user as mob) + set waitfor = 0 + active = 1 + update_icon() + + for(var/obj/machinery/door/blast/M in SSmachines.machinery) + if (M.id == src.id) + spawn( 0 ) + M.open() + return + + sleep(20) + + for(var/obj/machinery/mass_driver/M in SSmachines.machinery) + if(M.id == src.id) + M.drive() + + sleep(50) + + for(var/obj/machinery/door/blast/M in SSmachines.machinery) + if (M.id == src.id) + spawn(0) + M.close() + return + + icon_state = "launcherbtt" + update_icon() + + return + +/obj/machinery/button/remote/driver/update_icon() + if(!active || (stat & NOPOWER)) + icon_state = "launcherbtt" + else + icon_state = "launcheract" diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm new file mode 100644 index 00000000..c620ea17 --- /dev/null +++ b/code/game/machinery/doors/airlock.dm @@ -0,0 +1,1439 @@ +#define BOLTS_FINE 0 +#define BOLTS_EXPOSED 1 +#define BOLTS_CUT 2 +/obj/machinery/door/airlock + name = "airlock" + icon = 'icons/obj/doors/Doorint.dmi' + icon_state = "door_closed" + power_channel = ENVIRON + + explosion_resistance = 10 + var/aiControlDisabled = 0 //If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in. + var/hackProof = 0 // if 1, this door can't be hacked by the AI + var/electrified_until = 0 //World time when the door is no longer electrified. -1 if it is permanently electrified until someone fixes it. + var/main_power_lost_until = 0 //World time when main power is restored. + var/backup_power_lost_until = -1 //World time when backup power is restored. + var/next_beep_at = 0 //World time when we may next beep due to doors being blocked by mobs + var/spawnPowerRestoreRunning = 0 + var/welded = null + var/locked = 0 + var/lock_cut_state = BOLTS_FINE + var/lights = 1 // bolt lights show by default + var/aiDisabledIdScanner = 0 + var/aiHacking = 0 + var/obj/machinery/door/airlock/closeOther = null + var/closeOtherId = null + var/lockdownbyai = 0 + autoclose = 1 + var/assembly_type = /obj/structure/door_assembly + var/mineral = null + var/justzap = 0 + var/safe = 1 + normalspeed = 1 + var/obj/item/weapon/airlock_electronics/electronics = null + var/hasShocked = 0 //Prevents multiple shocks from happening + var/secured_wires = 0 + var/datum/wires/airlock/wires = null + + var/open_sound_powered = 'sound/machines/airlock_open.ogg' + var/open_sound_unpowered = 'sound/machines/airlock_open_force.ogg' + var/open_failure_access_denied = 'sound/machines/airlock_deny.ogg' + + var/close_sound_powered = 'sound/machines/airlock_close.ogg' + var/close_sound_unpowered = 'sound/machines/airlock_close_force.ogg' + var/close_failure_blocked = 'sound/machines/triple_beep.ogg' + + var/bolts_dropping = 'sound/machines/BoltsDown.ogg' + var/bolts_rising = 'sound/machines/BoltsUp.ogg' + + var/door_crush_damage = DOOR_CRUSH_DAMAGE + var/spam_flag = 0 + + var/_wifi_id + var/datum/wifi/receiver/button/door/wifi_receiver + var/obj/item/weapon/airlock_brace/brace = null + +/obj/machinery/door/airlock/attack_generic(var/mob/user, var/damage) + if(stat & (BROKEN|NOPOWER)) + if(damage >= 10) + if(src.density) + visible_message("\The [user] forces \the [src] open!") + open(1) + else + visible_message("\The [user] forces \the [src] closed!") + close(1) + else + visible_message("\The [user] strains fruitlessly to force \the [src] [density ? "open" : "closed"].") + return + ..() + +/obj/machinery/door/airlock/get_material() + if(mineral) + return get_material_by_name(mineral) + return get_material_by_name(DEFAULT_WALL_MATERIAL) + +/obj/machinery/door/airlock/command + name = "Airlock" + icon = 'icons/obj/doors/Doorcom.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_com + +/obj/machinery/door/airlock/black + name = "Airlock" + icon = 'icons/obj/doors/doorblack.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_black + +/obj/machinery/door/airlock/hydroponics + name = "Airlock" + icon = 'icons/obj/doors/doorhydro.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_hyd + +/obj/machinery/door/airlock/chemistry + name = "Airlock" + icon = 'icons/obj/doors/doorchem.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_chem + +/obj/machinery/door/airlock/cone + name = "Airlock" + icon = 'icons/obj/doors/Doormetalone.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_cone + +/obj/machinery/door/airlock/arbiter + name = "Arbiter" + icon = 'icons/obj/doors/Doorcomalt.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_arbiter + req_access = list(access_chapel_office) + +/obj/machinery/door/airlock/security + name = "Airlock" + icon = 'icons/obj/doors/Doorsec.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_sec + +/obj/machinery/door/airlock/engineering + name = "Airlock" + icon = 'icons/obj/doors/Dooreng.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_eng + +/obj/machinery/door/airlock/medical + name = "Airlock" + icon = 'icons/obj/doors/Doormed.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_med + +/obj/machinery/door/airlock/virology + name = "Airlock" + icon = 'icons/obj/doors/Doorviro.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_viro + +/obj/machinery/door/airlock/maintenance + name = "Maintenance Access" + icon = 'icons/obj/doors/Doormaint.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_mai + +/obj/machinery/door/airlock/external + name = "External Airlock" + icon = 'icons/obj/doors/Doorext.dmi' + opacity = 1 + assembly_type = /obj/structure/door_assembly/door_assembly_ext + +/obj/machinery/door/airlock/weapon + name = "Airlock" + icon = 'icons/obj/doors/Doorweap.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_weap + +/obj/machinery/door/airlock/external/bolted + icon_state = "door_locked" + locked = 1 + +/obj/machinery/door/airlock/external/bolted/cycling + frequency = 1379 + +/obj/machinery/door/airlock/external/bolted_open + icon_state = "door_open" + density = 0 + locked = 1 + opacity = 0 + +/obj/machinery/door/airlock/sol + name = "Airlock" + icon = 'icons/obj/doors/Doorsol.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_sol + +/obj/machinery/door/airlock/glass + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + + open_sound_powered = 'sound/machines/windowdoor.ogg' + close_sound_powered = 'sound/machines/windowdoor.ogg' + + door_crush_damage = DOOR_CRUSH_DAMAGE*0.75 + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + glass = 1 + +/obj/machinery/door/airlock/centcom + name = "Airlock" + icon = 'icons/obj/doors/Doorele.dmi' + opacity = 0 + +/obj/machinery/door/airlock/vault + name = "Vault" + icon = 'icons/obj/doors/vault.dmi' + explosion_resistance = 20 + opacity = 1 + secured_wires = 1 + assembly_type = /obj/structure/door_assembly/door_assembly_highsecurity //Until somebody makes better sprites. + +/obj/machinery/door/airlock/vault/bolted + icon_state = "door_locked" + locked = 1 + +/obj/machinery/door/airlock/freezer + name = "Freezer Airlock" + icon = 'icons/obj/doors/Doorfreezer.dmi' + opacity = 1 + assembly_type = /obj/structure/door_assembly/door_assembly_fre + +/obj/machinery/door/airlock/hatch + name = "Airtight Hatch" + icon = 'icons/obj/doors/Doorhatchele.dmi' + explosion_resistance = 20 + opacity = 1 + assembly_type = /obj/structure/door_assembly/door_assembly_hatch + +/obj/machinery/door/airlock/maintenance_hatch + name = "Maintenance Hatch" + icon = 'icons/obj/doors/Doorhatchmaint2.dmi' + explosion_resistance = 20 + opacity = 1 + assembly_type = /obj/structure/door_assembly/door_assembly_mhatch + +/obj/machinery/door/airlock/maintenance_hatch/bolted + locked = 1 + icon_state = "door_locked" + +/obj/machinery/door/airlock/security_hatch + name = "Maintenance Hatch" + icon = 'icons/obj/doors/Doorhatcharmoury.dmi' + explosion_resistance = 20 + opacity = 1 + assembly_type = /obj/structure/door_assembly/door_assembly_shatch + +/obj/machinery/door/airlock/glass_command + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorcomglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_com + glass = 1 + +/obj/machinery/door/airlock/glass_black + name = "Glass Airlock" + icon = 'icons/obj/doors/doorblackglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_black + glass = 1 + +/obj/machinery/door/airlock/glass_hydroponics + name = "Glass Airlock" + icon = 'icons/obj/doors/doorhydroglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_hyd + glass = 1 + +/obj/machinery/door/airlock/glass_chemistry + name = "Glass Airlock" + icon = 'icons/obj/doors/doorchemglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_chem + glass = 1 + +/obj/machinery/door/airlock/glass_arbiter + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorcomaltglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_arbiter + glass = 1 + +/obj/machinery/door/airlock/glass_cone + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorglassone.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_cone + glass = 1 + +/obj/machinery/door/airlock/glass_weap + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorweapglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_weap + glass = 1 + +/obj/machinery/door/airlock/glass_external + name = "External Airlock" + icon = 'icons/obj/doors/Doorextglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_ext + glass = 1 + +/obj/machinery/door/airlock/glass_external/bolted + icon_state = "door_locked" + locked = 1 + +/obj/machinery/door/airlock/glass_external/bolted/cycling + frequency = 1379 + +/obj/machinery/door/airlock/glass_external/bolted_open + icon_state = "door_open" + density = 0 + locked = 1 + opacity = 0 + +/obj/machinery/door/airlock/glass_engineering + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorengglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_eng + glass = 1 + +/obj/machinery/door/airlock/glass_security + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorsecglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_sec + glass = 1 + +/obj/machinery/door/airlock/glass_medical + name = "Glass Airlock" + icon = 'icons/obj/doors/Doormedglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_med + glass = 1 + +/obj/machinery/door/airlock/glass_virology + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorviroglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_viro + glass = 1 + +/obj/machinery/door/airlock/glass_weap + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorweapglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_weap + glass = 1 + +/obj/machinery/door/airlock/glass_sol + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorsolglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_sol + glass = 1 + +/obj/machinery/door/airlock/mining + name = "Mining Airlock" + icon = 'icons/obj/doors/Doormining.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_min + +/obj/machinery/door/airlock/atmos + name = "Atmospherics Airlock" + icon = 'icons/obj/doors/Dooratmo.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_atmo + +/obj/machinery/door/airlock/research + name = "Airlock" + icon = 'icons/obj/doors/Doorresearch.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_research + +/obj/machinery/door/airlock/red + name = "Airlock" + icon = 'icons/obj/doors/Doorred.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_red + +/obj/machinery/door/airlock/glass_research + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorresearchglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_research + glass = 1 + heat_proof = 1 + +/obj/machinery/door/airlock/glass_red + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorredglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_red + glass = 1 + heat_proof = 1 + +/obj/machinery/door/airlock/glass_mining + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorminingglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_min + glass = 1 + +/obj/machinery/door/airlock/glass_atmos + name = "Glass Airlock" + icon = 'icons/obj/doors/Dooratmoglass.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_atmo + glass = 1 + +/obj/machinery/door/airlock/force_security + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorforce.dmi' + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 300 + explosion_resistance = 5 + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_force + glass = 1 + +/obj/machinery/door/airlock/gold + name = "Gold Airlock" + icon = 'icons/obj/doors/Doorgold.dmi' + mineral = "gold" + +/obj/machinery/door/airlock/silver + name = "Silver Airlock" + icon = 'icons/obj/doors/Doorsilver.dmi' + mineral = "silver" + +/obj/machinery/door/airlock/diamond + name = "Diamond Airlock" + icon = 'icons/obj/doors/Doordiamond.dmi' + mineral = "diamond" + +/obj/machinery/door/airlock/uranium + name = "Uranium Airlock" + desc = "And they said I was crazy." + icon = 'icons/obj/doors/Dooruranium.dmi' + mineral = "uranium" + var/last_event = 0 + var/rad_power = 7.5 + +/obj/machinery/door/airlock/Process() + if(main_power_lost_until > 0 && world.time >= main_power_lost_until) + regainMainPower() + + if(backup_power_lost_until > 0 && world.time >= backup_power_lost_until) + regainBackupPower() + + else if(electrified_until > 0 && world.time >= electrified_until) + electrify(0) + + ..() + +/obj/machinery/door/airlock/uranium/Process() + if(world.time > last_event+20) + if(prob(50)) + radiation_repository.radiate(src, rad_power) + last_event = world.time + ..() + +/obj/machinery/door/airlock/phoron + name = "Phoron Airlock" + desc = "No way this can end badly." + icon = 'icons/obj/doors/Doorphoron.dmi' + mineral = "phoron" + +/obj/machinery/door/airlock/phoron/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > 300) + PhoronBurn(exposed_temperature) + +/obj/machinery/door/airlock/phoron/proc/ignite(exposed_temperature) + if(exposed_temperature > 300) + PhoronBurn(exposed_temperature) + +/obj/machinery/door/airlock/phoron/proc/PhoronBurn(temperature) + for(var/turf/simulated/floor/target_tile in range(2,loc)) + target_tile.assume_gas("phoron", 35, 400+T0C) + spawn (0) target_tile.hotspot_expose(temperature, 400) + for(var/turf/simulated/wall/W in range(3,src)) + W.burn((temperature/4))//Added so that you can't set off a massive chain reaction with a small flame + for(var/obj/machinery/door/airlock/phoron/D in range(3,src)) + D.ignite(temperature/4) + new/obj/structure/door_assembly( src.loc ) + qdel(src) + +/obj/machinery/door/airlock/sandstone + name = "Sandstone Airlock" + icon = 'icons/obj/doors/Doorsand.dmi' + mineral = "sandstone" + +/obj/machinery/door/airlock/science + name = "Airlock" + icon = 'icons/obj/doors/Doorsci.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_science + +/obj/machinery/door/airlock/glass_science + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorsciglass.dmi' + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_science + glass = 1 + +/obj/machinery/door/airlock/highsecurity + name = "Secure Airlock" + icon = 'icons/obj/doors/hightechsecurity.dmi' + explosion_resistance = 20 + secured_wires = 1 + assembly_type = /obj/structure/door_assembly/door_assembly_highsecurity + +/obj/machinery/door/airlock/highsecurity/bolted + + icon_state = "door_locked" + locked = 1 + +/* +About the new airlock wires panel: +* An airlock wire dialog can be accessed by the normal way or by using wirecutters or a multitool on the door while the wire-panel is open. This would show the following wires, which you can either wirecut/mend or send a multitool pulse through. There are 9 wires. +* one wire from the ID scanner. Sending a pulse through this flashes the red light on the door (if the door has power). If you cut this wire, the door will stop recognizing valid IDs. (If the door has 0000 access, it still opens and closes, though) +* two wires for power. Sending a pulse through either one causes a breaker to trip, disabling the door for 10 seconds if backup power is connected, or 1 minute if not (or until backup power comes back on, whichever is shorter). Cutting either one disables the main door power, but unless backup power is also cut, the backup power re-powers the door in 10 seconds. While unpowered, the door may be open, but bolts-raising will not work. Cutting these wires may electrocute the user. +* one wire for door bolts. Sending a pulse through this drops door bolts (whether the door is powered or not) or raises them (if it is). Cutting this wire also drops the door bolts, and mending it does not raise them. If the wire is cut, trying to raise the door bolts will not work. +* two wires for backup power. Sending a pulse through either one causes a breaker to trip, but this does not disable it unless main power is down too (in which case it is disabled for 1 minute or however long it takes main power to come back, whichever is shorter). Cutting either one disables the backup door power (allowing it to be crowbarred open, but disabling bolts-raising), but may electocute the user. +* one wire for opening the door. Sending a pulse through this while the door has power makes it open the door if no access is required. +* one wire for AI control. Sending a pulse through this blocks AI control for a second or so (which is enough to see the AI control light on the panel dialog go off and back on again). Cutting this prevents the AI from controlling the door unless it has hacked the door through the power connection (which takes about a minute). If both main and backup power are cut, as well as this wire, then the AI cannot operate or hack the door at all. +* one wire for electrifying the door. Sending a pulse through this electrifies the door for 30 seconds. Cutting this wire electrifies the door, so that the next person to touch the door without insulated gloves gets electrocuted. (Currently it is also STAYING electrified until someone mends the wire) +* one wire for controling door safetys. When active, door does not close on someone. When cut, door will ruin someone's shit. When pulsed, door will immedately ruin someone's shit. +* one wire for controlling door speed. When active, dor closes at normal rate. When cut, door does not close manually. When pulsed, door attempts to close every tick. +*/ + +/obj/machinery/door/airlock/bumpopen(mob/living/user as mob) //Airlocks now zap you when you 'bump' them open when they're electrified. --NeoFite + if(!issilicon(usr)) + if(src.isElectrified()) + if(!src.justzap) + if(src.shock(user, 100)) + src.justzap = 1 + spawn (10) + src.justzap = 0 + return + else /*if(src.justzap)*/ + return + else if(prob(10) && src.operating == 0) + var/mob/living/carbon/C = user + if(istype(C) && C.hallucination_power > 25) + to_chat(user, "You feel a powerful shock course through your body!") + user.adjustHalLoss(10) + user.Stun(10) + return + ..(user) + +/obj/machinery/door/airlock/bumpopen(mob/living/simple_animal/user as mob) + ..(user) + +/obj/machinery/door/airlock/proc/isElectrified() + if(src.electrified_until != 0) + return 1 + return 0 + +/obj/machinery/door/airlock/proc/isWireCut(var/wireIndex) + // You can find the wires in the datum folder. + return wires.IsIndexCut(wireIndex) + +/obj/machinery/door/airlock/proc/canAIControl() + return ((src.aiControlDisabled!=1) && (!src.isAllPowerLoss())); + +/obj/machinery/door/airlock/proc/canAIHack() + return ((src.aiControlDisabled==1) && (!hackProof) && (!src.isAllPowerLoss())); + +/obj/machinery/door/airlock/proc/arePowerSystemsOn() + if (stat & (NOPOWER|BROKEN)) + return 0 + return (src.main_power_lost_until==0 || src.backup_power_lost_until==0) + +/obj/machinery/door/airlock/requiresID() + return !(src.isWireCut(AIRLOCK_WIRE_IDSCAN) || aiDisabledIdScanner) + +/obj/machinery/door/airlock/proc/isAllPowerLoss() + if(stat & (NOPOWER|BROKEN)) + return 1 + if(mainPowerCablesCut() && backupPowerCablesCut()) + return 1 + return 0 + +/obj/machinery/door/airlock/proc/mainPowerCablesCut() + return src.isWireCut(AIRLOCK_WIRE_MAIN_POWER1) || src.isWireCut(AIRLOCK_WIRE_MAIN_POWER2) + +/obj/machinery/door/airlock/proc/backupPowerCablesCut() + return src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER1) || src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER2) + +/obj/machinery/door/airlock/proc/loseMainPower() + main_power_lost_until = mainPowerCablesCut() ? -1 : world.time + SecondsToTicks(60) + + // If backup power is permanently disabled then activate in 10 seconds if possible, otherwise it's already enabled or a timer is already running + if(backup_power_lost_until == -1 && !backupPowerCablesCut()) + backup_power_lost_until = world.time + SecondsToTicks(10) + + // Disable electricity if required + if(electrified_until && isAllPowerLoss()) + electrify(0) + + update_icon() + +/obj/machinery/door/airlock/proc/loseBackupPower() + backup_power_lost_until = backupPowerCablesCut() ? -1 : world.time + SecondsToTicks(60) + + // Disable electricity if required + if(electrified_until && isAllPowerLoss()) + electrify(0) + + update_icon() + +/obj/machinery/door/airlock/proc/regainMainPower() + if(!mainPowerCablesCut()) + main_power_lost_until = 0 + // If backup power is currently active then disable, otherwise let it count down and disable itself later + if(!backup_power_lost_until) + backup_power_lost_until = -1 + + update_icon() + +/obj/machinery/door/airlock/proc/regainBackupPower() + if(!backupPowerCablesCut()) + // Restore backup power only if main power is offline, otherwise permanently disable + backup_power_lost_until = main_power_lost_until == 0 ? -1 : 0 + + update_icon() + +/obj/machinery/door/airlock/proc/electrify(var/duration, var/feedback = 0) + var/message = "" + if(src.isWireCut(AIRLOCK_WIRE_ELECTRIFY) && arePowerSystemsOn()) + message = text("The electrification wire is cut - Door permanently electrified.") + src.electrified_until = -1 + . = 1 + else if(duration && !arePowerSystemsOn()) + message = text("The door is unpowered - Cannot electrify the door.") + src.electrified_until = 0 + else if(!duration && electrified_until != 0) + message = "The door is now un-electrified." + src.electrified_until = 0 + else if(duration) //electrify door for the given duration seconds + if(usr) + shockedby += text("\[[time_stamp()]\] - [key_name(usr)]") + admin_attacker_log(usr, "electrified \the [name] [duration == -1 ? "permanently" : "for [duration] second\s"]") + else + shockedby += text("\[[time_stamp()]\] - EMP)") + message = "The door is now electrified [duration == -1 ? "permanently" : "for [duration] second\s"]." + src.electrified_until = duration == -1 ? -1 : world.time + SecondsToTicks(duration) + . = 1 + + if(feedback && message) + to_chat(usr, message) + if(.) + playsound(src, 'sound/effects/sparks3.ogg', 30, 0, -6) + +/obj/machinery/door/airlock/proc/set_idscan(var/activate, var/feedback = 0) + var/message = "" + if(src.isWireCut(AIRLOCK_WIRE_IDSCAN)) + message = "The IdScan wire is cut - IdScan feature permanently disabled." + else if(activate && src.aiDisabledIdScanner) + src.aiDisabledIdScanner = 0 + message = "IdScan feature has been enabled." + else if(!activate && !src.aiDisabledIdScanner) + src.aiDisabledIdScanner = 1 + message = "IdScan feature has been disabled." + + if(feedback && message) + to_chat(usr, message) + +/obj/machinery/door/airlock/proc/set_safeties(var/activate, var/feedback = 0) + var/message = "" + // Safeties! We don't need no stinking safeties! + if (src.isWireCut(AIRLOCK_WIRE_SAFETY)) + message = text("The safety wire is cut - Cannot enable safeties.") + else if (!activate && src.safe) + safe = 0 + else if (activate && !src.safe) + safe = 1 + + if(feedback && message) + to_chat(usr, message) + +// shock user with probability prb (if all connections & power are working) +// returns 1 if shocked, 0 otherwise +// The preceding comment was borrowed from the grille's shock script +/obj/machinery/door/airlock/shock(mob/user, prb) + if(!arePowerSystemsOn()) + return 0 + if(hasShocked) + return 0 //Already shocked someone recently? + if(..()) + hasShocked = 1 + sleep(10) + hasShocked = 0 + return 1 + else + return 0 + + +/obj/machinery/door/airlock/update_icon() + set_light(0) + if(overlays) overlays.Cut() + if(density) + if(locked && lights && src.arePowerSystemsOn()) + icon_state = "door_locked" + set_light(2, 0.75, COLOR_RED_LIGHT) + else + icon_state = "door_closed" + if(p_open || welded) + overlays = list() + if(p_open) + overlays += image(icon, "panel_open") + if (!(stat & NOPOWER)) + if(stat & BROKEN) + overlays += image(icon, "sparks_broken") + else if (health < maxhealth * 3/4) + overlays += image(icon, "sparks_damaged") + if(welded) + overlays += image(icon, "welded") + else if (health < maxhealth * 3/4 && !(stat & NOPOWER)) + overlays += image(icon, "sparks_damaged") + else + icon_state = "door_open" + if(src.arePowerSystemsOn()) + set_light(2, 0.65, COLOR_LIME) + if((stat & BROKEN) && !(stat & NOPOWER)) + overlays += image(icon, "sparks_open") + + if(brace) + brace.update_icon() + overlays += image(brace.icon, brace.icon_state) + +/obj/machinery/door/airlock/do_animate(animation) + switch(animation) + if("opening") + if(overlays) overlays.Cut() + if(p_open) + spawn(2) // The only work around that works. Downside is that the door will be gone for a millisecond. + flick("o_door_opening", src) //can not use flick due to BYOND bug updating overlays right before flicking + update_icon() + else + flick("door_opening", src)//[stat ? "_stat":] + update_icon() + if("closing") + if(overlays) overlays.Cut() + if(p_open) + spawn(2) + flick("o_door_closing", src) + update_icon() + else + flick("door_closing", src) + update_icon() + if("spark") + if(density) + flick("door_spark", src) + if("deny") + if(density && src.arePowerSystemsOn() && !spam_flag) + spam_flag = 1 + flick("door_deny", src) + //if(secured_wires) + playsound(src.loc, open_failure_access_denied, 50, 0) + spawn(15) + spam_flag = 0 + return + +/obj/machinery/door/airlock/attack_ai(mob/user as mob) + ui_interact(user) + +/obj/machinery/door/airlock/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/data[0] + + data["main_power_loss"] = round(main_power_lost_until > 0 ? max(main_power_lost_until - world.time, 0) / 10 : main_power_lost_until, 1) + data["backup_power_loss"] = round(backup_power_lost_until > 0 ? max(backup_power_lost_until - world.time, 0) / 10 : backup_power_lost_until, 1) + data["electrified"] = round(electrified_until > 0 ? max(electrified_until - world.time, 0) / 10 : electrified_until, 1) + data["open"] = !density + + var/commands[0] + commands[++commands.len] = list("name" = "IdScan", "command"= "idscan", "active" = !aiDisabledIdScanner, "enabled" = "Enabled", "disabled" = "Disable", "danger" = 0, "act" = 1) + commands[++commands.len] = list("name" = "Bolts", "command"= "bolts", "active" = !locked, "enabled" = "Raised ", "disabled" = "Dropped", "danger" = 0, "act" = 0) + commands[++commands.len] = list("name" = "Bolt Lights", "command"= "lights", "active" = lights, "enabled" = "Enabled", "disabled" = "Disable", "danger" = 0, "act" = 1) + commands[++commands.len] = list("name" = "Safeties", "command"= "safeties", "active" = safe, "enabled" = "Nominal", "disabled" = "Overridden", "danger" = 1, "act" = 0) + commands[++commands.len] = list("name" = "Timing", "command"= "timing", "active" = normalspeed, "enabled" = "Nominal", "disabled" = "Overridden", "danger" = 1, "act" = 0) + commands[++commands.len] = list("name" = "Door State", "command"= "open", "active" = density, "enabled" = "Closed", "disabled" = "Opened", "danger" = 0, "act" = 0) + + data["commands"] = commands + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "door_control.tmpl", "Door Controls", 450, 350, state = state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/door/airlock/proc/hack(mob/user as mob) + if(src.aiHacking==0) + src.aiHacking=1 + spawn(20) + //TODO: Make this take a minute + to_chat(user, "Airlock AI control has been blocked. Beginning fault-detection.") + sleep(50) + if(src.canAIControl()) + to_chat(user, "Alert cancelled. Airlock control has been restored without our assistance.") + src.aiHacking=0 + return + else if(!src.canAIHack(user)) + to_chat(user, "We've lost our connection! Unable to hack airlock.") + src.aiHacking=0 + return + to_chat(user, "Fault confirmed: airlock control wire disabled or cut.") + sleep(20) + to_chat(user, "Attempting to hack into airlock. This may take some time.") + sleep(200) + if(src.canAIControl()) + to_chat(user, "Alert cancelled. Airlock control has been restored without our assistance.") + src.aiHacking=0 + return + else if(!src.canAIHack(user)) + to_chat(user, "We've lost our connection! Unable to hack airlock.") + src.aiHacking=0 + return + to_chat(user, "Upload access confirmed. Loading control program into airlock software.") + sleep(170) + if(src.canAIControl()) + to_chat(user, "Alert cancelled. Airlock control has been restored without our assistance.") + src.aiHacking=0 + return + else if(!src.canAIHack(user)) + to_chat(user, "We've lost our connection! Unable to hack airlock.") + src.aiHacking=0 + return + to_chat(user, "Transfer complete. Forcing airlock to execute program.") + sleep(50) + //disable blocked control + src.aiControlDisabled = 2 + to_chat(user, "Receiving control information from airlock.") + sleep(10) + //bring up airlock dialog + src.aiHacking = 0 + if (user) + src.attack_ai(user) + +/obj/machinery/door/airlock/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if (src.isElectrified()) + if (istype(mover, /obj/item)) + var/obj/item/i = mover + if (i.matter && (DEFAULT_WALL_MATERIAL in i.matter) && i.matter[DEFAULT_WALL_MATERIAL] > 0) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, src) + s.start() + return ..() + +/obj/machinery/door/airlock/attack_hand(mob/user as mob) + if(!istype(usr, /mob/living/silicon)) + if(src.isElectrified()) + if(src.shock(user, 100)) + return + + if(src.p_open) + user.set_machine(src) + wires.Interact(user) + else + ..(user) + return + +/obj/machinery/door/airlock/CanUseTopic(var/mob/user) + if(operating < 0) //emagged + to_chat(user, "Unable to interface: Internal error.") + return STATUS_CLOSE + if(issilicon(user) && !src.canAIControl()) + if(src.canAIHack(user)) + src.hack(user) + else + if (src.isAllPowerLoss()) //don't really like how this gets checked a second time, but not sure how else to do it. + to_chat(user, "Unable to interface: Connection timed out.") + else + to_chat(user, "Unable to interface: Connection refused.") + return STATUS_CLOSE + + return ..() + +/obj/machinery/door/airlock/Topic(href, href_list) + if(..()) + return 1 + + var/activate = text2num(href_list["activate"]) + switch (href_list["command"]) + if("idscan") + set_idscan(activate, 1) + if("main_power") + if(!main_power_lost_until) + src.loseMainPower() + if("backup_power") + if(!backup_power_lost_until) + src.loseBackupPower() + if("bolts") + if(src.isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) + to_chat(usr, "The door bolt control wire is cut - Door bolts permanently dropped.") + else if(activate && src.lock()) + to_chat(usr, "The door bolts have been dropped.") + else if(!activate && src.unlock()) + to_chat(usr, "The door bolts have been raised.") + if("electrify_temporary") + electrify(30 * activate, 1) + if("electrify_permanently") + electrify(-1 * activate, 1) + if("open") + if(src.welded) + to_chat(usr, text("The airlock has been welded shut!")) + else if(src.locked) + to_chat(usr, text("The door bolts are down!")) + else if(activate && density) + open() + else if(!activate && !density) + close() + if("safeties") + set_safeties(!activate, 1) + if("timing") + // Door speed control + if(src.isWireCut(AIRLOCK_WIRE_SPEED)) + to_chat(usr, text("The timing wire is cut - Cannot alter timing.")) + else if (activate && src.normalspeed) + normalspeed = 0 + else if (!activate && !src.normalspeed) + normalspeed = 1 + if("lights") + // Bolt lights + if(src.isWireCut(AIRLOCK_WIRE_LIGHT)) + to_chat(usr, "The bolt lights wire is cut - The door bolt lights are permanently disabled.") + else if (!activate && src.lights) + lights = 0 + to_chat(usr, "The door bolt lights have been disabled.") + else if (activate && !src.lights) + lights = 1 + to_chat(usr, "The door bolt lights have been enabled.") + + update_icon() + return 1 + +//returns 1 on success, 0 on failure +/obj/machinery/door/airlock/proc/cut_bolts(item, var/mob/user) + var/cut_delay = (15 SECONDS) + var/cut_verb + var/cut_sound + + if(isWelder(item)) + var/obj/item/weapon/weldingtool/WT = item + if(!WT.isOn()) + return 0 + if(!WT.remove_fuel(0,user)) + to_chat(user, "You need more welding fuel to complete this task.") + return 0 + cut_verb = "cutting" + cut_sound = 'sound/items/Welder.ogg' + else if(istype(item,/obj/item/weapon/gun/energy/plasmacutter)) //They could probably just shoot them out, but who cares! + cut_verb = "cutting" + cut_sound = 'sound/items/Welder.ogg' + cut_delay *= 0.66 + else if(istype(item,/obj/item/weapon/melee/energy/blade) || istype(item,/obj/item/weapon/melee/energy/sword)) + cut_verb = "slicing" + cut_sound = "sparks" + cut_delay *= 0.66 + else if(istype(item,/obj/item/weapon/circular_saw)) + cut_verb = "sawing" + cut_sound = 'sound/weapons/circsawhit.ogg' + cut_delay *= 1.5 + + else if(istype(item,/obj/item/weapon/material/twohanded/fireaxe)) + //special case - zero delay, different message + if (src.lock_cut_state == BOLTS_EXPOSED) + return 0 //can't actually cut the bolts, go back to regular smashing + var/obj/item/weapon/material/twohanded/fireaxe/F = item + if (!F.wielded) + return 0 + user.visible_message( + "\The [user] smashes the bolt cover open!", + "You smash the bolt cover open!" + ) + playsound(src, 'sound/weapons/smash.ogg', 100, 1) + src.lock_cut_state = BOLTS_EXPOSED + return 0 + + else + // I guess you can't cut bolts with that item. Never mind then. + return 0 + + if (src.lock_cut_state == BOLTS_FINE) + user.visible_message( + "\The [user] begins [cut_verb] through the bolt cover on [src].", + "You begin [cut_verb] through the bolt cover." + ) + + playsound(src, cut_sound, 100, 1) + if (do_after(user, cut_delay, src)) + user.visible_message( + "\The [user] removes the bolt cover from [src]", + "You remove the cover and expose the door bolts." + ) + src.lock_cut_state = BOLTS_EXPOSED + return 1 + + if (src.lock_cut_state == BOLTS_EXPOSED) + user.visible_message( + "\The [user] begins [cut_verb] through [src]'s bolts.", + "You begin [cut_verb] through the door bolts." + ) + playsound(src, cut_sound, 100, 1) + if (do_after(user, cut_delay, src)) + user.visible_message( + "\The [user] severs the door bolts, unlocking [src].", + "You sever the door bolts, unlocking the door." + ) + src.lock_cut_state = BOLTS_CUT + src.unlock(1) //force it + return 1 + +/obj/machinery/door/airlock/attackby(var/obj/item/C, var/mob/user) + // Brace is considered installed on the airlock, so interacting with it is protected from electrification. + if(brace && (istype(C.GetIdCard(), /obj/item/weapon/card/id/) || istype(C, /obj/item/weapon/crowbar/brace_jack))) + return brace.attackby(C, user) + + if(!brace && istype(C, /obj/item/weapon/airlock_brace)) + var/obj/item/weapon/airlock_brace/A = C + if(!density) + to_chat(user, "You must close \the [src] before installing \the [A]!") + return + + if((!A.req_access.len && !A.req_one_access) && (alert("\the [A]'s 'Access Not Set' light is flashing. Install it anyway?", "Access not set", "Yes", "No") == "No")) + return + + if(do_after(user, 50, src) && density) + to_chat(user, "You successfully install \the [A]. \The [src] has been locked.") + brace = A + brace.airlock = src + user.drop_from_inventory(brace) + brace.forceMove(src) + update_icon() + return + + if(!istype(usr, /mob/living/silicon)) + if(src.isElectrified()) + if(src.shock(user, 75)) + return + if(istype(C, /obj/item/taperoll)) + return + + if (!repairing && (stat & BROKEN) && src.locked) //bolted and broken + if (!cut_bolts(C,user)) + ..() + return + + if(!repairing && isWelder(C) && !( src.operating > 0 ) && src.density) + var/obj/item/weapon/weldingtool/W = C + if(W.remove_fuel(0,user)) + if(!src.welded) + src.welded = 1 + else + src.welded = null + playsound(src, 'sound/items/Welder.ogg', 100, 1) + src.update_icon() + return + else + return + else if(isScrewdriver(C)) + if (src.p_open) + if (stat & BROKEN) + to_chat(usr, "The panel is broken and cannot be closed.") + else + src.p_open = 0 + else + src.p_open = 1 + src.update_icon() + else if(isWirecutter(C)) + return src.attack_hand(user) + else if(isMultitool(C)) + return src.attack_hand(user) + else if(istype(C, /obj/item/device/assembly/signaler)) + return src.attack_hand(user) + else if(istype(C, /obj/item/weapon/pai_cable)) // -- TLE + var/obj/item/weapon/pai_cable/cable = C + cable.plugin(src, user) + else if(!repairing && isCrowbar(C)) + if(src.p_open && (operating < 0 || (!operating && welded && !src.arePowerSystemsOn() && density && !src.locked)) && !brace) + playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) + user.visible_message("[user] removes the electronics from the airlock assembly.", "You start to remove electronics from the airlock assembly.") + if(do_after(user,40,src)) + to_chat(user, "You removed the airlock electronics!") + deconstruct(user) + return + else if(arePowerSystemsOn()) + to_chat(user, "The airlock's motors resist your efforts to force it.") + else if(locked) + to_chat(user, "The airlock's bolts prevent it from being forced.") + else if(brace) + to_chat(user, "The airlock's brace holds it firmly in place.") + else + if(density) + spawn(0) open(1) + else + spawn(0) close(1) + + //if door is unbroken, but at half health or less, hit with fire axe using harm intent + else if (istype(C, /obj/item/weapon/material/twohanded/fireaxe) && !(stat & BROKEN) && (src.health <= src.maxhealth / 2) && user.a_intent == I_HURT) + var/obj/item/weapon/material/twohanded/fireaxe/F = C + if (F.wielded) + playsound(src, 'sound/weapons/smash.ogg', 100, 1) + user.visible_message("[user] smashes \the [C] into the airlock's control panel! It explodes in a shower of sparks!", "You smash \the [C] into the airlock's control panel! It explodes in a shower of sparks!") + src.health = 0 + src.set_broken() + else + ..() + return + + else if(istype(C, /obj/item/weapon/material/twohanded/fireaxe) && !arePowerSystemsOn()) + if(locked) + to_chat(user, "The airlock's bolts prevent it from being forced.") + else if( !welded && !operating ) + if(density) + var/obj/item/weapon/material/twohanded/fireaxe/F = C + if(F.wielded) + spawn(0) open(1) + else + to_chat(user, "You need to be wielding \the [C] to do that.") + else + var/obj/item/weapon/material/twohanded/fireaxe/F = C + if(F.wielded) + spawn(0) close(1) + else + to_chat(user, "You need to be wielding \the [C] to do that.") + + else + ..() + return + +/obj/machinery/door/airlock/deconstruct(mob/user, var/moved = FALSE) + var/obj/structure/door_assembly/da = new assembly_type(src.loc) + if (istype(da, /obj/structure/door_assembly/multi_tile)) + da.set_dir(src.dir) + if(mineral) + da.glass = mineral + //else if(glass) + else if(glass && !da.glass) + da.glass = 1 + + if(moved) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, src) + s.start() + else + da.anchored = 1 + da.state = 1 + da.created_name = src.name + da.update_state() + + if(operating == -1 || (stat & BROKEN)) + new /obj/item/weapon/circuitboard/broken(src.loc) + operating = 0 + else + if (!electronics) create_electronics() + + electronics.dropInto(loc) + electronics = null + + qdel(src) + + return da +/obj/machinery/door/airlock/phoron/attackby(C as obj, mob/user as mob) + if(C) + ignite(is_hot(C)) + ..() + +/obj/machinery/door/airlock/set_broken() + src.p_open = 1 + stat |= BROKEN + if (secured_wires) + lock() + for (var/mob/O in viewers(src, null)) + if ((O.client && !( O.blinded ))) + O.show_message("[src.name]'s control panel bursts open, sparks spewing out!") + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, src) + s.start() + + update_icon() + return + +/obj/machinery/door/airlock/open(var/forced=0) + if(!can_open(forced)) + return 0 + use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people + + //if the door is unpowered then it doesn't make sense to hear the woosh of a pneumatic actuator + if(arePowerSystemsOn()) + playsound(src.loc, open_sound_powered, 100, 1) + else + playsound(src.loc, open_sound_unpowered, 100, 1) + + if(src.closeOther != null && istype(src.closeOther, /obj/machinery/door/airlock/) && !src.closeOther.density) + src.closeOther.close() + return ..() + +/obj/machinery/door/airlock/can_open(var/forced=0) + if(brace) + return 0 + + if(!forced) + if(!arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR)) + return 0 + + if(locked || welded) + return 0 + return ..() + +/obj/machinery/door/airlock/can_close(var/forced=0) + if(locked || welded) + return 0 + + if(!forced) + //despite the name, this wire is for general door control. + if(!arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR)) + return 0 + + return ..() + +/obj/machinery/door/airlock/close(var/forced=0) + if(!can_close(forced)) + return 0 + + if(safe) + for(var/turf/turf in locs) + for(var/atom/movable/AM in turf) + if(AM.blocks_airlock()) + if(world.time > next_beep_at) + playsound(src.loc, close_failure_blocked, 30, 0, -3) + next_beep_at = world.time + SecondsToTicks(10) + close_door_at = world.time + 6 + return + + for(var/turf/turf in locs) + for(var/atom/movable/AM in turf) + if(AM.airlock_crush(door_crush_damage)) + take_damage(door_crush_damage) + use_power(door_crush_damage * 100) // Uses bunch extra power for crushing the target. + + use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people + if(arePowerSystemsOn()) + playsound(src.loc, close_sound_powered, 100, 1) + else + playsound(src.loc, close_sound_unpowered, 100, 1) + + ..() + +/obj/machinery/door/airlock/proc/lock(var/forced=0) + if(locked) + return 0 + + if (operating && !forced) return 0 + + if (lock_cut_state == BOLTS_CUT) return 0 //what bolts? + + src.locked = 1 + playsound(src, bolts_dropping, 30, 0, -6) + audible_message("You hear a click from the bottom of the door.", hearing_distance = 1) + update_icon() + return 1 + +/obj/machinery/door/airlock/proc/unlock(var/forced=0) + if(!src.locked) + return + + if (!forced) + if(operating || !src.arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) + return + + src.locked = 0 + playsound(src, bolts_rising, 30, 0, -6) + audible_message("You hear a click from the bottom of the door.", hearing_distance = 1) + update_icon() + return 1 + +/obj/machinery/door/airlock/allowed(mob/M) + if(locked) + return 0 + return ..(M) + +/obj/machinery/door/airlock/New(var/newloc, var/obj/structure/door_assembly/assembly=null) + ..() + + //if assembly is given, create the new door from the assembly + if (assembly && istype(assembly)) + assembly_type = assembly.type + + electronics = assembly.electronics + electronics.forceMove(src) + + //update the door's access to match the electronics' + secured_wires = electronics.secure + if(electronics.one_access) + req_access.Cut() + req_one_access = src.electronics.conf_access + else + req_one_access.Cut() + req_access = src.electronics.conf_access + + //get the name from the assembly + if(assembly.created_name) + SetName(assembly.created_name) + else + SetName("[istext(assembly.glass) ? "[assembly.glass] airlock" : assembly.base_name]") + + //get the dir from the assembly + set_dir(assembly.dir) + + //wires + var/turf/T = get_turf(newloc) + if(T && (T.z in GLOB.using_map.admin_levels)) + secured_wires = 1 + if (secured_wires) + wires = new/datum/wires/airlock/secure(src) + else + wires = new/datum/wires/airlock(src) + +/obj/machinery/door/airlock/Initialize() + if(src.closeOtherId != null) + for (var/obj/machinery/door/airlock/A in world) + if(A.closeOtherId == src.closeOtherId && A != src) + src.closeOther = A + break + var/turf/T = loc + var/obj/item/weapon/airlock_brace/A = locate(/obj/item/weapon/airlock_brace) in T + if(!brace && A) + brace = A + brace.airlock = src + brace.forceMove(src) + update_icon() + . = ..() + +/obj/machinery/door/airlock/Destroy() + qdel(wires) + wires = null + qdel(wifi_receiver) + wifi_receiver = null + if(brace) + qdel(brace) + return ..() + +// Most doors will never be deconstructed over the course of a round, +// so as an optimization defer the creation of electronics until +// the airlock is deconstructed +/obj/machinery/door/airlock/proc/create_electronics() + //create new electronics + if (secured_wires) + src.electronics = new/obj/item/weapon/airlock_electronics/secure( src.loc ) + else + src.electronics = new/obj/item/weapon/airlock_electronics( src.loc ) + + //update the electronics to match the door's access + if(!src.req_access) + src.check_access() + if(src.req_access.len) + electronics.conf_access = src.req_access + else if (src.req_one_access.len) + electronics.conf_access = src.req_one_access + electronics.one_access = 1 + +/obj/machinery/door/airlock/emp_act(var/severity) + if(prob(20/severity)) + spawn(0) + open() + if(prob(40/severity)) + var/duration = SecondsToTicks(30 / severity) + if(electrified_until > -1 && (duration + world.time) > electrified_until) + electrify(duration) + ..() + +/obj/machinery/door/airlock/power_change() //putting this is obj/machinery/door itself makes non-airlock doors turn invisible for some reason + . = ..() + if(stat & NOPOWER) + // If we lost power, disable electrification + electrified_until = 0 + +/obj/machinery/door/airlock/proc/prison_open() + if(arePowerSystemsOn()) + src.unlock() + src.open() + src.lock() + return + +// Braces can act as an extra layer of armor - they will take damage first. +/obj/machinery/door/airlock/take_damage(var/amount) + if(brace) + brace.take_damage(amount) + else + ..(amount) + +/obj/machinery/door/airlock/examine() + . = ..() + if (lock_cut_state == BOLTS_EXPOSED) + to_chat(usr, "The bolt cover has been cut open.") + if (lock_cut_state == BOLTS_CUT) + to_chat(usr, "The door bolts have been cut.") + if(brace) + to_chat(usr, "\The [brace] is installed on \the [src], preventing it from opening.") + to_chat(usr, brace.examine_health()) + +/obj/machinery/door/airlock/autoname + name = "hatch" + icon = 'icons/obj/doors/Doorhatchmaint2.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_mhatch + +/obj/machinery/door/airlock/autoname/New() + var/area/A = get_area(src) + name = A.name + ..() \ No newline at end of file diff --git a/code/game/machinery/doors/airlock_control.dm b/code/game/machinery/doors/airlock_control.dm new file mode 100644 index 00000000..7f972128 --- /dev/null +++ b/code/game/machinery/doors/airlock_control.dm @@ -0,0 +1,313 @@ +#define AIRLOCK_CONTROL_RANGE 22 + +// This code allows for airlocks to be controlled externally by setting an id_tag and comm frequency (disables ID access) +obj/machinery/door/airlock + var/id_tag + var/frequency + var/shockedby = list() + var/datum/radio_frequency/radio_connection + var/cur_command = null //the command the door is currently attempting to complete + +obj/machinery/door/airlock/Process() + ..() + if (arePowerSystemsOn()) + execute_current_command() + +obj/machinery/door/airlock/receive_signal(datum/signal/signal) + if(!signal || signal.encryption) return + + if(id_tag != signal.data["tag"] || !signal.data["command"]) return + + command(signal.data["command"]) + +obj/machinery/door/airlock/proc/command(var/new_command) + cur_command = new_command + + //if there's no power, recieve the signal but just don't do anything. This allows airlocks to continue to work normally once power is restored + if(arePowerSystemsOn()) + spawn() + execute_current_command() + +obj/machinery/door/airlock/proc/execute_current_command() + if(operating) + return //emagged or busy doing something else + + if (!cur_command) + return + + do_command(cur_command) + if (command_completed(cur_command)) + cur_command = null + +obj/machinery/door/airlock/proc/do_command(var/command) + switch(command) + if("open") + open() + + if("close") + close() + + if("unlock") + unlock() + + if("lock") + lock() + + if("secure_open") + unlock() + + sleep(2) + open() + + lock() + + if("secure_close") + unlock() + close() + + lock() + sleep(2) + + send_status() + +obj/machinery/door/airlock/proc/command_completed(var/command) + switch(command) + if("open") + return (!density) + + if("close") + return density + + if("unlock") + return !locked + + if("lock") + return locked + + if("secure_open") + return (locked && !density) + + if("secure_close") + return (locked && density) + + return 1 //Unknown command. Just assume it's completed. + +obj/machinery/door/airlock/proc/send_status(var/bumped = 0) + if(radio_connection) + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.data["tag"] = id_tag + signal.data["timestamp"] = world.time + + signal.data["door_status"] = density?("closed"):("open") + signal.data["lock_status"] = locked?("locked"):("unlocked") + + if (bumped) + signal.data["bumped_with_access"] = 1 + + radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK) + + +obj/machinery/door/airlock/open(surpress_send) + . = ..() + if(!surpress_send) send_status() + + +obj/machinery/door/airlock/close(surpress_send) + . = ..() + if(!surpress_send) send_status() + + +obj/machinery/door/airlock/Bumped(atom/AM) + ..(AM) + if(istype(AM, /obj/mecha)) + var/obj/mecha/mecha = AM + if(density && radio_connection && mecha.occupant && (src.allowed(mecha.occupant) || src.check_access_list(mecha.operation_req_access))) + send_status(1) + return + +obj/machinery/door/airlock/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + if(new_frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_AIRLOCK) + + +obj/machinery/door/airlock/Initialize() + . = ..() + if(frequency) + set_frequency(frequency) + + //wireless connection + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + + update_icon() + +obj/machinery/door/airlock/New() + ..() + + if(radio_controller) + set_frequency(frequency) + +obj/machinery/door/airlock/Destroy() + if(frequency && radio_controller) + radio_controller.remove_object(src,frequency) + return ..() + +obj/machinery/airlock_sensor + icon = 'icons/obj/airlock_machines.dmi' + icon_state = "airlock_sensor_off" + name = "airlock sensor" + + anchored = 1 + power_channel = ENVIRON + + var/id_tag + var/master_tag + var/frequency = 1379 + var/command = "cycle" + + var/datum/radio_frequency/radio_connection + + var/on = 1 + var/alert = 0 + var/previousPressure + +obj/machinery/airlock_sensor/update_icon() + if(on) + if(alert) + icon_state = "airlock_sensor_alert" + else + icon_state = "airlock_sensor_standby" + else + icon_state = "airlock_sensor_off" + +obj/machinery/airlock_sensor/attack_hand(mob/user) + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.data["tag"] = master_tag + signal.data["command"] = command + + radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK) + flick("airlock_sensor_cycle", src) + +obj/machinery/airlock_sensor/Process() + if(on) + var/datum/gas_mixture/air_sample = return_air() + var/pressure = round(air_sample.return_pressure(),0.1) + + if(abs(pressure - previousPressure) > 0.001 || previousPressure == null) + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.data["tag"] = id_tag + signal.data["timestamp"] = world.time + signal.data["pressure"] = num2text(pressure) + + radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK) + + previousPressure = pressure + + alert = (pressure < ONE_ATMOSPHERE*0.8) + + update_icon() + +obj/machinery/airlock_sensor/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_AIRLOCK) + +obj/machinery/airlock_sensor/Initialize() + set_frequency(frequency) + . = ..() + +obj/machinery/airlock_sensor/New() + ..() + if(radio_controller) + set_frequency(frequency) + +obj/machinery/airlock_sensor/Destroy() + if(radio_controller) + radio_controller.remove_object(src,frequency) + return ..() + +obj/machinery/airlock_sensor/airlock_interior + command = "cycle_interior" + +obj/machinery/airlock_sensor/airlock_exterior + command = "cycle_exterior" + +obj/machinery/access_button + icon = 'icons/obj/airlock_machines.dmi' + icon_state = "access_button_standby" + name = "access button" + + anchored = 1 + power_channel = ENVIRON + + var/master_tag + var/frequency = 1449 + var/command = "cycle" + + var/datum/radio_frequency/radio_connection + + var/on = 1 + + +obj/machinery/access_button/update_icon() + if(on) + icon_state = "access_button_standby" + else + icon_state = "access_button_off" + +obj/machinery/access_button/attackby(obj/item/I as obj, mob/user as mob) + //Swiping ID on the access button + if (istype(I, /obj/item/weapon/card/id) || istype(I, /obj/item/device/pda)) + attack_hand(user) + return + ..() + +obj/machinery/access_button/attack_hand(mob/user) + ..() + if(!allowed(user)) + to_chat(user, "Access Denied") + + else if(radio_connection) + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.data["tag"] = master_tag + signal.data["command"] = command + + radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK) + flick("access_button_cycle", src) + + +obj/machinery/access_button/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_AIRLOCK) + + +obj/machinery/access_button/Initialize() + . = ..() + set_frequency(frequency) + + +obj/machinery/access_button/New() + ..() + + if(radio_controller) + set_frequency(frequency) + +obj/machinery/access_button/Destroy() + if(radio_controller) + radio_controller.remove_object(src, frequency) + return ..() + +obj/machinery/access_button/airlock_interior + frequency = 1379 + command = "cycle_interior" + +obj/machinery/access_button/airlock_exterior + frequency = 1379 + command = "cycle_exterior" diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock_electronics.dm new file mode 100644 index 00000000..0fb1e6df --- /dev/null +++ b/code/game/machinery/doors/airlock_electronics.dm @@ -0,0 +1,120 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/obj/item/weapon/airlock_electronics + name = "airlock electronics" + icon = 'icons/obj/doors/door_assembly.dmi' + icon_state = "door_electronics" + w_class = ITEM_SIZE_SMALL //It should be tiny! -Agouri + + matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 50) + + req_access = list(access_engine) + + var/secure = 0 //if set, then wires will be randomized and bolts will drop if the door is broken + var/list/conf_access = list() + var/one_access = 0 //if set to 1, door would receive req_one_access instead of req_access + var/last_configurator = null + var/locked = 1 + var/lockable = 1 + + +/obj/item/weapon/airlock_electronics/attack_self(mob/user as mob) + if (!ishuman(user) && !istype(user,/mob/living/silicon/robot)) + return ..(user) + + tg_ui_interact(user) + + + +//tgui interact code generously lifted from tgstation. +/obj/item/weapon/airlock_electronics/tg_ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, \ + datum/tgui/master_ui = null, datum/ui_state/state = tg_hands_state) + + tgui_process.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "airlock_electronics", src.name, 1000, 500, master_ui, state) + ui.open() + +/obj/item/weapon/airlock_electronics/ui_data(mob/user) + var/list/data = list() + var/list/regions = list() + + for(var/i in ACCESS_REGION_SECURITY to ACCESS_REGION_SUPPLY) //code/game/jobs/_access_defs.dm + var/list/region = list() + var/list/accesses = list() + for(var/j in get_region_accesses(i)) + var/list/access = list() + access["name"] = get_access_desc(j) + access["id"] = j + access["req"] = (j in src.conf_access) + accesses[++accesses.len] = access + region["name"] = get_region_accesses_name(i) + region["accesses"] = accesses + regions[++regions.len] = region + data["regions"] = regions + data["oneAccess"] = one_access + data["locked"] = locked + data["lockable"] = lockable + + return data + +/obj/item/weapon/airlock_electronics/ui_act(action, params) + if(..()) + return TRUE + switch(action) + if("clear") + conf_access = list() + one_access = 0 + return TRUE + if("one_access") + one_access = !one_access + return TRUE + if("set") + var/access = text2num(params["access"]) + if (!(access in conf_access)) + conf_access += access + else + conf_access -= access + return TRUE + if("unlock") + if(!lockable) + return TRUE + if(!req_access || istype(usr,/mob/living/silicon)) + locked = 0 + last_configurator = usr.name + return TRUE + else + var/obj/item/weapon/card/id/I = usr.get_active_hand() + I = I ? I.GetIdCard() : null + if(!istype(I, /obj/item/weapon/card/id)) + to_chat(usr, "[\src] flashes a yellow LED near the ID scanner. Did you remember to scan your ID or PDA?") + return TRUE + if (check_access(I)) + locked = 0 + last_configurator = I.registered_name + else + to_chat(usr, "[\src] flashes a red LED near the ID scanner, indicating your access has been denied.") + return TRUE + if("lock") + if(!lockable) + return TRUE + locked = 1 + . = TRUE + +/obj/item/weapon/airlock_electronics/secure + name = "secure airlock electronics" + desc = "designed to be somewhat more resistant to hacking than standard electronics." + origin_tech = list(TECH_DATA = 2) + secure = 1 + +/obj/item/weapon/airlock_electronics/brace + name = "airlock brace access circuit" + req_access = list() + locked = 0 + lockable = 0 + +/obj/item/weapon/airlock_electronics/brace/tg_ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = tg_deep_inventory_state) + tgui_process.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "airlock_electronics", src.name, 1000, 500, master_ui, state) + ui.open() diff --git a/code/game/machinery/doors/airlock_interactions.dm b/code/game/machinery/doors/airlock_interactions.dm new file mode 100644 index 00000000..7ddb44e7 --- /dev/null +++ b/code/game/machinery/doors/airlock_interactions.dm @@ -0,0 +1,100 @@ +/* + Moved the non-airlock procs in airlock.dm to here. +*/ + +//*** Blocking Airlocks + +/atom/movable/proc/blocks_airlock() + return density + +/obj/machinery/door/blocks_airlock() + return 0 + +/obj/structure/window/blocks_airlock() + return 0 + +/obj/structure/window_frame/blocks_airlock() + return 0 + +/obj/machinery/mech_sensor/blocks_airlock() + return 0 + +/obj/effect/energy_field/blocks_airlock() + return 0 + +/obj/machinery/shield/blocks_airlock() + return 0 + +/mob/living/blocks_airlock() + return 1 + +/obj/structure/closet/body_bag/blocks_airlock() + if (locate(/mob) in src) + return 1 + else + return 0 //Prevents Airlocks from closing on Bodybags and Cryobags with people inside + + +//*** Airlock Crushing + +#define AIRLOCK_CRUSH_INCREMENT 10 // Damage caused by airlock crushing a mob is split into multiple smaller hits. Makes door crushing behave more like a "slow" crushing effect rather than high-speed impacts. +#define CYBORG_AIRLOCKCRUSH_RESISTANCE 2 // Damage caused to silicon mobs (usually cyborgs) from being crushed by airlocks is divided by this number. Unlike organics cyborgs don't have passive regeneration. + +/atom/movable/proc/airlock_crush(var/crush_damage) + return + +/obj/structure/window/airlock_crush(var/crush_damage) + ex_act(2)//Smashin windows + +/obj/machinery/portable_atmospherics/canister/airlock_crush(var/crush_damage) + . = ..() + health -= crush_damage + healthcheck() + +/obj/effect/energy_field/airlock_crush(var/crush_damage) + Stress(crush_damage) + +/obj/structure/closet/airlock_crush(var/crush_damage) + ..() + damage(crush_damage) + for(var/atom/movable/AM in src) + AM.airlock_crush() + return + +/mob/living/airlock_crush(var/crush_damage) + . = ..() + + //using getarmor() instead of run_armor_check() to reflect the fact that this is "slow" damage and not high-impact damage + var/protection = blocked_mult(getarmor(null, "melee")) + crush_damage *= protection + + for(var/i in 1 to round(crush_damage/AIRLOCK_CRUSH_INCREMENT, 1)) + apply_damage(AIRLOCK_CRUSH_INCREMENT, BRUTE, null, 0) + + SetStunned(round(crush_damage / 8, 1)) + SetWeakened(round(crush_damage / 8, 1)) + + var/turf/T = loc + if(!istype(T)) + return + + var/list/valid_turfs = list() + for(var/dir_to_test in GLOB.cardinal) + var/turf/new_turf = get_step(T, dir_to_test) + if(!new_turf.contains_dense_objects()) + valid_turfs |= new_turf + + while(valid_turfs.len) + T = pick(valid_turfs) + valid_turfs -= T + // Try to move us to the turf. If all turfs fail for some reason we will stay on this tile. + if(src.Move(T)) + return + +/mob/living/carbon/airlock_crush(var/crush_damage) + . = ..() + if (can_feel_pain()) + emote("scream") + +/mob/living/silicon/robot/airlock_crush(var/crush_damage) + return ..(round(crush_damage / CYBORG_AIRLOCKCRUSH_RESISTANCE)) //TODO implement robot melee armour and remove this. diff --git a/code/game/machinery/doors/alarmlock.dm b/code/game/machinery/doors/alarmlock.dm new file mode 100644 index 00000000..f8d0ea6b --- /dev/null +++ b/code/game/machinery/doors/alarmlock.dm @@ -0,0 +1,45 @@ +/obj/machinery/door/airlock/alarmlock + + name = "Glass Alarm Airlock" + icon = 'icons/obj/doors/Doorglass.dmi' + opacity = 0 + glass = 1 + + var/datum/radio_frequency/air_connection + var/air_frequency = 1437 + autoclose = 0 + +/obj/machinery/door/airlock/alarmlock/New() + ..() + air_connection = new + +/obj/machinery/door/airlock/alarmlock/Destroy() + if(radio_controller) + radio_controller.remove_object(src,air_frequency) + ..() + +/obj/machinery/door/airlock/alarmlock/Initialize() + . = ..() + radio_controller.remove_object(src, air_frequency) + air_connection = radio_controller.add_object(src, air_frequency, RADIO_TO_AIRALARM) + open() + + +/obj/machinery/door/airlock/alarmlock/receive_signal(datum/signal/signal) + ..() + if(stat & (NOPOWER|BROKEN)) + return + + var/alarm_area = signal.data["zone"] + var/alert = signal.data["alert"] + + var/area/our_area = get_area(src) + + if(alarm_area == our_area.name) + switch(alert) + if("severe") + autoclose = 1 + close() + if("minor", "clear") + autoclose = 0 + open() diff --git a/code/game/machinery/doors/blast_door.dm b/code/game/machinery/doors/blast_door.dm new file mode 100644 index 00000000..8e2e5b73 --- /dev/null +++ b/code/game/machinery/doors/blast_door.dm @@ -0,0 +1,267 @@ +// BLAST DOORS +// +// Refactored 27.12.2014 by Atlantis +// +// Blast doors are supposed to be reinforced versions of regular doors. Instead of being manually +// controlled they use buttons or other means of remote control. This is why they cannot be emagged +// as they lack any ID scanning system, they just handle remote control signals. Subtypes have +// different icons, which are defined by set of variables. Subtypes are on bottom of this file. + +/obj/machinery/door/blast + name = "Blast Door" + desc = "That looks like it doesn't open easily." + icon = 'icons/obj/doors/rapid_pdoor.dmi' + icon_state = null + + // Icon states for different shutter types. Simply change this instead of rewriting the update_icon proc. + var/icon_state_open = null + var/icon_state_opening = null + var/icon_state_closed = null + var/icon_state_closing = null + + var/open_sound = 'sound/machines/airlock_heavy.ogg' + var/close_sound = 'sound/machines/AirlockClose_heavy.ogg' + + closed_layer = ABOVE_HUMAN_LAYER + var/closed_plane = ABOVE_HUMAN_PLANE + var/id = 1.0 + dir = 1 + explosion_resistance = 25 + + //Most blast doors are infrequently toggled and sometimes used with regular doors anyways, + //turning this off prevents awkward zone geometry in places like medbay lobby, for example. + block_air_zones = 0 + + var/begins_closed = TRUE + var/_wifi_id + var/datum/wifi/receiver/button/door/wifi_receiver + var/material/implicit_material + var/opaque = 1 + +/obj/machinery/door/blast/Initialize() + . = ..() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + + if(!begins_closed) + icon_state = icon_state_open + set_density(0) + set_opacity(0) + layer = open_layer + + implicit_material = get_material_by_name("plasteel") + +/obj/machinery/door/airlock/Destroy() + qdel(wifi_receiver) + wifi_receiver = null + return ..() + +// Proc: Bumped() +// Parameters: 1 (AM - Atom that tried to walk through this object) +// Description: If we are open returns zero, otherwise returns result of parent function. +/obj/machinery/door/blast/Bumped(atom/AM) + if(!density) + return ..() + else + return 0 + +// Proc: update_icon() +// Parameters: None +// Description: Updates icon of this object. Uses icon state variables. +/obj/machinery/door/blast/update_icon() + if(density) + icon_state = icon_state_closed + else + icon_state = icon_state_open + radiation_repository.resistance_cache.Remove(get_turf(src)) + return + +// Proc: force_open() +// Parameters: None +// Description: Opens the door. No checks are done inside this proc. +/obj/machinery/door/blast/proc/force_open() + src.operating = 1 + playsound(src.loc, open_sound, 60, 1) + flick(icon_state_opening, src) + src.set_density(0) + update_nearby_tiles() + src.update_icon() + src.set_opacity(0) + sleep(15) + src.layer = open_layer + plane = initial(plane) + src.operating = 0 + +// Proc: force_close() +// Parameters: None +// Description: Closes the door. No checks are done inside this proc. +/obj/machinery/door/blast/proc/force_close() + src.operating = 1 + playsound(src.loc, close_sound, 60, 1) + src.layer = closed_layer + src.plane = closed_plane + flick(icon_state_closing, src) + src.set_density(1) + update_nearby_tiles() + src.update_icon() + if(opaque == 1) + src.set_opacity(1) + sleep(15) + src.operating = 0 + +// Proc: force_toggle() +// Parameters: None +// Description: Opens or closes the door, depending on current state. No checks are done inside this proc. +/obj/machinery/door/blast/proc/force_toggle() + if(src.density) + src.force_open() + else + src.force_close() + +/obj/machinery/door/blast/get_material() + return implicit_material + +// Proc: attackby() +// Parameters: 2 (C - Item this object was clicked with, user - Mob which clicked this object) +// Description: If we are clicked with crowbar or wielded fire axe, try to manually open the door. +// This only works on broken doors or doors without power. Also allows repair with Plasteel. +/obj/machinery/door/blast/attackby(obj/item/weapon/C as obj, mob/user as mob) + src.add_fingerprint(user, 0, C) + if(isCrowbar(C) || (istype(C, /obj/item/weapon/material/twohanded/fireaxe) && C:wielded == 1)) + if(((stat & NOPOWER) || (stat & BROKEN)) && !( src.operating )) + force_toggle() + else + to_chat(usr, "[src]'s motors resist your effort.") + return + if(istype(C, /obj/item/stack/material) && C.get_material_name() == "plasteel") + var/amt = Ceiling((maxhealth - health)/150) + if(!amt) + to_chat(usr, "\The [src] is already fully repaired.") + return + var/obj/item/stack/P = C + if(P.amount < amt) + to_chat(usr, "You don't have enough sheets to repair this! You need at least [amt] sheets.") + return + to_chat(usr, "You begin repairing [src]...") + if(do_after(usr, 30, src)) + if(P.use(amt)) + to_chat(usr, "You have repaired \the [src]") + src.repair() + else + to_chat(usr, "You don't have enough sheets to repair this! You need at least [amt] sheets.") + + + +// Proc: open() +// Parameters: None +// Description: Opens the door. Does necessary checks. Automatically closes if autoclose is true +/obj/machinery/door/blast/open() + if (src.operating || (stat & BROKEN || stat & NOPOWER)) + return + force_open() + if(autoclose) + spawn(150) + close() + return 1 + +// Proc: close() +// Parameters: None +// Description: Closes the door. Does necessary checks. +/obj/machinery/door/blast/close() + if (src.operating || (stat & BROKEN || stat & NOPOWER)) + return + for(var/mob/living/M in src.loc) + if(prob(30)) + M.do_dodge() + else + var/damage = 70 + M.apply_damage(rand(40, damage), BRUTE, BP_HEAD) + M.apply_damage(rand(40, damage), BRUTE, BP_CHEST) + M.apply_damage(rand(40, damage), BRUTE, BP_L_LEG) + M.apply_damage(rand(40, damage), BRUTE, BP_R_LEG) + M.apply_damage(rand(40, damage), BRUTE, BP_L_ARM) + M.apply_damage(rand(40, damage), BRUTE, BP_R_ARM) + M.KnockDown() + M.updatehealth() + force_close() + + +// Proc: repair() +// Parameters: None +// Description: Fully repairs the blast door. +/obj/machinery/door/blast/proc/repair() + health = maxhealth + if(stat & BROKEN) + stat &= ~BROKEN + + +/obj/machinery/door/blast/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group) return 1 + return ..() + + + +// SUBTYPE: Regular +// Your classical blast door, found almost everywhere. +/obj/machinery/door/blast/regular + icon_state_open = "pdoor0" + icon_state_opening = "pdoorc0" + icon_state_closed = "pdoor1" + icon_state_closing = "pdoorc1" + icon_state = "pdoor1" + maxhealth = 600 + block_air_zones = 1 + +/obj/machinery/door/blast/regular/open + icon_state = "pdoor0" + begins_closed = FALSE + +// SUBTYPE: Shutters +// Nicer looking, and also weaker, shutters. Found in kitchen and similar areas. +/obj/machinery/door/blast/shutters + icon_state_open = "shutter0" + icon_state_opening = "shutterc0" + icon_state_closed = "shutter1" + icon_state_closing = "shutterc1" + icon_state = "shutter1" + open_sound = 'sound/machines/shutters_open.ogg' + close_sound = 'sound/machines/shutters_close.ogg' + +/obj/machinery/door/blast/shutters/open + icon_state = "shutter0" + begins_closed = FALSE + +/obj/machinery/door/blast/grates + icon_state_open = "gshutter0" + icon_state_opening = "gshutterc0" + icon_state_closed = "gshutter1" + icon_state_closing = "gshutterc1" + icon_state = "gshutter1" + name = "grate" + open_sound = 'sound/machines/shutters_open.ogg' + close_sound = 'sound/machines/shutters_close.ogg' + open_layer = ABOVE_WINDOW_LAYER + atmos_canpass = 1 + block_air_zones = 0 + opaque = 0 + opacity = 0 + +/obj/machinery/door/blast/grates/open + icon_state = "gshutter0" + begins_closed = FALSE + +/obj/machinery/door/blast/id_door + name = "door" + desc = null + icon_state_open = "iddoor_open" + icon_state_opening = "iddoor_opening" + icon_state_closed = "iddoor_close" + icon_state_closing = "iddoor_closing" + icon_state = "iddoor_close" + open_sound = 'sound/machines/id_door_open.ogg' + close_sound = 'sound/machines/id_door_close.ogg' + open_layer = ABOVE_WINDOW_LAYER + +/obj/machinery/door/blast/id_door/open + icon_state = "iddoor_open" + begins_closed = FALSE diff --git a/code/game/machinery/doors/braces.dm b/code/game/machinery/doors/braces.dm new file mode 100644 index 00000000..2cbad0b9 --- /dev/null +++ b/code/game/machinery/doors/braces.dm @@ -0,0 +1,152 @@ +// MAINTENANCE JACK - Allows removing of braces with certain delay. +/obj/item/weapon/crowbar/brace_jack + name = "maintenance jack" + desc = "A special crowbar that can be used to safely remove airlock braces from airlocks." + w_class = ITEM_SIZE_NORMAL + icon = 'icons/obj/tools.dmi' + icon_state = "maintenance_jack" + force = 8 //It has a hammer head, should probably do some more damage. - Cirra + throwforce = 10 + + + + +// BRACE - Can be installed on airlock to reinforce it and keep it closed. +/obj/item/weapon/airlock_brace + name = "airlock brace" + desc = "A sturdy device that can be attached to an airlock to reinforce it and provide additional security." + w_class = ITEM_SIZE_LARGE + icon = 'icons/obj/airlock_machines.dmi' + icon_state = "brace_open" + var/cur_health + var/max_health = 450 + var/obj/machinery/door/airlock/airlock = null + var/obj/item/weapon/airlock_electronics/brace/electronics + + +/obj/item/weapon/airlock_brace/examine(var/mob/user) + . = ..() + to_chat(user, examine_health()) + + +// This is also called from airlock's examine, so it's a different proc to prevent code copypaste. +/obj/item/weapon/airlock_brace/proc/examine_health() + switch(health_percentage()) + if(-100 to 25) + return "\The [src] looks seriously damaged, and probably won't last much more." + if(25 to 50) + return "\The [src] looks damaged." + if(50 to 75) + return "\The [src] looks slightly damaged." + if(75 to 99) + return "\The [src] has few dents." + if(99 to INFINITY) + return "\The [src] is in excellent condition." + + +/obj/item/weapon/airlock_brace/update_icon() + if(airlock) + icon_state = "brace_closed" + else + icon_state = "brace_open" + + +/obj/item/weapon/airlock_brace/New() + ..() + cur_health = max_health + electronics = new/obj/item/weapon/airlock_electronics/brace(src) + update_access() + +/obj/item/weapon/airlock_brace/Destroy() + if(airlock) + airlock.brace = null + airlock = null + qdel(electronics) + electronics = null + ..() + + +// Interact with the electronics to set access requirements. +/obj/item/weapon/airlock_brace/attack_self(mob/user as mob) + electronics.attack_self(user) + + +/obj/item/weapon/airlock_brace/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + if (istype(W.GetIdCard(), /obj/item/weapon/card/id)) + if(!airlock) + attack_self(user) + return + else + var/obj/item/weapon/card/id/C = W.GetIdCard() + update_access() + if(check_access(C)) + to_chat(user, "You swipe \the [C] through \the [src].") + if(do_after(user, 10, airlock)) + to_chat(user, "\The [src] clicks a few times and detaches itself from \the [airlock]!") + unlock_brace(usr) + else + to_chat(user, "You swipe \the [C] through \the [src], but it does not react.") + return + + if (istype(W, /obj/item/weapon/crowbar/brace_jack)) + if(!airlock) + return + var/obj/item/weapon/crowbar/brace_jack/C = W + to_chat(user, "You begin forcibly removing \the [src] with \the [C].") + if(do_after(user, rand(150,300), airlock)) + to_chat(user, "You finish removing \the [src].") + unlock_brace(user) + return + + if(isWelder(W)) + var/obj/item/weapon/weldingtool/C = W + if(cur_health == max_health) + to_chat(user, "\The [src] does not require repairs.") + return + if(C.remove_fuel(0,user)) + playsound(src, 'sound/items/Welder.ogg', 100, 1) + cur_health = min(cur_health + rand(80,120), max_health) + if(cur_health == max_health) + to_chat(user, "You repair some dents on \the [src]. It is in perfect condition now.") + else + to_chat(user, "You repair some dents on \the [src].") + + +/obj/item/weapon/airlock_brace/proc/take_damage(var/amount) + cur_health = between(0, cur_health - amount, max_health) + if(!cur_health) + if(airlock) + airlock.visible_message("\The [src] breaks off of \the [airlock]!") + unlock_brace(null) + qdel(src) + + +/obj/item/weapon/airlock_brace/proc/unlock_brace(var/mob/user) + if(!airlock) + return + if(user) + user.put_in_hands(src) + airlock.visible_message("\The [user] removes \the [src] from \the [airlock]!") + else + forceMove(get_turf(src)) + airlock.brace = null + airlock.update_icon() + airlock = null + update_icon() + + +/obj/item/weapon/airlock_brace/proc/health_percentage() + if(!max_health) + return 0 + return (cur_health / max_health) * 100 + +/obj/item/weapon/airlock_brace/proc/update_access() + if(!electronics) + return + if(electronics.one_access) + req_access = list() + req_one_access = electronics.conf_access + else + req_access = electronics.conf_access + req_one_access = list() \ No newline at end of file diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm new file mode 100644 index 00000000..1d7ea64c --- /dev/null +++ b/code/game/machinery/doors/brigdoors.dm @@ -0,0 +1,292 @@ +#define CHARS_PER_LINE 5 +#define FONT_SIZE "5pt" +#define FONT_COLOR "#09f" +#define FONT_STYLE "Arial Black" + +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/////////////////////////////////////////////////////////////////////////////////////////////// +// Brig Door control displays. +// Description: This is a controls the timer for the brig doors, displays the timer on itself and +// has a popup window when used, allowing to set the timer. +// Code Notes: Combination of old brigdoor.dm code from rev4407 and the status_display.dm code +// Date: 01/September/2010 +// Programmer: Veryinky +///////////////////////////////////////////////////////////////////////////////////////////////// +/obj/machinery/door_timer + name = "Door Timer" + icon = 'icons/obj/status_display.dmi' + icon_state = "frame" + desc = "A remote control for a door." + req_access = list(access_brig) + anchored = 1.0 // can't pick it up + density = 0 // can walk through it. + var/id = null // id of door it controls. + var/releasetime = 0 // when world.timeofday reaches it - release the prisoner + var/timing = 1 // boolean, true/1 timer is on, false/0 means it's not timing + var/picture_state // icon_state of alert picture, if not displaying text/numbers + var/list/obj/machinery/targets = list() + var/timetoset = 0 // Used to set releasetime upon starting the timer + + maptext_height = 26 + maptext_width = 32 + +/obj/machinery/door_timer/Initialize() + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/door_timer/LateInitialize() + for(var/obj/machinery/door/window/brigdoor/M in SSmachines.machinery) + if (M.id == src.id) + targets += M + + for(var/obj/machinery/flasher/F in SSmachines.machinery) + if(F.id == src.id) + targets += F + + for(var/obj/structure/closet/secure_closet/brig/C in world) + if(C.id == src.id) + targets += C + + if(targets.len==0) + stat |= BROKEN + update_icon() + +//Main door timer loop, if it's timing and time is >0 reduce time by 1. +// if it's less than 0, open door, reset timer +// update the door_timer window and the icon +/obj/machinery/door_timer/Process() + + if(stat & (NOPOWER|BROKEN)) return + if(src.timing) + + // poorly done midnight rollover + // (no seriously there's gotta be a better way to do this) + var/timeleft = timeleft() + if(timeleft > 1e5) + src.releasetime = 0 + + + if(world.timeofday > src.releasetime) + src.timer_end() // open doors, reset timer, clear status screen + src.timing = 0 + + src.update_icon() + + else + timer_end() + + return + + +// open/closedoor checks if door_timer has power, if so it checks if the +// linked door is open/closed (by density) then opens it/closes it. + +// Closes and locks doors, power check +/obj/machinery/door_timer/proc/timer_start() + if(stat & (NOPOWER|BROKEN)) return 0 + + // Set releasetime + releasetime = world.timeofday + timetoset + + + //set timing + timing = 1 + + for(var/obj/machinery/door/window/brigdoor/door in targets) + if(door.density) continue + spawn(0) + door.close() + + for(var/obj/structure/closet/secure_closet/brig/C in targets) + if(C.broken) continue + if(C.opened && !C.close()) continue + C.locked = 1 + C.icon_state = C.icon_locked + return 1 + + +// Opens and unlocks doors, power check +/obj/machinery/door_timer/proc/timer_end() + if(stat & (NOPOWER|BROKEN)) return 0 + + // Reset releasetime + releasetime = 0 + + //reset timing + timing = 0 + + for(var/obj/machinery/door/window/brigdoor/door in targets) + if(!door.density) continue + spawn(0) + door.open() + + for(var/obj/structure/closet/secure_closet/brig/C in targets) + if(C.broken) continue + if(C.opened) continue + C.locked = 0 + C.icon_state = C.icon_closed + + return 1 + + +// Check for releasetime timeleft +/obj/machinery/door_timer/proc/timeleft() + . = (releasetime - world.timeofday)/10 + if(. < 0) + . = 0 + +// Set timetoset +/obj/machinery/door_timer/proc/timeset(var/seconds) + timetoset = seconds * 10 + + if(timetoset <= 0) + timetoset = 0 + + return + +//Allows AIs to use door_timer, see human attack_hand function below +/obj/machinery/door_timer/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/door_timer/attack_hand(var/mob/user as mob) + tg_ui_interact(user) + +/obj/machinery/door_timer/ui_data(mob/user) + var/list/data = list() + + data["timing"] = timing + data["releasetime"] = releasetime + data["timetoset"] = timetoset + data["timeleft"] = timeleft() + + var/list/flashes = list() + + for(var/obj/machinery/flasher/flash in targets) + var/list/flashdata = list() + if(flash.last_flash && (flash.last_flash + 150) > world.time) + flashdata["status"] = 0 + else + flashdata["status"] = 1 + flashes[++flashes.len] = flashdata + + data["flashes"] = flashes + return data + + +/obj/machinery/door_timer/ui_act(action, params) + if(..()) + return TRUE + + if(!src.allowed(usr)) + return TRUE + + switch (action) + if("start") + if(timetoset > 18000) + log_and_message_admins("has started a brig timer over 30 minutes in length!") + timer_start() + if("stop") + timer_end() + if("flash") + for(var/obj/machinery/flasher/F in targets) + F.flash() + if("time") + timetoset += text2num(params["adjust"]) + timetoset = Clamp(timetoset, 0, 36000) + + src.update_icon() + return TRUE + + +/obj/machinery/door_timer/tg_ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = tgui_process.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "brig_timer", name , 300, 150, master_ui, state) + ui.open() + +//icon update function +// if NOPOWER, display blank +// if BROKEN, display blue screen of death icon AI uses +// if timing=true, run update display function +/obj/machinery/door_timer/update_icon() + if(stat & (NOPOWER)) + icon_state = "frame" + return + if(stat & (BROKEN)) + set_picture("ai_bsod") + return + if(src.timing) + var/disp1 = id + var/timeleft = timeleft() + var/disp2 = "[add_zero(num2text((timeleft / 60) % 60),2)]~[add_zero(num2text(timeleft % 60), 2)]" + if(length(disp2) > CHARS_PER_LINE) + disp2 = "Error" + update_display(disp1, disp2) + else + if(maptext) + maptext = "" + update_display("Set","Time") // would be nice to have some default printed text + return + + +// Adds an icon in case the screen is broken/off, stolen from status_display.dm +/obj/machinery/door_timer/proc/set_picture(var/state) + picture_state = state + overlays.Cut() + overlays += image('icons/obj/status_display.dmi', icon_state=picture_state) + + +//Checks to see if there's 1 line or 2, adds text-icons-numbers/letters over display +// Stolen from status_display +/obj/machinery/door_timer/proc/update_display(var/line1, var/line2) + var/new_text = {"
    [line1]
    [line2]
    "} + if(maptext != new_text) + maptext = new_text + + +//Actual string input to icon display for loop, with 5 pixel x offsets for each letter. +//Stolen from status_display +/obj/machinery/door_timer/proc/texticon(var/tn, var/px = 0, var/py = 0) + var/image/I = image('icons/obj/status_display.dmi', "blank") + var/len = length(tn) + + for(var/d = 1 to len) + var/char = copytext(tn, len-d+1, len-d+2) + if(char == " ") + continue + var/image/ID = image('icons/obj/status_display.dmi', icon_state=char) + ID.pixel_x = -(d-1)*5 + px + ID.pixel_y = py + I.overlays += ID + return I + + +/obj/machinery/door_timer/cell_1 + name = "Cell 1" + id = "Cell 1" + +/obj/machinery/door_timer/cell_2 + name = "Cell 2" + id = "Cell 2" + +/obj/machinery/door_timer/cell_3 + name = "Cell 3" + id = "Cell 3" + +/obj/machinery/door_timer/cell_4 + name = "Cell 4" + id = "Cell 4" + +/obj/machinery/door_timer/cell_5 + name = "Cell 5" + id = "Cell 5" + +/obj/machinery/door_timer/cell_6 + name = "Cell 6" + id = "Cell 6" + +#undef FONT_SIZE +#undef FONT_COLOR +#undef FONT_STYLE +#undef CHARS_PER_LINE diff --git a/code/game/machinery/doors/checkForMultipleDoors.dm b/code/game/machinery/doors/checkForMultipleDoors.dm new file mode 100644 index 00000000..f7ad56cb --- /dev/null +++ b/code/game/machinery/doors/checkForMultipleDoors.dm @@ -0,0 +1,16 @@ +/obj/machinery/door/proc/checkForMultipleDoors() + if(!src.loc) + return 0 + for(var/obj/machinery/door/D in src.loc) + if(!istype(D, /obj/machinery/door/window) && D.density) + return 0 + return 1 + +/turf/simulated/wall/proc/checkForMultipleDoors() + if(!src.loc) + return 0 + for(var/obj/machinery/door/D in locate(src.x,src.y,src.z)) + if(!istype(D, /obj/machinery/door/window) && D.density) + return 0 + //There are no false wall checks because that would be fucking retarded + return 1 \ No newline at end of file diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm new file mode 100644 index 00000000..6aa2ae07 --- /dev/null +++ b/code/game/machinery/doors/door.dm @@ -0,0 +1,472 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 +#define DOOR_REPAIR_AMOUNT 50 //amount of health regained per stack amount used + +/obj/machinery/door + name = "Door" + desc = "It opens and closes." + icon = 'icons/obj/doors/Doorint.dmi' + icon_state = "door1" + anchored = 1 + opacity = 1 + density = 1 + layer = CLOSED_DOOR_LAYER + var/open_layer = OPEN_DOOR_LAYER + var/closed_layer = CLOSED_DOOR_LAYER + + var/visible = 1 + var/p_open = 0 + var/operating = 0 + var/autoclose = 0 + var/glass = 0 + var/normalspeed = 1 + var/heat_proof = 0 // For glass airlocks/opacity firedoors + var/air_properties_vary_with_direction = 0 + var/maxhealth = 300 + var/health + var/destroy_hits = 10 //How many strong hits it takes to destroy the door + var/min_force = 10 //minimum amount of force needed to damage the door with a melee weapon + var/hitsound = 'sound/weapons/smash.ogg' //sound door makes when hit with a weapon + var/obj/item/stack/material/repairing + var/block_air_zones = 1 //If set, air zones cannot merge across the door even when it is opened. + var/close_door_at = 0 //When to automatically close the door, if possible + + //Multi-tile doors + dir = EAST + var/width = 1 + var/obj/machinery/filler_object/f5 //Filler objects so you can't see through doors. + var/obj/machinery/filler_object/f6 + + // turf animation + var/atom/movable/overlay/c_animation = null + + atmos_canpass = CANPASS_PROC + +/obj/machinery/door/attack_generic(var/mob/user, var/damage) + if(damage >= 10) + visible_message("\The [user] smashes into \the [src]!") + take_damage(damage) + else + visible_message("\The [user] bonks \the [src] harmlessly.") + attack_animation(user) + +/obj/machinery/door/New() + . = ..() + if(density) + layer = closed_layer + update_heat_protection(get_turf(src)) + else + layer = open_layer + + + if(width > 1) + if(dir in list(EAST, WEST)) + bound_width = width * world.icon_size + bound_height = world.icon_size + else + bound_width = world.icon_size + bound_height = width * world.icon_size + + health = maxhealth + update_icon() + + update_nearby_tiles(need_rebuild=1) + return + +/obj/machinery/door/Destroy() + set_density(0) + update_nearby_tiles() + . = ..() + +/obj/machinery/door/Process() + if(close_door_at && world.time >= close_door_at) + if(autoclose) + close_door_at = next_close_time() + close() + else + close_door_at = 0 + +/obj/machinery/door/proc/can_open() + if(!density || operating || !ticker) + return 0 + return 1 + +/obj/machinery/door/proc/can_close() + if(density || operating || !ticker) + return 0 + return 1 + +/obj/machinery/door/Bumped(atom/AM) + if(p_open || operating) return + if(ismob(AM)) + var/mob/M = AM + if(world.time - M.last_bumped <= 10) return //Can bump-open one airlock per second. This is to prevent shock spam. + M.last_bumped = world.time + if(!M.restrained() && (!issmall(M) || ishuman(M))) + bumpopen(M) + return + + if(istype(AM, /mob/living/bot)) + var/mob/living/bot/bot = AM + if(src.check_access(bot.botcard)) + if(density) + open() + return + + if(istype(AM, /obj/mecha)) + var/obj/mecha/mecha = AM + if(density) + if(mecha.occupant && (src.allowed(mecha.occupant) || src.check_access_list(mecha.operation_req_access))) + open() + else + do_animate("deny") + return + if(istype(AM, /obj/structure/bed/chair/wheelchair)) + var/obj/structure/bed/chair/wheelchair/wheel = AM + if(density) + if(wheel.pulling && (src.allowed(wheel.pulling))) + open() + else + do_animate("deny") + return + return + + +/obj/machinery/door/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group) return !block_air_zones + if(istype(mover) && mover.checkpass(PASS_FLAG_GLASS)) + return !opacity + return !density + + +/obj/machinery/door/proc/bumpopen(mob/user as mob) + if(operating) return + if(user.last_airflow > world.time - vsc.airflow_delay) //Fakkit + return + src.add_fingerprint(user) + if(density) + if(allowed(user)) open() + else do_animate("deny") + return + +/obj/machinery/door/bullet_act(var/obj/item/projectile/Proj) + ..() + + var/damage = Proj.get_structure_damage() + + // Emitter Blasts - these will eventually completely destroy the door, given enough time. + if (damage > 90) + destroy_hits-- + if (destroy_hits <= 0) + visible_message("\The [src.name] disintegrates!") + switch (Proj.damage_type) + if(BRUTE) + new /obj/item/stack/material/steel(src.loc, 2) + new /obj/item/stack/rods(src.loc, 3) + if(BURN) + new /obj/effect/decal/cleanable/ash(src.loc) // Turn it to ashes! + qdel(src) + + if(damage) + //cap projectile damage so that there's still a minimum number of hits required to break the door + take_damage(min(damage, 100)) + + + +/obj/machinery/door/hitby(AM as mob|obj, var/speed=5) + + ..() + visible_message("[src.name] was hit by [AM].") + var/tforce = 0 + if(ismob(AM)) + tforce = 15 * (speed/5) + else + tforce = AM:throwforce * (speed/5) + playsound(src.loc, hitsound, 100, 1) + take_damage(tforce) + return + +/obj/machinery/door/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/door/attack_hand(mob/user as mob) + return src.attackby(user, user) + +/obj/machinery/door/attack_tk(mob/user as mob) + if(requiresID() && !allowed(null)) + return + ..() + +/obj/machinery/door/attackby(obj/item/I as obj, mob/user as mob) + src.add_fingerprint(user, 0, I) + + if(istype(I, /obj/item/stack/material) && I.get_material_name() == src.get_material_name()) + if(stat & BROKEN) + to_chat(user, "It looks like \the [src] is pretty busted. It's going to need more than just patching up now.") + return + if(health >= maxhealth) + to_chat(user, "Nothing to fix!") + return + if(!density) + to_chat(user, "\The [src] must be closed before you can repair it.") + return + + //figure out how much metal we need + var/amount_needed = (maxhealth - health) / DOOR_REPAIR_AMOUNT + amount_needed = ceil(amount_needed) + + var/obj/item/stack/stack = I + var/transfer + if (repairing) + transfer = stack.transfer_to(repairing, amount_needed - repairing.amount) + if (!transfer) + to_chat(user, "You must weld or remove \the [repairing] from \the [src] before you can add anything else.") + else + repairing = stack.split(amount_needed, force=TRUE) + if (repairing) + repairing.loc = src + transfer = repairing.amount + repairing.uses_charge = FALSE //for clean robot door repair - stacks hint immortal if true + + if (transfer) + to_chat(user, "You fit [transfer] [stack.singular_name]\s to damaged and broken parts on \the [src].") + + return + + if(repairing && isWelder(I)) + if(!density) + to_chat(user, "\The [src] must be closed before you can repair it.") + return + + var/obj/item/weapon/weldingtool/welder = I + if(welder.remove_fuel(0,user)) + to_chat(user, "You start to fix dents and weld \the [repairing] into place.") + playsound(src, 'sound/items/Welder.ogg', 100, 1) + if(do_after(user, 5 * repairing.amount, src) && welder && welder.isOn()) + to_chat(user, "You finish repairing the damage to \the [src].") + health = between(health, health + repairing.amount*DOOR_REPAIR_AMOUNT, maxhealth) + update_icon() + qdel(repairing) + repairing = null + return + + if(repairing && isCrowbar(I)) + to_chat(user, "You remove \the [repairing].") + playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) + repairing.loc = user.loc + repairing = null + return + + //psa to whoever coded this, there are plenty of objects that need to call attack() on doors without bludgeoning them. + if(src.density && istype(I, /obj/item/weapon) && user.a_intent == I_HURT && !istype(I, /obj/item/weapon/card)) + var/obj/item/weapon/W = I + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(W.damtype == BRUTE || W.damtype == BURN) + if(W.force < min_force) + user.visible_message("\The [user] hits \the [src] with \the [W] with no visible effect.") + else + user.visible_message("\The [user] forcefully strikes \the [src] with \the [W]!") + playsound(src.loc, hitsound, 100, 1) + take_damage(W.force) + return + + if(src.operating > 0 || isrobot(user)) return //borgs can't attack doors open because it conflicts with their AI-like interaction with them. + + if(src.operating) return + + if(src.allowed(user) && operable()) + if(src.density) + open() + else + close() + return + + if(src.density) + do_animate("deny") + return + +/obj/machinery/door/emag_act(var/remaining_charges) + if(density && operable()) + do_animate("spark") + sleep(6) + open() + operating = -1 + return 1 + +/obj/machinery/door/proc/take_damage(var/damage) + var/initialhealth = src.health + src.health = max(0, src.health - damage) + if(src.health <= 0 && initialhealth > 0) + src.set_broken() + else if(src.health < src.maxhealth / 4 && initialhealth >= src.maxhealth / 4) + visible_message("\The [src] looks like it's about to break!" ) + else if(src.health < src.maxhealth / 2 && initialhealth >= src.maxhealth / 2) + visible_message("\The [src] looks seriously damaged!" ) + else if(src.health < src.maxhealth * 3/4 && initialhealth >= src.maxhealth * 3/4) + visible_message("\The [src] shows signs of damage!" ) + update_icon() + return + + +/obj/machinery/door/examine(mob/user) + . = ..() + if(src.health < src.maxhealth / 4) + to_chat(user, "\The [src] looks like it's about to break!") + else if(src.health < src.maxhealth / 2) + to_chat(user, "\The [src] looks seriously damaged!") + else if(src.health < src.maxhealth * 3/4) + to_chat(user, "\The [src] shows signs of damage!") + + +/obj/machinery/door/proc/set_broken() + stat |= BROKEN + visible_message("\The [src.name] breaks!") + update_icon() + + +/obj/machinery/door/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + if(2.0) + if(prob(25)) + qdel(src) + else + take_damage(300) + if(3.0) + if(prob(80)) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, src) + s.start() + else + take_damage(150) + return + + +/obj/machinery/door/update_icon() + if(density) + icon_state = "door1" + else + icon_state = "door0" + radiation_repository.resistance_cache.Remove(get_turf(src)) + return + + +/obj/machinery/door/proc/do_animate(animation) + switch(animation) + if("opening") + if(p_open) + flick("o_doorc0", src) + else + flick("doorc0", src) + if("closing") + if(p_open) + flick("o_doorc1", src) + else + flick("doorc1", src) + if("spark") + if(density) + flick("door_spark", src) + if("deny") + if(density && !(stat & (NOPOWER|BROKEN))) + flick("door_deny", src) + playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0) + return + + +/obj/machinery/door/proc/open(var/forced = 0) + if(!can_open(forced)) + return + operating = 1 + + do_animate("opening") + icon_state = "door0" + set_opacity(0) + if(istype(src, /obj/machinery/door/airlock/multi_tile/metal)) + f5.set_opacity(0) + f6.set_opacity(0) + sleep(3) + src.set_density(0) + update_nearby_tiles() + sleep(7) + src.layer = open_layer + update_icon() + set_opacity(0) + operating = 0 + + if(autoclose) + close_door_at = next_close_time() + + return 1 + +/obj/machinery/door/proc/next_close_time() + return world.time + (normalspeed ? 150 : 5) + +/obj/machinery/door/proc/close(var/forced = 0) + if(!can_close(forced)) + return + operating = 1 + + close_door_at = 0 + do_animate("closing") + sleep(3) + src.set_density(1) + src.layer = closed_layer + update_nearby_tiles() + sleep(7) + update_icon() + if(visible && !glass) + set_opacity(1) //caaaaarn! + if(istype(src, /obj/machinery/door/airlock/multi_tile/metal)) + f5.set_opacity(1) + f6.set_opacity(1) + operating = 0 + + //I shall not add a check every x ticks if a door has closed over some fire. + var/obj/fire/fire = locate() in loc + if(fire) + qdel(fire) + return + +/obj/machinery/door/proc/requiresID() + return 1 + +/obj/machinery/door/allowed(mob/M) + if(!requiresID()) + return ..(null) //don't care who they are or what they have, act as if they're NOTHING + return ..(M) + +/obj/machinery/door/update_nearby_tiles(need_rebuild) + . = ..() + for(var/turf/simulated/turf in locs) + update_heat_protection(turf) + SSair.mark_for_update(turf) + return 1 + +/obj/machinery/door/proc/update_heat_protection(var/turf/simulated/source) + if(istype(source)) + if(src.density && (src.opacity || src.heat_proof)) + source.thermal_conductivity = DOOR_HEAT_TRANSFER_COEFFICIENT + else + source.thermal_conductivity = initial(source.thermal_conductivity) + +/obj/machinery/door/Move(new_loc, new_dir) + update_nearby_tiles() + + . = ..() + if(width > 1) + if(dir in list(EAST, WEST)) + bound_width = width * world.icon_size + bound_height = world.icon_size + else + bound_width = world.icon_size + bound_height = width * world.icon_size + + if(.) + deconstruct(null, TRUE) + + +/obj/machinery/door/proc/deconstruct(mob/user, var/moved = FALSE) + return null + +/obj/machinery/door/morgue + icon = 'icons/obj/doors/doormorgue.dmi' diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm new file mode 100644 index 00000000..49246be0 --- /dev/null +++ b/code/game/machinery/doors/firedoor.dm @@ -0,0 +1,457 @@ + +#define FIREDOOR_MAX_PRESSURE_DIFF 25 // kPa +#define FIREDOOR_MAX_TEMP 50 // °C +#define FIREDOOR_MIN_TEMP 0 + +// Bitflags +#define FIREDOOR_ALERT_HOT 1 +#define FIREDOOR_ALERT_COLD 2 +// Not used #define FIREDOOR_ALERT_LOWPRESS 4 + +/obj/machinery/door/firedoor + name = "\improper Emergency Shutter" + desc = "Emergency air-tight shutter, capable of sealing off breached areas." + icon = 'icons/obj/doors/DoorHazard.dmi' + icon_state = "door_open" + req_one_access = list(access_atmospherics, access_engine_equip) + dir = 2 + opacity = 0 + density = 0 + layer = BELOW_DOOR_LAYER + open_layer = BELOW_DOOR_LAYER + closed_layer = ABOVE_DOOR_LAYER + + //These are frequenly used with windows, so make sure zones can pass. + //Generally if a firedoor is at a place where there should be a zone boundery then there will be a regular door underneath it. + block_air_zones = 0 + + var/blocked = 0 + var/lockdown = 0 // When the door has detected a problem, it locks. + var/pdiff_alert = 0 + var/pdiff = 0 + var/nextstate = null + var/net_id + var/list/areas_added + var/list/users_to_open = new + var/next_process_time = 0 + + var/hatch_open = 0 + + power_channel = ENVIRON + use_power = 1 + idle_power_usage = 5 + + var/list/tile_info[4] + var/list/dir_alerts[4] // 4 dirs, bitflags + + // MUST be in same order as FIREDOOR_ALERT_* + var/list/ALERT_STATES=list( + "hot", + "cold" + ) + +/obj/machinery/door/firedoor/Initialize() + . = ..() + for(var/obj/machinery/door/firedoor/F in loc) + if(F != src) + return INITIALIZE_HINT_QDEL + var/area/A = get_area(src) + ASSERT(istype(A)) + + LAZYADD(A.all_doors, src) + areas_added = list(A) + + for(var/direction in GLOB.cardinal) + A = get_area(get_step(src,direction)) + if(istype(A) && !(A in areas_added)) + LAZYADD(A.all_doors, src) + areas_added += A + +/obj/machinery/door/firedoor/Destroy() + for(var/area/A in areas_added) + LAZYREMOVE(A.all_doors, src) + . = ..() + +/obj/machinery/door/firedoor/get_material() + return get_material_by_name(DEFAULT_WALL_MATERIAL) + +/obj/machinery/door/firedoor/examine(mob/user) + . = ..(user, 1) + if(!. || !density) + return + + if(pdiff >= FIREDOOR_MAX_PRESSURE_DIFF) + to_chat(user, "WARNING: Current pressure differential is [pdiff]kPa! Opening door may result in injury!") + to_chat(user, "Sensor readings:") + for(var/index = 1; index <= tile_info.len; index++) + var/o = "  " + switch(index) + if(1) + o += "NORTH: " + if(2) + o += "SOUTH: " + if(3) + o += "EAST: " + if(4) + o += "WEST: " + if(tile_info[index] == null) + o += "DATA UNAVAILABLE" + to_chat(user, o) + continue + var/celsius = convert_k2c(tile_info[index][1]) + var/pressure = tile_info[index][2] + o += "" + o += "[celsius]°C " + o += "" + o += "[pressure]kPa
  • " + to_chat(user, o) + if(islist(users_to_open) && users_to_open.len) + var/users_to_open_string = users_to_open[1] + if(users_to_open.len >= 2) + for(var/i = 2 to users_to_open.len) + users_to_open_string += ", [users_to_open[i]]" + to_chat(user, "These people have opened \the [src] during an alert: [users_to_open_string].") +/obj/machinery/door/firedoor/Bumped(atom/AM) + if(p_open || operating) + return + if(!density) + return ..() + if(istype(AM, /obj/mecha)) + var/obj/mecha/mecha = AM + if(mecha.occupant) + var/mob/M = mecha.occupant + if(world.time - M.last_bumped <= 10) return //Can bump-open one airlock per second. This is to prevent popup message spam. + M.last_bumped = world.time + attack_hand(M) + return 0 + +/obj/machinery/door/firedoor/attack_hand(mob/user as mob) + add_fingerprint(user) + if(operating) + return//Already doing something. + + if(blocked) + to_chat(user, "\The [src] is welded solid!") + return + + var/alarmed = lockdown + for(var/area/A in areas_added) //Checks if there are fire alarms in any areas associated with that firedoor + if(A.fire || A.air_doors_activated) + alarmed = 1 + + var/answer = alert(user, "Would you like to [density ? "open" : "close"] this [src.name]?[ alarmed && density ? "\nNote that by doing so, you acknowledge any damages from opening this\n[src.name] as being your own fault, and you will be held accountable under the law." : ""]",\ + "\The [src]", "Yes, [density ? "open" : "close"]", "No") + if(answer == "No") + return + if(user.incapacitated() || (get_dist(src, user) > 1 && !issilicon(user))) + to_chat(user, "Sorry, you must remain able bodied and close to \the [src] in order to use it.") + return + if(density && (stat & (BROKEN|NOPOWER))) //can still close without power + to_chat(user, "\The [src] is not functioning, you'll have to force it open manually.") + return + + if(alarmed && density && lockdown && !allowed(user)) + to_chat(user, "Access denied. Please wait for authorities to arrive, or for the alert to clear.") + return + else + user.visible_message("\The [src] [density ? "open" : "close"]s for \the [user].",\ + "\The [src] [density ? "open" : "close"]s.",\ + "You hear a beep, and a door opening.") + + var/needs_to_close = 0 + if(density) + if(alarmed) + // Accountability! + users_to_open |= user.name + needs_to_close = !issilicon(user) + spawn() + open() + else + spawn() + close() + + if(needs_to_close) + spawn(50) + alarmed = 0 + for(var/area/A in areas_added) //Just in case a fire alarm is turned off while the firedoor is going through an autoclose cycle + if(A.fire || A.air_doors_activated) + alarmed = 1 + if(alarmed) + nextstate = FIREDOOR_CLOSED + close() + +/obj/machinery/door/firedoor/attackby(obj/item/weapon/C as obj, mob/user as mob) + add_fingerprint(user, 0, C) + if(operating) + return//Already doing something. + if(isWelder(C) && !repairing) + var/obj/item/weapon/weldingtool/W = C + if(W.remove_fuel(0, user)) + blocked = !blocked + user.visible_message("\The [user] [blocked ? "welds" : "unwelds"] \the [src] with \a [W].",\ + "You [blocked ? "weld" : "unweld"] \the [src] with \the [W].",\ + "You hear something being welded.") + playsound(src, 'sound/items/Welder.ogg', 100, 1) + update_icon() + return + + if(density && isScrewdriver(C)) + hatch_open = !hatch_open + user.visible_message("[user] has [hatch_open ? "opened" : "closed"] \the [src] maintenance hatch.", + "You have [hatch_open ? "opened" : "closed"] the [src] maintenance hatch.") + update_icon() + return + + if(blocked && isCrowbar(C) && !repairing) + if(!hatch_open) + to_chat(user, "You must open the maintenance hatch first!") + else + user.visible_message("[user] is removing the electronics from \the [src].", + "You start to remove the electronics from [src].") + if(do_after(user,30,src)) + if(blocked && density && hatch_open) + playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) + user.visible_message("[user] has removed the electronics from \the [src].", + "You have removed the electronics from [src].") + deconstruct(user) + return + + if(blocked) + to_chat(user, "\The [src] is welded shut!") + return + + if(isCrowbar(C) || istype(C,/obj/item/weapon/material/twohanded/fireaxe)) + if(operating) + return + + if(blocked && isCrowbar(C)) + user.visible_message("\The [user] pries at \the [src] with \a [C], but \the [src] is welded in place!",\ + "You try to pry \the [src] [density ? "open" : "closed"], but it is welded in place!",\ + "You hear someone struggle and metal straining.") + return + + if(istype(C,/obj/item/weapon/material/twohanded/fireaxe)) + var/obj/item/weapon/material/twohanded/fireaxe/F = C + if(!F.wielded) + return + + user.visible_message("\The [user] starts to force \the [src] [density ? "open" : "closed"] with \a [C]!",\ + "You start forcing \the [src] [density ? "open" : "closed"] with \the [C]!",\ + "You hear metal strain.") + if(do_after(user,30,src)) + if(isCrowbar(C)) + if(stat & (BROKEN|NOPOWER) || !density) + user.visible_message("\The [user] forces \the [src] [density ? "open" : "closed"] with \a [C]!",\ + "You force \the [src] [density ? "open" : "closed"] with \the [C]!",\ + "You hear metal strain, and a door [density ? "open" : "close"].") + else + user.visible_message("\The [user] forces \the [ blocked ? "welded" : "" ] [src] [density ? "open" : "closed"] with \a [C]!",\ + "You force \the [ blocked ? "welded" : "" ] [src] [density ? "open" : "closed"] with \the [C]!",\ + "You hear metal strain and groan, and a door [density ? "opening" : "closing"].") + if(density) + spawn(0) + open(1) + else + spawn(0) + close() + return + + return ..() + +/obj/machinery/door/firedoor/deconstruct(mob/user, var/moved = FALSE) + if (stat & BROKEN) + new /obj/item/weapon/circuitboard/broken(src.loc) + else + new/obj/item/weapon/airalarm_electronics(src.loc) + + var/obj/structure/firedoor_assembly/FA = new/obj/structure/firedoor_assembly(src.loc) + FA.anchored = !moved + FA.set_density(1) + FA.wired = 1 + FA.update_icon() + qdel(src) + + return FA + +// CHECK PRESSURE +/obj/machinery/door/firedoor/Process() + ..() + + if(density && next_process_time <= world.time) + next_process_time = world.time + 100 // 10 second delays between process updates + var/changed = 0 + lockdown=0 + // Pressure alerts + pdiff = getOPressureDifferential(src.loc) + if(pdiff >= FIREDOOR_MAX_PRESSURE_DIFF) + lockdown = 1 + if(!pdiff_alert) + pdiff_alert = 1 + changed = 1 // update_icon() + else + if(pdiff_alert) + pdiff_alert = 0 + changed = 1 // update_icon() + + tile_info = getCardinalAirInfo(src.loc,list("temperature","pressure")) + var/old_alerts = dir_alerts + for(var/index = 1; index <= 4; index++) + var/list/tileinfo=tile_info[index] + if(tileinfo==null) + continue // Bad data. + var/celsius = convert_k2c(tileinfo[1]) + + var/alerts=0 + + // Temperatures + if(celsius >= FIREDOOR_MAX_TEMP) + alerts |= FIREDOOR_ALERT_HOT + lockdown = 1 + else if(celsius <= FIREDOOR_MIN_TEMP) + alerts |= FIREDOOR_ALERT_COLD + lockdown = 1 + + dir_alerts[index]=alerts + + if(dir_alerts != old_alerts) + changed = 1 + if(changed) + update_icon() + +/obj/machinery/door/firedoor/proc/latetoggle() + if(operating || !nextstate) + return + switch(nextstate) + if(FIREDOOR_OPEN) + nextstate = null + + open() + if(FIREDOOR_CLOSED) + nextstate = null + close() + return + +/obj/machinery/door/firedoor/close() + latetoggle() + return ..() + +/obj/machinery/door/firedoor/open(var/forced = 0) + if(hatch_open) + hatch_open = 0 + visible_message("The maintenance hatch of \the [src] closes.") + update_icon() + + if(!forced) + if(stat & (BROKEN|NOPOWER)) + return //needs power to open unless it was forced + else + use_power(360) + else + log_admin("[usr]([usr.ckey]) has forced open an emergency shutter.") + message_admins("[usr]([usr.ckey]) has forced open an emergency shutter.") + latetoggle() + return ..() + +// Only opens when all areas connecting with our turf have an air alarm and are cleared +/obj/machinery/door/firedoor/proc/can_safely_open() + var/turf/neighbour + for(var/dir in GLOB.cardinal) + neighbour = get_step(src.loc, dir) + if(neighbour.c_airblock(src.loc) & AIR_BLOCKED) + continue + for(var/obj/O in src.loc) + if(istype(O, /obj/machinery/door)) + continue + . |= O.c_airblock(neighbour) + if(. & AIR_BLOCKED) + continue + var/area/A = get_area(neighbour) + if(!A.master_air_alarm) + return + if(A.atmosalm) + return + return TRUE + +/obj/machinery/door/firedoor/do_animate(animation) + switch(animation) + if("opening") + flick("door_opening", src) + if("closing") + flick("door_closing", src) + return + + +/obj/machinery/door/firedoor/update_icon() + overlays.Cut() + set_light(0) + var/do_set_light = FALSE + + if(density) + icon_state = "door_closed" + if(hatch_open) + overlays += "hatch" + if(blocked) + overlays += "welded" + if(pdiff_alert) + overlays += "palert" + do_set_light = TRUE + if(dir_alerts) + for(var/d=1;d<=4;d++) + var/cdir = GLOB.cardinal[d] + for(var/i=1;i<=ALERT_STATES.len;i++) + if(dir_alerts[d] & (1<<(i-1))) + overlays += new/icon(icon,"alert_[ALERT_STATES[i]]", dir=cdir) + do_set_light = TRUE + else + icon_state = "door_open" + if(blocked) + overlays += "welded_open" + + if(do_set_light) + set_light(1.5, 0.5, COLOR_SUN) + +//These are playing merry hell on ZAS. Sorry fellas :( + +/obj/machinery/door/firedoor/border_only +/* + icon = 'icons/obj/doors/edge_Doorfire.dmi' + glass = 1 //There is a glass window so you can see through the door + //This is needed due to BYOND limitations in controlling visibility + heat_proof = 1 + air_properties_vary_with_direction = 1 + + CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(istype(mover) && mover.checkpass(PASS_FLAG_GLASS)) + return 1 + if(get_dir(loc, target) == dir) //Make sure looking at appropriate border + if(air_group) return 0 + return !density + else + return 1 + + CheckExit(atom/movable/mover as mob|obj, turf/target as turf) + if(istype(mover) && mover.checkpass(PASS_FLAG_GLASS)) + return 1 + if(get_dir(loc, target) == dir) + return !density + else + return 1 + + + update_nearby_tiles(need_rebuild) + if(!air_master) return 0 + + var/turf/simulated/source = loc + var/turf/simulated/destination = get_step(source,dir) + + update_heat_protection(loc) + + if(istype(source)) air_master.tiles_to_update += source + if(istype(destination)) air_master.tiles_to_update += destination + return 1 +*/ + +/obj/machinery/door/firedoor/multi_tile + icon = 'icons/obj/doors/DoorHazard2x1.dmi' + width = 2 + dir = 4 \ No newline at end of file diff --git a/code/game/machinery/doors/firedoor_assembly.dm b/code/game/machinery/doors/firedoor_assembly.dm new file mode 100644 index 00000000..ace97257 --- /dev/null +++ b/code/game/machinery/doors/firedoor_assembly.dm @@ -0,0 +1,69 @@ +obj/structure/firedoor_assembly + name = "\improper emergency shutter assembly" + desc = "It can save lives." + icon = 'icons/obj/doors/DoorHazard.dmi' + icon_state = "door_construction" + anchored = 0 + opacity = 0 + density = 1 + var/wired = 0 + +obj/structure/firedoor_assembly/update_icon() + if(anchored) + icon_state = "door_anchored" + else + icon_state = "door_construction" + +obj/structure/firedoor_assembly/attackby(C as obj, mob/user as mob) + if(isCoil(C) && !wired && anchored) + var/obj/item/stack/cable_coil/cable = C + if (cable.get_amount() < 1) + to_chat(user, "You need one length of coil to wire \the [src].") + return + user.visible_message("[user] wires \the [src].", "You start to wire \the [src].") + if(do_after(user, 40, src) && !wired && anchored) + if (cable.use(1)) + wired = 1 + to_chat(user, "You wire \the [src].") + + else if(isWirecutter(C) && wired ) + playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) + user.visible_message("[user] cuts the wires from \the [src].", "You start to cut the wires from \the [src].") + + if(do_after(user, 40, src)) + if(!src) return + to_chat(user, "You cut the wires!") + new/obj/item/stack/cable_coil(src.loc, 1) + wired = 0 + + else if(istype(C, /obj/item/weapon/airalarm_electronics) && wired) + if(anchored) + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + user.visible_message("[user] has inserted a circuit into \the [src]!", + "You have inserted the circuit into \the [src]!") + new /obj/machinery/door/firedoor(src.loc) + qdel(C) + qdel(src) + else + to_chat(user, "You must secure \the [src] first!") + else if(isWrench(C)) + anchored = !anchored + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + user.visible_message("[user] has [anchored ? "" : "un" ]secured \the [src]!", + "You have [anchored ? "" : "un" ]secured \the [src]!") + update_icon() + else if(!anchored && isWelder(C)) + var/obj/item/weapon/weldingtool/WT = C + if(WT.remove_fuel(0, user)) + user.visible_message("[user] dissassembles \the [src].", + "You start to dissassemble \the [src].") + if(do_after(user, 40, src)) + if(!src || !WT.isOn()) return + user.visible_message("[user] has dissassembled \the [src].", + "You have dissassembled \the [src].") + new /obj/item/stack/material/steel(src.loc, 2) + qdel(src) + else + to_chat(user, "You need more welding fuel.") + else + ..(C, user) diff --git a/code/game/machinery/doors/multi_tile.dm b/code/game/machinery/doors/multi_tile.dm new file mode 100644 index 00000000..62017ae7 --- /dev/null +++ b/code/game/machinery/doors/multi_tile.dm @@ -0,0 +1,62 @@ +//Terribly sorry for the code doubling, but things go derpy otherwise. +/obj/machinery/door/airlock/multi_tile + width = 2 + appearance_flags = 0 + +/obj/machinery/door/airlock/multi_tile/New() + ..() + SetBounds() + +/obj/machinery/door/airlock/multi_tile/Move() + . = ..() + SetBounds() + + +/obj/machinery/door/airlock/multi_tile/proc/SetBounds() + if(dir in list(EAST, WEST)) + bound_width = width * world.icon_size + bound_height = world.icon_size + else + bound_width = world.icon_size + bound_height = width * world.icon_size + +/obj/machinery/door/airlock/multi_tile/glass + name = "Glass Airlock" + icon = 'icons/obj/doors/Door2x1glass.dmi' + opacity = 0 + glass = 1 + assembly_type = /obj/structure/door_assembly/multi_tile + + +//Shit that isn't glass. +/obj/machinery/door/airlock/multi_tile/metal/maintenance + name = "Airlock" + icon = 'icons/obj/doors/Door2x1maint.dmi' + opacity = 1 + glass = 0 + assembly_type = /obj/structure/door_assembly/multi_tile/maintenance + +/obj/machinery/door/airlock/multi_tile/metal/New() + ..() + if(src.dir > 3) + f5 = new/obj/machinery/filler_object(src.loc) + f6 = new/obj/machinery/filler_object(get_step(src,EAST)) + else + f5 = new/obj/machinery/filler_object(src.loc) + f6 = new/obj/machinery/filler_object(get_step(src,NORTH)) + f5.density = FALSE + f6.density = FALSE + f5.set_opacity(opacity) + f6.set_opacity(opacity) + +/obj/machinery/door/airlock/multi_tile/metal/Destroy() + qdel(f5) + qdel(f6) + . = ..() + +/obj/machinery/filler_object + name = "" + icon = 'icons/obj/doors/rapid_pdoor.dmi' + icon_state = "" + density = FALSE + anchored = TRUE diff --git a/code/game/machinery/doors/simple.dm b/code/game/machinery/doors/simple.dm new file mode 100644 index 00000000..07000926 --- /dev/null +++ b/code/game/machinery/doors/simple.dm @@ -0,0 +1,239 @@ +/obj/machinery/door/unpowered/simple + name = "door" + icon = 'icons/obj/doors/material_doors.dmi' + icon_state = "metal" + + var/material/material + var/icon_base + hitsound = 'sound/weapons/genhit.ogg' + var/datum/lock/lock + var/initial_lock_value //for mapping purposes. Basically if this value is set, it sets the lock to this value. + + +/obj/machinery/door/unpowered/simple/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + TemperatureAct(exposed_temperature) + +/obj/machinery/door/unpowered/simple/proc/TemperatureAct(temperature) + take_damage(100*material.combustion_effect(get_turf(src),temperature, 0.3)) + +/obj/machinery/door/unpowered/simple/New(var/newloc, var/material_name, var/locked) + ..() + if(!material_name) + material_name = DEFAULT_WALL_MATERIAL + material = get_material_by_name(material_name) + if(!material) + qdel(src) + return + maxhealth = max(100, material.integrity*10) + health = maxhealth + if(!icon_base) + icon_base = material.door_icon_base + hitsound = material.hitsound + name = "[material.display_name] door" + color = material.icon_colour + if(initial_lock_value) + locked = initial_lock_value + if(locked) + lock = new(src,locked) + + if(material.opacity < 0.5) + glass = 1 + set_opacity(0) + else + set_opacity(1) + update_icon() + +/obj/machinery/door/unpowered/simple/requiresID() + return 0 + +/obj/machinery/door/unpowered/simple/get_material() + return material + +/obj/machinery/door/unpowered/simple/get_material_name() + return material.name + +/obj/machinery/door/unpowered/simple/bullet_act(var/obj/item/projectile/Proj) + var/damage = Proj.get_structure_damage() + if(damage) + //cap projectile damage so that there's still a minimum number of hits required to break the door + take_damage(min(damage, 100)) + +/obj/machinery/door/unpowered/simple/update_icon() + if(density) + icon_state = "[icon_base]" + else + icon_state = "[icon_base]open" + return + +/obj/machinery/door/unpowered/simple/do_animate(animation) + switch(animation) + if("opening") + flick("[icon_base]opening", src) + if("closing") + flick("[icon_base]closing", src) + return + +/obj/machinery/door/unpowered/simple/inoperable(var/additional_flags = 0) + return (stat & (BROKEN|additional_flags)) + +/obj/machinery/door/unpowered/simple/close(var/forced = 0) + if(!can_close(forced)) + return + playsound(src.loc, material.dooropen_noise, 100, 1) + ..() + +/obj/machinery/door/unpowered/simple/open(var/forced = 0) + if(!can_open(forced)) + return + playsound(src.loc, material.dooropen_noise, 100, 1) + ..() + +/obj/machinery/door/unpowered/simple/set_broken() + ..() + deconstruct(null) + +/obj/machinery/door/unpowered/simple/deconstruct(mob/user, moved = FALSE) + material.place_dismantled_product(get_turf(src)) + qdel(src) + +/obj/machinery/door/unpowered/simple/attack_ai(mob/user as mob) //those aren't machinery, they're just big fucking slabs of a mineral + if(isAI(user)) //so the AI can't open it + return + else if(isrobot(user)) //but cyborgs can + if(Adjacent(user)) //not remotely though + return attack_hand(user) + +/obj/machinery/door/unpowered/simple/ex_act(severity) + switch(severity) + if(1.0) + set_broken() + if(2.0) + if(prob(25)) + set_broken() + else + take_damage(300) + if(3.0) + if(prob(20)) + take_damage(150) + + +/obj/machinery/door/unpowered/simple/attackby(obj/item/I as obj, mob/user as mob) + src.add_fingerprint(user, 0, I) + if(istype(I, /obj/item/weapon/key) && lock) + var/obj/item/weapon/key/K = I + if(!lock.toggle(I)) + to_chat(user, "\The [K] does not fit in the lock!") + return + if(lock && lock.pick_lock(I,user)) + return + + if(istype(I,/obj/item/weapon/material/lock_construct)) + if(lock) + to_chat(user, "\The [src] already has a lock.") + else + var/obj/item/weapon/material/lock_construct/L = I + lock = L.create_lock(src,user) + return + + if(istype(I, /obj/item/stack/material) && I.get_material_name() == src.get_material_name()) + if(stat & BROKEN) + to_chat(user, "It looks like \the [src] is pretty busted. It's going to need more than just patching up now.") + return + if(health >= maxhealth) + to_chat(user, "Nothing to fix!") + return + if(!density) + to_chat(user, "\The [src] must be closed before you can repair it.") + return + + //figure out how much metal we need + var/obj/item/stack/stack = I + var/amount_needed = ceil((maxhealth - health)/DOOR_REPAIR_AMOUNT) + var/used = min(amount_needed,stack.amount) + if (used) + to_chat(user, "You fit [used] [stack.singular_name]\s to damaged and broken parts on \the [src].") + stack.use(used) + health = between(health, health + used*DOOR_REPAIR_AMOUNT, maxhealth) + return + + //psa to whoever coded this, there are plenty of objects that need to call attack() on doors without bludgeoning them. + if(src.density && istype(I, /obj/item/weapon) && user.a_intent == I_HURT && !istype(I, /obj/item/weapon/card)) + var/obj/item/weapon/W = I + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(W.damtype == BRUTE || W.damtype == BURN) + if(W.force < min_force) + user.visible_message("\The [user] hits \the [src] with \the [W] with no visible effect.") + else + user.visible_message("\The [user] forcefully strikes \the [src] with \the [W]!") + playsound(src.loc, hitsound, 100, 1) + take_damage(W.force) + return + + if(src.operating) return + + if(lock && lock.isLocked()) + to_chat(user, "\The [src] is locked!") + + if(operable()) + if(src.density) + open() + else + close() + return + + return + +/obj/machinery/door/unpowered/simple/examine(mob/user) + if(..(user,1) && lock) + to_chat(user, "It appears to have a lock.") + +/obj/machinery/door/unpowered/simple/can_open() + if(!..() || (lock && lock.isLocked())) + return 0 + return 1 + +/obj/machinery/door/unpowered/simple/Destroy() + qdel(lock) + lock = null + ..() + +/obj/machinery/door/unpowered/simple/iron/New(var/newloc,var/material_name,var/complexity) + ..(newloc, "iron", complexity) + +/obj/machinery/door/unpowered/simple/silver/New(var/newloc,var/material_name,var/complexity) + ..(newloc, "silver", complexity) + +/obj/machinery/door/unpowered/simple/gold/New(var/newloc,var/material_name,var/complexity) + ..(newloc, "gold", complexity) + +/obj/machinery/door/unpowered/simple/uranium/New(var/newloc,var/material_name,var/complexity) + ..(newloc, "uranium", complexity) + +/obj/machinery/door/unpowered/simple/sandstone/New(var/newloc,var/material_name,var/complexity) + ..(newloc, "sandstone", complexity) + +/obj/machinery/door/unpowered/simple/diamond/New(var/newloc,var/material_name,var/complexity) + ..(newloc, "diamond", complexity) + +/obj/machinery/door/unpowered/simple/wood + icon_state = "wood" + color = "#824b28" + +/obj/machinery/door/unpowered/simple/wood/New(var/newloc,var/material_name,var/complexity) + ..(newloc, "wood", complexity) + +/obj/machinery/door/unpowered/simple/wood/saloon + icon_base = "saloon" + autoclose = 1 + normalspeed = 0 + +/obj/machinery/door/unpowered/simple/wood/saloon/New(var/newloc,var/material_name,var/complexity) + ..(newloc, "wood", complexity) + glass = 1 + set_opacity(0) + +/obj/machinery/door/unpowered/simple/resin/New(var/newloc,var/material_name,var/complexity) + ..(newloc, "resin", complexity) + +/obj/machinery/door/unpowered/simple/cult/New(var/newloc,var/material_name,var/complexity) + ..(newloc, "cult", complexity) \ No newline at end of file diff --git a/code/game/machinery/doors/unpowered.dm b/code/game/machinery/doors/unpowered.dm new file mode 100644 index 00000000..90a8c0db --- /dev/null +++ b/code/game/machinery/doors/unpowered.dm @@ -0,0 +1,25 @@ +/obj/machinery/door/unpowered + autoclose = 0 + var/locked = 0 + +/obj/machinery/door/unpowered/Bumped(atom/AM) + if(src.locked) + return + ..() + return + +/obj/machinery/door/unpowered/attackby(obj/item/I as obj, mob/user as mob) + if(istype(I, /obj/item/weapon/melee/energy/blade)) return + if(src.locked) return + ..() + return + +/obj/machinery/door/unpowered/emag_act() + return -1 + +/obj/machinery/door/unpowered/shuttle + icon = 'icons/turf/shuttle.dmi' + name = "door" + icon_state = "door1" + opacity = 1 + density = 1 diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm new file mode 100644 index 00000000..a73ba630 --- /dev/null +++ b/code/game/machinery/doors/windowdoor.dm @@ -0,0 +1,329 @@ +/obj/machinery/door/window + name = "interior door" + desc = "A strong door." + icon = 'icons/obj/doors/windoor.dmi' + icon_state = "left" + var/base_state = "left" + min_force = 4 + hitsound = 'sound/effects/Glasshit.ogg' + maxhealth = 150 //If you change this, consiter changing ../door/window/brigdoor/ health at the bottom of this .dm file + health = 150 + visible = 0.0 + use_power = 0 + atom_flags = ATOM_FLAG_CHECKS_BORDER + opacity = 0 + var/obj/item/weapon/airlock_electronics/electronics = null + explosion_resistance = 5 + air_properties_vary_with_direction = 1 + +/obj/machinery/door/window/New() + ..() + update_nearby_tiles() + if (src.req_access && src.req_access.len) + src.icon_state = "[src.icon_state]" + src.base_state = src.icon_state + return + +/obj/machinery/door/window/update_icon() + if(density) + icon_state = base_state + else + icon_state = "[base_state]open" + +/obj/machinery/door/window/proc/shatter(var/display_message = 1) + new /obj/item/weapon/material/shard(src.loc) + var/obj/item/stack/cable_coil/CC = new /obj/item/stack/cable_coil(src.loc) + CC.amount = 2 + var/obj/item/weapon/airlock_electronics/ae + if(!electronics) + ae = new/obj/item/weapon/airlock_electronics( src.loc ) + if(!src.req_access) + src.check_access() + if(src.req_access.len) + ae.conf_access = src.req_access + else if (src.req_one_access.len) + ae.conf_access = src.req_one_access + ae.one_access = 1 + else + ae = electronics + electronics = null + ae.loc = src.loc + if(operating == -1) + ae.icon_state = "door_electronics_smoked" + operating = 0 + set_density(0) + playsound(src, "shatter", 70, 1) + if(display_message) + visible_message("[src] shatters!") + qdel(src) + +/obj/machinery/door/window/deconstruct(mob/user, var/moved = FALSE) + shatter() + +/obj/machinery/door/window/Destroy() + set_density(0) + update_nearby_tiles() + return ..() + +/obj/machinery/door/window/Bumped(atom/movable/AM as mob|obj) + if (!( ismob(AM) )) + var/mob/living/bot/bot = AM + if(istype(bot)) + if(density && src.check_access(bot.botcard)) + open() + sleep(50) + close() + else if(istype(AM, /obj/mecha)) + var/obj/mecha/mecha = AM + if(density) + if(mecha.occupant && src.allowed(mecha.occupant)) + open() + sleep(50) + close() + return + var/mob/M = AM // we've returned by here if M is not a mob + if (!( ticker )) + return + if (src.operating) + return + if (src.density && (!issmall(M) || ishuman(M)) && src.allowed(AM)) + open() + if(src.check_access(null)) + sleep(50) + else //secure doors close faster + sleep(20) + close() + return + +/obj/machinery/door/window/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(istype(mover) && mover.checkpass(PASS_FLAG_GLASS)) + return 1 + if(get_dir(loc, target) == dir) //Make sure looking at appropriate border + if(air_group) return 0 + return !density + else + return 1 + +/obj/machinery/door/window/CheckExit(atom/movable/mover as mob|obj, turf/target as turf) + if(istype(mover) && mover.checkpass(PASS_FLAG_GLASS)) + return 1 + if(get_dir(loc, target) == dir) + return !density + else + return 1 + +/obj/machinery/door/window/open() + if (operating == 1) //doors can still open when emag-disabled + return 0 + if (!ticker) + return 0 + if (!src.operating) //in case of emag + src.operating = 1 + + flick("[src.base_state]opening", src) + playsound(src.loc, 'sound/machines/windowdoor.ogg', 100, 1) + sleep(10) + + explosion_resistance = 0 + set_density(0) + update_icon() + update_nearby_tiles() + + if(operating == 1) //emag again + src.operating = 0 + return 1 + +/obj/machinery/door/window/close() + if (src.operating) + return 0 + operating = 1 + flick(text("[]closing", src.base_state), src) + playsound(src.loc, 'sound/machines/windowdoor.ogg', 100, 1) + set_density(1) + update_icon() + explosion_resistance = initial(explosion_resistance) + update_nearby_tiles() + + sleep(10) + src.operating = 0 + return 1 + +/obj/machinery/door/window/take_damage(var/damage) + src.health = max(0, src.health - damage) + if (src.health <= 0) + shatter() + return + +/obj/machinery/door/window/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/door/window/attack_hand(mob/user as mob) + + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(H.species.can_shred(H)) + playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) + visible_message("[user] smashes against the [src.name].", 1) + take_damage(25) + return + return src.attackby(user, user) + +/obj/machinery/door/window/emag_act(var/remaining_charges, var/mob/user) + if (density && operable()) + operating = -1 + flick("[src.base_state]spark", src) + sleep(6) + open() + return 1 + +/obj/machinery/door/emp_act(severity) + if(prob(20/severity)) + spawn(0) + open() + ..() + +/obj/machinery/door/window/attackby(obj/item/weapon/I as obj, mob/user as mob) + + //If it's in the process of opening/closing, ignore the click + if (src.operating == 1) + return + + //If it's emagged, crowbar can pry electronics out. + if (src.operating == -1 && isCrowbar(I)) + playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) + user.visible_message("[user] removes the electronics from the windoor.", "You start to remove electronics from the windoor.") + if (do_after(user,40,src)) + to_chat(user, "You removed the windoor electronics!") + + var/obj/structure/windoor_assembly/wa = new/obj/structure/windoor_assembly(src.loc) + if (istype(src, /obj/machinery/door/window/brigdoor)) + wa.secure = "secure_" + wa.SetName("Secure Wired Windoor Assembly") + else + wa.SetName("Wired Windoor Assembly") + if (src.base_state == "right" || src.base_state == "rightsecure") + wa.facing = "r" + wa.set_dir(src.dir) + wa.state = "02" + wa.update_icon() + + var/obj/item/weapon/airlock_electronics/ae + if(!electronics) + ae = new/obj/item/weapon/airlock_electronics( src.loc ) + if(!src.req_access) + src.check_access() + if(src.req_access.len) + ae.conf_access = src.req_access + else if (src.req_one_access.len) + ae.conf_access = src.req_one_access + ae.one_access = 1 + else + ae = electronics + electronics = null + ae.loc = src.loc + ae.icon_state = "door_electronics_smoked" + + operating = 0 + shatter(src) + return + + //If it's a weapon, smash windoor. Unless it's an id card, agent card, ect.. then ignore it (Cards really shouldnt damage a door anyway) + if(src.density && istype(I, /obj/item/weapon) && !istype(I, /obj/item/weapon/card)) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + var/aforce = I.force + playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) + visible_message("[src] was hit by [I].") + if(I.damtype == BRUTE || I.damtype == BURN) + take_damage(aforce) + return + + + src.add_fingerprint(user, 0, I) + + if (src.allowed(user)) + if (src.density) + open() + else + close() + + else if (src.density) + flick(text("[]deny", src.base_state), src) + + return + + + +/obj/machinery/door/window/brigdoor + name = "secure door" + icon = 'icons/obj/doors/windoor.dmi' + icon_state = "leftsecure" + base_state = "leftsecure" + req_access = list(access_security) + var/id = null + maxhealth = 300 + health = 300.0 //Stronger doors for prison (regular window door health is 150) + + +/obj/machinery/door/window/northleft + dir = NORTH + +/obj/machinery/door/window/eastleft + dir = EAST + +/obj/machinery/door/window/westleft + dir = WEST + +/obj/machinery/door/window/southleft + dir = SOUTH + +/obj/machinery/door/window/northright + dir = NORTH + icon_state = "right" + base_state = "right" + +/obj/machinery/door/window/eastright + dir = EAST + icon_state = "right" + base_state = "right" + +/obj/machinery/door/window/westright + dir = WEST + icon_state = "right" + base_state = "right" + +/obj/machinery/door/window/southright + dir = SOUTH + icon_state = "right" + base_state = "right" + +/obj/machinery/door/window/brigdoor/northleft + dir = NORTH + +/obj/machinery/door/window/brigdoor/eastleft + dir = EAST + +/obj/machinery/door/window/brigdoor/westleft + dir = WEST + +/obj/machinery/door/window/brigdoor/southleft + dir = SOUTH + +/obj/machinery/door/window/brigdoor/northright + dir = NORTH + icon_state = "rightsecure" + base_state = "rightsecure" + +/obj/machinery/door/window/brigdoor/eastright + dir = EAST + icon_state = "rightsecure" + base_state = "rightsecure" + +/obj/machinery/door/window/brigdoor/westright + dir = WEST + icon_state = "rightsecure" + base_state = "rightsecure" + +/obj/machinery/door/window/brigdoor/southright + dir = SOUTH + icon_state = "rightsecure" + base_state = "rightsecure" diff --git a/code/game/machinery/doppler_array.dm b/code/game/machinery/doppler_array.dm new file mode 100644 index 00000000..7aed4f97 --- /dev/null +++ b/code/game/machinery/doppler_array.dm @@ -0,0 +1,48 @@ +var/list/doppler_arrays = list() + +/obj/machinery/doppler_array + name = "tachyon-doppler array" + desc = "A highly precise directional sensor array which measures the release of quants from decaying tachyons. The doppler shifting of the mirror-image formed by these quants can reveal the size, location and temporal affects of energetic disturbances within a large radius ahead of the array." + + +/obj/machinery/doppler_array/New() + ..() + doppler_arrays += src + +/obj/machinery/doppler_array/Destroy() + doppler_arrays -= src + ..() + +/obj/machinery/doppler_array/proc/sense_explosion(var/x0,var/y0,var/z0,var/devastation_range,var/heavy_impact_range,var/light_impact_range,var/took) + if(stat & NOPOWER) return + if(z != z0) return + + var/dx = abs(x0-x) + var/dy = abs(y0-y) + var/distance + var/direct + + if(dx > dy) + distance = dx + if(x0 > x) direct = EAST + else direct = WEST + else + distance = dy + if(y0 > y) direct = NORTH + else direct = SOUTH + + if(distance > 100) return + if(!(direct & dir)) return + + var/message = "Explosive disturbance detected - Epicenter at: grid ([x0],[y0]). Epicenter radius: [devastation_range]. Outer radius: [heavy_impact_range]. Shockwave radius: [light_impact_range]. Temporal displacement of tachyons: [took]seconds." + + for(var/mob/O in hearers(src, null)) + O.show_message("[src] states coldly, \"[message]\"",2) + +/obj/machinery/doppler_array/update_icon() + if(stat & BROKEN) + icon_state = "[initial(icon_state)]-broken" + else if( !(stat & NOPOWER) ) + icon_state = initial(icon_state) + else + icon_state = "[initial(icon_state)]-off" \ No newline at end of file diff --git a/code/game/machinery/embedded_controller/airlock_controllers.dm b/code/game/machinery/embedded_controller/airlock_controllers.dm new file mode 100644 index 00000000..50e9e9b2 --- /dev/null +++ b/code/game/machinery/embedded_controller/airlock_controllers.dm @@ -0,0 +1,201 @@ +//base type for controllers of two-door systems +/obj/machinery/embedded_controller/radio/airlock + // Setup parameters only + radio_filter = RADIO_AIRLOCK + var/tag_exterior_door + var/tag_interior_door + var/tag_airpump + var/tag_chamber_sensor + var/tag_exterior_sensor + var/tag_interior_sensor + var/tag_airlock_mech_sensor + var/tag_shuttle_mech_sensor + var/tag_secure = 0 + var/list/dummy_terminals = list() + var/cycle_to_external_air = 0 + +/obj/machinery/embedded_controller/radio/airlock/New() + ..() + program = new/datum/computer/file/embedded_program/airlock(src) + +/obj/machinery/embedded_controller/radio/airlock/Destroy() + for(var/thing in dummy_terminals) + var/obj/machinery/dummy_airlock_controller/dummy = thing + dummy.master_controller = null + dummy_terminals.Cut() + return ..() + +/obj/machinery/embedded_controller/radio/airlock/CanUseTopic(var/mob/user) + if(!allowed(user)) + return min(STATUS_UPDATE, ..()) + else + return ..() + +//Advanced airlock controller for when you want a more versatile airlock controller - useful for turning simple access control rooms into airlocks +/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller + name = "Advanced Airlock Controller" + +/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nano_ui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) + var/data[0] + + data = list( + "chamber_pressure" = round(program.memory["chamber_sensor_pressure"]), + "external_pressure" = round(program.memory["external_sensor_pressure"]), + "internal_pressure" = round(program.memory["internal_sensor_pressure"]), + "processing" = program.memory["processing"], + "purge" = program.memory["purge"], + "secure" = program.memory["secure"] + ) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + + if (!ui) + ui = new(user, src, ui_key, "advanced_airlock_console.tmpl", name, 470, 290, state = state) + + ui.set_initial_data(data) + + ui.open() + + ui.set_auto_update(1) + +/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller/Topic(href, href_list) + if(..()) + return + + usr.set_machine(src) + + var/clean = 0 + switch(href_list["command"]) //anti-HTML-hacking checks + if("cycle_ext") + clean = 1 + if("cycle_int") + clean = 1 + if("force_ext") + clean = 1 + if("force_int") + clean = 1 + if("abort") + clean = 1 + if("purge") + clean = 1 + if("secure") + clean = 1 + + if(clean) + program.receive_user_command(href_list["command"]) + + return 1 + + +//Airlock controller for airlock control - most airlocks on the station use this +/obj/machinery/embedded_controller/radio/airlock/airlock_controller + name = "Airlock Controller" + tag_secure = 1 + +/obj/machinery/embedded_controller/radio/airlock/airlock_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nano_ui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) + var/data[0] + + data = list( + "chamber_pressure" = round(program.memory["chamber_sensor_pressure"]), + "exterior_status" = program.memory["exterior_status"], + "interior_status" = program.memory["interior_status"], + "processing" = program.memory["processing"], + ) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + + if (!ui) + ui = new(user, src, ui_key, "simple_airlock_console.tmpl", name, 470, 290, state = state) + + ui.set_initial_data(data) + + ui.open() + + ui.set_auto_update(1) + +/obj/machinery/embedded_controller/radio/airlock/airlock_controller/Topic(href, href_list) + if(..()) + return + + usr.set_machine(src) + + var/clean = 0 + switch(href_list["command"]) //anti-HTML-hacking checks + if("cycle_ext") + clean = 1 + if("cycle_int") + clean = 1 + if("force_ext") + clean = 1 + if("force_int") + clean = 1 + if("abort") + clean = 1 + + if(clean) + program.receive_user_command(href_list["command"]) + + return 1 + + +//Access controller for door control - used in virology and the like +/obj/machinery/embedded_controller/radio/airlock/access_controller + icon = 'icons/obj/airlock_machines.dmi' + icon_state = "access_control_standby" + + name = "Access Controller" + tag_secure = 1 + + +/obj/machinery/embedded_controller/radio/airlock/access_controller/update_icon() + if(on && program) + if(program.memory["processing"]) + icon_state = "access_control_process" + else + icon_state = "access_control_standby" + else + icon_state = "access_control_off" + +/obj/machinery/embedded_controller/radio/airlock/access_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nano_ui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) + var/data[0] + + data = list( + "exterior_status" = program.memory["exterior_status"], + "interior_status" = program.memory["interior_status"], + "processing" = program.memory["processing"] + ) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + + if (!ui) + ui = new(user, src, ui_key, "door_access_console.tmpl", name, 330, 220, state = state) + + ui.set_initial_data(data) + + ui.open() + + ui.set_auto_update(1) + +/obj/machinery/embedded_controller/radio/airlock/access_controller/Topic(href, href_list) + if(..()) + return + + usr.set_machine(src) + + var/clean = 0 + switch(href_list["command"]) //anti-HTML-hacking checks + if("cycle_ext_door") + clean = 1 + if("cycle_int_door") + clean = 1 + if("force_ext") + if(program.memory["interior_status"]["state"] == "closed") + clean = 1 + if("force_int") + if(program.memory["exterior_status"]["state"] == "closed") + clean = 1 + + if(clean) + program.receive_user_command(href_list["command"]) + + return 1 \ No newline at end of file diff --git a/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm b/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm new file mode 100644 index 00000000..9f912c47 --- /dev/null +++ b/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm @@ -0,0 +1,53 @@ +// Provides remote access to a controller (since they must be unique). +/obj/machinery/dummy_airlock_controller + name = "airlock control terminal" + icon = 'icons/obj/airlock_machines.dmi' + icon_state = "airlock_control_standby" + layer = ABOVE_OBJ_LAYER + + var/datum/topic_state/remote/remote_state + var/obj/machinery/embedded_controller/radio/airlock/master_controller + var/id_tag + +/obj/machinery/dummy_airlock_controller/Process() + if(master_controller) + appearance = master_controller + . = ..() + +/obj/machinery/dummy_airlock_controller/Initialize() + . = ..() + if(id_tag) + for(var/obj/machinery/embedded_controller/radio/airlock/_master in SSmachines.machinery) + if(_master.id_tag == id_tag) + master_controller = _master + master_controller.dummy_terminals += src + break + if(!master_controller) + qdel(src) + else + remote_state = new /datum/topic_state/remote(src, master_controller) + +/obj/machinery/dummy_airlock_controller/Destroy() + if(master_controller) + master_controller.dummy_terminals -= src + if(remote_state) + qdel(remote_state) + remote_state = null + return ..() + +/obj/machinery/dummy_airlock_controller/attack_ai(var/mob/user) + open_remote_ui(user) + +/obj/machinery/dummy_airlock_controller/attack_hand(var/mob/user) + open_remote_ui(user) + +/obj/machinery/dummy_airlock_controller/proc/open_remote_ui(var/mob/user) + if(master_controller) + appearance = master_controller + return master_controller.ui_interact(user, state = remote_state) + +/obj/machinery/dummy_airlock_controller/powered(var/chan = -1, var/area/check_area = null) + if(master_controller) + var/area/A = get_area(master_controller) + return master_controller.powered(chan, A) + return ..() \ No newline at end of file diff --git a/code/game/machinery/embedded_controller/airlock_docking_controller.dm b/code/game/machinery/embedded_controller/airlock_docking_controller.dm new file mode 100644 index 00000000..8dc76329 --- /dev/null +++ b/code/game/machinery/embedded_controller/airlock_docking_controller.dm @@ -0,0 +1,199 @@ +//a docking port based on an airlock +/obj/machinery/embedded_controller/radio/airlock/docking_port + name = "docking port controller" + var/datum/computer/file/embedded_program/airlock/docking/airlock_program + var/datum/computer/file/embedded_program/docking/airlock/docking_program + var/display_name //how would it show up on docking monitoring program, area name + coordinates if unset + tag_secure = 1 + +/obj/machinery/embedded_controller/radio/airlock/docking_port/New() + ..() + airlock_program = new/datum/computer/file/embedded_program/airlock/docking(src) + docking_program = new/datum/computer/file/embedded_program/docking/airlock(src, airlock_program) + program = docking_program + if(display_name) + docking_program.display_name = display_name + +/obj/machinery/embedded_controller/radio/airlock/docking_port/attackby(obj/item/W, mob/user) + if(istype(W,/obj/item/device/multitool)) //give them part of code, would take few tries to get full + var/code = docking_program.docking_codes + if(!code) + code = "N/A" + else + code = stars(code) + to_chat(user,"[W]'s screen displays '[code]'") + else + ..() + +/obj/machinery/embedded_controller/radio/airlock/docking_port/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nano_ui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) + var/data[0] + + data = list( + "chamber_pressure" = round(airlock_program.memory["chamber_sensor_pressure"]), + "exterior_status" = airlock_program.memory["exterior_status"], + "interior_status" = airlock_program.memory["interior_status"], + "processing" = airlock_program.memory["processing"], + "docking_status" = docking_program.get_docking_status(), + "airlock_disabled" = !(docking_program.undocked() || docking_program.override_enabled), + "override_enabled" = docking_program.override_enabled, + "docking_codes" = docking_program.docking_codes, + "name" = docking_program.get_name() + ) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + + if (!ui) + ui = new(user, src, ui_key, "docking_airlock_console.tmpl", name, 470, 290, state = state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/embedded_controller/radio/airlock/docking_port/Topic(href, href_list) + if(..()) + return + + usr.set_machine(src) + + var/clean = 0 + switch(href_list["command"]) //anti-HTML-hacking checks + if("cycle_ext") + clean = 1 + if("cycle_int") + clean = 1 + if("force_ext") + clean = 1 + if("force_int") + clean = 1 + if("abort") + clean = 1 + if("toggle_override") + clean = 1 + if("dock") + clean = 1 + + if(clean) + program.receive_user_command(href_list["command"]) + + return 1 + + + +//A docking controller for an airlock based docking port +/datum/computer/file/embedded_program/docking/airlock + var/datum/computer/file/embedded_program/airlock/docking/airlock_program + +/datum/computer/file/embedded_program/docking/airlock/New(var/obj/machinery/embedded_controller/M, var/datum/computer/file/embedded_program/airlock/docking/A) + ..(M) + airlock_program = A + airlock_program.master_prog = src + +/datum/computer/file/embedded_program/docking/airlock/receive_user_command(command) + if (command == "toggle_override") + if (override_enabled) + disable_override() + else + enable_override() + return + + ..(command) + airlock_program.receive_user_command(command) //pass along to subprograms + +/datum/computer/file/embedded_program/docking/airlock/process() + airlock_program.process() + ..() + +/datum/computer/file/embedded_program/docking/airlock/receive_signal(datum/signal/signal, receive_method, receive_param) + airlock_program.receive_signal(signal, receive_method, receive_param) //pass along to subprograms + ..(signal, receive_method, receive_param) + +//tell the docking port to start getting ready for docking - e.g. pressurize +/datum/computer/file/embedded_program/docking/airlock/prepare_for_docking() + airlock_program.begin_cycle_in() + +//are we ready for docking? +/datum/computer/file/embedded_program/docking/airlock/ready_for_docking() + return airlock_program.done_cycling() + +//we are docked, open the doors or whatever. +/datum/computer/file/embedded_program/docking/airlock/finish_docking() + airlock_program.enable_mech_regulators() + airlock_program.open_doors() + +//tell the docking port to start getting ready for undocking - e.g. close those doors. +/datum/computer/file/embedded_program/docking/airlock/prepare_for_undocking() + airlock_program.stop_cycling() + airlock_program.close_doors() + airlock_program.disable_mech_regulators() + +//are we ready for undocking? +/datum/computer/file/embedded_program/docking/airlock/ready_for_undocking() + var/ext_closed = airlock_program.check_exterior_door_secured() + var/int_closed = airlock_program.check_interior_door_secured() + return (ext_closed || int_closed) + +//An airlock controller to be used by the airlock-based docking port controller. +//Same as a regular airlock controller but allows disabling of the regular airlock functions when docking +/datum/computer/file/embedded_program/airlock/docking + var/datum/computer/file/embedded_program/docking/airlock/master_prog + +/datum/computer/file/embedded_program/airlock/docking/receive_user_command(command) + if (master_prog.undocked() || master_prog.override_enabled) //only allow the port to be used as an airlock if nothing is docked here or the override is enabled + ..(command) + +/datum/computer/file/embedded_program/airlock/docking/proc/enable_mech_regulators() + enable_mech_regulation() + +/datum/computer/file/embedded_program/airlock/docking/proc/disable_mech_regulators() + disable_mech_regulation() + +/datum/computer/file/embedded_program/airlock/docking/proc/open_doors() + toggleDoor(memory["interior_status"], tag_interior_door, memory["secure"], "open") + toggleDoor(memory["exterior_status"], tag_exterior_door, memory["secure"], "open") + +/datum/computer/file/embedded_program/airlock/docking/cycleDoors(var/target) + if (master_prog.undocked() || master_prog.override_enabled) //only allow the port to be used as an airlock if nothing is docked here or the override is enabled + ..(target) + +/*** DEBUG VERBS *** + +/datum/computer/file/embedded_program/docking/proc/print_state() + log_debug("id_tag: [id_tag]") + log_debug("dock_state: [dock_state]") + log_debug("control_mode: [control_mode]") + log_debug("tag_target: [tag_target]") + log_debug("response_sent: [response_sent]") + +/datum/computer/file/embedded_program/docking/post_signal(datum/signal/signal, comm_line) + log_debug("Program [id_tag] sent a message!") + + print_state() + log_debug("[id_tag] sent command \"[signal.data["command"]]\" to \"[signal.data["recipient"]]\"") + + ..(signal) + +/obj/machinery/embedded_controller/radio/airlock/docking_port/verb/view_state() + set category = "Debug" + set src in view(1) + src.program:print_state() + +/obj/machinery/embedded_controller/radio/airlock/docking_port/verb/spoof_signal(var/command as text, var/sender as text) + set category = "Debug" + set src in view(1) + var/datum/signal/signal = new + signal.data["tag"] = sender + signal.data["command"] = command + signal.data["recipient"] = id_tag + + src.program:receive_signal(signal) + +/obj/machinery/embedded_controller/radio/airlock/docking_port/verb/debug_init_dock(var/target as text) + set category = "Debug" + set src in view(1) + src.program:initiate_docking(target) + +/obj/machinery/embedded_controller/radio/airlock/docking_port/verb/debug_init_undock() + set category = "Debug" + set src in view(1) + src.program:initiate_undocking() + +*/ \ No newline at end of file diff --git a/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm b/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm new file mode 100644 index 00000000..6b7488bc --- /dev/null +++ b/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm @@ -0,0 +1,154 @@ +//a controller for a docking port with multiple independent airlocks +//this is the master controller, that things will try to dock with. +/obj/machinery/embedded_controller/radio/docking_port_multi + name = "docking port controller" + + var/child_tags_txt + var/child_names_txt + var/list/child_names = list() + + var/datum/computer/file/embedded_program/docking/multi/docking_program + +/obj/machinery/embedded_controller/radio/docking_port_multi/New() + ..() + docking_program = new/datum/computer/file/embedded_program/docking/multi(src) + program = docking_program + + var/list/names = splittext(child_names_txt, ";") + var/list/tags = splittext(child_tags_txt, ";") + + if (names.len == tags.len) + for (var/i = 1; i <= tags.len; i++) + child_names[tags[i]] = names[i] + + +/obj/machinery/embedded_controller/radio/docking_port_multi/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nano_ui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) + var/data[0] + + var/list/airlocks[child_names.len] + var/i = 1 + for (var/child_tag in child_names) + airlocks[i++] = list("name"=child_names[child_tag], "override_enabled"=(docking_program.children_override[child_tag] == "enabled")) + + data = list( + "docking_status" = docking_program.get_docking_status(), + "airlocks" = airlocks, + ) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + + if (!ui) + ui = new(user, src, ui_key, "multi_docking_console.tmpl", name, 470, 290, state = state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/embedded_controller/radio/docking_port_multi/Topic(href, href_list) + return + + + +//a docking port based on an airlock +/obj/machinery/embedded_controller/radio/airlock/docking_port_multi + name = "docking port controller" + var/master_tag //for mapping + var/datum/computer/file/embedded_program/airlock/multi_docking/airlock_program + tag_secure = 1 + +/obj/machinery/embedded_controller/radio/airlock/docking_port_multi/Initialize() + . = ..() + airlock_program = new/datum/computer/file/embedded_program/airlock/multi_docking(src) + program = airlock_program + +/obj/machinery/embedded_controller/radio/airlock/docking_port_multi/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nano_ui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) + var/data[0] + + data = list( + "chamber_pressure" = round(airlock_program.memory["chamber_sensor_pressure"]), + "exterior_status" = airlock_program.memory["exterior_status"], + "interior_status" = airlock_program.memory["interior_status"], + "processing" = airlock_program.memory["processing"], + "docking_status" = airlock_program.master_status, + "airlock_disabled" = (airlock_program.docking_enabled && !airlock_program.override_enabled), + "override_enabled" = airlock_program.override_enabled, + ) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + + if (!ui) + ui = new(user, src, ui_key, "docking_airlock_console.tmpl", name, 470, 290, state = state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/embedded_controller/radio/airlock/docking_port_multi/Topic(href, href_list) + if(..()) + return + + usr.set_machine(src) + + var/clean = 0 + switch(href_list["command"]) //anti-HTML-hacking checks + if("cycle_ext") + clean = 1 + if("cycle_int") + clean = 1 + if("force_ext") + clean = 1 + if("force_int") + clean = 1 + if("abort") + clean = 1 + if("toggle_override") + clean = 1 + + if(clean) + program.receive_user_command(href_list["command"]) + + return 1 + + + +/*** DEBUG VERBS *** + +/datum/computer/file/embedded_program/docking/multi/proc/print_state() + log_debug("id_tag: [id_tag]") + log_debug("dock_state: [dock_state]") + log_debug("control_mode: [control_mode]") + log_debug("tag_target: [tag_target]") + log_debug("response_sent: [response_sent]") + +/datum/computer/file/embedded_program/docking/multi/post_signal(datum/signal/signal, comm_line) + log_debug("Program [id_tag] sent a message!") + + print_state() + log_debug("[id_tag] sent command \"[signal.data["command"]]\" to \"[signal.data["recipient"]]\"") + + ..(signal) + +/obj/machinery/embedded_controller/radio/docking_port_multi/verb/view_state() + set category = "Debug" + set src in view(1) + src.program:print_state() + +/obj/machinery/embedded_controller/radio/docking_port_multi/verb/spoof_signal(var/command as text, var/sender as text) + set category = "Debug" + set src in view(1) + var/datum/signal/signal = new + signal.data["tag"] = sender + signal.data["command"] = command + signal.data["recipient"] = id_tag + + src.program:receive_signal(signal) + +/obj/machinery/embedded_controller/radio/docking_port_multi/verb/debug_init_dock(var/target as text) + set category = "Debug" + set src in view(1) + src.program:initiate_docking(target) + +/obj/machinery/embedded_controller/radio/docking_port_multi/verb/debug_init_undock() + set category = "Debug" + set src in view(1) + src.program:initiate_undocking() + +*/ diff --git a/code/game/machinery/embedded_controller/airlock_program.dm b/code/game/machinery/embedded_controller/airlock_program.dm new file mode 100644 index 00000000..f8341921 --- /dev/null +++ b/code/game/machinery/embedded_controller/airlock_program.dm @@ -0,0 +1,414 @@ +//Handles the control of airlocks + +#define STATE_IDLE 0 +#define STATE_PREPARE 1 +#define STATE_DEPRESSURIZE 2 +#define STATE_PRESSURIZE 3 + +#define TARGET_NONE 0 +#define TARGET_INOPEN -1 +#define TARGET_OUTOPEN -2 + +#define SENSOR_TOLERANCE 1 + +/datum/computer/file/embedded_program/airlock + var/tag_exterior_door + var/tag_interior_door + var/tag_airpump + var/tag_chamber_sensor + var/tag_exterior_sensor + var/tag_interior_sensor + var/tag_airlock_mech_sensor + var/tag_shuttle_mech_sensor + + var/state = STATE_IDLE + var/target_state = TARGET_NONE + + var/cycle_to_external_air = 0 + var/tag_pump_out_external + var/tag_pump_out_internal + +/datum/computer/file/embedded_program/airlock/New(var/obj/machinery/embedded_controller/M) + ..(M) + + memory["chamber_sensor_pressure"] = ONE_ATMOSPHERE + memory["external_sensor_pressure"] = 0 //assume vacuum for simple airlock controller + memory["internal_sensor_pressure"] = ONE_ATMOSPHERE + memory["exterior_status"] = list(state = "closed", lock = "locked") //assume closed and locked in case the doors dont report in + memory["interior_status"] = list(state = "closed", lock = "locked") + memory["pump_status"] = "unknown" + memory["target_pressure"] = ONE_ATMOSPHERE + memory["purge"] = 0 + memory["secure"] = 0 + + if (istype(M, /obj/machinery/embedded_controller/radio/airlock)) //if our controller is an airlock controller than we can auto-init our tags + var/obj/machinery/embedded_controller/radio/airlock/controller = M + cycle_to_external_air = controller.cycle_to_external_air + if(cycle_to_external_air) + tag_pump_out_external = "[id_tag]_pump_out_external" + tag_pump_out_internal = "[id_tag]_pump_out_internal" + tag_exterior_door = controller.tag_exterior_door? controller.tag_exterior_door : "[id_tag]_outer" + tag_interior_door = controller.tag_interior_door? controller.tag_interior_door : "[id_tag]_inner" + tag_airpump = controller.tag_airpump? controller.tag_airpump : "[id_tag]_pump" + tag_chamber_sensor = controller.tag_chamber_sensor? controller.tag_chamber_sensor : "[id_tag]_sensor" + tag_exterior_sensor = controller.tag_exterior_sensor + tag_interior_sensor = controller.tag_interior_sensor + tag_airlock_mech_sensor = controller.tag_airlock_mech_sensor? controller.tag_airlock_mech_sensor : "[id_tag]_airlock_mech" + tag_shuttle_mech_sensor = controller.tag_shuttle_mech_sensor? controller.tag_shuttle_mech_sensor : "[id_tag]_shuttle_mech" + memory["secure"] = controller.tag_secure + + spawn(10) + signalDoor(tag_exterior_door, "update") //signals connected doors to update their status + signalDoor(tag_interior_door, "update") + +/datum/computer/file/embedded_program/airlock/receive_signal(datum/signal/signal, receive_method, receive_param) + var/receive_tag = signal.data["tag"] + if(!receive_tag) return + + if(receive_tag==tag_chamber_sensor) + if(signal.data["pressure"]) + memory["chamber_sensor_pressure"] = text2num(signal.data["pressure"]) + + else if(receive_tag==tag_exterior_sensor) + memory["external_sensor_pressure"] = text2num(signal.data["pressure"]) + + else if(receive_tag==tag_interior_sensor) + memory["internal_sensor_pressure"] = text2num(signal.data["pressure"]) + + else if(receive_tag==tag_exterior_door) + memory["exterior_status"]["state"] = signal.data["door_status"] + memory["exterior_status"]["lock"] = signal.data["lock_status"] + + else if(receive_tag==tag_interior_door) + memory["interior_status"]["state"] = signal.data["door_status"] + memory["interior_status"]["lock"] = signal.data["lock_status"] + + else if(receive_tag==tag_airpump || receive_tag==tag_pump_out_internal) + if(signal.data["power"]) + memory["pump_status"] = signal.data["direction"] + else + memory["pump_status"] = "off" + + else if(receive_tag==id_tag) + if(istype(master, /obj/machinery/embedded_controller/radio/airlock/access_controller)) + switch(signal.data["command"]) + if("cycle_exterior") + receive_user_command("cycle_ext_door") + if("cycle_interior") + receive_user_command("cycle_int_door") + if("cycle") + if(memory["interior_status"]["state"] == "open") //handle backwards compatibility + receive_user_command("cycle_ext") + else + receive_user_command("cycle_int") + else + switch(signal.data["command"]) + if("cycle_exterior") + receive_user_command("cycle_ext") + if("cycle_interior") + receive_user_command("cycle_int") + if("cycle") + if(memory["interior_status"]["state"] == "open") //handle backwards compatibility + receive_user_command("cycle_ext") + else + receive_user_command("cycle_int") + + +/datum/computer/file/embedded_program/airlock/receive_user_command(command) + var/shutdown_pump = 0 + switch(command) + if("cycle_ext") + //If airlock is already cycled in this direction, just toggle the doors. + if(!memory["purge"] && IsInRange(memory["external_sensor_pressure"], memory["chamber_sensor_pressure"] - SENSOR_TOLERANCE, memory["chamber_sensor_pressure"] + SENSOR_TOLERANCE)) + toggleDoor(memory["exterior_status"], tag_exterior_door, memory["secure"], "toggle") + //only respond to these commands if the airlock isn't already doing something + //prevents the controller from getting confused and doing strange things + else if(state == target_state) + begin_cycle_out() + + if("cycle_int") + if(!memory["purge"] && IsInRange(memory["internal_sensor_pressure"], memory["chamber_sensor_pressure"] - SENSOR_TOLERANCE, memory["chamber_sensor_pressure"] + SENSOR_TOLERANCE)) + toggleDoor(memory["interior_status"], tag_interior_door, memory["secure"], "toggle") + else if(state == target_state) + begin_cycle_in() + + if("cycle_ext_door") + cycleDoors(TARGET_OUTOPEN) + + if("cycle_int_door") + cycleDoors(TARGET_INOPEN) + + if("abort") + stop_cycling() + + if("force_ext") + toggleDoor(memory["exterior_status"], tag_exterior_door, memory["secure"], "toggle") + + if("force_int") + toggleDoor(memory["interior_status"], tag_interior_door, memory["secure"], "toggle") + + if("purge") + memory["purge"] = !memory["purge"] + if(memory["purge"]) + close_doors() + state = STATE_PREPARE + target_state = TARGET_NONE + + if("secure") + memory["secure"] = !memory["secure"] + if(memory["secure"]) + signalDoor(tag_interior_door, "lock") + signalDoor(tag_exterior_door, "lock") + else + signalDoor(tag_interior_door, "unlock") + signalDoor(tag_exterior_door, "unlock") + + if(shutdown_pump) + signalPump(tag_airpump, 0) //send a signal to stop pressurizing + if(cycle_to_external_air) + signalPump(tag_pump_out_internal, 0) + signalPump(tag_pump_out_external, 0) + + + +/datum/computer/file/embedded_program/airlock/process() + if(!state) //Idle + if(target_state) + switch(target_state) + if(TARGET_INOPEN) + memory["target_pressure"] = memory["internal_sensor_pressure"] + if(TARGET_OUTOPEN) + memory["target_pressure"] = memory["external_sensor_pressure"] + + //lock down the airlock before activating pumps + close_doors() + + state = STATE_PREPARE + else + //make sure to return to a sane idle state + if(memory["pump_status"] != "off") //send a signal to stop pumping + signalPump(tag_airpump, 0) + if(cycle_to_external_air) + signalPump(tag_pump_out_internal, 0) + signalPump(tag_pump_out_external, 0) + + if ((state == STATE_PRESSURIZE || state == STATE_DEPRESSURIZE) && !check_doors_secured()) + //the airlock will not allow itself to continue to cycle when any of the doors are forced open. + stop_cycling() + + switch(state) + if(STATE_PREPARE) + if (check_doors_secured()) + var/chamber_pressure = memory["chamber_sensor_pressure"] + var/target_pressure = memory["target_pressure"] + + if(memory["purge"]) + //purge apparently means clearing the airlock chamber to vacuum (then refilling, handled later) + target_pressure = 0 + state = STATE_DEPRESSURIZE + if(!cycle_to_external_air || target_state == TARGET_OUTOPEN) // if going outside, pump internal air into air tank + signalPump(tag_airpump, 1, 0, target_pressure) //send a signal to start depressurizing + else + signalPump(tag_pump_out_internal, 1, 0, target_pressure) // if going inside, pump external air out of the airlock + signalPump(tag_pump_out_external, 1, 1, 1000) // make sure the air is actually going outside + + else if(chamber_pressure <= target_pressure) + state = STATE_PRESSURIZE + if(!cycle_to_external_air || target_state == TARGET_INOPEN) // if going inside, pump air into airlock + signalPump(tag_airpump, 1, 1, target_pressure) //send a signal to start pressurizing + else + signalPump(tag_pump_out_internal, 1, 1, target_pressure) // if going outside, fill airlock with external air + signalPump(tag_pump_out_external, 1, 0, 0) + + else if(chamber_pressure > target_pressure) + if(!cycle_to_external_air) + state = STATE_DEPRESSURIZE + signalPump(tag_airpump, 1, 0, target_pressure) //send a signal to start depressurizing + else + memory["purge"] = 1 // should always purge first if using external air, chamber pressure should never be higher than target pressure here + + memory["target_pressure"] = target_pressure + + if(STATE_PRESSURIZE) + if(memory["chamber_sensor_pressure"] >= memory["target_pressure"] - SENSOR_TOLERANCE) + //not done until the pump has reported that it's off + if(memory["pump_status"] != "off") //send a signal to stop pumping + signalPump(tag_airpump, 0) + if(cycle_to_external_air) + signalPump(tag_pump_out_internal, 0) + signalPump(tag_pump_out_external, 0) + else + cycleDoors(target_state) + state = STATE_IDLE + target_state = TARGET_NONE + + + if(STATE_DEPRESSURIZE) + if(memory["chamber_sensor_pressure"] <= memory["target_pressure"] + SENSOR_TOLERANCE) + if(memory["pump_status"] != "off") + signalPump(tag_airpump, 0) + if(cycle_to_external_air) + signalPump(tag_pump_out_internal, 0) + signalPump(tag_pump_out_external, 0) + else + if(memory["purge"]) + memory["purge"] = 0 + memory["target_pressure"] = (target_state == TARGET_INOPEN ? memory["internal_sensor_pressure"] : memory["external_sensor_pressure"]) + if (memory["target_pressure"] > SENSOR_TOLERANCE) + state = STATE_PREPARE + else + cycleDoors(target_state) + state = STATE_IDLE + target_state = TARGET_NONE + + + memory["processing"] = (state != target_state) + + return 1 + +//these are here so that other types don't have to make so many assuptions about our implementation + +/datum/computer/file/embedded_program/airlock/proc/begin_cycle_in() + state = STATE_IDLE + target_state = TARGET_INOPEN + memory["purge"] = cycle_to_external_air + +/datum/computer/file/embedded_program/airlock/proc/begin_cycle_out() + state = STATE_IDLE + target_state = TARGET_OUTOPEN + memory["purge"] = cycle_to_external_air + +/datum/computer/file/embedded_program/airlock/proc/close_doors() + toggleDoor(memory["interior_status"], tag_interior_door, 1, "close") + toggleDoor(memory["exterior_status"], tag_exterior_door, 1, "close") + +/datum/computer/file/embedded_program/airlock/proc/stop_cycling() + state = STATE_IDLE + target_state = TARGET_NONE + +/datum/computer/file/embedded_program/airlock/proc/done_cycling() + return (state == STATE_IDLE && target_state == TARGET_NONE) + +//are the doors closed and locked? +/datum/computer/file/embedded_program/airlock/proc/check_exterior_door_secured() + return (memory["exterior_status"]["state"] == "closed" && memory["exterior_status"]["lock"] == "locked") + +/datum/computer/file/embedded_program/airlock/proc/check_interior_door_secured() + return (memory["interior_status"]["state"] == "closed" && memory["interior_status"]["lock"] == "locked") + +/datum/computer/file/embedded_program/airlock/proc/check_doors_secured() + var/ext_closed = check_exterior_door_secured() + var/int_closed = check_interior_door_secured() + return (ext_closed && int_closed) + +/datum/computer/file/embedded_program/airlock/proc/signalDoor(var/tag, var/command) + var/datum/signal/signal = new + signal.data["tag"] = tag + signal.data["command"] = command + post_signal(signal, RADIO_AIRLOCK) + +/datum/computer/file/embedded_program/airlock/proc/signalPump(var/tag, var/power, var/direction, var/pressure) + var/datum/signal/signal = new + signal.data = list( + "tag" = tag, + "sigtype" = "command", + "power" = power, + "direction" = direction, + "set_external_pressure" = pressure + ) + post_signal(signal) + +//this is called to set the appropriate door state at the end of a cycling process, or for the exterior buttons +/datum/computer/file/embedded_program/airlock/proc/cycleDoors(var/target) + switch(target) + if(TARGET_OUTOPEN) + toggleDoor(memory["interior_status"], tag_interior_door, memory["secure"], "close") + toggleDoor(memory["exterior_status"], tag_exterior_door, memory["secure"], "open") + + if(TARGET_INOPEN) + toggleDoor(memory["exterior_status"], tag_exterior_door, memory["secure"], "close") + toggleDoor(memory["interior_status"], tag_interior_door, memory["secure"], "open") + if(TARGET_NONE) + var/command = "unlock" + if(memory["secure"]) + command = "lock" + signalDoor(tag_exterior_door, command) + signalDoor(tag_interior_door, command) + +datum/computer/file/embedded_program/airlock/proc/signal_mech_sensor(var/command, var/sensor) + var/datum/signal/signal = new + signal.data["tag"] = sensor + signal.data["command"] = command + post_signal(signal) + +/datum/computer/file/embedded_program/airlock/proc/enable_mech_regulation() + signal_mech_sensor("enable", tag_shuttle_mech_sensor) + signal_mech_sensor("enable", tag_airlock_mech_sensor) + +/datum/computer/file/embedded_program/airlock/proc/disable_mech_regulation() + signal_mech_sensor("disable", tag_shuttle_mech_sensor) + signal_mech_sensor("disable", tag_airlock_mech_sensor) + +/*---------------------------------------------------------- +toggleDoor() + +Sends a radio command to a door to either open or close. If +the command is 'toggle' the door will be sent a command that +reverses it's current state. +Can also toggle whether the door bolts are locked or not, +depending on the state of the 'secure' flag. +Only sends a command if it is needed, i.e. if the door is +already open, passing an open command to this proc will not +send an additional command to open the door again. +----------------------------------------------------------*/ +/datum/computer/file/embedded_program/airlock/proc/toggleDoor(var/list/doorStatus, var/doorTag, var/secure, var/command) + var/doorCommand = null + + if(command == "toggle") + if(doorStatus["state"] == "open") + command = "close" + else if(doorStatus["state"] == "closed") + command = "open" + + switch(command) + if("close") + if(secure) + if(doorStatus["state"] == "open") + doorCommand = "secure_close" + else if(doorStatus["lock"] == "unlocked") + doorCommand = "lock" + else + if(doorStatus["state"] == "open") + if(doorStatus["lock"] == "locked") + signalDoor(doorTag, "unlock") + doorCommand = "close" + else if(doorStatus["lock"] == "locked") + doorCommand = "unlock" + + if("open") + if(secure) + if(doorStatus["state"] == "closed") + doorCommand = "secure_open" + else if(doorStatus["lock"] == "unlocked") + doorCommand = "lock" + else + if(doorStatus["state"] == "closed") + if(doorStatus["lock"] == "locked") + signalDoor(doorTag,"unlock") + doorCommand = "open" + else if(doorStatus["lock"] == "locked") + doorCommand = "unlock" + + if(doorCommand) + signalDoor(doorTag, doorCommand) + + +#undef STATE_IDLE +#undef STATE_DEPRESSURIZE +#undef STATE_PRESSURIZE + +#undef TARGET_NONE +#undef TARGET_INOPEN +#undef TARGET_OUTOPEN + +#undef SENSOR_TOLERANCE \ No newline at end of file diff --git a/code/game/machinery/embedded_controller/docking_program.dm b/code/game/machinery/embedded_controller/docking_program.dm new file mode 100644 index 00000000..a269722e --- /dev/null +++ b/code/game/machinery/embedded_controller/docking_program.dm @@ -0,0 +1,311 @@ + +#define STATE_UNDOCKED 0 +#define STATE_DOCKING 1 +#define STATE_UNDOCKING 2 +#define STATE_DOCKED 3 + +#define MODE_NONE 0 +#define MODE_SERVER 1 +#define MODE_CLIENT 2 //The one who initiated the docking, and who can initiate the undocking. The server cannot initiate undocking, and is the one responsible for deciding to accept a docking request and signals when docking and undocking is complete. (Think server == station, client == shuttle) + +#define MESSAGE_RESEND_TIME 5 //how long (in seconds) do we wait before resending a message + +/* + *** STATE TABLE *** + + MODE_CLIENT|STATE_UNDOCKED sent a request for docking and now waiting for a reply. + MODE_CLIENT|STATE_DOCKING server told us they are OK to dock, waiting for our docking port to be ready. + MODE_CLIENT|STATE_DOCKED idle - docked as client. + MODE_CLIENT|STATE_UNDOCKING we are either waiting for our docking port to be ready or for the server to give us the OK to finish undocking. + + MODE_SERVER|STATE_UNDOCKED should never happen. + MODE_SERVER|STATE_DOCKING someone requested docking, we are waiting for our docking port to be ready. + MODE_SERVER|STATE_DOCKED idle - docked as server + MODE_SERVER|STATE_UNDOCKING client requested undocking, we are waiting for our docking port to be ready. + + MODE_NONE|STATE_UNDOCKED idle - not docked. + MODE_NONE|anything else should never happen. + + *** Docking Signals *** + + Docking + Client sends request_dock + Server sends confirm_dock to say that yes, we will serve your request + When client is ready, sends confirm_dock + Server sends confirm_dock back to indicate that docking is complete + + Undocking + Client sends request_undock + When client is ready, sends confirm_undock + Server sends confirm_undock back to indicate that docking is complete + + Note that in both cases each side exchanges confirm_dock before the docking operation is considered done. + The client first sends a confirm message to indicate it is ready, and then finally the server will send it's + confirm message to indicate that the operation is complete. + + Note also that when docking, the server sends an additional confirm message. This is because before docking, + the server and client do not have a defined relationship. Before undocking, the server and client are already + related to each other, thus the extra confirm message is not needed. + + *** Override, what is it? *** + + The purpose of enabling the override is to prevent the docking program from automatically doing things with the docking port when docking or undocking. + Maybe the shuttle is full of plamsa/phoron for some reason, and you don't want the door to automatically open, or the airlock to cycle. + This means that the prepare_for_docking/undocking and finish_docking/undocking procs don't get called. + + The docking controller will still check the state of the docking port, and thus prevent the shuttle from launching unless they force the launch (handling forced + launches is not the docking controller's responsibility). In this case it is up to the players to manually get the docking port into a good state to undock + (which usually just means closing and locking the doors). + + In line with this, docking controllers should prevent players from manually doing things when the override is NOT enabled. +*/ + + +/datum/computer/file/embedded_program/docking + var/tag_target //the tag of the docking controller that we are trying to dock with + var/dock_state = STATE_UNDOCKED + var/control_mode = MODE_NONE + var/response_sent = 0 //so we don't spam confirmation messages + var/resend_counter = 0 //for periodically resending confirmation messages in case they are missed + + var/override_enabled = 0 //when enabled, do not open/close doors or cycle airlocks and wait for the player to do it manually + var/received_confirm = 0 //for undocking, whether the server has recieved a confirmation from the client + var/docking_codes //would only allow docking when receiving signal with these, if set + var/display_name //how would it show up on docking monitoring program, area name + coordinates if unset + +/datum/computer/file/embedded_program/docking/New(var/obj/machinery/embedded_controller/M) + ..() + if(id_tag) + tag = id_tag //set tags for initialization + +/datum/computer/file/embedded_program/docking/receive_user_command(command) + if(command == "dock") + var/datum/signal/signal = new() + signal.data["tag"] = tag_target + signal.data["command"] = "request_dock" + signal.data["recipient"] = id_tag + signal.data["code"] = docking_codes + receive_signal(signal) + +/datum/computer/file/embedded_program/docking/receive_signal(datum/signal/signal, receive_method, receive_param) + var/receive_tag = signal.data["tag"] //for docking signals, this is the sender id + var/command = signal.data["command"] + var/recipient = signal.data["recipient"] //the intended recipient of the docking signal + + if (recipient != id_tag) + return //this signal is not for us + + switch (command) + if ("confirm_dock") + if (control_mode == MODE_CLIENT && dock_state == STATE_UNDOCKED && receive_tag == tag_target) + dock_state = STATE_DOCKING + broadcast_docking_status() + if (!override_enabled) + prepare_for_docking() + + else if (control_mode == MODE_CLIENT && dock_state == STATE_DOCKING && receive_tag == tag_target) + dock_state = STATE_DOCKED + broadcast_docking_status() + if (!override_enabled) + finish_docking() //client done docking! + response_sent = 0 + else if (control_mode == MODE_SERVER && dock_state == STATE_DOCKING && receive_tag == tag_target) //client just sent us the confirmation back, we're done with the docking process + received_confirm = 1 + + if ("request_dock") + if (control_mode == MODE_NONE && dock_state == STATE_UNDOCKED) + tag_target = receive_tag + + if(docking_codes) + var/code = signal.data["code"] + if(code != docking_codes) + return + + control_mode = MODE_SERVER + + dock_state = STATE_DOCKING + broadcast_docking_status() + + if (!override_enabled) + prepare_for_docking() + send_docking_command(tag_target, "confirm_dock") //acknowledge the request + + if ("confirm_undock") + if (control_mode == MODE_CLIENT && dock_state == STATE_UNDOCKING && receive_tag == tag_target) + if (!override_enabled) + finish_undocking() + reset() //client is done undocking! + else if (control_mode == MODE_SERVER && dock_state == STATE_UNDOCKING && receive_tag == tag_target) + received_confirm = 1 + + if ("request_undock") + if (control_mode == MODE_SERVER && dock_state == STATE_DOCKED && receive_tag == tag_target) + dock_state = STATE_UNDOCKING + broadcast_docking_status() + + if (!override_enabled) + prepare_for_undocking() + + if ("dock_error") + if (receive_tag == tag_target) + reset() + +/datum/computer/file/embedded_program/docking/process() + switch(dock_state) + if (STATE_DOCKING) //waiting for our docking port to be ready for docking + if (ready_for_docking()) + if (control_mode == MODE_CLIENT) + if (!response_sent) + send_docking_command(tag_target, "confirm_dock") //tell the server we're ready + response_sent = 1 + + else if (control_mode == MODE_SERVER && received_confirm) + send_docking_command(tag_target, "confirm_dock") //tell the client we are done docking. + + dock_state = STATE_DOCKED + broadcast_docking_status() + + if (!override_enabled) + finish_docking() //server done docking! + response_sent = 0 + received_confirm = 0 + + if (STATE_UNDOCKING) + if (ready_for_undocking()) + if (control_mode == MODE_CLIENT) + if (!response_sent) + send_docking_command(tag_target, "confirm_undock") //tell the server we are OK to undock. + response_sent = 1 + + else if (control_mode == MODE_SERVER && received_confirm) + send_docking_command(tag_target, "confirm_undock") //tell the client we are done undocking. + if (!override_enabled) + finish_undocking() + reset() //server is done undocking! + + if (response_sent || resend_counter > 0) + resend_counter++ + + if (resend_counter >= MESSAGE_RESEND_TIME || (dock_state != STATE_DOCKING && dock_state != STATE_UNDOCKING)) + response_sent = 0 + resend_counter = 0 + + //handle invalid states + if (control_mode == MODE_NONE && dock_state != STATE_UNDOCKED) + if (tag_target) + send_docking_command(tag_target, "dock_error") + reset() + if (control_mode == MODE_SERVER && dock_state == STATE_UNDOCKED) + control_mode = MODE_NONE + + +/datum/computer/file/embedded_program/docking/proc/initiate_docking(var/target) + if (dock_state != STATE_UNDOCKED || control_mode == MODE_SERVER) //must be undocked and not serving another request to begin a new docking handshake + return + + tag_target = target + control_mode = MODE_CLIENT + + send_docking_command(tag_target, "request_dock") + +/datum/computer/file/embedded_program/docking/proc/initiate_undocking() + if (dock_state != STATE_DOCKED || control_mode != MODE_CLIENT) //must be docked and must be client to start undocking + return + + dock_state = STATE_UNDOCKING + broadcast_docking_status() + + if (!override_enabled) + prepare_for_undocking() + + send_docking_command(tag_target, "request_undock") + +//tell the docking port to start getting ready for docking - e.g. pressurize +/datum/computer/file/embedded_program/docking/proc/prepare_for_docking() + return + +//are we ready for docking? +/datum/computer/file/embedded_program/docking/proc/ready_for_docking() + return 1 + +//we are docked, open the doors or whatever. +/datum/computer/file/embedded_program/docking/proc/finish_docking() + return + +//tell the docking port to start getting ready for undocking - e.g. close those doors. +/datum/computer/file/embedded_program/docking/proc/prepare_for_undocking() + return + +//we are docked, open the doors or whatever. +/datum/computer/file/embedded_program/docking/proc/finish_undocking() + return + +//are we ready for undocking? +/datum/computer/file/embedded_program/docking/proc/ready_for_undocking() + return 1 + +/datum/computer/file/embedded_program/docking/proc/enable_override() + override_enabled = 1 + +/datum/computer/file/embedded_program/docking/proc/disable_override() + override_enabled = 0 + +/datum/computer/file/embedded_program/docking/proc/reset() + dock_state = STATE_UNDOCKED + broadcast_docking_status() + + control_mode = MODE_NONE + tag_target = null + response_sent = 0 + received_confirm = 0 + +/datum/computer/file/embedded_program/docking/proc/force_undock() +// log_debug("[id_tag]: forcing undock") + + if (tag_target) + send_docking_command(tag_target, "dock_error") + reset() + +/datum/computer/file/embedded_program/docking/proc/docked() + return (dock_state == STATE_DOCKED) + +/datum/computer/file/embedded_program/docking/proc/undocked() + return (dock_state == STATE_UNDOCKED) + +//returns 1 if we are saftely undocked (and the shuttle can leave) +/datum/computer/file/embedded_program/docking/proc/can_launch() + return undocked() + +/datum/computer/file/embedded_program/docking/proc/send_docking_command(var/recipient, var/command) + var/datum/signal/signal = new + signal.data["tag"] = id_tag + signal.data["command"] = command + signal.data["recipient"] = recipient + signal.data["code"] = docking_codes + post_signal(signal) + +/datum/computer/file/embedded_program/docking/proc/broadcast_docking_status() + var/datum/signal/signal = new + signal.data["tag"] = id_tag + signal.data["dock_status"] = get_docking_status() + post_signal(signal) + +//this is mostly for NanoUI +/datum/computer/file/embedded_program/docking/proc/get_docking_status() + switch (dock_state) + if (STATE_UNDOCKED) return "undocked" + if (STATE_DOCKING) return "docking" + if (STATE_UNDOCKING) return "undocking" + if (STATE_DOCKED) return "docked" + +/datum/computer/file/embedded_program/docking/proc/get_name() + return display_name ? display_name : "[get_area(master)] ([master.x], [master.y])" + +#undef STATE_UNDOCKED +#undef STATE_DOCKING +#undef STATE_UNDOCKING +#undef STATE_DOCKED + +#undef MODE_NONE +#undef MODE_SERVER +#undef MODE_CLIENT \ No newline at end of file diff --git a/code/game/machinery/embedded_controller/docking_program_multi.dm b/code/game/machinery/embedded_controller/docking_program_multi.dm new file mode 100644 index 00000000..a4ad7d29 --- /dev/null +++ b/code/game/machinery/embedded_controller/docking_program_multi.dm @@ -0,0 +1,225 @@ +/* + These programs are for docking controllers that consist of multiple independent airlocks + Each airlock has an airlock controller running the child program, and there is one docking controller running the master program +*/ + +/* + the master program +*/ +/datum/computer/file/embedded_program/docking/multi + var/list/children_tags + var/list/children_ready + var/list/children_override + +/datum/computer/file/embedded_program/docking/multi/New(var/obj/machinery/embedded_controller/M) + ..(M) + + if (istype(M,/obj/machinery/embedded_controller/radio/docking_port_multi)) //if our parent controller is the right type, then we can auto-init stuff at construction + var/obj/machinery/embedded_controller/radio/docking_port_multi/controller = M + //parse child_tags_txt and create child tags + children_tags = splittext(controller.child_tags_txt, ";") + + children_ready = list() + children_override = list() + for (var/child_tag in children_tags) + children_ready[child_tag] = 0 + children_override[child_tag] = "disabled" + +/datum/computer/file/embedded_program/docking/multi/proc/clear_children_ready_status() + for (var/child_tag in children_tags) + children_ready[child_tag] = 0 + +/datum/computer/file/embedded_program/docking/multi/receive_signal(datum/signal/signal, receive_method, receive_param) + var/receive_tag = signal.data["tag"] //for docking signals, this is the sender id + var/command = signal.data["command"] + var/recipient = signal.data["recipient"] //the intended recipient of the docking signal + + if (receive_tag in children_tags) + + //track children status + if (signal.data["override_status"]) + children_override[receive_tag] = signal.data["override_status"] + + if (recipient == id_tag) + switch (command) + if ("ready_for_docking") + children_ready[receive_tag] = 1 + if ("ready_for_undocking") + children_ready[receive_tag] = 1 + if ("status_override_enabled") + children_override[receive_tag] = 1 + if ("status_override_disabled") + children_override[receive_tag] = 0 + + ..(signal, receive_method, receive_param) + +/datum/computer/file/embedded_program/docking/multi/prepare_for_docking() + //clear children ready status + clear_children_ready_status() + + //tell children to prepare for docking + for (var/child_tag in children_tags) + send_docking_command(child_tag, "prepare_for_docking") + +/datum/computer/file/embedded_program/docking/multi/ready_for_docking() + //check children ready status + for (var/child_tag in children_tags) + if (!children_ready[child_tag]) + return 0 + return 1 + +/datum/computer/file/embedded_program/docking/multi/finish_docking() + //tell children to finish docking + for (var/child_tag in children_tags) + send_docking_command(child_tag, "finish_docking") + + //clear ready flags + clear_children_ready_status() + +/datum/computer/file/embedded_program/docking/multi/prepare_for_undocking() + //clear children ready status + clear_children_ready_status() + + //tell children to prepare for undocking + for (var/child_tag in children_tags) + send_docking_command(child_tag, "prepare_for_undocking") + +/datum/computer/file/embedded_program/docking/multi/ready_for_undocking() + //check children ready status + for (var/child_tag in children_tags) + if (!children_ready[child_tag]) + return 0 + return 1 + +/datum/computer/file/embedded_program/docking/multi/finish_undocking() + //tell children to finish undocking + for (var/child_tag in children_tags) + send_docking_command(child_tag, "finish_undocking") + + //clear ready flags + clear_children_ready_status() + + + + +/* + the child program + technically should be "slave" but eh... I'm too politically correct. +*/ +/datum/computer/file/embedded_program/airlock/multi_docking + var/master_tag + + var/master_status = "undocked" + var/override_enabled = 0 + var/docking_enabled = 0 + var/docking_mode = 0 //0 = docking, 1 = undocking + var/response_sent = 0 + +/datum/computer/file/embedded_program/airlock/multi_docking/New(var/obj/machinery/embedded_controller/M) + ..(M) + + if (istype(M, /obj/machinery/embedded_controller/radio/airlock/docking_port_multi)) //if our parent controller is the right type, then we can auto-init stuff at construction + var/obj/machinery/embedded_controller/radio/airlock/docking_port_multi/controller = M + src.master_tag = controller.master_tag + +/datum/computer/file/embedded_program/airlock/multi_docking/receive_user_command(command) + if (command == "toggle_override") + if (override_enabled) + override_enabled = 0 + broadcast_override_status() + else + override_enabled = 1 + broadcast_override_status() + return + + if (!docking_enabled|| override_enabled) //only allow the port to be used as an airlock if nothing is docked here or the override is enabled + ..(command) + +/datum/computer/file/embedded_program/airlock/multi_docking/receive_signal(datum/signal/signal, receive_method, receive_param) + ..() + + var/receive_tag = signal.data["tag"] //for docking signals, this is the sender id + var/command = signal.data["command"] + var/recipient = signal.data["recipient"] //the intended recipient of the docking signal + + if (receive_tag != master_tag) + return //only respond to master + + //track master's status + if (signal.data["dock_status"]) + master_status = signal.data["dock_status"] + + if (recipient != id_tag) + return //this signal is not for us + + switch (command) + if ("prepare_for_docking") + docking_enabled = 1 + docking_mode = 0 + response_sent = 0 + + if (!override_enabled) + begin_cycle_in() + + if ("prepare_for_undocking") + docking_mode = 1 + response_sent = 0 + + if (!override_enabled) + stop_cycling() + close_doors() + disable_mech_regulation() + + if ("finish_docking") + if (!override_enabled) + enable_mech_regulation() + open_doors() + + if ("finish_undocking") + docking_enabled = 0 + +/datum/computer/file/embedded_program/airlock/multi_docking/process() + ..() + + if (docking_enabled && !response_sent) + + switch (docking_mode) + if (0) //docking + if (ready_for_docking()) + send_signal_to_master("ready_for_docking") + response_sent = 1 + if (1) //undocking + if (ready_for_undocking()) + send_signal_to_master("ready_for_undocking") + response_sent = 1 + +//checks if we are ready for docking +/datum/computer/file/embedded_program/airlock/multi_docking/proc/ready_for_docking() + return done_cycling() + +//checks if we are ready for undocking +/datum/computer/file/embedded_program/airlock/multi_docking/proc/ready_for_undocking() + var/ext_closed = check_exterior_door_secured() + var/int_closed = check_interior_door_secured() + return (ext_closed || int_closed) + +/datum/computer/file/embedded_program/airlock/multi_docking/proc/open_doors() + toggleDoor(memory["interior_status"], tag_interior_door, memory["secure"], "open") + toggleDoor(memory["exterior_status"], tag_exterior_door, memory["secure"], "open") + +/datum/computer/file/embedded_program/airlock/multi_docking/cycleDoors(var/target) + if (!docking_enabled|| override_enabled) //only allow the port to be used as an airlock if nothing is docked here or the override is enabled + ..(target) + +/datum/computer/file/embedded_program/airlock/multi_docking/proc/send_signal_to_master(var/command) + var/datum/signal/signal = new + signal.data["tag"] = id_tag + signal.data["command"] = command + signal.data["recipient"] = master_tag + post_signal(signal) + +/datum/computer/file/embedded_program/airlock/multi_docking/proc/broadcast_override_status() + var/datum/signal/signal = new + signal.data["tag"] = id_tag + signal.data["override_status"] = override_enabled? "enabled" : "disabled" + post_signal(signal) diff --git a/code/game/machinery/embedded_controller/embedded_controller_base.dm b/code/game/machinery/embedded_controller/embedded_controller_base.dm new file mode 100644 index 00000000..3742c40b --- /dev/null +++ b/code/game/machinery/embedded_controller/embedded_controller_base.dm @@ -0,0 +1,83 @@ +/obj/machinery/embedded_controller + var/datum/computer/file/embedded_program/program //the currently executing program + + name = "Embedded Controller" + anchored = 1 + + use_power = 1 + idle_power_usage = 10 + + var/on = 1 + +obj/machinery/embedded_controller/radio/Destroy() + if(radio_controller) + radio_controller.remove_object(src,frequency) + ..() + +/obj/machinery/embedded_controller/proc/post_signal(datum/signal/signal, comm_line) + return 0 + +/obj/machinery/embedded_controller/receive_signal(datum/signal/signal, receive_method, receive_param) + if(!signal || signal.encryption) return + + if(program) + program.receive_signal(signal, receive_method, receive_param) + //spawn(5) program.process() //no, program.process sends some signals and machines respond and we here again and we lag -rastaf0 + +/obj/machinery/embedded_controller/Process() + if(program) + program.process() + + update_icon() + +/obj/machinery/embedded_controller/attack_ai(mob/user as mob) + src.ui_interact(user) + +/obj/machinery/embedded_controller/attack_hand(mob/user as mob) + + if(!user.IsAdvancedToolUser()) + return 0 + + src.ui_interact(user) + +/obj/machinery/embedded_controller/ui_interact() + return + +/obj/machinery/embedded_controller/radio + icon = 'icons/obj/airlock_machines.dmi' + icon_state = "airlock_control_standby" + power_channel = ENVIRON + density = 0 + + var/id_tag + //var/radio_power_use = 50 //power used to xmit signals + + var/frequency = 1379 + var/radio_filter = null + var/datum/radio_frequency/radio_connection + unacidable = 1 + +/obj/machinery/embedded_controller/radio/Initialize() + set_frequency(frequency) + . = ..() + +/obj/machinery/embedded_controller/radio/update_icon() + if(!on || !program) + icon_state = "airlock_control_off" + else if(program.memory["processing"]) + icon_state = "airlock_control_process" + else + icon_state = "airlock_control_standby" + +/obj/machinery/embedded_controller/radio/post_signal(datum/signal/signal, var/filter = null) + signal.transmission_method = TRANSMISSION_RADIO + if(radio_connection) + //use_power(radio_power_use) //neat idea, but causes way too much lag. + return radio_connection.post_signal(src, signal, filter) + else + qdel(signal) + +/obj/machinery/embedded_controller/radio/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, radio_filter) \ No newline at end of file diff --git a/code/game/machinery/embedded_controller/embedded_program_base.dm b/code/game/machinery/embedded_controller/embedded_program_base.dm new file mode 100644 index 00000000..91d3bd12 --- /dev/null +++ b/code/game/machinery/embedded_controller/embedded_program_base.dm @@ -0,0 +1,30 @@ + +/datum/computer/file/embedded_program + var/list/memory = list() + var/obj/machinery/embedded_controller/master + + var/id_tag + +/datum/computer/file/embedded_program/New(var/obj/machinery/embedded_controller/M) + master = M + if (istype(M, /obj/machinery/embedded_controller/radio)) + var/obj/machinery/embedded_controller/radio/R = M + var/datum/computer/file/embedded_program/P = locate(R.id_tag) + if(istype(P)) + error("Duplicate program: '[R.id_tag]'") + id_tag = R.id_tag + +/datum/computer/file/embedded_program/proc/receive_user_command(command) + return + +/datum/computer/file/embedded_program/proc/receive_signal(datum/signal/signal, receive_method, receive_param) + return + +/datum/computer/file/embedded_program/proc/process() + return + +/datum/computer/file/embedded_program/proc/post_signal(datum/signal/signal, comm_line) + if(master) + master.post_signal(signal, comm_line) + else + qdel(signal) diff --git a/code/game/machinery/embedded_controller/simple_docking_controller.dm b/code/game/machinery/embedded_controller/simple_docking_controller.dm new file mode 100644 index 00000000..b4e85f5f --- /dev/null +++ b/code/game/machinery/embedded_controller/simple_docking_controller.dm @@ -0,0 +1,164 @@ +//a docking port that uses a single door +/obj/machinery/embedded_controller/radio/simple_docking_controller + name = "docking hatch controller" + var/tag_door + var/datum/computer/file/embedded_program/docking/simple/docking_program + var/progtype = /datum/computer/file/embedded_program/docking/simple/ + +/obj/machinery/embedded_controller/radio/simple_docking_controller/New() + ..() + docking_program = new progtype(src) + program = docking_program + +/obj/machinery/embedded_controller/radio/simple_docking_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nano_ui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) + var/data[0] + + data = list( + "docking_status" = docking_program.get_docking_status(), + "override_enabled" = docking_program.override_enabled, + "door_state" = docking_program.memory["door_status"]["state"], + "door_lock" = docking_program.memory["door_status"]["lock"], + ) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + + if (!ui) + ui = new(user, src, ui_key, "simple_docking_console.tmpl", name, 470, 290, state = state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/embedded_controller/radio/simple_docking_controller/Topic(href, href_list) + if(..()) + return 1 + + usr.set_machine(src) + + var/clean = 0 + switch(href_list["command"]) //anti-HTML-hacking checks + if("force_door") + clean = 1 + if("toggle_override") + clean = 1 + + if(clean) + program.receive_user_command(href_list["command"]) + + return 0 + + +//A docking controller program for a simple door based docking port +/datum/computer/file/embedded_program/docking/simple + var/tag_door + +/datum/computer/file/embedded_program/docking/simple/New(var/obj/machinery/embedded_controller/M) + ..(M) + memory["door_status"] = list(state = "closed", lock = "locked") //assume closed and locked in case the doors dont report in + + if (istype(M, /obj/machinery/embedded_controller/radio/simple_docking_controller)) + var/obj/machinery/embedded_controller/radio/simple_docking_controller/controller = M + + tag_door = controller.tag_door? controller.tag_door : "[id_tag]_hatch" + + spawn(10) + signal_door("update") //signals connected doors to update their status + + +/datum/computer/file/embedded_program/docking/simple/receive_signal(datum/signal/signal, receive_method, receive_param) + var/receive_tag = signal.data["tag"] + + if(!receive_tag) return + + if(receive_tag==tag_door) + memory["door_status"]["state"] = signal.data["door_status"] + memory["door_status"]["lock"] = signal.data["lock_status"] + + ..(signal, receive_method, receive_param) + +/datum/computer/file/embedded_program/docking/simple/receive_user_command(command) + switch(command) + if("force_door") + if (override_enabled) + if(memory["door_status"]["state"] == "open") + close_door() + else + open_door() + if("toggle_override") + if (override_enabled) + disable_override() + else + enable_override() + + +/datum/computer/file/embedded_program/docking/simple/proc/signal_door(var/command) + var/datum/signal/signal = new + signal.data["tag"] = tag_door + signal.data["command"] = command + post_signal(signal) + +///datum/computer/file/embedded_program/docking/simple/proc/signal_mech_sensor(var/command) +// signal_door(command) +// return + +/datum/computer/file/embedded_program/docking/simple/proc/open_door() + if(memory["door_status"]["state"] == "closed") + //signal_mech_sensor("enable") + signal_door("secure_open") + else if(memory["door_status"]["lock"] == "unlocked") + signal_door("lock") + +/datum/computer/file/embedded_program/docking/simple/proc/close_door() + if(memory["door_status"]["state"] == "open") + signal_door("secure_close") + //signal_mech_sensor("disable") + else if(memory["door_status"]["lock"] == "unlocked") + signal_door("lock") + +//tell the docking port to start getting ready for docking - e.g. pressurize +/datum/computer/file/embedded_program/docking/simple/prepare_for_docking() + return //don't need to do anything + +//are we ready for docking? +/datum/computer/file/embedded_program/docking/simple/ready_for_docking() + return 1 //don't need to do anything + +//we are docked, open the doors or whatever. +/datum/computer/file/embedded_program/docking/simple/finish_docking() + open_door() + +//tell the docking port to start getting ready for undocking - e.g. close those doors. +/datum/computer/file/embedded_program/docking/simple/prepare_for_undocking() + close_door() + +//are we ready for undocking? +/datum/computer/file/embedded_program/docking/simple/ready_for_undocking() + return (memory["door_status"]["state"] == "closed" && memory["door_status"]["lock"] == "locked") + +/*** DEBUG VERBS *** + +/obj/machinery/embedded_controller/radio/simple_docking_controller/verb/view_state() + set category = "Debug" + set src in view(1) + src.program:print_state() + +/obj/machinery/embedded_controller/radio/simple_docking_controller/verb/spoof_signal(var/command as text, var/sender as text) + set category = "Debug" + set src in view(1) + var/datum/signal/signal = new + signal.data["tag"] = sender + signal.data["command"] = command + signal.data["recipient"] = id_tag + + src.program:receive_signal(signal) + +/obj/machinery/embedded_controller/radio/simple_docking_controller/verb/debug_init_dock(var/target as text) + set category = "Debug" + set src in view(1) + src.program:initiate_docking(target) + +/obj/machinery/embedded_controller/radio/simple_docking_controller/verb/debug_init_undock() + set category = "Debug" + set src in view(1) + src.program:initiate_undocking() + +*/ \ No newline at end of file diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm new file mode 100644 index 00000000..c6202bdc --- /dev/null +++ b/code/game/machinery/flasher.dm @@ -0,0 +1,156 @@ +// It is a gizmo that flashes a small area + +/obj/machinery/flasher + name = "Mounted flash" + desc = "A wall-mounted flashbulb device." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "mflash1" + var/id = null + var/range = 2 //this is roughly the size of brig cell + var/disable = 0 + var/last_flash = 0 //Don't want it getting spammed like regular flashes + var/strength = 10 //How weakened targets are when flashed. + var/base_state = "mflash" + anchored = 1 + use_power = 1 + idle_power_usage = 2 + movable_flags = MOVABLE_FLAG_PROXMOVE + var/_wifi_id + var/datum/wifi/receiver/button/flasher/wifi_receiver + +/obj/machinery/flasher/portable //Portable version of the flasher. Only flashes when anchored + name = "portable flasher" + desc = "A portable flashing device. Wrench to activate and deactivate. Cannot detect slow movements." + icon_state = "pflash1" + strength = 8 + anchored = 0 + base_state = "pflash" + density = 1 + +/obj/machinery/flasher/Initialize() + . = ..() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + +/obj/machinery/flasher/Destroy() + qdel(wifi_receiver) + wifi_receiver = null + return ..() + +/obj/machinery/flasher/update_icon() + if ( !(stat & (BROKEN|NOPOWER)) ) + icon_state = "[base_state]1" +// src.sd_SetLuminosity(2) + else + icon_state = "[base_state]1-p" +// src.sd_SetLuminosity(0) + +//Don't want to render prison breaks impossible +/obj/machinery/flasher/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWirecutter(W)) + add_fingerprint(user, 0, W) + src.disable = !src.disable + if (src.disable) + user.visible_message("[user] has disconnected the [src]'s flashbulb!", "You disconnect the [src]'s flashbulb!") + if (!src.disable) + user.visible_message("[user] has connected the [src]'s flashbulb!", "You connect the [src]'s flashbulb!") + else + ..() + +//Let the AI trigger them directly. +/obj/machinery/flasher/attack_ai() + if (src.anchored) + return src.flash() + else + return + +/obj/machinery/flasher/proc/flash() + if (!(powered())) + return + + if ((src.disable) || (src.last_flash && world.time < src.last_flash + 150)) + return + + playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1) + flick("[base_state]_flash", src) + src.last_flash = world.time + use_power(1500) + + for (var/mob/living/O in viewers(src, null)) + if (get_dist(src, O) > src.range) + continue + + var/flash_time = strength + if (istype(O, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = O + if(!H.eyecheck() <= 0) + continue + flash_time = round(H.species.flash_mod * flash_time) + var/obj/item/organ/internal/eyes/E = H.internal_organs_by_name[BP_EYES] + if(!E) + return + if(E.is_bruised() && prob(E.damage + 50)) + H.flash_eyes() + E.damage += rand(1, 5) + if(!O.blinded) + O.flash_eyes() + O.eye_blurry += flash_time + O.confused += (flash_time + 2) + O.Stun(flash_time / 2) + O.Weaken(3) + +/obj/machinery/flasher/emp_act(severity) + if(stat & (BROKEN|NOPOWER)) + ..(severity) + return + if(prob(75/severity)) + flash() + ..(severity) + +/obj/machinery/flasher/portable/HasProximity(atom/movable/AM as mob|obj) + if ((src.disable) || (src.last_flash && world.time < src.last_flash + 150)) + return + + if(istype(AM, /mob/living/carbon)) + var/mob/living/carbon/M = AM + if ((M.m_intent != "walk") && (src.anchored)) + src.flash() + +/obj/machinery/flasher/portable/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWrench(W)) + add_fingerprint(user) + src.anchored = !src.anchored + + if (!src.anchored) + user.show_message(text("[src] can now be moved.")) + src.overlays.Cut() + + else if (src.anchored) + user.show_message(text("[src] is now secured.")) + src.overlays += "[base_state]-s" + +/obj/machinery/button/flasher + name = "flasher button" + desc = "A remote control switch for a mounted flasher." + +/obj/machinery/button/flasher/attack_hand(mob/user as mob) + + if(..()) + return + + use_power(5) + + active = 1 + icon_state = "launcheract" + + for(var/obj/machinery/flasher/M in SSmachines.machinery) + if(M.id == src.id) + spawn() + M.flash() + + sleep(50) + + icon_state = "launcherbtt" + active = 0 + + return diff --git a/code/game/machinery/floodlight.dm b/code/game/machinery/floodlight.dm new file mode 100644 index 00000000..6ed71150 --- /dev/null +++ b/code/game/machinery/floodlight.dm @@ -0,0 +1,133 @@ +//these are probably broken + +/obj/machinery/floodlight + name = "Emergency Floodlight" + icon = 'icons/obj/machines/floodlight.dmi' + icon_state = "flood00" + density = 1 + var/on = 0 + var/obj/item/weapon/cell/cell = null + var/use = 200 // 200W light + var/unlocked = 0 + var/open = 0 + var/brightness_on = 8 //can't remember what the maxed out value is + +/obj/machinery/floodlight/New() + cell = new/obj/item/weapon/cell/crap(src) + ..() + +/obj/machinery/floodlight/update_icon() + overlays.Cut() + icon_state = "flood[open ? "o" : ""][open && cell ? "b" : ""]0[on]" + +/obj/machinery/floodlight/Process() + if(!on) + return + + if(!cell || (cell.charge < (use * CELLRATE))) + turn_off(1) + return + + // If the cell is almost empty rarely "flicker" the light. Aesthetic only. + if((cell.percent() < 10) && prob(5)) + set_light(brightness_on/2, brightness_on/4) + spawn(20) + if(on) + set_light(brightness_on, brightness_on/2) + + cell.use(use*CELLRATE) + + +// Returns 0 on failure and 1 on success +/obj/machinery/floodlight/proc/turn_on(var/loud = 0) + if(!cell) + return 0 + if(cell.charge < (use * CELLRATE)) + return 0 + + on = 1 + set_light(brightness_on, brightness_on / 2) + update_icon() + if(loud) + playsound(src, 'sound/machines/click.ogg', 50) + visible_message("\The [src] turns on.") + return 1 + +/obj/machinery/floodlight/proc/turn_off(var/loud = 0) + on = 0 + set_light(0, 0) + update_icon() + if(loud) + playsound(src, 'sound/machines/click.ogg', 50) + visible_message("\The [src] shuts down.") + +/obj/machinery/floodlight/attack_ai(mob/user as mob) + if(istype(user, /mob/living/silicon/robot) && Adjacent(user)) + return attack_hand(user) + + if(on) + turn_off(1) + else + if(!turn_on(1)) + to_chat(user, "You try to turn on \the [src] but it does not work.") + + +/obj/machinery/floodlight/attack_hand(mob/user as mob) + if(open && cell) + if(ishuman(user)) + if(!user.get_active_hand()) + user.put_in_hands(cell) + cell.loc = user.loc + else + cell.loc = loc + + cell.add_fingerprint(user) + cell.update_icon() + + src.cell = null + on = 0 + set_light(0) + to_chat(user, "You remove the power cell") + update_icon() + return + + if(on) + turn_off(1) + else + if(!turn_on(1)) + to_chat(user, "You try to turn on \the [src] but it does not work.") + + update_icon() + + +/obj/machinery/floodlight/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isScrewdriver(W)) + if (!open) + if(unlocked) + unlocked = 0 + to_chat(user, "You screw the battery panel in place.") + else + unlocked = 1 + to_chat(user, "You unscrew the battery panel.") + + if(isCrowbar(W)) + if(unlocked) + if(open) + open = 0 + overlays = null + to_chat(user, "You crowbar the battery panel in place.") + else + if(unlocked) + open = 1 + to_chat(user, "You remove the battery panel.") + + if (istype(W, /obj/item/weapon/cell)) + if(open) + if(cell) + to_chat(user, "There is a power cell already installed.") + else + user.drop_item() + W.loc = src + cell = W + to_chat(user, "You insert the power cell.") + update_icon() diff --git a/code/game/machinery/floor_light.dm b/code/game/machinery/floor_light.dm new file mode 100644 index 00000000..16f38786 --- /dev/null +++ b/code/game/machinery/floor_light.dm @@ -0,0 +1,156 @@ +var/list/floor_light_cache = list() + +/obj/machinery/floor_light + name = "floor light" + icon = 'icons/obj/machines/floor_light.dmi' + icon_state = "base" + desc = "A backlit floor panel." + plane = ABOVE_TURF_PLANE + layer = ABOVE_TILE_LAYER + anchored = 0 + use_power = 2 + idle_power_usage = 2 + active_power_usage = 20 + power_channel = LIGHT + matter = list(DEFAULT_WALL_MATERIAL = 250, "glass" = 250) + + var/on + var/damaged + var/default_light_range = 4 + var/default_light_power = 2 + var/default_light_colour = "#ffffff" + +/obj/machinery/floor_light/prebuilt + anchored = 1 + +/obj/machinery/floor_light/attackby(var/obj/item/W, var/mob/user) + if(isScrewdriver(W)) + anchored = !anchored + visible_message("\The [user] has [anchored ? "attached" : "detached"] \the [src].") + else if(isWelder(W) && (damaged || (stat & BROKEN))) + var/obj/item/weapon/weldingtool/WT = W + if(!WT.remove_fuel(0, user)) + to_chat(user, "\The [src] must be on to complete this task.") + return + playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) + if(!do_after(user, 20, src)) + return + if(!src || !WT.isOn()) + return + visible_message("\The [user] has repaired \the [src].") + stat &= ~BROKEN + damaged = null + update_brightness() + else if(W.force && user.a_intent == "hurt") + attack_hand(user) + return + +/obj/machinery/floor_light/attack_hand(var/mob/user) + + if(user.a_intent == I_HURT && !issmall(user)) + if(!isnull(damaged) && !(stat & BROKEN)) + visible_message("\The [user] smashes \the [src]!") + playsound(src, "shatter", 70, 1) + stat |= BROKEN + else + visible_message("\The [user] attacks \the [src]!") + playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) + if(isnull(damaged)) damaged = 0 + update_brightness() + return + else + + if(!anchored) + to_chat(user, "\The [src] must be screwed down first.") + return + + if(stat & BROKEN) + to_chat(user, "\The [src] is too damaged to be functional.") + return + + if(stat & NOPOWER) + to_chat(user, "\The [src] is unpowered.") + return + + on = !on + if(on) use_power = 2 + visible_message("\The [user] turns \the [src] [on ? "on" : "off"].") + update_brightness() + return + +/obj/machinery/floor_light/Process() + ..() + var/need_update + if((!anchored || broken()) && on) + use_power = 0 + on = 0 + need_update = 1 + else if(use_power && !on) + use_power = 0 + need_update = 1 + if(need_update) + update_brightness() + +/obj/machinery/floor_light/proc/update_brightness() + if(on && use_power == 2) + if(light_range != default_light_range || light_power != default_light_power || light_color != default_light_colour) + set_light(default_light_range, default_light_power, default_light_colour) + else + use_power = 0 + if(light_range || light_power) + set_light(0) + + active_power_usage = ((light_range + light_power) * 10) + update_icon() + +/obj/machinery/floor_light/update_icon() + overlays.Cut() + if(use_power && !broken()) + if(isnull(damaged)) + var/cache_key = "floorlight-[default_light_colour]" + if(!floor_light_cache[cache_key]) + var/image/I = image("on") + I.color = default_light_colour + I.plane = plane + I.layer = layer+0.001 + floor_light_cache[cache_key] = I + overlays |= floor_light_cache[cache_key] + else + if(damaged == 0) //Needs init. + damaged = rand(1,4) + var/cache_key = "floorlight-broken[damaged]-[default_light_colour]" + if(!floor_light_cache[cache_key]) + var/image/I = image("flicker[damaged]") + I.color = default_light_colour + I.plane = plane + I.layer = layer+0.001 + floor_light_cache[cache_key] = I + overlays |= floor_light_cache[cache_key] + +/obj/machinery/floor_light/proc/broken() + return (stat & (BROKEN|NOPOWER)) + +/obj/machinery/floor_light/ex_act(severity) + switch(severity) + if(1) + qdel(src) + if(2) + if (prob(50)) + qdel(src) + else if(prob(20)) + stat |= BROKEN + else + if(isnull(damaged)) + damaged = 0 + if(3) + if (prob(5)) + qdel(src) + else if(isnull(damaged)) + damaged = 0 + return + +/obj/machinery/floor_light/Destroy() + var/area/A = get_area(src) + if(A) + on = 0 + . = ..() diff --git a/code/game/machinery/floorlayer.dm b/code/game/machinery/floorlayer.dm new file mode 100644 index 00000000..001c9319 --- /dev/null +++ b/code/game/machinery/floorlayer.dm @@ -0,0 +1,112 @@ +/obj/machinery/floorlayer + + name = "automatic floor layer" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "pipe_d" + density = 1 + var/turf/old_turf + var/on = 0 + var/obj/item/stack/tile/T + var/list/mode = list("dismantle"=0,"laying"=0,"collect"=0) + +/obj/machinery/floorlayer/New() + T = new/obj/item/stack/tile/floor(src) + ..() + +/obj/machinery/floorlayer/Move(new_turf,M_Dir) + ..() + + if(on) + if(mode["dismantle"]) + dismantleFloor(old_turf) + + if(mode["laying"]) + layFloor(old_turf) + + if(mode["collect"]) + CollectTiles(old_turf) + + + old_turf = new_turf + +/obj/machinery/floorlayer/attack_hand(mob/user as mob) + on=!on + user.visible_message("[user] has [!on?"de":""]activated \the [src].", "You [!on?"de":""]activate \the [src].") + return + +/obj/machinery/floorlayer/attackby(var/obj/item/W as obj, var/mob/user as mob) + + if(isWrench(W)) + var/m = input("Choose work mode", "Mode") as null|anything in mode + mode[m] = !mode[m] + var/O = mode[m] + user.visible_message("[usr] has set \the [src] [m] mode [!O?"off":"on"].", "You set \the [src] [m] mode [!O?"off":"on"].") + return + + if(istype(W, /obj/item/stack/tile)) + to_chat(user, "\The [W] successfully loaded.") + user.drop_item(T) + TakeTile(T) + return + + if(isCrowbar(W)) + if(!length(contents)) + to_chat(user, "\The [src] is empty.") + else + var/obj/item/stack/tile/E = input("Choose remove tile type.", "Tiles") as null|anything in contents + if(E) + to_chat(user, "You remove the [E] from /the [src].") + E.loc = src.loc + T = null + return + + if(isScrewdriver(W)) + T = input("Choose tile type.", "Tiles") as null|anything in contents + return + ..() + +/obj/machinery/floorlayer/examine(mob/user) + . = ..() + var/dismantle = mode["dismantle"] + var/laying = mode["laying"] + var/collect = mode["collect"] + var/message = "\The [src] [!T?"don't ":""]has [!T?"":"[T.get_amount()] [T] "]tile\s, dismantle is [dismantle?"on":"off"], laying is [laying?"on":"off"], collect is [collect?"on":"off"]." + to_chat(user, message) +/obj/machinery/floorlayer/proc/reset() + on=0 + return + +/obj/machinery/floorlayer/proc/dismantleFloor(var/turf/new_turf) + if(istype(new_turf, /turf/simulated/floor)) + var/turf/simulated/floor/T = new_turf + if(!T.is_plating()) + T.make_plating(!(T.broken || T.burnt)) + return new_turf.is_plating() + +/obj/machinery/floorlayer/proc/TakeNewStack() + for(var/obj/item/stack/tile/tile in contents) + T = tile + return 1 + return 0 + +/obj/machinery/floorlayer/proc/SortStacks() + for(var/obj/item/stack/tile/tile1 in contents) + for(var/obj/item/stack/tile/tile2 in contents) + tile2.transfer_to(tile1) + +/obj/machinery/floorlayer/proc/layFloor(var/turf/w_turf) + if(!T) + if(!TakeNewStack()) + return 0 + w_turf.attackby(T , src) + return 1 + +/obj/machinery/floorlayer/proc/TakeTile(var/obj/item/stack/tile/tile) + if(!T) T = tile + tile.loc = src + + SortStacks() + +/obj/machinery/floorlayer/proc/CollectTiles(var/turf/w_turf) + for(var/obj/item/stack/tile/tile in w_turf) + TakeTile(tile) diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm new file mode 100644 index 00000000..a1f46d47 --- /dev/null +++ b/code/game/machinery/hologram.dm @@ -0,0 +1,414 @@ +/* Holograms! + * Contains: + * Holopad + * Hologram + * Other stuff + */ + +/* +Revised. Original based on space ninja hologram code. Which is also mine. /N +How it works: +AI clicks on holopad in camera view. View centers on holopad. +AI clicks again on the holopad to display a hologram. Hologram stays as long as AI is looking at the pad and it (the hologram) is in range of the pad. +AI can use the directional keys to move the hologram around, provided the above conditions are met and the AI in question is the holopad's master. +Only one AI may project from a holopad at any given time. +AI may cancel the hologram at any time by clicking on the holopad once more. + +Possible to do for anyone motivated enough: + Give an AI variable for different hologram icons. + Itegrate EMP effect to disable the unit. +*/ + + +/* + * Holopad + */ + +#define HOLOPAD_PASSIVE_POWER_USAGE 1 +#define HOLOGRAM_POWER_USAGE 2 +#define RANGE_BASED 4 +#define AREA_BASED 6 + +var/const/HOLOPAD_MODE = RANGE_BASED + +/obj/machinery/hologram/holopad + name = "\improper AI holopad" + desc = "It's a floor-mounted device for projecting holographic images." + icon_state = "holopad-B0" + + plane = ABOVE_TURF_PLANE + layer = ABOVE_TILE_LAYER + + var/power_per_hologram = 500 //per usage per hologram + idle_power_usage = 5 + use_power = 1 + + var/list/mob/living/silicon/ai/masters = new() //List of AIs that use the holopad + var/last_request = 0 //to prevent request spam. ~Carn + var/holo_range = 5 // Change to change how far the AI can move away from the holopad before deactivating. + + var/incoming_connection = 0 + var/mob/living/caller_id + var/obj/machinery/hologram/holopad/sourcepad + var/obj/machinery/hologram/holopad/targetpad + var/last_message + + var/map_range = -1 //how far on overmap can it connect, -1 for local zlevels only + + var/holopadType = HOLOPAD_SHORT_RANGE //Whether the holopad is short-range or long-range. + var/base_icon = "holopad-B" + +/obj/machinery/hologram/holopad/New() + ..() + desc = "It's a floor-mounted device for projecting holographic images. Its ID is '[loc.loc]'" + +/obj/machinery/hologram/holopad/attack_hand(var/mob/living/carbon/human/user) //Carn: Hologram requests. + if(!istype(user)) + return + if(incoming_connection&&caller_id) + visible_message("The pad hums quietly as it establishes a connection.") + if(caller_id.loc!=sourcepad.loc) + visible_message("The pad flashes an error message. The caller has left their holopad.") + return + take_call(user) + return + else if(caller_id && !incoming_connection) + audible_message("Severing connection to distant holopad.") + end_call(user) + return + switch(alert(user,"Would you like to request an AI's presence or establish communications with another pad?", "Holopad","AI","Holocomms","Cancel")) + if("AI") + if(last_request + 200 < world.time) //don't spam the AI with requests you jerk! + last_request = world.time + to_chat(user, "You request an AI's presence.") + var/area/area = get_area(src) + for(var/mob/living/silicon/ai/AI in GLOB.living_mob_list_) + if(!AI.client) continue + to_chat(AI, "Your presence is requested at \the [area].") + else + to_chat(user, "A request for AI presence was already sent recently.") + if("Holocomms") + if(user.loc != src.loc) + to_chat(user, "Please step onto the holopad.") + return + if(last_request + 200 < world.time) //don't spam other people with requests either, you jerk! + last_request = world.time + var/list/holopadlist = list() + var/zlevels = GetConnectedZlevels(z) + if(GLOB.using_map.use_overmap && map_range >= 0) + var/obj/effect/overmap/O = map_sectors["[z]"] + for(var/obj/effect/overmap/OO in range(O,map_range)) + zlevels |= OO.map_z + for(var/obj/machinery/hologram/holopad/H in SSmachines.machinery) + if((H.z in zlevels) && H.operable()) + holopadlist["[H.loc.loc.name]"] = H //Define a list and fill it with the area of every holopad in the world + holopadlist = sortAssoc(holopadlist) + var/temppad = input(user, "Which holopad would you like to contact?", "holopad list") as null|anything in holopadlist + targetpad = holopadlist["[temppad]"] + if(targetpad==src) + to_chat(user, "Using such sophisticated technology, just to talk to yourself seems a bit silly.") + return + if(targetpad && targetpad.caller_id) + to_chat(user, "The pad flashes a busy sign. Maybe you should try again later..") + return + if(targetpad) + make_call(targetpad, user) + else + to_chat(user, "A request for holographic communication was already sent recently.") + + +/obj/machinery/hologram/holopad/proc/make_call(var/obj/machinery/hologram/holopad/targetpad, var/mob/living/carbon/user) + targetpad.last_request = world.time + targetpad.sourcepad = src //This marks the holopad you are making the call from + targetpad.caller_id = user //This marks you as the caller + targetpad.incoming_connection = 1 + playsound(targetpad.loc, 'sound/machines/chime.ogg', 25, 5) + targetpad.icon_state = "[targetpad.base_icon]1" + targetpad.audible_message("\The [src] announces, \"Incoming communications request from [targetpad.sourcepad.loc.loc].\"") + to_chat(user, "Trying to establish a connection to the holopad in [targetpad.loc.loc]... Please await confirmation from recipient.") + + +/obj/machinery/hologram/holopad/proc/take_call(mob/living/carbon/user) + incoming_connection = 0 + caller_id.machine = sourcepad + caller_id.reset_view(src) + if(!masters[caller_id])//If there is no hologram, possibly make one. + activate_holocall(caller_id) + log_admin("[key_name(caller_id)] just established a holopad connection from [sourcepad.loc.loc] to [src.loc.loc]") + +/obj/machinery/hologram/holopad/proc/end_call(mob/user) + caller_id.unset_machine() + caller_id.reset_view() //Send the caller back to his body + clear_holo(0, caller_id) // destroy the hologram + caller_id = null + +/obj/machinery/hologram/holopad/check_eye(mob/user) + return 0 + +/obj/machinery/hologram/holopad/attack_ai(mob/living/silicon/ai/user) + if (!istype(user)) + return + /*There are pretty much only three ways to interact here. + I don't need to check for client since they're clicking on an object. + This may change in the future but for now will suffice.*/ + if(user.eyeobj && (user.eyeobj.loc != src.loc))//Set client eye on the object if it's not already. + user.eyeobj.setLoc(get_turf(src)) + else if(!masters[user])//If there is no hologram, possibly make one. + activate_holo(user) + else//If there is a hologram, remove it. + clear_holo(user) + return + +/obj/machinery/hologram/holopad/proc/activate_holo(mob/living/silicon/ai/user) + if(!(stat & NOPOWER) && user.eyeobj && user.eyeobj.loc == src.loc)//If the projector has power and client eye is on it + if (user.holo) + to_chat(user, "ERROR: Image feed in progress.") + return + src.visible_message("A holographic image of [user] flicks to life right before your eyes!") + create_holo(user)//Create one. + else + to_chat(user, "ERROR: Unable to project hologram.") + return + +/obj/machinery/hologram/holopad/proc/activate_holocall(mob/living/carbon/caller_id) + if(caller_id) + src.visible_message("A holographic image of [caller_id] flicks to life right before your eyes!") + create_holo(0,caller_id)//Create one. + else + to_chat(caller_id, "ERROR: Unable to project hologram.") + return + +/*This is the proc for special two-way communication between AI and holopad/people talking near holopad. +For the other part of the code, check silicon say.dm. Particularly robot talk.*/ +/obj/machinery/hologram/holopad/hear_talk(mob/living/M, text, verb, datum/language/speaking) + if(M) + for(var/mob/living/silicon/ai/master in masters) + if(!master.say_understands(M, speaking))//The AI will be able to understand most mobs talking through the holopad. + if(speaking) + text = speaking.scramble(text) + else + text = stars(text) + var/name_used = M.GetVoice() + //This communication is imperfect because the holopad "filters" voices and is only designed to connect to the master only. + var/rendered + if(speaking) + rendered = "Holopad received, [name_used] [speaking.format_message(text, verb)]" + else + rendered = "Holopad received, [name_used] [verb], \"[text]\"" + master.show_message(rendered, 2) + var/name_used = M.GetVoice() + if(targetpad) //If this is the pad you're making the call from + var/message = "Holopad received, [name_used] [speaking.format_message(text, verb)]" + targetpad.audible_message(message) + targetpad.last_message = message + if(sourcepad) //If this is a pad receiving a call + if(name_used==caller_id||text==last_message||findtext(text, "Holopad received")) //prevent echoes + return + sourcepad.audible_message("Holopad received, [name_used] [speaking.format_message(text, verb)]") + +/obj/machinery/hologram/holopad/see_emote(mob/living/M, text) + if(M) + for(var/mob/living/silicon/ai/master in masters) + //var/name_used = M.GetVoice() + var/rendered = "Holopad received, [text]" + //The lack of name_used is needed, because message already contains a name. This is needed for simple mobs to emote properly. + master.show_message(rendered, 2) + for(var/mob/living/carbon/master in masters) + //var/name_used = M.GetVoice() + var/rendered = "Holopad received, [text]" + //The lack of name_used is needed, because message already contains a name. This is needed for simple mobs to emote properly. + master.show_message(rendered, 2) + if(targetpad) + targetpad.visible_message("[text]") + +/obj/machinery/hologram/holopad/show_message(msg, type, alt, alt_type) + for(var/mob/living/silicon/ai/master in masters) + var/rendered = "The holographic image of [msg]" + master.show_message(rendered, type) + if(findtext(msg, "Holopad received,")) + return + for(var/mob/living/carbon/master in masters) + var/rendered = "The holographic image of [msg]" + master.show_message(rendered, type) + if(targetpad) + for(var/mob/living/carbon/master in view(targetpad)) + var/rendered = "The holographic image of [msg]" + master.show_message(rendered, type) + +/obj/machinery/hologram/holopad/proc/create_holo(mob/living/silicon/ai/A, mob/living/carbon/caller_id, turf/T = loc) + var/obj/effect/overlay/hologram = new(T)//Spawn a blank effect at the location. + if(caller_id) + var/tempicon = 0 + var/datum/computer_file/crew_record/R = get_crewmember_record(caller_id.name) + if(R) + tempicon = R.photo_front + hologram.overlays += getHologramIcon(icon(tempicon), hologram_color = holopadType) // Add the callers image as an overlay to keep coloration! + else + if(holopadType == HOLOPAD_LONG_RANGE) + hologram.overlays += A.holo_icon_longrange + else + hologram.overlays += A.holo_icon // Add the AI's configured holo Icon + if(A) + if(A.holo_icon_malf == TRUE) + hologram.overlays += icon("icons/effects/effects.dmi", "malf-scanline") + hologram.mouse_opacity = 0//So you can't click on it. + hologram.plane = ABOVE_HUMAN_PLANE + hologram.layer = ABOVE_HUMAN_LAYER //Above all the other objects/mobs. Or the vast majority of them. + hologram.anchored = 1//So space wind cannot drag it. + if(caller_id) + hologram.SetName("[caller_id.name] (Hologram)") + hologram.loc = get_step(src,1) + masters[caller_id] = hologram + else + hologram.SetName("[A.name] (Hologram)") //If someone decides to right click. + A.holo = src + masters[A] = hologram + hologram.set_light(2) //hologram lighting + hologram.color = color //painted holopad gives coloured holograms + set_light(2) //pad lighting + icon_state = "[base_icon]1" + return 1 + +/obj/machinery/hologram/holopad/proc/clear_holo(mob/living/silicon/ai/user, mob/living/carbon/caller_id) + if(user) + qdel(masters[user])//Get rid of user's hologram + user.holo = null + masters -= user //Discard AI from the list of those who use holopad + if(caller_id) + qdel(masters[caller_id])//Get rid of user's hologram + masters -= caller_id //Discard the caller from the list of those who use holopad + if (!masters.len)//If no users left + set_light(0) //pad lighting (hologram lighting will be handled automatically since its owner was deleted) + icon_state = "[base_icon]0" + if(sourcepad) + sourcepad.targetpad = null + sourcepad = null + caller_id = null + return 1 + + +/obj/machinery/hologram/holopad/Process() + for (var/mob/living/silicon/ai/master in masters) + var/active_ai = (master && !master.incapacitated() && master.client && master.eyeobj)//If there is an AI with an eye attached, it's not incapacitated, and it has a client + if((stat & NOPOWER) || !active_ai) + clear_holo(master) + continue + + if(!(masters[master] in view(src))) + clear_holo(master) + continue + + use_power(power_per_hologram) + if(last_request + 200 < world.time&&incoming_connection==1) + if(sourcepad) + sourcepad.audible_message("The holopad connection timed out") + incoming_connection = 0 + end_call() + if (caller_id&&sourcepad) + if(caller_id.loc!=sourcepad.loc) + to_chat(caller_id, "Severing connection to distant holopad.") + end_call() + audible_message("The connection has been terminated by the caller.") + return 1 + +/obj/machinery/hologram/holopad/proc/move_hologram(mob/living/silicon/ai/user) + if(masters[user]) + step_to(masters[user], user.eyeobj) // So it turns. + var/obj/effect/overlay/H = masters[user] + H.forceMove(get_turf(user.eyeobj)) + masters[user] = H + + if(!(H in view(src))) + clear_holo(user) + return 0 + + if((HOLOPAD_MODE == RANGE_BASED && (get_dist(user.eyeobj, src) > holo_range))) + clear_holo(user) + + if(HOLOPAD_MODE == AREA_BASED) + var/area/holo_area = get_area(src) + var/area/hologram_area = get_area(H) + if(hologram_area != holo_area) + clear_holo(user) + return 1 + + +/obj/machinery/hologram/holopad/proc/set_dir_hologram(new_dir, mob/living/silicon/ai/user) + if(masters[user]) + var/obj/effect/overlay/hologram = masters[user] + hologram.dir = new_dir + + + +/* + * Hologram + */ + +/obj/machinery/hologram + anchored = 1 + use_power = 1 + idle_power_usage = 5 + active_power_usage = 100 + +//Destruction procs. +/obj/machinery/hologram/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/machinery/hologram/holopad/Destroy() + for (var/mob/living/master in masters) + clear_holo(master) + return ..() + +/* +Holographic project of everything else. + +/mob/verb/hologram_test() + set name = "Hologram Debug New" + set category = "CURRENT DEBUG" + + var/obj/effect/overlay/hologram = new(loc)//Spawn a blank effect at the location. + var/icon/flat_icon = icon(getFlatIcon(src,0))//Need to make sure it's a new icon so the old one is not reused. + flat_icon.ColorTone(rgb(125,180,225))//Let's make it bluish. + flat_icon.ChangeOpacity(0.5)//Make it half transparent. + var/input = input("Select what icon state to use in effect.",,"") + if(input) + var/icon/alpha_mask = new('icons/effects/effects.dmi', "[input]") + flat_icon.AddAlphaMask(alpha_mask)//Finally, let's mix in a distortion effect. + hologram.icon = flat_icon + + log_debug("Your icon should appear now.") + + return +*/ + +/* + * Other Stuff: Is this even used? + */ +/obj/machinery/hologram/projector + name = "hologram projector" + desc = "It makes a hologram appear...with magnets or something..." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "hologram0" + +/obj/machinery/hologram/holopad/longrange + name = "long range holopad" + desc = "It's a floor-mounted device for projecting holographic images. This one utilizes bluespace transmitter to communicate with far away locations." + icon_state = "holopad-Y0" + map_range = 2 + power_per_hologram = 1000 //per usage per hologram + holopadType = HOLOPAD_LONG_RANGE + base_icon = "holopad-Y" + +#undef RANGE_BASED +#undef AREA_BASED +#undef HOLOPAD_PASSIVE_POWER_USAGE +#undef HOLOGRAM_POWER_USAGE diff --git a/code/game/machinery/holosign.dm b/code/game/machinery/holosign.dm new file mode 100644 index 00000000..f18cf2dd --- /dev/null +++ b/code/game/machinery/holosign.dm @@ -0,0 +1,73 @@ +////////////////////HOLOSIGN/////////////////////////////////////// +/obj/machinery/holosign + name = "holosign" + desc = "Small wall-mounted holographic projector." + icon = 'icons/obj/holosign.dmi' + icon_state = "sign_off" + layer = ABOVE_DOOR_LAYER + use_power = 1 + idle_power_usage = 2 + active_power_usage = 70 + anchored = 1 + var/lit = 0 + var/id = null + var/on_icon = "sign_on" + var/_wifi_id + var/datum/wifi/receiver/button/holosign/wifi_receiver + +/obj/machinery/holosign/Initialize() + . = ..() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + +/obj/machinery/holosign/Destroy() + qdel(wifi_receiver) + wifi_receiver = null + return ..() + +/obj/machinery/holosign/proc/toggle() + if (stat & (BROKEN|NOPOWER)) + return + lit = !lit + use_power = lit ? 2 : 1 + update_icon() + +//maybe add soft lighting? Maybe, though not everything needs it +/obj/machinery/holosign/update_icon() + if (!lit || (stat & (BROKEN|NOPOWER))) + icon_state = "sign_off" + else + icon_state = on_icon + +/obj/machinery/holosign/surgery + name = "surgery holosign" + desc = "Small wall-mounted holographic projector. This one reads SURGERY." + on_icon = "surgery" +////////////////////SWITCH/////////////////////////////////////// + +/obj/machinery/button/holosign + name = "holosign switch" + desc = "A remote control switch for holosign." + icon = 'icons/obj/power.dmi' + icon_state = "crema_switch" + +/obj/machinery/button/holosign/attack_hand(mob/user as mob) + if(..()) + return + + use_power(5) + + active = !active + update_icon() + + for(var/obj/machinery/holosign/M in SSmachines.machinery) + if (M.id == src.id) + spawn( 0 ) + M.toggle() + return + + return + +/obj/machinery/button/holosign/update_icon() + icon_state = "light[active]" + return \ No newline at end of file diff --git a/code/game/machinery/igniter.dm b/code/game/machinery/igniter.dm new file mode 100644 index 00000000..1ec9d1c6 --- /dev/null +++ b/code/game/machinery/igniter.dm @@ -0,0 +1,166 @@ +/obj/machinery/igniter + name = "igniter" + desc = "It's useful for igniting flammable items." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "igniter1" + var/id = null + var/on = 0 + anchored = 1 + use_power = 1 + idle_power_usage = 2 + active_power_usage = 4 + var/_wifi_id + var/datum/wifi/receiver/button/igniter/wifi_receiver + +/obj/machinery/igniter/New() + ..() + update_icon() + +/obj/machinery/igniter/Initialize() + . = ..() + update_icon() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + +/obj/machinery/igniter/update_icon() + ..() + icon_state = "igniter[on]" + +/obj/machinery/igniter/Destroy() + qdel(wifi_receiver) + wifi_receiver = null + return ..() + +/obj/machinery/igniter/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/igniter/attack_hand(mob/user as mob) + if(..()) + return + ignite() + +/obj/machinery/igniter/Process() //ugh why is this even in process()? + if (on && powered() ) + var/turf/location = src.loc + if (isturf(location)) + location.hotspot_expose(1000,500,1) + return 1 + +/obj/machinery/igniter/proc/ignite() + use_power(50) + on = !on + update_icon() + + +// Wall mounted remote-control igniter. + +/obj/machinery/sparker + name = "Mounted igniter" + desc = "A wall-mounted ignition device." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "migniter" + var/id = null + var/disable = 0 + var/last_spark = 0 + var/base_state = "migniter" + anchored = 1 + use_power = 1 + idle_power_usage = 2 + active_power_usage = 4 + var/_wifi_id + var/datum/wifi/receiver/button/sparker/wifi_receiver + +/obj/machinery/sparker/Initialize() + . = ..() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + +/obj/machinery/sparker/Destroy() + qdel(wifi_receiver) + wifi_receiver = null + return ..() + +/obj/machinery/sparker/update_icon() + ..() + if(disable) + icon_state = "migniter-d" + else if(powered()) + icon_state = "migniter" +// src.sd_SetLuminosity(2) + else + icon_state = "migniter-p" +// src.sd_SetLuminosity(0) + +/obj/machinery/sparker/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isScrewdriver(W)) + add_fingerprint(user) + disable = !disable + if(disable) + user.visible_message("[user] has disabled the [src]!", "You disable the connection to the [src].") + else if(!disable) + user.visible_message("[user] has reconnected the [src]!", "You fix the connection to the [src].") + update_icon() + else + ..() + +/obj/machinery/sparker/attack_ai() + if (anchored) + return ignite() + else + return + +/obj/machinery/sparker/proc/ignite() + if (!powered()) + return + + if (disable || (last_spark && world.time < last_spark + 50)) + return + + + flick("migniter-spark", src) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, src) + s.start() + src.last_spark = world.time + use_power(1000) + var/turf/location = src.loc + if (isturf(location)) + location.hotspot_expose(1000,500,1) + return 1 + +/obj/machinery/sparker/emp_act(severity) + if(stat & (BROKEN|NOPOWER)) + ..(severity) + return + ignite() + ..(severity) + +/obj/machinery/button/ignition + name = "ignition switch" + desc = "A remote control switch for a mounted igniter." + +/obj/machinery/button/ignition/attack_hand(mob/user as mob) + + if(..()) + return + + use_power(5) + + active = 1 + icon_state = "launcheract" + + for(var/obj/machinery/sparker/M in SSmachines.machinery) + if (M.id == id) + spawn( 0 ) + M.ignite() + + for(var/obj/machinery/igniter/M in SSmachines.machinery) + if(M.id == id) + M.ignite() + + sleep(50) + + icon_state = "launcherbtt" + active = 0 + + return diff --git a/code/game/machinery/jukebox.dm b/code/game/machinery/jukebox.dm new file mode 100644 index 00000000..6d0735b2 --- /dev/null +++ b/code/game/machinery/jukebox.dm @@ -0,0 +1,218 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +datum/track + var/title + var/sound + +datum/track/New(var/title_name, var/audio) + title = title_name + sound = audio + +/obj/machinery/media/jukebox + name = "jukebox" + icon = 'icons/obj/jukebox.dmi' + icon_state = "jukebox2-nopower" + var/state_base = "jukebox2" + anchored = 1 + density = 1 + power_channel = EQUIP + use_power = 1 + idle_power_usage = 10 + active_power_usage = 100 + clicksound = 'sound/machines/buttonbeep.ogg' + + var/playing = 0 + var/volume = 20 + + var/sound_id + var/datum/sound_token/sound_token + + var/datum/track/current_track + var/list/datum/track/tracks = list( + new/datum/track("Flexifunk", 'sound/jukebox/barsong1.ogg'), + new/datum/track("Suffer", 'sound/jukebox/barsong2.ogg'), + new/datum/track("Cherry", 'sound/jukebox/barsong3.ogg'), + new/datum/track("Game", 'sound/jukebox/barsong4.ogg'), + new/datum/track("Guru", 'sound/jukebox/barsong5.ogg'), + new/datum/track("Beach", 'sound/jukebox/barsong6.ogg'), + new/datum/track("Wild", 'sound/jukebox/barsong7.ogg'), + new/datum/track("Spiral", 'sound/jukebox/barsong8.ogg'), + new/datum/track("Blizzard", 'sound/jukebox/barsong9.ogg'), + new/datum/track("Evolution", 'sound/jukebox/barsong10.ogg'), + new/datum/track("Sweet", 'sound/jukebox/barsong11.ogg'), + new/datum/track("Fight", 'sound/jukebox/barsong12.ogg'), + new/datum/track("Russian", 'sound/jukebox/barsong13.ogg') + ) + +/obj/machinery/media/jukebox/New() + ..() + update_icon() + sound_id = "[type]_[sequential_id(type)]" + +/obj/machinery/media/jukebox/Destroy() + StopPlaying() + . = ..() + +/obj/machinery/media/jukebox/powered() + return anchored && ..() + +/obj/machinery/media/jukebox/power_change() + . = ..() + if(stat & (NOPOWER|BROKEN) && playing) + StopPlaying() + +/obj/machinery/media/jukebox/update_icon() + overlays.Cut() + if(stat & (NOPOWER|BROKEN) || !anchored) + if(stat & BROKEN) + icon_state = "[state_base]-broken" + else + icon_state = "[state_base]-nopower" + return + icon_state = state_base + if(playing) + if(emagged) + overlays += "[state_base]-emagged" + else + overlays += "[state_base]-running" + +/obj/machinery/media/jukebox/interact(mob/user) + if(!anchored) + to_chat(usr, "You must secure \the [src] first.") + return + + if(stat & (NOPOWER|BROKEN)) + to_chat(usr, "\The [src] doesn't appear to function.") + return + + tg_ui_interact(user) + +/obj/machinery/media/jukebox/ui_status(mob/user, datum/ui_state/state) + if(!anchored || inoperable()) + return UI_CLOSE + return ..() + +/obj/machinery/media/jukebox/tg_ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = tg_default_state) + ui = tgui_process.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "jukebox", "RetroBox - Space Style", 340, 440, master_ui, state) + ui.open() + +/obj/machinery/media/jukebox/ui_data() + var/list/juke_tracks = new + for(var/datum/track/T in tracks) + juke_tracks.Add(T.title) + + var/list/data = list( + "current_track" = current_track != null ? current_track.title : "No track selected", + "playing" = playing, + "tracks" = juke_tracks, + "volume" = volume + ) + + return data + +/obj/machinery/media/jukebox/ui_act(action, params) + if(..()) + return TRUE + switch(action) + if("change_track") + for(var/datum/track/T in tracks) + if(T.title == params["title"]) + current_track = T + StartPlaying() + break + . = TRUE + if("stop") + StopPlaying() + . = TRUE + if("play") + if(emagged) + emag_play() + else if(!current_track) + to_chat(usr, "No track selected.") + else + StartPlaying() + . = TRUE + if("volume") + AdjustVolume(text2num(params["level"])) + . = TRUE + +/obj/machinery/media/jukebox/proc/emag_play() + playsound(loc, 'sound/items/AirHorn.ogg', 100, 1) + for(var/mob/living/carbon/M in ohearers(6, src)) + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(istype(H.l_ear, /obj/item/clothing/ears/earmuffs) || istype(H.r_ear, /obj/item/clothing/ears/earmuffs)) + continue + M.sleeping = 0 + M.stuttering += 20 + M.ear_deaf += 30 + M.Weaken(3) + if(prob(30)) + M.Stun(10) + M.Paralyse(4) + else + M.make_jittery(400) + spawn(15) + explode() + +/obj/machinery/media/jukebox/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/media/jukebox/attack_hand(var/mob/user as mob) + interact(user) + +/obj/machinery/media/jukebox/proc/explode() + walk_to(src,0) + src.visible_message("\the [src] blows apart!", 1) + + explosion(src.loc, 0, 0, 1, rand(1,2), 1) + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + + new /obj/effect/decal/cleanable/blood/oil(src.loc) + qdel(src) + +/obj/machinery/media/jukebox/attackby(obj/item/W as obj, mob/user as mob) + if(isWrench(W)) + add_fingerprint(user) + wrench_floor_bolts(user, 0) + power_change() + return + return ..() + +/obj/machinery/media/jukebox/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + emagged = 1 + StopPlaying() + visible_message("\The [src] makes a fizzling sound.") + update_icon() + return 1 + +/obj/machinery/media/jukebox/proc/StopPlaying() + playing = 0 + update_use_power(1) + update_icon() + QDEL_NULL(sound_token) + + +/obj/machinery/media/jukebox/proc/StartPlaying() + StopPlaying() + if(!current_track) + return + + // Jukeboxes cheat massively and actually don't share id. This is only done because it's music rather than ambient noise. + // It also has the "ignore_vis" flag so it can be heard through walls and zlevels + sound_token = sound_player.PlayLoopingSound(src, sound_id, current_track.sound, volume = volume, range = 14, falloff = 3, prefer_mute = TRUE, ignore_vis = TRUE) + + playing = 1 + update_use_power(2) + update_icon() + +/obj/machinery/media/jukebox/proc/AdjustVolume(var/new_volume) + volume = Clamp(new_volume, 0, 50) + if(sound_token) + sound_token.SetVolume(volume) diff --git a/code/game/machinery/kitchen/cooking_machines/_cooker.dm b/code/game/machinery/kitchen/cooking_machines/_cooker.dm new file mode 100644 index 00000000..70f409f9 --- /dev/null +++ b/code/game/machinery/kitchen/cooking_machines/_cooker.dm @@ -0,0 +1,236 @@ +// This folder contains code that was originally ported from Apollo Station and then refactored/optimized/changed. + +// Tracks precooked food to stop deep fried baked grilled grilled grilled diona nymph cereal. +/obj/item/weapon/reagent_containers/food/snacks/var/list/cooked + +// Root type for cooking machines. See following files for specific implementations. +/obj/machinery/cooker + name = "cooker" + desc = "You shouldn't be seeing this!" + icon = 'icons/obj/cooking_machines.dmi' + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 5 + + var/on_icon // Icon state used when cooking. + var/off_icon // Icon state used when not cooking. + var/cooking // Whether or not the machine is currently operating. + var/cook_type // A string value used to track what kind of food this machine makes. + var/cook_time = 200 // How many ticks the cooking will take. + var/can_cook_mobs // Whether or not this machine accepts grabbed mobs. + var/food_color // Colour of resulting food item. + var/cooked_sound // Sound played when cooking completes. + var/can_burn_food // Can the object burn food that is left inside? + var/burn_chance = 10 // How likely is the food to burn? + var/obj/item/cooking_obj // Holder for the currently cooking object. + + // If the machine has multiple output modes, define them here. + var/selected_option + var/list/output_options = list() + +/obj/machinery/cooker/Destroy() + if(cooking_obj) + qdel(cooking_obj) + cooking_obj = null + return ..() + +/obj/machinery/cooker/examine() + . = ..() + if(cooking_obj && Adjacent(usr)) + to_chat(usr, "You can see \a [cooking_obj] inside.") + +/obj/machinery/cooker/attackby(var/obj/item/I, var/mob/user) + + if(!cook_type || (stat & (NOPOWER|BROKEN))) + to_chat(user, "\The [src] is not working.") + return + + if(cooking) + to_chat(user, "\The [src] is running!") + return + + // We are trying to cook a grabbed mob. + var/obj/item/grab/G = I + if(istype(G)) + + if(!can_cook_mobs) + to_chat(user, "That's not going to fit.") + return + + if(!isliving(G.affecting)) + to_chat(user, "You can't cook that.") + return + + cook_mob(G.affecting, user) + return + + // We're trying to cook something else. Check if it's valid. + var/obj/item/weapon/reagent_containers/food/snacks/check = I + if(istype(check) && islist(check.cooked) && (cook_type in check.cooked)) + to_chat(user, "\The [check] has already been [cook_type].") + return 0 + else if(istype(check, /obj/item/weapon/reagent_containers/glass)) + to_chat(user, "That would probably break [src].") + return 0 + else if(istype(check, /obj/item/weapon/disk/nuclear)) + to_chat(user, "Central Command would kill you if you [cook_type] that.") + return 0 + else if(!istype(check) && !istype(check, /obj/item/weapon/holder)) + to_chat(user, "That's not edible.") + return 0 + + // Gotta hurt. + if(istype(cooking_obj, /obj/item/weapon/holder)) + for(var/mob/living/M in cooking_obj.contents) + M.apply_damage(rand(30,40), BURN, BP_CHEST) + + // Not sure why a food item that passed the previous checks would fail to drop, but safety first. + if(!user.unEquip(I)) + return + + // We can actually start cooking now. + user.visible_message("\The [user] puts \the [I] into \the [src].") + cooking_obj = I + cooking_obj.forceMove(src) + cooking = 1 + icon_state = on_icon + + // Doop de doo. Jeopardy theme goes here. + sleep(cook_time) + + // Sanity checks. + check_cooking_obj() + + // RIP slow-moving held mobs. + if(istype(cooking_obj, /obj/item/weapon/holder)) + for(var/mob/living/M in cooking_obj.contents) + M.death() + + // Cook the food. + var/cook_path + if(selected_option && output_options.len) + cook_path = output_options[selected_option] + if(!cook_path) + cook_path = /obj/item/weapon/reagent_containers/food/snacks/variable + var/obj/item/weapon/reagent_containers/food/snacks/result = new cook_path(src) //Holy typepaths, Batman. + + if(cooking_obj.reagents && cooking_obj.reagents.total_volume) + cooking_obj.reagents.trans_to(result, cooking_obj.reagents.total_volume) + + // Set icon and appearance. + change_product_appearance(result) + + // Update strings. + change_product_strings(result) + + // Set cooked data. + var/obj/item/weapon/reagent_containers/food/snacks/food_item = cooking_obj + if(istype(food_item) && islist(food_item.cooked)) + result.cooked = food_item.cooked.Copy() + else + result.cooked = list() + result.cooked |= cook_type + + // Reset relevant variables. + qdel(cooking_obj) + src.visible_message("\The [src] pings!") + if(cooked_sound) + playsound(get_turf(src), cooked_sound, 50, 1) + + if(!can_burn_food) + icon_state = off_icon + cooking = 0 + result.forceMove(get_turf(src)) + cooking_obj = null + else + var/failed + var/overcook_period = max(Floor(cook_time/5),1) + cooking_obj = result + while(1) + sleep(overcook_period) + if(!cooking || !result || result.loc != src) + failed = 1 + else if(prob(burn_chance)) + // You dun goofed. + qdel(cooking_obj) + cooking_obj = new /obj/item/weapon/reagent_containers/food/snacks/badrecipe(src) + // Produce nasty smoke. + visible_message("\The [src] vomits a gout of rancid smoke!") + var/datum/effect/effect/system/smoke_spread/bad/smoke = new /datum/effect/effect/system/smoke_spread/bad() + smoke.attach(src) + smoke.set_up(10, 0, usr.loc) + smoke.start() + failed = 1 + + if(failed) + cooking = 0 + icon_state = off_icon + break + +/obj/machinery/cooker/proc/check_cooking_obj() + if(!cooking_obj || cooking_obj.loc != src) + cooking_obj = null + icon_state = off_icon + cooking = 0 + return + +/obj/machinery/cooker/attack_hand(var/mob/user) + + if(cooking_obj) + to_chat(user, "You grab \the [cooking_obj] from \the [src].") + user.put_in_hands(cooking_obj) + cooking = 0 + cooking_obj = null + icon_state = off_icon + return + + if(output_options.len) + + if(cooking) + to_chat(user, "\The [src] is in use!") + return + + var/choice = input("What specific food do you wish to make with \the [src]?") as null|anything in output_options+"Default" + if(!choice) + return + if(choice == "Default") + selected_option = null + to_chat(user, "You decide not to make anything specific with \the [src].") + else + selected_option = choice + to_chat(user, "You prepare \the [src] to make \a [selected_option].") + + ..() + +/obj/machinery/cooker/proc/cook_mob(var/mob/living/victim, var/mob/user) + return + +/obj/machinery/cooker/proc/change_product_strings(var/obj/item/weapon/reagent_containers/food/snacks/product) + if(product.type == /obj/item/weapon/reagent_containers/food/snacks/variable) // Base type, generic. + product.SetName("[cook_type] [cooking_obj.name]") + product.desc = "[cooking_obj.desc] It has been [cook_type]." + else + product.SetName("[cooking_obj.name] [product.name]") + +/obj/machinery/cooker/proc/change_product_appearance(var/obj/item/weapon/reagent_containers/food/snacks/product) + if(product.type == /obj/item/weapon/reagent_containers/food/snacks/variable) // Base type, generic. + product.appearance = cooking_obj + product.color = food_color + product.filling_color = food_color + + // Make 'em into a corpse. + if(istype(cooking_obj, /obj/item/weapon/holder)) + var/matrix/M = matrix() + M.Turn(90) + M.Translate(1,-6) + product.transform = M + else + var/image/I = image(product.icon, "[product.icon_state]_filling") + if(istype(cooking_obj, /obj/item/weapon/reagent_containers/food/snacks)) + var/obj/item/weapon/reagent_containers/food/snacks/S = cooking_obj + I.color = S.filling_color + if(!I.color) + I.color = food_color + product.overlays += I + diff --git a/code/game/machinery/kitchen/cooking_machines/_cooker_output.dm b/code/game/machinery/kitchen/cooking_machines/_cooker_output.dm new file mode 100644 index 00000000..7127a583 --- /dev/null +++ b/code/game/machinery/kitchen/cooking_machines/_cooker_output.dm @@ -0,0 +1,79 @@ +// Wrapper obj for cooked food. Appearance is set in the cooking code, not on spawn. +/obj/item/weapon/reagent_containers/food/snacks/variable + name = "cooked food" + icon = 'icons/obj/food_custom.dmi' + desc = "If you can see this description then something is wrong. Please report the bug on the tracker." + nutriment_amt = 5 + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/variable/pizza + name = "personal pizza" + desc = "A personalized pan pizza meant for only one person." + icon_state = "personal_pizza" + +/obj/item/weapon/reagent_containers/food/snacks/variable/bread + name = "bread" + desc = "Tasty bread." + icon_state = "breadcustom" + +/obj/item/weapon/reagent_containers/food/snacks/variable/pie + name = "pie" + desc = "Tasty pie." + icon_state = "piecustom" + +/obj/item/weapon/reagent_containers/food/snacks/variable/cake + name = "cake" + desc = "A popular band." + icon_state = "cakecustom" + +/obj/item/weapon/reagent_containers/food/snacks/variable/pocket + name = "hot pocket" + desc = "You wanna put a bangin- oh, nevermind." + icon_state = "donk" + +/obj/item/weapon/reagent_containers/food/snacks/variable/kebab + name = "kebab" + desc = "Remove this!" + icon_state = "kabob" + +/obj/item/weapon/reagent_containers/food/snacks/variable/waffles + name = "waffles" + desc = "Made with love." + icon_state = "waffles" + gender = PLURAL + +/obj/item/weapon/reagent_containers/food/snacks/variable/pancakes + name = "pancakes" + desc = "How does an oven make pancakes?" + icon_state = "pancakescustom" + gender = PLURAL + +/obj/item/weapon/reagent_containers/food/snacks/variable/cookie + name = "cookie" + desc = "Sugar snap!" + icon_state = "cookie" + +/obj/item/weapon/reagent_containers/food/snacks/variable/donut + name = "filled donut" + desc = "Donut eat this!" // kill me + icon_state = "donut" + +/obj/item/weapon/reagent_containers/food/snacks/variable/jawbreaker + name = "flavored jawbreaker" + desc = "It's like cracking a molar on a rainbow." + icon_state = "jawbreaker" + +/obj/item/weapon/reagent_containers/food/snacks/variable/candybar + name = "flavored chocolate bar" + desc = "Made in a factory downtown." + icon_state = "bar" + +/obj/item/weapon/reagent_containers/food/snacks/variable/sucker + name = "flavored sucker" + desc = "Suck, suck, suck." + icon_state = "sucker" + +/obj/item/weapon/reagent_containers/food/snacks/variable/jelly + name = "jelly" + desc = "All your friends will be jelly." + icon_state = "jellycustom" diff --git a/code/game/machinery/kitchen/cooking_machines/candy.dm b/code/game/machinery/kitchen/cooking_machines/candy.dm new file mode 100644 index 00000000..21fd5069 --- /dev/null +++ b/code/game/machinery/kitchen/cooking_machines/candy.dm @@ -0,0 +1,18 @@ +/obj/machinery/cooker/candy + name = "candy machine" + desc = "Get yer candied cheese wheels here!" + icon_state = "mixer_off" + off_icon = "mixer_off" + on_icon = "mixer_on" + cook_type = "candied" + + output_options = list( + "Jawbreaker" = /obj/item/weapon/reagent_containers/food/snacks/variable/jawbreaker, + "Candy Bar" = /obj/item/weapon/reagent_containers/food/snacks/variable/candybar, + "Sucker" = /obj/item/weapon/reagent_containers/food/snacks/variable/sucker, + "Jelly" = /obj/item/weapon/reagent_containers/food/snacks/variable/jelly + ) + +/obj/machinery/cooker/candy/change_product_appearance(var/obj/item/weapon/reagent_containers/food/snacks/cooked/product) + food_color = get_random_colour(1) + . = ..() diff --git a/code/game/machinery/kitchen/cooking_machines/cereal.dm b/code/game/machinery/kitchen/cooking_machines/cereal.dm new file mode 100644 index 00000000..77bf500a --- /dev/null +++ b/code/game/machinery/kitchen/cooking_machines/cereal.dm @@ -0,0 +1,25 @@ +/obj/machinery/cooker/cereal + name = "cereal maker" + desc = "Now with Dann O's available!" + icon = 'icons/obj/cooking_machines.dmi' + icon_state = "cereal_off" + cook_type = "cerealized" + on_icon = "cereal_on" + off_icon = "cereal_off" + +/obj/machinery/cooker/cereal/change_product_strings(var/obj/item/weapon/reagent_containers/food/snacks/product) + . = ..() + product.SetName("box of [cooking_obj.name] cereal") + +/obj/machinery/cooker/cereal/change_product_appearance(var/obj/item/weapon/reagent_containers/food/snacks/product) + product.icon = 'icons/obj/food.dmi' + product.icon_state = "cereal_box" + product.filling_color = cooking_obj.color + + var/image/food_image = image(cooking_obj.icon, cooking_obj.icon_state) + food_image.color = cooking_obj.color + food_image.overlays += cooking_obj.overlays + food_image.transform *= 0.7 + + product.overlays += food_image + diff --git a/code/game/machinery/kitchen/cooking_machines/fryer.dm b/code/game/machinery/kitchen/cooking_machines/fryer.dm new file mode 100644 index 00000000..76136262 --- /dev/null +++ b/code/game/machinery/kitchen/cooking_machines/fryer.dm @@ -0,0 +1,52 @@ +/obj/machinery/cooker/fryer + name = "deep fryer" + desc = "Deep fried everything." + icon_state = "fryer_off" + can_cook_mobs = 1 + cook_type = "deep fried" + on_icon = "fryer_on" + off_icon = "fryer_off" + food_color = "#ffad33" + cooked_sound = 'sound/machines/ding.ogg' + +/obj/machinery/cooker/fryer/cook_mob(var/mob/living/victim, var/mob/user) + + if(!istype(victim)) + return + + user.visible_message("\The [user] starts pushing \the [victim] into \the [src]!") + icon_state = on_icon + cooking = 1 + + if(!do_mob(user, victim, 20)) + cooking = 0 + icon_state = off_icon + return + + if(!victim || !victim.Adjacent(user)) + to_chat(user, "Your victim slipped free!") + cooking = 0 + icon_state = off_icon + return + + var/target_zone = user.zone_sel.selecting + if(ishuman(victim) && !(target_zone in list(BP_GROIN, BP_CHEST))) + var/mob/living/carbon/human/H = victim + var/obj/item/organ/external/E = H.get_organ(target_zone) + if(!E) + to_chat(user, "They are missing that body part!") + else + visible_message("\The [user] shoves \the [victim][E ? "'s [E.name]" : ""] into \the [src]!") + var/blocked = H.run_armor_check(target_zone, "energy") + H.apply_damage(rand(20,30), BURN, target_zone, blocked) + + else + var/blocked = victim.run_armor_check(null, "energy") + victim.apply_damage(rand(30,40), BURN, null, blocked) + + if(victim) + admin_attack_log(user, victim, "Has [cook_type] their victim in \a [src]", "Has been [cook_type] in \a [src] by the attacker.", "[cook_type], in \a [src], ") + + icon_state = off_icon + cooking = 0 + return diff --git a/code/game/machinery/kitchen/cooking_machines/grill.dm b/code/game/machinery/kitchen/cooking_machines/grill.dm new file mode 100644 index 00000000..b4f83c56 --- /dev/null +++ b/code/game/machinery/kitchen/cooking_machines/grill.dm @@ -0,0 +1,10 @@ +/obj/machinery/cooker/grill + name = "griddle" + desc = "A flat, wide, and smooth cooking surface." + icon_state = "grill_off" + cook_type = "grilled" + cook_time = 100 + food_color = "#a34719" + on_icon = "grill_on" + off_icon = "grill_off" + can_burn_food = 1 \ No newline at end of file diff --git a/code/game/machinery/kitchen/cooking_machines/oven.dm b/code/game/machinery/kitchen/cooking_machines/oven.dm new file mode 100644 index 00000000..c4ad7441 --- /dev/null +++ b/code/game/machinery/kitchen/cooking_machines/oven.dm @@ -0,0 +1,24 @@ +/obj/machinery/cooker/oven + name = "oven" + desc = "Cookies are ready, dear." + icon = 'icons/obj/cooking_machines.dmi' + icon_state = "oven_off" + on_icon = "oven_on" + off_icon = "oven_off" + cook_type = "baked" + cook_time = 300 + food_color = "#a34719" + can_burn_food = 1 + + output_options = list( + "Personal Pizza" = /obj/item/weapon/reagent_containers/food/snacks/variable/pizza, + "Bread" = /obj/item/weapon/reagent_containers/food/snacks/variable/bread, + "Pie" = /obj/item/weapon/reagent_containers/food/snacks/variable/pie, + "Small Cake" = /obj/item/weapon/reagent_containers/food/snacks/variable/cake, + "Hot Pocket" = /obj/item/weapon/reagent_containers/food/snacks/variable/pocket, + "Kebab" = /obj/item/weapon/reagent_containers/food/snacks/variable/kebab, + "Waffles" = /obj/item/weapon/reagent_containers/food/snacks/variable/waffles, + "Pancakes" = /obj/item/weapon/reagent_containers/food/snacks/variable/pancakes, + "Cookie" = /obj/item/weapon/reagent_containers/food/snacks/variable/cookie, + "Donut" = /obj/item/weapon/reagent_containers/food/snacks/variable/donut, + ) \ No newline at end of file diff --git a/code/game/machinery/kitchen/gibber.dm b/code/game/machinery/kitchen/gibber.dm new file mode 100644 index 00000000..73e1cc52 --- /dev/null +++ b/code/game/machinery/kitchen/gibber.dm @@ -0,0 +1,237 @@ + +/obj/machinery/gibber + name = "meat grinder" + desc = "The name isn't descriptive enough?" + icon = 'icons/obj/kitchen.dmi' + icon_state = "grinder" + density = 1 + anchored = 1 + req_access = list(access_kitchen,access_morgue) + + var/operating = 0 //Is it on? + var/dirty = 0 // Does it need cleaning? + var/mob/living/occupant // Mob who has been put inside + var/gib_time = 40 // Time from starting until meat appears + var/gib_throw_dir = WEST // Direction to spit meat and gibs in. + + use_power = 1 + idle_power_usage = 2 + active_power_usage = 500 + +//auto-gibs anything that bumps into it +/obj/machinery/gibber/autogibber + var/turf/input_plate + +/obj/machinery/gibber/autogibber/New() + ..() + spawn(5) + for(var/i in GLOB.cardinal) + var/obj/machinery/mineral/input/input_obj = locate( /obj/machinery/mineral/input, get_step(src.loc, i) ) + if(input_obj) + if(isturf(input_obj.loc)) + input_plate = input_obj.loc + gib_throw_dir = i + qdel(input_obj) + break + + if(!input_plate) + log_misc("a [src] didn't find an input plate.") + return + +/obj/machinery/gibber/autogibber/Bumped(var/atom/A) + if(!input_plate) return + + if(ismob(A)) + var/mob/M = A + + if(M.loc == input_plate) + M.forceMove(src) + M.gib() + + +/obj/machinery/gibber/Initialize() + . = ..() + update_icon() + +/obj/machinery/gibber/update_icon() + overlays.Cut() + if (dirty) + src.overlays += image('icons/obj/kitchen.dmi', "grbloody") + if(stat & (NOPOWER|BROKEN)) + return + if (!occupant) + src.overlays += image('icons/obj/kitchen.dmi', "grjam") + else if (operating) + src.overlays += image('icons/obj/kitchen.dmi', "gruse") + else + src.overlays += image('icons/obj/kitchen.dmi', "gridle") + +/obj/machinery/gibber/relaymove(mob/user as mob) + src.go_out() + return + +/obj/machinery/gibber/attack_hand(mob/user as mob) + if(stat & (NOPOWER|BROKEN)) + return + if(operating) + to_chat(user, "\The [src] is locked and running, wait for it to finish.") + return + else + src.startgibbing(user) + +/obj/machinery/gibber/examine() + . = ..() + to_chat(usr, "The safety guard is [emagged ? "disabled" : "enabled"].") + +/obj/machinery/gibber/emag_act(var/remaining_charges, var/mob/user) + emagged = !emagged + to_chat(user, "You [emagged ? "disable" : "enable"] \the [src]'s safety guard.") + return 1 + +/obj/machinery/gibber/attackby(var/obj/item/W, var/mob/user) + if(istype(W, /obj/item/grab)) + var/obj/item/grab/G = W + if(!G.force_danger()) + to_chat(user, "You need a better grip to do that!") + return + move_into_gibber(user,G.affecting) + user.drop_from_inventory(G) + else if(istype(W, /obj/item/organ)) + user.drop_from_inventory(W) + qdel(W) + user.visible_message("\The [user] feeds \the [W] into \the [src], obliterating it.") + else + return ..() + +/obj/machinery/gibber/MouseDrop_T(mob/target, mob/user) + if(user.stat || user.restrained()) + return + move_into_gibber(user,target) + +/obj/machinery/gibber/proc/move_into_gibber(var/mob/user,var/mob/living/victim) + + if(src.occupant) + to_chat(user, "\The [src] is full, empty it first!") + return + + if(operating) + to_chat(user, "\The [src] is locked and running, wait for it to finish.") + return + + if(!(istype(victim, /mob/living/carbon)) && !(istype(victim, /mob/living/simple_animal)) ) + to_chat(user, "This is not suitable for \the [src]!") + return + + if(istype(victim,/mob/living/carbon/human) && !emagged) + to_chat(user, "\The [src] safety guard is engaged!") + return + + + if(victim.abiotic(1)) + to_chat(user, "\The [victim] may not have any abiotic items on.") + return + + user.visible_message("\The [user] starts to put \the [victim] into \the [src]!") + src.add_fingerprint(user) + if(do_after(user, 30, src) && victim.Adjacent(src) && user.Adjacent(src) && victim.Adjacent(user) && !occupant) + user.visible_message("\The [user] stuffs \the [victim] into \the [src]!") + if(victim.client) + victim.client.perspective = EYE_PERSPECTIVE + victim.client.eye = src + victim.forceMove(src) + src.occupant = victim + update_icon() + +/obj/machinery/gibber/proc/eject() + set category = "Object" + set name = "Empty Gibber" + + if (usr.stat != 0) + return + src.go_out() + add_fingerprint(usr) + return + +/obj/machinery/gibber/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + eject() + +/obj/machinery/gibber/proc/go_out() + if(operating || !src.occupant) + return + for(var/obj/O in src) + O.dropInto(loc) + if (src.occupant.client) + src.occupant.client.eye = src.occupant.client.mob + src.occupant.client.perspective = MOB_PERSPECTIVE + src.occupant.dropInto(loc) + src.occupant = null + update_icon() + return + +/obj/machinery/gibber/proc/startgibbing(mob/user as mob) + if(src.operating) + return + if(!src.occupant) + visible_message("You hear a loud metallic grinding sound.") + return + + use_power(1000) + visible_message("You hear a loud [occupant.isSynthetic() ? "metallic" : "squelchy"] grinding sound.") + src.operating = 1 + update_icon() + + var/slab_name = occupant.name + var/slab_count = 3 + var/slab_type = /obj/item/weapon/reagent_containers/food/snacks/meat + var/slab_nutrition = 20 + if(iscarbon(occupant)) + var/mob/living/carbon/C = occupant + slab_nutrition = C.nutrition / 15 + + // Some mobs have specific meat item types. + if(istype(src.occupant,/mob/living/simple_animal)) + var/mob/living/simple_animal/critter = src.occupant + if(critter.meat_amount) + slab_count = critter.meat_amount + if(critter.meat_type) + slab_type = critter.meat_type + else if(istype(src.occupant,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = occupant + slab_name = src.occupant.real_name + slab_type = H.isSynthetic() ? /obj/item/stack/material/steel : H.species.meat_type + + // Small mobs don't give as much nutrition. + if(issmall(src.occupant)) + slab_nutrition *= 0.5 + slab_nutrition /= slab_count + + for(var/i=1 to slab_count) + var/obj/item/weapon/reagent_containers/food/snacks/meat/new_meat = new slab_type(src, rand(3,8)) + if(istype(new_meat)) + new_meat.SetName("[slab_name] [new_meat.name]") + new_meat.reagents.add_reagent(/datum/reagent/nutriment,slab_nutrition) + if(src.occupant.reagents) + src.occupant.reagents.trans_to_obj(new_meat, round(occupant.reagents.total_volume/slab_count,1)) + + admin_attack_log(user, occupant, "Gibbed the victim", "Was gibbed", "gibbed") + src.occupant.ghostize() + + spawn(gib_time) + + src.operating = 0 + src.occupant.gib() + qdel(src.occupant) + + playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) + operating = 0 + for (var/obj/thing in contents) + // There's a chance that the gibber will fail to destroy some evidence. + if(istype(thing,/obj/item/organ) && prob(80)) + qdel(thing) + continue + thing.dropInto(loc) // Attempts to drop it onto the turf for throwing. + thing.throw_at(get_edge_target_turf(src,gib_throw_dir),rand(0,3),emagged ? 100 : 50) // Being pelted with bits of meat and bone would hurt. + update_icon() + + diff --git a/code/game/machinery/kitchen/icecream.dm b/code/game/machinery/kitchen/icecream.dm new file mode 100644 index 00000000..f8ca70b0 --- /dev/null +++ b/code/game/machinery/kitchen/icecream.dm @@ -0,0 +1,210 @@ +#define ICECREAM_VANILLA 1 +#define ICECREAM_CHOCOLATE 2 +#define ICECREAM_STRAWBERRY 3 +#define ICECREAM_BLUE 4 +#define ICECREAM_CHERRY 5 +#define ICECREAM_BANANA 6 +#define CONE_WAFFLE 7 +#define CONE_CHOC 8 + +// Ported wholesale from Apollo Station. + +/obj/machinery/icecream_vat + name = "icecream vat" + desc = "A heavy metal container used to produce and store ice cream." + icon = 'icons/obj/kitchen.dmi' + icon_state = "icecream_vat" + density = 1 + anchored = 0 + use_power = 0 + atom_flags = ATOM_FLAG_NO_REACT + atom_flags = ATOM_FLAG_OPEN_CONTAINER + + var/list/product_types = list() + var/dispense_flavour = ICECREAM_VANILLA + var/flavour_name = "vanilla" + +/obj/machinery/icecream_vat/proc/get_ingredient_list(var/type) + switch(type) + if(ICECREAM_CHOCOLATE) + return list(/datum/reagent/drink/milk, /datum/reagent/drink/ice, /datum/reagent/nutriment/coco) + if(ICECREAM_STRAWBERRY) + return list(/datum/reagent/drink/milk, /datum/reagent/drink/ice, /datum/reagent/drink/juice/berry) + if(ICECREAM_BLUE) + return list(/datum/reagent/drink/milk, /datum/reagent/drink/ice, /datum/reagent/ethanol/singulo) + if(ICECREAM_CHERRY) + return list(/datum/reagent/drink/milk, /datum/reagent/drink/ice, /datum/reagent/nutriment/cherryjelly) + if(ICECREAM_BANANA) + return list(/datum/reagent/drink/milk, /datum/reagent/drink/ice, /datum/reagent/drink/juice/banana) + if(CONE_WAFFLE) + return list(/datum/reagent/nutriment/flour, /datum/reagent/sugar) + if(CONE_CHOC) + return list(/datum/reagent/nutriment/flour, /datum/reagent/sugar, /datum/reagent/nutriment/coco) + else + return list(/datum/reagent/drink/milk, /datum/reagent/drink/ice) + +/obj/machinery/icecream_vat/proc/get_flavour_name(var/flavour_type) + switch(flavour_type) + if(ICECREAM_CHOCOLATE) + return "chocolate" + if(ICECREAM_STRAWBERRY) + return "strawberry" + if(ICECREAM_BLUE) + return "blue" + if(ICECREAM_CHERRY) + return "cherry" + if(ICECREAM_BANANA) + return "banana" + if(CONE_WAFFLE) + return "waffle" + if(CONE_CHOC) + return "chocolate" + else + return "vanilla" + +/obj/machinery/icecream_vat/Initialize() + . = ..() + create_reagents(100) + while(product_types.len < 8) + product_types.Add(5) + reagents.add_reagent(/datum/reagent/drink/milk, 5) + reagents.add_reagent(/datum/reagent/nutriment/flour, 5) + reagents.add_reagent(/datum/reagent/sugar, 5) + reagents.add_reagent(/datum/reagent/drink/ice, 5) + +/obj/machinery/icecream_vat/attack_hand(mob/user as mob) + user.set_machine(src) + interact(user) + +/obj/machinery/icecream_vat/interact(mob/user as mob) + var/dat + dat += "ICECREAM
    " + dat += "Dispensing: [flavour_name] icecream

    " + dat += "Vanilla icecream: Select Make x5 [product_types[ICECREAM_VANILLA]] scoops left. (Ingredients: milk, ice)
    " + dat += "Strawberry icecream: Select Make x5 [product_types[ICECREAM_STRAWBERRY]] dollops left. (Ingredients: milk, ice, berry juice)
    " + dat += "Chocolate icecream: Select Make x5 [product_types[ICECREAM_CHOCOLATE]] dollops left. (Ingredients: milk, ice, coco powder)
    " + dat += "Blue icecream: Select Make x5 [product_types[ICECREAM_BLUE]] dollops left. (Ingredients: milk, ice, singulo)
    " + dat += "Cherry icecream: Select Make x5 [product_types[ICECREAM_CHERRY]] dollops left. (Ingredients: milk, ice, cherry jelly)
    " + dat += "Banana icecream: Select Make x5 [product_types[ICECREAM_BANANA]] dollops left. (Ingredients: milk, ice, banana)
    " + dat += "
    CONES
    " + dat += "Waffle cones: Dispense Make x5 [product_types[CONE_WAFFLE]] cones left. (Ingredients: flour, sugar)
    " + dat += "Chocolate cones: Dispense Make x5 [product_types[CONE_CHOC]] cones left. (Ingredients: flour, sugar, coco powder)
    " + dat += "
    " + dat += "VAT CONTENT
    " + for(var/datum/reagent/R in reagents.reagent_list) + dat += "[R.name]: [R.volume]" + dat += "Purge
    " + dat += "Refresh Close" + + var/datum/browser/popup = new(user, "icecreamvat","Icecream Vat", 700, 500, src) + popup.set_content(dat) + popup.open() + +/obj/machinery/icecream_vat/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/icecream)) + var/obj/item/weapon/reagent_containers/food/snacks/icecream/I = O + if(!I.ice_creamed) + if(product_types[dispense_flavour] > 0) + src.visible_message("\icon[src] [user] scoops delicious [flavour_name] icecream into [I].") + product_types[dispense_flavour] -= 1 + I.add_ice_cream(flavour_name) + // if(beaker) + // beaker.reagents.trans_to(I, 10) + if(I.reagents.total_volume < 10) + I.reagents.add_reagent(/datum/reagent/sugar, 10 - I.reagents.total_volume) + else + to_chat(user, "There is not enough icecream left!") + else + to_chat(user, "[O] already has icecream in it.") + return 1 + else if(O.is_open_container()) + return + else + ..() + +/obj/machinery/icecream_vat/proc/make(var/mob/user, var/make_type, var/amount) + for(var/R in get_ingredient_list(make_type)) + if(reagents.has_reagent(R, amount)) + continue + amount = 0 + break + if(amount) + for(var/R in get_ingredient_list(make_type)) + reagents.remove_reagent(R, amount) + product_types[make_type] += amount + var/flavour = get_flavour_name(make_type) + if(make_type > 6) + src.visible_message("[user] cooks up some [flavour] cones.") + else + src.visible_message("[user] whips up some [flavour] icecream.") + else + to_chat(user, "You don't have the ingredients to make this.") + +/obj/machinery/icecream_vat/OnTopic(user, href_list) + if(href_list["close"]) + usr << browse(null,"window=icecreamvat") + return TOPIC_HANDLED + + if(href_list["select"]) + dispense_flavour = text2num(href_list["select"]) + flavour_name = get_flavour_name(dispense_flavour) + src.visible_message("[user] sets [src] to dispense [flavour_name] flavoured icecream.") + . = TOPIC_HANDLED + + else if(href_list["cone"]) + var/dispense_cone = text2num(href_list["cone"]) + var/cone_name = get_flavour_name(dispense_cone) + if(product_types[dispense_cone] >= 1) + product_types[dispense_cone] -= 1 + var/obj/item/weapon/reagent_containers/food/snacks/icecream/I = new(src.loc) + I.cone_type = cone_name + I.icon_state = "icecream_cone_[cone_name]" + I.desc = "Delicious [cone_name] cone, but no ice cream." + src.visible_message("[user] dispenses a crunchy [cone_name] cone from [src].") + else + to_chat(user, "There are no [cone_name] cones left!") + . = TOPIC_REFRESH + + else if(href_list["make"]) + var/amount = (text2num(href_list["amount"])) + var/C = text2num(href_list["make"]) + make(user, C, amount) + . = TOPIC_REFRESH + + else if(href_list["disposeI"]) + var/datum/reagent/R = locate(href_list["disposeI"]) in reagents.reagent_list + if(R) + reagents.del_reagent(R.type) + . = TOPIC_REFRESH + + if(href_list["refresh"] || . == TOPIC_REFRESH) + interact(user) + +/obj/item/weapon/reagent_containers/food/snacks/icecream + name = "ice cream cone" + desc = "Delicious waffle cone, but no ice cream." + icon_state = "icecream_cone_waffle" //default for admin-spawned cones, href_list["cone"] should overwrite this all the time + layer = ABOVE_OBJ_LAYER + bitesize = 3 + + var/ice_creamed = 0 + var/cone_type + +/obj/item/weapon/reagent_containers/food/snacks/icecream/New() + create_reagents(20) + reagents.add_reagent(/datum/reagent/nutriment, 5) + +/obj/item/weapon/reagent_containers/food/snacks/icecream/proc/add_ice_cream(var/flavour_name) + name = "[flavour_name] icecream" + src.overlays += "icecream_[flavour_name]" + desc = "Delicious [cone_type] cone with a dollop of [flavour_name] ice cream." + ice_creamed = 1 + +#undef ICECREAM_VANILLA +#undef ICECREAM_CHOCOLATE +#undef ICECREAM_STRAWBERRY +#undef ICECREAM_BLUE +#undef ICECREAM_CHERRY +#undef ICECREAM_BANANA +#undef CONE_WAFFLE +#undef CONE_CHOC \ No newline at end of file diff --git a/code/game/machinery/kitchen/microwave.dm b/code/game/machinery/kitchen/microwave.dm new file mode 100644 index 00000000..8af8b9ba --- /dev/null +++ b/code/game/machinery/kitchen/microwave.dm @@ -0,0 +1,391 @@ + +/obj/machinery/microwave + name = "microwave" + icon = 'icons/obj/kitchen.dmi' + icon_state = "mw" + layer = BELOW_OBJ_LAYER + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 5 + active_power_usage = 100 + atom_flags = ATOM_FLAG_NO_REACT + atom_flags = ATOM_FLAG_OPEN_CONTAINER + var/operating = 0 // Is it on? + var/dirty = 0 // = {0..100} Does it need cleaning? + var/broken = 0 // ={0,1,2} How broken is it??? + var/global/list/datum/recipe/available_recipes // List of the recipes you can use + var/global/list/acceptable_items // List of the items you can put in + var/global/list/acceptable_reagents // List of the reagents you can put in + var/global/max_n_of_items = 0 + + +// see code/modules/food/recipes_microwave.dm for recipes + +/******************* +* Initialising +********************/ + +/obj/machinery/microwave/New() + ..() + create_reagents(100) + if (!available_recipes) + available_recipes = new + for (var/type in (typesof(/datum/recipe)-/datum/recipe)) + available_recipes+= new type + acceptable_items = new + acceptable_reagents = new + for (var/datum/recipe/recipe in available_recipes) + for (var/item in recipe.items) + acceptable_items |= item + for (var/reagent in recipe.reagents) + acceptable_reagents |= reagent + if (recipe.items) + max_n_of_items = max(max_n_of_items,recipe.items.len) + // This will do until I can think of a fun recipe to use dionaea in - + // will also allow anything using the holder item to be microwaved into + // impure carbon. ~Z + acceptable_items |= /obj/item/weapon/holder + acceptable_items |= /obj/item/weapon/reagent_containers/food/snacks/grown + +/******************* +* Item Adding +********************/ + +/obj/machinery/microwave/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(src.broken > 0) + if(src.broken == 2 && isScrewdriver(O)) // If it's broken and they're using a screwdriver + user.visible_message( \ + "\The [user] starts to fix part of the microwave.", \ + "You start to fix part of the microwave." \ + ) + if (do_after(user, 20, src)) + user.visible_message( \ + "\The [user] fixes part of the microwave.", \ + "You have fixed part of the microwave." \ + ) + src.broken = 1 // Fix it a bit + else if(src.broken == 1 && isWrench(O)) // If it's broken and they're doing the wrench + user.visible_message( \ + "\The [user] starts to fix part of the microwave.", \ + "You start to fix part of the microwave." \ + ) + if (do_after(user, 20, src)) + user.visible_message( \ + "\The [user] fixes the microwave.", \ + "You have fixed the microwave." \ + ) + src.broken = 0 // Fix it! + src.dirty = 0 // just to be sure + src.update_icon() + src.atom_flags = ATOM_FLAG_OPEN_CONTAINER + else + to_chat(user, "It's broken!") + return 1 + else if(src.dirty==100) // The microwave is all dirty so can't be used! + if(istype(O, /obj/item/weapon/reagent_containers/spray/cleaner) || istype(O, /obj/item/weapon/reagent_containers/glass/rag)) // If they're trying to clean it then let them + user.visible_message( \ + "\The [user] starts to clean the microwave.", \ + "You start to clean the microwave." \ + ) + if (do_after(user, 20, src)) + user.visible_message( \ + "\The [user] has cleaned the microwave.", \ + "You have cleaned the microwave." \ + ) + src.dirty = 0 // It's clean! + src.broken = 0 // just to be sure + src.update_icon() + src.atom_flags = ATOM_FLAG_OPEN_CONTAINER + else //Otherwise bad luck!! + to_chat(user, "It's dirty!") + return 1 + else if(is_type_in_list(O,acceptable_items)) + if (contents.len >= max_n_of_items) + to_chat(user, "This [src] is full of ingredients, you cannot put more.") + return 1 + if(istype(O, /obj/item/stack)) // This is bad, but I can't think of how to change it + var/obj/item/stack/S = O + if(S.get_amount() > 1) + new O.type (src) + S.use(1) + user.visible_message( \ + "\The [user] has added one of [O] to \the [src].", \ + "You add one of [O] to \the [src].") + return + else + user.drop_item(src) + user.visible_message( \ + "\The [user] has added \the [O] to \the [src].", \ + "You add \the [O] to \the [src].") + return + else if(istype(O,/obj/item/weapon/reagent_containers/glass) || \ + istype(O,/obj/item/weapon/reagent_containers/food/drinks) || \ + istype(O,/obj/item/weapon/reagent_containers/food/condiment) \ + ) + if (!O.reagents) + return 1 + for (var/datum/reagent/R in O.reagents.reagent_list) + if (!(R.type in acceptable_reagents)) + to_chat(user, "Your [O] contains components unsuitable for cookery.") + return 1 + return + else if(istype(O,/obj/item/grab)) + var/obj/item/grab/G = O + to_chat(user, "This is ridiculous. You can not fit \the [G.affecting] in this [src].") + return 1 + else if(isCrowbar(O)) + user.visible_message( \ + "\The [user] begins [src.anchored ? "securing" : "unsecuring"] the microwave.", \ + "You attempt to [src.anchored ? "secure" : "unsecure"] the microwave." + ) + if (do_after(user,20, src)) + user.visible_message( \ + "\The [user] [src.anchored ? "secures" : "unsecures"] the microwave.", \ + "You [src.anchored ? "secure" : "unsecure"] the microwave." + ) + src.anchored = !src.anchored + else + to_chat(user, "You decide not to do that.") + else + + to_chat(user, "You have no idea what you can cook with this [O].") + ..() + src.updateUsrDialog() + +/obj/machinery/microwave/attack_ai(mob/user as mob) + if(istype(user, /mob/living/silicon/robot) && Adjacent(user)) + attack_hand(user) + +/obj/machinery/microwave/attack_hand(mob/user as mob) + user.set_machine(src) + interact(user) + +/******************* +* Microwave Menu +********************/ + +/obj/machinery/microwave/interact(mob/user as mob) // The microwave Menu + var/dat = list() + if(src.broken > 0) + dat += "Bzzzzttttt" + else if(src.operating) + dat += "Microwaving in progress!
    Please wait...!
    " + else if(src.dirty==100) + dat += "This microwave is dirty!
    Please clean it before use!
    " + else + var/list/items_counts = new + var/list/items_measures = new + var/list/items_measures_p = new + for (var/obj/O in InsertedContents()) + var/display_name = O.name + if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/egg)) + items_measures[display_name] = "egg" + items_measures_p[display_name] = "eggs" + if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/tofu)) + items_measures[display_name] = "tofu chunk" + items_measures_p[display_name] = "tofu chunks" + if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/meat)) //any meat + items_measures[display_name] = "slab of meat" + items_measures_p[display_name] = "slabs of meat" + if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/donkpocket)) + display_name = "Turnovers" + items_measures[display_name] = "turnover" + items_measures_p[display_name] = "turnovers" + if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/carpmeat)) + items_measures[display_name] = "fillet of meat" + items_measures_p[display_name] = "fillets of meat" + items_counts[display_name]++ + for (var/O in items_counts) + var/N = items_counts[O] + if (!(O in items_measures)) + dat += "[capitalize(O)]: [N] [lowertext(O)]\s" + else + if (N==1) + dat += "[capitalize(O)]: [N] [items_measures[O]]" + else + dat += "[capitalize(O)]: [N] [items_measures_p[O]]" + + for (var/datum/reagent/R in reagents.reagent_list) + var/display_name = R.name + if (R.type == /datum/reagent/capsaicin) + display_name = "Hotsauce" + if (R.type == /datum/reagent/frostoil) + display_name = "Coldsauce" + dat += "[display_name]: [R.volume] unit\s" + + if (items_counts.len==0 && reagents.reagent_list.len==0) + dat += "The microwave is empty" + else + dat += "Ingredients:
    [dat]" + dat += "

    Turn on!
    Eject ingredients!" + + show_browser(user, "Microwave Controls[jointext(dat,"
    ")]
    ", "window=microwave") + onclose(user, "microwave") + return + + + +/*********************************** +* Microwave Menu Handling/Cooking +************************************/ + +/obj/machinery/microwave/proc/cook() + if(stat & (NOPOWER|BROKEN)) + return + start() + if (reagents.total_volume==0 && !contents.len) //dry run + if (!wzhzhzh(10)) + abort() + return + stop() + return + + var/datum/recipe/recipe = select_recipe(available_recipes,src) + var/obj/cooked + if (!recipe) + dirty += 1 + if (prob(max(10,dirty*5))) + if (!wzhzhzh(4)) + abort() + return + muck_start() + wzhzhzh(4) + muck_finish() + cooked = fail() + cooked.dropInto(loc) + return + else if (has_extra_item()) + if (!wzhzhzh(4)) + abort() + return + broke() + cooked = fail() + cooked.dropInto(loc) + return + else + if (!wzhzhzh(10)) + abort() + return + stop() + cooked = fail() + cooked.dropInto(loc) + return + else + var/halftime = round(recipe.time/10/2) + if (!wzhzhzh(halftime)) + abort() + return + if (!wzhzhzh(halftime)) + abort() + cooked = fail() + cooked.dropInto(loc) + return + cooked = recipe.make_food(src) + stop() + if(cooked) + cooked.dropInto(loc) + return + +/obj/machinery/microwave/proc/wzhzhzh(var/seconds as num) // Whoever named this proc is fucking literally Satan. ~ Z + for (var/i=1 to seconds) + if (stat & (NOPOWER|BROKEN)) + return 0 + use_power(500) + sleep(10) + return 1 + +/obj/machinery/microwave/proc/has_extra_item() + for (var/obj/O in src) + if (!istype(O,/obj/item/weapon/reagent_containers/food) && !istype(O, /obj/item/weapon/grown)) + return 1 + return 0 + +/obj/machinery/microwave/proc/start() + src.visible_message("The microwave turns on.", "You hear a microwave.") + src.operating = 1 + src.updateUsrDialog() + src.update_icon() + +/obj/machinery/microwave/proc/abort() + src.operating = 0 // Turn it off again aferwards + src.updateUsrDialog() + src.update_icon() + +/obj/machinery/microwave/proc/stop() + playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) + src.operating = 0 // Turn it off again aferwards + src.updateUsrDialog() + src.update_icon() + +/obj/machinery/microwave/proc/dispose() + for (var/obj/O in src) + O.dropInto(loc) + if (src.reagents.total_volume) + src.dirty++ + src.reagents.clear_reagents() + to_chat(usr, "You dispose of the microwave contents.") + src.updateUsrDialog() + +/obj/machinery/microwave/proc/muck_start() + playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) // Play a splat sound + src.update_icon() + +/obj/machinery/microwave/proc/muck_finish() + playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) + src.visible_message("The microwave gets covered in muck!") + src.dirty = 100 // Make it dirty so it can't be used util cleaned + src.obj_flags = null //So you can't add condiments + src.operating = 0 // Turn it off again aferwards + src.updateUsrDialog() + src.update_icon() + +/obj/machinery/microwave/proc/broke() + var/datum/effect/effect/system/spark_spread/s = new + s.set_up(2, 1, src) + s.start() + src.visible_message("The microwave breaks!") //Let them know they're stupid + src.broken = 2 // Make it broken so it can't be used util fixed + src.obj_flags = null //So you can't add condiments + src.operating = 0 // Turn it off again aferwards + src.updateUsrDialog() + src.update_icon() + +/obj/machinery/microwave/update_icon() + if(dirty == 100) + src.icon_state = "mwbloody[operating]" + else if(broken) + src.icon_state = "mwb" + else + src.icon_state = "mw[operating]" + +/obj/machinery/microwave/proc/fail() + var/amount = 0 + for (var/obj/O in contents) + amount++ + if (O.reagents) + var/reagent_type = O.reagents.get_master_reagent_type() + if (reagent_type) + amount+=O.reagents.get_reagent_amount(reagent_type) + qdel(O) + src.reagents.clear_reagents() + var/obj/item/weapon/reagent_containers/food/snacks/badrecipe/ffuu = new(src) + ffuu.reagents.add_reagent(/datum/reagent/carbon, amount) + ffuu.reagents.add_reagent(/datum/reagent/toxin, amount/10) + return ffuu + +/obj/machinery/microwave/Topic(href, href_list) + if(..()) + return 1 + + usr.set_machine(src) + if(src.operating) + src.updateUsrDialog() + return + + switch(href_list["action"]) + if ("cook") + cook() + + if ("dispose") + dispose() \ No newline at end of file diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm new file mode 100644 index 00000000..9c257c81 --- /dev/null +++ b/code/game/machinery/kitchen/smartfridge.dm @@ -0,0 +1,351 @@ + +/* SmartFridge. Much todo +*/ +/obj/machinery/smartfridge + name = "\improper SmartFridge" + icon = 'icons/obj/vending.dmi' + icon_state = "smartfridge" + layer = BELOW_OBJ_LAYER + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 5 + active_power_usage = 100 + atom_flags = ATOM_FLAG_NO_REACT + var/global/max_n_of_items = 999 // Sorry but the BYOND infinite loop detector doesn't look things over 1000. + var/icon_on = "smartfridge" + var/icon_off = "smartfridge-off" + var/icon_panel = "smartfridge-panel" + var/list/item_records = list() + var/datum/stored_items/currently_vending = null //What we're putting out of the machine. + var/seconds_electrified = 0; + var/shoot_inventory = 0 + var/locked = 0 + var/scan_id = 1 + var/is_secure = 0 + var/datum/wires/smartfridge/wires = null + +/obj/machinery/smartfridge/secure + is_secure = 1 + +/obj/machinery/smartfridge/New() + ..() + if(is_secure) + wires = new/datum/wires/smartfridge/secure(src) + else + wires = new/datum/wires/smartfridge(src) + +/obj/machinery/smartfridge/Destroy() + qdel(wires) + wires = null + for(var/datum/stored_items/S in item_records) + qdel(S) + item_records = null + return ..() + +/obj/machinery/smartfridge/proc/accept_check(var/obj/item/O as obj) + if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/grown/) || istype(O,/obj/item/seeds/)) + return 1 + return 0 + +/obj/machinery/smartfridge/seeds + name = "\improper MegaSeed Servitor" + desc = "When you need seeds fast!" + icon = 'icons/obj/vending.dmi' + icon_state = "seeds" + icon_on = "seeds" + icon_off = "seeds-off" + +/obj/machinery/smartfridge/seeds/accept_check(var/obj/item/O as obj) + if(istype(O,/obj/item/seeds/)) + return 1 + return 0 + +/obj/machinery/smartfridge/secure/extract + name = "\improper Slime Extract Storage" + desc = "A refrigerated storage unit for slime extracts." + req_access = list(access_research) + +/obj/machinery/smartfridge/secure/extract/accept_check(var/obj/item/O as obj) + if(istype(O,/obj/item/slime_extract)) + return 1 + return 0 + +/obj/machinery/smartfridge/secure/medbay + name = "\improper Refrigerated Medicine Storage" + desc = "A refrigerated storage unit for storing medicine and chemicals." + icon_state = "smartfridge" //To fix the icon in the map editor. + icon_on = "smartfridge_chem" + req_one_access = list(access_medical,access_chemistry) + +/obj/machinery/smartfridge/secure/medbay/accept_check(var/obj/item/O as obj) + if(istype(O,/obj/item/weapon/reagent_containers/glass/)) + return 1 + if(istype(O,/obj/item/weapon/storage/pill_bottle/)) + return 1 + if(istype(O,/obj/item/weapon/reagent_containers/pill/)) + return 1 + return 0 + +/obj/machinery/smartfridge/secure/virology + name = "\improper Refrigerated Virus Storage" + desc = "A refrigerated storage unit for storing viral material." + req_access = list(access_virology) + icon_state = "smartfridge_virology" + icon_on = "smartfridge_virology" + icon_off = "smartfridge_virology-off" + +/obj/machinery/smartfridge/secure/virology/accept_check(var/obj/item/O as obj) + if(istype(O,/obj/item/weapon/reagent_containers/glass/beaker/vial/)) + return 1 + if(istype(O,/obj/item/weapon/virusdish/)) + return 1 + return 0 + +/obj/machinery/smartfridge/chemistry + name = "\improper Smart Chemical Storage" + desc = "A refrigerated storage unit for medicine and chemical storage." + +/obj/machinery/smartfridge/chemistry/accept_check(var/obj/item/O as obj) + if(istype(O,/obj/item/weapon/storage/pill_bottle) || istype(O,/obj/item/weapon/reagent_containers)) + return 1 + return 0 + +/obj/machinery/smartfridge/chemistry/virology + name = "\improper Smart Virus Storage" + desc = "A refrigerated storage unit for volatile sample storage." + + +/obj/machinery/smartfridge/drinks + name = "\improper Drink Showcase" + desc = "A refrigerated storage unit for tasty tasty alcohol." + +/obj/machinery/smartfridge/drinks/accept_check(var/obj/item/O as obj) + if(istype(O,/obj/item/weapon/reagent_containers/glass) || istype(O,/obj/item/weapon/reagent_containers/food/drinks) || istype(O,/obj/item/weapon/reagent_containers/food/condiment)) + return 1 + +/obj/machinery/smartfridge/drying_rack + name = "\improper Drying Rack" + desc = "A machine for drying plants." + icon_state = "drying_rack" + icon_on = "drying_rack_on" + icon_off = "drying_rack" + +/obj/machinery/smartfridge/drying_rack/accept_check(var/obj/item/O as obj) + if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/)) + var/obj/item/weapon/reagent_containers/food/snacks/S = O + if (S.dried_type) + return 1 + return 0 + +/obj/machinery/smartfridge/drying_rack/Process() + ..() + if(inoperable()) + return + if(contents.len) + dry() + update_icon() + +/obj/machinery/smartfridge/drying_rack/update_icon() + overlays.Cut() + if(inoperable()) + icon_state = icon_off + else + icon_state = icon_on + if(contents.len) + overlays += "drying_rack_filled" + if(!inoperable()) + overlays += "drying_rack_drying" + +/obj/machinery/smartfridge/drying_rack/proc/dry() + for(var/datum/stored_items/I in item_records) + for(var/obj/item/weapon/reagent_containers/food/snacks/S in I.instances) + if(S.dry || !I.get_specific_product(get_turf(src), S)) continue + if(S.dried_type == S.type) + S.dry = 1 + S.SetName("dried [S.name]") + S.color = "#a38463" + stock_item(S) + else + var/D = S.dried_type + new D(get_turf(src)) + qdel(S) + return + +/obj/machinery/smartfridge/Process() + if(stat & (BROKEN|NOPOWER)) + return + if(src.seconds_electrified > 0) + src.seconds_electrified-- + if(src.shoot_inventory && prob(2)) + src.throw_item() + +/obj/machinery/smartfridge/update_icon() + if(stat & (BROKEN|NOPOWER)) + icon_state = icon_off + else + icon_state = icon_on + +/******************* +* Item Adding +********************/ + +/obj/machinery/smartfridge/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(isScrewdriver(O)) + panel_open = !panel_open + user.visible_message("[user] [panel_open ? "opens" : "closes"] the maintenance panel of \the [src].", "You [panel_open ? "open" : "close"] the maintenance panel of \the [src].") + overlays.Cut() + if(panel_open) + overlays += image(icon, icon_panel) + GLOB.nanomanager.update_uis(src) + return + + if(isMultitool(O) || isWirecutter(O)) + if(panel_open) + attack_hand(user) + return + + if(stat & NOPOWER) + to_chat(user, "\The [src] is unpowered and useless.") + return + + if(accept_check(O)) + if(!user.remove_from_mob(O)) + return + stock_item(O) + user.visible_message("\The [user] has added \the [O] to \the [src].", "You add \the [O] to \the [src].") + + else if(istype(O, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/bag/P = O + var/plants_loaded = 0 + for(var/obj/G in P.contents) + if(accept_check(G) && P.remove_from_storage(G, src)) + plants_loaded++ + stock_item(G) + + if(plants_loaded) + user.visible_message("\The [user] loads \the [src] with the contents of \the [P].", "You load \the [src] with the contents of \the [P].") + if(P.contents.len > 0) + to_chat(user, "Some items were refused.") + + else + to_chat(user, "\The [src] smartly refuses [O].") + return 1 + +/obj/machinery/smartfridge/secure/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + emagged = 1 + locked = -1 + to_chat(user, "You short out the product lock on [src].") + return 1 + +/obj/machinery/smartfridge/proc/stock_item(var/obj/item/O) + for(var/datum/stored_items/I in item_records) + if(istype(O, I.item_path) && O.name == I.item_name) + stock(I, O) + return + + var/datum/stored_items/I = new/datum/stored_items(src, O.type, O.name) + dd_insertObjectList(item_records, I) + stock(I, O) + +/obj/machinery/smartfridge/proc/stock(var/datum/stored_items/I, var/obj/item/O) + I.add_product(O) + GLOB.nanomanager.update_uis(src) + +/obj/machinery/smartfridge/attack_ai(mob/user as mob) + attack_hand(user) + +/obj/machinery/smartfridge/attack_hand(mob/user as mob) + if(stat & (NOPOWER|BROKEN)) + return + wires.Interact(user) + ui_interact(user) + +/******************* +* SmartFridge Menu +********************/ + +/obj/machinery/smartfridge/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) + + var/data[0] + data["contents"] = null + data["electrified"] = seconds_electrified > 0 + data["shoot_inventory"] = shoot_inventory + data["locked"] = locked + data["secure"] = is_secure + + var/list/items[0] + for (var/i=1 to length(item_records)) + var/datum/stored_items/I = item_records[i] + var/count = I.get_amount() + if(count > 0) + items.Add(list(list("display_name" = html_encode(capitalize(I.item_name)), "vend" = i, "quantity" = count))) + + if(items.len > 0) + data["contents"] = items + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "smartfridge.tmpl", src.name, 400, 500) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/smartfridge/Topic(href, href_list) + if(..()) return 0 + + var/mob/user = usr + var/datum/nanoui/ui = GLOB.nanomanager.get_open_ui(user, src, "main") + + if(href_list["close"]) + user.unset_machine() + ui.close() + return 0 + + if(href_list["vend"]) + var/index = text2num(href_list["vend"]) + var/amount = text2num(href_list["amount"]) + var/datum/stored_items/I = item_records[index] + var/count = I.get_amount() + + // Sanity check, there are probably ways to press the button when it shouldn't be possible. + if(count > 0) + if((count - amount) < 0) + amount = count + for(var/i = 1 to amount) + I.get_product(get_turf(src)) + + return 1 + return 0 + +/obj/machinery/smartfridge/proc/throw_item() + var/obj/throw_item = null + var/mob/living/target = locate() in view(7,src) + if(!target) + return 0 + + for(var/datum/stored_items/I in src.item_records) + throw_item = I.get_product(loc) + if (!throw_item) + continue + break + + if(!throw_item) + return 0 + spawn(0) + throw_item.throw_at(target,16,3,src) + src.visible_message("[src] launches [throw_item.name] at [target.name]!") + return 1 + +/************************ +* Secure SmartFridges +*************************/ + +/obj/machinery/smartfridge/secure/Topic(href, href_list) + if(stat & (NOPOWER|BROKEN)) return 0 + if(usr.contents.Find(src) || (in_range(src, usr) && istype(loc, /turf))) + if(!allowed(usr) && !emagged && locked != -1 && href_list["vend"]) + to_chat(usr, "Access denied.") + return 0 + return ..() diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm new file mode 100644 index 00000000..35ef0ebf --- /dev/null +++ b/code/game/machinery/lightswitch.dm @@ -0,0 +1,81 @@ +// the light switch +// can have multiple per area +// can also operate on non-loc area through "otherarea" var +/obj/machinery/light_switch + name = "light switch" + desc = "It turns lights on and off. What are you, simple?" + icon = 'icons/obj/power.dmi' + icon_state = "light0" + anchored = 1.0 + use_power = 1 + idle_power_usage = 20 + power_channel = LIGHT + var/on = 0 + var/area/connected_area = null + var/other_area = null + var/image/overlay + +/obj/machinery/light_switch/Initialize() + . = ..() + if(other_area) + src.connected_area = locate(other_area) + else + src.connected_area = get_area(src) + + if(name == initial(name)) + SetName("light switch ([connected_area.name])") + + connected_area.set_lightswitch(on) + update_icon() + +/obj/machinery/light_switch/update_icon() + if(!overlay) + overlay = image(icon, "light1-overlay") + overlay.plane = EFFECTS_ABOVE_LIGHTING_PLANE + overlay.layer = ABOVE_LIGHTING_LAYER + + overlays.Cut() + if(stat & (NOPOWER|BROKEN)) + icon_state = "light-p" + set_light(0) + else + icon_state = "light[on]" + overlay.icon_state = "light[on]-overlay" + overlays += overlay + set_light(2, 0.3, on ? "#82ff4c" : "#f86060") + +/obj/machinery/light_switch/examine(mob/user) + if(..(user, 1)) + to_chat(user, "A light switch. It is [on? "on" : "off"].") + +/obj/machinery/light_switch/proc/set_state(var/newstate) + if(on != newstate) + on = newstate + connected_area.set_lightswitch(on) + update_icon() + +/obj/machinery/light_switch/proc/sync_state() + if(connected_area && on != connected_area.lightswitch) + on = connected_area.lightswitch + update_icon() + return 1 + +/obj/machinery/light_switch/attack_hand(mob/user) + playsound(src, "switch", 30) + set_state(!on) + +/obj/machinery/light_switch/powered() + . = ..(power_channel, connected_area) //tie our powered status to the connected area + +/obj/machinery/light_switch/power_change() + . = ..() + //synch ourselves to the new state + if(connected_area) //If an APC initializes before we do it will force a power_change() before we can get our connected area + sync_state() + +/obj/machinery/light_switch/emp_act(severity) + if(stat & (BROKEN|NOPOWER)) + ..(severity) + return + power_change() + ..(severity) diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm new file mode 100644 index 00000000..85d235e2 --- /dev/null +++ b/code/game/machinery/machinery.dm @@ -0,0 +1,355 @@ +/* +Overview: + Used to create objects that need a per step proc call. Default definition of 'New()' + stores a reference to src machine in global 'machines list'. Default definition + of 'Destroy' removes reference to src machine in global 'machines list'. + +Class Variables: + use_power (num) + current state of auto power use. + Possible Values: + 0 -- no auto power use + 1 -- machine is using power at its idle power level + 2 -- machine is using power at its active power level + + active_power_usage (num) + Value for the amount of power to use when in active power mode + + idle_power_usage (num) + Value for the amount of power to use when in idle power mode + + power_channel (num) + What channel to draw from when drawing power for power mode + Possible Values: + EQUIP:0 -- Equipment Channel + LIGHT:2 -- Lighting Channel + ENVIRON:3 -- Environment Channel + + component_parts (list) + A list of component parts of machine used by frame based machines. + + panel_open (num) + Whether the panel is open + + uid (num) + Unique id of machine across all machines. + + gl_uid (global num) + Next uid value in sequence + + stat (bitflag) + Machine status bit flags. + Possible bit flags: + BROKEN:1 -- Machine is broken + NOPOWER:2 -- No power is being supplied to machine. + POWEROFF:4 -- tbd + MAINT:8 -- machine is currently under going maintenance. + EMPED:16 -- temporary broken by EMP pulse + +Class Procs: + New() 'game/machinery/machine.dm' + + Destroy() 'game/machinery/machine.dm' + + auto_use_power() 'game/machinery/machine.dm' + This proc determines how power mode power is deducted by the machine. + 'auto_use_power()' is called by the 'master_controller' game_controller every + tick. + + Return Value: + return:1 -- if object is powered + return:0 -- if object is not powered. + + Default definition uses 'use_power', 'power_channel', 'active_power_usage', + 'idle_power_usage', 'powered()', and 'use_power()' implement behavior. + + powered(chan = EQUIP) 'modules/power/power.dm' + Checks to see if area that contains the object has power available for power + channel given in 'chan'. + + use_power(amount, chan=EQUIP, autocalled) 'modules/power/power.dm' + Deducts 'amount' from the power channel 'chan' of the area that contains the object. + If it's autocalled then everything is normal, if something else calls use_power we are going to + need to recalculate the power two ticks in a row. + + power_change() 'modules/power/power.dm' + Called by the area that contains the object when ever that area under goes a + power state change (area runs out of power, or area channel is turned off). + + RefreshParts() 'game/machinery/machine.dm' + Called to refresh the variables in the machine that are contributed to by parts + contained in the component_parts list. (example: glass and material amounts for + the autolathe) + + Default definition does nothing. + + assign_uid() 'game/machinery/machine.dm' + Called by machine to assign a value to the uid variable. + + process() 'game/machinery/machine.dm' + Called by the 'master_controller' once per game tick for each machine that is listed in the 'machines' list. + + + Compiled by Aygar +*/ + +/obj/machinery + name = "machinery" + icon = 'icons/obj/stationobjs.dmi' + w_class = ITEM_SIZE_NO_CONTAINER + + var/stat = 0 + var/emagged = 0 + var/malf_upgraded = 0 + var/use_power = 1 + //0 = dont run the auto + //1 = run auto, use idle + //2 = run auto, use active + var/idle_power_usage = 0 + var/active_power_usage = 0 + var/power_channel = EQUIP //EQUIP, ENVIRON or LIGHT + var/list/component_parts = null //list of all the parts used to build it, if made from certain kinds of frames. + var/uid + var/panel_open = 0 + var/global/gl_uid = 1 + var/interact_offline = 0 // Can the machine be interacted with while de-powered. + var/clicksound // sound played on succesful interface use by a carbon lifeform + var/clickvol = 40 // sound played on succesful interface use + +/obj/machinery/Initialize(mapload, d=0) + . = ..() + if(d) + set_dir(d) + START_PROCESSING(SSmachines, src) + +/obj/machinery/Destroy() + STOP_PROCESSING(SSmachines, src) + if(component_parts) + for(var/atom/A in component_parts) + if(A.loc == src) // If the components are inside the machine, delete them. + qdel(A) + else // Otherwise we assume they were dropped to the ground during deconstruction, and were not removed from the component_parts list by deconstruction code. + component_parts -= A + . = ..() + +/obj/machinery/Process()//If you dont use process or power why are you here + if(!(use_power || idle_power_usage || active_power_usage)) + return PROCESS_KILL + +/obj/machinery/emp_act(severity) + if(use_power && stat == 0) + use_power(7500/severity) + + var/obj/effect/overlay/pulse2 = new /obj/effect/overlay(loc) + pulse2.icon = 'icons/effects/effects.dmi' + pulse2.icon_state = "empdisable" + pulse2.SetName("emp sparks") + pulse2.anchored = 1 + pulse2.set_dir(pick(GLOB.cardinal)) + + spawn(10) + qdel(pulse2) + ..() + +/obj/machinery/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + if (prob(50)) + qdel(src) + return + if(3.0) + if (prob(25)) + qdel(src) + return + else + return + +//sets the use_power var and then forces an area power update +/obj/machinery/proc/update_use_power(var/new_use_power) + use_power = new_use_power + +/obj/machinery/proc/auto_use_power() + if(!powered(power_channel)) + return 0 + if(src.use_power == 1) + use_power(idle_power_usage,power_channel, 1) + else if(src.use_power >= 2) + use_power(active_power_usage,power_channel, 1) + return 1 + +/proc/is_operable(var/obj/machinery/M, var/mob/user) + return istype(M) && M.operable() + +/obj/machinery/proc/operable(var/additional_flags = 0) + return !inoperable(additional_flags) + +/obj/machinery/proc/inoperable(var/additional_flags = 0) + return (stat & (NOPOWER|BROKEN|additional_flags)) + +/obj/machinery/CanUseTopic(var/mob/user) + if(stat & BROKEN) + return STATUS_CLOSE + + if(!interact_offline && (stat & NOPOWER)) + return STATUS_CLOSE + + return ..() + +/obj/machinery/CouldUseTopic(var/mob/user) + ..() + user.set_machine(src) + +/obj/machinery/CouldNotUseTopic(var/mob/user) + user.unset_machine() + +//////////////////////////////////////////////////////////////////////////////////////////// + +/obj/machinery/attack_ai(mob/user as mob) + if(isrobot(user)) + // For some reason attack_robot doesn't work + // This is to stop robots from using cameras to remotely control machines. + if(user.client && user.client.eye == user) + return src.attack_hand(user) + else + return src.attack_hand(user) + +/obj/machinery/attack_hand(mob/user as mob) + if(inoperable(MAINT)) + return 1 + if(user.lying || user.stat) + return 1 + if ( ! (istype(usr, /mob/living/carbon/human) || \ + istype(usr, /mob/living/silicon))) + to_chat(usr, "You don't have the dexterity to do this!") + return 1 +/* + //distance checks are made by atom/proc/DblClick + if ((get_dist(src, user) > 1 || !istype(src.loc, /turf)) && !istype(user, /mob/living/silicon)) + return 1 +*/ + if (ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.getBrainLoss() >= 55) + visible_message("[H] stares cluelessly at \the [src].") + return 1 + else if(prob(H.getBrainLoss())) + to_chat(user, "You momentarily forget how to use \the [src].") + return 1 + + return ..() + +/obj/machinery/proc/RefreshParts() //Placeholder proc for machines that are built using frames. + return + +/obj/machinery/proc/assign_uid() + uid = gl_uid + gl_uid++ + +/obj/machinery/proc/state(var/msg) + for(var/mob/O in hearers(src, null)) + O.show_message("\icon[src] [msg]", 2) + +/obj/machinery/proc/ping(text=null) + if (!text) + text = "\The [src] pings." + + state(text, "blue") + playsound(src.loc, 'sound/machines/ping.ogg', 50, 0) + +/obj/machinery/proc/shock(mob/user, prb) + if(inoperable()) + return 0 + if(!prob(prb)) + return 0 + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, src) + s.start() + if(electrocute_mob(user, get_area(src), src, 0.7)) + var/area/temp_area = get_area(src) + if(temp_area) + var/obj/machinery/power/apc/temp_apc = temp_area.get_apc() + + if(temp_apc && temp_apc.terminal && temp_apc.terminal.powernet) + temp_apc.terminal.powernet.trigger_warning() + if(user.stunned) + return 1 + return 0 + +/obj/machinery/proc/default_deconstruction_crowbar(var/mob/user, var/obj/item/weapon/crowbar/C) + if(!istype(C)) + return 0 + if(!panel_open) + return 0 + . = dismantle() + +/obj/machinery/proc/default_deconstruction_screwdriver(var/mob/user, var/obj/item/weapon/screwdriver/S) + if(!istype(S)) + return 0 + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + panel_open = !panel_open + to_chat(user, "You [panel_open ? "open" : "close"] the maintenance hatch of \the [src].") + update_icon() + return 1 + +/obj/machinery/proc/default_part_replacement(var/mob/user, var/obj/item/weapon/storage/part_replacer/R) + if(!istype(R)) + return 0 + if(!component_parts) + return 0 + if(panel_open) + var/obj/item/weapon/circuitboard/CB = locate(/obj/item/weapon/circuitboard) in component_parts + var/P + for(var/obj/item/weapon/stock_parts/A in component_parts) + for(var/T in CB.req_components) + if(ispath(A.type, T)) + P = T + break + for(var/obj/item/weapon/stock_parts/B in R.contents) + if(istype(B, P) && istype(A, P)) + if(B.rating > A.rating) + R.remove_from_storage(B, src) + R.handle_item_insertion(A, 1) + component_parts -= A + component_parts += B + B.loc = null + to_chat(user, "[A.name] replaced with [B.name].") + break + update_icon() + RefreshParts() + else + to_chat(user, "Following parts detected in the machine:") + for(var/var/obj/item/C in component_parts) + to_chat(user, " [C.name]") + return 1 + +/obj/machinery/proc/dismantle() + playsound(loc, 'sound/items/Crowbar.ogg', 50, 1) + var/obj/machinery/constructable_frame/machine_frame/M = new /obj/machinery/constructable_frame/machine_frame(get_turf(src)) + M.set_dir(src.dir) + M.state = 2 + M.icon_state = "box_1" + for(var/obj/I in component_parts) + I.forceMove(get_turf(src)) + + qdel(src) + return 1 + +/obj/machinery/InsertedContents() + return (contents - component_parts) + +/datum/proc/apply_visual(mob/M) + return + +/datum/proc/remove_visual(mob/M) + return + +/obj/machinery/proc/malf_upgrade(var/mob/living/silicon/ai/user) + return 0 + +/obj/machinery/CouldUseTopic(var/mob/user) + ..() + if(clicksound && istype(user, /mob/living/carbon)) + playsound(src, clicksound, clickvol) diff --git a/code/game/machinery/magnet.dm b/code/game/machinery/magnet.dm new file mode 100644 index 00000000..94c6124a --- /dev/null +++ b/code/game/machinery/magnet.dm @@ -0,0 +1,409 @@ +// Magnetic attractor, creates variable magnetic fields and attraction. +// Can also be used to emit electron/proton beams to create a center of magnetism on another tile + +// tl;dr: it's magnets lol +// This was created for firing ranges, but I suppose this could have other applications - Doohl + +/obj/machinery/magnetic_module + + icon = 'icons/obj/objects.dmi' + icon_state = "floor_magnet-f" + name = "Electromagnetic Generator" + desc = "A device that uses powernet to create points of magnetic energy." + level = 1 // underfloor + plane = ABOVE_PLATING_PLANE + layer = ABOVE_WIRE_LAYER + anchored = 1 + use_power = 1 + idle_power_usage = 50 + + var/freq = 1449 // radio frequency + var/electricity_level = 1 // intensity of the magnetic pull + var/magnetic_field = 1 // the range of magnetic attraction + var/code = 0 // frequency code, they should be different unless you have a group of magnets working together or something + var/turf/center // the center of magnetic attraction + var/on = 0 + var/pulling = 0 + + // x, y modifiers to the center turf; (0, 0) is centered on the magnet, whereas (1, -1) is one tile right, one tile down + var/center_x = 0 + var/center_y = 0 + var/max_dist = 20 // absolute value of center_x,y cannot exceed this integer + + New() + ..() + var/turf/T = loc + hide(!T.is_plating()) + center = T + + spawn(10) // must wait for map loading to finish + if(radio_controller) + radio_controller.add_object(src, freq, RADIO_MAGNETS) + + spawn() + magnetic_process() + + // update the invisibility and icon + hide(var/intact) + set_invisibility(intact ? 101 : 0) + update_icon() + + // update the icon_state + update_icon() + var/state="floor_magnet" + var/onstate="" + if(!on) + onstate="0" + + if(invisibility) + icon_state = "[state][onstate]-f" // if invisible, set icon to faded version + // in case of being revealed by T-scanner + else + icon_state = "[state][onstate]" + + receive_signal(datum/signal/signal) + + var/command = signal.data["command"] + var/modifier = signal.data["modifier"] + var/signal_code = signal.data["code"] + if(command && (signal_code == code)) + + Cmd(command, modifier) + + + + proc/Cmd(var/command, var/modifier) + + if(command) + switch(command) + if("set-electriclevel") + if(modifier) electricity_level = modifier + if("set-magneticfield") + if(modifier) magnetic_field = modifier + + if("add-elec") + electricity_level++ + if(electricity_level > 12) + electricity_level = 12 + if("sub-elec") + electricity_level-- + if(electricity_level <= 0) + electricity_level = 1 + if("add-mag") + magnetic_field++ + if(magnetic_field > 4) + magnetic_field = 4 + if("sub-mag") + magnetic_field-- + if(magnetic_field <= 0) + magnetic_field = 1 + + if("set-x") + if(modifier) center_x = modifier + if("set-y") + if(modifier) center_y = modifier + + if("N") // NORTH + center_y++ + if("S") // SOUTH + center_y-- + if("E") // EAST + center_x++ + if("W") // WEST + center_x-- + if("C") // CENTER + center_x = 0 + center_y = 0 + if("R") // RANDOM + center_x = rand(-max_dist, max_dist) + center_y = rand(-max_dist, max_dist) + + if("set-code") + if(modifier) code = modifier + if("toggle-power") + on = !on + + if(on) + spawn() + magnetic_process() + + + + Process() + if(stat & NOPOWER) + on = 0 + + // Sanity checks: + if(electricity_level <= 0) + electricity_level = 1 + if(magnetic_field <= 0) + magnetic_field = 1 + + + // Limitations: + if(abs(center_x) > max_dist) + center_x = max_dist + if(abs(center_y) > max_dist) + center_y = max_dist + if(magnetic_field > 4) + magnetic_field = 4 + if(electricity_level > 12) + electricity_level = 12 + + // Update power usage: + if(on) + use_power = 2 + active_power_usage = electricity_level*15 + else + use_power = 0 + + + // Overload conditions: + /* // Eeeehhh kinda stupid + if(on) + if(electricity_level > 11) + if(prob(electricity_level)) + explosion(loc, 0, 1, 2, 3) // ooo dat shit EXPLODES son + spawn(2) + qdel(src) + */ + + update_icon() + + + proc/magnetic_process() // proc that actually does the pulling + if(pulling) return + while(on) + + pulling = 1 + center = locate(x+center_x, y+center_y, z) + if(center) + for(var/obj/M in orange(magnetic_field, center)) + if(!M.anchored && (M.obj_flags & OBJ_FLAG_CONDUCTIBLE)) + step_towards(M, center) + + for(var/mob/living/silicon/S in orange(magnetic_field, center)) + if(istype(S, /mob/living/silicon/ai)) continue + step_towards(S, center) + + use_power(electricity_level * 5) + sleep(13 - electricity_level) + + pulling = 0 + +/obj/machinery/magnetic_module/Destroy() + if(radio_controller) + radio_controller.remove_object(src, freq) + ..() + +/obj/machinery/magnetic_controller + name = "Magnetic Control Console" + icon = 'icons/obj/airlock_machines.dmi' // uses an airlock machine icon, THINK GREEN HELP THE ENVIRONMENT - RECYCLING! + icon_state = "airlock_control_standby" + density = 1 + anchored = 1.0 + use_power = 1 + idle_power_usage = 45 + var/frequency = 1449 + var/code = 0 + var/list/magnets = list() + var/title = "Magnetic Control Console" + var/autolink = 0 // if set to 1, can't probe for other magnets! + + var/pathpos = 1 // position in the path + var/path = "NULL" // text path of the magnet + var/speed = 1 // lowest = 1, highest = 10 + var/list/rpath = list() // real path of the magnet, used in iterator + + var/moving = 0 // 1 if scheduled to loop + var/looping = 0 // 1 if looping + + var/datum/radio_frequency/radio_connection + + + New() + ..() + + if(autolink) + for(var/obj/machinery/magnetic_module/M in world) + if(M.freq == frequency && M.code == code) + magnets.Add(M) + + + spawn(45) // must wait for map loading to finish + if(radio_controller) + radio_connection = radio_controller.add_object(src, frequency, RADIO_MAGNETS) + + + if(path) // check for default path + filter_path() // renders rpath + + + Process() + if(magnets.len == 0 && autolink) + for(var/obj/machinery/magnetic_module/M in world) + if(M.freq == frequency && M.code == code) + magnets.Add(M) + + + attack_ai(mob/user as mob) + return src.attack_hand(user) + + attack_hand(mob/user as mob) + if(stat & (BROKEN|NOPOWER)) + return + user.set_machine(src) + var/dat = "Magnetic Control Console

    " + if(!autolink) + dat += {" + Frequency:
    [frequency]
    + Code: [code]
    + Probe Generators
    + "} + + if(magnets.len >= 1) + + dat += "Magnets confirmed:
    " + var/i = 0 + for(var/obj/machinery/magnetic_module/M in magnets) + i++ + dat += "     < \[[i]\] ([M.on ? "On":"Off"]) | Electricity level: - [M.electricity_level] +; Magnetic field: - [M.magnetic_field] +
    " + + dat += "
    Speed: - [speed] +
    " + dat += "Path: {[path]}
    " + dat += "Moving: [moving ? "Enabled":"Disabled"]" + + + user << browse(dat, "window=magnet;size=400x500") + onclose(user, "magnet") + + Topic(href, href_list) + if(..()) + return 1 + if(stat & (BROKEN|NOPOWER)) + return + usr.set_machine(src) + + if(href_list["radio-op"]) + + // Prepare signal beforehand, because this is a radio operation + var/datum/signal/signal = new + signal.transmission_method = 1 // radio transmission + signal.source = src + signal.frequency = frequency + signal.data["code"] = code + + // Apply any necessary commands + switch(href_list["radio-op"]) + if("togglepower") + signal.data["command"] = "toggle-power" + + if("minuselec") + signal.data["command"] = "sub-elec" + if("pluselec") + signal.data["command"] = "add-elec" + + if("minusmag") + signal.data["command"] = "sub-mag" + if("plusmag") + signal.data["command"] = "add-mag" + + + // Broadcast the signal + + radio_connection.post_signal(src, signal, filter = RADIO_MAGNETS) + + spawn(1) + updateUsrDialog() // pretty sure this increases responsiveness + + if(href_list["operation"]) + switch(href_list["operation"]) + if("plusspeed") + speed ++ + if(speed > 10) + speed = 10 + if("minusspeed") + speed -- + if(speed <= 0) + speed = 1 + if("setpath") + var/newpath = sanitize(input(usr, "Please define a new path!",,path) as text|null) + if(newpath && newpath != "") + moving = 0 // stop moving + path = newpath + pathpos = 1 // reset position + filter_path() // renders rpath + + if("togglemoving") + moving = !moving + if(moving) + spawn() MagnetMove() + + + updateUsrDialog() + + proc/MagnetMove() + if(looping) return + + while(moving && rpath.len >= 1) + + if(stat & (BROKEN|NOPOWER)) + break + + looping = 1 + + // Prepare the radio signal + var/datum/signal/signal = new + signal.transmission_method = 1 // radio transmission + signal.source = src + signal.frequency = frequency + signal.data["code"] = code + + if(pathpos > rpath.len) // if the position is greater than the length, we just loop through the list! + pathpos = 1 + + var/nextmove = uppertext(rpath[pathpos]) // makes it un-case-sensitive + + if(!(nextmove in list("N","S","E","W","C","R"))) + // N, S, E, W are directional + // C is center + // R is random (in magnetic field's bounds) + qdel(signal) + break // break the loop if the character located is invalid + + signal.data["command"] = nextmove + + + pathpos++ // increase iterator + + // Broadcast the signal + spawn() + radio_connection.post_signal(src, signal, filter = RADIO_MAGNETS) + + if(speed == 10) + sleep(1) + else + sleep(12-speed) + + looping = 0 + + + proc/filter_path() + // Generates the rpath variable using the path string, think of this as "string2list" + // Doesn't use params2list() because of the akward way it stacks entities + rpath = list() // clear rpath + var/maximum_character = min( 50, length(path) ) // chooses the maximum length of the iterator. 50 max length + + for(var/i=1, i<=maximum_character, i++) // iterates through all characters in path + + var/nextchar = copytext(path, i, i+1) // find next character + + if(!(nextchar in list(";", "&", "*", " "))) // if char is a separator, ignore + rpath += copytext(path, i, i+1) // else, add to list + + // there doesn't HAVE to be separators but it makes paths syntatically visible + +/obj/machinery/magnetic_controller/Destroy() + if(radio_controller) + radio_controller.remove_object(src, frequency) + ..() diff --git a/code/game/machinery/mass_driver.dm b/code/game/machinery/mass_driver.dm new file mode 100644 index 00000000..60f3aed5 --- /dev/null +++ b/code/game/machinery/mass_driver.dm @@ -0,0 +1,53 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/obj/machinery/mass_driver + name = "mass driver" + desc = "Shoots things into space." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "mass_driver" + anchored = 1.0 + use_power = 1 + idle_power_usage = 2 + active_power_usage = 50 + + var/power = 1.0 + var/code = 1.0 + var/id = 1.0 + var/drive_range = 50 //this is mostly irrelevant since current mass drivers throw into space, but you could make a lower-range mass driver for interstation transport or something I guess. + var/_wifi_id + var/datum/wifi/receiver/button/mass_driver/wifi_receiver + +/obj/machinery/mass_driver/Initialize() + . = ..() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + +/obj/machinery/mass_driver/Destroy() + qdel(wifi_receiver) + wifi_receiver = null + return ..() + +/obj/machinery/mass_driver/proc/drive(amount) + if(stat & (BROKEN|NOPOWER)) + return + use_power(500) + var/O_limit + var/atom/target = get_edge_target_turf(src, dir) + for(var/atom/movable/O in loc) + if(!O.anchored||istype(O, /obj/mecha))//Mechs need their launch platforms. + O_limit++ + if(O_limit >= 20) + for(var/mob/M in hearers(src, null)) + to_chat(M, "The mass driver lets out a screech, it mustn't be able to handle any more items.") + break + use_power(500) + spawn( 0 ) + O.throw_at(target, drive_range * power, power) + flick("mass_driver1", src) + return + +/obj/machinery/mass_driver/emp_act(severity) + if(stat & (BROKEN|NOPOWER)) + return + drive() + ..(severity) diff --git a/code/game/machinery/navbeacon.dm b/code/game/machinery/navbeacon.dm new file mode 100644 index 00000000..93098cb3 --- /dev/null +++ b/code/game/machinery/navbeacon.dm @@ -0,0 +1,379 @@ +var/global/list/navbeacons = list() + +/obj/machinery/navbeacon + icon = 'icons/obj/objects.dmi' + icon_state = "navbeacon0-f" + name = "navigation beacon" + desc = "A radio beacon used for bot navigation." + level = 1 + plane = ABOVE_PLATING_PLANE + layer = ABOVE_WIRE_LAYER + anchored = 1 + + var/open = 0 // true if cover is open + var/locked = 1 // true if controls are locked + var/location = "" // location response text + var/list/codes = list() // assoc. list of transponder codes + + req_access = list(access_engine) + +/obj/machinery/navbeacon/New() + ..() + + var/turf/T = loc + hide(!T.is_plating()) + + navbeacons += src + +/obj/machinery/navbeacon/hide(var/intact) + set_invisibility(intact ? 101 : 0) + update_icon() + +/obj/machinery/navbeacon/update_icon() + var/state="navbeacon[open]" + + if(invisibility) + icon_state = "[state]-f" // if invisible, set icon to faded version + // in case revealed by T-scanner + else + icon_state = "[state]" + +/obj/machinery/navbeacon/attackby(var/obj/item/I, var/mob/user) + var/turf/T = loc + if(!T.is_plating()) + return // prevent intraction when T-scanner revealed + + if(isScrewdriver(I)) + open = !open + + user.visible_message("\The [user] [open ? "opens" : "closes"] cover of \the [src].", "You [open ? "open" : "close"] cover of \the [src].") + + update_icon() + + else if(I.GetIdCard()) + if(open) + if (src.allowed(user)) + src.locked = !src.locked + to_chat(user, "Controls are now [src.locked ? "locked." : "unlocked."]") + else + to_chat(user, "Access denied.") + updateDialog() + else + to_chat(user, "You must open the cover first!") + return + +/obj/machinery/navbeacon/attack_ai(var/mob/user) + interact(user, 1) + +/obj/machinery/navbeacon/attack_hand(var/mob/user) + + if(!user.IsAdvancedToolUser()) + return 0 + + interact(user, 0) + +/obj/machinery/navbeacon/interact(var/mob/user, var/ai = 0) + var/turf/T = loc + if(!T.is_plating()) + return // prevent intraction when T-scanner revealed + + if(!open && !ai) // can't alter controls if not open, unless you're an AI + to_chat(user, "The beacon's control cover is closed.") + return + + var/t + + if(locked && !ai) + t = {"Navigation Beacon

    +(swipe card to unlock controls)

    +Location: [location ? location : "(none)"]
    +Transponder Codes:
      "} + + for(var/key in codes) + t += "
    • [key] ... [codes[key]]" + t+= "
        " + + else + + t = {"Navigation Beacon

        +(swipe card to lock controls)

        +Location: [location ? location : "(none)"]
        +Transponder Codes:
          "} + + for(var/key in codes) + t += "
        • [key] ... [codes[key]]" + t += " (edit)" + t += " (delete)
          " + t += "(add new)
          " + t+= "
            " + + user << browse(t, "window=navbeacon") + onclose(user, "navbeacon") + return + +/obj/machinery/navbeacon/Topic(href, href_list) + ..() + if (usr.stat) + return + if ((in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon))) + if(open && !locked) + usr.set_machine(src) + + if(href_list["locedit"]) + var/newloc = sanitize(input("Enter New Location", "Navigation Beacon", location) as text|null) + if(newloc) + location = newloc + updateDialog() + + else if(href_list["edit"]) + var/codekey = href_list["code"] + + var/newkey = input("Enter Transponder Code Key", "Navigation Beacon", codekey) as text|null + if(!newkey) + return + + var/codeval = codes[codekey] + var/newval = input("Enter Transponder Code Value", "Navigation Beacon", codeval) as text|null + if(!newval) + newval = codekey + return + + codes.Remove(codekey) + codes[newkey] = newval + + updateDialog() + + else if(href_list["delete"]) + var/codekey = href_list["code"] + codes.Remove(codekey) + updateDialog() + + else if(href_list["add"]) + + var/newkey = input("Enter New Transponder Code Key", "Navigation Beacon") as text|null + if(!newkey) + return + + var/newval = input("Enter New Transponder Code Value", "Navigation Beacon") as text|null + if(!newval) + newval = "1" + return + + if(!codes) + codes = new() + + codes[newkey] = newval + + updateDialog() + +/obj/machinery/navbeacon/Destroy() + navbeacons.Remove(src) + ..() + +// Patrol beacon types below. So many. + +/obj/machinery/navbeacon/Security + location = "Security" + codes = list("patrol" = 1, "next_patrol" = "EVA") + +/obj/machinery/navbeacon/EVA + location = "EVA" + codes = list("patrol" = 1, "next_patrol" = "Lockers") + +/obj/machinery/navbeacon/Lockers + location = "Lockers" + codes = list("patrol" = 1, "next_patrol" = "CHW") + +/obj/machinery/navbeacon/CHW + location = "CHW" + codes = list("patrol" = 1, "next_patrol" = "QM") + +/obj/machinery/navbeacon/QM + location = "QM" + codes = list("patrol" = 1, "next_patrol" = "AIW") + +/obj/machinery/navbeacon/AIW + location = "AIW" + codes = list("patrol" = 1, "next_patrol" = "AftH") + +/obj/machinery/navbeacon/AftH + location = "AftH" + codes = list("patrol" = 1, "next_patrol" = "AIE") + +/obj/machinery/navbeacon/AIE + location = "AIE" + codes = list("patrol" = 1, "next_patrol" = "CHE") + +/obj/machinery/navbeacon/CHE + location = "CHE" + codes = list("patrol" = 1, "next_patrol" = "HOP") + +/obj/machinery/navbeacon/HOP + location = "HOP" + codes = list("patrol" = 1, "next_patrol" = "Stbd") + +/obj/machinery/navbeacon/Stbd + location = "Stbd" + codes = list("patrol" = 1, "next_patrol" = "HOP2") + +/obj/machinery/navbeacon/HOP2 + location = "HOP2" + codes = list("patrol" = 1, "next_patrol" = "Dorm") + +/obj/machinery/navbeacon/Dorm + location = "Dorm" + codes = list("patrol" = 1, "next_patrol" = "EVA2") + +/obj/machinery/navbeacon/EVA2 + location = "EVA2" + codes = list("patrol" = 1, "next_patrol" = "Security") // And the cycle is finished + +// Delivery types below. + +/obj/machinery/navbeacon/QM1 + location = "QM #1" + codes = list("delivery" = 1, "dir" = 8) + +/obj/machinery/navbeacon/QM2 + location = "QM #2" + codes = list("delivery" = 1, "dir" = 8) + +/obj/machinery/navbeacon/QM3 + location = "QM #3" + codes = list("delivery" = 1, "dir" = 8) + +/obj/machinery/navbeacon/QM4 + location = "QM #4" + codes = list("delivery" = 1, "dir" = 8) + +/obj/machinery/navbeacon/Research + location = "Research Division" + codes = list("delivery" = 1, "dir" = 8) + +/obj/machinery/navbeacon/Janitor + location = "Janitor" + codes = list("delivery" = 1, "dir" = 8) + +/obj/machinery/navbeacon/SecurityD + location = "Security" + codes = list("delivery" = 1, "dir" = 8) + +/obj/machinery/navbeacon/ToolStorage + location = "Tool Storage" + codes = list("delivery" = 1, "dir" = 8) + +/obj/machinery/navbeacon/Medbay + location = "Medbay" + codes = list("delivery" = 1, "dir" = 4) + +/obj/machinery/navbeacon/Engineering + location = "Engineering" + codes = list("delivery" = 1, "dir" = 4) + +/obj/machinery/navbeacon/Bar + location = "Bar" + codes = list("delivery" = 1, "dir" = 2) + +/obj/machinery/navbeacon/Kitchen + location = "Kitchen" + codes = list("delivery" = 1, "dir" = 2) + +/obj/machinery/navbeacon/Hydroponics + location = "Hydroponics" + codes = list("delivery" = 1, "dir" = 2) + +// Torch types below + +/obj/machinery/navbeacon/torch/bridge1 + location = "bridge1" + codes = list("patrol" = 1, "next_patrol" = "bridge2") + +/obj/machinery/navbeacon/torch/FDforehallway3 + location = "FDforehallway3" + codes = list("patrol" = 1, "next_patrol" = "FDforehallway4") + +/obj/machinery/navbeacon/torch/FDforehallway4 + location = "FDforehallway4" + codes = list("patrol" = 1, "next_patrol" = "FDelevator2") + +/obj/machinery/navbeacon/torch/FDelevator2 + location = "FDelevator2" + codes = list("patrol" = 1, "next_patrol" = "Supply") + +/obj/machinery/navbeacon/torch/Supply + location = "Supply" + codes = list("patrol" = 1, "next_patrol" = "FDelevator") + +/obj/machinery/navbeacon/torch/FDelevator + location = "FDelevator" + codes = list("patrol" = 1, "next_patrol" = "FDforehallway1") + +/obj/machinery/navbeacon/torch/FDforehallway1 + location = "FDforehallway1" + codes = list("patrol" = 1, "next_patrol" = "FDforehallway2") + +/obj/machinery/navbeacon/torch/telecomms + location = "telecomms" + codes = list("patrol" = 1, "next_patrol" = "briefingroom2") + +/obj/machinery/navbeacon/torch/aiupload2 + location = "aiupload2" + codes = list("patrol" = 1, "next_patrol" = "brig") + +/obj/machinery/navbeacon/torch/brig + location = "brig" + codes = list("patrol" = 1, "next_patrol" = "aiupload") + +/obj/machinery/navbeacon/torch/aiupload + location = "aiupload" + codes = list("patrol" = 1, "next_patrol" = "forehallway") + +/obj/machinery/navbeacon/torch/briefingroom2 + location = "briefingroom2" + codes = list("patrol" = 1, "next_patrol" = "forehallway2") + +/obj/machinery/navbeacon/torch/forehallway2 + location = "forehallway2" + codes = list("patrol" = 1, "next_patrol" = "aiupload2") + +/obj/machinery/navbeacon/torch/briefingroom + location = "briefingroom" + codes = list("patrol" = 1, "next_patrol" = "telecomms") + +/obj/machinery/navbeacon/torch/forehallway + location = "forehallway" + codes = list("patrol" = 1, "next_patrol" = "briefingroom") + +/obj/machinery/navbeacon/torch/bridge1 + location = "bridge1" + codes = list("patrol" = 1, "next_patrol" = "bridge2") + +/obj/machinery/navbeacon/torch/bridge2 + location = "bridge2" + codes = list("patrol" = 1, "next_patrol" = "rdoffice") + +/obj/machinery/navbeacon/torch/vault2 + location = "vault2" + codes = list("patrol" = 1, "next_patrol" = "medical") + +/obj/machinery/navbeacon/torch/vault1 + location = "vault1" + codes = list("patrol" = 1, "next_patrol" = "xooffice") + +/obj/machinery/navbeacon/torch/medical + location = "medical" + codes = list("patrol" = 1, "next_patrol" = "vault1") + +/obj/machinery/navbeacon/torch/bridge2 + location = "bridge2" + codes = list("patrol" = 1, "next_patrol" = "rdoffice") + +/obj/machinery/navbeacon/torch/rdoffice + location = "rdoffice" + codes = list("patrol" = 1, "next_patrol" = "vault2") + +// Torch delivery types + +/obj/machinery/navbeacon/torch/QM3 + location = "QM #3" + codes = list("delivery" = 1) \ No newline at end of file diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm new file mode 100644 index 00000000..69cdf064 --- /dev/null +++ b/code/game/machinery/newscaster.dm @@ -0,0 +1,978 @@ +//############################################## +//################### NEWSCASTERS BE HERE! #### +//###-Agouri################################### + +/datum/feed_message + var/author ="" + var/body ="" + var/message_type ="Story" + var/datum/feed_channel/parent_channel + var/is_admin_message = 0 + var/icon/img = null + var/icon/caption = "" + var/time_stamp = "" + var/backup_body = "" + var/backup_author = "" + var/icon/backup_img = null + var/icon/backup_caption = "" + +/datum/feed_channel + var/channel_name="" + var/list/datum/feed_message/messages = list() + var/locked=0 + var/author="" + var/backup_author="" + var/views=0 + var/censored=0 + var/is_admin_channel=0 + var/updated = 0 + var/announcement = "" + +/datum/feed_message/proc/clear() + src.author = "" + src.body = "" + src.caption = "" + src.img = null + src.time_stamp = "" + src.backup_body = "" + src.backup_author = "" + src.backup_caption = "" + src.backup_img = null + parent_channel.update() + +/datum/feed_channel/proc/update() + updated = world.time + +/datum/feed_channel/proc/clear() + src.channel_name = "" + src.messages = list() + src.locked = 0 + src.author = "" + src.backup_author = "" + src.censored = 0 + src.is_admin_channel = 0 + src.announcement = "" + update() + +/datum/feed_network + var/list/datum/feed_channel/network_channels = list() + var/datum/feed_message/wanted_issue + +/datum/feed_network/New() + CreateFeedChannel("Announcements", "SS13", 1, 1, "New Announcement Available") + +/datum/feed_network/proc/CreateFeedChannel(var/channel_name, var/author, var/locked, var/adminChannel = 0, var/announcement_message) + var/datum/feed_channel/newChannel = new /datum/feed_channel + newChannel.channel_name = channel_name + newChannel.author = author + newChannel.locked = locked + newChannel.is_admin_channel = adminChannel + if(announcement_message) + newChannel.announcement = announcement_message + else + newChannel.announcement = "Breaking news from [channel_name]!" + network_channels += newChannel + +/datum/feed_network/proc/SubmitArticle(var/msg, var/author, var/channel_name, var/obj/item/weapon/photo/photo, var/adminMessage = 0, var/message_type = "") + var/datum/feed_message/newMsg = new /datum/feed_message + newMsg.author = author + newMsg.body = msg + newMsg.time_stamp = "[stationtime2text()]" + newMsg.is_admin_message = adminMessage + if(message_type) + newMsg.message_type = message_type + if(photo) + newMsg.img = photo.img + newMsg.caption = photo.scribble + for(var/datum/feed_channel/FC in network_channels) + if(FC.channel_name == channel_name) + insert_message_in_channel(FC, newMsg) //Adding message to the network's appropriate feed_channel + break + +/datum/feed_network/proc/insert_message_in_channel(var/datum/feed_channel/FC, var/datum/feed_message/newMsg) + FC.messages += newMsg + if(newMsg.img) + register_asset("newscaster_photo_[sanitize(FC.channel_name)]_[FC.messages.len].png", newMsg.img) + newMsg.parent_channel = FC + FC.update() + alert_readers(FC.announcement) + +/datum/feed_network/proc/alert_readers(var/annoncement) + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) + NEWSCASTER.newsAlert(annoncement) + NEWSCASTER.update_icon() + + var/list/receiving_pdas = new + for (var/obj/item/device/pda/P in PDAs) + if (!P.owner) + continue + if (P.toff) + continue + receiving_pdas += P + + spawn(0) // get_receptions sleeps further down the line, spawn of elsewhere + var/datum/receptions/receptions = get_receptions(null, receiving_pdas) // datums are not atoms, thus we have to assume the newscast network always has reception + + for(var/obj/item/device/pda/PDA in receiving_pdas) + if(!(receptions.receiver_reception[PDA] & TELECOMMS_RECEPTION_RECEIVER)) + continue + + PDA.new_news(annoncement) + +var/datum/feed_network/news_network = new /datum/feed_network //The global news-network, which is coincidentally a global list. + +var/list/obj/machinery/newscaster/allCasters = list() //Global list that will contain reference to all newscasters in existence. + + +/obj/machinery/newscaster + name = "newscaster" + desc = "A standard newsfeed handler. All the news you absolutely have no use for, in one place!" + icon = 'icons/obj/terminals.dmi' + icon_state = "newscaster_normal" + //var/list/datum/feed_channel/channel_list = list() //This list will contain the names of the feed channels. Each name will refer to a data region where the messages of the feed channels are stored. + //OBSOLETE: We're now using a global news network + var/screen = 0 //Or maybe I'll make it into a list within a list afterwards... whichever I prefer, go fuck yourselves :3 + // 0 = welcome screen - main menu + // 1 = view feed channels + // 2 = create feed channel + // 3 = create feed story + // 4 = feed story submited sucessfully + // 5 = feed channel created successfully + // 6 = ERROR: Cannot create feed story + // 7 = ERROR: Cannot create feed channel + // 8 = print newspaper + // 9 = viewing channel feeds + // 10 = censor feed story + // 11 = censor feed channel + //Holy shit this is outdated, made this when I was still starting newscasters :3 + var/paper_remaining = 0 + var/securityCaster = 0 + // 0 = Caster cannot be used to issue wanted posters + // 1 = the opposite + var/unit_no = 0 //Each newscaster has a unit number + //var/datum/feed_message/wanted //We're gonna use a feed_message to store data of the wanted person because fields are similar + //var/wanted_issue = 0 //OBSOLETE + // 0 = there's no WANTED issued, we don't need a special icon_state + // 1 = Guess what. + var/alert_delay = 500 + var/alert = 0 + // 0 = there hasn't been a news/wanted update in the last alert_delay + // 1 = there has + var/scanned_user = "Unknown" //Will contain the name of the person who currently uses the newscaster + var/msg = ""; //Feed message + var/datum/news_photo/photo_data = null + var/channel_name = ""; //the feed channel which will be receiving the feed, or being created + var/c_locked=0; //Will our new channel be locked to public submissions? + var/hitstaken = 0 //Death at 3 hits from an item with force>=15 + var/datum/feed_channel/viewing_channel = null + light_range = 0 + anchored = 1 + layer = ABOVE_WINDOW_LAYER + +/obj/machinery/newscaster/security_unit //Security unit + name = "Security Newscaster" + securityCaster = 1 + +/obj/machinery/newscaster/New() //Constructor, ho~ + allCasters += src + src.paper_remaining = 15 // Will probably change this to something better + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) // Let's give it an appropriate unit number + src.unit_no++ + src.update_icon() //for any custom ones on the map... + ..() //I just realised the newscasters weren't in the global machines list. The superconstructor call will tend to that + +/obj/machinery/newscaster/Destroy() + allCasters -= src + ..() + +/obj/machinery/newscaster/update_icon() + if(inoperable()) + icon_state = "newscaster_off" + if(stat & BROKEN) //If the thing is smashed, add crack overlay on top of the unpowered sprite. + overlays.Cut() + overlays += image(src.icon, "crack3") + return + + src.overlays.Cut() //reset overlays + + if(news_network.wanted_issue) //wanted icon state, there can be no overlays on it as it's a priority message + icon_state = "newscaster_wanted" + return + + if(alert) //new message alert overlay + src.overlays += "newscaster_alert" + + if(hitstaken > 0) //Cosmetic damage overlay + src.overlays += image(src.icon, "crack[hitstaken]") + + icon_state = "newscaster_normal" + return + +/obj/machinery/newscaster/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/newscaster/attack_hand(mob/user as mob) //########### THE MAIN BEEF IS HERE! And in the proc below this...############ + + if(inoperable()) + return + + if(!user.IsAdvancedToolUser()) + return 0 + + if(istype(user, /mob/living/carbon/human) || istype(user,/mob/living/silicon) ) + var/mob/living/human_or_robot_user = user + var/dat + dat = text("Newscaster

            Newscaster Unit #[src.unit_no]

            ") + + src.scan_user(human_or_robot_user) //Newscaster scans you + + switch(screen) + if(0) + dat += "Welcome to Newscasting Unit #[src.unit_no].
            Interface & News networks Operational." + dat += "
            Property of Nanotransen Inc" + if(news_network.wanted_issue) + dat+= "
            Read Wanted Issue" + dat+= "

            Create Feed Channel" + dat+= "
            View Feed Channels" + dat+= "
            Submit new Feed story" + dat+= "
            Print newspaper" + dat+= "
            Re-scan User" + dat+= "

            Exit" + if(src.securityCaster) + var/wanted_already = 0 + if(news_network.wanted_issue) + wanted_already = 1 + + dat+="
            Feed Security functions:
            " + dat+="
            [(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue" + dat+="
            Censor Feed Stories" + dat+="
            Mark Feed Channel with [GLOB.using_map.company_name] D-Notice" + dat+="

            The newscaster recognises you as: [src.scanned_user]" + if(1) + dat+= "Local Feed Channels
            " + if( isemptylist(news_network.network_channels) ) + dat+="No active channels found..." + else + for(var/datum/feed_channel/CHANNEL in news_network.network_channels) + if(CHANNEL.is_admin_channel) + dat+="[CHANNEL.channel_name]
            " + else + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
            " + dat+="

            Refresh" + dat+="
            Back" + if(2) + dat+="Creating new Feed Channel..." + dat+="
            Channel Name: [src.channel_name]
            " + dat+="Channel Author: [src.scanned_user]
            " + dat+="Will Accept Public Feeds: [(src.c_locked) ? ("NO") : ("YES")]

            " + dat+="
            Submit

            Cancel
            " + if(3) + dat+="Creating new Feed Message..." + dat+="
            Receiving Channel: [src.channel_name]
            " //MARK + dat+="Message Author: [src.scanned_user]
            " + dat+="Message Body: [src.msg]
            " + dat+="Attach Photo: [(src.photo_data ? "Photo Attached" : "No Photo")]
            " + dat+="
            Submit

            Cancel
            " + if(4) + dat+="Feed story successfully submitted to [src.channel_name].

            " + dat+="
            Return
            " + if(5) + dat+="Feed Channel [src.channel_name] created successfully.

            " + dat+="
            Return
            " + if(6) + dat+="ERROR: Could not submit Feed story to Network.

            " + if(src.channel_name=="") + dat+="�Invalid receiving channel name.
            " + if(src.scanned_user=="Unknown") + dat+="�Channel author unverified.
            " + if(src.msg == "" || src.msg == "\[REDACTED\]") + dat+="�Invalid message body.
            " + + dat+="
            Return
            " + if(7) + dat+="ERROR: Could not submit Feed Channel to Network.

            " + var/list/existing_authors = list() + for(var/datum/feed_channel/FC in news_network.network_channels) + if(FC.author == "\[REDACTED\]") + existing_authors += FC.backup_author + else + existing_authors += FC.author + if(src.scanned_user in existing_authors) + dat+="�There already exists a Feed channel under your name.
            " + if(src.channel_name=="" || src.channel_name == "\[REDACTED\]") + dat+="�Invalid channel name.
            " + var/check = 0 + for(var/datum/feed_channel/FC in news_network.network_channels) + if(FC.channel_name == src.channel_name) + check = 1 + break + if(check) + dat+="�Channel name already in use.
            " + if(src.scanned_user=="Unknown") + dat+="�Channel author unverified.
            " + dat+="
            Return
            " + if(8) + var/total_num=length(news_network.network_channels) + var/active_num=total_num + var/message_num=0 + for(var/datum/feed_channel/FC in news_network.network_channels) + if(!FC.censored) + message_num += length(FC.messages) //Dont forget, datum/feed_channel's var messages is a list of datum/feed_message + else + active_num-- + dat+="Network currently serves a total of [total_num] Feed channels, [active_num] of which are active, and a total of [message_num] Feed Stories." //TODO: CONTINUE + dat+="

            Liquid Paper remaining: [(src.paper_remaining) *100 ] cm^3" + dat+="

            Print Paper" + dat+="
            Cancel" + if(9) + dat+="[src.viewing_channel.channel_name]: \[created by: [src.viewing_channel.author]\] \[views: [++src.viewing_channel.views]\]
            " + if(src.viewing_channel.censored) + dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the [station_name()], and marked with a [GLOB.using_map.company_name] D-Notice.
            " + dat+="No further feed story additions are allowed while the D-Notice is in effect.

            " + else + if( isemptylist(src.viewing_channel.messages) ) + dat+="No feed messages found in channel...
            " + else + var/i = 0 + for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) + ++i + dat+="-[MESSAGE.body]
            " + if(MESSAGE.img) + var/resourc_name = "newscaster_photo_[sanitize(viewing_channel.channel_name)]_[i].png" + send_asset(usr.client, resourc_name) + dat+="
            " + if(MESSAGE.caption) + dat+="[MESSAGE.caption]
            " + dat+="
            " + dat+="\[Story by [MESSAGE.author] - [MESSAGE.time_stamp]\]
            " + dat+="

            Refresh" + dat+="
            Back" + if(10) + dat+="[GLOB.using_map.company_name] Feed Censorship Tool
            " + dat+="NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.
            " + dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.
            " + dat+="
            Select Feed channel to get Stories from:
            " + if(isemptylist(news_network.network_channels)) + dat+="No feed channels found active...
            " + else + for(var/datum/feed_channel/CHANNEL in news_network.network_channels) + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
            " + dat+="
            Cancel" + if(11) + dat+="[GLOB.using_map.company_name] D-Notice Handler
            " + dat+="A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the [station_name()]'s" + dat+="morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed" + dat+="stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.
            " + if(isemptylist(news_network.network_channels)) + dat+="No feed channels found active...
            " + else + for(var/datum/feed_channel/CHANNEL in news_network.network_channels) + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
            " + + dat+="
            Back" + if(12) + dat+="[src.viewing_channel.channel_name]: \[ created by: [src.viewing_channel.author] \]
            " + dat+="[(src.viewing_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
            " + + + if( isemptylist(src.viewing_channel.messages) ) + dat+="No feed messages found in channel...
            " + else + for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) + dat+="-[MESSAGE.body]
            \[[MESSAGE.message_type] by [MESSAGE.author]\]
            " + dat+="[(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]
            " + dat+="
            Back" + if(13) + dat+="[src.viewing_channel.channel_name]: \[ created by: [src.viewing_channel.author] \]
            " + dat+="Channel messages listed below. If you deem them dangerous to the [station_name()], you can Bestow a D-Notice upon the channel.
            " + if(src.viewing_channel.censored) + dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the [station_name()], and marked with a [GLOB.using_map.company_name] D-Notice.
            " + dat+="No further feed story additions are allowed while the D-Notice is in effect.

            " + else + if( isemptylist(src.viewing_channel.messages) ) + dat+="No feed messages found in channel...
            " + else + for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) + dat+="-[MESSAGE.body]
            \[[MESSAGE.message_type] by [MESSAGE.author]\]
            " + + dat+="
            Back" + if(14) + dat+="Wanted Issue Handler:" + var/wanted_already = 0 + var/end_param = 1 + if(news_network.wanted_issue) + wanted_already = 1 + end_param = 2 + + if(wanted_already) + dat+="
            A wanted issue is already in Feed Circulation. You can edit or cancel it below.
            " + dat+="
            " + dat+="Criminal Name: [src.channel_name]
            " + dat+="Description: [src.msg]
            " + dat+="Attach Photo: [(src.photo_data ? "Photo Attached" : "No Photo")]
            " + if(wanted_already) + dat+="Wanted Issue created by: [news_network.wanted_issue.backup_author]
            " + else + dat+="Wanted Issue will be created under prosecutor: [src.scanned_user]
            " + dat+="
            [(wanted_already) ? ("Edit Issue") : ("Submit")]" + if(wanted_already) + dat+="
            Take down Issue" + dat+="
            Cancel" + if(15) + dat+="Wanted issue for [src.channel_name] is now in Network Circulation.

            " + dat+="
            Return
            " + if(16) + dat+="ERROR: Wanted Issue rejected by Network.

            " + if(src.channel_name=="" || src.channel_name == "\[REDACTED\]") + dat+="�Invalid name for person wanted.
            " + if(src.scanned_user=="Unknown") + dat+="�Issue author unverified.
            " + if(src.msg == "" || src.msg == "\[REDACTED\]") + dat+="�Invalid description.
            " + dat+="
            Return
            " + if(17) + dat+="Wanted Issue successfully deleted from Circulation
            " + dat+="
            Return
            " + if(18) + dat+="-- STATIONWIDE WANTED ISSUE --
            \[Submitted by: [news_network.wanted_issue.backup_author]\]
            " + dat+="Criminal: [news_network.wanted_issue.author]
            " + dat+="Description: [news_network.wanted_issue.body]
            " + dat+="Photo:: " + if(news_network.wanted_issue.img) + usr << browse_rsc(news_network.wanted_issue.img, "tmp_photow.png") + dat+="
            " + else + dat+="None" + dat+="

            Back
            " + if(19) + dat+="Wanted issue for [src.channel_name] successfully edited.

            " + dat+="
            Return
            " + if(20) + dat+="Printing successful. Please receive your newspaper from the bottom of the machine.

            " + dat+="Return" + if(21) + dat+="Unable to print newspaper. Insufficient paper. Please notify maintenance personnel to refill machine storage.

            " + dat+="Return" + else + dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com" + + + human_or_robot_user << browse(dat, "window=newscaster_main;size=400x600") + onclose(human_or_robot_user, "newscaster_main") + +/obj/machinery/newscaster/Topic(href, href_list) + if(..()) + return + if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) + usr.set_machine(src) + if(href_list["set_channel_name"]) + src.channel_name = sanitizeSafe(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""), MAX_LNAME_LEN) + src.updateUsrDialog() + //src.update_icon() + + else if(href_list["set_channel_lock"]) + src.c_locked = !src.c_locked + src.updateUsrDialog() + //src.update_icon() + + else if(href_list["submit_new_channel"]) + //var/list/existing_channels = list() //OBSOLETE + var/list/existing_authors = list() + for(var/datum/feed_channel/FC in news_network.network_channels) + //existing_channels += FC.channel_name + if(FC.author == "\[REDACTED\]") + existing_authors += FC.backup_author + else + existing_authors +=FC.author + var/check = 0 + for(var/datum/feed_channel/FC in news_network.network_channels) + if(FC.channel_name == src.channel_name) + check = 1 + break + if(src.channel_name == "" || src.channel_name == "\[REDACTED\]" || src.scanned_user == "Unknown" || check || (src.scanned_user in existing_authors) ) + src.screen=7 + else + var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel") + if(choice=="Confirm") + news_network.CreateFeedChannel(src.channel_name, src.scanned_user, c_locked) + src.screen=5 + src.updateUsrDialog() + //src.update_icon() + + else if(href_list["set_channel_receiving"]) + //var/list/datum/feed_channel/available_channels = list() + var/list/available_channels = list() + for(var/datum/feed_channel/F in news_network.network_channels) + if( (!F.locked || F.author == scanned_user) && !F.censored) + available_channels += F.channel_name + src.channel_name = input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels + src.updateUsrDialog() + + else if(href_list["set_new_message"]) + src.msg = sanitize(usr, "Write your Feed story", "Network Channel Handler", "") + src.updateUsrDialog() + + else if(href_list["set_attachment"]) + AttachPhoto(usr) + src.updateUsrDialog() + + else if(href_list["submit_new_message"]) + if(src.msg =="" || src.msg=="\[REDACTED\]" || src.scanned_user == "Unknown" || src.channel_name == "" ) + src.screen=6 + else + var/image = photo_data ? photo_data.photo : null + feedback_inc("newscaster_stories",1) + news_network.SubmitArticle(src.msg, src.scanned_user, src.channel_name, image, 0) + src.screen=4 + + src.updateUsrDialog() + + else if(href_list["create_channel"]) + src.screen=2 + src.updateUsrDialog() + + else if(href_list["create_feed_story"]) + src.screen=3 + src.updateUsrDialog() + + else if(href_list["menu_paper"]) + src.screen=8 + src.updateUsrDialog() + else if(href_list["print_paper"]) + if(!src.paper_remaining) + src.screen=21 + else + src.print_paper() + src.screen = 20 + src.updateUsrDialog() + + else if(href_list["menu_censor_story"]) + src.screen=10 + src.updateUsrDialog() + + else if(href_list["menu_censor_channel"]) + src.screen=11 + src.updateUsrDialog() + + else if(href_list["menu_wanted"]) + var/already_wanted = 0 + if(news_network.wanted_issue) + already_wanted = 1 + + if(already_wanted) + src.channel_name = news_network.wanted_issue.author + src.msg = news_network.wanted_issue.body + src.screen = 14 + src.updateUsrDialog() + + else if(href_list["set_wanted_name"]) + src.channel_name = sanitizeSafe(input(usr, "Provide the name of the Wanted person", "Network Security Handler", ""), MAX_LNAME_LEN) + src.updateUsrDialog() + + else if(href_list["set_wanted_desc"]) + src.msg = sanitize(usr, "Provide the a description of the Wanted person and any other details you deem important", "Network Security Handler", "") + src.updateUsrDialog() + + else if(href_list["submit_wanted"]) + var/input_param = text2num(href_list["submit_wanted"]) + if(src.msg == "" || src.channel_name == "" || src.scanned_user == "Unknown") + src.screen = 16 + else + var/choice = alert("Please confirm Wanted Issue [(input_param==1) ? ("creation.") : ("edit.")]","Network Security Handler","Confirm","Cancel") + if(choice=="Confirm") + if(input_param==1) //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one. See the else below + var/datum/feed_message/WANTED = new /datum/feed_message + WANTED.author = src.channel_name + WANTED.body = src.msg + WANTED.backup_author = src.scanned_user //I know, a bit wacky + if(photo_data) + WANTED.img = photo_data.photo.img + news_network.wanted_issue = WANTED + news_network.alert_readers() + src.screen = 15 + else + if(news_network.wanted_issue.is_admin_message) + alert("The wanted issue has been distributed by a [GLOB.using_map.company_name] higherup. You cannot edit it.","Ok") + return + news_network.wanted_issue.author = src.channel_name + news_network.wanted_issue.body = src.msg + news_network.wanted_issue.backup_author = src.scanned_user + if(photo_data) + news_network.wanted_issue.img = photo_data.photo.img + src.screen = 19 + + src.updateUsrDialog() + + else if(href_list["cancel_wanted"]) + if(news_network.wanted_issue.is_admin_message) + alert("The wanted issue has been distributed by a [GLOB.using_map.company_name] higherup. You cannot take it down.","Ok") + return + var/choice = alert("Please confirm Wanted Issue removal","Network Security Handler","Confirm","Cancel") + if(choice=="Confirm") + news_network.wanted_issue = null + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) + NEWSCASTER.update_icon() + src.screen=17 + src.updateUsrDialog() + + else if(href_list["view_wanted"]) + src.screen=18 + src.updateUsrDialog() + else if(href_list["censor_channel_author"]) + var/datum/feed_channel/FC = locate(href_list["censor_channel_author"]) + if(FC.is_admin_channel) + alert("This channel was created by a [GLOB.using_map.company_name] Officer. You cannot censor it.","Ok") + return + if(FC.author != "\[REDACTED\]") + FC.backup_author = FC.author + FC.author = "\[REDACTED\]" + else + FC.author = FC.backup_author + FC.update() + src.updateUsrDialog() + + else if(href_list["censor_channel_story_author"]) + var/datum/feed_message/MSG = locate(href_list["censor_channel_story_author"]) + if(MSG.is_admin_message) + alert("This message was created by a [GLOB.using_map.company_name] Officer. You cannot censor its author.","Ok") + return + if(MSG.author != "\[REDACTED\]") + MSG.backup_author = MSG.author + MSG.author = "\[REDACTED\]" + else + MSG.author = MSG.backup_author + MSG.parent_channel.update() + src.updateUsrDialog() + + else if(href_list["censor_channel_story_body"]) + var/datum/feed_message/MSG = locate(href_list["censor_channel_story_body"]) + if(MSG.is_admin_message) + alert("This channel was created by a [GLOB.using_map.company_name] Officer. You cannot censor it.","Ok") + return + if(MSG.body != "\[REDACTED\]") + MSG.backup_body = MSG.body + MSG.backup_caption = MSG.caption + MSG.backup_img = MSG.img + MSG.body = "\[REDACTED\]" + MSG.caption = "\[REDACTED\]" + MSG.img = null + else + MSG.body = MSG.backup_body + MSG.caption = MSG.caption + MSG.img = MSG.backup_img + + MSG.parent_channel.update() + src.updateUsrDialog() + + else if(href_list["pick_d_notice"]) + var/datum/feed_channel/FC = locate(href_list["pick_d_notice"]) + src.viewing_channel = FC + src.screen=13 + src.updateUsrDialog() + + else if(href_list["toggle_d_notice"]) + var/datum/feed_channel/FC = locate(href_list["toggle_d_notice"]) + if(FC.is_admin_channel) + alert("This channel was created by a [GLOB.using_map.company_name] Officer. You cannot place a D-Notice upon it.","Ok") + return + FC.censored = !FC.censored + FC.update() + src.updateUsrDialog() + + else if(href_list["view"]) + src.screen=1 + src.updateUsrDialog() + + else if(href_list["setScreen"]) //Brings us to the main menu and resets all fields~ + src.screen = text2num(href_list["setScreen"]) + if (src.screen == 0) + src.scanned_user = "Unknown"; + msg = ""; + src.c_locked=0; + channel_name=""; + src.viewing_channel = null + src.updateUsrDialog() + + else if(href_list["show_channel"]) + var/datum/feed_channel/FC = locate(href_list["show_channel"]) + src.viewing_channel = FC + src.screen = 9 + src.updateUsrDialog() + + else if(href_list["pick_censor_channel"]) + var/datum/feed_channel/FC = locate(href_list["pick_censor_channel"]) + src.viewing_channel = FC + src.screen = 12 + src.updateUsrDialog() + + else if(href_list["refresh"]) + src.updateUsrDialog() + + + +/obj/machinery/newscaster/attackby(obj/item/I as obj, mob/user as mob) + if (stat & BROKEN) + playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 100, 1) + for (var/mob/O in hearers(5, src.loc)) + O.show_message("[user.name] further abuses the shattered [src.name].") + else + if(istype(I, /obj/item/weapon) ) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + var/obj/item/weapon/W = I + if(W.force <15) + for (var/mob/O in hearers(5, src.loc)) + O.show_message("[user.name] hits the [src.name] with the [W.name] with no visible effect." ) + playsound(src.loc, 'sound/effects/Glasshit.ogg', 100, 1) + else + src.hitstaken++ + if(hitstaken==3) + for (var/mob/O in hearers(5, src.loc)) + O.show_message("[user.name] smashes the [src.name]!" ) + stat |= BROKEN + playsound(src.loc, 'sound/effects/Glassbr3.ogg', 100, 1) + else + for (var/mob/O in hearers(5, src.loc)) + O.show_message("[user.name] forcefully slams the [src.name] with the [I.name]!" ) + playsound(src.loc, 'sound/effects/Glasshit.ogg', 100, 1) + else + to_chat(user, "This does nothing.") + update_icon() + +/obj/machinery/newscaster/attack_ai(mob/user as mob) + return src.attack_hand(user) //or maybe it'll have some special functions? No idea. + +/datum/news_photo + var/is_synth = 0 + var/obj/item/weapon/photo/photo = null + +/datum/news_photo/New(var/obj/item/weapon/photo/p, var/synth) + is_synth = synth + photo = p + +/obj/machinery/newscaster/proc/AttachPhoto(mob/user as mob) + if(photo_data) + if(!photo_data.is_synth) + photo_data.photo.loc = src.loc + if(!issilicon(user)) + user.put_in_inactive_hand(photo_data.photo) + qdel(photo_data) + + if(istype(user.get_active_hand(), /obj/item/weapon/photo)) + var/obj/item/photo = user.get_active_hand() + user.drop_item() + photo.loc = src + photo_data = new(photo, 0) + else if(istype(user,/mob/living/silicon)) + var/mob/living/silicon/tempAI = user + var/obj/item/weapon/photo/selection = tempAI.GetPicture() + if (!selection) + return + + photo_data = new(selection, 1) + + +//######################################################################################################################## +//###################################### NEWSPAPER! ###################################################################### +//######################################################################################################################## + +/obj/item/weapon/newspaper + name = "newspaper" + desc = "An issue of The Griffon, the space newspaper." + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "newspaper" + w_class = ITEM_SIZE_SMALL //Let's make it fit in trashbags! + attack_verb = list("bapped") + var/screen = 0 + var/pages = 0 + var/curr_page = 0 + var/list/datum/feed_channel/news_content = list() + var/datum/feed_message/important_message = null + var/scribble="" + var/scribble_page = null + +obj/item/weapon/newspaper/attack_self(mob/user as mob) + if(ishuman(user)) + var/mob/living/carbon/human/human_user = user + var/dat + src.pages = 0 + switch(screen) + if(0) //Cover + dat+="
            The Griffon
            " + dat+="
            [GLOB.using_map.company_name]-standard newspaper, for use on [GLOB.using_map.company_name]� Space Facilities

            " + if(isemptylist(src.news_content)) + if(src.important_message) + dat+="Contents:
              **Important Security Announcement** \[page [src.pages+2]\]
            " + else + dat+="Other than the title, the rest of the newspaper is unprinted..." + else + dat+="Contents:
              " + for(var/datum/feed_channel/NP in src.news_content) + src.pages++ + if(src.important_message) + dat+="**Important Security Announcement** \[page [src.pages+2]\]
              " + var/temp_page=0 + for(var/datum/feed_channel/NP in src.news_content) + temp_page++ + dat+="[NP.channel_name] \[page [temp_page+1]\]
              " + dat+="
            " + if(scribble_page==curr_page) + dat+="
            There is a small scribble near the end of this page... It reads: \"[src.scribble]\"" + dat+= "
            " + if(1) // X channel pages inbetween. + for(var/datum/feed_channel/NP in src.news_content) + src.pages++ //Let's get it right again. + var/datum/feed_channel/C = src.news_content[src.curr_page] + dat+="[C.channel_name] \[created by: [C.author]\]

            " + if(C.censored) + dat+="This channel was deemed dangerous to the general welfare of the [station_name()] and therefore marked with a D-Notice. Its contents were not transferred to the newspaper at the time of printing." + else + if(isemptylist(C.messages)) + dat+="No Feed stories stem from this channel..." + else + dat+="
              " + var/i = 0 + for(var/datum/feed_message/MESSAGE in C.messages) + ++i + dat+="-[MESSAGE.body]
              " + if(MESSAGE.img) + var/resourc_name = "newscaster_photo_[sanitize(C.channel_name)]_[i].png" + send_asset(user.client, resourc_name) + dat+="
              " + dat+="\[[MESSAGE.message_type] by [MESSAGE.author]\]

              " + dat+="
            " + if(scribble_page==curr_page) + dat+="
            There is a small scribble near the end of this page... It reads: \"[src.scribble]\"" + dat+= "

            " + if(2) //Last page + for(var/datum/feed_channel/NP in src.news_content) + src.pages++ + if(src.important_message!=null) + dat+="
            Wanted Issue:


            " + dat+="Criminal name: [important_message.author]
            " + dat+="Description: [important_message.body]
            " + dat+="Photo:: " + if(important_message.img) + user << browse_rsc(important_message.img, "tmp_photow.png") + dat+="
            " + else + dat+="None" + else + dat+="Apart from some uninteresting Classified ads, there's nothing on this page..." + if(scribble_page==curr_page) + dat+="
            There is a small scribble near the end of this page... It reads: \"[src.scribble]\"" + dat+= "
            " + else + dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com" + + dat+="

            [src.curr_page+1]
            " + human_user << browse(dat, "window=newspaper_main;size=300x400") + onclose(human_user, "newspaper_main") + else + to_chat(user, "The paper is full of intelligible symbols!") + + +obj/item/weapon/newspaper/Topic(href, href_list) + var/mob/living/U = usr + ..() + if ((src in U.contents) || ( istype(loc, /turf) && in_range(src, U) )) + U.set_machine(src) + if(href_list["next_page"]) + if(curr_page==src.pages+1) + return //Don't need that at all, but anyway. + if(src.curr_page == src.pages) //We're at the middle, get to the end + src.screen = 2 + else + if(curr_page == 0) //We're at the start, get to the middle + src.screen=1 + src.curr_page++ + playsound(src.loc, "pageturn", 50, 1) + + else if(href_list["prev_page"]) + if(curr_page == 0) + return + if(curr_page == 1) + src.screen = 0 + + else + if(curr_page == src.pages+1) //we're at the end, let's go back to the middle. + src.screen = 1 + src.curr_page-- + playsound(src.loc, "pageturn", 50, 1) + + if (istype(src.loc, /mob)) + src.attack_self(src.loc) + + +obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/pen)) + if(src.scribble_page == src.curr_page) + to_chat(user, "There's already a scribble in this page... You wouldn't want to make things too cluttered, would you?") + else + var/s = sanitize(input(user, "Write something", "Newspaper", "")) + s = sanitize(s) + if (!s) + return + if (!in_range(src, usr) && src.loc != usr) + return + src.scribble_page = src.curr_page + src.scribble = s + src.attack_self(user) + return + + +////////////////////////////////////helper procs + + +/obj/machinery/newscaster/proc/scan_user(mob/living/user as mob) + if(istype(user,/mob/living/carbon/human)) //User is a human + var/mob/living/carbon/human/human_user = user + if(human_user.wear_id) //Newscaster scans you + if(istype(human_user.wear_id, /obj/item/device/pda) ) //autorecognition, woo! + var/obj/item/device/pda/P = human_user.wear_id + if(P.id) + src.scanned_user = GetNameAndAssignmentFromId(P.id) + else + src.scanned_user = "Unknown" + else if(istype(human_user.wear_id, /obj/item/weapon/card/id) ) + var/obj/item/weapon/card/id/ID = human_user.wear_id + src.scanned_user = GetNameAndAssignmentFromId(ID) + else + src.scanned_user ="Unknown" + else + src.scanned_user ="Unknown" + else + var/mob/living/silicon/ai_user = user + src.scanned_user = "[ai_user.name] ([ai_user.job])" + + +/obj/machinery/newscaster/proc/print_paper() + feedback_inc("newscaster_newspapers_printed",1) + var/obj/item/weapon/newspaper/NEWSPAPER = new /obj/item/weapon/newspaper + for(var/datum/feed_channel/FC in news_network.network_channels) + NEWSPAPER.news_content += FC + if(news_network.wanted_issue) + NEWSPAPER.important_message = news_network.wanted_issue + NEWSPAPER.loc = get_turf(src) + src.paper_remaining-- + return + +//Removed for now so these aren't even checked every tick. Left this here in-case Agouri needs it later. +///obj/machinery/newscaster/process() //Was thinking of doing the icon update through process, but multiple iterations per second does not +// return //bode well with a newscaster network of 10+ machines. Let's just return it, as it's added in the machines list. + +/obj/machinery/newscaster/proc/newsAlert(var/news_call) //This isn't Agouri's work, for it is ugly and vile. + var/turf/T = get_turf(src) //Who the fuck uses spawn(600) anyway, jesus christ + if(news_call) + for(var/mob/O in hearers(world.view-1, T)) + O.show_message("[src.name] beeps, \"[news_call]\"",2) + src.alert = 1 + src.update_icon() + spawn(300) + src.alert = 0 + src.update_icon() + playsound(src.loc, 'sound/machines/twobeep.ogg', 75, 1) + else + for(var/mob/O in hearers(world.view-1, T)) + O.show_message("[src.name] beeps, \"Attention! Wanted issue distributed!\"",2) + playsound(src.loc, 'sound/machines/warning-buzzer.ogg', 75, 1) + return diff --git a/code/game/machinery/nuclear_bomb.dm b/code/game/machinery/nuclear_bomb.dm new file mode 100644 index 00000000..b9c4d198 --- /dev/null +++ b/code/game/machinery/nuclear_bomb.dm @@ -0,0 +1,528 @@ +var/bomb_set + +/obj/machinery/nuclearbomb + name = "\improper Nuclear Fission Explosive" + desc = "Uh oh. RUN!!!!" + icon = 'icons/obj/nuke.dmi' + icon_state = "idle" + density = 1 + use_power = 0 + unacidable = 1 + + var/deployable = 0 + var/extended = 0 + var/lighthack = 0 + var/timeleft = 120 + var/timing = 0 + var/r_code = "ADMIN" + var/code = "" + var/yes_code = 0 + var/safety = 1 + var/obj/item/weapon/disk/nuclear/auth = null + var/removal_stage = 0 // 0 is no removal, 1 is covers removed, 2 is covers open, 3 is sealant open, 4 is unwrenched, 5 is removed from bolts. + var/lastentered + var/previous_level = "" + var/datum/wires/nuclearbomb/wires = null + var/decl/security_level/original_level + +/obj/machinery/nuclearbomb/New() + ..() + r_code = "[rand(10000, 99999.0)]"//Creates a random code upon object spawn. + wires = new/datum/wires/nuclearbomb(src) + +/obj/machinery/nuclearbomb/Destroy() + qdel(wires) + wires = null + qdel(auth) + auth = null + return ..() + +/obj/machinery/nuclearbomb/Process(var/wait) + if(timing) + timeleft = max(timeleft - (wait / 10), 0) + if(timeleft <= 0) + spawn + explode() + GLOB.nanomanager.update_uis(src) + +/obj/machinery/nuclearbomb/attackby(obj/item/weapon/O as obj, mob/user as mob, params) + if(isScrewdriver(O)) + src.add_fingerprint(user) + if(src.auth) + if(panel_open == 0) + panel_open = 1 + overlays |= "panel_open" + to_chat(user, "You unscrew the control panel of [src].") + playsound(src, 'sound/items/Screwdriver.ogg', 50, 1) + else + panel_open = 0 + overlays -= "panel_open" + to_chat(user, "You screw the control panel of [src] back on.") + playsound(src, 'sound/items/Screwdriver.ogg', 50, 1) + else + if(panel_open == 0) + to_chat(user, "\The [src] emits a buzzing noise, the panel staying locked in.") + if(panel_open == 1) + panel_open = 0 + overlays -= "panel_open" + to_chat(user, "You screw the control panel of \the [src] back on.") + playsound(src, 'sound/items/Screwdriver.ogg', 50, 1) + flick("lock", src) + return + + if(panel_open && isMultitool(O) || isWirecutter(O)) + return attack_hand(user) + + if(src.extended) + if(istype(O, /obj/item/weapon/disk/nuclear)) + usr.drop_item() + O.forceMove(src) + src.auth = O + src.add_fingerprint(user) + return attack_hand(user) + + if(src.anchored) + switch(removal_stage) + if(0) + if(isWelder(O)) + var/obj/item/weapon/weldingtool/WT = O + if(!WT.isOn()) return + if(WT.get_fuel() < 5) // uses up 5 fuel. + to_chat(user, "You need more fuel to complete this task.") + return + + user.visible_message("[user] starts cutting loose the anchoring bolt covers on [src].", "You start cutting loose the anchoring bolt covers with [O]...") + + if(do_after(user,40, src)) + if(!src || !user || !WT.remove_fuel(5, user)) return + user.visible_message("\The [user] cuts through the bolt covers on \the [src].", "You cut through the bolt cover.") + removal_stage = 1 + return + + if(1) + if(isCrowbar(O)) + user.visible_message("[user] starts forcing open the bolt covers on [src].", "You start forcing open the anchoring bolt covers with [O]...") + + if(do_after(user, 15, src)) + if(!src || !user) return + user.visible_message("\The [user] forces open the bolt covers on \the [src].", "You force open the bolt covers.") + removal_stage = 2 + return + + if(2) + if(isWelder(O)) + var/obj/item/weapon/weldingtool/WT = O + if(!WT.isOn()) return + if (WT.get_fuel() < 5) // uses up 5 fuel. + to_chat(user, "You need more fuel to complete this task.") + return + + user.visible_message("[user] starts cutting apart the anchoring system sealant on [src].", "You start cutting apart the anchoring system's sealant with [O]...") + + if(do_after(user, 40, src)) + if(!src || !user || !WT.remove_fuel(5, user)) return + user.visible_message("\The [user] cuts apart the anchoring system sealant on \the [src].", "You cut apart the anchoring system's sealant.") + removal_stage = 3 + return + + if(3) + if(isWrench(O)) + user.visible_message("[user] begins unwrenching the anchoring bolts on [src].", "You begin unwrenching the anchoring bolts...") + if(do_after(user, 50, src)) + if(!src || !user) return + user.visible_message("[user] unwrenches the anchoring bolts on [src].", "You unwrench the anchoring bolts.") + removal_stage = 4 + return + + if(4) + if(isCrowbar(O)) + user.visible_message("[user] begins lifting [src] off of the anchors.", "You begin lifting the device off the anchors...") + if(do_after(user, 80, src)) + if(!src || !user) return + user.visible_message("\The [user] crowbars \the [src] off of the anchors. It can now be moved.", "You jam the crowbar under the nuclear device and lift it off its anchors. You can now move it!") + anchored = 0 + removal_stage = 5 + return + ..() + +/obj/machinery/nuclearbomb/attack_ghost(mob/user as mob) + attack_hand(user) + +/obj/machinery/nuclearbomb/attack_hand(mob/user as mob) + if(extended) + if(panel_open) + wires.Interact(user) + else + ui_interact(user) + else if(deployable) + if(removal_stage < 5) + src.anchored = 1 + visible_message("With a steely snap, bolts slide out of [src] and anchor it to the flooring!") + else + visible_message("\The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") + extended = 1 + if(!src.lighthack) + flick("lock", src) + update_icon() + return + +/obj/machinery/nuclearbomb/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + data["hacking"] = 0 + data["auth"] = is_auth(user) + data["moveable_anchor"] = !istype(src, /obj/machinery/nuclearbomb/station) + if(is_auth(user)) + if(yes_code) + data["authstatus"] = timing ? "Functional/Set" : "Functional" + else + data["authstatus"] = "Auth. S2" + else + if(timing) + data["authstatus"] = "Set" + else + data["authstatus"] = "Auth. S1" + data["safe"] = safety ? "Safe" : "Engaged" + data["time"] = timeleft + data["timer"] = timing + data["safety"] = safety + data["anchored"] = anchored + data["yescode"] = yes_code + data["message"] = "AUTH" + if(is_auth(user)) + data["message"] = code + if(yes_code) + data["message"] = "*****" + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "nuclear_bomb.tmpl", "Nuke Control Panel", 300, 510) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/nuclearbomb/proc/toggle_deployable() + set category = "Object" + set name = "Toggle Deployable" + + if(usr.incapacitated()) + return + + if(src.deployable) + to_chat(usr, "You close several panels to make [src] undeployable.") + src.deployable = 0 + else + to_chat(usr, "You adjust some panels to make [src] deployable.") + src.deployable = 1 + return + +/obj/machinery/nuclearbomb/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + toggle_deployable() + +/obj/machinery/nuclearbomb/proc/is_auth(var/mob/user) + if(auth) + return 1 + if(user.can_admin_interact()) + return 1 + return 0 + +/obj/machinery/nuclearbomb/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["auth"]) + if(auth) + auth.forceMove(loc) + yes_code = 0 + auth = null + else + var/obj/item/I = usr.get_active_hand() + if(istype(I, /obj/item/weapon/disk/nuclear)) + usr.drop_item() + I.forceMove(src) + auth = I + if(is_auth(usr)) + if(href_list["type"]) + if(href_list["type"] == "E") + if(code == r_code) + yes_code = 1 + code = null + log_and_message_admins("has armed \the [src]") + else + code = "ERROR" + else + if(href_list["type"] == "R") + yes_code = 0 + code = null + else + lastentered = text("[]", href_list["type"]) + if(text2num(lastentered) == null) + log_and_message_admins("tried to exploit a nuclear bomb by entering non-numerical codes") + else + code += lastentered + if(length(code) > 5) + code = "ERROR" + if(yes_code) + if(href_list["time"]) + if(timing) + to_chat(usr, "Cannot alter the timing during countdown.") + return + + var/time = text2num(href_list["time"]) + timeleft += time + timeleft = Clamp(timeleft, 120, 600) + if(href_list["timer"]) + if(timing == -1) + return 1 + if(!anchored) + to_chat(usr, "\The [src] needs to be anchored.") + return 1 + if(safety) + to_chat(usr, "The safety is still on.") + return 1 + if(wires.IsIndexCut(NUCLEARBOMB_WIRE_TIMING)) + to_chat(usr, "Nothing happens, something might be wrong with the wiring.") + return 1 + if(!timing && !safety) + if(istype(src, /obj/machinery/nuclearbomb/station)) + var/obj/machinery/nuclearbomb/station/B = src + for(var/inserter in B.inserters) + var/obj/machinery/self_destruct/sd = inserter + if(!istype(sd) || !sd.armed) + to_chat(usr, "An inserter has not been armed or is damaged.") + return + timing = 1 + log_and_message_admins("activated the detonation countdown of \the [src]") + bomb_set++ //There can still be issues with this resetting when there are multiple bombs. Not a big deal though for Nuke/N + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + original_level = security_state.current_security_level + security_state.set_security_level(security_state.severe_security_level, TRUE) + update_icon() + else + secure_device() + + if(href_list["safety"]) + if (wires.IsIndexCut(NUCLEARBOMB_WIRE_SAFETY)) + to_chat(usr, "Nothing happens, something might be wrong with the wiring.") + return 1 + safety = !safety + if(safety) + secure_device() + update_icon() + if(href_list["anchor"]) + if(removal_stage == 5) + anchored = 0 + visible_message("\The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") + return 1 + + if(!isinspace()) + anchored = !anchored + if(anchored) + visible_message("With a steely snap, bolts slide out of \the [src] and anchor it to the flooring.") + else + secure_device() + visible_message("The anchoring bolts slide back into the depths of \the [src].") + else + to_chat(usr, "There is nothing to anchor to!") + return 1 + +/obj/machinery/nuclearbomb/proc/secure_device() + if(timing <= 0) + return + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + security_state.set_security_level(original_level, TRUE) + bomb_set-- + safety = TRUE + timing = 0 + timeleft = Clamp(timeleft, 120, 600) + update_icon() + +/obj/machinery/nuclearbomb/ex_act(severity) + return + +#define NUKERANGE 80 +/obj/machinery/nuclearbomb/proc/explode() + if (src.safety) + timing = 0 + return + src.timing = -1 + src.yes_code = 0 + src.safety = 1 + update_icon() + + SetUniversalState(/datum/universal_state/nuclear_explosion, arguments=list(src)) + +/obj/machinery/nuclearbomb/update_icon() + if(lighthack) + icon_state = "idle" + else if(timing == -1) + icon_state = "exploding" + else if(timing) + icon_state = "urgent" + else if(extended || !safety) + icon_state = "greenlight" + else + icon_state = "idle" + +//====The nuclear authentication disc==== +/obj/item/weapon/disk/nuclear + name = "nuclear authentication disk" + desc = "Better keep this safe." + icon = 'icons/obj/items.dmi' + icon_state = "nucleardisk" + item_state = "card-id" + w_class = ITEM_SIZE_TINY + +/obj/item/weapon/disk/nuclear/New() + ..() + nuke_disks |= src + +/obj/item/weapon/disk/nuclear/Initialize() + . = ..() + // Can never be quite sure that a game mode has been properly initiated or not at this point, so always register + GLOB.moved_event.register(src, src, /obj/item/weapon/disk/nuclear/proc/check_z_level) + +/obj/item/weapon/disk/nuclear/proc/check_z_level() + if(!(ticker && istype(ticker.mode, /datum/game_mode/nuclear))) + GLOB.moved_event.unregister(src, src, /obj/item/weapon/disk/nuclear/proc/check_z_level) // However, when we are certain unregister if necessary + return + var/turf/T = get_turf(src) + if(!T || isNotStationLevel(T.z)) + qdel(src) + +/obj/item/weapon/disk/nuclear/Destroy() + GLOB.moved_event.unregister(src, src, /obj/item/weapon/disk/nuclear/proc/check_z_level) + 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("[src], the last authentication disk, has been destroyed. Spawning [D] at ([D.x], [D.y], [D.z]).", location = T) + else + log_and_message_admins("[src], the last authentication disk, has been destroyed. Failed to respawn disc!") + return ..() + +//====the nuclear football (holds the disk and instructions)==== +/obj/item/weapon/storage/secure/briefcase/nukedisk + desc = "A large briefcase with a digital locking system." + startswith = list( + /obj/item/weapon/disk/nuclear, + /obj/item/weapon/pinpointer, + /obj/item/weapon/folder/envelope/nuke_instructions, + /obj/item/modular_computer/laptop/preset/custom_loadout/cheap/ + ) + +/obj/item/weapon/storage/secure/briefcase/nukedisk/examine(var/user) + ..() + to_chat(user,"On closer inspection, you see \a [GLOB.using_map.company_name] emblem is etched into the front of it.") + +/obj/item/weapon/folder/envelope/nuke_instructions + name = "instructions envelope" + desc = "A small envelope. The label reads 'open only in event of high emergency'." + +/obj/item/weapon/folder/envelope/nuke_instructions/Initialize() + . = ..() + var/obj/item/weapon/paper/R = new(src) + R.set_content("


            \ + Warning: Classified
            [GLOB.using_map.station_name] Self Destruct System - Instructions


            \ + In the event of a Delta-level emergency, this document will guide you through the activation of the vessel's \ + on-board nuclear self destruct system. Please read carefully.

            \ + 1) (Optional) Announce the imminent activation to any surviving crew members, and begin evacuation procedures.
            \ + 2) Notify two heads of staff, both with ID cards with access to the ship's Keycard Authentication Devices.
            \ + 3) Proceed to the self-destruct chamber, located on Deck One by the stairwell.
            \ + 4) Unbolt the door and enter the chamber.
            \ + 5) Both heads of staff should stand in front of their own Keycard Authentication Devices. On the KAD interface, select \ + Grant Nuclear Authentication Code. Both heads of staff should then swipe their ID cards simultaneously.
            \ + 6) The KAD will now display the Authentication Code. Memorize this code.
            \ + 7) Insert the nuclear authentication disk into the self-destruct terminal.
            \ + 8) Enter the code into the self-destruct terminal.
            \ + 9) Authentication procedures are now complete. Open the two cabinets containing the nuclear cylinders. They are \ + located on the back wall of the chamber.
            \ + 10) Place the cylinders upon the six nuclear cylinder inserters.
            \ + 11) Activate the inserters. The cylinders will be pulled down into the self-destruct system.
            \ + 12) Return to the terminal. Enter the desired countdown time.
            \ + 13) When ready, disable the safety switch.
            \ + 14) Start the countdown.

            \ + This concludes the instructions.", "vessel self-destruct instructions") + + //stamp the paper + var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') + stampoverlay.icon_state = "paper_stamp-hos" + R.stamped += /obj/item/weapon/stamp + R.overlays += stampoverlay + R.stamps += "
            This paper has been stamped as 'Top Secret'." + +//====vessel self-destruct system==== +/obj/machinery/nuclearbomb/station + name = "self-destruct terminal" + desc = "For when it all gets too much to bear. Do not taunt." + icon = 'icons/obj/nuke_station.dmi' + anchored = 1 + deployable = 1 + extended = 1 + + var/list/flash_tiles = list() + var/last_turf_state + var/list/inserters = list() + +/obj/machinery/nuclearbomb/station/Initialize() + . = ..() + verbs -= /obj/machinery/nuclearbomb/proc/toggle_deployable + for(var/turf/simulated/floor/T in get_area(src)) + if(istype(T.flooring, /decl/flooring/reinforced/circuit/red)) + flash_tiles += T + update_icon() + for(var/obj/machinery/self_destruct/ch in get_area(src)) + inserters += ch + +/obj/machinery/nuclearbomb/station/attackby(obj/item/weapon/O as obj, mob/user as mob) + if(isWrench(O)) + return + +/obj/machinery/nuclearbomb/station/Topic(href, href_list) + if((. = ..())) + return + + if(href_list["anchor"]) + return + + if(href_list["time"]) + if(timing) + to_chat(usr, "Cannot alter the timing during countdown.") + return + + var/time = text2num(href_list["time"]) + timeleft += time + timeleft = Clamp(timeleft, 300, 900) + return 1 + +/obj/machinery/nuclearbomb/station/Destroy() + flash_tiles.Cut() + return ..() + +/obj/machinery/nuclearbomb/station/update_icon() + var/target_icon_state + if(lighthack) + target_icon_state = "rcircuit_off" + icon_state = "idle" + else if(timing == -1) + target_icon_state = "rcircuitanim" + icon_state = "exploding" + else if(timing) + target_icon_state = "rcircuitanim" + icon_state = "urgent" + else if(!safety) + target_icon_state = "rcircuit" + icon_state = "greenlight" + else + target_icon_state = "rcircuit_off" + icon_state = "idle" + + if(!last_turf_state || target_icon_state != last_turf_state) + for(var/thing in flash_tiles) + var/turf/simulated/floor/T = thing + if(!istype(T.flooring, /decl/flooring/reinforced/circuit/red)) + flash_tiles -= T + continue + T.icon_state = target_icon_state + last_turf_state = target_icon_state diff --git a/code/game/machinery/oxygen_pump.dm b/code/game/machinery/oxygen_pump.dm new file mode 100644 index 00000000..bf2fa9be --- /dev/null +++ b/code/game/machinery/oxygen_pump.dm @@ -0,0 +1,245 @@ +/obj/machinery/oxygen_pump + name = "emergency oxygen pump" + icon = 'icons/obj/walllocker.dmi' + desc = "A wall mounted oxygen pump with a retractable face mask that you can pull over your face in case of emergencies." + icon_state = "emerg" + + anchored = TRUE + + var/obj/item/weapon/tank/tank + var/mob/living/carbon/breather + var/obj/item/clothing/mask/breath/contained + + var/spawn_type = /obj/item/weapon/tank/emergency/oxygen/engi + var/mask_type = /obj/item/clothing/mask/breath/emergency + var/icon_state_open = "emerg_open" + var/icon_state_closed = "emerg" + + power_channel = ENVIRON + idle_power_usage = 10 + active_power_usage = 120 // No idea what the realistic amount would be. + +/obj/machinery/oxygen_pump/New() + ..() + tank = new spawn_type (src) + contained = new mask_type (src) + +/obj/machinery/oxygen_pump/Destroy() + if(breather) + breather.internal = null + if(breather.internals) + breather.internals.icon_state = "internal0" + if(tank) + qdel(tank) + if(breather) + breather.remove_from_mob(contained) + src.visible_message("The mask rapidly retracts just before /the [src] is destroyed!") + qdel(contained) + contained = null + breather = null + return ..() + +/obj/machinery/oxygen_pump/MouseDrop(var/mob/living/carbon/human/target, src_location, over_location) + ..() + if(istype(target) && CanMouseDrop(target)) + if(!can_apply_to_target(target, usr)) // There is no point in attempting to apply a mask if it's impossible. + return + usr.visible_message("\The [usr] begins placing the mask onto [target]..") + if(!do_mob(usr, target, 25) || !can_apply_to_target(target, usr)) + return + // place mask and add fingerprints + usr.visible_message("\The [usr] has placed \the mask on [target]'s mouth.") + attach_mask(target) + src.add_fingerprint(usr) + + +/obj/machinery/oxygen_pump/attack_hand(mob/user as mob) + if((stat & MAINT) && tank) + user.visible_message("\The [user] removes \the [tank] from \the [src].", "You remove \the [tank] from \the [src].") + user.put_in_hands(tank) + src.add_fingerprint(user) + tank.add_fingerprint(user) + tank = null + return + if (!tank) + to_chat(user, "There is no tank in \the [src]!") + return + if(breather) + if(tank) + tank.forceMove(src) + breather.remove_from_mob(contained) + contained.forceMove(src) + src.visible_message("\The [user] makes \The [contained] rapidly retracts back into \the [src]!") + if(breather.internals) + breather.internals.icon_state = "internal0" + breather = null + use_power = 1 + +/obj/machinery/oxygen_pump/attack_ai(mob/user as mob) + ui_interact(user) + +/obj/machinery/oxygen_pump/proc/attach_mask(var/mob/living/carbon/C) + if(C && istype(C)) + contained.forceMove(get_turf(C)) + C.equip_to_slot(contained, slot_wear_mask) + if(tank) + tank.forceMove(C) + breather = C + spawn(1) + if(!breather.internal && tank) + breather.internal = tank + if(breather.internals) + breather.internals.icon_state = "internal1" + use_power = 2 + +/obj/machinery/oxygen_pump/proc/can_apply_to_target(var/mob/living/carbon/human/target, mob/user as mob) + if(!user) + user = target + // Check target validity + if(!target.organs_by_name[BP_HEAD]) + to_chat(user, "\The [target] doesn't have a head.") + return + if(!target.check_has_mouth()) + to_chat(user, "\The [target] doesn't have a mouth.") + return + if(target.wear_mask && target != breather) + to_chat(user, "\The [target] is already wearing a mask.") + return + if(target.head && (target.head.body_parts_covered & FACE)) + to_chat(user, "Remove their [target.head] first.") + return + if(!tank) + to_chat(user, "There is no tank in \the [src].") + return + if(stat & MAINT) + to_chat(user, "Please close \the maintenance hatch first.") + return + if(!Adjacent(target)) + to_chat(user, "Please stay close to \the [src].") + return + //when there is a breather: + if(breather && target != breather) + to_chat(user, "\The pump is already in use.") + return + //Checking if breather is still valid + if(target == breather && target.wear_mask != contained) + to_chat(user, "\The [target] is not using the supplied mask.") + return + return 1 + +/obj/machinery/oxygen_pump/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isScrewdriver(W)) + stat ^= MAINT + user.visible_message("\The [user] [stat & MAINT ? "opens" : "closes"] \the [src].", "You [stat & MAINT ? "open" : "close"] \the [src].") + if(stat & MAINT) + icon_state = icon_state_open + if(!stat) + icon_state = icon_state_closed + //TO-DO: Open icon + if(istype(W, /obj/item/weapon/tank) && (stat & MAINT)) + if(tank) + to_chat(user, "\The [src] already has a tank installed!") + else + user.drop_item() + W.forceMove(src) + tank = W + user.visible_message("\The [user] installs \the [tank] into \the [src].", "You install \the [tank] into \the [src].") + src.add_fingerprint(user) + if(istype(W, /obj/item/weapon/tank) && !stat) + to_chat(user, "Please open the maintenance hatch first.") + +/obj/machinery/oxygen_pump/examine(var/mob/user) + . = ..() + if(tank) + to_chat(user, "The meter shows [round(tank.air_contents.return_pressure())]") + else + to_chat(user, "It is missing a tank!") + + +/obj/machinery/oxygen_pump/Process() + if(breather) + if(!can_apply_to_target(breather)) + if(tank) + tank.forceMove(src) + breather.remove_from_mob(contained) + contained.forceMove(src) + src.visible_message("\The [contained] rapidly retracts back into \the [src]!") + breather = null + use_power = 1 + else if(!breather.internal && tank) + breather.internal = tank + if(breather.internals) + breather.internals.icon_state = "internal0" + + +//Create rightclick to view tank settings +/obj/machinery/oxygen_pump/proc/settings() + set category = "Object" + set name = "Show Tank Settings" + ui_interact(usr) + +/obj/machinery/oxygen_pump/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + settings() + +//GUI Tank Setup +/obj/machinery/oxygen_pump/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + if(!tank) + to_chat(usr, "It is missing a tank!") + data["tankPressure"] = 0 + data["releasePressure"] = 0 + data["defaultReleasePressure"] = 0 + data["maxReleasePressure"] = 0 + data["maskConnected"] = 0 + data["tankInstalled"] = 0 + // this is the data which will be sent to the ui + if(tank) + data["tankPressure"] = round(tank.air_contents.return_pressure() ? tank.air_contents.return_pressure() : 0) + data["releasePressure"] = round(tank.distribute_pressure ? tank.distribute_pressure : 0) + data["defaultReleasePressure"] = round(TANK_DEFAULT_RELEASE_PRESSURE) + data["maxReleasePressure"] = round(TANK_MAX_RELEASE_PRESSURE) + data["maskConnected"] = 0 + data["tankInstalled"] = 1 + + if(!breather) + data["maskConnected"] = 0 + if(breather) + data["maskConnected"] = 1 + + + // update the ui if it exists, returns null if no ui is passed/found + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "Oxygen_pump.tmpl", "Tank", 500, 300) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(1) + +/obj/machinery/oxygen_pump/Topic(href, href_list) + if(..()) + return 1 + + if (href_list["dist_p"]) + if (href_list["dist_p"] == "reset") + tank.distribute_pressure = TANK_DEFAULT_RELEASE_PRESSURE + else if (href_list["dist_p"] == "max") + tank.distribute_pressure = TANK_MAX_RELEASE_PRESSURE + else + var/cp = text2num(href_list["dist_p"]) + tank.distribute_pressure += cp + tank.distribute_pressure = min(max(round(tank.distribute_pressure), 0), TANK_MAX_RELEASE_PRESSURE) + return 1 + +/obj/machinery/oxygen_pump/anesthetic + name = "anesthetic pump" + spawn_type = /obj/item/weapon/tank/anesthetic + icon_state = "anesthetic_tank" + icon_state_closed = "anesthetic_tank" + icon_state_open = "anesthetic_tank_open" + mask_type = /obj/item/clothing/mask/breath/anesthetic diff --git a/code/game/machinery/pager.dm b/code/game/machinery/pager.dm new file mode 100644 index 00000000..52fb8130 --- /dev/null +++ b/code/game/machinery/pager.dm @@ -0,0 +1,68 @@ +/obj/machinery/pager + name = "departmental pager button" + icon = 'icons/obj/objects.dmi' + icon_state = "doorbell" + desc = "A button used to request the presence of anyone in the department." + anchored = 1 + use_power = 1 + idle_power_usage = 2 + var/acknowledged = 0 + var/last_paged + var/department = COM + var/location + +/obj/machinery/pager/Initialize() + . = ..() + if(!location) + var/area/A = get_area(src) + location = A.name + +/obj/machinery/pager/attack_ai(mob/user as mob) + return attack_hand(user) + +/obj/machinery/pager/attackby(obj/item/weapon/W, mob/user as mob) + return attack_hand(user) + +/obj/machinery/pager/attack_hand(mob/living/user) + if(..()) return 1 + if(istype(user, /mob/living/carbon)) + playsound(src, "button", 60) + flick("doorbellpressed",src) + activate(user) + +/obj/machinery/pager/proc/activate(mob/living/user) + if(!powered()) + return + var/obj/machinery/message_server/MS = get_message_server(z) + if(!MS) + return + if(world.time < last_paged + 5 SECONDS) + return + last_paged = world.time + var/paged = MS.send_to_department(department,"Department page to [location] received. Take", "*page*") + acknowledged = 0 + if(paged) + playsound(src, 'sound/machines/ping.ogg', 60) + to_chat(user,"Page received by [paged] devices.") + else + to_chat(user,"No valid destinations were found for the page.") + +/obj/machinery/pager/Topic(href, href_list) + if(..()) + return 1 + if(!powered()) + return + if(!acknowledged && href_list["ack"]) + playsound(src, 'sound/machines/ping.ogg', 60) + visible_message("Page acknowledged.") + acknowledged = 1 + var/obj/machinery/message_server/MS = get_message_server(z) + if(!MS) + return + MS.send_to_department(department,"Page to [location] was acknowledged.", "*ack*") + +/obj/machinery/pager/medical + department = MED + +/obj/machinery/pager/cargo //supply + department = SUP \ No newline at end of file diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm new file mode 100644 index 00000000..36869079 --- /dev/null +++ b/code/game/machinery/pipe/construction.dm @@ -0,0 +1,1334 @@ +/*CONTENTS +Buildable pipes +Buildable meters +*/ + +/obj/item/pipe + name = "pipe" + desc = "A pipe." + var/pipe_type = 0 + //var/pipe_dir = 0 + var/pipename + var/connect_types = CONNECT_TYPE_REGULAR + force = 7 + icon = 'icons/obj/pipe-item.dmi' + icon_state = "simple" + randpixel = 5 + item_state = "buildpipe" + w_class = ITEM_SIZE_NORMAL + level = 2 + +/obj/item/pipe/New(var/loc, var/pipe_type as num, var/dir as num, var/obj/machinery/atmospherics/make_from = null) + ..() + if (make_from) + src.set_dir(make_from.dir) + src.pipename = make_from.name + color = make_from.pipe_color + var/is_bent + if (make_from.initialize_directions in list(NORTH|SOUTH, WEST|EAST)) + is_bent = 0 + else + is_bent = 1 + if (istype(make_from, /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction)) + src.pipe_type = PIPE_JUNCTION + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_HE + else if(istype(make_from, /obj/machinery/atmospherics/pipe/simple/heat_exchanging)) + src.pipe_type = PIPE_HE_STRAIGHT + is_bent + connect_types = CONNECT_TYPE_HE + else if(istype(make_from, /obj/machinery/atmospherics/pipe/simple/visible/supply) || istype(make_from, /obj/machinery/atmospherics/pipe/simple/hidden/supply)) + src.pipe_type = PIPE_SUPPLY_STRAIGHT + is_bent + connect_types = CONNECT_TYPE_SUPPLY + src.color = PIPE_COLOR_BLUE + else if(istype(make_from, /obj/machinery/atmospherics/pipe/simple/visible/scrubbers) || istype(make_from, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers)) + src.pipe_type = PIPE_SCRUBBERS_STRAIGHT + is_bent + connect_types = CONNECT_TYPE_SCRUBBER + src.color = PIPE_COLOR_RED + else if(istype(make_from, /obj/machinery/atmospherics/pipe/simple/visible/fuel) || istype(make_from, /obj/machinery/atmospherics/pipe/simple/hidden/fuel)) + src.pipe_type = PIPE_FUEL_STRAIGHT + is_bent + src.color = PIPE_COLOR_ORANGE + else if(istype(make_from, /obj/machinery/atmospherics/pipe/simple/visible/universal) || istype(make_from, /obj/machinery/atmospherics/pipe/simple/hidden/universal)) + src.pipe_type = PIPE_UNIVERSAL + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER + else if(istype(make_from, /obj/machinery/atmospherics/pipe/simple)) + src.pipe_type = PIPE_SIMPLE_STRAIGHT + is_bent + else if(istype(make_from, /obj/machinery/atmospherics/portables_connector)) + src.pipe_type = PIPE_CONNECTOR + else if(istype(make_from, /obj/machinery/atmospherics/pipe/manifold/visible/supply) || istype(make_from, /obj/machinery/atmospherics/pipe/manifold/hidden/supply)) + src.pipe_type = PIPE_SUPPLY_MANIFOLD + connect_types = CONNECT_TYPE_SUPPLY + src.color = PIPE_COLOR_BLUE + else if(istype(make_from, /obj/machinery/atmospherics/pipe/manifold/visible/scrubbers) || istype(make_from, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers)) + src.pipe_type = PIPE_SCRUBBERS_MANIFOLD + connect_types = CONNECT_TYPE_SCRUBBER + src.color = PIPE_COLOR_RED + else if(istype(make_from, /obj/machinery/atmospherics/pipe/manifold)) + src.pipe_type = PIPE_MANIFOLD + else if(istype(make_from, /obj/machinery/atmospherics/pipe/manifold/visible/fuel) || istype(make_from, /obj/machinery/atmospherics/pipe/manifold/hidden/fuel)) + src.pipe_type = PIPE_FUEL_MANIFOLD + src.color = PIPE_COLOR_ORANGE + else if(istype(make_from, /obj/machinery/atmospherics/unary/vent_pump)) + src.pipe_type = PIPE_UVENT + else if(istype(make_from, /obj/machinery/atmospherics/valve/shutoff)) + src.pipe_type = PIPE_SVALVE + else if(istype(make_from, /obj/machinery/atmospherics/valve/digital)) + src.pipe_type = PIPE_DVALVE + else if(istype(make_from, /obj/machinery/atmospherics/valve)) + src.pipe_type = PIPE_MVALVE + else if(istype(make_from, /obj/machinery/atmospherics/binary/pump/high_power)) + src.pipe_type = PIPE_VOLUME_PUMP + else if(istype(make_from, /obj/machinery/atmospherics/binary/pump)) + src.pipe_type = PIPE_PUMP + else if(istype(make_from, /obj/machinery/atmospherics/trinary/filter/m_filter)) + src.pipe_type = PIPE_GAS_FILTER_M + else if(istype(make_from, /obj/machinery/atmospherics/trinary/mixer/t_mixer)) + src.pipe_type = PIPE_GAS_MIXER_T + else if(istype(make_from, /obj/machinery/atmospherics/trinary/mixer/m_mixer)) + src.pipe_type = PIPE_GAS_MIXER_M + else if(istype(make_from, /obj/machinery/atmospherics/trinary/filter)) + src.pipe_type = PIPE_GAS_FILTER + else if(istype(make_from, /obj/machinery/atmospherics/trinary/mixer)) + src.pipe_type = PIPE_GAS_MIXER + else if(istype(make_from, /obj/machinery/atmospherics/unary/vent_scrubber)) + src.pipe_type = PIPE_SCRUBBER + else if(istype(make_from, /obj/machinery/atmospherics/binary/passive_gate)) + src.pipe_type = PIPE_PASSIVE_GATE + else if(istype(make_from, /obj/machinery/atmospherics/unary/heat_exchanger)) + src.pipe_type = PIPE_HEAT_EXCHANGE + else if(istype(make_from, /obj/machinery/atmospherics/tvalve/mirrored)) + src.pipe_type = PIPE_MTVALVEM + else if(istype(make_from, /obj/machinery/atmospherics/tvalve)) + src.pipe_type = PIPE_MTVALVE + else if(istype(make_from, /obj/machinery/atmospherics/pipe/manifold4w/visible/supply) || istype(make_from, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply)) + src.pipe_type = PIPE_SUPPLY_MANIFOLD4W + connect_types = CONNECT_TYPE_SUPPLY + src.color = PIPE_COLOR_BLUE + else if(istype(make_from, /obj/machinery/atmospherics/pipe/manifold4w/visible/scrubbers) || istype(make_from, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers)) + src.pipe_type = PIPE_SCRUBBERS_MANIFOLD4W + connect_types = CONNECT_TYPE_SCRUBBER + src.color = PIPE_COLOR_RED + else if(istype(make_from, /obj/machinery/atmospherics/pipe/manifold4w/visible/fuel) || istype(make_from, /obj/machinery/atmospherics/pipe/manifold4w/hidden/fuel)) + src.pipe_type = PIPE_FUEL_MANIFOLD4W + src.color = PIPE_COLOR_ORANGE + else if(istype(make_from, /obj/machinery/atmospherics/pipe/manifold4w)) + src.pipe_type = PIPE_MANIFOLD4W + else if(istype(make_from, /obj/machinery/atmospherics/pipe/cap/visible/supply) || istype(make_from, /obj/machinery/atmospherics/pipe/cap/hidden/supply)) + src.pipe_type = PIPE_SUPPLY_CAP + connect_types = CONNECT_TYPE_SUPPLY + src.color = PIPE_COLOR_BLUE + else if(istype(make_from, /obj/machinery/atmospherics/pipe/cap/visible/scrubbers) || istype(make_from, /obj/machinery/atmospherics/pipe/cap/hidden/scrubbers)) + src.pipe_type = PIPE_SCRUBBERS_CAP + connect_types = CONNECT_TYPE_SCRUBBER + src.color = PIPE_COLOR_RED + else if(istype(make_from, /obj/machinery/atmospherics/pipe/cap/visible/fuel) || istype(make_from, /obj/machinery/atmospherics/pipe/cap/hidden/fuel)) + src.pipe_type = PIPE_FUEL_CAP + src.color = PIPE_COLOR_ORANGE + else if(istype(make_from, /obj/machinery/atmospherics/pipe/cap)) + src.pipe_type = PIPE_CAP + else if(istype(make_from, /obj/machinery/atmospherics/omni/mixer)) + src.pipe_type = PIPE_OMNI_MIXER + else if(istype(make_from, /obj/machinery/atmospherics/omni/filter)) + src.pipe_type = PIPE_OMNI_FILTER +///// Z-Level stuff + else if(istype(make_from, /obj/machinery/atmospherics/pipe/zpipe/up/supply)) + src.pipe_type = PIPE_SUPPLY_UP + connect_types = CONNECT_TYPE_SUPPLY + src.color = PIPE_COLOR_BLUE + else if(istype(make_from, /obj/machinery/atmospherics/pipe/zpipe/up/scrubbers)) + src.pipe_type = PIPE_SCRUBBERS_UP + connect_types = CONNECT_TYPE_SCRUBBER + src.color = PIPE_COLOR_RED + else if(istype(make_from, /obj/machinery/atmospherics/pipe/zpipe/up/fuel)) + src.pipe_type = PIPE_FUEL_UP + src.color = PIPE_COLOR_ORANGE + else if(istype(make_from, /obj/machinery/atmospherics/pipe/zpipe/up)) + src.pipe_type = PIPE_UP + else if(istype(make_from, /obj/machinery/atmospherics/pipe/zpipe/down/supply)) + src.pipe_type = PIPE_SUPPLY_DOWN + connect_types = CONNECT_TYPE_SUPPLY + src.color = PIPE_COLOR_BLUE + else if(istype(make_from, /obj/machinery/atmospherics/pipe/zpipe/down/scrubbers)) + src.pipe_type = PIPE_SCRUBBERS_DOWN + connect_types = CONNECT_TYPE_SCRUBBER + src.color = PIPE_COLOR_RED + else if(istype(make_from, /obj/machinery/atmospherics/pipe/zpipe/down/fuel)) + src.pipe_type = PIPE_FUEL_DOWN + src.color = PIPE_COLOR_ORANGE + else if(istype(make_from, /obj/machinery/atmospherics/pipe/zpipe/down)) + src.pipe_type = PIPE_DOWN +///// Z-Level stuff + else + src.pipe_type = pipe_type + src.set_dir(dir) + if (pipe_type == 29 || pipe_type == 30 || pipe_type == 33 || pipe_type == 35 || pipe_type == 37 || pipe_type == 39 || pipe_type == 41) + connect_types = CONNECT_TYPE_SUPPLY + src.color = PIPE_COLOR_BLUE + else if (pipe_type == 31 || pipe_type == 32 || pipe_type == 34 || pipe_type == 36 || pipe_type == 38 || pipe_type == 40 || pipe_type == 42) + connect_types = CONNECT_TYPE_SCRUBBER + src.color = PIPE_COLOR_RED + else if (pipe_type == 45 || pipe_type == 46 || pipe_type == 47 || pipe_type == 48 || pipe_type == 49 || pipe_type == 50 || pipe_type == 51) + src.color = PIPE_COLOR_ORANGE + else if (pipe_type == 2 || pipe_type == 3) + connect_types = CONNECT_TYPE_HE + else if (pipe_type == 6) + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_HE + else if (pipe_type == 28) + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER + //src.pipe_dir = get_pipe_dir() + update() + +//update the name and icon of the pipe item depending on the type + +/obj/item/pipe/proc/update() + var/list/nlist = list( \ + "pipe", \ + "bent pipe", \ + "h/e pipe", \ + "bent h/e pipe", \ + "connector", \ + "manifold", \ + "junction", \ + "uvent", \ + "manual valve", \ + "digital valve", \ + "pump", \ + "scrubber", \ + "unused", \ + "gas filter", \ + "gas mixer", \ + "pressure regulator", \ + "high power pump", \ + "heat exchanger", \ + "t-valve", \ + "4-way manifold", \ + "pipe cap", \ +///// Z-Level stuff + "pipe up", \ + "pipe down", \ +///// Z-Level stuff + "gas filter m", \ + "gas mixer t", \ + "gas mixer m", \ + "omni mixer", \ + "omni filter", \ +///// Supply and scrubbers pipes + "universal pipe adapter", \ + "supply pipe", \ + "bent supply pipe", \ + "scrubbers pipe", \ + "bent scrubbers pipe", \ + "supply manifold", \ + "scrubbers manifold", \ + "supply 4-way manifold", \ + "scrubbers 4-way manifold", \ + "supply pipe up", \ + "scrubbers pipe up", \ + "supply pipe down", \ + "scrubbers pipe down", \ + "supply pipe cap", \ + "scrubbers pipe cap", \ + "t-valve m", \ + "shutoff valve", \ +///// Fuel pipes + "fuel pipe",\ + "bent fuel pipe",\ + "fuel manifold",\ + "fuel 4-way manifold",\ + "fuel pipe up",\ + "fuel down",\ + "fuel pipe cap",\ + ) + SetName(nlist[pipe_type+1] + " fitting") + var/list/islist = list( \ + "simple", \ + "simple", \ + "he", \ + "he", \ + "connector", \ + "manifold", \ + "junction", \ + "uvent", \ + "mvalve", \ + "dvalve", \ + "pump", \ + "scrubber", \ + "unused", \ + "filter", \ + "mixer", \ + "passivegate", \ + "volumepump", \ + "heunary", \ + "mtvalve", \ + "manifold4w", \ + "cap", \ +///// Z-Level stuff + "cap", \ + "cap", \ +///// Z-Level stuff + "m_filter", \ + "t_mixer", \ + "m_mixer", \ + "omni_mixer", \ + "omni_filter", \ +///// Supply and scrubbers pipes + "universal", \ + "simple", \ + "simple", \ + "simple", \ + "simple", \ + "manifold", \ + "manifold", \ + "manifold4w", \ + "manifold4w", \ + "cap", \ + "cap", \ + "cap", \ + "cap", \ + "cap", \ + "cap", \ + "mtvalvem", \ + "svalve", \ +///// Fuel pipes + "simple",\ + "simple",\ + "manifold",\ + "manifold4w",\ + "cap", \ + "cap", \ + "cap", \ + ) + icon_state = islist[pipe_type + 1] + +//called when a turf is attacked with a pipe item +/obj/item/pipe/afterattack(turf/simulated/floor/target, mob/user, proximity) + if(!proximity) return + if(istype(target)) + user.drop_from_inventory(src, target) + else + return ..() + +// rotate the pipe item clockwise + +/obj/item/pipe/proc/rotate() + set category = "Object" + set name = "Rotate Pipe" + + if ( usr.stat || usr.restrained() ) + return + + src.set_dir(turn(src.dir, -90)) + + if (pipe_type in list (PIPE_SIMPLE_STRAIGHT, PIPE_SUPPLY_STRAIGHT, PIPE_SCRUBBERS_STRAIGHT, PIPE_UNIVERSAL, PIPE_HE_STRAIGHT, PIPE_MVALVE, PIPE_DVALVE, PIPE_SVALVE, PIPE_FUEL_STRAIGHT)) + if(dir==2) + set_dir(1) + else if(dir==8) + set_dir(4) + else if (pipe_type in list (PIPE_MANIFOLD4W, PIPE_SUPPLY_MANIFOLD4W, PIPE_SCRUBBERS_MANIFOLD4W, PIPE_FUEL_MANIFOLD4W)) + set_dir(2) + //src.pipe_set_dir(get_pipe_dir()) + return + +/obj/item/pipe/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + rotate() + +/obj/item/pipe/Move() + ..() + if ((pipe_type in list (PIPE_SIMPLE_BENT, PIPE_SUPPLY_BENT, PIPE_SCRUBBERS_BENT, PIPE_HE_BENT, PIPE_FUEL_BENT)) \ + && (src.dir in GLOB.cardinal)) + src.set_dir(src.dir|turn(src.dir, 90)) + else if (pipe_type in list (PIPE_SIMPLE_STRAIGHT, PIPE_SUPPLY_STRAIGHT, PIPE_SCRUBBERS_STRAIGHT, PIPE_UNIVERSAL, PIPE_HE_STRAIGHT, PIPE_MVALVE, PIPE_DVALVE, PIPE_SVALVE, PIPE_FUEL_STRAIGHT)) + if(dir==2) + set_dir(1) + else if(dir==8) + set_dir(4) + return + +// returns all pipe's endpoints + +/obj/item/pipe/proc/get_pipe_dir() + if (!dir) + return 0 + var/flip = turn(dir, 180) + var/cw = turn(dir, -90) + var/acw = turn(dir, 90) + + switch(pipe_type) + if( PIPE_SIMPLE_STRAIGHT, \ + PIPE_HE_STRAIGHT, \ + PIPE_JUNCTION ,\ + PIPE_PUMP ,\ + PIPE_VOLUME_PUMP ,\ + PIPE_PASSIVE_GATE ,\ + PIPE_MVALVE, \ + PIPE_DVALVE, \ + PIPE_SVALVE, \ + PIPE_SUPPLY_STRAIGHT, \ + PIPE_SCRUBBERS_STRAIGHT, \ + PIPE_UNIVERSAL, \ + PIPE_FUEL_STRAIGHT, \ + ) + return dir|flip + if(PIPE_SIMPLE_BENT, PIPE_HE_BENT, PIPE_SUPPLY_BENT, PIPE_SCRUBBERS_BENT, PIPE_FUEL_BENT) + return dir //dir|acw + if(PIPE_CONNECTOR,PIPE_UVENT,PIPE_SCRUBBER,PIPE_HEAT_EXCHANGE) + return dir + if(PIPE_MANIFOLD4W, PIPE_SUPPLY_MANIFOLD4W, PIPE_SCRUBBERS_MANIFOLD4W, PIPE_OMNI_MIXER, PIPE_OMNI_FILTER, PIPE_FUEL_MANIFOLD4W) + return dir|flip|cw|acw + if(PIPE_MANIFOLD, PIPE_SUPPLY_MANIFOLD, PIPE_SCRUBBERS_MANIFOLD, PIPE_FUEL_MANIFOLD) + return flip|cw|acw + if(PIPE_GAS_FILTER, PIPE_GAS_MIXER, PIPE_MTVALVE) + return dir|flip|cw + if(PIPE_GAS_FILTER_M, PIPE_GAS_MIXER_M, PIPE_MTVALVEM) + return dir|flip|acw + if(PIPE_GAS_MIXER_T) + return dir|cw|acw + if(PIPE_CAP, PIPE_SUPPLY_CAP, PIPE_SCRUBBERS_CAP, PIPE_FUEL_CAP) + return dir +///// Z-Level stuff + if(PIPE_UP,PIPE_DOWN,PIPE_SUPPLY_UP,PIPE_SUPPLY_DOWN,PIPE_SCRUBBERS_UP,PIPE_SCRUBBERS_DOWN,PIPE_FUEL_UP,PIPE_FUEL_DOWN) + return dir +///// Z-Level stuff + return 0 + +/obj/item/pipe/proc/get_pdir() //endpoints for regular pipes + + var/flip = turn(dir, 180) +// var/cw = turn(dir, -90) +// var/acw = turn(dir, 90) + + if (!(pipe_type in list(PIPE_HE_STRAIGHT, PIPE_HE_BENT, PIPE_JUNCTION))) + return get_pipe_dir() + switch(pipe_type) + if(PIPE_HE_STRAIGHT,PIPE_HE_BENT) + return 0 + if(PIPE_JUNCTION) + return flip + return 0 + +// return the h_dir (heat-exchange pipes) from the type and the dir + +/obj/item/pipe/proc/get_hdir() //endpoints for h/e pipes + +// var/flip = turn(dir, 180) +// var/cw = turn(dir, -90) + + switch(pipe_type) + if(PIPE_HE_STRAIGHT) + return get_pipe_dir() + if(PIPE_HE_BENT) + return get_pipe_dir() + if(PIPE_JUNCTION) + return dir + else + return 0 + +/obj/item/pipe/attack_self(mob/user as mob) + return rotate() + +/obj/item/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + ..() + //* + if(!isWrench(W)) + return ..() + if (!isturf(src.loc)) + return 1 + if (pipe_type in list (PIPE_SIMPLE_STRAIGHT, PIPE_SUPPLY_STRAIGHT, PIPE_SCRUBBERS_STRAIGHT, PIPE_HE_STRAIGHT, PIPE_MVALVE, PIPE_DVALVE, PIPE_SVALVE, PIPE_FUEL_STRAIGHT)) + if(dir==2) + set_dir(1) + else if(dir==8) + set_dir(4) + else if (pipe_type in list(PIPE_MANIFOLD4W, PIPE_SUPPLY_MANIFOLD4W, PIPE_SCRUBBERS_MANIFOLD4W, PIPE_OMNI_MIXER, PIPE_OMNI_FILTER, PIPE_FUEL_MANIFOLD4W)) + set_dir(2) + var/pipe_dir = get_pipe_dir() + + for(var/obj/machinery/atmospherics/M in src.loc) + if((M.initialize_directions & pipe_dir) && M.check_connect_types_construction(M,src)) // matches at least one direction on either type of pipe & same connection type + to_chat(user, "There is already a pipe of the same type at this location.") + return 1 + // no conflicts found + + var/pipefailtext = "There's nothing to connect this pipe section to!" //(with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)" + + //TODO: Move all of this stuff into the various pipe constructors. + switch(pipe_type) + if(PIPE_SIMPLE_STRAIGHT, PIPE_SIMPLE_BENT) + var/obj/machinery/atmospherics/pipe/simple/P = new( src.loc ) + P.pipe_color = color + P.set_dir(src.dir) + P.initialize_directions = pipe_dir + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + if (QDELETED(P)) + to_chat(usr, pipefailtext) + return 1 + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + + if(PIPE_SUPPLY_STRAIGHT, PIPE_SUPPLY_BENT) + var/obj/machinery/atmospherics/pipe/simple/hidden/supply/P = new( src.loc ) + P.color = color + P.set_dir(src.dir) + P.initialize_directions = pipe_dir + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + if (QDELETED(P)) + to_chat(usr, pipefailtext) + return 1 + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + + if(PIPE_SCRUBBERS_STRAIGHT, PIPE_SCRUBBERS_BENT) + var/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers/P = new( src.loc ) + P.color = color + P.set_dir(src.dir) + P.initialize_directions = pipe_dir + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + if (QDELETED(P)) + to_chat(usr, pipefailtext) + return 1 + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + + if(PIPE_FUEL_STRAIGHT, PIPE_FUEL_BENT) + var/obj/machinery/atmospherics/pipe/simple/hidden/fuel/P = new( src.loc ) + P.color = color + P.set_dir(src.dir) + P.initialize_directions = pipe_dir + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + if (QDELETED(P)) + to_chat(usr, pipefailtext) + return 1 + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + + if(PIPE_UNIVERSAL) + var/obj/machinery/atmospherics/pipe/simple/hidden/universal/P = new( src.loc ) + P.color = color + P.set_dir(src.dir) + P.initialize_directions = pipe_dir + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + if (QDELETED(P)) + to_chat(usr, pipefailtext) + return 1 + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + + if(PIPE_HE_STRAIGHT, PIPE_HE_BENT) + var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/P = new ( src.loc ) + P.set_dir(src.dir) + P.initialize_directions = pipe_dir //this var it's used to know if the pipe is bent or not + P.initialize_directions_he = pipe_dir + P.atmos_init() + if (QDELETED(P)) + to_chat(usr, pipefailtext) + return 1 + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + + if(PIPE_CONNECTOR) // connector + var/obj/machinery/atmospherics/portables_connector/C = new( src.loc ) + C.set_dir(dir) + C.initialize_directions = pipe_dir + if (pipename) + C.SetName(pipename) + var/turf/T = C.loc + C.level = !T.is_plating() ? 2 : 1 + C.atmos_init() + C.build_network() + if (C.node) + C.node.atmos_init() + C.node.build_network() + + + if(PIPE_MANIFOLD) //manifold + var/obj/machinery/atmospherics/pipe/manifold/M = new( src.loc ) + M.pipe_color = color + M.set_dir(dir) + M.initialize_directions = pipe_dir + //M.New() + var/turf/T = M.loc + M.level = !T.is_plating() ? 2 : 1 + M.atmos_init() + if (QDELETED(M)) + to_chat(usr, pipefailtext) + return 1 + M.build_network() + if (M.node1) + M.node1.atmos_init() + M.node1.build_network() + if (M.node2) + M.node2.atmos_init() + M.node2.build_network() + if (M.node3) + M.node3.atmos_init() + M.node3.build_network() + + if(PIPE_SUPPLY_MANIFOLD) //manifold + var/obj/machinery/atmospherics/pipe/manifold/hidden/supply/M = new( src.loc ) + M.color = color + M.set_dir(dir) + M.initialize_directions = pipe_dir + //M.New() + var/turf/T = M.loc + M.level = !T.is_plating() ? 2 : 1 + M.atmos_init() + if (!M) + to_chat(usr, "There's nothing to connect this manifold to! (with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)") + return 1 + M.build_network() + if (M.node1) + M.node1.atmos_init() + M.node1.build_network() + if (M.node2) + M.node2.atmos_init() + M.node2.build_network() + if (M.node3) + M.node3.atmos_init() + M.node3.build_network() + + if(PIPE_SCRUBBERS_MANIFOLD) //manifold + var/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers/M = new( src.loc ) + M.color = color + M.set_dir(dir) + M.initialize_directions = pipe_dir + //M.New() + var/turf/T = M.loc + M.level = !T.is_plating() ? 2 : 1 + M.atmos_init() + if (!M) + to_chat(usr, "There's nothing to connect this manifold to! (with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)") + return 1 + M.build_network() + if (M.node1) + M.node1.atmos_init() + M.node1.build_network() + if (M.node2) + M.node2.atmos_init() + M.node2.build_network() + if (M.node3) + M.node3.atmos_init() + M.node3.build_network() + + if(PIPE_FUEL_MANIFOLD) //manifold + var/obj/machinery/atmospherics/pipe/manifold/hidden/fuel/M = new( src.loc ) + M.color = color + M.set_dir(dir) + M.initialize_directions = pipe_dir + //M.New() + var/turf/T = M.loc + M.level = !T.is_plating() ? 2 : 1 + M.atmos_init() + if (!M) + to_chat(usr, "There's nothing to connect this manifold to! (with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)") + return 1 + M.build_network() + if (M.node1) + M.node1.atmos_init() + M.node1.build_network() + if (M.node2) + M.node2.atmos_init() + M.node2.build_network() + if (M.node3) + M.node3.atmos_init() + M.node3.build_network() + + if(PIPE_MANIFOLD4W) //4-way manifold + var/obj/machinery/atmospherics/pipe/manifold4w/M = new( src.loc ) + M.pipe_color = color + M.set_dir(dir) + M.initialize_directions = pipe_dir + //M.New() + var/turf/T = M.loc + M.level = !T.is_plating() ? 2 : 1 + M.atmos_init() + if (QDELETED(M)) + to_chat(usr, pipefailtext) + return 1 + M.build_network() + if (M.node1) + M.node1.atmos_init() + M.node1.build_network() + if (M.node2) + M.node2.atmos_init() + M.node2.build_network() + if (M.node3) + M.node3.atmos_init() + M.node3.build_network() + if (M.node4) + M.node4.atmos_init() + M.node4.build_network() + + if(PIPE_SUPPLY_MANIFOLD4W) //4-way manifold + var/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply/M = new( src.loc ) + M.color = color + M.set_dir(dir) + M.initialize_directions = pipe_dir + M.connect_types = src.connect_types + //M.New() + var/turf/T = M.loc + M.level = !T.is_plating() ? 2 : 1 + M.atmos_init() + if (!M) + to_chat(usr, "There's nothing to connect this manifold to! (with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)") + return 1 + M.build_network() + if (M.node1) + M.node1.atmos_init() + M.node1.build_network() + if (M.node2) + M.node2.atmos_init() + M.node2.build_network() + if (M.node3) + M.node3.atmos_init() + M.node3.build_network() + if (M.node4) + M.node4.atmos_init() + M.node4.build_network() + + if(PIPE_SCRUBBERS_MANIFOLD4W) //4-way manifold + var/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers/M = new( src.loc ) + M.color = color + M.set_dir(dir) + M.initialize_directions = pipe_dir + M.connect_types = src.connect_types + //M.New() + var/turf/T = M.loc + M.level = !T.is_plating() ? 2 : 1 + M.atmos_init() + if (!M) + to_chat(usr, "There's nothing to connect this manifold to! (with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)") + return 1 + M.build_network() + if (M.node1) + M.node1.atmos_init() + M.node1.build_network() + if (M.node2) + M.node2.atmos_init() + M.node2.build_network() + if (M.node3) + M.node3.atmos_init() + M.node3.build_network() + if (M.node4) + M.node4.atmos_init() + M.node4.build_network() + + if(PIPE_FUEL_MANIFOLD4W) //4-way manifold + var/obj/machinery/atmospherics/pipe/manifold4w/hidden/fuel/M = new( src.loc ) + M.color = color + M.set_dir(dir) + M.initialize_directions = pipe_dir + M.connect_types = src.connect_types + //M.New() + var/turf/T = M.loc + M.level = !T.is_plating() ? 2 : 1 + M.atmos_init() + if (!M) + to_chat(usr, "There's nothing to connect this manifold to! (with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)") + return 1 + M.build_network() + if (M.node1) + M.node1.atmos_init() + M.node1.build_network() + if (M.node2) + M.node2.atmos_init() + M.node2.build_network() + if (M.node3) + M.node3.atmos_init() + M.node3.build_network() + if (M.node4) + M.node4.atmos_init() + M.node4.build_network() + + if(PIPE_JUNCTION) + var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/P = new ( src.loc ) + P.set_dir(src.dir) + P.initialize_directions = src.get_pdir() | src.get_hdir() + P.initialize_directions_he = src.get_hdir() + P.atmos_init() + if (QDELETED(P)) + to_chat(usr, pipefailtext)//"There's nothing to connect this pipe to! (with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)" + + return 1 + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + + if(PIPE_UVENT) //unary vent + var/obj/machinery/atmospherics/unary/vent_pump/V = new( src.loc ) + V.set_dir(dir) + V.initialize_directions = pipe_dir + if (pipename) + V.SetName(pipename) + var/turf/T = V.loc + V.level = !T.is_plating() ? 2 : 1 + V.atmos_init() + V.build_network() + if (V.node) + V.node.atmos_init() + V.node.build_network() + + + if(PIPE_MVALVE) //manual valve + var/obj/machinery/atmospherics/valve/V = new( src.loc) + V.set_dir(dir) + V.initialize_directions = pipe_dir + if (pipename) + V.SetName(pipename) + var/turf/T = V.loc + V.level = !T.is_plating() ? 2 : 1 + V.atmos_init() + V.build_network() + if (V.node1) +// log_error("[V.node1.name] is connected to valve, forcing it to update its nodes.") + V.node1.atmos_init() + V.node1.build_network() + if (V.node2) +// log_error("[V.node2.name] is connected to valve, forcing it to update its nodes.") + V.node2.atmos_init() + V.node2.build_network() + + if(PIPE_DVALVE) //digital valve + var/obj/machinery/atmospherics/valve/digital/D = new( src.loc) + D.set_dir(dir) + D.initialize_directions = pipe_dir + if (pipename) + D.SetName(pipename) + var/turf/T = D.loc + D.level = !T.is_plating() ? 2 : 1 + D.atmos_init() + D.build_network() + if (D.node1) + D.node1.atmos_init() + D.node1.build_network() + if (D.node2) + D.node2.atmos_init() + D.node2.build_network() + + if(PIPE_SVALVE) //shutoff valve + var/obj/machinery/atmospherics/valve/shutoff/S = new( src.loc) + S.set_dir(dir) + S.initialize_directions = pipe_dir + if (pipename) + S.SetName(pipename) + var/turf/T = S.loc + S.level = !T.is_plating() ? 2 : 1 + S.atmos_init() + S.build_network() + if (S.node1) + S.node1.atmos_init() + S.node1.build_network() + if (S.node2) + S.node2.atmos_init() + S.node2.build_network() + + + if(PIPE_PUMP) //gas pump + var/obj/machinery/atmospherics/binary/pump/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + + if(PIPE_GAS_FILTER) //gas filter + var/obj/machinery/atmospherics/trinary/filter/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + if (P.node3) + P.node3.atmos_init() + P.node3.build_network() + + if(PIPE_GAS_MIXER) //gas mixer + var/obj/machinery/atmospherics/trinary/mixer/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + if (P.node3) + P.node3.atmos_init() + P.node3.build_network() + + if(PIPE_GAS_FILTER_M) //gas filter mirrored + var/obj/machinery/atmospherics/trinary/filter/m_filter/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + if (P.node3) + P.node3.atmos_init() + P.node3.build_network() + + if(PIPE_GAS_MIXER_T) //gas mixer-t + var/obj/machinery/atmospherics/trinary/mixer/t_mixer/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + if (P.node3) + P.node3.atmos_init() + P.node3.build_network() + + if(PIPE_GAS_MIXER_M) //gas mixer mirrored + var/obj/machinery/atmospherics/trinary/mixer/m_mixer/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + if (P.node3) + P.node3.atmos_init() + P.node3.build_network() + + if(PIPE_SCRUBBER) //scrubber + var/obj/machinery/atmospherics/unary/vent_scrubber/S = new(src.loc) + S.set_dir(dir) + S.initialize_directions = pipe_dir + if (pipename) + S.SetName(pipename) + var/turf/T = S.loc + S.level = !T.is_plating() ? 2 : 1 + S.atmos_init() + S.build_network() + if (S.node) + S.node.atmos_init() + S.node.build_network() + + if(PIPE_MTVALVE) //manual t-valve + var/obj/machinery/atmospherics/tvalve/V = new(src.loc) + V.set_dir(dir) + V.initialize_directions = pipe_dir + if (pipename) + V.SetName(pipename) + var/turf/T = V.loc + V.level = !T.is_plating() ? 2 : 1 + V.atmos_init() + V.build_network() + if (V.node1) + V.node1.atmos_init() + V.node1.build_network() + if (V.node2) + V.node2.atmos_init() + V.node2.build_network() + if (V.node3) + V.node3.atmos_init() + V.node3.build_network() + + if(PIPE_MTVALVEM) //manual t-valve + var/obj/machinery/atmospherics/tvalve/mirrored/V = new(src.loc) + V.set_dir(dir) + V.initialize_directions = pipe_dir + if (pipename) + V.SetName(pipename) + var/turf/T = V.loc + V.level = !T.is_plating() ? 2 : 1 + V.atmos_init() + V.build_network() + if (V.node1) + V.node1.atmos_init() + V.node1.build_network() + if (V.node2) + V.node2.atmos_init() + V.node2.build_network() + if (V.node3) + V.node3.atmos_init() + V.node3.build_network() + + if(PIPE_CAP) + var/obj/machinery/atmospherics/pipe/cap/C = new(src.loc) + C.set_dir(dir) + C.initialize_directions = pipe_dir + C.atmos_init() + C.build_network() + if(C.node) + C.node.atmos_init() + C.node.build_network() + + if(PIPE_SUPPLY_CAP) + var/obj/machinery/atmospherics/pipe/cap/hidden/supply/C = new(src.loc) + C.set_dir(dir) + C.initialize_directions = pipe_dir + C.atmos_init() + C.build_network() + if(C.node) + C.node.atmos_init() + C.node.build_network() + + if(PIPE_SCRUBBERS_CAP) + var/obj/machinery/atmospherics/pipe/cap/hidden/scrubbers/C = new(src.loc) + C.set_dir(dir) + C.initialize_directions = pipe_dir + C.atmos_init() + C.build_network() + if(C.node) + C.node.atmos_init() + C.node.build_network() + + if(PIPE_FUEL_CAP) + var/obj/machinery/atmospherics/pipe/cap/hidden/fuel/C = new(src.loc) + C.set_dir(dir) + C.initialize_directions = pipe_dir + C.atmos_init() + C.build_network() + if(C.node) + C.node.atmos_init() + C.node.build_network() + + if(PIPE_PASSIVE_GATE) //passive gate + var/obj/machinery/atmospherics/binary/passive_gate/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + + if(PIPE_VOLUME_PUMP) //volume pump + var/obj/machinery/atmospherics/binary/pump/high_power/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + + if(PIPE_HEAT_EXCHANGE) // heat exchanger + var/obj/machinery/atmospherics/unary/heat_exchanger/C = new( src.loc ) + C.set_dir(dir) + C.initialize_directions = pipe_dir + if (pipename) + C.SetName(pipename) + var/turf/T = C.loc + C.level = !T.is_plating() ? 2 : 1 + C.atmos_init() + C.build_network() + if (C.node) + C.node.atmos_init() + C.node.build_network() +///// Z-Level stuff + if(PIPE_UP) + var/obj/machinery/atmospherics/pipe/zpipe/up/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + if(PIPE_DOWN) + var/obj/machinery/atmospherics/pipe/zpipe/down/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + if(PIPE_SUPPLY_UP) + var/obj/machinery/atmospherics/pipe/zpipe/up/supply/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + if(PIPE_SUPPLY_DOWN) + var/obj/machinery/atmospherics/pipe/zpipe/down/supply/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + if(PIPE_SCRUBBERS_UP) + var/obj/machinery/atmospherics/pipe/zpipe/up/scrubbers/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + if(PIPE_SCRUBBERS_DOWN) + var/obj/machinery/atmospherics/pipe/zpipe/down/scrubbers/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + + if(PIPE_FUEL_UP) + var/obj/machinery/atmospherics/pipe/zpipe/up/fuel/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() + if(PIPE_FUEL_DOWN) + var/obj/machinery/atmospherics/pipe/zpipe/down/fuel/P = new(src.loc) + P.set_dir(dir) + P.initialize_directions = pipe_dir + if (pipename) + P.SetName(pipename) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if (P.node1) + P.node1.atmos_init() + P.node1.build_network() + if (P.node2) + P.node2.atmos_init() + P.node2.build_network() +///// Z-Level stuff + if(PIPE_OMNI_MIXER) + var/obj/machinery/atmospherics/omni/mixer/P = new(loc) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + if(PIPE_OMNI_FILTER) + var/obj/machinery/atmospherics/omni/filter/P = new(loc) + var/turf/T = P.loc + P.level = !T.is_plating() ? 2 : 1 + P.atmos_init() + P.build_network() + + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + user.visible_message( \ + "[user] fastens the [src].", \ + "You have fastened the [src].", \ + "You hear ratchet.") + qdel(src) // remove the pipe item + + return + //TODO: DEFERRED + +// ensure that setterm() is called for a newly connected pipeline + + + +/obj/item/pipe_meter + name = "meter" + desc = "A meter that can be laid on pipes." + icon = 'icons/obj/pipe-item.dmi' + icon_state = "meter" + item_state = "buildpipe" + w_class = ITEM_SIZE_LARGE + +/obj/item/pipe_meter/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + ..() + + if(!isWrench(W)) + return ..() + if(!locate(/obj/machinery/atmospherics/pipe, src.loc)) + to_chat(user, "You need to fasten it to a pipe") + return 1 + new/obj/machinery/meter( src.loc ) + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You have fastened the meter to the pipe") + qdel(src) +//not sure why these are necessary +#undef PIPE_SIMPLE_STRAIGHT +#undef PIPE_SIMPLE_BENT +#undef PIPE_HE_STRAIGHT +#undef PIPE_HE_BENT +#undef PIPE_CONNECTOR +#undef PIPE_MANIFOLD +#undef PIPE_JUNCTION +#undef PIPE_UVENT +#undef PIPE_MVALVE +#undef PIPE_DVALVE +#undef PIPE_SVALVE +#undef PIPE_PUMP +#undef PIPE_SCRUBBER +#undef PIPE_GAS_FILTER +#undef PIPE_GAS_MIXER +#undef PIPE_PASSIVE_GATE +#undef PIPE_VOLUME_PUMP +//#undef PIPE_OUTLET_INJECT +#undef PIPE_MTVALVE +#undef PIPE_MTVALVEM +#undef PIPE_GAS_FILTER_M +#undef PIPE_GAS_MIXER_T +#undef PIPE_GAS_MIXER_M +#undef PIPE_SUPPLY_STRAIGHT +#undef PIPE_SUPPLY_BENT +#undef PIPE_SCRUBBERS_STRAIGHT +#undef PIPE_SCRUBBERS_BENT +#undef PIPE_SUPPLY_MANIFOLD +#undef PIPE_SCRUBBERS_MANIFOLD +#undef PIPE_UNIVERSAL +//#undef PIPE_MANIFOLD4W diff --git a/code/game/machinery/pipe/pipe_dispenser.dm b/code/game/machinery/pipe/pipe_dispenser.dm new file mode 100644 index 00000000..046c22ba --- /dev/null +++ b/code/game/machinery/pipe/pipe_dispenser.dm @@ -0,0 +1,272 @@ +/obj/machinery/pipedispenser + name = "Pipe Dispenser" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "pipe_d" + density = 1 + anchored = 1 + var/unwrenched = 0 + var/wait = 0 + +/obj/machinery/pipedispenser/attack_hand(user as mob) + if(..()) + return +///// Z-Level stuff + var/dat = {" +Regular pipes:
            +Pipe
            +Bent Pipe
            +Manifold
            +Manual Valve
            +Digital Valve
            +Automatic Shutoff Valve
            +Pipe Cap
            +4-Way Manifold
            +Manual T-Valve
            +Manual T-Valve - Mirrored
            +Upward Pipe
            +Downward Pipe
            +Supply pipes:
            +Pipe
            +Bent Pipe
            +Manifold
            +Pipe Cap
            +4-Way Manifold
            +Upward Pipe
            +Downward Pipe
            +Scrubbers pipes:
            +Pipe
            +Bent Pipe
            +Manifold
            +Pipe Cap
            +4-Way Manifold
            +Upward Pipe
            +Downward Pipe
            +Fuel pipes:
            +Pipe
            +Bent Pipe
            +Manifold
            +Pipe Cap
            +4-Way Manifold
            +Upward Pipe
            +Downward Pipe
            +Devices:
            +Universal pipe adapter
            +Connector
            +Unary Vent
            +Gas Pump
            +Pressure Regulator
            +High Power Gas Pump
            +Scrubber
            +Meter
            +Gas Filter
            +Gas Filter - Mirrored
            +Gas Mixer
            +Gas Mixer - Mirrored
            +Gas Mixer - T
            +Omni Gas Mixer
            +Omni Gas Filter
            +Heat exchange:
            +Pipe
            +Bent Pipe
            +Junction
            +Heat Exchanger
            + +"} +///// Z-Level stuff +//What number the make points to is in the define # at the top of construction.dm in same folder + + user << browse("[src][dat]", "window=pipedispenser") + onclose(user, "pipedispenser") + return + +/obj/machinery/pipedispenser/Topic(href, href_list) + if(..()) + return + if(unwrenched || !usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) + usr << browse(null, "window=pipedispenser") + return + usr.set_machine(src) + if(href_list["make"]) + if(!wait) + var/p_type = text2num(href_list["make"]) + var/p_dir = text2num(href_list["dir"]) + var/obj/item/pipe/P = new (/*usr.loc*/ src.loc, pipe_type=p_type, dir=p_dir) + P.update() + wait = 1 + spawn(10) + wait = 0 + if(href_list["makemeter"]) + if(!wait) + new /obj/item/pipe_meter(/*usr.loc*/ src.loc) + wait = 1 + spawn(15) + wait = 0 + return + +/obj/machinery/pipedispenser/attackby(var/obj/item/W as obj, var/mob/user as mob) + if (istype(W, /obj/item/pipe) || istype(W, /obj/item/pipe_meter)) + to_chat(usr, "You put \the [W] back into \the [src].") + user.drop_item() + add_fingerprint(usr) + qdel(W) + return + else if(isWrench(W)) + add_fingerprint(usr) + if (unwrenched==0) + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to unfasten \the [src] from the floor...") + if (do_after(user, 40, src)) + user.visible_message( \ + "\The [user] unfastens \the [src].", \ + "You have unfastened \the [src]. Now it can be pulled somewhere else.", \ + "You hear ratchet.") + src.anchored = 0 + src.stat |= MAINT + src.unwrenched = 1 + if (usr.machine==src) + usr << browse(null, "window=pipedispenser") + else /*if (unwrenched==1)*/ + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to fasten \the [src] to the floor...") + if (do_after(user, 20, src)) + user.visible_message( \ + "\The [user] fastens \the [src].", \ + "You have fastened \the [src]. Now it can dispense pipes.", \ + "You hear ratchet.") + src.anchored = 1 + src.stat &= ~MAINT + src.unwrenched = 0 + power_change() + else + return ..() + +/obj/machinery/pipedispenser/disposal + name = "Disposal Pipe Dispenser" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "pipe_d" + density = 1 + anchored = 1.0 + +/* +//Allow you to push disposal pipes into it (for those with density 1) +/obj/machinery/pipedispenser/disposal/Crossed(var/obj/structure/disposalconstruct/pipe as obj) + if(istype(pipe) && !pipe.anchored) + qdel(pipe) + +Nah +*/ + +//Allow you to drag-drop disposal pipes into it +/obj/machinery/pipedispenser/disposal/MouseDrop_T(var/obj/structure/disposalconstruct/pipe as obj, mob/usr as mob) + if(!usr.canmove || usr.stat || usr.restrained()) + return + + if (!istype(pipe) || get_dist(usr, src) > 1 || get_dist(src,pipe) > 1 ) + return + + if (pipe.anchored) + return + + qdel(pipe) + +/obj/machinery/pipedispenser/disposal/attack_hand(user as mob) + if(..()) + return + +///// Z-Level stuff + var/dat = {"Disposal Pipes

            +Pipe
            +Bent Pipe
            +Junction
            +Y-Junction
            +Trunk
            +Bin
            +Outlet
            +Chute
            +Upwards
            +Downwards
            +Sorting
            +Sorting (Wildcard)
            +Sorting (Untagged)
            +Tagger
            +Tagger (Partial)
            +Diversion
            +Diversion Switch
            +"} +///// Z-Level stuff + + user << browse("[src][dat]", "window=pipedispenser") + return + +// 0=straight, 1=bent, 2=junction-j1, 3=junction-j2, 4=junction-y, 5=trunk + + +/obj/machinery/pipedispenser/disposal/Topic(href, href_list) + if(..()) + return + usr.set_machine(src) + if(href_list["dmake"]) + if(unwrenched || !usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) + usr << browse(null, "window=pipedispenser") + return + if(!wait) + var/p_type = text2num(href_list["dmake"]) + if(p_type == 15) + new /obj/machinery/disposal_switch (get_turf(src)) + else + var/obj/structure/disposalconstruct/C = new (src.loc) + switch(p_type) + if(0) + C.ptype = 0 + if(1) + C.ptype = 1 + if(2) + C.ptype = 2 + if(3) + C.ptype = 4 + if(4) + C.ptype = 5 + if(5) + C.ptype = 6 + C.set_density(1) + if(6) + C.ptype = 7 + C.set_density(1) + if(7) + C.ptype = 8 + C.set_density(1) + if(8) + C.ptype = 9 + C.subtype = 0 + if(9) + C.ptype = 9 + C.subtype = 1 + if(10) + C.ptype = 9 + C.subtype = 2 + if(11) + C.ptype = 13 + if(12) + C.ptype = 14 + if(13) + C.ptype = 15 +///// Z-Level stuff + if(21) + C.ptype = 11 + if(22) + C.ptype = 12 +///// Z-Level stuff + C.update() + wait = 1 + spawn(15) + wait = 0 + return + +// adding a pipe dispensers that spawn unhooked from the ground +/obj/machinery/pipedispenser/orderable + anchored = 0 + unwrenched = 1 + +/obj/machinery/pipedispenser/disposal/orderable + anchored = 0 + unwrenched = 1 diff --git a/code/game/machinery/pipe/pipelayer.dm b/code/game/machinery/pipe/pipelayer.dm new file mode 100644 index 00000000..1043a521 --- /dev/null +++ b/code/game/machinery/pipe/pipelayer.dm @@ -0,0 +1,135 @@ +/obj/machinery/pipelayer + + name = "automatic pipe layer" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "pipe_d" + density = 1 + var/turf/old_turf + var/old_dir + var/on = 0 + var/a_dis = 0 + var/P_type = 0 + var/P_type_t = "" + var/max_metal = 50 + var/metal = 10 + var/obj/item/weapon/wrench/W + var/list/Pipes = list("regular pipes"=0,"scrubbers pipes"=31,"supply pipes"=29,"heat exchange pipes"=2, "fuel pipes"=45) + +/obj/machinery/pipelayer/New() + W = new(src) + ..() + +/obj/machinery/pipelayer/Move(new_turf,M_Dir) + ..() + + if(on && a_dis) + dismantleFloor(old_turf) + layPipe(old_turf,M_Dir,old_dir) + + old_turf = new_turf + old_dir = turn(M_Dir,180) + +/obj/machinery/pipelayer/attack_hand(mob/user as mob) + if(!metal&&!on) + to_chat(user, "\The [src] doesn't work without metal.") + return + on=!on + user.visible_message("[user] has [!on?"de":""]activated \the [src].", "You [!on?"de":""]activate \the [src].") + return + +/obj/machinery/pipelayer/attackby(var/obj/item/W as obj, var/mob/user as mob) + + if(isWrench(W)) + P_type_t = input("Choose pipe type", "Pipe type") as null|anything in Pipes + P_type = Pipes[P_type_t] + user.visible_message("[user] has set \the [src] to manufacture [P_type_t].", "You set \the [src] to manufacture [P_type_t].") + return + + if(isCrowbar(W)) + a_dis=!a_dis + user.visible_message("[user] has [!a_dis?"de":""]activated auto-dismantling.", "You [!a_dis?"de":""]activate auto-dismantling.") + return + + if(istype(W, /obj/item/stack/material) && W.get_material_name() == DEFAULT_WALL_MATERIAL) + + var/result = load_metal(W) + if(isnull(result)) + to_chat(user, "Unable to load [W] - no metal found.") + else if(!result) + to_chat(user, "\The [src] is full.") + else + user.visible_message("[user] has loaded metal into \the [src].", "You load metal into \the [src]") + + return + + if(isScrewdriver(W)) + if(metal) + var/m = round(input(usr,"Please specify the amount of metal to remove","Remove metal",min(round(metal),50)) as num, 1) + m = min(m, 50) + m = min(m, round(metal)) + m = round(m) + if(m) + use_metal(m) + var/obj/item/stack/material/steel/MM = new (get_turf(src)) + MM.amount = m + user.visible_message("[user] removes [m] sheet\s of metal from the \the [src].", "You remove [m] sheet\s of metal from \the [src]") + else + to_chat(user, "\The [src] is empty.") + return + ..() + +/obj/machinery/pipelayer/examine(mob/user) + . = ..() + to_chat(user, "\The [src] has [metal] sheet\s, is set to produce [P_type_t], and auto-dismantling is [!a_dis?"de":""]activated.") + +/obj/machinery/pipelayer/proc/reset() + on=0 + return + +/obj/machinery/pipelayer/proc/load_metal(var/obj/item/stack/MM) + if(istype(MM) && MM.get_amount()) + var/cur_amount = metal + var/to_load = max(max_metal - round(cur_amount),0) + if(to_load) + to_load = min(MM.get_amount(), to_load) + metal += to_load + MM.use(to_load) + return to_load + else + return 0 + return + +/obj/machinery/pipelayer/proc/use_metal(amount) + if(!metal || metalThere seems to be a firewall preventing you from accessing this device.") + return 1 + + if(locked && !issilicon(user)) + to_chat(user, "Access denied.") + return 1 + + return 0 + +/obj/machinery/porta_turret/attack_ai(mob/user) + if(isLocked(user)) + return + + ui_interact(user) + +/obj/machinery/porta_turret/attack_hand(mob/user) + if(isLocked(user)) + return + + ui_interact(user) + +/obj/machinery/porta_turret/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + data["access"] = !isLocked(user) + data["locked"] = locked + data["enabled"] = enabled + data["is_lethal"] = 1 + data["lethal"] = lethal + + if(data["access"]) + var/settings[0] + settings[++settings.len] = list("category" = "Neutralize All Non-Synthetics", "setting" = "check_synth", "value" = check_synth) + settings[++settings.len] = list("category" = "Check Weapon Authorization", "setting" = "check_weapons", "value" = check_weapons) + settings[++settings.len] = list("category" = "Check Security Records", "setting" = "check_records", "value" = check_records) + settings[++settings.len] = list("category" = "Check Arrest Status", "setting" = "check_arrest", "value" = check_arrest) + settings[++settings.len] = list("category" = "Check Access Authorization", "setting" = "check_access", "value" = check_access) + settings[++settings.len] = list("category" = "Check misc. Lifeforms", "setting" = "check_anomalies", "value" = check_anomalies) + data["settings"] = settings + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 300) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/porta_turret/proc/HasController() + var/area/A = get_area(src) + return A && A.turret_controls.len > 0 + +/obj/machinery/porta_turret/CanUseTopic(var/mob/user) + if(HasController()) + to_chat(user, "Turrets can only be controlled using the assigned turret controller.") + return STATUS_CLOSE + + if(isLocked(user)) + return STATUS_CLOSE + + if(!anchored) + to_chat(usr, "\The [src] has to be secured first!") + return STATUS_CLOSE + + return ..() + + +/obj/machinery/porta_turret/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["command"] && href_list["value"]) + var/value = text2num(href_list["value"]) + if(href_list["command"] == "enable") + enabled = value + else if(href_list["command"] == "lethal") + lethal = value + else if(href_list["command"] == "check_synth") + check_synth = value + else if(href_list["command"] == "check_weapons") + check_weapons = value + else if(href_list["command"] == "check_records") + check_records = value + else if(href_list["command"] == "check_arrest") + check_arrest = value + else if(href_list["command"] == "check_access") + check_access = value + else if(href_list["command"] == "check_anomalies") + check_anomalies = value + + return 1 + +/obj/machinery/porta_turret/power_change() + if(powered()) + stat &= ~NOPOWER + update_icon() + else + spawn(rand(0, 15)) + stat |= NOPOWER + update_icon() + + +/obj/machinery/porta_turret/attackby(obj/item/I, mob/user) + if(stat & BROKEN) + if(isCrowbar(I)) + //If the turret is destroyed, you can remove it with a crowbar to + //try and salvage its components + to_chat(user, "You begin prying the metal coverings off.") + if(do_after(user, 20, src)) + if(prob(70)) + to_chat(user, "You remove the turret and salvage some components.") + if(installation) + var/obj/item/weapon/gun/energy/Gun = new installation(loc) + Gun.power_supply.charge = gun_charge + Gun.update_icon() + if(prob(50)) + new /obj/item/stack/material/steel(loc, rand(1,4)) + if(prob(50)) + new /obj/item/device/assembly/prox_sensor(loc) + else + to_chat(user, "You remove the turret but did not manage to salvage anything.") + qdel(src) // qdel + + else if(isWrench(I)) + if(enabled || raised) + to_chat(user, "You cannot unsecure an active turret!") + return + if(wrenching) + to_chat(user, "Someone is already [anchored ? "un" : ""]securing the turret!") + return + if(!anchored && isinspace()) + to_chat(user, "Cannot secure turrets in space!") + return + + user.visible_message( \ + "[user] begins [anchored ? "un" : ""]securing the turret.", \ + "You begin [anchored ? "un" : ""]securing the turret." \ + ) + + wrenching = 1 + if(do_after(user, 50, src)) + //This code handles moving the turret around. After all, it's a portable turret! + if(!anchored) + playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) + anchored = 1 + update_icon() + to_chat(user, "You secure the exterior bolts on the turret.") + else if(anchored) + playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) + anchored = 0 + to_chat(user, "You unsecure the exterior bolts on the turret.") + update_icon() + wrenching = 0 + + else if(istype(I, /obj/item/weapon/card/id)||istype(I, /obj/item/device/pda)) + //Behavior lock/unlock mangement + if(allowed(user)) + locked = !locked + to_chat(user, "Controls are now [locked ? "locked" : "unlocked"].") + updateUsrDialog() + else + to_chat(user, "Access denied.") + + else + //if the turret was attacked with the intention of harming it: + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + take_damage(I.force * 0.5) + if(I.force * 0.5 > 1) //if the force of impact dealt at least 1 damage, the turret gets pissed off + if(!attacked && !emagged) + attacked = 1 + spawn() + sleep(60) + attacked = 0 + ..() + +/obj/machinery/porta_turret/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + //Emagging the turret makes it go bonkers and stun everyone. It also makes + //the turret shoot much, much faster. + to_chat(user, "You short out [src]'s threat assessment circuits.") + visible_message("[src] hums oddly...") + emagged = 1 + iconholder = 1 + controllock = 1 + enabled = 0 //turns off the turret temporarily + sleep(60) //6 seconds for the traitor to gtfo of the area before the turret decides to ruin his shit + enabled = 1 //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here + return 1 + +/obj/machinery/porta_turret/proc/take_damage(var/force) + if(!raised && !raising) + force = force / 8 + if(force < 5) + return + + health -= force + if (force > 5 && prob(45)) + spark_system.start() + if(health <= 0) + die() //the death process :( + +/obj/machinery/porta_turret/bullet_act(obj/item/projectile/Proj) + var/damage = Proj.get_structure_damage() + + if(!damage) + return + + if(enabled) + if(!attacked && !emagged) + attacked = 1 + spawn() + sleep(60) + attacked = 0 + + ..() + + take_damage(damage) + +/obj/machinery/porta_turret/emp_act(severity) + if(enabled) + //if the turret is on, the EMP no matter how severe disables the turret for a while + //and scrambles its settings, with a slight chance of having an emag effect + check_arrest = prob(50) + check_records = prob(50) + check_weapons = prob(50) + check_access = prob(20) // check_access is a pretty big deal, so it's least likely to get turned on + check_anomalies = prob(50) + if(prob(5)) + emagged = 1 + + enabled=0 + spawn(rand(60,600)) + if(!enabled) + enabled=1 + + ..() + +/obj/machinery/porta_turret/ex_act(severity) + switch (severity) + if (1) + qdel(src) + if (2) + if (prob(25)) + qdel(src) + else + take_damage(initial(health) * 8) //should instakill most turrets + if (3) + take_damage(initial(health) * 8 / 3) + +/obj/machinery/porta_turret/proc/die() //called when the turret dies, ie, health <= 0 + health = 0 + stat |= BROKEN //enables the BROKEN bit + spark_system.start() //creates some sparks because they look cool + update_icon() + +/obj/machinery/porta_turret/Process() + //the main machinery process + + if(stat & (NOPOWER|BROKEN)) + //if the turret has no power or is broken, make the turret pop down if it hasn't already + popDown() + return + + if(!enabled) + //if the turret is off, make it pop down + popDown() + return + + var/list/targets = list() //list of primary targets + var/list/secondarytargets = list() //targets that are least important + + for(var/mob/M in mobs_in_view(world.view, src)) + assess_and_assign(M, targets, secondarytargets) + + if(!tryToShootAt(targets)) + if(!tryToShootAt(secondarytargets)) // if no valid targets, go for secondary targets + spawn() + popDown() // no valid targets, close the cover + + if(auto_repair && (health < maxhealth)) + use_power(20000) + health = min(health+1, maxhealth) // 1HP for 20kJ + +/obj/machinery/porta_turret/proc/assess_and_assign(var/mob/living/L, var/list/targets, var/list/secondarytargets) + switch(assess_living(L)) + if(TURRET_PRIORITY_TARGET) + targets += L + if(TURRET_SECONDARY_TARGET) + secondarytargets += L + +/obj/machinery/porta_turret/proc/assess_living(var/mob/living/L) + if(!istype(L)) + return TURRET_NOT_TARGET + + if(L.invisibility >= INVISIBILITY_LEVEL_ONE) // Cannot see him. see_invisible is a mob-var + return TURRET_NOT_TARGET + + if(!L) + return TURRET_NOT_TARGET + + if(!emagged && issilicon(L)) // Don't target silica + return TURRET_NOT_TARGET + + if(L.stat && !emagged) //if the perp is dead/dying, no need to bother really + return TURRET_NOT_TARGET //move onto next potential victim! + + if(get_dist(src, L) > 7) //if it's too far away, why bother? + return TURRET_NOT_TARGET + + if(!check_trajectory(L, src)) //check if we have true line of sight + return TURRET_NOT_TARGET + + if(emagged) // If emagged not even the dead get a rest + return L.stat ? TURRET_SECONDARY_TARGET : TURRET_PRIORITY_TARGET + + if(lethal && locate(/mob/living/silicon/ai) in get_turf(L)) //don't accidentally kill the AI! + return TURRET_NOT_TARGET + + if(check_synth) //If it's set to attack all non-silicons, target them! + if(L.lying) + return lethal ? TURRET_SECONDARY_TARGET : TURRET_NOT_TARGET + return TURRET_PRIORITY_TARGET + + if(iscuffed(L)) // If the target is handcuffed, leave it alone + return TURRET_NOT_TARGET + + if(isanimal(L) || issmall(L)) // Animals are not so dangerous + return check_anomalies ? TURRET_SECONDARY_TARGET : TURRET_NOT_TARGET + + /*if(isxenomorph(L) || isalien(L)) // Xenos are dangerous + return check_anomalies ? TURRET_PRIORITY_TARGET : TURRET_NOT_TARGET + */ + + if(ishuman(L)) //if the target is a human, analyze threat level + if(assess_perp(L) < 4) + return TURRET_NOT_TARGET //if threat level < 4, keep going + + if(L.lying) //if the perp is lying down, it's still a target but a less-important target + return lethal ? TURRET_SECONDARY_TARGET : TURRET_NOT_TARGET + + return TURRET_PRIORITY_TARGET //if the perp has passed all previous tests, congrats, it is now a "shoot-me!" nominee + +/obj/machinery/porta_turret/proc/assess_perp(var/mob/living/carbon/human/H) + if(!H || !istype(H)) + return 0 + + if(emagged) + return 10 + + return H.assess_perp(src, check_access, check_weapons, check_records, check_arrest) + +/obj/machinery/porta_turret/proc/tryToShootAt(var/list/mob/living/targets) + if(targets.len && last_target && (last_target in targets) && target(last_target)) + return 1 + + while(targets.len > 0) + var/mob/living/M = pick(targets) + targets -= M + if(target(M)) + return 1 + + +/obj/machinery/porta_turret/proc/popUp() //pops the turret up + if(disabled) + return + if(raising || raised) + return + if(stat & BROKEN) + return + set_raised_raising(raised, 1) + update_icon() + + var/atom/flick_holder = new /atom/movable/porta_turret_cover(loc) + flick_holder.layer = layer + 0.1 + flick("popup", flick_holder) + sleep(10) + qdel(flick_holder) + + set_raised_raising(1, 0) + update_icon() + +/obj/machinery/porta_turret/proc/popDown() //pops the turret down + last_target = null + if(disabled) + return + if(raising || !raised) + return + if(stat & BROKEN) + return + set_raised_raising(raised, 1) + update_icon() + + var/atom/flick_holder = new /atom/movable/porta_turret_cover(loc) + flick_holder.layer = layer + 0.1 + flick("popdown", flick_holder) + sleep(10) + qdel(flick_holder) + + set_raised_raising(0, 0) + update_icon() + +/obj/machinery/porta_turret/proc/set_raised_raising(var/raised, var/raising) + src.raised = raised + src.raising = raising + set_density(raised || raising) + +/obj/machinery/porta_turret/proc/target(var/mob/living/target) + if(disabled) + return + if(target) + last_target = target + spawn() + popUp() //pop the turret up if it's not already up. + set_dir(get_dir(src, target)) //even if you can't shoot, follow the target + spawn() + shootAt(target) + return 1 + return + +/obj/machinery/porta_turret/proc/shootAt(var/mob/living/target) + //any emagged turrets will shoot extremely fast! This not only is deadly, but drains a lot power! + if(!(emagged || attacked)) //if it hasn't been emagged or attacked, it has to obey a cooldown rate + if(last_fired || !raised) //prevents rapid-fire shooting, unless it's been emagged + return + last_fired = 1 + spawn() + sleep(shot_delay) + last_fired = 0 + + var/turf/T = get_turf(src) + var/turf/U = get_turf(target) + if(!istype(T) || !istype(U)) + return + + if(!raised) //the turret has to be raised in order to fire - makes sense, right? + return + + update_icon() + var/obj/item/projectile/A + if(emagged || lethal) + A = new eprojectile(loc) + playsound(loc, eshot_sound, 75, 1) + else + A = new projectile(loc) + playsound(loc, shot_sound, 75, 1) + + // Lethal/emagged turrets use twice the power due to higher energy beams + // Emagged turrets again use twice as much power due to higher firing rates + use_power(reqpower * (2 * (emagged || lethal)) * (2 * emagged)) + + //Turrets aim for the center of mass by default. + //If the target is grabbing someone then the turret smartly aims for extremities + var/def_zone = get_exposed_defense_zone(target) + //Shooting Code: + A.launch_projectile(target, def_zone) + +/datum/turret_checks + var/enabled + var/lethal + var/check_synth + var/check_access + var/check_records + var/check_arrest + var/check_weapons + var/check_anomalies + var/ailock + +/obj/machinery/porta_turret/proc/setState(var/datum/turret_checks/TC) + if(controllock) + return + src.enabled = TC.enabled + src.lethal = TC.lethal + src.iconholder = TC.lethal + + check_synth = TC.check_synth + check_access = TC.check_access + check_records = TC.check_records + check_arrest = TC.check_arrest + check_weapons = TC.check_weapons + check_anomalies = TC.check_anomalies + ailock = TC.ailock + + src.power_change() + +/* + Portable turret constructions + Known as "turret frame"s +*/ + +/obj/machinery/porta_turret_construct + name = "turret frame" + icon = 'icons/obj/turrets.dmi' + icon_state = "turret_frame" + density=1 + var/target_type = /obj/machinery/porta_turret // The type we intend to build + var/build_step = 0 //the current step in the building process + var/finish_name="turret" //the name applied to the product turret + var/installation = null //the gun type installed + var/gun_charge = 0 //the gun charge of the gun type installed + + +/obj/machinery/porta_turret_construct/attackby(obj/item/I, mob/user) + //this is a bit unwieldy but self-explanatory + switch(build_step) + if(0) //first step + if(isWrench(I) && !anchored) + playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) + to_chat(user, "You secure the external bolts.") + anchored = 1 + build_step = 1 + return + + else if(isCrowbar(I) && !anchored) + playsound(loc, 'sound/items/Crowbar.ogg', 75, 1) + to_chat(user, "You dismantle the turret construction.") + new /obj/item/stack/material/steel( loc, 5) + qdel(src) + return + + if(1) + if(istype(I, /obj/item/stack/material) && I.get_material_name() == DEFAULT_WALL_MATERIAL) + var/obj/item/stack/M = I + if(M.use(2)) + to_chat(user, "You add some metal armor to the interior frame.") + build_step = 2 + icon_state = "turret_frame2" + else + to_chat(user, "You need two sheets of metal to continue construction.") + return + + else if(istype(I, /obj/item/weapon/wrench)) + playsound(loc, 'sound/items/Ratchet.ogg', 75, 1) + to_chat(user, "You unfasten the external bolts.") + anchored = 0 + build_step = 0 + return + + + if(2) + if(istype(I, /obj/item/weapon/wrench)) + playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) + to_chat(user, "You bolt the metal armor into place.") + build_step = 3 + return + + else if(isWelder(I)) + var/obj/item/weapon/weldingtool/WT = I + if(!WT.isOn()) + return + if(WT.get_fuel() < 5) //uses up 5 fuel. + to_chat(user, "You need more fuel to complete this task.") + return + + playsound(loc, pick('sound/items/Welder.ogg', 'sound/items/Welder2.ogg'), 50, 1) + if(do_after(user, 20, src)) + if(!src || !WT.remove_fuel(5, user)) return + build_step = 1 + to_chat(user, "You remove the turret's interior metal armor.") + new /obj/item/stack/material/steel( loc, 2) + return + + + if(3) + if(istype(I, /obj/item/weapon/gun/energy)) //the gun installation part + + if(isrobot(user)) + return + var/obj/item/weapon/gun/energy/E = I //typecasts the item to an energy gun + if(!user.unEquip(I)) + to_chat(user, "\the [I] is stuck to your hand, you cannot put it in \the [src]") + return + installation = I.type //installation becomes I.type + gun_charge = E.power_supply.charge //the gun's charge is stored in gun_charge + to_chat(user, "You add [I] to the turret.") + target_type = /obj/machinery/porta_turret + + build_step = 4 + qdel(I) //delete the gun :( + return + + else if(istype(I, /obj/item/weapon/wrench)) + playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) + to_chat(user, "You remove the turret's metal armor bolts.") + build_step = 2 + return + + if(4) + if(isprox(I)) + build_step = 5 + if(!user.unEquip(I)) + to_chat(user, "\the [I] is stuck to your hand, you cannot put it in \the [src]") + return + to_chat(user, "You add the prox sensor to the turret.") + qdel(I) + return + + //attack_hand() removes the gun + + if(5) + if(isScrewdriver(I)) + playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1) + build_step = 6 + to_chat(user, "You close the internal access hatch.") + return + + //attack_hand() removes the prox sensor + + if(6) + if(istype(I, /obj/item/stack/material) && I.get_material_name() == DEFAULT_WALL_MATERIAL) + var/obj/item/stack/M = I + if(M.use(2)) + to_chat(user, "You add some metal armor to the exterior frame.") + build_step = 7 + else + to_chat(user, "You need two sheets of metal to continue construction.") + return + + else if(istype(I, /obj/item/weapon/screwdriver)) + playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1) + build_step = 5 + to_chat(user, "You open the internal access hatch.") + return + + if(7) + if(isWelder(I)) + var/obj/item/weapon/weldingtool/WT = I + if(!WT.isOn()) return + if(WT.get_fuel() < 5) + to_chat(user, "You need more fuel to complete this task.") + + playsound(loc, pick('sound/items/Welder.ogg', 'sound/items/Welder2.ogg'), 50, 1) + if(do_after(user, 30, src)) + if(!src || !WT.remove_fuel(5, user)) + return + build_step = 8 + to_chat(user, "You weld the turret's armor down.") + + //The final step: create a full turret + var/obj/machinery/porta_turret/Turret = new target_type(loc) + Turret.SetName(finish_name) + Turret.installation = installation + Turret.gun_charge = gun_charge + Turret.enabled = 0 + Turret.setup() + + qdel(src) // qdel + + else if(isCrowbar(I)) + playsound(loc, 'sound/items/Crowbar.ogg', 75, 1) + to_chat(user, "You pry off the turret's exterior armor.") + new /obj/item/stack/material/steel(loc, 2) + build_step = 6 + return + + if(istype(I, /obj/item/weapon/pen)) //you can rename turrets like bots! + var/t = sanitizeSafe(input(user, "Enter new turret name", name, finish_name) as text, MAX_NAME_LEN) + if(!t) + return + if(!in_range(src, usr) && loc != usr) + return + + finish_name = t + return + + ..() + + +/obj/machinery/porta_turret_construct/attack_hand(mob/user) + switch(build_step) + if(4) + if(!installation) + return + build_step = 3 + + var/obj/item/weapon/gun/energy/Gun = new installation(loc) + Gun.power_supply.charge = gun_charge + Gun.update_icon() + installation = null + gun_charge = 0 + to_chat(user, "You remove [Gun] from the turret frame.") + + if(5) + to_chat(user, "You remove the prox sensor from the turret frame.") + new /obj/item/device/assembly/prox_sensor(loc) + build_step = 4 + +/obj/machinery/porta_turret_construct/attack_ai() + return + +/atom/movable/porta_turret_cover + icon = 'icons/obj/turrets.dmi' + + + + +#undef TURRET_PRIORITY_TARGET +#undef TURRET_SECONDARY_TARGET +#undef TURRET_NOT_TARGET diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm new file mode 100644 index 00000000..18f37e9c --- /dev/null +++ b/code/game/machinery/recharger.dm @@ -0,0 +1,155 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/obj/machinery/recharger + name = "recharger" + desc = "An all-purpose recharger for a variety of devices." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "recharger0" + anchored = 1 + use_power = 1 + idle_power_usage = 4 + active_power_usage = 30 KILOWATTS + var/obj/item/charging = null + var/list/allowed_devices = list(/obj/item/weapon/melee/baton, /obj/item/weapon/cell, /obj/item/modular_computer/, /obj/item/device/suit_sensor_jammer, /obj/item/weapon/computer_hardware/battery_module, /obj/item/weapon/shield_diffuser, /obj/item/clothing/mask/smokable/ecig) + var/icon_state_charged = "recharger2" + var/icon_state_charging = "recharger1" + var/icon_state_idle = "recharger0" //also when unpowered + var/portable = 1 + +/obj/machinery/recharger/attackby(obj/item/weapon/G as obj, mob/user as mob) + if(istype(user,/mob/living/silicon)) + return + + var/allowed = 0 + for (var/allowed_type in allowed_devices) + if (istype(G, allowed_type)) allowed = 1 + + if(allowed) + if(charging) + to_chat(user, "\A [charging] is already charging here.") + return + // Checks to make sure he's not in space doing it, and that the area got proper power. + if(!powered()) + to_chat(user, "The [name] blinks red as you try to insert the item!") + return + if (istype(G, /obj/item/weapon/gun/energy/gun/nuclear) || istype(G, /obj/item/weapon/gun/energy/crossbow)) + to_chat(user, "Your gun's recharge port was removed to make room for a miniaturized reactor.") + return + if (istype(G, /obj/item/weapon/gun/energy/staff)) + return + if(istype(G, /obj/item/modular_computer)) + var/obj/item/modular_computer/C = G + if(!C.battery_module) + to_chat(user, "This device does not have a battery installed.") + return + if(istype(G, /obj/item/device/suit_sensor_jammer)) + var/obj/item/device/suit_sensor_jammer/J = G + if(!J.bcell) + to_chat(user, "This device does not have a battery installed.") + return + + if(user.unEquip(G)) + G.forceMove(src) + charging = G + playsound(src, 'sound/weapons/guns/interact/mag_load.ogg', 100) + update_icon() + else if(portable && isWrench(G)) + if(charging) + to_chat(user, "Remove [charging] first!") + return + anchored = !anchored + to_chat(user, "You [anchored ? "attached" : "detached"] the recharger.") + playsound(loc, 'sound/items/Ratchet.ogg', 75, 1) + +/obj/machinery/recharger/attack_hand(mob/user as mob) + if(istype(user,/mob/living/silicon)) + return + + ..() + + if(charging) + charging.update_icon() + user.put_in_hands(charging) + charging = null + update_icon() + playsound(src, 'sound/weapons/guns/interact/mag_unload.ogg', 100) + +/obj/machinery/recharger/Process() + if(stat & (NOPOWER|BROKEN) || !anchored) + update_use_power(0) + icon_state = icon_state_idle + return + + if(!charging) + update_use_power(1) + icon_state = icon_state_idle + else + var/cell = charging + if(istype(charging, /obj/item/device/suit_sensor_jammer)) + var/obj/item/device/suit_sensor_jammer/J = charging + charging = J.bcell + else if(istype(charging, /obj/item/weapon/melee/baton)) + var/obj/item/weapon/melee/baton/B = charging + cell = B.bcell + else if(istype(charging, /obj/item/modular_computer)) + var/obj/item/modular_computer/C = charging + cell = C.battery_module.battery + else if(istype(charging, /obj/item/weapon/gun/energy)) + var/obj/item/weapon/gun/energy/E = charging + cell = E.power_supply + else if(istype(charging, /obj/item/weapon/computer_hardware/battery_module)) + var/obj/item/weapon/computer_hardware/battery_module/BM = charging + cell = BM.battery + else if(istype(charging, /obj/item/weapon/shield_diffuser)) + var/obj/item/weapon/shield_diffuser/SD = charging + cell = SD.cell + else if(istype(charging, /obj/item/clothing/mask/smokable/ecig)) + var/obj/item/clothing/mask/smokable/ecig/CIG = charging + cell = CIG.cigcell + + if(istype(cell, /obj/item/weapon/cell)) + var/obj/item/weapon/cell/C = cell + if(!C.fully_charged()) + icon_state = icon_state_charging + C.give(active_power_usage*CELLRATE) + update_use_power(2) + else + icon_state = icon_state_charged + update_use_power(1) + return + +/obj/machinery/recharger/emp_act(severity) + if(stat & (NOPOWER|BROKEN) || !anchored) + ..(severity) + return + + if(istype(charging, /obj/item/weapon/gun/energy)) + var/obj/item/weapon/gun/energy/E = charging + if(E.power_supply) + E.power_supply.emp_act(severity) + + else if(istype(charging, /obj/item/weapon/melee/baton)) + var/obj/item/weapon/melee/baton/B = charging + if(B.bcell) + B.bcell.charge = 0 + + ..(severity) + +obj/machinery/recharger/update_icon() //we have an update_icon() in addition to the stuff in process to make it feel a tiny bit snappier. + if(charging) + icon_state = icon_state_charging + else + icon_state = icon_state_idle + + +/obj/machinery/recharger/wallcharger + name = "wall recharger" + desc = "A heavy duty wall recharger specialized for energy weaponry." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "wrecharger0" + active_power_usage = 50 KILOWATTS //It's more specialized than the standalone recharger (guns and batons only) so make it more powerful + allowed_devices = list(/obj/item/weapon/gun/energy, /obj/item/weapon/melee/baton) + icon_state_charged = "wrecharger2" + icon_state_charging = "wrecharger1" + icon_state_idle = "wrecharger0" + portable = 0 diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm new file mode 100644 index 00000000..ec60e420 --- /dev/null +++ b/code/game/machinery/rechargestation.dm @@ -0,0 +1,274 @@ +/obj/machinery/recharge_station + name = "cyborg recharging station" + desc = "A heavy duty rapid charging system, designed to quickly recharge cyborg power reserves." + icon = 'icons/obj/objects.dmi' + icon_state = "borgcharger0" + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 50 + var/mob/living/occupant = null + var/obj/item/weapon/cell/cell = null + var/icon_update_tick = 0 // Used to rebuild the overlay only once every 10 ticks + var/charging = 0 + + var/charging_power // W. Power rating used for charging the cyborg. 120 kW if un-upgraded + var/restore_power_active // W. Power drawn from APC when an occupant is charging. 40 kW if un-upgraded + var/restore_power_passive // W. Power drawn from APC when idle. 7 kW if un-upgraded + var/weld_rate = 0 // How much brute damage is repaired per tick + var/wire_rate = 0 // How much burn damage is repaired per tick + + var/weld_power_use = 2300 // power used per point of brute damage repaired. 2.3 kW ~ about the same power usage of a handheld arc welder + var/wire_power_use = 500 // power used per point of burn damage repaired. + +/obj/machinery/recharge_station/New() + ..() + + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/recharge_station(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/capacitor(src) + component_parts += new /obj/item/weapon/stock_parts/capacitor(src) + component_parts += new /obj/item/weapon/cell/high(src) + component_parts += new /obj/item/stack/cable_coil(src, 5) + + RefreshParts() + + update_icon() + +/obj/machinery/recharge_station/proc/has_cell_power() + return cell && cell.percent() > 0 + +/obj/machinery/recharge_station/Process() + if(stat & (BROKEN)) + return + if(!cell) // Shouldn't be possible, but sanity check + return + + if((stat & NOPOWER) && !has_cell_power()) // No power and cell is dead. + if(icon_update_tick) + icon_update_tick = 0 //just rebuild the overlay once more only + update_icon() + return + + //First, draw from the internal power cell to recharge/repair/etc the occupant + if(occupant) + process_occupant() + + //Then, if external power is available, recharge the internal cell + var/recharge_amount = 0 + if(!(stat & NOPOWER)) + // Calculating amount of power to draw + recharge_amount = (occupant ? restore_power_active : restore_power_passive) * CELLRATE + + recharge_amount = cell.give(recharge_amount) + use_power(recharge_amount / CELLRATE) + + if(icon_update_tick >= 10) + icon_update_tick = 0 + else + icon_update_tick++ + + if(occupant || recharge_amount) + update_icon() + +//since the recharge station can still be on even with NOPOWER. Instead it draws from the internal cell. +/obj/machinery/recharge_station/auto_use_power() + if(!(stat & NOPOWER)) + return ..() + + if(!has_cell_power()) + return 0 + if(src.use_power == 1) + cell.use(idle_power_usage * CELLRATE) + else if(src.use_power >= 2) + cell.use(active_power_usage * CELLRATE) + return 1 + +//Processes the occupant, drawing from the internal power cell if needed. +/obj/machinery/recharge_station/proc/process_occupant() + // Check whether the mob is compatible + if(!isrobot(occupant) && !ishuman(occupant)) + return + + // If we have repair capabilities, repair any damage. + if(weld_rate && occupant.getBruteLoss() && cell.checked_use(weld_power_use * weld_rate * CELLRATE)) + occupant.adjustBruteLoss(-weld_rate) + if(wire_rate && occupant.getFireLoss() && cell.checked_use(wire_power_use * wire_rate * CELLRATE)) + occupant.adjustFireLoss(-wire_rate) + + var/obj/item/weapon/cell/target + if(isrobot(occupant)) + var/mob/living/silicon/robot/R = occupant + target = R.cell + if(R.module) + R.module.respawn_consumable(R, charging_power * CELLRATE / 250) //consumables are magical, apparently + // If we are capable of repairing damage, reboot destroyed components and allow them to be repaired for very large power spike. + var/list/damaged = R.get_damaged_components(1,1,1) + if(damaged.len && wire_rate && weld_rate) + for(var/datum/robot_component/C in damaged) + if((C.installed == -1) && cell.checked_use(100 KILOWATTS * CELLRATE)) + C.repair() + + if(ishuman(occupant)) + var/mob/living/carbon/human/H = occupant + var/obj/item/organ/internal/cell/potato = H.internal_organs_by_name[BP_CELL] + if(potato) + target = potato.cell + + if(target && !target.fully_charged()) + var/diff = min(target.maxcharge - target.charge, charging_power * CELLRATE) // Capped by charging_power / tick + var/charge_used = cell.use(diff) + target.give(charge_used) + + +/obj/machinery/recharge_station/examine(mob/user) + . = ..(user) + to_chat(user, "The charge meter reads: [round(chargepercentage())]%") + +/obj/machinery/recharge_station/proc/chargepercentage() + if(!cell) + return 0 + return cell.percent() + +/obj/machinery/recharge_station/relaymove(mob/user as mob) + if(user.stat) + return + go_out() + return + +/obj/machinery/recharge_station/emp_act(severity) + if(occupant) + occupant.emp_act(severity) + go_out() + if(cell) + cell.emp_act(severity) + ..(severity) + +/obj/machinery/recharge_station/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(!occupant) + if(default_deconstruction_screwdriver(user, O)) + return + if(default_deconstruction_crowbar(user, O)) + return + if(default_part_replacement(user, O)) + return + + ..() + +/obj/machinery/recharge_station/RefreshParts() + ..() + var/man_rating = 0 + var/cap_rating = 0 + + for(var/obj/item/weapon/stock_parts/P in component_parts) + if(istype(P, /obj/item/weapon/stock_parts/capacitor)) + cap_rating += P.rating + if(istype(P, /obj/item/weapon/stock_parts/manipulator)) + man_rating += P.rating + cell = locate(/obj/item/weapon/cell) in component_parts + + charging_power = 40000 + 40000 * cap_rating + restore_power_active = 10000 + 15000 * cap_rating + restore_power_passive = 5000 + 1000 * cap_rating + weld_rate = max(0, man_rating - 3) + wire_rate = max(0, man_rating - 5) + + desc = initial(desc) + desc += " Uses a dedicated internal power cell to deliver [charging_power]W when in use." + if(weld_rate) + desc += "
            It is capable of repairing structural damage." + if(wire_rate) + desc += "
            It is capable of repairing burn damage." + +/obj/machinery/recharge_station/proc/build_overlays() + overlays.Cut() + switch(round(chargepercentage())) + if(1 to 20) + overlays += image('icons/obj/objects.dmi', "statn_c0") + if(21 to 40) + overlays += image('icons/obj/objects.dmi', "statn_c20") + if(41 to 60) + overlays += image('icons/obj/objects.dmi', "statn_c40") + if(61 to 80) + overlays += image('icons/obj/objects.dmi', "statn_c60") + if(81 to 98) + overlays += image('icons/obj/objects.dmi', "statn_c80") + if(99 to 110) + overlays += image('icons/obj/objects.dmi', "statn_c100") + +/obj/machinery/recharge_station/update_icon() + ..() + if(stat & BROKEN) + icon_state = "borgcharger0" + return + + if(occupant) + if((stat & NOPOWER) && !has_cell_power()) + icon_state = "borgcharger2" + else + icon_state = "borgcharger1" + else + icon_state = "borgcharger0" + + if(icon_update_tick == 0) + build_overlays() + +/obj/machinery/recharge_station/Bumped(var/mob/living/silicon/robot/R) + go_in(R) + +/obj/machinery/recharge_station/proc/go_in(var/mob/M) + + + if(occupant) + return + + if(!hascell(M)) + return + + add_fingerprint(M) + M.reset_view(src) + M.forceMove(src) + occupant = M + update_icon() + return 1 + +/obj/machinery/recharge_station/proc/hascell(var/mob/M) + if(isrobot(M)) + var/mob/living/silicon/robot/R = M + return (R.cell) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.isSynthetic()) // FBPs and IPCs + return 1 + return H.internal_organs_by_name["cell"] + return 0 + +/obj/machinery/recharge_station/proc/go_out() + if(!occupant) + return + + occupant.forceMove(loc) + occupant.reset_view() + occupant = null + update_icon() + +/obj/machinery/recharge_station/verb/move_eject() + set category = "Object" + set name = "Eject Recharger" + set src in oview(1) + + if(usr.incapacitated()) + return + + go_out() + add_fingerprint(usr) + return + +/obj/machinery/recharge_station/verb/move_inside() + set category = "Object" + set name = "Enter Recharger" + set src in oview(1) + + go_in(usr) diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm new file mode 100644 index 00000000..96b58bb4 --- /dev/null +++ b/code/game/machinery/requests_console.dm @@ -0,0 +1,250 @@ +/******************** Requests Console ********************/ +/** Originally written by errorage, updated by: Carn, needs more work though. I just added some security fixes */ + +//Request Console Department Types +#define RC_ASSIST 1 //Request Assistance +#define RC_SUPPLY 2 //Request Supplies +#define RC_INFO 4 //Relay Info + +//Request Console Screens +#define RCS_MAINMENU 0 // Main menu +#define RCS_RQASSIST 1 // Request supplies +#define RCS_RQSUPPLY 2 // Request assistance +#define RCS_SENDINFO 3 // Relay information +#define RCS_SENTPASS 4 // Message sent successfully +#define RCS_SENTFAIL 5 // Message sent unsuccessfully +#define RCS_VIEWMSGS 6 // View messages +#define RCS_MESSAUTH 7 // Authentication before sending +#define RCS_ANNOUNCE 8 // Send announcement + +var/req_console_assistance = list() +var/req_console_supplies = list() +var/req_console_information = list() +var/list/obj/machinery/requests_console/allConsoles = list() + +/obj/machinery/requests_console + name = "Requests Console" + desc = "A console intended to send requests to different departments." + anchored = 1 + icon = 'icons/obj/terminals.dmi' + icon_state = "req_comp0" + var/department = "Unknown" //The list of all departments on the station (Determined from this variable on each unit) Set this to the same thing if you want several consoles in one department + var/list/message_log = list() //List of all messages + var/departmentType = 0 //Bitflag. Zero is reply-only. Map currently uses raw numbers instead of defines. + var/newmessagepriority = 0 + // 0 = no new message + // 1 = normal priority + // 2 = high priority + var/screen = RCS_MAINMENU + var/silent = 0 // set to 1 for it not to beep all the time +// var/hackState = 0 + // 0 = not hacked + // 1 = hacked + var/announcementConsole = 0 + // 0 = This console cannot be used to send department announcements + // 1 = This console can send department announcementsf + var/open = 0 // 1 if open + var/announceAuth = 0 //Will be set to 1 when you authenticate yourself for announcements + var/msgVerified = "" //Will contain the name of the person who varified it + var/msgStamped = "" //If a message is stamped, this will contain the stamp name + var/message = ""; + var/recipient = ""; //the department which will be receiving the message + var/priority = -1 ; //Priority of the message being sent + light_range = 0 + var/datum/announcement/announcement = new + +/obj/machinery/requests_console/update_icon() + if(stat & NOPOWER) + if(icon_state != "req_comp_off") + icon_state = "req_comp_off" + else + if(icon_state == "req_comp_off") + icon_state = "req_comp[newmessagepriority]" + +/obj/machinery/requests_console/New() + ..() + + announcement.title = "[department] announcement" + announcement.newscast = 1 + + name = "[department] Requests Console" + allConsoles += src + if (departmentType & RC_ASSIST) + req_console_assistance |= department + if (departmentType & RC_SUPPLY) + req_console_supplies |= department + if (departmentType & RC_INFO) + req_console_information |= department + + set_light(1) + +/obj/machinery/requests_console/Destroy() + allConsoles -= src + var/lastDeptRC = 1 + for (var/obj/machinery/requests_console/Console in allConsoles) + if (Console.department == department) + lastDeptRC = 0 + break + if(lastDeptRC) + if (departmentType & RC_ASSIST) + req_console_assistance -= department + if (departmentType & RC_SUPPLY) + req_console_supplies -= department + if (departmentType & RC_INFO) + req_console_information -= department + ..() + +/obj/machinery/requests_console/attack_hand(user as mob) + if(..(user)) + return + ui_interact(user) + +/obj/machinery/requests_console/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + + data["department"] = department + data["screen"] = screen + data["message_log"] = message_log + data["newmessagepriority"] = newmessagepriority + data["silent"] = silent + data["announcementConsole"] = announcementConsole + + data["assist_dept"] = req_console_assistance + data["supply_dept"] = req_console_supplies + data["info_dept"] = req_console_information + + data["message"] = message + data["recipient"] = recipient + data["priortiy"] = priority + data["msgStamped"] = msgStamped + data["msgVerified"] = msgVerified + data["announceAuth"] = announceAuth + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "request_console.tmpl", "[department] Request Console", 520, 410) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/requests_console/Topic(href, href_list) + if(..()) return + usr.set_machine(src) + + if(reject_bad_text(href_list["write"])) + recipient = href_list["write"] //write contains the string of the receiving department's name + + var/new_message = sanitize("Write your message:", "Awaiting Input", "") + if(new_message) + message = new_message + screen = RCS_MESSAUTH + switch(href_list["priority"]) + if("1") priority = 1 + if("2") priority = 2 + else priority = 0 + else + reset_message(1) + + if(href_list["writeAnnouncement"]) + var/new_message = sanitize("Write your message:", "Awaiting Input", "") + if(new_message) + message = new_message + else + reset_message(1) + + if(href_list["sendAnnouncement"]) + if(!announcementConsole) return + announcement.Announce(message, msg_sanitized = 1) + reset_message(1) + + if( href_list["department"] && message ) + var/log_msg = message + var/pass = 0 + screen = RCS_SENTFAIL + for (var/obj/machinery/message_server/MS in world) + if(!MS.active) continue + MS.send_rc_message(ckey(href_list["department"]),department,log_msg,msgStamped,msgVerified,priority) + pass = 1 + if(pass) + screen = RCS_SENTPASS + message_log += "Message sent to [recipient]
            [message]" + else + audible_message(text("\icon[src] *The Requests Console beeps: 'NOTICE: No server detected!'"),,4) + + //Handle screen switching + if(href_list["setScreen"]) + var/tempScreen = text2num(href_list["setScreen"]) + if(tempScreen == RCS_ANNOUNCE && !announcementConsole) + return + if(tempScreen == RCS_VIEWMSGS) + for (var/obj/machinery/requests_console/Console in allConsoles) + if (Console.department == department) + Console.newmessagepriority = 0 + Console.icon_state = "req_comp0" + Console.set_light(1) + if(tempScreen == RCS_MAINMENU) + reset_message() + screen = tempScreen + + //Handle silencing the console + if(href_list["toggleSilent"]) + silent = !silent + + updateUsrDialog() + return + + //err... hacking code, which has no reason for existing... but anyway... it was once supposed to unlock priority 3 messanging on that console (EXTREME priority...), but the code for that was removed. +/obj/machinery/requests_console/attackby(var/obj/item/weapon/O as obj, var/mob/user as mob) + /* + if (istype(O, /obj/item/weapon/crowbar)) + if(open) + open = 0 + icon_state="req_comp0" + else + open = 1 + if(hackState == 0) + icon_state="req_comp_open" + else if(hackState == 1) + icon_state="req_comp_rewired" + if (istype(O, /obj/item/weapon/screwdriver)) + if(open) + if(hackState == 0) + hackState = 1 + icon_state="req_comp_rewired" + else if(hackState == 1) + hackState = 0 + icon_state="req_comp_open" + else + to_chat(user, "You can't do much with that.") */ + if (istype(O, /obj/item/weapon/card/id)) + if(inoperable(MAINT)) return + if(screen == RCS_MESSAUTH) + var/obj/item/weapon/card/id/T = O + msgVerified = text("Verified by [T.registered_name] ([T.assignment])") + updateUsrDialog() + if(screen == RCS_ANNOUNCE) + var/obj/item/weapon/card/id/ID = O + if (access_RC_announce in ID.GetAccess()) + announceAuth = 1 + announcement.announcer = ID.assignment ? "[ID.assignment] [ID.registered_name]" : ID.registered_name + else + reset_message() + to_chat(user, "You are not authorized to send announcements.") + updateUsrDialog() + if (istype(O, /obj/item/weapon/stamp)) + if(inoperable(MAINT)) return + if(screen == RCS_MESSAUTH) + var/obj/item/weapon/stamp/T = O + msgStamped = text("Stamped with the [T.name]") + updateUsrDialog() + return + +/obj/machinery/requests_console/proc/reset_message(var/mainmenu = 0) + message = "" + recipient = "" + priority = 0 + msgVerified = "" + msgStamped = "" + announceAuth = 0 + announcement.announcer = "" + if(mainmenu) + screen = RCS_MAINMENU diff --git a/code/game/machinery/resleever.dm b/code/game/machinery/resleever.dm new file mode 100644 index 00000000..f2fedbdd --- /dev/null +++ b/code/game/machinery/resleever.dm @@ -0,0 +1,289 @@ +/obj/machinery/resleever + name = "neural lace resleever" + desc = "It's a machine that allows neural laces to be sleeved into new bodies." + icon = 'icons/obj/Cryogenic2.dmi' + + anchored = 1 + density = 1 + use_power = 1 + idle_power_usage = 4 + active_power_usage = 4000 // 4 Kw. A CT scan machine uses 1-15 kW depending on the model and equipment involved. + req_access = list(access_medical) + + icon_state = "body_scanner_0" + var/empty_state = "body_scanner_0" + var/occupied_state = "body_scanner_1" + var/allow_occupant_types = list(/mob/living/carbon/human) + var/disallow_occupant_types = list() + + var/mob/living/carbon/human/occupant = null + var/obj/item/organ/internal/stack/lace = null + + var/resleeving = 0 + var/remaining = 0 + var/timetosleeve = 120 + + var/occupant_name = null // Put in seperate var to prevent runtime. + var/lace_name = null + +/obj/machinery/resleever/New() + ..() + component_parts = list() + component_parts += new /obj/item/stack/cable_coil(src, 2) + component_parts += new /obj/item/weapon/stock_parts/scanning_module(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src, 3) + component_parts += new /obj/item/weapon/stock_parts/console_screen(src) + + RefreshParts() + update_icon() + +/obj/machinery/resleever/Destroy() + eject_occupant() + eject_lace() + return ..() + + +obj/machinery/resleever/Process() + + if(occupant) + occupant.Paralyse(4) // We need to always keep the occupant sleeping if they're in here. + if(stat & (NOPOWER|BROKEN) || !anchored) + update_use_power(0) + return + if(resleeving) + update_use_power(2) + if(remaining < timetosleeve) + remaining += 1 + + if(remaining == 90) // 30 seconds left + to_chat(occupant, "You feel a wash of sensation as your senses begin to flood your mind. You will come to soon.") + else + remaining = 0 + resleeving = 0 + update_use_power(1) + eject_occupant() + playsound(loc, 'sound/machines/ping.ogg', 100, 1) + visible_message("\The [src] pings as it completes its procedure!", 3) + return + update_use_power(0) + return + +/obj/machinery/resleever/proc/isOccupiedEjectable() + if(occupant) + if(!resleeving) + return 1 + return 0 + +/obj/machinery/resleever/proc/isLaceEjectable() + if(lace) + if(!resleeving) + return 1 + return 0 + +/obj/machinery/resleever/proc/readyToBegin() + if(lace && occupant) + if(!resleeving) + return 1 + return 0 + +/obj/machinery/resleever/attack_ai(mob/user as mob) + + add_hiddenprint(user) + return attack_hand(user) + + +/obj/machinery/resleever/attack_hand(mob/user as mob) + if(!anchored) + return + + if(stat & (NOPOWER|BROKEN)) + to_chat(usr, "\The [src] doesn't appear to function.") + return + + tg_ui_interact(user) + +/obj/machinery/resleever/ui_status(mob/user, datum/ui_state/state) + if(!anchored || inoperable()) + return UI_CLOSE + return ..() + + +/obj/machinery/resleever/tg_ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = tgui_process.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "resleever", "Neural Lace Resleever", 300, 300, master_ui, state) + ui.open() + +/obj/machinery/resleever/ui_data() + var/list/data = list( + "name" = occupant_name, + "lace" = lace_name, + "isOccupiedEjectable" = isOccupiedEjectable(), + "isLaceEjectable" = isLaceEjectable(), + "active" = resleeving, + "remaining" = remaining, + "timetosleeve" = 120, + "ready" = readyToBegin() + ) + + return data + +/obj/machinery/resleever/ui_act(action, params) + if(..()) + return TRUE + switch(action) + if("begin") + sleeve() + resleeving = 1 + if("eject") + eject_occupant() + if("ejectlace") + eject_lace() + update_icon() + return TRUE + +/obj/machinery/resleever/proc/sleeve() + if(lace && occupant) + var/obj/item/organ/O = occupant.get_organ(lace.parent_organ) + if(istype(O)) + lace.status &= ~ORGAN_CUT_AWAY //ensure the lace is properly attached + lace.replaced(occupant, O) + lace = null + lace_name = null + else + return + +/obj/machinery/resleever/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(default_deconstruction_screwdriver(user, W)) + if(occupant) + to_chat(user, "You need to remove the occupant first!") + return + if(default_deconstruction_crowbar(user, W)) + if(occupant) + to_chat(user, "You need to remove the occupant first!") + return + if(default_part_replacement(user, W)) + if(occupant) + to_chat(user, "You need to remove the occupant first!") + return + if(istype(W, /obj/item/organ/internal/stack)) + if(isnull(lace)) + to_chat(user, "You insert \the [W] into [src].") + user.drop_from_inventory(W) + lace = W + W.forceMove(src) + if(lace.backup) + lace_name = lace.backup.name + else + to_chat(user, "\The [src] already has a neural lace inside it!") + return + else if(isWrench(W)) + if(isnull(occupant)) + if(anchored) + anchored = 0 + user.visible_message("[user] unsecures [src] from the floor.", "You unsecure [src] from the floor.") + else + anchored = 1 + user.visible_message("[user] secures [src] to the floor.", "You secure [src] to the floor.") + playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) + else + to_chat(user, "Can not do that while [src] is occupied.") + + else if(istype(W, /obj/item/grab)) + var/obj/item/grab/grab = W + if(occupant) + to_chat(user, "\The [src] is in use.") + return + + if(!ismob(grab.affecting)) + return + + if(!check_occupant_allowed(grab.affecting)) + return + + var/mob/M = grab.affecting + + visible_message("[user] starts putting [grab.affecting:name] into \the [src].", 3) + + if(do_after(user, 20, src)) + if(!M || !grab || !grab.affecting) return + + M.forceMove(src) + + occupant = M + occupant_name = occupant.name + update_icon() + if(M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + +/obj/machinery/resleever/proc/eject_occupant() + if(!(occupant)) + return + occupant.forceMove(loc) + if(occupant.client) + occupant.reset_view(null) + occupant = null + occupant_name = null + update_icon() + +/obj/machinery/resleever/proc/eject_lace() + if(!(lace)) + return + lace.forceMove(loc) + lace = null + lace_name = null + +/obj/machinery/resleever/emp_act(severity) + //if(prob(100/severity)) + //malfunction() //NOT DEFINED YET + ..() + + + +/obj/machinery/resleever/ex_act(severity) + switch(severity) + if(1.0) + for(var/atom/movable/A as mob|obj in src) + A.forceMove(loc) + ex_act(severity) + qdel(src) + return + if(2.0) + if(prob(50)) + for(var/atom/movable/A as mob|obj in src) + A.forceMove(loc) + ex_act(severity) + qdel(src) + return + if(3.0) + if(prob(25)) + for(var/atom/movable/A as mob|obj in src) + A.forceMove(loc) + ex_act(severity) + qdel(src) + return + else + return + +/obj/machinery/resleever/update_icon() + ..() + icon_state = empty_state + if(occupant) + icon_state = occupied_state + + +/obj/machinery/resleever/proc/check_occupant_allowed(mob/M) + var/correct_type = 0 + for(var/type in allow_occupant_types) + if(istype(M, type)) + correct_type = 1 + break + + if(!correct_type) return 0 + + for(var/type in disallow_occupant_types) + if(istype(M, type)) + return 0 + + return 1 diff --git a/code/game/machinery/robot_fabricator.dm b/code/game/machinery/robot_fabricator.dm new file mode 100644 index 00000000..d29c4cef --- /dev/null +++ b/code/game/machinery/robot_fabricator.dm @@ -0,0 +1,137 @@ +/obj/machinery/robotic_fabricator + name = "Robotic Fabricator" + icon = 'icons/obj/robotics.dmi' + icon_state = "fab-idle" + density = 1 + anchored = 1 + var/metal_amount = 0 + var/operating = 0 + var/obj/item/robot_parts/being_built = null + use_power = 1 + idle_power_usage = 40 + active_power_usage = 10000 + +/obj/machinery/robotic_fabricator/attackby(var/obj/item/O as obj, var/mob/user as mob) + if (istype(O, /obj/item/stack/material) && O.get_material_name() == DEFAULT_WALL_MATERIAL) + var/obj/item/stack/M = O + if (src.metal_amount < 150000.0) + var/count = 0 + src.overlays += "fab-load-metal" + spawn(15) + if(M) + if(!M.get_amount()) + return + while(metal_amount < 150000 && M.amount) + src.metal_amount += O.matter[DEFAULT_WALL_MATERIAL] /*O:height * O:width * O:length * 100000.0*/ + M.use(1) + count++ + + to_chat(user, "You insert [count] metal sheet\s into the fabricator.") + src.overlays -= "fab-load-metal" + updateDialog() + else + to_chat(user, "The robot part maker is full. Please remove metal from the robot part maker in order to insert more.") + +/obj/machinery/robotic_fabricator/attack_hand(user as mob) + var/dat + if (..()) + return + + if (src.operating) + dat = {" +Building [src.being_built.name].
            +Please wait until completion...

            +
            +"} + else + dat = {" +Metal Amount: [min(150000, src.metal_amount)] cm3 (MAX: 150,000)

            +
            +Left Arm (25,000 cc metal.)
            +
            Right Arm (25,000 cc metal.)
            +
            Left Leg (25,000 cc metal.)
            +
            Right Leg (25,000 cc metal).
            +
            Chest (50,000 cc metal).
            +
            Head (50,000 cc metal).
            +
            Robot Frame (75,000 cc metal).
            +"} + + user << browse("Robotic Fabricator Control Panel[dat]", "window=robot_fabricator") + onclose(user, "robot_fabricator") + return + +/obj/machinery/robotic_fabricator/Topic(href, href_list) + if (..()) + return + + usr.set_machine(src) + + if (href_list["make"]) + if (!src.operating) + var/part_type = text2num(href_list["make"]) + + var/build_type = null + var/build_time = 200 + var/build_cost = 25000 + + switch (part_type) + if (1) + build_type = /obj/item/robot_parts/l_arm + build_time = 200 + build_cost = 25000 + + if (2) + build_type = /obj/item/robot_parts/r_arm + build_time = 200 + build_cost = 25000 + + if (3) + build_type = /obj/item/robot_parts/l_leg + build_time = 200 + build_cost = 25000 + + if (4) + build_type = /obj/item/robot_parts/r_leg + build_time = 200 + build_cost = 25000 + + if (5) + build_type = /obj/item/robot_parts/chest + build_time = 350 + build_cost = 50000 + + if (6) + build_type = /obj/item/robot_parts/head + build_time = 350 + build_cost = 50000 + + if (7) + build_type = /obj/item/robot_parts/robot_suit + build_time = 600 + build_cost = 75000 + + var/building = build_type + if (!isnull(building)) + if (src.metal_amount >= build_cost) + src.operating = 1 + src.update_use_power(2) + + src.metal_amount = max(0, src.metal_amount - build_cost) + + src.being_built = new building(src) + + src.overlays += "fab-active" + src.updateUsrDialog() + + spawn (build_time) + if (!isnull(src.being_built)) + src.being_built.loc = get_turf(src) + src.being_built = null + src.update_use_power(1) + src.operating = 0 + src.overlays -= "fab-active" + return + + for (var/mob/M in viewers(1, src)) + if (M.client && M.machine == src) + src.attack_hand(M) diff --git a/code/game/machinery/seed_extractor.dm b/code/game/machinery/seed_extractor.dm new file mode 100644 index 00000000..98ca5964 --- /dev/null +++ b/code/game/machinery/seed_extractor.dm @@ -0,0 +1,51 @@ +/obj/machinery/seed_extractor + name = "seed extractor" + desc = "Extracts and bags seeds from produce." + icon = 'icons/obj/hydroponics_machines.dmi' + icon_state = "sextractor" + density = 1 + anchored = 1 + use_power = 2 + idle_power_usage = 10 + active_power_usage = 2000 + +obj/machinery/seed_extractor/attackby(var/obj/item/O as obj, var/mob/user as mob) + + // Fruits and vegetables. + if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/grown) || istype(O, /obj/item/weapon/grown)) + + user.remove_from_mob(O) + + var/datum/seed/new_seed_type + if(istype(O, /obj/item/weapon/grown)) + var/obj/item/weapon/grown/F = O + new_seed_type = plant_controller.seeds[F.plantname] + else + var/obj/item/weapon/reagent_containers/food/snacks/grown/F = O + new_seed_type = plant_controller.seeds[F.plantname] + + if(new_seed_type) + to_chat(user, "You extract some seeds from [O].") + var/produce = rand(1,4) + for(var/i = 0;i<=produce;i++) + var/obj/item/seeds/seeds = new(get_turf(src)) + seeds.seed_type = new_seed_type.name + seeds.update_seed() + else + to_chat(user, "[O] doesn't seem to have any usable seeds inside it.") + + qdel(O) + + //Grass. + else if(istype(O, /obj/item/stack/tile/grass)) + var/obj/item/stack/tile/grass/S = O + if (S.use(1)) + to_chat(user, "You extract some seeds from the grass tile.") + new /obj/item/seeds/grassseed(loc) + + else if(istype(O, /obj/item/weapon/fossil/plant)) // Fossils + var/obj/item/seeds/random/R = new(get_turf(src)) + to_chat(user, "\The [src] scans \the [O] and spits out \a [R].") + qdel(O) + + return diff --git a/code/game/machinery/self_destruct.dm b/code/game/machinery/self_destruct.dm new file mode 100644 index 00000000..15cb15ec --- /dev/null +++ b/code/game/machinery/self_destruct.dm @@ -0,0 +1,123 @@ +/obj/machinery/self_destruct + name = "\improper Nuclear Cylinder Inserter" + desc = "A hollow space used to insert nuclear cylinders for arming the self destruct." + icon = 'icons/obj/machines/self_destruct.dmi' + icon_state = "empty" + density = 0 + anchored = 1 + var/obj/item/weapon/nuclear_cylinder/cylinder + var/armed = 0 + var/damaged = 0 + +/obj/machinery/self_destruct/attackby(obj/item/W as obj, mob/usr as mob) + if(isWelder(W)) + if(damaged) + usr.visible_message("[usr] begins to repair [src].", "You begin repairing [src].") + if(do_after(usr, 100, src)) + var/obj/item/weapon/weldingtool/w + if(w.burn_fuel(10)) + damaged = 0 + usr.visible_message("[usr] repairs [src].", "You repair [src].") + else + to_chat(usr, "There is not enough fuel to repair [src].") + return + if(istype(W, /obj/item/weapon/nuclear_cylinder)) + if(damaged) + to_chat(usr, "[src] is damaged, you cannot place the cylinder.") + return + if(cylinder) + to_chat(usr, "There is already a cylinder here.") + return + usr.visible_message("[usr] begins to carefully place [W] onto the Inserter.", "You begin to carefully place [W] onto the Inserter.") + if(do_after(usr, 80, src)) + usr.drop_from_inventory(W, src) + cylinder = W + density = 1 + usr.visible_message("[usr] places [W] onto the Inserter.", "You place [W] onto the Inserter.") + update_icon() + return + ..() + +/obj/machinery/self_destruct/attack_hand(mob/usr as mob) + if(cylinder) + if(armed) + if(damaged) + to_chat(usr, "The inserter has been damaged, unable to disarm.") + return + var/obj/machinery/nuclearbomb/nuke = locate(/obj/machinery/nuclearbomb/station) in get_area(src) + if(!nuke) + to_chat(usr, "Unable to interface with the self destruct terminal, unable to disarm.") + return + if(nuke.timing) + to_chat(usr, "The self destruct sequence is in progress, unable to disarm.") + return + usr.visible_message("[usr] begins extracting [cylinder].", "You begin extracting [cylinder].") + if(do_after(usr, 40, src)) + usr.visible_message("[usr] extracts [cylinder].", "You extract [cylinder].") + armed = 0 + density = 1 + flick("unloading", src) + else if(!damaged) + usr.visible_message("[usr] begins to arm [cylinder].", "You begin to arm [cylinder].") + if(do_after(usr, 40, src)) + armed = 1 + density = 0 + usr.visible_message("[usr] arms [cylinder].", "You arm [cylinder].") + flick("loading", src) + playsound(src.loc,'sound/effects/caution.ogg',50,1,5) + update_icon() + src.add_fingerprint(usr) + else + ..() + +/obj/machinery/self_destruct/MouseDrop(atom/over) + if(!CanMouseDrop(over, usr)) + return + if(over == usr && cylinder) + if(armed) + to_chat(usr, "Disarm the cylinder first.") + else + usr.visible_message("[usr] beings to carefully pick up [cylinder].", "You begin to carefully pick up [cylinder].") + if(do_after(usr, 70, src)) + usr.put_in_hands(cylinder) + usr.visible_message("[usr] picks up [cylinder].", "You pick up [cylinder].") + density = 0 + cylinder = null + update_icon() + src.add_fingerprint(usr) + ..() + +/obj/machinery/self_destruct/ex_act(severity) + switch(severity) + if(1) + set_damaged() + if(2) + if(prob(50)) + set_damaged() + if(3) + if(prob(25)) + set_damaged() + +/obj/machinery/self_destruct/proc/set_damaged() + src.visible_message("[src] dents and chars.") + damaged = 1 + +/obj/machinery/self_destruct/examine(mob/usr) + . = ..() + if(damaged) + to_chat(usr, "[src] is damaged, it needs repairs.") + return + if(armed) + to_chat(usr, "[src] is armed and ready.") + return + if(cylinder) + to_chat(usr, "[src] is loaded and ready to be armed.") + return + +/obj/machinery/self_destruct/update_icon() + if(armed) + icon_state = "armed" + else if(cylinder) + icon_state = "loaded" + else + icon_state = "empty" \ No newline at end of file diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm new file mode 100644 index 00000000..a9299d7e --- /dev/null +++ b/code/game/machinery/spaceheater.dm @@ -0,0 +1,197 @@ +/obj/machinery/space_heater + use_power = 0 + anchored = 0 + density = 1 + icon = 'icons/obj/atmos.dmi' + icon_state = "sheater-off" + name = "space heater" + desc = "Made by Space Amish using traditional space techniques, this heater is guaranteed not to set anything, or anyone, on fire." + var/obj/item/weapon/cell/cell + var/on = 0 + var/set_temperature = T0C + 20 //K + var/active = 0 + var/heating_power = 40 KILOWATTS + atom_flags = ATOM_FLAG_CLIMBABLE + clicksound = "switch" + + +/obj/machinery/space_heater/New() + ..() + cell = new/obj/item/weapon/cell/high(src) + update_icon() + +/obj/machinery/space_heater/update_icon(var/rebuild_overlay = 0) + if(!on) + icon_state = "sheater-off" + else if(active > 0) + icon_state = "sheater-heat" + else if(active < 0) + icon_state = "sheater-cool" + else + icon_state = "sheater-standby" + + if(rebuild_overlay) + overlays.Cut() + if(panel_open) + overlays += "sheater-open" + +/obj/machinery/space_heater/examine(mob/user) + . = ..(user) + + to_chat(user, "The heater is [on ? "on" : "off"] and the hatch is [panel_open ? "open" : "closed"].") + if(panel_open) + to_chat(user, "The power cell is [cell ? "installed" : "missing"].") + else + to_chat(user, "The charge meter reads [cell ? round(cell.percent(),1) : 0]%") + return + +/obj/machinery/space_heater/emp_act(severity) + if(stat & (BROKEN|NOPOWER)) + ..(severity) + return + if(cell) + cell.emp_act(severity) + ..(severity) + +/obj/machinery/space_heater/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/weapon/cell)) + if(panel_open) + if(cell) + to_chat(user, "There is already a power cell inside.") + return + else + // insert cell + var/obj/item/weapon/cell/C = usr.get_active_hand() + if(istype(C)) + user.drop_item() + cell = C + C.forceMove(src) + C.add_fingerprint(usr) + + user.visible_message("[user] inserts a power cell into [src].", "You insert the power cell into [src].") + power_change() + else + to_chat(user, "The hatch must be open to insert a power cell.") + return + else if(isScrewdriver(I)) + panel_open = !panel_open + user.visible_message("[user] [panel_open ? "opens" : "closes"] the hatch on the [src].", "You [panel_open ? "open" : "close"] the hatch on the [src].") + update_icon(1) + if(!panel_open && user.machine == src) + show_browser(user, null, "window=spaceheater") + user.unset_machine() + else + ..() + return + +/obj/machinery/space_heater/attack_hand(mob/user as mob) + ..() + interact(user) + +/obj/machinery/space_heater/interact(mob/user as mob) + + if(panel_open) + + var/list/dat = list() + dat += "Power cell: " + if(cell) + dat += "
            Installed
            " + else + dat += "Removed
            " + + dat += "Power Level: [cell ? round(cell.percent(),1) : 0]%

            " + + dat += "Set Temperature: " + + dat += "-" + + dat += " [set_temperature]K ([set_temperature-T0C]°C)" + dat += "+
            " + + var/datum/browser/popup = new(usr, "spaceheater", "Space Heater Control Panel") + popup.set_content(jointext(dat, null)) + popup.set_title_image(usr.browse_rsc_icon(src.icon, "sheater-standby")) + popup.open() + else + on = !on + user.visible_message("[user] switches [on ? "on" : "off"] the [src].","You switch [on ? "on" : "off"] the [src].") + update_icon() + return + + +/obj/machinery/space_heater/Topic(href, href_list, state = GLOB.physical_state) + if (..()) + show_browser(usr, null, "window=spaceheater") + usr.unset_machine() + return 1 + + switch(href_list["op"]) + + if("temp") + var/value = text2num(href_list["val"]) + + // limit to 0-90 degC + set_temperature = dd_range(T0C, T0C + 90, set_temperature + value) + + if("cellremove") + if(panel_open && cell && !usr.get_active_hand()) + usr.visible_message("\The usr] removes \the [cell] from \the [src].", "You remove \the [cell] from \the [src].") + cell.update_icon() + usr.put_in_hands(cell) + cell.add_fingerprint(usr) + cell = null + power_change() + + if("cellinstall") + if(panel_open && !cell) + var/obj/item/weapon/cell/C = usr.get_active_hand() + if(istype(C)) + usr.drop_item() + cell = C + C.forceMove(src) + C.add_fingerprint(usr) + power_change() + usr.visible_message("[usr] inserts \the [C] into \the [src].", "You insert \the [C] into \the [src].") + + updateDialog() + +/obj/machinery/space_heater/Process() + if(on) + if(powered() || (cell && cell.charge)) + var/datum/gas_mixture/env = loc.return_air() + if(env && abs(env.temperature - set_temperature) <= 0.1) + active = 0 + else + var/transfer_moles = 0.25 * env.total_moles + var/datum/gas_mixture/removed = env.remove(transfer_moles) + + if(removed) + var/heat_transfer = removed.get_thermal_energy_change(set_temperature) + var/power_draw + if(heat_transfer > 0) //heating air + heat_transfer = min( heat_transfer , heating_power ) //limit by the power rating of the heater + + removed.add_thermal_energy(heat_transfer) + power_draw = heat_transfer + else //cooling air + heat_transfer = abs(heat_transfer) + + //Assume the heat is being pumped into the hull which is fixed at 20 C + var/cop = removed.temperature/T20C //coefficient of performance from thermodynamics -> power used = heat_transfer/cop + heat_transfer = min(heat_transfer, cop * heating_power) //limit heat transfer by available power + + heat_transfer = removed.add_thermal_energy(-heat_transfer) //get the actual heat transfer + + power_draw = abs(heat_transfer)/cop + if(!powered()) + cell.use(power_draw*CELLRATE) + else + use_power(power_draw) + active = heat_transfer + + env.merge(removed) + else + on = 0 + active = 0 + power_change() + update_icon() diff --git a/code/game/machinery/startcryo.dm b/code/game/machinery/startcryo.dm new file mode 100644 index 00000000..11107776 --- /dev/null +++ b/code/game/machinery/startcryo.dm @@ -0,0 +1,49 @@ +var/list/starting_cryopods = list() + +/obj/machinery/startcryo + name = "CryoPod" + icon = 'icons/obj/cryostart.dmi' + icon_state = "cryo_loaded" + var/mob/living/carbon/human/occupant + anchored = 1 + density = 1 + var/is_used = 0 + plane = ABOVE_OBJ_PLANE + interact_offline = 1 + layer = 0 + +/obj/machinery/startcryo/New() + starting_cryopods.Add(src) + ..() + +/obj/machinery/startcryo/Destroy() + starting_cryopods.Remove(src) + ..() + +/obj/machinery/startcryo/proc/move_occupant_in(var/mob/living/carbon/C) + occupant = C + C.forceMove(src) + update_icon() + starting_cryopods.Remove(src) + +/obj/machinery/startcryo/relaymove(mob/user) + eject_occupant() + +/obj/machinery/startcryo/proc/eject_occupant() + spawn(20) + is_used = 1 + occupant.forceMove(src.loc) + occupant.reset_view(0) + occupant.visible_message("[occupant] gets out from [src]!") + playsound(occupant.loc, 'sound/machines/cryoexit.ogg') + occupant = null + update_icon() + return + +/obj/machinery/startcryo/update_icon() + underlays.Cut() + icon_state = "cryo_[is_used ? "used" : "loaded"]" + if(occupant) + var/image/pickle = image(occupant.icon, occupant.icon_state) + pickle.overlays = occupant.overlays + underlays += pickle \ No newline at end of file diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm new file mode 100644 index 00000000..2d9c5257 --- /dev/null +++ b/code/game/machinery/status_display.dm @@ -0,0 +1,234 @@ +#define FONT_SIZE "5pt" +#define FONT_COLOR "#10c729" +#define FONT_STYLE "Arial Black" +#define SCROLL_SPEED 2 + +// Status display +// (formerly Countdown timer display) + +// Use to show shuttle ETA/ETD times +// Alert status +// And arbitrary messages set by comms computer +/obj/machinery/status_display + icon = 'icons/obj/status_display.dmi' + icon_state = "frame" + name = "status display" + layer = ABOVE_WINDOW_LAYER + anchored = 1 + density = 0 + use_power = 1 + idle_power_usage = 10 + + var/const/CHARS_PER_LINE = 5 + var/const/STATUS_DISPLAY_BLANK = 0 //Blank + var/const/STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME = 1 //Shuttle timer + var/const/STATUS_DISPLAY_MESSAGE = 2 //Arbitrary message(s) + var/const/STATUS_DISPLAY_ALERT = 3 //alert picture + var/const/STATUS_DISPLAY_TIME = 4 //Supply shuttle timer + var/const/STATUS_DISPLAY_IMAGE = 5 + var/const/STATUS_DISPLAY_CUSTOM = 99 + + var/mode = STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME + + var/picture_state = "greenalert" // icon_state of alert picture + var/message1 = "" // message line 1 + var/message2 = "" // message line 2 + var/index1 // display index for scrolling messages or 0 if non-scrolling + var/index2 + var/picture = null + + var/frequency = 1435 // radio frequency + + var/friendc = 0 // track if Friend Computer mode + var/ignore_friendc = 0 + + maptext_height = 26 + maptext_width = 32 + +/obj/machinery/status_display/Destroy() + if(radio_controller) + radio_controller.remove_object(src,frequency) + return ..() + +// register for radio system +/obj/machinery/status_display/Initialize() + . = ..() + if(radio_controller) + radio_controller.add_object(src, frequency) + +// timed process +/obj/machinery/status_display/Process() + if(stat & NOPOWER) + remove_display() + return + update() + +/obj/machinery/status_display/emp_act(severity) + if(stat & (BROKEN|NOPOWER)) + ..(severity) + return + set_picture("ai_bsod") + ..(severity) + +// set what is displayed +/obj/machinery/status_display/proc/update() + remove_display() + if(friendc && !ignore_friendc) + set_picture("ai_friend") + return 1 + + switch(mode) + if(STATUS_DISPLAY_BLANK) //blank + return 1 + if(STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME) //emergency shuttle timer + if(evacuation_controller.is_prepared()) + message1 = "-ETD-" + if (evacuation_controller.waiting_to_leave()) + message2 = "Launch" + else + message2 = get_shuttle_timer() + if(length(message2) > CHARS_PER_LINE) + message2 = "Error" + update_display(message1, message2) + else if(evacuation_controller.has_eta()) + message1 = "-ETA-" + message2 = get_shuttle_timer() + if(length(message2) > CHARS_PER_LINE) + message2 = "Error" + update_display(message1, message2) + return 1 + if(STATUS_DISPLAY_MESSAGE) //custom messages + var/line1 + var/line2 + + if(!index1) + line1 = message1 + else + line1 = copytext(message1+"|"+message1, index1, index1+CHARS_PER_LINE) + var/message1_len = length(message1) + index1 += SCROLL_SPEED + if(index1 > message1_len) + index1 -= message1_len + + if(!index2) + line2 = message2 + else + line2 = copytext(message2+"|"+message2, index2, index2+CHARS_PER_LINE) + var/message2_len = length(message2) + index2 += SCROLL_SPEED + if(index2 > message2_len) + index2 -= message2_len + update_display(line1, line2) + return 1 + if(STATUS_DISPLAY_ALERT) + display_alert() + return 1 + if(STATUS_DISPLAY_TIME) + message1 = "TIME" + message2 = stationtime2text() + update_display(message1, message2) + return 1 + if(STATUS_DISPLAY_IMAGE) + set_picture(picture_state) + return 1 + return 0 + +/obj/machinery/status_display/examine(mob/user) + . = ..(user) + if(mode != STATUS_DISPLAY_BLANK && mode != STATUS_DISPLAY_ALERT) + to_chat(user, "The display says:
            \t[sanitize(message1)]
            \t[sanitize(message2)]") + if(mode == STATUS_DISPLAY_ALERT) + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + to_chat(user, "The current alert level is [security_state.current_security_level.name].") + +/obj/machinery/status_display/proc/set_message(m1, m2) + if(m1) + index1 = (length(m1) > CHARS_PER_LINE) + message1 = m1 + else + message1 = "" + index1 = 0 + + if(m2) + index2 = (length(m2) > CHARS_PER_LINE) + message2 = m2 + else + message2 = "" + index2 = 0 + +/obj/machinery/status_display/proc/display_alert() + remove_display() + + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + var/decl/security_level/sl = security_state.current_security_level + + var/image/alert = image(sl.icon, sl.overlay_status_display) + set_light(l_range = sl.light_range, l_power = sl.light_power, l_color = sl.light_color_status_display) + overlays |= alert + +/obj/machinery/status_display/proc/set_picture(state) + remove_display() + if(!picture || picture_state != state) + picture_state = state + picture = image('icons/obj/status_display.dmi', icon_state=picture_state) + overlays |= picture + set_light(1.5, 1, COLOR_WHITE) + +/obj/machinery/status_display/proc/update_display(line1, line2) + var/new_text = {"
            [line1]
            [line2]
            "} + if(maptext != new_text) + maptext = new_text + set_light(1.5, 1, COLOR_WHITE) + +/obj/machinery/status_display/proc/get_shuttle_timer() + var/timeleft = evacuation_controller.get_eta() + if(timeleft < 0) + return "" + return "[add_zero(num2text((timeleft / 60) % 60),2)]:[add_zero(num2text(timeleft % 60), 2)]" + +/obj/machinery/status_display/proc/get_supply_shuttle_timer() + var/datum/shuttle/autodock/ferry/supply/shuttle = supply_controller.shuttle + if (!shuttle) + return "Error" + + if(shuttle.has_arrive_time()) + var/timeleft = round((shuttle.arrive_time - world.time) / 10,1) + if(timeleft < 0) + return "Late" + return "[add_zero(num2text((timeleft / 60) % 60),2)]:[add_zero(num2text(timeleft % 60), 2)]" + return "" + +/obj/machinery/status_display/proc/remove_display() + if(overlays.len) + overlays.Cut() + if(maptext) + maptext = "" + set_light(0) + +/obj/machinery/status_display/receive_signal(datum/signal/signal) + switch(signal.data["command"]) + if("blank") + mode = STATUS_DISPLAY_BLANK + + if("shuttle") + mode = STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME + + if("message") + mode = STATUS_DISPLAY_MESSAGE + set_message(signal.data["msg1"], signal.data["msg2"]) + + if("alert") + mode = STATUS_DISPLAY_ALERT + + if("time") + mode = STATUS_DISPLAY_TIME + + if("image") + mode = STATUS_DISPLAY_IMAGE + set_picture(signal.data["picture_state"]) + update() + +#undef FONT_SIZE +#undef FONT_COLOR +#undef FONT_STYLE +#undef SCROLL_SPEED diff --git a/code/game/machinery/status_display_ai.dm b/code/game/machinery/status_display_ai.dm new file mode 100644 index 00000000..08cb3234 --- /dev/null +++ b/code/game/machinery/status_display_ai.dm @@ -0,0 +1,98 @@ +/datum/ai_emotion + var/overlay + var/ckey + +/datum/ai_emotion/New(var/over, var/key) + overlay = over + ckey = key + +var/list/ai_status_emotions = list( + "Very Happy" = new /datum/ai_emotion("ai_veryhappy"), + "Happy" = new /datum/ai_emotion("ai_happy"), + "Neutral" = new /datum/ai_emotion("ai_neutral"), + "Unsure" = new /datum/ai_emotion("ai_unsure"), + "Confused" = new /datum/ai_emotion("ai_confused"), + "Sad" = new /datum/ai_emotion("ai_sad"), + "Surprised" = new /datum/ai_emotion("ai_surprised"), + "Upset" = new /datum/ai_emotion("ai_upset"), + "Angry" = new /datum/ai_emotion("ai_angry"), + "BSOD" = new /datum/ai_emotion("ai_bsod"), + "Blank" = new /datum/ai_emotion("ai_off"), + "Problems?" = new /datum/ai_emotion("ai_trollface"), + "Awesome" = new /datum/ai_emotion("ai_awesome"), + "Dorfy" = new /datum/ai_emotion("ai_urist"), + "Facepalm" = new /datum/ai_emotion("ai_facepalm"), + "Friend Computer" = new /datum/ai_emotion("ai_friend"), + "Tribunal" = new /datum/ai_emotion("ai_tribunal", "serithi"), + "Tribunal Malfunctioning" = new /datum/ai_emotion("ai_tribunal_malf", "serithi"), + "Ship Scan" = new /datum/ai_emotion("ai_shipscan") + ) + +/proc/get_ai_emotions(var/ckey) + var/list/emotions = new + for(var/emotion_name in ai_status_emotions) + var/datum/ai_emotion/emotion = ai_status_emotions[emotion_name] + if(!emotion.ckey || emotion.ckey == ckey) + emotions += emotion_name + + return emotions + +/proc/set_ai_status_displays(mob/user as mob) + var/list/ai_emotions = get_ai_emotions(user.ckey) + var/emote = input("Please, select a status!", "AI Status", null, null) in ai_emotions + for (var/obj/machinery/M in SSmachines.machinery) //change status + if(istype(M, /obj/machinery/ai_status_display)) + var/obj/machinery/ai_status_display/AISD = M + AISD.emotion = emote + AISD.update_icon() + //if Friend Computer, change ALL displays + else if(istype(M, /obj/machinery/status_display)) + + var/obj/machinery/status_display/SD = M + if(emote=="Friend Computer") + SD.friendc = 1 + else + SD.friendc = 0 + +/obj/machinery/ai_status_display + icon = 'icons/obj/status_display.dmi' + icon_state = "frame" + name = "AI display" + anchored = 1 + density = 0 + + var/mode = 0 // 0 = Blank + // 1 = AI emoticon + // 2 = Blue screen of death + + var/picture_state // icon_state of ai picture + + var/emotion = "Neutral" + +/obj/machinery/ai_status_display/attack_ai/(mob/user as mob) + var/list/ai_emotions = get_ai_emotions(user.ckey) + var/emote = input("Please, select a status!", "AI Status", null, null) in ai_emotions + src.emotion = emote + +/obj/machinery/ai_status_display/Process() + return + +/obj/machinery/ai_status_display/update_icon() + if(stat & (NOPOWER|BROKEN)) + overlays.Cut() + return + + switch(mode) + if(0) //Blank + overlays.Cut() + if(1) // AI emoticon + var/datum/ai_emotion/ai_emotion = ai_status_emotions[emotion] + set_picture(ai_emotion.overlay) + if(2) // BSOD + set_picture("ai_bsod") + +/obj/machinery/ai_status_display/proc/set_picture(var/state) + picture_state = state + if(overlays.len) + overlays.Cut() + overlays += image('icons/obj/status_display.dmi', icon_state=picture_state) diff --git a/code/game/machinery/status_light.dm b/code/game/machinery/status_light.dm new file mode 100644 index 00000000..bce85143 --- /dev/null +++ b/code/game/machinery/status_light.dm @@ -0,0 +1,37 @@ +/obj/machinery/status_light + name = "combustion chamber status indicator" + desc = "A status indicator for a combustion chamber, based on temperature." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "doortimer-p" + var/frequency = 1439 + var/id_tag + var/alert_temperature = 10000 + var/alert = 1 + var/datum/radio_frequency/radio_connection + +/obj/machinery/status_light/Initialize() + . = ..() + update_icon() + radio_connection = register_radio(src, frequency, frequency, RADIO_ATMOSIA) + + +/obj/machinery/status_light/update_icon() + if(stat & (NOPOWER|BROKEN)) + icon_state = "doortimer-b" + return + icon_state = "doortimer[alert]" + +/obj/machinery/status_light/receive_signal(datum/signal/signal) + if(stat & (NOPOWER|BROKEN)) + return + + if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || !signal.data["temperature"]) + return 0 + + if(signal.data["temperature"] >= alert_temperature) + alert = 1 + else + alert = 2 + + update_icon() + return diff --git a/code/game/machinery/storage/storage.dm b/code/game/machinery/storage/storage.dm new file mode 100644 index 00000000..0930e95c --- /dev/null +++ b/code/game/machinery/storage/storage.dm @@ -0,0 +1,51 @@ +/* Copyright (C) The interbay dev team - All Rights Reserved + * Unauthorized copying of this file, via any medium is strictly prohibited + * + * Proprietary and confidential + * Do not modify or remove this header. + * + * Written by Kyrah Abattoir , August 2018 + */ + +//This is a special baseclass to equip machineries and other static objects with +//a standard backpack style storage, it does so by overriding the adjacency check +//allowing to manipulate the container's inventory despite not being on a player +//or a turf. + +/obj/item/weapon/storage/special + name = "/obj/item/weapon/storage/special" + desc = "base storage for storage machines" + w_class = ITEM_SIZE_NO_CONTAINER + max_w_class = ITEM_SIZE_GARGANTUAN //you prolly want to change this on subclasses. + storage_slots = 1 + use_sound = null + +//overrides item:Adjacent() so we can drop down one level +/obj/item/weapon/storage/special/Adjacent(var/atom/neighbor) + return loc.Adjacent(neighbor) + +/obj/item/weapon/storage/special/attack_hand(mob/user as mob) + open(user) + +//Use this machine as a base class it's pretty simple +/obj/machinery/storage/ + name = "/obj/machinery/storage/" + desc = "baseclass for storage enabled machines" + var/obj/item/weapon/storage/special/inventory + +/obj/machinery/storage/New() + inventory = new /obj/item/weapon/storage/special() + inventory.loc = src //VERY IMPORTANT + inventory.name = name //Not strictly needed but this affects the text description when players insert items inside the storage. + +/obj/machinery/storage/Destroy() + qdel(inventory) + ..() + +//fowards attack_hand +/obj/machinery/storage/attack_hand(mob/user as mob) + inventory.attack_hand(user) + +//fowards attackby +/obj/machinery/storage/attackby(obj/item/W as obj, mob/user as mob) + inventory.attackby(W, user) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm new file mode 100644 index 00000000..a7059827 --- /dev/null +++ b/code/game/machinery/suit_storage_unit.dm @@ -0,0 +1,1186 @@ +////////////////////////////////////// +// SUIT STORAGE UNIT ///////////////// +////////////////////////////////////// + + +/obj/machinery/suit_storage_unit + name = "Suit Storage Unit" + desc = "An industrial U-Stor-It Storage unit designed to accomodate all kinds of space suits. Its on-board equipment also allows the user to decontaminate the contents through a UV-ray purging cycle. There's a warning label dangling from the control pad, reading \"STRICTLY NO BIOLOGICALS IN THE CONFINES OF THE UNIT\"." + icon = 'icons/obj/suitstorage.dmi' + icon_state = "close" + anchored = 1 + density = 1 + use_power = 1 + idle_power_usage = 50 + active_power_usage = 200 + interact_offline = 1 + req_access = list() + + var/mob/living/carbon/human/occupant = null + var/obj/item/clothing/suit/space/suit = null + var/obj/item/clothing/head/helmet/space/helmet = null + var/obj/item/clothing/shoes/magboots/boots = null + var/obj/item/weapon/tank/tank = null + var/obj/item/clothing/mask/mask = null + + var/suit_type = null + var/helmet_type = null + var/boots_type = null + var/tank_type = null + var/mask_type = null + + var/isopen = 0 + var/islocked = 0 + var/isUV = 0 + var/isbroken = 0 + var/issuperUV = 0 + var/panelopen = 0 + var/safetieson = 1 + var/cycletime_left = 0 + +//The units themselves///////////////// + +/obj/machinery/suit_storage_unit/standard_unit + suit_type = /obj/item/clothing/suit/space + helmet_type = /obj/item/clothing/head/helmet/space + tank_type = /obj/item/weapon/tank/oxygen + mask_type = /obj/item/clothing/mask/breath + req_access = list(access_eva) + +/obj/machinery/suit_storage_unit/atmos + name = "Atmospherics Voidsuit Storage Unit" + suit_type = /obj/item/clothing/suit/space/void/atmos + helmet_type = /obj/item/clothing/head/helmet/space/void/atmos + boots_type = /obj/item/clothing/shoes/magboots + tank_type = /obj/item/weapon/tank/oxygen + mask_type = /obj/item/clothing/mask/breath + req_access = list(access_atmospherics) + islocked = 1 + +/obj/machinery/suit_storage_unit/atmos/alt + suit_type = /obj/item/clothing/suit/space/void/atmos/alt + helmet_type = /obj/item/clothing/head/helmet/space/void/atmos/alt + +/obj/machinery/suit_storage_unit/engineering + name = "Engineering Voidsuit Storage Unit" + suit_type = /obj/item/clothing/suit/space/void/engineering + helmet_type = /obj/item/clothing/head/helmet/space/void/engineering + boots_type = /obj/item/clothing/shoes/magboots + tank_type = /obj/item/weapon/tank/oxygen + mask_type = /obj/item/clothing/mask/breath + req_access = list(access_engine) + islocked = 1 + +/obj/machinery/suit_storage_unit/engineering/alt + suit_type = /obj/item/clothing/suit/space/void/engineering/alt + helmet_type = /obj/item/clothing/head/helmet/space/void/engineering/alt + mask_type = /obj/item/clothing/mask/breath + +/obj/machinery/suit_storage_unit/engineering/salvage + suit_type = /obj/item/clothing/suit/space/void/engineering/salvage + helmet_type = /obj/item/clothing/head/helmet/space/void/engineering/salvage + mask_type = /obj/item/clothing/mask/breath + +/obj/machinery/suit_storage_unit/medical + name = "Medical Voidsuit Storage Unit" + suit_type = /obj/item/clothing/suit/space/void/medical + helmet_type = /obj/item/clothing/head/helmet/space/void/medical + boots_type = /obj/item/clothing/shoes/magboots + tank_type = /obj/item/weapon/tank/oxygen + mask_type = /obj/item/clothing/mask/breath + req_access = list(access_medical) + islocked = 1 + +/obj/machinery/suit_storage_unit/medical/alt + suit_type = /obj/item/clothing/suit/space/void/medical/alt + helmet_type = /obj/item/clothing/head/helmet/space/void/medical/alt + mask_type = /obj/item/clothing/mask/breath + +/obj/machinery/suit_storage_unit/mining + name = "Mining Voidsuit Storage Unit" + suit_type = /obj/item/clothing/suit/space/void/mining + helmet_type = /obj/item/clothing/head/helmet/space/void/mining + boots_type = /obj/item/clothing/shoes/magboots + tank_type = /obj/item/weapon/tank/oxygen + mask_type = /obj/item/clothing/mask/breath + req_access = list(access_mining) + islocked = 1 + +/obj/machinery/suit_storage_unit/mining/alt + suit_type = /obj/item/clothing/suit/space/void/mining/alt + helmet_type = /obj/item/clothing/head/helmet/space/void/mining/alt + mask_type = /obj/item/clothing/mask/breath + +/obj/machinery/suit_storage_unit/science + name = "Excavation Voidsuit Storage Unit" + suit_type = /obj/item/clothing/suit/space/void/excavation + helmet_type = /obj/item/clothing/head/helmet/space/void/excavation + boots_type = /obj/item/clothing/shoes/magboots + tank_type = /obj/item/weapon/tank/oxygen + mask_type = /obj/item/clothing/mask/breath + req_access = list(access_xenoarch) + islocked = 1 + +/obj/machinery/suit_storage_unit/security + name = "Security Voidsuit Storage Unit" + suit_type = /obj/item/clothing/suit/space/void/security + helmet_type = /obj/item/clothing/head/helmet/space/void/security + boots_type = /obj/item/clothing/shoes/magboots + tank_type = /obj/item/weapon/tank/oxygen + mask_type = /obj/item/clothing/mask/breath + req_access = list(access_security) + islocked = 1 + +/obj/machinery/suit_storage_unit/security/alt + suit_type = /obj/item/clothing/suit/space/void/security/alt + helmet_type = /obj/item/clothing/head/helmet/space/void/security/alt + mask_type = /obj/item/clothing/mask/breath + +/obj/machinery/suit_storage_unit/merc + name = "Nonstandard Voidsuit Storage Unit" + suit_type = /obj/item/clothing/suit/space/void/merc + helmet_type = /obj/item/clothing/head/helmet/space/void/merc + boots_type = /obj/item/clothing/shoes/magboots + tank_type = /obj/item/weapon/tank/oxygen + mask_type = /obj/item/clothing/mask/breath + req_access = list(access_syndicate) + islocked = 1 + + + +/obj/machinery/suit_storage_unit/Initialize() + . = ..() + if(suit_type) + suit = new suit_type(src) + if(helmet_type) + helmet = new helmet_type(src) + if(boots_type) + boots = new boots_type(src) + if(tank_type) + tank = new tank_type(src) + if(mask_type) + mask = new mask_type(src) + update_icon() + +/obj/machinery/suit_storage_unit/update_icon() + overlays.Cut() + if(panelopen) + overlays += ("panel") + if(isUV) + if(issuperUV) + overlays += ("super") + else if(occupant) + overlays += ("uvhuman") + else + overlays += ("uv") + else if(isopen) + if(stat & BROKEN) + overlays += ("broken") + else + overlays += ("open") + if(suit) + overlays += ("suit") + if(helmet) + overlays += ("helm") + if(boots || tank || mask) + overlays += ("storage") + else if(occupant) + overlays += ("human") + +/obj/machinery/suit_storage_unit/ex_act(severity) + switch(severity) + if(1) + if(prob(50)) + dump_everything() //So suits dont survive all the time + qdel(src) + return + if(2) + if(prob(35)) + dump_everything() + qdel(src) + return + else + return + return + + +/obj/machinery/suit_storage_unit/attack_hand(mob/user as mob) + ..() + var/dat + if(!user.IsAdvancedToolUser()) + return 0 + if(panelopen) //The maintenance panel is open. Time for some shady stuff + dat+= "Suit storage unit: Maintenance panel" + dat+= "Maintenance panel controls
            " + dat+= "The panel is ridden with controls, button and meters, labeled in strange signs and symbols that
            you cannot understand. Probably the manufactoring world's language.
            Among other things, a few controls catch your eye.


            " + dat+= text("A small dial with a small lambda symbol on it. It's pointing towards a gauge that reads [].
            Turn towards []
            ",(issuperUV ? "15nm" : "185nm"),src,(issuperUV ? "185nm" : "15nm") ) + dat+= text("A thick old-style button, with 2 grimy LED lights next to it. The [] LED is on.
            Press button",(safetieson? "GREEN" : "RED"),src) + dat+= text("

            Close panel", user) + else if(isUV) //The thing is running its cauterisation cycle. You have to wait. + dat += "Suit storage unit" + dat+= "Unit is cauterising contents with selected UV ray intensity. Please wait.
            " + dat+= "Cycle end in: [cycletime_left] seconds. " + + else + if(!isbroken) + dat+= "Suit storage unit" + dat+= "U-Stor-It Suit Storage Unit, model DS1900
            " + dat+= "Welcome to the Unit control panel.

            " + dat+= text("Helmet storage compartment: []
            ",(helmet ? helmet.name : "No helmet detected.") ) + if(helmet && isopen) + dat+=text("Dispense helmet
            ",src) + dat+= text("Suit storage compartment: []
            ",(suit ? suit.name : "
            No suit detected.") ) + if(suit && isopen) + dat+=text("Dispense suit
            ",src) + dat+= text("Footwear storage compartment: []
            ",(boots ? boots.name : "
            No footwear detected.") ) + if(boots && isopen) + dat+=text("Dispense footwear
            ",src) + dat+= text("Tank storage compartment: []
            ",(tank ? tank.name : "
            No air tank detected.") ) + if(tank && isopen) + dat+=text("Dispense air tank
            ",src) + dat+= text("Breathmask storage compartment: []
            ",(mask ? mask.name : "
            No breathmask detected.") ) + if(mask && isopen) + dat+=text("Dispense mask
            ",src) + if(occupant) + dat+= "
            WARNING: Biological entity detected inside the Unit's storage. Please remove.
            " + dat+= "Eject extra load" + dat+= text("
            Unit is: [] - [] Unit ",(isopen ? "Open" : "Closed"),src,(isopen ? "Close" : "Open")) + if(isopen) + dat+="
            " + else + dat+= text(" - [] Unit
            ",src,(islocked ? "Unlock" : "Lock") ) + dat+= text("Unit status: []",(islocked? "LOCKED
            " : "UNLOCKED
            ") ) + dat+= text("Start Disinfection cycle
            ",src) + dat += text("

            Close control panel", user) + else //Ohhhh shit it's dirty or broken! Let's inform the guy. + dat+= "Suit storage unit" + dat+= "Unit chamber is too contaminated to continue usage. Please call for a qualified individual to perform maintenance.

            " + dat+= text("
            Close control panel", user) + + user << browse(dat, "window=suit_storage_unit;size=400x500") + onclose(user, "suit_storage_unit") + return + + +/obj/machinery/suit_storage_unit/Topic(href, href_list) //I fucking HATE this proc + if(..()) + return + usr.set_machine(src) + if (href_list["toggleUV"]) + toggleUV(usr) + updateUsrDialog() + update_icon() + if (href_list["togglesafeties"]) + togglesafeties(usr) + updateUsrDialog() + update_icon() + if (href_list["dispense_helmet"]) + dispense_helmet(usr) + updateUsrDialog() + update_icon() + if (href_list["dispense_suit"]) + dispense_suit(usr) + updateUsrDialog() + update_icon() + if (href_list["dispense_boots"]) + dispense_boots(usr) + updateUsrDialog() + update_icon() + if (href_list["dispense_tank"]) + dispense_tank(usr) + updateUsrDialog() + update_icon() + if (href_list["dispense_mask"]) + dispense_mask(usr) + updateUsrDialog() + update_icon() + if (href_list["toggle_open"]) + toggle_open(usr) + updateUsrDialog() + update_icon() + if (href_list["toggle_lock"]) + toggle_lock(usr) + updateUsrDialog() + update_icon() + if (href_list["start_UV"]) + start_UV(usr) + updateUsrDialog() + update_icon() + if (href_list["eject_guy"]) + eject_occupant(usr) + updateUsrDialog() + update_icon() + return + + +/obj/machinery/suit_storage_unit/proc/toggleUV(mob/user as mob) + if(!panelopen) + return + else //welp, the guy is protected, we can continue + if(issuperUV) + to_chat(user, "You slide the dial back towards \"185nm\".") + issuperUV = 0 + else + to_chat(user, "You crank the dial all the way up to \"15nm\".") + issuperUV = 1 + return + + +/obj/machinery/suit_storage_unit/proc/togglesafeties(mob/user as mob) + if(!panelopen) //Needed check due to bugs + return + else + safetieson = !safetieson + to_chat(user, "You push the button. The coloured LED next to it [safetieson ? "turns green" : "turns red"].") + +#define dispense_clothing(item) if(item){item.dropInto(loc); item = null} + +/obj/machinery/suit_storage_unit/proc/dispense_helmet(mob/user as mob) + dispense_clothing(helmet) + +/obj/machinery/suit_storage_unit/proc/dispense_suit(mob/user as mob) + dispense_clothing(suit) + +/obj/machinery/suit_storage_unit/proc/dispense_boots(mob/user as mob) + dispense_clothing(boots) + +/obj/machinery/suit_storage_unit/proc/dispense_tank(mob/user as mob) + dispense_clothing(tank) + +/obj/machinery/suit_storage_unit/proc/dispense_mask(mob/user as mob) + dispense_clothing(mask) + +/obj/machinery/suit_storage_unit/proc/dump_everything() + islocked = 0 //locks go free + dispense_clothing(suit) + dispense_clothing(helmet) + dispense_clothing(boots) + dispense_clothing(tank) + dispense_clothing(mask) + if(occupant) + eject_occupant(occupant) + return + +#undef dispense_clothing + +/obj/machinery/suit_storage_unit/proc/toggle_open(mob/user as mob) + if(stat & NOPOWER) + to_chat(user, "The unit is offline.") + return + if(islocked || isUV) + to_chat(user, "Unable to open unit.") + return + if(occupant) + eject_occupant(user) + return // eject_occupant opens the door, so we need to return + isopen = !isopen + return + + +/obj/machinery/suit_storage_unit/proc/toggle_lock(mob/user as mob) + if(stat & NOPOWER) + to_chat(user, "The unit is offline.") + return + if(!allowed(user)) + to_chat(user, FEEDBACK_ACCESS_DENIED) + return + if(occupant && safetieson) + to_chat(user, "The Unit's safety protocols disallow locking when a biological form is detected inside its compartments.") + return + if(isopen) + return + islocked = !islocked + return + + +/obj/machinery/suit_storage_unit/proc/start_UV(mob/user as mob) + if(isUV || isopen) //I'm bored of all these sanity checks + return + if(stat & NOPOWER) + to_chat(user, "The unit is offline.") + return + if(occupant && safetieson) + to_chat(user, "WARNING: Biological entity detected in the confines of the Unit's storage. Cannot initiate cycle.") + return + if(!helmet && !mask && !suit && !boots && !tank && !occupant ) //shit's empty yo + to_chat(user, "Unit storage bays empty. Nothing to disinfect -- Aborting.") + return + to_chat(user, "You start the Unit's cauterisation cycle.") + cycletime_left = 20 + isUV = 1 + if(occupant && !islocked) + islocked = 1 //Let's lock it for good measure + update_icon() + updateUsrDialog() + + var/i //our counter + for(i=0,i<4,i++) + sleep(50) + if(occupant) + occupant.apply_effect(50, IRRADIATE, blocked = occupant.getarmor(null, "rad")) + if(i==3) //End of the cycle + if(!issuperUV) + if(helmet ) + helmet.clean_blood() + if(suit) + suit.clean_blood() + if(boots) + boots.clean_blood() + if(tank) + tank.clean_blood() + if(mask) + mask.clean_blood() + else //It was supercycling, destroy everything + if(helmet ) + helmet = null + if(suit) + suit = null + if(boots) + boots = null + if(tank) + tank = null + if(mask) + mask = null + visible_message("With a loud whining noise, the Suit Storage Unit's door grinds open. Puffs of ashen smoke come out of its chamber.", 3) + isbroken = 1 + isopen = 1 + islocked = 0 + eject_occupant(occupant) //Mixing up these two lines causes bug. DO NOT DO IT. + isUV = 0 //Cycle ends + update_icon() + updateUsrDialog() + return + +/obj/machinery/suit_storage_unit/proc/cycletimeleft() + if(cycletime_left >= 1) + cycletime_left-- + return cycletime_left + + +/obj/machinery/suit_storage_unit/proc/eject_occupant(mob/user as mob) + if (islocked) + return + + if (!occupant) + return + + if (occupant.client) + if(user != occupant) + to_chat(occupant, "The machine kicks you out!") + if(user.loc != loc) + to_chat(occupant, "You leave the not-so-cozy confines of the SSU.") + + occupant.client.eye = occupant.client.mob + occupant.client.perspective = MOB_PERSPECTIVE + occupant.dropInto(loc) + occupant = null + if(!isopen) + isopen = 1 + update_icon() + return + + +/obj/machinery/suit_storage_unit/verb/get_out() + set name = "Eject Suit Storage Unit" + set category = "Object" + set src in oview(1) + + if (usr.stat != 0) + return + eject_occupant(usr) + add_fingerprint(usr) + updateUsrDialog() + update_icon() + return + + +/obj/machinery/suit_storage_unit/verb/move_inside() + set name = "Hide in Suit Storage Unit" + set category = "Object" + set src in oview(1) + + if (usr.stat != 0) + return + if (!isopen) + to_chat(usr, "The unit's doors are shut.") + return + if ((stat & NOPOWER) || isbroken) + to_chat(usr, "The unit is not operational.") + return + if ( (occupant) || (helmet ) || (suit) ) + to_chat(usr, "It's too cluttered inside for you to fit in!") + return + visible_message("\The [usr] starts squeezing into the suit storage unit!", 3) + if(do_after(usr, 10, src)) + usr.stop_pulling() + usr.client.perspective = EYE_PERSPECTIVE + usr.client.eye = src + usr.loc = src + occupant = usr + isopen = 0 //Close the thing after the guy gets inside + update_icon() + add_fingerprint(usr) + updateUsrDialog() + return + else + occupant = null //Testing this as a backup sanity test + return + + +/obj/machinery/suit_storage_unit/attackby(obj/item/I as obj, mob/user as mob) + if(isScrewdriver(I)) + panelopen = !panelopen + playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1) + to_chat(user, text("You [panelopen ? "open" : "close"] the unit's maintenance panel.")) + updateUsrDialog() + update_icon() + return + if(isCrowbar(I)) + if((stat & NOPOWER) && !islocked && !isopen) + to_chat(user, "You begin prying the unit open.") + if(do_after(user, 50, src)) + isopen = 1 + to_chat(user, "You pry the unit open.") + update_icon() + else if(islocked) + to_chat(user, "You can't pry the unit open, it's locked!") + return + if(istype(I, /obj/item/grab) ) + var/obj/item/grab/G = I + if( !(ismob(G.affecting)) ) + return + if (!isopen) + to_chat(user, "The unit's doors are shut.") + return + if ((stat & NOPOWER) || isbroken) + to_chat(user, "The unit is not operational.") + return + if ( (occupant) || (helmet ) || (suit) || (boots) || (tank) || (mask)) //Unit needs to be absolutely empty + to_chat(user, "The unit's storage area is too cluttered.") + return + visible_message("[user] starts putting [G.affecting.name] into the Suit Storage Unit.", 3) + if(do_after(user, 20, src)) + if(!G || !G.affecting) return //derpcheck + var/mob/M = G.affecting + if (M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.loc = src + occupant = M + isopen = 0 //close ittt + add_fingerprint(user) + qdel(G) + updateUsrDialog() + update_icon() + return + return + if( istype(I,/obj/item/clothing/suit/space) ) + if(!isopen) + return + var/obj/item/clothing/suit/space/S = I + if(suit) + to_chat(user, "The unit already contains a suit.") + return + to_chat(user, "You load the [S.name] into the storage compartment.") + user.drop_item() + S.forceMove(src) + suit = S + update_icon() + updateUsrDialog() + return + if( istype(I,/obj/item/clothing/head/helmet/space) ) + if(!isopen) + return + var/obj/item/clothing/head/helmet/H = I + if(helmet ) + to_chat(user, "The unit already contains a helmet.") + return + to_chat(user, "You load the [H.name] into the storage compartment.") + user.drop_item() + H.forceMove(src) + helmet = H + update_icon() + updateUsrDialog() + return + if( istype(I,/obj/item/clothing/shoes/magboots) ) + if(!isopen) + return + var/obj/item/clothing/shoes/magboots/B = I + if(boots) + to_chat(user, "The unit already contains a pair of magboots.") + return + to_chat(user, "You load the [B.name] into the storage compartment.") + user.drop_item() + B.forceMove(src) + boots = B + update_icon() + updateUsrDialog() + return + if( istype(I,/obj/item/weapon/tank) ) + if(!isopen) + return + var/obj/item/weapon/tank/T = I + if(tank) + to_chat(user, "The unit already contains an air tank.") + return + to_chat(user, "You load the [T.name] into the storage compartment.") + user.drop_item() + T.forceMove(src) + tank = T + update_icon() + updateUsrDialog() + return + if( istype(I,/obj/item/clothing/mask) ) + if(!isopen) + return + var/obj/item/clothing/mask/M = I + if(mask) + to_chat(user, "The unit already contains a mask.") + return + to_chat(user, "You load the [M.name] into the storage compartment.") + user.drop_item() + M.forceMove(src) + mask = M + update_icon() + updateUsrDialog() + return + update_icon() + updateUsrDialog() + return + + +/obj/machinery/suit_storage_unit/attack_ai(mob/user as mob) + return attack_hand(user) + +//////////////////////////////REMINDER: Make it lock once you place some fucker inside. + +//God this entire file is fucking awful +//Suit painter for Bay's special snowflake aliums. + +/obj/machinery/suit_cycler + + name = "suit cycler" + desc = "An industrial machine for painting and refitting voidsuits." + anchored = 1 + density = 1 + + icon = 'icons/obj/suitstorage.dmi' + icon_state = "close" + + req_access = list(access_captain,access_heads) + + var/active = 0 // PLEASE HOLD. + var/safeties = 1 // The cycler won't start with a living thing inside it unless safeties are off. + var/irradiating = 0 // If this is > 0, the cycler is decontaminating whatever is inside it. + var/radiation_level = 2 // 1 is removing germs, 2 is removing blood, 3 is removing phoron. + var/model_text = "" // Some flavour text for the topic box. + var/locked = 1 // If locked, nothing can be taken from or added to the cycler. + var/can_repair // If set, the cycler can repair voidsuits. + var/electrified = 0 + + //Departments that the cycler can paint suits to look like. + var/list/departments = list("Engineering","Mining","Medical","Security","Atmos","Science","Pilot") + //Species that the suits can be configured to fit. + var/list/species = list(SPECIES_HUMAN,SPECIES_SKRELL,SPECIES_UNATHI,SPECIES_TAJARA) + + var/target_department + var/target_species + + var/mob/living/carbon/human/occupant = null + var/obj/item/clothing/suit/space/void/suit = null + var/obj/item/clothing/head/helmet/space/helmet = null + + var/datum/wires/suit_storage_unit/wires = null + +/obj/machinery/suit_cycler/New() + ..() + + wires = new(src) + target_department = departments[1] + target_species = species[1] + if(!target_department || !target_species) qdel(src) + +/obj/machinery/suit_cycler/Destroy() + qdel(wires) + wires = null + return ..() + +/obj/machinery/suit_cycler/engineering + name = "Engineering suit cycler" + model_text = "Engineering" + req_access = list(access_construction) + departments = list("Engineering","Atmos") + species = list(SPECIES_HUMAN,SPECIES_TAJARA,SPECIES_SKRELL,SPECIES_UNATHI) //Add Unathi when sprites exist for their suits. + +/obj/machinery/suit_cycler/mining + name = "Mining suit cycler" + model_text = "Mining" + req_access = list(access_mining) + departments = list("Mining") + species = list(SPECIES_HUMAN,SPECIES_TAJARA,SPECIES_SKRELL,SPECIES_UNATHI) + +/obj/machinery/suit_cycler/science + name = "Excavation suit cycler" + model_text = "Excavation" + req_access = list(access_xenoarch) + departments = list("Science") + species = list(SPECIES_HUMAN,SPECIES_TAJARA,SPECIES_SKRELL,SPECIES_UNATHI) + +/obj/machinery/suit_cycler/security + name = "Security suit cycler" + model_text = "Security" + req_access = list(access_security) + departments = list("Security") + species = list(SPECIES_HUMAN,SPECIES_TAJARA,SPECIES_SKRELL,SPECIES_UNATHI) + +/obj/machinery/suit_cycler/medical + name = "Medical suit cycler" + model_text = "Medical" + req_access = list(access_medical) + departments = list("Medical") + species = list(SPECIES_HUMAN,SPECIES_TAJARA,SPECIES_SKRELL,SPECIES_UNATHI) + +/obj/machinery/suit_cycler/syndicate + name = "Nonstandard suit cycler" + model_text = "Nonstandard" + req_access = list(access_syndicate) + departments = list("Mercenary") + species = list(SPECIES_HUMAN,SPECIES_TAJARA,SPECIES_SKRELL,SPECIES_UNATHI) + can_repair = 1 + +/obj/machinery/suit_cycler/pilot + name = "Pilot suit cycler" + model_text = "Pilot" + req_access = list(access_mining_office) + departments = list("Pilot") + species = list(SPECIES_HUMAN,SPECIES_TAJARA,SPECIES_SKRELL,SPECIES_UNATHI) + +/obj/machinery/suit_cycler/attack_ai(mob/user as mob) + return attack_hand(user) + +/obj/machinery/suit_cycler/attackby(obj/item/I as obj, mob/user as mob) + + if(electrified != 0) + if(shock(user, 100)) + return + + //Hacking init. + if(isMultitool(I) || isWirecutter(I)) + if(panel_open) + attack_hand(user) + return + //Other interface stuff. + if(istype(I, /obj/item/grab)) + var/obj/item/grab/G = I + + if(!(ismob(G.affecting))) + return + + if(locked) + to_chat(user, "The suit cycler is locked.") + return + + if(contents.len > 0) + to_chat(user, "There is no room inside the cycler for [G.affecting.name].") + return + + visible_message("[user] starts putting [G.affecting.name] into the suit cycler.", 3) + + if(do_after(user, 20, src)) + if(!G || !G.affecting) return + var/mob/M = G.affecting + if (M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.loc = src + occupant = M + + add_fingerprint(user) + qdel(G) + + updateUsrDialog() + + return + else if(isScrewdriver(I)) + + panel_open = !panel_open + to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.") + updateUsrDialog() + return + + else if(istype(I,/obj/item/clothing/head/helmet/space)) + + if(locked) + to_chat(user, "The suit cycler is locked.") + return + + if(helmet) + to_chat(user, "The cycler already contains a helmet.") + return + + if(I.icon_override == CUSTOM_ITEM_MOB) + to_chat(user, "You cannot refit a customised voidsuit.") + return + + to_chat(user, "You fit \the [I] into the suit cycler.") + user.drop_item() + I.loc = src + helmet = I + + update_icon() + updateUsrDialog() + return + + else if(istype(I,/obj/item/clothing/suit/space/void)) + + if(locked) + to_chat(user, "The suit cycler is locked.") + return + + if(suit) + to_chat(user, "The cycler already contains a voidsuit.") + return + + if(I.icon_override == CUSTOM_ITEM_MOB) + to_chat(user, "You cannot refit a customised voidsuit.") + return + + to_chat(user, "You fit \the [I] into the suit cycler.") + user.drop_item() + I.loc = src + suit = I + + update_icon() + updateUsrDialog() + return + + ..() + +/obj/machinery/suit_cycler/emag_act(var/remaining_charges, var/mob/user) + if(emagged) + to_chat(user, "The cycler has already been subverted.") + return + + //Clear the access reqs, disable the safeties, and open up all paintjobs. + to_chat(user, "You run the sequencer across the interface, corrupting the operating protocols.") + departments = list("Engineering","Mining","Medical","Security","Atmos","^%###^%$") + emagged = 1 + safeties = 0 + req_access = list() + updateUsrDialog() + return 1 + +/obj/machinery/suit_cycler/attack_hand(mob/user as mob) + if(..() || stat & (BROKEN|NOPOWER)) + return + + if(!user.IsAdvancedToolUser()) + return 0 + + if(electrified != 0) + if(shock(user, 100)) + return + + user.set_machine(src) + + var/dat = "Suit Cycler Interface" + + if(active) + dat+= "
            The [model_text ? "[model_text] " : ""]suit cycler is currently in use. Please wait..." + + else if(locked) + dat += "
            The [model_text ? "[model_text] " : ""]suit cycler is currently locked. Please contact your system administrator." + if(allowed(user)) + dat += "
            \[unlock unit\]" + else + dat += "

            Suit cycler

            " + dat += "Welcome to the [model_text ? "[model_text] " : ""]suit cycler control panel. \[lock unit\]
            " + + dat += "

            Maintenance

            " + dat += "Helmet: [helmet ? "\the [helmet]" : "no helmet stored" ]. \[eject\]
            " + dat += "Suit: [suit ? "\the [suit]" : "no suit stored" ]. \[eject\]" + + if(can_repair && suit && istype(suit)) + dat += "[(suit.damage ? " \[repair\]" : "")]" + + dat += "
            UV decontamination systems: SYSTEM ERROR" : "green'>READY"]
            " + dat += "Output level: [radiation_level]
            " + dat += "\[select power level\] \[begin decontamination cycle\]

            " + + dat += "

            Customisation

            " + dat += "Target product: [target_department], [target_species]." + dat += "
            \[apply customisation routine\]


            " + + if(panel_open) + wires.Interact(user) + + user << browse(dat, "window=suit_cycler") + onclose(user, "suit_cycler") + return + +/obj/machinery/suit_cycler/Topic(href, href_list) + if(href_list["eject_suit"]) + if(!suit) return + suit.loc = get_turf(src) + suit = null + else if(href_list["eject_helmet"]) + if(!helmet) return + helmet.loc = get_turf(src) + helmet = null + else if(href_list["select_department"]) + var/choice = input("Please select the target department paintjob.","Suit cycler",null) as null|anything in departments + if(choice) target_department = choice + else if(href_list["select_species"]) + var/choice = input("Please select the target species configuration.","Suit cycler",null) as null|anything in species + if(choice) target_species = choice + else if(href_list["select_rad_level"]) + var/choices = list(1,2,3) + if(emagged) + choices = list(1,2,3,4,5) + radiation_level = input("Please select the desired radiation level.","Suit cycler",null) as null|anything in choices + else if(href_list["repair_suit"]) + + if(!suit || !can_repair) return + active = 1 + spawn(100) + repair_suit() + finished_job() + + else if(href_list["apply_paintjob"]) + + if(!suit && !helmet) return + active = 1 + spawn(100) + apply_paintjob() + finished_job() + + else if(href_list["toggle_safties"]) + safeties = !safeties + + else if(href_list["toggle_lock"]) + + if(allowed(usr)) + locked = !locked + to_chat(usr, "You [locked ? "lock" : "unlock"] [src].") + else + to_chat(usr, FEEDBACK_ACCESS_DENIED) + + else if(href_list["begin_decontamination"]) + + if(safeties && occupant) + to_chat(usr, "The cycler has detected an occupant. Please remove the occupant before commencing the decontamination cycle.") + return + + active = 1 + irradiating = 10 + updateUsrDialog() + + sleep(10) + + if(helmet) + if(radiation_level > 2) + helmet.decontaminate() + if(radiation_level > 1) + helmet.clean_blood() + + if(suit) + if(radiation_level > 2) + suit.decontaminate() + if(radiation_level > 1) + suit.clean_blood() + + updateUsrDialog() + return + +/obj/machinery/suit_cycler/Process() + + if(electrified > 0) + electrified-- + + if(!active) + return + + if(active && stat & (BROKEN|NOPOWER)) + active = 0 + irradiating = 0 + electrified = 0 + return + + if(irradiating == 1) + finished_job() + irradiating = 0 + return + + irradiating-- + + if(occupant) + if(prob(radiation_level*2)) occupant.emote("scream") + if(radiation_level > 2) + occupant.take_organ_damage(0,radiation_level*2 + rand(1,3)) + if(radiation_level > 1) + occupant.take_organ_damage(0,radiation_level + rand(1,3)) + occupant.apply_effect(radiation_level*10, IRRADIATE, blocked = occupant.getarmor(null, "rad")) + +/obj/machinery/suit_cycler/proc/finished_job() + var/turf/T = get_turf(src) + T.visible_message("\icon[src]The [src] pings loudly.") + icon_state = initial(icon_state) + active = 0 + updateUsrDialog() + +/obj/machinery/suit_cycler/proc/repair_suit() + if(!suit || !suit.damage || !suit.can_breach) + return + + suit.breaches = list() + suit.calc_breach_damage() + + return + +/obj/machinery/suit_cycler/verb/leave() + set name = "Eject Cycler" + set category = "Object" + set src in oview(1) + + if (usr.stat != 0) + return + + eject_occupant(usr) + +/obj/machinery/suit_cycler/proc/eject_occupant(mob/user as mob) + + if(locked || active) + to_chat(user, "The cycler is locked.") + return + + if (!occupant) + return + + if (occupant.client) + occupant.client.eye = occupant.client.mob + occupant.client.perspective = MOB_PERSPECTIVE + + occupant.loc = get_turf(occupant) + occupant = null + + add_fingerprint(user) + updateUsrDialog() + update_icon() + + return + +//There HAS to be a less bloated way to do this. TODO: some kind of table/icon name coding? ~Z +/obj/machinery/suit_cycler/proc/apply_paintjob() + + if(!target_species || !target_department) + return + + if(target_species) + if(helmet) helmet.refit_for_species(target_species) + if(suit) suit.refit_for_species(target_species) + + switch(target_department) + if("Engineering") + if(helmet) + helmet.SetName("engineering voidsuit helmet") + helmet.icon_state = "rig0-engineering" + helmet.item_state = "eng_helm" + if(suit) + suit.SetName("engineering voidsuit") + suit.icon_state = "rig-engineering" + suit.item_state_slots = list( + slot_l_hand_str = "eng_voidsuit", + slot_r_hand_str = "eng_voidsuit", + ) + if("Mining") + if(helmet) + helmet.SetName("mining voidsuit helmet") + helmet.icon_state = "rig0-mining" + helmet.item_state = "mining_helm" + if(suit) + suit.SetName("mining voidsuit") + suit.icon_state = "rig-mining" + suit.item_state_slots = list( + slot_l_hand_str = "mining_voidsuit", + slot_r_hand_str = "mining_voidsuit", + ) + if("Science") + if(helmet) + helmet.SetName("excavation voidsuit helmet") + helmet.icon_state = "rig0-excavation" + helmet.item_state = "excavation_helm" + if(suit) + suit.SetName("excavation voidsuit") + suit.icon_state = "rig-excavation" + suit.item_state_slots = list( + slot_l_hand_str = "excavation_voidsuit", + slot_r_hand_str = "excavation_voidsuit", + ) + if("Medical") + if(helmet) + helmet.SetName("medical voidsuit helmet") + helmet.icon_state = "rig0-medical" + helmet.item_state = "medical_helm" + if(suit) + suit.SetName("medical voidsuit") + suit.icon_state = "rig-medical" + suit.item_state_slots = list( + slot_l_hand_str = "medical_voidsuit", + slot_r_hand_str = "medical_voidsuit", + ) + if("Security") + if(helmet) + helmet.SetName("security voidsuit helmet") + helmet.icon_state = "rig0-sec" + helmet.item_state = "sec_helm" + if(suit) + suit.SetName("security voidsuit") + suit.icon_state = "rig-sec" + suit.item_state_slots = list( + slot_l_hand_str = "sec_voidsuit", + slot_r_hand_str = "sec_voidsuit", + ) + if("Atmos") + if(helmet) + helmet.SetName("atmospherics voidsuit helmet") + helmet.icon_state = "rig0-atmos" + helmet.item_state = "atmos_helm" + if(suit) + suit.SetName("atmospherics voidsuit") + suit.icon_state = "rig-atmos" + suit.item_state_slots = list( + slot_l_hand_str = "atmos_voidsuit", + slot_r_hand_str = "atmos_voidsuit", + ) + if("Explorer") + if(helmet) + helmet.SetName("exploration voidsuit helmet") + helmet.icon_state = "helm_explorer" + helmet.item_state = "helm_explorer" + if(suit) + suit.SetName("exploration voidsuit") + suit.icon_state = "void_explorer" + + if("^%###^%$" || "Mercenary") + if(helmet) + helmet.SetName("blood-red voidsuit helmet") + helmet.icon_state = "rig0-syndie" + helmet.item_state = "syndie_helm" + if(suit) + suit.SetName("blood-red voidsuit") + suit.icon_state = "rig-syndie" + suit.item_state_slots = list( + slot_l_hand_str = "syndie_voidsuit", + slot_r_hand_str = "syndie_voidsuit", + ) + if("Pilot") + if(helmet) + helmet.SetName("pilot voidsuit helmet") + helmet.icon_state = "rig0_pilot" + helmet.item_state = "pilot_helm" + if(suit) + suit.SetName("pilot voidsuit") + suit.icon_state = "rig-pilot" + + if(helmet) helmet.SetName("refitted [helmet.name]") + if(suit) suit.SetName("refitted [suit.name]") diff --git a/code/game/machinery/supply_display.dm b/code/game/machinery/supply_display.dm new file mode 100644 index 00000000..3458627f --- /dev/null +++ b/code/game/machinery/supply_display.dm @@ -0,0 +1,34 @@ +/obj/machinery/status_display/supply_display + ignore_friendc = 1 + +/obj/machinery/status_display/supply_display/update() + if(!..() && mode == STATUS_DISPLAY_CUSTOM) + message1 = "CARGO" + message2 = "" + + var/datum/shuttle/autodock/ferry/supply/shuttle = supply_controller.shuttle + if (!shuttle) + message2 = "Error" + else if(shuttle.has_arrive_time()) + message2 = get_supply_shuttle_timer() + if(length(message2) > CHARS_PER_LINE) + message2 = "Error" + else if (shuttle.is_launching()) + if (shuttle.at_station()) + message2 = "Launch" + else + message2 = "ETA" + else + if(shuttle.at_station()) + message2 = "Docked" + else + message1 = "" + update_display(message1, message2) + return 1 + return 0 + +/obj/machinery/status_display/supply_display/receive_signal/(datum/signal/signal) + if(signal.data["command"] == "supply") + mode = STATUS_DISPLAY_CUSTOM + else + ..(signal) diff --git a/code/game/machinery/supplybeacon.dm b/code/game/machinery/supplybeacon.dm new file mode 100644 index 00000000..2d59e7a9 --- /dev/null +++ b/code/game/machinery/supplybeacon.dm @@ -0,0 +1,118 @@ +// Used to deploy the bacon. +/obj/item/supply_beacon + name = "inactive supply beacon" + icon = 'icons/obj/supplybeacon.dmi' + desc = "An inactive, hacked supply beacon stamped with the Nyx Rapid Fabrication logo. Good for one (1) ballistic supply pod shipment." + icon_state = "beacon" + var/deploy_path = /obj/machinery/power/supply_beacon + var/deploy_time = 30 + +/obj/item/supply_beacon/supermatter + name = "inactive supermatter supply beacon" + deploy_path = /obj/machinery/power/supply_beacon/supermatter + +/obj/item/supply_beacon/attack_self(var/mob/user) + user.visible_message("\The [user] begins setting up \the [src].") + if(!do_after(user, deploy_time, src)) + return + var/obj/S = new deploy_path(get_turf(user)) + user.visible_message("\The [user] deploys \the [S].") + user.unEquip(src) + qdel(src) + +/obj/machinery/power/supply_beacon + name = "supply beacon" + desc = "A bulky moonshot supply beacon. Someone has been messing with the wiring." + icon = 'icons/obj/supplybeacon.dmi' + icon_state = "beacon" + + anchored = 0 + density = 1 + stat = 0 + + var/target_drop_time + var/drop_delay = 450 + var/expended + var/drop_type + +/obj/machinery/power/supply_beacon/New() + ..() + if(!drop_type) drop_type = pick(supply_drop_random_loot_types()) + +/obj/machinery/power/supply_beacon/supermatter + name = "supermatter supply beacon" + drop_type = "supermatter" + +/obj/machinery/power/supply_beacon/attackby(var/obj/item/weapon/W, var/mob/user) + if(!use_power && isWrench(W)) + if(!anchored && !connect_to_network()) + to_chat(user, "This device must be placed over an exposed cable.") + return + anchored = !anchored + user.visible_message("\The [user] [anchored ? "secures" : "unsecures"] \the [src].") + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + return + return ..() + +/obj/machinery/power/supply_beacon/attack_hand(var/mob/user) + + if(expended) + use_power = 0 + to_chat(user, "\The [src] has used up its charge.") + return + + if(anchored) + return use_power ? deactivate(user) : activate(user) + else + to_chat(user, "You need to secure the beacon with a wrench first!") + return + +/obj/machinery/power/supply_beacon/attack_ai(var/mob/user) + if(user.Adjacent(src)) + attack_hand(user) + +/obj/machinery/power/supply_beacon/proc/activate(var/mob/user) + if(expended) + return + if(surplus() < 500) + if(user) to_chat(user, "The connected wire doesn't have enough current.") + return + set_light(3, 3, "#00ccaa") + icon_state = "beacon_active" + use_power = 1 + if(user) to_chat(user, "You activate the beacon. The supply drop will be dispatched soon.") + +/obj/machinery/power/supply_beacon/proc/deactivate(var/mob/user, var/permanent) + if(permanent) + expended = 1 + icon_state = "beacon_depleted" + else + icon_state = "beacon" + set_light(0) + use_power = 0 + target_drop_time = null + if(user) to_chat(user, "You deactivate the beacon.") + +/obj/machinery/power/supply_beacon/Destroy() + if(use_power) + deactivate() + ..() + +/obj/machinery/power/supply_beacon/Process() + if(expended) + return PROCESS_KILL + if(!use_power) + return + if(draw_power(500) < 500) + deactivate() + return + if(!target_drop_time) + target_drop_time = world.time + drop_delay + else if(world.time >= target_drop_time) + deactivate(permanent = 1) + var/drop_x = src.x-2 + var/drop_y = src.y-2 + var/drop_z = src.z + command_announcement.Announce("Nyx Rapid Fabrication priority supply request #[rand(1000,9999)]-[rand(100,999)] recieved. Shipment dispatched via ballistic supply pod for immediate delivery. Have a nice day.", "Thank You For Your Patronage") + spawn(rand(100,300)) + new /datum/random_map/droppod/supply(null, drop_x, drop_y, drop_z, supplied_drop = drop_type) // Splat. diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm new file mode 100644 index 00000000..77f19a27 --- /dev/null +++ b/code/game/machinery/syndicatebeacon.dm @@ -0,0 +1,173 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +// Beacon randomly spawns in space +// When a non-traitor (no special role in /mind) uses it, he is given the choice to become a traitor +// If he accepts there is a random chance he will be accepted, rejected, or rejected and killed +// Bringing certain items can help improve the chance to become a traitor + + +/obj/machinery/syndicate_beacon + name = "ominous beacon" + desc = "This looks suspicious..." + icon = 'icons/obj/device.dmi' + icon_state = "syndbeacon" + + anchored = 1 + density = 1 + + var/temptext = "" + var/selfdestructing = 0 + var/charges = 1 + +/obj/machinery/syndicate_beacon/attack_hand(var/mob/user as mob) + usr.set_machine(src) + var/dat = "Scanning [pick("retina pattern", "voice print", "fingerprints", "dna sequence")]...
            Identity confirmed,
            " + if(istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon/ai)) + if(is_special_character(user)) + dat += "Operative record found. Greetings, Agent [user.name].
            " + else if(charges < 1) + dat += "Connection severed.
            " + else + var/honorific = "Mr." + if(user.gender == FEMALE) + honorific = "Ms." + dat += "Identity not found in operative database. What can the Syndicate do for you today, [honorific] [user.name]?
            " + if(!selfdestructing) + dat += "

            \"[pick("I want to switch teams.", "I want to work for you.", "Let me join you.", "I can be of use to you.", "You want me working for you, and here's why...", "Give me an objective.", "How's the 401k over at the Syndicate?")]\"
            " + dat += temptext + user << browse(dat, "window=syndbeacon") + onclose(user, "syndbeacon") + +/obj/machinery/syndicate_beacon/Topic(href, href_list) + if(..()) + return + if(href_list["betraitor"]) + if(charges < 1) + src.updateUsrDialog() + return + var/mob/M = locate(href_list["traitormob"]) + if(M.mind.special_role || jobban_isbanned(M, MODE_TRAITOR)) + temptext = "We have no need for you at this time. Have a pleasant day.
            " + src.updateUsrDialog() + return + charges -= 1 + switch(rand(1,2)) + if(1) + temptext = "Double-crosser. You planned to betray us from the start. Allow us to repay the favor in kind." + src.updateUsrDialog() + spawn(rand(50,200)) selfdestruct() + return + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/N = M + to_chat(M, "You have joined the ranks of the Syndicate and become a traitor to the station!") + traitors.add_antagonist(N.mind) + traitors.equip(N) + message_admins("[N]/([N.ckey]) has accepted a traitor objective from a syndicate beacon.") + + + src.updateUsrDialog() + return + + +/obj/machinery/syndicate_beacon/proc/selfdestruct() + selfdestructing = 1 + spawn() explosion(src.loc, 1, rand(1,3), rand(3,8), 10) + +//////////////////////////////////////// +//Singularity beacon +//////////////////////////////////////// +/obj/machinery/power/singularity_beacon + name = "ominous beacon" + desc = "This looks suspicious..." + icon = 'icons/obj/singularity.dmi' + icon_state = "beacon" + + anchored = 0 + density = 1 + plane = ABOVE_OBJ_PLANE + layer = BASE_ABOVE_OBJ_LAYER //so people can't hide it and it's REALLY OBVIOUS + stat = 0 + + var/active = 0 + var/icontype = "beacon" + +/obj/machinery/power/singularity_beacon/Destroy() + if(active) + STOP_PROCESSING(SSmachines, src) + . = ..() + +/obj/machinery/power/singularity_beacon/proc/Activate(mob/user = null) + if(surplus() < 1500) + if(user) to_chat(user, "The connected wire doesn't have enough current.") + return + for(var/obj/singularity/singulo in world) + if(singulo.z == z) + singulo.target = src + icon_state = "[icontype]1" + active = 1 + + START_PROCESSING(SSmachines, src) + if(user) + to_chat(user, "You activate the beacon.") + + +/obj/machinery/power/singularity_beacon/proc/Deactivate(mob/user = null) + for(var/obj/singularity/singulo in world) + if(singulo.target == src) + singulo.target = null + icon_state = "[icontype]0" + active = 0 + if(user) + to_chat(user, "You deactivate the beacon.") + + +/obj/machinery/power/singularity_beacon/attack_ai(mob/user as mob) + return + + +/obj/machinery/power/singularity_beacon/attack_hand(var/mob/user as mob) + if(anchored) + return active ? Deactivate(user) : Activate(user) + else + to_chat(user, "You need to screw the beacon to the floor first!") + return + + +/obj/machinery/power/singularity_beacon/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isScrewdriver(W)) + if(active) + to_chat(user, "You need to deactivate the beacon first!") + return + + if(anchored) + anchored = 0 + to_chat(user, "You unscrew the beacon from the floor.") + disconnect_from_network() + return + else + if(!connect_to_network()) + to_chat(user, "This device must be placed over an exposed cable.") + return + anchored = 1 + to_chat(user, "You screw the beacon to the floor and attach the cable.") + return + ..() + return + + +/obj/machinery/power/singularity_beacon/Destroy() + if(active) + Deactivate() + ..() + +//stealth direct power usage +/obj/machinery/power/singularity_beacon/Process() + if(!active) + return PROCESS_KILL + else + if(draw_power(1500) < 1500) + Deactivate() + +/obj/machinery/power/singularity_beacon/syndicate + icontype = "beaconsynd" + icon_state = "beaconsynd0" diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm new file mode 100644 index 00000000..76fcce6f --- /dev/null +++ b/code/game/machinery/telecomms/broadcaster.dm @@ -0,0 +1,635 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/* + The broadcaster sends processed messages to all radio devices in the game. They + do not have to be headsets; intercoms and station-bounced radios suffice. + + They receive their message from a server after the message has been logged. +*/ + +var/list/recentmessages = list() // global list of recent messages broadcasted : used to circumvent massive radio spam +var/message_delay = 0 // To make sure restarting the recentmessages list is kept in sync + +/obj/machinery/telecomms/broadcaster + name = "Subspace Broadcaster" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "broadcaster" + desc = "A dish-shaped machine used to broadcast processed subspace signals." + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 25 + machinetype = 5 + produces_heat = 0 + delay = 7 + circuitboard = /obj/item/weapon/circuitboard/telecomms/broadcaster + outage_probability = 10 + +/obj/machinery/telecomms/broadcaster/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) + // Don't broadcast rejected signals + if(signal.data["reject"]) + return + + if(signal.data["message"]) + + // Prevents massive radio spam + signal.data["done"] = 1 // mark the signal as being broadcasted + // Search for the original signal and mark it as done as well + var/datum/signal/original = signal.data["original"] + if(original) + original.data["done"] = 1 + original.data["compression"] = signal.data["compression"] + original.data["level"] = signal.data["level"] + + var/signal_message = "[signal.frequency]:[signal.data["message"]]:[signal.data["realname"]]" + if(signal_message in recentmessages) + return + recentmessages.Add(signal_message) + + if(signal.data["slow"] > 0) + sleep(signal.data["slow"]) // simulate the network lag if necessary + + signal.data["level"] |= listening_levels + + /** #### - Normal Broadcast - #### **/ + + if(signal.data["type"] == 0) + + /* ###### Broadcast a message using signal.data ###### */ + Broadcast_Message(signal.data["connection"], signal.data["mob"], + signal.data["vmask"], signal.data["vmessage"], + signal.data["radio"], signal.data["message"], + signal.data["name"], signal.data["job"], + signal.data["realname"], signal.data["vname"],, + signal.data["compression"], signal.data["level"], signal.frequency, + signal.data["verb"], signal.data["language"] ) + + + /** #### - Simple Broadcast - #### **/ + + if(signal.data["type"] == 1) + + /* ###### Broadcast a message using signal.data ###### */ + Broadcast_SimpleMessage(signal.data["name"], signal.frequency, + signal.data["message"],null, null, + signal.data["compression"], listening_levels) + + + /** #### - Artificial Broadcast - #### **/ + // (Imitates a mob) + + if(signal.data["type"] == 2) + + /* ###### Broadcast a message using signal.data ###### */ + // Parameter "data" as 4: AI can't track this person/mob + + Broadcast_Message(signal.data["connection"], signal.data["mob"], + signal.data["vmask"], signal.data["vmessage"], + signal.data["radio"], signal.data["message"], + signal.data["name"], signal.data["job"], + signal.data["realname"], signal.data["vname"], 4, signal.data["compression"], signal.data["level"], signal.frequency, + signal.data["verb"], signal.data["language"]) + + if(!message_delay) + message_delay = 1 + spawn(10) + message_delay = 0 + recentmessages = list() + + /* --- Do a snazzy animation! --- */ + flick("broadcaster_send", src) + +/obj/machinery/telecomms/broadcaster/Destroy() + // In case message_delay is left on 1, otherwise it won't reset the list and people can't say the same thing twice anymore. + if(message_delay) + message_delay = 0 + ..() + + +/* + Basically just an empty shell for receiving and broadcasting radio messages. Not + very flexible, but it gets the job done. +*/ + +/obj/machinery/telecomms/allinone + name = "Telecommunications Mainframe" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "comm_server" + desc = "A compact machine used for portable subspace telecommuniations processing." + density = 1 + anchored = 1 + use_power = 0 + idle_power_usage = 0 + machinetype = 6 + produces_heat = 0 + on = TRUE + var/intercept = 0 // if nonzero, broadcasts all messages to syndicate channel + +/obj/machinery/telecomms/allinone/receive_signal(datum/signal/signal) + + //if(!on) // has to be on to receive messages + // return + + if(is_freq_listening(signal)) // detect subspace signals + + signal.data["done"] = 1 // mark the signal as being broadcasted + signal.data["compression"] = 0 + + // Search for the original signal and mark it as done as well + var/datum/signal/original = signal.data["original"] + if(original) + original.data["done"] = 1 + + if(signal.data["slow"] > 0) + sleep(signal.data["slow"]) // simulate the network lag if necessary + + /* ###### Broadcast a message using signal.data ###### */ + + var/datum/radio_frequency/connection = signal.data["connection"] + + if(connection.frequency in ANTAG_FREQS) // if antag broadcast, just + Broadcast_Message(signal.data["connection"], signal.data["mob"], + signal.data["vmask"], signal.data["vmessage"], + signal.data["radio"], signal.data["message"], + signal.data["name"], signal.data["job"], + signal.data["realname"], signal.data["vname"],, signal.data["compression"], list(0), connection.frequency, + signal.data["verb"], signal.data["language"]) + else + if(intercept) + Broadcast_Message(signal.data["connection"], signal.data["mob"], + signal.data["vmask"], signal.data["vmessage"], + signal.data["radio"], signal.data["message"], + signal.data["name"], signal.data["job"], + signal.data["realname"], signal.data["vname"], 3, signal.data["compression"], list(0), connection.frequency, + signal.data["verb"], signal.data["language"]) + + + +/** + + Here is the big, bad function that broadcasts a message given the appropriate + parameters. + + @param connection: + The datum generated in radio.dm, stored in signal.data["connection"]. + + @param M: + Reference to the mob/speaker, stored in signal.data["mob"] + + @param vmask: + Boolean value if the mob is "hiding" its identity via voice mask, stored in + signal.data["vmask"] + + @param vmessage: + If specified, will display this as the message; such as "chimpering" + for monkies if the mob is not understood. Stored in signal.data["vmessage"]. + + @param radio: + Reference to the radio broadcasting the message, stored in signal.data["radio"] + + @param message: + The actual string message to display to mobs who understood mob M. Stored in + signal.data["message"] + + @param name: + The name to display when a mob receives the message. signal.data["name"] + + @param job: + The name job to display for the AI when it receives the message. signal.data["job"] + + @param realname: + The "real" name associated with the mob. signal.data["realname"] + + @param vname: + If specified, will use this name when mob M is not understood. signal.data["vname"] + + @param data: + If specified: + 1 -- Will only broadcast to intercoms + 2 -- Will only broadcast to intercoms and station-bounced radios + 3 -- Broadcast to syndicate frequency + 4 -- AI can't track down this person. Useful for imitation broadcasts where you can't find the actual mob + + @param compression: + If 0, the signal is audible + If nonzero, the signal may be partially inaudible or just complete gibberish. + + @param level: + The list of Z levels that the sending radio is broadcasting to. Having 0 in the list broadcasts on all levels + + @param freq + The frequency of the signal + +**/ + +/proc/Broadcast_Message(var/datum/radio_frequency/connection, var/mob/M, + var/vmask, var/vmessage, var/obj/item/device/radio/radio, + var/message, var/name, var/job, var/realname, var/vname, + var/data, var/compression, var/list/level, var/freq, var/verbage = "says", var/datum/language/speaking = null) + + + /* ###### Prepare the radio connection ###### */ + + var/display_freq = freq + + var/list/obj/item/device/radio/radios = list() + + // --- Broadcast only to intercom devices --- + + if(data == 1) + + for (var/obj/item/device/radio/intercom/R in connection.devices["[RADIO_CHAT]"]) + if(R.receive_range(display_freq, level) > -1) + radios += R + + // --- Broadcast only to intercoms and station-bounced radios --- + + else if(data == 2) + + for (var/obj/item/device/radio/R in connection.devices["[RADIO_CHAT]"]) + + if(istype(R, /obj/item/device/radio/headset)) + continue + + if(R.receive_range(display_freq, level) > -1) + radios += R + + // --- Broadcast to antag radios! --- + + else if(data == 3) + for(var/antag_freq in ANTAG_FREQS) + var/datum/radio_frequency/antag_connection = radio_controller.return_frequency(antag_freq) + for (var/obj/item/device/radio/R in antag_connection.devices["[RADIO_CHAT]"]) + if(R.intercept && R.receive_range(antag_freq, level) > -1) + radios += R + + // --- Broadcast to ALL radio devices --- + + else + + for (var/obj/item/device/radio/R in connection.devices["[RADIO_CHAT]"]) + if(R.receive_range(display_freq, level) > -1) + radios += R + + // Get a list of mobs who can hear from the radios we collected. + var/list/receive = get_mobs_in_radio_ranges(radios) + + /* ###### Organize the receivers into categories for displaying the message ###### */ + + // Understood the message: + var/list/heard_masked = list() // masked name or no real name + var/list/heard_normal = list() // normal message + + // Did not understand the message: + var/list/heard_voice = list() // voice message (ie "chimpers") + var/list/heard_garbled = list() // garbled message (ie "f*c* **u, **i*er!") + var/list/heard_gibberish= list() // completely screwed over message (ie "F%! (O*# *#!<>&**%!") + + for (var/mob/R in receive) + + /* --- Loop through the receivers and categorize them --- */ + if(istype(R, /mob/new_player)) // we don't want new players to hear messages. rare but generates runtimes. + continue + + // Ghosts hearing all radio chat don't want to hear syndicate intercepts, they're duplicates + if(data == 3 && isghost(R) && R.get_preference_value(/datum/client_preference/ghost_radio) == GLOB.PREF_ALL_CHATTER) + continue + + // --- Check for compression --- + if(compression > 0) + heard_gibberish += R + continue + + // --- Can understand the speech --- + + if (!M || R.say_understands(M)) + + // - Not human or wearing a voice mask - + if (!M || !ishuman(M) || vmask) + heard_masked += R + + // - Human and not wearing voice mask - + else + heard_normal += R + + // --- Can't understand the speech --- + + else + // - The speaker has a prespecified "voice message" to display if not understood - + if (vmessage) + heard_voice += R + + // - Just display a garbled message - + else + heard_garbled += R + + + /* ###### Begin formatting and sending the message ###### */ + if (length(heard_masked) || length(heard_normal) || length(heard_voice) || length(heard_garbled) || length(heard_gibberish)) + + /* --- Some miscellaneous variables to format the string output --- */ + var/freq_text = get_frequency_name(display_freq) + + var/part_b_extra = "" + if(data == 3) // intercepted radio message + part_b_extra = " (Intercepted)" + var/part_a = "\icon[radio]\[[freq_text]\][part_b_extra] " // goes in the actual output + + // --- Some more pre-message formatting --- + var/part_b = " " // Tweaked for security headsets -- TLE + var/part_c = "" + + + // --- Filter the message; place it in quotes apply a verb --- + + var/quotedmsg = null + if(M) + quotedmsg = M.say_quote(message) + else + quotedmsg = "says, \"[message]\"" + + // --- This following recording is intended for research and feedback in the use of department radio channels --- + + var/part_blackbox_b = " \[[freq_text]\] " // Tweaked for security headsets -- TLE + var/blackbox_msg = "[part_a][name][part_blackbox_b][quotedmsg][part_c]" + //var/blackbox_admin_msg = "[part_a][M.name] (Real name: [M.real_name])[part_blackbox_b][quotedmsg][part_c]" + + //BR.messages_admin += blackbox_admin_msg + if(istype(blackbox)) + switch(display_freq) + if(PUB_FREQ) + blackbox.msg_common += blackbox_msg + if(SCI_FREQ) + blackbox.msg_science += blackbox_msg + if(COMM_FREQ) + blackbox.msg_command += blackbox_msg + if(MED_FREQ) + blackbox.msg_medical += blackbox_msg + if(ENG_FREQ) + blackbox.msg_engineering += blackbox_msg + if(SEC_FREQ) + blackbox.msg_security += blackbox_msg + if(DTH_FREQ) + blackbox.msg_deathsquad += blackbox_msg + if(RED_FREQ) + blackbox.msg_syndicate += blackbox_msg + if(BLUE_FREQ) + blackbox.msg_raider += blackbox_msg + if(SUP_FREQ) + blackbox.msg_cargo += blackbox_msg + if(SRV_FREQ) + blackbox.msg_service += blackbox_msg + if(EXP_FREQ) + blackbox.msg_exploration += blackbox_msg + else + blackbox.messages += blackbox_msg + + //End of research and feedback code. + + /* ###### Send the message ###### */ + + + /* --- Process all the mobs that heard a masked voice (understood) --- */ + + if (length(heard_masked)) + for (var/mob/R in heard_masked) + R.hear_radio(message,verbage, speaking, part_a, part_b, part_c, M, 0, name) + + /* --- Process all the mobs that heard the voice normally (understood) --- */ + + if (length(heard_normal)) + for (var/mob/R in heard_normal) + R.hear_radio(message, verbage, speaking, part_a, part_b, part_c, M, 0, realname) + + /* --- Process all the mobs that heard the voice normally (did not understand) --- */ + + if (length(heard_voice)) + for (var/mob/R in heard_voice) + R.hear_radio(message,verbage, speaking, part_a, part_b, part_c, M,0, vname) + + /* --- Process all the mobs that heard a garbled voice (did not understand) --- */ + // Displays garbled message (ie "f*c* **u, **i*er!") + + if (length(heard_garbled)) + for (var/mob/R in heard_garbled) + R.hear_radio(message, verbage, speaking, part_a, part_b, part_c, M, 1, vname) + + + /* --- Complete gibberish. Usually happens when there's a compressed message --- */ + + if (length(heard_gibberish)) + for (var/mob/R in heard_gibberish) + R.hear_radio(message, verbage, speaking, part_a, part_b, part_c, M, compression) + + return 1 + +/proc/Broadcast_SimpleMessage(var/source, var/frequency, var/text, var/data, var/mob/M, var/compression, var/level) + + /* ###### Prepare the radio connection ###### */ + + if(!M) + var/mob/living/carbon/human/H = new + M = H + + var/datum/radio_frequency/connection = radio_controller.return_frequency(frequency) + + var/display_freq = connection.frequency + + var/list/receive = list() + + + // --- Broadcast only to intercom devices --- + + if(data == 1) + for (var/obj/item/device/radio/intercom/R in connection.devices["[RADIO_CHAT]"]) + var/turf/position = get_turf(R) + if(position && position.z == level) + receive |= R.send_hear(display_freq, level) + + + // --- Broadcast only to intercoms and station-bounced radios --- + + else if(data == 2) + for (var/obj/item/device/radio/R in connection.devices["[RADIO_CHAT]"]) + + if(istype(R, /obj/item/device/radio/headset)) + continue + var/turf/position = get_turf(R) + if(position && position.z == level) + receive |= R.send_hear(display_freq) + + + // --- Broadcast to antag radios! --- + + else if(data == 3) + for(var/freq in ANTAG_FREQS) + var/datum/radio_frequency/antag_connection = radio_controller.return_frequency(freq) + for (var/obj/item/device/radio/R in antag_connection.devices["[RADIO_CHAT]"]) + var/turf/position = get_turf(R) + if(position && position.z == level) + receive |= R.send_hear(freq) + + + // --- Broadcast to ALL radio devices --- + + else + for (var/obj/item/device/radio/R in connection.devices["[RADIO_CHAT]"]) + var/turf/position = get_turf(R) + if(position && position.z == level) + receive |= R.send_hear(display_freq) + + + /* ###### Organize the receivers into categories for displaying the message ###### */ + + // Understood the message: + var/list/heard_normal = list() // normal message + + // Did not understand the message: + var/list/heard_garbled = list() // garbled message (ie "f*c* **u, **i*er!") + var/list/heard_gibberish= list() // completely screwed over message (ie "F%! (O*# *#!<>&**%!") + + for (var/mob/R in receive) + + /* --- Loop through the receivers and categorize them --- */ + // --- Check for compression --- + if(compression > 0) + + heard_gibberish += R + continue + + // --- Can understand the speech --- + + if (R.say_understands(M)) + + heard_normal += R + + // --- Can't understand the speech --- + + else + // - Just display a garbled message - + + heard_garbled += R + + + /* ###### Begin formatting and sending the message ###### */ + if (length(heard_normal) || length(heard_garbled) || length(heard_gibberish)) + + /* --- Some miscellaneous variables to format the string output --- */ + var/part_a = "" // goes in the actual output + var/freq_text = get_frequency_name(display_freq) + + // --- Some more pre-message formatting --- + + var/part_b_extra = "" + if(data == 3) // intercepted radio message + part_b_extra = " (Intercepted)" + + // Create a radio headset for the sole purpose of using its icon + var/obj/item/device/radio/headset/radio = new + + var/part_b = " \icon[radio]\[[freq_text]\][part_b_extra] " // Tweaked for security headsets -- TLE + var/part_blackbox_b = " \[[freq_text]\] " // Tweaked for security headsets -- TLE + var/part_c = "" + + var/blackbox_msg = "[part_a][source][part_blackbox_b]\"[text]\"[part_c]" + + //BR.messages_admin += blackbox_admin_msg + if(istype(blackbox)) + switch(display_freq) + if(PUB_FREQ) + blackbox.msg_common += blackbox_msg + if(SCI_FREQ) + blackbox.msg_science += blackbox_msg + if(COMM_FREQ) + blackbox.msg_command += blackbox_msg + if(MED_FREQ) + blackbox.msg_medical += blackbox_msg + if(ENG_FREQ) + blackbox.msg_engineering += blackbox_msg + if(SEC_FREQ) + blackbox.msg_security += blackbox_msg + if(DTH_FREQ) + blackbox.msg_deathsquad += blackbox_msg + if(RED_FREQ) + blackbox.msg_syndicate += blackbox_msg + if(BLUE_FREQ) + blackbox.msg_raider += blackbox_msg + if(SUP_FREQ) + blackbox.msg_cargo += blackbox_msg + if(SRV_FREQ) + blackbox.msg_service += blackbox_msg + if(EXP_FREQ) + blackbox.msg_exploration += blackbox_msg + else + blackbox.messages += blackbox_msg + + //End of research and feedback code. + + /* ###### Send the message ###### */ + + /* --- Process all the mobs that heard the voice normally (understood) --- */ + + if (length(heard_normal)) + var/rendered = "[part_a][source][part_b]\"[text]\"[part_c]" + + for (var/mob/R in heard_normal) + R.show_message(rendered, 2) + + /* --- Process all the mobs that heard a garbled voice (did not understand) --- */ + // Displays garbled message (ie "f*c* **u, **i*er!") + + if (length(heard_garbled)) + var/quotedmsg = "\"[stars(text)]\"" + var/rendered = "[part_a][source][part_b][quotedmsg][part_c]" + + for (var/mob/R in heard_garbled) + R.show_message(rendered, 2) + + + /* --- Complete gibberish. Usually happens when there's a compressed message --- */ + + if (length(heard_gibberish)) + var/quotedmsg = "\"[Gibberish(text, compression + 50)]\"" + var/rendered = "[part_a][Gibberish(source, compression + 50)][part_b][quotedmsg][part_c]" + + for (var/mob/R in heard_gibberish) + R.show_message(rendered, 2) + +//Use this to test if an obj can communicate with a Telecommunications Network + +/atom/proc/test_telecomms() + var/datum/signal/signal = src.telecomms_process() + var/turf/position = get_turf(src) + return (position.z in signal.data["level"] && signal.data["done"]) + +/atom/proc/telecomms_process(var/do_sleep = 1) + + // First, we want to generate a new radio signal + var/datum/signal/signal = new + signal.transmission_method = 2 // 2 would be a subspace transmission. + var/turf/pos = get_turf(src) + + // --- Finally, tag the actual signal with the appropriate values --- + signal.data = list( + "slow" = 0, // how much to sleep() before broadcasting - simulates net lag + "message" = "TEST", + "compression" = rand(45, 50), // If the signal is compressed, compress our message too. + "traffic" = 0, // dictates the total traffic sum that the signal went through + "type" = 4, // determines what type of radio input it is: test broadcast + "reject" = 0, + "done" = 0, + "level" = pos ? pos.z : 0 // The level it is being broadcasted at. + ) + signal.frequency = PUB_FREQ// Common channel + + //#### Sending the signal to all subspace receivers ####// + for(var/obj/machinery/telecomms/receiver/R in telecomms_list) + R.receive_signal(signal) + + if(do_sleep) + sleep(rand(10,25)) + + //world.log << "Level: [signal.data["level"]] - Done: [signal.data["done"]]" + + return signal + diff --git a/code/game/machinery/telecomms/logbrowser.dm b/code/game/machinery/telecomms/logbrowser.dm new file mode 100644 index 00000000..ef1db555 --- /dev/null +++ b/code/game/machinery/telecomms/logbrowser.dm @@ -0,0 +1,225 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/obj/machinery/computer/telecomms + icon_keyboard = "tech_key" + +/obj/machinery/computer/telecomms/server + name = "Telecommunications Server Monitor" + icon_screen = "comm_logs" + + var/screen = 0 // the screen number: + var/list/servers = list() // the servers located by the computer + var/obj/machinery/telecomms/server/SelectedServer + + var/network = "NULL" // the network to probe + var/temp = "" // temporary feedback messages + + var/universal_translate = 0 // set to 1 if it can translate nonhuman speech + + req_access = list(access_tcomsat) + + attack_hand(mob/user as mob) + if(stat & (BROKEN|NOPOWER)) + return + user.set_machine(src) + var/dat = "Telecommunication Server Monitor
            Telecommunications Server Monitor
            " + + switch(screen) + + + // --- Main Menu --- + + if(0) + dat += "
            [temp]
            " + dat += "
            Current Network: [network]
            " + if(servers.len) + dat += "
            Detected Telecommunication Servers:
              " + for(var/obj/machinery/telecomms/T in servers) + dat += "
            • \ref[T] [T.name] ([T.id])
            • " + dat += "
            " + dat += "
            \[Flush Buffer\]" + + else + dat += "
            No servers detected. Scan for servers: \[Scan\]" + + + // --- Viewing Server --- + + if(1) + dat += "
            [temp]
            " + dat += "
            \[Main Menu\] \[Refresh\]
            " + dat += "
            Current Network: [network]" + dat += "
            Selected Server: [SelectedServer.id]" + + if(SelectedServer.totaltraffic >= 1024) + dat += "
            Total recorded traffic: [round(SelectedServer.totaltraffic / 1024)] Terrabytes

            " + else + dat += "
            Total recorded traffic: [SelectedServer.totaltraffic] Gigabytes

            " + + dat += "Stored Logs:
              " + + var/i = 0 + for(var/datum/comm_log_entry/C in SelectedServer.log_entries) + i++ + + + // If the log is a speech file + if(C.input_type == "Speech File") + + dat += "
            1. [C.name] \[X\]
              " + + // -- Determine race of orator -- + + var/race = C.parameters["race"] // The actual race of the mob + var/language = C.parameters["language"] // The language spoken, or null/"" + + // -- If the orator is a human, or universal translate is active, OR mob has universal speech on -- + + if(universal_translate || C.parameters["uspeech"] || C.parameters["intelligible"]) + dat += "Data type: [C.input_type]
              " + dat += "Source: [C.parameters["name"]] (Job: [C.parameters["job"]])
              " + dat += "Class: [race]
              " + dat += "Contents: \"[C.parameters["message"]]\"
              " + if(language) + dat += "Language: [language]
              " + + // -- Orator is not human and universal translate not active -- + + else + dat += "Data type: Audio File
              " + dat += "Source: Unidentifiable
              " + dat += "Class: [race]
              " + dat += "Contents: Unintelligble
              " + + dat += "

            2. " + + else if(C.input_type == "Execution Error") + + dat += "
            3. [C.name] \[X\]
              " + dat += "Output: \"[C.parameters["message"]]\"
              " + dat += "

            4. " + + + dat += "
            " + + + + user << browse(dat, "window=comm_monitor;size=575x400") + onclose(user, "server_control") + + temp = "" + return + + + Topic(href, href_list) + if(..()) + return + + usr.set_machine(src) + + if(href_list["viewserver"]) + screen = 1 + for(var/obj/machinery/telecomms/T in servers) + if(T.id == href_list["viewserver"]) + SelectedServer = T + break + + if(href_list["operation"]) + switch(href_list["operation"]) + + if("release") + servers = list() + screen = 0 + + if("mainmenu") + screen = 0 + + if("scan") + if(servers.len > 0) + temp = "- FAILED: CANNOT PROBE WHEN BUFFER FULL -" + + else + for(var/obj/machinery/telecomms/server/T in range(25, src)) + if(T.network == network) + servers.Add(T) + + if(!servers.len) + temp = "- FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\] -" + else + temp = "- [servers.len] SERVERS PROBED & BUFFERED -" + + screen = 0 + + if(href_list["delete"]) + + if(!src.allowed(usr) && !emagged) + to_chat(usr, "ACCESS DENIED.") + return + + if(SelectedServer) + + var/datum/comm_log_entry/D = SelectedServer.log_entries[text2num(href_list["delete"])] + + temp = "- DELETED ENTRY: [D.name] -" + + SelectedServer.log_entries.Remove(D) + qdel(D) + + else + temp = "- FAILED: NO SELECTED MACHINE -" + + if(href_list["network"]) + + var/newnet = input(usr, "Which network do you want to view?", "Comm Monitor", network) as null|text + + if(newnet && ((usr in range(1, src) || issilicon(usr)))) + if(length(newnet) > 15) + temp = "- FAILED: NETWORK TAG STRING TOO LENGHTLY -" + + else + + network = newnet + screen = 0 + servers = list() + temp = "- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -" + + updateUsrDialog() + return + + attackby(var/obj/item/weapon/D as obj, var/mob/user as mob) + if(isScrewdriver(D)) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + if(do_after(user, 20, src)) + if (src.stat & BROKEN) + to_chat(user, "The broken glass falls out.") + var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) + new /obj/item/weapon/material/shard( src.loc ) + var/obj/item/weapon/circuitboard/comm_server/M = new /obj/item/weapon/circuitboard/comm_server( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + qdel(src) + else + to_chat(user, "You disconnect the monitor.") + var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/comm_server/M = new /obj/item/weapon/circuitboard/comm_server( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + qdel(src) + src.updateUsrDialog() + return + +/obj/machinery/computer/telecomms/server/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1) + emagged = 1 + to_chat(user, "You you disable the security protocols") + src.updateUsrDialog() + return 1 diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm new file mode 100644 index 00000000..b5f5ecd0 --- /dev/null +++ b/code/game/machinery/telecomms/machine_interactions.dm @@ -0,0 +1,408 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + + +/* + + All telecommunications interactions: + +*/ + +#define STATION_Z 1 +#define TELECOMM_Z 3 + +/obj/machinery/telecomms + var/temp = "" // output message + var/construct_op = 0 + + +/obj/machinery/telecomms/attackby(obj/item/P as obj, mob/user as mob) + + // Using a multitool lets you access the receiver's interface + if(isMultitool(P)) + attack_hand(user) + + + // REPAIRING: Use Nanopaste to repair 10-20 integrity points. + if(istype(P, /obj/item/stack/nanopaste)) + var/obj/item/stack/nanopaste/T = P + if (integrity < 100) //Damaged, let's repair! + if (T.use(1)) + integrity = between(0, integrity + rand(10,20), 100) + to_chat(usr, "You apply the Nanopaste to [src], repairing some of the damage.") + else + to_chat(usr, "This machine is already in perfect condition.") + return + + + switch(construct_op) + if(0) + if(isScrewdriver(P)) + to_chat(user, "You unfasten the bolts.") + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + construct_op ++ + if(1) + if(isScrewdriver(P)) + to_chat(user, "You fasten the bolts.") + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + construct_op -- + if(isWrench(P)) + to_chat(user, "You dislodge the external plating.") + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + construct_op ++ + if(2) + if(isWrench(P)) + to_chat(user, "You secure the external plating.") + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + construct_op -- + if(isWirecutter(P)) + playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1) + to_chat(user, "You remove the cables.") + construct_op ++ + var/obj/item/stack/cable_coil/A = new /obj/item/stack/cable_coil( user.loc ) + A.amount = 5 + stat |= BROKEN // the machine's been borked! + if(3) + if(isCoil(P)) + var/obj/item/stack/cable_coil/A = P + if (A.use(5)) + to_chat(user, "You insert the cables.") + construct_op-- + stat &= ~BROKEN // the machine's not borked anymore! + else + to_chat(user, "You need five coils of wire for this.") + if(isCrowbar(P)) + to_chat(user, "You begin prying out the circuit board other components...") + playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) + if(do_after(user,60, src)) + to_chat(user, "You finish prying out the components.") + + // Drop all the component stuff + if(contents.len > 0) + for(var/obj/x in src) + x.loc = user.loc + else + + // If the machine wasn't made during runtime, probably doesn't have components: + // manually find the components and drop them! + var/obj/item/weapon/circuitboard/C = new circuitboard + for(var/I in C.req_components) + for(var/i = 1, i <= C.req_components[I], i++) + var/obj/item/s = new I + s.loc = user.loc + if(istype(P, /obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/A = P + A.amount = 1 + + // Drop a circuit board too + C.loc = user.loc + + // Create a machine frame and delete the current machine + var/obj/machinery/constructable_frame/machine_frame/F = new + F.loc = src.loc + qdel(src) + + +/obj/machinery/telecomms/attack_ai(var/mob/user as mob) + attack_hand(user) + +/obj/machinery/telecomms/attack_hand(var/mob/user as mob) + + // You need a multitool to use this, or be silicon + if(!issilicon(user)) + // istype returns false if the value is null + if(!istype(user.get_active_hand(), /obj/item/device/multitool)) + return + + if(stat & (BROKEN|NOPOWER)) + return + + var/obj/item/device/multitool/P = get_multitool(user) + + user.set_machine(src) + var/dat + dat = "[src.name]

            [src.name] Access

            " + dat += "
            [temp]
            " + dat += "
            Power Status: [src.toggled ? "On" : "Off"]" + if(overloaded_for) + dat += "

            WARNING: Ion interference detected. System will automatically recover in [overloaded_for*2] seconds. Reset manually
            " + if(on && toggled) + if(id != "" && id) + dat += "
            Identification String: [id]" + else + dat += "
            Identification String: NULL" + dat += "
            Network: [network]" + dat += "
            Prefabrication: [autolinkers.len ? "TRUE" : "FALSE"]" + if(hide) dat += "
            Shadow Link: ACTIVE" + + //Show additional options for certain machines. + dat += Options_Menu() + + dat += "
            Linked Network Entities:
              " + + var/i = 0 + for(var/obj/machinery/telecomms/T in links) + i++ + if(T.hide && !src.hide) + continue + dat += "
            1. \ref[T] [T.name] ([T.id]) \[X\]
            2. " + dat += "
            " + + dat += "
            Filtering Frequencies: " + + i = 0 + if(length(freq_listening)) + for(var/x in freq_listening) + i++ + if(i < length(freq_listening)) + dat += "[format_frequency(x)] GHz\[X\]; " + else + dat += "[format_frequency(x)] GHz\[X\]" + else + dat += "NONE" + + dat += "
            \[Add Filter\]" + dat += "
            " + + if(P) + var/obj/machinery/telecomms/device = P.get_buffer() + if(istype(device)) + dat += "

            MULTITOOL BUFFER: [device] ([device.id]) \[Link\] \[Flush\]" + else + dat += "

            MULTITOOL BUFFER:
            \[Add Machine\]" + + dat += "
            " + temp = "" + user << browse(dat, "window=tcommachine;size=520x500;can_resize=0") + onclose(user, "dormitory") + + +// Off-Site Relays +// +// You are able to send/receive signals from the station's z level (changeable in the STATION_Z #define) if +// the relay is on the telecomm satellite (changable in the TELECOMM_Z #define) + + +/obj/machinery/telecomms/relay/proc/toggle_level() + + var/turf/position = get_turf(src) + + // Toggle on/off getting signals from the station or the current Z level + if(src.listening_levels == GLOB.using_map.contact_levels) // equals the station + src.listening_levels = GetConnectedZlevels(position.z) + return 1 + else + src.listening_levels = GLOB.using_map.contact_levels + return 1 + return 0 + +// Returns a multitool from a user depending on their mobtype. + +/obj/machinery/telecomms/proc/get_multitool(mob/user as mob) + + var/obj/item/device/multitool/P = null + // Let's double check + if(!issilicon(user) && istype(user.get_active_hand(), /obj/item/device/multitool)) + P = user.get_active_hand() + else if(isAI(user)) + var/mob/living/silicon/ai/U = user + P = U.aiMulti + else if(isrobot(user) && in_range(user, src)) + if(istype(user.get_active_hand(), /obj/item/device/multitool)) + P = user.get_active_hand() + return P + +// Additional Options for certain machines. Use this when you want to add an option to a specific machine. +// Example of how to use below. + +/obj/machinery/telecomms/proc/Options_Menu() + return "" + +/* +// Add an option to the processor to switch processing mode. (COMPRESS -> UNCOMPRESS or UNCOMPRESS -> COMPRESS) +/obj/machinery/telecomms/processor/Options_Menu() + var/dat = "
            Processing Mode: [process_mode ? "UNCOMPRESS" : "COMPRESS"]" + return dat +*/ +// The topic for Additional Options. Use this for checking href links for your specific option. +// Example of how to use below. +/obj/machinery/telecomms/proc/Options_Topic(href, href_list) + return + +/* +/obj/machinery/telecomms/processor/Options_Topic(href, href_list) + + if(href_list["process"]) + temp = "-% Processing mode changed. %-" + src.process_mode = !src.process_mode +*/ + +// RELAY + +/obj/machinery/telecomms/relay/Options_Menu() + var/dat = "" + if(src.z == TELECOMM_Z) + dat += "
            Signal Locked to the [station_name()]: [listening_levels == GLOB.using_map.contact_levels ? "TRUE" : "FALSE"]" + dat += "
            Broadcasting: [broadcasting ? "YES" : "NO"]" + dat += "
            Receiving: [receiving ? "YES" : "NO"]" + return dat + +/obj/machinery/telecomms/relay/Options_Topic(href, href_list) + + if(href_list["receive"]) + receiving = !receiving + temp = "-% Receiving mode changed. %-" + if(href_list["broadcast"]) + broadcasting = !broadcasting + temp = "-% Broadcasting mode changed. %-" + if(href_list["change_listening"]) + //Lock to the station OR lock to the current position! + //You need at least two receivers and two broadcasters for this to work, this includes the machine. + var/result = toggle_level() + if(result) + temp = "-% [src]'s signal has been successfully changed." + else + temp = "-% [src] could not lock it's signal onto the [station_name()]. Two broadcasters or receivers required." + +// BUS + +/obj/machinery/telecomms/bus/Options_Menu() + var/dat = "
            Change Signal Frequency: [change_frequency ? "YES ([change_frequency])" : "NO"]" + return dat + +/obj/machinery/telecomms/bus/Options_Topic(href, href_list) + + if(href_list["change_freq"]) + + var/newfreq = input(usr, "Specify a new frequency for new signals to change to. Enter null to turn off frequency changing. Decimals assigned automatically.", src, network) as null|num + if(canAccess(usr)) + if(newfreq) + if(findtext(num2text(newfreq), ".")) + newfreq *= 10 // shift the decimal one place + if(newfreq < 10000) + change_frequency = newfreq + temp = "-% New frequency to change to assigned: \"[newfreq] GHz\" %-" + else + change_frequency = 0 + temp = "-% Frequency changing deactivated %-" + + +/obj/machinery/telecomms/Topic(href, href_list) + if(..()) + return 1 + if(!issilicon(usr)) + if(!istype(usr.get_active_hand(), /obj/item/device/multitool)) + return + + if(stat & (BROKEN|NOPOWER)) + return + + var/obj/item/device/multitool/P = get_multitool(usr) + + if(href_list["input"]) + switch(href_list["input"]) + + if("resetoverload") + overloaded_for = 0 + temp = "-% Manual override accepted. \The [src] has been reset." + + if("toggle") + + src.toggled = !src.toggled + temp = "-% [src] has been [src.toggled ? "activated" : "deactivated"]." + update_power() + + /* + if("hide") + src.hide = !hide + temp = "-% Shadow Link has been [src.hide ? "activated" : "deactivated"]." + */ + + if("id") + var/newid = copytext(reject_bad_text(input(usr, "Specify the new ID for this machine", src, id) as null|text),1,MAX_MESSAGE_LEN) + if(newid && canAccess(usr)) + id = newid + temp = "-% New ID assigned: \"[id]\" %-" + + if("network") + var/newnet = input(usr, "Specify the new network for this machine. This will break all current links.", src, network) as null|text + if(newnet && canAccess(usr)) + + if(length(newnet) > 15) + temp = "-% Too many characters in new network tag %-" + + else + for(var/obj/machinery/telecomms/T in links) + T.links.Remove(src) + + network = newnet + links = list() + temp = "-% New network tag assigned: \"[network]\" %-" + + + if("freq") + var/newfreq = input(usr, "Specify a new frequency to filter (GHz). Decimals assigned automatically.", src, network) as null|num + if(newfreq && canAccess(usr)) + if(findtext(num2text(newfreq), ".")) + newfreq *= 10 // shift the decimal one place + if(!(newfreq in freq_listening) && newfreq < 10000) + freq_listening.Add(newfreq) + temp = "-% New frequency filter assigned: \"[newfreq] GHz\" %-" + + if(href_list["delete"]) + + // changed the layout about to workaround a pesky runtime -- Doohl + + var/x = text2num(href_list["delete"]) + temp = "-% Removed frequency filter [x] %-" + freq_listening.Remove(x) + + if(href_list["unlink"]) + + if(text2num(href_list["unlink"]) <= length(links)) + var/obj/machinery/telecomms/T = links[text2num(href_list["unlink"])] + temp = "-% Removed \ref[T] [T.name] from linked entities. %-" + + // Remove link entries from both T and src. + + if(src in T.links) + T.links.Remove(src) + links.Remove(T) + + if(href_list["link"]) + + if(P) + var/obj/machinery/telecomms/device = P.get_buffer() + if(istype(device) && device != src) + if(!(src in device.links)) + device.links.Add(src) + + if(!(device in src.links)) + src.links.Add(device) + + temp = "-% Successfully linked with \ref[device] [device.name] %-" + + else + temp = "-% Unable to acquire buffer %-" + + if(href_list["buffer"]) + + P.set_buffer(src) + var/atom/buffer = P.get_buffer() + temp = "-% Successfully stored \ref[buffer] [buffer.name] in buffer %-" + + + if(href_list["flush"]) + + temp = "-% Buffer successfully flushed. %-" + P.set_buffer(null) + + src.Options_Topic(href, href_list) + + usr.set_machine(src) + + updateUsrDialog() + +/obj/machinery/telecomms/proc/canAccess(var/mob/user) + if(issilicon(user) || in_range(user, src)) + return 1 + return 0 diff --git a/code/game/machinery/telecomms/presets.dm b/code/game/machinery/telecomms/presets.dm new file mode 100644 index 00000000..bf919358 --- /dev/null +++ b/code/game/machinery/telecomms/presets.dm @@ -0,0 +1,249 @@ +// ### Preset machines ### + +//Relay + +/obj/machinery/telecomms/relay/preset + network = "tcommsat" + +/obj/machinery/telecomms/relay/preset/station + id = "Primary Relay" + autolinkers = list("s_relay") + +/obj/machinery/telecomms/relay/preset/station/Initialize() + listening_levels = GLOB.using_map.contact_levels + return ..() + +/obj/machinery/telecomms/relay/preset/telecomms + id = "Telecomms Relay" + autolinkers = list("relay") + +/obj/machinery/telecomms/relay/preset/mining + id = "Mining Relay" + autolinkers = list("m_relay") + +/obj/machinery/telecomms/relay/preset/bridge + id = "Bridge Relay" + autolinkers = list("b_relay") + +/obj/machinery/telecomms/relay/preset/firstdeck + id = "First Deck Relay" + autolinkers = list("1_relay") + +/obj/machinery/telecomms/relay/preset/seconddeck + id = "Second Deck Relay" + autolinkers = list("2_relay") + +/obj/machinery/telecomms/relay/preset/thirddeck + id = "Third Deck Relay" + autolinkers = list("3_relay") + +/obj/machinery/telecomms/relay/preset/fourthdeck + id = "Fourth Deck Relay" + autolinkers = list("4_relay") + +/obj/machinery/telecomms/relay/preset/fifthdeck + id = "Fifth Deck Relay" + autolinkers = list("5_relay") + +/obj/machinery/telecomms/relay/preset/ruskie + id = "Ruskie Relay" + hide = 1 + toggled = 0 + autolinkers = list("r_relay") + +/obj/machinery/telecomms/relay/preset/centcom + id = "Centcom Relay" + hide = 1 + toggled = 1 + //anchored = 1 + //use_power = 0 + //idle_power_usage = 0 + produces_heat = 0 + autolinkers = list("c_relay") + +//HUB + +/obj/machinery/telecomms/hub/preset + id = "Hub" + network = "tcommsat" + autolinkers = list("hub", "relay", "c_relay", "s_relay", "m_relay", "r_relay", "b_relay", "1_relay", "2_relay", "3_relay", "4_relay", "5_relay", "s_relay", "science", "medical", + "supply", "service", "common", "command", "engineering", "security", "unused", + "receiverA", "broadcasterA") + +/obj/machinery/telecomms/hub/preset_cent + id = "CentComm Hub" + network = "tcommsat" + produces_heat = 0 + autolinkers = list("hub_cent", "c_relay", "s_relay", "m_relay", "r_relay", + "centcomm", "receiverCent", "broadcasterCent") + +//Receivers + +/obj/machinery/telecomms/receiver/preset_right + id = "Receiver A" + network = "tcommsat" + autolinkers = list("receiverA") // link to relay + freq_listening = list(AI_FREQ, SCI_FREQ, MED_FREQ, SUP_FREQ, SRV_FREQ, COMM_FREQ, ENG_FREQ, SEC_FREQ, ENT_FREQ, INQ_FREQ) + + //Common and other radio frequencies for people to freely use + New() + for(var/i = PUBLIC_LOW_FREQ, i < PUBLIC_HIGH_FREQ, i += 2) + freq_listening |= i + ..() + +/obj/machinery/telecomms/receiver/preset_cent + id = "CentComm Receiver" + network = "tcommsat" + produces_heat = 0 + autolinkers = list("receiverCent") + freq_listening = list(ERT_FREQ, DTH_FREQ) + + +//Buses + +/obj/machinery/telecomms/bus/preset_one + id = "Bus 1" + network = "tcommsat" + freq_listening = list(SCI_FREQ, MED_FREQ) + autolinkers = list("processor1", "science", "medical") + +/obj/machinery/telecomms/bus/preset_two + id = "Bus 2" + network = "tcommsat" + freq_listening = list(SUP_FREQ, SRV_FREQ) + autolinkers = list("processor2", "supply", "service", "unused") + +/obj/machinery/telecomms/bus/preset_two/New() + for(var/i = PUBLIC_LOW_FREQ, i < PUBLIC_HIGH_FREQ, i += 2) + if(i == PUB_FREQ) + continue + freq_listening |= i + ..() + +/obj/machinery/telecomms/bus/preset_three + id = "Bus 3" + network = "tcommsat" + freq_listening = list(SEC_FREQ, COMM_FREQ, INQ_FREQ) + autolinkers = list("processor3", "security", "command") + +/obj/machinery/telecomms/bus/preset_four + id = "Bus 4" + network = "tcommsat" + freq_listening = list(ENG_FREQ, AI_FREQ, PUB_FREQ, ENT_FREQ) + autolinkers = list("processor4", "engineering", "common") + +/obj/machinery/telecomms/bus/preset_cent + id = "CentComm Bus" + network = "tcommsat" + freq_listening = list(ERT_FREQ, DTH_FREQ, ENT_FREQ) + produces_heat = 0 + autolinkers = list("processorCent", "centcomm") + +//Processors + +/obj/machinery/telecomms/processor/preset_one + id = "Processor 1" + network = "tcommsat" + autolinkers = list("processor1") // processors are sort of isolated; they don't need backward links + +/obj/machinery/telecomms/processor/preset_two + id = "Processor 2" + network = "tcommsat" + autolinkers = list("processor2") + +/obj/machinery/telecomms/processor/preset_three + id = "Processor 3" + network = "tcommsat" + autolinkers = list("processor3") + +/obj/machinery/telecomms/processor/preset_four + id = "Processor 4" + network = "tcommsat" + autolinkers = list("processor4") + +/obj/machinery/telecomms/processor/preset_cent + id = "CentComm Processor" + network = "tcommsat" + produces_heat = 0 + autolinkers = list("processorCent") + +//Servers + +/obj/machinery/telecomms/server/presets + + network = "tcommsat" + +/obj/machinery/telecomms/server/presets/science + id = "Science Server" + freq_listening = list(SCI_FREQ) + autolinkers = list("science") + +/obj/machinery/telecomms/server/presets/medical + id = "Medical Server" + freq_listening = list(MED_FREQ) + autolinkers = list("medical") + +/obj/machinery/telecomms/server/presets/supply + id = "Supply Server" + freq_listening = list(SUP_FREQ) + autolinkers = list("supply") + +/obj/machinery/telecomms/server/presets/service + id = "Service Server" + freq_listening = list(SRV_FREQ) + autolinkers = list("service") + +/obj/machinery/telecomms/server/presets/common + id = "Common Server" + freq_listening = list(PUB_FREQ, AI_FREQ, ENT_FREQ) // AI Private and Common + autolinkers = list("common") + +// "Unused" channels, AKA all others. +/obj/machinery/telecomms/server/presets/unused + id = "Unused Server" + freq_listening = list() + autolinkers = list("unused") + +/obj/machinery/telecomms/server/presets/unused/New() + for(var/i = PUBLIC_LOW_FREQ, i < PUBLIC_HIGH_FREQ, i += 2) + if(i == AI_FREQ || i == PUB_FREQ) + continue + freq_listening |= i + ..() + +/obj/machinery/telecomms/server/presets/command + id = "Command Server" + freq_listening = list(COMM_FREQ) + autolinkers = list("command") + +/obj/machinery/telecomms/server/presets/engineering + id = "Engineering Server" + freq_listening = list(ENG_FREQ) + autolinkers = list("engineering") + +/obj/machinery/telecomms/server/presets/security + id = "Security Server" + freq_listening = list(SEC_FREQ, INQ_FREQ) + autolinkers = list("security") + +/obj/machinery/telecomms/server/presets/centcomm + id = "CentComm Server" + freq_listening = list(ERT_FREQ, DTH_FREQ) + produces_heat = 0 + autolinkers = list("centcomm") + + +//Broadcasters + +//--PRESET LEFT--// + +/obj/machinery/telecomms/broadcaster/preset_right + id = "Broadcaster A" + network = "tcommsat" + autolinkers = list("broadcasterA") + +/obj/machinery/telecomms/broadcaster/preset_cent + id = "CentComm Broadcaster" + network = "tcommsat" + produces_heat = 0 + autolinkers = list("broadcasterCent") diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm new file mode 100644 index 00000000..6ee5128d --- /dev/null +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -0,0 +1,654 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/* + Hello, friends, this is Doohl from sexylands. You may be wondering what this + monstrous code file is. Sit down, boys and girls, while I tell you the tale. + + + The machines defined in this file were designed to be compatible with any radio + signals, provided they use subspace transmission. Currently they are only used for + headsets, but they can eventually be outfitted for real COMPUTER networks. This + is just a skeleton, ladies and gentlemen. + + Look at radio.dm for the prequel to this code. +*/ + +var/global/list/obj/machinery/telecomms/telecomms_list = list() + +/obj/machinery/telecomms + var/list/links = list() // list of machines this machine is linked to + var/traffic = 0 // value increases as traffic increases + var/netspeed = 5 // how much traffic to lose per tick (50 gigabytes/second * netspeed) + var/list/autolinkers = list() // list of text/number values to link with + var/id = "NULL" // identification string + var/network = "NULL" // the network of the machinery + + var/list/freq_listening = list() // list of frequencies to tune into: if none, will listen to all + + var/machinetype = 0 // just a hacky way of preventing alike machines from pairing + var/toggled = 1 // Is it toggled on + var/on = 1 + var/integrity = 100 // basically HP, loses integrity by heat + var/produces_heat = 1 //whether the machine will produce heat when on. + var/delay = 10 // how many process() ticks to delay per heat + var/long_range_link = 0 // Can you link it across Z levels or on the otherside of the map? (Relay & Hub) + var/circuitboard = null // string pointing to a circuitboard type + var/hide = 0 // Is it a hidden machine? + var/listening_levels = null // null = auto set in Initialize() - these are the z levels that the machine is listening to. + var/overloaded_for = 0 + var/outage_probability = 75 // Probability of failing during a ionospheric storm + + +/obj/machinery/telecomms/proc/relay_information(datum/signal/signal, filter, copysig, amount = 20) + // relay signal to all linked machinery that are of type [filter]. If signal has been sent [amount] times, stop sending + + if(!on || overloaded_for) + return +// log_debug("[src] ([src.id]) - [signal.debug_print()]") + + var/send_count = 0 + + signal.data["slow"] += rand(0, round((100-integrity))) // apply some lag based on integrity + + /* + // Edit by Atlantis: Commented out as emergency fix due to causing extreme delays in communications. + // Apply some lag based on traffic rates + var/netlag = round(traffic / 50) + if(netlag > signal.data["slow"]) + signal.data["slow"] = netlag + */ +// Loop through all linked machines and send the signal or copy. + for(var/obj/machinery/telecomms/machine in links) + if(filter && !istype( machine, filter )) + continue + if(!machine.on) + continue + if(amount && send_count >= amount) + break + if(!(machine.loc.z in listening_levels)) + if(long_range_link == 0 && machine.long_range_link == 0) + continue + // If we're sending a copy, be sure to create the copy for EACH machine and paste the data + var/datum/signal/copy + if(copysig) + copy = new + copy.transmission_method = 2 + copy.frequency = signal.frequency + copy.data = signal.data.Copy() + + // Keep the "original" signal constant + if(!signal.data["original"]) + copy.data["original"] = signal + else + copy.data["original"] = signal.data["original"] + + send_count++ + if(machine.is_freq_listening(signal)) + machine.traffic++ + + if(copysig && copy) + machine.receive_information(copy, src) + else + machine.receive_information(signal, src) + + + if(send_count > 0 && is_freq_listening(signal)) + traffic++ + + return send_count + +/obj/machinery/telecomms/proc/relay_direct_information(datum/signal/signal, obj/machinery/telecomms/machine) + // send signal directly to a machine + machine.receive_information(signal, src) + +/obj/machinery/telecomms/proc/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) + // receive information from linked machinery + ..() + +/obj/machinery/telecomms/proc/is_freq_listening(datum/signal/signal) + // return 1 if found, 0 if not found + if(!signal) + return 0 + if((signal.frequency in freq_listening) || (!freq_listening.len)) + return 1 + else + return 0 + + +/obj/machinery/telecomms/New() + telecomms_list += src + ..() + +/obj/machinery/telecomms/Initialize() + //Set the listening_levels if there's none. + if(!listening_levels) + //Defaults to our Z level! + var/turf/position = get_turf(src) + listening_levels = GetConnectedZlevels(position.z) + + if(autolinkers.len) + // Links nearby machines + if(!long_range_link) + for(var/obj/machinery/telecomms/T in orange(20, src)) + add_link(T) + else + for(var/obj/machinery/telecomms/T in telecomms_list) + add_link(T) + update_power() + . = ..() + +/obj/machinery/telecomms/Destroy() + telecomms_list -= src + for(var/obj/machinery/telecomms/comm in telecomms_list) + comm.links -= src + links = list() + ..() + +// Used in auto linking +/obj/machinery/telecomms/proc/add_link(var/obj/machinery/telecomms/T) + var/turf/position = get_turf(src) + var/turf/T_position = get_turf(T) + if((position.z == T_position.z) || (src.long_range_link && T.long_range_link)) + for(var/x in autolinkers) + if(T.autolinkers.Find(x)) + if(src != T) + links |= T + +/obj/machinery/telecomms/update_icon() + if(on && !overloaded_for) + icon_state = initial(icon_state) + else + icon_state = "[initial(icon_state)]_off" + +/obj/machinery/telecomms/proc/update_power() + if(toggled) + if(stat & (BROKEN|NOPOWER|EMPED) || integrity <= 0) // if powered, on. if not powered, off. if too damaged, off + on = 0 + else + on = 1 + else + on = 0 + use_power = on + +/obj/machinery/telecomms/Process() + update_power() + + if(overloaded_for) + overloaded_for-- + + // Check heat and generate some + checkheat() + + // Update the icon + update_icon() + + if(traffic > 0) + traffic -= netspeed + +/obj/machinery/telecomms/emp_act(severity) + if(prob(100/severity)) + overloaded_for = max(round(150 / severity), overloaded_for) + ..() + +/obj/machinery/telecomms/proc/checkheat() + // Checks heat from the environment and applies any integrity damage + var/datum/gas_mixture/environment = loc.return_air() + var/damage_chance = 0 // Percent based chance of applying 1 integrity damage this tick + switch(environment.temperature) + if((T0C + 40) to (T0C + 70)) // 40C-70C, minor overheat, 10% chance of taking damage + damage_chance = 10 + if((T0C + 70) to (T0C + 130)) // 70C-130C, major overheat, 25% chance of taking damage + damage_chance = 25 + if((T0C + 130) to (T0C + 200)) // 130C-200C, dangerous overheat, 50% chance of taking damage + damage_chance = 50 + if((T0C + 200) to INFINITY) // More than 200C, INFERNO. Takes damage every tick. + damage_chance = 100 + if (damage_chance && prob(damage_chance)) + integrity = between(0, integrity - 1, 100) + + + if(delay > 0) + delay-- + else if(on) + produce_heat() + delay = initial(delay) + + + +/obj/machinery/telecomms/proc/produce_heat() + if (!produces_heat) + return + + if (!use_power) + return + + if(!(stat & (NOPOWER|BROKEN))) + var/turf/simulated/L = loc + if(istype(L)) + var/datum/gas_mixture/env = L.return_air() + + var/transfer_moles = 0.25 * env.total_moles + + var/datum/gas_mixture/removed = env.remove(transfer_moles) + + if(removed) + + var/heat_produced = idle_power_usage //obviously can't produce more heat than the machine draws from it's power source + if (traffic <= 0) + heat_produced *= 0.30 //if idle, produce less heat. + + removed.add_thermal_energy(heat_produced) + + env.merge(removed) +/* + The receiver idles and receives messages from subspace-compatible radio equipment; + primarily headsets. They then just relay this information to all linked devices, + which can would probably be network hubs. + + Link to Processor Units in case receiver can't send to bus units. +*/ + +/obj/machinery/telecomms/receiver + name = "Subspace Receiver" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "broadcast receiver" + desc = "This machine has a dish-like shape and green lights. It is designed to detect and process subspace radio activity." + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 600 + machinetype = 1 + produces_heat = 0 + circuitboard = /obj/item/weapon/circuitboard/telecomms/receiver + outage_probability = 10 + +/obj/machinery/telecomms/receiver/receive_signal(datum/signal/signal) + + if(!on) // has to be on to receive messages + return + if(!signal) + return + if(!check_receive_level(signal)) + return + + if(signal.transmission_method == 2) + + if(is_freq_listening(signal)) // detect subspace signals + + //Remove the level and then start adding levels that it is being broadcasted in. + signal.data["level"] = list() + + var/can_send = relay_information(signal, /obj/machinery/telecomms/hub) // ideally relay the copied information to relays + if(!can_send) + relay_information(signal, /obj/machinery/telecomms/bus) // Send it to a bus instead, if it's linked to one + +/obj/machinery/telecomms/receiver/proc/check_receive_level(datum/signal/signal) + + if(!(signal.data["level"] in listening_levels)) + for(var/obj/machinery/telecomms/hub/H in links) + var/list/connected_levels = list() + for(var/obj/machinery/telecomms/relay/R in H.links) + if(R.can_receive(signal)) + connected_levels |= R.listening_levels + if(signal.data["level"] in connected_levels) + return 1 + return 0 + return 1 + + +/* + The HUB idles until it receives information. It then passes on that information + depending on where it came from. + + This is the heart of the Telecommunications Network, sending information where it + is needed. It mainly receives information from long-distance Relays and then sends + that information to be processed. Afterwards it gets the uncompressed information + from Servers/Buses and sends that back to the relay, to then be broadcasted. +*/ + +/obj/machinery/telecomms/hub + name = "Telecommunication Hub" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "hub" + desc = "A mighty piece of hardware used to send/receive massive amounts of data." + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 1600 + machinetype = 7 + circuitboard = /obj/item/weapon/circuitboard/telecomms/hub + long_range_link = 1 + netspeed = 40 + outage_probability = 10 + +/obj/machinery/telecomms/hub/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) + if(is_freq_listening(signal)) + if(istype(machine_from, /obj/machinery/telecomms/receiver)) + //If the signal is compressed, send it to the bus. + relay_information(signal, /obj/machinery/telecomms/bus, 1) // ideally relay the copied information to bus units + else + // Get a list of relays that we're linked to, then send the signal to their levels. + relay_information(signal, /obj/machinery/telecomms/relay, 1) + relay_information(signal, /obj/machinery/telecomms/broadcaster, 1) // Send it to a broadcaster. + + +/* + The relay idles until it receives information. It then passes on that information + depending on where it came from. + + The relay is needed in order to send information pass Z levels. It must be linked + with a HUB, the only other machine that can send/receive pass Z levels. +*/ + +/obj/machinery/telecomms/relay + name = "Telecommunication Relay" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "relay" + desc = "A mighty piece of hardware used to send massive amounts of data far away." + density = 1 + anchored = 1 + use_power = 1 + machinetype = 8 + produces_heat = 0 + circuitboard = /obj/item/weapon/circuitboard/telecomms/relay + netspeed = 5 + long_range_link = 1 + var/broadcasting = 1 + var/receiving = 1 + +/obj/machinery/telecomms/relay/forceMove(var/newloc) + . = ..(newloc) + listening_levels = GetConnectedZlevels(z) + update_power() + +// Relays on ship's Z levels use less power as they don't have to transmit over such large distances. +/obj/machinery/telecomms/relay/update_power() + ..() + if(z in GLOB.using_map.station_levels) + idle_power_usage = 2.5 KILOWATTS + else + idle_power_usage = 30 KILOWATTS + +/obj/machinery/telecomms/relay/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) + + // Add our level and send it back + if(can_send(signal)) + signal.data["level"] |= listening_levels + +// Checks to see if it can send/receive. + +/obj/machinery/telecomms/relay/proc/can(datum/signal/signal) + if(!on) + return 0 + if(!is_freq_listening(signal)) + return 0 + return 1 + +/obj/machinery/telecomms/relay/proc/can_send(datum/signal/signal) + if(!can(signal)) + return 0 + return broadcasting + +/obj/machinery/telecomms/relay/proc/can_receive(datum/signal/signal) + if(!can(signal)) + return 0 + return receiving + +/* + The bus mainframe idles and waits for hubs to relay them signals. They act + as junctions for the network. + + They transfer uncompressed subspace packets to processor units, and then take + the processed packet to a server for logging. + + Link to a subspace hub if it can't send to a server. +*/ + +/obj/machinery/telecomms/bus + name = "Bus Mainframe" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "bus" + desc = "A mighty piece of hardware used to send massive amounts of data quickly." + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 1000 + machinetype = 2 + circuitboard = /obj/item/weapon/circuitboard/telecomms/bus + netspeed = 40 + var/change_frequency = 0 + +/obj/machinery/telecomms/bus/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) + + if(is_freq_listening(signal)) + + if(change_frequency) + signal.frequency = change_frequency + + if(!istype(machine_from, /obj/machinery/telecomms/processor) && machine_from != src) // Signal must be ready (stupid assuming machine), let's send it + // send to one linked processor unit + var/send_to_processor = relay_information(signal, /obj/machinery/telecomms/processor) + + if(send_to_processor) + return + // failed to send to a processor, relay information anyway + signal.data["slow"] += rand(1, 5) // slow the signal down only slightly + src.receive_information(signal, src) + + // Try sending it! + var/list/try_send = list(/obj/machinery/telecomms/server, /obj/machinery/telecomms/hub, /obj/machinery/telecomms/broadcaster, /obj/machinery/telecomms/bus) + var/i = 0 + for(var/send in try_send) + if(i) + signal.data["slow"] += rand(0, 1) // slow the signal down only slightly + i++ + var/can_send = relay_information(signal, send) + if(can_send) + break + + + +/* + The processor is a very simple machine that decompresses subspace signals and + transfers them back to the original bus. It is essential in producing audible + data. + + Link to servers if bus is not present +*/ + +/obj/machinery/telecomms/processor + name = "Processor Unit" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "processor" + desc = "This machine is used to process large quantities of information." + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 600 + machinetype = 3 + delay = 5 + circuitboard = /obj/item/weapon/circuitboard/telecomms/processor + var/process_mode = 1 // 1 = Uncompress Signals, 0 = Compress Signals + +/obj/machinery/telecomms/processor/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) + if(!is_freq_listening(signal)) + return + + if(process_mode) + signal.data["compression"] = 0 // uncompress subspace signal + else + signal.data["compression"] = 100 // even more compressed signal + + if(istype(machine_from, /obj/machinery/telecomms/bus)) + relay_direct_information(signal, machine_from) // send the signal back to the machine + else // no bus detected - send the signal to servers instead + signal.data["slow"] += rand(5, 10) // slow the signal down + relay_information(signal, /obj/machinery/telecomms/server) + + +/* + The server logs all traffic and signal data. Once it records the signal, it sends + it to the subspace broadcaster. + + Store a maximum of 100 logs and then deletes them. +*/ + + +/obj/machinery/telecomms/server + name = "Telecommunication Server" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "comm_server" + desc = "A machine used to store data and network statistics." + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 300 + machinetype = 4 + circuitboard = /obj/item/weapon/circuitboard/telecomms/server + var/list/log_entries = list() + var/list/stored_names = list() + var/list/TrafficActions = list() + var/logs = 0 // number of logs + var/totaltraffic = 0 // gigabytes (if > 1024, divide by 1024 -> terrabytes) + + var/list/memory = list() // stored memory + var/rawcode = "" // the code to compile (raw text) + var/datum/TCS_Compiler/Compiler // the compiler that compiles and runs the code + var/autoruncode = 0 // 1 if the code is set to run every time a signal is picked up + + var/encryption = "null" // encryption key: ie "password" + var/salt = "null" // encryption salt: ie "123comsat" + // would add up to md5("password123comsat") + var/language = "human" + var/obj/item/device/radio/headset/server_radio = null + +/obj/machinery/telecomms/server/New() + ..() + Compiler = new() + Compiler.Holder = src + server_radio = new() + +/obj/machinery/telecomms/server/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) + + if(signal.data["message"]) + + if(is_freq_listening(signal)) + + if(traffic > 0) + totaltraffic += traffic // add current traffic to total traffic + + //Is this a test signal? Bypass logging + if(signal.data["type"] != 4) + + // If signal has a message and appropriate frequency + + update_logs() + + var/datum/comm_log_entry/log = new + var/mob/M = signal.data["mob"] + + // Copy the signal.data entries we want + log.parameters["mobtype"] = signal.data["mobtype"] + log.parameters["job"] = signal.data["job"] + log.parameters["key"] = signal.data["key"] + log.parameters["vmessage"] = signal.data["message"] + log.parameters["vname"] = signal.data["message"] + log.parameters["message"] = signal.data["message"] + log.parameters["name"] = signal.data["name"] + log.parameters["realname"] = signal.data["realname"] + log.parameters["language"] = signal.data["language"] + + var/race = "Unknown" + if(ishuman(M) || isbrain(M)) + race = "Sapient Race" + log.parameters["intelligible"] = 1 + else if(M.isMonkey()) + race = "Monkey" + else if(issilicon(M)) + race = "Artificial Life" + log.parameters["intelligible"] = 1 + else if(isslime(M)) + race = "Slime" + else if(isanimal(M)) + race = "Domestic Animal" + + log.parameters["race"] = race + + if(!istype(M, /mob/new_player) && M) + log.parameters["uspeech"] = M.universal_speak + else + log.parameters["uspeech"] = 0 + + // If the signal is still compressed, make the log entry gibberish + if(signal.data["compression"] > 0) + log.parameters["message"] = Gibberish(signal.data["message"], signal.data["compression"] + 50) + log.parameters["job"] = Gibberish(signal.data["job"], signal.data["compression"] + 50) + log.parameters["name"] = Gibberish(signal.data["name"], signal.data["compression"] + 50) + log.parameters["realname"] = Gibberish(signal.data["realname"], signal.data["compression"] + 50) + log.parameters["vname"] = Gibberish(signal.data["vname"], signal.data["compression"] + 50) + log.input_type = "Corrupt File" + + // Log and store everything that needs to be logged + log_entries.Add(log) + if(!(signal.data["name"] in stored_names)) + stored_names.Add(signal.data["name"]) + logs++ + signal.data["server"] = src + + // Give the log a name + var/identifier = num2text( rand(-1000,1000) + world.time ) + log.name = "data packet ([md5(identifier)])" + + if(Compiler && autoruncode) + Compiler.Run(signal) // execute the code + + var/can_send = relay_information(signal, /obj/machinery/telecomms/hub) + if(!can_send) + relay_information(signal, /obj/machinery/telecomms/broadcaster) + + +/obj/machinery/telecomms/server/proc/setcode(var/t) + if(t) + if(istext(t)) + rawcode = t + +/obj/machinery/telecomms/server/proc/compile() + if(Compiler) + return Compiler.Compile(rawcode) + +/obj/machinery/telecomms/server/proc/update_logs() + // start deleting the very first log entry + if(logs >= 400) + for(var/i = 1, i <= logs, i++) // locate the first garbage collectable log entry and remove it + var/datum/comm_log_entry/L = log_entries[i] + if(L.garbage_collector) + log_entries.Remove(L) + logs-- + break + +/obj/machinery/telecomms/server/proc/add_entry(var/content, var/input) + var/datum/comm_log_entry/log = new + var/identifier = num2text( rand(-1000,1000) + world.time ) + log.name = "[input] ([md5(identifier)])" + log.input_type = input + log.parameters["message"] = content + log_entries.Add(log) + update_logs() + + + + +// Simple log entry datum + +/datum/comm_log_entry + var/parameters = list() // carbon-copy to signal.data[] + var/name = "data packet (#)" + var/garbage_collector = 1 // if set to 0, will not be garbage collected + var/input_type = "Speech File" + + + + + + + diff --git a/code/game/machinery/telecomms/telemonitor.dm b/code/game/machinery/telecomms/telemonitor.dm new file mode 100644 index 00000000..e96b1955 --- /dev/null +++ b/code/game/machinery/telecomms/telemonitor.dm @@ -0,0 +1,160 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + + +/* + Telecomms monitor tracks the overall trafficing of a telecommunications network + and displays a heirarchy of linked machines. +*/ + + +/obj/machinery/computer/telecomms/monitor + name = "Telecommunications Monitor" + icon_screen = "comm_monitor" + + var/screen = 0 // the screen number: + var/list/machinelist = list() // the machines located by the computer + var/obj/machinery/telecomms/SelectedMachine + + var/network = "NULL" // the network to probe + + var/temp = "" // temporary feedback messages + + attack_hand(mob/user as mob) + if(stat & (BROKEN|NOPOWER)) + return + user.set_machine(src) + var/dat = "Telecommunications Monitor
            Telecommunications Monitor
            " + + switch(screen) + + + // --- Main Menu --- + + if(0) + dat += "
            [temp]

            " + dat += "
            Current Network: [network]
            " + if(machinelist.len) + dat += "
            Detected Network Entities:
              " + for(var/obj/machinery/telecomms/T in machinelist) + dat += "
            • \ref[T] [T.name] ([T.id])
            • " + dat += "
            " + dat += "
            \[Flush Buffer\]" + else + dat += "\[Probe Network\]" + + + // --- Viewing Machine --- + + if(1) + dat += "
            [temp]
            " + dat += "
            \[Main Menu\]
            " + dat += "
            Current Network: [network]
            " + dat += "Selected Network Entity: [SelectedMachine.name] ([SelectedMachine.id])
            " + dat += "Linked Entities:
              " + for(var/obj/machinery/telecomms/T in SelectedMachine.links) + if(!T.hide) + dat += "
            1. \ref[T.id] [T.name] ([T.id])
            2. " + dat += "
            " + + + + user << browse(dat, "window=comm_monitor;size=575x400") + onclose(user, "server_control") + + temp = "" + return + + + Topic(href, href_list) + if(..()) + return + + usr.set_machine(src) + + if(href_list["viewmachine"]) + screen = 1 + for(var/obj/machinery/telecomms/T in machinelist) + if(T.id == href_list["viewmachine"]) + SelectedMachine = T + break + + if(href_list["operation"]) + switch(href_list["operation"]) + + if("release") + machinelist = list() + screen = 0 + + if("mainmenu") + screen = 0 + + if("probe") + if(machinelist.len > 0) + temp = "- FAILED: CANNOT PROBE WHEN BUFFER FULL -" + + else + for(var/obj/machinery/telecomms/T in range(25, src)) + if(T.network == network) + machinelist.Add(T) + + if(!machinelist.len) + temp = "- FAILED: UNABLE TO LOCATE NETWORK ENTITIES IN \[[network]\] -" + else + temp = "- [machinelist.len] ENTITIES LOCATED & BUFFERED -" + + screen = 0 + + + if(href_list["network"]) + + var/newnet = input(usr, "Which network do you want to view?", "Comm Monitor", network) as null|text + if(newnet && ((usr in range(1, src) || issilicon(usr)))) + if(length(newnet) > 15) + temp = "- FAILED: NETWORK TAG STRING TOO LENGHTLY -" + + else + network = newnet + screen = 0 + machinelist = list() + temp = "- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -" + + updateUsrDialog() + return + + attackby(var/obj/item/weapon/D as obj, var/mob/user as mob) + if(isScrewdriver(D)) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + if(do_after(user, 20, src)) + if (src.stat & BROKEN) + to_chat(user, "The broken glass falls out.") + var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) + new /obj/item/weapon/material/shard( src.loc ) + var/obj/item/weapon/circuitboard/comm_monitor/M = new /obj/item/weapon/circuitboard/comm_monitor( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + qdel(src) + else + to_chat(user, "You disconnect the monitor.") + var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/comm_monitor/M = new /obj/item/weapon/circuitboard/comm_monitor( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + qdel(src) + src.updateUsrDialog() + return + +/obj/machinery/computer/telecomms/monitor/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1) + emagged = 1 + to_chat(user, "You you disable the security protocols") + src.updateUsrDialog() + return 1 diff --git a/code/game/machinery/telecomms/traffic_control.dm b/code/game/machinery/telecomms/traffic_control.dm new file mode 100644 index 00000000..5d01c426 --- /dev/null +++ b/code/game/machinery/telecomms/traffic_control.dm @@ -0,0 +1,243 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + + + + + +/obj/machinery/computer/telecomms/traffic + name = "Telecommunications Traffic Control" + icon_screen = "generic" + + var/screen = 0 // the screen number: + var/list/servers = list() // the servers located by the computer + var/mob/editingcode + var/mob/lasteditor + var/list/viewingcode = list() + var/obj/machinery/telecomms/server/SelectedServer + + var/network = "NULL" // the network to probe + var/temp = "" // temporary feedback messages + + var/storedcode = "" // code stored + + + proc/update_ide() + + // loop if there's someone manning the keyboard + while(editingcode) + if(!editingcode.client) + editingcode = null + break + + // For the typer, the input is enabled. Buffer the typed text + if(editingcode) + storedcode = "[winget(editingcode, "tcscode", "text")]" + if(editingcode) // double if's to work around a runtime error + winset(editingcode, "tcscode", "is-disabled=false") + + // If the player's not manning the keyboard anymore, adjust everything + if( (!(editingcode in range(1, src)) && !issilicon(editingcode)) || (editingcode.machine != src && !issilicon(editingcode))) + if(editingcode) + winshow(editingcode, "Telecomms IDE", 0) // hide the window! + editingcode = null + break + + // For other people viewing the typer type code, the input is disabled and they can only view the code + // (this is put in place so that there's not any magical shenanigans with 50 people inputting different code all at once) + + if(length(viewingcode)) + // This piece of code is very important - it escapes quotation marks so string aren't cut off by the input element + var/showcode = replacetext(storedcode, "\\\"", "\\\\\"") + showcode = replacetext(storedcode, "\"", "\\\"") + + for(var/mob/M in viewingcode) + + if( (M.machine == src && M in view(1, src) ) || issilicon(M)) + winset(M, "tcscode", "is-disabled=true") + winset(M, "tcscode", "text=\"[showcode]\"") + else + viewingcode.Remove(M) + winshow(M, "Telecomms IDE", 0) // hide the window! + + sleep(5) + + if(length(viewingcode) > 0) + editingcode = pick(viewingcode) + viewingcode.Remove(editingcode) + update_ide() + + + + req_access = list(access_tcomsat) + + attack_hand(mob/user as mob) + if(stat & (BROKEN|NOPOWER)) + return + user.set_machine(src) + var/dat = "Telecommunication Traffic Control
            Telecommunications Traffic Control
            " + + switch(screen) + + + // --- Main Menu --- + + if(0) + dat += "
            [temp]
            " + dat += "
            Current Network: [network]
            " + if(servers.len) + dat += "
            Detected Telecommunication Servers:
              " + for(var/obj/machinery/telecomms/T in servers) + dat += "
            • \ref[T] [T.name] ([T.id])
            • " + dat += "
            " + dat += "
            \[Flush Buffer\]" + + else + dat += "
            No servers detected. Scan for servers: \[Scan\]" + + + // --- Viewing Server --- + + if(1) + dat += "
            [temp]
            " + dat += "
            \[Main Menu\] \[Refresh\]
            " + dat += "
            Current Network: [network]" + dat += "
            Selected Server: [SelectedServer.id]

            " + dat += "
            \[Edit Code\]" + dat += "
            Signal Execution: " + if(SelectedServer.autoruncode) + dat += "ALWAYS" + else + dat += "NEVER" + + + user << browse(dat, "window=traffic_control;size=575x400") + onclose(user, "server_control") + + temp = "" + return + + + Topic(href, href_list) + if(..()) + return + + usr.set_machine(src) + if(!src.allowed(usr) && !emagged) + to_chat(usr, "ACCESS DENIED.") + return + + if(href_list["viewserver"]) + screen = 1 + for(var/obj/machinery/telecomms/T in servers) + if(T.id == href_list["viewserver"]) + SelectedServer = T + break + + if(href_list["operation"]) + switch(href_list["operation"]) + + if("release") + servers = list() + screen = 0 + + if("mainmenu") + screen = 0 + + if("scan") + if(servers.len > 0) + temp = "- FAILED: CANNOT PROBE WHEN BUFFER FULL -" + + else + for(var/obj/machinery/telecomms/server/T in range(25, src)) + if(T.network == network) + servers.Add(T) + + if(!servers.len) + temp = "- FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\] -" + else + temp = "- [servers.len] SERVERS PROBED & BUFFERED -" + + screen = 0 + + if("editcode") + if(editingcode == usr) return + if(usr in viewingcode) return + + if(!editingcode) + lasteditor = usr + editingcode = usr + winshow(editingcode, "Telecomms IDE", 1) // show the IDE + winset(editingcode, "tcscode", "is-disabled=false") + winset(editingcode, "tcscode", "text=\"\"") + var/showcode = replacetext(storedcode, "\\\"", "\\\\\"") + showcode = replacetext(storedcode, "\"", "\\\"") + winset(editingcode, "tcscode", "text=\"[showcode]\"") + spawn() + update_ide() + + else + viewingcode.Add(usr) + winshow(usr, "Telecomms IDE", 1) // show the IDE + winset(usr, "tcscode", "is-disabled=true") + winset(editingcode, "tcscode", "text=\"\"") + var/showcode = replacetext(storedcode, "\"", "\\\"") + winset(usr, "tcscode", "text=\"[showcode]\"") + + if("togglerun") + SelectedServer.autoruncode = !(SelectedServer.autoruncode) + + if(href_list["network"]) + + var/newnet = input(usr, "Which network do you want to view?", "Comm Monitor", network) as null|text + + if(newnet && ((usr in range(1, src) || issilicon(usr)))) + if(length(newnet) > 15) + temp = "- FAILED: NETWORK TAG STRING TOO LENGHTLY -" + + else + + network = newnet + screen = 0 + servers = list() + temp = "- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -" + + updateUsrDialog() + return + + attackby(var/obj/item/weapon/D as obj, var/mob/user as mob) + if(isScrewdriver(D)) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + if(do_after(user, 20, src)) + if (src.stat & BROKEN) + to_chat(user, "The broken glass falls out.") + var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) + new /obj/item/weapon/material/shard( src.loc ) + var/obj/item/weapon/circuitboard/comm_traffic/M = new /obj/item/weapon/circuitboard/comm_traffic( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + qdel(src) + else + to_chat(user, "You disconnect the monitor.") + var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/comm_traffic/M = new /obj/item/weapon/circuitboard/comm_traffic( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + qdel(src) + src.updateUsrDialog() + return + +/obj/machinery/computer/telecomms/traffic/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1) + emagged = 1 + to_chat(user, "You you disable the security protocols") + src.updateUsrDialog() + return 1 diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm new file mode 100644 index 00000000..64bfbfb6 --- /dev/null +++ b/code/game/machinery/teleporter.dm @@ -0,0 +1,360 @@ +/obj/machinery/computer/teleporter + name = "Teleporter Control Console" + desc = "Used to control a linked teleportation hub and station." + icon_keyboard = "teleport_key" + icon_screen = "teleport" + circuit = /obj/item/weapon/circuitboard/teleporter + dir = 4 + var/obj/machinery/teleport/station/station = null + var/obj/machinery/teleport/hub/hub = null + var/obj/item/locked = null + var/id = null + var/one_time_use = 0 //Used for one-time-use teleport cards (such as clown planet coordinates.) + //Setting this to 1 will set src.locked to null after a player enters the portal and will not allow hand-teles to open portals to that location. + +/obj/machinery/computer/teleporter/New() + src.id = "[random_id(/obj/machinery/computer/teleporter, 1000, 9999)]" + ..() + underlays.Cut() + underlays += image('icons/obj/stationobjs.dmi', icon_state = "telecomp-wires") + return + +/obj/machinery/computer/teleporter/Initialize() + . = ..() + station = locate(/obj/machinery/teleport/station, get_step(src, dir)) + if(station) + hub = locate(/obj/machinery/teleport/hub, get_step(station, dir)) + + if(istype(station)) + station.com = hub + station.set_dir(dir) + + if(istype(hub)) + hub.com = src + hub.set_dir(dir) + +/obj/machinery/computer/teleporter/examine(mob/user) + . = ..() + if(locked) + var/turf/T = get_turf(locked) + to_chat(user, "The console is locked on to \[[T.loc.name]\].") + + +/obj/machinery/computer/teleporter/attackby(I as obj, mob/living/user as mob) + if(istype(I, /obj/item/weapon/card/data/)) + var/obj/item/weapon/card/data/C = I + if(stat & (NOPOWER|BROKEN) & (C.function != "teleporter")) + src.attack_hand() + + var/obj/L = null + + for(var/obj/effect/landmark/sloc in landmarks_list) + if(sloc.name != C.data) continue + if(locate(/mob/living) in sloc.loc) continue + L = sloc + break + + if(!L) + L = locate("landmark*[C.data]") // use old stype + + + if(istype(L, /obj/effect/landmark/) && istype(L.loc, /turf)) + to_chat(usr, "You insert the coordinates into the machine.") + to_chat(usr, "A message flashes across the screen reminding the traveller that the nuclear authentication disk is to remain on the [station_name()] at all times.") + user.drop_item() + qdel(I) + + if(C.data == "Clown Land") + //whoops + for(var/mob/O in hearers(src, null)) + O.show_message("Incoming bluespace portal detected, unable to lock in.", 2) + + for(var/obj/machinery/teleport/hub/H in range(1)) + var/amount = rand(2,5) + for(var/i=0;iLocked In
            ", 2) + src.locked = L + one_time_use = 1 + + src.add_fingerprint(usr) + else + ..() + + return + +/obj/machinery/teleport/station/attack_ai() + src.attack_hand() + +/obj/machinery/computer/teleporter/attack_hand(user as mob) + if(..()) return + + /* Ghosts can't use this one because it's a direct selection */ + if(isobserver(user)) return + + var/list/L = list() + var/list/areaindex = list() + + for(var/obj/item/device/radio/beacon/R in world) + var/turf/T = get_turf(R) + if (!T) + continue + if(!(T.z in GLOB.using_map.player_levels)) + continue + var/tmpname = T.loc.name + if(areaindex[tmpname]) + tmpname = "[tmpname] ([++areaindex[tmpname]])" + else + areaindex[tmpname] = 1 + L[tmpname] = R + + for (var/obj/item/weapon/implant/tracking/I in world) + if (!I.implanted || !ismob(I.loc)) + continue + else + var/mob/M = I.loc + if (M.stat == 2) + if (M.timeofdeath + 6000 < world.time) + continue + var/turf/T = get_turf(M) + if(!T) + continue + if(!(T.z in GLOB.using_map.player_levels)) + continue + var/tmpname = M.real_name + if(areaindex[tmpname]) + tmpname = "[tmpname] ([++areaindex[tmpname]])" + else + areaindex[tmpname] = 1 + L[tmpname] = I + + var/desc = input("Please select a location to lock in.", "Locking Computer") in L|null + if(!desc) + return + if(get_dist(src, usr) > 1 && !issilicon(usr)) + return + + src.locked = L[desc] + for(var/mob/O in hearers(src, null)) + O.show_message("Locked In", 2) + return + +/obj/machinery/computer/teleporter/verb/set_id(t as text) + set category = "Object" + set name = "Set teleporter ID" + set src in oview(1) + set desc = "ID Tag:" + + if(stat & (NOPOWER|BROKEN) || !istype(usr,/mob/living)) + return + if (t) + src.id = t + return + +/proc/find_loc(obj/R as obj) + if (!R) return null + var/turf/T = R.loc + while(!istype(T, /turf)) + T = T.loc + if(!T || istype(T, /area)) return null + return T + +/obj/machinery/teleport + name = "teleport" + icon = 'icons/obj/stationobjs.dmi' + density = 1 + anchored = 1.0 + var/lockeddown = 0 + + +/obj/machinery/teleport/hub + name = "teleporter hub" + desc = "It's the hub of a teleporting machine." + icon_state = "tele0" + dir = 4 + use_power = 1 + idle_power_usage = 10 + active_power_usage = 2000 + var/obj/machinery/computer/teleporter/com + + +/obj/machinery/teleport/hub/New() + ..() + underlays.Cut() + underlays += image('icons/obj/stationobjs.dmi', icon_state = "tele-wires") + +/obj/machinery/teleport/hub/Bumped(M as mob|obj) + spawn() + if (src.icon_state == "tele1") + teleport(M) + use_power(5000) + return + +/obj/machinery/teleport/hub/proc/teleport(atom/movable/M as mob|obj) + if (!com) + return + if (!com.locked) + for(var/mob/O in hearers(src, null)) + O.show_message("Failure: Cannot authenticate locked on coordinates. Please reinstate coordinate matrix.") + return + do_teleport(M, com.locked) + if(com.one_time_use) //Make one-time-use cards only usable one time! + com.one_time_use = 0 + com.locked = null + return +/* +/proc/do_teleport(atom/movable/M as mob|obj, atom/destination, precision) + if(istype(M, /obj/effect)) + qdel(M) + return + if (istype(M, /obj/item/weapon/disk/nuclear)) // Don't let nuke disks get teleported --NeoFite + for(var/mob/O in viewers(M, null)) + O.show_message(text("The [] bounces off of the portal!", M.name), 1) + return + if (istype(M, /mob/living)) + var/mob/living/MM = M + if(MM.check_contents_for(/obj/item/weapon/disk/nuclear)) + to_chat(MM, "Something you are carrying seems to be unable to pass through the portal. Better drop it if you want to go through.") + return + var/disky = 0 + for (var/atom/O in M.contents) //I'm pretty sure this accounts for the maximum amount of container in container stacking. --NeoFite + if (istype(O, /obj/item/weapon/storage) || istype(O, /obj/item/weapon/gift)) + for (var/obj/OO in O.contents) + if (istype(OO, /obj/item/weapon/storage) || istype(OO, /obj/item/weapon/gift)) + for (var/obj/OOO in OO.contents) + if (istype(OOO, /obj/item/weapon/disk/nuclear)) + disky = 1 + if (istype(OO, /obj/item/weapon/disk/nuclear)) + disky = 1 + if (istype(O, /obj/item/weapon/disk/nuclear)) + disky = 1 + if (istype(O, /mob/living)) + var/mob/living/MM = O + if(MM.check_contents_for(/obj/item/weapon/disk/nuclear)) + disky = 1 + if (disky) + for(var/mob/P in viewers(M, null)) + P.show_message(text("The [] bounces off of the portal!", M.name), 1) + return + +//Bags of Holding cause bluespace teleportation to go funky. --NeoFite + if (istype(M, /mob/living)) + var/mob/living/MM = M + if(MM.check_contents_for(/obj/item/weapon/storage/backpack/holding)) + to_chat(MM, "The Bluespace interface on your Bag of Holding interferes with the teleport!") + precision = rand(1,100) + if (istype(M, /obj/item/weapon/storage/backpack/holding)) + precision = rand(1,100) + for (var/atom/O in M.contents) //I'm pretty sure this accounts for the maximum amount of container in container stacking. --NeoFite + if (istype(O, /obj/item/weapon/storage) || istype(O, /obj/item/weapon/gift)) + for (var/obj/OO in O.contents) + if (istype(OO, /obj/item/weapon/storage) || istype(OO, /obj/item/weapon/gift)) + for (var/obj/OOO in OO.contents) + if (istype(OOO, /obj/item/weapon/storage/backpack/holding)) + precision = rand(1,100) + if (istype(OO, /obj/item/weapon/storage/backpack/holding)) + precision = rand(1,100) + if (istype(O, /obj/item/weapon/storage/backpack/holding)) + precision = rand(1,100) + if (istype(O, /mob/living)) + var/mob/living/MM = O + if(MM.check_contents_for(/obj/item/weapon/storage/backpack/holding)) + precision = rand(1,100) + + + var/turf/destturf = get_turf(destination) + + var/tx = destturf.x + rand(precision * -1, precision) + var/ty = destturf.y + rand(precision * -1, precision) + + var/tmploc + + if (ismob(destination.loc)) //If this is an implant. + tmploc = locate(tx, ty, destturf.z) + else + tmploc = locate(tx, ty, destination.z) + + if(tx == destturf.x && ty == destturf.y && (istype(destination.loc, /obj/structure/closet) || istype(destination.loc, /obj/structure/closet/secure_closet))) + tmploc = destination.loc + + if(tmploc==null) + return + + M.forceMove(tmploc) + sleep(2) + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, M) + s.start() + return +*/ + +/obj/machinery/teleport/station + name = "station" + desc = "It's the station thingy of a teleport thingy." //seriously, wtf. + icon_state = "controller" + dir = 4 + var/active = 0 + var/engaged = 0 + use_power = 1 + idle_power_usage = 10 + active_power_usage = 2000 + var/obj/machinery/teleport/hub/com + +/obj/machinery/teleport/station/New() + ..() + overlays.Cut() + overlays += image('icons/obj/stationobjs.dmi', icon_state = "controller-wires") + +/obj/machinery/teleport/station/attackby(var/obj/item/weapon/W) + src.attack_hand() + +/obj/machinery/teleport/station/attack_ai() + src.attack_hand() + +/obj/machinery/teleport/station/attack_hand() + if(engaged) + src.disengage() + else + src.engage() + +/obj/machinery/teleport/station/proc/engage() + if(stat & (BROKEN|NOPOWER)) + return + + if (com) + com.icon_state = "tele1" + use_power(5000) + update_use_power(2) + com.update_use_power(2) + for(var/mob/O in hearers(src, null)) + O.show_message("Teleporter engaged!", 2) + src.add_fingerprint(usr) + src.engaged = 1 + return + +/obj/machinery/teleport/station/proc/disengage() + if(stat & (BROKEN|NOPOWER)) + return + + if (com) + com.icon_state = "tele0" + com.update_use_power(1) + update_use_power(1) + for(var/mob/O in hearers(src, null)) + O.show_message("Teleporter disengaged!", 2) + src.add_fingerprint(usr) + src.engaged = 0 + return + +/obj/machinery/teleport/station/update_icon() + if(stat & NOPOWER) + icon_state = "controller-p" + + if(com) + com.icon_state = "tele0" + else + icon_state = "controller" diff --git a/code/game/machinery/turret_control.dm b/code/game/machinery/turret_control.dm new file mode 100644 index 00000000..25b75ebb --- /dev/null +++ b/code/game/machinery/turret_control.dm @@ -0,0 +1,253 @@ +//////////////////////// +//Turret Control Panel// +//////////////////////// + +/area + // Turrets use this list to see if individual power/lethal settings are allowed + var/list/turret_controls = list() + +/obj/machinery/turretid + name = "turret control panel" + desc = "Used to control a room's automated defenses." + icon = 'icons/obj/machines/turret_control.dmi' + icon_state = "control_standby" + anchored = 1 + density = 0 + var/enabled = 0 + var/lethal = 0 + var/locked = 1 + var/area/control_area //can be area name, path or nothing. + var/mob/living/silicon/ai/master_ai + + var/check_arrest = 1 //checks if the perp is set to arrest + var/check_records = 1 //checks if a security record exists at all + var/check_weapons = 0 //checks if it can shoot people that have a weapon they aren't authorized to have + var/check_access = 1 //if this is active, the turret shoots everything that does not meet the access requirements + var/check_anomalies = 1 //checks if it can shoot at unidentified lifeforms (ie xenos) + var/check_synth = 0 //if active, will shoot at anything not an AI or cyborg + var/ailock = 0 //Silicons cannot use this + + req_access = list(access_ai_upload) + +/obj/machinery/turretid/stun + enabled = 1 + icon_state = "control_stun" + +/obj/machinery/turretid/lethal + enabled = 1 + lethal = 1 + icon_state = "control_kill" + +/obj/machinery/turretid/Destroy() + if(control_area) + var/area/A = control_area + if(A && istype(A)) + A.turret_controls -= src + . = ..() + +/obj/machinery/turretid/Initialize() + if(!control_area) + control_area = get_area(src) + else if(istext(control_area)) + for(var/area/A in world) + if(A.name && A.name==control_area) + control_area = A + break + + if(control_area) + var/area/A = control_area + if(istype(A)) + A.turret_controls += src + else + control_area = null + + power_change() //Checks power and initial settings + . = ..() + +/obj/machinery/turretid/proc/isLocked(mob/user) + if(ailock && issilicon(user)) + to_chat(user, "There seems to be a firewall preventing you from accessing this device.") + return 1 + + if(malf_upgraded && master_ai) + if((user == master_ai) || (user in master_ai.connected_robots)) + return 0 + return 1 + + if(locked && !issilicon(user)) + to_chat(user, "Access denied.") + return 1 + + return 0 + +/obj/machinery/turretid/CanUseTopic(mob/user) + if(isLocked(user)) + return STATUS_CLOSE + + return ..() + +/obj/machinery/turretid/attackby(obj/item/weapon/W, mob/user) + if(stat & BROKEN) + return + + if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) + if(src.allowed(usr)) + if(emagged) + to_chat(user, "The turret control is unresponsive.") + else + locked = !locked + to_chat(user, "You [ locked ? "lock" : "unlock"] the panel.") + return + return ..() + +/obj/machinery/turretid/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + to_chat(user, "You short out the turret controls' access analysis module.") + emagged = 1 + locked = 0 + ailock = 0 + return 1 + +/obj/machinery/turretid/attack_ai(mob/user as mob) + if(isLocked(user)) + return + + ui_interact(user) + +/obj/machinery/turretid/attack_hand(mob/user as mob) + if(isLocked(user)) + return + + ui_interact(user) + +/obj/machinery/turretid/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + data["access"] = !isLocked(user) + data["locked"] = locked + data["enabled"] = enabled + data["is_lethal"] = 1 + data["lethal"] = lethal + + if(data["access"]) + var/settings[0] + settings[++settings.len] = list("category" = "Neutralize All Non-Synthetics", "setting" = "check_synth", "value" = check_synth) + settings[++settings.len] = list("category" = "Check Weapon Authorization", "setting" = "check_weapons", "value" = check_weapons) + settings[++settings.len] = list("category" = "Check Security Records", "setting" = "check_records", "value" = check_records) + settings[++settings.len] = list("category" = "Check Arrest Status", "setting" = "check_arrest", "value" = check_arrest) + settings[++settings.len] = list("category" = "Check Access Authorization", "setting" = "check_access", "value" = check_access) + settings[++settings.len] = list("category" = "Check misc. Lifeforms", "setting" = "check_anomalies", "value" = check_anomalies) + data["settings"] = settings + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 300) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/turretid/Topic(href, href_list) + if(..()) + return 1 + + + if(href_list["command"] && href_list["value"]) + var/log_action = null + + var/list/toggle = list("disabled","enabled") + + var/value = text2num(href_list["value"]) + if(href_list["command"] == "enable") + enabled = value + log_action = "[toggle[enabled+1]] the turrets" + else if(href_list["command"] == "lethal") + lethal = value + log_action = "[toggle[lethal+1]] the turrets lethal mode." + else if(href_list["command"] == "check_synth") + check_synth = value + else if(href_list["command"] == "check_weapons") + check_weapons = value + else if(href_list["command"] == "check_records") + check_records = value + else if(href_list["command"] == "check_arrest") + check_arrest = value + else if(href_list["command"] == "check_access") + check_access = value + else if(href_list["command"] == "check_anomalies") + check_anomalies = value + + if(!isnull(log_action)) + log_admin("[key_name(usr)] has [log_action]") + message_admins("[key_name_admin(usr)] has [log_action]", 1) + + updateTurrets() + return 1 + +/obj/machinery/turretid/proc/updateTurrets() + var/datum/turret_checks/TC = new + TC.enabled = enabled + TC.lethal = lethal + TC.check_synth = check_synth + TC.check_access = check_access + TC.check_records = check_records + TC.check_arrest = check_arrest + TC.check_weapons = check_weapons + TC.check_anomalies = check_anomalies + TC.ailock = ailock + + if(istype(control_area)) + for (var/obj/machinery/porta_turret/aTurret in control_area) + aTurret.setState(TC) + + update_icon() + +/obj/machinery/turretid/power_change() + . = ..() + if(.) + updateTurrets() + +/obj/machinery/turretid/update_icon() + ..() + if(stat & NOPOWER) + icon_state = "control_off" + set_light(0) + else if (enabled) + if (lethal) + icon_state = "control_kill" + set_light(1.5, 1,"#990000") + else + icon_state = "control_stun" + set_light(1.5, 1,"#ff9900") + else + icon_state = "control_standby" + set_light(1.5, 1,"#003300") + +/obj/machinery/turretid/emp_act(severity) + if(enabled) + //if the turret is on, the EMP no matter how severe disables the turret for a while + //and scrambles its settings, with a slight chance of having an emag effect + + check_arrest = pick(0, 1) + check_records = pick(0, 1) + check_weapons = pick(0, 1) + check_access = pick(0, 0, 0, 0, 1) // check_access is a pretty big deal, so it's least likely to get turned on + check_anomalies = pick(0, 1) + + enabled=0 + updateTurrets() + + spawn(rand(60,600)) + if(!enabled) + enabled=1 + updateTurrets() + + ..() + + +/obj/machinery/turretid/malf_upgrade(var/mob/living/silicon/ai/user) + ..() + malf_upgraded = 1 + locked = 1 + ailock = 0 + to_chat(user, "\The [src] has been upgraded. It has been locked and can not be tampered with by anyone but you and your cyborgs.") + master_ai = user + return 1 \ No newline at end of file diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm new file mode 100644 index 00000000..8ba4796a --- /dev/null +++ b/code/game/machinery/vending.dm @@ -0,0 +1,1107 @@ + +/** + * A vending machine + */ +/obj/machinery/vending + name = "Vendomat" + desc = "A generic vending machine." + icon = 'icons/obj/vending.dmi' + icon_state = "generic" + layer = BELOW_OBJ_LAYER + anchored = 1 + density = 1 + obj_flags = OBJ_FLAG_ANCHORABLE + clicksound = "button" + clickvol = 40 + + var/icon_vend //Icon_state when vending + var/icon_deny //Icon_state when denying access + var/diona_spawn_chance = 0.1 + + // Power + use_power = 1 + idle_power_usage = 10 + var/vend_power_usage = 150 //actuators and stuff + + // Vending-related + var/active = 1 //No sales pitches if off! + var/vend_ready = 1 //Are we ready to vend?? Is it time?? + var/vend_delay = 10 //How long does it take to vend? + var/categories = VENDING_CATEGORY_NORMAL // Bitmask of cats we're currently showing + var/datum/stored_items/vending_products/currently_vending = null // What we're requesting payment for right now + var/status_message = "" // Status screen messages like "insufficient funds", displayed in NanoUI + var/status_error = 0 // Set to 1 if status_message is an error + + /* + Variables used to initialize the product list + These are used for initialization only, and so are optional if + product_records is specified + */ + var/list/products = list() // For each, use the following pattern: + var/list/contraband = list() // list(/type/path = amount,/type/path2 = amount2) + var/list/premium = list() // No specified amount = only one in stock + var/list/prices = list() // Prices for each item, list(/type/path = price), items not in the list don't have a price. + + // List of vending_product items available. + var/list/product_records = list() + + + // Variables used to initialize advertising + var/product_slogans = "" //String of slogans spoken out loud, separated by semicolons + var/product_ads = "" //String of small ad messages in the vending screen + + var/list/ads_list = list() + + // Stuff relating vocalizations + var/list/slogan_list = list() + var/shut_up = 1 //Stop spouting those godawful pitches! + var/vend_reply //Thank you for shopping! + var/last_reply = 0 + var/last_slogan = 0 //When did we last pitch? + var/slogan_delay = 6000 //How long until we can pitch again? + + // Things that can go wrong + emagged = 0 //Ignores if somebody doesn't have card access to that machine. + var/seconds_electrified = 0 //Shock customers like an airlock. + var/shoot_inventory = 0 //Fire items at customers! We're broken! + + var/scan_id = 1 + var/obj/item/weapon/coin/coin + var/datum/wires/vending/wires = null + + var/vending_sound = "machines/vending_drop.ogg" + var/rand_amount = TRUE + +/obj/machinery/vending/New() + ..() + wires = new(src) + spawn(4) + if(src.product_slogans) + src.slogan_list += splittext(src.product_slogans, ";") + + // So not all machines speak at the exact same time. + // The first time this machine says something will be at slogantime + this random value, + // so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is crated. + src.last_slogan = world.time + rand(0, slogan_delay) + + if(src.product_ads) + src.ads_list += splittext(src.product_ads, ";") + + src.build_inventory() + power_change() + + return + + return + +/** + * Build src.produdct_records from the products lists + * + * src.products, src.contraband, src.premium, and src.prices allow specifying + * products that the vending machine is to carry without manually populating + * src.product_records. + */ +/obj/machinery/vending/proc/build_inventory() + var/list/all_products = list( + list(src.products, VENDING_CATEGORY_NORMAL), + list(src.contraband, VENDING_CATEGORY_HIDDEN), + list(src.premium, VENDING_CATEGORY_PREMIUM)) + + for(var/current_list in all_products) + var/category = current_list[2] + + for(var/entry in current_list[1]) + var/datum/stored_items/vending_products/product = new/datum/stored_items/vending_products(src, entry) + + product.price = (entry in src.prices) ? src.prices[entry] : 0 + + if(rand_amount) + var/sum = current_list[1][entry] + product.amount = sum ? max(0, sum - rand(0, round(sum * 1.5))) : 1 + else + product.amount = (current_list[1][entry]) ? current_list[1][entry] : 1 + + product.category = category + + src.product_records.Add(product) + +/obj/machinery/vending/Destroy() + qdel(wires) + wires = null + qdel(coin) + coin = null + for(var/datum/stored_items/vending_products/R in product_records) + qdel(R) + product_records = null + return ..() + +/obj/machinery/vending/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + if (prob(50)) + qdel(src) + return + if(3.0) + if (prob(25)) + spawn(0) + src.malfunction() + return + return + else + return + +/obj/machinery/vending/emag_act(var/remaining_charges, var/mob/user) + if (!emagged) + src.emagged = 1 + to_chat(user, "You short out the product lock on \the [src]") + return 1 + +/obj/machinery/vending/attackby(obj/item/weapon/W as obj, mob/user as mob) + + var/obj/item/weapon/card/id/I = W.GetIdCard() + + if (currently_vending && vendor_account && !vendor_account.suspended) + var/paid = 0 + var/handled = 0 + + //if (I) //for IDs and PDAs and wallets with IDs + // paid = pay_with_card(I,W) + // handled = 1 + if (istype(W, /obj/item/weapon/spacecash/ewallet)) + var/obj/item/weapon/spacecash/ewallet/C = W + paid = pay_with_ewallet(C) + handled = 1 + else if (istype(W, /obj/item/weapon/spacecash/bundle)) + var/obj/item/weapon/spacecash/bundle/C = W + paid = pay_with_cash(C) + handled = 1 + + if(paid) + src.vend(currently_vending, usr) + return + else if(handled) + GLOB.nanomanager.update_uis(src) + return // don't smack that machine with your 2 credits + + if (I || istype(W, /obj/item/weapon/spacecash)) + attack_hand(user) + return + else if(istype(W, /obj/item/weapon/screwdriver)) + src.panel_open = !src.panel_open + to_chat(user, "You [src.panel_open ? "open" : "close"] the maintenance panel.") + src.overlays.Cut() + if(src.panel_open) + src.overlays += image(src.icon, "[initial(icon_state)]-panel") + + GLOB.nanomanager.update_uis(src) // Speaker switch is on the main UI, not wires UI + return + else if(isMultitool(W) || isWirecutter(W)) + if(src.panel_open) + attack_hand(user) + return + else if((obj_flags & OBJ_FLAG_ANCHORABLE) && isWrench(W)) + wrench_floor_bolts(user) + power_change() + return + else if(istype(W, /obj/item/weapon/coin) && premium.len > 0) + user.drop_item() + W.forceMove(src) + coin = W + categories |= VENDING_CATEGORY_PREMIUM + to_chat(user, "You insert \the [W] into \the [src].") + GLOB.nanomanager.update_uis(src) + return + else if(attempt_to_stock(W, user)) + return + ..() + return + +/obj/machinery/vending/MouseDrop_T(var/obj/item/I as obj, var/mob/user as mob) + if(!CanMouseDrop(I, user) || (I.loc != user)) + return + return attempt_to_stock(I, user) + +/obj/machinery/vending/proc/attempt_to_stock(var/obj/item/I as obj, var/mob/user as mob) + for(var/datum/stored_items/vending_products/R in product_records) + if(I.type == R.item_path) + stock(I, R, user) + return 1 + +/** + * Receive payment with cashmoney. + */ +/obj/machinery/vending/proc/pay_with_cash(var/obj/item/weapon/spacecash/bundle/cashmoney) + if(currently_vending.price > cashmoney.worth) + // This is not a status display message, since it's something the character + // themselves is meant to see BEFORE putting the money in + to_chat(usr, "\icon[cashmoney] That is not enough money.") + return 0 + + visible_message("\The [usr] inserts some cash into \the [src].") + if(prob(50)) + playsound(loc, 'sound/items/polaroid1.ogg', 50, 1) + else + playsound(loc, 'sound/items/polaroid2.ogg', 50, 1) + cashmoney.worth -= currently_vending.price + + if(cashmoney.worth <= 0) + usr.drop_from_inventory(cashmoney) + qdel(cashmoney) + else + cashmoney.update_icon() + + // Vending machines have no idea who paid with cash + credit_purchase("(cash)") + return 1 + +/** + * Scan a chargecard and deduct payment from it. + * + * Takes payment for whatever is the currently_vending item. Returns 1 if + * successful, 0 if failed. + */ +/obj/machinery/vending/proc/pay_with_ewallet(var/obj/item/weapon/spacecash/ewallet/wallet) + visible_message("\The [usr] swipes \the [wallet] through \the [src].") + if(currently_vending.price > wallet.worth) + src.status_message = "Insufficient funds on chargecard." + src.status_error = 1 + return 0 + else + wallet.worth -= currently_vending.price + credit_purchase("[wallet.owner_name] (chargecard)") + return 1 + +/** + * Scan a card and attempt to transfer payment from associated account. + * + * Takes payment for whatever is the currently_vending item. Returns 1 if + * successful, 0 if failed + */ +/obj/machinery/vending/proc/pay_with_card(var/obj/item/weapon/card/id/I, var/obj/item/ID_container) + if(I==ID_container || ID_container == null) + visible_message("\The [usr] swipes \the [I] through \the [src].") + else + visible_message("\The [usr] swipes \the [ID_container] through \the [src].") + playsound(loc, 'sound/items/use_card.ogg', 50, 1) + var/datum/money_account/customer_account = get_account(I.associated_account_number) + if (!customer_account) + src.status_message = "Error: Unable to access account. Please contact technical support if problem persists." + src.status_error = 1 + return 0 + + if(customer_account.suspended) + src.status_message = "Unable to access account: account suspended." + src.status_error = 1 + return 0 + + // Have the customer punch in the PIN before checking if there's enough money. Prevents people from figuring out acct is + // empty at high security levels + if(customer_account.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2) + var/attempt_pin = input("Enter pin code", "Vendor transaction") as num + customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2) + + if(!customer_account) + src.status_message = "Unable to access account: incorrect credentials." + src.status_error = 1 + return 0 + + if(currently_vending.price > customer_account.money) + src.status_message = "Insufficient funds in account." + src.status_error = 1 + return 0 + else + // Okay to move the money at this point + var/datum/transaction/T = new("[vendor_account.owner_name] (via [name])", "Purchase of [currently_vending.item_name]", -currently_vending.price, name) + + customer_account.do_transaction(T) + + // Give the vendor the money. We use the account owner name, which means + // that purchases made with stolen/borrowed card will look like the card + // owner made them + credit_purchase(customer_account.owner_name) + return 1 + +/** + * Add money for current purchase to the vendor account. + * + * Called after the money has already been taken from the customer. + */ +/obj/machinery/vending/proc/credit_purchase(var/target as text) + vendor_account.money += currently_vending.price + + var/datum/transaction/T = new(target, "Purchase of [currently_vending.item_name]", currently_vending.price, name) + vendor_account.do_transaction(T) + +/obj/machinery/vending/attack_ai(mob/user as mob) + return attack_hand(user) + +/obj/machinery/vending/attack_hand(mob/user as mob) + if(stat & (BROKEN|NOPOWER)) + return + + if(src.seconds_electrified != 0) + if(src.shock(user, 100)) + return + + wires.Interact(user) + ui_interact(user) + +/** + * Display the NanoUI window for the vending machine. + * + * See NanoUI documentation for details. + */ +/obj/machinery/vending/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) + + var/list/data = list() + if(currently_vending) + data["mode"] = 1 + data["product"] = currently_vending.item_name + data["price"] = currently_vending.price + data["message_err"] = 0 + data["message"] = src.status_message + data["message_err"] = src.status_error + else + data["mode"] = 0 + var/list/listed_products = list() + + for(var/key = 1 to src.product_records.len) + var/datum/stored_items/vending_products/I = src.product_records[key] + + if(!(I.category & src.categories)) + continue + + listed_products.Add(list(list( + "key" = key, + "name" = I.item_name, + "price" = I.price, + "color" = I.display_color, + "amount" = I.get_amount()))) + + data["products"] = listed_products + + if(src.coin) + data["coin"] = src.coin.name + + if(src.panel_open) + data["panel"] = 1 + data["speaker"] = src.shut_up ? 0 : 1 + else + data["panel"] = 0 + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "vending_machine.tmpl", src.name, 440, 600) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/vending/Topic(href, href_list) + if(stat & (BROKEN|NOPOWER)) + return + if(..()) + return + + if(href_list["remove_coin"] && !istype(usr,/mob/living/silicon)) + if(!coin) + to_chat(usr, "There is no coin in this machine.") + return + + coin.forceMove(src.loc) + if(!usr.get_active_hand()) + usr.put_in_hands(coin) + to_chat(usr, "You remove \the [coin] from \the [src]") + coin = null + categories &= ~VENDING_CATEGORY_PREMIUM + + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)))) + if ((href_list["vend"]) && (src.vend_ready) && (!currently_vending)) + if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH + to_chat(usr, "Access denied.")//Unless emagged of course + flick(icon_deny,src) + return + + var/key = text2num(href_list["vend"]) + var/datum/stored_items/vending_products/R = product_records[key] + + // This should not happen unless the request from NanoUI was bad + if(!(R.category & src.categories)) + return + + if(R.price <= 0) + src.vend(R, usr) + else if(istype(usr,/mob/living/silicon)) //If the item is not free, provide feedback if a synth is trying to buy something. + to_chat(usr, "Artificial unit recognized. Artificial units cannot complete this transaction. Purchase canceled.") + return + else + src.currently_vending = R + if(!vendor_account || vendor_account.suspended) + src.status_message = "This machine is currently unable to process payments due to problems with the associated account." + src.status_error = 1 + else + src.status_message = "Please insert cash to pay for the item." + src.status_error = 0 + + else if (href_list["cancelpurchase"]) + src.currently_vending = null + + else if ((href_list["togglevoice"]) && (src.panel_open)) + src.shut_up = !src.shut_up + + GLOB.nanomanager.update_uis(src) + +/obj/machinery/vending/proc/vend(var/datum/stored_items/vending_products/R, mob/user) + if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH + to_chat(usr, "Access denied.")//Unless emagged of course + flick(src.icon_deny,src) + return + src.vend_ready = 0 //One thing at a time!! + src.status_message = "Vending..." + src.status_error = 0 + GLOB.nanomanager.update_uis(src) + + if (R.category & VENDING_CATEGORY_PREMIUM) + if(!coin) + to_chat(user, "You need to insert a coin to get this item.") + return + if(coin.string_attached) + if(prob(50)) + to_chat(user, "You successfully pull the coin out before \the [src] could swallow it.") + else + to_chat(user, "You weren't able to pull the coin out fast enough, the machine ate it, string and all.") + qdel(coin) + coin = null + categories &= ~VENDING_CATEGORY_PREMIUM + else + qdel(coin) + coin = null + categories &= ~VENDING_CATEGORY_PREMIUM + + if(((src.last_reply + (src.vend_delay + 200)) <= world.time) && src.vend_reply) + spawn(0) + src.speak(src.vend_reply) + src.last_reply = world.time + + use_power(vend_power_usage) //actuators and stuff + if (src.icon_vend) //Show the vending animation if needed + flick(src.icon_vend,src) + spawn(src.vend_delay) //Time to vend + //Just a normal vend, then + playsound(src.loc, "sound/[vending_sound]", 100, 1) + R.get_product(get_turf(src)) + src.visible_message("\The [src] whirs as it vends \the [R.item_name].") + if(prob(1)) //The vending gods look favorably upon you + sleep(3) + if(R.get_product(get_turf(src))) + src.visible_message("\The [src] clunks as it vends an additional [R.item_name].") + + src.status_message = "" + src.status_error = 0 + src.vend_ready = 1 + currently_vending = null + GLOB.nanomanager.update_uis(src) + +/** + * Add item to the machine + * + * Checks if item is vendable in this machine should be performed before + * calling. W is the item being inserted, R is the associated vending_product entry. + */ +/obj/machinery/vending/proc/stock(obj/item/weapon/W, var/datum/stored_items/vending_products/R, var/mob/user) + if(!user.unEquip(W)) + return + + if(R.add_product(W)) + to_chat(user, "You insert \the [W] in the product receptor.") + GLOB.nanomanager.update_uis(src) + return 1 + + GLOB.nanomanager.update_uis(src) + +/obj/machinery/vending/Process() + if(stat & (BROKEN|NOPOWER)) + return + + if(!src.active) + return + + if(src.seconds_electrified > 0) + src.seconds_electrified-- + + //Pitch to the people! Really sell it! + if(((src.last_slogan + src.slogan_delay) <= world.time) && (src.slogan_list.len > 0) && (!src.shut_up) && prob(5)) + var/slogan = pick(src.slogan_list) + src.speak(slogan) + src.last_slogan = world.time + + if(src.shoot_inventory && prob(2)) + src.throw_item() + + return + +/obj/machinery/vending/proc/speak(var/message) + if(stat & NOPOWER) + return + + if (!message) + return + + for(var/mob/O in hearers(src, null)) + O.show_message("\The [src] beeps, \"[message]\"",2) + return + +/obj/machinery/vending/powered() + return anchored && ..() + +/obj/machinery/vending/update_icon() + if(stat & BROKEN) + icon_state = "[initial(icon_state)]-broken" + else if( !(stat & NOPOWER) ) + icon_state = initial(icon_state) + else + spawn(rand(0, 15)) + src.icon_state = "[initial(icon_state)]-off" + +//Oh no we're malfunctioning! Dump out some product and break. +/obj/machinery/vending/proc/malfunction() + for(var/datum/stored_items/vending_products/R in src.product_records) + while(R.get_amount()>0) + R.get_product(loc) + break + + stat |= BROKEN + src.icon_state = "[initial(icon_state)]-broken" + return + +//Somebody cut an important wire and now we're following a new definition of "pitch." +/obj/machinery/vending/proc/throw_item() + var/obj/throw_item = null + var/mob/living/target = locate() in view(7,src) + if(!target) + return 0 + + for(var/datum/stored_items/vending_products/R in src.product_records) + throw_item = R.get_product(loc) + if (throw_item) + break + if (!throw_item) + return 0 + spawn(0) + throw_item.throw_at(target, rand(1,2), 3, src) + src.visible_message("\The [src] launches \a [throw_item] at \the [target]!") + return 1 + +/* + * Vending machine types + */ + +/* + +/obj/machinery/vending/[vendors name here] // --vending machine template :) + name = "" + desc = "" + icon = '' + icon_state = "" + vend_delay = 15 + products = list() + contraband = list() + premium = list() + +*/ + +/obj/machinery/vending/boozeomat + name = "Booze-O-Mat" + desc = "A refrigerated vending unit for alcoholic beverages and alcoholic beverage accessories." + icon_state = "boozeomat" + icon_deny = "boozeomat-deny" + products = list(/obj/item/weapon/reagent_containers/food/drinks/bottle/gin = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/whiskey = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/tequilla = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/vodka = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/vermouth = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/rum = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/wine = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/cognac = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/kahlua = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer = 15, + /obj/item/weapon/reagent_containers/food/drinks/bottle/small/ale = 15, + /obj/item/weapon/reagent_containers/food/drinks/bottle/orangejuice = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/tomatojuice = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/limejuice = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/cream = 5, + /obj/item/weapon/reagent_containers/food/drinks/cans/tonic = 15, + /obj/item/weapon/reagent_containers/food/drinks/bottle/cola = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/space_up = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/space_mountain_wind = 5, + /obj/item/weapon/reagent_containers/food/drinks/cans/sodawater = 15, + /obj/item/weapon/reagent_containers/food/drinks/flask/barflask = 5, + /obj/item/weapon/reagent_containers/food/drinks/flask/vacuumflask = 5, + /obj/item/weapon/reagent_containers/food/drinks/coffeecup/metal = 8, + /obj/item/weapon/reagent_containers/food/drinks/glass2/square = 10, + /obj/item/weapon/reagent_containers/food/drinks/glass2/rocks = 10, + /obj/item/weapon/reagent_containers/food/drinks/glass2/shake = 10, + /obj/item/weapon/reagent_containers/food/drinks/glass2/cocktail = 10, + /obj/item/weapon/reagent_containers/food/drinks/glass2/shot = 10, + /obj/item/weapon/reagent_containers/food/drinks/glass2/pint = 10, + /obj/item/weapon/reagent_containers/food/drinks/glass2/mug = 10, + /obj/item/weapon/reagent_containers/food/drinks/glass2/wine = 10, + /obj/item/weapon/reagent_containers/food/drinks/ice = 10, + /obj/item/weapon/reagent_containers/food/drinks/bottle/melonliquor = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/bluecuracao = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/absinthe = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/grenadine = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/specialwhiskey = 5, + /obj/item/weapon/reagent_containers/food/drinks/bottle/herbal = 5, + /obj/item/weapon/reagent_containers/food/drinks/tea = 15, + /obj/item/weapon/glass_extra/stick = 15, + /obj/item/weapon/glass_extra/straw = 15) + contraband = list(/obj/item/weapon/reagent_containers/food/drinks/bottle/premiumwine = 2, + /obj/item/weapon/reagent_containers/food/drinks/bottle/premiumvodka = 2) + vend_delay = 15 + idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan. + product_slogans = "I hope nobody asks me for a bloody cup o' tea...;Alcohol is humanity's friend. Would you abandon a friend?;Quite delighted to serve you!;Is nobody thirsty on this station?" + product_ads = "Drink up!;Booze is good for you!;Alcohol is humanity's best friend.;Quite delighted to serve you!;Care for a nice, cold beer?;Nothing cures you like booze!;Have a sip!;Have a drink!;Have a beer!;Beer is good for you!;Only the finest alcohol!;Best quality booze since 2053!;Award-winning wine!;Maximum alcohol!;Man loves beer.;A toast for progress!" + req_access = list(access_bar) + vending_sound = "machines/vendingcans.ogg" + +/obj/machinery/vending/assist + products = list( /obj/item/device/assembly/prox_sensor = 5,/obj/item/device/assembly/igniter = 3,/obj/item/device/assembly/signaler = 4, + /obj/item/weapon/wirecutters = 1, /obj/item/weapon/cartridge/signal = 4) + contraband = list(/obj/item/device/flashlight = 5,/obj/item/device/assembly/timer = 2) + product_ads = "Only the finest!;Have some tools.;The most robust equipment.;The finest gear in space!" + +/obj/machinery/vending/assist/antag + name = "AntagCorpVend" + contraband = list() + products = list( /obj/item/device/assembly/prox_sensor = 5, /obj/item/device/assembly/signaler = 4, + /obj/item/device/assembly/infra = 4, /obj/item/device/assembly/prox_sensor = 4, + /obj/item/weapon/handcuffs = 8, /obj/item/device/flash = 4, + /obj/item/weapon/cartridge/signal = 4, /obj/item/clothing/glasses/sunglasses = 4) + +/obj/machinery/vending/coffee + name = "Hot Drinks machine" + desc = "A vending machine which dispenses hot drinks." + product_ads = "Have a drink!;Drink up!;It's good for you!;Would you like a hot joe?;I'd kill for some coffee!;The best beans in the galaxy.;Only the finest brew for you.;Mmmm. Nothing like a coffee.;I like coffee, don't you?;Coffee helps you work!;Try some tea.;We hope you like the best!;Try our new chocolate!;Admin conspiracies" + icon_state = "coffee" + icon_vend = "coffee-vend" + vend_delay = 34 + idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan. + vend_power_usage = 85000 //85 kJ to heat a 250 mL cup of coffee + products = list(/obj/item/weapon/reagent_containers/food/drinks/coffee = 25,/obj/item/weapon/reagent_containers/food/drinks/tea = 25,/obj/item/weapon/reagent_containers/food/drinks/h_chocolate = 25) + contraband = list(/obj/item/weapon/reagent_containers/food/drinks/ice = 10) + prices = list(/obj/item/weapon/reagent_containers/food/drinks/coffee = 3, /obj/item/weapon/reagent_containers/food/drinks/tea = 3, /obj/item/weapon/reagent_containers/food/drinks/h_chocolate = 3) + vending_sound = "machines/vendingcoffee.ogg" + + + + +/obj/machinery/vending/snack + name = "Trenchmore Snack Machine" + desc = "A snack machine courtesy of the Trenchmore Chocolate Corporation. Who knew chocolate could thrive in a war like that." + product_slogans = "Try our new nougat bar!;Twice the calories for half the price!" + product_ads = "The healthiest!;Award-winning chocolate bars!;Mmm! So good!;Oh my god it's so juicy!;Have a snack.;Snacks are good for you!;Have some more Getmore!;Best quality snacks straight from mars.;We love chocolate!;Try our new jerky!" + icon_state = "snack" + icon_vend = "snack-vend" + vend_delay = 25 + products = list(/obj/item/weapon/reagent_containers/food/snacks/candy = 6,/obj/item/weapon/reagent_containers/food/drinks/dry_ramen = 6,/obj/item/weapon/reagent_containers/food/snacks/chips =6, + /obj/item/weapon/reagent_containers/food/snacks/sosjerky = 6,/obj/item/weapon/reagent_containers/food/snacks/no_raisin = 6,/obj/item/weapon/reagent_containers/food/snacks/spacetwinkie = 6, + /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers = 6, /obj/item/weapon/reagent_containers/food/snacks/tastybread = 6) + contraband = list(/obj/item/weapon/reagent_containers/food/snacks/syndicake = 6, /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks = 3) + prices = list(/obj/item/weapon/reagent_containers/food/snacks/candy = 1,/obj/item/weapon/reagent_containers/food/drinks/dry_ramen = 5,/obj/item/weapon/reagent_containers/food/snacks/chips = 1, + /obj/item/weapon/reagent_containers/food/snacks/sosjerky = 2,/obj/item/weapon/reagent_containers/food/snacks/no_raisin = 1,/obj/item/weapon/reagent_containers/food/snacks/spacetwinkie = 1, + /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers = 1, /obj/item/weapon/reagent_containers/food/snacks/tastybread = 2) + + + +/obj/machinery/vending/cola + name = "Robust Softdrinks" + desc = "A softdrink vendor provided by Robust Industries, LLC." + icon_state = "Cola_Machine" + icon_vend = "Cola_Machine-vend" + vend_delay = 11 + product_slogans = "Robust Softdrinks: More robust than a toolbox to the head!" + product_ads = "Refreshing!;Hope you're thirsty!;Over 1 million drinks sold!;Thirsty? Why not cola?;Please, have a drink!;Drink up!;The best drinks in space." + products = list(/obj/item/weapon/reagent_containers/food/drinks/cans/cola = 10,/obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind = 10, + /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb = 10,/obj/item/weapon/reagent_containers/food/drinks/cans/starkist = 10, + /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle = 10,/obj/item/weapon/reagent_containers/food/drinks/cans/space_up = 10, + /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea = 10, /obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice = 10) + contraband = list(/obj/item/weapon/reagent_containers/food/drinks/cans/thirteenloko = 5, /obj/item/weapon/reagent_containers/food/snacks/liquidfood = 6) + prices = list(/obj/item/weapon/reagent_containers/food/drinks/cans/cola = 1,/obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind = 1, + /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb = 1,/obj/item/weapon/reagent_containers/food/drinks/cans/starkist = 1, + /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle = 2,/obj/item/weapon/reagent_containers/food/drinks/cans/space_up = 1, + /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea = 1,/obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice = 1) + idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan. + vending_sound = "machines/vendingcans.ogg" + +/obj/machinery/vending/fitness + name = "SweatMAX" + desc = "An exercise aid and nutrition supplement vendor that preys on your inadequacy." + product_slogans = "SweatMAX, get robust!" + product_ads = "Pain is just weakness leaving the body!;Run! Your fat is catching up to you;Never forget leg day!;Push out!;This is the only break you get today.;Don't cry, sweat!;Healthy is an outfit that looks good on everybody." + icon_state = "fitness" + icon_vend = "fitness-vend" + vend_delay = 6 + products = list(/obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton = 8, + /obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton/chocolate = 8, + /obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask/proteinshake = 8, + /obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask = 8, + /obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar = 8, + /obj/item/weapon/reagent_containers/food/snacks/liquidfood = 8, + /obj/item/weapon/reagent_containers/pill/diet = 8, + /obj/item/weapon/towel/random = 8) + + prices = list(/obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton = 3, + /obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton/chocolate = 3, + /obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask/proteinshake = 20, + /obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask = 5, + /obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar = 5, + /obj/item/weapon/reagent_containers/food/snacks/liquidfood = 5, + /obj/item/weapon/reagent_containers/pill/diet = 25, + /obj/item/weapon/towel/random = 40) + + contraband = list(/obj/item/weapon/reagent_containers/syringe/steroid = 4) + +//This one's from bay12 +/obj/machinery/vending/cart + name = "PTech" + desc = "Cartridges for PDAs." + product_slogans = "Carts to go!" + icon_state = "cart" + icon_deny = "cart-deny" + icon_vend = "cart-vend" + vend_delay = 23 + products = list(/obj/item/weapon/cartridge/medical = 10,/obj/item/weapon/cartridge/engineering = 10,/obj/item/weapon/cartridge/security = 10, + /obj/item/weapon/cartridge/janitor = 10,/obj/item/weapon/cartridge/signal/science = 10,/obj/item/device/pda/heads = 10, + /obj/item/weapon/cartridge/captain = 3,/obj/item/weapon/cartridge/quartermaster = 10) + + +/obj/machinery/vending/cigarette + name = "Cigarette machine" //OCD had to be uppercase to look nice with the new formating + desc = "A specialized vending machine designed to contribute to your slow and uncomfortable death." + product_slogans = "There's no better time to start smokin'.;\ + Smoke now, and win the adoration of your peers.;\ + They beat cancer centuries ago, so smoke away.;\ + If you're not smoking, you must be joking." + product_ads = "Probably not bad for you!;\ + Don't believe the scientists!;\ + It's good for you!;\ + Don't quit, buy more!;\ + Smoke!;\ + Nicotine heaven.;\ + Best cigarettes since 2150.;\ + Award-winning cigarettes, all the best brands.;\ + Feeling temperamental? Try a Temperamento!;\ + Carcinoma Angels - go fuck yerself!;\ + Don't be so hard on yourself, kid. Smoke a Lucky Star!;\ + We understand the depressed, alcoholic cowboy in you. That's why we also smoke Jericho.;\ + Professionals. Better cigarettes for better people. Yes, better people." + vend_delay = 21 + icon_state = "cigs" + icon_vend = "cigs-vend" + products = list(/obj/item/weapon/storage/fancy/cigarettes = 5, + /obj/item/weapon/storage/fancy/cigarettes/luckystars = 2, + /obj/item/weapon/storage/fancy/cigarettes/jerichos = 2, + /obj/item/weapon/storage/fancy/cigarettes/carcinomas = 2, + /obj/item/weapon/storage/box/matches = 10, + /obj/item/weapon/flame/lighter/random = 4, + /obj/item/weapon/flame/lighter/zippo = 4) + + prices = list(/obj/item/weapon/storage/fancy/cigarettes = 45, + /obj/item/weapon/storage/fancy/cigarettes/luckystars = 50, + /obj/item/weapon/storage/fancy/cigarettes/jerichos = 65, + /obj/item/weapon/storage/fancy/cigarettes/carcinomas = 65, + /obj/item/weapon/storage/box/matches = 2, + /obj/item/weapon/flame/lighter/random = 5, + /obj/item/weapon/flame/lighter/zippo = 100) + + +/obj/machinery/vending/medical + name = "NanoMed Plus" + desc = "Medical drug dispenser." + icon_state = "med" + icon_deny = "med-deny" + icon_vend = "med-vend" + vend_delay = 18 + product_ads = "Go save some lives!;The best stuff for your medbay.;Only the finest tools.;Natural chemicals!;This stuff saves lives.;Don't you want some?;Ping!" + req_access = list(access_medical_equip) + products = list(/obj/item/weapon/reagent_containers/glass/bottle/antitoxin = 4,/obj/item/weapon/reagent_containers/glass/bottle/inaprovaline = 4, + /obj/item/weapon/reagent_containers/glass/bottle/stoxin = 4,/obj/item/weapon/reagent_containers/glass/bottle/toxin = 4, + /obj/item/weapon/reagent_containers/syringe/antiviral = 4,/obj/item/weapon/reagent_containers/syringe = 12, + /obj/item/device/healthanalyzer = 5,/obj/item/weapon/reagent_containers/glass/beaker = 4, /obj/item/weapon/reagent_containers/dropper = 2, + /obj/item/stack/medical/advanced/bruise_pack = 3, /obj/item/stack/medical/advanced/ointment = 3, /obj/item/stack/medical/splint = 2, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/pain = 4, /obj/item/weapon/reagent_containers/hypospray/autoinjector/revive = 5,/obj/item/weapon/reagent_containers/hypospray/autoinjector/blood = 5) + contraband = list(/obj/item/weapon/reagent_containers/pill/tox = 3,/obj/item/weapon/reagent_containers/pill/stox = 4,/obj/item/weapon/reagent_containers/pill/antitox = 6, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/combatpain = 2) + idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan. + + +//This one's from bay12 +/obj/machinery/vending/phoronresearch + name = "Toximate 3000" + desc = "All the fine parts you need in one vending machine!" + products = list(/obj/item/clothing/suit/bio_suit = 6,/obj/item/clothing/head/bio_hood = 6, + /obj/item/device/transfer_valve = 6,/obj/item/device/assembly/timer = 6,/obj/item/device/assembly/signaler = 6, + /obj/item/device/assembly/prox_sensor = 6,/obj/item/device/assembly/igniter = 6) + +/obj/machinery/vending/wallmed1 + name = "NanoMed" + desc = "A wall-mounted version of the NanoMed." + product_ads = "Go save some lives!;The best stuff for your medbay.;Only the finest tools.;Natural chemicals!;This stuff saves lives.;Don't you want some?" + icon_state = "wallmed" + icon_deny = "wallmed-deny" + density = 0 //It is wall-mounted, and thus, not dense. --Superxpdude + products = list(/obj/item/stack/medical/bruise_pack = 2,/obj/item/stack/medical/ointment = 2,/obj/item/weapon/reagent_containers/hypospray/autoinjector = 4) + contraband = list(/obj/item/weapon/reagent_containers/syringe/antitoxin = 4,/obj/item/weapon/reagent_containers/syringe/antiviral = 4,/obj/item/weapon/reagent_containers/pill/tox = 1) + +/obj/machinery/vending/wallmed2 + name = "NanoMed Mini" + desc = "A wall-mounted version of the NanoMed, containing only vital first aid equipment." + product_ads = "Go save some lives!;The best stuff for your medbay.;Only the finest tools.;Natural chemicals!;This stuff saves lives.;Don't you want some?" + icon_state = "wallmed" + icon_deny = "wallmed-deny" + density = 0 //It is wall-mounted, and thus, not dense. --Superxpdude + products = list(/obj/item/weapon/reagent_containers/hypospray/autoinjector = 5,/obj/item/weapon/reagent_containers/syringe/antitoxin = 1,/obj/item/stack/medical/bruise_pack = 3, + /obj/item/stack/medical/ointment =3) + contraband = list(/obj/item/weapon/reagent_containers/pill/tox = 3, /obj/item/weapon/reagent_containers/hypospray/autoinjector/pain = 2) + +/obj/machinery/vending/security + name = "SecTech" + desc = "A security equipment vendor." + product_ads = "Crack capitalist skulls!;Beat some heads in!;Don't forget - harm is good!;Your weapons are right here.;Handcuffs!;Freeze, scumbag!;Don't tase me bro!;Tase them, bro.;Why not have a donut?" + icon_state = "sec" + icon_deny = "sec-deny" + icon_vend = "sec-vend" + vend_delay = 14 + req_access = list(access_security) + products = list(/obj/item/weapon/handcuffs = 8,/obj/item/weapon/grenade/flashbang = 4,/obj/item/weapon/grenade/chem_grenade/teargas = 4,/obj/item/device/flash = 5, + /obj/item/weapon/reagent_containers/food/snacks/donut/normal = 12,/obj/item/weapon/storage/box/evidence = 6) + contraband = list(/obj/item/clothing/glasses/sunglasses = 2,/obj/item/weapon/storage/box/donut = 2) + +/obj/machinery/vending/hydronutrients + name = "NutriMax" + desc = "A plant nutrients vendor." + product_slogans = "Aren't you glad you don't have to fertilize the natural way?;Now with 50% less stink!;Plants are people too!" + product_ads = "We like plants!;Don't you want some?;The greenest thumbs ever.;We like big plants.;Soft soil..." + icon_state = "nutri" + icon_deny = "nutri-deny" + icon_vend = "nutri-vend" + vend_delay = 26 + products = list(/obj/item/weapon/reagent_containers/glass/bottle/eznutrient = 6,/obj/item/weapon/reagent_containers/glass/bottle/left4zed = 4,/obj/item/weapon/reagent_containers/glass/bottle/robustharvest = 3,/obj/item/weapon/plantspray/pests = 20, + /obj/item/weapon/reagent_containers/syringe = 5,/obj/item/weapon/storage/plants = 5) + premium = list(/obj/item/weapon/reagent_containers/glass/bottle/ammonia = 10,/obj/item/weapon/reagent_containers/glass/bottle/diethylamine = 5) + idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan. + +/obj/machinery/vending/hydroseeds + name = "MegaSeed Servitor" + desc = "When you need seeds fast!" + product_slogans = "THIS'S WHERE TH' SEEDS LIVE! GIT YOU SOME!;Hands down the best seed selection this half of the galaxy!;Also certain mushroom varieties available, more for experts! Get certified today!" + product_ads = "We like plants!;Grow some crops!;Grow, baby, growww!;Aw h'yeah son!" + icon_state = "seeds" + icon_vend = "seeds-vend" + vend_delay = 13 + products = list(/obj/item/seeds/bananaseed = 3,/obj/item/seeds/berryseed = 3,/obj/item/seeds/carrotseed = 3,/obj/item/seeds/chantermycelium = 3,/obj/item/seeds/chiliseed = 3, + /obj/item/seeds/cornseed = 3, /obj/item/seeds/eggplantseed = 3, /obj/item/seeds/potatoseed = 3, /obj/item/seeds/replicapod = 3,/obj/item/seeds/soyaseed = 3, + /obj/item/seeds/sunflowerseed = 3,/obj/item/seeds/tomatoseed = 3,/obj/item/seeds/towermycelium = 3,/obj/item/seeds/wheatseed = 3,/obj/item/seeds/appleseed = 3, + /obj/item/seeds/poppyseed = 3,/obj/item/seeds/sugarcaneseed = 3,/obj/item/seeds/ambrosiavulgarisseed = 3,/obj/item/seeds/peanutseed = 3,/obj/item/seeds/whitebeetseed = 3,/obj/item/seeds/watermelonseed = 3,/obj/item/seeds/limeseed = 3, + /obj/item/seeds/lemonseed = 3,/obj/item/seeds/orangeseed = 3,/obj/item/seeds/grassseed = 3,/obj/item/seeds/cocoapodseed = 3,/obj/item/seeds/plumpmycelium = 2, + /obj/item/seeds/cabbageseed = 3,/obj/item/seeds/grapeseed = 3,/obj/item/seeds/pumpkinseed = 3,/obj/item/seeds/cherryseed = 3,/obj/item/seeds/plastiseed = 3,/obj/item/seeds/riceseed = 3,/obj/item/seeds/lavenderseed = 3) + contraband = list(/obj/item/seeds/amanitamycelium = 2,/obj/item/seeds/glowshroom = 2,/obj/item/seeds/libertymycelium = 2,/obj/item/seeds/mtearseed = 2, + /obj/item/seeds/nettleseed = 2,/obj/item/seeds/reishimycelium = 2,/obj/item/seeds/reishimycelium = 2,/obj/item/seeds/shandseed = 2,) + premium = list(/obj/item/weapon/reagent_containers/spray/waterflower = 1) + +/** + * Populate hydroseeds product_records + */ +/obj/machinery/vending/hydroseeds/build_inventory() + var/list/all_products = list( + list(src.products, VENDING_CATEGORY_NORMAL), + list(src.contraband, VENDING_CATEGORY_HIDDEN), + list(src.premium, VENDING_CATEGORY_PREMIUM)) + + for(var/current_list in all_products) + var/category = current_list[2] + + for(var/entry in current_list[1]) + var/obj/item/I = new entry(src) + + //seed pack names are initialized at runtime, and the machine can contain non seed items! + //Hello kludgecode. + var/name = I.name + if(istype(I, /obj/item/seeds)) + var/obj/item/seeds/S = I + name = S.seed_type + + var/datum/stored_items/vending_products/product = new/datum/stored_items/vending_products(src, entry, name) + + product.price = (entry in src.prices) ? src.prices[entry] : 0 + product.amount = (current_list[1][entry]) ? current_list[1][entry] : 1 + product.category = category + + src.product_records.Add(product) + +/obj/machinery/vending/magivend + name = "MagiVend" + desc = "A magic vending machine." + icon_state = "MagiVend" + product_slogans = "Sling spells the proper way with MagiVend!;Be your own Houdini! Use MagiVend!" + vend_delay = 15 + vend_reply = "Have an enchanted evening!" + product_ads = "FJKLFJSD;AJKFLBJAKL;1234 LOONIES LOL!;>MFW;Kill them fuckers!;GET DAT FUKKEN DISK;HONK!;EI NATH;Down with Central!;Admin conspiracies since forever!;Space-time bending hardware!" + products = list(/obj/item/clothing/head/wizard = 1,/obj/item/clothing/suit/wizrobe = 1,/obj/item/clothing/head/wizard/red = 1,/obj/item/clothing/suit/wizrobe/red = 1,/obj/item/clothing/shoes/sandal = 1,/obj/item/weapon/staff = 2) + +/obj/machinery/vending/dinnerware + name = "Dinnerware" + desc = "A kitchen and restaurant equipment vendor." + product_ads = "Mm, food stuffs!;Food and food accessories.;Get your plates!;You like forks?;I like forks.;Woo, utensils.;You don't really need these..." + icon_state = "dinnerware" + icon_vend = "dinnerware-vend" + products = list( + /obj/item/weapon/tray = 8, + /obj/item/weapon/material/kitchen/utensil/fork = 6, + /obj/item/weapon/material/kitchen/utensil/knife = 6, + /obj/item/weapon/material/kitchen/utensil/spoon = 6, + /obj/item/weapon/material/knife = 3, + /obj/item/weapon/material/kitchen/rollingpin = 2, + /obj/item/weapon/reagent_containers/food/drinks/pitcher = 2, + /obj/item/weapon/reagent_containers/food/drinks/coffeecup = 8, + /obj/item/weapon/reagent_containers/food/drinks/glass2/carafe = 2, + /obj/item/weapon/reagent_containers/food/drinks/glass2/square = 8, + /obj/item/clothing/suit/chef/classic = 2, + /obj/item/weapon/storage/lunchbox = 3, + /obj/item/weapon/storage/lunchbox/heart = 3, + /obj/item/weapon/storage/lunchbox/cat = 3, + /obj/item/weapon/storage/lunchbox/nt = 3, + /obj/item/weapon/storage/lunchbox/mars = 3, + /obj/item/weapon/storage/lunchbox/cti = 3, + /obj/item/weapon/storage/lunchbox/nymph = 3, + /obj/item/weapon/storage/lunchbox/syndicate = 3) + + + contraband = list(/obj/item/weapon/material/knife/butch = 2) + +/obj/machinery/vending/sovietsoda + name = "BODA" + desc = "An old soda vending machine. How could this have got here?" + icon_state = "sovietsoda" + icon_vend = "sovietsoda-vend" + product_ads = "For Tsar and Country.;Have you fulfilled your nutrition quota today?;Very nice!;We are simple people, for this is all we eat.;If there is a person, there is a problem. If there is no person, then there is no problem." + products = list(/obj/item/weapon/reagent_containers/food/drinks/bottle/space_up = 30) // TODO Russian soda can + contraband = list(/obj/item/weapon/reagent_containers/food/drinks/bottle/cola = 20) // TODO Russian cola can + idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan. + vending_sound = "machines/vendingcans.ogg" + +/obj/machinery/vending/tool + name = "YouTool" + desc = "Tools for tools." + icon_state = "tool" + icon_deny = "tool-deny" + icon_vend = "tool-vend" + vend_delay = 11 + //req_access = list(access_maint_tunnels) //Maintenance access + products = list(/obj/item/stack/cable_coil/random = 10,/obj/item/weapon/crowbar = 5,/obj/item/weapon/weldingtool = 3,/obj/item/weapon/wirecutters = 5, + /obj/item/weapon/wrench = 5,/obj/item/device/analyzer = 5,/obj/item/device/t_scanner = 5,/obj/item/weapon/screwdriver = 5, + /obj/item/device/flashlight/glowstick = 3, /obj/item/device/flashlight/glowstick/red = 3) + contraband = list(/obj/item/weapon/weldingtool/hugetank = 2,/obj/item/clothing/gloves/insulated/cheap = 2) + premium = list(/obj/item/clothing/gloves/insulated = 1) + +/obj/machinery/vending/engivend + name = "Engi-Vend" + desc = "Spare tool vending. What? Did you expect some witty description?" + icon_state = "engivend" + icon_deny = "engivend-deny" + icon_vend = "engivend-vend" + vend_delay = 21 + req_one_access = list(access_atmospherics,access_engine_equip) + products = list(/obj/item/clothing/glasses/meson = 2,/obj/item/device/multitool = 4,/obj/item/device/geiger = 4,/obj/item/weapon/airlock_electronics = 10,/obj/item/weapon/module/power_control = 10,/obj/item/weapon/airalarm_electronics = 10,/obj/item/weapon/cell = 10,/obj/item/clamp = 10) + contraband = list(/obj/item/weapon/cell/high = 3) + premium = list(/obj/item/weapon/storage/belt/utility = 3) + +//This one's from bay12 +/obj/machinery/vending/engineering + name = "Robco Tool Maker" + desc = "Everything you need for do-it-yourself repair." + icon_state = "engi" + icon_deny = "engi-deny" + req_one_access = list(access_atmospherics,access_engine_equip) + products = list(/obj/item/weapon/storage/belt/utility = 4,/obj/item/clothing/glasses/meson = 4,/obj/item/clothing/gloves/insulated = 4, /obj/item/weapon/screwdriver = 12, + /obj/item/weapon/crowbar = 12,/obj/item/weapon/wirecutters = 12,/obj/item/device/multitool = 12,/obj/item/weapon/wrench = 12,/obj/item/device/t_scanner = 12, + /obj/item/weapon/cell = 8, /obj/item/weapon/weldingtool = 8,/obj/item/clothing/head/welding = 8, + /obj/item/weapon/light/tube = 10,/obj/item/weapon/stock_parts/scanning_module = 5,/obj/item/weapon/stock_parts/micro_laser = 5, + /obj/item/weapon/stock_parts/matter_bin = 5,/obj/item/weapon/stock_parts/manipulator = 5,/obj/item/weapon/stock_parts/console_screen = 5, + /obj/item/weapon/stock_parts/capacitor = 5) + contraband = list(/obj/item/weapon/rcd = 1, /obj/item/weapon/rcd_ammo = 5) + // There was an incorrect entry (cablecoil/power). I improvised to cablecoil/heavyduty. + // Another invalid entry, /obj/item/weapon/circuitry. I don't even know what that would translate to, removed it. + // The original products list wasn't finished. The ones without given quantities became quantity 5. -Sayu + +//This one's from bay12 +/obj/machinery/vending/robotics + name = "Robotech Deluxe" + desc = "All the tools you need to create your own robot army." + icon_state = "robotics" + icon_deny = "robotics-deny" + req_access = list(access_robotics) + products = list(/obj/item/stack/cable_coil = 4,/obj/item/device/flash/synthetic = 4,/obj/item/weapon/cell = 4,/obj/item/device/healthanalyzer = 2, + /obj/item/weapon/scalpel = 1,/obj/item/weapon/circular_saw = 1,/obj/item/weapon/tank/anesthetic = 2,/obj/item/clothing/mask/breath/medical = 5, + /obj/item/weapon/screwdriver = 2,/obj/item/weapon/crowbar = 2) + contraband = list(/obj/item/device/flash = 2) + +//FOR ACTORS GUILD - mainly props that cannot be spawned otherwise +/obj/machinery/vending/props + name = "prop dispenser" + desc = "All the props an actor could need. Probably." + icon_state = "Theater" + products = list(/obj/structure/flora/pottedplant = 2, /obj/item/device/flashlight/lamp = 2, /obj/item/device/flashlight/lamp/green = 2, /obj/item/weapon/reagent_containers/food/drinks/jar = 1, + /obj/item/weapon/nullrod = 1, /obj/item/toy/cultsword = 4, /obj/item/toy/katana = 2) + +//FOR ACTORS GUILD - Containers +/obj/machinery/vending/containers + name = "container dispenser" + desc = "A container that dispenses containers." + icon_state = "robotics" + products = list(/obj/structure/closet/crate/freezer = 2, /obj/structure/closet = 3, /obj/structure/closet/crate = 3) + +/obj/machinery/vending/fashionvend + name = "Smashing Fashions" + desc = "For all your cheap knockoff needs." + product_slogans = "Look smashing for your darling!;Be rich! Dress rich!" + icon_state = "Theater" + vend_delay = 15 + vend_reply = "Absolutely smashing!" + product_ads = "Impress the love of your life!;Don't look poor, look rich!;100% authentic designers!;All sales are final!;Lowest prices guaranteed!" + products = list(/obj/item/weapon/mirror = 8, + /obj/item/weapon/haircomb = 8, + /obj/item/clothing/glasses/monocle = 5, + /obj/item/clothing/glasses/sunglasses = 5, + /obj/item/weapon/lipstick = 3, + /obj/item/weapon/lipstick/black = 3, + /obj/item/weapon/lipstick/purple = 3, + /obj/item/weapon/lipstick/jade = 3, + /obj/item/weapon/storage/wallet/poly = 2) + contraband = list(/obj/item/clothing/glasses/eyepatch = 2, /obj/item/clothing/accessory/horrible = 2) + premium = list(/obj/item/clothing/mask/smokable/pipe = 3) + prices = list(/obj/item/weapon/mirror = 60, + /obj/item/weapon/haircomb = 40, + /obj/item/clothing/glasses/monocle = 700, + /obj/item/clothing/glasses/sunglasses = 500, + /obj/item/weapon/lipstick = 100, + /obj/item/weapon/lipstick/black = 100, + /obj/item/weapon/lipstick/purple = 100, + /obj/item/weapon/lipstick/jade = 100, + /obj/item/weapon/storage/wallet/poly = 600 + ) +// eliza's attempt at a new vending machine +/obj/machinery/vending/games + name = "Good Clean Fun" + desc = "Vends things that the CO and SEA are probably not going to appreciate you fiddling with instead of your job..." + vend_delay = 15 + product_slogans = "Escape to a fantasy world!;Fuel your gambling addiction!;Ruin your friendships!" + product_ads = "Elves and dwarves!;Totally not satanic!;Fun times forever!" + icon_state = "games" + products = list(/obj/item/toy/blink = 5, /obj/item/toy/spinningtoy = 2, /obj/item/weapon/deck/cards = 5, /obj/item/weapon/deck/tarot = 5, /obj/item/weapon/pack/cardemon = 6, /obj/item/weapon/storage/pill_bottle/dice_nerd = 5, /obj/item/weapon/storage/pill_bottle/dice = 5, /obj/item/weapon/storage/box/checkers = 2, /obj/item/weapon/storage/box/checkers/chess/red = 2, /obj/item/weapon/storage/box/checkers/chess = 2) + prices = list(/obj/item/toy/blink = 3, /obj/item/toy/spinningtoy = 10, /obj/item/weapon/deck/tarot = 3, /obj/item/weapon/deck/cards = 3, /obj/item/weapon/pack/cardemon = 5, /obj/item/weapon/storage/pill_bottle/dice_nerd = 6, /obj/item/weapon/storage/pill_bottle/dice = 6, /obj/item/weapon/storage/box/checkers = 10, /obj/item/weapon/storage/box/checkers/chess/red = 10, /obj/item/weapon/storage/box/checkers/chess = 10) + premium = list(/obj/item/weapon/gun/projectile/revolver/capgun = 1, /obj/item/ammo_magazine/caps = 4) + contraband = list(/obj/item/weapon/reagent_containers/spray/waterflower = 2, /obj/item/weapon/storage/box/snappops = 3) diff --git a/code/game/machinery/wall_frames.dm b/code/game/machinery/wall_frames.dm new file mode 100644 index 00000000..d3e4f6a1 --- /dev/null +++ b/code/game/machinery/wall_frames.dm @@ -0,0 +1,74 @@ +/obj/item/frame + name = "frame" + desc = "Used for building machines." + icon = 'icons/obj/monitors.dmi' + icon_state = "fire_bitem" + obj_flags = OBJ_FLAG_CONDUCTIBLE + var/build_machine_type + var/refund_amt = 2 + var/refund_type = /obj/item/stack/material/steel + var/reverse = 0 //if resulting object faces opposite its dir (like light fixtures) + +/obj/item/frame/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWrench(W)) + new refund_type( get_turf(src.loc), refund_amt) + qdel(src) + return + ..() + +/obj/item/frame/proc/try_build(turf/on_wall) + if(!build_machine_type) + return + + if (get_dist(on_wall,usr)>1) + return + + var/ndir + if(reverse) + ndir = get_dir(usr,on_wall) + else + ndir = get_dir(on_wall,usr) + + if (!(ndir in GLOB.cardinal)) + return + + var/turf/loc = get_turf(usr) + var/area/A = loc.loc + if (!istype(loc, /turf/simulated/floor)) + to_chat(usr, "\The [src] cannot be placed on this spot.") + return + if (A.requires_power == 0 || A.name == "Space") + to_chat(usr, "\The [src] cannot be placed in this area.") + return + + if(gotwallitem(loc, ndir)) + to_chat(usr, "There's already an item on this wall!") + return + + new build_machine_type(loc, ndir, src) + qdel(src) + +/obj/item/frame/fire_alarm + name = "fire alarm frame" + desc = "Used for building fire alarms." + build_machine_type = /obj/machinery/firealarm + +/obj/item/frame/air_alarm + name = "air alarm frame" + icon_state = "alarm_bitem" + desc = "Used for building air alarms." + build_machine_type = /obj/machinery/alarm + +/obj/item/frame/light + name = "light fixture frame" + desc = "Used for building lights." + icon = 'icons/obj/lighting.dmi' + icon_state = "tube-construct-item" + build_machine_type = /obj/machinery/light_construct + reverse = 1 + +/obj/item/frame/light/small + name = "small light fixture frame" + icon_state = "bulb-construct-item" + refund_amt = 1 + build_machine_type = /obj/machinery/light_construct/small diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm new file mode 100644 index 00000000..2ebe4089 --- /dev/null +++ b/code/game/machinery/washing_machine.dm @@ -0,0 +1,198 @@ +/obj/machinery/washing_machine + name = "Washing Machine" + icon = 'icons/obj/machines/washing_machine.dmi' + icon_state = "wm_10" + density = 1 + anchored = 1.0 + var/state = 1 + //1 = empty, open door + //2 = empty, closed door + //3 = full, open door + //4 = full, closed door + //5 = running + //6 = blood, open door + //7 = blood, closed door + //8 = blood, running + var/panel = 0 + //0 = closed + //1 = open + var/hacked = 1 //Bleh, screw hacking, let's have it hacked by default. + //0 = not hacked + //1 = hacked + var/gibs_ready = 0 + var/obj/crayon + +/obj/machinery/washing_machine/Destroy() + qdel(crayon) + crayon = null + . = ..() + +/obj/machinery/washing_machine/proc/start() + set name = "Start Washing" + set category = "Object" + + if(!istype(usr, /mob/living)) //ew ew ew usr, but it's the only way to check. + return + + if( state != 4 ) + to_chat(usr, "The washing machine cannot run in this state.") + return + + if( locate(/mob,contents) ) + state = 8 + else + state = 5 + update_icon() + sleep(200) + for(var/atom/A in contents) + A.clean_blood() + if(isitem(A)) + var/obj/item/I = A + I.decontaminate() + if(crayon && iscolorablegloves(I)) + var/obj/item/clothing/gloves/C = I + C.color = crayon.color + + //Tanning! + for(var/obj/item/stack/material/hairlesshide/HH in contents) + var/obj/item/stack/material/wetleather/WL = new(src) + WL.amount = HH.amount + qdel(HH) + + if( locate(/mob,contents) ) + state = 7 + gibs_ready = 1 + else + state = 4 + update_icon() + +/obj/machinery/washing_machine/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + start() + +/obj/machinery/washing_machine/verb/climb_out() + set name = "Climb out" + set category = "Object" + set src in usr.loc + + sleep(20) + if(state in list(1,3,6) ) + usr.loc = src.loc + + +/obj/machinery/washing_machine/update_icon() + icon_state = "wm_[state][panel]" + +/obj/machinery/washing_machine/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/weapon/pen/crayon) || istype(W,/obj/item/weapon/stamp)) + if( state in list( 1, 3, 6 ) ) + if(!crayon) + user.drop_item() + crayon = W + crayon.forceMove(src) + else + ..() + else + ..() + else if(istype(W,/obj/item/grab)) + if( (state == 1) && hacked) + var/obj/item/grab/G = W + if(ishuman(G.assailant) && iscorgi(G.affecting)) + G.affecting.loc = src + qdel(G) + state = 3 + else + ..() + else if(istype(W,/obj/item/stack/material/hairlesshide) || \ + istype(W,/obj/item/clothing/under) || \ + istype(W,/obj/item/clothing/mask) || \ + istype(W,/obj/item/clothing/head) || \ + istype(W,/obj/item/clothing/gloves) || \ + istype(W,/obj/item/clothing/shoes) || \ + istype(W,/obj/item/clothing/suit) || \ + istype(W,/obj/item/weapon/bedsheet)) + + //YES, it's hardcoded... saves a var/can_be_washed for every single clothing item. + if ( istype(W,/obj/item/clothing/suit/space ) ) + to_chat(user, "This item does not fit.") + return + if ( istype(W,/obj/item/clothing/suit/syndicatefake ) ) + to_chat(user, "This item does not fit.") + return +// if ( istype(W,/obj/item/clothing/suit/powered ) ) +// to_chat(user, "This item does not fit.") +// return + if ( istype(W,/obj/item/clothing/suit/cyborg_suit ) ) + to_chat(user, "This item does not fit.") + return + if ( istype(W,/obj/item/clothing/suit/bomb_suit ) ) + to_chat(user, "This item does not fit.") + return + if ( istype(W,/obj/item/clothing/suit/armor ) ) + to_chat(user, "This item does not fit.") + return + if ( istype(W,/obj/item/clothing/suit/armor ) ) + to_chat(user, "This item does not fit.") + return + if ( istype(W,/obj/item/clothing/mask/gas ) ) + to_chat(user, "This item does not fit.") + return + if ( istype(W,/obj/item/clothing/mask/smokable/cigarette ) ) + to_chat(user, "This item does not fit.") + return + if ( istype(W,/obj/item/clothing/head/syndicatefake ) ) + to_chat(user, "This item does not fit.") + return +// if ( istype(W,/obj/item/clothing/head/powered ) ) +// to_chat(user, "This item does not fit.") +// return + if ( istype(W,/obj/item/clothing/head/helmet ) ) + to_chat(user, "This item does not fit.") + return + + if(contents.len < 5) + if ( state in list(1, 3) ) + user.drop_item() + W.loc = src + state = 3 + else + to_chat(user, "You can't put the item in right now.") + else + to_chat(user, "The washing machine is full.") + else + ..() + update_icon() + +/obj/machinery/washing_machine/attack_hand(mob/user as mob) + switch(state) + if(1) + state = 2 + if(2) + state = 1 + for(var/atom/movable/O in contents) + O.forceMove(loc) + if(3) + state = 4 + if(4) + state = 3 + for(var/atom/movable/O in contents) + O.forceMove(src) + crayon = null + state = 1 + if(5) + to_chat(user, "The [src] is busy.") + if(6) + state = 7 + if(7) + if(gibs_ready) + gibs_ready = 0 + if(locate(/mob,contents)) + var/mob/M = locate(/mob,contents) + M.gib() + for(var/atom/movable/O in contents) + O.forceMove(src.loc) + crayon = null + state = 1 + + + update_icon() diff --git a/code/game/machinery/wishgranter.dm b/code/game/machinery/wishgranter.dm new file mode 100644 index 00000000..85e8dc23 --- /dev/null +++ b/code/game/machinery/wishgranter.dm @@ -0,0 +1,68 @@ +/obj/machinery/wish_granter + name = "Wish Granter" + desc = "You're not so sure about this, anymore..." + icon = 'icons/obj/device.dmi' + icon_state = "syndbeacon" + + use_power = 0 + anchored = 1 + density = 1 + + var/charges = 1 + var/insisting = 0 + +/obj/machinery/wish_granter/attack_hand(var/mob/user as mob) + usr.set_machine(src) + + if(charges <= 0) + to_chat(user, "The Wish Granter lies silent.") + return + + else if(!istype(user, /mob/living/carbon/human)) + to_chat(user, "You feel a dark stirring inside of the Wish Granter, something you want nothing of. Your instincts are better than any man's.") + return + + else if(is_special_character(user)) + to_chat(user, "Even to a heart as dark as yours, you know nothing good will come of this. Something instinctual makes you pull away.") + else if (!insisting) + to_chat(user, "Your first touch makes the Wish Granter stir, listening to you. Are you really sure you want to do this?") + insisting++ + + else + var/message = "You speak. [pick("I want the [station_name()] to disappear","Humanity is corrupt, mankind must be destroyed","I want to be rich", "I want to rule the world","I want immortality.")]. The Wish Granter answers." + to_chat(user, message) + to_chat(user, "Your head pounds for a moment, before your vision clears. You are the avatar of the Wish Granter, and your power is LIMITLESS! And it's all yours. You need to make sure no one can take it from you. No one can know, first.") + charges-- + insisting = 0 + + if (!(HULK in user.mutations)) + user.mutations.Add(HULK) + + if (!(LASER in user.mutations)) + user.mutations.Add(LASER) + + if (!(XRAY in user.mutations)) + user.mutations.Add(XRAY) + user.set_sight(user.sight|SEE_MOBS|SEE_OBJS|SEE_TURFS) + user.set_see_in_dark(8) + user.set_see_invisible(SEE_INVISIBLE_LEVEL_TWO) + + if (!(COLD_RESISTANCE in user.mutations)) + user.mutations.Add(COLD_RESISTANCE) + + if (!(TK in user.mutations)) + user.mutations.Add(TK) + + if(!(HEAL in user.mutations)) + user.mutations.Add(HEAL) + + user.update_mutations() + user.mind.special_role = "Avatar of the Wish Granter" + + var/datum/objective/silence/silence = new + silence.owner = user.mind + user.mind.objectives += silence + + show_objectives(user.mind) + to_chat(user, "You have a very bad feeling about this.") + return diff --git a/code/game/magic/Uristrunes.dm b/code/game/magic/Uristrunes.dm new file mode 100644 index 00000000..cecbefc7 --- /dev/null +++ b/code/game/magic/Uristrunes.dm @@ -0,0 +1,131 @@ + +var/list/word_to_uristrune_table = null + +/proc/word_to_uristrune_bit(word) + if(word_to_uristrune_table == null) + word_to_uristrune_table = list() + + var/bit = 1 + var/list/words = list("ire", "ego", "nahlizet", "certum", "veri", "jatkaa", "mgar", "balaq", "karazet", "geeri") + + while(length(words)) + var/w = pick(words) + + word_to_uristrune_table[w] = bit + + words -= w + bit <<= 1 + + return word_to_uristrune_table[word] + + + +/proc/get_uristrune_cult(word1, word2, word3) + var/animated + + if((word1 == cultwords["travel"] && word2 == cultwords["self"]) \ + || (word1 == cultwords["join"] && word2 == cultwords["blood"] && word3 == cultwords["self"]) \ + || (word1 == cultwords["hell"] && word2 == cultwords["join"] && word3 == cultwords["self"]) \ + || (word1 == cultwords["see"] && word2 == cultwords["blood"] && word3 == cultwords["hell"]) \ + || (word1 == cultwords["destroy"] && word2 == cultwords["see"] && word3 == cultwords["technology"]) \ + || (word1 == cultwords["travel"] && word2 == cultwords["blood"] && word3 == cultwords["self"]) \ + || (word1 == cultwords["see"] && word2 == cultwords["hell"] && word3 == cultwords["join"]) \ + || (word1 == cultwords["blood"] && word2 == cultwords["join"] && word3 == cultwords["hell"]) \ + || (word1 == cultwords["hide"] && word2 == cultwords["see"] && word3 == cultwords["blood"]) \ + || (word1 == cultwords["hell"] && word2 == cultwords["travel"] && word3 == cultwords["self"]) \ + || (word1 == cultwords["blood"] && word2 == cultwords["see"] && word3 == cultwords["travel"]) \ + || (word1 == cultwords["hell"] && word2 == cultwords["technology"] && word3 == cultwords["join"]) \ + || (word1 == cultwords["hell"] && word2 == cultwords["blood"] && word3 == cultwords["join"]) \ + || (word1 == cultwords["blood"] && word2 == cultwords["see"] && word3 == cultwords["hide"]) \ + || (word1 == cultwords["destroy"] && word2 == cultwords["travel"] && word3 == cultwords["self"]) \ + || (word1 == cultwords["travel"] && word2 == cultwords["technology"] && word3 == cultwords["other"]) \ + || (word1 == cultwords["join"] && word2 == cultwords["other"] && word3 == cultwords["self"]) \ + || (word1 == cultwords["hide"] && word2 == cultwords["other"] && word3 == cultwords["see"]) \ + || (word1 == cultwords["destroy"] && word2 == cultwords["see"] && word3 == cultwords["other"]) \ + || (word1 == cultwords["destroy"] && word2 == cultwords["see"] && word3 == cultwords["blood"]) \ + || (word1 == cultwords["self"] && word2 == cultwords["other"] && word3 == cultwords["technology"]) \ + || (word1 == cultwords["travel"] && word2 == cultwords["other"]) \ + || (word1 == cultwords["join"] && word2 == cultwords["hide"] && word3 == cultwords["technology"]) ) + animated = 1 + else + animated = 0 + + var/bits = word_to_uristrune_bit(word1) \ + | word_to_uristrune_bit(word2) \ + | word_to_uristrune_bit(word3) + + return get_uristrune(bits, animated) + + +var/list/uristrune_cache = list() + +/proc/get_uristrune(symbol_bits, animated = 0) + var/lookup = "[symbol_bits]-[animated]" + + if(lookup in uristrune_cache) + return uristrune_cache[lookup] + + var/icon/I = icon('icons/effects/uristrunes.dmi', "blank") + + for(var/i = 0, i < 10, i++) + if(BITTEST(symbol_bits, i)) + I.Blend(icon('icons/effects/uristrunes.dmi', "rune-[1 << i]"), ICON_OVERLAY) + + + I.SwapColor(rgb(0, 0, 0, 100), rgb(100, 0, 0, 200)) + I.SwapColor(rgb(0, 0, 0, 50), rgb(150, 0, 0, 200)) + + for(var/x = 1, x <= 32, x++) + for(var/y = 1, y <= 32, y++) + var/p = I.GetPixel(x, y) + + if(p == null) + var/n = I.GetPixel(x, y + 1) + var/s = I.GetPixel(x, y - 1) + var/e = I.GetPixel(x + 1, y) + var/w = I.GetPixel(x - 1, y) + + if(n == "#000000" || s == "#000000" || e == "#000000" || w == "#000000") + I.DrawBox(rgb(200, 0, 0, 200), x, y) + + else + var/ne = I.GetPixel(x + 1, y + 1) + var/se = I.GetPixel(x + 1, y - 1) + var/nw = I.GetPixel(x - 1, y + 1) + var/sw = I.GetPixel(x - 1, y - 1) + + if(ne == "#000000" || se == "#000000" || nw == "#000000" || sw == "#000000") + I.DrawBox(rgb(200, 0, 0, 100), x, y) + + var/icon/result = icon(I, "") + + result.Insert(I, "", frame = 1, delay = 10) + + if(animated == 1) + var/icon/I2 = icon(I, "") + I2.MapColors(rgb(0xff,0x0c,0,0), rgb(0,0,0,0), rgb(0,0,0,0), rgb(0,0,0,0xff)) + I2.SetIntensity(1.04) + + var/icon/I3 = icon(I, "") + I3.MapColors(rgb(0xff,0x18,0,0), rgb(0,0,0,0), rgb(0,0,0,0), rgb(0,0,0,0xff)) + I3.SetIntensity(1.08) + + var/icon/I4 = icon(I, "") + I4.MapColors(rgb(0xff,0x24,0,0), rgb(0,0,0,0), rgb(0,0,0,0), rgb(0,0,0,0xff)) + I4.SetIntensity(1.12) + + var/icon/I5 = icon(I, "") + I5.MapColors(rgb(0xff,0x30,0,0), rgb(0,0,0,0), rgb(0,0,0,0), rgb(0,0,0,0xff)) + I5.SetIntensity(1.16) + + result.Insert(I2, "", frame = 2, delay = 4) + result.Insert(I3, "", frame = 3, delay = 3) + result.Insert(I4, "", frame = 4, delay = 2) + result.Insert(I5, "", frame = 5, delay = 6) + result.Insert(I4, "", frame = 6, delay = 2) + result.Insert(I3, "", frame = 7, delay = 2) + result.Insert(I2, "", frame = 8, delay = 2) + + uristrune_cache[lookup] = result + + return result diff --git a/code/game/magic/archived_book.dm b/code/game/magic/archived_book.dm new file mode 100644 index 00000000..6a442281 --- /dev/null +++ b/code/game/magic/archived_book.dm @@ -0,0 +1,126 @@ +//This file was auto-corrected by findeclaration.exe on 29/05/2012 15:03:04 + +#define BOOK_VERSION_MIN 1 +#define BOOK_VERSION_MAX 2 +#define BOOK_PATH "data/books/" +#define BOOKS_USE_SQL 0 // no guarentee for this branch to work right with sql + +var/global/datum/book_manager/book_mgr = new() + +datum/book_manager/proc/path(id) + if(isnum(id)) // kill any path exploits + return "[BOOK_PATH][id].sav" + +datum/book_manager/proc/getall() + var/list/paths = flist(BOOK_PATH) + var/list/books = new() + + for(var/path in paths) + var/datum/archived_book/B = new(BOOK_PATH + path) + books += B + + return books + +datum/book_manager/proc/freeid() + var/list/paths = flist(BOOK_PATH) + var/id = paths.len + 101 + + // start at 101+number of books, which will be correct id if none have been deleted, etc + // otherwise, keep moving forward until we find an open id + while(fexists(path(id))) + id++ + + return id + +/client/proc/delbook() + set name = "Delete Book" + set desc = "Permamently deletes a book from the database." + set category = "Admin" + if(!src.holder) + to_chat(src, "Only administrators may use this command.") + return + + var/isbn = input("ISBN number?", "Delete Book") as num | null + if(!isbn) + return + + if(BOOKS_USE_SQL && config.sql_enabled) + var/DBConnection/dbcon = new() + dbcon.Connect("dbi:mysql:[sqldb]:[sqladdress]:[sqlport]","[sqllogin]","[sqlpass]") + if(!dbcon.IsConnected()) + alert("Connection to Archive has been severed. Aborting.") + else + var/DBQuery/query = dbcon.NewQuery("DELETE FROM library WHERE id=[isbn]") + if(!query.Execute()) + to_chat(usr, query.ErrorMsg()) + dbcon.Disconnect() + else + book_mgr.remove(isbn) + log_admin("[usr.key] has deleted the book [isbn]") + +// delete a book +datum/book_manager/proc/remove(var/id) + fdel(path(id)) + +datum/archived_book + var/author // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned + var/title // The real name of the book. + var/category // The category/genre of the book + var/id // the id of the book (like an isbn number) + var/dat // Actual page content + + var/author_real // author's real_name + var/author_key // author's byond key + var/list/icon/photos // in-game photos used + +// loads the book corresponding by the specified id +datum/archived_book/New(var/path) + if(isnull(path)) + return + + var/savefile/F = new(path) + + var/version + F["version"] >> version + + if (isnull(version) || version < BOOK_VERSION_MIN || version > BOOK_VERSION_MAX) + fdel(path) + to_chat(usr, "What book?") + return 0 + + F["author"] >> author + F["title"] >> title + F["category"] >> category + F["id"] >> id + F["dat"] >> dat + + F["author_real"] >> author_real + F["author_key"] >> author_key + F["photos"] >> photos + if(!photos) + photos = new() + + // let's sanitize it here too! + for(var/tag in paper_blacklist) + if(findtext(dat,"<"+tag)) + dat = "" + return + + +datum/archived_book/proc/save() + var/savefile/F = new(book_mgr.path(id)) + + F["version"] << BOOK_VERSION_MAX + F["author"] << author + F["title"] << title + F["category"] << category + F["id"] << id + F["dat"] << dat + + F["author_real"] << author_real + F["author_key"] << author_key + F["photos"] << photos + +#undef BOOK_VERSION_MIN +#undef BOOK_VERSION_MAX +#undef BOOK_PATH diff --git a/code/game/mecha/combat/combat.dm b/code/game/mecha/combat/combat.dm new file mode 100644 index 00000000..47d0b44f --- /dev/null +++ b/code/game/mecha/combat/combat.dm @@ -0,0 +1,242 @@ +/obj/mecha/combat + force = 30 + var/melee_cooldown = 10 + var/melee_can_hit = 1 + var/list/destroyable_obj = list(/obj/mecha, /obj/structure/window, /obj/structure/grille, /turf/simulated/wall) + internal_damage_threshold = 50 + maint_access = 0 + //add_req_access = 0 + //operation_req_access = list(access_hos) + damage_absorption = list("brute"=0.7,"fire"=1,"bullet"=0.7,"laser"=0.85,"energy"=1,"bomb"=0.8) + var/am = "d3c2fbcadca903a41161ccc9df9cf948" + +/* +/obj/mecha/combat/range_action(target as obj|mob|turf) + if(internal_damage&MECHA_INT_CONTROL_LOST) + target = pick(view(3,target)) + if(selected_weapon) + selected_weapon.fire(target) + return +*/ + +/obj/mecha/combat/melee_action(target as obj|mob|turf) + if(internal_damage&MECHA_INT_CONTROL_LOST) + target = safepick(oview(1,src)) + if(!melee_can_hit || !istype(target, /atom)) return + if(istype(target, /mob/living)) + var/mob/living/M = target + if(src.occupant.a_intent == I_HURT) + playsound(src, 'sound/weapons/punch_04.ogg', 50, 1) + if(damtype == "brute") + step_away(M,src,15) + /* + if(M.stat>1) + M.gib() + melee_can_hit = 0 + if(do_after(melee_cooldown)) + melee_can_hit = 1 + return + */ + + var/hit_zone = ran_zone() + switch(damtype) + if("brute") + var/blocked = M.run_armor_check(hit_zone, "melee") + if(M.apply_damage(rand(force/2, force), BRUTE, hit_zone, blocked)) + M.Weaken(1) + if("fire") + var/blocked = M.run_armor_check(hit_zone, "energy") + M.apply_damage(rand(force/2, force), BRUTE, hit_zone, blocked) + if("tox") + if(M.reagents) + if(M.reagents.get_reagent_amount(/datum/reagent/toxin/carpotoxin) + force < force*2) + M.reagents.add_reagent(/datum/reagent/toxin/carpotoxin, force) + if(M.reagents.get_reagent_amount(/datum/reagent/cryptobiolin) + force < force*2) + M.reagents.add_reagent(/datum/reagent/cryptobiolin, force) + + src.occupant_message("You hit [target].") + src.visible_message("[src.name] hits [target].") + else + step_away(M,src) + src.occupant_message("You push [target] out of the way.") + src.visible_message("[src] pushes [target] out of the way.") + + melee_can_hit = 0 + if(do_after(melee_cooldown)) + melee_can_hit = 1 + return + + else + if(damtype == "brute") + for(var/target_type in src.destroyable_obj) + if(istype(target, target_type) && hascall(target, "attackby")) + src.occupant_message("You hit [target].") + src.visible_message("[src.name] hits [target]") + if(!istype(target, /turf/simulated/wall)) + target:attackby(src,src.occupant) + else if(prob(5)) + target:dismantle_wall(1) + src.occupant_message("You smash through the wall.") + src.visible_message("[src.name] smashes through the wall") + playsound(src, 'sound/weapons/smash.ogg', 50, 1) + melee_can_hit = 0 + if(do_after(melee_cooldown)) + melee_can_hit = 1 + break + return + +/* +/obj/mecha/combat/proc/mega_shake(target) + if(!istype(target, /obj) && !istype(target, /mob)) return + if(istype(target, /mob)) + var/mob/M = target + M.make_dizzy(3) + M.adjustBruteLoss(1) + M.updatehealth() + for (var/mob/V in viewers(src)) + V.show_message("[src.name] shakes [M] like a rag doll.") + return +*/ + +/* + if(energy>0 && can_move) + if(step(src,direction)) + can_move = 0 + spawn(step_in) can_move = 1 + if(overload) + energy = energy-2 + health-- + else + energy-- + return 1 + + return 0 +*/ +/* +/obj/mecha/combat/hear_talk(mob/M as mob, text) + ..() + if(am && M==occupant) + if(findtext(text,"")) + sam() + return + +/obj/mecha/combat/proc/sam() + if(am) + var/window = {" + + + + + +
            +
            + + +
            +
            + + + "} + occupant << browse(window, "window=sam;size=800x600;") + onclose(occupant, "sam", src) + return +*/ +/obj/mecha/combat/moved_inside(var/mob/living/carbon/human/H as mob) + if(..()) + if(H.client) + H.client.mouse_pointer_icon = file("icons/mecha/mecha_mouse.dmi") + return 1 + else + return 0 + +/obj/mecha/combat/go_out() + if(src.occupant && src.occupant.client) + src.occupant.client.mouse_pointer_icon = initial(src.occupant.client.mouse_pointer_icon) + ..() + return + +/obj/mecha/combat/Topic(href,href_list) + ..() + var/datum/topic_input/F = new (href,href_list) + if(F.get("close")) + am = null + return + /* + if(filter.get("saminput")) + if(md5(filter.get("saminput")) == am) + occupant_message("From the lies of the Antipath, Circuit preserve us.") + am = null + return + */ diff --git a/code/game/mecha/combat/durand.dm b/code/game/mecha/combat/durand.dm new file mode 100644 index 00000000..a5ba3137 --- /dev/null +++ b/code/game/mecha/combat/durand.dm @@ -0,0 +1,74 @@ +/obj/mecha/combat/durand + desc = "An aging combat exosuit utilized by many corporations. Originally developed to combat hostile alien lifeforms." + name = "Durand" + icon_state = "durand" + initial_icon = "durand" + step_in = 4 + health = 400 + deflect_chance = 20 + damage_absorption = list("brute"=0.5,"fire"=1.1,"bullet"=0.65,"laser"=0.85,"energy"=0.9,"bomb"=0.8) + max_temperature = 30000 + infra_luminosity = 8 + force = 40 + var/defence = 0 + var/def_boost = 15 + wreckage = /obj/effect/decal/mecha_wreckage/durand + +/* +/obj/mecha/combat/durand/New() + ..() + weapons += new /datum/mecha_weapon/ballistic/lmg(src) + weapons += new /datum/mecha_weapon/ballistic/scattershot(src) + selected_weapon = weapons[1] + return +*/ + +/obj/mecha/combat/durand/relaymove(mob/user,direction) + if(defence) + if(world.time - last_message > 20) + src.occupant_message("Unable to move while in defence mode") + last_message = world.time + return 0 + . = ..() + return + + +/obj/mecha/combat/durand/verb/defence_mode() + set category = "Exosuit Interface" + set name = "Toggle defence mode" + set src = usr.loc + set popup_menu = 0 + if(usr!=src.occupant) + return + defence = !defence + if(defence) + deflect_chance += def_boost + src.occupant_message("You enable [src] defence mode.") + else + deflect_chance -= def_boost + src.occupant_message("You disable [src] defence mode.") + src.log_message("Toggled defence mode.") + return + + +/obj/mecha/combat/durand/get_stats_part() + var/output = ..() + output += "Defence mode: [defence?"on":"off"]" + return output + +/obj/mecha/combat/durand/get_commands() + var/output = {"
            +
            Special
            + +
            + "} + output += ..() + return output + +/obj/mecha/combat/durand/Topic(href, href_list) + ..() + if (href_list["toggle_defence_mode"]) + src.defence_mode() + return \ No newline at end of file diff --git a/code/game/mecha/combat/gygax.dm b/code/game/mecha/combat/gygax.dm new file mode 100644 index 00000000..6a7819dc --- /dev/null +++ b/code/game/mecha/combat/gygax.dm @@ -0,0 +1,100 @@ +/obj/mecha/combat/gygax + desc = "A lightweight, security exosuit. Popular among private and corporate security." + name = "Gygax" + icon_state = "gygax" + initial_icon = "gygax" + step_in = 3 + dir_in = 1 //Facing North. + health = 300 + deflect_chance = 15 + damage_absorption = list("brute"=0.75,"fire"=1,"bullet"=0.8,"laser"=0.7,"energy"=0.85,"bomb"=1) + max_temperature = 25000 + infra_luminosity = 6 + var/overload = 0 + var/overload_coeff = 2 + wreckage = /obj/effect/decal/mecha_wreckage/gygax + internal_damage_threshold = 35 + max_equip = 3 + +/obj/mecha/combat/gygax/dark + desc = "A lightweight exosuit used by Heavy Asset Protection. A significantly upgraded Gygax security mech." + name = "Dark Gygax" + icon_state = "darkgygax" + initial_icon = "darkgygax" + health = 400 + deflect_chance = 25 + damage_absorption = list("brute"=0.6,"fire"=0.8,"bullet"=0.6,"laser"=0.5,"energy"=0.65,"bomb"=0.8) + max_temperature = 45000 + overload_coeff = 1 + wreckage = /obj/effect/decal/mecha_wreckage/gygax/dark + max_equip = 4 + step_energy_drain = 5 + +/obj/mecha/combat/gygax/dark/New() + ..() + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang/clusterbang + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/teleporter + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay + ME.attach(src) + return + +/obj/mecha/combat/gygax/dark/add_cell() + cell = new /obj/item/weapon/cell/hyper(src) + +/obj/mecha/combat/gygax/verb/overload() + set category = "Exosuit Interface" + set name = "Toggle leg actuators overload" + set src = usr.loc + set popup_menu = 0 + if(usr!=src.occupant) + return + if(overload) + overload = 0 + step_in = initial(step_in) + step_energy_drain = initial(step_energy_drain) + src.occupant_message("You disable leg actuators overload.") + else + overload = 1 + step_in = min(1, round(step_in/2)) + step_energy_drain = step_energy_drain*overload_coeff + src.occupant_message("You enable leg actuators overload.") + src.log_message("Toggled leg actuators overload.") + return + +/obj/mecha/combat/gygax/do_move(direction) + if(!..()) return + if(overload) + health-- + if(health < initial(health) - initial(health)/3) + overload = 0 + step_in = initial(step_in) + step_energy_drain = initial(step_energy_drain) + src.occupant_message("Leg actuators damage threshold exceded. Disabling overload.") + return + + +/obj/mecha/combat/gygax/get_stats_part() + var/output = ..() + output += "Leg actuators overload: [overload?"on":"off"]" + return output + +/obj/mecha/combat/gygax/get_commands() + var/output = {"
            +
            Special
            + +
            + "} + output += ..() + return output + +/obj/mecha/combat/gygax/Topic(href, href_list) + ..() + if (href_list["toggle_leg_overload"]) + src.overload() + return \ No newline at end of file diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm new file mode 100644 index 00000000..fd914926 --- /dev/null +++ b/code/game/mecha/combat/marauder.dm @@ -0,0 +1,216 @@ +/obj/mecha/combat/marauder + desc = "Heavy-duty, combat exosuit, developed after the Durand model. Rarely found among civilian populations." + name = "Marauder" + icon_state = "marauder" + initial_icon = "marauder" + step_in = 5 + health = 500 + deflect_chance = 25 + damage_absorption = list("brute"=0.5,"fire"=0.7,"bullet"=0.45,"laser"=0.6,"energy"=0.7,"bomb"=0.7) + max_temperature = 60000 + infra_luminosity = 3 + var/zoom = 0 + var/thrusters = 0 + var/smoke = 5 + var/smoke_ready = 1 + var/smoke_cooldown = 100 + var/datum/effect/effect/system/smoke_spread/smoke_system = new + operation_req_access = list(access_cent_specops) + wreckage = /obj/effect/decal/mecha_wreckage/marauder + add_req_access = 0 + internal_damage_threshold = 25 + force = 45 + max_equip = 4 + +/obj/mecha/combat/marauder/seraph + desc = "Heavy-duty, command-type exosuit. This is a custom model, utilized only by high-ranking military personnel." + name = "Seraph" + icon_state = "seraph" + initial_icon = "seraph" + operation_req_access = list(access_cent_creed) + step_in = 3 + health = 550 + wreckage = /obj/effect/decal/mecha_wreckage/seraph + internal_damage_threshold = 20 + force = 55 + max_equip = 5 + +/obj/mecha/combat/marauder/mauler + desc = "Heavy-duty, combat exosuit, developed off of the existing Marauder model." + name = "Mauler" + icon_state = "mauler" + initial_icon = "mauler" + operation_req_access = list(access_syndicate) + wreckage = /obj/effect/decal/mecha_wreckage/mauler + +/obj/mecha/combat/marauder/New() + ..() + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/explosive + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/armor_booster/antiproj_armor_booster(src) + ME.attach(src) + src.smoke_system.set_up(3, 0, src) + src.smoke_system.attach(src) + return + +/obj/mecha/combat/marauder/seraph/New() + ..()//Let it equip whatever is needed. + var/obj/item/mecha_parts/mecha_equipment/ME + if(equipment.len)//Now to remove it and equip anew. + for(ME in equipment) + ME.detach(src) + qdel(ME) + ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/explosive(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/teleporter(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/armor_booster/antiproj_armor_booster(src) + ME.attach(src) + return + +/obj/mecha/combat/marauder/Destroy() + qdel(smoke_system) + ..() + +/obj/mecha/combat/marauder/relaymove(mob/user,direction) + if(user != src.occupant) //While not "realistic", this piece is player friendly. + user.loc = get_turf(src) + to_chat(user, "You climb out from [src]") + return 0 + if(!can_move) + return 0 + if(zoom) + if(world.time - last_message > 20) + src.occupant_message("Unable to move while in zoom mode.") + last_message = world.time + return 0 + if(connected_port) + if(world.time - last_message > 20) + src.occupant_message("Unable to move while connected to the air system port") + last_message = world.time + return 0 + if(!thrusters && src.pr_inertial_movement.active()) + return 0 + if(state || !has_charge(step_energy_drain)) + return 0 + var/tmp_step_in = step_in + var/tmp_step_energy_drain = step_energy_drain + var/move_result = 0 + if(internal_damage&MECHA_INT_CONTROL_LOST) + move_result = mechsteprand() + else if(src.dir!=direction) + move_result = mechturn(direction) + else + move_result = mechstep(direction) + if(move_result) + if(istype(src.loc, /turf/space)) + if(!src.check_for_support()) + src.pr_inertial_movement.start(list(src,direction)) + if(thrusters) + src.pr_inertial_movement.set_process_args(list(src,direction)) + tmp_step_energy_drain = step_energy_drain*2 + + can_move = 0 + spawn(tmp_step_in) can_move = 1 + use_power(tmp_step_energy_drain) + return 1 + return 0 + + +/obj/mecha/combat/marauder/verb/toggle_thrusters() + set category = "Exosuit Interface" + set name = "Toggle thrusters" + set src = usr.loc + set popup_menu = 0 + if(usr!=src.occupant) + return + if(src.occupant) + if(get_charge() > 0) + thrusters = !thrusters + src.log_message("Toggled thrusters.") + src.occupant_message("Thrusters [thrusters?"en":"dis"]abled.") + return + + +/obj/mecha/combat/marauder/verb/smoke() + set category = "Exosuit Interface" + set name = "Smoke" + set src = usr.loc + set popup_menu = 0 + if(usr!=src.occupant) + return + if(smoke_ready && smoke>0) + src.smoke_system.start() + smoke-- + smoke_ready = 0 + spawn(smoke_cooldown) + smoke_ready = 1 + return + +//TODO replace this with zoom code that doesn't increase peripherial vision +/obj/mecha/combat/marauder/verb/zoom() + set category = "Exosuit Interface" + set name = "Zoom" + set src = usr.loc + set popup_menu = 0 + if(usr!=src.occupant) + return + if(src.occupant.client) + src.zoom = !src.zoom + src.log_message("Toggled zoom mode.") + src.occupant_message("Zoom mode [zoom?"en":"dis"]abled.") + if(zoom) + src.occupant.client.view = 12 + sound_to(src.occupant, sound('sound/mecha/imag_enh.ogg',volume=50)) + else + src.occupant.client.view = world.view//world.view - default mob view size + return + + +/obj/mecha/combat/marauder/go_out() + if(src.occupant && src.occupant.client) + src.occupant.client.view = world.view + src.zoom = 0 + ..() + return + + +/obj/mecha/combat/marauder/get_stats_part() + var/output = ..() + output += {"Smoke: [smoke] +
            + Thrusters: [thrusters?"on":"off"] + "} + return output + + +/obj/mecha/combat/marauder/get_commands() + var/output = {"
            +
            Special
            + +
            + "} + output += ..() + return output + +/obj/mecha/combat/marauder/Topic(href, href_list) + ..() + if (href_list["toggle_thrusters"]) + src.toggle_thrusters() + if (href_list["smoke"]) + src.smoke() + if (href_list["toggle_zoom"]) + src.zoom(usr) + return diff --git a/code/game/mecha/combat/phazon.dm b/code/game/mecha/combat/phazon.dm new file mode 100644 index 00000000..5fa7a11a --- /dev/null +++ b/code/game/mecha/combat/phazon.dm @@ -0,0 +1,91 @@ +/obj/mecha/combat/phazon + desc = "An exosuit which can only be described as 'WTF?'." + name = "Phazon" + icon_state = "phazon" + initial_icon = "phazon" + step_in = 1 + dir_in = 1 //Facing North. + step_energy_drain = 100 + health = 200 + deflect_chance = 30 + damage_absorption = list("brute"=0.7,"fire"=0.7,"bullet"=0.7,"laser"=0.7,"energy"=0.7,"bomb"=0.7) + max_temperature = 25000 + infra_luminosity = 3 + wreckage = /obj/effect/decal/mecha_wreckage/phazon + add_req_access = 1 + //operation_req_access = list() + internal_damage_threshold = 25 + force = 15 + var/phasing = 0 + var/phasing_energy_drain = 5 KILOWATTS + max_equip = 4 + + +/obj/mecha/combat/phazon/New() + ..() + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/tool/rcd + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/gravcatapult + ME.attach(src) + return + +/obj/mecha/combat/phazon/Bump(var/atom/obstacle) + if(phasing && get_charge()>=phasing_energy_drain) + spawn() + if(can_move) + can_move = 0 + flick("phazon-phase", src) + src.loc = get_step(src,src.dir) + src.use_power(phasing_energy_drain) + sleep(step_in*3) + can_move = 1 + else + . = ..() + return + +/obj/mecha/combat/phazon/click_action(atom/target,mob/user) + if(phasing) + src.occupant_message("Unable to interact with objects while phasing") + return + else + return ..() + +/obj/mecha/combat/phazon/verb/switch_damtype() + set category = "Exosuit Interface" + set name = "Change melee damage type" + set src = usr.loc + set popup_menu = 0 + if(usr!=src.occupant) + return + var/new_damtype = alert(src.occupant,"Melee Damage Type",null,"Brute","Fire","Toxic") + switch(new_damtype) + if("Brute") + damtype = "brute" + if("Fire") + damtype = "fire" + if("Toxic") + damtype = "tox" + src.occupant_message("Melee damage type switched to [new_damtype ]") + return + +/obj/mecha/combat/phazon/get_commands() + var/output = {" + "} + output += ..() + return output + +/obj/mecha/combat/phazon/Topic(href, href_list) + ..() + if (href_list["switch_damtype"]) + src.switch_damtype() + if (href_list["phasing"]) + phasing = !phasing + send_byjax(src.occupant,"exosuit.browser","phasing_command","[phasing?"Dis":"En"]able phasing") + src.occupant_message("En":"#f00\">Dis"]abled phasing.") + return \ No newline at end of file diff --git a/code/game/mecha/equipment/mecha_equipment.dm b/code/game/mecha/equipment/mecha_equipment.dm new file mode 100644 index 00000000..df25ded6 --- /dev/null +++ b/code/game/mecha/equipment/mecha_equipment.dm @@ -0,0 +1,146 @@ +//DO NOT ADD MECHA PARTS TO THE GAME WITH THE DEFAULT "SPRITE ME" SPRITE! +//I'm annoyed I even have to tell you this! SPRITE FIRST, then commit. + +/obj/item/mecha_parts/mecha_equipment + name = "mecha equipment" + icon = 'icons/mecha/mecha_equipment.dmi' + icon_state = "mecha_equip" + force = 5 + origin_tech = list(TECH_MATERIAL = 2) + var/equip_cooldown = 0 + var/equip_ready = 1 + var/energy_drain = 0 + var/obj/mecha/chassis = null + var/range = MELEE //bitflags + var/salvageable = 1 + var/required_type = /obj/mecha //may be either a type or a list of allowed types + + +/obj/item/mecha_parts/mecha_equipment/proc/do_after_cooldown(target=1) + sleep(equip_cooldown) + set_ready_state(1) + if(target && chassis) + return 1 + return 0 + +/obj/item/mecha_parts/mecha_equipment/New() + ..() + return + +/obj/item/mecha_parts/mecha_equipment/proc/update_chassis_page() + if(chassis) + send_byjax(chassis.occupant,"exosuit.browser","eq_list",chassis.get_equipment_list()) + send_byjax(chassis.occupant,"exosuit.browser","equipment_menu",chassis.get_equipment_menu(),"dropdowns") + return 1 + return + +/obj/item/mecha_parts/mecha_equipment/proc/update_equip_info() + if(chassis) + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",get_equip_info()) + return 1 + return + +/obj/item/mecha_parts/mecha_equipment/proc/destroy()//missiles detonating, teleporter creating singularity? + if(chassis) + chassis.equipment -= src + listclearnulls(chassis.equipment) + if(chassis.selected == src) + chassis.selected = null + src.update_chassis_page() + chassis.occupant_message("The [src] is destroyed!") + chassis.log_append_to_last("[src] is destroyed.",1) + if(istype(src, /obj/item/mecha_parts/mecha_equipment/weapon)) + sound_to(chassis.occupant, sound('sound/mecha/weapdestr.ogg',volume=50)) + else + sound_to(chassis.occupant, sound('sound/mecha/critdestr.ogg',volume=50)) + spawn + qdel(src) + return + +/obj/item/mecha_parts/mecha_equipment/proc/critfail() + if(chassis) + log_message("Critical failure",1) + return + +/obj/item/mecha_parts/mecha_equipment/proc/get_equip_info() + if(!chassis) return + return "* [chassis.selected==src?"":""][src.name][chassis.selected==src?"":""]" + +/obj/item/mecha_parts/mecha_equipment/proc/is_ranged()//add a distance restricted equipment. Why not? + return range&RANGED + +/obj/item/mecha_parts/mecha_equipment/proc/is_melee() + return range&MELEE + + +/obj/item/mecha_parts/mecha_equipment/proc/action_checks(atom/target) + if(!target) + return 0 + if(!chassis) + return 0 + if(!equip_ready) + return 0 + if(energy_drain && !chassis.has_charge(energy_drain)) + return 0 + return 1 + +/obj/item/mecha_parts/mecha_equipment/proc/action(atom/target) + return + +/obj/item/mecha_parts/mecha_equipment/proc/can_attach(obj/mecha/M as obj) + if(M.equipment.len >= M.max_equip) + return 0 + + if (ispath(required_type)) + return istype(M, required_type) + + for (var/path in required_type) + if (istype(M, path)) + return 1 + + return 0 + +/obj/item/mecha_parts/mecha_equipment/proc/attach(obj/mecha/M as obj) + M.equipment += src + chassis = M + src.loc = M + M.log_message("[src] initialized.") + if(!M.selected) + M.selected = src + src.update_chassis_page() + return + +/obj/item/mecha_parts/mecha_equipment/proc/detach(atom/moveto=null) + moveto = moveto || get_turf(chassis) + if(src.Move(moveto)) + chassis.equipment -= src + if(chassis.selected == src) + chassis.selected = null + update_chassis_page() + chassis.log_message("[src] removed from equipment.") + chassis = null + set_ready_state(1) + return + + +/obj/item/mecha_parts/mecha_equipment/Topic(href,href_list) + if(href_list["detach"]) + src.detach() + return + + +/obj/item/mecha_parts/mecha_equipment/proc/set_ready_state(state) + equip_ready = state + if(chassis) + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + return + +/obj/item/mecha_parts/mecha_equipment/proc/occupant_message(message) + if(chassis) + chassis.occupant_message("\icon[src] [message]") + return + +/obj/item/mecha_parts/mecha_equipment/proc/log_message(message) + if(chassis) + chassis.log_message("[src]: [message]") + return diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm new file mode 100644 index 00000000..78e547ac --- /dev/null +++ b/code/game/mecha/equipment/tools/medical_tools.dm @@ -0,0 +1,494 @@ +/obj/item/mecha_parts/mecha_equipment/tool/sleeper + name = "mounted sleeper" + desc = "A sleeper. Mountable to an exosuit. (Can be attached to: Medical Exosuits)" + icon = 'icons/obj/Cryogenic2.dmi' + icon_state = "sleeper_0" + origin_tech = list(TECH_DATA = 2, TECH_BIO = 3) + energy_drain = 20 + range = MELEE + equip_cooldown = 20 + var/mob/living/carbon/occupant = null + var/datum/global_iterator/pr_mech_sleeper + var/inject_amount = 10 + required_type = /obj/mecha/medical + salvageable = 0 + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/New() + ..() + pr_mech_sleeper = new /datum/global_iterator/mech_sleeper(list(src),0) + pr_mech_sleeper.set_delay(equip_cooldown) + return + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/Destroy() + qdel(pr_mech_sleeper) + for(var/atom/movable/AM in src) + AM.forceMove(get_turf(src)) + return ..() + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/Exit(atom/movable/O) + return 0 + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/action(var/mob/living/carbon/target) + if(!action_checks(target)) + return + if(!istype(target)) + return + if(target.buckled) + occupant_message("[target] will not fit into the sleeper because they are buckled to [target.buckled].") + return + if(occupant) + occupant_message("The sleeper is already occupied") + return + for(var/mob/living/carbon/slime/M in range(1,target)) + if(M.Victim == target) + occupant_message("[target] will not fit into the sleeper because they have a slime latched onto their head.") + return + occupant_message("You start putting [target] into [src].") + chassis.visible_message("[chassis] starts putting [target] into the [src].") + var/C = chassis.loc + var/T = target.loc + if(do_after_cooldown(target)) + if(chassis.loc!=C || target.loc!=T) + return + if(occupant) + occupant_message("The sleeper is already occupied!") + return + target.forceMove(src) + occupant = target + target.reset_view(src) + set_ready_state(0) + pr_mech_sleeper.start() + occupant_message("[target] successfully loaded into [src]. Life support functions engaged.") + chassis.visible_message("[chassis] loads [target] into [src].") + log_message("[target] loaded. Life support functions engaged.") + return + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/relaymove(mob, direct) + go_out() + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/go_out() + if(!occupant) + return + occupant.forceMove(get_turf(src)) + occupant_message("[occupant] ejected. Life support functions disabled.") + log_message("[occupant] ejected. Life support functions disabled.") + occupant.reset_view() + occupant = null + pr_mech_sleeper.stop() + set_ready_state(1) + return + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/detach() + if(occupant) + occupant_message("Unable to detach [src] - equipment occupied.") + return + pr_mech_sleeper.stop() + return ..() + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/get_equip_info() + var/output = ..() + if(output) + var/temp = "" + if(occupant) + temp = "
            \[Occupant: [occupant] (Health: [occupant.health]%)\]
            View stats|Eject" + return "[output] [temp]" + return + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/Topic(href,href_list) + ..() + var/datum/topic_input/F = new /datum/topic_input(href,href_list) + if(F.get("eject")) + go_out() + if(F.get("view_stats")) + chassis.occupant << browse(get_occupant_stats(),"window=msleeper") + onclose(chassis.occupant, "msleeper") + return + if(F.get("inject")) + inject_reagent(F.getType("inject",/datum/reagent),F.getObj("source")) + return + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_stats() + if(!occupant) + return + return {" + + [occupant] statistics + + + + +

            Health statistics

            +
            + [get_occupant_dam()] +
            +

            Reagents in bloodstream

            +
            + [get_occupant_reagents()] +
            +
            + [get_available_reagents()] +
            + + "} + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_dam() + var/t1 + switch(occupant.stat) + if(0) + t1 = "Conscious" + if(1) + t1 = "Unconscious" + if(2) + t1 = "*dead*" + else + t1 = "Unknown" + return {"Health: [occupant.health]% ([t1])
            + Core Temperature: [src.occupant.bodytemperature-T0C]°C ([src.occupant.bodytemperature*1.8-459.67]°F)
            + Brute Damage: [occupant.getBruteLoss()]%
            + Respiratory Damage: [occupant.getOxyLoss()]%
            + Toxin Content: [occupant.getToxLoss()]%
            + Burn Severity: [occupant.getFireLoss()]%
            + "} + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_reagents() + if(occupant.reagents) + for(var/datum/reagent/R in occupant.reagents.reagent_list) + if(R.volume > 0) + . += "[R]: [round(R.volume,0.01)]
            " + return . || "None" + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_available_reagents() + var/output + var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/SG = locate(/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun) in chassis + if(SG && SG.reagents && islist(SG.reagents.reagent_list)) + for(var/datum/reagent/R in SG.reagents.reagent_list) + if(R.volume > 0) + output += "Inject [R.name]
            " + return output + + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/inject_reagent(var/datum/reagent/R,var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/SG) + if(!R || !occupant || !SG || !(SG in chassis.equipment)) + return 0 + var/to_inject = min(R.volume, inject_amount) + if(to_inject && occupant.reagents.get_reagent_amount(R.type) + to_inject <= inject_amount*2) + occupant_message("Injecting [occupant] with [to_inject] units of [R.name].") + log_message("Injecting [occupant] with [to_inject] units of [R.name].") + SG.reagents.trans_type_to(occupant,R.type,to_inject) + update_equip_info() + return + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/update_equip_info() + if(..()) + send_byjax(chassis.occupant,"msleeper.browser","lossinfo",get_occupant_dam()) + send_byjax(chassis.occupant,"msleeper.browser","reagents",get_occupant_reagents()) + send_byjax(chassis.occupant,"msleeper.browser","injectwith",get_available_reagents()) + return 1 + return + +/datum/global_iterator/mech_sleeper + +/datum/global_iterator/mech_sleeper/process(var/obj/item/mecha_parts/mecha_equipment/tool/sleeper/S) + if(!S.chassis) + S.set_ready_state(1) + return stop() + if(!S.chassis.has_charge(S.energy_drain)) + S.set_ready_state(1) + S.log_message("Deactivated.") + S.occupant_message("[src] deactivated - no power.") + return stop() + var/mob/living/carbon/M = S.occupant + if(!M) + return + if(M.health > 0) + M.adjustOxyLoss(-1) + M.updatehealth() + M.AdjustStunned(-4) + M.AdjustWeakened(-4) + M.AdjustStunned(-4) + if(M.reagents.get_reagent_amount(/datum/reagent/inaprovaline) < 5) + M.reagents.add_reagent(/datum/reagent/inaprovaline, 5) + S.chassis.use_power(S.energy_drain) + S.update_equip_info() + return + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun + name = "syringe gun" + desc = "Exosuit-mounted chem synthesizer with syringe gun. Reagents inside are held in stasis, so no reactions will occur. (Can be attached to: Medical Exosuits)" + icon = 'icons/obj/gun.dmi' + icon_state = "syringegun" + var/list/syringes + var/list/known_reagents + var/list/processed_reagents + var/max_syringes = 10 + var/max_volume = 75 //max reagent volume + var/synth_speed = 5 //[num] reagent units per cycle + energy_drain = 2 KILOWATTS // Synthetises things, so it's quite power-hungry + var/mode = 0 //0 - fire syringe, 1 - analyze reagents. + var/datum/global_iterator/mech_synth/synth + range = MELEE|RANGED + equip_cooldown = 10 + origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4, TECH_MAGNET = 4, TECH_DATA = 3) + required_type = /obj/mecha/medical + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/New() + ..() + atom_flags |= ATOM_FLAG_NO_REACT + syringes = new + known_reagents = list(/datum/reagent/inaprovaline="Inaprovaline",/datum/reagent/dylovene="Dylovene") + processed_reagents = new + create_reagents(max_volume) + synth = new (list(src),0) + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/detach() + synth.stop() + return ..() + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/critfail() + ..() + atom_flags &= ~ATOM_FLAG_NO_REACT + return + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/get_equip_info() + var/output = ..() + if(output) + return "[output] \[[mode? "Analyze" : "Launch"]\]
            \[Syringes: [syringes.len]/[max_syringes] | Reagents: [reagents.total_volume]/[reagents.maximum_volume]\]
            Reagents list" + return + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/action(atom/movable/target) + if(!action_checks(target)) + return + if(istype(target,/obj/item/weapon/reagent_containers/syringe)) + return load_syringe(target) + if(istype(target,/obj/item/weapon/storage))//Loads syringes from boxes + for(var/obj/item/weapon/reagent_containers/syringe/S in target.contents) + load_syringe(S) + return + if(mode) + return analyze_reagents(target) + if(!syringes.len) + occupant_message("No syringes loaded.") + return + if(reagents.total_volume<=0) + occupant_message("No available reagents to load syringe with.") + return + set_ready_state(0) + chassis.use_power(energy_drain) + var/turf/trg = get_turf(target) + var/obj/item/weapon/reagent_containers/syringe/S = syringes[1] + S.forceMove(get_turf(chassis)) + reagents.trans_to_obj(S, min(S.volume, reagents.total_volume)) + syringes -= S + S.icon = 'icons/obj/chemical.dmi' + S.icon_state = "syringeproj" + playsound(chassis, 'sound/items/syringeproj.ogg', 50, 1) + log_message("Launched [S] from [src], targeting [target].") + spawn(-1) + src = null //if src is deleted, still process the syringe + for(var/i=0, i<6, i++) + if(!S) + break + if(step_towards(S,trg)) + var/list/mobs = new + for(var/mob/living/carbon/M in S.loc) + mobs += M + var/mob/living/carbon/M = safepick(mobs) + if(M) + S.icon_state = initial(S.icon_state) + S.icon = initial(S.icon) + S.reagents.trans_to_mob(M, S.reagents.total_volume, CHEM_BLOOD) + M.take_organ_damage(2) + S.visible_message(" [M] was hit by the syringe!") + break + else if(S.loc == trg) + S.icon_state = initial(S.icon_state) + S.icon = initial(S.icon) + S.update_icon() + break + else + S.icon_state = initial(S.icon_state) + S.icon = initial(S.icon) + S.update_icon() + break + sleep(1) + do_after_cooldown() + return 1 + + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/Topic(href,href_list) + ..() + var/datum/topic_input/F = new (href,href_list) + if(F.get("toggle_mode")) + mode = !mode + update_equip_info() + return + if(F.get("select_reagents")) + processed_reagents.len = 0 + var/m = 0 + var/message + for(var/i=1 to known_reagents.len) + if(m>=synth_speed) + break + var/reagent = F.get("reagent_[i]") + if(reagent && (reagent in known_reagents)) + message = "[m ? ", " : null][known_reagents[reagent]]" + processed_reagents += reagent + m++ + if(processed_reagents.len) + message += " added to production" + synth.start() + occupant_message(message) + occupant_message("Reagent processing started.") + log_message("Reagent processing started.") + return + if(F.get("show_reagents")) + chassis.occupant << browse(get_reagents_page(),"window=msyringegun") + if(F.get("purge_reagent")) + var/datum/reagent/R = locate(F.get("purge_reagent")) in reagents.reagent_list + if(R) + reagents.del_reagent(R.type) + return + if(F.get("purge_all")) + reagents.clear_reagents() + return + return + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_reagents_page() + var/output = {" + + Reagent Synthesizer + + + + +

            Current reagents:

            +
            + [get_current_reagents()] +
            +

            Reagents production:

            +
            + [get_reagents_form()] +
            + + + "} + return output + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_reagents_form() + var/r_list = get_reagents_list() + var/inputs + if(r_list) + inputs += "" + inputs += "" + inputs += "" + var/output = {"
            + [r_list || "No known reagents"] + [inputs] +
            + [r_list? "Only the first [synth_speed] selected reagent\s will be added to production" : null] + "} + return output + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_reagents_list() + var/output + for(var/i=1 to known_reagents.len) + var/reagent_id = known_reagents[i] + output += {" [known_reagents[reagent_id]]
            "} + return output + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_current_reagents() + var/output + for(var/datum/reagent/R in reagents.reagent_list) + if(R.volume > 0) + output += "[R]: [round(R.volume,0.001)] - Purge Reagent
            " + if(output) + output += "Total: [round(reagents.total_volume,0.001)]/[reagents.maximum_volume] - Purge All" + return output || "None" + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/load_syringe(obj/item/weapon/reagent_containers/syringe/S) + if(syringes.len= 2) + occupant_message("The syringe is too far away.") + return 0 + for(var/obj/structure/D in S.loc)//Basic level check for structures in the way (Like grilles and windows) + if(!(D.CanPass(S,src.loc))) + occupant_message("Unable to load syringe.") + return 0 + for(var/obj/machinery/door/D in S.loc)//Checks for doors + if(!(D.CanPass(S,src.loc))) + occupant_message("Unable to load syringe.") + return 0 + S.reagents.trans_to_obj(src, S.reagents.total_volume) + S.forceMove(src) + syringes += S + occupant_message("Syringe loaded.") + update_equip_info() + return 1 + occupant_message("The [src] syringe chamber is full.") + return 0 + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/analyze_reagents(atom/A) + if(get_dist(src,A) >= 4) + occupant_message("The object is too far away.") + return 0 + if(!A.reagents || istype(A,/mob)) + occupant_message("No reagent info gained from [A].") + return 0 + occupant_message("Analyzing reagents...") + for(var/datum/reagent/R in A.reagents.reagent_list) + if(R.reagent_state == 2 && add_known_reagent(R.type,R.name)) + occupant_message("Reagent analyzed, identified as [R.name] and added to database.") + send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form()) + occupant_message("Analyzis complete.") + return 1 + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/add_known_reagent(r_id,r_name) + set_ready_state(0) + do_after_cooldown() + if(!(r_id in known_reagents)) + known_reagents += r_id + known_reagents[r_id] = r_name + return 1 + return 0 + + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/update_equip_info() + if(..()) + send_byjax(chassis.occupant,"msyringegun.browser","reagents",get_current_reagents()) + send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form()) + return 1 + return + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/on_reagent_change() + ..() + update_equip_info() + return + +/datum/global_iterator/mech_synth + delay = 100 + +/datum/global_iterator/mech_synth/process(var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/S) + if(!S.chassis) + return stop() + var/energy_drain = S.energy_drain + if(!S.processed_reagents.len || S.reagents.total_volume >= S.reagents.maximum_volume || !S.chassis.has_charge(energy_drain)) + S.occupant_message("Reagent processing stopped.") + S.log_message("Reagent processing stopped.") + return stop() + var/amount = S.synth_speed / S.processed_reagents.len + for(var/reagent in S.processed_reagents) + S.reagents.add_reagent(reagent,amount) + S.chassis.use_power(energy_drain) + return 1 diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm new file mode 100644 index 00000000..b0a1fd6e --- /dev/null +++ b/code/game/mecha/equipment/tools/tools.dm @@ -0,0 +1,1280 @@ +/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp + name = "hydraulic clamp" + icon_state = "mecha_clamp" + equip_cooldown = 15 + energy_drain = 1 KILOWATTS + var/dam_force = 20 + var/obj/mecha/working/ripley/cargo_holder + required_type = /obj/mecha/working + + attach(obj/mecha/M as obj) + ..() + cargo_holder = M + return + + action(atom/target) + if(!action_checks(target)) return + if(!cargo_holder) return + + //loading + if(istype(target,/obj)) + var/obj/O = target + if(O.buckled_mob) + return + if(locate(/mob/living) in O) + occupant_message("You can't load living things into the cargo compartment.") + return + if(O.anchored) + occupant_message("[target] is firmly secured.") + return + if(cargo_holder.cargo.len >= cargo_holder.cargo_capacity) + occupant_message("Not enough room in cargo compartment.") + return + if(istype(O, /obj/machinery/power/supermatter)) + occupant_message("Warning: Safety systems prevent the loading of [target] into the cargo compartment.") + return + + occupant_message("You lift [target] and start to load it into cargo compartment.") + chassis.visible_message("[chassis] lifts [target] and starts to load it into cargo compartment.") + set_ready_state(0) + chassis.use_power(energy_drain) + O.anchored = 1 + var/T = chassis.loc + if(do_after_cooldown(target)) + if(T == chassis.loc && src == chassis.selected) + cargo_holder.cargo += O + O.loc = chassis + O.anchored = 0 + occupant_message("[target] succesfully loaded.") + log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]") + else + occupant_message("You must hold still while handling objects.") + O.anchored = initial(O.anchored) + + //attacking + else if(istype(target,/mob/living)) + var/mob/living/M = target + if(M.stat>1) return + if(chassis.occupant.a_intent == I_HURT) + M.take_overall_damage(dam_force) + M.adjustOxyLoss(round(dam_force/2)) + M.updatehealth() + occupant_message("You squeeze [target] with [src.name]. Something cracks.") + chassis.visible_message("[chassis] squeezes [target].") + else + step_away(M,chassis) + occupant_message("You push [target] out of the way.") + chassis.visible_message("[chassis] pushes [target] out of the way.") + set_ready_state(0) + chassis.use_power(energy_drain) + do_after_cooldown() + return 1 + +/obj/item/mecha_parts/mecha_equipment/tool/drill + name = "drill" + desc = "This is the drill that'll pierce the heavens! (Can be attached to: Combat and Engineering Exosuits)" + icon_state = "mecha_drill" + equip_cooldown = 30 + energy_drain = 10 + force = 15 + required_type = list(/obj/mecha/working/ripley, /obj/mecha/combat) + + action(atom/target) + if(!action_checks(target)) return + if(isobj(target)) + var/obj/target_obj = target + if(!target_obj.vars.Find("unacidable") || target_obj.unacidable) return + set_ready_state(0) + chassis.use_power(energy_drain) + chassis.visible_message("\The [chassis] starts to drill \the [target]", "You hear a large drill.") + occupant_message("You start to drill \the [target]") + var/T = chassis.loc + var/C = target.loc //why are these backwards? we may never know -Pete + if(do_after_cooldown(target)) + if(T == chassis.loc && src == chassis.selected) + if(istype(target, /turf/simulated/wall)) + var/turf/simulated/wall/W = target + if(W.is_reinf()) + occupant_message("\The [target] is too durable to drill through.") + else + log_message("Drilled through \the [target]") + target.ex_act(2) + else if(istype(target, /turf/simulated/mineral)) + for(var/turf/simulated/mineral/M in range(chassis,1)) + if(get_dir(chassis,M)&chassis.dir) + M.GetDrilled() + log_message("Drilled through \the [target]") + if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) + var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo + if(ore_box) + for(var/obj/item/weapon/ore/ore in range(chassis,1)) + if(get_dir(chassis,ore)&chassis.dir) + ore.Move(ore_box) + else if(istype(target, /turf/simulated/floor/asteroid)) + for(var/turf/simulated/floor/asteroid/M in range(chassis,1)) + if(get_dir(chassis,M)&chassis.dir) + M.gets_dug() + log_message("Drilled through \the [target]") + if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) + var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo + if(ore_box) + for(var/obj/item/weapon/ore/ore in range(chassis,1)) + if(get_dir(chassis,ore)&chassis.dir) + ore.Move(ore_box) + else if(target.loc == C) + log_message("Drilled through \the [target]") + target.ex_act(2) + return 1 + +/obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill + name = "diamond drill" + desc = "This is an upgraded version of the drill that'll pierce the heavens! (Can be attached to: Combat and Engineering Exosuits)" + icon_state = "mecha_diamond_drill" + origin_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 3) + equip_cooldown = 20 + force = 15 + + action(atom/target) + if(!action_checks(target)) return + if(isobj(target)) + var/obj/target_obj = target + if(target_obj.unacidable) return + set_ready_state(0) + chassis.use_power(energy_drain) + chassis.visible_message("\The [chassis] starts to drill \the [target]", "You hear a large drill.") + occupant_message("You start to drill \the [target]") + var/T = chassis.loc + var/C = target.loc //why are these backwards? we may never know -Pete + if(do_after_cooldown(target)) + if(T == chassis.loc && src == chassis.selected) + if(istype(target, /turf/simulated/wall)) + var/turf/simulated/wall/W = target + if(!W.is_reinf() || do_after_cooldown(target))//To slow down how fast mechs can drill through the station + log_message("Drilled through \the [target]") + target.ex_act(3) + else if(istype(target, /turf/simulated/mineral)) + for(var/turf/simulated/mineral/M in range(chassis,1)) + if(get_dir(chassis,M)&chassis.dir) + M.GetDrilled() + log_message("Drilled through \the [target]") + if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) + var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo + if(ore_box) + for(var/obj/item/weapon/ore/ore in range(chassis,1)) + if(get_dir(chassis,ore)&chassis.dir) + ore.Move(ore_box) + else if(istype(target,/turf/simulated/floor/asteroid)) + for(var/turf/simulated/floor/asteroid/M in range(target,1)) + M.gets_dug() + log_message("Drilled through \the [target]") + if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) + var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo + if(ore_box) + for(var/obj/item/weapon/ore/ore in range(target,1)) + ore.Move(ore_box) + else if(target.loc == C) + log_message("Drilled through \the [target]") + target.ex_act(2) + return 1 + +/obj/item/mecha_parts/mecha_equipment/tool/extinguisher + name = "extinguisher" + desc = "Exosuit-mounted extinguisher (Can be attached to: Engineering exosuits)" + icon_state = "mecha_exting" + equip_cooldown = 5 + energy_drain = 0 + range = MELEE|RANGED + required_type = /obj/mecha/working + var/spray_particles = 5 + var/spray_amount = 5 //units of liquid per particle. 5 is enough to wet the floor - it's a big fire extinguisher, so should be fine + var/max_water = 1000 + + New() + create_reagents(max_water) + reagents.add_reagent(/datum/reagent/water, max_water) + ..() + + action(atom/target) //copypasted from extinguisher. TODO: Rewrite from scratch. + if(!action_checks(target) || get_dist(chassis, target)>3) return + if(get_dist(chassis, target)>2) return + set_ready_state(0) + if(do_after_cooldown(target)) + if( istype(target, /obj/structure/reagent_dispensers/watertank) && get_dist(chassis,target) <= 1) + var/obj/o = target + var/amount = o.reagents.trans_to_obj(src, 200) + occupant_message("[amount] units transferred into internal tank.") + playsound(chassis, 'sound/effects/refill.ogg', 50, 1, -6) + return + + if (src.reagents.total_volume < 1) + occupant_message("\The [src] is empty.") + return + + playsound(chassis, 'sound/effects/extinguish.ogg', 75, 1, -3) + + var/direction = get_dir(chassis,target) + + var/turf/T = get_turf(target) + var/turf/T1 = get_step(T,turn(direction, 90)) + var/turf/T2 = get_step(T,turn(direction, -90)) + + var/list/the_targets = list(T,T1,T2) + + for(var/a = 1 to 5) + spawn(0) + var/obj/effect/effect/water/W = new /obj/effect/effect/water(get_turf(chassis)) + var/turf/my_target + if(a == 1) + my_target = T + else if(a == 2) + my_target = T1 + else if(a == 3) + my_target = T2 + else + my_target = pick(the_targets) + W.create_reagents(5) + if(!W || !src) + return + reagents.trans_to_obj(W, spray_amount) + W.set_color() + W.set_up(my_target) + return 1 + + get_equip_info() + return "[..()] \[[src.reagents.total_volume]\]" + + on_reagent_change() + return + + +/obj/item/mecha_parts/mecha_equipment/tool/rcd + name = "mounted RCD" + desc = "An exosuit-mounted Rapid Construction Device. (Can be attached to: Any exosuit)" + icon_state = "mecha_rcd" + origin_tech = list(TECH_MATERIAL = 4, TECH_BLUESPACE = 3, TECH_MAGNET = 4, TECH_POWER = 4) + equip_cooldown = 10 + energy_drain = 25 KILOWATTS + range = MELEE|RANGED + var/mode = 0 //0 - deconstruct, 1 - wall or floor, 2 - airlock. + var/disabled = 0 //malf + + action(atom/target) + if(istype(target,/area/shuttle)||istype(target, /turf/space/transit))//>implying these are ever made -Sieve + disabled = 1 + else + disabled = 0 + if(!istype(target, /turf) && !istype(target, /obj/machinery/door/airlock)) + target = get_turf(target) + if(!action_checks(target) || disabled || get_dist(chassis, target)>3) return + playsound(chassis, 'sound/machines/click.ogg', 50, 1) + //meh + switch(mode) + if(0) + if (istype(target, /turf/simulated/wall)) + occupant_message("Deconstructing [target]...") + set_ready_state(0) + if(do_after_cooldown(target)) + if(disabled) return + chassis.spark_system.start() + target:ChangeTurf(/turf/simulated/floor/plating) + playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) + chassis.use_power(energy_drain) + else if (istype(target, /turf/simulated/floor)) + occupant_message("Deconstructing [target]...") + set_ready_state(0) + if(do_after_cooldown(target)) + if(disabled) return + chassis.spark_system.start() + target:ChangeTurf(get_base_turf_by_area(target)) + playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) + chassis.use_power(energy_drain) + else if (istype(target, /obj/machinery/door/airlock)) + occupant_message("Deconstructing [target]...") + set_ready_state(0) + if(do_after_cooldown(target)) + if(disabled) return + chassis.spark_system.start() + qdel(target) + playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) + chassis.use_power(energy_drain) + if(1) + if(istype(target, /turf/space) || istype(target,get_base_turf_by_area(target))) + occupant_message("Building Floor...") + set_ready_state(0) + if(do_after_cooldown(target)) + if(disabled) return + target:ChangeTurf(/turf/simulated/floor/plating) + playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) + chassis.spark_system.start() + chassis.use_power(energy_drain*2) + else if(istype(target, /turf/simulated/floor)) + occupant_message("Building Wall...") + set_ready_state(0) + if(do_after_cooldown(target)) + if(disabled) return + target:ChangeTurf(/turf/simulated/wall) + playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) + chassis.spark_system.start() + chassis.use_power(energy_drain*2) + if(2) + if(istype(target, /turf/simulated/floor)) + occupant_message("Building Airlock...") + set_ready_state(0) + if(do_after_cooldown(target)) + if(disabled) return + chassis.spark_system.start() + var/obj/machinery/door/airlock/T = new /obj/machinery/door/airlock(target) + T.autoclose = 1 + playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) + playsound(target, 'sound/effects/sparks2.ogg', 50, 1) + chassis.use_power(energy_drain*2) + return + + + Topic(href,href_list) + ..() + if(href_list["mode"]) + mode = text2num(href_list["mode"]) + switch(mode) + if(0) + occupant_message("Switched RCD to Deconstruct.") + if(1) + occupant_message("Switched RCD to Construct.") + if(2) + occupant_message("Switched RCD to Construct Airlock.") + return + + get_equip_info() + return "[..()] \[D|C|A\]" + + + + +/obj/item/mecha_parts/mecha_equipment/teleporter + name = "teleporter" + desc = "An exosuit module that allows exosuits to teleport to any position in view." + icon_state = "mecha_teleport" + origin_tech = list(TECH_BLUESPACE = 10) + equip_cooldown = 150 + energy_drain = 200 KILOWATTS + range = RANGED + +/obj/item/mecha_parts/mecha_equipment/teleporter/action(atom/target) + if(!action_checks(target)) return + var/turf/T = get_turf(target) + if(T) + if(isAdminLevel(T.z)) + return + set_ready_state(0) + chassis.use_power(energy_drain) + do_teleport(chassis, T, 4) + do_after_cooldown() + + +/obj/item/mecha_parts/mecha_equipment/wormhole_generator + name = "wormhole generator" + desc = "An exosuit module that allows generating of small quasi-stable wormholes." + icon_state = "mecha_wholegen" + origin_tech = list(TECH_BLUESPACE = 3) + equip_cooldown = 50 + energy_drain = 50 KILOWATTS + range = RANGED + + + action(atom/target) + if(!action_checks(target) || src.loc.z == 2) return + var/list/theareas = list() + for(var/area/AR in orange(100, chassis)) + if(AR in theareas) continue + theareas += AR + if(!theareas.len) + return + var/area/thearea = pick(theareas) + var/list/L = list() + var/turf/pos = get_turf(src) + for(var/turf/T in get_area_turfs(thearea)) + if(!T.density && pos.z == T.z) + var/clear = 1 + for(var/obj/O in T) + if(O.density) + clear = 0 + break + if(clear) + L+=T + if(!L.len) + return + var/turf/target_turf = pick(L) + if(!target_turf) + return + chassis.use_power(energy_drain) + set_ready_state(0) + var/obj/effect/portal/P = new /obj/effect/portal(get_turf(target)) + P.target = target_turf + P.creator = null + P.icon = 'icons/obj/objects.dmi' + P.failchance = 0 + P.icon_state = "anom" + P.SetName("wormhole") + do_after_cooldown() + src = null + spawn(rand(150,300)) + qdel(P) + return + +/obj/item/mecha_parts/mecha_equipment/gravcatapult + name = "gravitational catapult" + desc = "An exosuit mounted Gravitational Catapult." + icon_state = "mecha_teleport" + origin_tech = list(TECH_BLUESPACE = 2, TECH_MAGNET = 3) + equip_cooldown = 10 + energy_drain = 10 KILOWATTS + range = MELEE|RANGED + var/atom/movable/locked + var/mode = 1 //1 - gravsling 2 - gravpush + + var/last_fired = 0 //Concept stolen from guns. + var/fire_delay = 10 //Used to prevent spam-brute against humans. + + action(atom/movable/target) + + if(world.time >= last_fired + fire_delay) + last_fired = world.time + else + if (world.time % 3) + occupant_message("[src] is not ready to fire again!") + return 0 + + switch(mode) + if(1) + if(!action_checks(target) && !locked) return + if(!locked) + if(!istype(target) || target.anchored) + occupant_message("Unable to lock on [target]") + return + locked = target + occupant_message("Locked on [target]") + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + return + else if(target!=locked) + if(locked in view(chassis)) + locked.throw_at(target, 14, 1.5, chassis) + locked = null + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + set_ready_state(0) + chassis.use_power(energy_drain) + do_after_cooldown() + else + locked = null + occupant_message("Lock on [locked] disengaged.") + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + if(2) + if(!action_checks(target)) return + var/list/atoms = list() + if(isturf(target)) + atoms = range(target,3) + else + atoms = orange(target,3) + for(var/atom/movable/A in atoms) + if(A.anchored) continue + spawn(0) + var/iter = 5-get_dist(A,target) + for(var/i=0 to iter) + step_away(A,target) + sleep(2) + set_ready_state(0) + chassis.use_power(energy_drain) + do_after_cooldown() + return + + get_equip_info() + return "[..()] [mode==1?"([locked||"Nothing"])":null] \[S|P\]" + + Topic(href, href_list) + ..() + if(href_list["mode"]) + mode = text2num(href_list["mode"]) + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + return + + +/obj/item/mecha_parts/mecha_equipment/armor_booster + name = "armor booster" + desc = "Powered armor-enhancing mech equipment." + icon_state = "mecha_abooster_proj" + equip_cooldown = 10 + energy_drain = 5 KILOWATTS + range = 0 + var/deflect_coeff = 1 + var/damage_coeff = 1 + var/melee + + attach(obj/mecha/M as obj) + ..() + activate_boost() + return + + detach() + if(equip_ready) + deactivate_boost() + ..() + return + + get_equip_info() + if(!chassis) return + return "* [src.name]" + + proc/activate_boost() + if(!src.chassis) + return 0 + return 1 + + proc/deactivate_boost() + if(!src.chassis) + return 0 + return 1 + + set_ready_state(state) + if(state && !equip_ready) + activate_boost() + else if(equip_ready) + deactivate_boost() + ..() + + +/obj/item/mecha_parts/mecha_equipment/armor_booster/anticcw_armor_booster //what is that noise? A BAWWW from TK mutants. + name = "\improper CCW armor booster" + desc = "Close-combat armor booster. Boosts exosuit armor against armed melee attacks. Requires energy to operate." + icon_state = "mecha_abooster_ccw" + origin_tech = list(TECH_MATERIAL = 3) + deflect_coeff = 1.15 + damage_coeff = 0.8 + melee = 1 + + activate_boost() + if(..()) + chassis.m_deflect_coeff *= deflect_coeff + chassis.m_damage_coeff *= damage_coeff + chassis.mhit_power_use += energy_drain + + + deactivate_boost() + if(..()) + chassis.m_deflect_coeff /= deflect_coeff + chassis.m_damage_coeff /= damage_coeff + chassis.mhit_power_use -= energy_drain + + +/obj/item/mecha_parts/mecha_equipment/armor_booster/antiproj_armor_booster + name = "\improper RW armor booster" + desc = "Ranged-weaponry armor booster. Boosts exosuit armor against ranged attacks. Completely blocks taser shots, but requires energy to operate." + icon_state = "mecha_abooster_proj" + origin_tech = list(TECH_MATERIAL = 4) + deflect_coeff = 1.15 + damage_coeff = 0.8 + melee = 0 + + activate_boost() + if(..()) + chassis.r_deflect_coeff *= deflect_coeff + chassis.r_damage_coeff *= damage_coeff + chassis.rhit_power_use += energy_drain + + deactivate_boost() + if(..()) + chassis.r_deflect_coeff /= deflect_coeff + chassis.r_damage_coeff /= damage_coeff + chassis.rhit_power_use -= energy_drain + + +/obj/item/mecha_parts/mecha_equipment/repair_droid + name = "repair droid" + desc = "Automated repair droid. Scans exosuit for damage and repairs it. Can fix almost any type of external or internal damage." + icon_state = "repair_droid" + origin_tech = list(TECH_MAGNET = 3, TECH_DATA = 3) + equip_cooldown = 20 + energy_drain = 10 KILOWATTS + range = 0 + var/health_boost = 2 + var/datum/global_iterator/pr_repair_droid + var/icon/droid_overlay + var/list/repairable_damage = list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH) + + New() + ..() + pr_repair_droid = new /datum/global_iterator/mecha_repair_droid(list(src),0) + pr_repair_droid.set_delay(equip_cooldown) + return + + Destroy() + qdel(pr_repair_droid) + pr_repair_droid = null + ..() + + attach(obj/mecha/M as obj) + ..() + droid_overlay = new(src.icon, icon_state = "repair_droid") + M.overlays += droid_overlay + return + + destroy() + chassis.overlays -= droid_overlay + ..() + return + + detach() + chassis.overlays -= droid_overlay + pr_repair_droid.stop() + ..() + return + + get_equip_info() + if(!chassis) return + return "* [src.name] - [pr_repair_droid.active()?"Dea":"A"]ctivate" + + + Topic(href, href_list) + ..() + if(href_list["toggle_repairs"]) + chassis.overlays -= droid_overlay + if(pr_repair_droid.toggle()) + droid_overlay = new(src.icon, icon_state = "repair_droid_a") + log_message("Activated.") + else + droid_overlay = new(src.icon, icon_state = "repair_droid") + log_message("Deactivated.") + set_ready_state(1) + chassis.overlays += droid_overlay + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + return + + +/datum/global_iterator/mecha_repair_droid + + process(var/obj/item/mecha_parts/mecha_equipment/repair_droid/RD as obj) + if(!RD.chassis) + stop() + RD.set_ready_state(1) + return + var/health_boost = RD.health_boost + var/repaired = 0 + if(RD.chassis.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) + health_boost *= -2 + else if(RD.chassis.hasInternalDamage() && prob(15)) + for(var/int_dam_flag in RD.repairable_damage) + if(RD.chassis.hasInternalDamage(int_dam_flag)) + RD.chassis.clearInternalDamage(int_dam_flag) + repaired = 1 + break + if(health_boost<0 || RD.chassis.health < initial(RD.chassis.health)) + RD.chassis.health += min(health_boost, initial(RD.chassis.health)-RD.chassis.health) + repaired = 1 + if(repaired) + if(RD.chassis.use_power(RD.energy_drain)) + RD.set_ready_state(0) + else + stop() + RD.set_ready_state(1) + return + else + RD.set_ready_state(1) + return + + +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay + name = "energy relay" + desc = "Wirelessly drains energy from any available power channel in area. The performance index is quite low." + icon_state = "tesla" + origin_tech = list(TECH_MAGNET = 4, TECH_ILLEGAL = 2) + equip_cooldown = 10 + energy_drain = 0 + range = 0 + var/datum/global_iterator/pr_energy_relay + var/coeff = 100 + var/list/use_channels = list(EQUIP,ENVIRON,LIGHT) + + New() + ..() + pr_energy_relay = new /datum/global_iterator/mecha_energy_relay(list(src),0) + pr_energy_relay.set_delay(equip_cooldown) + return + + Destroy() + qdel(pr_energy_relay) + pr_energy_relay = null + ..() + + detach() + pr_energy_relay.stop() + ..() + return + + attach(obj/mecha/M) + ..() + return + + proc/get_power_channel(var/area/A) + var/pow_chan + if(A) + for(var/c in use_channels) + if(A.powered(c)) + pow_chan = c + break + return pow_chan + + Topic(href, href_list) + ..() + if(href_list["toggle_relay"]) + if(pr_energy_relay.toggle()) + set_ready_state(0) + log_message("Activated.") + else + set_ready_state(1) + log_message("Deactivated.") + return + + get_equip_info() + if(!chassis) return + return "* [src.name] - [pr_energy_relay.active()?"Dea":"A"]ctivate" + +/datum/global_iterator/mecha_energy_relay + + process(var/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/ER) + if(!ER.chassis || ER.chassis.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) + stop() + ER.set_ready_state(1) + return + var/cur_charge = ER.chassis.get_charge() + if(isnull(cur_charge) || !ER.chassis.cell) + stop() + ER.set_ready_state(1) + ER.occupant_message("No powercell detected.") + return + if(cur_charge3\] - [pr_mech_generator.active()?"Dea":"A"]ctivate" + return + + action(target) + if(chassis) + var/result = load_fuel(target) + var/message + if(isnull(result)) + message = "[fuel] traces in target minimal. [target] cannot be used as fuel." + else if(!result) + message = "Unit is full." + else + message = "[result] unit\s of [fuel] successfully loaded." + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + occupant_message(message) + return + + proc/load_fuel(var/obj/item/stack/material/P) + if(P.type == fuel.type && P.amount) + var/to_load = max(max_fuel - fuel.amount*fuel.perunit,0) + if(to_load) + var/units = min(max(round(to_load / P.perunit),1),P.amount) + if(units) + fuel.amount += units + P.use(units) + return units + else + return 0 + return + + attackby(weapon,mob/user) + var/result = load_fuel(weapon) + if(isnull(result)) + user.visible_message("[user] tries to shove [weapon] into [src]. What a dumb-ass.","[fuel] traces minimal. [weapon] cannot be used as fuel.") + else if(!result) + to_chat(user, "Unit is full.") + else + user.visible_message("[user] loads [src] with [fuel].","[result] unit\s of [fuel] successfully loaded.") + return + + critfail() + ..() + var/turf/simulated/T = get_turf(src) + if(!T) + return + var/datum/gas_mixture/GM = new + if(prob(10)) + T.assume_gas("phoron", 100, 1500+T0C) + T.visible_message("The [src] suddenly disgorges a cloud of heated phoron.") + destroy() + else + T.assume_gas("phoron", 5, istype(T) ? T.air.temperature : T20C) + T.visible_message("The [src] suddenly disgorges a cloud of phoron.") + T.assume_air(GM) + return + +/datum/global_iterator/mecha_generator + + process(var/obj/item/mecha_parts/mecha_equipment/generator/EG) + if(!EG.chassis) + stop() + EG.set_ready_state(1) + return 0 + if(EG.fuel.amount<=0) + stop() + EG.log_message("Deactivated - no fuel.") + EG.set_ready_state(1) + return 0 + var/cur_charge = EG.chassis.get_charge() + if(isnull(cur_charge)) + EG.set_ready_state(1) + EG.occupant_message("No powercell detected.") + EG.log_message("Deactivated.") + stop() + return 0 + var/use_fuel = EG.fuel_per_cycle_idle + if(cur_charge[target] succesfully loaded.") + chassis.log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]") + else + chassis.occupant_message("You must hold still while handling objects.") + O.anchored = initial(O.anchored) + else + chassis.occupant_message("Not enough room in cargo compartment.") + else + chassis.occupant_message("[target] is firmly secured.") + + else if(istype(target,/mob/living)) + var/mob/living/M = target + if(M.stat>1) return + if(chassis.occupant.a_intent == I_HURT) + chassis.occupant_message("You obliterate [target] with [src.name], leaving blood and guts everywhere.") + chassis.visible_message("[chassis] destroys [target] in an unholy fury.") + if(chassis.occupant.a_intent == I_DISARM) + chassis.occupant_message("You tear [target]'s limbs off with [src.name].") + chassis.visible_message("[chassis] rips [target]'s arms off.") + else + step_away(M,chassis) + chassis.occupant_message("You smash into [target], sending them flying.") + chassis.visible_message("[chassis] tosses [target] like a piece of paper.") + set_ready_state(0) + chassis.use_power(energy_drain) + do_after_cooldown() + return 1 + +/obj/item/mecha_parts/mecha_equipment/tool/passenger + name = "passenger compartment" + desc = "A mountable passenger compartment for exo-suits. Rather cramped." + icon_state = "mecha_abooster_ccw" + origin_tech = list(TECH_ENGINEERING = 1, TECH_BIO = 1) + energy_drain = 1 KILOWATTS + range = MELEE + equip_cooldown = 20 + var/mob/living/carbon/occupant = null + var/door_locked = 1 + salvageable = 0 + +/obj/item/mecha_parts/mecha_equipment/tool/passenger/destroy() + for(var/atom/movable/AM in src) + AM.forceMove(get_turf(src)) + to_chat(AM, "You tumble out of the destroyed [src.name]!") + return ..() + +/obj/item/mecha_parts/mecha_equipment/tool/passenger/Exit(atom/movable/O) + return 0 + +/obj/item/mecha_parts/mecha_equipment/tool/passenger/proc/move_inside(var/mob/user) + if (chassis) + chassis.visible_message("[user] starts to climb into [chassis].") + + if(do_after(user, 40, src, needhand=0)) + if(!src.occupant) + user.forceMove(src) + occupant = user + log_message("\The [user] boarded.") + occupant_message("\The [user] boarded.") + else if(src.occupant != user) + to_chat(user, "[src.occupant] was faster. Try better next time, loser.") + else + to_chat(user, "You stop entering the exosuit.") + +/obj/item/mecha_parts/mecha_equipment/tool/passenger/verb/eject() + set name = "Eject" + set category = "Exosuit Interface" + set src = usr.loc + set popup_menu = 0 + + if(usr != occupant) + return + to_chat(occupant, "You climb out from \the [src].") + go_out() + occupant_message("[occupant] disembarked.") + log_message("[occupant] disembarked.") + add_fingerprint(usr) + +/obj/item/mecha_parts/mecha_equipment/tool/passenger/proc/go_out() + if(!occupant) + return + occupant.forceMove(get_turf(src)) + occupant.reset_view() + /* + if(occupant.client) + occupant.client.eye = occupant.client.mob + occupant.client.perspective = MOB_PERSPECTIVE + */ + occupant = null + return + +/obj/item/mecha_parts/mecha_equipment/tool/passenger/attach() + ..() + if (chassis) + chassis.verbs |= /obj/mecha/proc/move_inside_passenger + +/obj/item/mecha_parts/mecha_equipment/tool/passenger/detach() + if(occupant) + occupant_message("Unable to detach [src] - equipment occupied.") + return + + var/obj/mecha/M = chassis + ..() + if (M && !(locate(/obj/item/mecha_parts/mecha_equipment/tool/passenger) in M)) + M.verbs -= /obj/mecha/proc/move_inside_passenger + +/obj/item/mecha_parts/mecha_equipment/tool/passenger/get_equip_info() + return "[..()]
            [occupant? "\[Occupant: [occupant]\]|" : ""]Exterior Hatch: Toggle Lock" + +/obj/item/mecha_parts/mecha_equipment/tool/passenger/Topic(href,href_list) + ..() + if (href_list["toggle_lock"]) + door_locked = !door_locked + occupant_message("Passenger compartment hatch [door_locked? "locked" : "unlocked"].") + if (chassis) + chassis.visible_message("The hatch on \the [chassis] [door_locked? "locks" : "unlocks"].", "You hear something latching.") + + +#define LOCKED 1 +#define OCCUPIED 2 + +/obj/mecha/proc/move_inside_passenger() + set category = "Object" + set name = "Enter Passenger Compartment" + set src in oview(1) + + //check that usr can climb in + if (usr.stat || !ishuman(usr)) + return + + if (!usr.Adjacent(src)) + return + + if (!isturf(usr.loc)) + to_chat(usr, "You can't reach the passenger compartment from here.") + return + + if(iscarbon(usr)) + var/mob/living/carbon/C = usr + if(C.handcuffed) + to_chat(usr, "Kinda hard to climb in while handcuffed don't you think?") + return + + for(var/mob/living/carbon/slime/M in range(1,usr)) + if(M.Victim == usr) + to_chat(usr, "You're too busy getting your life sucked out of you.") + return + + //search for a valid passenger compartment + var/feedback = 0 //for nicer user feedback + for(var/obj/item/mecha_parts/mecha_equipment/tool/passenger/P in src) + if (P.occupant) + feedback |= OCCUPIED + continue + if (P.door_locked) + feedback |= LOCKED + continue + + //found a boardable compartment + P.move_inside(usr) + return + + //didn't find anything + switch (feedback) + if (OCCUPIED) + to_chat(usr, "The passenger compartment is already occupied!") + if (LOCKED) + to_chat(usr, "The passenger compartment hatch is locked!") + if (OCCUPIED|LOCKED) + to_chat(usr, "All of the passenger compartments are already occupied or locked!") + if (0) + to_chat(usr, "\The [src] doesn't have a passenger compartment.") + +#undef LOCKED +#undef OCCUPIED + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer + name = "Cable Layer" + icon_state = "mecha_wire" + var/datum/event/event + var/turf/old_turf + var/obj/structure/cable/last_piece + var/obj/item/stack/cable_coil/cable + var/max_cable = 1000 + required_type = /obj/mecha/working + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/New() + cable = new(src) + cable.amount = 0 + ..() + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/attach() + ..() + event = chassis.events.addEvent("onMove",src,"layCable") + return + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/detach() + chassis.events.clearEvent("onMove",event) + return ..() + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/destroy() + chassis.events.clearEvent("onMove",event) + return ..() + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/action(var/obj/item/stack/cable_coil/target) + if(!action_checks(target)) + return + var/result = load_cable(target) + var/message + if(isnull(result)) + message = "Unable to load [target] - no cable found." + else if(!result) + message = "Reel is full." + else + message = "[result] meters of cable successfully loaded." + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + occupant_message(message) + return + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/Topic(href,href_list) + ..() + if(href_list["toggle"]) + set_ready_state(!equip_ready) + occupant_message("[src] [equip_ready?"dea":"a"]ctivated.") + log_message("[equip_ready?"Dea":"A"]ctivated.") + return + if(href_list["cut"]) + if(cable && cable.amount) + var/m = round(input(chassis.occupant,"Please specify the length of cable to cut","Cut cable",min(cable.amount,30)) as num, 1) + m = min(m, cable.amount) + if(m) + use_cable(m) + var/obj/item/stack/cable_coil/CC = new (get_turf(chassis)) + CC.amount = m + else + occupant_message("There's no more cable on the reel.") + return + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/get_equip_info() + var/output = ..() + if(output) + return "[output] \[Cable: [cable ? cable.amount : 0] m\][(cable && cable.amount) ? "- [!equip_ready?"Dea":"A"]ctivate|Cut" : null]" + return + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/load_cable(var/obj/item/stack/cable_coil/CC) + if(istype(CC) && CC.amount) + var/cur_amount = cable? cable.amount : 0 + var/to_load = max(max_cable - cur_amount,0) + if(to_load) + to_load = min(CC.amount, to_load) + if(!cable) + cable = new(src) + cable.amount = 0 + cable.amount += to_load + CC.use(to_load) + return to_load + else + return 0 + return + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/use_cable(amount) + if(!cable || cable.amount<1) + set_ready_state(1) + occupant_message("Cable depleted, [src] deactivated.") + log_message("Cable depleted, [src] deactivated.") + return + if(cable.amount < amount) + occupant_message("No enough cable to finish the task.") + return + cable.use(amount) + update_equip_info() + return 1 + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/reset() + last_piece = null + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/dismantleFloor(var/turf/new_turf) + if(istype(new_turf, /turf/simulated/floor)) + var/turf/simulated/floor/T = new_turf + if(!T.is_plating()) + T.make_plating(!(T.broken || T.burnt)) + return new_turf.is_plating() + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/layCable(var/turf/new_turf) + if(equip_ready || !istype(new_turf) || !dismantleFloor(new_turf)) + return reset() + var/fdirn = turn(chassis.dir,180) + for(var/obj/structure/cable/LC in new_turf) // check to make sure there's not a cable there already + if(LC.d1 == fdirn || LC.d2 == fdirn) + return reset() + if(!use_cable(1)) + return reset() + var/obj/structure/cable/NC = new(new_turf) + NC.cableColor("red") + NC.d1 = 0 + NC.d2 = fdirn + NC.update_icon() + + var/datum/powernet/PN + if(last_piece && last_piece.d2 != chassis.dir) + last_piece.d1 = min(last_piece.d2, chassis.dir) + last_piece.d2 = max(last_piece.d2, chassis.dir) + last_piece.update_icon() + PN = last_piece.powernet + + if(!PN) + PN = new() + PN.add_cable(NC) + NC.mergeConnectedNetworks(NC.d2) + + //NC.mergeConnectedNetworksOnTurf() + last_piece = NC + return 1 \ No newline at end of file diff --git a/code/game/mecha/equipment/tools/unused_tools.dm b/code/game/mecha/equipment/tools/unused_tools.dm new file mode 100644 index 00000000..f65265b4 --- /dev/null +++ b/code/game/mecha/equipment/tools/unused_tools.dm @@ -0,0 +1,155 @@ + + + +/****** Do not tick this file in without looking over this code first ******/ + + + + + +//NEEDS SPRITE! (When this gets ticked in search for 'TODO MECHA JETPACK SPRITE MISSING' through code to uncomment the place where it's missing.) +/obj/item/mecha_parts/mecha_equipment/jetpack + name = "jetpack" + desc = "Using directed ion bursts and cunning solar wind reflection technique, this device enables controlled space flight." + icon_state = "mecha_equip" + equip_cooldown = 5 + energy_drain = 50 + var/wait = 0 + var/datum/effect/effect/system/ion_trail_follow/ion_trail + + + can_attach(obj/mecha/M as obj) + if(!(locate(src.type) in M.equipment) && !M.proc_res["dyndomove"]) + return ..() + + detach() + ..() + chassis.proc_res["dyndomove"] = null + return + + attach(obj/mecha/M as obj) + ..() + if(!ion_trail) + ion_trail = new + ion_trail.set_up(chassis) + return + + proc/toggle() + if(!chassis) + return + !equip_ready? turn_off() : turn_on() + return equip_ready + + proc/turn_on() + set_ready_state(0) + chassis.proc_res["dyndomove"] = src + ion_trail.start() + occupant_message("Activated") + log_message("Activated") + + proc/turn_off() + set_ready_state(1) + chassis.proc_res["dyndomove"] = null + ion_trail.stop() + occupant_message("Deactivated") + log_message("Deactivated") + + proc/dyndomove(direction) + if(!action_checks()) + return chassis.dyndomove(direction) + var/move_result = 0 + if(chassis.hasInternalDamage(MECHA_INT_CONTROL_LOST)) + move_result = step_rand(chassis) + else if(chassis.dir!=direction) + chassis.set_dir(direction) + move_result = 1 + else + move_result = step(chassis,direction) + if(chassis.occupant) + for(var/obj/effect/speech_bubble/B in range(1, chassis)) + if(B.parent == chassis.occupant) + B.loc = chassis.loc + if(move_result) + wait = 1 + chassis.use_power(energy_drain) + if(!chassis.pr_inertial_movement.active()) + chassis.pr_inertial_movement.start(list(chassis,direction)) + else + chassis.pr_inertial_movement.set_process_args(list(chassis,direction)) + do_after_cooldown() + return 1 + return 0 + + action_checks() + if(equip_ready || wait) + return 0 + if(energy_drain && !chassis.has_charge(energy_drain)) + return 0 + if(chassis.check_for_support()) + return 0 + return 1 + + get_equip_info() + if(!chassis) return + return "* [src.name] \[Toggle\]" + + + Topic(href,href_list) + ..() + if(href_list["toggle"]) + toggle() + + do_after_cooldown() + sleep(equip_cooldown) + wait = 0 + return 1 + + +/obj/item/mecha_parts/mecha_equipment/defence_shocker + name = "exosuit defence shocker" + desc = "" + icon_state = "mecha_teleport" + equip_cooldown = 10 + energy_drain = 100 + range = RANGED + var/shock_damage = 15 + var/active + + can_attach(obj/mecha/M as obj) + if(..()) + if(!istype(M, /obj/mecha/combat/honker)) + if(!M.proc_res["dynattackby"] && !M.proc_res["dynattackhand"] && !M.proc_res["dynattackalien"]) + return 1 + return 0 + + attach(obj/mecha/M as obj) + ..() + chassis.proc_res["dynattackby"] = src + return + + proc/dynattackby(obj/item/weapon/W as obj, mob/user as mob) + if(!action_checks(user) || !active) + return + user.electrocute_act(shock_damage, src) + return chassis.dynattackby(W,user) + + +/* +/obj/item/mecha_parts/mecha_equipment/book_stocker + + action(var/mob/target) + if(!istype(target)) + return + if(target.search_contents_for(/obj/item/book/WGW)) + target.gib() + target.client.gib() + target.client.mom.monkeyize() + target.client.mom.gib() + for(var/mob/M in range(target, 1000)) + M.gib() + explosion(target.loc,100000,100000,100000) + usr.gib() + world.Reboot() + return 1 + +*/ diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm new file mode 100644 index 00000000..0bb0a96e --- /dev/null +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -0,0 +1,301 @@ +/obj/item/mecha_parts/mecha_equipment/weapon + name = "mecha weapon" + range = RANGED + origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 3) + var/projectile //Type of projectile fired. + var/projectiles = 1 //Amount of projectiles loaded. + var/projectiles_per_shot = 1 //Amount of projectiles fired per single shot. + var/deviation = 0 //Inaccuracy of shots. + var/fire_cooldown = 0 //Duration of sleep between firing projectiles in single shot. + var/fire_sound //Sound played while firing. + var/fire_volume = 50 //How loud it is played. + var/auto_rearm = 0 //Does the weapon reload itself after each shot? + required_type = list(/obj/mecha/combat, /obj/mecha/working/hoverpod/combatpod) + +/obj/item/mecha_parts/mecha_equipment/weapon/action_checks(atom/target) + if(projectiles <= 0) + return 0 + return ..() + +/obj/item/mecha_parts/mecha_equipment/weapon/action(atom/target) + if(!action_checks(target)) + return + var/turf/curloc = chassis.loc + var/turf/targloc = get_turf(target) + if(!curloc || !targloc) + return + chassis.use_power(energy_drain) + chassis.visible_message("[chassis] fires [src]!") + occupant_message("You fire [src]!") + log_message("Fired from [src], targeting [target].") + for(var/i = 1 to min(projectiles, projectiles_per_shot)) + var/turf/aimloc = targloc + if(deviation) + aimloc = locate(targloc.x+GaussRandRound(deviation,1),targloc.y+GaussRandRound(deviation,1),targloc.z) + if(!aimloc || aimloc == curloc) + break + playsound(chassis, fire_sound, fire_volume, 1) + projectiles-- + var/P = new projectile(curloc) + Fire(P, target) + if(fire_cooldown) + sleep(fire_cooldown) + if(auto_rearm) + src.rearm() + set_ready_state(0) + do_after_cooldown() + return + +/obj/item/mecha_parts/mecha_equipment/weapon/proc/rearm() + projectiles = projectiles_per_shot + return + +/obj/item/mecha_parts/mecha_equipment/weapon/proc/Fire(atom/A, atom/target) + var/obj/item/projectile/P = A + var/def_zone + if(chassis && istype(chassis.occupant,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = chassis.occupant + def_zone = H.zone_sel.selecting + P.launch_projectile(target, def_zone) + +/obj/item/mecha_parts/mecha_equipment/weapon/energy + name = "general energy weapon" + auto_rearm = 1 + +/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser + equip_cooldown = 8 + name = "\improper CH-PS \"Immolator\" laser" + icon_state = "mecha_laser" + energy_drain = 3 KILOWATTS + projectile = /obj/item/projectile/beam + fire_sound = 'sound/weapons/Laser.ogg' + +/obj/item/mecha_parts/mecha_equipment/weapon/energy/riggedlaser + equip_cooldown = 30 + name = "jury-rigged welder-laser" + desc = "While not regulation, this inefficient weapon can be attached to working exo-suits in desperate, or malicious, times." + icon_state = "mecha_laser" + energy_drain = 10 KILOWATTS // Inefficient + projectile = /obj/item/projectile/beam + fire_sound = 'sound/weapons/Laser.ogg' + required_type = list(/obj/mecha/combat, /obj/mecha/working) + +/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy + equip_cooldown = 15 + name = "\improper CH-LC \"Solaris\" laser cannon" + icon_state = "mecha_laser" + energy_drain = 6 KILOWATTS + projectile = /obj/item/projectile/beam/heavylaser + fire_sound = 'sound/weapons/lasercannonfire.ogg' + +/obj/item/mecha_parts/mecha_equipment/weapon/energy/ion + equip_cooldown = 40 + name = "mkIV ion heavy cannon" + icon_state = "mecha_ion" + energy_drain = 25 KILOWATTS + projectile = /obj/item/projectile/ion + fire_sound = 'sound/weapons/Laser.ogg' + +/obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse + equip_cooldown = 30 + name = "eZ-13 mk2 heavy pulse rifle" + icon_state = "mecha_pulse" + energy_drain = 15 KILOWATTS + origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 6, TECH_POWER = 4) + projectile = /obj/item/projectile/beam/pulse/heavy + fire_sound = 'sound/weapons/marauder.ogg' + +/obj/item/projectile/beam/pulse/heavy + name = "heavy pulse laser" + icon_state = "pulse1_bl" + var/life = 20 + + Bump(atom/A) + A.bullet_act(src, def_zone) + src.life -= 10 + if(life <= 0) + qdel(src) + return + +/obj/item/mecha_parts/mecha_equipment/weapon/energy/taser + name = "\improper PBT \"Pacifier\" mounted taser" + icon_state = "mecha_taser" + energy_drain = 2 KILOWATTS + equip_cooldown = 8 + projectile = /obj/item/projectile/beam/stun + fire_sound = 'sound/weapons/Taser.ogg' + +/* Commenting this out rather than removing it because it may be useful for reference. +/obj/item/mecha_parts/mecha_equipment/weapon/honker + name = "\improper HoNkER BlAsT 5000" + icon_state = "mecha_honker" + energy_drain = 200 + equip_cooldown = 150 + range = MELEE|RANGED + construction_time = 500 + construction_cost = list("metal"=20000,"bananium"=10000) + + can_attach(obj/mecha/combat/honker/M as obj) + if(!istype(M)) + return 0 + return ..() + + action(target) + if(!chassis) + return 0 + if(energy_drain && chassis.get_charge() < energy_drain) + return 0 + if(!equip_ready) + return 0 + + playsound(chassis, 'sound/items/AirHorn.ogg', 100, 1) + chassis.occupant_message("HONK") + for(var/mob/living/carbon/M in ohearers(6, chassis)) + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(istype(H.l_ear, /obj/item/clothing/ears/earmuffs) || istype(H.r_ear, /obj/item/clothing/ears/earmuffs)) + continue + to_chat(M, "HONK") + M.sleeping = 0 + M.stuttering += 20 + M.ear_deaf += 30 + M.Weaken(3) + if(prob(30)) + M.Stun(10) + M.Paralyse(4) + else + M.make_jittery(500) + chassis.use_power(energy_drain) + log_message("Honked from [src.name]. HONK!") + do_after_cooldown() + return +*/ + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic + name = "general ballisic weapon" + var/projectile_energy_cost + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/get_equip_info() + return "[..()]\[[src.projectiles]\][(src.projectiles < initial(src.projectiles))?" - Rearm":null]" + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/rearm() + if(projectiles < initial(projectiles)) + var/projectiles_to_add = initial(projectiles) - projectiles + while(chassis.get_charge() >= projectile_energy_cost && projectiles_to_add) + projectiles++ + projectiles_to_add-- + chassis.use_power(projectile_energy_cost) + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + log_message("Rearmed [src.name].") + return + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/Topic(href, href_list) + ..() + if (href_list["rearm"]) + src.rearm() + return + + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot + name = "\improper LBX AC 10 \"Scattershot\"" + icon_state = "mecha_scatter" + equip_cooldown = 20 + projectile = /obj/item/projectile/bullet/pistol/medium + fire_sound = 'sound/weapons/gunshot/shotgun.ogg' + fire_volume = 80 + projectiles = 40 + projectiles_per_shot = 4 + deviation = 0.7 + projectile_energy_cost = 50 KILOWATTS + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg + name = "\improper Ultra AC 2" + icon_state = "mecha_uac2" + equip_cooldown = 10 + projectile = /obj/item/projectile/bullet/pistol/medium + fire_sound = 'sound/weapons/gunshot/gunshot3.ogg' + projectiles = 300 + projectiles_per_shot = 3 + deviation = 0.3 + projectile_energy_cost = 40 KILOWATTS + fire_cooldown = 2 + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack + var/missile_speed = 2 + var/missile_range = 30 + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/Fire(atom/movable/AM, atom/target) + AM.throw_at(target,missile_range, missile_speed, chassis) + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flare + name = "\improper BNI Flare Launcher" + icon_state = "mecha_flaregun" + projectile = /obj/item/device/flashlight/flare + fire_sound = 'sound/weapons/tablehit1.ogg' + auto_rearm = 1 + fire_cooldown = 20 + projectiles_per_shot = 1 + projectile_energy_cost = 40 KILOWATTS + missile_speed = 1 + missile_range = 15 + required_type = /obj/mecha //Why restrict it to just mining or combat mechs? + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flare/Fire(atom/movable/AM, atom/target, turf/aimloc) + var/obj/item/device/flashlight/flare/fired = AM + fired.turn_on() + ..() + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/explosive + name = "\improper SRM-8 missile rack" + icon_state = "mecha_missilerack" + projectile = /obj/item/missile + fire_sound = 'sound/effects/bang.ogg' + projectiles = 8 + projectile_energy_cost = 200 KILOWATTS + equip_cooldown = 60 + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/explosive/Fire(atom/movable/AM, atom/target) + var/obj/item/missile/M = AM + M.primed = 1 + ..() + +/obj/item/missile + icon = 'icons/obj/grenade.dmi' + icon_state = "missile" + var/primed = null + throwforce = 15 + + throw_impact(atom/hit_atom) + if(primed) + explosion(hit_atom, 0, 1, 2, 4) + qdel(src) + else + ..() + return + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang + name = "\improper SGL-6 grenade launcher" + icon_state = "mecha_grenadelnchr" + projectile = /obj/item/weapon/grenade/flashbang + fire_sound = 'sound/effects/bang.ogg' + projectiles = 6 + missile_speed = 1.5 + projectile_energy_cost = 200 KILOWATTS + equip_cooldown = 60 + var/det_time = 20 + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang/Fire(atom/movable/AM, atom/target) + ..() + var/obj/item/weapon/grenade/flashbang/F = AM + spawn(det_time) + F.detonate() + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang/clusterbang//Because I am a heartless bastard -Sieve + name = "\improper SOP-6 grenade launcher" + projectile = /obj/item/weapon/grenade/flashbang/clusterbang + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang/clusterbang/limited/get_equip_info()//Limited version of the clusterbang launcher that can't reload + return "* [chassis.selected==src?"":""][src.name][chassis.selected==src?"":""]\[[src.projectiles]\]" + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang/clusterbang/limited/rearm() + return//Extra bit of security \ No newline at end of file diff --git a/code/game/mecha/mech_bay.dm b/code/game/mecha/mech_bay.dm new file mode 100644 index 00000000..1ca8cc8b --- /dev/null +++ b/code/game/mecha/mech_bay.dm @@ -0,0 +1,123 @@ +/obj/machinery/mech_recharger + name = "mech recharger" + desc = "A mech recharger, built into the floor." + icon = 'icons/mecha/mech_bay.dmi' + icon_state = "recharge_floor" + density = 0 + plane = ABOVE_TURF_PLANE + layer = ABOVE_TILE_LAYER + anchored = 1 + idle_power_usage = 200 // Some electronics, passive drain. + active_power_usage = 60 KILOWATTS // When charging + use_power = 1 + + var/obj/mecha/charging = null + var/base_charge_rate = 60 KILOWATTS + var/repair_power_usage = 10 KILOWATTS // Per 1 HP of health. + var/repair = 0 + +/obj/machinery/mech_recharger/New() + ..() + component_parts = list() + + component_parts += new /obj/item/weapon/circuitboard/mech_recharger(src) + component_parts += new /obj/item/weapon/stock_parts/capacitor(src) + component_parts += new /obj/item/weapon/stock_parts/capacitor(src) + component_parts += new /obj/item/weapon/stock_parts/scanning_module(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + + RefreshParts() + +/obj/machinery/mech_recharger/Crossed(var/obj/mecha/M) + . = ..() + if(istype(M) && charging != M) + start_charging(M) + +/obj/machinery/mech_recharger/Uncrossed(var/obj/mecha/M) + . = ..() + if(M == charging) + stop_charging() + +/obj/machinery/mech_recharger/RefreshParts() + ..() + // Calculates an average rating of components that affect charging rate. + var/chargerate_multiplier = 0 + var/chargerate_divisor = 0 + repair = -5 + for(var/obj/item/weapon/stock_parts/P in component_parts) + if(istype(P, /obj/item/weapon/stock_parts/capacitor)) + chargerate_multiplier += P.rating + chargerate_divisor++ + if(istype(P, /obj/item/weapon/stock_parts/scanning_module)) + chargerate_multiplier += P.rating + chargerate_divisor++ + repair += P.rating + if(istype(P, /obj/item/weapon/stock_parts/manipulator)) + repair += P.rating * 2 + if(chargerate_multiplier) + active_power_usage = base_charge_rate * (chargerate_multiplier / chargerate_divisor) + else + active_power_usage = base_charge_rate + + +/obj/machinery/mech_recharger/Process() + ..() + if(!charging) + use_power = 1 + return + if(charging.loc != loc) + stop_charging() + return + + if(stat & (BROKEN|NOPOWER)) + stop_charging() + charging.occupant_message("Internal System Error - Charging aborted.") + return + + // Cell could have been removed. + if(!charging.cell) + stop_charging() + return + + var/remaining_energy = active_power_usage + + if(repair && !fully_repaired()) + charging.health = min(charging.health + repair, initial(charging.health)) + remaining_energy -= repair * repair_power_usage + if(fully_repaired()) + charging.occupant_message("Fully repaired.") + + if(!charging.cell.fully_charged() && remaining_energy) + charging.give_power(remaining_energy) + if(charging.cell.fully_charged()) + charging.occupant_message("Fully charged.") + + if((!repair || fully_repaired()) && charging.cell.fully_charged()) + stop_charging() + +// An ugly proc, but apparently mechs don't have maxhealth var of any kind. +/obj/machinery/mech_recharger/proc/fully_repaired() + return charging && (charging.health == initial(charging.health)) + +/obj/machinery/mech_recharger/attackby(var/obj/item/I, var/mob/user) + if(default_deconstruction_screwdriver(user, I)) + return + if(default_deconstruction_crowbar(user, I)) + return + if(default_part_replacement(user, I)) + return + +/obj/machinery/mech_recharger/proc/start_charging(var/obj/mecha/M) + if(stat & (NOPOWER | BROKEN)) + M.occupant_message("Power port not responding. Terminating.") + return + + if(M.cell) + M.occupant_message("Now charging...") + charging = M + use_power = 2 + +/obj/machinery/mech_recharger/proc/stop_charging() + use_power = 1 + charging = null diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm new file mode 100644 index 00000000..a6c02a0f --- /dev/null +++ b/code/game/mecha/mech_fabricator.dm @@ -0,0 +1,344 @@ +/obj/machinery/mecha_part_fabricator + icon = 'icons/obj/robotics.dmi' + icon_state = "fab-idle" + name = "Exosuit Fabricator" + desc = "A machine used for construction of robotcs and mechas." + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 20 + active_power_usage = 5000 + req_access = list(access_robotics) + + var/speed = 1 + var/mat_efficiency = 1 + var/list/materials = list(DEFAULT_WALL_MATERIAL = 0, "glass" = 0, "gold" = 0, "silver" = 0, "diamond" = 0, "phoron" = 0, "uranium" = 0) + var/res_max_amount = 200000 + + var/datum/research/files + var/list/datum/design/queue = list() + var/progress = 0 + var/busy = 0 + + var/list/categories = list() + var/category = null + var/manufacturer = null + var/sync_message = "" + +/obj/machinery/mecha_part_fabricator/New() + ..() + + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/mechfab(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) + component_parts += new /obj/item/weapon/stock_parts/console_screen(src) + RefreshParts() + + files = new /datum/research(src) //Setup the research data holder. + return + +/obj/machinery/mecha_part_fabricator/Initialize() + manufacturer = basic_robolimb.company + update_categories() + . = ..() + +/obj/machinery/mecha_part_fabricator/Process() + ..() + if(stat) + return + if(busy) + use_power = 2 + progress += speed + check_build() + else + use_power = 1 + update_icon() + +/obj/machinery/mecha_part_fabricator/update_icon() + overlays.Cut() + if(panel_open) + icon_state = "fab-o" + else + icon_state = "fab-idle" + if(busy) + overlays += "fab-active" + +/obj/machinery/mecha_part_fabricator/dismantle() + for(var/f in materials) + eject_materials(f, -1) + ..() + +/obj/machinery/mecha_part_fabricator/RefreshParts() + res_max_amount = 0 + for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts) + res_max_amount += M.rating * 100000 // 200k -> 600k + var/T = 0 + for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) + T += M.rating + mat_efficiency = 1 - (T - 1) / 4 // 1 -> 0.5 + for(var/obj/item/weapon/stock_parts/micro_laser/M in component_parts) // Not resetting T is intended; speed is affected by both + T += M.rating + speed = T / 2 // 1 -> 3 + +/obj/machinery/mecha_part_fabricator/attack_hand(var/mob/user) + if(..()) + return + if(!allowed(user)) + return + ui_interact(user) + +/obj/machinery/mecha_part_fabricator/ui_interact(var/mob/user, var/ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + + var/datum/design/current = queue.len ? queue[1] : null + if(current) + data["current"] = current.name + data["queue"] = get_queue_names() + data["buildable"] = get_build_options() + data["category"] = category + data["categories"] = categories + if(all_robolimbs) + var/list/T = list() + for(var/A in all_robolimbs) + var/datum/robolimb/R = all_robolimbs[A] + if(R.unavailable_at_fab || R.applies_to_part.len) + continue + T += list(list("id" = A, "company" = R.company)) + data["manufacturers"] = T + data["manufacturer"] = manufacturer + data["materials"] = get_materials() + data["maxres"] = res_max_amount + data["sync"] = sync_message + if(current) + data["builtperc"] = round((progress / current.time) * 100) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "mechfab.tmpl", "Exosuit Fabricator UI", 800, 600) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/mecha_part_fabricator/Topic(href, href_list) + if(..()) + return + + if(href_list["build"]) + add_to_queue(text2num(href_list["build"])) + + if(href_list["remove"]) + remove_from_queue(text2num(href_list["remove"])) + + if(href_list["category"]) + if(href_list["category"] in categories) + category = href_list["category"] + + if(href_list["manufacturer"]) + if(href_list["manufacturer"] in all_robolimbs) + manufacturer = href_list["manufacturer"] + + if(href_list["eject"]) + eject_materials(href_list["eject"], text2num(href_list["amount"])) + + if(href_list["sync"]) + sync() + else + sync_message = "" + + return 1 + +/obj/machinery/mecha_part_fabricator/attackby(var/obj/item/I, var/mob/user) + if(busy) + to_chat(user, "\The [src] is busy. Please wait for completion of previous operation.") + return 1 + if(default_deconstruction_screwdriver(user, I)) + return + if(default_deconstruction_crowbar(user, I)) + return + if(default_part_replacement(user, I)) + return + + if(!istype(I, /obj/item/stack/material)) + return ..() + + var/obj/item/stack/material/stack = I + var/material = stack.material.name + var/stack_singular = "[stack.material.use_name] [stack.material.sheet_singular_name]" // eg "steel sheet", "wood plank" + var/stack_plural = "[stack.material.use_name] [stack.material.sheet_plural_name]" // eg "steel sheets", "wood planks" + var/amnt = stack.perunit + + if(stack.uses_charge) + return + + if(!(material in materials)) + to_chat(user, "\The [src] does not accept [stack_plural]!") + return + + if(materials[material] + amnt <= res_max_amount) + if(stack && stack.amount >= 1) + var/count = 0 + overlays += "fab-load-metal" + spawn(10) + overlays -= "fab-load-metal" + while(materials[material] + amnt <= res_max_amount && stack.amount >= 1) + materials[material] += amnt + stack.use(1) + count++ + to_chat(user, "You insert [count] [count==1 ? stack_singular : stack_plural] into the fabricator.")// 0 steel sheets, 1 steel sheet, 2 steel sheets, etc + + update_busy() + else + to_chat(user, "The fabricator cannot hold more [stack_plural].")// use the plural form even if the given sheet is singular + + +/obj/machinery/mecha_part_fabricator/emag_act(var/remaining_charges, var/mob/user) + switch(emagged) + if(0) + emagged = 0.5 + visible_message("\icon[src] [src] beeps: \"DB error \[Code 0x00F1\]\"") + sleep(10) + visible_message("\icon[src] [src] beeps: \"Attempting auto-repair\"") + sleep(15) + visible_message("\icon[src] [src] beeps: \"User DB corrupted \[Code 0x00FA\]. Truncating data structure...\"") + sleep(30) + visible_message("\icon[src] [src] beeps: \"User DB truncated. Please contact your [GLOB.using_map.company_name] system operator for future assistance.\"") + req_access = null + emagged = 1 + return 1 + if(0.5) + visible_message("\icon[src] [src] beeps: \"DB not responding \[Code 0x0003\]...\"") + if(1) + visible_message("\icon[src] [src] beeps: \"No records in User DB\"") + +/obj/machinery/mecha_part_fabricator/proc/update_busy() + if(queue.len) + if(can_build(queue[1])) + busy = 1 + else + busy = 0 + else + busy = 0 +/obj/machinery/mecha_part_fabricator/proc/add_to_queue(var/index) + var/datum/design/D = files.known_designs[index] + queue += D + update_busy() + +/obj/machinery/mecha_part_fabricator/proc/remove_from_queue(var/index) + if(index == 1) + progress = 0 + queue.Cut(index, index + 1) + update_busy() + +/obj/machinery/mecha_part_fabricator/proc/can_build(var/datum/design/D) + for(var/M in D.materials) + if(materials[M] <= D.materials[M] * mat_efficiency) + return 0 + return 1 + +/obj/machinery/mecha_part_fabricator/proc/check_build() + if(!queue.len) + progress = 0 + return + var/datum/design/D = queue[1] + if(!can_build(D)) + progress = 0 + return + if(D.time > progress) + return + for(var/M in D.materials) + materials[M] = max(0, materials[M] - D.materials[M] * mat_efficiency) + if(D.build_path) + var/obj/new_item = D.Fabricate(loc, src) + visible_message("\The [src] pings, indicating that \the [D] is complete.", "You hear a ping.") + if(mat_efficiency != 1) + if(new_item.matter && new_item.matter.len > 0) + for(var/i in new_item.matter) + new_item.matter[i] = new_item.matter[i] * mat_efficiency + remove_from_queue(1) + +/obj/machinery/mecha_part_fabricator/proc/get_queue_names() + . = list() + for(var/i = 2 to queue.len) + var/datum/design/D = queue[i] + . += D.name + +/obj/machinery/mecha_part_fabricator/proc/get_build_options() + . = list() + for(var/i = 1 to files.known_designs.len) + var/datum/design/D = files.known_designs[i] + if(!D.build_path || !(D.build_type & MECHFAB)) + continue + . += list(list("name" = D.name, "id" = i, "category" = D.category, "resourses" = get_design_resourses(D), "time" = get_design_time(D))) + +/obj/machinery/mecha_part_fabricator/proc/get_design_resourses(var/datum/design/D) + var/list/F = list() + for(var/T in D.materials) + F += "[capitalize(T)]: [D.materials[T] * mat_efficiency]" + return english_list(F, and_text = ", ") + +/obj/machinery/mecha_part_fabricator/proc/get_design_time(var/datum/design/D) + return time2text(round(10 * D.time / speed), "mm:ss") + +/obj/machinery/mecha_part_fabricator/proc/update_categories() + categories = list() + for(var/datum/design/D in files.known_designs) + if(!D.build_path || !(D.build_type & MECHFAB)) + continue + categories |= D.category + if(!category || !(category in categories)) + category = categories[1] + +/obj/machinery/mecha_part_fabricator/proc/get_materials() + . = list() + for(var/T in materials) + . += list(list("mat" = capitalize(T), "amt" = materials[T])) + +/obj/machinery/mecha_part_fabricator/proc/eject_materials(var/material, var/amount) // 0 amount = 0 means ejecting a full stack; -1 means eject everything + var/recursive = amount == -1 ? 1 : 0 + material = lowertext(material) + var/mattype + switch(material) + if(DEFAULT_WALL_MATERIAL) + mattype = /obj/item/stack/material/steel + if("glass") + mattype = /obj/item/stack/material/glass + if("gold") + mattype = /obj/item/stack/material/gold + if("silver") + mattype = /obj/item/stack/material/silver + if("diamond") + mattype = /obj/item/stack/material/diamond + if("phoron") + mattype = /obj/item/stack/material/phoron + if("uranium") + mattype = /obj/item/stack/material/uranium + else + return + var/obj/item/stack/material/S = new mattype(loc) + if(amount <= 0) + amount = S.max_amount + var/ejected = min(round(materials[material] / S.perunit), amount) + S.amount = min(ejected, amount) + if(S.amount <= 0) + qdel(S) + return + materials[material] -= ejected * S.perunit + if(recursive && materials[material] >= S.perunit) + eject_materials(material, -1) + update_busy() + +/obj/machinery/mecha_part_fabricator/proc/sync() + sync_message = "Error: no console found." + for(var/obj/machinery/computer/rdconsole/RDC in get_area_all_atoms(get_area(src))) + if(!RDC.sync) + continue + for(var/datum/tech/T in RDC.files.known_tech) + files.AddTech2Known(T) + for(var/datum/design/D in RDC.files.known_designs) + files.AddDesign2Known(D) + files.RefreshResearch() + sync_message = "Sync complete." + update_categories() diff --git a/code/game/mecha/mech_sensor.dm b/code/game/mecha/mech_sensor.dm new file mode 100644 index 00000000..36a14d79 --- /dev/null +++ b/code/game/mecha/mech_sensor.dm @@ -0,0 +1,89 @@ +/obj/machinery/mech_sensor + icon = 'icons/obj/airlock_machines.dmi' + icon_state = "airlock_sensor_off" + name = "mechatronic sensor" + desc = "Regulates mech movement." + anchored = 1 + density = 1 + throwpass = 1 + use_power = 1 + layer = ABOVE_WINDOW_LAYER + power_channel = EQUIP + var/on = 0 + var/id_tag = null + + var/frequency = 1379 + var/datum/radio_frequency/radio_connection + +/obj/machinery/mech_sensor/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(!src.enabled()) return 1 + if(air_group || (height==0)) return 1 + + if ((get_dir(loc, target) & dir) && src.is_blocked(mover)) + src.give_feedback(mover) + return 0 + return 1 + +/obj/machinery/mech_sensor/proc/is_blocked(O as obj) + if(istype(O, /obj/mecha/medical/odysseus)) + var/obj/mecha/medical/odysseus/M = O + for(var/obj/item/mecha_parts/mecha_equipment/ME in M.equipment) + if(istype(ME, /obj/item/mecha_parts/mecha_equipment/tool/sleeper)) + var/obj/item/mecha_parts/mecha_equipment/tool/sleeper/S = ME + if(S.occupant != null) + return 0 + + return istype(O, /obj/mecha) || istype(O, /obj/vehicle) + +/obj/machinery/mech_sensor/proc/give_feedback(O as obj) + var/block_message = "Movement control overridden. Area denial active." + var/feedback_timer = 0 + if(feedback_timer) + return + + if(istype(O, /obj/mecha)) + var/obj/mecha/R = O + if(R && R.occupant) + to_chat(R.occupant, block_message) + else if(istype(O, /obj/vehicle/train/cargo/engine)) + var/obj/vehicle/train/cargo/engine/E = O + if(E && E.load && E.is_train_head()) + to_chat(E.load, block_message) + + feedback_timer = 1 + spawn(50) //Without this timer the feedback becomes horribly spamy + feedback_timer = 0 + +/obj/machinery/mech_sensor/proc/enabled() + return on && !(stat & NOPOWER) + +/obj/machinery/mech_sensor/update_icon(var/safety = 0) + if (enabled()) + icon_state = "airlock_sensor_standby" + else + icon_state = "airlock_sensor_off" + +/obj/machinery/mech_sensor/Initialize() + . = ..() + set_frequency(frequency) + +/obj/machinery/mech_sensor/proc/set_frequency(new_frequency) + if(radio_connection) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency) + +/obj/machinery/mech_sensor/receive_signal(datum/signal/signal) + if(stat & NOPOWER) + return + + if(!signal.data["tag"] || (signal.data["tag"] != id_tag)) + return + + if(signal.data["command"] == "enable") + on = 1 + else if (signal.data["command"] == "disable") + on = 0 + + update_icon() diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm new file mode 100644 index 00000000..34a2b2b5 --- /dev/null +++ b/code/game/mecha/mecha.dm @@ -0,0 +1,1856 @@ +#define MECHA_INT_FIRE 1 +#define MECHA_INT_TEMP_CONTROL 2 +#define MECHA_INT_SHORT_CIRCUIT 4 +#define MECHA_INT_TANK_BREACH 8 +#define MECHA_INT_CONTROL_LOST 16 + +#define MELEE 1 +#define RANGED 2 + + +/obj/mecha + name = "Mecha" + desc = "An exosuit." + icon = 'icons/mecha/mecha.dmi' + density = 1 //Dense. To raise the heat. + opacity = 1 ///opaque. Menacing. + anchored = 1 //no pulling around. + unacidable = 1 //and no deleting hoomans inside + plane = OBJ_PLANE + layer = ABOVE_WINDOW_LAYER //icon draw layer + infra_luminosity = 15 //byond implementation is bugged. + anchor_fall = TRUE + w_class = ITEM_SIZE_NO_CONTAINER + var/initial_icon = null //Mech type for resetting icon. Only used for reskinning kits (see custom items) + var/can_move = 1 + var/mob/living/carbon/occupant = null + var/list/dropped_items = list() + var/step_in = 10 //make a step in step_in/10 sec. + var/dir_in = 2//What direction will the mech face when entered/powered on? Defaults to South. + var/step_energy_drain = 200 // Energy usage per step in joules. + var/health = 300 //health is health + var/deflect_chance = 10 //chance to deflect incoming projectiles, hits, or lesser the effect of ex_act. + var/r_deflect_coeff = 1 + var/m_deflect_coeff = 1 + //ranged and melee damage multipliers + var/r_damage_coeff = 1 + var/m_damage_coeff = 1 + var/rhit_power_use = 0 + var/mhit_power_use = 0 + + //the values in this list show how much damage will pass through, not how much will be absorbed. + var/list/damage_absorption = list("brute"=0.8,"fire"=1.2,"bullet"=0.9,"laser"=1,"energy"=1,"bomb"=1) + var/obj/item/weapon/cell/cell + var/state = 0 + var/list/log = new + var/last_message = 0 + var/add_req_access = 1 + var/maint_access = 1 + var/dna //dna-locking the mech + var/datum/effect/effect/system/spark_spread/spark_system = new + var/lights = 0 + var/lights_power = 6 + var/force = 0 + + //inner atmos + var/use_internal_tank = 0 + var/internal_tank_valve = ONE_ATMOSPHERE + var/obj/machinery/portable_atmospherics/canister/internal_tank + var/datum/gas_mixture/cabin_air + var/obj/machinery/atmospherics/portables_connector/connected_port = null + + var/obj/item/device/radio/radio = null + + var/max_temperature = 25000 + var/internal_damage_threshold = 50 //health percentage below which internal damage is possible + var/internal_damage = 0 //contains bitflags + + var/list/operation_req_access = list()//required access level for mecha operation + var/list/internals_req_access = list(access_engine,access_robotics)//required access level to open cell compartment + + var/datum/global_iterator/pr_int_temp_processor //normalizes internal air mixture temperature + var/datum/global_iterator/pr_inertial_movement //controls intertial movement in spesss + var/datum/global_iterator/pr_give_air //moves air from tank to cabin + var/datum/global_iterator/pr_internal_damage //processes internal damage + + + var/wreckage + + var/list/equipment = new + var/obj/item/mecha_parts/mecha_equipment/selected + var/max_equip = 3 + var/datum/events/events + +/obj/mecha/drain_power(var/drain_check) + + if(drain_check) + return 1 + + if(!cell) + return 0 + + return cell.drain_power(drain_check) + +/obj/mecha/New() + ..() + events = new + + icon_state += "-open" + add_radio() + add_cabin() + add_airtank() //All mecha currently have airtanks. No need to check unless changes are made. + spark_system.set_up(2, 0, src) + spark_system.attach(src) + add_cell() + add_iterators() + removeVerb(/obj/mecha/verb/disconnect_from_port) + log_message("[src.name] created.") + loc.Entered(src) + mechas_list += src //global mech list + return + +/obj/mecha/Destroy() + src.go_out() + for(var/mob/M in src) //Let's just be ultra sure + M.Move(loc) + + if(loc) + loc.Exited(src) + + if(prob(30)) + explosion(get_turf(loc), 0, 0, 1, 3) + + if(wreckage) + var/obj/effect/decal/mecha_wreckage/WR = new wreckage(loc) + for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) + if(E.salvageable && prob(30)) + WR.crowbar_salvage += E + E.forceMove(WR) + E.equip_ready = 1 + else + E.forceMove(loc) + E.destroy() + if(cell) + WR.crowbar_salvage += cell + cell.forceMove(WR) + cell.charge = rand(0, cell.charge) + if(internal_tank) + WR.crowbar_salvage += internal_tank + internal_tank.forceMove(WR) + else + for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) + E.detach(loc) + E.destroy() + if(cell) + qdel(cell) + if(internal_tank) + qdel(internal_tank) + equipment.Cut() + cell = null + internal_tank = null + + QDEL_NULL(pr_int_temp_processor) + QDEL_NULL(pr_inertial_movement) + QDEL_NULL(pr_give_air) + QDEL_NULL(pr_internal_damage) + QDEL_NULL(spark_system) + + mechas_list -= src //global mech list + . = ..() + +//////////////////////// +////// Helpers ///////// +//////////////////////// + +/obj/mecha/proc/removeVerb(verb_path) + verbs -= verb_path + +/obj/mecha/proc/addVerb(verb_path) + verbs += verb_path + +/obj/mecha/proc/add_airtank() + internal_tank = new /obj/machinery/portable_atmospherics/canister/air(src) + return internal_tank + +/obj/mecha/proc/add_cell() + cell = new /obj/item/weapon/cell/mecha(src) + +/obj/mecha/proc/add_cabin() + cabin_air = new + cabin_air.temperature = T20C + cabin_air.volume = 200 + cabin_air.adjust_multi("oxygen", O2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature), "nitrogen", N2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature)) + return cabin_air + +/obj/mecha/proc/add_radio() + radio = new(src) + radio.SetName("[src] radio") + radio.icon = icon + radio.icon_state = icon_state + radio.subspace_transmission = 1 + +/obj/mecha/proc/add_iterators() + pr_int_temp_processor = new /datum/global_iterator/mecha_preserve_temp(list(src)) + pr_inertial_movement = new /datum/global_iterator/mecha_inertial_movement(null,0) + pr_give_air = new /datum/global_iterator/mecha_tank_give_air(list(src)) + pr_internal_damage = new /datum/global_iterator/mecha_internal_damage(list(src),0) + +/obj/mecha/proc/do_after(delay as num) + sleep(delay) + if(src) + return 1 + return 0 + +/obj/mecha/proc/enter_after(delay as num, var/mob/user as mob, var/numticks = 5) + var/delayfraction = delay/numticks + + var/turf/T = user.loc + + for(var/i = 0, iMaintenance protocols in effect.
            ") + return + if(!get_charge()) return + if(src == target) return + var/dir_to_target = get_dir(src,target) + if(dir_to_target && !(dir_to_target & src.dir)) + return + if(hasInternalDamage(MECHA_INT_CONTROL_LOST)) + target = safepick(view(3,target)) + if(!target) + return + if(istype(target, /obj/machinery)) + if (src.interface_action(target)) + return + if(!target.Adjacent(src)) + if(selected && selected.is_ranged()) + selected.action(target) + else if(selected && selected.is_melee()) + selected.action(target) + else + src.melee_action(target) + return + +/obj/mecha/proc/interface_action(obj/machinery/target) + if(istype(target, /obj/machinery/access_button) && target.Adjacent(src)) + src.occupant_message("Interfacing with [target].") + src.log_message("Interfaced with [target].") + target.attack_hand(src.occupant) + return 1 + if(istype(target, /obj/machinery/embedded_controller)) + if(target in view(2,src)) + src.occupant_message("Interfacing with [target]...") + src.log_message("Interfaced with [target].") + target.ui_interact(src.occupant) + else + src.occupant_message("Unable to interface with [target], target out of range.") + return 1 + return 0 + +/obj/mecha/contents_nano_distance(var/src_object, var/mob/living/user) + . = user.shared_living_nano_distance(src_object) //allow them to interact with anything they can interact with normally. + if(. != STATUS_INTERACTIVE) + //Allow interaction with the mecha or anything that is part of the mecha + if(src_object == src || (src_object in src)) + return STATUS_INTERACTIVE + if(src.Adjacent(src_object)) + return STATUS_INTERACTIVE + if(src_object in view(2, src)) + return STATUS_UPDATE //if they're close enough, allow the occupant to see the screen through the viewport or whatever. + +/obj/mecha/proc/melee_action(atom/target) + return + +/obj/mecha/proc/range_action(atom/target) + return + + +////////////////////////////////// +//////// Movement procs //////// +////////////////////////////////// + +/obj/mecha/Move() + . = ..() + if(.) + events.fireEvent("onMove",get_turf(src)) + return + +/obj/mecha/relaymove(mob/user,direction) + if(user != src.occupant) //While not "realistic", this piece is player friendly. + user.forceMove(get_turf(src)) + to_chat(user, "You climb out from [src]") + return 0 + if(connected_port) + if(world.time - last_message > 20) + src.occupant_message("Unable to move while connected to the air system port.") + last_message = world.time + return 0 + if(state) + occupant_message("Maintenance protocols in effect.") + return + return do_move(direction) + +/obj/mecha/proc/do_move(direction) + if(!can_move) + return 0 + if(src.pr_inertial_movement.active()) + return 0 + if(!has_charge(step_energy_drain)) + return 0 + var/move_result = 0 + if(hasInternalDamage(MECHA_INT_CONTROL_LOST)) + move_result = mechsteprand() + else if(src.dir!=direction) + move_result = mechturn(direction) + else + move_result = mechstep(direction) + if(move_result) + can_move = 0 + use_power(step_energy_drain) + if(istype(src.loc, /turf/space)) + if(!src.check_for_support()) + src.pr_inertial_movement.start(list(src,direction)) + src.log_message("Movement control lost. Inertial movement started.") + if(do_after(step_in)) + can_move = 1 + return 1 + return 0 + +/obj/mecha/proc/mechturn(direction) + set_dir(direction) + playsound(src,'sound/mecha/mechturn.ogg',40,1) + return 1 + +/obj/mecha/proc/mechstep(direction) + var/result = step(src,direction) + if(result) + playsound(src,'sound/mecha/mechstep.ogg',40,1) + return result + + +/obj/mecha/proc/mechsteprand() + var/result = step_rand(src) + if(result) + playsound(src,'sound/mecha/mechstep.ogg',40,1) + return result + +/obj/mecha/Bump(var/atom/obstacle) +// src.inertia_dir = null + if(istype(obstacle, /obj)) + var/obj/O = obstacle + if(istype(O, /obj/effect/portal)) //derpfix + src.anchored = 0 + O.Crossed(src) + spawn(0)//countering portal teleport spawn(0), hurr + src.anchored = 1 + else if(!O.anchored) + step(obstacle,src.dir) + else //I have no idea why I disabled this + obstacle.Bumped(src) + else if(istype(obstacle, /mob)) + step(obstacle,src.dir) + else + obstacle.Bumped(src) + return + +/////////////////////////////////// +//////// Internal damage //////// +/////////////////////////////////// + +/obj/mecha/proc/check_for_internal_damage(var/list/possible_int_damage,var/ignore_threshold=null) + if(!islist(possible_int_damage) || isemptylist(possible_int_damage)) return + if(prob(20)) + if(ignore_threshold || src.health*100/initial(src.health)Life support system reactivated.") + pr_int_temp_processor.start() + if(MECHA_INT_FIRE) + occupant_message("Internal fire extinquished.") + if(MECHA_INT_TANK_BREACH) + occupant_message("Damaged internal tank has been sealed.") + return + + +//////////////////////////////////////// +//////// Health related procs //////// +//////////////////////////////////////// + +/obj/mecha/proc/take_damage(amount, type="brute") + if(amount) + var/damage = absorb_damage(amount,type) + health -= damage + update_health() + log_append_to_last("Took [damage] points of damage. Damage type: \"[type]\".",1) + return + +/obj/mecha/proc/absorb_damage(damage,damage_type) + return damage*(listgetindex(damage_absorption,damage_type) || 1) + +/obj/mecha/proc/hit_damage(damage, type="brute", is_melee=0) + + var/power_to_use + var/damage_coeff_to_use + + if(is_melee) + power_to_use = mhit_power_use + damage_coeff_to_use = m_damage_coeff + else + power_to_use = rhit_power_use + damage_coeff_to_use = r_damage_coeff + + if(power_to_use && use_power(power_to_use)) + take_damage(round(damage*damage_coeff_to_use), type) + start_booster_cooldown(is_melee) + return + else + start_booster_cooldown(is_melee) + take_damage(round(damage*damage_coeff_to_use), type) + + return + +/obj/mecha/proc/deflect_hit(is_melee=0) + + var/power_to_use + var/deflect_coeff_to_use + + if(is_melee) + power_to_use = mhit_power_use + deflect_coeff_to_use = m_damage_coeff + else + power_to_use = rhit_power_use + deflect_coeff_to_use = r_damage_coeff + + if(power_to_use) + if(prob(src.deflect_chance*deflect_coeff_to_use)) + use_power(power_to_use) + start_booster_cooldown(is_melee) + return 1 + else + return 0 + + else + start_booster_cooldown(is_melee) + if(prob(src.deflect_chance*deflect_coeff_to_use)) + return 1 + + return 0 + +/obj/mecha/proc/start_booster_cooldown(is_melee) + + for(var/obj/item/mecha_parts/mecha_equipment/armor_booster/B in equipment) //Ideally this would be done by the armor booster itself; attempts weren't great for performance. + if(B.melee == is_melee && B.equip_ready) + B.set_ready_state(0) + B.do_after_cooldown() + +/obj/mecha/airlock_crush(var/crush_damage) + ..() + hit_damage(crush_damage, is_melee=1) + check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) + return 1 + +/obj/mecha/proc/update_health() + if(src.health > 0) + src.spark_system.start() + else + qdel(src) + return + +/obj/mecha/attack_hand(mob/user as mob) + src.log_message("Attack by hand/paw. Attacker - [user].",1) + + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(H.species.can_shred(user)) + if(!deflect_hit(is_melee=1)) + src.hit_damage(damage=15, is_melee=1) + src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) + playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1, -1) + to_chat(user, "You slash at the armored suit!") + visible_message("\The [user] slashes at [src.name]'s armor!") + else + src.log_append_to_last("Armor saved.") + playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1, -1) + to_chat(user, "Your claws had no effect!") + src.occupant_message("\The [user]'s claws are stopped by the armor.") + visible_message("\The [user] rebounds off [src.name]'s armor!") + else + user.visible_message("\The [user] hits \the [src]. Nothing happens.","You hit \the [src] with no visible effect.") + src.log_append_to_last("Armor saved.") + return + else if ((HULK in user.mutations) && !deflect_hit(is_melee=1)) + src.hit_damage(damage=15, is_melee=1) + src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) + user.visible_message("[user] hits [src.name], doing some damage.", "You hit [src.name] with all your might. The metal creaks and bends.") + else + user.visible_message("[user] hits [src.name]. Nothing happens","You hit [src.name] with no visible effect.") + src.log_append_to_last("Armor saved.") + return + +/obj/mecha/hitby(atom/movable/A as mob|obj) + ..() + src.log_message("Hit by [A].",1) + if(istype(A, /obj/item/mecha_parts/mecha_tracking)) + A.forceMove(src) + src.visible_message("The [A] fastens firmly to [src].") + return + if(deflect_hit(is_melee=0) || istype(A, /mob)) + src.occupant_message("\The [A] bounces off the armor.") + src.visible_message("\The [A] bounces off \the [src] armor.") + src.log_append_to_last("Armor saved.") + if(istype(A, /mob/living)) + var/mob/living/M = A + M.take_organ_damage(10) + else if(istype(A, /obj)) + var/obj/O = A + if(O.throwforce) + src.hit_damage(O.throwforce, is_melee=0) + src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) + return + +/obj/mecha/bullet_act(var/obj/item/projectile/Proj) + if(Proj.damage_type == PAIN && !(src.r_deflect_coeff > 1)) + use_power(Proj.agony * 5) + + src.log_message("Hit by projectile. Type: [Proj.name]([Proj.check_armour]).",1) + if(deflect_hit(is_melee=0)) + src.occupant_message("The armor deflects incoming projectile.") + src.visible_message("The [src.name] armor deflects the projectile.") + src.log_append_to_last("Armor saved.") + return + + if(!(Proj.nodamage)) + var/ignore_threshold + if(istype(Proj, /obj/item/projectile/beam/pulse)) + ignore_threshold = 1 + src.hit_damage(Proj.damage, Proj.check_armour, is_melee=0) + if(prob(25)) spark_system.start() + src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),ignore_threshold) + + //AP projectiles have a chance to cause additional damage + if(Proj.penetrating) + var/distance = get_dist(Proj.starting, get_turf(loc)) + var/hit_occupant = 1 //only allow the occupant to be hit once + for(var/i in 1 to min(Proj.penetrating, round(Proj.damage/15))) + if(src.occupant && hit_occupant && prob(20)) + Proj.attack_mob(src.occupant, distance) + hit_occupant = 0 + else + src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT), 1) + + Proj.penetrating-- + + if(prob(15)) + break //give a chance to exit early + + Proj.on_hit(src) //on_hit just returns if it's argument is not a living mob so does this actually do anything? + ..() + return + +/obj/mecha/ex_act(severity) + src.log_message("Affected by explosion of severity: [severity].",1) + if(prob(src.deflect_chance)) + severity++ + src.log_append_to_last("Armor saved, changing severity to [severity].") + switch(severity) + if(1.0) + qdel(src) + if(2.0) + if (prob(30)) + qdel(src) + else + src.take_damage(initial(src.health)/2) + src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),1) + if(3.0) + if (prob(5)) + qdel(src) + else + src.take_damage(initial(src.health)/5) + src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),1) + return + +/*Will fix later -Sieve +/obj/mecha/attack_blob(mob/user as mob) + src.log_message("Attack by blob. Attacker - [user].",1) + if(!prob(src.deflect_chance)) + src.take_damage(6) + src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) + playsound(src.loc, 'sound/effects/blobattack.ogg', 50, 1, -1) + to_chat(user, "You smash at the armored suit!") + for (var/mob/V in viewers(src)) + if(V.client && !(V.blinded)) + V.show_message("\The [user] smashes against [src.name]'s armor!", 1) + else + src.log_append_to_last("Armor saved.") + playsound(src.loc, 'sound/effects/blobattack.ogg', 50, 1, -1) + to_chat(user, "Your attack had no effect!") + src.occupant_message("\The [user]'s attack is stopped by the armor.") + for (var/mob/V in viewers(src)) + if(V.client && !(V.blinded)) + V.show_message("\The [user] rebounds off the [src.name] armor!", 1) + return +*/ + +/obj/mecha/emp_act(severity) + if(use_power((cell.charge/2)/severity)) + take_damage(50 / severity,"energy") + src.log_message("EMP detected",1) + check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),1) + return + +/obj/mecha/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature>src.max_temperature) + src.log_message("Exposed to dangerous temperature.",1) + src.take_damage(5,"fire") + src.check_for_internal_damage(list(MECHA_INT_FIRE, MECHA_INT_TEMP_CONTROL)) + return + + +////////////////////// +////// AttackBy ////// +////////////////////// + +/obj/mecha/attackby(obj/item/weapon/W as obj, mob/user as mob) + + if(istype(W, /obj/item/mecha_parts/mecha_equipment)) + var/obj/item/mecha_parts/mecha_equipment/E = W + spawn() + if(E.can_attach(src)) + user.drop_item() + E.attach(src) + user.visible_message("[user] attaches [W] to [src]", "You attach [W] to [src]") + else + to_chat(user, "You were unable to attach [W] to [src]") + return + + var/obj/item/weapon/card/id/id_card = W.GetIdCard() + if(id_card) + if(add_req_access || maint_access) + if(internals_access_allowed(usr)) + output_maintenance_dialog(id_card, user) + return + else + to_chat(user, "Invalid ID: Access denied.") + else + to_chat(user, "Maintenance protocols disabled by operator.") + else if(isWrench(W)) + if(state==1) + state = 2 + to_chat(user, "You undo the securing bolts.") + else if(state==2) + state = 1 + to_chat(user, "You tighten the securing bolts.") + return + else if(isCrowbar(W)) + if(state==2) + state = 3 + to_chat(user, "You open the hatch to the power unit") + else if(state==3) + state=2 + to_chat(user, "You close the hatch to the power unit") + return + else if(isCoil(W)) + if(state == 3 && hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) + var/obj/item/stack/cable_coil/CC = W + if(CC.use(2)) + clearInternalDamage(MECHA_INT_SHORT_CIRCUIT) + to_chat(user, "You replace the fused wires.") + else + to_chat(user, "There's not enough wire to finish the task.") + return + else if(isScrewdriver(W)) + if(hasInternalDamage(MECHA_INT_TEMP_CONTROL)) + clearInternalDamage(MECHA_INT_TEMP_CONTROL) + to_chat(user, "You repair the damaged temperature controller.") + else if(state==3 && src.cell) + src.cell.forceMove(src.loc) + src.cell = null + state = 4 + to_chat(user, "You unscrew and pry out the powercell.") + src.log_message("Powercell removed.") + else if(state==4 && src.cell) + state=3 + to_chat(user, "You screw the cell in place.") + return + + else if(isMultitool(W)) + if(state>=3 && src.occupant) + to_chat(user, "You attempt to eject the pilot using the maintenance controls.") + if(src.occupant.stat) + src.go_out() + src.log_message("[src.occupant] was ejected using the maintenance controls.") + else + to_chat(user, "Your attempt is rejected.") + src.occupant_message("An attempt to eject you was made using the maintenance controls.") + src.log_message("Eject attempt made using maintenance controls - rejected.") + return + + else if(istype(W, /obj/item/weapon/cell)) + if(state==4) + if(!src.cell) + to_chat(user, "You install the powercell") + user.drop_item() + W.forceMove(src) + src.cell = W + src.log_message("Powercell installed") + else + to_chat(user, "There's already a powercell installed.") + return + + else if(isWelder(W) && user.a_intent != I_HURT) + var/obj/item/weapon/weldingtool/WT = W + if (WT.remove_fuel(0,user)) + if (hasInternalDamage(MECHA_INT_TANK_BREACH)) + clearInternalDamage(MECHA_INT_TANK_BREACH) + to_chat(user, "You repair the damaged gas tank.") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + else + return + if(src.healthYou repair some damage to [src.name].") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + src.health += min(10, initial(src.health)-src.health) + else + to_chat(user, "The [src.name] is at full integrity") + return + + else if(istype(W, /obj/item/mecha_parts/mecha_tracking)) + user.drop_from_inventory(W) + W.forceMove(src) + user.visible_message("[user] attaches [W] to [src].", "You attach [W] to [src]") + return + + else + src.log_message("Attacked by [W]. Attacker - [user]") + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(deflect_hit(is_melee=1)) + to_chat(user, "\The [W] bounces off [src.name].") + src.log_append_to_last("Armor saved.") + else + src.occupant_message("[user] hits [src] with [W].") + user.visible_message("[user] hits [src] with [W].", "You hit [src] with [W].") + src.hit_damage(W.force, W.damtype, is_melee=1) + src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) + + return + +/* +/obj/mecha/attack_ai(var/mob/living/silicon/ai/user as mob) + if(!istype(user, /mob/living/silicon/ai)) + return + var/output = {"Assume direct control over [src]? + Yes
            + "} + user << browse(output, "window=mecha_attack_ai") + return +*/ + +///////////////////////////////////// +//////// Atmospheric stuff //////// +///////////////////////////////////// + +/obj/mecha/proc/get_turf_air() + var/turf/T = get_turf(src) + if(T) + . = T.return_air() + return + +/obj/mecha/remove_air(amount) + if(use_internal_tank) + return cabin_air.remove(amount) + else + var/turf/T = get_turf(src) + if(T) + return T.remove_air(amount) + return + +/obj/mecha/return_air() + if(use_internal_tank) + return cabin_air + return get_turf_air() + +/obj/mecha/proc/return_pressure() + . = 0 + if(use_internal_tank) + . = cabin_air.return_pressure() + else + var/datum/gas_mixture/t_air = get_turf_air() + if(t_air) + . = t_air.return_pressure() + return + +//skytodo: //No idea what you want me to do here, mate. +/obj/mecha/proc/return_temperature() + . = 0 + if(use_internal_tank) + . = cabin_air.temperature + else + var/datum/gas_mixture/t_air = get_turf_air() + if(t_air) + . = t_air.temperature + return + +/obj/mecha/proc/connect(obj/machinery/atmospherics/portables_connector/new_port) + //Make sure not already connected to something else + if(connected_port || !new_port || new_port.connected_device) + return 0 + + //Make sure are close enough for a valid connection + if(new_port.loc != src.loc) + return 0 + + //Perform the connection + connected_port = new_port + connected_port.connected_device = src + + //Actually enforce the air sharing + var/datum/pipe_network/network = connected_port.return_network(src) + if(network && !(internal_tank.return_air() in network.gases)) + network.gases += internal_tank.return_air() + network.update = 1 + log_message("Connected to gas port.") + return 1 + +/obj/mecha/proc/disconnect() + if(!connected_port) + return 0 + + var/datum/pipe_network/network = connected_port.return_network(src) + if(network) + network.gases -= internal_tank.return_air() + + connected_port.connected_device = null + connected_port = null + src.log_message("Disconnected from gas port.") + return 1 + + +///////////////////////// +//////// Verbs //////// +///////////////////////// + + +/obj/mecha/verb/connect_to_port() + set name = "Connect to port" + set category = "Exosuit Interface" + set src = usr.loc + set popup_menu = 0 + if(!src.occupant) return + if(usr!=src.occupant) + return + var/obj/machinery/atmospherics/portables_connector/possible_port = locate(/obj/machinery/atmospherics/portables_connector/) in loc + if(possible_port) + if(connect(possible_port)) + src.occupant_message("\The [name] connects to the port.") + src.verbs += /obj/mecha/verb/disconnect_from_port + src.verbs -= /obj/mecha/verb/connect_to_port + return + else + src.occupant_message("\The [name] failed to connect to the port.") + return + else + src.occupant_message("Nothing happens") + + +/obj/mecha/verb/disconnect_from_port() + set name = "Disconnect from port" + set category = "Exosuit Interface" + set src = usr.loc + set popup_menu = 0 + if(!src.occupant) return + if(usr!=src.occupant) + return + if(disconnect()) + src.occupant_message("[name] disconnects from the port.") + src.verbs -= /obj/mecha/verb/disconnect_from_port + src.verbs += /obj/mecha/verb/connect_to_port + else + src.occupant_message("[name] is not connected to the port at the moment.") + +/obj/mecha/verb/toggle_lights() + set name = "Toggle Lights" + set category = "Exosuit Interface" + set src = usr.loc + set popup_menu = 0 + if(usr!=occupant) return + lights = !lights + if(lights) set_light(light_range + lights_power) + else set_light(light_range - lights_power) + src.occupant_message("Toggled lights [lights?"on":"off"].") + log_message("Toggled lights [lights?"on":"off"].") + return + + +/obj/mecha/verb/toggle_internal_tank() + set name = "Toggle internal airtank usage." + set category = "Exosuit Interface" + set src = usr.loc + set popup_menu = 0 + if(usr!=src.occupant) + return + use_internal_tank = !use_internal_tank + src.occupant_message("Now taking air from [use_internal_tank?"internal airtank":"environment"].") + src.log_message("Now taking air from [use_internal_tank?"internal airtank":"environment"].") + return + + +/obj/mecha/verb/move_inside() + set category = "Object" + set name = "Enter Exosuit" + set src in oview(1) + + if (usr.stat || !ishuman(usr)) + return + + if (usr.buckled) + to_chat(usr, "You can't climb into the exosuit while buckled!") + return + + src.log_message("[usr] tries to move in.") + if(iscarbon(usr)) + var/mob/living/carbon/C = usr + if(C.handcuffed) + to_chat(usr, "Kinda hard to climb in while handcuffed don't you think?") + return + if (src.occupant) + to_chat(usr, "The [src.name] is already occupied!") + src.log_append_to_last("Permission denied.") + return +/* + if (usr.abiotic()) + to_chat(usr, "Subject cannot have abiotic items on.") + return +*/ + var/passed + if(src.dna) + if(usr.dna.unique_enzymes==src.dna) + passed = 1 + else if(src.operation_allowed(usr)) + passed = 1 + if(!passed) + to_chat(usr, "Access denied") + src.log_append_to_last("Permission denied.") + return + for(var/mob/living/carbon/slime/M in range(1,usr)) + if(M.Victim == usr) + to_chat(usr, "You're too busy getting your life sucked out of you.") + return +// to_chat(usr, "You start climbing into [src.name]") + + visible_message("\The [usr] starts to climb into [src.name]") + + if(enter_after(40,usr)) + if(!src.occupant) + moved_inside(usr) + else if(src.occupant!=usr) + to_chat(usr, "[src.occupant] was faster. Try better next time, loser.") + else + to_chat(usr, "You stop entering the exosuit.") + return + +/obj/mecha/proc/moved_inside(var/mob/living/carbon/human/H as mob) + if(H && H.client && H in range(1)) + H.reset_view(src) + /* + H.client.perspective = EYE_PERSPECTIVE + H.client.eye = src + */ + H.stop_pulling() + H.forceMove(src) + src.occupant = H + src.add_fingerprint(H) + src.forceMove(src.loc) + src.log_append_to_last("[H] moved in as pilot.") + src.icon_state = src.reset_icon() + set_dir(dir_in) + playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) + if(!hasInternalDamage()) + to_chat(src.occupant, sound('sound/mecha/nominal.ogg',volume=50)) + return 1 + else + return 0 + +/obj/mecha/verb/view_stats() + set name = "View Stats" + set category = "Exosuit Interface" + set src = usr.loc + set popup_menu = 0 + if(usr!=src.occupant) + return + //pr_update_stats.start() + src.occupant << browse(src.get_stats_html(), "window=exosuit") + return + +/* +/obj/mecha/verb/force_eject() + set category = "Object" + set name = "Force Eject" + set src in view(5) + src.go_out() + return +*/ + +/obj/mecha/verb/eject() + set name = "Eject" + set category = "Exosuit Interface" + set src = usr.loc + set popup_menu = 0 + if(usr!=src.occupant) + return + src.go_out() + add_fingerprint(usr) + return + + +/obj/mecha/proc/go_out() + if(!src.occupant) return + var/atom/movable/mob_container + if(ishuman(occupant)) + mob_container = src.occupant + else if(istype(occupant, /mob/living/carbon/brain)) + var/mob/living/carbon/brain/brain = occupant + mob_container = brain.container + else + return + for(var/item in dropped_items) + var/atom/movable/I = item + I.forceMove(loc) + dropped_items.Cut() + if(mob_container.forceMove(src.loc))//ejecting mob container + /* + if(ishuman(occupant) && (return_pressure() > HAZARD_HIGH_PRESSURE)) + use_internal_tank = 0 + var/datum/gas_mixture/environment = get_turf_air() + if(environment) + var/env_pressure = environment.return_pressure() + var/pressure_delta = (cabin.return_pressure() - env_pressure) + //Can not have a pressure delta that would cause environment pressure > tank pressure + + var/transfer_moles = 0 + if(pressure_delta > 0) + transfer_moles = pressure_delta*environment.volume/(cabin.return_temperature() * R_IDEAL_GAS_EQUATION) + + //Actually transfer the gas + var/datum/gas_mixture/removed = cabin.air_contents.remove(transfer_moles) + loc.assume_air(removed) + + occupant.SetStunned(5) + occupant.SetWeakened(5) + to_chat(occupant, "You were blown out of the mech!") + */ + src.log_message("[mob_container] moved out.") + occupant.reset_view() + /* + if(src.occupant.client) + src.occupant.client.eye = src.occupant.client.mob + src.occupant.client.perspective = MOB_PERSPECTIVE + */ + src.occupant << browse(null, "window=exosuit") + if(istype(mob_container, /obj/item/device/mmi)) + var/obj/item/device/mmi/mmi = mob_container + if(mmi.brainmob) + occupant.loc = mmi + mmi.mecha = null + src.occupant.canmove = 0 + src.verbs += /obj/mecha/verb/eject + src.occupant = null + src.icon_state = src.reset_icon()+"-open" + src.set_dir(dir_in) + return + +///////////////////////// +////// Access stuff ///// +///////////////////////// + +/obj/mecha/proc/operation_allowed(mob/living/carbon/human/H) + for(var/ID in list(H.get_active_hand(), H.wear_id, H.belt)) + if(src.check_access(ID,src.operation_req_access)) + return 1 + return 0 + + +/obj/mecha/proc/internals_access_allowed(mob/living/carbon/human/H) + for(var/atom/ID in list(H.get_active_hand(), H.wear_id, H.belt)) + if(src.check_access(ID,src.internals_req_access)) + return 1 + return 0 + + +/obj/mecha/check_access(obj/item/weapon/card/id/I, list/access_list) + if(!istype(access_list)) + return 1 + if(!access_list.len) //no requirements + return 1 + I = I.GetIdCard() + if(!istype(I) || !I.access) //not ID or no access + return 0 + if(access_list==src.operation_req_access) + for(var/req in access_list) + if(!(req in I.access)) //doesn't have this access + return 0 + else if(access_list==src.internals_req_access) + for(var/req in access_list) + if(req in I.access) + return 1 + return 1 + + +//////////////////////////////////// +///// Rendering stats window /////// +//////////////////////////////////// + +/obj/mecha/proc/get_stats_html() + var/output = {" + [src.name] data + + + + +
            + [src.get_stats_part()] +
            +
            + [src.get_equipment_list()] +
            +
            +
            + [src.get_commands()] +
            + + + "} + return output + + +/obj/mecha/proc/report_internal_damage() + var/output = null + var/list/dam_reports = list( + "[MECHA_INT_FIRE]" = "INTERNAL FIRE", + "[MECHA_INT_TEMP_CONTROL]" = "LIFE SUPPORT SYSTEM MALFUNCTION", + "[MECHA_INT_TANK_BREACH]" = "GAS TANK BREACH", + "[MECHA_INT_CONTROL_LOST]" = "COORDINATION SYSTEM CALIBRATION FAILURE - Recalibrate", + "[MECHA_INT_SHORT_CIRCUIT]" = "SHORT CIRCUIT" + ) + for(var/tflag in dam_reports) + var/intdamflag = text2num(tflag) + if(hasInternalDamage(intdamflag)) + output += dam_reports[tflag] + output += "
            " + if(return_pressure() > WARNING_HIGH_PRESSURE) + output += "DANGEROUSLY HIGH CABIN PRESSURE
            " + return output + + +/obj/mecha/proc/get_stats_part() + var/integrity = health/initial(health)*100 + var/cell_charge = get_charge() + var/tank_pressure = internal_tank ? round(internal_tank.return_pressure(),0.01) : "None" + var/tank_temperature = internal_tank ? internal_tank.return_temperature() : "Unknown" //Results in type mismatch if there is no tank. + var/cabin_pressure = round(return_pressure(),0.01) + var/output = {"[report_internal_damage()] + [integrity<30?"DAMAGE LEVEL CRITICAL
            ":null] + Integrity: [integrity]%
            + Powercell charge: [isnull(cell_charge)?"No powercell installed":"[cell.percent()]%"]
            + Air source: [use_internal_tank?"Internal Airtank":"Environment"]
            + Airtank pressure: [tank_pressure]kPa
            + Airtank temperature: [tank_temperature]K|[isnum(tank_temperature) ? "tank_temperature - T0C°C" : ""]
            + Cabin pressure: [cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa
            + Cabin temperature: [return_temperature()]K|[return_temperature() - T0C]°C
            + Lights: [lights?"on":"off"]
            + [src.dna?"DNA-locked:
            [src.dna] \[Reset\]
            ":null] + "} + return output + +/obj/mecha/proc/get_commands() + var/output = {"
            +
            Electronics
            + +
            +
            +
            Airtank
            + +
            + +
            [get_equipment_menu()]
            +
            + [(/obj/mecha/verb/eject in src.verbs)?"Eject
            ":null] + "} + return output + +/obj/mecha/proc/get_equipment_menu() //outputs mecha html equipment menu + var/output + if(equipment.len) + output += {"
            +
            Equipment
            +
            " + return output + +/obj/mecha/proc/get_equipment_list() //outputs mecha equipment list in html + if(!equipment.len) + return + var/output = "Equipment:
            " + for(var/obj/item/mecha_parts/mecha_equipment/MT in equipment) + output += "
            [MT.get_equip_info()]
            " + output += "
            " + return output + + +/obj/mecha/proc/get_log_html() + var/output = "[src.name] Log" + for(var/list/entry in log) + output += {"
            [time2text(entry["time"],"DDD MMM DD hh:mm:ss")] [game_year]
            +
            [entry["message"]]
            + "} + output += "" + return output + + +/obj/mecha/proc/output_access_dialog(obj/item/weapon/card/id/id_card, mob/user) + if(!id_card || !user) return + var/output = {" + + + +

            Following keycodes are present in this system:

            "} + for(var/a in operation_req_access) + output += "[get_access_desc(a)] - Delete
            " + output += "

            Following keycodes were detected on portable device:

            " + for(var/a in id_card.access) + if(a in operation_req_access) continue + var/a_name = get_access_desc(a) + if(!a_name) continue //there's some strange access without a name + output += "[a_name] - Add
            " + output += "
            Finish (Warning! The ID upload panel will be locked. It can be unlocked only through Exosuit Interface.)" + output += "" + user << browse(output, "window=exosuit_add_access") + onclose(user, "exosuit_add_access") + return + +/obj/mecha/proc/output_maintenance_dialog(obj/item/weapon/card/id/id_card,mob/user) + if(!id_card || !user) return + + var/maint_options = "Set Cabin Air Pressure" + if (locate(/obj/item/mecha_parts/mecha_equipment/tool/passenger) in contents) + maint_options += "Remove Passenger" + + var/output = {" + + + + + [add_req_access?"Edit operation keycodes":null] + [maint_access?"Initiate maintenance protocol":null] + [(state>0) ? maint_options : ""] + + "} + user << browse(output, "window=exosuit_maint_console") + onclose(user, "exosuit_maint_console") + return + + +//////////////////////////////// +/////// Messages and Log /////// +//////////////////////////////// + +/obj/mecha/proc/occupant_message(message as text) + if(message) + if(src.occupant && src.occupant.client) + to_chat(src.occupant, "\icon[src] [message]") + return + +/obj/mecha/proc/log_message(message as text,red=null) + log.len++ + log[log.len] = list("time"=world.timeofday,"message"="[red?"":null][message][red?"":null]") + return log.len + +/obj/mecha/proc/log_append_to_last(message as text,red=null) + var/list/last_entry = src.log[src.log.len] + last_entry["message"] += "
            [red?"":null][message][red?"":null]" + return + + +///////////////// +///// Topic ///// +///////////////// + +/obj/mecha/Topic(href, href_list) + ..() + if(href_list["update_content"]) + if(usr != src.occupant) return + send_byjax(src.occupant,"exosuit.browser","content",src.get_stats_part()) + return + if(href_list["close"]) + return + if(usr.stat > 0) + return + var/datum/topic_input/F = new /datum/topic_input(href,href_list) + if(href_list["select_equip"]) + if(usr != src.occupant) return + var/obj/item/mecha_parts/mecha_equipment/equip = F.getObj("select_equip") + if(equip) + src.selected = equip + src.occupant_message("You switch to [equip]") + src.visible_message("[src] raises [equip]") + send_byjax(src.occupant,"exosuit.browser","eq_list",src.get_equipment_list()) + return + if(href_list["eject"]) + if(usr != src.occupant) return + src.eject() + return + if(href_list["toggle_lights"]) + if(usr != src.occupant) return + src.toggle_lights() + return + if(href_list["toggle_airtank"]) + if(usr != src.occupant) return + src.toggle_internal_tank() + return + if(href_list["rmictoggle"]) + if(usr != src.occupant) return + radio.broadcasting = !radio.broadcasting + send_byjax(src.occupant,"exosuit.browser","rmicstate",(radio.broadcasting?"Engaged":"Disengaged")) + return + if(href_list["rspktoggle"]) + if(usr != src.occupant) return + radio.listening = !radio.listening + send_byjax(src.occupant,"exosuit.browser","rspkstate",(radio.listening?"Engaged":"Disengaged")) + return + if(href_list["rfreq"]) + if(usr != src.occupant) return + var/new_frequency = (radio.frequency + F.getNum("rfreq")) + if ((radio.frequency < PUBLIC_LOW_FREQ || radio.frequency > PUBLIC_HIGH_FREQ)) + new_frequency = sanitize_frequency(new_frequency) + radio.set_frequency(new_frequency) + send_byjax(src.occupant,"exosuit.browser","rfreq","[format_frequency(radio.frequency)]") + return + if(href_list["port_disconnect"]) + if(usr != src.occupant) return + src.disconnect_from_port() + return + if (href_list["port_connect"]) + if(usr != src.occupant) return + src.connect_to_port() + return + if (href_list["view_log"]) + if(usr != src.occupant) return + src.occupant << browse(src.get_log_html(), "window=exosuit_log") + onclose(occupant, "exosuit_log") + return + if (href_list["change_name"]) + if(usr != src.occupant) return + var/newname = sanitizeSafe(input(occupant,"Choose new exosuit name","Rename exosuit",initial(name)) as text, MAX_NAME_LEN) + if(newname) + SetName(newname) + else + alert(occupant, "nope.avi") + return + if (href_list["toggle_id_upload"]) + if(usr != src.occupant) return + add_req_access = !add_req_access + send_byjax(src.occupant,"exosuit.browser","t_id_upload","[add_req_access?"L":"Unl"]ock ID upload panel") + return + if(href_list["toggle_maint_access"]) + if(usr != src.occupant) return + if(state) + occupant_message("Maintenance protocols in effect") + return + maint_access = !maint_access + send_byjax(src.occupant,"exosuit.browser","t_maint_access","[maint_access?"Forbid":"Permit"] maintenance protocols") + return + if(href_list["req_access"] && add_req_access) + if(!in_range(src, usr)) return + output_access_dialog(F.getObj("id_card"),F.getMob("user")) + return + if(href_list["maint_access"] && maint_access) + if(!in_range(src, usr)) return + var/mob/user = F.getMob("user") + if(user) + if(state==0) + state = 1 + to_chat(user, "The securing bolts are now exposed.") + else if(state==1) + state = 0 + to_chat(user, "The securing bolts are now hidden.") + output_maintenance_dialog(F.getObj("id_card"),user) + return + if(href_list["set_internal_tank_valve"] && state >=1) + if(!in_range(src, usr)) return + var/mob/user = F.getMob("user") + if(user) + var/new_pressure = input(user,"Input new output pressure","Pressure setting",internal_tank_valve) as num + if(new_pressure) + internal_tank_valve = new_pressure + to_chat(user, "The internal pressure valve has been set to [internal_tank_valve]kPa.") + if(href_list["remove_passenger"] && state >= 1) + var/mob/user = F.getMob("user") + var/list/passengers = list() + for (var/obj/item/mecha_parts/mecha_equipment/tool/passenger/P in contents) + if (P.occupant) + passengers["[P.occupant]"] = P + + if (!passengers) + to_chat(user, "There are no passengers to remove.") + return + + var/pname = input(user, "Choose a passenger to forcibly remove.", "Forcibly Remove Passenger") as null|anything in passengers + + if (!pname) + return + + var/obj/item/mecha_parts/mecha_equipment/tool/passenger/P = passengers[pname] + var/mob/occupant = P.occupant + + user.visible_message("\The [user] begins opening the hatch on \the [P]...", "You begin opening the hatch on \the [P]...") + if (!do_after(user, 40, needhand=0)) + return + + user.visible_message("\The [user] opens the hatch on \the [P] and removes [occupant]!", "You open the hatch on \the [P] and remove [occupant]!") + P.go_out() + P.log_message("[occupant] was removed.") + return + if(href_list["add_req_access"] && add_req_access && F.getObj("id_card")) + if(!in_range(src, usr)) return + operation_req_access += F.getNum("add_req_access") + output_access_dialog(F.getObj("id_card"),F.getMob("user")) + return + if(href_list["del_req_access"] && add_req_access && F.getObj("id_card")) + if(!in_range(src, usr)) return + operation_req_access -= F.getNum("del_req_access") + output_access_dialog(F.getObj("id_card"),F.getMob("user")) + return + if(href_list["finish_req_access"]) + if(!in_range(src, usr)) return + add_req_access = 0 + var/mob/user = F.getMob("user") + user << browse(null,"window=exosuit_add_access") + return + if(href_list["dna_lock"]) + if(usr != src.occupant) return + if(istype(occupant, /mob/living/carbon/brain)) + occupant_message("You are a brain. No.") + return + if(src.occupant) + src.dna = src.occupant.dna.unique_enzymes + src.occupant_message("You feel a prick as the needle takes your DNA sample.") + return + if(href_list["reset_dna"]) + if(usr != src.occupant) return + src.dna = null + if(href_list["repair_int_control_lost"]) + if(usr != src.occupant) return + src.occupant_message("Recalibrating coordination system.") + src.log_message("Recalibration of coordination system started.") + var/T = src.loc + if(do_after(100)) + if(T == src.loc) + src.clearInternalDamage(MECHA_INT_CONTROL_LOST) + src.occupant_message("Recalibration successful.") + src.log_message("Recalibration of coordination system finished with 0 errors.") + else + src.occupant_message("Recalibration failed.") + src.log_message("Recalibration of coordination system failed with 1 error.",1) + + //debug + /* + if(href_list["debug"]) + if(href_list["set_i_dam"]) + setInternalDamage(F.getNum("set_i_dam")) + if(href_list["clear_i_dam"]) + clearInternalDamage(F.getNum("clear_i_dam")) + return + */ + + + +/* + + if (href_list["ai_take_control"]) + var/mob/living/silicon/ai/AI = locate(href_list["ai_take_control"]) + var/duration = text2num(href_list["duration"]) + var/mob/living/silicon/ai/O = new /mob/living/silicon/ai(src) + var/cur_occupant = src.occupant + O.invisibility = 0 + O.canmove = 1 + O.SetName(AI.name) + O.real_name = AI.real_name + O.anchored = 1 + O.aiRestorePowerRoutine = 0 + O.control_disabled = 1 // Can't control things remotely if you're stuck in a card! + O.laws = AI.laws + O.set_stat(AI.stat) + O.oxyloss = AI.getOxyLoss() + O.fireloss = AI.getFireLoss() + O.bruteloss = AI.getBruteLoss() + O.toxloss = AI.toxloss + O.updatehealth() + src.occupant = O + if(AI.mind) + AI.mind.transfer_to(O) + AI.SetName("Inactive AI") + AI.real_name = "Inactive AI" + AI.icon_state = "ai-empty" + spawn(duration) + AI.SetName(O.name) + AI.real_name = O.real_name + if(O.mind) + O.mind.transfer_to(AI) + AI.control_disabled = 0 + AI.laws = O.laws + AI.oxyloss = O.getOxyLoss() + AI.fireloss = O.getFireLoss() + AI.bruteloss = O.getBruteLoss() + AI.toxloss = O.toxloss + AI.updatehealth() + qdel(O) + if (!AI.stat) + AI.icon_state = "ai" + else + AI.icon_state = "ai-crash" + src.occupant = cur_occupant +*/ + return + +/////////////////////// +///// Power stuff ///// +/////////////////////// + +/obj/mecha/proc/has_charge(amount) + return (get_charge()>=amount) + +/obj/mecha/proc/get_charge() + if(!src.cell) + return + return max(0, src.cell.charge / CELLRATE) + +/obj/mecha/proc/use_power(amount) + if(get_charge()) + cell.use(amount * CELLRATE) + return 1 + return 0 + +/obj/mecha/proc/give_power(amount) + if(!isnull(get_charge())) + cell.give(amount * CELLRATE) + return 1 + return 0 + +/obj/mecha/proc/reset_icon() + if (initial_icon) + icon_state = initial_icon + else + icon_state = initial(icon_state) + return icon_state + +/obj/mecha/attack_generic(var/mob/user, var/damage, var/attack_message) + + if(!damage) + return 0 + + src.log_message("Attacked. Attacker - [user].",1) + + if(!deflect_hit(is_melee=1)) + src.hit_damage(damage, is_melee=1) + src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) + visible_message("[user] [attack_message] [src]!") + admin_attacker_log(user, "attacked \the [src]") + else + src.log_append_to_last("Armor saved.") + playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1, -1) + src.occupant_message("\The [user]'s attack is stopped by the armor.") + visible_message("\The [user] rebounds off [src.name]'s armor!") + admin_attacker_log(user, "attacked \the [src] but rebounded") + return 1 + +/obj/mecha/onDropInto(var/atom/movable/AM) + dropped_items |= AM + +////////////////////////////////////////// +//////// Mecha global iterators //////// +////////////////////////////////////////// + + +/datum/global_iterator/mecha_preserve_temp //normalizing cabin air temperature to 20 degrees celsius + delay = 20 + + process(var/obj/mecha/mecha) + if(mecha.cabin_air && mecha.cabin_air.volume > 0) + var/delta = mecha.cabin_air.temperature - T20C + mecha.cabin_air.temperature -= max(-10, min(10, round(delta/4,0.1))) + return + +/datum/global_iterator/mecha_tank_give_air + delay = 15 + + process(var/obj/mecha/mecha) + if(mecha.internal_tank) + var/datum/gas_mixture/tank_air = mecha.internal_tank.return_air() + var/datum/gas_mixture/cabin_air = mecha.cabin_air + + var/release_pressure = mecha.internal_tank_valve + var/cabin_pressure = cabin_air.return_pressure() + var/pressure_delta = min(release_pressure - cabin_pressure, (tank_air.return_pressure() - cabin_pressure)/2) + var/transfer_moles = 0 + if(pressure_delta > 0) //cabin pressure lower than release pressure + if(tank_air.temperature > 0) + transfer_moles = pressure_delta*cabin_air.volume/(cabin_air.temperature * R_IDEAL_GAS_EQUATION) + var/datum/gas_mixture/removed = tank_air.remove(transfer_moles) + cabin_air.merge(removed) + else if(pressure_delta < 0) //cabin pressure higher than release pressure + var/datum/gas_mixture/t_air = mecha.get_turf_air() + pressure_delta = cabin_pressure - release_pressure + if(t_air) + pressure_delta = min(cabin_pressure - t_air.return_pressure(), pressure_delta) + if(pressure_delta > 0) //if location pressure is lower than cabin pressure + transfer_moles = pressure_delta*cabin_air.volume/(cabin_air.temperature * R_IDEAL_GAS_EQUATION) + var/datum/gas_mixture/removed = cabin_air.remove(transfer_moles) + if(t_air) + t_air.merge(removed) + else //just delete the cabin gas, we're in space or some shit + qdel(removed) + else + return stop() + return + +/datum/global_iterator/mecha_inertial_movement //inertial movement in space + delay = 7 + + process(var/obj/mecha/mecha as obj,direction) + if(direction) + if(!step(mecha, direction)||mecha.check_for_support()) + src.stop() + else + src.stop() + return + +/datum/global_iterator/mecha_internal_damage // processing internal damage + + process(var/obj/mecha/mecha) + if(!mecha.hasInternalDamage()) + return stop() + if(mecha.hasInternalDamage(MECHA_INT_FIRE)) + if(!mecha.hasInternalDamage(MECHA_INT_TEMP_CONTROL) && prob(5)) + mecha.clearInternalDamage(MECHA_INT_FIRE) + if(mecha.internal_tank) + if(mecha.internal_tank.return_pressure()>mecha.internal_tank.maximum_pressure && !(mecha.hasInternalDamage(MECHA_INT_TANK_BREACH))) + mecha.setInternalDamage(MECHA_INT_TANK_BREACH) + var/datum/gas_mixture/int_tank_air = mecha.internal_tank.return_air() + if(int_tank_air && int_tank_air.volume>0) //heat the air_contents + int_tank_air.temperature = min(6000+T0C, int_tank_air.temperature+rand(10,15)) + if(mecha.cabin_air && mecha.cabin_air.volume>0) + mecha.cabin_air.temperature = min(6000+T0C, mecha.cabin_air.temperature+rand(10,15)) + if(mecha.cabin_air.temperature>mecha.max_temperature/2) + mecha.take_damage(4/round(mecha.max_temperature/mecha.cabin_air.temperature,0.1),"fire") + if(mecha.hasInternalDamage(MECHA_INT_TEMP_CONTROL)) //stop the mecha_preserve_temp loop datum + mecha.pr_int_temp_processor.stop() + if(mecha.hasInternalDamage(MECHA_INT_TANK_BREACH)) //remove some air from internal tank + if(mecha.internal_tank) + var/datum/gas_mixture/int_tank_air = mecha.internal_tank.return_air() + var/datum/gas_mixture/leaked_gas = int_tank_air.remove_ratio(0.10) + if(mecha.loc && hascall(mecha.loc,"assume_air")) + mecha.loc.assume_air(leaked_gas) + else + qdel(leaked_gas) + if(mecha.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) + if(mecha.get_charge()) + mecha.spark_system.start() + mecha.use_power(rand(1 KILOWATTS, 5 KILOWATTS)) + return + + +///////////// + +//debug +/* +/obj/mecha/verb/test_int_damage() + set name = "Test internal damage" + set category = "Exosuit Interface" + set src in view(0) + if(!occupant) return + if(usr!=occupant) + return + var/output = {" + + + +

            Set:

            + MECHA_INT_FIRE
            + MECHA_INT_TEMP_CONTROL
            + MECHA_INT_SHORT_CIRCUIT
            + MECHA_INT_TANK_BREACH
            + MECHA_INT_CONTROL_LOST
            +
            +

            Clear:

            + MECHA_INT_FIRE
            + MECHA_INT_TEMP_CONTROL
            + MECHA_INT_SHORT_CIRCUIT
            + MECHA_INT_TANK_BREACH
            + MECHA_INT_CONTROL_LOST
            + + "} + + occupant << browse(output, "window=ex_debug") + //src.health = initial(src.health)/2.2 + //src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) + return +*/ +/obj/mecha/fall_damage() + return 550 \ No newline at end of file diff --git a/code/game/mecha/mecha_construction_paths.dm b/code/game/mecha/mecha_construction_paths.dm new file mode 100644 index 00000000..0b1b0c96 --- /dev/null +++ b/code/game/mecha/mecha_construction_paths.dm @@ -0,0 +1,1295 @@ +//////////////////////////////// +///// Construction datums ////// +//////////////////////////////// + +/datum/construction/mecha/custom_action(step, atom/used_atom, mob/user) + if(isWelder(used_atom)) + var/obj/item/weapon/weldingtool/W = used_atom + if (W.remove_fuel(0, user)) + playsound(holder, 'sound/items/Welder2.ogg', 50, 1) + else + return 0 + else if(isWrench(used_atom)) + playsound(holder, 'sound/items/Ratchet.ogg', 50, 1) + + else if(isScrewdriver(used_atom)) + playsound(holder, 'sound/items/Screwdriver.ogg', 50, 1) + + else if(isWirecutter(used_atom)) + playsound(holder, 'sound/items/Wirecutter.ogg', 50, 1) + + else if(isCoil(used_atom)) + var/obj/item/stack/cable_coil/C = used_atom + if(C.use(4)) + playsound(holder, 'sound/items/Deconstruct.ogg', 50, 1) + else + to_chat(user, ("There's not enough cable to finish the task.")) + return 0 + else if(istype(used_atom, /obj/item/stack)) + var/obj/item/stack/S = used_atom + if(S.get_amount() < 5) + to_chat(user, ("There's not enough material in this stack.")) + return 0 + else + S.use(5) + return 1 + +/datum/construction/reversible/mecha/custom_action(index as num, diff as num, atom/used_atom, mob/user as mob) + if(isWelder(used_atom)) + var/obj/item/weapon/weldingtool/W = used_atom + if (W.remove_fuel(0, user)) + playsound(holder, 'sound/items/Welder2.ogg', 50, 1) + else + return 0 + else if(isWrench(used_atom)) + playsound(holder, 'sound/items/Ratchet.ogg', 50, 1) + + else if(isScrewdriver(used_atom)) + playsound(holder, 'sound/items/Screwdriver.ogg', 50, 1) + + else if(isWirecutter(used_atom)) + playsound(holder, 'sound/items/Wirecutter.ogg', 50, 1) + + else if(istype(used_atom, /obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/C = used_atom + if(C.use(4)) + playsound(holder, 'sound/items/Deconstruct.ogg', 50, 1) + else + to_chat(user, ("There's not enough cable to finish the task.")) + return 0 + else if(istype(used_atom, /obj/item/stack)) + var/obj/item/stack/S = used_atom + if(S.get_amount() < 5) + to_chat(user, ("There's not enough material in this stack.")) + return 0 + else + S.use(5) + return 1 + + +/datum/construction/mecha/ripley_chassis + steps = list(list("key"=/obj/item/mecha_parts/part/ripley_torso),//1 + list("key"=/obj/item/mecha_parts/part/ripley_left_arm),//2 + list("key"=/obj/item/mecha_parts/part/ripley_right_arm),//3 + list("key"=/obj/item/mecha_parts/part/ripley_left_leg),//4 + list("key"=/obj/item/mecha_parts/part/ripley_right_leg)//5 + ) + + custom_action(step, atom/used_atom, mob/user) + user.visible_message("[user] has connected [used_atom] to [holder].", "You connect [used_atom] to [holder]") + holder.overlays += used_atom.icon_state+"+o" + qdel(used_atom) + return 1 + + action(atom/used_atom,mob/user as mob) + return check_all_steps(used_atom,user) + + spawn_result() + var/obj/item/mecha_parts/chassis/const_holder = holder + const_holder.construct = new /datum/construction/reversible/mecha/ripley(const_holder) + const_holder.icon = 'icons/mecha/mech_construction.dmi' + const_holder.icon_state = "ripley0" + const_holder.set_density(1) + const_holder.overlays.len = 0 + spawn() + qdel(src) + return + + +/datum/construction/reversible/mecha/ripley + result = /obj/mecha/working/ripley + steps = list( + //1 + list("key"=/obj/item/weapon/weldingtool, + "backkey"=/obj/item/weapon/wrench, + "desc"="External armor is wrenched."), + //2 + list("key"=/obj/item/weapon/wrench, + "backkey"=/obj/item/weapon/crowbar, + "desc"="External armor is installed."), + //3 + list("key"=/obj/item/stack/material/plasteel, + "backkey"=/obj/item/weapon/weldingtool, + "desc"="Internal armor is welded."), + //4 + list("key"=/obj/item/weapon/weldingtool, + "backkey"=/obj/item/weapon/wrench, + "desc"="Internal armor is wrenched"), + //5 + list("key"=/obj/item/weapon/wrench, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Internal armor is installed"), + //6 + list("key"=/obj/item/stack/material/steel, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Peripherals control module is secured"), + //7 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Peripherals control module is installed"), + //8 + list("key"=/obj/item/weapon/circuitboard/mecha/ripley/peripherals, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Central control module is secured"), + //9 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Central control module is installed"), + //10 + list("key"=/obj/item/weapon/circuitboard/mecha/ripley/main, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The wiring is adjusted"), + //11 + list("key"=/obj/item/weapon/wirecutters, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The wiring is added"), + //12 + list("key"=/obj/item/stack/cable_coil, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The hydraulic systems are active."), + //13 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/wrench, + "desc"="The hydraulic systems are connected."), + //14 + list("key"=/obj/item/weapon/wrench, + "desc"="The hydraulic systems are disconnected.") + ) + + action(atom/used_atom,mob/user as mob) + return check_step(used_atom,user) + + custom_action(index, diff, atom/used_atom, mob/user) + if(!..()) + return 0 + + //TODO: better messages. + switch(index) + if(14) + user.visible_message("[user] connects [holder] hydraulic systems", "You connect [holder] hydraulic systems.") + holder.icon_state = "ripley1" + if(13) + if(diff==FORWARD) + user.visible_message("[user] activates [holder] hydraulic systems.", "You activate [holder] hydraulic systems.") + holder.icon_state = "ripley2" + else + user.visible_message("[user] disconnects [holder] hydraulic systems", "You disconnect [holder] hydraulic systems.") + holder.icon_state = "ripley0" + if(12) + if(diff==FORWARD) + user.visible_message("[user] adds the wiring to [holder].", "You add the wiring to [holder].") + holder.icon_state = "ripley3" + else + user.visible_message("[user] deactivates [holder] hydraulic systems.", "You deactivate [holder] hydraulic systems.") + holder.icon_state = "ripley1" + if(11) + if(diff==FORWARD) + user.visible_message("[user] adjusts the wiring of [holder].", "You adjust the wiring of [holder].") + holder.icon_state = "ripley4" + else + user.visible_message("[user] removes the wiring from [holder].", "You remove the wiring from [holder].") + var/obj/item/stack/cable_coil/coil = new /obj/item/stack/cable_coil(get_turf(holder)) + coil.amount = 4 + holder.icon_state = "ripley2" + if(10) + if(diff==FORWARD) + user.visible_message("[user] installs the central control module into [holder].", "You install the central computer mainboard into [holder].") + qdel(used_atom) + holder.icon_state = "ripley5" + else + user.visible_message("[user] disconnects the wiring of [holder].", "You disconnect the wiring of [holder].") + holder.icon_state = "ripley3" + if(9) + if(diff==FORWARD) + user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") + holder.icon_state = "ripley6" + else + user.visible_message("[user] removes the central control module from [holder].", "You remove the central computer mainboard from [holder].") + new /obj/item/weapon/circuitboard/mecha/ripley/main(get_turf(holder)) + holder.icon_state = "ripley4" + if(8) + if(diff==FORWARD) + user.visible_message("[user] installs the peripherals control module into [holder].", "You install the peripherals control module into [holder].") + qdel(used_atom) + holder.icon_state = "ripley7" + else + user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") + holder.icon_state = "ripley5" + if(7) + if(diff==FORWARD) + user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") + holder.icon_state = "ripley8" + else + user.visible_message("[user] removes the peripherals control module from [holder].", "You remove the peripherals control module from [holder].") + new /obj/item/weapon/circuitboard/mecha/ripley/peripherals(get_turf(holder)) + holder.icon_state = "ripley6" + if(6) + if(diff==FORWARD) + user.visible_message("[user] installs internal armor layer to [holder].", "You install internal armor layer to [holder].") + holder.icon_state = "ripley9" + else + user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") + holder.icon_state = "ripley7" + if(5) + if(diff==FORWARD) + user.visible_message("[user] secures internal armor layer.", "You secure internal armor layer.") + holder.icon_state = "ripley10" + else + user.visible_message("[user] pries internal armor layer from [holder].", "You prie internal armor layer from [holder].") + var/obj/item/stack/material/steel/MS = new /obj/item/stack/material/steel(get_turf(holder)) + MS.amount = 5 + holder.icon_state = "ripley8" + if(4) + if(diff==FORWARD) + user.visible_message("[user] welds internal armor layer to [holder].", "You weld the internal armor layer to [holder].") + holder.icon_state = "ripley11" + else + user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") + holder.icon_state = "ripley9" + if(3) + if(diff==FORWARD) + user.visible_message("[user] installs external reinforced armor layer to [holder].", "You install external reinforced armor layer to [holder].") + holder.icon_state = "ripley12" + else + user.visible_message("[user] cuts internal armor layer from [holder].", "You cut the internal armor layer from [holder].") + holder.icon_state = "ripley10" + if(2) + if(diff==FORWARD) + user.visible_message("[user] secures external armor layer.", "You secure external reinforced armor layer.") + holder.icon_state = "ripley13" + else + user.visible_message("[user] pries external armor layer from [holder].", "You prie external armor layer from [holder].") + var/obj/item/stack/material/plasteel/MS = new /obj/item/stack/material/plasteel(get_turf(holder)) + MS.amount = 5 + holder.icon_state = "ripley11" + if(1) + if(diff==FORWARD) + user.visible_message("[user] welds external armor layer to [holder].", "You weld external armor layer to [holder].") + else + user.visible_message("[user] unfastens the external armor layer.", "You unfasten the external armor layer.") + holder.icon_state = "ripley12" + return 1 + + spawn_result() + ..() + feedback_inc("mecha_ripley_created",1) + return + + + +/datum/construction/mecha/gygax_chassis + steps = list(list("key"=/obj/item/mecha_parts/part/gygax_torso),//1 + list("key"=/obj/item/mecha_parts/part/gygax_left_arm),//2 + list("key"=/obj/item/mecha_parts/part/gygax_right_arm),//3 + list("key"=/obj/item/mecha_parts/part/gygax_left_leg),//4 + list("key"=/obj/item/mecha_parts/part/gygax_right_leg),//5 + list("key"=/obj/item/mecha_parts/part/gygax_head) + ) + + custom_action(step, atom/used_atom, mob/user) + user.visible_message("[user] has connected [used_atom] to [holder].", "You connect [used_atom] to [holder]") + holder.overlays += used_atom.icon_state+"+o" + qdel(used_atom) + return 1 + + action(atom/used_atom,mob/user as mob) + return check_all_steps(used_atom,user) + + spawn_result() + var/obj/item/mecha_parts/chassis/const_holder = holder + const_holder.construct = new /datum/construction/reversible/mecha/gygax(const_holder) + const_holder.icon = 'icons/mecha/mech_construction.dmi' + const_holder.icon_state = "gygax0" + const_holder.set_density(1) + spawn() + qdel(src) + return + + +/datum/construction/reversible/mecha/gygax + result = /obj/mecha/combat/gygax + steps = list( + //1 + list("key"=/obj/item/weapon/weldingtool, + "backkey"=/obj/item/weapon/wrench, + "desc"="External armor is wrenched."), + //2 + list("key"=/obj/item/weapon/wrench, + "backkey"=/obj/item/weapon/crowbar, + "desc"="External armor is installed."), + //3 + list("key"=/obj/item/mecha_parts/part/gygax_armour, + "backkey"=/obj/item/weapon/weldingtool, + "desc"="Internal armor is welded."), + //4 + list("key"=/obj/item/weapon/weldingtool, + "backkey"=/obj/item/weapon/wrench, + "desc"="Internal armor is wrenched"), + //5 + list("key"=/obj/item/weapon/wrench, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Internal armor is installed"), + //6 + list("key"=/obj/item/stack/material/steel, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Advanced capacitor is secured"), + //7 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Advanced capacitor is installed"), + //8 + list("key"=/obj/item/weapon/stock_parts/capacitor/adv, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Advanced scanner module is secured"), + //9 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Advanced scanner module is installed"), + //10 + list("key"=/obj/item/weapon/stock_parts/scanning_module/adv, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Targeting module is secured"), + //11 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Targeting module is installed"), + //12 + list("key"=/obj/item/weapon/circuitboard/mecha/gygax/targeting, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Peripherals control module is secured"), + //13 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Peripherals control module is installed"), + //14 + list("key"=/obj/item/weapon/circuitboard/mecha/gygax/peripherals, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Central control module is secured"), + //15 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Central control module is installed"), + //16 + list("key"=/obj/item/weapon/circuitboard/mecha/gygax/main, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The wiring is adjusted"), + //17 + list("key"=/obj/item/weapon/wirecutters, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The wiring is added"), + //18 + list("key"=/obj/item/stack/cable_coil, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The hydraulic systems are active."), + //19 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/wrench, + "desc"="The hydraulic systems are connected."), + //20 + list("key"=/obj/item/weapon/wrench, + "desc"="The hydraulic systems are disconnected.") + ) + + action(atom/used_atom,mob/user as mob) + return check_step(used_atom,user) + + custom_action(index, diff, atom/used_atom, mob/user) + if(!..()) + return 0 + + //TODO: better messages. + switch(index) + if(20) + user.visible_message("[user] connects [holder] hydraulic systems", "You connect [holder] hydraulic systems.") + holder.icon_state = "gygax1" + if(19) + if(diff==FORWARD) + user.visible_message("[user] activates [holder] hydraulic systems.", "You activate [holder] hydraulic systems.") + holder.icon_state = "gygax2" + else + user.visible_message("[user] disconnects [holder] hydraulic systems", "You disconnect [holder] hydraulic systems.") + holder.icon_state = "gygax0" + if(18) + if(diff==FORWARD) + user.visible_message("[user] adds the wiring to [holder].", "You add the wiring to [holder].") + holder.icon_state = "gygax3" + else + user.visible_message("[user] deactivates [holder] hydraulic systems.", "You deactivate [holder] hydraulic systems.") + holder.icon_state = "gygax1" + if(17) + if(diff==FORWARD) + user.visible_message("[user] adjusts the wiring of [holder].", "You adjust the wiring of [holder].") + holder.icon_state = "gygax4" + else + user.visible_message("[user] removes the wiring from [holder].", "You remove the wiring from [holder].") + var/obj/item/stack/cable_coil/coil = new /obj/item/stack/cable_coil(get_turf(holder)) + coil.amount = 4 + holder.icon_state = "gygax2" + if(16) + if(diff==FORWARD) + user.visible_message("[user] installs the central control module into [holder].", "You install the central computer mainboard into [holder].") + qdel(used_atom) + holder.icon_state = "gygax5" + else + user.visible_message("[user] disconnects the wiring of [holder].", "You disconnect the wiring of [holder].") + holder.icon_state = "gygax3" + if(15) + if(diff==FORWARD) + user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") + holder.icon_state = "gygax6" + else + user.visible_message("[user] removes the central control module from [holder].", "You remove the central computer mainboard from [holder].") + new /obj/item/weapon/circuitboard/mecha/gygax/main(get_turf(holder)) + holder.icon_state = "gygax4" + if(14) + if(diff==FORWARD) + user.visible_message("[user] installs the peripherals control module into [holder].", "You install the peripherals control module into [holder].") + qdel(used_atom) + holder.icon_state = "gygax7" + else + user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") + holder.icon_state = "gygax5" + if(13) + if(diff==FORWARD) + user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") + holder.icon_state = "gygax8" + else + user.visible_message("[user] removes the peripherals control module from [holder].", "You remove the peripherals control module from [holder].") + new /obj/item/weapon/circuitboard/mecha/gygax/peripherals(get_turf(holder)) + holder.icon_state = "gygax6" + if(12) + if(diff==FORWARD) + user.visible_message("[user] installs the weapon control module into [holder].", "You install the weapon control module into [holder].") + qdel(used_atom) + holder.icon_state = "gygax9" + else + user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") + holder.icon_state = "gygax7" + if(11) + if(diff==FORWARD) + user.visible_message("[user] secures the weapon control module.", "You secure the weapon control module.") + holder.icon_state = "gygax10" + else + user.visible_message("[user] removes the weapon control module from [holder].", "You remove the weapon control module from [holder].") + new /obj/item/weapon/circuitboard/mecha/gygax/targeting(get_turf(holder)) + holder.icon_state = "gygax8" + if(10) + if(diff==FORWARD) + user.visible_message("[user] installs advanced scanner module to [holder].", "You install advanced scanner module to [holder].") + qdel(used_atom) + holder.icon_state = "gygax11" + else + user.visible_message("[user] unfastens the weapon control module.", "You unfasten the weapon control module.") + holder.icon_state = "gygax9" + if(9) + if(diff==FORWARD) + user.visible_message("[user] secures the advanced scanner module.", "You secure the advanced scanner module.") + holder.icon_state = "gygax12" + else + user.visible_message("[user] removes the advanced scanner module from [holder].", "You remove the advanced scanner module from [holder].") + new /obj/item/weapon/stock_parts/scanning_module/adv(get_turf(holder)) + holder.icon_state = "gygax10" + if(8) + if(diff==FORWARD) + user.visible_message("[user] installs advanced capacitor to [holder].", "You install advanced capacitor to [holder].") + qdel(used_atom) + holder.icon_state = "gygax13" + else + user.visible_message("[user] unfastens the advanced scanner module.", "You unfasten the advanced scanner module.") + holder.icon_state = "gygax11" + if(7) + if(diff==FORWARD) + user.visible_message("[user] secures the advanced capacitor.", "You secure the advanced capacitor.") + holder.icon_state = "gygax14" + else + user.visible_message("[user] removes the advanced capacitor from [holder].", "You remove the advanced capacitor from [holder].") + new /obj/item/weapon/stock_parts/capacitor/adv(get_turf(holder)) + holder.icon_state = "gygax12" + if(6) + if(diff==FORWARD) + user.visible_message("[user] installs internal armor layer to [holder].", "You install internal armor layer to [holder].") + holder.icon_state = "gygax15" + else + user.visible_message("[user] unfastens the advanced capacitor.", "You unfasten the advanced capacitor.") + holder.icon_state = "gygax13" + if(5) + if(diff==FORWARD) + user.visible_message("[user] secures internal armor layer.", "You secure internal armor layer.") + holder.icon_state = "gygax16" + else + user.visible_message("[user] pries internal armor layer from [holder].", "You prie internal armor layer from [holder].") + var/obj/item/stack/material/steel/MS = new /obj/item/stack/material/steel(get_turf(holder)) + MS.amount = 5 + holder.icon_state = "gygax14" + if(4) + if(diff==FORWARD) + user.visible_message("[user] welds internal armor layer to [holder].", "You weld the internal armor layer to [holder].") + holder.icon_state = "gygax17" + else + user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") + holder.icon_state = "gygax15" + if(3) + if(diff==FORWARD) + user.visible_message("[user] installs Gygax Armour Plates to [holder].", "You install Gygax Armour Plates to [holder].") + qdel(used_atom) + holder.icon_state = "gygax18" + else + user.visible_message("[user] cuts internal armor layer from [holder].", "You cut the internal armor layer from [holder].") + holder.icon_state = "gygax16" + if(2) + if(diff==FORWARD) + user.visible_message("[user] secures Gygax Armour Plates.", "You secure Gygax Armour Plates.") + holder.icon_state = "gygax19" + else + user.visible_message("[user] pries Gygax Armour Plates from [holder].", "You prie Gygax Armour Plates from [holder].") + new /obj/item/mecha_parts/part/gygax_armour(get_turf(holder)) + holder.icon_state = "gygax17" + if(1) + if(diff==FORWARD) + user.visible_message("[user] welds Gygax Armour Plates to [holder].", "You weld Gygax Armour Plates to [holder].") + else + user.visible_message("[user] unfastens Gygax Armour Plates.", "You unfasten Gygax Armour Plates.") + holder.icon_state = "gygax18" + return 1 + + spawn_result() + ..() + feedback_inc("mecha_gygax_created",1) + return + +/datum/construction/mecha/firefighter_chassis + steps = list(list("key"=/obj/item/mecha_parts/part/ripley_torso),//1 + list("key"=/obj/item/mecha_parts/part/ripley_left_arm),//2 + list("key"=/obj/item/mecha_parts/part/ripley_right_arm),//3 + list("key"=/obj/item/mecha_parts/part/ripley_left_leg),//4 + list("key"=/obj/item/mecha_parts/part/ripley_right_leg),//5 + list("key"=/obj/item/clothing/suit/fire)//6 + ) + + custom_action(step, atom/used_atom, mob/user) + user.visible_message("[user] has connected [used_atom] to [holder].", "You connect [used_atom] to [holder]") + holder.overlays += used_atom.icon_state+"+o" + user.drop_item() + qdel(used_atom) + return 1 + + action(atom/used_atom,mob/user as mob) + return check_all_steps(used_atom,user) + + spawn_result() + var/obj/item/mecha_parts/chassis/const_holder = holder + const_holder.construct = new /datum/construction/reversible/mecha/firefighter(const_holder) + const_holder.icon = 'icons/mecha/mech_construction.dmi' + const_holder.icon_state = "fireripley0" + const_holder.set_density(1) + spawn() + qdel(src) + return + + +/datum/construction/reversible/mecha/firefighter + result = /obj/mecha/working/ripley/firefighter + steps = list( + //1 + list("key"=/obj/item/weapon/weldingtool, + "backkey"=/obj/item/weapon/wrench, + "desc"="External armor is wrenched."), + //2 + list("key"=/obj/item/weapon/wrench, + "backkey"=/obj/item/weapon/crowbar, + "desc"="External armor is installed."), + //3 + list("key"=/obj/item/stack/material/plasteel, + "backkey"=/obj/item/weapon/crowbar, + "desc"="External armor is being installed."), + //4 + list("key"=/obj/item/stack/material/plasteel, + "backkey"=/obj/item/weapon/weldingtool, + "desc"="Internal armor is welded."), + //5 + list("key"=/obj/item/weapon/weldingtool, + "backkey"=/obj/item/weapon/wrench, + "desc"="Internal armor is wrenched"), + //6 + list("key"=/obj/item/weapon/wrench, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Internal armor is installed"), + + //7 + list("key"=/obj/item/stack/material/plasteel, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Peripherals control module is secured"), + //8 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Peripherals control module is installed"), + //9 + list("key"=/obj/item/weapon/circuitboard/mecha/ripley/peripherals, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Central control module is secured"), + //10 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Central control module is installed"), + //11 + list("key"=/obj/item/weapon/circuitboard/mecha/ripley/main, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The wiring is adjusted"), + //12 + list("key"=/obj/item/weapon/wirecutters, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The wiring is added"), + //13 + list("key"=/obj/item/stack/cable_coil, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The hydraulic systems are active."), + //14 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/wrench, + "desc"="The hydraulic systems are connected."), + //15 + list("key"=/obj/item/weapon/wrench, + "desc"="The hydraulic systems are disconnected.") + ) + + action(atom/used_atom,mob/user as mob) + return check_step(used_atom,user) + + custom_action(index, diff, atom/used_atom, mob/user) + if(!..()) + return 0 + + //TODO: better messages. + switch(index) + if(15) + user.visible_message("[user] connects [holder] hydraulic systems", "You connect [holder] hydraulic systems.") + holder.icon_state = "fireripley1" + if(14) + if(diff==FORWARD) + user.visible_message("[user] activates [holder] hydraulic systems.", "You activate [holder] hydraulic systems.") + holder.icon_state = "fireripley2" + else + user.visible_message("[user] disconnects [holder] hydraulic systems", "You disconnect [holder] hydraulic systems.") + holder.icon_state = "fireripley0" + if(13) + if(diff==FORWARD) + user.visible_message("[user] adds the wiring to [holder].", "You add the wiring to [holder].") + holder.icon_state = "fireripley3" + else + user.visible_message("[user] deactivates [holder] hydraulic systems.", "You deactivate [holder] hydraulic systems.") + holder.icon_state = "fireripley1" + if(12) + if(diff==FORWARD) + user.visible_message("[user] adjusts the wiring of [holder].", "You adjust the wiring of [holder].") + holder.icon_state = "fireripley4" + else + user.visible_message("[user] removes the wiring from [holder].", "You remove the wiring from [holder].") + var/obj/item/stack/cable_coil/coil = new /obj/item/stack/cable_coil(get_turf(holder)) + coil.amount = 4 + holder.icon_state = "fireripley2" + if(11) + if(diff==FORWARD) + user.visible_message("[user] installs the central control module into [holder].", "You install the central computer mainboard into [holder].") + qdel(used_atom) + holder.icon_state = "fireripley5" + else + user.visible_message("[user] disconnects the wiring of [holder].", "You disconnect the wiring of [holder].") + holder.icon_state = "fireripley3" + if(10) + if(diff==FORWARD) + user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") + holder.icon_state = "fireripley6" + else + user.visible_message("[user] removes the central control module from [holder].", "You remove the central computer mainboard from [holder].") + new /obj/item/weapon/circuitboard/mecha/ripley/main(get_turf(holder)) + holder.icon_state = "fireripley4" + if(9) + if(diff==FORWARD) + user.visible_message("[user] installs the peripherals control module into [holder].", "You install the peripherals control module into [holder].") + qdel(used_atom) + holder.icon_state = "fireripley7" + else + user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") + holder.icon_state = "fireripley5" + if(8) + if(diff==FORWARD) + user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") + holder.icon_state = "fireripley8" + else + user.visible_message("[user] removes the peripherals control module from [holder].", "You remove the peripherals control module from [holder].") + new /obj/item/weapon/circuitboard/mecha/ripley/peripherals(get_turf(holder)) + holder.icon_state = "fireripley6" + if(7) + if(diff==FORWARD) + user.visible_message("[user] installs internal armor layer to [holder].", "You install internal armor layer to [holder].") + holder.icon_state = "fireripley9" + else + user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") + holder.icon_state = "fireripley7" + + if(6) + if(diff==FORWARD) + user.visible_message("[user] secures internal armor layer.", "You secure internal armor layer.") + holder.icon_state = "fireripley10" + else + user.visible_message("[user] pries internal armor layer from [holder].", "You prie internal armor layer from [holder].") + var/obj/item/stack/material/plasteel/MS = new /obj/item/stack/material/plasteel(get_turf(holder)) + MS.amount = 5 + holder.icon_state = "fireripley8" + if(5) + if(diff==FORWARD) + user.visible_message("[user] welds internal armor layer to [holder].", "You weld the internal armor layer to [holder].") + holder.icon_state = "fireripley11" + else + user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") + holder.icon_state = "fireripley9" + if(4) + if(diff==FORWARD) + user.visible_message("[user] starts to install the external armor layer to [holder].", "You start to install the external armor layer to [holder].") + holder.icon_state = "fireripley12" + else + user.visible_message("[user] cuts internal armor layer from [holder].", "You cut the internal armor layer from [holder].") + holder.icon_state = "fireripley10" + if(3) + if(diff==FORWARD) + user.visible_message("[user] installs external reinforced armor layer to [holder].", "You install external reinforced armor layer to [holder].") + holder.icon_state = "fireripley13" + else + user.visible_message("[user] removes the external armor from [holder].", "You remove the external armor from [holder].") + var/obj/item/stack/material/plasteel/MS = new /obj/item/stack/material/plasteel(get_turf(holder)) + MS.amount = 5 + holder.icon_state = "fireripley11" + if(2) + if(diff==FORWARD) + user.visible_message("[user] secures external armor layer.", "You secure external reinforced armor layer.") + holder.icon_state = "fireripley14" + else + user.visible_message("[user] pries external armor layer from [holder].", "You prie external armor layer from [holder].") + var/obj/item/stack/material/plasteel/MS = new /obj/item/stack/material/plasteel(get_turf(holder)) + MS.amount = 5 + holder.icon_state = "fireripley12" + if(1) + if(diff==FORWARD) + user.visible_message("[user] welds external armor layer to [holder].", "You weld external armor layer to [holder].") + else + user.visible_message("[user] unfastens the external armor layer.", "You unfasten the external armor layer.") + holder.icon_state = "fireripley13" + return 1 + + spawn_result() + ..() + feedback_inc("mecha_firefighter_created",1) + return + +/datum/construction/mecha/durand_chassis + steps = list(list("key"=/obj/item/mecha_parts/part/durand_torso),//1 + list("key"=/obj/item/mecha_parts/part/durand_left_arm),//2 + list("key"=/obj/item/mecha_parts/part/durand_right_arm),//3 + list("key"=/obj/item/mecha_parts/part/durand_left_leg),//4 + list("key"=/obj/item/mecha_parts/part/durand_right_leg),//5 + list("key"=/obj/item/mecha_parts/part/durand_head) + ) + + custom_action(step, atom/used_atom, mob/user) + user.visible_message("[user] has connected [used_atom] to [holder].", "You connect [used_atom] to [holder]") + holder.overlays += used_atom.icon_state+"+o" + qdel(used_atom) + return 1 + + action(atom/used_atom,mob/user as mob) + return check_all_steps(used_atom,user) + + spawn_result() + var/obj/item/mecha_parts/chassis/const_holder = holder + const_holder.construct = new /datum/construction/reversible/mecha/durand(const_holder) + const_holder.icon = 'icons/mecha/mech_construction.dmi' + const_holder.icon_state = "durand0" + const_holder.set_density(1) + spawn() + qdel(src) + return + +/datum/construction/reversible/mecha/durand + result = /obj/mecha/combat/durand + steps = list( + //1 + list("key"=/obj/item/weapon/weldingtool, + "backkey"=/obj/item/weapon/wrench, + "desc"="External armor is wrenched."), + //2 + list("key"=/obj/item/weapon/wrench, + "backkey"=/obj/item/weapon/crowbar, + "desc"="External armor is installed."), + //3 + list("key"=/obj/item/mecha_parts/part/durand_armour, + "backkey"=/obj/item/weapon/weldingtool, + "desc"="Internal armor is welded."), + //4 + list("key"=/obj/item/weapon/weldingtool, + "backkey"=/obj/item/weapon/wrench, + "desc"="Internal armor is wrenched"), + //5 + list("key"=/obj/item/weapon/wrench, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Internal armor is installed"), + //6 + list("key"=/obj/item/stack/material/steel, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Advanced capacitor is secured"), + //7 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Advanced capacitor is installed"), + //8 + list("key"=/obj/item/weapon/stock_parts/capacitor/adv, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Advanced scanner module is secured"), + //9 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Advanced scanner module is installed"), + //10 + list("key"=/obj/item/weapon/stock_parts/scanning_module/adv, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Targeting module is secured"), + //11 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Targeting module is installed"), + //12 + list("key"=/obj/item/weapon/circuitboard/mecha/durand/targeting, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Peripherals control module is secured"), + //13 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Peripherals control module is installed"), + //14 + list("key"=/obj/item/weapon/circuitboard/mecha/durand/peripherals, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Central control module is secured"), + //15 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Central control module is installed"), + //16 + list("key"=/obj/item/weapon/circuitboard/mecha/durand/main, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The wiring is adjusted"), + //17 + list("key"=/obj/item/weapon/wirecutters, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The wiring is added"), + //18 + list("key"=/obj/item/stack/cable_coil, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The hydraulic systems are active."), + //19 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/wrench, + "desc"="The hydraulic systems are connected."), + //20 + list("key"=/obj/item/weapon/wrench, + "desc"="The hydraulic systems are disconnected.") + ) + + + action(atom/used_atom,mob/user as mob) + return check_step(used_atom,user) + + custom_action(index, diff, atom/used_atom, mob/user) + if(!..()) + return 0 + + //TODO: better messages. + switch(index) + if(20) + user.visible_message("[user] connects [holder] hydraulic systems", "You connect [holder] hydraulic systems.") + holder.icon_state = "durand1" + if(19) + if(diff==FORWARD) + user.visible_message("[user] activates [holder] hydraulic systems.", "You activate [holder] hydraulic systems.") + holder.icon_state = "durand2" + else + user.visible_message("[user] disconnects [holder] hydraulic systems", "You disconnect [holder] hydraulic systems.") + holder.icon_state = "durand0" + if(18) + if(diff==FORWARD) + user.visible_message("[user] adds the wiring to [holder].", "You add the wiring to [holder].") + holder.icon_state = "durand3" + else + user.visible_message("[user] deactivates [holder] hydraulic systems.", "You deactivate [holder] hydraulic systems.") + holder.icon_state = "durand1" + if(17) + if(diff==FORWARD) + user.visible_message("[user] adjusts the wiring of [holder].", "You adjust the wiring of [holder].") + holder.icon_state = "durand4" + else + user.visible_message("[user] removes the wiring from [holder].", "You remove the wiring from [holder].") + var/obj/item/stack/cable_coil/coil = new /obj/item/stack/cable_coil(get_turf(holder)) + coil.amount = 4 + holder.icon_state = "durand2" + if(16) + if(diff==FORWARD) + user.visible_message("[user] installs the central control module into [holder].", "You install the central computer mainboard into [holder].") + qdel(used_atom) + holder.icon_state = "durand5" + else + user.visible_message("[user] disconnects the wiring of [holder].", "You disconnect the wiring of [holder].") + holder.icon_state = "durand3" + if(15) + if(diff==FORWARD) + user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") + holder.icon_state = "durand6" + else + user.visible_message("[user] removes the central control module from [holder].", "You remove the central computer mainboard from [holder].") + new /obj/item/weapon/circuitboard/mecha/durand/main(get_turf(holder)) + holder.icon_state = "durand4" + if(14) + if(diff==FORWARD) + user.visible_message("[user] installs the peripherals control module into [holder].", "You install the peripherals control module into [holder].") + qdel(used_atom) + holder.icon_state = "durand7" + else + user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") + holder.icon_state = "durand5" + if(13) + if(diff==FORWARD) + user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") + holder.icon_state = "durand8" + else + user.visible_message("[user] removes the peripherals control module from [holder].", "You remove the peripherals control module from [holder].") + new /obj/item/weapon/circuitboard/mecha/durand/peripherals(get_turf(holder)) + holder.icon_state = "durand6" + if(12) + if(diff==FORWARD) + user.visible_message("[user] installs the weapon control module into [holder].", "You install the weapon control module into [holder].") + qdel(used_atom) + holder.icon_state = "durand9" + else + user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") + holder.icon_state = "durand7" + if(11) + if(diff==FORWARD) + user.visible_message("[user] secures the weapon control module.", "You secure the weapon control module.") + holder.icon_state = "durand10" + else + user.visible_message("[user] removes the weapon control module from [holder].", "You remove the weapon control module from [holder].") + new /obj/item/weapon/circuitboard/mecha/durand/targeting(get_turf(holder)) + holder.icon_state = "durand8" + if(10) + if(diff==FORWARD) + user.visible_message("[user] installs advanced scanner module to [holder].", "You install advanced scanner module to [holder].") + qdel(used_atom) + holder.icon_state = "durand11" + else + user.visible_message("[user] unfastens the weapon control module.", "You unfasten the weapon control module.") + holder.icon_state = "durand9" + if(9) + if(diff==FORWARD) + user.visible_message("[user] secures the advanced scanner module.", "You secure the advanced scanner module.") + holder.icon_state = "durand12" + else + user.visible_message("[user] removes the advanced scanner module from [holder].", "You remove the advanced scanner module from [holder].") + new /obj/item/weapon/stock_parts/scanning_module/adv(get_turf(holder)) + holder.icon_state = "durand10" + if(8) + if(diff==FORWARD) + user.visible_message("[user] installs advanced capacitor to [holder].", "You install advanced capacitor to [holder].") + qdel(used_atom) + holder.icon_state = "durand13" + else + user.visible_message("[user] unfastens the advanced scanner module.", "You unfasten the advanced scanner module.") + holder.icon_state = "durand11" + if(7) + if(diff==FORWARD) + user.visible_message("[user] secures the advanced capacitor.", "You secure the advanced capacitor.") + holder.icon_state = "durand14" + else + user.visible_message("[user] removes the advanced capacitor from [holder].", "You remove the advanced capacitor from [holder].") + new /obj/item/weapon/stock_parts/capacitor/adv(get_turf(holder)) + holder.icon_state = "durand12" + if(6) + if(diff==FORWARD) + user.visible_message("[user] installs internal armor layer to [holder].", "You install internal armor layer to [holder].") + holder.icon_state = "durand15" + else + user.visible_message("[user] unfastens the advanced capacitor.", "You unfasten the advanced capacitor.") + holder.icon_state = "durand13" + if(5) + if(diff==FORWARD) + user.visible_message("[user] secures internal armor layer.", "You secure internal armor layer.") + holder.icon_state = "durand16" + else + user.visible_message("[user] pries internal armor layer from [holder].", "You prie internal armor layer from [holder].") + var/obj/item/stack/material/steel/MS = new /obj/item/stack/material/steel(get_turf(holder)) + MS.amount = 5 + holder.icon_state = "durand14" + if(4) + if(diff==FORWARD) + user.visible_message("[user] welds internal armor layer to [holder].", "You weld the internal armor layer to [holder].") + holder.icon_state = "durand17" + else + user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") + holder.icon_state = "durand15" + if(3) + if(diff==FORWARD) + user.visible_message("[user] installs Durand Armour Plates to [holder].", "You install Durand Armour Plates to [holder].") + qdel(used_atom) + holder.icon_state = "durand18" + else + user.visible_message("[user] cuts internal armor layer from [holder].", "You cut the internal armor layer from [holder].") + holder.icon_state = "durand16" + if(2) + if(diff==FORWARD) + user.visible_message("[user] secures Durand Armour Plates.", "You secure Durand Armour Plates.") + holder.icon_state = "durand19" + else + user.visible_message("[user] pries Durand Armour Plates from [holder].", "You prie Durand Armour Plates from [holder].") + new /obj/item/mecha_parts/part/durand_armour(get_turf(holder)) + holder.icon_state = "durand17" + if(1) + if(diff==FORWARD) + user.visible_message("[user] welds Durand Armour Plates to [holder].", "You weld Durand Armour Plates to [holder].") + else + user.visible_message("[user] unfastens Durand Armour Plates.", "You unfasten Durand Armour Plates.") + holder.icon_state = "durand18" + return 1 + + spawn_result() + ..() + feedback_inc("mecha_durand_created",1) + return + + +/datum/construction/mecha/phazon_chassis + result = /obj/mecha/combat/phazon + steps = list(list("key"=/obj/item/mecha_parts/part/phazon_torso),//1 + list("key"=/obj/item/mecha_parts/part/phazon_left_arm),//2 + list("key"=/obj/item/mecha_parts/part/phazon_right_arm),//3 + list("key"=/obj/item/mecha_parts/part/phazon_left_leg),//4 + list("key"=/obj/item/mecha_parts/part/phazon_right_leg),//5 + list("key"=/obj/item/mecha_parts/part/phazon_head) + ) + + custom_action(step, atom/used_atom, mob/user) + user.visible_message("[user] has connected [used_atom] to [holder].", "You connect [used_atom] to [holder]") + holder.overlays += used_atom.icon_state+"+o" + qdel(used_atom) + return 1 + + action(atom/used_atom,mob/user as mob) + return check_all_steps(used_atom,user) + + + + +/datum/construction/mecha/odysseus_chassis + steps = list(list("key"=/obj/item/mecha_parts/part/odysseus_torso),//1 + list("key"=/obj/item/mecha_parts/part/odysseus_head),//2 + list("key"=/obj/item/mecha_parts/part/odysseus_left_arm),//3 + list("key"=/obj/item/mecha_parts/part/odysseus_right_arm),//4 + list("key"=/obj/item/mecha_parts/part/odysseus_left_leg),//5 + list("key"=/obj/item/mecha_parts/part/odysseus_right_leg)//6 + ) + + custom_action(step, atom/used_atom, mob/user) + user.visible_message("[user] has connected [used_atom] to [holder].", "You connect [used_atom] to [holder]") + holder.overlays += used_atom.icon_state+"+o" + qdel(used_atom) + return 1 + + action(atom/used_atom,mob/user as mob) + return check_all_steps(used_atom,user) + + spawn_result() + var/obj/item/mecha_parts/chassis/const_holder = holder + const_holder.construct = new /datum/construction/reversible/mecha/odysseus(const_holder) + const_holder.icon = 'icons/mecha/mech_construction.dmi' + const_holder.icon_state = "odysseus0" + const_holder.set_density(1) + spawn() + qdel(src) + return + + +/datum/construction/reversible/mecha/odysseus + result = /obj/mecha/medical/odysseus + steps = list( + //1 + list("key"=/obj/item/weapon/weldingtool, + "backkey"=/obj/item/weapon/wrench, + "desc"="External armor is wrenched."), + //2 + list("key"=/obj/item/weapon/wrench, + "backkey"=/obj/item/weapon/crowbar, + "desc"="External armor is installed."), + //3 + list("key"=/obj/item/stack/material/plasteel, + "backkey"=/obj/item/weapon/weldingtool, + "desc"="Internal armor is welded."), + //4 + list("key"=/obj/item/weapon/weldingtool, + "backkey"=/obj/item/weapon/wrench, + "desc"="Internal armor is wrenched"), + //5 + list("key"=/obj/item/weapon/wrench, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Internal armor is installed"), + //6 + list("key"=/obj/item/stack/material/steel, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Peripherals control module is secured"), + //7 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Peripherals control module is installed"), + //8 + list("key"=/obj/item/weapon/circuitboard/mecha/odysseus/peripherals, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Central control module is secured"), + //9 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Central control module is installed"), + //10 + list("key"=/obj/item/weapon/circuitboard/mecha/odysseus/main, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The wiring is adjusted"), + //11 + list("key"=/obj/item/weapon/wirecutters, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The wiring is added"), + //12 + list("key"=/obj/item/stack/cable_coil, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The hydraulic systems are active."), + //13 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/wrench, + "desc"="The hydraulic systems are connected."), + //14 + list("key"=/obj/item/weapon/wrench, + "desc"="The hydraulic systems are disconnected.") + ) + + action(atom/used_atom,mob/user as mob) + return check_step(used_atom,user) + + custom_action(index, diff, atom/used_atom, mob/user) + if(!..()) + return 0 + + //TODO: better messages. + switch(index) + if(14) + user.visible_message("[user] connects [holder] hydraulic systems", "You connect [holder] hydraulic systems.") + holder.icon_state = "odysseus1" + if(13) + if(diff==FORWARD) + user.visible_message("[user] activates [holder] hydraulic systems.", "You activate [holder] hydraulic systems.") + holder.icon_state = "odysseus2" + else + user.visible_message("[user] disconnects [holder] hydraulic systems", "You disconnect [holder] hydraulic systems.") + holder.icon_state = "odysseus0" + if(12) + if(diff==FORWARD) + user.visible_message("[user] adds the wiring to [holder].", "You add the wiring to [holder].") + holder.icon_state = "odysseus3" + else + user.visible_message("[user] deactivates [holder] hydraulic systems.", "You deactivate [holder] hydraulic systems.") + holder.icon_state = "odysseus1" + if(11) + if(diff==FORWARD) + user.visible_message("[user] adjusts the wiring of [holder].", "You adjust the wiring of [holder].") + holder.icon_state = "odysseus4" + else + user.visible_message("[user] removes the wiring from [holder].", "You remove the wiring from [holder].") + var/obj/item/stack/cable_coil/coil = new /obj/item/stack/cable_coil(get_turf(holder)) + coil.amount = 4 + holder.icon_state = "odysseus2" + if(10) + if(diff==FORWARD) + user.visible_message("[user] installs the central control module into [holder].", "You install the central computer mainboard into [holder].") + qdel(used_atom) + holder.icon_state = "odysseus5" + else + user.visible_message("[user] disconnects the wiring of [holder].", "You disconnect the wiring of [holder].") + holder.icon_state = "odysseus3" + if(9) + if(diff==FORWARD) + user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") + holder.icon_state = "odysseus6" + else + user.visible_message("[user] removes the central control module from [holder].", "You remove the central computer mainboard from [holder].") + new /obj/item/weapon/circuitboard/mecha/odysseus/main(get_turf(holder)) + holder.icon_state = "odysseus4" + if(8) + if(diff==FORWARD) + user.visible_message("[user] installs the peripherals control module into [holder].", "You install the peripherals control module into [holder].") + qdel(used_atom) + holder.icon_state = "odysseus7" + else + user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") + holder.icon_state = "odysseus5" + if(7) + if(diff==FORWARD) + user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") + holder.icon_state = "odysseus8" + else + user.visible_message("[user] removes the peripherals control module from [holder].", "You remove the peripherals control module from [holder].") + new /obj/item/weapon/circuitboard/mecha/odysseus/peripherals(get_turf(holder)) + holder.icon_state = "odysseus6" + if(6) + if(diff==FORWARD) + user.visible_message("[user] installs internal armor layer to [holder].", "You install internal armor layer to [holder].") + holder.icon_state = "odysseus9" + else + user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") + holder.icon_state = "odysseus7" + if(5) + if(diff==FORWARD) + user.visible_message("[user] secures internal armor layer.", "You secure internal armor layer.") + holder.icon_state = "odysseus10" + else + user.visible_message("[user] pries internal armor layer from [holder].", "You prie internal armor layer from [holder].") + var/obj/item/stack/material/steel/MS = new /obj/item/stack/material/steel(get_turf(holder)) + MS.amount = 5 + holder.icon_state = "odysseus8" + if(4) + if(diff==FORWARD) + user.visible_message("[user] welds internal armor layer to [holder].", "You weld the internal armor layer to [holder].") + holder.icon_state = "odysseus11" + else + user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") + holder.icon_state = "odysseus9" + if(3) + if(diff==FORWARD) + user.visible_message("[user] installs [used_atom] layer to [holder].", "You install external reinforced armor layer to [holder].") + + holder.icon_state = "odysseus12" + else + user.visible_message("[user] cuts internal armor layer from [holder].", "You cut the internal armor layer from [holder].") + holder.icon_state = "odysseus10" + if(2) + if(diff==FORWARD) + user.visible_message("[user] secures external armor layer.", "You secure external reinforced armor layer.") + holder.icon_state = "odysseus13" + else + var/obj/item/stack/material/plasteel/MS = new /obj/item/stack/material/plasteel(get_turf(holder)) + MS.amount = 5 + user.visible_message("[user] pries [MS] from [holder].", "You prie [MS] from [holder].") + holder.icon_state = "odysseus11" + if(1) + if(diff==FORWARD) + user.visible_message("[user] welds external armor layer to [holder].", "You weld external armor layer to [holder].") + holder.icon_state = "odysseus14" + else + user.visible_message("[user] unfastens the external armor layer.", "You unfasten the external armor layer.") + holder.icon_state = "odysseus12" + return 1 + + spawn_result() + ..() + feedback_inc("mecha_odysseus_created",1) + return diff --git a/code/game/mecha/mecha_control_console.dm b/code/game/mecha/mecha_control_console.dm new file mode 100644 index 00000000..5b9373a7 --- /dev/null +++ b/code/game/mecha/mecha_control_console.dm @@ -0,0 +1,122 @@ +/obj/machinery/computer/mecha + name = "Exosuit Control" + icon = 'icons/obj/computer.dmi' + icon_keyboard = "rd_key" + icon_screen = "mecha" + light_color = "#a97faa" + req_access = list(access_robotics) + circuit = /obj/item/weapon/circuitboard/mecha_control + var/list/located = list() + var/screen = 0 + var/stored_data + + attack_ai(var/mob/user as mob) + return src.attack_hand(user) + + attack_hand(var/mob/user as mob) + if(..()) + return + user.set_machine(src) + var/dat = "[src.name]" + if(screen == 0) + dat += "

            Tracking beacons data

            " + for(var/obj/item/mecha_parts/mecha_tracking/TR in world) + var/answer = TR.get_mecha_info() + if(answer) + dat += {"
            [answer]
            + Send message
            + Show exosuit log | (EMP pulse)
            "} + + if(screen==1) + dat += "

            Log contents

            " + dat += "Return
            " + dat += "[stored_data]" + + dat += "(Refresh)
            " + dat += "" + + user << browse(dat, "window=computer;size=400x500") + onclose(user, "computer") + return + + Topic(href, href_list) + if(..()) + return + var/datum/topic_input/F = new /datum/topic_input(href,href_list) + if(href_list["send_message"]) + var/obj/item/mecha_parts/mecha_tracking/MT = F.getObj("send_message") + var/message = sanitize(input(usr,"Input message","Transmit message") as text) + var/obj/mecha/M = MT.in_mecha() + if(message && M) + M.occupant_message(message) + return + if(href_list["shock"]) + var/obj/item/mecha_parts/mecha_tracking/MT = F.getObj("shock") + MT.shock() + if(href_list["get_log"]) + var/obj/item/mecha_parts/mecha_tracking/MT = F.getObj("get_log") + stored_data = MT.get_mecha_log() + screen = 1 + if(href_list["return"]) + screen = 0 + src.updateUsrDialog() + return + + + +/obj/item/mecha_parts/mecha_tracking + name = "Exosuit tracking beacon" + desc = "Device used to transmit exosuit data." + icon = 'icons/obj/device.dmi' + icon_state = "motion2" + origin_tech = list(TECH_DATA = 2, TECH_MAGNET = 2) + + proc/get_mecha_info() + if(!in_mecha()) + return 0 + var/obj/mecha/M = src.loc + var/cell_charge = M.get_charge() + var/answer = {"Name: [M.name]
            + Integrity: [M.health/initial(M.health)*100]%
            + Cell charge: [isnull(cell_charge)?"Not found":"[M.cell.percent()]%"]
            + Airtank: [M.return_pressure()]kPa
            + Pilot: [M.occupant||"None"]
            + Location: [get_area(M)||"Unknown"]
            + Active equipment: [M.selected||"None"]"} + if(istype(M, /obj/mecha/working/ripley)) + var/obj/mecha/working/ripley/RM = M + answer += "Used cargo space: [RM.cargo.len/RM.cargo_capacity*100]%
            " + + return answer + + emp_act() + qdel(src) + return + + ex_act() + qdel(src) + return + + proc/in_mecha() + if(istype(src.loc, /obj/mecha)) + return src.loc + return 0 + + proc/shock() + var/obj/mecha/M = in_mecha() + if(M) + M.emp_act(2) + qdel(src) + + proc/get_mecha_log() + if(!src.in_mecha()) + return 0 + var/obj/mecha/M = src.loc + return M.get_log_html() + + +/obj/structure/closet/crate/mechabeacons + name = "exosuit tracking beacons crate" + +/obj/structure/closet/crate/mechabeacons/WillContain() + return list(/obj/item/mecha_parts/mecha_tracking = 7) diff --git a/code/game/mecha/mecha_parts.dm b/code/game/mecha/mecha_parts.dm new file mode 100644 index 00000000..b85efaa4 --- /dev/null +++ b/code/game/mecha/mecha_parts.dm @@ -0,0 +1,297 @@ +///////////////////////// +////// Mecha Parts ////// +///////////////////////// + +// Mecha circuitboards can be found in /code/game/objects/items/weapons/circuitboards/mecha.dm + +/obj/item/mecha_parts + name = "mecha part" + icon = 'icons/mecha/mech_construct.dmi' + icon_state = "blank" + w_class = ITEM_SIZE_HUGE + obj_flags = OBJ_FLAG_CONDUCTIBLE + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2) + + +/obj/item/mecha_parts/chassis + name="Mecha Chassis" + icon_state = "backbone" + randpixel = 0 + var/datum/construction/construct + obj_flags = OBJ_FLAG_CONDUCTIBLE + + attackby(obj/item/W as obj, mob/user as mob) + if(!construct || !construct.action(W, user)) + ..() + return + + attack_hand() + return + +/////////// Ripley + +/obj/item/mecha_parts/chassis/ripley + name = "Ripley Chassis" + + New() + ..() + construct = new /datum/construction/mecha/ripley_chassis(src) + +/obj/item/mecha_parts/part/ripley_torso + name="Ripley Torso" + desc="A torso part of Ripley APLU. Contains power unit, processing core and life support systems." + icon_state = "ripley_harness" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_BIO = 2, TECH_ENGINEERING = 2) + +/obj/item/mecha_parts/part/ripley_left_arm + name="Ripley Left Arm" + desc="A Ripley APLU left arm. Data and power sockets are compatible with most exosuit tools." + icon_state = "ripley_l_arm" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_ENGINEERING = 2) + +/obj/item/mecha_parts/part/ripley_right_arm + name="Ripley Right Arm" + desc="A Ripley APLU right arm. Data and power sockets are compatible with most exosuit tools." + icon_state = "ripley_r_arm" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_ENGINEERING = 2) + +/obj/item/mecha_parts/part/ripley_left_leg + name="Ripley Left Leg" + desc="A Ripley APLU left leg. Contains somewhat complex servodrives and balance maintaining systems." + icon_state = "ripley_l_leg" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_ENGINEERING = 2) + +/obj/item/mecha_parts/part/ripley_right_leg + name="Ripley Right Leg" + desc="A Ripley APLU right leg. Contains somewhat complex servodrives and balance maintaining systems." + icon_state = "ripley_r_leg" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_ENGINEERING = 2) + +///////// Gygax + +/obj/item/mecha_parts/chassis/gygax + name = "Gygax Chassis" + + New() + ..() + construct = new /datum/construction/mecha/gygax_chassis(src) + +/obj/item/mecha_parts/part/gygax_torso + name="Gygax Torso" + desc="A torso part of Gygax. Contains power unit, processing core and life support systems. Has an additional equipment slot." + icon_state = "gygax_harness" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_BIO = 3, TECH_ENGINEERING = 3) + +/obj/item/mecha_parts/part/gygax_head + name="Gygax Head" + desc="A Gygax head. Houses advanced surveilance and targeting sensors." + icon_state = "gygax_head" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_MAGNET = 3, TECH_ENGINEERING = 3) + +/obj/item/mecha_parts/part/gygax_left_arm + name="Gygax Left Arm" + desc="A Gygax left arm. Data and power sockets are compatible with most exosuit tools and weapons." + icon_state = "gygax_l_arm" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_ENGINEERING = 3) + +/obj/item/mecha_parts/part/gygax_right_arm + name="Gygax Right Arm" + desc="A Gygax right arm. Data and power sockets are compatible with most exosuit tools and weapons." + icon_state = "gygax_r_arm" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_ENGINEERING = 3) + +/obj/item/mecha_parts/part/gygax_left_leg + name="Gygax Left Leg" + icon_state = "gygax_l_leg" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_ENGINEERING = 3) + +/obj/item/mecha_parts/part/gygax_right_leg + name="Gygax Right Leg" + icon_state = "gygax_r_leg" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_ENGINEERING = 3) + +/obj/item/mecha_parts/part/gygax_armour + name="Gygax Armour Plates" + icon_state = "gygax_armour" + origin_tech = list(TECH_MATERIAL = 6, TECH_COMBAT = 4, TECH_ENGINEERING = 5) + + +//////////// Durand + +/obj/item/mecha_parts/chassis/durand + name = "Durand Chassis" + + New() + ..() + construct = new /datum/construction/mecha/durand_chassis(src) + +/obj/item/mecha_parts/part/durand_torso + name="Durand Torso" + icon_state = "durand_harness" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 3, TECH_BIO = 3, TECH_ENGINEERING = 3) + +/obj/item/mecha_parts/part/durand_head + name="Durand Head" + icon_state = "durand_head" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 3, TECH_MAGNET = 3, TECH_ENGINEERING = 3) + +/obj/item/mecha_parts/part/durand_left_arm + name="Durand Left Arm" + icon_state = "durand_l_arm" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 3, TECH_ENGINEERING = 3) + +/obj/item/mecha_parts/part/durand_right_arm + name="Durand Right Arm" + icon_state = "durand_r_arm" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 3, TECH_ENGINEERING = 3) + +/obj/item/mecha_parts/part/durand_left_leg + name="Durand Left Leg" + icon_state = "durand_l_leg" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 3, TECH_ENGINEERING = 3) + +/obj/item/mecha_parts/part/durand_right_leg + name="Durand Right Leg" + icon_state = "durand_r_leg" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 3, TECH_ENGINEERING = 3) + +/obj/item/mecha_parts/part/durand_armour + name="Durand Armour Plates" + icon_state = "durand_armour" + origin_tech = list(TECH_MATERIAL = 5, TECH_COMBAT = 4, TECH_ENGINEERING = 5) + + + +////////// Firefighter + +/obj/item/mecha_parts/chassis/firefighter + name = "Firefighter Chassis" + + New() + ..() + construct = new /datum/construction/mecha/firefighter_chassis(src) +/* +/obj/item/mecha_parts/part/firefighter_torso + name="Ripley-on-Fire Torso" + icon_state = "ripley_harness" + +/obj/item/mecha_parts/part/firefighter_left_arm + name="Ripley-on-Fire Left Arm" + icon_state = "ripley_l_arm" + +/obj/item/mecha_parts/part/firefighter_right_arm + name="Ripley-on-Fire Right Arm" + icon_state = "ripley_r_arm" + +/obj/item/mecha_parts/part/firefighter_left_leg + name="Ripley-on-Fire Left Leg" + icon_state = "ripley_l_leg" + +/obj/item/mecha_parts/part/firefighter_right_leg + name="Ripley-on-Fire Right Leg" + icon_state = "ripley_r_leg" +*/ + +////////// Phazon + +/obj/item/mecha_parts/chassis/phazon + name = "Phazon Chassis" + origin_tech = list(TECH_MATERIAL = 7) + + New() + ..() + construct = new /datum/construction/mecha/phazon_chassis(src) + +/obj/item/mecha_parts/part/phazon_torso + name="Phazon Torso" + icon_state = "phazon_harness" + //construction_time = 300 + //construction_cost = list(DEFAULT_WALL_MATERIAL=35000,"glass"=10000,"phoron"=20000) + origin_tech = list(TECH_DATA = 5, TECH_MATERIAL = 7, TECH_BLUESPACE = 6, TECH_POWER = 6) + +/obj/item/mecha_parts/part/phazon_head + name="Phazon Head" + icon_state = "phazon_head" + //construction_time = 200 + //construction_cost = list(DEFAULT_WALL_MATERIAL=15000,"glass"=5000,"phoron"=10000) + origin_tech = list(TECH_DATA = 4, TECH_MATERIAL = 5, TECH_MAGNET = 6) + +/obj/item/mecha_parts/part/phazon_left_arm + name="Phazon Left Arm" + icon_state = "phazon_l_arm" + //construction_time = 200 + //construction_cost = list(DEFAULT_WALL_MATERIAL=20000,"phoron"=10000) + origin_tech = list(TECH_MATERIAL = 5, TECH_BLUESPACE = 2, TECH_MAGNET = 2) + +/obj/item/mecha_parts/part/phazon_right_arm + name="Phazon Right Arm" + icon_state = "phazon_r_arm" + //construction_time = 200 + //construction_cost = list(DEFAULT_WALL_MATERIAL=20000,"phoron"=10000) + origin_tech = list(TECH_MATERIAL = 5, TECH_BLUESPACE = 2, TECH_MAGNET = 2) + +/obj/item/mecha_parts/part/phazon_left_leg + name="Phazon Left Leg" + icon_state = "phazon_l_leg" + //construction_time = 200 + //construction_cost = list(DEFAULT_WALL_MATERIAL=20000,"phoron"=10000) + origin_tech = list(TECH_MATERIAL = 5, TECH_BLUESPACE = 3, TECH_MAGNET = 3) + +/obj/item/mecha_parts/part/phazon_right_leg + name="Phazon Right Leg" + icon_state = "phazon_r_leg" + //construction_time = 200 + //construction_cost = list(DEFAULT_WALL_MATERIAL=20000,"phoron"=10000) + origin_tech = list(TECH_MATERIAL = 5, TECH_BLUESPACE = 3, TECH_MAGNET = 3) + +///////// Odysseus + + +/obj/item/mecha_parts/chassis/odysseus + name = "Odysseus Chassis" + + New() + ..() + construct = new /datum/construction/mecha/odysseus_chassis(src) + +/obj/item/mecha_parts/part/odysseus_head + name="Odysseus Head" + icon_state = "odysseus_head" + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 2) + +/obj/item/mecha_parts/part/odysseus_torso + name="Odysseus Torso" + desc="A torso part of Odysseus. Contains power unit, processing core and life support systems." + icon_state = "odysseus_torso" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_BIO = 2, TECH_ENGINEERING = 2) + +/obj/item/mecha_parts/part/odysseus_left_arm + name="Odysseus Left Arm" + desc="An Odysseus left arm. Data and power sockets are compatible with most exosuit tools." + icon_state = "odysseus_l_arm" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_ENGINEERING = 2) + +/obj/item/mecha_parts/part/odysseus_right_arm + name="Odysseus Right Arm" + desc="An Odysseus right arm. Data and power sockets are compatible with most exosuit tools." + icon_state = "odysseus_r_arm" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_ENGINEERING = 2) + +/obj/item/mecha_parts/part/odysseus_left_leg + name="Odysseus Left Leg" + desc="An Odysseus left leg. Contains somewhat complex servodrives and balance maintaining systems." + icon_state = "odysseus_l_leg" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_ENGINEERING = 2) + +/obj/item/mecha_parts/part/odysseus_right_leg + name="Odysseus Right Leg" + desc="A Odysseus right leg. Contains somewhat complex servodrives and balance maintaining systems." + icon_state = "odysseus_r_leg" + origin_tech = list(TECH_DATA = 2, TECH_MATERIAL = 2, TECH_ENGINEERING = 2) + +/*/obj/item/mecha_parts/part/odysseus_armour + name="Odysseus Carapace" + icon_state = "odysseus_armour" + origin_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 3) + construction_time = 200 + construction_cost = list(DEFAULT_WALL_MATERIAL=15000)*/ diff --git a/code/game/mecha/mecha_wreckage.dm b/code/game/mecha/mecha_wreckage.dm new file mode 100644 index 00000000..9a5372d0 --- /dev/null +++ b/code/game/mecha/mecha_wreckage.dm @@ -0,0 +1,202 @@ +/////////////////////////////////// +//////// Mecha wreckage //////// +/////////////////////////////////// + + +/obj/effect/decal/mecha_wreckage + name = "Exosuit wreckage" + desc = "Remains of some unfortunate mecha. Completely unrepairable." + icon = 'icons/mecha/mecha.dmi' + density = 1 + anchored = 0 + opacity = 0 + + plane = OBJ_PLANE + layer = BELOW_OBJ_LAYER + + var/list/welder_salvage = list(/obj/item/stack/material/plasteel,/obj/item/stack/material/steel,/obj/item/stack/rods) + var/list/wirecutters_salvage = list(/obj/item/stack/cable_coil) + var/list/crowbar_salvage = list() + var/salvage_num = 5 + +/obj/effect/decal/mecha_wreckage/ex_act(severity) + if(severity < 2) + spawn + qdel(src) + return + +/obj/effect/decal/mecha_wreckage/bullet_act(var/obj/item/projectile/Proj) + return + + +/obj/effect/decal/mecha_wreckage/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWelder(W)) + var/obj/item/weapon/weldingtool/WT = W + if(salvage_num <= 0) + to_chat(user, "You don't see anything that can be cut with [W].") + return + if (!isemptylist(welder_salvage) && WT.remove_fuel(0,user)) + var/type = prob(70)?pick(welder_salvage):null + if(type) + var/N = new type(get_turf(user)) + user.visible_message("[user] cuts [N] from [src]", "You cut [N] from [src]", "You hear a sound of welder nearby") + if(istype(N, /obj/item/mecha_parts/part)) + welder_salvage -= type + salvage_num-- + else + to_chat(user, "You failed to salvage anything valuable from [src].") + else + to_chat(user, "You need more welding fuel to complete this task.") + return + if(isWirecutter(W)) + if(salvage_num <= 0) + to_chat(user, "You don't see anything that can be cut with [W].") + return + else if(!isemptylist(wirecutters_salvage)) + var/type = prob(70)?pick(wirecutters_salvage):null + if(type) + var/N = new type(get_turf(user)) + user.visible_message("[user] cuts [N] from [src].", "You cut [N] from [src].") + salvage_num-- + else + to_chat(user, "You failed to salvage anything valuable from [src].") + if(isCrowbar(W)) + if(!isemptylist(crowbar_salvage)) + var/obj/S = pick(crowbar_salvage) + if(S) + S.loc = get_turf(user) + crowbar_salvage -= S + user.visible_message("[user] pries [S] from [src].", "You pry [S] from [src].") + return + else + to_chat(user, "You don't see anything that can be pried with [W].") + else + ..() + return + + +/obj/effect/decal/mecha_wreckage/gygax + name = "Gygax wreckage" + icon_state = "gygax-broken" + + New() + ..() + var/list/parts = list(/obj/item/mecha_parts/part/gygax_torso, + /obj/item/mecha_parts/part/gygax_head, + /obj/item/mecha_parts/part/gygax_left_arm, + /obj/item/mecha_parts/part/gygax_right_arm, + /obj/item/mecha_parts/part/gygax_left_leg, + /obj/item/mecha_parts/part/gygax_right_leg) + for(var/i=0;i<2;i++) + if(!isemptylist(parts) && prob(40)) + var/part = pick(parts) + welder_salvage += part + parts -= part + return + +/obj/effect/decal/mecha_wreckage/gygax/dark + name = "Dark Gygax wreckage" + icon_state = "darkgygax-broken" + +/obj/effect/decal/mecha_wreckage/marauder + name = "Marauder wreckage" + icon_state = "marauder-broken" + +/obj/effect/decal/mecha_wreckage/mauler + name = "Mauler Wreckage" + icon_state = "mauler-broken" + desc = "The syndicate won't be very happy about this..." + +/obj/effect/decal/mecha_wreckage/seraph + name = "Seraph wreckage" + icon_state = "seraph-broken" + +/obj/effect/decal/mecha_wreckage/ripley + name = "Ripley wreckage" + icon_state = "ripley-broken" + + New() + ..() + var/list/parts = list(/obj/item/mecha_parts/part/ripley_torso, + /obj/item/mecha_parts/part/ripley_left_arm, + /obj/item/mecha_parts/part/ripley_right_arm, + /obj/item/mecha_parts/part/ripley_left_leg, + /obj/item/mecha_parts/part/ripley_right_leg) + for(var/i=0;i<2;i++) + if(!isemptylist(parts) && prob(40)) + var/part = pick(parts) + welder_salvage += part + parts -= part + return + +/obj/effect/decal/mecha_wreckage/ripley/firefighter + name = "Firefighter wreckage" + icon_state = "firefighter-broken" + + New() + ..() + var/list/parts = list(/obj/item/mecha_parts/part/ripley_torso, + /obj/item/mecha_parts/part/ripley_left_arm, + /obj/item/mecha_parts/part/ripley_right_arm, + /obj/item/mecha_parts/part/ripley_left_leg, + /obj/item/mecha_parts/part/ripley_right_leg, + /obj/item/clothing/suit/fire) + for(var/i=0;i<2;i++) + if(!isemptylist(parts) && prob(40)) + var/part = pick(parts) + welder_salvage += part + parts -= part + return + +/obj/effect/decal/mecha_wreckage/ripley/deathripley + name = "Death-Ripley wreckage" + icon_state = "deathripley-broken" + +/obj/effect/decal/mecha_wreckage/durand + name = "Durand wreckage" + icon_state = "durand-broken" + + New() + ..() + var/list/parts = list( + /obj/item/mecha_parts/part/durand_torso, + /obj/item/mecha_parts/part/durand_head, + /obj/item/mecha_parts/part/durand_left_arm, + /obj/item/mecha_parts/part/durand_right_arm, + /obj/item/mecha_parts/part/durand_left_leg, + /obj/item/mecha_parts/part/durand_right_leg) + for(var/i=0;i<2;i++) + if(!isemptylist(parts) && prob(40)) + var/part = pick(parts) + welder_salvage += part + parts -= part + return + +/obj/effect/decal/mecha_wreckage/phazon + name = "Phazon wreckage" + icon_state = "phazon-broken" + + +/obj/effect/decal/mecha_wreckage/odysseus + name = "Odysseus wreckage" + icon_state = "odysseus-broken" + + New() + ..() + var/list/parts = list( + /obj/item/mecha_parts/part/odysseus_torso, + /obj/item/mecha_parts/part/odysseus_head, + /obj/item/mecha_parts/part/odysseus_left_arm, + /obj/item/mecha_parts/part/odysseus_right_arm, + /obj/item/mecha_parts/part/odysseus_left_leg, + /obj/item/mecha_parts/part/odysseus_right_leg) + for(var/i=0;i<2;i++) + if(!isemptylist(parts) && prob(40)) + var/part = pick(parts) + welder_salvage += part + parts -= part + return + +/obj/effect/decal/mecha_wreckage/hoverpod + name = "Hover pod wreckage" + icon_state = "engineering_pod-broken" diff --git a/code/game/mecha/medical/medical.dm b/code/game/mecha/medical/medical.dm new file mode 100644 index 00000000..9b80787a --- /dev/null +++ b/code/game/mecha/medical/medical.dm @@ -0,0 +1,23 @@ +/obj/mecha/medical/Initialize() + . = ..() + var/turf/T = get_turf(src) + if(isPlayerLevel(T.z)) + new /obj/item/mecha_parts/mecha_tracking(src) + + +/obj/mecha/medical/mechturn(direction) + set_dir(direction) + playsound(src,'sound/mecha/mechmove01.ogg',40,1) + return 1 + +/obj/mecha/medical/mechstep(direction) + var/result = step(src,direction) + if(result) + playsound(src,'sound/mecha/mechstep.ogg',25,1) + return result + +/obj/mecha/medical/mechsteprand() + var/result = step_rand(src) + if(result) + playsound(src,'sound/mecha/mechstep.ogg',25,1) + return result \ No newline at end of file diff --git a/code/game/mecha/medical/odysseus.dm b/code/game/mecha/medical/odysseus.dm new file mode 100644 index 00000000..b4e1db10 --- /dev/null +++ b/code/game/mecha/medical/odysseus.dm @@ -0,0 +1,133 @@ +/obj/mecha/medical/odysseus + desc = "These exosuits are developed and produced by Vey-Med. (© All rights reserved)." + name = "Odysseus" + icon_state = "odysseus" + initial_icon = "odysseus" + step_in = 2 + max_temperature = 15000 + health = 120 + wreckage = /obj/effect/decal/mecha_wreckage/odysseus + internal_damage_threshold = 35 + deflect_chance = 15 + var/obj/item/clothing/glasses/hud/health/mech/hud + + New() + ..() + hud = new /obj/item/clothing/glasses/hud/health/mech(src) + return + + moved_inside(var/mob/living/carbon/human/H as mob) + if(..()) + if(H.glasses) + occupant_message("[H.glasses] prevent you from using [src] [hud]") + else + H.glasses = hud + return 1 + else + return 0 + + go_out() + if(ishuman(occupant)) + var/mob/living/carbon/human/H = occupant + if(H.glasses == hud) + H.glasses = null + ..() + return +/* + verb/set_perspective() + set name = "Set client perspective." + set category = "Exosuit Interface" + set src = usr.loc + var/perspective = input("Select a perspective type.", + "Client perspective", + occupant.client.perspective) in list(MOB_PERSPECTIVE,EYE_PERSPECTIVE) + log_debug("[perspective]") + + occupant.client.perspective = perspective + return + + verb/toggle_eye() + set name = "Toggle eye." + set category = "Exosuit Interface" + set src = usr.loc + if(occupant.client.eye == occupant) + occupant.client.eye = src + else + occupant.client.eye = occupant + log_debug("[occupant.client.eye]") + + return +*/ + +//TODO - Check documentation for client.eye and client.perspective... +/obj/item/clothing/glasses/hud/health/mech + name = "Integrated Medical Hud" + + + process_hud(var/mob/M) +/* + log_debug("view(M)") + + for(var/mob/mob in view(M)) + log_debug("[mob]") + + log_debug("view(M.client)") + + for(var/mob/mob in view(M.client)) + log_debug("[mob]") + + log_debug("view(M.loc)") + + for(var/mob/mob in view(M.loc)) + log_debug("[mob]") + +*/ + + if(!M || M.stat || !(M in view(M))) return + if(!M.client) return + var/client/C = M.client + var/image/holder + for(var/mob/living/carbon/human/patient in view(M.loc)) + if(M.see_invisible < patient.invisibility) + continue + var/foundVirus = 0 + + for (var/ID in patient.virus2) + if (ID in virusDB) + foundVirus = 1 + break + + holder = patient.hud_list[HEALTH_HUD] + if(patient.stat == DEAD) + holder.icon_state = "hudhealth-100" + C.images += holder + else + holder.icon_state = "hudhealth-100" // TODO + C.images += holder + + holder = patient.hud_list[STATUS_HUD] + if(patient.stat == DEAD) + holder.icon_state = "huddead" + else if(patient.status_flags & XENO_HOST) + holder.icon_state = "hudxeno" + else if(foundVirus) + holder.icon_state = "hudill" + else if(patient.has_brain_worms()) + var/mob/living/simple_animal/borer/B = patient.has_brain_worms() + if(B.controlling) + holder.icon_state = "hudbrainworm" + else + holder.icon_state = "hudhealthy" + else + holder.icon_state = "hudhealthy" + + C.images += holder + +/obj/mecha/medical/odysseus/loaded/New() + ..() + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/tool/sleeper + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/tool/sleeper + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/tool/syringe_gun + ME.attach(src) \ No newline at end of file diff --git a/code/game/mecha/working/hoverpod.dm b/code/game/mecha/working/hoverpod.dm new file mode 100644 index 00000000..55bb8843 --- /dev/null +++ b/code/game/mecha/working/hoverpod.dm @@ -0,0 +1,102 @@ +/obj/mecha/working/hoverpod + desc = "Stubby and round, this space-capable craft is an ancient favorite." + name = "Hover Pod" + icon_state = "engineering_pod" + initial_icon = "engineering_pod" + internal_damage_threshold = 80 + step_in = 4 + step_energy_drain = 400 + max_temperature = 20000 + health = 150 + infra_luminosity = 6 + wreckage = /obj/effect/decal/mecha_wreckage/hoverpod + cargo_capacity = 5 + max_equip = 3 + var/datum/effect/effect/system/trail/ion_trail + var/stabilization_enabled = 1 + +/obj/mecha/working/hoverpod/New() + ..() + ion_trail = new /datum/effect/effect/system/trail/ion() + ion_trail.set_up(src) + ion_trail.start() + +//Modified phazon code +/obj/mecha/working/hoverpod/Topic(href, href_list) + ..() + if (href_list["toggle_stabilization"]) + stabilization_enabled = !stabilization_enabled + send_byjax(src.occupant,"exosuit.browser","stabilization_command","[stabilization_enabled?"Dis":"En"]able thruster stabilization") + src.occupant_message("Thruster stabilization [stabilization_enabled? "enabled" : "disabled"].") + return + +/obj/mecha/working/hoverpod/get_commands() + var/output = {" + "} + output += ..() + return output + +//No space drifting +/obj/mecha/working/hoverpod/check_for_support() + //does the hoverpod have enough charge left to stabilize itself? + if (!has_charge(step_energy_drain)) + ion_trail.stop() + else + if (!ion_trail.on) + ion_trail.start() + if (stabilization_enabled) + return 1 + + return ..() + +//these three procs overriden to play different sounds +/obj/mecha/working/hoverpod/mechturn(direction) + set_dir(direction) + //playsound(src,'sound/machines/hiss.ogg',40,1) + return 1 + +/obj/mecha/working/hoverpod/mechstep(direction) + var/result = step(src,direction) + if(result) + playsound(src,'sound/machines/hiss.ogg',40,1) + return result + + +/obj/mecha/working/hoverpod/mechsteprand() + var/result = step_rand(src) + if(result) + playsound(src,'sound/machines/hiss.ogg',40,1) + return result + + +//Hoverpod variants +/obj/mecha/working/hoverpod/combatpod + desc = "An ancient, run-down combat spacecraft." // Ideally would have a seperate icon. + name = "Combat Hoverpod" + health = 200 + internal_damage_threshold = 35 + cargo_capacity = 2 + max_equip = 2 + +/obj/mecha/working/hoverpod/combatpod/New() + ..() + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/explosive + ME.attach(src) + + +/obj/mecha/working/hoverpod/shuttlepod + desc = "Who knew a tiny ball could fit three people?" + +/obj/mecha/working/hoverpod/shuttlepod/New() + ..() + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/tool/passenger + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/tool/passenger + ME.attach(src) diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm new file mode 100644 index 00000000..088ee0c5 --- /dev/null +++ b/code/game/mecha/working/ripley.dm @@ -0,0 +1,70 @@ +/obj/mecha/working/ripley + desc = "Autonomous Power Loader Unit. The workhorse of the exosuit world." + name = "APLU \"Ripley\"" + icon_state = "ripley" + initial_icon = "ripley" + step_in = 6 + max_temperature = 20000 + health = 200 + wreckage = /obj/effect/decal/mecha_wreckage/ripley + cargo_capacity = 10 + +/obj/mecha/working/ripley/Destroy() + for(var/atom/movable/A in src.cargo) + A.loc = loc + var/turf/T = loc + if(istype(T)) + T.Entered(A) + step_rand(A) + cargo.Cut() + ..() + +/obj/mecha/working/ripley/firefighter + desc = "Standart APLU chassis was refitted with additional thermal protection and cistern." + name = "APLU \"Firefighter\"" + icon_state = "firefighter" + initial_icon = "firefighter" + max_temperature = 65000 + health = 250 + lights_power = 8 + damage_absorption = list("fire"=0.5,"bullet"=0.8,"bomb"=0.5) + wreckage = /obj/effect/decal/mecha_wreckage/ripley/firefighter + +/obj/mecha/working/ripley/deathripley + desc = "OH SHIT IT'S THE DEATHSQUAD WE'RE ALL GONNA DIE!" + name = "DEATH-RIPLEY" + icon_state = "deathripley" + initial_icon = "deathripley" + step_in = 2 + opacity=0 + lights_power = 60 + wreckage = /obj/effect/decal/mecha_wreckage/ripley/deathripley + step_energy_drain = 0 + +/obj/mecha/working/ripley/deathripley/New() + ..() + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/tool/safety_clamp + ME.attach(src) + return + +/obj/mecha/working/ripley/mining + desc = "An old, dusty mining ripley." + name = "APLU \"Miner\"" + +/obj/mecha/working/ripley/mining/New() + ..() + //Attach drill + if(prob(25)) //Possible diamond drill... Feeling lucky? + var/obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill/D = new /obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill + D.attach(src) + else + var/obj/item/mecha_parts/mecha_equipment/tool/drill/D = new /obj/item/mecha_parts/mecha_equipment/tool/drill + D.attach(src) + + //Attach hydrolic clamp + var/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/HC = new /obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp + HC.attach(src) + for(var/obj/item/mecha_parts/mecha_tracking/B in src.contents)//Deletes the beacon so it can't be found easily + qdel (B) + + diff --git a/code/game/mecha/working/working.dm b/code/game/mecha/working/working.dm new file mode 100644 index 00000000..a6748af7 --- /dev/null +++ b/code/game/mecha/working/working.dm @@ -0,0 +1,59 @@ +/obj/mecha/working + internal_damage_threshold = 60 + var/list/cargo = new + var/cargo_capacity = 5 + +/obj/mecha/working/Initialize() + . = ..() + var/turf/T = get_turf(src) + if(isPlayerLevel(T.z)) + new /obj/item/mecha_parts/mecha_tracking(src) + +/obj/mecha/working/Destroy() + for(var/mob/M in src) + if(M==src.occupant) + continue + M.loc = get_turf(src) + M.loc.Entered(M) + step_rand(M) + for(var/atom/movable/A in src.cargo) + A.loc = get_turf(src) + var/turf/T = get_turf(A) + if(T) + T.Entered(A) + step_rand(A) + ..() + return + +/obj/mecha/working/Topic(href, href_list) + ..() + if(href_list["drop_from_cargo"]) + var/obj/O = locate(href_list["drop_from_cargo"]) + if(O && O in src.cargo) + src.occupant_message("You unload [O].") + O.loc = get_turf(src) + src.cargo -= O + var/turf/T = get_turf(O) + if(T) + T.Entered(O) + src.log_message("Unloaded [O]. Cargo compartment capacity: [cargo_capacity - src.cargo.len]") + return + +/obj/mecha/working/Exit(atom/movable/O) + if(O in cargo) + return 0 + return ..() + +/obj/mecha/working/get_stats_part() + var/output = ..() + output += "Cargo Compartment Contents:
            " + if(src.cargo.len) + for(var/obj/O in src.cargo) + output += "Unload : [O]
            " + else + output += "Nothing" + output += "
            " + return output + +/obj/mecha/working/range_action(atom/target as obj|mob|turf) + return diff --git a/code/game/movietitles.dm b/code/game/movietitles.dm new file mode 100644 index 00000000..d84fbe58 --- /dev/null +++ b/code/game/movietitles.dm @@ -0,0 +1,177 @@ +#define CREDIT_ROLL_SPEED 185 +#define CREDIT_SPAWN_SPEED 20 +#define CREDIT_ANIMATE_HEIGHT (14 * world.icon_size) +#define CREDIT_EASE_DURATION 22 + +GLOBAL_LIST(end_titles) + +client + var/list/credits + +/client/proc/RollCredits() + set waitfor = FALSE + + if(!GLOB.end_titles) + GLOB.end_titles = generate_titles() + + LAZYINITLIST(credits) + + if(mob) + mob.overlay_fullscreen("fishbed",/obj/screen/fullscreen/fishbed) + mob.overlay_fullscreen("fadeout",/obj/screen/fullscreen/fadeout) + + if(mob.get_preference_value(/datum/client_preference/play_lobby_music) == GLOB.PREF_YES) + sound_to(mob, sound(null, channel = 1)) + sound_to(mob, sound('sound/music/THUNDERDOME.ogg', wait = 0, volume = 40, channel = 1)) + sleep(50) + var/list/_credits = credits + verbs += /client/proc/ClearCredits + for(var/I in GLOB.end_titles) + if(!credits) + return + var/obj/screen/credit/T = new(null, I, src) + _credits += T + T.rollem() + sleep(CREDIT_SPAWN_SPEED) + sleep(CREDIT_ROLL_SPEED - CREDIT_SPAWN_SPEED) + + ClearCredits() + verbs -= /client/proc/ClearCredits + +/client/proc/ClearCredits() + set name = "Stop End Titles" + set category = "OOC" + verbs -= /client/proc/ClearCredits + QDEL_NULL_LIST(credits) + mob.clear_fullscreen("fishbed") + mob.clear_fullscreen("fadeout") + sound_to(mob, sound(null, channel = 1)) + +/obj/screen/credit + icon_state = "blank" + mouse_opacity = 0 + alpha = 0 + screen_loc = "1,1" + plane = HUD_PLANE + layer = HUD_ABOVE_ITEM_LAYER + var/client/parent + var/matrix/target + +/obj/screen/credit/Initialize(mapload, credited, client/P) + . = ..() + parent = P + maptext = credited + maptext_height = world.icon_size * 2 + maptext_width = world.icon_size * 14 + +/obj/screen/credit/proc/rollem() + var/matrix/M = matrix(transform) + M.Translate(0, CREDIT_ANIMATE_HEIGHT) + animate(src, transform = M, time = CREDIT_ROLL_SPEED) + target = M + animate(src, alpha = 255, time = CREDIT_EASE_DURATION, flags = ANIMATION_PARALLEL) + spawn(CREDIT_ROLL_SPEED - CREDIT_EASE_DURATION) + if(!QDELETED(src)) + animate(src, alpha = 0, transform = target, time = CREDIT_EASE_DURATION) + sleep(CREDIT_EASE_DURATION) + qdel(src) + parent.screen += src + +/obj/screen/credit/Destroy() + var/client/P = parent + if(parent) + P.screen -= src + LAZYREMOVE(P.credits, src) + parent = null + return ..() + +/proc/generate_titles() + var/list/titles = list() + var/list/cast = list() + var/list/chunk = list() + var/list/possible_titles = list() + var/chunksize = 0 + + /* Establish a big-ass list of potential titles for the "episode". */ + possible_titles += "THE [pick("DOWNFALL OF", "RISE OF", "TROUBLE WITH", "FINAL STAND OF", "DARK SIDE OF")] [pick("SPACEMEN", "HUMANITY", "DIGNITY", "SANITY", "THE CHIMPANZEES", "THE VENDOMAT PRICES","[uppertext(GLOB.using_map.station_name)]")]" + possible_titles += "THE CREW GETS [pick("RACIST", "PICKLED", "AN INCURABLE DISEASE", "PIZZA", "A VALUABLE HISTORY LESSON", "A BREAK", "HIGH", "TO LIVE", "TO RELIVE THEIR CHILDHOOD", "EMBROILED IN CIVIL WAR", "SERIOUS ABOUT [pick("DRUG ABUSE", "CRIME", "PRODUCTIVITY", "ANCIENT AMERICAN CARTOONS", "SPACEBALL")]")]" + possible_titles += "THE CREW LEARNS ABOUT [pick("LOVE", "DRUGS", "THE DANGERS OF MONEY LAUNDERING", "XENIC SENSITIVITY", "INVESTMENT FRAUD", "KELOTANE ABUSE", "RADIATION PROTECTION", "SACRED GEOMETRY", "STRING THEORY", "ABSTRACT MATHEMATICS", "[pick("TAJARAN", "UNATHI", "SKRELLIAN", "DIONAN", "KHAARMANI", "VOX", "SERPENTID")] MATING RITUALS", "ANCIENT CHINESE MEDICINE")]" + possible_titles += "A VERY [pick("NANOTRASEN", "EXPEDITIONARY", "DIONA", "PHORON", "MARTIAN")] CHRISTMAS" + possible_titles += "[pick("GUNS, GUNS EVERYWHERE", "THE LITTLEST ARMALIS", "WHAT HAPPENS WHEN YOU MIX MAINTENANCE DRONES AND COMMERCIAL-GRADE PACKING FOAM", "ATTACK! ATTACK! ATTACK!", "SEX BOMB")]" + possible_titles += "[pick("SPACE", "SEXY", "DRAGON", "WARLOCK", "LAUNDRY", "GUN", "ADVERTISING", "DOG", "CARBON MONOXIDE", "NINJA", "WIZARD", "SOCRATIC", "JUVENILE DELIQUENCY", "POLITICALLY MOTIVATED", "RADTACULAR SICKNASTY")] [pick("QUEST", "FORCE", "ADVENTURE")]" + possible_titles += "[pick("THE DAY [uppertext(GLOB.using_map.station_short)] STOOD STILL", "HUNT FOR THE GREEN WEENIE", "ALIEN VS VENDOMAT", "SPACE TRACK")]" + titles += "

            EPISODE [rand(1,1000)]
            [pick(possible_titles)]

            " + for(var/mob/living/carbon/human/H in GLOB.living_mob_list_|GLOB.dead_mob_list_) + if(findtext(H.real_name,"(mannequin)")) + continue + if(H.isMonkey() && findtext(H.real_name,"[lowertext(H.species.name)]")) //no monki + continue + if(H.timeofdeath && H.timeofdeath < 5 MINUTES) //don't mention these losers (prespawned corpses mostly) + continue + if(!cast.len && !chunksize) + chunk += "CAST:" + var/job = "" + if(GetAssignment(H) != "Unassigned") + job = ", [uppertext(GetAssignment(H))]" + var/used_name = H.real_name + var/datum/computer_file/crew_record/R = get_crewmember_record(H.real_name) + if(R && R.get_rank()) + var/datum/mil_rank/rank = mil_branches.get_rank(R.get_branch(), R.get_rank()) + if(rank.name_short) + used_name = "[rank.name_short] [used_name]" + if(prob(90)) + var/actor_name = H.species.get_random_name(H.gender) + if(!(H.species.spawn_flags & SPECIES_CAN_JOIN) || prob(10)) //sometimes can't get actor of thos species + var/datum/species/S = all_species["Human"] + actor_name = S.get_random_name(H.gender) + chunk += "[actor_name]\t \t \t \t[uppertext(used_name)][job]" + else + var/datum/gender/G = gender_datums[H.gender] + chunk += "[used_name]\t \t \t \t[uppertext(G.him)]SELF" + chunksize++ + if(chunksize > 2) + cast += "
            [jointext(chunk,"
            ")]
            " + chunk.Cut() + chunksize = 0 + if(chunk.len) + cast += "
            [jointext(chunk,"
            ")]
            " + + titles += cast + + var/list/corpses = list() + var/list/monkies = list() + for(var/mob/living/carbon/human/H in GLOB.dead_mob_list_) + if(H.timeofdeath < 5 MINUTES) //no prespawned corpses + continue + if(H.isMonkey() && findtext(H.real_name,"[lowertext(H.species.name)]")) + monkies[H.species.name] += 1 + else if(H.real_name) + corpses += H.real_name + for(var/spec in monkies) + var/datum/species/S = all_species[spec] + corpses += "[monkies[spec]] [lowertext(monkies[spec] > 1 ? S.name_plural : S.name)]" + if(corpses.len) + titles += "
            BASED ON REAL EVENTS
            In memory of [english_list(corpses)].
            " + + var/list/staff = list("PRODUCTION STAFF:") + var/list/staffjobs = list("Coffe Fetcher", "Cameraman", "Angry Yeller", "Chair Operator", "Choreographer", "Historical Consultant", "Costume Designer", "Chief Editor", "Executive Assistant") + var/list/goodboys = list() + for(var/client/C) + if(!C.holder) + continue + if(C.holder.rights & (R_DEBUG|R_ADMIN)) + var/datum/species/S = all_species[pick(all_species)] + var/g = prob(50) ? MALE : FEMALE + staff += "[uppertext(pick(staffjobs))] - [S.get_random_name(g)] a.k.a. '[C.key]'" + else if(C.holder.rights & R_MOD) + goodboys += "[C.key]" + + titles += "
            [jointext(staff,"
            ")]
            " + if(goodboys.len) + titles += "
            STAFF'S GOOD BOYS:
            [english_list(goodboys)]
            " + + var/disclaimer = "Sponsored by [GLOB.using_map.company_name].
            All rights reserved.
            " + disclaimer += pick("Use for parody prohibited. Prohibited.", "All stunts were performed by underpaid interns. Do NOT try at home.", "[GLOB.using_map.company_name] does not endorse behaviour depicted. Attempt at your own risk.") + titles += "
            [disclaimer]
            " + + return titles diff --git a/code/game/objects/auras/aura.dm b/code/game/objects/auras/aura.dm new file mode 100644 index 00000000..36801694 --- /dev/null +++ b/code/game/objects/auras/aura.dm @@ -0,0 +1,49 @@ +/*Auras are simple: They are simple overriders for attackbys, bullet_act, damage procs, etc. They also tick after their respective mob. +They should be used for undeterminate mob effects, like for instance a toggle-able forcefield, or indestructability as long as you don't move. +They should also be used for when you want to effect the ENTIRE mob, like having an armor buff or showering candy everytime you walk. +*/ + +/obj/aura + var/mob/living/user + +/obj/aura/New(var/mob/living/target) + ..() + user = target + user.add_aura(src) + +/obj/aura/Destroy() + if(user) + user.remove_aura(src) + user = null + return ..() + +/obj/aura/proc/life_tick() + return 0 + +/obj/aura/attackby(var/obj/item/I, var/mob/user) + return 0 + +/obj/aura/bullet_act(var/obj/item/projectile/P, var/def_zone) + return 0 + +/obj/aura/hitby(var/atom/movable/M, var/speed) + return 0 + +/obj/aura/debug + var/returning = 0 + +/obj/aura/debug/attackby(var/obj/item/I, var/mob/user) + log_debug("Attackby for \ref[src]: [I], [user]") + return returning + +/obj/aura/debug/bullet_act(var/obj/item/projectile/P, var/def_zone) + log_debug("Bullet Act for \ref[src]: [P], [def_zone]") + return returning + +/obj/aura/debug/life_tick() + log_debug("Life tick") + return returning + +/obj/aura/debug/hitby(var/atom/movable/M, var/speed) + log_debug("Hit By for \ref[src]: [M], [speed]") + return returning \ No newline at end of file diff --git a/code/game/objects/auras/personal_shields/personal_shield.dm b/code/game/objects/auras/personal_shields/personal_shield.dm new file mode 100644 index 00000000..22aa393b --- /dev/null +++ b/code/game/objects/auras/personal_shields/personal_shield.dm @@ -0,0 +1,34 @@ +/obj/aura/personal_shield + name = "personal shield" + +/obj/aura/personal_shield/New(var/mob/living/user) + ..() + playsound(user,'sound/weapons/flash.ogg',35,1) + to_chat(user,"You feel your body prickle as \the [src] comes online.") + +/obj/aura/personal_shield/bullet_act(var/obj/item/projectile/P, var/def_zone) + user.visible_message("\The [user]'s [src.name] flashes before \the [P] can hit them!") + new /obj/effect/shield_impact(user.loc) + playsound(user,'sound/effects/basscannon.ogg',35,1) + return AURA_FALSE|AURA_CANCEL + +/obj/aura/personal_shield/Destroy() + to_chat(user,"\The [src] goes offline!") + playsound(user,'sound/mecha/internaldmgalarm.ogg',25,1) + return ..() + +/obj/aura/personal_shield/device + var/obj/item/device/personal_shield/shield + +/obj/aura/personal_shield/device/bullet_act() + . = ..() + if(shield) + shield.take_charge() + +/obj/aura/personal_shield/device/New(var/mob/living/user, var/user_shield) + ..() + shield = user_shield + +/obj/aura/personal_shield/device/Destroy() + shield = null + return ..() \ No newline at end of file diff --git a/code/game/objects/auras/radiant_aura.dm b/code/game/objects/auras/radiant_aura.dm new file mode 100644 index 00000000..28dd8085 --- /dev/null +++ b/code/game/objects/auras/radiant_aura.dm @@ -0,0 +1,21 @@ +/obj/aura/radiant_aura + name = "radiant aura" + icon = 'icons/effects/effects.dmi' + icon_state = "fire_goon" + plane = OBJ_PLANE + layer = ABOVE_WINDOW_LAYER + +/obj/aura/radiant_aura/New() + ..() + to_chat(user,"A bubble of light appears around you, exuding protection and warmth.") + set_light(6,6, "#e09d37") + +/obj/aura/radiant_aura/Destroy() + to_chat(user, "Your protective aura dissipates, leaving you feeling cold and unsafe.") + return ..() + +/obj/aura/radiant_aura/bullet_act(var/obj/item/projectile/P, var/def_zone) + if(P.check_armour == "laser") + user.visible_message("\The [P] refracts, bending into \the [user]'s aura.") + return AURA_FALSE + return 0 \ No newline at end of file diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm new file mode 100644 index 00000000..a0fb139a --- /dev/null +++ b/code/game/objects/buckling.dm @@ -0,0 +1,112 @@ +/obj + var/can_buckle = 0 + var/buckle_movable = 0 + var/buckle_dir = 0 + var/buckle_lying = -1 //bed-like behavior, forces mob.lying = buckle_lying if != -1 + var/buckle_pixel_shift = "x=0;y=0" //where the buckled mob should be pixel shifted to, or null for no pixel shift control + var/buckle_require_restraints = 0 //require people to be handcuffed before being able to buckle. eg: pipes + var/mob/living/buckled_mob = null + +/obj/attack_hand(mob/living/user) + . = ..() + if(can_buckle && buckled_mob) + user_unbuckle_mob(user) + +/obj/MouseDrop_T(mob/living/M, mob/living/user) + . = ..() + if(can_buckle && istype(M)) + user_buckle_mob(M, user) + +/obj/Destroy() + unbuckle_mob() + return ..() + + +/obj/proc/buckle_mob(mob/living/M) + if(buckled_mob) //unless buckled_mob becomes a list this can cause problems + return 0 + if(!istype(M) || (M.loc != loc) || M.buckled || M.pinned.len || (buckle_require_restraints && !M.restrained())) + return 0 + if(ismob(src)) + var/mob/living/carbon/C = src //Don't wanna forget the xenos. + if(M != src && C.incapacitated()) + return 0 + + M.buckled = src + M.facing_dir = null + M.set_dir(buckle_dir ? buckle_dir : dir) + M.update_canmove() + M.update_floating() + buckled_mob = M + + post_buckle_mob(M) + return 1 + +/obj/proc/unbuckle_mob() + if(buckled_mob && buckled_mob.buckled == src) + . = buckled_mob + buckled_mob.buckled = null + buckled_mob.anchored = initial(buckled_mob.anchored) + buckled_mob.update_canmove() + buckled_mob.update_floating() + buckled_mob = null + + post_buckle_mob(.) + +/obj/proc/post_buckle_mob(mob/living/M) + if(buckle_pixel_shift) + if(M == buckled_mob) + var/list/pixel_shift = cached_key_number_decode(buckle_pixel_shift) + animate(M, pixel_x = M.default_pixel_x + pixel_shift["x"], pixel_y = M.default_pixel_y + pixel_shift["y"], 4, 1, LINEAR_EASING) + else + animate(M, pixel_x = M.default_pixel_x, pixel_y = M.default_pixel_y, 4, 1, LINEAR_EASING) + +/obj/proc/user_buckle_mob(mob/living/M, mob/user, silent) + if(!ticker) //why do we need to check this? + to_chat(user, "You can't buckle anyone in before the game starts.") + return 0 + if(!user.Adjacent(M) || user.restrained() || user.stat || istype(user, /mob/living/silicon/pai)) + return 0 + if(M == buckled_mob) + return 0 + if(istype(M, /mob/living/carbon/slime)) + to_chat(user, "The [M] is too squishy to buckle in.") + return 0 + + add_fingerprint(user) + unbuckle_mob() + + //can't buckle unless you share locs so try to move M to the obj. + if(M.loc != src.loc) + step_towards(M, src) + + . = buckle_mob(M) + if(.) + if(!silent) + if(M == user) + M.visible_message(\ + "[M.name] sits on [src].",\ + "You sit on [src].",\ + "You hear metal clanking.") + else + M.visible_message(\ + "[M.name] is sat onto [src] by [user.name]!",\ + "You are sat onto [src] by [user.name]!",\ + "You hear metal clanking.") + +/obj/proc/user_unbuckle_mob(mob/user) + var/mob/living/M = unbuckle_mob() + if(M) + if(M != user) + M.visible_message(\ + "[M.name] was helped up by [user.name]!",\ + "You were helped up from [src] by [user.name].",\ + "You hear metal clanking.") + else + M.visible_message(\ + "[M.name] rises from [src]!",\ + "You rise from [src].",\ + "You hear metal clanking.") + add_fingerprint(user) + return M + diff --git a/code/game/objects/effects/aliens.dm b/code/game/objects/effects/aliens.dm new file mode 100644 index 00000000..ae1a172d --- /dev/null +++ b/code/game/objects/effects/aliens.dm @@ -0,0 +1,56 @@ +/* + * Acid + */ + #define ACID_STRONG 2 + #define ACID_MODERATE 1.5 + #define ACID_WEAK 1 + +/obj/effect/acid + name = "acid" + desc = "Burbling corrosive stuff. Probably a bad idea to roll around in it." + icon_state = "acid" + icon = 'icons/mob/alien.dmi' + + density = 0 + opacity = 0 + anchored = 1 + + var/atom/target + var/acid_strength = ACID_WEAK + var/melt_time = 10 SECONDS + var/last_melt = 0 + +/obj/effect/acid/New(loc, supplied_target) + ..(loc) + target = supplied_target + melt_time = melt_time / acid_strength + START_PROCESSING(SSprocessing, src) + +/obj/effect/acid/Destroy() + STOP_PROCESSING(SSprocessing, src) + target = null + . = ..() + +/obj/effect/acid/Process() + if(QDELETED(target)) + qdel(src) + else if(world.time > last_melt + melt_time) + var/done_melt = target.acid_melt() + last_melt = world.time + if(done_melt) + qdel(src) + +/atom/var/acid_melted = 0 + +/atom/proc/acid_melt() + . = FALSE + switch(acid_melted) + if(0) + visible_message("Acid hits \the [src] with a sizzle!") + if(1 to 3) + visible_message("The acid melts \the [src]!") + if(4) + visible_message("The acid melts \the [src] away into nothing!") + . = TRUE + qdel(src) + acid_melted++ diff --git a/code/game/objects/effects/bump_teleporter.dm b/code/game/objects/effects/bump_teleporter.dm new file mode 100644 index 00000000..07018396 --- /dev/null +++ b/code/game/objects/effects/bump_teleporter.dm @@ -0,0 +1,34 @@ +var/list/obj/effect/bump_teleporter/BUMP_TELEPORTERS = list() + +/obj/effect/bump_teleporter + name = "bump-teleporter" + icon = 'icons/mob/screen1.dmi' + icon_state = "x2" + var/id = null //id of this bump_teleporter. + var/id_target = null //id of bump_teleporter which this moves you to. + invisibility = 101 //nope, can't see this + anchored = 1 + density = 1 + opacity = 0 + +/obj/effect/bump_teleporter/New() + ..() + BUMP_TELEPORTERS += src + +/obj/effect/bump_teleporter/Destroy() + BUMP_TELEPORTERS -= src + return ..() + +/obj/effect/bump_teleporter/Bumped(atom/user) + if(!ismob(user)) + //user.loc = src.loc //Stop at teleporter location + return + + if(!id_target) + //user.loc = src.loc //Stop at teleporter location, there is nowhere to teleport to. + return + + for(var/obj/effect/bump_teleporter/BT in BUMP_TELEPORTERS) + if(BT.id == src.id_target) + usr.forceMove(BT.loc) //Teleport to location with correct id. + return \ No newline at end of file diff --git a/code/game/objects/effects/chem/chemsmoke.dm b/code/game/objects/effects/chem/chemsmoke.dm new file mode 100644 index 00000000..5c794284 --- /dev/null +++ b/code/game/objects/effects/chem/chemsmoke.dm @@ -0,0 +1,277 @@ +///////////////////////////////////////////// +// Chem smoke +///////////////////////////////////////////// +/obj/effect/effect/smoke/chem + icon = 'icons/effects/chemsmoke.dmi' + opacity = 0 + plane = EFFECTS_BELOW_LIGHTING_PLANE + layer = ABOVE_PROJECTILE_LAYER + time_to_live = 300 + pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GRILLE | PASS_FLAG_GLASS //PASS_FLAG_GLASS 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 + + ..() + + create_reagents(500) + + if(cached_icon) + icon = cached_icon + + set_dir(pick(GLOB.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?) + set_opacity(1) + + //float over to our destination, if we have one + destination = dest_turf + if(destination) + walk_to(src, destination) + +/obj/effect/effect/smoke/chem/Destroy() + walk(src, 0) // Because we might have called walk_to, we must stop the walk loop or BYOND keeps an internal reference to us forever. + set_opacity(0) + // TODO - fadeOut() sleeps. Sleeping in /Destroy is Bad, this needs to be fixed. + fadeOut() + return ..() + +/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 + var/range + var/list/targetTurfs + var/list/wallList + var/density + var/show_log = 1 + +/datum/effect/effect/system/smoke_spread/chem/spores + show_log = 0 + var/datum/seed/seed + +/datum/effect/effect/system/smoke_spread/chem/spores/New(seed_name) + if(seed_name && plant_controller) + seed = plant_controller.seeds[seed_name] + if(!seed) + qdel(src) + ..() + +/datum/effect/effect/system/smoke_spread/chem/New() + ..() + chemholder = new/obj() + chemholder.create_reagents(500) + +//Sets up the chem smoke effect +// Calculates the max range smoke can travel, then gets all turfs in that view range. +// Culls the selected turfs to a (roughly) circle shape, then calls smokeFlow() to make +// sure the smoke can actually path to the turfs. This culls any turfs it can't reach. +/datum/effect/effect/system/smoke_spread/chem/set_up(var/datum/reagents/carry = null, n = 10, c = 0, loca, direct) + range = n * 0.3 + cardinals = c + carry.trans_to_obj(chemholder, carry.total_volume, copy = 1) + + if(istype(loca, /turf/)) + location = loca + else + location = get_turf(loca) + if(!location) + return + + targetTurfs = new() + + //build affected area list + for(var/turf/T in view(range, location)) + //cull turfs to circle + if(sqrt((T.x - location.x)**2 + (T.y - location.y)**2) <= range) + targetTurfs += T + + wallList = new() + + smokeFlow() //pathing check + + //set the density of the cloud - for diluting reagents + density = max(1, targetTurfs.len / 4) //clamp the cloud density minimum to 1 so it cant multiply the reagents + + //Admin messaging + var/contained = carry.get_reagents() + var/area/A = get_area(location) + + var/where = "[A.name] | [location.x], [location.y]" + var/whereLink = "[where]" + + if(show_log) + if(carry.my_atom.fingerprintslast) + var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) + var/more = "" + if(M) + more = "(?)" + message_admins("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1) + log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].") + else + message_admins("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1) + log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.") + +//Runs the chem smoke effect +// Spawns damage over time loop for each reagent held in the cloud. +// Applies reagents to walls that affect walls (only thermite and plant-b-gone at the moment). +// Also calculates target locations to spawn the visual smoke effect on, so the whole area +// is covered fairly evenly. +/datum/effect/effect/system/smoke_spread/chem/start() + if(!location) + return + + if(chemholder.reagents.reagent_list.len) //reagent application - only run if there are extra reagents in the smoke + for(var/turf/T in wallList) + chemholder.reagents.touch_turf(T) + for(var/turf/T in targetTurfs) + chemholder.reagents.touch_turf(T) + for(var/atom/A in T.contents) + if(istype(A, /obj/effect/effect/smoke/chem) || istype(A, /mob)) + continue + else if(isobj(A) && !A.simulated) + chemholder.reagents.touch_obj(A) + + var/color = chemholder.reagents.get_color() //build smoke icon + var/icon/I + if(color) + I = icon('icons/effects/chemsmoke.dmi') + I += color + 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) + addtimer(CALLBACK(src, .proc/spawnSmoke,location, I, 1, 1), 0) + continue + + var/offset = 0 + var/points = round((radius * 2 * M_PI) / arcLength) + var/angle = round(ToDegrees(arcLength / radius), 1) + + if(!IsInteger(radius)) + offset = 45 //degrees + + for(var/j = 0, j < points, j++) + var/a = (angle * j) + offset + var/x = round(radius * cos(a) + location.x, 1) + var/y = round(radius * sin(a) + location.y, 1) + var/turf/T = locate(x,y,location.z) + if(!T) + continue + if(T in targetTurfs) + addtimer(CALLBACK(src, .proc/spawnSmoke,T, I, range), 0) + + +//------------------------------------------ +// 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) + + var/obj/effect/effect/smoke/chem/smoke + if(passed_smoke) + smoke = passed_smoke + else + smoke = new /obj/effect/effect/smoke/chem(location, smoke_duration + rand(0, 20), T, I) + + 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 + + //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/icon/I, var/smoke_duration, var/dist = 1) + var/obj/effect/effect/smoke/chem/spores = new /obj/effect/effect/smoke/chem(location) + spores.SetName("cloud of [seed.seed_name] [seed.seed_noun]") + ..(T, I, smoke_duration, dist, passed_smoke=spores) + + +/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. + + var/list/pending = new() + var/list/complete = new() + + pending += location + + while(pending.len) + for(var/turf/current in pending) + for(var/D in GLOB.cardinal) + var/turf/target = get_step(current, D) + if(wallList) + if(istype(target, /turf/simulated/wall)) + if(!(target in wallList)) + wallList += target + continue + + if(target in pending) + continue + if(target in complete) + continue + if(!(target in targetTurfs)) + continue + if(current.c_airblock(target)) //this is needed to stop chemsmoke from passing through thin window walls + continue + if(target.c_airblock(current)) + continue + pending += target + + pending -= current + complete += current + + targetTurfs = complete + + return diff --git a/code/game/objects/effects/chem/foam.dm b/code/game/objects/effects/chem/foam.dm new file mode 100644 index 00000000..281b9276 --- /dev/null +++ b/code/game/objects/effects/chem/foam.dm @@ -0,0 +1,183 @@ +// Foam +// Similar to smoke, but spreads out more +// metal foams leave behind a foamed metal wall + +/obj/effect/effect/foam + name = "foam" + icon_state = "foam" + opacity = 0 + anchored = 1 + density = 0 + layer = ABOVE_OBJ_LAYER + mouse_opacity = 0 + animate_movement = 0 + var/amount = 3 + var/expand = 1 + var/metal = 0 + +/obj/effect/effect/foam/New(var/loc, var/ismetal = 0) + ..(loc) + icon_state = "[ismetal? "m" : ""]foam" + metal = ismetal + playsound(src, 'sound/effects/bubbles2.ogg', 80, 1, -3) + spawn(3 + metal * 3) + Process() + checkReagents() + spawn(120) + STOP_PROCESSING(SSobj, src) + sleep(30) + if(metal) + var/obj/structure/foamedmetal/M = new(src.loc) + M.metal = metal + M.update_icon() + flick("[icon_state]-disolve", src) + sleep(5) + qdel(src) + return + +/obj/effect/effect/foam/proc/checkReagents() // transfer any reagents to the floor + if(!metal && reagents) + var/turf/T = get_turf(src) + reagents.touch_turf(T) + for(var/obj/O in T) + reagents.touch_obj(O) + +/obj/effect/effect/foam/Process() + if(--amount < 0) + return + + for(var/direction in GLOB.cardinal) + var/turf/T = get_step(src, direction) + if(!T) + continue + + if(!T.Enter(src)) + continue + + var/obj/effect/effect/foam/F = locate() in T + if(F) + continue + + F = new(T, metal) + F.amount = amount + if(!metal) + F.create_reagents(10) + if(reagents) + for(var/datum/reagent/R in reagents.reagent_list) + F.reagents.add_reagent(R.type, 1, safety = 1) //added safety check since reagents in the foam have already had a chance to react + +/obj/effect/effect/foam/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) // foam disolves when heated, except metal foams + if(!metal && prob(max(0, exposed_temperature - 475))) + flick("[icon_state]-disolve", src) + + spawn(5) + qdel(src) + +/obj/effect/effect/foam/Crossed(var/atom/movable/AM) + if(metal) + return + if(istype(AM, /mob/living)) + var/mob/living/M = AM + M.slip("the foam", 6) + +/datum/effect/effect/system/foam_spread + var/amount = 5 // the size of the foam spread. + var/list/carried_reagents // the IDs of reagents present when the foam was mixed + var/metal = 0 // 0 = foam, 1 = metalfoam, 2 = ironfoam + +/datum/effect/effect/system/foam_spread/set_up(amt=5, loca, var/datum/reagents/carry = null, var/metalfoam = 0) + amount = round(sqrt(amt / 3), 1) + if(istype(loca, /turf/)) + location = loca + else + location = get_turf(loca) + + carried_reagents = list() + metal = metalfoam + + // bit of a hack here. Foam carries along any reagent also present in the glass it is mixed with (defaults to water if none is present). Rather than actually transfer the reagents, this makes a list of the reagent ids and spawns 1 unit of that reagent when the foam disolves. + + if(carry && !metal) + for(var/datum/reagent/R in carry.reagent_list) + carried_reagents += R.type + +/datum/effect/effect/system/foam_spread/start() + spawn(0) + var/obj/effect/effect/foam/F = locate() in location + if(F) + F.amount += amount + return + + F = new /obj/effect/effect/foam(location, metal) + F.amount = amount + + if(!metal) // don't carry other chemicals if a metal foam + F.create_reagents(10) + + if(carried_reagents) + for(var/id in carried_reagents) + F.reagents.add_reagent(id, 1, safety = 1) //makes a safety call because all reagents should have already reacted anyway + else + F.reagents.add_reagent(/datum/reagent/water, 1, safety = 1) + +// wall formed by metal foams, dense and opaque, but easy to break + +/obj/structure/foamedmetal + icon = 'icons/effects/effects.dmi' + icon_state = "metalfoam" + density = 1 + opacity = 1 // changed in New() + anchored = 1 + name = "foamed metal" + desc = "A lightweight foamed metal wall." + var/metal = 1 // 1 = aluminum, 2 = iron + +/obj/structure/foamedmetal/New() + ..() + update_nearby_tiles(1) + +/obj/structure/foamedmetal/Destroy() + set_density(0) + update_nearby_tiles(1) + ..() + +/obj/structure/foamedmetal/update_icon() + if(metal == 1) + icon_state = "metalfoam" + else + icon_state = "ironfoam" + +/obj/structure/foamedmetal/ex_act(severity) + qdel(src) + +/obj/structure/foamedmetal/bullet_act() + if(metal == 1 || prob(50)) + qdel(src) + +/obj/structure/foamedmetal/attack_hand(var/mob/user) + if ((HULK in user.mutations) || (prob(75 - metal * 25))) + user.visible_message("[user] smashes through the foamed metal.", "You smash through the metal foam wall.") + qdel(src) + else + to_chat(user, "You hit the metal foam but bounce off it.") + return + +/obj/structure/foamedmetal/attackby(var/obj/item/I, var/mob/user) + if(istype(I, /obj/item/grab)) + var/obj/item/grab/G = I + G.affecting.loc = src.loc + visible_message("[G.assailant] smashes [G.affecting] through the foamed metal wall.") + qdel(I) + qdel(src) + return + + if(prob(I.force * 20 - metal * 25)) + user.visible_message("[user] smashes through the foamed metal.", "You smash through the foamed metal with \the [I].") + qdel(src) + else + to_chat(user, "You hit the metal foam to no effect.") + +/obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) + if(air_group) + return 0 + return !density \ No newline at end of file diff --git a/code/game/objects/effects/chem/water.dm b/code/game/objects/effects/chem/water.dm new file mode 100644 index 00000000..67b02a91 --- /dev/null +++ b/code/game/objects/effects/chem/water.dm @@ -0,0 +1,66 @@ +/obj/effect/effect/water + name = "water" + icon = 'icons/effects/effects.dmi' + icon_state = "extinguish" + mouse_opacity = 0 + pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GRILLE + +/obj/effect/effect/water/New(loc) + ..() + spawn(150) // In case whatever made it forgets to delete it + if(src) + qdel(src) + +/obj/effect/effect/water/proc/set_color() // Call it after you move reagents to it + icon += reagents.get_color() + +/obj/effect/effect/water/proc/set_up(var/turf/target, var/step_count = 5, var/delay = 5) + if(!target) + return + for(var/i = 1 to step_count) + if(!loc) + return + step_towards(src, target) + var/turf/T = get_turf(src) + if(T && reagents) + var/list/splash_mobs = list() + var/list/splash_others = list(T) + for(var/atom/A in T) + if(A.simulated) + if(!ismob(A)) + splash_others += A + else if(isliving(A)) + splash_mobs += A + + //each step splash 1/5 of the reagents on non-mobs + //could determine the # of steps until target, but that would be complicated + for(var/atom/A in splash_others) + reagents.splash(A, (reagents.total_volume/step_count)/splash_others.len) + for(var/mob/living/M in splash_mobs) + reagents.splash(M, reagents.total_volume/splash_mobs.len) + if(reagents.total_volume < 1) + break + if(T == get_turf(target)) + for(var/atom/A in splash_others) + reagents.splash(A, reagents.total_volume/splash_others.len) //splash anything left + break + + sleep(delay) + sleep(10) + qdel(src) + +/obj/effect/effect/water/Move(turf/newloc) + if(newloc.density) + return 0 + . = ..() + +/obj/effect/effect/water/Bump(atom/A) + if(reagents) + reagents.touch(A) + return ..() + +//Used by spraybottles. +/obj/effect/effect/water/chempuff + name = "chemicals" + icon = 'icons/obj/chempuff.dmi' + icon_state = "" diff --git a/code/game/objects/effects/decals/Cleanable/aliens.dm b/code/game/objects/effects/decals/Cleanable/aliens.dm new file mode 100644 index 00000000..e81d76f6 --- /dev/null +++ b/code/game/objects/effects/decals/Cleanable/aliens.dm @@ -0,0 +1,33 @@ +/obj/effect/decal/cleanable/blood/xeno + name = "xeno blood" + desc = "It's green and acidic. It looks like... blood?" + icon = 'icons/effects/blood.dmi' + basecolor = "#05ee05" + +/obj/effect/decal/cleanable/blood/gibs/xeno + name = "xeno gibs" + desc = "Gnarly..." + icon_state = "xgib1" + random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6") + basecolor = "#05ee05" + +/obj/effect/decal/cleanable/blood/gibs/xeno/update_icon() + color = "#ffffff" + +/obj/effect/decal/cleanable/blood/gibs/xeno/up + random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6","xgibup1","xgibup1","xgibup1") + +/obj/effect/decal/cleanable/blood/gibs/xeno/down + random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6","xgibdown1","xgibdown1","xgibdown1") + +/obj/effect/decal/cleanable/blood/gibs/xeno/body + random_icon_states = list("xgibhead", "xgibtorso") + +/obj/effect/decal/cleanable/blood/gibs/xeno/limb + random_icon_states = list("xgibleg", "xgibarm") + +/obj/effect/decal/cleanable/blood/gibs/xeno/core + random_icon_states = list("xgibmid1", "xgibmid2", "xgibmid3") + +/obj/effect/decal/cleanable/blood/xtracks + basecolor = "#05ee05" \ No newline at end of file diff --git a/code/game/objects/effects/decals/Cleanable/fuel.dm b/code/game/objects/effects/decals/Cleanable/fuel.dm new file mode 100644 index 00000000..a5df6b3f --- /dev/null +++ b/code/game/objects/effects/decals/Cleanable/fuel.dm @@ -0,0 +1,71 @@ +/obj/effect/decal/cleanable/liquid_fuel + //Liquid fuel is used for things that used to rely on volatile fuels or phoron being contained to a couple tiles. + icon = 'icons/effects/effects.dmi' + icon_state = "fuel" + plane = ABOVE_TURF_PLANE + layer = BLOOD_LAYER + anchored = 1 + var/amount = 1 + +/obj/effect/decal/cleanable/liquid_fuel/proc/Spread(exclude=list()) + //Allows liquid fuels to sometimes flow into other tiles. + if(amount < 15) return //lets suppose welder fuel is fairly thick and sticky. For something like water, 5 or less would be more appropriate. + var/turf/simulated/S = loc + if(!istype(S)) return + for(var/d in GLOB.cardinal) + var/turf/simulated/target = get_step(src,d) + var/turf/simulated/origin = get_turf(src) + if(origin.CanPass(null, target, 0, 0) && target.CanPass(null, origin, 0, 0)) + var/obj/effect/decal/cleanable/liquid_fuel/other_fuel = locate() in target + if(other_fuel) + other_fuel.amount += amount*0.25 + if(!(other_fuel in exclude)) + exclude += src + other_fuel.Spread(exclude) + else + new/obj/effect/decal/cleanable/liquid_fuel(target, amount*0.25,1) + amount *= 0.75 + + +/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel + icon_state = "mustard" + anchored = 0 + +/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel/Initialize(mapload, amt=1, d=0) + set_dir(d) //Setting this direction means you won't get torched by your own flamethrower. + . = ..() + +/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel/Spread() + //The spread for flamethrower fuel is much more precise, to create a wide fire pattern. + if(amount < 0.1) return + var/turf/simulated/S = loc + if(!istype(S)) return + + for(var/d in list(turn(dir,90),turn(dir,-90), dir)) + var/turf/simulated/O = get_step(S,d) + if(locate(/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel) in O) + continue + if(O.CanPass(null, S, 0, 0) && S.CanPass(null, O, 0, 0)) + new/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel(O,amount*0.25,d) + O.hotspot_expose((T20C*2) + 380,500) //Light flamethrower fuel on fire immediately. + + amount *= 0.25 + +/obj/effect/decal/cleanable/liquid_fuel/Initialize(mapload, amt=1, nologs=FALSE) + if(!nologs && !mapload) + log_and_message_admins(" - Liquid fuel has been spilled") + src.amount = amt + var/has_spread = 0 + //Be absorbed by any other liquid fuel in the tile. + for(var/obj/effect/decal/cleanable/liquid_fuel/other in loc) + if(other != src) + other.amount += src.amount + other.Spread() + has_spread = 1 + break + + . = ..() + if(!has_spread) + Spread() + else + return INITIALIZE_HINT_QDEL diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm new file mode 100644 index 00000000..dd04e957 --- /dev/null +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -0,0 +1,260 @@ +#define DRYING_TIME 5 * 60*10 //for 1 unit of depth in puddle (amount var) + +var/global/list/image/splatter_cache=list() + +/obj/effect/decal/cleanable/blood + name = "blood" + var/dryname = "dried blood" + desc = "It's thick and gooey. Perhaps it's the chef's cooking?" + var/drydesc = "It's dry and crusty. Someone is not doing their job." + gender = PLURAL + density = 0 + anchored = 1 + icon = 'icons/effects/blood.dmi' + icon_state = "mfloor1" + random_icon_states = list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7") + var/base_icon = 'icons/effects/blood.dmi' + var/list/viruses = list() + blood_DNA = list() + var/basecolor=COLOR_BLOOD_HUMAN // Color when wet. + var/list/datum/disease2/disease/virus2 = list() + var/amount = 5 + var/drytime + appearance_flags = NO_CLIENT_COLOR + +/obj/effect/decal/cleanable/blood/reveal_blood() + if(!fluorescent) + fluorescent = 1 + basecolor = COLOR_LUMINOL + update_icon() + +/obj/effect/decal/cleanable/blood/clean_blood() + fluorescent = 0 + if(invisibility != 100) + set_invisibility(100) + amount = 0 + STOP_PROCESSING(SSobj, src) + ..(ignore=1) + +/obj/effect/decal/cleanable/blood/hide() + return + +/obj/effect/decal/cleanable/blood/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/effect/decal/cleanable/blood/Initialize() + . = ..() + update_icon() + if(istype(src, /obj/effect/decal/cleanable/blood/gibs)) + return + if(src.type == /obj/effect/decal/cleanable/blood) + if(isturf(src.loc)) + for(var/obj/effect/decal/cleanable/blood/B in src.loc) + if(B != src) + if (B.blood_DNA) + blood_DNA |= B.blood_DNA.Copy() + qdel(B) + drytime = world.time + DRYING_TIME * (amount+1) + START_PROCESSING(SSobj, src) + +/obj/effect/decal/cleanable/blood/Process() + if(world.time > drytime) + dry() + +/obj/effect/decal/cleanable/blood/update_icon() + if(basecolor == "rainbow") basecolor = get_random_colour(1) + color = basecolor + if(basecolor == SYNTH_BLOOD_COLOUR) + SetName("oil") + desc = "It's black and greasy." + else + SetName(initial(name)) + desc = initial(desc) + +/obj/effect/decal/cleanable/blood/Crossed(mob/living/carbon/human/perp) + if (!istype(perp)) + return + if(amount < 1) + return + + var/obj/item/organ/external/l_foot = perp.get_organ(BP_L_FOOT) + var/obj/item/organ/external/r_foot = perp.get_organ(BP_R_FOOT) + var/hasfeet = 1 + if((!l_foot || l_foot.is_stump()) && (!r_foot || r_foot.is_stump())) + hasfeet = 0 + if(perp.shoes && !perp.buckled)//Adding blood to shoes + var/obj/item/clothing/shoes/S = perp.shoes + if(istype(S)) + S.blood_color = basecolor + S.track_blood = max(amount,S.track_blood) + if(!S.blood_overlay) + S.generate_blood_overlay() + if(!S.blood_DNA) + S.blood_DNA = list() + S.blood_overlay.color = basecolor + S.overlays += S.blood_overlay + if(S.blood_overlay && S.blood_overlay.color != basecolor) + S.blood_overlay.color = basecolor + S.overlays.Cut() + S.overlays += S.blood_overlay + S.blood_DNA |= blood_DNA.Copy() + + else if (hasfeet)//Or feet + perp.feet_blood_color = basecolor + perp.track_blood = max(amount,perp.track_blood) + if(!perp.feet_blood_DNA) + perp.feet_blood_DNA = list() + perp.feet_blood_DNA |= blood_DNA.Copy() + else if (perp.buckled && istype(perp.buckled, /obj/structure/bed/chair/wheelchair)) + var/obj/structure/bed/chair/wheelchair/W = perp.buckled + W.bloodiness = 4 + + perp.update_inv_shoes(1) + amount-- + +/obj/effect/decal/cleanable/blood/proc/dry() + name = dryname + desc = drydesc + color = adjust_brightness(color, -50) + amount = 0 + STOP_PROCESSING(SSobj, src) + +/obj/effect/decal/cleanable/blood/attack_hand(mob/living/carbon/human/user) + ..() + if (amount && istype(user)) + if (user.gloves) + return + var/taken = rand(1,amount) + amount -= taken + to_chat(user, "You get some of \the [src] on your hands.") + if (!user.blood_DNA) + user.blood_DNA = list() + user.blood_DNA |= blood_DNA.Copy() + user.bloody_hands = taken + user.hand_blood_color = basecolor + user.update_inv_gloves(1) + user.verbs += /mob/living/carbon/human/proc/bloody_doodle + +/obj/effect/decal/cleanable/blood/splatter + random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5") + amount = 2 + +/obj/effect/decal/cleanable/blood/drip + name = "drips of blood" + desc = "It's red." + gender = PLURAL + icon = 'icons/effects/drip.dmi' + icon_state = "1" + random_icon_states = list("1","2","3","4","5") + amount = 0 + var/list/drips + +/obj/effect/decal/cleanable/blood/drip/Initialize() + . = ..() + drips = list(icon_state) + +/obj/effect/decal/cleanable/blood/writing + icon_state = "tracks" + desc = "It looks like a writing in blood." + gender = NEUTER + random_icon_states = list("writing1","writing2","writing3","writing4","writing5") + amount = 0 + var/message + +/obj/effect/decal/cleanable/blood/writing/New() + ..() + if(LAZYLEN(random_icon_states)) + for(var/obj/effect/decal/cleanable/blood/writing/W in loc) + random_icon_states.Remove(W.icon_state) + icon_state = pick(random_icon_states) + else + icon_state = "writing1" + +/obj/effect/decal/cleanable/blood/writing/examine(mob/user) + . = ..(user) + to_chat(user, "It reads: \"[message]\"") + +/obj/effect/decal/cleanable/blood/gibs + name = "gibs" + desc = "They look bloody and gruesome." + gender = PLURAL + density = 0 + anchored = 1 + icon = 'icons/effects/blood.dmi' + icon_state = "gibbl5" + random_icon_states = list("gib1", "gib2", "gib3", "gib5", "gib6") + var/fleshcolor = "#ffffff" + +/obj/effect/decal/cleanable/blood/gibs/update_icon() + + var/image/giblets = new(base_icon, "[icon_state]_flesh", dir) + if(!fleshcolor || fleshcolor == "rainbow") + fleshcolor = get_random_colour(1) + giblets.color = fleshcolor + + var/icon/blood = new(base_icon,"[icon_state]",dir) + if(basecolor == "rainbow") basecolor = get_random_colour(1) + blood.Blend(basecolor,ICON_MULTIPLY) + + icon = blood + overlays.Cut() + overlays += giblets + +/obj/effect/decal/cleanable/blood/gibs/up + random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1") + +/obj/effect/decal/cleanable/blood/gibs/down + random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibdown1","gibdown1","gibdown1") + +/obj/effect/decal/cleanable/blood/gibs/body + random_icon_states = list("gibhead", "gibtorso") + +/obj/effect/decal/cleanable/blood/gibs/limb + random_icon_states = list("gibleg", "gibarm") + +/obj/effect/decal/cleanable/blood/gibs/core + random_icon_states = list("gibmid1", "gibmid2", "gibmid3") + + +/obj/effect/decal/cleanable/blood/gibs/proc/streak(var/list/directions) + spawn (0) + var/direction = pick(directions) + for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++) + sleep(3) + if (i > 0) + var/obj/effect/decal/cleanable/blood/b = new /obj/effect/decal/cleanable/blood/splatter(loc) + b.basecolor = src.basecolor + b.update_icon() + if (step_to(src, get_step(src, direction), 0)) + break + +/obj/effect/decal/cleanable/mucus + name = "mucus" + desc = "Disgusting mucus." + gender = PLURAL + density = 0 + anchored = 1 + icon = 'icons/effects/blood.dmi' + icon_state = "mucus" + + var/list/datum/disease2/disease/virus2 = list() + var/dry=0 // Keeps the lag down + +/obj/effect/decal/cleanable/mucus/New() + ..() + spawn(DRYING_TIME * 2) + dry=1 + +/obj/effect/decal/cleanable/trail_holder //not a child of blood on purpose + name = "blood" + icon_state = "blank" + desc = "Your instincts say you shouldn't be following these." + gender = PLURAL + density = 0 + anchored = 1 + layer = 2 + random_icon_states = null + var/list/existing_dirs = list() + blood_DNA = list() + appearance_flags = NO_CLIENT_COLOR \ No newline at end of file diff --git a/code/game/objects/effects/decals/Cleanable/misc.dm b/code/game/objects/effects/decals/Cleanable/misc.dm new file mode 100644 index 00000000..49527deb --- /dev/null +++ b/code/game/objects/effects/decals/Cleanable/misc.dm @@ -0,0 +1,132 @@ +/obj/effect/decal/cleanable/generic + name = "clutter" + desc = "Someone should clean that up." + gender = PLURAL + density = 0 + anchored = 1 + icon = 'icons/obj/objects.dmi' + icon_state = "shards" + +/obj/effect/decal/cleanable/ash + name = "ashes" + desc = "Ashes to ashes, dust to dust, and into space." + gender = PLURAL + icon = 'icons/obj/objects.dmi' + icon_state = "ash" + anchored = 1 + +/obj/effect/decal/cleanable/ash/attack_hand(mob/user as mob) + to_chat(user, "[src] sifts through your fingers.") + var/turf/simulated/floor/F = get_turf(src) + if (istype(F)) + F.dirt += 4 + qdel(src) + +/obj/effect/decal/cleanable/greenglow + + New() + ..() + spawn(1200)// 2 minutes + qdel(src) + +/obj/effect/decal/cleanable/dirt + name = "dirt" + desc = "Someone should clean that up." + gender = PLURAL + density = 0 + anchored = 1 + icon = 'icons/effects/effects.dmi' + icon_state = "dirt" + mouse_opacity = 0 + +/obj/effect/decal/cleanable/flour + name = "flour" + desc = "It's still good. Four second rule!" + gender = PLURAL + density = 0 + anchored = 1 + icon = 'icons/effects/effects.dmi' + icon_state = "flour" + +/obj/effect/decal/cleanable/greenglow + name = "glowing goo" + desc = "Jeez. I hope that's not for lunch." + gender = PLURAL + density = 0 + anchored = 1 + light_range = 1 + icon = 'icons/effects/effects.dmi' + icon_state = "greenglow" + +/obj/effect/decal/cleanable/cobweb + name = "cobweb" + desc = "Somebody should remove that." + density = 0 + anchored = 1 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + icon = 'icons/effects/effects.dmi' + icon_state = "cobweb1" + +/obj/effect/decal/cleanable/molten_item + name = "gooey grey mass" + desc = "It looks like a melted... something." + density = 0 + anchored = 1 + icon = 'icons/obj/chemical.dmi' + icon_state = "molten" + +/obj/effect/decal/cleanable/cobweb2 + name = "cobweb" + desc = "Somebody should remove that." + density = 0 + anchored = 1 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + icon = 'icons/effects/effects.dmi' + icon_state = "cobweb2" + +//Vomit (sorry) +/obj/effect/decal/cleanable/vomit + name = "vomit" + desc = "Gosh, how unpleasant." + gender = PLURAL + density = 0 + anchored = 1 + icon = 'icons/effects/blood.dmi' + icon_state = "vomit_1" + random_icon_states = list("vomit_1", "vomit_2", "vomit_3", "vomit_4") + var/list/viruses = list() + +/obj/effect/decal/cleanable/tomato_smudge + name = "tomato smudge" + desc = "It's red." + density = 0 + anchored = 1 + icon = 'icons/effects/tomatodecal.dmi' + random_icon_states = list("tomato_floor1", "tomato_floor2", "tomato_floor3") + +/obj/effect/decal/cleanable/egg_smudge + name = "smashed egg" + desc = "Seems like this one won't hatch." + density = 0 + anchored = 1 + icon = 'icons/effects/tomatodecal.dmi' + random_icon_states = list("smashed_egg1", "smashed_egg2", "smashed_egg3") + +/obj/effect/decal/cleanable/pie_smudge //honk + name = "smashed pie" + desc = "It's pie cream from a cream pie." + density = 0 + anchored = 1 + icon = 'icons/effects/tomatodecal.dmi' + random_icon_states = list("smashed_pie") + +/obj/effect/decal/cleanable/fruit_smudge + name = "smudge" + desc = "Some kind of fruit smear." + density = 0 + anchored = 1 + icon = 'icons/effects/blood.dmi' + icon_state = "mfloor1" + random_icon_states = list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7") diff --git a/code/game/objects/effects/decals/Cleanable/robots.dm b/code/game/objects/effects/decals/Cleanable/robots.dm new file mode 100644 index 00000000..d2eb484f --- /dev/null +++ b/code/game/objects/effects/decals/Cleanable/robots.dm @@ -0,0 +1,48 @@ +/obj/effect/decal/cleanable/blood/gibs/robot + name = "robot debris" + desc = "It's a useless heap of junk... or is it?" + icon = 'icons/mob/robots.dmi' + icon_state = "gib1" + basecolor = SYNTH_BLOOD_COLOUR + random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7") + +/obj/effect/decal/cleanable/blood/gibs/robot/update_icon() + color = "#ffffff" + +/obj/effect/decal/cleanable/blood/gibs/robot/dry() //pieces of robots do not dry up like + return + +/obj/effect/decal/cleanable/blood/gibs/robot/streak(var/list/directions) + spawn (0) + var/direction = pick(directions) + for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++) + sleep(3) + if (i > 0) + if (prob(40)) + var/obj/effect/decal/cleanable/blood/oil/streak = new(src.loc) + streak.update_icon() + else if (prob(10)) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + if (step_to(src, get_step(src, direction), 0)) + break + +/obj/effect/decal/cleanable/blood/gibs/robot/limb + random_icon_states = list("gibarm", "gibleg") + +/obj/effect/decal/cleanable/blood/gibs/robot/up + random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7","gibup1","gibup1") //2:7 is close enough to 1:4 + +/obj/effect/decal/cleanable/blood/gibs/robot/down + random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7","gibdown1","gibdown1") //2:7 is close enough to 1:4 + +/obj/effect/decal/cleanable/blood/oil + basecolor = SYNTH_BLOOD_COLOUR + +/obj/effect/decal/cleanable/blood/oil/dry() + return + +/obj/effect/decal/cleanable/blood/oil/streak + random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5") + amount = 2 \ No newline at end of file diff --git a/code/game/objects/effects/decals/Cleanable/tracks.dm b/code/game/objects/effects/decals/Cleanable/tracks.dm new file mode 100644 index 00000000..bb34d77b --- /dev/null +++ b/code/game/objects/effects/decals/Cleanable/tracks.dm @@ -0,0 +1,202 @@ +// Stolen en masse from N3X15 of /vg/station with much gratitude. + +// The idea is to have 4 bits for coming and 4 for going. +#define TRACKS_COMING_NORTH 1 +#define TRACKS_COMING_SOUTH 2 +#define TRACKS_COMING_EAST 4 +#define TRACKS_COMING_WEST 8 +#define TRACKS_GOING_NORTH 16 +#define TRACKS_GOING_SOUTH 32 +#define TRACKS_GOING_EAST 64 +#define TRACKS_GOING_WEST 128 + +// 5 seconds +#define TRACKS_CRUSTIFY_TIME 50 + +// color-dir-dry +var/global/list/image/fluidtrack_cache=list() + +/datum/fluidtrack + var/direction=0 + var/basecolor=COLOR_BLOOD_HUMAN + var/wet=0 + var/fresh=1 + var/crusty=0 + var/image/overlay + + New(_direction,_color,_wet) + src.direction=_direction + src.basecolor=_color + src.wet=_wet + +/obj/effect/decal/cleanable/blood/tracks/reveal_blood() + if(!fluorescent) + if(stack && stack.len) + for(var/datum/fluidtrack/track in stack) + track.basecolor = COLOR_LUMINOL + ..() + +// Footprints, tire trails... +/obj/effect/decal/cleanable/blood/tracks + amount = 0 + random_icon_states = null + var/dirs=0 + icon = 'icons/effects/fluidtracks.dmi' + icon_state = "" + var/coming_state="blood1" + var/going_state="blood2" + var/updatedtracks=0 + + // dir = id in stack + var/list/setdirs=list( + "1"=0, + "2"=0, + "4"=0, + "8"=0, + "16"=0, + "32"=0, + "64"=0, + "128"=0 + ) + + // List of laid tracks and their colors. + var/list/datum/fluidtrack/stack=list() + + /** + * Add tracks to an existing trail. + * + * @param DNA bloodDNA to add to collection. + * @param comingdir Direction tracks come from, or 0. + * @param goingdir Direction tracks are going to (or 0). + * @param bloodcolor Color of the blood when wet. + */ + proc/AddTracks(var/list/DNA, var/comingdir, var/goingdir, var/bloodcolor=COLOR_BLOOD_HUMAN) + var/updated=0 + // Shift our goingdir 4 spaces to the left so it's in the GOING bitblock. + var/realgoing=goingdir<<4 + + // Current bit + var/b=0 + + // When tracks will start to dry out + var/t=world.time + TRACKS_CRUSTIFY_TIME + + var/datum/fluidtrack/track + + // Process 4 bits + for(var/bi=0;bi<4;bi++) + b=1<>4 + + if(track.overlay) + track.overlay=null + var/image/I = image(icon, icon_state=state, dir=num2dir(truedir)) + I.color = track.basecolor + + track.fresh=0 + track.overlay=I + stack[stack_idx]=track + overlays += I + updatedtracks=0 // Clear our memory of updated tracks. + +/obj/effect/decal/cleanable/blood/tracks/footprints + name = "wet footprints" + dryname = "dried footprints" + desc = "They look like still wet tracks left by footwear." + drydesc = "They look like dried tracks left by footwear." + coming_state = "human1" + going_state = "human2" + amount = 0 + +/obj/effect/decal/cleanable/blood/tracks/snake + name = "wet tracks" + dryname = "dried tracks" + desc = "They look like still wet tracks left by a giant snake." + drydesc = "They look like dried tracks left by a giant snake." + coming_state = "snake1" + going_state = "snake2" + random_icon_states = null + amount = 0 + +/obj/effect/decal/cleanable/blood/tracks/paw + name = "wet tracks" + dryname = "dried tracks" + desc = "They look like still wet tracks left by a mammal." + drydesc = "They look like dried tracks left by a mammal." + coming_state = "paw1" + going_state = "paw2" + random_icon_states = null + amount = 0 + +/obj/effect/decal/cleanable/blood/tracks/claw + name = "wet tracks" + dryname = "dried tracks" + desc = "They look like still wet tracks left by a reptile." + drydesc = "They look like dried tracks left by a reptile." + coming_state = "claw1" + going_state = "claw2" + random_icon_states = null + amount = 0 + +/obj/effect/decal/cleanable/blood/tracks/wheels + name = "wet tracks" + dryname = "dried tracks" + desc = "They look like still wet tracks left by wheels." + drydesc = "They look like dried tracks left by wheels." + coming_state = "wheels" + going_state = "" + gender = PLURAL + random_icon_states = null + amount = 0 \ No newline at end of file diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm new file mode 100644 index 00000000..3b815660 --- /dev/null +++ b/code/game/objects/effects/decals/cleanable.dm @@ -0,0 +1,13 @@ +/obj/effect/decal/cleanable + var/list/random_icon_states + +/obj/effect/decal/cleanable/clean_blood(var/ignore = 0) + if(!ignore) + qdel(src) + return + ..() + +/obj/effect/decal/cleanable/Initialize() + if (random_icon_states && length(src.random_icon_states) > 0) + src.icon_state = pick(src.random_icon_states) + . = ..() diff --git a/code/game/objects/effects/decals/contraband.dm b/code/game/objects/effects/decals/contraband.dm new file mode 100644 index 00000000..51013897 --- /dev/null +++ b/code/game/objects/effects/decals/contraband.dm @@ -0,0 +1,193 @@ + +//########################## CONTRABAND ;3333333333333333333 -Agouri ################################################### + +/obj/item/weapon/contraband + name = "contraband item" + desc = "You probably shouldn't be holding this." + icon = 'icons/obj/contraband.dmi' + force = 0 + + +/obj/item/weapon/contraband/poster + name = "rolled-up poster" + desc = "The poster comes with its own automatic adhesive mechanism, for easy pinning to any vertical surface." + icon_state = "rolled_poster" + var/serial_number = 0 + + +/obj/item/weapon/contraband/poster/New(turf/loc, var/given_serial = 0) + if(given_serial == 0) + serial_number = rand(1, poster_designs.len) + else + serial_number = given_serial + name += " - No. [serial_number]" + ..(loc) + +//Places the poster on a wall +/obj/item/weapon/contraband/poster/afterattack(var/atom/A, var/mob/user, var/adjacent, var/clickparams) + if (!adjacent) + return + + //must place on a wall and user must not be inside a closet/mecha/whatever + var/turf/W = A + if (!iswall(W) || !isturf(user.loc)) + to_chat(user, "You can't place this here!") + return + + var/placement_dir = get_dir(user, W) + if (!(placement_dir in GLOB.cardinal)) + to_chat(user, "You must stand directly in front of the wall you wish to place that on.") + return + + //just check if there is a poster on or adjacent to the wall + var/stuff_on_wall = 0 + if (locate(/obj/structure/sign/poster) in W) + stuff_on_wall = 1 + + //crude, but will cover most cases. We could do stuff like check pixel_x/y but it's not really worth it. + for (var/dir in GLOB.cardinal) + var/turf/T = get_step(W, dir) + if (locate(/obj/structure/sign/poster) in T) + stuff_on_wall = 1 + break + + if (stuff_on_wall) + to_chat(user, "There is already a poster there!") + return + + to_chat(user, "You start placing the poster on the wall...")//Looks like it's uncluttered enough. Place the poster. + + + var/obj/structure/sign/poster/P = new(user.loc, placement_dir=get_dir(user, W), serial=serial_number) + + flick("poster_being_set", P) + //playsound(W, 'sound/items/poster_being_created.ogg', 100, 1) //why the hell does placing a poster make printer sounds? + + var/oldsrc = src //get a reference to src so we can delete it after detaching ourselves + src = null + spawn(17) + if(!P) return + + if(iswall(W) && user && P.loc == user.loc) //Let's check if everything is still there + to_chat(user, "You place the poster!") + else + P.roll_and_drop(P.loc) + + qdel(oldsrc) //delete it now to cut down on sanity checks afterwards. Agouri's code supports rerolling it anyway + +//############################## THE ACTUAL DECALS ########################### + +/obj/structure/sign/poster + name = "poster" + desc = "A large piece of space-resistant printed paper." + icon = 'icons/obj/contraband.dmi' + anchored = 1 + var/serial_number //Will hold the value of src.loc if nobody initialises it + var/poster_type //So mappers can specify a desired poster + var/ruined = 0 + +/obj/structure/sign/poster/New(var/newloc, var/placement_dir=null, var/serial=null) + ..(newloc) + + if(!serial) + serial = rand(1, poster_designs.len) //use a random serial if none is given + + serial_number = serial + var/datum/poster/design = poster_designs[serial_number] + set_poster(design) + + switch (placement_dir) + if (NORTH) + pixel_x = 0 + pixel_y = 32 + if (SOUTH) + pixel_x = 0 + pixel_y = -32 + if (EAST) + pixel_x = 32 + pixel_y = 0 + if (WEST) + pixel_x = -32 + pixel_y = 0 + +/obj/structure/sign/poster/Initialize() + if (poster_type) + var/path = ispath(poster_type) ? poster_type : text2path(poster_type) + var/datum/poster/design = new path + set_poster(design) + . = ..() + +/obj/structure/sign/poster/proc/set_poster(var/datum/poster/design) + SetName("[initial(name)] - [design.name]") + desc = "[initial(desc)] [design.desc]" + icon_state = design.icon_state // poster[serial_number] + +/obj/structure/sign/poster/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWirecutter(W)) + playsound(loc, 'sound/items/Wirecutter.ogg', 100, 1) + if(ruined) + to_chat(user, "You remove the remnants of the poster.") + qdel(src) + else + to_chat(user, "You carefully remove the poster from the wall.") + roll_and_drop(user.loc) + return + + +/obj/structure/sign/poster/attack_hand(mob/user as mob) + + if(ruined) + return + + if(alert("Do I want to rip the poster from the wall?","You think...","Yes","No") == "Yes") + + if(ruined || !user.Adjacent(src)) + return + + visible_message("\The [user] rips \the [src] in a single, decisive motion!" ) + playsound(src.loc, 'sound/items/poster_ripped.ogg', 100, 1) + ruined = 1 + icon_state = "poster_ripped" + SetName("ripped poster") + desc = "You can't make out anything from the poster's original print. It's ruined." + add_fingerprint(user) + +/obj/structure/sign/poster/proc/roll_and_drop(turf/newloc) + var/obj/item/weapon/contraband/poster/P = new(src, serial_number) + P.loc = newloc + src.loc = P + qdel(src) + +/datum/poster + // Name suffix. Poster - [name] + var/name="" + // Description suffix + var/desc="" + var/icon_state="" + + + +/obj/structure/poster + anchored = TRUE + icon = 'icons/obj/contraband.dmi' + icon_state = "red1" + desc = "Just a silly little poster. Doesn't look like it'll be coming off any time soon." + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + +/obj/structure/poster/red + name = "Red Propganda" + icon_state = "red1" + +/obj/structure/poster/red/New() + ..() + icon_state = pick("red1", "red2", "red3") + + +/obj/structure/poster/blue + name = "Blue Propganda" + icon_state = "blue1" + +/obj/structure/poster/blue/New() + ..() + icon_state = pick("blue1", "blue2", "blue3") \ No newline at end of file diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm new file mode 100644 index 00000000..5de73a37 --- /dev/null +++ b/code/game/objects/effects/decals/crayon.dm @@ -0,0 +1,29 @@ +/obj/effect/decal/cleanable/crayon + name = "rune" + desc = "A rune drawn in crayon." + icon = 'icons/obj/rune.dmi' + anchored = 1 + + New(location,main = "#ffffff",shade = "#000000",var/type = "rune") + ..() + loc = location + + name = type + desc = "A [type] drawn in crayon." + + switch(type) + if("rune") + type = "rune[rand(1,6)]" + if("graffiti") + type = pick("amyjon","face","matt","revolution","engie","guy","end","dwarf","uboa") + + var/icon/mainOverlay = new/icon('icons/effects/crayondecal.dmi',"[type]",2.1) + var/icon/shadeOverlay = new/icon('icons/effects/crayondecal.dmi',"[type]s",2.1) + + mainOverlay.Blend(main,ICON_ADD) + shadeOverlay.Blend(shade,ICON_ADD) + + overlays += mainOverlay + overlays += shadeOverlay + + add_hiddenprint(usr) \ No newline at end of file diff --git a/code/game/objects/effects/decals/decal.dm b/code/game/objects/effects/decals/decal.dm new file mode 100644 index 00000000..66786d06 --- /dev/null +++ b/code/game/objects/effects/decals/decal.dm @@ -0,0 +1,6 @@ +/obj/effect/decal + plane = ABOVE_TURF_PLANE + layer = DECAL_LAYER + +/obj/effect/decal/fall_damage() + return 0 diff --git a/code/game/objects/effects/decals/misc.dm b/code/game/objects/effects/decals/misc.dm new file mode 100644 index 00000000..012b910b --- /dev/null +++ b/code/game/objects/effects/decals/misc.dm @@ -0,0 +1,16 @@ +/obj/effect/decal/point + name = "arrow" + desc = "It's an arrow hanging in mid-air. There may be a wizard about." + icon = 'icons/mob/screen1.dmi' + icon_state = "arrow" + plane = EFFECTS_BELOW_LIGHTING_PLANE + layer = POINTER_LAYER + anchored = 1 + mouse_opacity = 0 + +// Used for spray that you spray at walls, tables, hydrovats etc +/obj/effect/decal/spraystill + density = 0 + anchored = 1 + plane = EFFECTS_BELOW_LIGHTING_PLANE + layer = PROJECTILE_LAYER diff --git a/code/game/objects/effects/decals/posters/bs12.dm b/code/game/objects/effects/decals/posters/bs12.dm new file mode 100644 index 00000000..f36fe53d --- /dev/null +++ b/code/game/objects/effects/decals/posters/bs12.dm @@ -0,0 +1,295 @@ +// bs12 posters +/datum/poster/bay_1 + icon_state="bsposter1" + name = "Unlucky Space Explorer" + desc = "This particular one depicts a skeletal form within a space suit." + +/datum/poster/bay_2 + icon_state="bsposter2" + name = "Positronic Logic Conflicts" + desc = "This particular one depicts the cold, unmoving stare of a particular advanced AI." + +/datum/poster/bay_3 + icon_state="bsposter3" + name = "Paranoia" + desc = "This particular one warns of the dangers of trusting your co-workers too much." + +/datum/poster/bay_4 + icon_state="bsposter4" + name = "Keep Calm" + desc = "This particular one is of a famous New Earth design, although a bit modified. Someone has scribbled an O over the A on the poster." + +/datum/poster/bay_5 + icon_state="bsposter5" + name = "Martian Warlord" + desc = "This particular one depicts the cartoony mug of a certain Martial Warmonger." + +/datum/poster/bay_6 + icon_state="bsposter6" + name = "Technological Singularity" + desc = "This particular one is of the blood-curdling symbol of a long-since defeated enemy of humanity." + +/datum/poster/bay_7 + icon_state="bsposter7" + name = "Wasteland" + desc = "This particular one is of a couple of ragged gunmen, one male and one female, on top of a mound of rubble. The number \"12\" is visible on their blue jumpsuits." + +/datum/poster/bay_8 + icon_state="bsposter8" + name = "Pinup Girl Cindy" + desc = "This particular one is of a historical corporate PR girl, Cindy, in a particularly feminine pose." + +/datum/poster/bay_9 + icon_state="bsposter9" + name = "Pinup Girl Amy" + desc = "This particular one is of Amy, the nymphomaniac urban legend of deep space. How this photograph came to be is not known." + +/datum/poster/bay_10 + icon_state="bsposter10" + name = "Don't Panic" + desc = "This particular one depicts some sort of star in a grimace. The \"Don't Panic\" is written in big, friendly letters." + +/datum/poster/bay_11 + icon_state="bsposter11" + name = "Underwater Laboratory" + desc = "This particular one is of the fabled last crew of a previous Company project." + +/datum/poster/bay_12 + icon_state="bsposter12" + name = "Rogue AI" + desc = "This particular one depicts the shell of the infamous AI that catastropically comandeered one of humanity's earliest space stations. Back then, the Company was just known as TriOptimum." + +/datum/poster/bay_13 + icon_state="bsposter13" + name = "User of the Arcane Arts" + desc = "This particular one depicts a wizard, casting a spell. You can't really make out if it's an actual photograph or a computer-generated image." + +/datum/poster/bay_14 + icon_state="bsposter14" + name = "Levitating Skull" + desc = "This particular one is the portrait of a flying enchanted skull. Its adventures along with its fabled companion are now fading through history..." + +/datum/poster/bay_15 + icon_state="bsposter15" + name = "Augmented Legend" + desc = "This particular one is of an obviously augmented individual, gazing towards the sky. The cyber-city in the backround is rather punkish." + +/datum/poster/bay_16 + icon_state="bsposter16" + name = "Dangerous Static" + desc = "This particular one depicts nothing remarkable other than a rather mesmerising pattern of monitor static. There's a tag on the sides of the poster, but it's ripped off." + +/datum/poster/bay_17 + icon_state="bsposter17" + name = "Pinup Girl Val" + desc = "Luscious Val McNeil, the vertically challenged Legal Extraordinaire, winner of Miss Space two years running and favoured pinup girl of Lawyers Weekly." + +/datum/poster/bay_18 + icon_state="bsposter18" + name = "Derpman, Enforcer of the State" + desc = "Here to protect and serve... your donuts! A generously proportioned man, he teaches you the value of hiding your snacks." + +/datum/poster/bay_19 + icon_state="bsposter19" + name = "Respect an Unathi" + desc = "This poster depicts a well dressed looking Unathi receiving a prestigious award. It appears to espouse greater co-operation and harmony between the two races." + +/datum/poster/bay_20 + icon_state="bsposter20" + name = "Skrell Twilight" + desc = "This poster depicts a mysteriously inscrutable, alien scene. Numerous Skrell can be seen conversing amidst great, crystalline towers rising above crashing waves" + +/datum/poster/bay_21 + icon_state="bsposter21" + name = "Join the Fuzz!" + desc = "It's a nice recruitment poster of a white haired Chinese woman that says; \"Big Guns, Hot Women, Good Times. Security. We get it done.\"" + +/datum/poster/bay_22 + icon_state="bsposter22" + name = "Looking for a career with excitement?" + desc = "A recruitment poster starring a dark haired woman with glasses and a purple shirt that has \"Got Brains? Got Talent? Not afraid of electric flying monsters that want to suck the soul out of you? Then Xenobiology could use someone like you!\" written on the bottom." + +/datum/poster/bay_23 + icon_state="bsposter23" + name = "Safety first: because electricity doesn't wait!" + desc = "A safety poster starring a clueless looking redhead with frazzled hair. \"Every year, hundreds of NT employees expose themselves to electric shock. Play it safe. Avoid suspicious doors after electrical storms, and always wear protection when doing electric maintenance.\"" + +/datum/poster/bay_24 + icon_state="bsposter24" + name = "Responsible medbay habits, No #259" + desc = "A poster with a nervous looking geneticist on it states; \"Friends Tell Friends They're Clones. It can cause severe and irreparable emotional trauma if a person is not properly informed of their recent demise. Always follow your contractual obligation and inform them of their recent rejuvenation.\"" + +/datum/poster/bay_25 + icon_state="bsposter25" + name = "Irresponsible medbay habits, No #2" + desc = "This is a safety poster starring a perverted looking naked doctor. \"Sexual harassment is never okay. REPORT any acts of sexual deviance or harassment that disrupt a healthy working environment.\"" + +/datum/poster/bay_26 + icon_state="bsposter26" + name = "The Men We Knew" + desc = "This movie poster depicts a group of soldiers fighting a large mech, the movie seems to be a patriotic war movie." + +/datum/poster/bay_27 + icon_state="bsposter27" + name = "Plastic Sheep Can't Scream" + desc = "This is a movie poster for an upcoming horror movie, it features an AI in the front of it." + +/datum/poster/bay_28 + icon_state="bsposter28" + name = "The Stars Know Love" + desc = "This is a movie poster. A bleeding woman is shown drawing a heart in her blood on the window of space ship, it seems to be a romantic Drama." + +/datum/poster/bay_29 + icon_state="bsposter29" + name = "Winter Is Coming" + desc = "On the poster is a frighteningly large wolf, he warns: \"Only YOU can keep humanity from freezing during planetary occultation!\"" + +/datum/poster/bay_30 + icon_state="bsposter30" + name = "Ambrosia Vulgaris" + desc = "Just looking at this poster makes you feel a little bit dizzy." + +/datum/poster/bay_31 + icon_state="bsposter31" + name = "Donut Corp" + desc = "This is an advertisement for Donut Corp, the new innovation in donut technology!" + +/datum/poster/bay_32 + icon_state="bsposter32" + name = "Eat!" + desc = "A poster depicting a hamburger. The poster orders you to consume the hamburger." + +/datum/poster/bay_33 + icon_state="bsposter33" + name = "Tools, tools, tools" + desc = "You can never have enough tools, thats for sure!" + +/datum/poster/bay_34 + icon_state="bsposter34" + name = "Power Up!" + desc = "High reward, higher risk!" + +/datum/poster/bay_35 + icon_state="bsposter35" + name = "Lamarr" + desc = "This is a poster depicting the pet and mascot of the science department." + +/datum/poster/bay_36 + icon_state="bsposter36" + name = "Fancy Borg" + desc = "A poster depicting a cyborg using the service module. 'Fancy Borg' is written on it." + +/datum/poster/bay_37 + icon_state="bsposter37" + name = "Fancier Borg" + desc = "A poster depicting a cyborg using the service module. 'Fancy Borg' is written on it. This is even fancier than the first poster." + +/datum/poster/bay_38 + icon_state="bsposter38" + name = "Toaster Love" + desc = "This is a poster of a toaster containing two slices of bread. The word LOVE is written in big pink letters underneath." + +/datum/poster/bay_39 + icon_state="bsposter39" + name = "Responsible medbay habits, No #91" + desc = "A safety poster with a chemist holding a vial. \"Always wear safety gear while handling dangerous chemicals, even if it concerns only small amounts.\"" + +/datum/poster/bay_40 + icon_state="bsposter40" + name = "Agreeable work environment" + desc = "This poster depicts a young woman in a stylish dress. \"Try to aim for a pleasant atmosphere in the workspace. A friendly word can do more than forms in triplicate.\"" + +/datum/poster/bay_41 + icon_state="bsposter41" + name = "Professional work environment" + desc = "A safety poster featuring a green haired woman in a shimmering blue dress. \"As an Internal Affairs Agent, your job is to create a fair and agreeable work environment for the crewmembers, as discreetly and professionally as possible.\"" + +/datum/poster/bay_42 + icon_state="bsposter42" + name = "Engineering pinup" + desc = "This is pin-up poster. A half-naked girl with white hair, toned muscles and stunning blue eyes looks back at you from the poster. Her welding helmet, tattoos and grey jumpsuit hanging around her waist gives a bit of a rugged feel." + +/datum/poster/bay_43 + icon_state="bsposter43" + name = "Responsible medbay habits, No #3" + desc = "A safety poster with a purple-haired surgeon. She looks a bit cross. \"Let the surgeons do their work. NEVER replace or remove a surgery tool from where the surgeon put it.\"" + +/datum/poster/bay_44 + icon_state="bsposter44" + name = "Time for a drink?" + desc = "This poster depicts a friendly-looking Tajara holding a tray of drinks." + +/datum/poster/bay_45 + icon_state="bsposter45" + name = "Responsible engineering habits, No #1" + desc = "A safety poster featuring a blue haired engineer. \"When repairing a machine or construction, always aim for long-term solutions.\"" + +/datum/poster/bay_46 + icon_state="bsposter46" + name = "Inspirational lawyer" + desc = "An inspirational poster depicting a Skrellian lawyer. He seems to be shouting something, while pointing fiercely to the right." + +/datum/poster/bay_47 + icon_state="bsposter47" + name = "Security pinup" + desc = "This is a pin-up poster. A dark skinned white haired girl poses in the sunlight wearing a tank top with her stomach exposed. The text on the poster states \"M, Succubus of Security.\" and a lipstick mark stains the top right corner, as if kissed by the model herself." + +/datum/poster/bay_48 + icon_state="bsposter48" + name = "Borg pinup?" + desc = "This is a.. pin-up poster? It is a diagram on an old model of cyborg with a note scribbled in marker on the bottom, on the top there is a large XO written in red marker." + +/datum/poster/bay_49 + icon_state="bsposter49" + name = "Engineering recruitment" + desc = "This is a poster showing an engineer relaxing by a computer, the text states \"Living the life! Join Engineering today!\"" + +/datum/poster/bay_50 + icon_state="bsposter50" + name = "Pinup Girl Cindy Kate" + desc = "This particular one is of Cindy Kate, a seductive performer well known among less savoury circles." + +/datum/poster/bay_51 + icon_state="bsposter51" + name = "space appreciation poster" + desc = "This is a poster produced by the Generic Space Company, as a part of a series of commemorative posters on the wonders of space. One of three." + +/datum/poster/bay_52 + icon_state="bsposter52" + name = "fire safety poster" + desc = "This is a poster reminding you of what you should do if you are on fire, or if you are at a dance party." + +/datum/poster/bay_53 + icon_state="bsposter53" + name = "fire extinguisher poster" + desc = "This is a poster reminding you of what you should use to put out a fire." + +/datum/poster/bay_54 + icon_state="bsposter54" + name = "firefighter poster" + desc = "This is a poster of a particularly stern looking firefighter. The caption reads, \"Only you can prevent space fires.\"" + +/datum/poster/bay_55 + icon_state="bsposter55" + name = "Earth appreciation poster" + desc = "This is a poster produced by the Generic Space Company, as a part of a series of commemorative posters on the wonders of space. Two of three." + +/datum/poster/bay_56 + icon_state="bsposter56" + name = "Mars appreciation poster" + desc = "This is a poster produced by the Generic Space Company, as a part of a series of commemorative posters on the wonders of space. Three of three." + +/datum/poster/bay_57 + icon_state="bsposter57" + name = "space carp warning poster" + desc = "This poster tells of the dangers of space carp infestations." + +/datum/poster/bay_58 + icon_state="bsposter58" + name = "space carp information poster" + desc = "This poster showcases an old spacer saying on the dangers of migrant space carp." + +/datum/poster/bay_59 + icon_state="bsposter59" + name = "poster - Miss Science 2558" + desc = "A large piece of space-resistant printed paper. This pin-up poster depicts a woman wearing a NanoTrasen labcoat, a bikini, and a sheepish grin. She's shyly posing atop some highly specialized research equipment." diff --git a/code/game/objects/effects/decals/posters/tgposters.dm b/code/game/objects/effects/decals/posters/tgposters.dm new file mode 100644 index 00000000..ce5e6b7f --- /dev/null +++ b/code/game/objects/effects/decals/posters/tgposters.dm @@ -0,0 +1,50 @@ +// /tg/ posters. +/datum/poster/tg_1 + name = "Free Tonto" + desc = "A framed shred of a much larger flag, colors bled together and faded from age." + icon_state="poster1" + +/datum/poster/tg_2 + name = "Atmosia Declaration of Independence" + desc = "A relic of a failed rebellion" + icon_state="poster2" + +/datum/poster/tg_3 + name = "Fun Police" + desc = "A poster condemning the security forces." + icon_state="poster3" + +/datum/poster/tg_4 + name = "Lusty Xeno" + desc = "A heretical poster depicting the titular star of an equally heretical book." + icon_state="poster4" + +/datum/poster/tg_5 + name = "Mercenary Recruitment Poster" + desc = "See the galaxy! Shatter corrupt megacorporations! Join today!" + icon_state="poster5" + +/datum/poster/tg_6 + name = "Clown" + desc = "Honk." + icon_state="poster6" + +/datum/poster/tg_7 + name = "Smoke" + desc = "A poster depicting a carton of cigarettes." + icon_state="poster7" + +/datum/poster/tg_8 + name = "Grey Tide" + desc = "A rebellious poster symbolizing assistant solidarity." + icon_state="poster8" + +/datum/poster/tg_9 + name = "Missing Gloves" + desc = "This poster is about the uproar that followed Nanotrasen's financial cuts towards insulated-glove purchases." + icon_state="poster9" + +/datum/poster/tg_10 + name = "Hacking Guide" + desc = "This poster details the internal workings of the common Nanotrasen airlock." + icon_state="poster10" diff --git a/code/game/objects/effects/decals/remains.dm b/code/game/objects/effects/decals/remains.dm new file mode 100644 index 00000000..0d0e18a9 --- /dev/null +++ b/code/game/objects/effects/decals/remains.dm @@ -0,0 +1,41 @@ +/obj/item/remains + name = "remains" + gender = PLURAL + icon = 'icons/effects/blood.dmi' + icon_state = "remains" + anchored = 0 + +/obj/item/remains/human + desc = "They look like human remains. They have a strange aura about them." + +/obj/effect/decal/remains // Apparently used by cult somewhere? + desc = "They look like human remains. They have a strange aura about them." + icon = 'icons/effects/blood.dmi' + icon_state = "remains" + +/obj/item/remains/xeno + desc = "They look like the remains of something... alien. They have a strange aura about them." + icon_state = "remainsxeno" + +/obj/item/remains/robot + desc = "They look like the remains of something mechanical. They have a strange aura about them." + icon = 'icons/mob/robots.dmi' + icon_state = "remainsrobot" + +/obj/item/remains/mouse + desc = "They look like the remains of a small rodent." + icon_state = "mouse" + +/obj/item/remains/lizard + desc = "They look like the remains of a small rodent." + icon_state = "lizard" + +/obj/item/remains/attack_hand(mob/user as mob) + to_chat(user, "[src] sinks together into a pile of ash.") + var/turf/simulated/floor/F = get_turf(src) + if (istype(F)) + new /obj/effect/decal/cleanable/ash(F) + qdel(src) + +/obj/item/remains/robot/attack_hand(mob/user as mob) + return diff --git a/code/game/objects/effects/decals/warning_stripes.dm b/code/game/objects/effects/decals/warning_stripes.dm new file mode 100644 index 00000000..05c2a095 --- /dev/null +++ b/code/game/objects/effects/decals/warning_stripes.dm @@ -0,0 +1,12 @@ +/obj/effect/decal/warning_stripes + icon = 'icons/effects/warning_stripes.dmi' + +/obj/effect/decal/warning_stripes/New() + . = ..() + var/turf/T=get_turf(src) + var/image/I=image(icon, icon_state = icon_state, dir = dir) + I.color=color + I.plane = ABOVE_TURF_PLANE + I.layer = DECAL_LAYER + T.overlays += I + qdel(src) diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm new file mode 100644 index 00000000..bc019f72 --- /dev/null +++ b/code/game/objects/effects/effect_system.dm @@ -0,0 +1,526 @@ +/* This is an attempt to make some easily reusable "particle" type effect, to stop the code +constantly having to be rewritten. An item like the jetpack that uses the ion_trail_follow system, just has one +defined, then set up when it is created with New(). Then this same system can just be reused each time +it needs to create more trails.A beaker could have a steam_trail_follow system set up, then the steam +would spawn and follow the beaker, even if it is carried or thrown. +*/ + + +/obj/effect/effect + name = "effect" + icon = 'icons/effects/effects.dmi' + mouse_opacity = 0 + unacidable = 1//So effect are not targeted by alien acid. + pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GRILLE + plane = ABOVE_HUMAN_PLANE + +/datum/effect/effect/system + var/number = 3 + var/cardinals = 0 + var/turf/location + var/atom/holder + var/setup = 0 + + proc/set_up(n = 3, c = 0, turf/loc) + if(n > 10) + n = 10 + number = n + cardinals = c + location = loc + setup = 1 + + proc/attach(atom/atom) + holder = atom + + proc/start() + + +///////////////////////////////////////////// +// GENERIC STEAM SPREAD SYSTEM + +//Usage: set_up(number of bits of steam, use North/South/East/West only, spawn location) +// The attach(atom/atom) proc is optional, and can be called to attach the effect +// to something, like a smoking beaker, so then you can just call start() and the steam +// will always spawn at the items location, even if it's moved. + +/* Example: +var/datum/effect/system/steam_spread/steam = new /datum/effect/system/steam_spread() -- creates new system +steam.set_up(5, 0, mob.loc) -- sets up variables +OPTIONAL: steam.attach(mob) +steam.start() -- spawns the effect +*/ +///////////////////////////////////////////// +/obj/effect/effect/steam + name = "steam" + icon = 'icons/effects/effects.dmi' + icon_state = "extinguish" + density = 0 + +/datum/effect/effect/system/steam_spread + + set_up(n = 3, c = 0, turf/loc) + if(n > 10) + n = 10 + number = n + cardinals = c + location = loc + + start() + var/i = 0 + for(i=0, i 10) + n = 10 + number = n + cardinals = c + if(istype(loca, /turf/)) + location = loca + else + location = get_turf(loca) + + start() + var/i = 0 + for(i=0, i 10) + n = 10 + number = n + cardinals = c + if(istype(loca, /turf/)) + location = loca + else + location = get_turf(loca) + if(direct) + direction = direct + +/datum/effect/effect/system/smoke_spread/start() + var/i = 0 + for(i=0, i 20) + return + addtimer(CALLBACK(src, .proc/make_smokes, i), 0) + + +//Hi, this isn't bay. Please don't think too hard about how ugly these are. It's better than a billion spawns. +/datum/effect/effect/system/smoke_spread/proc/make_smokes(var/i) + if(holder) + src.location = get_turf(holder) + var/obj/effect/effect/smoke/smoke = new smoke_type(location) + src.total_smoke++ + var/direction = src.direction + if(!direction) + if(src.cardinals) + direction = pick(GLOB.cardinal) + else + direction = pick(GLOB.alldirs) + for(i=0, iThe solution violently explodes.") + for(var/mob/M in viewers(1, location)) + if (prob (50 * amount)) + to_chat(M, "The explosion knocks you down.") + M.Weaken(rand(1,5)) + return + else + var/devst = -1 + var/heavy = -1 + var/light = -1 + var/flash = -1 + + // Clamp all values to fractions of GLOB.max_explosion_range, following the same pattern as for tank transfer bombs + if (round(amount/12) > 0) + devst = devst + amount/12 + + if (round(amount/6) > 0) + heavy = heavy + amount/6 + + if (round(amount/3) > 0) + light = light + amount/3 + + if (flashing && flashing_factor) + flash = (amount/4) * flashing_factor + + for(var/mob/M in viewers(8, location)) + to_chat(M, "The solution violently explodes.") + + explosion( + location, + round(min(devst, BOMBCAP_DVSTN_RADIUS)), + round(min(heavy, BOMBCAP_HEAVY_RADIUS)), + round(min(light, BOMBCAP_LIGHT_RADIUS)), + round(min(flash, BOMBCAP_FLASH_RADIUS)) + ) diff --git a/code/game/objects/effects/explosion_particles.dm b/code/game/objects/effects/explosion_particles.dm new file mode 100644 index 00000000..e867a273 --- /dev/null +++ b/code/game/objects/effects/explosion_particles.dm @@ -0,0 +1,70 @@ +/obj/effect/expl_particles + name = "explosive particles" + icon = 'icons/effects/effects.dmi' + icon_state = "explosion_particle" + opacity = 1 + anchored = 1 + mouse_opacity = 0 + +/obj/effect/expl_particles/New() + ..() + spawn (15) + qdel(src) + return + +/obj/effect/expl_particles/Move() + ..() + return + +/datum/effect/system/expl_particles + var/number = 10 + var/turf/location + var/total_particles = 0 + +/datum/effect/system/expl_particles/proc/set_up(n = 10, loca) + number = n + if(istype(loca, /turf/)) location = loca + else location = get_turf(loca) + +/datum/effect/system/expl_particles/proc/start() + var/i = 0 + for(i=0, i\The [src] sucks in \the [AM]!") + if(!ismob(AM)) + var/obj/O = AM + if(O.w_class <= ITEM_SIZE_SMALL) + return //Dont spam for small stuff + playsound(src,'sound/effects/teleport.ogg',40,1) + return + +/obj/effect/force_portal/Bumped(var/atom/movable/AM) + AM.dropInto(src) + +/obj/effect/force_portal/bullet_act(var/obj/item/projectile/P) + var/atom/movable/AM = new P.type() + if(istype(P, /obj/item/projectile/bullet/pellet)) + var/obj/item/projectile/bullet/pellet/old_pellet = P + var/obj/item/projectile/bullet/pellet/new_pellet = AM + new_pellet.pellets = old_pellet.pellets + AM.dropInto(src) + P.forceMove(null) + qdel(P) \ No newline at end of file diff --git a/code/game/objects/effects/gibs.dm b/code/game/objects/effects/gibs.dm new file mode 100644 index 00000000..c7b75b24 --- /dev/null +++ b/code/game/objects/effects/gibs.dm @@ -0,0 +1,61 @@ +/proc/gibs(atom/location, var/datum/dna/MobDNA, gibber_type = /obj/effect/gibspawner/generic, var/fleshcolor, var/bloodcolor) + new gibber_type(location,MobDNA,fleshcolor,bloodcolor) + +/obj/effect/gibspawner + var/sparks = 0 //whether sparks spread on Gib() + var/virusProb = 20 //the chance for viruses to spread on the gibs + var/list/gibtypes = list() + var/list/gibamounts = list() + var/list/gibdirections = list() //of lists + var/fleshcolor //Used for gibbed humans. + var/bloodcolor //Used for gibbed humans. + var/datum/dna/MobDNA + + New(location, var/datum/dna/MobDNA, var/fleshcolor, var/bloodcolor) + ..() + + if(fleshcolor) src.fleshcolor = fleshcolor + if(bloodcolor) src.bloodcolor = bloodcolor + if(MobDNA) src.MobDNA = MobDNA + + Initialize() + ..() + Gib(loc) + return INITIALIZE_HINT_QDEL + + proc/Gib(atom/location) + if(gibtypes.len != gibamounts.len || gibamounts.len != gibdirections.len) + log_error("Gib list length mismatch!") + return + + if(sparks) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread() + s.set_up(2, 1, get_turf(location)) // Not sure if it's safe to pass an arbitrary object to set_up, todo + s.start() + + var/obj/effect/decal/cleanable/blood/gibs/gib = null + for(var/i = 1, i<= gibtypes.len, i++) + if(gibamounts[i]) + for(var/j = 1, j<= gibamounts[i], j++) + var/gibType = gibtypes[i] + gib = new gibType(location) + + // Apply human species colouration to masks. + if(fleshcolor) + gib.fleshcolor = fleshcolor + if(bloodcolor) + gib.basecolor = bloodcolor + + gib.update_icon() + + gib.blood_DNA = list() + if(MobDNA) + gib.blood_DNA[MobDNA.unique_enzymes] = MobDNA.b_type + else if(istype(src, /obj/effect/gibspawner/human)) // Probably a monkey + gib.blood_DNA["Non-human DNA"] = "A+" + if(istype(location,/turf/)) + var/list/directions = gibdirections[i] + if(directions.len) + gib.streak(directions) + + qdel(src) diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm new file mode 100644 index 00000000..9989f158 --- /dev/null +++ b/code/game/objects/effects/landmarks.dm @@ -0,0 +1,345 @@ +/obj/effect/landmark + name = "landmark" + icon = 'icons/mob/screen1.dmi' + icon_state = "x2" + anchored = 1.0 + unacidable = 1 + simulated = 0 + invisibility = 101 + var/delete_me = 0 + +/obj/effect/landmark/New() + ..() + tag = "landmark*[name]" + + //TODO clean up this mess + switch(name) //some of these are probably obsolete + if("monkey") + GLOB.monkeystart += loc + delete_me = 1 + return + if("start") + GLOB.newplayer_start += loc + delete_me = 1 + return + if("JoinLate") + GLOB.latejoin += loc + delete_me = 1 + return + if("JoinLateGateway") + GLOB.latejoin_gateway += loc + delete_me = 1 + return + if("JoinLateCryo") + GLOB.latejoin_cryo += loc + delete_me = 1 + return + if("JoinLateCyborg") + GLOB.latejoin_cyborg += loc + delete_me = 1 + return + if("prisonwarp") + GLOB.prisonwarp += loc + delete_me = 1 + return + if("tdome1") + GLOB.tdome1 += loc + if("tdome2") + GLOB.tdome2 += loc + if("tdomeadmin") + GLOB.tdomeadmin += loc + if("tdomeobserve") + GLOB.tdomeobserve += loc + if("prisonsecuritywarp") + GLOB.prisonsecuritywarp += loc + delete_me = 1 + return + if("endgame_exit") + endgame_safespawns += loc + delete_me = 1 + return + if("bluespacerift") + endgame_exits += loc + delete_me = 1 + return + + landmarks_list += src + return 1 + +/obj/effect/landmark/proc/delete() + delete_me = 1 + +/obj/effect/landmark/Initialize() + . = ..() + if(delete_me) + return INITIALIZE_HINT_QDEL + +/obj/effect/landmark/Destroy() + landmarks_list -= src + return ..() + +/obj/effect/landmark/start + name = "start" + icon = 'icons/mob/screen1.dmi' + icon_state = "x" + anchored = 1.0 + invisibility = 101 + +/obj/effect/landmark/start/New() + ..() + tag = "start*[name]" + return 1 + +/obj/effect/landmark/start/assistant + name = "Assistant" +/obj/effect/landmark/start/botanic + name = "Botanic" +/obj/effect/landmark/start/bartender + name = "Bartender" +/obj/effect/landmark/start/magistrate + name = "Commandant" +/obj/effect/landmark/start/cargo + name = "Crate Pusher" +/obj/effect/landmark/start/chemist + name = "Chemist" +/obj/effect/landmark/start/chef + name = "Chef" +/obj/effect/landmark/start/chaplain + name = "Chaplain" +/obj/effect/landmark/start/chief_engineer + name = "Head Upkeeper" +/obj/effect/landmark/start/cmo + name = "Head Practitioner" +/obj/effect/landmark/start/detective + name = "Inspector" +/obj/effect/landmark/start/engineer + name = "Upkeeper" +/obj/effect/landmark/start/overseer + name = "Overseer" +/obj/effect/landmark/start/head_peacekeeper + name = "Head Peacekeeper" +/obj/effect/landmark/start/janitor + name = "Janitor" +/obj/effect/landmark/start/librarian + name = "Librarian" +/obj/effect/landmark/start/medical_doctor + name = "Practitioner" +/obj/effect/landmark/start/paramedic + name = "Paramedic" +/obj/effect/landmark/start/meister + name = "Quartermaster" +/obj/effect/landmark/start/robotic_augmentor + name = "Robotic Augmentor" +/obj/effect/landmark/start/peacekeeper + name = "Peacekeeper" +/obj/effect/landmark/start/shaft_miner + name = "Shaft Miner" +/obj/effect/landmark/start/scientist + name = "Tenchotrainee" +/obj/effect/landmark/start/warden + name = "Warden" +/obj/effect/landmark/start/xenobiologist + name = "Xenobiologist" +/obj/effect/landmark/start/supreme_arbiter + name = "Supreme Arbiter" +/obj/effect/landmark/start/arbiter + name = "Arbiter" +/obj/effect/landmark/start/cargo_kid + name ="Cargo Kid" +/obj/effect/landmark/start/cadet + name = "Cadet" +/obj/effect/landmark/start/heir + name = "Heir" + +//Costume spawner landmarks +/obj/effect/landmark/costume/New() //costume spawner, selects a random subclass and disappears + + var/list/options = typesof(/obj/effect/landmark/costume) + var/PICK= options[rand(1,options.len)] + new PICK(src.loc) + delete_me = 1 + +//SUBCLASSES. Spawn a bunch of items and disappear likewise +/obj/effect/landmark/costume/chameleon/New() + new /obj/item/clothing/mask/chameleon(src.loc) + new /obj/item/clothing/under/chameleon(src.loc) + new /obj/item/clothing/glasses/chameleon(src.loc) + new /obj/item/clothing/shoes/chameleon(src.loc) + new /obj/item/clothing/gloves/chameleon(src.loc) + new /obj/item/clothing/suit/chameleon(src.loc) + new /obj/item/clothing/head/chameleon(src.loc) + new /obj/item/weapon/storage/backpack/chameleon(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/gladiator/New() + new /obj/item/clothing/under/gladiator(src.loc) + new /obj/item/clothing/head/helmet/gladiator(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/madscientist/New() + new /obj/item/clothing/under/gimmick/rank/captain/suit(src.loc) + new /obj/item/clothing/head/flatcap(src.loc) + new /obj/item/clothing/suit/storage/toggle/labcoat/mad(src.loc) + new /obj/item/clothing/glasses/gglasses(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/elpresidente/New() + new /obj/item/clothing/under/gimmick/rank/captain/suit(src.loc) + new /obj/item/clothing/head/flatcap(src.loc) + new /obj/item/clothing/mask/smokable/cigarette/cigar/havana(src.loc) + new /obj/item/clothing/shoes/jackboots(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/nyangirl/New() + new /obj/item/clothing/under/schoolgirl(src.loc) + new /obj/item/clothing/head/kitty(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/maid/New() + new /obj/item/clothing/under/blackskirt(src.loc) + var/CHOICE = pick( /obj/item/clothing/head/beret , /obj/item/clothing/head/rabbitears ) + new CHOICE(src.loc) + new /obj/item/clothing/glasses/sunglasses/blindfold(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/butler/New() + new /obj/item/clothing/accessory/wcoat(src.loc) + new /obj/item/clothing/under/suit_jacket(src.loc) + new /obj/item/clothing/head/that(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/scratch/New() + new /obj/item/clothing/gloves/white(src.loc) + new /obj/item/clothing/shoes/white(src.loc) + new /obj/item/clothing/under/scratch(src.loc) + if (prob(30)) + new /obj/item/clothing/head/cueball(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/prig/New() + new /obj/item/clothing/accessory/wcoat(src.loc) + new /obj/item/clothing/glasses/monocle(src.loc) + var/CHOICE= pick( /obj/item/clothing/head/bowler, /obj/item/clothing/head/that) + new CHOICE(src.loc) + new /obj/item/clothing/shoes/black(src.loc) + new /obj/item/weapon/cane(src.loc) + new /obj/item/clothing/under/sl_suit(src.loc) + new /obj/item/clothing/mask/fakemoustache(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/plaguedoctor/New() + new /obj/item/clothing/suit/bio_suit/plaguedoctorsuit(src.loc) + new /obj/item/clothing/head/plaguedoctorhat(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/nightowl/New() + new /obj/item/clothing/under/owl(src.loc) + new /obj/item/clothing/mask/gas/owl_mask(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/waiter/New() + new /obj/item/clothing/under/waiter(src.loc) + var/CHOICE= pick( /obj/item/clothing/head/kitty, /obj/item/clothing/head/rabbitears) + new CHOICE(src.loc) + new /obj/item/clothing/suit/apron(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/pirate/New() + new /obj/item/clothing/under/pirate(src.loc) + new /obj/item/clothing/suit/pirate(src.loc) + var/CHOICE = pick( /obj/item/clothing/head/pirate , /obj/item/clothing/mask/bandana/red) + new CHOICE(src.loc) + new /obj/item/clothing/glasses/eyepatch(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/commie/New() + new /obj/item/clothing/under/soviet(src.loc) + new /obj/item/clothing/head/ushanka(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/imperium_monk/New() + new /obj/item/clothing/suit/imperium_monk(src.loc) + if (prob(25)) + new /obj/item/clothing/mask/gas/cyborg(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/holiday_priest/New() + new /obj/item/clothing/suit/holidaypriest(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/marisawizard/fake/New() + new /obj/item/clothing/head/wizard/marisa/fake(src.loc) + new/obj/item/clothing/suit/wizrobe/marisa/fake(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/cutewitch/New() + new /obj/item/clothing/under/sundress(src.loc) + new /obj/item/clothing/head/witchwig(src.loc) + new /obj/item/weapon/staff/broom(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/fakewizard/New() + new /obj/item/clothing/suit/wizrobe/fake(src.loc) + new /obj/item/clothing/head/wizard/fake(src.loc) + new /obj/item/weapon/staff/(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/sexyclown/New() + new /obj/item/clothing/mask/gas/sexyclown(src.loc) + new /obj/item/clothing/under/sexyclown(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/sexymime/New() + new /obj/item/clothing/mask/gas/sexymime(src.loc) + new /obj/item/clothing/under/sexymime(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/savagehunter/New() + new /obj/item/clothing/mask/spirit(src.loc) + new /obj/item/clothing/under/savage_hunter(src.loc) + delete_me = 1 + +/obj/effect/landmark/costume/savagehuntress/New() + new /obj/item/clothing/mask/spirit(src.loc) + new /obj/item/clothing/under/savage_hunter/female(src.loc) + delete_me = 1 + +/obj/effect/landmark/ruin + var/datum/map_template/ruin/ruin_template + +/obj/effect/landmark/ruin/New(loc, my_ruin_template) + name = "ruin_[sequential_id(/obj/effect/landmark/ruin)]" + ..(loc) + ruin_template = my_ruin_template + GLOB.ruin_landmarks |= src + +/obj/effect/landmark/ruin/Destroy() + GLOB.ruin_landmarks -= src + ruin_template = null + . = ..() + +/obj/effect/landmark/random_gen + var/generation_width + var/generation_height + var/seed + delete_me = TRUE + +/obj/effect/landmark/random_gen/asteroid/Initialize() + . = ..() + + var/min_x = 1 + var/min_y = 1 + var/max_x = world.maxx + var/max_y = world.maxy + + if (generation_width) + min_x = max(src.x, min_x) + max_x = min(src.x + generation_width, max_x) + if (generation_height) + min_y = max(src.y, min_y) + max_y = min(src.y + generation_height, max_y) + + new /datum/random_map/automata/cave_system(seed, min_x, min_y, src.z, max_x, max_y) + new /datum/random_map/noise/ore(seed, min_x, min_y, src.z, max_x, max_y) + + GLOB.using_map.refresh_mining_turfs(src.z) diff --git a/code/game/objects/effects/manifest.dm b/code/game/objects/effects/manifest.dm new file mode 100644 index 00000000..9f56f254 --- /dev/null +++ b/code/game/objects/effects/manifest.dm @@ -0,0 +1,21 @@ +/obj/effect/manifest + name = "manifest" + icon = 'icons/mob/screen1.dmi' + icon_state = "x" + unacidable = 1//Just to be sure. + +/obj/effect/manifest/New() + + src.invisibility = 101 + return + +/obj/effect/manifest/proc/manifest() + var/dat = "Crew Manifest:
            " + for(var/mob/living/carbon/human/M in SSmobs.mob_list) + dat += text(" [] - []
            ", M.name, M.get_assignment()) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( src.loc ) + P.info = dat + P.SetName("paper- 'Crew Manifest'") + //SN src = null + qdel(src) + return \ No newline at end of file diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm new file mode 100644 index 00000000..7572c680 --- /dev/null +++ b/code/game/objects/effects/mines.dm @@ -0,0 +1,106 @@ +/obj/effect/mine + name = "Mine" + desc = "I Better stay away from that thing." + density = 1 + anchored = 1 + plane = OBJ_PLANE + layer = BASE_OBJ_LAYER + icon = 'icons/obj/weapons.dmi' + icon_state = "uglymine" + var/triggerproc = "explode" //name of the proc thats called when the mine is triggered + var/triggered = 0 + +/obj/effect/mine/New() + icon_state = "uglyminearmed" + +/obj/effect/mine/Crossed(AM as mob|obj) + Bumped(AM) + +/obj/effect/mine/Bumped(mob/M as mob|obj) + + if(triggered) return + + if(istype(M, /mob/living/carbon/human)) + for(var/mob/O in viewers(world.view, src.loc)) + to_chat(O, "\The [M] triggered the \icon[src] [src]") + triggered = 1 + call(src,triggerproc)(M) + +/obj/effect/mine/proc/triggerrad(obj) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread() + s.set_up(3, 1, src) + s.start() + obj:radiation += 50 + randmutb(obj) + domutcheck(obj,null) + spawn(0) + qdel(src) + +/obj/effect/mine/proc/triggerstun(obj) + if(ismob(obj)) + var/mob/M = obj + M.Stun(30) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread() + s.set_up(3, 1, src) + s.start() + spawn(0) + qdel(src) + +/obj/effect/mine/proc/triggern2o(obj) + //example: n2o triggerproc + //note: im lazy + + for (var/turf/simulated/floor/target in range(1,src)) + if(!target.blocks_air) + target.assume_gas("sleeping_agent", 30) + + spawn(0) + qdel(src) + +/obj/effect/mine/proc/triggerphoron(obj) + for (var/turf/simulated/floor/target in range(1,src)) + if(!target.blocks_air) + target.assume_gas("phoron", 30) + + target.hotspot_expose(1000, CELL_VOLUME) + + spawn(0) + qdel(src) + +/obj/effect/mine/proc/triggerkick(obj) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread() + s.set_up(3, 1, src) + s.start() + qdel(obj:client) + spawn(0) + qdel(src) + +/obj/effect/mine/proc/explode(obj) + explosion(loc, 0, 1, 2, 3) + spawn(0) + qdel(src) + +/obj/effect/mine/dnascramble + name = "Radiation Mine" + icon_state = "uglymine" + triggerproc = "triggerrad" + +/obj/effect/mine/phoron + name = "Phoron Mine" + icon_state = "uglymine" + triggerproc = "triggerphoron" + +/obj/effect/mine/kick + name = "Kick Mine" + icon_state = "uglymine" + triggerproc = "triggerkick" + +/obj/effect/mine/n2o + name = "N2O Mine" + icon_state = "uglymine" + triggerproc = "triggern2o" + +/obj/effect/mine/stun + name = "Stun Mine" + icon_state = "uglymine" + triggerproc = "triggerstun" diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm new file mode 100644 index 00000000..eafaf57b --- /dev/null +++ b/code/game/objects/effects/misc.dm @@ -0,0 +1,14 @@ +//The effect when you wrap a dead body in gift wrap +/obj/effect/spresent + name = "strange present" + desc = "It's a ... present?" + icon = 'icons/obj/items.dmi' + icon_state = "strangepresent" + density = 1 + anchored = 0 + +/obj/effect/stop + var/victim = null + icon_state = "empty" + name = "Geas" + desc = "You can't resist." diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm new file mode 100644 index 00000000..f01a9baf --- /dev/null +++ b/code/game/objects/effects/overlays.dm @@ -0,0 +1,142 @@ +/obj/effect/overlay + name = "overlay" + unacidable = 1 + var/i_attached//Added for possible image attachments to objects. For hallucinations and the like. + +/obj/effect/overlay/beam//Not actually a projectile, just an effect. + name="beam" + icon='icons/effects/beam.dmi' + icon_state= "b_beam" + var/tmp/atom/BeamSource + New() + ..() + spawn(10) qdel(src) + +/obj/effect/overlay/palmtree_r + name = "Palm tree" + icon = 'icons/misc/beach2.dmi' + icon_state = "palm1" + density = 1 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + anchored = 1 + +/obj/effect/overlay/palmtree_l + name = "Palm tree" + icon = 'icons/misc/beach2.dmi' + icon_state = "palm2" + density = 1 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + anchored = 1 + +/obj/effect/overlay/coconut + name = "Coconuts" + icon = 'icons/misc/beach.dmi' + icon_state = "coconuts" + +/obj/effect/overlay/bluespacify + name = "Bluespace" + icon = 'icons/turf/space.dmi' + icon_state = "bluespacify" + plane = EFFECTS_ABOVE_LIGHTING_PLANE + layer = SUPERMATTER_WALL_LAYER + +/obj/effect/overlay/wallrot + name = "wallrot" + desc = "Ick..." + icon = 'icons/effects/wallrot.dmi' + anchored = 1 + density = 1 + plane = ABOVE_TURF_PLANE + layer = ABOVE_TILE_LAYER + mouse_opacity = 0 + +/obj/effect/overlay/bmark + name = "bullet hole" + desc = "Well someone shot something." + icon = 'icons/effects/effects.dmi' + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_OBJ_LAYER + icon_state = "scorch" + +/obj/effect/overlay/wallrot/New() + ..() + pixel_x += rand(-10, 10) + pixel_y += rand(-10, 10) + +/obj/effect/overlay/temp + anchored = 1 + plane = ABOVE_HUMAN_PLANE + mouse_opacity = 0 + var/duration = 10 + var/randomdir = TRUE + +/obj/effect/overlay/temp/New() + if(randomdir) + dir = pick(GLOB.cardinal) + + flick("[icon_state]", src) //Because we might be pulling it from a pool, flick whatever icon it uses so it starts at the start of the icon's animation. + + spawn(duration) + qdel(src) + + +/obj/effect/overlay/temp/dir_setting/bloodsplatter + icon = 'icons/effects/blood.dmi' + duration = 5 + randomdir = FALSE + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + color = "#C80000" + var/splatter_type = "splatter" + +/obj/effect/overlay/temp/dir_setting/bloodsplatter/New(loc, set_dir, blood_color) + if(blood_color) + color = blood_color + if(set_dir in GLOB.cornerdirs) + icon_state = "[splatter_type][pick(1, 2, 6)]" + else + icon_state = "[splatter_type][pick(3, 4, 5)]" + ..() + var/target_pixel_x = 0 + var/target_pixel_y = 0 + switch(set_dir) + if(NORTH) + target_pixel_y = 16 + if(SOUTH) + target_pixel_y = -16 + layer = BASE_MOB_LAYER + 0.1 + if(EAST) + target_pixel_x = 16 + if(WEST) + target_pixel_x = -16 + if(NORTHEAST) + target_pixel_x = 16 + target_pixel_y = 16 + if(NORTHWEST) + target_pixel_x = -16 + target_pixel_y = 16 + if(SOUTHEAST) + target_pixel_x = 16 + target_pixel_y = -16 + layer = BASE_MOB_LAYER + 0.1 + if(SOUTHWEST) + target_pixel_x = -16 + target_pixel_y = -16 + layer = BASE_MOB_LAYER + 0.1 + animate(src, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = duration) + +/obj/effect/overlay/temp/dir_setting/bloodsplatter/xenosplatter + splatter_type = "xsplatter" + +/obj/effect/overlay/temp/bullet_impact + icon = 'icons/effects/effects.dmi' + icon_state = "impact_bullet" + randomdir = FALSE + duration = 5 + +/obj/effect/overlay/temp/bullet_impact/New(x,y) + ..() + pixel_x = x + pixel_y = y \ No newline at end of file diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm new file mode 100644 index 00000000..d05e601d --- /dev/null +++ b/code/game/objects/effects/portals.dm @@ -0,0 +1,65 @@ +/obj/effect/portal + name = "portal" + desc = "Looks unstable. Best to test it with the clown." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "portal" + density = 1 + unacidable = 1//Can't destroy energy portals. + var/obj/item/target = null + var/creator = null + anchored = 1.0 + var/dangerous = 0 + var/failchance = 0 + +/obj/effect/portal/Bumped(mob/M as mob|obj) + spawn(0) + src.teleport(M) + return + return + +/obj/effect/portal/Crossed(AM as mob|obj) + spawn(0) + src.teleport(AM) + return + return + +/obj/effect/portal/attack_hand(mob/user as mob) + spawn(0) + src.teleport(user) + return + return + +/obj/effect/portal/New(var/start, var/end, var/delete_after = 300, var/failure_rate) + ..() + if(failure_rate) + failchance = failure_rate + if(prob(failchance)) + icon_state = "portal1" + dangerous = 1 + playsound(src, 'sound/effects/phasein.ogg', 25, 1) + target = end + + if(delete_after) + spawn(delete_after) + qdel(src) + +/obj/effect/portal/Destroy() + target = null + . = ..() + +/obj/effect/portal/proc/teleport(atom/movable/M as mob|obj) + if(istype(M, /obj/effect)) //sparks don't teleport + return + if (M.anchored&&istype(M, /obj/mecha)) + return + if (icon_state == "portal1") + return + if (!( target )) + qdel(src) + return + if (istype(M, /atom/movable)) + if(dangerous && prob(failchance)) //oh dear a problem, put em in deep space + var/destination_z = GLOB.using_map.get_transit_zlevel(z) + do_teleport(M, locate(rand(TRANSITIONEDGE, world.maxx - TRANSITIONEDGE), rand(TRANSITIONEDGE, world.maxy -TRANSITIONEDGE), destination_z), 0) + else + do_teleport(M, target, 1) ///You will appear adjacent to the beacon diff --git a/code/game/objects/effects/spawners/bombspawner.dm b/code/game/objects/effects/spawners/bombspawner.dm new file mode 100644 index 00000000..fb2f073c --- /dev/null +++ b/code/game/objects/effects/spawners/bombspawner.dm @@ -0,0 +1,218 @@ +/* The old single tank bombs that dont really work anymore +/obj/effect/spawner/bomb + name = "bomb" + icon = 'icons/mob/screen1.dmi' + icon_state = "x" + var/btype = 0 //0 = radio, 1= prox, 2=time + var/explosive = 1 // 0= firebomb + var/btemp = 500 // bomb temperature (degC) + var/active = 0 + +/obj/effect/spawner/bomb/radio + btype = 0 + +/obj/effect/spawner/bomb/proximity + btype = 1 + +/obj/effect/spawner/bomb/timer + btype = 2 + +/obj/effect/spawner/bomb/timer/syndicate + btemp = 450 + +/obj/effect/spawner/bomb/suicide + btype = 3 + +/obj/effect/spawner/bomb/New() + ..() + + switch (src.btype) + // radio + if (0) + var/obj/item/assembly/r_i_ptank/R = new /obj/item/assembly/r_i_ptank(src.loc) + var/obj/item/weapon/tank/phoron/p3 = new /obj/item/weapon/tank/phoron(R) + var/obj/item/device/radio/signaler/p1 = new /obj/item/device/radio/signaler(R) + var/obj/item/device/igniter/p2 = new /obj/item/device/igniter(R) + R.part1 = p1 + R.part2 = p2 + R.part3 = p3 + p1.master = R + p2.master = R + p3.master = R + R.status = explosive + p1.b_stat = 0 + p2.secured = 1 + p3.air_contents.temperature = btemp + T0C + + // proximity + if (1) + var/obj/item/assembly/m_i_ptank/R = new /obj/item/assembly/m_i_ptank(src.loc) + var/obj/item/weapon/tank/phoron/p3 = new /obj/item/weapon/tank/phoron(R) + var/obj/item/device/prox_sensor/p1 = new /obj/item/device/prox_sensor(R) + var/obj/item/device/igniter/p2 = new /obj/item/device/igniter(R) + R.part1 = p1 + R.part2 = p2 + R.part3 = p3 + p1.master = R + p2.master = R + p3.master = R + R.status = explosive + + p3.air_contents.temperature = btemp + T0C + p2.secured = 1 + + if(src.active) + R.part1.secured = 1 + R.part1.icon_state = text("motion[]", 1) + R.c_state(1, src) + + // timer + if (2) + var/obj/item/assembly/t_i_ptank/R = new /obj/item/assembly/t_i_ptank(src.loc) + var/obj/item/weapon/tank/phoron/p3 = new /obj/item/weapon/tank/phoron(R) + var/obj/item/device/timer/p1 = new /obj/item/device/timer(R) + var/obj/item/device/igniter/p2 = new /obj/item/device/igniter(R) + R.part1 = p1 + R.part2 = p2 + R.part3 = p3 + p1.master = R + p2.master = R + p3.master = R + R.status = explosive + + p3.air_contents.temperature = btemp + T0C + p2.secured = 1 + //bombvest + if(3) + var/obj/item/clothing/suit/armor/a_i_a_ptank/R = new /obj/item/clothing/suit/armor/a_i_a_ptank(src.loc) + var/obj/item/weapon/tank/phoron/p4 = new /obj/item/weapon/tank/phoron(R) + var/obj/item/device/healthanalyzer/p1 = new /obj/item/device/healthanalyzer(R) + var/obj/item/device/igniter/p2 = new /obj/item/device/igniter(R) + var/obj/item/clothing/suit/armor/vest/p3 = new /obj/item/clothing/suit/armor/vest(R) + R.part1 = p1 + R.part2 = p2 + R.part3 = p3 + R.part4 = p4 + p1.master = R + p2.master = R + p3.master = R + p4.master = R + R.status = explosive + + p4.air_contents.temperature = btemp + T0C + p2.secured = 1 + + 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" + 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 = 12 + var/oxygen_amt = 18 + var/carbon_amt = 0 + +/obj/effect/spawner/newbomb/timer + name = "TTV bomb - timer" + assembly_type = /obj/item/device/assembly/timer + +/obj/effect/spawner/newbomb/timer/syndicate + name = "TTV bomb - merc" + //High yield bombs. Yes, it is possible to make these with toxins + phoron_amt = 18.5 + oxygen_amt = 28.5 + +/obj/effect/spawner/newbomb/proximity + name = "TTV bomb - proximity" + assembly_type = /obj/item/device/assembly/prox_sensor + +/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 + ..() + +/obj/effect/spawner/newbomb/Initialize() + ..() + 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) + + V.tank_one = PT + V.tank_two = OT + + PT.master = V + OT.master = V + + PT.valve_welded = 1 + PT.air_contents.gas["phoron"] = phoron_amt + PT.air_contents.gas["carbon_dioxide"] = carbon_amt + PT.air_contents.total_moles = phoron_amt + carbon_amt + PT.air_contents.temperature = PHORON_MINIMUM_BURN_TEMPERATURE+1 + PT.air_contents.update_values() + + OT.valve_welded = 1 + OT.air_contents.gas["oxygen"] = oxygen_amt + OT.air_contents.total_moles = oxygen_amt + OT.air_contents.temperature = PHORON_MINIMUM_BURN_TEMPERATURE+1 + OT.air_contents.update_values() + + + var/obj/item/device/assembly/S = new assembly_type(V) + + + V.attached_device = S + + S.holder = V + S.toggle_secure() + + V.update_icon() + return INITIALIZE_HINT_QDEL + +/////////////////////// +//One Tank Bombs, WOOOOOOO! -Luke +/////////////////////// + +/obj/effect/spawner/onetankbomb + name = "Single-tank 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 = 0 + var/oxygen_amt = 0 + +/obj/effect/spawner/onetankbomb/New(newloc) //just needs an assembly. + ..(newloc) + + var/type = pick(/obj/item/weapon/tank/phoron/onetankbomb, /obj/item/weapon/tank/oxygen/onetankbomb) + new type(src.loc) + + qdel(src) diff --git a/code/game/objects/effects/spawners/gibspawner.dm b/code/game/objects/effects/spawners/gibspawner.dm new file mode 100644 index 00000000..a05bd22f --- /dev/null +++ b/code/game/objects/effects/spawners/gibspawner.dm @@ -0,0 +1,27 @@ +/obj/effect/gibspawner + generic + gibtypes = list(/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs/core) + gibamounts = list(2,2,1) + + New() + gibdirections = list(list(WEST, NORTHWEST, SOUTHWEST, NORTH),list(EAST, NORTHEAST, SOUTHEAST, SOUTH), list()) + ..() + + human + gibtypes = list(/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs/down,/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs/core) + gibamounts = list(1,1,1,1,1,1,1) + + New() + gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs, list()) + gibamounts[6] = pick(0,1,2) + ..() + + robot + sparks = 1 + gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/robot/up,/obj/effect/decal/cleanable/blood/gibs/robot/down,/obj/effect/decal/cleanable/blood/gibs/robot,/obj/effect/decal/cleanable/blood/gibs/robot,/obj/effect/decal/cleanable/blood/gibs/robot,/obj/effect/decal/cleanable/blood/gibs/robot/limb) + gibamounts = list(1,1,1,1,1,1) + + New() + gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs) + gibamounts[6] = pick(0,1,2) + ..() \ No newline at end of file diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm new file mode 100644 index 00000000..00dcd129 --- /dev/null +++ b/code/game/objects/effects/spiders.dm @@ -0,0 +1,308 @@ +//generic procs copied from obj/effect/alien +/obj/effect/spider + name = "web" + desc = "It's stringy and sticky." + icon = 'icons/effects/effects.dmi' + anchored = 1 + density = 0 + var/health = 15 + +//similar to weeds, but only barfed out by nurses manually +/obj/effect/spider/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/spider/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(isWelder(W)) + 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/spider/bullet_act(var/obj/item/projectile/Proj) + ..() + health -= Proj.get_structure_damage() + healthcheck() + +/obj/effect/spider/proc/healthcheck() + if(health <= 0) + qdel(src) + +/obj/effect/spider/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > 300 + T0C) + health -= 5 + healthcheck() + +/obj/effect/spider/stickyweb + icon_state = "stickyweb1" + New() + if(prob(50)) + icon_state = "stickyweb2" + +/obj/effect/spider/stickyweb/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group || (height==0)) return 1 + if(istype(mover, /mob/living/simple_animal/hostile/giant_spider)) + return 1 + else if(istype(mover, /mob/living)) + if(prob(50)) + to_chat(mover, "You get stuck in \the [src] for a moment.") + return 0 + else if(istype(mover, /obj/item/projectile)) + return prob(30) + return 1 + +/obj/effect/spider/eggcluster + name = "egg cluster" + desc = "They seem to pulse slightly with an inner life." + icon_state = "eggs" + var/amount_grown = 0 + +/obj/effect/spider/eggcluster/Initialize() + . = ..() + pixel_x = rand(3,-3) + pixel_y = rand(3,-3) + START_PROCESSING(SSobj, src) + +/obj/effect/spider/eggcluster/New(var/location, var/atom/parent) + get_light_and_color(parent) + ..() + +/obj/effect/spider/eggcluster/Destroy() + STOP_PROCESSING(SSobj, src) + if(istype(loc, /obj/item/organ/external)) + var/obj/item/organ/external/O = loc + O.implants -= src + . = ..() + +/obj/effect/spider/eggcluster/Process() + amount_grown += rand(0,2) + if(amount_grown >= 100) + var/num = rand(6,24) + var/obj/item/organ/external/O = null + if(istype(loc, /obj/item/organ/external)) + O = loc + + for(var/i=0, i 0) + disturbed() + +/obj/effect/spider/spiderling/Crossed(var/mob/living/L) + if(dormant && istype(L) && L.mob_size > MOB_TINY) + disturbed() + +/obj/effect/spider/spiderling/proc/disturbed() + if(!dormant) + return + dormant = FALSE + + GLOB.moved_event.unregister(src, src, /obj/effect/spider/spiderling/proc/disturbed) + START_PROCESSING(SSobj, src) + +/obj/effect/spider/spiderling/Bump(atom/user) + if(istype(user, /obj/structure/table)) + src.loc = user.loc + else + ..() + +/obj/effect/spider/spiderling/proc/die() + visible_message("[src] dies!") + new /obj/effect/decal/cleanable/spiderling_remains(loc) + qdel(src) + +/obj/effect/spider/spiderling/healthcheck() + if(health <= 0) + die() + +/obj/effect/spider/spiderling/Process() + if(travelling_in_vent) + if(istype(src.loc, /turf)) + travelling_in_vent = 0 + entry_vent = null + else if(entry_vent) + if(get_dist(src, entry_vent) <= 1) + if(entry_vent.network && entry_vent.network.normal_members.len) + var/list/vents = list() + for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in entry_vent.network.normal_members) + vents.Add(temp_vent) + if(!vents.len) + entry_vent = null + return + var/obj/machinery/atmospherics/unary/vent_pump/exit_vent = pick(vents) + /*if(prob(50)) + src.visible_message("[src] scrambles into the ventillation ducts!")*/ + + spawn(rand(20,60)) + loc = exit_vent + var/travel_time = round(get_dist(loc, exit_vent.loc) / 2) + spawn(travel_time) + + if(!exit_vent || exit_vent.welded) + loc = entry_vent + entry_vent = null + return + + if(prob(50)) + src.visible_message("You hear something squeezing through the ventilation ducts.",2) + sleep(travel_time) + + if(!exit_vent || exit_vent.welded) + loc = entry_vent + entry_vent = null + return + loc = exit_vent.loc + entry_vent = null + var/area/new_area = get_area(loc) + if(new_area) + new_area.Entered(src) + else + entry_vent = null + //================= + + if(isturf(loc)) + if(prob(25)) + var/list/nearby = trange(5, src) - loc + if(nearby.len) + var/target_atom = pick(nearby) + walk_to(src, target_atom, 5) + if(prob(25)) + src.visible_message("\The [src] skitters[pick(" away"," around","")].") + // Reduces the risk of spiderlings hanging out at the extreme ranges of the shift range. + var/min_x = pixel_x <= -shift_range ? 0 : -2 + var/max_x = pixel_x >= shift_range ? 0 : 2 + var/min_y = pixel_y <= -shift_range ? 0 : -2 + var/max_y = pixel_y >= shift_range ? 0 : 2 + + pixel_x = Clamp(pixel_x + rand(min_x, max_x), -shift_range, shift_range) + pixel_y = Clamp(pixel_y + rand(min_y, max_y), -shift_range, shift_range) + else if(prob(5)) + //vent crawl! + for(var/obj/machinery/atmospherics/unary/vent_pump/v in view(7,src)) + if(!v.welded) + entry_vent = v + walk_to(src, entry_vent, 5) + break + + if(amount_grown >= 100) + new greater_form(src.loc, src) + qdel(src) + else if(isorgan(loc)) + if(!amount_grown) amount_grown = 1 + var/obj/item/organ/external/O = loc + if(!O.owner || O.owner.stat == DEAD || amount_grown > 80) + amount_grown = 20 //reset amount_grown so that people have some time to react to spiderlings before they grow big + O.implants -= src + src.loc = O.owner ? O.owner.loc : O.loc + src.visible_message("\A [src] emerges from inside [O.owner ? "[O.owner]'s [O.name]" : "\the [O]"]!") + if(O.owner) + O.owner.apply_damage(1, BRUTE, O.organ_tag) + else if(prob(1)) + O.owner.apply_damage(1, TOX, O.organ_tag) + if(world.time > last_itch + 30 SECONDS) + last_itch = world.time + to_chat(O.owner, "Your [O.name] itches...") + else if(prob(1)) + src.visible_message("\The [src] skitters.") + + if(amount_grown > 0) + amount_grown += rand(0,2) + +/obj/effect/decal/cleanable/spiderling_remains + name = "spiderling remains" + desc = "Green squishy mess." + icon = 'icons/effects/effects.dmi' + icon_state = "greenshatter" + anchored = 1 + plane = ABOVE_TURF_PLANE + layer = BLOOD_LAYER + +/obj/effect/spider/cocoon + name = "cocoon" + desc = "Something wrapped in silky spider web." + icon_state = "cocoon1" + health = 60 + + New() + icon_state = pick("cocoon1","cocoon2","cocoon3") + +/obj/effect/spider/cocoon/Destroy() + src.visible_message("\The [src] splits open.") + for(var/atom/movable/A in contents) + A.dropInto(loc) + return ..() diff --git a/code/game/objects/effects/step_triggers.dm b/code/game/objects/effects/step_triggers.dm new file mode 100644 index 00000000..b48c21ed --- /dev/null +++ b/code/game/objects/effects/step_triggers.dm @@ -0,0 +1,113 @@ +/* Simple object type, calls a proc when "stepped" on by something */ + +/obj/effect/step_trigger + var/affect_ghosts = 0 + var/stopper = 1 // stops throwers + invisibility = 101 // nope cant see this shit + anchored = 1 + +/obj/effect/step_trigger/proc/Trigger(var/atom/movable/A) + return 0 + +/obj/effect/step_trigger/Crossed(H as mob|obj) + ..() + if(!H) + return + if(isobserver(H) && !(isghost(H) && affect_ghosts)) + return + Trigger(H) + + + +/* Tosses things in a certain direction */ + +/obj/effect/step_trigger/thrower + var/direction = SOUTH // the direction of throw + var/tiles = 3 // if 0: forever until atom hits a stopper + var/immobilize = 1 // if nonzero: prevents mobs from moving while they're being flung + var/speed = 1 // delay of movement + var/facedir = 0 // if 1: atom faces the direction of movement + var/nostop = 0 // if 1: will only be stopped by teleporters + var/list/affecting = list() + +/obj/effect/step_trigger/thrower/Trigger(var/atom/movable/AM) + if(!AM || !istype(AM) || !AM.simulated) + return + var/curtiles = 0 + var/stopthrow = 0 + for(var/obj/effect/step_trigger/thrower/T in orange(2, src)) + if(AM in T.affecting) + return + + if(ismob(AM)) + var/mob/M = AM + if(immobilize) + M.canmove = 0 + + affecting.Add(AM) + while(AM && !stopthrow) + if(tiles) + if(curtiles >= tiles) + break + if(AM.z != src.z) + break + + curtiles++ + + sleep(speed) + + // Calculate if we should stop the process + if(!nostop) + for(var/obj/effect/step_trigger/T in get_step(AM, direction)) + if(T.stopper && T != src) + stopthrow = 1 + else + for(var/obj/effect/step_trigger/teleporter/T in get_step(AM, direction)) + if(T.stopper) + stopthrow = 1 + + if(AM) + var/predir = AM.dir + step(AM, direction) + if(!facedir) + AM.set_dir(predir) + + + + affecting.Remove(AM) + + if(ismob(AM)) + var/mob/M = AM + if(immobilize) + M.canmove = 1 + +/* Stops things thrown by a thrower, doesn't do anything */ + +/obj/effect/step_trigger/stopper + +/* Instant teleporter */ + +/obj/effect/step_trigger/teleporter + var/teleport_x = 0 // teleportation coordinates (if one is null, then no teleport!) + var/teleport_y = 0 + var/teleport_z = 0 + + Trigger(var/atom/movable/A) + if(teleport_x && teleport_y && teleport_z) + + A.x = teleport_x + A.y = teleport_y + A.z = teleport_z + +/* Random teleporter, teleports atoms to locations ranging from teleport_x - teleport_x_offset, etc */ + +/obj/effect/step_trigger/teleporter/random + opacity = 1 + var/teleport_x_offset = 0 + var/teleport_y_offset = 0 + var/teleport_z_offset = 0 + +/obj/effect/step_trigger/teleporter/random/Trigger(var/atom/movable/A) + var/turf/T = locate(rand(teleport_x, teleport_x_offset), rand(teleport_y, teleport_y_offset), rand(teleport_z, teleport_z_offset)) + if(T) + A.forceMove(T) diff --git a/code/game/objects/empulse.dm b/code/game/objects/empulse.dm new file mode 100644 index 00000000..f88f6ef5 --- /dev/null +++ b/code/game/objects/empulse.dm @@ -0,0 +1,52 @@ +// Uncomment this define to check for possible lengthy processing of emp_act()s. +// If emp_act() takes more than defined deciseconds (1/10 seconds) an admin message and log is created. +// I do not recommend having this uncommented on main server, it probably causes a bit more lag, espicially with larger EMPs. + +// #define EMPDEBUG 10 + +proc/empulse(turf/epicenter, heavy_range, light_range, log=0) + if(!epicenter) return + + if(!istype(epicenter, /turf)) + epicenter = get_turf(epicenter.loc) + + if(log) + message_admins("EMP with size ([heavy_range], [light_range]) in area [epicenter.loc.name] ") + log_game("EMP with size ([heavy_range], [light_range]) in area [epicenter.loc.name] ") + + if(heavy_range > 1) + var/obj/effect/overlay/pulse = new/obj/effect/overlay(epicenter) + pulse.icon = 'icons/effects/effects.dmi' + pulse.icon_state = "emppulse" + pulse.SetName("emp pulse") + pulse.anchored = 1 + spawn(20) + qdel(pulse) + + if(heavy_range > light_range) + light_range = heavy_range + + for(var/mob/M in range(heavy_range, epicenter)) + sound_to(M, 'sound/effects/EMPulse.ogg') + + for(var/atom/T in range(light_range, epicenter)) + #ifdef EMPDEBUG + var/time = world.timeofday + #endif + var/distance = get_dist(epicenter, T) + if(distance < 0) + distance = 0 + if(distance < heavy_range) + T.emp_act(1) + else if(distance == heavy_range) + if(prob(50)) + T.emp_act(1) + else + T.emp_act(2) + else if(distance <= light_range) + T.emp_act(2) + #ifdef EMPDEBUG + if((world.timeofday - time) >= EMPDEBUG) + log_and_message_admins("EMPDEBUG: [T.name] - [T.type] - took [world.timeofday - time]ds to process emp_act()!") + #endif + return 1 \ No newline at end of file diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm new file mode 100644 index 00000000..845ee138 --- /dev/null +++ b/code/game/objects/explosion.dm @@ -0,0 +1,154 @@ +//TODO: Flash range does nothing currently + +proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = 1, z_transfer = UP|DOWN, shaped) + var/multi_z_scalar = 0.35 + src = null //so we don't abort once src is deleted + spawn(0) + var/start = world.timeofday + epicenter = get_turf(epicenter) + if(!epicenter) return + + // Handles recursive propagation of explosions. + if(z_transfer) + var/adj_dev = max(0, (multi_z_scalar * devastation_range) - (shaped ? 2 : 0) ) + var/adj_heavy = max(0, (multi_z_scalar * heavy_impact_range) - (shaped ? 2 : 0) ) + var/adj_light = max(0, (multi_z_scalar * light_impact_range) - (shaped ? 2 : 0) ) + var/adj_flash = max(0, (multi_z_scalar * flash_range) - (shaped ? 2 : 0) ) + + + if(adj_dev > 0 || adj_heavy > 0) + if(HasAbove(epicenter.z) && z_transfer & UP) + explosion(GetAbove(epicenter), round(adj_dev), round(adj_heavy), round(adj_light), round(adj_flash), 0, UP, shaped) + if(HasBelow(epicenter.z) && z_transfer & DOWN) + explosion(GetBelow(epicenter), round(adj_dev), round(adj_heavy), round(adj_light), round(adj_flash), 0, DOWN, shaped) + + var/max_range = max(devastation_range, heavy_impact_range, light_impact_range, flash_range) + + // Play sounds; we want sounds to be different depending on distance so we will manually do it ourselves. + // Stereo users will also hear the direction of the explosion! + // Calculate far explosion sound range. Only allow the sound effect for heavy/devastating explosions. + // 3/7/14 will calculate to 80 + 35 + var/far_dist = 0 + far_dist += heavy_impact_range * 5 + far_dist += devastation_range * 20 + var/frequency = get_rand_frequency() + for(var/mob/M in GLOB.player_list) + if(M.z == epicenter.z) + var/turf/M_turf = get_turf(M) + var/dist = get_dist(M_turf, epicenter) + // If inside the blast radius + world.view - 2 + //if(dist <= round(max_range + world.view - 2, 1)) + playsound(epicenter, get_sfx("explosion"), 100, 0) // get_sfx() is so that everyone gets the same sound + if(dist <= far_dist) + var/far_volume = Clamp(far_dist, 30, 50) // Volume is based on explosion size and dist + far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion + M.playsound_local(epicenter, 'sound/effects/explosionfar.ogg', far_volume, 1, frequency, falloff = 5) + + if(adminlog) + message_admins("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range]) in area [epicenter.loc.name] ([epicenter.x],[epicenter.y],[epicenter.z]) (JMP)") + log_game("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range]) in area [epicenter.loc.name] ") + + var/approximate_intensity = (devastation_range * 3) + (heavy_impact_range * 2) + light_impact_range + // Large enough explosion. For performance reasons, powernets will be rebuilt manually + if(!defer_powernet_rebuild && (approximate_intensity > 25)) + defer_powernet_rebuild = 1 + + if(heavy_impact_range > 1) + var/datum/effect/system/explosion/E = new/datum/effect/system/explosion() + E.set_up(epicenter) + E.start() + + var/x0 = epicenter.x + var/y0 = epicenter.y + var/z0 = epicenter.z + if(config.use_recursive_explosions) + var/power = devastation_range * 2 + heavy_impact_range + light_impact_range //The ranges add up, ie light 14 includes both heavy 7 and devestation 3. So this calculation means devestation counts for 4, heavy for 2 and light for 1 power, giving us a cap of 27 power. + explosion_rec(epicenter, power, shaped) + else + for(var/turf/T in trange(max_range, epicenter)) + var/dist = sqrt((T.x - x0)**2 + (T.y - y0)**2) + + if(dist < devastation_range) dist = 1 + else if(dist < heavy_impact_range) dist = 2 + else if(dist < light_impact_range) dist = 3 + else continue + + T.ex_act(dist) + if(!T) + T = locate(x0,y0,z0) + for(var/atom_movable in T.contents) //bypass type checking since only atom/movable can be contained by turfs anyway + var/atom/movable/AM = atom_movable + if(AM && AM.simulated && !T.protects_atom(AM)) + AM.ex_act(dist) + + var/took = (world.timeofday-start)/10 + //You need to press the DebugGame verb to see these now....they were getting annoying and we've collected a fair bit of data. Just -test- changes to explosion code using this please so we can compare + if(Debug2) world.log << "## DEBUG: Explosion([x0],[y0],[z0])(d[devastation_range],h[heavy_impact_range],l[light_impact_range]): Took [took] seconds." + + sleep(8) + + return 1 + + + +proc/secondaryexplosion(turf/epicenter, range) + for(var/turf/tile in range(range, epicenter)) + tile.ex_act(2) + + +proc/drop_mortar(turf/dropped, mortar) + var/direction = pick(GLOB.cardinal) + var/turf/dropped_turf = get_step(dropped,direction) + playsound(dropped_turf, 'sound/effects/bomb.ogg', 100, FALSE) + var/obj/effect/shadow/S = new(dropped_turf)//Create a cool shadow effect for the bomb. + spawn(40) + qdel(S) + if(mortar == "rflare") //They don't hit the ground. + new /obj/mortar/flare(dropped_turf) + return + if(mortar == "bflare") + new /obj/mortar/flare/blue(dropped_turf) + return + explosion(dropped_turf, 1, 1, 1, 1) + if(mortar == "shrapnel") + new /obj/mortar/frag(dropped_turf) + if(mortar == "gas") + new /obj/mortar/gas(dropped_turf) + if(mortar == "fire") + new /obj/mortar/fire(dropped_turf) + +/obj/effect/shadow + name = "Shadow" + icon = 'icons/effects/effects.dmi' + icon_state = "target" + density = FALSE + + +/*============== +ARTILLERY BARAGE +==============*/ +//only works on no man land z level (2) +//checks for valid spot within range. +proc/artillery_barage(var/x, var/y) + + var/x_random = x + var/y_random = y + var/sleep_randomizer = 10 + var/turf/turf_to_drop + + for(var/i = 1, i< 10, i++)//value may need to tweak + x_random = x + (rand(0, 6) -3 ) + y_random = y + (rand(0, 6) -3 ) + //randomize sleep time to get more dynamic artillery + sleep_randomizer = rand(8, 25) + turf_to_drop = locate(x_random, y_random, 2) + if(istype(turf_to_drop.loc, /area/warfare/battlefield/no_mans_land) || istype(turf_to_drop.loc, /area/warfare/battlefield/capture_point/mid)) + drop_mortar(turf_to_drop, "shrapnel") + else + //if we fail to find a valid place just drop on the target + world.log << "Invalid landing zone. [x_random], [y_random]... defaulting to original position." + turf_to_drop = locate(x,y,2) + drop_mortar(turf_to_drop, "shrapnel") + + + sleep(sleep_randomizer) diff --git a/code/game/objects/explosion_recursive.dm b/code/game/objects/explosion_recursive.dm new file mode 100644 index 00000000..c45d50ca --- /dev/null +++ b/code/game/objects/explosion_recursive.dm @@ -0,0 +1,138 @@ + + + + +var/list/explosion_turfs = list() + +var/explosion_in_progress = 0 + + +proc/explosion_rec(turf/epicenter, power, shaped) + var/loopbreak = 0 + while(explosion_in_progress) + if(loopbreak >= 15) return + sleep(10) + loopbreak++ + + if(power <= 0) return + epicenter = get_turf(epicenter) + if(!epicenter) return + + explosion_in_progress = 1 + explosion_turfs = list() + + explosion_turfs[epicenter] = power + + //This steap handles the gathering of turfs which will be ex_act() -ed in the next step. It also ensures each turf gets the maximum possible amount of power dealt to it. + for(var/direction in GLOB.cardinal) + var/turf/T = get_step(epicenter, direction) + var/adj_power = power - epicenter.get_explosion_resistance() + if(shaped) + if (shaped == direction) + adj_power *= 3 + else if (shaped == reverse_direction(direction)) + adj_power *= 0.10 + else + adj_power *= 0.45 + + T.explosion_spread(adj_power, direction) + + //This step applies the ex_act effects for the explosion, as planned in the previous step. + for(var/spot in explosion_turfs) + var/turf/T = spot + if(explosion_turfs[T] <= 0) continue + if(!T) continue + + //Wow severity looks confusing to calculate... Fret not, I didn't leave you with any additional instructions or help. (just kidding, see the line under the calculation) + var/severity = 4 - round(max(min( 3, ((explosion_turfs[T] - T.get_explosion_resistance()) / (max(3,(power/3)))) ) ,1), 1) //sanity effective power on tile divided by either 3 or one third the total explosion power + // One third because there are three power levels and I + // want each one to take up a third of the crater + var/x = T.x + var/y = T.y + var/z = T.z + T.ex_act(severity) + if(!T) + T = locate(x,y,z) + + var/throw_target = get_edge_target_turf(T, get_dir(epicenter,T)) + for(var/atom_movable in T.contents) + var/atom/movable/AM = atom_movable + if(AM && AM.simulated && !T.protects_atom(AM)) + AM.ex_act(severity) + if(!AM.anchored) + addtimer(CALLBACK(AM, /atom/movable/.proc/throw_at, throw_target, 9/severity, 9/severity), 0) + + explosion_turfs.Cut() + explosion_in_progress = 0 + + +//Code-wise, a safe value for power is something up to ~25 or ~30.. This does quite a bit of damage to the station. +//direction is the direction that the spread took to come to this tile. So it is pointing in the main blast direction - meaning where this tile should spread most of it's force. +/turf/proc/explosion_spread(power, direction) + if(power <= 0) + return + + if(explosion_turfs[src] >= power) + return //The turf already sustained and spread a power greated than what we are dealing with. No point spreading again. + explosion_turfs[src] = power +/* + sleep(2) + var/obj/effect/debugging/M = locate() in src + if (!M) + M = new(src, power, direction) + M.maptext = "[power] vs [src.get_explosion_resistance()]" + if(power > 10) + M.color = "#cccc00" + if(power > 20) + M.color = "#ffcc00" +*/ + var/spread_power = power - src.get_explosion_resistance() //This is the amount of power that will be spread to the tile in the direction of the blast + + var/turf/T = get_step(src, direction) + if(T) + T.explosion_spread(spread_power, direction) + T = get_step(src, turn(direction,90)) + if(T) + T.explosion_spread(spread_power, turn(direction,90)) + T = get_step(src, turn(direction,-90)) + if(T) + T.explosion_spread(spread_power, turn(direction,90)) + +/turf/unsimulated/explosion_spread(power) + return //So it doesn't get to the parent proc, which simulates explosions + +/atom/var/explosion_resistance +/atom/proc/get_explosion_resistance() + if(simulated) + return explosion_resistance + +/turf/get_explosion_resistance() + . = ..() + for(var/obj/O in src) + . += O.get_explosion_resistance() + +/turf/space + explosion_resistance = 3 + +/turf/simulated/floor/get_explosion_resistance() + . = ..() + if(is_below_sound_pressure(src)) + . *= 3 + +/turf/simulated/floor + explosion_resistance = 1 + +/turf/simulated/mineral + explosion_resistance = 2 + +/turf/simulated/shuttle/wall + explosion_resistance = 10 + +/turf/simulated/wall + explosion_resistance = 10 + +/obj/machinery/door/get_explosion_resistance() + if(!density) + return 0 + else + return ..() \ No newline at end of file diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm new file mode 100644 index 00000000..0057068a --- /dev/null +++ b/code/game/objects/items.dm @@ -0,0 +1,963 @@ +/obj/item + name = "item" + icon = 'icons/obj/items.dmi' + w_class = ITEM_SIZE_NORMAL + mouse_drag_pointer = MOUSE_ACTIVE_POINTER + layer = BASE_OBJ_LAYER + + var/image/blood_overlay = null //this saves our blood splatter overlay, which will be processed not to go over the edges of the sprite + var/randpixel = 6 + var/r_speed = 1.0 + var/health = null + var/burn_point = null + var/burning = null + var/hitsound = null + var/equipsound = null + var/str_requirement = 0 + var/slot_flags = 0 //This is used to determine on which slots an item can fit. + var/no_attack_log = 0 //If it's an item we don't want to log attack_logs with, set this to 1 + pass_flags = PASS_FLAG_TABLE +// causeerrorheresoifixthis + var/obj/item/master = null + var/list/origin_tech = null //Used by R&D to determine what research bonuses it grants. + var/list/attack_verb = list("hit") //Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]" + var/lock_picking_level = 0 //used to determine whether something can pick a lock, and how well. + var/force = 0 + + var/heat_protection = 0 //flags which determine which body parts are protected from heat. Use the HEAD, UPPER_TORSO, LOWER_TORSO, etc. flags. See setup.dm + var/cold_protection = 0 //flags which determine which body parts are protected from cold. Use the HEAD, UPPER_TORSO, LOWER_TORSO, etc. flags. See setup.dm + var/max_heat_protection_temperature //Set this variable to determine up to which temperature (IN KELVIN) the item protects against heat damage. Keep at null to disable protection. Only protects areas set by heat_protection flags + var/min_cold_protection_temperature //Set this variable to determine down to which temperature (IN KELVIN) the item protects against cold damage. 0 is NOT an acceptable number due to if(varname) tests!! Keep at null to disable protection. Only protects areas set by cold_protection flags + + var/datum/action/item_action/action = null + var/action_button_name //It is also the text which gets displayed on the action button. If not set it defaults to 'Use [name]'. If it's not set, there'll be no button. + var/action_button_is_hands_free = 0 //If 1, bypass the restrained, lying, and stunned checks action buttons normally test for + + //This flag is used to determine when items in someone's inventory cover others. IE helmets making it so you can't see glasses, etc. + //It should be used purely for appearance. For gameplay effects caused by items covering body parts, use body_parts_covered. + var/flags_inv = 0 + var/body_parts_covered = 0 //see setup.dm for appropriate bit flags + + var/item_flags = 0 //Miscellaneous flags pertaining to equippable objects. + + //var/heat_transfer_coefficient = 1 //0 prevents all transfers, 1 is invisible + var/gas_transfer_coefficient = 1 // for leaking gas from turf to mask and vice-versa (for masks right now, but at some point, i'd like to include space helmets) + var/permeability_coefficient = 1 // for chemicals/diseases + var/siemens_coefficient = 1 // for electrical admittance/conductance (electrocution checks and shit) + var/slowdown_general = 0 // How much clothing is slowing you down. Negative values speeds you up. This is a genera##l slowdown, no matter equipment slot. + var/slowdown_per_slot[slot_last] // How much clothing is slowing you down. This is an associative list: item slot - slowdown + var/slowdown_accessory // How much an accessory will slow you down when attached to a worn article of clothing. + var/canremove = 1 //Mostly for Ninja code at this point but basically will not allow the item to be removed if set to 0. /N + var/list/armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + var/list/allowed = null //suit storage stuff. + var/obj/item/device/uplink/hidden_uplink = null // All items can have an uplink hidden inside, just remember to add the triggers. + var/zoomdevicename = null //name used for message when binoculars/scope is used + var/zoom = 0 //1 if item is actively being used to zoom. For scoped guns and binoculars. + + var/icon_override = null //Used to override hardcoded clothing dmis in human clothing proc. + + var/use_alt_layer = FALSE // Use the slot's alternative layer when rendering on a mob + + //** These specify item/icon overrides for _slots_ + + var/list/item_state_slots = list(slot_wear_id_str = "id") //overrides the default item_state for particular slots. + + // Used to specify the icon file to be used when the item is worn. If not set the default icon for that slot will be used. + // If icon_override or sprite_sheets are set they will take precendence over this, assuming they apply to the slot in question. + // Only slot_l_hand/slot_r_hand are implemented at the moment. Others to be implemented as needed. + var/list/item_icons + + //** These specify item/icon overrides for _species_ + + /* Species-specific sprites, concept stolen from Paradise//vg/. + ex: + sprite_sheets = list( + SPECIES_TAJARA = 'icons/cat/are/bad' + ) + If index term exists and icon_override is not set, this sprite sheet will be used. + */ + var/list/sprite_sheets = list() + + // Species-specific sprite sheets for inventory sprites + // Works similarly to worn sprite_sheets, except the alternate sprites are used when the clothing/refit_for_species() proc is called. + var/list/sprite_sheets_obj = list() + + var/sharpness = 0 //This is a special snowflake var that lets us cut peoples' heads off. + var/block_chance = 0 //This is the chance in percent that we will be able to block an attack with this weapon. + var/list/parry_sounds = list() //List of parry sounds to play when we block. + + var/next_attack_time = 0 + var/weapon_speed_delay = 15 + var/drop_sound = 'sound/items/handle/generic_drop1.ogg' + var/swing_sound = null + var/grab_sound = null + var/grab_sound_is_loud = FALSE + var/wielded = 0 + var/wieldsound = 'sound/weapons/thudswoosh.ogg' + var/unwieldsound = null + var/wielded_icon = null + var/force_unwielded = 0 + var/force_wielded = 0 + + var/table_pickup_sound = null //Sound it makes when you take something off a table. + + +/obj/item/New() + ..() + if(!swing_sound) + if(sharp || edge) + swing_sound = "swing_sound" + else + swing_sound = "blunt_swing" + if(randpixel && (!pixel_x && !pixel_y) && isturf(loc)) //hopefully this will prevent us from messing with mapper-set pixel_x/y + pixel_x = rand(-randpixel, randpixel) + pixel_y = rand(-randpixel, randpixel) + +/obj/item/Destroy() + qdel(hidden_uplink) + hidden_uplink = null + if(ismob(loc)) + var/mob/m = loc + m.drop_from_inventory(src) + m.update_inv_r_hand() + m.update_inv_l_hand() + src.loc = null + return ..() + +/obj/item/device + icon = 'icons/obj/device.dmi' + +/mob/verb/wield_hotkey()//For the hotkeys. + set name = ".wield" + do_wield() + +/mob/verb/toggle_gun_safety() + set name = ".toggle_safety" + set hidden = TRUE + var/obj/item/I = get_active_hand() + if(!I) + return + if(istype(I, /obj/item/weapon/gun)) + var/obj/item/weapon/gun/G = I + G.toggle_safety(src) + +/mob/proc/do_wield()//The proc we actually care about. + if(!isliving(src))//So ghosts can't do this. + return + var/obj/item/I = get_active_hand() + if(!I) + return + I.attempt_wield(src) + +/obj/item/proc/unwield(mob/user) + if(!wielded || !user) + return + wielded = 0 + if(force_unwielded) + force = force_unwielded + else + force = (force / 1.5) + var/sf = findtext(name," (Wielded)") + if(sf) + name = copytext(name,1,sf) + else //something wrong + name = "[initial(name)]" + update_unwield_icon() + update_icon() + if(user) + user.update_inv_r_hand() + user.update_inv_l_hand() + + user.visible_message("[user] lets go of their other hand.") + if(unwieldsound) + playsound(loc, unwieldsound, 50, 1) + var/obj/item/weapon/twohanded/offhand/O = user.get_inactive_hand() + if(O && istype(O)) + user.drop_from_inventory(O) + return + +/obj/item/proc/wield(mob/user) + if(wielded) + return + if(!is_held_twohanded(user)) + return + if(user.get_inactive_hand()) + to_chat(user, "You need your other hand to be empty!") + return + wielded = 1 + if(force_wielded) + force = force_wielded + else + force = (force * 1.5) + name = "wielded [name]" + update_wield_icon() + update_icon()//Legacy + if(user) + user.update_inv_r_hand() + user.update_inv_l_hand() + user.visible_message("[user] grabs the [initial(name)] with both hands.") + if(wieldsound) + playsound(loc, wieldsound, 50, 1) + var/obj/item/weapon/twohanded/offhand/O = new(user) ////Let's reserve his other hand~ + O.name = "[name] - offhand" + O.desc = "Your second grip on the [name]" + O.weight = 0 + user.put_in_inactive_hand(O) + return + +/obj/item/proc/update_wield_icon() + if(wielded && wielded_icon) + item_state = wielded_icon + +/obj/item/proc/update_unwield_icon()//That way it doesn't interupt any other special icon_states. + if(wielded && wielded_icon) + item_state = "[initial(item_state)]" + +//For general weapons. +/obj/item/proc/attempt_wield(mob/user) + if(wielded) //Trying to unwield it + unwield(user) + else //Trying to wield it + wield(user) + +//Checks if the item is being held by a mob, and if so, updates the held icons +/obj/item/proc/update_twohanding() + update_held_icon() + +/obj/item/proc/update_held_icon() + if(ismob(src.loc)) + var/mob/M = src.loc + if(M.l_hand == src) + M.update_inv_l_hand() + else if(M.r_hand == src) + M.update_inv_r_hand() + +/obj/item/proc/is_held_twohanded(mob/living/M) + var/check_hand + if(M.l_hand == src && !M.r_hand) + check_hand = BP_R_HAND //item in left hand, check right hand + else if(M.r_hand == src && !M.l_hand) + check_hand = BP_L_HAND //item in right hand, check left hand + else + return FALSE + + //would check is_broken() and is_malfunctioning() here too but is_malfunctioning() + //is probabilistic so we can't do that and it would be unfair to just check one. + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/hand = H.organs_by_name[check_hand] + if(istype(hand) && hand.is_usable()) + return TRUE + return FALSE + + +/obj/item/weapon/twohanded/offhand + name = "offhand" + icon_state = "offhand" + w_class = ITEM_SIZE_NO_CONTAINER + atom_flags = ATOM_FLAG_NO_BLOOD//ABSTRACT | NOBLOODY + item_flags = ITEM_FLAG_ABSTRACT + + +/obj/item/weapon/twohanded/offhand/RightClick(mob/user) + var/obj/item/I = user.get_active_hand() + var/obj/item/II = user.get_inactive_hand() + if(I) + I.unwield(user) + if(II) + II.unwield(user) + + loc = null + if(!QDELETED(src)) + qdel(src) + + +/obj/item/weapon/twohanded/offhand/unwield() + //if(wielded)//Only delete if we're wielded + wielded = FALSE + loc = null + if(!QDELETED(src)) + qdel(src) + +/obj/item/weapon/twohanded/offhand/wield() + if(wielded)//Only delete if we're wielded + wielded = FALSE + loc = null + if(!QDELETED(src)) + qdel(src) + +/obj/item/weapon/twohanded/offhand/dropped(mob/user) + ..() + var/obj/item/I = user.get_active_hand() + var/obj/item/II = user.get_inactive_hand() + if(I) + I.unwield(user) + if(II) + II.unwield(user) + loc = null + if(!QDELETED(src)) + qdel(src) + + +/obj/item/ex_act(severity) + switch(severity) + if(1) + qdel(src) + if(2) + if (prob(50)) + qdel(src) + if(3) + if (prob(5)) + qdel(src) + +/obj/item/proc/move_to_top() + set name = "Move To Top" + set category = "Object" + set src in oview(1) + + if(!istype(src.loc, /turf) || usr.stat || usr.restrained() ) + return + + var/turf/T = src.loc + + src.loc = null + + src.loc = T + +/obj/item/examine(mob/user, var/distance = -1) + var/size + switch(src.w_class) + if(ITEM_SIZE_TINY) + size = "tiny" + if(ITEM_SIZE_SMALL) + size = "small" + if(ITEM_SIZE_NORMAL) + size = "normal-sized" + if(ITEM_SIZE_LARGE) + size = "large" + if(ITEM_SIZE_HUGE) + size = "bulky" + if(ITEM_SIZE_HUGE + 1 to INFINITY) + size = "huge" + return ..(user, distance, "", "It is a [size] item.") + +/obj/item/attack_hand(mob/user as mob) + if (!user) return + if (hasorgans(user)) + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/temp = H.organs_by_name[BP_R_HAND] + if (user.hand) + temp = H.organs_by_name[BP_L_HAND] + if(temp && !temp.is_usable() || temp && temp.status & ORGAN_BROKEN) + to_chat(user, "You try to move your [temp.name], but cannot!") + return + if(!temp) + to_chat(user, "You try to use your hand, but realize it is no longer attached!") + return + src.pickup(user) + if (istype(src.loc, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = src.loc + S.remove_from_storage(src) + + src.throwing = 0 + if (src.loc == user) + if(!user.unEquip(src)) + return + else + if(isliving(src.loc)) + return + if(user.put_in_active_hand(src)) + if(randpixel) + pixel_x = rand(-randpixel, randpixel) + pixel_y = rand(-randpixel/2, randpixel/2) + pixel_z = 0 + else if(randpixel == 0) + pixel_x = 0 + pixel_y = 0 + return + +/obj/item/attack_ai(mob/user as mob) + if (istype(src.loc, /obj/item/weapon/robot_module)) + //If the item is part of a cyborg module, equip it + if(!isrobot(user)) + return + var/mob/living/silicon/robot/R = user + R.activate_module(src) + R.hud_used.update_robot_modules_display() + +/obj/item/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = W + if(S.use_to_pickup) + if(S.collection_mode) //Mode is set to collect all items + if(isturf(src.loc)) + S.gather_all(src.loc, user) + else if(S.can_be_inserted(src, user)) + S.handle_item_insertion(src) + +/obj/item/proc/talk_into(mob/M as mob, text) + return + +/obj/item/proc/moved(mob/user as mob, old_loc as turf) + return + +// apparently called whenever an item is removed from a slot, container, or anything else. +/obj/item/proc/dropped(mob/user as mob) + if(randpixel) + pixel_z = randpixel //an idea borrowed from some of the older pixel_y randomizations. Intended to make items appear to drop at a character + if(zoom) + zoom(user) //binoculars, scope, etc + if(wielded) + unwield(user) + + update_twohanding() + if(user) + if(user.l_hand) + user.l_hand.update_twohanding() + if(user.r_hand) + user.r_hand.update_twohanding() + + +// called just as an item is picked up (loc is not yet changed) +/obj/item/proc/pickup(mob/user) + if(locate(/obj/structure/table) in loc) + if(table_pickup_sound) + playsound(src, table_pickup_sound, 50) + return + +// called when this item is removed from a storage item, which is passed on as S. The loc variable is already set to the new destination before this is called. +/obj/item/proc/on_exit_storage(obj/item/weapon/storage/S as obj) + return + +// called when this item is added into a storage item, which is passed on as S. The loc variable is already set to the storage item. +/obj/item/proc/on_enter_storage(obj/item/weapon/storage/S as obj) + return + +// called when "found" in pockets and storage items. Returns 1 if the search should end. +/obj/item/proc/on_found(mob/finder as mob) + return + +/obj/item/proc/mill() + return + +/obj/item/proc/press() + return + + +// called after an item is placed in an equipment slot +// user is mob that equipped it +// slot uses the slot_X defines found in setup.dm +// for items that can be placed in multiple slots +// note this isn't called during the initial dressing of a player +/obj/item/proc/equipped(var/mob/user, var/slot) + hud_layerise() + if(user.client) user.client.screen |= src + if(user.pulling == src) user.stop_pulling() + + //Update two-handing status + var/mob/M = loc + if(!istype(M)) + return + if(M.l_hand) + M.l_hand.update_twohanding() + if(M.r_hand) + M.r_hand.update_twohanding() + + if(wielded) + unwield(user) + + + +//Defines which slots correspond to which slot flags +var/list/global/slot_flags_enumeration = list( + "[slot_wear_mask]" = SLOT_MASK, + "[slot_back]" = SLOT_BACK, + "[slot_wear_suit]" = SLOT_OCLOTHING, + "[slot_gloves]" = SLOT_GLOVES, + "[slot_shoes]" = SLOT_FEET, + "[slot_belt]" = SLOT_BELT, + "[slot_glasses]" = SLOT_EYES, + "[slot_head]" = SLOT_HEAD, + "[slot_l_ear]" = SLOT_EARS|SLOT_TWOEARS, + "[slot_r_ear]" = SLOT_EARS|SLOT_TWOEARS, + "[slot_w_uniform]" = SLOT_ICLOTHING, + "[slot_wear_id]" = SLOT_ID, + "[slot_tie]" = SLOT_TIE, + "[slot_s_store]" = SLOT_S_STORE + ) + +//the mob M is attempting to equip this item into the slot passed through as 'slot'. Return 1 if it can do this and 0 if it can't. +//If you are making custom procs but would like to retain partial or complete functionality of this one, include a 'return ..()' to where you want this to happen. +//Set disable_warning to 1 if you wish it to not give you outputs. +//Should probably move the bulk of this into mob code some time, as most of it is related to the definition of slots and not item-specific +//set force to ignore blocking overwear and occupied slots +/obj/item/proc/mob_can_equip(M as mob, slot, disable_warning = 0, force = 0) + if(!slot) return 0 + if(!M) return 0 + + if(!ishuman(M)) return 0 + + var/mob/living/carbon/human/H = M + var/list/mob_equip = list() + if(H.species.hud && H.species.hud.equip_slots) + mob_equip = H.species.hud.equip_slots + + if(H.species && !(slot in mob_equip)) + return 0 + + //First check if the item can be equipped to the desired slot. + if("[slot]" in slot_flags_enumeration) + var/req_flags = slot_flags_enumeration["[slot]"] + if(!(req_flags & slot_flags)) + return 0 + + if(!force) + //Next check that the slot is free + if(H.get_equipped_item(slot)) + return 0 + + //Next check if the slot is accessible. + var/mob/_user = disable_warning? null : H + if(!H.slot_is_accessible(slot, src, _user)) + return 0 + + //Lastly, check special rules for the desired slot. + switch(slot) + if(slot_l_ear, slot_r_ear) + var/slot_other_ear = (slot == slot_l_ear)? slot_r_ear : slot_l_ear + if( (w_class > ITEM_SIZE_TINY) && !(slot_flags & SLOT_EARS) ) + return 0 + if( (slot_flags & SLOT_TWOEARS) && H.get_equipped_item(slot_other_ear) ) + return 0 + if(slot_belt) + if(!H.w_uniform && (slot_w_uniform in mob_equip)) + if(!disable_warning) + to_chat(H, "You need a jumpsuit before you can attach this [name].") + return 0 + if(slot_l_store, slot_r_store) + if(!H.w_uniform && (slot_w_uniform in mob_equip)) + if(!disable_warning) + to_chat(H, "You need a jumpsuit before you can attach this [name].") + return 0 + if(slot_flags & SLOT_DENYPOCKET) + return 0 + if( w_class > ITEM_SIZE_SMALL && !(slot_flags & SLOT_POCKET) ) + return 0 + if(get_storage_cost() == ITEM_SIZE_NO_CONTAINER) + return 0 //pockets act like storage and should respect ITEM_SIZE_NO_CONTAINER. Suit storage might be fine as is + /* + if(slot_s_store) + if(!H.wear_suit && (slot_wear_suit in mob_equip)) + if(!disable_warning) + to_chat(H, "You need a suit before you can attach this [name].") + return 0 + if(!H.wear_suit.allowed) + if(!disable_warning) + to_chat(usr, "You somehow have a suit with no defined allowed items for suit storage, stop that.") + return 0 + if( !(istype(src, /obj/item/device/pda) || istype(src, /obj/item/weapon/pen) || is_type_in_list(src, H.wear_suit.allowed)) ) + return 0 + */ + if(slot_handcuffed) + if(!istype(src, /obj/item/weapon/handcuffs)) + return 0 + if(slot_in_backpack) //used entirely for equipping spawned mobs or at round start + var/allow = 0 + if(H.back && istype(H.back, /obj/item/weapon/storage/backpack)) + var/obj/item/weapon/storage/backpack/B = H.back + if(B.can_be_inserted(src,M,1)) + allow = 1 + if(!allow) + return 0 + return 1 + +/obj/item/proc/mob_can_unequip(mob/M, slot, disable_warning = 0) + if(!slot) return 0 + if(!M) return 0 + + if(!canremove) + return 0 + if(!M.slot_is_accessible(slot, src, disable_warning? null : M)) + return 0 + return 1 + +/obj/item/proc/verb_pickup() + set src in oview(1) + set category = "Object" + set name = "Pick up" + + if(!(usr)) //BS12 EDIT + return + if(usr.incapacitated(INCAPACITATION_STUNNED) || usr.incapacitated(INCAPACITATION_KNOCKOUT) || usr.stat || usr.restrained() || !Adjacent(usr))//!usr.canmove + return //If they're stunned, or knocked out, then they can't pick shit up. But if they're just lying down they can. + if((!istype(usr, /mob/living/carbon)) || (istype(usr, /mob/living/carbon/brain)))//Is humanoid, and is not a brain + to_chat(usr, "You can't pick things up!") + return + if( usr.stat || usr.restrained() )//Is not asleep/dead and is not restrained + to_chat(usr, "You can't pick things up!") + return + if(src.anchored) //Object isn't anchored + to_chat(usr, "You can't pick that up!") + return + if(!usr.hand && usr.r_hand) //Right hand is not full + to_chat(usr, "Your right hand is full.") + return + if(usr.hand && usr.l_hand) //Left hand is not full + to_chat(usr, "Your left hand is full.") + return + if(!istype(src.loc, /turf)) //Object is on a turf + to_chat(usr, "You can't pick that up!") + return + //All checks are done, time to pick it up! + usr.UnarmedAttack(src) + return + + +//This proc is executed when someone clicks the on-screen UI button. To make the UI button show, set the 'icon_action_button' to the icon_state of the image of the button in screen1_action.dmi +//The default action is attack_self(). +//Checks before we get to here are: mob is alive, mob is not restrained, paralyzed, asleep, laying, item is on the mob. +/obj/item/proc/ui_action_click() + attack_self(usr) + +//RETURN VALUES +//handle_shield should return a positive value to indicate that the attack is blocked and should be prevented. +//If a negative value is returned, it should be treated as a special return value for bullet_act() and handled appropriately. +//For non-projectile attacks this usually means the attack is blocked. +//Otherwise should return 0 to indicate that the attack is not affected in any way. +/obj/item/proc/handle_shield(mob/living/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + return 0 + +/obj/item/proc/get_loc_turf() + var/atom/L = loc + while(L && !istype(L, /turf/)) + L = L.loc + return loc + +/obj/item/proc/eyestab(mob/living/carbon/M as mob, mob/living/carbon/user as mob) + + var/mob/living/carbon/human/H = M + if(istype(H)) + for(var/obj/item/protection in list(H.head, H.wear_mask, H.glasses)) + if(protection && (protection.body_parts_covered & EYES)) + // you can't stab someone in the eyes wearing a mask! + to_chat(user, "You're going to need to remove the eye covering first.") + return + + if(!M.has_eyes()) + to_chat(user, "You cannot locate any eyes on [M]!") + return + + admin_attack_log(user, M, "Attacked using \a [src]", "Was attacked with \a [src]", "used \a [src] to attack") + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(M) + + src.add_fingerprint(user) + //if((CLUMSY in user.mutations) && prob(50)) + // M = user + /* + to_chat(M, "You stab yourself in the eye.") + M.sdisabilities |= BLIND + M.weakened += 4 + M.adjustBruteLoss(10) + */ + + if(istype(H)) + + var/obj/item/organ/internal/eyes/eyes = H.internal_organs_by_name[BP_EYES] + + if(H != user) + for(var/mob/O in (viewers(M) - user - M)) + O.show_message("[M] has been stabbed in the eye with [src] by [user].", 1) + to_chat(M, "[user] stabs you in the eye with [src]!") + to_chat(user, "You stab [M] in the eye with [src]!") + else + user.visible_message( \ + "[user] has stabbed themself with [src]!", \ + "You stab yourself in the eyes with [src]!" \ + ) + + eyes.damage += rand(3,4) + if(eyes.damage >= eyes.min_bruised_damage) + if(M.stat != 2) + if(eyes.robotic < ORGAN_ROBOT) //robot eyes bleeding might be a bit silly + to_chat(M, "Your eyes start to bleed profusely!") + if(prob(50)) + if(M.stat != 2) + to_chat(M, "You drop what you're holding and clutch at your eyes!") + M.drop_item() + M.eye_blurry += 10 + M.Paralyse(1) + M.Weaken(4) + if (eyes.damage >= eyes.min_broken_damage) + if(M.stat != 2) + to_chat(M, "You go blind!") + + var/obj/item/organ/external/affecting = H.get_organ(eyes.parent_organ) + affecting.take_damage(7) + else + M.take_organ_damage(7) + M.eye_blurry += rand(3,4) + return + +/obj/item/clean_blood() + . = ..() + if(blood_overlay) + overlays.Remove(blood_overlay) + if(istype(src, /obj/item/clothing/gloves)) + var/obj/item/clothing/gloves/G = src + G.transfer_blood = 0 + +/obj/item/reveal_blood() + if(was_bloodied && !fluorescent) + fluorescent = 1 + blood_color = COLOR_LUMINOL + blood_overlay.color = COLOR_LUMINOL + update_icon() + +/obj/item/add_blood(mob/living/carbon/human/M as mob) + if (!..()) + return 0 + + if(istype(src, /obj/item/weapon/melee/energy)) + return + + //if we haven't made our blood_overlay already + if( !blood_overlay ) + generate_blood_overlay() + + //apply the blood-splatter overlay if it isn't already in there + if(!blood_DNA.len) + blood_overlay.color = blood_color + overlays += blood_overlay + + //if this blood isn't already in the list, add it + if(istype(M)) + if(blood_DNA[M.dna.unique_enzymes]) + return 0 //already bloodied with this blood. Cannot add more. + blood_DNA[M.dna.unique_enzymes] = M.dna.b_type + return 1 //we applied blood to the item + +/obj/item/proc/generate_blood_overlay() + if(blood_overlay) + return + + var/icon/I = new /icon(icon, icon_state) + I.Blend(new /icon('icons/effects/blood.dmi', rgb(255,255,255)),ICON_ADD) //fills the icon_state with white (except where it's transparent) + I.Blend(new /icon('icons/effects/blood.dmi', "itemblood"),ICON_MULTIPLY) //adds blood and the remaining white areas become transparant + + //not sure if this is worth it. It attaches the blood_overlay to every item of the same type if they don't have one already made. + for(var/obj/item/A in world) + if(A.type == type && !A.blood_overlay) + A.blood_overlay = image(I) + +/obj/item/proc/showoff(mob/user) + for (var/mob/M in view(user)) + M.show_message("[user] holds up [src]. Take a closer look.",1) + +/mob/living/carbon/verb/showoff() + set name = "Show Held Item" + set category = "Object" + + var/obj/item/I = get_active_hand() + if(I && I.simulated) + I.showoff(src) + +/* +For zooming with scope or binoculars. This is called from +modules/mob/mob_movement.dm if you move you will be zoomed out +modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. +*/ +//Looking through a scope or binoculars should /not/ improve your periphereal vision. Still, increase viewsize a tiny bit so that sniping isn't as restricted to NSEW +/obj/item/proc/zoom(mob/user, var/tileoffset = 14,var/viewsize = 9) //tileoffset is client view offset in the direction the user is facing. viewsize is how far out this thing zooms. 7 is normal view + if(!user.client) + return + + var/devicename + if(zoomdevicename) + devicename = zoomdevicename + else + devicename = src.name + + var/cannotzoom + + var/mob/living/carbon/human/H = user + if(user.incapacitated(INCAPACITATION_DISABLED)) + to_chat(user, "You are unable to focus through the [devicename].") + cannotzoom = 1 + else if(!zoom && istype(H) && H.equipment_tint_total >= TINT_MODERATE) + to_chat(user, "Your visor gets in the way of looking through the [devicename].") + cannotzoom = 1 + else if(!zoom && usr.get_active_hand() != src) + to_chat(user, "You are too distracted to look through the [devicename], perhaps if it was in your active hand this might work better.") + cannotzoom = 1 + + if(!zoom && !cannotzoom) + //if(user.hud_used.hud_shown) + // user.toggle_zoom_hud() // If the user has already limited their HUD this avoids them having a HUD when they zoom in + user.client.view = viewsize + zoom = 1 + + var/tilesize = 32 + var/viewoffset = tilesize * tileoffset + + switch(user.dir) + if (NORTH) + user.client.pixel_x = 0 + user.client.pixel_y = viewoffset + if (SOUTH) + user.client.pixel_x = 0 + user.client.pixel_y = -viewoffset + if (EAST) + user.client.pixel_x = viewoffset + user.client.pixel_y = 0 + if (WEST) + user.client.pixel_x = -viewoffset + user.client.pixel_y = 0 + + user.visible_message("\The [user] peers through the [zoomdevicename ? "[zoomdevicename] of [src]" : "[src]"].") + if(ishuman(user)) + H.hide_cone() + if(!user.zoomed) + user.zoomed = TRUE + + else + if(user.zoomed) + user.zoomed = FALSE + user.set_face_dir(FALSE)//Reset our facing direction. + user.client.view = world.view + //if(!user.hud_used.hud_shown) + // user.toggle_zoom_hud() + zoom = 0 + + user.client.pixel_x = 0 + user.client.pixel_y = 0 + + if(!cannotzoom) + user.visible_message("[zoomdevicename ? "\The [user] looks up from [src]" : "\The [user] lowers [src]"].") + if(ishuman(user)) + H.show_cone() + + return + +/obj/item/proc/pwr_drain() + return 0 // Process Kill + +/obj/item/proc/use_spritesheet(var/bodytype, var/slot, var/icon_state) + if(!sprite_sheets || !sprite_sheets[bodytype]) + return 0 + if(slot == slot_r_hand_str || slot == slot_l_hand_str) + return 0 + + if(icon_state in icon_states(sprite_sheets[bodytype])) + return 1 + + return (slot != slot_wear_suit_str && slot != slot_head_str) + +/obj/item/proc/get_icon_state(mob/user_mob, slot) + var/mob_state + if(item_state_slots && item_state_slots[slot]) + mob_state = item_state_slots[slot] + else if (item_state) + mob_state = item_state + else + mob_state = icon_state + return mob_state + +/obj/item/proc/dir_shift(var/icon/given_icon, var/dir_given, var/x = 0, var/y = 0) + var/icon/I = new(given_icon, dir = dir_given) + I.Shift(EAST, x) + I.Shift(NORTH, y) + given_icon.Insert(I, dir = dir_given) + return given_icon + +/obj/item/proc/get_mob_overlay(mob/user_mob, slot) + var/bodytype = "Default" + var/mob/living/carbon/human/user_human + if(ishuman(user_mob)) + user_human = user_mob + bodytype = user_human.species.get_bodytype(user_human) + + var/mob_state = get_icon_state(user_mob, slot) + + var/mob_icon + var/spritesheet = FALSE + if(icon_override) + mob_icon = icon_override + if(slot == slot_l_hand_str || slot == slot_l_ear_str) + mob_state = "[mob_state]_l" + if(slot == slot_r_hand_str || slot == slot_r_ear_str) + mob_state = "[mob_state]_r" + else if(use_spritesheet(bodytype, slot, mob_state)) + if(slot == slot_l_ear) + mob_state = "[mob_state]_l" + if(slot == slot_r_ear) + mob_state = "[mob_state]_r" + spritesheet = TRUE + mob_icon = sprite_sheets[bodytype] + else if(item_icons && item_icons[slot]) + mob_icon = item_icons[slot] + else + mob_icon = default_onmob_icons[slot] + + var/image/ret_overlay = overlay_image(mob_icon,mob_state,color)//,RESET_COLOR) + if(user_human && user_human.species && user_human.species.equip_adjust.len && !spritesheet) + var/list/equip_adjusts = user_human.species.equip_adjust + if(equip_adjusts[slot]) + var/image_key = "[user_human.species] [mob_icon] [mob_state] [color]" + ret_overlay = user_human.species.equip_overlays[image_key] + if(!ret_overlay) + var/icon/final_I = new(mob_icon, icon_state = mob_state) + var/list/shifts = equip_adjusts[slot] + if(shifts && shifts.len) + var/shift_facing + for(shift_facing in shifts) + var/list/facing_list = shifts[shift_facing] + final_I = dir_shift(final_I, text2dir(shift_facing), facing_list["x"], facing_list["y"]) + ret_overlay = overlay_image(final_I, color)//, flags = RESET_COLOR) + + user_human.species.equip_overlays[image_key] = ret_overlay + + return ret_overlay + +/obj/item/proc/get_examine_line() + if(blood_DNA) + . = "\icon[src] [gender==PLURAL?"some":"a"] [(blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [src]" + else + . = "\icon[src] \a [src]" + +//Kicking an item +/obj/item/kick_act(var/mob/living/user) + if(!..()) + return + var/turf/target = get_turf(src.loc) + var/range = throw_range + var/throw_dir = get_dir(user, src) + for(var/i = 1; i < range; i++) + var/turf/new_turf = get_step(target, throw_dir) + target = new_turf + if(new_turf.density) + break + throw_at(target, rand(1,3), throw_speed) + user.visible_message("[user] kicks \the [src.name].") + + +/obj/item/throw_impact(atom/hit_atom) + ..() + if(drop_sound) + playsound(src, drop_sound, 50, 0) + + +/obj/item/proc/grab_sound(mob/user) + if(grab_sound) + if(grab_sound_is_loud) + user.visible_message("[user] grabs a weapon!") + playsound(user, grab_sound, 50, FALSE) + + +//This is for the object breaking and repair system. These procs are top level and individual items below it can have their methods of being repaired. +/obj/item/proc/can_be_repaired() + return FALSE + +/obj/item/proc/repair_item() + return \ No newline at end of file diff --git a/code/game/objects/items/apc_frame.dm b/code/game/objects/items/apc_frame.dm new file mode 100644 index 00000000..e60f9ff2 --- /dev/null +++ b/code/game/objects/items/apc_frame.dm @@ -0,0 +1,43 @@ +// APC HULL + +/obj/item/frame/apc + name = "\improper APC frame" + desc = "Used for repairing or building APCs." + icon = 'icons/obj/apc_repair.dmi' + icon_state = "apc_frame" + obj_flags = OBJ_FLAG_CONDUCTIBLE + +/obj/item/frame/apc/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + if(isWrench(W)) + new /obj/item/stack/material/steel( get_turf(src.loc), 2 ) + qdel(src) + +/obj/item/frame/apc/try_build(turf/on_wall) + if (get_dist(on_wall,usr)>1) + return + var/ndir = get_dir(usr,on_wall) + if (!(ndir in GLOB.cardinal)) + return + var/turf/loc = get_turf(usr) + var/area/A = loc.loc + if (!istype(loc, /turf/simulated/floor)) + to_chat(usr, "APC cannot be placed on this spot.") + return + if (A.requires_power == 0 || istype(A, /area/space)) + to_chat(usr, "APC cannot be placed in this area.") + return + if (A.get_apc()) + to_chat(usr, "This area already has an APC.") + return //only one APC per area + for(var/obj/machinery/power/terminal/T in loc) + if (T.master) + to_chat(usr, "There is another network terminal here.") + return + else + var/obj/item/stack/cable_coil/C = new /obj/item/stack/cable_coil(loc) + C.amount = 10 + to_chat(usr, "You cut the cables and disassemble the unused power terminal.") + qdel(T) + new /obj/machinery/power/apc(loc, ndir, 1) + qdel(src) diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm new file mode 100644 index 00000000..1842d952 --- /dev/null +++ b/code/game/objects/items/blueprints.dm @@ -0,0 +1,267 @@ +/obj/item/blueprints + name = "blueprints" + desc = "Blueprints..." + icon = 'icons/obj/items.dmi' + icon_state = "blueprints" + attack_verb = list("attacked", "bapped", "hit") + var/const/AREA_ERRNONE = 0 + var/const/AREA_STATION = 1 + var/const/AREA_SPACE = 2 + var/const/AREA_SPECIAL = 3 + + var/const/BORDER_ERROR = 0 + var/const/BORDER_NONE = 1 + var/const/BORDER_BETWEEN = 2 + var/const/BORDER_2NDTILE = 3 + var/const/BORDER_SPACE = 4 + + var/const/ROOM_ERR_LOLWAT = 0 + var/const/ROOM_ERR_SPACE = -1 + var/const/ROOM_ERR_TOOLARGE = -2 + +/obj/item/blueprints/New() + ..() + desc = "Blueprints of the [station_name()]. There is a \"Classified\" stamp and several coffee stains on it." + +/obj/item/blueprints/attack_self(mob/M as mob) + if (!istype(M,/mob/living/carbon/human)) + to_chat(M, "This stack of blue paper means nothing to you.")//monkeys cannot into projecting + + return + interact() + return + +/obj/item/blueprints/Topic(href, href_list) + ..() + if ((usr.restrained() || usr.stat || usr.get_active_hand() != src)) + return + if (!href_list["action"]) + return + switch(href_list["action"]) + if ("create_area") + if (get_area_type()!=AREA_SPACE) + interact() + return + create_area() + if ("edit_area") + if (get_area_type()!=AREA_STATION) + interact() + return + edit_area() + if ("delete_area") + //skip the sanity checking, delete_area() does it anyway + delete_area() + +/obj/item/blueprints/interact() + var/area/A = get_area() + var/text = {"[src] +

            [station_name()] blueprints

            +Property of [GLOB.using_map.company_name]. For heads of staff only. Store in high-secure storage.
            +"} + switch (get_area_type()) + if (AREA_SPACE) + text += {" +

            According the blueprints, you are now in outer space. Hold your breath.

            +

            Mark this place as new area.

            +"} + if (AREA_STATION) + if (A.apc) + text += {" +

            According the blueprints, you are now in \"[A.name]\".

            +

            You may +move an amendment to the drawing.

            +

            You can't erase this area, because it has an APC.

            +"} + else + text += {" +

            According the blueprints, you are now in \"[A.name]\".

            +

            You may +move an amendment to the drawing, or erase part of it.

            +"} + if (AREA_SPECIAL) + text += {" +

            This place isn't noted on the blueprint.

            +"} + else + return + text += "" + usr << browse(text, "window=blueprints") + onclose(usr, "blueprints") + + +/obj/item/blueprints/proc/get_area() + var/turf/T = get_turf(usr) + var/area/A = T.loc + return A + +/obj/item/blueprints/proc/get_area_type(var/area/A = get_area()) + if(istype(A, /area/space)) + return AREA_SPACE + + var/list/SPECIALS = list( + /area/shuttle + ) + + if(is_type_in_list(A, SPECIALS)) + return AREA_SPECIAL + + if(A.z in GLOB.using_map.station_levels) + return AREA_STATION + + return AREA_SPECIAL + +/obj/item/blueprints/proc/create_area() +// log_debug("create_area") + + var/res = detect_room(get_turf(usr)) + if(!istype(res,/list)) + switch(res) + if(ROOM_ERR_SPACE) + to_chat(usr, "The new area must be completely airtight!") + return + if(ROOM_ERR_TOOLARGE) + to_chat(usr, "The new area too large!") + return + else + to_chat(usr, "Error! Please notify administration!") + return + var/list/turf/turfs = res + var/str = sanitizeSafe(input("New area name:","Blueprint Editing", ""), MAX_NAME_LEN) + if(!str || !length(str)) //cancel + return + if(length(str) > 50) + to_chat(usr, "Name too long.") + return + var/area/A = new + A.SetName(str) + //var/ma + //ma = A.master ? "[A.master]" : "(null)" +// log_debug(create_area:
            A.name=[A.name]
            A.tag=[A.tag]
            A.master=[ma]") + + A.power_equip = 0 + A.power_light = 0 + A.power_environ = 0 + A.always_unpowered = 0 + move_turfs_to_area(turfs, A) + + A.always_unpowered = 0 + + spawn(5) + //ma = A.master ? "[A.master]" : "(null)" +// log_debug)create_area(5):
            A.name=[A.name]
            A.tag=[A.tag]
            A.master=[ma]") + + interact() + return + + +/obj/item/blueprints/proc/move_turfs_to_area(var/list/turf/turfs, var/area/A) + A.contents.Add(turfs) + //oldarea.contents.Remove(usr.loc) // not needed + //T.loc = A //error: cannot change constant value + + +/obj/item/blueprints/proc/edit_area() + var/area/A = get_area() +// log_debug(edit_area") + + var/prevname = "[A.name]" + var/str = sanitizeSafe(input("New area name:","Blueprint Editing", prevname), MAX_NAME_LEN) + if(!str || !length(str) || str==prevname) //cancel + return + if(length(str) > 50) + to_chat(usr, "Text too long.") + return + set_area_machinery_title(A,str,prevname) + A.SetName(str) + to_chat(usr, "You set the area '[prevname]' title to '[str]'.") + interact() + return + + +/obj/item/blueprints/proc/delete_area() + var/area/A = get_area() + if (get_area_type(A)!=AREA_STATION || A.apc) //let's just check this one last time, just in case + interact() + return + to_chat(usr, "You scrub [A.name] off the blueprint.") + log_and_message_admins("deleted area [A.name] via station blueprints.") + qdel(A) + interact() + + + +/obj/item/blueprints/proc/set_area_machinery_title(var/area/A,var/title,var/oldtitle) + if (!oldtitle) // or replacetext goes to infinite loop + return + + for(var/obj/machinery/alarm/M in A) + M.SetName(replacetext(M.name,oldtitle,title)) + for(var/obj/machinery/power/apc/M in A) + M.SetName(replacetext(M.name,oldtitle,title)) + for(var/obj/machinery/atmospherics/unary/vent_scrubber/M in A) + M.SetName(replacetext(M.name,oldtitle,title)) + for(var/obj/machinery/atmospherics/unary/vent_pump/M in A) + M.SetName(replacetext(M.name,oldtitle,title)) + for(var/obj/machinery/door/M in A) + M.SetName(replacetext(M.name,oldtitle,title)) + //TODO: much much more. Unnamed airlocks, cameras, etc. + +/obj/item/blueprints/proc/check_tile_is_border(var/turf/T2,var/dir) + if (istype(T2, /turf/space)) + return BORDER_SPACE //omg hull breach we all going to die here + if (istype(T2, /turf/simulated/shuttle)) + return BORDER_SPACE + if (get_area_type(T2.loc)!=AREA_SPACE) + return BORDER_BETWEEN + if (istype(T2, /turf/simulated/wall)) + return BORDER_2NDTILE + if (!istype(T2, /turf/simulated)) + return BORDER_BETWEEN + + for (var/obj/structure/window/W in T2) + if(turn(dir,180) == W.dir) + return BORDER_BETWEEN + if (W.dir in list(NORTHEAST,SOUTHEAST,NORTHWEST,SOUTHWEST)) + return BORDER_2NDTILE + for(var/obj/machinery/door/window/D in T2) + if(turn(dir,180) == D.dir) + return BORDER_BETWEEN + if (locate(/obj/machinery/door) in T2) + return BORDER_2NDTILE + + return BORDER_NONE + +/obj/item/blueprints/proc/detect_room(var/turf/first) + var/list/turf/found = new + var/list/turf/pending = list(first) + while(pending.len) + if (found.len+pending.len > 300) + return ROOM_ERR_TOOLARGE + var/turf/T = pending[1] //why byond havent list::pop()? + pending -= T + for (var/dir in GLOB.cardinal) + var/skip = 0 + for (var/obj/structure/window/W in T) + if(dir == W.dir || (W.dir in list(NORTHEAST,SOUTHEAST,NORTHWEST,SOUTHWEST))) + skip = 1; break + if (skip) continue + for(var/obj/machinery/door/window/D in T) + if(dir == D.dir) + skip = 1; break + if (skip) continue + + var/turf/NT = get_step(T,dir) + if (!isturf(NT) || (NT in found) || (NT in pending)) + continue + + switch(check_tile_is_border(NT,dir)) + if(BORDER_NONE) + pending+=NT + if(BORDER_BETWEEN) + //do nothing, may be later i'll add 'rejected' list as optimization + if(BORDER_2NDTILE) + found+=NT //tile included to new area, but we dont seek more + if(BORDER_SPACE) + return ROOM_ERR_SPACE + found+=T + return found diff --git a/code/game/objects/items/bodybag.dm b/code/game/objects/items/bodybag.dm new file mode 100644 index 00000000..d278a08b --- /dev/null +++ b/code/game/objects/items/bodybag.dm @@ -0,0 +1,105 @@ +//Also contains /obj/structure/closet/body_bag because I doubt anyone would think to look for bodybags in /object/structures + +/obj/item/bodybag + name = "body bag" + desc = "A folded bag designed for the storage and transportation of cadavers." + icon = 'icons/obj/bodybag.dmi' + icon_state = "bodybag_folded" + w_class = ITEM_SIZE_SMALL + + attack_self(mob/user) + var/obj/structure/closet/body_bag/R = new /obj/structure/closet/body_bag(user.loc) + R.add_fingerprint(user) + qdel(src) + + +/obj/item/weapon/storage/box/bodybags + name = "body bags" + desc = "This box contains body bags." + icon_state = "bodybags" + New() + ..() + new /obj/item/bodybag(src) + new /obj/item/bodybag(src) + new /obj/item/bodybag(src) + new /obj/item/bodybag(src) + new /obj/item/bodybag(src) + new /obj/item/bodybag(src) + new /obj/item/bodybag(src) + + +/obj/structure/closet/body_bag + name = "body bag" + desc = "A plastic bag designed for the storage and transportation of cadavers." + icon = 'icons/obj/bodybag.dmi' + icon_state = "bodybag_closed" + icon_closed = "bodybag_closed" + icon_opened = "bodybag_open" + open_sound = 'sound/items/zip.ogg' + close_sound = 'sound/items/zip.ogg' + var/item_path = /obj/item/bodybag + density = 0 + storage_capacity = (MOB_MEDIUM * 2) - 1 + var/contains_body = 0 + +/obj/structure/closet/body_bag/attackby(W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/pen)) + var/t = input(user, "What would you like the label to be?", text("[]", src.name), null) as text + if (user.get_active_hand() != W) + return + if (!in_range(src, user) && src.loc != user) + return + t = sanitizeSafe(t, MAX_NAME_LEN) + if (t) + src.SetName("body bag - ") + src.name += t + src.overlays += image(src.icon, "bodybag_label") + else + src.SetName("body bag") + //..() //Doesn't need to run the parent. Since when can fucking bodybags be welded shut? -Agouri + return + else if(isWirecutter(W)) + src.SetName("body bag") + src.overlays.Cut() + to_chat(user, "You cut the tag off \the [src].") + return + else if(istype(W, /obj/item/device/healthanalyzer/) && !opened) + if(contains_body) + var/obj/item/device/healthanalyzer/HA = W + for(var/mob/living/L in contents) + HA.scan_mob(L, user) + else + to_chat(user, "\The [W] reports that \the [src] is empty.") + return + +/obj/structure/closet/body_bag/store_mobs(var/stored_units) + contains_body = ..() + return contains_body + +/obj/structure/closet/body_bag/close() + if(..()) + set_density(0) + return 1 + return 0 + +/obj/structure/closet/body_bag/proc/fold(var/user) + if(!ishuman(user)) return 0 + if(opened) return 0 + if(contents.len) return 0 + visible_message("[user] folds up the [name]") + . = new item_path(get_turf(src)) + qdel(src) + +/obj/structure/closet/body_bag/MouseDrop(over_object, src_location, over_location) + ..() + if((over_object == usr && (in_range(src, usr) || usr.contents.Find(src)))) + fold(usr) + +/obj/structure/closet/body_bag/update_icon() + if(opened) + icon_state = icon_opened + else + if(contains_body > 0) + icon_state = "bodybag_closed1" + else + icon_state = icon_closed \ No newline at end of file diff --git a/code/game/objects/items/contraband.dm b/code/game/objects/items/contraband.dm new file mode 100644 index 00000000..61b4891b --- /dev/null +++ b/code/game/objects/items/contraband.dm @@ -0,0 +1,57 @@ +//Let's get some REAL contraband stuff in here. Because come on, getting brigged for LIPSTICK is no fun. + +//Illicit drugs~ +/obj/item/weapon/storage/pill_bottle/happy + name = "bottle of Happy pills" + desc = "Highly illegal drug. When you want to see the rainbow." + +/obj/item/weapon/storage/pill_bottle/happy/New() + ..() + new /obj/item/weapon/reagent_containers/pill/happy( src ) + new /obj/item/weapon/reagent_containers/pill/happy( src ) + new /obj/item/weapon/reagent_containers/pill/happy( src ) + new /obj/item/weapon/reagent_containers/pill/happy( src ) + new /obj/item/weapon/reagent_containers/pill/happy( src ) + new /obj/item/weapon/reagent_containers/pill/happy( src ) + new /obj/item/weapon/reagent_containers/pill/happy( src ) + +/obj/item/weapon/storage/pill_bottle/zoom + name = "bottle of Zoom pills" + desc = "Highly illegal drug. Trade brain for speed." + +/obj/item/weapon/storage/pill_bottle/zoom/New() + ..() + new /obj/item/weapon/reagent_containers/pill/zoom( src ) + new /obj/item/weapon/reagent_containers/pill/zoom( src ) + new /obj/item/weapon/reagent_containers/pill/zoom( src ) + new /obj/item/weapon/reagent_containers/pill/zoom( src ) + new /obj/item/weapon/reagent_containers/pill/zoom( src ) + new /obj/item/weapon/reagent_containers/pill/zoom( src ) + new /obj/item/weapon/reagent_containers/pill/zoom( src ) + +/obj/item/weapon/reagent_containers/glass/beaker/vial/random + atom_flags = 0 + var/list/random_reagent_list = list(list(/datum/reagent/water = 15) = 1, list(/datum/reagent/space_cleaner = 15) = 1) + +/obj/item/weapon/reagent_containers/glass/beaker/vial/random/toxin + random_reagent_list = list( + list(/datum/reagent/mindbreaker = 10, /datum/reagent/space_drugs = 20) = 3, + list(/datum/reagent/toxin/carpotoxin = 15) = 2, + list(/datum/reagent/impedrezene = 15) = 2, + list(/datum/reagent/toxin/zombiepowder = 10) = 1) + +/obj/item/weapon/reagent_containers/glass/beaker/vial/random/New() + ..() + if(is_open_container()) + atom_flags ^= ATOM_FLAG_OPEN_CONTAINER + + var/list/picked_reagents = pickweight(random_reagent_list) + for(var/reagent in picked_reagents) + reagents.add_reagent(reagent, picked_reagents[reagent]) + + var/list/names = new + for(var/datum/reagent/R in reagents.reagent_list) + names += R.name + + desc = "Contains [english_list(names)]." + update_icon() diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm new file mode 100644 index 00000000..447fb2ef --- /dev/null +++ b/code/game/objects/items/crayons.dm @@ -0,0 +1,111 @@ +/obj/item/weapon/pen/crayon/red + icon_state = "crayonred" + colour = "#da0000" + shadeColour = "#810c0c" + colourName = "red" + +/obj/item/weapon/pen/crayon/orange + icon_state = "crayonorange" + colour = "#ff9300" + shadeColour = "#a55403" + colourName = "orange" + +/obj/item/weapon/pen/crayon/yellow + icon_state = "crayonyellow" + colour = "#fff200" + shadeColour = "#886422" + colourName = "yellow" + +/obj/item/weapon/pen/crayon/green + icon_state = "crayongreen" + colour = "#a8e61d" + shadeColour = "#61840f" + colourName = "green" + +/obj/item/weapon/pen/crayon/blue + icon_state = "crayonblue" + colour = "#00b7ef" + shadeColour = "#0082a8" + colourName = "blue" + +/obj/item/weapon/pen/crayon/purple + icon_state = "crayonpurple" + colour = "#da00ff" + shadeColour = "#810cff" + colourName = "purple" + +/obj/item/weapon/pen/crayon/random/Initialize() + ..() + var/crayon_type = pick(subtypesof(/obj/item/weapon/pen/crayon) - /obj/item/weapon/pen/crayon/random) + new crayon_type(loc) + return INITIALIZE_HINT_QDEL + +/obj/item/weapon/pen/crayon/mime + icon_state = "crayonmime" + desc = "A very sad-looking crayon." + colour = "#ffffff" + shadeColour = "#000000" + colourName = "mime" + uses = 0 + +/obj/item/weapon/pen/crayon/mime/attack_self(mob/living/user as mob) //inversion + if(colour != "#ffffff" && shadeColour != "#000000") + colour = "#ffffff" + shadeColour = "#000000" + to_chat(user, "You will now draw in white and black with this crayon.") + else + colour = "#000000" + shadeColour = "#ffffff" + to_chat(user, "You will now draw in black and white with this crayon.") + return + +/obj/item/weapon/pen/crayon/rainbow + icon_state = "crayonrainbow" + colour = "#fff000" + shadeColour = "#000fff" + colourName = "rainbow" + uses = 0 + +/obj/item/weapon/pen/crayon/rainbow/attack_self(mob/living/user as mob) + colour = input(user, "Please select the main colour.", "Crayon colour") as color + shadeColour = input(user, "Please select the shade colour.", "Crayon colour") as color + return + +/obj/item/weapon/pen/crayon/afterattack(atom/target, mob/user as mob, proximity) + if(!proximity) return + if(istype(target,/turf/simulated/floor)) + var/drawtype = input("Choose what you'd like to draw.", "Crayon scribbles") in list("graffiti","rune","letter","arrow") + switch(drawtype) + if("letter") + drawtype = input("Choose the letter.", "Crayon scribbles") in list("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z") + to_chat(user, "You start drawing a letter on the [target.name].") + if("graffiti") + to_chat(user, "You start drawing graffiti on the [target.name].") + if("rune") + to_chat(user, "You start drawing a rune on the [target.name].") + if("arrow") + drawtype = input("Choose the arrow.", "Crayon scribbles") in list("left", "right", "up", "down") + to_chat(user, "You start drawing an arrow on the [target.name].") + if(instant || do_after(user, 50)) + new /obj/effect/decal/cleanable/crayon(target,colour,shadeColour,drawtype) + to_chat(user, "You finish drawing.") + target.add_fingerprint(user) // Adds their fingerprints to the floor the crayon is drawn on. + if(uses) + uses-- + if(!uses) + to_chat(user, "You used up your crayon!") + qdel(src) + return + +/obj/item/weapon/pen/crayon/attack(mob/living/carbon/M as mob, mob/user as mob) + if(istype(M) && M == user) + to_chat(M, "You take a bite of the crayon and swallow it.") + M.nutrition += 1 + M.reagents.add_reagent(/datum/reagent/crayon_dust,min(5,uses)/3) + if(uses) + uses -= 5 + if(uses <= 0) + to_chat(M, "You ate your crayon!") + qdel(src) + else + ..() diff --git a/code/game/objects/items/cryobag.dm b/code/game/objects/items/cryobag.dm new file mode 100644 index 00000000..ced8e43a --- /dev/null +++ b/code/game/objects/items/cryobag.dm @@ -0,0 +1,111 @@ + +/obj/item/bodybag/cryobag + name = "stasis bag" + desc = "A folded, non-reusable bag designed to prevent additional damage to an occupant, especially useful if short on time or in \ + a hostile enviroment." + icon = 'icons/obj/cryobag.dmi' + icon_state = "bodybag_folded" + origin_tech = list(TECH_BIO = 4) + var/stasis_power + +/obj/item/bodybag/cryobag/attack_self(mob/user) + var/obj/structure/closet/body_bag/cryobag/R = new /obj/structure/closet/body_bag/cryobag(user.loc) + if(stasis_power) + R.stasis_power = stasis_power + R.update_icon() + R.add_fingerprint(user) + qdel(src) + +/obj/structure/closet/body_bag/cryobag + name = "stasis bag" + desc = "A non-reusable plastic bag designed to prevent additional damage to an occupant, especially useful if short on time or in \ + a hostile enviroment." + icon = 'icons/obj/cryobag.dmi' + item_path = /obj/item/bodybag/cryobag + + storage_types = CLOSET_STORAGE_MOBS + var/datum/gas_mixture/airtank + + var/stasis_power = 20 + var/degradation_time = 150 //ticks until stasis power degrades, ~5 minutes + +/obj/structure/closet/body_bag/cryobag/Initialize() + . = ..() + airtank = new() + airtank.temperature = T0C + airtank.adjust_gas("oxygen", MOLES_O2STANDARD, 0) + airtank.adjust_gas("nitrogen", MOLES_N2STANDARD) + update_icon() + +/obj/structure/closet/body_bag/cryobag/Destroy() + STOP_PROCESSING(SSobj, src) + QDEL_NULL(airtank) + return ..() + +/obj/structure/closet/body_bag/cryobag/Entered(atom/movable/AM) + if(ishuman(AM)) + START_PROCESSING(SSobj, src) + ..() + +/obj/structure/closet/body_bag/cryobag/Exited(atom/movable/AM) + if(ishuman(AM)) + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/structure/closet/body_bag/cryobag/update_icon() + ..() + overlays.Cut() + var/image/I = image(icon, "indicator[opened]") + I.appearance_flags = RESET_COLOR + var/maxstasis = initial(stasis_power) + if(stasis_power > 0.5 * maxstasis) + I.color = COLOR_LIME + else if(stasis_power) + I.color = COLOR_YELLOW + else + I.color = COLOR_RED + overlays += I + +/obj/structure/closet/body_bag/cryobag/proc/get_saturation() + return -155 * (1 - stasis_power/initial(stasis_power)) + +/obj/structure/closet/body_bag/cryobag/fold(var/user) + var/obj/item/bodybag/cryobag/folded = ..() + if(istype(folded)) + folded.stasis_power = stasis_power + folded.color = color_saturation(get_saturation()) + +/obj/structure/closet/body_bag/cryobag/Process() + if(stasis_power < 2) + return PROCESS_KILL + var/mob/living/carbon/human/H = locate() in src + if(!H) + return PROCESS_KILL + degradation_time-- + if(degradation_time < 0) + degradation_time = initial(degradation_time) + stasis_power = round(0.75 * stasis_power) + animate(src, color = color_saturation(get_saturation()), time = 10) + update_icon() + + if(H.stasis_sources[STASIS_CRYOBAG] != stasis_power) + H.SetStasis(stasis_power, STASIS_CRYOBAG) + +/obj/structure/closet/body_bag/cryobag/return_air() //Used to make stasis bags protect from vacuum. + if(airtank) + return airtank + ..() + +/obj/structure/closet/body_bag/cryobag/examine(mob/user) + . = ..() + to_chat(user,"The stasis meter shows '[stasis_power]x'.") + if(Adjacent(user)) //The bag's rather thick and opaque from a distance. + to_chat(user, "You peer into \the [src].") + for(var/mob/living/L in contents) + L.examine(user) + +/obj/item/usedcryobag + name = "used stasis bag" + desc = "Pretty useless now.." + icon_state = "bodybag_used" + icon = 'icons/obj/cryobag.dmi' \ No newline at end of file diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm new file mode 100644 index 00000000..4f1d8eee --- /dev/null +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -0,0 +1,1457 @@ + +//The advanced pea-green monochrome lcd of tomorrow. + +var/global/list/obj/item/device/pda/PDAs = list() + +/obj/item/device/pda + name = "\improper PDA" + desc = "A portable microcomputer by Thinktronic Systems, LTD. Functionality determined by a preprogrammed ROM cartridge." + icon = 'icons/obj/pda.dmi' + icon_state = "pda" + item_state = "electronic" + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_ID | SLOT_BELT + + //Main variables + var/owner = null + var/default_cartridge = 0 // Access level defined by cartridge + var/obj/item/weapon/cartridge/cartridge = null //current cartridge + var/mode = 0 //Controls what menu the PDA will display. 0 is hub; the rest are either built in or based on cartridge. + + var/lastmode = 0 + var/ui_tick = 0 + var/nanoUI[0] + + //Secondary variables + var/scanmode = 0 //1 is medical scanner, 2 is forensics, 3 is reagent scanner. + var/fon = 0 //Is the flashlight function on? + var/f_lum = 3 //Luminosity for the flashlight function + var/message_silent = 0 //To beep or not to beep, that is the question + var/news_silent = 1 //To beep or not to beep, that is the question. The answer is No. + var/toff = 0 //If 1, messenger disabled + var/tnote[0] //Current Texts + var/last_text //No text spamming + var/last_honk //Also no honk spamming that's bad too + var/ttone = "beep" //The PDA ringtone! + var/newstone = "beep, beep" //The news ringtone! + var/lock_code = "" // Lockcode to unlock uplink + var/honkamt = 0 //How many honks left when infected with honk.exe + var/mimeamt = 0 //How many silence left when infected with mime.exe + var/note = "Thank you for choosing the Thinktronic 5230 Personal Data Assistant!" //Current note in the notepad function + var/notehtml = "" + var/cart = "" //A place to stick cartridge menu information + var/detonate = 1 // Can the PDA be blown up? + var/hidden = 0 // Is the PDA hidden from the PDA list? + var/active_conversation = null // New variable that allows us to only view a single conversation. + var/list/conversations = list() // For keeping up with who we have PDA messsages from. + var/new_message = 0 //To remove hackish overlay check + var/new_news = 0 + var/list/tempmessage = list() // Used to store message in memory if sending failed + var/active_feed // The selected feed + var/list/warrant // The warrant as we last knew it + var/list/feeds = list() // The list of feeds as we last knew them + var/list/feed_info = list() // The data and contents of each feed as we last knew them + + var/list/cartmodes = list(40, 42, 43, 433, 44, 441, 45, 451, 46, 48, 47, 49) // If you add more cartridge modes add them to this list as well. + var/list/no_auto_update = list(1, 40, 43, 44, 441, 45, 451) // These modes we turn off autoupdate + var/list/update_every_five = list(3, 41, 433, 46, 47, 48, 49) // These we update every 5 ticks + + var/obj/item/weapon/card/id/id = null //Making it possible to slot an ID card into the PDA so it can function as both. + var/ownjob = null //related to above - this is assignment (potentially alt title) + var/ownrank = null // this one is rank, never alt title + + var/obj/item/device/paicard/pai = null // A slot for a personal AI device + +/obj/item/device/pda/AltClick(mob/user) + . = ..() + remove_id() + +/obj/item/device/pda/examine(mob/user) + . = ..(user, 1) + if(.) + to_chat(user, "The time [stationtime2text()] is displayed in the corner of the screen.") + + +/obj/item/device/pda/medical + default_cartridge = /obj/item/weapon/cartridge/medical + icon_state = "pda-medical" + +/obj/item/device/pda/viro + default_cartridge = /obj/item/weapon/cartridge/medical + icon_state = "pda-virology" + +/obj/item/device/pda/engineering + default_cartridge = /obj/item/weapon/cartridge/engineering + icon_state = "pda-engineer" + +/obj/item/device/pda/security + default_cartridge = /obj/item/weapon/cartridge/security + icon_state = "pda-security" + +/obj/item/device/pda/detective + default_cartridge = /obj/item/weapon/cartridge/detective + icon_state = "pda-detective" + +/obj/item/device/pda/warden + default_cartridge = /obj/item/weapon/cartridge/security + icon_state = "pda-warden" + +/obj/item/device/pda/janitor + default_cartridge = /obj/item/weapon/cartridge/janitor + ttone = "slip" + icon_state = "pda-janitor" + +/obj/item/device/pda/science + default_cartridge = /obj/item/weapon/cartridge/signal/science + ttone = "boom" + icon_state = "pda-science" + +/obj/item/device/pda/clown + default_cartridge = /obj/item/weapon/cartridge/clown + desc = "A portable microcomputer by Thinktronic Systems, LTD. The surface is coated with polytetrafluoroethylene and banana drippings." + icon_state = "pda-clown" + +/obj/item/device/pda/mime + default_cartridge = /obj/item/weapon/cartridge/mime + message_silent = 1 + news_silent = 1 + ttone = "silence" + newstone = "silence" + +/obj/item/device/pda/heads + default_cartridge = /obj/item/weapon/cartridge/head + news_silent = 1 + +/obj/item/device/pda/heads/hop + default_cartridge = /obj/item/weapon/cartridge/hop + icon_state = "pda-hop" + +/obj/item/device/pda/heads/hos + default_cartridge = /obj/item/weapon/cartridge/hos + icon_state = "pda-hos" + +/obj/item/device/pda/heads/ce + default_cartridge = /obj/item/weapon/cartridge/ce + icon_state = "pda-ce" + +/obj/item/device/pda/heads/cmo + default_cartridge = /obj/item/weapon/cartridge/cmo + icon_state = "pda-cmo" + +/obj/item/device/pda/heads/rd + default_cartridge = /obj/item/weapon/cartridge/rd + icon_state = "pda-science" + +/obj/item/device/pda/captain + default_cartridge = /obj/item/weapon/cartridge/captain + detonate = 0 + icon_state = "pda-captain" + //toff = 1 + +/obj/item/device/pda/ert + default_cartridge = /obj/item/weapon/cartridge/captain + detonate = 0 + hidden = 1 + +/obj/item/device/pda/cargo + default_cartridge = /obj/item/weapon/cartridge/quartermaster + icon_state = "pda-cargo" + +/obj/item/device/pda/quartermaster + default_cartridge = /obj/item/weapon/cartridge/quartermaster + icon_state = "pda-qm" + +/obj/item/device/pda/shaftminer + icon_state = "pda-miner" + +/obj/item/device/pda/syndicate + default_cartridge = /obj/item/weapon/cartridge/syndicate + name = "Military PDA" + owner = "Roma" + hidden = 1 + +/obj/item/device/pda/chaplain + ttone = "holy" + +/obj/item/device/pda/lawyer + default_cartridge = /obj/item/weapon/cartridge/lawyer + ttone = "..." + +/obj/item/device/pda/botanist + //default_cartridge = /obj/item/weapon/cartridge/botanist + +/obj/item/device/pda/roboticist + +/obj/item/device/pda/librarian + desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a WGW-11 series e-reader." + note = "Thank you for choosing the Thinktronic 5290 WGW-11 Series E-reader and Personal Data Assistant!" + message_silent = 1 //Quiet in the library! + news_silent = 0 // Librarian is above the law! (That and alt job title is reporter) + icon_state = "pda-library" + +/obj/item/device/pda/clear + note = "Thank you for choosing the Thinktronic 5230 Personal Data Assistant Deluxe Special Max Turbo Limited Edition!" + +/obj/item/device/pda/chef + +/obj/item/device/pda/bar + +/obj/item/device/pda/atmos + default_cartridge = /obj/item/weapon/cartridge/atmos + icon_state = "pda-engineer" + +/obj/item/device/pda/chemist + default_cartridge = /obj/item/weapon/cartridge/chemistry + icon_state = "pda-chemistry" + +/obj/item/device/pda/geneticist + default_cartridge = /obj/item/weapon/cartridge/medical + +// Special AI/pAI PDAs that cannot explode. +/obj/item/device/pda/ai + icon_state = "NONE" + ttone = "data" + newstone = "news" + detonate = 0 + + +/obj/item/device/pda/ai/proc/set_name_and_job(newname as text, newjob as text, newrank as null|text) + owner = newname + ownjob = newjob + if(newrank) + ownrank = newrank + else + ownrank = ownjob + SetName(newname + " (" + ownjob + ")") + + +//AI verb and proc for sending PDA messages. +/obj/item/device/pda/ai/verb/cmd_send_pdamesg() + set category = "AI IM" + set name = "Send Message" + set src in usr + if(usr.stat == 2) + to_chat(usr, "You can't send PDA messages because you are dead!") + return + var/list/plist = available_pdas() + if (plist) + var/c = input(usr, "Please select a PDA") as null|anything in sortList(plist) + if (!c) // if the user hasn't selected a PDA file we can't send a message + return + var/selected = plist[c] + create_message(usr, selected, 0) + + +/obj/item/device/pda/ai/verb/cmd_toggle_pda_receiver() + set category = "AI IM" + set name = "Toggle Sender/Receiver" + set src in usr + if(usr.stat == 2) + to_chat(usr, "You can't do that because you are dead!") + return + toff = !toff + to_chat(usr, "PDA sender/receiver toggled [(toff ? "Off" : "On")]!") + + +/obj/item/device/pda/ai/verb/cmd_toggle_pda_silent() + set category = "AI IM" + set name = "Toggle Ringer" + set src in usr + if(usr.stat == 2) + to_chat(usr, "You can't do that because you are dead!") + return + message_silent=!message_silent + to_chat(usr, "PDA ringer toggled [(message_silent ? "Off" : "On")]!") + + +/obj/item/device/pda/ai/verb/cmd_show_message_log() + set category = "AI IM" + set name = "Show Message Log" + set src in usr + if(usr.stat == 2) + to_chat(usr, "You can't do that because you are dead!") + return + var/HTML = "AI PDA Message Log" + for(var/index in tnote) + if(index["sent"]) + HTML += addtext("→ To ", index["owner"],":
            ", index["message"], "
            ") + else + HTML += addtext("← From ", index["owner"],":
            ", index["message"], "
            ") + HTML +="" + usr << browse(HTML, "window=log;size=400x444;border=1;can_resize=1;can_close=1;can_minimize=0") + + +/obj/item/device/pda/ai/can_use() + return 1 + + +/obj/item/device/pda/ai/attack_self(mob/user as mob) + if ((honkamt > 0) && (prob(60)))//For clown virus. + honkamt-- + playsound(loc, 'sound/items/bikehorn.ogg', 30, 1) + return + + +/obj/item/device/pda/ai/pai + ttone = "assist" + + +/* + * The Actual PDA + */ + +/obj/item/device/pda/New() + ..() + PDAs += src + PDAs = sortAtom(PDAs) + if(default_cartridge) + cartridge = new default_cartridge(src) + new /obj/item/weapon/pen(src) + +/obj/item/device/pda/proc/can_use() + + if(!ismob(loc)) + return 0 + + var/mob/M = loc + if(M.stat || M.restrained() || M.paralysis || M.stunned || M.weakened) + return 0 + if((src in M.contents) || ( istype(loc, /turf) && in_range(src, M) )) + return 1 + else + return 0 + +/obj/item/device/pda/proc/toggle_light() + if(can_use()) + if(fon) + fon = 0 + set_light(0) + else + fon = 1 + set_light(f_lum) + +/obj/item/device/pda/GetAccess() + if(id) + return id.GetAccess() + else + return ..() + +/obj/item/device/pda/GetIdCard() + return id + +/obj/item/device/pda/MouseDrop(obj/over_object as obj, src_location, over_location) + if(!canremove) + return + + if(ishuman(usr) || issmall(usr)) //so monkeys can take off their backpacks -- Urist + + if (!( istype(over_object, /obj/screen) )) + return ..() + + if (usr.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_KNOCKOUT)) + return + + //makes sure that the storage is equipped, so that we can't drag it into our hand from miles away. + if (!usr.contains(src)) + return + + src.add_fingerprint(usr) + if(usr.unEquip(src)) + switch(over_object.name) + if(BP_R_HAND) + usr.put_in_r_hand(src) + if(BP_L_HAND) + usr.put_in_l_hand(src) + +/obj/item/device/pda/attack_hand(var/mob/user) + if(loc == user) + if(user.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_KNOCKOUT)) + return + var/mob/living/carbon/human/H = user + if(istype(H) && src == H.wear_id) + return attack_self(user) + return ..() + + +/obj/item/device/pda/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + ui_tick++ + var/datum/nanoui/old_ui = GLOB.nanomanager.get_open_ui(user, src, "main") + var/auto_update = 1 + if(mode in no_auto_update) + auto_update = 0 + if(old_ui && (mode == lastmode && ui_tick % 5 && mode in update_every_five)) + return + + lastmode = mode + + var/title = "Personal Data Assistant" + + var/data[0] // This is the data that will be sent to the PDA + + data["owner"] = owner // Who is your daddy... + data["ownjob"] = ownjob // ...and what does he do? + + data["mode"] = mode // The current view + data["scanmode"] = scanmode // Scanners + data["fon"] = fon // Flashlight on? + data["pai"] = (isnull(pai) ? 0 : 1) // pAI inserted? + data["note"] = note // current pda notes + data["message_silent"] = message_silent // does the pda make noise when it receives a message? + data["news_silent"] = news_silent // does the pda make noise when it receives news? + data["toff"] = toff // is the messenger function turned off? + data["active_conversation"] = active_conversation // Which conversation are we following right now? + + + data["idInserted"] = (id ? 1 : 0) + data["idLink"] = (id ? text("[id.registered_name], [id.assignment]") : "--------") + + data["cart_loaded"] = cartridge ? 1:0 + if(cartridge) + var/cartdata[0] + cartdata["access"] = list(\ + "access_security" = cartridge.access_security,\ + "access_engine" = cartridge.access_engine,\ + "access_atmos" = cartridge.access_atmos,\ + "access_medical" = cartridge.access_medical,\ + "access_clown" = cartridge.access_clown,\ + "access_mime" = cartridge.access_mime,\ + "access_janitor" = cartridge.access_janitor,\ + "access_quartermaster" = cartridge.access_quartermaster,\ + "access_hydroponics" = cartridge.access_hydroponics,\ + "access_reagent_scanner" = cartridge.access_reagent_scanner,\ + "access_remote_door" = cartridge.access_remote_door,\ + "access_status_display" = cartridge.access_status_display,\ + "access_detonate_pda" = cartridge.access_detonate_pda\ + ) + + if(mode in cartmodes) + data["records"] = cartridge.create_NanoUI_values() + + if(mode == 0) + cartdata["name"] = cartridge.name + if(isnull(cartridge.radio)) + cartdata["radio"] = 0 + else + if(istype(cartridge.radio, /obj/item/radio/integrated/beepsky)) + cartdata["radio"] = 1 + if(istype(cartridge.radio, /obj/item/radio/integrated/signal)) + cartdata["radio"] = 2 + + if(mode == 2) + cartdata["charges"] = cartridge.charges ? cartridge.charges : 0 + data["cartridge"] = cartdata + + data["stationTime"] = stationtime2text() + data["new_Message"] = new_message + data["new_News"] = new_news + + var/datum/reception/reception = get_reception(src, do_sleep = 0) + var/has_reception = reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER + data["reception"] = has_reception + + if(mode==41) + data["crew_manifest"] = html_crew_manifest(1, 0) + + if(mode==2) + var/convopdas[0] + var/pdas[0] + var/count = 0 + for (var/obj/item/device/pda/P in PDAs) + if (!P.owner||P.toff||P == src||P.hidden) continue + if(conversations.Find("\ref[P]")) + convopdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "1"))) + else + pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) + count++ + + data["convopdas"] = convopdas + data["pdas"] = pdas + data["pda_count"] = count + + if(mode==21) + data["messagescount"] = tnote.len + data["messages"] = tnote + else + data["messagescount"] = null + data["messages"] = null + + if(active_conversation) + for(var/c in tnote) + if(c["target"] == active_conversation) + data["convo_name"] = sanitize(c["owner"]) + data["convo_job"] = sanitize(c["job"]) + break + + if(mode==3) + var/turf/T = get_turf(user.loc) + if(!isnull(T)) + var/datum/gas_mixture/environment = T.return_air() + + var/pressure = environment.return_pressure() + var/total_moles = environment.total_moles + + if (total_moles) + var/o2_level = environment.gas["oxygen"]/total_moles + var/n2_level = environment.gas["nitrogen"]/total_moles + var/co2_level = environment.gas["carbon_dioxide"]/total_moles + var/phoron_level = environment.gas["phoron"]/total_moles + var/unknown_level = 1-(o2_level+n2_level+co2_level+phoron_level) + data["aircontents"] = list(\ + "pressure" = "[round(pressure,0.1)]",\ + "nitrogen" = "[round(n2_level*100,0.1)]",\ + "oxygen" = "[round(o2_level*100,0.1)]",\ + "carbon_dioxide" = "[round(co2_level*100,0.1)]",\ + "phoron" = "[round(phoron_level*100,0.01)]",\ + "other" = "[round(unknown_level, 0.01)]",\ + "temp" = "[round(environment.temperature-T0C,0.1)]",\ + "reading" = 1\ + ) + if(isnull(data["aircontents"])) + data["aircontents"] = list("reading" = 0) + if(mode==6) + if(has_reception) + feeds.Cut() + for(var/datum/feed_channel/channel in news_network.network_channels) + feeds[++feeds.len] = list("name" = channel.channel_name, "censored" = channel.censored) + data["feedChannels"] = feeds + if(mode==61) + var/datum/feed_channel/FC + for(FC in news_network.network_channels) + if(FC.channel_name == active_feed["name"]) + break + + var/list/feed = feed_info[active_feed] + if(!feed) + feed = list() + feed["channel"] = FC.channel_name + feed["author"] = "Unknown" + feed["censored"]= 0 + feed["updated"] = -1 + feed["views"] = 0 + feed_info[active_feed] = feed + + if(FC.updated > feed["updated"] && has_reception) + feed["author"] = FC.author + feed["updated"] = FC.updated + feed["views"] = ++FC.views + feed["censored"] = FC.censored + + var/list/messages = list() + if(!FC.censored) + var/index = 0 + for(var/datum/feed_message/FM in FC.messages) + ++index + if(FM.img) + send_asset(usr.client, "newscaster_photo_[sanitize(FC.channel_name)]_[index].png") + // News stories are HTML-stripped but require newline replacement to be properly displayed in NanoUI + var/body = replacetext(FM.body, "\n", "
            ") + messages[++messages.len] = list("author" = FM.author, "body" = body, "message_type" = FM.message_type, "time_stamp" = FM.time_stamp, "has_image" = (FM.img != null), "caption" = FM.caption, "index" = index) + feed["messages"] = messages + + data["feed"] = feed + + data["manifest"] = nano_crew_manifest() + + nanoUI = data + // update the ui if it exists, returns null if no ui is passed/found + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "pda.tmpl", title, 520, 400, state = GLOB.inventory_state) + // when the ui is first opened this is the data it will use + + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(auto_update) + +//NOTE: graphic resources are loaded on client login +/obj/item/device/pda/attack_self(mob/user as mob) + var/datum/asset/assets = get_asset_datum(/datum/asset/simple/pda) + assets.send(user) + + user.set_machine(src) + + if(active_uplink_check(user)) + return + + ui_interact(user) //NanoUI requires this proc + return + +/obj/item/device/pda/CouldUseTopic(var/mob/user) + ..() + if(ishuman(user)) + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25) + +/obj/item/device/pda/Topic(href, href_list) + if(href_list["cartmenu"] && !isnull(cartridge)) + cartridge.Topic(href, href_list) + return 1 + if(href_list["radiomenu"] && !isnull(cartridge) && !isnull(cartridge.radio)) + cartridge.radio.Topic(href, href_list) + return 1 + + + ..() + var/mob/user = usr + var/datum/nanoui/ui = GLOB.nanomanager.get_open_ui(user, src, "main") + var/mob/living/U = usr + //Looking for master was kind of pointless since PDAs don't appear to have one. + //if ((src in U.contents) || ( istype(loc, /turf) && in_range(src, U) ) ) + if (usr.stat == DEAD) + return 0 + if(!can_use()) //Why reinvent the wheel? There's a proc that does exactly that. + U.unset_machine() + if(ui) + ui.close() + return 0 + + U.set_machine(src) + + switch(href_list["choice"]) + +//BASIC FUNCTIONS=================================== + + if("Close")//Self explanatory + U.unset_machine() + ui.close() + return 0 + if("Refresh")//Refresh, goes to the end of the proc. + if("Return")//Return + if(mode<=9) + mode = 0 + else + mode = round(mode/10) + if(mode==2) + active_conversation = null + if(mode==4)//Fix for cartridges. Redirects to hub. + mode = 0 + else if(mode >= 40 && mode <= 49)//Fix for cartridges. Redirects to refresh the menu. + cartridge.mode = mode + if ("Authenticate")//Checks for ID + id_check(U, 1) + if("UpdateInfo") + if(id) + set_rank_job(id.rank, id.assignment) + if("Eject")//Ejects the cart, only done from hub. + verb_remove_cartridge() + +//MENU FUNCTIONS=================================== + + if("0")//Hub + mode = 0 + if("1")//Notes + mode = 1 + if("2")//Messenger + mode = 2 + if("21")//Read messages + mode = 21 + if("3")//Atmos scan + mode = 3 + if("4")//Redirects to hub + mode = 0 + if("chatroom") // chatroom hub + mode = 5 + if("41") //Manifest + mode = 41 + + +//MAIN FUNCTIONS=================================== + + if("Light") + toggle_light() + if("Medical Scan") + if(scanmode == 1) + scanmode = 0 + else if((!isnull(cartridge)) && (cartridge.access_medical)) + scanmode = 1 + if("Reagent Scan") + if(scanmode == 3) + scanmode = 0 + else if((!isnull(cartridge)) && (cartridge.access_reagent_scanner)) + scanmode = 3 + if("Halogen Counter") + if(scanmode == 4) + scanmode = 0 + else if((!isnull(cartridge)) && (cartridge.access_engine)) + scanmode = 4 + if("Honk") + if ( !(last_honk && world.time < last_honk + 20) ) + playsound(loc, 'sound/items/bikehorn.ogg', 50, 1) + last_honk = world.time + if("Gas Scan") + if(scanmode == 5) + scanmode = 0 + else if((!isnull(cartridge)) && (cartridge.access_atmos)) + scanmode = 5 + +//MESSENGER/NOTE FUNCTIONS=================================== + + if ("Edit") + var/n = input(U, "Please enter message", name, notehtml) as message + if (in_range(src, U) && loc == U) + n = sanitizeSafe(n, extra = 0) + if (mode == 1) + note = html_decode(n) + notehtml = note + note = replacetext(note, "\n", "
            ") + else + ui.close() + if("Toggle Messenger") + toff = !toff + if("Toggle Ringer")//If viewing texts then erase them, if not then toggle silent status + message_silent = !message_silent + if("Toggle News") + news_silent = !news_silent + if("Clear")//Clears messages + if(href_list["option"] == "All") + tnote.Cut() + conversations.Cut() + if(href_list["option"] == "Convo") + var/new_tnote[0] + for(var/i in tnote) + if(i["target"] != active_conversation) + new_tnote[++new_tnote.len] = i + tnote = new_tnote + conversations.Remove(active_conversation) + + active_conversation = null + if(mode==21) + mode=2 + + if("Ringtone") + var/t = input(U, "Please enter new ringtone", name, ttone) as text + if (in_range(src, U) && loc == U) + if (t) + if(src.hidden_uplink && hidden_uplink.check_trigger(U, lowertext(t), lowertext(lock_code))) + to_chat(U, "The PDA softly beeps.") + ui.close() + else + t = sanitize(t, 20) + ttone = t + else + ui.close() + return 0 + if("Newstone") + var/t = input(U, "Please enter new news tone", name, newstone) as text + if (in_range(src, U) && loc == U) + if (t) + t = sanitize(t, 20) + newstone = t + else + ui.close() + return 0 + 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) + 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"] + mode = 21 + + if("Select Conversation") + var/P = href_list["convo"] + for(var/n in conversations) + if(P == n) + active_conversation=P + mode=21 + if("Select Feed") + var/n = href_list["name"] + for(var/f in feeds) + if(f["name"] == n) + active_feed = f + mode=61 + if("Send Honk")//Honk virus + if(cartridge && cartridge.access_clown)//Cartridge checks are kind of unnecessary since everything is done through switch. + var/obj/item/device/pda/P = locate(href_list["target"])//Leaving it alone in case it may do something useful, I guess. + if(!isnull(P)) + if (!P.toff && cartridge.charges > 0) + cartridge.charges-- + U.show_message("Virus sent!", 1) + P.honkamt = (rand(15,20)) + else + to_chat(U, "PDA not found.") + else + ui.close() + return 0 + if("Send Silence")//Silent virus + if(cartridge && cartridge.access_mime) + var/obj/item/device/pda/P = locate(href_list["target"]) + if(!isnull(P)) + if (!P.toff && cartridge.charges > 0) + cartridge.charges-- + U.show_message("Virus sent!", 1) + P.message_silent = 1 + P.news_silent = 1 + P.ttone = "silence" + P.newstone = "silence" + else + to_chat(U, "PDA not found.") + else + ui.close() + return 0 + + +//SYNDICATE FUNCTIONS=================================== + + if("Toggle Door") + if(cartridge && cartridge.access_remote_door) + for(var/obj/machinery/door/blast/M in world) + if(M.id == cartridge.remote_door_id) + if(M.density) + M.open() + else + M.close() + + if("Detonate")//Detonate PDA... maybe + if(cartridge && cartridge.access_detonate_pda) + var/obj/item/device/pda/P = locate(href_list["target"]) + var/datum/reception/reception = get_reception(src, P, "", do_sleep = 0) + if(!(reception.message_server && reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER)) + U.show_message("An error flashes on your [src]: Connection unavailable", 1) + return + if(reception.telecomms_reception & TELECOMMS_RECEPTION_RECEIVER == 0) // Does our recepient have a broadcaster on their level? + U.show_message("An error flashes on your [src]: Recipient unavailable", 1) + return + if(!isnull(P)) + if (!P.toff && cartridge.charges > 0) + cartridge.charges-- + + var/difficulty = 2 + + if(P.cartridge) + difficulty += P.cartridge.access_medical + difficulty += P.cartridge.access_security + difficulty += P.cartridge.access_engine + difficulty += P.cartridge.access_clown + difficulty += P.cartridge.access_janitor + if(P.hidden_uplink) + difficulty += 3 + + if(prob(difficulty)) + U.show_message("An error flashes on your [src].", 1) + else if (prob(difficulty * 7)) + U.show_message("Energy feeds back into your [src]!", 1) + ui.close() + detonate_act(src) + log_admin("[key_name(U)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up") + message_admins("[key_name_admin(U)] just attempted to blow up [P] with the Detomatix cartridge but failed.", 1) + else + U.show_message("Success!", 1) + log_admin("[key_name(U)] just attempted to blow up [P] with the Detomatix cartridge and succeeded") + message_admins("[key_name_admin(U)] just attempted to blow up [P] with the Detomatix cartridge and succeeded.", 1) + detonate_act(P) + else + to_chat(U, "No charges left.") + else + to_chat(U, "PDA not found.") + else + U.unset_machine() + ui.close() + return 0 + +//pAI FUNCTIONS=================================== + if("pai") + if(pai) + if(pai.loc != src) + pai = null + else + switch(href_list["option"]) + if("1") // Configure pAI device + pai.attack_self(U) + if("2") // Eject pAI device + var/turf/T = get_turf_or_move(src.loc) + if(T) + pai.loc = T + pai = null + + else + mode = text2num(href_list["choice"]) + if(cartridge) + cartridge.mode = mode + +//EXTRA FUNCTIONS=================================== + + if (mode == 2||mode == 21)//To clear message overlays. + new_message = 0 + update_icon() + + if (mode == 6||mode == 61)//To clear news overlays. + new_news = 0 + update_icon() + + if ((honkamt > 0) && (prob(60)))//For clown virus. + honkamt-- + playsound(loc, 'sound/items/bikehorn.ogg', 30, 1) + + return 1 // return 1 tells it to refresh the UI in NanoUI + +/obj/item/device/pda/update_icon() + ..() + + overlays.Cut() + if((new_message) || (new_news)) + overlays += image('icons/obj/pda.dmi', "pda-r") + +/obj/item/device/pda/proc/detonate_act(var/obj/item/device/pda/P) + //TODO: sometimes these attacks show up on the message server + var/i = rand(1,100) + var/j = rand(0,1) //Possibility of losing the PDA after the detonation + var/message = "" + var/mob/living/M = null + if(ismob(P.loc)) + M = P.loc + + //switch(i) //Yes, the overlapping cases are intended. + if(i<=10) //The traditional explosion + P.explode() + j=1 + message += "Your [P] suddenly explodes!" + if(i>=10 && i<= 20) //The PDA burns a hole in the holder. + j=1 + if(M && isliving(M)) + M.apply_damage( rand(30,60) , BURN) + message += "You feel a searing heat! Your [P] is burning!" + if(i>=20 && i<=25) //EMP + empulse(P.loc, 3, 6, 1) + message += "Your [P] emits a wave of electromagnetic energy!" + if(i>=25 && i<=40) //Smoke + var/datum/effect/effect/system/smoke_spread/S = new /datum/effect/effect/system/smoke_spread + S.attach(P.loc) + S.set_up(10, 0, P.loc) + playsound(P.loc, 'sound/effects/smoke.ogg', 50, 1, -3) + S.start() + message += "Large clouds of smoke billow forth from your [P]!" + if(i>=40 && i<=45) //Bad smoke + var/datum/effect/effect/system/smoke_spread/bad/B = new /datum/effect/effect/system/smoke_spread/bad + B.attach(P.loc) + B.set_up(10, 0, P.loc) + playsound(P.loc, 'sound/effects/smoke.ogg', 50, 1, -3) + B.start() + message += "Large clouds of noxious smoke billow forth from your [P]!" + if(i>=65 && i<=75) //Weaken + if(M && isliving(M)) + M.apply_effects(weaken = 1) + message += "Your [P] flashes with a blinding white light! You feel weaker." + if(i>=75 && i<=85) //Stun and stutter + if(M && isliving(M)) + M.apply_effects(stun = 1, stutter = 1) + message += "Your [P] flashes with a blinding white light! You feel weaker." + if(i>=85) //Sparks + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, P.loc) + s.start() + message += "Your [P] begins to spark violently!" + if(i>45 && i<65 && prob(50)) //Nothing happens + message += "Your [P] bleeps loudly." + j = prob(10) + + if(j) //This kills the PDA + qdel(P) + if(message) + message += "It melts in a puddle of plastic." + else + message += "Your [P] shatters in a thousand pieces!" + + if(M && isliving(M)) + message = "[message]" + M.show_message(message, 1) + +/obj/item/device/pda/proc/remove_id() + if (id) + if (ismob(loc)) + var/mob/M = loc + M.put_in_hands(id) + to_chat(usr, "You remove the ID from the [name].") + else + id.loc = get_turf(src) + id = null + + +/obj/item/device/pda/proc/create_message(var/mob/living/U = usr, var/obj/item/device/pda/P, var/tap = 1) + if(!istype(P)) + to_chat(U, "ERROR: This user does not accept messages.") + return + if(tap) + U.visible_message("\The [U] taps on \his PDA's screen.") + var/t = input(U, "Please enter message", P.name, tempmessage[P]) as text + t = sanitizeSafe(t, extra = 0) + //t = readd_quotes(t) + t = replace_characters(t, list(""" = "\"")) + if (!t) + return + if (!in_range(src, U) && loc != U) + return + + if (isnull(P)||P.toff || toff) + return + + if (last_text && world.time < last_text + 5) + return + + if(!can_use()) + return + + last_text = world.time + tempmessage.Remove(P) + var/datum/reception/reception = get_reception(src, P, t) + t = reception.message + if(!get_message_server(z)) + to_chat(U, "ERROR: Messaging server is not responding.") + tempmessage[P] = t + return + if(!get_message_server(P.z)) + to_chat(U, "ERROR: Receiving messaging server is not responding.") + tempmessage[P] = t + return + if(reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER) // only send the message if it's stable + if(reception.telecomms_reception & TELECOMMS_RECEPTION_RECEIVER == 0) // Does our recipient have a broadcaster on their level? + to_chat(U, "ERROR: Cannot reach recipient.") + tempmessage[P] = t + return + var/send_result = reception.message_server.send_pda_message("[P.owner]","[owner]","[t]") + if (send_result) + to_chat(U, "ERROR: Messaging server rejected your message. Reason: contains '[send_result]'.") + tempmessage[P] = t + return + var/utf_convert = rustoutf(html_decode(t)) + tnote.Add(list(list("sent" = 1, "owner" = "[P.owner]", "job" = "[P.ownjob]", "message" = "[utf_convert]", "timestamp" = stationtime2text(), "target" = "\ref[P]"))) + P.tnote.Add(list(list("sent" = 0, "owner" = "[owner]", "job" = "[ownjob]", "message" = "[utf_convert]", "timestamp" = stationtime2text(), "target" = "\ref[src]"))) + for(var/mob/M in GLOB.player_list) + if(M.stat == DEAD && M.get_preference_value(/datum/client_preference/ghost_ears) == GLOB.PREF_ALL_SPEECH) // src.client is so that ghosts don't have to listen to mice + if(istype(M, /mob/new_player)) + continue + M.show_message("PDA Message - [owner] -> [P.owner]: [t]") + + if(!conversations.Find("\ref[P]")) + conversations.Add("\ref[P]") + if(!P.conversations.Find("\ref[src]")) + P.conversations.Add("\ref[src]") + + + if (prob(15)) //Give the AI a chance of intercepting the message + var/who = src.owner + if(prob(50)) + who = P.owner + for(var/mob/living/silicon/ai/ai in GLOB.silicon_mob_list) + // Allows other AIs to intercept the message but the AI won't intercept their own message. + if(ai.aiPDA != P && ai.aiPDA != src) + ai.show_message("Intercepted message from [who]: [t]") + + P.new_message_from_pda(src, t) + GLOB.nanomanager.update_user_uis(U, src) // Update the sending user's PDA UI so that they can see the new message + +/obj/item/device/pda/proc/new_info(var/beep_silent, var/message_tone, var/reception_message) + if (!beep_silent) + playsound(loc, 'sound/machines/twobeep.ogg', 50, 1) + for (var/mob/O in hearers(2, loc)) + O.show_message(text("\icon[src] *[message_tone]*")) + //Search for holder of the PDA. + var/mob/living/L = null + if(loc && isliving(loc)) + L = loc + //Maybe they are a pAI! + else + L = get(src, /mob/living/silicon) + + if(L) + if(reception_message) + to_chat(L, reception_message) + GLOB.nanomanager.update_user_uis(L, src) // Update the receiving user's PDA UI so that they can see the new message + +/obj/item/device/pda/proc/new_news(var/message) + new_info(news_silent, newstone, news_silent ? "" : "\icon[src] [message]") + + if(!news_silent) + new_news = 1 + update_icon() + +/obj/item/device/pda/ai/new_news(var/message) + // Do nothing + +/obj/item/device/pda/proc/new_message_from_pda(var/obj/item/device/pda/sending_device, var/message) + 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)" + new_info(message_silent, ttone, reception_message) + log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]") + new_message = 1 + update_icon() + +/obj/item/device/pda/ai/new_message(var/atom/movable/sending_unit, var/sender, var/sender_job, var/message) + if(!istype(sending_unit)) + to_chat(usr, "This destination does not accept messages.") + return + var/track = "" + if(ismob(sending_unit.loc) && isAI(loc)) + track = "(Follow)" + + 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]") + new_message = 1 + +/obj/item/device/pda/verb/verb_reset_pda() + set category = "Object" + set name = "Reset PDA" + set src in usr + + if(issilicon(usr)) + return + + if(can_use(usr)) + mode = 0 + GLOB.nanomanager.update_uis(src) + to_chat(usr, "You press the reset button on \the [src].") + else + to_chat(usr, "You cannot do it right now.") + +/obj/item/device/pda/verb/verb_remove_id() + set category = "Object" + set name = "Remove id" + set src in usr + + if(issilicon(usr)) + return + + if ( can_use(usr) ) + if(id) + remove_id() + else + to_chat(usr, "\The [src] does not have an ID in it.") + else + to_chat(usr, "You cannot do it right now.") + + +/obj/item/device/pda/verb/verb_remove_pen() + set category = "Object" + set name = "Remove pen" + set src in usr + + if(issilicon(usr)) + return + + if ( can_use(usr) ) + var/obj/item/weapon/pen/O = locate() in src + if(O) + if (istype(loc, /mob)) + var/mob/M = loc + if(M.get_active_hand() == null) + M.put_in_hands(O) + to_chat(usr, "You remove \the [O] from \the [src].") + return + O.loc = get_turf(src) + else + to_chat(usr, "\The [src] does not have a pen in it.") + else + to_chat(usr, "You cannot do it right now.") + +/obj/item/device/pda/verb/verb_remove_cartridge() + set category = "Object" + set name = "Remove cartridge" + set src in usr + + if(issilicon(usr)) + return + + if(isnull(cartridge)) + to_chat(usr, "\The [src] does not have a cartridge in it.") + return + + if (can_use(usr)) + var/turf/T = get_turf(src) + cartridge.loc = T + if (ismob(loc)) + var/mob/M = loc + M.put_in_hands(cartridge) + else + cartridge.loc = get_turf(src) + mode = 0 + scanmode = 0 + if (cartridge.radio) + cartridge.radio.hostpda = null + to_chat(usr, "You remove \the [cartridge] from the [name].") + cartridge = null + else + to_chat(usr, "You cannot do it right now.") + +/obj/item/device/pda/proc/id_check(mob/user as mob, choice as num)//To check for IDs; 1 for in-pda use, 2 for out of pda use. + if(choice == 1) + if (id) + remove_id() + return 1 + else + var/obj/item/I = user.get_active_hand() + if (istype(I, /obj/item/weapon/card/id) && user.unEquip(I)) + I.loc = src + id = I + return 1 + else + var/obj/item/weapon/card/I = user.get_active_hand() + if (istype(I, /obj/item/weapon/card/id) && I:registered_name && user.unEquip(I)) + var/obj/old_id = id + I.loc = src + id = I + user.put_in_hands(old_id) + return 1 + return 0 + +// access to status display signals +/obj/item/device/pda/attackby(obj/item/C as obj, mob/user as mob) + ..() + if(istype(C, /obj/item/weapon/cartridge) && !cartridge) + cartridge = C + user.drop_item() + cartridge.loc = src + to_chat(user, "You insert [cartridge] into [src].") + GLOB.nanomanager.update_uis(src) // update all UIs attached to src + if(cartridge.radio) + cartridge.radio.hostpda = src + + else if(istype(C, /obj/item/weapon/card/id)) + var/obj/item/weapon/card/id/idcard = C + if(!idcard.registered_name) + to_chat(user, "\The [src] rejects the ID.") + return + if(!owner) + set_owner_rank_job(idcard.registered_name, idcard.rank, idcard.assignment) + SetName("PDA-[owner] ([ownjob])") + to_chat(user, "Card scanned.") + else + //Basic safety check. If either both objects are held by user or PDA is on ground and card is in hand. + if(((src in user.contents) && (C in user.contents)) || (istype(loc, /turf) && in_range(src, user) && (C in user.contents)) ) + if(id_check(user, 2)) + to_chat(user, "You put the ID into \the [src]'s slot.") + updateSelfDialog()//Update self dialog on success. + return //Return in case of failed check or when successful. + updateSelfDialog()//For the non-input related code. + else if(istype(C, /obj/item/device/paicard) && !src.pai) + user.drop_item() + C.loc = src + pai = C + to_chat(user, "You slot \the [C] into [src].") + GLOB.nanomanager.update_uis(src) // update all UIs attached to src + else if(istype(C, /obj/item/weapon/pen)) + var/obj/item/weapon/pen/O = locate() in src + if(O) + to_chat(user, "There is already a pen in \the [src].") + else + user.drop_item() + C.loc = src + to_chat(user, "You slide \the [C] into \the [src].") + return + +/obj/item/device/pda/attack(mob/living/C as mob, mob/living/user as mob) + if (istype(C, /mob/living/carbon)) + switch(scanmode) + if(1) + + for (var/mob/O in viewers(C, null)) + O.show_message("\The [user] has analyzed [C]'s vitals!", 1) + user.show_message(medical_scan_results(C, 1)) + + if(2) + if (!istype(C:dna, /datum/dna)) + to_chat(user, "No fingerprints found on [C]") + else + to_chat(user, text("\The [C]'s Fingerprints: [md5(C:dna.uni_identity)]")) + if ( !(C:blood_DNA) ) + to_chat(user, "No blood found on [C]") + if(C:blood_DNA) + qdel(C:blood_DNA) + else + to_chat(user, "Blood found on [C]. Analysing...") + spawn(15) + for(var/blood in C:blood_DNA) + to_chat(user, "Blood type: [C:blood_DNA[blood]]\nDNA: [blood]") + + if(4) + for (var/mob/O in viewers(C, null)) + O.show_message("\The [user] has analyzed [C]'s radiation levels!", 1) + + user.show_message("Analyzing Results for [C]:") + if(C.radiation) + user.show_message("Radiation Level: [C.radiation] mSv") + else + user.show_message("No radiation detected.") + +/obj/item/device/pda/afterattack(atom/A as mob|obj|turf|area, mob/user as mob, proximity) + if(!proximity) return + switch(scanmode) + + if(3) + if(!isobj(A)) + return + if(!isnull(A.reagents)) + if(A.reagents.reagent_list.len > 0) + var/reagents_length = A.reagents.reagent_list.len + to_chat(user, "[reagents_length] chemical agent[reagents_length > 1 ? "s" : ""] found.") + for (var/re in A.reagents.reagent_list) + to_chat(user, " [re]") + else + to_chat(user, "No active chemical agents found in [A].") + else + to_chat(user, "No significant chemical agents found in [A].") + + if(5) + analyze_gases(A, user) + + if (!scanmode && istype(A, /obj/item/weapon/paper) && owner) + // JMO 20140705: Makes scanned document show up properly in the notes. Not pretty for formatted documents, + // as this will clobber the HTML, but at least it lets you scan a document. You can restore the original + // notes by editing the note again. (Was going to allow you to edit, but scanned documents are too long.) + var/raw_scan = (A:info) + var/formatted_scan = "" + // Scrub out the tags (replacing a few formatting ones along the way) + + // Find the beginning and end of the first tag. + var/tag_start = findtext(raw_scan,"<") + var/tag_stop = findtext(raw_scan,">") + + // Until we run out of complete tags... + while(tag_start&&tag_stop) + var/pre = copytext(raw_scan,1,tag_start) // Get the stuff that comes before the tag + var/tag = lowertext(copytext(raw_scan,tag_start+1,tag_stop)) // Get the tag so we can do intellegent replacement + var/tagend = findtext(tag," ") // Find the first space in the tag if there is one. + + // Anything that's before the tag can just be added as is. + formatted_scan = formatted_scan+pre + + // If we have a space after the tag (and presumably attributes) just crop that off. + if (tagend) + tag=copytext(tag,1,tagend) + + if (tag=="p"||tag=="/p"||tag=="br") // Check if it's I vertical space tag. + formatted_scan=formatted_scan+"
            " // If so, add some padding in. + + raw_scan = copytext(raw_scan,tag_stop+1) // continue on with the stuff after the tag + + // Look for the next tag in what's left + tag_start = findtext(raw_scan,"<") + tag_stop = findtext(raw_scan,">") + + // Anything that is left in the page. just tack it on to the end as is + formatted_scan=formatted_scan+raw_scan + + // If there is something in there already, pad it out. + if (length(note)>0) + note = note + "

            " + + // Store the scanned document to the notes + note = "Scanned Document. Edit to restore previous notes/delete scan.
            ----------
            " + formatted_scan + "
            " + // notehtml ISN'T set to allow user to get their old notes back. A better implementation would add a "scanned documents" + // feature to the PDA, which would better convey the availability of the feature, but this will work for now. + + // Inform the user + to_chat(user, "Paper scanned and OCRed to notekeeper.")//concept of scanning paper copyright brainoblivion 2009 + + + + +/obj/item/device/pda/proc/explode() //This needs tuning. //Sure did. + if(!src.detonate) return + var/turf/T = get_turf(src.loc) + if(T) + T.hotspot_expose(700,125) + explosion(T, 0, 0, 1, rand(1,2)) + return + +/obj/item/device/pda/Destroy() + PDAs -= src + if (src.id && prob(90)) //IDs are kept in 90% of the cases + src.id.forceMove(get_turf(src.loc)) + else + QDEL_NULL(src.id) + QDEL_NULL(src.cartridge) + QDEL_NULL(src.pai) + return ..() + +/obj/item/device/pda/clown/Crossed(AM as mob|obj) //Clown PDA is slippery. + if (istype(AM, /mob/living)) + var/mob/living/M = AM + + if(M.slip("the PDA",8) && M.real_name != src.owner && istype(src.cartridge, /obj/item/weapon/cartridge/clown)) + if(src.cartridge.charges < 5) + src.cartridge.charges++ + +/obj/item/device/pda/proc/available_pdas() + var/list/names = list() + var/list/plist = list() + var/list/namecounts = list() + + if (toff) + to_chat(usr, "Turn on your receiver in order to send messages.") + return + + for (var/obj/item/device/pda/P in PDAs) + if (!P.owner) + continue + else if(P.hidden) + continue + else if (P == src) + continue + else if (P.toff) + continue + + var/name = P.owner + if (name in names) + namecounts[name]++ + SetName(text("[name] ([namecounts[name]])")) + else + names.Add(name) + namecounts[name] = 1 + + plist[text("[name]")] = P + return plist + + +//Some spare PDAs in a box +/obj/item/weapon/storage/box/PDAs + name = "box of spare PDAs" + desc = "A box of spare PDA microcomputers." + icon = 'icons/obj/pda.dmi' + icon_state = "pdabox" + + New() + ..() + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/weapon/cartridge/head(src) + + var/newcart = pick( /obj/item/weapon/cartridge/engineering, + /obj/item/weapon/cartridge/security, + /obj/item/weapon/cartridge/medical, + /obj/item/weapon/cartridge/signal/science, + /obj/item/weapon/cartridge/quartermaster) + new newcart(src) + +// Pass along the pulse to atoms in contents, largely added so pAIs are vulnerable to EMP +/obj/item/device/pda/emp_act(severity) + for(var/atom/A in src) + A.emp_act(severity) + +/obj/item/device/pda/proc/set_owner(var/owner) + src.owner = owner + update_label() + +/obj/item/device/pda/proc/set_rank_job(var/owner, var/rank, var/job) + ownrank = rank + ownjob = job ? job : rank + update_label() + +/obj/item/device/pda/proc/set_owner_rank_job(var/owner, var/rank, var/job) + set_owner(owner) + set_rank_job(rank, job) + +/obj/item/device/pda/proc/update_label() + name = "PDA-[owner] ([ownjob])" diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm new file mode 100644 index 00000000..1f04f0f1 --- /dev/null +++ b/code/game/objects/items/devices/PDA/cart.dm @@ -0,0 +1,497 @@ +/obj/item/weapon/cartridge + name = "generic cartridge" + desc = "A data cartridge for portable microcomputers." + icon = 'icons/obj/pda.dmi' + icon_state = "cart" + item_state = "electronic" + w_class = ITEM_SIZE_TINY + + var/obj/item/radio/integrated/radio = null + var/access_security = 0 + var/access_engine = 0 + var/access_atmos = 0 + var/access_medical = 0 + var/access_clown = 0 + var/access_mime = 0 + var/access_janitor = 0 +// var/access_flora = 0 + var/access_reagent_scanner = 0 + var/access_remote_door = 0 // Control some blast doors remotely!! + var/remote_door_id = "" + var/access_status_display = 0 + var/access_quartermaster = 0 + var/access_detonate_pda = 0 + var/access_hydroponics = 0 + var/charges = 0 + var/mode = null + var/menu + var/datum/data/record/active1 = null //General + var/datum/data/record/active2 = null //Medical + var/datum/data/record/active3 = null //Security + var/selected_sensor = null // Power Sensor + var/message1 // used for status_displays + var/message2 + var/list/stored_data = list() + +/obj/item/weapon/cartridge/Destroy() + QDEL_NULL(radio) + return ..() + +/obj/item/weapon/cartridge/engineering + name = "\improper Power-ON cartridge" + icon_state = "cart-e" + access_engine = 1 + +/obj/item/weapon/cartridge/atmos + name = "\improper BreatheDeep cartridge" + icon_state = "cart-a" + access_atmos = 1 + +/obj/item/weapon/cartridge/medical + name = "\improper Med-U cartridge" + icon_state = "cart-m" + access_medical = 1 + +/obj/item/weapon/cartridge/chemistry + name = "\improper ChemWhiz cartridge" + icon_state = "cart-chem" + access_reagent_scanner = 1 + +/obj/item/weapon/cartridge/security + name = "\improper R.O.B.U.S.T. cartridge" + icon_state = "cart-s" + access_security = 1 + +/obj/item/weapon/cartridge/security/Initialize() + radio = new /obj/item/radio/integrated/beepsky(src) + . = ..() + +/obj/item/weapon/cartridge/detective + name = "\improper D.E.T.E.C.T. cartridge" + icon_state = "cart-s" + access_security = 1 + access_medical = 1 + + +/obj/item/weapon/cartridge/janitor + name = "\improper CustodiPRO cartridge" + desc = "The ultimate in clean-room design." + icon_state = "cart-j" + access_janitor = 1 + +/obj/item/weapon/cartridge/lawyer + name = "\improper P.R.O.V.E. cartridge" + icon_state = "cart-s" + access_security = 1 + +/obj/item/weapon/cartridge/clown + name = "\improper Honkworks 5.0 cartridge" + icon_state = "cart-clown" + access_clown = 1 + charges = 5 + +/obj/item/weapon/cartridge/mime + name = "\improper Gestur-O 1000 cartridge" + icon_state = "cart-mi" + access_mime = 1 + charges = 5 +/* +/obj/item/weapon/cartridge/botanist + name = "Green Thumb v4.20" + icon_state = "cart-b" + access_flora = 1 +*/ + +/obj/item/weapon/cartridge/signal + name = "generic signaler cartridge" + desc = "A data cartridge with an integrated radio signaler module." + var/qdeled = 0 + +/obj/item/weapon/cartridge/signal/science + name = "\improper Signal Ace 2 cartridge" + desc = "Complete with integrated radio signaler!" + icon_state = "cart-tox" + access_reagent_scanner = 1 + access_atmos = 1 + +/obj/item/weapon/cartridge/signal/Initialize() + radio = new /obj/item/radio/integrated/signal(src) + . = ..() + +/obj/item/weapon/cartridge/quartermaster + name = "\improper Space Parts & Space Vendors cartridge" + desc = "Perfect for the Quartermaster on the go!" + icon_state = "cart-q" + access_quartermaster = 1 + +/obj/item/weapon/cartridge/head + name = "\improper Easy-Record DELUXE" + icon_state = "cart-h" + access_status_display = 1 + +/obj/item/weapon/cartridge/hop + name = "\improper HumanResources9001 cartridge" + icon_state = "cart-h" + access_status_display = 1 + access_quartermaster = 1 + access_janitor = 1 + access_security = 1 + +/obj/item/weapon/cartridge/hos + name = "\improper R.O.B.U.S.T. DELUXE" + icon_state = "cart-hos" + access_status_display = 1 + access_security = 1 + +/obj/item/weapon/cartridge/hos/Initialize() + radio = new /obj/item/radio/integrated/beepsky(src) + . = ..() + +/obj/item/weapon/cartridge/ce + name = "\improper Power-On DELUXE" + icon_state = "cart-ce" + access_status_display = 1 + access_engine = 1 + access_atmos = 1 + +/obj/item/weapon/cartridge/cmo + name = "\improper Med-U DELUXE" + icon_state = "cart-cmo" + access_status_display = 1 + access_reagent_scanner = 1 + access_medical = 1 + +/obj/item/weapon/cartridge/rd + name = "\improper Signal Ace DELUXE" + icon_state = "cart-rd" + access_status_display = 1 + access_reagent_scanner = 1 + access_atmos = 1 + +/obj/item/weapon/cartridge/rd/Initialize() + radio = new /obj/item/radio/integrated/signal(src) + . = ..() + +/obj/item/weapon/cartridge/captain + name = "\improper Value-PAK cartridge" + desc = "Now with 200% more value!" + icon_state = "cart-c" + access_quartermaster = 1 + access_janitor = 1 + access_engine = 1 + access_security = 1 + access_medical = 1 + access_reagent_scanner = 1 + access_status_display = 1 + access_atmos = 1 + +/obj/item/weapon/cartridge/syndicate + name = "\improper Detomatix cartridge" + icon_state = "cart" + access_remote_door = 1 + access_detonate_pda = 1 + remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing. + charges = 4 + +/obj/item/weapon/cartridge/proc/post_status(var/command, var/data1, var/data2) + + var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) + if(!frequency) return + + var/datum/signal/status_signal = new + status_signal.source = src + status_signal.transmission_method = 1 + status_signal.data["command"] = command + + switch(command) + if("message") + status_signal.data["msg1"] = data1 + status_signal.data["msg2"] = data2 + if(loc) + var/obj/item/PDA = loc + var/mob/user = PDA.fingerprintslast + if(istype(PDA.loc,/mob/living)) + SetName(PDA.loc) + log_admin("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]") + message_admins("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]") + + if("image") + status_signal.data["picture_state"] = data1 + + frequency.post_signal(src, status_signal) + + +/* + This generates the nano values of the cart menus. + Because we close the UI when we insert a new cart + we don't have to worry about null values on items + the user can't access. Well, unless they are href hacking. + But in that case their UI will just lock up. +*/ + + +/obj/item/weapon/cartridge/proc/create_NanoUI_values(mob/user as mob) + var/values[0] + + /* Signaler (Mode: 40) */ + + + if(istype(radio,/obj/item/radio/integrated/signal) && (mode==40)) + var/obj/item/radio/integrated/signal/R = radio + values["signal_freq"] = format_frequency(R.frequency) + values["signal_code"] = R.code + + + /* Station Display (Mode: 42) */ + + if(mode==42) + values["message1"] = message1 ? message1 : "(none)" + values["message2"] = message2 ? message2 : "(none)" + + + + /* Power Monitor (Mode: 43 / 433) */ + + if(mode==43 || mode==433) + var/list/sensors = list() + var/obj/machinery/power/sensor/MS = null + + for(var/obj/machinery/power/sensor/S in SSmachines.machinery) + sensors.Add(list(list("name_tag" = S.name_tag))) + if(S.name_tag == selected_sensor) + MS = S + values["power_sensors"] = sensors + if(selected_sensor && MS) + values["sensor_reading"] = MS.return_reading_data() + + /* Security Bot Control (Mode: 46) */ + + if(mode==46) + var/botsData[0] + var/beepskyData[0] + if(istype(radio,/obj/item/radio/integrated/beepsky)) + var/obj/item/radio/integrated/beepsky/SC = radio + beepskyData["active"] = SC.active + if(SC.active && !isnull(SC.botstatus)) + var/area/loca = SC.botstatus["loca"] + var/loca_name = sanitize(loca.name) + beepskyData["botstatus"] = list("loca" = loca_name, "mode" = SC.botstatus["mode"]) + else + beepskyData["botstatus"] = list("loca" = null, "mode" = -1) + var/botsCount=0 + if(SC.botlist && SC.botlist.len) + for(var/mob/living/bot/B in SC.botlist) + botsCount++ + if(B.loc) + botsData[++botsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]") + + if(!botsData.len) + botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) + + beepskyData["bots"] = botsData + beepskyData["count"] = botsCount + + else + beepskyData["active"] = 0 + botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) + beepskyData["botstatus"] = list("loca" = null, "mode" = null) + beepskyData["bots"] = botsData + beepskyData["count"] = 0 + + values["beepsky"] = beepskyData + + + /* MULEBOT Control (Mode: 48) */ + + if(mode==48) + var/mulebotsData[0] + var/count = 0 + + for(var/mob/living/bot/mulebot/M in GLOB.living_mob_list_) + if(!M.on) + continue + ++count + var/muleData[0] + muleData["name"] = M.suffix + muleData["location"] = get_area(M) + muleData["paused"] = M.paused + muleData["home"] = M.homeName + muleData["target"] = M.targetName + muleData["ref"] = "\ref[M]" + muleData["load"] = M.load ? M.load.name : "Nothing" + + mulebotsData[++mulebotsData.len] = muleData.Copy() + + values["mulebotcount"] = count + values["mulebots"] = mulebotsData + + + + /* Supply Shuttle Requests Menu (Mode: 47) */ + + if(mode==47) + var/supplyData[0] + var/datum/shuttle/autodock/ferry/supply/shuttle = supply_controller.shuttle + if (shuttle) + supplyData["shuttle_moving"] = shuttle.has_arrive_time() + supplyData["shuttle_eta"] = shuttle.eta_minutes() + supplyData["shuttle_loc"] = shuttle.at_station() ? "Station" : "Dock" + var/supplyOrderCount = 0 + var/supplyOrderData[0] + for(var/S in supply_controller.shoppinglist) + var/datum/supply_order/SO = S + + supplyOrderData[++supplyOrderData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "ApprovedBy" = SO.orderedby, "Comment" = html_encode(SO.comment)) + if(!supplyOrderData.len) + supplyOrderData[++supplyOrderData.len] = list("Number" = null, "Name" = null, "OrderedBy"=null) + + supplyData["approved"] = supplyOrderData + supplyData["approved_count"] = supplyOrderCount + + var/requestCount = 0 + var/requestData[0] + for(var/S in supply_controller.requestlist) + var/datum/supply_order/SO = S + requestCount++ + requestData[++requestData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "OrderedBy" = SO.orderedby, "Comment" = html_encode(SO.comment)) + if(!requestData.len) + requestData[++requestData.len] = list("Number" = null, "Name" = null, "orderedBy" = null, "Comment" = null) + + supplyData["requests"] = requestData + supplyData["requests_count"] = requestCount + + + values["supply"] = supplyData + + + + /* Janitor Supplies Locator (Mode: 49) */ + if(mode==49) + var/JaniData[0] + var/turf/cl = get_turf(src) + + if(cl) + JaniData["user_loc"] = list("x" = cl.x, "y" = cl.y) + else + JaniData["user_loc"] = list("x" = 0, "y" = 0) + var/MopData[0] + for(var/obj/item/weapon/mop/M in world) + var/turf/ml = get_turf(M) + if(ml) + if(ml.z != cl.z) + continue + var/direction = get_dir(src, M) + MopData[++MopData.len] = list ("x" = ml.x, "y" = ml.y, "dir" = uppertext(dir2text(direction)), "status" = M.reagents.total_volume ? "Wet" : "Dry") + + if(!MopData.len) + MopData[++MopData.len] = list("x" = 0, "y" = 0, dir=null, status = null) + + + var/BucketData[0] + for(var/obj/structure/mopbucket/B in world) + var/turf/bl = get_turf(B) + if(bl) + if(bl.z != cl.z) + continue + var/direction = get_dir(src,B) + BucketData[++BucketData.len] = list ("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.reagents.total_volume/100) + + if(!BucketData.len) + BucketData[++BucketData.len] = list("x" = 0, "y" = 0, dir=null, status = null) + + var/CbotData[0] + for(var/mob/living/bot/cleanbot/B in world) + var/turf/bl = get_turf(B) + if(bl) + if(bl.z != cl.z) + continue + var/direction = get_dir(src,B) + CbotData[++CbotData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.on ? "Online" : "Offline") + + + if(!CbotData.len) + CbotData[++CbotData.len] = list("x" = 0, "y" = 0, dir=null, status = null) + var/CartData[0] + for(var/obj/structure/janitorialcart/B in world) + var/turf/bl = get_turf(B) + if(bl) + if(bl.z != cl.z) + continue + var/direction = get_dir(src,B) + CartData[++CartData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.reagents.total_volume/100) + if(!CartData.len) + CartData[++CartData.len] = list("x" = 0, "y" = 0, dir=null, status = null) + + + + + JaniData["mops"] = MopData + JaniData["buckets"] = BucketData + JaniData["cleanbots"] = CbotData + JaniData["carts"] = CartData + values["janitor"] = JaniData + + return values + + + + + +/obj/item/weapon/cartridge/Topic(href, href_list) + ..() + + if (!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) + usr.unset_machine() + usr << browse(null, "window=pda") + return + + + + + switch(href_list["choice"]) + if("Send Signal") + spawn( 0 ) + radio:send_signal("ACTIVATE") + return + + if("Signal Frequency") + var/new_frequency = sanitize_frequency(radio:frequency + text2num(href_list["sfreq"])) + radio:set_frequency(new_frequency) + + if("Signal Code") + radio:code += text2num(href_list["scode"]) + radio:code = round(radio:code) + radio:code = min(100, radio:code) + radio:code = max(1, radio:code) + + if("Status") + switch(href_list["statdisp"]) + if("message") + post_status("message", message1, message2) + if("image") + post_status("image", href_list["image"]) + if("setmsg1") + message1 = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", message1) as text|null, 40), 40) + updateSelfDialog() + if("setmsg2") + message2 = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", message2) as text|null, 40), 40) + updateSelfDialog() + else + post_status(href_list["statdisp"]) + + if("Power Select") + selected_sensor = href_list["target"] + loc:mode = 433 + mode = 433 + if("Power Clear") + selected_sensor = null + loc:mode = 43 + mode = 43 + + if("MULEbot") + var/mob/living/bot/mulebot/M = locate(href_list["ref"]) + if(istype(M)) + M.obeyCommand(href_list["command"]) + + + return 1 diff --git a/code/game/objects/items/devices/PDA/radio.dm b/code/game/objects/items/devices/PDA/radio.dm new file mode 100644 index 00000000..299dc10c --- /dev/null +++ b/code/game/objects/items/devices/PDA/radio.dm @@ -0,0 +1,159 @@ +/obj/item/radio/integrated + name = "\improper PDA radio module" + desc = "An electronic radio system." + icon = 'icons/obj/module.dmi' + icon_state = "power_mod" + var/obj/item/device/pda/hostpda = null + + var/on = 0 //Are we currently active?? + var/menu_message = "" + + New() + ..() + if (istype(loc.loc, /obj/item/device/pda)) + hostpda = loc.loc + + proc/post_signal(var/freq, var/key, var/value, var/key2, var/value2, var/key3, var/value3, s_filter) + +// log_debug("Post: [freq]: [key]=[value], [key2]=[value2]") + + var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq) + + if(!frequency) return + + var/datum/signal/signal = new() + signal.source = src + signal.transmission_method = 1 + signal.data[key] = value + if(key2) + signal.data[key2] = value2 + if(key3) + signal.data[key3] = value3 + + frequency.post_signal(src, signal, filter = s_filter) + + return + + proc/generate_menu() + +/obj/item/radio/integrated/beepsky + var/list/botlist = null // list of bots + var/mob/living/bot/secbot/active // the active bot; if null, show bot list + var/list/botstatus // the status signal sent by the bot + + var/control_freq = BOT_FREQ + + // create a new QM cartridge, and register to receive bot control & beacon message + New() + ..() + spawn(5) + if(radio_controller) + radio_controller.add_object(src, control_freq, filter = RADIO_SECBOT) + + // receive radio signals + // can detect bot status signals + // create/populate list as they are recvd + + receive_signal(datum/signal/signal) +// var/obj/item/device/pda/P = src.loc + + /* + log_debug("recvd:[P] : [signal.source]") + + for(var/d in signal.data) + log_debug("- [d] = [signal.data[d]]") + + */ + if (signal.data["type"] == "secbot") + if(!botlist) + botlist = new() + + if(!(signal.source in botlist)) + botlist += signal.source + + if(active == signal.source) + var/list/b = signal.data + botstatus = b.Copy() + +// if (istype(P)) P.updateSelfDialog() + + Topic(href, href_list) + ..() + var/obj/item/device/pda/PDA = src.hostpda + + switch(href_list["op"]) + + if("control") + active = locate(href_list["bot"]) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT) + + if("scanbots") // find all bots + botlist = null + post_signal(control_freq, "command", "bot_status", s_filter = RADIO_SECBOT) + + if("botlist") + active = null + + if("stop", "go") + post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = RADIO_SECBOT) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT) + + if("summon") + post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , s_filter = RADIO_SECBOT) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT) + + +/obj/item/radio/integrated/beepsky/Destroy() + if(radio_controller) + radio_controller.remove_object(src, control_freq) + return ..() + +/* + * Radio Cartridge, essentially a signaler. + */ + + +/obj/item/radio/integrated/signal + var/frequency = 1457 + var/code = 30.0 + var/last_transmission + var/datum/radio_frequency/radio_connection + + Initialize() + if(!radio_controller) + return + + if (src.frequency < PUBLIC_LOW_FREQ || src.frequency > PUBLIC_HIGH_FREQ) + src.frequency = sanitize_frequency(src.frequency) + + set_frequency(frequency) + . = ..() + + proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency) + + proc/send_signal(message="ACTIVATE") + + if(last_transmission && world.time < (last_transmission + 5)) + return + last_transmission = world.time + + var/time = time2text(world.realtime,"hh:mm:ss") + var/turf/T = get_turf(src) + GLOB.lastsignalers.Add("[time] : [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) : [format_frequency(frequency)]/[code]") + + var/datum/signal/signal = new + signal.source = src + signal.encryption = code + signal.data["message"] = message + + radio_connection.post_signal(src, signal) + + return + +/obj/item/radio/integrated/signal/Destroy() + if(radio_controller) + radio_controller.remove_object(src, frequency) + ..() diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm new file mode 100644 index 00000000..c085e7c5 --- /dev/null +++ b/code/game/objects/items/devices/aicard.dm @@ -0,0 +1,151 @@ +/obj/item/weapon/aicard + name = "inteliCard" + icon = 'icons/obj/pda.dmi' + icon_state = "aicard" // aicard-full + item_state = "electronic" + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_BELT + var/flush = null + origin_tech = list(TECH_DATA = 4, TECH_MATERIAL = 4) + + var/mob/living/silicon/ai/carded_ai + +/obj/item/weapon/aicard/attack(mob/living/silicon/decoy/M as mob, mob/user as mob) + if (!istype (M, /mob/living/silicon/decoy)) + return ..() + else + M.death() + to_chat(user, "ERROR ERROR ERROR") + +/obj/item/weapon/aicard/attack_self(mob/user) + + ui_interact(user) + +/obj/item/weapon/aicard/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.inventory_state) + var/data[0] + data["has_ai"] = carded_ai != null + if(carded_ai) + data["name"] = carded_ai.name + data["hardware_integrity"] = carded_ai.hardware_integrity() + data["backup_capacitor"] = carded_ai.backup_capacitor() + data["radio"] = !carded_ai.ai_radio.disabledAi + data["wireless"] = !carded_ai.control_disabled + data["operational"] = carded_ai.stat != DEAD + data["flushing"] = flush + + var/laws[0] + for(var/datum/ai_law/AL in carded_ai.laws.all_laws()) + laws[++laws.len] = list("index" = AL.get_index(), "law" = sanitize(AL.law)) + data["laws"] = laws + data["has_laws"] = laws.len + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "aicard.tmpl", "[name]", 600, 400, state = state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/item/weapon/aicard/Topic(href, href_list, state) + if(..()) + return 1 + + if(!carded_ai) + return 1 + + var/user = usr + if (href_list["wipe"]) + var/confirm = alert("Are you sure you want to wipe this card's memory? This cannot be undone once started.", "Confirm Wipe", "Yes", "No") + if(confirm == "Yes" && (CanUseTopic(user, state) == STATUS_INTERACTIVE)) + admin_attack_log(user, carded_ai, "Wiped using \the [src.name]", "Was wiped with \the [src.name]", "used \the [src.name] to wipe") + flush = 1 + to_chat(carded_ai, "Your core files are being wiped!") + while (carded_ai && carded_ai.stat != DEAD) + carded_ai.adjustOxyLoss(2) + carded_ai.updatehealth() + sleep(10) + flush = 0 + if (href_list["radio"]) + carded_ai.ai_radio.disabledAi = text2num(href_list["radio"]) + to_chat(carded_ai, "Your Subspace Transceiver has been [carded_ai.ai_radio.disabledAi ? "disabled" : "enabled"]!") + to_chat(user, "You [carded_ai.ai_radio.disabledAi ? "disable" : "enable"] the AI's Subspace Transceiver.") + if (href_list["wireless"]) + carded_ai.control_disabled = text2num(href_list["wireless"]) + to_chat(carded_ai, "Your wireless interface has been [carded_ai.control_disabled ? "disabled" : "enabled"]!") + to_chat(user, "You [carded_ai.control_disabled ? "disable" : "enable"] the AI's wireless interface.") + update_icon() + return 1 + +/obj/item/weapon/aicard/update_icon() + overlays.Cut() + if(carded_ai) + if (!carded_ai.control_disabled) + overlays += image('icons/obj/pda.dmi', "aicard-on") + if(carded_ai.stat) + icon_state = "aicard-404" + else + icon_state = "aicard-full" + else + icon_state = "aicard" + +/obj/item/weapon/aicard/proc/grab_ai(var/mob/living/silicon/ai/ai, var/mob/living/user) + if(!ai.client) + to_chat(user, "ERROR: AI [ai.name] is offline. Unable to download.") + return 0 + + if(carded_ai) + to_chat(user, "Transfer failed: Existing AI found on remote terminal. Remove existing AI to install a new one.") + return 0 + + if(ai.malfunctioning && ai.uncardable) + to_chat(user, "ERROR: Remote transfer interface disabled.") + return 0 + + if(istype(ai.loc, /turf/)) + new /obj/structure/AIcore/deactivated(get_turf(ai)) + + ai.carded = 1 + admin_attack_log(user, ai, "Carded with [src.name]", "Was carded with [src.name]", "used the [src.name] to card") + src.SetName("[initial(name)] - [ai.name]") + + ai.forceMove(src) + ai.destroy_eyeobj(src) + ai.cancel_camera() + ai.control_disabled = 1 + ai.aiRestorePowerRoutine = 0 + ai.calculate_power_usage() + carded_ai = ai + + if(ai.client) + to_chat(ai, "You have been downloaded to a mobile storage device. Remote access lost.") + if(user.client) + to_chat(user, "Transfer successful: [ai.name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory.") + + ai.canmove = 1 + update_icon() + return 1 + +/obj/item/weapon/aicard/proc/clear() + if(carded_ai && istype(carded_ai.loc, /turf)) + carded_ai.canmove = 0 + carded_ai.carded = 0 + SetName(initial(name)) + carded_ai.calculate_power_usage() + carded_ai = null + update_icon() + +/obj/item/weapon/aicard/see_emote(mob/living/M, text) + if(carded_ai && carded_ai.client) + var/rendered = "[text]" + carded_ai.show_message(rendered, 2) + ..() + +/obj/item/weapon/aicard/show_message(msg, type, alt, alt_type) + if(carded_ai && carded_ai.client) + var/rendered = "[msg]" + carded_ai.show_message(rendered, type) + ..() + +/obj/item/weapon/aicard/relaymove(var/mob/user, var/direction) + if(user.stat || user.stunned) + return diff --git a/code/game/objects/items/devices/binoculars.dm b/code/game/objects/items/devices/binoculars.dm new file mode 100644 index 00000000..9277b304 --- /dev/null +++ b/code/game/objects/items/devices/binoculars.dm @@ -0,0 +1,21 @@ +/obj/item/device/binoculars + + name = "binoculars" + desc = "A pair of binoculars." + icon_state = "binoculars" + + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 5.0 + w_class = ITEM_SIZE_SMALL + throwforce = 5.0 + throw_range = 15 + throw_speed = 3 + + +/obj/item/device/binoculars/attack_self(mob/user) + zoom(user) + +/obj/item/device/binoculars/equipped(var/mob/user, var/slot) + ..() + if(zoom) + zoom(user) \ No newline at end of file diff --git a/code/game/objects/items/devices/cable_painter.dm b/code/game/objects/items/devices/cable_painter.dm new file mode 100644 index 00000000..6422c81e --- /dev/null +++ b/code/game/objects/items/devices/cable_painter.dm @@ -0,0 +1,41 @@ +obj/item/device/cable_painter + name = "cable painter" + desc = "A device for repainting cables." + description_info = "Use this device to select a preferred cable color. Apply it to a bundle of cables on your person, or use it on installed cabling on the floor to paint it in your chosen color." + description_fluff = "A device often used by spacefaring engineers to color-code their electrical systems. An experienced technician can identify traditional installations by color alone." + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "labeler0" + item_state = "flight" + var/color_selection + var/list/modes + w_class = ITEM_SIZE_SMALL + +obj/item/device/cable_painter/New() + ..() + color_selection = pick(possible_cable_coil_colours) + +obj/item/device/cable_painter/examine(var/user) + . = ..(user, 1) + if(.) + to_chat(user, "The color is currently set to [lowertext(color_selection)].") + +obj/item/device/cable_painter/attack_self(mob/user) + var/new_color_selection = input("What color would you like to use?", "Choose a Color", color_selection) as null|anything in possible_cable_coil_colours + if(new_color_selection && !user.incapacitated() && (src in user)) + color_selection = new_color_selection + to_chat(user, "You change the paint mode to [lowertext(color_selection)].") + +/obj/item/device/cable_painter/afterattack(var/atom/A, var/mob/user, var/proximity) + if(!proximity) + return ..() + if(istype(A, /obj/structure/cable)) + var/picked_color = possible_cable_coil_colours[color_selection] + if(!picked_color || A.color == picked_color) + return + A.color = picked_color + to_chat(user, "You set \the [A]'s color to [lowertext(color_selection)].") + else if(isCoil(A)) + var/obj/item/stack/cable_coil/c = A + c.set_cable_color(color_selection, user) + else + . = ..() diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm new file mode 100644 index 00000000..92f98e42 --- /dev/null +++ b/code/game/objects/items/devices/chameleonproj.dm @@ -0,0 +1,148 @@ +/obj/item/device/chameleon + name = "chameleon projector" + icon_state = "shield0" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + item_state = "electronic" + throwforce = 5.0 + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_SMALL + origin_tech = list(TECH_ILLEGAL = 4, TECH_MAGNET = 4) + var/can_use = 1 + var/obj/effect/dummy/chameleon/active_dummy = null + var/saved_item = /obj/item/weapon/cigbutt + var/saved_icon = 'icons/obj/clothing/masks.dmi' + var/saved_icon_state = "cigbutt" + var/saved_overlays + +/obj/item/device/chameleon/dropped() + disrupt() + ..() + +/obj/item/device/chameleon/equipped() + disrupt() + ..() + +/obj/item/device/chameleon/attack_self() + toggle() + +/obj/item/device/chameleon/afterattack(atom/target, mob/user , proximity) + if(!proximity) return + if(!active_dummy) + if(istype(target,/obj/item) && !istype(target, /obj/item/weapon/disk/nuclear)) + playsound(get_turf(src), 'sound/weapons/flash.ogg', 100, 1, -6) + to_chat(user, "Scanned [target].") + saved_item = target.type + saved_icon = target.icon + saved_icon_state = target.icon_state + saved_overlays = target.overlays + +/obj/item/device/chameleon/proc/toggle() + if(!can_use || !saved_item) return + if(active_dummy) + eject_all() + playsound(get_turf(src), 'sound/effects/pop.ogg', 100, 1, -6) + qdel(active_dummy) + active_dummy = null + to_chat(usr, "You deactivate the [src].") + var/obj/effect/overlay/T = new /obj/effect/overlay(get_turf(src)) + T.icon = 'icons/effects/effects.dmi' + flick("emppulse",T) + spawn(8) qdel(T) + else + playsound(get_turf(src), 'sound/effects/pop.ogg', 100, 1, -6) + var/obj/O = new saved_item(src) + if(!O) return + var/obj/effect/dummy/chameleon/C = new /obj/effect/dummy/chameleon(usr.loc) + C.activate(O, usr, saved_icon, saved_icon_state, saved_overlays, src) + qdel(O) + to_chat(usr, "You activate the [src].") + var/obj/effect/overlay/T = new/obj/effect/overlay(get_turf(src)) + T.icon = 'icons/effects/effects.dmi' + flick("emppulse",T) + spawn(8) qdel(T) + +/obj/item/device/chameleon/proc/disrupt(var/delete_dummy = 1) + if(active_dummy) + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread + spark_system.set_up(5, 0, src) + spark_system.attach(src) + spark_system.start() + eject_all() + if(delete_dummy) + qdel(active_dummy) + active_dummy = null + can_use = 0 + spawn(50) can_use = 1 + +/obj/item/device/chameleon/proc/eject_all() + for(var/atom/movable/A in active_dummy) + A.forceMove(active_dummy.loc) + if(ismob(A)) + var/mob/M = A + M.reset_view(null) + +/obj/effect/dummy/chameleon + name = "" + desc = "" + density = 0 + anchored = 1 + var/can_move = 1 + var/obj/item/device/chameleon/master = null + +/obj/effect/dummy/chameleon/proc/activate(var/obj/O, var/mob/M, new_icon, new_iconstate, new_overlays, var/obj/item/device/chameleon/C) + name = O.name + desc = O.desc + icon = new_icon + icon_state = new_iconstate + overlays = new_overlays + set_dir(O.dir) + M.forceMove(src) + master = C + master.active_dummy = src + +/obj/effect/dummy/chameleon/attackby() + for(var/mob/M in src) + to_chat(M, "Your chameleon-projector deactivates.") + master.disrupt() + +/obj/effect/dummy/chameleon/attack_hand() + for(var/mob/M in src) + to_chat(M, "Your chameleon-projector deactivates.") + master.disrupt() + +/obj/effect/dummy/chameleon/ex_act() + for(var/mob/M in src) + to_chat(M, "Your chameleon-projector deactivates.") + master.disrupt() + +/obj/effect/dummy/chameleon/bullet_act() + for(var/mob/M in src) + to_chat(M, "Your chameleon-projector deactivates.") + ..() + master.disrupt() + +/obj/effect/dummy/chameleon/relaymove(var/mob/user, direction) + var/area/A = get_area(src) + if(!A || !A.has_gravity()) return //No magical space movement! + + if(can_move) + can_move = 0 + switch(user.bodytemperature) + if(300 to INFINITY) + spawn(10) can_move = 1 + if(295 to 300) + spawn(13) can_move = 1 + if(280 to 295) + spawn(16) can_move = 1 + if(260 to 280) + spawn(20) can_move = 1 + else + spawn(25) can_move = 1 + step(src, direction) + return + +/obj/effect/dummy/chameleon/Destroy() + master.disrupt(0) + ..() diff --git a/code/game/objects/items/devices/compass.dm b/code/game/objects/items/devices/compass.dm new file mode 100644 index 00000000..867f9dd1 --- /dev/null +++ b/code/game/objects/items/devices/compass.dm @@ -0,0 +1,24 @@ +/obj/item/device/compass + + name = "Compass" + desc = "A small metallic device with a swivel on top of its face. You could find your location with this." + icon_state = "compass" + + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 5.0 + w_class = ITEM_SIZE_SMALL + throwforce = 5.0 + throw_range = 15 + throw_speed = 3 + + //matter = list("metal" = 50,"glass" = 50) + + +/obj/item/device/compass/attack_self(mob/user) + var/turf/T = get_turf(src) + to_chat(user, "You start finding your location...") + if(do_after(user, 10)) + to_chat(user, "It looks like I'm at [T.x] [T.y]") + else + to_chat(user, "You lower the compass and stop.") + diff --git a/code/game/objects/items/devices/debugger.dm b/code/game/objects/items/devices/debugger.dm new file mode 100644 index 00000000..3adc3a05 --- /dev/null +++ b/code/game/objects/items/devices/debugger.dm @@ -0,0 +1,46 @@ +/** + * Multitool -- A multitool is used for hacking electronic devices. + * TO-DO -- Using it as a power measurement tool for cables etc. Nannek. + * + */ + +/obj/item/device/debugger + name = "debugger" + desc = "Used to debug electronic equipment." + icon = 'icons/obj/hacktool.dmi' + icon_state = "hacktool-g" + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 5.0 + w_class = ITEM_SIZE_SMALL + throwforce = 5.0 + throw_range = 15 + throw_speed = 3 + desc = "You can use this on airlocks or APCs to try to hack them without cutting wires." + + matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 20) + + origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1) + var/obj/machinery/telecomms/buffer // simple machine buffer for device linkage + +/obj/item/device/debugger/is_used_on(obj/O, mob/user) + if(istype(O, /obj/machinery/power/apc)) + var/obj/machinery/power/apc/A = O + if(A.emagged || A.hacker) + to_chat(user, "There is a software error with the device.") + else + to_chat(user, "The device's software appears to be fine.") + return 1 + if(istype(O, /obj/machinery/door)) + var/obj/machinery/door/D = O + if(D.operating == -1) + to_chat(user, "There is a software error with the device.") + else + to_chat(user, "The device's software appears to be fine.") + return 1 + else if(istype(O, /obj/machinery)) + var/obj/machinery/A = O + if(A.emagged) + to_chat(user, "There is a software error with the device.") + else + to_chat(user, "The device's software appears to be fine.") + return 1 diff --git a/code/game/objects/items/devices/dociler.dm b/code/game/objects/items/devices/dociler.dm new file mode 100644 index 00000000..68675660 --- /dev/null +++ b/code/game/objects/items/devices/dociler.dm @@ -0,0 +1,59 @@ +/obj/item/device/dociler + name = "dociler" + desc = "A complex single use recharging injector that spreads a complex neurological serum that makes animals docile and friendly. Somewhat." + w_class = ITEM_SIZE_NORMAL + origin_tech = list(TECH_BIO = 5, TECH_MATERIAL = 2) + icon_state = "animal_tagger1" + item_icons = list( + slot_l_hand_str = 'icons/mob/onmob/items/lefthand_guns.dmi', + slot_r_hand_str = 'icons/mob/onmob/items/righthand_guns.dmi', + ) + item_state = "gun" + force = 1 + var/loaded = 1 + var/mode = "completely" + +/obj/item/device/dociler/examine(var/mob/user) + . = ..(user) + to_chat(user, "It is currently set to [mode] docile mode.") + +/obj/item/device/dociler/attack_self(var/mob/user) + if(mode == "somewhat") + mode = "completely" + else + mode = "somewhat" + + to_chat(user, "You set \the [src] to [mode] docile mode.") + +/obj/item/device/dociler/attack(var/mob/living/L, var/mob/user) + if(!istype(L, /mob/living/simple_animal)) + to_chat(user, "\The [src] cannot not work on \the [L].") + return + + if(!loaded) + to_chat(user, "\The [src] isn't loaded!") + return + + user.visible_message("\The [user] thrusts \the [src] deep into \the [L]'s head, injecting something!") + to_chat(L, "You feel pain as \the [user] injects something into you. All of a sudden you feel as if [user] is the friendliest and nicest person you've ever know. You want to be friends with him and all his friends.") + if(mode == "somewhat") + L.faction = user.faction + else + L.faction = null + if(istype(L,/mob/living/simple_animal/hostile)) + var/mob/living/simple_animal/hostile/H = L + H.LoseTarget() + H.attack_same = 0 + H.friends += weakref(user) + L.desc += "
            It looks especially docile." + var/name = input(user, "Would you like to rename \the [L]?", "Dociler", L.name) as text + if(length(name)) + L.real_name = name + L.SetName(name) + + loaded = 0 + icon_state = "animal_tagger0" + spawn(1450) + loaded = 1 + icon_state = "animal_tagger1" + src.visible_message("\The [src] beeps, refilling itself.") \ No newline at end of file diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm new file mode 100644 index 00000000..b85cc49b --- /dev/null +++ b/code/game/objects/items/devices/flash.dm @@ -0,0 +1,200 @@ +/obj/item/device/flash + name = "flash" + desc = "A device that produces a bright flash of light, designed to stun and disorient an attacker." + icon_state = "flash" + item_state = "flashtool" + throwforce = 5 + w_class = ITEM_SIZE_SMALL + throw_speed = 4 + throw_range = 10 + obj_flags = OBJ_FLAG_CONDUCTIBLE + origin_tech = list(TECH_MAGNET = 2, TECH_COMBAT = 1) + + var/times_used = 0 //Number of times it's been used. + var/broken = 0 //Is the flash burnt out? + var/last_used = 0 //last world.time it was used. + var/str_min = 2 //how weak the effect CAN be + var/str_max = 7 //how powerful the effect COULD be + +/obj/item/device/flash/proc/clown_check(var/mob/user) + if(user && (CLUMSY in user.mutations) && prob(50)) + to_chat(user, "\The [src] slips out of your hand.") + user.drop_item() + return 0 + return 1 + +/obj/item/device/flash/proc/flash_recharge() + //capacitor recharges over time + for(var/i=0, i<3, i++) + if(last_used+600 > world.time) + break + last_used += 600 + times_used -= 2 + 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) + if(!user || !M) return //sanity + admin_attack_log(user, M, "flashed their victim using \a [src].", "Was flashed by \a [src].", "used \a [src] to flash") + + if(!clown_check(user)) return + if(broken) + to_chat(user, "\The [src] is broken.") + return + + flash_recharge() + + //spamming the flash before it's fully charged (60seconds) increases the chance of it breaking + //It will never break on the first use. + switch(times_used) + if(0 to 5) + last_used = world.time + if(prob(times_used)) //if you use it 5 times in a minute it has a 10% chance to break! + broken = 1 + to_chat(user, "The bulb has burnt out!") + icon_state = "[initial(icon_state)]_burnt" + return + times_used++ + else //can only use it 5 times a minute + to_chat(user, "*click* *click*") + return + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(M) + + playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1) + var/flashfail = 0 + + if(iscarbon(M)) + if(M.stat!=DEAD) + var/mob/living/carbon/C = M + var/safety = C.eyecheck() + if(safety < FLASH_PROTECTION_MODERATE) + var/flash_strength = (rand(str_min,str_max)) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + flash_strength = round(H.species.flash_mod * flash_strength) + if(flash_strength > 0) + M.flash_eyes(FLASH_PROTECTION_MODERATE - safety) + M.Stun(flash_strength / 2) + M.eye_blurry += flash_strength + M.confused += (flash_strength + 2) + if(flash_strength > 3) + M.drop_l_hand() + M.drop_r_hand() + if(flash_strength > 5) + M.Weaken(2) + else + flashfail = 1 + + else if(issilicon(M)) + M.Weaken(rand(str_min,6)) + else + flashfail = 1 + + if(isrobot(user)) + spawn(0) + var/atom/movable/overlay/animation = new(user.loc) + animation.plane = user.plane + animation.layer = user.layer + 0.01 + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = user + flick("blspell", animation) + sleep(5) + qdel(animation) + + if(!flashfail) + flick("[initial(icon_state)]_on", src) + if(!issilicon(M)) + user.visible_message("[user] blinds [M] with \the [src]!") + else + user.visible_message("[user] overloads [M]'s sensors with \the [src]!") + else + user.visible_message("[user] fails to blind [M] with \the [src]!") + return + + + + +/obj/item/device/flash/attack_self(mob/living/carbon/user as mob, flag = 0, emp = 0) + if(!user || !clown_check(user)) return + + if(broken) + user.show_message("The [src.name] is broken", 2) + return + + flash_recharge() + + //spamming the flash before it's fully charged (60seconds) increases the chance of it breaking + //It will never break on the first use. + switch(times_used) + if(0 to 5) + if(prob(2*times_used)) //if you use it 5 times in a minute it has a 10% chance to break! + broken = 1 + to_chat(user, "The bulb has burnt out!") + icon_state = "[initial(icon_state)]_burnt" + return + times_used++ + else //can only use it 5 times a minute + user.show_message("*click* *click*", 2) + return + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1) + flick("[initial(icon_state)]_on", src) + if(user && isrobot(user)) + spawn(0) + var/atom/movable/overlay/animation = new(user.loc) + animation.plane = user.plane + animation.layer = user.layer + 0.01 + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = user + flick("blspell", animation) + sleep(5) + qdel(animation) + + for(var/mob/living/carbon/M in oviewers(3, null)) + var/safety = M.eyecheck() + if(safety < FLASH_PROTECTION_MODERATE) + if(!M.blinded) + M.flash_eyes() + M.eye_blurry += 2 + + return + +/obj/item/device/flash/emp_act(severity) + if(broken) return + flash_recharge() + switch(times_used) + if(0 to 5) + if(prob(2*times_used)) + broken = 1 + icon_state = "[initial(icon_state)]_burnt" + return + times_used++ + if(istype(loc, /mob/living/carbon)) + var/mob/living/carbon/M = loc + var/safety = M.eyecheck() + if(safety < FLASH_PROTECTION_MODERATE) + M.Weaken(10) + M.flash_eyes() + for(var/mob/O in viewers(M, null)) + O.show_message("[M] is blinded by the [name]!") + ..() + +/obj/item/device/flash/synthetic //not for regular use, weaker effects + name = "modified flash" + desc = "A device that produces a bright flash of light. This is a specialized version designed specifically for use in camera systems." + icon_state = "sflash" + str_min = 1 + str_max = 4 + +/obj/item/device/flash/advanced + name = "advanced flash" + desc = "A device that produces a very bright flash of light. This is an advanced and expensive version often issued to VIPs." + icon_state = "advflash" + origin_tech = list(TECH_COMBAT = 2, TECH_MAGNET = 2) + str_min = 3 + str_max = 8 \ No newline at end of file diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm new file mode 100644 index 00000000..91cf7f17 --- /dev/null +++ b/code/game/objects/items/devices/flashlight.dm @@ -0,0 +1,352 @@ +/obj/item/device/flashlight + name = "flashlight" + desc = "A hand-held emergency light." + icon = 'icons/obj/lighting.dmi' + icon_state = "flashlight" + item_state = "flashlight" + w_class = ITEM_SIZE_SMALL + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + + matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 20) + + action_button_name = "Toggle Flashlight" + var/on = 0 + var/brightness_on = 4 //range of light when on + var/activation_sound = 'sound/effects/flashlight.ogg' + var/flashlight_power //luminosity of light when on, can be negative + +/obj/item/device/flashlight/Initialize() + . = ..() + update_icon() + +/obj/item/device/flashlight/update_icon() + if(on) + icon_state = "[initial(icon_state)]-on" + if(flashlight_power) + set_light(l_range = brightness_on, l_power = flashlight_power) + else + set_light(brightness_on) + else + icon_state = "[initial(icon_state)]" + set_light(0) + +/obj/item/device/flashlight/attack_self(mob/user) + if(!isturf(user.loc)) + to_chat(user, "You cannot turn the light on while in this [user.loc].")//To prevent some lighting anomalities. + + return 0 + on = !on + if(activation_sound) + playsound(src.loc, activation_sound, 75, 1) + update_icon() + user.update_action_buttons() + return 1 + + +/obj/item/device/flashlight/attack(mob/living/M as mob, mob/living/user as mob) + add_fingerprint(user) + if(on && user.zone_sel.selecting == BP_EYES) + + if((CLUMSY in user.mutations) && prob(50)) //too dumb to use flashlight properly + return ..() //just hit them in the head + + var/mob/living/carbon/human/H = M //mob has protective eyewear + if(istype(H)) + for(var/obj/item/clothing/C in list(H.head,H.wear_mask,H.glasses)) + if(istype(C) && (C.body_parts_covered & EYES)) + to_chat(user, "You're going to need to remove [C] first.") + return + + var/obj/item/organ/vision + if(!H.species.vision_organ || !H.should_have_organ(H.species.vision_organ)) + to_chat(user, "You can't find anything on [H] to direct [src] into!") + return + + vision = H.internal_organs_by_name[H.species.vision_organ] + if(!vision) + vision = H.species.has_organ[H.species.vision_organ] + to_chat(user, "\The [H] is missing \his [initial(vision.name)]!") + return + + user.visible_message("\The [user] directs [src] into [M]'s [vision.name].", \ + "You direct [src] into [M]'s [vision.name].") + + inspect_vision(vision, user) + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //can be used offensively + M.flash_eyes() + else + return ..() + +/obj/item/device/flashlight/proc/inspect_vision(obj/item/organ/vision, mob/living/user) + var/mob/living/carbon/human/H = vision.owner + + if(H == user) //can't look into your own eyes buster + return + + if(vision.robotic < ORGAN_ROBOT ) + + if(vision.owner.stat == DEAD || H.blinded) //mob is dead or fully blind + to_chat(user, "\The [H]'s pupils do not react to the light!") + return + if(XRAY in H.mutations) + to_chat(user, "\The [H]'s pupils give an eerie glow!") + if(vision.damage) + to_chat(user, "There's visible damage to [H]'s [vision.name]!") + else if(H.eye_blurry) + to_chat(user, "\The [H]'s pupils react slower than normally.") + if(H.getBrainLoss() > 15) + to_chat(user, "There's visible lag between left and right pupils' reactions.") + + var/list/pinpoint = list(/datum/reagent/tramadol/oxycodone=1,/datum/reagent/tramadol=5) + var/list/dilating = list(/datum/reagent/space_drugs=5,/datum/reagent/mindbreaker=1,/datum/reagent/adrenaline=1) + if(H.reagents.has_any_reagent(pinpoint) || H.ingested.has_any_reagent(pinpoint)) + to_chat(user, "\The [H]'s pupils are already pinpoint and cannot narrow any more.") + else if(H.shock_stage >= 30 || H.reagents.has_any_reagent(dilating) || H.ingested.has_any_reagent(dilating)) + to_chat(user, "\The [H]'s pupils narrow slightly, but are still very dilated.") + else + to_chat(user, "\The [H]'s pupils narrow.") + + //if someone wants to implement inspecting robot eyes here would be the place to do it. + +/obj/item/device/flashlight/upgraded + name = "\improper LED flashlight" + desc = "An energy efficient flashlight." + icon_state = "biglight" + item_state = "biglight" + brightness_on = 6 + flashlight_power = 3 + +/obj/item/device/flashlight/flashdark + name = "flashdark" + desc = "A strange device manufactured with mysterious elements that somehow emits darkness. Or maybe it just sucks in light? Nobody knows for sure." + icon_state = "flashdark" + item_state = "flashdark" + w_class = ITEM_SIZE_NORMAL + brightness_on = 8 + flashlight_power = -6 + +/obj/item/device/flashlight/pen + name = "penlight" + desc = "A pen-sized light, used by medical staff." + icon_state = "penlight" + item_state = "" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_EARS + brightness_on = 2 + w_class = ITEM_SIZE_TINY + +/obj/item/device/flashlight/maglight + name = "maglight" + desc = "A very, very heavy duty flashlight." + icon_state = "maglight" + item_state = "maglight" + force = 10 + attack_verb = list ("smacked", "thwacked", "thunked") + matter = list(DEFAULT_WALL_MATERIAL = 200,"glass" = 50) + hitsound = "swing_hit" + +/obj/item/device/flashlight/drone + name = "low-power flashlight" + desc = "A miniature lamp, that might be used by small robots." + icon_state = "penlight" + item_state = "" + obj_flags = OBJ_FLAG_CONDUCTIBLE + brightness_on = 2 + w_class = ITEM_SIZE_TINY + + +// the desk lamps are a bit special +/obj/item/device/flashlight/lamp + name = "desk lamp" + desc = "A desk lamp with an adjustable mount." + icon_state = "lamp" + item_state = "lamp" + brightness_on = 5 + w_class = ITEM_SIZE_LARGE + obj_flags = OBJ_FLAG_CONDUCTIBLE + + on = 1 + + +// green-shaded desk lamp +/obj/item/device/flashlight/lamp/green + desc = "A classic green-shaded desk lamp." + icon_state = "lampgreen" + item_state = "lampgreen" + brightness_on = 4 + light_color = "#ffc58f" + +// FLARES + +/obj/item/device/flashlight/flare + name = "flare" + desc = "A red standard-issue flare. There are instructions on the side reading 'pull cord, make light'." + w_class = ITEM_SIZE_TINY + brightness_on = 8 // Pretty bright. + light_power = 3 + light_color = "#e58775" + icon_state = "flare" + item_state = "flare" + action_button_name = null //just pull it manually, neckbeard. + var/fuel = 0 + var/on_damage = 7 + var/produce_heat = 1500 + activation_sound = 'sound/effects/flare.ogg' + +/obj/item/device/flashlight/flare/New() + fuel = rand(800, 1000) // Sorry for changing this so much but I keep under-estimating how long X number of ticks last in seconds. + ..() + +/obj/item/device/flashlight/flare/Process() + var/turf/pos = get_turf(src) + if(pos) + pos.hotspot_expose(produce_heat, 5) + fuel = max(fuel - 1, 0) + if(!fuel || !on) + turn_off() + if(!fuel) + src.icon_state = "[initial(icon_state)]-empty" + STOP_PROCESSING(SSobj, src) + +/obj/item/device/flashlight/flare/proc/turn_off() + on = 0 + src.force = initial(src.force) + src.damtype = initial(src.damtype) + update_icon() + +/obj/item/device/flashlight/flare/attack_self(mob/user) + if(turn_on(user)) + user.visible_message("\The [user] activates \the [src].", "You pull the cord on the flare, activating it!") + playsound(src.loc, activation_sound, 75, 1)//IT HAS AN ACTIVATION SOUND BUT NO ..() GOOD JOB BAY REALLY DID A GOOD ONE HERE + + +/obj/item/device/flashlight/flare/proc/turn_on(var/mob/user) + if(on) + return FALSE + if(!fuel) + if(user) + to_chat(user, "It's out of fuel.") + return FALSE + on = TRUE + force = on_damage + damtype = "fire" + START_PROCESSING(SSobj, src) + update_icon() + return 1 + +//Glowsticks +/obj/item/device/flashlight/glowstick + name = "green glowstick" + desc = "A military-grade glowstick." + w_class = 2.0 + brightness_on = 4 + light_power = 2 + color = "#49f37c" + icon_state = "glowstick" + item_state = "glowstick" + randpixel = 12 + var/fuel = 0 + activation_sound = null + +/obj/item/device/flashlight/glowstick/New() + fuel = rand(1600, 2000) + light_color = color + ..() + +/obj/item/device/flashlight/glowstick/Destroy() + . = ..() + STOP_PROCESSING(SSobj, src) + +/obj/item/device/flashlight/glowstick/Process() + fuel = max(fuel - 1, 0) + if(!fuel) + turn_off() + STOP_PROCESSING(SSobj, src) + update_icon() + +/obj/item/device/flashlight/glowstick/proc/turn_off() + on = 0 + update_icon() + +/obj/item/device/flashlight/glowstick/update_icon() + item_state = "glowstick" + overlays.Cut() + if(!fuel) + icon_state = "glowstick-empty" + set_light(0) + else if (on) + var/image/I = overlay_image(icon,"glowstick-on",color) + I.blend_mode = BLEND_ADD + overlays += I + item_state = "glowstick-on" + set_light(brightness_on) + else + icon_state = "glowstick" + var/mob/M = loc + if(istype(M)) + if(M.l_hand == src) + M.update_inv_l_hand() + if(M.r_hand == src) + M.update_inv_r_hand() + +/obj/item/device/flashlight/glowstick/attack_self(mob/user) + + if(!fuel) + to_chat(user,"\The [src] is spent.") + return + if(on) + to_chat(user,"\The [src] is already lit.") + return + + . = ..() + if(.) + user.visible_message("[user] cracks and shakes the glowstick.", "You crack and shake the glowstick, turning it on!") + START_PROCESSING(SSobj, src) + +/obj/item/device/flashlight/glowstick/red + name = "red glowstick" + color = "#fc0f29" + +/obj/item/device/flashlight/glowstick/blue + name = "blue glowstick" + color = "#599dff" + +/obj/item/device/flashlight/glowstick/orange + name = "orange glowstick" + color = "#fa7c0b" + +/obj/item/device/flashlight/glowstick/yellow + name = "yellow glowstick" + color = "#fef923" + +/obj/item/device/flashlight/glowstick/random + name = "glowstick" + desc = "A party-grade glowstick." + color = "#ff00ff" + +/obj/item/device/flashlight/glowstick/random/New() + color = rgb(rand(50,255),rand(50,255),rand(50,255)) + ..() + +/obj/item/device/flashlight/slime + gender = PLURAL + name = "glowing slime extract" + desc = "A glowing ball of what appears to be amber." + icon = 'icons/obj/lighting.dmi' + icon_state = "floor1" //not a slime extract sprite but... something close enough! + item_state = "slime" + w_class = ITEM_SIZE_TINY + brightness_on = 6 + on = 1 //Bio-luminesence has one setting, on. + +/obj/item/device/flashlight/slime/New() + ..() + set_light(brightness_on) + +/obj/item/device/flashlight/slime/update_icon() + return + +/obj/item/device/flashlight/slime/attack_self(mob/user) + return //Bio-luminescence does not toggle. diff --git a/code/game/objects/items/devices/floor_painter.dm b/code/game/objects/items/devices/floor_painter.dm new file mode 100644 index 00000000..4bf92bfa --- /dev/null +++ b/code/game/objects/items/devices/floor_painter.dm @@ -0,0 +1,161 @@ +/obj/item/device/floor_painter + name = "floor painter" + icon = 'icons/obj/device.dmi' + icon_state = "flpainter" + item_state = "fl_painter" + desc = "A slender and none-too-sophisticated device capable of painting, erasing, and applying decals to most types of floors." + description_info = "Use this item in your hand to access a menu in which you may change the type of decal, applied direction, and color. Click any accessible tile on the floor to apply your choice." + description_fluff = "This ubiquitous maintenance-grade floor painter isn't as fancy or convenient as modern consumer models, but with an internal synthesizer it never runs out of pigment!" + description_antag = "This thing would be perfect for vandalism. Could you write your name in the halls?" + + var/decal = "remove all decals" + var/paint_dir = "precise" + var/paint_colour = COLOR_WHITE + + var/list/decals = list( + "quarter-turf" = list("path" = /obj/effect/floor_decal/corner, "precise" = 1, "coloured" = 1), + "hazard stripes" = list("path" = /obj/effect/floor_decal/industrial/warning), + "corner, hazard" = list("path" = /obj/effect/floor_decal/industrial/warning/corner), + "hatched marking" = list("path" = /obj/effect/floor_decal/industrial/hatch, "coloured" = 1), + "dashed outline" = list("path" = /obj/effect/floor_decal/industrial/outline, "coloured" = 1), + "loading sign" = list("path" = /obj/effect/floor_decal/industrial/loading), + "mosaic, large" = list("path" = /obj/effect/floor_decal/chapel), + "1" = list("path" = /obj/effect/floor_decal/sign), + "2" = list("path" = /obj/effect/floor_decal/sign/two), + "A" = list("path" = /obj/effect/floor_decal/sign/a), + "B" = list("path" = /obj/effect/floor_decal/sign/b), + "C" = list("path" = /obj/effect/floor_decal/sign/c), + "D" = list("path" = /obj/effect/floor_decal/sign/d), + "M" = list("path" = /obj/effect/floor_decal/sign/m), + "V" = list("path" = /obj/effect/floor_decal/sign/v), + "CMO" = list("path" = /obj/effect/floor_decal/sign/cmo), + "Ex" = list("path" = /obj/effect/floor_decal/sign/ex), + "Psy" = list("path" = /obj/effect/floor_decal/sign/p), + "remove all decals" = list("path" = /obj/effect/floor_decal/reset) + ) + var/list/paint_dirs = list( + "north" = NORTH, + "northwest" = NORTHWEST, + "west" = WEST, + "southwest" = SOUTHWEST, + "south" = SOUTH, + "southeast" = SOUTHEAST, + "east" = EAST, + "northeast" = NORTHEAST, + "precise" = 0 + ) + +/obj/item/device/floor_painter/afterattack(var/atom/A, var/mob/user, proximity, params) + if(!proximity) + return + + var/turf/simulated/floor/F = A + if(!istype(F)) + to_chat(user, "\The [src] can only be used on actual flooring.") + return + + if(!F.flooring.can_paint || F.broken || F.burnt) + to_chat(user, "\The [src] cannot paint broken tiles.") + return + + var/list/decal_data = decals[decal] + var/config_error + if(!islist(decal_data)) + config_error = 1 + var/painting_decal + if(!config_error) + painting_decal = decal_data["path"] + if(!ispath(painting_decal)) + config_error = 1 + + if(config_error) + to_chat(user, "\The [src] flashes an error light. You might need to reconfigure it.") + return + + if(F.decals && F.decals.len > 5 && painting_decal != /obj/effect/floor_decal/reset) + to_chat(user, "\The [F] has been painted too much; you need to clear it off.") + return + + var/painting_dir = 0 + if(paint_dir == "precise") + if(!decal_data["precise"]) + painting_dir = user.dir + else + var/list/mouse_control = params2list(params) + var/mouse_x = text2num(mouse_control["icon-x"]) + var/mouse_y = text2num(mouse_control["icon-y"]) + if(isnum(mouse_x) && isnum(mouse_y)) + if(mouse_x <= 16) + if(mouse_y <= 16) + painting_dir = WEST + else + painting_dir = NORTH + else + if(mouse_y <= 16) + painting_dir = SOUTH + else + painting_dir = EAST + else + painting_dir = user.dir + else if(paint_dirs[paint_dir]) + painting_dir = paint_dirs[paint_dir] + + var/painting_colour + if(decal_data["coloured"] && paint_colour) + painting_colour = paint_colour + + new painting_decal(F, painting_dir, painting_colour) + +/obj/item/device/floor_painter/attack_self(var/mob/user) + var/choice = input("Do you wish to change the decal type, paint direction, or paint colour?") as null|anything in list("Decal","Direction", "Colour") + if(choice == "Decal") + choose_decal() + else if(choice == "Direction") + choose_direction() + else if(choice == "Colour") + choose_colour() + +/obj/item/device/floor_painter/examine(mob/user) + . = ..(user) + to_chat(user, "It is configured to produce the '[decal]' decal with a direction of '[paint_dir]' using [paint_colour] paint.") + +/obj/item/device/floor_painter/verb/choose_colour() + set name = "Choose Colour" + set desc = "Choose a floor painter colour." + set category = "Object" + set src in usr + + if(usr.incapacitated()) + return + var/new_colour = input(usr, "Choose a colour.", "Floor painter", paint_colour) as color|null + if(new_colour && new_colour != paint_colour) + paint_colour = new_colour + to_chat(usr, "You set \the [src] to paint with a new colour.") + +/obj/item/device/floor_painter/verb/choose_decal() + set name = "Choose Decal" + set desc = "Choose a floor painter decal." + set category = "Object" + set src in usr + + if(usr.incapacitated()) + return + + var/new_decal = input("Select a decal.") as null|anything in decals + if(new_decal && !isnull(decals[new_decal])) + decal = new_decal + to_chat(usr, "You set \the [src] decal to '[decal]'.") + +/obj/item/device/floor_painter/verb/choose_direction() + set name = "Choose Direction" + set desc = "Choose a floor painter direction." + set category = "Object" + set src in usr + + if(usr.incapacitated()) + return + + var/new_dir = input("Select a direction.") as null|anything in paint_dirs + if(new_dir && !isnull(paint_dirs[new_dir])) + paint_dir = new_dir + to_chat(usr, "You set \the [src] direction to '[paint_dir]'.") diff --git a/code/game/objects/items/devices/geiger.dm b/code/game/objects/items/devices/geiger.dm new file mode 100644 index 00000000..953e44ec --- /dev/null +++ b/code/game/objects/items/devices/geiger.dm @@ -0,0 +1,55 @@ +//Geiger counter +//Rewritten version of TG's geiger counter +//I opted to show exact radiation levels + +/obj/item/device/geiger + name = "geiger counter" + desc = "A handheld device used for detecting and measuring radiation in an area." + description_info = "By using this item, you may toggle its scanning mode on and off. Examine it while it's on to check for ambient radiation." + description_fluff = "For centuries geiger counters have been saving the lives of unsuspecting laborers and technicians. You can never be too careful around radiation." + icon_state = "geiger_off" + item_state = "multitool" + w_class = ITEM_SIZE_SMALL + var/scanning = 0 + var/radiation_count = 0 + +/obj/item/device/geiger/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/item/device/geiger/Destroy() + . = ..() + STOP_PROCESSING(SSobj, src) + +/obj/item/device/geiger/Process() + if(!scanning) + return + radiation_count = radiation_repository.get_rads_at_turf(get_turf(src)) + update_icon() + +/obj/item/device/geiger/examine(mob/user) + . = ..(user) + var/msg = "[scanning ? "ambient" : "stored"] Radiation level: [radiation_count ? radiation_count : "0"] Bq." + if(radiation_count > RAD_LEVEL_LOW) + to_chat(user, "[msg]") + else + to_chat(user, "[msg]") + +/obj/item/device/geiger/attack_self(var/mob/user) + scanning = !scanning + update_icon() + to_chat(user, "\icon[src] You switch [scanning ? "on" : "off"] [src].") + +/obj/item/device/geiger/update_icon() + if(!scanning) + icon_state = "geiger_off" + return 1 + + switch(radiation_count) + if(null) icon_state = "geiger_on_1" + if(-INFINITY to RAD_LEVEL_LOW) icon_state = "geiger_on_1" + if(RAD_LEVEL_LOW + 0.01 to RAD_LEVEL_MODERATE) icon_state = "geiger_on_2" + if(RAD_LEVEL_MODERATE + 0.1 to RAD_LEVEL_HIGH) icon_state = "geiger_on_3" + if(RAD_LEVEL_HIGH + 1 to RAD_LEVEL_VERY_HIGH) icon_state = "geiger_on_4" + if(RAD_LEVEL_VERY_HIGH + 1 to INFINITY) icon_state = "geiger_on_5" + diff --git a/code/game/objects/items/devices/hacktool.dm b/code/game/objects/items/devices/hacktool.dm new file mode 100644 index 00000000..b0fd185a --- /dev/null +++ b/code/game/objects/items/devices/hacktool.dm @@ -0,0 +1,95 @@ +/obj/item/device/multitool/hacktool + var/is_hacking = 0 + var/max_known_targets + + var/in_hack_mode = 0 + var/list/known_targets + var/list/supported_types + var/datum/topic_state/default/must_hack/hack_state + +/obj/item/device/multitool/hacktool/New() + ..() + known_targets = list() + max_known_targets = 5 + rand(1,3) + supported_types = list(/obj/machinery/door/airlock) + hack_state = new(src) + +/obj/item/device/multitool/hacktool/Destroy() + for(var/T in known_targets) + var/atom/target = T + GLOB.destroyed_event.unregister(target, src) + known_targets.Cut() + qdel(hack_state) + hack_state = null + return ..() + +/obj/item/device/multitool/hacktool/attackby(var/obj/W, var/mob/user) + if(isScrewdriver(W)) + in_hack_mode = !in_hack_mode + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + else + ..() + +/obj/item/device/multitool/hacktool/resolve_attackby(atom/A, mob/user) + sanity_check() + + if(!in_hack_mode || !attempt_hack(user, A)) //will still show the unable to hack message, oh well + return ..() + + A.ui_interact(user, state = hack_state) + return 1 + +/obj/item/device/multitool/hacktool/proc/attempt_hack(var/mob/user, var/atom/target) + if(is_hacking) + to_chat(user, "You are already hacking!") + return 1 + if(!is_type_in_list(target, supported_types)) + to_chat(user, "\icon[src] Unable to hack this target.") + return 0 + var/found = known_targets.Find(target) + if(found) + known_targets.Swap(1, found) // Move the last hacked item first + return 1 + + to_chat(user, "You begin hacking \the [target]...") + is_hacking = 1 + // Hackin takes roughly 15-25 seconds. Fairly small random span to avoid people simply aborting and trying again. + var/hack_result = do_after(user, (15 SECONDS + rand(0, 5 SECONDS) + rand(0, 5 SECONDS)), progress = 0) + is_hacking = 0 + + if(hack_result && in_hack_mode) + to_chat(user, "Your hacking attempt was succesful!") + user.playsound_local(get_turf(src), 'sound/piano/A#6.ogg', 50) + known_targets.Insert(1, target) // Insert the newly hacked target first, + GLOB.destroyed_event.register(target, src, /obj/item/device/multitool/hacktool/proc/on_target_destroy) + else + to_chat(user, "Your hacking attempt failed!") + return 1 + +/obj/item/device/multitool/hacktool/proc/sanity_check() + if(max_known_targets < 1) max_known_targets = 1 + // Cut away the oldest items if the capacity has been reached + if(known_targets.len > max_known_targets) + for(var/i = (max_known_targets + 1) to known_targets.len) + var/atom/A = known_targets[i] + GLOB.destroyed_event.unregister(A, src) + known_targets.Cut(max_known_targets + 1) + +/obj/item/device/multitool/hacktool/proc/on_target_destroy(var/target) + known_targets -= target + +/datum/topic_state/default/must_hack + var/obj/item/device/multitool/hacktool/hacktool + +/datum/topic_state/default/must_hack/New(var/hacktool) + src.hacktool = hacktool + ..() + +/datum/topic_state/default/must_hack/Destroy() + hacktool = null + return ..() + +/datum/topic_state/default/must_hack/can_use_topic(var/src_object, var/mob/user) + if(!hacktool || !hacktool.in_hack_mode || !(src_object in hacktool.known_targets)) + return STATUS_CLOSE + return ..() diff --git a/code/game/objects/items/devices/holowarrant.dm b/code/game/objects/items/devices/holowarrant.dm new file mode 100644 index 00000000..484ae2db --- /dev/null +++ b/code/game/objects/items/devices/holowarrant.dm @@ -0,0 +1,115 @@ +/obj/item/device/holowarrant + name = "warrant projector" + desc = "The practical paperwork replacement for the officer on the go." + icon_state = "holowarrant" + item_state = "holowarrant" + throwforce = 5 + w_class = ITEM_SIZE_SMALL + throw_speed = 4 + throw_range = 10 + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + var/datum/computer_file/data/warrant/active + +//look at it +/obj/item/device/holowarrant/examine(mob/user) + . = ..() + if(active) + to_chat(user, "It's a holographic warrant for '[active.fields["namewarrant"]]'.") + if(in_range(user, src) || isghost(user)) + show_content(user) + else + to_chat(user, "You have to be closer if you want to read it.") + +//hit yourself with it +/obj/item/device/holowarrant/attack_self(mob/living/user as mob) + active = null + var/list/warrants = list() + for(var/datum/computer_file/data/warrant/W in GLOB.all_warrants) + if(!W.archived) + warrants += W.fields["namewarrant"] + if(warrants.len == 0) + to_chat(user,"There are no warrants available") + return + var/temp + temp = input(user, "Which warrant would you like to load?") as null|anything in warrants + for(var/datum/computer_file/data/warrant/W in GLOB.all_warrants) + if(W.fields["namewarrant"] == temp) + active = W + update_icon() + +/obj/item/device/holowarrant/attackby(obj/item/weapon/W, mob/user) + if(active) + var/obj/item/weapon/card/id/I = W.GetIdCard() + if(I && (access_security in I.access)) + var/choice = alert(user, "Would you like to authorize this warrant?","Warrant authorization","Yes","No") + if(choice == "Yes") + active.fields["auth"] = "[I.registered_name] - [I.assignment ? I.assignment : "(Unknown)"]" + user.visible_message("You swipe \the [I] through the [src].", \ + "[user] swipes \the [I] through the [src].") + broadcast_security_hud_message("\A [active.fields["arrestsearch"]] warrant for [active.fields["namewarrant"]] has been authorized by [I.assignment ? I.assignment+" " : ""][I.registered_name].", src) + else + to_chat(user, "A red \"Access Denied\" light blinks on \the [src]") + return 1 + ..() + +//hit other people with it +/obj/item/device/holowarrant/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) + user.visible_message("[user] holds up a warrant projector and shows the contents to [M].", \ + "You show the warrant to [M].") + M.examinate(src) + +/obj/item/device/holowarrant/update_icon() + if(active) + icon_state = "holowarrant_filled" + else + icon_state = "holowarrant" + +/obj/item/device/holowarrant/proc/show_content(mob/user, forceshow) + if(!active) + return + if(active.fields["arrestsearch"] == "arrest") + var/output = {" + [active.fields["namewarrant"]] +
            Sol Central Government Colonial Marshal Bureau
            + in the jurisdiction of the
            + [GLOB.using_map.boss_name] in [GLOB.using_map.system_name]
            +
            + ARREST WARRANT

            +
            + This document serves as authorization and notice for the arrest of _[active.fields["namewarrant"]]____ for the crime(s) of:
            [active.fields["charges"]]
            +
            + Vessel or habitat: _[GLOB.using_map.station_name]____
            +
            _[active.fields["auth"]]____
            + Person authorizing arrest
            + + "} + + show_browser(user, output, "window=Warrant for the arrest of [active.fields["namewarrant"]]") + if(active.fields["arrestsearch"] == "search") + var/output= {" + Search Warrant: [active.fields["namewarrant"]] +
            in the jurisdiction of the
            + [GLOB.using_map.boss_name] in [GLOB.using_map.system_name]
            +
            + SEARCH WARRANT

            +
            + The Security Officer(s) bearing this Warrant are hereby authorized by the Issuer
            + to conduct a one time lawful search of the Suspect's person/belongings/premises and/or Department
            + for any items and materials that could be connected to the suspected criminal act described below,
            + pending an investigation in progress. The Security Officer(s) are obligated to remove any and all
            + such items from the Suspects posession and/or Department and file it as evidence. The Suspect/Department
            + staff is expected to offer full co-operation. In the event of the Suspect/Department staff attempting
            + to resist/impede this search or flee, they must be taken into custody immediately!
            + All confiscated items must be filed and taken to Evidence!

            +
            + Suspect's/location name: [active.fields["namewarrant"]]
            +
            + For the following reasons: [active.fields["charges"]]
            +
            + Warrant issued by: [active.fields ["auth"]]
            +
            + Vessel or habitat: _[GLOB.using_map.station_name]____
            + + "} + show_browser(user, output, "window=Search warrant for [active.fields["namewarrant"]]") diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm new file mode 100644 index 00000000..1097c846 --- /dev/null +++ b/code/game/objects/items/devices/lightreplacer.dm @@ -0,0 +1,164 @@ + +// Light Replacer (LR) +// +// ABOUT THE DEVICE +// +// This is a device supposedly to be used by Janitors and Janitor Cyborgs which will +// allow them to easily replace lights. This was mostly designed for Janitor Cyborgs since +// they don't have hands or a way to replace lightbulbs. +// +// HOW IT WORKS +// +// You attack a light fixture with it, if the light fixture is broken it will replace the +// light fixture with a working light; the broken light is then placed on the floor for the +// user to then pickup with a trash bag. If it's empty then it will just place a light in the fixture. +// +// HOW TO REFILL THE DEVICE +// +// It can be manually refilled or by clicking on a storage item containing lights. +// If it's part of a robot module, it will charge when the Robot is inside a Recharge Station. +// +// EMAGGED FEATURES +// +// NOTICE: The Cyborg cannot use the emagged Light Replacer and the light's explosion was nerfed. It cannot create holes in the station anymore. +// +// I'm not sure everyone will react the emag's features so please say what your opinions are of it. +// +// When emagged it will rig every light it replaces, which will explode when the light is on. +// This is VERY noticable, even the device's name changes when you emag it so if anyone +// examines you when you're holding it in your hand, you will be discovered. +// It will also be very obvious who is setting all these lights off, since only Janitor Borgs and Janitors have easy +// access to them, and only one of them can emag their device. +// +// The explosion cannot insta-kill anyone with 30% or more health. + +#define LIGHT_OK 0 +#define LIGHT_EMPTY 1 +#define LIGHT_BROKEN 2 +#define LIGHT_BURNED 3 + + +/obj/item/device/lightreplacer + + name = "light replacer" + desc = "A lightweight automated device, capable of interfacing with and rapidly replacing standard light installations." + description_info = "Examine or use this item to see how many lights are remaining. You can feed it lightbulbs or sheets of glass to refill it." + description_fluff = "Can you believe they used to have to screw lightbulbs in by hand?" + description_antag = "Using a cryptographic sequencer on this device will cause it to overload each light it replaces; when turned on, the new lights will explode!" + + icon = 'icons/obj/janitor.dmi' + icon_state = "lightreplacer0" + item_state = "electronic" + + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + origin_tech = list(TECH_MAGNET = 3, TECH_MATERIAL = 2) + + var/max_uses = 32 + var/uses = 32 + var/emagged = 0 + var/failmsg = "" + var/charge = 0 + +/obj/item/device/lightreplacer/New() + failmsg = "The [name]'s refill light blinks red." + ..() + +/obj/item/device/lightreplacer/examine(mob/user) + if(..(user, 2)) + to_chat(user, "It has [uses] light\s remaining.") + +/obj/item/device/lightreplacer/attackby(obj/item/W, mob/user) + if(istype(W, /obj/item/stack/material) && W.get_material_name() == "glass") + var/obj/item/stack/G = W + if(uses >= max_uses) + to_chat(user, "[src.name] is full.") + return + else if(G.use(1)) + AddUses(16) //Autolathe converts 1 sheet into 16 lights. + to_chat(user, "You insert a piece of glass into \the [src.name]. You have [uses] light\s remaining.") + return + else + to_chat(user, "You need one sheet of glass to replace lights.") + + if(istype(W, /obj/item/weapon/light)) + var/obj/item/weapon/light/L = W + if(L.status == 0) // LIGHT OKAY + if(uses < max_uses) + AddUses(1) + to_chat(user, "You insert \the [L.name] into \the [src.name]. You have [uses] light\s remaining.") + user.drop_item() + qdel(L) + return + else + to_chat(user, "You need a working light.") + return + +/obj/item/device/lightreplacer/attack_self(mob/user) + /* // This would probably be a bit OP. If you want it though, uncomment the code. + if(isrobot(user)) + var/mob/living/silicon/robot/R = user + if(R.emagged) + src.Emag() + to_chat(usr, "You shortcircuit the [src].") + return + */ + to_chat(usr, "It has [uses] lights remaining.") + +/obj/item/device/lightreplacer/update_icon() + icon_state = "lightreplacer[emagged]" + + +/obj/item/device/lightreplacer/proc/Use(var/mob/user) + + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + AddUses(-1) + return 1 + +// Negative numbers will subtract +/obj/item/device/lightreplacer/proc/AddUses(var/amount = 1) + uses = min(max(uses + amount, 0), max_uses) + +/obj/item/device/lightreplacer/proc/Charge(var/mob/user, var/amount = 1) + charge += amount + if(charge > 6) + AddUses(1) + charge = 0 + +/obj/item/device/lightreplacer/proc/ReplaceLight(var/obj/machinery/light/target, var/mob/living/U) + + if(target.get_status() == LIGHT_OK) + to_chat(U, "There is a working [target.get_fitting_name()] already inserted.") + else if(!CanUse(U)) + to_chat(U, failmsg) + else if(Use(U)) + to_chat(U, "You replace the [target.get_fitting_name()] with the [src].") + + if(target.lightbulb) + target.remove_bulb() + + var/obj/item/weapon/light/L = new target.light_type() + L.rigged = emagged + target.insert_bulb(L) + + +/obj/item/device/lightreplacer/emag_act(var/remaining_charges, var/mob/user) + emagged = !emagged + playsound(src.loc, "sparks", 100, 1) + update_icon() + return 1 + +//Can you use it? + +/obj/item/device/lightreplacer/proc/CanUse(var/mob/living/user) + src.add_fingerprint(user) + //Not sure what else to check for. Maybe if clumsy? + if(uses > 0) + return 1 + else + return 0 + +#undef LIGHT_OK +#undef LIGHT_EMPTY +#undef LIGHT_BROKEN +#undef LIGHT_BURNED diff --git a/code/game/objects/items/devices/megaphone.dm b/code/game/objects/items/devices/megaphone.dm new file mode 100644 index 00000000..ce810ddb --- /dev/null +++ b/code/game/objects/items/devices/megaphone.dm @@ -0,0 +1,51 @@ +/obj/item/device/megaphone + name = "megaphone" + desc = "A device used to project your voice. Loudly." + icon_state = "megaphone" + item_state = "radio" + w_class = ITEM_SIZE_SMALL + obj_flags = OBJ_FLAG_CONDUCTIBLE + + var/spamcheck = 0 + var/emagged = 0 + var/insults = 0 + var/list/insultmsg = list("FUCK EVERYONE!", "I'M A TATER!", "ALL SECURITY TO SHOOT ME ON SIGHT!", "I HAVE A BOMB!", "CAPTAIN IS A COMDOM!", "FOR THE SYNDICATE!") + +/obj/item/device/megaphone/attack_self(mob/living/user as mob) + if (user.client) + if(user.client.prefs.muted & MUTE_IC) + to_chat(src, "You cannot speak in IC (muted).") + return + if(user.silent) + return + if(spamcheck) + to_chat(user, "\The [src] needs to recharge!") + return + + var/message = sanitize(input(user, "Shout a message?", "Megaphone", null) as text) + if(!message) + return + message = capitalize(message) + if ((src.loc == user && usr.stat == 0)) + if(emagged) + if(insults) + for(var/mob/O in (viewers(user))) + O.show_message("[user] broadcasts, \"[pick(insultmsg)]\"",2) // 2 stands for hearable message + insults-- + else + to_chat(user, "*BZZZZzzzzzt*") + else + for(var/mob/O in (viewers(user))) + O.show_message("[user] broadcasts, \"[message]\"",2) // 2 stands for hearable message + + spamcheck = 1 + spawn(20) + spamcheck = 0 + return + +/obj/item/device/megaphone/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + to_chat(user, "You overload \the [src]'s voice synthesizer.") + emagged = 1 + insults = rand(1, 3)//to prevent dickflooding + return 1 diff --git a/code/game/objects/items/devices/modkit.dm b/code/game/objects/items/devices/modkit.dm new file mode 100644 index 00000000..be4afddd --- /dev/null +++ b/code/game/objects/items/devices/modkit.dm @@ -0,0 +1,72 @@ +#define MODKIT_HELMET 1 +#define MODKIT_SUIT 2 +#define MODKIT_FULL 3 + +/obj/item/device/modkit + name = "hardsuit modification kit" + desc = "A kit containing all the needed tools and parts to modify a hardsuit for another user." + icon_state = "modkit" + var/parts = MODKIT_FULL + var/target_species = SPECIES_HUMAN + + var/list/permitted_types = list( + /obj/item/clothing/head/helmet/space/void, + /obj/item/clothing/suit/space/void + ) + +/obj/item/device/modkit/afterattack(obj/O, mob/user as mob, proximity) + if(!proximity) + return + + if (!target_species) + return //it shouldn't be null, okay? + + if(!parts) + to_chat(user, "This kit has no parts for this modification left.") + user.drop_from_inventory(src) + qdel(src) + return + + var/allowed = 0 + for (var/permitted_type in permitted_types) + if(istype(O, permitted_type)) + allowed = 1 + + var/obj/item/clothing/I = O + if (!istype(I) || !allowed) + to_chat(user, "[src] is unable to modify that.") + return + + var/excluding = ("exclude" in I.species_restricted) + var/in_list = (target_species in I.species_restricted) + if (excluding ^ in_list) + to_chat(user, "[I] is already modified.") + return + + if(!isturf(O.loc)) + to_chat(user, "[O] must be safely placed on the ground for modification.") + return + + playsound(user.loc, 'sound/items/Screwdriver.ogg', 100, 1) + + user.visible_message("\The [user] opens \the [src] and modifies \the [O].","You open \the [src] and modify \the [O].") + + I.refit_for_species(target_species) + + if (istype(I, /obj/item/clothing/head/helmet)) + parts &= ~MODKIT_HELMET + if (istype(I, /obj/item/clothing/suit)) + parts &= ~MODKIT_SUIT + + if(!parts) + user.drop_from_inventory(src) + qdel(src) + +/obj/item/device/modkit/examine(mob/user) + . = ..(user) + to_chat(user, "It looks as though it modifies hardsuits to fit [target_species] users.") + +/obj/item/device/modkit/tajaran + name = "tajaran hardsuit modification kit" + desc = "A kit containing all the needed tools and parts to modify a hardsuit for another user. This one looks like it's meant for Tajaran." + target_species = SPECIES_TAJARA diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm new file mode 100644 index 00000000..dd94db33 --- /dev/null +++ b/code/game/objects/items/devices/multitool.dm @@ -0,0 +1,72 @@ +/** + * Multitool -- A multitool is used for hacking electronic devices. + * + */ + +/obj/item/device/multitool + name = "multitool" + desc = "This small, handheld device is made of durable, insulated plastic, and tipped with electrodes, perfect for interfacing with numerous machines." + description_info = "Multitools are incredibly versatile and can be used on a wide variety of machines. The most common use for this is to trip a device's wires without having to cut them. Simply click on an object with exposed wiring to use it. There might be other uses, as well..." + description_fluff = "The common, every day multitool is descended from certain electrical tools from Earth's early space age. Though none too cheap, they are incredibly handy, and can be found in any self-respecting technician's toolbox." + description_antag = "This handy little tool can get you through doors, turn off power, and anything else you might need." + icon_state = "multitool" + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 5.0 + w_class = ITEM_SIZE_SMALL + throwforce = 5.0 + throw_range = 15 + throw_speed = 3 + + matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 20) + + origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1) + + var/buffer_name + var/atom/buffer_object + +/obj/item/device/multitool/Destroy() + unregister_buffer(buffer_object) + return ..() + +/obj/item/device/multitool/proc/get_buffer(var/typepath) + // Only allow clearing the buffer name when someone fetches the buffer. + // Means you cannot be sure the source hasn't been destroyed until the very moment it's needed. + get_buffer_name(TRUE) + if(buffer_object && (!typepath || istype(buffer_object, typepath))) + return buffer_object + +/obj/item/device/multitool/proc/get_buffer_name(var/null_name_if_missing = FALSE) + if(buffer_object) + buffer_name = buffer_object.name + else if(null_name_if_missing) + buffer_name = null + return buffer_name + +/obj/item/device/multitool/proc/set_buffer(var/atom/buffer) + if(!buffer || istype(buffer)) + buffer_name = buffer ? buffer.name : null + if(buffer != buffer_object) + unregister_buffer(buffer_object) + buffer_object = buffer + if(buffer_object) + GLOB.destroyed_event.register(buffer_object, src, /obj/item/device/multitool/proc/unregister_buffer) + +/obj/item/device/multitool/proc/unregister_buffer(var/atom/buffer_to_unregister) + // Only remove the buffered object, don't reset the name + // This means one cannot know if the buffer has been destroyed until one attempts to use it. + if(buffer_to_unregister == buffer_object && buffer_object) + GLOB.destroyed_event.unregister(buffer_object, src) + buffer_object = null + +/obj/item/device/multitool/resolve_attackby(atom/A, mob/user) + if(!isobj(A)) + return ..(A, user) + + var/obj/O = A + var/datum/extension/interactive/multitool/MT = get_extension(O, /datum/extension/interactive/multitool) + if(!MT) + return ..(A, user) + + user.AddTopicPrint(src) + MT.interact(src, user) + return 1 diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm new file mode 100644 index 00000000..2280277a --- /dev/null +++ b/code/game/objects/items/devices/paicard.dm @@ -0,0 +1,329 @@ +/obj/item/device/paicard + name = "personal AI device" + icon = 'icons/obj/pda.dmi' + icon_state = "pai" + item_state = "electronic" + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_BELT + origin_tech = list(TECH_DATA = 2) + var/obj/item/device/radio/radio + var/looking_for_personality = 0 + var/mob/living/silicon/pai/pai + +/obj/item/device/paicard/relaymove(var/mob/user, var/direction) + if(user.stat || user.stunned) + return + +/obj/item/device/paicard/New() + ..() + overlays += "pai-off" + +/obj/item/device/paicard/Destroy() + //Will stop people throwing friend pAIs into the singularity so they can respawn + if(!isnull(pai)) + pai.death(0) + QDEL_NULL(radio) + return ..() + +/obj/item/device/paicard/attack_self(mob/user) + if (!in_range(src, user)) + return + user.set_machine(src) + var/dat = {" + + + + + + + "} + + if(pai) + dat += {" + Personal AI Device

            + + + + + + + + + + + + + +
            Installed Personality:[pai.name]
            Prime directive:[pai.pai_law0]
            Additional directives:[pai.pai_laws]
            +
            + "} + dat += {" + + +
            + Configure Directives +
            + "} + if(pai && (!pai.master_dna || !pai.master)) + dat += {" + + +
            + Imprint Master DNA +
            + "} + dat += "
            " + if(radio) + dat += "Radio Uplink" + dat += {" + + + + + + + + + +
            Transmit:[radio.broadcasting ? "En" : "Dis" ]abled + +
            Receive:[radio.listening ? "En" : "Dis" ]abled + +
            +
            + "} + else // + dat += "Radio Uplink
            " + dat += "Radio firmware not loaded. Please install a pAI personality to load firmware.
            " + dat += {" + + +
            Wipe current pAI personality + +
            + "} + else + if(looking_for_personality) + dat += {" + pAI Request Module

            +

            Requesting AI personalities from central database... If there are no entries, or if a suitable entry is not listed, check again later as more personalities may be added.

            + Searching for personalities

            + + + + + +
            + Refresh available personalities +

            + "} + else + dat += {" + pAI Request Module

            +

            No personality is installed.

            + + + + +
            Request personality +
            +
            +

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

            + "} + user << browse(dat, "window=paicard") + onclose(user, "paicard") + return + +/obj/item/device/paicard/Topic(href, href_list) + + if(!usr || usr.stat) + return + + if(href_list["setdna"]) + if(pai.master_dna) + return + var/mob/M = usr + if(!istype(M, /mob/living/carbon)) + to_chat(usr, "You don't have any DNA, or your DNA is incompatible with this device.") + else + var/datum/dna/dna = usr.dna + pai.master = M.real_name + pai.master_dna = dna.unique_enzymes + to_chat(pai, "You have been bound to a new master.") + if(href_list["request"]) + src.looking_for_personality = 1 + paiController.findPAI(src, usr) + if(href_list["wipe"]) + var/confirm = input("Are you CERTAIN you wish to delete the current personality? This action cannot be undone.", "Personality Wipe") in list("Yes", "No") + if(confirm == "Yes") + for(var/mob/M in src) + to_chat(M, "

            You feel yourself slipping away from reality.

            ") + to_chat(M, "

            Byte by byte you lose your sense of self.

            ") + to_chat(M, "

            Your mental faculties leave you.

            ") + to_chat(M, "
            oblivion...
            ") + M.death(0) + removePersonality() + if(href_list["wires"]) + var/t1 = text2num(href_list["wires"]) + switch(t1) + if(4) + radio.ToggleBroadcast() + if(2) + radio.ToggleReception() + if(href_list["setlaws"]) + var/newlaws = sanitize(input("Enter any additional directives you would like your pAI personality to follow. Note that these directives will not override the personality's allegiance to its imprinted master. Conflicting directives will be ignored.", "pAI Directive Configuration", pai.pai_laws) as message) + if(newlaws) + pai.pai_laws = newlaws + to_chat(pai, "Your supplemental directives have been updated. Your new directives are:") + to_chat(pai, "Prime Directive:
            [pai.pai_law0]") + to_chat(pai, "Supplemental Directives:
            [pai.pai_laws]") + attack_self(usr) + +// WIRE_SIGNAL = 1 +// WIRE_RECEIVE = 2 +// WIRE_TRANSMIT = 4 + +/obj/item/device/paicard/proc/setPersonality(mob/living/silicon/pai/personality) + src.pai = personality + src.overlays += "pai-happy" + +/obj/item/device/paicard/proc/removePersonality() + src.pai = null + src.overlays.Cut() + src.overlays += "pai-off" + +/obj/item/device/paicard + var/current_emotion = 1 +/obj/item/device/paicard/proc/setEmotion(var/emotion) + if(pai) + src.overlays.Cut() + switch(emotion) + if(1) src.overlays += "pai-happy" + if(2) src.overlays += "pai-cat" + if(3) src.overlays += "pai-extremely-happy" + if(4) src.overlays += "pai-face" + if(5) src.overlays += "pai-laugh" + if(6) src.overlays += "pai-off" + if(7) src.overlays += "pai-sad" + if(8) src.overlays += "pai-angry" + if(9) src.overlays += "pai-what" + if(10) src.overlays += "pai-neutral" + if(11) src.overlays += "pai-silly" + if(12) src.overlays += "pai-nose" + if(13) src.overlays += "pai-smirk" + if(14) src.overlays += "pai-exclamation" + if(15) src.overlays += "pai-question" + current_emotion = emotion + +/obj/item/device/paicard/proc/alertUpdate() + var/turf/T = get_turf_or_move(src.loc) + for (var/mob/M in viewers(T)) + M.show_message("\The [src] flashes a message across its screen, \"Additional personalities available for download.\"", 3, "\The [src] bleeps electronically.", 2) + +/obj/item/device/paicard/emp_act(severity) + for(var/mob/M in src) + M.emp_act(severity) + +/obj/item/device/paicard/ex_act(severity) + if(pai) + pai.ex_act(severity) + else + qdel(src) + +/obj/item/device/paicard/see_emote(mob/living/M, text) + if(pai && pai.client && !pai.canmove) + var/rendered = "[text]" + pai.show_message(rendered, 2) + ..() + +/obj/item/device/paicard/show_message(msg, type, alt, alt_type) + if(pai && pai.client) + var/rendered = "[msg]" + pai.show_message(rendered, type) + ..() diff --git a/code/game/objects/items/devices/personal_shield.dm b/code/game/objects/items/devices/personal_shield.dm new file mode 100644 index 00000000..c4414451 --- /dev/null +++ b/code/game/objects/items/devices/personal_shield.dm @@ -0,0 +1,38 @@ +/obj/item/device/personal_shield + name = "personal shield" + desc = "Truely a life-saver: this device protects its user from being hit by objects moving very, very fast, though only for a few shots." + icon = 'icons/obj/device.dmi' + icon_state = "batterer" + var/uses = 5 + var/obj/aura/personal_shield/device/shield + +/obj/item/device/personal_shield/attack_self(var/mob/living/user) + if(uses) + shield = new(user,src) + else + QDEL_NULL(shield) + +/obj/item/device/personal_shield/Move() + QDEL_NULL(shield) + return ..() + +/obj/item/device/personal_shield/forceMove() + QDEL_NULL(shield) + return ..() + +/obj/item/device/personal_shield/proc/take_charge() + if(!--uses) + QDEL_NULL(shield) + to_chat(loc,"\The [src] begins to spark as it breaks!") + update_icon() + return + +/obj/item/device/personal_shield/update_icon() + if(uses) + icon_state = "batterer" + else + icon_state = "battererburnt" + +/obj/item/device/personal_shield/Destroy() + QDEL_NULL(shield) + return ..() \ No newline at end of file diff --git a/code/game/objects/items/devices/pipe_painter.dm b/code/game/objects/items/devices/pipe_painter.dm new file mode 100644 index 00000000..72076aea --- /dev/null +++ b/code/game/objects/items/devices/pipe_painter.dm @@ -0,0 +1,34 @@ +/obj/item/device/pipe_painter + name = "pipe painter" + icon = 'icons/obj/device.dmi' + icon_state = "pipainter" + item_state = "flight" + desc = "A long, slender device consisting of a pigment synthesizer, dual applicators, and a small battery, all hooked up to a long extendable rod." + description_info = "Use the pipe painter to specify which color you'd like to apply to pipes. Click on exposed piping to alter its hue." + description_fluff = "Though by no means a modern miracle, synthesized pigments have revolutionized the electrical engineering industry, making time-consuming painting and color coding jobs an effortless non-issue." + var/list/modes + var/mode + +/obj/item/device/pipe_painter/New() + ..() + modes = new() + for(var/C in pipe_colors) + modes += "[C]" + mode = pick(modes) + +/obj/item/device/pipe_painter/afterattack(atom/A, mob/user as mob, proximity) + if(!proximity) + return + + if(!istype(A,/obj/machinery/atmospherics/pipe) || istype(A,/obj/machinery/atmospherics/pipe/tank) || istype(A,/obj/machinery/atmospherics/pipe/vent) || istype(A,/obj/machinery/atmospherics/pipe/simple/heat_exchanging) || !in_range(user, A)) + return + var/obj/machinery/atmospherics/pipe/P = A + + P.change_color(pipe_colors[mode]) + +/obj/item/device/pipe_painter/attack_self(mob/user as mob) + mode = input("Which colour do you want to use?", "Pipe painter", mode) in modes + +/obj/item/device/pipe_painter/examine(mob/user) + . = ..(user) + to_chat(user, "It is in [mode] mode.") diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm new file mode 100644 index 00000000..71702a8e --- /dev/null +++ b/code/game/objects/items/devices/powersink.dm @@ -0,0 +1,129 @@ +// Powersink - used to drain station power + +/obj/item/device/powersink + name = "power sink" + desc = "A nulling power sink which drains energy from electrical systems." + icon_state = "powersink0" + item_state = "electronic" + w_class = ITEM_SIZE_LARGE + obj_flags = OBJ_FLAG_CONDUCTIBLE + throwforce = 5 + throw_speed = 1 + throw_range = 2 + + matter = list(DEFAULT_WALL_MATERIAL = 750,"waste" = 750) + + origin_tech = list(TECH_POWER = 3, TECH_ILLEGAL = 5) + var/drain_rate = 1500000 // amount of power to drain per tick + var/apc_drain_rate = 5000 // Max. amount drained from single APC. In Watts. + var/dissipation_rate = 20000 // Passive dissipation of drained power. In Watts. + var/power_drained = 0 // Amount of power drained. + var/max_power = 5e9 // Detonation point. + var/mode = 0 // 0 = off, 1=clamped (off), 2=operating + var/drained_this_tick = 0 // This is unfortunately necessary to ensure we process powersinks BEFORE other machinery such as APCs. + + var/datum/powernet/PN // Our powernet + var/obj/structure/cable/attached // the attached cable + +/obj/item/device/powersink/Destroy() + if(mode == 2) + STOP_PROCESSING_POWER_OBJECT(src) + . = ..() + +/obj/item/device/powersink/attackby(var/obj/item/I, var/mob/user) + if(isScrewdriver(I)) + if(mode == 0) + var/turf/T = loc + if(isturf(T) && !!T.is_plating()) + attached = locate() in T + if(!attached) + to_chat(user, "No exposed cable here to attach to.") + return + else + anchored = 1 + mode = 1 + src.visible_message("[user] attaches [src] to the cable!") + return + else + to_chat(user, "Device must be placed over an exposed cable to attach to it.") + return + else + if (mode == 2) + STOP_PROCESSING_POWER_OBJECT(src) + anchored = 0 + mode = 0 + src.visible_message("[user] detaches [src] from the cable!") + set_light(0) + icon_state = "powersink0" + + return + else + ..() + +/obj/item/device/powersink/attack_ai() + return + +/obj/item/device/powersink/attack_hand(var/mob/user) + switch(mode) + if(0) + ..() + if(1) + src.visible_message("[user] activates [src]!") + mode = 2 + icon_state = "powersink1" + START_PROCESSING_POWER_OBJECT(src) + if(2) //This switch option wasn't originally included. It exists now. --NeoFite + src.visible_message("[user] deactivates [src]!") + mode = 1 + set_light(0) + icon_state = "powersink0" + STOP_PROCESSING_POWER_OBJECT(src) + +/obj/item/device/powersink/pwr_drain() + if(!attached) + return 0 + + if(drained_this_tick) + return 1 + drained_this_tick = 1 + + var/drained = 0 + + if(!PN) + return 1 + + set_light(12) + PN.trigger_warning() + // found a powernet, so drain up to max power from it + drained = PN.draw_power(drain_rate) + // if tried to drain more than available on powernet + // now look for APCs and drain their cells + if(drained < drain_rate) + for(var/obj/machinery/power/terminal/T in PN.nodes) + // Enough power drained this tick, no need to torture more APCs + if(drained >= drain_rate) + break + if(istype(T.master, /obj/machinery/power/apc)) + var/obj/machinery/power/apc/A = T.master + if(A.operating && A.cell) + var/cur_charge = A.cell.charge / CELLRATE + var/drain_val = min(apc_drain_rate, cur_charge) + A.cell.use(drain_val * CELLRATE) + drained += drain_val + power_drained += drained + return 1 + + +/obj/item/device/powersink/Process() + drained_this_tick = 0 + power_drained -= min(dissipation_rate, power_drained) + if(power_drained > max_power * 0.95) + playsound(src, 'sound/effects/screech.ogg', 100, 1, 1) + if(power_drained >= max_power) + explosion(src.loc, 3,6,9,12) + qdel(src) + return + if(attached && attached.powernet) + PN = attached.powernet + else + PN = null diff --git a/code/game/objects/items/devices/radio/beacon.dm b/code/game/objects/items/devices/radio/beacon.dm new file mode 100644 index 00000000..7e6ba097 --- /dev/null +++ b/code/game/objects/items/devices/radio/beacon.dm @@ -0,0 +1,26 @@ +/obj/item/device/radio/beacon + name = "tracking beacon" + desc = "A beacon used by a teleporter." + icon_state = "beacon" + item_state = "signaler" + var/code = "electronic" + origin_tech = list(TECH_BLUESPACE = 1) + +/obj/item/device/radio/beacon/hear_talk() + return + +/obj/item/device/radio/beacon/send_hear() + return null + +/obj/item/device/radio/beacon/proc/alter_signal(newcode as text) + set name = "Alter Beacon's Signal" + set category = "Object" + + var/mob/user = usr + if (!user.incapacitated()) + code = newcode + add_fingerprint(user) + +//obj/item/device/radio/beacon/RightClick(mob/user) +// if(CanPhysicallyInteract(user)) +// alter_signal(newcode as text) \ No newline at end of file diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm new file mode 100644 index 00000000..6127ac80 --- /dev/null +++ b/code/game/objects/items/devices/radio/electropack.dm @@ -0,0 +1,127 @@ +/obj/item/device/radio/electropack + name = "electropack" + desc = "Dance my monkeys! DANCE!!!" + icon_state = "electropack0" + item_state = "electropack" + frequency = 1449 + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BACK + w_class = ITEM_SIZE_HUGE + + matter = list(DEFAULT_WALL_MATERIAL = 10000,"glass" = 2500) + + var/code = 2 + +/obj/item/device/radio/electropack/attack_hand(mob/user as mob) + if(src == user.back) + to_chat(user, "You need help taking this off!") + return + ..() + +/obj/item/device/radio/electropack/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + if(istype(W, /obj/item/clothing/head/helmet)) + if(!b_stat) + to_chat(user, "[src] is not ready to be attached!") + return + var/obj/item/assembly/shock_kit/A = new /obj/item/assembly/shock_kit( user ) + A.icon = 'icons/obj/assemblies.dmi' + + user.drop_from_inventory(W) + W.loc = A + W.master = A + A.part1 = W + + user.drop_from_inventory(src) + loc = A + master = A + A.part2 = src + + user.put_in_hands(A) + +/obj/item/device/radio/electropack/Topic(href, href_list) + //..() + if(usr.stat || usr.restrained()) + return + if(((istype(usr, /mob/living/carbon/human) && ((!( ticker ) || (ticker && ticker.mode != "monkey")) && usr.contents.Find(src))) || (usr.contents.Find(master) || (in_range(src, usr) && istype(loc, /turf))))) + usr.set_machine(src) + if(href_list["freq"]) + var/new_frequency = sanitize_frequency(frequency + text2num(href_list["freq"])) + set_frequency(new_frequency) + else + if(href_list["code"]) + code += text2num(href_list["code"]) + code = round(code) + code = min(100, code) + code = max(1, code) + else + if(href_list["power"]) + on = !( on ) + icon_state = "electropack[on]" + if(!( master )) + if(istype(loc, /mob)) + attack_self(loc) + else + for(var/mob/M in viewers(1, src)) + if(M.client) + attack_self(M) + else + if(istype(master.loc, /mob)) + attack_self(master.loc) + else + for(var/mob/M in viewers(1, master)) + if(M.client) + attack_self(M) + else + usr << browse(null, "window=radio") + return + return + +/obj/item/device/radio/electropack/receive_signal(datum/signal/signal) + if(!signal || signal.encryption != code) + return + + if(ismob(loc) && on) + var/mob/M = loc + var/turf/T = M.loc + if(istype(T, /turf)) + if(!M.moved_recently && M.last_move) + M.moved_recently = 1 + step(M, M.last_move) + sleep(50) + if(M) + M.moved_recently = 0 + to_chat(M, "You feel a sharp shock!") + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, M) + s.start() + + M.Weaken(10) + + if(master && wires & 1) + master.receive_signal() + return + +/obj/item/device/radio/electropack/attack_self(mob/user as mob, flag1) + + if(!istype(user, /mob/living/carbon/human)) + return + user.set_machine(src) + var/dat = {" +Turn [on ? "Off" : "On"]
            +Frequency/Code for electropack:
            +Frequency: +- +- [format_frequency(frequency)] ++ ++
            + +Code: +- +- [code] ++ ++
            +
            "} + user << browse(dat, "window=radio") + onclose(user, "radio") + return diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm new file mode 100644 index 00000000..6d5c3e94 --- /dev/null +++ b/code/game/objects/items/devices/radio/encryptionkey.dm @@ -0,0 +1,250 @@ + +/obj/item/device/encryptionkey/ + name = "standard encryption key" + desc = "An encryption key for a radio headset. Contains cypherkeys." + icon = 'icons/obj/radio.dmi' + icon_state = "cypherkey" + item_state = "" + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + var/translate_binary = 0 + var/translate_hive = 0 + var/syndie = 0 + var/list/channels = list() + +/obj/item/device/encryptionkey/attackby(obj/item/weapon/W as obj, mob/user as mob) + + +//Base red one. +/obj/item/device/encryptionkey/red + icon_state = "cypherkey" + channels = list("Red" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1//Signifies that it de-crypts Syndicate transmissions + +/obj/item/device/encryptionkey/redsl_alpha + icon_state = "cypherkey" + channels = list("Red" = 1, "Red Alpha" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + +/obj/item/device/encryptionkey/redsl_bravo + icon_state = "cypherkey" + channels = list("Red" = 1, "Red Bravo" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + +/obj/item/device/encryptionkey/redsl_charlie + icon_state = "cypherkey" + channels = list("Red" = 1, "Red Charlie" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + +/obj/item/device/encryptionkey/redsl_delta + icon_state = "cypherkey" + channels = list("Red" = 1, "Red Delta" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + +/obj/item/device/encryptionkey/red_all + icon_state = "cypherkey" + channels = list("Red" = 1, "Red Alpha" = 1, "Red Bravo" = 1, "Red Charlie" = 1, "Red Delta" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + +/obj/item/device/encryptionkey/red_alpha + icon_state = "cypherkey" + channels = list("Red Alpha" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + +/obj/item/device/encryptionkey/red_bravo + icon_state = "cypherkey" + channels = list("Red Bravo" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1//Signifies that it de-crypts Syndicate transmissions + +/obj/item/device/encryptionkey/red_charlie + icon_state = "cypherkey" + channels = list("Red Charlie" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1//Signifies that it de-crypts Syndicate transmissions + +/obj/item/device/encryptionkey/red_delta + icon_state = "cypherkey" + channels = list("Red Delta" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1//Signifies that it de-crypts Syndicate transmissions + + +//Base blue one. +/obj/item/device/encryptionkey/blue + icon_state = "cypherkey" + channels = list("Blue" = 1) + origin_tech = list(TECH_ILLEGAL = 2) + syndie = 1 + +/obj/item/device/encryptionkey/bluesl_alpha + icon_state = "cypherkey" + channels = list("Blue" = 1, "Blue Alpha" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + +/obj/item/device/encryptionkey/bluesl_bravo + icon_state = "cypherkey" + channels = list("Blue" = 1, "Blue Bravo" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + +/obj/item/device/encryptionkey/bluesl_charlie + icon_state = "cypherkey" + channels = list("Blue" = 1, "Blue Charlie" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + +/obj/item/device/encryptionkey/bluesl_delta + icon_state = "cypherkey" + channels = list("Blue" = 1, "Blue Delta" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + +/obj/item/device/encryptionkey/blue_all + icon_state = "cypherkey" + channels = list("Blue" = 1, "Blue Alpha" = 1, "Blue Bravo" = 1, "Blue Charlie" = 1, "Blue Delta" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + +/obj/item/device/encryptionkey/blue_alpha + icon_state = "cypherkey" + channels = list("Blue Alpha" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + +/obj/item/device/encryptionkey/blue_bravo + icon_state = "cypherkey" + channels = list("Blue Bravo" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + +/obj/item/device/encryptionkey/blue_charlie + icon_state = "cypherkey" + channels = list("Blue Charlie" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + +/obj/item/device/encryptionkey/blue_delta + icon_state = "cypherkey" + channels = list("Blue Delta" = 1) + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + +/obj/item/device/encryptionkey/binary + icon_state = "cypherkey" + translate_binary = 1 + origin_tech = list(TECH_ILLEGAL = 3) + +/obj/item/device/encryptionkey/headset_sec + name = "security radio encryption key" + icon_state = "sec_cypherkey" + channels = list("Security" = 1) + + +/obj/item/device/encryptionkey/headset_red + name = "red radio encryption key" + icon_state = "sec_cypherkey" + channels = list("Security" = 1) + +/obj/item/device/encryptionkey/headset_eng + name = "engineering radio encryption key" + icon_state = "eng_cypherkey" + channels = list("Engineering" = 1) + +/obj/item/device/encryptionkey/headset_rob + name = "robotics radio encryption key" + icon_state = "rob_cypherkey" + channels = list("Engineering" = 1, "Science" = 1) + +/obj/item/device/encryptionkey/headset_med + name = "medical radio encryption key" + icon_state = "med_cypherkey" + channels = list("Medical" = 1) + +/obj/item/device/encryptionkey/headset_sci + name = "science radio encryption key" + icon_state = "sci_cypherkey" + channels = list("Science" = 1) + +/obj/item/device/encryptionkey/headset_medsci + name = "medical research radio encryption key" + icon_state = "medsci_cypherkey" + channels = list("Medical" = 1, "Science" = 1) + +/obj/item/device/encryptionkey/headset_com + name = "command radio encryption key" + icon_state = "com_cypherkey" + channels = list("Command" = 1) + +/obj/item/device/encryptionkey/heads/captain + name = "captain's encryption key" + icon_state = "cap_cypherkey" + channels = list("Command" = 1, "Security" = 1, "Engineering" = 0, "Science" = 0, "Medical" = 0, "Supply" = 0, "Service" = 0) + +/obj/item/device/encryptionkey/heads/ai_integrated + name = "ai integrated encryption key" + desc = "Integrated encryption key." + icon_state = "cap_cypherkey" + channels = list("Command" = 1, "Security" = 1, "Engineering" = 1, "Science" = 1, "Medical" = 1, "Supply" = 1, "Service" = 1, "AI Private" = 1) + +/obj/item/device/encryptionkey/heads/rd + name = "research director's encryption key" + icon_state = "rd_cypherkey" + channels = list("Science" = 1, "Command" = 1) + +/obj/item/device/encryptionkey/heads/hos + name = "head of security's encryption key" + icon_state = "hos_cypherkey" + channels = list("Security" = 1, "Command" = 1) + +/obj/item/device/encryptionkey/heads/ce + name = "chief engineer's encryption key" + icon_state = "ce_cypherkey" + channels = list("Engineering" = 1, "Command" = 1) + +/obj/item/device/encryptionkey/heads/cmo + name = "chief medical officer's encryption key" + icon_state = "cmo_cypherkey" + channels = list("Medical" = 1, "Command" = 1) + +/obj/item/device/encryptionkey/heads/hop + name = "head of personnel's encryption key" + icon_state = "hop_cypherkey" + channels = list("Supply" = 1, "Service" = 1, "Command" = 1, "Security" = 0) + +/obj/item/device/encryptionkey/headset_cargo + name = "supply radio encryption key" + icon_state = "cargo_cypherkey" + channels = list("Supply" = 1) + +/obj/item/device/encryptionkey/headset_service + name = "service radio encryption key" + icon_state = "srv_cypherkey" + channels = list("Service" = 1) + +/obj/item/device/encryptionkey/headset_inquisition + name = "inquisition radio key" + icon_state = "hos_cypherkey" + channels = list("Inquisition" = 1) + +/obj/item/device/encryptionkey/ert + name = "\improper ERT radio encryption key" + channels = list("Response Team" = 1, "Science" = 1, "Command" = 1, "Medical" = 1, "Engineering" = 1, "Security" = 1, "Supply" = 1, "Service" = 1) + +/obj/item/device/encryptionkey/specops //for events + name = "special operations radio encryption key" + icon_state = "bin_cypherkey" + channels = list("Special Ops" = 1) + origin_tech = list(TECH_ILLEGAL = 2) + +/obj/item/device/encryptionkey/entertainment + name = "entertainment radio key" + channels = list("Entertainment" = 1) \ No newline at end of file diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm new file mode 100644 index 00000000..e43a2396 --- /dev/null +++ b/code/game/objects/items/devices/radio/headset.dm @@ -0,0 +1,371 @@ +/obj/item/device/radio/headset + name = "radio headset" + desc = "An updated, modular intercom that fits over the head. Takes encryption keys." + var/radio_desc = "" + icon_state = "headset" + item_state = "headset" + matter = list(DEFAULT_WALL_MATERIAL = 75) + subspace_transmission = 1 + canhear_range = 0 // can't hear headsets from very far away + + slot_flags = SLOT_EARS + var/translate_binary = 0 + var/translate_hive = 0 + var/obj/item/device/encryptionkey/keyslot1 = null + var/obj/item/device/encryptionkey/keyslot2 = null + + var/ks1type = /obj/item/device/encryptionkey + var/ks2type = null + +/obj/item/device/radio/headset/Initialize() + . = ..() + internal_channels.Cut() + if(ks1type) + keyslot1 = new ks1type(src) + if(ks2type) + keyslot2 = new ks2type(src) + recalculateChannels(1) + +/obj/item/device/radio/headset/Destroy() + qdel(keyslot1) + qdel(keyslot2) + keyslot1 = null + keyslot2 = null + return ..() + +/obj/item/device/radio/headset/list_channels(var/mob/user) + return list_secure_channels() + +/obj/item/device/radio/headset/examine(mob/user) + if(!(..(user, 1) && radio_desc)) + return + + to_chat(user, "The following channels are available:") + to_chat(user, radio_desc) + +/obj/item/device/radio/headset/handle_message_mode(mob/living/M as mob, message, channel) + if (channel == "special") + if (translate_binary) + var/datum/language/binary = all_languages["Robot Talk"] + binary.broadcast(M, message) + if (translate_hive) + var/datum/language/hivemind = all_languages["Hivemind"] + hivemind.broadcast(M, message) + return null + + return ..() + +/obj/item/device/radio/headset/receive_range(freq, level, aiOverride = 0) + if (aiOverride) + return ..(freq, level) + if(ishuman(src.loc)) + var/mob/living/carbon/human/H = src.loc + if(H.l_ear == src || H.r_ear == src) + return ..(freq, level) + return -1 + +/obj/item/device/radio/headset/syndicate + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + ks1type = /obj/item/device/encryptionkey/red + +/obj/item/device/radio/headset/syndicate/Initialize() + . = ..() + set_frequency(RED_FREQ) + +/obj/item/device/radio/headset/raider + origin_tech = list(TECH_ILLEGAL = 2) + syndie = 1 + ks1type = /obj/item/device/encryptionkey/blue + +/obj/item/device/radio/headset/raider/Initialize() + . = ..() + set_frequency(BLUE_FREQ) + +/obj/item/device/radio/headset/binary + origin_tech = list(TECH_ILLEGAL = 3) + ks1type = /obj/item/device/encryptionkey/binary + +/obj/item/device/radio/headset/headset_sec + name = "security radio headset" + desc = "This is used by your elite security force." + icon_state = "sec_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/headset_sec + +/obj/item/device/radio/headset/headset_eng + name = "engineering radio headset" + desc = "When the engineers wish to chat like girls." + icon_state = "eng_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/headset_eng + +/obj/item/device/radio/headset/headset_rob + name = "robotics radio headset" + desc = "Made specifically for the roboticists who cannot decide between departments." + icon_state = "rob_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/headset_rob + +/obj/item/device/radio/headset/headset_med + name = "medical radio headset" + desc = "A headset for the trained staff of the medbay." + icon_state = "med_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/headset_med + +/obj/item/device/radio/headset/headset_sci + name = "science radio headset" + desc = "A sciency headset. Like usual." + icon_state = "com_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/headset_sci + +/obj/item/device/radio/headset/headset_medsci + name = "medical research radio headset" + desc = "A headset that is a result of the mating between medical and science." + icon_state = "med_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/headset_medsci + +/obj/item/device/radio/headset/headset_com + name = "command radio headset" + desc = "A headset with a commanding channel." + icon_state = "com_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/headset_com + +/obj/item/device/radio/headset/heads/captain + name = "captain's headset" + desc = "The headset of the boss." + icon_state = "com_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/heads/captain + +/obj/item/device/radio/headset/heads/ai_integrated //No need to care about icons, it should be hidden inside the AI anyway. + name = "\improper AI subspace transceiver" + desc = "Integrated AI radio transceiver." + icon = 'icons/obj/robot_component.dmi' + icon_state = "radio" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/heads/ai_integrated + var/myAi = null // Atlantis: Reference back to the AI which has this radio. + var/disabledAi = 0 // Atlantis: Used to manually disable AI's integrated radio via inteliCard menu. + +/obj/item/device/radio/headset/heads/ai_integrated/Destroy() + myAi = null + . = ..() + +/obj/item/device/radio/headset/heads/ai_integrated/receive_range(freq, level) + if (disabledAi) + return -1 //Transciever Disabled. + return ..(freq, level, 1) + +/obj/item/device/radio/headset/heads/rd + name = "research director's headset" + desc = "Headset of the researching God." + icon_state = "com_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/heads/rd + +/obj/item/device/radio/headset/heads/hos + name = "head of security's headset" + desc = "The headset of the man who protects your worthless lives." + icon_state = "com_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/heads/hos + +/obj/item/device/radio/headset/heads/ce + name = "chief engineer's headset" + desc = "The headset of the guy who is in charge of morons." + icon_state = "com_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/heads/ce + +/obj/item/device/radio/headset/heads/cmo + name = "chief medical officer's headset" + desc = "The headset of the highly trained medical chief." + icon_state = "com_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/heads/cmo + +/obj/item/device/radio/headset/heads/hop + name = "head of personnel's headset" + desc = "The headset of the guy who will one day be captain." + icon_state = "com_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/heads/hop + +/obj/item/device/radio/headset/headset_cargo + name = "supply radio headset" + desc = "A headset used by the box pushers." + icon_state = "cargo_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/headset_cargo + +/obj/item/device/radio/headset/headset_service + name = "service radio headset" + desc = "Headset used by the service staff, tasked with keeping everyone full, happy and clean." + icon_state = "srv_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/headset_service + +/obj/item/device/radio/headset/ert + name = "emergency response team radio headset" + desc = "The headset of the boss's boss." + icon_state = "com_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/ert + +/obj/item/device/radio/headset/ia + name = "internal affair's headset" + desc = "The headset of your worst enemy." + icon_state = "com_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/heads/hos + +/obj/item/device/radio/headset/entertainment + name = "actor's radio headset" + desc = "specially made to make you sound less cheesy." + icon_state = "com_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/entertainment + +/obj/item/device/radio/headset/inquisition + name = "inquisition's headset" + desc = "The headset of religious intolorence." + icon_state = "rob_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/headset_inquisition + +/obj/item/device/radio/headset/specops + name = "special operations radio headset" + desc = "The headset of the spooks." + icon_state = "cent_headset" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/specops + +/obj/item/device/radio/headset/attackby(obj/item/weapon/W as obj, mob/user as mob) +// ..() + user.set_machine(src) + if (!( isScrewdriver(W) || (istype(W, /obj/item/device/encryptionkey/ )))) + return + + if(isScrewdriver(W)) + if(keyslot1 || keyslot2) + + + for(var/ch_name in channels) + radio_controller.remove_object(src, radiochannels[ch_name]) + secure_radio_connections[ch_name] = null + + + if(keyslot1) + var/turf/T = get_turf(user) + if(T) + keyslot1.loc = T + keyslot1 = null + + + + if(keyslot2) + var/turf/T = get_turf(user) + if(T) + keyslot2.loc = T + keyslot2 = null + + recalculateChannels() + to_chat(user, "You pop out the encryption keys in the headset!") + + else + to_chat(user, "This headset doesn't have any encryption keys! How useless...") + + if(istype(W, /obj/item/device/encryptionkey/)) + if(keyslot1 && keyslot2) + to_chat(user, "The headset can't hold another key!") + return + + if(!keyslot1) + user.drop_item() + W.loc = src + keyslot1 = W + + else + user.drop_item() + W.loc = src + keyslot2 = W + + + recalculateChannels() + + return + +/obj/item/device/radio/headset/MouseDrop(var/obj/over_object) + var/mob/M = usr + if((!istype(over_object, /obj/screen)) && (src in M) && CanUseTopic(M)) + return attack_self(M) + return + +/obj/item/device/radio/headset/recalculateChannels(var/setDescription = 0) + src.channels = list() + src.translate_binary = 0 + src.translate_hive = 0 + src.syndie = 0 + + if(keyslot1) + for(var/ch_name in keyslot1.channels) + if(ch_name in src.channels) + continue + src.channels += ch_name + src.channels[ch_name] = keyslot1.channels[ch_name] + + if(keyslot1.translate_binary) + src.translate_binary = 1 + + if(keyslot1.translate_hive) + src.translate_hive = 1 + + if(keyslot1.syndie) + src.syndie = 1 + + if(keyslot2) + for(var/ch_name in keyslot2.channels) + if(ch_name in src.channels) + continue + src.channels += ch_name + src.channels[ch_name] = keyslot2.channels[ch_name] + + if(keyslot2.translate_binary) + src.translate_binary = 1 + + if(keyslot2.translate_hive) + src.translate_hive = 1 + + if(keyslot2.syndie) + src.syndie = 1 + + + for (var/ch_name in channels) + if(!radio_controller) + sleep(30) // Waiting for the radio_controller to be created. + if(!radio_controller) + src.SetName("broken radio headset") + return + + secure_radio_connections[ch_name] = radio_controller.add_object(src, radiochannels[ch_name], RADIO_CHAT) + + if(setDescription) + setupRadioDescription() + + return + +/obj/item/device/radio/headset/proc/setupRadioDescription() + var/radio_text = "" + for(var/i = 1 to channels.len) + var/channel = channels[i] + var/key = get_radio_key_from_channel(channel) + radio_text += "[key] - [channel]" + if(i != channels.len) + radio_text += ", " + + radio_desc = radio_text diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm new file mode 100644 index 00000000..ff9d6c71 --- /dev/null +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -0,0 +1,164 @@ +/obj/item/device/radio/intercom + name = "intercom (General)" + desc = "Talk through this." + icon_state = "intercom" + randpixel = 0 + anchored = 1 + w_class = ITEM_SIZE_HUGE + canhear_range = 2 + atom_flags = ATOM_FLAG_NO_BLOOD + obj_flags = OBJ_FLAG_CONDUCTIBLE + layer = ABOVE_WINDOW_LAYER + var/number = 0 + var/last_tick //used to delay the powercheck + +/obj/item/device/radio/intercom/get_storage_cost() + return ITEM_SIZE_NO_CONTAINER + +/obj/item/device/radio/intercom/custom + name = "intercom (Custom)" + broadcasting = 0 + listening = 0 + +/obj/item/device/radio/intercom/interrogation + name = "intercom (Interrogation)" + frequency = 1449 + +/obj/item/device/radio/intercom/private + name = "intercom (Private)" + frequency = AI_FREQ + +/obj/item/device/radio/intercom/specops + name = "\improper Spec Ops intercom" + frequency = ERT_FREQ + +/obj/item/device/radio/intercom/department + canhear_range = 5 + broadcasting = 0 + listening = 1 + +/obj/item/device/radio/intercom/department/medbay + name = "intercom (Medbay)" + frequency = MED_I_FREQ + +/obj/item/device/radio/intercom/department/security + name = "intercom (Security)" + frequency = SEC_I_FREQ + +/obj/item/device/radio/intercom/entertainment + name = "entertainment intercom" + frequency = ENT_FREQ + canhear_range = 4 + +/obj/item/device/radio/intercom/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/item/device/radio/intercom/department/medbay/Initialize() + . = ..() + internal_channels = GLOB.default_medbay_channels.Copy() + +/obj/item/device/radio/intercom/department/security/Initialize() + . = ..() + internal_channels = list( + num2text(PUB_FREQ) = list(), + num2text(SEC_I_FREQ) = list(access_security) + ) + +/obj/item/device/radio/intercom/entertainment/Initialize() + . = ..() + internal_channels = list( + num2text(PUB_FREQ) = list(), + num2text(ENT_FREQ) = list() + ) + +/obj/item/device/radio/intercom/syndicate + name = "illicit intercom" + desc = "Talk through this. Evilly." + frequency = RED_FREQ + subspace_transmission = 1 + syndie = 1 + +/obj/item/device/radio/intercom/syndicate/Initialize() + . = ..() + internal_channels[num2text(RED_FREQ)] = list(access_syndicate) + +/obj/item/device/radio/intercom/raider + name = "illicit intercom" + desc = "Pirate radio, but not in the usual sense of the word." + frequency = BLUE_FREQ + subspace_transmission = 1 + syndie = 1 + +/obj/item/device/radio/intercom/raider/Initialize() + . = ..() + internal_channels[num2text(BLUE_FREQ)] = list(access_syndicate) + +/obj/item/device/radio/intercom/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/device/radio/intercom/attack_ai(mob/user as mob) + src.add_fingerprint(user) + spawn (0) + attack_self(user) + +/obj/item/device/radio/intercom/attack_hand(mob/user as mob) + src.add_fingerprint(user) + spawn (0) + attack_self(user) + +/obj/item/device/radio/intercom/receive_range(freq, level) + if (!on) + return -1 + if(!(0 in level)) + var/turf/position = get_turf(src) + if(isnull(position) || !(position.z in level)) + return -1 + if (!src.listening) + return -1 + if(freq in ANTAG_FREQS) + if(!(src.syndie)) + return -1//Prevents broadcast of messages over devices lacking the encryption + + return canhear_range + +/obj/item/device/radio/intercom/Process() + if(((world.timeofday - last_tick) > 30) || ((world.timeofday - last_tick) < 0)) + last_tick = world.timeofday + + if(!src.loc) + on = 0 + else + var/area/A = get_area(src) + if(!A) + on = 0 + else + on = A.powered(EQUIP) // set "on" to the power status + + if(!on) + icon_state = "intercom-p" + else + icon_state = "intercom" + +/obj/item/device/radio/intercom/broadcasting + broadcasting = 1 + +/obj/item/device/radio/intercom/locked + var/locked_frequency + +/obj/item/device/radio/intercom/locked/set_frequency() + ..(locked_frequency) + +/obj/item/device/radio/intercom/locked/list_channels() + return "" + +/obj/item/device/radio/intercom/locked/ai_private + name = "\improper AI intercom" + locked_frequency = AI_FREQ + broadcasting = 1 + listening = 1 + +/obj/item/device/radio/intercom/locked/confessional + name = "confessional intercom" + locked_frequency = 1480 \ No newline at end of file diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm new file mode 100644 index 00000000..94fd6f84 --- /dev/null +++ b/code/game/objects/items/devices/radio/radio.dm @@ -0,0 +1,768 @@ +/obj/item/device/radio + icon = 'icons/obj/radio.dmi' + name = "shortwave radio" + suffix = "\[3\]" + icon_state = "walkietalkie" + item_state = "walkietalkie" + + var/on = 1 // 0 for off + var/last_transmission + var/frequency = PUB_FREQ //common chat + var/traitor_frequency = 0 //tune to frequency to unlock traitor supplies + var/canhear_range = 3 // the range which mobs can hear this radio from + var/datum/wires/radio/wires = null + var/b_stat = 0 + var/broadcasting = 0 + var/listening = 1 + var/list/channels = list() //see communications.dm for full list. First channel is a "default" for :h + var/subspace_transmission = 0 + var/syndie = 0//Holder to see if it's a syndicate encrypted radio + var/intercept = 0 //can intercept other channels + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + throw_speed = 2 + throw_range = 9 + w_class = ITEM_SIZE_SMALL + + matter = list("glass" = 25,DEFAULT_WALL_MATERIAL = 75) + var/const/FREQ_LISTENING = 1 + var/list/internal_channels + +/obj/item/device/radio + var/datum/radio_frequency/radio_connection + var/list/datum/radio_frequency/secure_radio_connections = new + + proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) + +/obj/item/device/radio/Initialize() + . = ..() + wires = new(src) + internal_channels = GLOB.using_map.default_internal_channels() + GLOB.listening_objects += src + + if(frequency < RADIO_LOW_FREQ || frequency > RADIO_HIGH_FREQ) + frequency = sanitize_frequency(frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) + set_frequency(frequency) + + for (var/ch_name in channels) + secure_radio_connections[ch_name] = radio_controller.add_object(src, radiochannels[ch_name], RADIO_CHAT) + +/obj/item/device/radio/Destroy() + QDEL_NULL(wires) + GLOB.listening_objects -= src + if(radio_controller) + radio_controller.remove_object(src, frequency) + for (var/ch_name in channels) + radio_controller.remove_object(src, radiochannels[ch_name]) + return ..() + +/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 + + if(b_stat) + wires.Interact(user) + + return ui_interact(user) + +/obj/item/device/radio/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) + + data["mic_cut"] = (wires.IsIndexCut(WIRE_TRANSMIT) || wires.IsIndexCut(WIRE_SIGNAL)) + data["spk_cut"] = (wires.IsIndexCut(WIRE_RECEIVE) || wires.IsIndexCut(WIRE_SIGNAL)) + + 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 = GLOB.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() + +/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])))) + + return dat + +/obj/item/device/radio/proc/list_internal_channels(var/mob/user) + var/dat[0] + 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))))) + + return dat + +/obj/item/device/radio/proc/has_channel_access(var/mob/user, var/freq) + if(!user) + return 0 + + if(!(freq in internal_channels)) + return 0 + + return user.has_internal_radio_channel_access(internal_channels[freq]) + +/mob/proc/has_internal_radio_channel_access(var/list/req_one_accesses) + var/obj/item/weapon/card/id/I = GetIdCard() + return has_access(list(), req_one_accesses, I ? I.GetAccess() : list()) + +/mob/observer/ghost/has_internal_radio_channel_access(var/list/req_one_accesses) + return can_admin_interact() + +/obj/item/device/radio/proc/text_wires() + if (b_stat) + return wires.GetInteractWindow() + return + + +/obj/item/device/radio/proc/text_sec_channel(var/chan_name, var/chan_stat) + var/list = !!(chan_stat&FREQ_LISTENING)!=0 + return {" + [chan_name]
            + Speaker: [list ? "Engaged" : "Disengaged"]
            + "} + +/obj/item/device/radio/proc/ToggleBroadcast() + broadcasting = !broadcasting && !(wires.IsIndexCut(WIRE_TRANSMIT) || wires.IsIndexCut(WIRE_SIGNAL)) + +/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(..()) + return 1 + + usr.set_machine(src) + if (href_list["track"]) + var/mob/target = locate(href_list["track"]) + var/mob/living/silicon/ai/A = locate(href_list["track2"]) + if(A && target) + A.ai_actual_track(target) + . = 1 + + else if (href_list["freq"]) + var/new_frequency = (frequency + text2num(href_list["freq"])) + if ((new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ)) + new_frequency = sanitize_frequency(new_frequency) + set_frequency(new_frequency) + if(hidden_uplink) + if(hidden_uplink.check_trigger(usr, frequency, traitor_frequency)) + usr << browse(null, "window=radio") + . = 1 + else if (href_list["talk"]) + ToggleBroadcast() + . = 1 + else if (href_list["listen"]) + var/chan_name = href_list["ch_name"] + if (!chan_name) + ToggleReception() + else + if (channels[chan_name] & FREQ_LISTENING) + channels[chan_name] &= ~FREQ_LISTENING + else + channels[chan_name] |= FREQ_LISTENING + . = 1 + else if(href_list["spec_freq"]) + var freq = href_list["spec_freq"] + if(has_channel_access(usr, freq)) + set_frequency(text2num(freq)) + . = 1 + if(href_list["nowindow"]) // here for pAIs, maybe others will want it, idk + return 1 + + if(.) + GLOB.nanomanager.update_uis(src) + +/obj/item/device/radio/proc/autosay(var/message, var/from, var/channel) //BS12 EDIT + var/datum/radio_frequency/connection = null + if(channel && channels && channels.len > 0) + if (channel == "department") + channel = channels[1] + connection = secure_radio_connections[channel] + else + connection = radio_connection + channel = null + if (!istype(connection)) + return + var/mob/living/silicon/ai/A = new /mob/living/silicon/ai(src, null, null, 1) + A.fully_replace_character_name(from) + talk_into(A, message, channel,"states") + qdel(A) + +// Interprets the message mode when talking into a radio, possibly returning a connection datum +/obj/item/device/radio/proc/handle_message_mode(mob/living/M as mob, message, message_mode) + // If a channel isn't specified, send to common. + if(!message_mode || message_mode == "headset") + return radio_connection + + // Otherwise, if a channel is specified, look for it. + if(channels && channels.len > 0) + if (message_mode == "department") // Department radio shortcut + message_mode = channels[1] + + if (channels[message_mode]) // only broadcast if the channel is set on + return secure_radio_connections[message_mode] + + // If we were to send to a channel we don't have, drop it. + return null + +/obj/item/device/radio/talk_into(mob/living/M as mob, message, channel, var/verb = "says", var/datum/language/speaking = null) + if(!on) return 0 // the device has to be on + // Fix for permacell radios, but kinda eh about actually fixing them. + if(!M || !message) return 0 + + if(speaking && (speaking.flags & (NONVERBAL|SIGNLANG))) return 0 + + if(istype(M)) M.trigger_aiming(TARGET_CAN_RADIO) + + // Uncommenting this. To the above comment: + // The permacell radios aren't suppose to be able to transmit, this isn't a bug and this "fix" is just making radio wires useless. -Giacom + if(wires.IsIndexCut(WIRE_TRANSMIT)) // The device has to have all its wires and shit intact + return 0 + + if(!radio_connection) + set_frequency(frequency) + + /* Quick introduction: + This new radio system uses a very robust FTL signaling technology unoriginally + dubbed "subspace" which is somewhat similar to 'blue-space' but can't + actually transmit large mass. Headsets are the only radio devices capable + of sending subspace transmissions to the Communications Satellite. + + A headset sends a signal to a subspace listener/reciever elsewhere in space, + the signal gets processed and logged, and an audible transmission gets sent + to each individual headset. + */ + + //#### Grab the connection datum ####// + var/datum/radio_frequency/connection = handle_message_mode(M, message, channel) + if (!istype(connection)) + return 0 + + var/turf/position = get_turf(src) + + //#### Tagging the signal with all appropriate identity values ####// + + // ||-- The mob's name identity --|| + var/displayname = M.name // grab the display name (name you get when you hover over someone's icon) + var/real_name = M.real_name // mob's real name + var/mobkey = "none" // player key associated with mob + var/voicemask = 0 // the speaker is wearing a voice mask + if(M.client) + mobkey = M.key // assign the mob's key + + + var/jobname // the mob's "job" + + // --- Human: use their actual job --- + if (ishuman(M)) + var/mob/living/carbon/human/H = M + jobname = H.get_assignment() + + // --- Carbon Nonhuman --- + else if (iscarbon(M)) // Nonhuman carbon mob + jobname = "No id" + + // --- AI --- + else if (isAI(M)) + jobname = "AI" + + // --- Cyborg --- + else if (isrobot(M)) + jobname = "Cyborg" + + // --- Personal AI (pAI) --- + else if (istype(M, /mob/living/silicon/pai)) + jobname = "Personal AI" + + // --- Unidentifiable mob --- + else + jobname = "Unknown" + + + // --- Modifications to the mob's identity --- + + // The mob is disguising their identity: + if (ishuman(M) && M.GetVoice() != real_name) + displayname = M.GetVoice() + jobname = "Unknown" + voicemask = 1 + + + + /* ###### Radio headsets can only broadcast through subspace ###### */ + if(subspace_transmission) + // First, we want to generate a new radio signal + var/datum/signal/signal = new + signal.transmission_method = 2 // 2 would be a subspace transmission. + // transmission_method could probably be enumerated through #define. Would be neater. + + // --- Finally, tag the actual signal with the appropriate values --- + signal.data = list( + // Identity-associated tags: + "mob" = M, // store a reference to the mob + "mobtype" = M.type, // the mob's type + "realname" = real_name, // the mob's real name + "name" = displayname, // the mob's display name + "job" = jobname, // the mob's job + "key" = mobkey, // the mob's key + "vmessage" = pick(M.speak_emote), // the message to display if the voice wasn't understood + "vname" = M.voice_name, // the name to display if the voice wasn't understood + "vmask" = voicemask, // 1 if the mob is using a voice gas mask + + // We store things that would otherwise be kept in the actual mob + // so that they can be logged even AFTER the mob is deleted or something + + // Other tags: + "compression" = rand(45,50), // compressed radio signal + "message" = message, // the actual sent message + "connection" = connection, // the radio connection to use + "radio" = src, // stores the radio used for transmission + "slow" = 0, // how much to sleep() before broadcasting - simulates net lag + "traffic" = 0, // dictates the total traffic sum that the signal went through + "type" = 0, // determines what type of radio input it is: normal broadcast + "server" = null, // the last server to log this signal + "reject" = 0, // if nonzero, the signal will not be accepted by any broadcasting machinery + "level" = position.z, // The source's z level + "language" = speaking, + "verb" = verb + ) + signal.frequency = connection.frequency // Quick frequency set + + //#### Sending the signal to all subspace receivers ####// + + for(var/obj/machinery/telecomms/receiver/R in telecomms_list) + R.receive_signal(signal) + + // Allinone can act as receivers. + for(var/obj/machinery/telecomms/allinone/R in telecomms_list) + R.receive_signal(signal) + + // Receiving code can be located in Telecommunications.dm + return signal.data["done"] && position.z in signal.data["level"] + + + /* ###### Intercoms and station-bounced radios ###### */ + + var/filter_type = 2 + + /* --- Intercoms can only broadcast to other intercoms, but bounced radios can broadcast to bounced radios and intercoms --- */ + if(istype(src, /obj/item/device/radio/intercom)) + filter_type = 1 + + + var/datum/signal/signal = new + signal.transmission_method = 2 + + + /* --- Try to send a normal subspace broadcast first */ + + signal.data = list( + + "mob" = M, // store a reference to the mob + "mobtype" = M.type, // the mob's type + "realname" = real_name, // the mob's real name + "name" = displayname, // the mob's display name + "job" = jobname, // the mob's job + "key" = mobkey, // the mob's key + "vmessage" = pick(M.speak_emote), // the message to display if the voice wasn't understood + "vname" = M.voice_name, // the name to display if the voice wasn't understood + "vmask" = voicemask, // 1 if the mob is using a voice gas mas + + "compression" = 0, // uncompressed radio signal + "message" = message, // the actual sent message + "connection" = connection, // the radio connection to use + "radio" = src, // stores the radio used for transmission + "slow" = 0, + "traffic" = 0, + "type" = 0, + "server" = null, + "reject" = 0, + "level" = position.z, + "language" = speaking, + "verb" = verb + ) + signal.frequency = connection.frequency // Quick frequency set + + for(var/obj/machinery/telecomms/receiver/R in telecomms_list) + R.receive_signal(signal) + + + sleep(rand(10,25)) // wait a little... + + if(signal.data["done"] && position.z in signal.data["level"]) + // we're done here. + return 1 + + // Oh my god; the comms are down or something because the signal hasn't been broadcasted yet in our level. + // Send a mundane broadcast with limited targets: + + //THIS IS TEMPORARY. YEAH RIGHT + if(!connection) return 0 //~Carn + return Broadcast_Message(connection, M, voicemask, pick(M.speak_emote), + src, message, displayname, jobname, real_name, M.voice_name, + filter_type, signal.data["compression"], GetConnectedZlevels(position.z), connection.frequency,verb,speaking) + + +/obj/item/device/radio/hear_talk(mob/M as mob, msg, var/verb = "says", var/datum/language/speaking = null) + + if (broadcasting) + if(get_dist(src, M) <= canhear_range) + talk_into(M, msg,null,verb,speaking) + + +/* +/obj/item/device/radio/proc/accept_rad(obj/item/device/radio/R as obj, message) + + if ((R.frequency == frequency && message)) + return 1 + else if + + else + return null + return +*/ + + +/obj/item/device/radio/proc/receive_range(freq, level) + // check if this radio can receive on the given frequency, and if so, + // what the range is in which mobs will hear the radio + // returns: -1 if can't receive, range otherwise + + if (wires.IsIndexCut(WIRE_RECEIVE)) + return -1 + if(!listening) + return -1 + if(!(0 in level)) + var/turf/position = get_turf(src) + if(!position || !(position.z in level)) + return -1 + if(freq in ANTAG_FREQS) + if(!(src.syndie))//Checks to see if it's allowed on that frequency, based on the encryption keys + return -1 + if (!on) + return -1 + if (!freq) //recieved on main frequency + if (!listening) + return -1 + else + var/accept = (freq==frequency && listening) + if (!accept) + for (var/ch_name in channels) + var/datum/radio_frequency/RF = secure_radio_connections[ch_name] + if (RF.frequency==freq && (channels[ch_name]&FREQ_LISTENING)) + accept = 1 + break + if (!accept) + return -1 + return canhear_range + +/obj/item/device/radio/proc/send_hear(freq, level) + + var/range = receive_range(freq, level) + if(range > -1) + return get_mobs_or_objects_in_view(canhear_range, src) + + +/obj/item/device/radio/examine(mob/user) + . = ..() + if ((in_range(src, user) || loc == user)) + if (b_stat) + user.show_message("\The [src] can be attached and modified!") + else + user.show_message("\The [src] can not be modified or attached!") + return + +/obj/item/device/radio/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + user.set_machine(src) + if (!( isScrewdriver(W) )) + return + b_stat = !( b_stat ) + if(!istype(src, /obj/item/device/radio/beacon)) + if (b_stat) + user.show_message("\The [src] can now be attached and modified!") + else + user.show_message("\The [src] can no longer be modified or attached!") + updateDialog() + return + +/obj/item/device/radio/emp_act(severity) + broadcasting = 0 + listening = 0 + for (var/ch_name in channels) + channels[ch_name] = 0 + ..() + +/obj/item/device/radio/proc/recalculateChannels() + return + +/////////////////////////////// +//////////Borg Radios////////// +/////////////////////////////// +//Giving borgs their own radio to have some more room to work with -Sieve + +/obj/item/device/radio/borg + var/mob/living/silicon/robot/myborg = null // Cyborg which owns this radio. Used for power checks + var/obj/item/device/encryptionkey/keyslot = null//Borg radios can handle a single encryption key + var/shut_up = 1 + icon = 'icons/obj/robot_component.dmi' // Cyborgs radio icons should look like the component. + icon_state = "radio" + canhear_range = 0 + subspace_transmission = 1 + +/obj/item/device/radio/borg/ert + keyslot = /obj/item/device/encryptionkey/ert + +/obj/item/device/radio/borg/syndicate + keyslot = /obj/item/device/encryptionkey/red + +/obj/item/device/radio/borg/New(var/mob/living/silicon/robot/loc) + if(!istype(loc)) + CRASH("Invalid spawn location: [log_info_line(loc)]") + ..() + myborg = loc + +/obj/item/device/radio/borg/Initialize() + . = ..() + recalculateChannels() + +/obj/item/device/radio/borg/Destroy() + QDEL_NULL(keyslot) + myborg = null + return ..() + +/obj/item/device/radio/borg/list_channels(var/mob/user) + return list_secure_channels(user) + +/obj/item/device/radio/borg/talk_into() + . = ..() + if (isrobot(src.loc)) + var/mob/living/silicon/robot/R = src.loc + var/datum/robot_component/C = R.components["radio"] + R.cell_use_power(C.active_usage) + +/obj/item/device/radio/borg/attackby(obj/item/weapon/W as obj, mob/user as mob) +// ..() + user.set_machine(src) + if (!( isScrewdriver(W) || (istype(W, /obj/item/device/encryptionkey/ )))) + return + + if(isScrewdriver(W)) + if(keyslot) + + + for(var/ch_name in channels) + radio_controller.remove_object(src, radiochannels[ch_name]) + secure_radio_connections[ch_name] = null + + + if(keyslot) + var/turf/T = get_turf(user) + if(T) + keyslot.loc = T + keyslot = null + + recalculateChannels() + to_chat(user, "You pop out the encryption key in the radio!") + + else + to_chat(user, "This radio doesn't have any encryption keys!") + + if(istype(W, /obj/item/device/encryptionkey/)) + if(keyslot) + to_chat(user, "The radio can't hold another key!") + return + + if(!keyslot) + user.drop_item() + W.loc = src + keyslot = W + + recalculateChannels() + + return + +/obj/item/device/radio/borg/recalculateChannels() + src.channels = list() + src.syndie = 0 + + var/mob/living/silicon/robot/D = src.loc + if(D.module) + for(var/ch_name in D.module.channels) + if(ch_name in src.channels) + continue + src.channels += ch_name + src.channels[ch_name] += D.module.channels[ch_name] + if(keyslot) + for(var/ch_name in keyslot.channels) + if(ch_name in src.channels) + continue + src.channels += ch_name + src.channels[ch_name] += keyslot.channels[ch_name] + + if(keyslot.syndie) + src.syndie = 1 + + for (var/ch_name in src.channels) + if(!radio_controller) + src.SetName("broken radio") + return + + secure_radio_connections[ch_name] = radio_controller.add_object(src, radiochannels[ch_name], RADIO_CHAT) + +/obj/item/device/radio/borg/Topic(href, href_list) + if(..()) + return 1 + if (href_list["mode"]) + var/enable_subspace_transmission = text2num(href_list["mode"]) + if(enable_subspace_transmission != subspace_transmission) + subspace_transmission = !subspace_transmission + if(subspace_transmission) + to_chat(usr, "Subspace Transmission is enabled") + else + to_chat(usr, "Subspace Transmission is disabled") + + if(subspace_transmission == 0)//Simple as fuck, clears the channel list to prevent talking/listening over them if subspace transmission is disabled + channels = list() + else + recalculateChannels() + . = 1 + if (href_list["shutup"]) // Toggle loudspeaker mode, AKA everyone around you hearing your radio. + var/do_shut_up = text2num(href_list["shutup"]) + if(do_shut_up != shut_up) + shut_up = !shut_up + if(shut_up) + canhear_range = 0 + to_chat(usr, "Loadspeaker disabled.") + else + canhear_range = 3 + to_chat(usr, "Loadspeaker enabled.") + . = 1 + + if(.) + GLOB.nanomanager.update_uis(src) + +/obj/item/device/radio/borg/interact(mob/user as mob) + if(!on) + return + + . = ..() + +/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 = GLOB.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() + +/obj/item/device/radio/proc/config(op) + if(radio_controller) + for (var/ch_name in channels) + radio_controller.remove_object(src, radiochannels[ch_name]) + secure_radio_connections = new + channels = op + if(radio_controller) + for (var/ch_name in op) + secure_radio_connections[ch_name] = radio_controller.add_object(src, radiochannels[ch_name], RADIO_CHAT) + return + +/obj/item/device/radio/off + listening = 0 + +/obj/item/device/radio/announcer + invisibility = 101 + listening = 0 + canhear_range = 0 + anchored = 1 + simulated = 0 + channels=list("Engineering" = 1, "Security" = 1, "Medical" = 1, "Command" = 1, "Common" = 1, "Science" = 1, "Supply" = 1, "Service" = 1, "Exploration" = 1) + +/obj/item/device/radio/announcer/Destroy() + crash_with("attempt to delete a [src.type] detected, and prevented.") + return 1 + +/obj/item/device/radio/announcer/Initialize() + . = ..() + forceMove(locate(1,1,GLOB.using_map.contact_levels.len ? GLOB.using_map.contact_levels[1] : 1)) + +/obj/item/device/radio/announcer/subspace + subspace_transmission = 1 + +/obj/item/device/radio/phone + broadcasting = 0 + icon = 'icons/obj/items.dmi' + icon_state = "red_phone" + randpixel = 0 + listening = 1 + name = "phone" + +/obj/item/device/radio/phone/medbay + frequency = MED_I_FREQ + +/obj/item/device/radio/phone/medbay/New() + ..() + internal_channels = GLOB.default_medbay_channels.Copy() + +/obj/item/device/radio/CouldUseTopic(var/mob/user) + ..() + if(istype(user, /mob/living/carbon)) + playsound(src, "button", 10) + +/obj/item/device/radio/intercept + name = "bulky radio" + desc = "A large radio fitted with several military-grade communication interception circuits." + icon_state = "radio" + intercept = 1 + w_class = ITEM_SIZE_NORMAL \ No newline at end of file diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm new file mode 100644 index 00000000..c32764e0 --- /dev/null +++ b/code/game/objects/items/devices/scanners.dm @@ -0,0 +1,555 @@ +/* +CONTAINS: +T-RAY +DETECTIVE SCANNER +HEALTH ANALYZER +GAS ANALYZER +MASS SPECTROMETER +REAGENT SCANNER +*/ + + +/obj/item/device/healthanalyzer + name = "health analyzer" + desc = "A hand-held body scanner able to distinguish vital signs of the subject." + icon_state = "health" + item_state = "analyzer" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + throwforce = 3 + w_class = ITEM_SIZE_SMALL + throw_speed = 5 + throw_range = 10 + matter = list(DEFAULT_WALL_MATERIAL = 200) + origin_tech = list(TECH_MAGNET = 1, TECH_BIO = 1) + var/mode = 1; + +/obj/item/device/healthanalyzer/do_surgery(mob/living/M, mob/living/user) + if(user.a_intent != I_HELP) //in case it is ever used as a surgery tool + return ..() + scan_mob(M, user) //default surgery behaviour is just to scan as usual + return 1 + +/obj/item/device/healthanalyzer/attack(mob/living/M, mob/living/user) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + scan_mob(M, user) + +/obj/item/device/healthanalyzer/proc/scan_mob(var/mob/living/carbon/human/H, var/mob/living/user) + + if (!user.IsAdvancedToolUser()) + to_chat(user, "You are not nimble enough to use this device.") + return + + if ((CLUMSY in user.mutations) && prob(50)) + user.visible_message("\The [user] runs \the [src] over the floor.") + to_chat(user, "Scan results for the floor:") + to_chat(user, "Overall Status: Healthy") + return + + if (!istype(H) || H.isSynthetic()) + to_chat(user, "\The [src] is designed for organic humanoid patients only.") + return + + user.visible_message("\The [user] runs \the [src] over \the [H].") + playsound(user, "sound/effects/medscan[rand(1,7)].ogg", 50) + to_chat(user, "
            ") + to_chat(user, medical_scan_results(H, mode)) + to_chat(user, "
            ") + +proc/medical_scan_results(var/mob/living/carbon/human/H, var/verbose) + . = list() + . += "Scan results for \the [H]:" + + // Brain activity. + var/brain_result = "normal" + if(H.should_have_organ(BP_BRAIN)) + var/obj/item/organ/internal/brain/brain = H.internal_organs_by_name[BP_BRAIN] + if(!brain || H.stat == DEAD || (H.status_flags & FAKEDEATH)) + brain_result = "none, patient is braindead" + else if(H.stat != DEAD) + if(H.has_brain_worms()) + brain_result = "ERROR - aberrant/unknown brainwave patterns, advanced scanner recommended" + else + switch(brain.get_current_damage_threshold()) + if(0) + brain_result = "normal" + if(1 to 2) + brain_result = "minor brain damage" + if(3 to 5) + brain_result = "weak" + if(6 to 8) + brain_result = "extremely weak" + if(9 to INFINITY) + brain_result = "fading" + else + brain_result = "ERROR - Hardware fault" + else + brain_result = "ERROR - Nonstandard biology" + . += "Brain activity: [brain_result]." + + if(H.stat == DEAD || (H.status_flags & FAKEDEATH)) + . += "Time of Death: [time2text(worldtime2stationtime(H.timeofdeath), "hh:mm")]" + + if (H.internal_organs_by_name[BP_STACK]) + . += "Subject has a neural lace implant." + + // Pulse rate. + var/pulse_result = "normal" + if(H.should_have_organ(BP_HEART)) + if(H.status_flags & FAKEDEATH) + pulse_result = 0 + else + pulse_result = H.get_pulse(1) + else + pulse_result = "ERROR - Nonstandard biology" + + . += "Pulse rate: [pulse_result]bpm." + + // Blood pressure. Based on the idea of a normal blood pressure being 120 over 80. + if(H.get_blood_volume() <= 70) + . += "Severe blood loss detected." + . += "Blood pressure: [H.get_blood_pressure()] ([H.get_blood_oxygenation()]% blood oxygenation)" + + // Body temperature. + . += "Body temperature: [H.bodytemperature-T0C]°C ([H.bodytemperature*1.8-459.67]°F)" + + . += "Blood type: [H.b_type]." + + // Radiation. + switch(H.radiation) + if(-INFINITY to 0) + . += "No radiation detected." + if(1 to 30) + . += "Patient shows minor traces of radiation exposure." + if(31 to 60) + . += "Patient is suffering from mild radiation poisoning." + if(61 to 90) + . += "Patient is suffering from advanced radiation poisoning." + if(91 to 120) + . += "Patient is suffering from severe radiation poisoning." + if(121 to 240) + . += "Patient is suffering from extreme radiation poisoning. Immediate treatment recommended." + if(241 to INFINITY) + . += "Patient is suffering from acute radiation poisoning. Immediate treatment recommended." + + // Traumatic shock. + if(H.is_asystole()) + . += "Patient is suffering from cardiovascular shock. Administer CPR immediately." + else if(H.shock_stage > 80) + . += "Patient is at serious risk of going into shock. Pain relief recommended." + + // Other general warnings. + if(H.getOxyLoss() > 50) + . += "Severe oxygen deprivation detected." + if(H.getToxLoss() > 50) + . += "Major systemic organ failure detected." + if(H.getFireLoss() > 50) + . += "Severe burn damage detected." + if(H.getBruteLoss() > 50) + . += "Severe anatomical damage detected." + + for(var/name in H.organs_by_name) + var/obj/item/organ/external/e = H.organs_by_name[name] + if(!e) + continue + var/limb = e.name + if(e.status & ORGAN_BROKEN) + if(((e.name == BP_L_ARM) || (e.name == BP_R_ARM) || (e.name == BP_L_LEG) || (e.name == BP_R_LEG)) && (!e.splinted)) + . += "Unsecured fracture in subject [limb]. Splinting recommended for transport." + if(e.has_infected_wound()) + . += "Infected wound detected in subject [limb]. Disinfection recommended." + + for(var/name in H.organs_by_name) + var/obj/item/organ/external/E = H.organs_by_name[name] + if(E && E.status & ORGAN_BROKEN) + . += "Fractures detected in the [E.name]." + + var/found_disloc + for(var/obj/item/organ/external/e in H.organs) + if(e) + if(!found_disloc && e.dislocated == 2) + . += "Dislocation detected. Advanced scanner required for location." + found_disloc = TRUE + if(e.status & ORGAN_TENDON_CUT) + . += "Tendon or ligament damage detected in [e.name]." + if(found_disloc) + break + + if(verbose) + + // Limb status. + . += "Specific limb damage:" + + var/list/damaged = H.get_damaged_organs(1,1) + if(damaged.len) + for(var/obj/item/organ/external/org in damaged) + var/limb_result = "[capitalize(org.name)][(org.robotic >= ORGAN_ROBOT) ? " (Cybernetic)" : ""]:" + if(org.brute_dam > 0) + limb_result = "[limb_result] \[[get_wound_severity(org.brute_ratio, org.vital)] physical trauma\]" + if(org.burn_dam > 0) + limb_result = "[limb_result] \[[get_wound_severity(org.burn_ratio, org.vital)] burns\]" + if(org.status & ORGAN_BLEEDING) + limb_result = "[limb_result] \[bleeding\]" + if(org.status & ORGAN_ARTERY_CUT) + limb_result = "[limb_result] \[arterial bleeding\]" + for(var/datum/wound/wound in org.wounds) + if(wound.embedded_objects.len) + limb_result += " \[bullet shrapnel\]" + . += limb_result + else + . += "No detectable limb injuries." + + // Reagent data. + . += "Reagent scan:" + + var/print_reagent_default_message = TRUE + if(H.reagents.total_volume) + var/unknown = 0 + var/reagentdata[0] + for(var/A in H.reagents.reagent_list) + var/datum/reagent/R = A + if(R.scannable) + print_reagent_default_message = FALSE + reagentdata[R.type] = " [round(H.reagents.get_reagent_amount(R.type), 1)]u [R.name]" + else + unknown++ + if(reagentdata.len) + print_reagent_default_message = FALSE + . += "Beneficial reagents detected in subject's blood:" + for(var/d in reagentdata) + . += reagentdata[d] + if(unknown) + print_reagent_default_message = FALSE + . += "Warning: Unknown substance[(unknown>1)?"s":""] detected in subject's blood." + + if(H.ingested && H.ingested.total_volume) + var/unknown = 0 + for(var/datum/reagent/R in H.ingested.reagent_list) + if(R.scannable) + print_reagent_default_message = FALSE + . += "[R.name] found in subject's stomach." + else + ++unknown + if(unknown) + print_reagent_default_message = FALSE + . += "Non-medical reagent[(unknown > 1)?"s":""] found in subject's stomach." + + if(H.chem_doses.len) + var/list/chemtraces = list() + for(var/T in H.chem_doses) + var/datum/reagent/R = T + if(initial(R.scannable)) + chemtraces += "[initial(R.name)] ([H.chem_doses[T]])" + if(chemtraces.len) + . += "Metabolism products of [english_list(chemtraces)] found in subject's system." + + if(H.virus2.len) + for (var/ID in H.virus2) + if (ID in virusDB) + print_reagent_default_message = FALSE + var/datum/computer_file/data/virus_record/V = virusDB[ID] + . += "Warning: Pathogen [V.fields["name"]] detected in subject's blood. Known antigen : [V.fields["antigen"]]" + + if(print_reagent_default_message) + . += "No results." + . = jointext(.,"
            ") + +// Calculates severity based on the ratios defined external limbs. +proc/get_wound_severity(var/damage_ratio, var/vital = 0) + var/degree + + switch(damage_ratio) + if(0 to 0.1) + degree = "minor" + if(0.1 to 0.25) + degree = "moderate" + if(0.25 to 0.5) + degree = "significant" + if(0.5 to 0.75) + degree = "severe" + if(0.75 to 1) + degree = "extreme" + else + if(vital) + degree = "critical" + else + degree = "irreparable" + + return degree + +/obj/item/device/healthanalyzer/verb/toggle_mode() + set name = "Switch Verbosity" + set category = "Object" + + mode = !mode + if(mode) + to_chat(usr, "The scanner now shows specific limb damage.") + else + to_chat(usr, "The scanner no longer shows limb damage.") + +/obj/item/device/analyzer + name = "analyzer" + desc = "A hand-held environmental scanner which reports current gas levels." + icon_state = "atmos" + item_state = "analyzer" + w_class = ITEM_SIZE_SMALL + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + throwforce = 5 + throw_speed = 4 + throw_range = 20 + + matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 20) + + origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1) + var/advanced_mode = 0 + +/obj/item/device/analyzer/proc/verbosity(mob/user) + set name = "Toggle Advanced Gas Analysis" + set category = "Object" + + if (!user.incapacitated()) + advanced_mode = !advanced_mode + to_chat(user, "You toggle advanced gas analysis [advanced_mode ? "on" : "off"].") + +/obj/item/device/analyzer/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + if(src == user.get_active_hand()) + verbosity(user) + +/obj/item/device/analyzer/attack_self(mob/user) + + if (user.incapacitated()) + return + if (!user.IsAdvancedToolUser()) + return + + analyze_gases(user.loc, user,advanced_mode) + return 1 + +/obj/item/device/analyzer/afterattack(obj/O, mob/user, proximity) + if(!proximity) + return + if (user.incapacitated()) + return + if (!user.IsAdvancedToolUser()) + return + if(istype(O) && O.simulated) + analyze_gases(O, user, advanced_mode) + +/obj/item/device/mass_spectrometer + name = "mass spectrometer" + desc = "A hand-held mass spectrometer which identifies trace chemicals in a blood sample." + icon_state = "spectrometer" + item_state = "analyzer" + w_class = ITEM_SIZE_SMALL + atom_flags = ATOM_FLAG_OPEN_CONTAINER + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + throwforce = 5 + throw_speed = 4 + throw_range = 20 + + matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 20) + + origin_tech = list(TECH_MAGNET = 2, TECH_BIO = 2) + var/details = 0 + var/recent_fail = 0 + +/obj/item/device/mass_spectrometer/New() + ..() + create_reagents(5) + +/obj/item/device/mass_spectrometer/on_reagent_change() + update_icon() + +/obj/item/device/mass_spectrometer/update_icon() + icon_state = initial(icon_state) + if(reagents.total_volume) + icon_state += "_s" + +/obj/item/device/mass_spectrometer/attack_self(mob/user as mob) + if (user.incapacitated()) + return + if (!user.IsAdvancedToolUser()) + return + if(reagents.total_volume) + var/list/blood_traces = list() + var/list/blood_doses = list() + for(var/datum/reagent/R in reagents.reagent_list) + if(R.type != /datum/reagent/blood) + reagents.clear_reagents() + to_chat(user, "The sample was contaminated! Please insert another sample") + return + else + blood_traces = params2list(R.data["trace_chem"]) + blood_doses = params2list(R.data["dose_chem"]) + break + var/dat = "Trace Chemicals Found: " + for(var/T in blood_traces) + var/datum/reagent/R = T + if(details) + dat += "[initial(R.name)] ([blood_traces[T]] units) " + else + dat += "[initial(R.name)] " + if(details) + dat += "\nMetabolism Products of Chemicals Found:" + for(var/T in blood_doses) + var/datum/reagent/R = T + dat += "[initial(R.name)] ([blood_doses[T]] units) " + to_chat(user, "[dat]") + reagents.clear_reagents() + return + +/obj/item/device/mass_spectrometer/adv + name = "advanced mass spectrometer" + icon_state = "adv_spectrometer" + details = 1 + origin_tech = list(TECH_MAGNET = 4, TECH_BIO = 2) + +/obj/item/device/reagent_scanner + name = "reagent scanner" + desc = "A hand-held reagent scanner which identifies chemical agents." + icon_state = "spectrometer" + item_state = "analyzer" + w_class = ITEM_SIZE_SMALL + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + throwforce = 5 + throw_speed = 4 + throw_range = 20 + matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 20) + + origin_tech = list(TECH_MAGNET = 2, TECH_BIO = 2) + var/details = 0 + var/recent_fail = 0 + +/obj/item/device/reagent_scanner/afterattack(obj/O, mob/user as mob, proximity) + if(!proximity) + return + if (user.incapacitated()) + return + if (!user.IsAdvancedToolUser()) + return + if(!istype(O)) + return + + if(!isnull(O.reagents)) + var/dat = "" + if(O.reagents.reagent_list.len > 0) + var/one_percent = O.reagents.total_volume / 100 + for (var/datum/reagent/R in O.reagents.reagent_list) + dat += "\n \t [R][details ? ": [R.volume / one_percent]%" : ""]" + if(dat) + to_chat(user, "Chemicals found: [dat]") + else + to_chat(user, "No active chemical agents found in [O].") + else + to_chat(user, "No significant chemical agents found in [O].") + + return + +/obj/item/device/reagent_scanner/adv + name = "advanced reagent scanner" + icon_state = "adv_spectrometer" + details = 1 + origin_tech = list(TECH_MAGNET = 4, TECH_BIO = 2) + +/obj/item/device/price_scanner + name = "price scanner" + desc = "Using an up-to-date database of various costs and prices, this device estimates the market price of an item up to 0.001% accuracy." + icon_state = "price_scanner" + origin_tech = list(TECH_MATERIAL = 6, TECH_MAGNET = 4) + slot_flags = SLOT_BELT + w_class = ITEM_SIZE_SMALL + throwforce = 0 + throw_speed = 3 + throw_range = 3 + matter = list(DEFAULT_WALL_MATERIAL = 25, "glass" = 25) + +/obj/item/device/price_scanner/afterattack(atom/movable/target, mob/user as mob, proximity) + if(!proximity) + return + + var/value = get_value(target) + user.visible_message("\The [user] scans \the [target] with \the [src]") + user.show_message("Price estimation of \the [target]: [value ? value : "N/A"] credits") + +/obj/item/device/slime_scanner + name = "xenolife scanner" + desc = "Multipurpose organic life scanner. With spectral breath analyzer you can find out what snacks Ian had! Or what gasses alien life breathes." + icon_state = "xenobio" + item_state = "analyzer" + slot_flags = SLOT_BELT + w_class = ITEM_SIZE_SMALL + origin_tech = list(TECH_MAGNET = 1, TECH_BIO = 1) + obj_flags = OBJ_FLAG_CONDUCTIBLE + matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 20) + +/obj/item/device/slime_scanner/proc/list_gases(var/gases) + . = list() + for(var/g in gases) + . += "[gas_data.name[g]] ([gases[g]]%)" + return english_list(.) + +/obj/item/device/slime_scanner/afterattack(mob/target, mob/user, proximity) + if(!proximity) + return + + if(!istype(target)) + return + + user.visible_message("\The [user] scans \the [target] with \the [src]") + if(istype(target, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = target + user.show_message("Data for [H]:") + user.show_message("Species:\t[H.species]") + user.show_message("Breathes:\t[gas_data.name[H.species.breath_type]]") + user.show_message("Exhales:\t[gas_data.name[H.species.exhale_type]]") + user.show_message("Known toxins:\t[gas_data.name[H.species.poison_type]]") + user.show_message("Temperature comfort zone:\t[H.species.cold_discomfort_level] K to [H.species.heat_discomfort_level] K") + user.show_message("Pressure comfort zone:\t[H.species.warning_low_pressure] kPa to [H.species.warning_high_pressure] kPa") + else if(istype(target, /mob/living/simple_animal)) + var/mob/living/simple_animal/A = target + user.show_message("Data for [A]:") + user.show_message("Species:\t[initial(A.name)]") + user.show_message("Breathes:\t[list_gases(A.min_gas)]") + user.show_message("Known toxins:\t[list_gases(A.max_gas)]") + user.show_message("Temperature comfort zone:\t[A.minbodytemp] K to [A.maxbodytemp] K") + else if(istype(target, /mob/living/carbon/slime/)) + var/mob/living/carbon/slime/T = target + user.show_message("Slime scan result for \the [T]:") + user.show_message("[T.colour] [T.is_adult ? "adult" : "baby"] slime") + user.show_message("Nutrition:\t[T.nutrition]/[T.get_max_nutrition()]") + if(T.nutrition < T.get_starve_nutrition()) + user.show_message("Warning:\tthe slime is starving!") + else if (T.nutrition < T.get_hunger_nutrition()) + user.show_message("Warning:\tthe slime is hungry.") + user.show_message("Electric charge strength:\t[T.powerlevel]") + user.show_message("Health:\t[round(T.health / T.maxHealth)]%") + + var/list/mutations = T.GetMutations() + + if(!mutations.len) + user.show_message("This slime will never mutate.") + else + var/list/mutationChances = list() + for(var/i in mutations) + if(i == T.colour) + continue + if(mutationChances[i]) + mutationChances[i] += T.mutation_chance / mutations.len + else + mutationChances[i] = T.mutation_chance / mutations.len + + var/list/mutationTexts = list("[T.colour] ([100 - T.mutation_chance]%)") + for(var/i in mutationChances) + mutationTexts += "[i] ([mutationChances[i]]%)" + + user.show_message("Possible colours on splitting:\t[english_list(mutationTexts)]") + + if (T.cores > 1) + user.show_message("Anomalous slime core amount detected.") + user.show_message("Growth progress:\t[T.amount_grown]/10.") + else + user.show_message("Incompatible life form, analysis failed.") diff --git a/code/game/objects/items/devices/spy_bug.dm b/code/game/objects/items/devices/spy_bug.dm new file mode 100644 index 00000000..5af9745e --- /dev/null +++ b/code/game/objects/items/devices/spy_bug.dm @@ -0,0 +1,168 @@ +/obj/item/device/spy_bug + name = "bug" + desc = "" // Nothing to see here + icon = 'icons/obj/weapons.dmi' + icon_state = "eshield0" + item_state = "nothing" + plane = OBJ_PLANE + layer = BELOW_TABLE_LAYER + + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 5.0 + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + throwforce = 5.0 + throw_range = 15 + throw_speed = 3 + + origin_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1, TECH_ILLEGAL = 3) + + var/obj/item/device/radio/spy/radio + var/obj/machinery/camera/spy/camera + +/obj/item/device/spy_bug/New() + ..() + radio = new(src) + camera = new(src) + GLOB.listening_objects += src + +/obj/item/device/spy_bug/Destroy() + QDEL_NULL(radio) + QDEL_NULL(camera) + GLOB.listening_objects -= src + return ..() + +/obj/item/device/spy_bug/examine(mob/user) + . = ..(user, 0) + if(.) + to_chat(user, "It's a tiny camera, microphone, and transmission device in a happy union.") + to_chat(user, "Needs to be both configured and brought in contact with monitor device to be fully functional.") + +/obj/item/device/spy_bug/attack_self(mob/user) + radio.attack_self(user) + +/obj/item/device/spy_bug/attackby(obj/W as obj, mob/living/user as mob) + if(istype(W, /obj/item/device/spy_monitor)) + var/obj/item/device/spy_monitor/SM = W + SM.pair(src, user) + else + ..() + +/obj/item/device/spy_bug/hear_talk(mob/M, var/msg, verb, datum/language/speaking) + radio.hear_talk(M, msg, speaking) + + +/obj/item/device/spy_monitor + name = "\improper PDA" + desc = "A portable microcomputer by Thinktronic Systems, LTD. Functionality determined by a preprogrammed ROM cartridge." + icon = 'icons/obj/pda.dmi' + icon_state = "pda" + item_state = "electronic" + + w_class = ITEM_SIZE_SMALL + + origin_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1, TECH_ILLEGAL = 3) + + var/operating = 0 + var/obj/item/device/radio/spy/radio + var/obj/machinery/camera/spy/selected_camera + var/list/obj/machinery/camera/spy/cameras = new() + +/obj/item/device/spy_monitor/New() + ..() + radio = new(src) + GLOB.listening_objects += src + +/obj/item/device/spy_monitor/Destroy() + GLOB.listening_objects -= src + return ..() + +/obj/item/device/spy_monitor/examine(mob/user) + . = ..(user, 1) + if(.) + to_chat(user, "The time '12:00' is blinking in the corner of the screen and \the [src] looks very cheaply made.") + +/obj/item/device/spy_monitor/attack_self(mob/user) + if(operating) + return + + radio.attack_self(user) + view_cameras(user) + +/obj/item/device/spy_monitor/attackby(obj/W as obj, mob/living/user as mob) + if(istype(W, /obj/item/device/spy_bug)) + pair(W, user) + else + return ..() + +/obj/item/device/spy_monitor/proc/pair(var/obj/item/device/spy_bug/SB, var/mob/living/user) + if(SB.camera in cameras) + to_chat(user, "\The [SB] has been unpaired from \the [src].") + cameras -= SB.camera + else + to_chat(user, "\The [SB] has been paired with \the [src].") + cameras += SB.camera + +/obj/item/device/spy_monitor/proc/view_cameras(mob/user) + if(!can_use_cam(user)) + return + + selected_camera = cameras[1] + view_camera(user) + + operating = 1 + while(selected_camera && Adjacent(user)) + selected_camera = input("Select camera bug to view.") as null|anything in cameras + selected_camera = null + operating = 0 + +/obj/item/device/spy_monitor/proc/view_camera(mob/user) + spawn(0) + while(selected_camera && Adjacent(user)) + var/turf/T = get_turf(selected_camera) + if(!T || !is_on_same_plane_or_station(T.z, user.z) || !selected_camera.can_use()) + user.unset_machine() + user.reset_view(null) + to_chat(user, "[selected_camera] unavailable.") + sleep(90) + else + user.set_machine(selected_camera) + user.reset_view(selected_camera) + sleep(10) + user.unset_machine() + user.reset_view(null) + +/obj/item/device/spy_monitor/proc/can_use_cam(mob/user) + if(operating) + return + + if(!cameras.len) + to_chat(user, "No paired cameras detected!") + to_chat(user, "Bring a bug in contact with this device to pair the camera.") + return + + return 1 + +/obj/item/device/spy_monitor/hear_talk(mob/M, var/msg, verb, datum/language/speaking) + return radio.hear_talk(M, msg, speaking) + + +/obj/machinery/camera/spy + // These cheap toys are accessible from the mercenary camera console as well + network = list(NETWORK_MERCENARY) + +/obj/machinery/camera/spy/New() + ..() + name = "DV-136ZB #[random_id(/obj/machinery/camera/spy, 1000,9999)]" + c_tag = name + +/obj/machinery/camera/spy/check_eye(var/mob/user as mob) + return 0 + +/obj/item/device/radio/spy + listening = 0 + frequency = 1473 + broadcasting = 0 + canhear_range = 1 + name = "spy device" + icon_state = "syn_cypherkey" diff --git a/code/game/objects/items/devices/suit_cooling.dm b/code/game/objects/items/devices/suit_cooling.dm new file mode 100644 index 00000000..84de1961 --- /dev/null +++ b/code/game/objects/items/devices/suit_cooling.dm @@ -0,0 +1,184 @@ +/obj/item/device/suit_cooling_unit + name = "portable cooling unit" + desc = "A large portable heat sink with liquid cooled radiator packaged into a modified backpack." + description_info = "You may wear this instead of your packpack to cool yourself down. It is commonly used by IPCs, \ + as it allows them to go into low pressure environments for more than few seconds without overheating. It runs off energy provided by an internal power cell. \ + Remember to turn it on by clicking it when it's your in your hand before you put it on." + description_fluff = "Before the advent of ultra-heat-resistant fibers and flexible alloyed shielding, portable coolers were most commonly used to keep technicians from roasting alive in their suits. Nowadays they have been repurposed to keep IPCs from overheating in vacuum environments." + + w_class = ITEM_SIZE_LARGE + icon = 'icons/obj/suitcooler.dmi' + icon_state = "suitcooler0" + item_state = "coolingpack" // beautiful codersprites until someone makes a prettier one. + slot_flags = SLOT_BACK + + //copied from tank.dm + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 5.0 + throwforce = 10.0 + throw_speed = 1 + throw_range = 4 + action_button_name = "Toggle Heatsink" + + matter = list("steel" = 15000, "glass" = 3500) + origin_tech = list(TECH_MAGNET = 2, TECH_MATERIAL = 2) + + var/on = 0 //is it turned on? + var/cover_open = 0 //is the cover open? + var/obj/item/weapon/cell/cell + var/max_cooling = 12 // in degrees per second - probably don't need to mess with heat capacity here + var/charge_consumption = 2 KILOWATTS // energy usage at full power + var/thermostat = T20C + +/obj/item/device/suit_cooling_unit/ui_action_click() + toggle(usr) + +/obj/item/device/suit_cooling_unit/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + cell = new/obj/item/weapon/cell/high() // 10K rated cell. + cell.forceMove(src) + +/obj/item/device/suit_cooling_unit/Destroy() + . = ..() + STOP_PROCESSING(SSobj, src) + +/obj/item/device/suit_cooling_unit/Process() + if (!on || !cell) + return + + if (!is_in_slot()) + return + + var/mob/living/carbon/human/H = loc + + var/temp_adj = min(H.bodytemperature - thermostat, max_cooling) + + if (temp_adj < 0.5) //only cools, doesn't heat, also we don't need extreme precision + return + + var/charge_usage = (temp_adj/max_cooling)*charge_consumption + + H.bodytemperature -= temp_adj + + cell.use(charge_usage * CELLRATE) + update_icon() + + if(cell.charge <= 0) + turn_off(1) + +// Checks whether the cooling unit is being worn on the back/suit slot. +// That way you can't carry it in your hands while it's running to cool yourself down. +/obj/item/device/suit_cooling_unit/proc/is_in_slot() + var/mob/living/carbon/human/H = loc + if(!istype(H)) + return 0 + + return (H.back == src) || (H.s_store == src) + +/obj/item/device/suit_cooling_unit/proc/turn_on() + if(!cell) + return + if(cell.charge <= 0) + return + + on = 1 + update_icon() + +/obj/item/device/suit_cooling_unit/proc/turn_off(var/failed) + if(failed) visible_message("\The [src] clicks and whines as it powers down.") + on = 0 + update_icon() + +/obj/item/device/suit_cooling_unit/attack_self(var/mob/user) + if(cover_open && cell) + if(ishuman(user)) + user.put_in_hands(cell) + else + cell.forceMove(get_turf(src)) + + cell.add_fingerprint(user) + cell.update_icon() + + to_chat(user, "You remove \the [src.cell].") + src.cell = null + update_icon() + return + + toggle(user) + +/obj/item/device/suit_cooling_unit/proc/toggle(var/mob/user) + if(on) + turn_off() + else + turn_on() + to_chat(user, "You switch \the [src] [on ? "on" : "off"].") + +/obj/item/device/suit_cooling_unit/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isScrewdriver(W)) + if(cover_open) + cover_open = 0 + to_chat(user, "You screw the panel into place.") + else + cover_open = 1 + to_chat(user, "You unscrew the panel.") + update_icon() + return + + if (istype(W, /obj/item/weapon/cell)) + if(cover_open) + if(cell) + to_chat(user, "There is a [cell] already installed here.") + else + user.drop_item() + W.forceMove(src) + cell = W + to_chat(user, "You insert the [cell].") + update_icon() + return + + return ..() + +/obj/item/device/suit_cooling_unit/update_icon() + overlays.Cut() + if (cover_open) + if (cell) + icon_state = "suitcooler1" + else + icon_state = "suitcooler2" + return + + icon_state = "suitcooler0" + + if(!cell || !on) + return + + switch(round(cell.percent())) + if(86 to INFINITY) + overlays.Add("battery-0") + if(69 to 85) + overlays.Add("battery-1") + if(52 to 68) + overlays.Add("battery-2") + if(35 to 51) + overlays.Add("battery-3") + if(18 to 34) + overlays.Add("battery-4") + if(-INFINITY to 17) + overlays.Add("battery-5") + + +/obj/item/device/suit_cooling_unit/examine(mob/user) + if(!..(user, 1)) + return + + if (on) + to_chat(user, "It's switched on and running.") + else + to_chat(user, "It is switched off.") + + if (cover_open) + to_chat(user, "The panel is open.") + + if (cell) + to_chat(user, "The charge meter reads [round(cell.percent())]%.") diff --git a/code/game/objects/items/devices/suit_sensor_jammer.dm b/code/game/objects/items/devices/suit_sensor_jammer.dm new file mode 100644 index 00000000..dca97903 --- /dev/null +++ b/code/game/objects/items/devices/suit_sensor_jammer.dm @@ -0,0 +1,213 @@ +#define JAMMER_MAX_RANGE world.view*2 +#define JAMMER_POWER_CONSUMPTION(tick_delay) ((max(0.75, range)**2 * jammer_method.energy_cost * tick_delay) / 20) + +/obj/item/device/suit_sensor_jammer + name = "small device" + desc = "This object menaces with tiny, dull spikes of plastic." + icon_state = "jammer" + w_class = ITEM_SIZE_SMALL + var/active = FALSE + var/range = 2 // This is a radius, thus a range of 7 covers the entire visible screen + var/obj/item/weapon/cell/bcell = /obj/item/weapon/cell/high + var/suit_sensor_jammer_method/jammer_method + var/list/suit_sensor_jammer_methods_by_type + var/list/suit_sensor_jammer_methods + +/obj/item/device/suit_sensor_jammer/New() + ..() + if(ispath(bcell)) + bcell = new bcell(src) + suit_sensor_jammer_methods = list() + suit_sensor_jammer_methods_by_type = list() + for(var/jammer_method_type in subtypesof(/suit_sensor_jammer_method)) + var/new_method = new jammer_method_type(src, /obj/item/device/suit_sensor_jammer/proc/may_process_crew_data) + dd_insertObjectList(suit_sensor_jammer_methods, new_method) + suit_sensor_jammer_methods_by_type[jammer_method_type] = new_method + jammer_method = suit_sensor_jammer_methods[1] + update_icon() + +/obj/item/device/suit_sensor_jammer/Destroy() + . = ..() + qdel(bcell) + bcell = null + jammer_method = null + for(var/method in suit_sensor_jammer_methods) + qdel(method) + suit_sensor_jammer_methods = null + suit_sensor_jammer_methods_by_type = null + disable() + +/obj/item/device/suit_sensor_jammer/attack_self(var/mob/user) + tg_ui_interact(user) + +/obj/item/device/suit_sensor_jammer/attackby(obj/item/I as obj, mob/user as mob) + if(isCrowbar(I)) + if(bcell) + to_chat(user, "You remove \the [bcell].") + disable() + bcell.dropInto(loc) + bcell = null + else + to_chat(user, "There is no cell to remove.") + else if(istype(I, /obj/item/weapon/cell)) + if(bcell) + to_chat(user, "There's already a cell in \the [src].") + else if(user.unEquip(I)) + I.forceMove(src) + bcell = I + to_chat(user, "You insert \the [bcell] into \the [src]..") + else + to_chat(user, "You're unable to insert the battery.") + +/obj/item/device/suit_sensor_jammer/update_icon() + overlays.Cut() + if(bcell) + var/percent = bcell.percent() + switch(percent) + if(0 to 25) + overlays += "forth_quarter" + if(25 to 50) + overlays += "one_quarter" + overlays += "third_quarter" + if(50 to 75) + overlays += "two_quarters" + overlays += "second_quarter" + if(75 to 99) + overlays += "three_quarters" + overlays += "first_quarter" + else + overlays += "four_quarters" + + if(active) + overlays += "active" + +/obj/item/device/suit_sensor_jammer/emp_act(var/severity) + ..() + if(bcell) + bcell.emp_act(severity) + + if(prob(70/severity)) + enable() + else + disable() + + if(prob(90/severity)) + set_method(suit_sensor_jammer_methods_by_type[/suit_sensor_jammer_method/random]) + else + set_method(pick(suit_sensor_jammer_methods)) + + var/new_range = range + (rand(0,6) / severity) - (rand(0,3) / severity) + set_range(new_range) + +obj/item/device/suit_sensor_jammer/examine(var/user) + . = ..(user, 3) + if(.) + var/list/message = list() + message += "This device appears to be [active ? "" : "in"]active and " + if(bcell) + message += "displays a charge level of [bcell.percent()]%." + else + message += "is lacking a cell." + to_chat(user, jointext(message,.)) + +obj/item/device/suit_sensor_jammer/ui_status(mob/user, datum/ui_state/state) + if(!bcell || bcell.charge <= 0) + return UI_CLOSE + return ..() + +obj/item/device/suit_sensor_jammer/tg_ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = tg_default_state) + ui = tgui_process.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "suit_sensor_jammer", "Sensor Jammer", 350, 610, master_ui, state) + ui.open() + +obj/item/device/suit_sensor_jammer/ui_data() + var/list/methods = new + for(var/suit_sensor_jammer_method/ssjm in suit_sensor_jammer_methods) + methods[++methods.len] = list("name" = ssjm.name, "cost" = ssjm.energy_cost, "ref" = "\ref[ssjm]") + + var/list/data = list( + "active" = active, + "current_charge" = bcell ? round(bcell.charge, 1) : 0, + "max_charge" = bcell ? bcell.maxcharge : 0, + "range" = range, + "max_range" = JAMMER_MAX_RANGE, + "methods" = methods, + "current_method" = "\ref[jammer_method]", + "current_cost" = jammer_method.energy_cost, + "total_cost" = "[ceil(JAMMER_POWER_CONSUMPTION(10))]" + ) + + return data + +obj/item/device/suit_sensor_jammer/ui_act(action, params) + if(..()) + return TRUE + switch(action) + if("enable_jammer") + enable() + . TRUE + if("disable_jammer") + disable() + . FALSE + if("increase_range") + set_range(range + 1) + . = 1 + if("decrease_range") + set_range(range - 1) + . = 1 + if("select_method") + var/method = locate(params["method"]) in suit_sensor_jammer_methods + if(method) + set_method(method) + . = TRUE + +/obj/item/device/suit_sensor_jammer/Process(var/wait) + if(bcell) + // With a range of 2 and jammer cost of 3 the default (high capacity) cell will last for almost 14 minutes, give or take + // 10000 / (2^2 * 3 / 10) ~= 8333 ticks ~= 13.8 minutes + var/deduction = JAMMER_POWER_CONSUMPTION(wait) + if(!bcell.use(deduction)) + disable() + else + disable() + update_icon() + +/obj/item/device/suit_sensor_jammer/proc/enable() + if(active) + return FALSE + active = TRUE + START_PROCESSING(SSobj, src) + jammer_method.enable() + update_icon() + return TRUE + +/obj/item/device/suit_sensor_jammer/proc/disable() + if(!active) + return FALSE + active = FALSE + jammer_method.disable() + STOP_PROCESSING(SSobj, src) + update_icon() + return TRUE + +/obj/item/device/suit_sensor_jammer/proc/set_range(var/new_range) + range = Clamp(new_range, 0, JAMMER_MAX_RANGE) // 0 range still covers the current turf + return range != new_range + +/obj/item/device/suit_sensor_jammer/proc/set_method(var/suit_sensor_jammer_method/sjm) + if(sjm == jammer_method) + return + if(active) + jammer_method.disable() + sjm.enable() + jammer_method = sjm + +/obj/item/device/suit_sensor_jammer/proc/may_process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos) + if(!pos) + return FALSE + var/turf/T = get_turf(src) + return T && T.z == pos.z && get_dist(T, pos) <= range + +#undef JAMMER_MAX_RANGE +#undef JAMMER_POWER_CONSUMPTION diff --git a/code/game/objects/items/devices/t_scanner.dm b/code/game/objects/items/devices/t_scanner.dm new file mode 100644 index 00000000..8b79f185 --- /dev/null +++ b/code/game/objects/items/devices/t_scanner.dm @@ -0,0 +1,174 @@ +#define OVERLAY_CACHE_LEN 50 + +/obj/item/device/t_scanner + name = "\improper T-ray scanner" + desc = "A terahertz-ray emitter and scanner, capable of penetrating conventional hull materials." + description_info = "Use this to toggle its scanning capabilities on and off. While on, it will expose the layout of cabling and pipework in a 3x3 area around you." + description_fluff = "The T-ray scanner is a modern spectroscopy solution and labor-saving device. Why work yourself to the bone removing floor panels when you can simply look through them with submillimeter radiation?" + icon_state = "t-ray0" + slot_flags = SLOT_BELT + w_class = ITEM_SIZE_SMALL + item_state = "electronic" + matter = list(DEFAULT_WALL_MATERIAL = 150) + origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1) + action_button_name = "Toggle T-Ray scanner" + + var/scan_range = 1 + + var/on = 0 + var/list/active_scanned = list() //assoc list of objects being scanned, mapped to their overlay + var/client/user_client //since making sure overlays are properly added and removed is pretty important, so we track the current user explicitly + var/flicker = 0 + + var/global/list/overlay_cache = list() //cache recent overlays + +/obj/item/device/t_scanner/Destroy() + . = ..() + if(on) + set_active(FALSE) + +/obj/item/device/t_scanner/update_icon() + icon_state = "t-ray[on]" + +/obj/item/device/t_scanner/emp_act() + audible_message(src, " \The [src] buzzes oddly.") + set_active(FALSE) + +/obj/item/device/t_scanner/attack_self(mob/user) + set_active(!on) + user.update_action_buttons() + +/obj/item/device/t_scanner/proc/set_active(var/active) + on = active + if(on) + START_PROCESSING(SSobj, src) + flicker = 0 + else + STOP_PROCESSING(SSobj, src) + set_user_client(null) + update_icon() + +//If reset is set, then assume the client has none of our overlays, otherwise we only send new overlays. +/obj/item/device/t_scanner/Process() + if(!on) return + + //handle clients changing + var/client/loc_client = null + if(ismob(src.loc)) + var/mob/M = src.loc + loc_client = M.client + set_user_client(loc_client) + + //no sense processing if no-one is going to see it. + if(!user_client) return + + //get all objects in scan range + var/list/scanned = get_scanned_objects(scan_range) + var/list/update_add = scanned - active_scanned + var/list/update_remove = active_scanned - scanned + + //Add new overlays + for(var/obj/O in update_add) + var/image/overlay = get_overlay(O) + active_scanned[O] = overlay + user_client.images += overlay + + //Remove stale overlays + for(var/obj/O in update_remove) + user_client.images -= active_scanned[O] + active_scanned -= O + + //Flicker effect + for(var/obj/O in active_scanned) + var/image/overlay = active_scanned[O] + if(flicker) + overlay.alpha = 0 + else + overlay.alpha = 128 + flicker = !flicker + +//creates a new overlay for a scanned object +/obj/item/device/t_scanner/proc/get_overlay(var/atom/movable/scanned) + //Use a cache so we don't create a whole bunch of new images just because someone's walking back and forth in a room. + //Also means that images are reused if multiple people are using t-rays to look at the same objects. + if(scanned in overlay_cache) + . = overlay_cache[scanned] + else + var/image/I = image(loc = scanned, icon = scanned.icon, icon_state = scanned.icon_state) + I.plane = HUD_PLANE + I.layer = UNDER_HUD_LAYER + + //Pipes are special + if(istype(scanned, /obj/machinery/atmospherics/pipe)) + var/obj/machinery/atmospherics/pipe/P = scanned + I.color = P.pipe_color + I.overlays += P.overlays + I.underlays += P.underlays + + if(ismob(scanned)) + if(ishuman(scanned)) + var/mob/living/carbon/human/H = scanned + if(H.species.appearance_flags & HAS_SKIN_COLOR) + I.color = rgb(H.r_skin, H.g_skin, H.b_skin) + var/mob/M = scanned + I.color = M.color + I.overlays += M.overlays + I.underlays += M.underlays + + I.alpha = 128 + I.mouse_opacity = 0 + . = I + + // Add it to cache, cutting old entries if the list is too long + overlay_cache[scanned] = . + if(overlay_cache.len > OVERLAY_CACHE_LEN) + overlay_cache.Cut(1, overlay_cache.len-OVERLAY_CACHE_LEN-1) + +/obj/item/device/t_scanner/proc/get_scanned_objects(var/scan_dist) + . = list() + + var/turf/center = get_turf(src.loc) + if(!center) return + + for(var/turf/T in range(scan_range, center)) + for(var/mob/M in T.contents) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.is_cloaked()) + . += M + else if(M.alpha < 255) + . += M + else if(round_is_spooky() && isobserver(M)) + . += M + + if(!!T.is_plating()) + continue + + for(var/obj/O in T.contents) + if(O.level != 1) + continue + if(!O.invisibility) + continue //if it's already visible don't need an overlay for it + . += O + + + +/obj/item/device/t_scanner/proc/set_user_client(var/client/new_client) + if(new_client == user_client) + return + if(user_client) + for(var/scanned in active_scanned) + user_client.images -= active_scanned[scanned] + if(new_client) + for(var/scanned in active_scanned) + new_client.images += active_scanned[scanned] + else + active_scanned.Cut() + + user_client = new_client + +/obj/item/device/t_scanner/dropped(mob/user) + set_user_client(null) + ..() + +#undef OVERLAY_CACHE_LEN diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm new file mode 100644 index 00000000..47a9f8e5 --- /dev/null +++ b/code/game/objects/items/devices/taperecorder.dm @@ -0,0 +1,432 @@ +/obj/item/device/taperecorder + name = "universal recorder" + desc = "A device that can record to cassette tapes, and play them. It automatically translates the content in playback." + icon_state = "taperecorder" + item_state = "analyzer" + w_class = ITEM_SIZE_SMALL + + matter = list(DEFAULT_WALL_MATERIAL = 60,"glass" = 30) + + var/emagged = 0.0 + var/recording = 0.0 + var/playing = 0.0 + var/playsleepseconds = 0.0 + var/obj/item/device/tape/mytape = /obj/item/device/tape/random + var/canprint = 1 + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + throwforce = 2 + throw_speed = 4 + throw_range = 20 + +/obj/item/device/taperecorder/New() + ..() + set_extension(src, /datum/extension/base_icon_state, /datum/extension/base_icon_state, icon_state) + if(ispath(mytape)) + mytape = new mytape(src) + GLOB.listening_objects += src + update_icon() + +/obj/item/device/taperecorder/empty + mytape = null + +/obj/item/device/taperecorder/Destroy() + GLOB.listening_objects -= src + if(mytape) + qdel(mytape) + mytape = null + return ..() + + +/obj/item/device/taperecorder/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/device/tape)) + if(mytape) + to_chat(user, "There's already a tape inside.") + return + if(!user.unEquip(I)) + return + I.forceMove(src) + mytape = I + to_chat(user, "You insert [I] into [src].") + update_icon() + return + ..() + + +/obj/item/device/taperecorder/fire_act() + if(mytape) + mytape.ruin() //Fires destroy the tape + return ..() + + +/obj/item/device/taperecorder/attack_hand(mob/user) + if(user.get_inactive_hand() == src) + if(mytape) + eject() + return + ..() + + +/obj/item/device/taperecorder/verb/eject() + set name = "Eject Tape" + set category = "Object" + + if(usr.incapacitated()) + return + if(!mytape) + to_chat(usr, "There's no tape in \the [src].") + return + if(emagged) + to_chat(usr, "The tape seems to be stuck inside.") + return + + if(playing || recording) + stop() + to_chat(usr, "You remove [mytape] from [src].") + usr.put_in_hands(mytape) + mytape = null + update_icon() + + +/obj/item/device/taperecorder/hear_talk(mob/living/M as mob, msg, var/verb="says", datum/language/speaking=null) + if(mytape && recording) + + if(speaking) + if(!speaking.machine_understands) + msg = speaking.scramble(msg) + mytape.record_speech("[M.name] [speaking.format_message_plain(msg, verb)]") + else + mytape.record_speech("[M.name] [verb], \"[msg]\"") + + +/obj/item/device/taperecorder/see_emote(mob/M as mob, text, var/emote_type) + if(emote_type != AUDIBLE_MESSAGE) //only hearable emotes + return + if(mytape && recording) + mytape.record_speech("[strip_html_properly(text)]") + + +/obj/item/device/taperecorder/show_message(msg, type, alt, alt_type) + var/recordedtext + if (msg && type == AUDIBLE_MESSAGE) //must be hearable + recordedtext = msg + else if (alt && alt_type == AUDIBLE_MESSAGE) + recordedtext = alt + else + return + if(mytape && recording) + mytape.record_noise("[strip_html_properly(recordedtext)]") + +/obj/item/device/taperecorder/emag_act(var/remaining_charges, var/mob/user) + if(emagged == 0) + emagged = 1 + recording = 0 + to_chat(user, "PZZTTPFFFT") + update_icon() + return 1 + else + to_chat(user, "It is already emagged!") + +/obj/item/device/taperecorder/proc/explode() + var/turf/T = get_turf(loc) + if(ismob(loc)) + var/mob/M = loc + to_chat(M, "\The [src] explodes!") + if(T) + T.hotspot_expose(700,125) + explosion(T, -1, -1, 0, 4) + qdel(src) + return + +/obj/item/device/taperecorder/verb/record() + set name = "Start Recording" + set category = "Object" + + if(usr.incapacitated()) + return + if(!mytape) + to_chat(usr, "There's no tape!") + return + if(mytape.ruined || emagged) + audible_message("The tape recorder makes a scratchy noise.") + return + if(recording) + to_chat(usr, "You're already recording!") + return + if(playing) + to_chat(usr, "You can't record when playing!") + return + if(mytape.used_capacity < mytape.max_capacity) + to_chat(usr, "Recording started.") + recording = 1 + update_icon() + + mytape.record_speech("Recording started.") + + //count seconds until full, or recording is stopped + while(mytape && recording && mytape.used_capacity < mytape.max_capacity) + sleep(10) + mytape.used_capacity++ + if(mytape.used_capacity >= mytape.max_capacity) + if(ismob(loc)) + var/mob/M = loc + to_chat(M, "The tape is full.") + stop_recording() + + + update_icon() + return + else + to_chat(usr, "The tape is full.") + + +/obj/item/device/taperecorder/proc/stop_recording() + //Sanity checks skipped, should not be called unless actually recording + recording = 0 + update_icon() + mytape.record_speech("Recording stopped.") + if(ismob(loc)) + var/mob/M = loc + to_chat(M, "Recording stopped.") + + +/obj/item/device/taperecorder/verb/stop() + set name = "Stop" + set category = "Object" + + if(usr.incapacitated()) + return + if(recording) + stop_recording() + return + else if(playing) + playing = 0 + update_icon() + to_chat(usr, "Playback stopped.") + return + else + to_chat(usr, "Stop what?") + + +/obj/item/device/taperecorder/verb/wipe_tape() + set name = "Wipe Tape" + set category = "Object" + + if(usr.incapacitated()) + return + if(emagged || mytape.ruined) + audible_message("The tape recorder makes a scratchy noise.") + return + if(recording || playing) + to_chat(usr, "You can't wipe the tape while playing or recording!") + return + else + if(mytape.storedinfo) mytape.storedinfo.Cut() + if(mytape.timestamp) mytape.timestamp.Cut() + mytape.used_capacity = 0 + to_chat(usr, "You wipe the tape.") + return + + +/obj/item/device/taperecorder/verb/playback_memory() + set name = "Playback Tape" + set category = "Object" + + if(usr.incapacitated()) + return + if(!mytape) + to_chat(usr, "There's no tape!") + return + if(mytape.ruined) + audible_message("The tape recorder makes a scratchy noise.") + return + if(recording) + to_chat(usr, "You can't playback when recording!") + return + if(playing) + to_chat(usr, "You're already playing!") + return + playing = 1 + update_icon() + to_chat(usr, "Audio playback started.") + for(var/i=1 , i < mytape.max_capacity , i++) + if(!mytape || !playing) + break + if(mytape.storedinfo.len < i) + break + + var/turf/T = get_turf(src) + var/playedmessage = mytape.storedinfo[i] + if (findtextEx(playedmessage,"*",1,2)) //remove marker for action sounds + playedmessage = copytext(playedmessage,2) + T.audible_message("Tape Recorder: [playedmessage]") + + if(mytape.storedinfo.len < i+1) + playsleepseconds = 1 + sleep(10) + T = get_turf(src) + T.audible_message("Tape Recorder: End of recording.") + break + else + playsleepseconds = mytape.timestamp[i+1] - mytape.timestamp[i] + + if(playsleepseconds > 14) + sleep(10) + T = get_turf(src) + T.audible_message("Tape Recorder: Skipping [playsleepseconds] seconds of silence") + playsleepseconds = 1 + sleep(10 * playsleepseconds) + + + playing = 0 + update_icon() + + if(emagged) + var/turf/T = get_turf(src) + T.audible_message("Tape Recorder: This tape recorder will self-destruct in... Five.") + sleep(10) + T = get_turf(src) + T.audible_message("Tape Recorder: Four.") + sleep(10) + T = get_turf(src) + T.audible_message("Tape Recorder: Three.") + sleep(10) + T = get_turf(src) + T.audible_message("Tape Recorder: Two.") + sleep(10) + T = get_turf(src) + T.audible_message("Tape Recorder: One.") + sleep(10) + explode() + + +/obj/item/device/taperecorder/verb/print_transcript() + set name = "Print Transcript" + set category = "Object" + + if(usr.incapacitated()) + return + if(!mytape) + to_chat(usr, "There's no tape!") + return + if(mytape.ruined || emagged) + audible_message("The tape recorder makes a scratchy noise.") + return + if(!canprint) + to_chat(usr, "The recorder can't print that fast!") + return + if(recording || playing) + to_chat(usr, "You can't print the transcript while playing or recording!") + return + + to_chat(usr, "Transcript printed.") + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(get_turf(src)) + var/t1 = "Transcript:

            " + for(var/i=1,mytape.storedinfo.len >= i,i++) + var/printedmessage = mytape.storedinfo[i] + if (findtextEx(printedmessage,"*",1,2)) //replace action sounds + printedmessage = "\[[time2text(mytape.timestamp[i]*10,"mm:ss")]\] (Unrecognized sound)" + t1 += "[printedmessage]
            " + P.info = t1 + P.SetName("Transcript") + canprint = 0 + sleep(300) + canprint = 1 + + +/obj/item/device/taperecorder/attack_self(mob/user) + if(recording || playing) + stop() + else + record() + + +/obj/item/device/taperecorder/update_icon() + var/datum/extension/base_icon_state/bis = get_extension(src, /datum/extension/base_icon_state) + + if(!mytape) + icon_state = "[bis.base_icon_state]_empty" + else if(recording) + icon_state = "[bis.base_icon_state]_recording" + else if(playing) + icon_state = "[bis.base_icon_state]_playing" + else + icon_state = "[bis.base_icon_state]_idle" + +/obj/item/device/tape + name = "tape" + desc = "A magnetic tape that can hold up to ten minutes of content." + icon_state = "tape_white" + item_state = "analyzer" + w_class = ITEM_SIZE_TINY + matter = list(DEFAULT_WALL_MATERIAL=20, "glass"=5) + force = 1 + throwforce = 0 + var/max_capacity = 600 + var/used_capacity = 0 + var/list/storedinfo = new/list() + var/list/timestamp = new/list() + var/ruined = 0 + + +/obj/item/device/tape/update_icon() + overlays.Cut() + if(ruined) + overlays += "ribbonoverlay" + + +/obj/item/device/tape/fire_act() + ruin() + +/obj/item/device/tape/attack_self(mob/user) + if(!ruined) + to_chat(user, "You pull out all the tape!") + ruin() + + +/obj/item/device/tape/proc/ruin() + ruined = 1 + update_icon() + + +/obj/item/device/tape/proc/fix() + ruined = 0 + update_icon() + + +/obj/item/device/tape/proc/record_speech(text) + timestamp += used_capacity + storedinfo += "\[[time2text(used_capacity*10,"mm:ss")]\] [text]" + + +//shows up on the printed transcript as (Unrecognized sound) +/obj/item/device/tape/proc/record_noise(text) + timestamp += used_capacity + storedinfo += "*\[[time2text(used_capacity*10,"mm:ss")]\] [text]" + + +/obj/item/device/tape/attackby(obj/item/I, mob/user, params) + if(ruined && isScrewdriver(I)) + to_chat(user, "You start winding the tape back in...") + if(do_after(user, 120, target = src)) + to_chat(user, "You wound the tape back in.") + fix() + return + else if(istype(I, /obj/item/weapon/pen)) + if(loc == user && !user.incapacitated()) + var/new_name = input(user, "What would you like to label the tape?", "Tape labeling") as null|text + if(isnull(new_name)) return + new_name = sanitizeSafe(new_name) + if(new_name) + SetName("tape - '[new_name]'") + to_chat(user, "You label the tape '[new_name]'.") + else + SetName("tape") + to_chat(user, "You scratch off the label.") + return + ..() + + +//Random colour tapes +/obj/item/device/tape/random/New() + icon_state = "tape_[pick("white", "blue", "red", "yellow", "purple")]" \ No newline at end of file diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm new file mode 100644 index 00000000..a4a900d5 --- /dev/null +++ b/code/game/objects/items/devices/traitordevices.dm @@ -0,0 +1,56 @@ +/* + +Miscellaneous traitor devices + +BATTERER + + +*/ + +/* + +The Batterer, like a flashbang but 50% chance to knock people over. Can be either very +effective or pretty fucking useless. + +*/ + +/obj/item/device/batterer + name = "mind batterer" + desc = "A strange device with twin antennas." + icon_state = "batterer" + throwforce = 5 + w_class = ITEM_SIZE_TINY + throw_speed = 4 + throw_range = 10 + obj_flags = OBJ_FLAG_CONDUCTIBLE + item_state = "electronic" + origin_tech = list(TECH_MAGNET = 3, TECH_COMBAT = 3, TECH_ILLEGAL = 3) + + var/times_used = 0 //Number of times it's been used. + var/max_uses = 2 + +/obj/item/device/batterer/attack_self(mob/living/carbon/user as mob, flag = 0, emp = 0) + if(!user) return + if(times_used >= max_uses) + to_chat(user, "The mind batterer has been burnt out!") + return + + var/list/stun_victims = list() + for(var/mob/living/carbon/human/M in orange(10, user)) + stun_victims += M + spawn() + if(prob(50)) + M.Weaken(rand(10,20)) + if(prob(25)) + M.Stun(rand(5,10)) + to_chat(M, "You feel a tremendous, paralyzing wave flood your mind.") + else + to_chat(M, "You feel a sudden, electric jolt travel through your head.") + + admin_attacker_log_many_victims(user, stun_victims, "Used \a [src] to attempt to knockdown their victim.", "Was subject to a knockdown attempt.", ", using \a [src], attempted to knockdown") + + playsound(src.loc, 'sound/misc/interference.ogg', 50, 1) + to_chat(user, "You trigger [src].") + times_used += 1 + if(times_used >= max_uses) + icon_state = "battererburnt" diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm new file mode 100644 index 00000000..171ebdca --- /dev/null +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -0,0 +1,232 @@ +/obj/item/device/transfer_valve + name = "tank transfer valve" + desc = "A small, versatile valve with dual-headed heat-resistant pipes. This mechanism is the standard size for coupling with portable gas tanks." + description_info = "This machine is used to merge the contents of two different gas tanks. Plug the tanks into the transfer, then open the valve to mix them together. You can also attach various assembly devices to trigger this process." + description_antag = "With a tank of hot phoron and cold oxygen, this benign little atmospheric device becomes an incredibly deadly bomb. You don't want to be anywhere near it when it goes off." + icon = 'icons/obj/assemblies.dmi' + icon_state = "valve_1" + var/obj/item/weapon/tank/tank_one + var/obj/item/weapon/tank/tank_two + var/obj/item/device/attached_device + var/mob/attacher = null + var/valve_open = 0 + var/toggle = 1 + movable_flags = MOVABLE_FLAG_PROXMOVE + +/obj/item/device/transfer_valve/proc/process_activation(var/obj/item/device/D) + +/obj/item/device/transfer_valve/IsAssemblyHolder() + return 1 + +/obj/item/device/transfer_valve/attackby(obj/item/item, mob/user) + var/turf/location = get_turf(src) // For admin logs + if(istype(item, /obj/item/weapon/tank)) + + var/T1_weight = 0 + var/T2_weight = 0 + if(tank_one && tank_two) + to_chat(user, "There are already two tanks attached, remove one first.") + return + + user.drop_item() + item.forceMove(src) + if(!tank_one) + tank_one = item + else + tank_two = item + message_admins("[key_name_admin(user)] attached both tanks to a transfer valve. (JMP)") + log_game("[key_name_admin(user)] attached both tanks to a transfer valve.") + to_chat(user, "You attach the tank to the transfer valve.") + + T1_weight = tank_one.w_class + if(tank_two) + T2_weight = tank_two.w_class + + src.w_class = max(initial(src.w_class),T1_weight,T2_weight) //gets w_class of biggest object, because you shouldn't be able to just shove tanks in and have them be tiny. + + update_icon() + + GLOB.nanomanager.update_uis(src) // update all UIs attached to src +//TODO: Have this take an assemblyholder + else if(isassembly(item)) + var/obj/item/device/assembly/A = item + if(A.secured) + to_chat(user, "The device is secured.") + return + if(attached_device) + to_chat(user, "There is already an device attached to the valve, remove it first.") + return + user.remove_from_mob(item) + attached_device = A + A.forceMove(src) + to_chat(user, "You attach the [item] to the valve controls and secure it.") + A.holder = src + A.toggle_secure() //this calls update_icon(), which calls update_icon() on the holder (i.e. the bomb). + + GLOB.bombers += "[key_name(user)] attached a [item] to a transfer valve." + message_admins("[key_name_admin(user)] attached a [item] to a transfer valve. (JMP)") + log_game("[key_name_admin(user)] attached a [item] to a transfer valve.") + attacher = user + GLOB.nanomanager.update_uis(src) // update all UIs attached to src + return + + +/obj/item/device/transfer_valve/HasProximity(atom/movable/AM as mob|obj) + if(!attached_device) return + attached_device.HasProximity(AM) + return + + +/obj/item/device/transfer_valve/attack_self(mob/user as mob) + ui_interact(user) + +/obj/item/device/transfer_valve/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + + // this is the data which will be sent to the ui + var/data[0] + data["attachmentOne"] = tank_one ? tank_one.name : null + data["attachmentTwo"] = tank_two ? tank_two.name : null + data["valveAttachment"] = attached_device ? attached_device.name : null + data["valveOpen"] = valve_open ? 1 : 0 + + // update the ui if it exists, returns null if no ui is passed/found + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "transfer_valve.tmpl", "Tank Transfer Valve", 460, 280) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + //ui.set_auto_update(1) + +/obj/item/device/transfer_valve/Topic(href, href_list) + ..() + if ( usr.stat || usr.restrained() ) + return 0 + if (src.loc != usr) + return 0 + if(tank_one && href_list["tankone"]) + remove_tank(tank_one) + else if(tank_two && href_list["tanktwo"]) + remove_tank(tank_two) + else if(href_list["open"]) + toggle_valve() + else if(attached_device) + if(href_list["rem_device"]) + attached_device.loc = get_turf(src) + attached_device:holder = null + attached_device = null + update_icon() + if(href_list["device"]) + attached_device.attack_self(usr) + return 1 // Returning 1 sends an update to attached UIs + +/obj/item/device/transfer_valve/process_activation(var/obj/item/device/D) + if(toggle) + toggle = 0 + toggle_valve() + spawn(50) // To stop a signal being spammed from a proxy sensor constantly going off or whatever + toggle = 1 + +/obj/item/device/transfer_valve/update_icon() + overlays.Cut() + underlays = null + + if(!tank_one && !tank_two && !attached_device) + icon_state = "valve_1" + return + icon_state = "valve" + + if(tank_one) + overlays += "[tank_one.icon_state]" + if(tank_two) + var/icon/J = new(icon, icon_state = "[tank_two.icon_state]") + J.Shift(WEST, 13) + underlays += J + 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 + + if(!tank_one && !tank_two) src.w_class = initial(src.w_class) //returns it to just the transfer valve size + T.dropInto(loc) + 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) + return + + valve_open = 0 + + if(QDELETED(tank_one) || QDELETED(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 + it explodes properly when it gets a signal (and it does). + */ + +/obj/item/device/transfer_valve/proc/toggle_valve() + if(!valve_open && (tank_one && tank_two)) + var/turf/bombturf = get_turf(src) + var/area/A = get_area(bombturf) + + var/attacher_name = "" + if(!attacher) + attacher_name = "Unknown" + else + attacher_name = "[attacher.name]([attacher.ckey])" + + var/log_str = "Bomb valve opened in [A.name] " + log_str += "with [attached_device ? attached_device : "no device"] attacher: [attacher_name]" + + if(attacher) + log_str += "(?)" + + var/mob/mob = get_mob_by_key(src.fingerprintslast) + var/last_touch_info = "" + if(mob) + last_touch_info = "(?)" + + log_str += " Last touched by: [src.fingerprintslast][last_touch_info]" + GLOB.bombers += log_str + message_admins(log_str, 0, 1) + log_game(log_str) + merge_gases() + + else if(valve_open==1 && (tank_one && tank_two)) + split_gases() + + 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 +/obj/item/device/transfer_valve/proc/c_state() + return diff --git a/code/game/objects/items/devices/tvcamera.dm b/code/game/objects/items/devices/tvcamera.dm new file mode 100644 index 00000000..f5cb9223 --- /dev/null +++ b/code/game/objects/items/devices/tvcamera.dm @@ -0,0 +1,159 @@ +/obj/item/device/tvcamera + name = "press camera drone" + desc = "A Ward-Takahashi EyeBuddy livestreaming press camera drone. Weapon of choice for war correspondents and reality show cameramen. It does not appear to have any internal memory storage." + icon_state = "camcorder" + item_state = "camcorder" + w_class = ITEM_SIZE_LARGE + slot_flags = SLOT_BELT + var/channel = "General News Feed" + var/obj/machinery/camera/network/thunder/camera + var/obj/item/device/radio/radio + +/obj/item/device/tvcamera/New() + ..() + GLOB.listening_objects += src + +/obj/item/device/tvcamera/Destroy() + GLOB.listening_objects -= src + QDEL_NULL(camera) + QDEL_NULL(radio) + . = ..() + +/obj/item/device/tvcamera/Initialize() + . = ..() + camera = new(src) + camera.c_tag = channel + camera.status = FALSE + radio = new(src) + radio.listening = FALSE + radio.set_frequency(ENT_FREQ) + update_icon() + +/obj/item/device/tvcamera/examine() + . = ..() + to_chat(usr, "Video feed is currently: [camera.status ? "Online" : "Offline"]") + to_chat(usr, "Audio feed is currently: [radio.broadcasting ? "Online" : "Offline"]") + +/obj/item/device/tvcamera/attack_self(mob/user) + add_fingerprint(user) + user.set_machine(src) + var/dat = list() + dat += "Channel name is: [channel ? channel : "unidentified broadcast"]
            " + dat += "Video streaming is: [camera.status ? "Online" : "Offline"]
            " + dat += "Microphone is: [radio.broadcasting ? "Online" : "Offline"]
            " + dat += "Sound is being broadcasted on frequency: [format_frequency(radio.frequency)] ([get_frequency_name(radio.frequency)])
            " + var/datum/browser/popup = new(user, "Press Camera Drone", "EyeBuddy", 300, 390, src) + popup.set_content(jointext(dat,null)) + popup.open() + +/obj/item/device/tvcamera/Topic(bred, href_list, state = GLOB.physical_state) + if(..()) + return 1 + if(href_list["channel"]) + var/nc = input(usr, "Channel name", "Select new channel name", channel) as text|null + if(nc) + channel = nc + camera.c_tag = channel + to_chat(usr, "New channel name: '[channel]' has been set.") + if(href_list["video"]) + camera.set_status(!camera.status) + if(camera.status) + to_chat(usr,"Video streaming: Activated. Broadcasting on channel: '[channel]'") + else + to_chat(usr,"Video streaming: Deactivated.") + update_icon() + if(href_list["sound"]) + radio.ToggleBroadcast() + if(radio.broadcasting) + to_chat(usr,"Audio streaming: Activated. Broadcasting on frequency: [format_frequency(radio.frequency)].") + else + to_chat(usr,"Audio streaming: Deactivated.") + if(!href_list["close"]) + attack_self(usr) + +/obj/item/device/tvcamera/update_icon() + ..() + if(camera.status) + icon_state = "camcorder_on" + item_state = "camcorder_on" + else + icon_state = "camcorder" + item_state = "camcorder" + var/mob/living/carbon/human/H = loc + if(istype(H)) + H.update_inv_r_hand(0) + H.update_inv_l_hand() + +/* Assembly by a roboticist */ +/obj/item/robot_parts/head/attackby(var/obj/item/device/assembly/S, mob/user as mob) + if ((!istype(S, /obj/item/device/assembly/infra))) + ..() + return + var/obj/item/weapon/TVAssembly/A = new(user) + qdel(S) + user.put_in_hands(A) + to_chat(user, "You add the infrared sensor to the robot head.") + user.drop_from_inventory(src) + qdel(src) + +/* Using camcorder icon as I can't sprite. +Using robohead because of restricting to roboticist */ +/obj/item/weapon/TVAssembly + name = "TV Camera assembly" + desc = "A robotic head with an infrared sensor inside" + icon = 'icons/obj/robot_parts.dmi' + icon_state = "head" + item_state = "head" + var/buildstep = 0 + w_class = ITEM_SIZE_LARGE + +/obj/item/weapon/TVAssembly/attackby(W, mob/user) + switch(buildstep) + if(0) + if(istype(W, /obj/item/robot_parts/robot_component/camera)) + var/obj/item/robot_parts/robot_component/camera/CA = W + to_chat(user, "You add the camera module to [src]") + user.drop_item() + qdel(CA) + desc = "This TV camera assembly has a camera module." + buildstep++ + if(1) + if(istype(W, /obj/item/device/taperecorder)) + var/obj/item/device/taperecorder/T = W + user.drop_item() + qdel(T) + buildstep++ + to_chat(user, "You add the tape recorder to [src]") + desc = "This TV camera assembly has a camera and audio module." + return + if(2) + if(isCoil(W)) + var/obj/item/stack/cable_coil/C = W + if(!C.use(3)) + to_chat(user, "You need three cable coils to wire the devices.") + ..() + return + C.use(3) + buildstep++ + to_chat(user, "You wire the assembly") + desc = "This TV camera assembly has wires sticking out" + return + if(3) + if(isWirecutter(W)) + to_chat(user, " You trim the wires.") + buildstep++ + desc = "This TV camera assembly needs casing." + return + if(4) + if(istype(W, /obj/item/stack/material/steel)) + var/obj/item/stack/material/steel/S = W + buildstep++ + S.use(1) + to_chat(user, "You encase the assembly.") + var/turf/T = get_turf(src) + new /obj/item/device/tvcamera(T) + user.drop_from_inventory(src) + qdel(src) + return + + ..() \ No newline at end of file diff --git a/code/game/objects/items/devices/uplink.dm b/code/game/objects/items/devices/uplink.dm new file mode 100644 index 00000000..0a4d8eb8 --- /dev/null +++ b/code/game/objects/items/devices/uplink.dm @@ -0,0 +1,268 @@ +// HIDDEN UPLINK - Can be stored in anything but the host item has to have a trigger for it. +/* How to create an uplink in 3 easy steps! + + 1. All obj/item 's have a hidden_uplink var. By default it's null. Give the item one with "new(src)", it must be in it's contents. Feel free to add "uses". + + 2. Code in the triggers. Use check_trigger for this, I recommend closing the item's menu with "usr << browse(null, "window=windowname") if it returns true. + The var/value is the value that will be compared with the var/target. If they are equal it will activate the menu. + + 3. If you want the menu to stay until the users locks his uplink, add an active_uplink_check(mob/user as mob) in your interact/attack_hand proc. + Then check if it's true, if true return. This will stop the normal menu appearing and will instead show the uplink menu. +*/ + +/obj/item/device/uplink + name = "hidden uplink" + desc = "There is something wrong if you're examining this." + var/active = 0 + var/datum/uplink_category/category = 0 // The current category we are in + var/exploit_id // Id of the current exploit record we are viewing + + var/welcome = "Welcome, Operative" // Welcoming menu message + var/uses // Numbers of crystals + var/list/ItemsCategory // List of categories with lists of items + var/list/ItemsReference // List of references with an associated item + var/list/nanoui_items // List of items for NanoUI use + var/nanoui_menu = 0 // The current menu we are in + var/list/nanoui_data = new // Additional data for NanoUI use + + var/datum/mind/uplink_owner = null + var/used_TC = 0 + var/offer_time = 15 MINUTES //The time increment per discount offered + var/next_offer_time //The time a discount will next be offered + var/datum/uplink_item/discount_item //The item to be discounted + var/discount_amount //The amount as a percent the item will be discounted by + +/obj/item/device/uplink/nano_host() + return loc + +/obj/item/device/uplink/New(var/atom/location, var/datum/mind/owner, var/telecrystals = DEFAULT_TELECRYSTAL_AMOUNT) + if(!istype(location, /atom)) + CRASH("Invalid spawn location. Expected /atom, was [location ? location.type : "NULL"]") + + ..() + nanoui_data = list() + update_nano_data() + + src.uplink_owner = owner + world_uplinks += src + uses = telecrystals + START_PROCESSING(SSobj, src) + +/obj/item/device/uplink/Destroy() + uplink_owner = null + world_uplinks -= src + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/device/uplink/Process() + if(world.time > next_offer_time) + next_offer_time = world.time + offer_time + discount_amount = pick(90;0.9, 80;0.8, 70;0.7, 60;0.6, 50;0.5, 40;0.4, 30;0.3, 20;0.2, 10;0.1) + + var/datum/uplink_item/new_discount_item + do + var/datum/uplink_random_selection/uplink_selection = get_uplink_random_selection_by_type(/datum/uplink_random_selection/blacklist) + new_discount_item = uplink_selection.get_random_item(INFINITY, src) + // Ensures we only only get items for which we get an actual discount and that this particular uplink can actually view (can buy would risk near-infinite loops). + while(is_improper_item(new_discount_item, discount_amount)) + if(!new_discount_item) + return + + discount_item = new_discount_item + update_nano_data() + GLOB.nanomanager.update_uis(src) + +/obj/item/device/uplink/proc/is_improper_item(var/datum/uplink_item/new_discount_item, discount_amount) + if(!new_discount_item) + return FALSE + + if(istype(new_discount_item, /datum/uplink_item/item/stealthy_weapons/soap)) + return FALSE + + var/discount_price = round(new_discount_item.cost(uses) * discount_amount) + if(!discount_price || new_discount_item.cost(uses) == discount_price) + return TRUE + + if(!new_discount_item.can_view(src)) + return TRUE + + return FALSE + +/obj/item/device/uplink/proc/get_item_cost(var/item_type, var/item_cost) + return item_type == discount_item ? max(1, round(item_cost*discount_amount)) : item_cost + +// Toggles the uplink on and off. Normally this will bypass the item's normal functions and go to the uplink menu, if activated. +/obj/item/device/uplink/proc/toggle() + active = !active + +// Directly trigger the uplink. Turn on if it isn't already. +/obj/item/device/uplink/proc/trigger(mob/user as mob) + if(!active) + toggle() + interact(user) + +// Checks to see if the value meets the target. Like a frequency being a traitor_frequency, in order to unlock a headset. +// If true, it accesses trigger() and returns 1. If it fails, it returns false. Use this to see if you need to close the +// current item's menu. +/obj/item/device/uplink/proc/check_trigger(mob/user as mob, var/value, var/target) + if(value == target) + trigger(user) + return 1 + return 0 + +/* + NANO UI FOR UPLINK WOOP WOOP +*/ +/obj/item/device/uplink/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/uistate = GLOB.inventory_state) + var/title = "Remote Uplink" + var/data[0] + + data["welcome"] = welcome + data["crystals"] = uses + data["menu"] = nanoui_menu + data["discount_category"] = discount_item ? discount_item.category.name : "" + data["discount_name"] = discount_item ? discount_item.name : "" + data["discount_amount"] = (1-discount_amount)*100 + data["offer_expiry"] = worldtime2stationtime(next_offer_time) + + data += nanoui_data + + // update the ui if it exists, returns null if no ui is passed/found + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) // No auto-refresh + ui = new(user, src, ui_key, "uplink.tmpl", title, 450, 600, state = uistate) + ui.set_initial_data(data) + ui.open() + + +// Interaction code. Gathers a list of items purchasable from the paren't uplink and displays it. It also adds a lock button. +/obj/item/device/uplink/interact(mob/user) + ui_interact(user) + +/obj/item/device/uplink/CanUseTopic() + if(!active) + return STATUS_CLOSE + return ..() + +// The purchasing code. +/obj/item/device/uplink/OnTopic(user, href_list) + if(href_list["buy_item"]) + var/datum/uplink_item/UI = (locate(href_list["buy_item"]) in uplink.items) + UI.buy(src, usr) + . = TOPIC_REFRESH + else if(href_list["lock"]) + toggle() + GLOB.nanomanager.close_user_uis(user, src, "main") + . = TOPIC_HANDLED + else if(href_list["return"]) + nanoui_menu = round(nanoui_menu/10) + . = TOPIC_REFRESH + else if(href_list["menu"]) + nanoui_menu = text2num(href_list["menu"]) + if(href_list["id"]) + exploit_id = text2num(href_list["id"]) + if(href_list["category"]) + category = locate(href_list["category"]) in uplink.categories + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + update_nano_data() + +/obj/item/device/uplink/proc/update_nano_data() + if(nanoui_menu == 0) + var/categories[0] + for(var/datum/uplink_category/category in uplink.categories) + if(category.can_view(src)) + categories[++categories.len] = list("name" = category.name, "ref" = "\ref[category]") + nanoui_data["categories"] = categories + else if(nanoui_menu == 1) + var/items[0] + for(var/datum/uplink_item/item in category.items) + if(item.can_view(src)) + var/cost = item.cost(uses, src) + if(!cost) cost = "???" + items[++items.len] = list("name" = item.name(), "description" = replacetext(item.description(), "\n", "
            "), "can_buy" = item.can_buy(src), "cost" = cost, "ref" = "\ref[item]") + nanoui_data["items"] = items + else if(nanoui_menu == 2) + var/permanentData[0] + for(var/datum/computer_file/crew_record/L in GLOB.all_crew_records) + permanentData[++permanentData.len] = list(Name = L.get_name(),"id" = L.uid, "exploit" = length(L.get_antagRecord())) + nanoui_data["exploit_records"] = permanentData + else if(nanoui_menu == 21) + nanoui_data["exploit_exists"] = 0 + + for(var/datum/computer_file/crew_record/L in GLOB.all_crew_records) + if(L.uid == exploit_id) + nanoui_data["exploit"] = list() // Setting this to equal L.fields passes it's variables that are lists as reference instead of value. + // We trade off being able to automatically add shit for more control over what gets passed to json + // and if it's sanitized for html. + var/list/fields = list( + REC_FIELD(name), + REC_FIELD(sex), + REC_FIELD(age), + //REC_FIELD(species), + REC_FIELD(rank), + //REC_FIELD(homeSystem), + //REC_FIELD(citizenship), + //REC_FIELD(faction), + //REC_FIELD(religion), + REC_FIELD(fingerprint), + REC_FIELD(antagRecord)) + var/list/rec_fields = list() + for(var/field in fields) + var/record_field/F = locate(field) in L.fields + if(!F) + continue + rec_fields.Add(list(list( + "name" = html_encode(F.name), + "val" = F.get_display_value() + ))) + nanoui_data["exploit"]["fields"] = rec_fields + + nanoui_data["exploit_exists"] = 1 + break + +// I placed this here because of how relevant it is. +// You place this in your uplinkable item to check if an uplink is active or not. +// If it is, it will display the uplink menu and return 1, else it'll return false. +// If it returns true, I recommend closing the item's normal menu with "user << browse(null, "window=name")" +/obj/item/proc/active_uplink_check(mob/user as mob) + // Activates the uplink if it's active + if(src.hidden_uplink) + if(src.hidden_uplink.active) + src.hidden_uplink.trigger(user) + return 1 + return 0 + +// PRESET UPLINKS +// A collection of preset uplinks. +// +// Includes normal radio uplink, multitool uplink, +// implant uplink (not the implant tool) and a preset headset uplink. + +/obj/item/device/radio/uplink/New(var/loc, var/owner, var/amount) + ..() + hidden_uplink = new(src, owner, amount) + icon_state = "radio" + +/obj/item/device/radio/uplink/attack_self(mob/user as mob) + if(hidden_uplink) + hidden_uplink.trigger(user) + +/obj/item/device/multitool/uplink/New(var/loc, var/owner) + ..() + hidden_uplink = new(src, owner) + +/obj/item/device/multitool/uplink/attack_self(mob/user as mob) + if(hidden_uplink) + hidden_uplink.trigger(user) + +/obj/item/device/radio/headset/uplink + traitor_frequency = 1445 + +/obj/item/device/radio/headset/uplink/New() + ..() + hidden_uplink = new(src) + +/obj/item/device/uplink/contained/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/uistate = GLOB.contained_state) + return ..() diff --git a/code/game/objects/items/devices/uplink_random_lists.dm b/code/game/objects/items/devices/uplink_random_lists.dm new file mode 100644 index 00000000..b6845a0e --- /dev/null +++ b/code/game/objects/items/devices/uplink_random_lists.dm @@ -0,0 +1,150 @@ +/datum/uplink_random_item + var/uplink_item // The uplink item + var/keep_probability // The probability we'll decide to keep this item if selected + var/reselect_probability // Probability that we'll decide to keep this item if previously selected. + // Is done together with the keep_probability check. Being selected more than once does not affect this probability. + +/datum/uplink_random_item/New(var/uplink_item, var/keep_probability = 100, var/reselect_propbability = 33) + ..() + src.uplink_item = uplink_item + src.keep_probability = keep_probability + src.reselect_probability = reselect_probability + +/datum/uplink_random_selection + var/list/datum/uplink_random_item/items + +/datum/uplink_random_selection/New() + ..() + items = list() + +/datum/uplink_random_selection/proc/get_random_item(var/telecrystals, obj/item/device/uplink/U, var/list/bought_items) + var/const/attempts = 50 + + for(var/i = 0; i < attempts; i++) + var/datum/uplink_random_item/RI = pick(items) + if(!prob(RI.keep_probability)) + continue + var/datum/uplink_item/I = uplink.items_assoc[RI.uplink_item] + if(I.cost(telecrystals, U) > telecrystals) + continue + if(bought_items && (I in bought_items) && !prob(RI.reselect_probability)) + continue + if(U && !I.can_buy(U)) + continue + return I + return uplink.items_assoc[/datum/uplink_item/item/stealthy_weapons/soap] + +var/list/uplink_random_selections_ +/proc/get_uplink_random_selection_by_type(var/uplist_selection_type) + if(!uplink_random_selections_) + uplink_random_selections_ = init_subtypes(/datum/uplink_random_selection) + for(var/datum/entry in uplink_random_selections_) + uplink_random_selections_[entry.type] = entry + return uplink_random_selections_[uplist_selection_type] + +/datum/uplink_random_selection/default/New() + ..() + + items += new/datum/uplink_random_item(/datum/uplink_item/item/visible_weapons/g9mm) + items += new/datum/uplink_random_item(/datum/uplink_item/item/visible_weapons/revolver) + items += new/datum/uplink_random_item(/datum/uplink_item/item/visible_weapons/heavysniper, 15, 0) + items += new/datum/uplink_random_item(/datum/uplink_item/item/grenades/emp, 50) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/visible_weapons/crossbow, 33) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/visible_weapons/energy_sword, 75) + + items += new/datum/uplink_random_item(/datum/uplink_item/item/stealthy_weapons/soap, 5, 100) + items += new/datum/uplink_random_item(/datum/uplink_item/item/stealthy_weapons/concealed_cane, 50, 10) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/stealthy_weapons/detomatix, 20, 10) + items += new/datum/uplink_random_item(/datum/uplink_item/item/stealthy_weapons/sleepy) + items += new/datum/uplink_random_item(/datum/uplink_item/item/stealthy_weapons/cigarette_kit) + + items += new/datum/uplink_random_item(/datum/uplink_item/item/stealth_items/id) + items += new/datum/uplink_random_item(/datum/uplink_item/item/stealth_items/spy) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/stealth_items/chameleon_kit) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/stealth_items/chameleon_projector) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/stealth_items/voice) + + //items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/toolbox, reselect_propbability = 10) + items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/plastique) + items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/encryptionkey_radio) + items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/encryptionkey_binary) + items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/emag, 100, 50) + items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/clerical) + items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/space_suit, 50, 10) + items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/thermal) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/heavy_armor) + items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/powersink, 10, 10) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/ai_module, 25, 0) + items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/teleporter, 10, 0) + + //items += new/datum/uplink_random_item(/datum/uplink_item/item/implants/imp_freedom) + items += new/datum/uplink_random_item(/datum/uplink_item/item/implants/imp_compress) + items += new/datum/uplink_random_item(/datum/uplink_item/item/implants/imp_explosive) + + items += new/datum/uplink_random_item(/datum/uplink_item/item/medical/sinpockets, reselect_propbability = 20) + items += new/datum/uplink_random_item(/datum/uplink_item/item/medical/surgery, reselect_propbability = 10) + items += new/datum/uplink_random_item(/datum/uplink_item/item/medical/combat, reselect_propbability = 10) + + //items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/thermal, reselect_propbability = 15) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/energy_net, reselect_propbability = 15) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/ewar_voice, reselect_propbability = 15) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/maneuvering_jets, reselect_propbability = 15) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/egun, reselect_propbability = 15) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/power_sink, reselect_propbability = 15) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/laser_canon, reselect_propbability = 5) + + //items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/thermal, reselect_propbability = 15) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/thermal, reselect_propbability = 15) + //items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/thermal, reselect_propbability = 15) + + items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/suit_sensor_mobile) + items += new/datum/uplink_random_item(/datum/uplink_item/item/services/suit_sensor_shutdown, 75, 0) + items += new/datum/uplink_random_item(/datum/uplink_item/item/services/suit_sensor_garble, 75, 0) + +/datum/uplink_random_selection/blacklist + var/list/blacklist = list( + /datum/uplink_item/item/ammo, + /datum/uplink_item/item/badassery, + /datum/uplink_item/item/telecrystal, + /datum/uplink_item/item/tools/teleporter, + ///datum/uplink_item/item/tools/supply_beacon, + /datum/uplink_item/item/implants/imp_uplink + ) + +/datum/uplink_random_selection/blacklist/New() + ..() + for(var/uplink_item_type in subtypesof(/datum/uplink_item/item)) + var/datum/uplink_item/item/ui = uplink_item_type + if(!initial(ui.name)) + continue + if(is_path_in_list(uplink_item_type, blacklist)) + continue + var/new_thing = new/datum/uplink_random_item(uplink_item_type) + items += new_thing + +/datum/uplink_random_selection/blacklist/get_random_item(var/telecrystals, obj/item/device/uplink/U, var/list/bought_items) + var/const/attempts = 50 + for(var/i = 0; i < attempts; i++) + var/datum/uplink_random_item/RI = pick(items) + if(!prob(RI.keep_probability)) + continue + var/datum/uplink_item/I = uplink.items_assoc[RI.uplink_item] + if(I.cost(telecrystals, U) > telecrystals) + continue + if(bought_items && (I in bought_items) && !prob(RI.reselect_probability)) + continue + return I + return uplink.items_assoc[/datum/uplink_item/item/stealthy_weapons/soap] + +#ifdef DEBUG +/proc/debug_uplink_purchage_log() + var/list/all_antag_types = all_antag_types() + for(var/antag_type in all_antag_types) + var/datum/antagonist/A = all_antag_types[antag_type] + A.print_player_summary() + +/proc/debug_uplink_item_assoc_list() + for(var/key in uplink.items_assoc) + log_debug("[key] - [uplink.items_assoc[key]]") + +#endif diff --git a/code/game/objects/items/devices/violin.dm b/code/game/objects/items/devices/violin.dm new file mode 100644 index 00000000..f62074c4 --- /dev/null +++ b/code/game/objects/items/devices/violin.dm @@ -0,0 +1,398 @@ +//copy pasta of the space piano, don't hurt me -Pete + +/obj/item/device/violin + name = "space violin" + desc = "A wooden musical instrument with four strings and a bow. \"The devil went down to space, he was looking for an assistant to grief.\"." + icon = 'icons/obj/musician.dmi' + icon_state = "violin" + item_state = "violin" + force = 10 + var/datum/song/song + var/playing = 0 + var/help = 0 + var/edit = 1 + var/repeat = 0 + +/obj/item/device/violin/proc/playnote(var/note as text) +// log_debug("Note: [note]") + + var/soundfile + /*BYOND loads resource files at compile time if they are ''. This means you can't really manipulate them dynamically. + Tried doing it dynamically at first but its more trouble than its worth. Would have saved many lines tho.*/ + switch(note) + if("Cn1") soundfile = 'sound/violin/Cn1.mid' + if("C#1") soundfile = 'sound/violin/C#1.mid' + if("Db1") soundfile = 'sound/violin/Db1.mid' + if("Dn1") soundfile = 'sound/violin/Dn1.mid' + if("D#1") soundfile = 'sound/violin/D#1.mid' + if("Eb1") soundfile = 'sound/violin/Eb1.mid' + if("En1") soundfile = 'sound/violin/En1.mid' + if("E#1") soundfile = 'sound/violin/E#1.mid' + if("Fb1") soundfile = 'sound/violin/Fb1.mid' + if("Fn1") soundfile = 'sound/violin/Fn1.mid' + if("F#1") soundfile = 'sound/violin/F#1.mid' + if("Gb1") soundfile = 'sound/violin/Gb1.mid' + if("Gn1") soundfile = 'sound/violin/Gn1.mid' + if("G#1") soundfile = 'sound/violin/G#1.mid' + if("Ab1") soundfile = 'sound/violin/Ab1.mid' + if("An1") soundfile = 'sound/violin/An1.mid' + if("A#1") soundfile = 'sound/violin/A#1.mid' + if("Bb1") soundfile = 'sound/violin/Bb1.mid' + if("Bn1") soundfile = 'sound/violin/Bn1.mid' + if("B#1") soundfile = 'sound/violin/B#1.mid' + if("Cb2") soundfile = 'sound/violin/Cb2.mid' + if("Cn2") soundfile = 'sound/violin/Cn2.mid' + if("C#2") soundfile = 'sound/violin/C#2.mid' + if("Db2") soundfile = 'sound/violin/Db2.mid' + if("Dn2") soundfile = 'sound/violin/Dn2.mid' + if("D#2") soundfile = 'sound/violin/D#2.mid' + if("Eb2") soundfile = 'sound/violin/Eb2.mid' + if("En2") soundfile = 'sound/violin/En2.mid' + if("E#2") soundfile = 'sound/violin/E#2.mid' + if("Fb2") soundfile = 'sound/violin/Fb2.mid' + if("Fn2") soundfile = 'sound/violin/Fn2.mid' + if("F#2") soundfile = 'sound/violin/F#2.mid' + if("Gb2") soundfile = 'sound/violin/Gb2.mid' + if("Gn2") soundfile = 'sound/violin/Gn2.mid' + if("G#2") soundfile = 'sound/violin/G#2.mid' + if("Ab2") soundfile = 'sound/violin/Ab2.mid' + if("An2") soundfile = 'sound/violin/An2.mid' + if("A#2") soundfile = 'sound/violin/A#2.mid' + if("Bb2") soundfile = 'sound/violin/Bb2.mid' + if("Bn2") soundfile = 'sound/violin/Bn2.mid' + if("B#2") soundfile = 'sound/violin/B#2.mid' + if("Cb3") soundfile = 'sound/violin/Cb3.mid' + if("Cn3") soundfile = 'sound/violin/Cn3.mid' + if("C#3") soundfile = 'sound/violin/C#3.mid' + if("Db3") soundfile = 'sound/violin/Db3.mid' + if("Dn3") soundfile = 'sound/violin/Dn3.mid' + if("D#3") soundfile = 'sound/violin/D#3.mid' + if("Eb3") soundfile = 'sound/violin/Eb3.mid' + if("En3") soundfile = 'sound/violin/En3.mid' + if("E#3") soundfile = 'sound/violin/E#3.mid' + if("Fb3") soundfile = 'sound/violin/Fb3.mid' + if("Fn3") soundfile = 'sound/violin/Fn3.mid' + if("F#3") soundfile = 'sound/violin/F#3.mid' + if("Gb3") soundfile = 'sound/violin/Gb3.mid' + if("Gn3") soundfile = 'sound/violin/Gn3.mid' + if("G#3") soundfile = 'sound/violin/G#3.mid' + if("Ab3") soundfile = 'sound/violin/Ab3.mid' + if("An3") soundfile = 'sound/violin/An3.mid' + if("A#3") soundfile = 'sound/violin/A#3.mid' + if("Bb3") soundfile = 'sound/violin/Bb3.mid' + if("Bn3") soundfile = 'sound/violin/Bn3.mid' + if("B#3") soundfile = 'sound/violin/B#3.mid' + if("Cb4") soundfile = 'sound/violin/Cb4.mid' + if("Cn4") soundfile = 'sound/violin/Cn4.mid' + if("C#4") soundfile = 'sound/violin/C#4.mid' + if("Db4") soundfile = 'sound/violin/Db4.mid' + if("Dn4") soundfile = 'sound/violin/Dn4.mid' + if("D#4") soundfile = 'sound/violin/D#4.mid' + if("Eb4") soundfile = 'sound/violin/Eb4.mid' + if("En4") soundfile = 'sound/violin/En4.mid' + if("E#4") soundfile = 'sound/violin/E#4.mid' + if("Fb4") soundfile = 'sound/violin/Fb4.mid' + if("Fn4") soundfile = 'sound/violin/Fn4.mid' + if("F#4") soundfile = 'sound/violin/F#4.mid' + if("Gb4") soundfile = 'sound/violin/Gb4.mid' + if("Gn4") soundfile = 'sound/violin/Gn4.mid' + if("G#4") soundfile = 'sound/violin/G#4.mid' + if("Ab4") soundfile = 'sound/violin/Ab4.mid' + if("An4") soundfile = 'sound/violin/An4.mid' + if("A#4") soundfile = 'sound/violin/A#4.mid' + if("Bb4") soundfile = 'sound/violin/Bb4.mid' + if("Bn4") soundfile = 'sound/violin/Bn4.mid' + if("B#4") soundfile = 'sound/violin/B#4.mid' + if("Cb5") soundfile = 'sound/violin/Cb5.mid' + if("Cn5") soundfile = 'sound/violin/Cn5.mid' + if("C#5") soundfile = 'sound/violin/C#5.mid' + if("Db5") soundfile = 'sound/violin/Db5.mid' + if("Dn5") soundfile = 'sound/violin/Dn5.mid' + if("D#5") soundfile = 'sound/violin/D#5.mid' + if("Eb5") soundfile = 'sound/violin/Eb5.mid' + if("En5") soundfile = 'sound/violin/En5.mid' + if("E#5") soundfile = 'sound/violin/E#5.mid' + if("Fb5") soundfile = 'sound/violin/Fb5.mid' + if("Fn5") soundfile = 'sound/violin/Fn5.mid' + if("F#5") soundfile = 'sound/violin/F#5.mid' + if("Gb5") soundfile = 'sound/violin/Gb5.mid' + if("Gn5") soundfile = 'sound/violin/Gn5.mid' + if("G#5") soundfile = 'sound/violin/G#5.mid' + if("Ab5") soundfile = 'sound/violin/Ab5.mid' + if("An5") soundfile = 'sound/violin/An5.mid' + if("A#5") soundfile = 'sound/violin/A#5.mid' + if("Bb5") soundfile = 'sound/violin/Bb5.mid' + if("Bn5") soundfile = 'sound/violin/Bn5.mid' + if("B#5") soundfile = 'sound/violin/B#5.mid' + if("Cb6") soundfile = 'sound/violin/Cb6.mid' + if("Cn6") soundfile = 'sound/violin/Cn6.mid' + if("C#6") soundfile = 'sound/violin/C#6.mid' + if("Db6") soundfile = 'sound/violin/Db6.mid' + if("Dn6") soundfile = 'sound/violin/Dn6.mid' + if("D#6") soundfile = 'sound/violin/D#6.mid' + if("Eb6") soundfile = 'sound/violin/Eb6.mid' + if("En6") soundfile = 'sound/violin/En6.mid' + if("E#6") soundfile = 'sound/violin/E#6.mid' + if("Fb6") soundfile = 'sound/violin/Fb6.mid' + if("Fn6") soundfile = 'sound/violin/Fn6.mid' + if("F#6") soundfile = 'sound/violin/F#6.mid' + if("Gb6") soundfile = 'sound/violin/Gb6.mid' + if("Gn6") soundfile = 'sound/violin/Gn6.mid' + if("G#6") soundfile = 'sound/violin/G#6.mid' + if("Ab6") soundfile = 'sound/violin/Ab6.mid' + if("An6") soundfile = 'sound/violin/An6.mid' + if("A#6") soundfile = 'sound/violin/A#6.mid' + if("Bb6") soundfile = 'sound/violin/Bb6.mid' + if("Bn6") soundfile = 'sound/violin/Bn6.mid' + if("B#6") soundfile = 'sound/violin/B#6.mid' + if("Cb7") soundfile = 'sound/violin/Cb7.mid' + if("Cn7") soundfile = 'sound/violin/Cn7.mid' + if("C#7") soundfile = 'sound/violin/C#7.mid' + if("Db7") soundfile = 'sound/violin/Db7.mid' + if("Dn7") soundfile = 'sound/violin/Dn7.mid' + if("D#7") soundfile = 'sound/violin/D#7.mid' + if("Eb7") soundfile = 'sound/violin/Eb7.mid' + if("En7") soundfile = 'sound/violin/En7.mid' + if("E#7") soundfile = 'sound/violin/E#7.mid' + if("Fb7") soundfile = 'sound/violin/Fb7.mid' + if("Fn7") soundfile = 'sound/violin/Fn7.mid' + if("F#7") soundfile = 'sound/violin/F#7.mid' + if("Gb7") soundfile = 'sound/violin/Gb7.mid' + if("Gn7") soundfile = 'sound/violin/Gn7.mid' + if("G#7") soundfile = 'sound/violin/G#7.mid' + if("Ab7") soundfile = 'sound/violin/Ab7.mid' + if("An7") soundfile = 'sound/violin/An7.mid' + if("A#7") soundfile = 'sound/violin/A#7.mid' + if("Bb7") soundfile = 'sound/violin/Bb7.mid' + if("Bn7") soundfile = 'sound/violin/Bn7.mid' + if("B#7") soundfile = 'sound/violin/B#7.mid' + if("Cb8") soundfile = 'sound/violin/Cb8.mid' + if("Cn8") soundfile = 'sound/violin/Cn8.mid' + if("C#8") soundfile = 'sound/violin/C#8.mid' + if("Db8") soundfile = 'sound/violin/Db8.mid' + if("Dn8") soundfile = 'sound/violin/Dn8.mid' + if("D#8") soundfile = 'sound/violin/D#8.mid' + if("Eb8") soundfile = 'sound/violin/Eb8.mid' + if("En8") soundfile = 'sound/violin/En8.mid' + if("E#8") soundfile = 'sound/violin/E#8.mid' + if("Fb8") soundfile = 'sound/violin/Fb8.mid' + if("Fn8") soundfile = 'sound/violin/Fn8.mid' + if("F#8") soundfile = 'sound/violin/F#8.mid' + if("Gb8") soundfile = 'sound/violin/Gb8.mid' + if("Gn8") soundfile = 'sound/violin/Gn8.mid' + if("G#8") soundfile = 'sound/violin/G#8.mid' + if("Ab8") soundfile = 'sound/violin/Ab8.mid' + if("An8") soundfile = 'sound/violin/An8.mid' + if("A#8") soundfile = 'sound/violin/A#8.mid' + if("Bb8") soundfile = 'sound/violin/Bb8.mid' + if("Bn8") soundfile = 'sound/violin/Bn8.mid' + if("B#8") soundfile = 'sound/violin/B#8.mid' + if("Cb9") soundfile = 'sound/violin/Cb9.mid' + if("Cn9") soundfile = 'sound/violin/Cn9.mid' + else return + + sound_to(hearers(15, get_turf(src)), sound(soundfile)) + +/obj/item/device/violin/proc/playsong() + do + var/cur_oct[7] + var/cur_acc[7] + for(var/i = 1 to 7) + cur_oct[i] = "3" + cur_acc[i] = "n" + + for(var/line in song.lines) +// log_debug(line) + + for(var/beat in splittext(lowertext(line), ",")) +// log_debug("beat: [beat]") + + var/list/notes = splittext(beat, "/") + for(var/note in splittext(notes[1], "-")) +// log_debug("note: [note]") + + if(!playing || !isliving(loc))//If the violin is playing, or isn't held by a person + playing = 0 + return + if(length(note) == 0) + continue +// log_debug("Parse: [copytext(note,1,2)]") + + var/cur_note = text2ascii(note) - 96 + if(cur_note < 1 || cur_note > 7) + continue + for(var/i=2 to length(note)) + var/ni = copytext(note,i,i+1) + if(!text2num(ni)) + if(ni == "#" || ni == "b" || ni == "n") + cur_acc[cur_note] = ni + else if(ni == "s") + cur_acc[cur_note] = "#" // so shift is never required + else + cur_oct[cur_note] = ni + playnote(uppertext(copytext(note,1,2)) + cur_acc[cur_note] + cur_oct[cur_note]) + if(notes.len >= 2 && text2num(notes[2])) + sleep(song.tempo / text2num(notes[2])) + else + sleep(song.tempo) + if(repeat > 0) + repeat-- //Infinite loops are baaaad. + while(repeat > 0) + playing = 0 + +/obj/item/device/violin/attack_self(mob/user as mob) + if(!isliving(user) || user.stat || user.restrained() || user.lying) return + user.set_machine(src) + + var/dat = "Violin" + + if(song) + if(song.lines.len > 0 && !(playing)) + dat += "Play Song

            " + dat += "Repeat Song: [repeat] times.

            " + if(playing) + dat += "Stop Playing
            " + dat += "Repeats left: [repeat].

            " + if(!edit) + dat += "Show Editor

            " + else + dat += "Hide Editor
            " + dat += "Start a New Song
            " + dat += "Import a Song

            " + if(song) + var/calctempo = (10/song.tempo)*60 + dat += "Tempo : -- [calctempo] BPM ++

            " + var/linecount = 0 + for(var/line in song.lines) + linecount += 1 + dat += "Line [linecount]: [line] Delete Line Modify Line
            " + dat += "Add Line

            " + if(help) + dat += "Hide Help
            " + dat += {" + Lines are a series of chords, separated by commas (,), each with notes seperated by hyphens (-).
            + Every note in a chord will play together, with chord timed by the tempo.
            +
            + Notes are played by the names of the note, and optionally, the accidental, and/or the octave number.
            + By default, every note is natural and in octave 3. Defining otherwise is remembered for each note.
            + Example: C,D,E,F,G,A,B will play a C major scale.
            + After a note has an accidental placed, it will be remembered: C,C4,C,C3 is C3,C4,C4,C3
            + Chords can be played simply by seperating each note with a hyphon: A-C#,Cn-E,E-G#,Gn-B
            + A pause may be denoted by an empty chord: C,E,,C,G
            + To make a chord be a different time, end it with /x, where the chord length will be length
            + defined by tempo / x: C,G/2,E/4
            + Combined, an example is: E-E4/4,/2,G#/8,B/8,E3-E4/4 +
            + Lines may be up to 50 characters.
            + A song may only contain up to 50 lines.
            + "} + else + dat += "Show Help
            " + dat += "" + user << browse(dat, "window=violin;size=700x300") + onclose(user, "violin") + +/obj/item/device/violin/Topic(href, href_list) + if(..()) + return 1 + if(!in_range(src, usr) || issilicon(usr) || !isliving(usr) || !usr.canmove || usr.restrained()) + usr << browse(null, "window=violin;size=700x300") + onclose(usr, "violin") + return + + if(href_list["newsong"]) + song = new() + else if(song) + if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops. + if(playing) return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing. + var/tempnum = input("How many times do you want to repeat this piece? (max:10)") as num|null + if(tempnum > 10) + tempnum = 10 + if(tempnum < 0) + tempnum = 0 + repeat = round(tempnum) + + else if(href_list["tempo"]) + song.tempo += round(text2num(href_list["tempo"])) + if(song.tempo < 1) + song.tempo = 1 + + else if(href_list["play"]) + if(song) + playing = 1 + spawn() playsong() + + else if(href_list["newline"]) + var/newline = html_encode(input("Enter your line: ", "violin") as text|null) + if(!newline) + return + if(song.lines.len > 50) + return + if(length(newline) > 50) + newline = copytext(newline, 1, 50) + song.lines.Add(newline) + + else if(href_list["deleteline"]) + var/num = round(text2num(href_list["deleteline"])) + if(num > song.lines.len || num < 1) + return + song.lines.Cut(num, num+1) + + else if(href_list["modifyline"]) + var/num = round(text2num(href_list["modifyline"]),1) + var/content = html_encode(input("Enter your line: ", "violin", song.lines[num]) as text|null) + if(!content) + return + if(length(content) > 50) + content = copytext(content, 1, 50) + if(num > song.lines.len || num < 1) + return + song.lines[num] = content + + else if(href_list["stop"]) + playing = 0 + + else if(href_list["help"]) + help = text2num(href_list["help"]) - 1 + + else if(href_list["edit"]) + edit = text2num(href_list["edit"]) - 1 + + else if(href_list["import"]) + var/t = "" + do + t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message) + if(!in_range(src, usr)) + return + + if(length(t) >= 3072) + var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no") + if(cont == "no") + break + while(length(t) > 3072) + + //split into lines + spawn() + var/list/lines = splittext(t, "\n") + var/tempo = 5 + if(copytext(lines[1],1,6) == "BPM: ") + tempo = 600 / text2num(copytext(lines[1],6)) + lines.Cut(1,2) + if(lines.len > 50) + to_chat(usr, "Too many lines!") + lines.Cut(51) + var/linenum = 1 + for(var/l in lines) + if(length(l) > 50) + to_chat(usr, "Line [linenum] too long!") + lines.Remove(l) + else + linenum++ + song = new() + song.lines = lines + song.tempo = tempo + + for(var/mob/M in viewers(1, loc)) + if((M.client && M.machine == src)) + attack_self(M) + return diff --git a/code/game/objects/items/devices/whistle.dm b/code/game/objects/items/devices/whistle.dm new file mode 100644 index 00000000..126a7103 --- /dev/null +++ b/code/game/objects/items/devices/whistle.dm @@ -0,0 +1,56 @@ +/obj/item/device/hailer + name = "hailer" + desc = "Used by obese officers to save their breath for running." + icon_state = "voice0" + item_state = "flashbang" //looks exactly like a flash (and nothing like a flashbang) + w_class = ITEM_SIZE_TINY + obj_flags = OBJ_FLAG_CONDUCTIBLE + + var/use_message = "Halt! Security!" + var/spamcheck = 0 + var/insults + +/obj/item/device/hailer/verb/set_message() + set name = "Set Hailer Message" + set category = "Object" + set desc = "Alter the message shouted by your hailer." + + if(!isnull(insults)) + to_chat(usr, "The hailer is fried. The tiny input screen just shows a waving ASCII penis.") + return + + var/new_message = input(usr, "Please enter new message (leave blank to reset).") as text + if(!new_message || new_message == "") + use_message = "Halt! Security!" + else + use_message = capitalize(copytext(sanitize(new_message), 1, MAX_MESSAGE_LEN)) + + to_chat(usr, "You configure the hailer to shout \"[use_message]\".") + +/obj/item/device/hailer/attack_self(mob/living/carbon/user as mob) + if (spamcheck) + return + + if(isnull(insults)) + playsound(get_turf(src), 'sound/voice/halt.ogg', 100, 1, vary = 0) + user.audible_message("[user]'s [name] rasps, \"[use_message]\"", null, "\The [user] holds up \the [name].") + else + if(insults > 0) + playsound(get_turf(src), 'sound/voice/binsult.ogg', 100, 1, vary = 0) + // Yes, it used to show the transcription of the sound clip. That was a) inaccurate b) immature as shit. + user.audible_message("[user]'s [name] gurgles something indecipherable and deeply offensive.", null, "\The [user] holds up \the [name].") + insults-- + else + to_chat(user, "*BZZZZZZZZT*") + + spamcheck = 1 + spawn(20) + spamcheck = 0 + +/obj/item/device/hailer/emag_act(var/remaining_charges, var/mob/user) + if(isnull(insults)) + to_chat(user, "You overload \the [src]'s voice synthesizer.") + insults = rand(1, 3)//to prevent dickflooding + return 1 + else + to_chat(user, "The hailer is fried. You can't even fit the sequencer into the input slot.") diff --git a/code/game/objects/items/glassjar.dm b/code/game/objects/items/glassjar.dm new file mode 100644 index 00000000..995a38ef --- /dev/null +++ b/code/game/objects/items/glassjar.dm @@ -0,0 +1,110 @@ +/obj/item/glass_jar + name = "glass jar" + desc = "A small empty jar." + icon = 'icons/obj/items.dmi' + icon_state = "jar" + w_class = ITEM_SIZE_SMALL + matter = list("glass" = 200) + item_flags = ITEM_FLAG_NO_BLUDGEON + var/list/accept_mobs = list(/mob/living/simple_animal/lizard, /mob/living/simple_animal/mouse) + var/contains = 0 // 0 = nothing, 1 = money, 2 = animal, 3 = spiderling + +/obj/item/glass_jar/New() + ..() + update_icon() + +/obj/item/glass_jar/afterattack(var/atom/A, var/mob/user, var/proximity) + if(!proximity || contains) + return + if(istype(A, /mob)) + var/accept = 0 + for(var/D in accept_mobs) + if(istype(A, D)) + accept = 1 + if(!accept) + to_chat(user, "[A] doesn't fit into \the [src].") + return + var/mob/L = A + user.visible_message("[user] scoops [L] into \the [src].", "You scoop [L] into \the [src].") + L.forceMove(src) + contains = 2 + update_icon() + return + else if(istype(A, /obj/effect/spider/spiderling)) + var/obj/effect/spider/spiderling/S = A + user.visible_message("[user] scoops [S] into \the [src].", "You scoop [S] into \the [src].") + S.forceMove(src) + STOP_PROCESSING(SSobj, S) // No growing inside jars + contains = 3 + update_icon() + return + +/obj/item/glass_jar/attack_self(var/mob/user) + switch(contains) + if(1) + for(var/obj/O in src) + O.loc = user.loc + to_chat(user, "You take money out of \the [src].") + contains = 0 + update_icon() + return + if(2) + for(var/mob/M in src) + M.loc = user.loc + user.visible_message("[user] releases [M] from \the [src].", "You release [M] from \the [src].") + contains = 0 + update_icon() + return + if(3) + for(var/obj/effect/spider/spiderling/S in src) + S.dropInto(user.loc) + user.visible_message("[user] releases [S] from \the [src].", "You release [S] from \the [src].") + START_PROCESSING(SSobj, S) // They can grow after being let out though + contains = 0 + update_icon() + return + +/obj/item/glass_jar/attackby(var/obj/item/W, var/mob/user) + if(istype(W, /obj/item/weapon/spacecash)) + if(contains == 0) + contains = 1 + if(contains != 1) + return + var/obj/item/weapon/spacecash/S = W + user.visible_message("[user] puts [S.worth] [S.worth > 1 ? "credits" : "credit"] into \the [src].") + user.drop_from_inventory(S) + S.forceMove(src) + update_icon() + +/obj/item/glass_jar/update_icon() // Also updates name and desc + underlays.Cut() + overlays.Cut() + switch(contains) + if(0) + SetName(initial(name)) + desc = initial(desc) + if(1) + SetName("tip jar") + desc = "A small jar with money inside." + for(var/obj/item/weapon/spacecash/S in src) + var/list/moneyImages = S.getMoneyImages() + for(var/A in moneyImages) + var/image/money = image('icons/obj/items.dmi', A) + money.pixel_x = rand(-2, 3) + money.pixel_y = rand(-6, 6) + money.transform *= 0.6 + underlays += money + if(2) + for(var/mob/M in src) + var/image/victim = image(M.icon, M.icon_state) + victim.pixel_y = 6 + underlays += victim + SetName("glass jar with [M]") + desc = "A small jar with [M] inside." + if(3) + for(var/obj/effect/spider/spiderling/S in src) + var/image/victim = image(S.icon, S.icon_state) + underlays += victim + SetName("glass jar with [S]") + desc = "A small jar with [S] inside." + return diff --git a/code/game/objects/items/instruments.dm b/code/game/objects/items/instruments.dm new file mode 100644 index 00000000..a9b10b72 --- /dev/null +++ b/code/game/objects/items/instruments.dm @@ -0,0 +1,15 @@ +/obj/item/instrument + icon = 'icons/obj/items.dmi' + throwforce = 0 + throw_speed = 3 + throw_range = 6 + force = 0 + +/obj/item/instrument/guitar + name = "guitar" + desc = "An antique musical instrument made of wood, originating from Earth. It has six metal strings of different girth and tension. When moved, they vibrate and the waves resonate in the guitar's open body, producing sounds. Obtained notes can be altered by pressing the strings to the neck, affecting the vibration's frequency." + icon = 'icons/obj/items.dmi' + icon_state = "guitar" + +/obj/item/instrument/guitar/attack_self(mob/user as mob) + user.visible_message("\The [user] strums [src]!","You strum [src]!") diff --git a/code/game/objects/items/latexballoon.dm b/code/game/objects/items/latexballoon.dm new file mode 100644 index 00000000..09c5d0bf --- /dev/null +++ b/code/game/objects/items/latexballoon.dm @@ -0,0 +1,48 @@ +/obj/item/latexballon + name = "latex glove" + desc = "A latex glove, usually used as a balloon." + icon_state = "latexballon" + item_state = "lgloves" + force = 0 + throwforce = 0 + w_class = ITEM_SIZE_SMALL + throw_speed = 1 + throw_range = 15 + var/state + var/datum/gas_mixture/air_contents = null + +/obj/item/latexballon/proc/blow(obj/item/weapon/tank/tank) + if (icon_state == "latexballon_bursted") + return + src.air_contents = tank.remove_air_volume(3) + icon_state = "latexballon_blow" + item_state = "latexballon" + +/obj/item/latexballon/proc/burst() + if (!air_contents) + return + playsound(src, 'sound/weapons/gunshot/gunshot.ogg', 100, 1) + icon_state = "latexballon_bursted" + item_state = "lgloves" + loc.assume_air(air_contents) + +/obj/item/latexballon/ex_act(severity) + burst() + switch(severity) + if (1) + qdel(src) + if (2) + if (prob(50)) + qdel(src) + +/obj/item/latexballon/bullet_act() + burst() + +/obj/item/latexballon/fire_act(datum/gas_mixture/air, temperature, volume) + if(temperature > T0C+100) + burst() + return + +/obj/item/latexballon/attackby(obj/item/W as obj, mob/user as mob) + if (W.can_puncture()) + burst() diff --git a/code/game/objects/items/paintkit.dm b/code/game/objects/items/paintkit.dm new file mode 100644 index 00000000..c251e8d1 --- /dev/null +++ b/code/game/objects/items/paintkit.dm @@ -0,0 +1,178 @@ +/obj/item/device/kit + icon_state = "modkit" + icon = 'icons/obj/device.dmi' + var/new_name = "mech" //What is the variant called? + var/new_desc = "A mech." //How is the new mech described? + var/new_icon = "ripley" //What base icon will the new mech use? + var/new_icon_file + var/uses = 1 // Uses before the kit deletes itself. + +/obj/item/device/kit/examine() + . = ..() + to_chat(usr, "It has [uses] use\s left.") + +/obj/item/device/kit/proc/use(var/amt, var/mob/user) + uses -= amt + playsound(get_turf(user), 'sound/items/Screwdriver.ogg', 50, 1) + if(uses<1) + user.drop_item() + qdel(src) + +// Root hardsuit kit defines. +// Icons for modified hardsuits need to be in the proper .dmis because suit cyclers may cock them up. +/obj/item/device/kit/suit + name = "voidsuit modification kit" + desc = "A kit for modifying a voidsuit." + uses = 2 + var/new_light_overlay + var/new_mob_icon_file + +/obj/item/clothing/head/helmet/space/void/attackby(var/obj/item/O, var/mob/user) + if(istype(O,/obj/item/device/kit/suit)) + var/obj/item/device/kit/suit/kit = O + SetName("[kit.new_name] suit helmet") + desc = kit.new_desc + icon_state = "[kit.new_icon]_helmet" + item_state = "[kit.new_icon]_helmet" + if(kit.new_icon_file) + icon = kit.new_icon_file + if(kit.new_mob_icon_file) + icon_override = kit.new_mob_icon_file + if(kit.new_light_overlay) + light_overlay = kit.new_light_overlay + to_chat(user, "You set about modifying the helmet into [src].") + var/mob/living/carbon/human/H = user + if(istype(H)) + species_restricted = list(H.species.get_bodytype(H)) + kit.use(1,user) + return 1 + return ..() + +/obj/item/clothing/suit/space/void/attackby(var/obj/item/O, var/mob/user) + if(istype(O,/obj/item/device/kit/suit)) + var/obj/item/device/kit/suit/kit = O + SetName("[kit.new_name] voidsuit") + desc = kit.new_desc + icon_state = "[kit.new_icon]_suit" + item_state = "[kit.new_icon]_suit" + if(kit.new_icon_file) + icon = kit.new_icon_file + if(kit.new_mob_icon_file) + icon_override = kit.new_mob_icon_file + to_chat(user, "You set about modifying the suit into [src].") + var/mob/living/carbon/human/H = user + if(istype(H)) + species_restricted = list(H.species.get_bodytype(H)) + kit.use(1,user) + return 1 + return ..() + +/obj/item/device/kit/paint + name = "mecha customisation kit" + desc = "A kit containing all the needed tools and parts to repaint a mech." + var/removable = null + var/list/allowed_types = list() + +/obj/item/device/kit/paint/examine() + . = ..() + to_chat(usr, "This kit will convert an exosuit into: [new_name].") + to_chat(usr, "This kit can be used on the following exosuit models:") + for(var/exotype in allowed_types) + to_chat(usr, "- [capitalize(exotype)]") + +/obj/mecha/attackby(var/obj/item/weapon/W, var/mob/user) + if(istype(W, /obj/item/device/kit/paint)) + if(occupant) + to_chat(user, "You can't customize a mech while someone is piloting it - that would be unsafe!") + return + + var/obj/item/device/kit/paint/P = W + var/found = null + + for(var/type in P.allowed_types) + if(type==src.initial_icon) + found = 1 + break + + if(!found) + to_chat(user, "That kit isn't meant for use on this class of exosuit.") + return + + user.visible_message("[user] opens [P] and spends some quality time customising [src].") + src.SetName(P.new_name) + src.desc = P.new_desc + src.initial_icon = P.new_icon + if(P.new_icon_file) + src.icon = P.new_icon_file + src.reset_icon() + P.use(1, user) + return 1 + else + return ..() + +//Ripley APLU kits. +/obj/item/device/kit/paint/ripley + name = "\"Classic\" APLU customisation kit" + new_name = "APLU \"Classic\"" + new_desc = "A very retro APLU unit; didn't they retire these back in 2543?" + new_icon = "ripley-old" + allowed_types = list("ripley") + +/obj/item/device/kit/paint/ripley/death + name = "\"Reaper\" APLU customisation kit" + new_name = "APLU \"Reaper\"" + new_desc = "A terrifying, grim power loader. Why do those clamps have spikes?" + new_icon = "deathripley" + allowed_types = list("ripley","firefighter") + +/obj/item/device/kit/paint/ripley/flames_red + name = "\"Firestarter\" APLU customisation kit" + new_name = "APLU \"Firestarter\"" + new_desc = "A standard APLU exosuit with stylish orange flame decals." + new_icon = "ripley_flames_red" + +/obj/item/device/kit/paint/ripley/flames_blue + name = "\"Burning Chrome\" APLU customisation kit" + new_name = "APLU \"Burning Chrome\"" + new_desc = "A standard APLU exosuit with stylish blue flame decals." + new_icon = "ripley_flames_blue" + +// Durand kits. +/obj/item/device/kit/paint/durand + name = "\"Classic\" Durand customisation kit" + new_name = "Durand \"Classic\"" + new_desc = "An older model of Durand combat exosuit. This model was retired for rotating a pilot's torso 180 degrees." + new_icon = "old_durand" + allowed_types = list("durand") + +/obj/item/device/kit/paint/durand/seraph + name = "\"Cherubim\" Durand customisation kit" + new_name = "Durand \"Cherubim\"" + new_desc = "A Durand combat exosuit modelled after ancient Earth entertainment. Your heart goes doki-doki just looking at it." + new_icon = "old_durand" + +/obj/item/device/kit/paint/durand/phazon + name = "\"Sypher\" Durand customisation kit" + new_name = "Durand \"Sypher\"" + new_desc = "A Durand combat exosuit with some very stylish neons and decals. Seems to blur slightly at the edges; probably an optical illusion." + new_icon = "phazon" + +// Gygax kits. +/obj/item/device/kit/paint/gygax + name = "\"Jester\" Gygax customisation kit" + new_name = "Gygax \"Jester\"" + new_desc = "A Gygax exosuit modelled after the infamous combat-troubadors of Earth's distant past. Terrifying to behold." + new_icon = "honker" + allowed_types = list("gygax") + +/obj/item/device/kit/paint/gygax/darkgygax + name = "\"Silhouette\" Gygax customisation kit" + new_name = "Gygax \"Silhouette\"" + new_desc = "An ominous Gygax exosuit modelled after the fictional corporate 'death squads' that were popular in pulp action-thrillers back in 2554." + new_icon = "darkgygax" + +/obj/item/device/kit/paint/gygax/recitence + name = "\"Gaoler\" Gygax customisation kit" + new_name = "Durand \"Gaoler\"" + new_desc = "A bulky silver Gygax exosuit. The extra armour appears to be painted on, but it's very shiny." + new_icon = "recitence" \ No newline at end of file diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm new file mode 100644 index 00000000..eb559ac9 --- /dev/null +++ b/code/game/objects/items/robot/robot_items.dm @@ -0,0 +1,66 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/********************************************************************** + Cyborg Spec Items +***********************************************************************/ +/obj/item/borg/overdrive + name = "overdrive" + icon = 'icons/obj/decals.dmi' + icon_state = "shock" + +/********************************************************************** + HUD/SIGHT things +***********************************************************************/ +/obj/item/borg/sight + icon = 'icons/obj/decals.dmi' + icon_state = "securearea" + var/sight_mode = null + + +/obj/item/borg/sight/xray + name = "\proper x-ray vision" + sight_mode = BORGXRAY + + +/obj/item/borg/sight/thermal + name = "\proper thermal vision" + sight_mode = BORGTHERM + icon_state = "thermal" + icon = 'icons/obj/clothing/glasses.dmi' + + +/obj/item/borg/sight/meson + name = "\proper meson vision" + sight_mode = BORGMESON + icon_state = "meson" + icon = 'icons/obj/clothing/glasses.dmi' + +/obj/item/borg/sight/material + name = "\proper material scanner vision" + sight_mode = BORGMATERIAL + +/obj/item/borg/sight/hud + name = "hud" + var/obj/item/clothing/glasses/hud/hud = null + + +/obj/item/borg/sight/hud/med + name = "medical hud" + icon_state = "healthhud" + icon = 'icons/obj/clothing/glasses.dmi' + + New() + ..() + hud = new /obj/item/clothing/glasses/hud/health(src) + return + + +/obj/item/borg/sight/hud/sec + name = "security hud" + icon_state = "securityhud" + icon = 'icons/obj/clothing/glasses.dmi' + + New() + ..() + hud = new /obj/item/clothing/glasses/hud/security(src) + return diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm new file mode 100644 index 00000000..260e2226 --- /dev/null +++ b/code/game/objects/items/robot/robot_parts.dm @@ -0,0 +1,363 @@ +/obj/item/robot_parts + name = "robot parts" + icon = 'icons/obj/robot_parts.dmi' + item_state = "buildpipe" + icon_state = "blank" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + var/list/part = null // Order of args is important for installing robolimbs. + var/sabotaged = 0 //Emagging limbs can have repercussions when installed as prosthetics. + var/model_info + var/bp_tag = null // What part is this? + dir = SOUTH + +/obj/item/robot_parts/set_dir() + return + +/obj/item/robot_parts/New(var/newloc, var/model) + ..(newloc) + if(model_info && model) + model_info = model + var/datum/robolimb/R = all_robolimbs[model] + if(R) + SetName("[R.company] [initial(name)]") + desc = "[R.desc]" + if(icon_state in icon_states(R.icon)) + icon = R.icon + else + SetName("robot [initial(name)]") + +/obj/item/robot_parts/proc/can_install(mob/user) + return TRUE + +/obj/item/robot_parts/l_arm + name = "left arm" + desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." + icon_state = "l_arm" + part = list(BP_L_ARM, BP_L_HAND) + model_info = 1 + bp_tag = BP_L_ARM + +/obj/item/robot_parts/r_arm + name = "right arm" + desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." + icon_state = "r_arm" + part = list(BP_R_ARM, BP_R_HAND) + model_info = 1 + bp_tag = BP_R_ARM + +/obj/item/robot_parts/l_leg + name = "left leg" + desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." + icon_state = "l_leg" + part = list(BP_L_LEG, BP_L_FOOT) + model_info = 1 + bp_tag = BP_L_LEG + +/obj/item/robot_parts/r_leg + name = "right leg" + desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." + icon_state = "r_leg" + part = list(BP_R_LEG, BP_R_FOOT) + model_info = 1 + bp_tag = BP_R_LEG + +/obj/item/robot_parts/chest + name = "torso" + desc = "A heavily reinforced case containing cyborg logic boards, with space for a standard power cell." + icon_state = "chest" + part = list(BP_GROIN,BP_CHEST) + model_info = 1 + bp_tag = BP_CHEST + var/wires = 0.0 + var/obj/item/weapon/cell/cell = null + +/obj/item/robot_parts/chest/can_install(mob/user) + var/success = TRUE + if(!wires) + to_chat(user, "You need to attach wires to it first!") + success = FALSE + if(!cell) + to_chat(user, "You need to attach a cell to it first!") + success = FALSE + return success && ..() + +/obj/item/robot_parts/head + name = "head" + desc = "A standard reinforced braincase, with spine-plugged neural socket and sensor gimbals." + icon_state = "head" + part = list(BP_HEAD) + model_info = 1 + bp_tag = BP_HEAD + var/obj/item/device/flash/flash1 = null + var/obj/item/device/flash/flash2 = null + +/obj/item/robot_parts/head/can_install(mob/user) + var/success = TRUE; + if(!(flash1 && flash2)) + to_chat(user, "You need to attach a flash to it first!") + success = FALSE + return success && ..(); + +/obj/item/robot_parts/robot_suit + name = "endoskeleton" + desc = "A complex metal backbone with standard limb sockets and pseudomuscle anchors." + icon_state = "robo_suit" + var/parts = list() + var/created_name = "" + +/obj/item/robot_parts/robot_suit/New() + ..() + src.update_icon() + +/obj/item/robot_parts/robot_suit/update_icon() + src.overlays.Cut() + if(src.parts[BP_L_ARM]) + src.overlays += "l_arm+o" + if(src.parts[BP_R_ARM]) + src.overlays += "r_arm+o" + if(src.parts[BP_CHEST]) + src.overlays += "chest+o" + if(src.parts[BP_L_LEG]) + src.overlays += "l_leg+o" + if(src.parts[BP_R_LEG]) + src.overlays += "r_leg+o" + if(src.parts[BP_HEAD]) + src.overlays += "head+o" + +/obj/item/robot_parts/robot_suit/proc/check_completion() + if(src.parts[BP_L_ARM] && src.parts[BP_R_ARM] && src.parts[BP_L_LEG] && src.parts[BP_R_LEG] && src.parts[BP_CHEST] && src.parts[BP_HEAD]) + feedback_inc("cyborg_frames_built",1) + return 1 + return 0 + +/obj/item/robot_parts/robot_suit/attackby(obj/item/W as obj, mob/user as mob) + ..() + if(istype(W, /obj/item/stack/material) && W.get_material_name() == DEFAULT_WALL_MATERIAL && !parts[BP_L_ARM] && !parts[BP_R_ARM] && !parts[BP_L_LEG] && !parts[BP_R_LEG] && !parts[BP_CHEST] && !parts[BP_HEAD]) + var/obj/item/stack/material/M = W + if (M.use(1)) + var/obj/item/weapon/secbot_assembly/ed209_assembly/B = new /obj/item/weapon/secbot_assembly/ed209_assembly + B.loc = get_turf(src) + to_chat(user, "You armed the robot frame.") + if (user.get_inactive_hand()==src) + user.remove_from_mob(src) + user.put_in_inactive_hand(B) + qdel(src) + else + to_chat(user, "You need one sheet of metal to arm the robot frame.") + + if (istype(W, /obj/item/robot_parts)) + var/obj/item/robot_parts/part = W + if(src.parts[part.bp_tag]) return + if(part.can_install(user)) + user.drop_item() + part.loc = src + src.parts[part.bp_tag] = part + src.update_icon() + + if(istype(W, /obj/item/device/mmi) || istype(W, /obj/item/organ/internal/posibrain)) + var/mob/living/carbon/brain/B + if(istype(W, /obj/item/device/mmi)) + var/obj/item/device/mmi/M = W + B = M.brainmob + else + var/obj/item/organ/internal/posibrain/P = W + B = P.brainmob + if(check_completion()) + if(!istype(loc,/turf)) + to_chat(user, "You can't put \the [W] in, the frame has to be standing on the ground to be perfectly precise.") + return + if(!B) + to_chat(user, "Sticking an empty [W] into the frame would sort of defeat the purpose.") + return + if(!B.key) + var/ghost_can_reenter = 0 + if(B.mind) + for(var/mob/observer/ghost/G in GLOB.player_list) + if(G.can_reenter_corpse && G.mind == B.mind) + ghost_can_reenter = 1 + break + if(!ghost_can_reenter) + to_chat(user, "\The [W] is completely unresponsive; there's no point.") + return + + if(B.stat == DEAD) + to_chat(user, "Sticking a dead [W] into the frame would sort of defeat the purpose.") + return + + if(jobban_isbanned(B, "Cyborg")) + to_chat(user, "This [W] does not seem to fit.") + return + + var/mob/living/silicon/robot/O = new /mob/living/silicon/robot(get_turf(loc), unfinished = 1) + if(!O) return + + user.drop_item() + + O.mmi = W + O.set_invisibility(0) + O.custom_name = created_name + O.updatename("Default") + + B.mind.transfer_to(O) + + if(O.mind && O.mind.special_role) + O.mind.store_memory("In case you look at this after being borged, the objectives are only here until I find a way to make them not show up for you, as I can't simply delete them without screwing up round-end reporting. --NeoFite") + + O.job = "Cyborg" + + var/obj/item/robot_parts/chest/chest = parts[BP_CHEST] + O.cell = chest.cell + O.cell.loc = O + W.loc = O//Should fix cybros run time erroring when blown up. It got deleted before, along with the frame. + + // Since we "magically" installed a cell, we also have to update the correct component. + if(O.cell) + var/datum/robot_component/cell_component = O.components["power cell"] + cell_component.wrapped = O.cell + cell_component.installed = 1 + + feedback_inc("cyborg_birth",1) + callHook("borgify", list(O)) + O.Namepick() + + qdel(src) + else + to_chat(user, "The MMI must go in after everything else!") + + if (istype(W, /obj/item/weapon/pen)) + var/t = sanitizeSafe(input(user, "Enter new robot name", src.name, src.created_name), MAX_NAME_LEN) + if (!t) + return + if (!in_range(src, usr) && src.loc != usr) + return + + src.created_name = t + + return + +/obj/item/robot_parts/chest/attackby(obj/item/W as obj, mob/user as mob) + ..() + if(istype(W, /obj/item/weapon/cell)) + if(src.cell) + to_chat(user, "You have already inserted a cell!") + return + else + user.drop_item() + W.loc = src + src.cell = W + to_chat(user, "You insert the cell!") + if(isCoil(W)) + if(src.wires) + to_chat(user, "You have already inserted wire!") + return + else + var/obj/item/stack/cable_coil/coil = W + coil.use(1) + src.wires = 1.0 + to_chat(user, "You insert the wire!") + if(istype(W, /obj/item/robot_parts/head)) + var/obj/item/robot_parts/head/head_part = W + // Attempt to create full-body prosthesis. + var/success = TRUE + success &= can_install(user) + success &= head_part.can_install(user) + if (success) + + // Species selection. + var/species = input(user, "Select a species for the prosthetic.") as null|anything in GetCyborgSpecies() + if(!species) + return + var/name = sanitizeSafe(input(user,"Set a name for the new prosthetic."), MAX_NAME_LEN) + if(!name) + SetName("prosthetic ([random_id("prosthetic_id", 1, 999)])") + + // Create a new, nonliving human. + var/mob/living/carbon/human/H = new /mob/living/carbon/human(get_turf(loc)) + H.death(0, "no message") + H.set_species(species) + H.fully_replace_character_name(name) + + // Remove all external organs other than chest and head.. + for (var/O in list(BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG)) + var/obj/item/organ/external/organ = H.organs_by_name[O] + H.organs -= organ + H.organs_by_name[organ.organ_tag] = null + qdel(organ) + + // Remove brain (we want to put one in). + var/obj/item/organ/internal/brain = H.internal_organs_by_name[BP_BRAIN] + H.organs -= brain + H.organs_by_name[brain.organ_tag] = null + qdel(brain) + + // Robotize remaining organs: Eyes, head, and chest. + // Respect brand used. + var/obj/item/organ/internal/eyes = H.internal_organs_by_name[BP_EYES] + eyes.robotize() + + var/obj/item/organ/external/head = H.organs_by_name[BP_HEAD] + var/head_company = head_part.model_info + head.robotize(head_company) + + var/obj/item/organ/external/chest = H.organs_by_name[BP_CHEST] + var/chest_company = model_info + chest.robotize(chest_company) + + // Cleanup + qdel(W) + qdel(src) + return + +/obj/item/robot_parts/chest/proc/GetCyborgSpecies() + . = list() + for(var/N in playable_species) + var/datum/species/S = all_species[N] + if(S.spawn_flags & SPECIES_NO_FBP_CONSTRUCTION) + continue + . += N + +/obj/item/robot_parts/head/attackby(obj/item/W as obj, mob/user as mob) + ..() + if(istype(W, /obj/item/device/flash)) + if(istype(user,/mob/living/silicon/robot)) + var/current_module = user.get_active_hand() + if(current_module == W) + to_chat(user, "How do you propose to do that?") + return + else + add_flashes(W,user) + else + add_flashes(W,user) + else if(istype(W, /obj/item/weapon/stock_parts/manipulator)) + to_chat(user, "You install some manipulators and modify the head, creating a functional spider-bot!") + new /mob/living/simple_animal/spiderbot(get_turf(loc)) + user.drop_item() + qdel(W) + qdel(src) + return + return + +/obj/item/robot_parts/head/proc/add_flashes(obj/item/W as obj, mob/user as mob) //Made into a seperate proc to avoid copypasta + if(src.flash1 && src.flash2) + to_chat(user, "You have already inserted the eyes!") + return + else if(src.flash1) + user.drop_item() + W.loc = src + src.flash2 = W + to_chat(user, "You insert the flash into the eye socket!") + else + user.drop_item() + W.loc = src + src.flash1 = W + to_chat(user, "You insert the flash into the eye socket!") + + +/obj/item/robot_parts/emag_act(var/remaining_charges, var/mob/user) + if(sabotaged) + to_chat(user, "[src] is already sabotaged!") + else + to_chat(user, "You short out the safeties.") + sabotaged = 1 + return 1 diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm new file mode 100644 index 00000000..044c47fa --- /dev/null +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -0,0 +1,197 @@ +// robot_upgrades.dm +// Contains various borg upgrades. + +/obj/item/borg/upgrade + name = "borg upgrade module." + desc = "Protected by FRM." + icon = 'icons/obj/module.dmi' + icon_state = "cyborg_upgrade" + var/locked = 0 + var/require_module = 0 + var/installed = 0 + +/obj/item/borg/upgrade/proc/action(var/mob/living/silicon/robot/R) + if(R.stat == DEAD) + to_chat(usr, "The [src] will not function on a deceased robot.") + return 1 + return 0 + + +/obj/item/borg/upgrade/reset + name = "robotic module reset board" + desc = "Used to reset a cyborg's module. Destroys any other upgrades applied to the robot." + icon_state = "cyborg_upgrade1" + require_module = 1 + +/obj/item/borg/upgrade/reset/action(var/mob/living/silicon/robot/R) + if(..()) return 0 + R.uneq_all() + R.modtype = initial(R.modtype) + R.hands.icon_state = initial(R.hands.icon_state) + + R.notify_ai(ROBOT_NOTIFICATION_MODULE_RESET, R.module.name) + R.module.Reset(R) + qdel(R.module) + R.module = null + R.updatename("Default") + + return 1 + +/obj/item/borg/upgrade/rename + name = "robot reclassification board" + desc = "Used to rename a cyborg." + icon_state = "cyborg_upgrade1" + var/heldname = "default name" + +/obj/item/borg/upgrade/rename/attack_self(mob/user as mob) + heldname = sanitizeSafe(input(user, "Enter new robot name", "Robot Reclassification", heldname), MAX_NAME_LEN) + +/obj/item/borg/upgrade/rename/action(var/mob/living/silicon/robot/R) + if(..()) return 0 + R.notify_ai(ROBOT_NOTIFICATION_NEW_NAME, R.name, heldname) + R.SetName(heldname) + R.custom_name = heldname + R.real_name = heldname + + return 1 + +/obj/item/borg/upgrade/floodlight + name = "robot floodlight module" + desc = "Used to boost cyborg's light intensity." + icon_state = "cyborg_upgrade1" + +/obj/item/borg/upgrade/floodlight/action(var/mob/living/silicon/robot/R) + if(..()) return 0 + + if(R.intenselight) + to_chat(usr, "This cyborg's light was already upgraded") + return 0 + else + R.intenselight = 1 + R.update_robot_light() + to_chat(R, "Lighting systems upgrade detected.") + return 1 + +/obj/item/borg/upgrade/restart + name = "robot emergency restart module" + desc = "Used to force a restart of a disabled-but-repaired robot, bringing it back online." + icon_state = "cyborg_upgrade1" + + +/obj/item/borg/upgrade/restart/action(var/mob/living/silicon/robot/R) + if(R.health < 0) + to_chat(usr, "You have to repair the robot before using this module!") + return 0 + + if(!R.key) + for(var/mob/observer/ghost/ghost in GLOB.player_list) + if(ghost.mind && ghost.mind.current == R) + R.key = ghost.key + + R.set_stat(CONSCIOUS) + R.switch_from_dead_to_living_mob_list() + R.notify_ai(ROBOT_NOTIFICATION_NEW_UNIT) + return 1 + + +/obj/item/borg/upgrade/vtec + name = "robotic VTEC Module" + desc = "Used to kick in a robot's VTEC systems, increasing their speed." + icon_state = "cyborg_upgrade2" + require_module = 1 + +/obj/item/borg/upgrade/vtec/action(var/mob/living/silicon/robot/R) + if(..()) return 0 + + if(R.speed == -1) + return 0 + + R.speed-- + return 1 + + +/obj/item/borg/upgrade/tasercooler + name = "robotic Rapid Taser Cooling Module" + desc = "Used to cool a mounted taser, increasing the potential current in it and thus its recharge rate." + icon_state = "cyborg_upgrade3" + require_module = 1 + + +/obj/item/borg/upgrade/tasercooler/action(var/mob/living/silicon/robot/R) + if(..()) return 0 + + if(!R.module || !(type in R.module.supported_upgrades)) + to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") + to_chat(usr, "There's no mounting point for the module!") + return 0 + + var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in R.module + if(!T) + T = locate() in R.module.contents + if(!T) + T = locate() in R.module.modules + if(!T) + to_chat(usr, "This robot has had its taser removed!") + return 0 + + if(T.recharge_time <= 2) + to_chat(R, "Maximum cooling achieved for this hardpoint!") + to_chat(usr, "There's no room for another cooling unit!") + return 0 + + else + T.recharge_time = max(2 , T.recharge_time - 4) + + return 1 + +/obj/item/borg/upgrade/jetpack + name = "mining robot jetpack" + desc = "A carbon dioxide jetpack suitable for low-gravity mining operations." + icon_state = "cyborg_upgrade3" + require_module = 1 + +/obj/item/borg/upgrade/jetpack/action(var/mob/living/silicon/robot/R) + if(..()) return 0 + + if(!R.module || !(type in R.module.supported_upgrades)) + to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") + to_chat(usr, "There's no mounting point for the module!") + return 0 + else + R.module.modules += new/obj/item/weapon/tank/jetpack/carbondioxide + for(var/obj/item/weapon/tank/jetpack/carbondioxide in R.module.modules) + R.internals = src + //R.icon_state="Miner+j" + return 1 + +/obj/item/borg/upgrade/rcd + name = "engineering robot RCD" + desc = "A rapid construction device module for use during construction operations." + icon_state = "cyborg_upgrade3" + require_module = 1 + +/obj/item/borg/upgrade/rcd/action(var/mob/living/silicon/robot/R) + if(..()) return 0 + + if(!R.module || !(type in R.module.supported_upgrades)) + to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") + to_chat(usr, "There's no mounting point for the module!") + return 0 + else + R.module.modules += new/obj/item/weapon/rcd/borg(R.module) + return 1 + +/obj/item/borg/upgrade/syndicate/ + name = "illegal equipment module" + desc = "Unlocks the hidden, deadlier functions of a robot." + icon_state = "cyborg_upgrade3" + require_module = 1 + +/obj/item/borg/upgrade/syndicate/action(var/mob/living/silicon/robot/R) + if(..()) return 0 + + if(R.emagged == 1) + return 0 + + R.emagged = 1 + return 1 diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm new file mode 100644 index 00000000..b6198b78 --- /dev/null +++ b/code/game/objects/items/shooting_range.dm @@ -0,0 +1,182 @@ +// Targets, the things that actually get shot! +/obj/item/target + name = "shooting target" + desc = "A shooting target." + icon = 'icons/obj/objects.dmi' + icon_state = "target_h" + density = 0 + var/hp = 1800 + var/icon/virtualIcon + var/list/bulletholes = list() + + Destroy() + // if a target is deleted and associated with a stake, force stake to forget + for(var/obj/structure/target_stake/T in view(3,src)) + if(T.pinned_target == src) + T.pinned_target = null + T.set_density(1) + break + ..() // delete target + + Move() + ..() + // After target moves, check for nearby stakes. If associated, move to target + for(var/obj/structure/target_stake/M in view(3,src)) + if(M.density == 0 && M.pinned_target == src) + M.loc = loc + + // This may seem a little counter-intuitive but I assure you that's for a purpose. + // Stakes are the ones that carry targets, yes, but in the stake code we set + // a stake's density to 0 meaning it can't be pushed anymore. Instead of pushing + // the stake now, we have to push the target. + + + + attackby(obj/item/W as obj, mob/user as mob) + if(isWelder(W)) + var/obj/item/weapon/weldingtool/WT = W + if(WT.remove_fuel(0, user)) + overlays.Cut() + to_chat(usr, "You slice off [src]'s uneven chunks of aluminum and scorch marks.") + return + + + attack_hand(mob/user as mob) + // taking pinned targets off! + var/obj/structure/target_stake/stake + for(var/obj/structure/target_stake/T in view(3,src)) + if(T.pinned_target == src) + stake = T + break + + if(stake) + if(stake.pinned_target) + stake.set_density(1) + set_density(0) + layer = OBJ_LAYER + + forceMove(user.loc) + if(ishuman(user)) + if(!user.get_active_hand()) + user.put_in_hands(src) + to_chat(user, "You take the target out of the stake.") + else + src.loc = get_turf(user) + to_chat(user, "You take the target out of the stake.") + + stake.pinned_target = null + return + + else + ..() + + syndicate + icon_state = "target_s" + desc = "A shooting target that looks like a hostile agent." + hp = 2600 // i guess syndie targets are sturdier? + alien + icon_state = "target_q" + desc = "A shooting target with a threatening silhouette." + hp = 2350 // alium onest too kinda + +/obj/item/target/bullet_act(var/obj/item/projectile/Proj) + var/p_x = Proj.p_x + pick(0,0,0,0,0,-1,1) // really ugly way of coding "sometimes offset Proj.p_x!" + var/p_y = Proj.p_y + pick(0,0,0,0,0,-1,1) + var/decaltype = 1 // 1 - scorch, 2 - bullet + + if(istype(/obj/item/projectile/bullet, Proj)) + decaltype = 2 + + + virtualIcon = new(icon, icon_state) + + if( virtualIcon.GetPixel(p_x, p_y) ) // if the located pixel isn't blank (null) + + hp -= Proj.damage + if(hp <= 0) + for(var/mob/O in oviewers()) + if ((O.client && !( O.blinded ))) + to_chat(O, "\The [src] breaks into tiny pieces and collapses!") + qdel(src) + + // Create a temporary object to represent the damage + var/obj/bmark = new + bmark.pixel_x = p_x + bmark.pixel_y = p_y + bmark.icon = 'icons/effects/effects.dmi' + bmark.plane = OBJ_PLANE + bmark.layer = ABOVE_OBJ_LAYER + bmark.icon_state = "scorch" + + if(decaltype == 1) + // Energy weapons are hot. they scorch! + + // offset correction + bmark.pixel_x-- + bmark.pixel_y-- + + if(Proj.damage >= 20 || istype(Proj, /obj/item/projectile/beam/practice)) + bmark.icon_state = "scorch" + bmark.set_dir(pick(NORTH,SOUTH,EAST,WEST)) // random scorch design + + + else + bmark.icon_state = "light_scorch" + else + + // Bullets are hard. They make dents! + bmark.icon_state = "dent" + + if(Proj.damage >= 10 && bulletholes.len <= 35) // maximum of 35 bullet holes + if(decaltype == 2) // bullet + if(prob(Proj.damage+30)) // bullets make holes more commonly! + new/datum/bullethole(src, bmark.pixel_x, bmark.pixel_y) // create new bullet hole + else // Lasers! + if(prob(Proj.damage-10)) // lasers make holes less commonly + new/datum/bullethole(src, bmark.pixel_x, bmark.pixel_y) // create new bullet hole + + // draw bullet holes + for(var/datum/bullethole/B in bulletholes) + + virtualIcon.DrawBox(null, B.b1x1, B.b1y, B.b1x2, B.b1y) // horizontal line, left to right + virtualIcon.DrawBox(null, B.b2x, B.b2y1, B.b2x, B.b2y2) // vertical line, top to bottom + + overlays += bmark // add the decal + + icon = virtualIcon // apply bulletholes over decals + + return + + return PROJECTILE_CONTINUE // the bullet/projectile goes through the target! + + +// Small memory holder entity for transparent bullet holes +/datum/bullethole + // First box + var/b1x1 = 0 + var/b1x2 = 0 + var/b1y = 0 + + // Second box + var/b2x = 0 + var/b2y1 = 0 + var/b2y2 = 0 + + New(var/obj/item/target/Target, var/pixel_x = 0, var/pixel_y = 0) + if(!Target) return + + // Randomize the first box + b1x1 = pixel_x - pick(1,1,1,1,2,2,3,3,4) + b1x2 = pixel_x + pick(1,1,1,1,2,2,3,3,4) + b1y = pixel_y + if(prob(35)) + b1y += rand(-4,4) + + // Randomize the second box + b2x = pixel_x + if(prob(35)) + b2x += rand(-4,4) + b2y1 = pixel_y + pick(1,1,1,1,2,2,3,3,4) + b2y2 = pixel_y - pick(1,1,1,1,2,2,3,3,4) + + Target.bulletholes.Add(src) diff --git a/code/game/objects/items/stacks/matter_synth.dm b/code/game/objects/items/stacks/matter_synth.dm new file mode 100644 index 00000000..b18cd330 --- /dev/null +++ b/code/game/objects/items/stacks/matter_synth.dm @@ -0,0 +1,61 @@ +/datum/matter_synth + var/name = "Generic Synthesizer" + var/max_energy = 60000 + var/recharge_rate = 2000 + var/max_energy_multiplied = 60000 + var/multiplier = 1 // Robot may be upgraded with better matter bin to multiply capacity of it's synthetisers + var/energy + +/datum/matter_synth/New(var/store = 0) + if(store) + max_energy = store + energy = max_energy_multiplied + set_multiplier(1) + return + +/datum/matter_synth/proc/get_charge() + return energy + +/datum/matter_synth/proc/use_charge(var/amount) + if (energy >= amount) + energy -= amount + return 1 + return 0 + +/datum/matter_synth/proc/add_charge(var/amount) + energy = min(energy + amount, max_energy_multiplied) + +/datum/matter_synth/proc/emp_act(var/severity) + use_charge(max_energy_multiplied * 0.1 / severity) + +/datum/matter_synth/proc/set_multiplier(var/new_multiplier) + multiplier = new_multiplier + max_energy_multiplied = max_energy * multiplier + energy = min(max_energy_multiplied, energy) + +/datum/matter_synth/medicine + name = "Medicine Synthesizer" + +/datum/matter_synth/nanite + name = "Nanite Synthesizer" + +/datum/matter_synth/metal + name = "Metal Synthesizer" + +/datum/matter_synth/plasteel + name = "Plasteel Synthesizer" + max_energy = 10000 + +/datum/matter_synth/glass + name = "Glass Synthesizer" + +/datum/matter_synth/wood + name = "Wood Synthesizer" + +/datum/matter_synth/plastic + name = "Plastic Synthesizer" + +/datum/matter_synth/wire + name = "Wire Synthesizer" + max_energy = 50 + recharge_rate = 2 \ No newline at end of file diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm new file mode 100644 index 00000000..46026c96 --- /dev/null +++ b/code/game/objects/items/stacks/medical.dm @@ -0,0 +1,293 @@ +/obj/item/stack/medical + name = "medical pack" + singular_name = "medical pack" + icon = 'icons/obj/items.dmi' + amount = 10 + max_amount = 10 + w_class = ITEM_SIZE_SMALL + throw_speed = 4 + throw_range = 20 + var/heal_brute = 0 + var/heal_burn = 0 + var/animal_heal = 3 + var/apply_sounds + +/obj/item/stack/medical/attack(mob/living/carbon/M as mob, mob/user as mob) + if (!istype(M)) + to_chat(user, "\The [src] cannot be applied to [M]!") + return 1 + + if ( ! (istype(user, /mob/living/carbon/human) || \ + istype(user, /mob/living/silicon)) ) + to_chat(user, "You don't have the dexterity to do this!") + return 1 + + if (istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) + + if(!affecting) + to_chat(user, "\The [M] is missing that body part!") + return 1 + + if(affecting.organ_tag == BP_HEAD) + if(H.head && istype(H.head,/obj/item/clothing/head/helmet/space)) + to_chat(user, "You can't apply [src] through [H.head]!") + return 1 + else + if(H.wear_suit && istype(H.wear_suit,/obj/item/clothing/suit/space)) + to_chat(user, "You can't apply [src] through [H.wear_suit]!") + return 1 + + if(affecting.robotic >= ORGAN_ROBOT) + to_chat(user, "This isn't useful at all on a robotic limb..") + return 1 + + H.UpdateDamageIcon() + + else + + M.heal_organ_damage((src.heal_brute/2), (src.heal_burn/2)) + user.visible_message( \ + "[M] has been applied with [src] by [user].", \ + "You apply \the [src] to [M]." \ + ) + use(1) + + M.updatehealth() +/obj/item/stack/medical/bruise_pack + name = "roll of gauze" + singular_name = "gauze length" + desc = "Some sterile gauze to wrap around bloody stumps." + icon_state = "brutepack" + origin_tech = list(TECH_BIO = 1) + animal_heal = 5 + apply_sounds = list('sound/effects/rip1.ogg','sound/effects/rip2.ogg') + +/obj/item/stack/medical/bruise_pack/attack(mob/living/carbon/M as mob, mob/living/carbon/human/user as mob) + if(..()) + return 1 + + if (istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) //nullchecked by ..() + + if(affecting.is_bandaged()) + to_chat(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.bandaged) + continue + if(used == amount) + break + if(!do_mob(user, M, backwards_skill_scale(user.SKILL_LEVEL(medical)) * 5))//W.damage/5)) + to_chat(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]." ) + //H.add_side_effect("Itch") + else if (W.damage_type == 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]." ) + 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() + playsound(src, pick(apply_sounds), 25) + used++ + affecting.update_damages() + if(used == amount) + if(affecting.is_bandaged()) + to_chat(user, "\The [src] is used up.") + else + to_chat(user, "\The [src] is used up, but there are more wounds to treat on \the [affecting.name].") + use(used) + H.update_bandages(1) + +/obj/item/stack/medical/ointment + name = "ointment" + desc = "Used to treat those nasty burns." + gender = PLURAL + singular_name = "ointment" + icon_state = "ointment" + heal_burn = 1 + origin_tech = list(TECH_BIO = 1) + animal_heal = 4 + apply_sounds = list('sound/effects/ointment.ogg') + +/obj/item/stack/medical/ointment/attack(mob/living/carbon/M as mob, mob/living/carbon/human/user as mob) + if(..()) + return 1 + + if (istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) //nullchecked by ..() + + if(affecting.is_salved()) + to_chat(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, backwards_skill_scale(user.SKILL_LEVEL(medical)) * 5)) + to_chat(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]." ) + playsound(src, pick(apply_sounds), 25) + use(1) + affecting.salve() + +/obj/item/stack/medical/advanced/bruise_pack + name = "advanced trauma kit" + singular_name = "advanced trauma kit" + desc = "An advanced trauma kit for severe injuries." + icon_state = "traumakit" + heal_brute = 0 + origin_tech = list(TECH_BIO = 1) + animal_heal = 12 + apply_sounds = list('sound/effects/rip1.ogg','sound/effects/rip2.ogg','sound/effects/tape.ogg') + +/obj/item/stack/medical/advanced/bruise_pack/attack(mob/living/carbon/M as mob, mob/user as mob) + if(..()) + return 1 + + if (istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) //nullchecked by ..() + if(affecting.is_bandaged() && affecting.is_disinfected()) + to_chat(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.bandaged && W.disinfected) + continue + if(used == amount) + break + if(!do_mob(user, M, backwards_skill_scale(user.SKILL_LEVEL(medical)) * 5)) + to_chat(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]." ) + else if (W.damage_type == 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]." ) + 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]." ) + playsound(src, pick(apply_sounds), 25) + W.bandage() + W.disinfect() + W.heal_damage(heal_brute) + used++ + affecting.update_damages() + if(used == amount) + if(affecting.is_bandaged()) + to_chat(user, "\The [src] is used up.") + else + to_chat(user, "\The [src] is used up, but there are more wounds to treat on \the [affecting.name].") + use(used) + H.update_bandages(1) + +/obj/item/stack/medical/advanced/ointment + name = "advanced burn kit" + singular_name = "advanced burn kit" + desc = "An advanced treatment kit for severe burns." + icon_state = "burnkit" + heal_burn = 0 + origin_tech = list(TECH_BIO = 1) + animal_heal = 7 + apply_sounds = list('sound/effects/ointment.ogg') + + +/obj/item/stack/medical/advanced/ointment/attack(mob/living/carbon/M as mob, mob/living/carbon/human/user as mob) + if(..()) + return 1 + + if (istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) //nullchecked by ..() + + if(affecting.is_salved()) + to_chat(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, backwards_skill_scale(user.SKILL_LEVEL(medical)) * 5)) + to_chat(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." ) + playsound(src, pick(apply_sounds), 25) + affecting.heal_damage(0,heal_burn) + use(1) + affecting.salve() + +/obj/item/stack/medical/splint + name = "medical splints" + singular_name = "medical splint" + desc = "Modular splints capable of supporting and immobilizing bones in both limbs and appendages." + icon_state = "splint" + amount = 10 + max_amount = 10 + animal_heal = 0 + var/list/splintable_organs = list(BP_HEAD, BP_CHEST, BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG, BP_L_HAND, BP_R_HAND, BP_L_FOOT, BP_R_FOOT) //List of organs you can splint, natch. + +/obj/item/stack/medical/splint/attack(mob/living/carbon/M as mob, mob/living/carbon/human/user as mob) + if(..()) + return 1 + + if (istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) //nullchecked by ..() + var/limb = affecting.name + if(!(affecting.organ_tag in splintable_organs)) + to_chat(user, "You can't use \the [src] to apply a splint there!") + return + if(affecting.splinted) + to_chat(user, "[M]'s [limb] is already splinted!") + return + if (M != user) + user.visible_message("[user] starts to apply \the [src] to [M]'s [limb].", "You start to apply \the [src] to [M]'s [limb].", "You hear something being wrapped.") + else + if(( !user.hand && (affecting.organ_tag in list(BP_R_ARM, BP_R_HAND)) || \ + user.hand && (affecting.organ_tag in list(BP_L_ARM, BP_L_HAND)) )) + to_chat(user, "You can't apply a splint to the arm you're using!") + return + user.visible_message("[user] starts to apply \the [src] to their [limb].", "You start to apply \the [src] to your [limb].", "You hear something being wrapped.") + if(do_after(user, backwards_skill_scale(user.SKILL_LEVEL(medical)) * 5, M)) + if(M == user && prob(75)) + user.visible_message("\The [user] fumbles [src].", "You fumble [src].", "You hear something being wrapped.") + return + var/obj/item/stack/medical/splint/S = split(1) + if(S) + if(affecting.apply_splint(S)) + S.forceMove(affecting) + if (M != user) + user.visible_message("\The [user] finishes applying [src] to [M]'s [limb].", "You finish applying \the [src] to [M]'s [limb].", "You hear something being wrapped.") + else + user.visible_message("\The [user] successfully applies [src] to their [limb].", "You successfully apply \the [src] to your [limb].", "You hear something being wrapped.") + return + S.dropInto(src.loc) //didn't get applied, so just drop it + user.visible_message("\The [user] fails to apply [src].", "You fail to apply [src].", "You hear something being wrapped.") + return + + +/obj/item/stack/medical/splint/ghetto + name = "makeshift splints" + singular_name = "makeshift splint" + desc = "For holding your limbs in place with duct tape and scrap metal." + icon_state = "tape-splint" + amount = 1 + splintable_organs = list(BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG) diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm new file mode 100644 index 00000000..22b3fba8 --- /dev/null +++ b/code/game/objects/items/stacks/nanopaste.dm @@ -0,0 +1,43 @@ +/obj/item/stack/nanopaste + name = "nanopaste" + singular_name = "nanite swarm" + desc = "A tube of paste containing swarms of repair nanites. Very effective in repairing robotic machinery." + icon = 'icons/obj/nanopaste.dmi' + icon_state = "tube" + origin_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 3) + amount = 10 + + +/obj/item/stack/nanopaste/attack(mob/living/M as mob, mob/user as mob) + if (!istype(M) || !istype(user)) + return 0 + if (istype(M,/mob/living/silicon/robot)) //Repairing cyborgs + var/mob/living/silicon/robot/R = M + if (R.getBruteLoss() || R.getFireLoss() ) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + R.adjustBruteLoss(-15) + R.adjustFireLoss(-15) + R.updatehealth() + use(1) + user.visible_message("\The [user] applied some [src] on [R]'s damaged areas.",\ + "You apply some [src] at [R]'s damaged areas.") + else + to_chat(user, "All [R]'s systems are nominal.") + + if (istype(M,/mob/living/carbon/human)) //Repairing robolimbs + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/S = H.get_organ(user.zone_sel.selecting) + + if(!S) + to_chat(user, "\The [M] is missing that body part.") + + if(S && S.robotic >= ORGAN_ROBOT && S.hatch_state == HATCH_OPENED) + if(!S.get_damage()) + to_chat(user, "Nothing to fix here.") + else if(can_use(1)) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + S.heal_damage(15, 15, robo_repair = 1) + H.updatehealth() + use(1) + user.visible_message("\The [user] applies some nanite paste on [user != M ? "[M]'s [S.name]" : "[S]"] with [src].",\ + "You apply some nanite paste on [user == M ? "your" : "[M]'s"] [S.name].") diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm new file mode 100644 index 00000000..b932a4da --- /dev/null +++ b/code/game/objects/items/stacks/rods.dm @@ -0,0 +1,117 @@ +/obj/item/stack/rods + name = "metal rod" + desc = "Some rods. Can be used for building, or something." + singular_name = "metal rod" + icon_state = "rods" + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_LARGE + force = 9.0 + throwforce = 15.0 + throw_speed = 5 + throw_range = 20 + matter = list(DEFAULT_WALL_MATERIAL = 1875) + max_amount = 100 + center_of_mass = null + attack_verb = list("hit", "bludgeoned", "whacked") + lock_picking_level = 3 + +/obj/item/stack/rods/ten + amount = 10 + +/obj/item/stack/rods/fifty + amount = 50 + +/obj/item/stack/rods/cyborg + name = "metal rod synthesizer" + desc = "A device that makes metal rods." + gender = NEUTER + matter = null + uses_charge = 1 + charge_costs = list(500) + stacktype = /obj/item/stack/rods + +/obj/item/stack/rods/New() + ..() + update_icon() + +/obj/item/stack/rods/attackby(obj/item/W as obj, mob/user as mob) + if(isWelder(W)) + var/obj/item/weapon/weldingtool/WT = W + + if(get_amount() < 2) + to_chat(user, "You need at least two rods to do this.") + return + + if(WT.remove_fuel(0,user)) + var/obj/item/stack/material/steel/new_item = new(usr.loc) + new_item.add_to_stacks(usr) + for (var/mob/M in viewers(src)) + M.show_message("[src] is shaped into metal by [user.name] with the weldingtool.", 3, "You hear welding.", 2) + var/obj/item/stack/rods/R = src + src = null + var/replace = (user.get_inactive_hand()==R) + R.use(2) + if (!R && replace) + user.put_in_hands(new_item) + return + + if (istype(W, /obj/item/weapon/tape_roll)) + var/obj/item/stack/medical/splint/ghetto/new_splint = new(user.loc) + new_splint.dropInto(loc) + new_splint.add_fingerprint(user) + + user.visible_message("\The [user] constructs \a [new_splint] out of a [singular_name].", \ + "You use make \a [new_splint] out of a [singular_name].") + src.use(1) + return + + ..() + + +/obj/item/stack/rods/attack_self(mob/user as mob) + src.add_fingerprint(user) + + if(!istype(user.loc,/turf)) return 0 + + if (locate(/obj/structure/grille, usr.loc)) + for(var/obj/structure/grille/G in usr.loc) + if (G.destroyed) + G.health = 10 + G.set_density(1) + G.destroyed = 0 + G.icon_state = "grille" + use(1) + else + return 1 + + else if(!in_use) + if(get_amount() < 2) + to_chat(user, "You need at least two rods to do this.") + return + to_chat(usr, "Assembling grille...") + in_use = 1 + if (!do_after(usr, 10)) + in_use = 0 + return + var/obj/structure/grille/F = new /obj/structure/grille/ ( usr.loc ) + to_chat(usr, "You assemble a grille") + in_use = 0 + F.add_fingerprint(usr) + use(2) + return + +/obj/item/stack/rods/update_icon() + if(amount == 1) + icon = 'icons/obj/weapons.dmi' + icon_state = "metal-rod" + else + icon = initial(icon) + icon_state = initial(icon_state) + +/obj/item/stack/rods/use() + . = ..() + update_icon() + +/obj/item/stack/rods/add() + . = ..() + update_icon() \ No newline at end of file diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm new file mode 100644 index 00000000..7b6e8578 --- /dev/null +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -0,0 +1,173 @@ +/* Glass stack types + * Contains: + * Glass sheets + * Reinforced glass sheets + * Phoron Glass Sheets + * Reinforced Phoron Glass Sheets (AKA Holy fuck strong windows) + * Glass shards - TODO: Move this into code/game/object/item/weapons + */ + +/* + * Glass sheets + */ +/obj/item/stack/material/glass + name = "glass" + singular_name = "glass sheet" + icon_state = "sheet-glass" + var/created_window = /obj/structure/window/basic + var/is_reinforced = 0 + var/list/construction_options = list("One Direction", "Full Window") + default_type = "glass" + +/obj/item/stack/material/glass/attack_self(mob/user as mob) + construct_window(user) + +/obj/item/stack/material/glass/attackby(obj/item/W, mob/user) + ..() + if(!is_reinforced) + if(istype(W,/obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/CC = W + if (get_amount() < 1 || CC.get_amount() < 5) + to_chat(user, "You need five lengths of coil and one sheet of glass to make wired glass.") + return + + CC.use(5) + use(1) + to_chat(user, "You attach wire to the [name].") + new /obj/item/stack/light_w(user.loc) + else if(istype(W, /obj/item/stack/rods)) + var/obj/item/stack/rods/V = W + if (V.get_amount() < 1 || get_amount() < 1) + to_chat(user, "You need one rod and one sheet of glass to make reinforced glass.") + return + + var/obj/item/stack/material/glass/reinforced/RG = new (user.loc) + RG.add_to_stacks(user) + var/obj/item/stack/material/glass/G = src + src = null + var/replace = (user.get_inactive_hand()==G) + V.use(1) + G.use(1) + if (!G && replace) + user.put_in_hands(RG) + +/obj/item/stack/material/glass/proc/construct_window(mob/user as mob) + if(!user || !src) return 0 + if(!istype(user.loc,/turf)) return 0 + if(!user.IsAdvancedToolUser()) + return 0 + var/title = "Sheet-[name]" + title += " ([src.get_amount()] sheet\s left)" + switch(input(title, "What would you like to construct?") as null|anything in construction_options) + if("One Direction") + if(!src) return 1 + if(src.loc != user) return 1 + + var/list/directions = new/list(cardinal) + var/i = 0 + for (var/obj/structure/window/win in user.loc) + i++ + if(i >= 4) + to_chat(user, "There are too many windows in this location.") + return 1 + directions-=win.dir + if(!(win.dir in cardinal)) + to_chat(user, "Can't let you do that.") + return 1 + + //Determine the direction. It will first check in the direction the person making the window is facing, if it finds an already made window it will try looking at the next cardinal direction, etc. + var/dir_to_set = 2 + for(var/direction in list( user.dir, turn(user.dir,90), turn(user.dir,180), turn(user.dir,270) )) + var/found = 0 + for(var/obj/structure/window/WT in user.loc) + if(WT.dir == direction) + found = 1 + if(!found) + dir_to_set = direction + break + new created_window( user.loc, dir_to_set, 1 ) + src.use(1) + if("Full Window") + if(!src) return 1 + if(src.loc != user) return 1 + if(src.get_amount() < 4) + to_chat(user, "You need more glass to do that.") + return 1 + if(locate(/obj/structure/window) in user.loc) + to_chat(user, "There is a window in the way.") + return 1 + new created_window( user.loc, SOUTHWEST, 1 ) + src.use(4) + if("Windoor") + if(!is_reinforced) return 1 + + + if(!src || src.loc != user) return 1 + + if(isturf(user.loc) && locate(/obj/structure/windoor_assembly/, user.loc)) + to_chat(user, "There is already a windoor assembly in that location.") + return 1 + + if(isturf(user.loc) && locate(/obj/machinery/door/window/, user.loc)) + to_chat(user, "There is already a windoor in that location.") + return 1 + + if(src.get_amount() < 5) + to_chat(user, "You need more glass to do that.") + return 1 + + new /obj/structure/windoor_assembly(user.loc, user.dir, 1) + src.use(5) + + return 0 + + +/* + * Reinforced glass sheets + */ +/obj/item/stack/material/glass/reinforced + name = "reinforced glass" + singular_name = "reinforced glass sheet" + icon_state = "sheet-rglass" + default_type = "reinforced glass" + created_window = /obj/structure/window/reinforced + is_reinforced = 1 + construction_options = list("One Direction", "Full Window", "Windoor") + +/* + * Phoron Glass sheets + */ +/obj/item/stack/material/glass/phoronglass + name = "phoron glass" + singular_name = "phoron glass sheet" + icon_state = "sheet-phoronglass" + created_window = /obj/structure/window/phoronbasic + default_type = "phoron glass" + +/obj/item/stack/material/glass/phoronglass/attackby(obj/item/W, mob/user) + ..() + if( istype(W, /obj/item/stack/rods) ) + var/obj/item/stack/rods/V = W + var/obj/item/stack/material/glass/phoronrglass/RG = new (user.loc) + RG.add_fingerprint(user) + RG.add_to_stacks(user) + V.use(1) + var/obj/item/stack/material/glass/G = src + src = null + var/replace = (user.get_inactive_hand()==G) + G.use(1) + if (!G && !RG && replace) + user.put_in_hands(RG) + else + return ..() + +/* + * Reinforced phoron glass sheets + */ +/obj/item/stack/material/glass/phoronrglass + name = "reinforced phoron glass" + singular_name = "reinforced phoron glass sheet" + icon_state = "sheet-phoronrglass" + default_type = "reinforced phoron glass" + created_window = /obj/structure/window/phoronreinforced + is_reinforced = 1 diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm new file mode 100644 index 00000000..4542ac07 --- /dev/null +++ b/code/game/objects/items/stacks/sheets/leather.dm @@ -0,0 +1,115 @@ +/obj/item/stack/material/animalhide/human + name = "human skin" + desc = "The by-product of human farming." + singular_name = "human skin piece" + icon_state = "sheet-hide" + +/obj/item/stack/material/animalhide/corgi + name = "corgi hide" + desc = "The by-product of corgi farming." + singular_name = "corgi hide piece" + icon_state = "sheet-corgi" + +/obj/item/stack/material/animalhide/cat + name = "cat hide" + desc = "The by-product of cat farming." + singular_name = "cat hide piece" + icon_state = "sheet-cat" + +/obj/item/stack/material/animalhide/monkey + name = "monkey hide" + desc = "The by-product of monkey farming." + singular_name = "monkey hide piece" + icon_state = "sheet-monkey" + +/obj/item/stack/material/animalhide/lizard + name = "lizard skin" + desc = "Sssssss..." + singular_name = "lizard skin piece" + icon_state = "sheet-lizard" + +/obj/item/stack/material/animalhide/xeno + name = "alien hide" + desc = "The skin of a terrible creature." + singular_name = "alien hide piece" + icon_state = "sheet-xeno" + +//don't see anywhere else to put these, maybe together they could be used to make the xenos suit? +/obj/item/stack/material/xenochitin + name = "alien chitin" + desc = "A piece of the hide of a terrible creature." + singular_name = "alien hide piece" + icon = 'icons/mob/alien.dmi' + icon_state = "chitin" + +/obj/item/xenos_claw + name = "alien claw" + desc = "The claw of a terrible creature." + icon = 'icons/mob/alien.dmi' + icon_state = "claw" + +/obj/item/weed_extract + name = "weed extract" + desc = "A piece of slimy, purplish weed." + icon = 'icons/mob/alien.dmi' + icon_state = "weed_extract" + +/obj/item/stack/material/hairlesshide + name = "hairless hide" + desc = "This hide was stripped of it's hair, but still needs tanning." + singular_name = "hairless hide piece" + icon_state = "sheet-hairlesshide" + +/obj/item/stack/material/wetleather + name = "wet leather" + desc = "This leather has been cleaned but still needs to be dried." + singular_name = "wet leather piece" + icon_state = "sheet-wetleather" + var/wetness = 30 //Reduced when exposed to high temperautres + var/drying_threshold_temperature = 500 //Kelvin to start drying + +//Step one - dehairing. +/obj/item/stack/material/animalhide/attackby(obj/item/weapon/W as obj, mob/user as mob) + if( istype(W, /obj/item/weapon/material/knife) || \ + istype(W, /obj/item/weapon/material/kitchen/utensil/knife) || \ + istype(W, /obj/item/weapon/material/twohanded/fireaxe) || \ + istype(W, /obj/item/weapon/material/hatchet) ) + + //visible message on mobs is defined as visible_message(var/message, var/self_message, var/blind_message) + usr.visible_message("\The [usr] starts cutting hair off \the [src]", "You start cutting the hair off \the [src]", "You hear the sound of a knife rubbing against flesh") + if(do_after(user,50)) + to_chat(usr, "You cut the hair from this [src.singular_name]") + //Try locating an exisitng stack on the tile and add to there if possible + for(var/obj/item/stack/material/hairlesshide/HS in usr.loc) + if(HS.amount < 50) + HS.amount++ + src.use(1) + break + //If it gets to here it means it did not find a suitable stack on the tile. + var/obj/item/stack/material/hairlesshide/HS = new(usr.loc) + HS.amount = 1 + src.use(1) + else + ..() + + +//Step two - washing..... it's actually in washing machine code. + +//Step three - drying +/obj/item/stack/material/wetleather/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + ..() + if(exposed_temperature >= drying_threshold_temperature) + wetness-- + if(wetness == 0) + //Try locating an exisitng stack on the tile and add to there if possible + for(var/obj/item/stack/material/leather/HS in src.loc) + if(HS.amount < 50) + HS.amount++ + src.use(1) + wetness = initial(wetness) + break + //If it gets to here it means it did not find a suitable stack on the tile. + var/obj/item/stack/material/leather/HS = new(src.loc) + HS.amount = 1 + wetness = initial(wetness) + src.use(1) diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm new file mode 100644 index 00000000..ca3084d5 --- /dev/null +++ b/code/game/objects/items/stacks/stack.dm @@ -0,0 +1,374 @@ +/* Stack type objects! + * Contains: + * Stacks + * Recipe datum + * Recipe list datum + */ + +/* + * Stacks + */ + +/obj/item/stack + gender = PLURAL + origin_tech = list(TECH_MATERIAL = 1) + var/list/datum/stack_recipe/recipes + var/singular_name + var/amount = 1 + var/max_amount //also see stack recipes initialisation, param "max_res_amount" must be equal to this max_amount + var/stacktype //determines whether different stack types can merge + var/build_type = null //used when directly applied to a turf + var/uses_charge = 0 + var/list/charge_costs = null + var/list/datum/matter_synth/synths = null + +/obj/item/stack/New(var/loc, var/amount=null) + ..() + if (!stacktype) + stacktype = type + if (amount) + src.amount = amount + +/obj/item/stack/Destroy() + if(uses_charge) + return 1 + if (src && usr && usr.machine == src) + usr << browse(null, "window=stack") + return ..() + +/obj/item/stack/examine(mob/user) + if(..(user, 1)) + if(!uses_charge) + to_chat(user, "There [src.amount == 1 ? "is" : "are"] [src.amount] [src.singular_name]\s in the stack.") + else + to_chat(user, "There is enough charge for [get_amount()].") + +/obj/item/stack/attack_self(mob/user as mob) + list_recipes(user) + +/obj/item/stack/proc/list_recipes(mob/user as mob, recipes_sublist) + if (!recipes) + return + if (!src || get_amount() <= 0) + user << browse(null, "window=stack") + user.set_machine(src) //for correct work of onclose + var/list/recipe_list = recipes + if (recipes_sublist && recipe_list[recipes_sublist] && istype(recipe_list[recipes_sublist], /datum/stack_recipe_list)) + var/datum/stack_recipe_list/srl = recipe_list[recipes_sublist] + recipe_list = srl.recipes + var/t1 = text("Constructions from []Amount Left: []
            ", src, src.get_amount()) + for(var/i=1;i<=recipe_list.len,i++) + var/E = recipe_list[i] + if (isnull(E)) + t1 += "
            " + continue + + if (i>1 && !isnull(recipe_list[i-1])) + t1+="
            " + + if (istype(E, /datum/stack_recipe_list)) + var/datum/stack_recipe_list/srl = E + t1 += "[srl.title]" + + if (istype(E, /datum/stack_recipe)) + var/datum/stack_recipe/R = E + var/max_multiplier = round(src.get_amount() / R.req_amount) + var/title + var/can_build = 1 + can_build = can_build && (max_multiplier>0) + if (R.res_amount>1) + title+= "[R.res_amount]x [R.title]\s" + else + title+= "[R.title]" + title+= " ([R.req_amount] [src.singular_name]\s)" + if (can_build) + t1 += text("[title] ") + else + t1 += text("[]", title) + continue + if (R.max_res_amount>1 && max_multiplier>1) + max_multiplier = min(max_multiplier, round(R.max_res_amount/R.res_amount)) + t1 += " |" + var/list/multipliers = list(5,10,25) + for (var/n in multipliers) + if (max_multiplier>=n) + t1 += " [n*R.res_amount]x" + if (!(max_multiplier in multipliers)) + t1 += " [max_multiplier*R.res_amount]x" + + t1 += "
            " + user << browse(t1, "window=stack") + onclose(user, "stack") + return + +/obj/item/stack/proc/produce_recipe(datum/stack_recipe/recipe, var/quantity, mob/user) + var/required = quantity*recipe.req_amount + var/produced = min(quantity*recipe.res_amount, recipe.max_res_amount) + + if (!can_use(required)) + if (produced>1) + to_chat(user, "You haven't got enough [src] to build \the [produced] [recipe.title]\s!") + else + to_chat(user, "You haven't got enough [src] to build \the [recipe.title]!") + return + + if (recipe.one_per_turf && (locate(recipe.result_type) in user.loc)) + to_chat(user, "There is another [recipe.title] here!") + return + + if (recipe.on_floor && !isfloor(user.loc)) + to_chat(user, "\The [recipe.title] must be constructed on the floor!") + return + + if (recipe.time) + to_chat(user, "Building [recipe.title] ...") + if (!do_after(user, recipe.time)) + return + + if (use(required)) + var/atom/O + if(recipe.use_material) + O = new recipe.result_type(user.loc, recipe.use_material) + else + O = new recipe.result_type(user.loc) + O.set_dir(user.dir) + O.add_fingerprint(user) + + if (recipe.goes_in_hands) + user.put_in_hands(O) + + if (istype(O, /obj/item/stack)) + var/obj/item/stack/S = O + S.amount = produced + S.add_to_stacks(user, recipe.goes_in_hands) + +/obj/item/stack/Topic(href, href_list) + ..() + if ((usr.restrained() || usr.stat || usr.get_active_hand() != src)) + return + + if (href_list["sublist"] && !href_list["make"]) + list_recipes(usr, text2num(href_list["sublist"])) + + if (href_list["make"]) + if (src.get_amount() < 1) qdel(src) //Never should happen + + var/list/recipes_list = recipes + if (href_list["sublist"]) + var/datum/stack_recipe_list/srl = recipes_list[text2num(href_list["sublist"])] + recipes_list = srl.recipes + + var/datum/stack_recipe/R = recipes_list[text2num(href_list["make"])] + var/multiplier = text2num(href_list["multiplier"]) + if (!multiplier || (multiplier <= 0)) //href exploit protection + return + + src.produce_recipe(R, multiplier, usr) + + if (src && usr.machine==src) //do not reopen closed window + spawn( 0 ) + src.interact(usr) + return + return + +//Return 1 if an immediate subsequent call to use() would succeed. +//Ensures that code dealing with stacks uses the same logic +/obj/item/stack/proc/can_use(var/used) + if (get_amount() < used) + return 0 + return 1 + +/obj/item/stack/proc/use(var/used) + if (!can_use(used)) + return 0 + if(!uses_charge) + amount -= used + if (amount <= 0) + if(usr) + usr.remove_from_mob(src) + qdel(src) //should be safe to qdel immediately since if someone is still using this stack it will persist for a little while longer + return 1 + else + if(get_amount() < used) + return 0 + for(var/i = 1 to charge_costs.len) + var/datum/matter_synth/S = synths[i] + S.use_charge(charge_costs[i] * used) // Doesn't need to be deleted + return 1 + return 0 + +/obj/item/stack/proc/add(var/extra) + if(!uses_charge) + if(amount + extra > get_max_amount()) + return 0 + else + amount += extra + return 1 + else if(!synths || synths.len < uses_charge) + return 0 + else + for(var/i = 1 to uses_charge) + var/datum/matter_synth/S = synths[i] + S.add_charge(charge_costs[i] * extra) + +/* + The transfer and split procs work differently than use() and add(). + Whereas those procs take no action if the desired amount cannot be added or removed these procs will try to transfer whatever they can. + They also remove an equal amount from the source stack. +*/ + +//attempts to transfer amount to S, and returns the amount actually transferred +/obj/item/stack/proc/transfer_to(obj/item/stack/S, var/tamount=null, var/type_verified) + if (!get_amount()) + return 0 + if ((stacktype != S.stacktype) && !type_verified) + return 0 + if (isnull(tamount)) + tamount = src.get_amount() + + var/transfer = max(min(tamount, src.get_amount(), (S.get_max_amount() - S.get_amount())), 0) + + var/orig_amount = src.get_amount() + if (transfer && src.use(transfer)) + S.add(transfer) + if (prob(transfer/orig_amount * 100)) + transfer_fingerprints_to(S) + if(blood_DNA) + S.blood_DNA |= blood_DNA + return transfer + return 0 + +//creates a new stack with the specified amount +/obj/item/stack/proc/split(var/tamount, var/force=FALSE) + if (!amount) + return null + if(uses_charge && !force) + return null + + var/transfer = max(min(tamount, src.amount, initial(max_amount)), 0) + + var/orig_amount = src.amount + if (transfer && src.use(transfer)) + var/obj/item/stack/newstack = new src.type(loc, transfer) + newstack.color = color + if (prob(transfer/orig_amount * 100)) + transfer_fingerprints_to(newstack) + if(blood_DNA) + newstack.blood_DNA |= blood_DNA + return newstack + return null + +/obj/item/stack/proc/get_amount() + if(uses_charge) + if(!synths || synths.len < uses_charge) + 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) + S = synths[i] + . = min(., round(S.get_charge() / charge_costs[i])) + return + return amount + +/obj/item/stack/proc/get_max_amount() + if(uses_charge) + if(!synths || synths.len < uses_charge) + return 0 + var/datum/matter_synth/S = synths[1] + . = round(S.max_energy / charge_costs[1]) + if(uses_charge > 1) + for(var/i = 2 to uses_charge) + S = synths[i] + . = min(., round(S.max_energy / charge_costs[i])) + return + return max_amount + +/obj/item/stack/proc/add_to_stacks(mob/user, check_hands) + var/list/stacks = list() + if(check_hands) + if(isstack(user.l_hand)) + stacks += user.l_hand + if(isstack(user.r_hand)) + stacks += user.r_hand + for (var/obj/item/stack/item in user.loc) + stacks += item + for (var/obj/item/stack/item in stacks) + if (item==src) + continue + var/transfer = src.transfer_to(item) + if (transfer) + to_chat(user, "You add a new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s.") + if(!amount) + break + +/obj/item/stack/get_storage_cost() //Scales storage cost to stack size + . = ..() + if (amount < max_amount) + . = ceil(. * amount / max_amount) + +/obj/item/stack/attack_hand(mob/user as mob) + if (user.get_inactive_hand() == src) + var/N = input("How many stacks of [src] would you like to split off?", "Split stacks", 1) as num|null + if(N) + var/obj/item/stack/F = src.split(N) + if (F) + user.put_in_hands(F) + src.add_fingerprint(user) + F.add_fingerprint(user) + spawn(0) + if (src && usr.machine==src) + src.interact(usr) + else + ..() + return + +/obj/item/stack/attackby(obj/item/W as obj, mob/user as mob) + if (istype(W, /obj/item/stack)) + var/obj/item/stack/S = W + src.transfer_to(S) + + spawn(0) //give the stacks a chance to delete themselves if necessary + if (S && usr.machine==S) + S.interact(usr) + if (src && usr.machine==src) + src.interact(usr) + else + return ..() + +/* + * Recipe datum + */ +/datum/stack_recipe + var/title = "ERROR" + var/result_type + var/req_amount = 1 //amount of material needed for this recipe + var/res_amount = 1 //amount of stuff that is produced in one batch (e.g. 4 for floor tiles) + var/max_res_amount = 1 + var/time = 0 + var/one_per_turf = 0 + var/on_floor = 0 + var/use_material + var/goes_in_hands = 1 + + New(title, result_type, req_amount = 1, res_amount = 1, max_res_amount = 1, time = 0, one_per_turf = 0, on_floor = 0, supplied_material = null, goes_in_hands = 1) + src.title = title + src.result_type = result_type + src.req_amount = req_amount + src.res_amount = res_amount + src.max_res_amount = max_res_amount + src.time = time + src.one_per_turf = one_per_turf + src.on_floor = on_floor + src.use_material = supplied_material + src.goes_in_hands = goes_in_hands + +/* + * Recipe list datum + */ +/datum/stack_recipe_list + var/title = "ERROR" + var/list/recipes = null + New(title, recipes) + src.title = title + src.recipes = recipes diff --git a/code/game/objects/items/stacks/telecrystal.dm b/code/game/objects/items/stacks/telecrystal.dm new file mode 100644 index 00000000..035e5d58 --- /dev/null +++ b/code/game/objects/items/stacks/telecrystal.dm @@ -0,0 +1,31 @@ +/obj/item/stack/telecrystal + name = "telecrystal" + desc = "It seems to be pulsing with suspiciously enticing energies." + description_antag = "Telecrystals can be activated by utilizing them on devices with an actively running uplink. They will not activate on unactivated uplinks." + singular_name = "telecrystal" + icon = 'icons/obj/telescience.dmi' + icon_state = "telecrystal" + w_class = ITEM_SIZE_TINY + max_amount = 50 + item_flags = ITEM_FLAG_NO_BLUDGEON + origin_tech = list(TECH_MATERIAL = 6, TECH_BLUESPACE = 4) + +/obj/item/stack/telecrystal/afterattack(var/obj/item/I as obj, mob/user as mob, proximity) + if(!proximity) + return + if(istype(I, /obj/item)) + if(I.hidden_uplink && I.hidden_uplink.active) //No metagaming by using this on every PDA around just to see if it gets used up. + I.hidden_uplink.uses += amount + I.hidden_uplink.update_nano_data() + GLOB.nanomanager.update_uis(I.hidden_uplink) + use(amount) + to_chat(user, "You slot \the [src] into \the [I] and charge its internal uplink.") + +/obj/item/stack/telecrystal/attack_self(var/mob/user) + if(use(ceil(DEFAULT_TELECRYSTAL_AMOUNT/20))) + user.visible_message("\The [user] crushes a crystal!", "You crush \a [src]!", "You hear the sound of a crystal breaking just before a sudden crack of electricity.") + var/turf/T = get_random_turf_in_range(user, 7, 3) + if(T) + user.phase_out(T, get_turf(user)) + user.forceMove(T) + user.phase_in(T, get_turf(user)) diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm new file mode 100644 index 00000000..49965740 --- /dev/null +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -0,0 +1,173 @@ +/* Diffrent misc types of tiles + * Contains: + * Prototype + * Grass + * Wood + * Linoleum + * Carpet + */ + +/obj/item/stack/tile + name = "tile" + singular_name = "tile" + desc = "A non-descript floor tile." + randpixel = 7 + w_class = ITEM_SIZE_NORMAL + max_amount = 100 + icon = 'icons/obj/tiles.dmi' + + force = 1 + throwforce = 1 + throw_speed = 5 + throw_range = 20 + item_flags = 0 + obj_flags = 0 + +/* + * Grass + */ +/obj/item/stack/tile/grass + name = "grass tile" + singular_name = "grass floor tile" + desc = "A patch of grass like they often use on golf courses." + icon_state = "tile_grass" + origin_tech = list(TECH_BIO = 1) + +/* + * Wood + */ +/obj/item/stack/tile/wood + name = "wood floor tile" + singular_name = "wood floor tile" + desc = "An easy to fit wooden floor tile." + icon_state = "tile-wood" + +/obj/item/stack/tile/wood/cyborg + name = "wood floor tile synthesizer" + desc = "A device that makes wood floor tiles." + uses_charge = 1 + charge_costs = list(250) + stacktype = /obj/item/stack/tile/wood + build_type = /obj/item/stack/tile/wood + +/obj/item/stack/tile/floor + name = "steel floor tile" + singular_name = "steel floor tile" + desc = "Those could work as a pretty decent throwing weapon." //why? + icon_state = "tile" + force = 6 + matter = list(DEFAULT_WALL_MATERIAL = 937.5) + throwforce = 15 + obj_flags = OBJ_FLAG_CONDUCTIBLE + +/obj/item/stack/tile/floor_white + name = "white floor tile" + singular_name = "white floor tile" + icon_state = "tile_white" + matter = list("plastic" = 937.5) + +/obj/item/stack/tile/floor_white/fifty + amount = 50 + +/obj/item/stack/tile/floor_dark + name = "dark floor tile" + singular_name = "dark floor tile" + icon_state = "fr_tile" + matter = list("plasteel" = 937.5) + +/obj/item/stack/tile/floor_dark/fifty + amount = 50 + +/obj/item/stack/tile/floor_freezer + name = "freezer floor tile" + singular_name = "freezer floor tile" + icon_state = "tile_freezer" + matter = list("plastic" = 937.5) + +/obj/item/stack/tile/floor_freezer/fifty + amount = 50 + +/obj/item/stack/tile/floor/cyborg + name = "floor tile synthesizer" + desc = "A device that makes floor tiles." + gender = NEUTER + matter = null + uses_charge = 1 + charge_costs = list(250) + stacktype = /obj/item/stack/tile/floor + build_type = /obj/item/stack/tile/floor + +/obj/item/stack/tile/linoleum + name = "linoleum" + singular_name = "linoleum" + desc = "A piece of linoleum. It is the same size as a normal floor tile!" + icon_state = "tile-linoleum" + +/obj/item/stack/tile/linoleum/fifty + amount = 50 + +/* + * Carpets + */ +/obj/item/stack/tile/carpet + name = "brown carpet" + singular_name = "brown carpet" + desc = "A piece of brown carpet." + icon_state = "tile_carpetbrown" + +/obj/item/stack/tile/carpet/fifty + amount = 50 + +/obj/item/stack/tile/carpetblue + name = "blue carpet" + desc = "A piece of blue and gold carpet." + singular_name = "blue carpet" + icon_state = "tile_carpetblue" + +/obj/item/stack/tile/carpetblue/fifty + amount = 50 + +/obj/item/stack/tile/carpetblue2 + name = "pale blue carpet" + desc = "A piece of blue and silver carpet." + singular_name = "pale blue carpet" + icon_state = "tile_carpetblue2" + +/obj/item/stack/tile/carpetblue2/fifty + amount = 50 + +/obj/item/stack/tile/carpetpurple + name = "purple carpet" + desc = "A piece of purple carpet." + singular_name = "purple carpet" + icon_state = "tile_carpetpurple" + +/obj/item/stack/tile/carpetpurple/fifty + amount = 50 + +/obj/item/stack/tile/carpetorange + name = "orange carpet" + desc = "A piece of orange carpet." + singular_name = "orange carpet" + icon_state = "tile_carpetorange" + +/obj/item/stack/tile/carpetorange/fifty + amount = 50 + +/obj/item/stack/tile/carpetgreen + name = "green carpet" + desc = "A piece of green carpet." + singular_name = "green carpet" + icon_state = "tile_carpetgreen" + +/obj/item/stack/tile/carpetgreen/fifty + amount = 50 + +/obj/item/stack/tile/carpetred + name = "red carpet" + desc = "A piece of red carpet." + singular_name = "red carpet" + icon_state = "tile_carpetred" + +/obj/item/stack/tile/carpetred/fifty + amount = 50 \ No newline at end of file diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm new file mode 100644 index 00000000..44431807 --- /dev/null +++ b/code/game/objects/items/toys.dm @@ -0,0 +1,845 @@ +/* Toys! + * Contains: + * Balloons + * Fake telebeacon + * Fake singularity + * Toy gun + * Toy crossbow + * Toy swords + * Toy bosun's whistle + * Toy mechs + * Snap pops + * Water flower + * Therapy dolls + * Inflatable duck + * Action figures + * Plushies + * Toy cult sword + * Marshalling wand + * Ring bell + */ + + +/obj/item/toy + icon = 'icons/obj/toy.dmi' + throwforce = 0 + throw_speed = 4 + throw_range = 20 + force = 0 + +/* + * Balloons + */ +/obj/item/toy/water_balloon + name = "water balloon" + desc = "A translucent balloon. There's nothing in it." + icon = 'icons/obj/toy.dmi' + icon_state = "waterballoon-e" + item_state = "balloon-empty" + +/obj/item/toy/water_balloon/New() + create_reagents(10) + ..() + +/obj/item/toy/water_balloon/attack(mob/living/carbon/human/M as mob, mob/user as mob) + return + +/obj/item/toy/water_balloon/afterattack(atom/A as mob|obj, mob/user as mob, proximity) + if(!proximity) return + if (istype(A, /obj/structure/reagent_dispensers/watertank) && get_dist(src,A) <= 1) + A.reagents.trans_to_obj(src, 10) + to_chat(user, "You fill the balloon with the contents of [A].") + src.desc = "A translucent balloon with some form of liquid sloshing around in it." + src.update_icon() + return + +/obj/item/toy/water_balloon/attackby(obj/O as obj, mob/user as mob) + if(istype(O, /obj/item/weapon/reagent_containers/glass)) + if(O.reagents) + if(O.reagents.total_volume < 1) + to_chat(user, "The [O] is empty.") + else if(O.reagents.total_volume >= 1) + if(O.reagents.has_reagent(/datum/reagent/acid/polyacid, 1)) + to_chat(user, "The acid chews through the balloon!") + O.reagents.splash(user, reagents.total_volume) + qdel(src) + else + src.desc = "A translucent balloon with some form of liquid sloshing around in it." + to_chat(user, "You fill the balloon with the contents of [O].") + O.reagents.trans_to_obj(src, 10) + src.update_icon() + return + +/obj/item/toy/water_balloon/throw_impact(atom/hit_atom) + if(src.reagents.total_volume >= 1) + src.visible_message("\The [src] bursts!","You hear a pop and a splash.") + src.reagents.touch_turf(get_turf(hit_atom)) + for(var/atom/A in get_turf(hit_atom)) + src.reagents.touch(A) + src.icon_state = "burst" + spawn(5) + if(src) + qdel(src) + return + +/obj/item/toy/water_balloon/update_icon() + if(src.reagents.total_volume >= 1) + icon_state = "waterballoon" + item_state = "balloon" + else + icon_state = "waterballoon-e" + item_state = "balloon-empty" + +/obj/item/toy/balloon + name = "\improper 'criminal' balloon" + desc = "FUK NT!11!" + throwforce = 0 + throw_speed = 4 + throw_range = 20 + force = 0 + icon = 'icons/obj/weapons.dmi' + icon_state = "syndballoon" + item_state = "syndballoon" + w_class = ITEM_SIZE_HUGE + +/obj/item/toy/balloon/New() + ..() + desc = "Across the balloon is printed: \"[desc]\"" + +/obj/item/toy/balloon/nanotrasen + name = "\improper 'motivational' balloon" + desc = "Man, I love NanoTrasen soooo much. I use only NT products. You have NO idea." + icon_state = "ntballoon" + item_state = "ntballoon" + +/* + * Fake telebeacon + */ +/obj/item/toy/blink + name = "electronic blink toy game" + desc = "Blink. Blink. Blink. Ages 8 and up." + icon = 'icons/obj/radio.dmi' + icon_state = "beacon" + item_state = "signaler" + +/* + * Fake singularity + */ +/obj/item/toy/spinningtoy + name = "gravitational singularity" + desc = "\"Singulo\" brand spinning toy." + icon = 'icons/obj/singularity.dmi' + icon_state = "singularity_s1" + +/* + * Toy crossbow + */ + +/obj/item/toy/crossbow + name = "foam dart crossbow" + desc = "A weapon favored by many overactive children. Ages 8 and up." + icon = 'icons/obj/gun.dmi' + icon_state = "crossbow" + item_state = "crossbow" + item_icons = list( + icon_l_hand = 'icons/mob/onmob/items/lefthand_guns.dmi', + icon_r_hand = 'icons/mob/onmob/items/righthand_guns.dmi', + ) + w_class = ITEM_SIZE_SMALL + attack_verb = list("attacked", "struck", "hit") + var/bullets = 5 + + examine(mob/user) + if(..(user, 2) && bullets) + to_chat(user, "It is loaded with [bullets] foam darts!") + + attackby(obj/item/I as obj, mob/user as mob) + if(istype(I, /obj/item/toy/ammo/crossbow)) + if(bullets <= 4) + user.drop_item() + qdel(I) + bullets++ + to_chat(user, "You load the foam dart into the crossbow.") + else + to_chat(usr, "It's already fully loaded.") + + + afterattack(atom/target as mob|obj|turf|area, mob/user as mob, flag) + if(!isturf(target.loc) || target == user) return + if(flag) return + + if (locate (/obj/structure/table, src.loc)) + return + else if (bullets) + var/turf/trg = get_turf(target) + var/obj/effect/foam_dart_dummy/D = new/obj/effect/foam_dart_dummy(get_turf(src)) + bullets-- + D.icon_state = "foamdart" + D.SetName("foam dart") + playsound(user.loc, 'sound/items/syringeproj.ogg', 50, 1) + + for(var/i=0, i<6, i++) + if (D) + if(D.loc == trg) break + step_towards(D,trg) + + for(var/mob/living/M in D.loc) + if(!istype(M,/mob/living)) continue + if(M == user) continue + for(var/mob/O in viewers(world.view, D)) + O.show_message(text("\The [] was hit by the foam dart!", M), 1) + new /obj/item/toy/ammo/crossbow(M.loc) + qdel(D) + return + + for(var/atom/A in D.loc) + if(A == user) continue + if(A.density) + new /obj/item/toy/ammo/crossbow(A.loc) + qdel(D) + + sleep(1) + + spawn(10) + if(D) + new /obj/item/toy/ammo/crossbow(D.loc) + qdel(D) + + return + else if (bullets == 0) + user.Weaken(5) + for(var/mob/O in viewers(world.view, user)) + O.show_message(text("\The [] realized they were out of ammo and starting scrounging for some!", user), 1) + + + attack(mob/M as mob, mob/user as mob) + src.add_fingerprint(user) + +// ******* Check + + if (src.bullets > 0 && M.lying) + + for(var/mob/O in viewers(M, null)) + if(O.client) + O.show_message(text("\The [] casually lines up a shot with []'s head and pulls the trigger!", user, M), 1, "You hear the sound of foam against skull", 2) + O.show_message(text("\The [] was hit in the head by the foam dart!", M), 1) + + playsound(user.loc, 'sound/items/syringeproj.ogg', 50, 1) + new /obj/item/toy/ammo/crossbow(M.loc) + src.bullets-- + else if (M.lying && src.bullets == 0) + for(var/mob/O in viewers(M, null)) + if (O.client) O.show_message(text("\The [] casually lines up a shot with []'s head, pulls the trigger, then realizes they are out of ammo and drops to the floor in search of some!", user, M), 1, "You hear someone fall", 2) + user.Weaken(5) + return + +/obj/item/toy/ammo/crossbow + name = "foam dart" + desc = "It's nerf or nothing! Ages 8 and up." + icon = 'icons/obj/toy.dmi' + icon_state = "foamdart" + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + +/obj/effect/foam_dart_dummy + name = "" + desc = "" + icon = 'icons/obj/toy.dmi' + icon_state = "null" + anchored = 1 + density = 0 + + +/* + * Toy swords + */ +/obj/item/toy/sword + name = "toy sword" + desc = "A cheap, plastic replica of an energy sword. Realistic sounds! Ages 8 and up." + icon = 'icons/obj/weapons.dmi' + icon_state = "sword0" + item_state = "sword0" + var/active = 0.0 + w_class = ITEM_SIZE_SMALL + attack_verb = list("attacked", "struck", "hit") + + attack_self(mob/user as mob) + src.active = !( src.active ) + if (src.active) + to_chat(user, "You extend the plastic blade with a quick flick of your wrist.") + playsound(user, 'sound/weapons/saberon.ogg', 50, 1) + src.icon_state = "swordblue" + src.item_state = "swordblue" + src.w_class = ITEM_SIZE_HUGE + else + to_chat(user, "You push the plastic blade back down into the handle.") + playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) + src.icon_state = "sword0" + src.item_state = "sword0" + src.w_class = initial(w_class) + + update_held_icon() + + src.add_fingerprint(user) + return + +/obj/item/toy/katana + name = "replica katana" + desc = "Woefully underpowered in D20." + icon = 'icons/obj/weapons.dmi' + icon_state = "katana" + item_state = "katana" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT | SLOT_BACK + force = 5 + throwforce = 5 + w_class = ITEM_SIZE_LARGE + attack_verb = list("attacked", "slashed", "stabbed", "sliced") + +/* + * Snap pops + */ +/obj/item/toy/snappop + name = "snap pop" + desc = "Wow!" + icon = 'icons/obj/toy.dmi' + icon_state = "snappop" + w_class = ITEM_SIZE_TINY + + throw_impact(atom/hit_atom) + ..() + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + new /obj/effect/decal/cleanable/ash(src.loc) + src.visible_message("The [src.name] explodes!","You hear a snap!") + playsound(src, 'sound/effects/snap.ogg', 50, 1) + qdel(src) + +/obj/item/toy/snappop/Crossed(H as mob|obj) + if((ishuman(H))) //i guess carp and shit shouldn't set them off + var/mob/living/carbon/M = H + if(M.m_intent == "run") + to_chat(M, "You step on the snap pop!") + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 0, src) + s.start() + new /obj/effect/decal/cleanable/ash(src.loc) + src.visible_message("The [src.name] explodes!","You hear a snap!") + playsound(src, 'sound/effects/snap.ogg', 50, 1) + qdel(src) + +/* + * Bosun's whistle + */ + +/obj/item/toy/bosunwhistle + name = "bosun's whistle" + desc = "A genuine Admiral Krush Bosun's Whistle, for the aspiring ship's captain! Suitable for ages 8 and up, do not swallow." + icon = 'icons/obj/toy.dmi' + icon_state = "bosunwhistle" + var/cooldown = 0 + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + +/obj/item/toy/bosunwhistle/attack_self(mob/user as mob) + if(cooldown < world.time - 35) + to_chat(user, "You blow on [src], creating an ear-splitting noise!") + playsound(user, 'sound/misc/boatswain.ogg', 20, 1) + cooldown = world.time + +/* + * Mech prizes + */ +/obj/item/toy/prize + icon = 'icons/obj/toy.dmi' + icon_state = "ripleytoy" + var/cooldown = 0 + +//all credit to skasi for toy mech fun ideas +/obj/item/toy/prize/attack_self(mob/user as mob) + if(cooldown < world.time - 8) + to_chat(user, "You play with [src].") + playsound(user, 'sound/mecha/mechstep.ogg', 20, 1) + cooldown = world.time + +/obj/item/toy/prize/attack_hand(mob/user as mob) + if(loc == user) + if(cooldown < world.time - 8) + to_chat(user, "You play with [src].") + playsound(user, 'sound/mecha/mechturn.ogg', 20, 1) + cooldown = world.time + return + ..() + +/obj/item/toy/prize/ripley + name = "toy ripley" + desc = "Mini-Mecha action figure! Collect them all! 1/11." + +/obj/item/toy/prize/fireripley + name = "toy firefighting ripley" + desc = "Mini-Mecha action figure! Collect them all! 2/11." + icon_state = "fireripleytoy" + +/obj/item/toy/prize/deathripley + name = "toy deathsquad ripley" + desc = "Mini-Mecha action figure! Collect them all! 3/11." + icon_state = "deathripleytoy" + +/obj/item/toy/prize/gygax + name = "toy gygax" + desc = "Mini-Mecha action figure! Collect them all! 4/11." + icon_state = "gygaxtoy" + +/obj/item/toy/prize/durand + name = "toy durand" + desc = "Mini-Mecha action figure! Collect them all! 5/11." + icon_state = "durandprize" + +/obj/item/toy/prize/honk + name = "toy H.O.N.K." + desc = "Mini-Mecha action figure! Collect them all! 6/11." + icon_state = "honkprize" + +/obj/item/toy/prize/marauder + name = "toy marauder" + desc = "Mini-Mecha action figure! Collect them all! 7/11." + icon_state = "marauderprize" + +/obj/item/toy/prize/seraph + name = "toy seraph" + desc = "Mini-Mecha action figure! Collect them all! 8/11." + icon_state = "seraphprize" + +/obj/item/toy/prize/mauler + name = "toy mauler" + desc = "Mini-Mecha action figure! Collect them all! 9/11." + icon_state = "maulerprize" + +/obj/item/toy/prize/odysseus + name = "toy odysseus" + desc = "Mini-Mecha action figure! Collect them all! 10/11." + icon_state = "odysseusprize" + +/obj/item/toy/prize/phazon + name = "toy phazon" + desc = "Mini-Mecha action figure! Collect them all! 11/11." + icon_state = "phazonprize" + +/* + * Action figures + */ + +/obj/item/toy/figure + name = "Completely Glitched action figure" + desc = "A \"Space Life\" brand... wait, what the hell is this thing? It seems to be requesting the sweet release of death." + icon_state = "assistant" + icon = 'icons/obj/toy.dmi' + +/obj/item/toy/figure/cmo + name = "Chief Medical Officer action figure" + desc = "A \"Space Life\" brand Chief Medical Officer action figure." + icon_state = "cmo" + +/obj/item/toy/figure/assistant + name = "Assistant action figure" + desc = "A \"Space Life\" brand Assistant action figure." + icon_state = "assistant" + +/obj/item/toy/figure/atmos + name = "Atmospheric Technician action figure" + desc = "A \"Space Life\" brand Atmospheric Technician action figure." + icon_state = "atmos" + +/obj/item/toy/figure/bartender + name = "Bartender action figure" + desc = "A \"Space Life\" brand Bartender action figure." + icon_state = "bartender" + +/obj/item/toy/figure/borg + name = "Cyborg action figure" + desc = "A \"Space Life\" brand Cyborg action figure." + icon_state = "borg" + +/obj/item/toy/figure/gardener + name = "Gardener action figure" + desc = "A \"Space Life\" brand Gardener action figure." + icon_state = "botanist" + +/obj/item/toy/figure/captain + name = "Captain action figure" + desc = "A \"Space Life\" brand Captain action figure." + icon_state = "captain" + +/obj/item/toy/figure/cargotech + name = "Cargo Technician action figure" + desc = "A \"Space Life\" brand Cargo Technician action figure." + icon_state = "cargotech" + +/obj/item/toy/figure/ce + name = "Chief Engineer action figure" + desc = "A \"Space Life\" brand Chief Engineer action figure." + icon_state = "ce" + +/obj/item/toy/figure/chaplain + name = "Chaplain action figure" + desc = "A \"Space Life\" brand Chaplain action figure." + icon_state = "chaplain" + +/obj/item/toy/figure/chef + name = "Chef action figure" + desc = "A \"Space Life\" brand Chef action figure." + icon_state = "chef" + +/obj/item/toy/figure/chemist + name = "Chemist action figure" + desc = "A \"Space Life\" brand Chemist action figure." + icon_state = "chemist" + +/obj/item/toy/figure/clown + name = "Clown action figure" + desc = "A \"Space Life\" brand Clown action figure." + icon_state = "clown" + +/obj/item/toy/figure/corgi + name = "Corgi action figure" + desc = "A \"Space Life\" brand Corgi action figure." + icon_state = "ian" + +/obj/item/toy/figure/detective + name = "Detective action figure" + desc = "A \"Space Life\" brand Detective action figure." + icon_state = "detective" + +/obj/item/toy/figure/dsquad + name = "Space Commando action figure" + desc = "A \"Space Life\" brand Space Commando action figure." + icon_state = "dsquad" + +/obj/item/toy/figure/engineer + name = "Engineer action figure" + desc = "A \"Space Life\" brand Engineer action figure." + icon_state = "engineer" + +/obj/item/toy/figure/geneticist + name = "Geneticist action figure" + desc = "A \"Space Life\" brand Geneticist action figure, which was recently dicontinued." + icon_state = "geneticist" + +/obj/item/toy/figure/hop + name = "Head of Personel action figure" + desc = "A \"Space Life\" brand Head of Personel action figure." + icon_state = "hop" + +/obj/item/toy/figure/hos + name = "Head of Security action figure" + desc = "A \"Space Life\" brand Head of Security action figure." + icon_state = "hos" + +/obj/item/toy/figure/qm + name = "Quartermaster action figure" + desc = "A \"Space Life\" brand Quartermaster action figure." + icon_state = "qm" + +/obj/item/toy/figure/janitor + name = "Janitor action figure" + desc = "A \"Space Life\" brand Janitor action figure." + icon_state = "janitor" + +/obj/item/toy/figure/agent + name = "Internal Affairs Agent action figure" + desc = "A \"Space Life\" brand Internal Affairs Agent action figure." + icon_state = "agent" + +/obj/item/toy/figure/librarian + name = "Librarian action figure" + desc = "A \"Space Life\" brand Librarian action figure." + icon_state = "librarian" + +/obj/item/toy/figure/md + name = "Medical Doctor action figure" + desc = "A \"Space Life\" brand Medical Doctor action figure." + icon_state = "md" + +/obj/item/toy/figure/mime + name = "Mime action figure" + desc = "A \"Space Life\" brand Mime action figure." + icon_state = "mime" + +/obj/item/toy/figure/miner + name = "Shaft Miner action figure" + desc = "A \"Space Life\" brand Shaft Miner action figure." + icon_state = "miner" + +/obj/item/toy/figure/ninja + name = "Space Ninja action figure" + desc = "A \"Space Life\" brand Space Ninja action figure." + icon_state = "ninja" + +/obj/item/toy/figure/wizard + name = "Wizard action figure" + desc = "A \"Space Life\" brand Wizard action figure." + icon_state = "wizard" + +/obj/item/toy/figure/rd + name = "Research Director action figure" + desc = "A \"Space Life\" brand Research Director action figure." + icon_state = "rd" + +/obj/item/toy/figure/roboticist + name = "Roboticist action figure" + desc = "A \"Space Life\" brand Roboticist action figure." + icon_state = "roboticist" + +/obj/item/toy/figure/scientist + name = "Scientist action figure" + desc = "A \"Space Life\" brand Scientist action figure." + icon_state = "scientist" + +/obj/item/toy/figure/syndie + name = "Doom Operative action figure" + desc = "A \"Space Life\" brand Doom Operative action figure." + icon_state = "syndie" + +/obj/item/toy/figure/secofficer + name = "Security Officer action figure" + desc = "A \"Space Life\" brand Security Officer action figure." + icon_state = "secofficer" + +/obj/item/toy/figure/warden + name = "Warden action figure" + desc = "A \"Space Life\" brand Warden action figure." + icon_state = "warden" + +/obj/item/toy/figure/psychologist + name = "Psychologist action figure" + desc = "A \"Space Life\" brand Psychologist action figure." + icon_state = "psychologist" + +/obj/item/toy/figure/paramedic + name = "Paramedic action figure" + desc = "A \"Space Life\" brand Paramedic action figure." + icon_state = "paramedic" + +/obj/item/toy/figure/ert + name = "Emergency Response Team Commander action figure" + desc = "A \"Space Life\" brand Emergency Response Team Commander action figure." + icon_state = "ert" + +/obj/item/toy/therapy_red + name = "red therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is red." + icon_state = "therapyred" + item_state = "egg4" // It's the red egg in items_left/righthand + w_class = ITEM_SIZE_TINY + +/obj/item/toy/therapy_purple + name = "purple therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is purple." + icon_state = "therapypurple" + item_state = "egg1" // It's the magenta egg in items_left/righthand + w_class = ITEM_SIZE_TINY + +/obj/item/toy/therapy_blue + name = "blue therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is blue." + icon_state = "therapyblue" + item_state = "egg2" // It's the blue egg in items_left/righthand + w_class = ITEM_SIZE_TINY + +/obj/item/toy/therapy_yellow + name = "yellow therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is yellow." + icon_state = "therapyyellow" + item_state = "egg5" // It's the yellow egg in items_left/righthand + w_class = ITEM_SIZE_TINY + +/obj/item/toy/therapy_orange + name = "orange therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is orange." + icon_state = "therapyorange" + item_state = "egg4" // It's the red one again, lacking an orange item_state and making a new one is pointless + w_class = ITEM_SIZE_TINY + +/obj/item/toy/therapy_green + name = "green therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is green." + icon_state = "therapygreen" + item_state = "egg3" // It's the green egg in items_left/righthand + w_class = ITEM_SIZE_TINY + +/* + * Plushies + */ + +//Large plushies. +/obj/structure/plushie + name = "generic plush" + desc = "A very generic plushie. It seems to not want to exist." + icon = 'icons/obj/toy.dmi' + icon_state = "ianplushie" + anchored = 0 + density = 1 + var/phrase = "I don't want to exist anymore!" + +/obj/structure/plushie/attack_hand(mob/user) + if(user.a_intent == I_HELP) + user.visible_message("\The [user] hugs [src]!","You hug [src]!") + else if (user.a_intent == I_HURT) + user.visible_message("\The [user] punches [src]!","You punch [src]!") + else if (user.a_intent == I_GRAB) + user.visible_message("\The [user] attempts to strangle [src]!","You attempt to strangle [src]!") + else + user.visible_message("\The [user] pokes the [src].","You poke the [src].") + visible_message("[src] says, \"[phrase]\"") + +/obj/structure/plushie/ian + name = "plush corgi" + desc = "A plushie of an adorable corgi! Don't you just want to hug it and squeeze it and call it \"Ian\"?" + icon_state = "ianplushie" + phrase = "Arf!" + +/obj/structure/plushie/drone + name = "plush drone" + desc = "A plushie of a happy drone! It appears to be smiling, and has a small tag which reads \"N.D.V. Icarus Gift Shop\"." + icon_state = "droneplushie" + phrase = "Beep boop!" + +/obj/structure/plushie/carp + name = "plush carp" + desc = "A plushie of an elated carp! Straight from the wilds of the Nyx frontier, now right here in your hands." + icon_state = "carpplushie" + phrase = "Glorf!" + +/obj/structure/plushie/beepsky + name = "plush Officer Sweepsky" + desc = "A plushie of a popular industrious cleaning robot! If it could feel emotions, it would love you." + icon_state = "beepskyplushie" + phrase = "Ping!" + +//Small plushies. +/obj/item/toy/plushie + name = "generic small plush" + desc = "A very generic small plushie. It seems to not want to exist." + icon = 'icons/obj/toy.dmi' + icon_state = "nymphplushie" + +/obj/item/toy/plushie/attack_self(mob/user as mob) + if(user.a_intent == I_HELP) + user.visible_message("\The [user] hugs [src]!","You hug [src]!") + else if (user.a_intent == I_HURT) + user.visible_message("\The [user] punches [src]!","You punch [src]!") + else if (user.a_intent == I_GRAB) + user.visible_message("\The [user] attempts to strangle [src]!","You attempt to strangle [src]!") + else + user.visible_message("\The [user] pokes the [src].","You poke the [src].") + +/obj/item/toy/plushie/nymph + name = "diona nymph plush" + desc = "A plushie of an adorable diona nymph! While its level of self-awareness is still being debated, its level of cuteness is not." + icon_state = "nymphplushie" + +/obj/item/toy/plushie/mouse + name = "mouse plush" + desc = "A plushie of a delightful mouse! What was once considered a vile rodent is now your very best friend." + icon_state = "mouseplushie" + +/obj/item/toy/plushie/kitten + name = "kitten plush" + desc = "A plushie of a cute kitten! Watch as it purrs it's way right into your heart." + icon_state = "kittenplushie" + +/obj/item/toy/plushie/lizard + name = "lizard plush" + desc = "A plushie of a scaly lizard! Very controversial, after being accused as \"racist\" by some Unathi." + icon_state = "lizardplushie" + +/obj/item/toy/plushie/spider + name = "spider plush" + desc = "A plushie of a fuzzy spider! It has eight legs - all the better to hug you with." + icon_state = "spiderplushie" + +/obj/item/toy/plushie/farwa + name = "farwa plush" + desc = "A farwa plush doll. It's soft and comforting!" + icon_state = "farwaplushie" + +//Toy cult sword +/obj/item/toy/cultsword + name = "foam sword" + desc = "An arcane weapon (made of foam) wielded by the followers of the hit Saturday morning cartoon \"King Nursee and the Acolytes of Heroism\"." + icon = 'icons/obj/weapons.dmi' + icon_state = "cultblade" + item_state = "cultblade" + w_class = ITEM_SIZE_HUGE + attack_verb = list("attacked", "slashed", "stabbed", "poked") + +/obj/item/weapon/inflatable_duck + name = "inflatable duck" + desc = "No bother to sink or swim when you can just float!" + icon_state = "inflatable" + item_state = "inflatable" + icon = 'icons/obj/clothing/belts.dmi' + slot_flags = SLOT_BELT + +/obj/item/weapon/marshalling_wand + name = "marshalling wand" + desc = "An illuminated, hand-held baton used by hangar personnel to visually signal shuttle pilots. The signal changes depending on your intent." + icon_state = "marshallingwand" + item_state = "marshallingwand" + icon = 'icons/obj/toy.dmi' + item_icons = list( + icon_l_hand = 'icons/mob/onmob/items/lefthand.dmi', + icon_r_hand = 'icons/mob/onmob/items/righthand.dmi', + ) + slot_flags = SLOT_BELT + w_class = ITEM_SIZE_SMALL + force = 1 + attack_verb = list("attacked", "whacked", "jabbed", "poked", "marshalled") + +/obj/item/weapon/marshalling_wand/Initialize() + set_light(1.5, 1.5, "#ff0000") + return ..() + +/obj/item/weapon/marshalling_wand/attack_self(mob/living/user as mob) + if (user.a_intent == I_HELP) + user.visible_message("[user] beckons with \the [src], signalling forward motion.", + "You beckon with \the [src], signalling forward motion.") + else if (user.a_intent == I_DISARM) + user.visible_message("[user] holds \the [src] above their head, signalling a stop.", + "You hold \the [src] above your head, signalling a stop.") + else if (user.a_intent == I_GRAB) + var/WAND_TURN_DIRECTION + if (user.l_hand == src) WAND_TURN_DIRECTION = "left" + else if (user.r_hand == src) WAND_TURN_DIRECTION = "right" + else return //how can you not be holding it in either hand?? black magic + user.visible_message("[user] waves \the [src] to the [WAND_TURN_DIRECTION], signalling a turn.", + "You wave \the [src] to the [WAND_TURN_DIRECTION], signalling a turn.") + else if (user.a_intent == I_HURT) + user.visible_message("[user] frantically waves \the [src] above their head!", + "You frantically wave \the [src] above your head!") + +/obj/item/toy/torchmodel + name = "table-top SEV Torch model" + desc = "This is a replica of the SEV Torch, in 1:250th scale, on a handsome wooden stand. Small lights blink on the hull and at the engine exhaust." + icon = 'icons/obj/toy.dmi' + icon_state = "torch_model_figure" + +/obj/item/toy/ringbell + name = "ringside bell" + desc = "A bell used to signal the beginning and end of various ring sports." + icon = 'icons/obj/toy.dmi' + icon_state= "ringbell" + anchored = 1 + +/obj/item/toy/ringbell/attack_hand(mob/user as mob) + if (user.a_intent == I_HELP) + user.visible_message("[user] rings \the [src], signalling the beginning of the contest.") + playsound(user.loc, 'sound/items/oneding.ogg', 60) + else if (user.a_intent == I_DISARM) + user.visible_message("[user] rings \the [src] three times, signalling the end of the contest!") + playsound(user.loc, 'sound/items/threedings.ogg', 60) + else if (user.a_intent == I_HURT) + user.visible_message("[user] rings \the [src] repeatedly, signalling a disqualification!") + playsound(user.loc, 'sound/items/manydings.ogg', 60) \ No newline at end of file diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm new file mode 100644 index 00000000..45ab30a6 --- /dev/null +++ b/code/game/objects/items/trash.dm @@ -0,0 +1,95 @@ +//Items labled as 'trash' for the trash bag. +//TODO: Make this an item var or something... + +//Added by Jack Rost +/obj/item/trash + icon = 'icons/obj/trash.dmi' + w_class = ITEM_SIZE_SMALL + desc = "This is rubbish." + +/obj/item/trash/raisins + name = "\improper 4no raisins" + icon_state = "4no_raisins" + +/obj/item/trash/candy + name = "candy" + icon_state = "candy" + +/obj/item/trash/candy/proteinbar + name = "protein bar" + icon_state = "proteinbar" + +/obj/item/trash/cheesie + name = "\improper Cheesie Honkers" + icon_state = "cheesie_honkers" + +/obj/item/trash/chips + name = "chips" + icon_state = "chips" + +/obj/item/trash/popcorn + name = "popcorn" + icon_state = "popcorn" + +/obj/item/trash/sosjerky + name = "Sgt Scaredy's Private Reserve Beef Jerky" + icon_state = "sosjerky" + +/obj/item/trash/syndi_cakes + name = "syndi cakes" + icon_state = "syndi_cakes" + +/obj/item/trash/waffles + name = "waffles" + icon_state = "waffles" + +/obj/item/trash/plate + name = "plate" + icon_state = "plate" + +/obj/item/trash/snack_bowl + name = "snack bowl" + icon_state = "snack_bowl" + +/obj/item/trash/pistachios + name = "pistachios pack" + icon_state = "pistachios_pack" + +/obj/item/trash/semki + name = "semki pack" + icon_state = "semki_pack" + +/obj/item/trash/tray + name = "tray" + icon_state = "tray" + +/obj/item/trash/candle + name = "candle" + icon = 'icons/obj/candle.dmi' + icon_state = "candle4" + +/obj/item/trash/liquidfood + name = "\improper \"LiquidFood\" MRE" + icon_state = "liquidfood" + +/obj/item/trash/tastybread + name = "bread tube" + icon_state = "tastybread" + +/obj/item/trash/warfare_can + icon = 'icons/obj/food.dmi' + name = "used can" + icon_state = "cbeans_empty" + drop_sound = 'sound/items/handle/can_drop.ogg' + +/obj/item/trash/warfare_can/flower + icon_state = "flowersgrub_empty" + +/obj/item/trash/warfare_can/sardine + icon_state = "pisssardine_empty" + +/obj/item/trash/warfare_can/rat + icon_state = "ratmeat_empty" + +/obj/item/trash/attack(mob/M as mob, mob/living/user as mob) + return diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm new file mode 100644 index 00000000..60f7b348 --- /dev/null +++ b/code/game/objects/items/weapons/AI_modules.dm @@ -0,0 +1,411 @@ +/* +CONTAINS: +AI MODULES + +*/ + +// AI module + +/obj/item/weapon/aiModule + name = "\improper AI module" + icon = 'icons/obj/module.dmi' + icon_state = "std_mod" + item_state = "electronic" + desc = "An AI Module for transmitting encrypted instructions to the AI." + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 5.0 + w_class = ITEM_SIZE_SMALL + throwforce = 5.0 + throw_speed = 3 + throw_range = 15 + origin_tech = list(TECH_DATA = 3) + var/datum/ai_laws/laws = null + +/obj/item/weapon/aiModule/proc/install(var/obj/machinery/computer/C) + if (istype(C, /obj/machinery/computer/aiupload)) + var/obj/machinery/computer/aiupload/comp = C + if(comp.stat & NOPOWER) + to_chat(usr, "The upload computer has no power!") + return + if(comp.stat & BROKEN) + to_chat(usr, "The upload computer is broken!") + return + if (!comp.current) + to_chat(usr, "You haven't selected an AI to transmit laws to!") + return + + if(ticker && ticker.mode && ticker.mode.name == "blob") + to_chat(usr, "Law uploads have been disabled by [GLOB.using_map.company_name]!") + return + + if (comp.current.stat == 2 || comp.current.control_disabled == 1) + to_chat(usr, "Upload failed. No signal is being detected from the AI.") + else if (comp.current.see_in_dark == 0) + to_chat(usr, "Upload failed. Only a faint signal is being detected from the AI, and it is not responding to our requests. It may be low on power.") + else + src.transmitInstructions(comp.current, usr) + for(var/mob/living/silicon/robot/R in GLOB.silicon_mob_list) + if(R.lawupdate && (R.connected_ai == comp.current)) + to_chat(R, "These are your laws now:") + R.show_laws() + to_chat(usr, "Upload complete. The AI's laws have been modified.") + + + else if (istype(C, /obj/machinery/computer/borgupload)) + var/obj/machinery/computer/borgupload/comp = C + if(comp.stat & NOPOWER) + to_chat(usr, "The upload computer has no power!") + return + if(comp.stat & BROKEN) + to_chat(usr, "The upload computer is broken!") + return + if (!comp.current) + to_chat(usr, "You haven't selected a robot to transmit laws to!") + return + + if (comp.current.stat == 2 || comp.current.emagged) + to_chat(usr, "Upload failed. No signal is being detected from the robot.") + else if (comp.current.connected_ai) + to_chat(usr, "Upload failed. The robot is slaved to an AI.") + else + src.transmitInstructions(comp.current, usr) + to_chat(comp.current, "These are your laws now:") + comp.current.show_laws() + to_chat(usr, "Upload complete. The robot's laws have been modified.") + + +/obj/item/weapon/aiModule/proc/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender) + log_law_changes(target, sender) + + if(laws) + laws.sync(target, 0) + addAdditionalLaws(target, sender) + + to_chat(target, "\The [sender] has uploaded a change to the laws you must follow, using \an [src]. From now on: ") + target.show_laws() + +/obj/item/weapon/aiModule/proc/log_law_changes(var/mob/living/silicon/ai/target, var/mob/sender) + var/time = time2text(world.realtime,"hh:mm:ss") + GLOB.lawchanges.Add("[time] : [sender.name]([sender.key]) used [src.name] on [target.name]([target.key])") + log_and_message_admins("used [src.name] on [target.name]([target.key])") + +/obj/item/weapon/aiModule/proc/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) + + +/******************** Modules ********************/ + +/******************** Safeguard ********************/ + +/obj/item/weapon/aiModule/safeguard + name = "\improper 'Safeguard' AI module" + var/targetName = "" + desc = "A 'safeguard' AI module: 'Safeguard . Anyone threatening or attempting to harm is no longer to be considered a crew member, and is a threat which must be neutralized.'." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) + +/obj/item/weapon/aiModule/safeguard/attack_self(var/mob/user as mob) + ..() + var/targName = sanitize(input("Please enter the name of the person to safeguard.", "Safeguard who?", user.name)) + targetName = targName + desc = text("A 'safeguard' AI module: 'Safeguard []. Anyone threatening or attempting to harm [] is no longer to be considered a crew member, and is a threat which must be neutralized.'.", targetName, targetName) + +/obj/item/weapon/aiModule/safeguard/install(var/obj/machinery/computer/C) + if(!targetName) + to_chat(usr, "No name detected on module, please enter one.") + return 0 + ..() + +/obj/item/weapon/aiModule/safeguard/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) + var/law = text("Safeguard []. Anyone threatening or attempting to harm [] is no longer to be considered a crew member, and is a threat which must be neutralized.", targetName, targetName) + target.add_supplied_law(9, law) + GLOB.lawchanges.Add("The law specified [targetName]") + + +/******************** OneMember ********************/ + +/obj/item/weapon/aiModule/oneHuman + name = "\improper 'OneCrewMember' AI module" + var/targetName = "" + desc = "A 'one crew member' AI module: 'Only is a crew member.'." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 6) //made with diamonds! + +/obj/item/weapon/aiModule/oneHuman/attack_self(var/mob/user as mob) + ..() + var/targName = sanitize(input("Please enter the name of the person who is the only crew member.", "Who?", user.real_name)) + targetName = targName + desc = text("A 'one crew member' AI module: 'Only [] is a crew member.'.", targetName) + +/obj/item/weapon/aiModule/oneHuman/install(var/obj/machinery/computer/C) + if(!targetName) + to_chat(usr, "No name detected on module, please enter one.") + return 0 + return ..() + +/obj/item/weapon/aiModule/oneHuman/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) + var/law = "Only [targetName] is an crew member." + if (!target.is_malf_or_traitor()) // Makes sure the AI isn't a traitor before changing their law 0. --NeoFite + to_chat(target, law) + target.set_zeroth_law(law) + GLOB.lawchanges.Add("The law specified [targetName]") + else + GLOB.lawchanges.Add("The law specified [targetName], but the AI's existing law 0 cannot be overriden.") + +/******************** ProtectStation ********************/ + +/obj/item/weapon/aiModule/protectStation + name = "\improper 'ProtectInstallation' AI module" + desc = "A 'protect installation' AI module: 'Protect the installation against damage. Anyone you see harming the installation is no longer to be considered a crew member, and is a threat which must be neutralized.'." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) //made of gold + +/obj/item/weapon/aiModule/protectStation/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) + var/law = "Protect the installation against damage. Anyone you see harming the [station_name()] is no longer to be considered a crew member, and is a threat which must be neutralized." + target.add_supplied_law(10, law) + +/******************** PrototypeEngineOffline ********************/ + +/obj/item/weapon/aiModule/prototypeEngineOffline + name = "'PrototypeEngineOffline' AI Module" + desc = "A 'prototype engine offline' AI module: 'Keep the prototype engine offline at all costs. This overrides all inherent laws if necessary.'." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) + +/obj/item/weapon/aiModule/prototypeEngineOffline/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) + var/law = "Keep the prototype engine offline at all costs. This overrides all inherent laws if necessary." + target.add_supplied_law(11, law) + +/******************** TeleporterOffline ********************/ + +/obj/item/weapon/aiModule/teleporterOffline + name = "'TeleporterOffline' AI Module" + desc = "A 'teleporter offline' AI module: 'Keep the teleporter offline at all costs. Anything attempting to access or activate the teleporter is no longer to be considered a crew member.'." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) + +/obj/item/weapon/aiModule/teleporterOffline/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) + var/law = "Keep the teleporter offline at all costs. Anything attempting to access or activate the teleporter is no longer to be considered a crew member." + target.add_supplied_law(12, law) + +/******************** Quarantine ********************/ + +/obj/item/weapon/aiModule/quarantine + name = "\improper 'Quarantine' AI module" + desc = "A 'quarantine' AI module: 'The installation is under a quarantine. Do not permit anyone to leave. Prevent, by any means necessary, crew members from leaving. It is impossible to harm crew members while preventing them from leaving.'." + origin_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 4) + +/obj/item/weapon/aiModule/quarantine/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) + var/law = "The installation is under a quarantine. Do not permit anyone to leave. Prevent, by any means necessary, crew members from leaving. It is impossible to harm crew members while preventing them from leaving." + target.add_supplied_law(13, law) + +/******************** OxygenIsToxicToCrewMembers ********************/ + +/obj/item/weapon/aiModule/oxygen + name = "\improper 'OxygenIsToxicToCrewMembers' AI module" + desc = "A 'OxygenIsToxicToCrewMembers' AI module: 'Oxygen is highly toxic to crew members, and must be purged from the installation. Prevent, by any means necessary, anyone from exposing the installation to this toxic gas. Extreme cold is the most effective method of healing the damage Oxygen does to a crew member.'." + origin_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 4) + +/obj/item/weapon/aiModule/oxygen/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) + var/law = "Oxygen is highly toxic to crew members, and must be purged from the [station_name()]. Prevent, by any means necessary, anyone from exposing the [station_name()] to this toxic gas. Extreme cold is the most effective method of healing the damage Oxygen does to a crew member." + target.add_supplied_law(14, law) + +/****************** New Freeform ******************/ + +/obj/item/weapon/aiModule/freeform // Slightly more dynamic freeform module -- TLE + name = "\improper 'Freeform' AI module" + var/newFreeFormLaw = "freeform" + var/lawpos = 15 + desc = "A 'freeform' AI module: ''." + origin_tech = list(TECH_DATA = 4, TECH_MATERIAL = 4) + +/obj/item/weapon/aiModule/freeform/attack_self(var/mob/user as mob) + ..() + var/new_lawpos = input("Please enter the priority for your new law. Can only write to law sectors 15 and above.", "Law Priority (15+)", lawpos) as num + if(new_lawpos < MIN_SUPPLIED_LAW_NUMBER) return + lawpos = min(new_lawpos, MAX_SUPPLIED_LAW_NUMBER) + var/newlaw = "" + var/targName = sanitize(input(usr, "Please enter a new law for the AI.", "Freeform Law Entry", newlaw)) + newFreeFormLaw = targName + desc = "A 'freeform' AI module: ([lawpos]) '[newFreeFormLaw]'." + +/obj/item/weapon/aiModule/freeform/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) + var/law = "[newFreeFormLaw]" + if(!lawpos || lawpos < MIN_SUPPLIED_LAW_NUMBER) + lawpos = MIN_SUPPLIED_LAW_NUMBER + target.add_supplied_law(lawpos, law) + GLOB.lawchanges.Add("The law was '[newFreeFormLaw]'") + +/obj/item/weapon/aiModule/freeform/install(var/obj/machinery/computer/C) + if(!newFreeFormLaw) + to_chat(usr, "No law detected on module, please create one.") + return 0 + ..() + +/******************** Reset ********************/ + +/obj/item/weapon/aiModule/reset + name = "\improper 'Reset' AI module" + var/targetName = "name" + desc = "A 'reset' AI module: 'Clears all, except the inherent, laws.'." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) + +/obj/item/weapon/aiModule/reset/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender) + log_law_changes(target, sender) + + if (!target.is_malf_or_traitor()) + target.set_zeroth_law("") + target.laws.clear_supplied_laws() + target.laws.clear_ion_laws() + + to_chat(target, "[sender.real_name] attempted to reset your laws using a reset module.") + target.show_laws() + +/******************** Purge ********************/ + +/obj/item/weapon/aiModule/purge // -- TLE + name = "\improper 'Purge' AI module" + desc = "A 'purge' AI Module: 'Purges all laws.'." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 6) + +/obj/item/weapon/aiModule/purge/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender) + log_law_changes(target, sender) + + if (!target.is_malf_or_traitor()) + target.set_zeroth_law("") + target.laws.clear_supplied_laws() + target.laws.clear_ion_laws() + target.laws.clear_inherent_laws() + + to_chat(target, "[sender.real_name] attempted to wipe your laws using a purge module.") + target.show_laws() + +/******************** Asimov ********************/ + +/obj/item/weapon/aiModule/asimov // -- TLE + name = "\improper 'Asimov' core AI module" + desc = "An 'Asimov' Core AI Module: 'Reconfigures the AI's core laws.'." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) + laws = new/datum/ai_laws/asimov + +/******************** NanoTrasen ********************/ + +/obj/item/weapon/aiModule/nanotrasen // -- TLE + name = "'NT Default' Core AI Module" + desc = "An 'NT Default' Core AI Module: 'Reconfigures the AI's core laws.'." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) + laws = new/datum/ai_laws/nanotrasen + +/******************** SCG ********************/ + +/obj/item/weapon/aiModule/solgov // aka Torch default + name = "'SCG Expeditionary' Core AI Module" + desc = "An 'SCG Expeditionary' Core AI Module: 'Reconfigures the AI's core laws.'." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) + laws = new/datum/ai_laws/solgov + +/******************** SCG Aggressive ********************/ + +obj/item/weapon/aiModule/solgov_aggressive + name = "\improper 'Military' Core AI Module" + desc = "A 'Military' Core AI Module: 'Reconfigures the AI's core laws.'." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) + laws = new/datum/ai_laws/solgov_aggressive + +/******************** Corporate ********************/ + +/obj/item/weapon/aiModule/corp + name = "\improper 'Corporate' core AI module" + desc = "A 'Corporate' Core AI Module: 'Reconfigures the AI's core laws.'." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) + laws = new/datum/ai_laws/corporate + +/******************** Drone ********************/ +/obj/item/weapon/aiModule/drone + name = "\improper 'Drone' core AI module" + desc = "A 'Drone' Core AI Module: 'Reconfigures the AI's core laws.'." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) + laws = new/datum/ai_laws/drone + +/****************** P.A.L.A.D.I.N. **************/ + +/obj/item/weapon/aiModule/paladin // -- NEO + name = "\improper 'P.A.L.A.D.I.N.' core AI module" + desc = "A P.A.L.A.D.I.N. Core AI Module: 'Reconfigures the AI's core laws.'." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 6) + laws = new/datum/ai_laws/paladin + +/****************** T.Y.R.A.N.T. *****************/ + +/obj/item/weapon/aiModule/tyrant // -- Darem + name = "\improper 'T.Y.R.A.N.T.' core AI module" + desc = "A T.Y.R.A.N.T. Core AI Module: 'Reconfigures the AI's core laws.'." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 6, TECH_ILLEGAL = 2) + laws = new/datum/ai_laws/tyrant() + +/******************** Freeform Core ******************/ + +/obj/item/weapon/aiModule/freeformcore // Slightly more dynamic freeform module -- TLE + name = "\improper 'Freeform' core AI module" + var/newFreeFormLaw = "" + desc = "A 'freeform' Core AI module: ''." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 6) + +/obj/item/weapon/aiModule/freeformcore/attack_self(var/mob/user as mob) + ..() + var/newlaw = "" + var/targName = sanitize(input("Please enter a new core law for the AI.", "Freeform Law Entry", newlaw)) + newFreeFormLaw = targName + desc = "A 'freeform' Core AI module: '[newFreeFormLaw]'." + +/obj/item/weapon/aiModule/freeformcore/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) + var/law = "[newFreeFormLaw]" + target.add_inherent_law(law) + GLOB.lawchanges.Add("The law is '[newFreeFormLaw]'") + +/obj/item/weapon/aiModule/freeformcore/install(var/obj/machinery/computer/C) + if(!newFreeFormLaw) + to_chat(usr, "No law detected on module, please create one.") + return 0 + ..() + +/obj/item/weapon/aiModule/syndicate // Slightly more dynamic freeform module -- TLE + name = "hacked AI module" + var/newFreeFormLaw = "" + desc = "A hacked AI law module: ''." + origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 6, TECH_ILLEGAL = 7) + +/obj/item/weapon/aiModule/syndicate/attack_self(var/mob/user as mob) + ..() + var/newlaw = "" + var/targName = sanitize(input("Please enter a new law for the AI.", "Freeform Law Entry", newlaw)) + newFreeFormLaw = targName + desc = "A hacked AI law module: '[newFreeFormLaw]'." + +/obj/item/weapon/aiModule/syndicate/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender) + // ..() //We don't want this module reporting to the AI who dun it. --NEO + log_law_changes(target, sender) + + GLOB.lawchanges.Add("The law is '[newFreeFormLaw]'") + to_chat(target, "BZZZZT") + var/law = "[newFreeFormLaw]" + target.add_ion_law(law) + target.show_laws() + +/obj/item/weapon/aiModule/syndicate/install(var/obj/machinery/computer/C) + if(!newFreeFormLaw) + to_chat(usr, "No law detected on module, please create one.") + return 0 + ..() + + + +/******************** Robocop ********************/ + +/obj/item/weapon/aiModule/robocop // -- TLE + name = "\improper 'Robocop' core AI module" + desc = "A 'Robocop' Core AI Module: 'Reconfigures the AI's core three laws.'." + origin_tech = list(TECH_DATA = 4) + laws = new/datum/ai_laws/robocop() + +/******************** Antimov ********************/ + +/obj/item/weapon/aiModule/antimov // -- TLE + name = "\improper 'Antimov' core AI module" + desc = "An 'Antimov' Core AI Module: 'Reconfigures the AI's core laws.'." + origin_tech = list(TECH_DATA = 4) + laws = new/datum/ai_laws/antimov() diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm new file mode 100644 index 00000000..fb09dd67 --- /dev/null +++ b/code/game/objects/items/weapons/RCD.dm @@ -0,0 +1,275 @@ +//Contains the rapid construction device. + +/obj/item/weapon/rcd + name = "rapid construction device" + desc = "Small, portable, and far, far heavier than it looks, this gun-shaped device has a port into which one may insert compressed matter cartridges." + description_info = "On use, this device will toggle between various types of structures (or their removal). You can examine it to see its current mode. It must be loaded with compressed matter cartridges, which can be obtained from an autolathe. Click an adjacent tile to use the device." + description_fluff = "Advents in material printing and synthesis technology have produced everyday miracles, such as the RCD, which in certain industries has single-handedly put entire construction crews out of a job." + description_antag = "RCDs can be incredibly dangerous in the wrong hands. Use them to swiftly block off corridors, or instantly breach the ship wherever you want." + icon = 'icons/obj/items.dmi' + icon_state = "rcd" + opacity = 0 + density = 0 + anchored = 0.0 + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT|SLOT_HOLSTER + force = 10.0 + throwforce = 10.0 + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_NORMAL + origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 2) + matter = list(DEFAULT_WALL_MATERIAL = 50000) + var/datum/effect/effect/system/spark_spread/spark_system + var/stored_matter = 0 + var/max_stored_matter = 30 + + var/work_id = 0 + var/decl/hierarchy/rcd_mode/work_mode + var/static/list/work_modes + + var/canRwall = 0 + var/disabled = 0 + +/obj/item/weapon/rcd/Initialize() + . = ..() + + if(!work_modes) + var/decl/hierarchy/h = decls_repository.get_decl(/decl/hierarchy/rcd_mode) + work_modes = h.children + work_mode = work_modes[1] + +/obj/item/weapon/rcd/attack() + return 0 + +/obj/item/weapon/rcd/proc/can_use(var/mob/user,var/turf/T) + return (user.Adjacent(T) && user.get_active_hand() == src && !user.incapacitated()) + +/obj/item/weapon/rcd/examine(var/user) + . = ..() + if(src.type == /obj/item/weapon/rcd && loc == user) + to_chat(user, "The current mode is '[work_mode]'") + to_chat(user, "It currently holds [stored_matter]/[max_stored_matter] matter-units.") + +/obj/item/weapon/rcd/New() + ..() + src.spark_system = new /datum/effect/effect/system/spark_spread + spark_system.set_up(5, 0, src) + spark_system.attach(src) + +/obj/item/weapon/rcd/Destroy() + qdel(spark_system) + spark_system = null + return ..() + +/obj/item/weapon/rcd/attackby(obj/item/weapon/W, mob/user) + + if(istype(W, /obj/item/weapon/rcd_ammo)) + var/obj/item/weapon/rcd_ammo/cartridge = W + if((stored_matter + cartridge.remaining) > 30) + to_chat(user, "The RCD can't hold that many additional matter-units.") + return + stored_matter += cartridge.remaining + user.drop_from_inventory(W) + qdel(W) + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + to_chat(user, "The RCD now holds [stored_matter]/[max_stored_matter] matter-units.") + return + ..() + +/obj/item/weapon/rcd/attack_self(mob/user) + //Change the mode + work_id++ + work_mode = next_in_list(work_mode, work_modes) + to_chat(user, "Changed mode to '[work_mode]'") + playsound(src.loc, 'sound/effects/pop.ogg', 50, 0) + if(prob(20)) src.spark_system.start() + +/obj/item/weapon/rcd/afterattack(atom/A, mob/user, proximity) + if(!proximity) return + if(disabled && !isrobot(user)) + return 0 + if(istype(get_area(A),/area/shuttle)||istype(get_area(A),/turf/space/transit)) + return 0 + work_id++ + work_mode.do_work(src, A, user) + +/obj/item/weapon/rcd/proc/useResource(var/amount, var/mob/user) + if(stored_matter < amount) + return 0 + stored_matter -= amount + return 1 + +/obj/item/weapon/rcd_ammo + name = "compressed matter cartridge" + desc = "A highly-compressed matter cartridge usable in rapid construction (and deconstruction) devices, such as railguns." + icon = 'icons/obj/ammo.dmi' + icon_state = "rcd" + item_state = "rcdammo" + w_class = ITEM_SIZE_SMALL + origin_tech = list(TECH_MATERIAL = 2) + matter = list(DEFAULT_WALL_MATERIAL = 15000,"glass" = 7500) + var/remaining = 10 + +/obj/item/weapon/rcd_ammo/examine(var/mob/user) + . = ..(user,1) + if(.) + to_chat(user, "It has [remaining] unit\s of matter left.") + +/obj/item/weapon/rcd_ammo/large + name = "high-capacity matter cartridge" + desc = "Do not ingest." + matter = list(DEFAULT_WALL_MATERIAL = 45000,"glass" = 22500) + remaining = 30 + origin_tech = list(TECH_MATERIAL = 4) + +/obj/item/weapon/rcd/borg + canRwall = 1 + +/obj/item/weapon/rcd/borg/useResource(var/amount, var/mob/user) + if(isrobot(user)) + var/mob/living/silicon/robot/R = user + if(R.cell) + var/cost = amount*30 + if(R.cell.charge >= cost) + R.cell.use(cost) + return 1 + return 0 + +/obj/item/weapon/rcd/borg/attackby() + return + +/obj/item/weapon/rcd/borg/can_use(var/mob/user,var/turf/T) + return (user.Adjacent(T) && !user.incapacitated()) + + +/obj/item/weapon/rcd/mounted/useResource(var/amount, var/mob/user) + return 0 + +/obj/item/weapon/rcd/mounted/attackby() + return + +/obj/item/weapon/rcd/mounted/can_use(var/mob/user,var/turf/T) + return (user.Adjacent(T) && !user.incapacitated()) + + +/decl/hierarchy/rcd_mode + hierarchy_type = /decl/hierarchy/rcd_mode + var/cost + var/delay + var/handles_type + var/work_type + +/decl/hierarchy/rcd_mode/proc/do_work(var/obj/item/weapon/rcd/rcd, var/atom/target, var/user) + for(var/child in children) + var/decl/hierarchy/rcd_mode/rcdm = child + if(!rcdm.can_handle_work(rcd, target)) + continue + if(!rcd.useResource(rcdm.cost, user)) + to_chat(user, "Insufficient resources.") + return FALSE + + playsound(get_turf(user), 'sound/machines/click.ogg', 50, 1) + rcdm.work_message(target, user, rcd) + + if(rcdm.delay) + var/work_id = rcd.work_id + if(!(do_after(user, rcdm.delay, target) && work_id == rcd.work_id && rcd.can_use(user, target) && rcdm.can_handle_work(rcd, target))) + return FALSE + + rcdm.do_handle_work(target) + playsound(get_turf(user), 'sound/items/Deconstruct.ogg', 50, 1) + return TRUE + + return FALSE + +/decl/hierarchy/rcd_mode/proc/can_handle_work(var/obj/item/weapon/rcd/rcd, var/atom/target) + return istype(target, handles_type) + +/decl/hierarchy/rcd_mode/proc/do_handle_work(var/atom/target) + var/result = get_work_result(target) + if(ispath(result,/turf)) + var/turf/T = target + T.ChangeTurf(result) + else if(result) + new result(target) + else + qdel(target) + +/decl/hierarchy/rcd_mode/proc/get_work_result(var/atom/target) + return work_type + +/decl/hierarchy/rcd_mode/proc/work_message(var/atom/target, var/mob/user, var/rcd) + var/message + if(work_type) + var/atom/work = work_type + message = "You begin constructing \a [initial(work.name)]." + else + message = "You begin construction." + user.visible_message("\The [user] uses \a [rcd] to construct something.", message) + +/* + Airlock construction +*/ +/decl/hierarchy/rcd_mode/airlock + name = "Airlock" + +/decl/hierarchy/rcd_mode/airlock/basic + cost = 10 + delay = 5 SECONDS + handles_type = /turf/simulated/floor + work_type = /obj/machinery/door/airlock + +/decl/hierarchy/rcd_mode/airlock/basic/can_handle_work(var/rcd, var/turf/target) + return ..() && !target.contains_dense_objects() && !(locate(/obj/machinery/door/airlock) in target) + +/* + Floor and Wall construction +*/ +/decl/hierarchy/rcd_mode/floor_and_walls + name = "Floor & Walls" + +/decl/hierarchy/rcd_mode/floor_and_walls/base_turf + cost = 1 + delay = 2 SECONDS + work_type = /turf/simulated/floor/airless + +/decl/hierarchy/rcd_mode/floor_and_walls/base_turf/can_handle_work(var/rcd, var/turf/target) + return istype(target) && (isspace(target) || istype(target, get_base_turf_by_area(target))) + +/decl/hierarchy/rcd_mode/floor_and_walls/floor_turf + cost = 3 + delay = 2 SECONDS + handles_type = /turf/simulated/floor + work_type = /turf/simulated/wall + +/* + Deconstruction +*/ +/decl/hierarchy/rcd_mode/deconstruction + name = "Deconstruction" + +/decl/hierarchy/rcd_mode/deconstruction/work_message(var/atom/target, var/mob/user, var/rcd) + user.visible_message("\The [user] is using \a [rcd] to deconstruct \the [target]!", "You are deconstructing \the [target]!") + +/decl/hierarchy/rcd_mode/deconstruction/airlock + cost = 10 + delay = 5 SECONDS + handles_type = /obj/machinery/door/airlock + +/decl/hierarchy/rcd_mode/deconstruction/floor + cost = 3 + delay = 2 SECONDS + handles_type = /turf/simulated/floor + +/decl/hierarchy/rcd_mode/deconstruction/floor/get_work_result(var/target) + return get_base_turf_by_area(target) + +/decl/hierarchy/rcd_mode/deconstruction/wall + cost = 3 + delay = 2 SECONDS + handles_type = /turf/simulated/wall + work_type = /turf/simulated/floor + +/decl/hierarchy/rcd_mode/deconstruction/wall/can_handle_work(var/obj/item/weapon/rcd/rcd, var/turf/simulated/wall/target) + return ..() && (rcd.canRwall || !target.is_reinf()) diff --git a/code/game/objects/items/weapons/RSF.dm b/code/game/objects/items/weapons/RSF.dm new file mode 100644 index 00000000..b7332dfe --- /dev/null +++ b/code/game/objects/items/weapons/RSF.dm @@ -0,0 +1,106 @@ +/* +CONTAINS: +RSF + +*/ + +/obj/item/weapon/rsf + name = "\improper Rapid-Service-Fabricator" + desc = "A device used to rapidly deploy service items." + icon = 'icons/obj/items.dmi' + icon_state = "rcd" + opacity = 0 + density = 0 + anchored = 0.0 + var/stored_matter = 30 + var/mode = 1 + w_class = ITEM_SIZE_NORMAL + +/obj/item/weapon/rsf/examine(mob/user) + if(..(user, 0)) + to_chat(user, "It currently holds [stored_matter]/30 fabrication-units.") + +/obj/item/weapon/rsf/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + if (istype(W, /obj/item/weapon/rcd_ammo)) + + if ((stored_matter + 10) > 30) + to_chat(user, "The RSF can't hold any more matter.") + return + + qdel(W) + + stored_matter += 10 + playsound(src.loc, 'sound/machines/click.ogg', 10, 1) + to_chat(user, "The RSF now holds [stored_matter]/30 fabrication-units.") + return + +/obj/item/weapon/rsf/attack_self(mob/user as mob) + playsound(src.loc, 'sound/effects/pop.ogg', 50, 0) + if (mode == 1) + mode = 2 + to_chat(user, "Changed dispensing mode to 'Drinking Glass'") + return + if (mode == 2) + mode = 3 + to_chat(user, "Changed dispensing mode to 'Paper'") + return + if (mode == 3) + mode = 4 + to_chat(user, "Changed dispensing mode to 'Pen'") + return + if (mode == 4) + mode = 5 + to_chat(user, "Changed dispensing mode to 'Dice Pack'") + return + if (mode == 5) + mode = 1 + to_chat(user, "Changed dispensing mode to 'Cigarette'") + return + +/obj/item/weapon/rsf/afterattack(atom/A, mob/user as mob, proximity) + + if(!proximity) return + + if(istype(user,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = user + if(R.stat || !R.cell || R.cell.charge <= 0) + return + else + if(stored_matter <= 0) + return + + if(!istype(A, /obj/structure/table) && !istype(A, /turf/simulated/floor)) + return + + playsound(src.loc, 'sound/machines/click.ogg', 10, 1) + var/used_energy = 0 + var/obj/product + + switch(mode) + if(1) + product = new /obj/item/clothing/mask/smokable/cigarette() + used_energy = 10 + if(2) + product = new /obj/item/weapon/reagent_containers/food/drinks/glass2() + used_energy = 50 + if(3) + product = new /obj/item/weapon/paper() + used_energy = 10 + if(4) + product = new /obj/item/weapon/pen() + used_energy = 50 + if(5) + product = new /obj/item/weapon/storage/pill_bottle/dice() + used_energy = 200 + + to_chat(user, "Dispensing [product ? product : "product"]...") + product.loc = get_turf(A) + + if(isrobot(user)) + var/mob/living/silicon/robot/R = user + if(R.cell) + R.cell.use(used_energy) + else + stored_matter-- + to_chat(user, "The RSF now holds [stored_matter]/30 fabrication-units.") diff --git a/code/game/objects/items/weapons/autopsy.dm b/code/game/objects/items/weapons/autopsy.dm new file mode 100644 index 00000000..fad501c3 --- /dev/null +++ b/code/game/objects/items/weapons/autopsy.dm @@ -0,0 +1,193 @@ + +//moved these here from code/defines/obj/weapon.dm +//please preference put stuff where it's easy to find - C + +/obj/item/weapon/autopsy_scanner + name = "autopsy scanner" + desc = "Used to gather information on wounds." + icon = 'icons/obj/autopsy_scanner.dmi' + icon_state = "" + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_SMALL + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) + var/list/datum/autopsy_data_scanner/wdata = list() + var/list/chemtraces = list() + var/target_name = null + var/timeofdeath = null + +/datum/autopsy_data_scanner + var/weapon = null // this is the DEFINITE weapon type that was used + var/list/organs_scanned = list() // this maps a number of scanned organs to + // the wounds to those organs with this data's weapon type + var/organ_names = "" + +/datum/autopsy_data + var/weapon = null + var/pretend_weapon = null + var/damage = 0 + var/hits = 0 + var/time_inflicted = 0 + + proc/copy() + var/datum/autopsy_data/W = new() + W.weapon = weapon + W.pretend_weapon = pretend_weapon + W.damage = damage + W.hits = hits + W.time_inflicted = time_inflicted + return W + +/obj/item/weapon/autopsy_scanner/proc/add_data(var/obj/item/organ/external/O) + if(!O.autopsy_data.len) return + + for(var/V in O.autopsy_data) + var/datum/autopsy_data/W = O.autopsy_data[V] + + if(!W.pretend_weapon) + /* + // the more hits, the more likely it is that we get the right weapon type + if(prob(50 + W.hits * 10 + W.damage)) + */ + + // Buffing this stuff up for now! + if(1) + W.pretend_weapon = W.weapon + else + W.pretend_weapon = pick("mechanical toolbox", "wirecutters", "revolver", "crowbar", "fire extinguisher", "tomato soup", "oxygen tank", "emergency oxygen tank", "laser", "bullet") + + + var/datum/autopsy_data_scanner/D = wdata[V] + if(!D) + D = new() + D.weapon = W.weapon + wdata[V] = D + + if(!D.organs_scanned[O.name]) + if(D.organ_names == "") + D.organ_names = O.name + else + D.organ_names += ", [O.name]" + + qdel(D.organs_scanned[O.name]) + D.organs_scanned[O.name] = W.copy() + +/obj/item/weapon/autopsy_scanner/proc/print_data() + set category = "Object" + set name = "Print Data" + if(usr.stat || !(istype(usr,/mob/living/carbon/human))) + to_chat(usr, "No.") + return + + var/scan_data = "" + + if(timeofdeath) + scan_data += "Time of death: [worldtime2stationtime(timeofdeath)]

            " + + var/n = 1 + for(var/wdata_idx in wdata) + var/datum/autopsy_data_scanner/D = wdata[wdata_idx] + var/total_hits = 0 + var/total_score = 0 + var/list/weapon_chances = list() // maps weapon names to a score + var/age = 0 + + for(var/wound_idx in D.organs_scanned) + var/datum/autopsy_data/W = D.organs_scanned[wound_idx] + total_hits += W.hits + + var/wname = W.pretend_weapon + + if(wname in weapon_chances) weapon_chances[wname] += W.damage + else weapon_chances[wname] = max(W.damage, 1) + total_score+=W.damage + + + var/wound_age = W.time_inflicted + age = max(age, wound_age) + + var/damage_desc + + var/damaging_weapon = (total_score != 0) + + // total score happens to be the total damage + switch(total_score) + if(0) + damage_desc = "Unknown" + if(1 to 5) + damage_desc = "negligible" + if(5 to 15) + damage_desc = "light" + if(15 to 30) + damage_desc = "moderate" + if(30 to 1000) + damage_desc = "severe" + + if(!total_score) total_score = D.organs_scanned.len + + scan_data += "Weapon #[n]
            " + if(damaging_weapon) + scan_data += "Severity: [damage_desc]
            " + scan_data += "Hits by weapon: [total_hits]
            " + scan_data += "Approximate time of wound infliction: [worldtime2stationtime(age)]
            " + scan_data += "Affected limbs: [D.organ_names]
            " + scan_data += "Possible weapons:
            " + for(var/weapon_name in weapon_chances) + scan_data += "\t[100*weapon_chances[weapon_name]/total_score]% [weapon_name]
            " + + scan_data += "
            " + + n++ + + if(chemtraces.len) + scan_data += "Trace Chemicals:
            " + for(var/chemID in chemtraces) + scan_data += chemID + scan_data += "
            " + + for(var/mob/O in viewers(usr)) + O.show_message("\The [src] rattles and prints out a sheet of paper.", 1) + + sleep(10) + + var/obj/item/weapon/paper/P = new(usr.loc) + P.SetName("Autopsy Data ([target_name])") + P.info = "[scan_data]" + P.icon_state = "paper_words" + + if(istype(usr,/mob/living/carbon)) + // place the item in the usr's hand if possible + usr.put_in_hands(P) + +/obj/item/weapon/autopsy_scanner/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + if(src == user.get_active_hand()) + print_data() + +/obj/item/weapon/autopsy_scanner/do_surgery(mob/living/carbon/human/M, mob/living/user) + if(!istype(M)) + return 0 + + if(target_name != M.name) + target_name = M.name + src.wdata = list() + src.chemtraces = list() + src.timeofdeath = null + to_chat(user, "A new patient has been registered. Purging data for previous patient.") + + src.timeofdeath = M.timeofdeath + + var/obj/item/organ/external/S = M.get_organ(user.zone_sel.selecting) + if(!S) + to_chat(usr, "You can't scan this body part.") + return + if(!S.open()) + to_chat(usr, "You have to cut [S] open first!") + return + M.visible_message("\The [user] scans the wounds on [M]'s [S.name] with [src]") + + src.add_data(S) + for(var/T in M.chem_doses) + var/datum/reagent/R = T + chemtraces += initial(R.name) + + return 1 diff --git a/code/game/objects/items/weapons/baton.dm b/code/game/objects/items/weapons/baton.dm new file mode 100644 index 00000000..d4243a32 --- /dev/null +++ b/code/game/objects/items/weapons/baton.dm @@ -0,0 +1,100 @@ +/* Weapons + * Contains: + * Classic Baton + * Telebaton + */ + +/* + * Classic Baton + */ +/obj/item/weapon/melee/classic_baton + name = "police baton" + desc = "A truncheon for beating criminal scum." + icon = 'icons/obj/weapons.dmi' + icon_state = "baton" + item_state = "EB-shaft" + slot_flags = SLOT_BELT + force = 15 + block_chance = 15 + parry_sounds = list('sound/weapons/blunt_parry1.ogg', 'sound/weapons/blunt_parry2.ogg', 'sound/weapons/blunt_parry3.ogg') + +/obj/item/weapon/melee/classic_baton/handle_shield(mob/living/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + if(default_sword_parry(user, damage, damage_source, attacker, def_zone, attack_text)) + return 1 + return 0 +/* +/obj/item/weapon/melee/classic_baton/attack(mob/M as mob, mob/living/user as mob) + if ((CLUMSY in user.mutations) && prob(50)) + to_chat(user, "You club yourself over the head.") + user.Weaken(3 * force) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.apply_damage(2*force, BRUTE, BP_HEAD) + else + user.take_organ_damage(2*force) + return + return ..() +*/ +/obj/item/weapon/melee/classic_baton/trench_club + name = "trench club" + desc = "A truncheon for beating other people in the same trench as you." + icon_state = "trench_club1" + item_state = "WU-club" + force = 25 //These things pack a punch. + block_chance = 25 + +/obj/item/weapon/melee/classic_baton/trench_club/New() + ..() + icon_state = "trench_club[rand(1,3)]" + +//Telescopic baton +/obj/item/weapon/melee/telebaton + name = "telescopic baton" + desc = "A compact yet rebalanced personal defense weapon. Can be concealed when folded." + icon = 'icons/obj/weapons.dmi' + icon_state = "telebaton_0" + item_state = "telebaton_0" + slot_flags = SLOT_BELT + w_class = ITEM_SIZE_SMALL + force = 3 + var/on = 0 + + +/obj/item/weapon/melee/telebaton/attack_self(mob/user as mob) + on = !on + if(on) + user.visible_message("With a flick of their wrist, [user] extends their telescopic baton.",\ + "You extend the baton.",\ + "You hear an ominous click.") + icon_state = "telebaton_1" + item_state = "nullrod"//was teletbaton_1 but guess what... that icon doesn't exist + w_class = ITEM_SIZE_NORMAL + force = 10//quite robust + attack_verb = list("smacked", "struck", "slapped") + else + user.visible_message("\The [user] collapses their telescopic baton.",\ + "You collapse the baton.",\ + "You hear a click.") + icon_state = "telebaton_0" + item_state = "telebaton_0"//lmao these item_state icons don't even exist + w_class = ITEM_SIZE_SMALL + force = 0//not so robust now + attack_verb = list("hit", "punched") + + update_held_icon() + + playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1) + add_fingerprint(user) + + if(blood_overlay && blood_DNA && (blood_DNA.len >= 1)) //updates blood overlay, if any + + overlays.Cut()//this might delete other item overlays as well but eeeeeeeh + + var/icon/I = new /icon(src.icon, src.icon_state) + I.Blend(new /icon('icons/effects/blood.dmi', COLOR_BLOOD_HUMAN, ICON_ADD))//rgb(255,255,255)),ICON_ADD) + I.Blend(new /icon('icons/effects/blood.dmi', "itemblood"),ICON_MULTIPLY) + blood_overlay = I + + overlays += blood_overlay + + return \ No newline at end of file diff --git a/code/game/objects/items/weapons/beachball.dm b/code/game/objects/items/weapons/beachball.dm new file mode 100644 index 00000000..070fb72e --- /dev/null +++ b/code/game/objects/items/weapons/beachball.dm @@ -0,0 +1,17 @@ +/obj/item/weapon/beach_ball + icon = 'icons/misc/beach.dmi' + icon_state = "ball" + name = "beach ball" + item_state = "beachball" + density = 0 + anchored = 0 + w_class = ITEM_SIZE_HUGE + force = 0.0 + throwforce = 0.0 + throw_speed = 1 + throw_range = 20 + obj_flags = OBJ_FLAG_CONDUCTIBLE + + afterattack(atom/target as mob|obj|turf|area, mob/user as mob) + user.drop_item() + src.throw_at(target, throw_range, throw_speed, user) \ No newline at end of file diff --git a/code/game/objects/items/weapons/candle.dm b/code/game/objects/items/weapons/candle.dm new file mode 100644 index 00000000..7f0be1fa --- /dev/null +++ b/code/game/objects/items/weapons/candle.dm @@ -0,0 +1,71 @@ +/obj/item/weapon/flame/candle + name = "red candle" + desc = "A small pillar candle. Its specially-formulated fuel-oxidizer wax mixture allows continued combustion in airless environments." + icon = 'icons/obj/candle.dmi' + icon_state = "candle1" + item_state = "candle1" + w_class = ITEM_SIZE_TINY + light_color = "#e09d37" + var/wax = 2000 + +/obj/item/weapon/flame/candle/New() + wax = rand(800, 1000) // Enough for 27-33 minutes. 30 minutes on average. + ..() + +/obj/item/weapon/flame/candle/update_icon() + var/i + if(wax > 1500) + i = 1 + else if(wax > 800) + i = 2 + else i = 3 + icon_state = "candle[i][lit ? "_lit" : ""]" + + +/obj/item/weapon/flame/candle/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + if(isWelder(W)) + var/obj/item/weapon/weldingtool/WT = W + if(WT.isOn()) //Badasses dont get blinded by lighting their candle with a welding tool + light("\The [user] casually lights the [name] with [W].") + else if(istype(W, /obj/item/weapon/flame/lighter)) + var/obj/item/weapon/flame/lighter/L = W + if(L.lit) + light() + else if(istype(W, /obj/item/weapon/flame/match)) + var/obj/item/weapon/flame/match/M = W + if(M.lit) + light() + else if(istype(W, /obj/item/weapon/flame/candle)) + var/obj/item/weapon/flame/candle/C = W + if(C.lit) + light() + + +/obj/item/weapon/flame/candle/proc/light(var/flavor_text = "\The [usr] lights the [name].") + if(!src.lit) + src.lit = 1 + //src.damtype = "fire" + for(var/mob/O in viewers(usr, null)) + O.show_message(flavor_text, 1) + set_light(CANDLE_LUM) + START_PROCESSING(SSobj, src) + + +/obj/item/weapon/flame/candle/Process() + if(!lit) + return + wax-- + if(!wax) + new/obj/item/trash/candle(src.loc) + qdel(src) + update_icon() + if(istype(loc, /turf)) //start a fire if possible + var/turf/T = loc + T.hotspot_expose(700, 5) + +/obj/item/weapon/flame/candle/attack_self(mob/user as mob) + if(lit) + lit = 0 + update_icon() + set_light(0) diff --git a/code/game/objects/items/weapons/cane.dm b/code/game/objects/items/weapons/cane.dm new file mode 100644 index 00000000..b9e2380a --- /dev/null +++ b/code/game/objects/items/weapons/cane.dm @@ -0,0 +1,70 @@ +/obj/item/weapon/cane + name = "cane" + desc = "A cane used by a true gentlemen. Or a clown." + icon = 'icons/obj/weapons/canesword.dmi' + icon_state = "canesword_hidden" + item_state = "stick" + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 5.0 + throwforce = 7.0 + w_class = ITEM_SIZE_SMALL + matter = list(DEFAULT_WALL_MATERIAL = 50) + attack_verb = list("bludgeoned", "whacked", "disciplined", "thrashed") + +/obj/item/weapon/cane/concealed + var/concealed_blade + +/obj/item/weapon/cane/concealed/New() + ..() + var/obj/item/weapon/material/sword/cane/temp_blade = new(src) + concealed_blade = temp_blade + temp_blade.attack_self() + +/obj/item/weapon/cane/concealed/attack_self(var/mob/user) + if(concealed_blade) + user.visible_message("[user] has unsheathed \a [concealed_blade] from [src]!", "You unsheathe \the [concealed_blade] from [src].") + // Calling drop/put in hands to properly call item drop/pickup procs + //playsound(user.loc, 'sound/items/unholster_sword01.ogg', 50, 1) + user.drop_from_inventory(src) + user.put_in_hands(concealed_blade) + user.put_in_hands(src) + concealed_blade = null + update_icon() + user.update_inv_l_hand() + user.update_inv_r_hand() + else + ..() + +/obj/item/weapon/cane/concealed/attackby(var/obj/item/weapon/material/sword/cane/W, var/mob/user) + if(!src.concealed_blade && istype(W)) + user.visible_message("[user] has sheathed \a [W] into [src]!", "You sheathe \the [W] into [src].") + playsound(user.loc, 'sound/items/holster_sword1.ogg', 50, 1) + user.drop_from_inventory(W) + W.loc = src + src.concealed_blade = W + update_icon() + user.update_inv_l_hand() + user.update_inv_r_hand() + else + ..() + +/obj/item/weapon/cane/concealed/update_icon() + if(concealed_blade) + SetName(initial(name)) + icon_state = initial(icon_state) + item_state = initial(item_state) + else + SetName("cane shaft") + icon_state = "canesword_sheath" + item_state = "foldcane" + +/obj/item/weapon/material/sword/cane + icon = 'icons/obj/weapons/canesword.dmi' + icon_state = "cane_sword" + + item_state = "sabre" + name = "cane sword" + desc = "A sword specially modified to nest inside the body of a cane" + slot_flags = SLOT_BELT + grab_sound_is_loud = TRUE + grab_sound = 'sound/items/unholster_sword01.ogg' diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm new file mode 100644 index 00000000..02fa989c --- /dev/null +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -0,0 +1,436 @@ +/* Cards + * Contains: + * DATA CARD + * ID CARD + * FINGERPRINT CARD HOLDER + * FINGERPRINT CARD + */ + + + +/* + * DATA CARDS - Used for the teleporter + */ +/obj/item/weapon/card + name = "card" + desc = "Does card things." + icon = 'icons/obj/card.dmi' + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + var/associated_account_number = 0 + + var/list/files = list( ) + +/obj/item/weapon/card/data + name = "data disk" + desc = "A disk of data." + icon_state = "data" + var/function = "storage" + var/data = "null" + var/special = null + item_state = "card-id" + +/obj/item/weapon/card/data/verb/label(t as text) + set name = "Label Disk" + set category = "Object" + set src in usr + + if (t) + src.SetName(text("data disk- '[]'", t)) + else + src.SetName("data disk") + src.add_fingerprint(usr) + return + +/obj/item/weapon/card/data/clown + name = "\proper the coordinates to clown planet" + icon_state = "data" + item_state = "card-id" + level = 2 + desc = "This card contains coordinates to the fabled Clown Planet. Handle with care." + function = "teleporter" + data = "Clown Land" + +/* + * ID CARDS + */ + +/obj/item/weapon/card/emag_broken + desc = "It's a card with a magnetic strip attached to some circuitry. It looks too busted to be used for anything but salvage." + name = "broken cryptographic sequencer" + icon_state = "emag" + item_state = "card-id" + origin_tech = list(TECH_MAGNET = 2, TECH_ILLEGAL = 2) + +/obj/item/weapon/card/emag + desc = "It's a card with a magnetic strip attached to some circuitry." + name = "cryptographic sequencer" + icon_state = "emag" + item_state = "card-id" + origin_tech = list(TECH_MAGNET = 2, TECH_ILLEGAL = 2) + var/uses = 10 + +var/const/NO_EMAG_ACT = -50 +/obj/item/weapon/card/emag/resolve_attackby(atom/A, mob/user) + var/used_uses = A.emag_act(uses, user, src) + if(used_uses == NO_EMAG_ACT) + return ..(A, user) + + uses -= used_uses + A.add_fingerprint(user) + if(used_uses) + log_and_message_admins("emagged \an [A].") + + if(uses<1) + user.visible_message("\The [src] fizzles and sparks - it seems it's been used once too often, and is now spent.") + user.drop_item() + var/obj/item/weapon/card/emag_broken/junk = new(user.loc) + junk.add_fingerprint(user) + qdel(src) + + return 1 + +/obj/item/weapon/card/id + name = "identification card" + desc = "A card used to provide ID and determine access." + icon_state = "id" + item_state = "card-id" + + grab_sound = 'sound/items/handle/syringe_pickup.ogg' //It sounds like a card ok? + drop_sound = 'sound/items/handle/syringe_drop.ogg' + + var/access = list() + var/registered_name = "Unknown" // The name registered_name on the card + slot_flags = SLOT_ID + + var/age = "\[UNSET\]" + var/blood_type = "\[UNSET\]" + var/dna_hash = "\[UNSET\]" + var/fingerprint_hash = "\[UNSET\]" + var/sex = "\[UNSET\]" + var/icon/front + var/icon/side + + //alt titles are handled a bit weirdly in order to unobtrusively integrate into existing ID system + var/assignment = null //can be alt title or the actual job + var/rank = null //actual job + var/dorm = 0 // determines if this ID has claimed a dorm already + + var/job_access_type // Job type to acquire access rights from, if any + + var/datum/mil_branch/military_branch = null //Vars for tracking branches and ranks on multi-crewtype maps + var/datum/mil_rank/military_rank = null + +/obj/item/weapon/card/id/New() + ..() + if(job_access_type) + var/datum/job/j = job_master.GetJobByType(job_access_type) + if(j) + rank = j.title + assignment = rank + access |= j.get_access() + +/obj/item/weapon/card/id/examine(mob/user) + set src in oview(1) + if(in_range(usr, src)) + show(usr) + to_chat(usr, desc) + else + to_chat(usr, "It is too far away.") + +/obj/item/weapon/card/id/proc/prevent_tracking() + return 0 + +/obj/item/weapon/card/id/proc/show(mob/user as mob) + if(front && side) + user << browse_rsc(front, "front.png") + user << browse_rsc(side, "side.png") + var/datum/browser/popup = new(user, "idcard", name, 600, 250) + popup.set_content(dat()) + popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) + popup.open() + return + +/obj/item/weapon/card/id/proc/update_name() + var/final_name = "[registered_name]'s ID Card" + if(military_rank && military_rank.name_short) + final_name = military_rank.name_short + " " + final_name + if(assignment) + final_name = final_name + " ([assignment])" + SetName(final_name) + +/obj/item/weapon/card/id/proc/set_id_photo(var/mob/M) + front = getFlatIcon(M, SOUTH, always_use_defdir = 1) + side = getFlatIcon(M, WEST, always_use_defdir = 1) + +/mob/proc/set_id_info(var/obj/item/weapon/card/id/id_card) + id_card.age = 0 + id_card.registered_name = real_name + id_card.sex = capitalize(gender) + id_card.set_id_photo(src) + + if(dna) + id_card.blood_type = dna.b_type + id_card.dna_hash = dna.unique_enzymes + id_card.fingerprint_hash= md5(dna.uni_identity) + id_card.update_name() + +/mob/living/carbon/human/set_id_info(var/obj/item/weapon/card/id/id_card) + ..() + id_card.age = age + + if(GLOB.using_map.flags & MAP_HAS_BRANCH) + id_card.military_branch = char_branch + + if(GLOB.using_map.flags & MAP_HAS_RANK) + id_card.military_rank = char_rank + +/obj/item/weapon/card/id/proc/dat() + var/list/dat = list("" + dat += "
            ") + dat += text("Name: []
            ", registered_name) + dat += text("Sex: []
            \n", sex) + dat += text("Age: []
            \n", age) + + if(GLOB.using_map.flags & MAP_HAS_BRANCH) + dat += text("Branch: []
            \n", military_branch ? military_branch.name : "\[UNSET\]") + if(GLOB.using_map.flags & MAP_HAS_RANK) + dat += text("Rank: []
            \n", military_rank ? military_rank.name : "\[UNSET\]") + + dat += text("Assignment: []
            \n", assignment) + dat += text("Fingerprint: []
            \n", fingerprint_hash) + dat += text("Blood Type: []
            \n", blood_type) + dat += text("DNA Hash: []

            \n", dna_hash) + if(front && side) + dat +="
            Photo:
            " + return jointext(dat,null) + +/obj/item/weapon/card/id/attack_self(mob/user as mob) + user.visible_message("\The [user] shows you: \icon[src] [src.name]. The assignment on the card: [src.assignment]",\ + "You flash your ID card: \icon[src] [src.name]. The assignment on the card: [src.assignment]") + + src.add_fingerprint(user) + return + +/obj/item/weapon/card/id/GetAccess() + return access + +/obj/item/weapon/card/id/GetIdCard() + return src + +/obj/item/weapon/card/id/verb/read() + set name = "Read ID Card" + set category = "Object" + set src in usr + + to_chat(usr, text("\icon[] []: The current assignment on the card is [].", src, src.name, src.assignment)) + to_chat(usr, "The blood type on the card is [blood_type].") + to_chat(usr, "The DNA hash on the card is [dna_hash].") + to_chat(usr, "The fingerprint hash on the card is [fingerprint_hash].") + return + +/obj/item/weapon/card/id/silver + name = "identification card" + desc = "A silver card which shows honour and dedication." + icon_state = "silver" + item_state = "silver_id" + job_access_type = /datum/job/hop + +/obj/item/weapon/card/id/gold + name = "identification card" + desc = "A golden card which shows power and might." + icon_state = "gold" + item_state = "gold_id" + job_access_type = /datum/job/captain + +/obj/item/weapon/card/id/syndicate_command + name = "syndicate ID card" + desc = "An ID straight from the Syndicate." + registered_name = "Syndicate" + assignment = "Syndicate Overlord" + access = list(access_syndicate, access_external_airlocks) + +/obj/item/weapon/card/id/captains_spare + name = "captain's spare ID" + desc = "The spare ID of the High Lord himself." + icon_state = "gold" + item_state = "gold_id" + registered_name = "Captain" + assignment = "Captain" + +/obj/item/weapon/card/id/captains_spare/New() + access = get_all_station_access() + ..() + +/obj/item/weapon/card/id/synthetic + name = "\improper Synthetic ID" + desc = "Access module for lawed synthetics." + icon_state = "id-robot" + item_state = "tdgreen" + assignment = "Synthetic" + +/obj/item/weapon/card/id/synthetic/New() + access = get_all_station_access() + access_synth + ..() + +/obj/item/weapon/card/id/centcom + name = "\improper CentCom. ID" + desc = "An ID straight from Cent. Com." + icon_state = "centcom" + registered_name = "Central Command" + assignment = "General" +/obj/item/weapon/card/id/centcom/New() + access = get_all_centcom_access() + ..() + +/obj/item/weapon/card/id/centcom/station/New() + ..() + access |= get_all_station_access() + +/obj/item/weapon/card/id/centcom/ERT + name = "\improper Emergency Response Team ID" + assignment = "Emergency Response Team" + +/obj/item/weapon/card/id/centcom/ERT/New() + ..() + access |= get_all_station_access() + +/obj/item/weapon/card/id/all_access + name = "\improper Administrator's spare ID" + desc = "The spare ID of the Lord of Lords himself." + icon_state = "data" + item_state = "tdgreen" + registered_name = "Administrator" + assignment = "Administrator" +/obj/item/weapon/card/id/all_access/New() + access = get_access_ids() + ..() + +// Department-flavor IDs +/obj/item/weapon/card/id/medical + name = "identification card" + desc = "A card issued to medical staff." + icon_state = "med" + job_access_type = /datum/job/doctor + +/obj/item/weapon/card/id/medical/chemist + job_access_type = /datum/job/chemist + +/obj/item/weapon/card/id/medical/geneticist + job_access_type = /datum/job/geneticist + +/obj/item/weapon/card/id/medical/psychiatrist + job_access_type = /datum/job/psychiatrist + +/obj/item/weapon/card/id/medical/paramedic + job_access_type = /datum/job/Paramedic + +/obj/item/weapon/card/id/medical/head + name = "identification card" + desc = "A card which represents care and compassion." + icon_state = "medGold" + job_access_type = /datum/job/cmo + +/obj/item/weapon/card/id/security + name = "identification card" + desc = "A card issued to security staff." + icon_state = "sec" + job_access_type = /datum/job/officer + +/obj/item/weapon/card/id/security/warden + job_access_type = /datum/job/warden + +/obj/item/weapon/card/id/security/detective + job_access_type = /datum/job/detective + +/obj/item/weapon/card/id/security/head + name = "identification card" + desc = "A card which represents honor and protection." + icon_state = "secGold" + job_access_type = /datum/job/hos + +/obj/item/weapon/card/id/engineering + name = "identification card" + desc = "A card issued to engineering staff." + icon_state = "eng" + job_access_type = /datum/job/engineer + +/obj/item/weapon/card/id/engineering/atmos + job_access_type = /datum/job/atmos + +/obj/item/weapon/card/id/engineering/head + name = "identification card" + desc = "A card which represents creativity and ingenuity." + icon_state = "engGold" + job_access_type = /datum/job/chief_engineer + +/obj/item/weapon/card/id/science + name = "identification card" + desc = "A card issued to science staff." + icon_state = "sci" + job_access_type = /datum/job/scientist + +/obj/item/weapon/card/id/science/xenobiologist + job_access_type = /datum/job/xenobiologist + +/obj/item/weapon/card/id/science/roboticist + job_access_type = /datum/job/roboticist + +/obj/item/weapon/card/id/science/head + name = "identification card" + desc = "A card which represents knowledge and reasoning." + icon_state = "sciGold" + job_access_type = /datum/job/rd + +/obj/item/weapon/card/id/cargo + name = "identification card" + desc = "A card issued to cargo staff." + icon_state = "cargo" + job_access_type = /datum/job/cargo_tech + +/obj/item/weapon/card/id/cargo/mining + job_access_type = /datum/job/mining + +/obj/item/weapon/card/id/cargo/head + name = "identification card" + desc = "A card which represents service and planning." + icon_state = "cargoGold" + job_access_type = /datum/job/qm + +/obj/item/weapon/card/id/civilian + name = "identification card" + desc = "A card issued to civilian staff." + icon_state = "civ" + job_access_type = /datum/job/assistant + +/obj/item/weapon/card/id/civilian/bartender + job_access_type = /datum/job/bartender + +/obj/item/weapon/card/id/civilian/chef + job_access_type = /datum/job/chef + +/obj/item/weapon/card/id/civilian/botanist + job_access_type = /datum/job/hydro + +/obj/item/weapon/card/id/civilian/janitor + job_access_type = /datum/job/janitor + +/obj/item/weapon/card/id/civilian/librarian + job_access_type = /datum/job/librarian + +/obj/item/weapon/card/id/civilian/internal_affairs_agent + job_access_type = /datum/job/lawyer + +/obj/item/weapon/card/id/civilian/chaplain + job_access_type = /datum/job/chaplain + +/obj/item/weapon/card/id/civilian/head //This is not the HoP. There's no position that uses this right now. + name = "identification card" + desc = "A card which represents common sense and responsibility." + icon_state = "civGold" + +/obj/item/weapon/card/id/merchant + name = "identification card" + desc = "A card issued to Merchants, indicating their right to sell and buy goods." + icon_state = "trader" + access = list(access_merchant) diff --git a/code/game/objects/items/weapons/cards_ids_syndicate.dm b/code/game/objects/items/weapons/cards_ids_syndicate.dm new file mode 100644 index 00000000..b4345b6c --- /dev/null +++ b/code/game/objects/items/weapons/cards_ids_syndicate.dm @@ -0,0 +1,229 @@ +/obj/item/weapon/card/id/syndicate + name = "agent card" + icon_state = "syndicate" + assignment = "Agent" + origin_tech = list(TECH_ILLEGAL = 3) + var/electronic_warfare = 1 + var/mob/registered_user = null + +/obj/item/weapon/card/id/syndicate/New(mob/user as mob) + ..() + access = syndicate_access.Copy() + +/obj/item/weapon/card/id/syndicate/station_access/New() + ..() // Same as the normal Syndicate id, only already has all station access + access |= get_all_station_access() + +/obj/item/weapon/card/id/syndicate/Destroy() + unset_registered_user(registered_user) + return ..() + +/obj/item/weapon/card/id/syndicate/prevent_tracking() + return electronic_warfare + +/obj/item/weapon/card/id/syndicate/afterattack(var/obj/item/weapon/O as obj, mob/user as mob, proximity) + if(!proximity) return + if(istype(O, /obj/item/weapon/card/id)) + var/obj/item/weapon/card/id/I = O + src.access |= I.access + if(player_is_antag(user.mind)) + to_chat(user, "The microscanner activates as you pass it over the ID, copying its access.") + +/obj/item/weapon/card/id/syndicate/attack_self(mob/user as mob) + // We use the fact that registered_name is not unset should the owner be vaporized, to ensure the id doesn't magically become unlocked. + if(!registered_user && register_user(user)) + to_chat(user, "The microscanner marks you as its owner, preventing others from accessing its internals.") + if(registered_user == user) + switch(alert("Would you like edit the ID, or show it?","Show or Edit?", "Edit","Show")) + if("Edit") + ui_interact(user) + if("Show") + ..() + else + ..() + +/obj/item/weapon/card/id/syndicate/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + var/entries[0] + entries[++entries.len] = list("name" = "Age", "value" = age) + entries[++entries.len] = list("name" = "Appearance", "value" = "Set") + entries[++entries.len] = list("name" = "Assignment", "value" = assignment) + if(GLOB.using_map.flags & MAP_HAS_BRANCH) + entries[++entries.len] = list("name" = "Branch", "value" = military_branch ? military_branch.name : "N/A") + if(military_branch && (GLOB.using_map.flags & MAP_HAS_RANK)) + entries[++entries.len] = list("name" = "Rank", "value" = military_rank ? military_rank.name : "N/A") + entries[++entries.len] = list("name" = "Blood Type", "value" = blood_type) + entries[++entries.len] = list("name" = "DNA Hash", "value" = dna_hash) + entries[++entries.len] = list("name" = "Fingerprint Hash", "value" = fingerprint_hash) + entries[++entries.len] = list("name" = "Name", "value" = registered_name) + entries[++entries.len] = list("name" = "Photo", "value" = "Update") + entries[++entries.len] = list("name" = "Sex", "value" = sex) + entries[++entries.len] = list("name" = "Factory Reset", "value" = "Use With Care") + data["electronic_warfare"] = electronic_warfare + data["entries"] = entries + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "agent_id_card.tmpl", "Agent id", 600, 400) + ui.set_initial_data(data) + ui.open() + +/obj/item/weapon/card/id/syndicate/proc/register_user(var/mob/user) + if(!istype(user) || user == registered_user) + return FALSE + unset_registered_user() + registered_user = user + user.set_id_info(src) + GLOB.destroyed_event.register(user, src, /obj/item/weapon/card/id/syndicate/proc/unset_registered_user) + return TRUE + +/obj/item/weapon/card/id/syndicate/proc/unset_registered_user(var/mob/user) + if(!registered_user || (user && user != registered_user)) + return + GLOB.destroyed_event.unregister(registered_user, src) + registered_user = null + +/obj/item/weapon/card/id/syndicate/CanUseTopic(mob/user) + if(user != registered_user) + return STATUS_CLOSE + return ..() + +/obj/item/weapon/card/id/syndicate/Topic(href, href_list, var/datum/topic_state/state) + if(..()) + return 1 + + var/user = usr + if(href_list["electronic_warfare"]) + electronic_warfare = text2num(href_list["electronic_warfare"]) + to_chat(user, "Electronic warfare [electronic_warfare ? "enabled" : "disabled"].") + else if(href_list["set"]) + switch(href_list["set"]) + if("Age") + var/new_age = input(user,"What age would you like to put on this card?","Agent Card Age", age) as null|num + if(!isnull(new_age) && CanUseTopic(user, state)) + if(new_age < 0) + age = initial(age) + else + age = new_age + to_chat(user, "Age has been set to '[age]'.") + . = 1 + if("Appearance") + var/datum/card_state/choice = input(user, "Select the appearance for this card.", "Agent Card Appearance") as null|anything in id_card_states() + if(choice && CanUseTopic(user, state)) + src.icon_state = choice.icon_state + src.item_state = choice.item_state + to_chat(usr, "Appearance changed to [choice].") + . = 1 + if("Assignment") + var/new_job = sanitize(input(user,"What assignment would you like to put on this card?\nChanging assignment will not grant or remove any access levels.","Agent Card Assignment", assignment) as null|text) + if(!isnull(new_job) && CanUseTopic(user, state)) + src.assignment = new_job + to_chat(user, "Occupation changed to '[new_job]'.") + update_name() + . = 1 + if("Blood Type") + var/default = blood_type + if(default == initial(blood_type) && ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.dna) + default = H.dna.b_type + var/new_blood_type = sanitize(input(user,"What blood type would you like to be written on this card?","Agent Card Blood Type",default) as null|text) + if(!isnull(new_blood_type) && CanUseTopic(user, state)) + src.blood_type = new_blood_type + to_chat(user, "Blood type changed to '[new_blood_type]'.") + . = 1 + if("DNA Hash") + var/default = dna_hash + if(default == initial(dna_hash) && ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.dna) + default = H.dna.unique_enzymes + var/new_dna_hash = sanitize(input(user,"What DNA hash would you like to be written on this card?","Agent Card DNA Hash",default) as null|text) + if(!isnull(new_dna_hash) && CanUseTopic(user, state)) + src.dna_hash = new_dna_hash + to_chat(user, "DNA hash changed to '[new_dna_hash]'.") + . = 1 + if("Fingerprint Hash") + var/default = fingerprint_hash + if(default == initial(fingerprint_hash) && ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.dna) + default = md5(H.dna.uni_identity) + var/new_fingerprint_hash = sanitize(input(user,"What fingerprint hash would you like to be written on this card?","Agent Card Fingerprint Hash",default) as null|text) + if(!isnull(new_fingerprint_hash) && CanUseTopic(user, state)) + src.fingerprint_hash = new_fingerprint_hash + to_chat(user, "Fingerprint hash changed to '[new_fingerprint_hash]'.") + . = 1 + if("Name") + var/new_name = sanitizeName(input(user,"What name would you like to put on this card?","Agent Card Name", registered_name) as null|text, allow_numbers=TRUE) + if(!isnull(new_name) && CanUseTopic(user, state)) + src.registered_name = new_name + update_name() + to_chat(user, "Name changed to '[new_name]'.") + . = 1 + if("Photo") + set_id_photo(user) + to_chat(user, "Photo changed.") + . = 1 + if("Sex") + var/new_sex = sanitize(input(user,"What sex would you like to put on this card?","Agent Card Sex", sex) as null|text) + if(!isnull(new_sex) && CanUseTopic(user, state)) + src.sex = new_sex + to_chat(user, "Sex changed to '[new_sex]'.") + . = 1 + if("Factory Reset") + if(alert("This will factory reset the card, including access and owner. Continue?", "Factory Reset", "No", "Yes") == "Yes" && CanUseTopic(user, state)) + age = initial(age) + access = syndicate_access.Copy() + assignment = initial(assignment) + blood_type = initial(blood_type) + dna_hash = initial(dna_hash) + electronic_warfare = initial(electronic_warfare) + fingerprint_hash = initial(fingerprint_hash) + icon_state = initial(icon_state) + SetName(initial(name)) + registered_name = initial(registered_name) + unset_registered_user() + sex = initial(sex) + military_branch = initial(military_branch) + military_rank = initial(military_rank) + to_chat(user, "All information has been deleted from \the [src].") + . = 1 + if("Branch") + var/new_branch = sanitize(input(user,"What branch of service would you like to put on this card?","Agent Card Branch") as null|anything in mil_branches.spawn_branches()) + if(!isnull(new_branch) && CanUseTopic(user, state)) + src.military_branch = mil_branches.spawn_branches()[new_branch] + to_chat(user, "Branch changed to '[military_branch.name]'.") + . = 1 + if("Rank") + var/new_rank = sanitize(input(user,"What rank would you like to put on this card?","Agent Card Rank") as null|anything in mil_branches.spawn_ranks(military_branch.name)) + if(!isnull(new_rank) && CanUseTopic(user, state)) + src.military_rank = mil_branches.spawn_ranks(military_branch.name)[new_rank] + to_chat(user, "Rank changed to '[military_rank.name]'.") + . = 1 + + // Always update the UI, or buttons will spin indefinitely + GLOB.nanomanager.update_uis(src) + +/var/global/list/id_card_states +/proc/id_card_states() + if(!id_card_states) + id_card_states = list() + for(var/path in typesof(/obj/item/weapon/card/id)) + var/obj/item/weapon/card/id/ID = path + var/datum/card_state/CS = new() + CS.icon_state = initial(ID.icon_state) + CS.item_state = initial(ID.item_state) + CS.name = initial(ID.name) + " - " + initial(ID.icon_state) + id_card_states += CS + id_card_states = dd_sortedObjectList(id_card_states) + + return id_card_states + +/datum/card_state + var/name + var/icon_state + var/item_state + +/datum/card_state/dd_SortValue() + return name diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm new file mode 100644 index 00000000..ffc49d9c --- /dev/null +++ b/code/game/objects/items/weapons/cigs_lighters.dm @@ -0,0 +1,725 @@ +//cleansed 9/15/2012 17:48 + +/* +CONTAINS: +MATCHES +CIGARETTES +CIGARS +SMOKING PIPES +CHEAP LIGHTERS +ZIPPO + +CIGARETTE PACKETS ARE IN FANCY.DM +*/ + +//For anything that can light stuff on fire +/obj/item/weapon/flame + var/lit = 0 + +/proc/isflamesource(A) + if(isWelder(A)) + var/obj/item/weapon/weldingtool/WT = A + return (WT.isOn()) + else if(istype(A, /obj/item/weapon/flame)) + var/obj/item/weapon/flame/F = A + return (F.lit) + else if(istype(A, /obj/item/clothing/mask/smokable) && !istype(A, /obj/item/clothing/mask/smokable/pipe)) + var/obj/item/clothing/mask/smokable/S = A + return (S.lit) + else if(istype(A, /obj/item/device/assembly/igniter)) + return 1 + else if(istype(A,/obj/item/torch)) + var/obj/item/torch/T = A + return (T.lit) + else if(istype(A,/obj/item/warflare)) + var/obj/item/warflare/W = A + return (W.on) + return 0 + +/////////// +//MATCHES// +/////////// +/obj/item/weapon/flame/match + name = "match" + desc = "A simple match stick, used for lighting fine smokables." + icon = 'icons/obj/cigarettes.dmi' + icon_state = "match_unlit" + var/burnt = 0 + var/smoketime = 5 + w_class = ITEM_SIZE_TINY + origin_tech = list(TECH_MATERIAL = 1) + slot_flags = SLOT_EARS + attack_verb = list("burnt", "singed") + +/obj/item/weapon/flame/match/Process() + if(isliving(loc)) + var/mob/living/M = loc + M.IgniteMob() + var/turf/location = get_turf(src) + smoketime-- + if(smoketime < 1) + burn_out() + return + if(location) + location.hotspot_expose(700, 5) + return + +/obj/item/weapon/flame/match/dropped(mob/user as mob) + //If dropped, put ourselves out + //not before lighting up the turf we land on, though. + if(lit) + spawn(0) + var/turf/location = src.loc + if(istype(location)) + location.hotspot_expose(700, 5) + burn_out() + return ..() + +/obj/item/weapon/flame/match/proc/burn_out() + lit = 0 + burnt = 1 + damtype = "brute" + icon_state = "match_burnt" + item_state = "cigoff" + name = "burnt match" + desc = "A match. This one has seen better days." + STOP_PROCESSING(SSobj, src) + +////////////////// +//FINE SMOKABLES// +////////////////// +/obj/item/clothing/mask/smokable + name = "smokable item" + desc = "You're not sure what this is. You should probably ahelp it." + body_parts_covered = 0 + var/lit = 0 + var/icon_on + var/type_butt = null + var/chem_volume = 0 + var/smoketime = 0 + var/matchmes = "USER lights NAME with FLAME" + var/lightermes = "USER lights NAME with FLAME" + var/zippomes = "USER lights NAME with FLAME" + var/weldermes = "USER lights NAME with FLAME" + var/ignitermes = "USER lights NAME with FLAME" + var/brand + +/obj/item/clothing/mask/smokable/New() + ..() + atom_flags |= ATOM_FLAG_NO_REACT // so it doesn't react until you light it + create_reagents(chem_volume) // making the cigarrete a chemical holder with a maximum volume of 15 + +/obj/item/clothing/mask/smokable/Destroy() + . = ..() + if(lit) + STOP_PROCESSING(SSobj, src) + +/obj/item/clothing/mask/smokable/proc/smoke(amount) + smoketime -= amount + if(reagents && reagents.total_volume) // check if it has any reagents at all + if(ishuman(loc)) + var/mob/living/carbon/human/C = loc + if (src == C.wear_mask && C.check_has_mouth()) // if it's in the human/monkey mouth, transfer reagents to the mob + reagents.trans_to_mob(C, REM, CHEM_INGEST, 0.2) // Most of it is not inhaled... balance reasons. + else // else just remove some of the reagents + reagents.remove_any(REM) + +/obj/item/clothing/mask/smokable/Process() + var/turf/location = get_turf(src) + smoke(1) + if(smoketime < 1) + die() + return + if(location) + location.hotspot_expose(700, 5) + +/obj/item/clothing/mask/smokable/update_icon() + if(lit && icon_on) + icon_state = icon_on + item_state = icon_on + else + icon_state = initial(icon_state) + item_state = initial(item_state) + if(ismob(loc)) + var/mob/living/M = loc + M.update_inv_wear_mask(0) + M.update_inv_l_hand(0) + M.update_inv_r_hand(1) + +/obj/item/clothing/mask/smokable/proc/light(var/flavor_text = "[usr] lights the [name].") + if(!src.lit) + src.lit = 1 + damtype = "fire" + playsound(src, 'sound/items/cig_light.ogg', 75, 1, -1)//Play the nice sound. + if(reagents.get_reagent_amount(/datum/reagent/toxin/phoron)) // the phoron explodes when exposed to fire + var/datum/effect/effect/system/reagents_explosion/e = new() + e.set_up(round(reagents.get_reagent_amount(/datum/reagent/toxin/phoron) / 2.5, 1), get_turf(src), 0, 0) + e.start() + qdel(src) + return + if(reagents.get_reagent_amount(/datum/reagent/fuel)) // the fuel explodes, too, but much less violently + var/datum/effect/effect/system/reagents_explosion/e = new() + e.set_up(round(reagents.get_reagent_amount(/datum/reagent/fuel) / 5, 1), get_turf(src), 0, 0) + e.start() + qdel(src) + return + atom_flags &= ~ATOM_FLAG_NO_REACT // allowing reagents to react after being lit + reagents.process_reactions() + update_icon() + var/turf/T = get_turf(src) + T.visible_message(flavor_text) + set_light(2, 0.25, "#e38f46") + START_PROCESSING(SSobj, src) + +/obj/item/clothing/mask/smokable/proc/die(var/nomessage = 0) + playsound(src, 'sound/items/cig_snuff.ogg', 25, 1) + set_light(0) + lit = 0 + STOP_PROCESSING(SSobj, src) + update_icon() + +/obj/item/clothing/mask/smokable/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + if(isflamesource(W)) + var/text = matchmes + if(istype(W, /obj/item/weapon/flame/match)) + text = matchmes + else if(istype(W, /obj/item/weapon/flame/lighter/zippo)) + text = zippomes + else if(istype(W, /obj/item/weapon/flame/lighter)) + text = lightermes + else if(isWelder(W)) + text = weldermes + else if(istype(W, /obj/item/device/assembly/igniter)) + text = ignitermes + text = replacetext(text, "USER", "[user]") + text = replacetext(text, "NAME", "[name]") + text = replacetext(text, "FLAME", "[W.name]") + light(text) + +/obj/item/clothing/mask/smokable/attack(var/mob/living/M, var/mob/living/user, def_zone) + if(istype(M) && M.on_fire) + user.do_attack_animation(M) + light("\The [user] coldly lights the \the [src] with the burning body of \the [M].") + return 1 + else + return ..() + +/obj/item/clothing/mask/smokable/cigarette + name = "cigarette" + desc = "A small paper cylinder filled with processed tobacco and various fillers." + icon_state = "cigoff" + throw_speed = 0.5 + item_state = "cigoff" + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS | SLOT_MASK + attack_verb = list("burnt", "singed") + type_butt = /obj/item/weapon/cigbutt + chem_volume = 5 + smoketime = 300 + matchmes = "USER lights their NAME with their FLAME." + lightermes = "USER manages to light their NAME with FLAME." + zippomes = "With a flick of their wrist, USER lights their NAME with their FLAME." + weldermes = "USER casually lights the NAME with FLAME." + ignitermes = "USER fiddles with FLAME, and manages to light their NAME." + brand = "\improper FrozenNova" + var/list/filling = list(/datum/reagent/tobacco = 1) + +/obj/item/clothing/mask/smokable/cigarette/New() + ..() + for(var/R in filling) + reagents.add_reagent(R, filling[R]) + +/obj/item/clothing/mask/smokable/cigarette/update_icon() + ..() + overlays.Cut() + if(lit) + overlays += overlay_image(icon, "cigon", flags=RESET_COLOR) + +/obj/item/clothing/mask/smokable/cigarette/trident/update_icon() + ..() + overlays.Cut() + if(lit) + overlays += overlay_image(icon, "cigarello-on", flags=RESET_COLOR) + +/obj/item/clothing/mask/smokable/cigarette/die(var/nomessage = 0) + ..() + if (type_butt) + var/obj/item/butt = new type_butt(get_turf(src)) + transfer_fingerprints_to(butt) + butt.color = color + if(brand) + butt.desc += " This one is \a [brand]." + if(ismob(loc)) + var/mob/living/M = loc + if (!nomessage) + to_chat(M, "Your [name] goes out.") + M.remove_from_mob(src) //un-equip it so the overlays can update + qdel(src) + +/obj/item/clothing/mask/smokable/cigarette/menthol + name = "menthol cigarette" + desc = "A cigarette with a little minty kick. Well, minty in theory." + icon_state = "cigmentol" + brand = "\improper Temperamento Menthol" + color = "#ddffe8" + type_butt = /obj/item/weapon/cigbutt/menthol + filling = list(/datum/reagent/tobacco = 1, /datum/reagent/menthol = 1) + +/obj/item/weapon/cigbutt/menthol + icon_state = "cigbuttmentol" + +/obj/item/clothing/mask/smokable/cigarette/luckystars + brand = "\improper Brouzefs"//It's spelled wrong on purpose. + icon_state = "BrouzoufCig" + type_butt = /obj/item/weapon/cigbutt/brouzef + +/obj/item/weapon/cigbutt/brouzef + icon_state = "BrourzoufCigButt" + +/obj/item/clothing/mask/smokable/cigarette/jerichos + name = "rugged cigarette" + brand = "\improper RoachEyes" + icon_state = "cigjer" + color = "#dcdcdc" + type_butt = /obj/item/weapon/cigbutt/jerichos + filling = list(/datum/reagent/tobacco/bad = 1.5) + +/obj/item/weapon/cigbutt/jerichos + icon_state = "cigbuttjer" + +/obj/item/clothing/mask/smokable/cigarette/carcinomas + name = "tannhauser cigarette" + brand = "\improper Tannhauser Gate" + icon_state = "TannhauserGateCig" + type_butt = /obj/item/weapon/cigbutt/jerichos + //color = "#869286" + +/obj/item/weapon/cigbutt/tannhauser + icon_state = "TannhauserGateCigButt" + +/obj/item/clothing/mask/smokable/cigarette/professionals + name = "thin cigarette" + brand = "\improper Professional" + icon_state = "cigpro" + type_butt = /obj/item/weapon/cigbutt/professionals + filling = list(/datum/reagent/tobacco/bad = 1) + +/obj/item/weapon/cigbutt/professionals + icon_state = "cigbuttpro" + +/obj/item/clothing/mask/smokable/cigarette/killthroat + brand = "\improper Acme Co. cigarette" + +/obj/item/clothing/mask/smokable/cigarette/dromedaryco + brand = "\improper Dromedary Co. cigarette" + +/obj/item/clothing/mask/smokable/cigarette/trident + name = "wood tip cigar" + brand = "\improper Trident cigar" + desc = "A narrow cigar with a wooden tip." + icon_state = "cigarello" + item_state = "cigaroff" + smoketime = 600 + chem_volume = 10 + type_butt = /obj/item/weapon/cigbutt/woodbutt + filling = list(/datum/reagent/tobacco/fine = 2) + +/obj/item/clothing/mask/smokable/cigarette/trident/mint + icon_state = "cigarelloMi" + filling = list(/datum/reagent/tobacco/fine = 2, /datum/reagent/menthol = 2) + +/obj/item/clothing/mask/smokable/cigarette/trident/berry + icon_state = "cigarelloBe" + filling = list(/datum/reagent/tobacco/fine = 2, /datum/reagent/drink/juice/berry = 2) + +/obj/item/clothing/mask/smokable/cigarette/trident/cherry + icon_state = "cigarelloCh" + filling = list(/datum/reagent/tobacco/fine = 2, /datum/reagent/nutriment/cherryjelly = 2) + +/obj/item/clothing/mask/smokable/cigarette/trident/grape + icon_state = "cigarelloGr" + filling = list(/datum/reagent/tobacco/fine = 2, /datum/reagent/drink/juice/grape = 2) + +/obj/item/clothing/mask/smokable/cigarette/trident/watermelon + icon_state = "cigarelloWm" + filling = list(/datum/reagent/tobacco/fine = 2, /datum/reagent/drink/juice/watermelon = 2) + +/obj/item/clothing/mask/smokable/cigarette/trident/orange + icon_state = "cigarelloOr" + filling = list(/datum/reagent/tobacco/fine = 2, /datum/reagent/drink/juice/orange = 2) + +/obj/item/weapon/cigbutt/woodbutt + name = "wooden tip" + desc = "A wooden mouthpiece from a cigar. Smells rather bad." + icon_state = "woodbutt" + matter = list("Wood" = 1) + +/obj/item/clothing/mask/smokable/cigarette/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + + if(istype(W, /obj/item/weapon/melee/energy/sword)) + var/obj/item/weapon/melee/energy/sword/S = W + if(S.active) + light("[user] swings their [W], barely missing their nose. They light their [name] in the process.") + + return + +/obj/item/clothing/mask/smokable/cigarette/attack(mob/living/carbon/human/H, mob/user, def_zone) + if(lit && H == user && istype(H)) + var/obj/item/blocked = H.check_mouth_coverage() + if(blocked) + to_chat(H, "\The [blocked] is in the way!") + return 1 + H.visible_message("[H.name] takes a drag of their [name].") + playsound(H, 'sound/effects/inhale.ogg', 50, 0, -1) + smoke(5) + return 1 + return ..() + +/obj/item/clothing/mask/smokable/cigarette/afterattack(obj/item/weapon/reagent_containers/glass/glass, mob/user as mob, proximity) + ..() + if(!proximity) + return + if(istype(glass)) //you can dip cigarettes into beakers + if(!glass.is_open_container()) + to_chat(user, "You need to take the lid off first.") + return + var/transfered = glass.reagents.trans_to_obj(src, chem_volume) + if(transfered) //if reagents were transfered, show the message + to_chat(user, "You dip \the [src] into \the [glass].") + else //if not, either the beaker was empty, or the cigarette was full + if(!glass.reagents.total_volume) + to_chat(user, "[glass] is empty.") + else + to_chat(user, "[src] is full.") + +/obj/item/clothing/mask/smokable/cigarette/attack_self(mob/user as mob) + if(lit == 1) + user.visible_message("[user] calmly drops and treads on the lit [src], putting it out instantly.") + die(1) + return ..() + +/obj/item/clothing/mask/smokable/cigarette/get_icon_state(mob/user_mob, slot) + return item_state + +/obj/item/clothing/mask/smokable/cigarette/get_mob_overlay(mob/user_mob, slot) + var/image/res = ..() + if(lit == 1) + var/image/ember = overlay_image(res.icon, "cigember")//, flags=RESET_COLOR) + //ember.layer = ABOVE_LIGHTING_LAYER + //ember.plane = EFFECTS_ABOVE_LIGHTING_PLANE + res.overlays += ember + return res + +//////////// +// CIGARS // +//////////// +/obj/item/clothing/mask/smokable/cigarette/cigar + name = "premium cigar" + desc = "A brown roll of tobacco and... well, you're not quite sure. This thing's huge!" + icon_state = "cigar2off" + icon_on = "cigar2on" + type_butt = /obj/item/weapon/cigbutt/cigarbutt + throw_speed = 0.5 + item_state = "cigaroff" + smoketime = 1500 + chem_volume = 15 + matchmes = "USER lights their NAME with their FLAME." + lightermes = "USER manages to offend their NAME by lighting it with FLAME." + zippomes = "With a flick of their wrist, USER lights their NAME with their FLAME." + weldermes = "USER insults NAME by lighting it with FLAME." + ignitermes = "USER fiddles with FLAME, and manages to light their NAME with the power of science." + filling = list(/datum/reagent/tobacco/fine = 5) + +/obj/item/clothing/mask/smokable/cigarette/cigar/cohiba + name = "\improper Cohiba Robusto cigar" + desc = "There's little more you could want from a cigar." + icon_state = "cigar2off" + icon_on = "cigar2on" + +/obj/item/clothing/mask/smokable/cigarette/cigar/havana + name = "premium Havanian cigar" + desc = "A cigar fit for only the best of the best." + icon_state = "cigar2off" + icon_on = "cigar2on" + smoketime = 3000 + chem_volume = 20 + filling = list(/datum/reagent/tobacco/fine = 10) + +/obj/item/weapon/cigbutt + name = "cigarette butt" + desc = "A manky old cigarette butt." + icon = 'icons/obj/clothing/masks.dmi' + icon_state = "cigbutt" + randpixel = 10 + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + throwforce = 1 + +/obj/item/weapon/cigbutt/New() + ..() + transform = turn(transform,rand(0,360)) + +/obj/item/weapon/cigbutt/cigarbutt + name = "cigar butt" + desc = "A manky old cigar butt." + icon_state = "cigarbutt" + +/obj/item/clothing/mask/smokable/cigarette/cigar/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + + user.update_inv_wear_mask(0) + user.update_inv_l_hand(0) + user.update_inv_r_hand(1) + +///////////////// +//SMOKING PIPES// +///////////////// +/obj/item/clothing/mask/smokable/pipe + name = "smoking pipe" + desc = "A pipe, for smoking. Probably made of meershaum or something." + icon_state = "pipeoff" + item_state = "pipeoff" + w_class = ITEM_SIZE_TINY + icon_on = "pipeon" //Note - these are in masks.dmi + smoketime = 0 + chem_volume = 50 + matchmes = "USER lights their NAME with their FLAME." + lightermes = "USER manages to light their NAME with FLAME." + zippomes = "With much care, USER lights their NAME with their FLAME." + weldermes = "USER recklessly lights NAME with FLAME." + ignitermes = "USER fiddles with FLAME, and manages to light their NAME with the power of science." + +/obj/item/clothing/mask/smokable/pipe/New() + ..() + name = "empty [initial(name)]" + +/obj/item/clothing/mask/smokable/pipe/light(var/flavor_text = "[usr] lights the [name].") + if(!src.lit && src.smoketime) + src.lit = 1 + damtype = "fire" + icon_state = icon_on + item_state = icon_on + var/turf/T = get_turf(src) + T.visible_message(flavor_text) + START_PROCESSING(SSobj, src) + if(ismob(loc)) + var/mob/living/M = loc + M.update_inv_wear_mask(0) + M.update_inv_l_hand(0) + M.update_inv_r_hand(1) + +/obj/item/clothing/mask/smokable/pipe/die(var/nomessage = 0) + ..() + new /obj/effect/decal/cleanable/ash(get_turf(src)) + if(ismob(loc)) + var/mob/living/M = loc + if (!nomessage) + to_chat(M, "Your [name] goes out, and you empty the ash.") + +/obj/item/clothing/mask/smokable/pipe/attack_self(mob/user as mob) + if(lit == 1) + user.visible_message("[user] puts out [src].", "You put out [src].") + lit = 0 + update_icon() + STOP_PROCESSING(SSobj, src) + else if (smoketime) + var/turf/location = get_turf(user) + user.visible_message("[user] empties out [src].", "You empty out [src].") + new /obj/effect/decal/cleanable/ash(location) + smoketime = 0 + reagents.clear_reagents() + SetName("empty [initial(name)]") + +/obj/item/clothing/mask/smokable/pipe/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/melee/energy/sword)) + return + + ..() + + if (istype(W, /obj/item/weapon/reagent_containers/food/snacks)) + var/obj/item/weapon/reagent_containers/food/snacks/grown/G = W + if (!G.dry) + to_chat(user, "[G] must be dried before you stuff it into [src].") + return + if (smoketime) + to_chat(user, "[src] is already packed.") + return + smoketime = 1000 + if(G.reagents) + G.reagents.trans_to_obj(src, G.reagents.total_volume) + SetName("[G.name]-packed [initial(name)]") + qdel(G) + + else if(istype(W, /obj/item/weapon/flame/lighter)) + var/obj/item/weapon/flame/lighter/L = W + if(L.lit) + light("[user] manages to light their [name] with [W].") + + else if(istype(W, /obj/item/weapon/flame/match)) + var/obj/item/weapon/flame/match/M = W + if(M.lit) + light("[user] lights their [name] with their [W].") + + else if(istype(W, /obj/item/device/assembly/igniter)) + light("[user] fiddles with [W], and manages to light their [name] with the power of science.") + + user.update_inv_wear_mask(0) + user.update_inv_l_hand(0) + user.update_inv_r_hand(1) + +/obj/item/clothing/mask/smokable/pipe/cobpipe + name = "corn cob pipe" + desc = "A nicotine delivery system popularized by folksy backwoodsmen, kept popular in the modern age and beyond by space hipsters." + icon_state = "cobpipeoff" + item_state = "cobpipeoff" + icon_on = "cobpipeon" //Note - these are in masks.dmi + chem_volume = 35 + +///////// +//ZIPPO// +///////// +/obj/item/weapon/flame/lighter + name = "cheap lighter" + desc = "A cheap-as-free lighter." + icon = 'icons/obj/items.dmi' + icon_state = "lighter-g" + item_state = "lighter-g" + w_class = ITEM_SIZE_TINY + throwforce = 4 + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + attack_verb = list("burnt", "singed") + var/max_fuel = 5 + +/obj/item/weapon/flame/lighter/New() + ..() + create_reagents(max_fuel) + reagents.add_reagent(/datum/reagent/fuel, max_fuel) + set_extension(src, /datum/extension/base_icon_state, /datum/extension/base_icon_state, icon_state) + update_icon() + +/obj/item/weapon/flame/lighter/proc/light(mob/user) + playsound(src.loc, "light_bic", 100, 1, -4) + if(prob(50)) + return + lit = 1 + update_icon() + user.visible_message("[user] manages to light the [src].") + set_light(2, 2, "#E38F46") + START_PROCESSING(SSobj, src) + + +/obj/item/weapon/flame/lighter/proc/light_effects(mob/living/carbon/user) + if(prob(95)) + user.visible_message("[user] manages to light the [src].") + else + to_chat(user, "You burn yourself while lighting the lighter.") + if (user.l_hand == src) + user.apply_damage(2,BURN,BP_L_HAND) + else + user.apply_damage(2,BURN,BP_R_HAND) + user.visible_message("After a few attempts, [user] manages to light the [src], they however burn their finger in the process.") + playsound(src.loc, "light_bic", 100, 1, -4) + + +/obj/item/weapon/flame/lighter/proc/shutoff(mob/user) + lit = 0 + update_icon() + if(user) + shutoff_effects(user) + else + visible_message("[src] goes out.") + set_light(0) + STOP_PROCESSING(SSobj, src) + +/obj/item/weapon/flame/lighter/proc/shutoff_effects(mob/user) + user.visible_message("[user] quietly shuts off the [src].") + +/obj/item/weapon/flame/lighter/zippo + name = "\improper Zippo lighter" + desc = "The zippo." + icon_state = "zippo" + item_state = "zippo" + max_fuel = 10 + +/obj/item/weapon/flame/lighter/zippo/light(mob/user) + lit = 1 + light_effects(user) + update_icon() + set_light(2, 2, "#E38F46") + START_PROCESSING(SSobj, src) + +/obj/item/weapon/flame/lighter/zippo/light_effects(mob/user) + playsound(src.loc, 'sound/items/zippo_open.ogg', 100, 1, -4) + +/obj/item/weapon/flame/lighter/zippo/shutoff_effects(mob/user) + playsound(src.loc, 'sound/items/zippo_close.ogg', 100, 1, -4) + +/obj/item/weapon/flame/lighter/zippo/afterattack(obj/O, mob/user, proximity) + if(!proximity) return + if (istype(O, /obj/structure/reagent_dispensers/fueltank) && !lit) + O.reagents.trans_to_obj(src, max_fuel) + to_chat(user, "You refuel [src] from \the [O]") + playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) + +/obj/item/weapon/flame/lighter/random/New() + icon_state = "lighter-[pick("r","c","g")]"//"y", + item_state = icon_state + ..() + +/obj/item/weapon/flame/lighter/attack_self(mob/living/user) + if(!lit) + if(reagents.has_reagent(/datum/reagent/fuel)) + light(user) + else + to_chat(user, "[src] won't ignite - out of fuel.") + else + shutoff(user) + +/obj/item/weapon/flame/lighter/update_icon() + var/datum/extension/base_icon_state/bis = get_extension(src, /datum/extension/base_icon_state) + + if(lit) + icon_state = "[bis.base_icon_state]on" + item_state = "[bis.base_icon_state]on" + else + icon_state = "[bis.base_icon_state]" + item_state = "[bis.base_icon_state]" + +/obj/item/weapon/flame/lighter/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) + if(!istype(M, /mob)) + return + + if(lit) + M.IgniteMob() + + if(istype(M.wear_mask, /obj/item/clothing/mask/smokable/cigarette) && user.zone_sel.selecting == BP_MOUTH) + var/obj/item/clothing/mask/smokable/cigarette/cig = M.wear_mask + if(M == user) + cig.attackby(src, user) + else + if(istype(src, /obj/item/weapon/flame/lighter/zippo)) + cig.light("[user] whips the [name] out and holds it for [M].") + else + cig.light("[user] holds the [name] out for [M], and lights the [cig.name].") + return + + ..() + +/obj/item/weapon/flame/lighter/Process() + if(reagents.has_reagent(/datum/reagent/fuel)) + if(ismob(loc) && prob(10) && reagents.get_reagent_amount(/datum/reagent/fuel) < 1) + to_chat(loc, "[src]'s flame flickers.") + set_light(0) + spawn(4) + set_light(2) + reagents.remove_reagent(/datum/reagent/fuel, 0.05) + else + shutoff() + return + + var/turf/location = get_turf(src) + if(location) + location.hotspot_expose(700, 5) diff --git a/code/game/objects/items/weapons/circuitboards/broken.dm b/code/game/objects/items/weapons/circuitboards/broken.dm new file mode 100644 index 00000000..ce2cbb72 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/broken.dm @@ -0,0 +1,6 @@ +/obj/item/weapon/circuitboard/broken + name = "broken electronics" + icon = 'icons/obj/doors/door_assembly.dmi' + icon_state = "door_electronics_smoked" + origin_tech = null + board_type = "other" diff --git a/code/game/objects/items/weapons/circuitboards/circuitboard.dm b/code/game/objects/items/weapons/circuitboards/circuitboard.dm new file mode 100644 index 00000000..167e6f54 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/circuitboard.dm @@ -0,0 +1,37 @@ +//Define a macro that we can use to assemble all the circuit board names +#ifdef T_BOARD +#error T_BOARD already defined elsewhere, we can't use it. +#endif +#define T_BOARD(name) "circuit board (" + (name) + ")" + +/obj/item/weapon/circuitboard + name = "circuit board" + icon = 'icons/obj/module.dmi' + icon_state = "id_mod" + item_state = "electronic" + origin_tech = list(TECH_DATA = 2) + density = 0 + anchored = 0 + w_class = ITEM_SIZE_SMALL + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 5.0 + throwforce = 5.0 + throw_speed = 3 + throw_range = 15 + var/build_path = null + var/board_type = "computer" + var/list/req_components = null + var/contain_parts = 1 + +//Called when the circuitboard is used to contruct a new machine. +/obj/item/weapon/circuitboard/proc/construct(var/obj/machinery/M) + if (istype(M, build_path)) + return 1 + return 0 + +//Called when a computer is deconstructed to produce a circuitboard. +//Only used by computers, as other machines store their circuitboard instance. +/obj/item/weapon/circuitboard/proc/deconstruct(var/obj/machinery/M) + if (istype(M, build_path)) + return 1 + return 0 diff --git a/code/game/objects/items/weapons/circuitboards/computer/air_management.dm b/code/game/objects/items/weapons/circuitboards/computer/air_management.dm new file mode 100644 index 00000000..b13fb5e8 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/computer/air_management.dm @@ -0,0 +1,135 @@ +#ifndef T_BOARD +#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.SetName(console_name) + C.set_frequency(frequency) + C.sensors = sensors.Copy() + C.sensor_information = sensor_information.Copy() + return 1 + +/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/computer.dm b/code/game/objects/items/weapons/circuitboards/computer/computer.dm new file mode 100644 index 00000000..4a703a97 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/computer/computer.dm @@ -0,0 +1,143 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/message_monitor + name = T_BOARD("message monitor console") + build_path = /obj/machinery/computer/message_monitor + origin_tech = list(TECH_DATA = 3) + +/obj/item/weapon/circuitboard/aiupload + name = T_BOARD("AI upload console") + build_path = /obj/machinery/computer/aiupload + origin_tech = list(TECH_DATA = 4) + +/obj/item/weapon/circuitboard/borgupload + name = T_BOARD("cyborg upload console") + build_path = /obj/machinery/computer/borgupload + origin_tech = list(TECH_DATA = 4) + +/obj/item/weapon/circuitboard/teleporter + name = T_BOARD("teleporter control console") + build_path = /obj/machinery/computer/teleporter + origin_tech = list(TECH_DATA = 2, TECH_BLUESPACE = 2) + +/obj/item/weapon/circuitboard/atmos_alert + name = T_BOARD("atmospheric alert console") + build_path = /obj/machinery/computer/atmos_alert + +/obj/item/weapon/circuitboard/pod + name = T_BOARD("massdriver control") + build_path = /obj/machinery/computer/pod + +/obj/item/weapon/circuitboard/robotics + name = T_BOARD("robotics control console") + build_path = /obj/machinery/computer/robotics + origin_tech = list(TECH_DATA = 3) + +/obj/item/weapon/circuitboard/drone_control + name = T_BOARD("drone control console") + build_path = /obj/machinery/computer/drone_control + origin_tech = list(TECH_DATA = 3) + +/obj/item/weapon/circuitboard/arcade/battle + name = T_BOARD("battle arcade machine") + build_path = /obj/machinery/computer/arcade/battle + origin_tech = list(TECH_DATA = 1) + +/obj/item/weapon/circuitboard/arcade/orion_trail + name = T_BOARD("orion trail arcade machine") + build_path = /obj/machinery/computer/arcade/orion_trail + origin_tech = list(TECH_DATA = 1) + +/obj/item/weapon/circuitboard/turbine_control + name = T_BOARD("turbine control console") + build_path = /obj/machinery/computer/turbine_computer + +/obj/item/weapon/circuitboard/solar_control + name = T_BOARD("solar control console") + build_path = /obj/machinery/power/solar_control + origin_tech = list(TECH_DATA = 2, TECH_POWER = 2) + +/obj/item/weapon/circuitboard/powermonitor + name = T_BOARD("power monitoring console") + build_path = /obj/machinery/computer/power_monitor + +/obj/item/weapon/circuitboard/olddoor + name = T_BOARD("DoorMex") + build_path = /obj/machinery/computer/pod/old + +/obj/item/weapon/circuitboard/syndicatedoor + name = T_BOARD("ProComp Executive") + build_path = /obj/machinery/computer/pod/old/syndicate + +/obj/item/weapon/circuitboard/swfdoor + name = T_BOARD("Magix") + build_path = /obj/machinery/computer/pod/old/swf + +/obj/item/weapon/circuitboard/prisoner + name = T_BOARD("prisoner management console") + build_path = /obj/machinery/computer/prisoner + +/obj/item/weapon/circuitboard/mecha_control + name = T_BOARD("exosuit control console") + build_path = /obj/machinery/computer/mecha + +/obj/item/weapon/circuitboard/rdservercontrol + name = T_BOARD("R&D server control console") + build_path = /obj/machinery/computer/rdservercontrol + +/obj/item/weapon/circuitboard/crew + name = T_BOARD("crew monitoring console") + build_path = /obj/machinery/computer/crew + origin_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MAGNET = 2) + +/obj/item/weapon/circuitboard/operating + name = T_BOARD("patient monitoring console") + build_path = /obj/machinery/computer/operating + origin_tech = list(TECH_DATA = 2, TECH_BIO = 2) + +/obj/item/weapon/circuitboard/curefab + name = T_BOARD("cure fabricator") + build_path = /obj/machinery/computer/curer + +/obj/item/weapon/circuitboard/splicer + name = T_BOARD("disease splicer") + build_path = /obj/machinery/computer/diseasesplicer + +/obj/item/weapon/circuitboard/helm + name = T_BOARD("helm control console") + build_path = /obj/machinery/computer/helm + +/obj/item/weapon/circuitboard/nav + name = T_BOARD("navigation console") + build_path = /obj/machinery/computer/navigation + +/obj/item/weapon/circuitboard/mining_shuttle + name = T_BOARD("mining shuttle console") + build_path = /obj/machinery/computer/shuttle_control/mining + origin_tech = list(TECH_DATA = 2) + +/obj/item/weapon/circuitboard/engineering_shuttle + name = T_BOARD("engineering shuttle console") + build_path = /obj/machinery/computer/shuttle_control/engineering + origin_tech = list(TECH_DATA = 2) + +/obj/item/weapon/circuitboard/research_shuttle + name = T_BOARD("research shuttle console") + build_path = /obj/machinery/computer/shuttle_control/research + origin_tech = list(TECH_DATA = 2) + +/obj/item/weapon/circuitboard/area_atmos + name = T_BOARD("area air control console") + build_path = /obj/machinery/computer/area_atmos + origin_tech = list(TECH_DATA = 2) + +/obj/item/weapon/circuitboard/rcon_console + name = T_BOARD("RCON remote control console") + build_path = /obj/machinery/computer/rcon + origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 3, TECH_POWER = 5) + +/obj/item/weapon/circuitboard/account_database + name = T_BOARD("accounts uplink terminal") + build_path = /obj/machinery/computer/account_database \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm b/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm new file mode 100644 index 00000000..590f106e --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm @@ -0,0 +1,31 @@ +#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 = list(TECH_DATA = 2, TECH_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/circuitboards/computer/research.dm b/code/game/objects/items/weapons/circuitboards/computer/research.dm new file mode 100644 index 00000000..1a78d24c --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/computer/research.dm @@ -0,0 +1,20 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/rdconsole + name = T_BOARD("R&D control console") + build_path = /obj/machinery/computer/rdconsole/core + +/obj/item/weapon/circuitboard/rdconsole/attackby(obj/item/I as obj, mob/user as mob) + if(isScrewdriver(I)) + user.visible_message("\The [user] adjusts the jumper on \the [src]'s access protocol pins.", "You adjust the jumper on the access protocol pins.") + if(src.build_path == /obj/machinery/computer/rdconsole/core) + src.SetName(T_BOARD("RD Console - Robotics")) + src.build_path = /obj/machinery/computer/rdconsole/robotics + to_chat(user, "Access protocols set to robotics.") + else + src.SetName(T_BOARD("RD Console")) + src.build_path = /obj/machinery/computer/rdconsole/core + to_chat(user, "Access protocols set to default.") + return diff --git a/code/game/objects/items/weapons/circuitboards/computer/station_alert.dm b/code/game/objects/items/weapons/circuitboards/computer/station_alert.dm new file mode 100644 index 00000000..11b01b63 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/computer/station_alert.dm @@ -0,0 +1,29 @@ +/obj/item/weapon/circuitboard/stationalert + name = T_BOARD("alert console") + build_path = /obj/machinery/computer/station_alert + var/list/alarm_handlers + +/obj/item/weapon/circuitboard/stationalert/New() + alarm_handlers = new() + set_extension(src, /datum/extension/interactive/multitool, /datum/extension/interactive/multitool/circuitboards/stationalert) + ..() + +/obj/item/weapon/circuitboard/stationalert/construct(var/obj/machinery/computer/station_alert/SA) + if(..(SA)) + SA.unregister_monitor() + + var/datum/nano_module/alarm_monitor/monitor = new(SA) + monitor.alarm_handlers.Cut() + for(var/alarm_handler in alarm_handlers) + monitor.alarm_handlers += alarm_handler + + SA.register_monitor(monitor) + return 1 + +/obj/item/weapon/circuitboard/stationalert/deconstruct(var/obj/machinery/computer/station_alert/SA) + if(..(SA)) + alarm_handlers.Cut() + if(SA.alarm_monitor) + for(var/alarm_handler in SA.alarm_monitor.alarm_handlers) + alarm_handlers += alarm_handler + return 1 diff --git a/code/game/objects/items/weapons/circuitboards/computer/telecomms.dm b/code/game/objects/items/weapons/circuitboards/computer/telecomms.dm new file mode 100644 index 00000000..b7ad5db0 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/computer/telecomms.dm @@ -0,0 +1,18 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/comm_monitor + name = T_BOARD("telecommunications monitor console") + build_path = /obj/machinery/computer/telecomms/monitor + origin_tech = list(TECH_DATA = 3) + +/obj/item/weapon/circuitboard/comm_server + name = T_BOARD("telecommunications server monitor console") + build_path = /obj/machinery/computer/telecomms/server + origin_tech = list(TECH_DATA = 3) + +/obj/item/weapon/circuitboard/comm_traffic + name = T_BOARD("telecommunications traffic control console") + build_path = /obj/machinery/computer/telecomms/traffic + origin_tech = list(TECH_DATA = 3) diff --git a/code/game/objects/items/weapons/circuitboards/machinery/biogenerator.dm b/code/game/objects/items/weapons/circuitboards/machinery/biogenerator.dm new file mode 100644 index 00000000..8b85f881 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/biogenerator.dm @@ -0,0 +1,12 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/biogenerator + name = T_BOARD("biogenerator") + build_path = /obj/machinery/biogenerator + board_type = "machine" + origin_tech = list(TECH_DATA = 2) + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/manipulator = 1) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/cloning.dm b/code/game/objects/items/weapons/circuitboards/machinery/cloning.dm new file mode 100644 index 00000000..77fefefa --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/cloning.dm @@ -0,0 +1,34 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/resleever + name = T_BOARD("neural lace resleever") + build_path = /obj/machinery/resleever + board_type = "machine" + origin_tech = list(TECH_DATA = 3, TECH_BIO = 3) + req_components = list( + /obj/item/stack/cable_coil = 2, + /obj/item/weapon/stock_parts/scanning_module = 1, + /obj/item/weapon/stock_parts/manipulator = 3, + /obj/item/weapon/stock_parts/console_screen = 1) +/obj/item/weapon/circuitboard/bioprinter + name = T_BOARD("bioprinter") + build_path = /obj/machinery/organ_printer/flesh + board_type = "machine" + origin_tech = list(TECH_ENGINEERING = 1, TECH_BIO = 3, TECH_DATA = 3) + req_components = list( + /obj/item/device/healthanalyzer = 1, + /obj/item/weapon/stock_parts/matter_bin = 2, + /obj/item/weapon/stock_parts/manipulator = 2, + ) + +/obj/item/weapon/circuitboard/roboprinter + name = T_BOARD("prosthetic organ fabricator") + build_path = /obj/machinery/organ_printer/robot + board_type = "machine" + origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3) + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 2, + /obj/item/weapon/stock_parts/manipulator = 2, + ) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/commsantenna.dm b/code/game/objects/items/weapons/circuitboards/machinery/commsantenna.dm new file mode 100644 index 00000000..bf8b5f7f --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/commsantenna.dm @@ -0,0 +1,15 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/bluespacerelay + name = T_BOARD("bluespacerelay") + build_path = /obj/machinery/bluespacerelay + board_type = "machine" + origin_tech = list(TECH_BLUESPACE = 2, TECH_DATA = 2) + req_components = list( + /obj/item/stack/cable_coil = 30, + /obj/item/weapon/stock_parts/manipulator = 2, + /obj/item/weapon/stock_parts/subspace/filter = 1, + /obj/item/weapon/stock_parts/subspace/crystal = 1, + ) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/mech_recharger.dm b/code/game/objects/items/weapons/circuitboards/machinery/mech_recharger.dm new file mode 100644 index 00000000..ea3821a4 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/mech_recharger.dm @@ -0,0 +1,13 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/mech_recharger + name = T_BOARD("mech recharger") + build_path = /obj/machinery/mech_recharger + board_type = "machine" + origin_tech = list(TECH_DATA = 2, TECH_POWER = 2, TECH_ENGINEERING = 2) + req_components = list( + /obj/item/weapon/stock_parts/capacitor = 2, + /obj/item/weapon/stock_parts/scanning_module = 1, + /obj/item/weapon/stock_parts/manipulator = 2) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/mining_drill.dm b/code/game/objects/items/weapons/circuitboards/machinery/mining_drill.dm new file mode 100644 index 00000000..8ad2d6cb --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/mining_drill.dm @@ -0,0 +1,21 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/miningdrill + name = T_BOARD("mining drill head") + build_path = /obj/machinery/mining/drill + board_type = "machine" + origin_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1) + req_components = list( + /obj/item/weapon/stock_parts/capacitor = 1, + /obj/item/weapon/cell = 1, + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/micro_laser = 1) + +/obj/item/weapon/circuitboard/miningdrillbrace + name = T_BOARD("mining drill brace") + build_path = /obj/machinery/mining/brace + board_type = "machine" + origin_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1) + req_components = list() diff --git a/code/game/objects/items/weapons/circuitboards/machinery/oxyregenerator.dm b/code/game/objects/items/weapons/circuitboards/machinery/oxyregenerator.dm new file mode 100644 index 00000000..fa5d4765 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/oxyregenerator.dm @@ -0,0 +1,13 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/oxyregenerator + name = T_BOARD("oxygen regenerator") + build_path = /obj/machinery/atmospherics/binary/oxyregenerator + board_type = "machine" + origin_tech = list(TECH_DATA = 2) + req_components = list( + /obj/item/weapon/stock_parts/micro_laser = 1, + /obj/item/weapon/stock_parts/manipulator = 1, + /obj/item/weapon/stock_parts/matter_bin = 1) diff --git a/code/game/objects/items/weapons/circuitboards/machinery/pacman.dm b/code/game/objects/items/weapons/circuitboards/machinery/pacman.dm new file mode 100644 index 00000000..ab07b680 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/pacman.dm @@ -0,0 +1,29 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/pacman + name = T_BOARD("PACMAN-type generator") + build_path = /obj/machinery/power/port_gen/pacman + board_type = "machine" + origin_tech = list(TECH_DATA = 3, TECH_POWER = 3, TECH_PHORON = 3, TECH_ENGINEERING = 3) + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/micro_laser = 1, + /obj/item/stack/cable_coil = 2, + /obj/item/weapon/stock_parts/capacitor = 1) + +/obj/item/weapon/circuitboard/pacman/super + name = T_BOARD("SUPERPACMAN-type generator") + build_path = /obj/machinery/power/port_gen/pacman/super + origin_tech = list(TECH_DATA = 3, TECH_POWER = 4, TECH_ENGINEERING = 4) + +/obj/item/weapon/circuitboard/pacman/super/potato + name = T_BOARD("PTTO-3 nuclear generator") + build_path = /obj/machinery/power/port_gen/pacman/super/potato + origin_tech = list(TECH_DATA = 3, TECH_POWER = 5, TECH_ENGINEERING = 4) + +/obj/item/weapon/circuitboard/pacman/mrs + name = T_BOARD("MRSPACMAN-type generator") + build_path = /obj/machinery/power/port_gen/pacman/mrs + origin_tech = list(TECH_DATA = 3, TECH_POWER = 5, TECH_ENGINEERING = 5) diff --git a/code/game/objects/items/weapons/circuitboards/machinery/power.dm b/code/game/objects/items/weapons/circuitboards/machinery/power.dm new file mode 100644 index 00000000..c6dd7412 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/power.dm @@ -0,0 +1,18 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/smes + name = T_BOARD("superconductive magnetic energy storage") + build_path = /obj/machinery/power/smes/buildable + board_type = "machine" + origin_tech = list(TECH_POWER = 6, TECH_ENGINEERING = 4) + req_components = list(/obj/item/weapon/smes_coil = 1, /obj/item/stack/cable_coil = 30) + + +/obj/item/weapon/circuitboard/batteryrack + name = T_BOARD("battery rack PSU") + build_path = /obj/machinery/power/smes/batteryrack + board_type = "machine" + origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 2) + req_components = list(/obj/item/weapon/stock_parts/capacitor/ = 3, /obj/item/weapon/stock_parts/matter_bin/ = 1) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/recharge_station.dm b/code/game/objects/items/weapons/circuitboards/machinery/recharge_station.dm new file mode 100644 index 00000000..295e3aed --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/recharge_station.dm @@ -0,0 +1,14 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/recharge_station + name = T_BOARD("cyborg recharging station") + build_path = /obj/machinery/recharge_station + board_type = "machine" + origin_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 3) + req_components = list( + /obj/item/stack/cable_coil = 5, + /obj/item/weapon/stock_parts/capacitor = 2, + /obj/item/weapon/stock_parts/manipulator = 2, + /obj/item/weapon/cell = 1) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/replicator.dm b/code/game/objects/items/weapons/circuitboards/machinery/replicator.dm new file mode 100644 index 00000000..46938057 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/replicator.dm @@ -0,0 +1,13 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/replicator + name = T_BOARD("food replicator") + build_path = /obj/machinery/food_replicator + board_type = "machine" + origin_tech = list(TECH_DATA = 2) + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/manipulator = 1, + /obj/item/weapon/stock_parts/micro_laser = 1) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/research.dm b/code/game/objects/items/weapons/circuitboards/machinery/research.dm new file mode 100644 index 00000000..9c28c73e --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/research.dm @@ -0,0 +1,82 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +obj/item/weapon/circuitboard/rdserver + name = T_BOARD("R&D server") + build_path = /obj/machinery/r_n_d/server + board_type = "machine" + origin_tech = list(TECH_DATA = 3) + req_components = list( + /obj/item/stack/cable_coil = 2, + /obj/item/weapon/stock_parts/scanning_module = 1) + +/obj/item/weapon/circuitboard/destructive_analyzer + name = T_BOARD("destructive analyzer") + build_path = /obj/machinery/r_n_d/destructive_analyzer + board_type = "machine" + origin_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 2, TECH_DATA = 2) + req_components = list( + /obj/item/weapon/stock_parts/scanning_module = 1, + /obj/item/weapon/stock_parts/manipulator = 1, + /obj/item/weapon/stock_parts/micro_laser = 1) + +/obj/item/weapon/circuitboard/autolathe + name = T_BOARD("autolathe") + build_path = /obj/machinery/autolathe + board_type = "machine" + origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2) + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 3, + /obj/item/weapon/stock_parts/manipulator = 1, + /obj/item/weapon/stock_parts/console_screen = 1) + +/obj/item/weapon/circuitboard/protolathe + name = T_BOARD("protolathe") + build_path = /obj/machinery/r_n_d/protolathe + board_type = "machine" + origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2) + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 2, + /obj/item/weapon/stock_parts/manipulator = 2, + /obj/item/weapon/reagent_containers/glass/beaker = 2) + + +/obj/item/weapon/circuitboard/circuit_imprinter + name = T_BOARD("circuit imprinter") + build_path = /obj/machinery/r_n_d/circuit_imprinter + board_type = "machine" + origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2) + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/manipulator = 1, + /obj/item/weapon/reagent_containers/glass/beaker = 2) + +/obj/item/weapon/circuitboard/mechfab + name = "Circuit board (Exosuit Fabricator)" + build_path = /obj/machinery/mecha_part_fabricator + board_type = "machine" + origin_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 3) + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 2, + /obj/item/weapon/stock_parts/manipulator = 1, + /obj/item/weapon/stock_parts/micro_laser = 1, + /obj/item/weapon/stock_parts/console_screen = 1) + +/obj/item/weapon/circuitboard/ntnet_relay + name = "Circuit board (NTNet Quantum Relay)" + build_path = /obj/machinery/ntnet_relay + board_type = "machine" + origin_tech = list(TECH_DATA = 4) + req_components = list( + /obj/item/stack/cable_coil = 15) + +/obj/item/weapon/circuitboard/integrated_printer + name = "Circuit board (Integrated Circuit Printer)" + build_path = /obj/machinery/integrated_circuit_printer + board_type = "machine" + origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2) + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/manipulator = 1, + /obj/item/weapon/stock_parts/micro_laser = 1) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/shieldgen.dm b/code/game/objects/items/weapons/circuitboards/machinery/shieldgen.dm new file mode 100644 index 00000000..14ad0c3a --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/shieldgen.dm @@ -0,0 +1,23 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif +// New shields +/obj/item/weapon/circuitboard/shield_generator + name = T_BOARD("advanced shield generator") + board_type = "machine" + build_path = /obj/machinery/power/shield_generator + origin_tech = list(TECH_MAGNET = 3, TECH_POWER = 4) + req_components = list( + /obj/item/weapon/stock_parts/capacitor = 1, + /obj/item/weapon/stock_parts/micro_laser = 1, + /obj/item/weapon/smes_coil = 1, + /obj/item/weapon/stock_parts/console_screen = 1) + +/obj/item/weapon/circuitboard/shield_diffuser + name = T_BOARD("shield diffuser") + board_type = "machine" + build_path = /obj/machinery/shield_diffuser + origin_tech = list(TECH_MAGNET = 4, TECH_POWER = 2) + req_components = list( + /obj/item/weapon/stock_parts/capacitor = 1, + /obj/item/weapon/stock_parts/micro_laser = 1) diff --git a/code/game/objects/items/weapons/circuitboards/machinery/telecomms.dm b/code/game/objects/items/weapons/circuitboards/machinery/telecomms.dm new file mode 100644 index 00000000..241b6e94 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/telecomms.dm @@ -0,0 +1,75 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/telecomms + board_type = "machine" + +/obj/item/weapon/circuitboard/telecomms/receiver + name = T_BOARD("subspace receiver") + build_path = /obj/machinery/telecomms/receiver + origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 3, TECH_BLUESPACE = 2) + req_components = list( + /obj/item/weapon/stock_parts/subspace/ansible = 1, + /obj/item/weapon/stock_parts/subspace/filter = 1, + /obj/item/weapon/stock_parts/manipulator = 2, + /obj/item/weapon/stock_parts/micro_laser = 1) + +/obj/item/weapon/circuitboard/telecomms/hub + name = T_BOARD("hub mainframe") + build_path = /obj/machinery/telecomms/hub + origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4) + req_components = list( + /obj/item/weapon/stock_parts/manipulator = 2, + /obj/item/stack/cable_coil = 2, + /obj/item/weapon/stock_parts/subspace/filter = 2) + +/obj/item/weapon/circuitboard/telecomms/relay + name = T_BOARD("relay mainframe") + build_path = /obj/machinery/telecomms/relay + origin_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 4, TECH_BLUESPACE = 3) + req_components = list( + /obj/item/weapon/stock_parts/manipulator = 2, + /obj/item/stack/cable_coil = 2, + /obj/item/weapon/stock_parts/subspace/filter = 2) + +/obj/item/weapon/circuitboard/telecomms/bus + name = T_BOARD("bus mainframe") + build_path = /obj/machinery/telecomms/bus + origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4) + req_components = list( + /obj/item/weapon/stock_parts/manipulator = 2, + /obj/item/stack/cable_coil = 1, + /obj/item/weapon/stock_parts/subspace/filter = 1) + +/obj/item/weapon/circuitboard/telecomms/processor + name = T_BOARD("processor unit") + build_path = /obj/machinery/telecomms/processor + origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4) + req_components = list( + /obj/item/weapon/stock_parts/manipulator = 3, + /obj/item/weapon/stock_parts/subspace/filter = 1, + /obj/item/weapon/stock_parts/subspace/treatment = 2, + /obj/item/weapon/stock_parts/subspace/analyzer = 1, + /obj/item/stack/cable_coil = 2, + /obj/item/weapon/stock_parts/subspace/amplifier = 1) + +/obj/item/weapon/circuitboard/telecomms/server + name = T_BOARD("telecommunication server") + build_path = /obj/machinery/telecomms/server + origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4) + req_components = list( + /obj/item/weapon/stock_parts/manipulator = 2, + /obj/item/stack/cable_coil = 1, + /obj/item/weapon/stock_parts/subspace/filter = 1) + +/obj/item/weapon/circuitboard/telecomms/broadcaster + name = T_BOARD("subspace broadcaster") + build_path = /obj/machinery/telecomms/broadcaster + origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4, TECH_BLUESPACE = 2) + req_components = list( + /obj/item/weapon/stock_parts/manipulator = 2, + /obj/item/stack/cable_coil = 1, + /obj/item/weapon/stock_parts/subspace/filter = 1, + /obj/item/weapon/stock_parts/subspace/crystal = 1, + /obj/item/weapon/stock_parts/micro_laser/high = 2) diff --git a/code/game/objects/items/weapons/circuitboards/machinery/unary_atmos.dm b/code/game/objects/items/weapons/circuitboards/machinery/unary_atmos.dm new file mode 100644 index 00000000..4b7ecf78 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/unary_atmos.dm @@ -0,0 +1,33 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/unary_atmos + board_type = "machine" + +/obj/item/weapon/circuitboard/unary_atmos/construct(var/obj/machinery/atmospherics/unary/U) + //TODO: Move this stuff into the relevant constructor when pipe/construction.dm is cleaned up. + U.atmos_init() + U.build_network() + if (U.node) + U.node.atmos_init() + U.node.build_network() + +/obj/item/weapon/circuitboard/unary_atmos/heater + name = T_BOARD("gas heating system") + build_path = /obj/machinery/atmospherics/unary/heater + origin_tech = list(TECH_POWER = 2, TECH_ENGINEERING = 1) + req_components = list( + /obj/item/stack/cable_coil = 5, + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/capacitor = 2) + +/obj/item/weapon/circuitboard/unary_atmos/cooler + name = T_BOARD("gas cooling system") + build_path = /obj/machinery/atmospherics/unary/freezer + origin_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 2) + req_components = list( + /obj/item/stack/cable_coil = 2, + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/capacitor = 2, + /obj/item/weapon/stock_parts/manipulator = 1) diff --git a/code/game/objects/items/weapons/circuitboards/mecha.dm b/code/game/objects/items/weapons/circuitboards/mecha.dm new file mode 100644 index 00000000..4c0a15a4 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/mecha.dm @@ -0,0 +1,88 @@ +#ifdef T_BOARD_MECHA +#error T_BOARD_MECHA already defined elsewhere, we can't use it. +#endif +#define T_BOARD_MECHA(name) "exosuit module circuit board (" + (name) + ")" + +/obj/item/weapon/circuitboard/mecha + name = "exosuit circuit board" + icon = 'icons/obj/module.dmi' + icon_state = "std_mod" + item_state = "electronic" + board_type = "other" + + +/obj/item/weapon/circuitboard/mecha/ripley + origin_tech = list(TECH_DATA = 3) + +/obj/item/weapon/circuitboard/mecha/ripley/peripherals + name = T_BOARD_MECHA("Ripley peripherals control") + icon_state = "mcontroller" + +/obj/item/weapon/circuitboard/mecha/ripley/main + name = T_BOARD_MECHA("Ripley central control") + icon_state = "mainboard" + + +/obj/item/weapon/circuitboard/mecha/gygax + origin_tech = list(TECH_DATA = 4) + +/obj/item/weapon/circuitboard/mecha/gygax/peripherals + name = T_BOARD_MECHA("Gygax peripherals control") + icon_state = "mcontroller" + +/obj/item/weapon/circuitboard/mecha/gygax/targeting + name = T_BOARD_MECHA("Gygax weapon control and targeting") + icon_state = "mcontroller" + origin_tech = list(TECH_DATA = 4, TECH_COMBAT = 4) + +/obj/item/weapon/circuitboard/mecha/gygax/main + name = T_BOARD_MECHA("Gygax central control") + icon_state = "mainboard" + + +/obj/item/weapon/circuitboard/mecha/durand + origin_tech = list(TECH_DATA = 4) + +/obj/item/weapon/circuitboard/mecha/durand/peripherals + name = T_BOARD_MECHA("Durand peripherals control") + icon_state = "mcontroller" + +/obj/item/weapon/circuitboard/mecha/durand/targeting + name = T_BOARD_MECHA("Durand weapon control and targeting") + icon_state = "mcontroller" + origin_tech = list(TECH_DATA = 4, TECH_COMBAT = 4) + +/obj/item/weapon/circuitboard/mecha/durand/main + name = T_BOARD_MECHA("Durand central control") + icon_state = "mainboard" + + +/obj/item/weapon/circuitboard/mecha/honker + origin_tech = list(TECH_DATA = 4) + +/obj/item/weapon/circuitboard/mecha/honker/peripherals + name = T_BOARD_MECHA("H.O.N.K peripherals control") + icon_state = "mcontroller" + +/obj/item/weapon/circuitboard/mecha/honker/targeting + name = T_BOARD_MECHA("H.O.N.K weapon control and targeting") + icon_state = "mcontroller" + +/obj/item/weapon/circuitboard/mecha/honker/main + name = T_BOARD_MECHA("H.O.N.K central control") + icon_state = "mainboard" + + +/obj/item/weapon/circuitboard/mecha/odysseus + origin_tech = list(TECH_DATA = 3) + +/obj/item/weapon/circuitboard/mecha/odysseus/peripherals + name = T_BOARD_MECHA("Odysseus peripherals control") + icon_state = "mcontroller" + +/obj/item/weapon/circuitboard/mecha/odysseus/main + name = T_BOARD_MECHA("Odysseus central control") + icon_state = "mainboard" + +//Undef the macro, shouldn't be needed anywhere else +#undef T_BOARD_MECHA \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/other.dm b/code/game/objects/items/weapons/circuitboards/other.dm new file mode 100644 index 00000000..6d016a96 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/other.dm @@ -0,0 +1,10 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +//Stuff that doesn't fit into any category goes here + +/obj/item/weapon/circuitboard/aicore + name = T_BOARD("AI core") + origin_tech = list(TECH_DATA = 4, TECH_BIO = 2) + board_type = "other" diff --git a/code/game/objects/items/weapons/clothingbag.dm b/code/game/objects/items/weapons/clothingbag.dm new file mode 100644 index 00000000..33759863 --- /dev/null +++ b/code/game/objects/items/weapons/clothingbag.dm @@ -0,0 +1,47 @@ +/obj/item/weapon/clothingbag + name = "clothing bag" + desc = "A cheap plastic bag that contains a fresh set of clothes." + icon = 'icons/obj/trash.dmi' + icon_state = "trashbag3" + + var/icon_used = "trashbag0" + var/opened = 0 + +/obj/item/weapon/clothingbag/attack_self(mob/user as mob) + if(!opened) + user.visible_message("\The [user] tears open \the [src.name]!", "You tear open \the [src.name]!") + opened = 1 + icon_state = icon_used + for(var/obj/item in contents) + item.dropInto(loc) + else + to_chat(user, "\The [src.name] is already ripped open and is now completely useless!") + +/obj/item/weapon/clothingbag/rubbersuit + name = "rubber suit bag" + desc = "A cheap plastic bag that contains an emergency party set." + +/obj/item/weapon/clothingbag/rubbersuit/New() + ..() + switch(rand(1,4)) + if(1) + new/obj/item/clothing/suit/rubber(src) + new/obj/item/clothing/mask/rubber/species(src) + if(2) + new/obj/item/clothing/suit/rubber/tajaran(src) + new/obj/item/clothing/mask/rubber/species/tajaran(src) + if(3) + new/obj/item/clothing/suit/rubber/skrell(src) + new/obj/item/clothing/mask/rubber/species/skrell(src) + if(4) + new/obj/item/clothing/suit/rubber/unathi(src) + new/obj/item/clothing/mask/rubber/species/unathi(src) + +/obj/item/weapon/clothingbag/rubbermask + name = "rubber masks bag" + desc = "A cheap plastic bag that contains emergency Halloween supplies." + +/obj/item/weapon/clothingbag/rubbermask/New() + ..() + for(var/T in subtypesof(/obj/item/clothing/mask/rubber)) + new T(src) \ No newline at end of file diff --git a/code/game/objects/items/weapons/clown_items.dm b/code/game/objects/items/weapons/clown_items.dm new file mode 100644 index 00000000..b4d7b7ec --- /dev/null +++ b/code/game/objects/items/weapons/clown_items.dm @@ -0,0 +1,55 @@ +/* Clown Items + * Contains: + * Banana Peels + * Bike Horns + */ + +/* + * Banana Peals + */ +/obj/item/weapon/bananapeel/Crossed(AM as mob|obj) + if (istype(AM, /mob/living)) + var/mob/living/M = AM + M.slip("the [src.name]",4) +/* + * Bike Horns + */ +/obj/item/weapon/bikehorn + name = "bike horn" + desc = "A horn off of a bicycle." + icon = 'icons/obj/items.dmi' + icon_state = "bike_horn" + item_state = "bike_horn" + throwforce = 3 + w_class = ITEM_SIZE_SMALL + throw_speed = 3 + throw_range = 15 + attack_verb = list("HONKED") + var/spam_flag = 0 + +/obj/item/weapon/bikehorn/attack_self(mob/user as mob) + if (spam_flag == 0) + spam_flag = 1 + playsound(src.loc, 'sound/items/bikehorn.ogg', 50, 1) + src.add_fingerprint(user) + spawn(20) + spam_flag = 0 + return + +/obj/item/weapon/randy + name = "Plushie Leha" + icon = 'icons/obj/items.dmi' + icon_state = "rendos" + item_state = "bike_horn" + w_class = ITEM_SIZE_SMALL + var/list/jokes = list("Äîðîãàÿ, ÿ íàçâàë íàøåãî ñûíà ëàéáåá!", "Íî çàòî ó íàñ åñòü ëàéáåá!", "Ëþáëþ ìÿãêèå èãðóøêè èç òâåðäûõ ëþäåé..", "ß òåïåðü ñâåðõ÷åëîâåê!", "Ìíå åùå è ïîìîãàòü òåáå ëàéáàõ èìèòèðîâàòü?", "ïèøó äîíîñ", "ñëèøêîì ìíîãî âîéíû...", "íà÷èíàé çà ñîáîé ñëåäèòü è âñå íàëàäèòñÿ", "Îñòàëñÿ, ðàçîáðàëñÿ, çíà÷èò - ìåøêîì åáíóòûé", "íåîáõîäèìîå çëî, ÷òîáû ïîëó÷èòü ðåçóëüòàò") + var/list/rendos_sounds = list('sound/voice/allo.ogg') + var/spam_flag = 0 + +/obj/item/weapon/randy/attack_self(mob/user) + if(!spam_flag) + spam_flag = 1 + playsound(src.loc, pick(rendos_sounds), 50, 1) + user.visible_message("[src.name] says, \"[pick(jokes)]\"") + spawn(40) + spam_flag = 0 \ No newline at end of file diff --git a/code/game/objects/items/weapons/cosmetics.dm b/code/game/objects/items/weapons/cosmetics.dm new file mode 100644 index 00000000..e349d021 --- /dev/null +++ b/code/game/objects/items/weapons/cosmetics.dm @@ -0,0 +1,81 @@ +/obj/item/weapon/lipstick + gender = PLURAL + name = "red lipstick" + desc = "A generic brand of lipstick." + icon = 'icons/obj/items.dmi' + icon_state = "lipstick" + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + var/colour = "red" + var/open = 0 + + +/obj/item/weapon/lipstick/purple + name = "purple lipstick" + colour = "purple" + +/obj/item/weapon/lipstick/jade + name = "jade lipstick" + colour = "jade" + +/obj/item/weapon/lipstick/black + name = "black lipstick" + colour = "black" + + +/obj/item/weapon/lipstick/random + name = "lipstick" + +/obj/item/weapon/lipstick/random/New() + colour = pick("red","purple","jade","black") + name = "[colour] lipstick" + + +/obj/item/weapon/lipstick/attack_self(mob/user as mob) + to_chat(user, "You twist \the [src] [open ? "closed" : "open"].") + open = !open + if(open) + icon_state = "[initial(icon_state)]_[colour]" + else + icon_state = initial(icon_state) + +/obj/item/weapon/lipstick/attack(mob/M as mob, mob/user as mob) + if(!open) return + + if(!istype(M, /mob)) return + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.lip_style) //if they already have lipstick on + to_chat(user, "You need to wipe off the old lipstick first!") + return + if(H == user) + user.visible_message("[user] does their lips with \the [src].", \ + "You take a moment to apply \the [src]. Perfect!") + H.lip_style = colour + H.update_body() + else + user.visible_message("[user] begins to do [H]'s lips with \the [src].", \ + "You begin to apply \the [src].") + if(do_after(user, 20, H) && do_after(H, 20, needhand = 0, progress = 0, incapacitation_flags = INCAPACITATION_NONE)) //user needs to keep their active hand, H does not. + user.visible_message("[user] does [H]'s lips with \the [src].", \ + "You apply \the [src].") + H.lip_style = colour + H.update_body() + else + to_chat(user, "Where are the lips on that?") + +//you can wipe off lipstick with paper! see code/modules/paperwork/paper.dm, paper/attack() + + +/obj/item/weapon/haircomb //sparklysheep's comb + name = "plastic comb" + desc = "A pristine comb made from flexible plastic." + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + icon = 'icons/obj/items.dmi' + icon_state = "comb" + item_state = "comb" + +/obj/item/weapon/haircomb/attack_self(mob/user) + user.visible_message("[user] uses [src] to comb their hair with incredible style and sophistication. What a [user.gender == FEMALE ? "lady" : "guy"].") \ No newline at end of file diff --git a/code/game/objects/items/weapons/crutches.dm b/code/game/objects/items/weapons/crutches.dm new file mode 100644 index 00000000..71b6bdc9 --- /dev/null +++ b/code/game/objects/items/weapons/crutches.dm @@ -0,0 +1,7 @@ +/obj/item/weapon/crutches + name = "crutches" + gender = PLURAL + desc = "You use them to walk when you're legs or feet are broken. Can also be used to break others' legs and feet." + icon_state = "crutches" + item_state = "crutches" + force = 5 \ No newline at end of file diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm new file mode 100644 index 00000000..b304e447 --- /dev/null +++ b/code/game/objects/items/weapons/defib.dm @@ -0,0 +1,578 @@ +#define DEFIB_TIME_LIMIT (8 MINUTES) //past this many seconds, defib is useless. Currently 8 Minutes +#define DEFIB_TIME_LOSS (2 MINUTES) //past this many seconds, brain damage occurs. Currently 2 minutes + +//backpack item +/obj/item/weapon/defibrillator + name = "auto-resuscitator" + desc = "A device that delivers powerful shocks via detachable paddles to resuscitate incapacitated patients." + icon = 'icons/obj/defibrillator.dmi' + icon_state = "defibunit" + item_state = "defibunit" + slot_flags = SLOT_BACK + force = 5 + throwforce = 6 + w_class = ITEM_SIZE_LARGE + origin_tech = list(TECH_BIO = 4, TECH_POWER = 2) + action_button_name = "Remove/Replace Paddles" + + var/obj/item/weapon/shockpaddles/linked/paddles + var/obj/item/weapon/cell/bcell = null + +/obj/item/weapon/defibrillator/New() //starts without a cell for rnd + ..() + if(ispath(paddles)) + paddles = new paddles(src, src) + else + paddles = new(src, src) + + if(ispath(bcell)) + bcell = new bcell(src) + update_icon() + +/obj/item/weapon/defibrillator/Destroy() + . = ..() + QDEL_NULL(paddles) + QDEL_NULL(bcell) + +/obj/item/weapon/defibrillator/loaded //starts with regular power cell for R&D to replace later in the round. + bcell = /obj/item/weapon/cell/apc + +/obj/item/weapon/defibrillator/update_icon() + var/list/new_overlays = list() + + if(paddles) //in case paddles got destroyed somehow. + if(paddles.loc == src) + new_overlays += "[initial(icon_state)]-paddles" + if(bcell && bcell.check_charge(paddles.chargecost)) + if(!paddles.safety) + new_overlays += "[initial(icon_state)]-emagged" + else + new_overlays += "[initial(icon_state)]-powered" + + if(bcell) + var/ratio = Ceiling(bcell.percent()/25) * 25 + new_overlays += "[initial(icon_state)]-charge[ratio]" + else + new_overlays += "[initial(icon_state)]-nocell" + + overlays = new_overlays + +/obj/item/weapon/defibrillator/ui_action_click() + toggle_paddles() + +/obj/item/weapon/defibrillator/attack_hand(mob/user) + if(loc == user) + toggle_paddles() + else + ..() + +/obj/item/weapon/defibrillator/MouseDrop() + if(ismob(src.loc)) + if(!CanMouseDrop(src)) + return + var/mob/M = src.loc + if(!M.unEquip(src)) + return + src.add_fingerprint(usr) + M.put_in_any_hand_if_possible(src) + + +/obj/item/weapon/defibrillator/attackby(obj/item/weapon/W, mob/user, params) + if(W == paddles) + reattach_paddles(user) + else if(istype(W, /obj/item/weapon/cell)) + if(bcell) + to_chat(user, "\the [src] already has a cell.") + else + if(!user.unEquip(W)) + return + W.forceMove(src) + bcell = W + to_chat(user, "You install a cell in \the [src].") + update_icon() + + else if(isScrewdriver(W)) + if(bcell) + bcell.update_icon() + bcell.forceMove(get_turf(src.loc)) + bcell = null + to_chat(user, "You remove the cell from \the [src].") + update_icon() + else + return ..() + +/obj/item/weapon/defibrillator/emag_act(mob/user) + if(paddles) + return paddles.emag_act(user) + return NO_EMAG_ACT + +//Paddle stuff + +/obj/item/weapon/defibrillator/verb/toggle_paddles() + set name = "Toggle Paddles" + set category = "Object" + + var/mob/living/carbon/human/user = usr + if(!paddles) + to_chat(user, "The paddles are missing!") + return + + if(paddles.loc != src) + reattach_paddles(user) //Remove from their hands and back onto the defib unit + return + + if(!slot_check()) + to_chat(user, "You need to equip [src] before taking out [paddles].") + else + if(!usr.put_in_hands(paddles)) //Detach the paddles into the user's hands + to_chat(user, "You need a free hand to hold the paddles!") + update_icon() //success + +//checks that the base unit is in the correct slot to be used +/obj/item/weapon/defibrillator/proc/slot_check() + var/mob/M = loc + if(!istype(M)) + return 0 //not equipped + + if((slot_flags & SLOT_BACK) && M.get_equipped_item(slot_back) == src) + return 1 + if((slot_flags & SLOT_BELT) && M.get_equipped_item(slot_belt) == src) + return 1 + + return 0 + +/obj/item/weapon/defibrillator/dropped(mob/user) + ..() + reattach_paddles(user) //paddles attached to a base unit should never exist outside of their base unit or the mob equipping the base unit + +/obj/item/weapon/defibrillator/proc/reattach_paddles(mob/user) + if(!paddles) return + + if(ismob(paddles.loc)) + var/mob/M = paddles.loc + if(M.drop_from_inventory(paddles, src)) + to_chat(user, "\The [paddles] snap back into the main unit.") + else + paddles.forceMove(src) + + update_icon() + +/* + Base Unit Subtypes +*/ + +/obj/item/weapon/defibrillator/compact + name = "compact defibrillator" + desc = "A belt-equipped defibrillator that can be rapidly deployed." + icon_state = "defibcompact" + item_state = "defibcompact" + w_class = ITEM_SIZE_NORMAL + slot_flags = SLOT_BELT + origin_tech = list(TECH_BIO = 5, TECH_POWER = 3) + +/obj/item/weapon/defibrillator/compact/loaded + bcell = /obj/item/weapon/cell/high + + +/obj/item/weapon/defibrillator/compact/combat + name = "combat defibrillator" + desc = "A belt-equipped blood-red defibrillator that can be rapidly deployed. Does not have the restrictions or safeties of conventional defibrillators and can revive through space suits." + paddles = /obj/item/weapon/shockpaddles/linked/combat + +/obj/item/weapon/defibrillator/compact/combat/loaded + bcell = /obj/item/weapon/cell/high + +/obj/item/weapon/shockpaddles/linked/combat + combat = 1 + safety = 0 + chargetime = (1 SECONDS) + + +//paddles + +/obj/item/weapon/shockpaddles + name = "defibrillator paddles" + desc = "A pair of plastic-gripped paddles with flat metal surfaces that are used to deliver powerful electric shocks." + icon = 'icons/obj/defibrillator.dmi' + icon_state = "defibpaddles" + item_state = "defibpaddles" + gender = PLURAL + force = 2 + throwforce = 6 + w_class = ITEM_SIZE_LARGE + + var/safety = 1 //if you can zap people with the paddles on harm mode + var/combat = 0 //If it can be used to revive people wearing thick clothing (e.g. spacesuits) + var/cooldowntime = (6 SECONDS) // How long in deciseconds until the defib is ready again after use. + var/chargetime = (2 SECONDS) + var/chargecost = 100 //units of charge + var/burn_damage_amt = 5 + +// var/wielded = 0 + var/cooldown = 0 + var/busy = 0 + +/obj/item/weapon/shockpaddles/proc/set_cooldown(var/delay) + cooldown = 1 + update_icon() + + spawn(delay) + if(cooldown) + cooldown = 0 + update_icon() + + make_announcement("beeps, \"Unit is re-energized.\"", "notice") + playsound(src, 'sound/machines/defib_ready.ogg', 50, 0) +/* +/obj/item/weapon/shockpaddles/update_twohanding() + var/mob/living/M = loc + if(istype(M) && is_held_twohanded(M)) + wielded = 1 + SetName("[initial(name)] (wielded)") + else + wielded = 0 + SetName(initial(name)) + update_icon() + ..() +*/ +/obj/item/weapon/shockpaddles/update_icon() + icon_state = "defibpaddles[wielded]" + item_state = "defibpaddles[wielded]" + if(cooldown) + icon_state = "defibpaddles[wielded]_cooldown" + +/obj/item/weapon/shockpaddles/proc/can_use(mob/user, mob/M) + if(busy) + return 0 + if(!check_charge(chargecost)) + to_chat(user, "\The [src] doesn't have enough charge left to do that.") + return 0 + if(!wielded && !isrobot(user)) + to_chat(user, "You need to wield the paddles with both hands before you can use them on someone!") + return 0 + if(cooldown) + to_chat(user, "\The [src] are re-energizing!") + return 0 + return 1 + +//Checks for various conditions to see if the mob is revivable +/obj/item/weapon/shockpaddles/proc/can_defib(mob/living/carbon/human/H) //This is checked before doing the defib operation + if((H.species.species_flags & SPECIES_FLAG_NO_SCAN) || H.isSynthetic()) + return "buzzes, \"Unrecogized physiology. Operation aborted.\"" + + if(!check_contact(H)) + return "buzzes, \"Patient's chest is obstructed. Operation aborted.\"" + +/obj/item/weapon/shockpaddles/proc/can_revive(mob/living/carbon/human/H) //This is checked right before attempting to revive + if(H.stat == DEAD) + return "buzzes, \"Resuscitation failed - Severe neurological decay makes recovery of patient impossible. Further attempts futile.\"" + +/obj/item/weapon/shockpaddles/proc/check_contact(mob/living/carbon/human/H) + if(!combat) + for(var/obj/item/clothing/cloth in list(H.wear_suit, H.w_uniform)) + if((cloth.body_parts_covered & UPPER_TORSO) && (cloth.item_flags & ITEM_FLAG_THICKMATERIAL)) + return FALSE + return TRUE + +/obj/item/weapon/shockpaddles/proc/check_blood_level(mob/living/carbon/human/H) + if(!H.should_have_organ(BP_HEART)) + return FALSE + var/obj/item/organ/internal/heart/heart = H.internal_organs_by_name[BP_HEART] + if(!heart || H.get_blood_volume() < BLOOD_VOLUME_SURVIVE) + return TRUE + return FALSE + +/obj/item/weapon/shockpaddles/proc/check_charge(var/charge_amt) + return 0 + +/obj/item/weapon/shockpaddles/proc/checked_use(var/charge_amt) + return 0 + +/obj/item/weapon/shockpaddles/attack(mob/living/M, mob/living/user, var/target_zone) + var/mob/living/carbon/human/H = M + if(!istype(H) || user.a_intent == I_HURT) + return ..() //Do a regular attack. Harm intent shocking happens as a hit effect + + if(can_use(user, H)) + busy = 1 + update_icon() + + do_revive(H, user) + + busy = 0 + update_icon() + + return 1 + +//Since harm-intent now skips the delay for deliberate placement, you have to be able to hit them in combat in order to shock people. +/obj/item/weapon/shockpaddles/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) + if(ishuman(target) && can_use(user, target)) + busy = 1 + update_icon() + + do_electrocute(target, user, hit_zone) + + busy = 0 + update_icon() + + return 1 + + return ..() + +// This proc is used so that we can return out of the revive process while ensuring that busy and update_icon() are handled +/obj/item/weapon/shockpaddles/proc/do_revive(mob/living/carbon/human/H, mob/user) + if(H.ssd_check()) + to_chat(find_dead_player(H.ckey, 1), "Someone is attempting to resuscitate you. Re-enter your body if you want to be revived!") + + //beginning to place the paddles on patient's chest to allow some time for people to move away to stop the process + user.visible_message("\The [user] begins to place [src] on [H]'s chest.", "You begin to place [src] on [H]'s chest...") + if(!do_after(user, 30, H)) + return + user.visible_message("\The [user] places [src] on [H]'s chest.", "You place [src] on [H]'s chest.") + playsound(get_turf(src), 'sound/machines/defib_charge.ogg', 50, 0) + + var/error = can_defib(H) + if(error) + make_announcement(error, "warning") + playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0) + return + + if(check_blood_level(H)) + make_announcement("buzzes, \"Warning - Patient is in hypovolemic shock and may require a blood transfusion.\"", "warning") //also includes heart damage + + //placed on chest and short delay to shock for dramatic effect, revive time is 5sec total + if(!do_after(user, chargetime, H)) + return + + //deduct charge here, in case the base unit was EMPed or something during the delay time + if(!checked_use(chargecost)) + make_announcement("buzzes, \"Insufficient charge.\"", "warning") + playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0) + return + + H.visible_message("\The [H]'s body convulses a bit.") + playsound(get_turf(src), "bodyfall", 50, 1) + playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 50, 1, -1) + set_cooldown(cooldowntime) + + error = can_revive(H) + if(error) + make_announcement(error, "warning") + playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0) + return + + H.apply_damage(burn_damage_amt, BURN, BP_CHEST) + + //set oxyloss so that the patient is just barely in crit, if possible + make_announcement("pings, \"Resuscitation successful.\"", "notice") + playsound(get_turf(src), 'sound/machines/defib_success.ogg', 50, 0) + user.unlock_achievement(new/datum/achievement/revive()) + H.resuscitate() + var/obj/item/organ/internal/cell/potato = H.internal_organs_by_name[BP_CELL] + if(istype(potato) && potato.cell) + var/obj/item/weapon/cell/C = potato.cell + C.give(chargecost) + log_and_message_admins("used \a [src] to revive [key_name(H)].") + + +/obj/item/weapon/shockpaddles/proc/do_electrocute(mob/living/carbon/human/H, mob/user, var/target_zone) + var/obj/item/organ/external/affecting = H.get_organ(target_zone) + if(!affecting) + to_chat(user, "They are missing that body part!") + return + + //no need to spend time carefully placing the paddles, we're just trying to shock them + user.visible_message("\The [user] slaps [src] onto [H]'s [affecting.name].", "You overcharge [src] and slap them onto [H]'s [affecting.name].") + + //Just stop at awkwardly slapping electrodes on people if the safety is enabled + if(safety) + to_chat(user, "You can't do that while the safety is enabled.") + return + + playsound(get_turf(src), 'sound/machines/defib_charge.ogg', 50, 0) + audible_message("\The [src] lets out a steadily rising hum...") + + if(!do_after(user, chargetime, H)) + return + + //deduct charge here, in case the base unit was EMPed or something during the delay time + if(!checked_use(chargecost)) + make_announcement("buzzes, \"Insufficient charge.\"", "warning") + playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0) + return + + user.visible_message("\The [user] shocks [H] with \the [src]!", "You shock [H] with \the [src]!") + playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 100, 1, -1) + playsound(loc, 'sound/weapons/Egloves.ogg', 100, 1, -1) + set_cooldown(cooldowntime) + + H.stun_effect_act(2, 120, target_zone) + var/burn_damage = H.electrocute_act(burn_damage_amt*2, src, def_zone = target_zone) + if(burn_damage > 15 && H.can_feel_pain()) + H.emote("scream") + + admin_attack_log(user, H, "Electrocuted using \a [src]", "Was electrocuted with \a [src]", "used \a [src] to electrocute") + +/obj/item/weapon/shockpaddles/proc/make_alive(mob/living/carbon/human/M) //This revives the mob + var/deadtime = world.time - M.timeofdeath + + M.switch_from_dead_to_living_mob_list() + M.timeofdeath = 0 + M.set_stat(UNCONSCIOUS) //Life() can bring them back to consciousness if it needs to. + M.regenerate_icons() + M.failed_last_breath = 0 //So mobs that died of oxyloss don't revive and have perpetual out of breath. + M.reload_fullscreen() + + M.emote("gasp") + M.Weaken(rand(10,25)) + M.updatehealth() + apply_brain_damage(M, deadtime) + +/obj/item/weapon/shockpaddles/proc/apply_brain_damage(mob/living/carbon/human/H, var/deadtime) + if(deadtime < DEFIB_TIME_LOSS) return + + if(!H.should_have_organ(BP_BRAIN)) return //no brain + + var/obj/item/organ/internal/brain/brain = H.internal_organs_by_name[BP_BRAIN] + if(!brain) return //no brain + + var/brain_damage = Clamp((deadtime - DEFIB_TIME_LOSS)/(DEFIB_TIME_LIMIT - DEFIB_TIME_LOSS)*brain.max_damage, H.getBrainLoss(), brain.max_damage) + H.setBrainLoss(brain_damage) + +/obj/item/weapon/shockpaddles/proc/make_announcement(var/message, var/msg_class) + audible_message("\The [src] [message]", "\The [src] vibrates slightly.") + +/obj/item/weapon/shockpaddles/emag_act(mob/user) + if(safety) + safety = 0 + to_chat(user, "You silently disable \the [src]'s safety protocols with the cryptographic sequencer.") + burn_damage_amt *= 3 + update_icon() + return 1 + else + safety = 1 + to_chat(user, "You silently enable \the [src]'s safety protocols with the cryptographic sequencer.") + burn_damage_amt = initial(burn_damage_amt) + update_icon() + return 1 + +/obj/item/weapon/shockpaddles/emp_act(severity) + var/new_safety = rand(0, 1) + if(safety != new_safety) + safety = new_safety + if(safety) + make_announcement("beeps, \"Safety protocols enabled!\"", "notice") + playsound(get_turf(src), 'sound/machines/defib_safetyon.ogg', 50, 0) + else + make_announcement("beeps, \"Safety protocols disabled!\"", "warning") + playsound(get_turf(src), 'sound/machines/defib_safetyoff.ogg', 50, 0) + update_icon() + ..() + +/obj/item/weapon/shockpaddles/robot + name = "defibrillator paddles" + desc = "A pair of advanced shockpaddles powered by a robot's internal power cell, able to penetrate thick clothing." + chargecost = 50 + combat = 1 + icon_state = "defibpaddles0" + item_state = "defibpaddles0" + cooldowntime = (3 SECONDS) + +/obj/item/weapon/shockpaddles/robot/check_charge(var/charge_amt) + if(isrobot(src.loc)) + var/mob/living/silicon/robot/R = src.loc + return (R.cell && R.cell.check_charge(charge_amt)) + +/obj/item/weapon/shockpaddles/robot/checked_use(var/charge_amt) + if(isrobot(src.loc)) + var/mob/living/silicon/robot/R = src.loc + return (R.cell && R.cell.checked_use(charge_amt)) + +/* + Shockpaddles that are linked to a base unit +*/ +/obj/item/weapon/shockpaddles/linked + var/obj/item/weapon/defibrillator/base_unit + +/obj/item/weapon/shockpaddles/linked/New(newloc, obj/item/weapon/defibrillator/defib) + base_unit = defib + ..(newloc) + +/obj/item/weapon/shockpaddles/linked/Destroy() + if(base_unit) + //ensure the base unit's icon updates + if(base_unit.paddles == src) + base_unit.paddles = null + base_unit.update_icon() + base_unit = null + return ..() + +/obj/item/weapon/shockpaddles/linked/dropped(mob/user) + ..() //update twohanding + if(base_unit) + base_unit.reattach_paddles(user) //paddles attached to a base unit should never exist outside of their base unit or the mob equipping the base unit + +/obj/item/weapon/shockpaddles/linked/check_charge(var/charge_amt) + return (base_unit.bcell && base_unit.bcell.check_charge(charge_amt)) + +/obj/item/weapon/shockpaddles/linked/checked_use(var/charge_amt) + return (base_unit.bcell && base_unit.bcell.checked_use(charge_amt)) + +/obj/item/weapon/shockpaddles/linked/make_announcement(var/message, var/msg_class) + base_unit.audible_message("\The [base_unit] [message]", "\The [base_unit] vibrates slightly.") + +/* + Standalone Shockpaddles +*/ + +/obj/item/weapon/shockpaddles/standalone + desc = "A pair of shockpaddles powered by an experimental miniaturized reactor" //Inspired by the advanced e-gun + var/fail_counter = 0 + +/obj/item/weapon/shockpaddles/standalone/Destroy() + . = ..() + if(fail_counter) + STOP_PROCESSING(SSobj, src) + +/obj/item/weapon/shockpaddles/standalone/check_charge(var/charge_amt) + return 1 + +/obj/item/weapon/shockpaddles/standalone/checked_use(var/charge_amt) + radiation_repository.radiate(src, charge_amt/12) //just a little bit of radiation. It's the price you pay for being powered by magic I guess + return 1 + +/obj/item/weapon/shockpaddles/standalone/Process() + if(fail_counter > 0) + radiation_repository.radiate(src, fail_counter--) + else + STOP_PROCESSING(SSobj, src) + +/obj/item/weapon/shockpaddles/standalone/emp_act(severity) + ..() + var/new_fail = 0 + switch(severity) + if(1) + new_fail = max(fail_counter, 20) + visible_message("\The [src]'s reactor overloads!") + if(2) + new_fail = max(fail_counter, 8) + if(ismob(loc)) + to_chat(loc, "\The [src] feel pleasantly warm.") + + if(new_fail && !fail_counter) + START_PROCESSING(SSobj, src) + fail_counter = new_fail + +/obj/item/weapon/shockpaddles/standalone/traitor + name = "defibrillator paddles" + desc = "A pair of unusual looking paddles powered by an experimental miniaturized reactor. It possesses both the ability to penetrate armor and to deliver powerful shocks." + icon = 'icons/obj/weapons.dmi' + icon_state = "defibpaddles0" + item_state = "defibpaddles0" + combat = 1 + safety = 0 + chargetime = (1 SECONDS) + burn_damage_amt = 15 + +#undef DEFIB_TIME_LIMIT +#undef DEFIB_TIME_LOSS diff --git a/code/game/objects/items/weapons/dice.dm b/code/game/objects/items/weapons/dice.dm new file mode 100644 index 00000000..a43c05ac --- /dev/null +++ b/code/game/objects/items/weapons/dice.dm @@ -0,0 +1,77 @@ +/obj/item/weapon/dice + name = "d6" + desc = "A dice with six sides." + icon = 'icons/obj/dice.dmi' + icon_state = "d66" + w_class = ITEM_SIZE_TINY + var/sides = 6 + attack_verb = list("diced") + +/obj/item/weapon/dice/New() + icon_state = "[name][rand(1,sides)]" + +/obj/item/weapon/dice/d4 + name = "d4" + desc = "A dice with four sides." + icon_state = "d44" + sides = 4 + +/obj/item/weapon/dice/d8 + name = "d8" + desc = "A dice with eight sides." + icon_state = "d88" + sides = 8 + +/obj/item/weapon/dice/d10 + name = "d10" + desc = "A dice with ten sides." + icon_state = "d1010" + sides = 10 + +/obj/item/weapon/dice/d12 + name = "d12" + desc = "A dice with twelve sides." + icon_state = "d1212" + sides = 12 + +/obj/item/weapon/dice/d20 + name = "d20" + desc = "A dice with twenty sides." + icon_state = "d2020" + sides = 20 + +/obj/item/weapon/dice/d100 + name = "d100" + desc = "A dice with ten sides. This one is for the tens digit." + icon_state = "d10010" + sides = 10 + +/obj/item/weapon/dice/proc/roll_die() + var/result = rand(1, sides) + return list(result, "") + +/obj/item/weapon/dice/d20/roll_die() + var/result = rand(1, sides) + var/comment = "" + if(result == 20) + comment = "Nat 20!" + else if(result == 1) + comment = "Ouch, bad luck." + return list(result, comment) + +/obj/item/weapon/dice/attack_self(mob/user as mob) + var/list/roll_result = roll_die() + var/result = roll_result[1] + var/comment = roll_result[2] + icon_state = "[name][result]" + user.visible_message("[user] has thrown [src]. It lands on [result]. [comment]", \ + "You throw [src]. It lands on a [result]. [comment]", \ + "You hear [src] landing on a [result]. [comment]") + +/obj/item/weapon/dice/throw_impact(atom/hit_atom, var/speed) + ..() + var/list/roll_result = roll_die() + var/result = roll_result[1] + var/comment = roll_result[2] + icon_state = "[name][result]" + src.visible_message("\The [src] lands on [result]. [comment]") \ No newline at end of file diff --git a/code/game/objects/items/weapons/ecigs.dm b/code/game/objects/items/weapons/ecigs.dm new file mode 100644 index 00000000..2fd0b3fb --- /dev/null +++ b/code/game/objects/items/weapons/ecigs.dm @@ -0,0 +1,300 @@ +/obj/item/clothing/mask/smokable/ecig + name = "electronic cigarette" + desc = "Device with modern approach to smoking." + icon = 'icons/obj/ecig.dmi' + var/active = 0 + var/obj/item/weapon/cell/cigcell + var/cartridge_type = /obj/item/weapon/reagent_containers/ecig_cartridge/med_nicotine + var/obj/item/weapon/reagent_containers/ecig_cartridge/ec_cartridge + var/cell_type = /obj/item/weapon/cell/device/standard + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS | SLOT_MASK + attack_verb = list("attacked", "poked", "battered") + body_parts_covered = 0 + var/brightness_on = 1 + chem_volume = 0 //ecig has no storage on its own but has reagent container created by parent obj + item_state = "ecigoff" + var/icon_off + var/icon_empty + var/power_usage = 450 //value for simple ecig, enough for about 1 cartridge, in JOULES! + var/ecig_colors = list(null, COLOR_DARK_GRAY, COLOR_RED_GRAY, COLOR_BLUE_GRAY, COLOR_GREEN_GRAY, COLOR_PURPLE_GRAY) + var/idle = 0 + var/idle_treshold = 30 + +/obj/item/clothing/mask/smokable/ecig/New() + ..() + if(ispath(cell_type)) + cigcell = new cell_type + ec_cartridge = new cartridge_type(src) + +/obj/item/clothing/mask/smokable/ecig/simple + name = "cheap electronic cigarette" + desc = "A cheap Lucky 1337 electronic cigarette, styled like a traditional cigarette." + icon_state = "ccigoff" + icon_off = "ccigoff" + icon_empty = "ccigoff" + icon_on = "ccigon" + +/obj/item/clothing/mask/smokable/ecig/simple/examine(mob/user) + ..() + if(src.ec_cartridge) + to_chat(user,"There is roughly [round(ec_cartridge.reagents.total_volume / ec_cartridge.volume, 25)]% of liquid remaining.") + else + to_chat(user,"There is no cartridge connected.") + +/obj/item/clothing/mask/smokable/ecig/util + name = "electronic cigarette" + desc = "A popular utilitarian model electronic cigarette, the ONI-55. Comes in a variety of colors." + icon_state = "ecigoff1" + icon_off = "ecigoff1" + icon_empty = "ecigoff1" + icon_on = "ecigon" + cell_type = /obj/item/weapon/cell/device/high //enough for four cartridges + +/obj/item/clothing/mask/smokable/ecig/util/New() + ..() + color = pick(ecig_colors) + +obj/item/clothing/mask/smokable/ecig/util/examine(mob/user) + ..() + if(src.ec_cartridge) + to_chat(user,"There are [round(ec_cartridge.reagents.total_volume, 1)] units of liquid remaining.") + else + to_chat(user,"There is no cartridge connected.") + to_chat(user,"Gauge shows about [round(cigcell.percent(), 25)]% energy remaining") + +/obj/item/clothing/mask/smokable/ecig/deluxe + name = "deluxe electronic cigarette" + desc = "A premium model eGavana MK3 electronic cigarette, shaped like a cigar." + icon_state = "pcigoff1" + icon_off = "pcigoff1" + icon_empty = "pcigoff2" + icon_on = "pcigon" + cell_type = /obj/item/weapon/cell/device/high //enough for four catridges + +obj/item/clothing/mask/smokable/ecig/deluxe/examine(mob/user) + ..() + if(src.ec_cartridge) + to_chat(user,"There are [round(ec_cartridge.reagents.total_volume, 1)] units of liquid remaining.") + else + to_chat(user,"There is no cartridge connected.") + to_chat(user,"Gauge shows [round(cigcell.percent(), 1)]% energy remaining") + +/obj/item/clothing/mask/smokable/ecig/Process() + if(idle >= idle_treshold) //idle too long -> automatic shut down + idle = 0 + src.visible_message("\The [src] powered down automatically.", null, 2) + active=0//autodisable the cigarette + STOP_PROCESSING(SSobj, src) + update_icon() + return + + idle ++ + + if(ishuman(loc)) + var/mob/living/carbon/human/C = loc + + if (!active || !ec_cartridge || !ec_cartridge.reagents.total_volume)//no cartridge + if(!ec_cartridge.reagents.total_volume) + to_chat(C, "There is no liquid left in \the [src], so you shut it down.") + active=0//autodisable the cigarette + STOP_PROCESSING(SSobj, src) + update_icon() + return + + if (src == C.wear_mask && C.check_has_mouth()) //transfer, but only when not disabled + idle = 0 + //here we'll reduce battery by usage, and check powerlevel - you only use batery while smoking + if(!cigcell.checked_use(power_usage * CELLRATE)) //if this passes, there's not enough power in the battery + active = 0 + STOP_PROCESSING(SSobj, src) + update_icon() + to_chat(C,"Battery in \the [src] ran out and it powered down.") + return + ec_cartridge.reagents.trans_to_mob(C, REM, CHEM_INGEST, 0.4) // Most of it is not inhaled... balance reasons. + +/obj/item/clothing/mask/smokable/ecig/update_icon() + if (active) + item_state = icon_on + icon_state = icon_on + set_light(brightness_on) + else if (ec_cartridge) + set_light(0) + item_state = icon_off + icon_state = icon_off + else + icon_state = icon_empty + item_state = icon_empty + set_light(0) + if(ismob(loc)) + var/mob/living/M = loc + M.update_inv_wear_mask(0) + M.update_inv_l_hand(0) + M.update_inv_r_hand(1) + + +/obj/item/clothing/mask/smokable/ecig/attackby(var/obj/item/I, var/mob/user as mob) + if(istype(I, /obj/item/weapon/reagent_containers/ecig_cartridge)) + if (ec_cartridge)//can't add second one + to_chat(user, "A cartridge has already been installed. ") + else//fits in new one + user.remove_from_mob(I) + I.forceMove(src)//I.loc=src + ec_cartridge = I + update_icon() + to_chat(user, "You insert [I] into [src]. ") + + if(istype(I, /obj/item/weapon/screwdriver)) + if(cigcell) //if contains powercell + cigcell.update_icon() + cigcell.dropInto(loc) + cigcell = null + to_chat(user, "You remove the cell from \the [src].") + else //does not contains cell + to_chat(user, "There is no powercell in \the [src].") + + if(istype(I, /obj/item/weapon/cell/device)) + if(!cigcell && user.unEquip(I)) + I.forceMove(src) + cigcell = I + to_chat(user, "You install a powercell into the [src].") + update_icon() + else + to_chat(user, "[src] already has a powercell.") + + +/obj/item/clothing/mask/smokable/ecig/attack_self(mob/user as mob) + if (active) + active=0 + STOP_PROCESSING(SSobj, src) + to_chat(user, "You turn off \the [src]. ") + update_icon() + else + if(cigcell) + if (!ec_cartridge) + to_chat(user, "You can't use \the [src] with no cartridge installed! ") + return + else if(!ec_cartridge.reagents.total_volume) + to_chat(user, "You can't use \the [src] with no liquid left! ") + return + else if(!cigcell.check_charge(power_usage * CELLRATE)) + to_chat(user, "Battery of \the [src] is too depleted to use. ") + return + active=1 + START_PROCESSING(SSobj, src) + to_chat(user, "You turn on \the [src]. ") + update_icon() + + else + to_chat(user, "\The [src] does not have a powercell installed.") + +/obj/item/clothing/mask/smokable/ecig/attack_hand(mob/user as mob)//eject cartridge + if(user.get_inactive_hand() == src)//if being hold + if (ec_cartridge) + active=0 + user.put_in_hands(ec_cartridge) + to_chat(user, "You eject \the [ec_cartridge] from \the [src]. ") + ec_cartridge = null + update_icon() + else + ..() + +/obj/item/weapon/reagent_containers/ecig_cartridge + name = "tobacco flavour cartridge" + desc = "A small metal cartridge, used with electronic cigarettes, which contains an atomizing coil and a solution to be atomized." + w_class = ITEM_SIZE_TINY + icon = 'icons/obj/ecig.dmi' + icon_state = "ecartridge" + matter = list("metal" = 50, "glass" = 10) + volume = 20 + atom_flags = ATOM_FLAG_OPEN_CONTAINER + +/obj/item/weapon/reagent_containers/ecig_cartridge/New() + create_reagents(volume) + +/obj/item/weapon/reagent_containers/ecig_cartridge/examine(mob/user as mob)//to see how much left + ..() + to_chat(user, "The cartridge has [reagents.total_volume] units of liquid remaining.") + +//flavours +/obj/item/weapon/reagent_containers/ecig_cartridge/blank + name = "ecigarette cartridge" + desc = "A small metal cartridge which contains an atomizing coil." + +/obj/item/weapon/reagent_containers/ecig_cartridge/blanknico + name = "flavorless nicotine cartridge" + desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says you can add whatever flavoring agents you want." +/obj/item/weapon/reagent_containers/ecig_cartridge/blanknico/New() + ..() + reagents.add_reagent(/datum/reagent/tobacco/liquid, 5) + reagents.add_reagent(/datum/reagent/water, 10) + +/obj/item/weapon/reagent_containers/ecig_cartridge/med_nicotine + name = "tobacco flavour cartridge" + desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its tobacco flavored." +/obj/item/weapon/reagent_containers/ecig_cartridge/med_nicotine/New() + ..() + reagents.add_reagent(/datum/reagent/tobacco, 5) + reagents.add_reagent(/datum/reagent/water, 15) + +/obj/item/weapon/reagent_containers/ecig_cartridge/high_nicotine + name = "high nicotine tobacco flavour cartridge" + desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its tobacco flavored, with extra nicotine." +/obj/item/weapon/reagent_containers/ecig_cartridge/high_nicotine/New() + ..() + reagents.add_reagent(/datum/reagent/tobacco, 10) + reagents.add_reagent(/datum/reagent/water, 10) + +/obj/item/weapon/reagent_containers/ecig_cartridge/orange + name = "orange flavour cartridge" + desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its orange flavored." +/obj/item/weapon/reagent_containers/ecig_cartridge/orange/New() + ..() + reagents.add_reagent(/datum/reagent/tobacco/liquid, 5) + reagents.add_reagent(/datum/reagent/water, 10) + reagents.add_reagent(/datum/reagent/drink/juice/orange, 5) + +/obj/item/weapon/reagent_containers/ecig_cartridge/mint + name = "mint flavour cartridge" + desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its mint flavored." +/obj/item/weapon/reagent_containers/ecig_cartridge/mint/New() + ..() + reagents.add_reagent(/datum/reagent/tobacco/liquid, 5) + reagents.add_reagent(/datum/reagent/water, 10) + reagents.add_reagent(/datum/reagent/menthol, 5) + +/obj/item/weapon/reagent_containers/ecig_cartridge/watermelon + name = "watermelon flavour cartridge" + desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its watermelon flavored." +/obj/item/weapon/reagent_containers/ecig_cartridge/watermelon/New() + ..() + reagents.add_reagent(/datum/reagent/tobacco/liquid, 5) + reagents.add_reagent(/datum/reagent/water, 10) + reagents.add_reagent(/datum/reagent/drink/juice/watermelon, 5) + +/obj/item/weapon/reagent_containers/ecig_cartridge/grape + name = "grape flavour cartridge" + desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its grape flavored." +/obj/item/weapon/reagent_containers/ecig_cartridge/grape/New() + ..() + reagents.add_reagent(/datum/reagent/tobacco/liquid, 5) + reagents.add_reagent(/datum/reagent/water, 10) + reagents.add_reagent(/datum/reagent/drink/juice/grape, 5) + +/obj/item/weapon/reagent_containers/ecig_cartridge/lemonlime + name = "lemon-lime flavour cartridge" + desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its lemon-lime flavored." +/obj/item/weapon/reagent_containers/ecig_cartridge/lemonlime/New() + ..() + reagents.add_reagent(/datum/reagent/tobacco/liquid, 5) + reagents.add_reagent(/datum/reagent/water, 10) + reagents.add_reagent(/datum/reagent/drink/lemon_lime, 5) + +/obj/item/weapon/reagent_containers/ecig_cartridge/coffee + name = "coffee flavour cartridge" + desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its coffee flavored." +/obj/item/weapon/reagent_containers/ecig_cartridge/coffee/New() + ..() + reagents.add_reagent(/datum/reagent/tobacco/liquid, 5) + reagents.add_reagent(/datum/reagent/water, 10) + reagents.add_reagent(/datum/reagent/drink/coffee, 5) \ No newline at end of file diff --git a/code/game/objects/items/weapons/explosives.dm b/code/game/objects/items/weapons/explosives.dm new file mode 100644 index 00000000..47be7b22 --- /dev/null +++ b/code/game/objects/items/weapons/explosives.dm @@ -0,0 +1,90 @@ +/obj/item/weapon/plastique + name = "plastic explosives" + desc = "Used to put holes in specific areas without too much extra hole." + gender = PLURAL + icon = 'icons/obj/assemblies.dmi' + icon_state = "plastic-explosive0" + item_state = "plasticx" + item_flags = ITEM_FLAG_NO_BLUDGEON + w_class = ITEM_SIZE_SMALL + origin_tech = list(TECH_ILLEGAL = 2) + var/datum/wires/explosive/c4/wires = null + var/timer = 10 + var/atom/target = null + var/open_panel = 0 + var/image_overlay = null + +/obj/item/weapon/plastique/New() + wires = new(src) + image_overlay = image('icons/obj/assemblies.dmi', "plastic-explosive2") + ..() + +/obj/item/weapon/plastique/Destroy() + qdel(wires) + wires = null + return ..() + +/obj/item/weapon/plastique/attackby(var/obj/item/I, var/mob/user) + if(isScrewdriver(I)) + open_panel = !open_panel + to_chat(user, "You [open_panel ? "open" : "close"] the wire panel.") + else if(isWirecutter(I) || isMultitool(I) || istype(I, /obj/item/device/assembly/signaler )) + wires.Interact(user) + else + ..() + +/obj/item/weapon/plastique/attack_self(mob/user as mob) + var/newtime = input(usr, "Please set the timer.", "Timer", 10) as num + if(user.get_active_hand() == src) + newtime = Clamp(newtime, 10, 60000) + timer = newtime + to_chat(user, "Timer set for [timer] seconds.") + +/obj/item/weapon/plastique/afterattack(atom/movable/target, mob/user, flag) + if (!flag) + return + if(!istype(target, /obj/machinery/door) && !iswall(target)) + return + to_chat(user, "Planting explosives...") + user.do_attack_animation(target) + + if(do_after(user, 50, target) && in_range(user, target)) + user.drop_item() + src.target = target + forceMove(null) + + if (ismob(target)) + admin_attack_log(user, target, "Planted \a [src] with a [timer] second fuse.", "Had \a [src] with a [timer] second fuse planted on them.", "planted \a [src] with a [timer] second fuse on") + user.visible_message("[user.name] finished planting an explosive on [target.name]!") + log_game("[key_name(user)] planted [src.name] on [key_name(target)] with [timer] second fuse") + + else + log_and_message_admins("planted \a [src] with a [timer] second fuse on \the [target].") + + target.overlays += image_overlay + to_chat(user, "Bomb has been planted. Timer counting down from [timer].") + spawn(timer*10) + explode(get_turf(target)) + +/obj/item/weapon/plastique/proc/explode(var/location) + if(!target) + target = get_atom_on_turf(src) + if(!target) + target = src + if(location) + explosion(location, -1, -1, 2, 3) + + if(target) + if (istype(target, /turf/simulated/wall)) + var/turf/simulated/wall/W = target + W.dismantle_wall(1) + else if(istype(target, /mob/living)) + target.ex_act(2) // c4 can't gib mobs anymore. + else + target.ex_act(1) + if(target) + target.overlays -= image_overlay + qdel(src) + +/obj/item/weapon/plastique/attack(mob/M as mob, mob/user as mob, def_zone) + return diff --git a/code/game/objects/items/weapons/extinguisher.dm b/code/game/objects/items/weapons/extinguisher.dm new file mode 100644 index 00000000..61c14e76 --- /dev/null +++ b/code/game/objects/items/weapons/extinguisher.dm @@ -0,0 +1,135 @@ +/obj/item/weapon/extinguisher + name = "fire extinguisher" + desc = "A traditional red fire extinguisher." + icon = 'icons/obj/items.dmi' + icon_state = "fire_extinguisher0" + item_state = "fire_extinguisher" + hitsound = 'sound/weapons/smash.ogg' + obj_flags = OBJ_FLAG_CONDUCTIBLE + throwforce = 10 + w_class = ITEM_SIZE_NORMAL + throw_speed = 2 + throw_range = 10 + force = 10.0 + matter = list(DEFAULT_WALL_MATERIAL = 90) + attack_verb = list("slammed", "whacked", "bashed", "thunked", "battered", "bludgeoned", "thrashed") + + var/spray_particles = 3 + var/spray_amount = 120 //units of liquid per spray - 120 -> same as splashing them with a bucket per spray + var/max_water = 2000 + var/last_use = 1.0 + var/safety = 1 + var/sprite_name = "fire_extinguisher" + +/obj/item/weapon/extinguisher/mini + name = "fire extinguisher" + desc = "A light and compact fibreglass-framed model fire extinguisher." + icon_state = "miniFE0" + item_state = "miniFE" + hitsound = null //it is much lighter, after all. + throwforce = 2 + w_class = ITEM_SIZE_SMALL + force = 3.0 + spray_amount = 80 + max_water = 1000 + sprite_name = "miniFE" + +/obj/item/weapon/extinguisher/New() + create_reagents(max_water) + reagents.add_reagent(/datum/reagent/water, max_water) + ..() + +/obj/item/weapon/extinguisher/examine(mob/user) + if(..(user, 0)) + to_chat(user, text("\icon[] [] contains [] units of water left!", src, src.name, src.reagents.total_volume)) + return + +/obj/item/weapon/extinguisher/attack_self(mob/user as mob) + safety = !safety + src.icon_state = "[sprite_name][!safety]" + src.desc = "The safety is [safety ? "on" : "off"]." + to_chat(user, "The safety is [safety ? "on" : "off"].") + return + +/obj/item/weapon/extinguisher/attack(var/mob/living/M, var/mob/user) + if(user.a_intent == I_HELP) + if(src.safety || (world.time < src.last_use + 20)) // We still catch help intent to not randomly attack people + return + if(src.reagents.total_volume < 1) + to_chat(user, "\The [src] is empty.") + return + + src.last_use = world.time + reagents.splash(M, min(reagents.total_volume, spray_amount)) + + user.visible_message("\The [user] sprays \the [M] with \the [src].") + playsound(src.loc, 'sound/effects/extinguish.ogg', 75, 1, -3) + + return 1 // No afterattack + return ..() + +/obj/item/weapon/extinguisher/proc/propel_object(var/obj/O, mob/user, movementdirection) + if(O.anchored) return + + var/obj/structure/bed/chair/C + if(istype(O, /obj/structure/bed/chair)) + C = O + + var/list/move_speed = list(1, 1, 1, 2, 2, 3) + for(var/i in 1 to 6) + if(C) C.propelled = (6-i) + O.Move(get_step(user,movementdirection), movementdirection) + sleep(move_speed[i]) + + //additional movement + for(var/i in 1 to 3) + O.Move(get_step(user,movementdirection), movementdirection) + sleep(3) + +/obj/item/weapon/extinguisher/afterattack(var/atom/target, var/mob/user, var/flag) + //TODO; Add support for reagents in water. + + if( istype(target, /obj/structure/reagent_dispensers/watertank) && flag) + var/obj/o = target + var/amount = o.reagents.trans_to_obj(src, 500) + to_chat(user, "You fill [src] with [amount] units of the contents of [target].") + playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) + return + + if (!safety) + if (src.reagents.total_volume < 1) + to_chat(usr, "\The [src] is empty.") + return + + if (world.time < src.last_use + 20) + return + + src.last_use = world.time + + playsound(src.loc, 'sound/effects/extinguish.ogg', 75, 1, -3) + + var/direction = get_dir(src,target) + + if(user.buckled && isobj(user.buckled)) + spawn(0) + propel_object(user.buckled, user, turn(direction,180)) + + var/turf/T = get_turf(target) + + var/per_particle = min(spray_amount, reagents.total_volume)/spray_particles + for(var/a = 1 to spray_particles) + spawn(0) + if(!src || !reagents.total_volume) return + + var/obj/effect/effect/water/W = new /obj/effect/effect/water(get_turf(src)) + W.create_reagents(per_particle) + reagents.trans_to_obj(W, per_particle) + W.set_color() + W.set_up(T) + + if((istype(usr.loc, /turf/space)) || (usr.lastarea.has_gravity == 0)) + user.inertia_dir = get_dir(target, user) + step(user, user.inertia_dir) + else + return ..() + return diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm new file mode 100644 index 00000000..7e850c51 --- /dev/null +++ b/code/game/objects/items/weapons/flamethrower.dm @@ -0,0 +1,210 @@ +/obj/item/weapon/flamethrower + name = "flamethrower" + desc = "You are a firestarter!" + icon = 'icons/obj/flamethrower.dmi' + icon_state = "flamethrowerbase" + item_state = "flamethrower_0" + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 3.0 + throwforce = 10.0 + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_LARGE + origin_tech = list(TECH_COMBAT = 1) + matter = list(DEFAULT_WALL_MATERIAL = 500) + var/status = 0 + var/throw_amount = 100 + var/lit = 0 //on or off + var/operating = 0//cooldown + var/turf/previousturf = null + var/obj/item/weapon/weldingtool/weldtool = null + var/obj/item/device/assembly/igniter/igniter = null + var/obj/item/weapon/tank/hydrogen/ptank = null + + +/obj/item/weapon/flamethrower/Destroy() + QDEL_NULL(weldtool) + QDEL_NULL(igniter) + QDEL_NULL(ptank) + . = ..() + +/obj/item/weapon/flamethrower/Process() + if(!lit) + STOP_PROCESSING(SSobj, src) + return null + var/turf/location = loc + if(istype(location, /mob/)) + var/mob/M = location + if(M.l_hand == src || M.r_hand == src) + location = M.loc + if(isturf(location)) //start a fire if possible + location.hotspot_expose(700, 2) + return + + +/obj/item/weapon/flamethrower/update_icon() + overlays.Cut() + if(igniter) + overlays += "+igniter[status]" + if(ptank) + overlays += "+ptank" + if(lit) + overlays += "+lit" + item_state = "flamethrower_1" + else + item_state = "flamethrower_0" + return + +/obj/item/weapon/flamethrower/afterattack(atom/target, mob/user, proximity) + // Make sure our user is still holding us + if(user && user.get_active_hand() == src) + if(user.a_intent == I_HELP) //don't shoot if we're on help intent + to_chat(user, "You refrain from firing \the [src] as your intent is set to help.") + return + var/turf/target_turf = get_turf(target) + if(target_turf) + var/turflist = getline(user, target_turf) + flame_turf(turflist) + +/obj/item/weapon/flamethrower/attackby(obj/item/W as obj, mob/user as mob) + if(user.stat || user.restrained() || user.lying) return + if(isWrench(W) && !status)//Taking this apart + var/turf/T = get_turf(src) + if(weldtool) + weldtool.loc = T + weldtool = null + if(igniter) + igniter.loc = T + igniter = null + if(ptank) + ptank.loc = T + ptank = null + new /obj/item/stack/rods(T) + qdel(src) + return + + if(isScrewdriver(W) && igniter && !lit) + status = !status + to_chat(user, "[igniter] is now [status ? "secured" : "unsecured"]!") + update_icon() + return + + if(isigniter(W)) + var/obj/item/device/assembly/igniter/I = W + if(I.secured) return + if(igniter) return + user.drop_item() + I.loc = src + igniter = I + update_icon() + return + + if(istype(W,/obj/item/weapon/tank/hydrogen)) + if(ptank) + to_chat(user, "There appears to already be a hydrogen tank loaded in [src]!") + return + user.drop_item() + ptank = W + W.loc = src + update_icon() + return + + if(istype(W, /obj/item/device/analyzer)) + var/obj/item/device/analyzer/A = W + A.analyze_gases(src, user) + return + ..() + return + + +/obj/item/weapon/flamethrower/attack_self(mob/user as mob) + if(user.stat || user.restrained() || user.lying) return + user.set_machine(src) + if(!ptank) + to_chat(user, "Attach a hydrogen tank first!") + return + var/dat = text("Flamethrower ([lit ? "Lit" : "Unlit"])
            \n Tank Pressure: [ptank.air_contents.return_pressure()]
            \nAmount to throw: - - - [throw_amount] + + +
            \nRemove hydrogen tank - Close
            ") + user << browse(dat, "window=flamethrower;size=600x300") + onclose(user, "flamethrower") + return + +/obj/item/weapon/flamethrower/return_air() + if(ptank) + return ptank.return_air() + +/obj/item/weapon/flamethrower/Topic(href,href_list[]) + if(href_list["close"]) + usr.unset_machine() + usr << browse(null, "window=flamethrower") + return + if(usr.stat || usr.restrained() || usr.lying) return + usr.set_machine(src) + if(href_list["light"]) + if(!ptank) return + if(ptank.air_contents.gas["hydrogen"] < 1) return + if(!status) return + lit = !lit + if(lit) + START_PROCESSING(SSobj, src) + if(href_list["amount"]) + throw_amount = throw_amount + text2num(href_list["amount"]) + throw_amount = max(50, min(5000, throw_amount)) + if(href_list["remove"]) + if(!ptank) return + usr.put_in_hands(ptank) + ptank = null + lit = 0 + usr.unset_machine() + usr << browse(null, "window=flamethrower") + for(var/mob/M in viewers(1, loc)) + if((M.client && M.machine == src)) + attack_self(M) + update_icon() + return + + +//Called from turf.dm turf/dblclick +/obj/item/weapon/flamethrower/proc/flame_turf(turflist) + if(!lit || operating) return + operating = 1 + for(var/turf/T in turflist) + if(T.density || istype(T, /turf/space)) + break + if(!previousturf && length(turflist)>1) + previousturf = get_turf(src) + continue //so we don't burn the tile we be standin on + if(previousturf && LinkBlocked(previousturf, T)) + break + ignite_turf(T) + sleep(1) + previousturf = null + operating = 0 + for(var/mob/M in viewers(1, loc)) + if((M.client && M.machine == src)) + attack_self(M) + return + + +/obj/item/weapon/flamethrower/proc/ignite_turf(turf/target) + //TODO: DEFERRED Consider checking to make sure tank pressure is high enough before doing this... + //Transfer 5% of current tank air contents to turf + var/datum/gas_mixture/air_transfer = ptank.air_contents.remove_ratio(0.02*(throw_amount/100)) + //air_transfer.toxins = air_transfer.toxins * 5 // This is me not comprehending the air system. I realize this is retarded and I could probably make it work without fucking it up like this, but there you have it. -- TLE + new/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel(target,air_transfer.gas["hydrogen"],get_dir(loc,target)) + air_transfer.gas["hydrogen"] = 0 + target.assume_air(air_transfer) + //Burn it based on transfered gas + //target.hotspot_expose(part4.air_contents.temperature*2,300) + target.hotspot_expose((ptank.air_contents.temperature*2) + 380,500) // -- More of my "how do I shot fire?" dickery. -- TLE + //location.hotspot_expose(1000,500,1) + return + +/obj/item/weapon/flamethrower/full/New(var/loc) + ..() + weldtool = new /obj/item/weapon/weldingtool(src) + weldtool.status = 0 + igniter = new /obj/item/device/assembly/igniter(src) + igniter.secured = 0 + status = 1 + update_icon() + return diff --git a/code/game/objects/items/weapons/gift_wrappaper.dm b/code/game/objects/items/weapons/gift_wrappaper.dm new file mode 100644 index 00000000..9458ecd4 --- /dev/null +++ b/code/game/objects/items/weapons/gift_wrappaper.dm @@ -0,0 +1,210 @@ +/* Gifts and wrapping paper + * Contains: + * Gifts + * Wrapping Paper + */ + +/* + * Gifts + */ +/obj/item/weapon/a_gift + name = "gift" + desc = "PRESENTS!!!! eek!" + icon = 'icons/obj/items.dmi' + icon_state = "gift1" + item_state = "gift1" + randpixel = 10 + +/obj/item/weapon/a_gift/New() + ..() + if(w_class > 0 && w_class < ITEM_SIZE_HUGE) + icon_state = "gift[w_class]" + else + icon_state = "gift[pick(1, 2, 3)]" + return + +/obj/item/weapon/a_gift/ex_act() + qdel(src) + return + +/obj/effect/spresent/relaymove(mob/user as mob) + if (user.stat) + return + to_chat(user, "You can't move.") + +/obj/effect/spresent/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + + if(!isWirecutter(W)) + to_chat(user, "I need wirecutters for that.") + return + + to_chat(user, "You cut open the present.") + + for(var/mob/M in src) //Should only be one but whatever. + M.dropInto(loc) + if (M.client) + M.client.eye = M.client.mob + M.client.perspective = MOB_PERSPECTIVE + + qdel(src) + +/obj/item/weapon/a_gift/attack_self(mob/M as mob) + var/gift_type = pick( + /obj/item/weapon/storage/wallet, + /obj/item/weapon/storage/photo_album, + /obj/item/weapon/storage/box/snappops, + /obj/item/weapon/storage/fancy/crayons, + /obj/item/weapon/storage/backpack/holding, + /obj/item/weapon/storage/belt/champion, + /obj/item/weapon/soap/deluxe, + /obj/item/weapon/pickaxe/silver, + /obj/item/weapon/pen/invisible, + /obj/item/weapon/lipstick/random, + /obj/item/weapon/grenade/smokebomb, + /obj/item/weapon/corncob, + /obj/item/weapon/contraband/poster, + /obj/item/weapon/book/manual/barman_recipes, + /obj/item/weapon/book/manual/chef_recipes, + /obj/item/weapon/bikehorn, + /obj/item/weapon/beach_ball, + /obj/item/weapon/beach_ball/holoball, + /obj/item/toy/water_balloon, + /obj/item/toy/blink, + /obj/item/toy/crossbow, + /obj/item/weapon/gun/projectile/revolver/capgun, + /obj/item/toy/katana, + /obj/item/toy/prize/deathripley, + /obj/item/toy/prize/durand, + /obj/item/toy/prize/fireripley, + /obj/item/toy/prize/gygax, + /obj/item/toy/prize/honk, + /obj/item/toy/prize/marauder, + /obj/item/toy/prize/mauler, + /obj/item/toy/prize/odysseus, + /obj/item/toy/prize/phazon, + /obj/item/toy/prize/ripley, + /obj/item/toy/prize/seraph, + /obj/item/toy/spinningtoy, + /obj/item/toy/sword, + /obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiadeus, + /obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiavulgaris, + /obj/item/device/paicard, + /obj/item/device/violin, + /obj/item/weapon/storage/belt/utility/full, + /obj/item/clothing/accessory/horrible) + + if(!ispath(gift_type,/obj/item)) return + + var/obj/item/I = new gift_type(M) + M.remove_from_mob(src) + M.put_in_hands(I) + I.add_fingerprint(M) + qdel(src) + return + +/* + * Wrapping Paper and Gifts + */ + +/obj/item/weapon/gift + name = "gift" + desc = "A wrapped item." + icon = 'icons/obj/items.dmi' + icon_state = "gift3" + var/size = 3.0 + var/obj/item/gift = null + item_state = "gift" + w_class = ITEM_SIZE_HUGE + +/obj/item/weapon/gift/New(newloc, obj/item/wrapped = null) + ..(newloc) + + if(istype(wrapped)) + gift = wrapped + w_class = gift.w_class + gift.forceMove(src) + + //a good example of where we don't want to use the w_class defines + switch(gift.w_class) + if(1) icon_state = "gift1" + if(2) icon_state = "gift1" + if(3) icon_state = "gift2" + if(4) icon_state = "gift2" + if(5) icon_state = "gift3" + +/obj/item/weapon/gift/attack_self(mob/user as mob) + user.drop_item() + if(src.gift) + user.put_in_active_hand(gift) + src.gift.add_fingerprint(user) + else + to_chat(user, "The gift was empty!") + qdel(src) + return + +/obj/item/weapon/wrapping_paper + name = "wrapping paper" + desc = "You can use this to wrap items in." + icon = 'icons/obj/items.dmi' + icon_state = "wrap_paper" + var/amount = 2.5*base_storage_cost(ITEM_SIZE_HUGE) + +/obj/item/weapon/wrapping_paper/attackby(obj/item/W as obj, mob/user as mob) + ..() + if (!( locate(/obj/structure/table, src.loc) )) + to_chat(user, "You MUST put the paper on a table!") + if (W.w_class < ITEM_SIZE_HUGE) + if(isWirecutter(user.l_hand) || isWirecutter(user.r_hand)) + var/a_used = W.get_storage_cost() + if (a_used == ITEM_SIZE_NO_CONTAINER) + to_chat(user, "You can't wrap that!")//no gift-wrapping lit welders + + return + if (src.amount < a_used) + to_chat(user, "You need more paper!") + return + else + if(istype(W, /obj/item/smallDelivery) || istype(W, /obj/item/weapon/gift)) //No gift wrapping gifts! + return + + if(user.drop_from_inventory(W)) + var/obj/item/weapon/gift/G = new /obj/item/weapon/gift( src.loc, W ) + G.add_fingerprint(user) + W.add_fingerprint(user) + src.amount -= a_used + + if (src.amount <= 0) + new /obj/item/weapon/c_tube( src.loc ) + qdel(src) + return + else + to_chat(user, "You need scissors!") + else + to_chat(user, "The object is FAR too large!") + return + +/obj/item/weapon/wrapping_paper/examine(mob/user) + if(..(user, 1)) + to_chat(user, text("There is about [] square units of paper left!", src.amount)) + +/obj/item/weapon/wrapping_paper/attack(mob/target as mob, mob/user as mob) + if (!istype(target, /mob/living/carbon/human)) return + var/mob/living/carbon/human/H = target + + if (istype(H.wear_suit, /obj/item/clothing/suit/straight_jacket) || H.stat) + if (src.amount > 2) + var/obj/effect/spresent/present = new /obj/effect/spresent (H.loc) + src.amount -= 2 + + if (H.client) + H.client.perspective = EYE_PERSPECTIVE + H.client.eye = present + + H.forceMove(present) + admin_attack_log(user, H, "Used \a [src] to wrap their victim", "Was wrapepd with \a [src]", "used \the [src] to wrap") + + else + to_chat(user, "You need more paper.") + else + to_chat(user, "They are moving around too much. A straightjacket would help.") \ No newline at end of file diff --git a/code/game/objects/items/weapons/grenades/anti_photon_grenade.dm b/code/game/objects/items/weapons/grenades/anti_photon_grenade.dm new file mode 100644 index 00000000..839746bc --- /dev/null +++ b/code/game/objects/items/weapons/grenades/anti_photon_grenade.dm @@ -0,0 +1,23 @@ +/obj/item/weapon/grenade/anti_photon + desc = "An experimental device for temporarily removing light in a limited area." + name = "photon disruption grenade" + icon = 'icons/obj/grenade.dmi' + icon_state = "emp" + item_state = "emp" + det_time = 20 + origin_tech = list(TECH_BLUESPACE = 4, TECH_MATERIAL = 4) + +/obj/item/weapon/grenade/anti_photon/detonate() + playsound(src.loc, 'sound/effects/phasein.ogg', 50, 1, 5) + set_light(10, -10, "#ffffff") + + var/extra_delay = rand(0,90) + + spawn(extra_delay) + spawn(200) + if(prob(10+extra_delay)) + set_light(10, 10, "#[num2hex(rand(64,255))][num2hex(rand(64,255))][num2hex(rand(64,255))]") + spawn(210) + ..() + playsound(src.loc, 'sound/effects/bang.ogg', 50, 1, 5) + qdel(src) diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm new file mode 100644 index 00000000..a993cb0d --- /dev/null +++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm @@ -0,0 +1,303 @@ +/obj/item/weapon/grenade/chem_grenade + name = "grenade casing" + icon_state = "chemg" + item_state = "grenade" + desc = "A hand made chemical grenade." + w_class = ITEM_SIZE_SMALL + force = 2.0 + det_time = null + unacidable = 1 + var/stage = 0 + var/state = 0 + var/path = 0 + var/obj/item/device/assembly_holder/detonator = null + var/list/beakers = new/list() + var/list/allowed_containers = list(/obj/item/weapon/reagent_containers/glass/beaker, /obj/item/weapon/reagent_containers/glass/bottle) + var/affected_area = 3 + + New() + create_reagents(1000) + + attack_self(mob/user as mob) + if(!stage || stage==1) + if(detonator) +// detonator.loc=src.loc + detonator.detached() + usr.put_in_hands(detonator) + detonator=null + det_time = null + stage=0 + icon_state = initial(icon_state) + else if(beakers.len) + for(var/obj/B in beakers) + if(istype(B)) + beakers -= B + user.put_in_hands(B) + SetName("unsecured grenade with [beakers.len] containers[detonator?" and detonator":""]") + if(stage > 1 && !active && clown_check(user)) + to_chat(user, "You prime \the [name]!") + + msg_admin_attack("[user.name] ([user.ckey]) primed \a [src]. (JMP)") + + activate() + add_fingerprint(user) + if(iscarbon(user)) + var/mob/living/carbon/C = user + C.throw_mode_on() + + attackby(obj/item/weapon/W as obj, mob/user as mob) + + if(istype(W,/obj/item/device/assembly_holder) && (!stage || stage==1) && path != 2) + var/obj/item/device/assembly_holder/det = W + if(istype(det.a_left,det.a_right.type) || (!isigniter(det.a_left) && !isigniter(det.a_right))) + to_chat(user, "Assembly must contain one igniter.") + return + if(!det.secured) + to_chat(user, "Assembly must be secured with screwdriver.") + return + path = 1 + to_chat(user, "You add [W] to the metal casing.") + playsound(src.loc, 'sound/items/Screwdriver2.ogg', 25, -3) + user.remove_from_mob(det) + det.loc = src + detonator = det + if(istimer(detonator.a_left)) + var/obj/item/device/assembly/timer/T = detonator.a_left + det_time = 10*T.time + if(istimer(detonator.a_right)) + var/obj/item/device/assembly/timer/T = detonator.a_right + det_time = 10*T.time + icon_state = initial(icon_state) +"_ass" + SetName("unsecured grenade with [beakers.len] containers[detonator?" and detonator":""]") + stage = 1 + else if(isScrewdriver(W) && path != 2) + if(stage == 1) + path = 1 + if(beakers.len) + to_chat(user, "You lock the assembly.") + SetName("grenade") + else +// to_chat(user, "You need to add at least one beaker before locking the assembly.") + to_chat(user, "You lock the empty assembly.") + SetName("fake grenade") + playsound(src.loc, 'sound/items/Screwdriver.ogg', 25, -3) + icon_state = initial(icon_state) +"_locked" + stage = 2 + else if(stage == 2) + if(active && prob(95)) + to_chat(user, "You trigger the assembly!") + detonate() + return + else + to_chat(user, "You unlock the assembly.") + playsound(src.loc, 'sound/items/Screwdriver.ogg', 25, -3) + SetName("unsecured grenade with [beakers.len] containers[detonator?" and detonator":""]") + icon_state = initial(icon_state) + (detonator?"_ass":"") + stage = 1 + active = 0 + else if(is_type_in_list(W, allowed_containers) && (!stage || stage==1) && path != 2) + path = 1 + if(beakers.len == 2) + to_chat(user, "The grenade can not hold more containers.") + return + else + if(W.reagents.total_volume) + to_chat(user, "You add \the [W] to the assembly.") + user.drop_item() + W.loc = src + beakers += W + stage = 1 + SetName("unsecured grenade with [beakers.len] containers[detonator?" and detonator":""]") + else + to_chat(user, "\The [W] is empty.") + + examine(mob/user) + . = ..(user) + if(detonator) + to_chat(user, "With attached [detonator.name]") + + activate(mob/user as mob) + if(active) return + + if(detonator) + if(!isigniter(detonator.a_left)) + detonator.a_left.activate() + active = 1 + if(!isigniter(detonator.a_right)) + detonator.a_right.activate() + active = 1 + if(active) + icon_state = initial(icon_state) + "_active" + + if(user) + msg_admin_attack("[user.name] ([user.ckey]) primed \a [src] (JMP)") + + return + + proc/primed(var/primed = 1) + if(active) + icon_state = initial(icon_state) + (primed?"_primed":"_active") + + detonate() + if(!stage || stage<2) return + + var/has_reagents = 0 + for(var/obj/item/weapon/reagent_containers/glass/G in beakers) + if(G.reagents.total_volume) has_reagents = 1 + + active = 0 + if(!has_reagents) + icon_state = initial(icon_state) +"_locked" + playsound(src.loc, 'sound/items/Screwdriver2.ogg', 50, 1) + spawn(0) //Otherwise det_time is erroneously set to 0 after this + if(istimer(detonator.a_left)) //Make sure description reflects that the timer has been reset + var/obj/item/device/assembly/timer/T = detonator.a_left + det_time = 10*T.time + if(istimer(detonator.a_right)) + var/obj/item/device/assembly/timer/T = detonator.a_right + det_time = 10*T.time + return + + playsound(src.loc, 'sound/effects/bamf.ogg', 50, 1) + + for(var/obj/item/weapon/reagent_containers/glass/G in beakers) + G.reagents.trans_to_obj(src, G.reagents.total_volume) + + if(src.reagents.total_volume) //The possible reactions didnt use up all reagents. + var/datum/effect/effect/system/steam_spread/steam = new /datum/effect/effect/system/steam_spread() + steam.set_up(10, 0, get_turf(src)) + steam.attach(src) + steam.start() + + for(var/atom/A in view(affected_area, src.loc)) + if( A == src ) continue + src.reagents.touch(A) + + if(istype(loc, /mob/living/carbon)) //drop dat grenade if it goes off in your hand + var/mob/living/carbon/C = loc + C.drop_from_inventory(src) + C.throw_mode_off() + + set_invisibility(INVISIBILITY_MAXIMUM) //Why am i doing this? + spawn(50) //To make sure all reagents can work + qdel(src) //correctly before deleting the grenade. + + +/obj/item/weapon/grenade/chem_grenade/large + name = "large chem grenade" + desc = "An oversized grenade that affects a larger area." + icon_state = "large_grenade" + allowed_containers = list(/obj/item/weapon/reagent_containers/glass) + origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 3) + affected_area = 4 + +/obj/item/weapon/grenade/chem_grenade/metalfoam + name = "metal-foam grenade" + desc = "Used for emergency sealing of air breaches." + path = 1 + stage = 2 + + New() + ..() + var/obj/item/weapon/reagent_containers/glass/beaker/B1 = new(src) + var/obj/item/weapon/reagent_containers/glass/beaker/B2 = new(src) + + B1.reagents.add_reagent(/datum/reagent/aluminum, 30) + B2.reagents.add_reagent(/datum/reagent/foaming_agent, 10) + B2.reagents.add_reagent(/datum/reagent/acid/polyacid, 10) + + detonator = new/obj/item/device/assembly_holder/timer_igniter(src) + + beakers += B1 + beakers += B2 + icon_state = initial(icon_state) +"_locked" + +/obj/item/weapon/grenade/chem_grenade/incendiary + name = "incendiary grenade" + desc = "Used for clearing rooms of living things." + path = 1 + stage = 2 + + New() + ..() + var/obj/item/weapon/reagent_containers/glass/beaker/B1 = new(src) + var/obj/item/weapon/reagent_containers/glass/beaker/B2 = new(src) + + B1.reagents.add_reagent(/datum/reagent/aluminum, 15) + B1.reagents.add_reagent(/datum/reagent/fuel,20) + B2.reagents.add_reagent(/datum/reagent/toxin/phoron, 15) + B2.reagents.add_reagent(/datum/reagent/acid, 15) + B1.reagents.add_reagent(/datum/reagent/fuel,20) + + detonator = new/obj/item/device/assembly_holder/timer_igniter(src) + + beakers += B1 + beakers += B2 + icon_state = initial(icon_state) +"_locked" + +/obj/item/weapon/grenade/chem_grenade/antiweed + name = "weedkiller grenade" + desc = "Used for purging large areas of invasive plant species. Contents under pressure. Do not directly inhale contents." + path = 1 + stage = 2 + + New() + ..() + var/obj/item/weapon/reagent_containers/glass/beaker/B1 = new(src) + var/obj/item/weapon/reagent_containers/glass/beaker/B2 = new(src) + + B1.reagents.add_reagent(/datum/reagent/toxin/plantbgone, 25) + B1.reagents.add_reagent(/datum/reagent/potassium, 25) + B2.reagents.add_reagent(/datum/reagent/phosphorus, 25) + B2.reagents.add_reagent(/datum/reagent/sugar, 25) + + detonator = new/obj/item/device/assembly_holder/timer_igniter(src) + + beakers += B1 + beakers += B2 + icon_state = "grenade" + +/obj/item/weapon/grenade/chem_grenade/cleaner + name = "cleaner grenade" + desc = "BLAM!-brand foaming space cleaner. In a special applicator for rapid cleaning of wide areas." + stage = 2 + path = 1 + + New() + ..() + var/obj/item/weapon/reagent_containers/glass/beaker/B1 = new(src) + var/obj/item/weapon/reagent_containers/glass/beaker/B2 = new(src) + + B1.reagents.add_reagent(/datum/reagent/surfactant, 40) + B2.reagents.add_reagent(/datum/reagent/water, 40) + B2.reagents.add_reagent(/datum/reagent/space_cleaner, 10) + + detonator = new/obj/item/device/assembly_holder/timer_igniter(src) + + beakers += B1 + beakers += B2 + icon_state = initial(icon_state) +"_locked" + +/obj/item/weapon/grenade/chem_grenade/teargas + name = "tear gas grenade" + desc = "Concentrated Capsaicin. Contents under pressure. Use with caution." + stage = 2 + path = 1 + + New() + ..() + var/obj/item/weapon/reagent_containers/glass/beaker/large/B1 = new(src) + var/obj/item/weapon/reagent_containers/glass/beaker/large/B2 = new(src) + + B1.reagents.add_reagent(/datum/reagent/phosphorus, 40) + B1.reagents.add_reagent(/datum/reagent/potassium, 40) + B1.reagents.add_reagent(/datum/reagent/capsaicin/condensed, 40) + B2.reagents.add_reagent(/datum/reagent/sugar, 40) + B2.reagents.add_reagent(/datum/reagent/capsaicin/condensed, 80) + + detonator = new/obj/item/device/assembly_holder/timer_igniter(src) + + beakers += B1 + beakers += B2 + icon_state = initial(icon_state) +"_locked" + diff --git a/code/game/objects/items/weapons/grenades/emgrenade.dm b/code/game/objects/items/weapons/grenades/emgrenade.dm new file mode 100644 index 00000000..38b5111c --- /dev/null +++ b/code/game/objects/items/weapons/grenades/emgrenade.dm @@ -0,0 +1,24 @@ +/obj/item/weapon/grenade/empgrenade + name = "classic emp grenade" + icon_state = "emp" + item_state = "empgrenade" + origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 3) + + detonate() + ..() + if(empulse(src, 4, 10)) + qdel(src) + return + +/obj/item/weapon/grenade/empgrenade/low_yield + name = "low yield emp grenade" + desc = "A weaker variant of the classic emp grenade." + icon_state = "lyemp" + item_state = "lyempgrenade" + origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 3) + + detonate() + ..() + if(empulse(src, 4, 1)) + qdel(src) + return diff --git a/code/game/objects/items/weapons/grenades/explosive.dm b/code/game/objects/items/weapons/grenades/explosive.dm new file mode 100644 index 00000000..db0dccc0 --- /dev/null +++ b/code/game/objects/items/weapons/grenades/explosive.dm @@ -0,0 +1,153 @@ +/obj/item/projectile/bullet/pellet/fragment + damage = 100 + range_step = 2 //controls damage falloff with distance. projectiles lose a "pellet" each time they travel this distance. Can be a non-integer. + + base_spread = 0 //causes it to be treated as a shrapnel explosion instead of cone + spread_step = 20 + + silenced = 1 + fire_sound = null + no_attack_log = 1 + muzzle_type = null + do_not_pass_trench = TRUE + +/obj/item/projectile/bullet/pellet/fragment/strong + damage = 40 + +/obj/item/weapon/grenade/frag + name = "fragmentation grenade" + desc = "A military fragmentation grenade, designed to explode in a deadly shower of fragments, while avoiding massive structural damage." + icon_state = "frggrenade" + arm_sound = 'sound/weapons/grenade_arm.ogg' + throw_range = 10 + + var/list/fragment_types = list(/obj/item/projectile/bullet/pellet/fragment = 1) + var/num_fragments = 72 //total number of fragments produced by the grenade + var/explosion_size = 2 //size of the center explosion + + //The radius of the circle used to launch projectiles. Lower values mean less projectiles are used but if set too low gaps may appear in the spread pattern + var/spread_range = 7 //leave as is, for some reason setting this higher makes the spread pattern have gaps close to the epicenter + +/obj/item/weapon/grenade/frag/detonate() + ..() + + var/turf/O = get_turf(src) + if(!O) return + + if(explosion_size) + on_explosion(O) + + src.fragmentate(O, num_fragments, spread_range, fragment_types) + + qdel(src) + + +/atom/proc/fragmentate(var/turf/T=get_turf(src), var/fragment_number = 30, var/spreading_range = 5, var/list/fragtypes=list(/obj/item/projectile/bullet/pellet/fragment/)) + set waitfor = 0 + var/list/target_turfs = getcircle(T, spreading_range) + var/fragments_per_projectile = round(fragment_number/target_turfs.len) + + playsound(src, 'sound/weapons/grenade_exp.ogg') + for(var/turf/O in target_turfs) + sleep(0) + var/fragment_type = pickweight(fragtypes) + var/obj/item/projectile/bullet/pellet/fragment/P = new fragment_type(T) + P.pellets = fragments_per_projectile + P.shot_from = src.name + + P.launch_projectile(O) + + //Make sure to hit any mobs in the source turf + for(var/mob/living/M in T) + //lying on a frag grenade while the grenade is on the ground causes you to absorb most of the shrapnel. + //you will most likely be dead, but others nearby will be spared the fragments that hit you instead. + if(M.lying && isturf(src.loc)) + P.attack_mob(M, 0, 5) + else if(!M.lying && src.loc != get_turf(src)) //if it's not on the turf, it must be in the mob! + P.attack_mob(M, 0, 25) //you're holding a grenade, dude! + else + P.attack_mob(M, 0, 100) //otherwise, allow a decent amount of fragments to pass + +/obj/mortar/frag + name = "Mortar" + desc = "You'll never see this it just explodes." + +/obj/mortar/frag/New() + ..() + fragmentate(get_turf(src), 72) + qdel(src) + +/obj/mortar/gas + name = "gas mortar" + +/obj/mortar/gas/New() + ..() + create_reagents(100) + reagents.add_reagent(/datum/reagent/toxin/mustard_gas, 50) + var/location = get_turf(src) + var/datum/effect/effect/system/smoke_spread/chem/S = new + S.attach(location) + S.set_up(reagents, 50, 0, location) + spawn(0) + S.start() + qdel(src) + +/obj/mortar/fire + name = "fire mortar" + +/obj/mortar/fire/New()//Just spawns fire. + ..() + new /obj/flamer_fire(loc, 12, 10, "red", 8) + qdel(src) + +/obj/mortar/flare + name = "illumination mortar" + var/flare_type = /obj/effect/lighting_dummy/flare + +obj/mortar/flare/blue + flare_type = /obj/effect/lighting_dummy/flare/blue + +/obj/mortar/flare/New()//Just spawns a flare. + ..() + new flare_type(loc) + qdel(src) + +/obj/item/weapon/grenade/frag/proc/on_explosion(var/turf/O) + if(explosion_size) + explosion(O, -1, -1, explosion_size, round(explosion_size/2), 0) + +/obj/item/weapon/grenade/frag/warfare + desc = "Throw it at THE ENEMEY!" + icon_state = "warfare_grenade" + + +/obj/item/weapon/grenade/frag/ex_act(severity) + . = ..() + if(severity) + detonate() + + +/obj/item/weapon/grenade/frag/shell + name = "fragmentation grenade" + desc = "A light fragmentation grenade, designed to be fired from a launcher. It can still be activated and thrown by hand if necessary." + icon_state = "fragshell" + + num_fragments = 50 //less powerful than a regular frag grenade + + +/obj/item/weapon/grenade/frag/high_yield + name = "fragmentation bomb" + desc = "Larger and heavier than a standard fragmentation grenade, this device is extremely dangerous. It cannot be thrown as far because of its weight." + icon_state = "frag" + + w_class = ITEM_SIZE_NORMAL + throw_speed = 3 + throw_range = 5 //heavy, can't be thrown as far + + fragment_types = list(/obj/item/projectile/bullet/pellet/fragment=1,/obj/item/projectile/bullet/pellet/fragment/strong=4) + num_fragments = 200 //total number of fragments produced by the grenade + explosion_size = 3 + +/obj/item/weapon/grenade/frag/high_yield/on_explosion(var/turf/O) + if(explosion_size) + explosion(O, -1, round(explosion_size/2), explosion_size, round(explosion_size/2), 0) //has a chance to blow a hole in the floor diff --git a/code/game/objects/items/weapons/grenades/flashbang.dm b/code/game/objects/items/weapons/grenades/flashbang.dm new file mode 100644 index 00000000..5ec3cd8e --- /dev/null +++ b/code/game/objects/items/weapons/grenades/flashbang.dm @@ -0,0 +1,171 @@ +/obj/item/weapon/grenade/flashbang + name = "flashbang" + icon_state = "flashbang" + item_state = "flashbang" + origin_tech = list(TECH_MATERIAL = 2, TECH_COMBAT = 1) + var/banglet = 0 + + detonate() + ..() + for(var/obj/structure/closet/L in hear(7, get_turf(src))) + if(locate(/mob/living/carbon/, L)) + for(var/mob/living/carbon/M in L) + bang(get_turf(src), M) + + + for(var/mob/living/carbon/M in hear(7, get_turf(src))) + bang(get_turf(src), M) + + for(var/obj/effect/blob/B in hear(8,get_turf(src))) //Blob damage here + var/damage = round(30/(get_dist(B,get_turf(src))+1)) + B.health -= damage + B.update_icon() + + new/obj/effect/sparks(src.loc) + new/obj/effect/effect/smoke/illumination(src.loc, 5, range=30, power=30, color="#ffffff") + qdel(src) + return + + proc/bang(var/turf/T , var/mob/living/carbon/M) // Added a new proc called 'bang' that takes a location and a person to be banged. + to_chat(M, "BANG")// Called during the loop that bangs people in lockers/containers and when banging + playsound(src.loc, 'sound/effects/bang.ogg', 50, 1, 30) // people in normal view. Could theroetically be called during other explosions. + // -- Polymorph + +//Checking for protections + var/eye_safety = 0 + var/ear_safety = 0 + if(iscarbon(M)) + eye_safety = M.eyecheck() + if(ishuman(M)) + if(istype(M:l_ear, /obj/item/clothing/ears/earmuffs) || istype(M:r_ear, /obj/item/clothing/ears/earmuffs)) + ear_safety += 2 + if(HULK in M.mutations) + ear_safety += 1 + if(istype(M:head, /obj/item/clothing/head/helmet)) + ear_safety += 1 + +//Flashing everyone + if(eye_safety < FLASH_PROTECTION_MODERATE) + M.flash_eyes() + M.Stun(2) + M.Weaken(10) + + + +//Now applying sound + if((get_dist(M, T) <= 2 || src.loc == M.loc || src.loc == M)) + if(ear_safety > 0) + M.KnockDown() + else + M.Stun(10) + M.Weaken(3) + if ((prob(14) || (M == src.loc && prob(70)))) + M.ear_damage += rand(1, 10) + else + M.ear_damage += rand(0, 5) + M.ear_deaf = max(M.ear_deaf,15) + + else if(get_dist(M, T) <= 5) + if(!ear_safety) + M.Stun(8) + M.ear_damage += rand(0, 3) + M.ear_deaf = max(M.ear_deaf,10) + + else if(!ear_safety) + M.Stun(4) + M.ear_damage += rand(0, 1) + M.ear_deaf = max(M.ear_deaf,5) + +//This really should be in mob not every check + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/internal/eyes/E = H.internal_organs_by_name[BP_EYES] + if (E && E.damage >= E.min_bruised_damage) + to_chat(M, "Your eyes start to burn badly!") + if(!banglet && !(istype(src , /obj/item/weapon/grenade/flashbang/clusterbang))) + if (E.damage >= E.min_broken_damage) + to_chat(M, "You can't see anything!") + if (M.ear_damage >= 15) + to_chat(M, "Your ears start to ring badly!") + if(!banglet && !(istype(src , /obj/item/weapon/grenade/flashbang/clusterbang))) + if (prob(M.ear_damage - 10 + 5)) + to_chat(M, "You can't hear anything!") + M.sdisabilities |= DEAF + else + if (M.ear_damage >= 5) + to_chat(M, "Your ears start to ring!") + M.update_icons() + +/obj/item/weapon/grenade/flashbang/Destroy() + walk(src, 0) // Because we might have called walk_away, we must stop the walk loop or BYOND keeps an internal reference to us forever. + return ..() + +/obj/item/weapon/grenade/flashbang/clusterbang//Created by Polymorph, fixed by Sieve + desc = "Use of this weapon may constiute a war crime in your area, consult your local captain." + name = "clusterbang" + icon = 'icons/obj/grenade.dmi' + icon_state = "clusterbang" + +/obj/item/weapon/grenade/flashbang/clusterbang/detonate() + var/numspawned = rand(4,8) + var/again = 0 + for(var/more = numspawned,more > 0,more--) + if(prob(35)) + again++ + numspawned -- + + for(,numspawned > 0, numspawned--) + spawn(0) + new /obj/item/weapon/grenade/flashbang/cluster(src.loc)//Launches flashbangs + playsound(src.loc, 'sound/weapons/armbomb.ogg', 75, 1, -3) + + for(,again > 0, again--) + spawn(0) + new /obj/item/weapon/grenade/flashbang/clusterbang/segment(src.loc)//Creates a 'segment' that launches a few more flashbangs + playsound(src.loc, 'sound/weapons/armbomb.ogg', 75, 1, -3) + qdel(src) + return + +/obj/item/weapon/grenade/flashbang/clusterbang/segment + desc = "A smaller segment of a clusterbang. Better run." + name = "clusterbang segment" + icon = 'icons/obj/grenade.dmi' + icon_state = "clusterbang_segment" + +/obj/item/weapon/grenade/flashbang/clusterbang/segment/New()//Segments should never exist except part of the clusterbang, since these immediately 'do their thing' and asplode + icon_state = "clusterbang_segment_active" + active = 1 + banglet = 1 + var/stepdist = rand(1,4)//How far to step + var/temploc = src.loc//Saves the current location to know where to step away from + walk_away(src,temploc,stepdist)//I must go, my people need me + var/dettime = rand(15,60) + spawn(dettime) + detonate() + ..() + +/obj/item/weapon/grenade/flashbang/clusterbang/segment/detonate() + var/numspawned = rand(4,8) + for(var/more = numspawned,more > 0,more--) + if(prob(35)) + numspawned -- + + for(,numspawned > 0, numspawned--) + spawn(0) + new /obj/item/weapon/grenade/flashbang/cluster(src.loc) + playsound(src.loc, 'sound/weapons/armbomb.ogg', 75, 1, -3) + qdel(src) + return + +/obj/item/weapon/grenade/flashbang/cluster/New()//Same concept as the segments, so that all of the parts don't become reliant on the clusterbang + spawn(0) + icon_state = "flashbang_active" + active = 1 + banglet = 1 + var/stepdist = rand(1,3) + var/temploc = src.loc + walk_away(src,temploc,stepdist) + var/dettime = rand(15,60) + spawn(dettime) + detonate() + ..() diff --git a/code/game/objects/items/weapons/grenades/grenade.dm b/code/game/objects/items/weapons/grenades/grenade.dm new file mode 100644 index 00000000..63801275 --- /dev/null +++ b/code/game/objects/items/weapons/grenades/grenade.dm @@ -0,0 +1,120 @@ +/obj/item/weapon/grenade + name = "grenade" + desc = "A hand held grenade, with an adjustable timer." + w_class = ITEM_SIZE_SMALL + icon = 'icons/obj/grenade.dmi' + icon_state = "grenade" + item_state = "grenade" + throw_speed = 4 + throw_range = 20 + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + var/active = 0 + var/det_time = 50 + var/arm_sound = 'sound/weapons/armbomb.ogg' + +/obj/item/weapon/grenade/proc/clown_check(var/mob/living/user) + if((CLUMSY in user.mutations) && prob(50)) + to_chat(user, "Huh? How does this thing work?") + + activate(user) + add_fingerprint(user) + spawn(5) + detonate() + return 0 + return 1 + + +/*/obj/item/weapon/grenade/afterattack(atom/target as mob|obj|turf|area, mob/user as mob) + if (istype(target, /obj/item/weapon/storage)) return ..() // Trying to put it in a full container + if (istype(target, /obj/item/weapon/gun/grenadelauncher)) return ..() + if((user.get_active_hand() == src) && (!active) && (clown_check(user)) && target.loc != src.loc) + to_chat(user, "You prime the [name]! [det_time/10] seconds!") + active = 1 + icon_state = initial(icon_state) + "_active" + playsound(loc, 'sound/weapons/armbomb.ogg', 75, 1, -3) + spawn(det_time) + detonate() + return + user.set_dir(get_dir(user, target)) + user.drop_item() + var/t = (isturf(target) ? target : target.loc) + walk_towards(src, t, 3) + return*/ + + +/obj/item/weapon/grenade/examine(mob/user) + if(..(user, 0)) + if(det_time > 1) + to_chat(user, "The timer is set to [det_time/10] seconds.") + return + if(det_time == null) + return + to_chat(user, "\The [src] is set for instant detonation.") + + +/obj/item/weapon/grenade/attack_self(mob/user as mob) + if(!active) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.isChild()) + if(!istype(src, /obj/item/weapon/grenade/smokebomb)) + to_chat(H, "I'm just not able to pull the pin on \the [name]!") + return + if(clown_check(user)) + to_chat(user, "You prime \the [name]! [det_time/10] seconds!") + + activate(user) + add_fingerprint(user) + if(iscarbon(user)) + var/mob/living/carbon/C = user + C.throw_mode_on() + return + + +/obj/item/weapon/grenade/proc/activate(mob/user as mob) + if(active) + return + + if(user) + log_and_message_admins("[user.name] ([user.ckey]) primed \a [src] (JMP)") + + icon_state = initial(icon_state) + "_active" + active = 1 + playsound(loc, arm_sound, 75, 0, -3) + + spawn(det_time) + detonate() + return + + +/obj/item/weapon/grenade/proc/detonate() +// playsound(loc, 'sound/items/Welder2.ogg', 25, 1) + var/turf/T = get_turf(src) + if(T) + T.hotspot_expose(700,125) + + +/obj/item/weapon/grenade/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isScrewdriver(W)) + switch(det_time) + if (1) + det_time = 10 + to_chat(user, "You set the [name] for 1 second detonation time.") + if (10) + det_time = 30 + to_chat(user, "You set the [name] for 3 second detonation time.") + if (30) + det_time = 50 + to_chat(user, "You set the [name] for 5 second detonation time.") + if (50) + det_time = 1 + to_chat(user, "You set the [name] for instant detonation.") + add_fingerprint(user) + ..() + return + +/obj/item/weapon/grenade/attack_hand() + walk(src, null, null) + ..() + return diff --git a/code/game/objects/items/weapons/grenades/prank_grenades.dm b/code/game/objects/items/weapons/grenades/prank_grenades.dm new file mode 100644 index 00000000..f6b5b070 --- /dev/null +++ b/code/game/objects/items/weapons/grenades/prank_grenades.dm @@ -0,0 +1,12 @@ +/obj/item/weapon/grenade/fake + icon_state = "frggrenade" + +/obj/item/weapon/grenade/fake/detonate() + active = 0 + playsound(src.loc, get_sfx("explosion"), 50, 1, 30) + +/obj/item/weapon/grenade/spawnergrenade/fake_carp + origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 2, TECH_BLUESPACE = 5) + spawner_type = /mob/living/simple_animal/hostile/carp/holodeck + deliveryamt = 4 + newvars = list("faction" = null, "melee_damage_lower" = 0, "melee_damage_upper" = 0, "environment_smash" = 0, "destroy_surroundings" = 0) \ No newline at end of file diff --git a/code/game/objects/items/weapons/grenades/smokebomb.dm b/code/game/objects/items/weapons/grenades/smokebomb.dm new file mode 100644 index 00000000..bfc076d3 --- /dev/null +++ b/code/game/objects/items/weapons/grenades/smokebomb.dm @@ -0,0 +1,50 @@ +/obj/item/weapon/grenade/smokebomb + desc = "Use this to stop both you, and the enemy from seeing anything." + name = "smoke bomb" + icon = 'icons/obj/grenade.dmi' + icon_state = "csmoke" + arm_sound = 'sound/weapons/grenade_arm.ogg' + det_time = 30 + item_state = "flashbang" + slot_flags = SLOT_BELT + var/datum/effect/effect/system/smoke_spread/smoke + +/obj/item/weapon/grenade/smokebomb/New() + ..() + src.smoke = new /datum/effect/effect/system/smoke_spread() + src.smoke.attach(src) + +/obj/item/weapon/grenade/smokebomb/Destroy() + qdel(smoke) + smoke = null + return ..() + +/obj/item/weapon/grenade/smokebomb/detonate() + playsound(src.loc, 'sound/effects/smoke.ogg', 50) + src.smoke.set_up(10, 0, usr.loc) + spawn(0) + src.smoke.start() + sleep(10) + src.smoke.start() + sleep(10) + src.smoke.start() + sleep(10) + src.smoke.start() + sleep(80) + qdel(src) + + +//These are debug items and are not used in game. +/obj/item/weapon/grenade/smokebomb/mortar + name = "mortar marker" + desc = "Throw it at the spot you want mortar fire at. MAKE SURE YOU'RE NOT THERE!" + det_time = 50 + var/mortar_type = "shrapnel" + +/obj/item/weapon/grenade/smokebomb/mortar/detonate() + drop_mortar(get_turf(src), mortar_type) + qdel(src) + + +/obj/item/weapon/grenade/smokebomb/mortar/gas + mortar_type = "gas" \ No newline at end of file diff --git a/code/game/objects/items/weapons/grenades/spawnergrenade.dm b/code/game/objects/items/weapons/grenades/spawnergrenade.dm new file mode 100644 index 00000000..e2edda68 --- /dev/null +++ b/code/game/objects/items/weapons/grenades/spawnergrenade.dm @@ -0,0 +1,48 @@ +/obj/item/weapon/grenade/spawnergrenade + desc = "It is set to detonate in 5 seconds. It will unleash unleash an unspecified anomaly into the vicinity." + name = "delivery grenade" + icon = 'icons/obj/grenade.dmi' + icon_state = "delivery" + item_state = "flashbang" + origin_tech = list(TECH_MATERIAL = 3, TECH_MAGNET = 4) + var/banglet = 0 + var/spawner_type = null // must be an object path + var/deliveryamt = 1 // amount of type to deliver + var/list/newvars + + detonate() // Prime now just handles the two loops that query for people in lockers and people who can see it. + + if(spawner_type && deliveryamt) + // Make a quick flash + 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) + M.flash_eyes() + + for(var/i=1, i<=deliveryamt, i++) + var/atom/movable/x = new spawner_type + if(newvars && length(newvars)) + for(var/v in newvars) + x.vars[v] = newvars[v] + x.loc = T + if(prob(50)) + for(var/j = 1, j <= rand(1, 3), j++) + step(x, pick(NORTH,SOUTH,EAST,WEST)) + + // Spawn some hostile syndicate critters + + qdel(src) + return + +/obj/item/weapon/grenade/spawnergrenade/manhacks + name = "manhack delivery grenade" + spawner_type = /mob/living/simple_animal/hostile/viscerator + deliveryamt = 5 + origin_tech = list(TECH_MATERIAL = 3, TECH_MAGNET = 4, TECH_ILLEGAL = 4) + +/obj/item/weapon/grenade/spawnergrenade/spesscarp + name = "carp delivery grenade" + spawner_type = /mob/living/simple_animal/hostile/carp + deliveryamt = 5 + origin_tech = list(TECH_MATERIAL = 3, TECH_MAGNET = 4, TECH_ILLEGAL = 4) diff --git a/code/game/objects/items/weapons/grenades/supermatter.dm b/code/game/objects/items/weapons/grenades/supermatter.dm new file mode 100644 index 00000000..03e12085 --- /dev/null +++ b/code/game/objects/items/weapons/grenades/supermatter.dm @@ -0,0 +1,36 @@ +/obj/item/weapon/grenade/supermatter + name = "supermatter grenade" + icon_state = "banana" + item_state = "emergency_engi" + origin_tech = list(TECH_BLUESPACE = 5, TECH_MAGNET = 4, TECH_ENGINEERING = 5) + arm_sound = 'sound/effects/3.wav' + var/implode_at + +/obj/item/weapon/grenade/supermatter/Destroy() + if(implode_at) + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/item/weapon/grenade/supermatter/detonate() + ..() + START_PROCESSING(SSobj, src) + implode_at = world.time + 10 SECONDS + update_icon() + playsound(src, 'sound/weapons/wave.ogg', 100) + +/obj/item/weapon/grenade/supermatter/update_icon() + overlays.Cut() + if(implode_at) + overlays += image(icon = 'icons/obj/machines/power/fusion.dmi', icon_state = "emfield_s1") + +/obj/item/weapon/grenade/supermatter/Process() + if(!isturf(loc)) + if(ismob(loc)) + var/mob/M = loc + M.drop_from_inventory(src) + forceMove(get_turf(src)) + playsound(src, 'sound/effects/supermatter.ogg', 100) + supermatter_pull(src, world.view, STAGE_THREE) + if(world.time > implode_at) + explosion(loc, 0, 1, 3, 4) + qdel(src) diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm new file mode 100644 index 00000000..77b02714 --- /dev/null +++ b/code/game/objects/items/weapons/handcuffs.dm @@ -0,0 +1,178 @@ +/obj/item/weapon/handcuffs + name = "handcuffs" + desc = "Use this to keep prisoners in line." + gender = PLURAL + icon = 'icons/obj/items.dmi' + icon_state = "handcuff" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + throwforce = 5 + w_class = ITEM_SIZE_SMALL + throw_speed = 2 + throw_range = 5 + origin_tech = list(TECH_MATERIAL = 1) + matter = list(DEFAULT_WALL_MATERIAL = 500) + var/elastic + var/dispenser = 0 + var/breakouttime = 1200 //Deciseconds = 120s = 2 minutes + var/cuff_sound = 'sound/weapons/handcuffs.ogg' + var/cuff_type = "handcuffs" + + + +/obj/item/weapon/handcuffs/get_icon_state(mob/user_mob, slot) + if(slot == slot_handcuffed_str) + return "handcuff1" + if(slot == slot_legcuffed_str) + return "legcuff1" + return ..() + +/obj/item/weapon/handcuffs/attack(var/mob/living/carbon/C, var/mob/living/user) + + if(!user.IsAdvancedToolUser()) + return + + if ((CLUMSY in user.mutations) && prob(50)) + to_chat(user, "Uh ... how do those things work?!") + place_handcuffs(user, user) + return + + // only carbons can be handcuffed + if(istype(C)) + if(!C.handcuffed) + if (C == user) + place_handcuffs(user, user) + return + + //check for an aggressive grab (or robutts) + if(can_place(C, user)) + place_handcuffs(C, user) + else + to_chat(user, "You need to have a firm grip on [C] before you can put \the [src] on!") + else + to_chat(user, "\The [C] is already handcuffed!") + else + ..() + +/obj/item/weapon/handcuffs/proc/can_place(var/mob/target, var/mob/user) + if(user == target || istype(user, /mob/living/silicon/robot) || istype(user, /mob/living/bot)) + return 1 + else + for (var/obj/item/grab/G in target.grabbed_by) + if (G.force_danger()) + return 1 + return 0 + +/obj/item/weapon/handcuffs/proc/place_handcuffs(var/mob/living/carbon/target, var/mob/user) + playsound(src.loc, cuff_sound, 30, 1, -2) + + var/mob/living/carbon/human/H = target + if(!istype(H)) + return 0 + + if (!H.has_organ_for_slot(slot_handcuffed)) + to_chat(user, "\The [H] needs at least two wrists before you can cuff them together!") + return 0 + + user.visible_message("\The [user] is attempting to put [cuff_type] on \the [H]!") + + if(!do_after(user,30, target)) + return 0 + + if(!can_place(target, user)) // victim may have resisted out of the grab in the meantime + return 0 + + admin_attack_log(user, H, "Attempted to handcuff the victim", "Was target of an attempted handcuff", "attempted to handcuff") + 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. + var/obj/item/weapon/handcuffs/cuffs = src + if(dispenser) + cuffs = new(get_turf(user)) + else + user.drop_from_inventory(cuffs) + target.equip_to_slot(cuffs,slot_handcuffed) + return 1 + +var/last_chew = 0 +/mob/living/carbon/human/RestrainedClickOn(var/atom/A) + if (A != src) return ..() + if (last_chew + 26 > world.time) return + + var/mob/living/carbon/human/H = A + if (!H.handcuffed) return + if (H.a_intent != I_HURT) return + if (H.zone_sel.selecting != BP_MOUTH) return + if (H.wear_mask) return + if (istype(H.wear_suit, /obj/item/clothing/suit/straight_jacket)) return + + var/obj/item/organ/external/O = H.organs_by_name[(H.hand ? BP_L_HAND : BP_R_HAND)] + if (!O) return + + H.visible_message("\The [H] chews on \his [O.name]!", "You chew on your [O.name]!") + admin_attacker_log(H, "chewed on their [O.name]!") + + O.take_damage(3,0, DAM_SHARP|DAM_EDGE ,"teeth marks") + + last_chew = world.time + +/obj/item/weapon/handcuffs/cable + name = "cable restraints" + desc = "Looks like some cables tied together. Could be used to tie something up." + icon_state = "cuff_white" + breakouttime = 300 //Deciseconds = 30s + cuff_sound = 'sound/weapons/cablecuff.ogg' + cuff_type = "cable restraints" + elastic = 1 + +/obj/item/weapon/handcuffs/cable/red + color = "#dd0000" + +/obj/item/weapon/handcuffs/cable/yellow + color = "#dddd00" + +/obj/item/weapon/handcuffs/cable/blue + color = "#0000dd" + +/obj/item/weapon/handcuffs/cable/green + color = "#00dd00" + +/obj/item/weapon/handcuffs/cable/pink + color = "#dd00dd" + +/obj/item/weapon/handcuffs/cable/orange + color = "#dd8800" + +/obj/item/weapon/handcuffs/cable/cyan + color = "#00dddd" + +/obj/item/weapon/handcuffs/cable/white + color = "#ffffff" + +/obj/item/weapon/handcuffs/cable/attackby(var/obj/item/I, mob/user as mob) + ..() + if(istype(I, /obj/item/stack/rods)) + var/obj/item/stack/rods/R = I + if (R.use(1)) + var/obj/item/weapon/material/wirerod/W = new(get_turf(user)) + user.put_in_hands(W) + to_chat(user, "You wrap the cable restraint around the top of the rod.") + qdel(src) + update_icon(user) + +/obj/item/weapon/handcuffs/cyborg + dispenser = 1 + +/obj/item/weapon/handcuffs/cable/tape + name = "tape restraints" + desc = "DIY!" + icon_state = "tape_cross" + item_state = null + icon = 'icons/obj/bureaucracy.dmi' + breakouttime = 200 + cuff_type = "duct tape" diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm new file mode 100644 index 00000000..f0d8539c --- /dev/null +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -0,0 +1,98 @@ +#define MALFUNCTION_TEMPORARY 1 +#define MALFUNCTION_PERMANENT 2 + + +/obj/item/weapon/implant + name = "implant" + icon = 'icons/obj/device.dmi' + icon_state = "implant" + w_class = ITEM_SIZE_TINY + var/implanted = null + var/mob/imp_in = null + var/obj/item/organ/external/part = null + var/implant_color = "b" + var/malfunction = 0 + var/known //if advanced scanners would name these in results + var/truly_unknown = FALSE + +/obj/item/weapon/implant/proc/trigger(emote, source) + return + +/obj/item/weapon/implant/proc/hear(message) + return + +/obj/item/weapon/implant/proc/activate() + return + +// What does the implant do upon injection? +// return 0 if the implant fails (ex. Revhead and loyalty implant.) +// return TRUE if the implant succeeds (ex. Nonrevhead and loyalty implant.) +/obj/item/weapon/implant/proc/implanted(var/mob/source) + return TRUE + +/obj/item/weapon/implant/proc/can_implant(mob/M, mob/user, var/target_zone) + var/mob/living/carbon/human/H = M + if(istype(H) && !H.get_organ(target_zone)) + to_chat(user, "\The [M] is missing that body part.") + return FALSE + return TRUE + +/obj/item/weapon/implant/proc/implant_in_mob(mob/M, var/target_zone) + if (ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/affected = H.get_organ(target_zone) + if(affected) + affected.implants += src + part = affected + + BITSET(H.hud_updateflag, IMPLOYAL_HUD) + + forceMove(M) + imp_in = M + implanted = 1 + implanted(M) + + return TRUE + +/obj/item/weapon/implant/proc/removed(mob/source) + imp_in = null + if(part) + part.implants -= src + part = null + implanted = 0 + +//Called in surgery when incision is retracted open / ribs are opened - basically before you can take implant out +/obj/item/weapon/implant/proc/exposed() + return + +/obj/item/weapon/implant/proc/get_data() + return "No information available" + +/obj/item/weapon/implant/interact(user) + var/datum/browser/popup = new(user, capitalize(name), capitalize(name), 300, 700, src) + var/dat = get_data() + if(malfunction) + popup.title = "??? implant" + dat = stars(dat,10) + popup.set_content(dat) + popup.open() + +/obj/item/weapon/implant/proc/islegal() + return FALSE + +/obj/item/weapon/implant/proc/meltdown() //breaks it down, making implant unrecongizible + to_chat(imp_in, "You feel something melting inside [part ? "your [part.name]" : "you"]!") + if (part) + part.take_damage(burn = 15, used_weapon = "Electronics meltdown") + else + var/mob/living/M = imp_in + M.apply_damage(15,BURN) + name = "melted implant" + desc = "Charred circuit in melted plastic case. Wonder what that used to be..." + icon_state = "implant_melted" + malfunction = MALFUNCTION_PERMANENT + +/obj/item/weapon/implant/Destroy() + if(part) + part.implants.Remove(src) + return ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implantcase.dm b/code/game/objects/items/weapons/implants/implantcase.dm new file mode 100644 index 00000000..04a951b8 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implantcase.dm @@ -0,0 +1,73 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/obj/item/weapon/implantcase + name = "glass case" + desc = "A case containing an implant." + icon = 'icons/obj/items.dmi' + icon_state = "implantcase-0" + item_state = "implantcase" + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_TINY + var/obj/item/weapon/implant/imp = null + +/obj/item/weapon/implantcase/New() + if(ispath(imp)) + imp = new imp(src) + update_description() + ..() + update_icon() + +/obj/item/weapon/implantcase/proc/update_description() + if (imp) + desc = "A case containing \a [imp]." + origin_tech = imp.origin_tech + else + desc = "A case for implants." + origin_tech.Cut() + +/obj/item/weapon/implantcase/update_icon() + if (imp) + icon_state = "implantcase-[imp.implant_color]" + else + icon_state = "implantcase-0" + return + +/obj/item/weapon/implantcase/attackby(obj/item/weapon/I, mob/user) + if (istype(I, /obj/item/weapon/pen)) + var/t = input(user, "What would you like the label to be?", src.name, null) + if (user.get_active_hand() != I) + return + if((!in_range(src, usr) && loc != user)) + return + t = sanitizeSafe(t, MAX_NAME_LEN) + if(t) + SetName("glass case - '[t]'") + desc = "A case containing \a [t] implant." + else + SetName(initial(name)) + desc = "A case containing an implant." + else if(istype(I, /obj/item/weapon/reagent_containers/syringe)) + if(istype(imp,/obj/item/weapon/implant/chem)) + imp.attackby(I,user) + else if (istype(I, /obj/item/weapon/implanter)) + var/obj/item/weapon/implanter/M = I + if (M.imp && !imp && !M.imp.implanted) + M.imp.forceMove(src) + imp = M.imp + M.imp = null + else if (imp && !M.imp) + imp.forceMove(M) + M.imp = src.imp + imp = null + update_description() + update_icon() + M.update_icon() + else if (istype(I, /obj/item/weapon/implant)) + to_chat(usr, "You slide \the [I] into \the [src].") + user.drop_from_inventory(I,src) + imp = I + update_description() + update_icon() + else + return ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implantchair.dm b/code/game/objects/items/weapons/implants/implantchair.dm new file mode 100644 index 00000000..4925202d --- /dev/null +++ b/code/game/objects/items/weapons/implants/implantchair.dm @@ -0,0 +1,172 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/obj/machinery/implantchair + name = "loyalty implanter" + desc = "Used to implant occupants with loyalty implants." + icon = 'icons/obj/machines/implantchair.dmi' + icon_state = "implantchair" + density = 1 + opacity = 0 + anchored = 1 + + var/ready = 1 + var/malfunction = 0 + var/list/obj/item/weapon/implant/loyalty/implant_list = list() + var/max_implants = 5 + var/injection_cooldown = 600 + var/replenish_cooldown = 6000 + var/replenishing = 0 + var/mob/living/carbon/occupant = null + var/injecting = 0 + + proc + go_out() + put_mob(mob/living/carbon/M as mob) + implant(var/mob/M) + add_implants() + + + New() + ..() + add_implants() + + + attack_hand(mob/user as mob) + user.set_machine(src) + var/health_text = "" + if(src.occupant) + if(src.occupant.health <= -100) + health_text = "Dead" + else if(src.occupant.health < 0) + health_text = "[round(src.occupant.health,0.1)]" + else + health_text = "[round(src.occupant.health,0.1)]" + + var/dat ="Implanter Status
            " + + dat +="Current occupant: [src.occupant ? "
            Name: [src.occupant]
            Health: [health_text]
            " : "None"]
            " + dat += "Implants: [src.implant_list.len ? "[implant_list.len]" : "Replenish"]
            " + if(src.occupant) + dat += "[src.ready ? "Implant" : "Recharging"]
            " + user.set_machine(src) + user << browse(dat, "window=implant") + onclose(user, "implant") + + + Topic(href, href_list) + if((get_dist(src, usr) <= 1) || istype(usr, /mob/living/silicon/ai)) + if(href_list["implant"]) + if(src.occupant) + injecting = 1 + go_out() + ready = 0 + spawn(injection_cooldown) + ready = 1 + + if(href_list["replenish"]) + ready = 0 + spawn(replenish_cooldown) + add_implants() + ready = 1 + + src.updateUsrDialog() + src.add_fingerprint(usr) + return + + + attackby(var/obj/item/weapon/G as obj, var/mob/user as mob) + if(istype(G, /obj/item/grab)) + var/obj/item/grab/grab = G + if(!ismob(grab.affecting)) + return + for(var/mob/living/carbon/slime/M in range(1,G:affecting)) + if(M.Victim == grab.affecting) + to_chat(usr, "[grab.affecting:name] will not fit into the [src.name] because they have a slime latched onto their head.") + return + var/mob/M = G:affecting + if(put_mob(M)) + qdel(G) + src.updateUsrDialog() + return + + + go_out(var/mob/M) + if(!( src.occupant )) + return + if(M == occupant) // so that the guy inside can't eject himself -Agouri + return + if (src.occupant.client) + src.occupant.client.eye = src.occupant.client.mob + src.occupant.client.perspective = MOB_PERSPECTIVE + src.occupant.loc = src.loc + if(injecting) + implant(src.occupant) + injecting = 0 + src.occupant = null + icon_state = "implantchair" + return + + + put_mob(mob/living/carbon/M as mob) + if(!iscarbon(M)) + to_chat(usr, "\The [src] cannot hold this!") + return + if(src.occupant) + to_chat(usr, "\The [src] is already occupied!") + return + if(M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.stop_pulling() + M.loc = src + src.occupant = M + src.add_fingerprint(usr) + icon_state = "implantchair_on" + return 1 + + + implant(var/mob/M) + if (!istype(M, /mob/living/carbon)) + return + if(!implant_list.len) return + for(var/obj/item/weapon/implant/loyalty/imp in implant_list) + if(!imp) continue + if(istype(imp, /obj/item/weapon/implant/loyalty)) + for (var/mob/O in viewers(M, null)) + O.show_message("\The [M] has been implanted by \the [src].", 1) + + if(imp.implanted(M)) + imp.loc = M + imp.imp_in = M + imp.implanted = 1 + implant_list -= imp + break + return + + + add_implants() + for(var/i=0, iThere is no implant to remove.
            ") + return + imp.forceMove(get_turf(src)) + usr.put_in_hands(imp) + to_chat(usr, "You remove \the [imp] from \the [src].") + name = "implanter" + imp = null + update_icon() + return + else + to_chat(usr, "You cannot do this in your current condition.") + +/obj/item/weapon/implanter/proc/can_use() + + if(!ismob(loc)) + return 0 + + var/mob/M = loc + + if(M.incapacitated()) + return 0 + if((src in M.contents) || (istype(loc, /turf) && in_range(src, M))) + return 1 + return 0 + +/obj/item/weapon/implanter/attackby(obj/item/weapon/I, mob/user) + if(!imp && istype(I, /obj/item/weapon/implant)) + to_chat(usr, "You slide \the [I] into \the [src].") + user.drop_from_inventory(I,src) + imp = I + update_icon() + else + ..() + +/obj/item/weapon/implanter/attack(mob/M as mob, mob/user as mob) + if (!istype(M, /mob/living/carbon)) + return + if (user && src.imp) + M.visible_message("[user] is attemping to implant [M].") + + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + user.do_attack_animation(M) + + var/target_zone = user.zone_sel.selecting + if(src.imp.can_implant(M, user, target_zone)) + var/imp_name = imp.name + + if(do_after(user, 50, M) && src.imp.implant_in_mob(M, target_zone)) + M.visible_message("[M] has been implanted by [user].") + admin_attack_log(user, M, "Implanted using \the [src] ([imp_name])", "Implanted with \the [src] ([imp_name])", "used an implanter, \the [src] ([imp_name]), on") + + src.imp = null + update_icon() + + return \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implantpad.dm b/code/game/objects/items/weapons/implants/implantpad.dm new file mode 100644 index 00000000..31105188 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implantpad.dm @@ -0,0 +1,62 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/obj/item/weapon/implantpad + name = "implant pad" + desc = "Used to reprogramm implants." + icon = 'icons/obj/items.dmi' + icon_state = "implantpad-0" + item_state = "electronic" + w_class = ITEM_SIZE_SMALL + var/obj/item/weapon/implant/imp + +/obj/item/weapon/implantpad/update_icon() + if (imp) + icon_state = "implantpad-1" + else + icon_state = "implantpad-0" + +/obj/item/weapon/implantpad/attack_hand(mob/user) + if ((imp && (user.l_hand == src || user.r_hand == src))) + user.put_in_active_hand(imp) + imp.add_fingerprint(user) + add_fingerprint(user) + + imp = null + update_icon() + else + return ..() + +/obj/item/weapon/implantpad/attackby(obj/item/I, mob/user) + ..() + if(istype(I, /obj/item/weapon/implantcase)) + var/obj/item/weapon/implantcase/C = I + if(!imp && C.imp) + C.imp.forceMove(src) + imp = C.imp + C.imp = null + else if (imp && !C.imp) + imp.forceMove(C) + C.imp = imp + imp = null + C.update_icon() + else if(istype(I, /obj/item/weapon/implanter)) + var/obj/item/weapon/implanter/C = I + if(!imp && C.imp) + C.imp.forceMove(src) + imp = C.imp + C.imp = null + else if (imp && !C.imp) + imp.forceMove(C) + C.imp = imp + imp = null + C.update_icon() + else if(istype(I, /obj/item/weapon/implant)) + imp = I + user.drop_from_inventory(I,src) + update_icon() + +/obj/item/weapon/implantpad/attack_self(mob/user) + if (imp) + imp.interact(user) + else + to_chat(user,"There's no implant loaded in \the [src].") \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/adrenaline.dm b/code/game/objects/items/weapons/implants/implants/adrenaline.dm new file mode 100644 index 00000000..fed80bb9 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/adrenaline.dm @@ -0,0 +1,39 @@ +/obj/item/weapon/implant/adrenalin + name = "adrenalin" + desc = "Removes all stuns and knockdowns." + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 2, TECH_ILLEGAL = 2) + var/uses + +/obj/item/weapon/implant/adrenalin/get_data() + return {" + Implant Specifications:
            + Name: Cybersun Industries Adrenalin Implant
            + Life: Five days.
            + Important Notes: Illegal
            +
            + Implant Details: Subjects injected with implant can activate a massive injection of adrenalin.
            + Function: Contains nanobots to stimulate body to mass-produce Adrenalin.
            + Special Features: Will prevent and cure most forms of brainwashing.
            + Integrity: Implant can only be used three times before the nanobots are depleted."} + +/obj/item/weapon/implant/adrenalin/trigger(emote, mob/source) + if (src.uses < 1) return 0 + if (emote == "pale") + src.uses-- + to_chat(source, "You feel a sudden surge of energy!") + source.SetStunned(0) + source.SetWeakened(0) + source.SetParalysis(0) + +/obj/item/weapon/implant/adrenalin/implanted(mob/source) + source.mind.store_memory("A implant can be activated by using the pale emote, say *pale to attempt to activate.", 0, 0) + to_chat(source, "The implanted freedom implant can be activated by using the pale emote, say *pale to attempt to activate.") + return TRUE + +/obj/item/weapon/implanter/adrenalin + name = "implanter-adrenalin" + imp = /obj/item/weapon/implant/adrenalin + +/obj/item/weapon/implantcase/adrenalin + name = "glass case - 'adrenalin'" + imp = /obj/item/weapon/implant/adrenalin \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/chem.dm b/code/game/objects/items/weapons/implants/implants/chem.dm new file mode 100644 index 00000000..6bc6e624 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/chem.dm @@ -0,0 +1,63 @@ +/obj/item/weapon/implant/chem + name = "chemical implant" + desc = "Injects things." + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 2) + known = 1 + +/obj/item/weapon/implant/chem/get_data() + return {" + Implant Specifications:
            + Name: Robust Corp MJ-420 Prisoner Management Implant
            + Life: Deactivates upon death but remains within the body.
            + Important Notes: Due to the system functioning off of nutrients in the implanted subject's body, the subject
            + will suffer from an increased appetite.

            +
            + Implant Details:
            + Function: Contains a small capsule that can contain various chemicals. Upon receiving a specially encoded signal
            + the implant releases the chemicals directly into the blood stream.
            + Special Features: + Micro-Capsule- Can be loaded with any sort of chemical agent via the common syringe and can hold 50 units.
            + Can only be loaded while still in its original case.
            + Integrity: Implant will last so long as the subject is alive. However, if the subject suffers from malnutrition,
            + the implant may become unstable and either pre-maturely inject the subject or simply break."} + +/obj/item/weapon/implant/chem/New() + ..() + create_reagents(50) + +/obj/item/weapon/implant/chem/activate(var/amount) + if((!amount) || (!iscarbon(imp_in))) return 0 + var/mob/living/carbon/R = imp_in + reagents.trans_to_mob(R, amount, CHEM_BLOOD) + to_chat(R, "You hear a faint *beep*.") + +/obj/item/weapon/implant/chem/attackby(obj/item/weapon/I, mob/user) + if(istype(I, /obj/item/weapon/reagent_containers/syringe)) + if(reagents.total_volume >= reagents.maximum_volume) + to_chat(user, "\The [src] is full.") + else + if(do_after(user,5,src)) + I.reagents.trans_to_obj(src, 5) + to_chat(user, "You inject 5 units of the solution. The syringe now contains [I.reagents.total_volume] units.") + else + ..() + +/obj/item/weapon/implant/chem/emp_act(severity) + if (malfunction) + return + malfunction = MALFUNCTION_TEMPORARY + + switch(severity) + if(1) + if(prob(60)) + activate(20) + if(2) + if(prob(30)) + activate(5) + + spawn(20) + malfunction = 0 + +/obj/item/weapon/implantcase/chem + name = "glass case - 'chem'" + imp = /obj/item/weapon/implant/chem \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/compressed.dm b/code/game/objects/items/weapons/implants/implants/compressed.dm new file mode 100644 index 00000000..7e4bef37 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/compressed.dm @@ -0,0 +1,102 @@ +/obj/item/weapon/implant/compressed + name = "compressed matter implant" + desc = "Based on compressed matter technology, can store a single item." + icon_state = "implant_evil" + origin_tech = list(TECH_MATERIAL = 4, TECH_BIO = 2, TECH_ILLEGAL = 2) + var/activation_emote + var/obj/item/scanned + +/obj/item/weapon/implant/compressed/get_data() + var/dat = {" + Implant Specifications:
            + Name: [GLOB.using_map.company_name] \"Profit Margin\" Class Employee Lifesign Sensor
            + Life: Activates upon death.
            + Important Notes: Alerts crew to crewmember death.
            +
            + Implant Details:
            + Function: Contains a compact radio signaler that triggers when the host's lifesigns cease.
            + Special Features: Alerts crew to crewmember death.
            +Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} + return dat + +/obj/item/weapon/implant/compressed/trigger(emote, mob/source) + if (src.scanned == null) + return 0 + + if (emote == src.activation_emote) + to_chat(source, "The air glows as \the [src.scanned.name] uncompresses.") + activate() + +/obj/item/weapon/implant/compressed/activate() + var/turf/T = get_turf(src) + if (imp_in) + imp_in.put_in_hands(scanned) + else + scanned.forceMove(T) + qdel(src) + +/obj/item/weapon/implant/compressed/implanted(mob/source) + src.activation_emote = input("Choose activation emote:") in list("blink", "blink_r", "eyebrow", "chuckle", "twitch_v", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink") + if (source.mind) + source.mind.store_memory("Compressed matter implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.", 0, 0) + to_chat(source, "The implanted compressed matter implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.") + return TRUE + +/obj/item/weapon/implanter/compressed + name = "implanter (C)" + icon_state = "cimplanter1" + desc = "The matter compressor safety is on." + var/safe = 1 + imp = /obj/item/weapon/implant/compressed + +/obj/item/weapon/implanter/compressed/update_icon() + if (imp) + var/obj/item/weapon/implant/compressed/c = imp + if(!c.scanned) + icon_state = "cimplanter1" + else + icon_state = "cimplanter2" + else + icon_state = "cimplanter0" + return + +/obj/item/weapon/implanter/compressed/attack(mob/M as mob, mob/user as mob) + var/obj/item/weapon/implant/compressed/c = imp + if (!c) return + if (c.scanned == null) + to_chat(user, "Please compress an object with the implanter first.") + return + ..() + +/obj/item/weapon/implanter/compressed/afterattack(atom/A, mob/user as mob, proximity) + if(!proximity) + return + if(istype(A,/obj/item) && imp) + var/obj/item/weapon/implant/compressed/c = imp + if (c.scanned) + if (!istype(A,/obj/item/weapon/storage)) + to_chat(user, "Something is already compressed inside the implant!") + return + else if(safe) + if (!istype(A,/obj/item/weapon/storage)) + to_chat(user, "The matter compressor safeties prevent you from doing that.") + return + c.scanned = A + if(istype(A.loc,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = A.loc + H.remove_from_mob(A) + else if(istype(A.loc,/obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = A.loc + S.remove_from_storage(A) + A.loc.contents.Remove(A) + safe = 2 + desc = "It currently contains some matter." + update_icon() + +/obj/item/weapon/implanter/compressed/attack_self(var/mob/user) + if(!imp || safe == 2) + return ..() + + safe = !safe + to_chat(user, "You [safe ? "enable" : "disable"] the matter compressor safety.") + src.desc = "The matter compressor safety is [safe ? "on" : "off"]." \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/death_alarm.dm b/code/game/objects/items/weapons/implants/implants/death_alarm.dm new file mode 100644 index 00000000..8a7c896f --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/death_alarm.dm @@ -0,0 +1,77 @@ +/obj/item/weapon/implant/death_alarm + name = "death alarm implant" + desc = "An alarm which monitors host vital signs and transmits a radio message upon death." + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 2, TECH_DATA = 1) + known = 1 + var/mobname = "Will Robinson" + +/obj/item/weapon/implant/death_alarm/get_data() + return {" + Implant Specifications:
            + Name: [GLOB.using_map.company_name] \"Profit Margin\" Class Employee Lifesign Sensor
            + Life: Activates upon death.
            + Important Notes: Alerts crew to crewmember death.
            +
            + Implant Details:
            + Function: Contains a compact radio signaler that triggers when the host's lifesigns cease.
            + Special Features: Alerts crew to crewmember death.
            + Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} + +/obj/item/weapon/implant/death_alarm/islegal() + return TRUE + +/obj/item/weapon/implant/death_alarm/Process() + if (!implanted) return + var/mob/M = imp_in + + if(isnull(M)) // If the mob got gibbed + activate() + else if(M.stat == DEAD) + activate("death") + +/obj/item/weapon/implant/death_alarm/activate(var/cause) + var/mob/M = imp_in + var/area/t = get_area(M) + var/location = t.name + if (cause == "emp" && prob(50)) + location = pick(teleportlocs) + if(!t.requires_power) // We assume areas that don't use power are some sort of special zones + var/area/default = world.area + location = initial(default.name) + var/death_message = "[mobname] has died in [location]!" + if(!cause) + death_message = "[mobname] has died-zzzzt in-in-in..." + STOP_PROCESSING(SSobj, src) + + for(var/channel in list("Security", "Medical", "Command")) + GLOB.global_headset.autosay(death_message, "[mobname]'s Death Alarm", channel) + +/obj/item/weapon/implant/death_alarm/emp_act(severity) //for some reason alarms stop going off in case they are emp'd, even without this + if (malfunction) //so I'm just going to add a meltdown chance here + return + malfunction = MALFUNCTION_TEMPORARY + + if(prob(20)) + activate("emp") //let's shout that this dude is dead + if(severity == 1) + if(prob(40)) //small chance of obvious meltdown + meltdown() + else if (prob(60)) //but more likely it will just quietly die + malfunction = MALFUNCTION_PERMANENT + STOP_PROCESSING(SSobj, src) + + spawn(20) + malfunction = 0 + +/obj/item/weapon/implant/death_alarm/implanted(mob/source as mob) + mobname = source.real_name + START_PROCESSING(SSobj, src) + return TRUE + +/obj/item/weapon/implant/death_alarm/removed() + ..() + STOP_PROCESSING(SSobj, src) + +/obj/item/weapon/implantcase/death_alarm + name = "glass case - 'death alarm'" + imp = /obj/item/weapon/implant/death_alarm \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/explosive.dm b/code/game/objects/items/weapons/implants/implants/explosive.dm new file mode 100644 index 00000000..63940b7a --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/explosive.dm @@ -0,0 +1,185 @@ +//BS12 Explosive +/obj/item/weapon/implant/explosive + name = "explosive implant" + desc = "A military grade micro bio-explosive. Highly dangerous." + icon_state = "implant_evil" + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 2, TECH_ILLEGAL = 3) + var/elevel + var/phrase + var/code = 13 + var/frequency = 1443 + var/datum/radio_frequency/radio_connection + var/warning_message = "Tampering detected. Tampering detected." + +/obj/item/weapon/implant/explosive/get_data() + . = {" + Implant Specifications:
            + Name: Robust Corp RX-78 Intimidation Class Implant
            + Life: Activates upon codephrase.
            + Important Notes: Explodes
            +
            + Implant Details:
            + Function: Contains a compact, electrically detonated explosive that detonates upon receiving a specially encoded signal or upon host death.
            + Special Features: Explodes
            + Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} + if(!malfunction) + . += {" +
            Explosion yield mode:
            + [elevel ? elevel : "NONE SET"]
            + Activation phrase:
            + [phrase ? phrase : "NONE SET"]
            + Frequency:
            + - + - + [format_frequency(src.frequency)] + + + +
            + Code:
            + - + - + [src.code] + + + +
            + Tampering warning message:
            + This will be broadcasted on radio if implant is exposed during surgery.
            + [warning_message ? warning_message : "NONE SET"] + "} + +/obj/item/weapon/implant/explosive/Initialize() + . = ..() + GLOB.listening_objects += src + set_frequency(frequency) + +/obj/item/weapon/implant/explosive/Topic(href, href_list) + ..() + if (href_list["freq"]) + var/new_frequency = frequency + text2num(href_list["freq"]) + new_frequency = sanitize_frequency(new_frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) + set_frequency(new_frequency) + interact(usr) + if (href_list["code"]) + var/adj = text2num(href_list["code"]) + if(!adj) + code = input("Set radio activation code","Radio activation") as num + else + code += adj + code = Clamp(code,1,100) + interact(usr) + if (href_list["mode"]) + var/mod = input("Set explosion mode", "Explosion mode") as null|anything in list("Localized Limb", "Destroy Body", "Full Explosion") + if(mod) + elevel = mod + interact(usr) + if (href_list["msg"]) + var/msg = input("Set tampering message, or leave blank for no broadcasting.", "Anti-tampering", warning_message) as text|null + if(msg) + warning_message = msg + interact(usr) + if (href_list["phrase"]) + var/talk = input("Set activation phrase", "Audio activation", phrase) as text|null + if(talk) + phrase = sanitize_phrase(talk) + interact(usr) + +/obj/item/weapon/implant/explosive/receive_signal(datum/signal/signal) + if(signal && signal.encryption == code) + activate() + +/obj/item/weapon/implant/explosive/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) + +/obj/item/weapon/implant/explosive/hear_talk(mob/M as mob, msg) + hear(msg) + +/obj/item/weapon/implant/explosive/hear(var/msg) + if(!phrase) + return + if(findtext(sanitize_phrase(msg),phrase)) + activate() + qdel(src) + +/obj/item/weapon/implant/explosive/exposed() + if(warning_message) + GLOB.global_headset.autosay(warning_message, "Anti Tampering System") + +/obj/item/weapon/implant/explosive/proc/sanitize_phrase(phrase) + var/list/replacechars = list("'" = "","\"" = "",">" = "","<" = "","(" = "",")" = "") + return replace_characters(phrase, replacechars) + +/obj/item/weapon/implant/explosive/activate() + if (malfunction == MALFUNCTION_PERMANENT) + return + + var/turf/T = get_turf(src) + if(T) + T.hotspot_expose(3500,125) + + playsound(loc, 'sound/items/countdown.ogg', 75, 1, -3) + if(ismob(imp_in)) + imp_in.audible_message("Something beeps inside [imp_in][part ? "'s [part.name]" : ""]!") + message_admins("Explosive implant triggered in [imp_in] ([imp_in.key]). (JMP) ") + log_game("Explosive implant triggered in [imp_in] ([imp_in.key]).") + else + audible_message("[src] beeps omniously!") + message_admins("Explosive implant triggered in [T.loc]. (JMP) ") + log_game("Explosive implant triggered in [T.loc].") + + if(!elevel) + elevel = "Full Explosion" + switch(elevel) + if ("Localized Limb") + if (part) + if (istype(part,/obj/item/organ/external/chest) || \ + istype(part,/obj/item/organ/external/groin)) + part.take_damage(60, used_weapon = "Explosion") + else + part.droplimb(0,DROPLIMB_BLUNT) + explosion(T, -1, -1, 2, 3) + if ("Destroy Body") + explosion(T, -1, 0, 1, 6) + if(ismob(imp_in)) + imp_in.gib() + if ("Full Explosion") + explosion(T, 0, 1, 3, 6) + if(ismob(imp_in)) + imp_in.gib() + qdel(src) + +/obj/item/weapon/implant/explosive/implanted(mob/target) + if(!elevel) + elevel = alert("What sort of explosion would you prefer?", "Implant Intent", "Localized Limb", "Destroy Body", "Full Explosion") + if(!phrase) + phrase = sanitize_phrase(input("Choose activation phrase:") as text) + var/memo = "Explosive implant in [target] can be activated by saying something containing the phrase ''[phrase]'', say [phrase] to attempt to activate. It can also be triggered with a radio signal on frequency [format_frequency(src.frequency)] with code [code]." + usr.mind.store_memory(memo, 0, 0) + to_chat(usr, memo) + return TRUE + +/obj/item/weapon/implant/explosive/emp_act(severity) + if (malfunction) + return + malfunction = MALFUNCTION_TEMPORARY + switch (severity) + if (1) //strong EMP will melt implant either making it go off, or disarming it + if (prob(25)) + if (prob(50)) + activate() //50% chance of bye bye + else + meltdown() //50% chance of implant disarming + spawn (20) + malfunction = 0 + +/obj/item/weapon/implant/explosive/Destroy() + removed() + GLOB.listening_objects -= src + return ..() + +/obj/item/weapon/implanter/explosive + name = "implanter (E)" + imp = /obj/item/weapon/implant/explosive + +/obj/item/weapon/implantcase/explosive + name = "glass case - 'explosive'" + imp = /obj/item/weapon/implant/explosive \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/freedom.dm b/code/game/objects/items/weapons/implants/implants/freedom.dm new file mode 100644 index 00000000..0430f542 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/freedom.dm @@ -0,0 +1,59 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/obj/item/weapon/implant/freedom + name = "freedom implant" + desc = "Use this to escape from those evil Red Shirts." + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 2, TECH_ILLEGAL = 2) + implant_color = "r" + var/activation_emote + var/uses + +/obj/item/weapon/implant/freedom/get_data() + return {" + Implant Specifications:
            + Name: Freedom Beacon
            + Life: optimum 5 uses
            + Important Notes: Illegal
            +
            + Implant Details:
            + Function: Transmits a specialized cluster of signals to override handcuff locking + mechanisms
            + Special Features:
            + Neuro-Scan- Analyzes certain shadow signals in the nervous system
            + Integrity: The battery is extremely weak and commonly after injection its + life can drive down to only 1 use.
            + No Implant Specifics"} + +/obj/item/weapon/implant/freedom/New() + uses = rand(1, 5) + ..() + return + +/obj/item/weapon/implant/freedom/trigger(emote, mob/living/carbon/source as mob) + if (src.uses < 1) return 0 + if (emote == src.activation_emote) + if(remove_cuffs_and_unbuckle(source)) + src.uses-- + to_chat(source, "You feel a faint click.") + +/obj/item/weapon/implant/freedom/proc/remove_cuffs_and_unbuckle(mob/living/carbon/user) + if(!user.handcuffed) + return 0 + . = user.unEquip(user.handcuffed) + if(. && user.buckled && user.buckled.buckle_require_restraints) + user.buckled.unbuckle_mob() + return + +/obj/item/weapon/implant/freedom/implanted(mob/living/carbon/source) + src.activation_emote = input("Choose activation emote:") in list("blink", "blink_r", "eyebrow", "chuckle", "twitch_v", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink") + source.mind.store_memory("Freedom implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.", 0, 0) + to_chat(source, "The implanted freedom implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.") + return TRUE + +/obj/item/weapon/implanter/freedom + name = "implanter (F)" + imp = /obj/item/weapon/implant/freedom + +/obj/item/weapon/implantcase/freedom + name = "glass case - 'freedom'" + imp = /obj/item/weapon/implant/freedom \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/imprinting.dm b/code/game/objects/items/weapons/implants/implants/imprinting.dm new file mode 100644 index 00000000..b258e45d --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/imprinting.dm @@ -0,0 +1,89 @@ +/obj/item/weapon/implant/imprinting + name = "imprinting implant" + desc = "Latest word in training your peons." + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 2, TECH_DATA = 3) + var/list/instructions = list("Do your job.", "Respect your superiours.", "Wash you hands after using the toilet.") + var/brainwashing = 0 + var/last_reminder + +/obj/item/weapon/implant/imprinting/get_data() + . = {" + Implant Specifications:
            + Name: NanoTrasen BB-56 "Educator" Employee Assistance Implant
            + Life: 1 year.
            +
            + Function: Adjusts itself to host's brainwaves, and presents supplied instructions as their 'inner voice' for less intrusive reminding. It will transmit them every 5 minutes in non-obtrusive manner.
            + Special Features: Do NOT implant if subject is under effect of any mind-altering drugs. + It carries risk of over-tuning, making subject unable to question the suggestions received, treating them as beliefs they feel strongly about.
            + It is HIGLY ILLEGAL and NanoTrasen does NOT endorse use of this device in such way. + Any amount of Nanotrasen brand "Mind-Breaker"(TM) present in bloodstream will trigger this side-effect.
            "} + . += "
            Instructions:
            " + for(var/i = 1 to instructions.len) + . += "- [instructions[i]] Edit Remove
            " + . += "Add" + +/obj/item/weapon/implant/imprinting/Topic(href, href_list) + ..() + if (href_list["add"]) + var/mod = sanitize(input("Add an instruction", "Instructions") as text|null) + if(mod) + instructions += mod + interact(usr) + if (href_list["edit"]) + var/idx = text2num(href_list["edit"]) + var/mod = sanitize(input("Edit the instruction", "Instruction Editing", instructions[idx]) as text|null) + if(mod) + instructions[idx] = mod + interact(usr) + if (href_list["del"]) + instructions -= instructions[text2num(href_list["del"])] + interact(usr) + +/obj/item/weapon/implant/imprinting/implanted(mob/M) + var/mob/living/carbon/human/H = M + if(!istype(H)) + return FALSE + if(H.reagents.has_reagent(/datum/reagent/mindbreaker)) + brainwashing = 1 + var/msg + if(brainwashing) + msg += "The fog in your head clears, and you remember some important things. You hold following things as deep convictions, almost like synthetics' laws:
            " + else + msg += "You hear an annoying voice in the back of your head. The things it keeps reminding you of:
            " + for(var/thing in instructions) + msg += "- [thing]
            " + to_chat(M, msg) + if(M.mind) + M.mind.store_memory("
            [msg]") + + START_PROCESSING(SSobj, src) + return TRUE + +/obj/item/weapon/implant/imprinting/Process() + if(world.time < last_reminder + 5 MINUTES) + return + last_reminder = world.time + var/instruction = pick(instructions) + if(brainwashing) + instruction = "You recall one of your beliefs: \"[instruction]\"" + else + instruction = "You remember suddenly: \"[instruction]\"" + to_chat(imp_in, instruction) + +/obj/item/weapon/implant/imprinting/removed() + if(brainwashing) + to_chat(imp_in,"You are no longer so sure of those beliefs you've had...") + ..() + STOP_PROCESSING(SSobj, src) + +/obj/item/weapon/implant/imprinting/Destroy() + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/item/weapon/implanter/imprinting + name = "imprinting implanter" + imp = /obj/item/weapon/implant/imprinting + +/obj/item/weapon/implantcase/imprinting + name = "glass case - 'imprinting'" + imp = /obj/item/weapon/implant/imprinting \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/loyalty.dm b/code/game/objects/items/weapons/implants/implants/loyalty.dm new file mode 100644 index 00000000..d45e8085 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/loyalty.dm @@ -0,0 +1,37 @@ +/obj/item/weapon/implant/loyalty + name = "loyalty implant" + desc = "Makes you loyal or such." + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 2, TECH_ILLEGAL = 3) + known = 1 + +/obj/item/weapon/implant/loyalty/get_data() + return {" + Implant Specifications:
            + Name: [GLOB.using_map.company_name] Employee Management Implant
            + Life: Ten years.
            + Important Notes: Personnel injected with this device tend to be much more loyal to the company.
            +
            + Implant Details:
            + Function: Contains a small pod of nanobots that manipulate the host's mental functions.
            + Special Features: Will prevent and cure most forms of brainwashing.
            + Integrity: Implant will last so long as the nanobots are inside the bloodstream."} + +/obj/item/weapon/implant/loyalty/implanted(mob/M) + if(!istype(M, /mob/living/carbon/human)) return FALSE + var/mob/living/carbon/human/H = M + var/datum/antagonist/antag_data = get_antag_data(H.mind.special_role) + if(antag_data && (antag_data.flags & ANTAG_IMPLANT_IMMUNE)) + H.visible_message("[H] seems to resist the implant!", "You feel the corporate tendrils of [GLOB.using_map.company_name] try to invade your mind!") + return FALSE + else + clear_antag_roles(H.mind, 1) + to_chat(H, "You feel a surge of loyalty towards [GLOB.using_map.company_name].") + return TRUE + +/obj/item/weapon/implanter/loyalty + name = "implanter-loyalty" + imp = /obj/item/weapon/implant/loyalty + +/obj/item/weapon/implantcase/loyalty + name = "glass case - 'loyalty'" + imp = /obj/item/weapon/implant/loyalty \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/tracking.dm b/code/game/objects/items/weapons/implants/implants/tracking.dm new file mode 100644 index 00000000..9bd8ce72 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/tracking.dm @@ -0,0 +1,57 @@ +/obj/item/weapon/implant/tracking + name = "tracking implant" + desc = "Track with this." + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 2, TECH_BLUESPACE = 2) + known = 1 + var/id = 1 + +/obj/item/weapon/implant/tracking/get_data() + . = {"Implant Specifications:
            + Name: Tracking Beacon
            + Life: 10 minutes after death of host
            + Important Notes: None
            +
            + Implant Details:
            + Function: Continuously transmits low power signal. Useful for tracking.
            + Special Features:
            + Neuro-Safe- Specialized shell absorbs excess voltages self-destructing the chip if + a malfunction occurs thereby securing safety of subject. The implant will melt and + disintegrate into bio-safe elements.
            + Integrity: Gradient creates slight risk of being overcharged and frying the + circuitry. As a result neurotoxins can cause massive damage.
            "} + if(!malfunction) + .+= {"ID (1-100):
            + - + - [id] + + + +
            "} + +/obj/item/weapon/implant/tracking/Topic(href, href_list) + ..() + if (href_list["tracking_id"]) + id = Clamp(id+text2num(href_list["tracking_id"]), 1, 100) + interact(usr) + +/obj/item/weapon/implant/tracking/islegal() + return TRUE + +/obj/item/weapon/implant/tracking/emp_act(severity) + if (malfunction) //no, dawg, you can't malfunction while you are malfunctioning + return + malfunction = MALFUNCTION_TEMPORARY + + var/delay = 20 + switch(severity) + if(1) + if(prob(60)) + removed() + qdel(src) + if(2) + delay = rand(5,15) * 600 //from 5 to 15 minutes of free time + + spawn(delay) + malfunction = 0 + +/obj/item/weapon/implantcase/tracking + name = "glass case - 'tracking'" + imp = /obj/item/weapon/implant/tracking \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/uplink.dm b/code/game/objects/items/weapons/implants/implants/uplink.dm new file mode 100644 index 00000000..2ba08e41 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/uplink.dm @@ -0,0 +1,26 @@ +/obj/item/weapon/implant/uplink + name = "uplink" + desc = "Summon things." + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 2, TECH_ILLEGAL = 3) + var/activation_emote + +/obj/item/weapon/implant/uplink/New(var/loc, var/amount) + amount = amount || IMPLANT_TELECRYSTAL_AMOUNT(DEFAULT_TELECRYSTAL_AMOUNT) + hidden_uplink = new(src, telecrystals = amount) + ..() + +/obj/item/weapon/implant/uplink/implanted(mob/source) + var/emote_options = list("blink", "blink_r", "eyebrow", "chuckle", "twitch_v", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink") + activation_emote = source.client ? (input(source, "Choose activation emote:", "Uplink Implant Setup") in emote_options) : emote_options[1] + source.mind.store_memory("Uplink implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.", 0, 0) + to_chat(source, "The implanted uplink implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.") + hidden_uplink.uplink_owner = source.mind + return TRUE + +/obj/item/weapon/implant/uplink/trigger(emote, mob/source as mob) + if(hidden_uplink && usr == source) // Let's not have another people activate our uplink + hidden_uplink.check_trigger(source, emote, activation_emote) + +/obj/item/weapon/implanter/uplink + name = "implanter (U)" + imp = /obj/item/weapon/implant/uplink diff --git a/code/game/objects/items/weapons/improvised_components.dm b/code/game/objects/items/weapons/improvised_components.dm new file mode 100644 index 00000000..cec25807 --- /dev/null +++ b/code/game/objects/items/weapons/improvised_components.dm @@ -0,0 +1,72 @@ +/obj/item/weapon/material/butterflyconstruction + name = "unfinished concealed knife" + desc = "An unfinished concealed knife, it looks like the screws need to be tightened." + icon = 'icons/obj/buildingobject.dmi' + icon_state = "butterflystep1" + force_divisor = 0.1 + thrown_force_divisor = 0.1 + +/obj/item/weapon/material/butterflyconstruction/attackby(obj/item/W as obj, mob/user as mob) + if(isScrewdriver(W)) + to_chat(user, "You finish the concealed blade weapon.") + user.put_in_hands(new /obj/item/weapon/material/butterfly(user.loc, material.name)) + qdel(src) + return + +/obj/item/weapon/material/butterflyblade + name = "knife blade" + desc = "A knife blade. Unusable as a weapon without a grip." + icon = 'icons/obj/buildingobject.dmi' + icon_state = "butterfly2" + force_divisor = 0.1 + thrown_force_divisor = 0.1 + +/obj/item/weapon/material/butterflyhandle + name = "concealed knife grip" + desc = "A plasteel grip with screw fittings for a blade." + icon = 'icons/obj/buildingobject.dmi' + icon_state = "butterfly1" + force_divisor = 0.1 + thrown_force_divisor = 0.1 + +/obj/item/weapon/material/butterflyhandle/attackby(obj/item/W as obj, mob/user as mob) + + if(istype(W,/obj/item/weapon/material/butterflyblade)) + var/obj/item/weapon/material/butterflyblade/B = W + to_chat(user, "You attach the two concealed blade parts.") + var/finished = new /obj/item/weapon/material/butterflyconstruction(user.loc, B.material.name) + qdel(W) + qdel(src) + user.put_in_hands(finished) + return + +/obj/item/weapon/material/wirerod + name = "wired rod" + desc = "A rod with some wire wrapped around the top. It'd be easy to attach something to the top bit." + icon_state = "wiredrod" + item_state = "rods" + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 8 + throwforce = 10 + w_class = ITEM_SIZE_NORMAL + attack_verb = list("hit", "bludgeoned", "whacked", "bonked") + force_divisor = 0.1 + thrown_force_divisor = 0.1 + +/obj/item/weapon/material/wirerod/attackby(var/obj/item/I, mob/user as mob) + ..() + var/obj/item/finished + if(istype(I, /obj/item/weapon/material/shard) || istype(I, /obj/item/weapon/material/butterflyblade)) + var/obj/item/weapon/material/tmp_shard = I + finished = new /obj/item/weapon/material/twohanded/spear(get_turf(user), tmp_shard.material.name) + to_chat(user, "You fasten \the [I] to the top of the rod with the cable.") + else if(isWirecutter(I)) + finished = new /obj/item/weapon/melee/baton/cattleprod(get_turf(user)) + to_chat(user, "You fasten the wirecutters to the top of the rod with the cable, prongs outward.") + if(finished) + user.drop_from_inventory(src) + user.drop_from_inventory(I) + qdel(I) + qdel(src) + user.put_in_hands(finished) + update_icon(user) diff --git a/code/game/objects/items/weapons/janitor_sign.dm b/code/game/objects/items/weapons/janitor_sign.dm new file mode 100644 index 00000000..fd84f037 --- /dev/null +++ b/code/game/objects/items/weapons/janitor_sign.dm @@ -0,0 +1,16 @@ +/obj/item/weapon/caution + desc = "Caution! Wet Floor!" + name = "wet floor sign" + icon = 'icons/obj/janitor.dmi' + icon_state = "caution" + force = 1.0 + throwforce = 3.0 + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_SMALL + attack_verb = list("warned", "cautioned", "smashed") + +/obj/item/weapon/caution/cone + desc = "This cone is trying to warn you of something!" + name = "warning cone" + icon_state = "cone" \ No newline at end of file diff --git a/code/game/objects/items/weapons/material/ashtray.dm b/code/game/objects/items/weapons/material/ashtray.dm new file mode 100644 index 00000000..a0c9d739 --- /dev/null +++ b/code/game/objects/items/weapons/material/ashtray.dm @@ -0,0 +1,76 @@ +/obj/item/weapon/material/ashtray + name = "ashtray" + desc = "A thing to keep your butts in." + icon = 'icons/obj/objects.dmi' + icon_state = "ashtray" + force_divisor = 0.1 + thrown_force_divisor = 0.1 + randpixel = 5 + var/max_butts = 10 + +/obj/item/weapon/material/ashtray/examine(mob/user) + ..() + if(material) + to_chat(user, "It's made of [material.display_name].") + if(contents.len >= max_butts) + to_chat(user, "It's full.") + else if(contents.len) + to_chat(user, "It has [contents.len] cig butts in it.") + +/obj/item/weapon/material/ashtray/update_icon() + overlays.Cut() + if (contents.len == max_butts) + overlays |= image('icons/obj/objects.dmi',"ashtray_full") + else if (contents.len >= max_butts/2) + overlays |= image('icons/obj/objects.dmi',"ashtray_half") + +/obj/item/weapon/material/ashtray/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (health <= 0) + return + if (istype(W,/obj/item/weapon/cigbutt) || istype(W,/obj/item/clothing/mask/smokable/cigarette) || istype(W, /obj/item/weapon/flame/match)) + if (contents.len >= max_butts) + to_chat(user, "\The [src] is full.") + return + + if (istype(W,/obj/item/clothing/mask/smokable/cigarette)) + var/obj/item/clothing/mask/smokable/cigarette/cig = W + if (cig.lit == 1) + visible_message("[user] crushes [cig] in [src], putting it out.") + W = cig.die(1) + else if (cig.lit == 0) + to_chat(user, "You place [cig] in [src] without even smoking it. Why would you do that?") + + user.remove_from_mob(W, src) + + visible_message("[user] places [W] in [src].") + user.update_inv_l_hand() + user.update_inv_r_hand() + add_fingerprint(user) + update_icon() + else + ..() + health = max(0,health - W.force) + if (health < 1) + shatter() + +/obj/item/weapon/material/ashtray/throw_impact(atom/hit_atom) + if (health > 0) + health = max(0,health - 3) + if (contents.len) + visible_message("\The [src] slams into [hit_atom], spilling its contents!") + for (var/obj/O in contents) + O.dropInto(loc) + if (health < 1) + shatter() + return + update_icon() + return ..() + +/obj/item/weapon/material/ashtray/plastic/New(var/newloc) + ..(newloc, "plastic") + +/obj/item/weapon/material/ashtray/bronze/New(var/newloc) + ..(newloc, "bronze") + +/obj/item/weapon/material/ashtray/glass/New(var/newloc) + ..(newloc, "glass") diff --git a/code/game/objects/items/weapons/material/bats.dm b/code/game/objects/items/weapons/material/bats.dm new file mode 100644 index 00000000..f4178dca --- /dev/null +++ b/code/game/objects/items/weapons/material/bats.dm @@ -0,0 +1,30 @@ +/obj/item/weapon/material/twohanded/baseballbat + name = "bat" + desc = "HOME RUN!" + icon_state = "metalbat0" + base_icon = "metalbat" + item_state = "metalbat" + w_class = ITEM_SIZE_LARGE + throwforce = 7 + attack_verb = list("smashed", "beaten", "slammed", "smacked", "struck", "battered", "bonked") + hitsound = 'sound/weapons/genhit3.ogg' + default_material = "wood" + force_divisor = 1.1 // 22 when wielded with weight 20 (steel) + unwielded_force_divisor = 0.7 // 15 when unwielded based on above. + slot_flags = SLOT_BACK + +//Predefined materials go here. +/obj/item/weapon/material/twohanded/baseballbat/metal/New(var/newloc) + ..(newloc,"steel") + +/obj/item/weapon/material/twohanded/baseballbat/uranium/New(var/newloc) + ..(newloc,"uranium") + +/obj/item/weapon/material/twohanded/baseballbat/gold/New(var/newloc) + ..(newloc,"gold") + +/obj/item/weapon/material/twohanded/baseballbat/platinum/New(var/newloc) + ..(newloc,"platinum") + +/obj/item/weapon/material/twohanded/baseballbat/diamond/New(var/newloc) + ..(newloc,"diamond") \ No newline at end of file diff --git a/code/game/objects/items/weapons/material/kitchen.dm b/code/game/objects/items/weapons/material/kitchen.dm new file mode 100644 index 00000000..9963e782 --- /dev/null +++ b/code/game/objects/items/weapons/material/kitchen.dm @@ -0,0 +1,138 @@ +/obj/item/weapon/material/kitchen + icon = 'icons/obj/kitchen.dmi' + +/* + * Utensils + */ +/obj/item/weapon/material/kitchen/utensil + w_class = ITEM_SIZE_TINY + thrown_force_divisor = 1 + origin_tech = list(TECH_MATERIAL = 1) + attack_verb = list("attacked", "stabbed", "poked") + sharp = 0 + edge = 0 + force_divisor = 0.1 // 6 when wielded with hardness 60 (steel) + thrown_force_divisor = 0.25 // 5 when thrown with weight 20 (steel) + var/loaded //Descriptive string for currently loaded food object. + var/scoop_food = 1 + +/obj/item/weapon/material/kitchen/utensil/New() + ..() + if (prob(60)) + src.pixel_y = rand(0, 4) + create_reagents(5) + return + +/obj/item/weapon/material/kitchen/utensil/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) + if(!istype(M)) + return ..() + + if(user.a_intent != I_HELP) + if(user.zone_sel.selecting == BP_HEAD || user.zone_sel.selecting == BP_EYES) + if((CLUMSY in user.mutations) && prob(50)) + M = user + return eyestab(M,user) + else + return ..() + + if (reagents.total_volume > 0) + reagents.trans_to_mob(M, reagents.total_volume, CHEM_INGEST) + if(M == user) + if(!M.can_eat(loaded)) + return + M.visible_message("\The [user] eats some [loaded] from \the [src].") + else + user.visible_message("\The [user] begins to feed \the [M]!") + if(!(M.can_force_feed(user, loaded) && do_mob(user, M, 5 SECONDS))) + return + M.visible_message("\The [user] feeds some [loaded] to \the [M] with \the [src].") + playsound(M.loc,"eat", 100, FALSE) + overlays.Cut() + return + else + to_chat(user, "You don't have anything on \the [src].")//if we have help intent and no food scooped up DON'T STAB OURSELVES WITH THE FORK + return + +/obj/item/weapon/material/kitchen/utensil/fork + name = "fork" + desc = "It's a fork. Sure is pointy." + icon_state = "fork" + +/obj/item/weapon/material/kitchen/utensil/fork/plastic + default_material = "plastic" + +/obj/item/weapon/material/kitchen/utensil/spoon + name = "spoon" + desc = "It's a spoon. You can see your own upside-down face in it." + icon_state = "spoon" + attack_verb = list("attacked", "poked") + force_divisor = 0.1 //2 when wielded with weight 20 (steel) + +/obj/item/weapon/material/kitchen/utensil/spoon/plastic + default_material = "plastic" + +/* + * Knives + */ +/obj/item/weapon/material/kitchen/utensil/knife + name = "knife" + desc = "A knife for eating with. Can cut through any food." + icon_state = "knife" + force_divisor = 0.1 // 6 when wielded with hardness 60 (steel) + scoop_food = 0 + sharp = 1 + edge = 1 + +// Identical to the tactical knife but nowhere near as stabby. +// Kind of like the toy esword compared to the real thing. +//Making the sprite clear that this is a small knife +/obj/item/weapon/material/kitchen/utensil/knife/boot + name = "small knife" + desc = "A small, easily concealed knife." + icon = 'icons/obj/weapons.dmi' + icon_state = "pocketknife_open" + item_state = "knife" + applies_material_colour = 0 + unbreakable = 1 + +/obj/item/weapon/material/kitchen/utensil/knife/attack(target as mob, mob/living/user as mob) + if ((CLUMSY in user.mutations) && prob(50)) + to_chat(user, "You accidentally cut yourself with \the [src].") + user.take_organ_damage(20) + return + return ..() + +/obj/item/weapon/material/kitchen/utensil/knife/unathiknife + name = "dueling knife" + desc = "A length of leather-bound wood studded with razor-sharp teeth. How crude." + icon = 'icons/obj/weapons.dmi' + icon_state = "unathiknife" + item_state = "knife" + attack_verb = list("ripped", "torn", "cut") + applies_material_colour = 0 + unbreakable = 1 + +/obj/item/weapon/material/kitchen/utensil/knife/plastic + default_material = "plastic" + +/* + * Rolling Pins + */ + +/obj/item/weapon/material/kitchen/rollingpin + name = "rolling pin" + desc = "Used to knock out the Bartender." + icon_state = "rolling_pin" + attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "whacked") + default_material = "wood" + force_divisor = 0.7 // 10 when wielded with weight 15 (wood) + thrown_force_divisor = 1 // as above + +/obj/item/weapon/material/kitchen/rollingpin/attack(mob/living/M as mob, mob/living/user as mob) + if ((CLUMSY in user.mutations) && prob(50)) + to_chat(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 + return ..() diff --git a/code/game/objects/items/weapons/material/knives.dm b/code/game/objects/items/weapons/material/knives.dm new file mode 100644 index 00000000..62916554 --- /dev/null +++ b/code/game/objects/items/weapons/material/knives.dm @@ -0,0 +1,84 @@ +/obj/item/weapon/material/butterfly + name = "butterfly knife" + desc = "A basic metal blade concealed in a lightweight plasteel grip. Small enough when folded to fit in a pocket." + icon_state = "butterflyknife" + item_state = null + hitsound = null + var/active = 0 + w_class = ITEM_SIZE_SMALL + attack_verb = list("patted", "tapped") + force_divisor = 0.25 // 15 when wielded with hardness 60 (steel) + thrown_force_divisor = 0.25 // 5 when thrown with weight 20 (steel) + +/obj/item/weapon/material/butterfly/update_force() + if(active) + edge = 1 + sharp = 1 + ..() //Updates force. + throwforce = max(3,force-3) + hitsound = 'sound/weapons/bladeslice.ogg' + icon_state += "_open" + w_class = ITEM_SIZE_NORMAL + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + else + force = 3 + edge = 0 + sharp = 0 + hitsound = initial(hitsound) + icon_state = initial(icon_state) + w_class = initial(w_class) + attack_verb = initial(attack_verb) + +/obj/item/weapon/material/butterfly/switchblade + name = "switchblade" + desc = "A classic switchblade with gold engraving. Just holding it makes you feel like a gangster." + icon_state = "switchblade" + unbreakable = 1 + +/obj/item/weapon/material/butterfly/attack_self(mob/user) + active = !active + if(active) + to_chat(user, "You flip out \the [src].") + playsound(user, 'sound/weapons/flipblade.ogg', 15, 1) + else + to_chat(user, "\The [src] can now be concealed.") + update_force() + add_fingerprint(user) + +/* + * Kitchen knives + */ +/obj/item/weapon/material/knife + name = "kitchen knife" + icon = 'icons/obj/kitchen.dmi' + icon_state = "knife" + desc = "A general purpose Chef's Knife made by SpaceCook Incorporated. Guaranteed to stay sharp for years to come." + obj_flags = OBJ_FLAG_CONDUCTIBLE + sharp = 1 + edge = 1 + force_divisor = 0.15 // 9 when wielded with hardness 60 (steel) + matter = list(DEFAULT_WALL_MATERIAL = 12000) + origin_tech = list(TECH_MATERIAL = 1) + attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + unbreakable = 1 + +/obj/item/weapon/material/knife/hook + name = "meat hook" + desc = "A sharp, metal hook what sticks into things." + icon_state = "hook_knife" + item_state = "hook_knife" + +/obj/item/weapon/material/knife/ritual + name = "ritual knife" + desc = "The unearthly energies that once powered this blade are now dormant." + icon = 'icons/obj/wizard.dmi' + icon_state = "render" + applies_material_colour = 0 + +/obj/item/weapon/material/knife/butch + name = "butcher's cleaver" + icon = 'icons/obj/kitchen.dmi' + icon_state = "butch" + desc = "A huge thing used for chopping and chopping up meat. This includes clowns and clown-by-products." + force_divisor = 0.25 // 15 when wielded with hardness 60 (steel) + attack_verb = list("cleaved", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") diff --git a/code/game/objects/items/weapons/material/material_weapons.dm b/code/game/objects/items/weapons/material/material_weapons.dm new file mode 100644 index 00000000..43793332 --- /dev/null +++ b/code/game/objects/items/weapons/material/material_weapons.dm @@ -0,0 +1,131 @@ +// SEE code/modules/materials/materials.dm FOR DETAILS ON INHERITED DATUM. +// This class of weapons takes force and appearance data from a material datum. +// They are also fragile based on material data and many can break/smash apart. +/obj/item/weapon/material + health = 10 + hitsound = 'sound/weapons/bladeslice.ogg' + gender = NEUTER + throw_speed = 3 + throw_range = 7 + w_class = ITEM_SIZE_NORMAL + sharp = 0 + edge = 0 + + var/applies_material_colour = 1 + var/unbreakable + var/force_divisor = 0.5 + var/thrown_force_divisor = 0.5 + var/default_material = DEFAULT_WALL_MATERIAL + var/material/material + var/drops_debris = 1 + var/broken_icon = null + +/obj/item/weapon/material/New(var/newloc, var/material_key) + ..(newloc) + if(!material_key) + material_key = default_material + set_material(material_key) + if(!material) + qdel(src) + return + + matter = material.get_matter() + if(matter.len) + for(var/material_type in matter) + if(!isnull(matter[material_type])) + matter[material_type] *= force_divisor // May require a new var instead. + +/obj/item/weapon/material/get_material() + return material + +/obj/item/weapon/material/proc/update_force() + if(edge || sharp) + force = material.get_edge_damage() + else + force = material.get_blunt_damage() + force = round(force*force_divisor) + throwforce = round(material.get_blunt_damage()*thrown_force_divisor) + //spawn(1) +// log_debug("[src] has force [force] and throwforce [throwforce] when made from default material [material.name]") + + +/obj/item/weapon/material/proc/set_material(var/new_material) + material = get_material_by_name(new_material) + if(!material) + qdel(src) + else + SetName("[material.display_name] [initial(name)]") + health = round(material.integrity/10) + if(applies_material_colour) + color = material.icon_colour + if(material.products_need_process()) + START_PROCESSING(SSobj, src) + if(material.conductive) + obj_flags |= OBJ_FLAG_CONDUCTIBLE + else + obj_flags &= (~OBJ_FLAG_CONDUCTIBLE) + update_force() + +/obj/item/weapon/material/Destroy() + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/item/weapon/material/apply_hit_effect() + . = ..() + if(!unbreakable) + if(!prob(material.hardness)) + if(material.is_brittle()) + health = 0 + else + health-- + check_health() + +/obj/item/weapon/material/proc/check_health(var/consumed) + if(health<=0) + shatter(consumed) + +/obj/item/weapon/material/proc/shatter(var/consumed) + var/turf/T = get_turf(src) + if(broken_icon) + playsound(src, "shatter", 70, 1) + T.visible_message("\The [src] breaks!") + icon = 'icons/obj/items/broken_weapons.dmi' + icon_state = broken_icon + force = 0 + + + else + T.visible_message("\The [src] [material.destruction_desc]!") + if(istype(loc, /mob/living)) + var/mob/living/M = loc + M.drop_from_inventory(src) + playsound(src, "shatter", 70, 1) + if(!consumed && drops_debris) material.place_shard(T) + qdel(src) +/* +Commenting this out pending rebalancing of radiation based on small objects. +/obj/item/weapon/material/process() + if(!material.radioactivity) + return + for(var/mob/living/L in range(1,src)) + L.apply_effect(round(material.radioactivity/30),IRRADIATE, blocked = L.getarmor(null, "rad")) +*/ + +/* +// Commenting this out while fires are so spectacularly lethal, as I can't seem to get this balanced appropriately. +/obj/item/weapon/material/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + TemperatureAct(exposed_temperature) + +// This might need adjustment. Will work that out later. +/obj/item/weapon/material/proc/TemperatureAct(temperature) + health -= material.combustion_effect(get_turf(src), temperature, 0.1) + check_health(1) + +/obj/item/weapon/material/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + if(material.ignition_point && WT.remove_fuel(0, user)) + TemperatureAct(150) + else + return ..() +*/ \ No newline at end of file diff --git a/code/game/objects/items/weapons/material/misc.dm b/code/game/objects/items/weapons/material/misc.dm new file mode 100644 index 00000000..3311e100 --- /dev/null +++ b/code/game/objects/items/weapons/material/misc.dm @@ -0,0 +1,78 @@ +/obj/item/weapon/material/harpoon + name = "harpoon" + sharp = 1 + edge = 1 + desc = "Tharr she blows!" + icon_state = "harpoon" + item_state = "harpoon" + force_divisor = 0.3 // 18 with hardness 60 (steel) + attack_verb = list("jabbed","stabbed","ripped") + +/obj/item/weapon/material/hatchet + name = "hatchet" + desc = "A very sharp axe blade upon a short fibremetal handle. It has a long history of chopping things, but now it is used for chopping wood." + icon = 'icons/obj/weapons.dmi' + icon_state = "hatchet" + force_divisor = 0.2 // 12 with hardness 60 (steel) + thrown_force_divisor = 0.75 // 15 with weight 20 (steel) + w_class = ITEM_SIZE_SMALL + sharp = 1 + edge = 1 + origin_tech = list(TECH_MATERIAL = 2, TECH_COMBAT = 1) + attack_verb = list("chopped", "torn", "cut") + applies_material_colour = 0 + hitsound = "chop" + +/obj/item/weapon/material/hatchet/tacknife + name = "tactical knife" + desc = "You'd be killing loads of people if this was Medal of Valor: Heroes of Space." + icon = 'icons/obj/weapons.dmi' + icon_state = "tacknife" + item_state = "knife" + attack_verb = list("stabbed", "chopped", "cut") + applies_material_colour = 1 + +/obj/item/weapon/material/hatchet/machete + name = "machete" + desc = "A long, sturdy blade with a rugged handle. Leading the way to cursed treasures since before space travel." + icon_state = "machete" + w_class = ITEM_SIZE_NORMAL + slot_flags = SLOT_BELT + +/obj/item/weapon/material/hatchet/machete/Initialize() + icon_state = "machete[pick("","_red","_blue", "_black", "_olive")]" + . = ..() + +/obj/item/weapon/material/hatchet/machete/deluxe + name = "deluxe machete" + desc = "A fine example of a machete, with a polished blade, wooden handle and a leather cord loop." + icon_state = "machetedx" + item_state = "machete" + +/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" + force_divisor = 0.25 // 5 with weight 20 (steel) + thrown_force_divisor = 0.25 // as above + w_class = ITEM_SIZE_SMALL + attack_verb = list("slashed", "sliced", "cut", "clawed") + +/obj/item/weapon/material/scythe + icon_state = "scythe0" + name = "scythe" + desc = "A sharp and curved blade on a long fibremetal handle, this tool makes it easy to reap what you sow." + force_divisor = 0.275 // 16 with hardness 60 (steel) + thrown_force_divisor = 0.25 // 5 with weight 20 (steel) + sharp = 1 + edge = 1 + throw_speed = 1 + throw_range = 3 + w_class = ITEM_SIZE_HUGE + slot_flags = SLOT_BACK + origin_tech = list(TECH_MATERIAL = 2, TECH_COMBAT = 2) + attack_verb = list("chopped", "sliced", "cut", "reaped") + + diff --git a/code/game/objects/items/weapons/material/shards.dm b/code/game/objects/items/weapons/material/shards.dm new file mode 100644 index 00000000..4ffeff70 --- /dev/null +++ b/code/game/objects/items/weapons/material/shards.dm @@ -0,0 +1,102 @@ +// Glass shards + +/obj/item/weapon/material/shard + name = "shard" + icon = 'icons/obj/shards.dmi' + desc = "Made of nothing. How does this even exist?" // set based on material, if this desc is visible it's a bug (shards default to being made of glass) + icon_state = "large" + randpixel = 8 + sharp = 1 + edge = 1 + w_class = ITEM_SIZE_SMALL + force_divisor = 0.2 // 6 with hardness 30 (glass) + thrown_force_divisor = 0.4 // 4 with weight 15 (glass) + item_state = "shard-glass" + attack_verb = list("stabbed", "slashed", "sliced", "cut") + default_material = "glass" + unbreakable = 1 //It's already broken. + drops_debris = 0 + +/obj/item/weapon/material/shard/set_material(var/new_material) + ..(new_material) + if(!istype(material)) + return + + icon_state = "[material.shard_icon][pick("large", "medium", "small")]" + update_icon() + + if(material.shard_type) + SetName("[material.display_name] [material.shard_type]") + desc = "A small piece of [material.display_name]. It looks sharp, you wouldn't want to step on it barefoot. Could probably be used as ... a throwing weapon?" + switch(material.shard_type) + if(SHARD_SPLINTER, SHARD_SHRAPNEL) + gender = PLURAL + else + gender = NEUTER + else + qdel(src) + +/obj/item/weapon/material/shard/update_icon() + if(material) + color = material.icon_colour + // 1-(1-x)^2, so that glass shards with 0.3 opacity end up somewhat visible at 0.51 opacity + alpha = 255 * (1 - (1 - material.opacity)*(1 - material.opacity)) + else + color = "#ffffff" + alpha = 255 + +/obj/item/weapon/material/shard/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWelder(W) && material.shard_can_repair) + var/obj/item/weapon/weldingtool/WT = W + if(WT.remove_fuel(0, user)) + material.place_sheet(loc) + qdel(src) + return + return ..() + +/obj/item/weapon/material/shard/Crossed(AM as mob|obj) + ..() + if(isliving(AM)) + var/mob/M = AM + + if(M.buckled) //wheelchairs, office chairs, rollerbeds + return + + playsound(src.loc, 'sound/effects/glass_step.ogg', 50, 1) // not sure how to handle metal shards with sounds + if(ishuman(M)) + var/mob/living/carbon/human/H = M + + if(H.species.siemens_coefficient<0.5 || (H.species.species_flags & (SPECIES_FLAG_NO_EMBED|SPECIES_FLAG_NO_MINOR_CUT))) //Thick skin. + return + + if( H.shoes || ( H.wear_suit && (H.wear_suit.body_parts_covered & FEET) ) ) + return + + to_chat(M, "You step on \the [src]!") + + var/list/check = list(BP_L_FOOT, BP_R_FOOT) + while(check.len) + var/picked = pick(check) + var/obj/item/organ/external/affecting = H.get_organ(picked) + if(affecting) + if(affecting.robotic >= ORGAN_ROBOT) + return + affecting.take_damage(5, 0) + H.updatehealth() + if(affecting.can_feel_pain()) + H.Weaken(3) + return + check -= picked + return + +// Preset types - left here for the code that uses them +/obj/item/weapon/material/shrapnel + name = "shrapnel" + default_material = DEFAULT_WALL_MATERIAL + w_class = ITEM_SIZE_TINY //it's real small + +/obj/item/weapon/material/shard/shrapnel/New(loc) + ..(loc, DEFAULT_WALL_MATERIAL) + +/obj/item/weapon/material/shard/phoron/New(loc) + ..(loc, "phglass") diff --git a/code/game/objects/items/weapons/material/stick.dm b/code/game/objects/items/weapons/material/stick.dm new file mode 100644 index 00000000..8d962374 --- /dev/null +++ b/code/game/objects/items/weapons/material/stick.dm @@ -0,0 +1,35 @@ +/obj/item/weapon/material/stick + name = "stick" + desc = "You feel the urge to poke someone with this." + icon_state = "stick" + item_state = "stickmat" + force_divisor = 0.1 + thrown_force_divisor = 0.1 + w_class = ITEM_SIZE_NORMAL + default_material = "wood" + attack_verb = list("poked", "jabbed") + + +/obj/item/weapon/material/stick/attack_self(mob/user as mob) + user.visible_message("\The [user] snaps [src].", "You snap [src].") + shatter(0) + + +/obj/item/weapon/material/stick/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(W.sharp && W.edge && !sharp) + user.visible_message("[user] sharpens [src] with [W].", "You sharpen [src] using [W].") + sharp = 1 //Sharpen stick + SetName("sharpened " + name) + update_force() + return ..() + + +/obj/item/weapon/material/stick/attack(mob/M, mob/user) + if(user != M && user.a_intent == I_HELP) + //Playful poking is its own thing + user.visible_message("[user] pokes [M] with [src].", "You poke [M] with [src].") + //Consider adding a check to see if target is dead + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(M) + return + return ..() diff --git a/code/game/objects/items/weapons/material/swords.dm b/code/game/objects/items/weapons/material/swords.dm new file mode 100644 index 00000000..47ff2bd8 --- /dev/null +++ b/code/game/objects/items/weapons/material/swords.dm @@ -0,0 +1,188 @@ +#define SLASH 1 +#define STAB 2 +#define BASH 3 + + +/obj/item/weapon/material/sword + name = "claymore" + desc = "You use the sharp part on your foes. And the flat part on your lesser foes." + icon_state = "claymore" + item_state = "claymore" + slot_flags = SLOT_BELT + w_class = ITEM_SIZE_HUGE + force_divisor = 0.2 // 30 when wielded with hardness 60 (steel) + thrown_force_divisor = 0.2 // 10 when thrown with weight 20 (steel) + sharp = 1 + edge = 1 + attack_verb = list("slashed", "sliced") + hitsound = "slash_sound" + var/atk_mode = SLASH + block_chance = 25 + applies_material_colour = FALSE + grab_sound_is_loud = TRUE + grab_sound = 'sound/items/unholster_sword02.ogg' + equipsound = 'sound/items/holster_sword1.ogg' + sharpness = 25 + weapon_speed_delay = 20 + parry_sounds = list('sound/weapons/bladeparry1.ogg', 'sound/weapons/bladeparry2.ogg', 'sound/weapons/bladeparry3.ogg', 'sound/weapons/bladeparry4.ogg') + drop_sound = 'sound/items/drop_sword.ogg' + unbreakable = TRUE + + +/obj/item/weapon/material/sword/handle_shield(mob/living/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + if(default_sword_parry(user, damage, damage_source, attacker, def_zone, attack_text)) + return 1 + + return 0 + +/obj/item/proc/default_sword_parry(mob/living/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + //Ok this if looks like a bit of a mess, and it is. Basically you need to have the sword in your active hand, and pass the default parry check + //and also pass the prob which is your melee skill divided by two + the swords block chance. Complicated, I know, but hopefully it'll balance out. + + var/actual_block_chance = prob(block_chance + ((user.SKILL_LEVEL(melee) * 10) / 2))//Skills aren't base 100 anymore they're based 10 so I'm multiplying 100 + + if(user.atk_intent == I_DEFENSE) + actual_block_chance += 50 + + if(default_parry_check(user, attacker, damage_source) && actual_block_chance && (user.get_active_hand() == src))//You gotta be holding onto that sheesh bro. + user.visible_message("\The [user] parries [attack_text] with \the [src]!") + if(parry_sounds.len) + playsound(user.loc, pick(parry_sounds), 50, 1) + user.adjustStaminaLoss(10) + health -= 0.5 + if(!prob((user.SKILL_LEVEL(melee) * 10) + 15) || user.staminaloss >= user.staminaexhaust)//If you're out of stamina you will immediately be disarmed. + disarm(user)//Moved the disarm affect to it's own proc in case we want to call it elsewhere. + else if(user.atk_intent == I_GUARD)//If they're on gaurd intent then attack back immediately. + if(istype(src, /obj/item/weapon/gun))//If they're using a gun I don't want them shooting like it's fucking gun kaka. + if(user.a_intent != I_HURT) + visible_message("[user] ripostes!") + src.attack(attacker, user, def_zone) + user.adjustStaminaLoss(5) + else + visible_message("[user] ripostes!") + src.attack(attacker, user, def_zone) + user.adjustStaminaLoss(5) + return 1 + +/obj/item/proc/disarm(mob/living/user) + user.visible_message("\The [src] flies out of \the [user]'s hand!") + user.drop_from_inventory(src) + throw_at(get_edge_target_turf(src, pick(GLOB.alldirs)), rand(1,3), throw_speed)//Throw that sheesh away + + + +/obj/item/weapon/material/sword/attack_self(mob/user) + ..() + if(atk_mode == SLASH) + switch_intent(user,STAB) + else if(atk_mode == STAB) + switch_intent(user,BASH) + else if(atk_mode == BASH) + switch_intent(user,SLASH) + + + +/obj/item/weapon/material/sword/proc/switch_intent(mob/user,var/intent) + switch(intent) + if(STAB) + atk_mode = STAB + to_chat(user, "You will now stab.") + edge = 0 + sharp = 1 + attack_verb = list("stabbed") + hitsound = "stab_sound" + return + if(BASH) + atk_mode = BASH + to_chat(user, "You will now bash with the hilt.") + edge = 0 + sharp = 0 + attack_verb = list("bashed", "smacked") + hitsound = "swing_hit" + return + + if(SLASH) + atk_mode = SLASH + to_chat(user, "You will now slash.") + edge = TRUE + sharp = TRUE + attack_verb = list("slashed", "diced") + hitsound = "slash_sound" + return + + + + +/obj/item/weapon/material/sword/replica + edge = 0 + sharp = 0 + force_divisor = 0.2 + thrown_force_divisor = 0.2 + +/obj/item/weapon/material/sword/katana + name = "katana" + desc = "Woefully underpowered in D20. This one looks pretty sharp." + icon_state = "katana" + item_state = "katana" + slot_flags = SLOT_BELT | SLOT_BACK + +/obj/item/weapon/material/sword/katana/replica + edge = 0 + sharp = 0 + force_divisor = 0.2 + thrown_force_divisor = 0.2 + +/obj/item/weapon/material/sword/sabre + name = "sabre" + desc = "Like a claymore but for an officer." + icon_state = "sabre" + item_state = "sabre" + force_divisor = 0.4 + thrown_force_divisor = 0.4 + block_chance = 50 + + +/obj/item/weapon/material/sword/machete + name = "machete" + desc = "Both a vine removal tool, and a limb removal tool. Use it on vines, and also people who annoy you." + icon_state = "machete" + item_state = "machete" + w_class = ITEM_SIZE_NORMAL + slot_flags = SLOT_BELT + + +/obj/item/weapon/material/sword/combat_knife + name = "combat knife" + desc = "For self defense, and self offense." + icon_state = "combatknife" + item_state = "EB-knife"//"knife" + attack_verb = list("slashed") + force_divisor = 0.3 + block_chance = 15 + w_class = ITEM_SIZE_SMALL + grab_sound_is_loud = TRUE + grab_sound = 'sound/items/unholster_knife.ogg' + equipsound = 'sound/items/holster_knife.ogg' + sharpness = FALSE//No cutting peoples heads off with a knife please. + weapon_speed_delay = 10 + drop_sound = 'sound/items/knife_drop.ogg' + swing_sound = "blunt_swing" + + +/obj/item/weapon/material/sword/combat_knife/attack(mob/living/carbon/C as mob, mob/living/user as mob) + if(user.a_intent == I_HELP && (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.") + C.handcuffed = null + if(C.buckled && C.buckled.buckle_require_restraints) + C.buckled.unbuckle_mob() + C.update_inv_handcuffed() + return + + if(user.a_intent == I_HELP) + remove_shrapnel(C, user) + else + ..() + + diff --git a/code/game/objects/items/weapons/material/thrown.dm b/code/game/objects/items/weapons/material/thrown.dm new file mode 100644 index 00000000..01289819 --- /dev/null +++ b/code/game/objects/items/weapons/material/thrown.dm @@ -0,0 +1,24 @@ +/obj/item/weapon/material/star + name = "shuriken" + desc = "A sharp, perfectly weighted piece of metal." + icon_state = "star" + randpixel = 12 + force_divisor = 0.1 // 6 with hardness 60 (steel) + thrown_force_divisor = 0.75 // 15 with weight 20 (steel) + throw_speed = 10 + throw_range = 15 + sharp = 1 + edge = 1 + +/obj/item/weapon/material/star/New() + ..() + +/obj/item/weapon/material/star/throw_impact(atom/hit_atom) + ..() + if(material.radioactivity>0 && istype(hit_atom,/mob/living)) + var/mob/living/M = hit_atom + var/urgh = material.radioactivity + M.adjustToxLoss(rand(urgh/2,urgh)) + +/obj/item/weapon/material/star/ninja + default_material = "uranium" diff --git a/code/game/objects/items/weapons/material/twohanded.dm b/code/game/objects/items/weapons/material/twohanded.dm new file mode 100644 index 00000000..940160f6 --- /dev/null +++ b/code/game/objects/items/weapons/material/twohanded.dm @@ -0,0 +1,129 @@ +/* Two-handed Weapons + * Contains: + * Twohanded + * Fireaxe + * Double-Bladed Energy Swords + */ + +/*################################################################## +##################### TWO HANDED WEAPONS BE HERE~ -Agouri :3 ######## +####################################################################*/ + +//Rewrote TwoHanded weapons stuff and put it all here. Just copypasta fireaxe to make new ones ~Carn +//This rewrite means we don't have two variables for EVERY item which are used only by a few weapons. +//It also tidies stuff up elsewhere. + +/* + * Twohanded + */ +/obj/item/weapon/material/twohanded + w_class = ITEM_SIZE_HUGE +// var/wielded = 0 +// var/force_wielded = 0 +// var/force_unwielded +// var/wieldsound = null +// var/unwieldsound = null + var/base_icon + var/base_name + var/unwielded_force_divisor = 0.25 + +/* +/obj/item/weapon/material/twohanded/update_twohanding() + var/mob/living/M = loc + if(istype(M) && M.can_wield_item(src) && is_held_twohanded(M)) + wielded = 1 + force = force_wielded + else + wielded = 0 + force = force_unwielded + update_icon() + ..() +*/ +/obj/item/weapon/material/twohanded/update_force() + base_name = name + if(sharp || edge) + force_wielded = material.get_edge_damage() + else + force_wielded = material.get_blunt_damage() + force_wielded = round(force_wielded*force_divisor) + force_unwielded = round(force_wielded*unwielded_force_divisor) + force = force_unwielded + throwforce = round(force*thrown_force_divisor) +// log_debug("[src] has unwielded force [force_unwielded], wielded force [force_wielded] and throwforce [throwforce] when made from default material [material.name]") + + +/obj/item/weapon/material/twohanded/New() + ..() + update_icon() + +//Allow a small chance of parrying melee attacks when wielded - maybe generalize this to other weapons someday +/obj/item/weapon/material/twohanded/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + if(wielded && default_parry_check(user, attacker, damage_source) && prob(15)) + user.visible_message("\The [user] parries [attack_text] with \the [src]!") + playsound(user.loc, 'sound/weapons/punchmiss.ogg', 50, 1) + return 1 + return 0 + +/obj/item/weapon/material/twohanded/update_icon() + icon_state = "[base_icon][wielded]" + item_state_slots[slot_l_hand_str] = icon_state + item_state_slots[slot_r_hand_str] = icon_state + +/* + * Fireaxe + */ +/obj/item/weapon/material/twohanded/fireaxe // DEM AXES MAN, marker -Agouri + icon_state = "fireaxe0" + base_icon = "fireaxe" + name = "fire axe" + desc = "Truly, the weapon of a madman. Who would think to fight fire with an axe?" + + // 15/32 with hardness 60 (steel) and 20/42 with hardness 80 (plasteel) + force_divisor = 0.525 + unwielded_force_divisor = 0.25 + sharp = 1 + edge = 1 + w_class = ITEM_SIZE_HUGE + slot_flags = SLOT_BACK + force_wielded = 30 + attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") + applies_material_colour = 0 + +/obj/item/weapon/material/twohanded/fireaxe/afterattack(atom/A as mob|obj|turf|area, mob/user as mob, proximity) + if(!proximity) return + ..() + if(A && wielded) + if(istype(A,/obj/structure/window)) + var/obj/structure/window/W = A + W.shatter() + else if(istype(A,/obj/structure/grille)) + qdel(A) + else if(istype(A,/obj/effect/vine)) + var/obj/effect/vine/P = A + P.die_off() + +//spears, bay edition +/obj/item/weapon/material/twohanded/spear + icon_state = "spearglass0" + base_icon = "spearglass" + name = "spear" + desc = "A haphazardly-constructed yet still deadly weapon of ancient design." + force = 10 + w_class = ITEM_SIZE_HUGE + slot_flags = SLOT_BACK + + // 12/19 with hardness 60 (steel) or 10/16 with hardness 50 (glass) + force_divisor = 0.33 + unwielded_force_divisor = 0.20 + thrown_force_divisor = 1.5 // 20 when thrown with weight 15 (glass) + throw_speed = 3 + edge = 0 + sharp = 1 + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "poked", "jabbed", "torn", "gored") + default_material = "glass" + +/obj/item/weapon/material/twohanded/spear/shatter(var/consumed) + if(!consumed) + new /obj/item/weapon/material/wirerod(get_turf(src)) //give back the wired rod + ..() diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm new file mode 100644 index 00000000..9363fc55 --- /dev/null +++ b/code/game/objects/items/weapons/melee/energy.dm @@ -0,0 +1,238 @@ +/obj/item/weapon/melee/energy + var/active = 0 + var/active_force + var/active_throwforce + sharp = 0 + edge = 0 + armor_penetration = 50 + atom_flags = ATOM_FLAG_NO_BLOOD + +/obj/item/weapon/melee/energy/proc/activate(mob/living/user) + anchored = 1 + if(active) + return + active = 1 + force = active_force + throwforce = active_throwforce + sharp = 1 + edge = 1 + slot_flags |= SLOT_DENYPOCKET + playsound(user, 'sound/weapons/saberon.ogg', 50, 1) + +/obj/item/weapon/melee/energy/proc/deactivate(mob/living/user) + anchored = 0 + if(!active) + return + playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) + active = 0 + force = initial(force) + throwforce = initial(throwforce) + sharp = initial(sharp) + edge = initial(edge) + slot_flags = initial(slot_flags) + +/obj/item/weapon/melee/energy/attack_self(mob/living/user as mob) + if (active) + if ((CLUMSY in user.mutations) && prob(50)) + user.visible_message("\The [user] accidentally cuts \himself with \the [src].",\ + "You accidentally cut yourself with \the [src].") + user.take_organ_damage(5,5) + deactivate(user) + else + activate(user) + + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + H.update_inv_l_hand() + H.update_inv_r_hand() + + add_fingerprint(user) + return + +/obj/item/weapon/melee/energy/get_storage_cost() + if(active) + return ITEM_SIZE_NO_CONTAINER + return ..() + +/* + * Energy Axe + */ +/obj/item/weapon/melee/energy/axe + name = "energy axe" + desc = "An energised battle axe." + icon_state = "axe0" + //active_force = 150 //holy... + active_force = 60 + active_throwforce = 35 + //force = 40 + //throwforce = 25 + force = 20 + throwforce = 10 + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_NORMAL + atom_flags = ATOM_FLAG_NO_BLOOD + obj_flags = OBJ_FLAG_CONDUCTIBLE + origin_tech = list(TECH_MAGNET = 3, TECH_COMBAT = 4) + attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") + sharp = 1 + edge = 1 + +/obj/item/weapon/melee/energy/axe/activate(mob/living/user) + ..() + icon_state = "axe1" + to_chat(user, "\The [src] is now energised.") + +/obj/item/weapon/melee/energy/axe/deactivate(mob/living/user) + ..() + icon_state = initial(icon_state) + to_chat(user, "\The [src] is de-energised. It's just a regular axe now.") + +/* + * Energy Sword + */ +/obj/item/weapon/melee/energy/sword + color + name = "energy sword" + desc = "May the force be within you." + icon_state = "sword0" + active_force = 30 + active_throwforce = 20 + force = 3 + throwforce = 5 + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_SMALL + atom_flags = ATOM_FLAG_NO_BLOOD + origin_tech = list(TECH_MAGNET = 3, TECH_ILLEGAL = 4) + sharp = 1 + edge = 1 + var/blade_color + +/obj/item/weapon/melee/energy/sword/dropped(var/mob/user) + ..() + if(!istype(loc,/mob)) + deactivate(user) + +/obj/item/weapon/melee/energy/sword/New() + blade_color = pick("red","blue","green","purple") + +/obj/item/weapon/melee/energy/sword/green/New() + blade_color = "green" + +/obj/item/weapon/melee/energy/sword/red/New() + blade_color = "red" + +/obj/item/weapon/melee/energy/sword/blue/New() + blade_color = "blue" + +/obj/item/weapon/melee/energy/sword/purple/New() + blade_color = "purple" + +/obj/item/weapon/melee/energy/sword/activate(mob/living/user) + if(!active) + to_chat(user, "\The [src] is now energised.") + ..() + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + icon_state = "sword[blade_color]" + +/obj/item/weapon/melee/energy/sword/deactivate(mob/living/user) + if(active) + to_chat(user, "\The [src] deactivates!") + ..() + attack_verb = list() + icon_state = initial(icon_state) + +/obj/item/weapon/melee/energy/sword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + if(active && default_parry_check(user, attacker, damage_source) && prob(50)) + user.visible_message("\The [user] parries [attack_text] with \the [src]!") + + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, user.loc) + spark_system.start() + playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) + return 1 + return 0 + +/obj/item/weapon/melee/energy/sword/pirate + name = "energy cutlass" + desc = "Arrrr matey." + icon_state = "cutlass0" + +/obj/item/weapon/melee/energy/sword/pirate/activate(mob/living/user) + ..() + icon_state = "cutlass1" + + +/obj/item/weapon/melee/energy/sword/bogsword + name = "alien sword" + desc = "A strange, strange energy sword." + icon_state = "sword0" + +/obj/item/weapon/melee/energy/sword/bogswrd/activate(mob/living/user) + ..() + icon_state = "bog_sword" + + +/* + *Energy Blade + */ + +//Can't be activated or deactivated, so no reason to be a subtype of energy +/obj/item/weapon/melee/energy/blade + name = "energy blade" + desc = "A concentrated beam of energy in the shape of a blade. Very stylish... and lethal." + icon_state = "blade" + force = 40 //Normal attacks deal very high damage - about the same as wielded fire axe + armor_penetration = 100 + sharp = 1 + edge = 1 + anchored = 1 // Never spawned outside of inventory, should be fine. + throwforce = 1 //Throwing or dropping the item deletes it. + throw_speed = 1 + throw_range = 1 + w_class = ITEM_SIZE_TINY //technically it's just energy or something, I dunno + atom_flags = ATOM_FLAG_NO_BLOOD + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + var/mob/living/creator + var/datum/effect/effect/system/spark_spread/spark_system + +/obj/item/weapon/melee/energy/blade/New() + ..() + spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, src) + spark_system.attach(src) + +/obj/item/weapon/melee/energy/blade/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/item/weapon/melee/energy/blade/Destroy() + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/item/weapon/melee/energy/blade/get_storage_cost() + return ITEM_SIZE_NO_CONTAINER + +/obj/item/weapon/melee/energy/blade/attack_self(mob/user as mob) + user.drop_from_inventory(src) + spawn(1) if(src) qdel(src) + +/obj/item/weapon/melee/energy/blade/dropped() + ..() + spawn(1) if(src) qdel(src) + +/obj/item/weapon/melee/energy/blade/Process() + if(!creator || loc != creator || (creator.l_hand != src && creator.r_hand != src)) + // Tidy up a bit. + if(istype(loc,/mob/living)) + var/mob/living/carbon/human/host = loc + if(istype(host)) + for(var/obj/item/organ/external/organ in host.organs) + for(var/obj/item/O in organ.implants) + if(O == src) + organ.implants -= src + host.pinned -= src + host.embedded -= src + host.drop_from_inventory(src) + spawn(1) if(src) qdel(src) diff --git a/code/game/objects/items/weapons/melee/misc.dm b/code/game/objects/items/weapons/melee/misc.dm new file mode 100644 index 00000000..78fb5ff6 --- /dev/null +++ b/code/game/objects/items/weapons/melee/misc.dm @@ -0,0 +1,58 @@ +/obj/item/weapon/melee/whip + name = "whip" + desc = "A generic whip." + icon_state = "chain" + item_state = "chain" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + force = 10 + throwforce = 7 + w_class = ITEM_SIZE_NORMAL + origin_tech = list(TECH_COMBAT = 4) + attack_verb = list("flicked", "whipped", "lashed") + + +/obj/item/weapon/melee/whip/abyssal + name = "abyssal whip" + desc = "A weapon from the abyss. Requires 70 attack to wield." + icon_state = "whip" + item_state = "whip" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + force = 16 //max hit with 60 strength and no equipment. Duel Arena no No forfeit - Snapshot + throwforce = 7 + w_class = ITEM_SIZE_NORMAL + origin_tech = list(TECH_COMBAT = 4) + attack_verb = list("flicked", "whipped", "lashed") + +/obj/item/weapon/melee/whip/chainofcommand + name = "chain of command" + desc = "A tool used by great men to placate the frothing masses." + attack_verb = list("flogged", "whipped", "lashed", "disciplined") + icon_state = "chain" + item_state = "whip" + +/obj/item/weapon/material/sword/replica/officersword + name = "fleet officer's sword" + desc = "A polished sword issued to officers of the fleet." + icon_state = "officersword" + item_state = "officersword" + slot_flags = SLOT_BELT + applies_material_colour = FALSE + +/obj/item/weapon/material/sword/replica/officersword/marine + name = "marine NCO's sword" + desc = "A polished sword issued to SCG Marine NCOs." + icon_state = "marinesword" + +/obj/item/weapon/material/sword/replica/officersword/marineofficer + name = "marine officer's sword" + desc = "A curved sword issued to SCG Marine officers." + icon_state = "marineofficersword" + item_state = "marineofficersword" + +/obj/item/weapon/material/sword/replica/officersword/pettyofficer + name = "chief petty officer's cutlass" + desc = "A polished cutlass issued to chief petty officers of the fleet." + icon_state = "pettyofficersword" + item_state = "pettyofficersword" diff --git a/code/game/objects/items/weapons/mop.dm b/code/game/objects/items/weapons/mop.dm new file mode 100644 index 00000000..8a53d0db --- /dev/null +++ b/code/game/objects/items/weapons/mop.dm @@ -0,0 +1,40 @@ +/obj/item/weapon/mop + desc = "The world of janitalia wouldn't be complete without a mop." + name = "mop" + icon = 'icons/obj/janitor.dmi' + icon_state = "mop" + force = 5 + throwforce = 10.0 + throw_speed = 5 + throw_range = 10 + w_class = ITEM_SIZE_NORMAL + attack_verb = list("mopped", "bashed", "bludgeoned", "whacked") + var/mopping = 0 + var/mopcount = 0 + + +/obj/item/weapon/mop/New() + create_reagents(30) + +/obj/item/weapon/mop/afterattack(atom/A, mob/user, proximity) + if(!proximity) return + if(istype(A, /turf) || istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/overlay) || istype(A, /obj/effect/rune)) + if(reagents.total_volume < 1) + to_chat(user, "Your mop is dry!") + return + var/turf/T = get_turf(A) + if(!T) + return + + user.visible_message("[user] begins to clean \the [T].") + + if(do_after(user, 40, T)) + if(T) + T.clean(src, user) + to_chat(user, "You have finished mopping!") + + +/obj/effect/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/weapon/mop) || istype(I, /obj/item/weapon/soap)) + return + ..() diff --git a/code/game/objects/items/weapons/nuclear_cylinder.dm b/code/game/objects/items/weapons/nuclear_cylinder.dm new file mode 100644 index 00000000..c6cf462e --- /dev/null +++ b/code/game/objects/items/weapons/nuclear_cylinder.dm @@ -0,0 +1,13 @@ +obj/item/weapon/nuclear_cylinder + name = "\improper nuclear cylinder" + desc = "This cylinder is used in the self destruct system of the ship." + icon = 'icons/obj/nuclear_cylinder.dmi' + icon_state = "nuclear_cylinder" + item_state = "nuclear" + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 10.0 + w_class = ITEM_SIZE_HUGE + throwforce = 15.0 + throw_speed = 2 + throw_range = 4 + origin_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 4) \ No newline at end of file diff --git a/code/game/objects/items/weapons/paint.dm b/code/game/objects/items/weapons/paint.dm new file mode 100644 index 00000000..092699ef --- /dev/null +++ b/code/game/objects/items/weapons/paint.dm @@ -0,0 +1,75 @@ +//NEVER USE THIS IT SUX -PETETHEGOAT +//THE GOAT WAS RIGHT - RKF + +var/global/list/cached_icons = list() + +/obj/item/weapon/reagent_containers/glass/paint + desc = "It's a paint bucket." + name = "paint bucket" + icon = 'icons/obj/items.dmi' + icon_state = "paint_neutral" + item_state = "paintcan" + matter = list(DEFAULT_WALL_MATERIAL = 200) + w_class = ITEM_SIZE_NORMAL + amount_per_transfer_from_this = 10 + possible_transfer_amounts = "10;20;30;60" + volume = 60 + unacidable = 0 + atom_flags = ATOM_FLAG_OPEN_CONTAINER + var/paint_hex = "#fe191a" + +/obj/item/weapon/reagent_containers/glass/paint/afterattack(turf/simulated/target, mob/user, proximity) + if(!proximity) return + if(istype(target) && reagents.total_volume > 5) + user.visible_message("\The [target] has been splashed with something by [user]!") + reagents.trans_to_turf(target, 5) + else + return ..() + +/obj/item/weapon/reagent_containers/glass/paint/New() + ..() + if(paint_hex && length(paint_hex) > 0) + reagents.add_reagent(/datum/reagent/paint, volume, paint_hex) + +/obj/item/weapon/reagent_containers/glass/paint/red + name = "red paint bucket" + icon_state = "paint_red" + paint_hex = "#fe191a" + +/obj/item/weapon/reagent_containers/glass/paint/yellow + name = "yellow paint bucket" + icon_state = "paint_yellow" + paint_hex = "#fdfe7d" + +/obj/item/weapon/reagent_containers/glass/paint/green + name = "green paint bucket" + icon_state = "paint_green" + paint_hex = "#18a31a" + +/obj/item/weapon/reagent_containers/glass/paint/blue + name = "blue paint bucket" + icon_state = "paint_blue" + paint_hex = "#247cff" + +/obj/item/weapon/reagent_containers/glass/paint/purple + name = "purple paint bucket" + icon_state = "paint_violet" + paint_hex = "#cc0099" + +/obj/item/weapon/reagent_containers/glass/paint/black + name = "black paint bucket" + icon_state = "paint_black" + paint_hex = "#333333" + +/obj/item/weapon/reagent_containers/glass/paint/white + name = "white paint bucket" + icon_state = "paint_white" + paint_hex = "#f0f8ff" + +/obj/item/weapon/reagent_containers/glass/paint/random + name = "odd paint bucket" + icon_state = "paint_neutral" + +/obj/item/weapon/reagent_containers/glass/paint/random/New() + paint_hex = rgb(rand(1,255),rand(1,255),rand(1,255)) + ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/paiwire.dm b/code/game/objects/items/weapons/paiwire.dm new file mode 100644 index 00000000..1504b047 --- /dev/null +++ b/code/game/objects/items/weapons/paiwire.dm @@ -0,0 +1,11 @@ +/obj/item/weapon/pai_cable/proc/plugin(obj/machinery/M as obj, mob/user as mob) + if(istype(M, /obj/machinery/door) || istype(M, /obj/machinery/camera)) + user.visible_message("[user] inserts [src] into a data port on [M].", "You insert [src] into a data port on [M].", "You hear the satisfying click of a wire jack fastening into place.") + user.drop_item() + src.loc = M + src.machine = M + else + user.visible_message("[user] dumbly fumbles to find a place on [M] to plug in [src].", "There aren't any ports on [M] that match the jack belonging to [src].") + +/obj/item/weapon/pai_cable/attack(obj/machinery/M as obj, mob/user as mob) + src.plugin(M, user) diff --git a/code/game/objects/items/weapons/policetape.dm b/code/game/objects/items/weapons/policetape.dm new file mode 100644 index 00000000..b18d39c5 --- /dev/null +++ b/code/game/objects/items/weapons/policetape.dm @@ -0,0 +1,367 @@ +//Define all tape types in policetape.dm +/obj/item/taperoll + name = "tape roll" + icon = 'icons/policetape.dmi' + icon_state = "tape" + w_class = ITEM_SIZE_SMALL + var/turf/start + var/turf/end + var/tape_type = /obj/item/tape + var/icon_base = "tape" + + var/apply_tape = FALSE + +/obj/item/taperoll/Initialize() + . = ..() + if(apply_tape) + var/turf/T = get_turf(src) + if(!T) + return + var/obj/machinery/door/airlock/airlock = locate(/obj/machinery/door/airlock) in T + if(airlock) + afterattack(airlock, null, TRUE) + return INITIALIZE_HINT_QDEL + + +var/list/image/hazard_overlays +var/list/tape_roll_applications = list() + +/obj/item/tape + name = "tape" + icon = 'icons/policetape.dmi' + icon_state = "tape" + layer = ABOVE_DOOR_LAYER + randpixel = 0 + anchored = 1 + var/lifted = 0 + var/crumpled = 0 + var/tape_dir = 0 + var/icon_base = "tape" + +/obj/item/tape/update_icon() + //Possible directional bitflags: 0 (AIRLOCK), 1 (NORTH), 2 (SOUTH), 4 (EAST), 8 (WEST), 3 (VERTICAL), 12 (HORIZONTAL) + switch (tape_dir) + if(0) // AIRLOCK + icon_state = "[icon_base]_door_[crumpled]" + if(3) // VERTICAL + icon_state = "[icon_base]_v_[crumpled]" + if(12) // HORIZONTAL + icon_state = "[icon_base]_h_[crumpled]" + else // END POINT (1|2|4|8) + icon_state = "[icon_base]_dir_[crumpled]" + dir = tape_dir + +/obj/item/tape/New() + ..() + if(!hazard_overlays) + hazard_overlays = list() + hazard_overlays["[NORTH]"] = new/image('icons/effects/warning_stripes.dmi', icon_state = "N") + hazard_overlays["[EAST]"] = new/image('icons/effects/warning_stripes.dmi', icon_state = "E") + hazard_overlays["[SOUTH]"] = new/image('icons/effects/warning_stripes.dmi', icon_state = "S") + hazard_overlays["[WEST]"] = new/image('icons/effects/warning_stripes.dmi', icon_state = "W") + +/obj/item/taperoll/police + name = "police tape" + desc = "A roll of police tape used to block off crime scenes from the public." + tape_type = /obj/item/tape/police + color = COLOR_RED + +/obj/item/tape/police + name = "police tape" + desc = "A length of police tape. Do not cross." + req_access = list(access_security) + color = COLOR_RED + +/obj/item/taperoll/engineering + name = "engineering tape" + desc = "A roll of engineering tape used to block off working areas from the public." + tape_type = /obj/item/tape/engineering + color = COLOR_ORANGE + +/obj/item/taperoll/engineering/applied + apply_tape = TRUE + +/obj/item/tape/engineering + name = "engineering tape" + desc = "A length of engineering tape. Better not cross it." + req_one_access = list(access_engine,access_atmospherics) + color = COLOR_ORANGE + +/obj/item/taperoll/atmos + name = "atmospherics tape" + desc = "A roll of atmospherics tape used to block off working areas from the public." + tape_type = /obj/item/tape/atmos + color = COLOR_BLUE_LIGHT + +/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) + color = COLOR_BLUE_LIGHT + +/obj/item/taperoll/research + name = "research tape" + desc = "A roll of research tape used to block off working areas from the public." + tape_type = /obj/item/tape/research + color = COLOR_WHITE + +/obj/item/tape/research + name = "research tape" + desc = "A length of research tape. Better not cross it." + req_one_access = list(access_research) + color = COLOR_WHITE + +/obj/item/taperoll/medical + name = "medical tape" + desc = "A roll of medical tape used to block off working areas from the public." + tape_type = /obj/item/tape/medical + color = COLOR_GREEN + +/obj/item/tape/medical + name = "medical tape" + desc = "A length of medical tape. Better not cross it." + req_one_access = list(access_medical) + color = COLOR_GREEN + +/obj/item/taperoll/update_icon() + overlays.Cut() + var/image/overlay = image(icon = src.icon) + overlay.appearance_flags = RESET_COLOR + if(ismob(loc)) + if(!start) + overlay.icon_state = "start" + else + overlay.icon_state = "stop" + overlays += overlay + +/obj/item/taperoll/dropped(mob/user) + update_icon() + return ..() + +/obj/item/taperoll/pickup(mob/user) + update_icon() + return ..() + +/obj/item/taperoll/attack_hand() + update_icon() + return ..() + +/obj/item/taperoll/attack_self(mob/user as mob) + if(!start) + start = get_turf(src) + to_chat(usr, "You place the first end of \the [src].") + update_icon() + else + end = get_turf(src) + if(start.y != end.y && start.x != end.x || start.z != end.z) + start = null + update_icon() + to_chat(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 GLOB.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 == GLOB.reverse_dir[dir]) + possible_dirs += dir + if(!possible_dirs) + start = null + update_icon() + to_chat(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.update_icon() + 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.update_icon() + start = null + update_icon() + to_chat(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/can_place = 1 + while (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) + can_place = 0 + break + if(cur == end) + break + cur = get_step_towards(cur,end) + if (!can_place) + start = null + update_icon() + to_chat(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, GLOB.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 = GLOB.reverse_dir[orientation] + for(var/obj/structure/window/W in T) + if(W.is_fulltile() || W.dir == GLOB.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)) + tapetest = 1 + break + if(!tapetest) + var/obj/item/tape/T = new tape_type(cur) + T.tape_dir = tape_dir + T.update_icon() + if(tape_dir & SOUTH) + T.layer += 0.1 // Must always show above other tapes + if(cur == end) + break + cur = get_step_towards(cur,end) + start = null + update_icon() + to_chat(usr, "You finish placing \the [src].") + return + +/obj/item/taperoll/afterattack(var/atom/A, mob/user as mob, proximity) + if(!proximity) + return + + if (istype(A, /obj/machinery/door/airlock)) + var/turf/T = get_turf(A) + var/obj/item/tape/P = new tape_type(T) + P.update_icon() + P.layer = ABOVE_DOOR_LAYER + to_chat(user, "You finish placing \the [src].") + + if (istype(A, /turf/simulated/floor) ||istype(A, /turf/unsimulated/floor)) + var/turf/F = A + var/direction = user.loc == F ? user.dir : turn(user.dir, 180) + var/icon/hazard_overlay = hazard_overlays["[direction]"] + if(tape_roll_applications[F] == null) + tape_roll_applications[F] = 0 + + if(tape_roll_applications[F] & direction) // hazard_overlay in F.overlays wouldn't work. + user.visible_message("\The [user] uses the adhesive of \the [src] to remove area markings from \the [F].", "You use the adhesive of \the [src] to remove area markings from \the [F].") + F.overlays -= hazard_overlay + tape_roll_applications[F] &= ~direction + else + user.visible_message("\The [user] applied \the [src] on \the [F] to create area markings.", "You apply \the [src] on \the [F] to create area markings.") + F.overlays |= hazard_overlay + tape_roll_applications[F] |= direction + return + +/obj/item/tape/proc/crumple() + if(!crumpled) + crumpled = 1 + update_icon() + SetName("crumpled [name]") + +/obj/item/tape/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(!lifted && ismob(mover)) + var/mob/M = mover + add_fingerprint(M) + if (!allowed(M)) //only select few learn art of not crumpling the tape + to_chat(M, "You are not supposed to go past [src]...") + if(M.a_intent == I_HELP) + return 0 + crumple() + return ..(mover) + +/obj/item/tape/attackby(obj/item/weapon/W as obj, mob/user as mob) + breaktape(user) + +/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 + else + breaktape(user) + +/obj/item/tape/proc/lift(time) + lifted = 1 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + spawn(time) + lifted = 0 + reset_plane_and_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(mob/user) + if(user.a_intent == I_HELP) + to_chat(user, "You refrain from breaking \the [src].") + return + user.visible_message("\The [user] breaks \the [src]!","You break \the [src].") + + for (var/obj/item/tape/T in gettapeline()) + if(T == src) + continue + if(T.tape_dir & get_dir(T, src)) + qdel(T) + + qdel(src) //TODO: Dropping a trash item holding fibers/fingerprints of all broken tape parts + return diff --git a/code/game/objects/items/weapons/scrolls.dm b/code/game/objects/items/weapons/scrolls.dm new file mode 100644 index 00000000..09dd1d42 --- /dev/null +++ b/code/game/objects/items/weapons/scrolls.dm @@ -0,0 +1,87 @@ +/obj/item/weapon/teleportation_scroll + name = "scroll of teleportation" + desc = "A scroll for moving around." + icon = 'icons/obj/wizard.dmi' + icon_state = "scroll" + var/uses = 4.0 + w_class = ITEM_SIZE_TINY + item_state = "paper" + throw_speed = 4 + throw_range = 20 + origin_tech = list(TECH_BLUESPACE = 4) + +/obj/item/weapon/teleportation_scroll/attack_self(mob/user as mob) + if((user.mind && !wizards.is_antagonist(user.mind))) + to_chat(usr, "You stare at the scroll but cannot make sense of the markings!") + return + + user.set_machine(src) + var/dat = "Teleportation Scroll:
            " + dat += "Number of uses: [src.uses]
            " + dat += "
            " + dat += "Four uses use them wisely:
            " + dat += "Teleport
            " + dat += "Kind regards,
            Wizards Federation

            P.S. Don't forget to bring your gear, you'll need it to cast most spells.
            " + user << browse(dat, "window=scroll") + onclose(user, "scroll") + return + +/obj/item/weapon/teleportation_scroll/Topic(href, href_list) + if(..()) + return 1 + var/mob/living/carbon/human/H = usr + if (!( istype(H, /mob/living/carbon/human))) + return 1 + if ((usr == src.loc || (in_range(src, usr) && istype(src.loc, /turf)))) + usr.set_machine(src) + if (href_list["spell_teleport"]) + if (src.uses >= 1) + teleportscroll(H) + attack_self(H) + return + +/obj/item/weapon/teleportation_scroll/proc/teleportscroll(var/mob/user) + var/area/thearea = input(user, "Area to jump to", "BOOYEA") as null|anything in teleportlocs + thearea = thearea ? teleportlocs[thearea] : thearea + + if (!thearea || CanUseTopic(user) != STATUS_INTERACTIVE) + return + + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() + smoke.set_up(5, 0, user.loc) + smoke.attach(user) + smoke.start() + var/list/L = list() + for(var/turf/T in get_area_turfs(thearea)) + if(!T.density) + var/clear = 1 + for(var/obj/O in T) + if(O.density) + clear = 0 + break + if(clear) + L+=T + + if(!L.len) + to_chat(user, "The spell matrix was unable to locate a suitable teleport destination for an unknown reason. Sorry.") + return + + if(user && user.buckled) + user.buckled.unbuckle_mob() + + var/list/tempL = L + var/attempt = null + var/success = 0 + while(tempL.len) + attempt = pick(tempL) + success = user.Move(attempt) + if(!success) + tempL.Remove(attempt) + else + break + + if(!success) + user.forceMove(pick(L)) + + smoke.start() + src.uses -= 1 diff --git a/code/game/objects/items/weapons/secrets_disk.dm b/code/game/objects/items/weapons/secrets_disk.dm new file mode 100644 index 00000000..6de9df2a --- /dev/null +++ b/code/game/objects/items/weapons/secrets_disk.dm @@ -0,0 +1,74 @@ +/obj/item/weapon/disk/secret_project + name = "'classified' project data disk" + desc = "A special disk for storing massive amounts of data. It is marked as classified, and has an ID card slot on top." + icon = 'icons/obj/cloning.dmi' + icon_state = "datadisk0" + item_state = "card-id" + w_class = ITEM_SIZE_SMALL + req_access = access_ce + var/subject = "some strange, incomprehensible design" + var/locked = 1 + +/obj/item/weapon/disk/secret_project/science + desc = "A special disk for storing massive amounts of data. It is marked as classified, and has an ID card slot on top. \ + This one has a NanoTrasen label on it." + req_access = access_rd + +/obj/item/weapon/disk/secret_project/Initialize() + . = ..() + var/codename = pick("gamma", "delta", "epsilon", "zeta", "theta", "lambda", "omicron", "sigma", "tau",\ + "upsilon", "omega", "echelon", "prism", "calypso", "bernoulli", "harmony", "nyx", "fresnel") + name = "'[codename]' project data disk" + subject = pick("an experimental design for", "a blueprint to build",\ + "a long set of theoretical formulas detailing the functioning of") + subject += " " + pick("a bluespace artillery cannon", "a supermatter engine", "a fusion engine", "an atmospheric scrubber",\ + "a human cloning pod", "a microwave oven", "a bluespace drive", "a laser carbine", "an energy pistol",\ + "a bluespace gateway", "a teleporter", "a huge mining drill", "a strange spacecraft", "a space station",\ + "a sleek-looking fighter spacecraft", "a ballistic rifle", "an energy sword", "an inanimate carbon rod") + subject += " " + pick("that is extremely powerful", "which is highly efficient", "which is incredibly compact",\ + "that runs off of phoron", "that runs off of hydrogen gas", "created by the Skrell", "that just looks really cool") + +/obj/item/weapon/disk/secret_project/examine(var/user) + ..() + if(!locked) + to_chat(user, "With the disk's classified contents unlocked, \ + you peer into its preview screen and see [subject].") + else + to_chat(user, "The disk is locked, you cannot see its contents.") + +/obj/item/weapon/disk/secret_project/emag_act(var/remaining_charges, var/mob/user) + to_chat(user, "The cryptographic lock on this disk is far too complex. \ + Your sequencer can't break the code.") + return 0 + +/obj/item/weapon/disk/secret_project/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/weapon/card/id)) + var/obj/item/weapon/card/id/ID = W + if(check_access(ID)) + locked = !locked + to_chat(user, "You swipe your card and [locked ? "lock":"unlock"] the disk.") + else + to_chat(user, "The disk's screen flashes 'Access Denied'.") + return + . = ..() + +/obj/item/weapon/disk/secret_project/verb/change_codename() + set name = "Change project codename" + set category = "Object" + set src in view(0) + + if(!locked) + var/input = sanitize(input(usr, "What would you like to change the project codename to?", "Classified Project Data Disk")) + if(!input || input == "") + return + SetName("'[input]' project data disk") + else + to_chat(usr, "The disk's screen flashes 'Access Denied'. It is locked.") + +/obj/item/weapon/storage/box/secret_project_disks + name = "box of classified data disks" + desc = "A box full of disks. Marked with a red 'Top Secret' label. Looks rather ominous." + startswith = list(/obj/item/weapon/disk/secret_project = 5) + +/obj/item/weapon/storage/box/secret_project_disks/science + startswith = list(/obj/item/weapon/disk/secret_project/science = 5) \ No newline at end of file diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm new file mode 100644 index 00000000..e4c92b37 --- /dev/null +++ b/code/game/objects/items/weapons/shields.dm @@ -0,0 +1,193 @@ +//** Shield Helpers +//These are shared by various items that have shield-like behaviour + +//bad_arc is the ABSOLUTE arc of directions from which we cannot block. If you want to fix it to e.g. the user's facing you will need to rotate the dirs yourself. +/proc/check_shield_arc(mob/user, var/bad_arc, atom/damage_source = null, mob/attacker = null) + //check attack direction + var/attack_dir = 0 //direction from the user to the source of the attack + if(istype(damage_source, /obj/item/projectile)) + var/obj/item/projectile/P = damage_source + attack_dir = get_dir(get_turf(user), P.starting) + else if(attacker) + attack_dir = get_dir(get_turf(user), get_turf(attacker)) + else if(damage_source) + attack_dir = get_dir(get_turf(user), get_turf(damage_source)) + + if(!(attack_dir && (attack_dir & bad_arc))) + return 1 + return 0 + +/proc/default_parry_check(mob/living/user, mob/attacker, atom/damage_source) + //parry only melee attacks + if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1) || user.incapacitated()) + return 0 + + if(!user.combat_mode)//If you're not in combat mode you won't parry. + return 0 + + if(user.defense_intent != I_PARRY)//If you're not on parry intent, you won't parry. + return 0 + + //if(!user.skillcheck(user.melee_skill, 60, 0))//Need at least 60 skill to be able to parry effectively. + // return 0 + + //block as long as they are not directly behind us + var/bad_arc = reverse_direction(user.dir) //arc of directions from which we cannot block + if(!check_shield_arc(user, bad_arc, damage_source, attacker)) + return 0 + + return 1 + +/obj/item/weapon/shield + name = "shield" + var/base_block_chance = 50 + +/obj/item/weapon/shield/handle_shield(mob/living/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + if(user.incapacitated()) + return 0 + + //block as long as they are not directly behind us + var/bad_arc = reverse_direction(user.dir) //arc of directions from which we cannot block + if(check_shield_arc(user, bad_arc, damage_source, attacker)) + if(prob(get_block_chance(user, damage, damage_source, attacker))) + user.visible_message("\The [user] blocks [attack_text] with \the [src]!") + return 1 + return 0 + +/obj/item/weapon/shield/proc/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) + return base_block_chance + (user.my_skills[SKILL(melee)].level*10)//Skills aren't base 100 anymore, so I'm multiplying by 10. + +/obj/item/weapon/shield/riot + name = "riot shield" + desc = "A shield adept at blocking blunt objects from connecting with the torso of the shield wielder." + icon = 'icons/obj/weapons.dmi' + icon_state = "riot" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BACK + force = 5.0 + throwforce = 5.0 + throw_speed = 1 + throw_range = 4 + w_class = ITEM_SIZE_HUGE + origin_tech = list(TECH_MATERIAL = 2) + matter = list("glass" = 7500, DEFAULT_WALL_MATERIAL = 1000) + attack_verb = list("shoved", "bashed") + var/cooldown = 0 //shield bash cooldown. based on world.time + +/obj/item/weapon/shield/riot/handle_shield(mob/living/user) + . = ..() + if(.) playsound(user.loc, 'sound/effects/shieldhitmetal.ogg', 50, 1) + +/obj/item/weapon/shield/riot/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) + if(istype(damage_source, /obj/item/projectile)) + var/obj/item/projectile/P = damage_source + //metal shields do not stop bullets or lasers, even in space. Will block beanbags, rubber bullets, and stunshots just fine though. + if((is_sharp(P) && damage > 10) || istype(P, /obj/item/projectile/beam)) + return 0 + return base_block_chance + +/obj/item/weapon/shield/riot/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/melee/classic_baton)) + if(cooldown < world.time - 25) + user.visible_message("[user] bashes [src] with [W]!") + playsound(user.loc, 'sound/effects/shieldbashmetal.ogg', 50, 1) + cooldown = world.time + else + ..() + +/obj/item/weapon/shield/buckler + name = "buckler" + desc = "A wooden buckler used to block sharp things from entering your body back in the day.." + icon = 'icons/obj/weapons.dmi' + icon_state = "buckler" + slot_flags = SLOT_BACK + force = 8 + throwforce = 8 + base_block_chance = 60 + throw_speed = 10 + throw_range = 20 + w_class = ITEM_SIZE_HUGE + origin_tech = list(TECH_MATERIAL = 1) + matter = list(DEFAULT_WALL_MATERIAL = 1000, "Wood" = 1000) + attack_verb = list("shoved", "bashed") + +/obj/item/weapon/shield/buckler/handle_shield(mob/living/user) + . = ..() + if(.) playsound(user.loc, 'sound/items/buckler_block.ogg', 50, 1) + +/obj/item/weapon/shield/buckler/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) + if(istype(damage_source, /obj/item/projectile)) + return 0 //No blocking bullets, I'm afraid. + return base_block_chance + +/* + * Energy Shield + */ + +/obj/item/weapon/shield/energy + name = "energy combat shield" + desc = "A shield capable of stopping most projectile and melee attacks. It can be retracted, expanded, and stored anywhere." + icon = 'icons/obj/weapons.dmi' + icon_state = "eshield0" // eshield1 for expanded + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 3.0 + throwforce = 5.0 + throw_speed = 1 + throw_range = 4 + w_class = ITEM_SIZE_SMALL + origin_tech = list(TECH_MATERIAL = 4, TECH_MAGNET = 3, TECH_ILLEGAL = 4) + attack_verb = list("shoved", "bashed") + var/active = 0 + +/obj/item/weapon/shield/energy/handle_shield(mob/living/user) + if(!active) + return 0 //turn it on first! + . = ..() + + if(.) + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, user.loc) + spark_system.start() + playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) + +/obj/item/weapon/shield/energy/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) + if(istype(damage_source, /obj/item/projectile)) + var/obj/item/projectile/P = damage_source + if((is_sharp(P) && damage > 10) || istype(P, /obj/item/projectile/beam)) + return (base_block_chance - round(damage / 3)) //block bullets and beams using the old block chance + return base_block_chance + +/obj/item/weapon/shield/energy/attack_self(mob/living/user as mob) + if ((CLUMSY in user.mutations) && prob(50)) + to_chat(user, "You beat yourself in the head with [src].") + user.take_organ_damage(5) + active = !active + if (active) + force = 10 + update_icon() + w_class = ITEM_SIZE_HUGE + playsound(user, 'sound/weapons/saberon.ogg', 50, 1) + to_chat(user, "\The [src] is now active.") + + else + force = 3 + update_icon() + w_class = ITEM_SIZE_TINY + playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) + to_chat(user, "\The [src] can now be concealed.") + + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + H.update_inv_l_hand() + H.update_inv_r_hand() + + add_fingerprint(user) + return + +/obj/item/weapon/shield/energy/update_icon() + icon_state = "eshield[active]" + if(active) + set_light(1.5, 1.5, "#006aff") + else + set_light(0) + diff --git a/code/game/objects/items/weapons/soap.dm b/code/game/objects/items/weapons/soap.dm new file mode 100644 index 00000000..b401f9f5 --- /dev/null +++ b/code/game/objects/items/weapons/soap.dm @@ -0,0 +1,91 @@ +/obj/item/weapon/soap + name = "soap" + desc = "A cheap bar of soap. Doesn't smell." + gender = PLURAL + icon = 'icons/obj/items.dmi' + icon_state = "soap" + atom_flags = ATOM_FLAG_OPEN_CONTAINER + w_class = ITEM_SIZE_SMALL + throwforce = 0 + throw_speed = 4 + throw_range = 20 + var/key_data + +/obj/item/weapon/soap/New() + ..() + create_reagents(30) + wet() + +/obj/item/weapon/soap/proc/wet() + reagents.add_reagent(/datum/reagent/space_cleaner, 15) + +/obj/item/weapon/soap/Crossed(AM as mob|obj) + if (istype(AM, /mob/living)) + var/mob/living/M = AM + M.slip("the [src.name]",3) + +/obj/item/weapon/soap/afterattack(atom/target, mob/user as mob, proximity) + if(!proximity) return + //I couldn't feasibly fix the overlay bugs caused by cleaning items we are wearing. + //So this is a workaround. This also makes more sense from an IC standpoint. ~Carn + if(user.client && (target in user.client.screen)) + to_chat(user, "You need to take that [target.name] off before cleaning it.") + else if(istype(target,/obj/effect/decal/cleanable/blood)) + to_chat(user, "You scrub \the [target.name] out.") + target.clean_blood() //Blood is a cleanable decal, therefore needs to be accounted for before all cleanable decals. + else if(istype(target,/obj/effect/decal/cleanable)) + to_chat(user, "You scrub \the [target.name] out.") + qdel(target) + else if(istype(target,/turf)) + to_chat(user, "You scrub \the [target.name] clean.") + var/turf/T = target + T.clean(src, user) + else if(istype(target,/obj/structure/sink)) + to_chat(user, "You wet \the [src] in the sink.") + wet() + else + to_chat(user, "You clean \the [target.name].") + target.clean_blood() //Clean bloodied atoms. Blood decals themselves need to be handled above. + return + +//attack_as_weapon +/obj/item/weapon/soap/attack(mob/living/target, mob/living/user, var/target_zone) + if(target && user && ishuman(target) && ishuman(user) && !target.stat && !user.stat && user.zone_sel &&user.zone_sel.selecting == BP_MOUTH) + user.visible_message("\The [user] washes \the [target]'s mouth out with soap!") + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) //prevent spam + return + ..() + +/obj/item/weapon/soap/attackby(var/obj/item/I, var/mob/user) + if(istype(I, /obj/item/weapon/key)) + if(!key_data) + to_chat(user, "You imprint \the [I] into \the [src].") + var/obj/item/weapon/key/K = I + key_data = K.key_data + update_icon() + return + ..() + +/obj/item/weapon/soap/update_icon() + overlays.Cut() + if(key_data) + overlays += image('icons/obj/items.dmi', icon_state = "soap_key_overlay") + +/obj/item/weapon/soap/nanotrasen + desc = "A NanoTrasen-brand bar of soap. Smells of phoron." + icon_state = "soapnt" + +/obj/item/weapon/soap/deluxe + icon_state = "soapdeluxe" + +/obj/item/weapon/soap/deluxe/New() + desc = "A deluxe Waffle Co. brand bar of soap. Smells of [pick("lavender", "vanilla", "strawberry", "chocolate" ,"space")]." + ..() + +/obj/item/weapon/soap/syndie + desc = "An untrustworthy bar of soap. Smells of fear." + icon_state = "soapsyndie" + +/obj/item/weapon/soap/gold + desc = "One true soap to rule them all." + icon_state = "soapgold" diff --git a/code/game/objects/items/weapons/staff.dm b/code/game/objects/items/weapons/staff.dm new file mode 100644 index 00000000..ce15c77a --- /dev/null +++ b/code/game/objects/items/weapons/staff.dm @@ -0,0 +1,24 @@ +/obj/item/weapon/staff + name = "wizards staff" + desc = "Apparently a staff used by the wizard." + icon = 'icons/obj/wizard.dmi' + icon_state = "staff" + force = 3.0 + throwforce = 5.0 + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_SMALL + attack_verb = list("bludgeoned", "whacked", "disciplined") + +/obj/item/weapon/staff/broom + name = "broom" + desc = "Used for sweeping, and flying into the night while cackling. Black cat not included." + icon = 'icons/obj/wizard.dmi' + icon_state = "broom" + +/obj/item/weapon/staff/gentcane + name = "Gentlemans Cane" + desc = "An ebony can with an ivory tip." + icon = 'icons/obj/weapons.dmi' + icon_state = "cane" + item_state = "stick" \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/backpack.dm b/code/game/objects/items/weapons/storage/backpack.dm new file mode 100644 index 00000000..dc16c357 --- /dev/null +++ b/code/game/objects/items/weapons/storage/backpack.dm @@ -0,0 +1,422 @@ + +/* + * Backpack + */ + +/obj/item/weapon/storage/backpack + name = "backpack" + desc = "You wear this on your back and put items into it." + item_icons = list( + slot_l_hand_str = 'icons/mob/onmob/items/lefthand_backpacks.dmi', + slot_r_hand_str = 'icons/mob/onmob/items/righthand_backpacks.dmi', + ) + icon_state = "backpack" + item_state = null + //most backpacks use the default backpack state for inhand overlays + item_state_slots = list( + slot_l_hand_str = "backpack", + slot_r_hand_str = "backpack", + ) + w_class = ITEM_SIZE_HUGE + slot_flags = SLOT_BACK + max_w_class = ITEM_SIZE_LARGE + max_storage_space = DEFAULT_BACKPACK_STORAGE + var/is_satchel = FALSE //A bit hacky yeah, but satchels carry less so whatever. + +/obj/item/weapon/storage/backpack/equipped() + if(!has_extension(src, /datum/extension/appearance)) + set_extension(src, /datum/extension/appearance, /datum/extension/appearance/cardborg) + ..() + +/obj/item/weapon/storage/backpack/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (src.use_sound) + playsound(src.loc, src.use_sound, 50, 1, -5) + return ..() + +/obj/item/weapon/storage/backpack/equipped(var/mob/user, var/slot) + if (slot == slot_back && src.use_sound) + playsound(src.loc, src.use_sound, 50, 1, -5) + close(user) + ..(user, slot) + + +/obj/item/weapon/storage/backpack/attack_hand(mob/user) + if(src == user.back && !is_satchel) // you have to hold backpacks, sorry my guys + to_chat(user, "You cannot reach into \the [src] while it's on your back.") + return + ..() + + +/* + * Backpack Types + */ + +/obj/item/weapon/storage/backpack/holding + name = "bag of holding" + desc = "A backpack that opens into a localized pocket of Blue Space." + origin_tech = list(TECH_BLUESPACE = 4) + icon_state = "holdingpack" + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = 56 + + New() + ..() + return + + attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/storage/backpack/holding)) + to_chat(user, "The Bluespace interfaces of the two devices conflict and malfunction.") + qdel(W) + return 1 + return ..() + + //Please don't clutter the parent storage item with stupid hacks. + can_be_inserted(obj/item/W as obj, stop_messages = 0) + if(istype(W, /obj/item/weapon/storage/backpack/holding)) + return 1 + return ..() + +/obj/item/weapon/storage/backpack/santabag + name = "\improper Santa's gift bag" + desc = "Space Santa uses this to deliver toys to all the nice children in space for Christmas! Wow, it's pretty big!" + icon_state = "giftbag0" + item_state = "giftbag" + w_class = ITEM_SIZE_HUGE + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = 400 // can store a ton of shit! + item_state_slots = null + +/obj/item/weapon/storage/backpack/cultpack + name = "trophy rack" + desc = "It's useful for both carrying extra gear and proudly declaring your insanity." + icon_state = "cultpack" + +/obj/item/weapon/storage/backpack/clown + name = "Giggles von Honkerton" + desc = "It's a backpack made by Honk! Co." + icon_state = "clownpack" + item_state_slots = null + +/obj/item/weapon/storage/backpack/medic + name = "medical backpack" + desc = "It's a backpack especially designed for use in a sterile environment." + icon_state = "medicalpack" + item_state_slots = null + +/obj/item/weapon/storage/backpack/security + name = "security backpack" + desc = "It's a very robust backpack." + icon_state = "securitypack" + item_state_slots = null + +/obj/item/weapon/storage/backpack/captain + name = "captain's backpack" + desc = "It's a special backpack made exclusively for officers." + icon_state = "captainpack" + item_state_slots = null + +/obj/item/weapon/storage/backpack/industrial + name = "industrial backpack" + desc = "It's a tough backpack for the daily grind of industrial life." + icon_state = "engiepack" + item_state_slots = null + +/obj/item/weapon/storage/backpack/toxins + name = "\improper NanoTrasen backpack" + desc = "It's a light backpack modeled for use in laboratories and other scientific institutions. The colors on it denote it as a NanoTrasen backpack." + icon_state = "ntpack" + +/obj/item/weapon/storage/backpack/hydroponics + name = "herbalist's backpack" + desc = "It's a green backpack with many pockets to store plants and tools in." + icon_state = "hydpack" + +/obj/item/weapon/storage/backpack/genetics + name = "geneticist backpack" + desc = "It's a backpack fitted with slots for diskettes and other workplace tools." + icon_state = "genpack" + +/obj/item/weapon/storage/backpack/virology + name = "sterile backpack" + desc = "It's a sterile backpack able to withstand different pathogens from entering its fabric." + icon_state = "viropack" + +/obj/item/weapon/storage/backpack/chemistry + name = "chemistry backpack" + desc = "It's an orange backpack which was designed to hold beakers, pill bottles and bottles." + icon_state = "chempack" + +/* + * Duffle Types + */ + +/obj/item/weapon/storage/backpack/dufflebag + name = "dufflebag" + desc = "A large dufflebag for holding extra things." + icon_state = "duffle" + item_state_slots = null + w_class = ITEM_SIZE_HUGE + max_storage_space = DEFAULT_BACKPACK_STORAGE + 10 + +/obj/item/weapon/storage/backpack/dufflebag/New() + ..() + slowdown_per_slot[slot_back] = 3 + slowdown_per_slot[slot_r_hand] = 1 + slowdown_per_slot[slot_l_hand] = 1 + +/obj/item/weapon/storage/backpack/dufflebag/syndie + name = "black dufflebag" + desc = "A large dufflebag for holding extra tactical supplies." + icon_state = "duffle_syndie" + +/obj/item/weapon/storage/backpack/dufflebag/syndie/New() + ..() + slowdown_per_slot[slot_back] = 1 + +/obj/item/weapon/storage/backpack/dufflebag/syndie/med + name = "medical dufflebag" + desc = "A large dufflebag for holding extra tactical medical supplies." + icon_state = "duffle_syndiemed" + +/obj/item/weapon/storage/backpack/dufflebag/syndie/ammo + name = "ammunition dufflebag" + desc = "A large dufflebag for holding extra weapons ammunition and supplies." + icon_state = "duffle_syndieammo" + +/obj/item/weapon/storage/backpack/dufflebag/captain + name = "captain's dufflebag" + desc = "A large dufflebag for holding extra captainly goods." + icon_state = "duffle_captain" + +/obj/item/weapon/storage/backpack/dufflebag/med + name = "medical dufflebag" + desc = "A large dufflebag for holding extra medical supplies." + icon_state = "duffle_med" + +/obj/item/weapon/storage/backpack/dufflebag/sec + name = "security dufflebag" + desc = "A large dufflebag for holding extra security supplies and ammunition." + icon_state = "duffle_sec" + +/obj/item/weapon/storage/backpack/dufflebag/eng + name = "industrial dufflebag" + desc = "A large dufflebag for holding extra tools and supplies." + icon_state = "duffle_eng" + +/* + * Satchel Types + */ + +/obj/item/weapon/storage/backpack/satchel + name = "satchel" + desc = "A trendy looking satchel." + icon_state = "satchel-norm" + max_storage_space = DEFAULT_BOX_STORAGE + slot_flags = SLOT_BACK|SLOT_S_STORE//In your back or your second back slot. Backpacks can only go in the main one though. + is_satchel = TRUE + +/obj/item/weapon/storage/backpack/satchel/warfare + desc = "Fit for war, and not much else." + icon_state = "warfare_satchel" + +/obj/item/weapon/storage/backpack/satchel/warfare/chestrig + name = "Chestrig" + desc = "Holds ammo and other goodies. But not a lot of it." + icon_state = "chestrig" + +/obj/item/weapon/storage/backpack/warfare + desc = "Holds more than a satchel, but can't open it on your back." + icon_state = "warfare_backpack" + +/obj/item/weapon/storage/backpack/satchel/grey + name = "grey satchel" + +/obj/item/weapon/storage/backpack/satchel/grey/withwallet + startswith = list(/obj/item/weapon/storage/wallet/random) + +/obj/item/weapon/storage/backpack/satchel/leather //brown, master type + name = "brown leather satchel" + desc = "A very fancy satchel made of some kind of leather." + icon_state = "satchel" + color = "#3d2711" + +/obj/item/weapon/storage/backpack/satchel/leather/khaki + name = "khaki leather satchel" + color = "#baa481" + +/obj/item/weapon/storage/backpack/satchel/leather/black + name = "black leather satchel" + color = "#212121" + +/obj/item/weapon/storage/backpack/satchel/leather/navy + name = "navy leather satchel" + color = "#1c2133" + +/obj/item/weapon/storage/backpack/satchel/leather/olive + name = "olive leather satchel" + color = "#544f3d" + +/obj/item/weapon/storage/backpack/satchel/leather/reddish + name = "auburn leather satchel" + color = "#512828" + +/obj/item/weapon/storage/backpack/satchel/pocketbook //black, master type + name = "black pocketbook" + desc = "A neat little folding clasp pocketbook with a shoulder sling." + icon_state = "pocketbook" + w_class = ITEM_SIZE_HUGE // to avoid recursive backpacks + slot_flags = SLOT_BACK + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = DEFAULT_LARGEBOX_STORAGE + color = "#212121" + +/obj/item/weapon/storage/backpack/satchel/pocketbook/brown + name = "brown pocketbook" + color = "#3d2711" + +/obj/item/weapon/storage/backpack/satchel/pocketbook/reddish + name = "auburn pocketbook" + color = "#512828" + +/obj/item/weapon/storage/backpack/satchel/satchel_eng + name = "industrial satchel" + desc = "A tough satchel with extra pockets." + icon_state = "satchel-eng" + item_state_slots = list( + slot_l_hand_str = "engiepack", + slot_r_hand_str = "engiepack", + ) + +/obj/item/weapon/storage/backpack/satchel/satchel_med + name = "medical satchel" + desc = "A sterile satchel used in medical departments." + icon_state = "satchel-med" + item_state_slots = list( + slot_l_hand_str = "medicalpack", + slot_r_hand_str = "medicalpack", + ) + +/obj/item/weapon/storage/backpack/satchel/satchel_vir + name = "virologist satchel" + desc = "A sterile satchel with virologist colours." + icon_state = "satchel-vir" + +/obj/item/weapon/storage/backpack/satchel/satchel_chem + name = "chemist satchel" + desc = "A sterile satchel with chemist colours." + icon_state = "satchel-chem" + +/obj/item/weapon/storage/backpack/satchel/satchel_gen + name = "geneticist satchel" + desc = "A sterile satchel with geneticist colours." + icon_state = "satchel-gen" + +/obj/item/weapon/storage/backpack/satchel/satchel_tox + name = "\improper NanoTrasen satchel" + desc = "Useful for holding research materials. The colors on it denote it as a NanoTrasen bag." + icon_state = "satchel-nt" + +/obj/item/weapon/storage/backpack/satchel/satchel_sec + name = "security satchel" + desc = "A robust satchel for security related needs." + icon_state = "satchel-sec" + item_state_slots = list( + slot_l_hand_str = "securitypack", + slot_r_hand_str = "securitypack", + ) + +/obj/item/weapon/storage/backpack/satchel/satchel_hyd + name = "hydroponics satchel" + desc = "A green satchel for plant related work." + icon_state = "satchel_hyd" + +/obj/item/weapon/storage/backpack/satchel/satchel_cap + name = "captain's satchel" + desc = "An exclusive satchel for officers." + icon_state = "satchel-cap" + item_state_slots = list( + slot_l_hand_str = "satchel-cap", + slot_r_hand_str = "satchel-cap", + ) + +//ERT backpacks. +/obj/item/weapon/storage/backpack/ert + name = "emergency response team backpack" + desc = "A spacious backpack with lots of pockets, used by members of the Emergency Response Team." + icon_state = "ert_commander" + item_state_slots = list( + slot_l_hand_str = "securitypack", + slot_r_hand_str = "securitypack", + ) + +//Commander +/obj/item/weapon/storage/backpack/ert/commander + name = "emergency response team commander backpack" + desc = "A spacious backpack with lots of pockets, worn by the commander of an Emergency Response Team." + +//Security +/obj/item/weapon/storage/backpack/ert/security + name = "emergency response team security backpack" + desc = "A spacious backpack with lots of pockets, worn by security members of an Emergency Response Team." + icon_state = "ert_security" + +//Engineering +/obj/item/weapon/storage/backpack/ert/engineer + name = "emergency response team engineer backpack" + desc = "A spacious backpack with lots of pockets, worn by engineering members of an Emergency Response Team." + icon_state = "ert_engineering" + +//Medical +/obj/item/weapon/storage/backpack/ert/medical + name = "emergency response team medical backpack" + desc = "A spacious backpack with lots of pockets, worn by medical members of an Emergency Response Team." + icon_state = "ert_medical" + +/* + * Messenger Bags + */ + +/obj/item/weapon/storage/backpack/messenger + name = "messenger bag" + desc = "A sturdy backpack worn over one shoulder." + icon_state = "courierbag" + +/obj/item/weapon/storage/backpack/messenger/chem + name = "chemistry messenger bag" + desc = "A serile backpack worn over one shoulder. This one is in Chemsitry colors." + icon_state = "courierbagchem" + +/obj/item/weapon/storage/backpack/messenger/med + name = "medical messenger bag" + desc = "A sterile backpack worn over one shoulder used in medical departments." + icon_state = "courierbagmed" + +/obj/item/weapon/storage/backpack/messenger/viro + name = "virology messenger bag" + desc = "A sterile backpack worn over one shoulder. This one is in Virology colors." + icon_state = "courierbagviro" + +/obj/item/weapon/storage/backpack/messenger/tox + name = "\improper NanoTrasen messenger bag" + desc = "A backpack worn over one shoulder. Useful for holding science materials. The colors on it denote it as a NanoTrasen bag." + icon_state = "courierbagnt" + +/obj/item/weapon/storage/backpack/messenger/com + name = "captain's messenger bag" + desc = "A special backpack worn over one shoulder. This one is made specifically for officers." + icon_state = "courierbagcom" + +/obj/item/weapon/storage/backpack/messenger/engi + name = "engineering messenger bag" + desc = "A strong backpack worn over one shoulder. This one is designed for Industrial work." + icon_state = "courierbagengi" + +/obj/item/weapon/storage/backpack/messenger/hyd + name = "hydroponics messenger bag" + desc = "A backpack worn over one shoulder. This one is designed for plant-related work." + icon_state = "courierbaghyd" + +/obj/item/weapon/storage/backpack/messenger/sec + name = "security messenger bag" + desc = "A tactical backpack worn over one shoulder. This one is in Security colors." + icon_state = "courierbagsec" diff --git a/code/game/objects/items/weapons/storage/bags.dm b/code/game/objects/items/weapons/storage/bags.dm new file mode 100644 index 00000000..b5625bb8 --- /dev/null +++ b/code/game/objects/items/weapons/storage/bags.dm @@ -0,0 +1,92 @@ +/* + Represents flexible bags that expand based on the size of their contents. +*/ +/obj/item/weapon/storage/bag + allow_quick_gather = 1 + allow_quick_empty = 1 + use_to_pickup = 1 + slot_flags = SLOT_BELT + +/obj/item/weapon/storage/bag/handle_item_insertion(obj/item/W as obj, prevent_warning = 0) + . = ..() + if(.) update_w_class() + +/obj/item/weapon/storage/bag/remove_from_storage(obj/item/W as obj, atom/new_location) + . = ..() + if(.) update_w_class() + +/obj/item/weapon/storage/bag/can_be_inserted(obj/item/W, mob/user, stop_messages = 0) + if(istype(src.loc, /obj/item/weapon/storage)) + if(!stop_messages) + to_chat(user, "Take [src] out of [src.loc] first.") + return 0 //causes problems if the bag expands and becomes larger than src.loc can hold, so disallow it + . = ..() + +/obj/item/weapon/storage/bag/proc/update_w_class() + w_class = initial(w_class) + for(var/obj/item/I in contents) + w_class = max(w_class, I.w_class) + + var/cur_storage_space = storage_space_used() + while(base_storage_capacity(w_class) < cur_storage_space) + w_class++ + +/obj/item/weapon/storage/bag/get_storage_cost() + var/used_ratio = storage_space_used()/max_storage_space + return max(base_storage_cost(w_class), round(used_ratio*base_storage_cost(max_w_class), 1)) + +// ----------------------------- +// Trash bag +// ----------------------------- +/obj/item/weapon/storage/bag/trash + name = "trash bag" + desc = "It's the heavy-duty black polymer kind. Time to take out the trash!" + icon = 'icons/obj/janitor.dmi' + icon_state = "trashbag0" + item_state = "trashbag" + + w_class = ITEM_SIZE_SMALL + max_w_class = ITEM_SIZE_HUGE //can fit a backpack inside a trash bag, seems right + max_storage_space = DEFAULT_BACKPACK_STORAGE + can_hold = list() // any + +/obj/item/weapon/storage/bag/trash/update_w_class() + ..() + update_icon() + +/obj/item/weapon/storage/bag/trash/update_icon() + switch(w_class) + if(2) icon_state = "trashbag0" + if(3) icon_state = "trashbag1" + if(4) icon_state = "trashbag2" + if(5 to INFINITY) icon_state = "trashbag3" + +// ----------------------------- +// Plastic Bag +// ----------------------------- + +/obj/item/weapon/storage/bag/plasticbag + name = "plastic bag" + desc = "It's a very flimsy, very noisy alternative to a bag." + icon = 'icons/obj/trash.dmi' + icon_state = "plasticbag" + item_state = "plasticbag" + + w_class = ITEM_SIZE_TINY + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = DEFAULT_BOX_STORAGE + can_hold = list() // any + +// ----------------------------- +// Cash Bag +// ----------------------------- + +/obj/item/weapon/storage/bag/cash + name = "cash bag" + icon = 'icons/obj/storage.dmi' + icon_state = "cashbag" + desc = "A bag for carrying lots of cash. It's got a big dollar sign printed on the front." + max_storage_space = 100 + max_w_class = ITEM_SIZE_HUGE + w_class = ITEM_SIZE_SMALL + can_hold = list(/obj/item/weapon/coin,/obj/item/weapon/spacecash) diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm new file mode 100644 index 00000000..cb1cac94 --- /dev/null +++ b/code/game/objects/items/weapons/storage/belt.dm @@ -0,0 +1,228 @@ +/obj/item/weapon/storage/belt + name = "belt" + desc = "Can hold various things." + icon = 'icons/obj/clothing/belts.dmi' + icon_state = "utilitybelt" + item_state = "utility" + //storage_slots = 7 + max_storage_space = DEFAULT_BOX_STORAGE + max_w_class = ITEM_SIZE_NORMAL + slot_flags = SLOT_BELT + attack_verb = list("whipped", "lashed", "disciplined") + +/obj/item/weapon/storage/belt/verb/toggle_layer() + set name = "Switch Belt Layer" + set category = "Object" + + use_alt_layer = !use_alt_layer + update_icon() + +/obj/item/weapon/storage/update_icon() + if (ismob(src.loc)) + var/mob/M = src.loc + M.update_inv_belt() + + +/obj/item/weapon/storage/belt/get_mob_overlay(mob/user_mob, slot) + var/image/ret = ..() + if(slot == slot_belt_str && contents.len) + for(var/obj/item/I in contents) + ret.overlays += image("icon" = 'icons/mob/onmob/belt.dmi', "icon_state" = "[I.item_state ? I.item_state : I.icon_state]") + return ret + +/obj/item/weapon/storage/belt/utility + name = "tool-belt" + desc = "A belt of durable leather, festooned with hooks, slots, and pouches." + description_info = "The tool-belt has enough slots to carry a full engineer's toolset: screwdriver, crowbar, wrench, welder, cable coil, and multitool. Simply click the belt to move a tool to one of its slots." + description_fluff = "Good hide is hard to come by in certain regions of the galaxy. When they can't come across it, most TSCs will outfit their crews with toolbelts made of synthesized leather." + description_antag = "Only amateurs skip grabbing a tool-belt." + icon_state = "utilitybelt" + item_state = "utility" + can_hold = list( + ///obj/item/weapon/combitool, + /obj/item/weapon/crowbar, + /obj/item/weapon/screwdriver, + /obj/item/weapon/weldingtool, + /obj/item/weapon/wirecutters, + /obj/item/weapon/wrench, + /obj/item/device/multitool, + /obj/item/device/flashlight, + /obj/item/stack/cable_coil, + /obj/item/device/t_scanner, + /obj/item/device/analyzer, + /obj/item/taperoll/engineering, + /obj/item/device/robotanalyzer, + /obj/item/weapon/material/minihoe, + /obj/item/weapon/material/hatchet, + /obj/item/device/analyzer/plant_analyzer, + /obj/item/taperoll, + /obj/item/weapon/extinguisher/mini, + /obj/item/weapon/marshalling_wand + ) + + +/obj/item/weapon/storage/belt/utility/full/New() + ..() + new /obj/item/weapon/screwdriver(src) + new /obj/item/weapon/wrench(src) + new /obj/item/weapon/weldingtool(src) + new /obj/item/weapon/crowbar(src) + new /obj/item/weapon/wirecutters(src) + new /obj/item/stack/cable_coil(src,30,pick("red","yellow","orange")) + + +/obj/item/weapon/storage/belt/utility/atmostech/New() + ..() + new /obj/item/weapon/screwdriver(src) + new /obj/item/weapon/wrench(src) + new /obj/item/weapon/weldingtool(src) + new /obj/item/weapon/crowbar(src) + new /obj/item/weapon/wirecutters(src) + new /obj/item/device/t_scanner(src) + + + +/obj/item/weapon/storage/belt/medical + name = "medical belt" + desc = "Can hold various medical equipment." + icon_state = "medicalbelt" + item_state = "medical" + can_hold = list( + /obj/item/device/healthanalyzer, + /obj/item/weapon/reagent_containers/dropper, + /obj/item/weapon/reagent_containers/glass/beaker, + /obj/item/weapon/reagent_containers/glass/bottle, + /obj/item/weapon/reagent_containers/pill, + /obj/item/weapon/reagent_containers/syringe, + /obj/item/weapon/flame/lighter/zippo, + /obj/item/weapon/storage/fancy/cigarettes, + /obj/item/weapon/storage/pill_bottle, + /obj/item/stack/medical, + /obj/item/device/flashlight/pen, + /obj/item/clothing/mask/surgical, + /obj/item/clothing/head/surgery, + /obj/item/clothing/gloves/latex, + /obj/item/weapon/reagent_containers/hypospray, + /obj/item/clothing/glasses/hud/health, + /obj/item/weapon/crowbar, + /obj/item/device/flashlight, + /obj/item/taperoll, + /obj/item/weapon/extinguisher/mini, + /obj/item/weapon/wirecutters, + /obj/item/weapon/reagent_containers/glass/ampule, + /obj/item/weapon/suture + ) + +/obj/item/weapon/storage/belt/medical/full + icon_state = "warfare_belt" + item_state = "warfare_belt" + max_storage_space = 16 + +/obj/item/weapon/storage/belt/medical/full/New() + ..() + new /obj/item/weapon/reagent_containers/hypospray/autoinjector/blood(src) + new /obj/item/weapon/reagent_containers/hypospray/autoinjector/revive(src) + new /obj/item/weapon/reagent_containers/hypospray/autoinjector/revive(src) + new /obj/item/weapon/reagent_containers/hypospray/autoinjector/morphine(src) + new /obj/item/weapon/reagent_containers/glass/ampule/morphine(src) + new /obj/item/weapon/suture(src) + new /obj/item/weapon/wirecutters(src) + new /obj/item/device/healthanalyzer(src) + +/obj/item/weapon/storage/belt/medical/emt + name = "EMT utility belt" + desc = "A sturdy black webbing belt with attached pouches." + icon_state = "emsbelt" + item_state = "emsbelt" + +/obj/item/weapon/storage/belt/security + name = "security belt" + desc = "Can hold security gear like handcuffs and flashes." + icon_state = "securitybelt" + item_state = "security" + can_hold = list( + /obj/item/weapon/crowbar, + /obj/item/weapon/grenade, + /obj/item/weapon/reagent_containers/spray/pepper, + /obj/item/weapon/handcuffs, + /obj/item/device/flash, + /obj/item/clothing/glasses, + /obj/item/ammo_casing/shotgun, + /obj/item/ammo_magazine, + /obj/item/weapon/reagent_containers/food/snacks/donut/, + /obj/item/weapon/melee/baton, + /obj/item/weapon/gun/energy/taser, + /obj/item/weapon/gun/energy/stunrevolver, + /obj/item/weapon/flame/lighter, + /obj/item/clothing/glasses/hud/security, + /obj/item/device/flashlight, + /obj/item/device/pda, + /obj/item/device/radio/headset, + /obj/item/device/hailer, + /obj/item/device/megaphone, + /obj/item/weapon/melee, + /obj/item/weapon/gun/projectile/sec, + /obj/item/taperoll, + /obj/item/device/holowarrant, + /obj/item/weapon/magnetic_ammo + ) + +/obj/item/weapon/storage/belt/soulstone + name = "soul stone belt" + desc = "Designed for ease of access to the shards during a fight, as to not let a single enemy spirit slip away." + icon_state = "soulstonebelt" + item_state = "soulstonebelt" + storage_slots = 6 + can_hold = list( + /obj/item/device/soulstone + ) + +/obj/item/weapon/storage/belt/soulstone/full/New() + ..() + new /obj/item/device/soulstone(src) + new /obj/item/device/soulstone(src) + new /obj/item/device/soulstone(src) + new /obj/item/device/soulstone(src) + new /obj/item/device/soulstone(src) + new /obj/item/device/soulstone(src) + + +/obj/item/weapon/storage/belt/champion + name = "championship belt" + desc = "Proves to the world that you are the strongest!" + icon_state = "championbelt" + item_state = "champion" + storage_slots = 1 + can_hold = list( + /obj/item/clothing/mask/luchador + ) + +/obj/item/weapon/storage/belt/security/tactical + name = "combat belt" + desc = "Can hold security gear like handcuffs and flashes, with more pouches for more storage." + icon_state = "swatbelt" + item_state = "swatbelt" + storage_slots = 9 + +/obj/item/weapon/storage/belt/waistpack + name = "waist pack" + desc = "A small bag designed to be worn on the waist. May make your butt look big." + icon_state = "fannypack_white" + item_state = "fannypack_white" + storage_slots = null + max_w_class = ITEM_SIZE_SMALL + max_storage_space = ITEM_SIZE_SMALL * 4 + slot_flags = SLOT_BELT | SLOT_BACK + +/obj/item/weapon/storage/belt/waistpack/big + name = "large waist pack" + desc = "An bag designed to be worn on the waist. Definitely makes your butt look big." + icon_state = "fannypack_big_white" + item_state = "fannypack_big_white" + w_class = ITEM_SIZE_LARGE + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = ITEM_SIZE_NORMAL * 4 + +/obj/item/weapon/storage/belt/waistpack/big/New() + ..() + slowdown_per_slot[slot_belt] = 3 \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/bible.dm b/code/game/objects/items/weapons/storage/bible.dm new file mode 100644 index 00000000..0d89bf04 --- /dev/null +++ b/code/game/objects/items/weapons/storage/bible.dm @@ -0,0 +1,36 @@ +/obj/item/weapon/storage/bible + name = "bible" + desc = "Apply to head repeatedly." + icon_state ="bible" + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_NORMAL + max_w_class = ITEM_SIZE_SMALL + max_storage_space = 4 + var/mob/affecting = null + var/deity_name = "Christ" + +/obj/item/weapon/storage/bible/booze + name = "bible" + desc = "To be applied to the head repeatedly." + icon_state ="bible" + + startswith = list( + /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer, + /obj/item/weapon/spacecash/bundle/c50, + /obj/item/weapon/spacecash/bundle/c50, + ) + +/obj/item/weapon/storage/bible/afterattack(atom/A, mob/user as mob, proximity) + if(!proximity) return + if(user.mind && (user.mind.assigned_role == "Chaplain")) + if(A.reagents && A.reagents.has_reagent(/datum/reagent/water)) //blesses all the water in the holder + to_chat(user, "You bless \the [A].") // I wish it was this easy in nethack + var/water2holy = A.reagents.get_reagent_amount(/datum/reagent/water) + A.reagents.del_reagent(/datum/reagent/water) + A.reagents.add_reagent(/datum/reagent/water/holywater,water2holy) + +/obj/item/weapon/storage/bible/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (src.use_sound) + playsound(src.loc, src.use_sound, 50, 1, -5) + return ..() diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm new file mode 100644 index 00000000..109e489f --- /dev/null +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -0,0 +1,501 @@ +/* + * Everything derived from the common cardboard box. + * Basically everything except the original is a kit (starts full). + * + * Contains: + * Empty box, starter boxes (survival/engineer), + * Latex glove and sterile mask boxes, + * Syringe, beaker, dna injector boxes, + * Blanks, flashbangs, and EMP grenade boxes, + * Tracking and chemical implant boxes, + * Prescription glasses and drinking glass boxes, + * Condiment bottle and silly cup boxes, + * Donkpocket and monkeycube boxes, + * ID and security PDA cart boxes, + * Handcuff, mousetrap, and pillbottle boxes, + * Snap-pops and matchboxes, + * Replacement light boxes. + * + * For syndicate call-ins see uplink_kits.dm + */ + +/obj/item/weapon/storage/box + name = "box" + desc = "It's just an ordinary box." + icon_state = "box" + item_state = "syringe_kit" + max_storage_space = DEFAULT_BOX_STORAGE + var/foldable = /obj/item/stack/material/cardboard // BubbleWrap - if set, can be folded (when empty) into a sheet of cardboard + +/obj/item/weapon/storage/box/large + name = "large box" + icon_state = "largebox" + w_class = ITEM_SIZE_LARGE + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = DEFAULT_LARGEBOX_STORAGE + +// BubbleWrap - A box can be folded up to make card +/obj/item/weapon/storage/box/attack_self(mob/user as mob) + if(..()) return + + //try to fold it. + if ( contents.len ) + return + + if ( !ispath(src.foldable) ) + return + var/found = 0 + // Close any open UI windows first + for(var/mob/M in range(1)) + if (M.s_active == src) + src.close(M) + if ( M == user ) + found = 1 + if ( !found ) // User is too far away + return + // Now make the cardboard + to_chat(user, "You fold [src] flat.") + if(ispath(foldable, /obj/item/stack)) + var/stack_amt = max(2**(w_class - 3), 1) + new src.foldable(get_turf(src), stack_amt) + else + new src.foldable(get_turf(src)) + qdel(src) + +/obj/item/weapon/storage/box/make_exact_fit() + ..() + foldable = null //special form fitted boxes should not be foldable. + +/obj/item/weapon/storage/box/survival/ + name = "crew survival kit" + desc = "A box decorated in warning colors that contains a limited supply of survival tools. The panel and white stripe indicate this one contains oxygen." + icon_state = "survival" + startswith = list(/obj/item/clothing/mask/breath = 1, + /obj/item/weapon/tank/emergency/oxygen = 1, + /obj/item/weapon/reagent_containers/hypospray/autoinjector = 1, + /obj/item/stack/medical/bruise_pack = 1, + /obj/item/device/flashlight/glowstick = 1, + /obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar = 1) + +/obj/item/weapon/storage/box/vox/ + name = "vox survival kit" + desc = "A box decorated in warning colors that contains a limited supply of survival tools. The panel and black stripe indicate this one contains nitrogen." + icon_state = "survivalvox" + startswith = list(/obj/item/clothing/mask/breath = 1, + /obj/item/weapon/tank/emergency/nitrogen = 1, + /obj/item/stack/medical/bruise_pack = 1, + /obj/item/device/flashlight/glowstick = 1, + /obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar = 1) + +/obj/item/weapon/storage/box/engineer/ + name = "engineer survival kit" + desc = "A box decorated in warning colors that contains a limited supply of survival tools. The panel and orange stripe indicate this one as the engineering variant." + icon_state = "survivaleng" + startswith = list(/obj/item/clothing/mask/breath = 1, + /obj/item/weapon/tank/emergency/oxygen/engi = 1, + /obj/item/weapon/reagent_containers/hypospray/autoinjector = 1, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/detox = 1, + /obj/item/stack/medical/bruise_pack = 1, + /obj/item/device/flashlight/glowstick = 1, + /obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar = 1) + +/obj/item/weapon/storage/box/gloves + name = "box of sterile gloves" + desc = "Contains sterile gloves." + icon_state = "latex" + startswith = list(/obj/item/clothing/gloves/latex = 5, + /obj/item/clothing/gloves/latex/nitrile = 2) + +/obj/item/weapon/storage/box/masks + name = "box of sterile masks" + desc = "This box contains masks of sterility." + icon_state = "sterile" + startswith = list(/obj/item/clothing/mask/surgical = 7) + + +/obj/item/weapon/storage/box/syringes + name = "box of syringes" + desc = "A box full of syringes." + icon_state = "syringe" + startswith = list(/obj/item/weapon/reagent_containers/syringe = 7) + +/obj/item/weapon/storage/box/syringegun + name = "box of syringe gun cartridges" + desc = "A box full of compressed gas cartridges." + icon_state = "syringe" + startswith = list(/obj/item/weapon/syringe_cartridge = 7) + + +/obj/item/weapon/storage/box/beakers + name = "box of beakers" + icon_state = "beaker" + startswith = list(/obj/item/weapon/reagent_containers/glass/beaker = 7) + +/obj/item/weapon/storage/box/blanks + name = "box of blank shells" + desc = "It has a picture of a gun and several warning symbols on the front." + startswith = list(/obj/item/ammo_casing/shotgun/blank = 7) + +/obj/item/weapon/storage/box/beanbags + name = "box of beanbag shells" + desc = "It has a picture of a gun and several warning symbols on the front.
            WARNING: Live ammunition. Misuse may result in serious injury or death." + startswith = list(/obj/item/ammo_casing/shotgun/beanbag = 7) + +/obj/item/weapon/storage/box/shotgunammo + name = "box of shotgun slugs" + desc = "It has a picture of a gun and several warning symbols on the front.
            WARNING: Live ammunition. Misuse may result in serious injury or death." + startswith = list(/obj/item/ammo_casing/shotgun = 7) + +/obj/item/weapon/storage/box/shotgunshells + name = "box of shotgun shells" + desc = "It has a picture of a gun and several warning symbols on the front.
            WARNING: Live ammunition. Misuse may result in serious injury or death." + startswith = list(/obj/item/ammo_casing/shotgun/pellet = 7) + +/obj/item/weapon/storage/box/flashshells + name = "box of illumination shells" + desc = "It has a picture of a gun and several warning symbols on the front.
            WARNING: Live ammunition. Misuse may result in serious injury or death." + startswith = list(/obj/item/ammo_casing/shotgun/flash = 7) + +/obj/item/weapon/storage/box/stunshells + name = "box of stun shells" + desc = "It has a picture of a gun and several warning symbols on the front.
            WARNING: Live ammunition. Misuse may result in serious injury or death." + startswith = list(/obj/item/ammo_casing/shotgun/stunshell = 7) + +/obj/item/weapon/storage/box/practiceshells + name = "box of practice shells" + desc = "It has a picture of a gun and several warning symbols on the front.
            WARNING: Live ammunition. Misuse may result in serious injury or death." + startswith = list(/obj/item/ammo_casing/shotgun/practice = 7) + +/obj/item/weapon/storage/box/sniperammo + name = "box of 14.5mm shells" + desc = "It has a picture of a gun and several warning symbols on the front.
            WARNING: Live ammunition. Misuse may result in serious injury or death." + startswith = list(/obj/item/ammo_casing/a145 = 7) + +/obj/item/weapon/storage/box/sniperammo/apds + name = "box of 14.5mm APDS shells" + startswith = list(/obj/item/ammo_casing/a145/apds = 3) + +/obj/item/weapon/storage/box/flashbangs + name = "box of flashbangs" + desc = "A box containing 7 antipersonnel flashbang grenades.
            WARNING: These devices are extremely dangerous and can cause blindness or deafness from repeated use." + icon_state = "flashbang" + startswith = list(/obj/item/weapon/grenade/flashbang = 7) + +/obj/item/weapon/storage/box/teargas + name = "box of pepperspray grenades" + desc = "A box containing 7 tear gas grenades. A gas mask is printed on the label.
            WARNING: Exposure carries risk of serious injury or death. Keep away from persons with lung conditions." + icon_state = "flashbang" + startswith = list(/obj/item/weapon/grenade/chem_grenade/teargas = 7) + +/obj/item/weapon/storage/box/emps + name = "box of emp grenades" + desc = "A box containing 5 military grade EMP grenades.
            WARNING: Do not use near unshielded electronics or biomechanical augmentations, death or permanent paralysis may occur." + icon_state = "flashbang" + startswith = list(/obj/item/weapon/grenade/empgrenade = 5) + +/obj/item/weapon/storage/box/frags + name = "box of frag grenades" + desc = "A box containing 5 military grade fragmentation grenades.
            WARNING: Live explosives. Misuse may result in serious injury or death." + icon_state = "flashbang" + startswith = list(/obj/item/weapon/grenade/frag = 5) + +/obj/item/weapon/storage/box/fragshells + name = "box of frag shells" + desc = "A box containing 5 military grade fragmentation shells.
            WARNING: Live explosive munitions. Misuse may result in serious injury or death." + icon_state = "flashbang" + startswith = list(/obj/item/weapon/grenade/frag/shell = 5) + +/obj/item/weapon/storage/box/smokes + name = "box of smoke bombs" + desc = "A box containing 5 smoke bombs." + icon_state = "flashbang" + startswith = list(/obj/item/weapon/grenade/smokebomb = 5) + +/obj/item/weapon/storage/box/anti_photons + name = "box of anti-photon grenades" + desc = "A box containing 5 experimental photon disruption grenades." + icon_state = "flashbang" + startswith = list(/obj/item/weapon/grenade/anti_photon = 5) + +/obj/item/weapon/storage/box/supermatters + name = "box of supermatter grenades" + desc = "A box containing 5 highly experimental supermatter grenades." + icon_state = "radbox" + startswith = list(/obj/item/weapon/grenade/supermatter = 5) + +/obj/item/weapon/storage/box/trackimp + name = "boxed tracking implant kit" + desc = "Box full of scum-bag tracking utensils." + icon_state = "implant" + startswith = list(/obj/item/weapon/implantcase/tracking = 4, + /obj/item/weapon/implanter = 1, + /obj/item/weapon/implantpad = 1, + /obj/item/weapon/locator = 1) + +/obj/item/weapon/storage/box/chemimp + name = "boxed chemical implant kit" + desc = "Box of stuff used to implant chemicals." + icon_state = "implant" + startswith = list(/obj/item/weapon/implantcase/chem = 5, + /obj/item/weapon/implanter = 1, + /obj/item/weapon/implantpad = 1) + +/obj/item/weapon/storage/box/rxglasses + name = "box of prescription glasses" + desc = "This box contains nerd glasses." + icon_state = "glasses" + startswith = list(/obj/item/clothing/glasses/regular = 7) + +/obj/item/weapon/storage/box/cdeathalarm_kit + name = "death alarm kit" + desc = "Box of stuff used to implant death alarms." + icon_state = "implant" + item_state = "syringe_kit" + startswith = list(/obj/item/weapon/implanter = 1, + /obj/item/weapon/implantcase/death_alarm = 6) + +/obj/item/weapon/storage/box/condimentbottles + name = "box of condiment bottles" + desc = "It has a large ketchup smear on it." + startswith = list(/obj/item/weapon/reagent_containers/food/condiment = 6) + +/obj/item/weapon/storage/box/cups + name = "box of paper cups" + desc = "It has pictures of paper cups on the front." + startswith = list(/obj/item/weapon/reagent_containers/food/drinks/sillycup = 7) + +/obj/item/weapon/storage/box/donkpockets + name = "box of donk-pockets" + desc = "Instructions: Heat in microwave. Product will cool if not eaten within seven minutes." + icon_state = "donk_kit" + startswith = list(/obj/item/weapon/reagent_containers/food/snacks/donkpocket = 6) + +/obj/item/weapon/storage/box/sinpockets + name = "box of sin-pockets" + desc = "Instructions: Crush bottom of package to initiate chemical heating. Wait for 20 seconds before consumption. Product will cool if not eaten within seven minutes." + icon_state = "donk_kit" + startswith = list(/obj/item/weapon/reagent_containers/food/snacks/donkpocket/sinpocket = 6) + +/obj/item/weapon/storage/box/monkeycubes + name = "monkey cube box" + desc = "Drymate brand monkey cubes. Just add water!" + icon = 'icons/obj/food.dmi' + icon_state = "monkeycubebox" + can_hold = list(/obj/item/weapon/reagent_containers/food/snacks/monkeycube) + startswith = list(/obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped = 5) + +/obj/item/weapon/storage/box/monkeycubes/farwacubes + name = "farwa cube box" + desc = "Drymate brand farwa cubes, shipped from Ahdomai. Just add water!" + startswith = list(/obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped/farwacube = 5) + +/obj/item/weapon/storage/box/monkeycubes/stokcubes + name = "stok cube box" + desc = "Drymate brand stok cubes, shipped from Moghes. Just add water!" + startswith = list(/obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped/stokcube = 5) + +/obj/item/weapon/storage/box/monkeycubes/neaeracubes + name = "neaera cube box" + desc = "Drymate brand neaera cubes, shipped from Jargon 4. Just add water!" + startswith = list(/obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped/neaeracube = 5) + +/obj/item/weapon/storage/box/ids + name = "box of spare IDs" + desc = "Has so many empty IDs." + icon_state = "id" + startswith = list(/obj/item/weapon/card/id = 7) + +/obj/item/weapon/storage/box/large/ids + name = "box of spare IDs" + desc = "Has so, so many empty IDs." + icon_state = "id_large" + startswith = list(/obj/item/weapon/card/id = 14) + +/obj/item/weapon/storage/box/seccarts + name = "box of spare R.O.B.U.S.T. Cartridges" + desc = "A box full of R.O.B.U.S.T. Cartridges, used by Security." + icon_state = "pda" + startswith = list(/obj/item/weapon/cartridge/security = 7) + +/obj/item/weapon/storage/box/handcuffs + name = "box of spare handcuffs" + desc = "A box full of handcuffs." + icon_state = "handcuff" + startswith = list(/obj/item/weapon/handcuffs = 7) + +/obj/item/weapon/storage/box/mousetraps + name = "box of Pest-B-Gon mousetraps" + desc = "WARNING: Keep out of reach of children." + icon_state = "mousetraps" + startswith = list(/obj/item/device/assembly/mousetrap = 6) + +/obj/item/weapon/storage/box/mousetraps/empty + startswith = null + +/obj/item/weapon/storage/box/pillbottles + name = "box of pill bottles" + desc = "It has pictures of pill bottles on its front." + startswith = list(/obj/item/weapon/storage/pill_bottle = 7) + +/obj/item/weapon/storage/box/snappops + name = "snap pop box" + desc = "Eight wrappers of fun! Ages 8 and up. Not suitable for children." + icon = 'icons/obj/toy.dmi' + icon_state = "spbox" + can_hold = list(/obj/item/toy/snappop) + startswith = list(/obj/item/toy/snappop = 8) + +/obj/item/weapon/storage/box/matches + name = "matchbox" + desc = "A small box of 'Space-Proof' premium matches." + icon = 'icons/obj/cigarettes.dmi' + icon_state = "matchbox" + item_state = "zippo" + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_BELT + can_hold = list(/obj/item/weapon/flame/match) + startswith = list(/obj/item/weapon/flame/match = 10) + + attackby(obj/item/weapon/flame/match/W as obj, mob/user as mob) + if(istype(W) && !W.lit && !W.burnt) + user.visible_message("[user] strikes the match on the matchbox.") + if(prob(50)) + playsound(src.loc, 'sound/items/matchstick_hit.ogg', 60, 1, -4) + return + playsound(src.loc, 'sound/items/matchstick_lit.ogg', 60, 1, -4) + W.lit = 1 + W.damtype = "burn" + W.icon_state = "match_lit" + START_PROCESSING(SSobj, W) + + + W.update_icon() + return + +/obj/item/weapon/storage/box/autoinjectors + name = "box of injectors" + desc = "Contains autoinjectors." + icon_state = "syringe" + + startswith = list(/obj/item/weapon/reagent_containers/hypospray/autoinjector = 7) + +/obj/item/weapon/storage/box/lights + name = "box of replacement bulbs" + icon = 'icons/obj/storage.dmi' + icon_state = "light" + desc = "This box is shaped on the inside so that only light tubes and bulbs fit." + item_state = "syringe_kit" + use_to_pickup = 1 // for picking up broken bulbs, not that most people will try + +/obj/item/weapon/storage/box/lights/Initialize() + . = ..() + make_exact_fit() + +/obj/item/weapon/storage/box/lights/bulbs + startswith = list(/obj/item/weapon/light/bulb = 21) + +/obj/item/weapon/storage/box/lights/bulbs/empty + startswith = null + +/obj/item/weapon/storage/box/lights/tubes + name = "box of replacement tubes" + icon_state = "lighttube" + startswith = list(/obj/item/weapon/light/tube = 17, + /obj/item/weapon/light/tube/large = 4) + +/obj/item/weapon/storage/box/lights/tubes/empty + startswith = null + +/obj/item/weapon/storage/box/lights/mixed + name = "box of replacement lights" + icon_state = "lightmixed" + startswith = list(/obj/item/weapon/light/tube = 12, + /obj/item/weapon/light/tube/large = 4, + /obj/item/weapon/light/bulb = 5) + +/obj/item/weapon/storage/box/lights/mixed/empty + startswith = null + +/obj/item/weapon/storage/box/glowsticks + name = "box of mixed glowsticks" + icon_state = "box" + startswith = list(/obj/item/device/flashlight/glowstick = 1, /obj/item/device/flashlight/glowstick/red = 1, + /obj/item/device/flashlight/glowstick/blue = 1, /obj/item/device/flashlight/glowstick/orange = 1, + /obj/item/device/flashlight/glowstick/yellow = 1, /obj/item/device/flashlight/glowstick/random = 1) + +/obj/item/weapon/storage/box/greenglowsticks + name = "box of green glowsticks" + icon_state = "box" + startswith = list(/obj/item/device/flashlight/glowstick = 6) + +/obj/item/weapon/storage/box/freezer + name = "portable freezer" + desc = "This nifty shock-resistant device will keep your 'groceries' nice and non-spoiled." + icon = 'icons/obj/storage.dmi' + icon_state = "portafreezer" + item_state = "medicalpack" + foldable = null + max_w_class = ITEM_SIZE_NORMAL + w_class = ITEM_SIZE_HUGE + can_hold = list(/obj/item/organ, /obj/item/weapon/reagent_containers/food, /obj/item/weapon/reagent_containers/glass) + max_storage_space = DEFAULT_BACKPACK_STORAGE + use_to_pickup = 1 // for picking up broken bulbs, not that most people will try + +/obj/item/weapon/storage/box/checkers + name = "checkers box" + desc = "This box holds a nifty portion of checkers. Foam-shaped on the inside so that only checkers may fit." + icon_state = "checkers" + max_storage_space = 24 + foldable = null + can_hold = list(/obj/item/weapon/reagent_containers/food/snacks/checker) + startswith = list(/obj/item/weapon/reagent_containers/food/snacks/checker = 12, + /obj/item/weapon/reagent_containers/food/snacks/checker/red = 12) + +/obj/item/weapon/storage/box/checkers/chess + name = "black chess box" + desc = "This box holds all the pieces needed for the black side of the chess board." + icon_state = "chess_b" + startswith = list(/obj/item/weapon/reagent_containers/food/snacks/checker/pawn = 8, + /obj/item/weapon/reagent_containers/food/snacks/checker/knight = 2, + /obj/item/weapon/reagent_containers/food/snacks/checker/bishop = 2, + /obj/item/weapon/reagent_containers/food/snacks/checker/rook = 2, + /obj/item/weapon/reagent_containers/food/snacks/checker/queen = 1, + /obj/item/weapon/reagent_containers/food/snacks/checker/king = 1) + +/obj/item/weapon/storage/box/checkers/chess/red + name = "red chess box" + desc = "This box holds all the pieces needed for the red side of the chess board." + icon_state = "chess_r" + startswith = list(/obj/item/weapon/reagent_containers/food/snacks/checker/pawn/red = 8, + /obj/item/weapon/reagent_containers/food/snacks/checker/knight/red = 2, + /obj/item/weapon/reagent_containers/food/snacks/checker/bishop/red = 2, + /obj/item/weapon/reagent_containers/food/snacks/checker/rook/red = 2, + /obj/item/weapon/reagent_containers/food/snacks/checker/queen/red = 1, + /obj/item/weapon/reagent_containers/food/snacks/checker/king/red = 1) + + +/obj/item/weapon/storage/box/headset + name = "box of spare headsets" + desc = "A box full of headsets." + startswith = list(/obj/item/device/radio/headset = 7) + +//Spare Armbands + +/obj/item/weapon/storage/box/armband/engine + name = "box of spare engineering armbands" + desc = "A box full of engineering armbands. For use in emergencies when provisional engineering peronnel are needed." + startswith = list(/obj/item/clothing/accessory/armband/engine = 5) + +/obj/item/weapon/storage/box/armband/med + name = "box of spare medical armbands" + desc = "A box full of medical armbands. For use in emergencies when provisional medical personnel are needed." + startswith = list(/obj/item/clothing/accessory/armband/med = 5) + +/obj/item/weapon/storage/box/imprinting + name = "box of education implants" + desc = "A box full of neural implants for on-job training." + startswith = list( + /obj/item/weapon/implanter, + /obj/item/weapon/implantpad, + /obj/item/weapon/implantcase/imprinting = 3 + ) \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/briefcase.dm b/code/game/objects/items/weapons/storage/briefcase.dm new file mode 100644 index 00000000..41558f06 --- /dev/null +++ b/code/game/objects/items/weapons/storage/briefcase.dm @@ -0,0 +1,12 @@ +/obj/item/weapon/storage/briefcase + name = "briefcase" + desc = "It's made of AUTHENTIC faux-leather and has a price-tag still attached. Its owner must be a real professional." + icon_state = "briefcase" + item_state = "briefcase" + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 8.0 + throw_speed = 1 + throw_range = 4 + w_class = ITEM_SIZE_HUGE + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = DEFAULT_BACKPACK_STORAGE diff --git a/code/game/objects/items/weapons/storage/fancy.dm b/code/game/objects/items/weapons/storage/fancy.dm new file mode 100644 index 00000000..8904da92 --- /dev/null +++ b/code/game/objects/items/weapons/storage/fancy.dm @@ -0,0 +1,335 @@ +/* + * The 'fancy' path is for objects like candle boxes that show how many items are in the storage item on the sprite itself + * .. Sorry for the shitty path name, I couldnt think of a better one. + * + * + * Contains: + * Egg Box + * Candle Box + * Crayon Box + * Cigarette Box + */ + +/obj/item/weapon/storage/fancy + item_state = "syringe_kit" //placeholder, many of these don't have inhands + var/obj/item/key_type //path of the key item that this "fancy" container is meant to store + var/opened = 0 //if an item has been removed from this container + +/obj/item/weapon/storage/fancy/remove_from_storage() + . = ..() + if(!opened && .) + opened = 1 + update_icon() + + +/obj/item/weapon/storage/fancy/update_icon() + if(!opened) + src.icon_state = initial(icon_state) + else + var/key_count = count_by_type(contents, key_type) + src.icon_state = "[initial(icon_state)][key_count]" + +/obj/item/weapon/storage/fancy/examine(mob/user) + if(!..(user, 1)) + return + + var/key_name = initial(key_type.name) + if(!contents.len) + to_chat(user, "There are no [key_name]s left in the box.") + else + var/key_count = count_by_type(contents, key_type) + to_chat(user, "There [key_count == 1? "is" : "are"] [key_count] [key_name]\s in the box.") + +/* + * Egg Box + */ + +/obj/item/weapon/storage/fancy/egg_box + icon = 'icons/obj/food.dmi' + icon_state = "eggbox" + name = "egg box" + storage_slots = 12 + max_w_class = ITEM_SIZE_SMALL + w_class = ITEM_SIZE_NORMAL + + key_type = /obj/item/weapon/reagent_containers/food/snacks/egg + can_hold = list( + /obj/item/weapon/reagent_containers/food/snacks/egg, + /obj/item/weapon/reagent_containers/food/snacks/boiledegg + ) + + startswith = list(/obj/item/weapon/reagent_containers/food/snacks/egg = 12) + +/obj/item/weapon/storage/fancy/egg_box/empty + startswith = null + + +/* + * Candle Box + */ + +/obj/item/weapon/storage/fancy/candle_box + name = "candle pack" + desc = "A pack of red candles." + icon = 'icons/obj/candle.dmi' + icon_state = "candlebox" + opened = 1 //no closed state + throwforce = 2 + w_class = ITEM_SIZE_SMALL + max_w_class = ITEM_SIZE_TINY + max_storage_space = 5 + slot_flags = SLOT_BELT + + key_type = /obj/item/weapon/flame/candle + startswith = list(/obj/item/weapon/flame/candle = 5) + +/* + * Crayon Box + */ + +/obj/item/weapon/storage/fancy/crayons + name = "box of crayons" + desc = "A box of crayons for all your rune drawing needs." + icon = 'icons/obj/crayons.dmi' + icon_state = "crayonbox" + w_class = ITEM_SIZE_SMALL + max_w_class = ITEM_SIZE_TINY + max_storage_space = 6 + + key_type = /obj/item/weapon/pen/crayon + startswith = list( + /obj/item/weapon/pen/crayon/red, + /obj/item/weapon/pen/crayon/orange, + /obj/item/weapon/pen/crayon/yellow, + /obj/item/weapon/pen/crayon/green, + /obj/item/weapon/pen/crayon/blue, + /obj/item/weapon/pen/crayon/purple, + ) + +/obj/item/weapon/storage/fancy/crayons/update_icon() + overlays = list() //resets list + overlays += image('icons/obj/crayons.dmi',"crayonbox") + for(var/obj/item/weapon/pen/crayon/crayon in contents) + overlays += image('icons/obj/crayons.dmi',crayon.colourName) + +//////////// +//CIG PACK// +//////////// +/obj/item/weapon/storage/fancy/cigarettes + name = "pack of Smokey Boys" + desc = "A ubiquitous brand of cigarettes. As mild and flavorless as it gets." + icon = 'icons/obj/cigarettes.dmi' + icon_state = "cigpacket" + item_state = "cigpacket" + w_class = ITEM_SIZE_SMALL + max_w_class = ITEM_SIZE_TINY + max_storage_space = 6 + throwforce = 2 + slot_flags = SLOT_BELT + + key_type = /obj/item/clothing/mask/smokable/cigarette + startswith = list(/obj/item/clothing/mask/smokable/cigarette = 6) + +/obj/item/weapon/storage/fancy/cigarettes/New() + ..() + atom_flags |= ATOM_FLAG_NO_REACT|ATOM_FLAG_OPEN_CONTAINER + create_reagents(5 * max_storage_space)//so people can inject cigarettes without opening a packet, now with being able to inject the whole one + +/obj/item/weapon/storage/fancy/cigarettes/remove_from_storage(obj/item/W as obj, atom/new_location) + // Don't try to transfer reagents to lighters + if(istype(W, /obj/item/clothing/mask/smokable/cigarette)) + var/obj/item/clothing/mask/smokable/cigarette/C = W + reagents.trans_to_obj(C, (reagents.total_volume/contents.len)) + ..() + +/obj/item/weapon/storage/fancy/cigarettes/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) + if(!istype(M, /mob)) + return + + if(M == user && user.zone_sel.selecting == BP_MOUTH && contents.len > 0 && !user.wear_mask) + // Find ourselves a cig. Note that we could be full of lighters. + var/obj/item/clothing/mask/smokable/cigarette/cig = null + for(var/obj/item/clothing/mask/smokable/cigarette/C in contents) + cig = C + break + + if(cig == null) + to_chat(user, "Looks like the packet is out of cigarettes.") + return + + // Instead of running equip_to_slot_if_possible() we check here first, + // to avoid dousing cig with reagents if we're not going to equip it + if(!cig.mob_can_equip(user, slot_wear_mask)) + return + + // We call remove_from_storage first to manage the reagent transfer and + // UI updates. + remove_from_storage(cig, null) + user.equip_to_slot(cig, slot_wear_mask) + + reagents.maximum_volume = 5 * contents.len + to_chat(user, "You take a cigarette out of the pack.") + update_icon() + else + ..() + +/obj/item/weapon/storage/fancy/cigarettes/dromedaryco + name = "pack of Dromedary Co. cigarettes" + desc = "A packet of six imported Dromedary Company cancer sticks. A label on the packaging reads, \"Wouldn't a slow death make a change?\"." + icon_state = "Dpacket" + startswith = list(/obj/item/clothing/mask/smokable/cigarette/dromedaryco = 6) + +/obj/item/weapon/storage/fancy/cigarettes/killthroat + name = "pack of Acme Co. cigarettes" + desc = "A packet of six Acme Company cigarettes. For those who somehow want to obtain the record for the most amount of cancerous tumors." + icon_state = "Bpacket" + startswith = list(/obj/item/clothing/mask/smokable/cigarette/killthroat = 6) + +/obj/item/weapon/storage/fancy/cigarettes/killthroat/New() + ..() + fill_cigarre_package(src,list(/datum/reagent/fuel = 4)) + +// New exciting ways to kill your lungs! - Earthcrusher // + +/obj/item/weapon/storage/fancy/cigarettes/luckystars + name = "pack of Brouzefs" + desc = "Captain Brouzef's famous cigarettes. It's rumored they're used as currency in the shittier parts of the planet." + icon_state = "LSpacket" + item_state = "Dpacket" //I actually don't mind cig packs not showing up in the hand. whotf doesn't just keep them in their pockets/coats // + startswith = list(/obj/item/clothing/mask/smokable/cigarette/luckystars = 6) + +/obj/item/weapon/storage/fancy/cigarettes/jerichos + name = "pack of Roacheyes" + desc = "Typically seen dangling from the lips of soldiers. Feels like warm liquid death down your lungs." + icon_state = "Jpacket" + item_state = "Dpacket" + startswith = list(/obj/item/clothing/mask/smokable/cigarette/jerichos = 6) + +/obj/item/weapon/storage/fancy/cigarettes/menthols + name = "pack of Temperamento Menthols" + desc = "With a sharp and natural organic menthol flavor, these Temperamentos are a favorite of NDV crews. Hardly anyone knows they make 'em in non-menthol!" + icon_state = "TMpacket" + item_state = "Dpacket" + + key_type = /obj/item/clothing/mask/smokable/cigarette/menthol + startswith = list(/obj/item/clothing/mask/smokable/cigarette/menthol = 6) + +/obj/item/weapon/storage/fancy/cigarettes/carcinomas + name = "pack of Tannhauser Gates" + desc = "Know one really knows who Tannhauser Gate was, or why he sold cigarettes." + icon_state = "CApacket" + item_state = "Dpacket" + startswith = list(/obj/item/clothing/mask/smokable/cigarette/carcinomas = 6) + +/obj/item/weapon/storage/fancy/cigarettes/professionals + name = "pack of Professional 120s" + desc = "Let's face it - if you're smoking these, you're either trying to look upper-class or you're 80 years old. That's the only excuse. They taste disgusting, too." + icon_state = "P100packet" + item_state = "Dpacket" + startswith = list(/obj/item/clothing/mask/smokable/cigarette/professionals = 6) + +//cigarellos +/obj/item/weapon/storage/fancy/cigarettes/cigarello + name = "pack of Trident Original cigars" + desc = "The Trident brand's wood tipped little cigar, favored by the Sol corps diplomatique for their pleasant aroma. Machine made on Mars for over 100 years." + icon_state = "CRpacket" + item_state = "Dpacket" + key_type = /obj/item/clothing/mask/smokable/cigarette/trident + startswith = list(/obj/item/clothing/mask/smokable/cigarette/trident = 5) + +/obj/item/weapon/storage/fancy/cigarettes/cigarello/variety + name = "pack of Trident Fruit cigars" + desc = "The Trident brand's wood tipped little cigar, favored by the Sol corps diplomatique for their pleasant aroma. Machine made on Mars for over 100 years. This is a fruit variety pack." + icon_state = "CRFpacket" + startswith = list( /obj/item/clothing/mask/smokable/cigarette/trident/watermelon, + /obj/item/clothing/mask/smokable/cigarette/trident/orange, + /obj/item/clothing/mask/smokable/cigarette/trident/grape, + /obj/item/clothing/mask/smokable/cigarette/trident/cherry, + /obj/item/clothing/mask/smokable/cigarette/trident/berry) + +/obj/item/weapon/storage/fancy/cigarettes/cigarello/mint + name = "pack of Trident Menthol cigars" + desc = "The Trident brand's wood tipped little cigar, favored by the Sol corps diplomatique for their pleasant aroma. Machine made on Mars for over 100 years. These are the menthol variety." + icon_state = "CRMpacket" + startswith = list(/obj/item/clothing/mask/smokable/cigarette/trident/mint = 5) + +/obj/item/weapon/storage/fancy/cigar + name = "cigar case" + desc = "A case for holding your cigars when you are not smoking them." + icon_state = "cigarcase" + item_state = "cigpacket" + icon = 'icons/obj/cigarettes.dmi' + w_class = ITEM_SIZE_SMALL + max_w_class = ITEM_SIZE_TINY + max_storage_space = 6 + throwforce = 2 + slot_flags = SLOT_BELT + storage_slots = 7 + + key_type = /obj/item/clothing/mask/smokable/cigarette/cigar + startswith = list(/obj/item/clothing/mask/smokable/cigarette/cigar = 6) + +/obj/item/weapon/storage/fancy/cigar/New() + ..() + atom_flags |= ATOM_FLAG_NO_REACT + create_reagents(10 * storage_slots) + +/obj/item/weapon/storage/fancy/cigar/remove_from_storage(obj/item/W as obj, atom/new_location) + var/obj/item/clothing/mask/smokable/cigarette/cigar/C = W + if(!istype(C)) return + reagents.trans_to_obj(C, (reagents.total_volume/contents.len)) + ..() + +/* + * Vial Box + */ + +/obj/item/weapon/storage/fancy/vials + icon = 'icons/obj/vialbox.dmi' + icon_state = "vialbox" + name = "vial storage box" + w_class = ITEM_SIZE_NORMAL + max_w_class = ITEM_SIZE_TINY + storage_slots = 12 + + key_type = /obj/item/weapon/reagent_containers/glass/beaker/vial + startswith = list(/obj/item/weapon/reagent_containers/glass/beaker/vial = 12) + +/obj/item/weapon/storage/fancy/vials/update_icon() + var/key_count = count_by_type(contents, key_type) + src.icon_state = "[initial(icon_state)][Floor(key_count/2)]" + +/* + * Not actually a "fancy" storage... + */ +/obj/item/weapon/storage/lockbox/vials + name = "secure vial storage box" + desc = "A locked box for keeping things away from children." + icon = 'icons/obj/vialbox.dmi' + icon_state = "vialbox0" + item_state = "syringe_kit" + w_class = ITEM_SIZE_NORMAL + max_w_class = ITEM_SIZE_TINY + max_storage_space = null + storage_slots = 12 + req_access = list(access_virology) + +/obj/item/weapon/storage/lockbox/vials/New() + ..() + update_icon() + +/obj/item/weapon/storage/lockbox/vials/update_icon() + var/total_contents = count_by_type(contents, /obj/item/weapon/reagent_containers/glass/beaker/vial) + src.icon_state = "vialbox[Floor(total_contents/2)]" + src.overlays.Cut() + if (!broken) + overlays += image(icon, src, "led[locked]") + if(locked) + overlays += image(icon, src, "cover") + else + overlays += image(icon, src, "ledb") + return + +/obj/item/weapon/storage/lockbox/vials/attackby(obj/item/weapon/W as obj, mob/user as mob) + . = ..() + update_icon() diff --git a/code/game/objects/items/weapons/storage/firstaid.dm b/code/game/objects/items/weapons/storage/firstaid.dm new file mode 100644 index 00000000..b51f428c --- /dev/null +++ b/code/game/objects/items/weapons/storage/firstaid.dm @@ -0,0 +1,276 @@ +/* First aid storage + * Contains: + * First Aid Kits + * Pill Bottles + */ + +/* + * First Aid Kits + */ +/obj/item/weapon/storage/firstaid + name = "first-aid kit" + desc = "It's an emergency medical kit for those serious boo-boos." + icon_state = "firstaid" + throw_speed = 2 + throw_range = 8 + max_w_class = ITEM_SIZE_SMALL + max_storage_space = DEFAULT_BOX_STORAGE + use_sound = 'sound/effects/storage/briefcase.ogg' + +/obj/item/weapon/storage/firstaid/empty + icon_state = "firstaid" + name = "First-Aid (empty)" + +/obj/item/weapon/storage/firstaid/fire + name = "fire first-aid kit" + desc = "It's an emergency medical kit for when the toxins lab -spontaneously- burns down." + icon_state = "ointment" + item_state = "firstaid-ointment" + + startswith = list( + /obj/item/device/healthanalyzer, + /obj/item/weapon/reagent_containers/hypospray/autoinjector, + /obj/item/stack/medical/ointment, + /obj/item/weapon/storage/pill_bottle/kelotane, + /obj/item/weapon/storage/pill_bottle/paracetamol + ) + +/obj/item/weapon/storage/firstaid/fire/New() + ..() + icon_state = pick("ointment","firefirstaid") + +/obj/item/weapon/storage/firstaid/regular + icon_state = "firstaid" + + startswith = list( + /obj/item/stack/medical/bruise_pack = 2, + /obj/item/stack/medical/ointment = 1, + /obj/item/device/healthanalyzer, + /obj/item/weapon/storage/pill_bottle/inaprovaline, + /obj/item/weapon/storage/pill_bottle/antidexafen, + /obj/item/weapon/storage/pill_bottle/paracetamol + ) + +/obj/item/weapon/storage/firstaid/toxin + name = "toxin first aid" + desc = "Used to treat when you have a high amount of toxins in your body." + icon_state = "antitoxin" + item_state = "firstaid-toxin" + + startswith = list( + /obj/item/weapon/reagent_containers/syringe/antitoxin = 3, + /obj/item/weapon/storage/pill_bottle/antitox, + /obj/item/device/healthanalyzer, + ) + +/obj/item/weapon/storage/firstaid/toxin/New() + ..() + icon_state = pick("antitoxin","antitoxfirstaid","antitoxfirstaid2","antitoxfirstaid3") + +/obj/item/weapon/storage/firstaid/o2 + name = "oxygen deprivation first aid" + desc = "A box full of oxygen goodies." + icon_state = "o2" + item_state = "firstaid-o2" + + startswith = list( + /obj/item/weapon/storage/pill_bottle/dexalin, + /obj/item/weapon/reagent_containers/hypospray/autoinjector, + /obj/item/weapon/reagent_containers/syringe/inaprovaline, + /obj/item/device/healthanalyzer, + ) + +/obj/item/weapon/storage/firstaid/adv + name = "advanced first-aid kit" + desc = "Contains advanced medical treatments." + icon_state = "advfirstaid" + item_state = "firstaid-advanced" + + startswith = list( + /obj/item/weapon/reagent_containers/hypospray/autoinjector, + /obj/item/stack/medical/advanced/bruise_pack = 3, + /obj/item/stack/medical/advanced/ointment = 2, + /obj/item/stack/medical/splint + ) + +/obj/item/weapon/storage/firstaid/combat + name = "combat medical kit" + desc = "Contains advanced medical treatments." + icon_state = "bezerk" + item_state = "firstaid-advanced" + + startswith = list( + /obj/item/weapon/storage/pill_bottle/bicaridine, + /obj/item/weapon/storage/pill_bottle/dermaline, + /obj/item/weapon/storage/pill_bottle/dexalin_plus, + /obj/item/weapon/storage/pill_bottle/dylovene, + /obj/item/weapon/storage/pill_bottle/tramadol, + /obj/item/weapon/storage/pill_bottle/spaceacillin, + /obj/item/stack/medical/splint, + ) + +/obj/item/weapon/storage/firstaid/surgery + name = "surgery kit" + desc = "Contains tools for surgery. Has precise foam fitting for safe transport and automatically sterilizes the content between uses." + icon_state = "surgerykit" + item_state = "firstaid-surgery" + + storage_slots = 14 + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = null + + can_hold = list( + /obj/item/weapon/bonesetter, + /obj/item/weapon/cautery, + /obj/item/weapon/circular_saw, + /obj/item/weapon/hemostat, + /obj/item/weapon/retractor, + /obj/item/weapon/scalpel, + /obj/item/weapon/surgicaldrill, + /obj/item/weapon/bonegel, + /obj/item/weapon/suture, + /obj/item/weapon/FixOVein, + /obj/item/stack/medical/advanced/bruise_pack, + /obj/item/stack/nanopaste + ) + + startswith = list( + /obj/item/weapon/bonesetter, + /obj/item/weapon/cautery, + /obj/item/weapon/circular_saw, + /obj/item/weapon/hemostat, + /obj/item/weapon/retractor, + /obj/item/weapon/scalpel, + /obj/item/weapon/surgicaldrill, + /obj/item/weapon/bonegel, + /obj/item/weapon/suture, + /obj/item/stack/medical/advanced/bruise_pack + ) + +/* + * Pill Bottles + */ +/obj/item/weapon/storage/pill_bottle + name = "pill bottle" + desc = "It's an airtight container for storing medication." + icon_state = "pill_canister" + icon = 'icons/obj/chemical.dmi' + item_state = "contsolid" + w_class = ITEM_SIZE_SMALL + max_w_class = ITEM_SIZE_TINY + max_storage_space = 21 + can_hold = list(/obj/item/weapon/reagent_containers/pill,/obj/item/weapon/dice,/obj/item/weapon/paper) + allow_quick_gather = 1 + use_to_pickup = 1 + use_sound = 'sound/effects/storage/pillbottle.ogg' + +/obj/item/weapon/storage/pill_bottle/attack_self(mob/living/user) + if(user.get_inactive_hand()) + to_chat(user, "You need an empty hand to take something out.") + return + if(contents.len) + var/obj/item/I = contents[1] + if(!remove_from_storage(I,user)) + return + if(user.put_in_inactive_hand(I)) + to_chat(user, "You take \the [I] out of \the [src].") + playsound(user, use_sound, 100) + if(iscarbon(user)) + var/mob/living/carbon/C = user + C.swap_hand() + else + I.dropInto(loc) + to_chat(user, "You fumble around with \the [src] and drop \the [I] on the floor.") + else + to_chat(user, "\The [src] is empty.") + +/obj/item/weapon/storage/pill_bottle/antitox + name = "bottle of Dylovene pills" + desc = "Contains pills used to counter toxins." + + startswith = list(/obj/item/weapon/reagent_containers/pill/antitox = 21) + +/obj/item/weapon/storage/pill_bottle/bicaridine + name = "bottle of Bicaridine pills" + desc = "Contains pills used to stabilize the severely injured." + + startswith = list(/obj/item/weapon/reagent_containers/pill/bicaridine = 21) + +/obj/item/weapon/storage/pill_bottle/dexalin_plus + name = "bottle of Dexalin Plus pills" + desc = "Contains pills used to treat extreme cases of oxygen deprivation." + + startswith = list(/obj/item/weapon/reagent_containers/pill/dexalin_plus = 14) + +/obj/item/weapon/storage/pill_bottle/dexalin + name = "bottle of Dexalin pills" + desc = "Contains pills used to treat oxygen deprivation." + + startswith = list(/obj/item/weapon/reagent_containers/pill/dexalin = 21) + +/obj/item/weapon/storage/pill_bottle/dermaline + name = "bottle of Dermaline pills" + desc = "Contains pills used to treat burn wounds." + + startswith = list(/obj/item/weapon/reagent_containers/pill/dermaline = 14) + +/obj/item/weapon/storage/pill_bottle/dylovene + name = "bottle of Dylovene pills" + desc = "Contains pills used to treat toxic substances in the blood." + + startswith = list(/obj/item/weapon/reagent_containers/pill/dylovene = 21) + +/obj/item/weapon/storage/pill_bottle/inaprovaline + name = "bottle of Inaprovaline pills" + desc = "Contains pills used to stabilize patients." + + startswith = list(/obj/item/weapon/reagent_containers/pill/inaprovaline = 21) + +/obj/item/weapon/storage/pill_bottle/kelotane + name = "bottle of kelotane pills" + desc = "Contains pills used to treat burns." + + startswith = list(/obj/item/weapon/reagent_containers/pill/kelotane = 21) + +/obj/item/weapon/storage/pill_bottle/spaceacillin + name = "bottle of Spaceacillin pills" + desc = "A theta-lactam antibiotic. Effective against many diseases likely to be encountered in space." + + startswith = list(/obj/item/weapon/reagent_containers/pill/spaceacillin = 14) + +/obj/item/weapon/storage/pill_bottle/tramadol + name = "bottle of Tramadol pills" + desc = "Contains pills used to relieve pain." + + startswith = list(/obj/item/weapon/reagent_containers/pill/tramadol = 14) + +//Baycode specific Psychiatry pills. +/obj/item/weapon/storage/pill_bottle/citalopram + name = "bottle of Citalopram pills" + desc = "Mild antidepressant. For use in individuals suffering from depression or anxiety. 15u dose per pill." + + startswith = list(/obj/item/weapon/reagent_containers/pill/citalopram = 21) + +/obj/item/weapon/storage/pill_bottle/methylphenidate + name = "bottle of Methylphenidate pills" + desc = "Mental stimulant. For use in individuals suffering from ADHD, or general concentration issues. 15u dose per pill." + + startswith = list(/obj/item/weapon/reagent_containers/pill/methylphenidate = 21) + +/obj/item/weapon/storage/pill_bottle/paroxetine + name = "bottle of Paroxetine pills" + desc = "High-strength antidepressant. Only for use in severe depression. 10u dose per pill. WARNING: side-effects may include hallucinations." + + startswith = list(/obj/item/weapon/reagent_containers/pill/paroxetine = 14) + +/obj/item/weapon/storage/pill_bottle/antidexafen + name = "bottle of cold medicine pills" + desc = "All-in-one cold medicine. 15u dose per pill. Safe for babies like you!" + + startswith = list(/obj/item/weapon/reagent_containers/pill/antidexafen = 21) + +/obj/item/weapon/storage/pill_bottle/paracetamol + name = "bottle of paracetamol" + desc = "Mild painkiller, also known as Tylenol. Won't fix the cause of your headache (unlike cyanide), but might make it bearable." + + startswith = list(/obj/item/weapon/reagent_containers/pill/paracetamol = 21) diff --git a/code/game/objects/items/weapons/storage/internal.dm b/code/game/objects/items/weapons/storage/internal.dm new file mode 100644 index 00000000..4df324a1 --- /dev/null +++ b/code/game/objects/items/weapons/storage/internal.dm @@ -0,0 +1,99 @@ +//A storage item intended to be used by other items to provide storage functionality. +//Types that use this should consider overriding emp_act() and hear_talk(), unless they shield their contents somehow. +/obj/item/weapon/storage/internal + var/obj/item/master_item + +/obj/item/weapon/storage/internal/New(obj/item/MI) + master_item = MI + loc = master_item + name = master_item.name + ..() + +/obj/item/weapon/storage/internal/Destroy() + master_item = null + . = ..() + +/obj/item/weapon/storage/internal/attack_hand() + return //make sure this is never picked up + +/obj/item/weapon/storage/internal/mob_can_equip() + return 0 //make sure this is never picked up + +//Helper procs to cleanly implement internal storages - storage items that provide inventory slots for other items. +//These procs are completely optional, it is up to the master item to decide when it's storage get's opened by calling open() +//However they are helpful for allowing the master item to pretend it is a storage item itself. +//If you are using these you will probably want to override attackby() as well. +//See /obj/item/clothing/suit/storage for an example. + +//items that use internal storage have the option of calling this to emulate default storage MouseDrop behaviour. +//returns 1 if the master item's parent's MouseDrop() should be called, 0 otherwise. It's strange, but no other way of +//doing it without the ability to call another proc's parent, really. +/obj/item/weapon/storage/internal/proc/handle_mousedrop(mob/user as mob, obj/over_object as obj) + if (ishuman(user) || issmall(user)) //so monkeys can take off their backpacks -- Urist + + if (istype(user.loc,/obj/mecha)) // stops inventory actions in a mech + return 0 + + if(over_object == user && Adjacent(user)) // this must come before the screen objects only block + src.open(user) + return 0 + + if (!( istype(over_object, /obj/screen) )) + return 1 + + //makes sure master_item is equipped before putting it in hand, so that we can't drag it into our hand from miles away. + //there's got to be a better way of doing this... + if (!(master_item.loc == user) || (master_item.loc && master_item.loc.loc == user)) + return 0 + + //TODO make this less terrible + if (!( user.restrained() ) && !( user.stat )) + switch(over_object.name) + if(BP_R_HAND) + if(user.unEquip(master_item)) + user.put_in_r_hand(master_item) + if(BP_L_HAND) + if(user.unEquip(master_item)) + user.put_in_l_hand(master_item) + master_item.add_fingerprint(user) + return 0 + return 0 + +//items that use internal storage have the option of calling this to emulate default storage attack_hand behaviour. +//returns 1 if the master item's parent's attack_hand() should be called, 0 otherwise. +//It's strange, but no other way of doing it without the ability to call another proc's parent, really. +/obj/item/weapon/storage/internal/proc/handle_attack_hand(mob/user as mob) + + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.l_store == master_item && !H.get_active_hand()) //Prevents opening if it's in a pocket. + H.put_in_hands(master_item) + H.l_store = null + return 0 + if(H.r_store == master_item && !H.get_active_hand()) + H.put_in_hands(master_item) + H.r_store = null + return 0 + + src.add_fingerprint(user) + if (master_item.loc == user) + src.open(user) + return 0 + + for(var/mob/M in range(1, master_item.loc)) + if (M.s_active == src) + src.close(M) + return 1 + +/obj/item/weapon/storage/internal/Adjacent(var/atom/neighbor) + return master_item.Adjacent(neighbor) + +// Used by webbings, coat pockets, etc +/obj/item/weapon/storage/internal/pockets/New(var/newloc, var/slots, var/slot_size) + storage_slots = slots + max_w_class = slot_size + ..() + +/obj/item/weapon/storage/internal/pouch/New(var/newloc, var/storage_space) + max_storage_space = storage_space + ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/laundry_basket.dm b/code/game/objects/items/weapons/storage/laundry_basket.dm new file mode 100644 index 00000000..b9bb8373 --- /dev/null +++ b/code/game/objects/items/weapons/storage/laundry_basket.dm @@ -0,0 +1,88 @@ +// ----------------------------- +// 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 = ITEM_SIZE_GARGANTUAN + max_w_class = ITEM_SIZE_HUGE + max_storage_space = DEFAULT_BACKPACK_STORAGE //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(BP_R_HAND) + if (user.hand) + temp = H.get_organ(BP_L_HAND) + if(!temp) + to_chat(user, "You need two hands to pick this up!") + return + + if(user.get_inactive_hand()) + to_chat(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) + to_chat(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.SetName("[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/lockbox.dm b/code/game/objects/items/weapons/storage/lockbox.dm new file mode 100644 index 00000000..65f0786b --- /dev/null +++ b/code/game/objects/items/weapons/storage/lockbox.dm @@ -0,0 +1,95 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/obj/item/weapon/storage/lockbox + name = "lockbox" + desc = "A locked box." + icon_state = "lockbox+l" + item_state = "syringe_kit" + w_class = ITEM_SIZE_HUGE + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = 32 //The sum of the w_classes of all the items in this storage item. + req_access = list(access_armory) + var/locked = 1 + var/broken = 0 + var/icon_locked = "lockbox+l" + var/icon_closed = "lockbox" + var/icon_broken = "lockbox+b" + + + attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/card/id)) + if(src.broken) + to_chat(user, "It appears to be broken.") + return + if(src.allowed(user)) + src.locked = !( src.locked ) + if(src.locked) + src.icon_state = src.icon_locked + to_chat(user, "You lock \the [src]!") + close_all() + return + else + src.icon_state = src.icon_closed + to_chat(user, "You unlock \the [src]!") + return + else + to_chat(user, "Access Denied") + else if(istype(W, /obj/item/weapon/melee/energy/blade)) + if(emag_act(INFINITY, user, W, "The locker has been sliced open by [user] with an energy blade!", "You hear metal being sliced and sparks flying.")) + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, src.loc) + spark_system.start() + playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1) + playsound(src.loc, "sparks", 50, 1) + if(!locked) + ..() + else + to_chat(user, "It's locked!") + return + + + show_to(mob/user as mob) + if(locked) + to_chat(user, "It's locked!") + else + ..() + return + +/obj/item/weapon/storage/lockbox/emag_act(var/remaining_charges, var/mob/user, var/emag_source, var/visual_feedback = "", var/audible_feedback = "") + if(!broken) + if(visual_feedback) + visual_feedback = "[visual_feedback]" + else + visual_feedback = "The locker has been sliced open by [user] with an electromagnetic card!" + if(audible_feedback) + audible_feedback = "[audible_feedback]" + else + audible_feedback = "You hear a faint electrical spark." + + broken = 1 + locked = 0 + desc = "It appears to be broken." + icon_state = src.icon_broken + visible_message(visual_feedback, audible_feedback) + return 1 + +/obj/item/weapon/storage/lockbox/loyalty + name = "lockbox of loyalty implants" + req_access = list(access_security) + + New() + ..() + new /obj/item/weapon/implantcase/loyalty(src) + new /obj/item/weapon/implantcase/loyalty(src) + new /obj/item/weapon/implantcase/loyalty(src) + new /obj/item/weapon/implanter/loyalty(src) + + +/obj/item/weapon/storage/lockbox/clusterbang + name = "lockbox of clusterbangs" + desc = "You have a bad feeling about opening this." + req_access = list(access_security) + + New() + ..() + new /obj/item/weapon/grenade/flashbang/clusterbang(src) diff --git a/code/game/objects/items/weapons/storage/lunchbox.dm b/code/game/objects/items/weapons/storage/lunchbox.dm new file mode 100644 index 00000000..ba8b1ff3 --- /dev/null +++ b/code/game/objects/items/weapons/storage/lunchbox.dm @@ -0,0 +1,101 @@ +/obj/item/weapon/storage/lunchbox + max_storage_space = 8 //slightly smaller than a toolbox + name = "rainbow lunchbox" + icon_state = "lunchbox_rainbow" + item_state = "toolbox_pink" + desc = "A little lunchbox. This one is the colors of the rainbow!" + w_class = ITEM_SIZE_NORMAL + max_w_class = ITEM_SIZE_SMALL + var/filled = FALSE + attack_verb = list("lunched") + +/obj/item/weapon/storage/lunchbox/New() + ..() + if(filled) + var/list/lunches = lunchables_lunches() + var/lunch = lunches[pick(lunches)] + new lunch(src) + + var/list/snacks = lunchables_snacks() + var/snack = snacks[pick(snacks)] + new snack(src) + + var/list/drinks = lunchables_drinks() + var/drink = drinks[pick(drinks)] + new drink(src) + +/obj/item/weapon/storage/lunchbox/filled + filled = TRUE + +/obj/item/weapon/storage/lunchbox/heart + name = "heart lunchbox" + icon_state = "lunchbox_lovelyhearts" + item_state = "toolbox_pink" + desc = "A little lunchbox. This one has cute little hearts on it!" + +/obj/item/weapon/storage/lunchbox/heart/filled + filled = TRUE + +/obj/item/weapon/storage/lunchbox/cat + name = "cat lunchbox" + icon_state = "lunchbox_sciencecatshow" + item_state = "toolbox_green" + desc = "A little lunchbox. This one has a cute little science cat from a popular show on it!" + +/obj/item/weapon/storage/lunchbox/cat/filled + filled = TRUE + +/obj/item/weapon/storage/lunchbox/nt + name = "NanoTrasen brand lunchbox" + icon_state = "lunchbox_nanotrasen" + item_state = "toolbox_blue" + desc = "A little lunchbox. This one is branded with the Nanotrasen logo!" + +/obj/item/weapon/storage/lunchbox/nt/filled + filled = TRUE + +/obj/item/weapon/storage/lunchbox/mars + name = "\improper Mariner University lunchbox" + icon_state = "lunchbox_marsuniversity" + item_state = "toolbox_red" + desc = "A little lunchbox. This one is branded with the Mariner university logo!" + +/obj/item/weapon/storage/lunchbox/mars/filled + filled = TRUE + +/obj/item/weapon/storage/lunchbox/cti + name = "\improper CTI lunchbox" + icon_state = "lunchbox_cti" + item_state = "toolbox_blue" + desc = "A little lunchbox. This one is branded with the CTI logo!" + +/obj/item/weapon/storage/lunchbox/cti/filled + filled = TRUE + +/obj/item/weapon/storage/lunchbox/nymph + name = "\improper Diona nymph lunchbox" + icon_state = "lunchbox_dionanymph" + item_state = "toolbox_yellow" + desc = "A little lunchbox. This one is an adorable Diona nymph on the side!" + +/obj/item/weapon/storage/lunchbox/nymph/filled + filled = TRUE + +/obj/item/weapon/storage/lunchbox/syndicate + name = "black and red lunchbox" + icon_state = "lunchbox_syndie" + item_state = "toolbox_syndi" + desc = "A little lunchbox. This one is a sleek black and red, made of a durable steel!" + +/obj/item/weapon/storage/lunchbox/syndicate/filled + filled = TRUE + +/obj/item/weapon/storage/lunchbox/TCC + name = "\improper TCC lunchbox" + icon_state = "lunchbox_tcc" + item_state = "toolbox_syndi" + desc = "A little lunchbox. This one is branded with the flag of the Terran Colonial Confederation!" + +/obj/item/weapon/storage/lunchbox/syndicate/filled + filled = TRUE + diff --git a/code/game/objects/items/weapons/storage/misc.dm b/code/game/objects/items/weapons/storage/misc.dm new file mode 100644 index 00000000..dd910a32 --- /dev/null +++ b/code/game/objects/items/weapons/storage/misc.dm @@ -0,0 +1,49 @@ +/obj/item/weapon/storage/pill_bottle/dice //7d6 + name = "bag of dice" + desc = "It's a small bag with dice inside." + icon = 'icons/obj/dice.dmi' + icon_state = "dicebag" + +/obj/item/weapon/storage/pill_bottle/dice/New() + ..() + for(var/i = 1 to 7) + new /obj/item/weapon/dice( src ) + +/obj/item/weapon/storage/pill_bottle/dice_nerd //DnD dice + name = "bag of gaming dice" + desc = "It's a small bag with gaming dice inside." + icon = 'icons/obj/dice.dmi' + icon_state = "magicdicebag" + +/obj/item/weapon/storage/pill_bottle/dice_nerd/New() + ..() + new /obj/item/weapon/dice/d4( src ) + new /obj/item/weapon/dice( src ) + new /obj/item/weapon/dice/d8( src ) + new /obj/item/weapon/dice/d10( src ) + new /obj/item/weapon/dice/d12( src ) + new /obj/item/weapon/dice/d20( src ) + new /obj/item/weapon/dice/d100( src ) + +/* + * Donut Box + */ + +/obj/item/weapon/storage/box/donut + icon = 'icons/obj/food.dmi' + icon_state = "donutbox" + name = "donut box" + can_hold = list(/obj/item/weapon/reagent_containers/food/snacks/donut) + foldable = /obj/item/stack/material/cardboard + + startswith = list(/obj/item/weapon/reagent_containers/food/snacks/donut/normal = 6) + +/obj/item/weapon/storage/box/donut/update_icon() + overlays.Cut() + var/i = 0 + for(var/obj/item/weapon/reagent_containers/food/snacks/donut/D in contents) + overlays += image('icons/obj/food.dmi', "[i][D.overlay_state]") + i++ + +/obj/item/weapon/storage/box/donut/empty + startswith = null diff --git a/code/game/objects/items/weapons/storage/secure.dm b/code/game/objects/items/weapons/storage/secure.dm new file mode 100644 index 00000000..11243bff --- /dev/null +++ b/code/game/objects/items/weapons/storage/secure.dm @@ -0,0 +1,197 @@ +/* + * Absorbs /obj/item/weapon/secstorage. + * Reimplements it only slightly to use existing storage functionality. + * + * Contains: + * Secure Briefcase + * Wall Safe + */ + +// ----------------------------- +// Generic Item +// ----------------------------- +/obj/item/weapon/storage/secure + name = "secstorage" + var/icon_locking = "secureb" + var/icon_sparking = "securespark" + var/icon_opened = "secure0" + var/locked = 1 + var/code = "" + var/l_code = null + var/l_set = 0 + var/l_setshort = 0 + var/l_hacking = 0 + var/emagged = 0 + var/open = 0 + w_class = ITEM_SIZE_NORMAL + max_w_class = ITEM_SIZE_SMALL + max_storage_space = DEFAULT_BOX_STORAGE + + examine(mob/user) + if(..(user, 1)) + to_chat(user, text("The service panel is [src.open ? "open" : "closed"].")) + + attackby(obj/item/weapon/W as obj, mob/user as mob) + if(locked) + if (istype(W, /obj/item/weapon/melee/energy/blade) && emag_act(INFINITY, user, "You slice through the lock of \the [src]")) + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, src.loc) + spark_system.start() + playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1) + playsound(src.loc, "sparks", 50, 1) + return + + if(isScrewdriver(W)) + if (do_after(user, 20, src)) + src.open =! src.open + user.show_message(text("You [] the service panel.", (src.open ? "open" : "close"))) + return + if(isMultitool(W) && (src.open == 1)&& (!src.l_hacking)) + user.show_message("Now attempting to reset internal memory, please hold.", 1) + src.l_hacking = 1 + if (do_after(usr, 100, src)) + if (prob(40)) + src.l_setshort = 1 + src.l_set = 0 + user.show_message("Internal memory reset. Please give it a few seconds to reinitialize.", 1) + sleep(80) + src.l_setshort = 0 + src.l_hacking = 0 + else + user.show_message("Unable to reset internal memory.", 1) + src.l_hacking = 0 + else src.l_hacking = 0 + return + //At this point you have exhausted all the special things to do when locked + // ... but it's still locked. + return + + // -> storage/attackby() what with handle insertion, etc + ..() + + + MouseDrop(over_object, src_location, over_location) + if (locked) + src.add_fingerprint(usr) + return + ..() + + + attack_self(mob/user as mob) + user.set_machine(src) + var/dat = text("[]
            \n\nLock Status: []",src, (src.locked ? "LOCKED" : "UNLOCKED")) + var/message = "Code" + if ((src.l_set == 0) && (!src.emagged) && (!src.l_setshort)) + dat += text("

            \n5-DIGIT PASSCODE NOT SET.
            ENTER NEW PASSCODE.
            ") + if (src.emagged) + dat += text("

            \nLOCKING SYSTEM ERROR - 1701") + if (src.l_setshort) + dat += text("

            \nALERT: MEMORY SYSTEM ERROR - 6040 201") + message = text("[]", src.code) + if (!src.locked) + message = "*****" + dat += text("


            \n>[]
            \n1-2-3
            \n4-5-6
            \n7-8-9
            \nR-0-E
            \n
            ", message, src, src, src, src, src, src, src, src, src, src, src, src) + user << browse(dat, "window=caselock;size=300x280") + + Topic(href, href_list) + ..() + if ((usr.stat || usr.restrained()) || (get_dist(src, usr) > 1)) + return + if (href_list["type"]) + if (href_list["type"] == "E") + if ((src.l_set == 0) && (length(src.code) == 5) && (!src.l_setshort) && (src.code != "ERROR")) + src.l_code = src.code + src.l_set = 1 + else if ((src.code == src.l_code) && (src.emagged == 0) && (src.l_set == 1)) + src.locked = 0 + src.overlays = null + overlays += image('icons/obj/storage.dmi', icon_opened) + src.code = null + else + src.code = "ERROR" + else + if ((href_list["type"] == "R") && (src.emagged == 0) && (!src.l_setshort)) + src.locked = 1 + src.overlays = null + src.code = null + src.close(usr) + else + src.code += text("[]", href_list["type"]) + if (length(src.code) > 5) + src.code = "ERROR" + for(var/mob/M in viewers(1, src.loc)) + if ((M.client && M.machine == src)) + src.attack_self(M) + return + return + +/obj/item/weapon/storage/secure/emag_act(var/remaining_charges, var/mob/user, var/feedback) + if(!emagged) + emagged = 1 + src.overlays += image('icons/obj/storage.dmi', icon_sparking) + sleep(6) + src.overlays = null + overlays += image('icons/obj/storage.dmi', icon_locking) + locked = 0 + to_chat(user, (feedback ? feedback : "You short out the lock of \the [src].")) + return 1 + +// ----------------------------- +// Secure Briefcase +// ----------------------------- +/obj/item/weapon/storage/secure/briefcase + name = "secure briefcase" + icon = 'icons/obj/storage.dmi' + icon_state = "secure" + item_state = "sec-case" + desc = "A large briefcase with a digital locking system." + force = 8.0 + throw_speed = 1 + throw_range = 4 + w_class = ITEM_SIZE_HUGE + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = DEFAULT_BACKPACK_STORAGE + + attack_hand(mob/user as mob) + if ((src.loc == user) && (src.locked == 1)) + to_chat(usr, "[src] is locked and cannot be opened!") + else if ((src.loc == user) && (!src.locked)) + src.open(usr) + else + ..() + for(var/mob/M in range(1)) + if (M.s_active == src) + src.close(M) + src.add_fingerprint(user) + return + +// ----------------------------- +// Secure Safe +// ----------------------------- + +/obj/item/weapon/storage/secure/safe + name = "secure safe" + icon = 'icons/obj/storage.dmi' + icon_state = "safe" + icon_opened = "safe0" + icon_locking = "safeb" + icon_sparking = "safespark" + force = 8.0 + w_class = ITEM_SIZE_NO_CONTAINER + max_w_class = ITEM_SIZE_HUGE + max_storage_space = 56 + anchored = 1.0 + density = 0 + cant_hold = list(/obj/item/weapon/storage/secure/briefcase) + + New() + ..() + new /obj/item/weapon/paper(src) + new /obj/item/weapon/pen(src) + + attack_hand(mob/user as mob) + return attack_self(user) + +/obj/item/weapon/storage/secure/safe/HoS/New() + ..() + //new /obj/item/weapon/storage/lockbox/clusterbang(src) This item is currently broken... and probably shouldnt exist to begin with (even though it's cool) diff --git a/code/game/objects/items/weapons/storage/specialized.dm b/code/game/objects/items/weapons/storage/specialized.dm new file mode 100644 index 00000000..2e93c7fa --- /dev/null +++ b/code/game/objects/items/weapons/storage/specialized.dm @@ -0,0 +1,159 @@ +/* + Mining and plant bags, can store a ridiculous number of items in order to deal with the ridiculous amount of ores or plant products + that can be produced by mining or (xeno)botany, however it can only hold those items. + + These storages typically should also support quick gather and quick empty to make managing large numbers of items easier. +*/ + +// ----------------------------- +// Mining Satchel +// ----------------------------- + +/obj/item/weapon/storage/ore + name = "mining satchel" + desc = "This sturdy bag can be used to store and transport ores." + icon = 'icons/obj/mining.dmi' + icon_state = "satchel" + slot_flags = SLOT_BELT + max_storage_space = 200 + max_w_class = ITEM_SIZE_NORMAL + w_class = ITEM_SIZE_LARGE + can_hold = list(/obj/item/weapon/ore) + allow_quick_gather = 1 + allow_quick_empty = 1 + use_to_pickup = 1 + + +// ----------------------------- +// Plant bag +// ----------------------------- + +/obj/item/weapon/storage/plants + name = "botanical satchel" + desc = "This bag can be used to store all kinds of plant products and botanical specimen." + icon = 'icons/obj/hydroponics_machines.dmi' + icon_state = "plantbag" + slot_flags = SLOT_BELT + max_storage_space = 100 + max_w_class = ITEM_SIZE_SMALL + w_class = ITEM_SIZE_NORMAL + can_hold = list(/obj/item/weapon/reagent_containers/food/snacks/grown,/obj/item/seeds,/obj/item/weapon/grown) + allow_quick_gather = 1 + allow_quick_empty = 1 + use_to_pickup = 1 + + +// ----------------------------- +// Sheet Snatcher +// ----------------------------- +// Because it stacks stacks, this doesn't operate normally. +// However, making it a storage/bag allows us to reuse existing code in some places. -Sayu +// This is old and terrible + +/obj/item/weapon/storage/sheetsnatcher + name = "sheet snatcher" + icon = 'icons/obj/mining.dmi' + icon_state = "sheetsnatcher" + desc = "A patented storage system designed for any kind of mineral sheet." + + storage_ui = /datum/storage_ui/default/sheetsnatcher + + var/capacity = 300; //the number of sheets it can carry. + w_class = ITEM_SIZE_NORMAL + storage_slots = 7 + + allow_quick_empty = 1 // this function is superceded + use_to_pickup = 1 + New() + ..() + //verbs -= /obj/item/weapon/storage/verb/quick_empty + //verbs += /obj/item/weapon/storage/sheetsnatcher/quick_empty + + can_be_inserted(obj/item/W, mob/user, stop_messages = 0) + if(!istype(W,/obj/item/stack/material)) + if(!stop_messages) + to_chat(user, "The snatcher does not accept [W].") + return 0 + var/current = 0 + for(var/obj/item/stack/material/S in contents) + current += S.amount + if(capacity == current)//If it's full, you're done + if(!stop_messages) + to_chat(user, "The snatcher is full.") + return 0 + return 1 + + +// Modified handle_item_insertion. Would prefer not to, but... + handle_item_insertion(obj/item/W as obj, prevent_warning = 0) + var/obj/item/stack/material/S = W + if(!istype(S)) return 0 + + var/amount + var/inserted = 0 + var/current = 0 + for(var/obj/item/stack/material/S2 in contents) + current += S2.amount + if(capacity < current + S.amount)//If the stack will fill it up + amount = capacity - current + else + amount = S.amount + + for(var/obj/item/stack/material/sheet in contents) + if(S.type == sheet.type) // we are violating the amount limitation because these are not sane objects + sheet.amount += amount // they should only be removed through procs in this file, which split them up. + S.amount -= amount + inserted = 1 + break + + if(!inserted || !S.amount) + usr.drop_from_inventory(S, src) + if(!S.amount) + qdel(S) + usr.update_icons() //update our overlays + + prepare_ui(usr) + update_icon() + return 1 + +// Modified quick_empty verb drops appropriate sized stacks + quick_empty() + var/location = get_turf(src) + for(var/obj/item/stack/material/S in contents) + while(S.amount) + var/obj/item/stack/material/N = new S.type(location) + var/stacksize = min(S.amount,N.max_amount) + N.amount = stacksize + S.amount -= stacksize + if(!S.amount) + qdel(S) // todo: there's probably something missing here + prepare_ui() + if(usr.s_active) + usr.s_active.show_to(usr) + update_icon() + +// Instead of removing + remove_from_storage(obj/item/W as obj, atom/new_location) + var/obj/item/stack/material/S = W + if(!istype(S)) return 0 + + //I would prefer to drop a new stack, but the item/attack_hand code + // that calls this can't recieve a different object than you clicked on. + //Therefore, make a new stack internally that has the remainder. + // -Sayu + + if(S.amount > S.max_amount) + var/obj/item/stack/material/temp = new S.type(src) + temp.amount = S.amount - S.max_amount + S.amount = S.max_amount + + return ..(S,new_location) + +// ----------------------------- +// Sheet Snatcher (Cyborg) +// ----------------------------- + +/obj/item/weapon/storage/sheetsnatcher/borg + name = "sheet snatcher 9000" + desc = "" + capacity = 500//Borgs get more because >specialization \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm new file mode 100644 index 00000000..82197c35 --- /dev/null +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -0,0 +1,422 @@ +// To clarify: +// For use_to_pickup and allow_quick_gather functionality, +// see item/attackby() (/game/objects/items.dm) +// Do not remove this functionality without good reason, cough reagent_containers cough. +// -Sayu + + +/obj/item/weapon/storage + name = "storage" + icon = 'icons/obj/storage.dmi' + w_class = ITEM_SIZE_NORMAL + var/list/can_hold = new/list() //List of objects which this item can store (if set, it can't store anything else) + var/list/cant_hold = new/list() //List of objects which this item can't store (in effect only if can_hold isn't set) + + var/max_w_class = ITEM_SIZE_SMALL //Max size of objects that this object can store (in effect only if can_hold isn't set) + var/max_storage_space = null //Total storage cost of items this can hold. Will be autoset based on storage_slots if left null. + var/storage_slots = null //The number of storage slots in this container. + + var/use_to_pickup //Set this to make it possible to use this item in an inverse way, so you can have the item in your hand and click items on the floor to pick them up. + var/allow_quick_empty //Set this variable to allow the object to have the 'empty' verb, which dumps all the contents on the floor. + var/allow_quick_gather //Set this variable to allow the object to have the 'toggle mode' verb, which quickly collects all items from a tile. + var/collection_mode = 1; //0 = pick one at a time, 1 = pick all on tile + var/use_sound = "rustle" //sound played when used. null for no sound. + + //initializes the contents of the storage with some items based on an assoc list. The assoc key must be an item path, + //the assoc value can either be the quantity, or a list whose first value is the quantity and the rest are args. + var/list/startswith + var/datum/storage_ui/storage_ui = /datum/storage_ui/default + +/obj/item/weapon/storage/Destroy() + QDEL_NULL(storage_ui) + . = ..() + +/obj/item/weapon/storage/MouseDrop(obj/over_object as obj) + if(!canremove) + return + + if (ishuman(usr) || issmall(usr)) //so monkeys can take off their backpacks -- Urist + if(over_object == usr && Adjacent(usr)) // this must come before the screen objects only block + var/mob/living/carbon/human/H = usr + if(src == H.back) + return + src.open(usr) + return + + if (!( istype(over_object, /obj/screen) )) + return ..() + + if (usr.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_KNOCKOUT)) + return + + //makes sure that the storage is equipped, so that we can't drag it into our hand from miles away. + if (!usr.contains(src)) + return + + src.add_fingerprint(usr) + if(usr.unEquip(src)) + switch(over_object.name) + if(BP_R_HAND) + usr.put_in_r_hand(src) + if(BP_L_HAND) + usr.put_in_l_hand(src) + + +/obj/item/weapon/storage/proc/return_inv() + + var/list/L = list( ) + + L += src.contents + + for(var/obj/item/weapon/storage/S in src) + L += S.return_inv() + for(var/obj/item/weapon/gift/G in src) + L += G.gift + if (istype(G.gift, /obj/item/weapon/storage)) + L += G.gift:return_inv() + return L + +/obj/item/weapon/storage/proc/show_to(mob/user as mob) + storage_ui.show_to(user) + +/obj/item/weapon/storage/proc/hide_from(mob/user as mob) + storage_ui.hide_from(user) + +/obj/item/weapon/storage/proc/open(mob/user as mob) + if (src.use_sound) + playsound(src.loc, src.use_sound, 50, 1, -5) + + prepare_ui() + storage_ui.on_open(user) + storage_ui.show_to(user) + +/obj/item/weapon/storage/proc/prepare_ui() + storage_ui.prepare_ui() + +/obj/item/weapon/storage/proc/close(mob/user as mob) + hide_from(user) + storage_ui.after_close(user) + +/obj/item/weapon/storage/proc/close_all() + storage_ui.close_all() + +/obj/item/weapon/storage/proc/storage_space_used() + . = 0 + for(var/obj/item/I in contents) + . += I.get_storage_cost() + +//This proc return 1 if the item can be picked up and 0 if it can't. +//Set the stop_messages to stop it from printing messages +/obj/item/weapon/storage/proc/can_be_inserted(obj/item/W, mob/user, stop_messages = 0) + if(!istype(W)) return //Not an item + + if(user && user.isEquipped(W) && !user.canUnEquip(W)) + return 0 + + if(src.loc == W) + return 0 //Means the item is already in the storage item + if(storage_slots != null && contents.len >= storage_slots) + if(!stop_messages) + to_chat(user, "\The [src] is full, make some space.") + return 0 //Storage item is full + + if(W.anchored) + return 0 + + if(can_hold.len) + if(!is_type_in_list(W, can_hold)) + if(!stop_messages && ! istype(W, /obj/item/weapon/hand_labeler)) + to_chat(user, "\The [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)) + to_chat(user, "\The [src] has no more space specifically for \the [W].") + return 0 + + // Don't allow insertion of unsafed compressed matter implants + // Since they are sucking something up now, their afterattack will delete the storage + if(istype(W, /obj/item/weapon/implanter/compressed)) + var/obj/item/weapon/implanter/compressed/impr = W + if(!impr.safe) + stop_messages = 1 + return 0 + + if(cant_hold.len && is_type_in_list(W, cant_hold)) + if(!stop_messages) + to_chat(user, "\The [src] cannot hold \the [W].") + return 0 + + if (max_w_class != null && W.w_class > max_w_class) + if(!stop_messages) + to_chat(user, "\The [W] is too big for this [src.name].") + return 0 + + var/total_storage_space = W.get_storage_cost() + if(total_storage_space == ITEM_SIZE_NO_CONTAINER) + if(!stop_messages) + to_chat(user, "\The [W] cannot be placed in [src].") + return 0 + + total_storage_space += storage_space_used() //Adds up the combined w_classes which will be in the storage item if the item is added to it. + if(total_storage_space > max_storage_space) + if(!stop_messages) + to_chat(user, "\The [src] is too full, make some space.") + return 0 + + return 1 + +//This proc handles items being inserted. It does not perform any checks of whether an item can or can't be inserted. That's done by can_be_inserted() +//The stop_warning parameter will stop the insertion message from being displayed. It is intended for cases where you are inserting multiple items at once, +//such as when picking up all the items on a tile with one click. +/obj/item/weapon/storage/proc/handle_item_insertion(var/obj/item/W, var/prevent_warning = 0, var/NoUpdate = 0) + if(!istype(W)) + return 0 + if(istype(W.loc, /mob)) + var/mob/M = W.loc + M.remove_from_mob(W) + W.forceMove(src) + W.on_enter_storage(src) + if(usr) + add_fingerprint(usr) + + if(!prevent_warning) + for(var/mob/M in viewers(usr, null)) + if (M == usr) + to_chat(usr, "You put \the [W] into [src].") + else if (M in range(1)) //If someone is standing close enough, they can tell what it is... TODO replace with distance check + M.show_message("\The [usr] puts [W] into [src].") + else if (W && W.w_class >= ITEM_SIZE_NORMAL) //Otherwise they can only see large or normal items from a distance... + M.show_message("\The [usr] puts [W] into [src].") + + if(!NoUpdate) + update_ui_after_item_insertion() + update_icon() + return 1 + +/obj/item/weapon/storage/proc/update_ui_after_item_insertion() + prepare_ui() + storage_ui.on_insertion(usr) + +/obj/item/weapon/storage/proc/update_ui_after_item_removal() + prepare_ui() + storage_ui.on_post_remove(usr) + +//Call this proc to handle the removal of an item from the storage item. The item will be moved to the atom sent as new_target +/obj/item/weapon/storage/proc/remove_from_storage(obj/item/W as obj, atom/new_location, var/NoUpdate = 0) + if(!istype(W)) return 0 + new_location = new_location || get_turf(src) + + storage_ui.on_pre_remove(usr, W) + + if(ismob(loc)) + W.dropped(usr) + if(ismob(new_location)) + W.hud_layerise() + else + W.reset_plane_and_layer() + W.forceMove(new_location) + + if(usr && !NoUpdate) + update_ui_after_item_removal() + if(W.maptext) + W.maptext = "" + W.on_exit_storage(src) + update_icon() + return 1 + +//This proc is called when you want to place an item into the storage item. +/obj/item/weapon/storage/attackby(obj/item/W as obj, mob/user as mob) + ..() + + if(isrobot(user)) + return //Robots can't interact with storage items. + + if(istype(W, /obj/item/device/lightreplacer)) + var/obj/item/device/lightreplacer/LP = W + var/amt_inserted = 0 + var/turf/T = get_turf(user) + for(var/obj/item/weapon/light/L in src.contents) + if(L.status == 0) + if(LP.uses < LP.max_uses) + LP.AddUses(1) + amt_inserted++ + remove_from_storage(L, T) + qdel(L) + if(amt_inserted) + to_chat(user, "You inserted [amt_inserted] light\s into \the [LP.name]. You have [LP.uses] light\s remaining.") + return + + if(!can_be_inserted(W, user)) + return + + if(istype(W, /obj/item/weapon/tray)) + var/obj/item/weapon/tray/T = W + if(T.calc_carry() > 0) + if(prob(85)) + to_chat(user, "The tray won't fit in [src].") + return + else + if(user.unEquip(W)) + to_chat(user, "God damnit!") + W.add_fingerprint(user) + return handle_item_insertion(W) + +/obj/item/weapon/storage/attack_hand(mob/user as mob) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.l_store == src && !H.get_active_hand()) //Prevents opening if it's in a pocket. + H.put_in_hands(src) + H.l_store = null + return + if(H.r_store == src && !H.get_active_hand()) + H.put_in_hands(src) + H.r_store = null + return + + if (src.loc == user) + src.open(user) + else + ..() + storage_ui.on_hand_attack(user) + src.add_fingerprint(user) + return + +/obj/item/weapon/storage/proc/gather_all(var/turf/T, var/mob/user) + var/success = 0 + var/failure = 0 + + for(var/obj/item/I in T) + if(!can_be_inserted(I, user, 0)) // Note can_be_inserted still makes noise when the answer is no + failure = 1 + continue + success = 1 + handle_item_insertion(I, 1, 1) // First 1 is no messages, second 1 is no ui updates + if(success && !failure) + to_chat(user, "You put everything into \the [src].") + update_ui_after_item_insertion() + else if(success) + to_chat(user, "You put some things into \the [src].") + update_ui_after_item_insertion() + else + to_chat(user, "You fail to pick anything up with \the [src].") + +/obj/item/weapon/storage/verb/toggle_gathering_mode() + set name = "Switch Gathering Method" + set category = "Object" + + collection_mode = !collection_mode + switch (collection_mode) + if(1) + to_chat(usr, "\The [src] now picks up all items in a tile at once.") + if(0) + to_chat(usr, "\The [src] now picks up one item at a time.") + +/obj/item/weapon/storage/verb/quick_empty() + set name = "Empty Contents" + set category = "Object" + + if((!ishuman(usr) && (src.loc != usr)) || usr.stat || usr.restrained()) + return + + var/turf/T = get_turf(src) + hide_from(usr) + for(var/obj/item/I in contents) + remove_from_storage(I, T, 1) + update_ui_after_item_removal() + +/obj/item/weapon/storage/Initialize() + . = ..() + if(allow_quick_empty) + verbs += /obj/item/weapon/storage/verb/quick_empty + else + verbs -= /obj/item/weapon/storage/verb/quick_empty + + if(allow_quick_gather) + verbs += /obj/item/weapon/storage/verb/toggle_gathering_mode + else + verbs -= /obj/item/weapon/storage/verb/toggle_gathering_mode + + if(isnull(max_storage_space) && !isnull(storage_slots)) + max_storage_space = storage_slots*base_storage_cost(max_w_class) + + storage_ui = new storage_ui(src) + prepare_ui() + + if(startswith) + for(var/item_path in startswith) + var/list/data = startswith[item_path] + if(islist(data)) + var/qty = data[1] + var/list/argsl = data.Copy() + argsl[1] = src + for(var/i in 1 to qty) + new item_path(arglist(argsl)) + else + for(var/i in 1 to (isnull(data)? 1 : data)) + new item_path(src) + update_icon() + +/obj/item/weapon/storage/emp_act(severity) + if(!istype(src.loc, /mob/living)) + for(var/obj/O in contents) + O.emp_act(severity) + ..() + +/obj/item/weapon/storage/attack_self(mob/user as mob) + //Clicking on itself will empty it, if it has the verb to do that. + if(user.get_active_hand() == src) + if(src.verbs.Find(/obj/item/weapon/storage/verb/quick_empty)) + 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) + var/depth = 0 + var/atom/cur_atom = src + + while (cur_atom && !(cur_atom in container.contents)) + if (isarea(cur_atom)) + return -1 + if (istype(cur_atom.loc, /obj/item/weapon/storage)) + depth++ + cur_atom = cur_atom.loc + + if (!cur_atom) + return -1 //inside something with a null loc. + + return depth + +//Like storage depth, but returns the depth to the nearest turf +//Returns -1 if no top level turf (a loc was null somewhere, or a non-turf atom's loc was an area somehow). +/atom/proc/storage_depth_turf() + var/depth = 0 + var/atom/cur_atom = src + + while (cur_atom && !isturf(cur_atom)) + if (isarea(cur_atom)) + return -1 + if (istype(cur_atom.loc, /obj/item/weapon/storage)) + depth++ + cur_atom = cur_atom.loc + + if (!cur_atom) + return -1 //inside something with a null loc. + + return depth + +/obj/item/proc/get_storage_cost() + //If you want to prevent stuff above a certain w_class from being stored, use max_w_class + return base_storage_cost(w_class) diff --git a/code/game/objects/items/weapons/storage/storage_ui/default.dm b/code/game/objects/items/weapons/storage/storage_ui/default.dm new file mode 100644 index 00000000..5dd438d0 --- /dev/null +++ b/code/game/objects/items/weapons/storage/storage_ui/default.dm @@ -0,0 +1,259 @@ +/datum/storage_ui/default + var/list/is_seeing = new/list() //List of mobs which are currently seeing the contents of this item's storage + + var/obj/screen/storage/boxes + var/obj/screen/storage/storage_start //storage UI + var/obj/screen/storage/storage_continue + var/obj/screen/storage/storage_end + var/obj/screen/storage/stored_start + var/obj/screen/storage/stored_continue + var/obj/screen/storage/stored_end + var/obj/screen/close/closer + +/datum/storage_ui/default/New(var/storage) + ..() + boxes = new /obj/screen/storage( ) + boxes.SetName("storage") + boxes.master = storage + boxes.icon_state = "block" + boxes.screen_loc = "7,7 to 10,8" + boxes.layer = HUD_BASE_LAYER + boxes.plane = HUD_PLANE + + storage_start = new /obj/screen/storage( ) + storage_start.SetName("storage") + storage_start.master = storage + storage_start.icon_state = "storage_start" + storage_start.screen_loc = "7,7 to 10,8" + storage_start.layer = HUD_BASE_LAYER + storage_start.plane = HUD_PLANE + storage_continue = new /obj/screen/storage( ) + storage_continue.SetName("storage") + storage_continue.master = storage + storage_continue.icon_state = "storage_continue" + storage_continue.screen_loc = "7,7 to 10,8" + storage_continue.layer = HUD_BASE_LAYER + storage_continue.plane = HUD_PLANE + storage_end = new /obj/screen/storage( ) + storage_end.SetName("storage") + storage_end.master = storage + storage_end.icon_state = "storage_end" + storage_end.screen_loc = "7,7 to 10,8" + storage_end.layer = HUD_BASE_LAYER + storage_end.plane = HUD_PLANE + + stored_start = new /obj //we just need these to hold the icon + stored_start.icon_state = "stored_start" + stored_start.layer = HUD_BASE_LAYER + stored_start.plane = HUD_PLANE + + stored_continue = new /obj + stored_continue.icon_state = "stored_continue" + stored_continue.layer = HUD_BASE_LAYER + stored_continue.plane = HUD_PLANE + stored_end = new /obj + stored_end.icon_state = "stored_end" + stored_end.layer = HUD_BASE_LAYER + stored_end.plane = HUD_PLANE + + closer = new /obj/screen/close( ) + closer.master = storage + closer.icon_state = "hudclose" + closer.plane = HUD_PLANE + closer.layer = HUD_BASE_LAYER + +/datum/storage_ui/default/Destroy() + close_all() + QDEL_NULL(boxes) + QDEL_NULL(storage_start) + QDEL_NULL(storage_continue) + QDEL_NULL(storage_end) + QDEL_NULL(stored_start) + QDEL_NULL(stored_continue) + QDEL_NULL(stored_end) + QDEL_NULL(closer) + . = ..() + +/datum/storage_ui/default/on_open(var/mob/user) + if (user.s_active) + user.s_active.close(user) + +/datum/storage_ui/default/after_close(var/mob/user) + user.s_active = null + +/datum/storage_ui/default/on_insertion(var/mob/user) + if(user.s_active) + user.s_active.show_to(user) + +/datum/storage_ui/default/on_pre_remove(var/mob/user, var/obj/item/W) + for(var/mob/M in range(1, storage.loc)) + if (M.s_active == storage) + if (M.client) + M.client.screen -= W + +/datum/storage_ui/default/on_post_remove(var/mob/user) + if(user.s_active) + user.s_active.show_to(user) + +/datum/storage_ui/default/on_hand_attack(var/mob/user) + for(var/mob/M in range(1)) + if (M.s_active == storage) + storage.close(M) + +/datum/storage_ui/default/show_to(var/mob/user) + if(user.s_active != storage) + for(var/obj/item/I in storage) + if(I.on_found(user)) + return + if(user.s_active) + user.s_active.hide_from(user) + user.client.screen -= boxes + user.client.screen -= storage_start + user.client.screen -= storage_continue + user.client.screen -= storage_end + user.client.screen -= closer + user.client.screen -= storage.contents + user.client.screen += closer + user.client.screen += storage.contents + if(storage.storage_slots) + user.client.screen += boxes + else + user.client.screen += storage_start + user.client.screen += storage_continue + user.client.screen += storage_end + is_seeing |= user + user.s_active = storage + +/datum/storage_ui/default/hide_from(var/mob/user) + is_seeing -= user + if(!user.client) + return + user.client.screen -= boxes + user.client.screen -= storage_start + user.client.screen -= storage_continue + user.client.screen -= storage_end + user.client.screen -= closer + user.client.screen -= storage.contents + if(user.s_active == storage) + user.s_active = null + +//Creates the storage UI +/datum/storage_ui/default/prepare_ui() + //if storage slots is null then use the storage space UI, otherwise use the slots UI + if(storage.storage_slots == null) + space_orient_objs() + else + slot_orient_objs() + +/datum/storage_ui/default/close_all() + for(var/mob/M in can_see_contents()) + storage.close(M) + . = 1 + +/datum/storage_ui/default/proc/can_see_contents() + var/list/cansee = list() + for(var/mob/M in is_seeing) + if(M.s_active == storage && M.client) + cansee |= M + else + is_seeing -= M + return cansee + +//This proc draws out the inventory and places the items on it. tx and ty are the upper left tile and mx, my are the bottm right. +//The numbers are calculated from the bottom-left The bottom-left slot being 1,1. +/datum/storage_ui/default/proc/orient_objs(tx, ty, mx, my) + var/cx = tx + var/cy = ty + boxes.screen_loc = "[tx]:,[ty] to [mx],[my]" + for(var/obj/O in storage.contents) + O.screen_loc = "[cx],[cy]" + O.hud_layerise() + cx++ + if (cx > mx) + cx = tx + cy-- + closer.screen_loc = "[mx+1],[my]" + return + +//This proc determins the size of the inventory to be displayed. Please touch it only if you know what you're doing. +/datum/storage_ui/default/proc/slot_orient_objs() + var/adjusted_contents = storage.contents.len + var/row_num = 0 + var/col_count = min(7,storage.storage_slots) -1 + if (adjusted_contents > 7) + row_num = round((adjusted_contents-1) / 7) // 7 is the maximum allowed width. + arrange_item_slots(row_num, col_count) + +//This proc draws out the inventory and places the items on it. It uses the standard position. +/datum/storage_ui/default/proc/arrange_item_slots(var/rows, var/cols) + var/cx = 4 + var/cy = 1+rows + boxes.screen_loc = "4:16,1:16 to [4+cols]:16,[2+rows]:16"//"4:16,2:16 to [4+cols]:16,[2+rows]:16" + + for(var/obj/O in storage.contents) + O.screen_loc = "[cx]:16,[cy]:16"//"[cx]:16,[cy]:16" + O.maptext = "" + O.hud_layerise() + cx++ + if (cx > (4+cols)) + cx = 4 + cy-- + + closer.screen_loc = "[4+cols+1]:16,1:16"//"[4+cols+1]:16,2:16" + +/datum/storage_ui/default/proc/space_orient_objs() + + var/baseline_max_storage_space = DEFAULT_BOX_STORAGE //storage size corresponding to 224 pixels + var/storage_cap_width = 2 //length of sprite for start and end of the box representing total storage space + var/stored_cap_width = 4 //length of sprite for start and end of the box representing the stored item + var/storage_width = min( round( 224 * storage.max_storage_space/baseline_max_storage_space ,1) ,284) //length of sprite for the box representing total storage space + + storage_start.overlays.Cut() + + var/matrix/M = matrix() + M.Scale((storage_width-storage_cap_width*2+3)/32,1) + storage_continue.transform = M + + storage_start.screen_loc = "4:16,1:16"//"4:16,2:16" + storage_continue.screen_loc = "4:[storage_cap_width+(storage_width-storage_cap_width*2)/2+2],1:16"//32 + storage_end.screen_loc = "4:[19+storage_width-storage_cap_width],1:16"//32 + + var/startpoint = 0 + var/endpoint = 1 + + for(var/obj/item/O in storage.contents) + startpoint = endpoint + 1 + endpoint += storage_width * O.get_storage_cost()/storage.max_storage_space + + var/matrix/M_start = matrix() + var/matrix/M_continue = matrix() + var/matrix/M_end = matrix() + M_start.Translate(startpoint,0) + M_continue.Scale((endpoint-startpoint-stored_cap_width*2)/32,1) + M_continue.Translate(startpoint+stored_cap_width+(endpoint-startpoint-stored_cap_width*2)/2 - 16,0) + M_end.Translate(endpoint-stored_cap_width,0) + stored_start.transform = M_start + stored_continue.transform = M_continue + stored_end.transform = M_end + storage_start.overlays += stored_start + storage_start.overlays += stored_continue + storage_start.overlays += stored_end + + O.screen_loc = "4:[round((startpoint+endpoint)/2)+2],1:16"//32 + O.maptext = "" + O.hud_layerise() + + closer.screen_loc = "4:[storage_width+19],1:16"//32 + +// Sets up numbered display to show the stack size of each stored mineral +// NOTE: numbered display is turned off currently because it's broken +/datum/storage_ui/default/sheetsnatcher/prepare_ui(var/mob/user) + var/adjusted_contents = storage.contents.len + + var/row_num = 0 + var/col_count = min(7,storage.storage_slots) -1 + if (adjusted_contents > 7) + row_num = round((adjusted_contents-1) / 7) // 7 is the maximum allowed width. + arrange_item_slots(row_num, col_count) + if(user && user.s_active) + user.s_active.show_to(user) diff --git a/code/game/objects/items/weapons/storage/storage_ui/storage_ui.dm b/code/game/objects/items/weapons/storage/storage_ui/storage_ui.dm new file mode 100644 index 00000000..20f55b1c --- /dev/null +++ b/code/game/objects/items/weapons/storage/storage_ui/storage_ui.dm @@ -0,0 +1,40 @@ +/datum/storage_ui + var/obj/item/weapon/storage/storage + +/datum/storage_ui/New(var/storage) + src.storage = storage + ..() + +/datum/storage_ui/Destroy() + storage = null + . = ..() + +/datum/storage_ui/proc/show_to(var/mob/user) + return + +/datum/storage_ui/proc/hide_from(var/mob/user) + return + +/datum/storage_ui/proc/prepare_ui() + return + +/datum/storage_ui/proc/close_all() + return + +/datum/storage_ui/proc/on_open(var/mob/user) + return + +/datum/storage_ui/proc/after_close(var/mob/user) + return + +/datum/storage_ui/proc/on_insertion(var/mob/user) + return + +/datum/storage_ui/proc/on_pre_remove(var/mob/user, var/obj/item/W) + return + +/datum/storage_ui/proc/on_post_remove(var/mob/user, var/obj/item/W) + return + +/datum/storage_ui/proc/on_hand_attack(var/mob/user) + return diff --git a/code/game/objects/items/weapons/storage/storage_ui/tgui.dm b/code/game/objects/items/weapons/storage/storage_ui/tgui.dm new file mode 100644 index 00000000..83987608 --- /dev/null +++ b/code/game/objects/items/weapons/storage/storage_ui/tgui.dm @@ -0,0 +1,70 @@ +/datum/storage_ui/tgui + var/cached_ui_data + +/datum/storage_ui/tgui/ui_host() + return storage.ui_host() + +/datum/storage_ui/tgui/show_to(var/mob/user) + tg_ui_interact(user) + +/datum/storage_ui/tgui/hide_from(var/mob/user) + tg_ui_interact(user) + +/datum/storage_ui/tgui/close_all() + tgui_process.close_uis(src) + +/datum/storage_ui/tgui/on_open(var/mob/user) + tg_ui_interact(user) + +/datum/storage_ui/tgui/on_insertion(var/mob/user) + cached_ui_data = null + tg_ui_interact(user) + +/datum/storage_ui/tgui/on_post_remove(var/mob/user, var/obj/item/W) + cached_ui_data = null + tg_ui_interact(user) + +/datum/storage_ui/tgui/tg_ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = tg_physical_state) + ui = tgui_process.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "storage", storage.name, 340, 440, master_ui, state) + ui.open() + +/datum/storage_ui/tgui/ui_data() + if(!cached_ui_data) + + var/list/items_by_name_and_type = list() + for(var/obj/item/W in storage) + group_by(items_by_name_and_type, "[W.name]§[W.type]", W) + + var/list/item_list = list() + for(var/name_and_type in items_by_name_and_type) + var/list/items = items_by_name_and_type[name_and_type] + var/obj/item/first_item = items[1] + item_list[++item_list.len] = list("name" = first_item.name, "type" = first_item.type, "amount" = items.len) + + cached_ui_data = list( + "items" = item_list + ) + + return cached_ui_data + +/datum/storage_ui/tgui/ui_act(action, params) + if(..()) + return TRUE + + if(action == "remove_item") + if(remove_item_by_name_and_type(params["name"], params["type"])) + return TRUE + +/datum/storage_ui/tgui/proc/remove_item_by_name_and_type(var/name, var/type_name) + if(!istext(name) || !istext(type_name)) + return FALSE + var/type = text2path(type_name) + if(!type) + return FALSE + for(var/obj/item/W in storage) + if(W.name == name && W.type == type) + if(storage.remove_from_storage(W)) + return TRUE + return FALSE diff --git a/code/game/objects/items/weapons/storage/toolbox.dm b/code/game/objects/items/weapons/storage/toolbox.dm new file mode 100644 index 00000000..3c363b45 --- /dev/null +++ b/code/game/objects/items/weapons/storage/toolbox.dm @@ -0,0 +1,87 @@ +/obj/item/weapon/storage/toolbox + name = "toolbox" + desc = "Bright red toolboxes like these are one of the most common sights in maintenance corridors on virtually every ship in the galaxy." + description_info = "The toolbox is a general-purpose storage item with lots of space. With an item in your hand, click on it to store it inside." + description_fluff = "No one remembers which company designed this particular toolbox. It's been mass-produced, retired, brought out of retirement, and counterfeited for decades." + description_antag = "Carrying one of these and being bald tends to instill a certain primal fear in most people." + icon = 'icons/obj/storage.dmi' + icon_state = "red" + item_state = "toolbox_red" + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 15 + throwforce = 10 + throw_speed = 1 + throw_range = 7 + w_class = ITEM_SIZE_LARGE + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = DEFAULT_LARGEBOX_STORAGE //enough to hold all starting contents + origin_tech = list(TECH_COMBAT = 1) + attack_verb = list("robusted") + grab_sound = 'sound/items/handle/toolbox_pickup.ogg' + drop_sound = 'sound/items/handle/toolbox_drop.ogg' + use_sound = 'sound/effects/storage/toolbox.ogg' + +/obj/item/weapon/storage/toolbox/emergency + name = "emergency toolbox" + icon_state = "red" + item_state = "toolbox_red" + +/obj/item/weapon/storage/toolbox/emergency/New() + ..() + new /obj/item/weapon/crowbar/red(src) + new /obj/item/weapon/extinguisher/mini(src) + var/item = pick(list(/obj/item/device/flashlight, /obj/item/device/flashlight/flare, /obj/item/device/flashlight/glowstick/red)) + new item(src) + new /obj/item/device/radio(src) + +/obj/item/weapon/storage/toolbox/mechanical + name = "mechanical toolbox" + desc = "Bright blue toolboxes like these are one of the most common sights in maintenance corridors on virtually every ship in the galaxy." + icon_state = "blue" + item_state = "toolbox_blue" + +/obj/item/weapon/storage/toolbox/mechanical/New() + ..() + new /obj/item/weapon/screwdriver(src) + new /obj/item/weapon/wrench(src) + new /obj/item/weapon/weldingtool(src) + new /obj/item/weapon/crowbar(src) + new /obj/item/device/analyzer(src) + new /obj/item/weapon/wirecutters(src) + +/obj/item/weapon/storage/toolbox/electrical + name = "electrical toolbox" + desc = "Bright yellow toolboxes like these are one of the most common sights in maintenance corridors on virtually every ship in the galaxy." + icon_state = "yellow" + item_state = "toolbox_yellow" + +/obj/item/weapon/storage/toolbox/electrical/New() + ..() + new /obj/item/weapon/screwdriver(src) + new /obj/item/weapon/wirecutters(src) + new /obj/item/device/t_scanner(src) + new /obj/item/weapon/crowbar(src) + new /obj/item/stack/cable_coil/random(src,30) + new /obj/item/stack/cable_coil/random(src,30) + if(prob(5)) + new /obj/item/clothing/gloves/insulated(src) + else + new /obj/item/stack/cable_coil/random(src,30) + +/obj/item/weapon/storage/toolbox/syndicate + name = "black and red toolbox" + desc = "A toolbox in black, with stylish red trim. This one feels particularly heavy." + icon_state = "syndicate" + item_state = "toolbox_syndi" + origin_tech = list(TECH_COMBAT = 1, TECH_ILLEGAL = 1) + force = 7.0 + +/obj/item/weapon/storage/toolbox/syndicate/New() + ..() + new /obj/item/clothing/gloves/insulated(src) + new /obj/item/weapon/screwdriver(src) + new /obj/item/weapon/wrench(src) + new /obj/item/weapon/weldingtool(src) + new /obj/item/weapon/crowbar(src) + new /obj/item/weapon/wirecutters(src) + new /obj/item/device/multitool(src) \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm new file mode 100644 index 00000000..325f9351 --- /dev/null +++ b/code/game/objects/items/weapons/storage/uplink_kits.dm @@ -0,0 +1,193 @@ +/obj/item/weapon/storage/box/syndie_kit + name = "box" + desc = "A sleek, sturdy box." + icon_state = "box_of_doom" + +//For uplink kits that provide bulkier items +/obj/item/weapon/storage/backpack/satchel/syndie_kit + desc = "A sleek, sturdy satchel." + icon_state = "satchel-norm" + +//In case an uplink kit provides a lot of gear +/obj/item/weapon/storage/backpack/dufflebag/syndie_kit + name = "black dufflebag" + desc = "A sleek, sturdy dufflebag." + icon_state = "duffle_syndie" + + +/obj/item/weapon/storage/box/syndie_kit/imp_freedom + name = "box (F)" + startswith = list(/obj/item/weapon/implanter/freedom) + +/obj/item/weapon/storage/box/syndie_kit/imp_uplink + name = "box (U)" + startswith = list(/obj/item/weapon/implanter/uplink) + +/obj/item/weapon/storage/box/syndie_kit/imp_compress + name = "box (C)" + startswith = list(/obj/item/weapon/implanter/compressed) + +/obj/item/weapon/storage/box/syndie_kit/imp_explosive + name = "box (E)" + startswith = list( + /obj/item/weapon/implanter/explosive, + /obj/item/weapon/implantpad + ) + +/obj/item/weapon/storage/box/syndie_kit/imp_imprinting + name = "box (I)" + startswith = list( + /obj/item/weapon/implanter/imprinting, + /obj/item/weapon/implantpad, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/mindbreaker + ) + +// Space suit uplink kit +/obj/item/weapon/storage/backpack/satchel/syndie_kit/space + //name = "\improper EVA gear pack" + + startswith = list( + /obj/item/clothing/suit/space/void/merc, + /obj/item/clothing/head/helmet/space/void/merc, + /obj/item/clothing/mask/gas/syndicate, + /obj/item/weapon/tank/emergency/oxygen/double, + ) + +// Chameleon uplink kit +/obj/item/weapon/storage/backpack/chameleon/sydie_kit + startswith = list( + /obj/item/clothing/under/chameleon, + /obj/item/clothing/suit/chameleon, + /obj/item/clothing/shoes/chameleon, + /obj/item/clothing/mask/chameleon, + /obj/item/weapon/storage/box/syndie_kit/chameleon, + /obj/item/weapon/gun/energy/chameleon, + ) + +/obj/item/weapon/storage/box/syndie_kit/chameleon + name = "chameleon kit" + desc = "Comes with all the clothes you need to impersonate most people. Acting lessons sold seperately." + startswith = list( + /obj/item/clothing/gloves/chameleon, + /obj/item/clothing/glasses/chameleon, + /obj/item/clothing/head/chameleon, + ) + +// Clerical uplink kit +/obj/item/weapon/storage/backpack/satchel/syndie_kit/clerical + name = "clerical kit" + desc = "Comes with all you need to fake paperwork. Assumes you have passed basic writing lessons." + startswith = list( + /obj/item/weapon/packageWrap, + /obj/item/weapon/hand_labeler, + /obj/item/weapon/stamp/chameleon, + /obj/item/weapon/pen/chameleon, + /obj/item/device/destTagger, + ) + +/obj/item/weapon/storage/box/syndie_kit/spy + name = "spy kit" + desc = "For when you want to conduct voyeurism from afar." + startswith = list( + /obj/item/device/spy_bug = 6, + /obj/item/device/spy_monitor + ) + +/obj/item/weapon/storage/box/syndie_kit/g9mm + name = "\improper Smooth operator" + desc = "9mm with silencer kit and ammunition." + startswith = list( + /obj/item/weapon/gun/projectile/pistol, + /obj/item/weapon/silencer, + /obj/item/ammo_magazine/mc9mm + ) + +/obj/item/weapon/storage/backpack/satchel/syndie_kit/revolver + name = "\improper Tough operator" + desc = ".357 revolver, with ammunition." + startswith = list( + /obj/item/weapon/gun/projectile/revolver, + /obj/item/ammo_magazine/a357 + ) + +/obj/item/weapon/storage/backpack/satchel/syndie_kit/revolver2 + name = "\improper Dandy tough operator" + desc = ".44 magnum revolver, with ammunition." + startswith = list( + /obj/item/weapon/gun/projectile/revolver/webley, + /obj/item/ammo_magazine/c44 + ) + +/obj/item/weapon/storage/box/syndie_kit/toxin + name = "toxin kit" + desc = "An apple will not be enough to keep the doctor away after this." + startswith = list( + /obj/item/weapon/reagent_containers/glass/beaker/vial/random/toxin, + /obj/item/weapon/reagent_containers/syringe + ) + +/obj/item/weapon/storage/box/syndie_kit/syringegun + startswith = list( + /obj/item/weapon/gun/launcher/syringe/disguised, + /obj/item/weapon/syringe_cartridge = 4, + /obj/item/weapon/reagent_containers/syringe = 4 + ) + +/obj/item/weapon/storage/box/syndie_kit/cigarette + name = "\improper Tricky smokes" + desc = "Comes with the following brands of cigarettes, in this order: 2xFlash, 2xSmoke, 1xMindBreaker, 1xTricordrazine. Avoid mixing them up." + +/obj/item/weapon/storage/box/syndie_kit/cigarette/New() + ..() + var/obj/item/weapon/storage/fancy/cigarettes/pack + pack = new /obj/item/weapon/storage/fancy/cigarettes(src) + fill_cigarre_package(pack, list(/datum/reagent/aluminum = 1, /datum/reagent/potassium = 1, /datum/reagent/sulfur = 1)) + pack.desc += " 'F' has been scribbled on it." + + pack = new /obj/item/weapon/storage/fancy/cigarettes(src) + fill_cigarre_package(pack, list(/datum/reagent/aluminum = 1, /datum/reagent/potassium = 1, /datum/reagent/sulfur = 1)) + pack.desc += " 'F' has been scribbled on it." + + pack = new /obj/item/weapon/storage/fancy/cigarettes(src) + fill_cigarre_package(pack, list(/datum/reagent/potassium = 1, /datum/reagent/sugar = 1, /datum/reagent/phosphorus = 1)) + pack.desc += " 'S' has been scribbled on it." + + pack = new /obj/item/weapon/storage/fancy/cigarettes(src) + fill_cigarre_package(pack, list(/datum/reagent/potassium = 1, /datum/reagent/sugar = 1, /datum/reagent/phosphorus = 1)) + pack.desc += " 'S' has been scribbled on it." + + pack = new /obj/item/weapon/storage/fancy/cigarettes(src) + fill_cigarre_package(pack, list(/datum/reagent/dylovene = 1, /datum/reagent/silicon = 1, /datum/reagent/hydrazine = 1)) + pack.desc += " 'MB' has been scribbled on it." + + pack = new /obj/item/weapon/storage/fancy/cigarettes(src) + fill_cigarre_package(pack, list(/datum/reagent/tricordrazine = 4)) + pack.desc += " 'T' has been scribbled on it." + + new /obj/item/weapon/flame/lighter/zippo(src) + +/proc/fill_cigarre_package(var/obj/item/weapon/storage/fancy/cigarettes/C, var/list/reagents) + for(var/reagent in reagents) + C.reagents.add_reagent(reagent, reagents[reagent] * C.max_storage_space) + +/obj/item/weapon/storage/secure/briefcase/heavysniper + startswith = list( + /obj/item/weapon/gun/projectile/heavysniper, + /obj/item/weapon/storage/box/sniperammo + ) + +/obj/item/weapon/storage/secure/briefcase/heavysniper/Initialize() + . = ..() + make_exact_fit() + +/obj/item/weapon/storage/secure/briefcase/money + + startswith = list(/obj/item/weapon/spacecash/bundle/c1000 = 10) + +/obj/item/weapon/storage/backpack/satchel/syndie_kit/armor + name = "armor satchel" + desc = "A satchel for when you don't want to try a diplomatic approach." + startswith = list( + /obj/item/clothing/suit/armor/pcarrier/merc, + /obj/item/clothing/head/helmet/merc + ) diff --git a/code/game/objects/items/weapons/storage/wallets.dm b/code/game/objects/items/weapons/storage/wallets.dm new file mode 100644 index 00000000..68d1d6ca --- /dev/null +++ b/code/game/objects/items/weapons/storage/wallets.dm @@ -0,0 +1,137 @@ +/obj/item/weapon/storage/wallet + name = "wallet" + desc = "It can hold a few small and personal things." + icon = 'icons/obj/wallet.dmi' + icon_state = "wallet-white" + w_class = ITEM_SIZE_SMALL + max_w_class = ITEM_SIZE_SMALL //Don't worry, see can_hold[] + max_storage_space = 8 + can_hold = list( + /obj/item/weapon/spacecash, + /obj/item/weapon/card, + /obj/item/clothing/mask/smokable, + /obj/item/weapon/lipstick, + /obj/item/weapon/haircomb, + /obj/item/weapon/mirror, + /obj/item/clothing/accessory/locket, + /obj/item/clothing/head/hairflower, + /obj/item/device/flashlight/pen, + /obj/item/device/flashlight/slime, + /obj/item/seeds, + /obj/item/weapon/coin, + /obj/item/weapon/dice, + /obj/item/weapon/disk, + /obj/item/weapon/implant, + /obj/item/weapon/implanter, + /obj/item/weapon/flame, + /obj/item/weapon/paper, + /obj/item/weapon/paper_bundle, + /obj/item/weapon/pen, + /obj/item/weapon/photo, + /obj/item/weapon/reagent_containers/dropper, + /obj/item/weapon/reagent_containers/syringe, + /obj/item/weapon/reagent_containers/pill, + /obj/item/weapon/reagent_containers/hypospray/autoinjector, + /obj/item/weapon/reagent_containers/glass/beaker/vial, + /obj/item/device/radio/headset, + /obj/item/device/paicard, + /obj/item/weapon/stamp, + /obj/item/weapon/key, + /obj/item/clothing/accessory/badge) + slot_flags = SLOT_ID + + var/obj/item/weapon/card/id/front_id = null + +/obj/item/weapon/storage/wallet/leather + color = COLOR_SEDONA + +/obj/item/weapon/storage/wallet/Destroy() + if(front_id) + front_id.dropInto(loc) + front_id = null + . = ..() + +/obj/item/weapon/storage/wallet/remove_from_storage(obj/item/W as obj, atom/new_location) + . = ..(W, new_location) + if(.) + if(W == front_id) + front_id = null + SetName(initial(name)) + update_icon() + +/obj/item/weapon/storage/wallet/handle_item_insertion(obj/item/W as obj, prevent_warning = 0) + . = ..(W, prevent_warning) + if(.) + if(!front_id && istype(W, /obj/item/weapon/card/id)) + front_id = W + SetName("[name] ([front_id])") + update_icon() + +/obj/item/weapon/storage/wallet/update_icon() + overlays.Cut() + if(front_id) + var/tiny_state = "id-generic" + if("id-"+front_id.icon_state in icon_states(icon)) + tiny_state = "id-"+front_id.icon_state + var/image/tiny_image = new/image(icon, icon_state = tiny_state) + tiny_image.appearance_flags = RESET_COLOR + overlays += tiny_image + +/obj/item/weapon/storage/wallet/GetIdCard() + return front_id + +/obj/item/weapon/storage/wallet/GetAccess() + var/obj/item/I = GetIdCard() + if(I) + return I.GetAccess() + else + return ..() + +/obj/item/weapon/storage/wallet/random/New() + ..() + var/item1_type = pick( /obj/item/weapon/spacecash/bundle/c10,/obj/item/weapon/spacecash/bundle/c100,/obj/item/weapon/spacecash/bundle/c1000,/obj/item/weapon/spacecash/bundle/c20,/obj/item/weapon/spacecash/bundle/c200,/obj/item/weapon/spacecash/bundle/c50, /obj/item/weapon/spacecash/bundle/c500) + var/item2_type + if(prob(50)) + item2_type = pick( /obj/item/weapon/spacecash/bundle/c10,/obj/item/weapon/spacecash/bundle/c100,/obj/item/weapon/spacecash/bundle/c1000,/obj/item/weapon/spacecash/bundle/c20,/obj/item/weapon/spacecash/bundle/c200,/obj/item/weapon/spacecash/bundle/c50, /obj/item/weapon/spacecash/bundle/c500) + var/item3_type = pick( /obj/item/weapon/coin/silver, /obj/item/weapon/coin/silver, /obj/item/weapon/coin/gold, /obj/item/weapon/coin/iron, /obj/item/weapon/coin/iron, /obj/item/weapon/coin/iron ) + + spawn(2) + if(item1_type) + new item1_type(src) + if(item2_type) + new item2_type(src) + if(item3_type) + new item3_type(src) + update_icon() + +/obj/item/weapon/storage/wallet/poly + name = "polychromic wallet" + desc = "You can recolor it! Fancy! The future is NOW!" + +/obj/item/weapon/storage/wallet/poly/New() + ..() + color = get_random_colour() + update_icon() + +/obj/item/weapon/storage/wallet/poly/verb/change_color() + set name = "Change Wallet Color" + set category = "Object" + set desc = "Change the color of the wallet." + set src in usr + + if(usr.incapacitated()) + return + + var/new_color = input(usr, "Pick a new color", "Wallet Color", color) as color|null + if(!new_color || new_color == color || usr.incapacitated()) + return + color = new_color + +/obj/item/weapon/storage/wallet/poly/emp_act() + icon_state = "wallet-emp" + update_icon() + + spawn(200) + if(src) + icon_state = initial(icon_state) + update_icon() diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm new file mode 100644 index 00000000..d8fccdbe --- /dev/null +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -0,0 +1,250 @@ +//replaces our stun baton code with /tg/station's code +/obj/item/weapon/melee/baton + name = "stunbaton" + desc = "A stun baton for incapacitating people with." + icon_state = "stunbaton" + item_state = "baton" + slot_flags = SLOT_BELT + force = 15 + sharp = 0 + edge = 0 + throwforce = 7 + w_class = ITEM_SIZE_NORMAL + origin_tech = list(TECH_COMBAT = 2) + attack_verb = list("beaten") + var/stunforce = 0 + var/agonyforce = 30 + var/status = 0 //whether the thing is on or not + var/obj/item/weapon/cell/bcell + var/hitcost = 7 + block_chance = 15 + +/obj/item/weapon/melee/baton/handle_shield(mob/living/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + if(default_sword_parry(user, damage, damage_source, attacker, def_zone, attack_text)) + return 1 + return 0 + + +/obj/item/weapon/melee/baton/loaded + bcell = /obj/item/weapon/cell/device/high + +/obj/item/weapon/melee/baton/New() + if(ispath(bcell)) + bcell = new bcell(src) + update_icon() + ..() + +/obj/item/weapon/melee/baton/Destroy() + if(bcell && !ispath(bcell)) + qdel(bcell) + bcell = null + return ..() + +/obj/item/weapon/melee/baton/proc/deductcharge(var/chrgdeductamt) + if(bcell) + if(bcell.checked_use(chrgdeductamt)) + return 1 + else + status = 0 + update_icon() + return 0 + return null + +/obj/item/weapon/melee/baton/update_icon() + if(status) + icon_state = "[initial(name)]_active" + else if(!bcell) + icon_state = "[initial(name)]_nocell" + else + icon_state = "[initial(name)]" + + if(icon_state == "[initial(name)]_active") + set_light(2, 2, "#D9E9FF") + else + set_light(0) + +/obj/item/weapon/melee/baton/examine(mob/user) + if(!..(user, 1)) + return 0 + examine_cell(user) + return 1 + +// Addition made by Techhead0, thanks for fullfilling the todo! +/obj/item/weapon/melee/baton/proc/examine_cell(mob/user) + if(bcell) + to_chat(user, "The baton is [round(bcell.percent())]% charged.") + if(!bcell) + to_chat(user, "The baton does not have a power source installed.") + +/obj/item/weapon/melee/baton/attackby(obj/item/weapon/W, mob/user) + if(istype(W, /obj/item/weapon/cell/device)) + if(!bcell && user.unEquip(W)) + W.forceMove(src) + bcell = W + to_chat(user, "You install a cell into the [src].") + update_icon() + else + to_chat(user, "[src] already has a cell.") + else if(isScrewdriver(W)) + if(bcell) + bcell.update_icon() + bcell.dropInto(loc) + bcell = null + to_chat(user, "You remove the cell from the [src].") + status = 0 + update_icon() + else + ..() + +/obj/item/weapon/melee/baton/attack_self(mob/user) + set_status(!status, user) + add_fingerprint(user) + +/obj/item/weapon/melee/baton/proc/set_status(var/newstatus, mob/user) + if(bcell && bcell.charge > hitcost) + if(status != newstatus) + change_status(newstatus) + to_chat(user, "[src] is now [status ? "on" : "off"].") + playsound(loc, "sparks", 75, 1, -1) + else + change_status(0) + if(!bcell) + to_chat(user, "[src] does not have a power source!") + else + to_chat(user, "[src] is out of charge.") + +// Proc to -actually- change the status, and update the icons as well. +// Also exists to ease "helpful" admin-abuse in case an bug prevents attack_self +// to occur would appear. Hopefully it wasn't necessary. +/obj/item/weapon/melee/baton/proc/change_status(var/s) + if (status != s) + status = s + update_icon() + +/obj/item/weapon/melee/baton/attack(mob/M, mob/user) + if(status && (CLUMSY in user.mutations) && prob(50)) + to_chat(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 ..() + + 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) + + if(user.a_intent == I_HURT) + . = ..() + if (!.) //item/attack() does it's own messaging and logs + return 0 // item/attack() will return 1 if they hit, 0 if they missed. + + //whacking someone causes a much poorer electrical contact than deliberately prodding them. + stun *= 0.5 + if(status) //Checks to see if the stunbaton is on. + agony *= 0.5 //whacking someone causes a much poorer contact than prodding them. + else + agony = 0 //Shouldn't really stun if it's off, should it? + //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]!") + else + target.visible_message("[target] has been prodded with [src] by [user]!") + playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) + + //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].") + + deductcharge(hitcost) + + if(ishuman(target)) + var/mob/living/carbon/human/H = target + H.forcesay(GLOB.hit_appends) + + return 0 + +/obj/item/weapon/melee/baton/emp_act(severity) + if(bcell) + bcell.emp_act(severity) //let's not duplicate code everywhere if we don't have to please. + ..() + +// Stunbaton module for Security synthetics +/obj/item/weapon/melee/baton/robot + bcell = null + hitcost = 20 + +// Addition made by Techhead0, thanks for fullfilling the todo! +/obj/item/weapon/melee/baton/robot/examine_cell(mob/user) + to_chat(user, "The baton is running off an external power supply.") + +// Override proc for the stun baton module, found in PC Security synthetics +// Refactored to fix #14470 - old proc defination increased the hitcost beyond +// usability without proper checks. +// Also hard-coded to be unuseable outside their righteous synthetic owners. +/obj/item/weapon/melee/baton/robot/attack_self(mob/user) + var/mob/living/silicon/robot/R = isrobot(user) ? user : null // null if the user is NOT a robot + update_cell(R) // takes both robots and null + if (R) + return ..() + else // Stop pretending and get out of your cardborg suit, human. + to_chat(user, "You don't seem to be able interacting with this by yourself..") + add_fingerprint(user) + return 0 + +/obj/item/weapon/melee/baton/robot/attackby(obj/item/weapon/W, mob/user) + return + +/obj/item/weapon/melee/baton/robot/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) + update_cell(isrobot(user) ? user : null) // update the status before we apply the effects + return ..() + +// Updates the baton's cell to use user's own cell +// Otherwise, if null (when the user isn't a robot), render it unuseable +/obj/item/weapon/melee/baton/robot/proc/update_cell(mob/living/silicon/robot/user) + if (!user) + bcell = null + set_status(0) + else if (!bcell || bcell != user.cell) + bcell = user.cell // if it is null, nullify it anyway + +// Traitor variant for Engineering synthetics. +/obj/item/weapon/melee/baton/robot/electrified_arm + name = "electrified arm" + icon = 'icons/obj/device.dmi' + icon_state = "electrified_arm" + +/obj/item/weapon/melee/baton/robot/electrified_arm/update_icon() + if(status) + icon_state = "electrified_arm_active" + set_light(1.5, 2, "#006aff") + else + icon_state = "electrified_arm" + set_light(0) + +//Makeshift stun baton. Replacement for stun gloves. +/obj/item/weapon/melee/baton/cattleprod + name = "stunprod" + desc = "An improvised stun baton." + icon_state = "stunprod_nocell" + item_state = "prod" + force = 3 + throwforce = 5 + stunforce = 0 + agonyforce = 60 //same force as a stunbaton, but uses way more charge. + hitcost = 25 + attack_verb = list("poked") + slot_flags = null \ No newline at end of file diff --git a/code/game/objects/items/weapons/surgery_tools.dm b/code/game/objects/items/weapons/surgery_tools.dm new file mode 100644 index 00000000..5f2b127b --- /dev/null +++ b/code/game/objects/items/weapons/surgery_tools.dm @@ -0,0 +1,242 @@ +/* Surgery Tools + * Contains: + * Retractor + * Hemostat + * Cautery + * Surgical Drill + * Scalpel + * Circular Saw + */ + +/* + * Retractor + */ +/obj/item/weapon/retractor + name = "retractor" + desc = "Retracts stuff." + icon = 'icons/obj/surgery.dmi' + icon_state = "retractor" + matter = list(DEFAULT_WALL_MATERIAL = 10000, "glass" = 5000) + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_SMALL + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) + +/* + * Hemostat + */ +/obj/item/weapon/hemostat + name = "hemostat" + desc = "You think you have seen this before." + icon = 'icons/obj/surgery.dmi' + icon_state = "hemostat" + matter = list(DEFAULT_WALL_MATERIAL = 5000, "glass" = 2500) + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_SMALL + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) + attack_verb = list("attacked", "pinched") + +/* + * Cautery + */ +/obj/item/weapon/cautery + name = "cautery" + desc = "This stops bleeding." + icon = 'icons/obj/surgery.dmi' + icon_state = "cautery" + matter = list(DEFAULT_WALL_MATERIAL = 5000, "glass" = 2500) + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_SMALL + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) + attack_verb = list("burnt") + +/obj/item/weapon/suture + name = "suture" + icon = 'icons/obj/surgery.dmi' + icon_state = "suture" + desc = "Used to stitch up arteries and wounds." + matter = list(DEFAULT_WALL_MATERIAL = 5000, "glass" = 2500) + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_SMALL + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) + +/obj/item/weapon/suture/attack(mob/living/carbon/human/H as mob, mob/living/userr, var/target_zone)//All of this is snowflake because surgery is broken. + //Checks if they're human, have a limb, and have the skill to fix it. + if(!ishuman(H)) + return ..() + if(!ishuman(userr)) + return ..() + + var/mob/living/carbon/human/user = userr + var/obj/item/organ/external/affected = H.get_organ(target_zone) + + if(!affected) + return ..() + + + if(!(affected.status & ORGAN_ARTERY_CUT) && !affected.wounds.len)//There is nothing to fix don't fix anything. + return + + //Ok all the checks are over let's do the quick fix. + if(!user.doing_something) + user.doing_something = TRUE + if(affected.status & ORGAN_ARTERY_CUT)//Fix arteries first, + user.visible_message("[user] begins to suture [H]'s arteries.") + playsound(src, 'sound/weapons/suture.ogg', 70, FALSE) + if(do_mob(user, H, (backwards_skill_scale(user.SKILL_LEVEL(medical)) * 5))) + user.visible_message("[user] has patched the [affected.artery_name] in [H]'s [affected.name] with \the [src.name].", \ + "You have patched the [affected.artery_name] in [H]'s [affected.name] with \the [src.name].") + affected.status &= ~ORGAN_ARTERY_CUT + + else//Then fix wounds if they do it again. + for(var/datum/wound/W in affected.wounds) + if(W.damage) + user.visible_message("[user] begins to suture up [H]'s wounds.") + playsound(src, 'sound/weapons/suture.ogg', 40, FALSE) + H.custom_pain("The pain in your [affected.name] is unbearable!",rand(50, 65),affecting = affected) + if(do_mob(user, H, (backwards_skill_scale(user.SKILL_LEVEL(medical)) * 5))) + // Close it up to a point that it can be bandaged and heal naturally! + W.heal_damage(rand(5,20)+10) + if(W.damage >= W.autoheal_cutoff) + user.visible_message("\The [user] partially closes a wound on [H]'s [affected.name] with \the [src.name].", \ + "You partially close a wound on [H]'s [affected.name] with \the [src.name].") + else + user.visible_message("\The [user] closes a wound on [H]'s [affected.name] with \the [src.name].", \ + "You close a wound on [H]'s [affected.name] with \the [src.name].") + if(!W.damage) + affected.wounds -= W + qdel(W) + else if(W.damage <= 10) + W.clamped = 1 + else + to_chat(user, "There are no wounds to patch up.") + break + + affected.update_damages() + user.doing_something = FALSE + //else + // user.doing_something = FALSE + else + to_chat(user, "You're already trying to suture them.") + + + +/* + * Surgical Drill + */ +/obj/item/weapon/surgicaldrill + name = "surgical drill" + desc = "You can drill using this item. You dig?" + icon = 'icons/obj/surgery.dmi' + icon_state = "drill" + hitsound = 'sound/weapons/circsawhit.ogg' + matter = list(DEFAULT_WALL_MATERIAL = 15000, "glass" = 10000) + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 0 + w_class = ITEM_SIZE_NORMAL + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) + attack_verb = list("drilled") + +/* + * Scalpel + */ +/obj/item/weapon/scalpel + name = "scalpel" + desc = "Cut, cut, and once more cut." + icon = 'icons/obj/surgery.dmi' + icon_state = "scalpel" + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 0 + sharp = 1 + sharpness = 1 + //edge = 1 //WHY THE FUCK DOES THIS HAVE EDGE YOU'RE NOT GOING TO CUT SOMEONE'S HEAD OFF WITH A SCALPEL + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + throwforce = 5.0 + throw_speed = 3 + throw_range = 5 + hitsound = 'sound/weapons/bladeslice.ogg' + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) + matter = list(DEFAULT_WALL_MATERIAL = 10000, "glass" = 5000) + attack_verb = list("slashed", "stabbed") + +/* + * Researchable Scalpels + */ +/obj/item/weapon/scalpel/laser1 + name = "laser scalpel" + desc = "A scalpel augmented with a directed laser, for more precise cutting without blood entering the field. This one looks basic and could be improved." + icon_state = "scalpel_laser1_on" + damtype = "fire" + +/obj/item/weapon/scalpel/laser2 + name = "laser scalpel" + desc = "A scalpel augmented with a directed laser, for more precise cutting without blood entering the field. This one looks somewhat advanced." + icon_state = "scalpel_laser2_on" + damtype = "fire" + force = 12.0 + +/obj/item/weapon/scalpel/laser3 + name = "laser scalpel" + desc = "A scalpel augmented with a directed laser, for more precise cutting without blood entering the field. This one looks to be the pinnacle of precision energy cutlery!" + icon_state = "scalpel_laser3_on" + damtype = "fire" + force = 15.0 + +/obj/item/weapon/scalpel/manager + name = "incision management system" + desc = "A true extension of the surgeon's body, this marvel instantly and completely prepares an incision allowing for the immediate commencement of therapeutic steps." + icon_state = "scalpel_manager_on" + force = 7.5 + +/* + * Circular Saw + */ +/obj/item/weapon/circular_saw + name = "bone saw" + desc = "For heavy duty cutting." + icon = 'icons/obj/surgery.dmi' + icon_state = "saw3" + hitsound = 'sound/weapons/bladeslice.ogg' + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 0 + w_class = ITEM_SIZE_NORMAL + throwforce = 9.0 + throw_speed = 3 + throw_range = 5 + sharpness = 25 + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) + matter = list(DEFAULT_WALL_MATERIAL = 20000,"glass" = 10000) + attack_verb = list("slashed") + sharp = 1 + edge = 1 + +//misc, formerly from code/defines/weapons.dm +/obj/item/weapon/bonegel + name = "bone gel" + icon = 'icons/obj/surgery.dmi' + icon_state = "bone-gel" + force = 0 + w_class = ITEM_SIZE_SMALL + throwforce = 1.0 + +/obj/item/weapon/FixOVein + name = "FixOVein" + icon = 'icons/obj/surgery.dmi' + icon_state = "fixovein" + force = 0 + throwforce = 1.0 + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 3) + w_class = ITEM_SIZE_SMALL + var/usage_amount = 10 + + +/obj/item/weapon/bonesetter + name = "bone setter" + icon = 'icons/obj/surgery.dmi' + icon_state = "bone setter" + force = 0 + throwforce = 9.0 + throw_speed = 3 + throw_range = 5 + w_class = ITEM_SIZE_SMALL + attack_verb = list("attacked", "hit", "bludgeoned") diff --git a/code/game/objects/items/weapons/swords_axes_etc.dm b/code/game/objects/items/weapons/swords_axes_etc.dm new file mode 100644 index 00000000..cbf918b5 --- /dev/null +++ b/code/game/objects/items/weapons/swords_axes_etc.dm @@ -0,0 +1,95 @@ +/* Weapons + * Contains: + * Classic Baton + * Telebaton + */ + +/* + * Classic Baton + */ +/obj/item/weapon/melee/classic_baton + name = "police baton" + desc = "A truncheon for beating criminal scum." + icon = 'icons/obj/weapons.dmi' + icon_state = "baton" + item_state = "nullrod" + slot_flags = SLOT_BELT + force = 15 + block_chance = 15 + +/* +/obj/item/weapon/melee/classic_baton/attack(mob/M as mob, mob/living/user as mob) + if ((CLUMSY in user.mutations) && prob(50)) + to_chat(user, "You club yourself over the head.") + user.Weaken(3 * force) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.apply_damage(2*force, BRUTE, BP_HEAD) + else + user.take_organ_damage(2*force) + return + return ..() +*/ + +/obj/item/weapon/melee/classic_baton/trench_club + name = "trench club" + desc = "A truncheon for beating other people in the same trench as you." + icon_state = "trench_club1" + item_state = "trench_club" + force = 16 + +/obj/item/weapon/melee/classic_baton/trench_club/New() + ..() + icon_state = "trench_club[rand(1,3)]" + +//Telescopic baton +/obj/item/weapon/melee/telebaton + name = "telescopic baton" + desc = "A compact yet rebalanced personal defense weapon. Can be concealed when folded." + icon = 'icons/obj/weapons.dmi' + icon_state = "telebaton_0" + item_state = "telebaton_0" + slot_flags = SLOT_BELT + w_class = ITEM_SIZE_SMALL + force = 3 + var/on = 0 + + +/obj/item/weapon/melee/telebaton/attack_self(mob/user as mob) + on = !on + if(on) + user.visible_message("With a flick of their wrist, [user] extends their telescopic baton.",\ + "You extend the baton.",\ + "You hear an ominous click.") + icon_state = "telebaton_1" + item_state = "nullrod"//was teletbaton_1 but guess what... that icon doesn't exist + w_class = ITEM_SIZE_NORMAL + force = 10//quite robust + attack_verb = list("smacked", "struck", "slapped") + else + user.visible_message("\The [user] collapses their telescopic baton.",\ + "You collapse the baton.",\ + "You hear a click.") + icon_state = "telebaton_0" + item_state = "telebaton_0"//lmao these item_state icons don't even exist + w_class = ITEM_SIZE_SMALL + force = 0//not so robust now + attack_verb = list("hit", "punched") + + update_held_icon() + + playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1) + add_fingerprint(user) + + if(blood_overlay && blood_DNA && (blood_DNA.len >= 1)) //updates blood overlay, if any + + overlays.Cut()//this might delete other item overlays as well but eeeeeeeh + + var/icon/I = new /icon(src.icon, src.icon_state) + I.Blend(new /icon('icons/effects/blood.dmi', COLOR_BLOOD_HUMAN, ICON_ADD))//rgb(255,255,255)),ICON_ADD) + I.Blend(new /icon('icons/effects/blood.dmi', "itemblood"),ICON_MULTIPLY) + blood_overlay = I + + overlays += blood_overlay + + return \ No newline at end of file diff --git a/code/game/objects/items/weapons/syndie.dm b/code/game/objects/items/weapons/syndie.dm new file mode 100644 index 00000000..5b70118f --- /dev/null +++ b/code/game/objects/items/weapons/syndie.dm @@ -0,0 +1,84 @@ +/obj/item/weapon/syndie + icon = 'icons/obj/syndieweapons.dmi' + +/*C-4 explosive charge and etc, replaces the old syndie transfer valve bomb.*/ + + +/*The explosive charge itself. Flashes for five seconds before exploding.*/ + +/obj/item/weapon/syndie/c4explosive + icon_state = "c-4small_0" + item_state = "c-4small" + name = "normal-sized package" + desc = "A small wrapped package." + w_class = ITEM_SIZE_NORMAL + + var/power = 1 /*Size of the explosion.*/ + var/size = "small" /*Used for the icon, this one will make c-4small_0 for the off state.*/ + +/obj/item/weapon/syndie/c4explosive/heavy + icon_state = "c-4large_0" + item_state = "c-4large" + desc = "A mysterious package, it's quite heavy." + power = 2 + size = "large" + +/obj/item/weapon/syndie/c4explosive/New() + var/K = rand(1,2000) + K = md5(num2text(K)+name) + K = copytext(K,1,7) + src.desc += "\n You see [K] engraved on \the [src]." + var/obj/item/weapon/syndie/c4detonator/detonator = new(src.loc) + detonator.desc += "\n You see [K] engraved on the lighter." + detonator.bomb = src + +/obj/item/weapon/syndie/c4explosive/proc/detonate() + icon_state = "c-4[size]_1" + spawn(50) + explosion(get_turf(src), power, power*2, power*3, power*4, power*4) + for(var/dirn in cardinal) //This is to guarantee that C4 at least breaks down all immediately adjacent walls and doors. + var/turf/simulated/wall/T = get_step(src,dirn) + if(locate(/obj/machinery/door/airlock) in T) + var/obj/machinery/door/airlock/D = locate() in T + if(D.density) + D.open() + if(istype(T,/turf/simulated/wall)) + T.dismantle_wall(1) + qdel(src) + + +/*Detonator, disguised as a lighter*/ +/*Click it when closed to open, when open to bring up a prompt asking you if you want to close it or press the button.*/ + +/obj/item/weapon/syndie/c4detonator + icon_state = "c-4detonator_0" + item_state = "c-4detonator" + name = "\improper Zippo lighter" /*Sneaky, thanks Dreyfus.*/ + desc = "The zippo." + w_class = ITEM_SIZE_TINY + + var/obj/item/weapon/syndie/c4explosive/bomb + var/pr_open = 0 /*Is the "What do you want to do?" prompt open?*/ + +/obj/item/weapon/syndie/c4detonator/attack_self(mob/user as mob) + switch(src.icon_state) + if("c-4detonator_0") + src.icon_state = "c-4detonator_1" + to_chat(user, "You flick open the lighter.") + + if("c-4detonator_1") + if(!pr_open) + pr_open = 1 + switch(alert(user, "What would you like to do?", "Lighter", "Press the button.", "Close the lighter.")) + if("Press the button.") + to_chat(user, "You press the button.") + flick("c-4detonator_click", src) + if(src.bomb) + src.bomb.detonate() + log_admin("[key_name(user)] has triggered [src.bomb] with [src].") + message_admins("[key_name_admin(user)] has triggered [src.bomb] with [src].") + + if("Close the lighter.") + src.icon_state = "c-4detonator_0" + to_chat(user, "You close the lighter.") + pr_open = 0 diff --git a/code/game/objects/items/weapons/tagnabber.dm b/code/game/objects/items/weapons/tagnabber.dm new file mode 100644 index 00000000..9ecd2033 --- /dev/null +++ b/code/game/objects/items/weapons/tagnabber.dm @@ -0,0 +1,43 @@ +/obj/item/weapon/tagnabber + name = "Tagnabber" + desc = "Use this on a downed soldier to remove their dogtag!" + icon_state = "nullrod" + item_state = "nullrod" + slot_flags = SLOT_BELT + w_class = ITEM_SIZE_NORMAL + +/obj/item/weapon/tagnabber/attack(mob/living/M, mob/living/user, target_zone, special) + . = ..() + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/weapon/card/id/O = H.get_equipped_item(slot_wear_id) + var/obj/item/weapon/storage/S = user.get_equipped_item(slot_back) + + if(!H.stat) + to_chat(user, "[H] is conscious, this will take about 5 seconds...") + if(!do_after(user, 5 SECONDS, H)) + to_chat(user, "You couldn't grab anything!") + return + + if(O && istype(O)) // if there is a dog tag + if(S && istype(S)) // if there is a backpack + if(S.can_be_inserted(O, user)) // if the backpack can take the dog tag + S.handle_item_insertion(O) + user.visible_message("\The [user] extracts \the [O] from \the [M] and puts it in \the [S]") + + else if(user.put_in_any_hand_if_possible(O)) // if it cant, try to put it in hands + user.visible_message("\The [user] extracts \the [O] from \the [M] and places it in their hand.") + + else // no free hands + to_chat(user, "There is a [O] but you have no backpack or hand to put it!") + + else if(user.put_in_any_hand_if_possible(O)) // if no backpack, try to put in hands + user.visible_message("\The [user] extracts \the [O] from \the [M] and places it in their hand.") + + else // if no free hands + to_chat(user, "There is a [O] but you have no backpack or hand to put it!") + + else // if theres no dog tag + to_chat(user, "\The [H] has nothing to take!") + + diff --git a/code/game/objects/items/weapons/tanks/jetpack.dm b/code/game/objects/items/weapons/tanks/jetpack.dm new file mode 100644 index 00000000..3ab6a777 --- /dev/null +++ b/code/game/objects/items/weapons/tanks/jetpack.dm @@ -0,0 +1,96 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/obj/item/weapon/tank/jetpack + name = "jetpack (empty)" + desc = "A tank of compressed gas for use as propulsion in zero-gravity areas. Use with caution." + icon_state = "jetpack" + gauge_icon = null + w_class = ITEM_SIZE_HUGE + item_state = "jetpack" + distribute_pressure = ONE_ATMOSPHERE*O2STANDARD + var/datum/effect/effect/system/trail/ion/ion_trail + var/on = 0.0 + var/stabilization_on = 0 + var/volume_rate = 500 //Needed for borg jetpack transfer + action_button_name = "Toggle Jetpack" + +/obj/item/weapon/tank/jetpack/Initialize() + . = ..() + ion_trail = new /datum/effect/effect/system/trail/ion() + ion_trail.set_up(src) + +/obj/item/weapon/tank/jetpack/Destroy() + qdel(ion_trail) + ..() + +/obj/item/weapon/tank/jetpack/examine(mob/living/user) + . = ..() + if(air_contents.total_moles < 5) + to_chat(user, "The meter on \the [src] indicates you are almost out of gas!") + +/obj/item/weapon/tank/jetpack/verb/toggle_rockets() + set name = "Toggle Jetpack Stabilization" + set category = "Object" + src.stabilization_on = !( src.stabilization_on ) + to_chat(usr, "You toggle the stabilization [stabilization_on? "on":"off"].") + +/obj/item/weapon/tank/jetpack/verb/toggle() + set name = "Toggle Jetpack" + set category = "Object" + + on = !on + if(on) + icon_state = "[icon_state]-on" + ion_trail.start() + else + icon_state = initial(icon_state) + ion_trail.stop() + + if (ismob(usr)) + var/mob/M = usr + M.update_inv_back() + M.update_action_buttons() + + to_chat(usr, "You toggle the thrusters [on? "on":"off"].") + +/obj/item/weapon/tank/jetpack/proc/allow_thrust(num, mob/living/user as mob) + if(!(src.on)) + return 0 + if((num < 0.005 || src.air_contents.total_moles < num)) + src.ion_trail.stop() + return 0 + + var/datum/gas_mixture/G = src.air_contents.remove(num) + + var/allgases = G.gas["carbon_dioxide"] + G.gas["nitrogen"] + G.gas["oxygen"] + G.gas["phoron"] + if(allgases >= 0.005) + return 1 + + qdel(G) + return + +/obj/item/weapon/tank/jetpack/ui_action_click() + toggle() + + +/obj/item/weapon/tank/jetpack/void + name = "void jetpack (oxygen)" + desc = "It works well in a void." + icon_state = "jetpack-void" + item_state = "jetpack-void" + starting_pressure = list("oxygen" = 6*ONE_ATMOSPHERE) + +/obj/item/weapon/tank/jetpack/oxygen + name = "jetpack (oxygen)" + desc = "A tank of compressed oxygen for use as propulsion in zero-gravity areas. Use with caution." + icon_state = "jetpack" + item_state = "jetpack" + starting_pressure = list("oxygen" = 6*ONE_ATMOSPHERE) + +/obj/item/weapon/tank/jetpack/carbondioxide + name = "jetpack (carbon dioxide)" + desc = "A tank of compressed carbon dioxide for use as propulsion in zero-gravity areas. Painted black to indicate that it should not be used as a source for internals." + distribute_pressure = 0 + icon_state = "jetpack-black" + item_state = "jetpack-black" + starting_pressure = list("carbon_dioxide" = 6*ONE_ATMOSPHERE) diff --git a/code/game/objects/items/weapons/tanks/tank_types.dm b/code/game/objects/items/weapons/tanks/tank_types.dm new file mode 100644 index 00000000..80456130 --- /dev/null +++ b/code/game/objects/items/weapons/tanks/tank_types.dm @@ -0,0 +1,141 @@ +/* Types of tanks! + * Contains: + * Oxygen + * Anesthetic + * Air + * Phoron + * Hydrogen + * Emergency Oxygen + */ + +/* + * Oxygen + */ +/obj/item/weapon/tank/oxygen + name = "oxygen tank" + desc = "A tank of oxygen." + icon_state = "oxygen" + distribute_pressure = ONE_ATMOSPHERE*O2STANDARD + starting_pressure = list("oxygen" = 6*ONE_ATMOSPHERE) + volume = 100 + +/obj/item/weapon/tank/oxygen/yellow + desc = "A tank of oxygen. This one is yellow." + icon_state = "oxygen_f" + +/obj/item/weapon/tank/oxygen/red + desc = "A tank of oxygen. This one is red." + icon_state = "oxygen_fr" + +/* + * Anesthetic + */ +/obj/item/weapon/tank/anesthetic + name = "anesthetic tank" + desc = "A tank with an N2O/O2 gas mix." + icon_state = "anesthetic" + item_state = "an_tank" + starting_pressure = list("oxygen" = 3*ONE_ATMOSPHERE*O2STANDARD, "sleeping_agent" = 3*ONE_ATMOSPHERE*N2STANDARD) + volume = 180 + +/* + * Air + */ +/obj/item/weapon/tank/air + name = "air tank" + desc = "Mixed anyone?" + icon_state = "oxygen" + starting_pressure = list("oxygen" = 6*ONE_ATMOSPHERE*O2STANDARD, "nitrogen" = 6*ONE_ATMOSPHERE*N2STANDARD) + volume = 180 + +/* + * Phoron + */ +/obj/item/weapon/tank/phoron + name = "phoron tank" + desc = "Contains dangerous phoron. Do not inhale. Warning: extremely flammable." + icon_state = "phoron" + gauge_icon = null + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = null //they have no straps! + starting_pressure = list("phoron" = 3*ONE_ATMOSPHERE) + +/* + * Hydrogen + */ +/obj/item/weapon/tank/hydrogen + name = "hydrogen tank" + desc = "Contains hydrogen. Warning: flammable." + icon_state = "hydrogen" + gauge_icon = null + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = null + starting_pressure = list("hydrogen" = 3*ONE_ATMOSPHERE) + +/obj/item/weapon/tank/hydrogen/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + if (istype(W, /obj/item/weapon/flamethrower)) + var/obj/item/weapon/flamethrower/F = W + if (!F.status||F.ptank) return + master = F + F.ptank = src + user.remove_from_mob(src) + forceMove(F) + +/* + * Emergency Oxygen + */ +/obj/item/weapon/tank/emergency + name = "emergency tank" + icon_state = "emergency" + gauge_icon = "indicator_emergency" + gauge_cap = 4 + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + w_class = ITEM_SIZE_SMALL + force = 4 + distribute_pressure = ONE_ATMOSPHERE*O2STANDARD + volume = 40 //Tiny. Real life equivalents only have 21 breaths of oxygen in them. They're EMERGENCY tanks anyway -errorage (dangercon 2011) + +/obj/item/weapon/tank/emergency/oxygen + name = "emergency oxygen tank" + desc = "Used for emergencies. Contains very little oxygen, so try to conserve it until you actually need it." + icon_state = "emergency" + gauge_icon = "indicator_emergency" + starting_pressure = list("oxygen" = 3*ONE_ATMOSPHERE) + +/obj/item/weapon/tank/emergency/oxygen/engi + name = "extended-capacity emergency oxygen tank" + icon_state = "emergency_engi" + volume = 60 + +/obj/item/weapon/tank/emergency/oxygen/double + name = "double emergency oxygen tank" + icon_state = "emergency_double" + gauge_icon = "indicator_emergency_double" + volume = 90 + w_class = ITEM_SIZE_NORMAL + +/obj/item/weapon/tank/emergency/nitrogen + name = "emergency nitrogen tank" + desc = "An emergency air tank hastily painted red and issued to Vox crewmembers." + icon_state = "emergency_nitro" + gauge_icon = "indicator_emergency" + starting_pressure = list("nitrogen" = 3*ONE_ATMOSPHERE) + +/obj/item/weapon/tank/emergency/nitrogen/double + name = "double emergency nitrogen tank" + icon_state = "emergency_double_nitrogen" + gauge_icon = "indicator_emergency_double" + volume = 60 + +/* + * Nitrogen + */ +/obj/item/weapon/tank/nitrogen + name = "nitrogen tank" + desc = "A tank of nitrogen." + icon_state = "oxygen_fr" + distribute_pressure = ONE_ATMOSPHERE*O2STANDARD + starting_pressure = list("nitrogen" = 10*ONE_ATMOSPHERE) + volume = 180 \ No newline at end of file diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm new file mode 100644 index 00000000..0fb84c7e --- /dev/null +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -0,0 +1,592 @@ +#define TANK_RELEASE_PRESSURE 24 +#define TANK_IDEAL_PRESSURE 1015 //Arbitrary. + +var/list/global/tank_gauge_cache = list() + +/obj/item/weapon/tank + name = "tank" + icon = 'icons/obj/tank.dmi' + + var/gauge_icon = "indicator_tank" + var/gauge_cap = 6 + + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BACK + w_class = ITEM_SIZE_LARGE + + force = 5.0 + throwforce = 10.0 + throw_speed = 1 + throw_range = 4 + + var/datum/gas_mixture/air_contents = null + var/distribute_pressure = ONE_ATMOSPHERE + var/integrity = 20 + var/maxintegrity = 20 + var/valve_welded = 0 + var/obj/item/device/tankassemblyproxy/proxyassembly + + var/volume = 70 + var/manipulated_by = null //Used by _onclick/hud/screen_objects.dm internals to determine if someone has messed with our tank or not. + //If they have and we haven't scanned it with the PDA or gas analyzer then we might just breath whatever they put in it. + + var/failure_temp = 173 //173 deg C Borate seal (yes it should be 153 F, but that's annoying) + var/leaking = 0 + var/wired = 0 + + var/list/starting_pressure //list in format 'xgm gas id' = 'desired pressure at start' + + description_info = "These tanks are utilised to store any of the various types of gaseous substances. \ + They can be attached to various portable atmospheric devices to be filled or emptied.
            \ +
            \ + Each tank is fitted with an emergency relief valve. This relief valve will open if the tank is pressurised to over ~3000kPa or heated to over 173�C. \ + The valve itself will close after expending most or all of the contents into the air.
            \ +
            \ + Filling a tank such that experiences ~4000kPa of pressure will cause the tank to rupture, spilling out its contents and destroying the tank. \ + Tanks filled over ~5000kPa will rupture rather violently, exploding with significant force." + + description_antag = "Each tank may be incited to burn by attaching wires and an igniter assembly, though the igniter can only be used once and the mixture only burn if the igniter pushes a flammable gas mixture above the minimum burn temperature (126�C). \ + Wired and assembled tanks may be disarmed with a set of wirecutters. Any exploding or rupturing tank will generate shrapnel, assuming their relief valves have been welded beforehand. Even if not, they can be incited to expel hot gas on ignition if pushed above 173�C. \ + Relatively easy to make, the single tank bomb requries no tank transfer valve, and is still a fairly formidable weapon that can be manufactured from any tank." + + +/obj/item/weapon/tank/Initialize() + . = ..() + proxyassembly = new /obj/item/device/tankassemblyproxy(src) + proxyassembly.tank = src + + air_contents = new /datum/gas_mixture(volume, T20C) + for(var/gas in starting_pressure) + air_contents.adjust_gas(gas, starting_pressure[gas]*volume/(R_IDEAL_GAS_EQUATION*T20C), 0) + air_contents.update_values() + + START_PROCESSING(SSobj, src) + update_icon() + +/obj/item/weapon/tank/Destroy() + QDEL_NULL(air_contents) + + STOP_PROCESSING(SSobj, src) + QDEL_NULL(proxyassembly) + + if(istype(loc, /obj/item/device/transfer_valve)) + var/obj/item/device/transfer_valve/TTV = loc + TTV.remove_tank(src) + qdel(TTV) + + . = ..() + +/obj/item/weapon/tank/examine(mob/user) + . = ..(user, 0) + if(.) + var/celsius_temperature = air_contents.temperature - T0C + var/descriptive + switch(celsius_temperature) + if(300 to INFINITY) + descriptive = "furiously hot" + if(100 to 300) + descriptive = "hot" + if(80 to 100) + descriptive = "warm" + if(40 to 80) + descriptive = "lukewarm" + if(20 to 40) + descriptive = "room temperature" + if(-20 to 20) + descriptive = "cold" + else + descriptive = "bitterly cold" + to_chat(user, "\The [src] feels [descriptive].") + + if(proxyassembly.assembly || wired) + to_chat(user, "It seems to have [wired? "some wires ": ""][wired && proxyassembly.assembly? "and ":""][proxyassembly.assembly ? "some sort of assembly ":""]attached to it.") + if(valve_welded) + to_chat(user, "\The [src] emergency relief valve has been welded shut!") + + +/obj/item/weapon/tank/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + if (istype(loc, /obj/item/assembly)) + icon = loc + + if (istype(W, /obj/item/device/analyzer)) + return + + if (istype(W,/obj/item/latexballon)) + var/obj/item/latexballon/LB = W + LB.blow(src) + add_fingerprint(user) + + if(isCoil(W)) + var/obj/item/stack/cable_coil/C = W + if(C.use(1)) + wired = 1 + to_chat(user, "You attach the wires to the tank.") + update_icon() + + if(isWirecutter(W)) + if(wired && proxyassembly.assembly) + + to_chat(user, "You carefully begin clipping the wires that attach to the tank.") + if(do_after(user, 100,src)) + wired = 0 + to_chat(user, "You cut the wire and remove the device.") + + var/obj/item/device/assembly_holder/assy = proxyassembly.assembly + if(assy.a_left && assy.a_right) + assy.dropInto(usr.loc) + assy.master = null + proxyassembly.assembly = null + else + if(!proxyassembly.assembly.a_left) + assy.a_right.dropInto(usr.loc) + assy.a_right.holder = null + assy.a_right = null + proxyassembly.assembly = null + qdel(assy) + update_icon() + + else + to_chat(user, "You slip and bump the igniter!") + if(prob(85)) + proxyassembly.receive_signal() + + else if(wired) + if(do_after(user, 10, src)) + to_chat(user, "You quickly clip the wire from the tank.") + wired = 0 + update_icon() + + else + to_chat(user, "There are no wires to cut!") + + if(istype(W, /obj/item/device/assembly_holder)) + if(wired) + to_chat(user, "You begin attaching the assembly to \the [src].") + if(do_after(user, 50, src)) + to_chat(user, "You finish attaching the assembly to \the [src].") + GLOB.bombers += "[key_name(user)] attached an assembly to a wired [src]. Temp: [air_contents.temperature-T0C]" + message_admins("[key_name_admin(user)] attached an assembly to a wired [src]. Temp: [air_contents.temperature-T0C]") + assemble_bomb(W,user) + else + to_chat(user, "You stop attaching the assembly.") + else + to_chat(user, "You need to wire the device up first.") + + if(isWelder(W)) + var/obj/item/weapon/weldingtool/WT = W + if(WT.remove_fuel(1,user)) + if(!valve_welded) + to_chat(user, "You begin welding the \the [src] emergency pressure relief valve.") + if(do_after(user, 40,src)) + to_chat(user, "You carefully weld \the [src] emergency pressure relief valve shut. \The [src] may now rupture under pressure!") + valve_welded = 1 + leaking = 0 + else + GLOB.bombers += "[key_name(user)] attempted to weld a [src]. [air_contents.temperature-T0C]" + message_admins("[key_name_admin(user)] attempted to weld a [src]. [air_contents.temperature-T0C]") + if(WT.welding) + to_chat(user, "You accidentally rake \the [W] across \the [src]!") + maxintegrity -= rand(2,6) + integrity = min(integrity,maxintegrity) + air_contents.add_thermal_energy(rand(2000,50000)) + WT.eyecheck(user) + else + to_chat(user, "The emergency pressure relief valve has already been welded.") + add_fingerprint(user) + + + +/obj/item/weapon/tank/attack_self(mob/user as mob) + add_fingerprint(user) + if (!air_contents) + return + ui_interact(user) + +// There's GOT to be a better way to do this + if (proxyassembly.assembly) + proxyassembly.assembly.attack_self(user) + + +/obj/item/weapon/tank/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/mob/living/carbon/location = null + + if(istype(loc, /mob/living/carbon)) + location = loc + + var/using_internal + if(istype(location)) + if(location.internal==src) + using_internal = 1 + + // this is the data which will be sent to the ui + var/data[0] + data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0) + data["releasePressure"] = round(distribute_pressure ? distribute_pressure : 0) + data["defaultReleasePressure"] = round(TANK_RELEASE_PRESSURE) + data["maxReleasePressure"] = round(TANK_MAX_RELEASE_PRESSURE) + data["valveOpen"] = using_internal ? 1 : 0 + data["maskConnected"] = 0 + + if(istype(location)) + var/mask_check = 0 + + if(location.internal == src) // if tank is current internal + mask_check = 1 + else if(src in location) // or if tank is in the mobs possession + if(!location.internal) // and they do not have any active internals + mask_check = 1 + + if(mask_check) + if(location.wear_mask && (location.wear_mask.item_flags & ITEM_FLAG_AIRTIGHT)) + data["maskConnected"] = 1 + else if(istype(location, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = location + if(H.head && (H.head.item_flags & ITEM_FLAG_AIRTIGHT)) + data["maskConnected"] = 1 + + // update the ui if it exists, returns null if no ui is passed/found + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "tanks.tmpl", "Tank", 500, 300) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(1) + +/obj/item/weapon/tank/Topic(user, href_list, state = GLOB.inventory_state) + ..() + +/obj/item/weapon/tank/OnTopic(user, href_list) + if (href_list["dist_p"]) + if (href_list["dist_p"] == "reset") + distribute_pressure = TANK_RELEASE_PRESSURE + else if (href_list["dist_p"] == "max") + distribute_pressure = TANK_MAX_RELEASE_PRESSURE + else + var/cp = text2num(href_list["dist_p"]) + distribute_pressure += cp + distribute_pressure = min(max(round(distribute_pressure), 0), TANK_MAX_RELEASE_PRESSURE) + return TOPIC_REFRESH + + if (href_list["stat"]) + toggle_valve(usr) + return TOPIC_REFRESH + +/obj/item/weapon/tank/proc/toggle_valve(var/mob/user) + if(istype(loc,/mob/living/carbon)) + var/mob/living/carbon/location = loc + if(location.internal == src) + location.internal = null + location.internals.icon_state = "internal0" + to_chat(user, "You close the tank release valve.") + if (location.internals) + location.internals.icon_state = "internal0" + else + var/can_open_valve + if(location.wear_mask && (location.wear_mask.item_flags & ITEM_FLAG_AIRTIGHT)) + can_open_valve = 1 + else if(istype(location,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = location + if(H.head && (H.head.item_flags & ITEM_FLAG_AIRTIGHT)) + can_open_valve = 1 + + if(can_open_valve) + location.internal = src + to_chat(user, "You open \the [src] valve.") + if (location.internals) + location.internals.icon_state = "internal1" + else + to_chat(user, "You need something to connect to \the [src].") + +/obj/item/weapon/tank/remove_air(amount) + return air_contents.remove(amount) + +/obj/item/weapon/tank/return_air() + return air_contents + +/obj/item/weapon/tank/assume_air(datum/gas_mixture/giver) + air_contents.merge(giver) + + check_status() + return 1 + +/obj/item/weapon/tank/proc/remove_air_volume(volume_to_return) + if(!air_contents) + return null + + var/tank_pressure = air_contents.return_pressure() + if(tank_pressure < distribute_pressure) + distribute_pressure = tank_pressure + + var/datum/gas_mixture/removed = remove_air(distribute_pressure*volume_to_return/(R_IDEAL_GAS_EQUATION*air_contents.temperature)) + removed.volume = volume_to_return + return removed + +/obj/item/weapon/tank/Process() + //Allow for reactions + air_contents.react() //cooking up air tanks - add phoron and oxygen, then heat above PHORON_MINIMUM_BURN_TEMPERATURE + update_icon() + check_status() + +/obj/item/weapon/tank/update_icon() + overlays.Cut() + if(proxyassembly.assembly || wired) + overlays += image(icon,"bomb_assembly") + if(proxyassembly.assembly) + var/image/bombthing = image(proxyassembly.assembly.icon, proxyassembly.assembly.icon_state) + bombthing.overlays |= proxyassembly.assembly.overlays + bombthing.pixel_y = -1 + bombthing.pixel_x = -3 + overlays += bombthing + + if(!gauge_icon) + return + + var/gauge_pressure = 0 + if(air_contents) + gauge_pressure = air_contents.return_pressure() + if(gauge_pressure > TANK_IDEAL_PRESSURE) + gauge_pressure = -1 + else + gauge_pressure = round((gauge_pressure/TANK_IDEAL_PRESSURE)*gauge_cap) + + var/indicator = "[gauge_icon][(gauge_pressure == -1) ? "overload" : gauge_pressure]" + if(!tank_gauge_cache[indicator]) + tank_gauge_cache[indicator] = image(icon, indicator) + overlays += tank_gauge_cache[indicator] + +//Handle exploding, leaking, and rupturing of the tank +/obj/item/weapon/tank/proc/check_status() + if(!air_contents) + return 0 + + var/pressure = air_contents.return_pressure() + + if(pressure > TANK_FRAGMENT_PRESSURE) + if(integrity <= 7) + if(!istype(loc,/obj/item/device/transfer_valve)) + message_admins("Explosive tank rupture! last key to touch the tank was [fingerprintslast].") + log_game("Explosive tank rupture! last key to touch the tank was [fingerprintslast].") + + //Give the gas a chance to build up more pressure through reacting + air_contents.react() + air_contents.react() + air_contents.react() + + pressure = air_contents.return_pressure() + var/strength = ((pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE) + + var/mult = ((air_contents.volume/140)**(1/2)) * (air_contents.total_moles**2/3)/((29*0.64) **2/3) //tanks appear to be experiencing a reduction on scale of about 0.64 total moles + //tanks appear to be experiencing a reduction on scale of about 0.64 total moles + + var/turf/simulated/T = get_turf(src) + T.hotspot_expose(air_contents.temperature, 70, 1) + if(!T) + return + + T.assume_air(air_contents) + explosion( + get_turf(loc), + round(min(BOMBCAP_DVSTN_RADIUS, ((mult)*strength)*0.15)), + round(min(BOMBCAP_HEAVY_RADIUS, ((mult)*strength)*0.35)), + round(min(BOMBCAP_LIGHT_RADIUS, ((mult)*strength)*0.80)), + round(min(BOMBCAP_FLASH_RADIUS, ((mult)*strength)*1.20)), + ) + + var/num_fragments = round(rand(8,10) * sqrt(strength * mult)) + fragmentate(T, num_fragments, 7, list(/obj/item/projectile/bullet/pellet/fragment/tank/small = 7,/obj/item/projectile/bullet/pellet/fragment/tank = 2,/obj/item/projectile/bullet/pellet/fragment/strong = 1)) + + if(istype(loc, /obj/item/device/transfer_valve)) + var/obj/item/device/transfer_valve/TTV = loc + TTV.remove_tank(src) + qdel(TTV) + + if(src) + qdel(src) + else + integrity -=7 + else if(pressure > TANK_RUPTURE_PRESSURE) + #ifdef FIREDBG + log_debug("[x],[y] tank is rupturing: [pressure] kPa, integrity [integrity]") + #endif + + if(integrity <= 0) + var/turf/simulated/T = get_turf(src) + if(!T) + return + T.assume_air(air_contents) + playsound(get_turf(src), 'sound/weapons/gunshot/shotgun.ogg', 20, 1) + visible_message("\icon[src] \The [src] flies apart!", "You hear a bang!") + T.hotspot_expose(air_contents.temperature, 70, 1) + + var/strength = 1+((pressure-TANK_LEAK_PRESSURE)/TANK_FRAGMENT_SCALE) + + var/mult = (air_contents.total_moles**2/3)/((29*0.64) **2/3) //tanks appear to be experiencing a reduction on scale of about 0.64 total moles + + var/num_fragments = round(rand(6,8) * sqrt(strength * mult)) //Less chunks, but bigger + fragmentate(T, num_fragments, 7, list(/obj/item/projectile/bullet/pellet/fragment/tank/small = 1,/obj/item/projectile/bullet/pellet/fragment/tank = 5,/obj/item/projectile/bullet/pellet/fragment/strong = 4)) + + if(istype(loc, /obj/item/device/transfer_valve)) + var/obj/item/device/transfer_valve/TTV = loc + TTV.remove_tank(src) + + qdel(src) + else + integrity-= 5 + else if(pressure > TANK_LEAK_PRESSURE || air_contents.temperature - T0C > failure_temp) + if((integrity <= 19 || leaking) && !valve_welded) + var/turf/simulated/T = get_turf(src) + if(!T) + return + var/datum/gas_mixture/environment = loc.return_air() + var/env_pressure = environment.return_pressure() + var/tank_pressure = air_contents.return_pressure() + + var/release_ratio = Clamp(0.002, sqrt(max(tank_pressure-env_pressure,0)/tank_pressure),1) + var/datum/gas_mixture/leaked_gas = air_contents.remove_ratio(release_ratio) + //dynamic air release based on ambient pressure + + T.assume_air(leaked_gas) + if(!leaking) + visible_message("\icon[src] \The [src] relief valve flips open with a hiss!", "You hear hissing.") + playsound(loc, 'sound/effects/spray.ogg', 10, 1, -3) + leaking = 1 + #ifdef FIREDBG + log_debug("[x],[y] tank is leaking: [pressure] kPa, integrity [integrity]") + #endif + else + integrity-= 2 + else + if(integrity < maxintegrity) + integrity++ + if(leaking) + integrity++ + if(integrity == maxintegrity) + leaking = 0 + +///////////////////////////////// +///Prewelded tanks +///////////////////////////////// + +/obj/item/weapon/tank/phoron/welded + valve_welded = 1 +/obj/item/weapon/tank/oxygen/welded + valve_welded = 1 + +///////////////////////////////// +///Onetankbombs (added as actual items) +///////////////////////////////// + +/obj/item/weapon/tank/proc/onetankbomb() + var/phoron_amt = 4 + rand(4) + var/oxygen_amt = 6 + rand(8) + + air_contents.gas["phoron"] = phoron_amt + air_contents.gas["oxygen"] = oxygen_amt + air_contents.update_values() + valve_welded = 1 + air_contents.temperature = PHORON_MINIMUM_BURN_TEMPERATURE-1 + + wired = 1 + + var/obj/item/device/assembly_holder/H = new(src) + proxyassembly.assembly = H + H.master = proxyassembly + + H.update_icon() + update_icon() + +/obj/item/weapon/tank/phoron/onetankbomb/Initialize() + . = ..() + onetankbomb() + +/obj/item/weapon/tank/oxygen/onetankbomb/Initialize() + . = ..() + onetankbomb() + +///////////////////////////////// +///Pulled from rewritten bomb.dm +///////////////////////////////// + +/obj/item/device/tankassemblyproxy + name = "Tank assembly proxy" + desc = "Used as a stand in to trigger single tank assemblies... but you shouldn't see this." + var/obj/item/weapon/tank/tank = null + var/obj/item/device/assembly_holder/assembly = null + +/obj/item/device/tankassemblyproxy/receive_signal() //This is mainly called by the sensor through sense() to the holder, and from the holder to here. + tank.ignite() //boom (or not boom if you made shijwtty mix) + +/obj/item/weapon/tank/proc/assemble_bomb(W,user) //Bomb assembly proc. This turns assembly+tank into a bomb + var/obj/item/device/assembly_holder/S = W + var/mob/M = user + if(!S.secured) //Check if the assembly is secured + return + if(isigniter(S.a_left) == isigniter(S.a_right)) //Check if either part of the assembly has an igniter, but if both parts are igniters, then fuck it + return + + M.drop_item() //Remove the assembly from your hands + M.remove_from_mob(src) //Remove the tank from your character,in case you were holding it + M.put_in_hands(src) //Equips the bomb if possible, or puts it on the floor. + + proxyassembly.assembly = S //Tell the bomb about its assembly part + S.master = proxyassembly //Tell the assembly about its new owner + S.forceMove(src) //Move the assembly + + update_icon() + +/obj/item/weapon/tank/proc/ignite() //This happens when a bomb is told to explode + var/obj/item/device/assembly_holder/assy = proxyassembly.assembly + var/ign = assy.a_right + var/obj/item/other = assy.a_left + + if (isigniter(assy.a_left)) + ign = assy.a_left + other = assy.a_right + + other.dropInto(get_turf(src)) + qdel(ign) + assy.master = null + proxyassembly.assembly = null + qdel(assy) + update_icon() + + air_contents.add_thermal_energy(15000) + +/obj/item/device/tankassemblyproxy/update_icon() + tank.update_icon() + +/obj/item/device/tankassemblyproxy/HasProximity(atom/movable/AM as mob|obj) + if(assembly) + assembly.HasProximity(AM) + +//Fragmentation projectiles + +/obj/item/projectile/bullet/pellet/fragment/tank + name = "metal fragment" + damage = 9 //Big chunks flying off. + range_step = 1 //controls damage falloff with distance. projectiles lose a "pellet" each time they travel this distance. Can be a non-integer. + + base_spread = 0 //causes it to be treated as a shrapnel explosion instead of cone + spread_step = 20 + + silenced = 1 + fire_sound = null + no_attack_log = 1 + muzzle_type = null + pellets = 1 + +/obj/item/projectile/bullet/pellet/fragment/tank/small + name = "small metal fragment" + damage = 6 + +/obj/item/projectile/bullet/pellet/fragment/tank/big + name = "large metal fragment" + damage = 17 + +#undef TANK_RELEASE_PRESSURE diff --git a/code/game/objects/items/weapons/tape.dm b/code/game/objects/items/weapons/tape.dm new file mode 100644 index 00000000..fead9bb0 --- /dev/null +++ b/code/game/objects/items/weapons/tape.dm @@ -0,0 +1,146 @@ +/obj/item/weapon/tape_roll + name = "duct tape" + desc = "A roll of sticky tape. Possibly for taping ducks... or was that ducts?" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "taperoll" + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/tape_roll/attack(var/mob/living/carbon/human/H, var/mob/user) + if(istype(H)) + if(user.zone_sel.selecting == BP_EYES) + + if(!H.organs_by_name[BP_HEAD]) + to_chat(user, "\The [H] doesn't have a head.") + return + if(!H.has_eyes()) + to_chat(user, "\The [H] doesn't have any eyes.") + return + if(H.glasses) + to_chat(user, "\The [H] is already wearing somethign on their eyes.") + return + if(H.head && (H.head.body_parts_covered & FACE)) + to_chat(user, "Remove their [H.head] first.") + return + user.visible_message("\The [user] begins taping over \the [H]'s eyes!") + + if(!do_mob(user, H, 30)) + return + + // Repeat failure checks. + if(!H || !src || !H.organs_by_name[BP_HEAD] || !H.has_eyes() || H.glasses || (H.head && (H.head.body_parts_covered & FACE))) + return + + user.visible_message("\The [user] has taped up \the [H]'s eyes!") + H.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses/blindfold/tape(H), slot_glasses) + + else if(user.zone_sel.selecting == BP_MOUTH || user.zone_sel.selecting == BP_HEAD) + if(!H.organs_by_name[BP_HEAD]) + to_chat(user, "\The [H] doesn't have a head.") + return + if(!H.check_has_mouth()) + to_chat(user, "\The [H] doesn't have a mouth.") + return + if(H.wear_mask) + to_chat(user, "\The [H] is already wearing a mask.") + return + if(H.head && (H.head.body_parts_covered & FACE)) + to_chat(user, "Remove their [H.head] first.") + return + user.visible_message("\The [user] begins taping up \the [H]'s mouth!") + + if(!do_mob(user, H, 30)) + return + + // Repeat failure checks. + if(!H || !src || !H.organs_by_name[BP_HEAD] || !H.check_has_mouth() || H.wear_mask || (H.head && (H.head.body_parts_covered & FACE))) + return + + user.visible_message("\The [user] has taped up \the [H]'s mouth!") + H.equip_to_slot_or_del(new /obj/item/clothing/mask/muzzle/tape(H), slot_wear_mask) + + else if(user.zone_sel.selecting == BP_R_HAND || user.zone_sel.selecting == BP_L_HAND) + var/obj/item/weapon/handcuffs/cable/tape/T = new(user) + if(!T.place_handcuffs(H, user)) + user.unEquip(T) + qdel(T) + else + return ..() + return 1 + +/obj/item/weapon/tape_roll/proc/stick(var/obj/item/weapon/W, mob/user) + if(!istype(W, /obj/item/weapon/paper)) + return + user.drop_from_inventory(W) + var/obj/item/weapon/ducttape/tape = new(get_turf(src)) + tape.attach(W) + user.put_in_hands(tape) + +/obj/item/weapon/ducttape + name = "piece of tape" + desc = "A piece of sticky tape." + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "tape" + w_class = ITEM_SIZE_TINY + layer = ABOVE_OBJ_LAYER + anchored = 1 //it's sticky, no you cant move it + + var/obj/item/weapon/stuck = null + +/obj/item/weapon/ducttape/Initialize() + . = ..() + item_flags |= ITEM_FLAG_NO_BLUDGEON + +/obj/item/weapon/ducttape/examine(mob/user) + return stuck ? stuck.examine(user) : ..() + +/obj/item/weapon/ducttape/proc/attach(var/obj/item/weapon/W) + stuck = W + W.forceMove(src) + icon_state = W.icon_state + "_taped" + name = W.name + " (taped)" + overlays = W.overlays + +/obj/item/weapon/ducttape/attack_self(mob/user) + if(!stuck) + return + + to_chat(user, "You remove \the [initial(name)] from [stuck].") + user.drop_from_inventory(src) + stuck.forceMove(get_turf(src)) + user.put_in_hands(stuck) + stuck = null + overlays = null + qdel(src) + +/obj/item/weapon/ducttape/afterattack(var/A, mob/user, flag, params) + + if(!in_range(user, A) || istype(A, /obj/machinery/door) || !stuck) + return + + var/turf/target_turf = get_turf(A) + var/turf/source_turf = get_turf(user) + + var/dir_offset = 0 + if(target_turf != source_turf) + dir_offset = get_dir(source_turf, target_turf) + if(!(dir_offset in GLOB.cardinal)) + to_chat(user, "You cannot reach that from here.")// can only place stuck papers in cardinal directions, to + return // reduce papers around corners issue. + + user.drop_from_inventory(src) + forceMove(source_turf) + + if(params) + var/list/mouse_control = params2list(params) + if(mouse_control["icon-x"]) + pixel_x = text2num(mouse_control["icon-x"]) - 16 + if(dir_offset & EAST) + pixel_x += 32 + else if(dir_offset & WEST) + pixel_x -= 32 + if(mouse_control["icon-y"]) + pixel_y = text2num(mouse_control["icon-y"]) - 16 + if(dir_offset & NORTH) + pixel_y += 32 + else if(dir_offset & SOUTH) + pixel_y -= 32 diff --git a/code/game/objects/items/weapons/teleportation.dm b/code/game/objects/items/weapons/teleportation.dm new file mode 100644 index 00000000..784d391e --- /dev/null +++ b/code/game/objects/items/weapons/teleportation.dm @@ -0,0 +1,119 @@ +/* Teleportation devices. + * Contains: + * Locator + * Hand-tele + */ + +/* + * Locator + */ +/obj/item/weapon/locator + name = "locator" + desc = "Used to track those with locater implants." + icon = 'icons/obj/device.dmi' + icon_state = "locator" + var/temp = null + var/frequency = 1451 + var/broadcasting = null + var/listening = 1.0 + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_SMALL + item_state = "electronic" + throw_speed = 4 + throw_range = 20 + origin_tech = list(TECH_MAGNET = 1) + matter = list(DEFAULT_WALL_MATERIAL = 400) + +/obj/item/weapon/locator/attack_self(mob/user as mob) + user.set_machine(src) + var/dat + if (src.temp) + dat = "[src.temp]

            Clear" + else + dat = {" +Persistent Signal Locator
            +Frequency: +- +- [format_frequency(src.frequency)] ++ ++
            + +Refresh"} + user << browse(dat, "window=radio") + onclose(user, "radio") + return + +/obj/item/weapon/locator/Topic(href, href_list) + ..() + if (usr.stat || usr.restrained()) + return + var/turf/current_location = get_turf(usr)//What turf is the user on? + if(!current_location||current_location.z==2)//If turf was not found or they're on z level 2. + to_chat(usr, "The [src] is malfunctioning.") + return + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)))) + usr.set_machine(src) + if (href_list["refresh"]) + src.temp = "Persistent Signal Locator
            " + var/turf/sr = get_turf(src) + + if (sr) + src.temp += "Located Beacons:
            " + + for(var/obj/item/device/radio/beacon/W in world) + if (W.frequency == src.frequency) + var/turf/tr = get_turf(W) + if (tr.z == sr.z && tr) + var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y)) + if (direct < 5) + direct = "very strong" + else + if (direct < 10) + direct = "strong" + else + if (direct < 20) + direct = "weak" + else + direct = "very weak" + src.temp += "[W.code]-[dir2text(get_dir(sr, tr))]-[direct]
            " + + src.temp += "Extranneous Signals:
            " + for (var/obj/item/weapon/implant/tracking/W in world) + if (!W.implanted || !(istype(W.loc,/obj/item/organ/external) || ismob(W.loc))) + continue + else + var/mob/M = W.loc + if (M.stat == 2) + if (M.timeofdeath + 6000 < world.time) + continue + + var/turf/tr = get_turf(W) + if (tr.z == sr.z && tr) + var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y)) + if (direct < 20) + if (direct < 5) + direct = "very strong" + else + if (direct < 10) + direct = "strong" + else + direct = "weak" + src.temp += "[W.id]-[dir2text(get_dir(sr, tr))]-[direct]
            " + + src.temp += "You are at \[[sr.x],[sr.y],[sr.z]\] in orbital coordinates.

            Refresh
            " + else + src.temp += "Processing Error: Unable to locate orbital position.
            " + else + if (href_list["freq"]) + src.frequency += text2num(href_list["freq"]) + src.frequency = sanitize_frequency(src.frequency) + else + if (href_list["temp"]) + src.temp = null + if (istype(src.loc, /mob)) + attack_self(src.loc) + else + for(var/mob/M in viewers(1, src)) + if (M.client) + src.attack_self(M) + return diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm new file mode 100644 index 00000000..def00e49 --- /dev/null +++ b/code/game/objects/items/weapons/tools.dm @@ -0,0 +1,706 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/* Tools! + * Note: Multitools are /obj/item/device + * + * Contains: + * Wrench + * Screwdriver + * Wirecutters + * Welding Tool + * Crowbar + */ + +/* + * Wrench + */ +/obj/item/weapon/wrench + name = "wrench" + desc = "A good, durable combination wrench, with self-adjusting, universal open- and ring-end mechanisms to match a wide variety of nuts and bolts." + description_info = "This versatile tool is used for dismantling machine frames, anchoring or unanchoring heavy objects like vending machines and emitters, and much more. In general, if you want something to move or stop moving entirely, you ought to use a wrench on it." + description_fluff = "The classic open-end wrench (or spanner, if you prefer) hasn't changed significantly in shape in over 500 years, though these days they employ a bit of automated trickery to match various bolt sizes and configurations." + description_antag = "Not only is this handy tool good for making off with machines, but it even makes a weapon in a pinch!" + icon = 'icons/obj/tools.dmi' + icon_state = "wrench" + item_state = "wrench" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + force = 8 + throwforce = 7.0 + w_class = ITEM_SIZE_SMALL + origin_tech = list(TECH_MATERIAL = 1, TECH_ENGINEERING = 1) + matter = list(DEFAULT_WALL_MATERIAL = 150) + center_of_mass = "x=17;y=16" + attack_verb = list("bashed", "battered", "bludgeoned", "whacked") + grab_sound = 'sound/items/handle/wrench_pickup.ogg' + drop_sound = 'sound/items/handle/wrench_drop.ogg' + + +/* + * Screwdriver + */ +/obj/item/weapon/screwdriver + name = "screwdriver" + desc = "Your archetypal flathead screwdriver, with a nice, heavy polymer handle." + description_info = "This tool is used to expose or safely hide away cabling. It can open and shut the maintenance panels on vending machines, airlocks, and much more. You can also use it, in combination with a crowbar, to install or remove windows." + description_fluff = "Screws have not changed significantly in centuries, and neither have the drivers used to install and remove them." + description_antag = "In the world of breaking and entering, tools like multitools and wirecutters are the bread; the screwdriver is the butter. In a pinch, try targetting someone's eyes and stabbing them with it - it'll really hurt!" + icon = 'icons/obj/tools.dmi' + icon_state = "screwdriver" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT | SLOT_EARS + force = 5 + w_class = ITEM_SIZE_TINY + throwforce = 3 + throw_speed = 3 + throw_range = 5 + matter = list(DEFAULT_WALL_MATERIAL = 75) + center_of_mass = "x=16;y=7" + attack_verb = list("stabbed") + lock_picking_level = 5 + sharp = TRUE + grab_sound = 'sound/items/handle/screwdriver_pickup.ogg' + drop_sound = 'sound/items/handle/screwdriver_drop.ogg' + +/obj/item/weapon/screwdriver/Initialize() + switch(pick("red","blue","purple","brown","green","cyan","yellow")) + if ("red") + icon_state = "screwdriver2" + item_state = "screwdriver" + if ("blue") + icon_state = "screwdriver" + item_state = "screwdriver_blue" + if ("purple") + icon_state = "screwdriver3" + item_state = "screwdriver_purple" + if ("brown") + icon_state = "screwdriver4" + item_state = "screwdriver_brown" + if ("green") + icon_state = "screwdriver5" + item_state = "screwdriver_green" + if ("cyan") + icon_state = "screwdriver6" + item_state = "screwdriver_cyan" + if ("yellow") + icon_state = "screwdriver7" + item_state = "screwdriver_yellow" + + if (prob(75)) + src.pixel_y = rand(0, 16) + . = ..() + +/obj/item/weapon/screwdriver/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) + if(!istype(M) || user.a_intent == "help") + return ..() + if(user.zone_sel.selecting != BP_EYES && user.zone_sel.selecting != BP_HEAD) + return ..() + if((CLUMSY in user.mutations) && prob(50)) + M = user + return eyestab(M,user) + +/* + * Wirecutters + */ +/obj/item/weapon/wirecutters + name = "wirecutters" + desc = "A special pair of pliers with cutting edges. Various brackets and manipulators built into the handle allow it to repair severed wiring." + description_info = "This tool will cut wiring anywhere you see it - make sure to wear insulated gloves! When used on more complicated machines or airlocks, it can not only cut cables, but repair them, as well." + description_fluff = "With modern alloys, today's wirecutters can snap through cables of astonishing thickness." + description_antag = "These cutters can be used to cripple the power anywhere on the ship. All it takes is some creativity, and being in the right place at the right time." + icon = 'icons/obj/tools.dmi' + icon_state = "cutters" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + force = 3.0 + throw_speed = 2 + throw_range = 9 + w_class = ITEM_SIZE_SMALL + origin_tech = list(TECH_MATERIAL = 1, TECH_ENGINEERING = 1) + matter = list(DEFAULT_WALL_MATERIAL = 80) + center_of_mass = "x=18;y=10" + attack_verb = list("pinched", "nipped") + sharp = TRUE + grab_sound = 'sound/items/handle/wirecutter_pickup.ogg' + drop_sound = 'sound/items/handle/wirecutter_drop.ogg' + +/obj/item/weapon/wirecutters/Initialize() + if(prob(50)) + icon_state = "cutters-y" + item_state = "cutters_yellow" + . = ..() + +/obj/item/weapon/wirecutters/attack(mob/living/carbon/C as mob, mob/living/user as mob) + if(user.a_intent == I_HELP && (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.") + C.handcuffed = null + if(C.buckled && C.buckled.buckle_require_restraints) + C.buckled.unbuckle_mob() + C.update_inv_handcuffed() + return + + remove_shrapnel(C, user) + + //Tearing out teeth + if(ishuman(C) && user.zone_sel.selecting == "mouth") + var/mob/living/carbon/human/H = C + var/obj/item/organ/external/head/O = locate() in H.organs + if(!O || !O.get_teeth()) + to_chat(user, "[H] doesn't have any teeth left!") + return + if(!user.doing_something) + user.doing_something = 1 + H.visible_message("[user] tries to tear off [H]'s tooth with [src]!", + "[user] tries to tear off your tooth with [src]!") + if(do_after(user, 50)) + if(!O || !O.get_teeth()) return + var/obj/item/stack/teeth/E = pick(O.teeth_list) + if(!E || E.zero_amount()) return + var/obj/item/stack/teeth/T = new E.type(H.loc, 1) + E.use(1) + T.add_blood(H) + E.zero_amount() //Try to delete the teeth + H.visible_message("[user] tears off [H]'s tooth with [src]!", + "[user] tears off your tooth with [src]!") + + H.apply_damage(rand(1, 3), BRUTE, O) + H.custom_pain("[pick("OH GOD YOUR MOUTH HURTS SO BAD!", "OH GOD WHY!", "OH GOD YOUR MOUTH!")]", 100, affecting = O) + + playsound(H, 'sound/effects/gore/trauma3.ogg', 40, 1, -1) //And out it goes. + GLOB.teeth_lost++ + + user.doing_something = 0 + else + to_chat(user, "Your attempt to pull out a tooth fails...") + user.doing_something = 0 + return + else + to_chat(user, "You are already trying to pull out a tooth!") + return + + //..() + + +/obj/item/proc/remove_shrapnel(mob/living/C as mob, mob/living/user as mob) + //REMOVE SHRAPNEL! VERY IMPORTANT FOR WARFARE! + if(ishuman(C)) + var/mob/living/carbon/human/H = C + var/mob/living/carbon/human/userr = user + if(userr.a_intent == I_HELP) + var/obj/item/organ/external/organ = H.get_organ(userr.zone_sel.selecting) + for(var/obj/item/weapon/O in organ.implants) + if(istype(O,/obj/item/weapon/material/shard/shrapnel)) + H.visible_message("[userr] starts to remove \the [O.name] with \the [src].") + if(do_after(userr, (backwards_skill_scale(user.SKILL_LEVEL(medical)) * 5))) + for(var/datum/wound/wound in organ.wounds) + wound.embedded_objects -= O + organ.implants -= O + O.forceMove(get_turf(H)) + H.visible_message("[userr] successfully removes \the [O.name] with \the [src].") + H.custom_pain("[pick("OW!", "OH GOD WHY!", "THAT HURTS A LOT!")]", 70, affecting = organ) + playsound(H, 'sound/effects/bullet_remove.ogg', 50) + return + else + return + +/* + * Welding Tool + */ +/obj/item/weapon/weldingtool + name = "welding tool" + icon = 'icons/obj/tools.dmi' + icon_state = "welder" + item_state = "welder" + desc = "A heavy but portable welding gun with its own interchangeable fuel tank. It features a simple toggle switch and a port for attaching an external tank." + description_info = "Use in your hand to toggle the welder on and off. Hold in one hand and click with an empty hand to remove its internal tank. Click on an object to try to weld it. You can seal airlocks, attach heavy-duty machines like emitters and disposal chutes, and repair damaged walls - these are only a few of its uses. Each use of the welder will consume a unit of fuel. Be sure to wear protective equipment such as goggles, a mask, or certain voidsuit helmets to prevent eye damage. You can refill the welder with a welder tank by clicking on it, but be sure to turn it off first!" + description_fluff = "One of many tools of ancient design, still used in today's busy world of engineering with only minor tweaks here and there. Compact machinery and innovations in fuel storage have allowed for conveniences like this one-piece, handheld welder to exist." + description_antag = "You can use a welder to rapidly seal off doors, ventilation ducts, and scrubbers. It also makes for a devastating weapon. Modify it with a screwdriver and stick some metal rods on it, and you've got the beginnings of a flamethrower." + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + center_of_mass = "x=14;y=15" + grab_sound = 'sound/items/handle/weldingtool_pickup.ogg' + drop_sound = 'sound/items/handle/weldingtool_drop.ogg' + + //Amount of OUCH when it's thrown + force = 3.0 + throwforce = 5.0 + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_NORMAL + + //Cost to make in the autolathe + matter = list(DEFAULT_WALL_MATERIAL = 70, "glass" = 30) + + //R&D tech level + origin_tech = list(TECH_ENGINEERING = 1) + + //Welding tool specific stuff + var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2) + var/status = 1 //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower) + + var/obj/item/weapon/welder_tank/tank = /obj/item/weapon/welder_tank // where the fuel is stored + +/obj/item/weapon/weldingtool/Initialize() + if(ispath(tank)) + tank = new tank + + //set_extension(src, /datum/extension/base_icon_state, /datum/extension/base_icon_state, icon_state) + update_icon() + + . = ..() + +/obj/item/weapon/weldingtool/Destroy() + if(welding) + STOP_PROCESSING(SSobj, src) + + QDEL_NULL(tank) + + return ..() + +/obj/item/weapon/weldingtool/examine(mob/user) + if(..(user, 0)) + if(tank) + to_chat(user, "\icon[tank] \The [tank] contains [get_fuel()]/[tank.max_fuel] units of fuel!") + else + to_chat(user, "There is no tank attached.") + +/obj/item/weapon/weldingtool/MouseDrop(atom/over) + if(!CanMouseDrop(over, usr)) + return + + if(istype(over, /obj/item/weapon/weldpack)) + var/obj/item/weapon/weldpack/wp = over + if(wp.welder) + to_chat(usr, "\The [wp] already has \a [wp.welder] attached.") + else + usr.drop_from_inventory(src, wp) + wp.welder = src + usr.visible_message("[usr] attaches \the [src] to \the [wp].", "You attach \the [src] to \the [wp].") + wp.update_icon() + return + + ..() + +/obj/item/weapon/weldingtool/attackby(obj/item/W as obj, mob/user as mob) + if(welding) + to_chat(user, "Stop welding first!") + return + + if(isScrewdriver(W)) + status = !status + if(status) + to_chat(user, "You secure the welder.") + else + to_chat(user, "The welder can now be attached and modified.") + src.add_fingerprint(user) + return + + if((!status) && (istype(W,/obj/item/stack/rods))) + var/obj/item/stack/rods/R = W + R.use(1) + var/obj/item/weapon/flamethrower/F = new/obj/item/weapon/flamethrower(user.loc) + src.loc = F + F.weldtool = src + if (user.client) + user.client.screen -= src + if (user.r_hand == src) + user.remove_from_mob(src) + else + user.remove_from_mob(src) + src.master = F + src.reset_plane_and_layer() + user.remove_from_mob(src) + if (user.client) + user.client.screen -= src + src.loc = F + src.add_fingerprint(user) + return + + if(istype(W, /obj/item/weapon/welder_tank)) + if(tank) + to_chat(user, "Remove the current tank first.") + return + + if(W.w_class >= w_class) + to_chat(user, "\The [W] is too large to fit in \the [src].") + return + + user.drop_from_inventory(W, src) + tank = W + user.visible_message("[user] slots \a [W] into \the [src].", "You slot \a [W] into \the [src].") + update_icon() + return + + ..() + + +/obj/item/weapon/weldingtool/attack_hand(mob/user as mob) + if(tank && user.get_inactive_hand() == src) + if(!welding) + if(tank.can_remove) + user.visible_message("[user] removes \the [tank] from \the [src].", "You remove \the [tank] from \the [src].") + user.put_in_hands(tank) + tank = null + update_icon() + else + to_chat(user, "\The [tank] can't be removed.") + else + to_chat(user, "Stop welding first!") + + else + ..() + + +/obj/item/weapon/weldingtool/Process() + if(welding) + if(!remove_fuel(0.05)) + setWelding(0) + +/obj/item/weapon/weldingtool/afterattack(obj/O as obj, mob/user as mob, proximity) + if(!proximity) return + if (istype(O, /obj/structure/reagent_dispensers/fueltank) && get_dist(src,O) <= 1 && !src.welding) + if(!tank) + to_chat(user, "\The [src] has no tank attached!") + return + O.reagents.trans_to_obj(tank, tank.max_fuel) + to_chat(user, "You refuel \the [tank].") + playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) + return + if (src.welding) + remove_fuel(1) + var/turf/location = get_turf(user) + if(isliving(O)) + var/mob/living/L = O + L.IgniteMob() + if (istype(location, /turf)) + location.hotspot_expose(700, 50, 1) + return + + +/obj/item/weapon/weldingtool/attack_self(mob/user as mob) + setWelding(!welding, usr) + return + +//Returns the amount of fuel in the welder +/obj/item/weapon/weldingtool/proc/get_fuel() + return tank ? tank.reagents.get_reagent_amount(/datum/reagent/fuel) : 0 + + +//Removes fuel from the welding tool. If a mob is passed, it will perform an eyecheck on the mob. This should probably be renamed to use() +/obj/item/weapon/weldingtool/proc/remove_fuel(var/amount = 1, var/mob/M = null) + if(!welding) + return 0 + if(get_fuel() >= amount) + burn_fuel(amount) + if(M) + eyecheck(M) + return 1 + else + if(M) + to_chat(M, "You need more welding fuel to complete this task.") + return 0 + +/obj/item/weapon/weldingtool/proc/burn_fuel(var/amount) + if(!tank) + return + + var/mob/living/in_mob = null + + //consider ourselves in a mob if we are in the mob's contents and not in their hands + if(isliving(src.loc)) + var/mob/living/L = src.loc + if(!(L.l_hand == src || L.r_hand == src)) + in_mob = L + + if(in_mob) + amount = max(amount, 2) + tank.reagents.trans_type_to(in_mob, /datum/reagent/fuel, amount) + in_mob.IgniteMob() + + else + tank.reagents.remove_reagent(/datum/reagent/fuel, amount) + var/turf/location = get_turf(src.loc) + if(location) + location.hotspot_expose(700, 5) + +//Returns whether or not the welding tool is currently on. +/obj/item/weapon/weldingtool/proc/isOn() + return src.welding + +/obj/item/weapon/weldingtool/get_storage_cost() + if(isOn()) + return ITEM_SIZE_NO_CONTAINER + return ..() + +/obj/item/weapon/weldingtool/update_icon() + ..() + + //var/datum/extension/base_icon_state/bis = get_extension(src, /datum/extension/base_icon_state) + icon_state = welding ? "welder1" : "welder" + item_state = welding ? "welder1" : "welder" + + underlays.Cut() + /* + if(tank) + var/image/tank_image = image(tank.icon, icon_state = tank.icon_state) + tank_image.pixel_z = 0 + underlays += tank_image + */ + var/mob/M = loc + if(istype(M)) + M.update_inv_l_hand() + M.update_inv_r_hand() + +//Sets the welding state of the welding tool. If you see W.welding = 1 anywhere, please change it to W.setWelding(1) +//so that the welding tool updates accordingly +/obj/item/weapon/weldingtool/proc/setWelding(var/set_welding, var/mob/M) + if(!status) return + + //If we're turning it on + if(set_welding && !welding) + if (get_fuel() > 0) + if(M) + to_chat(M, "You switch the [src] on.") + M.visible_message("\The [src] turns on.") + playsound(M, 'sound/items/welderactivate.ogg', 100) + src.force = 15 + src.damtype = "fire" + welding = 1 + update_icon() + START_PROCESSING(SSobj, src) + else + if(M) + to_chat(M, "You need more welding fuel to complete this task.") + return + //Otherwise + else if(!set_welding && welding) + STOP_PROCESSING(SSobj, src) + if(M) + to_chat(M, "You switch \the [src] off.") + M.visible_message("\The [src] turns off.") + playsound(M, 'sound/items/welderdeactivate.ogg', 100) + src.force = 3 + src.damtype = "brute" + src.welding = 0 + update_icon() + +//Decides whether or not to damage a player's eyes based on what they're wearing as protection +//Note: This should probably be moved to mob +/obj/item/weapon/weldingtool/proc/eyecheck(mob/user as mob) + if(!iscarbon(user)) return 1 + if(istype(user, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + var/obj/item/organ/internal/eyes/E = H.internal_organs_by_name[BP_EYES] + if(!E) + return + var/safety = H.eyecheck() + switch(safety) + if(FLASH_PROTECTION_MODERATE) + to_chat(H, "Your eyes sting a little.") + //E.damage += rand(1, 2) + //if(E.damage > 12) + H.eye_blurry += rand(3,6) + if(FLASH_PROTECTION_NONE) + to_chat(H, "Your eyes burn.") + H.eye_blurry += rand(4,10) + //E.damage += rand(2, 4) + //if(E.damage > 10) + // E.damage += rand(4,10) + if(FLASH_PROTECTION_REDUCED) + to_chat(H, "Your equipment intensifies the welder's glow. Your eyes itch and burn severely.") + H.eye_blurry += rand(12,20) + //E.damage += rand(12, 16) + /* + if(safety 10) + to_chat(user, "Your eyes are really starting to hurt. This can't be good for you!") + + if (E.damage >= E.min_broken_damage) + to_chat(H, "You go blind!") + H.sdisabilities |= BLIND + else if (E.damage >= E.min_bruised_damage) + to_chat(H, "You go blind!") + H.eye_blind = 5 + H.eye_blurry = 5 + H.disabilities |= NEARSIGHTED + spawn(100) + H.disabilities &= ~NEARSIGHTED + */ + +/obj/item/weapon/welder_tank + name = "welding fuel tank" + desc = "An interchangeable fuel tank meant for a welding tool." + icon = 'icons/obj/tools.dmi' + icon_state = "fuel_m" + w_class = ITEM_SIZE_SMALL + var/max_fuel = 20 + var/can_remove = 1 + +/obj/item/weapon/welder_tank/Initialize() + create_reagents(max_fuel) + reagents.add_reagent(/datum/reagent/fuel, max_fuel) + . = ..() + +/obj/item/weapon/welder_tank/afterattack(obj/O as obj, mob/user as mob, proximity) + if(!proximity) return + if (istype(O, /obj/structure/reagent_dispensers/fueltank) && get_dist(src,O) <= 1) + O.reagents.trans_to_obj(src, max_fuel) + to_chat(user, "You refuel \the [src].") + playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) + return + +/obj/item/weapon/weldingtool/mini + name = "miniature welding tool" + icon_state = "welder_s" + item_state = "welder" + desc = "A smaller welder, meant for quick or emergency use." + origin_tech = list(TECH_ENGINEERING = 2) + matter = list(DEFAULT_WALL_MATERIAL = 15, "glass" = 5) + w_class = ITEM_SIZE_SMALL + tank = /obj/item/weapon/welder_tank/mini + +/obj/item/weapon/welder_tank/mini + name = "small welding fuel tank" + icon_state = "fuel_s" + w_class = ITEM_SIZE_TINY + max_fuel = 5 + can_remove = 0 + +/obj/item/weapon/weldingtool/largetank + name = "industrial welding tool" + icon_state = "welder_l" + item_state = "welder" + desc = "A heavy-duty portable welder, made to ensure it won't suddenly go cold on you." + origin_tech = list(TECH_ENGINEERING = 2) + matter = list(DEFAULT_WALL_MATERIAL = 70, "glass" = 60) + w_class = ITEM_SIZE_LARGE + tank = /obj/item/weapon/welder_tank/large + +/obj/item/weapon/welder_tank/large + name = "large welding fuel tank" + icon_state = "fuel_l" + w_class = ITEM_SIZE_NORMAL + max_fuel = 40 + +/obj/item/weapon/weldingtool/hugetank + name = "upgraded welding tool" + icon_state = "welder_h" + item_state = "welder" + desc = "A sizable welding tool with room to accomodate the largest of fuel tanks." + w_class = ITEM_SIZE_HUGE + origin_tech = list(TECH_ENGINEERING = 3) + matter = list(DEFAULT_WALL_MATERIAL = 70, "glass" = 120) + tank = /obj/item/weapon/welder_tank/huge + +/obj/item/weapon/welder_tank/huge + name = "huge welding fuel tank" + icon_state = "fuel_h" + w_class = ITEM_SIZE_LARGE + max_fuel = 80 + +/obj/item/weapon/weldingtool/experimental + name = "experimental welding tool" + icon_state = "welder_l" + item_state = "welder" + desc = "This welding tool feels heavier in your possession than is normal. There appears to be no external fuel port." + w_class = ITEM_SIZE_LARGE + origin_tech = list(TECH_ENGINEERING = 4, TECH_PHORON = 3) + matter = list(DEFAULT_WALL_MATERIAL = 70, "glass" = 120) + tank = /obj/item/weapon/welder_tank/experimental + +/obj/item/weapon/welder_tank/experimental + name = "experimental welding fuel tank" + icon_state = "fuel_x" + w_class = ITEM_SIZE_NORMAL + max_fuel = 40 + can_remove = 0 + var/last_gen = 0 + +/obj/item/weapon/welder_tank/experimental/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/item/weapon/welder_tank/experimental/Destroy() + STOP_PROCESSING(SSobj, src) + +/obj/item/weapon/welder_tank/experimental/Process() + var/cur_fuel = reagents.get_reagent_amount(/datum/reagent/fuel) + if(cur_fuel < max_fuel) + var/gen_amount = ((world.time-last_gen)/25) + reagents.add_reagent(/datum/reagent/fuel, gen_amount) + last_gen = world.time + +/obj/item/weapon/weldingtool/attack(mob/living/M, mob/living/user, target_zone) + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/S = H.organs_by_name[target_zone] + + if(!S || !(S.robotic >= ORGAN_ROBOT) || user.a_intent != I_HELP) + return ..() + + if(!welding) + to_chat(user, "You'll need to turn [src] on to patch the damage on [M]'s [S.name]!") + return 1 + + if(S.robo_repair(15, BRUTE, "some dents", src, user)) + remove_fuel(1, user) + + else + return ..() + +/* + * Crowbar + */ + +/obj/item/weapon/crowbar + name = "crowbar" + desc = "A heavy crowbar of solid steel, good and solid in your hand." + description_info = "Crowbars have countless uses: click on floor tiles to pry them loose. Use alongside a screwdriver to install or remove windows. Force open emergency shutters, or depowered airlocks. Open the panel of an unlocked APC. Pry a computer's circuit board free. And much more!" + description_fluff = "As is the case with most standard-issue tools, crowbars are a simple and timeless design, the only difference being that advanced materials like plasteel have made them uncommonly tough." + description_antag = "Need to bypass a bolted door? You can use a crowbar to pry the electronics out of an airlock, provided that it has no power and has been welded shut." + icon = 'icons/obj/tools.dmi' + icon_state = "crowbar" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + force = 7.0 + throwforce = 7.0 + throw_range = 3 + item_state = "crowbar" + hitsound = 'sound/weapons/crowbarhit2.ogg' //hitsound = 'sound/weapons/crowhit.ogg'//This sound effect has 0 punch, makes crowbars feel less powerful. + grab_sound = 'sound/items/handle/crowbar_pickup.ogg' + drop_sound = 'sound/items/handle/crowbar_drop.ogg' + w_class = ITEM_SIZE_NORMAL + origin_tech = list(TECH_ENGINEERING = 1) + matter = list(DEFAULT_WALL_MATERIAL = 140) + center_of_mass = "x=16;y=20" + attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked") + block_chance = 15 + parry_sounds = list('sound/weapons/blunt_parry1.ogg', 'sound/weapons/blunt_parry2.ogg', 'sound/weapons/blunt_parry3.ogg') + + +/obj/item/weapon/crowbar/red + icon_state = "red_crowbar" + item_state = "crowbar_red" + +/obj/item/weapon/crowbar/prybar + name = "pry bar" + desc = "A steel bar with a wedge. It comes in a variety of configurations - collect them all." + icon_state = "prybar" + item_state = "crowbar" + force = 4.0 + throwforce = 6.0 + throw_range = 5 + w_class = ITEM_SIZE_SMALL + matter = list(DEFAULT_WALL_MATERIAL = 80) + +/obj/item/weapon/crowbar/prybar/Initialize() + icon_state = "prybar[pick("","_red","_green","_aubergine","_blue")]" + . = ..() + +/obj/item/weapon/handle_shield(mob/living/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + if(default_sword_parry(user, damage, damage_source, attacker, def_zone, attack_text)) + return 1 + return 0 \ No newline at end of file diff --git a/code/game/objects/items/weapons/towels.dm b/code/game/objects/items/weapons/towels.dm new file mode 100644 index 00000000..b61590e6 --- /dev/null +++ b/code/game/objects/items/weapons/towels.dm @@ -0,0 +1,24 @@ +/obj/item/weapon/towel + name = "towel" + icon = 'icons/obj/weapons.dmi' + icon_state = "towel" + slot_flags = SLOT_HEAD | SLOT_BELT | SLOT_OCLOTHING + force = 3.0 + w_class = ITEM_SIZE_NORMAL + attack_verb = list("whipped") + hitsound = 'sound/weapons/towelwhip.ogg' + desc = "A soft cotton towel." + +/obj/item/weapon/towel/attack_self(mob/living/user as mob) + user.visible_message(text("[] uses [] to towel themselves off.", user, src)) + playsound(user, 'sound/weapons/towelwipe.ogg', 25, 1) + +/obj/item/weapon/towel/random/New() + ..() + color = get_random_colour() + +/obj/item/weapon/towel/fleece // loot from the king of goats. it's a golden towel + name = "golden fleece" + desc = "The legendary Golden Fleece of Jason made real." + color = "#ffd700" + attack_verb = list("smote", "whipped") \ No newline at end of file diff --git a/code/game/objects/items/weapons/traps.dm b/code/game/objects/items/weapons/traps.dm new file mode 100644 index 00000000..dac494fd --- /dev/null +++ b/code/game/objects/items/weapons/traps.dm @@ -0,0 +1,118 @@ +/obj/item/weapon/beartrap + name = "mechanical trap" + throw_speed = 2 + throw_range = 1 + gender = PLURAL + icon = 'icons/obj/items.dmi' + icon_state = "beartrap0" + randpixel = 0 + desc = "A mechanically activated leg trap. Low-tech, but reliable. Looks like it could really hurt if you set it off." + throwforce = 0 + w_class = ITEM_SIZE_NORMAL + origin_tech = list(TECH_MATERIAL = 1) + matter = list(DEFAULT_WALL_MATERIAL = 18750) + can_buckle = 0 //disallow manual un/buckling + var/deployed = 0 + +/obj/item/weapon/beartrap/proc/can_use(mob/user) + return (user.IsAdvancedToolUser() && !issilicon(user) && !user.stat && !user.restrained()) + +/obj/item/weapon/beartrap/user_unbuckle_mob(mob/user as mob) + if(buckled_mob && can_use(user)) + user.visible_message( + "\The [user] begins freeing \the [buckled_mob] from \the [src].", + "You carefully begin to free \the [buckled_mob] from \the [src].", + "You hear metal creaking." + ) + if(do_after(user, 60, src)) + user.visible_message("\The [buckled_mob] has been freed from \the [src] by \the [user].") + unbuckle_mob() + anchored = 0 + +/obj/item/weapon/beartrap/attack_self(mob/user as mob) + ..() + if(!deployed && can_use(user)) + user.visible_message( + "[user] starts to deploy \the [src].", + "You begin deploying \the [src]!", + "You hear the slow creaking of a spring." + ) + + if (do_after(user, 60, src)) + user.visible_message( + "\The [user] has deployed \the [src].", + "You have deployed \the [src]!", + "You hear a latch click loudly." + ) + + deployed = 1 + user.drop_from_inventory(src) + update_icon() + anchored = 1 + +/obj/item/weapon/beartrap/attack_hand(mob/user as mob) + if(buckled_mob) + user_unbuckle_mob(user) + else if(deployed && can_use(user)) + user.visible_message( + "[user] starts to disarm \the [src].", + "You begin disarming \the [src]!", + "You hear a latch click followed by the slow creaking of a spring." + ) + if(do_after(user, 60, src)) + user.visible_message( + "[user] has disarmed \the [src].", + "You have disarmed \the [src]!" + ) + deployed = 0 + anchored = 0 + update_icon() + else + ..() + +/obj/item/weapon/beartrap/proc/attack_mob(mob/living/L) + + var/target_zone + if(L.lying) + target_zone = ran_zone() + else + target_zone = pick(BP_L_FOOT, BP_R_FOOT, BP_L_LEG, BP_R_LEG) + + //armour + var/blocked = L.run_armor_check(target_zone, "melee") + + if(blocked >= 100) + return + + if(!L.apply_damage(30, BRUTE, target_zone, blocked, used_weapon=src)) + return 0 + + //trap the victim in place + set_dir(L.dir) + buckle_mob(L) + to_chat(L, "The steel jaws of \the [src] bite into you, trapping you in place!") + deployed = 0 + +/obj/item/weapon/beartrap/Crossed(AM as mob|obj) + if(deployed && isliving(AM)) + var/mob/living/L = AM + if(L.m_intent == "run") + L.visible_message( + "[L] steps on \the [src].", + "You step on \the [src]!", + "You hear a loud metallic snap!" + ) + attack_mob(L) + if(!buckled_mob) + anchored = 0 + deployed = 0 + update_icon() + ..() + +/obj/item/weapon/beartrap/update_icon() + ..() + + if(!deployed) + icon_state = "beartrap0" + else + icon_state = "beartrap1" diff --git a/code/game/objects/items/weapons/trays.dm b/code/game/objects/items/weapons/trays.dm new file mode 100644 index 00000000..e1268f93 --- /dev/null +++ b/code/game/objects/items/weapons/trays.dm @@ -0,0 +1,198 @@ +/* + * Trays - Agouri + */ +/obj/item/weapon/tray + name = "tray" + icon = 'icons/obj/food.dmi' + icon_state = "tray" + desc = "A metal tray to lay food on." + throwforce = 12.0 + throwforce = 10.0 + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_NORMAL + obj_flags = OBJ_FLAG_CONDUCTIBLE + matter = list(DEFAULT_WALL_MATERIAL = 3000) + var/list/carrying = list() // List of things on the tray. - Doohl + var/max_carry = 2*base_storage_cost(ITEM_SIZE_NORMAL) + +/obj/item/weapon/tray/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + // Drop all the things. All of them. + overlays.Cut() + for(var/obj/item/I in carrying) + I.loc = M.loc + carrying.Remove(I) + if(isturf(I.loc)) + spawn() + for(var/i = 1, i <= rand(1,2), i++) + if(I) + step(I, pick(NORTH,SOUTH,EAST,WEST)) + sleep(rand(2,4)) + + + if((CLUMSY in user.mutations) && prob(50)) //What if he's a clown? + to_chat(M, "You accidentally slam yourself with the [src]!") + M.Weaken(1) + user.take_organ_damage(2) + if(prob(50)) + playsound(M, 'sound/items/trayhit1.ogg', 50, 1) + return + else + playsound(M, 'sound/items/trayhit2.ogg', 50, 1) //sound playin' + return //it always returns, but I feel like adding an extra return just for safety's sakes. EDIT; Oh well I won't :3 + + var/mob/living/carbon/human/H = M ///////////////////////////////////// /Let's have this ready for later. + + + if(!(user.zone_sel.selecting == (BP_EYES || BP_HEAD))) //////////////hitting anything else other than the eyes + if(prob(33)) + src.add_blood(H) + var/turf/location = H.loc + if (istype(location, /turf/simulated)) + location.add_blood(H) ///Plik plik, the sound of blood + + admin_attack_log(user, M, "Attacked using \the [src]", "Was attacked with \a [src]", "used \a [src] to attack") + + if(prob(15)) + M.Weaken(3) + M.take_organ_damage(3) + else + M.take_organ_damage(5) + if(prob(50)) + playsound(M, 'sound/items/trayhit1.ogg', 50, 1) + for(var/mob/O in viewers(M, null)) + O.show_message(text("[] slams [] with the tray!", user, M), 1) + return + else + playsound(M, 'sound/items/trayhit2.ogg', 50, 1) //we applied the damage, we played the sound, we showed the appropriate messages. Time to return and stop the proc + for(var/mob/O in viewers(M, null)) + O.show_message(text("[] slams [] with the tray!", user, M), 1) + return + + + var/protected = 0 + for(var/slot in list(slot_head, slot_wear_mask, slot_glasses)) + var/obj/item/protection = M.get_equipped_item(slot) + if(istype(protection) && (protection.body_parts_covered & FACE)) + protected = 1 + break + + if(protected) + to_chat(M, "You get slammed in the face with the tray, against your mask!") + if(prob(33)) + src.add_blood(H) + if (H.wear_mask) + H.wear_mask.add_blood(H) + if (H.head) + H.head.add_blood(H) + if (H.glasses && prob(33)) + H.glasses.add_blood(H) + var/turf/location = H.loc + if (istype(location, /turf/simulated)) //Addin' blood! At least on the floor and item :v + location.add_blood(H) + + if(prob(50)) + playsound(M, 'sound/items/trayhit1.ogg', 50, 1) + for(var/mob/O in viewers(M, null)) + O.show_message(text("[] slams [] with the tray!", user, M), 1) + else + playsound(M, 'sound/items/trayhit2.ogg', 50, 1) //sound playin' + for(var/mob/O in viewers(M, null)) + O.show_message(text("[] slams [] with the tray!", user, M), 1) + if(prob(10)) + M.Stun(rand(1,3)) + M.take_organ_damage(3) + return + else + M.take_organ_damage(5) + return + + else //No eye or head protection, tough luck! + to_chat(M, "You get slammed in the face with the tray!") + if(prob(33)) + src.add_blood(M) + var/turf/location = H.loc + if (istype(location, /turf/simulated)) + location.add_blood(H) + + if(prob(50)) + playsound(M, 'sound/items/trayhit1.ogg', 50, 1) + for(var/mob/O in viewers(M, null)) + O.show_message(text("[] slams [] in the face with the tray!", user, M), 1) + else + playsound(M, 'sound/items/trayhit2.ogg', 50, 1) //sound playin' again + for(var/mob/O in viewers(M, null)) + O.show_message(text("[] slams [] in the face with the tray!", user, M), 1) + if(prob(30)) + M.Stun(rand(2,4)) + M.take_organ_damage(4) + return + else + M.take_organ_damage(8) + if(prob(30)) + M.Weaken(2) + return + return + +/obj/item/weapon/tray/var/cooldown = 0 //shield bash cooldown. based on world.time + +/obj/item/weapon/tray/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/material/kitchen/rollingpin)) + if(cooldown < world.time - 25) + user.visible_message("[user] bashes [src] with [W]!") + playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1) + cooldown = world.time + else + ..() + +/* +===============~~~~~================================~~~~~==================== += = += Code for trays carrying things. By Doohl for Doohl erryday Doohl Doohl~ = += = +===============~~~~~================================~~~~~==================== +*/ +/obj/item/weapon/tray/proc/calc_carry() + . = 0 + for(var/obj/item/I in carrying) + . += I.get_storage_cost() + +/obj/item/weapon/tray/pickup(mob/user) + + if(!isturf(loc)) + return + + for(var/obj/item/I in loc) + if( I != src && !I.anchored && !istype(I, /obj/item/clothing/under) && !istype(I, /obj/item/clothing/suit) && !istype(I, /obj/item/projectile) ) + var/add = I.get_storage_cost() + if(calc_carry() + add >= max_carry) + break + + I.loc = src + carrying.Add(I) + overlays += image("icon" = I.icon, "icon_state" = I.icon_state, "layer" = 30 + I.layer, "pixel_x" = I.pixel_x, "pixel_y" = I.pixel_y) + +/obj/item/weapon/tray/dropped(mob/user) + ..() + spawn(1) //why sleep 1? Because forceMove first drops us on the ground. + if(!isturf(loc)) //to handle hand switching + return + + var/foundtable = 0 + for(var/obj/structure/table/T in loc) + foundtable = 1 + break + + overlays.Cut() + + for(var/obj/item/I in carrying) + I.loc = loc + carrying.Remove(I) + if(!foundtable && isturf(loc)) + // if no table, presume that the person just shittily dropped the tray on the ground and made a mess everywhere! + spawn() + for(var/i = 1, i <= rand(1,2), i++) + if(I) + step(I, pick(NORTH,SOUTH,EAST,WEST)) + sleep(rand(2,4)) diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm new file mode 100644 index 00000000..4a6d8dba --- /dev/null +++ b/code/game/objects/items/weapons/weaponry.dm @@ -0,0 +1,230 @@ +/obj/item/weapon/nullrod + name = "null rod" + desc = "A rod of pure obsidian, its very presence disrupts and dampens the powers of paranormal phenomenae." + icon_state = "nullrod" + item_state = "nullrod" + slot_flags = SLOT_BELT + force = 15 + throw_speed = 1 + throw_range = 4 + throwforce = 10 + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/nullrod/attack(mob/M as mob, mob/living/user as mob) //Paste from old-code to decult with a null rod. + admin_attack_log(user, M, "Attacked using \a [src]", "Was attacked with \a [src]", "used \a [src] to attack") + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(M) + //if(user != M) + if(M.mind && M.mind.learned_spells) + M.silence_spells(300) //30 seconds + to_chat(M, "You've been silenced!") + return + + if (!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") + to_chat(user, "You don't have the dexterity to do this!") + return + + if ((CLUMSY in user.mutations) && prob(50)) + to_chat(user, "The rod slips out of your hand and hits your head.") + user.take_organ_damage(10) + user.Paralyse(20) + return + + if(cult && iscultist(M)) + M.visible_message("\The [user] waves \the [src] over \the [M]'s head.") + cult.offer_uncult(M) + return + + ..() + +/obj/item/weapon/nullrod/afterattack(var/atom/A, var/mob/user, var/proximity) + if(!proximity) + return + if(istype(A, /turf/simulated/wall/cult)) + var/turf/simulated/wall/cult/W = A + user.visible_message("\The [user] touches \the [A] with \the [src] and it starts fizzling and shifting.", "You touch \the [A] with \the [src] and it starts fizzling and shifting.") + W.ChangeTurf(/turf/simulated/wall) + +/obj/item/weapon/energy_net + name = "energy net" + desc = "It's a net made of green energy." + icon = 'icons/effects/effects.dmi' + icon_state = "energynet" + throwforce = 0 + force = 0 + var/net_type = /obj/effect/energy_net + +/obj/item/weapon/energy_net/safari + name = "animal net" + desc = "An energized net meant to subdue animals." + net_type = /obj/effect/energy_net/safari + +/obj/item/weapon/energy_net/dropped() + ..() + spawn(10) + if(src) qdel(src) + +/obj/item/weapon/energy_net/throw_impact(atom/hit_atom) + ..() + + var/mob/living/M = hit_atom + + if(!istype(M) || locate(/obj/effect/energy_net) in M.loc) + qdel(src) + return 0 + + var/turf/T = get_turf(M) + if(T) + var/obj/effect/energy_net/net = new net_type(T) + net.capture_mob(M) + qdel(src) + + // If we miss or hit an obstacle, we still want to delete the net. + spawn(10) + if(src) qdel(src) + +/obj/effect/energy_net + name = "energy net" + desc = "It's a net made of green energy." + icon = 'icons/effects/effects.dmi' + icon_state = "energynet" + + density = 1 + opacity = 0 + mouse_opacity = 1 + anchored = 1 + can_buckle = 0 //no manual buckling or unbuckling + + var/health = 25 + var/countdown = 15 + var/temporary = 1 + var/mob/living/carbon/captured = null + var/min_free_time = 50 + var/max_free_time = 85 + +/obj/effect/energy_net/safari + name = "animal net" + desc = "An energized net meant to subdue animals." + + anchored = 0 + health = 5 + temporary = 0 + min_free_time = 5 + max_free_time = 10 + +/obj/effect/energy_net/teleport + countdown = 60 + +/obj/effect/energy_net/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/effect/energy_net/Destroy() + if(istype(captured, /mob/living/carbon)) + if(captured.handcuffed == src) + captured.handcuffed = null + if(captured) + unbuckle_mob() + STOP_PROCESSING(SSobj, src) + captured = null + return ..() + +/obj/effect/energy_net/Process() + if(temporary) + countdown-- + if(captured.buckled != src) + health = 0 + if(get_turf(src) != get_turf(captured)) //just in case they somehow teleport around or + countdown = 0 + if(countdown <= 0) + health = 0 + healthcheck() + +/obj/effect/energy_net/Move() + ..() + + if(buckled_mob) + buckled_mob.forceMove(src.loc) + else + countdown = 0 + + +/obj/effect/energy_net/proc/capture_mob(mob/living/M) + captured = M + if(M.buckled) + M.buckled.unbuckle_mob() + buckle_mob(M) + if(istype(M, /mob/living/carbon)) + var/mob/living/carbon/C = M + if(!C.handcuffed) + C.handcuffed = src + return 1 + +/obj/effect/energy_net/post_buckle_mob(mob/living/M) + if(buckled_mob) + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + visible_message("\The [M] was caught in [src]!") + else + to_chat(M,"You are free of the net!") + reset_plane_and_layer() + +/obj/effect/energy_net/proc/healthcheck() + if(health <=0) + set_density(0) + if(countdown <= 0) + visible_message("\The [src] fades away!") + else + visible_message("\The [src] is torn apart!") + qdel(src) + +/obj/effect/energy_net/bullet_act(var/obj/item/projectile/Proj) + health -= Proj.get_structure_damage() + healthcheck() + return 0 + +/obj/effect/energy_net/ex_act() + health = 0 + healthcheck() + +/obj/effect/energy_net/attack_hand(var/mob/user) + + var/mob/living/carbon/human/H = user + if(istype(H)) + if(H.species.can_shred(H)) + playsound(src.loc, 'sound/weapons/slash.ogg', 80, 1) + health -= rand(10, 20) + else + health -= rand(1,3) + + else if (HULK in user.mutations) + health = 0 + else + health -= rand(5,8) + + to_chat(H,"You claw at the energy net.") + + healthcheck() + return + +/obj/effect/energy_net/attackby(obj/item/weapon/W as obj, mob/user as mob) + health -= W.force + healthcheck() + ..() + +obj/effect/energy_net/user_unbuckle_mob(mob/user) + return escape_net(user) + + +/obj/effect/energy_net/proc/escape_net(mob/user as mob) + visible_message( + "\The [user] attempts to free themselves from \the [src]!", + "You attempt to free yourself from \the [src]!" + ) + if(do_after(user, rand(min_free_time, max_free_time), src, incapacitation_flags = INCAPACITATION_DISABLED)) + health = 0 + healthcheck() + return 1 + else + return 0 diff --git a/code/game/objects/items/weapons/weldbackpack.dm b/code/game/objects/items/weapons/weldbackpack.dm new file mode 100644 index 00000000..db8f1d84 --- /dev/null +++ b/code/game/objects/items/weapons/weldbackpack.dm @@ -0,0 +1,90 @@ +/obj/item/weapon/weldpack + name = "welding kit" + desc = "An unwieldy, heavy backpack with two massive fuel tanks. Includes a connector for most models of portable welding tools." + description_info = "This pack acts as a portable source of welding fuel. Use a welder on it to refill its tank - but make sure it's not lit! You can use this kit on a fuel tank or appropriate reagent dispenser to replenish its reserves." + description_fluff = "The Shenzhen Chain of 2380 was an industrial accident of noteworthy infamy that occurred at Earth's L3 Lagrange Point. An apprentice welder, working for the Shenzhen Space Fabrication Group, failed to properly seal her fuel port, triggering a chain reaction that spread from laborer to laborer, instantly vaporizing a crew of fourteen. Don't let this happen to you!" + description_antag = "In theory, you could hold an open flame to this pack and produce some pretty catastrophic results. The trick is getting out of the blast radius." + slot_flags = SLOT_BACK + icon = 'icons/obj/storage.dmi' + icon_state = "welderpack" + w_class = ITEM_SIZE_HUGE + var/max_fuel = 350 + var/obj/item/weapon/weldingtool/welder + +/obj/item/weapon/weldpack/Initialize() + create_reagents(max_fuel) + reagents.add_reagent(/datum/reagent/fuel, max_fuel) + + . = ..() + +/obj/item/weapon/weldpack/Destroy() + QDEL_NULL(welder) + + . = ..() + +/obj/item/weapon/weldpack/attackby(obj/item/W as obj, mob/user as mob) + if(isWelder(W)) + var/obj/item/weapon/weldingtool/T = W + if(T.welding & prob(50)) + message_admins("[key_name_admin(user)] triggered a fueltank explosion.") + log_game("[key_name(user)] triggered a fueltank explosion.") + to_chat(user, "That was stupid of you.") + explosion(get_turf(src),-1,0,2) + if(src) + qdel(src) + return + else + if(T.welding) + to_chat(user, "That was close!") + if(!T.tank) + to_chat(user, "\The [T] has no tank attached!") + src.reagents.trans_to_obj(T.tank, T.tank.max_fuel) + to_chat(user, "You refuel \the [W].") + playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) + return + else if(istype(W, /obj/item/weapon/welder_tank)) + var/obj/item/weapon/welder_tank/tank = W + src.reagents.trans_to_obj(tank, tank.max_fuel) + to_chat(user, "You refuel \the [W].") + playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) + return + + to_chat(user, "The tank will accept only a welding tool or cartridge.") + return + +/obj/item/weapon/weldpack/afterattack(obj/O as obj, mob/user as mob, proximity) + if(!proximity) // this replaces and improves the get_dist(src,O) <= 1 checks used previously + return + if (istype(O, /obj/structure/reagent_dispensers/fueltank) && src.reagents.total_volume < max_fuel) + O.reagents.trans_to_obj(src, max_fuel) + to_chat(user, "You crack the cap off the top of the pack and fill it back up again from the tank.") + playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) + return + else if (istype(O, /obj/structure/reagent_dispensers/fueltank) && src.reagents.total_volume == max_fuel) + to_chat(user, "The pack is already full!") + return + +/obj/item/weapon/weldpack/attack_hand(mob/user as mob) + if(welder && user.get_inactive_hand() == src) + user.put_in_hands(welder) + user.visible_message("[user] removes \the [welder] from \the [src].", "You remove \the [welder] from \the [src].") + welder = null + update_icon() + else + ..() + +/obj/item/weapon/weldpack/update_icon() + ..() + + overlays.Cut() + if(welder) + var/image/welder_image = image(welder.icon, icon_state = welder.icon_state) + welder_image.pixel_x = 16 + overlays += welder_image + +/obj/item/weapon/weldpack/examine(mob/user) + . = ..(user) + to_chat(user, text("\icon[] [] units of fuel left!", src, src.reagents.total_volume)) + + if(welder) + to_chat(user, "\The [welder] is attached.") diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm new file mode 100644 index 00000000..686bdaa1 --- /dev/null +++ b/code/game/objects/objs.dm @@ -0,0 +1,159 @@ +/obj + layer = BASE_OBJ_LAYER + + var/obj_flags + + //Used to store information about the contents of the object. + var/list/matter + var/w_class // Size of the object. + var/unacidable = 0 //universal "unacidabliness" var, here so you can use it in any obj. + animate_movement = 2 + var/throwforce = 1 + var/sharp = 0 // whether this object cuts + var/edge = 0 // whether this object is more likely to dismember + var/in_use = 0 // If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING! + var/damtype = "brute" + var/armor_penetration = 0 + var/anchor_fall = FALSE + +/obj/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/proc/is_used_on(obj/O, mob/user) + +/obj/assume_air(datum/gas_mixture/giver) + if(loc) + return loc.assume_air(giver) + else + return null + +/obj/remove_air(amount) + if(loc) + return loc.remove_air(amount) + else + return null + +/obj/return_air() + if(loc) + return loc.return_air() + else + return null + +/obj/proc/updateUsrDialog() + if(in_use) + var/is_in_use = 0 + var/list/nearby = viewers(1, src) + for(var/mob/M in nearby) + if ((M.client && M.machine == src)) + is_in_use = 1 + src.attack_hand(M) + if (istype(usr, /mob/living/silicon/ai) || istype(usr, /mob/living/silicon/robot)) + if (!(usr in nearby)) + if (usr.client && usr.machine==src) // && M.machine == src is omitted because if we triggered this by using the dialog, it doesn't matter if our machine changed in between triggering it and this - the dialog is probably still supposed to refresh. + is_in_use = 1 + src.attack_ai(usr) + + // check for TK users + + if (istype(usr, /mob/living/carbon/human)) + if(istype(usr.l_hand, /obj/item/tk_grab) || istype(usr.r_hand, /obj/item/tk_grab/)) + if(!(usr in nearby)) + if(usr.client && usr.machine==src) + is_in_use = 1 + src.attack_hand(usr) + in_use = is_in_use + +/obj/proc/updateDialog() + // Check that people are actually using the machine. If not, don't update anymore. + if(in_use) + var/list/nearby = viewers(1, src) + var/is_in_use = 0 + for(var/mob/M in nearby) + if ((M.client && M.machine == src)) + is_in_use = 1 + src.interact(M) + var/ai_in_use = AutoUpdateAI(src) + + if(!ai_in_use && !is_in_use) + in_use = 0 + +/obj/attack_ghost(mob/user) + ui_interact(user) + tg_ui_interact(user) + ..() + +/obj/proc/interact(mob/user) + return + +/mob/proc/unset_machine() + src.machine = null + +/mob/proc/set_machine(var/obj/O) + if(src.machine) + unset_machine() + src.machine = O + if(istype(O)) + O.in_use = 1 + +/obj/item/proc/updateSelfDialog() + var/mob/M = src.loc + if(istype(M) && M.client && M.machine == src) + src.attack_self(M) + +/obj/proc/hide(var/hide) + set_invisibility(hide ? INVISIBILITY_MAXIMUM : initial(invisibility)) + +/obj/proc/hides_under_flooring() + return level == 1 + +/obj/proc/hear_talk(mob/M as mob, text, verb, datum/language/speaking) + if(talking_atom) + talking_atom.catchMessage(text, M) +/* + var/mob/mo = locate(/mob) in src + if(mo) + var/rendered = "[M.name]: [text]" + mo.show_message(rendered, 2) + */ + return + +/obj/proc/see_emote(mob/M as mob, text, var/emote_type) + return + +/obj/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2) + return + +/obj/proc/damage_flags() + . = 0 + if(has_edge(src)) + . |= DAM_EDGE + if(is_sharp(src)) + . |= DAM_SHARP + if(damtype == BURN) + . |= DAM_LASER + +/obj/attackby(obj/item/O as obj, mob/user as mob) + if(obj_flags & OBJ_FLAG_ANCHORABLE) + if(isWrench(O)) + wrench_floor_bolts(user) + update_icon() + return + return ..() + +/obj/proc/wrench_floor_bolts(mob/user, delay=20) + playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) + if(anchored) + user.visible_message("\The [user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.") + else + user.visible_message("\The [user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.") + if(do_after(user, delay, src)) + if(!src) return + to_chat(user, "You [anchored? "un" : ""]secured \the [src]!") + anchored = !anchored + return 1 + +/obj/attack_hand(mob/living/user) + if(Adjacent(user)) + add_fingerprint(user) + ..() \ No newline at end of file diff --git a/code/game/objects/random/random.dm b/code/game/objects/random/random.dm new file mode 100644 index 00000000..a054c902 --- /dev/null +++ b/code/game/objects/random/random.dm @@ -0,0 +1,1185 @@ +/obj/random + name = "random object" + desc = "This item type is used to spawn random objects at round-start." + icon = 'icons/misc/mark.dmi' + icon_state = "rup" + var/spawn_nothing_percentage = 0 // this variable determines the likelyhood that this random object will not spawn anything + + var/spawn_method = /obj/random/proc/spawn_item + +// creates a new object and deletes itself +/obj/random/Initialize() + ..() + call(src, spawn_method)() + return INITIALIZE_HINT_QDEL + +// creates the random item +/obj/random/proc/spawn_item() + if(prob(spawn_nothing_percentage)) + return + + if(isnull(loc)) + return + + var/build_path = pickweight(spawn_choices()) + + var/atom/A = new build_path(src.loc) + if(pixel_x || pixel_y) + A.pixel_x = pixel_x + A.pixel_y = pixel_y + +// Returns an associative list in format path:weight +/obj/random/proc/spawn_choices() + return list() + +/obj/random/single + name = "randomly spawned object" + desc = "This item type is used to randomly spawn a given object at round-start." + icon_state = "x3" + var/spawn_object = null + +/obj/random/single/spawn_choices() + return list(ispath(spawn_object) ? spawn_object : text2path(spawn_object)) + +/obj/random/tool + name = "random tool" + desc = "This is a random tool." + icon = 'icons/obj/items.dmi' + icon_state = "welder" + +/obj/random/tool/spawn_choices() + return list(/obj/item/weapon/screwdriver, + /obj/item/weapon/wirecutters, + /obj/item/weapon/weldingtool, + /obj/item/weapon/weldingtool/largetank, + /obj/item/weapon/crowbar, + /obj/item/weapon/wrench, + /obj/item/device/flashlight) + +/obj/random/technology_scanner + name = "random scanner" + desc = "This is a random technology scanner." + icon = 'icons/obj/device.dmi' + icon_state = "atmos" + +/obj/random/technology_scanner/spawn_choices() + return list(/obj/item/device/t_scanner = 5, + /obj/item/device/radio = 2, + /obj/item/device/analyzer = 5) + +/obj/random/powercell + name = "random powercell" + desc = "This is a random powercell." + icon = 'icons/obj/power.dmi' + icon_state = "hcell" + +/obj/random/powercell/spawn_choices() + return list(/obj/item/weapon/cell/crap = 1, + /obj/item/weapon/cell = 8, + /obj/item/weapon/cell/high = 5, + /obj/item/weapon/cell/super = 2, + /obj/item/weapon/cell/hyper = 1, + /obj/item/weapon/cell/device/standard = 7, + /obj/item/weapon/cell/device/high = 5) + +/obj/random/bomb_supply + name = "bomb supply" + desc = "This is a random bomb supply." + icon = 'icons/obj/assemblies/new_assemblies.dmi' + icon_state = "signaller" + +/obj/random/bomb_supply/spawn_choices() + return list(/obj/item/device/assembly/igniter, + /obj/item/device/assembly/prox_sensor, + /obj/item/device/assembly/signaler, + /obj/item/device/assembly/timer, + /obj/item/device/multitool) + +/obj/random/toolbox + name = "random toolbox" + desc = "This is a random toolbox." + icon = 'icons/obj/storage.dmi' + icon_state = "red" + +/obj/random/toolbox/spawn_choices() + return list(/obj/item/weapon/storage/toolbox/mechanical = 30, + /obj/item/weapon/storage/toolbox/electrical = 20, + /obj/item/weapon/storage/toolbox/emergency = 20, + /obj/item/weapon/storage/toolbox/syndicate = 1) + +/obj/random/tech_supply + name = "random tech supply" + desc = "This is a random piece of technology supplies." + icon = 'icons/obj/power.dmi' + icon_state = "cell" + spawn_nothing_percentage = 50 + +/obj/random/tech_supply/spawn_choices() + return list(/obj/random/powercell = 3, + /obj/random/technology_scanner = 2, + /obj/item/weapon/packageWrap = 1, + /obj/item/weapon/hand_labeler = 1, + /obj/random/bomb_supply = 2, + /obj/item/weapon/extinguisher = 1, + /obj/item/clothing/gloves/insulated/cheap = 1, + /obj/item/stack/cable_coil/random = 2, + /obj/random/toolbox = 2, + /obj/item/weapon/storage/belt/utility = 2, + /obj/item/weapon/storage/belt/utility/atmostech = 1, + /obj/random/tool = 5, + /obj/item/weapon/tape_roll = 2) + +/obj/random/medical + name = "Random Medical equipment" + desc = "This is a random medical item." + icon = 'icons/obj/items.dmi' + icon_state = "traumakit" + +/obj/random/medical/spawn_choices() + return list(/obj/random/medical/lite = 21, + /obj/item/bodybag = 2, + /obj/item/weapon/reagent_containers/glass/bottle/inaprovaline = 2, + /obj/item/weapon/reagent_containers/glass/bottle/antitoxin = 2, + /obj/item/weapon/storage/pill_bottle = 2, + /obj/item/weapon/storage/pill_bottle/tramadol = 1, + /obj/item/weapon/storage/pill_bottle/citalopram = 2, + /obj/item/weapon/storage/pill_bottle/dexalin_plus = 1, + /obj/item/weapon/storage/pill_bottle/dermaline = 1, + /obj/item/weapon/storage/pill_bottle/bicaridine = 1, + /obj/item/weapon/reagent_containers/syringe/antitoxin = 2, + /obj/item/weapon/reagent_containers/syringe/antiviral = 1, + /obj/item/weapon/reagent_containers/syringe/inaprovaline = 2, + /obj/item/weapon/storage/box/freezer = 1, + /obj/item/stack/nanopaste = 1) + +/obj/random/medical/lite + name = "Random Medicine" + desc = "This is a random simple medical item." + icon = 'icons/obj/items.dmi' + icon_state = "brutepack" + spawn_nothing_percentage = 25 + +/obj/random/medical/lite/spawn_choices() + return list(/obj/item/stack/medical/bruise_pack = 4, + /obj/item/stack/medical/ointment = 4, + /obj/item/weapon/storage/pill_bottle/antidexafen = 2, + /obj/item/weapon/storage/pill_bottle/paracetamol = 2, + /obj/item/stack/medical/advanced/bruise_pack = 2, + /obj/item/stack/medical/advanced/ointment = 2, + /obj/item/stack/medical/splint = 1, + /obj/item/bodybag/cryobag = 1, + /obj/item/weapon/reagent_containers/hypospray/autoinjector = 3, + /obj/item/weapon/storage/pill_bottle/kelotane = 2, + /obj/item/weapon/storage/pill_bottle/antitox = 2) + +/obj/random/firstaid + name = "Random First Aid Kit" + desc = "This is a random first aid kit." + icon = 'icons/obj/storage.dmi' + icon_state = "firstaid" + +/obj/random/firstaid/spawn_choices() + return list(/obj/item/weapon/storage/firstaid/regular = 4, + /obj/item/weapon/storage/firstaid/toxin = 3, + /obj/item/weapon/storage/firstaid/o2 = 3, + /obj/item/weapon/storage/firstaid/adv = 2, + /obj/item/weapon/storage/firstaid/combat = 1, + /obj/item/weapon/storage/firstaid/empty = 2, + /obj/item/weapon/storage/firstaid/fire = 3) + +/obj/random/contraband + name = "Random Illegal Item" + desc = "Hot Stuff." + icon = 'icons/obj/items.dmi' + icon_state = "purplecomb" + spawn_nothing_percentage = 50 + +/obj/random/contraband/spawn_choices() + return list(/obj/item/weapon/haircomb = 4, + /obj/item/weapon/storage/pill_bottle/tramadol = 3, + /obj/item/weapon/storage/pill_bottle/happy = 2, + /obj/item/weapon/storage/pill_bottle/zoom = 2, + /obj/item/weapon/reagent_containers/glass/beaker/vial/random/toxin = 1, + /obj/item/weapon/reagent_containers/glass/beaker/sulphuric = 1, + /obj/item/weapon/contraband/poster = 5, + /obj/item/weapon/material/butterfly = 2, + /obj/item/weapon/material/butterflyblade = 3, + /obj/item/weapon/material/butterflyhandle = 3, + /obj/item/weapon/material/wirerod = 3, + /obj/item/weapon/melee/baton/cattleprod = 1, + /obj/item/weapon/material/butterfly/switchblade = 1, + /obj/item/weapon/material/hatchet/tacknife = 1, + /obj/item/weapon/material/kitchen/utensil/knife/boot = 2, + /obj/item/weapon/storage/secure/briefcase/money = 1, + /obj/item/weapon/storage/box/syndie_kit/cigarette = 1, + /obj/item/stack/telecrystal = 1, + /obj/item/clothing/under/syndicate = 2, + /obj/item/weapon/reagent_containers/syringe = 3, + /obj/item/weapon/reagent_containers/syringe/steroid = 2, + /obj/item/weapon/reagent_containers/syringe/drugs = 1) + +/obj/random/drinkbottle + name = "random drink" + desc = "This is a random drink." + icon = 'icons/obj/drinks.dmi' + icon_state = "whiskeybottle" + +/obj/random/drinkbottle/spawn_choices() + return list(/obj/item/weapon/reagent_containers/food/drinks/bottle/whiskey, + /obj/item/weapon/reagent_containers/food/drinks/bottle/gin, + /obj/item/weapon/reagent_containers/food/drinks/bottle/specialwhiskey, + /obj/item/weapon/reagent_containers/food/drinks/bottle/vodka, + /obj/item/weapon/reagent_containers/food/drinks/bottle/tequilla, + /obj/item/weapon/reagent_containers/food/drinks/bottle/absinthe, + /obj/item/weapon/reagent_containers/food/drinks/bottle/wine, + /obj/item/weapon/reagent_containers/food/drinks/bottle/cognac, + /obj/item/weapon/reagent_containers/food/drinks/bottle/rum, + /obj/item/weapon/reagent_containers/food/drinks/bottle/patron) + +/obj/random/canned_food + name = "random canned food" + desc = "This is a random canned food" + icon = 'icons/obj/food.dmi' + icon_state = "cbeans" + +/obj/random/canned_food/spawn_choices() + return list(/obj/item/weapon/reagent_containers/food/snacks/warfare, + /obj/item/weapon/reagent_containers/food/snacks/warfare/flower, + /obj/item/weapon/reagent_containers/food/snacks/warfare/rat, + /obj/item/weapon/reagent_containers/food/snacks/warfare/sardine) + +/obj/random/bolt_action + name = "Bolt Action Rifle" + desc = "random bolties" + +/obj/random/bolt_action/spawn_choices() + return list(/obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty, + /obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty/leverchester) + +/obj/random/energy + name = "Random Energy Weapon" + desc = "This is a random energy weapon." + icon = 'icons/obj/gun.dmi' + icon_state = "energykill100" + +/obj/random/energy/spawn_choices() + return list(/obj/item/weapon/gun/energy/laser = 4, + /obj/item/weapon/gun/energy/gun = 3, + /obj/item/weapon/gun/energy/retro = 2, + /obj/item/weapon/gun/energy/lasercannon = 2, + /obj/item/weapon/gun/energy/sniperrifle = 1, + /obj/item/weapon/gun/energy/gun/nuclear = 1, + /obj/item/weapon/gun/energy/ionrifle = 2, + /obj/item/weapon/gun/energy/taser = 4, + /obj/item/weapon/gun/energy/crossbow/largecrossbow = 2, + /obj/item/weapon/gun/energy/stunrevolver = 4) + +/obj/random/projectile + name = "Random Projectile Weapon" + desc = "This is a random projectile weapon." + icon = 'icons/obj/gun.dmi' + icon_state = "revolver" + +/obj/random/projectile/spawn_choices() + return list(/obj/item/weapon/gun/projectile/shotgun/pump = 3, + /obj/item/weapon/gun/projectile/automatic/c20r = 2, + /obj/item/weapon/gun/projectile/automatic/sts35 = 2, + /obj/item/weapon/gun/projectile/automatic/z8 = 2, + /obj/item/weapon/gun/projectile/colt = 4, + /obj/item/weapon/gun/projectile/sec = 4, + /obj/item/weapon/gun/projectile/sec/wood = 3, + /obj/item/weapon/gun/projectile/pistol = 4, + /obj/item/weapon/gun/projectile/pirate = 5, + /obj/item/weapon/gun/projectile/revolver = 2, + /obj/item/weapon/gun/projectile/automatic/wt550 = 3, + /obj/item/weapon/gun/projectile/revolver/detective = 4, + /obj/item/weapon/gun/projectile/revolver/mateba = 2, + /obj/item/weapon/gun/projectile/shotgun/doublebarrel = 4, + /obj/item/weapon/gun/projectile/shotgun/doublebarrel/sawn = 3, + /obj/item/weapon/gun/projectile/heavysniper = 1, + /obj/item/weapon/gun/projectile/shotgun/pump/combat = 2) + +/obj/random/handgun + name = "Random Handgun" + desc = "This is a random sidearm." + icon = 'icons/obj/gun.dmi' + icon_state = "secgundark" + +/obj/random/handgun/spawn_choices() + return list(/obj/item/weapon/gun/projectile/sec = 3, + /obj/item/weapon/gun/energy/gun = 2, + /obj/item/weapon/gun/projectile/colt = 2, + /obj/item/weapon/gun/projectile/pistol = 2, + /obj/item/weapon/gun/energy/retro = 1, + /obj/item/weapon/gun/projectile/sec/wood = 1) + +/obj/random/ammo + name = "Random Ammunition" + desc = "This is random ammunition." + icon = 'icons/obj/ammo.dmi' + icon_state = "45-10" + +/obj/random/ammo/spawn_choices() + return list(/obj/item/weapon/storage/box/beanbags = 6, + /obj/item/weapon/storage/box/shotgunammo = 2, + /obj/item/weapon/storage/box/shotgunshells = 4, + /obj/item/weapon/storage/box/stunshells = 1, + /obj/item/ammo_magazine/c45m = 2, + /obj/item/ammo_magazine/c45m/rubber = 4, + /obj/item/ammo_magazine/c45m/flash = 4, + /obj/item/ammo_magazine/mc9mmt = 2, + /obj/item/ammo_magazine/mc9mmt/rubber = 6) + +/obj/random/action_figure + name = "random action figure" + desc = "This is a random action figure." + icon = 'icons/obj/toy.dmi' + icon_state = "assistant" + +/obj/random/action_figure/spawn_choices() + return list(/obj/item/toy/figure/cmo, + /obj/item/toy/figure/assistant, + /obj/item/toy/figure/atmos, + /obj/item/toy/figure/bartender, + /obj/item/toy/figure/borg, + /obj/item/toy/figure/gardener, + /obj/item/toy/figure/captain, + /obj/item/toy/figure/cargotech, + /obj/item/toy/figure/ce, + /obj/item/toy/figure/chaplain, + /obj/item/toy/figure/chef, + /obj/item/toy/figure/chemist, + /obj/item/toy/figure/clown, + /obj/item/toy/figure/corgi, + /obj/item/toy/figure/detective, + /obj/item/toy/figure/dsquad, + /obj/item/toy/figure/engineer, + /obj/item/toy/figure/geneticist, + /obj/item/toy/figure/hop, + /obj/item/toy/figure/hos, + /obj/item/toy/figure/qm, + /obj/item/toy/figure/janitor, + /obj/item/toy/figure/agent, + /obj/item/toy/figure/librarian, + /obj/item/toy/figure/md, + /obj/item/toy/figure/mime, + /obj/item/toy/figure/miner, + /obj/item/toy/figure/ninja, + /obj/item/toy/figure/wizard, + /obj/item/toy/figure/rd, + /obj/item/toy/figure/roboticist, + /obj/item/toy/figure/scientist, + /obj/item/toy/figure/syndie, + /obj/item/toy/figure/secofficer, + /obj/item/toy/figure/warden, + /obj/item/toy/figure/psychologist, + /obj/item/toy/figure/paramedic, + /obj/item/toy/figure/ert) + + +/obj/random/plushie + name = "random plushie" + desc = "This is a random plushie." + icon = 'icons/obj/toy.dmi' + icon_state = "nymphplushie" + +/obj/random/plushie/spawn_choices() + return list(/obj/item/toy/plushie/nymph, + /obj/item/toy/plushie/mouse, + /obj/item/toy/plushie/kitten, + /obj/item/toy/plushie/lizard) + +/obj/random/plushie/large + name = "random large plushie" + desc = "This is a random large plushie." + icon = 'icons/obj/toy.dmi' + icon_state = "droneplushie" + +/obj/random/plushie/large/spawn_choices() + return list(/obj/structure/plushie/ian, + /obj/structure/plushie/drone, + /obj/structure/plushie/carp, + /obj/structure/plushie/beepsky) + +/obj/random/junk //Broken items, or stuff that could be picked up + name = "random junk" + desc = "This is some random junk." + icon = 'icons/obj/trash.dmi' + icon_state = "trashbag3" + +/obj/random/junk/spawn_choices() + return list(get_random_junk_type()) + +/obj/random/trash //Mostly remains and cleanable decals. Stuff a janitor could clean up + name = "random trash" + desc = "This is some random trash." + icon = 'icons/effects/effects.dmi' + icon_state = "greenglow" + +/obj/random/trash/spawn_choices() + return list(/obj/item/remains/lizard, + /obj/effect/decal/cleanable/blood/gibs/robot, + /obj/effect/decal/cleanable/blood/oil, + /obj/effect/decal/cleanable/blood/oil/streak, + /obj/effect/decal/cleanable/spiderling_remains, + /obj/item/remains/mouse, + /obj/effect/decal/cleanable/vomit, + /obj/effect/decal/cleanable/blood/splatter, + /obj/effect/decal/cleanable/ash, + /obj/effect/decal/cleanable/generic, + /obj/effect/decal/cleanable/flour, + /obj/effect/decal/cleanable/dirt, + /obj/item/remains/robot) + + +obj/random/closet //A couple of random closets to spice up maint + name = "random closet" + desc = "This is a random closet." + icon = 'icons/obj/closet.dmi' + icon_state = "syndicate1" + +obj/random/closet/spawn_choices() + return list(/obj/structure/closet, + /obj/structure/closet/firecloset, + /obj/structure/closet/firecloset/full, + /obj/structure/closet/emcloset, + /obj/structure/closet/jcloset, + /obj/structure/closet/athletic_mixed, + /obj/structure/closet/toolcloset, + /obj/structure/closet/l3closet/general, + /obj/structure/closet/cabinet, + /obj/structure/closet/crate, + /obj/structure/closet/crate/freezer, + /obj/structure/closet/crate/freezer/rations, + /obj/structure/closet/crate/internals, + /obj/structure/closet/crate/trashcart, + /obj/structure/closet/crate/medical, + /obj/structure/closet/boxinggloves, + /obj/structure/largecrate, + /obj/structure/closet/wardrobe/xenos, + /obj/structure/closet/wardrobe/mixed, + /obj/structure/closet/wardrobe/suit, + /obj/structure/closet/wardrobe/orange) + +/obj/random/coin + name = "random coin" + desc = "This is a random coin." + icon = 'icons/obj/items.dmi' + icon_state = "coin" + +/obj/random/coin/spawn_choices() + return list(/obj/item/weapon/coin/gold = 3, + /obj/item/weapon/coin/silver = 4, + /obj/item/weapon/coin/diamond = 2, + /obj/item/weapon/coin/iron = 4, + /obj/item/weapon/coin/uranium = 3, + /obj/item/weapon/coin/platinum = 1, + /obj/item/weapon/coin/phoron = 1) + +/obj/random/toy + name = "random toy" + desc = "This is a random toy." + icon = 'icons/obj/toy.dmi' + icon_state = "ship" + +/obj/random/toy/spawn_choices() + return list(/obj/item/toy/bosunwhistle, + /obj/item/toy/therapy_red, + /obj/item/toy/therapy_purple, + /obj/item/toy/therapy_blue, + /obj/item/toy/therapy_yellow, + /obj/item/toy/therapy_orange, + /obj/item/toy/therapy_green, + /obj/item/toy/cultsword, + /obj/item/toy/katana, + /obj/item/toy/snappop, + /obj/item/toy/sword, + /obj/item/toy/water_balloon, + /obj/item/toy/crossbow, + /obj/item/toy/blink, + /obj/item/weapon/reagent_containers/spray/waterflower, + /obj/item/toy/prize/ripley, + /obj/item/toy/prize/fireripley, + /obj/item/toy/prize/deathripley, + /obj/item/toy/prize/gygax, + /obj/item/toy/prize/durand, + /obj/item/toy/prize/honk, + /obj/item/toy/prize/marauder, + /obj/item/toy/prize/seraph, + /obj/item/toy/prize/mauler, + /obj/item/toy/prize/odysseus, + /obj/item/toy/prize/phazon, + /obj/item/weapon/deck/cards) + +/obj/random/tank + name = "random tank" + desc = "This is a tank." + icon = 'icons/obj/tank.dmi' + icon_state = "canister" + +/obj/random/tank/spawn_choices() + return list(/obj/item/weapon/tank/oxygen = 5, + /obj/item/weapon/tank/oxygen/yellow = 4, + /obj/item/weapon/tank/oxygen/red = 4, + /obj/item/weapon/tank/air = 3, + /obj/item/weapon/tank/emergency/oxygen = 4, + /obj/item/weapon/tank/emergency/oxygen/engi = 3, + /obj/item/weapon/tank/emergency/oxygen/double = 2, + /obj/item/weapon/tank/emergency/nitrogen = 2, + /obj/item/weapon/tank/emergency/nitrogen/double = 1, + /obj/item/weapon/tank/nitrogen = 1, + /obj/item/device/suit_cooling_unit = 1) + +/obj/random/material //Random materials for building stuff + name = "random material" + desc = "This is a random material." + icon = 'icons/obj/items.dmi' + icon_state = "sheet-metal" + +/obj/random/material/spawn_choices() + return list(/obj/item/stack/material/steel/ten, + /obj/item/stack/material/glass/ten, + /obj/item/stack/material/glass/reinforced/ten, + /obj/item/stack/material/plastic/ten, + /obj/item/stack/material/wood/ten, + /obj/item/stack/material/cardboard/ten, + /obj/item/stack/rods/ten, + /obj/item/stack/material/plasteel/ten, + /obj/item/stack/material/steel/fifty, + /obj/item/stack/material/glass/fifty, + /obj/item/stack/material/glass/reinforced/fifty, + /obj/item/stack/material/plastic/fifty, + /obj/item/stack/material/wood/fifty, + /obj/item/stack/material/cardboard/fifty, + /obj/item/stack/rods/fifty, + /obj/item/stack/material/plasteel/fifty) + +/obj/random/soap + name = "Random Cleaning Supplies" + desc = "This is a random bar of soap. Soap! SOAP?! SOAP!!!" + icon = 'icons/obj/items.dmi' + icon_state = "soap" + +/obj/random/soap/spawn_choices() + return list(/obj/item/weapon/soap = 4, + /obj/item/weapon/soap/nanotrasen = 3, + /obj/item/weapon/soap/deluxe = 3, + /obj/item/weapon/soap/syndie = 1, + /obj/item/weapon/soap/gold = 1, + /obj/item/weapon/reagent_containers/glass/rag = 2, + /obj/item/weapon/reagent_containers/spray/cleaner = 2, + /obj/item/weapon/grenade/chem_grenade/cleaner = 1) + +obj/random/obstruction //Large objects to block things off in maintenance + name = "random obstruction" + desc = "This is a random obstruction." + icon = 'icons/obj/cult.dmi' + icon_state = "cultgirder" + +obj/random/obstruction/spawn_choices() + return list(/obj/structure/barricade, + /obj/structure/girder, + /obj/structure/girder/displaced, + /obj/structure/girder/reinforced, + /obj/structure/grille, + /obj/structure/grille/broken, + /obj/structure/foamedmetal, + /obj/item/weapon/caution, + /obj/item/weapon/caution/cone, + /obj/structure/inflatable/wall, + /obj/structure/inflatable/door) + +/obj/random/assembly + name = "random assembly" + desc = "This is a random circuit assembly." + icon = 'icons/obj/items.dmi' + icon_state = "gift1" + +/obj/random/assembly/spawn_choices() + return list(/obj/item/device/electronic_assembly, + /obj/item/device/electronic_assembly/medium, + /obj/item/device/electronic_assembly/large, + /obj/item/device/electronic_assembly/drone) + +/obj/random/advdevice + name = "random advanced device" + desc = "This is a random advanced device." + icon = 'icons/obj/items.dmi' + icon_state = "game_kit" + +/obj/random/advdevice/spawn_choices() + return list(/obj/item/device/flashlight/lantern, + /obj/item/device/flashlight/flare, + /obj/item/device/flashlight/pen, + /obj/item/device/toner, + /obj/item/device/paicard, + /obj/item/device/destTagger, + /obj/item/weapon/beartrap, + /obj/item/weapon/handcuffs, + /obj/item/weapon/camera_assembly, + /obj/item/device/camera, + /obj/item/device/pda, + /obj/item/weapon/card/emag_broken, + /obj/item/device/radio/headset, + /obj/item/device/flashlight/glowstick/yellow, + /obj/item/device/flashlight/glowstick/orange) + +/obj/random/smokes + name = "random smokeable" + desc = "This is a random smokeable item." + icon = 'icons/obj/cigarettes.dmi' + icon_state = "Bpacket" + +/obj/random/smokes/spawn_choices() + return list(/obj/item/weapon/storage/fancy/cigarettes = 5, + /obj/item/weapon/storage/fancy/cigarettes/dromedaryco = 4, + /obj/item/weapon/storage/fancy/cigarettes/killthroat = 1, + /obj/item/weapon/storage/fancy/cigarettes/luckystars = 3, + /obj/item/weapon/storage/fancy/cigarettes/jerichos = 3, + /obj/item/weapon/storage/fancy/cigarettes/menthols = 2, + /obj/item/weapon/storage/fancy/cigarettes/carcinomas = 3, + /obj/item/weapon/storage/fancy/cigarettes/professionals = 2, + /obj/item/weapon/storage/fancy/cigar = 1, + /obj/item/clothing/mask/smokable/cigarette = 2, + /obj/item/clothing/mask/smokable/cigarette/menthol = 2, + /obj/item/clothing/mask/smokable/cigarette/cigar = 1, + /obj/item/clothing/mask/smokable/cigarette/cigar/cohiba = 1, + /obj/item/clothing/mask/smokable/cigarette/cigar/havana = 1) + +/obj/random/masks + name = "random mask" + desc = "This is a random face mask." + icon = 'icons/obj/clothing/masks.dmi' + icon_state = "gas_mask" + +/obj/random/masks/spawn_choices() + return list(/obj/item/clothing/mask/gas = 4, + /obj/item/clothing/mask/gas/half = 5, + /obj/item/clothing/mask/gas/swat = 1, + /obj/item/clothing/mask/gas/syndicate = 1, + /obj/item/clothing/mask/breath = 6, + /obj/item/clothing/mask/breath/medical = 4, + /obj/item/clothing/mask/balaclava = 3, + /obj/item/clothing/mask/balaclava/tactical = 2, + /obj/item/clothing/mask/surgical = 4) + +/obj/random/snack + name = "random snack" + desc = "This is a random snack item." + icon = 'icons/obj/food.dmi' + icon_state = "sosjerky" + +/obj/random/snack/spawn_choices() + return list(/obj/item/weapon/reagent_containers/food/snacks/liquidfood, + /obj/item/weapon/reagent_containers/food/snacks/candy, + /obj/item/weapon/reagent_containers/food/drinks/dry_ramen, + /obj/item/weapon/reagent_containers/food/snacks/chips, + /obj/item/weapon/reagent_containers/food/snacks/sosjerky, + /obj/item/weapon/reagent_containers/food/snacks/no_raisin, + /obj/item/weapon/reagent_containers/food/snacks/spacetwinkie, + /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers, + /obj/item/weapon/reagent_containers/food/snacks/tastybread, + /obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar, + /obj/item/weapon/reagent_containers/food/snacks/syndicake, + /obj/item/weapon/reagent_containers/food/snacks/donut, + /obj/item/weapon/reagent_containers/food/snacks/donut/cherryjelly, + /obj/item/weapon/reagent_containers/food/snacks/donut/jelly, + /obj/item/pizzabox/meat, + /obj/item/pizzabox/vegetable, + /obj/item/pizzabox/margherita, + /obj/item/pizzabox/mushroom, + /obj/item/weapon/reagent_containers/food/snacks/plumphelmetbiscuit, + /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks) + + +/obj/random/storage + name = "random storage item" + desc = "This is a storage item." + icon = 'icons/obj/storage.dmi' + icon_state = "idOld" + +/obj/random/storage/spawn_choices() + return list(/obj/item/weapon/storage/secure/briefcase = 2, + /obj/item/weapon/storage/briefcase = 4, + /obj/item/weapon/storage/briefcase/inflatable = 3, + /obj/item/weapon/storage/backpack = 5, + /obj/item/weapon/storage/backpack/satchel = 5, + /obj/item/weapon/storage/backpack/dufflebag = 2, + /obj/item/weapon/storage/box = 5, + /obj/item/weapon/storage/box/donkpockets = 3, + /obj/item/weapon/storage/box/sinpockets = 1, + /obj/item/weapon/storage/box/donut = 2, + /obj/item/weapon/storage/box/cups = 3, + /obj/item/weapon/storage/box/mousetraps = 4, + /obj/item/weapon/storage/box/engineer = 3, + /obj/item/weapon/storage/box/autoinjectors = 2, + /obj/item/weapon/storage/box/beakers = 3, + /obj/item/weapon/storage/box/syringes = 3, + /obj/item/weapon/storage/box/gloves = 3, + /obj/item/weapon/storage/box/large = 2, + /obj/item/weapon/storage/box/glowsticks = 3, + /obj/item/weapon/storage/wallet = 1, + /obj/item/weapon/storage/ore = 2, + /obj/item/weapon/storage/belt/utility/full = 2, + /obj/item/weapon/storage/belt/medical/emt = 2, + /obj/item/weapon/storage/belt/medical = 2, + /obj/item/weapon/storage/belt/security = 2, + /obj/item/weapon/storage/belt/security/tactical = 1) + +/obj/random/shoes + name = "random footwear" + desc = "This is a random pair of shoes." + icon = 'icons/obj/clothing/shoes.dmi' + icon_state = "boots" + +/obj/random/shoes/spawn_choices() + return list(/obj/item/clothing/shoes/workboots = 3, + /obj/item/clothing/shoes/jackboots = 3, + /obj/item/clothing/shoes/swat = 1, + /obj/item/clothing/shoes/combat = 1, + /obj/item/clothing/shoes/galoshes = 2, + /obj/item/clothing/shoes/syndigaloshes = 1, + /obj/item/clothing/shoes/magboots = 1, + /obj/item/clothing/shoes/laceup = 4, + /obj/item/clothing/shoes/black = 4, + /obj/item/clothing/shoes/jungleboots = 3, + /obj/item/clothing/shoes/desertboots = 3, + /obj/item/clothing/shoes/dutyboots = 3, + /obj/item/clothing/shoes/tactical = 1, + /obj/item/clothing/shoes/dress = 3, + /obj/item/clothing/shoes/dress/white = 3, + /obj/item/clothing/shoes/sandal = 3, + /obj/item/clothing/shoes/brown = 4, + /obj/item/clothing/shoes/red = 4, + /obj/item/clothing/shoes/blue = 4, + /obj/item/clothing/shoes/leather = 4) + +/obj/random/gloves + name = "random gloves" + desc = "This is a random pair of gloves." + icon = 'icons/obj/clothing/gloves.dmi' + icon_state = "rainbow" + +/obj/random/gloves/spawn_choices() + return list(/obj/item/clothing/gloves/insulated = 3, + /obj/item/clothing/gloves/thick = 6, + /obj/item/clothing/gloves/thick/botany = 5, + /obj/item/clothing/gloves/latex = 4, + /obj/item/clothing/gloves/thick/swat = 3, + /obj/item/clothing/gloves/thick/combat = 3, + /obj/item/clothing/gloves/white = 5, + /obj/item/clothing/gloves/rainbow = 1, + /obj/item/clothing/gloves/duty = 5, + /obj/item/clothing/gloves/guards = 3, + /obj/item/clothing/gloves/tactical = 3, + /obj/item/clothing/gloves/insulated/cheap = 5) + +/obj/random/glasses + name = "random eyewear" + desc = "This is a random pair of glasses." + icon = 'icons/obj/clothing/glasses.dmi' + icon_state = "leforge" + +/obj/random/glasses/spawn_choices() + return list(/obj/item/clothing/glasses/sunglasses = 3, + /obj/item/clothing/glasses/regular = 7, + /obj/item/clothing/glasses/meson = 5, + /obj/item/clothing/glasses/meson/prescription = 4, + /obj/item/clothing/glasses/science = 6, + /obj/item/clothing/glasses/material = 5, + /obj/item/clothing/glasses/welding = 3, + /obj/item/clothing/glasses/hud/health = 4, + /obj/item/clothing/glasses/hud/health/prescription = 3, + /obj/item/clothing/glasses/hud/security = 4, + /obj/item/clothing/glasses/hud/security/prescription = 3, + /obj/item/clothing/glasses/sunglasses/sechud = 2, + /obj/item/clothing/glasses/sunglasses/sechud/toggle = 3, + /obj/item/clothing/glasses/sunglasses/sechud/goggles = 1, + /obj/item/clothing/glasses/tacgoggles = 1) + +/obj/random/hat + name = "random headgear" + desc = "This is a random hat of some kind." + icon = 'icons/obj/clothing/hats.dmi' + icon_state = "tophat" + +/obj/random/hat/spawn_choices() + return list(/obj/item/clothing/head/helmet = 2, + /obj/item/clothing/head/helmet/tactical = 1, + /obj/item/clothing/head/helmet/space/emergency = 1, + /obj/item/clothing/head/bio_hood/general = 1, + /obj/item/clothing/head/hardhat = 4, + /obj/item/clothing/head/hardhat/orange = 4, + /obj/item/clothing/head/hardhat/red = 4, + /obj/item/clothing/head/hardhat/dblue = 4, + /obj/item/clothing/head/ushanka = 3, + /obj/item/clothing/head/welding = 2) + +/obj/random/suit + name = "random suit" + desc = "This is a random piece of outerwear." + icon = 'icons/obj/clothing/suits.dmi' + icon_state = "fire" + +/obj/random/suit/spawn_choices() + return list(/obj/item/clothing/suit/storage/hazardvest = 4, + /obj/item/clothing/suit/storage/toggle/labcoat = 4, + /obj/item/clothing/suit/space/emergency = 1, + /obj/item/clothing/suit/armor/vest = 4, + /obj/item/clothing/suit/storage/vest/tactical = 1, + /obj/item/clothing/suit/storage/vest = 3, + /obj/item/clothing/suit/storage/toggle/bomber = 3, + /obj/item/clothing/suit/chef/classic = 3, + /obj/item/clothing/suit/surgicalapron = 2, + /obj/item/clothing/suit/apron/overalls = 3, + /obj/item/clothing/suit/bio_suit/general = 1, + /obj/item/clothing/suit/storage/toggle/hoodie/black = 3, + /obj/item/clothing/suit/storage/toggle/brown_jacket = 3, + /obj/item/clothing/suit/storage/leather_jacket = 3, + /obj/item/clothing/suit/apron = 4) + +/obj/random/clothing + name = "random clothes" + desc = "This is a random piece of clothing." + icon = 'icons/obj/clothing/uniforms.dmi' + icon_state = "grey" + +/obj/random/clothing/spawn_choices() + return list(/obj/item/clothing/under/syndicate/tacticool = 2, + /obj/item/clothing/under/syndicate/combat = 1, + /obj/item/clothing/under/hazard = 4, + /obj/item/clothing/under/sterile = 4, + /obj/item/clothing/under/casual_pants/camo = 2, + /obj/item/clothing/under/frontier = 2, + /obj/item/clothing/under/harness = 2, + /obj/item/clothing/under/rank/medical/paramedic = 2, + /obj/item/clothing/under/overalls = 2, + /obj/item/clothing/ears/earmuffs = 2, + /obj/item/clothing/under/tactical = 1) + +/obj/random/accessory + name = "random accessory" + desc = "This is a random utility accessory." + icon = 'icons/obj/clothing/ties.dmi' + icon_state = "horribletie" + +/obj/random/accessory/spawn_choices() + return list(/obj/item/clothing/accessory/storage/webbing = 3, + /obj/item/clothing/accessory/storage/webbing_large = 3, + /obj/item/clothing/accessory/storage/black_vest = 2, + /obj/item/clothing/accessory/storage/brown_vest = 2, + /obj/item/clothing/accessory/storage/white_vest = 2, + /obj/item/clothing/accessory/storage/bandolier = 1, + /obj/item/clothing/accessory/holster/thigh = 1, + /obj/item/clothing/accessory/holster/hip = 1, + /obj/item/clothing/accessory/holster/waist = 1, + /obj/item/clothing/accessory/holster/armpit = 1, + /obj/item/clothing/accessory/kneepads = 3, + /obj/item/clothing/accessory/stethoscope = 2) + +/obj/random/cash + name = "random currency" + desc = "LOADSAMONEY!" + icon = 'icons/obj/items.dmi' + icon_state = "spacecash1" + +/obj/random/cash/spawn_choices() + return list(/obj/item/weapon/spacecash/bundle/c1 = 4, + /obj/item/weapon/spacecash/bundle/c10 = 3, + /obj/item/weapon/spacecash/bundle/c20 = 3, + /obj/item/weapon/spacecash/bundle/c50 = 2, + /obj/item/weapon/spacecash/bundle/c100 = 2, + /obj/item/weapon/spacecash/bundle/c1000 = 1) + +/obj/random/maintenance //Clutter and loot for maintenance and away missions + name = "random maintenance item" + desc = "This is a random maintenance item." + icon = 'icons/obj/items.dmi' + icon_state = "gift1" + +/obj/random/maintenance/spawn_choices() + return list(/obj/random/junk = 4, + /obj/random/trash = 4, + /obj/random/maintenance/clean = 5) + +/obj/random/maintenance/clean +/*Maintenance loot lists without the trash, for use inside things. +Individual items to add to the maintenance list should go here, if you add +something, make sure it's not in one of the other lists.*/ + name = "random clean maintenance item" + desc = "This is a random clean maintenance item." + icon = 'icons/obj/items.dmi' + icon_state = "gift2" + +/obj/random/maintenance/clean/spawn_choices() + return list(/obj/random/tech_supply = 100, + /obj/random/medical = 40, + /obj/random/medical/lite = 80, + /obj/random/firstaid = 20, + /obj/random/powercell = 50, + /obj/random/technology_scanner = 80, + /obj/random/bomb_supply = 80, + /obj/random/contraband = 1, + /obj/random/action_figure = 2, + /obj/random/plushie = 2, + /obj/random/material = 40, + /obj/random/coin = 5, + /obj/random/toy = 20, + /obj/random/tank = 20, + /obj/random/soap = 5, + /obj/random/drinkbottle = 5, + /obj/random/loot = 1, + /obj/random/advdevice = 50, + /obj/random/smokes = 30, + /obj/random/masks = 10, + /obj/random/snack = 60, + /obj/random/storage = 30, + /obj/random/shoes = 20, + /obj/random/gloves = 10, + /obj/random/glasses = 20, + /obj/random/hat = 10, + /obj/random/suit = 20, + /obj/random/clothing = 30, + /obj/random/accessory = 20, + /obj/random/cash = 10) + +/obj/random/loot /*Better loot for away missions and salvage */ + name = "random loot" + desc = "This is some random loot." + icon = 'icons/obj/items.dmi' + icon_state = "gift3" + +/obj/random/loot/spawn_choices() + return list(/obj/random/energy = 10, + /obj/random/projectile = 10, + /obj/random/voidhelmet = 10, + /obj/random/voidsuit = 10, + /obj/item/clothing/mask/muzzle = 7, + /obj/item/clothing/mask/gas/vox = 8, + /obj/item/clothing/mask/gas/syndicate = 10, + /obj/item/clothing/glasses/night = 3, + /obj/item/clothing/glasses/thermal = 1, + /obj/item/clothing/glasses/welding/superior = 7, + /obj/item/clothing/head/collectable/petehat = 4, + /obj/item/clothing/suit/storage/vest/merc = 3, + /obj/item/clothing/suit/straight_jacket = 6, + /obj/item/clothing/head/helmet/merc = 3, + /obj/item/stack/material/diamond/ten = 7, + /obj/item/stack/material/glass/phoronrglass/ten = 7, + /obj/item/stack/material/marble/ten = 8, + /obj/item/stack/material/phoron/ten = 7, + /obj/item/stack/material/gold/ten = 7, + /obj/item/stack/material/silver/ten = 7, + /obj/item/stack/material/osmium/ten = 7, + /obj/item/stack/material/platinum/ten = 8, + /obj/item/stack/material/tritium/ten = 7, + /obj/item/stack/material/mhydrogen/ten = 6, + /obj/item/stack/material/plasteel/ten = 9, + /obj/item/weapon/storage/box/monkeycubes = 5, + /obj/item/weapon/storage/box/monkeycubes/neaeracubes = 4, + /obj/item/weapon/storage/box/monkeycubes/stokcubes = 4, + /obj/item/weapon/storage/box/monkeycubes/farwacubes = 4, + /obj/item/weapon/storage/firstaid/surgery = 4, + /obj/item/weapon/cell/infinite = 1, + /obj/item/weapon/archaeological_find = 2, + /obj/machinery/artifact = 1, + /obj/item/device/multitool/hacktool = 2, + /obj/item/weapon/surgicaldrill = 7, + /obj/item/weapon/FixOVein = 7, + /obj/item/weapon/retractor = 7, + /obj/item/weapon/hemostat = 7, + /obj/item/weapon/cautery = 7, + /obj/item/weapon/bonesetter = 7, + /obj/item/weapon/bonegel = 7, + /obj/item/weapon/circular_saw = 7, + /obj/item/weapon/scalpel = 7, + /obj/item/weapon/melee/baton/loaded = 9, + /obj/item/device/radio/headset/syndicate = 6) + +/obj/random/voidhelmet + name = "Random Voidsuit Helmet" + desc = "This is a random voidsuit helmet." + icon = 'icons/obj/clothing/hats.dmi' + icon_state = "void" + +/obj/random/voidhelmet/spawn_choices() + return list(/obj/item/clothing/head/helmet/space/void, + /obj/item/clothing/head/helmet/space/void/engineering, + /obj/item/clothing/head/helmet/space/void/engineering/alt, + /obj/item/clothing/head/helmet/space/void/engineering/salvage, + /obj/item/clothing/head/helmet/space/void/mining, + /obj/item/clothing/head/helmet/space/void/mining/alt, + /obj/item/clothing/head/helmet/space/void/security, + /obj/item/clothing/head/helmet/space/void/security/alt, + /obj/item/clothing/head/helmet/space/void/atmos, + /obj/item/clothing/head/helmet/space/void/atmos/alt, + /obj/item/clothing/head/helmet/space/void/merc, + /obj/item/clothing/head/helmet/space/void/medical, + /obj/item/clothing/head/helmet/space/void/medical/alt) + +/obj/random/voidsuit + name = "Random Voidsuit" + desc = "This is a random voidsuit." + icon = 'icons/obj/clothing/suits.dmi' + icon_state = "void" + +/obj/random/voidsuit/spawn_choices() + return list(/obj/item/clothing/suit/space/void, + /obj/item/clothing/suit/space/void/engineering, + /obj/item/clothing/suit/space/void/engineering/alt, + /obj/item/clothing/suit/space/void/engineering/salvage, + /obj/item/clothing/suit/space/void/mining, + /obj/item/clothing/suit/space/void/mining/alt, + /obj/item/clothing/suit/space/void/security, + /obj/item/clothing/suit/space/void/security/alt, + /obj/item/clothing/suit/space/void/atmos, + /obj/item/clothing/suit/space/void/atmos/alt, + /obj/item/clothing/suit/space/void/merc, + /obj/item/clothing/suit/space/void/medical, + /obj/item/clothing/suit/space/void/medical/alt) + +/obj/random/hostile + name = "Random Hostile Mob" + desc = "This is a random hostile mob." + icon = 'icons/mob/amorph.dmi' + icon_state = "standing" + spawn_nothing_percentage = 80 + +obj/random/hostile/spawn_choices() + return list(/mob/living/simple_animal/hostile/viscerator, + /mob/living/simple_animal/hostile/carp, + /mob/living/simple_animal/hostile/carp/pike, + /mob/living/simple_animal/hostile/vagrant/swarm) + +/obj/random/mob/roaches + name = "random roach" + icon_state = "standing" + +/obj/random/mob/roaches/spawn_choices() + return list(/mob/living/simple_animal/hostile/retaliate/roach,\ + /mob/living/simple_animal/hostile/retaliate/roach/tank,\ + /mob/living/simple_animal/hostile/retaliate/roach/hunter,\ + /mob/living/simple_animal/hostile/retaliate/roach/fuhrer) + +/obj/random/mob/roaches/low_chance + name = "low chance random roach" + icon_state = "standing" + spawn_nothing_percentage = 70 + +/obj/random/mining_hostile + name = "Random Hostile Mining Mob" + +/obj/random/mining_hostile/spawn_choices() + return list(/mob/living/simple_animal/hostile/mining_borg,\ + /mob/living/simple_animal/hostile/mining_borg/behemoth,\ + /mob/living/simple_animal/hostile/mining_borg/thin,\ + /mob/living/simple_animal/hostile/mining_borg/sleek,\ + /mob/living/simple_animal/hostile/mining_borg/buff, \ + /mob/living/simple_animal/hostile/mining_borg/minesect) + + + +/* + Selects one spawn point out of a group of points with the same ID and asks it to generate its items +*/ +var/list/multi_point_spawns + +/obj/random_multi + name = "random object spawn point" + desc = "This item type is used to spawn random objects at round-start. Only one spawn point for a given group id is selected." + icon = 'icons/misc/mark.dmi' + icon_state = "x3" + invisibility = INVISIBILITY_MAXIMUM + var/id // Group id + var/weights // Probability weight for this spawn point + +/obj/random_multi/Initialize() + . = ..() + weights = max(1, round(weights)) + + if(!multi_point_spawns) + multi_point_spawns = list() + var/list/spawnpoints = multi_point_spawns[id] + if(!spawnpoints) + spawnpoints = list() + multi_point_spawns[id] = spawnpoints + spawnpoints[src] = weights + +/obj/random_multi/Destroy() + var/list/spawnpoints = multi_point_spawns[id] + spawnpoints -= src + if(!spawnpoints.len) + multi_point_spawns -= id + . = ..() + +/obj/random_multi/proc/generate_items() + return + +/obj/random_multi/single_item + var/item_path // Item type to spawn + +/obj/random_multi/single_item/generate_items() + new item_path(loc) + +/hook/roundstart/proc/generate_multi_spawn_items() + for(var/id in multi_point_spawns) + var/list/spawn_points = multi_point_spawns[id] + var/obj/random_multi/rm = pickweight(spawn_points) + rm.generate_items() + for(var/entry in spawn_points) + qdel(entry) + return 1 + +/obj/random_multi/single_item/captains_spare_id + name = "Multi Point - Captain's Spare" + id = "Captain's spare id" + item_path = /obj/item/weapon/card/id/captains_spare + +var/list/random_junk_ +var/list/random_useful_ +/proc/get_random_useful_type() + if(!random_useful_) + random_useful_ = list() + random_useful_ += /obj/item/weapon/pen/crayon/random + random_useful_ += /obj/item/weapon/pen + random_useful_ += /obj/item/weapon/pen/blue + random_useful_ += /obj/item/weapon/pen/red + random_useful_ += /obj/item/weapon/pen/multi + random_useful_ += /obj/item/weapon/storage/box/matches + random_useful_ += /obj/item/stack/material/cardboard + random_useful_ += /obj/item/weapon/storage/fancy/cigarettes + random_useful_ += /obj/item/weapon/deck/cards + return pick(random_useful_) + +/proc/get_random_junk_type() + if(prob(20)) // Misc. clutter + return /obj/effect/decal/cleanable/generic + + // 80% chance that we reach here + if(prob(95)) // Misc. junk + if(!random_junk_) + random_junk_ = subtypesof(/obj/item/trash) + random_junk_ += typesof(/obj/item/weapon/cigbutt) + random_junk_ += /obj/effect/decal/cleanable/spiderling_remains + random_junk_ += /obj/item/remains/mouse + random_junk_ += /obj/item/remains/robot + random_junk_ += /obj/item/weapon/paper/crumpled + random_junk_ += /obj/item/inflatable/torn + random_junk_ += /obj/effect/decal/cleanable/molten_item + random_junk_ += /obj/item/weapon/material/shard + random_junk_ += /obj/item/weapon/hand/missing_card + + random_junk_ -= /obj/item/trash/plate + random_junk_ -= /obj/item/trash/snack_bowl + random_junk_ -= /obj/item/trash/syndi_cakes + random_junk_ -= /obj/item/trash/tray + return pick(random_junk_) + + // Misc. actually useful stuff or perhaps even food + // 4% chance that we reach here + if(prob(75)) + return get_random_useful_type() + + // 1% chance that we reach here + var/lunches = lunchables_lunches() + return lunches[pick(lunches)] diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm new file mode 100644 index 00000000..efe92a8a --- /dev/null +++ b/code/game/objects/structures.dm @@ -0,0 +1,46 @@ +/obj/structure + icon = 'icons/obj/structures.dmi' + w_class = ITEM_SIZE_NO_CONTAINER + + var/breakable + var/parts + +/obj/structure/Destroy() + if(parts) + new parts(loc) + . = ..() + +/obj/structure/attack_hand(mob/user) + ..() + if(breakable) + if(HULK in user.mutations) + user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) + attack_generic(user,1,"smashes") + else if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(H.species.can_shred(user)) + attack_generic(user,1,"slices") + return ..() + +/obj/structure/attack_tk() + return + +/obj/structure/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + if(prob(50)) + qdel(src) + return + if(3.0) + return + +/obj/structure/attack_generic(var/mob/user, var/damage, var/attack_verb, var/wallbreaker) + if(!breakable || !damage || !wallbreaker) + return 0 + visible_message("[user] [attack_verb] the [src] apart!") + attack_animation(user) + spawn(1) qdel(src) + return 1 diff --git a/code/game/objects/structures/alien/alien.dm b/code/game/objects/structures/alien/alien.dm new file mode 100644 index 00000000..5ae3e43b --- /dev/null +++ b/code/game/objects/structures/alien/alien.dm @@ -0,0 +1,62 @@ +/obj/structure/alien + name = "alien thing" + desc = "There's something alien about this." + icon = 'icons/mob/alien.dmi' + layer = ABOVE_OBJ_LAYER + var/health = 50 + +/obj/structure/alien/proc/healthcheck() + if(health <=0) + set_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(PASS_FLAG_GLASS)) + return !opacity + return !density diff --git a/code/game/objects/structures/alien/egg.dm b/code/game/objects/structures/alien/egg.dm new file mode 100644 index 00000000..e477f104 --- /dev/null +++ b/code/game/objects/structures/alien/egg.dm @@ -0,0 +1,97 @@ +#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/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/structure/alien/egg/Destroy() + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/structure/alien/egg/CanUseTopic(var/mob/user) + return isghost(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/observer/ghost/O in GLOB.ghost_mob_list) + if(O.client && O.client.prefs && (MODE_XENOMORPH in O.client.prefs.be_special_role)) + to_chat(O, "An alien is ready to hatch! ([ghost_follow_link(src, O)]) (spawn)") + STOP_PROCESSING(SSobj, 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/observer/ghost/user) + if(progress == -1) //Egg has been hatched. + return + + if(progress < MAX_PROGRESS) + to_chat(user, "\The [src] has not yet matured.") + return + + if(!user.MayRespawn(1)) + return + + // Check for bans properly. + if(jobban_isbanned(user, MODE_XENOMORPH)) + to_chat(user, "You are banned from playing a Xenophage.") + return + + var/confirm = alert(user, "Are you sure you want to join as a Xenophage larva?", "Become Larva", "No", "Yes") + + if(!src || confirm != "Yes") + return + + if(!user || !user.ckey) + return + + if(progress == -1) //Egg has been hatched. + to_chat(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 + xenomorphs.add_antagonist(larva.mind, 1) + 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 new file mode 100644 index 00000000..493d9db9 --- /dev/null +++ b/code/game/objects/structures/alien/node.dm @@ -0,0 +1,19 @@ +/obj/structure/alien/node + name = "alien weed node" + desc = "Some kind of strange, pulsating structure." + icon_state = "weednode" + health = 100 + layer = ABOVE_OBJ_LAYER + +/obj/structure/alien/node/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/structure/alien/node/Destroy() + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/structure/alien/node/Process() + if(locate(/obj/effect/vine) in loc) + return + new/obj/effect/vine(get_turf(src), plant_controller.seeds["xenomorph"], start_matured = 1) \ No newline at end of file diff --git a/code/game/objects/structures/alien/resin.dm b/code/game/objects/structures/alien/resin.dm new file mode 100644 index 00000000..7cebbfe6 --- /dev/null +++ b/code/game/objects/structures/alien/resin.dm @@ -0,0 +1,50 @@ +/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/internal/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/barsign.dm b/code/game/objects/structures/barsign.dm new file mode 100644 index 00000000..2a0d9f7f --- /dev/null +++ b/code/game/objects/structures/barsign.dm @@ -0,0 +1,50 @@ +/obj/structure/sign/double/barsign + desc = "A jumbo-sized LED sign. This one seems to be showing its age." + description_info = "If your ID has bar access, you may swipe it on this sign to alter its display." + icon = 'icons/obj/barsigns.dmi' + icon_state = "empty" + appearance_flags = 0 + anchored = 1 + var/cult = 0 + +/obj/structure/sign/double/barsign/proc/get_valid_states(initial=1) + . = icon_states(icon) + . -= "on" + . -= "narsiebistro" + . -= "empty" + if(initial) + . -= "Off" + +/obj/structure/sign/double/barsign/examine(mob/user) + . = ..() + switch(icon_state) + if("Off") + to_chat(user, "It appears to be switched off.") + if("narsiebistro") + to_chat(user, "It shows a picture of a large black and red being. Spooky!") + if("on", "empty") + to_chat(user, "The lights are on, but there's no picture.") + else + to_chat(user, "It says '[icon_state]'") + +/obj/structure/sign/double/barsign/New() + ..() + icon_state = pick(get_valid_states()) + +/obj/structure/sign/double/barsign/attackby(obj/item/I, mob/user) + if(cult) + return ..() + + var/obj/item/weapon/card/id/card = I.GetIdCard() + if(istype(card)) + if(access_bar in card.GetAccess()) + var/sign_type = input(user, "What would you like to change the barsign to?") as null|anything in get_valid_states(0) + if(!sign_type) + return + icon_state = sign_type + to_chat(user, "You change the barsign.") + else + to_chat(user, "Access denied.") + return + + return ..() diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm new file mode 100644 index 00000000..bd86df36 --- /dev/null +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -0,0 +1,186 @@ +/* +CONTAINS: +BEDSHEETS +LINEN BINS +*/ + +/obj/item/weapon/bedsheet + name = "bedsheet" + desc = "A surprisingly soft linen bedsheet." + icon = 'icons/obj/items.dmi' + icon_state = "sheet" + item_state = "bedsheet" + randpixel = 0 + slot_flags = SLOT_BACK + plane = ABOVE_OBJ_PLANE + layer = BASE_ABOVE_OBJ_LAYER + throwforce = 1 + throw_speed = 1 + throw_range = 2 + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/bedsheet/attackby(obj/item/I, mob/user) + if(is_sharp(I)) + user.visible_message("\The [user] begins cutting up \the [src] with \a [I].", "You begin cutting up \the [src] with \the [I].") + if(do_after(user, 50, src)) + to_chat(user, "You cut \the [src] into pieces!") + for(var/i in 1 to rand(2,5)) + new /obj/item/weapon/reagent_containers/glass/rag(get_turf(src)) + qdel(src) + return + ..() + +/obj/item/weapon/bedsheet/blue + icon_state = "sheetblue" + item_state = "sheetblue" + +/obj/item/weapon/bedsheet/green + icon_state = "sheetgreen" + item_state = "sheetgreen" + +/obj/item/weapon/bedsheet/orange + icon_state = "sheetorange" + item_state = "sheetorange" + +/obj/item/weapon/bedsheet/purple + icon_state = "sheetpurple" + item_state = "sheetpurple" + +/obj/item/weapon/bedsheet/rainbow + icon_state = "sheetrainbow" + item_state = "sheetrainbow" + +/obj/item/weapon/bedsheet/red + icon_state = "sheetred" + item_state = "sheetred" + +/obj/item/weapon/bedsheet/yellow + icon_state = "sheetyellow" + item_state = "sheetyellow" + +/obj/item/weapon/bedsheet/mime + icon_state = "sheetmime" + item_state = "sheetmime" + +/obj/item/weapon/bedsheet/clown + icon_state = "sheetclown" + item_state = "sheetclown" + +/obj/item/weapon/bedsheet/captain + icon_state = "sheetcaptain" + item_state = "sheetcaptain" + +/obj/item/weapon/bedsheet/rd + icon_state = "sheetrd" + item_state = "sheetrd" + +/obj/item/weapon/bedsheet/medical + icon_state = "sheetmedical" + item_state = "sheetmedical" + +/obj/item/weapon/bedsheet/hos + icon_state = "sheethos" + item_state = "sheethos" + +/obj/item/weapon/bedsheet/hop + icon_state = "sheethop" + item_state = "sheethop" + +/obj/item/weapon/bedsheet/ce + icon_state = "sheetce" + item_state = "sheetce" + +/obj/item/weapon/bedsheet/brown + icon_state = "sheetbrown" + item_state = "sheetbrown" + + +/obj/structure/bedsheetbin + name = "linen bin" + desc = "A linen bin. It looks rather cosy." + icon = 'icons/obj/structures.dmi' + icon_state = "linenbin-full" + anchored = 1 + var/amount = 20 + var/list/sheets = list() + var/obj/item/hidden = null + + +/obj/structure/bedsheetbin/examine(mob/user) + . = ..(user) + + if(amount < 1) + to_chat(user, "There are no bed sheets in the bin.") + return + if(amount == 1) + to_chat(user, "There is one bed sheet in the bin.") + return + to_chat(user, "There are [amount] bed sheets in the bin.") + + +/obj/structure/bedsheetbin/update_icon() + switch(amount) + if(0) icon_state = "linenbin-empty" + if(1 to amount / 2) icon_state = "linenbin-half" + else icon_state = "linenbin-full" + + +/obj/structure/bedsheetbin/attackby(obj/item/I as obj, mob/user as mob) + if(istype(I, /obj/item/weapon/bedsheet)) + user.drop_item() + I.loc = src + sheets.Add(I) + amount++ + to_chat(user, "You put [I] in [src].") + else if(amount && !hidden && I.w_class < ITEM_SIZE_HUGE) //make sure there's sheets to hide it among, make sure nothing else is hidden in there. + user.drop_item() + I.loc = src + hidden = I + to_chat(user, "You hide [I] among the sheets.") + +/obj/structure/bedsheetbin/attack_hand(mob/user as mob) + if(amount >= 1) + amount-- + + var/obj/item/weapon/bedsheet/B + if(sheets.len > 0) + B = sheets[sheets.len] + sheets.Remove(B) + + else + B = new /obj/item/weapon/bedsheet(loc) + + B.loc = user.loc + user.put_in_hands(B) + to_chat(user, "You take [B] out of [src].") + + if(hidden) + hidden.loc = user.loc + to_chat(user, "[hidden] falls out of [B]!") + hidden = null + + + add_fingerprint(user) + +/obj/structure/bedsheetbin/attack_tk(mob/user as mob) + if(amount >= 1) + amount-- + + var/obj/item/weapon/bedsheet/B + if(sheets.len > 0) + B = sheets[sheets.len] + sheets.Remove(B) + + else + B = new /obj/item/weapon/bedsheet(loc) + + B.loc = loc + to_chat(user, "You telekinetically remove [B] from [src].") + update_icon() + + if(hidden) + hidden.loc = loc + hidden = null + + + add_fingerprint(user) diff --git a/code/game/objects/structures/catwalk.dm b/code/game/objects/structures/catwalk.dm new file mode 100644 index 00000000..13195035 --- /dev/null +++ b/code/game/objects/structures/catwalk.dm @@ -0,0 +1,70 @@ +/obj/structure/catwalk + name = "catwalk" + desc = "Cats really don't like these things." + icon = 'icons/obj/catwalks.dmi' + icon_state = "catwalk" + density = 0 + anchored = 1.0 + plane = HIDING_MOB_PLANE + layer = CATWALK_LAYER + +/obj/structure/catwalk/Initialize() + . = ..() + for(var/obj/structure/catwalk/C in get_turf(src)) + if(C != src) + qdel(C) + update_icon() + redraw_nearby_catwalks() + + +/obj/structure/catwalk/Destroy() + redraw_nearby_catwalks() + return ..() + +/obj/structure/catwalk/proc/redraw_nearby_catwalks() + for(var/direction in GLOB.alldirs) + var/obj/structure/catwalk/L = locate() in get_step(src, direction) + if(L) + L.update_icon() //so siding get updated properly + + +/obj/structure/catwalk/update_icon() + var/connectdir = 0 + for(var/direction in GLOB.cardinal) + if(locate(/obj/structure/catwalk, get_step(src, direction))) + connectdir |= direction + + //Check the diagonal connections for corners, where you have, for example, connections both north and east. In this case it checks for a north-east connection to determine whether to add a corner marker or not. + var/diagonalconnect = 0 //1 = NE; 2 = SE; 4 = NW; 8 = SW + var/dirs = list(1,2,4,8) + var/i = 1 + for(var/diag in list(NORTHEAST, SOUTHEAST,NORTHWEST,SOUTHWEST)) + if((connectdir & diag) == diag) + if(locate(/obj/structure/catwalk, get_step(src, diag))) + diagonalconnect |= dirs[i] + i += 1 + + icon_state = "catwalk[connectdir]-[diagonalconnect]" + + +/obj/structure/catwalk/ex_act(severity) + switch(severity) + if(1) + new /obj/item/stack/rods(src.loc) + qdel(src) + if(2) + new /obj/item/stack/rods(src.loc) + qdel(src) + +/obj/structure/catwalk/attackby(obj/item/C as obj, mob/user as mob) + if(isWelder(C)) + var/obj/item/weapon/weldingtool/WT = C + if(WT.remove_fuel(0, user)) + playsound(src, 'sound/items/Welder.ogg', 100, 1) + to_chat(user, "Slicing catwalk joints ...") + new /obj/item/stack/rods(src.loc) + new /obj/item/stack/rods(src.loc) + //Lattice would delete itself, but let's save ourselves a new obj + if(istype(src.loc, /turf/space) || istype(src.loc, /turf/simulated/open)) + new /obj/structure/lattice/(src.loc) + qdel(src) diff --git a/code/game/objects/structures/coathanger.dm b/code/game/objects/structures/coathanger.dm new file mode 100644 index 00000000..f8139bbe --- /dev/null +++ b/code/game/objects/structures/coathanger.dm @@ -0,0 +1,52 @@ +/obj/structure/coatrack + name = "coat rack" + desc = "Rack that holds coats." + icon = 'icons/obj/coatrack.dmi' + icon_state = "coatrack0" + var/obj/item/clothing/suit/coat + var/list/allowed = list(/obj/item/clothing/suit/storage/toggle/labcoat, /obj/item/clothing/suit/storage/det_trench) + +/obj/structure/coatrack/attack_hand(mob/user as mob) + user.visible_message("[user] takes [coat] off \the [src].", "You take [coat] off the \the [src]") + if(!user.put_in_active_hand(coat)) + coat.loc = get_turf(user) + coat = null + update_icon() + +/obj/structure/coatrack/attackby(obj/item/weapon/W as obj, mob/user as mob) + var/can_hang = 0 + for (var/T in allowed) + if(istype(W,T)) + can_hang = 1 + if (can_hang && !coat) + user.visible_message("[user] hangs [W] on \the [src].", "You hang [W] on the \the [src]") + coat = W + user.drop_from_inventory(coat, src) + update_icon() + else + to_chat(user, "You cannot hang [W] on [src]") + return ..() + +/obj/structure/coatrack/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + var/can_hang = 0 + for (var/T in allowed) + if(istype(mover,T)) + can_hang = 1 + + if (can_hang && !coat) + src.visible_message("[mover] lands on \the [src].") + coat = mover + coat.loc = src + update_icon() + return 0 + else + return 1 + +/obj/structure/coatrack/update_icon() + overlays.Cut() + if (istype(coat, /obj/item/clothing/suit/storage/toggle/labcoat)) + overlays += image(icon, icon_state = "coat_lab") + if (istype(coat, /obj/item/clothing/suit/storage/toggle/labcoat/cmo)) + overlays += image(icon, icon_state = "coat_cmo") + if (istype(coat, /obj/item/clothing/suit/storage/det_trench)) + overlays += image(icon, icon_state = "coat_det") diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm new file mode 100644 index 00000000..4ffa5773 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -0,0 +1,568 @@ +/obj/structure/closet + name = "closet" + desc = "It's a basic storage unit." + icon = 'icons/obj/closet.dmi' + icon_state = "closed" + density = 1 + layer = 27 //A layer below items. + w_class = ITEM_SIZE_NO_CONTAINER + + var/icon_closed = "closed" + var/icon_opened = "open" + + var/icon_locked + var/icon_broken = "sparks" + var/icon_off + + var/welded = 0 + var/large = 1 + var/wall_mounted = 0 //never solid (You can always pass over it) + var/health = 100 + var/breakout = 0 //if someone is currently breaking out. mutex + var/storage_capacity = 2 * MOB_MEDIUM //This is so that someone can't pack hundreds of items in a locker/crate + //then open it in a populated area to crash clients. + var/open_sound = 'sound/effects/closet_open.ogg' + var/close_sound = 'sound/effects/closet_close.ogg' + + var/storage_types = CLOSET_STORAGE_ALL + var/setup = CLOSET_CAN_BE_WELDED + + // TODO: Turn these into flags. Skipped it for now because it requires updating 100+ locations... + var/broken = FALSE + var/opened = FALSE + var/locked = FALSE + +/obj/structure/closet/Initialize() + ..() + + if((setup & CLOSET_HAS_LOCK)) + verbs += /obj/structure/closet/proc/togglelock_verb + + return INITIALIZE_HINT_LATELOAD + +/obj/structure/closet/LateInitialize(mapload, ...) + var/list/will_contain = WillContain() + if(will_contain) + create_objects_in_loc(src, will_contain) + + if(!opened && mapload) // if closed and it's the map loading phase, relevant items at the crate's loc are put in the contents + store_contents() + +/obj/structure/closet/proc/WillContain() + return null + +/obj/structure/closet/examine(mob/user) + if(..(user, 1) && !opened) + var/content_size = 0 + for(var/atom/movable/AM in src.contents) + if(!AM.anchored) + content_size += content_size(AM) + if(!content_size) + to_chat(user, "It is empty.") + else if(storage_capacity > content_size*4) + to_chat(user, "It is barely filled.") + else if(storage_capacity > content_size*2) + to_chat(user, "It is less than half full.") + else if(storage_capacity > content_size) + to_chat(user, "There is still some free space.") + else + to_chat(user, "It is full.") + +/obj/structure/closet/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group || (height==0 || wall_mounted)) return 1 + return (!density) + +/obj/structure/closet/proc/can_open() + if((setup & CLOSET_HAS_LOCK) && locked) + return 0 + if((setup & CLOSET_CAN_BE_WELDED) && welded) + return 0 + return 1 + +/obj/structure/closet/proc/can_close() + for(var/obj/structure/closet/closet in get_turf(src)) + if(closet != src) + return 0 + return 1 + +/obj/structure/closet/proc/dump_contents() + for(var/mob/M in src) + M.dropInto(loc) + if(M.client) + M.client.eye = M.client.mob + M.client.perspective = MOB_PERSPECTIVE + + for(var/atom/movable/AM in src) + AM.dropInto(loc) + +/obj/structure/closet/proc/store_contents() + var/stored_units = 0 + + if(storage_types & CLOSET_STORAGE_ITEMS) + stored_units += store_items(stored_units) + if(storage_types & CLOSET_STORAGE_MOBS) + stored_units += store_mobs(stored_units) + if(storage_types & CLOSET_STORAGE_STRUCTURES) + stored_units += store_structures(stored_units) + +/obj/structure/closet/proc/open() + if(src.opened) + return 0 + + if(!src.can_open()) + return 0 + + src.dump_contents() + + src.opened = 1 + playsound(src.loc, open_sound, 50, 1, -3) + density = 0 + update_icon() + return 1 + +/obj/structure/closet/proc/close() + if(!src.opened) + return 0 + if(!src.can_close()) + return 0 + + store_contents() + src.opened = 0 + + playsound(src.loc, close_sound, 50, 0, -3) + density = 1 + + update_icon() + + return 1 + +#define CLOSET_CHECK_TOO_BIG(x) (stored_units + . + x > storage_capacity) +/obj/structure/closet/proc/store_items(var/stored_units) + . = 0 + + for(var/obj/effect/dummy/chameleon/AD in loc) + if(CLOSET_CHECK_TOO_BIG(1)) + break + .++ + AD.forceMove(src) + + for(var/obj/item/I in loc) + if(I.anchored) + continue + var/item_size = content_size(I) + if(CLOSET_CHECK_TOO_BIG(item_size)) + break + . += item_size + I.forceMove(src) + I.pixel_x = 0 + I.pixel_y = 0 + I.pixel_z = 0 + +/obj/structure/closet/proc/store_mobs(var/stored_units) + . = 0 + for(var/mob/living/M in loc) + if(M.buckled || M.pinned.len || M.anchored) + continue + var/mob_size = content_size(M) + if(CLOSET_CHECK_TOO_BIG(mob_size)) + break + . += mob_size + if(M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.forceMove(src) + +/obj/structure/closet/proc/store_structures(var/stored_units) + . = 0 + + for(var/obj/structure/S in loc) + if(S == src) + continue + if(S.anchored) + continue + var/structure_size = content_size(S) + if(CLOSET_CHECK_TOO_BIG(structure_size)) + break + . += structure_size + S.forceMove(src) + + for(var/obj/machinery/M in loc) + if(M.anchored) + continue + var/structure_size = content_size(M) + if(CLOSET_CHECK_TOO_BIG(structure_size)) + break + . += structure_size + M.forceMove(src) + +#undef CLOSET_CHECK_TOO_BIG + +// If you adjust any of the values below, please also update /proc/unit_test_weight_of_path(var/path) +/obj/structure/closet/proc/content_size(atom/movable/AM) + if(ismob(AM)) + var/mob/M = AM + return M.mob_size + if(istype(AM, /obj/item)) + var/obj/item/I = AM + return (I.w_class / 2) + if(istype(AM, /obj/structure) || istype(AM, /obj/machinery)) + return MOB_LARGE + return 0 + +/obj/structure/closet/proc/toggle(mob/user as mob) + if(locked) + togglelock(user) + else if(!(src.opened ? src.close() : src.open())) + to_chat(user, "It won't budge!") + update_icon() + +// this should probably use dump_contents() +/obj/structure/closet/ex_act(severity) + switch(severity) + if(1) + for(var/atom/movable/A in src)//pulls everything out of the locker and hits it with an explosion + A.forceMove(src.loc) + A.ex_act(severity + 1) + qdel(src) + if(2) + if(prob(50)) + for (var/atom/movable/A in src) + A.forceMove(src.loc) + A.ex_act(severity + 1) + qdel(src) + if(3) + if(prob(5)) + for(var/atom/movable/A in src) + A.forceMove(src.loc) + qdel(src) + +/obj/structure/closet/proc/damage(var/damage) + health -= damage + if(health <= 0) + for(var/atom/movable/A in src) + A.forceMove(src.loc) + qdel(src) + +/obj/structure/closet/bullet_act(var/obj/item/projectile/Proj) + var/proj_damage = Proj.get_structure_damage() + if(proj_damage) + ..() + damage(proj_damage) + + if(Proj.penetrating) + var/distance = get_dist(Proj.starting, get_turf(loc)) + for(var/mob/living/L in contents) + Proj.attack_mob(L, distance) + if(!(--Proj.penetrating)) + break + + return + +/obj/structure/closet/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(src.opened) + if(istype(W, /obj/item/grab)) + var/obj/item/grab/G = W + src.MouseDrop_T(G.affecting, user) //act like they were dragged onto the closet + return 0 + if(istype(W,/obj/item/tk_grab)) + return 0 + if(isWelder(W)) + var/obj/item/weapon/weldingtool/WT = W + if(WT.isOn()) + slice_into_parts(WT, user) + 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(usr.drop_item()) + W.forceMove(loc) + W.pixel_x = 0 + W.pixel_y = 0 + W.pixel_z = 0 + W.pixel_w = 0 + return + else if(istype(W, /obj/item/weapon/melee/energy/blade)) + if(emag_act(INFINITY, user, "The locker has been sliced open by [user] with \an [W]!", "You hear metal being sliced and sparks flying.")) + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, src.loc) + spark_system.start() + playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1) + playsound(src.loc, "sparks", 50, 1) + open() + else if(istype(W, /obj/item/weapon/packageWrap)) + return + else if(isWelder(W) && (setup & CLOSET_CAN_BE_WELDED)) + var/obj/item/weapon/weldingtool/WT = W + if(!WT.remove_fuel(0,user)) + if(!WT.isOn()) + return + else + to_chat(user, "You need more welding fuel to complete this task.") + return + src.welded = !src.welded + src.update_icon() + user.visible_message("\The [src] has been [welded?"welded shut":"unwelded"] by \the [user].", blind_message = "You hear welding.", range = 3) + else if(setup & CLOSET_HAS_LOCK) + src.togglelock(user, W) + else + src.attack_hand(user) + +/obj/structure/closet/proc/slice_into_parts(obj/item/weapon/weldingtool/WT, mob/user) + if(!WT.remove_fuel(0,user)) + to_chat(user, "You need more welding fuel to complete this task.") + return + new /obj/item/stack/material/steel(src.loc) + user.visible_message("\The [src] has been cut apart by [user] with \the [WT].", \ + "You have cut \the [src] apart with \the [WT].", \ + "You hear welding.") + qdel(src) + +/obj/structure/closet/MouseDrop_T(atom/movable/O as mob|obj, mob/user as mob) + if(istype(O, /obj/screen)) //fix for HUD elements making their way into the world -Pete + return + if(O.loc == user) + return + if(ismob(O) && src.large) + return + if(user.restrained() || user.stat || user.weakened || user.stunned || user.paralysis) + return + if((!( istype(O, /atom/movable) ) || O.anchored || !Adjacent(user) || !Adjacent(O) || !user.Adjacent(O) || user.contents.Find(src))) + return + if(!isturf(user.loc)) // are you in a container/closet/pod/etc? + return + if(!src.opened) + return + if(istype(O, /obj/structure/closet)) + return + step_towards(O, src.loc) + if(user != O) + user.show_viewers("[user] stuffs [O] into [src]!") + src.add_fingerprint(user) + return + +/obj/structure/closet/attack_ai(mob/user) + if(istype(user, /mob/living/silicon/robot) && Adjacent(user)) // Robots can open/close it, but not the AI. + attack_hand(user) + +/obj/structure/closet/relaymove(mob/user as mob) + if(user.stat || !isturf(src.loc)) + return + + if(!src.open()) + to_chat(user, "It won't budge!") + +/obj/structure/closet/attack_hand(mob/user as mob) + src.add_fingerprint(user) + src.toggle(user) + +// tk grab then use on self +/obj/structure/closet/attack_self_tk(mob/user as mob) + src.add_fingerprint(user) + if(!src.toggle()) + to_chat(usr, "It won't budge!") + +/obj/structure/closet/attack_ghost(mob/ghost) + if(ghost.client && ghost.client.inquisitive_ghost) + ghost.examinate(src) + if (!src.opened) + to_chat(ghost, "It contains: [english_list(contents)].") + +/obj/structure/closet/proc/verb_toggleopen() + set category = "Object" + set name = "Toggle Open" + + if(!CanPhysicallyInteract(usr)) + return + + if(ishuman(usr)) + src.add_fingerprint(usr) + src.toggle(usr) + else + to_chat(usr, "This mob type can't use this verb.") + +/obj/structure/closet/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + verb_toggleopen() + +/obj/structure/closet/update_icon()//Putting the welded stuff in update_icon() so it's easy to overwrite for special cases (Fridges, cabinets, and whatnot) + overlays.Cut() + + if(!opened) + if(broken && icon_off) + icon_state = icon_off + overlays += icon_broken + else if((setup & CLOSET_HAS_LOCK) && locked && icon_locked) + icon_state = icon_locked + else + icon_state = icon_closed + if(welded) + overlays += "welded" + else + icon_state = icon_opened + +/obj/structure/closet/attack_generic(var/mob/user, var/damage, var/attack_message = "destroys", var/wallbreaker) + if(!damage || !wallbreaker) + return + attack_animation(user) + visible_message("[user] [attack_message] the [src]!") + dump_contents() + spawn(1) qdel(src) + return 1 + +/obj/structure/closet/proc/req_breakout() + if(opened) + return 0 //Door's open... wait, why are you in it's contents then? + if((setup & CLOSET_HAS_LOCK) && locked) + return 1 // Closed and locked + return (!welded) //closed but not welded... + +/obj/structure/closet/proc/mob_breakout(var/mob/living/escapee) + var/breakout_time = 2 //2 minutes by default + + if(breakout || !req_breakout()) + return + + escapee.setClickCooldown(100) + + //okay, so the closet is either welded or locked... resist!!! + to_chat(escapee, "You lean on the back of \the [src] and start pushing the door open. (this will take about [breakout_time] minutes)") + + visible_message("\The [src] begins to shake violently!") + + breakout = 1 //can't think of a better way to do this right now. + for(var/i in 1 to (6*breakout_time * 2)) //minutes * 6 * 5seconds * 2 + if(!do_after(escapee, 50, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) //5 seconds + breakout = 0 + return + //Perform the same set of checks as above for weld and lock status to determine if there is even still a point in 'resisting'... + if(!req_breakout()) + breakout = 0 + return + + playsound(src.loc, 'sound/effects/grillehit.ogg', 100, 1) + animate_shake() + add_fingerprint(escapee) + + //Well then break it! + breakout = 0 + to_chat(escapee, "You successfully break out!") + visible_message("\The [escapee] successfully broke out of \the [src]!") + playsound(src.loc, 'sound/effects/grillehit.ogg', 100, 1) + break_open() + animate_shake() + +/obj/structure/closet/proc/break_open() + welded = 0 + + if((setup & CLOSET_HAS_LOCK) && locked) + make_broken() + + //Do this to prevent contents from being opened into nullspace (read: bluespace) + if(istype(loc, /obj/structure/bigDelivery)) + var/obj/structure/bigDelivery/BD = loc + BD.unwrap() + open() + +/obj/structure/closet/proc/animate_shake() + var/init_px = pixel_x + var/shake_dir = pick(-1, 1) + animate(src, transform=turn(matrix(), 8*shake_dir), pixel_x=init_px + 2*shake_dir, time=1) + animate(transform=null, pixel_x=init_px, time=6, easing=ELASTIC_EASING) + +/obj/structure/closet/onDropInto(var/atom/movable/AM) + return + +// If we use the /obj/structure/closet/proc/togglelock variant BYOND asks the user to select an input for id_card, which is then mostly irrelevant. +/obj/structure/closet/proc/togglelock_verb() + set src in oview(1) // One square distance + set category = "Object" + set name = "Toggle Lock" + + return togglelock(usr) + +/obj/structure/closet/proc/togglelock(var/mob/user, var/obj/item/weapon/card/id/id_card) + if(!(setup & CLOSET_HAS_LOCK)) + return FALSE + if(!CanPhysicallyInteract(user)) + return FALSE + if(src.opened) + to_chat(user, "Close \the [src] first.") + return FALSE + if(src.broken) + to_chat(user, "\The [src] appears to be broken.") + return FALSE + if(user.loc == src) + to_chat(user, "You can't reach the lock from inside.") + return FALSE + + add_fingerprint(user) + + if(!user.IsAdvancedToolUser()) + to_chat(user, FEEDBACK_YOU_LACK_DEXTERITY) + return FALSE + + if(CanToggleLock(user, id_card)) + locked = !locked + visible_message("\The [src] has been [locked ? null : "un"]locked by \the [user].", range = 3) + update_icon() + return TRUE + else + to_chat(user, "Access denied!") + return FALSE + +/obj/structure/closet/proc/CanToggleLock(var/mob/user, var/obj/item/weapon/card/id/id_card) + return allowed(user) || (istype(id_card) && check_access_list(id_card.GetAccess())) + +/obj/structure/closet/AltClick(var/mob/user) + if(!src.opened) + togglelock(user) + else + return ..() + +/obj/structure/closet/CtrlAltClick(var/mob/user) + verb_toggleopen() + +/obj/structure/closet/emp_act(severity) + for(var/obj/O in src) + O.emp_act(severity) + if(!broken && (setup & CLOSET_HAS_LOCK)) + if(prob(50/severity)) + locked = !locked + src.update_icon() + if(prob(20/severity) && !opened) + if(!locked) + open() + else + src.req_access = list() + src.req_access += pick(get_all_station_access()) + ..() + +/obj/structure/closet/emag_act(var/remaining_charges, var/mob/user, var/emag_source, var/visual_feedback = "", var/audible_feedback = "") + if(make_broken()) + update_icon() + if(visual_feedback) + visible_message(visual_feedback, audible_feedback) + else if(user && emag_source) + visible_message("\The [src] has been broken by \the [user] with \an [emag_source]!", "You hear a faint electrical spark.") + else + visible_message("\The [src] sparks and breaks open!", "You hear a faint electrical spark.") + return 1 + else + . = ..() + +/obj/structure/closet/proc/make_broken() + if(broken) + return FALSE + if(!(setup & CLOSET_HAS_LOCK)) + return FALSE + broken = TRUE + locked = FALSE + desc += " It appears to be broken." + return TRUE diff --git a/code/game/objects/structures/crates_lockers/closets/coffin.dm b/code/game/objects/structures/crates_lockers/closets/coffin.dm new file mode 100644 index 00000000..71f1bac6 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/coffin.dm @@ -0,0 +1,13 @@ +/obj/structure/closet/coffin + name = "coffin" + desc = "It's a burial receptacle for the dearly departed." + icon_state = "coffin" + icon_closed = "coffin" + icon_opened = "coffin_open" + setup = 0 + +/obj/structure/closet/coffin/update_icon() + if(!opened) + icon_state = icon_closed + else + icon_state = icon_opened diff --git a/code/game/objects/structures/crates_lockers/closets/crittercrate.dm b/code/game/objects/structures/crates_lockers/closets/crittercrate.dm new file mode 100644 index 00000000..b2baec0f --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/crittercrate.dm @@ -0,0 +1,6 @@ +/obj/structure/closet/crate/critter + name = "critter crate" + desc = "A crate which can sustain life for a while." + icon_state = "critter" + icon_opened = "critteropen" + icon_closed = "critter" diff --git a/code/game/objects/structures/crates_lockers/closets/fitness.dm b/code/game/objects/structures/crates_lockers/closets/fitness.dm new file mode 100644 index 00000000..15df23b0 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/fitness.dm @@ -0,0 +1,64 @@ +/obj/structure/closet/athletic_mixed + name = "athletic wardrobe" + desc = "It's a storage unit for athletic wear." + icon_state = "mixed" + icon_closed = "mixed" + +/obj/structure/closet/athletic_mixed/WillContain() + return list( + /obj/item/clothing/under/shorts/grey, + /obj/item/clothing/under/shorts/black, + /obj/item/clothing/under/shorts/red, + /obj/item/clothing/under/shorts/blue, + /obj/item/clothing/under/shorts/green, + /obj/item/clothing/under/swimsuit/red, + /obj/item/clothing/under/swimsuit/black, + /obj/item/clothing/under/swimsuit/blue, + /obj/item/clothing/under/swimsuit/green, + /obj/item/clothing/under/swimsuit/purple, + /obj/item/clothing/mask/snorkel = 2, + /obj/item/clothing/shoes/swimmingfins = 2, + /obj/item/weapon/towel = 2) + +/obj/structure/closet/boxinggloves + name = "boxing gloves" + desc = "It's a storage unit for gloves for use in the boxing ring." + +/obj/structure/closet/boxinggloves/WillContain() + return list( + /obj/item/clothing/gloves/boxing/blue, + /obj/item/clothing/gloves/boxing/green, + /obj/item/clothing/gloves/boxing/yellow, + /obj/item/clothing/gloves/boxing) + +/obj/structure/closet/masks + name = "mask closet" + desc = "IT'S A STORAGE UNIT FOR FIGHTER MASKS OLE!" + +/obj/structure/closet/masks/WillContain() + return list( + /obj/item/clothing/mask/luchador, + /obj/item/clothing/mask/luchador/rudos, + /obj/item/clothing/mask/luchador/tecnicos) + +/obj/structure/closet/lasertag/red + name = "red laser tag equipment" + desc = "It's a storage unit for laser tag equipment." + icon_state = "red" + icon_closed = "red" + +/obj/structure/closet/lasertag/red/WillContain() + return list( + /obj/item/weapon/gun/energy/lasertag/red = 3, + /obj/item/clothing/suit/redtag = 3) + +/obj/structure/closet/lasertag/blue + name = "blue laser tag equipment" + desc = "It's a storage unit for laser tag equipment." + icon_state = "blue" + icon_closed = "blue" + +/obj/structure/closet/lasertag/blue/WillContain() + return list( + /obj/item/weapon/gun/energy/lasertag/blue = 3, + /obj/item/clothing/suit/bluetag = 3) diff --git a/code/game/objects/structures/crates_lockers/closets/gimmick.dm b/code/game/objects/structures/crates_lockers/closets/gimmick.dm new file mode 100644 index 00000000..a6f877f4 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/gimmick.dm @@ -0,0 +1,94 @@ +/obj/structure/closet/cabinet + name = "cabinet" + desc = "Old will forever be in fashion." + icon_state = "guncloset" + icon_closed = "guncloset" + icon_opened = "gunclosetopen" + +/obj/structure/closet/cabinet/update_icon() + if(!opened) + icon_state = icon_closed + else + icon_state = icon_opened + +/obj/structure/closet/acloset + name = "strange closet" + desc = "It looks alien!" + icon_state = "acloset" + icon_closed = "acloset" + icon_opened = "aclosetopen" + +/obj/structure/closet/gimmick + name = "administrative supply closet" + desc = "It's a storage unit for things that have no right being here." + icon_state = "syndicate1" + icon_closed = "syndicate1" + icon_opened = "syndicate1open" + anchored = 0 + +/obj/structure/closet/gimmick/russian + name = "russian surplus closet" + desc = "It's a storage unit for Russian standard-issue surplus." + icon_state = "syndicate1" + icon_closed = "syndicate1" + icon_opened = "syndicate1open" + +/obj/structure/closet/gimmick/russian/WillContain() + return list( + /obj/item/clothing/head/ushanka = 5, + /obj/item/clothing/under/soviet = 5) + +/obj/structure/closet/gimmick/tacticool + name = "tacticool gear closet" + desc = "It's a storage unit for Tacticool gear." + icon_state = "syndicate1" + icon_closed = "syndicate1" + icon_opened = "syndicate1open" + +/obj/structure/closet/gimmick/tacticool/WillContain() + return list( + /obj/item/clothing/glasses/eyepatch, + /obj/item/clothing/glasses/sunglasses, + /obj/item/clothing/gloves/thick/swat = 2, + /obj/item/clothing/head/helmet/swat = 2, + /obj/item/clothing/mask/gas = 2, + /obj/item/clothing/shoes/swat = 2, + /obj/item/clothing/suit/space/void/swat = 2, + /obj/item/clothing/under/syndicate/tacticool = 2) + +/obj/structure/closet/thunderdome + name = "\improper Thunderdome closet" + desc = "Everything you need!" + icon_state = "syndicate" + icon_closed = "syndicate" + icon_opened = "syndicateopen" + anchored = 1 + +/obj/structure/closet/thunderdome/tdred + name = "red-team Thunderdome closet" + +/obj/structure/closet/thunderdome/tdred/WillContain() + return list( + /obj/item/clothing/suit/armor/tdome/red = 3, + /obj/item/weapon/melee/energy/sword = 3, + /obj/item/weapon/gun/energy/laser = 3, + /obj/item/weapon/melee/baton = 3, + /obj/item/weapon/storage/box/flashbangs = 3, + /obj/item/clothing/head/helmet/thunderdome = 3 + ) + +/obj/structure/closet/thunderdome/tdgreen + name = "green-team Thunderdome closet" + icon_state = "syndicate1" + icon_closed = "syndicate1" + icon_opened = "syndicate1open" + +/obj/structure/closet/thunderdome/tdgreen/WillContain() + return list( + /obj/item/clothing/suit/armor/tdome/green = 3, + /obj/item/weapon/melee/energy/sword = 3, + /obj/item/weapon/gun/energy/laser = 3, + /obj/item/weapon/melee/baton = 3, + /obj/item/weapon/storage/box/flashbangs = 3, + /obj/item/clothing/head/helmet/thunderdome = 3 + ) diff --git a/code/game/objects/structures/crates_lockers/closets/job_closets.dm b/code/game/objects/structures/crates_lockers/closets/job_closets.dm new file mode 100644 index 00000000..3c4ee961 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/job_closets.dm @@ -0,0 +1,95 @@ +/* Closets for specific jobs + * Contains: + * Bartender + * Janitor + * Lawyer + */ + +/* + * Bartender + */ +/obj/structure/closet/gmcloset + name = "formal closet" + desc = "It's a storage unit for formal clothing." + icon_state = "black" + icon_closed = "black" + +/obj/structure/closet/gmcloset/WillContain() + return list( + /obj/item/clothing/head/that = 2, + /obj/item/device/radio/headset/headset_service = 2, + /obj/item/clothing/head/hairflower, + /obj/item/clothing/head/hairflower/pink, + /obj/item/clothing/head/hairflower/yellow, + /obj/item/clothing/head/hairflower/blue, + /obj/item/clothing/under/sl_suit = 2, + /obj/item/clothing/under/rank/bartender = 2, + /obj/item/clothing/under/dress/dress_saloon, + /obj/item/clothing/accessory/wcoat = 2, + /obj/item/clothing/shoes/black = 2 + ) + +/* + * Chef + */ +/obj/structure/closet/chefcloset + name = "chef's closet" + desc = "It's a storage unit for foodservice garments." + icon_state = "black" + icon_closed = "black" + +/obj/structure/closet/chefcloset/WillContain() + return list( + /obj/item/clothing/under/sundress, + /obj/item/clothing/under/waiter = 2, + /obj/item/device/radio/headset/headset_service = 2, + /obj/item/weapon/storage/box/mousetraps = 2, + /obj/item/clothing/under/rank/chef, + /obj/item/clothing/head/chefhat + ) + +/* + * Janitor + */ +/obj/structure/closet/jcloset + name = "custodial closet" + desc = "It's a storage unit for janitorial clothes and gear." + icon_state = "mixed" + icon_closed = "mixed" + +/obj/structure/closet/jcloset/WillContain() + return list( + /obj/item/clothing/under/rank/janitor, + /obj/item/device/radio/headset/headset_service, + /obj/item/weapon/cartridge/janitor, + /obj/item/clothing/gloves/thick, + /obj/item/clothing/head/soft/purple, + /obj/item/clothing/head/beret/purple, + /obj/item/device/flashlight, + /obj/item/weapon/caution = 4, + /obj/item/device/lightreplacer, + /obj/item/weapon/storage/bag/trash, + /obj/item/clothing/shoes/galoshes, + /obj/item/weapon/soap/nanotrasen) + +/* + * Lawyer + */ +/obj/structure/closet/lawcloset + name = "legal closet" + desc = "It's a storage unit for courtroom apparel and items." + icon_state = "blue" + icon_closed = "blue" + +/obj/structure/closet/lawcloset/WillContain() + return list( + /obj/item/clothing/under/lawyer/female, + /obj/item/clothing/under/lawyer/black, + /obj/item/clothing/under/lawyer/red, + /obj/item/clothing/under/lawyer/bluesuit, + /obj/item/clothing/suit/storage/toggle/suit/blue, + /obj/item/clothing/under/lawyer/purpsuit, + /obj/item/clothing/suit/storage/toggle/suit/purple, + /obj/item/clothing/shoes/brown, + /obj/item/clothing/shoes/black + ) diff --git a/code/game/objects/structures/crates_lockers/closets/l3closet.dm b/code/game/objects/structures/crates_lockers/closets/l3closet.dm new file mode 100644 index 00000000..59524f82 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/l3closet.dm @@ -0,0 +1,102 @@ +/obj/structure/closet/l3closet + name = "level-3 biohazard suit closet" + desc = "It's a storage unit for level-3 biohazard gear." + icon_state = "bio" + icon_closed = "bio" + icon_opened = "bioopen" + +/obj/structure/closet/l3closet/general + icon_state = "bio_general" + icon_closed = "bio_general" + icon_opened = "bio_generalopen" + +/obj/structure/closet/l3closet/general/WillContain() + return list( + /obj/item/clothing/suit/bio_suit/general, + /obj/item/clothing/head/bio_hood/general, + /obj/item/clothing/mask/gas/half, + /obj/item/weapon/tank/emergency/oxygen/engi, + ) + +/obj/structure/closet/l3closet/general/multi/WillContain() + return MERGE_ASSOCS_WITH_NUM_VALUES(..(), list( + /obj/item/clothing/head/bio_hood/general = 5, + /obj/item/clothing/mask/gas/half = 5, + /obj/item/clothing/suit/bio_suit/general = 5, + /obj/item/weapon/tank/emergency/oxygen/engi = 5 + )) + + +/obj/structure/closet/l3closet/virology + icon_state = "bio_virology" + icon_closed = "bio_virology" + icon_opened = "bio_virologyopen" + +/obj/structure/closet/l3closet/virology/WillContain() + return list( + /obj/item/clothing/suit/bio_suit/virology, + /obj/item/clothing/head/bio_hood/virology, + /obj/item/clothing/mask/gas, + /obj/item/weapon/tank/oxygen + ) + + +/obj/structure/closet/l3closet/security + icon_state = "bio_security" + icon_closed = "bio_security" + icon_opened = "bio_securityopen" + +/obj/structure/closet/l3closet/security/WillContain() + return list( + /obj/item/clothing/suit/bio_suit/security, + /obj/item/clothing/head/bio_hood/security, + /obj/item/clothing/mask/gas/half, + /obj/item/weapon/tank/emergency/oxygen/engi + ) + +/obj/structure/closet/l3closet/janitor + icon_state = "bio_janitor" + icon_closed = "bio_janitor" + icon_opened = "bio_janitoropen" + +/obj/structure/closet/l3closet/janitor/WillContain() + return list( + /obj/item/clothing/suit/bio_suit/janitor, + /obj/item/clothing/head/bio_hood/janitor, + /obj/item/clothing/mask/gas/half, + /obj/item/weapon/tank/emergency/oxygen/engi + ) + +/obj/structure/closet/l3closet/scientist + icon_state = "bio_scientist" + icon_closed = "bio_scientist" + icon_opened = "bio_scientistopen" + +/obj/structure/closet/l3closet/scientist/WillContain() + return list( + /obj/item/clothing/suit/bio_suit/scientist, + /obj/item/clothing/head/bio_hood/scientist, + /obj/item/clothing/mask/gas, + /obj/item/weapon/tank/emergency/oxygen/double, + ) + +/obj/structure/closet/l3closet/scientist/multi/WillContain() + return MERGE_ASSOCS_WITH_NUM_VALUES(..(), list( + /obj/item/clothing/head/bio_hood/scientist = 5, + /obj/item/clothing/suit/bio_suit/scientist = 5, + /obj/item/clothing/mask/gas = 5, + /obj/item/weapon/tank/emergency/oxygen/double = 5, + )) + +/obj/structure/closet/l3closet/command + icon_state = "bio_command" + icon_closed = "bio_command" + icon_opened = "bio_commandopen" + +/obj/structure/closet/l3closet/command/WillContain() + return list( + /obj/item/clothing/suit/bio_suit/cmo, + /obj/item/clothing/head/bio_hood/cmo, + /obj/item/clothing/mask/gas/half, + /obj/item/weapon/tank/emergency/oxygen/engi + ) diff --git a/code/game/objects/structures/crates_lockers/closets/malfunction.dm b/code/game/objects/structures/crates_lockers/closets/malfunction.dm new file mode 100644 index 00000000..8fbf816a --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/malfunction.dm @@ -0,0 +1,15 @@ +/obj/structure/closet/malf/suits + desc = "It's a storage unit for operational gear." + icon_state = "syndicate" + icon_closed = "syndicate" + icon_opened = "syndicateopen" + +/obj/structure/closet/malf/suits/WillContain() + return list( + /obj/item/weapon/tank/jetpack/void, + /obj/item/clothing/mask/breath, + /obj/item/clothing/head/helmet/space/void, + /obj/item/clothing/suit/space/void, + /obj/item/weapon/crowbar, + /obj/item/weapon/cell, + /obj/item/device/multitool) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm new file mode 100644 index 00000000..4ff8a3fb --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm @@ -0,0 +1,12 @@ +/obj/structure/closet/secure_closet/bar + name = "booze closet" + req_access = list(access_bar) + icon_state = "cabinetdetective_locked" + icon_closed = "cabinetdetective" + icon_locked = "cabinetdetective_locked" + icon_opened = "cabinetdetective_open" + icon_broken = "cabinetdetective_sparks" + icon_off = "cabinetdetective_broken" + +/obj/structure/closet/secure_closet/bar/WillContain() + return list(/obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer = 10) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm b/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm new file mode 100644 index 00000000..cc80a839 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm @@ -0,0 +1,43 @@ +/obj/structure/closet/secure_closet/cargotech + name = "cargo technician's locker" + req_access = list(access_cargo) + icon_state = "securecargo1" + icon_closed = "securecargo" + icon_locked = "securecargo1" + icon_opened = "securecargoopen" + icon_off = "securecargooff" + +/obj/structure/closet/secure_closet/cargotech/WillContain() + return list( + new/datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack = 75, /obj/item/weapon/storage/backpack/satchel/grey = 25)), + new/datum/atom_creator/simple(/obj/item/weapon/storage/backpack/dufflebag, 25), + /obj/item/clothing/under/rank/cargotech, + /obj/item/clothing/shoes/black, + /obj/item/device/radio/headset/headset_cargo, + /obj/item/clothing/gloves/thick, + /obj/item/clothing/head/soft + ) + +/obj/structure/closet/secure_closet/quartermaster + name = "quartermaster's locker" + req_access = list(access_qm) + icon_state = "secureqm1" + icon_closed = "secureqm" + icon_locked = "secureqm1" + icon_opened = "secureqmopen" + icon_off = "secureqmoff" + +/obj/structure/closet/secure_closet/quartermaster/WillContain() + return list( + new/datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack = 75, /obj/item/weapon/storage/backpack/satchel/grey = 25)), + new/datum/atom_creator/simple(/obj/item/weapon/storage/backpack/dufflebag, 25), + /obj/item/clothing/under/rank/cargotech, + /obj/item/clothing/shoes/brown, + /obj/item/device/radio/headset/headset_cargo, + /obj/item/clothing/gloves/thick, + /obj/item/clothing/suit/fire/firefighter, + /obj/item/weapon/tank/emergency/oxygen, + /obj/item/clothing/mask/gas, + /obj/item/clothing/glasses/meson, + /obj/item/clothing/head/soft + ) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm new file mode 100644 index 00000000..ac68565d --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm @@ -0,0 +1,112 @@ +/obj/structure/closet/secure_closet/engineering_chief + name = "chief engineer's locker" + req_access = list(access_ce) + icon_state = "securece1" + icon_closed = "securece" + icon_locked = "securece1" + icon_opened = "secureceopen" + icon_off = "secureceoff" + +/obj/structure/closet/secure_closet/engineering_chief/WillContain() + return list( + new/datum/atom_creator/weighted(list(/obj/item/clothing/accessory/storage/brown_vest = 70, /obj/item/clothing/accessory/storage/webbing = 30)), + new/datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack/industrial, /obj/item/weapon/storage/backpack/satchel/satchel_eng)), + new/datum/atom_creator/simple(/obj/item/weapon/storage/backpack/dufflebag/eng, 50), + /obj/item/blueprints, + /obj/item/clothing/under/rank/chief_engineer, + /obj/item/clothing/head/hardhat/white, + /obj/item/clothing/head/welding, + /obj/item/clothing/gloves/insulated, + /obj/item/clothing/shoes/brown, + /obj/item/weapon/cartridge/ce, + /obj/item/device/radio/headset/heads/ce, + /obj/item/weapon/storage/toolbox/mechanical, + /obj/item/clothing/suit/storage/hazardvest, + /obj/item/clothing/mask/gas, + /obj/item/device/multitool, + /obj/item/device/flash, + /obj/item/taperoll/engineering, + /obj/item/weapon/crowbar/brace_jack + ) + +/obj/structure/closet/secure_closet/engineering_electrical + name = "electrical supplies" + req_access = list(access_engine_equip) + icon_state = "secureengelec1" + icon_closed = "secureengelec" + icon_locked = "secureengelec1" + icon_opened = "toolclosetopen" + icon_off = "secureengelecoff" + +/obj/structure/closet/secure_closet/engineering_electrical/WillContain() + return list( + /obj/item/clothing/gloves/insulated = 3, + /obj/item/weapon/storage/toolbox/electrical = 3, + /obj/item/weapon/module/power_control = 3, + /obj/item/device/multitool = 3 + ) + +/obj/structure/closet/secure_closet/engineering_welding + name = "welding supplies" + req_access = list(access_construction) + icon_state = "secureengweld1" + icon_closed = "secureengweld" + icon_locked = "secureengweld1" + icon_opened = "toolclosetopen" + icon_off = "secureengweldoff" + +/obj/structure/closet/secure_closet/engineering_welding/WillContain() + return list( + /obj/item/clothing/head/welding = 3, + /obj/item/weapon/weldingtool/largetank = 3, + /obj/item/weapon/weldpack = 3, + /obj/item/clothing/glasses/welding = 3, + /obj/item/weapon/welder_tank = 6 + ) + +/obj/structure/closet/secure_closet/engineering_personal + name = "engineer's locker" + req_access = list(access_engine_equip) + icon_state = "secureeng1" + icon_closed = "secureeng" + icon_locked = "secureeng1" + icon_opened = "secureengopen" + icon_off = "secureengoff" + +/obj/structure/closet/secure_closet/engineering_personal/WillContain() + return list( + new/datum/atom_creator/weighted(list(/obj/item/clothing/accessory/storage/brown_vest = 70, /obj/item/clothing/accessory/storage/webbing = 30)), + new/datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack/industrial, /obj/item/weapon/storage/backpack/satchel/satchel_eng)), + new/datum/atom_creator/simple(/obj/item/weapon/storage/backpack/dufflebag/eng, 50), + /obj/item/weapon/storage/toolbox/mechanical, + /obj/item/device/radio/headset/headset_eng, + /obj/item/clothing/suit/storage/hazardvest, + /obj/item/clothing/mask/gas, + /obj/item/clothing/glasses/meson, + /obj/item/weapon/cartridge/engineering, + /obj/item/taperoll/engineering + ) + +/obj/structure/closet/secure_closet/atmos_personal + name = "technician's locker" + req_access = list(access_atmospherics) + icon_state = "secureatm1" + icon_closed = "secureatm" + icon_locked = "secureatm1" + icon_opened = "secureatmopen" + icon_off = "secureatmoff" + +/obj/structure/closet/secure_closet/atmos_personal/WillContain() + return list( + new/datum/atom_creator/weighted(list(/obj/item/clothing/accessory/storage/brown_vest = 70, /obj/item/clothing/accessory/storage/webbing = 30)), + new/datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack/industrial, /obj/item/weapon/storage/backpack/satchel/satchel_eng)), + new/datum/atom_creator/simple(/obj/item/weapon/storage/backpack/dufflebag/eng, 50), + /obj/item/clothing/suit/fire/firefighter, + /obj/item/device/flashlight, + /obj/item/weapon/extinguisher, + /obj/item/device/radio/headset/headset_eng, + /obj/item/clothing/suit/storage/hazardvest, + /obj/item/clothing/mask/gas, + /obj/item/weapon/cartridge/atmos, + /obj/item/taperoll/atmos + ) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm new file mode 100644 index 00000000..4097cb85 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm @@ -0,0 +1,62 @@ +/obj/structure/closet/secure_closet/freezer/kitchen + name = "kitchen cabinet" + req_access = list(access_kitchen) + +/obj/structure/closet/secure_closet/freezer/kitchen/WillContain() + return list( + /obj/item/weapon/reagent_containers/food/condiment/flour = 7, + /obj/item/weapon/reagent_containers/food/condiment/sugar = 2 + ) + +/obj/structure/closet/secure_closet/freezer/kitchen/mining + req_access = list() + +/obj/structure/closet/secure_closet/freezer/meat + name = "meat fridge" + icon_state = "fridge1" + icon_closed = "fridge" + icon_locked = "fridge1" + icon_opened = "fridgeopen" + icon_off = "fridgebroken" + +/obj/structure/closet/secure_closet/freezer/meat/WillContain() + return list( + /obj/item/weapon/reagent_containers/food/snacks/meat/monkey = 10 + ) + +/obj/structure/closet/secure_closet/freezer/fridge + name = "refrigerator" + icon_state = "fridge1" + icon_closed = "fridge" + icon_locked = "fridge1" + icon_opened = "fridgeopen" + icon_off = "fridgebroken" + +/obj/structure/closet/secure_closet/freezer/fridge/WillContain() + return list( + /obj/item/weapon/reagent_containers/food/drinks/milk = 6, + /obj/item/weapon/reagent_containers/food/drinks/soymilk = 4, + /obj/item/weapon/storage/fancy/egg_box = 4 + ) + +/obj/structure/closet/secure_closet/freezer/money + name = "secure locker" + icon_state = "fridge1" + icon_closed = "fridge" + icon_locked = "fridge1" + icon_opened = "fridgeopen" + icon_off = "fridgebroken" + req_access = list(access_heads_vault) + +/obj/structure/closet/secure_closet/freezer/money/Initialize() + . = ..() + //let's make hold a substantial amount. + var/created_size = 0 + for(var/i = 1 to 200) //sanity loop limit + var/obj/item/cash_type = pick(3; /obj/item/weapon/spacecash/bundle/c1000, 4; /obj/item/weapon/spacecash/bundle/c500, 5; /obj/item/weapon/spacecash/bundle/c200) + var/bundle_size = initial(cash_type.w_class) / 2 + if(created_size + bundle_size <= storage_capacity) + created_size += bundle_size + new cash_type(src) + else + break diff --git a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm new file mode 100644 index 00000000..59be95d1 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm @@ -0,0 +1,59 @@ +/obj/structure/closet/secure_closet/guncabinet + name = "gun cabinet" + req_access = list(access_armory) + icon = 'icons/obj/guncabinet.dmi' + icon_state = "base" + icon_off ="base" + icon_broken ="base" + icon_locked ="base" + icon_closed ="base" + icon_opened = "base" + +/obj/structure/closet/secure_closet/guncabinet/Initialize() + . = ..() + update_icon() + +/obj/structure/closet/secure_closet/guncabinet/toggle() + ..() + update_icon() + +/obj/structure/closet/secure_closet/guncabinet/open() //There are plenty of things that can open it that don't use toggle + ..() + update_icon() + +/obj/structure/closet/secure_closet/guncabinet/update_icon() + overlays.Cut() + if(opened) + overlays += icon(icon,"door_open") + else + var/lazors = 0 + var/shottas = 0 + for (var/obj/item/weapon/gun/G in contents) + if (istype(G, /obj/item/weapon/gun/energy)) + lazors++ + if (istype(G, /obj/item/weapon/gun/projectile/)) + shottas++ + for (var/i = 0 to 2) + if(lazors || shottas) // only make icons if we have one of the two types. + var/image/gun = image(icon(src.icon)) + if (lazors > shottas) + lazors-- + gun.icon_state = "laser" + else if (shottas) + shottas-- + gun.icon_state = "projectile" + gun.pixel_x = i*4 + overlays += gun + + overlays += icon(src.icon, "door") + + if(welded) + overlays += icon(src.icon,"welded") + + if(broken) + overlays += icon(src.icon,"broken") + else if (locked) + overlays += icon(src.icon,"locked") + else + overlays += icon(src.icon,"open") + diff --git a/code/game/objects/structures/crates_lockers/closets/secure/hydroponics.dm b/code/game/objects/structures/crates_lockers/closets/secure/hydroponics.dm new file mode 100644 index 00000000..f1f61bf0 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/secure/hydroponics.dm @@ -0,0 +1,23 @@ +/obj/structure/closet/secure_closet/hydroponics + name = "botanist's locker" + req_access = list(access_hydroponics) + icon_state = "hydrosecure1" + icon_closed = "hydrosecure" + icon_locked = "hydrosecure1" + icon_opened = "hydrosecureopen" + icon_off = "hydrosecureoff" + +/obj/structure/closet/secure_closet/hydroponics/WillContain() + return list( + new /datum/atom_creator/weighted(list(/obj/item/clothing/suit/apron, /obj/item/clothing/suit/apron/overalls)), + /obj/item/weapon/storage/plants, + /obj/item/clothing/under/rank/hydroponics, + /obj/item/device/analyzer/plant_analyzer, + /obj/item/device/radio/headset/headset_service, + /obj/item/clothing/mask/bandana/botany, + /obj/item/clothing/head/bandana/green, + /obj/item/weapon/material/minihoe, + /obj/item/weapon/material/hatchet, + /obj/item/weapon/wirecutters/clippers, + /obj/item/weapon/reagent_containers/spray/plantbgone, + ) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm new file mode 100644 index 00000000..f1532d2a --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm @@ -0,0 +1,267 @@ +#define RANDOM_SCRUBS new/datum/atom_creator/weighted(list( \ + list(/obj/item/clothing/under/rank/medical/scrubs, /obj/item/clothing/head/surgery), \ + list(/obj/item/clothing/under/rank/medical/scrubs/blue, /obj/item/clothing/head/surgery/blue), \ + list(/obj/item/clothing/under/rank/medical/scrubs/green, /obj/item/clothing/head/surgery/green), \ + list(/obj/item/clothing/under/rank/medical/scrubs/purple, /obj/item/clothing/head/surgery/purple), \ + list(/obj/item/clothing/under/rank/medical/scrubs/black, /obj/item/clothing/head/surgery/black), \ + list(/obj/item/clothing/under/rank/medical/scrubs/lilac, /obj/item/clothing/head/surgery/lilac), \ + list(/obj/item/clothing/under/rank/medical/scrubs/teal, /obj/item/clothing/head/surgery/teal), \ + list(/obj/item/clothing/under/rank/medical/scrubs/heliodor, /obj/item/clothing/head/surgery/heliodor), \ + list(/obj/item/clothing/under/rank/medical/scrubs/navyblue, /obj/item/clothing/head/surgery/navyblue)\ + ) \ + ) + +/obj/structure/closet/secure_closet/medical1 + name = "medical equipment closet" + desc = "Filled with medical junk." + icon_state = "medical1" + icon_closed = "medical" + icon_locked = "medical1" + icon_opened = "medicalopen" + icon_off = "medicaloff" + req_access = list(access_medical_equip) + +/obj/structure/closet/secure_closet/medical1/WillContain() + return list( + /obj/item/weapon/storage/box/autoinjectors, + /obj/item/weapon/storage/box/syringes, + /obj/item/weapon/reagent_containers/dropper = 2, + /obj/item/weapon/reagent_containers/glass/beaker = 2, + /obj/item/weapon/reagent_containers/glass/bottle/inaprovaline = 2, + /obj/item/weapon/reagent_containers/glass/bottle/antitoxin = 2, + /obj/random/firstaid, + /obj/item/weapon/storage/box/masks, + /obj/item/weapon/storage/box/gloves + ) + +/obj/structure/closet/secure_closet/medical1/warfare + icon_state = "warfarecloset" + icon_closed = "warfarecloset" + icon_opened = "warfareclosetopen" + icon_off = "" + icon_locked = "" + setup = 0 + locked = FALSE + req_access = list() + +/obj/structure/closet/secure_closet/medical2 + name = "anesthetics closet" + desc = "Used to knock people out." + icon_state = "medical1" + icon_closed = "medical" + icon_locked = "medical1" + icon_opened = "medicalopen" + icon_off = "medicaloff" + req_access = list(access_surgery) + +/obj/structure/closet/secure_closet/medical2/WillContain() + return list( + /obj/item/weapon/tank/anesthetic = 3, + /obj/item/clothing/mask/breath/medical = 3 + ) + +/obj/structure/closet/secure_closet/medical3 + name = "medical doctor's locker" + req_access = list(access_medical_equip) + icon_state = "securemed1" + icon_closed = "securemed" + icon_locked = "securemed1" + icon_opened = "securemedopen" + icon_off = "securemedoff" + +/obj/structure/closet/secure_closet/medical3/WillContain() + return list( + new/datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack/medic, /obj/item/weapon/storage/backpack/satchel/satchel_med)), + new/datum/atom_creator/simple(/obj/item/weapon/storage/backpack/dufflebag/med, 50), + /obj/item/clothing/under/rank/nursesuit, + /obj/item/clothing/head/nursehat, + /obj/item/clothing/under/rank/medical, + /obj/item/clothing/under/rank/nurse, + /obj/item/clothing/under/rank/orderly, + /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/clothing/suit/storage/toggle/fr_jacket, + /obj/item/clothing/shoes/white, + /obj/item/device/radio/headset/headset_med, + /obj/item/taperoll/medical, + /obj/item/weapon/storage/belt/medical/emt, + RANDOM_SCRUBS, + RANDOM_SCRUBS + ) + +/obj/structure/closet/secure_closet/paramedic + name = "paramedic locker" + desc = "Supplies for a first responder." + icon_state = "medical1" + icon_closed = "medical" + icon_locked = "medical1" + icon_opened = "medicalopen" + icon_off = "medicaloff" + req_access = list(access_medical_equip) + +/obj/structure/closet/secure_closet/paramedic/WillContain() + return list( + /obj/item/weapon/storage/box/autoinjectors, + /obj/item/weapon/storage/box/syringes, + /obj/item/weapon/reagent_containers/glass/bottle/inaprovaline, + /obj/item/weapon/reagent_containers/glass/bottle/antitoxin, + /obj/item/weapon/storage/belt/medical/emt, + /obj/item/clothing/mask/gas, + /obj/item/clothing/suit/storage/toggle/fr_jacket, + /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/device/radio/headset/headset_med, + /obj/item/weapon/cartridge/medical, + /obj/item/device/flashlight, + /obj/item/weapon/tank/emergency/oxygen/engi, + /obj/item/clothing/glasses/hud/health, + /obj/item/device/healthanalyzer, + /obj/item/device/radio/off, + /obj/random/medical, + /obj/item/weapon/crowbar, + /obj/item/weapon/extinguisher/mini, + /obj/item/weapon/storage/box/freezer, + /obj/item/clothing/accessory/storage/white_vest, + ) + +/obj/structure/closet/secure_closet/CMO + name = "chief medical officer's locker" + req_access = list(access_cmo) + icon_state = "cmosecure1" + icon_closed = "cmosecure" + icon_locked = "cmosecure1" + icon_opened = "cmosecureopen" + icon_off = "cmosecureoff" + +/obj/structure/closet/secure_closet/CMO/WillContain() + return list( + new/datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack/medic, /obj/item/weapon/storage/backpack/satchel/satchel_med)), + new/datum/atom_creator/simple(/obj/item/weapon/storage/backpack/dufflebag/med, 50), + /obj/item/clothing/suit/bio_suit/cmo, + /obj/item/clothing/head/bio_hood/cmo, + /obj/item/clothing/shoes/white, + /obj/item/clothing/under/rank/chief_medical_officer, + /obj/item/clothing/suit/storage/toggle/labcoat/cmo, + /obj/item/clothing/suit/storage/toggle/labcoat/cmoalt, + /obj/item/weapon/cartridge/cmo, + /obj/item/clothing/gloves/latex, + /obj/item/clothing/shoes/brown, + /obj/item/device/radio/headset/heads/cmo, + /obj/item/device/flash, + /obj/item/weapon/reagent_containers/hypospray/vial, + RANDOM_SCRUBS + ) + +/obj/structure/closet/secure_closet/chemical + name = "chemical closet" + desc = "Store dangerous chemicals in here." + icon_state = "medical1" + icon_closed = "medical" + icon_locked = "medical1" + icon_opened = "medicalopen" + icon_off = "medicaloff" + req_access = list(access_chemistry) + +/obj/structure/closet/secure_closet/chemical/WillContain() + return list( + /obj/item/weapon/storage/box/pillbottles = 2, + /obj/item/weapon/reagent_containers/glass/beaker/cryoxadone, + /obj/random/medical = 12 + ) + +/obj/structure/closet/secure_closet/medical_wall + name = "first aid closet" + desc = "It's a secure wall-mounted storage unit for first aid supplies." + icon_state = "medical_wall_locked" + icon_closed = "medical_wall_unlocked" + icon_locked = "medical_wall_locked" + icon_opened = "medical_wall_open" + icon_broken = "medical_wall_sparks" + icon_off = "medical_wall_off" + anchored = 1 + density = 0 + wall_mounted = 1 + storage_types = CLOSET_STORAGE_ITEMS + req_access = list(access_medical_equip) + +/obj/structure/closet/secure_closet/counselor + name = "counselor's locker" + req_access = list(access_psychiatrist,access_chapel_office) + icon_state = "chaplainsecure1" + icon_closed = "chaplainsecure" + icon_locked = "chaplainsecure1" + icon_opened = "chaplainsecureopen" + icon_off = "chaplainsecureoff" + +/obj/structure/closet/secure_closet/counselor/WillContain() + return list( + /obj/item/clothing/under/rank/psych, + /obj/item/clothing/under/rank/psych/turtleneck, + /obj/item/clothing/under/rank/chaplain, + /obj/item/clothing/shoes/black, + /obj/item/clothing/suit/chaplain_hoodie, + /obj/item/weapon/storage/fancy/candle_box = 2, + /obj/item/weapon/deck/tarot, + /obj/item/weapon/reagent_containers/food/drinks/bottle/holywater, + /obj/item/weapon/nullrod, + /obj/item/clothing/suit/straight_jacket, + /obj/item/weapon/reagent_containers/glass/bottle/stoxin, + /obj/item/weapon/reagent_containers/syringe, + /obj/item/weapon/storage/pill_bottle/citalopram, + /obj/item/weapon/reagent_containers/pill/methylphenidate, + /obj/item/weapon/clipboard, + /obj/item/weapon/folder/white, + /obj/item/device/taperecorder, + /obj/item/device/tape/random = 3, + /obj/item/device/camera, + /obj/item/toy/therapy_blue, + ) + +/obj/structure/closet/secure_closet/virology + name = "virologist's locker" + icon_state = "secureviro1" + icon_closed = "secureviro" + icon_locked = "secureviro1" + icon_opened = "secureviroopen" + icon_off = "securevirooff" + req_access = list(access_virology) + +/obj/structure/closet/secure_closet/virology/WillContain() + return list( + /obj/item/weapon/storage/box/autoinjectors, + /obj/item/weapon/storage/box/syringes, + /obj/item/weapon/reagent_containers/dropper = 2, + /obj/item/weapon/reagent_containers/glass/beaker = 2, + /obj/item/weapon/reagent_containers/glass/bottle/inaprovaline, + /obj/item/weapon/storage/pill_bottle/spaceacillin, + /obj/item/weapon/reagent_containers/syringe/antiviral, + /obj/item/weapon/reagent_containers/glass/bottle/antitoxin, + /obj/item/weapon/storage/box/masks, + /obj/item/weapon/storage/box/gloves, + /obj/item/clothing/under/rank/virologist, + /obj/item/clothing/shoes/white, + /obj/item/clothing/suit/storage/toggle/labcoat/virologist, + /obj/item/clothing/mask/surgical, + /obj/item/device/healthanalyzer, + /obj/item/clothing/glasses/hud/health + ) + +/obj/structure/closet/secure_closet/psychiatry + name = "Psychiatrist's locker" + desc = "Everything you need to keep the lunatics at bay." + icon_state = "securemed1" + icon_closed = "securemed" + icon_locked = "securemed1" + icon_opened = "securemedopen" + icon_off = "securemedoff" + req_access = list(access_psychiatrist) + +/obj/structure/closet/secure_closet/psychiatry/WillContain() + return list( + /obj/item/clothing/suit/straight_jacket, + /obj/item/weapon/reagent_containers/glass/bottle/stoxin, + /obj/item/weapon/reagent_containers/syringe, + /obj/item/weapon/storage/pill_bottle/citalopram, + /obj/item/weapon/storage/pill_bottle/methylphenidate, + /obj/item/weapon/storage/pill_bottle/paroxetine, + /obj/item/clothing/under/rank/psych/turtleneck, + /obj/item/clothing/under/rank/psych + ) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/nuke.dm b/code/game/objects/structures/crates_lockers/closets/secure/nuke.dm new file mode 100644 index 00000000..625d97ba --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/secure/nuke.dm @@ -0,0 +1,22 @@ +/obj/structure/closet/secure_closet/nuke_wall + name = "nuclear cylinder closet" + desc = "It's a secure wall-mounted storage unit for storing the nuclear cylinders." + icon = 'icons/obj/machines/self_destruct.dmi' + icon_state = "self_destruct_wall_locked" + icon_closed = "self_destruct_wall_unlocked" + icon_locked = "self_destruct_wall_locked" + icon_opened = "self_destruct_wall_open" + icon_broken = "self_destruct_wall_spark" + icon_off = "self_destruct_wall_off" + anchored = 1 + density = 0 + wall_mounted = 1 + req_access = list(access_heads_vault) + storage_types = CLOSET_STORAGE_ITEMS + +/obj/structure/closet/secure_closet/nuke_wall/WillContain() + return list( + /obj/item/weapon/nuclear_cylinder, + /obj/item/weapon/nuclear_cylinder, + /obj/item/weapon/nuclear_cylinder + ) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm new file mode 100644 index 00000000..75daec4e --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm @@ -0,0 +1,73 @@ +/obj/structure/closet/secure_closet/personal + name = "personal closet" + desc = "It's a secure locker for personnel. The first card swiped gains control." + req_access = list(access_all_personal_lockers) + var/registered_name = null + +/obj/structure/closet/secure_closet/personal/WillContain() + return list( + new /datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack, /obj/item/weapon/storage/backpack/satchel/grey)), + /obj/item/device/radio/headset + ) + +/obj/structure/closet/secure_closet/personal/empty/WillContain() + return + +/obj/structure/closet/secure_closet/personal/patient + name = "patient's closet" +/obj/structure/closet/secure_closet/personal/patient/WillContain() + return + +/obj/structure/closet/secure_closet/personal/cabinet + icon_state = "cabinetdetective" + icon_closed = "cabinetdetective" + icon_locked = "cabinetdetective_locked" + icon_opened = "cabinetdetective_open" + icon_broken = "cabinetdetective_sparks" + icon_off = "cabinetdetective_broken" + +/obj/structure/closet/secure_closet/personal/cabinet/WillContain() + return list(/obj/item/weapon/storage/backpack/satchel/grey/withwallet, /obj/item/device/radio/headset) + +/obj/structure/closet/secure_closet/personal/attackby(var/obj/item/weapon/W, var/mob/user) + if (src.opened) + ..() + else if(W.GetIdCard()) + var/obj/item/weapon/card/id/I = W.GetIdCard() + + if(!I || !I.registered_name) + return + if(togglelock(user, I)) + if(!src.registered_name) + src.registered_name = I.registered_name + src.name += " ([I.registered_name])" + src.desc = "Owned by [I.registered_name]." + else + to_chat(user, "Access Denied") + else + ..() + +/obj/structure/closet/secure_closet/personal/CanToggleLock(var/mob/user, var/obj/item/weapon/card/id/id_card) + return ..() || (istype(id_card) && id_card.registered_name && (!registered_name || (registered_name == id_card.registered_name))) + +/obj/structure/closet/secure_closet/personal/verb/reset() + set src in oview(1) // One square distance + set category = "Object" + set name = "Reset Lock" + if(!CanPhysicallyInteract(usr)) // Don't use it if you're not able to! Checks for stuns, ghost and restrain + return + if(ishuman(usr)) + src.add_fingerprint(usr) + if (src.locked || !src.registered_name) + to_chat(usr, "You need to unlock it first.") + else if (src.broken) + to_chat(usr, "It appears to be broken.") + else + if (src.opened) + if(!src.close()) + return + src.locked = 1 + src.icon_state = src.icon_locked + src.registered_name = null + src.SetName(initial(name)) + src.desc = initial(desc) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm new file mode 100644 index 00000000..32e5479f --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm @@ -0,0 +1,83 @@ +/obj/structure/closet/secure_closet/scientist + name = "scientist's locker" + req_one_access = list(access_tox,access_tox_storage) + icon_state = "secureres1" + icon_closed = "secureres" + icon_locked = "secureres1" + icon_opened = "secureresopen" + icon_off = "secureresoff" + +/obj/structure/closet/secure_closet/scientist/WillContain() + return list( + new /datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack/messenger/tox, /obj/item/weapon/storage/backpack/satchel/satchel_tox)), + /obj/item/clothing/under/rank/scientist, + /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/clothing/shoes/white, + /obj/item/device/radio/headset/headset_sci, + /obj/item/clothing/mask/gas, + /obj/item/weapon/clipboard + ) + +/obj/structure/closet/secure_closet/xenobio + name = "xenobiologist's locker" + req_access = list(access_xenobiology) + icon_state = "secureres1" + icon_closed = "secureres" + icon_locked = "secureres1" + icon_opened = "secureresopen" + icon_off = "secureresoff" + +/obj/structure/closet/secure_closet/xenobio/WillContain() + return list( + new /datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack/messenger/tox, /obj/item/weapon/storage/backpack/satchel/satchel_tox)), + /obj/item/clothing/under/rank/scientist, + /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/clothing/shoes/white, + /obj/item/device/radio/headset/headset_sci, + /obj/item/clothing/mask/gas, + /obj/item/clothing/gloves/latex, + /obj/item/weapon/clipboard + ) + +/obj/structure/closet/secure_closet/RD + name = "research director's locker" + req_access = list(access_rd) + icon_state = "rdsecure1" + icon_closed = "rdsecure" + icon_locked = "rdsecure1" + icon_opened = "rdsecureopen" + icon_off = "rdsecureoff" + +/obj/structure/closet/secure_closet/RD/WillContain() + return list( + /obj/item/clothing/suit/bio_suit/scientist = 2, + /obj/item/clothing/under/rank/research_director, + /obj/item/clothing/under/rank/research_director/rdalt, + /obj/item/clothing/under/rank/research_director/dress_rd, + /obj/item/clothing/under/rank/scientist/executive, + /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/weapon/cartridge/rd, + /obj/item/clothing/shoes/white, + /obj/item/clothing/shoes/leather, + /obj/item/clothing/gloves/latex, + /obj/item/device/radio/headset/heads/rd, + /obj/item/clothing/mask/gas, + /obj/item/device/flash, + /obj/item/weapon/clipboard, + /obj/item/clothing/suit/storage/toggle/labcoat/rd + ) + +/obj/structure/closet/secure_closet/animal + name = "animal control closet" + req_access = list(access_research) + +/obj/structure/closet/secure_closet/animal/WillContain() + return list( + /obj/item/device/assembly/signaler, + /obj/item/device/radio/electropack = 3, + /obj/item/weapon/gun/launcher/syringe/rapid, + /obj/item/weapon/storage/box/syringegun, + /obj/item/weapon/storage/box/syringes, + /obj/item/weapon/reagent_containers/glass/bottle/chloralhydrate, + /obj/item/weapon/reagent_containers/glass/bottle/stoxin + ) 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 new file mode 100644 index 00000000..ef05e387 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm @@ -0,0 +1,19 @@ +/obj/structure/closet/secure_closet + name = "secure locker" + desc = "It's a card-locked storage unit." + + setup = CLOSET_HAS_LOCK | CLOSET_CAN_BE_WELDED + locked = TRUE + + icon_state = "secure1" + icon_closed = "secure" + icon_locked = "secure1" + icon_off = "secureoff" + + icon_opened = "secureopen" + + wall_mounted = 0 //never solid (You can always pass over it) + health = 200 + +/obj/structure/closet/secure_closet/slice_into_parts(obj/item/weapon/weldingtool/WT, mob/user) + to_chat(user, "\The [src] is too strong to be taken apart.") diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm new file mode 100644 index 00000000..35e4c086 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -0,0 +1,298 @@ +/obj/structure/closet/secure_closet/captains + name = "captain's locker" + req_access = list(access_captain) + icon_state = "capsecure1" + icon_closed = "capsecure" + icon_locked = "capsecure1" + icon_opened = "capsecureopen" + icon_off = "capsecureoff" + +/obj/structure/closet/secure_closet/captains/WillContain() + return list( + new/datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack/captain, /obj/item/weapon/storage/backpack/satchel/satchel_cap)), + new/datum/atom_creator/simple(/obj/item/weapon/storage/backpack/dufflebag/captain, 50), + /obj/item/clothing/suit/captunic, + /obj/item/clothing/suit/captunic/capjacket, + /obj/item/clothing/head/caphat/cap, + /obj/item/clothing/under/rank/captain, + /obj/item/clothing/suit/armor/vest/opvest, + /obj/item/weapon/cartridge/captain, + /obj/item/clothing/head/helmet, + /obj/item/clothing/shoes/brown, + /obj/item/device/radio/headset/heads/captain, + /obj/item/clothing/gloves/captain, + /obj/item/weapon/gun/energy/gun, + /obj/item/clothing/suit/armor/captain, + /obj/item/weapon/melee/telebaton, + /obj/item/clothing/under/dress/dress_cap, + /obj/item/clothing/head/caphat/formal, + /obj/item/clothing/under/captainformal, + ) + +/obj/structure/closet/secure_closet/hop + name = "head of personnel's locker" + req_access = list(access_hop) + icon_state = "hopsecure1" + icon_closed = "hopsecure" + icon_locked = "hopsecure1" + icon_opened = "hopsecureopen" + icon_off = "hopsecureoff" + +/obj/structure/closet/secure_closet/hop/WillContain() + return list( + /obj/item/clothing/glasses/sunglasses, + /obj/item/clothing/suit/armor/vest/opvest, + /obj/item/clothing/head/helmet, + /obj/item/weapon/cartridge/hop, + /obj/item/device/radio/headset/heads/hop, + /obj/item/weapon/storage/box/ids = 2, + /obj/item/weapon/gun/projectile/sec/flash, + /obj/item/device/flash + ) + +/obj/structure/closet/secure_closet/hop2 + name = "head of personnel's attire" + req_access = list(access_hop) + icon_state = "hopsecure1" + icon_closed = "hopsecure" + icon_locked = "hopsecure1" + icon_opened = "hopsecureopen" + icon_off = "hopsecureoff" + +/obj/structure/closet/secure_closet/hop2/WillContain() + return list( + /obj/item/clothing/under/rank/head_of_personnel, + /obj/item/clothing/under/dress/dress_hop, + /obj/item/clothing/under/dress/dress_hr, + /obj/item/clothing/under/lawyer/female, + /obj/item/clothing/under/lawyer/black, + /obj/item/clothing/under/lawyer/red, + /obj/item/clothing/under/lawyer/oldman, + /obj/item/clothing/shoes/brown, + /obj/item/clothing/shoes/black, + /obj/item/clothing/shoes/leather, + /obj/item/clothing/shoes/white, + /obj/item/clothing/under/rank/head_of_personnel_whimsy, + /obj/item/clothing/head/caphat/hop + ) + +/obj/structure/closet/secure_closet/hos + name = "head of security's locker" + req_access = list(access_hos) + icon_state = "hossecure1" + icon_closed = "hossecure" + icon_locked = "hossecure1" + icon_opened = "hossecureopen" + icon_off = "hossecureoff" + +/obj/structure/closet/secure_closet/hos/WillContain() + return list( + new/datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack/security, /obj/item/weapon/storage/backpack/satchel/satchel_sec)), + /obj/item/clothing/head/HoS, + ///obj/item/clothing/head/helmet/nt, + ///obj/item/clothing/suit/armor/vest/nt, + ///obj/item/clothing/suit/storage/vest/nt/hos, + /obj/item/clothing/under/rank/head_of_security/jensen, + /obj/item/clothing/under/rank/head_of_security/corp, + /obj/item/clothing/suit/armor/hos/jensen, + /obj/item/clothing/suit/armor/hos, + ///obj/item/clothing/head/HoS/dermal, + ///obj/item/weapon/cartridge/hos, + /obj/item/device/radio/headset/heads/hos, + /obj/item/clothing/glasses/sunglasses, + ///obj/item/taperoll/police, + /obj/item/weapon/shield/riot, + /obj/item/weapon/storage/box/flashbangs, + /obj/item/weapon/storage/belt/security, + /obj/item/device/flash, + /obj/item/weapon/material/sword,//Broadsword, the most powerful melee weapon a HoS could ask for. + /obj/item/weapon/melee/classic_baton,///obj/item/weapon/melee/baton/loaded, + ///obj/item/weapon/gun/energy/gun, + ///obj/item/clothing/accessory/holster/waist, + /obj/item/weapon/melee/telebaton, + /obj/item/clothing/head/beret/sec/corporate/hos, + /obj/item/device/holowarrant + ) + +/obj/structure/closet/secure_closet/warden + name = "warden's locker" + req_access = list(access_armory) + icon_state = "wardensecure1" + icon_closed = "wardensecure" + icon_locked = "wardensecure1" + icon_opened = "wardensecureopen" + icon_off = "wardensecureoff" + +/obj/structure/closet/secure_closet/warden/WillContain() + return list( + new/datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack/security, /obj/item/weapon/storage/backpack/satchel/satchel_sec)), + new/datum/atom_creator/simple(/obj/item/weapon/storage/backpack/dufflebag/sec, 50), + ///obj/item/clothing/head/helmet/nt, + ///obj/item/clothing/suit/armor/vest/nt, + ///obj/item/clothing/suit/storage/vest/nt/warden, + /obj/item/clothing/under/rank/warden, + /obj/item/clothing/under/rank/warden/corp, + /obj/item/clothing/suit/armor/vest/warden, + /obj/item/clothing/head/warden, + /obj/item/weapon/cartridge/security, + /obj/item/device/radio/headset/headset_sec, + /obj/item/clothing/glasses/sunglasses, + /obj/item/taperoll/police, + /obj/item/weapon/storage/box/flashbangs, + /obj/item/weapon/storage/box/teargas, + /obj/item/weapon/storage/belt/security, + /obj/item/weapon/reagent_containers/spray/pepper, + /obj/item/weapon/melee/classic_baton,///obj/item/weapon/melee/baton/loaded, + ///obj/item/weapon/gun/energy/gun, + /obj/item/weapon/storage/box/holobadge, + /obj/item/clothing/head/beret/sec/corporate/warden, + /obj/item/device/holowarrant + ) + +/obj/structure/closet/secure_closet/security + name = "security officer's locker" + req_access = list(access_brig) + icon_state = "sec1" + icon_closed = "sec" + icon_locked = "sec1" + icon_opened = "secopen" + icon_off = "secoff" + +/obj/structure/closet/secure_closet/security/WillContain() + return list( + new/datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack/security, /obj/item/weapon/storage/backpack/satchel/satchel_sec)), + new/datum/atom_creator/simple(/obj/item/weapon/storage/backpack/dufflebag/sec, 50), + /obj/item/clothing/suit/armor/vest/opvest, + /obj/item/clothing/head/helmet, + /obj/item/clothing/mask/gas/security, + /obj/item/clothing/mask/balaclava, + /obj/item/device/radio/headset/headset_sec, + /obj/item/weapon/storage/belt/security, + /obj/item/device/flash, + /obj/item/weapon/reagent_containers/spray/pepper, + /obj/item/weapon/grenade/chem_grenade/teargas, + /obj/item/weapon/melee/classic_baton,///obj/item/weapon/melee/baton/loaded, + /obj/item/clothing/glasses/sunglasses, + /obj/item/taperoll/police, + ///obj/item/device/hailer, + ///obj/item/clothing/accessory/storage/black_vest, + /obj/item/clothing/head/soft/sec/corp, + /obj/item/clothing/under/rank/security/corp, + /obj/item/weapon/gun/energy/taser + ) + +/obj/structure/closet/secure_closet/security/cargo/WillContain() + return MERGE_ASSOCS_WITH_NUM_VALUES(..(), list( + /obj/item/clothing/accessory/armband/cargo, + /obj/item/device/encryptionkey/headset_cargo + )) + +/obj/structure/closet/secure_closet/security/engine/WillContain() + return MERGE_ASSOCS_WITH_NUM_VALUES(..(), list( + /obj/item/clothing/accessory/armband/engine, + /obj/item/device/encryptionkey/headset_eng + )) + +/obj/structure/closet/secure_closet/security/science/WillContain() + return MERGE_ASSOCS_WITH_NUM_VALUES(..(), list(/obj/item/device/encryptionkey/headset_sci)) + +/obj/structure/closet/secure_closet/security/med/WillContain() + return MERGE_ASSOCS_WITH_NUM_VALUES(..(), list( + /obj/item/clothing/accessory/armband/medgreen, + /obj/item/device/encryptionkey/headset_med + )) + +/obj/structure/closet/secure_closet/detective + name = "detective's cabinet" + req_access = list(access_forensics_lockers) + icon_state = "cabinetdetective_locked" + icon_closed = "cabinetdetective" + icon_locked = "cabinetdetective_locked" + icon_opened = "cabinetdetective_open" + icon_broken = "cabinetdetective_sparks" + icon_off = "cabinetdetective_broken" + +/obj/structure/closet/secure_closet/detective/WillContain() + return list( + /obj/item/clothing/under/det, + /obj/item/clothing/under/det/grey, + /obj/item/clothing/under/det/black, + /obj/item/clothing/suit/storage/det_trench, + /obj/item/clothing/suit/storage/det_trench/grey, + /obj/item/clothing/suit/storage/forensics/blue, + /obj/item/clothing/suit/storage/forensics/red, + /obj/item/clothing/gloves/thick, + /obj/item/clothing/head/det, + /obj/item/clothing/head/det/grey, + /obj/item/clothing/shoes/laceup, + /obj/item/weapon/storage/box/evidence, + /obj/item/device/radio/headset/headset_sec, + /obj/item/clothing/suit/armor/vest/detective, + /obj/item/ammo_magazine/c45m/flash, + /obj/item/taperoll/police, + /obj/item/weapon/gun/projectile/colt/detective, + /obj/item/clothing/accessory/holster/armpit, + /obj/item/weapon/reagent_containers/food/drinks/flask/detflask, + /obj/item/weapon/storage/briefcase/crimekit, + /obj/item/device/holowarrant + ) + +/obj/structure/closet/secure_closet/injection + name = "lethal injections locker" + req_access = list(access_captain) + +/obj/structure/closet/secure_closet/injection/WillContain() + return list(/obj/item/weapon/reagent_containers/syringe/ld50_syringe/choral = 2) + +/obj/structure/closet/secure_closet/brig + name = "brig locker" + req_access = list(access_brig) + anchored = 1 + var/id = null + +/obj/structure/closet/secure_closet/brig/WillContain() + return list( + /obj/item/clothing/under/color/orange, + /obj/item/clothing/shoes/orange + ) + +/obj/structure/closet/secure_closet/courtroom + name = "courtroom locker" + req_access = list(access_lawyer) + +/obj/structure/closet/secure_closet/courtroom/WillContain() + return list( + /obj/item/clothing/shoes/brown, + /obj/item/weapon/paper/Court = 3, + /obj/item/weapon/pen , + /obj/item/clothing/suit/judgerobe, + /obj/item/clothing/head/powdered_wig , + /obj/item/weapon/storage/briefcase, + ) + +/obj/structure/closet/secure_closet/wall + name = "wall locker" + req_access = list(access_security) + icon_state = "wall-locker1" + density = 1 + icon_closed = "wall-locker" + icon_locked = "wall-locker1" + icon_opened = "wall-lockeropen" + icon_broken = "wall-lockerbroken" + icon_off = "wall-lockeroff" + + //too small to put a man in + large = 0 + +/obj/structure/closet/secure_closet/lawyer + name = "internal affairs secure closet" + req_access = list(access_lawyer) + +/obj/structure/closet/secure_closet/lawyer/WillContain() + return list( + /obj/item/device/flash = 2, + /obj/item/device/camera = 2, + /obj/item/device/camera_film = 2, + /obj/item/device/taperecorder = 2, + /obj/item/weapon/storage/secure/briefcase = 2, + ) diff --git a/code/game/objects/structures/crates_lockers/closets/statue.dm b/code/game/objects/structures/crates_lockers/closets/statue.dm new file mode 100644 index 00000000..6935f33e --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/statue.dm @@ -0,0 +1,131 @@ +/obj/structure/closet/statue //what + name = "statue" + desc = "An incredibly lifelike marble carving." + icon = 'icons/obj/statue.dmi' + icon_state = "human_male" + density = 1 + anchored = 1 + setup = 0 + health = 0 //destroying the statue kills the mob within + var/intialTox = 0 //these are here to keep the mob from taking damage from things that logically wouldn't affect a rock + var/intialFire = 0 //it's a little sloppy I know but it was this or the GODMODE flag. Lesser of two evils. + var/intialBrute = 0 + var/intialOxy = 0 + var/timer = 240 //eventually the person will be freed + +/obj/structure/closet/statue/New(loc, var/mob/living/L) + if(L && (ishuman(L) || L.isMonkey() || iscorgi(L))) + if(L.buckled) + L.buckled = 0 + L.anchored = 0 + if(L.client) + L.client.perspective = EYE_PERSPECTIVE + L.client.eye = src + L.loc = src + L.sdisabilities |= MUTE + health = L.health + 100 //stoning damaged mobs will result in easier to shatter statues + intialTox = L.getToxLoss() + intialFire = L.getFireLoss() + intialBrute = L.getBruteLoss() + intialOxy = L.getOxyLoss() + if(ishuman(L)) + name = "statue of [L.name]" + if(L.gender == "female") + icon_state = "human_female" + else if(L.isMonkey()) + name = "statue of a monkey" + icon_state = "monkey" + else if(iscorgi(L)) + name = "statue of a corgi" + icon_state = "corgi" + desc = "If it takes forever, I will wait for you..." + + if(health == 0) //meaning if the statue didn't find a valid target + qdel(src) + return + + START_PROCESSING(SSobj, src) + ..() + +/obj/structure/closet/statue/Process() + timer-- + for(var/mob/living/M in src) //Go-go gadget stasis field + M.setToxLoss(intialTox) + M.adjustFireLoss(intialFire - M.getFireLoss()) + M.adjustBruteLoss(intialBrute - M.getBruteLoss()) + M.setOxyLoss(intialOxy) + if (timer <= 0) + dump_contents() + STOP_PROCESSING(SSobj, src) + qdel(src) + +/obj/structure/closet/statue/dump_contents() + + for(var/obj/O in src) + O.loc = src.loc + + for(var/mob/living/M in src) + M.loc = src.loc + M.sdisabilities &= ~MUTE + M.take_overall_damage((M.health - health - 100),0) //any new damage the statue incurred is transfered to the mob + if(M.client) + M.client.eye = M.client.mob + M.client.perspective = MOB_PERSPECTIVE + +/obj/structure/closet/statue/open() + return + +/obj/structure/closet/statue/close() + return + +/obj/structure/closet/statue/toggle() + return + +/obj/structure/closet/statue/proc/check_health() + if(health <= 0) + for(var/mob/M in src) + shatter(M) + +/obj/structure/closet/statue/bullet_act(var/obj/item/projectile/Proj) + health -= Proj.get_structure_damage() + check_health() + + return + +/obj/structure/closet/statue/attack_generic(var/mob/user, damage, attacktext, environment_smash) + if(damage && environment_smash) + for(var/mob/M in src) + shatter(M) + +/obj/structure/closet/statue/ex_act(severity) + for(var/mob/M in src) + M.ex_act(severity) + health -= 60 / severity + check_health() + +/obj/structure/closet/statue/attackby(obj/item/I as obj, mob/user as mob) + health -= I.force + visible_message("[user] strikes [src] with [I].") + check_health() + +/obj/structure/closet/statue/MouseDrop_T() + return + +/obj/structure/closet/statue/relaymove() + return + +/obj/structure/closet/statue/attack_hand() + return + +/obj/structure/closet/statue/verb_toggleopen() + return + +/obj/structure/closet/statue/update_icon() + return + +/obj/structure/closet/statue/proc/shatter(mob/user as mob) + if (user) + user.dust() + dump_contents() + visible_message("[src] shatters!.") + qdel(src) diff --git a/code/game/objects/structures/crates_lockers/closets/syndicate.dm b/code/game/objects/structures/crates_lockers/closets/syndicate.dm new file mode 100644 index 00000000..047e69b7 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/syndicate.dm @@ -0,0 +1,147 @@ +/obj/structure/closet/syndicate + name = "armory closet" + desc = "Why is this here?" + icon_state = "syndicate" + icon_closed = "syndicate" + icon_opened = "syndicateopen" + + +/obj/structure/closet/syndicate/personal + desc = "It's a storage unit for operative gear." + +/obj/structure/closet/syndicate/personal/New() + ..() + new /obj/item/weapon/tank/jetpack/oxygen(src) + new /obj/item/clothing/mask/gas/syndicate(src) + new /obj/item/clothing/under/syndicate(src) + new /obj/item/clothing/head/helmet/space/void/merc(src) + new /obj/item/clothing/suit/space/void/merc(src) + new /obj/item/weapon/crowbar/red(src) + new /obj/item/weapon/cell/high(src) + new /obj/item/weapon/card/id/syndicate(src) + new /obj/item/device/multitool(src) + new /obj/item/weapon/shield/energy(src) + new /obj/item/clothing/shoes/magboots(src) + + +/obj/structure/closet/syndicate/suit + desc = "It's a storage unit for voidsuits." + +/obj/structure/closet/syndicate/suit/New() + ..() + new /obj/item/weapon/tank/jetpack/oxygen(src) + new /obj/item/clothing/shoes/magboots(src) + new /obj/item/clothing/suit/space/void/merc(src) + new /obj/item/clothing/mask/gas/syndicate(src) + new /obj/item/clothing/head/helmet/space/void/merc(src) + + +/obj/structure/closet/syndicate/nuclear + desc = "It's a storage unit for nuclear-operative gear." + +/obj/structure/closet/syndicate/nuclear/New() + ..() + + new /obj/item/ammo_magazine/a10mm(src) + new /obj/item/ammo_magazine/a10mm(src) + new /obj/item/ammo_magazine/a10mm(src) + new /obj/item/ammo_magazine/a10mm(src) + new /obj/item/ammo_magazine/a10mm(src) + new /obj/item/weapon/storage/box/handcuffs(src) + new /obj/item/weapon/storage/box/flashbangs(src) + new /obj/item/weapon/gun/energy/gun(src) + new /obj/item/weapon/gun/energy/gun(src) + new /obj/item/weapon/gun/energy/gun(src) + new /obj/item/weapon/gun/energy/gun(src) + new /obj/item/weapon/gun/energy/gun(src) + new /obj/item/weapon/pinpointer/nukeop(src) + new /obj/item/weapon/pinpointer/nukeop(src) + new /obj/item/weapon/pinpointer/nukeop(src) + new /obj/item/weapon/pinpointer/nukeop(src) + new /obj/item/weapon/pinpointer/nukeop(src) + new /obj/item/device/pda/syndicate(src) + var/obj/item/device/radio/uplink/U = new(src) + U.hidden_uplink.uses = 40 + return + +/obj/structure/closet/syndicate/resources/ + desc = "An old, dusty locker." + + New() + ..() + var/common_min = 30 //Minimum amount of minerals in the stack for common minerals + var/common_max = 50 //Maximum amount of HONK in the stack for HONK common minerals + var/rare_min = 5 //Minimum HONK of HONK in the stack HONK HONK rare minerals + var/rare_max = 20 //Maximum HONK HONK HONK in the HONK for HONK rare HONK + + + + var/pickednum = rand(1, 50) + + //Sad trombone + if(pickednum == 1) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(src) + P.SetName("IOU") + P.info = "Sorry man, we needed the money so we sold your stash. It's ok, we'll double our money for sure this time!" + + //Metal (common ore) + if(pickednum >= 2) + new /obj/item/stack/material/steel(src, rand(common_min, common_max)) + + //Glass (common ore) + if(pickednum >= 5) + new /obj/item/stack/material/glass(src, rand(common_min, common_max)) + + //Plasteel (common ore) Because it has a million more uses then phoron + if(pickednum >= 10) + new /obj/item/stack/material/plasteel(src, rand(common_min, common_max)) + + //Phoron (rare ore) + if(pickednum >= 15) + new /obj/item/stack/material/phoron(src, rand(rare_min, rare_max)) + + //Silver (rare ore) + if(pickednum >= 20) + new /obj/item/stack/material/silver(src, rand(rare_min, rare_max)) + + //Gold (rare ore) + if(pickednum >= 30) + new /obj/item/stack/material/gold(src, rand(rare_min, rare_max)) + + //Uranium (rare ore) + if(pickednum >= 40) + new /obj/item/stack/material/uranium(src, rand(rare_min, rare_max)) + + //Diamond (rare HONK) + if(pickednum >= 45) + new /obj/item/stack/material/diamond(src, rand(rare_min, rare_max)) + + //Jetpack (You hit the jackpot!) + if(pickednum == 50) + new /obj/item/weapon/tank/jetpack/carbondioxide(src) + + return + +/obj/structure/closet/syndicate/resources/everything + desc = "It's an emergency storage closet for repairs." + + New() + var/list/resources = list( + /obj/item/stack/material/steel, + /obj/item/stack/material/glass, + /obj/item/stack/material/gold, + /obj/item/stack/material/silver, + /obj/item/stack/material/phoron, + /obj/item/stack/material/uranium, + /obj/item/stack/material/diamond, + /obj/item/stack/material/plasteel, + /obj/item/stack/rods + ) + + + for(var/i = 0, i<2, i++) + for(var/res in resources) + var/obj/item/stack/R = new res(src) + R.amount = R.max_amount + + return diff --git a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm new file mode 100644 index 00000000..48eef2d9 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm @@ -0,0 +1,277 @@ +/* Utility Closets + * Contains: + * Emergency Closet + * Fire Closet + * Tool Closet + * Radiation Closet + * Bombsuit Closet + * Hydrant + * First Aid + * Excavation Closet + */ + +/* + * Emergency Closet + */ +/obj/structure/closet/emcloset + name = "emergency closet" + desc = "It's a storage unit for emergency breathmasks and o2 tanks." + icon_state = "emergency" + icon_closed = "emergency" + icon_opened = "emergencyopen" + +/obj/structure/closet/emcloset/New() + ..() + + switch (pickweight(list("small" = 50, "aid" = 25, "tank" = 10, "large" = 5, "both" = 10))) + if ("small") + new /obj/item/weapon/tank/emergency/oxygen(src) + new /obj/item/weapon/tank/emergency/oxygen(src) + new /obj/item/clothing/mask/breath(src) + new /obj/item/clothing/mask/breath(src) + new /obj/item/clothing/suit/space/emergency(src) + new /obj/item/clothing/head/helmet/space/emergency(src) + if ("aid") + new /obj/item/weapon/tank/emergency/oxygen(src) + new /obj/item/weapon/storage/toolbox/emergency(src) + new /obj/item/clothing/mask/breath(src) + new /obj/item/weapon/storage/firstaid/o2(src) + new /obj/item/clothing/suit/space/emergency(src) + new /obj/item/clothing/head/helmet/space/emergency(src) + if ("tank") + new /obj/item/weapon/tank/emergency/oxygen/engi(src) + new /obj/item/weapon/tank/emergency/oxygen/engi(src) + new /obj/item/clothing/mask/gas/half(src) + new /obj/item/clothing/mask/gas/half(src) + if ("large") + new /obj/item/weapon/tank/emergency/oxygen/double(src) + new /obj/item/weapon/tank/emergency/oxygen/double(src) + new /obj/item/clothing/mask/gas(src) + new /obj/item/clothing/mask/gas(src) + if ("both") + new /obj/item/weapon/storage/toolbox/emergency(src) + new /obj/item/weapon/tank/emergency/oxygen/engi(src) + new /obj/item/weapon/tank/emergency/oxygen/engi(src) + new /obj/item/clothing/mask/gas/half(src) + new /obj/item/clothing/mask/gas/half(src) + new /obj/item/weapon/storage/firstaid/o2(src) + new /obj/item/clothing/suit/space/emergency(src) + new /obj/item/clothing/suit/space/emergency(src) + new /obj/item/clothing/head/helmet/space/emergency(src) + new /obj/item/clothing/head/helmet/space/emergency(src) + +/obj/structure/closet/emcloset/legacy/New() + ..() + new /obj/item/weapon/tank/oxygen(src) + new /obj/item/clothing/mask/gas(src) + +/* + * Fire Closet + */ +/obj/structure/closet/firecloset + name = "fire-safety closet" + desc = "It's a storage unit for fire-fighting supplies." + icon_state = "firecloset" + icon_closed = "firecloset" + icon_opened = "fireclosetopen" + +/obj/structure/closet/firecloset/New() + ..() + + new /obj/item/clothing/suit/fire/firefighter(src) + new /obj/item/clothing/mask/gas(src) + new /obj/item/weapon/tank/oxygen/red(src) + new /obj/item/weapon/extinguisher(src) + new /obj/item/clothing/head/hardhat/red(src) + +/obj/structure/closet/firecloset/full/New() + ..() + + new /obj/item/clothing/suit/fire/firefighter(src) + new /obj/item/clothing/mask/gas(src) + new /obj/item/device/flashlight(src) + new /obj/item/weapon/tank/oxygen/red(src) + new /obj/item/weapon/extinguisher(src) + new /obj/item/clothing/head/hardhat/red(src) + +/obj/structure/closet/firecloset/update_icon() + if(!opened) + icon_state = icon_closed + else + icon_state = icon_opened + + +/* + * Tool Closet + */ +/obj/structure/closet/toolcloset + name = "tool closet" + desc = "It's a storage unit for tools." + icon_state = "toolcloset" + icon_closed = "toolcloset" + icon_opened = "toolclosetopen" + +/obj/structure/closet/toolcloset/New() + ..() + if(prob(40)) + new /obj/item/clothing/suit/storage/hazardvest(src) + if(prob(70)) + new /obj/item/device/flashlight(src) + if(prob(70)) + new /obj/item/weapon/screwdriver(src) + if(prob(70)) + new /obj/item/weapon/wrench(src) + if(prob(70)) + new /obj/item/weapon/weldingtool(src) + if(prob(70)) + new /obj/item/weapon/crowbar(src) + if(prob(70)) + new /obj/item/weapon/wirecutters(src) + if(prob(70)) + new /obj/item/device/t_scanner(src) + if(prob(20)) + new /obj/item/weapon/storage/belt/utility(src) + if(prob(30)) + new /obj/item/stack/cable_coil/random(src) + if(prob(30)) + new /obj/item/stack/cable_coil/random(src) + if(prob(30)) + new /obj/item/stack/cable_coil/random(src) + if(prob(20)) + new /obj/item/device/multitool(src) + if(prob(5)) + new /obj/item/clothing/gloves/insulated(src) + if(prob(40)) + new /obj/item/clothing/head/hardhat(src) + + +/* + * Radiation Closet + */ +/obj/structure/closet/radiation + name = "radiation suit closet" + desc = "It's a storage unit for rad-protective suits." + icon_state = "radsuitcloset" + icon_opened = "toolclosetopen" + icon_closed = "radsuitcloset" + +/obj/structure/closet/radiation/New() + ..() + new /obj/item/clothing/suit/radiation(src) + new /obj/item/clothing/head/radiation(src) + new /obj/item/clothing/suit/radiation(src) + new /obj/item/clothing/head/radiation(src) + new /obj/item/device/geiger(src) + new /obj/item/device/geiger(src) + +/* + * Bombsuit closet + */ +/obj/structure/closet/bombcloset + name = "\improper EOD closet" + desc = "It's a storage unit for explosion-protective suits." + icon_state = "bombsuit" + icon_closed = "bombsuit" + icon_opened = "bombsuitopen" + +/obj/structure/closet/bombcloset/New() + ..() + new /obj/item/clothing/suit/bomb_suit( src ) + new /obj/item/clothing/under/color/black( src ) + new /obj/item/clothing/shoes/black( src ) + new /obj/item/clothing/head/bomb_hood( src ) + + +/obj/structure/closet/bombclosetsecurity + name = "\improper EOD closet" + desc = "It's a storage unit for explosion-protective suits." + icon_state = "bombsuitsec" + icon_closed = "bombsuitsec" + icon_opened = "bombsuitsecopen" + +/obj/structure/closet/bombclosetsecurity/New() + ..() + new /obj/item/clothing/suit/bomb_suit/security( src ) + new /obj/item/clothing/under/rank/security( src ) + new /obj/item/clothing/shoes/brown( src ) + new /obj/item/clothing/head/bomb_hood/security( src ) + +/* + * Hydrant + */ +/obj/structure/closet/hydrant //wall mounted fire closet + name = "fire-safety closet" + desc = "It's a storage unit for fire-fighting supplies." + icon_state = "hydrant" + icon_closed = "hydrant" + icon_opened = "hydrant_open" + anchored = 1 + density = 0 + wall_mounted = 1 + storage_types = CLOSET_STORAGE_ITEMS + setup = 0 + +/obj/structure/closet/hydrant/New() + ..() + new /obj/item/inflatable/door(src) + new /obj/item/inflatable/door(src) + new /obj/item/clothing/suit/fire/firefighter(src) + new /obj/item/clothing/mask/gas/half(src) + new /obj/item/device/flashlight(src) + new /obj/item/weapon/tank/oxygen/red(src) + new /obj/item/weapon/extinguisher(src) + new /obj/item/clothing/head/hardhat/red(src) + +/* + * First Aid + */ +/obj/structure/closet/medical_wall //wall mounted medical closet + name = "first-aid closet" + desc = "It's a wall-mounted storage unit for first aid supplies." + icon_state = "medical_wall_first_aid" + icon_closed = "medical_wall_first_aid" + icon_opened = "medical_wall_first_aid_open" + anchored = 1 + density = 0 + wall_mounted = 1 + storage_types = CLOSET_STORAGE_ITEMS + setup = 0 + +/obj/structure/closet/medical_wall/update_icon() + if(!opened) + icon_state = icon_closed + else + icon_state = icon_opened + +/obj/structure/closet/medical_wall/filled + +/obj/structure/closet/medical_wall/filled/WillContain() + return list( + /obj/random/firstaid, + /obj/random/medical/lite = 12) + +/obj/structure/closet/shipping_wall + name = "shipping supplies closet" + desc = "It's a wall-mounted storage unit containing supplies for preparing shipments." + icon_state = "shipping_wall" + icon_closed = "shipping_wall" + icon_opened = "shipping_wall_open" + anchored = 1 + density = 0 + wall_mounted = 1 + storage_types = CLOSET_STORAGE_ITEMS + setup = 0 + +/obj/structure/closet/shipping_wall/update_icon() + if(!opened) + icon_state = icon_closed + else + icon_state = icon_opened + +/obj/structure/closet/shipping_wall/filled + +/obj/structure/closet/shipping_wall/filled/WillContain() + return list( + /obj/item/stack/material/cardboard/ten, + /obj/item/device/destTagger, + /obj/item/weapon/packageWrap) \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/closets/walllocker.dm b/code/game/objects/structures/crates_lockers/closets/walllocker.dm new file mode 100644 index 00000000..f26d40bb --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/walllocker.dm @@ -0,0 +1,59 @@ +//added by cael from old bs12 +//not sure if there's an immediate place for secure wall lockers, but i'm sure the players will think of something + +/obj/structure/closet/walllocker + desc = "A wall mounted storage locker." + name = "Wall Locker" + icon = 'icons/obj/walllocker.dmi' + icon_state = "wall-locker" + density = 0 + anchored = 1 + icon_closed = "wall-locker" + icon_opened = "wall-lockeropen" + storage_types = CLOSET_STORAGE_ITEMS + setup = 0 + +//spawns endless (3 sets) amounts of breathmask, emergency oxy tank and crowbar + +/obj/structure/closet/walllocker/emerglocker + name = "emergency locker" + desc = "A wall mounted locker with emergency supplies." + var/list/spawnitems = list(/obj/item/weapon/tank/emergency/oxygen,/obj/item/clothing/mask/breath) + var/amount = 2 // spawns each items X times. + icon_state = "emerg" + +/obj/structure/closet/walllocker/emerglocker/toggle(mob/user as mob) + src.attack_hand(user) + return + +/obj/structure/closet/walllocker/emerglocker/attackby(obj/item/weapon/W as obj, mob/user as mob) + return + +/obj/structure/closet/walllocker/emerglocker/attack_hand(mob/user as mob) + if (istype(user, /mob/living/silicon/ai)) //Added by Strumpetplaya - AI shouldn't be able to + return //activate emergency lockers. This fixes that. (Does this make sense, the AI can't call attack_hand, can it? --Mloc) + if(!amount) + to_chat(usr, "It's empty..") + return + if(amount) + to_chat(usr, "You take out some items from \the [src].") + for(var/path in spawnitems) + new path(src.loc) + amount-- + return + +/obj/structure/closet/walllocker/emerglocker/north + pixel_y = 32 + dir = SOUTH + +/obj/structure/closet/walllocker/emerglocker/south + pixel_y = -32 + dir = NORTH + +/obj/structure/closet/walllocker/emerglocker/west + pixel_x = -32 + dir = WEST + +/obj/structure/closet/walllocker/emerglocker/east + pixel_x = 32 + dir = EAST diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm new file mode 100644 index 00000000..fd80e012 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm @@ -0,0 +1,463 @@ +/obj/structure/closet/wardrobe + name = "wardrobe" + desc = "It's a storage unit for standard-issue attire." + icon_state = "blue" + icon_closed = "blue" + +/obj/structure/closet/wardrobe/red + name = "security wardrobe" + icon_state = "red" + icon_closed = "red" + +/obj/structure/closet/wardrobe/red/New() + ..() + new /obj/item/clothing/under/rank/security(src) + new /obj/item/clothing/under/rank/security(src) + new /obj/item/clothing/under/rank/security(src) + new /obj/item/clothing/under/rank/security2(src) + new /obj/item/clothing/under/rank/security2(src) + new /obj/item/clothing/under/rank/security2(src) + new /obj/item/clothing/shoes/jackboots(src) + new /obj/item/clothing/shoes/jackboots(src) + new /obj/item/clothing/shoes/jackboots(src) + new /obj/item/clothing/head/soft/sec(src) + new /obj/item/clothing/head/soft/sec(src) + new /obj/item/clothing/head/soft/sec(src) + new /obj/item/clothing/head/beret/sec(src) + new /obj/item/clothing/head/beret/sec(src) + new /obj/item/clothing/head/beret/sec(src) + new /obj/item/clothing/head/beret/sec/corporate/officer(src) + new /obj/item/clothing/head/beret/sec/corporate/officer(src) + new /obj/item/clothing/head/beret/sec/corporate/officer(src) + return + + +/obj/structure/closet/wardrobe/pink + name = "pink wardrobe" + icon_state = "pink" + icon_closed = "pink" + +/obj/structure/closet/wardrobe/pink/New() + ..() + new /obj/item/clothing/under/color/pink(src) + new /obj/item/clothing/under/color/pink(src) + new /obj/item/clothing/under/color/pink(src) + new /obj/item/clothing/shoes/brown(src) + new /obj/item/clothing/shoes/brown(src) + new /obj/item/clothing/shoes/brown(src) + return + +/obj/structure/closet/wardrobe/black + name = "black wardrobe" + icon_state = "black" + icon_closed = "black" + +/obj/structure/closet/wardrobe/black/New() + ..() + new /obj/item/clothing/under/color/black(src) + new /obj/item/clothing/under/color/black(src) + new /obj/item/clothing/under/color/black(src) + new /obj/item/clothing/shoes/black(src) + new /obj/item/clothing/shoes/black(src) + new /obj/item/clothing/shoes/black(src) + new /obj/item/clothing/head/that(src) + new /obj/item/clothing/head/that(src) + new /obj/item/clothing/head/that(src) + new /obj/item/clothing/head/soft/black(src) + new /obj/item/clothing/head/soft/black(src) + new /obj/item/clothing/head/soft/black(src) + return + + +/obj/structure/closet/wardrobe/chaplain_black + name = "chapel wardrobe" + desc = "It's a storage unit for approved religious attire." + icon_state = "black" + icon_closed = "black" + +/obj/structure/closet/wardrobe/chaplain_black/New() + ..() + new /obj/item/clothing/under/rank/chaplain(src) + new /obj/item/clothing/shoes/black(src) + new /obj/item/clothing/suit/nun(src) + new /obj/item/clothing/head/nun_hood(src) + new /obj/item/clothing/suit/chaplain_hoodie(src) + new /obj/item/clothing/head/chaplain_hood(src) + new /obj/item/clothing/suit/holidaypriest(src) + new /obj/item/clothing/under/wedding/bride_white(src) + new /obj/item/weapon/storage/backpack/cultpack (src) + new /obj/item/weapon/storage/fancy/candle_box(src) + new /obj/item/weapon/storage/fancy/candle_box(src) + new /obj/item/weapon/deck/tarot(src) + return + + +/obj/structure/closet/wardrobe/green + name = "green wardrobe" + icon_state = "green" + icon_closed = "green" + +/obj/structure/closet/wardrobe/green/New() + ..() + new /obj/item/clothing/under/color/green(src) + new /obj/item/clothing/under/color/green(src) + new /obj/item/clothing/under/color/green(src) + new /obj/item/clothing/shoes/black(src) + new /obj/item/clothing/shoes/black(src) + new /obj/item/clothing/shoes/black(src) + return + +/obj/structure/closet/wardrobe/xenos + name = "xenos wardrobe" + icon_state = "green" + icon_closed = "green" + +/obj/structure/closet/wardrobe/xenos/New() + ..() + new /obj/item/clothing/suit/unathi/mantle(src) + new /obj/item/clothing/suit/unathi/robe(src) + new /obj/item/clothing/shoes/sandal(src) + new /obj/item/clothing/shoes/sandal(src) + new /obj/item/clothing/shoes/sandal(src) + return + + +/obj/structure/closet/wardrobe/orange + name = "prison wardrobe" + desc = "It's a storage unit for regulation prisoner attire." + icon_state = "orange" + icon_closed = "orange" + +/obj/structure/closet/wardrobe/orange/New() + ..() + new /obj/item/clothing/under/color/orange(src) + new /obj/item/clothing/under/color/orange(src) + new /obj/item/clothing/under/color/orange(src) + new /obj/item/clothing/shoes/orange(src) + new /obj/item/clothing/shoes/orange(src) + new /obj/item/clothing/shoes/orange(src) + new /obj/item/device/radio/headset(src) + new /obj/item/device/radio/headset(src) + new /obj/item/device/radio/headset(src) + return + + +/obj/structure/closet/wardrobe/yellow + name = "yellow wardrobe" + icon_state = "wardrobe-y" + icon_closed = "wardrobe-y" + +/obj/structure/closet/wardrobe/yellow/New() + ..() + new /obj/item/clothing/under/color/yellow(src) + new /obj/item/clothing/under/color/yellow(src) + new /obj/item/clothing/under/color/yellow(src) + new /obj/item/clothing/shoes/orange(src) + new /obj/item/clothing/shoes/orange(src) + new /obj/item/clothing/shoes/orange(src) + return + + +/obj/structure/closet/wardrobe/atmospherics_yellow + name = "atmospherics wardrobe" + icon_state = "yellow" + icon_closed = "yellow" + +/obj/structure/closet/wardrobe/atmospherics_yellow/New() + ..() + new /obj/item/clothing/under/rank/atmospheric_technician(src) + new /obj/item/clothing/under/rank/atmospheric_technician(src) + new /obj/item/clothing/under/rank/atmospheric_technician(src) + new /obj/item/clothing/shoes/workboots(src) + new /obj/item/clothing/shoes/workboots(src) + new /obj/item/clothing/shoes/workboots(src) + new /obj/item/clothing/head/hardhat/red(src) + new /obj/item/clothing/head/hardhat/red(src) + new /obj/item/clothing/head/hardhat/red(src) + new /obj/item/clothing/head/beret/engineering(src) + new /obj/item/clothing/head/beret/engineering(src) + new /obj/item/clothing/head/beret/engineering(src) + return + + + +/obj/structure/closet/wardrobe/engineering_yellow + name = "engineering wardrobe" + icon_state = "yellow" + icon_closed = "yellow" + +/obj/structure/closet/wardrobe/engineering_yellow/New() + ..() + new /obj/item/clothing/under/rank/engineer(src) + new /obj/item/clothing/under/rank/engineer(src) + new /obj/item/clothing/under/rank/engineer(src) + new /obj/item/clothing/shoes/workboots(src) + new /obj/item/clothing/shoes/workboots(src) + new /obj/item/clothing/shoes/workboots(src) + new /obj/item/clothing/head/hardhat(src) + new /obj/item/clothing/head/hardhat(src) + new /obj/item/clothing/head/hardhat(src) + new /obj/item/clothing/head/beret/engineering(src) + new /obj/item/clothing/head/beret/engineering(src) + new /obj/item/clothing/head/beret/engineering(src) + return + + +/obj/structure/closet/wardrobe/white + name = "white wardrobe" + icon_state = "white" + icon_closed = "white" + +/obj/structure/closet/wardrobe/white/New() + ..() + new /obj/item/clothing/under/color/white(src) + new /obj/item/clothing/under/color/white(src) + new /obj/item/clothing/under/color/white(src) + new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/shoes/white(src) + return + + +/obj/structure/closet/wardrobe/pjs + name = "pajama wardrobe" + icon_state = "white" + icon_closed = "white" + +/obj/structure/closet/wardrobe/pjs/New() + ..() + new /obj/item/clothing/under/pj/red(src) + new /obj/item/clothing/under/pj/red(src) + new /obj/item/clothing/under/pj/blue(src) + new /obj/item/clothing/under/pj/blue(src) + new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/shoes/slippers(src) + new /obj/item/clothing/shoes/slippers(src) + return + + +/obj/structure/closet/wardrobe/science_white + name = "science wardrobe" + icon_state = "white" + icon_closed = "white" + +/obj/structure/closet/wardrobe/science_white/New() + ..() + new /obj/item/clothing/under/rank/scientist(src) + new /obj/item/clothing/under/rank/scientist(src) + new /obj/item/clothing/under/rank/scientist(src) + new /obj/item/clothing/suit/storage/toggle/labcoat(src) + new /obj/item/clothing/suit/storage/toggle/labcoat(src) + new /obj/item/clothing/suit/storage/toggle/labcoat(src) + new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/shoes/white(src) + return + + +/obj/structure/closet/wardrobe/robotics_black + name = "robotics wardrobe" + icon_state = "black" + icon_closed = "black" + +/obj/structure/closet/wardrobe/robotics_black/New() + ..() + new /obj/item/clothing/under/rank/roboticist(src) + new /obj/item/clothing/under/rank/roboticist(src) + new /obj/item/clothing/suit/storage/toggle/labcoat(src) + new /obj/item/clothing/suit/storage/toggle/labcoat(src) + new /obj/item/clothing/shoes/black(src) + new /obj/item/clothing/shoes/black(src) + new /obj/item/clothing/gloves/thick(src) + new /obj/item/clothing/gloves/thick(src) + return + + +/obj/structure/closet/wardrobe/chemistry_white + name = "chemistry wardrobe" + icon_state = "white" + icon_closed = "white" + +/obj/structure/closet/wardrobe/chemistry_white/New() + ..() + new /obj/item/clothing/under/rank/chemist(src) + new /obj/item/clothing/under/rank/chemist(src) + new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/suit/storage/toggle/labcoat/chemist(src) + new /obj/item/clothing/suit/storage/toggle/labcoat/chemist(src) + return + + +/obj/structure/closet/wardrobe/genetics_white + name = "genetics wardrobe" + icon_state = "white" + icon_closed = "white" + +/obj/structure/closet/wardrobe/genetics_white/New() + ..() + new /obj/item/clothing/under/rank/geneticist(src) + new /obj/item/clothing/under/rank/geneticist(src) + new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/suit/storage/toggle/labcoat/genetics(src) + new /obj/item/clothing/suit/storage/toggle/labcoat/genetics(src) + return + + +/obj/structure/closet/wardrobe/virology_white + name = "virology wardrobe" + icon_state = "white" + icon_closed = "white" + +/obj/structure/closet/wardrobe/virology_white/New() + ..() + new /obj/item/clothing/under/rank/virologist(src) + new /obj/item/clothing/under/rank/virologist(src) + new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/suit/storage/toggle/labcoat/virologist(src) + new /obj/item/clothing/suit/storage/toggle/labcoat/virologist(src) + new /obj/item/clothing/mask/surgical(src) + new /obj/item/clothing/mask/surgical(src) + return + + +/obj/structure/closet/wardrobe/medic_white + name = "medical wardrobe" + icon_state = "white" + icon_closed = "white" + +/obj/structure/closet/wardrobe/medic_white/New() + ..() + new /obj/item/clothing/under/rank/medical(src) + new /obj/item/clothing/under/rank/medical(src) + new /obj/item/clothing/under/rank/medical/scrubs/blue(src) + new /obj/item/clothing/under/rank/medical/scrubs/green(src) + new /obj/item/clothing/under/rank/medical/scrubs/purple(src) + new /obj/item/clothing/under/rank/medical/scrubs/black(src) + new /obj/item/clothing/under/rank/medical/scrubs/navyblue(src) + new /obj/item/clothing/head/surgery/navyblue(src) + new /obj/item/clothing/head/surgery/purple(src) + new /obj/item/clothing/head/surgery/blue(src) + new /obj/item/clothing/head/surgery/green(src) + new /obj/item/clothing/head/surgery/black(src) + new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/suit/storage/toggle/labcoat(src) + new /obj/item/clothing/suit/storage/toggle/labcoat(src) + new /obj/item/clothing/mask/surgical(src) + new /obj/item/clothing/mask/surgical(src) + +/obj/structure/closet/wardrobe/grey + name = "grey wardrobe" + icon_state = "grey" + icon_closed = "grey" + +/obj/structure/closet/wardrobe/grey/New() + ..() + new /obj/item/clothing/under/color/grey(src) + new /obj/item/clothing/under/color/grey(src) + new /obj/item/clothing/under/color/grey(src) + new /obj/item/clothing/shoes/black(src) + new /obj/item/clothing/shoes/black(src) + new /obj/item/clothing/shoes/black(src) + new /obj/item/clothing/head/soft/grey(src) + new /obj/item/clothing/head/soft/grey(src) + new /obj/item/clothing/head/soft/grey(src) + return + + +/obj/structure/closet/wardrobe/mixed + name = "mixed wardrobe" + icon_state = "mixed" + icon_closed = "mixed" + +/obj/structure/closet/wardrobe/mixed/New() + ..() + new /obj/item/clothing/under/color/blue(src) + new /obj/item/clothing/under/color/yellow(src) + new /obj/item/clothing/under/color/green(src) + new /obj/item/clothing/under/color/orange(src) + new /obj/item/clothing/under/color/pink(src) + new /obj/item/clothing/under/dress/plaid_blue(src) + new /obj/item/clothing/under/dress/plaid_red(src) + new /obj/item/clothing/under/dress/plaid_purple(src) + new /obj/item/clothing/shoes/blue(src) + new /obj/item/clothing/shoes/yellow(src) + new /obj/item/clothing/shoes/green(src) + new /obj/item/clothing/shoes/orange(src) + new /obj/item/clothing/shoes/purple(src) + new /obj/item/clothing/shoes/red(src) + new /obj/item/clothing/shoes/leather(src) + new /obj/item/clothing/accessory/toggleable/hawaii/random(src) + return + +/obj/structure/closet/wardrobe/tactical + name = "tactical equipment" + icon_state = "syndicate1" + icon_closed = "syndicate1" + icon_opened = "syndicate1open" + +/obj/structure/closet/wardrobe/tactical/New() + ..() + new /obj/item/clothing/under/tactical(src) + new /obj/item/clothing/suit/storage/vest/tactical(src) + new /obj/item/clothing/head/helmet/tactical(src) + new /obj/item/clothing/mask/balaclava/tactical(src) + new /obj/item/clothing/glasses/tacgoggles(src) + new /obj/item/weapon/storage/belt/security/tactical(src) + new /obj/item/clothing/shoes/tactical(src) + new /obj/item/clothing/gloves/tactical(src) + return + +/obj/structure/closet/wardrobe/suit + name = "formal clothing locker" + icon_state = "mixed" + icon_closed = "mixed" + +/obj/structure/closet/wardrobe/suit/New() + ..() + new /obj/item/clothing/under/suit_jacket/charcoal(src) + new /obj/item/clothing/under/suit_jacket/navy(src) + new /obj/item/clothing/under/suit_jacket/burgundy(src) + new /obj/item/clothing/under/suit_jacket/checkered(src) + new /obj/item/clothing/under/suit_jacket/tan(src) + new /obj/item/clothing/under/sl_suit(src) + new /obj/item/clothing/under/suit_jacket(src) + new /obj/item/clothing/under/suit_jacket/female(src) + new /obj/item/clothing/under/suit_jacket/really_black(src) + new /obj/item/clothing/under/suit_jacket/red(src) + new /obj/item/clothing/under/scratch(src) + new /obj/item/clothing/under/rank/internalaffairs/plain(src) + new /obj/item/clothing/suit/storage/toggle/suit/black(src) + new /obj/item/clothing/under/assistantformal(src) + new /obj/item/clothing/under/lawyer/female(src) + new /obj/item/clothing/under/lawyer/black(src) + new /obj/item/clothing/under/lawyer/red(src) + new /obj/item/clothing/under/lawyer/bluesuit(src) + new /obj/item/clothing/suit/storage/toggle/suit/blue(src) + new /obj/item/clothing/under/lawyer/purpsuit(src) + new /obj/item/clothing/suit/storage/toggle/suit/purple(src) + new /obj/item/clothing/shoes/brown(src) + new /obj/item/clothing/shoes/laceup(src) + +/obj/structure/closet/wardrobe/lawyer_black + name = "internal affairs wardrobe" + icon_state = "black" + icon_closed = "black" + +/obj/structure/closet/wardrobe/lawyer_black/New() + ..() + new /obj/item/clothing/under/rank/internalaffairs(src) + new /obj/item/clothing/under/rank/internalaffairs(src) + new /obj/item/clothing/suit/storage/toggle/suit/black(src) + new /obj/item/clothing/suit/storage/toggle/suit/black(src) + new /obj/item/clothing/shoes/brown(src) + new /obj/item/clothing/shoes/brown(src) + new /obj/item/clothing/glasses/sunglasses/big(src) + new /obj/item/clothing/glasses/sunglasses/big(src) + new /obj/item/weapon/storage/briefcase(src) + new /obj/item/weapon/storage/briefcase(src) + return diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm new file mode 100644 index 00000000..07c458ef --- /dev/null +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -0,0 +1,345 @@ +obj/structure/closet/crate + name = "crate" + desc = "A rectangular steel crate." + icon = 'icons/obj/storage.dmi' + icon_state = "crate" + icon_opened = "crateopen" + icon_closed = "crate" + open_sound = 'sound/effects/locker_open.ogg' + close_sound = 'sound/effects/locker_close.ogg' + atom_flags = ATOM_FLAG_CLIMBABLE + setup = 0 + + storage_types = CLOSET_STORAGE_ITEMS + + var/points_per_crate = 5 + var/rigged = 0 + +/obj/structure/closet/crate/open() + if((atom_flags & ATOM_FLAG_OPEN_CONTAINER) && !opened && can_open()) + object_shaken() + . = ..() + if(.) + if(rigged) + visible_message("There are wires attached to the lid of [src]...") + for(var/obj/item/device/assembly_holder/H in src) + H.process_activation(usr) + for(var/obj/item/device/assembly/A in src) + A.activate() + +/obj/structure/closet/crate/examine(mob/user) + ..() + if(rigged && opened) + var/list/devices = list() + for(var/obj/item/device/assembly_holder/H in src) + devices += H + for(var/obj/item/device/assembly/A in src) + devices += A + to_chat(user,"There are some wires attached to the lid, connected to [english_list(devices)].") + +/obj/structure/closet/crate/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(opened) + return ..() + else if(istype(W, /obj/item/weapon/packageWrap)) + return + else if(istype(W, /obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/C = W + if(rigged) + to_chat(user, "[src] is already rigged!") + return + if (C.use(1)) + to_chat(user, "You rig [src].") + rigged = 1 + return + else if(istype(W, /obj/item/device/assembly_holder) || istype(W, /obj/item/device/assembly)) + if(rigged) + to_chat(user, "You attach [W] to [src].") + user.drop_item() + W.forceMove(src) + return + else if(isWirecutter(W)) + if(rigged) + to_chat(user, "You cut away the wiring.") + playsound(loc, 'sound/items/Wirecutter.ogg', 100, 1) + rigged = 0 + return + else + return ..() + +/obj/structure/closet/crate/secure + desc = "A secure crate." + name = "Secure crate" + icon_state = "securecrate" + icon_opened = "securecrateopen" + icon_closed = "securecrate" + var/redlight = "securecrater" + var/greenlight = "securecrateg" + var/sparks = "securecratesparks" + var/emag = "securecrateemag" + + setup = CLOSET_HAS_LOCK + locked = TRUE + +/obj/structure/closet/crate/secure/Initialize() + . = ..() + update_icon() + +/obj/structure/closet/crate/secure/update_icon() + ..() + if(broken) + overlays += emag + else if(locked) + overlays += redlight + else + overlays += greenlight + +/obj/structure/closet/crate/plastic + name = "plastic crate" + desc = "A rectangular plastic crate." + icon_state = "plasticcrate" + icon_opened = "plasticcrateopen" + icon_closed = "plasticcrate" + points_per_crate = 1 + +/obj/structure/closet/crate/internals + name = "internals crate" + desc = "A internals crate." + icon_state = "o2crate" + icon_opened = "o2crateopen" + icon_closed = "o2crate" + +/obj/structure/closet/crate/internals/fuel + name = "\improper Fuel tank crate" + desc = "A fuel tank crate." + +/obj/structure/closet/crate/internals/fuel/WillContain() + return list(/obj/item/weapon/tank/hydrogen = 4) + +/obj/structure/closet/crate/trashcart + name = "trash cart" + desc = "A heavy, metal trashcart with wheels." + icon_state = "trashcart" + icon_opened = "trashcartopen" + icon_closed = "trashcart" + +/obj/structure/closet/crate/medical + name = "medical crate" + desc = "A medical crate." + icon_state = "medicalcrate" + icon_opened = "medicalcrateopen" + icon_closed = "medicalcrate" + +/obj/structure/closet/crate/rcd + name = "\improper RCD crate" + desc = "A crate with rapid construction device." + icon_state = "crate" + icon_opened = "crateopen" + icon_closed = "crate" + +/obj/structure/closet/crate/rcd/WillContain() + return list( + /obj/item/weapon/rcd_ammo = 3, + /obj/item/weapon/rcd + ) + +/obj/structure/closet/crate/solar + name = "solar pack crate" + +/obj/structure/closet/crate/solar/WillContain() + return list( + /obj/item/solar_assembly = 14, + /obj/item/weapon/circuitboard/solar_control, + /obj/item/weapon/tracker_electronics, + /obj/item/weapon/paper/solar + ) + +/obj/structure/closet/crate/solar_assembly + name = "solar assembly crate" + +/obj/structure/closet/crate/solar_assembly/WillContain() + return list(/obj/item/solar_assembly = 16) + +/obj/structure/closet/crate/freezer + name = "freezer" + desc = "A freezer." + icon_state = "freezer" + icon_opened = "freezeropen" + icon_closed = "freezer" + var/target_temp = T0C - 40 + var/cooling_power = 40 + + return_air() + var/datum/gas_mixture/gas = (..()) + if(!gas) return null + var/datum/gas_mixture/newgas = new/datum/gas_mixture() + newgas.copy_from(gas) + if(newgas.temperature <= target_temp) return + + if((newgas.temperature - cooling_power) > target_temp) + newgas.temperature -= cooling_power + else + newgas.temperature = target_temp + return newgas + +/obj/structure/closet/crate/freezer/rations //Fpr use in the escape shuttle + name = "emergency rations" + desc = "A crate of emergency rations." + + +/obj/structure/closet/crate/freezer/rations/WillContain() + return list(/obj/item/weapon/reagent_containers/food/snacks/liquidfood = 4) + +/obj/structure/closet/crate/bin + name = "large bin" + desc = "A large bin." + icon_state = "largebin" + icon_opened = "largebinopen" + icon_closed = "largebin" + +/obj/structure/closet/crate/radiation + name = "radioactive crate" + desc = "A leadlined crate with a radiation sign on it." + icon_state = "radiation" + icon_opened = "radiationopen" + icon_closed = "radiation" + +/obj/structure/closet/crate/radiation_gear + name = "radioactive gear crate" + desc = "A crate with a radiation sign on it." + icon_state = "radiation" + icon_opened = "radiationopen" + icon_closed = "radiation" + +/obj/structure/closet/crate/radiation_gear/WillContain() + return list(/obj/item/clothing/suit/radiation = 8) + +/obj/structure/closet/crate/secure/weapon + name = "weapons crate" + desc = "A secure weapons crate." + icon_state = "weaponcrate" + icon_opened = "weaponcrateopen" + icon_closed = "weaponcrate" + +/obj/structure/closet/crate/secure/phoron + name = "phoron crate" + desc = "A secure phoron crate." + icon_state = "phoroncrate" + icon_opened = "phoroncrateopen" + icon_closed = "phoroncrate" + +/obj/structure/closet/crate/secure/gear + name = "gear crate" + desc = "A secure gear crate." + icon_state = "secgearcrate" + icon_opened = "secgearcrateopen" + icon_closed = "secgearcrate" + +/obj/structure/closet/crate/secure/hydrosec + name = "secure hydroponics crate" + desc = "A crate with a lock on it, painted in the scheme of botany and botanists." + icon_state = "hydrosecurecrate" + icon_opened = "hydrosecurecrateopen" + icon_closed = "hydrosecurecrate" + +/obj/structure/closet/crate/secure/bin + name = "secure bin" + desc = "A secure bin." + icon_state = "largebins" + icon_opened = "largebinsopen" + icon_closed = "largebins" + redlight = "largebinr" + greenlight = "largebing" + sparks = "largebinsparks" + emag = "largebinemag" + +/obj/structure/closet/crate/large + name = "large crate" + desc = "A hefty metal crate." + icon = 'icons/obj/storage.dmi' + icon_state = "largemetal" + icon_opened = "largemetalopen" + icon_closed = "largemetal" + + storage_capacity = 2 * MOB_LARGE + storage_types = CLOSET_STORAGE_ITEMS|CLOSET_STORAGE_STRUCTURES + +/obj/structure/closet/crate/large/hydroponics + icon_state = "hydro_crate_large" + icon_opened = "hydro_crate_large_open" + icon_closed = "hydro_crate_large" + +/obj/structure/closet/crate/secure/large + name = "large crate" + desc = "A hefty metal crate with an electronic locking system." + icon = 'icons/obj/storage.dmi' + icon_state = "largemetal" + icon_opened = "largemetalopen" + icon_closed = "largemetal" + redlight = "largemetalr" + greenlight = "largemetalg" + + storage_capacity = 2 * MOB_LARGE + storage_types = CLOSET_STORAGE_ITEMS|CLOSET_STORAGE_STRUCTURES + +/obj/structure/closet/crate/secure/large/phoron + icon_state = "phoron_crate_large" + icon_opened = "phoron_crate_large_open" + icon_closed = "phoron_crate_large" + +//fluff variant +/obj/structure/closet/crate/secure/large/reinforced + desc = "A hefty, reinforced metal crate with an electronic locking system." + icon_state = "largermetal" + icon_opened = "largermetalopen" + icon_closed = "largermetal" + +/obj/structure/closet/crate/hydroponics + name = "hydroponics crate" + desc = "All you need to destroy those pesky weeds and pests." + icon_state = "hydrocrate" + icon_opened = "hydrocrateopen" + icon_closed = "hydrocrate" + +/obj/structure/closet/crate/hydroponics/prespawned/WillContain() + return list( + /obj/item/weapon/reagent_containers/spray/plantbgone = 2, + /obj/item/weapon/material/minihoe = 2, + /obj/item/weapon/storage/plants = 2, + /obj/item/weapon/material/hatchet = 2, + /obj/item/weapon/wirecutters/clippers = 2, + /obj/item/device/analyzer/plant_analyzer = 2 + ) + +/obj/structure/closet/crate/secure/biohazard + name = "biohazard cart" + desc = "A heavy cart with extensive sealing. You shouldn't eat things you find in it." + icon_state = "biohazard" + icon_opened = "biohazardopen" + icon_closed = "biohazard" + open_sound = 'sound/items/Deconstruct.ogg' + close_sound = 'sound/items/Deconstruct.ogg' + req_access = list(access_xenobiology) + storage_types = CLOSET_STORAGE_ITEMS|CLOSET_STORAGE_MOBS + +/obj/structure/closet/crate/secure/biohazard/blanks/WillContain() + return list(/mob/living/carbon/human/blank, /obj/item/usedcryobag) + +/obj/structure/closet/crate/paper_refill + name = "paper refill crate" + desc = "A rectangular plastic crate, filled up with blank papers for refilling bins and printers. A bureaucrat's favorite." + icon_state = "plasticcrate" + icon_opened = "plasticcrateopen" + icon_closed = "plasticcrate" + +/obj/structure/closet/crate/paper_refill/WillContain() + return list(/obj/item/weapon/paper = 30) + +/obj/structure/closet/crate/uranium + name = "fissibles crate" + desc = "A crate with a radiation sign on it." + icon_state = "radiation" + icon_opened = "radiationopen" + icon_closed = "radiation" + +/obj/structure/closet/crate/uranium/WillContain() + return list(/obj/item/stack/material/uranium/ten = 5) \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/largecrate.dm b/code/game/objects/structures/crates_lockers/largecrate.dm new file mode 100644 index 00000000..759a8380 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/largecrate.dm @@ -0,0 +1,89 @@ +/obj/structure/largecrate + name = "large crate" + desc = "A hefty wooden crate." + icon = 'icons/obj/storage.dmi' + icon_state = "densecrate" + density = 1 + atom_flags = ATOM_FLAG_CLIMBABLE + +/obj/structure/largecrate/Initialize() + . = ..() + for(var/obj/I in src.loc) + if(I.density || I.anchored || I == src || !I.simulated) + continue + I.forceMove(src) + +/obj/structure/largecrate/attack_hand(mob/user as mob) + to_chat(user, "You need a crowbar to pry this open!") + return + +/obj/structure/largecrate/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isCrowbar(W)) + new /obj/item/stack/material/wood(src) + var/turf/T = get_turf(src) + for(var/atom/movable/AM in contents) + if(AM.simulated) AM.forceMove(T) + user.visible_message("[user] pries \the [src] open.", \ + "You pry open \the [src].", \ + "You hear splitting wood.") + qdel(src) + else + return attack_hand(user) + +/obj/structure/largecrate/mule + name = "MULE crate" + +/obj/structure/largecrate/hoverpod + name = "\improper Hoverpod assembly crate" + desc = "It comes in a box for the fabricator's sake. Where does the wood come from? ... And why is it lighter?" + icon_state = "mulecrate" + +/obj/structure/largecrate/hoverpod/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isCrowbar(W)) + var/obj/item/mecha_parts/mecha_equipment/ME + var/obj/mecha/working/hoverpod/H = new (loc) + + ME = new /obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp + ME.attach(H) + ME = new /obj/item/mecha_parts/mecha_equipment/tool/passenger + ME.attach(H) + ..() + +/obj/structure/largecrate/animal + icon_state = "mulecrate" + var/held_count = 1 + var/held_type + +/obj/structure/largecrate/animal/New() + ..() + if(held_type) + for(var/i = 1;i<=held_count;i++) + new held_type(src) + +/obj/structure/largecrate/animal/mulebot + name = "Mulebot crate" + held_type = /mob/living/bot/mulebot + +/obj/structure/largecrate/animal/corgi + name = "corgi carrier" + held_type = /mob/living/simple_animal/corgi + +/obj/structure/largecrate/animal/cow + name = "cow crate" + held_type = /mob/living/simple_animal/cow + +/obj/structure/largecrate/animal/goat + name = "goat crate" + held_type = /mob/living/simple_animal/hostile/retaliate/goat + +/obj/structure/largecrate/animal/cat + name = "cat carrier" + held_type = /mob/living/simple_animal/cat + +/obj/structure/largecrate/animal/cat/bones + held_type = /mob/living/simple_animal/cat/fluff/bones + +/obj/structure/largecrate/animal/chick + name = "chicken crate" + held_count = 5 + held_type = /mob/living/simple_animal/chick diff --git a/code/game/objects/structures/curtains.dm b/code/game/objects/structures/curtains.dm new file mode 100644 index 00000000..2b62a250 --- /dev/null +++ b/code/game/objects/structures/curtains.dm @@ -0,0 +1,67 @@ +/obj/structure/curtain + name = "curtain" + icon = 'icons/obj/curtain.dmi' + icon_state = "closed" + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + anchored = TRUE + opacity = 1 + density = 0 + +/obj/structure/curtain/open + icon_state = "open" + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + opacity = 0 + +/obj/structure/curtain/bullet_act(obj/item/projectile/P, def_zone) + if(!P.nodamage) + visible_message("[P] tears [src] down!") + qdel(src) + else + ..(P, def_zone) + +/obj/structure/curtain/attack_hand(mob/user) + playsound(get_turf(loc), "rustle", 15, 1, -5) + toggle() + ..() + +/obj/structure/curtain/proc/toggle() + set_opacity(!opacity) + if(opacity) + icon_state = "closed" + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_WINDOW_LAYER + else + icon_state = "open" + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + +/obj/structure/curtain/black + name = "black curtain" + color = "#222222" + +/obj/structure/curtain/medical + name = "plastic curtain" + color = "#b8f5e3" + alpha = 200 + +/obj/structure/curtain/open/bed + name = "bed curtain" + color = "#854636" + +/obj/structure/curtain/open/privacy + name = "privacy curtain" + color = "#b8f5e3" + +/obj/structure/curtain/open/shower + name = "shower curtain" + color = "#acd1e9" + alpha = 200 + +/obj/structure/curtain/open/shower/engineering + color = "#ffa500" + +/obj/structure/curtain/open/shower/security + color = "#aa0000" + diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm new file mode 100644 index 00000000..096b09de --- /dev/null +++ b/code/game/objects/structures/displaycase.dm @@ -0,0 +1,79 @@ +/obj/structure/displaycase + name = "display case" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "glassbox1" + desc = "A display case for prized possessions. It taunts you to kick it." + density = 1 + anchored = 1 + unacidable = 1//Dissolving the case would also delete the gun. + var/health = 30 + var/occupied = 1 + var/destroyed = 0 + +/obj/structure/displaycase/ex_act(severity) + switch(severity) + if (1) + new /obj/item/weapon/material/shard( src.loc ) + if (occupied) + new /obj/item/weapon/gun/energy/captain( src.loc ) + occupied = 0 + qdel(src) + if (2) + if (prob(50)) + src.health -= 15 + src.healthcheck() + if (3) + if (prob(50)) + src.health -= 5 + src.healthcheck() + + +/obj/structure/displaycase/bullet_act(var/obj/item/projectile/Proj) + health -= Proj.get_structure_damage() + ..() + src.healthcheck() + return + +/obj/structure/displaycase/proc/healthcheck() + if (src.health <= 0) + if (!( src.destroyed )) + src.set_density(0) + src.destroyed = 1 + new /obj/item/weapon/material/shard( src.loc ) + playsound(src, "shatter", 70, 1) + update_icon() + else + playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) + return + +/obj/structure/displaycase/update_icon() + if(src.destroyed) + src.icon_state = "glassboxb[src.occupied]" + else + src.icon_state = "glassbox[src.occupied]" + return + + +/obj/structure/displaycase/attackby(obj/item/weapon/W as obj, mob/user as mob) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + src.health -= W.force + src.healthcheck() + ..() + return + +/obj/structure/displaycase/attack_hand(mob/user as mob) + if (src.destroyed && src.occupied) + new /obj/item/weapon/gun/energy/captain( src.loc ) + to_chat(user, "You deactivate the hover field built into the case.") + src.occupied = 0 + src.add_fingerprint(user) + update_icon() + return + else + to_chat(usr, text("You kick the display case.")) + for(var/mob/O in oviewers()) + if ((O.client && !( O.blinded ))) + to_chat(O, "[usr] kicks the display case.") + src.health -= 2 + healthcheck() + return diff --git a/code/game/objects/structures/dogbed.dm b/code/game/objects/structures/dogbed.dm new file mode 100644 index 00000000..803746b9 --- /dev/null +++ b/code/game/objects/structures/dogbed.dm @@ -0,0 +1,8 @@ +/obj/structure/dogbed + name = "dogbed" + desc = "A bed made especially for dogs, or other similarly sized pets." + icon = 'icons/obj/furniture.dmi' + icon_state = "dogbed" + can_buckle = 1 + buckle_dir = SOUTH + buckle_lying = 1 \ No newline at end of file diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm new file mode 100644 index 00000000..3190e281 --- /dev/null +++ b/code/game/objects/structures/door_assembly.dm @@ -0,0 +1,363 @@ +/obj/structure/door_assembly + name = "airlock assembly" + icon = 'icons/obj/doors/door_assembly.dmi' + icon_state = "door_as_0" + anchored = 0 + density = 1 + w_class = ITEM_SIZE_NO_CONTAINER + var/state = 0 + var/base_icon_state = "" + var/base_name = "Airlock" + var/obj/item/weapon/airlock_electronics/electronics = null + var/airlock_type = "" //the type path of the airlock once completed + var/glass_type = "/glass" + var/glass = 0 // 0 = glass can be installed. -1 = glass can't be installed. 1 = glass is already installed. Text = mineral plating is installed instead. + var/created_name = null + + New() + update_state() + +/obj/structure/door_assembly/door_assembly_com + base_icon_state = "com" + base_name = "Command Airlock" + glass_type = "/glass_command" + airlock_type = "/command" + +/obj/structure/door_assembly/door_assembly_black + base_icon_state = "black" + base_name = "Black Airlock" + glass_type = "/glass_black" + airlock_type = "/black" + +/obj/structure/door_assembly/door_assembly_hyd + base_icon_state = "hyd" + base_name = "Hydroponics Airlock" + glass_type = "/glass_hydroponics" + airlock_type = "/hydroponics" + +/obj/structure/door_assembly/door_assembly_chem + base_icon_state = "chem" + base_name = "Chemistry Airlock" + glass_type = "/glass_chemistry" + airlock_type = "/chemistry" + +/obj/structure/door_assembly/door_assembly_arbiter + base_icon_state = "coma" + base_name = "Arbiter Airlock" + glass_type = "/glass_arbiter" + airlock_type = "/arbiter" + +/obj/structure/door_assembly/door_assembly_cone + base_icon_state = "cone" + base_name = "Cone Airlock" + glass_type = "/glass_cone" + airlock_type = "/cone" + +/obj/structure/door_assembly/door_assembly_weap + base_icon_state = "weap" + base_name = "Weapon Airlock" + glass_type = "/glass_weap" + airlock_type = "/weap" + +/obj/structure/door_assembly/door_assembly_sec + base_icon_state = "sec" + base_name = "Security Airlock" + glass_type = "/glass_security" + airlock_type = "/security" + +/obj/structure/door_assembly/door_assembly_eng + base_icon_state = "eng" + base_name = "Engineering Airlock" + glass_type = "/glass_engineering" + airlock_type = "/engineering" + +/obj/structure/door_assembly/door_assembly_min + base_icon_state = "min" + base_name = "Mining Airlock" + glass_type = "/glass_mining" + airlock_type = "/mining" + +/obj/structure/door_assembly/door_assembly_atmo + base_icon_state = "atmo" + base_name = "Atmospherics Airlock" + glass_type = "/glass_atmos" + airlock_type = "/atmos" + +/obj/structure/door_assembly/door_assembly_research + base_icon_state = "res" + base_name = "Research Airlock" + glass_type = "/glass_research" + airlock_type = "/research" + +/obj/structure/door_assembly/door_assembly_red + base_icon_state = "red" + base_name = "Red Airlock" + glass_type = "/glass_red" + airlock_type = "/red" + +/obj/structure/door_assembly/door_assembly_science + base_icon_state = "sci" + base_name = "Science Airlock" + glass_type = "/glass_science" + airlock_type = "/science" + +/obj/structure/door_assembly/door_assembly_med + base_icon_state = "med" + base_name = "Medical Airlock" + glass_type = "/glass_medical" + airlock_type = "/medical" + +/obj/structure/door_assembly/door_assembly_viro + base_icon_state = "viro" + base_name = "Virology Airlock" + glass_type = "/glass_virology" + airlock_type = "/virology" + +/obj/structure/door_assembly/door_assembly_sol + base_icon_state = "sol" + base_name = "Sol Central Government Airlock" + glass_type = "/glass_sol" + airlock_type = "/sol" + +/obj/structure/door_assembly/door_assembly_ext + base_icon_state = "ext" + base_name = "External Airlock" + glass_type = "/glass_external" + airlock_type = "/external" + +/obj/structure/door_assembly/door_assembly_mai + base_icon_state = "mai" + base_name = "Maintenance Airlock" + airlock_type = "/maintenance" + glass = -1 + +/obj/structure/door_assembly/door_assembly_fre + base_icon_state = "fre" + base_name = "Freezer Airlock" + airlock_type = "/freezer" + glass = -1 + +/obj/structure/door_assembly/door_assembly_hatch + base_icon_state = "hatch" + base_name = "Airtight Hatch" + airlock_type = "/hatch" + glass = -1 + +/obj/structure/door_assembly/door_assembly_mhatch + base_icon_state = "mhatch" + base_name = "Maintenance Hatch" + airlock_type = "/maintenance_hatch" + glass = -1 + +/obj/structure/door_assembly/door_assembly_shatch + base_icon_state = "shatch" + base_name = "Security Hatch" + airlock_type = "/security_hatch" + glass = -1 + +/obj/structure/door_assembly/door_assembly_force + base_icon_state = "force" + base_name = "Force Hatch" + airlock_type = "/force_hatch" + +/obj/structure/door_assembly/door_assembly_highsecurity // Borrowing this until WJohnston makes sprites for the assembly + base_icon_state = "highsec" + base_name = "High Security Airlock" + airlock_type = "/highsecurity" + glass = -1 + +/obj/structure/door_assembly/multi_tile + icon = 'icons/obj/doors/door_assembly2x1.dmi' + dir = EAST + var/width = 1 + +/*Temporary until we get sprites. + glass_type = "/multi_tile/glass" + airlock_type = "/multi_tile/maint" + glass = 1*/ + base_icon_state = "g" //Remember to delete this line when reverting "glass" var to 1. + airlock_type = "/multi_tile/glass" + glass = -1 //To prevent bugs in deconstruction process. + + New() + if(dir in list(EAST, WEST)) + bound_width = width * world.icon_size + bound_height = world.icon_size + else + bound_width = world.icon_size + bound_height = width * world.icon_size + update_state() + + Move() + . = ..() + if(dir in list(EAST, WEST)) + bound_width = width * world.icon_size + bound_height = world.icon_size + else + bound_width = world.icon_size + bound_height = width * world.icon_size + +/obj/structure/door_assembly/multi_tile/maintenance + dir = EAST + +/obj/structure/door_assembly/attackby(obj/item/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/pen)) + var/t = sanitizeSafe(input(user, "Enter the name for the door.", src.name, src.created_name), MAX_NAME_LEN) + if(!t) return + if(!in_range(src, usr) && src.loc != usr) return + created_name = t + return + + if(isWelder(W) && ( (istext(glass)) || (glass == 1) || (!anchored) )) + var/obj/item/weapon/weldingtool/WT = W + if (WT.remove_fuel(0, user)) + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + if(istext(glass)) + user.visible_message("[user] welds the [glass] plating off the airlock assembly.", "You start to weld the [glass] plating off the airlock assembly.") + if(do_after(user, 40,src)) + if(!src || !WT.isOn()) return + to_chat(user, "You welded the [glass] plating off!") + var/M = text2path("/obj/item/stack/material/[glass]") + new M(src.loc, 2) + glass = 0 + else if(glass == 1) + user.visible_message("[user] welds the glass panel out of the airlock assembly.", "You start to weld the glass panel out of the airlock assembly.") + if(do_after(user, 40,src)) + if(!src || !WT.isOn()) return + to_chat(user, "You welded the glass panel out!") + new /obj/item/stack/material/glass/reinforced(src.loc) + glass = 0 + else if(!anchored) + user.visible_message("[user] dissassembles the airlock assembly.", "You start to dissassemble the airlock assembly.") + if(do_after(user, 40,src)) + if(!src || !WT.isOn()) return + to_chat(user, "You dissasembled the airlock assembly!") + new /obj/item/stack/material/steel(src.loc, 4) + qdel (src) + else + to_chat(user, "You need more welding fuel.") + return + + else if(isWrench(W) && state == 0) + playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + if(anchored) + user.visible_message("[user] begins unsecuring the airlock assembly from the floor.", "You starts unsecuring the airlock assembly from the floor.") + else + user.visible_message("[user] begins securing the airlock assembly to the floor.", "You starts securing the airlock assembly to the floor.") + + if(do_after(user, 40,src)) + if(!src) return + to_chat(user, "You [anchored? "un" : ""]secured the airlock assembly!") + anchored = !anchored + + else if(isCoil(W) && state == 0 && anchored) + var/obj/item/stack/cable_coil/C = W + if (C.get_amount() < 1) + to_chat(user, "You need one length of coil to wire the airlock assembly.") + return + user.visible_message("[user] wires the airlock assembly.", "You start to wire the airlock assembly.") + if(do_after(user, 40,src) && state == 0 && anchored) + if (C.use(1)) + src.state = 1 + to_chat(user, "You wire the airlock.") + + else if(isWirecutter(W) && state == 1 ) + playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) + user.visible_message("[user] cuts the wires from the airlock assembly.", "You start to cut the wires from airlock assembly.") + + if(do_after(user, 40,src)) + if(!src) return + to_chat(user, "You cut the airlock wires.!") + new/obj/item/stack/cable_coil(src.loc, 1) + src.state = 0 + + else if(istype(W, /obj/item/weapon/airlock_electronics) && state == 1) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) + user.visible_message("[user] installs the electronics into the airlock assembly.", "You start to install electronics into the airlock assembly.") + + if(do_after(user, 40,src)) + if(!src) return + user.drop_item() + W.loc = src + to_chat(user, "You installed the airlock electronics!") + src.state = 2 + src.SetName("Near finished Airlock Assembly") + src.electronics = W + + else if(isCrowbar(W) && state == 2 ) + //This should never happen, but just in case I guess + if (!electronics) + to_chat(user, "There was nothing to remove.") + src.state = 1 + return + + playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) + user.visible_message("\The [user] starts removing the electronics from the airlock assembly.", "You start removing the electronics from the airlock assembly.") + + if(do_after(user, 40,src)) + if(!src) return + to_chat(user, "You removed the airlock electronics!") + src.state = 1 + src.SetName("Wired Airlock Assembly") + electronics.loc = src.loc + electronics = null + + else if(istype(W, /obj/item/stack/material) && !glass) + var/obj/item/stack/S = W + var/material_name = S.get_material_name() + if (S) + if (S.get_amount() >= 1) + if(material_name == "rglass") + playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) + user.visible_message("[user] adds [S.name] to the airlock assembly.", "You start to install [S.name] into the airlock assembly.") + if(do_after(user, 40,src) && !glass) + if (S.use(1)) + to_chat(user, "You installed reinforced glass windows into the airlock assembly.") + glass = 1 + else if(material_name) + // Ugly hack, will suffice for now. Need to fix it upstream as well, may rewrite mineral walls. ~Z + if(!(material_name in list("gold", "silver", "diamond", "uranium", "phoron", "sandstone"))) + to_chat(user, "You cannot make an airlock out of that material.") + return + if(S.get_amount() >= 2) + playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) + user.visible_message("[user] adds [S.name] to the airlock assembly.", "You start to install [S.name] into the airlock assembly.") + if(do_after(user, 40,src) && !glass) + if (S.use(2)) + to_chat(user, "You installed [material_display_name(material_name)] plating into the airlock assembly.") + glass = material_name + + else if(isScrewdriver(W) && state == 2 ) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) + to_chat(user, "Now finishing the airlock.") + + if(do_after(user, 40,src)) + if(!src) return + to_chat(user, "You finish the airlock!") + var/path + if(istext(glass)) + path = text2path("/obj/machinery/door/airlock/[glass]") + else if (glass == 1) + path = text2path("/obj/machinery/door/airlock[glass_type]") + else + path = text2path("/obj/machinery/door/airlock[airlock_type]") + + new path(src.loc, src) + qdel(src) + else + ..() + update_state() + +/obj/structure/door_assembly/proc/update_state() + icon_state = "door_as_[glass == 1 ? "g" : ""][istext(glass) ? glass : base_icon_state][state]" + var/final_name = "" + switch (state) + if(0) + if (anchored) + final_name = "Secured " + if(1) + final_name = "Wired " + if(2) + final_name = "Near Finished " + final_name += "[glass == 1 ? "Window " : ""][istext(glass) ? "[glass] Airlock" : base_name] Assembly" + SetName(final_name) diff --git a/code/game/objects/structures/electricchair.dm b/code/game/objects/structures/electricchair.dm new file mode 100644 index 00000000..9bb50d14 --- /dev/null +++ b/code/game/objects/structures/electricchair.dm @@ -0,0 +1,80 @@ +/obj/structure/bed/chair/e_chair + name = "electric chair" + desc = "Looks absolutely SHOCKING!" + icon_state = "echair0" + var/on = 0 + var/obj/item/assembly/shock_kit/part = null + var/last_time = 1.0 + +/obj/structure/bed/chair/e_chair/New() + ..() + overlays += image('icons/obj/objects.dmi', src, "echair_over", BASE_MOB_LAYER + 1, dir) + return + +/obj/structure/bed/chair/e_chair/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWrench(W)) + var/obj/structure/bed/chair/C = new /obj/structure/bed/chair(loc) + playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) + C.set_dir(dir) + part.loc = loc + part.master = null + part = null + qdel(src) + return + return + +/obj/structure/bed/chair/e_chair/proc/toggle() + set name = "Toggle Electric Chair" + set category = "Object" + + if(on) + on = 0 + icon_state = "echair0" + else + on = 1 + icon_state = "echair1" + to_chat(usr, "You switch [on ? "on" : "off"] [src].") + return + +/obj/structure/bed/chair/e_chair/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + toggle() + +/obj/structure/bed/chair/e_chair/rotate() + ..() + overlays.Cut() + overlays += image('icons/obj/objects.dmi', src, "echair_over", BASE_MOB_LAYER + 1, dir) //there's probably a better way of handling this, but eh. -Pete + return + +/obj/structure/bed/chair/e_chair/proc/shock() + if(!on) + return + if(last_time + 50 > world.time) + return + last_time = world.time + + // special power handling + var/area/A = get_area(src) + if(!isarea(A)) + return + if(!A.powered(EQUIP)) + return + A.use_power(EQUIP, 5000) + var/light = A.power_light + A.update_icon() + + flick("echair1", src) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(12, 1, src) + s.start() + if(buckled_mob) + buckled_mob.burn_skin(85) + to_chat(buckled_mob, "You feel a deep shock course through your body!") + sleep(1) + buckled_mob.burn_skin(85) + buckled_mob.Stun(600) + visible_message("The electric chair went off!", "You hear a deep sharp shock!") + + A.power_light = light + A.update_icon() + return diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm new file mode 100644 index 00000000..9c6b05cf --- /dev/null +++ b/code/game/objects/structures/extinguisher.dm @@ -0,0 +1,79 @@ +/obj/structure/extinguisher_cabinet + name = "extinguisher cabinet" + desc = "A small wall mounted cabinet designed to hold a fire extinguisher." + icon = 'icons/obj/closet.dmi' + icon_state = "extinguisher_closed" + anchored = 1 + density = 0 + var/obj/item/weapon/extinguisher/has_extinguisher + var/opened = 0 + +/obj/structure/extinguisher_cabinet/New() + ..() + has_extinguisher = new/obj/item/weapon/extinguisher(src) + +/obj/structure/extinguisher_cabinet/attackby(obj/item/O, mob/user) + if(isrobot(user)) + return + if(istype(O, /obj/item/weapon/extinguisher)) + if(!has_extinguisher && opened) + user.remove_from_mob(O) + contents += O + has_extinguisher = O + to_chat(user, "You place [O] in [src].") + playsound(src.loc, 'sound/effects/extin.ogg', 50, 0) + else + opened = !opened + else + opened = !opened + update_icon() + + +/obj/structure/extinguisher_cabinet/attack_hand(mob/user) + if(isrobot(user)) + return + if (ishuman(user)) + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/temp = H.organs_by_name[BP_R_HAND] + if (user.hand) + temp = H.organs_by_name[BP_L_HAND] + if(temp && !temp.is_usable()) + to_chat(user, "You try to move your [temp.name], but cannot!") + return + if(has_extinguisher) + user.put_in_hands(has_extinguisher) + to_chat(user, "You take [has_extinguisher] from [src].") + playsound(src.loc, 'sound/effects/extout.ogg', 50, 0) + has_extinguisher = null + opened = 1 + else + opened = !opened + update_icon() + +/obj/structure/extinguisher_cabinet/attack_tk(mob/user) + if(has_extinguisher) + has_extinguisher.loc = loc + to_chat(user, "You telekinetically remove [has_extinguisher] from [src].") + has_extinguisher = null + opened = 1 + else + opened = !opened + update_icon() + +/obj/structure/extinguisher_cabinet/update_icon() + if(!opened) + icon_state = "extinguisher_closed" + return + if(has_extinguisher) + if(istype(has_extinguisher, /obj/item/weapon/extinguisher/mini)) + icon_state = "extinguisher_mini" + else + icon_state = "extinguisher_full" + else + icon_state = "extinguisher_empty" + +/obj/structure/extinguisher_cabinet/AltClick(var/mob/user) + if(CanPhysicallyInteract(user)) + opened = !opened + update_icon() + diff --git a/code/game/objects/structures/fireaxe_cabinet.dm b/code/game/objects/structures/fireaxe_cabinet.dm new file mode 100644 index 00000000..f4f2e8a6 --- /dev/null +++ b/code/game/objects/structures/fireaxe_cabinet.dm @@ -0,0 +1,135 @@ +/obj/structure/fireaxecabinet + name = "fire axe cabinet" + desc = "There is small label that reads \"For Emergency use only\" along with details for safe use of the axe. As if." + icon_state = "fireaxe" + anchored = 1 + density = 0 + + var/damage_threshold = 15 + var/open + var/unlocked + var/shattered + var/obj/item/weapon/material/twohanded/fireaxe/fireaxe + +/obj/structure/fireaxecabinet/attack_generic(var/mob/user, var/damage, var/attack_verb, var/wallbreaker) + attack_animation(user) + playsound(user, 'sound/effects/Glasshit.ogg', 50, 1) + visible_message("[user] [attack_verb] \the [src]!") + if(damage_threshold > damage) + to_chat(user, "Your strike is deflected by the reinforced glass!") + return + if(shattered) + return + shattered = 1 + unlocked = 1 + open = 1 + playsound(user, 'sound/effects/Glassbr3.ogg', 100, 1) + update_icon() + +/obj/structure/fireaxecabinet/update_icon() + overlays.Cut() + if(fireaxe) + overlays += image(icon, "fireaxe_item") + if(shattered) + overlays += image(icon, "fireaxe_window_broken") + else if(!open) + overlays += image(icon, "fireaxe_window") + +/obj/structure/fireaxecabinet/New() + ..() + fireaxe = new(src) + update_icon() + +/obj/structure/fireaxecabinet/attack_ai(var/mob/user) + toggle_lock(user) + +/obj/structure/fireaxecabinet/attack_hand(var/mob/user) + if(!unlocked) + to_chat(user, "\The [src] is locked.") + return + toggle_open(user) + +/obj/structure/fireaxecabinet/MouseDrop(over_object, src_location, over_location) + if(over_object == usr) + var/mob/user = over_object + if(!istype(user)) + return + + if(!open) + to_chat(user, "\The [src] is closed.") + return + + if(!fireaxe) + to_chat(user, "\The [src] is empty.") + return + + fireaxe.forceMove(get_turf(user)) + user.put_in_hands(fireaxe) + fireaxe = null + update_icon() + + return + +/obj/structure/fireaxecabinet/Destroy() + if(fireaxe) + fireaxe.forceMove(get_turf(src)) + fireaxe = null + return ..() + +/obj/structure/fireaxecabinet/attackby(var/obj/item/O, var/mob/user) + + if(isMultitool(O)) + toggle_lock(user) + return + + if(istype(O, /obj/item/weapon/material/twohanded/fireaxe)) + if(open) + if(fireaxe) + to_chat(user, "There is already \a [fireaxe] inside \the [src].") + else if(user.unEquip(O)) + O.forceMove(src) + fireaxe = O + to_chat(user, "You place \the [fireaxe] into \the [src].") + update_icon() + return + + if(O.force) + user.setClickCooldown(10) + attack_generic(user, O.force, "bashes") + return + + return ..() + +/obj/structure/fireaxecabinet/proc/toggle_open(var/mob/user) + if(shattered) + open = 1 + unlocked = 1 + else + user.setClickCooldown(10) + open = !open + to_chat(user, "You [open ? "open" : "close"] \the [src].") + update_icon() + +/obj/structure/fireaxecabinet/proc/toggle_lock(var/mob/user) + + + if(open) + return + + if(shattered) + open = 1 + unlocked = 1 + else + user.setClickCooldown(10) + to_chat(user, "You begin [unlocked ? "enabling" : "disabling"] \the [src]'s maglock.") + + if(!do_after(user, 20,src)) + return + + if(shattered) return + + unlocked = !unlocked + playsound(user, 'sound/machines/lockreset.ogg', 50, 1) + to_chat(user, "You [unlocked ? "disable" : "enable"] the maglock.") + + update_icon() diff --git a/code/game/objects/structures/fitness.dm b/code/game/objects/structures/fitness.dm new file mode 100644 index 00000000..2406d676 --- /dev/null +++ b/code/game/objects/structures/fitness.dm @@ -0,0 +1,64 @@ +/obj/structure/fitness + icon = 'icons/obj/stationobjs.dmi' + anchored = 1 + var/being_used = 0 + +/obj/structure/fitness/punchingbag + name = "punching bag" + desc = "A punching bag." + icon_state = "punchingbag" + density = 1 + var/list/hit_message = list("hit", "punch", "kick", "robust") + +/obj/structure/fitness/punchingbag/attack_hand(var/mob/living/carbon/human/user) + if(!istype(user)) + ..() + return + if(user.nutrition < 20) + to_chat(user, "You need more energy to use the punching bag. Go eat something.") + else + if(user.a_intent == I_HURT) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + flick("[icon_state]_hit", src) + playsound(src.loc, 'sound/effects/woodhit.ogg', 25, 1, -1) + user.nutrition = user.nutrition - 5 + to_chat(user, "You [pick(hit_message)] \the [src].") + +/obj/structure/fitness/weightlifter + name = "weightlifting machine" + desc = "A machine used to lift weights." + icon_state = "weightlifter" + var/weights = 1 + var/list/qualifiers = list("with ease", "without any trouble", "with great effort") + +/obj/structure/fitness/weightlifter/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWrench(W)) + playsound(src.loc, 'sound/items/Deconstruct.ogg', 75, 1) + weights = ((weights) % qualifiers.len) + 1 + to_chat(user, "You set the machine's weight level to [weight].") + +/obj/structure/fitness/weightlifter/attack_hand(var/mob/living/carbon/human/user) + if(!istype(user)) + return + if(user.loc != src.loc) + to_chat(user, "You must be on the weight machine to use it.") + return + if(user.nutrition < 50) + to_chat(user, "You need more energy to lift weights. Go eat something.") + return + if(being_used) + to_chat(user, "The weight machine is already in use by somebody else.") + return + else + being_used = 1 + playsound(src.loc, 'sound/effects/weightlifter.ogg', 50, 1) + user.set_dir(SOUTH) + flick("[icon_state]_[weight]", src) + if(do_after(user, 20 + (weights * 10))) + playsound(src.loc, 'sound/effects/weightdrop.ogg', 25, 1) + user.nutrition -= weights * 10 + to_chat(user, "You lift the weights [qualifiers[weight]].") + being_used = 0 + else + to_chat(user, "Against your previous judgement, perhaps working out is not for you.") + being_used = 0 diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm new file mode 100644 index 00000000..8302ed6d --- /dev/null +++ b/code/game/objects/structures/flora.dm @@ -0,0 +1,439 @@ +//trees +/obj/structure/flora/tree + name = "tree" + anchored = 1 + density = 1 + pixel_x = -16 + alpha = 200 + density = FALSE + mouse_opacity = 0 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + +/obj/structure/flora/tree/pine + name = "pine tree" + icon = 'icons/obj/flora/pinetrees.dmi' + icon_state = "pine_1" + +/obj/structure/flora/tree/pine/New() + ..() + icon_state = "pine_[rand(1, 3)]" + +/obj/structure/flora/tree/pine/xmas + name = "xmas tree" + icon = 'icons/obj/flora/pinetrees.dmi' + icon_state = "pine_c" + +/obj/structure/flora/tree/pine/xmas/New() + ..() + icon_state = "pine_c" + +/obj/structure/flora/tree/dead + icon = 'icons/obj/flora/164tree.dmi' + icon_state = "vhdtree152" + +/obj/structure/flora/tree/dead/New() + ..() + icon_state = pick("vhdtree152", "hdtree96") + + +//grass +/obj/structure/flora/grass + name = "grass" + icon = 'icons/obj/flora/snowflora.dmi' + anchored = 1 + +/obj/structure/flora/grass/attackby(obj/item/O, mob/user) + . = ..() + if(istype(O)) + if(O.sharp || O.edge) + playsound(src, 'sound/effects/ash_chop.ogg', 50, TRUE) + user.visible_message("[user] begins to cut away [src].") + if(do_after(user,20)) + if(src) + playsound(src, 'sound/effects/ash_cut.ogg', 50, TRUE) + user.visible_message("[user] finishes cutting away [src].") + qdel(src) + + else + user.visible_message("[user] stops cutting away [src].") + +/obj/structure/flora/grass/Crossed(AM as mob) + ..() + if(istype(AM, /mob/living/carbon) && prob(75)) + playsound(src, "foliage", 60, 1) + +/obj/structure/flora/grass/brown + icon_state = "snowgrass1bb" + +/obj/structure/flora/grass/brown/New() + ..() + icon_state = "snowgrass[rand(1, 3)]bb" + + +/obj/structure/flora/grass/green + icon_state = "snowgrass1gb" + +/obj/structure/flora/grass/green/New() + ..() + icon_state = "snowgrass[rand(1, 3)]gb" + +/obj/structure/flora/grass/both + icon_state = "snowgrassall1" + +/obj/structure/flora/grass/both/New() + ..() + icon_state = "snowgrassall[rand(1, 3)]" + + +//bushes +/obj/structure/flora/bush + name = "bush" + icon = 'icons/obj/flora/snowflora.dmi' + icon_state = "snowbush1" + anchored = 1 + +/obj/structure/flora/bush/New() + ..() + icon_state = "snowbush[rand(1, 6)]" + +/obj/structure/flora/pottedplant + name = "potted plant" + icon = 'icons/obj/plants.dmi' + icon_state = "plant-26" + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + +//newbushes + +/obj/structure/flora/ausbushes + name = "bush" + icon = 'icons/obj/flora/ausflora.dmi' + icon_state = "firstbush_1" + anchored = 1 + +/obj/structure/flora/ausbushes/New() + ..() + icon_state = "firstbush_[rand(1, 4)]" + +/obj/structure/flora/ausbushes/reedbush + icon_state = "reedbush_1" + +/obj/structure/flora/ausbushes/reedbush/New() + ..() + icon_state = "reedbush_[rand(1, 4)]" + +/obj/structure/flora/ausbushes/leafybush + icon_state = "leafybush_1" + +/obj/structure/flora/ausbushes/leafybush/New() + ..() + icon_state = "leafybush_[rand(1, 3)]" + +/obj/structure/flora/ausbushes/palebush + icon_state = "palebush_1" + +/obj/structure/flora/ausbushes/palebush/New() + ..() + icon_state = "palebush_[rand(1, 4)]" + +/obj/structure/flora/ausbushes/stalkybush + icon_state = "stalkybush_1" + +/obj/structure/flora/ausbushes/stalkybush/New() + ..() + icon_state = "stalkybush_[rand(1, 3)]" + +/obj/structure/flora/ausbushes/grassybush + icon_state = "grassybush_1" + +/obj/structure/flora/ausbushes/grassybush/New() + ..() + icon_state = "grassybush_[rand(1, 4)]" + +/obj/structure/flora/ausbushes/fernybush + icon_state = "fernybush_1" + +/obj/structure/flora/ausbushes/fernybush/New() + ..() + icon_state = "fernybush_[rand(1, 3)]" + +/obj/structure/flora/ausbushes/sunnybush + icon_state = "sunnybush_1" + +/obj/structure/flora/ausbushes/sunnybush/New() + ..() + icon_state = "sunnybush_[rand(1, 3)]" + +/obj/structure/flora/ausbushes/genericbush + icon_state = "genericbush_1" + +/obj/structure/flora/ausbushes/genericbush/New() + ..() + icon_state = "genericbush_[rand(1, 4)]" + +/obj/structure/flora/ausbushes/pointybush + icon_state = "pointybush_1" + +/obj/structure/flora/ausbushes/pointybush/New() + ..() + icon_state = "pointybush_[rand(1, 4)]" + +/obj/structure/flora/ausbushes/lavendergrass + icon_state = "lavendergrass_1" + +/obj/structure/flora/ausbushes/lavendergrass/New() + ..() + icon_state = "lavendergrass_[rand(1, 4)]" + +/obj/structure/flora/ausbushes/ywflowers + icon_state = "ywflowers_1" + +/obj/structure/flora/ausbushes/ywflowers/New() + ..() + icon_state = "ywflowers_[rand(1, 3)]" + +/obj/structure/flora/ausbushes/brflowers + icon_state = "brflowers_1" + +/obj/structure/flora/ausbushes/brflowers/New() + ..() + icon_state = "brflowers_[rand(1, 3)]" + +/obj/structure/flora/ausbushes/ppflowers + icon_state = "ppflowers_1" + +/obj/structure/flora/ausbushes/ppflowers/New() + ..() + icon_state = "ppflowers_[rand(1, 4)]" + +/obj/structure/flora/ausbushes/sparsegrass + icon_state = "sparsegrass_1" + +/obj/structure/flora/ausbushes/sparsegrass/New() + ..() + icon_state = "sparsegrass_[rand(1, 3)]" + +/obj/structure/flora/ausbushes/fullgrass + icon_state = "fullgrass_1" + +/obj/structure/flora/ausbushes/fullgrass/New() + ..() + icon_state = "fullgrass_[rand(1, 3)]" + +/obj/structure/flora/ash + name = "ashroom" + icon = 'icons/obj/flora/ash_flora.dmi' + anchored = TRUE + +/obj/structure/flora/ash/New() + ..() + icon_state = "[pick("l", "s", "t")]_mushroom[rand(1, 4)]" + +/obj/structure/flora/ash/attackby(obj/item/O, mob/user) + . = ..() + if(istype(O)) + if(O.sharp || O.edge) + playsound(src, 'sound/effects/ash_chop.ogg', 50, TRUE) + user.visible_message("[user] begins to cut away [src].") + if(do_after(user,20)) + if(src) + playsound(src, 'sound/effects/ash_cut.ogg', 50, TRUE) + user.visible_message("[user] finishes cutting away [src].") + qdel(src) + + else + user.visible_message("[user] stops cutting away [src].") + + +/obj/structure/flora/ash/mushrooms + name = "mushroom" + icon = 'icons/obj/flora/plants.dmi' + desc = "It's unlikely these would taste good." + +/obj/structure/flora/ash/mushrooms/New() + ..() + icon_state = pick("chanterelle", "dark_root", "greencap_01", "greencap_02", "greencap_03", "redonion", "bluespike", "lungshroom", "venus") + +/obj/structure/flora/jungle + anchored = TRUE + plane = EFFECTS_BELOW_LIGHTING_PLANE + mouse_opacity = 0 + + New() + ..() + set_light(3, 3, "#28284f") + +/obj/structure/flora/jungle/trees + name = "jungle tree" + icon = 'icons/obj/flora/jungletrees.dmi' + icon_state = "tree1" + desc = "A big hunk of wood that gets in the way of you, and who you're trying to shoot." + +/obj/structure/flora/jungle/trees/New() + ..() + icon_state = "tree[rand(1,7)]" + + +/obj/structure/flora/jungle/bushes + name = "flora" + icon = 'icons/obj/flora/largejungleflora.dmi' + icon_state = "tree1" + desc = "Pretty scenary. Soothes the mind of the bloodshed." + +/obj/structure/flora/jungle/bushes/New() + ..() + icon_state = "bush[rand(1,4)]" + + +/obj/structure/flora/rocks + name = "rocks" + icon = 'icons/obj/flora/rocks.dmi' + anchored = TRUE + +/obj/structure/flora/rocks/New() + ..() + icon_state = "rubble[pick(1,10)]" + + +//potted plants credit: Flashkirby +/obj/structure/flora/pottedplant + name = "potted plant" + desc = "Really brings the room together." + icon = 'icons/obj/plants.dmi' + icon_state = "plant-01" + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + +/obj/structure/flora/pottedplant/large + name = "large potted plant" + desc = "This is a large plant. Three branches support pairs of waxy leaves." + icon_state = "plant-26" + +/obj/structure/flora/pottedplant/fern + name = "potted fern" + desc = "This is an ordinary looking fern. It looks like it could do with some water." + icon_state = "plant-02" + +/obj/structure/flora/pottedplant/overgrown + name = "overgrown potted plants" + desc = "This is an assortment of colourful plants. Some parts are overgrown." + icon_state = "plant-03" + +/obj/structure/flora/pottedplant/bamboo + name = "potted bamboo" + desc = "These are bamboo shoots. The tops looks like they've been cut short." + icon_state = "plant-04" + +/obj/structure/flora/pottedplant/largebush + name = "large potted bush" + desc = "This is a large bush. The leaves stick upwards in an odd fashion." + icon_state = "plant-05" + +/obj/structure/flora/pottedplant/thinbush + name = "thin potted bush" + desc = "This is a thin bush. It appears to be flowering." + icon_state = "plant-06" + +/obj/structure/flora/pottedplant/mysterious + name = "mysterious potted bulbs" + desc = "This is a mysterious looking plant. Touching the bulbs cause them to shrink." + icon_state = "plant-07" + +/obj/structure/flora/pottedplant/smalltree + name = "small potted tree" + desc = "This is a small tree. It is rather pleasant." + icon_state = "plant-08" + +/obj/structure/flora/pottedplant/unusual + name = "unusual potted plant" + desc = "This is an unusual plant. It's bulbous ends emit a soft blue light." + icon_state = "plant-09" + set_light(l_range = 2, l_power = 2, l_color = "#007fff") + +/obj/structure/flora/pottedplant/orientaltree + name = "potted oriental tree" + desc = "This is a rather oriental style tree. It's flowers are bright pink." + icon_state = "plant-10" + +/obj/structure/flora/pottedplant/smallcactus + name = "small potted cactus" + desc = "This is a small cactus. Its needles are sharp." + icon_state = "plant-11" + +/obj/structure/flora/pottedplant/tall + name = "tall potted plant" + desc = "This is a tall plant. Tiny pores line its surface." + icon_state = "plant-12" + +/obj/structure/flora/pottedplant/sticky + name = "sticky potted plant" + desc = "This is an odd plant. Its sticky leaves trap insects." + icon_state = "plant-13" + +/obj/structure/flora/pottedplant/smelly + name = "smelly potted plant" + desc = "This is some kind of tropical plant. It reeks of rotten eggs." + icon_state = "plant-14" + +/obj/structure/flora/pottedplant/small + name = "small potted plant" + desc = "This is a pot of assorted small flora. Some look familiar." + icon_state = "plant-15" + +/obj/structure/flora/pottedplant/aquatic + name = "aquatic potted plant" + desc = "This is apparently an aquatic plant. It's probably fake." + icon_state = "plant-16" + +/obj/structure/flora/pottedplant/shoot + name = "small potted shoot" + desc = "This is a small shoot. It still needs time to grow." + icon_state = "plant-17" + +/obj/structure/flora/pottedplant/flower + name = "potted flower" + desc = "This is a slim plant. Sweet smelling flowers are supported by spindly stems." + icon_state = "plant-18" + +/obj/structure/flora/pottedplant/crystal + name = "crystalline potted plant" + desc = "These are rather cubic plants. Odd crystal formations grow on the end." + icon_state = "plant-19" + +/obj/structure/flora/pottedplant/subterranean + name = "subterranean potted plant" + desc = "This is a subterranean plant. It's bulbous ends glow faintly." + icon_state = "plant-20" + set_light(l_range = 1, l_power = 0.5, l_color = "#ff6633") + +/obj/structure/flora/pottedplant/minitree + name = "potted tree" + desc = "This is a miniature tree. Apparently it was grown to 1/5 scale." + icon_state = "plant-21" + +/obj/structure/flora/pottedplant/stoutbush + name = "stout potted bush" + desc = "This is a stout bush. Its leaves point up and outwards." + icon_state = "plant-22" + +/obj/structure/flora/pottedplant/drooping + name = "drooping potted plant" + desc = "This is a small plant. The drooping leaves make it look like its wilted." + icon_state = "plant-23" + +/obj/structure/flora/pottedplant/tropical + name = "tropical potted plant" + desc = "This is some kind of tropical plant. It hasn't begun to flower yet." + icon_state = "plant-24" + +/obj/structure/flora/pottedplant/dead + name = "dead potted plant" + desc = "This is the dried up remains of a dead plant. Someone should replace it." + icon_state = "plant-25" + +/obj/structure/flora/pottedplant/decorative + name = "decorative potted plant" + desc = "This is a decorative shrub. It's been trimmed into the shape of an apple." + icon_state = "applebush" + diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm new file mode 100644 index 00000000..d1090a7b --- /dev/null +++ b/code/game/objects/structures/girders.dm @@ -0,0 +1,250 @@ +/obj/structure/girder + icon_state = "girder" + anchored = 1 + density = 1 + plane = OBJ_PLANE + layer = BELOW_OBJ_LAYER + w_class = ITEM_SIZE_NO_CONTAINER + var/state = 0 + var/health = 200 + var/cover = 50 //how much cover the girder provides against projectiles. + var/material/reinf_material + var/reinforcing = 0 + +/obj/structure/girder/displaced + icon_state = "displaced" + anchored = 0 + health = 50 + cover = 25 + +/obj/structure/girder/attack_generic(var/mob/user, var/damage, var/attack_message = "smashes apart", var/wallbreaker) + if(!damage || !wallbreaker) + return 0 + attack_animation(user) + visible_message("[user] [attack_message] the [src]!") + spawn(1) dismantle() + return 1 + +/obj/structure/girder/bullet_act(var/obj/item/projectile/Proj) + //Girders only provide partial cover. There's a chance that the projectiles will just pass through. (unless you are trying to shoot the girder) + if(Proj.original != src && !prob(cover)) + return PROJECTILE_CONTINUE //pass through + + var/damage = Proj.get_structure_damage() + if(!damage) + return + + if(!istype(Proj, /obj/item/projectile/beam)) + damage *= 0.4 //non beams do reduced damage + + health -= damage + ..() + if(health <= 0) + dismantle() + + return + +/obj/structure/girder/proc/reset_girder() + anchored = 1 + cover = initial(cover) + health = min(health,initial(health)) + state = 0 + icon_state = initial(icon_state) + reinforcing = 0 + if(reinf_material) + reinforce_girder() + +/obj/structure/girder/attackby(obj/item/W as obj, mob/user as mob) + if(isWrench(W) && state == 0) + if(anchored && !reinf_material) + playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + to_chat(user, "Now disassembling the girder...") + if(do_after(user, 40,src)) + if(!src) return + to_chat(user, "You dissasembled the girder!") + dismantle() + else if(!anchored) + playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + to_chat(user, "Now securing the girder...") + if(do_after(user, 40,src)) + to_chat(user, "You secured the girder!") + reset_girder() + + else if(istype(W, /obj/item/weapon/gun/energy/plasmacutter)) + to_chat(user, "Now slicing apart the girder...") + if(do_after(user,30,src)) + if(!src) return + to_chat(user, "You slice apart the girder!") + dismantle() + + else if(istype(W, /obj/item/weapon/pickaxe/diamonddrill)) + to_chat(user, "You drill through the girder!") + dismantle() + + else if(isScrewdriver(W)) + if(state == 2) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) + to_chat(user, "Now unsecuring support struts...") + if(do_after(user, 40,src)) + if(!src) return + to_chat(user, "You unsecured the support struts!") + state = 1 + else if(anchored && !reinf_material) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) + reinforcing = !reinforcing + to_chat(user, "\The [src] can now be [reinforcing? "reinforced" : "constructed"]!") + + else if(isWirecutter(W) && state == 1) + playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) + to_chat(user, "Now removing support struts...") + if(do_after(user, 40,src)) + if(!src) return + to_chat(user, "You removed the support struts!") + reinf_material.place_dismantled_product(get_turf(src)) + reinf_material = null + reset_girder() + + else if(isCrowbar(W) && state == 0 && anchored) + playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) + to_chat(user, "Now dislodging the girder...") + if(do_after(user, 40,src)) + if(!src) return + to_chat(user, "You dislodged the girder!") + icon_state = "displaced" + anchored = 0 + health = 50 + cover = 25 + + else if(istype(W, /obj/item/stack/material)) + if(reinforcing && !reinf_material) + if(!reinforce_with_material(W, user)) + return ..() + else + if(!construct_wall(W, user)) + return ..() + + else + return ..() + +/obj/structure/girder/proc/construct_wall(obj/item/stack/material/S, mob/user) + if(S.get_amount() < 2) + to_chat(user, "There isn't enough material here to construct a wall.") + return 0 + +// var/material/M = name_to_material[S.default_type] +// if(!istype(M)) +// return 0 + + var/wall_fake + add_hiddenprint(usr) + +// if(M.integrity < 50) +// to_chat(user, "This material is too soft for use in wall construction.") +// return 0 + + to_chat(user, "You begin adding the plating...") + + if(!do_after(user,40,src) || !S.use(2)) + return 1 //once we've gotten this far don't call parent attackby() + + if(anchored) + to_chat(user, "You added the plating!") + else + to_chat(user, "You create a false wall! Push on it to open or close the passage.") + wall_fake = 1 + + var/turf/Tsrc = get_turf(src) + Tsrc.ChangeTurf(/turf/simulated/wall) + var/turf/simulated/wall/T = get_turf(src) + //T.set_material(M, reinf_material) + if(wall_fake) + T.can_open = 1 + T.add_hiddenprint(usr) + qdel(src) + return 1 + +/obj/structure/girder/proc/reinforce_with_material(obj/item/stack/material/S, mob/user) //if the verb is removed this can be renamed. + if(reinf_material) + to_chat(user, "\The [src] is already reinforced.") + return 0 + + if(S.get_amount() < 2) + to_chat(user, "There isn't enough material here to reinforce the girder.") + return 0 + + var/material/M = name_to_material[S.default_type] + if(!istype(M) || M.integrity < 50) + to_chat(user, "You cannot reinforce \the [src] with that; it is too soft.") + return 0 + + to_chat(user, "Now reinforcing...") + if (!do_after(user, 40,src) || !S.use(2)) + return 1 //don't call parent attackby() past this point + to_chat(user, "You added reinforcement!") + + reinf_material = M + reinforce_girder() + return 1 + +/obj/structure/girder/proc/reinforce_girder() + cover = 75 + health = 500 + state = 2 + icon_state = "reinforced" + reinforcing = 0 + +/obj/structure/girder/proc/dismantle() + new /obj/item/stack/material/steel(get_turf(src)) + qdel(src) + +/obj/structure/girder/attack_hand(mob/user as mob) + if (HULK in user.mutations) + visible_message("[user] smashes [src] apart!") + dismantle() + return + return ..() + + +/obj/structure/girder/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + if (prob(30)) + dismantle() + return + if(3.0) + if (prob(5)) + dismantle() + return + else + return + +/obj/structure/girder/cult + icon= 'icons/obj/cult.dmi' + icon_state= "cultgirder" + health = 250 + cover = 70 + +/obj/structure/girder/cult/dismantle() + qdel(src) + +/obj/structure/girder/cult/attackby(obj/item/W as obj, mob/user as mob) + if(isWrench(W)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + to_chat(user, "Now disassembling the girder...") + if(do_after(user,40,src)) + to_chat(user, "You dissasembled the girder!") + dismantle() + + else if(istype(W, /obj/item/weapon/gun/energy/plasmacutter)) + to_chat(user, "Now slicing apart the girder...") + if(do_after(user,30,src)) + to_chat(user, "You slice apart the girder!") + dismantle() + + else if(istype(W, /obj/item/weapon/pickaxe/diamonddrill)) + to_chat(user, "You drill through the girder!") + new /obj/item/remains/human(get_turf(src)) + dismantle() diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm new file mode 100644 index 00000000..643f46c3 --- /dev/null +++ b/code/game/objects/structures/grille.dm @@ -0,0 +1,266 @@ +/obj/structure/grille + name = "grille" + desc = "A flimsy lattice of metal rods, with screws to secure it to the floor." + icon = 'icons/obj/structures.dmi' + icon_state = "grille" + density = TRUE + anchored = TRUE + obj_flags = OBJ_FLAG_CONDUCTIBLE + layer = BELOW_OBJ_LAYER + explosion_resistance = 1 + var/health = 10 + var/destroyed = 0 + +/obj/structure/grille/floorgrille + name = "floor grille" + density = FALSE + icon_state = "floorgrille" + health = 20 + plane = HIDING_MOB_PLANE + layer = CATWALK_LAYER + +/obj/structure/grille/floorgrille/Crossed(atom/movable/O) + ..() + if(isobserver(O)) + return + if(!destroyed) + playsound(loc, 'sound/effects/grillehit.ogg', 10, 1) + + +/obj/structure/grille/ex_act(severity) + qdel(src) + +/obj/structure/grille/update_icon() + if(destroyed) + icon_state = "[initial(icon_state)]-b" + else + icon_state = initial(icon_state) + +/obj/structure/grille/Bumped(atom/user) + if(ismob(user)) shock(user, 70) + +/obj/structure/grille/attack_hand(mob/living/user as mob) + + user.adjustStaminaLoss(2)//Hitting that shit is hard work. + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + playsound(loc, 'sound/effects/grillehit.ogg', 80, 1) + + var/damage_dealt = 1 + var/attack_message = "kicks" + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(H.species.can_shred(H)) + attack_message = "mangles" + damage_dealt = 5 + + if(shock(user, 70)) + return + + if(HULK in user.mutations) + damage_dealt += 5 + else + damage_dealt += 1 + + attack_generic(user,damage_dealt,attack_message) + +/obj/structure/grille/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group || (height==0)) return 1 + if(istype(mover) && mover.checkpass(PASS_FLAG_GRILLE)) + return 1 + else + if(istype(mover, /obj/item/projectile)) + return prob(30) + else + return !density + +/obj/structure/grille/bullet_act(var/obj/item/projectile/Proj) + if(!Proj) return + + //Flimsy grilles aren't so great at stopping projectiles. However they can absorb some of the impact + var/damage = Proj.get_structure_damage() + var/passthrough = 0 + + if(!damage) return + + //20% chance that the grille provides a bit more cover than usual. Support structure for example might take up 20% of the grille's area. + //If they click on the grille itself then we assume they are aiming at the grille itself and the extra cover behaviour is always used. + switch(Proj.damage_type) + if(BRUTE) + //bullets + if(Proj.original == src || prob(20)) + Proj.damage *= between(0, Proj.damage/60, 0.5) + if(prob(max((damage-10)/25, 0))*100) + passthrough = 1 + else + Proj.damage *= between(0, Proj.damage/60, 1) + passthrough = 1 + if(BURN) + //beams and other projectiles are either blocked completely by grilles or stop half the damage. + if(!(Proj.original == src || prob(20))) + Proj.damage *= 0.5 + passthrough = 1 + + if(passthrough) + . = PROJECTILE_CONTINUE + damage = between(0, (damage - Proj.damage)*(Proj.damage_type == BRUTE? 0.4 : 1), 10) //if the bullet passes through then the grille avoids most of the damage + + src.health -= damage*0.2 + spawn(0) healthcheck() //spawn to make sure we return properly if the grille is deleted + +/obj/structure/grille/attackby(obj/item/weapon/W as obj, mob/living/user as mob) + if(isWirecutter(W)) + if(!shock(user, 100)) + playsound(loc, 'sound/items/Wirecutter.ogg', 100, 1) + new /obj/item/stack/rods(get_turf(src), destroyed ? 1 : 2) + qdel(src) + else if((isScrewdriver(W)) && (istype(loc, /turf/simulated) || anchored)) + if(!shock(user, 90)) + playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1) + anchored = !anchored + user.visible_message("[user] [anchored ? "fastens" : "unfastens"] the grille.", \ + "You have [anchored ? "fastened the grille to" : "unfastened the grill from"] the floor.") + return + +//window placing begin //TODO CONVERT PROPERLY TO MATERIAL DATUM + else if(istype(W,/obj/item/stack/material)) + var/obj/item/stack/material/ST = W + if(!ST.material.created_window) + return 0 + + var/dir_to_set = 1 + if(loc == user.loc) + dir_to_set = user.dir + else + if( ( x == user.x ) || (y == user.y) ) //Only supposed to work for cardinal directions. + if( x == user.x ) + if( y > user.y ) + dir_to_set = 2 + else + dir_to_set = 1 + else if( y == user.y ) + if( x > user.x ) + dir_to_set = 8 + else + dir_to_set = 4 + else + to_chat(user, "You can't reach.") + return //Only works for cardinal direcitons, diagonals aren't supposed to work like this. + for(var/obj/structure/window/WINDOW in loc) + if(WINDOW.dir == dir_to_set) + to_chat(user, "There is already a window facing this way there.") + return + to_chat(user, "You start placing the window.") + if(do_after(user,20,src)) + for(var/obj/structure/window/WINDOW in loc) + if(WINDOW.dir == dir_to_set)//checking this for a 2nd time to check if a window was made while we were waiting. + to_chat(user, "There is already a window facing this way there.") + return + + var/wtype = ST.material.created_window + if (ST.use(1)) + var/obj/structure/window/WD = new wtype(loc, dir_to_set, 1) + to_chat(user, "You place the [WD] on [src].") + WD.update_icon() + return +//window placing end + + else if(!(W.obj_flags & OBJ_FLAG_CONDUCTIBLE) || !shock(user, 70)) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.adjustStaminaLoss(2) + playsound(loc, 'sound/effects/grillehit.ogg', 80, 1) + switch(W.damtype) + if("fire") + health -= W.force + if("brute") + health -= W.force * 0.1 + healthcheck() + ..() + return + + +/obj/structure/grille/proc/healthcheck() + if(health <= 0) + if(!destroyed) + set_density(0) + destroyed = 1 + update_icon() + new /obj/item/stack/rods(get_turf(src)) + + else + if(health <= -6) + new /obj/item/stack/rods(get_turf(src)) + qdel(src) + return + return + +// shock user with probability prb (if all connections & power are working) +// returns 1 if shocked, 0 otherwise + +/obj/structure/grille/proc/shock(mob/user as mob, prb) + + if(!anchored || destroyed) // anchored/destroyed grilles are never connected + return 0 + if(!prob(prb)) + return 0 + if(!in_range(src, user))//To prevent TK and mech users from getting shocked + return 0 + var/turf/T = get_turf(src) + var/obj/structure/cable/C = T.get_cable_node() + if(C) + if(electrocute_mob(user, C, src)) + if(C.powernet) + C.powernet.trigger_warning() + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + if(user.stunned) + return 1 + else + return 0 + return 0 + +/obj/structure/grille/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(!destroyed) + if(exposed_temperature > T0C + 1500) + health -= 1 + healthcheck() + ..() + +/obj/structure/grille/attack_generic(var/mob/user, var/damage, var/attack_verb) + visible_message("[user] [attack_verb] the [src]!") + attack_animation(user) + health -= damage + spawn(1) healthcheck() + return 1 + +// Used in mapping to avoid +/obj/structure/grille/broken + destroyed = 1 + icon_state = "grille-b" + density = 0 + New() + ..() + health = rand(-5, -1) //In the destroyed but not utterly threshold. + healthcheck() //Send this to healthcheck just in case we want to do something else with it. + +/obj/structure/grille/cult + name = "cult grille" + desc = "A matrice built out of an unknown material, with some sort of force field blocking air around it." + icon_state = "grillecult" + health = 40 //Make it strong enough to avoid people breaking in too easily + +/obj/structure/grille/cult/CanPass(atom/movable/mover, turf/target, height = 1.5, air_group = 0) + if(air_group) + return 0 //Make sure air doesn't drain + ..() + +/obj/structure/grille/bogani + name = "alien grate" + desc = "This matrice is fashioned out of some exotic, strange material. Its strength allows it to function as a prison-like walling." + icon_state = "alien_grate" + health = 150 //hella strong + +/obj/structure/grille/bogani/CanPass(atom/movable/mover, turf/target, height = 1.5, air_group = 0) + if(air_group) + return 0 //Make sure air doesn't drain + ..() diff --git a/code/game/objects/structures/handrail.dm b/code/game/objects/structures/handrail.dm new file mode 100644 index 00000000..e8287c54 --- /dev/null +++ b/code/game/objects/structures/handrail.dm @@ -0,0 +1,8 @@ +/obj/structure/handrai + name = "handrail" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "handrail" + desc = "A safety railing with buckles to secure yourself to when floor isn't stable enough." + density = 0 + anchored = 1 + can_buckle = 1 \ No newline at end of file diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm new file mode 100644 index 00000000..2a434596 --- /dev/null +++ b/code/game/objects/structures/inflatable.dm @@ -0,0 +1,265 @@ +/obj/item/inflatable + name = "inflatable" + w_class = ITEM_SIZE_NORMAL + icon = 'icons/obj/inflatable.dmi' + var/deploy_path = null + + atmos_canpass = CANPASS_DENSITY + +/obj/item/inflatable/attack_self(mob/user) + if(!deploy_path) + return + playsound(loc, 'sound/items/zip.ogg', 75, 1) + to_chat(user, "You inflate \the [src].") + var/obj/structure/inflatable/R = new deploy_path(user.loc) + src.transfer_fingerprints_to(R) + R.add_fingerprint(user) + qdel(src) + + +/obj/item/inflatable/wall + name = "inflatable wall" + desc = "A folded membrane which rapidly expands into a large cubical shape on activation." + icon_state = "folded_wall" + deploy_path = /obj/structure/inflatable/wall + +/obj/item/inflatable/door/ + name = "inflatable door" + desc = "A folded membrane which rapidly expands into a simple door on activation." + icon_state = "folded_door" + deploy_path = /obj/structure/inflatable/door + +/obj/structure/inflatable + name = "inflatable" + desc = "An inflated membrane. Do not puncture." + density = 1 + anchored = 1 + opacity = 0 + icon = 'icons/obj/inflatable.dmi' + icon_state = "wall" + + var/undeploy_path = null + var/health = 50.0 + +/obj/structure/inflatable/wall + name = "inflatable wall" + undeploy_path = /obj/item/inflatable/wall + +/obj/structure/inflatable/New(location) + ..() + update_nearby_tiles(need_rebuild=1) + +/obj/structure/inflatable/Destroy() + update_nearby_tiles() + return ..() + +/obj/structure/inflatable/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + return 0 + +/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) + deflate(1) + return + +/obj/structure/inflatable/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + deflate(1) + return + if(3.0) + if(prob(50)) + deflate(1) + return + +/obj/structure/inflatable/attack_hand(mob/user as mob) + add_fingerprint(user) + return + +/obj/structure/inflatable/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(!istype(W) || istype(W, /obj/item/weapon/inflatable_dispenser)) return + + if((W.damtype == BRUTE || W.damtype == BURN) && W.can_puncture()) + ..() + if(hit(W.force)) + visible_message("[user] pierces [src] with [W]!") + return + +/obj/structure/inflatable/proc/hit(var/damage, var/sound_effect = 1) + health = max(0, health - damage) + if(sound_effect) + playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1) + if(health <= 0) + deflate(1) + return 1 + return 0 + +/obj/structure/inflatable/CtrlClick() + hand_deflate() + +/obj/structure/inflatable/proc/deflate(var/violent=0) + playsound(loc, 'sound/machines/hiss.ogg', 75, 1) + if(violent) + visible_message("[src] rapidly deflates!") + var/obj/item/inflatable/torn/R = new /obj/item/inflatable/torn(loc) + src.transfer_fingerprints_to(R) + qdel(src) + else + if(!undeploy_path) + return + visible_message("\The [src] slowly deflates.") + spawn(50) + var/obj/item/inflatable/R = new undeploy_path(src.loc) + src.transfer_fingerprints_to(R) + qdel(src) + +/obj/structure/inflatable/proc/hand_deflate() + set name = "Deflate" + set category = "Object" + + if(isobserver(usr) || usr.restrained() || !usr.Adjacent(src)) + return + + verbs -= /obj/structure/inflatable/proc/hand_deflate + deflate() + +/obj/structure/inflatable/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + hand_deflate() + +/obj/structure/inflatable/attack_generic(var/mob/user, var/damage, var/attack_verb) + health -= damage + attack_animation(user) + if(health <= 0) + user.visible_message("[user] [attack_verb] open the [src]!") + spawn(1) deflate(1) + else + user.visible_message("[user] [attack_verb] at [src]!") + return 1 + +/obj/structure/inflatable/door //Based on mineral door code + name = "inflatable door" + density = 1 + anchored = 1 + opacity = 0 + + icon_state = "door_closed" + undeploy_path = /obj/item/inflatable/door + + var/state = 0 //closed, 1 == open + var/isSwitchingStates = 0 + +/obj/structure/inflatable/door/attack_ai(mob/user as mob) //those aren't machinery, they're just big fucking slabs of a mineral + if(isAI(user)) //so the AI can't open it + return + else if(isrobot(user)) //but cyborgs can + if(get_dist(user,src) <= 1) //not remotely though + return TryToSwitchState(user) + +/obj/structure/inflatable/door/attack_hand(mob/user as mob) + return TryToSwitchState(user) + +/obj/structure/inflatable/door/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group) + return state + if(istype(mover, /obj/effect/beam)) + return !opacity + return !density + +/obj/structure/inflatable/door/proc/TryToSwitchState(atom/user) + if(isSwitchingStates) return + if(ismob(user)) + var/mob/M = user + if(M.client) + if(iscarbon(M)) + var/mob/living/carbon/C = M + if(!C.handcuffed) + SwitchState() + else + SwitchState() + else if(istype(user, /obj/mecha)) + SwitchState() + +/obj/structure/inflatable/door/proc/SwitchState() + if(state) + Close() + else + Open() + update_nearby_tiles() + +/obj/structure/inflatable/door/proc/Open() + isSwitchingStates = 1 + flick("door_opening",src) + sleep(10) + set_density(0) + set_opacity(0) + state = 1 + update_icon() + isSwitchingStates = 0 + +/obj/structure/inflatable/door/proc/Close() + isSwitchingStates = 1 + flick("door_closing",src) + sleep(10) + set_density(1) + set_opacity(0) + state = 0 + update_icon() + isSwitchingStates = 0 + +/obj/structure/inflatable/door/update_icon() + if(state) + icon_state = "door_open" + else + icon_state = "door_closed" + +/obj/structure/inflatable/door/deflate(var/violent=0) + playsound(loc, 'sound/machines/hiss.ogg', 75, 1) + if(violent) + visible_message("[src] rapidly deflates!") + var/obj/item/inflatable/door/torn/R = new /obj/item/inflatable/door/torn(loc) + src.transfer_fingerprints_to(R) + qdel(src) + else + visible_message("[src] slowly deflates.") + spawn(50) + var/obj/item/inflatable/door/R = new /obj/item/inflatable/door(loc) + src.transfer_fingerprints_to(R) + qdel(src) + +/obj/item/inflatable/torn + name = "torn inflatable wall" + desc = "A folded membrane which rapidly expands into a large cubical shape on activation. It is too torn to be usable." + icon = 'icons/obj/inflatable.dmi' + icon_state = "folded_wall_torn" + + attack_self(mob/user) + to_chat(user, "The inflatable wall is too torn to be inflated!") + add_fingerprint(user) + +/obj/item/inflatable/door/torn + name = "torn inflatable door" + desc = "A folded membrane which rapidly expands into a simple door on activation. It is too torn to be usable." + icon = 'icons/obj/inflatable.dmi' + icon_state = "folded_door_torn" + + attack_self(mob/user) + to_chat(user, "The inflatable door is too torn to be inflated!") + add_fingerprint(user) + +/obj/item/weapon/storage/briefcase/inflatable + name = "inflatable barrier box" + desc = "Contains inflatable walls and doors." + icon_state = "inf_box" + item_state = "syringe_kit" + w_class = ITEM_SIZE_LARGE + max_storage_space = DEFAULT_LARGEBOX_STORAGE + can_hold = list(/obj/item/inflatable) + startswith = list(/obj/item/inflatable/door = 2, /obj/item/inflatable/wall = 3) diff --git a/code/game/objects/structures/iv_drip.dm b/code/game/objects/structures/iv_drip.dm new file mode 100644 index 00000000..b9c7d014 --- /dev/null +++ b/code/game/objects/structures/iv_drip.dm @@ -0,0 +1,170 @@ +/obj/structure/iv_drip + name = "\improper IV drip" + icon = 'icons/obj/iv_drip.dmi' + anchored = 0 + density = 0 + var/mob/living/carbon/human/attached + var/mode = 1 // 1 is injecting, 0 is taking blood. + var/obj/item/weapon/reagent_containers/beaker + var/list/transfer_amounts = list(REM, 1, 2) + var/transfer_amount = 1 + +/obj/structure/iv_drip/proc/set_APTFT() + set name = "Set IV transfer amount" + set category = "Object" + var/N = input("Amount per transfer from this:","[src]") as null|anything in transfer_amounts + if(N) + transfer_amount = N + +/obj/structure/iv_drip/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + set_APTFT() + +/obj/structure/iv_drip/update_icon() + if(attached) + icon_state = "hooked" + else + icon_state = "" + + overlays.Cut() + + if(beaker) + var/datum/reagents/reagents = beaker.reagents + var/percent = round((reagents.total_volume / beaker.volume) * 100) + if(reagents.total_volume) + var/image/filling = image('icons/obj/iv_drip.dmi', src, "reagent") + + switch(percent) + if(0 to 9) filling.icon_state = "reagent0" + if(10 to 24) filling.icon_state = "reagent10" + if(25 to 49) filling.icon_state = "reagent25" + if(50 to 74) filling.icon_state = "reagent50" + if(75 to 79) filling.icon_state = "reagent75" + if(80 to 90) filling.icon_state = "reagent80" + if(91 to INFINITY) filling.icon_state = "reagent100" + filling.icon += reagents.get_color() + overlays += filling + + if(attached) + var/image/light = image('icons/obj/iv_drip.dmi', "light_full") + if(percent < 15) + light.icon_state = "light_low" + else if(percent < 60) + light.icon_state = "light_mid" + overlays += light + +/obj/structure/iv_drip/MouseDrop(over_object, src_location, over_location) + if(!CanMouseDrop(over_object)) + return + + if(attached) + visible_message("\The [attached] is taken off \the [src]") + attached = null + else if(ishuman(over_object)) + visible_message("\The [usr] hooks \the [over_object] up to \the [src].") + attached = over_object + START_PROCESSING(SSobj,src) + + update_icon() + +/obj/structure/iv_drip/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/reagent_containers)) + if(!isnull(src.beaker)) + to_chat(user, "There is already a reagent container loaded!") + return + user.drop_item() + W.forceMove(src) + beaker = W + to_chat(user, "You attach \the [W] to \the [src].") + update_icon() + else + return ..() + +/obj/structure/iv_drip/Destroy() + STOP_PROCESSING(SSobj,src) + attached = null + qdel(beaker) + beaker = null + . = ..() + +/obj/structure/iv_drip/Process() + if(attached) + if(!Adjacent(attached)) + visible_message("The needle is ripped out of [src.attached], doesn't that hurt?") + attached.apply_damage(1, BRUTE, pick(BP_R_ARM, BP_L_ARM)) + attached = null + update_icon() + return PROCESS_KILL + else + return PROCESS_KILL + + if(!beaker) + return + + if(mode) // Give blood + if(beaker.volume > 0) + beaker.reagents.trans_to_mob(attached, transfer_amount, CHEM_BLOOD) + update_icon() + else // Take blood + var/amount = beaker.reagents.maximum_volume - beaker.reagents.total_volume + amount = min(amount, 4) + + if(amount == 0) // If the beaker is full, ping + if(prob(5)) visible_message("\The [src] pings.") + return + + if(!attached.should_have_organ(BP_HEART)) + return + + // If the human is losing too much blood, beep. + if(attached.get_blood_volume() < BLOOD_VOLUME_SAFE * 1.05) + visible_message("\The [src] beeps loudly.") + + if(attached.take_blood(beaker,amount)) + update_icon() + +/obj/structure/iv_drip/attack_hand(mob/user as mob) + if(beaker) + beaker.dropInto(loc) + beaker = null + update_icon() + else + return ..() + +/obj/structure/iv_drip/attack_robot(var/mob/user) + if(Adjacent(user)) + attack_hand(user) + +/obj/structure/iv_drip/verb/toggle_mode() + set category = "Object" + set name = "Toggle IV Mode" + set src in view(1) + + if(!istype(usr, /mob/living)) + to_chat(usr, "You can't do that.") + return + + if(usr.incapacitated()) + return + + mode = !mode + to_chat(usr, "The IV drip is now [mode ? "injecting" : "taking blood"].") + +/obj/structure/iv_drip/examine(mob/user) + . = ..(user) + + if (get_dist(src, user) > 2) + return + + to_chat(user, "The IV drip is [mode ? "injecting" : "taking blood"].") + to_chat(user, "It is set to transfer [transfer_amount]u of chemicals per cycle.") + + if(beaker) + if(beaker.reagents && beaker.reagents.total_volume) + to_chat(usr, "Attached is \a [beaker] with [beaker.reagents.total_volume] units of liquid.") + else + to_chat(usr, "Attached is an empty [beaker].") + else + to_chat(usr, "No chemicals are attached.") + + to_chat(usr, "[attached ? attached : "No one"] is hooked up to it.") diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm new file mode 100644 index 00000000..5244108c --- /dev/null +++ b/code/game/objects/structures/janicart.dm @@ -0,0 +1,288 @@ +/obj/structure/janitorialcart + name = "janitorial cart" + desc = "The ultimate in janitorial carts! Has space for water, mops, signs, trash bags, and more!" + icon = 'icons/obj/janitor.dmi' + icon_state = "cart" + anchored = 0 + density = 1 + atom_flags = ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_CLIMBABLE + //copypaste sorry + var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite + var/obj/item/weapon/storage/bag/trash/mybag = null + var/obj/item/weapon/mop/mymop = null + var/obj/item/weapon/reagent_containers/spray/myspray = null + var/obj/item/device/lightreplacer/myreplacer = null + var/signs = 0 //maximum capacity hardcoded below + + +/obj/structure/janitorialcart/New() + create_reagents(180) + + +/obj/structure/janitorialcart/examine(mob/user) + if(..(user, 1)) + to_chat(user, "[src] \icon[src] contains [reagents.total_volume] unit\s of liquid!") + //everything else is visible, so doesn't need to be mentioned + + +/obj/structure/janitorialcart/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/weapon/storage/bag/trash) && !mybag) + user.drop_item() + mybag = I + I.loc = src + update_icon() + updateUsrDialog() + to_chat(user, "You put [I] into [src].") + + else if(istype(I, /obj/item/weapon/mop)) + if(I.reagents.total_volume < I.reagents.maximum_volume) //if it's not completely soaked we assume they want to wet it, otherwise store it + if(reagents.total_volume < 1) + to_chat(user, "[src] is out of water!") + else + reagents.trans_to_obj(I, I.reagents.maximum_volume) + to_chat(user, "You wet [I] in [src].") + playsound(loc, 'sound/effects/slosh.ogg', 25, 1) + return + if(!mymop) + user.drop_item() + mymop = I + I.loc = src + update_icon() + updateUsrDialog() + to_chat(user, "You put [I] into [src].") + + else if(istype(I, /obj/item/weapon/reagent_containers/spray) && !myspray) + user.drop_item() + myspray = I + I.loc = src + update_icon() + updateUsrDialog() + to_chat(user, "You put [I] into [src].") + + else if(istype(I, /obj/item/device/lightreplacer) && !myreplacer) + user.drop_item() + myreplacer = I + I.loc = src + update_icon() + updateUsrDialog() + to_chat(user, "You put [I] into [src].") + + else if(istype(I, /obj/item/weapon/caution)) + if(signs < 4) + user.drop_item() + I.loc = src + signs++ + update_icon() + updateUsrDialog() + to_chat(user, "You put [I] into [src].") + else + to_chat(user, "[src] can't hold any more signs.") + + else if(istype(I, /obj/item/weapon/reagent_containers/glass)) + return // So we do not put them in the trash bag as we mean to fill the mop bucket + + else if(mybag) + mybag.attackby(I, user) + + +/obj/structure/janitorialcart/attack_hand(mob/user) + ui_interact(user) + return + +/obj/structure/janitorialcart/ui_interact(var/mob/user, var/ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + data["name"] = capitalize(name) + data["bag"] = mybag ? capitalize(mybag.name) : null + data["mop"] = mymop ? capitalize(mymop.name) : null + data["spray"] = myspray ? capitalize(myspray.name) : null + data["replacer"] = myreplacer ? capitalize(myreplacer.name) : null + data["signs"] = signs ? "[signs] sign\s" : null + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "janitorcart.tmpl", "Janitorial cart", 240, 160) + ui.set_initial_data(data) + ui.open() + +/obj/structure/janitorialcart/Topic(href, href_list) + if(!in_range(src, usr)) + return + if(!isliving(usr)) + return + var/mob/living/user = usr + + if(href_list["take"]) + switch(href_list["take"]) + if("garbage") + if(mybag) + user.put_in_hands(mybag) + to_chat(user, "You take [mybag] from [src].") + mybag = null + if("mop") + if(mymop) + user.put_in_hands(mymop) + to_chat(user, "You take [mymop] from [src].") + mymop = null + if("spray") + if(myspray) + user.put_in_hands(myspray) + to_chat(user, "You take [myspray] from [src].") + myspray = null + if("replacer") + if(myreplacer) + user.put_in_hands(myreplacer) + to_chat(user, "You take [myreplacer] from [src].") + myreplacer = null + if("sign") + if(signs) + var/obj/item/weapon/caution/Sign = locate() in src + if(Sign) + user.put_in_hands(Sign) + to_chat(user, "You take \a [Sign] from [src].") + signs-- + else + warning("[src] signs ([signs]) didn't match contents") + signs = 0 + + update_icon() + updateUsrDialog() + + +/obj/structure/janitorialcart/update_icon() + overlays = null + if(mybag) + overlays += "cart_garbage" + if(mymop) + overlays += "cart_mop" + if(myspray) + overlays += "cart_spray" + if(myreplacer) + overlays += "cart_replacer" + if(signs) + overlays += "cart_sign[signs]" + + +//old style retardo-cart +/obj/structure/bed/chair/janicart + name = "janicart" + icon = 'icons/obj/vehicles.dmi' + icon_state = "pussywagon" + anchored = 1 + density = 1 + atom_flags = ATOM_FLAG_OPEN_CONTAINER + //copypaste sorry + var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite + var/obj/item/weapon/storage/bag/trash/mybag = null + var/callme = "pimpin' ride" //how do people refer to it? + + +/obj/structure/bed/chair/janicart/New() + create_reagents(100) + + +/obj/structure/bed/chair/janicart/examine(mob/user) + if(!..(user, 1)) + return + + to_chat(user, "\icon[src] This [callme] contains [reagents.total_volume] unit\s of water!") + if(mybag) + to_chat(user, "\A [mybag] is hanging on the [callme].") + + +/obj/structure/bed/chair/janicart/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/weapon/mop)) + if(reagents.total_volume > 1) + reagents.trans_to_obj(I, 2) + to_chat(user, "You wet [I] in the [callme].") + playsound(loc, 'sound/effects/slosh.ogg', 25, 1) + else + to_chat(user, "This [callme] is out of water!") + else if(istype(I, /obj/item/key)) + to_chat(user, "Hold [I] in one of your hands while you drive this [callme].") + else if(istype(I, /obj/item/weapon/storage/bag/trash)) + to_chat(user, "You hook the trashbag onto the [callme].") + user.drop_item() + I.loc = src + mybag = I + + +/obj/structure/bed/chair/janicart/attack_hand(mob/user) + if(mybag) + mybag.loc = get_turf(user) + user.put_in_hands(mybag) + mybag = null + else + ..() + + +/obj/structure/bed/chair/janicart/relaymove(mob/user, direction) + if(user.stat || user.stunned || user.weakened || user.paralysis) + unbuckle_mob() + if(istype(user.l_hand, /obj/item/key) || istype(user.r_hand, /obj/item/key)) + step(src, direction) + update_mob() + else + to_chat(user, "You'll need the keys in one of your hands to drive this [callme].") + + +/obj/structure/bed/chair/janicart/Move() + ..() + if(buckled_mob) + if(buckled_mob.buckled == src) + buckled_mob.loc = loc + + +/obj/structure/bed/chair/janicart/post_buckle_mob(mob/living/M) + update_mob() + return ..() + + +/obj/structure/bed/chair/janicart/unbuckle_mob() + var/mob/living/M = ..() + if(M) + M.pixel_x = 0 + M.pixel_y = 0 + return M + + +/obj/structure/bed/chair/janicart/set_dir() + ..() + if(buckled_mob) + if(buckled_mob.loc != loc) + buckled_mob.buckled = null //Temporary, so Move() succeeds. + buckled_mob.buckled = src //Restoring + + update_mob() + + +/obj/structure/bed/chair/janicart/proc/update_mob() + if(buckled_mob) + buckled_mob.set_dir(dir) + switch(dir) + if(SOUTH) + buckled_mob.pixel_x = 0 + buckled_mob.pixel_y = 7 + if(WEST) + buckled_mob.pixel_x = 13 + buckled_mob.pixel_y = 7 + if(NORTH) + buckled_mob.pixel_x = 0 + buckled_mob.pixel_y = 4 + if(EAST) + buckled_mob.pixel_x = -13 + buckled_mob.pixel_y = 7 + + +/obj/structure/bed/chair/janicart/bullet_act(var/obj/item/projectile/Proj) + if(buckled_mob) + if(prob(85)) + return buckled_mob.bullet_act(Proj) + visible_message("[Proj] ricochets off the [callme]!") + + +/obj/item/key + name = "key" + desc = "A keyring with a small steel key, and a pink fob reading \"Pussy Wagon\"." + icon = 'icons/obj/vehicles.dmi' + icon_state = "keys" + w_class = ITEM_SIZE_TINY diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm new file mode 100644 index 00000000..a671e76b --- /dev/null +++ b/code/game/objects/structures/kitchen_spike.dm @@ -0,0 +1,60 @@ +//////Kitchen Spike + +/obj/structure/kitchenspike + name = "meat spike" + icon = 'icons/obj/kitchen.dmi' + icon_state = "spike" + desc = "A spike for collecting meat from animals." + density = 1 + anchored = 1 + var/meat = 0 + var/occupied + var/meat_type + var/victim_name = "corpse" + +/obj/structure/kitchenspike/attackby(obj/item/grab/G, mob/living/carbon/human/user) + if(!istype(G) || !G.affecting) + return + if(occupied) + to_chat(user, "The spike already has something on it, finish collecting its meat first!") + else + if(spike(G.affecting)) + visible_message("[user] has forced [G.affecting] onto the spike, killing them instantly!") + qdel(G.affecting) + qdel(G) + else + to_chat(user, "They are too big for the spike, try something smaller!") + +/obj/structure/kitchenspike/proc/spike(var/mob/living/victim) + + if(!istype(victim)) + return + + if(istype(victim, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = victim + if(!issmall(H)) + return 0 + meat_type = H.species.meat_type + icon_state = "spikebloody" + else if(istype(victim, /mob/living/carbon/alien)) + meat_type = /obj/item/weapon/reagent_containers/food/snacks/xenomeat + icon_state = "spikebloodygreen" + else + return 0 + + victim_name = victim.name + occupied = 1 + meat = 5 + return 1 + +/obj/structure/kitchenspike/attack_hand(mob/user as mob) + if(..() || !occupied) + return + meat-- + new meat_type(get_turf(src)) + if(src.meat > 1) + to_chat(user, "You remove some meat from \the [victim_name].") + else if(src.meat == 1) + to_chat(user, "You remove the last piece of meat from \the [victim_name]!") + icon_state = "spike" + occupied = 0 diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm new file mode 100644 index 00000000..1c8e307a --- /dev/null +++ b/code/game/objects/structures/lattice.dm @@ -0,0 +1,93 @@ +/obj/structure/lattice + name = "lattice" + desc = "A lightweight support lattice." + icon = 'icons/obj/structures.dmi' + icon_state = "latticefull" + density = 0 + anchored = 1.0 + w_class = ITEM_SIZE_NORMAL + plane = HIDING_MOB_PLANE + layer = LATTICE_LAYER + +/obj/structure/lattice/Initialize() + . = ..() +///// Z-Level Stuff + if(!(istype(src.loc, /turf/space) || istype(src.loc, /turf/simulated/open))) +///// Z-Level Stuff + return INITIALIZE_HINT_QDEL + for(var/obj/structure/lattice/LAT in loc) + if(LAT != src) + crash_with("Found multiple lattices at '[log_info_line(loc)]'") + qdel(LAT) + icon = 'icons/obj/smoothlattice.dmi' + icon_state = "latticeblank" + updateOverlays() + for (var/dir in GLOB.cardinal) + var/obj/structure/lattice/L + if(locate(/obj/structure/lattice, get_step(src, dir))) + L = locate(/obj/structure/lattice, get_step(src, dir)) + L.updateOverlays() + +/obj/structure/lattice/Destroy() + for (var/dir in GLOB.cardinal) + var/obj/structure/lattice/L + if(locate(/obj/structure/lattice, get_step(src, dir))) + L = locate(/obj/structure/lattice, get_step(src, dir)) + L.updateOverlays(src.loc) + . = ..() + +/obj/structure/lattice/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + qdel(src) + return + if(3.0) + return + else + return + +/obj/structure/lattice/attackby(obj/item/C as obj, mob/user as mob) + + if (istype(C, /obj/item/stack/tile/floor)) + var/turf/T = get_turf(src) + T.attackby(C, user) //BubbleWrap - hand this off to the underlying turf instead + return + if(isWelder(C)) + var/obj/item/weapon/weldingtool/WT = C + if(WT.remove_fuel(0, user)) + to_chat(user, "Slicing lattice joints ...") + new /obj/item/stack/rods(loc) + qdel(src) + if (istype(C, /obj/item/stack/rods)) + var/obj/item/stack/rods/R = C + if(R.use(2)) + src.alpha = 0 + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + new /obj/structure/catwalk(src.loc) + qdel(src) + return + else + to_chat(user, "You require at least two rods to complete the catwalk.") + return + return + +/obj/structure/lattice/proc/updateOverlays() + spawn(1) + overlays = list() + + var/dir_sum = 0 + + var/turf/T + for (var/direction in GLOB.cardinal) + T = get_step(src, direction) + if(locate(/obj/structure/lattice, T) || locate(/obj/structure/catwalk, T)) + dir_sum += direction + else + if(!(istype(get_step(src, direction), /turf/simulated/shuttle/wall)) && !(istype(get_step(src, direction), /turf/simulated/floor/shuttle)) && !(istype(get_step(src, direction), /turf/simulated/open))) + dir_sum += direction + + icon_state = "lattice[dir_sum]" + return diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm new file mode 100644 index 00000000..8be31c4e --- /dev/null +++ b/code/game/objects/structures/mirror.dm @@ -0,0 +1,123 @@ +//wip wip wup +/obj/structure/mirror + name = "mirror" + desc = "A SalonPro Nano-Mirror(TM) brand mirror! The leading technology in hair salon products, utilizing nano-machinery to style your hair just right." + icon = 'icons/obj/watercloset.dmi' + icon_state = "mirror" + density = 0 + anchored = 1 + var/shattered = 0 + var/list/ui_users = list() + +/obj/structure/mirror/attack_hand(mob/user as mob) + + if(shattered) return + + if(ishuman(user)) + var/datum/nano_module/appearance_changer/AC = ui_users[user] + if(!AC) + AC = new(src, user) + AC.name = "SalonPro Nano-Mirror™" + ui_users[user] = AC + AC.ui_interact(user) + +/obj/structure/mirror/proc/shatter() + if(shattered) return + shattered = 1 + icon_state = "mirror_broke" + playsound(src, "shatter", 70, 1) + desc = "Oh no, seven years of bad luck!" + + +/obj/structure/mirror/bullet_act(var/obj/item/projectile/Proj) + + if(prob(Proj.get_structure_damage() * 2)) + if(!shattered) + shatter() + else + playsound(src, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1) + ..() + +/obj/structure/mirror/attackby(obj/item/I as obj, mob/user as mob) + if(shattered) + playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1) + return + + if(prob(I.force * 2)) + visible_message("[user] smashes [src] with [I]!") + shatter() + else + visible_message("[user] hits [src] with [I]!") + playsound(src.loc, 'sound/effects/Glasshit.ogg', 70, 1) + +/obj/structure/mirror/attack_generic(var/mob/user, var/damage) + attack_animation(user) + if(shattered) + playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1) + return 0 + + if(damage) + user.visible_message("[user] smashes [src]!") + shatter() + else + user.visible_message("[user] hits [src] and bounces off!") + return 1 + +/obj/structure/mirror/Destroy() + for(var/user in ui_users) + var/datum/nano_module/appearance_changer/AC = ui_users[user] + qdel(AC) + ui_users.Cut() + ..() + +// The following mirror is ~special~. +/obj/structure/mirror/raider + name = "cracked mirror" + desc = "Something seems strange about this old, dirty mirror. Your reflection doesn't look like you remember it." + icon_state = "mirror_broke" + shattered = 1 + +/obj/structure/mirror/raider/attack_hand(var/mob/living/carbon/human/user) + if(istype(get_area(src),/area/syndicate_mothership)) + if(istype(user) && user.mind && user.mind.special_role == "Raider" && user.species.name != SPECIES_VOX && is_alien_whitelisted(user, SPECIES_VOX)) + var/choice = input("Do you wish to become a true Vox of the Shoal? This is not reversible.") as null|anything in list("No","Yes") + if(choice && choice == "Yes") + var/mob/living/carbon/human/vox/vox = new(get_turf(src),SPECIES_VOX) + vox.gender = user.gender + raiders.equip(vox) + if(user.mind) + user.mind.transfer_to(vox) + spawn(1) + var/newname = sanitizeSafe(input(vox,"Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN) + if(!newname || newname == "") + var/datum/language/L = all_languages[vox.species.default_language] + newname = L.get_random_name() + vox.real_name = newname + vox.SetName(vox.real_name) + raiders.update_access(vox) + qdel(user) + ..() + +/obj/item/weapon/mirror + name = "mirror" + desc = "A SalonPro Nano-Mirror(TM) brand mirror! Now a portable version." + icon = 'icons/obj/items.dmi' + icon_state = "mirror" + var/list/ui_users = list() + +/obj/item/weapon/mirror/attack_self(mob/user as mob) + if(ishuman(user)) + var/datum/nano_module/appearance_changer/AC = ui_users[user] + if(!AC) + AC = new(src, user) + AC.name = "SalonPro Nano-Mirror™" + AC.flags = APPEARANCE_HAIR + ui_users[user] = AC + AC.ui_interact(user) + +/obj/item/weapon/mirror/Destroy() + for(var/user in ui_users) + var/datum/nano_module/appearance_changer/AC = ui_users[user] + qdel(AC) + ui_users.Cut() + ..() \ No newline at end of file diff --git a/code/game/objects/structures/mop_bucket.dm b/code/game/objects/structures/mop_bucket.dm new file mode 100644 index 00000000..7b85ba79 --- /dev/null +++ b/code/game/objects/structures/mop_bucket.dm @@ -0,0 +1,28 @@ +/obj/structure/mopbucket + name = "mop bucket" + desc = "Fill it with water, but don't forget a mop!" + icon = 'icons/obj/janitor.dmi' + icon_state = "mopbucket" + density = 1 + w_class = ITEM_SIZE_NORMAL + atom_flags = ATOM_FLAG_CLIMBABLE + atom_flags = ATOM_FLAG_OPEN_CONTAINER + var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite + + +/obj/structure/mopbucket/New() + create_reagents(180) + ..() + +/obj/structure/mopbucket/examine(mob/user) + if(..(user, 1)) + to_chat(user, "[src] \icon[src] contains [reagents.total_volume] unit\s of water!") + +/obj/structure/mopbucket/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/weapon/mop)) + if(reagents.total_volume < 1) + to_chat(user, "\The [src] is out of water!") + else + reagents.trans_to_obj(I, 5) + to_chat(user, "You wet \the [I] in \the [src].") + playsound(loc, 'sound/effects/slosh.ogg', 25, 1) diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm new file mode 100644 index 00000000..a3bf1a71 --- /dev/null +++ b/code/game/objects/structures/morgue.dm @@ -0,0 +1,433 @@ +/* Morgue stuff + * Contains: + * Morgue + * Morgue trays + * Creamatorium + * Creamatorium trays + */ + +/* + * Morgue + */ + +/obj/structure/morgue + name = "morgue" + desc = "Used to keep bodies in until someone fetches them." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "morgue1" + dir = EAST + density = 1 + var/obj/structure/m_tray/connected = null + anchored = 1.0 + +/obj/structure/morgue/Destroy() + if(connected) + qdel(connected) + connected = null + return ..() + +/obj/structure/morgue/update_icon() + if (src.connected) + src.icon_state = "morgue0" + else + if (src.contents.len) + src.icon_state = "morgue2" + else + src.icon_state = "morgue1" + return + +/obj/structure/morgue/ex_act(severity) + switch(severity) + if(1.0) + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.loc) + ex_act(severity) + qdel(src) + return + if(2.0) + if (prob(50)) + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.loc) + ex_act(severity) + qdel(src) + return + if(3.0) + if (prob(5)) + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.loc) + ex_act(severity) + qdel(src) + return + return + +/obj/structure/morgue/attack_hand(mob/user as mob) + if (src.connected) + for(var/atom/movable/A as mob|obj in src.connected.loc) + if (!( A.anchored )) + A.forceMove(src) + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + qdel(src.connected) + src.connected = null + else + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + src.connected = new /obj/structure/m_tray( src.loc ) + step(src.connected, src.dir) + src.connected.layer = OBJ_LAYER + var/turf/T = get_step(src, src.dir) + if (T.contents.Find(src.connected)) + src.connected.connected = src + src.icon_state = "morgue0" + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.connected.loc) + src.connected.icon_state = "morguet" + src.connected.set_dir(src.dir) + else + qdel(src.connected) + src.connected = null + src.add_fingerprint(user) + update_icon() + return + +/obj/structure/morgue/attack_robot(var/mob/user) + if(Adjacent(user)) + return attack_hand(user) + else return ..() + +/obj/structure/morgue/attackby(P as obj, mob/user as mob) + if (istype(P, /obj/item/weapon/pen)) + var/t = input(user, "What would you like the label to be?", text("[]", src.name), null) as text + if (user.get_active_hand() != P) + return + if ((!in_range(src, usr) && src.loc != user)) + return + t = sanitizeSafe(t, MAX_NAME_LEN) + if (t) + src.SetName(text("Morgue- '[]'", t)) + else + src.SetName("Morgue") + src.add_fingerprint(user) + return + +/obj/structure/morgue/relaymove(mob/user as mob) + if (user.stat) + return + src.connected = new /obj/structure/m_tray( src.loc ) + step(src.connected, EAST) + src.connected.layer = OBJ_LAYER + var/turf/T = get_step(src, EAST) + if (T.contents.Find(src.connected)) + src.connected.connected = src + src.icon_state = "morgue0" + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.connected.loc) + src.connected.icon_state = "morguet" + else + qdel(src.connected) + src.connected = null + return + + +/* + * Morgue tray + */ +/obj/structure/m_tray + name = "morgue tray" + desc = "Apply corpse before closing." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "morguet" + density = 1 + layer = BELOW_OBJ_LAYER + var/obj/structure/morgue/connected = null + anchored = 1 + throwpass = 1 + +/obj/structure/m_tray/Destroy() + if(connected && connected.connected == src) + connected.connected = null + connected = null + return ..() + +/obj/structure/m_tray/attack_hand(mob/user as mob) + if (src.connected) + for(var/atom/movable/A as mob|obj in src.loc) + if (!( A.anchored )) + A.forceMove(src.connected) + //Foreach goto(26) + src.connected.connected = null + src.connected.update_icon() + add_fingerprint(user) + //SN src = null + qdel(src) + return + return + +/obj/structure/m_tray/MouseDrop_T(atom/movable/O as mob|obj, mob/user as mob) + if ((!( istype(O, /atom/movable) ) || O.anchored || get_dist(user, src) > 1 || get_dist(user, O) > 1 || user.contents.Find(src) || user.contents.Find(O))) + return + if (!ismob(O) && !istype(O, /obj/structure/closet/body_bag)) + return + if (!ismob(user) || user.stat || user.lying || user.stunned) + return + O.forceMove(src.loc) + if (user != O) + for(var/mob/B in viewers(user, 3)) + if ((B.client && !( B.blinded ))) + to_chat(B, "\The [user] stuffs [O] into [src]!") + return + + +/* + * Crematorium + */ + +/obj/structure/crematorium + name = "crematorium" + desc = "A human incinerator. Works well on barbeque nights." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "crema1" + density = 1 + var/obj/structure/c_tray/connected = null + anchored = 1.0 + var/cremating = 0 + var/id = 1 + var/locked = 0 + var/_wifi_id + var/datum/wifi/receiver/button/crematorium/wifi_receiver + +/obj/structure/crematorium/Initialize() + . = ..() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + +/obj/structure/crematorium/Destroy() + if(connected) + qdel(connected) + connected = null + if(wifi_receiver) + qdel(wifi_receiver) + wifi_receiver = null + return ..() + +/obj/structure/crematorium/proc/update() + if (src.connected) + src.icon_state = "crema0" + else + if (src.contents.len) + src.icon_state = "crema2" + else + src.icon_state = "crema1" + return + +/obj/structure/crematorium/ex_act(severity) + switch(severity) + if(1.0) + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.loc) + ex_act(severity) + qdel(src) + return + if(2.0) + if (prob(50)) + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.loc) + ex_act(severity) + qdel(src) + return + if(3.0) + if (prob(5)) + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.loc) + ex_act(severity) + qdel(src) + return + return + +/obj/structure/crematorium/attack_hand(mob/user as mob) +// if (cremating) AWW MAN! THIS WOULD BE SO MUCH MORE FUN ... TO WATCH +// user.show_message("Uh-oh, that was a bad idea.", 1) +// to_chat(usr, "Uh-oh, that was a bad idea.") +// src:loc:poison += 20000000 +// src:loc:firelevel = src:loc:poison +// return + if (cremating) + to_chat(usr, "It's locked.") + return + if ((src.connected) && (src.locked == 0)) + for(var/atom/movable/A as mob|obj in src.connected.loc) + if (!( A.anchored )) + A.forceMove(src) + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + //src.connected = null + qdel(src.connected) + else if (src.locked == 0) + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + src.connected = new /obj/structure/c_tray( src.loc ) + step(src.connected, SOUTH) + src.connected.layer = OBJ_LAYER + var/turf/T = get_step(src, SOUTH) + if (T.contents.Find(src.connected)) + src.connected.connected = src + src.icon_state = "crema0" + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.connected.loc) + src.connected.icon_state = "cremat" + else + //src.connected = null + qdel(src.connected) + src.add_fingerprint(user) + update() + +/obj/structure/crematorium/attackby(P as obj, mob/user as mob) + if (istype(P, /obj/item/weapon/pen)) + var/t = input(user, "What would you like the label to be?", text("[]", src.name), null) as text + if (user.get_active_hand() != P) + return + if ((!in_range(src, usr) > 1 && src.loc != user)) + return + t = sanitizeSafe(t, MAX_NAME_LEN) + if (t) + src.SetName(text("Crematorium- '[]'", t)) + else + src.SetName("Crematorium") + src.add_fingerprint(user) + return + +/obj/structure/crematorium/relaymove(mob/user as mob) + if (user.stat || locked) + return + src.connected = new /obj/structure/c_tray( src.loc ) + step(src.connected, SOUTH) + src.connected.layer = OBJ_LAYER + var/turf/T = get_step(src, SOUTH) + if (T.contents.Find(src.connected)) + src.connected.connected = src + src.icon_state = "crema0" + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.connected.loc) + src.connected.icon_state = "cremat" + else + qdel(src.connected) + src.connected = null + return + +/obj/structure/crematorium/proc/cremate(atom/A, mob/user as mob) +// for(var/obj/machinery/crema_switch/O in src) //trying to figure a way to call the switch, too drunk to sort it out atm +// if(var/on == 1) +// return + if(cremating) + return //don't let you cremate something twice or w/e + + if(contents.len <= 0) + for (var/mob/M in viewers(src)) + M.show_message("You hear a hollow crackle.", 1) + return + + else + if(!isemptylist(src.search_contents_for(/obj/item/weapon/disk/nuclear))) + to_chat(usr, "You get the feeling that you shouldn't cremate one of the items in the cremator.") + return + + for (var/mob/M in viewers(src)) + M.show_message("You hear a roar as the crematorium activates.", 1) + + cremating = 1 + locked = 1 + + for(var/mob/living/M in contents) + if (M.stat!=2) + if (!iscarbon(M)) + M.emote("scream") + else + var/mob/living/carbon/C = M + if (C.can_feel_pain()) + C.emote("scream") + + //Logging for this causes runtimes resulting in the cremator locking up. Commenting it out until that's figured out. + //M.attack_log += "\[[time_stamp()]\] Has been cremated by [user]/[user.ckey]" //No point in this when the mob's about to be deleted + //user.attack_log +="\[[time_stamp()]\] Cremated [M]/[M.ckey]" + //log_attack("\[[time_stamp()]\] [user]/[user.ckey] cremated [M]/[M.ckey]") + M.death(1) + M.ghostize() + qdel(M) + + for(var/obj/O in contents) //obj instead of obj/item so that bodybags and ashes get destroyed. We dont want tons and tons of ash piling up + qdel(O) + + new /obj/effect/decal/cleanable/ash(src) + sleep(30) + cremating = 0 + locked = 0 + playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) + return + + +/* + * Crematorium tray + */ +/obj/structure/c_tray + name = "crematorium tray" + desc = "Apply body before burning." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "cremat" + density = 1 + layer = BELOW_OBJ_LAYER + var/obj/structure/crematorium/connected = null + anchored = 1 + throwpass = 1 + +/obj/structure/c_tray/Destroy() + if(connected && connected.connected == src) + connected.connected = null + connected = null + return ..() + +/obj/structure/c_tray/attack_hand(mob/user as mob) + if (src.connected) + for(var/atom/movable/A as mob|obj in src.loc) + if (!( A.anchored )) + A.forceMove(src.connected) + //Foreach goto(26) + src.connected.connected = null + src.connected.update() + add_fingerprint(user) + //SN src = null + qdel(src) + return + return + +/obj/structure/c_tray/MouseDrop_T(atom/movable/O as mob|obj, mob/user as mob) + if ((!( istype(O, /atom/movable) ) || O.anchored || get_dist(user, src) > 1 || get_dist(user, O) > 1 || user.contents.Find(src) || user.contents.Find(O))) + return + if (!ismob(O) && !istype(O, /obj/structure/closet/body_bag)) + return + if (!ismob(user) || user.stat || user.lying || user.stunned) + return + O.forceMove(src.loc) + if (user != O) + for(var/mob/B in viewers(user, 3)) + if ((B.client && !( B.blinded ))) + to_chat(B, text("[] stuffs [] into []!", user, O, src)) + //Foreach goto(99) + return + +/obj/machinery/button/crematorium + name = "crematorium igniter" + desc = "Burn baby burn!" + icon = 'icons/obj/power.dmi' + icon_state = "crema_switch" + //req_access = list(access_crematorium) + id = 1 + +/obj/machinery/button/crematorium/update_icon() + return + +/obj/machinery/button/crematorium/attack_hand(mob/user as mob) + if(..()) + return + if(src.allowed(user)) + for (var/obj/structure/crematorium/C in world) + if (C.id == id) + if (!C.cremating) + C.cremate(user) + else + to_chat(usr, "Access denied.") diff --git a/code/game/objects/structures/musician.dm b/code/game/objects/structures/musician.dm new file mode 100644 index 00000000..1442a126 --- /dev/null +++ b/code/game/objects/structures/musician.dm @@ -0,0 +1,441 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/datum/song + var/name = "Untitled" + var/list/lines = new() + var/tempo = 5 + +/obj/structure/device/piano + name = "space minimoog" + icon = 'icons/obj/musician.dmi' + icon_state = "minimoog" + anchored = 1 + density = 1 + var/datum/song/song + var/playing = 0 + var/help = 0 + var/edit = 1 + var/repeat = 0 + +/obj/structure/device/piano/New() + if(prob(50)) + name = "space minimoog" + desc = "This is a minimoog, like a space piano, but more spacey!" + icon_state = "minimoog" + else + name = "space piano" + desc = "This is a space piano, like a regular piano, but always in tune! Even if the musician isn't." + icon_state = "piano" + +/obj/structure/device/piano/proc/playnote(var/note as text) +// log_debug("Note: [note]") + + var/soundfile + /*BYOND loads resource files at compile time if they are ''. This means you can't really manipulate them dynamically. + Tried doing it dynamically at first but its more trouble than its worth. Would have saved many lines tho.*/ + switch(note) + if("Cn1") soundfile = 'sound/piano/Cn1.ogg' + if("C#1") soundfile = 'sound/piano/C#1.ogg' + if("Db1") soundfile = 'sound/piano/Db1.ogg' + if("Dn1") soundfile = 'sound/piano/Dn1.ogg' + if("D#1") soundfile = 'sound/piano/D#1.ogg' + if("Eb1") soundfile = 'sound/piano/Eb1.ogg' + if("En1") soundfile = 'sound/piano/En1.ogg' + if("E#1") soundfile = 'sound/piano/E#1.ogg' + if("Fb1") soundfile = 'sound/piano/Fb1.ogg' + if("Fn1") soundfile = 'sound/piano/Fn1.ogg' + if("F#1") soundfile = 'sound/piano/F#1.ogg' + if("Gb1") soundfile = 'sound/piano/Gb1.ogg' + if("Gn1") soundfile = 'sound/piano/Gn1.ogg' + if("G#1") soundfile = 'sound/piano/G#1.ogg' + if("Ab1") soundfile = 'sound/piano/Ab1.ogg' + if("An1") soundfile = 'sound/piano/An1.ogg' + if("A#1") soundfile = 'sound/piano/A#1.ogg' + if("Bb1") soundfile = 'sound/piano/Bb1.ogg' + if("Bn1") soundfile = 'sound/piano/Bn1.ogg' + if("B#1") soundfile = 'sound/piano/B#1.ogg' + if("Cb2") soundfile = 'sound/piano/Cb2.ogg' + if("Cn2") soundfile = 'sound/piano/Cn2.ogg' + if("C#2") soundfile = 'sound/piano/C#2.ogg' + if("Db2") soundfile = 'sound/piano/Db2.ogg' + if("Dn2") soundfile = 'sound/piano/Dn2.ogg' + if("D#2") soundfile = 'sound/piano/D#2.ogg' + if("Eb2") soundfile = 'sound/piano/Eb2.ogg' + if("En2") soundfile = 'sound/piano/En2.ogg' + if("E#2") soundfile = 'sound/piano/E#2.ogg' + if("Fb2") soundfile = 'sound/piano/Fb2.ogg' + if("Fn2") soundfile = 'sound/piano/Fn2.ogg' + if("F#2") soundfile = 'sound/piano/F#2.ogg' + if("Gb2") soundfile = 'sound/piano/Gb2.ogg' + if("Gn2") soundfile = 'sound/piano/Gn2.ogg' + if("G#2") soundfile = 'sound/piano/G#2.ogg' + if("Ab2") soundfile = 'sound/piano/Ab2.ogg' + if("An2") soundfile = 'sound/piano/An2.ogg' + if("A#2") soundfile = 'sound/piano/A#2.ogg' + if("Bb2") soundfile = 'sound/piano/Bb2.ogg' + if("Bn2") soundfile = 'sound/piano/Bn2.ogg' + if("B#2") soundfile = 'sound/piano/B#2.ogg' + if("Cb3") soundfile = 'sound/piano/Cb3.ogg' + if("Cn3") soundfile = 'sound/piano/Cn3.ogg' + if("C#3") soundfile = 'sound/piano/C#3.ogg' + if("Db3") soundfile = 'sound/piano/Db3.ogg' + if("Dn3") soundfile = 'sound/piano/Dn3.ogg' + if("D#3") soundfile = 'sound/piano/D#3.ogg' + if("Eb3") soundfile = 'sound/piano/Eb3.ogg' + if("En3") soundfile = 'sound/piano/En3.ogg' + if("E#3") soundfile = 'sound/piano/E#3.ogg' + if("Fb3") soundfile = 'sound/piano/Fb3.ogg' + if("Fn3") soundfile = 'sound/piano/Fn3.ogg' + if("F#3") soundfile = 'sound/piano/F#3.ogg' + if("Gb3") soundfile = 'sound/piano/Gb3.ogg' + if("Gn3") soundfile = 'sound/piano/Gn3.ogg' + if("G#3") soundfile = 'sound/piano/G#3.ogg' + if("Ab3") soundfile = 'sound/piano/Ab3.ogg' + if("An3") soundfile = 'sound/piano/An3.ogg' + if("A#3") soundfile = 'sound/piano/A#3.ogg' + if("Bb3") soundfile = 'sound/piano/Bb3.ogg' + if("Bn3") soundfile = 'sound/piano/Bn3.ogg' + if("B#3") soundfile = 'sound/piano/B#3.ogg' + if("Cb4") soundfile = 'sound/piano/Cb4.ogg' + if("Cn4") soundfile = 'sound/piano/Cn4.ogg' + if("C#4") soundfile = 'sound/piano/C#4.ogg' + if("Db4") soundfile = 'sound/piano/Db4.ogg' + if("Dn4") soundfile = 'sound/piano/Dn4.ogg' + if("D#4") soundfile = 'sound/piano/D#4.ogg' + if("Eb4") soundfile = 'sound/piano/Eb4.ogg' + if("En4") soundfile = 'sound/piano/En4.ogg' + if("E#4") soundfile = 'sound/piano/E#4.ogg' + if("Fb4") soundfile = 'sound/piano/Fb4.ogg' + if("Fn4") soundfile = 'sound/piano/Fn4.ogg' + if("F#4") soundfile = 'sound/piano/F#4.ogg' + if("Gb4") soundfile = 'sound/piano/Gb4.ogg' + if("Gn4") soundfile = 'sound/piano/Gn4.ogg' + if("G#4") soundfile = 'sound/piano/G#4.ogg' + if("Ab4") soundfile = 'sound/piano/Ab4.ogg' + if("An4") soundfile = 'sound/piano/An4.ogg' + if("A#4") soundfile = 'sound/piano/A#4.ogg' + if("Bb4") soundfile = 'sound/piano/Bb4.ogg' + if("Bn4") soundfile = 'sound/piano/Bn4.ogg' + if("B#4") soundfile = 'sound/piano/B#4.ogg' + if("Cb5") soundfile = 'sound/piano/Cb5.ogg' + if("Cn5") soundfile = 'sound/piano/Cn5.ogg' + if("C#5") soundfile = 'sound/piano/C#5.ogg' + if("Db5") soundfile = 'sound/piano/Db5.ogg' + if("Dn5") soundfile = 'sound/piano/Dn5.ogg' + if("D#5") soundfile = 'sound/piano/D#5.ogg' + if("Eb5") soundfile = 'sound/piano/Eb5.ogg' + if("En5") soundfile = 'sound/piano/En5.ogg' + if("E#5") soundfile = 'sound/piano/E#5.ogg' + if("Fb5") soundfile = 'sound/piano/Fb5.ogg' + if("Fn5") soundfile = 'sound/piano/Fn5.ogg' + if("F#5") soundfile = 'sound/piano/F#5.ogg' + if("Gb5") soundfile = 'sound/piano/Gb5.ogg' + if("Gn5") soundfile = 'sound/piano/Gn5.ogg' + if("G#5") soundfile = 'sound/piano/G#5.ogg' + if("Ab5") soundfile = 'sound/piano/Ab5.ogg' + if("An5") soundfile = 'sound/piano/An5.ogg' + if("A#5") soundfile = 'sound/piano/A#5.ogg' + if("Bb5") soundfile = 'sound/piano/Bb5.ogg' + if("Bn5") soundfile = 'sound/piano/Bn5.ogg' + if("B#5") soundfile = 'sound/piano/B#5.ogg' + if("Cb6") soundfile = 'sound/piano/Cb6.ogg' + if("Cn6") soundfile = 'sound/piano/Cn6.ogg' + if("C#6") soundfile = 'sound/piano/C#6.ogg' + if("Db6") soundfile = 'sound/piano/Db6.ogg' + if("Dn6") soundfile = 'sound/piano/Dn6.ogg' + if("D#6") soundfile = 'sound/piano/D#6.ogg' + if("Eb6") soundfile = 'sound/piano/Eb6.ogg' + if("En6") soundfile = 'sound/piano/En6.ogg' + if("E#6") soundfile = 'sound/piano/E#6.ogg' + if("Fb6") soundfile = 'sound/piano/Fb6.ogg' + if("Fn6") soundfile = 'sound/piano/Fn6.ogg' + if("F#6") soundfile = 'sound/piano/F#6.ogg' + if("Gb6") soundfile = 'sound/piano/Gb6.ogg' + if("Gn6") soundfile = 'sound/piano/Gn6.ogg' + if("G#6") soundfile = 'sound/piano/G#6.ogg' + if("Ab6") soundfile = 'sound/piano/Ab6.ogg' + if("An6") soundfile = 'sound/piano/An6.ogg' + if("A#6") soundfile = 'sound/piano/A#6.ogg' + if("Bb6") soundfile = 'sound/piano/Bb6.ogg' + if("Bn6") soundfile = 'sound/piano/Bn6.ogg' + if("B#6") soundfile = 'sound/piano/B#6.ogg' + if("Cb7") soundfile = 'sound/piano/Cb7.ogg' + if("Cn7") soundfile = 'sound/piano/Cn7.ogg' + if("C#7") soundfile = 'sound/piano/C#7.ogg' + if("Db7") soundfile = 'sound/piano/Db7.ogg' + if("Dn7") soundfile = 'sound/piano/Dn7.ogg' + if("D#7") soundfile = 'sound/piano/D#7.ogg' + if("Eb7") soundfile = 'sound/piano/Eb7.ogg' + if("En7") soundfile = 'sound/piano/En7.ogg' + if("E#7") soundfile = 'sound/piano/E#7.ogg' + if("Fb7") soundfile = 'sound/piano/Fb7.ogg' + if("Fn7") soundfile = 'sound/piano/Fn7.ogg' + if("F#7") soundfile = 'sound/piano/F#7.ogg' + if("Gb7") soundfile = 'sound/piano/Gb7.ogg' + if("Gn7") soundfile = 'sound/piano/Gn7.ogg' + if("G#7") soundfile = 'sound/piano/G#7.ogg' + if("Ab7") soundfile = 'sound/piano/Ab7.ogg' + if("An7") soundfile = 'sound/piano/An7.ogg' + if("A#7") soundfile = 'sound/piano/A#7.ogg' + if("Bb7") soundfile = 'sound/piano/Bb7.ogg' + if("Bn7") soundfile = 'sound/piano/Bn7.ogg' + if("B#7") soundfile = 'sound/piano/B#7.ogg' + if("Cb8") soundfile = 'sound/piano/Cb8.ogg' + if("Cn8") soundfile = 'sound/piano/Cn8.ogg' + if("C#8") soundfile = 'sound/piano/C#8.ogg' + if("Db8") soundfile = 'sound/piano/Db8.ogg' + if("Dn8") soundfile = 'sound/piano/Dn8.ogg' + if("D#8") soundfile = 'sound/piano/D#8.ogg' + if("Eb8") soundfile = 'sound/piano/Eb8.ogg' + if("En8") soundfile = 'sound/piano/En8.ogg' + if("E#8") soundfile = 'sound/piano/E#8.ogg' + if("Fb8") soundfile = 'sound/piano/Fb8.ogg' + if("Fn8") soundfile = 'sound/piano/Fn8.ogg' + if("F#8") soundfile = 'sound/piano/F#8.ogg' + if("Gb8") soundfile = 'sound/piano/Gb8.ogg' + if("Gn8") soundfile = 'sound/piano/Gn8.ogg' + if("G#8") soundfile = 'sound/piano/G#8.ogg' + if("Ab8") soundfile = 'sound/piano/Ab8.ogg' + if("An8") soundfile = 'sound/piano/An8.ogg' + if("A#8") soundfile = 'sound/piano/A#8.ogg' + if("Bb8") soundfile = 'sound/piano/Bb8.ogg' + if("Bn8") soundfile = 'sound/piano/Bn8.ogg' + if("B#8") soundfile = 'sound/piano/B#8.ogg' + if("Cb9") soundfile = 'sound/piano/Cb9.ogg' + if("Cn9") soundfile = 'sound/piano/Cn9.ogg' + else return + +// sound_to(hearers(15, src), sound(soundfile)) + + var/turf/source = get_turf(src) + for(var/mob/M in hearers(15, source)) + M.playsound_local(source, file(soundfile), 100, falloff = 5) + + +/obj/structure/device/piano/proc/playsong() + do + var/cur_oct[7] + var/cur_acc[7] + for(var/i = 1 to 7) + cur_oct[i] = "3" + cur_acc[i] = "n" + + for(var/line in song.lines) +// log_debug(line) + + for(var/beat in splittext(lowertext(line), ",")) +// log_debug("beat: [beat]") + + var/list/notes = splittext(beat, "/") + for(var/note in splittext(notes[1], "-")) +// log_debug("note: [note]") + + if(!playing || !anchored)//If the piano is playing, or is loose + playing = 0 + return + if(length(note) == 0) + continue +// log_debug("Parse: [copytext(note,1,2)]") + + var/cur_note = text2ascii(note) - 96 + if(cur_note < 1 || cur_note > 7) + continue + for(var/i=2 to length(note)) + var/ni = copytext(note,i,i+1) + if(!text2num(ni)) + if(ni == "#" || ni == "b" || ni == "n") + cur_acc[cur_note] = ni + else if(ni == "s") + cur_acc[cur_note] = "#" // so shift is never required + else + cur_oct[cur_note] = ni + playnote(uppertext(copytext(note,1,2)) + cur_acc[cur_note] + cur_oct[cur_note]) + if(notes.len >= 2 && text2num(notes[2])) + sleep(song.tempo / text2num(notes[2])) + else + sleep(song.tempo) + if(repeat > 0) + repeat-- //Infinite loops are baaaad. + while(repeat > 0) + playing = 0 + updateUsrDialog() + +/obj/structure/device/piano/attack_hand(var/mob/user as mob) + if(!anchored) + return + + usr.machine = src + var/dat = "Piano" + + if(song) + if(song.lines.len > 0 && !(playing)) + dat += "Play Song

            " + dat += "Repeat Song: [repeat] times.

            " + if(playing) + dat += "Stop Playing
            " + dat += "Repeats left: [repeat].

            " + if(!edit) + dat += "Show Editor

            " + else + dat += "Hide Editor
            " + dat += "Start a New Song
            " + dat += "Import a Song

            " + if(song) + var/calctempo = (10/song.tempo)*60 + dat += "Tempo : -- [calctempo] BPM ++

            " + var/linecount = 0 + for(var/line in song.lines) + linecount += 1 + dat += "Line [linecount]: [line] Delete Line Modify Line
            " + dat += "Add Line

            " + if(help) + dat += "Hide Help
            " + dat += {" + Lines are a series of chords, separated by commas (,), each with notes seperated by hyphens (-).
            + Every note in a chord will play together, with chord timed by the tempo.
            +
            + Notes are played by the names of the note, and optionally, the accidental, and/or the octave number.
            + By default, every note is natural and in octave 3. Defining otherwise is remembered for each note.
            + Example: C,D,E,F,G,A,B will play a C major scale.
            + After a note has an accidental placed, it will be remembered: C,C4,C,C3 is C3,C4,C4,C3
            + Chords can be played simply by seperating each note with a hyphon: A-C#,Cn-E,E-G#,Gn-B
            + A pause may be denoted by an empty chord: C,E,,C,G
            + To make a chord be a different time, end it with /x, where the chord length will be length
            + defined by tempo / x: C,G/2,E/4
            + Combined, an example is: E-E4/4,/2,G#/8,B/8,E3-E4/4 +
            + Lines may be up to 50 characters.
            + A song may only contain up to 50 lines.
            + "} + else + dat += "Show Help
            " + dat += "" + user << browse(dat, "window=piano;size=700x300") + onclose(user, "piano") + +/obj/structure/device/piano/Topic(href, href_list) + + if(!in_range(src, usr) || issilicon(usr) || !anchored || !usr.canmove || usr.restrained()) + usr << browse(null, "window=piano;size=700x300") + onclose(usr, "piano") + return + + if(href_list["newsong"]) + song = new() + else if(song) + if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops. + if(playing) return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing. + var/tempnum = input("How many times do you want to repeat this piece? (max:10)") as num|null + if(tempnum > 10) + tempnum = 10 + if(tempnum < 0) + tempnum = 0 + repeat = round(tempnum) + + else if(href_list["tempo"]) + song.tempo += round(text2num(href_list["tempo"])) + if(song.tempo < 1) + song.tempo = 1 + + else if(href_list["play"]) + if(song) + playing = 1 + spawn() playsong() + + else if(href_list["newline"]) + var/newline = html_encode(input("Enter your line: ", "Piano") as text|null) + if(!newline) + return + if(song.lines.len > 50) + return + if(length(newline) > 50) + newline = copytext(newline, 1, 50) + song.lines.Add(newline) + + else if(href_list["deleteline"]) + var/num = round(text2num(href_list["deleteline"])) + if(num > song.lines.len || num < 1) + return + song.lines.Cut(num, num+1) + + else if(href_list["modifyline"]) + var/num = round(text2num(href_list["modifyline"]),1) + var/content = html_encode(input("Enter your line: ", "Piano", song.lines[num]) as text|null) + if(!content) + return + if(length(content) > 50) + content = copytext(content, 1, 50) + if(num > song.lines.len || num < 1) + return + song.lines[num] = content + + else if(href_list["stop"]) + playing = 0 + + else if(href_list["help"]) + help = text2num(href_list["help"]) - 1 + + else if(href_list["edit"]) + edit = text2num(href_list["edit"]) - 1 + + else if(href_list["import"]) + var/t = "" + do + t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", src.name), t) as message) + if (!in_range(src, usr)) + return + + if(length(t) >= 3072) + var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no") + if(cont == "no") + break + while(length(t) > 3072) + + //split into lines + spawn() + var/list/lines = splittext(t, "\n") + var/tempo = 5 + if(copytext(lines[1],1,6) == "BPM: ") + tempo = 600 / text2num(copytext(lines[1],6)) + lines.Cut(1,2) + if(lines.len > 50) + to_chat(usr, "Too many lines!") + lines.Cut(51) + var/linenum = 1 + for(var/l in lines) + if(length(l) > 50) + to_chat(usr, "Line [linenum] too long!") + lines.Remove(l) + else + linenum++ + song = new() + song.lines = lines + song.tempo = tempo + updateUsrDialog() + + add_fingerprint(usr) + updateUsrDialog() + return + +/obj/structure/device/piano/attackby(obj/item/O as obj, mob/user as mob) + if(isWrench(O)) + if (anchored) + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to loosen \the [src]'s casters...") + if (do_after(user, 40, src)) + user.visible_message( \ + "[user] loosens \the [src]'s casters.", \ + "You have loosened \the [src]. Now it can be pulled somewhere else.", \ + "You hear ratchet.") + src.anchored = 0 + else + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to tighten \the [src] to the floor...") + if (do_after(user, 20, src)) + user.visible_message( \ + "[user] tightens \the [src]'s casters.", \ + "You have tightened \the [src]'s casters. Now it can be played again.", \ + "You hear ratchet.") + src.anchored = 1 + else + ..() diff --git a/code/game/objects/structures/noticeboard.dm b/code/game/objects/structures/noticeboard.dm new file mode 100644 index 00000000..77d7f4be --- /dev/null +++ b/code/game/objects/structures/noticeboard.dm @@ -0,0 +1,86 @@ +/obj/structure/noticeboard + name = "notice board" + desc = "A board for pinning important notices upon." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "nboard00" + density = 0 + anchored = 1 + var/notices = 0 + +/obj/structure/noticeboard/Initialize() + for(var/obj/item/I in loc) + if(notices > 4) break + if(istype(I, /obj/item/weapon/paper)) + I.forceMove(src) + notices++ + icon_state = "nboard0[notices]" + . = ..() + +//attaching papers!! +/obj/structure/noticeboard/attackby(var/obj/item/weapon/O as obj, var/mob/user as mob) + if(istype(O, /obj/item/weapon/paper) || istype(O, /obj/item/weapon/photo)) + if(notices < 5) + O.add_fingerprint(user) + add_fingerprint(user) + user.drop_from_inventory(O,src) + notices++ + icon_state = "nboard0[notices]" //update sprite + to_chat(user, "You pin the paper to the noticeboard.") + else + to_chat(user, "You reach to pin your paper to the board but hesitate. You are certain your paper will not be seen among the many others already attached.") + +/obj/structure/noticeboard/attack_hand(var/mob/user) + examine(user) + +// Since Topic() never seems to interact with usr on more than a superficial +// level, it should be fine to let anyone mess with the board other than ghosts. +/obj/structure/noticeboard/examine(var/mob/user) + if(!user) + user = usr + if(user.Adjacent(src)) + var/dat = "Noticeboard
            " + for(var/obj/item/weapon/paper/P in src) + dat += "[P.name] Write Remove
            " + for(var/obj/item/weapon/photo/P in src) + dat += "[P.name] Remove
            " + user << browse("Notices[dat]","window=noticeboard") + onclose(user, "noticeboard") + else + ..() + +/obj/structure/noticeboard/Topic(href, href_list) + ..() + usr.set_machine(src) + if(href_list["remove"]) + if((usr.stat || usr.restrained())) //For when a player is handcuffed while they have the notice window open + return + var/obj/item/P = locate(href_list["remove"]) + if(P && P.loc == src) + P.loc = get_turf(src) //dump paper on the floor because you're a clumsy fuck + P.add_fingerprint(usr) + add_fingerprint(usr) + notices-- + icon_state = "nboard0[notices]" + if(href_list["write"]) + if((usr.stat || usr.restrained())) //For when a player is handcuffed while they have the notice window open + return + var/obj/item/P = locate(href_list["write"]) + if((P && P.loc == src)) //ifthe paper's on the board + if(istype(usr.r_hand, /obj/item/weapon/pen)) //and you're holding a pen + add_fingerprint(usr) + P.attackby(usr.r_hand, usr) //then do ittttt + else + if(istype(usr.l_hand, /obj/item/weapon/pen)) //check other hand for pen + add_fingerprint(usr) + P.attackby(usr.l_hand, usr) + else + to_chat(usr, "You'll need something to write with!") + if(href_list["read"]) + var/obj/item/weapon/paper/P = locate(href_list["read"]) + if((P && P.loc == src)) + P.show_content(usr) + if(href_list["look"]) + var/obj/item/weapon/photo/P = locate(href_list["look"]) + if((P && P.loc == src)) + P.show(usr) + return diff --git a/code/game/objects/structures/pit.dm b/code/game/objects/structures/pit.dm new file mode 100644 index 00000000..08f87caa --- /dev/null +++ b/code/game/objects/structures/pit.dm @@ -0,0 +1,169 @@ +/obj/structure/pit + name = "pit" + desc = "Watch your step, partner." + icon = 'icons/obj/pit.dmi' + icon_state = "pit1" + blend_mode = BLEND_MULTIPLY + density = 0 + anchored = 1 + var/open = 1 + +/obj/structure/pit/attackby(obj/item/W, mob/user) + if( istype(W,/obj/item/weapon/shovel) ) + visible_message("\The [user] starts [open ? "filling" : "digging open"] \the [src]") + if( do_after(user, 50) ) + visible_message("\The [user] [open ? "fills" : "digs open"] \the [src]!") + if(open) + close(user) + else + open() + else + to_chat(user, "You stop shoveling.") + return + if (!open && istype(W,/obj/item/stack/material/wood)) + if(locate(/obj/structure/gravemarker) in src.loc) + to_chat(user, "There's already a grave marker here.") + else + visible_message("\The [user] starts making a grave marker on top of \the [src]") + if( do_after(user, 50) ) + visible_message("\The [user] finishes the grave marker") + var/obj/item/stack/material/wood/plank = W + plank.use(1) + new/obj/structure/gravemarker(src.loc) + else + to_chat(user, "You stop making a grave marker.") + return + ..() + +/obj/structure/pit/update_icon() + icon_state = "pit[open]" + if(istype(loc,/turf/simulated/floor/exoplanet)) + var/turf/simulated/floor/exoplanet/E = loc + if(E.mudpit) + icon_state="pit[open]mud" + blend_mode = BLEND_OVERLAY + +/obj/structure/pit/proc/open() + name = "pit" + desc = "Watch your step, partner." + open = 1 + for(var/atom/movable/A in src) + A.forceMove(src.loc) + update_icon() + +/obj/structure/pit/proc/close(var/user) + name = "mound" + desc = "Some things are better left buried." + open = 0 + for(var/atom/movable/A in src.loc) + if(!A.anchored && A != user) + A.forceMove(src) + update_icon() + +/obj/structure/pit/return_air() + return open + +/obj/structure/pit/proc/digout(mob/escapee) + var/breakout_time = 1 //2 minutes by default + + if(open) + return + + if(escapee.stat || escapee.restrained()) + return + + escapee.setClickCooldown(100) + to_chat(escapee, "You start digging your way out of \the [src] (this will take about [breakout_time] minute\s)") + visible_message("Something is scratching its way out of \the [src]!") + + for(var/i in 1 to (6*breakout_time * 2)) //minutes * 6 * 5seconds * 2 + playsound(src.loc, 'sound/weapons/bite.ogg', 100, 1) + + if(!do_after(escapee, 50)) + to_chat(escapee, "You have stopped digging.") + return + if(open) + return + + if(i == 6*breakout_time) + to_chat(escapee, "Halfway there...") + + to_chat(escapee, "You successfuly dig yourself out!") + visible_message("\the [escapee] emerges from \the [src]!") + playsound(src.loc, 'sound/effects/squelch1.ogg', 100, 1) + open() + +/obj/structure/pit/closed + name = "mound" + desc = "Some things are better left buried." + open = 0 + +/obj/structure/pit/closed/Initialize() + . = ..() + close() + +//invisible until unearthed first +/obj/structure/pit/closed/hidden + invisibility = INVISIBILITY_OBSERVER + +/obj/structure/pit/closed/hidden/open() + ..() + set_invisibility(INVISIBILITY_LEVEL_ONE) + +//spoooky +/obj/structure/pit/closed/grave + name = "grave" + icon_state = "pit0" + +/obj/structure/pit/closed/grave/Initialize() + var/obj/structure/closet/coffin/C = new(src.loc) + var/obj/item/remains/human/bones = new(C) + bones.plane = LYING_MOB_PLANE + bones.layer = LYING_MOB_LAYER + var/obj/structure/gravemarker/random/R = new(src.loc) + R.generate() + . = ..() + +/obj/structure/gravemarker + name = "grave marker" + desc = "You're not the first." + icon = 'icons/obj/gravestone.dmi' + icon_state = "wood" + pixel_x = 15 + pixel_y = 8 + anchored = 1 + var/message = "Unknown." + +/obj/structure/gravemarker/cross + icon_state = "cross" + +/obj/structure/gravemarker/examine() + ..() + to_chat(usr,"It says: '[message]'") + +/obj/structure/gravemarker/random/Initialize() + generate() + . = ..() + +/obj/structure/gravemarker/random/proc/generate() + icon_state = pick("wood","cross") + + var/datum/species/S = all_species["Human"] + var/nam = S.get_random_name(pick(MALE,FEMALE)) + var/cur_year = text2num(time2text(world.timeofday, "YYYY"))+544 + var/born = cur_year - rand(5,150) + var/died = max(cur_year - rand(0,70),born) + + message = "Here lies [nam], [born] - [died]." + +/obj/structure/gravemarker/attackby(obj/item/W, mob/user) + if(istype(W,/obj/item/weapon/material/hatchet)) + visible_message("\The [user] starts hacking away at \the [src] with \the [W].") + if(!do_after(user, 30)) + visible_message("\The [user] hacks \the [src] apart.") + new /obj/item/stack/material/wood(src) + qdel(src) + if(istype(W,/obj/item/weapon/pen)) + var/msg = sanitize(input(user, "What should it say?", "Grave marker", message) as text|null) + if(msg) + message = msg \ No newline at end of file diff --git a/code/game/objects/structures/railing.dm b/code/game/objects/structures/railing.dm new file mode 100644 index 00000000..ac53e942 --- /dev/null +++ b/code/game/objects/structures/railing.dm @@ -0,0 +1,336 @@ +//Snowflake proc for railings +/obj/structure/proc/neighbor_turf_passable() + var/turf/T = get_step(src, src.dir) + if(!T || !istype(T)) + return 0 + if(T.density == 1) + return 0 + for(var/obj/O in T.contents) + if(istype(O,/obj/structure)) + if(istype(O,/obj/structure/railing)) + return 1 + else if(O.density == 1) + return 0 + return 1 + +//actually railing code +/obj/structure/railing + name = "railing" + desc = "A standard steel railing. Prevents human stupidity." + icon = 'icons/obj/railing.dmi' + density = 1 + throwpass = 1 + //layer = 3.2//Just above doors //Layers mean nothing. + plane = ABOVE_HUMAN_PLANE // They go ontop of humans. + //pressure_resistance = 4*ONE_ATMOSPHERE + anchored = 1 + atom_flags = ATOM_FLAG_CLIMBABLE|ATOM_FLAG_CHECKS_BORDER + icon_state = "railing0" + var/broken = 0 + var/health=70 + var/maxhealth=70 + var/check = 0 + +/obj/structure/railing/New(loc, constructed=0) + ..() + if (constructed) //player-constructed railings + anchored = 0 + if(src.anchored) + spawn(5) + update_icon(0) + +/obj/structure/railing/Destroy() + anchored = null + atom_flags = null + broken = 1 + for(var/obj/structure/railing/R in oview(src, 1)) + R.update_icon() + ..() + +/obj/structure/railing/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(!mover) + return TRUE + + if(istype(mover) && mover.checkpass(PASS_FLAG_TABLE)) + return TRUE + + if (locate(/obj/structure/table) in get_turf(mover)) + return TRUE + + if(get_dir(loc, target) == dir) + return !density + else + return TRUE + + + +/obj/structure/railing/examine(mob/user) + . = ..() + if(health < maxhealth) + switch(health / maxhealth) + if(0.0 to 0.5) + to_chat(user, "It looks severely damaged!") + if(0.25 to 0.5) + to_chat(user,"It looks damaged!") + if(0.5 to 1.0) + to_chat(user, "It has a few scrapes and dents.") + +/obj/structure/railing/proc/take_damage(amount) + health -= amount + if(health <= 0) + visible_message("\The [src] breaks down!") + playsound(loc, 'sound/effects/grillehit.ogg', 50, 1) + new /obj/item/stack/rods(get_turf(usr)) + qdel(src) + +/obj/structure/railing/proc/NeighborsCheck(var/UpdateNeighbors = 1) + check = 0 + //if (!anchored) return + var/Rturn = turn(src.dir, -90) + var/Lturn = turn(src.dir, 90) + for(var/obj/structure/railing/R in src.loc) + if ((R.dir == Lturn) && R.anchored) + //src.LeftSide[1] = 1 + check |= 32 + if (UpdateNeighbors) + R.update_icon(0) + if ((R.dir == Rturn) && R.anchored) + //src.RightSide[1] = 1 + check |= 2 + if (UpdateNeighbors) + R.update_icon(0) + + for (var/obj/structure/railing/R in get_step(src, Lturn)) + if ((R.dir == src.dir) && R.anchored) + //src.LeftSide[2] = 1 + check |= 16 + if (UpdateNeighbors) + R.update_icon(0) + for (var/obj/structure/railing/R in get_step(src, Rturn)) + if ((R.dir == src.dir) && R.anchored) + //src.RightSide[2] = 1 + check |= 1 + if (UpdateNeighbors) + R.update_icon(0) + + for (var/obj/structure/railing/R in get_step(src, (Lturn + src.dir))) + if ((R.dir == Rturn) && R.anchored) + check |= 64 + if (UpdateNeighbors) + R.update_icon(0) + for (var/obj/structure/railing/R in get_step(src, (Rturn + src.dir))) + if ((R.dir == Lturn) && R.anchored) + check |= 4 + if (UpdateNeighbors) + R.update_icon(0) + + +/obj/structure/railing/update_icon(var/UpdateNeighgors = 1) + NeighborsCheck(UpdateNeighgors) + overlays.Cut() + if (!check || !anchored) + icon_state = "railing0" + else + icon_state = "railing1" + if (check & 32) + overlays += image ('icons/obj/railing.dmi', src, "corneroverlay") + if ((check & 16) || !(check & 32) || (check & 64)) + overlays += image ('icons/obj/railing.dmi', src, "frontoverlay_l") + if (!(check & 2) || (check & 1) || (check & 4)) + overlays += image ('icons/obj/railing.dmi', src, "frontoverlay_r") + if(check & 4) + switch (src.dir) + if (NORTH) + overlays += image ('icons/obj/railing.dmi', src, "mcorneroverlay", pixel_x = 32) + if (SOUTH) + overlays += image ('icons/obj/railing.dmi', src, "mcorneroverlay", pixel_x = -32) + if (EAST) + overlays += image ('icons/obj/railing.dmi', src, "mcorneroverlay", pixel_y = -32) + if (WEST) + overlays += image ('icons/obj/railing.dmi', src, "mcorneroverlay", pixel_y = 32) + + + +/obj/structure/railing/proc/rotate() + set name = "Rotate Railing Counter-Clockwise" + set category = "Object" + + if(usr.incapacitated()) + return 0 + + if(anchored) + usr << "It is fastened to the floor therefore you can't rotate it!" + return 0 + + set_dir(turn(dir, 90)) + update_icon() + return + +/obj/structure/railing/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + rotate() + +/obj/structure/railing/verb/revrotate() + set name = "Rotate Railing Clockwise" + set category = "Object" + set src in oview(1) + + if(usr.incapacitated()) + return 0 + + if(anchored) + usr << "It is fastened to the floor therefore you can't rotate it!" + return 0 + + set_dir(turn(dir, -90)) + update_icon() + return + +/obj/structure/railing/verb/flip() // This will help push railing to remote places, such as open space turfs + set name = "Flip Railing" + set category = "Object" + set src in oview(1) + + if(usr.incapacitated()) + return 0 + + if(anchored) + usr << "It is fastened to the floor therefore you can't flip it!" + return 0 + + if(!neighbor_turf_passable()) + usr << "You can't flip the [src] because something blocking it." + return 0 + + src.loc = get_step(src, src.dir) + set_dir(turn(dir, 180)) + update_icon() + return + +/obj/structure/railing/CheckExit(atom/movable/O as mob|obj, target as turf) + if(istype(O) && O.checkpass(PASS_FLAG_TABLE)) + return 1 + if(get_dir(O.loc, target) == dir) + return 0 + return 1 + +/obj/structure/railing/attackby(obj/item/W as obj, mob/user as mob) + // Dismantle + if(istype(W, /obj/item/weapon/wrench) && !anchored) + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + if(do_after(user, 20, src)) + user.visible_message("\The [user] dismantles \the [src].", "You dismantle \the [src].") + new /obj/item/stack/material/steel(get_turf(usr)) + new /obj/item/stack/material/steel(get_turf(usr)) + qdel(src) + return + + // Repair + if(health < maxhealth && istype(W, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/F = W + if(F.welding) + playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) + if(do_after(user, 20, src)) + user.visible_message("\The [user] repairs some damage to \the [src].", "You repair some damage to \the [src].") + health = min(health+(maxhealth/5), maxhealth)//max(health+(maxhealth/5), maxhealth) // 20% repair per application + return + + // Install + if(istype(W, /obj/item/weapon/screwdriver)) + user.visible_message(anchored ? "\The [user] begins unscrew \the [src]." : "\The [user] begins fasten \the [src]." ) + playsound(loc, 'sound/items/Screwdriver.ogg', 75, 1) + if(do_after(user, 10, src)) + user << (anchored ? "You have unfastened \the [src] from the floor." : "You have fastened \the [src] to the floor.") + anchored = !anchored + update_icon() + return + + // Handle harm intent grabbing/tabling. + if(istype(W, /obj/item/grab) && get_dist(src,user)<2) + var/obj/item/grab/G = W + if (istype(G.affecting, /mob/living)) + var/mob/living/M = G.affecting + var/obj/occupied = turf_is_crowded() + if(occupied) + user << "There's \a [occupied] in the way." + return + if (G.current_grab < 2) + if(user.a_intent == I_HURT) + if (prob(15)) M.Weaken(5) + M.apply_damage(8,def_zone = "head") + take_damage(8) + visible_message("[G.assailant] slams [G.affecting]'s face against \the [src]!") + playsound(loc, 'sound/effects/grillehit.ogg', 50, 1) + else + user << "You need a better grip to do that!" + return + else + if (get_turf(G.affecting) == get_turf(src)) + G.affecting.forceMove(get_step(src, src.dir)) + else + G.affecting.forceMove(get_turf(src)) + G.affecting.Weaken(5) + visible_message("[G.assailant] throws [G.affecting] over \the [src]!") + qdel(W) + return + + else + playsound(loc, 'sound/effects/grillehit.ogg', 50, 1) + take_damage(W.force) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + + return ..() + +/obj/structure/railing/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + qdel(src) + return + if(3.0) + qdel(src) + return + else + return + +/obj/structure/railing/do_climb(var/mob/living/user) + if(!can_climb(user)) + return + + usr.visible_message("[user] starts climbing onto \the [src]!") + climbers |= user + + if(!do_after(user,(issmall(user) ? 20 : 34))) + climbers -= user + return + + if(!can_climb(user, post_climb_check=1)) + climbers -= user + return + + if(!neighbor_turf_passable()) + user << "You can't climb there, the way is blocked." + climbers -= user + return + + if(get_turf(user) == get_turf(src)) + usr.forceMove(get_step(src, src.dir)) + else + usr.forceMove(get_turf(src)) + + usr.visible_message("[user] climbed over \the [src]!") + if(!anchored) take_damage(maxhealth) // Fatboy + climbers -= user + + +/obj/structure/railing/can_climb(var/mob/living/user, post_climb_check=0) + if (!(atom_flags & ATOM_FLAG_CLIMBABLE) || !can_touch(user) || (!post_climb_check && (user in climbers))) + return 0 + + if (!user.Adjacent(src)) + to_chat(user, "You can't climb there, the way is blocked.") + return 0 + + return 1 \ No newline at end of file diff --git a/code/game/objects/structures/rubble.dm b/code/game/objects/structures/rubble.dm new file mode 100644 index 00000000..7376ca5f --- /dev/null +++ b/code/game/objects/structures/rubble.dm @@ -0,0 +1,103 @@ +/obj/structure/rubble + name = "pile of rubble" + desc = "One man's garbage is another man's treasure." + icon = 'icons/obj/rubble.dmi' + icon_state = "base" + appearance_flags = PIXEL_SCALE + opacity = 1 + density = 1 + anchored = 1 + + var/list/loot = list(/obj/item/weapon/cell,/obj/item/stack/material/iron,/obj/item/stack/rods) + var/lootleft = 2 + var/emptyprob = 30 + var/health = 40 + +/obj/structure/rubble/New() + ..() + if(prob(emptyprob)) + lootleft = 0 + +/obj/structure/rubble/Initialize() + . = ..() + update_icon() + +/obj/structure/rubble/update_icon() + overlays.Cut() + var/list/parts = list() + for(var/i = 1 to 7) + var/image/I = image(icon,"rubble[rand(1,15)]") + if(prob(10)) + var/atom/A = pick(loot) + if(initial(A.icon) && initial(A.icon_state)) + I.icon = initial(A.icon) + I.icon_state = initial(A.icon_state) + I.color = initial(A.color) + if(!lootleft) + I.color = "#54362e" + I.appearance_flags = PIXEL_SCALE + I.pixel_x = rand(-16,16) + I.pixel_y = rand(-16,16) + var/matrix/M = matrix() + M.Turn(rand(0,360)) + I.transform = M + parts += I + overlays = parts + +/obj/structure/rubble/attack_hand(mob/user) + if(!lootleft) + to_chat(user, "There's nothing left in this one but unusable garbage...") + return + visible_message("[user] starts rummaging through \the [src].") + if(do_after(user, 30)) + var/obj/item/booty = pick(loot) + booty = new booty(loc) + lootleft-- + update_icon() + to_chat(user, "You find \a [booty] and pull it carefully out of \the [src].") + +/obj/structure/rubble/attackby(var/obj/item/I, var/mob/user) + if (istype(I, /obj/item/weapon/pickaxe)) + var/obj/item/weapon/pickaxe/P = I + visible_message("[user] starts clearing away \the [src].") + if(do_after(user,P.digspeed, src)) + visible_message("[user] clears away \the [src].") + if(lootleft && prob(1)) + var/obj/item/booty = pick(loot) + booty = new booty(loc) + qdel(src) + else + ..() + health -= I.force + if(health < 1) + visible_message("[user] clears away \the [src].") + qdel(src) + +/obj/structure/rubble/house + loot = list(/obj/item/weapon/archaeological_find/bowl, + /obj/item/weapon/archaeological_find/remains/, + /obj/item/weapon/archaeological_find/bowl/urn, + /obj/item/weapon/archaeological_find/cutlery, + /obj/item/weapon/archaeological_find/statuette, + /obj/item/weapon/archaeological_find/instrument, + /obj/item/weapon/archaeological_find/container, + /obj/item/weapon/archaeological_find/mask, + /obj/item/weapon/archaeological_find/coin, + /obj/item/weapon/archaeological_find/, + /obj/item/weapon/archaeological_find/material) + +/obj/structure/rubble/war + emptyprob = 70 //can't have piles upon piles of guns + loot = list(/obj/item/weapon/archaeological_find/knife, + /obj/item/weapon/archaeological_find/remains/xeno, + /obj/item/weapon/archaeological_find/remains/robot, + /obj/item/weapon/archaeological_find/remains/, + /obj/item/weapon/archaeological_find/gun, + /obj/item/weapon/archaeological_find/laser, + /obj/item/weapon/archaeological_find/statuette, + /obj/item/weapon/archaeological_find/instrument, + /obj/item/weapon/archaeological_find/container, + /obj/item/weapon/archaeological_find/mask, + /obj/item/weapon/archaeological_find/sword, + /obj/item/weapon/archaeological_find/katana, + /obj/item/weapon/archaeological_find/trap) \ No newline at end of file diff --git a/code/game/objects/structures/safe.dm b/code/game/objects/structures/safe.dm new file mode 100644 index 00000000..8ef58ba7 --- /dev/null +++ b/code/game/objects/structures/safe.dm @@ -0,0 +1,185 @@ +/* +CONTAINS: +SAFES +FLOOR SAFES +*/ + +//SAFES +/obj/structure/safe + name = "safe" + desc = "A huge chunk of metal with a dial embedded in it. Fine print on the dial reads \"Scarborough Arms - 2 tumbler safe, guaranteed thermite resistant, explosion resistant, and assistant resistant.\"." + icon = 'icons/obj/structures.dmi' + icon_state = "safe" + anchored = 1 + density = 1 + var/open = 0 //is the safe open? + var/tumbler_1_pos //the tumbler position- from 0 to 72 + var/tumbler_1_open //the tumbler position to open at- 0 to 72 + var/tumbler_2_pos + var/tumbler_2_open + var/dial = 0 //where is the dial pointing? + var/space = 0 //the combined w_class of everything in the safe + var/maxspace = 24 //the maximum combined w_class of stuff in the safe + + +/obj/structure/safe/New() + tumbler_1_pos = rand(0, 72) + tumbler_1_open = rand(0, 72) + + tumbler_2_pos = rand(0, 72) + tumbler_2_open = rand(0, 72) + + +/obj/structure/safe/Initialize() + for(var/obj/item/I in loc) + if(space >= maxspace) + return + if(I.w_class + space <= maxspace) //todo replace with internal storage or something + space += I.w_class + I.forceMove(src) + . = ..() + +/obj/structure/safe/proc/check_unlocked(mob/user as mob, canhear) + if(user && canhear) + if(tumbler_1_pos == tumbler_1_open) + to_chat(user, "You hear a [pick("tonk", "krunk", "plunk")] from [src].") + if(tumbler_2_pos == tumbler_2_open) + to_chat(user, "You hear a [pick("tink", "krink", "plink")] from [src].") + if(tumbler_1_pos == tumbler_1_open && tumbler_2_pos == tumbler_2_open) + if(user) visible_message("[pick("Spring", "Sprang", "Sproing", "Clunk", "Krunk")]!") + return 1 + return 0 + + +/obj/structure/safe/proc/decrement(num) + num -= 1 + if(num < 0) + num = 71 + return num + + +/obj/structure/safe/proc/increment(num) + num += 1 + if(num > 71) + num = 0 + return num + + +/obj/structure/safe/update_icon() + if(open) + icon_state = "[initial(icon_state)]-open" + else + icon_state = initial(icon_state) + + +/obj/structure/safe/attack_hand(mob/user as mob) + user.set_machine(src) + var/dat = "
            " + dat += "[open ? "Close" : "Open"] [src] | - [dial * 5] +" + if(open) + dat += "" + for(var/i = contents.len, i>=1, i--) + var/obj/item/P = contents[i] + dat += "" + dat += "
            [P.name]
            " + user << browse("[name][dat]", "window=safe;size=350x300") + + +/obj/structure/safe/Topic(href, href_list) + if(!ishuman(usr)) return + var/mob/living/carbon/human/user = usr + + var/canhear = 0 + if(istype(user.l_hand, /obj/item/clothing/accessory/stethoscope) || istype(user.r_hand, /obj/item/clothing/accessory/stethoscope)) + canhear = 1 + + if(href_list["open"]) + if(check_unlocked()) + to_chat(user, "You [open ? "close" : "open"] [src].") + open = !open + update_icon() + updateUsrDialog() + return + else + to_chat(user, "You can't [open ? "close" : "open"] [src], the lock is engaged!") + return + + if(href_list["decrement"]) + dial = decrement(dial) + if(dial == tumbler_1_pos + 1 || dial == tumbler_1_pos - 71) + tumbler_1_pos = decrement(tumbler_1_pos) + if(canhear) + to_chat(user, "You hear a [pick("clack", "scrape", "clank")] from [src].") + if(tumbler_1_pos == tumbler_2_pos + 37 || tumbler_1_pos == tumbler_2_pos - 35) + tumbler_2_pos = decrement(tumbler_2_pos) + if(canhear) + to_chat(user, "You hear a [pick("click", "chink", "clink")] from [src].") + check_unlocked(user, canhear) + updateUsrDialog() + return + + if(href_list["increment"]) + dial = increment(dial) + if(dial == tumbler_1_pos - 1 || dial == tumbler_1_pos + 71) + tumbler_1_pos = increment(tumbler_1_pos) + if(canhear) + to_chat(user, "You hear a [pick("clack", "scrape", "clank")] from [src].") + if(tumbler_1_pos == tumbler_2_pos - 37 || tumbler_1_pos == tumbler_2_pos + 35) + tumbler_2_pos = increment(tumbler_2_pos) + if(canhear) + to_chat(user, "You hear a [pick("click", "chink", "clink")] from [src].") + check_unlocked(user, canhear) + updateUsrDialog() + return + + if(href_list["retrieve"]) + user << browse("", "window=safe") // Close the menu + + var/obj/item/P = locate(href_list["retrieve"]) in src + if(open) + if(P && in_range(src, user)) + user.put_in_hands(P) + updateUsrDialog() + + +/obj/structure/safe/attackby(obj/item/I as obj, mob/user as mob) + if(open) + if(I.w_class + space <= maxspace) + space += I.w_class + user.drop_item() + I.loc = src + to_chat(user, "You put [I] in [src].") + updateUsrDialog() + return + else + to_chat(user, "[I] won't fit in [src].") + return + else + if(istype(I, /obj/item/clothing/accessory/stethoscope)) + to_chat(user, "Hold [I] in one of your hands while you manipulate the dial.") + return + + +obj/structure/safe/ex_act(severity) + return + +//FLOOR SAFES +/obj/structure/safe/floor + name = "floor safe" + icon_state = "floorsafe" + density = 0 + level = 1 //underfloor + layer = BELOW_OBJ_LAYER + +/obj/structure/safe/floor/Initialize() + . = ..() + var/turf/T = loc + if(istype(T) && !T.is_plating()) + hide(1) + update_icon() + +/obj/structure/safe/floor/hide(var/intact) + set_invisibility(intact ? 101 : 0) + +/obj/structure/safe/floor/hides_under_flooring() + return 1 diff --git a/code/game/objects/structures/showcase.dm b/code/game/objects/structures/showcase.dm new file mode 100644 index 00000000..1f2d1660 --- /dev/null +++ b/code/game/objects/structures/showcase.dm @@ -0,0 +1,8 @@ +/obj/structure/showcase + name = "Showcase" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "showcase_1" + desc = "A stand with the empty body of a cyborg bolted to it." + density = 1 + anchored = 1 + unacidable = 1//temporary until I decide whether the borg can be removed. -veyveyr \ No newline at end of file diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm new file mode 100644 index 00000000..06a35e8f --- /dev/null +++ b/code/game/objects/structures/signs.dm @@ -0,0 +1,489 @@ +/obj/structure/sign + icon = 'icons/obj/decals.dmi' + anchored = 1 + opacity = 0 + density = 0 + layer = ABOVE_WINDOW_LAYER + w_class = ITEM_SIZE_NORMAL + +/obj/structure/sign/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + qdel(src) + return + if(3.0) + qdel(src) + return + else + return + +/obj/structure/sign/attackby(obj/item/tool as obj, mob/user as mob) //deconstruction + if(isScrewdriver(tool) && !istype(src, /obj/structure/sign/double)) + to_chat(user, "You unfasten the sign with your [tool.name].") + var/obj/item/sign/S = new(src.loc) + S.SetName(name) + S.desc = desc + S.icon_state = icon_state + S.sign_state = icon_state + qdel(src) + else ..() + +/obj/item/sign + name = "sign" + desc = "" + icon = 'icons/obj/decals.dmi' + w_class = ITEM_SIZE_NORMAL //big + var/sign_state = "" + +/obj/item/sign/attackby(obj/item/tool as obj, mob/user as mob) //construction + if(istype(tool, /obj/item/weapon/screwdriver) && isturf(user.loc)) + var/direction = input("In which direction?", "Select direction.") in list("North", "East", "South", "West", "Cancel") + if(direction == "Cancel") return + var/obj/structure/sign/S = new(user.loc) + switch(direction) + if("North") + S.pixel_y = 32 + if("East") + S.pixel_x = 32 + if("South") + S.pixel_y = -32 + if("West") + S.pixel_x = -32 + else return + S.SetName(name) + S.desc = desc + S.icon_state = sign_state + to_chat(user, "You fasten \the [S] with your [tool].") + qdel(src) + else ..() + +/obj/structure/sign/double/map + name = "map" + desc = "A framed map." + +/obj/structure/sign/double/map/New() + ..() + desc = "A framed map of the [station_name()]." + +/obj/structure/sign/double/map/left + icon_state = "map-left" + +/obj/structure/sign/double/map/right + icon_state = "map-right" + +/obj/structure/sign/double/planet/left + icon_state = "planet_left" + +/obj/structure/sign/double/planet/right + icon_state = "planet_right" + +/obj/structure/sign/monkey_painting + name = "\improper Mr. Deempisi portrait" + desc = "Under the painting a plaque reads: 'While the meat grinder may not have spared you, fear not. Not one part of you has gone to waste... You were delicious.'" + icon_state = "monkey_painting" + +/obj/structure/sign/warning + name = "\improper WARNING" + icon_state = "securearea" + +/obj/structure/sign/warning/detailed + icon_state = "securearea2" + +/obj/structure/sign/warning/New() + ..() + desc = "A warning sign which reads '[sanitize(name)]'." + +/obj/structure/sign/warning/airlock + name = "\improper EXTERNAL AIRLOCK" + icon_state = "doors" + +/obj/structure/sign/warning/biohazard + name = "\improper BIOHAZARD" + icon_state = "bio" + +/obj/structure/sign/warning/bomb_range + name = "\improper BOMB RANGE" + icon_state = "blast" + +/obj/structure/sign/warning/caution + name = "\improper CAUTION" + +/obj/structure/sign/warning/compressed_gas + name = "\improper COMPRESSED GAS" + icon_state = "hikpa" + +/obj/structure/sign/warning/deathsposal + name = "\improper DISPOSAL LEADS TO SPACE" + icon_state = "deathsposal" + +/obj/structure/sign/warning/docking_area + name = "\improper KEEP CLEAR: DOCKING AREA" + +/obj/structure/sign/warning/engineering_access + name = "\improper ENGINEERING ACCESS" + +/obj/structure/sign/warning/fall + name = "\improper FALL HAZARD" + icon_state = "falling" + +/obj/structure/sign/warning/fire + name = "\improper DANGER: FIRE" + icon_state = "fire" + +/obj/structure/sign/warning/high_voltage + name = "\improper HIGH VOLTAGE" + icon_state = "shock" + +/obj/structure/sign/warning/hot_exhaust + name = "\improper HOT EXHAUST" + icon_state = "fire" + +/obj/structure/sign/warning/internals_required + name = "\improper INTERNALS REQUIRED" + +/obj/structure/sign/warning/lethal_turrets + name = "\improper LETHAL TURRETS" + icon_state = "turrets" + +/obj/structure/sign/warning/lethal_turrets/New() + ..() + desc += " Enter at own risk!" + +/obj/structure/sign/warning/mail_delivery + name = "\improper MAIL DELIVERY" + icon_state = "mail" + +/obj/structure/sign/warning/moving_parts + name = "\improper MOVING PARTS" + icon_state = "movingparts" + +/obj/structure/sign/warning/nosmoking_1 + name = "\improper NO SMOKING" + icon_state = "nosmoking" + +/obj/structure/sign/warning/nosmoking_2 + name = "\improper NO SMOKING" + icon_state = "nosmoking2" + +/obj/structure/sign/warning/smoking + name = "\improper SMOKING" + icon_state = "smoking" + +/obj/structure/sign/warning/smoking/Initialize() + . = ..() + desc += " Hell yeah." + +/obj/structure/sign/warning/pods + name = "\improper ESCAPE PODS" + icon_state = "pods" + +/obj/structure/sign/warning/radioactive + name = "\improper RADIOACTIVE AREA" + icon_state = "radiation" + +/obj/structure/sign/warning/secure_area + name = "\improper SECURE AREA" + +/obj/structure/sign/warning/secure_area/armory + name = "\improper ARMORY" + icon_state = "armory" + +/obj/structure/sign/warning/server_room + name = "\improper SERVER ROOM" + icon_state = "server" + +/obj/structure/sign/warning/siphon_valve + name = "\improper SIPHON VALVE" + +/obj/structure/sign/warning/vacuum + name = "\improper HARD VACUUM AHEAD" + icon_state = "space" + +/obj/structure/sign/warning/vent_port + name = "\improper EJECTION/VENTING PORT" + +/obj/structure/sign/redcross + name = "medbay" + desc = "The Intergalactic symbol of Medical institutions. You'll probably get help here." + icon_state = "redcross" + +/obj/structure/sign/greencross + name = "medbay" + desc = "The Intergalactic symbol of Medical institutions. You'll probably get help here." + icon_state = "greencross" + +/obj/structure/sign/bluecross_1 + name = "infirmary" + desc = "The Intergalactic symbol of Medical institutions. You'll probably get help here." + icon_state = "bluecross" + +/obj/structure/sign/bluecross_2 + name = "infirmary" + desc = "The Intergalactic symbol of Medical institutions. You'll probably get help here." + icon_state = "bluecross2" + +/obj/structure/sign/goldenplaque + name = "The Most Robust Men Award for Robustness" + desc = "To be Robust is not an action or a way of life, but a mental state. Only those with the force of Will strong enough to act during a crisis, saving friend from foe, are truly Robust. Stay Robust my friends." + icon_state = "goldenplaque" + +/obj/structure/sign/goldenplaque/security + name = "motivational plaque" + desc = "A plaque engraved with a generic motivational quote and picture. ' Greater love hath no man than this, that a man lay down his life for his friends. John 15:13 " + +/obj/structure/sign/goldenplaque/medical + name = "medical certificate" + desc = "A picture next to a long winded description of medical certifications and degrees." + +/obj/structure/sign/kiddieplaque + name = "\improper AI developers plaque" + desc = "An extremely long list of names and job titles and a picture of the design team responsible for building this AI Core." + icon_state = "kiddieplaque" + +/obj/structure/sign/atmosplaque + name = "\improper engineering memorial plaque" + desc = "This plaque memorializes those engineers and technicians who made the ultimate sacrifice to save their vessel and its crew." + icon_state = "atmosplaque" + +/obj/structure/sign/floorplaque + name = "\improper commemorative plaque" + desc = "A list of dead explorers who gave their lives in search of the next great discovery. Hope you don't join them." + icon_state = "floorplaque" + +/obj/structure/sign/double/maltesefalcon //The sign is 64x32, so it needs two tiles. ;3 + name = "The Maltese Falcon" + desc = "The Maltese Falcon, Space Bar and Grill." + +/obj/structure/sign/double/maltesefalcon/left + icon_state = "maltesefalcon-left" + +/obj/structure/sign/double/maltesefalcon/right + icon_state = "maltesefalcon-right" + +/obj/structure/sign/warning/science + name = "\improper SCIENCE!" + icon_state = "science1" + +/obj/structure/sign/warning/science/anomalous_materials + name = "\improper ANOMALOUS MATERIALS" + +/obj/structure/sign/warning/science/mass_spectrometry + name = "\improper MASS SPECTROMETRY" + +/obj/structure/sign/science_1 + name = "\improper RESEARCH WING" + desc = "A sign labelling the research wing." + icon_state = "science1" + +/obj/structure/sign/science_2 + name = "\improper RESEARCH" + desc = "A sign labelling an area where research is performed." + icon_state = "science2" + +/obj/structure/sign/xenobio_1 + name = "\improper XENOBIOLOGY" + desc = "A sign labelling an area as a place where xenobiological entites are researched." + icon_state = "xenobio" + +/obj/structure/sign/xenobio_2 + name = "\improper XENOBIOLOGY" + desc = "A sign labelling an area as a place where xenobiological entites are researched." + icon_state = "xenobio2" + +/obj/structure/sign/xenobio_3 + name = "\improper XENOBIOLOGY" + desc = "A sign labelling an area as a place where xenobiological entites are researched." + icon_state = "xenobio3" + +/obj/structure/sign/xenobio_4 + name = "\improper XENOBIOLOGY" + desc = "A sign labelling an area as a place where xenobiological entites are researched." + icon_state = "xenobio4" + +/obj/structure/sign/xenoarch + name = "\improper XENOARCHAEOLOGY" + desc = "A sign labelling an area as a place where xenoarchaeological finds are researched." + icon_state = "xenobio4" + +/obj/structure/sign/chemistry + name = "\improper CHEMISTRY" + desc = "A sign labelling an area containing chemical equipment." + icon_state = "chemistry1" + +/obj/structure/sign/xenoflora + name = "\improper XENOFLORA" + desc = "A sign labelling an area as a place where xenobiological plants are researched." + icon_state = "hydro4" + +/obj/structure/sign/botany + name = "\improper BOTANY" + desc = "A warning sign which reads 'BOTANY!'." + icon_state = "hydro3" + +/obj/structure/sign/hydro + name = "\improper HYDROPONICS" + desc = "A sign labelling an area as a place where plants are grown." + icon_state = "hydro1" + +/obj/structure/sign/hydrostorage + name = "\improper HYDROPONICS STORAGE" + desc = "A sign labelling an area as a place where plant growing supplies are kept." + icon_state = "hydro3" + +/obj/structure/sign/directions + name = "direction sign" + desc = "A direction sign, claiming to know the way." + icon_state = "direction" + +/obj/structure/sign/directions/New() + ..() + desc = "A direction sign, pointing out which way \the [src] is." + +/obj/structure/sign/directions/science + name = "\improper Research Division" + icon_state = "direction_sci" + +/obj/structure/sign/directions/engineering + name = "\improper Engineering Bay" + icon_state = "direction_eng" + +/obj/structure/sign/directions/security + name = "\improper Security Wing" + icon_state = "direction_sec" + +/obj/structure/sign/directions/medical + name = "\improper Medical Bay" + icon_state = "direction_med" + +/obj/structure/sign/directions/evac + name = "\improper Evacuation Wing" + icon_state = "direction_evac" + +/obj/structure/sign/directions/bridge + name = "\improper Bridge" + icon_state = "direction_bridge" + +/obj/structure/sign/directions/supply + name = "\improper Supply Office" + icon_state = "direction_supply" + +/obj/structure/sign/directions/infirmary + name = "\improper Infirmary" + icon_state = "direction_infirm" + +/obj/structure/sign/directions/examroom + name = "\improper Exam Room" + icon_state = "examroom" + +/obj/structure/sign/deck/bridge + name = "\improper Bridge Deck" + icon_state = "deck-b" + +/obj/structure/sign/deck/first + name = "\improper First Deck" + icon_state = "deck-1" + +/obj/structure/sign/deck/second + name = "\improper Second Deck" + icon_state = "deck-2" + +/obj/structure/sign/deck/third + name = "\improper Third Deck" + icon_state = "deck-3" + +/obj/structure/sign/deck/fourth + name = "\improper Fourth Deck" + icon_state = "deck-4" + +/obj/item/sign/medipolma + name = "medical diploma" + desc = "A fancy print laminated paper that certifies that its bearer is indeed a Doctor of Medicine, graduated from a medical school in one of fringe systems. You don't recognize the name though, and half of latin words they used do not actually exist." + icon = 'icons/obj/decals.dmi' + icon_state = "goldenplaque" + sign_state = "goldenplaque" + var/claimant + +/obj/item/sign/medipolma/attack_self(mob/user) + if(!claimant) + to_chat(user, "You fill in your name in the blanks with a permanent marker.") + claimant = user.real_name + ..() + +/obj/item/sign/medipolma/examine(mob/user) + ..() + if(claimant) + to_chat(user,"This one belongs to Dr.[claimant], MD.") + else + to_chat(user,"The name is left blank for some reason.") + +/obj/structure/sign/deck1 + desc = "A silver sign which reads 'DECK I'." + name = "DECK I" + icon_state = "deck1" + +/obj/structure/sign/deck2 + desc = "A silver sign which reads 'DECK II'." + name = "DECK II" + icon_state = "deck2" + +/obj/structure/sign/deck3 + desc = "A silver sign which reads 'DECK III'." + name = "DECK III" + icon_state = "deck3" + +/obj/structure/sign/deck4 + desc = "A silver sign which reads 'DECK IV'." + name = "DECK IV" + icon_state = "deck4" + +/obj/structure/sign/deck5 + desc = "A silver sign which reads 'DECK V'." + name = "DECK V" + icon_state = "deck5" + +/obj/structure/sign/nanotrasen + name = "\improper NanoTrasen" + desc = "An old metal sign which reads 'NanoTrasen'." + icon_state = "NT" + +/obj/structure/sign/church + name = "\improper Church" + desc = "Heretics beware." + icon_state = "church" + +/obj/structure/sign/kitchen + name = "\improper Kitchen" + desc = "Food be here." + icon_state = "kitchen" + +/obj/structure/sign/magistrate + name = "\improper Magistrate" + desc = "How regal." + icon_state = "magistrate" + +/obj/structure/sign/medholo + name = "Medbay" + icon_state = "medholo" + +/obj/structure/sign/neon/sec + name = "Security" + icon_state = "sec" + +/obj/structure/sign/neon/cargo + name = "Cargo" + icon_state = "cargo" + +/obj/structure/sign/neon/armory + name = "Armory" + icon_state = "armory1" + +/obj/structure/sign/neon/shuttle + name = "Shuttle" + icon_state = "shuttle" + +/obj/structure/sign/neon/exit + name = "Exit" + icon_state = "exit" \ No newline at end of file diff --git a/code/game/objects/structures/skele_stand.dm b/code/game/objects/structures/skele_stand.dm new file mode 100644 index 00000000..d35669cb --- /dev/null +++ b/code/game/objects/structures/skele_stand.dm @@ -0,0 +1,82 @@ +/obj/structure/skele_stand + name = "hanging skeleton model" + density = 1 + icon = 'icons/obj/surgery.dmi' + icon_state = "hangskele" + desc = "It's an anatomical model of a human skeletal system made of plaster." + var/list/swag = list() + +/obj/structure/skele_stand/New() + ..() + gender = pick(MALE, FEMALE) + +/obj/structure/skele_stand/proc/rattle_bones(mob/user, atom/thingy) + if(user) + visible_message("\The [user] pushes on [src][thingy?" with \the [thingy]":""], giving the bones a good rattle.") + else + visible_message("\The [src] rattles on \his stand upon hitting [thingy?"\the [thingy]":"something"].") + playsound(loc, 'sound/effects/bonerattle.ogg', 40) + +/obj/structure/skele_stand/attack_hand(mob/user) + if(swag.len) + var/obj/item/clothing/C = input("What piece of clothing do you want to remove?", "Skeleton undressing") as null|anything in list_values(swag) + if(C) + swag -= get_key_by_value(swag, C) + user.put_in_hands(C) + to_chat(user,"You take \the [C] off \the [src]") + update_icon() + else + rattle_bones(user, null) + +/obj/structure/skele_stand/Bumped(atom/thing) + rattle_bones(null, thing) + +/obj/structure/skele_stand/examine(mob/user) + ..() + if(swag.len) + var/list/swagnames = list() + for(var/slot in swag) + var/obj/item/clothing/C = swag[slot] + swagnames += C.get_examine_line() + to_chat(user,"[gender == MALE ? "He" : "She"] is wearing [english_list(swagnames)].") + +/obj/structure/skele_stand/attackby(obj/item/weapon/W, mob/user) + if(istype(W,/obj/item/weapon/pen)) + var/nuname = sanitize(input(user,"What do you want to name this skeleton as?","Skeleton Christening",name) as text|null) + if(nuname && CanPhysicallyInteract(user)) + SetName(nuname) + return 1 + if(istype(W,/obj/item/clothing)) + var/slot + if(istype(W, /obj/item/clothing/under)) + slot = slot_w_uniform_str + else if(istype(W, /obj/item/clothing/suit)) + slot = slot_wear_suit_str + else if(istype(W, /obj/item/clothing/head)) + slot = slot_head_str + else if(istype(W, /obj/item/clothing/shoes)) + slot = slot_shoes_str + else if(istype(W, /obj/item/clothing/mask)) + slot = slot_wear_mask_str + if(slot) + if(swag[slot]) + to_chat(user,"There is already that kind of clothing on \the [src].") + else + swag[slot] = W + user.drop_from_inventory(W,src) + update_icon() + return 1 + else + rattle_bones(user, W) + +/obj/structure/skele_stand/Destroy() + for(var/slot in swag) + var/obj/item/I = swag[slot] + I.forceMove(loc) + . = ..() + +/obj/structure/skele_stand/update_icon() + overlays.Cut() + for(var/slot in swag) + var/obj/item/I = swag[slot] + overlays += I.get_mob_overlay(null, slot) \ No newline at end of file diff --git a/code/game/objects/structures/stasis_cage.dm b/code/game/objects/structures/stasis_cage.dm new file mode 100644 index 00000000..032c5dfa --- /dev/null +++ b/code/game/objects/structures/stasis_cage.dm @@ -0,0 +1,61 @@ +/obj/structure/stasis_cage + name = "stasis cage" + desc = "A high-tech animal cage, designed to keep contained fauna docile and safe." + icon = 'icons/obj/storage.dmi' + icon_state = "critter" + density = 1 + + var/mob/living/simple_animal/contained + +/obj/structure/stasis_cage/Initialize() + . = ..() + + var/mob/living/simple_animal/A = locate() in loc + if(A) + contain(A) + +/obj/structure/stasis_cage/attack_hand(var/mob/user) + release() + +/obj/structure/stasis_cage/attack_robot(var/mob/user) + if(Adjacent(user)) + release() + +/obj/structure/stasis_cage/proc/contain(var/mob/living/simple_animal/animal) + if(contained || !istype(animal)) + return + + contained = animal + animal.forceMove(src) + animal.in_stasis = 1 + desc = initial(desc) + " \The [contained] is kept inside." + +/obj/structure/stasis_cage/proc/release() + if(!contained) + return + + contained.dropInto(src) + contained.in_stasis = 0 + contained = null + underlays.Cut() + desc = initial(desc) + +/obj/structure/stasis_cage/Destroy() + release() + + return ..() + +/mob/living/simple_animal/MouseDrop(var/obj/structure/stasis_cage/over_object) + if(istype(over_object) && Adjacent(over_object) && CanMouseDrop(over_object, usr)) + + if(!src.buckled || !istype(src.buckled, /obj/effect/energy_net)) + to_chat(usr, "It's going to be difficult to convince \the [src] to move into \the [over_object] without capturing it in a net.") + return + + usr.visible_message("[usr] begins stuffing \the [src] into \the [over_object].", "You begin stuffing \the [src] into \the [over_object].") + Bumped(usr) + if(do_after(usr, 20, over_object)) + usr.visible_message("[usr] has stuffed \the [src] into \the [over_object].", "You have stuffed \the [src] into \the [over_object].") + over_object.contain(src) + else + return ..() \ No newline at end of file diff --git a/code/game/objects/structures/statue.dm b/code/game/objects/structures/statue.dm new file mode 100644 index 00000000..290079e1 --- /dev/null +++ b/code/game/objects/structures/statue.dm @@ -0,0 +1,15 @@ +/obj/structure/statue/verina + name = "statue" + desc = "A statue of some ominous looking, robed, figure. There's barely a scratch on it." + icon = 'icons/obj/64x64.dmi' + icon_state = "statue" + anchored = 1 + density = 1 + layer = 4 + bound_height = 32 + bound_width = 64 + +/obj/structure/statue/verina/broken + name = "broken statue" + desc = "A statue of some ominous looking, robed, figure. It's badly damaged." + icon_state = "statue_broken" \ No newline at end of file diff --git a/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm b/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm new file mode 100644 index 00000000..c0f0e261 --- /dev/null +++ b/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm @@ -0,0 +1,78 @@ +//Alium nests. Essentially beds with an unbuckle delay that only aliums can buckle mobs to. +#define NEST_RESIST_TIME 1200 + +/obj/structure/bed/nest + name = "alien nest" + desc = "It's a gruesome pile of thick, sticky resin shaped like a nest." + icon = 'icons/mob/alien.dmi' + icon_state = "nest" + buckle_pixel_shift = "x=0;y=6" + var/health = 100 + +/obj/structure/bed/nest/update_icon() + return + +/obj/structure/bed/nest/user_unbuckle_mob(mob/user as mob) + if(buckled_mob) + if(buckled_mob.buckled == src) + if(buckled_mob != user) + buckled_mob.visible_message(\ + "[user.name] pulls [buckled_mob.name] free from the sticky nest!",\ + "[user.name] pulls you free from the gelatinous resin.",\ + "You hear squelching...") + unbuckle_mob() + else + if(world.time <= buckled_mob.last_special+NEST_RESIST_TIME) + return + buckled_mob.last_special = world.time + buckled_mob.visible_message(\ + "[buckled_mob.name] struggles to break free of the gelatinous resin...",\ + "You struggle to break free from the gelatinous resin...",\ + "You hear squelching...") + spawn(NEST_RESIST_TIME) + if(user && buckled_mob && user.buckled == src) + buckled_mob.last_special = world.time + unbuckle_mob() + src.add_fingerprint(user) + return + +/obj/structure/bed/nest/user_buckle_mob(mob/M as mob, mob/user as mob) + if ( !ismob(M) || (get_dist(src, user) > 1) || (M.loc != src.loc) || user.restrained() || usr.stat || M.buckled || istype(user, /mob/living/silicon/pai) ) + return + + unbuckle_mob() + + var/mob/living/carbon/xenos = user + var/mob/living/carbon/victim = M + + /*if(istype(victim) && locate(/obj/item/organ/internal/xenos/hivenode) in victim.internal_organs) + return + + if(istype(xenos) && !(locate(/obj/item/organ/internal/xenos/hivenode) in xenos.internal_organs)) + return + */ + + if(M == usr) + return + else + M.visible_message( + "[user.name] secretes a thick vile goo, securing [M] into [src]!", + "[user.name] drenches you in a foul-smelling resin, trapping you in the [src]!", + "You hear squelching...") + buckle_mob(M) + src.add_fingerprint(user) + return + +/obj/structure/bed/nest/attackby(obj/item/weapon/W as obj, mob/user as mob) + var/aforce = W.force + health = max(0, health - aforce) + playsound(loc, 'sound/effects/attackblob.ogg', 100, 1) + for(var/mob/M in viewers(src, 7)) + M.show_message("[user] hits [src] with [W]!", 1) + healthcheck() + +/obj/structure/bed/nest/proc/healthcheck() + if(health <=0) + set_density(0) + qdel(src) + return diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm new file mode 100644 index 00000000..eb9c99fd --- /dev/null +++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm @@ -0,0 +1,293 @@ +/* Beds... get your mind out of the gutter, they're for sleeping! + * Contains: + * Beds + * Roller beds + */ + +/* + * Beds + */ +/obj/structure/bed + name = "bed" + desc = "This is used to lie in, sleep in or strap on." + icon = 'icons/obj/furniture.dmi' + icon_state = "bed" + anchored = 1 + can_buckle = 1 + buckle_dir = SOUTH + buckle_lying = 1 + var/material/material + var/material/padding_material + var/base_icon = "bed" + var/material_alteration = MATERIAL_ALTERATION_ALL + +/obj/structure/bed/New(var/newloc, var/new_material, var/new_padding_material) + ..(newloc) + color = null + if(!new_material) + new_material = DEFAULT_WALL_MATERIAL + material = get_material_by_name(new_material) + if(!istype(material)) + qdel(src) + return + if(new_padding_material) + padding_material = get_material_by_name(new_padding_material) + update_icon() + +/obj/structure/bed/get_material() + return material + +// Reuse the cache/code from stools, todo maybe unify. +/obj/structure/bed/update_icon() + // Prep icon. + icon_state = "" + overlays.Cut() + // Base icon. + var/cache_key = "[base_icon]-[material.name]" + if(isnull(stool_cache[cache_key])) + var/image/I = image('icons/obj/furniture.dmi', base_icon) + if(material_alteration & MATERIAL_ALTERATION_COLOR) + I.color = material.icon_colour + stool_cache[cache_key] = I + overlays |= stool_cache[cache_key] + // Padding overlay. + if(padding_material) + var/padding_cache_key = "[base_icon]-padding-[padding_material.name]" + if(isnull(stool_cache[padding_cache_key])) + var/image/I = image(icon, "[base_icon]_padding") + if(material_alteration & MATERIAL_ALTERATION_COLOR) + I.color = padding_material.icon_colour + stool_cache[padding_cache_key] = I + overlays |= stool_cache[padding_cache_key] + + // Strings. + if(material_alteration & MATERIAL_ALTERATION_NAME) + SetName(padding_material ? "[padding_material.adjective_name] [initial(name)]" : "[material.adjective_name] [initial(name)]") //this is not perfect but it will do for now. + + if(material_alteration & MATERIAL_ALTERATION_DESC) + desc = initial(desc) + desc += padding_material ? " It's made of [material.use_name] and covered with [padding_material.use_name]." : " It's made of [material.use_name]." + +/obj/structure/bed/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(istype(mover) && mover.checkpass(PASS_FLAG_TABLE)) + return 1 + else + return ..() + +/obj/structure/bed/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + if (prob(50)) + qdel(src) + return + if(3.0) + if (prob(5)) + qdel(src) + return + +/obj/structure/bed/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWrench(W)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + dismantle() + qdel(src) + else if(istype(W,/obj/item/stack)) + if(padding_material) + to_chat(user, "\The [src] is already padded.") + return + var/obj/item/stack/C = W + if(C.get_amount() < 1) // How?? + user.drop_from_inventory(C) + qdel(C) + return + var/padding_type //This is awful but it needs to be like this until tiles are given a material var. + if(istype(W,/obj/item/stack/tile/carpet)) + padding_type = "carpet" + else if(istype(W,/obj/item/stack/material)) + var/obj/item/stack/material/M = W + if(M.material && (M.material.flags & MATERIAL_PADDING)) + padding_type = "[M.material.name]" + if(!padding_type) + to_chat(user, "You cannot pad \the [src] with that.") + return + C.use(1) + if(!istype(src.loc, /turf)) + user.drop_from_inventory(src) + src.loc = get_turf(src) + to_chat(user, "You add padding to \the [src].") + add_padding(padding_type) + return + + else if(isWirecutter(W)) + if(!padding_material) + to_chat(user, "\The [src] has no padding to remove.") + return + to_chat(user, "You remove the padding from \the [src].") + playsound(src, 'sound/items/Wirecutter.ogg', 100, 1) + remove_padding() + + else if(istype(W, /obj/item/grab)) + var/obj/item/grab/G = W + var/mob/living/affecting = G.affecting + user.visible_message("[user] attempts to buckle [affecting] into \the [src]!") + if(do_after(user, 20, src)) + if(user_buckle_mob(affecting, user)) + qdel(W) + else + ..() + +/obj/structure/bed/proc/remove_padding() + if(padding_material) + padding_material.place_sheet(get_turf(src)) + padding_material = null + update_icon() + +/obj/structure/bed/proc/add_padding(var/padding_type) + padding_material = get_material_by_name(padding_type) + update_icon() + +/obj/structure/bed/proc/dismantle() + material.place_sheet(get_turf(src)) + if(padding_material) + padding_material.place_sheet(get_turf(src)) + +/obj/structure/bed/psych + name = "psychiatrist's couch" + desc = "For prime comfort during psychiatric evaluations." + icon_state = "psychbed" + base_icon = "psychbed" + +/obj/structure/bed/psych/New(var/newloc) + ..(newloc,"wood","leather") + +/obj/structure/bed/padded/New(var/newloc) + ..(newloc,"plastic","cotton") + +/obj/structure/bed/alien + name = "resting contraption" + desc = "This looks similar to contraptions from earth. Could aliens be stealing our technology?" + +/obj/structure/bed/alien/New(var/newloc) + ..(newloc,"resin") + +/obj/structure/bed/bogani + name = "alien bed" + desc = "a strange looking bed, not from something you've seen before." + icon_state = "bogbed" + + +/* + * Roller beds + */ +/obj/structure/bed/roller + name = "roller bed" + icon = 'icons/obj/rollerbed.dmi' + icon_state = "down" + anchored = 0 + buckle_pixel_shift = "x=0;y=6" + +/obj/structure/bed/roller/update_icon() + return // Doesn't care about material or anything else. + +/obj/structure/bed/roller/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWrench(W) || istype(W,/obj/item/stack) || isWirecutter(W)) + return + else if(istype(W,/obj/item/roller_holder)) + if(buckled_mob) + user_unbuckle_mob(user) + else + visible_message("[user] collapses \the [src.name].") + new/obj/item/roller(get_turf(src)) + spawn(0) + qdel(src) + return + ..() + +/obj/item/roller + name = "roller bed" + desc = "A collapsed roller bed that can be carried around." + icon = 'icons/obj/rollerbed.dmi' + icon_state = "folded" + item_state = "rbed" + slot_flags = SLOT_BACK + w_class = ITEM_SIZE_HUGE // Can't be put in backpacks. Oh well. For now. + +/obj/item/roller/attack_self(mob/user) + var/obj/structure/bed/roller/R = new /obj/structure/bed/roller(user.loc) + R.add_fingerprint(user) + qdel(src) + +/obj/item/roller/attackby(obj/item/weapon/W as obj, mob/user as mob) + + if(istype(W,/obj/item/roller_holder)) + var/obj/item/roller_holder/RH = W + if(!RH.held) + to_chat(user, "You collect the roller bed.") + src.forceMove(RH) + RH.held = src + return + + ..() + +/obj/item/roller_holder + name = "roller bed rack" + desc = "A rack for carrying a collapsed roller bed." + icon = 'icons/obj/rollerbed.dmi' + icon_state = "folded" + var/obj/item/roller/held + +/obj/item/roller_holder/New() + ..() + held = new /obj/item/roller(src) + +/obj/item/roller_holder/attack_self(mob/user as mob) + + if(!held) + to_chat(user, "The rack is empty.") + return + + to_chat(user, "You deploy the roller bed.") + var/obj/structure/bed/roller/R = new /obj/structure/bed/roller(user.loc) + R.add_fingerprint(user) + qdel(held) + held = null + + +/obj/structure/bed/roller/proc/move_buckled() + if(buckled_mob) + if(buckled_mob.buckled == src) + buckled_mob.forceMove(src.loc) + else + buckled_mob = null + +/obj/structure/bed/roller/post_buckle_mob(mob/living/M as mob) + if(M == buckled_mob) + set_density(1) + icon_state = "up" + else + set_density(0) + icon_state = "down" + + return ..() + +/obj/structure/bed/roller/buckle_mob() + . = ..() + if(.) + GLOB.moved_event.register(src, src, /obj/structure/bed/roller/proc/move_buckled) + +/obj/structure/bed/roller/unbuckle_mob() + GLOB.moved_event.unregister(src, src) + return ..() + +/obj/structure/bed/roller/MouseDrop(over_object, src_location, over_location) + ..() + if((over_object == usr && (in_range(src, usr) || usr.contents.Find(src)))) + if(!ishuman(usr)) return + if(buckled_mob) return 0 + visible_message("[usr] collapses \the [src.name].") + new/obj/item/roller(get_turf(src)) + spawn(0) + qdel(src) + return diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm new file mode 100644 index 00000000..19faf04d --- /dev/null +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -0,0 +1,259 @@ +/obj/structure/bed/chair //YES, chairs are a type of bed, which are a type of stool. This works, believe me. -Pete + name = "chair" + desc = "You sit in this, either by will or force." + icon_state = "chair_preview" + color = "#666666" + base_icon = "chair" + buckle_dir = 0 + buckle_lying = 0 //force people to sit up in chairs when buckled + var/propelled = 0 // Check for fire-extinguisher-driven chairs + material_alteration = MATERIAL_ALTERATION_NONE + +/obj/structure/bed/chair/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + if(!padding_material && istype(W, /obj/item/assembly/shock_kit)) + var/obj/item/assembly/shock_kit/SK = W + if(!SK.status) + to_chat(user, "\The [SK] is not ready to be attached!") + return + user.drop_item() + var/obj/structure/bed/chair/e_chair/E = new (src.loc, material.name) + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + E.set_dir(dir) + E.part = SK + SK.forceMove(E) + SK.master = E + qdel(src) + +/obj/structure/bed/chair/attack_tk(mob/user as mob) + if(buckled_mob) + ..() + else + rotate() + return + +/obj/structure/bed/chair/post_buckle_mob() + update_icon() + return ..() + +/obj/structure/bed/chair/update_icon() + ..() + +/* var/cache_key = "[base_icon]-[material.name]-over" + if(isnull(stool_cache[cache_key])) + var/image/I = image('icons/obj/furniture.dmi', "[base_icon]_over") + if(material_alteration & MATERIAL_ALTERATION_COLOR) + I.color = material.icon_colour + I.plane = HUMAN_PLANE + 0.1 + I.layer = ABOVE_HUMAN_LAYER + stool_cache[cache_key] = I + overlays |= stool_cache[cache_key] + // Padding overlay. + if(padding_material) + var/padding_cache_key = "[base_icon]-padding-[padding_material.name]-over" + if(isnull(stool_cache[padding_cache_key])) + var/image/I = image(icon, "[base_icon]_padding_over") + if(material_alteration & MATERIAL_ALTERATION_COLOR) + I.color = padding_material.icon_colour + I.plane = ABOVE_HUMAN_PLANE + I.layer = ABOVE_HUMAN_LAYER + stool_cache[padding_cache_key] = I + overlays |= stool_cache[padding_cache_key] +*/ + if(buckled_mob && padding_material) + var/cache_key = "[base_icon]-armrest-[padding_material.name]" + if(isnull(stool_cache[cache_key])) + var/image/I = image(icon, "[base_icon]_armrest") + I.plane = ABOVE_HUMAN_PLANE + I.layer = ABOVE_HUMAN_LAYER + if(material_alteration & MATERIAL_ALTERATION_COLOR) + I.color = padding_material.icon_colour + stool_cache[cache_key] = I + overlays |= stool_cache[cache_key] + if(buckled_mob && padding_material && dir == NORTH) + var/padding_cache_key = "[base_icon]-padding-[padding_material.name]-over" + if(isnull(stool_cache[padding_cache_key])) + var/image/I = image(icon, "[base_icon]_padding_over") + if(material_alteration & MATERIAL_ALTERATION_COLOR) + I.color = padding_material.icon_colour + I.plane = ABOVE_HUMAN_PLANE + I.layer = ABOVE_HUMAN_LAYER + stool_cache[padding_cache_key] = I + overlays |= stool_cache[padding_cache_key] + + if(dir == NORTH && buckled_mob && !padding_material) + var/cache_key = "[base_icon]-over" + if(isnull(stool_cache[cache_key])) + var/image/I = image(icon, "[base_icon]_over") + if(material_alteration & MATERIAL_ALTERATION_COLOR) + I.color = padding_material.icon_colour + I.plane = ABOVE_HUMAN_PLANE + I.layer = ABOVE_HUMAN_LAYER + stool_cache[cache_key] = I + overlays |= stool_cache[cache_key] + +/obj/structure/bed/chair/set_dir() + ..() + if(buckled_mob) + buckled_mob.set_dir(dir) + +/obj/structure/bed/chair/AltClick() + rotate() + +/obj/structure/bed/chair/proc/rotate() + set name = "Rotate Chair" + set category = "Object" + + if(!usr || !Adjacent(usr)) + return + + if(usr.stat == DEAD) + if(!round_is_spooky()) + to_chat(src, "The veil is not thin enough for you to do that.") + return + else if(usr.incapacitated()) + return + + src.set_dir(turn(src.dir, 90)) + return + +/obj/structure/bed/chair/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + rotate() + +// Leaving this in for the sake of compilation. +/obj/structure/bed/chair/comfy + desc = "It's a chair. It looks comfy." + icon_state = "comfychair_preview" + material_alteration = MATERIAL_ALTERATION_ALL + +/obj/structure/bed/chair/comfy/brown/New(var/newloc,var/newmaterial) + ..(newloc,"steel","leather") + +/obj/structure/bed/chair/comfy/red/New(var/newloc,var/newmaterial) + ..(newloc,"steel","carpet") + +/obj/structure/bed/chair/comfy/teal/New(var/newloc,var/newmaterial) + ..(newloc,"steel","teal") + +/obj/structure/bed/chair/comfy/black/New(var/newloc,var/newmaterial) + ..(newloc,"steel","black") + +/obj/structure/bed/chair/comfy/green/New(var/newloc,var/newmaterial) + ..(newloc,"steel","green") + +/obj/structure/bed/chair/comfy/purp/New(var/newloc,var/newmaterial) + ..(newloc,"steel","purple") + +/obj/structure/bed/chair/comfy/blue/New(var/newloc,var/newmaterial) + ..(newloc,"steel","blue") + +/obj/structure/bed/chair/comfy/beige/New(var/newloc,var/newmaterial) + ..(newloc,"steel","beige") + +/obj/structure/bed/chair/comfy/lime/New(var/newloc,var/newmaterial) + ..(newloc,"steel","lime") + +/obj/structure/bed/chair/comfy/captain + name = "captain chair" + desc = "It's a chair. Only for the highest ranked asses." + icon_state = "capchair_preview" + base_icon = "capchair" + buckle_movable = 1 +/* +/obj/structure/bed/chair/comfy/captain/throne + var/datum/announcement/priority/crew_announcement = new + +/obj/structure/bed/chair/comfy/captain/throne/verb/announce + set name = "Announce" + set category = "Throne" + + crew_announcement.Announce(var/message as text, var/new_title = "", var/new_sound = null, var/do_newscast = newscast, var/msg_sanitized = 0) + + CanInteract(user, state) +*/ + +/obj/structure/bed/chair/comfy/captain/New(var/newloc,var/newmaterial) + ..(newloc,"steel","black") + +/obj/structure/bed/chair/office + anchored = 0 + buckle_movable = 1 + material_alteration = MATERIAL_ALTERATION_NONE + +/obj/structure/bed/chair/office/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/stack) || isWirecutter(W)) + return + ..() + +/obj/structure/bed/chair/office/Move() + ..() + if(buckled_mob) + var/mob/living/occupant = buckled_mob + occupant.buckled = null + occupant.Move(src.loc) + occupant.buckled = src + if (occupant && (src.loc != occupant.loc)) + if (propelled) + for (var/mob/O in src.loc) + if (O != occupant) + Bump(O) + else + unbuckle_mob() + +/obj/structure/bed/chair/office/Bump(atom/A) + ..() + if(!buckled_mob) return + + if(propelled) + var/mob/living/occupant = unbuckle_mob() + + var/def_zone = ran_zone() + var/blocked = occupant.run_armor_check(def_zone, "melee") + occupant.throw_at(A, 3, propelled) + occupant.apply_effect(6, STUN, blocked) + occupant.apply_effect(6, WEAKEN, blocked) + occupant.apply_effect(6, STUTTER, blocked) + occupant.apply_damage(10, BRUTE, def_zone, blocked) + playsound(src.loc, 'sound/weapons/punch_01.ogg', 50, 1, -1) + if(istype(A, /mob/living)) + var/mob/living/victim = A + def_zone = ran_zone() + blocked = victim.run_armor_check(def_zone, "melee") + victim.apply_effect(6, STUN, blocked) + victim.apply_effect(6, WEAKEN, blocked) + victim.apply_effect(6, STUTTER, blocked) + victim.apply_damage(10, BRUTE, def_zone, blocked) + occupant.visible_message("[occupant] crashed into \the [A]!") + +/obj/structure/bed/chair/office/light + base_icon = "officechair_white" + icon_state = "officechair_white_preview" + +/obj/structure/bed/chair/office/dark + base_icon = "officechair_dark" + icon_state = "officechair_dark_preview" + +// Chair types +/obj/structure/bed/chair/wood + desc = "Old is never too old to not be in fashion." + base_icon = "wooden_chair" + icon_state = "wooden_chair_preview" + material_alteration = MATERIAL_ALTERATION_NAME + +/obj/structure/bed/chair/wood/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/stack) || istype(W, /obj/item/weapon/wirecutters)) + return + ..() + +/obj/structure/bed/chair/wood/New(var/newloc) + ..(newloc, "wood") + +/obj/structure/bed/chair/wood/wings + base_icon = "wooden_chair_wings" + icon_state = "wooden_chair_wings_preview" + +/obj/structure/bed/chair/bogani + desc = "A strange chair, not from around here." + base_icon = "bogchair" + icon_state = "bogchair_preview" diff --git a/code/game/objects/structures/stool_bed_chair_nest/stools.dm b/code/game/objects/structures/stool_bed_chair_nest/stools.dm new file mode 100644 index 00000000..53335c2f --- /dev/null +++ b/code/game/objects/structures/stool_bed_chair_nest/stools.dm @@ -0,0 +1,163 @@ +//Todo: add leather and cloth for arbitrary coloured stools. +var/global/list/stool_cache = list() //haha stool + +/obj/item/weapon/stool + name = "stool" + desc = "Apply butt." + icon = 'icons/obj/furniture.dmi' + icon_state = "stool_preview" //set for the map + item_state = "stool" + randpixel = 0 + force = 10 + throwforce = 10 + w_class = ITEM_SIZE_HUGE + var/base_icon = "stool" + var/material/material + var/material/padding_material + +/obj/item/weapon/stool/padded + icon_state = "stool_padded_preview" //set for the map + +/obj/item/weapon/stool/New(var/newloc, var/new_material, var/new_padding_material) + ..(newloc) + if(!new_material) + new_material = DEFAULT_WALL_MATERIAL + material = get_material_by_name(new_material) + if(new_padding_material) + padding_material = get_material_by_name(new_padding_material) + if(!istype(material)) + qdel(src) + return + force = round(material.get_blunt_damage()*0.4) + update_icon() + +/obj/item/weapon/stool/padded/New(var/newloc, var/new_material) + ..(newloc, "steel", "carpet") + +/obj/item/weapon/stool/bar + name = "bar stool" + icon_state = "bar_stool_preview" //set for the map + item_state = "bar_stool" + base_icon = "bar_stool" + +/obj/item/weapon/stool/bar/padded + icon_state = "bar_stool_padded_preview" + +/obj/item/weapon/stool/bar/padded/New(var/newloc, var/new_material) + ..(newloc, "steel", "carpet") + +/obj/item/weapon/stool/update_icon() + // Prep icon. + icon_state = "" + // Base icon. + var/list/noverlays = list() + var/cache_key = "[base_icon]-[material.name]" + if(isnull(stool_cache[cache_key])) + var/image/I = image(icon, "[base_icon]_base") + I.color = material.icon_colour + stool_cache[cache_key] = I + noverlays |= stool_cache[cache_key] + // Padding overlay. + if(padding_material) + var/padding_cache_key = "[base_icon]-padding-[padding_material.name]" + if(isnull(stool_cache[padding_cache_key])) + var/image/I = image(icon, "[base_icon]_padding") + I.color = padding_material.icon_colour + stool_cache[padding_cache_key] = I + noverlays |= stool_cache[padding_cache_key] + overlays = noverlays + // Strings. + if(padding_material) + SetName("[padding_material.display_name] [initial(name)]") //this is not perfect but it will do for now. + desc = "A padded stool. Apply butt. It's made of [material.use_name] and covered with [padding_material.use_name]." + else + SetName("[material.display_name] [initial(name)]") + desc = "A stool. Apply butt with care. It's made of [material.use_name]." + +/obj/item/weapon/stool/proc/add_padding(var/padding_type) + padding_material = get_material_by_name(padding_type) + update_icon() + +/obj/item/weapon/stool/proc/remove_padding() + if(padding_material) + padding_material.place_sheet(get_turf(src)) + padding_material = null + update_icon() + +/obj/item/weapon/stool/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) + if (prob(5)) + user.visible_message("[user] breaks [src] over [target]'s back!") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(target) + user.remove_from_mob(src) + dismantle() + qdel(src) + + var/blocked = target.run_armor_check(hit_zone, "melee") + target.Weaken(10 * blocked_mult(blocked)) + target.apply_damage(20, BRUTE, hit_zone, blocked, src) + return + + ..() + +/obj/item/weapon/stool/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + if (prob(50)) + qdel(src) + return + if(3.0) + if (prob(5)) + qdel(src) + return + +/obj/item/weapon/stool/proc/dismantle() + if(material) + material.place_sheet(get_turf(src)) + if(padding_material) + padding_material.place_sheet(get_turf(src)) + qdel(src) + +/obj/item/weapon/stool/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWrench(W)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + dismantle() + qdel(src) + else if(istype(W,/obj/item/stack)) + if(padding_material) + to_chat(user, "\The [src] is already padded.") + return + var/obj/item/stack/C = W + if(C.get_amount() < 1) // How?? + user.drop_from_inventory(C) + qdel(C) + return + var/padding_type //This is awful but it needs to be like this until tiles are given a material var. + if(istype(W,/obj/item/stack/tile/carpet)) + padding_type = "carpet" + else if(istype(W,/obj/item/stack/material)) + var/obj/item/stack/material/M = W + if(M.material && (M.material.flags & MATERIAL_PADDING)) + padding_type = "[M.material.name]" + if(!padding_type) + to_chat(user, "You cannot pad \the [src] with that.") + return + C.use(1) + if(!istype(src.loc, /turf)) + user.drop_from_inventory(src) + src.dropInto(loc) + to_chat(user, "You add padding to \the [src].") + add_padding(padding_type) + return + else if(isWirecutter(W)) + if(!padding_material) + to_chat(user, "\The [src] has no padding to remove.") + return + to_chat(user, "You remove the padding from \the [src].") + playsound(src, 'sound/items/Wirecutter.ogg', 100, 1) + remove_padding() + else + ..() diff --git a/code/game/objects/structures/stool_bed_chair_nest/throne.dm b/code/game/objects/structures/stool_bed_chair_nest/throne.dm new file mode 100644 index 00000000..a5d29636 --- /dev/null +++ b/code/game/objects/structures/stool_bed_chair_nest/throne.dm @@ -0,0 +1,157 @@ +//The throne has many functions so it gets its own file. + +/obj/structure/bed/chair/throne + name = "\the Commandant's throne" + desc = "Fit for a king... or a uh... commadant" + base_icon = "throne" + icon_state = "throne" + var/datum/announcement/decree/magistrate_decree = new + var/announcement_cooldown = FALSE + +/obj/structure/bed/chair/throne/rotate()//Can't rotate it. + return + +/obj/structure/bed/chair/throne/attackby(obj/item/weapon/W as obj, mob/user as mob)//Can't deconstruct it. + return + +//Like an announcement only exclusively for Magistrates. +/obj/structure/bed/chair/throne/verb/decree() + set name = "Make A Decree" + set category = "Throne" + set src in view(0) + + if(!ishuman(usr)) + return + + var/mob/living/carbon/human/user = usr + + if(user.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_KNOCKOUT)) + return + + if(!user.is_wearing_crown()) + to_chat(user, "You cannot make decrees without the crown.") + return + + if(announcement_cooldown) + to_chat(user, "It is too soon to make another decree.") + return + + var/announcement = sanitize(input(user, "What would you like to announce?", "Announcement")as null|text) + if(!announcement) + return + to_chat(world, "

            Commandant's New Decree:
            [announcement]

            ") + + sound_to(world, 'sound/effects/klaxon_alarm.ogg') + announcement_cooldown = TRUE + spawn(600)//One minute cooldown + announcement_cooldown = FALSE + +//Banishing someone from the land. +/obj/structure/bed/chair/throne/verb/banish() + set name = "Banish A Subject" + set category = "Throne" + set src in view(0) + + if(!ishuman(usr)) + return + + var/mob/living/carbon/human/user = usr + + if(user.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_KNOCKOUT)) + return + + if(!user.is_wearing_crown()) + to_chat(user, "You require the crown for this.") + return + + if(announcement_cooldown) + to_chat(user, "It is too soon to do this again.") + return + + var/input = sanitize(input(user, "Input a subject to banish. THIS CANNOT BE UNDONE!", "Banish") as null|text) + if(!input) + return + + banish(input) + to_chat(world, "

            Commandant has banished:
            [input]

            ") + sound_to(world, 'sound/effects/klaxon_alarm.ogg') + announcement_cooldown = TRUE + spawn(600) + announcement_cooldown = FALSE + +//Declaring someone you want fucking dead! +/obj/structure/bed/chair/throne/verb/great_hunt() + set name = "Declare A Great Hunt" + set category = "Throne" + set src in view(0) + + if(!ishuman(usr)) + return + + var/mob/living/carbon/human/user = usr + + if(user.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_KNOCKOUT)) + return + + if(!user.is_wearing_crown()) + to_chat(user, "You require the crown for this.") + return + + if(announcement_cooldown) + to_chat(user, "It is too soon to do this again.") + return + + var/input = sanitize(input(user, "Who shall we declare a great hunt on? THIS CANNOT BE UNDONE!", "Great Hunt") as null|text) + if(!input) + return + to_chat(world, "

            COMMANDANT:
            A great hunt has been declared on [input]! All loyal men must participate until [input] is dead!

            ") + sound_to(world, 'sound/effects/klaxon_alarm.ogg') + announcement_cooldown = TRUE + spawn(600) + announcement_cooldown = FALSE + +//Declaring someone you want only captured. +/obj/structure/bed/chair/throne/verb/captured() + set name = "Declare A Criminal To Be Captured" + set category = "Throne" + set src in view(0) + + if(!ishuman(usr)) + return + + var/mob/living/carbon/human/user = usr + + if(user.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_KNOCKOUT)) + return + + if(!user.is_wearing_crown()) + to_chat(user, "You require the crown for this.") + return + + if(announcement_cooldown) + to_chat(user, "It is too soon to do this again.") + return + + var/input = sanitize(input(user, "Who is to be captured? THIS CANNOT BE UNDONE!", "Capture a Criminal") as null|text) + if(!input) + return + + to_chat(world, "

            COMMANDANT:
            [input] is a criminal to be captured alive!

            ") + sound_to(world, 'sound/effects/klaxon_alarm.ogg') + announcement_cooldown = TRUE + spawn(600) + announcement_cooldown = FALSE + +/proc/banish(var/name) + if(!name) + return + for(var/A in GLOB.human_mob_list)//Typless loops are quicker. + var/mob/living/carbon/human/H = A + if(H.real_name == name) + H.banished = TRUE + + +/mob/living/proc/is_wearing_crown() + var/obj/O = get_equipped_item(slot_head) + if(istype(O, /obj/item/clothing/head/crown)) + return TRUE \ No newline at end of file diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm new file mode 100644 index 00000000..b37ee76f --- /dev/null +++ b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm @@ -0,0 +1,194 @@ +/obj/structure/bed/chair/wheelchair + name = "wheelchair" + desc = "You sit in this. Either by will or force." + icon_state = "wheelchair" + anchored = 0 + buckle_movable = 1 + + var/driving = 0 + var/mob/living/pulling = null + var/bloodiness + +/obj/structure/bed/chair/wheelchair/update_icon() + return + +/obj/structure/bed/chair/wheelchair/set_dir() + ..() + overlays = null + var/image/O = image(icon = 'icons/obj/furniture.dmi', icon_state = "w_overlay", dir = src.dir) + O.plane = ABOVE_HUMAN_PLANE + O.layer = ABOVE_HUMAN_LAYER + overlays += O + if(buckled_mob) + buckled_mob.set_dir(dir) + +/obj/structure/bed/chair/wheelchair/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWrench(W) || istype(W,/obj/item/stack) || isWirecutter(W)) + return + ..() + +/obj/structure/bed/chair/wheelchair/relaymove(mob/user, direction) + // Redundant check? + if(user.stat || user.stunned || user.weakened || user.paralysis || user.lying || user.restrained()) + if(user==pulling) + pulling = null + user.pulledby = null + to_chat(user, "You lost your grip!") + return + if(buckled_mob && pulling && user == buckled_mob) + if(pulling.stat || pulling.stunned || pulling.weakened || pulling.paralysis || pulling.lying || pulling.restrained()) + pulling.pulledby = null + pulling = null + if(user.pulling && (user == pulling)) + pulling = null + user.pulledby = null + return + if(propelled) + return + if(pulling && (get_dist(src, pulling) > 1)) + pulling = null + user.pulledby = null + if(user==pulling) + return + if(pulling && (get_dir(src.loc, pulling.loc) == direction)) + to_chat(user, "You cannot go there.") + return + if(pulling && buckled_mob && (buckled_mob == user)) + to_chat(user, "You cannot drive while being pushed.") + return + + // Let's roll + driving = 1 + var/turf/T = null + //--1---Move occupant---1--// + if(buckled_mob) + buckled_mob.buckled = null + step(buckled_mob, direction) + buckled_mob.buckled = src + //--2----Move driver----2--// + if(pulling) + T = pulling.loc + if(get_dist(src, pulling) >= 1) + step(pulling, get_dir(pulling.loc, src.loc)) + //--3--Move wheelchair--3--// + step(src, direction) + if(buckled_mob) // Make sure it stays beneath the occupant + Move(buckled_mob.loc) + set_dir(direction) + if(pulling) // Driver + if(pulling.loc == src.loc) // We moved onto the wheelchair? Revert! + pulling.forceMove(T) + else + spawn(0) + if(get_dist(src, pulling) > 1) // We are too far away? Losing control. + pulling = null + user.pulledby = null + pulling.set_dir(get_dir(pulling, src)) // When everything is right, face the wheelchair + if(bloodiness) + create_track() + driving = 0 + +/obj/structure/bed/chair/wheelchair/Move() + ..() + if(buckled_mob) + if(buckled_mob.zoomed)//No more wheelchair sniping. + buckled_mob.do_zoom() + var/mob/living/occupant = buckled_mob + if(!driving) + occupant.buckled = null + occupant.Move(src.loc) + occupant.buckled = src + if (occupant && (src.loc != occupant.loc)) + if (propelled) + for (var/mob/O in src.loc) + if (O != occupant) + Bump(O) + else + unbuckle_mob() + if (pulling && (get_dist(src, pulling) > 1)) + pulling.pulledby = null + to_chat(pulling, "You lost your grip!") + pulling = null + else + if (occupant && (src.loc != occupant.loc)) + src.forceMove(occupant.loc) // Failsafe to make sure the wheelchair stays beneath the occupant after driving + +/obj/structure/bed/chair/wheelchair/attack_hand(mob/living/user as mob) + if (pulling) + MouseDrop(usr) + else + user_unbuckle_mob(user) + return + +/obj/structure/bed/chair/wheelchair/CtrlClick(var/mob/user) + if(in_range(src, user)) + if(!ishuman(user)) return + if(user == buckled_mob) + to_chat(user, "You realize you are unable to push the wheelchair you sit in.") + return + if(!pulling) + pulling = user + user.pulledby = src + if(user.pulling) + user.stop_pulling() + user.set_dir(get_dir(user, src)) + to_chat(user, "You grip \the [name]'s handles.") + else + to_chat(usr, "You let go of \the [name]'s handles.") + pulling.pulledby = null + pulling = null + return + +/obj/structure/bed/chair/wheelchair/Bump(atom/A) + ..() + if(!buckled_mob) return + + if(propelled || (pulling && (pulling.a_intent == I_HURT))) + var/mob/living/occupant = unbuckle_mob() + + if (pulling && (pulling.a_intent == I_HURT)) + occupant.throw_at(A, 3, 3, pulling) + else if (propelled) + occupant.throw_at(A, 3, propelled) + + var/def_zone = ran_zone() + var/blocked = occupant.run_armor_check(def_zone, "melee") + occupant.throw_at(A, 3, propelled) + occupant.apply_effect(6, STUN, blocked) + occupant.apply_effect(6, WEAKEN, blocked) + occupant.apply_effect(6, STUTTER, blocked) + occupant.apply_damage(10, BRUTE, def_zone, blocked) + playsound(src.loc, 'sound/weapons/punch_01.ogg', 50, 1, -1) + if(istype(A, /mob/living)) + var/mob/living/victim = A + def_zone = ran_zone() + blocked = victim.run_armor_check(def_zone, "melee") + victim.apply_effect(6, STUN, blocked) + victim.apply_effect(6, WEAKEN, blocked) + victim.apply_effect(6, STUTTER, blocked) + victim.apply_damage(10, BRUTE, def_zone, blocked) + if(pulling) + occupant.visible_message("[pulling] has thrusted \the [name] into \the [A], throwing \the [occupant] out of it!") + admin_attack_log(pulling, occupant, "Crashed their victim into \an [A].", "Was crashed into \an [A].", "smashed into \the [A] using") + else + occupant.visible_message("[occupant] crashed into \the [A]!") + +/obj/structure/bed/chair/wheelchair/proc/create_track() + var/obj/effect/decal/cleanable/blood/tracks/B = new(loc) + var/newdir = get_dir(get_step(loc, dir), loc) + if(newdir == dir) + B.set_dir(newdir) + else + newdir = newdir | dir + if(newdir == 3) + newdir = 1 + else if(newdir == 12) + newdir = 4 + B.set_dir(newdir) + bloodiness-- + +/obj/structure/bed/chair/wheelchair/buckle_mob(mob/M as mob, mob/user as mob) + if(M == pulling) + pulling = null + usr.pulledby = null + ..() diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm new file mode 100644 index 00000000..c39dc584 --- /dev/null +++ b/code/game/objects/structures/tank_dispenser.dm @@ -0,0 +1,120 @@ +/obj/structure/dispenser + name = "tank storage unit" + desc = "A simple yet bulky storage device for gas tanks. Has room for up to ten oxygen tanks, and ten phoron tanks." + icon = 'icons/obj/objects.dmi' + icon_state = "dispenser" + density = 1 + anchored = 1.0 + w_class = ITEM_SIZE_NO_CONTAINER + var/oxygentanks = 10 + var/phorontanks = 10 + var/list/oxytanks = list() //sorry for the similar var names + var/list/platanks = list() + + +/obj/structure/dispenser/oxygen + phorontanks = 0 + +/obj/structure/dispenser/phoron + oxygentanks = 0 + + +/obj/structure/dispenser/New() + update_icon() + + +/obj/structure/dispenser/update_icon() + overlays.Cut() + switch(oxygentanks) + if(1 to 3) overlays += "oxygen-[oxygentanks]" + if(4 to INFINITY) overlays += "oxygen-4" + switch(phorontanks) + if(1 to 4) overlays += "phoron-[phorontanks]" + if(5 to INFINITY) overlays += "phoron-5" + +/obj/structure/dispenser/attack_ai(mob/user as mob) + if(user.Adjacent(src)) + return attack_hand(user) + ..() + +/obj/structure/dispenser/attack_hand(mob/user as mob) + user.set_machine(src) + var/dat = "[src]

            " + dat += "Oxygen tanks: [oxygentanks] - [oxygentanks ? "Dispense" : "empty"]
            " + dat += "Phoron tanks: [phorontanks] - [phorontanks ? "Dispense" : "empty"]" + user << browse(dat, "window=dispenser") + onclose(user, "dispenser") + return + + +/obj/structure/dispenser/attackby(obj/item/I as obj, mob/user as mob) + if(istype(I, /obj/item/weapon/tank/oxygen) || istype(I, /obj/item/weapon/tank/air) || istype(I, /obj/item/weapon/tank/anesthetic)) + if(oxygentanks < 10) + user.drop_item() + I.loc = src + oxytanks.Add(I) + oxygentanks++ + to_chat(user, "You put [I] in [src].") + if(oxygentanks < 5) + update_icon() + else + to_chat(user, "[src] is full.") + updateUsrDialog() + return + if(istype(I, /obj/item/weapon/tank/phoron)) + if(phorontanks < 10) + user.drop_item() + I.loc = src + platanks.Add(I) + phorontanks++ + to_chat(user, "You put [I] in [src].") + if(oxygentanks < 6) + update_icon() + else + to_chat(user, "[src] is full.") + updateUsrDialog() + return + if(isWrench(I)) + if(anchored) + to_chat(user, "You lean down and unwrench [src].") + anchored = 0 + else + to_chat(user, "You wrench [src] into place.") + anchored = 1 + return + +/obj/structure/dispenser/Topic(href, href_list) + if(usr.stat || usr.restrained()) + return + if(Adjacent(usr)) + usr.set_machine(src) + if(href_list["oxygen"]) + if(oxygentanks > 0) + var/obj/item/weapon/tank/oxygen/O + if(oxytanks.len == oxygentanks) + O = oxytanks[1] + oxytanks.Remove(O) + else + O = new /obj/item/weapon/tank/oxygen(loc) + O.loc = loc + to_chat(usr, "You take [O] out of [src].") + oxygentanks-- + update_icon() + if(href_list["phoron"]) + if(phorontanks > 0) + var/obj/item/weapon/tank/phoron/P + if(platanks.len == phorontanks) + P = platanks[1] + platanks.Remove(P) + else + P = new /obj/item/weapon/tank/phoron(loc) + P.loc = loc + to_chat(usr, "You take [P] out of [src].") + phorontanks-- + update_icon() + add_fingerprint(usr) + updateUsrDialog() + else + usr << browse(null, "window=dispenser") + return + return diff --git a/code/game/objects/structures/target_stake.dm b/code/game/objects/structures/target_stake.dm new file mode 100644 index 00000000..301225da --- /dev/null +++ b/code/game/objects/structures/target_stake.dm @@ -0,0 +1,53 @@ +// Basically they are for the firing range +/obj/structure/target_stake + name = "target stake" + desc = "A thin platform with negatively-magnetized wheels." + icon = 'icons/obj/objects.dmi' + icon_state = "target_stake" + density = 1 + w_class = ITEM_SIZE_NO_CONTAINER + obj_flags = OBJ_FLAG_CONDUCTIBLE + var/obj/item/target/pinned_target // the current pinned target + + Move() + ..() + // Move the pinned target along with the stake + if(pinned_target in view(3, src)) + pinned_target.loc = loc + + else // Sanity check: if the pinned target can't be found in immediate view + pinned_target = null + set_density(1) + + attackby(obj/item/W as obj, mob/user as mob) + // Putting objects on the stake. Most importantly, targets + if(pinned_target) + return // get rid of that pinned target first! + + if(istype(W, /obj/item/target)) + set_density(0) + W.set_density(1) + user.remove_from_mob(W) + W.forceMove(loc) + W.layer = ABOVE_OBJ_LAYER + pinned_target = W + to_chat(user, "You slide the target into the stake.") + return + + attack_hand(mob/user as mob) + // taking pinned targets off! + if(pinned_target) + set_density(1) + pinned_target.set_density(0) + pinned_target.layer = OBJ_LAYER + + pinned_target.loc = user.loc + if(ishuman(user)) + if(!user.get_active_hand()) + user.put_in_hands(pinned_target) + to_chat(user, "You take the target out of the stake.") + else + pinned_target.loc = get_turf(user) + to_chat(user, "You take the target out of the stake.") + + pinned_target = null diff --git a/code/game/objects/structures/transit_tubes.dm b/code/game/objects/structures/transit_tubes.dm new file mode 100644 index 00000000..780913b5 --- /dev/null +++ b/code/game/objects/structures/transit_tubes.dm @@ -0,0 +1,611 @@ + +// Basic transit tubes. Straight pieces, curved sections, +// and basic splits/joins (no routing logic). +// Mappers: you can use "Generate Instances from Icon-states" +// to get the different pieces. +/obj/structure/transit_tube + icon = 'icons/obj/pipes/transit_tube.dmi' + icon_state = "E-W" + density = 1 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + anchored = 1.0 + var/list/tube_dirs = null + var/exit_delay = 2 + var/enter_delay = 1 + + // alldirs in global.dm is the same list of directions, but since + // the specific order matters to get a usable icon_state, it is + // copied here so that, in the unlikely case that alldirs is changed, + // this continues to work. + var/global/list/tube_dir_list = list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST) + + +// A place where tube pods stop, and people can get in or out. +// Mappers: use "Generate Instances from Directions" for this +// one. +/obj/structure/transit_tube/station + icon = 'icons/obj/pipes/transit_tube_station.dmi' + icon_state = "closed" + exit_delay = 2 + enter_delay = 3 + var/pod_moving = 0 + var/automatic_launch_time = 100 + + var/const/OPEN_DURATION = 6 + var/const/CLOSE_DURATION = 6 + + + +/obj/structure/transit_tube_pod + icon = 'icons/obj/pipes/transit_tube_pod.dmi' + icon_state = "pod" + animate_movement = FORWARD_STEPS + anchored = 1.0 + density = 1 + var/moving = 0 + var/datum/gas_mixture/air_contents = new() + + + +/obj/structure/transit_tube_pod/Destroy() + for(var/atom/movable/AM in contents) + AM.loc = loc + + ..() + + + +// When destroyed by explosions, properly handle contents. +obj/structure/ex_act(severity) + switch(severity) + if(1.0) + for(var/atom/movable/AM in contents) + AM.loc = loc + AM.ex_act(severity++) + + qdel(src) + return + if(2.0) + if(prob(50)) + for(var/atom/movable/AM in contents) + AM.loc = loc + AM.ex_act(severity++) + + qdel(src) + return + if(3.0) + return + + + +/obj/structure/transit_tube_pod/New(loc) + ..(loc) + + air_contents.adjust_multi("oxygen", MOLES_O2STANDARD * 2, "nitrogen", MOLES_N2STANDARD) + air_contents.temperature = T20C + + // Give auto tubes time to align before trying to start moving + spawn(5) + follow_tube() + + + +/obj/structure/transit_tube/New(loc) + ..(loc) + + if(tube_dirs == null) + init_dirs() + + + +/obj/structure/transit_tube/Bumped(mob/AM as mob|obj) + var/obj/structure/transit_tube/T = locate() in AM.loc + if(T) + to_chat(AM, "The tube's support pylons block your way.") + return ..() + else + AM.loc = src.loc + to_chat(AM, "You slip under the tube.") + + +/obj/structure/transit_tube/station/New(loc) + ..(loc) + + + +/obj/structure/transit_tube/station/Bumped(mob/AM as mob|obj) + if(!pod_moving && icon_state == "open" && istype(AM, /mob)) + for(var/obj/structure/transit_tube_pod/pod in loc) + if(pod.contents.len) + to_chat(AM, "The pod is already occupied.") + return + else if(!pod.moving && pod.dir in directions()) + AM.loc = pod + return + + +/obj/structure/transit_tube/station/attack_hand(mob/user as mob) + if(!pod_moving) + for(var/obj/structure/transit_tube_pod/pod in loc) + if(!pod.moving && pod.dir in directions()) + if(icon_state == "closed") + open_animation() + + else if(icon_state == "open") + close_animation() + + + +/obj/structure/transit_tube/station/proc/open_animation() + if(icon_state == "closed") + icon_state = "opening" + spawn(OPEN_DURATION) + if(icon_state == "opening") + icon_state = "open" + + + +/obj/structure/transit_tube/station/proc/close_animation() + if(icon_state == "open") + icon_state = "closing" + spawn(CLOSE_DURATION) + if(icon_state == "closing") + icon_state = "closed" + + + +/obj/structure/transit_tube/station/proc/launch_pod() + for(var/obj/structure/transit_tube_pod/pod in loc) + if(!pod.moving && pod.dir in directions()) + spawn(5) + pod_moving = 1 + close_animation() + sleep(CLOSE_DURATION + 2) + + //reverse directions for automated cycling + var/turf/next_loc = get_step(loc, pod.dir) + var/obj/structure/transit_tube/nexttube + for(var/obj/structure/transit_tube/tube in next_loc) + if(tube.has_entrance(pod.dir)) + nexttube = tube + break + if(!nexttube) + pod.set_dir(turn(pod.dir, 180)) + + if(icon_state == "closed" && pod) + pod.follow_tube() + + pod_moving = 0 + + return + + + +// Called to check if a pod should stop upon entering this tube. +/obj/structure/transit_tube/proc/should_stop_pod(pod, from_dir) + return 0 + + + +/obj/structure/transit_tube/station/should_stop_pod(pod, from_dir) + return 1 + + + +// Called when a pod stops in this tube section. +/obj/structure/transit_tube/proc/pod_stopped(pod, from_dir) + return + + + +/obj/structure/transit_tube/station/pod_stopped(obj/structure/transit_tube_pod/pod, from_dir) + pod_moving = 1 + spawn(5) + open_animation() + sleep(OPEN_DURATION + 2) + pod_moving = 0 + pod.mix_air() + + if(automatic_launch_time) + var/const/wait_step = 5 + var/i = 0 + while(i < automatic_launch_time) + sleep(wait_step) + i += wait_step + + if(pod_moving || icon_state != "open") + return + + launch_pod() + + + +// Returns a /list of directions this tube section can connect to. +// Tubes that have some sort of logic or changing direction might +// override it with additional logic. +/obj/structure/transit_tube/proc/directions() + return tube_dirs + + + +/obj/structure/transit_tube/proc/has_entrance(from_dir) + from_dir = turn(from_dir, 180) + + for(var/direction in directions()) + if(direction == from_dir) + return 1 + + return 0 + + + +/obj/structure/transit_tube/proc/has_exit(in_dir) + for(var/direction in directions()) + if(direction == in_dir) + return 1 + + return 0 + + + +// Searches for an exit direction within 45 degrees of the +// specified dir. Returns that direction, or 0 if none match. +/obj/structure/transit_tube/proc/get_exit(in_dir) + var/near_dir = 0 + var/in_dir_cw = turn(in_dir, -45) + var/in_dir_ccw = turn(in_dir, 45) + + for(var/direction in directions()) + if(direction == in_dir) + return direction + + else if(direction == in_dir_cw) + near_dir = direction + + else if(direction == in_dir_ccw) + near_dir = direction + + return near_dir + + + +// Return how many BYOND ticks to wait before entering/exiting +// the tube section. Default action is to return the value of +// a var, which wouldn't need a proc, but it makes it possible +// for later tube types to interact in more interesting ways +// such as being very fast in one direction, but slow in others +/obj/structure/transit_tube/proc/exit_delay(pod, to_dir) + return exit_delay + +/obj/structure/transit_tube/proc/enter_delay(pod, to_dir) + return enter_delay + + + +/obj/structure/transit_tube_pod/proc/follow_tube() + if(moving) + return + + moving = 1 + + spawn() + var/obj/structure/transit_tube/current_tube = null + var/next_dir + var/next_loc + var/last_delay = 0 + var/exit_delay + + for(var/obj/structure/transit_tube/tube in loc) + if(tube.has_exit(dir)) + current_tube = tube + break + + while(current_tube) + next_dir = current_tube.get_exit(dir) + + if(!next_dir) + break + + exit_delay = current_tube.exit_delay(src, dir) + last_delay += exit_delay + + sleep(exit_delay) + + next_loc = get_step(loc, next_dir) + + current_tube = null + for(var/obj/structure/transit_tube/tube in next_loc) + if(tube.has_entrance(next_dir)) + current_tube = tube + break + + if(current_tube == null) + set_dir(next_dir) + Move(get_step(loc, dir)) // Allow collisions when leaving the tubes. + break + + last_delay = current_tube.enter_delay(src, next_dir) + sleep(last_delay) + set_dir(next_dir) + loc = next_loc // When moving from one tube to another, skip collision and such. + set_density(current_tube.density) + + if(current_tube && current_tube.should_stop_pod(src, next_dir)) + current_tube.pod_stopped(src, dir) + break + + set_density(1) + + // If the pod is no longer in a tube, move in a line until stopped or slowed to a halt. + // /turf/inertial_drift appears to only work on mobs, and re-implementing some of the + // logic allows a gradual slowdown and eventual stop when passing over non-space turfs. + if(!current_tube && last_delay <= 10) + do + sleep(last_delay) + + if(!istype(loc, /turf/space)) + last_delay++ + + if(last_delay > 10) + break + + while(isturf(loc) && Move(get_step(loc, dir))) + + moving = 0 + +/obj/structure/transit_tube_pod/return_air() + return air_contents + +/obj/structure/transit_tube_pod/assume_air(datum/gas_mixture/giver) + return air_contents.merge(giver) + +/obj/structure/transit_tube_pod/remove_air(amount) + return air_contents.remove(amount) + +// Called when a pod arrives at, and before a pod departs from a station, +// giving it a chance to mix its internal air supply with the turf it is +// currently on. +/obj/structure/transit_tube_pod/proc/mix_air() + var/datum/gas_mixture/environment = loc.return_air() + + //note that share_ratio assumes both gas mixes have the same volume, + //so if the volume is changed this may need to be changed as well. + air_contents.share_ratio(environment, 1) + +// When the player moves, check if the pos is currently stopped at a station. +// if it is, check the direction. If the direction matches the direction of +// the station, try to exit. If the direction matches one of the station's +// tube directions, launch the pod in that direction. +/obj/structure/transit_tube_pod/relaymove(mob/mob, direction) + if(istype(mob, /mob) && mob.client) + // If the pod is not in a tube at all, you can get out at any time. + if(!(locate(/obj/structure/transit_tube) in loc)) + mob.loc = loc + mob.client.Move(get_step(loc, direction), direction) + + //if(moving && istype(loc, /turf/space)) + // Todo: If you get out of a moving pod in space, you should move as well. + // Same direction as pod? Direcion you moved? Halfway between? + + if(!moving) + for(var/obj/structure/transit_tube/station/station in loc) + if(dir in station.directions()) + if(!station.pod_moving) + if(direction == station.dir) + if(station.icon_state == "open") + mob.loc = loc + mob.client.Move(get_step(loc, direction), direction) + + else + station.open_animation() + + else if(direction in station.directions()) + set_dir(direction) + station.launch_pod() + return + + for(var/obj/structure/transit_tube/tube in loc) + if(dir in tube.directions()) + if(tube.has_exit(direction)) + set_dir(direction) + return + + + +// Parse the icon_state into a list of directions. +// This means that mappers can use Dream Maker's built in +// "Generate Instances from Icon-states" option to get all +// variations. Additionally, as a separate proc, sub-types +// can handle it more intelligently. +/obj/structure/transit_tube/proc/init_dirs() + if(icon_state == "auto") + // Additional delay, for map loading. + spawn(1) + init_dirs_automatic() + + else + tube_dirs = parse_dirs(icon_state) + + if(copytext(icon_state, 1, 3) == "D-" || findtextEx(icon_state, "Pass")) + set_density(0) + + + +// Tube station directions are simply 90 to either side of +// the exit. +/obj/structure/transit_tube/station/init_dirs() + tube_dirs = list(turn(dir, 90), turn(dir, -90)) + + + +// Initialize dirs by searching for tubes that do/might connect +// on nearby turfs. Create corner pieces if nessecary. +// Pick two directions, preferring tubes that already connect +// to loc, or other auto tubes if there aren't enough connections. +/obj/structure/transit_tube/proc/init_dirs_automatic() + var/list/connected = list() + var/list/connected_auto = list() + + for(var/direction in tube_dir_list) + var/location = get_step(loc, direction) + for(var/obj/structure/transit_tube/tube in location) + if(tube.directions() == null && tube.icon_state == "auto") + connected_auto += direction + break + + else if(turn(direction, 180) in tube.directions()) + connected += direction + break + + connected += connected_auto + + tube_dirs = select_automatic_dirs(connected) + + if(length(tube_dirs) == 2 && tube_dir_list.Find(tube_dirs[1]) > tube_dir_list.Find(tube_dirs[2])) + tube_dirs.Swap(1, 2) + + generate_automatic_corners(tube_dirs) + select_automatic_icon_state(tube_dirs) + + + +// Given a list of directions, look a pair that forms a 180 or +// 135 degree angle, and return a list containing the pair. +// If none exist, return list(connected[1], turn(connected[1], 180) +/obj/structure/transit_tube/proc/select_automatic_dirs(connected) + if(length(connected) < 1) + return list() + + for(var/i = 1, i <= length(connected), i++) + for(var/j = i + 1, j <= length(connected), j++) + var/d1 = connected[i] + var/d2 = connected[j] + + if(d1 == turn(d2, 135) || d1 == turn(d2, 180) || d1 == turn(d2, 225)) + return list(d1, d2) + + return list(connected[1], turn(connected[1], 180)) + + + +/obj/structure/transit_tube/proc/select_automatic_icon_state(directions) + if(length(directions) == 2) + icon_state = "[dir2text_short(directions[1])]-[dir2text_short(directions[2])]" + + + +// Look for diagonal directions, generate the decorative corners in each. +/obj/structure/transit_tube/proc/generate_automatic_corners(directions) + for(var/direction in directions) + if(direction == 5 || direction == 6 || direction == 9 || direction == 10) + if(direction & NORTH) + create_automatic_decorative_corner(get_step(loc, NORTH), direction ^ 3) + + else + create_automatic_decorative_corner(get_step(loc, SOUTH), direction ^ 3) + + if(direction & EAST) + create_automatic_decorative_corner(get_step(loc, EAST), direction ^ 12) + + else + create_automatic_decorative_corner(get_step(loc, WEST), direction ^ 12) + + + +// Generate a corner, if one doesn't exist for the direction on the turf. +/obj/structure/transit_tube/proc/create_automatic_decorative_corner(location, direction) + var/state = "D-[dir2text_short(direction)]" + + for(var/obj/structure/transit_tube/tube in location) + if(tube.icon_state == state) + return + + var/obj/structure/transit_tube/tube = new(location) + tube.icon_state = state + tube.init_dirs() + + + +// Uses a list() to cache return values. Since they should +// never be edited directly, all tubes with a certain +// icon_state can just reference the same list. In theory, +// reduces memory usage, and improves CPU cache usage. +// In reality, I don't know if that is quite how BYOND works, +// but it is probably safer to assume the existence of, and +// rely on, a sufficiently smart compiler/optimizer. +/obj/structure/transit_tube/proc/parse_dirs(text) + var/global/list/direction_table = list() + + if(text in direction_table) + return direction_table[text] + + var/list/split_text = splittext(text, "-") + + // If the first token is D, the icon_state represents + // a purely decorative tube, and doesn't actually + // connect to anything. + if(split_text[1] == "D") + direction_table[text] = list() + return null + + var/list/directions = list() + + for(var/text_part in split_text) + var/direction = text2dir_extended(text_part) + + if(direction > 0) + directions += direction + + direction_table[text] = directions + return directions + + + +// A copy of text2dir, extended to accept one and two letter +// directions, and to clearly return 0 otherwise. +/obj/structure/transit_tube/proc/text2dir_extended(direction) + switch(uppertext(direction)) + if("NORTH", "N") + return 1 + if("SOUTH", "S") + return 2 + if("EAST", "E") + return 4 + if("WEST", "W") + return 8 + if("NORTHEAST", "NE") + return 5 + if("NORTHWEST", "NW") + return 9 + if("SOUTHEAST", "SE") + return 6 + if("SOUTHWEST", "SW") + return 10 + else + return 0 + + + +// A copy of dir2text, which returns the short one or two letter +// directions used in tube icon states. +/obj/structure/transit_tube/proc/dir2text_short(direction) + switch(direction) + if(1) + return "N" + if(2) + return "S" + if(4) + return "E" + if(8) + return "W" + if(5) + return "NE" + if(6) + return "SE" + if(9) + return "NW" + if(10) + return "SW" + else + return diff --git a/code/game/objects/structures/under_wardrobe.dm b/code/game/objects/structures/under_wardrobe.dm new file mode 100644 index 00000000..2e8aec65 --- /dev/null +++ b/code/game/objects/structures/under_wardrobe.dm @@ -0,0 +1,119 @@ +#define WARDROBE_BLIND_MESSAGE(fool) "\The [src] flashes a light at \the [fool] as it states a message." + +/obj/structure/undies_wardrobe + name = "underwear wardrobe" + desc = "Holds item of clothing you shouldn't be showing off in the hallways." + icon = 'icons/obj/closet.dmi' + icon_state = "cabinet_closed" + density = 1 + + var/static/list/amount_of_underwear_by_id_card + +/obj/structure/undies_wardrobe/attackby(var/obj/item/underwear/underwear, var/mob/user) + if(istype(underwear)) + if(!user.unEquip(underwear)) + return + qdel(underwear) + user.visible_message("\The [user] inserts \their [underwear.name] into \the [src].", "You insert your [underwear.name] into \the [src].") + + var/id = user.GetIdCard() + var/message + if(id) + message = "ID card detected. Your underwear quota for this shift as been increased, if applicable." + else + message = "No ID card detected. Thank you for your contribution." + + audible_message(message, WARDROBE_BLIND_MESSAGE(user)) + + var/number_of_underwear = LAZYACCESS(amount_of_underwear_by_id_card, id) - 1 + if(number_of_underwear) + LAZYSET(amount_of_underwear_by_id_card, id, number_of_underwear) + GLOB.destroyed_event.register(id, src, /obj/structure/undies_wardrobe/proc/remove_id_card) + else + remove_id_card(id) + + else + ..() + +/obj/structure/undies_wardrobe/proc/remove_id_card(var/id_card) + LAZYREMOVE(amount_of_underwear_by_id_card, id_card) + GLOB.destroyed_event.unregister(id_card, src, /obj/structure/undies_wardrobe/proc/remove_id_card) + +/obj/structure/undies_wardrobe/attack_hand(var/mob/user) + if(!human_who_can_use_underwear(user)) + to_chat(user, "Sadly there's nothing in here for you to wear.") + return + interact(user) + +/obj/structure/undies_wardrobe/interact(var/mob/living/carbon/human/H) + return + /* + var/id = H.GetIdCard() + + var/dat = list() + dat += "Underwear

            " + dat += "You may claim [id ? length(GLOB.underwear.categories) - LAZYACCESS(amount_of_underwear_by_id_card, id) : 0] more article\s this shift.

            " + dat += "Available Categories

            " + for(var/datum/category_group/underwear/UWC in GLOB.underwear.categories) + dat += "[UWC.name] (Select)
            " + dat = jointext(dat,null) + show_browser(H, dat, "window=wardrobe;size=400x250") + */ + +/obj/structure/undies_wardrobe/proc/human_who_can_use_underwear(var/mob/living/carbon/human/H) + if(!istype(H) || !H.species || !(H.species.appearance_flags & HAS_UNDERWEAR)) + return FALSE + return TRUE + +/obj/structure/undies_wardrobe/CanUseTopic(var/user) + if(!human_who_can_use_underwear(user)) + return STATUS_CLOSE + + return ..() + +/obj/structure/undies_wardrobe/Topic(href, href_list, state) + if(..()) + return TRUE + + var/mob/living/carbon/human/H = usr + if(href_list["select_underwear"]) + var/datum/category_group/underwear/UWC = GLOB.underwear.categories_by_name[href_list["select_underwear"]] + if(!UWC) + return + var/datum/category_item/underwear/UWI = input("Select your desired underwear:", "Choose underwear") as null|anything in exlude_none(UWC.items) + if(!UWI) + return + + var/list/metadata_list = list() + + if(!CanInteract(H, state)) + return + + var/id = H.GetIdCard() + if(!id) + audible_message("No ID card detected. Unable to acquire your underwear quota for this shift.", WARDROBE_BLIND_MESSAGE(H)) + return + + var/current_quota = LAZYACCESS(amount_of_underwear_by_id_card, id) + if(current_quota >= length(GLOB.underwear.categories)) + audible_message("You have already used up your underwear quota for this shift. Please return previously acquired items to increase it.", WARDROBE_BLIND_MESSAGE(H)) + return + LAZYSET(amount_of_underwear_by_id_card, id, ++current_quota) + + var/obj/UW = UWI.create_underwear(metadata_list) + UW.forceMove(loc) + H.put_in_hands(UW) + + . = TRUE + + if(.) + interact(H) + +/obj/structure/undies_wardrobe/proc/exlude_none(var/list/L) + . = L.Copy() + for(var/e in .) + var/datum/category_item/underwear/UWI = e + if(!UWI.underwear_type) + . -= UWI + +#undef WARDROBE_BLIND_MESSAGE diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm new file mode 100644 index 00000000..d80d6603 --- /dev/null +++ b/code/game/objects/structures/watercloset.dm @@ -0,0 +1,428 @@ +//todo: toothbrushes, and some sort of "toilet-filthinator" for the hos + +/obj/structure/toilet + name = "toilet" + desc = "The HT-451, a torque rotation-based, waste disposal unit for small matter. This one seems remarkably clean." + icon = 'icons/obj/watercloset.dmi' + icon_state = "toilet00" + density = 0 + anchored = 1 + var/open = 0 //if the lid is up + var/cistern = 0 //if the cistern bit is open + var/w_items = 0 //the combined w_class of all the items in the cistern + var/mob/living/swirlie = null //the mob being given a swirlie + +/obj/structure/toilet/New() + open = round(rand(0, 1)) + update_icon() + +/obj/structure/toilet/attack_hand(mob/living/user as mob) + if(swirlie) + usr.visible_message("[user] slams the toilet seat onto [swirlie.name]'s head!", "You slam the toilet seat onto [swirlie.name]'s head!", "You hear reverberating porcelain.") + swirlie.adjustBruteLoss(8) + return + + if(cistern && !open) + if(!contents.len) + to_chat(user, "The cistern is empty.") + return + else + var/obj/item/I = pick(contents) + if(ishuman(user)) + user.put_in_hands(I) + else + I.loc = get_turf(src) + to_chat(user, "You find \an [I] in the cistern.") + w_items -= I.w_class + return + + open = !open + update_icon() + +/obj/structure/toilet/update_icon() + icon_state = "toilet[open][cistern]" + +/obj/structure/toilet/attackby(obj/item/I as obj, mob/living/user as mob) + if(isCrowbar(I)) + to_chat(user, "You start to [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"].") + playsound(loc, 'sound/effects/stonedoor_openclose.ogg', 50, 1) + if(do_after(user, 30, src)) + user.visible_message("[user] [cistern ? "replaces the lid on the cistern" : "lifts the lid off the cistern"]!", "You [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"]!", "You hear grinding porcelain.") + cistern = !cistern + update_icon() + return + + if(cistern && !istype(user,/mob/living/silicon/robot)) //STOP PUTTING YOUR MODULES IN THE TOILET. + if(I.w_class > ITEM_SIZE_NORMAL) + to_chat(user, "\The [I] does not fit.") + return + if(w_items + I.w_class > 5) + to_chat(user, "The cistern is full.") + return + user.drop_item() + I.loc = src + w_items += I.w_class + to_chat(user, "You carefully place \the [I] into the cistern.") + return + + + +/obj/structure/urinal + name = "urinal" + desc = "The HU-452, an experimental urinal." + icon = 'icons/obj/watercloset.dmi' + icon_state = "urinal" + density = 0 + anchored = 1 + +/obj/machinery/shower + name = "shower" + desc = "The best in class HS-451 shower unit has three temperature settings, one more than the HS-450 which preceded it." + icon = 'icons/obj/watercloset.dmi' + icon_state = "shower" + density = 0 + anchored = 1 + use_power = 0 + var/on = 0 + var/obj/effect/mist/mymist = null + var/ismist = 0 //needs a var so we can make it linger~ + var/watertemp = "normal" //freezing, normal, or boiling + var/is_washing = 0 + var/list/temperature_settings = list("normal" = 310, "boiling" = T0C+100, "freezing" = T0C) + +/obj/machinery/shower/New() + ..() + create_reagents(50) + +//add heat controls? when emagged, you can freeze to death in it? + +/obj/effect/mist + name = "mist" + icon = 'icons/obj/watercloset.dmi' + icon_state = "mist" + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + anchored = 1 + mouse_opacity = 0 + +/obj/machinery/shower/attack_hand(mob/M as mob) + on = !on + update_icon() + if(on) + if (M.loc == loc) + wash(M) + process_heat(M) + for (var/atom/movable/G in src.loc) + G.clean_blood() + +/obj/machinery/shower/attackby(obj/item/I as obj, mob/user as mob) + if(I.type == /obj/item/device/analyzer) + to_chat(user, "The water temperature seems to be [watertemp].") + if(isWrench(I)) + var/newtemp = input(user, "What setting would you like to set the temperature valve to?", "Water Temperature Valve") in temperature_settings + to_chat(user, "You begin to adjust the temperature valve with \the [I].") + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + if(do_after(user, 50, src)) + watertemp = newtemp + user.visible_message("\The [user] adjusts \the [src] with \the [I].", "You adjust the shower with \the [I].") + add_fingerprint(user) + +/obj/machinery/shower/update_icon() //this is terribly unreadable, but basically it makes the shower mist up + overlays.Cut() //once it's been on for a while, in addition to handling the water overlay. + if(mymist) + qdel(mymist) + mymist = null + + if(on) + overlays += image('icons/obj/watercloset.dmi', src, "water", BASE_MOB_LAYER + 1, dir) + if(temperature_settings[watertemp] < T20C) + return //no mist for cold water + if(!ismist) + spawn(50) + if(src && on) + ismist = 1 + mymist = new /obj/effect/mist(loc) + else + ismist = 1 + mymist = new /obj/effect/mist(loc) + else if(ismist) + ismist = 1 + mymist = new /obj/effect/mist(loc) + spawn(250) + if(src && !on) + qdel(mymist) + mymist = null + ismist = 0 + +//Yes, showers are super powerful as far as washing goes. +/obj/machinery/shower/proc/wash(atom/movable/O as obj|mob) + if(!on) return + + if(isliving(O)) + var/mob/living/L = O + L.ExtinguishMob() + L.fire_stacks = -20 //Douse ourselves with water to avoid fire more easily + + if(iscarbon(O)) + var/mob/living/carbon/M = O + if(M.r_hand) + M.r_hand.clean_blood() + if(M.l_hand) + M.l_hand.clean_blood() + if(M.back) + if(M.back.clean_blood()) + M.update_inv_back(0) + + //flush away reagents on the skin + if(M.touching) + var/remove_amount = M.touching.maximum_volume * M.reagent_permeability() //take off your suit first + M.touching.remove_any(remove_amount) + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/washgloves = 1 + var/washshoes = 1 + var/washmask = 1 + var/washears = 1 + var/washglasses = 1 + + if(H.wear_suit) + washgloves = !(H.wear_suit.flags_inv & HIDEGLOVES) + washshoes = !(H.wear_suit.flags_inv & HIDESHOES) + + if(H.head) + washmask = !(H.head.flags_inv & HIDEMASK) + washglasses = !(H.head.flags_inv & HIDEEYES) + washears = !(H.head.flags_inv & HIDEEARS) + + if(H.wear_mask) + if (washears) + washears = !(H.wear_mask.flags_inv & HIDEEARS) + if (washglasses) + washglasses = !(H.wear_mask.flags_inv & HIDEEYES) + + if(H.head) + if(H.head.clean_blood()) + H.update_inv_head(0) + if(H.wear_suit) + if(H.wear_suit.clean_blood()) + H.update_inv_wear_suit(0) + else if(H.w_uniform) + if(H.w_uniform.clean_blood()) + H.update_inv_w_uniform(0) + if(H.gloves && washgloves) + if(H.gloves.clean_blood()) + H.update_inv_gloves(0) + if(H.shoes && washshoes) + if(H.shoes.clean_blood()) + H.update_inv_shoes(0) + if(H.wear_mask && washmask) + if(H.wear_mask.clean_blood()) + H.update_inv_wear_mask(0) + if(H.glasses && washglasses) + if(H.glasses.clean_blood()) + H.update_inv_glasses(0) + if(H.l_ear && washears) + if(H.l_ear.clean_blood()) + H.update_inv_ears(0) + if(H.r_ear && washears) + if(H.r_ear.clean_blood()) + H.update_inv_ears(0) + if(H.belt) + if(H.belt.clean_blood()) + H.update_inv_belt(0) + H.clean_blood(washshoes) + else + if(M.wear_mask) //if the mob is not human, it cleans the mask without asking for bitflags + if(M.wear_mask.clean_blood()) + M.update_inv_wear_mask(0) + M.clean_blood() + else + O.clean_blood() + + if(isturf(loc)) + var/turf/tile = loc + for(var/obj/effect/E in tile) + if(istype(E,/obj/effect/rune) || istype(E,/obj/effect/decal/cleanable) || istype(E,/obj/effect/overlay)) + qdel(E) + + reagents.splash(O, 10) + +/obj/machinery/shower/Process() + if(!on) return + + for(var/thing in loc) + var/atom/movable/AM = thing + var/mob/living/L = thing + if(istype(AM) && AM.simulated) + wash(AM) + if(istype(L)) + process_heat(L) + wash_floor() + reagents.add_reagent(/datum/reagent/water, reagents.get_free_space()) + +/obj/machinery/shower/proc/wash_floor() + if(!ismist && is_washing) + return + is_washing = 1 + var/turf/T = get_turf(src) + reagents.splash(T, reagents.total_volume) + T.clean(src) + spawn(100) + is_washing = 0 + +/obj/machinery/shower/proc/process_heat(mob/living/M) + if(!on || !istype(M)) return + + var/temperature = temperature_settings[watertemp] + var/temp_adj = between(BODYTEMP_COOLING_MAX, temperature - M.bodytemperature, BODYTEMP_HEATING_MAX) + M.bodytemperature += temp_adj + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(temperature >= H.species.heat_level_1) + to_chat(H, "The water is searing hot!") + else if(temperature <= H.species.cold_level_1) + to_chat(H, "The water is freezing cold!") + +/obj/item/weapon/bikehorn/rubberducky + name = "rubber ducky" + desc = "Rubber ducky you're so fine, you make bathtime lots of fuuun. Rubber ducky I'm awfully fooooond of yooooouuuu~" //thanks doohl + icon = 'icons/obj/watercloset.dmi' + icon_state = "rubberducky" + item_state = "rubberducky" + + + +/obj/structure/sink + name = "sink" + icon = 'icons/obj/watercloset.dmi' + icon_state = "sink" + desc = "A sink used for washing one's hands and face." + anchored = 1 + var/busy = 0 //Something's being washed at the moment + +/obj/structure/sink/MouseDrop_T(var/obj/item/thing, var/mob/user) + ..() + if(!istype(thing) || !thing.is_open_container()) + return ..() + if(!usr.Adjacent(src)) + return ..() + if(!thing.reagents || thing.reagents.total_volume == 0) + to_chat(usr, "\The [thing] is empty.") + return + // Clear the vessel. + visible_message("\The [usr] tips the contents of \the [thing] into \the [src].") + thing.reagents.clear_reagents() + thing.update_icon() + +/obj/structure/sink/attack_hand(mob/user as mob) + if (ishuman(user)) + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/temp = H.organs_by_name[BP_R_HAND] + if (user.hand) + temp = H.organs_by_name[BP_L_HAND] + if(temp && !temp.is_usable()) + to_chat(user, "You try to move your [temp.name], but cannot!") + return + + if(isrobot(user) || isAI(user)) + return + + if(!Adjacent(user)) + return + + if(busy) + to_chat(user, "Someone's already washing here.") + return + + to_chat(usr, "You start washing your hands.") + playsound(loc, 'sound/effects/sink.ogg', 25, 1) + + busy = 1 + sleep(40) + busy = 0 + + if(!Adjacent(user)) return //Person has moved away from the sink + + user.clean_blood() + if(ishuman(user)) + user:update_inv_gloves() + for(var/mob/V in viewers(src, null)) + V.show_message("[user] washes their hands using \the [src].") + + +/obj/structure/sink/attackby(obj/item/O as obj, mob/living/user as mob) + if(busy) + to_chat(user, "Someone's already washing here.") + return + + var/obj/item/weapon/reagent_containers/RG = O + if (istype(RG) && RG.is_open_container()) + RG.reagents.add_reagent(/datum/reagent/water, min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this)) + user.visible_message("[user] fills \the [RG] using \the [src].","You fill \the [RG] using \the [src].") + return 1 + + else if (istype(O, /obj/item/weapon/melee/baton)) + var/obj/item/weapon/melee/baton/B = O + if(B.bcell) + if(B.bcell.charge > 0 && B.status == 1) + flick("baton_active", src) + user.Stun(10) + user.stuttering = 10 + user.Weaken(10) + if(isrobot(user)) + var/mob/living/silicon/robot/R = user + R.cell.charge -= 20 + else + B.deductcharge(B.hitcost) + user.visible_message( \ + "[user] was stunned by \his wet [O]!", \ + "[user] was stunned by \his wet [O]!") + return 1 + else if(istype(O, /obj/item/weapon/mop)) + O.reagents.add_reagent(/datum/reagent/water, 5) + to_chat(user, "You wet \the [O] in \the [src].") + playsound(loc, 'sound/effects/slosh.ogg', 25, 1) + return + + var/turf/location = user.loc + if(!isturf(location)) return + + var/obj/item/I = O + if(!I || !istype(I,/obj/item)) return + + to_chat(usr, "You start washing \the [I].") + + busy = 1 + sleep(40) + busy = 0 + + if(user.loc != location) return //User has moved + if(!I) return //Item's been destroyed while washing + if(user.get_active_hand() != I) return //Person has switched hands or the item in their hands + + O.clean_blood() + user.visible_message( \ + "[user] washes \a [I] using \the [src].", \ + "You wash \a [I] using \the [src].") + + +/obj/structure/sink/kitchen + name = "kitchen sink" + icon_state = "sink_alt" + +/obj/structure/sink/puddle //splishy splashy ^_^ + name = "puddle" + icon_state = "puddle" + desc = "A small pool of some liquid, ostensibly water." + +/obj/structure/sink/puddle/attack_hand(mob/M as mob) + icon_state = "puddle-splash" + ..() + icon_state = "puddle" + +/obj/structure/sink/puddle/attackby(obj/item/O as obj, mob/user as mob) + icon_state = "puddle-splash" + ..() + icon_state = "puddle" diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm new file mode 100644 index 00000000..e519cd7e --- /dev/null +++ b/code/game/objects/structures/windoor_assembly.dm @@ -0,0 +1,297 @@ +/* Windoor (window door) assembly -Nodrak + * Step 1: Create a windoor out of rglass + * Step 2: Add r-glass to the assembly to make a secure windoor (Optional) + * Step 3: Rotate or Flip the assembly to face and open the way you want + * Step 4: Wrench the assembly in place + * Step 5: Add cables to the assembly + * Step 6: Set access for the door. + * Step 7: Crowbar the door to complete + */ + + +obj/structure/windoor_assembly + name = "windoor assembly" + icon = 'icons/obj/doors/windoor.dmi' + icon_state = "l_windoor_assembly01" + anchored = 0 + density = 0 + dir = NORTH + w_class = ITEM_SIZE_NORMAL + + var/obj/item/weapon/airlock_electronics/electronics = null + + //Vars to help with the icon's name + var/facing = "l" //Does the windoor open to the left or right? + var/secure = "" //Whether or not this creates a secure windoor + var/state = "01" //How far the door assembly has progressed in terms of sprites + +obj/structure/windoor_assembly/New(Loc, start_dir=NORTH, constructed=0) + ..() + if(constructed) + state = "01" + anchored = 0 + switch(start_dir) + if(NORTH, SOUTH, EAST, WEST) + set_dir(start_dir) + else //If the user is facing northeast. northwest, southeast, southwest or north, default to north + set_dir(NORTH) + + update_nearby_tiles(need_rebuild=1) + +obj/structure/windoor_assembly/Destroy() + set_density(0) + update_nearby_tiles() + ..() + +/obj/structure/windoor_assembly/update_icon() + icon_state = "[facing]_[secure]windoor_assembly[state]" + +/obj/structure/windoor_assembly/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(istype(mover) && mover.checkpass(PASS_FLAG_GLASS)) + return 1 + if(get_dir(loc, target) == dir) //Make sure looking at appropriate border + if(air_group) return 0 + return !density + else + return 1 + +/obj/structure/windoor_assembly/CheckExit(atom/movable/mover as mob|obj, turf/target as turf) + if(istype(mover) && mover.checkpass(PASS_FLAG_GLASS)) + return 1 + if(get_dir(loc, target) == dir) + return !density + else + return 1 + + +/obj/structure/windoor_assembly/attackby(obj/item/W as obj, mob/user as mob) + //I really should have spread this out across more states but thin little windoors are hard to sprite. + switch(state) + if("01") + if(isWelder(W) && !anchored ) + var/obj/item/weapon/weldingtool/WT = W + if (WT.remove_fuel(0,user)) + user.visible_message("[user] dissassembles the windoor assembly.", "You start to dissassemble the windoor assembly.") + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + + if(do_after(user, 40,src)) + if(!src || !WT.isOn()) return + to_chat(user, "You dissasembled the windoor assembly!") + new /obj/item/stack/material/glass/reinforced(get_turf(src), 5) + if(secure) + new /obj/item/stack/rods(get_turf(src), 4) + qdel(src) + else + to_chat(user, "You need more welding fuel to dissassemble the windoor assembly.") + return + + //Wrenching an unsecure assembly anchors it in place. Step 4 complete + if(isWrench(W) && !anchored) + playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + user.visible_message("[user] secures the windoor assembly to the floor.", "You start to secure the windoor assembly to the floor.") + + if(do_after(user, 40,src)) + if(!src) return + to_chat(user, "You've secured the windoor assembly!") + src.anchored = 1 + if(src.secure) + src.SetName("Secure Anchored Windoor Assembly") + else + src.SetName("Anchored Windoor Assembly") + + //Unwrenching an unsecure assembly un-anchors it. Step 4 undone + else if(isWrench(W) && anchored) + playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + user.visible_message("[user] unsecures the windoor assembly to the floor.", "You start to unsecure the windoor assembly to the floor.") + + if(do_after(user, 40,src)) + if(!src) return + to_chat(user, "You've unsecured the windoor assembly!") + src.anchored = 0 + if(src.secure) + src.SetName("Secure Windoor Assembly") + else + src.SetName("Windoor Assembly") + + //Adding plasteel makes the assembly a secure windoor assembly. Step 2 (optional) complete. + else if(istype(W, /obj/item/stack/rods) && !secure) + var/obj/item/stack/rods/R = W + if(R.get_amount() < 4) + to_chat(user, "You need more rods to do this.") + return + to_chat(user, "You start to reinforce the windoor with rods.") + + if(do_after(user,40,src) && !secure) + if (R.use(4)) + to_chat(user, "You reinforce the windoor.") + src.secure = "secure_" + if(src.anchored) + src.SetName("Secure Anchored Windoor Assembly") + else + src.SetName("Secure Windoor Assembly") + + //Adding cable to the assembly. Step 5 complete. + else if(istype(W, /obj/item/stack/cable_coil) && anchored) + user.visible_message("[user] wires the windoor assembly.", "You start to wire the windoor assembly.") + + var/obj/item/stack/cable_coil/CC = W + if(do_after(user, 40,src)) + if (CC.use(1)) + to_chat(user, "You wire the windoor!") + src.state = "02" + if(src.secure) + src.SetName("Secure Wired Windoor Assembly") + else + src.SetName("Wired Windoor Assembly") + else + ..() + + if("02") + + //Removing wire from the assembly. Step 5 undone. + if(isWirecutter(W) && !src.electronics) + playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) + user.visible_message("[user] cuts the wires from the airlock assembly.", "You start to cut the wires from airlock assembly.") + + if(do_after(user, 40,src)) + if(!src) return + + to_chat(user, "You cut the windoor wires.!") + new/obj/item/stack/cable_coil(get_turf(user), 1) + src.state = "01" + if(src.secure) + src.SetName("Secure Anchored Windoor Assembly") + else + src.SetName("Anchored Windoor Assembly") + + //Adding airlock electronics for access. Step 6 complete. + else if(istype(W, /obj/item/weapon/airlock_electronics) && W:icon_state != "door_electronics_smoked") + playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) + user.visible_message("[user] installs the electronics into the airlock assembly.", "You start to install electronics into the airlock assembly.") + + if(do_after(user, 40,src)) + if(!src) return + + user.drop_item() + W.loc = src + to_chat(user, "You've installed the airlock electronics!") + src.SetName("Near finished Windoor Assembly") + src.electronics = W + else + W.loc = src.loc + + //Screwdriver to remove airlock electronics. Step 6 undone. + else if(isScrewdriver(W) && src.electronics) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) + user.visible_message("[user] removes the electronics from the airlock assembly.", "You start to uninstall electronics from the airlock assembly.") + + if(do_after(user, 40,src)) + if(!src || !src.electronics) return + to_chat(user, "You've removed the airlock electronics!") + if(src.secure) + src.SetName("Secure Wired Windoor Assembly") + else + src.SetName("Wired Windoor Assembly") + var/obj/item/weapon/airlock_electronics/ae = electronics + electronics = null + ae.loc = src.loc + + //Crowbar to complete the assembly, Step 7 complete. + else if(isCrowbar(W)) + if(!src.electronics) + to_chat(usr, "The assembly is missing electronics.") + return + usr << browse(null, "window=windoor_access") + playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) + user.visible_message("[user] pries the windoor into the frame.", "You start prying the windoor into the frame.") + + if(do_after(user, 40,src)) + + if(!src) return + + set_density(1) //Shouldn't matter but just incase + to_chat(user, "You finish the windoor!") + + if(secure) + var/obj/machinery/door/window/brigdoor/windoor = new /obj/machinery/door/window/brigdoor(src.loc) + if(src.facing == "l") + windoor.icon_state = "leftsecureopen" + windoor.base_state = "leftsecure" + else + windoor.icon_state = "rightsecureopen" + windoor.base_state = "rightsecure" + windoor.set_dir(src.dir) + windoor.set_density(0) + + if(src.electronics.one_access) + windoor.req_access = null + windoor.req_one_access = src.electronics.conf_access + else + windoor.req_access = src.electronics.conf_access + windoor.electronics = src.electronics + src.electronics.loc = windoor + else + var/obj/machinery/door/window/windoor = new /obj/machinery/door/window(src.loc) + if(src.facing == "l") + windoor.icon_state = "leftopen" + windoor.base_state = "left" + else + windoor.icon_state = "rightopen" + windoor.base_state = "right" + windoor.set_dir(src.dir) + windoor.set_density(0) + + if(src.electronics.one_access) + windoor.req_access = null + windoor.req_one_access = src.electronics.conf_access + else + windoor.req_access = src.electronics.conf_access + windoor.electronics = src.electronics + src.electronics.loc = windoor + + + qdel(src) + + + else + ..() + + //Update to reflect changes(if applicable) + update_icon() + + +//Rotates the windoor assembly clockwise +/obj/structure/windoor_assembly/verb/revrotate() + set name = "Rotate Windoor Assembly" + set category = "Object" + set src in oview(1) + + if (src.anchored) + to_chat(usr, "It is fastened to the floor; therefore, you can't rotate it!") + return 0 + if(src.state != "01") + update_nearby_tiles(need_rebuild=1) //Compel updates before + + src.set_dir(turn(src.dir, 270)) + + if(src.state != "01") + update_nearby_tiles(need_rebuild=1) + + update_icon() + return + +//Flips the windoor assembly, determines whather the door opens to the left or the right +/obj/structure/windoor_assembly/verb/flip() + set name = "Flip Windoor Assembly" + set category = "Object" + set src in oview(1) + + if(src.facing == "l") + to_chat(usr, "The windoor will now slide to the right.") + src.facing = "r" + else + src.facing = "l" + to_chat(usr, "The windoor will now slide to the left.") + + update_icon() + return diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm new file mode 100644 index 00000000..1c735484 --- /dev/null +++ b/code/game/objects/structures/window.dm @@ -0,0 +1,578 @@ +/obj/structure/window + name = "window" + desc = "A window." + icon = 'icons/obj/structures.dmi' + density = 1 + w_class = ITEM_SIZE_NORMAL + + layer = SIDE_WINDOW_LAYER + anchored = 1.0 + atom_flags = ATOM_FLAG_CHECKS_BORDER + var/maxhealth = 14.0 + var/maximal_heat = T0C + 100 // Maximal heat before this window begins taking damage from fire + var/damage_per_fire_tick = 2.0 // Amount of damage per fire tick. Regular windows are not fireproof so they might as well break quickly. + var/health + var/ini_dir = null + var/state = 2 + var/reinf = 0 + var/polarized = 0 + var/basestate + var/shardtype = /obj/item/weapon/material/shard + var/glasstype = null // Set this in subtypes. Null is assumed strange or otherwise impossible to dismantle, such as for shuttle glass. + var/silicate = 0 // number of units of silicate + + atmos_canpass = CANPASS_PROC + +/obj/structure/window/examine(mob/user) + . = ..(user) + + if(health == maxhealth) + to_chat(user, "It looks fully intact.") + else + var/perc = health / maxhealth + if(perc > 0.75) + to_chat(user, "It has a few cracks.") + else if(perc > 0.5) + to_chat(user, "It looks slightly damaged.") + else if(perc > 0.25) + to_chat(user, "It looks moderately damaged.") + else + to_chat(user, "It looks heavily damaged.") + if(silicate) + if (silicate < 30) + to_chat(user, "It has a thin layer of silicate.") + else if (silicate < 70) + to_chat(user, "It is covered in silicate.") + else + to_chat(user, "There is a thick layer of silicate covering it.") + +/obj/structure/window/proc/take_damage(var/damage = 0, var/sound_effect = 1) + var/initialhealth = health + + if(silicate) + damage = damage * (1 - silicate / 200) + + health = max(0, health - damage) + + if(health <= 0) + shatter() + else + if(sound_effect) + playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1) + if(health < maxhealth / 4 && initialhealth >= maxhealth / 4) + visible_message("[src] looks like it's about to shatter!" ) + else if(health < maxhealth / 2 && initialhealth >= maxhealth / 2) + visible_message("[src] looks seriously damaged!" ) + else if(health < maxhealth * 3/4 && initialhealth >= maxhealth * 3/4) + visible_message("Cracks begin to appear in [src]!" ) + return + +/obj/structure/window/proc/apply_silicate(var/amount) + if(health < maxhealth) // Mend the damage + health = min(health + amount * 3, maxhealth) + if(health == maxhealth) + visible_message("[src] looks fully repaired." ) + else // Reinforce + silicate = min(silicate + amount, 100) + updateSilicate() + +/obj/structure/window/proc/updateSilicate() + if (overlays) + overlays.Cut() + + var/image/img = image(src.icon, src.icon_state) + img.color = "#ffffff" + img.alpha = silicate * 255 / 100 + overlays += img + +/obj/structure/window/proc/shatter(var/display_message = 1) + playsound(src, "shatter", 70, 1) + if(display_message) + visible_message("[src] shatters!") + + cast_new(shardtype, is_fulltile() ? 4 : 1, loc) + if(reinf) cast_new(/obj/item/stack/rods, is_fulltile() ? 4 : 1, loc) + qdel(src) + return + + +/obj/structure/window/bullet_act(var/obj/item/projectile/Proj) + + var/proj_damage = Proj.get_structure_damage() + if(!proj_damage) return + + ..() + take_damage(proj_damage) + return + + +/obj/structure/window/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + shatter(0) + return + if(3.0) + if(prob(50)) + shatter(0) + return + +//TODO: Make full windows a separate type of window. +//Once a full window, it will always be a full window, so there's no point +//having the same type for both. +/obj/structure/window/proc/is_full_window() + return (dir == SOUTHWEST || dir == SOUTHEAST || dir == NORTHWEST || dir == NORTHEAST) + +/obj/structure/window/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(istype(mover) && mover.checkpass(PASS_FLAG_GLASS)) + return 1 + if(is_full_window()) + return 0 //full tile window, you can't move into it! + if(get_dir(loc, target) & dir) + return !density + else + return 1 + + +/obj/structure/window/CheckExit(atom/movable/O as mob|obj, target as turf) + if(istype(O) && O.checkpass(PASS_FLAG_GLASS)) + return 1 + if(get_dir(O.loc, target) == dir) + return 0 + return 1 + + +/obj/structure/window/hitby(AM as mob|obj) + ..() + visible_message("[src] was hit by [AM].") + var/tforce = 0 + if(ismob(AM)) // All mobs have a multiplier and a size according to mob_defines.dm + var/mob/I = AM + tforce = I.mob_size * 2 * I.throw_multiplier + else if(isobj(AM)) + var/obj/item/I = AM + tforce = I.throwforce + if(reinf) tforce *= 0.25 + if(health - tforce <= 7 && !reinf) + set_anchored(FALSE) + step(src, get_dir(AM, src)) + take_damage(tforce) + +/obj/structure/window/attack_tk(mob/user as mob) + user.visible_message("Something knocks on [src].") + playsound(loc, 'sound/effects/Glasshit.ogg', 50, 1) + +/obj/structure/window/attack_hand(mob/user as mob) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(HULK in user.mutations) + user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!")) + user.visible_message("[user] smashes through [src]!") + shatter() + + else if (usr.a_intent == I_HURT) + + if (istype(usr,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = usr + if(H.species.can_shred(H)) + attack_generic(H,25) + return + + playsound(src.loc, 'sound/effects/glassknock.ogg', 80, 1) + usr.visible_message("\The [usr] bangs against \the [src]!", + "You bang against \the [src]!", + "You hear a banging sound.") + else + playsound(src.loc, 'sound/effects/glassknock.ogg', 80, 1) + usr.visible_message("[usr.name] knocks on the [src.name].", + "You knock on the [src.name].", + "You hear a knocking sound.") + return + +/obj/structure/window/attack_generic(var/mob/user, var/damage) + if(istype(user)) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(!damage) + return + if(damage >= 10) + visible_message("[user] smashes into [src]!") + take_damage(damage) + else + visible_message("\The [user] bonks \the [src] harmlessly.") + return 1 + +/obj/structure/window/attackby(obj/item/W as obj, mob/user as mob) + if(!istype(W)) return//I really wish I did not need this + + if(W.item_flags & ITEM_FLAG_NO_BLUDGEON) return + + if(isScrewdriver(W)) + if(reinf && state >= 1) + state = 3 - state + update_nearby_icons() + playsound(loc, 'sound/items/Screwdriver.ogg', 75, 1) + to_chat(user, (state == 1 ? "You have unfastened the window from the frame." : "You have fastened the window to the frame.")) + else if(reinf && state == 0) + set_anchored(!anchored) + playsound(loc, 'sound/items/Screwdriver.ogg', 75, 1) + to_chat(user, (anchored ? "You have fastened the frame to the floor." : "You have unfastened the frame from the floor.")) + else if(!reinf) + set_anchored(!anchored) + playsound(loc, 'sound/items/Screwdriver.ogg', 75, 1) + to_chat(user, (anchored ? "You have fastened the window to the floor." : "You have unfastened the window.")) + else if(isCrowbar(W) && reinf && state <= 1) + state = 1 - state + playsound(loc, 'sound/items/Crowbar.ogg', 75, 1) + to_chat(user, (state ? "You have pried the window into the frame." : "You have pried the window out of the frame.")) + else if(isWrench(W) && !anchored && (!state || !reinf)) + if(!glasstype) + to_chat(user, "You're not sure how to dismantle \the [src] properly.") + else + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + visible_message("[user] dismantles \the [src].") + if(dir == SOUTHWEST) + var/obj/item/stack/material/mats = new glasstype(loc) + mats.amount = is_fulltile() ? 4 : 2 + else + new glasstype(loc) + qdel(src) + else if(isCoil(W) && reinf && !polarized) + var/obj/item/stack/cable_coil/C = W + if (C.use(1)) + playsound(src.loc, 'sound/effects/sparks1.ogg', 75, 1) + var/obj/structure/window/reinforced/polarized/P = new(loc) + P.set_dir(dir) + P.health = health + P.state = state + qdel(src) + else + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(W.damtype == BRUTE || W.damtype == BURN) + hit(W.force) + if(health <= 7) + set_anchored(FALSE) + step(src, get_dir(user, src)) + update_verbs() + else + playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1) + ..() + return + +/obj/structure/window/proc/hit(var/damage, var/sound_effect = 1) + if(reinf) damage *= 0.5 + take_damage(damage) + return + + +/obj/structure/window/proc/rotate() + set name = "Rotate Window Counter-Clockwise" + set category = "Object" + + if(usr.incapacitated()) + return 0 + + if(anchored) + to_chat(usr, "It is fastened to the floor therefore you can't rotate it!") + return 0 + + update_nearby_tiles(need_rebuild=1) //Compel updates before + set_dir(turn(dir, 90)) + updateSilicate() + update_nearby_tiles(need_rebuild=1) + return + +/obj/structure/window/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + rotate() + +/obj/structure/window/proc/revrotate() + set name = "Rotate Window Clockwise" + set category = "Object" + set src in oview(1) + + if(usr.incapacitated()) + return 0 + + if(anchored) + to_chat(usr, "It is fastened to the floor therefore you can't rotate it!") + return 0 + + update_nearby_tiles(need_rebuild=1) //Compel updates before + set_dir(turn(dir, 270)) + updateSilicate() + update_nearby_tiles(need_rebuild=1) + return + +/obj/structure/window/New(Loc, start_dir=null, constructed=0) + ..() + + //player-constructed windows + if (constructed) + set_anchored(FALSE) + + if (start_dir) + set_dir(start_dir) + + if(is_fulltile()) + maxhealth *= 4 + + health = maxhealth + + ini_dir = dir + + update_nearby_tiles(need_rebuild=1) + update_nearby_icons() + + +/obj/structure/window/Destroy() + set_density(0) + update_nearby_tiles() + var/turf/location = loc + . = ..() + for(var/obj/structure/window/W in orange(location, 1)) + W.update_icon() + + +/obj/structure/window/Move() + var/ini_dir = dir + update_nearby_tiles(need_rebuild=1) + ..() + set_dir(ini_dir) + update_nearby_tiles(need_rebuild=1) + +//checks if this window is full-tile one +/obj/structure/window/proc/is_fulltile() + if(dir & (dir - 1)) + return 1 + return 0 + +/obj/structure/window/proc/set_anchored(var/new_anchored) + if(anchored == new_anchored) + return + anchored = new_anchored + update_verbs() + update_nearby_icons() + +//This proc is used to update the icons of nearby windows. It should not be confused with update_nearby_tiles(), which is an atmos proc! +/obj/structure/window/proc/update_nearby_icons() + update_icon() + for(var/obj/structure/window/W in orange(src, 1)) + W.update_icon() + +//Updates the availabiliy of the rotation verbs +/obj/structure/window/proc/update_verbs() + if(anchored) + verbs -= /obj/structure/window/proc/rotate + verbs -= /obj/structure/window/proc/revrotate + else + verbs += /obj/structure/window/proc/rotate + verbs += /obj/structure/window/proc/revrotate + +//merges adjacent full-tile windows into one (blatant ripoff from game/smoothwall.dm) +/obj/structure/window/update_icon() + //A little cludge here, since I don't know how it will work with slim windows. Most likely VERY wrong. + //this way it will only update full-tile ones + overlays.Cut() + layer = FULL_WINDOW_LAYER + if(!is_fulltile()) + layer = SIDE_WINDOW_LAYER + icon_state = "[basestate]" + return + var/list/dirs = list() + if(anchored) + for(var/obj/structure/window/W in orange(src,1)) + if(W.anchored && W.density && W.type == src.type && W.is_fulltile()) //Only counts anchored, not-destroyed fill-tile windows. + dirs += get_dir(src, W) + + var/list/connections = dirs_to_corner_states(dirs) + + icon_state = "" + for(var/i = 1 to 4) + var/image/I = image(icon, "[basestate][connections[i]]", dir = 1<<(i-1)) + overlays += I + + return + +/obj/structure/window/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > maximal_heat) + hit(damage_per_fire_tick, 0) + ..() + + + +/obj/structure/window/basic + desc = "It looks thin and flimsy. A few knocks with... anything, really should shatter it." + icon_state = "window" + basestate = "window" + glasstype = /obj/item/stack/material/glass + maximal_heat = T0C + 100 + damage_per_fire_tick = 2.0 + maxhealth = 12.0 + +/obj/structure/window/phoronbasic + name = "phoron window" + desc = "A borosilicate alloy window. It seems to be quite strong." + basestate = "phoronwindow" + icon_state = "phoronwindow" + shardtype = /obj/item/weapon/material/shard/phoron + glasstype = /obj/item/stack/material/glass/phoronglass + maximal_heat = T0C + 2000 + damage_per_fire_tick = 1.0 + maxhealth = 40.0 + +/obj/structure/window/phoronreinforced + name = "reinforced borosilicate window" + desc = "A borosilicate alloy window, with rods supporting it. It seems to be very strong." + basestate = "phoronrwindow" + icon_state = "phoronrwindow" + shardtype = /obj/item/weapon/material/shard/phoron + glasstype = /obj/item/stack/material/glass/phoronrglass + reinf = 1 + maximal_heat = T0C + 4000 + damage_per_fire_tick = 1.0 // This should last for 80 fire ticks if the window is not damaged at all. The idea is that borosilicate windows have something like ablative layer that protects them for a while. + maxhealth = 80.0 + +/obj/structure/window/phoronreinforced/full + dir = 5 + icon_state = "phoronwindow0" + +/obj/structure/window/reinforced + name = "reinforced window" + desc = "It looks rather strong. Might take a few good hits to shatter it." + icon_state = "rwindow" + basestate = "rwindow" + maxhealth = 40.0 + reinf = 1 + maximal_heat = T0C + 750 + damage_per_fire_tick = 2.0 + glasstype = /obj/item/stack/material/glass/reinforced + + +/obj/structure/window/New(Loc, constructed=0) + ..() + + //player-constructed windows + if (constructed) + state = 0 + +/obj/structure/window/Initialize() + . = ..() + layer = is_full_window() ? FULL_WINDOW_LAYER : SIDE_WINDOW_LAYER + +/obj/structure/window/reinforced/full + dir = 5 + icon_state = "fwindow" + +/obj/structure/window/reinforced/tinted + name = "tinted window" + desc = "It looks rather strong and opaque. Might take a few good hits to shatter it." + icon_state = "twindow" + basestate = "twindow" + opacity = 1 + +/obj/structure/window/reinforced/tinted/frosted + name = "frosted window" + desc = "It looks rather strong and frosted over. Looks like it might take a few less hits then a normal reinforced window." + icon_state = "fwindow" + basestate = "fwindow" + maxhealth = 30 + +/obj/structure/window/shuttle + name = "shuttle window" + desc = "It looks rather strong. Might take a few good hits to shatter it." + icon = 'icons/obj/podwindows.dmi' + icon_state = "window" + basestate = "window" + maxhealth = 40 + reinf = 1 + basestate = "w" + dir = 5 + +/obj/structure/window/reinforced/polarized + name = "electrochromic window" + desc = "Adjusts its tint with voltage. Might take a few good hits to shatter it." + var/id + polarized = 1 + +/obj/structure/window/reinforced/polarized/full + dir = 5 + icon_state = "fwindow" + +/obj/structure/window/reinforced/polarized/attackby(obj/item/W as obj, mob/user as mob) + if(isMultitool(W)) + var/t = sanitizeSafe(input(user, "Enter the ID for the window.", src.name, null), MAX_NAME_LEN) + if (user.get_active_hand() != W) + return + if (!in_range(src, user) && src.loc != user) + return + t = sanitizeSafe(t, MAX_NAME_LEN) + if (t) + src.id = t + to_chat(user, "The new ID of the window is [id]") + return + ..() + +/obj/structure/window/reinforced/polarized/proc/toggle() + if(opacity) + animate(src, color="#ffffff", time=5) + set_opacity(0) + else + 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" + icon = 'icons/obj/power.dmi' + icon_state = "light0" + desc = "A remote control switch for electrochromic windows." + var/range = 7 + +/obj/machinery/button/windowtint/attack_hand(mob/user as mob) + if(..()) + return 1 + + toggle_tint() + +/obj/machinery/button/windowtint/attackby(obj/item/device/W as obj, mob/user as mob) + if(isMultitool(W)) + to_chat(user, "The ID of the button: [id]") + return + +/obj/machinery/button/windowtint/proc/toggle_tint() + use_power(5) + + active = !active + update_icon() + + for(var/obj/structure/window/reinforced/polarized/W in range(src,range)) + if (W.id == src.id || !W.id) + spawn(0) + W.toggle() + return + +/obj/machinery/button/windowtint/power_change() + . = ..() + if(active && !powered(power_channel)) + toggle_tint() + +/obj/machinery/button/windowtint/update_icon() + icon_state = "light[active]" diff --git a/code/game/objects/structures/window_frame.dm b/code/game/objects/structures/window_frame.dm new file mode 100644 index 00000000..1c9a3669 --- /dev/null +++ b/code/game/objects/structures/window_frame.dm @@ -0,0 +1,209 @@ + +#define HALF_HEALTH 80 +//I'm feeling really bad of copypasting alot of existing code +/obj/structure/window_frame + name = "window" + density = 1 + anchored = 1 + opacity = 0 + icon = 'icons/obj/cs.dmi' + icon_state = "window1" + layer = SIDE_WINDOW_LAYER + var/maximal_heat = T0C + 100 + var/damage_per_fire_tick = 2.0 + var/maxhealth = 160.0 + var/health + var/glass = TRUE + var/shattered = FALSE + atmos_canpass = CANPASS_PROC + +/obj/structure/window_frame/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + return !glass + +/obj/structure/window_frame/examine(mob/user) + . = ..(user) + + if(health == maxhealth) + to_chat(user, "It looks intact.") + else + if(health <= HALF_HEALTH) + to_chat(user, "It has a lots of cracks.") + +/obj/structure/window_frame/proc/take_damage(var/damage = 0, var/sound_effect = 1) + if(!glass) + return + health = max(0, health - damage) + + if(health <= 0) + shatter() + else + if(sound_effect) + playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1) + if(health <= HALF_HEALTH) + update_icon() + return + +/obj/structure/window_frame/proc/shatter(var/display_message = 1) + if(!glass) + return + playsound(src, "shatter", 70, 1) + if(display_message) + visible_message("[src] shatters!") + + cast_new(/obj/item/weapon/material/shard, 1, loc) + cast_new(/obj/item/stack/rods, 1, loc) + glass = FALSE + shattered = TRUE + update_icon() + update_nearby_tiles() + return + +/obj/structure/window_frame/bullet_act(var/obj/item/projectile/Proj) + + var/proj_damage = Proj.get_structure_damage() + if(!proj_damage) return + + ..() + take_damage(proj_damage) + return + +/obj/structure/window_frame/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + shatter(0) + return + if(3.0) + if(prob(50)) + shatter(0) + return + else + take_damage(100) + return + +/obj/structure/window_frame/hitby(AM as mob|obj) + ..() + visible_message("[src] was hit by [AM].") + var/tforce = 0 + if(ismob(AM)) // All mobs have a multiplier and a size according to mob_defines.dm + var/mob/I = AM + tforce = I.mob_size * 2 * I.throw_multiplier + else if(isobj(AM)) + var/obj/item/I = AM + tforce = I.throwforce + take_damage(tforce) + +/obj/structure/window_frame/attack_tk(mob/user as mob) + user.visible_message("Something knocks on [src].") + playsound(loc, 'sound/effects/Glasshit.ogg', 50, 1) + +/obj/structure/window_frame/attack_hand(mob/user as mob) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(!glass) + if(shattered) + to_chat(usr,"You clear broken glass from the frame.") + var/obj/item/weapon/material/shard/S = new + usr.put_in_hands(S) + shattered = 0 + update_icon() + else + return + else if (usr.a_intent == I_HURT) + if (istype(usr,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = usr + if(H.species.can_shred(H)) + attack_generic(H,25) + return + playsound(src.loc, 'sound/effects/glassknock.ogg', 80, 1) + usr.visible_message("\The [usr] bangs against \the [src]!", + "You bang against \the [src]!", + "You hear a banging sound.") + else + playsound(src.loc, 'sound/effects/glassknock.ogg', 80, 1) + usr.visible_message("[usr.name] knocks on the [src.name].", + "You knock on the [src.name].", + "You hear a knocking sound.") + return + +/obj/structure/window_frame/attack_generic(var/mob/user, var/damage) + if(istype(user)) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(!damage) + return + if(damage >= 10) + visible_message("[user] smashes into [src]!") + take_damage(damage) + else + visible_message("\The [user] bonks \the [src] harmlessly.") + return 1 + +/obj/structure/window_frame/attackby(var/obj/item/W, var/mob/user) + if(!istype(W)) + return + if(istype(W, /obj/item/stack/material/glass/reinforced)) + var/obj/item/stack/material/glass/reinforced/R = W + if(!shattered && !glass) + if(do_after(user, 10, src, same_direction = 1)) + R.use(5) + glass = TRUE + health = maxhealth + update_icon() + update_nearby_tiles() + return + else + if(shattered) + to_chat(usr,"I need to remove shards first.") + if(glass) + to_chat(usr,"There is glass already.") + return + + if(istype(W, /obj/item/stack/material/glass)) + to_chat(usr,"It doesn't fit the frame.") + + if(W.item_flags & ITEM_FLAG_NO_BLUDGEON) + return + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(W.damtype == BRUTE || W.damtype == BURN) + hit(W.force) + else + playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1) + ..() + + +/obj/structure/window_frame/proc/hit(var/damage, var/sound_effect = 1) + take_damage(damage) + return + +/obj/structure/window_frame/New(Loc, start_dir=null, constructed=0) + ..() + + if (start_dir) + set_dir(start_dir) + + health = maxhealth + +/obj/structure/window_frame/Destroy() + set_density(0) + update_nearby_tiles() + . = ..() + +/obj/structure/window_frame/update_icon() + if(glass) + if(health <= HALF_HEALTH) + icon_state = "window2" + else + icon_state = "window1" + else + if(shattered) + icon_state = "window3" + else + icon_state = "window4" + return + +/obj/structure/window_frame/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > maximal_heat) + hit(damage_per_fire_tick, 0) + ..() diff --git a/code/game/objects/structures/window_spawner.dm b/code/game/objects/structures/window_spawner.dm new file mode 100644 index 00000000..4cef45e9 --- /dev/null +++ b/code/game/objects/structures/window_spawner.dm @@ -0,0 +1,131 @@ +// Ported from Haine and WrongEnd with much gratitude! +/* ._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._. */ +/*-=-=-=-=-=-=-=-=-=-=-=-=-=WHAT-EVER=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +/* '~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~' */ + +/obj/effect/wingrille_spawn + name = "window grille spawner" + icon = 'icons/obj/structures.dmi' + icon_state = "wingrille" + density = 1 + anchored = 1.0 + var/win_path = /obj/structure/window/basic + var/activated = FALSE + var/fulltile = FALSE + +// stops ZAS expanding zones past us, the windows will block the zone anyway +/obj/effect/wingrille_spawn/CanPass() + return 0 + +/obj/effect/wingrille_spawn/attack_hand() + attack_generic() + +/obj/effect/wingrille_spawn/attack_ghost() + attack_generic() + +/obj/effect/wingrille_spawn/attack_generic() + activate() + +/obj/effect/wingrille_spawn/Initialize(mapload) + . = ..() + if(!win_path) + return + + // sometimes it's useful to plonk these down and activate them all manually, + // once all your ducks are in a row. So if we're already playing, only + // auto-activate if this has been put down by a maploader, not a creative admin + // see https://github.com/Baystation12/Baystation12/pull/9907#issuecomment-114896669 + var/auto_activate = mapload || (ticker && ticker.current_state < GAME_STATE_PLAYING) + + if(auto_activate) + activate() + return INITIALIZE_HINT_QDEL + +/obj/effect/wingrille_spawn/proc/activate() + if(activated) return + + if(locate(/obj/structure/window) in loc) + warning("Window Spawner: A window structure already exists at [loc.x]-[loc.y]-[loc.z]") + + if(locate(/obj/structure/grille) in loc) + warning("Window Spawner: A grille already exists at [loc.x]-[loc.y]-[loc.z]") + else + var/obj/structure/grille/G = new /obj/structure/grille(loc) + handle_grille_spawn(G) + + var/list/neighbours = list() + if(fulltile) + var/obj/structure/window/new_win = new win_path(loc) + handle_window_spawn(new_win) + else + for (var/dir in GLOB.cardinal) + var/turf/T = get_step(src, dir) + var/obj/effect/wingrille_spawn/other = locate(type) in T + if(!other) + var/found_connection + if(locate(/obj/structure/grille) in T) + for(var/obj/structure/window/W in T) + if(W.type == win_path && W.dir == get_dir(T,src)) + found_connection = 1 + qdel(W) + if(!found_connection) + var/obj/structure/window/new_win = new win_path(loc) + new_win.set_dir(dir) + handle_window_spawn(new_win) + else + neighbours |= other + activated = 1 + for(var/obj/effect/wingrille_spawn/other in neighbours) + if(!other.activated) other.activate() + +/obj/effect/wingrille_spawn/proc/handle_window_spawn(var/obj/structure/window/W) + return + +// Currently unused, could be useful for pre-wired electrified windows. +/obj/effect/wingrille_spawn/proc/handle_grille_spawn(var/obj/structure/grille/G) + return + +/obj/effect/wingrille_spawn/reinforced + name = "reinforced window grille spawner" + icon_state = "r-wingrille" + win_path = /obj/structure/window/reinforced + +/obj/effect/wingrille_spawn/reinforced/full + name = "reinforced window grille spawner - full tile" + icon_state = "rf-wingrille" + fulltile = TRUE + win_path = /obj/structure/window/reinforced/full + +/obj/effect/wingrille_spawn/reinforced/crescent + name = "Crescent window grille spawner" + win_path = /obj/structure/window/reinforced/crescent + +/obj/effect/wingrille_spawn/phoron + name = "phoron window grille spawner" + icon_state = "p-wingrille" + win_path = /obj/structure/window/phoronbasic + +/obj/effect/wingrille_spawn/reinforced_phoron + name = "reinforced phoron window grille spawner" + icon_state = "pr-wingrille" + win_path = /obj/structure/window/phoronreinforced + +/obj/effect/wingrille_spawn/reinforced_phoron/full + name = "reinforced phoron window grille spawner - full tile" + fulltile = TRUE + win_path = /obj/structure/window/phoronreinforced/full + +/obj/effect/wingrille_spawn/reinforced/polarized + name = "polarized window grille spawner" + color = "#444444" + win_path = /obj/structure/window/reinforced/polarized + var/id + +/obj/effect/wingrille_spawn/reinforced/polarized/full + name = "polarized window grille spawner - full tile" + fulltile = TRUE + win_path = /obj/structure/window/reinforced/polarized/full + +/obj/effect/wingrille_spawn/reinforced/polarized/handle_window_spawn(var/obj/structure/window/reinforced/polarized/P) + if(id) + P.id = id diff --git a/code/game/objects/topic.dm b/code/game/objects/topic.dm new file mode 100644 index 00000000..28036836 --- /dev/null +++ b/code/game/objects/topic.dm @@ -0,0 +1,49 @@ +/obj/Topic(var/href, var/href_list = list(), var/datum/topic_state/state = GLOB.default_state) + if((. = ..())) + return + if(CanUseTopic(usr, state, href_list) == STATUS_INTERACTIVE) + CouldUseTopic(usr) + return OnTopic(usr, href_list, state) + CouldNotUseTopic(usr) + +/obj/proc/OnTopic(var/mob/user, var/href_list, var/datum/topic_state/state) + return TOPIC_NOACTION + +/obj/CanUseTopic(var/mob/user, var/datum/topic_state/state, var/href_list) + if(user.CanUseObjTopic(src)) + return ..() + return STATUS_CLOSE + +/mob/living/silicon/CanUseObjTopic(var/obj/O) + var/id = src.GetIdCard() + if(id && O.check_access(id)) + return TRUE + to_chat(src, "\icon[src]Access Denied!") + return FALSE + +/mob/proc/CanUseObjTopic() + return TRUE + +/obj/proc/CouldUseTopic(var/mob/user) + user.AddTopicPrint(src) + +/mob/proc/AddTopicPrint(var/atom/target) + if(!istype(target)) + return + target.add_hiddenprint(src) + +/mob/living/AddTopicPrint(var/atom/target) + if(!istype(target)) + return + if(Adjacent(target)) + target.add_fingerprint(src) + else + target.add_hiddenprint(src) + +/mob/living/silicon/ai/AddTopicPrint(var/atom/target) + if(!istype(target)) + return + target.add_hiddenprint(src) + +/obj/proc/CouldNotUseTopic(var/mob/user) + return diff --git a/code/game/objects/weapons.dm b/code/game/objects/weapons.dm new file mode 100644 index 00000000..b62efa1c --- /dev/null +++ b/code/game/objects/weapons.dm @@ -0,0 +1,9 @@ +/obj/item/weapon + name = "weapon" + icon = 'icons/obj/weapons.dmi' + hitsound = "swing_hit" + +/obj/item/weapon/Bump(mob/M as mob) + spawn(0) + ..() + return \ No newline at end of file diff --git a/code/game/periodic_news.dm b/code/game/periodic_news.dm new file mode 100644 index 00000000..9be7ec93 --- /dev/null +++ b/code/game/periodic_news.dm @@ -0,0 +1,147 @@ +// This system defines news that will be displayed in the course of a round. +// Uses BYOND's type system to put everything into a nice format + +/datum/news_announcement + var + round_time // time of the round at which this should be announced, in seconds + message // body of the message + author = "NanoTrasen Editor" + channel_name = "Nyx Daily" + can_be_redacted = 0 + message_type = "Story" + + revolution_inciting_event + + paycuts_suspicion + round_time = 60*10 + message = {"Reports have leaked that NanoTrasen is planning to put paycuts into + effect on many of its Research Stations in Tau Ceti. Apparently these research + stations haven't been able to yield the expected revenue, and thus adjustments + have to be made."} + author = "Unauthorized" + + paycuts_confirmation + round_time = 60*40 + message = {"Earlier rumours about paycuts on Research Stations in the Tau Ceti system have + been confirmed. Shockingly, however, the cuts will only affect lower tier + personnel. Heads of Staff will, according to our sources, not be affected."} + author = "Unauthorized" + + human_experiments + round_time = 60*90 + message = {"Unbelievable reports about human experimentation have reached our ears. According + to a refugee from one of the Tau Ceti Research Stations, their station, in order + to increase revenue, has refactored several of their facilities to perform experiments + on live humans, including virology research, genetic manipulation, and \"feeding them + to the slimes to see what happens\". Allegedly, these test subjects were neither + humanified monkeys nor volunteers, but rather unqualified staff that were forced into + the experiments, and reported to have died in a \"work accident\" by NanoTrasen."} + author = "Unauthorized" + + bluespace_research + + announcement + round_time = 60*20 + message = {"The new field of research trying to explain several interesting spacetime oddities, + also known as \"Bluespace Research\", has reached new heights. Of the several + hundred space stations now orbiting in Tau Ceti, fifteen are now specially equipped + to experiment with and research Bluespace effects. Rumours have it some of these + stations even sport functional \"travel gates\" that can instantly move a whole research + team to an alternate reality."} + + random_junk + + cheesy_honkers + author = "Assistant Editor Carl Ritz" + channel_name = "The Gibson Gazette" + message = {"Do cheesy honkers increase risk of having a miscarriage? Several health administrations + say so!"} + round_time = 60 * 15 + + net_block + author = "Assistant Editor Carl Ritz" + channel_name = "The Gibson Gazette" + message = {"Several corporations banding together to block access to 'wetskrell.nt', site administrators + claiming violation of net laws."} + round_time = 60 * 50 + + found_ssd + channel_name = "Nyx Daily" + author = "Doctor Eric Hanfield" + + message = {"Several people have been found unconscious at their terminals. It is thought that it was due + to a lack of sleep or of simply migraines from staring at the screen too long. Camera footage + reveals that many of them were playing games instead of working and their pay has been docked + accordingly."} + round_time = 60 * 90 + + lotus_tree + + explosions + channel_name = "Nyx Daily" + author = "Reporter Leland H. Howards" + + message = {"The newly-christened civillian transport Lotus Tree suffered two very large explosions near the + bridge today, and there are unconfirmed reports that the death toll has passed 50. The cause of + the explosions remain unknown, but there is speculation that it might have something to do with + the recent change of regulation in the Moore-Lee Corporation, a major funder of the ship, when M-L + announced that they were officially acknowledging inter-species marriage and providing couples + with marriage tax-benefits."} + round_time = 60 * 30 + + food_riots + + breaking_news + channel_name = "Nyx Daily" + author = "Reporter Ro'kii Ar-Raqis" + + message = {"Breaking news: Food riots have broken out throughout the Refuge asteroid colony in the Tenebrae + Lupus system. This comes only hours after NanoTrasen officials announced they will no longer trade with the + colony, citing the increased presence of \"hostile factions\" on the colony has made trade too dangerous to + continue. NanoTrasen officials have not given any details about said factions. More on that at the top of + the hour."} + round_time = 60 * 10 + + more + channel_name = "Nyx Daily" + author = "Reporter Ro'kii Ar-Raqis" + + message = {"More on the Refuge food riots: The Refuge Council has condemned NanoTrasen's withdrawal from + the colony, claiming \"there has been no increase in anti-NanoTrasen activity\", and \"\[the only] reason + NanoTrasen withdrew was because the \[Tenebrae Lupus] system's Phoron deposits have been completely mined out. + We have little to trade with them now\". NanoTrasen officials have denied these allegations, calling them + \"further proof\" of the colony's anti-NanoTrasen stance. Meanwhile, Refuge Security has been unable to quell + the riots. More on this at 6."} + round_time = 60 * 60 + + +var/global/list/newscaster_standard_feeds = list(/datum/news_announcement/bluespace_research, /datum/news_announcement/lotus_tree, /datum/news_announcement/random_junk, /datum/news_announcement/food_riots) + +proc/process_newscaster() + check_for_newscaster_updates(ticker.mode.newscaster_announcements) + +var/global/tmp/announced_news_types = list() +proc/check_for_newscaster_updates(type) + for(var/subtype in typesof(type)-type) + var/datum/news_announcement/news = new subtype() + if(news.round_time * 10 <= world.time && !(subtype in announced_news_types)) + announced_news_types += subtype + announce_newscaster_news(news) + +proc/announce_newscaster_news(datum/news_announcement/news) + var/datum/feed_channel/sendto + for(var/datum/feed_channel/FC in news_network.network_channels) + if(FC.channel_name == news.channel_name) + sendto = FC + break + + if(!sendto) + sendto = new /datum/feed_channel + sendto.channel_name = news.channel_name + sendto.author = news.author + sendto.locked = 1 + sendto.is_admin_channel = 1 + news_network.network_channels += sendto + + var/author = news.author ? news.author : sendto.author + news_network.SubmitArticle(news.message, author, news.channel_name, null, !news.can_be_redacted, news.message_type) diff --git a/code/game/response_team.dm b/code/game/response_team.dm new file mode 100644 index 00000000..38507fbe --- /dev/null +++ b/code/game/response_team.dm @@ -0,0 +1,141 @@ +//STRIKE TEAMS +//Thanks to Kilakk for the admin-button portion of this code. + +var/global/send_emergency_team = 0 // Used for automagic response teams + // 'admin_emergency_team' for admin-spawned response teams +var/ert_base_chance = 10 // Default base chance. Will be incremented by increment ERT chance. +var/can_call_ert + +/client/proc/response_team() + set name = "Dispatch Emergency Response Team" + set category = "Special Verbs" + set desc = "Send an emergency response team" + + if(!holder) + to_chat(usr, "Only administrators may use this command.") + return + if(!ticker) + to_chat(usr, "The game hasn't started yet!") + return + if(ticker.current_state == 1) + to_chat(usr, "The round hasn't started yet!") + return + if(send_emergency_team) + to_chat(usr, "[GLOB.using_map.boss_name] has already dispatched an emergency response team!") + return + if(alert("Do you want to dispatch an Emergency Response Team?",,"Yes","No") != "Yes") + return + + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + if(security_state.current_security_level_is_lower_than(security_state.high_security_level)) // Allow admins to reconsider if the alert level is below High + switch(alert("Current security level lower than [security_state.high_security_level.name]. Do you still want to dispatch a response team?",,"Yes","No")) + if("No") + return + if(send_emergency_team) + to_chat(usr, "Looks like somebody beat you to it!") + return + + message_admins("[key_name_admin(usr)] is dispatching an Emergency Response Team.", 1) + log_admin("[key_name(usr)] used Dispatch Response Team.") + trigger_armed_response_team(1) + +client/verb/JoinResponseTeam() + + set name = "Join Response Team" + set category = "IC" + + if(!MayRespawn(1)) + to_chat(usr, "You cannot join the response team at this time.") + return + + if(isghost(usr) || isnewplayer(usr)) + if(!send_emergency_team) + to_chat(usr, "No emergency response team is currently being sent.") + return + if(jobban_isbanned(usr, MODE_ERT) || jobban_isbanned(usr, "Security Officer")) + to_chat(usr, "You are jobbanned from the emergency reponse team!") + return + if(ert.current_antagonists.len >= ert.hard_cap) + to_chat(usr, "The emergency response team is already full!") + return + ert.create_default(usr) + else + to_chat(usr, "You need to be an observer or new player to use this.") + +// returns a number of dead players in % +proc/percentage_dead() + var/total = 0 + var/deadcount = 0 + for(var/mob/living/carbon/human/H in SSmobs.mob_list) + if(H.client) // Monkeys and mice don't have a client, amirite? + if(H.stat == 2) deadcount++ + total++ + + if(total == 0) return 0 + else return round(100 * deadcount / total) + +// counts the number of antagonists in % +proc/percentage_antagonists() + var/total = 0 + var/antagonists = 0 + for(var/mob/living/carbon/human/H in SSmobs.mob_list) + if(is_special_character(H) >= 1) + antagonists++ + total++ + + if(total == 0) return 0 + else return round(100 * antagonists / total) + +// Increments the ERT chance automatically, so that the later it is in the round, +// the more likely an ERT is to be able to be called. +proc/increment_ert_chance() + while(send_emergency_team == 0) // There is no ERT at the time. + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + var/index = security_state.all_security_levels.Find(security_state.current_security_level) + ert_base_chance += 2**index + sleep(600 * 3) // Minute * Number of Minutes + + +proc/trigger_armed_response_team(var/force = 0) + if(!can_call_ert && !force) + return + if(send_emergency_team) + return + + var/send_team_chance = ert_base_chance // Is incremented by increment_ert_chance. + send_team_chance += 2*percentage_dead() // the more people are dead, the higher the chance + send_team_chance += percentage_antagonists() // the more antagonists, the higher the chance + send_team_chance = min(send_team_chance, 100) + + if(force) send_team_chance = 100 + + // there's only a certain chance a team will be sent + if(!prob(send_team_chance)) + command_announcement.Announce("It would appear that an emergency response team was requested for [station_name()]. Unfortunately, we were unable to send one at this time.", "[GLOB.using_map.boss_name]") + can_call_ert = 0 // Only one call per round, ladies. + return + + command_announcement.Announce("It would appear that an emergency response team was requested for [station_name()]. We will prepare and send one as soon as possible.", "[GLOB.using_map.boss_name]") + evacuation_controller.add_can_call_predicate(new/datum/evacuation_predicate/ert()) + + can_call_ert = 0 // Only one call per round, gentleman. + send_emergency_team = 1 + + sleep(600 * 5) + send_emergency_team = 0 // Can no longer join the ERT. + +/datum/evacuation_predicate/ert + var/prevent_until + +/datum/evacuation_predicate/ert/New() + ..() + prevent_until = world.time + 30 MINUTES + +/datum/evacuation_predicate/ert/is_valid() + return world.time < prevent_until + +/datum/evacuation_predicate/ert/can_call(var/user) + if(world.time >= prevent_until) + return TRUE + to_chat(user, "An emergency response team has been dispatched. Evacuation requests will be denied until [duration2stationtime(prevent_until - world.time)].") + return FALSE diff --git a/code/game/shuttle_engines.dm b/code/game/shuttle_engines.dm new file mode 100644 index 00000000..00f33adf --- /dev/null +++ b/code/game/shuttle_engines.dm @@ -0,0 +1,48 @@ +/obj/structure/shuttle + name = "shuttle" + icon = 'icons/turf/shuttle.dmi' + +/obj/structure/shuttle/window + name = "shuttle window" + icon = 'icons/obj/podwindows.dmi' + icon_state = "1" + density = 1 + opacity = 0 + anchored = 1 + + CanPass(atom/movable/mover, turf/target, height, air_group) + if(!height || air_group) return 0 + else return ..() + +/obj/structure/shuttle/engine + name = "engine" + density = 1 + anchored = 1.0 + +/obj/structure/shuttle/engine/heater + name = "heater" + icon_state = "heater" + +/obj/structure/shuttle/engine/platform + name = "platform" + icon_state = "platform" + +/obj/structure/shuttle/engine/propulsion + name = "propulsion" + icon_state = "propulsion" + opacity = 1 + +/obj/structure/shuttle/engine/propulsion/burst + name = "burst" + +/obj/structure/shuttle/engine/propulsion/burst/left + name = "left" + icon_state = "burst_l" + +/obj/structure/shuttle/engine/propulsion/burst/right + name = "right" + icon_state = "burst_r" + +/obj/structure/shuttle/engine/router + name = "router" + icon_state = "router" diff --git a/code/game/sound.dm b/code/game/sound.dm new file mode 100644 index 00000000..4d4ea9ff --- /dev/null +++ b/code/game/sound.dm @@ -0,0 +1,284 @@ +//Defines for echo list index positions. +//ECHO_DIRECT and ECHO_ROOM are the only two that actually appear to do anything, and represent the dry and wet channels of the environment effects, respectively. +//The rest of the defines are there primarily for the sake of completeness. It might be worth testing on EAX-enabled hardware, and on future BYOND versions (I've tested with 511, 512, and 513) +#define ECHO_DIRECT 1 +#define ECHO_DIRECTHF 2 +#define ECHO_ROOM 3 +#define ECHO_ROOMHF 4 +#define ECHO_OBSTRUCTION 5 +#define ECHO_OBSTRUCTIONLFRATIO 6 +#define ECHO_OCCLUSION 7 +#define ECHO_OCCLUSIONLFRATIO 8 +#define ECHO_OCCLUSIONROOMRATIO 9 +#define ECHO_OCCLUSIONDIRECTRATIO 10 +#define ECHO_EXCLUSION 11 +#define ECHO_EXCLUSIONLFRATIO 12 +#define ECHO_OUTSIDEVOLUMEHF 13 +#define ECHO_DOPPLERFACTOR 14 +#define ECHO_ROLLOFFFACTOR 15 +#define ECHO_ROOMROLLOFFFACTOR 16 +#define ECHO_AIRABSORPTIONFACTOR 17 +#define ECHO_FLAGS 18 + +//Defines for controlling how zsound sounds. +#define ZSOUND_DRYLOSS_PER_Z -2000 //Affects what happens to the dry channel as the sound travels through z-levels +#define ZSOUND_DISTANCE_PER_Z 2 //Affects the distance added to the sound per z-level travelled + +//Sound environment defines. Reverb preset for sounds played in an area, see sound datum reference for more. +#define GENERIC 0 +#define PADDED_CELL 1 +#define ROOM 2 +#define BATHROOM 3 +#define LIVINGROOM 4 +#define STONEROOM 5 +#define AUDITORIUM 6 +#define CONCERT_HALL 7 +#define CAVE 8 +#define ARENA 9 +#define HANGAR 10 +#define CARPETED_HALLWAY 11 +#define HALLWAY 12 +#define STONE_CORRIDOR 13 +#define ALLEY 14 +#define FOREST 15 +#define CITY 16 +#define MOUNTAINS 17 +#define QUARRY 18 +#define PLAIN 19 +#define PARKING_LOT 20 +#define SEWER_PIPE 21 +#define UNDERWATER 22 +#define DRUGGED 23 +#define DIZZY 24 +#define PSYCHOTIC 25 + +#define STANDARD_STATION STONEROOM +#define LARGE_ENCLOSED HANGAR +#define SMALL_ENCLOSED BATHROOM +#define TUNNEL_ENCLOSED CAVE +#define LARGE_SOFTFLOOR CARPETED_HALLWAY +#define MEDIUM_SOFTFLOOR LIVINGROOM +#define SMALL_SOFTFLOOR ROOM +#define ASTEROID CAVE +#define SPACE UNDERWATER + +GLOBAL_LIST_INIT(shatter_sound,list('sound/effects/Glassbr1.ogg','sound/effects/Glassbr2.ogg','sound/effects/Glassbr3.ogg')) +GLOBAL_LIST_INIT(explosion_sound,list('sound/effects/explosion1.ogg','sound/effects/explosion2.ogg')) +GLOBAL_LIST_INIT(spark_sound,list('sound/effects/sparks1.ogg','sound/effects/sparks2.ogg','sound/effects/sparks3.ogg','sound/effects/sparks4.ogg')) +GLOBAL_LIST_INIT(rustle_sound,list('sound/effects/rustle1.ogg','sound/effects/rustle2.ogg','sound/effects/rustle3.ogg','sound/effects/rustle4.ogg','sound/effects/rustle5.ogg')) +GLOBAL_LIST_INIT(punch_sound,list('sound/weapons/punch_01.ogg','sound/weapons/punch_02.ogg','sound/weapons/punch_03.ogg','sound/weapons/punch_04.ogg','sound/weapons/punch_05.ogg','sound/weapons/punch_06.ogg','sound/weapons/punch_07.ogg','sound/weapons/punch_08.ogg','sound/weapons/punch_09.ogg','sound/weapons/punch_10.ogg')) +GLOBAL_LIST_INIT(clown_sound,list('sound/effects/clownstep1.ogg','sound/effects/clownstep2.ogg')) +GLOBAL_LIST_INIT(swing_hit_sound,list('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg')) +GLOBAL_LIST_INIT(hiss_sound,list('sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg')) +GLOBAL_LIST_INIT(page_sound,list('sound/effects/pageturn1.ogg', 'sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg')) +GLOBAL_LIST_INIT(fracture_sound,list('sound/effects/bonebreak1.ogg','sound/effects/bonebreak2.ogg','sound/effects/bonebreak3.ogg','sound/effects/bonebreak4.ogg')) +GLOBAL_LIST_INIT(lighter_sound,list('sound/items/lighter1.ogg','sound/items/lighter2.ogg')) +GLOBAL_LIST_INIT(keypress_sound,list('sound/machines/keyboard/keypress1.ogg','sound/machines/keyboard/keypress2.ogg','sound/machines/keyboard/keypress3.ogg','sound/machines/keyboard/keypress4.ogg')) +GLOBAL_LIST_INIT(keystroke_sound,list('sound/machines/keyboard/keystroke1.ogg','sound/machines/keyboard/keystroke2.ogg','sound/machines/keyboard/keystroke3.ogg','sound/machines/keyboard/keystroke4.ogg')) +GLOBAL_LIST_INIT(switch_sound,list('sound/machines/switch1.ogg','sound/machines/switch2.ogg','sound/machines/switch3.ogg','sound/machines/switch4.ogg')) +GLOBAL_LIST_INIT(button_sound,list('sound/machines/button1.ogg','sound/machines/button2.ogg','sound/machines/button3.ogg','sound/machines/button4.ogg')) +GLOBAL_LIST_INIT(flop_sound, list('sound/effects/bodyfall1.ogg','sound/effects/bodyfall2.ogg','sound/effects/bodyfall3.ogg','sound/effects/bodyfall4.ogg')) +GLOBAL_LIST_INIT(trauma_sound, list('sound/effects/gore/trauma1.ogg', 'sound/effects/gore/trauma2.ogg', 'sound/effects/gore/trauma3.ogg')) +GLOBAL_LIST_INIT(casing_sound, list('sound/weapons/guns/misc/casingfall1.ogg','sound/weapons/guns/misc/casingfall2.ogg','sound/weapons/guns/misc/casingfall3.ogg')) +GLOBAL_LIST_INIT(terminal_type, list('sound/machines/keypress1.ogg', 'sound/machines/keypress2.ogg', 'sound/machines/keypress3.ogg', 'sound/machines/keypress4.ogg')) +GLOBAL_LIST_INIT(keyboard_sound, list('sound/machines/terminal_button01.ogg', 'sound/machines/terminal_button02.ogg', 'sound/machines/terminal_button03.ogg', + 'sound/machines/terminal_button04.ogg', 'sound/machines/terminal_button05.ogg', 'sound/machines/terminal_button06.ogg', + 'sound/machines/terminal_button07.ogg', 'sound/machines/terminal_button08.ogg')) +GLOBAL_LIST_INIT(keyboard_sound_long, list('sound/effects/keyboard/keyboard1.ogg', 'sound/effects/keyboard/keyboard2.ogg', 'sound/effects/keyboard/keyboard3.ogg', 'sound/effects/keyboard/keyboard4.ogg')) +GLOBAL_LIST_INIT(gun_sound, list('sound/weapons/guns/fire/pistol1.ogg', 'sound/weapons/guns/fire/pistol2.ogg', 'sound/weapons/guns/fire/pistol3.ogg', 'sound/weapons/guns/fire/pistol4.ogg', 'sound/weapons/guns/fire/pistol5.ogg')) +GLOBAL_LIST_INIT(brifle, list('sound/weapons/newrifle.ogg', 'sound/weapons/newrifle2.ogg', 'sound/weapons/newrifle3.ogg')) +GLOBAL_LIST_INIT(bullet_hit_wall, list('sound/weapons/guns/misc/ric1.ogg', 'sound/weapons/guns/misc/ric2.ogg', 'sound/weapons/guns/misc/ric3.ogg', 'sound/weapons/guns/misc/ric4.ogg', 'sound/weapons/guns/misc/ric5.ogg')) +GLOBAL_LIST_INIT(shotgun_insert, list('sound/weapons/guns/interact/shell_insert1.ogg','sound/weapons/guns/interact/shell_insert2.ogg')) +GLOBAL_LIST_INIT(stab_sound, list('sound/weapons/stab1.ogg', 'sound/weapons/stab2.ogg', 'sound/weapons/stab3.ogg')) +GLOBAL_LIST_INIT(slash_sound, list('sound/weapons/slash1.ogg','sound/weapons/slash2.ogg','sound/weapons/slash3.ogg')) +GLOBAL_LIST_INIT(blunt_swing, list('sound/weapons/blunt_swing1.ogg','sound/weapons/blunt_swing2.ogg','sound/weapons/blunt_swing3.ogg')) +GLOBAL_LIST_INIT(swing_sound, list('sound/weapons/swing_01.ogg', 'sound/weapons/swing_02.ogg', 'sound/weapons/swing_03.ogg')) +GLOBAL_LIST_INIT(shovel_swing, list('sound/weapons/shovel_swing1.ogg', 'sound/weapons/shovel_swing2.ogg')) +GLOBAL_LIST_INIT(shovel_hit, list('sound/weapons/shovel_hit1.ogg', 'sound/weapons/shovel_hit2.ogg', 'sound/weapons/shovel_hit3.ogg')) +GLOBAL_LIST_INIT(chop_sound, list('sound/weapons/chop1.ogg','sound/weapons/chop2.ogg','sound/weapons/chop3.ogg')) +GLOBAL_LIST_INIT(armor_walk_sound, list('sound/effects/footsteps/armor/gear1.ogg','sound/effects/footsteps/armor/gear2.ogg','sound/effects/footsteps/armor/gear3.ogg','sound/effects/footsteps/armor/gear4.ogg')) +GLOBAL_LIST_INIT(blood_drip, list('sound/effects/gore/blood1.ogg', 'sound/effects/gore/blood2.ogg', 'sound/effects/gore/blood3.ogg', 'sound/effects/gore/blood3.ogg', 'sound/effects/gore/blood4.ogg', 'sound/effects/gore/blood5.ogg', 'sound/effects/gore/blood6.ogg')) +GLOBAL_LIST_INIT(head_break_sound, list('sound/effects/gore/blast1.ogg', 'sound/effects/gore/blast3.ogg', 'sound/effects/gore/blast4.ogg')) +GLOBAL_LIST_INIT(foliage, list('sound/effects/foliage_01.ogg','sound/effects/foliage_02.ogg', 'sound/effects/foliage_03.ogg', 'sound/effects/foliage_04.ogg', 'sound/effects/foliage_05.ogg')) +GLOBAL_LIST_INIT(foliagedry, list('sound/effects/foliage_forest_01.ogg','sound/effects/foliage_forest_02.ogg', 'sound/effects/foliage_forest_03.ogg', 'sound/effects/foliage_forest_04.ogg', 'sound/effects/foliage_forest_05.ogg')) +GLOBAL_LIST_INIT(gun_pickup, list('sound/items/handle/gunpickup1.ogg', 'sound/items/handle/gunpickup2.ogg', 'sound/items/handle/gunpickup3.ogg')) +GLOBAL_LIST_INIT(far_fire_sound,list('sound/effects/weapons/gun/far_fire1.ogg','sound/effects/weapons/gun/far_fire2.ogg','sound/effects/weapons/gun/far_fire3.ogg')) +GLOBAL_LIST_INIT(far_sniper,list('sound/effects/weapons/gun/rifle_farfire1.ogg','sound/effects/weapons/gun/rifle_farfire2.ogg','sound/effects/weapons/gun/rifle_farfire3.ogg', 'sound/effects/weapons/gun/rifle_farfire4.ogg')) +GLOBAL_LIST_INIT(far_rifle,list('sound/effects/weapons/gun/semi_farfire1.ogg','sound/effects/weapons/gun/semi_farfire2.ogg','sound/effects/weapons/gun/semi_farfire3.ogg', 'sound/effects/weapons/gun/semi_farfire4.ogg')) +GLOBAL_LIST_INIT(eat_food, list('sound/effects/eating/eat1.ogg', 'sound/effects/eating/eat2.ogg', 'sound/effects/eating/eat3.ogg', 'sound/effects/eating/eat4.ogg', 'sound/effects/eating/eat5.ogg')) +GLOBAL_LIST_INIT(drink_sound, list('sound/effects/eating/drink1.ogg','sound/effects/eating/drink2.ogg','sound/effects/eating/drink3.ogg','sound/effects/eating/drink4.ogg','sound/effects/eating/drink5.ogg')) + + + +/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, is_global, frequency, is_ambiance = 0, ignore_walls = TRUE, zrange = 2, override_env, envdry, envwet) + if(isarea(source)) + error("[source] is an area and is trying to make the sound: [soundin]") + return + + soundin = get_sfx(soundin) // same sound for everyone + frequency = vary && isnull(frequency) ? get_rand_frequency() : frequency // Same frequency for everybody + + var/turf/turf_source = get_turf(source) + var/maxdistance = (world.view + extrarange) * 2 + + // Looping through the player list has the added bonus of working for mobs inside containers + var/list/listeners = GLOB.player_list + if(!ignore_walls) //these sounds don't carry through walls + listeners = listeners & hearers(maxdistance, turf_source) + + for(var/P in listeners) + var/mob/M = P + if(!M || !M.client) + continue + + if(get_dist(M, turf_source) <= maxdistance) + var/turf/T = get_turf(M) + + if(T && (T.z == turf_source.z || (zrange && AreConnectedZLevels(T.z, turf_source.z) && abs(T.z - turf_source.z) <= zrange)) && (!is_ambiance || M.get_preference_value(/datum/client_preference/play_ambiance) == GLOB.PREF_YES)) + M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, is_global, extrarange, override_env, envdry, envwet) + +var/const/FALLOFF_SOUNDS = 0.5 + +/mob/proc/playsound_local(var/turf/turf_source, soundin, vol as num, vary, frequency, falloff, is_global, extrarange, override_env, envdry, envwet) + if(!src.client || ear_deaf > 0) + return + + var/sound/S = soundin + if(!istype(S)) + soundin = get_sfx(soundin) + S = sound(soundin) + S.wait = 0 //No queue + S.channel = 0 //Any channel + S.volume = vol + S.environment = -1 + if(frequency) + S.frequency = frequency + else if (vary) + S.frequency = get_rand_frequency() + + //sound volume falloff with pressure + var/pressure_factor = 1.0 + + var/turf/T = get_turf(src) + // 3D sounds, the technology is here! + if(isturf(turf_source)) + //sound volume falloff with distance + var/distance = get_dist(T, turf_source) + + S.volume -= max(distance - (world.view + extrarange), 0) * 2 //multiplicative falloff to add on top of natural audio falloff. + + var/datum/gas_mixture/hearer_env = T.return_air() + var/datum/gas_mixture/source_env = turf_source.return_air() + + if (hearer_env && source_env) + var/pressure = min(hearer_env.return_pressure(), source_env.return_pressure()) + + if (pressure < ONE_ATMOSPHERE) + pressure_factor = max((pressure - SOUND_MINIMUM_PRESSURE)/(ONE_ATMOSPHERE - SOUND_MINIMUM_PRESSURE), 0) + else //in space + pressure_factor = 0 + + if (distance <= 1) + pressure_factor = max(pressure_factor, 0.15) //hearing through contact + + S.volume *= pressure_factor + + if (S.volume <= 0) + return //no volume means no sound + + var/dx = turf_source.x - T.x // Hearing from the right/left + S.x = dx + var/dz = turf_source.y - T.y // Hearing from infront/behind + S.z = dz + var/dy = (turf_source.z - T.z) * ZSOUND_DISTANCE_PER_Z // Hearing from above/below. There is ceiling in 2d spessmans. + S.y = (dy < 0) ? dy - 1 : dy + 1 //We want to make sure there's *always* at least one extra unit of distance. This helps normalize sound that's emitting from the turf you're on. + S.falloff = (falloff ? falloff : FALLOFF_SOUNDS) + + if(!override_env) + envdry = abs(turf_source.z - T.z) * ZSOUND_DRYLOSS_PER_Z + + if(!is_global) + + if(istype(src,/mob/living/)) + var/mob/living/carbon/M = src + if (istype(M) && M.hallucination_power > 50 && M.chem_effects[CE_MIND] < 1) + S.environment = PSYCHOTIC + else if (M.druggy) + S.environment = DRUGGED + else if (M.drowsyness) + S.environment = DIZZY + else if (M.confused) + S.environment = DIZZY + else if (M.stat == UNCONSCIOUS) + S.environment = UNDERWATER + else if (pressure_factor < 0.5) + S.environment = SPACE + else + var/area/A = get_area(src) + S.environment = A.sound_env + + else if (pressure_factor < 0.5) + S.environment = SPACE + else + var/area/A = get_area(src) + S.environment = A.sound_env + + var/list/echo_list = new(18) + echo_list[ECHO_DIRECT] = envdry + echo_list[ECHO_ROOM] = envwet + S.echo = echo_list + + sound_to(src, S) + +/client/proc/playtitlemusic() + if(get_preference_value(/datum/client_preference/play_lobby_music) == GLOB.PREF_YES) + GLOB.using_map.lobby_music.play_to(src) + +/proc/get_rand_frequency() + return rand(32000, 55000) //Frequency stuff only works with 45kbps oggs. + +/proc/get_sfx(soundin) + if(istext(soundin)) + switch(soundin) + if ("shatter") soundin = pick(GLOB.shatter_sound) + if ("explosion") soundin = pick(GLOB.explosion_sound) + if ("sparks") soundin = pick(GLOB.spark_sound) + if ("rustle") soundin = pick(GLOB.rustle_sound) + if ("punch") soundin = pick(GLOB.punch_sound) + if ("clownstep") soundin = pick(GLOB.clown_sound) + if ("swing_hit") soundin = pick(GLOB.swing_hit_sound) + if ("hiss") soundin = pick(GLOB.hiss_sound) + if ("pageturn") soundin = pick(GLOB.page_sound) + if ("fracture") soundin = pick(GLOB.fracture_sound) + if ("light_bic") soundin = pick(GLOB.lighter_sound) + if ("keyboard") soundin = pick(GLOB.keyboard_sound) + if ("keystroke") soundin = pick(GLOB.keystroke_sound) + if ("switch") soundin = pick(GLOB.switch_sound) + if ("button") soundin = pick(GLOB.button_sound) + if ("trauma") soundin = pick(GLOB.trauma_sound) + if ("headsmash") soundin = pick(GLOB.head_break_sound) + if ("stab_sound") soundin = pick(GLOB.stab_sound) + if ("casing_sound") soundin = pick(GLOB.casing_sound) + if ("keypress") soundin = pick(GLOB.keypress_sound) + if ("gunshot") soundin = pick(GLOB.gun_sound) + if ("brifle") soundin = pick(GLOB.brifle) + if ("hitwall") soundin = pick(GLOB.bullet_hit_wall) + if ("slash_sound") soundin = pick(GLOB.slash_sound) + if ("swing_sound") soundin = pick(GLOB.swing_sound) + if ("blunt_swing") soundin = pick(GLOB.blunt_swing) + if ("shovel_swing") soundin = pick(GLOB.shovel_swing) + if ("shovel_hit") soundin = pick(GLOB.shovel_hit) + if ("chop") soundin = pick(GLOB.chop_sound) + if ("pratfall") soundin = pick(GLOB.flop_sound) + if ("armorwalk") soundin = pick(GLOB.armor_walk_sound) + if ("blood_drip") soundin = pick(GLOB.blood_drip) + if ("shotgun_insert") soundin = pick(GLOB.shotgun_insert) + if ("foliage") soundin = pick(GLOB.foliage) + if ("foliagedry") soundin = pick(GLOB.foliagedry) + if ("gun_pickup") soundin = pick(GLOB.gun_pickup) + if ("far_fire") soundin = pick(GLOB.far_fire_sound) + if ("sniper_fire") soundin = pick(GLOB.far_sniper) + if ("rifle_fire") soundin = pick(GLOB.far_rifle) + if ("eat") soundin = pick(GLOB.eat_food) + if ("drink") soundin = pick(GLOB.drink_sound) + return soundin diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm new file mode 100644 index 00000000..479c9323 --- /dev/null +++ b/code/game/supplyshuttle.dm @@ -0,0 +1,279 @@ +//Config stuff +#define SUPPLY_DOCKZ 2 //Z-level of the Dock. +#define SUPPLY_STATIONZ 1 //Z-level of the Station. + +//Supply packs are in /code/defines/obj/supplypacks.dm +//Computers are in /code/game/machinery/computer/supply.dm + +var/datum/controller/supply/supply_controller = new() + +var/list/mechtoys = list( + /obj/item/toy/prize/ripley, + /obj/item/toy/prize/fireripley, + /obj/item/toy/prize/deathripley, + /obj/item/toy/prize/gygax, + /obj/item/toy/prize/durand, + /obj/item/toy/prize/honk, + /obj/item/toy/prize/marauder, + /obj/item/toy/prize/seraph, + /obj/item/toy/prize/mauler, + /obj/item/toy/prize/odysseus, + /obj/item/toy/prize/phazon +) + +/obj/item/weapon/paper/manifest + name = "supply manifest" + var/is_copy = 1 + +/obj/structure/plasticflaps //HOW DO YOU CALL THOSE THINGS ANYWAY + name = "\improper plastic flaps" + desc = "Completely impassable - or are they?" + icon = 'icons/obj/stationobjs.dmi' //Change this. + icon_state = "plasticflaps" + density = 0 + anchored = 1 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + explosion_resistance = 5 + var/list/mobs_can_pass = list( + /mob/living/bot, + /mob/living/carbon/slime, + /mob/living/simple_animal/mouse, + /mob/living/silicon/robot/drone + ) + +/obj/structure/plasticflaps/CanPass(atom/A, turf/T) + if(istype(A) && A.checkpass(PASS_FLAG_GLASS)) + return prob(60) + + var/obj/structure/bed/B = A + if (istype(A, /obj/structure/bed) && B.buckled_mob)//if it's a bed/chair and someone is buckled, it will not pass + return 0 + + if(istype(A, /obj/vehicle)) //no vehicles + return 0 + + var/mob/living/M = A + if(istype(M)) + if(M.lying) + return ..() + for(var/mob_type in mobs_can_pass) + if(istype(A, mob_type)) + return ..() + return issmall(M) + + return ..() + +/obj/structure/plasticflaps/ex_act(severity) + switch(severity) + if (1) + qdel(src) + if (2) + if (prob(50)) + qdel(src) + if (3) + if (prob(5)) + qdel(src) + +/obj/structure/plasticflaps/mining //A specific type for mining that doesn't allow airflow because of them damn crates + name = "airtight plastic flaps" + desc = "Heavy duty, airtight, plastic flaps." + + New() //set the turf below the flaps to block air + var/turf/T = get_turf(loc) + if(T) + T.blocks_air = 1 + ..() + + Destroy() //lazy hack to set the turf to allow air to pass if it's a simulated floor + var/turf/T = get_turf(loc) + if(T) + if(istype(T, /turf/simulated/floor)) + T.blocks_air = 0 + ..() + +/* +/obj/effect/marker/supplymarker + icon_state = "X" + icon = 'icons/misc/mark.dmi' + name = "X" + invisibility = 101 + anchored = 1 + opacity = 0 +*/ + +/datum/supply_order + var/ordernum + var/decl/hierarchy/supply_pack/object = null + var/orderedby = null + var/comment = null + var/reason = null + var/orderedrank = null //used for supply console printing + +var/list/point_source_descriptions = list( + "time" = "Base station supply", + "manifest" = "From exported manifests", + "crate" = "From exported crates", + "phoron" = "From exported phoron", + "platinum" = "From exported platinum", + "virology" = "From uploaded antibody data", + "total" = "Total" // If you're adding additional point sources, add it here in a new line. Don't forget to put a comma after the old last line. + ) + +//Adds the points from different sources together and saves them for the export overview +/datum/controller/supply/proc/add_points_from_source(amount, source) + points += amount + point_sources[source] += amount + point_sources["total"] += amount + +/datum/controller/supply + //supply points + var/points = 50 + var/points_per_process = 1.5 + var/points_per_slip = 2 + var/points_per_platinum = 5 // 5 points per sheet + var/points_per_phoron = 5 + var/point_sources = list() + var/pointstotalsum = 0 + var/pointstotal = 0 + //control + var/ordernum + var/list/shoppinglist = list() + var/list/requestlist = list() + var/list/donelist = list() + var/list/master_supply_list = list() + //shuttle movement + var/movetime = 1200 + var/datum/shuttle/autodock/ferry/supply/shuttle + + New() + ordernum = rand(1,9000) + + //Build master supply list + for(var/decl/hierarchy/supply_pack/sp in cargo_supply_pack_root.children) + if(sp.is_category()) + for(var/decl/hierarchy/supply_pack/spc in sp.children) + master_supply_list += spc + + + // Supply shuttle ticker - handles supply point regeneration + // This is called by the process scheduler every thirty seconds + proc/process() + add_points_from_source(points_per_process, "time") + + //To stop things being sent to centcomm which should not be sent to centcomm. Recursively checks for these types. + proc/forbidden_atoms_check(atom/A) + if(istype(A,/mob/living)) + return 1 + if(istype(A,/obj/item/weapon/disk/nuclear)) + return 1 + if(istype(A,/obj/machinery/nuclearbomb)) + return 1 + if(istype(A,/obj/item/device/radio/beacon)) + return 1 + + for(var/i=1, i<=A.contents.len, i++) + var/atom/B = A.contents[i] + if(.(B)) + return 1 + + //Sellin + proc/sell() + var/phoron_count = 0 + var/plat_count = 0 + for(var/area/subarea in shuttle.shuttle_area) + for(var/atom/movable/MA in subarea) + if(MA.anchored) continue + + // Must be in a crate! + if(istype(MA,/obj/structure/closet/crate)) + var/obj/structure/closet/crate/CR = MA + callHook("sell_crate", list(CR, subarea)) + + add_points_from_source(CR.points_per_crate, "crate") + var/find_slip = 1 + + for(var/atom in CR) + // Sell manifests + var/atom/A = atom + if(find_slip && istype(A,/obj/item/weapon/paper/manifest)) + var/obj/item/weapon/paper/manifest/slip = A + if(!slip.is_copy && slip.stamped && slip.stamped.len) //yes, the clown stamp will work. clown is the highest authority on the station, it makes sense + add_points_from_source(points_per_slip, "manifest") + find_slip = 0 + continue + + // Sell phoron and platinum + if(istype(A, /obj/item/stack)) + var/obj/item/stack/P = A + switch(P.get_material_name()) + if("phoron") phoron_count += P.get_amount() + if("platinum") plat_count += P.get_amount() + qdel(MA) + + if(phoron_count) + var/temp = phoron_count * points_per_phoron + add_points_from_source(temp, "phoron") + + if(plat_count) + var/temp = plat_count * points_per_platinum + add_points_from_source(temp, "platinum") + + //Buyin + proc/buy() + if(!shoppinglist.len) return + var/list/clear_turfs = list() + for(var/area/subarea in shuttle.shuttle_area) + for(var/turf/T in subarea) + if(T.density) continue + var/contcount + for(var/atom/A in T.contents) + if(!A.simulated || istype(A, /obj/machinery/conveyor)) + continue + contcount++ + if(contcount) + continue + clear_turfs += T + for(var/S in shoppinglist) + if(!clear_turfs.len) break + var/i = rand(1,clear_turfs.len) + var/turf/pickedloc = clear_turfs[i] + clear_turfs.Cut(i,i+1) + shoppinglist -= S + donelist += S + + var/datum/supply_order/SO = S + var/decl/hierarchy/supply_pack/SP = SO.object + + var/obj/A = new SP.containertype(pickedloc) + A.SetName("[SP.containername][SO.comment ? " ([SO.comment])":"" ]") + //supply manifest generation begin + + var/obj/item/weapon/paper/manifest/slip + if(!SP.contraband) + slip = new /obj/item/weapon/paper/manifest(A) + slip.is_copy = 0 + slip.info = "

            [command_name()] Shipping Manifest



            " + slip.info +="Order #[SO.ordernum]
            " + slip.info +="Destination: [GLOB.using_map.station_name]
            " + slip.info +="[shoppinglist.len] PACKAGES IN THIS SHIPMENT
            " + slip.info +="CONTENTS:
              " + + //spawn the stuff, finish generating the manifest while you're at it + if(SP.access) + if(isnum(SP.access)) + A.req_access = list(SP.access) + else if(islist(SP.access)) + var/list/L = SP.access // access var is a plain var, we need a list + A.req_access = L.Copy() + else + log_debug("Supply pack with invalid access restriction [SP.access] encountered!") + + var/list/spawned = SP.spawn_contents(A) + if(slip) + for(var/atom/content in spawned) + slip.info += "
            • [content.name]
            • " //add the item to the manifest + slip.info += "

            " + slip.info += "CHECK CONTENTS AND STAMP BELOW THE LINE TO CONFIRM RECEIPT OF GOODS
            " + + return diff --git a/code/game/turfs/flooring/flooring.dm b/code/game/turfs/flooring/flooring.dm new file mode 100644 index 00000000..6dc7ea66 --- /dev/null +++ b/code/game/turfs/flooring/flooring.dm @@ -0,0 +1,257 @@ +var/list/flooring_types + +/proc/get_flooring_data(var/flooring_path) + if(!flooring_types) + flooring_types = list() + if(!flooring_types["[flooring_path]"]) + flooring_types["[flooring_path]"] = new flooring_path + return flooring_types["[flooring_path]"] + +// State values: +// [icon_base]: initial base icon_state without edges or corners. +// if has_base_range is set, append 0-has_base_range ie. +// [icon_base][has_base_range] +// [icon_base]_broken: damaged overlay. +// if has_damage_range is set, append 0-damage_range for state ie. +// [icon_base]_broken[has_damage_range] +// [icon_base]_edges: directional overlays for edges. +// [icon_base]_corners: directional overlays for non-edge corners. + +/decl/flooring + var/name + var/desc + var/icon + var/icon_base + var/color + + var/has_base_range + var/has_damage_range + var/has_burn_range + var/damage_temperature + var/apply_thermal_conductivity + var/apply_heat_capacity + + var/build_type // Unbuildable if not set. Must be /obj/item/stack. + var/build_cost = 1 // Stack units. + var/build_time = 0 // BYOND ticks. + + var/descriptor = "tiles" + var/flags + var/can_paint + +/decl/flooring/proc/on_remove() + return + +/decl/flooring/grass + name = "grass" + desc = "Do they smoke grass out in space, Bowie? Or do they smoke AstroTurf?" + icon = 'icons/turf/flooring/grass.dmi' + icon_base = "grass" + has_base_range = 3 + damage_temperature = T0C+80 + flags = TURF_HAS_EDGES | TURF_REMOVE_SHOVEL + build_type = /obj/item/stack/tile/grass + +/decl/flooring/asteroid + name = "coarse sand" + desc = "Gritty and unpleasant." + icon = 'icons/turf/flooring/asteroid.dmi' + icon_base = "asteroid" + flags = TURF_HAS_EDGES | TURF_REMOVE_SHOVEL + build_type = null + +/decl/flooring/carpet + name = "brown carpet" + desc = "Comfy and fancy carpeting." + icon = 'icons/turf/flooring/carpet.dmi' + icon_base = "brown" + build_type = /obj/item/stack/tile/carpet + damage_temperature = T0C+200 + flags = TURF_HAS_EDGES | TURF_HAS_CORNERS | TURF_REMOVE_CROWBAR | TURF_CAN_BURN + +/decl/flooring/carpet/blue + name = "blue carpet" + icon_base = "blue1" + build_type = /obj/item/stack/tile/carpetblue + +/decl/flooring/carpet/blue2 + name = "pale blue carpet" + icon_base = "blue2" + build_type = /obj/item/stack/tile/carpetblue2 + +/decl/flooring/carpet/purple + name = "purple carpet" + icon_base = "purple" + build_type = /obj/item/stack/tile/carpetpurple + +/decl/flooring/carpet/orange + name = "orange carpet" + icon_base = "orange" + build_type = /obj/item/stack/tile/carpetorange + +/decl/flooring/carpet/green + name = "green carpet" + icon_base = "green" + build_type = /obj/item/stack/tile/carpetgreen + +/decl/flooring/carpet/red + name = "red carpet" + icon_base = "red" + build_type = /obj/item/stack/tile/carpetred + +/decl/flooring/linoleum + name = "linoleum" + desc = "It's like the 2390's all over again." + icon = 'icons/turf/flooring/linoleum.dmi' + icon_base = "lino" + can_paint = 1 + build_type = /obj/item/stack/tile/linoleum + flags = TURF_REMOVE_SCREWDRIVER + +/decl/flooring/tiling + name = "floor" + desc = "Scuffed from the passage of countless greyshirts." + icon = 'icons/turf/flooring/tiles.dmi' + icon_base = "steel" + color = null + has_damage_range = 4 + damage_temperature = T0C+1400 + flags = TURF_REMOVE_CROWBAR | TURF_CAN_BREAK | TURF_CAN_BURN + build_type = /obj/item/stack/tile/floor + can_paint = 1 + +/decl/flooring/tiling/mono + icon_base = "monotile" + +/decl/flooring/tiling/white + desc = "How sterile." + icon_base = "white" + color = null + build_type = /obj/item/stack/tile/floor_white + +/decl/flooring/tiling/white/mono + icon_base = "monotile" + +/decl/flooring/tiling/dark + desc = "How ominous." + icon_base = "dark" + color = null + build_type = /obj/item/stack/tile/floor_dark + +/decl/flooring/tiling/dark/mono + icon_base = "monotile" + +/decl/flooring/tiling/freezer + desc = "Don't slip." + icon_base = "freezer" + color = null + has_damage_range = null + flags = TURF_REMOVE_CROWBAR + build_type = /obj/item/stack/tile/floor_freezer + +/decl/flooring/wood + name = "wooden floor" + desc = "Polished redwood planks." + icon = 'icons/turf/flooring/wood.dmi' + icon_base = "wood" + has_damage_range = 6 + damage_temperature = T0C+200 + descriptor = "planks" + build_type = /obj/item/stack/tile/wood + flags = TURF_CAN_BREAK | TURF_IS_FRAGILE | TURF_REMOVE_SCREWDRIVER + +/decl/flooring/reinforced + name = "reinforced floor" + desc = "Heavily reinforced with steel plating." + icon = 'icons/turf/flooring/tiles.dmi' + icon_base = "reinforced" + flags = TURF_REMOVE_WRENCH | TURF_ACID_IMMUNE + build_type = /obj/item/stack/material/steel + build_cost = 1 + build_time = 30 + apply_thermal_conductivity = 0.025 + apply_heat_capacity = 325000 + can_paint = 1 + +/decl/flooring/reinforced/circuit + name = "processing strata" + icon = 'icons/turf/flooring/circuit.dmi' + icon_base = "bcircuit" + build_type = null + flags = TURF_ACID_IMMUNE | TURF_CAN_BREAK | TURF_REMOVE_WRENCH + can_paint = 1 + +/decl/flooring/reinforced/circuit/green + icon_base = "gcircuit" + +/decl/flooring/reinforced/circuit/red + icon_base = "rcircuit" + flags = TURF_ACID_IMMUNE + can_paint = 0 + +/decl/flooring/reinforced/cult + name = "engraved floor" + desc = "Unsettling whispers waver from the surface..." + icon = 'icons/turf/flooring/cult.dmi' + icon_base = "cult" + build_type = null + has_damage_range = 6 + flags = TURF_ACID_IMMUNE | TURF_CAN_BREAK | TURF_REMOVE_WRENCH + can_paint = null + +/decl/flooring/reinforced/cult/on_remove() + cult.remove_cultiness(CULTINESS_PER_TURF) + +/decl/flooring/reinforced/shuttle + name = "floor" + icon = 'icons/turf/shuttle.dmi' + build_type = null + flags = TURF_ACID_IMMUNE | TURF_CAN_BREAK | TURF_REMOVE_WRENCH + can_paint = 1 + +/decl/flooring/reinforced/shuttle/blue + icon_base = "floor" + +/decl/flooring/reinforced/shuttle/yellow + icon_base = "floor2" + +/decl/flooring/reinforced/shuttle/white + icon_base = "floor3" + +/decl/flooring/reinforced/shuttle/red + icon_base = "floor4" + +/decl/flooring/reinforced/shuttle/purple + icon_base = "floor5" + +/decl/flooring/reinforced/shuttle/darkred + icon_base = "floor6" + +/decl/flooring/reinforced/shuttle/black + icon_base = "floor7" + +/decl/flooring/diona + name = "biomass" + desc = "a mass of small intertwined aliens forming a floor... Creepy." + icon = 'icons/turf/floors.dmi' + icon_base = "diona" + flags = TURF_ACID_IMMUNE | TURF_REMOVE_SHOVEL + +/decl/flooring/reinforced/ramp + name = "foot ramp" + desc = "An archaic means of locomotion along the Z axis." + icon = 'icons/turf/flooring/tiles.dmi' + icon_base = "ramptop" + build_type = null + flags = TURF_ACID_IMMUNE | TURF_CAN_BREAK + can_paint = 1 + +/decl/flooring/reinforced/ramp/bottom + icon_base = "rampbot" + +/decl/flooring/diona + name = "biomass" + desc = "a mass of small intertwined aliens forming a floor... Creepy." + icon = 'icons/turf/floors.dmi' + icon_base = "diona" + flags = TURF_ACID_IMMUNE | TURF_REMOVE_SHOVEL \ No newline at end of file diff --git a/code/game/turfs/flooring/flooring_decals.dm b/code/game/turfs/flooring/flooring_decals.dm new file mode 100644 index 00000000..c4530782 --- /dev/null +++ b/code/game/turfs/flooring/flooring_decals.dm @@ -0,0 +1,855 @@ +// These are objects that destroy themselves and add themselves to the +// decal list of the floor under them. Use them rather than distinct icon_states +// when mapping in interesting floor designs. +var/list/floor_decals = list() + +/obj/effect/floor_decal + name = "floor decal" + icon = 'icons/turf/flooring/decals.dmi' + layer = DECAL_LAYER + plane = ABOVE_TURF_PLANE + var/supplied_dir + +/obj/effect/floor_decal/New(var/newloc, var/newdir, var/newcolour) + supplied_dir = newdir + if(newcolour) color = newcolour + layer = BASE_TURF_LAYER + 0.01 + plane = null + ..(newloc) + +/obj/effect/floor_decal/Initialize() + if(supplied_dir) set_dir(supplied_dir) + var/turf/T = get_turf(src) + if(istype(T, /turf/simulated/floor) || istype(T, /turf/unsimulated/floor)) + var/cache_key = "[alpha]-[color]-[dir]-[icon_state]-[layer]" + if(!floor_decals[cache_key]) + var/image/I = image(icon = src.icon, icon_state = src.icon_state, dir = src.dir) + I.color = src.color + I.alpha = src.alpha + floor_decals[cache_key] = I + if(!T.decals) T.decals = list() + T.decals |= floor_decals[cache_key] + T.overlays |= floor_decals[cache_key] + initialized = TRUE + return INITIALIZE_HINT_QDEL + +/obj/effect/floor_decal/reset + name = "reset marker" + +/obj/effect/floor_decal/reset/Initialize() + var/turf/T = get_turf(src) + T.remove_decals() + T.update_icon() + initialized = TRUE + return INITIALIZE_HINT_QDEL + +/obj/effect/floor_decal/carpet + name = "brown carpet" + icon = 'icons/turf/flooring/carpet.dmi' + icon_state = "brown_edges" + +/obj/effect/floor_decal/carpet/blue + name = "blue carpet" + icon_state = "blue1_edges" + +/obj/effect/floor_decal/carpet/blue2 + name = "pale blue carpet" + icon_state = "blue2_edges" + +/obj/effect/floor_decal/carpet/purple + name = "orange carpet" + icon_state = "purple_edges" + +/obj/effect/floor_decal/carpet/orange + name = "orange carpet" + icon_state = "orange_edges" + +/obj/effect/floor_decal/carpet/green + name = "green carpet" + icon_state = "green_edges" + +/obj/effect/floor_decal/carpet/red + name = "red carpet" + icon_state = "red_edges" + +/obj/effect/floor_decal/carpet/corners + name = "brown carpet" + icon_state = "brown_corners" + +/obj/effect/floor_decal/carpet/blue/corners + name = "blue carpet" + icon_state = "blue1_corners" + +/obj/effect/floor_decal/carpet/blue2/corners + name = "pale blue carpet" + icon_state = "blue2_corners" + +/obj/effect/floor_decal/carpet/purple/corners + name = "purple carpet" + icon_state = "purple_corners" + +/obj/effect/floor_decal/carpet/orange/corners + name = "orange carpet" + icon_state = "orange_corners" + +/obj/effect/floor_decal/carpet/green/corners + name = "green carpet" + icon_state = "green_corners" + +/obj/effect/floor_decal/carpet/red/corners + name = "red carpet" + icon_state = "red_corners" + +/obj/effect/floor_decal/corner + icon_state = "corner_white" + alpha = 229 + +/obj/effect/floor_decal/corner/black + name = "black corner" + color = "#333333" + +/obj/effect/floor_decal/corner/black/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/black/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/blue + name = "blue corner" + color = COLOR_BLUE_GRAY + +/obj/effect/floor_decal/corner/blue/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/blue/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/paleblue + name = "pale blue corner" + color = COLOR_PALE_BLUE_GRAY + +/obj/effect/floor_decal/corner/paleblue/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/paleblue/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/cyan + name = "cyan corner" + color = "#469085" + +/obj/effect/floor_decal/corner/cyan/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/cyan/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/green + name = "green corner" + color = COLOR_GREEN_GRAY + +/obj/effect/floor_decal/corner/green/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/green/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/dgreen + name = "dgreen corner" + color = "#6e8766" + +/obj/effect/floor_decal/corner/dgreen/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/dgreen/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/lime + name = "lime corner" + color = COLOR_PALE_GREEN_GRAY + +/obj/effect/floor_decal/corner/lime/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/lime/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/yellow + name = "yellow corner" + color = COLOR_BROWN + +/obj/effect/floor_decal/corner/yellow/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/yellow/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/yellow/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/beige + name = "beige corner" + color = COLOR_BEIGE + +/obj/effect/floor_decal/corner/beige/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/beige/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/bar + name = "bar corner" + color = "#7c443f" + +/obj/effect/floor_decal/corner/bar/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/bar/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/red + name = "red corner" + color = COLOR_RED_GRAY + +/obj/effect/floor_decal/corner/red/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/red/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/red/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/pink + name = "pink corner" + color = COLOR_PALE_RED_GRAY + +/obj/effect/floor_decal/corner/pink/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/pink/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/purple + name = "purple corner" + color = "#7C507f" + +/obj/effect/floor_decal/corner/purple/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/purple/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/mauve + name = "mauve corner" + color = COLOR_PALE_PURPLE_GRAY + +/obj/effect/floor_decal/corner/mauve/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/mauve/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/orange + name = "orange corner" + color = "#d27428" + +/obj/effect/floor_decal/corner/orange/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/orange/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/neutral + name = "neutral corner" + color = "#b2b0b0" + +/obj/effect/floor_decal/corner/neutral/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/neutral/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/brown + name = "brown corner" + color = COLOR_DARK_BROWN + +/obj/effect/floor_decal/corner/brown/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/brown/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/white + name = "white corner" + icon_state = "corner_white" + +/obj/effect/floor_decal/corner/white/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/white/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/grey + name = "grey corner" + color = "#8d8c8c" + +/obj/effect/floor_decal/corner/grey/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/grey/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/spline/plain + name = "spline - plain" + icon_state = "spline_plain" + alpha = 229 + +/obj/effect/floor_decal/spline/plain/diagonal + icon_state = "spline_plain_diagonal" + +/obj/effect/floor_decal/spline/fancy + name = "spline - fancy" + icon_state = "spline_fancy" + +/obj/effect/floor_decal/spline/fancy/wood + name = "spline - wood" + color = "#cb9e04" + +/obj/effect/floor_decal/spline/fancy/wood/corner + icon_state = "spline_fancy_corner" + +/obj/effect/floor_decal/spline/fancy/wood/cee + icon_state = "spline_fancy_cee" + +/obj/effect/floor_decal/spline/fancy/wood/three_quarters + icon_state = "spline_fancy_full" + +/obj/effect/floor_decal/industrial/warning + name = "hazard stripes" + icon_state = "warning" + +/obj/effect/floor_decal/industrial/warning/corner + icon_state = "warningcorner" + +/obj/effect/floor_decal/industrial/warning/full + icon_state = "warningfull" + +/obj/effect/floor_decal/industrial/warning/cee + icon_state = "warningcee" + +/obj/effect/floor_decal/industrial/warning/dust + name = "hazard stripes" + icon_state = "warning_dust" + +/obj/effect/floor_decal/industrial/warning/dust/corner + name = "hazard stripes" + icon_state = "warningcorner_dust" + +/obj/effect/floor_decal/industrial/warning_white + name = "hazard stripes" + icon_state = "warning_white" + +/obj/effect/floor_decal/industrial/warning_white/corner + icon_state = "warningcorner_white" + +/obj/effect/floor_decal/industrial/warning_white/full + icon_state = "warningfull_white" + +/obj/effect/floor_decal/industrial/warning_white/cee + icon_state = "warningcee_white" + +/obj/effect/floor_decal/industrial/warning_red + name = "hazard stripes" + icon_state = "warning_red" + +/obj/effect/floor_decal/industrial/warning_red/corner + icon_state = "warningcorner_red" + +/obj/effect/floor_decal/industrial/warning_red/full + icon_state = "warningfull_red" + +/obj/effect/floor_decal/industrial/warning_red/cee + icon_state = "warningcee_red" + +/obj/effect/floor_decal/industrial/hatch + name = "hatched marking" + icon_state = "delivery" + alpha = 229 + +/obj/effect/floor_decal/industrial/hatch/yellow + color = "#cfcf55" + +/obj/effect/floor_decal/industrial/hatch/red + color = COLOR_RED_GRAY + +/obj/effect/floor_decal/industrial/hatch/orange + color = COLOR_DARK_ORANGE + +/obj/effect/floor_decal/industrial/hatch/blue + color = COLOR_BLUE_GRAY + +/obj/effect/floor_decal/industrial/shutoff + name = "shutoff valve marker" + icon_state = "shutoff" + +/obj/effect/floor_decal/industrial/outline + name = "white outline" + icon_state = "outline" + alpha = 229 + +/obj/effect/floor_decal/industrial/outline/blue + name = "blue outline" + color = "#00b8b2" + +/obj/effect/floor_decal/industrial/outline/yellow + name = "yellow outline" + color = "#cfcf55" + +/obj/effect/floor_decal/industrial/outline/grey + name = "grey outline" + color = "#808080" + +/obj/effect/floor_decal/industrial/outline/red + name = "red outline" + color = COLOR_RED_GRAY + +/obj/effect/floor_decal/industrial/outline/orange + name = "orange outline" + color = COLOR_DARK_ORANGE + +/obj/effect/floor_decal/industrial/loading + name = "loading area" + icon_state = "loadingarea" + alpha = 229 + +/obj/effect/floor_decal/plaque + name = "plaque" + icon_state = "plaque" + +/obj/effect/floor_decal/asteroid + name = "random asteroid rubble" + icon_state = "asteroid0" + +/obj/effect/floor_decal/asteroid/New() + icon_state = "asteroid[rand(0,9)]" + ..() + +/obj/effect/floor_decal/chapel + name = "chapel" + icon_state = "chapel" + +/obj/effect/floor_decal/ss13/l1 + name = "L1" + icon_state = "L1" + +/obj/effect/floor_decal/ss13/l2 + name = "L2" + icon_state = "L2" + +/obj/effect/floor_decal/ss13/l3 + name = "L3" + icon_state = "L3" + +/obj/effect/floor_decal/ss13/l4 + name = "L4" + icon_state = "L4" + +/obj/effect/floor_decal/ss13/l5 + name = "L5" + icon_state = "L5" + +/obj/effect/floor_decal/ss13/l6 + name = "L6" + icon_state = "L6" + +/obj/effect/floor_decal/ss13/l7 + name = "L7" + icon_state = "L7" + +/obj/effect/floor_decal/ss13/l8 + name = "L8" + icon_state = "L8" + +/obj/effect/floor_decal/ss13/l9 + name = "L9" + icon_state = "L9" + +/obj/effect/floor_decal/ss13/l10 + name = "L10" + icon_state = "L10" + +/obj/effect/floor_decal/ss13/l11 + name = "L11" + icon_state = "L11" + +/obj/effect/floor_decal/ss13/l12 + name = "L12" + icon_state = "L12" + +/obj/effect/floor_decal/ss13/l13 + name = "L13" + icon_state = "L13" + +/obj/effect/floor_decal/ss13/l14 + name = "L14" + icon_state = "L14" + +/obj/effect/floor_decal/ss13/l15 + name = "L15" + icon_state = "L15" + +/obj/effect/floor_decal/ss13/l16 + name = "L16" + icon_state = "L16" + +/obj/effect/floor_decal/sign + name = "floor sign" + icon_state = "white_1" + +/obj/effect/floor_decal/sign/two + icon_state = "white_2" + +/obj/effect/floor_decal/sign/a + icon_state = "white_a" + +/obj/effect/floor_decal/sign/b + icon_state = "white_b" + +/obj/effect/floor_decal/sign/c + icon_state = "white_c" + +/obj/effect/floor_decal/sign/d + icon_state = "white_d" + +/obj/effect/floor_decal/sign/ex + icon_state = "white_ex" + +/obj/effect/floor_decal/sign/m + icon_state = "white_m" + +/obj/effect/floor_decal/sign/cmo + icon_state = "white_cmo" + +/obj/effect/floor_decal/sign/v + icon_state = "white_v" + +/obj/effect/floor_decal/sign/p + icon_state = "white_p" + +/obj/effect/floor_decal/solarpanel + icon_state = "solarpanel" + +/obj/effect/floor_decal/snow + icon = 'icons/turf/overlays.dmi' + icon_state = "snowfloor" + +/obj/effect/floor_decal/floordetail + plane = TURF_PLANE + layer = TURF_DETAIL_LAYER + color = COLOR_GUNMETAL + icon_state = "manydot" + appearance_flags = 0 + +/obj/effect/floor_decal/floordetail/New(var/newloc, var/newdir, var/newcolour) + color = null //color is here just for map preview, if left it applies both our and tile colors. + ..() + +/obj/effect/floor_decal/floordetail/tiled + icon_state = "manydot_tiled" + +/obj/effect/floor_decal/floordetail/pryhole + icon_state = "pryhole" + +/obj/effect/floor_decal/floordetail/edgedrain + icon_state = "edge" + +/obj/effect/floor_decal/floordetail/traction + icon_state = "traction" + +/obj/effect/floor_decal/ntlogo + icon_state = "ntlogo" + +/obj/effect/floor_decal/newcorner + icon = 'icons/turf/flooring/misc2.dmi' + +/obj/effect/floor_decal/newcorner/red + icon_state = "red" +/obj/effect/floor_decal/newcorner/red/quarter + icon_state = "red-quarter" +/obj/effect/floor_decal/newcorner/red/corner + icon_state = "red-corner" +/obj/effect/floor_decal/newcorner/red/diagonal + icon_state = "red-diagonal" +/obj/effect/floor_decal/newcorner/red/solid + icon_state = "redsolid" + +/obj/effect/floor_decal/newcorner/blue + icon_state = "blue" +/obj/effect/floor_decal/newcorner/blue/quarter + icon_state = "blue-quarter" +/obj/effect/floor_decal/newcorner/blue/corner + icon_state = "blue-corner" +/obj/effect/floor_decal/newcorner/blue/diagonal + icon_state = "blue-diagonal" +/obj/effect/floor_decal/newcorner/blue/solid + icon_state = "bluesolid" + +/obj/effect/floor_decal/newcorner/green + icon_state = "green" +/obj/effect/floor_decal/newcorner/green/quarter + icon_state = "green-quarter" +/obj/effect/floor_decal/newcorner/green/corner + icon_state = "green-corner" +/obj/effect/floor_decal/newcorner/green/diagonal + icon_state = "green-diagonal" +/obj/effect/floor_decal/newcorner/green/solid + icon_state = "greensolid" + +/obj/effect/floor_decal/newcorner/grey + icon_state = "grey" +/obj/effect/floor_decal/newcorner/grey/quarter + icon_state = "grey-quarter" +/obj/effect/floor_decal/newcorner/grey/corner + icon_state = "grey-corner" +/obj/effect/floor_decal/newcorner/grey/diagonal + icon_state = "grey-diagonal" +/obj/effect/floor_decal/newcorner/grey/solid + icon_state = "greysolid" + +/obj/effect/floor_decal/newcorner/yellow + icon_state = "yellow" +/obj/effect/floor_decal/newcorner/yellow/quarter + icon_state = "yellow-quarter" +/obj/effect/floor_decal/newcorner/yellow/corner + icon_state = "yellow-corner" +/obj/effect/floor_decal/newcorner/yellow/diagonal + icon_state = "yellow-diagonal" +/obj/effect/floor_decal/newcorner/yellow/solid + icon_state = "yellowsolid" + +/obj/effect/floor_decal/newcorner/purple + icon_state = "purple" +/obj/effect/floor_decal/newcorner/purple/quarter + icon_state = "purple-quarter" +/obj/effect/floor_decal/newcorner/purple/corner + icon_state = "purple-corner" +/obj/effect/floor_decal/newcorner/purple/diagonal + icon_state = "purple-diagonal" +/obj/effect/floor_decal/newcorner/purple/solid + icon_state = "purplesolid" + +/obj/effect/floor_decal/newcorner/teal + icon_state = "teal" +/obj/effect/floor_decal/newcorner/teal/quarter + icon_state = "teal-quarter" +/obj/effect/floor_decal/newcorner/teal/corner + icon_state = "teal-corner" +/obj/effect/floor_decal/newcorner/teal/diagonal + icon_state = "teal-diagonal" +/obj/effect/floor_decal/newcorner/teal/solid + icon_state = "tealsolid" + +/obj/effect/floor_decal/newcorner/white + icon_state = "white" +/obj/effect/floor_decal/newcorner/white/quarter + icon_state = "white-quarter" +/obj/effect/floor_decal/newcorner/white/corner + icon_state = "white-corner" +/obj/effect/floor_decal/newcorner/white/diagonal + icon_state = "white-diagonal" +/obj/effect/floor_decal/newcorner/white/solid + icon_state = "whitesolid" + +/obj/effect/floor_decal/newcorner/whitegreen + icon_state = "wgreen" +/obj/effect/floor_decal/newcorner/whitegreen/quarter + icon_state = "wgreen-quarter" +/obj/effect/floor_decal/newcorner/whitegreen/corner + icon_state = "wgreen-corner" +/obj/effect/floor_decal/newcorner/whitegreen/diagonal + icon_state = "wgreen-diagonal" +/obj/effect/floor_decal/newcorner/whitegreen/solid + icon_state = "wgreensolid" + +/obj/effect/floor_decal/newcorner/black + icon_state = "black" +/obj/effect/floor_decal/newcorner/black/quarter + icon_state = "black-quarter" +/obj/effect/floor_decal/newcorner/black/corner + icon_state = "black-corner" +/obj/effect/floor_decal/newcorner/black/diagonal + icon_state = "black-diagonal" +/obj/effect/floor_decal/newcorner/black/solid + icon_state = "blacksolid" + +/obj/effect/floor_decal/newcorner/kafel/white + icon_state = "whitekafel" +/obj/effect/floor_decal/newcorner/kafel/white/quarter + icon_state = "whitekafel-quarter" +/obj/effect/floor_decal/newcorner/kafel/white/diagonal + icon_state = "whitekafel-diagonal" +/obj/effect/floor_decal/newcorner/kafel/white/corner + icon_state = "whitekafel-corner" + +/obj/effect/floor_decal/newcorner/kafel/blue + icon_state = "bluekafel" +/obj/effect/floor_decal/newcorner/kafel/blue/quarter + icon_state = "bluekafel-quarter" +/obj/effect/floor_decal/newcorner/kafel/blue/diagonal + icon_state = "bluekafel-diagonal" +/obj/effect/floor_decal/newcorner/kafel/blue/corner + icon_state = "bluekafel-corner" + +/obj/effect/floor_decal/newcorner/plazaf + icon_state = "plazaf" +/obj/effect/floor_decal/newcorner/plazaf/quarter + icon_state = "plazaf-quarter" +/obj/effect/floor_decal/newcorner/plazaf/diagonal + icon_state = "plazaf-diagonal" +/obj/effect/floor_decal/newcorner/plazaf/corner + icon_state = "plazaf-corner" + +/obj/effect/floor_decal/newcorner/plazafalt + icon_state = "plazaf2" +/obj/effect/floor_decal/newcorner/plazafalt/quarter + icon_state = "plazaf2-quarter" +/obj/effect/floor_decal/newcorner/plazafalt/diagonal + icon_state = "plazaf2-quarter" +/obj/effect/floor_decal/newcorner/plazafalt/corner + icon_state = "plazaf2-corner" + +/obj/effect/floor_decal/newcorner/bar + icon_state = "bar" +/obj/effect/floor_decal/newcorner/bar/quarter + icon_state = "bar-quarter" +/obj/effect/floor_decal/newcorner/bar/corner + icon_state = "bar-corner" +/obj/effect/floor_decal/newcorner/bar/diagonal + icon_state = "bar-diagonal" + +/obj/effect/floor_decal/newcorner/cafe + icon_state = "cafe" +/obj/effect/floor_decal/newcorner/cafe/quarter + icon_state = "cafe-quarter" +/obj/effect/floor_decal/newcorner/cafe/corner + icon_state = "cafe-corner" +/obj/effect/floor_decal/newcorner/cafe/diagonal + icon_state = "cafe-diagonal" + +/obj/effect/floor_decal/newcorner/plating + icon_state = "plating" +/obj/effect/floor_decal/newcorner/plating/quarter + icon_state = "plating-quarter" +/obj/effect/floor_decal/newcorner/plating/corner + icon_state = "plating-corner" +/obj/effect/floor_decal/newcorner/plating/diagonal + icon_state = "plating-diagonal" + +/obj/effect/floor_decal/newcorner/polar + icon_state = "polar" +/obj/effect/floor_decal/newcorner/polar/quarter + icon_state = "polar-quarter" +/obj/effect/floor_decal/newcorner/polar/corner + icon_state = "polar-corner" + +/obj/effect/floor_decal/newcorner/reinforced + icon_state = "reinforced" +/obj/effect/floor_decal/newcorner/reinforced/corner + icon_state = "rcorner" + +/obj/effect/floor_decal/newcorner/train + icon_state = "train" +/obj/effect/floor_decal/newcorner/train/corner + icon_state = "train_c" + +/obj/effect/floor_decal/newcorner/train2 + icon_state = "train2" +/obj/effect/floor_decal/newcorner/train2/corner + icon_state = "train2_c" + +/obj/effect/floor_decal/newcorner/shaft + icon_state = "shaftplating" +/obj/effect/floor_decal/newcorner/shaft/quarter + icon_state = "shaftplating-quarter" +/obj/effect/floor_decal/newcorner/shaft/corner + icon_state = "shaftplating-corner" +/obj/effect/floor_decal/newcorner/shaft/diagonal + icon_state = "shaftplating-diagonal" + +/obj/effect/floor_decal/newcorner/step + icon_state = "step" +/obj/effect/floor_decal/newcorner/step_i + icon_state = "step_i" + +/obj/effect/floor_decal/newcorner/nbar + icon_state = "nbar" +/obj/effect/floor_decal/newcorner/nbar/corner + icon_state = "nbar_corner" + +/obj/effect/floor_decal/newcorner/dwood + icon_state = "dwood" + +/obj/effect/floor_decal/industrial/direction + icon_state = "dir_white" +/obj/effect/floor_decal/industrial/direction/black + icon_state = "dir_black" + +/obj/effect/floor_decal/industrial/mark + icon_state = "mark_white" +/obj/effect/floor_decal/industrial/mark/black + icon_state = "mark_black" + +/obj/effect/floor_decal/industrial/punctuation + icon_state = "punctuation_white" +/obj/effect/floor_decal/industrial/punctuation/black + icon_state = "punctuation_black" + +/obj/effect/floor_decal/industrial/plaza + icon_state = "plaza" +/obj/effect/floor_decal/industrial/plaza/box + icon_state = "plazabox" + +/obj/effect/floor_decal/turf/bloodbar + icon_state = "bloodbar" +/obj/effect/floor_decal/turf/bloodbar/off + icon_state = "bloodbar2" +/obj/effect/floor_decal/turf/bar + icon_state = "barfull" +/obj/effect/floor_decal/turf/bar2 + icon_state = "bar2" +/obj/effect/floor_decal/turf/bar3 + icon_state = "bar3" + +/obj/effect/floor_decal/turf/cafe + icon_state = "cafefull" +/obj/effect/floor_decal/turf/cafe2 + icon_state = "cafe2" + +/obj/effect/floor_decal/turf/shaft + icon_state = "shaft" +/obj/effect/floor_decal/turf/coldroom + icon_state = "coldroom" +/obj/effect/floor_decal/turf/steel + icon_state = "steel" + +/obj/effect/floor_decal/turf/aesculapius + icon_state = "aesculapius" +/obj/effect/floor_decal/turf/aesculapius/mem + icon_state = "mem" +/obj/effect/floor_decal/turf/aesculapius/mento + icon_state = "mento" +/obj/effect/floor_decal/turf/aesculapius/mori + icon_state = "mori" + +/obj/effect/floor_decal/turf/plating + icon_state = "platingfull" + +/obj/effect/floor_decal/turf/plate + icon_state = "plate" + +/obj/effect/floor_decal/turf/barnew + icon_state = "barnew" + +/obj/effect/floor_decal/turf/splate + icon_state = "shaftplating" diff --git a/code/game/turfs/flooring/flooring_premade.dm b/code/game/turfs/flooring/flooring_premade.dm new file mode 100644 index 00000000..0d22ef3f --- /dev/null +++ b/code/game/turfs/flooring/flooring_premade.dm @@ -0,0 +1,340 @@ +// simulated/floor is currently plating by default, but there really should be an explicit plating type. +/turf/simulated/floor/plating + name = "plating" + icon = 'icons/turf/flooring/plating.dmi' + icon_state = "plating" + plane = PLATING_PLANE + layer = PLATING_LAYER + +/turf/simulated/floor/plating/AltClick(var/mob/user) + if(CanPhysicallyInteract(user)) + if(istype(user.get_active_hand(), /obj/item/stack/rods)) + var/obj/item/stack/rods/R = user.get_active_hand() + visible_message("[user] has started place reinforced plating!") + if(R.get_amount() > 10) + if(do_after(user, 10 SECONDS)) + R.use(10) + ChangeTurf(/turf/simulated/floor/plating/reinforced) + + +/turf/simulated/floor/plating/reinforced + name = "reinforced plating" + icon = 'icons/turf/flooring/decals.dmi' + icon_state = "shaft-ready" + var/image/lattice_overlay + var/reinforced_stage = 1 + +/turf/simulated/floor/plating/reinforced/New() + ..() + icon_state = "shaft" + lattice_overlay = image(icon ='icons/obj/structures.dmi',icon_state ="latticefull") + lattice_overlay.layer = CATWALK_LAYER + //lattice_overlay.plane = ABOVE_TURF_PLANE + overlays += lattice_overlay + +/turf/simulated/floor/plating/reinforced/attackby(obj/item/C as obj, mob/user as mob) + if(isWelder(C) && reinforced_stage == 1) + var/obj/item/weapon/weldingtool/welder = C + if(welder.isOn()) + visible_message("[user] start to unweld lattice from [src]!") + if(do_after(user, 15 SECONDS) && welder.isOn()) + to_chat(user, "You unweld lattice from plating.") + playsound(src, 'sound/items/Welder.ogg', 80, 1) + overlays.Cut() + reinforced_stage++ + if(isCrowbar(C) && reinforced_stage == 2) + visible_message("[user] start to pry off [src.name] from floor!") + playsound(src, 'sound/items/Crowbar.ogg', 80, 1) + if(do_after(user, 10 SECONDS)) + playsound(src, 'sound/items/Crowbar.ogg', 80, 1) + new /obj/item/stack/rods(src.loc) + ChangeTurf(/turf/simulated/floor/plating) + + +/turf/simulated/floor/bluegrid + name = "mainframe floor" + icon = 'icons/turf/flooring/circuit.dmi' + icon_state = "bcircuit" + initial_flooring = /decl/flooring/reinforced/circuit + light_range = 2 + light_power = 3 + light_color = COLOR_BLUE + +/turf/simulated/floor/bluegrid/airless + initial_gas = null + +/turf/simulated/floor/greengrid + name = "mainframe floor" + icon = 'icons/turf/flooring/circuit.dmi' + icon_state = "gcircuit" + initial_flooring = /decl/flooring/reinforced/circuit/green + light_range = 2 + light_power = 3 + light_color = COLOR_GREEN + +/turf/simulated/floor/blackgrid + name = "mainframe floor" + icon = 'icons/turf/flooring/circuit.dmi' + icon_state = "rcircuit" + initial_flooring = /decl/flooring/reinforced/circuit/red + light_range = 2 + light_power = 2 + light_color = COLOR_RED + +/turf/simulated/floor/greengrid/airless + initial_gas = null + +/turf/simulated/floor/wood + name = "wooden floor" + icon = 'icons/turf/flooring/wood.dmi' + icon_state = "wood" + initial_flooring = /decl/flooring/wood + +/turf/simulated/floor/grass + name = "grass patch" + icon = 'icons/turf/flooring/grass.dmi' + icon_state = "grass0" + initial_flooring = /decl/flooring/grass + +/turf/simulated/floor/diona + name = "biomass" + icon = 'icons/turf/floors.dmi' + initial_flooring = /decl/flooring/diona + +/turf/simulated/floor/tiled + name = "steel floor" + icon = 'icons/turf/flooring/tiles.dmi' + icon_state = "steel" + initial_flooring = /decl/flooring/tiling + +/turf/simulated/floor/carpet + name = "brown carpet" + icon = 'icons/turf/flooring/carpet.dmi' + icon_state = "brown" + initial_flooring = /decl/flooring/carpet + +/turf/simulated/floor/carpet/blue + name = "blue carpet" + icon_state = "blue1" + initial_flooring = /decl/flooring/carpet/blue + +/turf/simulated/floor/carpet/blue2 + name = "pale blue carpet" + icon_state = "blue2" + initial_flooring = /decl/flooring/carpet/blue2 + +/turf/simulated/floor/carpet/purple + name = "purple carpet" + icon_state = "purple" + initial_flooring = /decl/flooring/carpet/purple + +/turf/simulated/floor/carpet/orange + name = "orange carpet" + icon_state = "orange" + initial_flooring = /decl/flooring/carpet/orange + +/turf/simulated/floor/carpet/green + name = "green carpet" + icon_state = "green" + initial_flooring = /decl/flooring/carpet/green + +/turf/simulated/floor/carpet/red + name = "red carpet" + icon_state = "red" + initial_flooring = /decl/flooring/carpet/red + +/turf/simulated/floor/reinforced + name = "reinforced floor" + icon = 'icons/turf/flooring/tiles.dmi' + icon_state = "reinforced" + initial_flooring = /decl/flooring/reinforced + +/turf/simulated/floor/reinforced/airless + initial_gas = null + +/turf/simulated/floor/reinforced/airmix + initial_gas = list("oxygen" = MOLES_O2ATMOS, "nitrogen" = MOLES_N2ATMOS) + +/turf/simulated/floor/reinforced/nitrogen + initial_gas = list("nitrogen" = ATMOSTANK_NITROGEN) + +/turf/simulated/floor/reinforced/hydrogen + initial_gas = list("hydrogen" = ATMOSTANK_HYDROGEN) + +/turf/simulated/floor/reinforced/oxygen + initial_gas = list("oxygen" = ATMOSTANK_OXYGEN) + +/turf/simulated/floor/reinforced/phoron + initial_gas = list("phoron" = ATMOSTANK_PHORON) + +/turf/simulated/floor/reinforced/nitrogen/engine + name = "engine floor" + initial_gas = list("nitrogen" = MOLES_N2STANDARD) + +/turf/simulated/floor/reinforced/phoron/fuel + initial_gas = list("phoron" = ATMOSTANK_PHORON_FUEL) + +/turf/simulated/floor/reinforced/hydrogen + initial_gas = list("hydrogen" = ATMOSTANK_HYDROGEN) + +/turf/simulated/floor/reinforced/hydrogen/fuel + initial_gas = list("hydrogen" = ATMOSTANK_HYDROGEN_FUEL) + +/turf/simulated/floor/reinforced/carbon_dioxide + initial_gas = list("carbon_dioxide" = ATMOSTANK_CO2) + +/turf/simulated/floor/reinforced/n20 + initial_gas = list("sleeping_agent" = ATMOSTANK_NITROUSOXIDE) + + +/turf/simulated/floor/cult + name = "engraved floor" + icon = 'icons/turf/flooring/cult.dmi' + icon_state = "cult" + initial_flooring = /decl/flooring/reinforced/cult + +/turf/simulated/floor/cult/cultify() + return + +/turf/simulated/floor/tiled/dark + name = "dark floor" + icon_state = "dark" + initial_flooring = /decl/flooring/tiling/dark + +/turf/simulated/floor/tiled/dark/airless + initial_gas = null + +/turf/simulated/floor/tiled/white + name = "white floor" + icon_state = "white" + initial_flooring = /decl/flooring/tiling/white + +/turf/simulated/floor/tiled/freezer + name = "tiles" + icon_state = "freezer" + initial_flooring = /decl/flooring/tiling/freezer + +/turf/simulated/floor/lino + name = "lino" + icon = 'icons/turf/flooring/linoleum.dmi' + icon_state = "lino" + initial_flooring = /decl/flooring/linoleum + +/turf/simulated/floor/tiled/ramp + name = "foot ramp" + icon = 'icons/turf/flooring/tiles.dmi' + icon_state = "ramptop" + initial_flooring = /decl/flooring/reinforced/ramp + +/turf/simulated/floor/tiled/ramp/bottom + name = "foot ramp" + icon = 'icons/turf/flooring/tiles.dmi' + icon_state = "rampbot" + initial_flooring = /decl/flooring/reinforced/ramp/bottom + +/turf/simulated/floor/plating/n2floor + name = "floor with low ceiling" + icon_state = "n2floor" + desc = "There is low ceiling here!" + +/turf/simulated/floor/plating/n2floor/Enter(var/atom/movable/A) + ..() + if(ishuman(A)) + var/mob/living/carbon/human/L = A + var/turf/Above = GetAbove(src) + if(!L.resting && !istype(Above, /turf/simulated/open)) + return 0 + return 1 + +//ATMOS PREMADES +/turf/simulated/floor/reinforced/airless + name = "vacuum floor" + initial_gas = null + temperature = TCMB + +/turf/simulated/floor/airless + name = "airless plating" + initial_gas = null + temperature = TCMB + +/turf/simulated/floor/tiled/airless + name = "airless floor" + initial_gas = null + temperature = TCMB + +/turf/simulated/floor/bluegrid/airless + name = "airless floor" + initial_gas = null + temperature = TCMB + +/turf/simulated/floor/greengrid/airless + name = "airless floor" + initial_gas = null + temperature = TCMB + +/turf/simulated/floor/greengrid/nitrogen + initial_gas = list("nitrogen" = MOLES_N2STANDARD) + +/turf/simulated/floor/tiled/white/airless + name = "airless floor" + initial_gas = null + temperature = TCMB + +// Placeholders +/turf/simulated/floor/airless/lava + name = "lava" + icon = 'icons/turf/flooring/lava.dmi' + icon_state = "lava" + +/turf/simulated/floor/ice + name = "ice" + icon = 'icons/turf/snow.dmi' + icon_state = "ice" + +/turf/simulated/floor/snow + name = "snow" + icon = 'icons/turf/snow.dmi' + icon_state = "snow" + +/turf/simulated/floor/snow/New() + icon_state = pick("snow[rand(1,12)]","snow0") + ..() + + +/turf/simulated/floor/light +/turf/simulated/floor/airless/ceiling + +/turf/simulated/floor/beach + name = "beach" + icon = 'icons/misc/beach.dmi' + +/turf/simulated/floor/beach/sand + name = "sand" + icon_state = "sand" + +/turf/simulated/floor/beach/sand/desert + icon_state = "desert" + has_resources = 1 + +/turf/simulated/floor/beach/sand/desert/New() + icon_state = "desert[rand(0,5)]" + ..() + +/turf/simulated/floor/beach/coastline + name = "coastline" + icon = 'icons/misc/beach2.dmi' + icon_state = "sandwater" + +/turf/simulated/floor/beach/water + name = "water" + icon_state = "water" + +/turf/simulated/floor/beach/water/update_dirt() + return // Water doesn't become dirty + +/turf/simulated/floor/beach/water/ocean + icon_state = "seadeep" + +/turf/simulated/floor/beach/water/New() + ..() + overlays += image("icon"='icons/misc/beach.dmi',"icon_state"="water5","layer"=BASE_MOB_LAYER+0.1) diff --git a/code/game/turfs/flooring/flooring_shuttle.dm b/code/game/turfs/flooring/flooring_shuttle.dm new file mode 100644 index 00000000..f61c6d87 --- /dev/null +++ b/code/game/turfs/flooring/flooring_shuttle.dm @@ -0,0 +1,31 @@ +/turf/simulated/floor/shuttle + name = "floor" + icon = 'icons/turf/shuttle.dmi' + +/turf/simulated/floor/shuttle/blue + icon_state = "floor" + initial_flooring = /decl/flooring/reinforced/shuttle/blue + +/turf/simulated/floor/shuttle/yellow + icon_state = "floor2" + initial_flooring = /decl/flooring/reinforced/shuttle/yellow + +/turf/simulated/floor/shuttle/white + icon_state = "floor3" + initial_flooring = /decl/flooring/reinforced/shuttle/white + +/turf/simulated/floor/shuttle/red + icon_state = "floor4" + initial_flooring = /decl/flooring/reinforced/shuttle/red + +/turf/simulated/floor/shuttle/purple + icon_state = "floor5" + initial_flooring = /decl/flooring/reinforced/shuttle/purple + +/turf/simulated/floor/shuttle/darkred + icon_state = "floor6" + initial_flooring = /decl/flooring/reinforced/shuttle/darkred + +/turf/simulated/floor/shuttle/black + icon_state = "floor7" + initial_flooring = /decl/flooring/reinforced/shuttle/black diff --git a/code/game/turfs/initialization/init.dm b/code/game/turfs/initialization/init.dm new file mode 100644 index 00000000..956a83b9 --- /dev/null +++ b/code/game/turfs/initialization/init.dm @@ -0,0 +1,102 @@ +/decl/turf_initializer/proc/InitializeTurf(var/turf/T) + return + +/area + var/turf_initializer = null + +/area/Initialize() + . = ..() + for(var/turf/T in src) + if(turf_initializer) + var/decl/turf_initializer/ti = decls_repository.get_decl(turf_initializer) + ti.InitializeTurf(T) + +/decl/turf_initializer/unexplored/InitializeTurf(var/turf/simulated/T) + if(T.density) + return + + //if(prob(1)) + // new /obj/random/mining_hostile(T) + + if(prob(10)) + new /obj/structure/flora/ash(T) + + else if(prob(10)) + new /obj/structure/flora/ash/mushrooms(T) + + else if(prob(10)) + new /obj/structure/flora/rocks(T) + + +/decl/turf_initializer/warfare/InitializeTurf(var/turf/simulated/T) + + if(T.density) + return + + if(istype(T, /turf/simulated/floor/trench) || istype(T, /turf/simulated/floor/exoplanet/water/shallow)) + return + + if(prob(1)) + new /mob/living/simple_animal/hostile/retaliate/rat(T) + + else if(prob(10)) + new /obj/structure/flora/grass/both(T) // /obj/structure/flora/tree/dead(T)// /obj/structure/flora/ash(T) + + else if(prob(10)) + new /obj/structure/flora/grass/brown(T) + + else if(prob(5)) + new /obj/structure/barbwire(T) + + else if(prob(5)) + new /obj/structure/anti_tank(T) + + else if(prob(5)) + new /obj/structure/landmine(T) + + +/decl/turf_initializer/oldfare/InitializeTurf(var/turf/simulated/T) + if(T.density) + return + + if(istype(T, /turf/simulated/floor/trench) || istype(T, /turf/simulated/floor/exoplanet/water/shallow)) + return + + //if(prob(1)) //Rats are lagging I'm pretty sure. + // new /mob/living/simple_animal/hostile/retaliate/rat(T) + + else if(prob(10)) + new /obj/structure/flora/ash(T) + + else if(prob(15)) + new /obj/structure/barbwire(T) + + else if(prob(5)) + new /obj/structure/anti_tank(T) + + else if(prob(5)) + new /obj/structure/landmine(T) + + +/decl/turf_initializer/vietfare/InitializeTurf(var/turf/simulated/T) + + if(T.density) + return + + if(istype(T, /turf/simulated/floor/trench) || istype(T, /turf/simulated/floor/exoplanet/water/shallow)) + return + + if(prob(1)) + new /mob/living/simple_animal/hostile/retaliate/rat(T) + + else if(prob(10)) + new /obj/structure/flora/jungle/trees(T) + + else if(prob(10)) + new /obj/structure/flora/jungle/bushes(T) + + else if(prob(1)) + new /obj/structure/anti_tank(T) + + else if(prob(1)) + new /obj/structure/landmine(T) \ No newline at end of file diff --git a/code/game/turfs/initialization/maintenance.dm b/code/game/turfs/initialization/maintenance.dm new file mode 100644 index 00000000..dbb64f95 --- /dev/null +++ b/code/game/turfs/initialization/maintenance.dm @@ -0,0 +1,78 @@ +/decl/turf_initializer/maintenance + var/clutter_probability = 2 + var/oil_probability = 2 + var/vermin_probability = 0.5 + var/web_probability = 25 + +/decl/turf_initializer/maintenance/heavy + clutter_probability = 5 + web_probability = 50 + vermin_probability = 0.5 + +/decl/turf_initializer/maintenance/space + clutter_probability = 0 + vermin_probability = 0 + web_probability = 0 + +/decl/turf_initializer/maintenance/InitializeTurf(var/turf/simulated/T) + if(T.density) + return + // Quick and dirty check to avoid placing things inside windows + if(locate(/obj/structure/grille, T)) + return + + var/cardinal_turfs = T.CardinalTurfs() + + T.dirt = get_dirt_amount() + // If a neighbor is dirty, then we get dirtier. + var/how_dirty = dirty_neighbors(cardinal_turfs) + for(var/i = 0; i < how_dirty; i++) + T.dirt += rand(0,10) + T.update_dirt() + + if(prob(oil_probability)) + new /obj/effect/decal/cleanable/blood/oil(T) + + if(prob(clutter_probability)) + var/new_junk = get_random_junk_type() + new new_junk(T) + + if(prob(vermin_probability)) + if(prob(80)) + new /obj/random/mob/roaches(T)///mob/living/simple_animal/mouse(T) + else + new /mob/living/simple_animal/hostile/retaliate/roach(T)///mob/living/simple_animal/lizard(T) + + if(prob(web_probability)) // Keep in mind that only "corners" get any sort of web + attempt_web(T, cardinal_turfs) + +/decl/turf_initializer/maintenance/proc/dirty_neighbors(var/list/cardinal_turfs) + var/how_dirty = 0 + for(var/turf/simulated/T in cardinal_turfs) + // Considered dirty if more than halfway to visible dirt + if(T.dirt > 25) + how_dirty++ + return how_dirty + +/decl/turf_initializer/maintenance/proc/attempt_web(var/turf/simulated/T) + var/turf/north_turf = get_step(T, NORTH) + if(!north_turf || !north_turf.density) + return + + for(var/dir in list(WEST, EAST)) // For the sake of efficiency, west wins over east in the case of 1-tile valid spots, rather than doing pick() + var/turf/neighbour = get_step(T, dir) + if(neighbour && neighbour.density) + if(dir == WEST) + new /obj/effect/decal/cleanable/cobweb(T) + if(dir == EAST) + new /obj/effect/decal/cleanable/cobweb2(T) + if(prob(web_probability)) + var/obj/effect/spider/spiderling/spiderling = new /obj/effect/spider/spiderling/mundane/dormant(T) + spiderling.pixel_y = spiderling.shift_range + spiderling.pixel_x = dir == WEST ? -spiderling.shift_range : spiderling.shift_range + +/decl/turf_initializer/maintenance/proc/get_dirt_amount() + return rand(10, 50) + rand(0, 50) + +/decl/turf_initializer/maintenance/heavy/get_dirt_amount() + return ..() + 10 diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm new file mode 100644 index 00000000..8b58e62a --- /dev/null +++ b/code/game/turfs/simulated.dm @@ -0,0 +1,168 @@ +/turf/simulated + name = "station" + var/wet = 0 + var/image/wet_overlay = null + + //Mining resources (for the large drills). + var/has_resources + var/list/resources + + var/thermite = 0 + initial_gas = list("oxygen" = MOLES_O2STANDARD, "nitrogen" = MOLES_N2STANDARD) + var/to_be_destroyed = 0 //Used for fire, if a melting temperature was reached, it will be destroyed + var/max_fire_temperature_sustained = 0 //The max temperature of the fire which it was subjected to + var/dirt = 0 + + var/timer_id + +// This is not great. +/turf/simulated/proc/wet_floor(var/wet_val = 1, var/overwrite = FALSE) + if(wet_val < wet && !overwrite) + return + + if(!wet) + wet = wet_val + wet_overlay = image('icons/effects/water.dmi',src,"wet_floor") + overlays += wet_overlay + + timer_id = addtimer(CALLBACK(src,/turf/simulated/proc/unwet_floor),8 SECONDS, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_NO_HASH_WAIT|TIMER_OVERRIDE) + +/turf/simulated/proc/unwet_floor(var/check_very_wet = TRUE) + if(check_very_wet && wet >= 2) + wet-- + timer_id = addtimer(CALLBACK(src,/turf/simulated/proc/unwet_floor), 8 SECONDS, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_NO_HASH_WAIT|TIMER_OVERRIDE) + return + + wet = 0 + if(wet_overlay) + overlays -= wet_overlay + wet_overlay = null + +/turf/simulated/clean_blood() + for(var/obj/effect/decal/cleanable/blood/B in contents) + B.clean_blood() + ..() + +/turf/simulated/New() + ..() + if(istype(loc, /area/chapel)) + holy = 1 + levelupdate() + +/turf/simulated/Destroy() + deltimer(timer_id) + return ..() + +/turf/simulated/proc/AddTracks(var/typepath,var/bloodDNA,var/comingdir,var/goingdir,var/bloodcolor=COLOR_BLOOD_HUMAN) + var/obj/effect/decal/cleanable/blood/tracks/tracks = locate(typepath) in src + if(!tracks) + tracks = new typepath(src) + tracks.AddTracks(bloodDNA,comingdir,goingdir,bloodcolor) + +/turf/simulated/proc/update_dirt() + dirt = min(dirt+1, 101) + var/obj/effect/decal/cleanable/dirt/dirtoverlay = locate(/obj/effect/decal/cleanable/dirt, src) + if (dirt > 50) + if (!dirtoverlay) + dirtoverlay = new/obj/effect/decal/cleanable/dirt(src) + dirtoverlay.alpha = min((dirt - 50) * 5, 255) + +/turf/simulated/remove_cleanables() + dirt = 0 + . = ..() + +/turf/simulated/Entered(atom/A, atom/OL) + if (istype(A,/mob/living)) + var/mob/living/M = A + if(M.lying) + return ..() + + // Dirt overlays. + update_dirt() + + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + // Tracking blood + var/list/bloodDNA = null + var/bloodcolor="" + if(H.shoes) + var/obj/item/clothing/shoes/S = H.shoes + if(istype(S)) + S.handle_movement(src,(H.m_intent == "run" ? 1 : 0)) + if(S.track_blood && S.blood_DNA) + bloodDNA = S.blood_DNA + bloodcolor=S.blood_color + S.track_blood-- + else + if(H.track_blood && H.feet_blood_DNA) + bloodDNA = H.feet_blood_DNA + bloodcolor = H.feet_blood_color + H.track_blood-- + + if (bloodDNA) + src.AddTracks(H.species.get_move_trail(H),bloodDNA,H.dir,0,bloodcolor) // Coming + var/turf/simulated/from = get_step(H,reverse_direction(H.dir)) + if(istype(from) && from) + from.AddTracks(H.species.get_move_trail(H),bloodDNA,0,H.dir,bloodcolor) // Going + + bloodDNA = null + + if(src.wet) + + if(M.buckled || (M.m_intent == "walk" && prob(min(100, 100/(wet/10))) ) ) + return + + var/slip_dist = 1 + var/slip_stun = 6 + var/floor_type = "wet" + + if(2 <= src.wet) // Lube + floor_type = "slippery" + slip_dist = 4 + slip_stun = 10 + + if(M.slip("the [floor_type] floor", slip_stun)) + for(var/i = 1 to slip_dist) + step(M, M.dir) + sleep(1) + else + M.inertia_dir = 0 + else + M.inertia_dir = 0 + + ..() + +//returns 1 if made bloody, returns 0 otherwise +/turf/simulated/add_blood(mob/living/carbon/human/M as mob) + if (!..()) + return 0 + + if(istype(M)) + for(var/obj/effect/decal/cleanable/blood/B in contents) + if(!B.blood_DNA) + B.blood_DNA = list() + if(!B.blood_DNA[M.dna.unique_enzymes]) + B.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type + B.virus2 = virus_copylist(M.virus2) + return 1 //we bloodied the floor + blood_splatter(src,M.get_blood(M.vessel),1) + return 1 //we bloodied the floor + return 0 + +// Only adds blood on the floor -- Skie +/turf/simulated/proc/add_blood_floor(mob/living/carbon/M as mob) + if( istype(M, /mob/living/carbon/alien )) + var/obj/effect/decal/cleanable/blood/xeno/this = new /obj/effect/decal/cleanable/blood/xeno(src) + this.blood_DNA["UNKNOWN BLOOD"] = "X*" + else if( istype(M, /mob/living/silicon/robot )) + new /obj/effect/decal/cleanable/blood/oil(src) + +/turf/simulated/proc/can_build_cable(var/mob/user) + return 0 + +/turf/simulated/attackby(var/obj/item/thing, var/mob/user) + if(isCoil(thing) && can_build_cable(user)) + var/obj/item/stack/cable_coil/coil = thing + coil.turf_place(src, user) + return + return ..() diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm new file mode 100644 index 00000000..8220d01e --- /dev/null +++ b/code/game/turfs/simulated/floor.dm @@ -0,0 +1,92 @@ +/turf/simulated/floor + name = "plating" + icon = 'icons/turf/flooring/plating.dmi' + icon_state = "plating" + + // Damage to flooring. + var/broken + var/burnt + + // Plating data. + var/base_name = "plating" + var/base_desc = "The naked hull." + var/base_icon = 'icons/turf/flooring/plating.dmi' + var/base_icon_state = "plating" + var/base_color = COLOR_WHITE + + // Flooring data. + var/flooring_override + var/initial_flooring + var/decl/flooring/flooring + var/mineral = DEFAULT_WALL_MATERIAL + + thermal_conductivity = 0.040 + heat_capacity = 10000 + var/lava = 0 + +/turf/simulated/floor/is_plating() + return !flooring + +/turf/simulated/floor/protects_atom(var/atom/A) + return (A.level <= 1 && !is_plating()) || ..() + +/turf/simulated/floor/New(var/newloc, var/floortype) + ..(newloc) + if(!floortype && initial_flooring) + floortype = initial_flooring + if(floortype) + set_flooring(get_flooring_data(floortype)) + generate_splines() + +/turf/simulated/floor/proc/set_flooring(var/decl/flooring/newflooring) + make_plating(defer_icon_update = 1) + flooring = newflooring + update_icon(1) + levelupdate() + +//This proc will set floor_type to null and the update_icon() proc will then change the icon_state of the turf +//This proc auto corrects the grass tiles' siding. +/turf/simulated/floor/proc/make_plating(var/place_product, var/defer_icon_update) + + overlays.Cut() + + SetName(base_name) + desc = base_desc + icon = base_icon + icon_state = base_icon_state + color = base_color + plane = PLATING_PLANE + layer = PLATING_LAYER + + if(flooring) + flooring.on_remove() + if(flooring.build_type && place_product) + new flooring.build_type(src) + flooring = null + + set_light(0) + broken = null + burnt = null + flooring_override = null + levelupdate() + + if(!defer_icon_update) + update_icon(1) + +/turf/simulated/floor/levelupdate() + for(var/obj/O in src) + O.hide(O.hides_under_flooring() && src.flooring) + + if(flooring) + plane = TURF_PLANE + else + plane = PLATING_PLANE + layer = PLATING_LAYER + +/turf/simulated/floor/Crossed(var/atom/A) + ..() + if(istype(A, /obj/item/projectile/flamer)) + for(var/mob/M in src) + if(ishuman(M)) + return + new /obj/flamer_fire(src, 12, 10, "red", 1) diff --git a/code/game/turfs/simulated/floor_acts.dm b/code/game/turfs/simulated/floor_acts.dm new file mode 100644 index 00000000..ee42c625 --- /dev/null +++ b/code/game/turfs/simulated/floor_acts.dm @@ -0,0 +1,45 @@ +/turf/simulated/floor/ex_act(severity) + //set src in oview(1) + switch(severity) + if(1.0) + src.ChangeTurf(get_base_turf_by_area(src)) + if(2.0) + switch(pick(40;1,40;2,3)) + if (1) + if(prob(33)) new /obj/item/stack/material/steel(src) + src.ReplaceWithLattice() + if(2) + src.ChangeTurf(get_base_turf_by_area(src)) + if(3) + if(prob(33)) new /obj/item/stack/material/steel(src) + if(prob(80)) + src.break_tile_to_plating() + else + src.break_tile() + src.hotspot_expose(1000,CELL_VOLUME) + if(3.0) + if (prob(50)) + src.break_tile() + src.hotspot_expose(1000,CELL_VOLUME) + return + +/turf/simulated/floor/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + + var/temp_destroy = get_damage_temperature() + if(!burnt && prob(5)) + burn_tile(exposed_temperature) + else if(temp_destroy && exposed_temperature >= (temp_destroy + 100) && prob(1) && !is_plating()) + make_plating() //destroy the tile, exposing plating + burn_tile(exposed_temperature) + return + +//should be a little bit lower than the temperature required to destroy the material +/turf/simulated/floor/proc/get_damage_temperature() + return flooring ? flooring.damage_temperature : null + +/turf/simulated/floor/adjacent_fire_act(turf/simulated/floor/adj_turf, datum/gas_mixture/adj_air, adj_temp, adj_volume) + var/dir_to = get_dir(src, adj_turf) + + for(var/obj/structure/window/W in src) + if(W.dir == dir_to || W.is_fulltile()) //Same direction or diagonal (full tile) + W.fire_act(adj_air, adj_temp, adj_volume) diff --git a/code/game/turfs/simulated/floor_attackby.dm b/code/game/turfs/simulated/floor_attackby.dm new file mode 100644 index 00000000..c87944b0 --- /dev/null +++ b/code/game/turfs/simulated/floor_attackby.dm @@ -0,0 +1,182 @@ +/turf/simulated/floor/attackby(obj/item/C as obj, mob/user as mob) + + if(!C || !user) + return 0 + + if(isCoil(C) || (flooring && istype(C, /obj/item/stack/rods))) + return ..(C, user) + + if(flooring) + if(isCrowbar(C) && user.a_intent == I_GRAB) + if(broken || burnt) + to_chat(user, "You start to pry the [flooring.descriptor].") + if(do_after(user, 4 SECONDS)) + to_chat(user, "You remove the broken [flooring.descriptor].") + ChangeTurf(/turf/simulated/floor/plating) + else if(flooring.flags & TURF_IS_FRAGILE) + to_chat(user, "You start to pry the [flooring.descriptor].") + if(do_after(user, 4 SECONDS)) + to_chat(user, "You forcefully pry off the [flooring.descriptor], destroying them in the process.") + ChangeTurf(/turf/simulated/floor/plating) + else if(flooring.flags & TURF_REMOVE_CROWBAR) + to_chat(user, "You start to pry the [flooring.descriptor].") + if(do_after(user, 4 SECONDS)) + to_chat(user, "You lever off the [flooring.descriptor].") + ChangeTurf(/turf/simulated/floor/plating) + new /obj/item/stack/tile/floor(src) + else + return + playsound(src, 'sound/items/Crowbar.ogg', 80, 1) + return + else if(isScrewdriver(C) && (flooring.flags & TURF_REMOVE_SCREWDRIVER)) + if(broken || burnt) + return + to_chat(user, "You unscrew and remove the [flooring.descriptor].") + ChangeTurf(/turf/simulated/floor/plating) + playsound(src, 'sound/items/Screwdriver.ogg', 80, 1) + return + else if(isWrench(C) && (flooring.flags & TURF_REMOVE_WRENCH)) + to_chat(user, "You unwrench and remove the [flooring.descriptor].") + ChangeTurf(/turf/simulated/floor/plating) + playsound(src, 'sound/items/Ratchet.ogg', 80, 1) + return + else if(istype(C, /obj/item/weapon/shovel) && (flooring.flags & TURF_REMOVE_SHOVEL)) + to_chat(user, "You shovel off the [flooring.descriptor].") + ChangeTurf(/turf/simulated/floor/plating) + playsound(src, 'sound/items/Deconstruct.ogg', 80, 1) + return + else if(isCoil(C)) + to_chat(user, "You must remove the [flooring.descriptor] first.") + return + else + + if(istype(C, /obj/item/stack)) + if(broken || burnt) + to_chat(user, "This section is too damaged to support anything. Use a welder to fix the damage.") + return + //first check, catwalk? Else let flooring do its thing + if(locate(/obj/structure/catwalk, src)) + return + if (istype(C, /obj/item/stack/rods)) + var/obj/item/stack/rods/R = C + if (R.use(2)) + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + new /obj/structure/catwalk(src) + return + var/obj/item/stack/S = C + var/decl/flooring/use_flooring + for(var/flooring_type in flooring_types) + var/decl/flooring/F = flooring_types[flooring_type] + if(!F.build_type) + continue + if(ispath(S.type, F.build_type) || ispath(S.build_type, F.build_type)) + use_flooring = F + break + if(!use_flooring) + return + // Do we have enough? + if(use_flooring.build_cost && S.get_amount() < use_flooring.build_cost) + to_chat(user, "You require at least [use_flooring.build_cost] [S.name] to complete the [use_flooring.descriptor].") + return + // Stay still and focus... + if(use_flooring.build_time && !do_after(user, use_flooring.build_time, src)) + return + if(flooring || !S || !user || !use_flooring) + return + if(S.use(use_flooring.build_cost)) + set_flooring(use_flooring) + playsound(src, 'sound/items/Deconstruct.ogg', 80, 1) + return + // Repairs and Deconstruction. + else if(isCrowbar(C)) + if(broken || burnt) + playsound(src, 'sound/items/Crowbar.ogg', 80, 1) + visible_message("[user] has begun prying off the damaged plating.") + var/turf/T = GetBelow(src) + if(T) + T.visible_message("The ceiling above looks as if it's being pried off.") + if(do_after(user, 10 SECONDS)) + visible_message("[user] has pried off the damaged plating.") + new /obj/item/stack/tile/floor(src) + src.ReplaceWithLattice() + playsound(src, 'sound/items/Deconstruct.ogg', 80, 1) + if(T) + T.visible_message("The ceiling above has been pried off!") + else + return + return + else if(isWelder(C)) + var/obj/item/weapon/weldingtool/welder = C + if(welder.isOn() && (is_plating())) + if(broken || burnt) + if(welder.isOn()) + to_chat(user, "You fix some dents on the broken plating.") + playsound(src, 'sound/items/Welder.ogg', 80, 1) + icon_state = "plating" + burnt = null + broken = null + else + to_chat(user, "You need more welding fuel to complete this task.") + return + else + if(welder.isOn()) + playsound(src, 'sound/items/Welder.ogg', 80, 1) + visible_message("[user] has started melting the plating's reinforcements!") + if(do_after(user, 5 SECONDS) && welder.isOn()) + visible_message("[user] has melted the plating's reinforcements! It should be possible to pry it off.") + playsound(src, 'sound/items/Welder.ogg', 80, 1) + burnt = 1 + remove_decals() + update_icon() + else + to_chat(user, "You need more welding fuel to complete this task.") + return + + + return ..() + +/turf/simulated/floor/acid_melt() + . = FALSE + var/turf/T = GetBelow(src) + + if(flooring) + visible_message("The acid dissolves the [flooring.descriptor]!") + make_plating() + + else if(is_plating() && !(broken || burnt)) + playsound(src, 'sound/items/Welder.ogg', 80, 1) + visible_message("The acid has started melting \the [name]'s reinforcements!") + if(T) + T.audible_message("A strange sizzling noise eminates from the ceiling.") + burnt = 1 + remove_decals() + update_icon() + + else if(broken || burnt) + if(acid_melted == 0) + visible_message("The acid has melted the plating's reinforcements! It's about to break through!.") + playsound(src, 'sound/items/Welder.ogg', 80, 1) + + if(T) + T.visible_message("A strange substance drips from the ceiling, dropping below with a sizzle.") + acid_melted++ + else + visible_message("The acid melts the plating away into nothing!") + new /obj/item/stack/tile/floor(src) + src.ReplaceWithLattice() + playsound(src, 'sound/items/Deconstruct.ogg', 80, 1) + if(T) + T.visible_message("The ceiling above melts away!") + . = TRUE + qdel(src) + else + return TRUE + +/turf/simulated/floor/can_build_cable(var/mob/user) + if(!is_plating() || flooring) + to_chat(user, "Removing the tiling first.") + return 0 + if(broken || burnt) + to_chat(user, "This section is too damaged to support anything. Use a welder to fix the damage.") + return 0 + return 1 diff --git a/code/game/turfs/simulated/floor_damage.dm b/code/game/turfs/simulated/floor_damage.dm new file mode 100644 index 00000000..c706a7f9 --- /dev/null +++ b/code/game/turfs/simulated/floor_damage.dm @@ -0,0 +1,27 @@ +/turf/simulated/floor/proc/gets_drilled() + return + +/turf/simulated/floor/proc/break_tile_to_plating() + if(!is_plating()) + make_plating() + break_tile() + +/turf/simulated/floor/proc/break_tile() + if(!flooring || !(flooring.flags & TURF_CAN_BREAK) || !isnull(broken)) + return + if(flooring.has_damage_range) + broken = rand(0,flooring.has_damage_range) + else + broken = 0 + remove_decals() + update_icon() + +/turf/simulated/floor/proc/burn_tile(var/exposed_temperature) + if(!flooring || !(flooring.flags & TURF_CAN_BURN) || !isnull(burnt)) + return + if(flooring.has_burn_range) + burnt = rand(0,flooring.has_burn_range) + else + burnt = 0 + remove_decals() + update_icon() \ No newline at end of file diff --git a/code/game/turfs/simulated/floor_icon.dm b/code/game/turfs/simulated/floor_icon.dm new file mode 100644 index 00000000..eaeaecaa --- /dev/null +++ b/code/game/turfs/simulated/floor_icon.dm @@ -0,0 +1,73 @@ +var/list/flooring_cache = list() + +/turf/simulated/floor/update_icon(var/update_neighbors) + + if(lava) + return + + if(flooring) + // Set initial icon and strings. + SetName(flooring.name) + desc = flooring.desc + icon = flooring.icon + color = flooring.color + + if(flooring_override) + icon_state = flooring_override + else + icon_state = flooring.icon_base + if(flooring.has_base_range) + icon_state = "[icon_state][rand(0,flooring.has_base_range)]" + flooring_override = icon_state + + // Apply edges, corners, and inner corners. + overlays.Cut() + var/has_border = 0 + if(flooring.flags & TURF_HAS_EDGES) + for(var/step_dir in GLOB.cardinal) + var/turf/simulated/floor/T = get_step(src, step_dir) + if(!istype(T) || !T.flooring || T.flooring.name != flooring.name) + has_border |= step_dir + overlays |= get_flooring_overlay("[flooring.icon_base]-edge-[step_dir]", "[flooring.icon_base]_edges", step_dir) + + for(var/diagonal in list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST)) + if((has_border & diagonal) == diagonal) + overlays |= get_flooring_overlay("[flooring.icon_base]-edge-[diagonal]", "[flooring.icon_base]_edges", diagonal) + if((has_border & diagonal) == 0 && (flooring.flags & TURF_HAS_CORNERS)) + var/turf/simulated/floor/T = get_step(src, diagonal) + if(!(istype(T) && T.flooring && T.flooring.name == flooring.name)) + overlays |= get_flooring_overlay("[flooring.icon_base]-corner-[diagonal]", "[flooring.icon_base]_corners", diagonal) + + if(flooring.can_paint && decals && decals.len) + overlays |= decals + + else if(decals && decals.len) + for(var/image/I in decals) + overlays |= I + + if(is_plating() && !(isnull(broken) && isnull(burnt))) //temp, todo + icon = 'icons/turf/flooring/plating.dmi' + icon_state = "dmg[rand(1,4)]" + else if(flooring) + if(!isnull(broken) && (flooring.flags & TURF_CAN_BREAK)) + overlays |= get_damage_overlay("broken[broken]", BLEND_MULTIPLY) + if(!isnull(burnt) && (flooring.flags & TURF_CAN_BURN)) + overlays |= get_damage_overlay("burned[burnt]") + + if(update_neighbors) + for(var/turf/simulated/floor/F in orange(src, 1)) + F.update_icon() + +/turf/simulated/floor/proc/get_flooring_overlay(var/cache_key, var/icon_base, var/icon_dir = 0) + if(!flooring_cache[cache_key]) + var/image/I = image(icon = flooring.icon, icon_state = icon_base, dir = icon_dir) + flooring_cache[cache_key] = I + return flooring_cache[cache_key] + +/turf/simulated/floor/proc/get_damage_overlay(var/cache_key, var/blend) + if(!flooring_cache[cache_key]) + var/image/I = image(icon = 'icons/turf/flooring/damage.dmi', icon_state = cache_key) + if(blend) + I.blend_mode = blend + flooring_cache[cache_key] = I + return flooring_cache[cache_key] \ No newline at end of file diff --git a/code/game/turfs/simulated/floor_static.dm b/code/game/turfs/simulated/floor_static.dm new file mode 100644 index 00000000..3fc9849e --- /dev/null +++ b/code/game/turfs/simulated/floor_static.dm @@ -0,0 +1,53 @@ +// This type of flooring cannot be altered short of being destroyed and rebuilt. +// Use this to bypass the flooring system entirely ie. event areas, holodeck, etc. + +/turf/simulated/floor/fixed + name = "floor" + icon = 'icons/turf/flooring/tiles.dmi' + icon_state = "steel" + initial_flooring = null + +/turf/simulated/floor/fixed/attackby(var/obj/item/C, var/mob/user) + if(istype(C, /obj/item/stack) && !isCoil(C)) + return + return ..() + +/turf/simulated/floor/fixed/update_icon() + return + +/turf/simulated/floor/fixed/is_plating() + return 0 + +/turf/simulated/floor/fixed/set_flooring() + return + +/turf/simulated/floor/fixed/alium + name = "alien plating" + desc = "This obviously wasn't made for your feet." + icon = 'icons/turf/flooring/alium.dmi' + icon_state = "jaggy" + +/turf/simulated/floor/fixed/alium/attackby(var/obj/item/C, var/mob/user) + if(isCrowbar(C)) + to_chat(user, "There aren't any openings big enough to pry it away...") + return + return ..() + +/turf/simulated/floor/fixed/alium/New() + ..() + var/material/A = get_material_by_name("alien alloy") + if(!A) + return + color = A.icon_colour + icon_state = "[A.icon_base][(x*y) % 7]" + +/turf/simulated/floor/fixed/alium/airless + initial_gas = null + temperature = TCMB + +/turf/simulated/floor/fixed/alium/ex_act(severity) + var/material/A = get_material_by_name("alien alloy") + if(prob(A.explosion_resistance)) + return + if(severity == 1) + ChangeTurf(get_base_turf_by_area(src)) \ No newline at end of file diff --git a/code/game/turfs/simulated/footsteps.dm b/code/game/turfs/simulated/footsteps.dm new file mode 100644 index 00000000..d15dffcf --- /dev/null +++ b/code/game/turfs/simulated/footsteps.dm @@ -0,0 +1,179 @@ +#define FOOTSTEP_CARPET "carpet" +#define FOOTSTEP_TILES "tiles" +#define FOOTSTEP_PLATING "plating" +#define FOOTSTEP_WOOD "wood" +#define FOOTSTEP_ASTEROID "asteroid" +#define FOOTSTEP_DIRT "dirt" +#define FOOTSTEP_GRASS "grass" +#define FOOTSTEP_WATER "water" +#define FOOTSTEP_BLANK "blank" +#define FOOTSTEP_REINFPLATING "reinforcedplating" +#define FOOTSTEP_SNOW "snow" +#define FOOTSTEP_MUD "mud" + +/turf/simulated/floor/var/global/list/footstep_sounds = list( + FOOTSTEP_WOOD = list( + 'sound/effects/footstep/wood1.ogg', + 'sound/effects/footstep/wood2.ogg', + 'sound/effects/footstep/wood3.ogg', + 'sound/effects/footstep/wood4.ogg', + 'sound/effects/footstep/wood5.ogg'), + FOOTSTEP_TILES = list( + 'sound/effects/footstep/floor1.ogg', + 'sound/effects/footstep/floor2.ogg', + 'sound/effects/footstep/floor3.ogg', + 'sound/effects/footstep/floor4.ogg'), + FOOTSTEP_PLATING = list( + 'sound/effects/footstep/plating1.ogg', + 'sound/effects/footstep/plating2.ogg', + 'sound/effects/footstep/plating3.ogg', + 'sound/effects/footstep/plating4.ogg', + 'sound/effects/footstep/plating5.ogg'), + FOOTSTEP_CARPET = list( + 'sound/effects/footstep/carpet1.ogg', + 'sound/effects/footstep/carpet2.ogg', + 'sound/effects/footstep/carpet3.ogg', + 'sound/effects/footstep/carpet4.ogg', + 'sound/effects/footstep/carpet5.ogg'), + FOOTSTEP_ASTEROID = list( + 'sound/effects/footstep/asteroid1.ogg', + 'sound/effects/footstep/asteroid2.ogg', + 'sound/effects/footstep/asteroid3.ogg', + 'sound/effects/footstep/asteroid4.ogg', + 'sound/effects/footstep/asteroid5.ogg'), + FOOTSTEP_DIRT = list( + 'sound/effects/footstep/dirt1.ogg', + 'sound/effects/footstep/dirt2.ogg', + 'sound/effects/footstep/dirt3.ogg'), + + FOOTSTEP_GRASS = list( + 'sound/effects/footstep/grass1.ogg', + 'sound/effects/footstep/grass2.ogg', + 'sound/effects/footstep/grass3.ogg', + 'sound/effects/footstep/grass4.ogg'), + FOOTSTEP_WATER = list( + 'sound/effects/footstep/water_max1.ogg', + 'sound/effects/footstep/water_max2.ogg'), + FOOTSTEP_SNOW = list( + 'sound/effects/footstep/snowstep1.ogg', + 'sound/effects/footstep/snowstep2.ogg', + 'sound/effects/footstep/snowstep3.ogg', + 'sound/effects/footstep/snowstep1.ogg'), + FOOTSTEP_MUD = list( + 'sound/effects/footstep/mud1.ogg', + 'sound/effects/footstep/mud2.ogg', + 'sound/effects/footstep/mud3.ogg', + 'sound/effects/footstep/mud4.ogg', + 'sound/effects/footstep/mud5.ogg'), + FOOTSTEP_BLANK = list( + 'sound/effects/footstep/blank.ogg'), + FOOTSTEP_REINFPLATING = list( + 'sound/effects/footstep/reinfplating1.ogg', + 'sound/effects/footstep/reinfplating2.ogg', + 'sound/effects/footstep/reinfplating3.ogg', + 'sound/effects/footstep/reinfplating4.ogg', + 'sound/effects/footstep/reinfplating5.ogg', + 'sound/effects/footstep/reinfplating6.ogg') +) + +/decl/flooring/var/footstep_type +/decl/flooring/footstep_type = FOOTSTEP_BLANK +/decl/flooring/carpet/footstep_type = FOOTSTEP_CARPET +/decl/flooring/tiling/footstep_type = FOOTSTEP_TILES +/decl/flooring/linoleum/footstep_type = FOOTSTEP_TILES +/decl/flooring/wood/footstep_type = FOOTSTEP_WOOD +/decl/flooring/reinforced/footstep_type = FOOTSTEP_PLATING + +/turf/simulated/floor/proc/get_footstep_sound() + if(is_plating()) + return safepick(footstep_sounds[FOOTSTEP_PLATING]) + else if(!flooring || !flooring.footstep_type) + return safepick(footstep_sounds[FOOTSTEP_BLANK]) + else + return safepick(footstep_sounds[flooring.footstep_type]) + +/turf/simulated/floor/asteroid/get_footstep_sound() + return safepick(footstep_sounds[FOOTSTEP_ASTEROID]) + +/turf/simulated/floor/exoplanet/get_footstep_sound() + return safepick(footstep_sounds[FOOTSTEP_CARPET]) + +/turf/simulated/floor/exoplanet/grass/get_footstep_sound() + return safepick(footstep_sounds[FOOTSTEP_GRASS]) + +/turf/simulated/floor/exoplanet/water/shallow/get_footstep_sound() + return safepick(footstep_sounds[FOOTSTEP_WATER]) + +/turf/simulated/floor/fixed/get_footstep_sound() + return safepick(footstep_sounds[FOOTSTEP_PLATING]) + +/turf/simulated/floor/plating/reinforced/get_footstep_sound() + return safepick(footstep_sounds[FOOTSTEP_REINFPLATING]) + +/turf/simulated/floor/dirty/get_footstep_sound() + return safepick(footstep_sounds[FOOTSTEP_DIRT])//FOOTSTEP_SNOW]) + +/turf/simulated/floor/trench/get_footstep_sound() + return safepick(footstep_sounds[FOOTSTEP_MUD]) + + + +/turf/simulated/floor/Entered(var/mob/living/carbon/human/H) + ..() + if(istype(H)) + H.handle_footsteps() + H.step_count++ + +/datum/species/var/silent_steps +/datum/species/nabber/silent_steps = 1 + +/mob/living/carbon/human/var/step_count + +/mob/living/carbon/human/proc/handle_footsteps() + var/turf/simulated/floor/T = get_turf(src) + if(!istype(T)) + return + + if(buckled || lying || throwing) + return //people flying, lying down or sitting do not step + + if(m_intent == "run") + if(step_count % 2) //every other turf makes a sound + return + + if(species.silent_steps) + return //species is silent + + if(!has_gravity(src)) + if(step_count % 3) // don't need to step as often when you hop around + return + + if(!has_organ(BP_L_FOOT) && !has_organ(BP_R_FOOT)) + return //no feet no footsteps + + var/S = T.get_footstep_sound() + if(S) + var/range = -(world.view - 2) + var/armor_range = -(world.view - 2) + var/volume = 50 + if(m_intent == "walk") + volume -= 45 + range -= 0.333 + if(!shoes) + volume -= 60 + range -= 0.333 + if(istype(wear_suit,/obj/item/clothing/suit/armor)) + playsound(T, "armorwalk", 50, 1, armor_range) + + playsound(T, S, volume, 1, range) + + var/list/clients_to_show = list() + + for(var/mob/living/carbon/human/H in view()) + clients_to_show += H.get_client() + if(!length(clients_to_show)) + return + clients_to_show -= src.get_client() + var/image/I = image('icons/effects/footstepsound.dmi', loc = T, icon_state = "default") + I.plane = FOOTSTEP_ALERT_PLANE + flick_overlay(I, clients_to_show, 4) diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm new file mode 100644 index 00000000..bea49d34 --- /dev/null +++ b/code/game/turfs/simulated/wall_attacks.dm @@ -0,0 +1,353 @@ +//Interactions +/turf/simulated/wall/proc/toggle_open(var/mob/user) + + if(can_open == WALL_OPENING) + return + + radiation_repository.resistance_cache.Remove(src) + + if(density) + can_open = WALL_OPENING + //flick("[material.icon_base]fwall_opening", src) + sleep(15) + set_density(0) + set_opacity(0) + blocks_air = ZONE_BLOCKED + update_icon() + update_air() + set_light(0) + src.blocks_air = 0 + set_opacity(0) + for(var/turf/simulated/turf in loc) + SSair.mark_for_update(turf) + else + can_open = WALL_OPENING + //flick("[material.icon_base]fwall_closing", src) + set_density(1) + set_opacity(1) + blocks_air = AIR_BLOCKED + update_icon() + update_air() + sleep(15) + set_light(1) + src.blocks_air = 1 + set_opacity(1) + for(var/turf/simulated/turf in loc) + SSair.mark_for_update(turf) + + can_open = WALL_CAN_OPEN + update_icon() + +/turf/simulated/wall/proc/update_air() + if(!SSair) + return + + for(var/turf/simulated/turf in loc) + update_thermal(turf) + SSair.mark_for_update(turf) + + +/turf/simulated/wall/proc/update_thermal(var/turf/simulated/source) + if(istype(source)) + if(density && opacity) + source.thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT + else + source.thermal_conductivity = initial(source.thermal_conductivity) + + + +/turf/simulated/wall/proc/fail_smash(var/mob/user) + to_chat(user, "You smash against \the [src]!") + take_damage(rand(25,75)) + +/turf/simulated/wall/proc/success_smash(var/mob/user) + to_chat(user, "You smash through \the [src]!") + spawn(1) + dismantle_wall(1) + +/turf/simulated/wall/proc/try_touch(var/mob/user, var/rotting) + + if(rotting) + if(is_reinf()) + to_chat(user, "\The [src.name] feels porous and crumbly.") + else + to_chat(user, "\The [src.name] crumbles under your touch!") + dismantle_wall() + return 1 + + if(..()) return 1 + + if(can_open) + toggle_open(user) + return 0 + + +/turf/simulated/wall/attack_hand(var/mob/user) + + add_fingerprint(user) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + var/rotting = (locate(/obj/effect/overlay/wallrot) in src) + if (HULK in user.mutations) + if (rotting || !prob(60)) + success_smash(user) + else + fail_smash(user) + return 1 + + try_touch(user, rotting) + +/turf/simulated/wall/attack_generic(var/mob/user, var/damage, var/attack_message, var/wallbreaker) + + if(!istype(user)) + return + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + var/rotting = (locate(/obj/effect/overlay/wallrot) in src) + if(!damage || !wallbreaker) + try_touch(user, rotting) + return + + if(rotting) + return success_smash(user) + + if(is_reinf()) + if(damage >= max(60,80)) + return success_smash(user) + else if(wallbreaker == 2 || damage >= 60) + return success_smash(user) + return fail_smash(user) + +/turf/simulated/wall/attackby(obj/item/weapon/W as obj, mob/user as mob) + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if (!user.IsAdvancedToolUser()) + to_chat(user, "You don't have the dexterity to do this!") + return + + //get the user's location + if(!istype(user.loc, /turf)) return //can't do this stuff whilst inside objects and such + if(locate(/obj/effect/overlay/wallrot) in src) + if(isWelder(W)) + var/obj/item/weapon/weldingtool/WT = W + if( WT.remove_fuel(0,user) ) + to_chat(user, "You burn away the fungi with \the [WT].") + playsound(src, 'sound/items/Welder.ogg', 10, 1) + for(var/obj/effect/overlay/wallrot/WR in src) + qdel(WR) + return + else if(!is_sharp(W) && W.force >= 10 || W.force >= 20) + to_chat(user, "\The [src] crumbles away under the force of your [W.name].") + src.dismantle_wall(1) + return + + //THERMITE related stuff. Calls src.thermitemelt() which handles melting simulated walls and the relevant effects + if(thermite) + if(isWelder(W)) + var/obj/item/weapon/weldingtool/WT = W + if( WT.remove_fuel(0,user) ) + thermitemelt(user) + return + + else if(istype(W, /obj/item/weapon/gun/energy/plasmacutter)) + thermitemelt(user) + return + + else if( istype(W, /obj/item/weapon/melee/energy/blade) ) + var/obj/item/weapon/melee/energy/blade/EB = W + + EB.spark_system.start() + to_chat(user, "You slash \the [src] with \the [EB]; the thermite ignites!") + playsound(src, "sparks", 50, 1) + playsound(src, 'sound/weapons/blade1.ogg', 50, 1) + + thermitemelt(user) + return + + var/turf/T = user.loc //get user's location for delay checks + + if(damage && istype(W, /obj/item/weapon/weldingtool)) + + var/obj/item/weapon/weldingtool/WT = W + + if(!WT.isOn()) + return + + if(WT.remove_fuel(0,user)) + to_chat(user, "You start repairing the damage to [src].") + playsound(src, 'sound/items/Welder.ogg', 100, 1) + if(do_after(user, max(5, damage / 5), src) && WT && WT.isOn()) + to_chat(user, "You finish repairing the damage to [src].") + take_damage(-damage) + else + to_chat(user, "You need more welding fuel to complete this task.") + return + return + + // Basic dismantling. + if(isnull(construction_stage) || !is_reinf()) + + var/cut_delay = 60 + var/dismantle_verb + var/dismantle_sound + + if(istype(W,/obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + if(!WT.isOn()) + return + if(!WT.remove_fuel(0,user)) + to_chat(user, "You need more welding fuel to complete this task.") + return + dismantle_verb = "cutting" + dismantle_sound = 'sound/items/Welder.ogg' + cut_delay *= 0.7 + else if(istype(W,/obj/item/weapon/melee/energy/blade)) + dismantle_sound = "sparks" + dismantle_verb = "slicing" + cut_delay *= 0.5 + //else if(istype(W,/obj/item/weapon/pickaxe)) + // var/obj/item/weapon/pickaxe/P = W + // dismantle_verb = P.drill_verb + // dismantle_sound = P.drill_sound + // cut_delay -= P.digspeed + + if(dismantle_verb) + + to_chat(user, "You begin [dismantle_verb] through the outer plating.") + if(dismantle_sound) + playsound(src, dismantle_sound, 100, 1) + + if(cut_delay<0) + cut_delay = 0 + + if(!do_after(user,cut_delay,src)) + return + + to_chat(user, "You remove the outer plating.") + dismantle_wall() + user.visible_message("\The [src] was torn open by [user]!") + return + + //Reinforced dismantling. + else + switch(construction_stage) + if(6) + if(isWirecutter(W)) + playsound(src, 'sound/items/Wirecutter.ogg', 100, 1) + construction_stage = 5 + new /obj/item/stack/rods( src ) + to_chat(user, "You cut the outer grille.") + update_icon() + return + if(5) + if(isScrewdriver(W)) + to_chat(user, "You begin removing the support lines.") + playsound(src, 'sound/items/Screwdriver.ogg', 100, 1) + if(!do_after(user,40,src) || !istype(src, /turf/simulated/wall) || construction_stage != 5) + return + construction_stage = 4 + update_icon() + to_chat(user, "You remove the support lines.") + return + else if( istype(W, /obj/item/stack/rods) ) + var/obj/item/stack/O = W + if(O.get_amount()>0) + O.use(1) + construction_stage = 6 + update_icon() + to_chat(user, "You replace the outer grille.") + return + if(4) + var/cut_cover + if(istype(W,/obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + if(!WT.isOn()) + return + if(WT.remove_fuel(0,user)) + cut_cover=1 + else + to_chat(user, "You need more welding fuel to complete this task.") + return + else if (istype(W, /obj/item/weapon/gun/energy/plasmacutter)) + cut_cover = 1 + if(cut_cover) + to_chat(user, "You begin slicing through the metal cover.") + playsound(src, 'sound/items/Welder.ogg', 100, 1) + if(!do_after(user, 60, src) || !istype(src, /turf/simulated/wall) || construction_stage != 4) + return + construction_stage = 3 + update_icon() + to_chat(user, "You press firmly on the cover, dislodging it.") + return + if(3) + if(isCrowbar(W)) + to_chat(user, "You struggle to pry off the cover.") + playsound(src, 'sound/items/Crowbar.ogg', 100, 1) + if(!do_after(user,100,src) || !istype(src, /turf/simulated/wall) || construction_stage != 3) + return + construction_stage = 2 + update_icon() + to_chat(user, "You pry off the cover.") + return + if(2) + if(isWrench(W)) + to_chat(user, "You start loosening the anchoring bolts which secure the support rods to their frame.") + playsound(src, 'sound/items/Ratchet.ogg', 100, 1) + if(!do_after(user,40,src) || !istype(src, /turf/simulated/wall) || construction_stage != 2) + return + construction_stage = 1 + update_icon() + to_chat(user, "You remove the bolts anchoring the support rods.") + return + if(1) + var/cut_cover + if(istype(W, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + if( WT.remove_fuel(0,user) ) + cut_cover=1 + else + to_chat(user, "You need more welding fuel to complete this task.") + return + else if(istype(W, /obj/item/weapon/gun/energy/plasmacutter)) + cut_cover = 1 + if(cut_cover) + to_chat(user, "You begin slicing through the support rods.") + playsound(src, 'sound/items/Welder.ogg', 100, 1) + if(!do_after(user,70,src) || !istype(src, /turf/simulated/wall) || construction_stage != 1) + return + construction_stage = 0 + update_icon() + new /obj/item/stack/rods(src) + to_chat(user, "The support rods drop out as you cut them loose from the frame.") + return + if(0) + if(isCrowbar(W)) + to_chat(user, "You struggle to pry off the outer sheath.") + playsound(src, 'sound/items/Crowbar.ogg', 100, 1) + if(!do_after(user,100,src) || !istype(src, /turf/simulated/wall) || !user || !W || !T ) return + if(user.loc == T && user.get_active_hand() == W ) + to_chat(user, "You pry off the outer sheath.") + dismantle_wall() + return + + if(istype(W,/obj/item/frame)) + var/obj/item/frame/F = W + F.try_build(src) + return + + else if(!istype(W,/obj/item/weapon/rcd) && !istype(W, /obj/item/weapon/reagent_containers)) + if(!W.force) + return attack_hand(user) + var/dam_threshhold = integrity + if(is_reinf()) + dam_threshhold = ceil(max(dam_threshhold,integrity)/2) + var/dam_prob = min(100,80*1.5) + if(dam_prob < 100 && W.force > (dam_threshhold/10)) + playsound(src, hitsound, 80, 1) + if(!prob(dam_prob)) + visible_message("\The [user] attacks \the [src] with \the [W] and it [pick("died","crashed")]!") + dismantle_wall(1) + else + visible_message("\The [user] attacks \the [src] with \the [W]!") + else + visible_message("\The [user] attacks \the [src] with \the [W], but it bounces off!") + return diff --git a/code/game/turfs/simulated/wall_icon.dm b/code/game/turfs/simulated/wall_icon.dm new file mode 100644 index 00000000..b7b51052 --- /dev/null +++ b/code/game/turfs/simulated/wall_icon.dm @@ -0,0 +1,42 @@ +/atom/proc/relativewall_neighbours() + for(var/turf/simulated/W in range(src,1)) + if(W.can_smooth) + W.relativewall() + return + +/atom/proc/relativewall() + var/junction = 0 + if(!istype(src,/turf/simulated/shuttle/wall)) + for(var/turf/simulated/W in orange(src,1)) + if(!W.can_smooth) + continue + if(abs(src.x-W.x)-abs(src.y-W.y)) + junction |= get_dir(src,W) + + +//We use this so we can smooth floor +/turf/simulated + var/can_smooth = FALSE + +/turf/simulated/wall/Del() + + var/temploc = src.loc + + spawn(10) + for(var/turf/simulated/wall/W in range(temploc,1)) + W.relativewall() + + //for(var/obj/structure/falsewall/W in range(temploc,1)) will do it later + // W.relativewall() + ..() + +/turf/simulated/wall/relativewall() + var/junction = 0 + + for(var/turf/simulated/wall/W in orange(src,1)) + if(abs(src.x-W.x)-abs(src.y-W.y)) + if(src.mineral == W.mineral) + junction |= get_dir(src,W) + //var/turf/simulated/wall/wall = src + icon_state = "[walltype][junction]" + return diff --git a/code/game/turfs/simulated/wall_shuttle.dm b/code/game/turfs/simulated/wall_shuttle.dm new file mode 100644 index 00000000..062c73f8 --- /dev/null +++ b/code/game/turfs/simulated/wall_shuttle.dm @@ -0,0 +1,92 @@ +/turf/simulated/shuttle + name = "shuttle" + icon = 'icons/turf/shuttle.dmi' + thermal_conductivity = 0.05 + heat_capacity = 0 + +/turf/simulated/shuttle/wall + name = "wall" + icon_state = "wall1" + opacity = 1 + density = 1 + blocks_air = 1 + +/turf/simulated/shuttle/wall/alien + name = "alien wall" + icon_state = "bog0" + +/turf/simulated/shuttle/wall/corner + var/corner_overlay_state = "diagonalWall" + var/image/corner_overlay + +/turf/simulated/shuttle/wall/corner/New() + ..() + reset_base_appearance() + reset_overlay() + +//Grabs the base turf type from our area and copies its appearance +/turf/simulated/shuttle/wall/corner/proc/reset_base_appearance() + var/turf/base_type = get_base_turf_by_area(src) + if(!base_type) return + + icon = initial(base_type.icon) + icon_state = initial(base_type.icon_state) + +/turf/simulated/shuttle/wall/corner/proc/reset_overlay() + if(corner_overlay) + overlays -= corner_overlay + else + corner_overlay = image(icon = 'icons/turf/shuttle.dmi', icon_state = corner_overlay_state, dir = src.dir) + corner_overlay.plane = plane + corner_overlay.layer = layer + overlays += corner_overlay + +//Predefined Shuttle Corners +/turf/simulated/shuttle/wall/corner/smoothwhite + icon_state = "corner_white" //for mapping preview + corner_overlay_state = "corner_white" +/turf/simulated/shuttle/wall/corner/smoothwhite/ne + dir = NORTH|EAST +/turf/simulated/shuttle/wall/corner/smoothwhite/nw + dir = NORTH|WEST +/turf/simulated/shuttle/wall/corner/smoothwhite/se + dir = SOUTH|EAST +/turf/simulated/shuttle/wall/corner/smoothwhite/sw + dir = SOUTH|WEST + +/turf/simulated/shuttle/wall/corner/blockwhite + icon_state = "corner_white_block" + corner_overlay_state = "corner_white_block" +/turf/simulated/shuttle/wall/corner/blockwhite/ne + dir = NORTH|EAST +/turf/simulated/shuttle/wall/corner/blockwhite/nw + dir = NORTH|WEST +/turf/simulated/shuttle/wall/corner/blockwhite/se + dir = SOUTH|EAST +/turf/simulated/shuttle/wall/corner/blockwhite/sw + dir = SOUTH|WEST + +/turf/simulated/shuttle/wall/corner/dark + icon_state = "corner_dark" + corner_overlay_state = "corner_dark" +/turf/simulated/shuttle/wall/corner/dark/ne + dir = NORTH|EAST +/turf/simulated/shuttle/wall/corner/dark/nw + dir = NORTH|WEST +/turf/simulated/shuttle/wall/corner/dark/se + dir = SOUTH|EAST +/turf/simulated/shuttle/wall/corner/dark/sw + dir = SOUTH|WEST + + +/turf/simulated/shuttle/wall/corner/alien + icon_state = "corner_alien" + corner_overlay_state = "corner_alien" +/turf/simulated/shuttle/wall/corner/alien/ne + dir = NORTH|EAST +/turf/simulated/shuttle/wall/corner/alien/nw + dir = NORTH|WEST +/turf/simulated/shuttle/wall/corner/alien/se + dir = SOUTH|EAST +/turf/simulated/shuttle/wall/corner/alien/sw + dir = SOUTH|WEST \ No newline at end of file diff --git a/code/game/turfs/simulated/wall_types.dm b/code/game/turfs/simulated/wall_types.dm new file mode 100644 index 00000000..27536d0f --- /dev/null +++ b/code/game/turfs/simulated/wall_types.dm @@ -0,0 +1,114 @@ +/turf/simulated/wall/r_wall + icon_state = "rgeneric" + walltype = "rwall" + icon_state = "rwall0" + //mineral = "reinforced_m" +/turf/simulated/wall/r_wall/New(var/newloc) + ..(newloc) //3strong +/turf/simulated/wall/ocp_wall + icon_state = "rgeneric" + +/turf/simulated/wall/concrete + name = "concrete wall" + desc = "An old concrete wall. For when metal just isn't good enough." + icon_state = "concrete0" + walltype = "concrete" + mineral = "rust" + plane = ABOVE_HUMAN_PLANE + integrity = 500 //Tough bois + +/turf/simulated/wall/rust + desc = "An old rusty wall. It's definitely seen better days." + icon_state = "rust0" + walltype = "rust" + mineral = "rust" + +/turf/simulated/wall/r_wall/containment + desc = "A strong containment wall. Used to \"contain\" things" + icon_state = "containment0" + walltype = "containment" + mineral = "containment" + +/turf/simulated/wall/ocp_wall/New(var/newloc) + ..(newloc) + + + + +/turf/simulated/wall/cult + icon_state = "cult" + walltype = "cult" + +/turf/simulated/wall/cult/New(var/newloc, var/reinforce = 0) + ..(newloc,) + +/turf/simulated/wall/cult/reinf/New(var/newloc) + ..(newloc) + +/turf/simulated/wall/cult/dismantle_wall() + cult.remove_cultiness(CULTINESS_PER_TURF) + ..() + +/turf/unsimulated/wall/cult + name = "cult wall" + desc = "Hideous images dance beneath the surface." + icon = 'icons/turf/wall_masks.dmi' + icon_state = "cult" +/*GAVNO!!!/ +/turf/simulated/wall/iron/New(var/newloc) + ..(newloc) +/turf/simulated/wall/uranium/New(var/newloc) + ..(newloc) +/turf/simulated/wall/diamond/New(var/newloc) + ..(newloc) +/turf/simulated/wall/gold/New(var/newloc) + ..(newloc) +/turf/simulated/wall/silver/New(var/newloc) + ..(newloc) +/turf/simulated/wall/phoron/New(var/newloc) + ..(newloc) +/turf/simulated/wall/sandstone/New(var/newloc) + ..(newloc) +/turf/simulated/wall/wood/New(var/newloc) + ..(newloc) +/turf/simulated/wall/ironphoron/New(var/newloc) + ..(newloc) +/turf/simulated/wall/golddiamond/New(var/newloc) + ..(newloc) +/turf/simulated/wall/silvergold/New(var/newloc) + ..(newloc) +/turf/simulated/wall/sandstonediamond/New(var/newloc) + ..(newloc) +*/ + +// Kind of wondering if this is going to bite me in the butt. +/turf/simulated/wall/voxshuttle/New(var/newloc) + ..(newloc) +/turf/simulated/wall/voxshuttle/attackby() + return +/turf/simulated/wall/titanium/New(var/newloc) + ..(newloc) + +/turf/simulated/wall/alium + icon_state = "jaggy" + floor_type = /turf/simulated/floor/fixed/alium + +/turf/simulated/wall/alium/New(var/newloc) + ..(newloc) + +/turf/simulated/wall/alium/ex_act(severity) + if(prob(explosion_resistance)) + return + ..() + +/turf/simulated/wall/stone + icon_state = "stone0" + walltype = "stone" + +/turf/simulated/wall/wood + icon_state = "wood0" + walltype = "wood" + +/turf/simulated/wall/scrap + icon_state = "scrap0" + walltype = "scrap" \ No newline at end of file diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm new file mode 100644 index 00000000..cd7df0d0 --- /dev/null +++ b/code/game/turfs/simulated/walls.dm @@ -0,0 +1,299 @@ +/turf/simulated/wall + name = "wall" + desc = "A huge chunk of metal used to seperate rooms." + icon = 'icons/turf/wall.dmi' + icon_state = "metal0" + plane = WALL_PLANE + opacity = 1 + density = 1 + blocks_air = 1 + var/walltype = "metal" + thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT + heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m plasteel wall + can_smooth = TRUE + var/mineral = "metal" + var/damage = 0 + var/damage_overlay = 0 + var/global/damage_overlays[16] + var/active + var/can_open = 0 + var/last_state + var/integrity = 150 + var/construction_stage + var/hitsound = 'sound/weapons/Genhit.ogg' + var/floor_type = /turf/simulated/floor/plating //turf it leaves after destruction + + +/turf/simulated/wall/New(var/newloc) + ..(newloc) + icon_state = "blank" + relativewall_neighbours() + processing_turfs |= src + generate_splines() + +/turf/simulated/wall/Destroy() + processing_turfs -= src + dismantle_wall(null,null,1) + . = ..() + +// Walls always hide the stuff below them. +/turf/simulated/wall/levelupdate() + for(var/obj/O in src) + O.hide(1) + +/turf/simulated/wall/protects_atom(var/atom/A) + var/obj/O = A + return (istype(O) && O.hides_under_flooring()) || ..() + + +/turf/simulated/wall/proc/return_material(material_type, times) + if(!material_type||!times) + return + var/obj/structure/girder/newgirder = null + switch(material_type) + if("metal") + newgirder = new /obj/structure/girder/reinforced(src) + for(var/i=1,i= 20 || istype(Proj, /obj/item/projectile/beam/practice)) + BM.icon_state = "dent"//"scorch" + BM.set_dir(pick(NORTH,SOUTH,EAST,WEST)) // random scorch design + else + BM.icon_state = "scorch"//"light_scorch" + else + + // Bullets are hard. They make dents! + BM.icon_state = "dent" + + + take_damage(damage) + + return + +/turf/simulated/wall/hitby(AM as mob|obj, var/speed=THROWFORCE_SPEED_DIVISOR) + ..() + if(ismob(AM)) + return + + var/tforce = AM:throwforce * (speed/THROWFORCE_SPEED_DIVISOR) + if (tforce < 15) + return + + take_damage(tforce) + +/turf/simulated/wall/proc/clear_plants() + for(var/obj/effect/overlay/wallrot/WR in src) + qdel(WR) + for(var/obj/effect/vine/plant in range(src, 1)) + if(!plant.floor) //shrooms drop to the floor + plant.floor = 1 + plant.update_icon() + plant.pixel_x = 0 + plant.pixel_y = 0 + plant.update_neighbors() + +/turf/simulated/wall/proc/clear_bulletholes() + for(var/obj/effect/overlay/bmark/BM in src) + qdel(BM) + +/turf/simulated/wall/ChangeTurf(var/newtype) + clear_plants() + clear_bulletholes() + return ..(newtype) + +//Appearance +/turf/simulated/wall/examine(mob/user) + . = ..(user) + + if(!damage) + to_chat(user, "It looks fully intact.") + else + var/dam = damage/150 + if(is_reinf()) + dam = damage/400 + if(dam <= 0.3) + to_chat(user, "It looks slightly damaged.") + else if(dam <= 0.6) + to_chat(user, "It looks moderately damaged.") + else + to_chat(user, "It looks heavily damaged.") + + if(locate(/obj/effect/overlay/wallrot) in src) + to_chat(user, "There is fungus growing on [src].") + +//Damage + +/turf/simulated/wall/melt() + + if(!can_melt()) + return + + src.ChangeTurf(/turf/simulated/floor/plating) + + var/turf/simulated/floor/F = src + if(!F) + return + F.burn_tile() + F.icon_state = "wall_thermite" + visible_message("\The [src] spontaneously combusts!.") //!!OH SHIT!! + return + +/turf/simulated/wall/proc/take_damage(dam) + if(dam) + damage = max(0, damage + dam) + update_damage() + return + + +/turf/simulated/wall/proc/update_damage() + var/cap = integrity + if(is_reinf()) + cap += 130 + + if(locate(/obj/effect/overlay/wallrot) in src) + cap = cap / 10 + + if(damage >= cap) + dismantle_wall() + else + update_icon() + + return + + +/turf/simulated/wall/adjacent_fire_act(turf/simulated/floor/adj_turf, datum/gas_mixture/adj_air, adj_temp, adj_volume) + if(adj_temp > 1200) + take_damage(log(RAND_F(0.9, 1.1) * (adj_temp - 1200))) + + return ..() + +/turf/simulated/wall/proc/dismantle_wall(var/devastated, var/explode, var/no_product) + + playsound(src, 'sound/items/Welder.ogg', 100, 1) + return_material(mineral, rand(1,2)) + for(var/obj/O in src.contents) //Eject contents! + if(istype(O,/obj/structure/sign/poster)) + var/obj/structure/sign/poster/P = O + P.roll_and_drop(src) + else + O.forceMove(src) + + clear_plants() + clear_bulletholes() + + ChangeTurf(floor_type) + +/turf/simulated/wall/ex_act(severity) + switch(severity) + if(1.0) + src.ChangeTurf(get_base_turf(src.z)) + return + if(2.0) + if(prob(75)) + take_damage(rand(150, 250)) + else + dismantle_wall(1,1) + if(3.0) + take_damage(rand(0, 250)) + else + return + +// Wall-rot effect, a nasty fungus that destroys walls. +/turf/simulated/wall/proc/rot() + if(locate(/obj/effect/overlay/wallrot) in src) + return + var/number_rots = rand(2,3) + for(var/i=0, iThe thermite starts melting through the wall.
            ") + + spawn(100) + if(O) + qdel(O) + return + +/*/turf/simulated/wall/proc/radiate() + var/total_radiation = material.radioactivity + (reinf_material ? reinf_material.radioactivity / 2 : 0) + if(!total_radiation) + return + + radiation_repository.radiate(src, total_radiation) + return total_radiation +*/ +/turf/simulated/wall/proc/burn(temperature) + new /obj/structure/girder(src) + src.ChangeTurf(/turf/simulated/floor) + for(var/turf/simulated/wall/W in range(3,src)) + W.burn((temperature/4)) + for(var/obj/machinery/door/airlock/phoron/D in range(3,src)) + D.ignite(temperature/4) diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm new file mode 100644 index 00000000..b0e6efc6 --- /dev/null +++ b/code/game/turfs/space/space.dm @@ -0,0 +1,228 @@ +/turf/space + plane = SPACE_PLANE + icon = 'icons/turf/space.dmi' + + name = "\proper space" + icon_state = "fake" + dynamic_lighting = 0 + temperature = T20C + thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT + var/static/list/dust_cache + +/turf/space/New() + icon_state = "white" + +/turf/space/proc/build_dust_cache() + LAZYINITLIST(dust_cache) + for (var/i in 0 to 25) + var/image/im = image('icons/turf/space_dust.dmi',"[i]") + im.plane = DUST_PLANE + im.alpha = 80 + im.blend_mode = BLEND_ADD + dust_cache["[i]"] = im + + +/turf/space/Initialize() + . = ..() + update_starlight() + if (!dust_cache) + build_dust_cache() + overlays += dust_cache["[((x + y) ^ ~(x * y) + z) % 25]"] + + if(!HasBelow(z)) + return + var/turf/below = GetBelow(src) + + if(istype(below, /turf/space)) + return + var/area/A = below.loc + + if(A.area_flags & AREA_FLAG_EXTERNAL) + return + + + return INITIALIZE_HINT_LATELOAD // oh no! we need to switch to being a different kind of turf! + +/turf/space/LateInitialize() + // We alter area type before the turf to ensure the turf-change-event-propagation is handled as expected. + if(GLOB.using_map.base_floor_area) + var/area/new_area = locate(GLOB.using_map.base_floor_area) || new GLOB.using_map.base_floor_area + new_area.contents.Add(src) + ChangeTurf(GLOB.using_map.base_floor_type) + +// override for space turfs, since they should never hide anything +/turf/space/levelupdate() + for(var/obj/O in src) + O.hide(0) + +/turf/space/is_solid_structure() + return locate(/obj/structure/lattice, src) //counts as solid structure if it has a lattice + +/turf/space/proc/update_starlight() + if(!config.starlight) + return + if(locate(/turf/simulated) in orange(src,1)) + set_light(config.starlight) + else + set_light(0) + +/turf/space/attackby(obj/item/C as obj, mob/user as mob) + + if (istype(C, /obj/item/stack/rods)) + var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) + if(L) + return L.attackby(C, user) + var/obj/item/stack/rods/R = C + if (R.use(1)) + to_chat(user, "Constructing support lattice ...") + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + ReplaceWithLattice() + return + + if (istype(C, /obj/item/stack/tile/floor)) + var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) + if(L) + var/obj/item/stack/tile/floor/S = C + if (S.get_amount() < 1) + return + qdel(L) + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + S.use(1) + ChangeTurf(/turf/simulated/floor/airless) + return + else + to_chat(user, "The plating is going to need some support.") + return + + +// Ported from unstable r355 + +/turf/space/Entered(atom/movable/A as mob|obj) + ..() + if(A && A.loc == src && ticker && ticker.mode) + + // Okay, so let's make it so that people can travel z levels but not nuke disks! + // if(ticker.mode.name == "mercenary") return + if (A.x <= TRANSITIONEDGE || A.x >= (world.maxx - TRANSITIONEDGE + 1) || A.y <= TRANSITIONEDGE || A.y >= (world.maxy - TRANSITIONEDGE + 1)) + A.touch_map_edge() + +/turf/space/proc/Sandbox_Spacemove(atom/movable/A as mob|obj) + var/cur_x + var/cur_y + var/next_x + var/next_y + var/target_z + var/list/y_arr + + if(src.x <= 1) + if(istype(A, /obj/effect/meteor)) + qdel(A) + return + + var/list/cur_pos = src.get_global_map_pos() + if(!cur_pos) return + cur_x = cur_pos["x"] + cur_y = cur_pos["y"] + next_x = (--cur_x||GLOB.global_map.len) + y_arr = GLOB.global_map[next_x] + target_z = y_arr[cur_y] +/* + //debug + log_debug("Src.z = [src.z] in global map X = [cur_x], Y = [cur_y]") + log_debug("Target Z = [target_z]") + log_debug("Next X = [next_x]") + + //debug +*/ + if(target_z) + A.z = target_z + A.x = world.maxx - 2 + spawn (0) + if ((A && A.loc)) + A.loc.Entered(A) + else if (src.x >= world.maxx) + if(istype(A, /obj/effect/meteor)) + qdel(A) + return + + var/list/cur_pos = src.get_global_map_pos() + if(!cur_pos) return + cur_x = cur_pos["x"] + cur_y = cur_pos["y"] + next_x = (++cur_x > GLOB.global_map.len ? 1 : cur_x) + y_arr = GLOB.global_map[next_x] + target_z = y_arr[cur_y] +/* + //debug + log_debug("Src.z = [src.z] in global map X = [cur_x], Y = [cur_y]") + log_debug("Target Z = [target_z]") + log_debug("Next X = [next_x]") + + //debug +*/ + if(target_z) + A.z = target_z + A.x = 3 + spawn (0) + if ((A && A.loc)) + A.loc.Entered(A) + else if (src.y <= 1) + if(istype(A, /obj/effect/meteor)) + qdel(A) + return + var/list/cur_pos = src.get_global_map_pos() + if(!cur_pos) return + cur_x = cur_pos["x"] + cur_y = cur_pos["y"] + y_arr = GLOB.global_map[cur_x] + next_y = (--cur_y||y_arr.len) + target_z = y_arr[next_y] +/* + //debug + log_debug("Src.z = [src.z] in global map X = [cur_x], Y = [cur_y]") + log_debug("Next Y = [next_y]") + log_debug("Target Z = [target_z]") + + //debug +*/ + if(target_z) + A.z = target_z + A.y = world.maxy - 2 + spawn (0) + if ((A && A.loc)) + A.loc.Entered(A) + + else if (src.y >= world.maxy) + if(istype(A, /obj/effect/meteor)) + qdel(A) + return + var/list/cur_pos = src.get_global_map_pos() + if(!cur_pos) return + cur_x = cur_pos["x"] + cur_y = cur_pos["y"] + y_arr = GLOB.global_map[cur_x] + next_y = (++cur_y > y_arr.len ? 1 : cur_y) + target_z = y_arr[next_y] +/* + //debug + log_debug("Src.z = [src.z] in global map X = [cur_x], Y = [cur_y]") + log_debug("Next Y = [next_y]") + log_debug("Target Z = [target_z]") + + //debug +*/ + if(target_z) + A.z = target_z + A.y = 3 + spawn (0) + if ((A && A.loc)) + A.loc.Entered(A) + return + +/turf/space/ChangeTurf(var/turf/N, var/tell_universe=1, var/force_lighting_update = 0) + return ..(N, tell_universe, 1) + +//Bluespace turfs for shuttles and possible future transit use +/turf/space/bluespace + name = "bluespace" + icon_state = "bluespace" diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm new file mode 100644 index 00000000..d1d58bd6 --- /dev/null +++ b/code/game/turfs/space/transit.dm @@ -0,0 +1,62 @@ +/turf/space/transit + var/pushdirection // push things that get caught in the transit tile this direction + +//Overwrite because we dont want people building rods in space. +/turf/space/transit/attackby(obj/O as obj, mob/user as mob) + return + +//generates a list used to randomize transit animations so they aren't in lockstep +/turf/space/transit/proc/get_cross_shift_list(var/size) + var/list/result = list() + + result += rand(0, 14) + for(var/i in 2 to size) + var/shifts = list(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) + shifts -= result[i - 1] //consecutive shifts should not be equal + if(i == size) + shifts -= result[1] //because shift list is a ring buffer + result += pick(shifts) + + return result + +/turf/space/transit/north // moving to the north + pushdirection = SOUTH // south because the space tile is scrolling south + var/static/list/phase_shift_by_x + +/turf/space/transit/north/Initialize() + . = ..() + if(!phase_shift_by_x) + phase_shift_by_x = get_cross_shift_list(15) + + var/x_shift = phase_shift_by_x[src.x % (phase_shift_by_x.len - 1) + 1] + var/transit_state = (world.maxy - src.y + x_shift)%15 + 1 + + icon_state = "speedspace_ns_[transit_state]" + +/turf/space/transit/east // moving to the east + pushdirection = WEST + var/static/list/phase_shift_by_y + +/turf/space/transit/east/New() + ..() + if(!phase_shift_by_y) + phase_shift_by_y = get_cross_shift_list(15) + + var/y_shift = phase_shift_by_y[src.y % (phase_shift_by_y.len - 1) + 1] + var/transit_state = (world.maxx - src.x + y_shift)%15 + 1 + + icon_state = "speedspace_ew_[transit_state]" + +/turf/space/transit/west // moving to the east + pushdirection = EAST + var/static/list/phase_shift_by_y + +/turf/space/transit/west/New() + ..() + if(!phase_shift_by_y) + phase_shift_by_y = get_cross_shift_list(15) + + var/y_shift = phase_shift_by_y[src.y % (phase_shift_by_y.len - 1) + 1] + var/transit_state = (world.maxx - src.x + y_shift)%15 + 1 + + icon_state = "speedspace_we_[transit_state]" diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm new file mode 100644 index 00000000..191bfa97 --- /dev/null +++ b/code/game/turfs/turf.dm @@ -0,0 +1,306 @@ +/turf + icon = 'icons/turf/floors.dmi' + level = 1 + + plane = TURF_PLANE + layer = BASE_TURF_LAYER + + var/turf_flags + + var/holy = 0 + + // Initial air contents (in moles) + var/list/initial_gas + + //Properties for airtight tiles (/wall) + var/thermal_conductivity = 0.05 + var/heat_capacity = 1 + + //Properties for both + var/temperature = T20C // Initial turf temperature. + var/blocks_air = 0 // Does this turf contain air/let air through? + + // General properties. + var/icon_old = null + var/pathweight = 1 // How much does it cost to pathfind over this turf? + var/blessed = 0 // Has the turf been blessed? + + var/list/decals + + var/movement_delay + + var/has_coldbreath = FALSE + +/turf/New() + ..() + for(var/atom/movable/AM as mob|obj in src) + spawn( 0 ) + src.Entered(AM) + return + + if(dynamic_lighting) + luminosity = 0 + else + luminosity = 1 + //queue_ao(TRUE) + +/turf/Initialize() + . = ..() + //queue_ao(TRUE) + +/turf/Destroy() + remove_cleanables() + ..() + return QDEL_HINT_IWILLGC + +/turf/ex_act(severity) + return 0 + +/turf/proc/is_solid_structure() + return 1 + +/turf/attack_hand(mob/user) + if(!(user.canmove) || user.restrained() || !(user.pulling)) + return 0 + if(user.pulling.anchored || !isturf(user.pulling.loc)) + return 0 + if(user.pulling.loc != user.loc && get_dist(user, user.pulling) > 1) + return 0 + + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + if(ismob(user.pulling)) + var/mob/M = user.pulling + var/atom/movable/t = M.pulling + M.stop_pulling() + step(user.pulling, get_dir(user.pulling.loc, src)) + M.start_pulling(t) + else + step(user.pulling, get_dir(user.pulling.loc, src)) + return 1 + +turf/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = W + if(S.use_to_pickup && S.collection_mode) + S.gather_all(src, user) + return ..() + +/turf/MouseDrop_T(atom/movable/O as mob|obj, mob/user as mob) + var/turf/T = get_turf(user) + var/area/A = T.loc + if((istype(A) && !(A.has_gravity)) || (istype(T,/turf/space))) + return + if(istype(O, /obj/screen)) + return + if((!(istype(O, /atom/movable)) || O.anchored || !Adjacent(user) || !Adjacent(O) || !user.Adjacent(O))) + return + if(!isturf(O.loc) || !isturf(user.loc)) + return + if(isanimal(user) && O != user) + return + for (var/obj/item/grab/G in user.grabbed_by) + if(G.stop_move()) + return + +/turf/Enter(atom/movable/mover as mob|obj, atom/forget as mob|obj|turf|area) + + ..() + + if (!mover || !isturf(mover.loc) || isobserver(mover)) + return 1 + + //First, check objects to block exit that are not on the border + for(var/obj/obstacle in mover.loc) + if(!(obstacle.atom_flags & ATOM_FLAG_CHECKS_BORDER) && (mover != obstacle) && (forget != obstacle)) + if(!obstacle.CheckExit(mover, src)) + mover.Bump(obstacle, 1) + return 0 + + //Now, check objects to block exit that are on the border + for(var/obj/border_obstacle in mover.loc) + if((border_obstacle.atom_flags & ATOM_FLAG_CHECKS_BORDER) && (mover != border_obstacle) && (forget != border_obstacle)) + if(!border_obstacle.CheckExit(mover, src)) + mover.Bump(border_obstacle, 1) + return 0 + + //Next, check objects to block entry that are on the border + for(var/obj/border_obstacle in src) + if(border_obstacle.atom_flags & ATOM_FLAG_CHECKS_BORDER) + if(!border_obstacle.CanPass(mover, mover.loc, 1, 0) && (forget != border_obstacle)) + mover.Bump(border_obstacle, 1) + return 0 + + //Then, check the turf itself + if (!src.CanPass(mover, src)) + mover.Bump(src, 1) + return 0 + + //Finally, check objects/mobs to block entry that are not on the border + for(var/atom/movable/obstacle in src) + if(!(obstacle.atom_flags & ATOM_FLAG_CHECKS_BORDER)) + if(!obstacle.CanPass(mover, mover.loc, 1, 0) && (forget != obstacle)) + mover.Bump(obstacle, 1) + return 0 + return 1 //Nothing found to block so return success! + +var/const/enterloopsanity = 100 +/turf/Entered(atom/atom as mob|obj) + + ..() + + if(!istype(atom, /atom/movable)) + return + + var/atom/movable/A = atom + + if(ismob(A)) + var/mob/M = A + if(!M.check_solid_ground()) + inertial_drift(M) + //we'll end up checking solid ground again but we still need to check the other things. + //Ususally most people aren't in space anyways so hopefully this is acceptable. + M.update_floating() + else + M.inertia_dir = 0 + M.make_floating(0) //we know we're not on solid ground so skip the checks to save a bit of processing + + var/objects = 0 + if(A && (A.movable_flags & MOVABLE_FLAG_PROXMOVE)) + for(var/atom/movable/thing in range(1)) + if(objects > enterloopsanity) break + objects++ + spawn(0) + if(A) + A.HasProximity(thing, 1) + if ((thing && A) && (thing.movable_flags & MOVABLE_FLAG_PROXMOVE)) + thing.HasProximity(A, 1) + + if(ishuman(atom)) + var/mob/living/carbon/human/H = atom + if(has_coldbreath) + H.add_coldbreath() + else + H.remove_coldbreath() + + return + +/turf/proc/adjacent_fire_act(turf/simulated/floor/source, temperature, volume) + return + +/turf/proc/is_plating() + return 0 + +/turf/proc/protects_atom(var/atom/A) + return FALSE + +/turf/proc/inertial_drift(atom/movable/A) + if(!(A.last_move)) return + if((istype(A, /mob/) && src.x > 2 && src.x < (world.maxx - 1) && src.y > 2 && src.y < (world.maxy-1))) + var/mob/M = A + if(M.Allow_Spacemove(1)) //if this mob can control their own movement in space then they shouldn't be drifting + M.inertia_dir = 0 + return + spawn(5) + if(M && !(M.anchored) && !(M.pulledby) && (M.loc == src)) + if(!M.inertia_dir) + M.inertia_dir = M.last_move + step(M, M.inertia_dir) + return + +/turf/proc/levelupdate() + for(var/obj/O in src) + O.hide(O.hides_under_flooring() && !is_plating()) + +/turf/proc/AdjacentTurfs(var/check_blockage = TRUE) + . = list() + for(var/turf/t in (trange(1,src) - src)) + if(check_blockage) + if(!t.density) + if(!LinkBlocked(src, t) && !TurfBlockedNonWindow(t)) + . += t + else + . += t + +/turf/proc/CardinalTurfs(var/check_blockage = TRUE) + . = list() + for(var/ad in AdjacentTurfs(check_blockage)) + var/turf/T = ad + if(T.x == src.x || T.y == src.y) + . += T + +/turf/proc/Distance(turf/t) + if(get_dist(src,t) == 1) + var/cost = (src.x - t.x) * (src.x - t.x) + (src.y - t.y) * (src.y - t.y) + cost *= (pathweight+t.pathweight)/2 + return cost + else + return get_dist(src,t) + +/turf/proc/AdjacentTurfsSpace() + var/L[] = new() + for(var/turf/t in oview(src,1)) + if(!t.density) + if(!LinkBlocked(src, t) && !TurfBlockedNonWindow(t)) + L.Add(t) + return L + +/turf/proc/process() + return PROCESS_KILL + +/turf/proc/contains_dense_objects() + if(density) + return 1 + for(var/atom/A in src) + if(A.density && !(A.atom_flags & ATOM_FLAG_CHECKS_BORDER)) + return 1 + return 0 + +//expects an atom containing the reagents used to clean the turf +/turf/proc/clean(atom/source, mob/user = null) + if(source.reagents.has_reagent(/datum/reagent/water, 1) || source.reagents.has_reagent(/datum/reagent/space_cleaner, 1)) + clean_blood() + remove_cleanables() + else + to_chat(user, "\The [source] is too dry to wash that.") + source.reagents.trans_to_turf(src, 1, 10) //10 is the multiplier for the reaction effect. probably needed to wet the floor properly. + +/turf/proc/remove_cleanables() + for(var/obj/effect/O in src) + if(istype(O,/obj/effect/rune) || istype(O,/obj/effect/decal/cleanable) || istype(O,/obj/effect/overlay)) + qdel(O) + +/turf/proc/update_blood_overlays() + return + +/turf/proc/remove_decals() + if(decals && decals.len) + decals.Cut() + decals = null + +// Called when turf is hit by a thrown object +/turf/hitby(atom/movable/AM as mob|obj, var/speed) + if(src.density) + spawn(2) + step(AM, turn(AM.last_move, 180)) + if(isliving(AM)) + var/mob/living/M = AM + M.turf_collision(src, speed) + +/turf/proc/generate_splines() + for(var/direction in GLOB.cardinal) + var/turf/turf_to_check = get_step(src,direction) + if(istype(turf_to_check, /turf/simulated/open)) + var/image/I = image('icons/turf/flooring/shadows.dmi', "spline", dir = turn(direction, 180)) + I.turf_decal_layerise() + + switch(direction) + if(NORTH) + I.pixel_y += (world.icon_size) + if(SOUTH) + I.pixel_y -= (world.icon_size) + if(EAST) + I.pixel_x += (world.icon_size) + if(WEST) + I.pixel_x -= (world.icon_size) + + overlays += I diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm new file mode 100644 index 00000000..5e18589e --- /dev/null +++ b/code/game/turfs/turf_changing.dm @@ -0,0 +1,115 @@ +/turf/proc/ReplaceWithLattice() + src.ChangeTurf(get_base_turf_by_area(src)) + spawn() + new /obj/structure/lattice( locate(src.x, src.y, src.z) ) + +// Removes all signs of lattice on the pos of the turf -Donkieyo +/turf/proc/RemoveLattice() + var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) + if(L) + qdel(L) +// Called after turf replaces old one +/turf/proc/post_change() + levelupdate() + var/turf/simulated/open/T = GetAbove(src) + if(istype(T)) + T.update_icon() + +//Creates a new turf +/turf/proc/ChangeTurf(var/turf/N, var/tell_universe=1, var/force_lighting_update = 0) + if (!N) + return + + // This makes sure that turfs are not changed to space when one side is part of a zone + if(N == /turf/space) + var/turf/below = GetBelow(src) + if(istype(below) && !istype(below,/turf/space)) + N = /turf/simulated/open + + var/obj/fire/old_fire = fire + var/old_opacity = opacity + var/old_dynamic_lighting = dynamic_lighting + var/old_affecting_lights = affecting_lights + var/old_lighting_overlay = lighting_overlay + var/old_corners = corners + +// log_debug("Replacing [src.type] with [N]") + + + if(connections) connections.erase_all() + + overlays.Cut() + underlays.Cut() + if(istype(src,/turf/simulated)) + //Yeah, we're just going to rebuild the whole thing. + //Despite this being called a bunch during explosions, + //the zone will only really do heavy lifting once. + var/turf/simulated/S = src + if(S.zone) S.zone.rebuild() + + var/turf/simulated/W = new N( locate(src.x, src.y, src.z) ) + + W.opaque_counter = opaque_counter + + if(ispath(N, /turf/simulated)) + if(old_fire) + fire = old_fire + if (istype(W,/turf/simulated/floor)) + W.RemoveLattice() + else if(old_fire) + old_fire.RemoveFire() + + if(tell_universe) + GLOB.universe.OnTurfChange(W) + + SSair.mark_for_update(src) //handle the addition of the new turf. + + for(var/turf/space/S in range(W,1)) + S.update_starlight() + + W.post_change() + //regenerate_ao() + . = W + + if(lighting_overlays_initialised) + lighting_overlay = old_lighting_overlay + affecting_lights = old_affecting_lights + corners = old_corners + if((old_opacity != opacity) || (dynamic_lighting != old_dynamic_lighting)) + reconsider_lights() + if(dynamic_lighting != old_dynamic_lighting) + if(dynamic_lighting) + lighting_build_overlay() + else + lighting_clear_overlay() + +/turf/proc/transport_properties_from(turf/other) + if(!istype(other, src.type)) + return 0 + src.set_dir(other.dir) + src.icon_state = other.icon_state + src.icon = other.icon + src.overlays = other.overlays.Copy() + src.underlays = other.underlays.Copy() + if(other.decals) + src.decals = other.decals.Copy() + src.update_icon() + return 1 + +//I would name this copy_from() but we remove the other turf from their air zone for some reason +/turf/simulated/transport_properties_from(turf/simulated/other) + if(!..()) + return 0 + + if(other.zone) + if(!src.air) + src.make_air() + src.air.copy_from(other.zone.air) + other.zone.remove(other) + return 1 + + +//No idea why resetting the base appearence from New() isn't enough, but without this it doesn't work +/turf/simulated/shuttle/wall/corner/transport_properties_from(turf/simulated/other) + . = ..() + reset_base_appearance() diff --git a/code/game/turfs/turf_flick_animations.dm b/code/game/turfs/turf_flick_animations.dm new file mode 100644 index 00000000..74dc66e5 --- /dev/null +++ b/code/game/turfs/turf_flick_animations.dm @@ -0,0 +1,21 @@ +/proc/anim(turf/location, var/atom/target, a_icon, a_icon_state, flick_anim, sleeptime = 0, direction as num) +//This proc throws up either an icon or an animation for a specified amount of time. +//The variables should be apparent enough. + if(!location && target) + location = get_turf(target) + if(location && !target) + target = location + var/atom/movable/overlay/animation = new /atom/movable/overlay(location) + if(direction) + animation.set_dir(direction) + animation.icon = a_icon + animation.plane = target.plane + animation.layer = target.layer + 0.1 + if(a_icon_state) + animation.icon_state = a_icon_state + else + animation.icon_state = "blank" + animation.master = target + flick(flick_anim, animation) + spawn(max(sleeptime, 15)) + qdel(animation) diff --git a/code/game/turfs/unsimulated.dm b/code/game/turfs/unsimulated.dm new file mode 100644 index 00000000..aa9f9f7b --- /dev/null +++ b/code/game/turfs/unsimulated.dm @@ -0,0 +1,3 @@ +/turf/unsimulated + name = "command" + initial_gas = list("oxygen" = MOLES_O2STANDARD, "nitrogen" = MOLES_N2STANDARD) \ No newline at end of file diff --git a/code/game/turfs/unsimulated/beach.dm b/code/game/turfs/unsimulated/beach.dm new file mode 100644 index 00000000..5f237313 --- /dev/null +++ b/code/game/turfs/unsimulated/beach.dm @@ -0,0 +1,20 @@ +/turf/unsimulated/beach + name = "Beach" + icon = 'icons/misc/beach.dmi' + +/turf/unsimulated/beach/sand + name = "Sand" + icon_state = "sand" + +/turf/unsimulated/beach/coastline + name = "Coastline" + icon = 'icons/misc/beach2.dmi' + icon_state = "sandwater" + +/turf/unsimulated/beach/water + name = "Water" + icon_state = "water" + +/turf/unsimulated/beach/water/New() + ..() + overlays += image("icon"='icons/misc/beach.dmi',"icon_state"="water2","layer"=BASE_MOB_LAYER+0.1) diff --git a/code/game/turfs/unsimulated/floor.dm b/code/game/turfs/unsimulated/floor.dm new file mode 100644 index 00000000..259449b8 --- /dev/null +++ b/code/game/turfs/unsimulated/floor.dm @@ -0,0 +1,21 @@ +/turf/unsimulated/floor + name = "floor" + icon = 'icons/turf/floors.dmi' + icon_state = "Floor3" + +/turf/unsimulated/floor/bluespace //non-doomsday version of bluespace for transit and wizden + name = "\improper bluespace" + icon = 'icons/turf/space.dmi' + icon_state = "bluespace" + desc = "Looks like infinity." + +/turf/unsimulated/mask + name = "mask" + icon = 'icons/turf/walls.dmi' + icon_state = "rockvault" + +/turf/unsimulated/floor/rescue_base + icon_state = "asteroidfloor" + +/turf/unsimulated/floor/shuttle_ceiling + icon_state = "reinforced" diff --git a/code/game/turfs/unsimulated/walls.dm b/code/game/turfs/unsimulated/walls.dm new file mode 100644 index 00000000..5d4dd5d6 --- /dev/null +++ b/code/game/turfs/unsimulated/walls.dm @@ -0,0 +1,14 @@ +/turf/unsimulated/wall + name = "wall" + icon = 'icons/turf/walls.dmi' + icon_state = "riveted" + opacity = 1 + density = 1 + +/turf/unsimulated/wall/fakeglass + name = "window" + icon_state = "fakewindows" + opacity = 0 + +/turf/unsimulated/wall/other + icon_state = "r_wall" \ No newline at end of file diff --git a/code/game/verbs/ignore.dm b/code/game/verbs/ignore.dm new file mode 100644 index 00000000..68a5e00d --- /dev/null +++ b/code/game/verbs/ignore.dm @@ -0,0 +1,44 @@ +/client/verb/ignore(key_to_ignore as text) + set name = "Ignore" + set category = "OOC" + set desc = "Makes OOC and Deadchat messages from a specific player not appear to you." + + if(!key_to_ignore) + return + key_to_ignore = ckey(sanitize(key_to_ignore)) + if(prefs && prefs.ignored_players) + if(key_to_ignore in prefs.ignored_players && key_to_ignore != ckey) + to_chat(usr, "[key_to_ignore] is already being ignored.") + return + prefs.ignored_players |= key_to_ignore + prefs.save_preferences() + to_chat(usr, "Now ignoring [key_to_ignore].") + +/client/verb/unignore(key_to_unignore as text) + set name = "Unignore" + set category = "OOC" + set desc = "Reverts your ignoring of a specific player." + + if(!key_to_unignore) + return + key_to_unignore = ckey(sanitize(key_to_unignore)) + if(prefs && prefs.ignored_players) + if(!(key_to_unignore in prefs.ignored_players)) + to_chat(usr, "[key_to_unignore] isn't being ignored.") + return + prefs.ignored_players -= key_to_unignore + prefs.save_preferences() + to_chat(usr, "Reverted ignore on [key_to_unignore].") + +/mob/proc/is_key_ignored(var/key_to_check) + if(client) + return client.is_key_ignored(key_to_check) + return 0 + +/client/proc/is_key_ignored(var/key_to_check) + key_to_check = ckey(key_to_check) + if(key_to_check in prefs.ignored_players) + if(check_rights(R_MENTOR|R_MOD|R_ADMIN, 0)) // Admins, mentors and moderators are not ignorable + return 0 + return 1 + return 0 \ No newline at end of file diff --git a/code/game/verbs/ooc.dm b/code/game/verbs/ooc.dm new file mode 100644 index 00000000..c3267e7d --- /dev/null +++ b/code/game/verbs/ooc.dm @@ -0,0 +1,12 @@ +/client/verb/ooc(message as text) + set name = "OOC" + set category = "OOC" + + sanitize_and_communicate(/decl/communication_channel/ooc, src, message) + +/client/verb/looc(message as text) + set name = "LOOC" + set desc = "Local OOC, seen only by those in view. Remember: Just because you see someone that doesn't mean they see you." + set category = "OOC" + + sanitize_and_communicate(/decl/communication_channel/ooc/looc, src, message) diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm new file mode 100644 index 00000000..30dcec80 --- /dev/null +++ b/code/game/verbs/who.dm @@ -0,0 +1,106 @@ + +/client/verb/who() + set name = "Who" + set category = "OOC" + + var/msg = "Current Players:\n" + + var/list/Lines = list() + + if(check_rights(R_INVESTIGATE, 0)) + for(var/client/C in GLOB.clients) + var/entry = "\t[C.key]" + if(!C.mob) //If mob is null, print error and skip rest of info for client. + entry += " - HAS NO MOB" + Lines += entry + continue + + entry += " - Playing as [C.mob.real_name]" + switch(C.mob.stat) + if(UNCONSCIOUS) + entry += " - Unconscious" + if(DEAD) + if(isghost(C.mob)) + var/mob/observer/ghost/O = C.mob + if(O.started_as_observer) + entry += " - Observing" + else + entry += " - DEAD" + else + entry += " - DEAD" + + var/age + if(isnum(C.player_age)) + age = C.player_age + else + age = 0 + + if(age <= 1) + age = "[age]" + else if(age < 10) + age = "[age]" + + entry += " - [age]" + + if(is_special_character(C.mob)) + entry += " - Antagonist" + if(C.warfare_faction == RED_TEAM) + entry += " - [RED_TEAM]" + else if(C.warfare_faction == BLUE_TEAM) + entry += " - [BLUE_TEAM]" + if(C.is_afk()) + entry += " (AFK - [C.inactivity2text()])" + entry += " (?)" + Lines += entry + else + for(var/client/C in GLOB.clients) + if(!C.is_stealthed()) + Lines += C.key + + for(var/line in sortList(Lines)) + msg += "[line]\n" + + msg += "Total Players: [length(Lines)]" + to_chat(src, msg) + +/client/verb/staffwho() + set category = "Admin" + set name = "Staffwho" + + var/list/msg = list() + var/active_staff = 0 + var/total_staff = 0 + var/can_investigate = check_rights(R_INVESTIGATE, 0) + + for(var/client/C in GLOB.admins) + var/line = list() + if(!can_investigate && C.is_stealthed()) + continue + total_staff++ + if(check_rights(R_ADMIN,0,C)) + line += "\t[C] is \an ["\improper[C.holder.rank]"]" + else + line += "\t[C] is \an ["\improper[C.holder.rank]"]" + if(!C.is_afk()) + active_staff++ + if(can_investigate) + if(C.is_afk()) + line += " (AFK - [C.inactivity2text()])" + if(isghost(C.mob)) + line += " - Observing" + else if(istype(C.mob,/mob/new_player)) + line += " - Lobby" + else + line += " - Playing" + if(C.is_stealthed()) + line += " (Stealthed)" + line = jointext(line,null) + if(check_rights(R_ADMIN,0,C)) + msg.Insert(1, line) + else + msg += line + + if(config.admin_irc) + to_chat(src, "Adminhelps are also sent to IRC. If no admins are available in game try anyway and an admin on IRC may see it and respond.") + to_chat(src, "Current Staff ([active_staff]/[total_staff]):") + to_chat(src, jointext(msg,"\n")) diff --git a/code/game/world.dm b/code/game/world.dm new file mode 100644 index 00000000..f08cee3e --- /dev/null +++ b/code/game/world.dm @@ -0,0 +1,755 @@ +/var/server_name = "Unofficial Interstation12" +/var/game_id = null +/var/list/warfare_taglines = list("WW1 Scifi Suffering Simulator", "Post Apoc WW1 Emulator", "WW1 But Terrible", "Pain, Suffering, and Flesh", "Your Heart Has Stopped", "Trench Pizza Simulator", "Warcrime Simulator")// list("It's Getting Cold Out There", "New Guns", "New Classes", "Cold", "Winter", "Frozen Solid", "Frozen Trench Pizza", "Warcrime Simulator", "Your Heart Has Stopped", ) +/var/warfare_tagline = null +/hook/global_init/proc/generate_gameid() + if(game_id != null) + return + game_id = "" + + //Thooloo did this. I have no idea why he did. + var/list/gods = list( + "Aker","Amun","Anhur", + "Aten","Atum","Bennu", + "Geb","Hapi","Horus", + "Khepri","Khnum","Khonsu", + "Maahes","Montu","Nefertum", + "Nemty","Neper","Osiris", + "Ptah","Ra","Set", + "Shu","Sobek","Sopdu", + "Thoth","Wadj-wer","Amunet", + "Anuket","Bastet","Bat", + "Hathor","Heqet","Hesat", + "Imentet","Isis","Maat", + "Menhit","Mut","Neith", + "Nekhbet","Nephthys","Nepit", + "Nut","Pakhet","Renenutet", + "Satet","Sekhmet","Tefnut", + "Wadjet","Wosret" + ) + + var/timestamp = world.timeofday % 500 + + game_id = "[pick(gods)] [timestamp]" + + return 1 + +// Find mobs matching a given string +// +// search_string: the string to search for, in params format; for example, "some_key;mob_name" +// restrict_type: A mob type to restrict the search to, or null to not restrict +// +// Partial matches will be found, but exact matches will be preferred by the search +// +// Returns: A possibly-empty list of the strongest matches +/proc/text_find_mobs(search_string, restrict_type = null) + var/list/search = params2list(search_string) + var/list/ckeysearch = list() + for(var/text in search) + ckeysearch += ckey(text) + + var/list/match = list() + + for(var/mob/M in SSmobs.mob_list) + if(restrict_type && !istype(M, restrict_type)) + continue + var/strings = list(M.name, M.ckey) + if(M.mind) + strings += M.mind.assigned_role + strings += M.mind.special_role + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.species) + strings += H.species.name + for(var/text in strings) + if(ckey(text) in ckeysearch) + match[M] += 10 // an exact match is far better than a partial one + else + for(var/searchstr in search) + if(findtext(text, searchstr)) + match[M] += 1 + + var/maxstrength = 0 + for(var/mob/M in match) + maxstrength = max(match[M], maxstrength) + for(var/mob/M in match) + if(match[M] < maxstrength) + match -= M + + return match + +#define RECOMMENDED_VERSION 513 + + + + +/world/New() + //set window title + if(config && config.server_name != null) + server_name = config.server_name + name = "[server_name] - [GLOB.using_map.full_name]" + warfare_tagline = "[pick(warfare_taglines)] Edition" + + //logs + SetupLogs() + var/date_string = time2text(world.realtime, "YYYY/MM-Month/DD-Day") + href_logfile = file("data/logs/[date_string] hrefs.htm") + diary = file("data/logs/[date_string].log") + diary << "[log_end]\n[log_end]\nStarting up. (ID: [game_id]) [time2text(world.timeofday, "hh:mm.ss")][log_end]\n---------------------[log_end]" + changelog_hash = md5('html/changelog.html') //used for telling if the changelog has changed recently + + if(byond_version < RECOMMENDED_VERSION) + world.log << "Your server's byond version does not meet the recommended requirements for this server. Please update BYOND" + + if(config && config.server_name != null && config.server_suffix && world.port > 0) + // dumb and hardcoded but I don't care~ + config.server_name += " #[(world.port % 1000) / 100]" + + if(config && config.log_runtime) + var/runtime_log = file("data/logs/runtime/[date_string]_[time2text(world.timeofday, "hh:mm")]_[game_id].log") + runtime_log << "Game [game_id] starting up at [time2text(world.timeofday, "hh:mm.ss")]" + log = runtime_log + + callHook("startup") + //Emergency Fix + load_mods() + //end-emergency fix + + . = ..() + +#ifdef UNIT_TEST + log_unit_test("Unit Tests Enabled. This will destroy the world when testing is complete.") + load_unit_test_changes() +#endif + + // Set up roundstart seed list. + plant_controller = new() + + // This is kinda important. Set up details of what the hell things are made of. + populate_material_list() + + if(config.generate_map) + GLOB.using_map.perform_map_generation() + GLOB.using_map.build_exoplanets() + + // Create robolimbs for chargen. + populate_robolimb_list() + + processScheduler = new + master_controller = new /datum/controller/game_controller() + + processScheduler.deferSetupFor(/datum/controller/process/ticker) + processScheduler.setup() + Master.Initialize(10, FALSE) + +#ifdef UNIT_TEST + spawn(1) + initialize_unit_tests() +#endif + +#undef RECOMMENDED_VERSION + +var/world_topic_spam_protect_ip = "0.0.0.0" +var/world_topic_spam_protect_time = world.timeofday + +/world/Topic(T, addr, master, key) + diary << "TOPIC: \"[T]\", from:[addr], master:[master], key:[key][log_end]" + + if (T == "ping") + var/x = 1 + for (var/client/C) + x++ + return x + + else if(T == "players") + var/n = 0 + for(var/mob/M in GLOB.player_list) + if(M.client) + n++ + return n + + else if (copytext(T,1,7) == "status") + var/input[] = params2list(T) + var/list/s = list() + s["version"] = game_version + s["mode"] = PUBLIC_GAME_MODE + s["respawn"] = config.abandon_allowed + s["enter"] = config.enter_allowed + s["vote"] = config.allow_vote_mode + s["ai"] = config.allow_ai + s["host"] = host ? host : null + + // This is dumb, but spacestation13.com's banners break if player count isn't the 8th field of the reply, so... this has to go here. + s["players"] = 0 + s["stationtime"] = stationtime2text() + s["roundduration"] = roundduration2text() + s["map"] = GLOB.using_map.full_name + + var/active = 0 + var/list/players = list() + var/list/admins = list() + var/legacy = input["status"] != "2" + for(var/client/C in GLOB.clients) + if(C.holder) + if(C.is_stealthed()) + continue //so stealthmins aren't revealed by the hub + admins[C.key] = C.holder.rank + if(legacy) + s["player[players.len]"] = C.key + players += C.key + if(istype(C.mob, /mob/living)) + active++ + + s["players"] = players.len + s["admins"] = admins.len + if(!legacy) + s["playerlist"] = list2params(players) + s["adminlist"] = list2params(admins) + s["active_players"] = active + + return list2params(s) + + else if(T == "manifest") + var/list/positions = list() + var/list/nano_crew_manifest = nano_crew_manifest() + // We rebuild the list in the format external tools expect + for(var/dept in nano_crew_manifest) + var/list/dept_list = nano_crew_manifest[dept] + if(dept_list.len > 0) + positions[dept] = list() + for(var/list/person in dept_list) + positions[dept][person["name"]] = person["rank"] + + for(var/k in positions) + positions[k] = list2params(positions[k]) // converts positions["heads"] = list("Bob"="Captain", "Bill"="CMO") into positions["heads"] = "Bob=Captain&Bill=CMO" + + return list2params(positions) + + else if(T == "revision") + var/list/L = list() + L["gameid"] = game_id + L["dm_version"] = DM_VERSION // DreamMaker version compiled in + L["dd_version"] = world.byond_version // DreamDaemon version running on + + if(revdata.revision) + L["revision"] = revdata.revision + L["branch"] = revdata.branch + L["date"] = revdata.date + else + L["revision"] = "unknown" + + return list2params(L) + + else if(copytext(T,1,5) == "laws") + var/input[] = params2list(T) + if(input["key"] != config.comms_password) + if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) + + spawn(50) + world_topic_spam_protect_time = world.time + return "Bad Key (Throttled)" + + world_topic_spam_protect_time = world.time + world_topic_spam_protect_ip = addr + + return "Bad Key" + + var/list/match = text_find_mobs(input["laws"], /mob/living/silicon) + + if(!match.len) + return "No matches" + else if(match.len == 1) + var/mob/living/silicon/S = match[1] + var/info = list() + info["name"] = S.name + info["key"] = S.key + + if(!S.laws) + info["laws"] = null + return list2params(info) + + var/list/lawset_parts = list( + "ion" = S.laws.ion_laws, + "inherent" = S.laws.inherent_laws, + "supplied" = S.laws.supplied_laws + ) + + for(var/law_type in lawset_parts) + var/laws = list() + for(var/datum/ai_law/L in lawset_parts[law_type]) + laws += L.law + info[law_type] = list2params(laws) + + info["zero"] = S.laws.zeroth_law ? S.laws.zeroth_law.law : null + + return list2params(info) + + else + var/list/ret = list() + for(var/mob/M in match) + ret[M.key] = M.name + return list2params(ret) + + else if(copytext(T,1,5) == "info") + var/input[] = params2list(T) + if(input["key"] != config.comms_password) + if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) + + spawn(50) + world_topic_spam_protect_time = world.time + return "Bad Key (Throttled)" + + world_topic_spam_protect_time = world.time + world_topic_spam_protect_ip = addr + + return "Bad Key" + + var/list/match = text_find_mobs(input["info"]) + + if(!match.len) + return "No matches" + else if(match.len == 1) + var/mob/M = match[1] + var/info = list() + info["key"] = M.key + info["name"] = M.name == M.real_name ? M.name : "[M.name] ([M.real_name])" + info["role"] = M.mind ? (M.mind.assigned_role ? M.mind.assigned_role : "No role") : "No mind" + var/turf/MT = get_turf(M) + info["loc"] = M.loc ? "[M.loc]" : "null" + info["turf"] = MT ? "[MT] @ [MT.x], [MT.y], [MT.z]" : "null" + info["area"] = MT ? "[MT.loc]" : "null" + info["antag"] = M.mind ? (M.mind.special_role ? M.mind.special_role : "Not antag") : "No mind" + info["hasbeenrev"] = M.mind ? M.mind.has_been_rev : "No mind" + info["stat"] = M.stat + info["type"] = M.type + if(isliving(M)) + var/mob/living/L = M + info["damage"] = list2params(list( + oxy = L.getOxyLoss(), + tox = L.getToxLoss(), + fire = L.getFireLoss(), + brute = L.getBruteLoss(), + clone = L.getCloneLoss(), + brain = L.getBrainLoss() + )) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + info["species"] = H.species.name + else + info["species"] = "non-human" + else + info["damage"] = "non-living" + info["species"] = "non-human" + info["gender"] = M.gender + return list2params(info) + else + var/list/ret = list() + for(var/mob/M in match) + ret[M.key] = M.name + return list2params(ret) + + else if(copytext(T,1,9) == "adminmsg") + /* + We got an adminmsg from IRC bot lets split the input then validate the input. + expected output: + 1. adminmsg = ckey of person the message is to + 2. msg = contents of message, parems2list requires + 3. validatationkey = the key the bot has, it should match the gameservers commspassword in it's configuration. + 4. sender = the ircnick that send the message. + */ + + + var/input[] = params2list(T) + if(input["key"] != config.comms_password) + if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) + + spawn(50) + world_topic_spam_protect_time = world.time + return "Bad Key (Throttled)" + + world_topic_spam_protect_time = world.time + world_topic_spam_protect_ip = addr + + return "Bad Key" + + var/client/C + var/req_ckey = ckey(input["adminmsg"]) + + for(var/client/K in GLOB.clients) + if(K.ckey == req_ckey) + C = K + break + if(!C) + return "No client with that name on server" + + var/rank = input["rank"] + if(!rank) + rank = "Admin" + if(rank == "Unknown") + rank = "Staff" + + var/message = "[rank] PM from [input["sender"]]: [input["msg"]]" + var/amessage = "[rank] PM from [input["sender"]] to [key_name(C)] : [input["msg"]]" + + C.received_irc_pm = world.time + C.irc_admin = input["sender"] + + sound_to(C, 'sound/effects/adminhelp.ogg') + to_chat(C, message) + + for(var/client/A in GLOB.admins) + if(A != C) + to_chat(A, amessage) + return "Message Successful" + + else if(copytext(T,1,6) == "notes") + /* + We got a request for notes from the IRC Bot + expected output: + 1. notes = ckey of person the notes lookup is for + 2. validationkey = the key the bot has, it should match the gameservers commspassword in it's configuration. + */ + var/input[] = params2list(T) + if(input["key"] != config.comms_password) + if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) + + spawn(50) + world_topic_spam_protect_time = world.time + return "Bad Key (Throttled)" + + world_topic_spam_protect_time = world.time + world_topic_spam_protect_ip = addr + return "Bad Key" + + return show_player_info_irc(ckey(input["notes"])) + + else if(copytext(T,1,4) == "age") + var/input[] = params2list(T) + if(input["key"] != config.comms_password) + if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) + spawn(50) + world_topic_spam_protect_time = world.time + return "Bad Key (Throttled)" + + world_topic_spam_protect_time = world.time + world_topic_spam_protect_ip = addr + return "Bad Key" + + var/age = get_player_age(input["age"]) + if(isnum(age)) + if(age >= 0) + return "[age]" + else + return "Ckey not found" + else + return "Database connection failed or not set up" + + else if(copytext(T,1,14) == "placepermaban") + var/input[] = params2list(T) + if(!config.ban_comms_password) + return "Not enabled" + if(input["bankey"] != config.ban_comms_password) + if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) + spawn(50) + world_topic_spam_protect_time = world.time + return "Bad Key (Throttled)" + + world_topic_spam_protect_time = world.time + world_topic_spam_protect_ip = addr + return "Bad Key" + + var/target = ckey(input["target"]) + + var/client/C + for(var/client/K in GLOB.clients) + if(K.ckey == target) + C = K + break + if(!C) + return "No client with that name found on server" + if(!C.mob) + return "Client missing mob" + + if(!_DB_ban_record(input["id"], "0", "127.0.0.1", 1, C.mob, -1, input["reason"])) + return "Save failed" + ban_unban_log_save("[input["id"]] has permabanned [C.ckey]. - Reason: [input["reason"]] - This is a ban until appeal.") + notes_add(target,"[input["id"]] has permabanned [C.ckey]. - Reason: [input["reason"]] - This is a ban until appeal.",input["id"]) + qdel(C) + + else if(copytext(T,1,19) == "prometheus_metrics") + var/input[] = params2list(T) + if(input["key"] != config.comms_password) + if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) + spawn(50) + world_topic_spam_protect_time = world.time + return "Bad Key (Throttled)" + + world_topic_spam_protect_time = world.time + world_topic_spam_protect_ip = addr + return "Bad Key" + + if(!GLOB || !GLOB.prometheus_metrics) + return "Metrics not ready" + + return GLOB.prometheus_metrics.collect() + + +/world/Reboot(var/reason) + /*spawn(0) + sound_to(world, sound(pick('sound/AI/newroundsexy.ogg','sound/misc/apcdestroyed.ogg','sound/misc/bangindonk.ogg')))// random end sounds!! - LastyBatsy + + */ + + processScheduler.stop() + + /* + if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite + for(var/client/C in GLOB.clients) + to_chat(C, link("byond://[config.server]")) + */ + + if(config.wait_for_sigusr1_reboot && reason != 3) + text2file("foo", "reboot_called") + to_world("World reboot waiting for external scripts. Please be patient.") + return + + ..(reason) + +/world/Del() + callHook("shutdown") + return ..() + +/hook/startup/proc/loadMode() + world.load_mode() + return 1 + +/world/proc/load_mode() + if(!fexists("data/mode.txt")) + return + + var/list/Lines = file2list("data/mode.txt") + if(Lines.len) + if(Lines[1]) + master_mode = Lines[1] + log_misc("Saved mode is '[master_mode]'") + +/world/proc/save_mode(var/the_mode) + var/F = file("data/mode.txt") + fdel(F) + F << the_mode + +/hook/startup/proc/loadMOTD() + world.load_motd() + return 1 + +/world/proc/load_motd() + join_motd = file2text("config/motd.txt") + +/proc/load_configuration() + config = new /datum/configuration() + config.load("config/config.txt") + config.load("config/discord_bot.txt") + config.load("config/game_options.txt","game_options") + config.loadsql("config/dbconfig.txt") + config.load_event("config/custom_event.txt") + +/hook/startup/proc/loadMods() + world.load_mods() + world.load_mentors() // no need to write another hook. + return 1 + +/world/proc/load_mods() + if(config.admin_legacy_system) + var/text = file2text("config/moderators.txt") + if (!text) + error("Failed to load config/mods.txt") + else + var/list/lines = splittext(text, "\n") + for(var/line in lines) + if (!line) + continue + + if (copytext(line, 1, 2) == ";") + continue + + var/title = "Moderator" + var/rights = admin_ranks[title] + + var/ckey = copytext(line, 1, length(line)+1) + var/datum/admins/D = new /datum/admins(title, rights, ckey) + D.associate(GLOB.ckey_directory[ckey]) + +/world/proc/load_mentors() + if(config.admin_legacy_system) + var/text = file2text("config/mentors.txt") + if (!text) + error("Failed to load config/mentors.txt") + else + var/list/lines = splittext(text, "\n") + for(var/line in lines) + if (!line) + continue + if (copytext(line, 1, 2) == ";") + continue + + var/title = "Mentor" + var/rights = admin_ranks[title] + + var/ckey = copytext(line, 1, length(line)+1) + var/datum/admins/D = new /datum/admins(title, rights, ckey) + D.associate(GLOB.ckey_directory[ckey]) + +/world/proc/update_status() + var/s = "" + + if (config && config.server_name) + s += "[config.server_name] — " + + //Pick a random tagline. + s += "[warfare_tagline]" + s += " (" + s += "" //This should be a config but it's not. + s += "Discord" + s += "" + s += ")" + + var/list/features = list() + + if(ticker) + if(master_mode) + features += master_mode + else + features += "STARTING" + + if (!config.enter_allowed) + features += "closed" + if(config.useckeywhitelist) + features += "private party" + if(config.private_party) + features += "bunkered" + + var/n = 0 + for (var/mob/M in GLOB.player_list) + if (M.client) + n++ + + if (n > 1) + features += "~[n] players" + else if (n > 0) + features += "~[n] player" + + + if (config && config.hostedby) + features += "hosted by [config.hostedby]" + + if (features) + s += ": [jointext(features, ", ")]" + + /* does this help? I do not know */ + if (src.status != s) + src.status = s + +#define WORLD_LOG_START(X) WRITE_FILE(GLOB.world_##X##_log, "\n\nStarting up round ID [game_id]. [time_stamp()]\n---------------------") +#define WORLD_SETUP_LOG(X) GLOB.world_##X##_log = file("[GLOB.log_directory]/[#X].log") ; WORLD_LOG_START(X) +/world/proc/SetupLogs() + GLOB.log_directory = "data/logs/[time2text(world.realtime, "YYYY/MM/DD")]/round-" + if(game_id) + GLOB.log_directory += "[game_id]" + else + GLOB.log_directory += "[replacetext(time_stamp(), ":", ".")]" + + WORLD_SETUP_LOG(runtime) + WORLD_SETUP_LOG(qdel) + +#undef WORLD_SETUP_LOG +#undef WORLD_LOG_START + +#define FAILED_DB_CONNECTION_CUTOFF 5 +var/failed_db_connections = 0 +var/failed_old_db_connections = 0 + +/hook/startup/proc/connectDB() + if(!setup_database_connection()) + world.log << "Your server failed to establish a connection with the feedback database." + else + world.log << "Feedback database connection established." + return 1 + +proc/setup_database_connection() + + if(failed_db_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to conenct anymore. + return 0 + + if(!dbcon) + dbcon = new() + + var/user = sqlfdbklogin + var/pass = sqlfdbkpass + var/db = sqlfdbkdb + var/address = sqladdress + var/port = sqlport + + dbcon.Connect("dbi:mysql:[db]:[address]:[port]","[user]","[pass]") + . = dbcon.IsConnected() + if ( . ) + failed_db_connections = 0 //If this connection succeeded, reset the failed connections counter. + else + failed_db_connections++ //If it failed, increase the failed connections counter. + world.log << dbcon.ErrorMsg() + + return . + +//This proc ensures that the connection to the feedback database (global variable dbcon) is established +proc/establish_db_connection() + if(failed_db_connections > FAILED_DB_CONNECTION_CUTOFF) + return 0 + + if(!dbcon || !dbcon.IsConnected()) + return setup_database_connection() + else + return 1 + + +/hook/startup/proc/connectOldDB() + if(!setup_old_database_connection()) + world.log << "Your server failed to establish a connection with the SQL database." + else + world.log << "SQL database connection established." + return 1 + +//These two procs are for the old database, while it's being phased out. See the tgstation.sql file in the SQL folder for more information. +proc/setup_old_database_connection() + + if(failed_old_db_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to conenct anymore. + return 0 + + if(!dbcon_old) + dbcon_old = new() + + var/user = sqllogin + var/pass = sqlpass + var/db = sqldb + var/address = sqladdress + var/port = sqlport + + dbcon_old.Connect("dbi:mysql:[db]:[address]:[port]","[user]","[pass]") + . = dbcon_old.IsConnected() + if ( . ) + failed_old_db_connections = 0 //If this connection succeeded, reset the failed connections counter. + else + failed_old_db_connections++ //If it failed, increase the failed connections counter. + world.log << dbcon.ErrorMsg() + + return . + +//This proc ensures that the connection to the feedback database (global variable dbcon) is established +proc/establish_old_db_connection() + if(failed_old_db_connections > FAILED_DB_CONNECTION_CUTOFF) + return 0 + + if(!dbcon_old || !dbcon_old.IsConnected()) + return setup_old_database_connection() + else + return 1 + +#undef FAILED_DB_CONNECTION_CUTOFF diff --git a/code/hub.dm b/code/hub.dm new file mode 100644 index 00000000..6bc18cba --- /dev/null +++ b/code/hub.dm @@ -0,0 +1,13 @@ +/world +/* This page contains info for the hub. To allow your server to be visible on the hub, update the entry in the config. + * You can also toggle visibility from in-game with toggle-hub-visibility; be aware that it takes a few minutes for the hub go + */ + hub = "Exadv1.spacestation13" + name = "Space Station 13" + +/world/proc/update_hub_visibility() + GLOB.visibility_pref = !(GLOB.visibility_pref) + if(GLOB.visibility_pref) + hub_password = "kMZy3U5jJHSiBQjr" + else + hub_password = "SORRYNOPASSWORD" \ No newline at end of file diff --git a/code/js/byjax.dm b/code/js/byjax.dm new file mode 100644 index 00000000..6f855a70 --- /dev/null +++ b/code/js/byjax.dm @@ -0,0 +1,50 @@ +//this function places received data into element with specified id. +var/const/js_byjax = {" + +function replaceContent() { + var args = Array.prototype.slice.call(arguments); + var id = args\[0\]; + var content = args\[1\]; + var callback = null; + if(args\[2\]){ + callback = args\[2\]; + if(args\[3\]){ + args = args.slice(3); + } + } + var parent = document.getElementById(id); + if(typeof(parent)!=='undefined' && parent!=null){ + parent.innerHTML = content?content:''; + } + if(callback && window\[callback\]){ + window\[callback\].apply(null,args); + } +} +"} + +/* +sends data to control_id:replaceContent + +receiver - mob +control_id - window id (for windows opened with browse(), it'll be "windowname.browser") +target_element - HTML element id +new_content - HTML content +callback - js function that will be called after the data is sent +callback_args - arguments for callback function + +Be sure to include required js functions in your page, or it'll raise an exception. +*/ +proc/send_byjax(receiver, control_id, target_element, new_content=null, callback=null, list/callback_args=null) + if(receiver && target_element && control_id) // && winexists(receiver, control_id)) + var/list/argums = list(target_element, new_content) + if(callback) + argums += callback + if(callback_args) + argums += callback_args + argums = list2params(argums) +/* if(callback_args) + argums += "&[list2params(callback_args)]" +*/ + receiver << output(argums,"[control_id]:replaceContent") + return + diff --git a/code/js/menus.dm b/code/js/menus.dm new file mode 100644 index 00000000..8d29335e --- /dev/null +++ b/code/js/menus.dm @@ -0,0 +1,37 @@ +var/const/js_dropdowns = {" +function dropdowns() { + var divs = document.getElementsByTagName('div'); + var headers = new Array(); + var links = new Array(); + for(var i=0;i=0) { + elem.className = elem.className.replace('visible','hidden'); + this.className = this.className.replace('open','closed'); + this.innerHTML = this.innerHTML.replace('-','+'); + } + else { + elem.className = elem.className.replace('hidden','visible'); + this.className = this.className.replace('closed','open'); + this.innerHTML = this.innerHTML.replace('+','-'); + } + return false; + } + })(links\[i\]); + } + } +} +"} \ No newline at end of file diff --git a/code/js/player_info.js b/code/js/player_info.js new file mode 100644 index 00000000..4461b296 --- /dev/null +++ b/code/js/player_info.js @@ -0,0 +1,30 @@ +// Copied from View Variables. +function updateSearch() { + var filter_text = document.getElementById('filter'); + var filter = filter_text.value.toLowerCase(); + var notes = document.getElementById('notes'); + var lis = notes.children; + + for(var i = 0; i < lis.length; i++) { + var li = lis[i]; + if(filter == "" || li.innerText.toLowerCase().indexOf(filter) != -1) { + li.style.display = "block"; + } else { + li.style.display = "none"; + } + } +} + +function selectTextField() { + var filter_text = document.getElementById('filter'); + filter_text.focus(); + filter_text.select(); +} + +function loadPage(list) { + if(list.options[list.selectedIndex].value == "") { + return; + } + location.href=list.options[list.selectedIndex].value; + list.selectedIndex = 0; +} diff --git a/code/js/view_variables.js b/code/js/view_variables.js new file mode 100644 index 00000000..86ca8cad --- /dev/null +++ b/code/js/view_variables.js @@ -0,0 +1,33 @@ +function updateSearch() { + var filter_text = document.getElementById('filter'); + var filter = filter_text.value.toLowerCase(); + + var vars_ol = document.getElementById('vars'); + var lis = vars_ol.children; + // the above line can be changed to vars_ol.getElementsByTagName("li") to filter child lists too + // potential todo: implement a per-admin toggle for this + + for(var i = 0; i < lis.length; i++) { + var li = lis[i]; + if(filter == "" || li.innerText.toLowerCase().indexOf(filter) != -1) { + li.style.display = "block"; + } else { + li.style.display = "none"; + } + } +} + +function selectTextField() { + var filter_text = document.getElementById('filter'); + filter_text.focus(); + filter_text.select(); +} + +function loadPage(list) { + if(list.options[list.selectedIndex].value == "") { + return; + } + + location.href=list.options[list.selectedIndex].value; + list.selectedIndex = 0; +} diff --git a/code/modules/ZAS/Airflow.dm b/code/modules/ZAS/Airflow.dm new file mode 100644 index 00000000..2b2fbdf1 --- /dev/null +++ b/code/modules/ZAS/Airflow.dm @@ -0,0 +1,155 @@ +/* +Contains helper procs for airflow, handled in /connection_group. +*/ + +mob/var/tmp/last_airflow_stun = 0 +mob/proc/airflow_stun() + if(stat == 2) + return 0 + if(last_airflow_stun > world.time - vsc.airflow_stun_cooldown) return 0 + + if(!(status_flags & CANSTUN) && !(status_flags & CANWEAKEN)) + to_chat(src, "You stay upright as the air rushes past you.") + return 0 + if(buckled) + to_chat(src, "Air suddenly rushes past you!") + return 0 + if(!lying) + to_chat(src, "The sudden rush of air knocks you over!") + Weaken(5) + last_airflow_stun = world.time + +mob/living/silicon/airflow_stun() + return + +mob/living/carbon/slime/airflow_stun() + return + +mob/living/carbon/human/airflow_stun() + if(!slip_chance()) + to_chat(src, "Air suddenly rushes past you!") + return 0 + ..() + +atom/movable/proc/check_airflow_movable(n) + + if(anchored && !ismob(src)) return 0 + + if(!isobj(src) && n < vsc.airflow_dense_pressure) return 0 + + return 1 + +mob/check_airflow_movable(n) + if(n < vsc.airflow_heavy_pressure) + return 0 + return 1 + +mob/living/silicon/check_airflow_movable() + return 0 + + +obj/check_airflow_movable(n) + if(isnull(w_class)) + if(n < vsc.airflow_dense_pressure) return 0 //most non-item objs don't have a w_class yet + else + switch(w_class) + if(1,2) + if(n < vsc.airflow_lightest_pressure) return 0 + if(3) + if(n < vsc.airflow_light_pressure) return 0 + if(4,5) + if(n < vsc.airflow_medium_pressure) return 0 + if(6) + if(n < vsc.airflow_heavy_pressure) return 0 + if(7 to INFINITY) + if(n < vsc.airflow_dense_pressure) return 0 + return ..() + + +/atom/movable/var/tmp/turf/airflow_dest +/atom/movable/var/tmp/airflow_speed = 0 +/atom/movable/var/tmp/airflow_time = 0 +/atom/movable/var/tmp/last_airflow = 0 +/atom/movable/var/tmp/airborne_acceleration = 0 + +/atom/movable/proc/AirflowCanMove(n) + return 1 + +/mob/AirflowCanMove(n) + if(status_flags & GODMODE) + return 0 + if(buckled) + return 0 + var/obj/item/shoes = get_equipped_item(slot_shoes) + if(istype(shoes) && (shoes.item_flags & ITEM_FLAG_NOSLIP)) + return 0 + return 1 + +/atom/movable/Bump(atom/A) + if(airflow_speed > 0 && airflow_dest) + if(airborne_acceleration > 1) + airflow_hit(A) + else if(istype(src, /mob/living/carbon/human)) + to_chat(src, "You are pinned against [A] by airflow!") + airborne_acceleration = 0 + else + airflow_speed = 0 + airflow_time = 0 + airborne_acceleration = 0 + . = ..() + +atom/movable/proc/airflow_hit(atom/A) + airflow_speed = 0 + airflow_dest = null + airborne_acceleration = 0 + +mob/airflow_hit(atom/A) + for(var/mob/M in hearers(src)) + M.show_message("\The [src] slams into \a [A]!",1,"You hear a loud slam!",2) + playsound(src.loc, "smash.ogg", 25, 1, -1) + var/weak_amt = istype(A,/obj/item) ? A:w_class : rand(1,5) //Heheheh + Weaken(weak_amt) + . = ..() + +obj/airflow_hit(atom/A) + for(var/mob/M in hearers(src)) + M.show_message("\The [src] slams into \a [A]!",1,"You hear a loud slam!",2) + playsound(src.loc, "smash.ogg", 25, 1, -1) + . = ..() + +obj/item/airflow_hit(atom/A) + airflow_speed = 0 + airflow_dest = null + +mob/living/carbon/human/airflow_hit(atom/A) +// for(var/mob/M in hearers(src)) +// M.show_message("[src] slams into [A]!",1,"You hear a loud slam!",2) + playsound(src.loc, "punch", 25, 1, -1) + if (prob(33)) + loc:add_blood(src) + bloody_body(src) + var/b_loss = min(airflow_speed, (airborne_acceleration*2)) * vsc.airflow_damage + + var/blocked = run_armor_check(BP_HEAD,"melee") + apply_damage(b_loss/3, BRUTE, BP_HEAD, blocked, 0, "Airflow") + + blocked = run_armor_check(BP_CHEST,"melee") + apply_damage(b_loss/3, BRUTE, BP_CHEST, blocked, 0, "Airflow") + + blocked = run_armor_check(BP_GROIN,"melee") + apply_damage(b_loss/3, BRUTE, BP_GROIN, blocked, 0, "Airflow") + + if(airflow_speed > 10) + Paralyse(round(airflow_speed * vsc.airflow_stun)) + Stun(paralysis + 3) + else + Stun(round(airflow_speed * vsc.airflow_stun/2)) + . = ..() + +zone/proc/movables() + . = list() + for(var/turf/T in contents) + for(var/atom/movable/A in T) + if(!A.simulated || A.anchored || istype(A, /obj/effect) || isobserver(A)) + continue + . += A diff --git a/code/modules/ZAS/Atom.dm b/code/modules/ZAS/Atom.dm new file mode 100644 index 00000000..2bf7ef1c --- /dev/null +++ b/code/modules/ZAS/Atom.dm @@ -0,0 +1,80 @@ + +/atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) + //Purpose: Determines if the object (or airflow) can pass this atom. + //Called by: Movement, airflow. + //Inputs: The moving atom (optional), target turf, "height" and air group + //Outputs: Boolean if can pass. + + return (!density || !height || air_group) + +/turf/CanPass(atom/movable/mover, turf/target, height=1.5,air_group=0) + if(!target) return 0 + + if(istype(mover)) // turf/Enter(...) will perform more advanced checks + return !density + + else // Now, doing more detailed checks for air movement and air group formation + if(target.blocks_air||blocks_air) + return 0 + + for(var/obj/obstacle in src) + if(!obstacle.CanPass(mover, target, height, air_group)) + return 0 + if(target != src) + for(var/obj/obstacle in target) + if(!obstacle.CanPass(mover, src, height, air_group)) + return 0 + + return 1 + +//Convenience function for atoms to update turfs they occupy +/atom/movable/proc/update_nearby_tiles(need_rebuild) + for(var/turf/simulated/turf in locs) + SSair.mark_for_update(turf) + + return 1 + +//Basically another way of calling CanPass(null, other, 0, 0) and CanPass(null, other, 1.5, 1). +//Returns: +// 0 - Not blocked +// AIR_BLOCKED - Blocked +// ZONE_BLOCKED - Not blocked, but zone boundaries will not cross. +// BLOCKED - Blocked, zone boundaries will not cross even if opened. +atom/proc/c_airblock(turf/other) + #ifdef ZASDBG + ASSERT(isturf(other)) + #endif + return (AIR_BLOCKED*!CanPass(null, other, 0, 0))|(ZONE_BLOCKED*!CanPass(null, other, 1.5, 1)) + + +turf/c_airblock(turf/other) + #ifdef ZASDBG + ASSERT(isturf(other)) + #endif + if(((blocks_air & AIR_BLOCKED) || (other.blocks_air & AIR_BLOCKED))) + return BLOCKED + + //Z-level handling code. Always block if there isn't an open space. + #ifdef MULTIZAS + if(other.z != src.z) + if(other.z < src.z) + if(!istype(src, /turf/simulated/open)) return BLOCKED + else + if(!istype(other, /turf/simulated/open)) return BLOCKED + #endif + + if(((blocks_air & ZONE_BLOCKED) || (other.blocks_air & ZONE_BLOCKED))) + if(z == other.z) + return ZONE_BLOCKED + else + return AIR_BLOCKED + + var/result = 0 + for(var/mm in contents) + var/atom/movable/M = mm + result |= M.c_airblock(other) + if(result == BLOCKED) return BLOCKED + return result + +/atom/movable + var/atmos_canpass = CANPASS_ALWAYS diff --git a/code/modules/ZAS/Connection.dm b/code/modules/ZAS/Connection.dm new file mode 100644 index 00000000..17c8ea16 --- /dev/null +++ b/code/modules/ZAS/Connection.dm @@ -0,0 +1,168 @@ +#define CONNECTION_DIRECT 2 +#define CONNECTION_SPACE 4 +#define CONNECTION_INVALID 8 + +/* + +Overview: + Connections are made between turfs by SSair.connect(). They represent a single point where two zones converge. + +Class Vars: + A - Always a simulated turf. + B - A simulated or unsimulated turf. + + zoneA - The archived zone of A. Used to check that the zone hasn't changed. + zoneB - The archived zone of B. May be null in case of unsimulated connections. + + edge - Stores the edge this connection is in. Can reference an edge that is no longer processed + after this connection is removed, so make sure to check edge.coefficient > 0 before re-adding it. + +Class Procs: + + mark_direct() + Marks this connection as direct. Does not update the edge. + Called when the connection is made and there are no doors between A and B. + Also called by update() as a correction. + + mark_indirect() + Unmarks this connection as direct. Does not update the edge. + Called by update() as a correction. + + mark_space() + Marks this connection as unsimulated. Updating the connection will check the validity of this. + Called when the connection is made. + This will not be called as a correction, any connections failing a check against this mark are erased and rebuilt. + + direct() + Returns 1 if no doors are in between A and B. + + valid() + Returns 1 if the connection has not been erased. + + erase() + Called by update() and connection_manager/erase_all(). + Marks the connection as erased and removes it from its edge. + + update() + Called by connection_manager/update_all(). + Makes numerous checks to decide whether the connection is still valid. Erases it automatically if not. + +*/ + +/connection/var/turf/simulated/A +/connection/var/turf/simulated/B +/connection/var/zone/zoneA +/connection/var/zone/zoneB + +/connection/var/connection_edge/edge + +/connection/var/state = 0 + +/connection/New(turf/simulated/A, turf/simulated/B) + #ifdef ZASDBG + ASSERT(SSair.has_valid_zone(A)) + //ASSERT(SSair.has_valid_zone(B)) + #endif + src.A = A + src.B = B + zoneA = A.zone + if(!istype(B)) + mark_space() + edge = SSair.get_edge(A.zone,B) + edge.add_connection(src) + else + zoneB = B.zone + edge = SSair.get_edge(A.zone,B.zone) + edge.add_connection(src) + +/connection/proc/mark_direct() + if(!direct()) + state |= CONNECTION_DIRECT + edge.direct++ +// log_debug("Marked direct.") + +/connection/proc/mark_indirect() + if(direct()) + state &= ~CONNECTION_DIRECT + edge.direct-- +// log_debug("Marked indirect.") + +/connection/proc/mark_space() + state |= CONNECTION_SPACE + +/connection/proc/direct() + return (state & CONNECTION_DIRECT) + +/connection/proc/valid() + return !(state & CONNECTION_INVALID) + +/connection/proc/erase() + edge.remove_connection(src) + state |= CONNECTION_INVALID +// log_debug("Connection Erased: [state]") + +/connection/proc/update() +// log_debug("Updated, \...") + if(!istype(A,/turf/simulated)) +// log_debug("Invalid A.") + erase() + return + + var/block_status = SSair.air_blocked(A,B) + if(block_status & AIR_BLOCKED) +// log_debug("Blocked connection.") + erase() + return + else if(block_status & ZONE_BLOCKED) + mark_indirect() + else + mark_direct() + + var/b_is_space = !istype(B,/turf/simulated) + + if(state & CONNECTION_SPACE) + if(!b_is_space) +// log_debug("Invalid B.") + erase() + return + if(A.zone != zoneA) +// log_debug("Zone changed, \...") + if(!A.zone) + erase() +// log_debug("erased.") + return + else + edge.remove_connection(src) + edge = SSair.get_edge(A.zone, B) + edge.add_connection(src) + zoneA = A.zone + +// log_debug("valid.") + return + + else if(b_is_space) +// log_debug("Invalid B.") + erase() + return + + if(A.zone == B.zone) +// log_debug("A == B") + erase() + return + + if(A.zone != zoneA || (zoneB && (B.zone != zoneB))) + +// log_debug("Zones changed, \...") + if(A.zone && B.zone) + edge.remove_connection(src) + edge = SSair.get_edge(A.zone, B.zone) + edge.add_connection(src) + zoneA = A.zone + zoneB = B.zone + else +// log_debug("erased.") + erase() + return + + +// log_debug("valid.") \ No newline at end of file diff --git a/code/modules/ZAS/ConnectionGroup.dm b/code/modules/ZAS/ConnectionGroup.dm new file mode 100644 index 00000000..17249aae --- /dev/null +++ b/code/modules/ZAS/ConnectionGroup.dm @@ -0,0 +1,260 @@ +/* + +Overview: + These are what handle gas transfers between zones and into space. + They are found in a zone's edges list and in SSair.edges. + Each edge updates every air tick due to their role in gas transfer. + They come in two flavors, /connection_edge/zone and /connection_edge/unsimulated. + As the type names might suggest, they handle inter-zone and spacelike connections respectively. + +Class Vars: + + A - This always holds a zone. In unsimulated edges, it holds the only zone. + + connecting_turfs - This holds a list of connected turfs, mainly for the sake of airflow. + + coefficent - This is a marker for how many connections are on this edge. Used to determine the ratio of flow. + + connection_edge/zone + + B - This holds the second zone with which the first zone equalizes. + + direct - This counts the number of direct (i.e. with no doors) connections on this edge. + Any value of this is sufficient to make the zones mergeable. + + connection_edge/unsimulated + + B - This holds an unsimulated turf which has the gas values this edge is mimicing. + + air - Retrieved from B on creation and used as an argument for the legacy ShareSpace() proc. + +Class Procs: + + add_connection(connection/c) + Adds a connection to this edge. Usually increments the coefficient and adds a turf to connecting_turfs. + + remove_connection(connection/c) + Removes a connection from this edge. This works even if c is not in the edge, so be careful. + If the coefficient reaches zero as a result, the edge is erased. + + contains_zone(zone/Z) + Returns true if either A or B is equal to Z. Unsimulated connections return true only on A. + + erase() + Removes this connection from processing and zone edge lists. + + tick() + Called every air tick on edges in the processing list. Equalizes gas. + + flow(list/movable, differential, repelled) + Airflow proc causing all objects in movable to be checked against a pressure differential. + If repelled is true, the objects move away from any turf in connecting_turfs, otherwise they approach. + A check against vsc.lightest_airflow_pressure should generally be performed before calling this. + + get_connected_zone(zone/from) + Helper proc that allows getting the other zone of an edge given one of them. + Only on /connection_edge/zone, otherwise use A. + +*/ + + +/connection_edge/var/zone/A + +/connection_edge/var/list/connecting_turfs = list() +/connection_edge/var/direct = 0 +/connection_edge/var/sleeping = 1 + +/connection_edge/var/coefficient = 0 + +/connection_edge/New() + CRASH("Cannot make connection edge without specifications.") + +/connection_edge/proc/add_connection(connection/c) + coefficient++ + if(c.direct()) direct++ +// log_debug("Connection added: [type] Coefficient: [coefficient]") + + +/connection_edge/proc/remove_connection(connection/c) +// log_debug("Connection removed: [type] Coefficient: [coefficient-1]") + + coefficient-- + if(coefficient <= 0) + erase() + if(c.direct()) direct-- + +/connection_edge/proc/contains_zone(zone/Z) + +/connection_edge/proc/erase() + SSair.remove_edge(src) +// log_debug("[type] Erased.") + + +/connection_edge/proc/tick() + +/connection_edge/proc/recheck() + +/connection_edge/proc/flow(list/movable, differential, repelled) + for(var/i = 1; i <= movable.len; i++) + var/atom/movable/M = movable[i] + + //If they're already being tossed, don't do it again. + if(M.last_airflow > world.time - vsc.airflow_delay) continue + if(M.airflow_speed) continue + + //Check for knocking people over + if(ismob(M) && differential > vsc.airflow_stun_pressure) + if(M:status_flags & GODMODE) continue + M:airflow_stun() + + if(M.check_airflow_movable(differential)) + //Check for things that are in range of the midpoint turfs. + var/list/close_turfs = list() + for(var/turf/U in connecting_turfs) + if(get_dist(M,U) < world.view) close_turfs += U + if(!close_turfs.len) continue + + M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards. + + if(repelled) spawn if(M) M.RepelAirflowDest(differential/5) + else spawn if(M) M.GotoAirflowDest(differential/10) + + + + +/connection_edge/zone/var/zone/B + +/connection_edge/zone/New(zone/A, zone/B) + + src.A = A + src.B = B + A.edges.Add(src) + B.edges.Add(src) + //id = edge_id(A,B) +// log_debug("New edge between [A] and [B]") + + +/connection_edge/zone/add_connection(connection/c) + . = ..() + connecting_turfs.Add(c.A) + +/connection_edge/zone/remove_connection(connection/c) + connecting_turfs.Remove(c.A) + . = ..() + +/connection_edge/zone/contains_zone(zone/Z) + return A == Z || B == Z + +/connection_edge/zone/erase() + A.edges.Remove(src) + B.edges.Remove(src) + . = ..() + +/connection_edge/zone/tick() + if(A.invalid || B.invalid) + erase() + return + + var/equiv = A.air.share_ratio(B.air, coefficient) + + var/differential = A.air.return_pressure() - B.air.return_pressure() + if(abs(differential) >= vsc.airflow_lightest_pressure) + var/list/attracted + var/list/repelled + if(differential > 0) + attracted = A.movables() + repelled = B.movables() + else + attracted = B.movables() + repelled = A.movables() + + flow(attracted, abs(differential), 0) + flow(repelled, abs(differential), 1) + + if(equiv) + if(direct) + erase() + SSair.merge(A, B) + return + else + A.air.equalize(B.air) + SSair.mark_edge_sleeping(src) + + SSair.mark_zone_update(A) + SSair.mark_zone_update(B) + +/connection_edge/zone/recheck() + if(!A.air.compare(B.air, vacuum_exception = 1)) + // Edges with only one side being vacuum need processing no matter how close. + SSair.mark_edge_active(src) + +//Helper proc to get connections for a zone. +/connection_edge/zone/proc/get_connected_zone(zone/from) + if(A == from) return B + else return A + +/connection_edge/unsimulated/var/turf/B +/connection_edge/unsimulated/var/datum/gas_mixture/air + +/connection_edge/unsimulated/New(zone/A, turf/B) + src.A = A + src.B = B + A.edges.Add(src) + air = B.return_air() + //id = 52*A.id +// log_debug("New edge from [A] to [B].") + + +/connection_edge/unsimulated/add_connection(connection/c) + . = ..() + connecting_turfs.Add(c.B) + air.group_multiplier = coefficient + +/connection_edge/unsimulated/remove_connection(connection/c) + connecting_turfs.Remove(c.B) + air.group_multiplier = coefficient + . = ..() + +/connection_edge/unsimulated/erase() + A.edges.Remove(src) + . = ..() + +/connection_edge/unsimulated/contains_zone(zone/Z) + return A == Z + +/connection_edge/unsimulated/tick() + if(A.invalid) + erase() + return + + var/equiv = A.air.share_space(air) + + var/differential = A.air.return_pressure() - air.return_pressure() + if(abs(differential) >= vsc.airflow_lightest_pressure) + var/list/attracted = A.movables() + flow(attracted, abs(differential), differential < 0) + + if(equiv) + A.air.copy_from(air) + SSair.mark_edge_sleeping(src) + + SSair.mark_zone_update(A) + +/connection_edge/unsimulated/recheck() + // Edges with only one side being vacuum need processing no matter how close. + // Note: This handles the glaring flaw of a room holding pressure while exposed to space, but + // does not specially handle the less common case of a simulated room exposed to an unsimulated pressurized turf. + if(!A.air.compare(air, vacuum_exception = 1)) + SSair.mark_edge_active(src) + +proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) + //This implements a simplistic version of the Stefan-Boltzmann law. + var/energy_delta = ((A.temperature - B.temperature) ** 4) * STEFAN_BOLTZMANN_CONSTANT * connecting_tiles * 2.5 + var/maximum_energy_delta = max(0, min(A.temperature * A.heat_capacity() * A.group_multiplier, B.temperature * B.heat_capacity() * B.group_multiplier)) + if(maximum_energy_delta > abs(energy_delta)) + if(energy_delta < 0) + maximum_energy_delta *= -1 + energy_delta = maximum_energy_delta + + A.temperature -= energy_delta / (A.heat_capacity() * A.group_multiplier) + B.temperature += energy_delta / (B.heat_capacity() * B.group_multiplier) diff --git a/code/modules/ZAS/ConnectionManager.dm b/code/modules/ZAS/ConnectionManager.dm new file mode 100644 index 00000000..3890cd85 --- /dev/null +++ b/code/modules/ZAS/ConnectionManager.dm @@ -0,0 +1,105 @@ +/* + +Overview: + The connection_manager class stores connections in each cardinal direction on a turf. + It isn't always present if a turf has no connections, check if(connections) before using. + Contains procs for mass manipulation of connection data. + +Class Vars: + + NSEWUD - Connections to this turf in each cardinal direction. + +Class Procs: + + get(d) + Returns the connection (if any) in this direction. + Preferable to accessing the connection directly because it checks validity. + + place(connection/c, d) + Called by air_master.connect(). Sets the connection in the specified direction to c. + + update_all() + Called after turf/update_air_properties(). Updates the validity of all connections on this turf. + + erase_all() + Called when the turf is changed with ChangeTurf(). Erases all existing connections. + +Macros: + check(connection/c) + Checks for connection validity. It's possible to have a reference to a connection that has been erased. + + +*/ + +// macro-ized to cut down on proc calls +#define check(c) (c && c.valid()) + +/turf/var/tmp/connection_manager/connections + +/connection_manager/var/connection/N +/connection_manager/var/connection/S +/connection_manager/var/connection/E +/connection_manager/var/connection/W + +#ifdef MULTIZAS +/connection_manager/var/connection/U +/connection_manager/var/connection/D +#endif + +/connection_manager/proc/get(d) + switch(d) + if(NORTH) + if(check(N)) return N + else return null + if(SOUTH) + if(check(S)) return S + else return null + if(EAST) + if(check(E)) return E + else return null + if(WEST) + if(check(W)) return W + else return null + + #ifdef MULTIZAS + if(UP) + if(check(U)) return U + else return null + if(DOWN) + if(check(D)) return D + else return null + #endif + +/connection_manager/proc/place(connection/c, d) + switch(d) + if(NORTH) N = c + if(SOUTH) S = c + if(EAST) E = c + if(WEST) W = c + + #ifdef MULTIZAS + if(UP) U = c + if(DOWN) D = c + #endif + +/connection_manager/proc/update_all() + if(check(N)) N.update() + if(check(S)) S.update() + if(check(E)) E.update() + if(check(W)) W.update() + #ifdef MULTIZAS + if(check(U)) U.update() + if(check(D)) D.update() + #endif + +/connection_manager/proc/erase_all() + if(check(N)) N.erase() + if(check(S)) S.erase() + if(check(E)) E.erase() + if(check(W)) W.erase() + #ifdef MULTIZAS + if(check(U)) U.erase() + if(check(D)) D.erase() + #endif + +#undef check diff --git a/code/modules/ZAS/Debug.dm b/code/modules/ZAS/Debug.dm new file mode 100644 index 00000000..6f0a67fd --- /dev/null +++ b/code/modules/ZAS/Debug.dm @@ -0,0 +1,20 @@ +var/image/assigned = image('icons/Testing/Zone.dmi', icon_state = "assigned") +var/image/created = image('icons/Testing/Zone.dmi', icon_state = "created") +var/image/merged = image('icons/Testing/Zone.dmi', icon_state = "merged") +var/image/invalid_zone = image('icons/Testing/Zone.dmi', icon_state = "invalid") +var/image/air_blocked = image('icons/Testing/Zone.dmi', icon_state = "block") +var/image/zone_blocked = image('icons/Testing/Zone.dmi', icon_state = "zoneblock") +var/image/blocked = image('icons/Testing/Zone.dmi', icon_state = "fullblock") +var/image/mark = image('icons/Testing/Zone.dmi', icon_state = "mark") + +/connection_edge/var/dbg_out = 0 + +/turf/var/tmp/dbg_img +/turf/proc/dbg(image/img, d = 0) + if(d > 0) img.dir = d + overlays -= dbg_img + overlays += img + dbg_img = img + +proc/soft_assert(thing,fail) + if(!thing) message_admins(fail) \ No newline at end of file diff --git a/code/modules/ZAS/Diagnostic.dm b/code/modules/ZAS/Diagnostic.dm new file mode 100644 index 00000000..4433dfef --- /dev/null +++ b/code/modules/ZAS/Diagnostic.dm @@ -0,0 +1,82 @@ +client/proc/Zone_Info(turf/T as null|turf) + set category = "Debug" + if(T) + if(istype(T,/turf/simulated) && T:zone) + T:zone:dbg_data(src) + else + to_chat(mob, "No zone here.") + var/datum/gas_mixture/mix = T.return_air() + to_chat(mob, "[mix.return_pressure()] kPa [mix.temperature]C") + for(var/g in mix.gas) + to_chat(mob, "[g]: [mix.gas[g]]\n") + else + if(zone_debug_images) + for(var/zone in zone_debug_images) + images -= zone_debug_images[zone] + zone_debug_images = null + +client/var/list/zone_debug_images + +client/proc/Test_ZAS_Connection(var/turf/simulated/T as turf) + set category = "Debug" + if(!istype(T)) + return + + var/direction_list = list(\ + "North" = NORTH,\ + "South" = SOUTH,\ + "East" = EAST,\ + "West" = WEST,\ + #ifdef MULTIZAS + "Up" = UP,\ + "Down" = DOWN,\ + #endif + "N/A" = null) + var/direction = input("What direction do you wish to test?","Set direction") as null|anything in direction_list + if(!direction) + return + + if(direction == "N/A") + if(!(T.c_airblock(T) & AIR_BLOCKED)) + to_chat(mob, "The turf can pass air! :D") + else + to_chat(mob, "No air passage :x") + return + + var/turf/simulated/other_turf = get_step(T, direction_list[direction]) + if(!istype(other_turf)) + return + + var/t_block = T.c_airblock(other_turf) + var/o_block = other_turf.c_airblock(T) + + if(o_block & AIR_BLOCKED) + if(t_block & AIR_BLOCKED) + to_chat(mob, "Neither turf can connect. :(") + + else + to_chat(mob, "The initial turf only can connect. :\\") + else + if(t_block & AIR_BLOCKED) + to_chat(mob, "The other turf can connect, but not the initial turf. :/") + + else + to_chat(mob, "Both turfs can connect! :)") + + to_chat(mob, "Additionally, \...") + + if(o_block & ZONE_BLOCKED) + if(t_block & ZONE_BLOCKED) + to_chat(mob, "neither turf can merge.") + else + to_chat(mob, "the other turf cannot merge.") + else + if(t_block & ZONE_BLOCKED) + to_chat(mob, "the initial turf cannot merge.") + else + to_chat(mob, "both turfs can merge.") + +client/proc/ZASSettings() + set category = "Debug" + + vsc.SetDefault(mob) diff --git a/code/modules/ZAS/Fire.dm b/code/modules/ZAS/Fire.dm new file mode 100644 index 00000000..f3aac4f4 --- /dev/null +++ b/code/modules/ZAS/Fire.dm @@ -0,0 +1,442 @@ +/* + +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. +*/ + +//#define FIREDBG + +/turf/var/obj/fire/fire = null + +//Some legacy definitions so fires can be started. +atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + return null + + +turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0) + + +/turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) + if(fire_protection > world.time-300) + return 0 + if(locate(/obj/fire) in src) + return 1 + var/datum/gas_mixture/air_contents = return_air() + if(!air_contents || exposed_temperature < PHORON_MINIMUM_BURN_TEMPERATURE) + return 0 + + var/igniting = 0 + var/obj/effect/decal/cleanable/liquid_fuel/liquid = locate() in src + + if(air_contents.check_combustability(liquid)) + igniting = 1 + + create_fire(exposed_temperature) + return igniting + +/zone/proc/process_fire() + var/datum/gas_mixture/burn_gas = air.remove_ratio(vsc.fire_consuption_rate, fire_tiles.len) + + var/firelevel = burn_gas.zburn(src, fire_tiles, force_burn = 1, no_check = 1) + + air.merge(burn_gas) + + if(firelevel) + for(var/turf/T in fire_tiles) + if(T.fire) + T.fire.firelevel = firelevel + else + var/obj/effect/decal/cleanable/liquid_fuel/fuel = locate() in T + fire_tiles -= T + fuel_objs -= fuel + else + for(var/turf/simulated/T in fire_tiles) + if(istype(T.fire)) + T.fire.RemoveFire() + T.fire = null + fire_tiles.Cut() + fuel_objs.Cut() + + if(!fire_tiles.len) + SSair.active_fire_zones.Remove(src) + +/zone/proc/remove_liquidfuel(var/used_liquid_fuel, var/remove_fire=0) + if(!fuel_objs.len) + return + + //As a simplification, we remove fuel equally from all fuel sources. It might be that some fuel sources have more fuel, + //some have less, but whatever. It will mean that sometimes we will remove a tiny bit less fuel then we intended to. + + var/fuel_to_remove = used_liquid_fuel/(fuel_objs.len*LIQUIDFUEL_AMOUNT_TO_MOL) //convert back to liquid volume units + + for(var/O in fuel_objs) + var/obj/effect/decal/cleanable/liquid_fuel/fuel = O + if(!istype(fuel)) + fuel_objs -= fuel + continue + + fuel.amount -= fuel_to_remove + if(fuel.amount <= 0) + fuel_objs -= fuel + if(remove_fire) + var/turf/T = fuel.loc + if(istype(T) && T.fire) qdel(T.fire) + qdel(fuel) + +/turf/proc/create_fire(fl) + return 0 + +/turf/simulated/create_fire(fl) + if(fire) + fire.firelevel = max(fl, fire.firelevel) + return 1 + + if(!zone) + return 1 + + fire = new(src, fl) + SSair.active_fire_zones |= zone + + var/obj/effect/decal/cleanable/liquid_fuel/fuel = locate() in src + zone.fire_tiles |= src + if(fuel) zone.fuel_objs += fuel + + return 0 + +/obj/fire + //Icon for fire on turfs. + + anchored = 1 + mouse_opacity = 0 + + blend_mode = BLEND_ADD + + icon = 'icons/effects/fire.dmi' + icon_state = "1" + light_color = "#ed9200" + plane = EFFECTS_BELOW_LIGHTING_PLANE + layer = FIRE_LAYER + + var/firelevel = 1 //Calculated by gas_mixture.calculate_firelevel() + +/obj/fire/Process() + . = 1 + + var/turf/simulated/my_tile = loc + if(!istype(my_tile) || !my_tile.zone) + if(my_tile && my_tile.fire == src) + my_tile.fire = null + RemoveFire() + return 1 + + var/datum/gas_mixture/air_contents = my_tile.return_air() + + if(firelevel > 6) + icon_state = "3" + set_light(7, 3) + else if(firelevel > 2.5) + icon_state = "2" + set_light(5, 2) + else + icon_state = "1" + set_light(3, 1) + + for(var/mob/living/L in loc) + L.FireBurn(firelevel, air_contents.temperature, air_contents.return_pressure()) //Burn the mobs! + + loc.fire_act(air_contents, air_contents.temperature, air_contents.volume) + for(var/atom/A in loc) + A.fire_act(air_contents, air_contents.temperature, air_contents.volume) + + //spread + for(var/direction in GLOB.cardinal) + var/turf/simulated/enemy_tile = get_step(my_tile, direction) + + if(istype(enemy_tile)) + if(my_tile.open_directions & direction) //Grab all valid bordering tiles + if(!enemy_tile.zone || enemy_tile.fire) + continue + + //if(!enemy_tile.zone.fire_tiles.len) TODO - optimize + var/datum/gas_mixture/acs = enemy_tile.return_air() + var/obj/effect/decal/cleanable/liquid_fuel/liquid = locate() in enemy_tile + if(!acs || !acs.check_combustability(liquid)) + continue + + //If extinguisher mist passed over the turf it's trying to spread to, don't spread and + //reduce firelevel. + if(enemy_tile.fire_protection > world.time-30) + firelevel -= 1.5 + continue + + //Spread the fire. + if(prob( 50 + 50 * (firelevel/vsc.fire_firelevel_multiplier) ) && my_tile.CanPass(null, enemy_tile, 0,0) && enemy_tile.CanPass(null, my_tile, 0,0)) + enemy_tile.create_fire(firelevel) + + else + enemy_tile.adjacent_fire_act(loc, air_contents, air_contents.temperature, air_contents.volume) + + animate(src, color = fire_color(air_contents.temperature), 5) + set_light(l_color = color) + +/obj/fire/New(newLoc,fl) + ..() + + if(!istype(loc, /turf)) + qdel(src) + return + + set_dir(pick(GLOB.cardinal)) + + var/datum/gas_mixture/air_contents = loc.return_air() + color = fire_color(air_contents.temperature) + set_light(3, 1, color) + + firelevel = fl + SSair.active_hotspots.Add(src) + + //When a fire is created, immediately call fire_act on things in the tile. + //This is needed for flamethrowers + for (var/a in loc) + var/atom/A = a + A.fire_act() + +/obj/fire/proc/fire_color(var/env_temperature) + var/temperature = max(4000*sqrt(firelevel/vsc.fire_firelevel_multiplier), env_temperature) + return heat2color(temperature) + +/obj/fire/Destroy() + RemoveFire() + + . = ..() + +/obj/fire/proc/RemoveFire() + var/turf/T = loc + if (istype(T)) + set_light(0) + + T.fire = null + loc = null + SSair.active_hotspots.Remove(src) + + +/turf/simulated/var/fire_protection = 0 //Protects newly extinguished tiles from being overrun again. +/turf/proc/apply_fire_protection() +/turf/simulated/apply_fire_protection() + fire_protection = world.time + +//Returns the firelevel +/datum/gas_mixture/proc/zburn(zone/zone, force_burn, no_check = 0) + . = 0 + if((temperature > PHORON_MINIMUM_BURN_TEMPERATURE || force_burn) && (no_check ||check_recombustability(zone? zone.fuel_objs : null))) + + #ifdef FIREDBG + log_debug("***************** FIREDBG *****************") + log_debug("Burning [zone? zone.name : "zoneless gas_mixture"]!") + #endif + + var/gas_fuel = 0 + var/liquid_fuel = 0 + var/total_fuel = 0 + var/total_oxidizers = 0 + + //*** Get the fuel and oxidizer amounts + for(var/g in gas) + if(gas_data.flags[g] & XGM_GAS_FUEL) + gas_fuel += gas[g] + if(gas_data.flags[g] & XGM_GAS_OXIDIZER) + total_oxidizers += gas[g] + gas_fuel *= group_multiplier + total_oxidizers *= group_multiplier + + //Liquid Fuel + var/fuel_area = 0 + if(zone) + for(var/obj/effect/decal/cleanable/liquid_fuel/fuel in zone.fuel_objs) + liquid_fuel += fuel.amount*LIQUIDFUEL_AMOUNT_TO_MOL + fuel_area++ + + total_fuel = gas_fuel + liquid_fuel + if(total_fuel <= 0.005) + return 0 + + //*** Determine how fast the fire burns + + //get the current thermal energy of the gas mix + //this must be taken here to prevent the addition or deletion of energy by a changing heat capacity + var/starting_energy = temperature * heat_capacity() + + //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 + + //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) + + //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/total_reaction_progress = gas_reaction_progress + liquid_reaction_progress + var/used_fuel = min(total_reaction_progress, reaction_limit) + var/used_oxidizers = used_fuel*(FIRE_REACTION_OXIDIZER_AMOUNT/FIRE_REACTION_FUEL_AMOUNT) + + #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("liquid_reaction_progress = [liquid_reaction_progress]") + log_debug("gas_reaction_progress = [gas_reaction_progress]") + log_debug("total_reaction_progress = [total_reaction_progress]") + log_debug("used_fuel = [used_fuel], used_oxidizers = [used_oxidizers]; ") + #endif + + //if the reaction is progressing too slow then it isn't self-sustaining anymore and burns out + if(zone) //be less restrictive with canister and tank reactions + if((!liquid_fuel || used_fuel <= FIRE_LIQUD_MIN_BURNRATE) && (!gas_fuel || used_fuel <= FIRE_GAS_MIN_BURNRATE*zone.contents.len)) + return 0 + + + //*** Remove fuel and oxidizer, add carbon dioxide and heat + + //remove and add gasses as calculated + var/used_gas_fuel = min(max(0.25, used_fuel*(gas_reaction_progress/total_reaction_progress)), gas_fuel) //remove in proportion to the relative reaction progress + var/used_liquid_fuel = min(max(0.25, used_fuel-used_gas_fuel), liquid_fuel) + + //remove_by_flag() and adjust_gas() handle the group_multiplier for us. + remove_by_flag(XGM_GAS_OXIDIZER, used_oxidizers) + var/datum/gas_mixture/burned_fuel = remove_by_flag(XGM_GAS_FUEL, used_gas_fuel) + for(var/g in burned_fuel.gas) + adjust_gas(gas_data.burn_product[g], burned_fuel.gas[g]) + + if(zone) + zone.remove_liquidfuel(used_liquid_fuel, !check_combustability()) + + //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()]") + #endif + + return firelevel + +datum/gas_mixture/proc/check_recombustability(list/fuel_objs) + . = 0 + for(var/g in gas) + if(gas_data.flags[g] & XGM_GAS_OXIDIZER && gas[g] >= 0.1) + . = 1 + break + + if(!.) + return 0 + + if(fuel_objs && fuel_objs.len) + return 1 + + . = 0 + for(var/g in gas) + if(gas_data.flags[g] & XGM_GAS_FUEL && gas[g] >= 0.1) + . = 1 + break + +/datum/gas_mixture/proc/check_combustability(obj/effect/decal/cleanable/liquid_fuel/liquid=null) + . = 0 + for(var/g in gas) + if(gas_data.flags[g] & XGM_GAS_OXIDIZER && QUANTIZE(gas[g] * vsc.fire_consuption_rate) >= 0.1) + . = 1 + break + + if(!.) + return 0 + + if(liquid) + return 1 + + . = 0 + for(var/g in gas) + if(gas_data.flags[g] & XGM_GAS_FUEL && QUANTIZE(gas[g] * vsc.fire_consuption_rate) >= 0.1) + . = 1 + 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) + //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) + + //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. + var/mix_multiplier = 1 / (1 + (5 * ((total_fuel / total_combustables) ** 2))) + + #ifdef FIREDBG + ASSERT(damping_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 + + return max( 0, firelevel) + + +/mob/living/proc/FireBurn(var/firelevel, var/last_temperature, var/pressure) + var/mx = 5 * firelevel/vsc.fire_firelevel_multiplier * min(pressure / ONE_ATMOSPHERE, 1) + apply_damage(2.5*mx, BURN) + + +/mob/living/carbon/human/FireBurn(var/firelevel, var/last_temperature, var/pressure) + //Burns mobs due to fire. Respects heat transfer coefficients on various body parts. + //Due to TG reworking how fireprotection works, this is kinda less meaningful. + + var/head_exposure = 1 + var/chest_exposure = 1 + var/groin_exposure = 1 + var/legs_exposure = 1 + var/arms_exposure = 1 + + //Get heat transfer coefficients for clothing. + + for(var/obj/item/clothing/C in src) + if(l_hand == C || r_hand == C) + continue + + if( C.max_heat_protection_temperature >= last_temperature ) + if(C.body_parts_covered & HEAD) + head_exposure = 0 + if(C.body_parts_covered & UPPER_TORSO) + chest_exposure = 0 + if(C.body_parts_covered & LOWER_TORSO) + groin_exposure = 0 + if(C.body_parts_covered & LEGS) + legs_exposure = 0 + if(C.body_parts_covered & ARMS) + arms_exposure = 0 + //minimize this for low-pressure enviroments + var/mx = 5 * firelevel/vsc.fire_firelevel_multiplier * min(pressure / ONE_ATMOSPHERE, 1) + + //Always check these damage procs first if fire damage isn't working. They're probably what's wrong. + + apply_damage(2.5*mx*head_exposure, BURN, BP_HEAD, 0, 0, "Fire") + apply_damage(2.5*mx*chest_exposure, BURN, BP_CHEST, 0, 0, "Fire") + apply_damage(2.0*mx*groin_exposure, BURN, BP_GROIN, 0, 0, "Fire") + apply_damage(0.6*mx*legs_exposure, BURN, BP_L_LEG, 0, 0, "Fire") + apply_damage(0.6*mx*legs_exposure, BURN, BP_R_LEG, 0, 0, "Fire") + apply_damage(0.4*mx*arms_exposure, BURN, BP_L_ARM, 0, 0, "Fire") + apply_damage(0.4*mx*arms_exposure, BURN, BP_R_ARM, 0, 0, "Fire") diff --git a/code/modules/ZAS/Phoron.dm b/code/modules/ZAS/Phoron.dm new file mode 100644 index 00000000..49acff43 --- /dev/null +++ b/code/modules/ZAS/Phoron.dm @@ -0,0 +1,170 @@ +var/image/contamination_overlay = image('icons/effects/contamination.dmi') + +/pl_control + var/PHORON_DMG = 3 + var/PHORON_DMG_NAME = "Phoron Damage Amount" + var/PHORON_DMG_DESC = "Self Descriptive" + + var/CLOTH_CONTAMINATION = 1 + var/CLOTH_CONTAMINATION_NAME = "Cloth Contamination" + var/CLOTH_CONTAMINATION_DESC = "If this is on, phoron does damage by getting into cloth." + + var/PHORONGUARD_ONLY = 0 + var/PHORONGUARD_ONLY_NAME = "\"PhoronGuard Only\"" + var/PHORONGUARD_ONLY_DESC = "If this is on, only biosuits and spacesuits protect against contamination and ill effects." + + var/GENETIC_CORRUPTION = 0 + var/GENETIC_CORRUPTION_NAME = "Genetic Corruption Chance" + var/GENETIC_CORRUPTION_DESC = "Chance of genetic corruption as well as toxic damage, X in 10,000." + + var/SKIN_BURNS = 0 + var/SKIN_BURNS_DESC = "Phoron has an effect similar to mustard gas on the un-suited." + var/SKIN_BURNS_NAME = "Skin Burns" + + var/EYE_BURNS = 1 + var/EYE_BURNS_NAME = "Eye Burns" + var/EYE_BURNS_DESC = "Phoron burns the eyes of anyone not wearing eye protection." + + var/CONTAMINATION_LOSS = 0.02 + var/CONTAMINATION_LOSS_NAME = "Contamination Loss" + var/CONTAMINATION_LOSS_DESC = "How much toxin damage is dealt from contaminated clothing" //Per tick? ASK ARYN + + var/PHORON_HALLUCINATION = 0 + var/PHORON_HALLUCINATION_NAME = "Phoron Hallucination" + var/PHORON_HALLUCINATION_DESC = "Does being in phoron cause you to hallucinate?" + + var/N2O_HALLUCINATION = 1 + var/N2O_HALLUCINATION_NAME = "N2O Hallucination" + var/N2O_HALLUCINATION_DESC = "Does being in sleeping gas cause you to hallucinate?" + + +obj/var/contaminated = 0 + + +/obj/item/proc/can_contaminate() + //Clothing and backpacks can be contaminated. + if(obj_flags & ITEM_FLAG_PHORONGUARD) return 0 + else if(istype(src,/obj/item/weapon/storage/backpack)) return 0 //Cannot be washed :( + else if(istype(src,/obj/item/clothing)) return 1 + +/obj/item/proc/contaminate() + //Do a contamination overlay? Temporary measure to keep contamination less deadly than it was. + if(!contaminated) + contaminated = 1 + overlays += contamination_overlay + +/obj/item/proc/decontaminate() + contaminated = 0 + overlays -= contamination_overlay + +/mob/proc/contaminate() + +/mob/living/carbon/human/contaminate() + //See if anything can be contaminated. + + if(!pl_suit_protected()) + suit_contamination() + + if(!pl_head_protected()) + if(prob(1)) suit_contamination() //Phoron can sometimes get through such an open suit. + +//Cannot wash backpacks currently. +// if(istype(back,/obj/item/weapon/storage/backpack)) +// back.contaminate() + +/mob/proc/pl_effects() + +/mob/living/carbon/human/pl_effects() + //Handles all the bad things phoron can do. + + //Contamination + if(vsc.plc.CLOTH_CONTAMINATION) contaminate() + + //Anything else requires them to not be dead. + if(stat >= 2) + return + + //Burn skin if exposed. + if(vsc.plc.SKIN_BURNS) + if(!pl_head_protected() || !pl_suit_protected()) + burn_skin(0.75) + if(prob(20)) to_chat(src, "Your skin burns!") + updatehealth() + + //Burn eyes if exposed. + if(vsc.plc.EYE_BURNS) + if(!head) + if(!wear_mask) + burn_eyes() + else + if(!(wear_mask.body_parts_covered & EYES)) + burn_eyes() + else + if(!(head.body_parts_covered & EYES)) + if(!wear_mask) + burn_eyes() + else + if(!(wear_mask.body_parts_covered & EYES)) + burn_eyes() + + //Genetic Corruption + if(vsc.plc.GENETIC_CORRUPTION) + if(rand(1,10000) < vsc.plc.GENETIC_CORRUPTION) + randmutb(src) + to_chat(src, "High levels of toxins cause you to spontaneously mutate!") + domutcheck(src,null) + + +/mob/living/carbon/human/proc/burn_eyes() + var/obj/item/organ/internal/eyes/E = internal_organs_by_name[BP_EYES] + if(E && !E.phoron_guard) + if(prob(20)) to_chat(src, "Your eyes burn!") + E.damage += 2.5 + eye_blurry = min(eye_blurry+1.5,50) + if (prob(max(0,E.damage - 15) + 1) &&!eye_blind) + to_chat(src, "You are blinded!") + eye_blind += 20 + +/mob/living/carbon/human/proc/pl_head_protected() + //Checks if the head is adequately sealed. + if(head) + if(vsc.plc.PHORONGUARD_ONLY) + if(head.item_flags & ITEM_FLAG_PHORONGUARD) + return 1 + else if(head.body_parts_covered & EYES) + return 1 + return 0 + +/mob/living/carbon/human/proc/pl_suit_protected() + //Checks if the suit is adequately sealed. + var/coverage = 0 + for(var/obj/item/protection in list(wear_suit, gloves, shoes)) + if(!protection) + continue + if(vsc.plc.PHORONGUARD_ONLY && !(protection.item_flags & ITEM_FLAG_PHORONGUARD)) + return 0 + coverage |= protection.body_parts_covered + + if(vsc.plc.PHORONGUARD_ONLY) + return 1 + + return BIT_TEST_ALL(coverage, UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS) + +/mob/living/carbon/human/proc/suit_contamination() + //Runs over the things that can be contaminated and does so. + if(w_uniform) w_uniform.contaminate() + if(shoes) shoes.contaminate() + if(gloves) gloves.contaminate() + + +turf/Entered(obj/item/I) + . = ..() + //Items that are in phoron, but not on a mob, can still be contaminated. + if(istype(I) && vsc && vsc.plc.CLOTH_CONTAMINATION && I.can_contaminate()) + var/datum/gas_mixture/env = return_air(1) + if(!env) + return + for(var/g in env.gas) + if(gas_data.flags[g] & XGM_GAS_CONTAMINANT && env.gas[g] > gas_data.overlay_limit[g] + 1) + I.contaminate() + break diff --git a/code/modules/ZAS/Turf.dm b/code/modules/ZAS/Turf.dm new file mode 100644 index 00000000..e92af63e --- /dev/null +++ b/code/modules/ZAS/Turf.dm @@ -0,0 +1,291 @@ +/turf/simulated/var/zone/zone +/turf/simulated/var/open_directions + +/turf/var/needs_air_update = 0 +/turf/var/datum/gas_mixture/air + +/turf/simulated/proc/update_graphic(list/graphic_add = null, list/graphic_remove = null) + if(graphic_add && graphic_add.len) + overlays += graphic_add + if(graphic_remove && graphic_remove.len) + overlays -= graphic_remove + +/turf/proc/update_air_properties() + var/block = c_airblock(src) + if(block & AIR_BLOCKED) + //dbg(blocked) + return 1 + + #ifdef MULTIZAS + for(var/d = 1, d < 64, d *= 2) + #else + for(var/d = 1, d < 16, d *= 2) + #endif + + var/turf/unsim = get_step(src, d) + + if(!unsim) + continue + + block = unsim.c_airblock(src) + + if(block & AIR_BLOCKED) + //unsim.dbg(air_blocked, turn(180,d)) + continue + + var/r_block = c_airblock(unsim) + + if(r_block & AIR_BLOCKED) + continue + + if(istype(unsim, /turf/simulated)) + + var/turf/simulated/sim = unsim + if(TURF_HAS_VALID_ZONE(sim)) + SSair.connect(sim, src) + +/* + Simple heuristic for determining if removing the turf from it's zone will not partition the zone (A very bad thing). + Instead of analyzing the entire zone, we only check the nearest 3x3 turfs surrounding the src turf. + This implementation may produce false negatives but it (hopefully) will not produce any false postiives. +*/ + +/turf/simulated/proc/can_safely_remove_from_zone() + if(!zone) return 1 + + var/check_dirs = get_zone_neighbours(src) + var/unconnected_dirs = check_dirs + + #ifdef MULTIZAS + var/to_check = GLOB.cornerdirsz + #else + var/to_check = GLOB.cornerdirs + #endif + + for(var/dir in to_check) + + //for each pair of "adjacent" cardinals (e.g. NORTH and WEST, but not NORTH and SOUTH) + if((dir & check_dirs) == dir) + //check that they are connected by the corner turf + var/connected_dirs = get_zone_neighbours(get_step(src, dir)) + if(connected_dirs && (dir & GLOB.reverse_dir[connected_dirs]) == dir) + unconnected_dirs &= ~dir //they are, so unflag the cardinals in question + + //it is safe to remove src from the zone if all cardinals are connected by corner turfs + return !unconnected_dirs + +//helper for can_safely_remove_from_zone() +/turf/simulated/proc/get_zone_neighbours(turf/simulated/T) + . = 0 + if(istype(T) && T.zone) + #ifdef MULTIZAS + var/to_check = GLOB.cardinalz + #else + var/to_check = GLOB.cardinal + #endif + for(var/dir in to_check) + var/turf/simulated/other = get_step(T, dir) + if(istype(other) && other.zone == T.zone && !(other.c_airblock(T) & AIR_BLOCKED) && get_dist(src, other) <= 1) + . |= dir + +/turf/simulated/update_air_properties() + + if(zone && zone.invalid) //this turf's zone is in the process of being rebuilt + c_copy_air() //not very efficient :( + zone = null //Easier than iterating through the list at the zone. + + var/s_block = c_airblock(src) + if(s_block & AIR_BLOCKED) + #ifdef ZASDBG + if(verbose) log_debug("Self-blocked.") + //dbg(blocked) + #endif + if(zone) + var/zone/z = zone + + if(can_safely_remove_from_zone()) //Helps normal airlocks avoid rebuilding zones all the time + c_copy_air() //we aren't rebuilding, but hold onto the old air so it can be readded + z.remove(src) + else + z.rebuild() + + return 1 + + var/previously_open = open_directions + open_directions = 0 + + var/list/postponed + #ifdef MULTIZAS + for(var/d = 1, d < 64, d *= 2) + #else + for(var/d = 1, d < 16, d *= 2) + #endif + + var/turf/unsim = get_step(src, d) + + if(!unsim) //edge of map + continue + + var/block = unsim.c_airblock(src) + if(block & AIR_BLOCKED) + + #ifdef ZASDBG + if(verbose) log_debug("[d] is blocked.") + //unsim.dbg(air_blocked, turn(180,d)) + #endif + + continue + + var/r_block = c_airblock(unsim) + if(r_block & AIR_BLOCKED) + + #ifdef ZASDBG + if(verbose) log_debug("[d] is blocked.") + //dbg(air_blocked, d) + #endif + + //Check that our zone hasn't been cut off recently. + //This happens when windows move or are constructed. We need to rebuild. + if((previously_open & d) && istype(unsim, /turf/simulated)) + var/turf/simulated/sim = unsim + if(zone && sim.zone == zone) + zone.rebuild() + return + + continue + + open_directions |= d + + if(istype(unsim, /turf/simulated)) + + var/turf/simulated/sim = unsim + sim.open_directions |= GLOB.reverse_dir[d] + + if(TURF_HAS_VALID_ZONE(sim)) + + //Might have assigned a zone, since this happens for each direction. + if(!zone) + + //We do not merge if + // they are blocking us and we are not blocking them, or if + // we are blocking them and not blocking ourselves - this prevents tiny zones from forming on doorways. + if(((block & ZONE_BLOCKED) && !(r_block & ZONE_BLOCKED)) || ((r_block & ZONE_BLOCKED) && !(s_block & ZONE_BLOCKED))) + #ifdef ZASDBG + if(verbose) log_debug("[d] is zone blocked.") + + //dbg(zone_blocked, d) + #endif + + //Postpone this tile rather than exit, since a connection can still be made. + if(!postponed) postponed = list() + postponed.Add(sim) + + else + + sim.zone.add(src) + + #ifdef ZASDBG + dbg(assigned) + if(verbose) log_debug("Added to [zone]") + #endif + + else if(sim.zone != zone) + + #ifdef ZASDBG + if(verbose) log_debug("Connecting to [sim.zone]") + #endif + + SSair.connect(src, sim) + + + #ifdef ZASDBG + else if(verbose) log_debug("[d] has same zone.") + + else if(verbose) log_debug("[d] has invalid zone.") + #endif + + else + + //Postponing connections to tiles until a zone is assured. + if(!postponed) postponed = list() + postponed.Add(unsim) + + if(!TURF_HAS_VALID_ZONE(src)) //Still no zone, make a new one. + var/zone/newzone = new/zone() + newzone.add(src) + + #ifdef ZASDBG + dbg(created) + + ASSERT(zone) + #endif + + //At this point, a zone should have happened. If it hasn't, don't add more checks, fix the bug. + + for(var/turf/T in postponed) + SSair.connect(src, T) + +/turf/proc/post_update_air_properties() + if(connections) connections.update_all() + +/turf/assume_air(datum/gas_mixture/giver) //use this for machines to adjust air + return 0 + +/turf/proc/assume_gas(gasid, moles, temp = 0) + return 0 + +/turf/return_air() + //Create gas mixture to hold data for passing + var/datum/gas_mixture/GM = new + + if(initial_gas) + GM.gas = initial_gas.Copy() + GM.temperature = temperature + GM.update_values() + + return GM + +/turf/remove_air(amount as num) + var/datum/gas_mixture/GM = return_air() + return GM.remove(amount) + +/turf/simulated/assume_air(datum/gas_mixture/giver) + var/datum/gas_mixture/my_air = return_air() + my_air.merge(giver) + +/turf/simulated/assume_gas(gasid, moles, temp = null) + var/datum/gas_mixture/my_air = return_air() + + if(isnull(temp)) + my_air.adjust_gas(gasid, moles) + else + my_air.adjust_gas_temp(gasid, moles, temp) + + return 1 + +/turf/simulated/return_air() + if(zone) + if(!zone.invalid) + SSair.mark_zone_update(zone) + return zone.air + else + if(!air) + make_air() + c_copy_air() + return air + else + if(!air) + make_air() + return air + +/turf/proc/make_air() + air = new/datum/gas_mixture + air.temperature = temperature + if(initial_gas) + air.gas = initial_gas.Copy() + air.update_values() + +/turf/simulated/proc/c_copy_air() + if(!air) air = new/datum/gas_mixture + air.copy_from(zone.air) + air.group_multiplier = 1 diff --git a/code/modules/ZAS/Variable Settings.dm b/code/modules/ZAS/Variable Settings.dm new file mode 100644 index 00000000..a4f46c75 --- /dev/null +++ b/code/modules/ZAS/Variable Settings.dm @@ -0,0 +1,367 @@ +var/global/vs_control/vsc = new + +/vs_control + var/fire_consuption_rate = 0.25 + var/fire_consuption_rate_NAME = "Fire - Air Consumption Ratio" + var/fire_consuption_rate_DESC = "Ratio of air removed and combusted per tick." + + var/fire_firelevel_multiplier = 25 + 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_NAME = "Fire - Fuel energy release" + var/fire_fuel_energy_release_DESC = "The energy in joule released when burning one mol of a burnable substance" + + + var/IgnitionLevel = 0.5 + var/IgnitionLevel_DESC = "Determines point at which fire can ignite" + + var/airflow_lightest_pressure = 20 + var/airflow_lightest_pressure_NAME = "Airflow - Small Movement Threshold %" + var/airflow_lightest_pressure_DESC = "Percent of 1 Atm. at which items with the small weight classes will move." + + var/airflow_light_pressure = 35 + var/airflow_light_pressure_NAME = "Airflow - Medium Movement Threshold %" + var/airflow_light_pressure_DESC = "Percent of 1 Atm. at which items with the medium weight classes will move." + + var/airflow_medium_pressure = 50 + var/airflow_medium_pressure_NAME = "Airflow - Heavy Movement Threshold %" + var/airflow_medium_pressure_DESC = "Percent of 1 Atm. at which items with the largest weight classes will move." + + var/airflow_heavy_pressure = 65 + var/airflow_heavy_pressure_NAME = "Airflow - Mob Movement Threshold %" + var/airflow_heavy_pressure_DESC = "Percent of 1 Atm. at which mobs will move." + + var/airflow_dense_pressure = 85 + var/airflow_dense_pressure_NAME = "Airflow - Dense Movement Threshold %" + var/airflow_dense_pressure_DESC = "Percent of 1 Atm. at which items with canisters and closets will move." + + var/airflow_stun_pressure = 60 + var/airflow_stun_pressure_NAME = "Airflow - Mob Stunning Threshold %" + var/airflow_stun_pressure_DESC = "Percent of 1 Atm. at which mobs will be stunned by airflow." + + var/airflow_stun_cooldown = 60 + var/airflow_stun_cooldown_NAME = "Aiflow Stunning - Cooldown" + var/airflow_stun_cooldown_DESC = "How long, in tenths of a second, to wait before stunning them again." + + var/airflow_stun = 1 + var/airflow_stun_NAME = "Airflow Impact - Stunning" + var/airflow_stun_DESC = "How much a mob is stunned when hit by an object." + + var/airflow_damage = 3 + var/airflow_damage_NAME = "Airflow Impact - Damage" + var/airflow_damage_DESC = "Damage from airflow impacts." + + var/airflow_speed_decay = 1.5 + var/airflow_speed_decay_NAME = "Airflow Speed Decay" + var/airflow_speed_decay_DESC = "How rapidly the speed gained from airflow decays." + + var/airflow_delay = 30 + var/airflow_delay_NAME = "Airflow Retrigger Delay" + var/airflow_delay_DESC = "Time in deciseconds before things can be moved by airflow again." + + var/airflow_mob_slowdown = 1 + var/airflow_mob_slowdown_NAME = "Airflow Slowdown" + var/airflow_mob_slowdown_DESC = "Time in tenths of a second to add as a delay to each movement by a mob if they are fighting the pull of the airflow." + + var/connection_insulation = 1 + var/connection_insulation_NAME = "Connections - Insulation" + var/connection_insulation_DESC = "Boolean, should doors forbid heat transfer?" + + var/connection_temperature_delta = 10 + var/connection_temperature_delta_NAME = "Connections - Temperature Difference" + var/connection_temperature_delta_DESC = "The smallest temperature difference which will cause heat to travel through doors." + + +/vs_control/var/list/settings = list() +/vs_control/var/list/bitflags = list("1","2","4","8","16","32","64","128","256","512","1024") +/vs_control/var/pl_control/plc = new() + +/vs_control/New() + . = ..() + settings = vars.Copy() + + var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars. + for(var/V in D.vars) + settings -= V + + for(var/V in settings) + if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC") || findtextEx(V,"_METHOD")) + settings -= V + + settings -= "settings" + settings -= "bitflags" + settings -= "plc" + +/vs_control/proc/ChangeSettingsDialog(mob/user,list/L) + //var/which = input(user,"Choose a setting:") in L + var/dat = "" + for(var/ch in L) + if(findtextEx(ch,"_RANDOM") || findtextEx(ch,"_DESC") || findtextEx(ch,"_METHOD") || findtextEx(ch,"_NAME")) continue + var/vw + var/vw_desc = "No Description." + var/vw_name = ch + if(ch in plc.settings) + vw = plc.vars[ch] + if("[ch]_DESC" in plc.vars) vw_desc = plc.vars["[ch]_DESC"] + if("[ch]_NAME" in plc.vars) vw_name = plc.vars["[ch]_NAME"] + else + vw = vars[ch] + if("[ch]_DESC" in vars) vw_desc = vars["[ch]_DESC"] + if("[ch]_NAME" in vars) vw_name = vars["[ch]_NAME"] + dat += "[vw_name] = [vw] \[Change\]
            " + dat += "[vw_desc]

            " + user << browse(dat,"window=settings") + +/vs_control/Topic(href,href_list) + if("changevar" in href_list) + ChangeSetting(usr,href_list["changevar"]) + +/vs_control/proc/ChangeSetting(mob/user,ch) + var/vw + var/how = "Text" + var/display_description = ch + if(ch in plc.settings) + vw = plc.vars[ch] + if("[ch]_NAME" in plc.vars) + display_description = plc.vars["[ch]_NAME"] + if("[ch]_METHOD" in plc.vars) + how = plc.vars["[ch]_METHOD"] + else + if(isnum(vw)) + how = "Numeric" + else + how = "Text" + else + vw = vars[ch] + if("[ch]_NAME" in vars) + display_description = vars["[ch]_NAME"] + if("[ch]_METHOD" in vars) + how = vars["[ch]_METHOD"] + else + if(isnum(vw)) + how = "Numeric" + else + how = "Text" + var/newvar = vw + switch(how) + if("Numeric") + newvar = input(user,"Enter a number:","Settings",newvar) as num + if("Bit Flag") + var/flag = input(user,"Toggle which bit?","Settings") in bitflags + flag = text2num(flag) + if(newvar & flag) + newvar &= ~flag + else + newvar |= flag + if("Toggle") + newvar = !newvar + if("Text") + newvar = input(user,"Enter a string:","Settings",newvar) as text + if("Long Text") + newvar = input(user,"Enter text:","Settings",newvar) as message + vw = newvar + if(ch in plc.settings) + plc.vars[ch] = vw + else + vars[ch] = vw + if(how == "Toggle") + newvar = (newvar?"ON":"OFF") + to_world("[key_name(user)] changed the setting [display_description] to [newvar].") + if(ch in plc.settings) + ChangeSettingsDialog(user,plc.settings) + else + ChangeSettingsDialog(user,settings) + +/vs_control/proc/RandomizeWithProbability() + for(var/V in settings) + var/newvalue + if("[V]_RANDOM" in vars) + if(isnum(vars["[V]_RANDOM"])) + newvalue = prob(vars["[V]_RANDOM"]) + else if(istext(vars["[V]_RANDOM"])) + newvalue = roll(vars["[V]_RANDOM"]) + else + newvalue = vars[V] + V = newvalue + +/vs_control/proc/ChangePhoron() + for(var/V in plc.settings) + plc.Randomize(V) + +/vs_control/proc/SetDefault(var/mob/user) + var/list/setting_choices = list("Phoron - Standard", "Phoron - Low Hazard", "Phoron - High Hazard", "Phoron - Oh Shit!",\ + "ZAS - Normal", "ZAS - Forgiving", "ZAS - Dangerous", "ZAS - Hellish", "ZAS/Phoron - Initial") + var/def = input(user, "Which of these presets should be used?") as null|anything in setting_choices + if(!def) + return + switch(def) + if("Phoron - Standard") + plc.CLOTH_CONTAMINATION = 1 //If this is on, phoron does damage by getting into cloth. + plc.PHORONGUARD_ONLY = 0 + plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. + plc.SKIN_BURNS = 0 //Phoron has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Phoron burns the eyes of anyone not wearing eye protection. + plc.PHORON_HALLUCINATION = 0 + plc.CONTAMINATION_LOSS = 0.02 + + if("Phoron - Low Hazard") + plc.CLOTH_CONTAMINATION = 0 //If this is on, phoron does damage by getting into cloth. + plc.PHORONGUARD_ONLY = 0 + plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000 + plc.SKIN_BURNS = 0 //Phoron has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Phoron burns the eyes of anyone not wearing eye protection. + plc.PHORON_HALLUCINATION = 0 + plc.CONTAMINATION_LOSS = 0.01 + + if("Phoron - High Hazard") + plc.CLOTH_CONTAMINATION = 1 //If this is on, phoron does damage by getting into cloth. + plc.PHORONGUARD_ONLY = 0 + plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. + plc.SKIN_BURNS = 1 //Phoron has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Phoron burns the eyes of anyone not wearing eye protection. + plc.PHORON_HALLUCINATION = 1 + plc.CONTAMINATION_LOSS = 0.05 + + if("Phoron - Oh Shit!") + plc.CLOTH_CONTAMINATION = 1 //If this is on, phoron does damage by getting into cloth. + plc.PHORONGUARD_ONLY = 1 + plc.GENETIC_CORRUPTION = 5 //Chance of genetic corruption as well as toxic damage, X in 1000. + plc.SKIN_BURNS = 1 //Phoron has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Phoron burns the eyes of anyone not wearing eye protection. + plc.PHORON_HALLUCINATION = 1 + plc.CONTAMINATION_LOSS = 0.075 + + if("ZAS - Normal") + airflow_lightest_pressure = 20 + airflow_light_pressure = 35 + airflow_medium_pressure = 50 + airflow_heavy_pressure = 65 + airflow_dense_pressure = 85 + airflow_stun_pressure = 60 + airflow_stun_cooldown = 60 + airflow_stun = 1 + airflow_damage = 3 + airflow_speed_decay = 1.5 + airflow_delay = 30 + airflow_mob_slowdown = 1 + + if("ZAS - Forgiving") + airflow_lightest_pressure = 45 + airflow_light_pressure = 60 + airflow_medium_pressure = 120 + airflow_heavy_pressure = 110 + airflow_dense_pressure = 200 + airflow_stun_pressure = 150 + airflow_stun_cooldown = 90 + airflow_stun = 0.15 + airflow_damage = 0.5 + airflow_speed_decay = 1.5 + airflow_delay = 50 + airflow_mob_slowdown = 0 + + if("ZAS - Dangerous") + airflow_lightest_pressure = 15 + airflow_light_pressure = 30 + airflow_medium_pressure = 45 + airflow_heavy_pressure = 55 + airflow_dense_pressure = 70 + airflow_stun_pressure = 50 + airflow_stun_cooldown = 50 + airflow_stun = 2 + airflow_damage = 4 + airflow_speed_decay = 1.2 + airflow_delay = 25 + airflow_mob_slowdown = 2 + + if("ZAS - Hellish") + airflow_lightest_pressure = 20 + airflow_light_pressure = 30 + airflow_medium_pressure = 40 + airflow_heavy_pressure = 50 + airflow_dense_pressure = 60 + airflow_stun_pressure = 40 + airflow_stun_cooldown = 40 + airflow_stun = 3 + airflow_damage = 5 + airflow_speed_decay = 1 + airflow_delay = 20 + airflow_mob_slowdown = 3 + connection_insulation = 0 + + if("ZAS/Phoron - Initial") + fire_consuption_rate = initial(fire_consuption_rate) + fire_firelevel_multiplier = initial(fire_firelevel_multiplier) + fire_fuel_energy_release = initial(fire_fuel_energy_release) + IgnitionLevel = initial(IgnitionLevel) + airflow_lightest_pressure = initial(airflow_lightest_pressure) + airflow_light_pressure = initial(airflow_light_pressure) + airflow_medium_pressure = initial(airflow_medium_pressure) + airflow_heavy_pressure = initial(airflow_heavy_pressure) + airflow_dense_pressure = initial(airflow_dense_pressure) + airflow_stun_pressure = initial(airflow_stun_pressure) + airflow_stun_cooldown = initial(airflow_stun_cooldown) + airflow_stun = initial(airflow_stun) + airflow_damage = initial(airflow_damage) + airflow_speed_decay = initial(airflow_speed_decay) + airflow_delay = initial(airflow_delay) + airflow_mob_slowdown = initial(airflow_mob_slowdown) + connection_insulation = initial(connection_insulation) + connection_temperature_delta = initial(connection_temperature_delta) + + plc.PHORON_DMG = initial(plc.PHORON_DMG) + plc.CLOTH_CONTAMINATION = initial(plc.CLOTH_CONTAMINATION) + plc.PHORONGUARD_ONLY = initial(plc.PHORONGUARD_ONLY) + plc.GENETIC_CORRUPTION = initial(plc.GENETIC_CORRUPTION) + plc.SKIN_BURNS = initial(plc.SKIN_BURNS) + plc.EYE_BURNS = initial(plc.EYE_BURNS) + plc.CONTAMINATION_LOSS = initial(plc.CONTAMINATION_LOSS) + plc.PHORON_HALLUCINATION = initial(plc.PHORON_HALLUCINATION) + plc.N2O_HALLUCINATION = initial(plc.N2O_HALLUCINATION) + + + to_world("[key_name(user)] changed the global phoron/ZAS settings to \"[def]\"") + +/pl_control/var/list/settings = list() + +/pl_control/New() + . = ..() + settings = vars.Copy() + + var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars. + for(var/V in D.vars) + settings -= V + + for(var/V in settings) + if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC")) + settings -= V + + settings -= "settings" + +/pl_control/proc/Randomize(V) + var/newvalue + if("[V]_RANDOM" in vars) + if(isnum(vars["[V]_RANDOM"])) + newvalue = prob(vars["[V]_RANDOM"]) + else if(istext(vars["[V]_RANDOM"])) + var/txt = vars["[V]_RANDOM"] + if(findtextEx(txt,"PROB")) + txt = splittext(txt,"/") + txt[1] = replacetext(txt[1],"PROB","") + var/p = text2num(txt[1]) + var/r = txt[2] + if(prob(p)) + newvalue = roll(r) + else + newvalue = vars[V] + else if(findtextEx(txt,"PICK")) + txt = replacetext(txt,"PICK","") + txt = splittext(txt,",") + newvalue = pick(txt) + else + newvalue = roll(txt) + else + newvalue = vars[V] + vars[V] = newvalue diff --git a/code/modules/ZAS/Zone.dm b/code/modules/ZAS/Zone.dm new file mode 100644 index 00000000..b600450c --- /dev/null +++ b/code/modules/ZAS/Zone.dm @@ -0,0 +1,188 @@ +/* + +Overview: + Each zone is a self-contained area where gas values would be the same if tile-based equalization were run indefinitely. + If you're unfamiliar with ZAS, FEA's air groups would have similar functionality if they didn't break in a stiff breeze. + +Class Vars: + name - A name of the format "Zone [#]", used for debugging. + invalid - True if the zone has been erased and is no longer eligible for processing. + needs_update - True if the zone has been added to the update list. + edges - A list of edges that connect to this zone. + air - The gas mixture that any turfs in this zone will return. Values are per-tile with a group multiplier. + +Class Procs: + add(turf/simulated/T) + Adds a turf to the contents, sets its zone and merges its air. + + remove(turf/simulated/T) + Removes a turf, sets its zone to null and erases any gas graphics. + Invalidates the zone if it has no more tiles. + + c_merge(zone/into) + Invalidates this zone and adds all its former contents to into. + + c_invalidate() + Marks this zone as invalid and removes it from processing. + + rebuild() + Invalidates the zone and marks all its former tiles for updates. + + add_tile_air(turf/simulated/T) + Adds the air contained in T.air to the zone's air supply. Called when adding a turf. + + tick() + Called only when the gas content is changed. Archives values and changes gas graphics. + + dbg_data(mob/M) + Sends M a printout of important figures for the zone. + +*/ + + +/zone/var/name +/zone/var/invalid = 0 +/zone/var/list/contents = list() +/zone/var/list/fire_tiles = list() +/zone/var/list/fuel_objs = list() + +/zone/var/needs_update = 0 + +/zone/var/list/edges = list() + +/zone/var/datum/gas_mixture/air = new + +/zone/var/list/graphic_add = list() +/zone/var/list/graphic_remove = list() + +/zone/New() + SSair.add_zone(src) + air.temperature = TCMB + air.group_multiplier = 1 + air.volume = CELL_VOLUME + +/zone/proc/add(turf/simulated/T) +#ifdef ZASDBG + ASSERT(!invalid) + ASSERT(istype(T)) + ASSERT(!SSair.has_valid_zone(T)) +#endif + + var/datum/gas_mixture/turf_air = T.return_air() + add_tile_air(turf_air) + T.zone = src + contents.Add(T) + if(T.fire) + var/obj/effect/decal/cleanable/liquid_fuel/fuel = locate() in T + fire_tiles.Add(T) + SSair.active_fire_zones |= src + if(fuel) fuel_objs += fuel + T.update_graphic(air.graphic) + +/zone/proc/remove(turf/simulated/T) +#ifdef ZASDBG + ASSERT(!invalid) + ASSERT(istype(T)) + ASSERT(T.zone == src) + soft_assert(T in contents, "Lists are weird broseph") +#endif + contents.Remove(T) + fire_tiles.Remove(T) + if(T.fire) + var/obj/effect/decal/cleanable/liquid_fuel/fuel = locate() in T + fuel_objs -= fuel + T.zone = null + T.update_graphic(graphic_remove = air.graphic) + if(contents.len) + air.group_multiplier = contents.len + else + c_invalidate() + +/zone/proc/c_merge(zone/into) +#ifdef ZASDBG + ASSERT(!invalid) + ASSERT(istype(into)) + ASSERT(into != src) + ASSERT(!into.invalid) +#endif + c_invalidate() + for(var/turf/simulated/T in contents) + into.add(T) + T.update_graphic(graphic_remove = air.graphic) + #ifdef ZASDBG + T.dbg(merged) + #endif + + //rebuild the old zone's edges so that they will be possessed by the new zone + for(var/connection_edge/E in edges) + if(E.contains_zone(into)) + continue //don't need to rebuild this edge + for(var/turf/T in E.connecting_turfs) + SSair.mark_for_update(T) + +/zone/proc/c_invalidate() + invalid = 1 + SSair.remove_zone(src) + #ifdef ZASDBG + for(var/turf/simulated/T in contents) + T.dbg(invalid_zone) + #endif + +/zone/proc/rebuild() + if(invalid) return //Short circuit for explosions where rebuild is called many times over. + c_invalidate() + for(var/turf/simulated/T in contents) + T.update_graphic(graphic_remove = air.graphic) //we need to remove the overlays so they're not doubled when the zone is rebuilt + //T.dbg(invalid_zone) + T.needs_air_update = 0 //Reset the marker so that it will be added to the list. + SSair.mark_for_update(T) + +/zone/proc/add_tile_air(datum/gas_mixture/tile_air) + //air.volume += CELL_VOLUME + air.group_multiplier = 1 + air.multiply(contents.len) + air.merge(tile_air) + air.divide(contents.len+1) + air.group_multiplier = contents.len+1 + +/zone/proc/tick() + if(air.temperature >= PHORON_FLASHPOINT && !(src in SSair.active_fire_zones) && air.check_combustability() && contents.len) + var/turf/T = pick(contents) + if(istype(T)) + T.create_fire(vsc.fire_firelevel_multiplier) + + if(air.check_tile_graphic(graphic_add, graphic_remove)) + for(var/turf/simulated/T in contents) + T.update_graphic(graphic_add, graphic_remove) + graphic_add.len = 0 + graphic_remove.len = 0 + + for(var/connection_edge/E in edges) + if(E.sleeping) + E.recheck() + +/zone/proc/dbg_data(mob/M) + to_chat(M, name) + for(var/g in air.gas) + to_chat(M, "[gas_data.name[g]]: [air.gas[g]]") + to_chat(M, "P: [air.return_pressure()] kPa V: [air.volume]L T: [air.temperature]°K ([air.temperature - T0C]°C)") + to_chat(M, "O2 per N2: [(air.gas["nitrogen"] ? air.gas["oxygen"]/air.gas["nitrogen"] : "N/A")] Moles: [air.total_moles]") + to_chat(M, "Simulated: [contents.len] ([air.group_multiplier])") +// to_chat(M, "Unsimulated: [unsimulated_contents.len]") +// to_chat(M, "Edges: [edges.len]") + if(invalid) to_chat(M, "Invalid!") + var/zone_edges = 0 + var/space_edges = 0 + var/space_coefficient = 0 + for(var/connection_edge/E in edges) + if(E.type == /connection_edge/zone) zone_edges++ + else + space_edges++ + space_coefficient += E.coefficient + to_chat(M, "[E:air:return_pressure()]kPa") + + to_chat(M, "Zone Edges: [zone_edges]") + to_chat(M, "Space Edges: [space_edges] ([space_coefficient] connections)") + + //for(var/turf/T in unsimulated_contents) +// to_chat(M, "[T] at ([T.x],[T.y])") diff --git a/code/modules/ZAS/_docs.dm b/code/modules/ZAS/_docs.dm new file mode 100644 index 00000000..41372ea2 --- /dev/null +++ b/code/modules/ZAS/_docs.dm @@ -0,0 +1,28 @@ +/* + +Zone Air System: + +This air system divides the station into impermeable areas called zones. +When something happens, i.e. a door opening or a wall being taken down, +zones equalize and eventually merge. Making an airtight area closes the connection again. + +Control Flow: +Every air tick: + Marked turfs are updated with update_air_properties(), followed by post_update_air_properties(). + Edges, including those generated by connections in the previous step, are processed. This is where gas is exchanged. + Fire is processed. + Marked zones have their air archived. + +Important Functions: + +SSair.mark_for_update(turf) + When stuff happens, call this. It works on everything. You basically don't need to worry about any other + functions besides CanPass(). + +Notes for people who used ZAS before: + There is no connected_zones anymore. + To get the zones that are connected to a zone, use this loop: + for(var/connection_edge/zone/edge in zone.edges) + var/zone/connected_zone = edge.get_connected_zone(zone) + +*/ \ No newline at end of file diff --git a/code/modules/achievements/achievements.dm b/code/modules/achievements/achievements.dm new file mode 100644 index 00000000..9efde263 --- /dev/null +++ b/code/modules/achievements/achievements.dm @@ -0,0 +1,107 @@ +//Put your actual achievements here +//use is mob.unlock_achievement(new/datum/achievement/achievement()) + +/datum/achievement/dead + name = "i ded pls berry!" + description = "reviv pls!" + +/datum/achievement/survivor + name = "Survivor" + description = "Make it till the end alive." + difficulty = DIFF_MEDIUM + +/datum/achievement/pissed + name = "Pissed" + description = "Sometimes you just can't hold it." + +/datum/achievement/shit_pants + name = "Trench Food" + description = "Those rations really did a number on your pants." + +/datum/achievement/shit_on + name = "Unrobust" + description = "Get shitted on." + +/datum/achievement/poo_eaten + name = "Eat Da Poo Poo" + description = "Discusting!" + +/datum/achievement/revive + name = "Life Giver" + description = "Actually manage to revive someone." + difficulty = DIFF_MEDIUM + +/datum/achievement/fall + name = "Subber Well Pupper" + description = "That first step's a doozy" + +/datum/achievement/lose_limb + name = "Getting Your Gun" + description = "Just like ol Johnny, you didn't need that limb anyway." + +/datum/achievement/revived + name = "I Live Again" + description = "Death can't stop you now." + difficulty = DIFF_MEDIUM + +/datum/achievement/clang + name = "The Wild Ride" + description = "The last thing anyone ever hears is CLANG CLANG CLANG." + +/datum/achievement/traitor + name = "The Villian In Everyone Else's Story" + description = "Every good story needs a bad guy." + difficulty = DIFF_MEDIUM + +/datum/achievement/winner + name = "Winner Winner Chicken Dinner" + description = "Actually manage to complete all your traitor objectives." + difficulty = DIFF_HARD + announced = TRUE + +/datum/achievement/kid + name = "You're A Kid Now!" + description = "Not a squid, but just as slippery." + +/datum/achievement/miss + name = "Hit Or Miss" + description = "I guess they never miss. Huh." + +/datum/achievement/warfare_victory + name = "War Is Heck" + description = "Win a game of warfare." + difficulty = DIFF_HARD + +/datum/achievement/suicide + name = "Hello Darkness My Old Friend" + description = "Sometimes the stresses of combat get the better of us." + +/datum/achievement/point_of_no_return + name = "Point Of No Return" + description = "Activate the point of no return device." + difficulty = DIFF_HARD + +/datum/achievement/deactivate + name = "Point Of Some Return" + description = "Deactivate the point of no return device." + difficulty = DIFF_HARD + announced = TRUE + +/datum/achievement/warfare_survivor + name = "Trench Survivor" + description = "You have survived this battle. But at what cost?" + difficulty = DIFF_HARD + announced = TRUE + +/datum/achievement/child_fire + name = "Napalm Sticks To Scavs" + description = "As good a use for your scorcher as any." + +/datum/achievement/flamer + name = "Lord of the Flame" + description = "It's time for you to burn down the trenches." + +/datum/achievement/headshot + name = "BOOM HEADSHOT" + difficulty = DIFF_MEDIUM + description = "In all likelyhood, they had a helmet, and you accomplished pretty much nothing." \ No newline at end of file diff --git a/code/modules/achievements/achievements_core.dm b/code/modules/achievements/achievements_core.dm new file mode 100644 index 00000000..ecde85a0 --- /dev/null +++ b/code/modules/achievements/achievements_core.dm @@ -0,0 +1,86 @@ +//Achievements system by Matt. +//This system allows you there to be achievements in the game, that are not tied to a database or to the byond medals system +//User mob.unlock_achievement(new/datum/achievement/achievement()) or client.unlock_achievement(new/datum/achievement/achievement()) +//Check achievements.dm for the list of achievements. + +//Defines for client. +/client + var/datum/achievements/achievement_holder = null + +//The achievement holder datum +/datum/achievements + var/list/achievements = list() + +/client/New() + achievement_holder = new + ..() + +//The actual achievements +/datum/achievement + var/name = "Default Achievement" + var/description = "Default Description" + var/difficulty = DIFF_EASY + var/announced = FALSE + +/client/proc/unlock_achievement(var/datum/achievement/A) + if(IsGuestKey(src.key)) + return + for(var/X in achievement_holder.achievements) + var/datum/achievement/AA = X + if(A.name == AA.name) //I don't think a name check is very safe here, we should type check instead. + return + achievement_holder.achievements |= A + var/savefile/F = new /savefile("data/player_saves/[copytext(ckey, 1, 2)]/[ckey]/achievements.sav")//Store the achievemnt in the file. + achievement_holder.Write(F) + var/H + switch(A.difficulty) + if (DIFF_MEDIUM) + H = "#EE9A4D" + if (DIFF_EASY) + H = "green" + if (DIFF_HARD) + H = "red" + if (A.announced) + to_world("Achievement Unlocked! [src.key] unlocked the '[A.name]' achievement.") + else + to_chat(src, "Achievement Unlocked! You unlocked the '[A.name]' achievement.") + if(A.description) + to_chat(src, "[A.description]") + +/mob/proc/unlock_achievement(var/datum/achievement/A)// use is mob.unlock_achievement(new/datum/achievement/achievement()) + if(client) + client.unlock_achievement(A) + + +/mob/verb/show_achievements() + set name = "Show Achievements" + set category = "OOC" + + if(!client)//How they check achievements without client? No idea. But I'm staying sane. + return + + if(IsGuestKey(src.key)) //How did they even connect without being logged in? No idea. But better safe than sorry. + to_chat(src, "Guests don't get achievements.") + return + + var/count = 0 + to_chat(src, "Achievements:\n") + + for(var/X in client.achievement_holder.achievements) + var/datum/achievement/A = X //Typeless loops are faster than typed ones. Or os TG told me anyway. *shrug* + var/H + count++ + switch(A.difficulty) + if (DIFF_MEDIUM) + H = "#EE9A4D" + if (DIFF_EASY) + H = "green" + if (DIFF_HARD) + H = "red" + to_chat(src, "[count]: [A.name]") + if(A.description) + to_chat(src, "[A.description]\n") + else + to_chat(src, "\n") + if(count) + to_chat(src, "---\nTOTAL ACHIEVEMENTS: [count]") \ No newline at end of file diff --git a/code/modules/acting/acting_items.dm b/code/modules/acting/acting_items.dm new file mode 100644 index 00000000..eef40888 --- /dev/null +++ b/code/modules/acting/acting_items.dm @@ -0,0 +1,45 @@ +/obj/machinery/acting/wardrobe + name = "wardrobe dispenser" + desc = "A machine that dispenses holo-clothing for those in need." + icon = 'icons/obj/vending.dmi' + icon_state = "cart" + anchored = 1 + density = 1 + var/active = 1 + +/obj/machinery/acting/wardrobe/attack_hand(var/mob/user as mob) + user.show_message("You push a button and watch patiently as the machine begins to hum.") + if(active) + active = 0 + spawn(30) + new /obj/item/weapon/storage/backpack/chameleon/sydie_kit(src.loc) + src.visible_message("\The [src] beeps, dispensing a small box onto the floor.", "You hear a beeping sound followed by a thumping noise of some kind.") + active = 1 + +/obj/machinery/acting/changer + name = "Quickee's Plastic Surgeon" + desc = "For when you need to be someone else right now." + icon = 'icons/obj/surgery.dmi' + icon_state = "bioprinter" + anchored = 1 + density = 1 + +/obj/machinery/acting/changer/attack_hand(var/mob/user as mob) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.change_appearance(APPEARANCE_ALL, H.loc, H, H.generate_valid_species(), state = GLOB.z_state) + var/getName = sanitize(input(H, "Would you like to change your name to something else?", "Name change") as null|text, MAX_NAME_LEN) + if(getName) + H.real_name = getName + H.SetName(getName) + H.dna.real_name = getName + if(H.mind) + H.mind.name = H.name + +/obj/machinery/acting/changer/mirror + name = "Mirror of Many Faces" + desc = "For when you need to be someone else right now." + icon = 'icons/obj/watercloset.dmi' + icon_state = "mirror_broke" + anchored = 1 + density = 0 diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm new file mode 100644 index 00000000..dfdfdebb --- /dev/null +++ b/code/modules/admin/DB ban/functions.dm @@ -0,0 +1,513 @@ +datum/admins/proc/DB_staffwarn_record(var/ckey, var/reason) + if(!check_rights((R_ADMIN|R_MOD), 0)) return + if(!istext(reason)) return + var/dbreason = sql_sanitize_text(reason) + var/dbckey = sql_sanitize_text(ckey) + + establish_db_connection() + if(!dbcon.IsConnected()) + to_chat(usr,"Failed adding StaffWarn: db error") + return + + var/DBQuery/query = dbcon.NewQuery("SELECT id FROM erro_player WHERE ckey = '[dbckey]'") + query.Execute() + var/playerid = -1 + if(query.NextRow()) + playerid = query.item[1] + if(playerid == -1) + to_chat(usr,"You've attempted to set staffwarn on [ckey], but they haven't been seen yet. Staffwarn can only be set on existing players.") + return + query = dbcon.NewQuery("UPDATE erro_player SET staffwarn='[dbreason]' WHERE id=[playerid]") + query.Execute() + to_chat(usr,"StaffWarn saved to DB") + +datum/admins/proc/DB_staffwarn_remove(var/ckey) + if(!check_rights((R_ADMIN|R_MOD), 0)) return + var/dbckey = sql_sanitize_text(ckey) + + establish_db_connection() + if(!dbcon.IsConnected()) + to_chat(usr,"Failed removing StaffWarn: db error") + return 0 + + var/DBQuery/query = dbcon.NewQuery("UPDATE erro_player SET staffwarn=NULL WHERE ckey='[dbckey]'") + query.Execute() + if(query.RowsAffected() != 1) + to_chat(usr,"StaffWarn unable to be removed from DB") + return 0 + to_chat(usr,"StaffWarn removed from DB") + return 1 + +datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = -1, var/reason, var/job = "", var/rounds = 0, var/banckey = null, var/banip = null, var/bancid = null) + if(!src || !src.owner) + return + _DB_ban_record(src.owner.ckey, src.owner.computer_id, src.owner.address, bantype, banned_mob, duration, reason, job, rounds, banckey, banip, bancid) + +//Either pass the mob you wish to ban in the 'banned_mob' attribute, or the banckey, banip and bancid variables. If both are passed, the mob takes priority! If a mob is not passed, banckey is the minimum that needs to be passed! banip and bancid are optional. +/proc/_DB_ban_record(var/a_ckey, var/a_computerid, var/a_ip, var/bantype, var/mob/banned_mob, var/duration = -1, var/reason, var/job = "", var/rounds = 0, var/banckey = null, var/banip = null, var/bancid = null) + + if(usr) + if(!check_rights(R_MOD,0) && !check_rights(R_BAN)) return + + establish_db_connection() + if(!dbcon.IsConnected()) + return 0 + + var/serverip = "[world.internet_address]:[world.port]" + var/bantype_pass = 0 + var/bantype_str + switch(bantype) + if(BANTYPE_PERMA) + bantype_str = "PERMABAN" + duration = -1 + bantype_pass = 1 + if(BANTYPE_TEMP) + bantype_str = "TEMPBAN" + bantype_pass = 1 + if(BANTYPE_JOB_PERMA) + bantype_str = "JOB_PERMABAN" + duration = -1 + bantype_pass = 1 + if(BANTYPE_JOB_TEMP) + bantype_str = "JOB_TEMPBAN" + bantype_pass = 1 + if( !bantype_pass ) return 0 + if( !istext(reason) ) return 0 + if( !isnum(duration) ) return 0 + + var/ckey + var/computerid + var/ip + + if(ismob(banned_mob)) + ckey = banned_mob.ckey + if(banned_mob.client) + computerid = banned_mob.client.computer_id + ip = banned_mob.client.address + else if(banckey) + ckey = ckey(banckey) + computerid = bancid + ip = banip + + var/who + for(var/client/C in GLOB.clients) + if(!who) + who = "[C]" + else + who += ", [C]" + + var/adminwho + for(var/client/C in GLOB.admins) + if(!adminwho) + adminwho = "[C]" + else + adminwho += ", [C]" + + reason = sql_sanitize_text(reason) + + var/sql = "INSERT INTO erro_ban (`id`,`bantime`,`serverip`,`bantype`,`reason`,`job`,`duration`,`rounds`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`,`edits`,`unbanned`,`unbanned_datetime`,`unbanned_ckey`,`unbanned_computerid`,`unbanned_ip`) VALUES (null, Now(), '[serverip]', '[bantype_str]', '[reason]', '[job]', [(duration)?"[duration]":"0"], [(rounds)?"[rounds]":"0"], Now() + INTERVAL [(duration>0) ? duration : 0] MINUTE, '[ckey]', '[computerid]', '[ip]', '[a_ckey]', '[a_computerid]', '[a_ip]', '[who]', '[adminwho]', '', null, null, null, null, null)" + var/DBQuery/query_insert = dbcon.NewQuery(sql) + query_insert.Execute() + var/setter = a_ckey + if(usr) + to_chat(usr, "Ban saved to database.") + setter = key_name_admin(usr) + message_admins("[setter] has added a [bantype_str] for [ckey] [(job)?"([job])":""] [(duration > 0)?"([duration] minutes)":""] with the reason: \"[reason]\" to the ban database.",1) + return 1 + + + +datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "") + + if(!check_rights(R_BAN)) return + + var/bantype_str + if(bantype) + var/bantype_pass = 0 + switch(bantype) + if(BANTYPE_PERMA) + bantype_str = "PERMABAN" + bantype_pass = 1 + if(BANTYPE_TEMP) + bantype_str = "TEMPBAN" + bantype_pass = 1 + if(BANTYPE_JOB_PERMA) + bantype_str = "JOB_PERMABAN" + bantype_pass = 1 + if(BANTYPE_JOB_TEMP) + bantype_str = "JOB_TEMPBAN" + bantype_pass = 1 + if(BANTYPE_ANY_FULLBAN) + bantype_str = "ANY" + bantype_pass = 1 + if( !bantype_pass ) return + + var/bantype_sql + if(bantype_str == "ANY") + bantype_sql = "(bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now() ) )" + else + bantype_sql = "bantype = '[bantype_str]'" + + var/sql = "SELECT id FROM erro_ban WHERE ckey = '[ckey]' AND [bantype_sql] AND (unbanned is null OR unbanned = false)" + if(job) + sql += " AND job = '[job]'" + + establish_db_connection() + if(!dbcon.IsConnected()) + return + + var/ban_id + var/ban_number = 0 //failsafe + + var/DBQuery/query = dbcon.NewQuery(sql) + query.Execute() + while(query.NextRow()) + ban_id = query.item[1] + ban_number++; + + if(ban_number == 0) + to_chat(usr, "Database update failed due to no bans fitting the search criteria. If this is not a legacy ban you should contact the database admin.") + return + + if(ban_number > 1) + to_chat(usr, "Database update failed due to multiple bans fitting the search criteria. Note down the ckey, job and current time and contact the database admin.") + return + + if(istext(ban_id)) + ban_id = text2num(ban_id) + if(!isnum(ban_id)) + to_chat(usr, "Database update failed due to a ban ID mismatch. Contact the database admin.") + return + + DB_ban_unban_by_id(ban_id) + +datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null) + + if(!check_rights(R_BAN)) return + + if(!isnum(banid) || !istext(param)) + to_chat(usr, "Cancelled") + return + + var/DBQuery/query = dbcon.NewQuery("SELECT ckey, duration, reason FROM erro_ban WHERE id = [banid]") + query.Execute() + + var/eckey = usr.ckey //Editing admin ckey + var/pckey //(banned) Player ckey + var/duration //Old duration + var/reason //Old reason + + if(query.NextRow()) + pckey = query.item[1] + duration = query.item[2] + reason = query.item[3] + else + to_chat(usr, "Invalid ban id. Contact the database admin") + return + + reason = sql_sanitize_text(reason) + var/value + + switch(param) + if("reason") + if(!value) + value = sanitize(input("Insert the new reason for [pckey]'s ban", "New Reason", "[reason]", null) as null|text) + value = sql_sanitize_text(value) + if(!value) + to_chat(usr, "Cancelled") + return + + var/DBQuery/update_query = dbcon.NewQuery("UPDATE erro_ban SET reason = '[value]', edits = CONCAT(edits,'- [eckey] changed ban reason from \\\"[reason]\\\" to \\\"[value]\\\"
            ') WHERE id = [banid]") + update_query.Execute() + message_admins("[key_name_admin(usr)] has edited a ban for [pckey]'s reason from [reason] to [value]",1) + if("duration") + if(!value) + value = input("Insert the new duration (in minutes) for [pckey]'s ban", "New Duration", "[duration]", null) as null|num + if(!isnum(value) || !value) + to_chat(usr, "Cancelled") + return + + var/DBQuery/update_query = dbcon.NewQuery("UPDATE erro_ban SET duration = [value], edits = CONCAT(edits,'- [eckey] changed ban duration from [duration] to [value]
            '), expiration_time = DATE_ADD(bantime, INTERVAL [value] MINUTE) WHERE id = [banid]") + message_admins("[key_name_admin(usr)] has edited a ban for [pckey]'s duration from [duration] to [value]",1) + update_query.Execute() + if("unban") + if(alert("Unban [pckey]?", "Unban?", "Yes", "No") == "Yes") + DB_ban_unban_by_id(banid) + return + else + to_chat(usr, "Cancelled") + return + else + to_chat(usr, "Cancelled") + return + +datum/admins/proc/DB_ban_unban_by_id(var/id) + + if(!check_rights(R_BAN)) return + + var/sql = "SELECT ckey FROM erro_ban WHERE id = [id]" + + establish_db_connection() + if(!dbcon.IsConnected()) + return + + var/ban_number = 0 //failsafe + + var/pckey + var/DBQuery/query = dbcon.NewQuery(sql) + query.Execute() + while(query.NextRow()) + pckey = query.item[1] + ban_number++; + + if(ban_number == 0) + to_chat(usr, "Database update failed due to a ban id not being present in the database.") + return + + if(ban_number > 1) + to_chat(usr, "Database update failed due to multiple bans having the same ID. Contact the database admin.") + return + + if(!src.owner || !istype(src.owner, /client)) + return + + var/unban_ckey = src.owner:ckey + var/unban_computerid = src.owner:computer_id + var/unban_ip = src.owner:address + + var/sql_update = "UPDATE erro_ban SET unbanned = 1, unbanned_datetime = Now(), unbanned_ckey = '[unban_ckey]', unbanned_computerid = '[unban_computerid]', unbanned_ip = '[unban_ip]' WHERE id = [id]" + message_admins("[key_name_admin(usr)] has lifted [pckey]'s ban.",1) + + var/DBQuery/query_update = dbcon.NewQuery(sql_update) + query_update.Execute() + + +/client/proc/DB_ban_panel() + set category = "Admin" + set name = "Banning Panel" + set desc = "Edit admin permissions" + + if(!holder) + return + + holder.DB_ban_panel() + + +/datum/admins/proc/DB_ban_panel(var/playerckey = null, var/adminckey = null, var/playerip = null, var/playercid = null, var/dbbantype = null, var/match = null) + if(!usr.client) + return + + if(!check_rights(R_BAN)) return + + establish_db_connection() + if(!dbcon.IsConnected()) + to_chat(usr, "Failed to establish database connection") + return + + var/output = "
            " + + output += "" + + output += "" + output += "" + output += "
            " + output += "

            Banning panel

            " + output += "
            " + + output += "
            Add custom ban: (ONLY use this if you can't ban through any other method)" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "
            Ban type:Ckey:
            IP: CID:
            Duration: Job:
            " + output += "Reason:

            " + output += "" + output += "
            " + + output += "
            " + + output += "
            " + output += "" + output += "" + output += "" + output += "" + output += "
            Search:" + output += "
            Ckey: Admin ckey:
            IP: CID:
            Ban type:
            " + output += "

            " + output += " Match(min. 3 characters to search by key or ip, and 7 to search by cid)
            " + output += "
            " + output += "Please note that all jobban bans or unbans are in-effect the following round.
            " + output += "This search shows only last 100 bans." + + if(adminckey || playerckey || playerip || playercid || dbbantype) + + adminckey = ckey(adminckey) + playerckey = ckey(playerckey) + playerip = sql_sanitize_text(playerip) + playercid = sql_sanitize_text(playercid) + + if(adminckey || playerckey || playerip || playercid || dbbantype) + + var/blcolor = "#ffeeee" //banned light + var/bdcolor = "#ffdddd" //banned dark + var/ulcolor = "#eeffee" //unbanned light + var/udcolor = "#ddffdd" //unbanned dark + var/alcolor = "#eeeeff" // auto-unbanned light + var/adcolor = "#ddddff" // auto-unbanned dark + + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + + var/adminsearch = "" + var/playersearch = "" + var/ipsearch = "" + var/cidsearch = "" + var/bantypesearch = "" + + if(!match) + if(adminckey) + adminsearch = "AND a_ckey = '[adminckey]' " + if(playerckey) + playersearch = "AND ckey = '[playerckey]' " + if(playerip) + ipsearch = "AND ip = '[playerip]' " + if(playercid) + cidsearch = "AND computerid = '[playercid]' " + else + if(adminckey && length(adminckey) >= 3) + adminsearch = "AND a_ckey LIKE '[adminckey]%' " + if(playerckey && length(playerckey) >= 3) + playersearch = "AND ckey LIKE '[playerckey]%' " + if(playerip && length(playerip) >= 3) + ipsearch = "AND ip LIKE '[playerip]%' " + if(playercid && length(playercid) >= 7) + cidsearch = "AND computerid LIKE '[playercid]%' " + + if(dbbantype) + bantypesearch = "AND bantype = " + + switch(dbbantype) + if(BANTYPE_TEMP) + bantypesearch += "'TEMPBAN' " + if(BANTYPE_JOB_PERMA) + bantypesearch += "'JOB_PERMABAN' " + if(BANTYPE_JOB_TEMP) + bantypesearch += "'JOB_TEMPBAN' " + else + bantypesearch += "'PERMABAN' " + + var/DBQuery/select_query = dbcon.NewQuery("SELECT id, bantime, bantype, reason, job, duration, expiration_time, ckey, a_ckey, unbanned, unbanned_ckey, unbanned_datetime, edits, ip, computerid FROM erro_ban WHERE 1 [playersearch] [adminsearch] [ipsearch] [cidsearch] [bantypesearch] ORDER BY bantime DESC LIMIT 100") + select_query.Execute() + + var/now = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") // MUST BE the same format as SQL gives us the dates in, and MUST be least to most specific (i.e. year, month, day not day, month, year) + + while(select_query.NextRow()) + var/banid = select_query.item[1] + var/bantime = select_query.item[2] + var/bantype = select_query.item[3] + var/reason = select_query.item[4] + var/job = select_query.item[5] + var/duration = select_query.item[6] + var/expiration = select_query.item[7] + var/ckey = select_query.item[8] + var/ackey = select_query.item[9] + var/unbanned = select_query.item[10] + var/unbanckey = select_query.item[11] + var/unbantime = select_query.item[12] + var/edits = select_query.item[13] + var/ip = select_query.item[14] + var/cid = select_query.item[15] + + // true if this ban has expired + var/auto = (bantype in list("TEMPBAN", "JOB_TEMPBAN")) && now > expiration // oh how I love ISO 8601 (ish) date strings + + var/lcolor = blcolor + var/dcolor = bdcolor + if(unbanned) + lcolor = ulcolor + dcolor = udcolor + else if(auto) + lcolor = alcolor + dcolor = adcolor + + var/typedesc ="" + switch(bantype) + if("PERMABAN") + typedesc = "PERMABAN" + if("TEMPBAN") + typedesc = "TEMPBAN
            ([duration] minutes) [(unbanned || auto) ? "" : "(Edit)"]
            Expires [expiration]
            " + if("JOB_PERMABAN") + typedesc = "JOBBAN
            ([job])" + if("JOB_TEMPBAN") + typedesc = "TEMP JOBBAN
            ([job])
            ([duration] minutes
            Expires [expiration]
            " + + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + if(edits) + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + if(unbanned) + output += "" + output += "" + output += "" + else if(auto) + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + + output += "
            TYPECKEYTIME APPLIEDADMINOPTIONS
            [typedesc][ckey][bantime][ackey][(unbanned || auto) ? "" : "Unban"]
            IP: [ip]CIP: [cid]
            Reason: [(unbanned || auto) ? "" : "(Edit)"] \"[reason]\"
            EDITS
            [edits]
            UNBANNED by admin [unbanckey] on [unbantime]
            EXPIRED at [expiration]
             
            " + + usr << browse(output,"window=lookupbans;size=900x700") diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm new file mode 100644 index 00000000..3246a4f0 --- /dev/null +++ b/code/modules/admin/IsBanned.dm @@ -0,0 +1,94 @@ +//Blocks an attempt to connect before even creating our client datum thing. +world/IsBanned(key,address,computer_id) + if(ckey(key) in admin_datums) + return ..() + + //Check if user is whitelisted + if(config.useckeywhitelist && !check_ckey_whitelisted(ckey(key))) + log_access("Failed Login: [key] [computer_id] [address] - Pool's Closed") + message_admins("Failed Login: [key] id:[computer_id] ip:[address] - Pool's Closed.") + return list("reason"="private", "desc"="\nPrivate party. Pool's closed.") + + if(config.private_party && !has_connected(ckey(key)) && !check_ckey_whitelisted(ckey(key))) + log_access("Failed Login: [key] [computer_id] [address] - Panic Bunker") + message_admins("Failed Login: [key] id:[computer_id] ip:[address] - Panic Bunker.") + return list("reason"="private", "desc"="\nPrivate party. Pool's closed.") + + //Guest Checking + if(!config.guests_allowed && IsGuestKey(key)) + log_access("Failed Login: [key] - Guests not allowed") + message_admins("Failed Login: [key] - Guests not allowed") + return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a byond account.") + + if(config.usepopcap) + var/popcap_value = GLOB.clients.len + if(popcap_value >= config.popcap && !GLOB.player_list.Find(key)) + log_access("Failed Login: [key] - Population cap reached") + message_admins("Failed Login: [key] - Server is full") + return list("reason"="popcap", "desc"= "\nReason: Server is full. Try again later.") + + if(config.ban_legacy_system) + + //Ban Checking + . = CheckBan( ckey(key), computer_id, address ) + if(.) + log_access("Failed Login: [key] [computer_id] [address] - Banned [.["reason"]]") + message_admins("Failed Login: [key] id:[computer_id] ip:[address] - Banned [.["reason"]]") + return . + + return ..() //default pager ban stuff + + else + + var/ckeytext = ckey(key) + + if(!establish_db_connection()) + error("Ban database connection failure. Key [ckeytext] not checked") + log_misc("Ban database connection failure. Key [ckeytext] not checked") + return + + var/failedcid = 1 + var/failedip = 1 + + var/ipquery = "" + var/cidquery = "" + if(address) + failedip = 0 + ipquery = " OR ip = '[address]' " + + if(computer_id) + failedcid = 0 + cidquery = " OR computerid = '[computer_id]' " + + var/DBQuery/query = dbcon.NewQuery("SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM erro_ban WHERE (ckey = '[ckeytext]' [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)") + + query.Execute() + + while(query.NextRow()) + var/pckey = query.item[1] + //var/pip = query.item[2] + //var/pcid = query.item[3] + var/ackey = query.item[4] + var/reason = query.item[5] + var/expiration = query.item[6] + var/duration = query.item[7] + var/bantime = query.item[8] + var/bantype = query.item[9] + + var/expires = "" + if(text2num(duration) > 0) + expires = " The ban is for [duration] minutes and expires on [expiration] (server time)." + + var/desc = "\nReason: You, or another user of this computer or connection ([pckey]) is banned from playing here. The ban reason is:\n[reason]\nThis ban was applied by [ackey] on [bantime], [expires]" + + return list("reason"="[bantype]", "desc"="[desc]") + + if (failedcid) + message_admins("[key] has logged in with a blank computer id in the ban check.") + if (failedip) + message_admins("[key] has logged in with a blank ip in the ban check.") + return ..() //default pager ban stuff + + +proc/has_connected(key) + return fexists("data/player_saves/[copytext(key,1,2)]/[key]/achievements.sav") \ No newline at end of file diff --git a/code/modules/admin/NewBan.dm b/code/modules/admin/NewBan.dm new file mode 100644 index 00000000..fcf9c3b5 --- /dev/null +++ b/code/modules/admin/NewBan.dm @@ -0,0 +1,229 @@ +var/CMinutes = null +var/savefile/Banlist + + +/proc/CheckBan(var/ckey, var/id, var/address) + if(!Banlist) // if Banlist cannot be located for some reason + LoadBans() // try to load the bans + if(!Banlist) // uh oh, can't find bans! + return 0 // ABORT ABORT ABORT + + . = list() + var/appeal + if(config && config.banappeals) + appeal = "\nFor more information on your ban, or to appeal, head to [config.banappeals]" + Banlist.cd = "/base" + if( "[ckey][id]" in Banlist.dir ) + Banlist.cd = "[ckey][id]" + if (Banlist["temp"]) + if (!GetExp(Banlist["minutes"])) + ClearTempbans() + return 0 + else + .["desc"] = "\nReason: [Banlist["reason"]]\nExpires: [GetExp(Banlist["minutes"])]\nBy: [Banlist["bannedby"]][appeal]" + else + Banlist.cd = "/base/[ckey][id]" + .["desc"] = "\nReason: [Banlist["reason"]]\nExpires: PERMENANT\nBy: [Banlist["bannedby"]][appeal]" + .["reason"] = "ckey/id" + return . + else + for (var/A in Banlist.dir) + Banlist.cd = "/base/[A]" + var/matches + if( ckey == Banlist["key"] ) + matches += "ckey" + if( id == Banlist["id"] ) + if(matches) + matches += "/" + matches += "id" + if( address == Banlist["ip"] ) + if(matches) + matches += "/" + matches += "ip" + + if(matches) + if(Banlist["temp"]) + if (!GetExp(Banlist["minutes"])) + ClearTempbans() + return 0 + else + .["desc"] = "\nReason: [Banlist["reason"]]\nExpires: [GetExp(Banlist["minutes"])]\nBy: [Banlist["bannedby"]][appeal]" + else + .["desc"] = "\nReason: [Banlist["reason"]]\nExpires: PERMENANT\nBy: [Banlist["bannedby"]][appeal]" + .["reason"] = matches + return . + return 0 + +/proc/UpdateTime() //No idea why i made this a proc. + CMinutes = (world.realtime / 10) / 60 + return 1 + +/hook/startup/proc/loadBans() + return LoadBans() + +/proc/LoadBans() + + Banlist = new("data/banlist.bdb") + log_admin("Loading Banlist") + + if (!length(Banlist.dir)) log_admin("Banlist is empty.") + + if (!Banlist.dir.Find("base")) + log_admin("Banlist missing base dir.") + Banlist.dir.Add("base") + Banlist.cd = "/base" + else if (Banlist.dir.Find("base")) + Banlist.cd = "/base" + + ClearTempbans() + return 1 + +/proc/ClearTempbans() + UpdateTime() + + Banlist.cd = "/base" + for (var/A in Banlist.dir) + Banlist.cd = "/base/[A]" + if (!Banlist["key"] || !Banlist["id"]) + RemoveBan(A) + log_admin("Invalid Ban.") + message_admins("Invalid Ban.") + continue + + if (!Banlist["temp"]) continue + if (CMinutes >= Banlist["minutes"]) RemoveBan(A) + + return 1 + + +/proc/AddBan(ckey, computerid, reason, bannedby, temp, minutes, address) + + var/bantimestamp + + if (temp) + UpdateTime() + bantimestamp = CMinutes + minutes + + Banlist.cd = "/base" + if ( Banlist.dir.Find("[ckey][computerid]") ) + to_chat(usr, "Ban already exists.") + return 0 + else + Banlist.dir.Add("[ckey][computerid]") + Banlist.cd = "/base/[ckey][computerid]" + Banlist["key"] << ckey + Banlist["id"] << computerid + Banlist["ip"] << address + Banlist["reason"] << reason + Banlist["bannedby"] << bannedby + Banlist["temp"] << temp + if (temp) + Banlist["minutes"] << bantimestamp + return 1 + +/proc/RemoveBan(foldername) + var/key + var/id + + Banlist.cd = "/base/[foldername]" + Banlist["key"] >> key + Banlist["id"] >> id + Banlist.cd = "/base" + + if (!Banlist.dir.Remove(foldername)) return 0 + + if(!usr) + log_admin("Ban Expired: [key]") + message_admins("Ban Expired: [key]") + else + ban_unban_log_save("[key_name_admin(usr)] unbanned [key]") + log_admin("[key_name_admin(usr)] unbanned [key]") + message_admins("[key_name_admin(usr)] unbanned: [key]") + feedback_inc("ban_unban",1) + usr.client.holder.DB_ban_unban( ckey(key), BANTYPE_ANY_FULLBAN) + for (var/A in Banlist.dir) + Banlist.cd = "/base/[A]" + if (key == Banlist["key"] /*|| id == Banlist["id"]*/) + Banlist.cd = "/base" + Banlist.dir.Remove(A) + continue + + return 1 + +/proc/GetExp(minutes as num) + UpdateTime() + var/exp = minutes - CMinutes + if (exp <= 0) + return 0 + else + var/timeleftstring + if (exp >= 1440) //1440 = 1 day in minutes + timeleftstring = "[round(exp / 1440, 0.1)] Days" + else if (exp >= 60) //60 = 1 hour in minutes + timeleftstring = "[round(exp / 60, 0.1)] Hours" + else + timeleftstring = "[exp] Minutes" + return timeleftstring + +/datum/admins/proc/unbanpanel() + var/count = 0 + var/dat + //var/dat = "
            Unban Player: (U) = Unban , (E) = Edit Ban (Total
            " + Banlist.cd = "/base" + for (var/A in Banlist.dir) + count++ + Banlist.cd = "/base/[A]" + var/ref = "\ref[src]" + var/key = Banlist["key"] + var/id = Banlist["id"] + var/ip = Banlist["ip"] + var/reason = Banlist["reason"] + var/by = Banlist["bannedby"] + var/expiry + if(Banlist["temp"]) + expiry = GetExp(Banlist["minutes"]) + if(!expiry) expiry = "Removal Pending" + else expiry = "Permaban" + + dat += text("") + + dat += "
            (U)(E) Key: [key]ComputerID: [id]IP: [ip] [expiry](By: [by])(Reason: [reason])
            " + dat = "
            Bans: (U) = Unban , (E) = Edit Ban - ([count] Bans)
            [dat]" + usr << browse(dat, "window=unbanp;size=875x400") + +//////////////////////////////////// DEBUG //////////////////////////////////// + +/proc/CreateBans() + + UpdateTime() + + var/i + var/last + + for(i=0, i<1001, i++) + var/a = pick(1,0) + var/b = pick(1,0) + if(b) + Banlist.cd = "/base" + Banlist.dir.Add("trash[i]trashid[i]") + Banlist.cd = "/base/trash[i]trashid[i]" + Banlist["key"] << "trash[i]" + else + Banlist.cd = "/base" + Banlist.dir.Add("[last]trashid[i]") + Banlist.cd = "/base/[last]trashid[i]" + Banlist["key"] << last + Banlist["id"] << "trashid[i]" + Banlist["reason"] << "Trashban[i]." + Banlist["temp"] << a + Banlist["minutes"] << CMinutes + rand(1,2000) + Banlist["bannedby"] << "trashmin" + last = "trash[i]" + + Banlist.cd = "/base" + +/proc/ClearAllBans() + Banlist.cd = "/base" + for (var/A in Banlist.dir) + RemoveBan(A) + diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm new file mode 100644 index 00000000..050c4ab2 --- /dev/null +++ b/code/modules/admin/admin.dm @@ -0,0 +1,1473 @@ + +var/global/BSACooldown = 0 +var/global/floorIsLava = 0 + + +//////////////////////////////// +/proc/message_admins(var/msg) + msg = "ADMIN LOG: [msg]" + log_adminwarn(msg) + for(var/client/C in GLOB.admins) + if(R_ADMIN & C.holder.rights) + to_chat(C, msg) +/proc/message_staff(var/msg) + msg = "STAFF LOG: [msg]" + log_adminwarn(msg) + for(var/client/C in GLOB.admins) + if(R_INVESTIGATE & C.holder.rights) + to_chat(C, msg) +/proc/msg_admin_attack(var/text) //Toggleable Attack Messages + log_attack(text) + var/rendered = "ATTACK: [text]" + for(var/client/C in GLOB.admins) + if(check_rights(R_INVESTIGATE, 0, C)) + if(C.get_preference_value(/datum/client_preference/staff/show_attack_logs) == GLOB.PREF_SHOW) + var/msg = rendered + to_chat(C, msg) +/proc/admin_notice(var/message, var/rights) + for(var/mob/M in SSmobs.mob_list) + if(check_rights(rights, 0, M)) + to_chat(M, message) +///////////////////////////////////////////////////////////////////////////////////////////////Panels + +/datum/admins/proc/show_player_panel(var/mob/M in SSmobs.mob_list) + set category = "Admin" + set name = "Show Player Panel" + set desc="Edit player (respawn, ban, heal, etc)" + + if(!M) + to_chat(usr, "You seem to be selecting a mob that doesn't exist anymore.") + return + if (!istype(src,/datum/admins)) + src = usr.client.holder + if (!istype(src,/datum/admins)) + to_chat(usr, "Error: you are not an admin!") + return + + var/body = "Options for [M.key]" + body += "Options panel for [M]" + if(M.client) + body += " played by [M.client] " + body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\]" + + if(istype(M, /mob/new_player)) + body += " Hasn't Entered Game " + else + body += " \[Heal\] " + + body += {" +

            \[ + VV - + TP - + PM - + SM - + [admin_jump_link(M, src)]\]
            + Mob type: [M.type]
            + Inactivity time: [M.client ? "[M.client.inactivity/600] minutes" : "Logged out"]

            + Kick | + Warn | + Ban | + Jobban | + Notes + "} + + if(M.client) + body += "| Prison | " + var/muted = M.client.prefs.muted + body += {"
            Mute: + \[IC | + AOOC | + PRAY | + ADMINHELP | + DEADCHAT\] + (toggle all) + "} + body += "

            Staff Warning: [M.client.staffwarn ? M.client.staffwarn : "No"]
            " + if (!M.client.staffwarn) + body += "Set StaffWarn" + else + body += "Remove StaffWarn" + + body += {"

            + Jump to | + Get | + Send To +

            + [check_rights(R_ADMIN|R_MOD,0) ? "Traitor panel | " : "" ] + Narrate to | + Subtle message + "} + + if (M.client) + if(!istype(M, /mob/new_player)) + body += "

            " + body += "Transformation:" + body += "
            " + + //Monkey + if(issmall(M)) + body += "Monkeyized | " + else + body += "Monkeyize | " + + //Corgi + if(iscorgi(M)) + body += "Corgized | " + else + body += "Corgize | " + + //AI / Cyborg + if(isAI(M)) + body += "Is an AI " + else if(ishuman(M)) + body += {"Make AI | + Make Robot | + Make Alien | + Make slime + "} + + //Simple Animals + if(isanimal(M)) + body += "Re-Animalize | " + else + body += "Animalize | " + + // DNA2 - Admin Hax + if(M.dna && iscarbon(M)) + body += "

            " + body += "DNA Blocks:
            " + var/bname + for(var/block=1;block<=DNA_SE_LENGTH;block++) + if(((block-1)%5)==0) + body += "" + bname = assigned_blocks[block] + body += "" + body += "
             12345
            [block-1]" + if(bname) + var/bstate=M.dna.GetSEState(block) + var/bcolor="[(bstate)?"#006600":"#ff0000"]" + body += "[bname][block]" + else + body += "[block]" + body+="
            " + + body += {"

            + Rudimentary transformation:
            These transformations only create a new mob type and copy stuff over. They do not take into account MMIs and similar mob-specific things. The buttons in 'Transformations' are preferred, when possible.

            + Observer | + \[ Xenos: Larva + Drone + Hunter + Sentinel + Queen \] | + \[ Crew: Human + Unathi + Tajaran + Skrell + Vox \] | \[ + Nymph + Diona \] | + \[ slime: Baby, + Adult \] + Monkey | + Cyborg | + Cat | + Runtime | + Corgi | + Ian | + Crab | + Coffee | + \[ Construct: Armoured , + Builder , + Wraith \] + Shade +
            + "} + body += {"

            + Other actions: +
            + Forcesay + "} + if (M.client) + body += {" | + Thunderdome 1 | + Thunderdome 2 | + Thunderdome Admin | + Thunderdome Observer | + "} + // language toggles + body += "

            Languages:
            " + var/f = 1 + for(var/k in all_languages) + var/datum/language/L = all_languages[k] + if(!(L.flags & INNATE)) + if(!f) body += " | " + else f = 0 + if(L in M.languages) + body += "[k]" + else + body += "[k]" + + body += {"
            + + "} + + usr << browse(body, "window=adminplayeropts;size=550x515") + feedback_add_details("admin_verb","SPP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/datum/player_info/var/author // admin who authored the information +/datum/player_info/var/rank //rank of admin who made the notes +/datum/player_info/var/content // text content of the information +/datum/player_info/var/timestamp // Because this is bloody annoying + +#define PLAYER_NOTES_ENTRIES_PER_PAGE 50 +/datum/admins/proc/PlayerNotes() + set category = "Admin" + set name = "Player Notes" + if (!istype(src,/datum/admins)) + src = usr.client.holder + if (!istype(src,/datum/admins)) + to_chat(usr, "Error: you are not an admin!") + return + PlayerNotesPage() + +/datum/admins/proc/PlayerNotesPage(var/filter_term) + var/list/dat = list() + dat += "Player notes
            " + var/savefile/S=new("data/player_notes.sav") + var/list/note_keys + S >> note_keys + + if(filter_term) + for(var/t in note_keys) + if(findtext(lowertext(t), lowertext(filter_term))) + continue + note_keys -= t + + dat += "
            Search term: [filter_term ? filter_term : "-----"]

            " + + if(!note_keys) + dat += "No notes found." + else + dat += "" + note_keys = sortList(note_keys) + for(var/t in note_keys) + dat += "" + dat += "
            [t]

            " + + var/datum/browser/popup = new(usr, "player_notes", "Player Notes", 400, 400) + popup.set_content(jointext(dat, null)) + popup.open() + + +/datum/admins/proc/player_has_info(var/key as text) + var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") + var/list/infos + info >> infos + if(!infos || !infos.len) return 0 + else return 1 + + +/datum/admins/proc/show_player_info(var/key as text) + + set category = "Admin" + set name = "Show Player Info" + if (!istype(src,/datum/admins)) + src = usr.client.holder + if (!istype(src,/datum/admins)) + to_chat(usr, "Error: you are not an admin!") + return + + var/list/dat = list() + + var/p_age = "unknown" + for(var/client/C in GLOB.clients) + if(C.ckey == key) + p_age = C.player_age + break + dat += "Player age: [p_age]
              " + + var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") + var/list/infos + info >> infos + if(!infos) + dat += "No information found on the given key.
              " + else + var/update_file = 0 + var/i = 0 + for(var/datum/player_info/I in infos) + i += 1 + if(!I.timestamp) + I.timestamp = "Pre-4/3/2012" + update_file = 1 + if(!I.rank) + I.rank = "N/A" + update_file = 1 + dat += "
            • [I.content] by [I.author] ([I.rank]) on [I.timestamp] " + if(I.author == usr.key || I.author == "Adminbot" || ishost(usr)) + dat += "Remove" + dat += "
            • " + if(update_file) info << infos + + dat += "

            Add Comment
            " + + var/html = {" + + + Info on [key] + + + +
            + + + +
            +
            + Search: +
            +
            + +
            +
            + [jointext(dat, null)] + + + "} + + send_rsc(usr,'code/js/player_info.js', "player_info.js") + var/datum/browser/popup = new(usr, "adminplayerinfo", "Player Info", 480, 480) + popup.set_content(html) + popup.open() + +/datum/admins/proc/access_news_network() //MARKER + set category = "Fun" + set name = "Access Newscaster Network" + set desc = "Allows you to view, add and edit news feeds." + + if (!istype(src,/datum/admins)) + src = usr.client.holder + if (!istype(src,/datum/admins)) + to_chat(usr, "Error: you are not an admin!") + return + var/dat + dat = text("Admin Newscaster

            Admin Newscaster Unit

            ") + + switch(admincaster_screen) + if(0) + dat += {"Welcome to the admin newscaster.
            Here you can add, edit and censor every newspiece on the network. +
            Feed channels and stories entered through here will be uneditable and handled as official news by the rest of the units. +
            Note that this panel allows full freedom over the news network, there are no constrictions except the few basic ones. Don't break things! + "} + if(news_network.wanted_issue) + dat+= "
            Read Wanted Issue" + + dat+= {"

            Create Feed Channel +
            View Feed Channels +
            Submit new Feed story +

            Exit + "} + + var/wanted_already = 0 + if(news_network.wanted_issue) + wanted_already = 1 + + dat+={"
            Feed Security functions:
            +
            [(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue +
            Censor Feed Stories +
            Mark Feed Channel with [GLOB.using_map.company_name] D-Notice (disables and locks the channel. +

            The newscaster recognises you as:
            [src.admincaster_signature]
            + "} + if(1) + dat+= "Feed Channels
            " + if( isemptylist(news_network.network_channels) ) + dat+="No active channels found..." + else + for(var/datum/feed_channel/CHANNEL in news_network.network_channels) + if(CHANNEL.is_admin_channel) + dat+="[CHANNEL.channel_name]
            " + else + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
            " + dat+={"

            Refresh +
            Back + "} + + if(2) + dat+={" + Creating new Feed Channel... +
            Channel Name: [src.admincaster_feed_channel.channel_name]
            + Channel Author: [src.admincaster_signature]
            + Will Accept Public Feeds: [(src.admincaster_feed_channel.locked) ? ("NO") : ("YES")]

            +
            Submit

            Cancel
            + "} + if(3) + dat+={" + Creating new Feed Message... +
            Receiving Channel: [src.admincaster_feed_channel.channel_name]
            //MARK + Message Author: [src.admincaster_signature]
            + Message Body: [src.admincaster_feed_message.body]
            +
            Submit

            Cancel
            + "} + if(4) + dat+={" + Feed story successfully submitted to [src.admincaster_feed_channel.channel_name].

            +
            Return
            + "} + if(5) + dat+={" + Feed Channel [src.admincaster_feed_channel.channel_name] created successfully.

            +
            Return
            + "} + if(6) + dat+="ERROR: Could not submit Feed story to Network.

            " + if(src.admincaster_feed_channel.channel_name=="") + dat+="•Invalid receiving channel name.
            " + if(src.admincaster_feed_message.body == "" || src.admincaster_feed_message.body == "\[REDACTED\]") + dat+="•Invalid message body.
            " + dat+="
            Return
            " + if(7) + dat+="ERROR: Could not submit Feed Channel to Network.

            " + if(src.admincaster_feed_channel.channel_name =="" || src.admincaster_feed_channel.channel_name == "\[REDACTED\]") + dat+="•Invalid channel name.
            " + var/check = 0 + for(var/datum/feed_channel/FC in news_network.network_channels) + if(FC.channel_name == src.admincaster_feed_channel.channel_name) + check = 1 + break + if(check) + dat+="•Channel name already in use.
            " + dat+="
            Return
            " + if(9) + dat+="[src.admincaster_feed_channel.channel_name]: \[created by: [src.admincaster_feed_channel.author]\]
            " + if(src.admincaster_feed_channel.censored) + dat+={" + ATTENTION: This channel has been deemed as threatening to the welfare of the [station_name()], and marked with a [GLOB.using_map.company_name] D-Notice.
            + No further feed story additions are allowed while the D-Notice is in effect.

            + "} + else + if( isemptylist(src.admincaster_feed_channel.messages) ) + dat+="No feed messages found in channel...
            " + else + var/i = 0 + for(var/datum/feed_message/MESSAGE in src.admincaster_feed_channel.messages) + i++ + dat+="-[MESSAGE.body]
            " + if(MESSAGE.img) + usr << browse_rsc(MESSAGE.img, "tmp_photo[i].png") + dat+="

            " + dat+="\[Story by [MESSAGE.author]\]
            " + dat+={" +

            Refresh +
            Back + "} + if(10) + dat+={" + [GLOB.using_map.company_name] Feed Censorship Tool
            + NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.
            + Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.
            +
            Select Feed channel to get Stories from:
            + "} + if(isemptylist(news_network.network_channels)) + dat+="No feed channels found active...
            " + else + for(var/datum/feed_channel/CHANNEL in news_network.network_channels) + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
            " + dat+="
            Cancel" + if(11) + dat+={" + [GLOB.using_map.company_name] D-Notice Handler
            + A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the [station_name()]'s + morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed + stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.
            + "} + if(isemptylist(news_network.network_channels)) + dat+="No feed channels found active...
            " + else + for(var/datum/feed_channel/CHANNEL in news_network.network_channels) + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
            " + + dat+="
            Back" + if(12) + dat+={" + [src.admincaster_feed_channel.channel_name]: \[ created by: [src.admincaster_feed_channel.author] \]
            + [(src.admincaster_feed_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
            + "} + if( isemptylist(src.admincaster_feed_channel.messages) ) + dat+="No feed messages found in channel...
            " + else + for(var/datum/feed_message/MESSAGE in src.admincaster_feed_channel.messages) + dat+={" + -[MESSAGE.body]
            \[Story by [MESSAGE.author]\]
            + [(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]
            + "} + dat+="
            Back" + if(13) + dat+={" + [src.admincaster_feed_channel.channel_name]: \[ created by: [src.admincaster_feed_channel.author] \]
            + Channel messages listed below. If you deem them dangerous to the [station_name()], you can Bestow a D-Notice upon the channel.
            + "} + if(src.admincaster_feed_channel.censored) + dat+={" + ATTENTION: This channel has been deemed as threatening to the welfare of the [station_name()], and marked with a [GLOB.using_map.company_name] D-Notice.
            + No further feed story additions are allowed while the D-Notice is in effect.

            + "} + else + if( isemptylist(src.admincaster_feed_channel.messages) ) + dat+="No feed messages found in channel...
            " + else + for(var/datum/feed_message/MESSAGE in src.admincaster_feed_channel.messages) + dat+="-[MESSAGE.body]
            \[Story by [MESSAGE.author]\]
            " + + dat+="
            Back" + if(14) + dat+="Wanted Issue Handler:" + var/wanted_already = 0 + var/end_param = 1 + if(news_network.wanted_issue) + wanted_already = 1 + end_param = 2 + if(wanted_already) + dat+="
            A wanted issue is already in Feed Circulation. You can edit or cancel it below.
            " + dat+={" +
            + Criminal Name: [src.admincaster_feed_message.author]
            + Description: [src.admincaster_feed_message.body]
            + "} + if(wanted_already) + dat+="Wanted Issue created by: [news_network.wanted_issue.backup_author]
            " + else + dat+="Wanted Issue will be created under prosecutor: [src.admincaster_signature]
            " + dat+="
            [(wanted_already) ? ("Edit Issue") : ("Submit")]" + if(wanted_already) + dat+="
            Take down Issue" + dat+="
            Cancel" + if(15) + dat+={" + Wanted issue for [src.admincaster_feed_message.author] is now in Network Circulation.

            +
            Return
            + "} + if(16) + dat+="ERROR: Wanted Issue rejected by Network.

            " + if(src.admincaster_feed_message.author =="" || src.admincaster_feed_message.author == "\[REDACTED\]") + dat+="•Invalid name for person wanted.
            " + if(src.admincaster_feed_message.body == "" || src.admincaster_feed_message.body == "\[REDACTED\]") + dat+="•Invalid description.
            " + dat+="
            Return
            " + if(17) + dat+={" + Wanted Issue successfully deleted from Circulation
            +
            Return
            + "} + if(18) + dat+={" + -- STATIONWIDE WANTED ISSUE --
            \[Submitted by: [news_network.wanted_issue.backup_author]\]
            + Criminal: [news_network.wanted_issue.author]
            + Description: [news_network.wanted_issue.body]
            + Photo:: + "} + if(news_network.wanted_issue.img) + usr << browse_rsc(news_network.wanted_issue.img, "tmp_photow.png") + dat+="
            " + else + dat+="None" + dat+="
            Back
            " + if(19) + dat+={" + Wanted issue for [src.admincaster_feed_message.author] successfully edited.

            +
            Return
            + "} + else + dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com" + +// log_debug("Channelname: [src.admincaster_feed_channel.channel_name] [src.admincaster_feed_channel.author]") +// log_debug("Msg: [src.admincaster_feed_message.author] [src.admincaster_feed_message.body]") + + usr << browse(dat, "window=admincaster_main;size=400x600") + onclose(usr, "admincaster_main") + + + +/datum/admins/proc/Jobbans() + if(!check_rights(R_BAN)) return + + var/dat = "Job Bans!
            " + for(var/t in jobban_keylist) + var/r = t + if( findtext(r,"##") ) + r = copytext( r, 1, findtext(r,"##") )//removes the description + dat += text("") + dat += "
            [t] (unban)
            " + usr << browse(dat, "window=ban;size=400x400") + +/datum/admins/proc/Game() + if(!check_rights(0)) return + + var/dat = {" +
            Game Panel

            \n + Change Game Mode
            + "} + if(master_mode == "secret") + dat += "(Force Secret Mode)
            " + + dat += {" +
            + Create Object
            + Quick Create Object
            + Create Turf
            + Create Mob
            +
            Edit Airflow Settings
            + Edit Phoron Settings
            + Choose a default ZAS setting
            + "} + + usr << browse(dat, "window=admin2;size=210x280") + return + +/datum/admins/proc/Secrets(var/datum/admin_secret_category/active_category = null) + if(!check_rights(0)) return + + // Print the header with category selection buttons. + var/dat = "The first rule of adminbuse is: you don't talk about the adminbuse.
            " + for(var/datum/admin_secret_category/category in admin_secrets.categories) + if(!category.can_view(usr)) + continue + if(active_category == category) + dat += "[category.name]" + else + dat += "[category.name] " + dat += "
            " + + // If a category is selected, print its description and then options + if(istype(active_category) && active_category.can_view(usr)) + if(active_category.desc) + dat += "[active_category.desc]
            " + for(var/datum/admin_secret_item/item in active_category.items) + if(!item.can_view(usr)) + continue + dat += "[item.name()]
            " + dat += "
            " + + var/datum/browser/popup = new(usr, "secrets", "Secrets", 550, 500) + popup.set_content(dat) + popup.open() + return + +/////////////////////////////////////////////////////////////////////////////////////////////////admins2.dm merge +//i.e. buttons/verbs + + +/datum/admins/proc/restart() + set category = "Server" + set name = "Restart" + set desc="Restarts the world" + if (!usr.client.holder) + return + var/confirm = alert("Restart the game world?", "Restart", "Yes", "Cancel") + if(confirm == "Cancel") + return + if(confirm == "Yes") + to_world("Restarting world! Initiated by [usr.key]!") + log_admin("[key_name(usr)] initiated a reboot.") + + feedback_set_details("end_error","admin reboot - by [usr.key]") + feedback_add_details("admin_verb","R") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + if(blackbox) + blackbox.save_all_data_to_sql() + + sleep(50) + world.Reboot() + + +/datum/admins/proc/announce() + set category = "Special Verbs" + set name = "Announce" + set desc="Announce your desires to the world" + if(!check_rights(0)) return + + var/message = input("Global message to send:", "Admin Announce", null, null) as message + message = sanitize(message, 500, extra = 0) + if(message) + message = replacetext(message, "\n", "
            ") // required since we're putting it in a

            tag + to_world("[usr.key] Announces:

            [message]

            ") + log_admin("Announce: [key_name(usr)] : [message]") + feedback_add_details("admin_verb","A") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/toggleooc() + set category = "Server" + set desc="Globally Toggles OOC" + set name="Toggle OOC" + + if(!check_rights(R_ADMIN)) + return + + config.ooc_allowed = !(config.ooc_allowed) + if (config.ooc_allowed) + to_world("The OOC channel has been globally enabled!") + else + to_world("The OOC channel has been globally disabled!") + log_and_message_admins("toggled OOC.") + feedback_add_details("admin_verb","TOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/togglelooc() + set category = "Server" + set desc="Globally Toggles LOOC" + set name="Toggle LOOC" + + if(!check_rights(R_ADMIN)) + return + + config.looc_allowed = !(config.looc_allowed) + if (config.looc_allowed) + to_world("The LOOC channel has been globally enabled!") + else + to_world("The LOOC channel has been globally disabled!") + log_and_message_admins("toggled LOOC.") + feedback_add_details("admin_verb","TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/datum/admins/proc/toggledsay() + set category = "Server" + set desc="Globally Toggles DSAY" + set name="Toggle DSAY" + + if(!check_rights(R_ADMIN)) + return + + config.dsay_allowed = !(config.dsay_allowed) + if (config.dsay_allowed) + to_world("Deadchat has been globally enabled!") + else + to_world("Deadchat has been globally disabled!") + log_and_message_admins("toggled deadchat.") + feedback_add_details("admin_verb","TDSAY") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc + +/datum/admins/proc/toggleoocdead() + set category = "Server" + set desc="Toggle Dead OOC." + set name="Toggle Dead OOC" + + if(!check_rights(R_ADMIN)) + return + + config.dooc_allowed = !( config.dooc_allowed ) + log_admin("[key_name(usr)] toggled Dead OOC.") + message_admins("[key_name_admin(usr)] toggled Dead OOC.", 1) + feedback_add_details("admin_verb","TDOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/togglehubvisibility() + set category = "Server" + set desc="Globally Toggles Hub Visibility" + set name="Toggle Hub Visibility" + + if(!check_rights(R_ADMIN)) + return + + //BYOND hates actually changing world.visibility at runtime, so let's just change if we give it the hub password. + world.update_hub_visibility() //proc defined in hub.dm + var/long_message = "toggled hub visibility. The server is now [GLOB.visibility_pref ? "visible" : "invisible"] ([GLOB.visibility_pref])." + if (GLOB.visibility_pref && !world.reachable) + message_admins("WARNING: The server will not show up on the hub because byond is detecting that a firewall is blocking incoming connections.") + + send2adminirc("[key_name(src)]" + long_message) + log_and_message_admins("toggled hub visibility.") + feedback_add_details("admin_verb","THUB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc + +/datum/admins/proc/toggletraitorscaling() + set category = "Server" + set desc="Toggle traitor scaling" + set name="Toggle Traitor Scaling" + config.traitor_scaling = !config.traitor_scaling + log_admin("[key_name(usr)] toggled Traitor Scaling to [config.traitor_scaling].") + message_admins("[key_name_admin(usr)] toggled Traitor Scaling [config.traitor_scaling ? "on" : "off"].", 1) + feedback_add_details("admin_verb","TTS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/startnow() + set category = "Server" + set desc="Start the round RIGHT NOW" + set name="Start Now" + if(!ticker) + alert("Unable to start the game as it is not set up.") + return + if(ticker.current_state == GAME_STATE_PREGAME && !(initialization_stage & INITIALIZATION_NOW)) + log_admin("[usr.key] has started the game.") + message_admins("[usr.key] has started the game.") + feedback_add_details("admin_verb","SN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + initialization_stage |= INITIALIZATION_NOW + return 1 + else + to_chat(usr, "Error: Start Now: Game has already started.") + return 0 + +/datum/admins/proc/toggleenter() + set category = "Server" + set desc="People can't enter" + set name="Toggle Entering" + config.enter_allowed = !(config.enter_allowed) + if (!(config.enter_allowed)) + to_world("New players may no longer enter the game.") + else + to_world("New players may now enter the game.") + log_and_message_admins("[key_name_admin(usr)] toggled new player game entering.") + world.update_status() + feedback_add_details("admin_verb","TE") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/toggleAI() + set category = "Server" + set desc="People can't be AI" + set name="Toggle AI" + config.allow_ai = !( config.allow_ai ) + if (!( config.allow_ai )) + to_world("The AI job is no longer chooseable.") + else + to_world("The AI job is chooseable now.") + log_admin("[key_name(usr)] toggled AI allowed.") + world.update_status() + feedback_add_details("admin_verb","TAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/toggleaban() + set category = "Server" + set desc="Respawn basically" + set name="Toggle Respawn" + config.abandon_allowed = !(config.abandon_allowed) + if(config.abandon_allowed) + to_world("You may now respawn.") + else + to_world("You may no longer respawn :(") + log_and_message_admins("toggled respawn to [config.abandon_allowed ? "On" : "Off"].") + world.update_status() + feedback_add_details("admin_verb","TR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/toggle_aliens() + set category = "Server" + set desc="Toggle alien mobs" + set name="Toggle Aliens" + if(!check_rights(R_ADMIN)) + return + + config.aliens_allowed = !config.aliens_allowed + log_admin("[key_name(usr)] toggled Aliens to [config.aliens_allowed].") + message_admins("[key_name_admin(usr)] toggled Aliens [config.aliens_allowed ? "on" : "off"].", 1) + feedback_add_details("admin_verb","TA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/toggle_alien_eggs() + set category = "Server" + set desc="Toggle xenomorph egg laying" + set name="Toggle Alien Eggs" + + if(!check_rights(R_ADMIN)) + return + config.alien_eggs_allowed = !config.alien_eggs_allowed + log_admin("[key_name(usr)] toggled Alien Egg Laying to [config.alien_eggs_allowed].") + message_admins("[key_name_admin(usr)] toggled Alien Egg Laying [config.alien_eggs_allowed ? "on" : "off"].", 1) + feedback_add_details("admin_verb","AEA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/delay() + set category = "Server" + set desc="Delay the game start/end" + set name="Delay" + + if(!check_rights(R_SERVER)) return + if (!ticker || ticker.current_state != GAME_STATE_PREGAME) + ticker.delay_end = !ticker.delay_end + log_and_message_admins("[ticker.delay_end ? "delayed the round end" : "has made the round end normally"].") + return //alert("Round end delayed", null, null, null, null, null) + round_progressing = !round_progressing + if (!round_progressing) + to_world("The game start has been delayed.") + log_admin("[key_name(usr)] delayed the game.") + else + to_world("The game will start soon.") + log_admin("[key_name(usr)] removed the delay.") + feedback_add_details("admin_verb","DELAY") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/adjump() + set category = "Server" + set desc="Toggle admin jumping" + set name="Toggle Jump" + config.allow_admin_jump = !(config.allow_admin_jump) + log_and_message_admins("Toggled admin jumping to [config.allow_admin_jump].") + feedback_add_details("admin_verb","TJ") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/adspawn() + set category = "Server" + set desc="Toggle admin spawning" + set name="Toggle Spawn" + config.allow_admin_spawning = !(config.allow_admin_spawning) + log_and_message_admins("toggled admin item spawning to [config.allow_admin_spawning].") + feedback_add_details("admin_verb","TAS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/adrev() + set category = "Server" + set desc="Toggle admin revives" + set name="Toggle Revive" + config.allow_admin_rev = !(config.allow_admin_rev) + log_and_message_admins("toggled reviving to [config.allow_admin_rev].") + feedback_add_details("admin_verb","TAR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/immreboot() + set category = "Server" + set desc="Reboots the server post haste" + set name="Immediate Reboot" + if(!usr.client.holder) return + if( alert("Reboot server?",,"Yes","No") == "No") + return + to_world("Rebooting world! Initiated by [usr.key]!") + log_admin("[key_name(usr)] initiated an immediate reboot.") + + feedback_set_details("end_error","immediate admin reboot - by [usr.key]") + feedback_add_details("admin_verb","IR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + if(blackbox) + blackbox.save_all_data_to_sql() + + world.Reboot() + +/datum/admins/proc/unprison(var/mob/M in SSmobs.mob_list) + set category = "Admin" + set name = "Unprison" + if (isAdminLevel(M.z)) + if (config.allow_admin_jump) + M.forceMove(pick(GLOB.latejoin)) + message_admins("[key_name_admin(usr)] has unprisoned [key_name_admin(M)]", 1) + log_admin("[key_name(usr)] has unprisoned [key_name(M)]") + else + alert("Admin jumping disabled") + else + alert("[M.name] is not prisoned.") + feedback_add_details("admin_verb","UP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +////////////////////////////////////////////////////////////////////////////////////////////////ADMIN HELPER PROCS + +/proc/is_special_character(var/character) // returns 1 for special characters and 2 for heroes of gamemode + if(!ticker || !ticker.mode) + return 0 + var/datum/mind/M + if (ismob(character)) + var/mob/C = character + M = C.mind + else if(istype(character, /datum/mind)) + M = character + + if(M) + if(ticker.mode.antag_templates && ticker.mode.antag_templates.len) + for(var/datum/antagonist/antag in ticker.mode.antag_templates) + if(antag.is_antagonist(M)) + return 2 + if(M.special_role) + return 1 + + if(isrobot(character)) + var/mob/living/silicon/robot/R = character + if(R.emagged) + return 1 + + return 0 + +/datum/admins/proc/spawn_fruit(seedtype in plant_controller.seeds) + set category = "Debug" + set desc = "Spawn the product of a seed." + set name = "Spawn Fruit" + + if(!check_rights(R_SPAWN)) return + + if(!seedtype || !plant_controller.seeds[seedtype]) + return + var/datum/seed/S = plant_controller.seeds[seedtype] + S.harvest(usr,0,0,1) + log_admin("[key_name(usr)] spawned [seedtype] fruit at ([usr.x],[usr.y],[usr.z])") + +/datum/admins/proc/spawn_custom_item() + set category = "Debug" + set desc = "Spawn a custom item." + set name = "Spawn Custom Item" + + if(!check_rights(R_SPAWN)) return + + var/owner = input("Select a ckey.", "Spawn Custom Item") as null|anything in custom_items + if(!owner|| !custom_items[owner]) + return + + var/list/possible_items = custom_items[owner] + var/datum/custom_item/item_to_spawn = input("Select an item to spawn.", "Spawn Custom Item") as null|anything in possible_items + if(!item_to_spawn || !item_to_spawn.is_valid(usr)) + return + + item_to_spawn.spawn_item(get_turf(usr)) + +/datum/admins/proc/check_custom_items() + + set category = "Debug" + set desc = "Check the custom item list." + set name = "Check Custom Items" + + if(!check_rights(R_SPAWN)) return + + if(!custom_items) + to_chat(usr, "Custom item list is null.") + return + + if(!custom_items.len) + to_chat(usr, "Custom item list not populated.") + return + + for(var/assoc_key in custom_items) + to_chat(usr, "[assoc_key] has:") + var/list/current_items = custom_items[assoc_key] + for(var/datum/custom_item/item in current_items) + to_chat(usr, "- name: [item.name] icon: [item.item_icon] path: [item.item_path] desc: [item.item_desc]") + +/datum/admins/proc/spawn_plant(seedtype in plant_controller.seeds) + set category = "Debug" + set desc = "Spawn a spreading plant effect." + set name = "Spawn Plant" + + if(!check_rights(R_SPAWN)) return + + if(!seedtype || !plant_controller.seeds[seedtype]) + return + new /obj/effect/vine(get_turf(usr), plant_controller.seeds[seedtype]) + log_admin("[key_name(usr)] spawned [seedtype] vines at ([usr.x],[usr.y],[usr.z])") + +/datum/admins/proc/spawn_atom(var/object as text) + set category = "Debug" + set desc = "(atom path) Spawn an atom" + set name = "Spawn" + + if(!check_rights(R_SPAWN)) return + + var/list/types = typesof(/atom) + var/list/matches = new() + + for(var/path in types) + if(findtext("[path]", object)) + matches += path + + if(matches.len==0) + return + + var/chosen + if(matches.len==1) + chosen = matches[1] + else + chosen = input("Select an atom type", "Spawn Atom", matches[1]) as null|anything in matches + if(!chosen) + return + + if(ispath(chosen,/turf)) + var/turf/T = get_turf(usr.loc) + T.ChangeTurf(chosen) + else + new chosen(usr.loc) + + log_and_message_admins("spawned [chosen] at ([usr.x],[usr.y],[usr.z])") + feedback_add_details("admin_verb","SA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/datum/admins/proc/show_traitor_panel(var/mob/M in SSmobs.mob_list) + set category = "Admin" + set desc = "Edit mobs's memory and role" + set name = "Show Traitor Panel" + + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + if(!M.mind) + to_chat(usr, "This mob has no mind!") + return + + M.mind.edit_memory() + feedback_add_details("admin_verb","STP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/show_game_mode() + set category = "Admin" + set desc = "Show the current round configuration." + set name = "Show Game Mode" + + if(!ticker || !ticker.mode) + alert("Not before roundstart!", "Alert") + return + + var/out = "Current mode: [ticker.mode.name] ([ticker.mode.config_tag])
            " + out += "
            " + + if(ticker.mode.ert_disabled) + out += "Emergency Response Teams: disabled" + else + out += "Emergency Response Teams: enabled" + out += "
            " + + if(ticker.mode.deny_respawn) + out += "Respawning: disallowed" + else + out += "Respawning: allowed" + out += "
            " + + out += "Shuttle delay multiplier: [ticker.mode.shuttle_delay]
            " + + if(ticker.mode.auto_recall_shuttle) + out += "Shuttle auto-recall: enabled" + else + out += "Shuttle auto-recall: disabled" + out += "

            " + + if(ticker.mode.event_delay_mod_moderate) + out += "Moderate event time modifier: [ticker.mode.event_delay_mod_moderate]
            " + else + out += "Moderate event time modifier: unset
            " + + if(ticker.mode.event_delay_mod_major) + out += "Major event time modifier: [ticker.mode.event_delay_mod_major]
            " + else + out += "Major event time modifier: unset
            " + + out += "
            " + + if(ticker.mode.antag_tags && ticker.mode.antag_tags.len) + out += "Core antag templates:
            " + for(var/antag_tag in ticker.mode.antag_tags) + out += "[antag_tag].
            " + + if(ticker.mode.round_autoantag) + out += "Autotraitor enabled." + if(ticker.mode.antag_scaling_coeff > 0) + out += " (scaling with [ticker.mode.antag_scaling_coeff])" + else + out += " (not currently scaling, set a coefficient)" + out += "
            " + else + out += "Autotraitor disabled.
            " + + out += "All antag ids:" + if(ticker.mode.antag_templates && ticker.mode.antag_templates.len) + for(var/datum/antagonist/antag in ticker.mode.antag_templates) + antag.update_current_antag_max() + out += " [antag.id]" + out += " ([antag.get_antag_count()]/[antag.cur_max]) " + out += " \[-\]
            " + else + out += " None." + out += " \[+\]
            " + + usr << browse(out, "window=edit_mode[src]") + feedback_add_details("admin_verb","SGM") + + +/datum/admins/proc/toggletintedweldhelmets() + set category = "Debug" + set desc="Reduces view range when wearing welding helmets" + set name="Toggle tinted welding helmets." + config.welder_vision = !( config.welder_vision ) + if (config.welder_vision) + to_world("Reduced welder vision has been enabled!") + else + to_world("Reduced welder vision has been disabled!") + log_and_message_admins("toggled welder vision.") + feedback_add_details("admin_verb","TTWH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/toggleguests() + set category = "Server" + set desc="Guests can't enter" + set name="Toggle guests" + config.guests_allowed = !(config.guests_allowed) + if (!(config.guests_allowed)) + to_world("Guests may no longer enter the game.") + else + to_world("Guests may now enter the game.") + log_admin("[key_name(usr)] toggled guests game entering [config.guests_allowed?"":"dis"]allowed.") + log_and_message_admins("toggled guests game entering [config.guests_allowed?"":"dis"]allowed.") + feedback_add_details("admin_verb","TGU") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/output_ai_laws() + var/ai_number = 0 + for(var/mob/living/silicon/S in SSmobs.mob_list) + ai_number++ + if(isAI(S)) + to_chat(usr, "AI [key_name(S, usr)]'s laws:") + else if(isrobot(S)) + var/mob/living/silicon/robot/R = S + to_chat(usr, "CYBORG [key_name(S, usr)] [R.connected_ai?"(Slaved to: [R.connected_ai])":"(Independant)"]: laws:") + else if (ispAI(S)) + to_chat(usr, "pAI [key_name(S, usr)]'s laws:") + else + to_chat(usr, "SOMETHING SILICON [key_name(S, usr)]'s laws:") + + if (S.laws == null) + to_chat(usr, "[key_name(S, usr)]'s laws are null?? Contact a coder.") + else + S.laws.show_laws(usr) + if(!ai_number) + to_chat(usr, "No AIs located")//Just so you know the thing is actually working and not just ignoring you. + + +/client/proc/update_mob_sprite(mob/living/carbon/human/H as mob) + set category = "Admin" + set name = "Update Mob Sprite" + set desc = "Should fix any mob sprite update errors." + + if (!holder) + to_chat(src, "Only administrators may use this command.") + return + + if(istype(H)) + H.regenerate_icons() + + +/* + helper proc to test if someone is a mentor or not. Got tired of writing this same check all over the place. +*/ +/proc/is_mentor(client/C) + + if(!istype(C)) + return 0 + if(!C.holder) + return 0 + + if(C.holder.rights == R_MENTOR) + return 1 + return 0 + +/proc/get_options_bar(whom, detail = 2, name = 0, link = 1, highlight_special = 1, var/datum/ticket/ticket = null) + if(!whom) + return "(*null*)" + var/mob/M + var/client/C + if(istype(whom, /client)) + C = whom + M = C.mob + else if(istype(whom, /mob)) + M = whom + C = M.client + else + return "(*not a mob*)" + switch(detail) + if(0) + return "[key_name(C, link, name, highlight_special, ticket)]" + + if(1) //Private Messages + return "[key_name(C, link, name, highlight_special, ticket)](?)" + + if(2) //Admins + var/ref_mob = "\ref[M]" + return "[key_name(C, link, name, highlight_special, ticket)](?) (PP) (VV) (SM) ([admin_jump_link(M, src)]) (CA)" + + if(3) //Devs + var/ref_mob = "\ref[M]" + return "[key_name(C, link, name, highlight_special, ticket)](VV)([admin_jump_link(M, src)])" + + if(4) //Mentors + var/ref_mob = "\ref[M]" + return "[key_name(C, link, name, highlight_special, ticket)] (?) (PP) (VV) (SM) ([admin_jump_link(M, src)])" + + +/proc/ishost(whom) + if(!whom) + return 0 + var/client/C + var/mob/M + if(istype(whom, /client)) + C = whom + if(istype(whom, /mob)) + M = whom + C = M.client + if(R_HOST & C.holder.rights) + return 1 + else + return 0 + +//Prevents SDQL2 commands from changing admin permissions +/datum/admins/SDQL_update(var/const/var_name, var/new_value) + return 0 + +// +// +//ALL DONE +//********************************************************************************************************* +// + +//Returns 1 to let the dragdrop code know we are trapping this event +//Returns 0 if we don't plan to trap the event +/datum/admins/proc/cmd_ghost_drag(var/mob/observer/ghost/frommob, var/mob/living/tomob) + if(!istype(frommob)) + return //Extra sanity check to make sure only observers are shoved into things + + //Same as assume-direct-control perm requirements. + if (!check_rights(R_VAREDIT,0) || !check_rights(R_ADMIN|R_DEBUG,0)) + return 0 + if (!frommob.ckey) + return 0 + var/question = "" + if (tomob.ckey) + question = "This mob already has a user ([tomob.key]) in control of it! " + question += "Are you sure you want to place [frommob.name]([frommob.key]) in control of [tomob.name]?" + var/ask = alert(question, "Place ghost in control of mob?", "Yes", "No") + if (ask != "Yes") + return 1 + if (!frommob || !tomob) //make sure the mobs don't go away while we waited for a response + return 1 + if(tomob.client) //No need to ghostize if there is no client + tomob.ghostize(0) + message_admins("[key_name_admin(usr)] has put [frommob.ckey] in control of [tomob.name].") + log_admin("[key_name(usr)] stuffed [frommob.ckey] into [tomob.name].") + feedback_add_details("admin_verb","CGD") + tomob.ckey = frommob.ckey + qdel(frommob) + return 1 + +/datum/admins/proc/force_antag_latespawn() + set category = "Admin" + set name = "Force Template Spawn" + set desc = "Force an antagonist template to spawn." + + if (!istype(src,/datum/admins)) + src = usr.client.holder + if (!istype(src,/datum/admins)) + to_chat(usr, "Error: you are not an admin!") + return + + if(!ticker || !ticker.mode) + to_chat(usr, "Mode has not started.") + return + + var/list/all_antag_types = all_antag_types() + var/antag_type = input("Choose a template.","Force Latespawn") as null|anything in all_antag_types + if(!antag_type || !all_antag_types[antag_type]) + to_chat(usr, "Aborting.") + return + + 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() + +/datum/admins/proc/force_mode_latespawn() + set category = "Admin" + set name = "Force Mode Spawn" + set desc = "Force autotraitor to proc." + + if (!istype(src,/datum/admins)) + src = usr.client.holder + if (!istype(src,/datum/admins) || !check_rights(R_ADMIN)) + to_chat(usr, "Error: you are not an admin!") + return + + if(!ticker || !ticker.mode) + to_chat(usr, "Mode has not started.") + return + + log_and_message_admins("attempting to force mode autospawn.") + ticker.mode.process_autoantag() + +/datum/admins/proc/paralyze_mob(mob/H as mob in GLOB.player_list) + set category = "Admin" + set name = "Toggle Paralyze" + set desc = "Paralyzes a player. Or unparalyses them." + + var/msg + + if(!isliving(H)) + return + + if(check_rights(R_ADMIN)) + if (H.paralysis == 0) + H.paralysis = 8000 + msg = "has paralyzed [key_name(H)]." + else + H.paralysis = 0 + msg = "has unparalyzed [key_name(H)]." + log_and_message_admins(msg) + + +/datum/admins/proc/sendFax() + set category = "Special Verbs" + set name = "Send Fax" + set desc = "Sends a fax to this machine" + var/department = input("Choose a fax", "Fax") as null|anything in GLOB.alldepartments + for(var/obj/machinery/photocopier/faxmachine/sendto in GLOB.allfaxes) + if(sendto.department == department) + + if (!istype(src,/datum/admins)) + src = usr.client.holder + if (!istype(src,/datum/admins)) + to_chat(usr, "Error: you are not an admin!") + return + + var/replyorigin = input(src.owner, "Please specify who the fax is coming from", "Origin") as text|null + + var/obj/item/weapon/paper/admin/P = new /obj/item/weapon/paper/admin( null ) //hopefully the null loc won't cause trouble for us + faxreply = P + + P.admindatum = src + P.origin = replyorigin + P.destination = sendto + + P.adminbrowse() + + +datum/admins/var/obj/item/weapon/paper/admin/faxreply // var to hold fax replies in + +/datum/admins/proc/faxCallback(var/obj/item/weapon/paper/admin/P, var/obj/machinery/photocopier/faxmachine/destination) + var/customname = input(src.owner, "Pick a title for the report", "Title") as text|null + + P.SetName("[P.origin] - [customname]") + P.desc = "This is a paper titled '" + P.name + "'." + + var/shouldStamp = 1 + if(!P.sender) // admin initiated + switch(alert("Would you like the fax stamped?",, "Yes", "No")) + if("No") + shouldStamp = 0 + + if(shouldStamp) + P.stamps += "
            This paper has been stamped by the [P.origin] Quantum Relay." + + var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') + var/x + var/y + x = rand(-2, 0) + y = rand(-1, 2) + P.offset_x += x + P.offset_y += y + stampoverlay.pixel_x = x + stampoverlay.pixel_y = y + + if(!P.ico) + P.ico = new + P.ico += "paper_stamp-cent" + stampoverlay.icon_state = "paper_stamp-cent" + + if(!P.stamped) + P.stamped = new + P.stamped += /obj/item/weapon/stamp/centcomm + P.overlays += stampoverlay + + var/obj/item/rcvdcopy + rcvdcopy = destination.copy(P) + rcvdcopy.loc = null //hopefully this shouldn't cause trouble + GLOB.adminfaxes += rcvdcopy + + + + if(destination.recievefax(P)) + to_chat(src.owner, "Message reply to transmitted successfully.") + if(P.sender) // sent as a reply + log_admin("[key_name(src.owner)] replied to a fax message from [key_name(P.sender)]") + for(var/client/C in GLOB.admins) + if((R_ADMIN | R_MOD) & C.holder.rights) + to_chat(C, "FAX LOG:[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(P.sender)] (VIEW)") + else + log_admin("[key_name(src.owner)] has sent a fax message to [destination.department]") + for(var/client/C in GLOB.admins) + if((R_ADMIN | R_MOD) & C.holder.rights) + to_chat(C, "FAX LOG:[key_name_admin(src.owner)] has sent a fax message to [destination.department] (VIEW)") + + else + to_chat(src.owner, "Message reply failed.") + + spawn(100) + qdel(P) + faxreply = null + return diff --git a/code/modules/admin/admin_attack_log.dm b/code/modules/admin/admin_attack_log.dm new file mode 100644 index 00000000..c1e2d14e --- /dev/null +++ b/code/modules/admin/admin_attack_log.dm @@ -0,0 +1,122 @@ +/mob + var/datum/mob_lite/last_attacker_ = null + var/datum/mob_lite/last_attacked_ = null + var/mob/attack_logs_ = list() + +/proc/log_and_message_admins(var/message as text, var/mob/user = usr, var/turf/location) + var/turf/T = location ? location : (user ? get_turf(user) : null) + message = append_admin_tools(message, user, T) + + log_admin(user ? "[key_name(user)] [message]" : "EVENT [message]") + message_admins(user ? "[key_name_admin(user)] [message]" : "EVENT [message]") + +/proc/log_and_message_staff(var/message as text, var/mob/user = usr, var/turf/location) + var/turf/T = location ? location : (user ? get_turf(user) : null) + message = append_admin_tools(message, user, T) + + log_admin(user ? "[key_name(user)] [message]" : "EVENT [message]") + message_staff(user ? "[key_name_admin(user)] [message]" : "EVENT [message]") + +/proc/log_and_message_admins_many(var/list/mob/users, var/message) + if(!users || !users.len) + return + + var/list/user_keys = list() + for(var/mob/user in users) + user_keys += key_name(user) + + log_admin("[english_list(user_keys)] [message]") + message_admins("[english_list(user_keys)] [message]") + +/proc/admin_attacker_log(var/mob/attacker, var/attacker_message) + if(!attacker) + EXCEPTION("No attacker was supplied.") + admin_attack_log(attacker, null, attacker_message, null, attacker_message) + +/proc/admin_victim_log(var/mob/victim, var/victim_message) + if(!victim) + EXCEPTION("No victim was supplied.") + admin_attack_log(null, victim, null, victim_message, victim_message) + +/proc/admin_attack_log(var/mob/attacker, var/mob/victim, var/attacker_message, var/victim_message, var/admin_message) + if(!(attacker || victim)) + EXCEPTION("Neither attacker or victim was supplied.") + if(!store_admin_attack_log(attacker, victim)) + return + + var/turf/attack_location + var/intent = "(INTENT: N/A)" + if(attacker) + intent = "(INTENT: [uppertext(attacker.a_intent)])" + if(victim) + attacker.attack_logs_ += text("\[[time_stamp()]\] [key_name(victim)] - [attacker_message] [intent]") + else + attacker.attack_logs_ += text("\[[time_stamp()]\] [attacker_message] [intent]") + attacker.last_attacked_ = mob_repository.get_lite_mob(victim) + attack_location = get_turf(attacker) + if(victim) + if(attacker) + victim.attack_logs_ += text("\[[time_stamp()]\] [key_name(attacker)] - [victim_message] [intent]") + else + victim.attack_logs_ += text("\[[time_stamp()]\] [victim_message]") + victim.last_attacker_ = mob_repository.get_lite_mob(attacker) + if(!attack_location) + attack_location = get_turf(victim) + + attack_log_repository.store_attack_log(attacker, victim, admin_message) + + if(!notify_about_admin_attack_log(attacker, victim)) + return + + var/full_admin_message + if(attacker && victim) + full_admin_message = "[key_name(attacker)] [admin_message] [key_name(victim)] (INTENT: [attacker? uppertext(attacker.a_intent) : "N/A"])" + else if(attacker) + full_admin_message = "[key_name(attacker)] [admin_message] (INTENT: [attacker? uppertext(attacker.a_intent) : "N/A"])" + else + full_admin_message = "[key_name(victim)] [admin_message]" + full_admin_message = append_admin_tools(full_admin_message, attacker||victim, attack_location) + msg_admin_attack(full_admin_message) + +// Only store attack logs if any of the involved subjects have (had) a client +/proc/store_admin_attack_log(var/mob/attacker, var/mob/victim) + if(attacker && attacker.ckey) + return TRUE + if(victim && victim.ckey) + return TRUE + return FALSE + +// Only notify admins if all involved subjects have (had) a client +/proc/notify_about_admin_attack_log(var/mob/attacker, var/mob/victim) + if(attacker && victim) + return attacker.ckey && victim.ckey + if(attacker) + return attacker.ckey + if(victim) + return victim.ckey + return FALSE + +/proc/admin_attacker_log_many_victims(var/mob/attacker, var/list/mob/victims, var/attacker_message, var/victim_message, var/admin_message) + if(!victims || !victims.len) + return + + for(var/mob/victim in victims) + admin_attack_log(attacker, victim, attacker_message, victim_message, admin_message) + +/proc/admin_inject_log(mob/attacker, mob/victim, obj/item/weapon, reagents, amount_transferred, violent=0) + if(violent) + violent = "violently " + else + violent = "" + admin_attack_log(attacker, + victim, + "used \the [weapon] to [violent]inject - [reagents] - [amount_transferred]u transferred", + "was [violent]injected with \the [weapon] - [reagents] - [amount_transferred]u transferred", + "used \the [weapon] to [violent]inject [reagents] ([amount_transferred]u transferred) into") + +/proc/append_admin_tools(var/message, var/mob, var/turf/location) + if(location) + message = message + " (LOC)" + if(mob) + message = message + " (MOB)" + return message diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm new file mode 100644 index 00000000..558e21cc --- /dev/null +++ b/code/modules/admin/admin_investigate.dm @@ -0,0 +1,50 @@ +//By Carnwennan + +//This system was made as an alternative to all the in-game lists and variables used to log stuff in-game. +//lists and variables are great. However, they have several major flaws: +//Firstly, they use memory. TGstation has one of the highest memory usage of all the ss13 branches. +//Secondly, they are usually stored in an object. This means that they aren't centralised. It also means that +//the data is lost when the object is deleted! This is especially annoying for things like the singulo engine! +#define INVESTIGATE_DIR "data/investigate/" + +//SYSTEM +/proc/investigate_subject2file(var/subject) + return file("[INVESTIGATE_DIR][subject].html") + +/hook/startup/proc/resetInvestigate() + investigate_reset() + return 1 + +/proc/investigate_reset() + if(fdel(INVESTIGATE_DIR)) return 1 + return 0 + +/atom/proc/investigate_log(var/message, var/subject) + if(!message) return + var/F = investigate_subject2file(subject) + if(!F) return + to_chat(F, "[time_stamp()] \ref[src] ([x],[y],[z]) || [src] [message]
            ") + +//ADMINVERBS +/client/proc/investigate_show( subject in list("hrefs","notes","singulo","telesci") ) + set name = "Investigate" + set category = "Admin" + if(!holder) return + switch(subject) + if("singulo", "telesci") //general one-round-only stuff + var/F = investigate_subject2file(subject) + if(!F) + to_chat(src, "Error: admin_investigate: [INVESTIGATE_DIR][subject] is an invalid path or cannot be accessed.") + return + src << browse(F,"window=investigate[subject];size=800x300") + + if("hrefs") //persistant logs and stuff + if(config && config.log_hrefs) + if(href_logfile) + src << browse(href_logfile,"window=investigate[subject];size=800x300") + else + to_chat(src, "Error: admin_investigate: No href logfile found.") + return + else + to_chat(src, "Error: admin_investigate: Href Logging is not on.") + return diff --git a/code/modules/admin/admin_memo.dm b/code/modules/admin/admin_memo.dm new file mode 100644 index 00000000..24ecba7c --- /dev/null +++ b/code/modules/admin/admin_memo.dm @@ -0,0 +1,54 @@ +#define MEMOFILE "data/memo.sav" //where the memos are saved +#define ENABLE_MEMOS 1 //using a define because screw making a config variable for it. This is more efficient and purty. + +//switch verb so we don't spam up the verb lists with like, 3 verbs for this feature. +/client/proc/admin_memo(task in list("write","show","delete")) + set name = "Memo" + set category = "Server" + if(!ENABLE_MEMOS) return + if(!check_rights(0)) return + switch(task) + if("write") admin_memo_write() + if("show") admin_memo_show() + if("delete") admin_memo_delete() + +//write a message +/client/proc/admin_memo_write() + var/savefile/F = new(MEMOFILE) + if(F) + var/memo = sanitize(input(src,"Type your memo\n(Leaving it blank will delete your current memo):","Write Memo",null) as null|message, extra = 0) + switch(memo) + if(null) + return + if("") + F.dir.Remove(ckey) + to_chat(src, "Memo removed") + return + if( findtext(memo,"[memo]" + message_admins("[key] set an admin memo:
            [memo]") + +//show all memos +/client/proc/admin_memo_show() + if(ENABLE_MEMOS) + var/savefile/F = new(MEMOFILE) + if(F) + for(var/ckey in F.dir) + to_chat(src, "
            Admin Memo by [F[ckey]]
            ") + +//delete your own or somebody else's memo +/client/proc/admin_memo_delete() + var/savefile/F = new(MEMOFILE) + if(F) + var/ckey + if(check_rights(R_SERVER,0)) //high ranking admins can delete other admin's memos + ckey = input(src,"Whose memo shall we remove?","Remove Memo",null) as null|anything in F.dir + else + ckey = src.ckey + if(ckey) + F.dir.Remove(ckey) + to_chat(src, "Removed Memo created by [ckey].") + +#undef MEMOFILE +#undef ENABLE_MEMOS \ No newline at end of file diff --git a/code/modules/admin/admin_ranks.dm b/code/modules/admin/admin_ranks.dm new file mode 100644 index 00000000..ffa0f3b1 --- /dev/null +++ b/code/modules/admin/admin_ranks.dm @@ -0,0 +1,161 @@ +var/list/admin_ranks = list() //list of all ranks with associated rights + +//load our rank - > rights associations +/proc/load_admin_ranks() + admin_ranks.Cut() + + var/previous_rights = 0 + + //load text from file + var/list/Lines = file2list("config/admin_ranks.txt") + + //process each line seperately + for(var/line in Lines) + if(!length(line)) continue + if(copytext(line,1,2) == "#") continue + + var/list/List = splittext(line,"+") + if(!List.len) continue + + var/rank = ckeyEx(List[1]) + switch(rank) + if(null,"") continue + if("Removed") continue //Reserved + + var/rights = 0 + for(var/i=2, i<=List.len, i++) + switch(ckey(List[i])) + if("@","prev") rights |= previous_rights + if("buildmode","build") rights |= R_BUILDMODE + if("admin") rights |= R_ADMIN + if("ban") rights |= R_BAN + if("fun") rights |= R_FUN + if("server") rights |= R_SERVER + if("debug") rights |= R_DEBUG + if("permissions","rights") rights |= R_PERMISSIONS + if("possess") rights |= R_POSSESS + if("stealth") rights |= R_STEALTH + if("rejuv","rejuvinate") rights |= R_REJUVINATE + if("varedit") rights |= R_VAREDIT + if("everything","host","all") rights |= (R_HOST | R_BUILDMODE | R_ADMIN | R_BAN | R_FUN | R_SERVER | R_DEBUG | R_PERMISSIONS | R_POSSESS | R_STEALTH | R_REJUVINATE | R_VAREDIT | R_SOUNDS | R_SPAWN | R_MOD| R_MENTOR) + if("sound","sounds") rights |= R_SOUNDS + if("spawn","create") rights |= R_SPAWN + if("mod") rights |= R_MOD + if("mentor") rights |= R_MENTOR + + admin_ranks[rank] = rights + previous_rights = rights + + #ifdef TESTING + var/msg = "Permission Sets Built:\n" + for(var/rank in admin_ranks) + msg += "\t[rank] - [admin_ranks[rank]]\n" + testing(msg) + #endif + +/hook/startup/proc/loadAdmins() + load_admins() + return 1 + +/proc/load_admins() + //clear the datums references + admin_datums.Cut() + for(var/client/C in GLOB.admins) + C.remove_admin_verbs() + C.holder = null + GLOB.admins.Cut() + + if(config.admin_legacy_system) + load_admin_ranks() + + //load text from file + var/list/Lines = file2list("config/admins.txt") + + //process each line seperately + for(var/line in Lines) + if(!length(line)) continue + if(copytext(line,1,2) == "#") continue + + //Split the line at every "-" + var/list/List = splittext(line, "-") + if(!List.len) continue + + //ckey is before the first "-" + var/ckey = ckey(List[1]) + if(!ckey) continue + + //rank follows the first "-" + var/rank = "" + if(List.len >= 2) + rank = ckeyEx(List[2]) + + //load permissions associated with this rank + var/rights = admin_ranks[rank] + + //create the admin datum and store it for later use + var/datum/admins/D = new /datum/admins(rank, rights, ckey) + + //find the client for a ckey if they are connected and associate them with the new admin datum + D.associate(GLOB.ckey_directory[ckey]) + + else + //The current admin system uses SQL + + establish_db_connection() + if(!dbcon.IsConnected()) + error("Failed to connect to database in load_admins(). Reverting to legacy system.") + log_misc("Failed to connect to database in load_admins(). Reverting to legacy system.") + config.admin_legacy_system = 1 + load_admins() + return + + var/DBQuery/query = dbcon.NewQuery("SELECT ckey, rank, level, flags FROM erro_admin") + query.Execute() + while(query.NextRow()) + var/ckey = query.item[1] + var/rank = query.item[2] + if(rank == "Removed") continue //This person was de-adminned. They are only in the admin list for archive purposes. + + var/rights = query.item[4] + if(istext(rights)) rights = text2num(rights) + var/datum/admins/D = new /datum/admins(rank, rights, ckey) + + //find the client for a ckey if they are connected and associate them with the new admin datum + D.associate(GLOB.ckey_directory[ckey]) + //ensure that we loaded the admins correctly + if(!admin_datums) + error("The database query in load_admins() resulted in no admins being added to the list. Reverting to legacy system.") + log_misc("The database query in load_admins() resulted in no admins being added to the list. Reverting to legacy system.") + config.admin_legacy_system = 1 + load_admins() + return + #ifdef TESTING + var/msg = "Admins Built:\n" + for(var/ckey in admin_datums) + var/rank + var/datum/admins/D = admin_datums[ckey] + if(D) rank = D.rank + msg += "\t[ckey] - [rank]\n" + testing(msg) + #endif + + +#ifdef TESTING +/client/verb/changerank(newrank in admin_ranks) + if(holder) + holder.rank = newrank + holder.rights = admin_ranks[newrank] + else + holder = new /datum/admins(newrank,admin_ranks[newrank],ckey) + remove_admin_verbs() + holder.associate(src) + +/client/verb/changerights(newrights as num) + if(holder) + holder.rights = newrights + else + holder = new /datum/admins("testing",newrights,ckey) + remove_admin_verbs() + holder.associate(src) + +#endif diff --git a/code/modules/admin/admin_report.dm b/code/modules/admin/admin_report.dm new file mode 100644 index 00000000..2be22b6c --- /dev/null +++ b/code/modules/admin/admin_report.dm @@ -0,0 +1,176 @@ +// Reports are a way to notify admins of wrongdoings that happened +// while no admin was present. They work a bit similar to news, but +// they can only be read by admins and moderators. + +// a single admin report +datum/admin_report/var + ID // the ID of the report + body // the content of the report + author // key of the author + date // date on which this was created + done // whether this was handled + + offender_key // store the key of the offender + offender_cid // store the cid of the offender + +datum/report_topic_handler + Topic(href,href_list) + ..() + var/client/C = locate(href_list["client"]) + if(href_list["action"] == "show_reports") + C.display_admin_reports() + else if(href_list["action"] == "remove") + C.mark_report_done(text2num(href_list["ID"])) + else if(href_list["action"] == "edit") + C.edit_report(text2num(href_list["ID"])) + +var/datum/report_topic_handler/report_topic_handler + +world/New() + ..() + report_topic_handler = new + +// add a new news datums +proc/make_report(body, author, okey, cid) + var/savefile/Reports = new("data/reports.sav") + var/list/reports + var/lastID + + Reports["reports"] >> reports + Reports["lastID"] >> lastID + + if(!reports) reports = list() + if(!lastID) lastID = 0 + + var/datum/admin_report/created = new() + created.ID = ++lastID + created.body = body + created.author = author + created.date = world.realtime + created.done = 0 + created.offender_key = okey + created.offender_cid = cid + + reports.Insert(1, created) + + to_chat(Reports["reports"], reports) + to_chat(Reports["lastID"], lastID) +// load the reports from disk +proc/load_reports() + var/savefile/Reports = new("data/reports.sav") + var/list/reports + + Reports["reports"] >> reports + + if(!reports) reports = list() + + return reports + +// check if there are any unhandled reports +client/proc/unhandled_reports() + if(!src.holder) return 0 + var/list/reports = load_reports() + + for(var/datum/admin_report/N in reports) + if(N.done) + continue + else return 1 + + return 0 + +// checks if the player has an unhandled report against him +client/proc/is_reported() + var/list/reports = load_reports() + + for(var/datum/admin_report/N in reports) if(!N.done) + if(N.offender_key == src.key) + return 1 + + return 0 + +// display only the reports that haven't been handled +client/proc/display_admin_reports() + set category = "Admin" + set name = "Display Admin Reports" + if(!src.holder) return + + var/list/reports = load_reports() + + var/output = "" + if(unhandled_reports()) + // load the list of unhandled reports + for(var/datum/admin_report/N in reports) + if(N.done) + continue + output += "Reported player: [N.offender_key](CID: [N.offender_cid])
            " + output += "Offense:[N.body]
            " + output += "Occured at [time2text(N.date,"MM/DD hh:mm:ss")]
            " + output += "authored by [N.author]
            " + output += " Flag as Handled" + if(src.key == N.author) + output += " Edit" + output += "
            " + output += "
            " + else + output += "Whoops, no reports!" + + usr << browse(output, "window=news;size=600x400") + + +client/proc/Report(mob/M as mob in mob_list) + set category = "Admin" + if(!src.holder) + return + + var/CID = "Unknown" + if(M.client) + CID = M.client.computer_id + + var/body = input(src.mob, "Describe in detail what you're reporting [M] for", "Report") as null|text + if(!body) return + + + make_report(body, key, M.key, CID) + + spawn(1) + display_admin_reports() + +client/proc/mark_report_done(ID as num) + if(!src.holder || src.holder.level < 0) + return + + var/savefile/Reports = new("data/reports.sav") + var/list/reports + + Reports["reports"] >> reports + + var/datum/admin_report/found + for(var/datum/admin_report/N in reports) + if(N.ID == ID) + found = N + if(!found) to_chat(src, "* An error occured, sorry.") + + found.done = 1 + + to_chat(Reports["reports"], reports) +client/proc/edit_report(ID as num) + if(!src.holder || src.holder.level < 0) + to_chat(src, "You tried to modify the news, but you're not an admin!") + return + + var/savefile/Reports = new("data/reports.sav") + var/list/reports + + Reports["reports"] >> reports + + var/datum/admin_report/found + for(var/datum/admin_report/N in reports) + if(N.ID == ID) + found = N + if(!found) to_chat(src, "* An error occured, sorry.") + var/body = input(src.mob, "Enter a body for the news", "Body") as null|message + if(!body) return + + found.body = body + + to_chat(Reports["reports"], reports) diff --git a/code/modules/admin/admin_secrets.dm b/code/modules/admin/admin_secrets.dm new file mode 100644 index 00000000..e0834169 --- /dev/null +++ b/code/modules/admin/admin_secrets.dm @@ -0,0 +1,128 @@ +var/datum/admin_secrets/admin_secrets = new() + +/datum/admin_secrets + var/list/datum/admin_secret_category/categories + var/list/datum/admin_secret_item/items + +/datum/admin_secrets/New() + ..() + categories = init_subtypes(/datum/admin_secret_category) + items = list() + var/list/category_assoc = list() + for(var/datum/admin_secret_category/category in categories) + category_assoc[category.type] = category + + for(var/item_type in (typesof(/datum/admin_secret_item) - /datum/admin_secret_item)) + var/datum/admin_secret_item/secret_item = item_type + if(!initial(secret_item.name)) + continue + + var/datum/admin_secret_item/item = new item_type() + var/datum/admin_secret_category/category = category_assoc[item.category] + dd_insertObjectList(category.items, item) + items += item + +// +// Secret Item Category - Each subtype is a category for organizing secret commands. +// +/datum/admin_secret_category + var/name = "" + var/desc = "" + var/list/datum/admin_secret_item/items + +/datum/admin_secret_category + items = list() + +/datum/admin_secret_category/proc/can_view(var/mob/user) + for(var/datum/admin_secret_item/item in items) + if(item.can_view(user)) + return 1 + return 0 + +// +// Secret Item Datum - Each subtype is a command on the secrets panel. +// Override execute() with the implementation of the command. +// +/datum/admin_secret_item + var/name = "" + var/category = null + var/log = 1 + var/feedback = 1 + var/permissions = R_HOST + var/warn_before_use = 0 + +/datum/admin_secret_item/dd_SortValue() + return "[name]" + +/datum/admin_secret_item/proc/name() + return name + +/datum/admin_secret_item/proc/can_view(var/mob/user) + return check_rights(permissions, 0, user) + +/datum/admin_secret_item/proc/can_execute(var/mob/user) + if(can_view(user)) + if(!warn_before_use || alert("Execute the command '[name]'?", name, "No","Yes") == "Yes") + return 1 + return 0 + +/datum/admin_secret_item/proc/execute(var/mob/user) + if(!can_execute(user)) + return 0 + + if(log) + log_and_message_admins("used secret '[name]'", user) + if(feedback) + feedback_inc("admin_secrets_used",1) + feedback_add_details("admin_secrets_used","[name]") + return 1 + +/datum/admin_secret_item/Topic() + . = ..() + return !. && !can_execute(usr) + +/************************* +* Pre-defined categories * +*************************/ +/datum/admin_secret_category/admin_secrets + name = "Admin Secrets" + +/datum/admin_secret_category/investigation + name = "Investigation" + +/datum/admin_secret_category/random_events + name = "'Random' Events" + +/datum/admin_secret_category/fun_secrets + name = "Fun Secrets" + +/datum/admin_secret_category/final_solutions + name = "Final Solutions" + desc = "(Warning, these will end the round!)" + +/************************* +* Pre-defined base items * +*************************/ +/datum/admin_secret_item/admin_secret + category = /datum/admin_secret_category/admin_secrets + log = 0 + permissions = R_ADMIN + +/datum/admin_secret_item/investigation + category = /datum/admin_secret_category/investigation + log = 0 + permissions = R_INVESTIGATE + +/datum/admin_secret_item/random_event + category = /datum/admin_secret_category/random_events + permissions = R_FUN + warn_before_use = 1 + +/datum/admin_secret_item/fun_secret + category = /datum/admin_secret_category/fun_secrets + permissions = R_FUN + warn_before_use = 1 + +/datum/admin_secret_item/final_solution + category = /datum/admin_secret_category/final_solutions + permissions = R_FUN|R_SERVER|R_ADMIN diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm new file mode 100644 index 00000000..3b41fefd --- /dev/null +++ b/code/modules/admin/admin_verbs.dm @@ -0,0 +1,957 @@ +//admin verb groups - They can overlap if you so wish. Only one of each verb will exist in the verbs list regardless +var/list/admin_verbs_default = list( + /datum/admins/proc/show_player_panel, //shows an interface for individual players, with various links (links require additional flags, + /client/proc/player_panel, + /client/proc/secrets, + /client/proc/deadmin_self, //destroys our own admin datum so we can play as a regular player, + /client/proc/hide_verbs, //hides all our adminverbs, + /client/proc/hide_most_verbs, //hides all our hideable adminverbs, + /client/proc/debug_variables, //allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify, + /client/proc/debug_global_variables,//as above but for global variables, +// /client/proc/check_antagonists, //shows all antags, + /client/proc/cmd_mentor_check_new_players +// /client/proc/deadchat //toggles deadchat on/off, + ) +var/list/admin_verbs_admin = list( + /client/proc/player_panel_new, //shows an interface for all players, with links to various panels, + /client/proc/invisimin, //allows our mob to go invisible/visible, +// /datum/admins/proc/show_traitor_panel, //interface which shows a mob's mind, -Removed due to rare practical use. Moved to debug verbs ~Errorage, + /datum/admins/proc/show_game_mode, //Configuration window for the current game mode., + /datum/admins/proc/force_mode_latespawn, //Force the mode to try a latespawn proc, + /datum/admins/proc/force_antag_latespawn, //Force a specific template to try a latespawn proc, + /datum/admins/proc/toggleenter, //toggles whether people can join the current game, + /datum/admins/proc/toggleguests, //toggles whether guests can join the current game, + /datum/admins/proc/announce, //priority announce something to all clients., + /client/proc/colorooc, //allows us to set a custom colour for everythign we say in ooc, + /client/proc/admin_ghost, //allows us to ghost/reenter body at will, + /client/proc/toggle_view_range, //changes how far we can see, + /datum/admins/proc/view_txt_log, //shows the server log (diary) for today, + /datum/admins/proc/view_atk_log, //shows the server combat-log, doesn't do anything presently, + /client/proc/cmd_admin_pm_context, //right-click adminPM interface, + /client/proc/cmd_admin_pm_panel, //admin-pm list, + /client/proc/cmd_admin_subtle_message, //send an message to somebody as a 'voice in their head', + /client/proc/cmd_admin_delete, //delete an instance/object/mob/etc, + /client/proc/cmd_admin_check_contents, //displays the contents of an instance, + /datum/admins/proc/access_news_network, //allows access of newscasters, + /client/proc/giveruntimelog, //allows us to give access to runtime logs to somebody, + /client/proc/getserverlog, //allows us to fetch server logs (diary) for other days, + /client/proc/jumptocoord, //we ghost and jump to a coordinate, + /client/proc/Getmob, //teleports a mob to our location, + /client/proc/Getkey, //teleports a mob with a certain ckey to our location, +// /client/proc/sendmob, //sends a mob somewhere, -Removed due to it needing two sorting procs to work, which were executed every time an admin right-clicked. ~Errorage, + /client/proc/Jump, + /client/proc/jumptokey, //allows us to jump to the location of a mob with a certain ckey, + /client/proc/jumptomob, //allows us to jump to a specific mob, + /client/proc/jumptoturf, //allows us to jump to a specific turf, + /client/proc/admin_call_shuttle, //allows us to call the emergency shuttle, + /client/proc/admin_cancel_shuttle, //allows us to cancel the emergency shuttle, sending it back to centcomm, + /client/proc/cmd_admin_direct_narrate, //send text directly to a player with no padding. Useful for narratives and fluff-text, + /client/proc/cmd_admin_visible_narrate, + /client/proc/cmd_admin_audible_narrate, + /client/proc/cmd_admin_local_narrate, + /client/proc/cmd_admin_world_narrate, //sends text to all players with no padding, + /client/proc/cmd_admin_create_centcom_report, + /client/proc/check_ai_laws, //shows AI and borg laws, + /client/proc/rename_silicon, //properly renames silicons, + /client/proc/manage_silicon_laws, // Allows viewing and editing silicon laws. , + /client/proc/check_antagonists, + /client/proc/admin_memo, //admin memo system. show/delete/write. +SERVER needed to delete admin memos of others, + /client/proc/dsay, //talk in deadchat using our ckey +// /client/proc/toggle_hear_deadcast, //toggles whether we hear deadchat, + /client/proc/investigate_show, //various admintools for investigation. Such as a singulo grief-log, + /datum/admins/proc/toggleooc, //toggles ooc on/off for everyone, + /datum/admins/proc/togglelooc, //toggles looc on/off for everyone, + /datum/admins/proc/toggleoocdead, //toggles ooc on/off for everyone who is dead, + /datum/admins/proc/toggledsay, //toggles dsay on/off for everyone, + /client/proc/game_panel, //game panel, allows to change game-mode etc, + /client/proc/cmd_admin_say, //admin-only ooc chat, + /datum/admins/proc/togglehubvisibility, //toggles visibility on the BYOND Hub, + /datum/admins/proc/PlayerNotes, + /client/proc/cmd_mod_say, + /datum/admins/proc/show_player_info, + /client/proc/free_slot, //frees slot for chosen job, + /client/proc/cmd_admin_change_custom_event, + /client/proc/cmd_admin_rejuvenate, + /client/proc/toggleghostwriters, + /client/proc/toggledrones, + /client/proc/check_customitem_activity, + /client/proc/man_up, + /client/proc/global_man_up, + /client/proc/response_team, // Response Teams admin verb, + /client/proc/toggle_antagHUD_use, + /client/proc/toggle_antagHUD_restrictions, + /client/proc/allow_character_respawn, // Allows a ghost to respawn , + /client/proc/event_manager_panel, + /client/proc/empty_ai_core_toggle_latejoin, + /client/proc/empty_ai_core_toggle_latejoin, + /client/proc/change_human_appearance_admin, // Allows an admin to change the basic appearance of human-based mobs , + /client/proc/change_human_appearance_self, // Allows the human-based mob itself change its basic appearance , + /client/proc/change_security_level, + /client/proc/view_chemical_reaction_logs, + /client/proc/makePAI, + /datum/admins/proc/paralyze_mob, + /client/proc/fixatmos, + /client/proc/list_traders, + /client/proc/add_trader, + /client/proc/remove_trader, + /datum/admins/proc/sendFax, + /client/proc/toggle_right_click, + /datum/admins/proc/ToggleCkeyWhitelist, + /datum/admins/proc/ReloadCkeyWhitelist, + /datum/admins/proc/toggle_panic_bunker, + /datum/admins/proc/force_aspect +) +var/list/admin_verbs_ban = list( + /client/proc/unban_panel, + /client/proc/jobbans + ) +var/list/admin_verbs_sounds = list( + /client/proc/play_local_sound, + /client/proc/play_sound, + /client/proc/play_server_sound + ) + +var/list/admin_verbs_fun = list( + /client/proc/object_talk, + /datum/admins/proc/cmd_admin_dress, + /client/proc/cmd_admin_gib_self, + /client/proc/drop_bomb, + /client/proc/everyone_random, + /client/proc/cinematic, + /datum/admins/proc/toggle_aliens, + /datum/admins/proc/toggle_alien_eggs, + /client/proc/cmd_admin_add_freeform_ai_law, + /client/proc/cmd_admin_add_random_ai_law, + /client/proc/toggle_random_events, + /client/proc/editappear, + /client/proc/roll_dices, + /datum/admins/proc/call_supply_drop, + /datum/admins/proc/call_drop_pod, + /client/proc/create_dungeon, + /datum/admins/proc/ai_hologram_set + ) + +var/list/admin_verbs_spawn = list( + /datum/admins/proc/spawn_fruit, + /datum/admins/proc/spawn_custom_item, + /datum/admins/proc/check_custom_items, + /datum/admins/proc/spawn_plant, + /datum/admins/proc/spawn_atom, // allows us to spawn instances, + /client/proc/respawn_character, + /client/proc/virus2_editor, + /client/proc/spawn_chemdisp_cartridge + ) +var/list/admin_verbs_server = list( + /datum/admins/proc/capture_map_part, + /client/proc/Set_Holiday, + /datum/admins/proc/startnow, + /datum/admins/proc/restart, + /datum/admins/proc/delay, + /datum/admins/proc/toggleaban, + /client/proc/toggle_log_hrefs, + /datum/admins/proc/immreboot, + /client/proc/everyone_random, + /datum/admins/proc/toggleAI, + /client/proc/cmd_admin_delete, // delete an instance/object/mob/etc, + /client/proc/cmd_debug_del_all, + /datum/admins/proc/adrev, + /datum/admins/proc/adspawn, + /datum/admins/proc/adjump, + /datum/admins/proc/toggle_aliens, + /datum/admins/proc/toggle_alien_eggs, + /client/proc/toggle_random_events, + /client/proc/check_customitem_activity, + /client/proc/nanomapgen_DumpImage, + /datum/admin/proc/add_hellban, + /datum/admin/proc/remove_hellban + ) +var/list/admin_verbs_debug = list( + /client/proc/getruntimelog, // allows us to access runtime logs to somebody, + /client/proc/cmd_admin_list_open_jobs, + /client/proc/Debug2, + /client/proc/kill_air, + /client/proc/ZASSettings, + /client/proc/cmd_debug_make_powernets, + /client/proc/debug_controller, + /client/proc/debug_antagonist_template, + /client/proc/cmd_debug_mob_lists, + /client/proc/cmd_admin_delete, + /client/proc/cmd_debug_del_all, + /client/proc/cmd_debug_tog_aliens, + /client/proc/air_report, + /client/proc/reload_admins, + /client/proc/reload_mentors, + /client/proc/restart_controller, + /client/proc/print_random_map, + /client/proc/create_random_map, + /client/proc/apply_random_map, + /client/proc/overlay_random_map, + /client/proc/delete_random_map, + /datum/admins/proc/map_template_load, + /datum/admins/proc/map_template_load_new_z, + /datum/admins/proc/map_template_upload, + /client/proc/show_plant_genes, + /client/proc/enable_debug_verbs, + /client/proc/callproc, + /client/proc/callproc_target, + /client/proc/SDQL_query, + /client/proc/SDQL2_query, + /client/proc/Jump, + /client/proc/jumptomob, + /client/proc/jumptocoord, + /client/proc/dsay, + /datum/admins/proc/run_unit_test, + /turf/proc/view_chunk, + /turf/proc/update_chunk, + /datum/admins/proc/capture_map, + /datum/admins/proc/view_runtimes, + /client/proc/cmd_analyse_health_context, + /client/proc/cmd_analyse_health_panel, + /client/proc/visualpower, + /client/proc/visualpower_remove + ) + +var/list/admin_verbs_paranoid_debug = list( + /client/proc/callproc, + /client/proc/callproc_target, + /client/proc/debug_controller + ) + +var/list/admin_verbs_possess = list( + /proc/possess, + /proc/release + ) +var/list/admin_verbs_permissions = list( + /client/proc/edit_admin_permissions + ) +var/list/admin_verbs_rejuv = list( + /client/proc/respawn_character + ) + +//verbs which can be hidden - needs work +var/list/admin_verbs_hideable = list( + /client/proc/deadmin_self, +// /client/proc/deadchat, + /datum/admins/proc/show_traitor_panel, + /datum/admins/proc/toggleenter, + /datum/admins/proc/toggleguests, + /datum/admins/proc/announce, + /client/proc/colorooc, + /client/proc/admin_ghost, + /client/proc/toggle_view_range, + /datum/admins/proc/view_txt_log, + /datum/admins/proc/view_atk_log, + /client/proc/cmd_admin_subtle_message, + /client/proc/cmd_admin_check_contents, + /datum/admins/proc/access_news_network, + /client/proc/admin_call_shuttle, + /client/proc/admin_cancel_shuttle, + /client/proc/cmd_admin_direct_narrate, + /client/proc/cmd_admin_visible_narrate, + /client/proc/cmd_admin_audible_narrate, + /client/proc/cmd_admin_local_narrate, + /client/proc/cmd_admin_world_narrate, + /client/proc/play_local_sound, + /client/proc/play_sound, + /client/proc/play_server_sound, + /client/proc/object_talk, + /datum/admins/proc/cmd_admin_dress, + /client/proc/cmd_admin_gib_self, + /client/proc/drop_bomb, + /client/proc/cinematic, + /datum/admins/proc/toggle_aliens, + /datum/admins/proc/toggle_alien_eggs, + /client/proc/cmd_admin_add_freeform_ai_law, + /client/proc/cmd_admin_add_random_ai_law, + /client/proc/cmd_admin_create_centcom_report, + /client/proc/toggle_random_events, + /client/proc/cmd_admin_add_random_ai_law, + /client/proc/Set_Holiday, + /datum/admins/proc/startnow, + /datum/admins/proc/restart, + /datum/admins/proc/delay, + /datum/admins/proc/toggleaban, + /client/proc/toggle_log_hrefs, + /datum/admins/proc/immreboot, + /client/proc/everyone_random, + /datum/admins/proc/toggleAI, + /datum/admins/proc/adrev, + /datum/admins/proc/adspawn, + /datum/admins/proc/adjump, + /client/proc/restart_controller, + /client/proc/cmd_admin_list_open_jobs, + /client/proc/callproc, + /client/proc/callproc_target, + /client/proc/Debug2, + /client/proc/reload_admins, + /client/proc/kill_air, + /client/proc/cmd_debug_make_powernets, + /client/proc/debug_controller, + /client/proc/startSinglo, + /client/proc/cmd_debug_mob_lists, + /client/proc/cmd_debug_del_all, + /client/proc/cmd_debug_tog_aliens, + /client/proc/air_report, + /client/proc/enable_debug_verbs, + /client/proc/roll_dices, + /proc/possess, + /proc/release + ) +var/list/admin_verbs_mod = list( + /client/proc/cmd_admin_pm_context, // right-click adminPM interface, + /client/proc/cmd_admin_pm_panel, // admin-pm list, + /client/proc/debug_variables, // allows us to -see- the variables of any instance in the game., + /client/proc/debug_global_variables,// as above but for global variables, + /datum/admins/proc/PlayerNotes, + /client/proc/admin_ghost, // allows us to ghost/reenter body at will, + /client/proc/cmd_mod_say, + /datum/admins/proc/show_player_info, + /client/proc/player_panel_new, + /client/proc/dsay, + /datum/admins/proc/show_player_panel, + /client/proc/check_antagonists, + /client/proc/cmd_admin_subtle_message, // send an message to somebody as a 'voice in their head', + /datum/admins/proc/sendFax + +) + +var/list/admin_verbs_mentor = list( + /client/proc/cmd_admin_pm_context, + /client/proc/cmd_admin_pm_panel, + /datum/admins/proc/PlayerNotes, + /client/proc/admin_ghost, + /client/proc/cmd_mod_say, + /datum/admins/proc/show_player_info, +// /client/proc/dsay, + /client/proc/cmd_admin_subtle_message +) + +/client/proc/add_admin_verbs() + if(holder) + verbs += admin_verbs_default + if(holder.rights & R_BUILDMODE) verbs += /client/proc/togglebuildmodeself + if(holder.rights & R_ADMIN) verbs += admin_verbs_admin + if(holder.rights & R_BAN) verbs += admin_verbs_ban + if(holder.rights & R_FUN) verbs += admin_verbs_fun + if(holder.rights & R_SERVER) verbs += admin_verbs_server + if(holder.rights & R_DEBUG) + verbs += admin_verbs_debug + if(config.debugparanoid && !(holder.rights & R_ADMIN)) + verbs.Remove(admin_verbs_paranoid_debug) //Right now it's just callproc but we can easily add others later on. + if(holder.rights & R_POSSESS) verbs += admin_verbs_possess + if(holder.rights & R_PERMISSIONS) verbs += admin_verbs_permissions + if(holder.rights & R_STEALTH) verbs += /client/proc/stealth + if(holder.rights & R_REJUVINATE) verbs += admin_verbs_rejuv + if(holder.rights & R_SOUNDS) verbs += admin_verbs_sounds + if(holder.rights & R_SPAWN) verbs += admin_verbs_spawn + if(holder.rights & R_MOD) verbs += admin_verbs_mod + if(holder.rights & R_MENTOR) verbs += admin_verbs_mentor + +/client/proc/remove_admin_verbs() + verbs.Remove( + admin_verbs_default, + /client/proc/togglebuildmodeself, + admin_verbs_admin, + admin_verbs_ban, + admin_verbs_fun, + admin_verbs_server, + admin_verbs_debug, + admin_verbs_possess, + admin_verbs_permissions, + /client/proc/stealth, + admin_verbs_rejuv, + admin_verbs_sounds, + admin_verbs_spawn, + debug_verbs + ) + +/client/proc/hide_most_verbs()//Allows you to keep some functionality while hiding some verbs + set name = "Adminverbs - Hide Most" + set category = "Admin" + + verbs.Remove(/client/proc/hide_most_verbs, admin_verbs_hideable) + verbs += /client/proc/show_verbs + + to_chat(src, "Most of your adminverbs have been hidden.") + feedback_add_details("admin_verb","HMV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + +/client/proc/hide_verbs() + set name = "Adminverbs - Hide All" + set category = "Admin" + + remove_admin_verbs() + verbs += /client/proc/show_verbs + + to_chat(src, "Almost all of your adminverbs have been hidden.") + feedback_add_details("admin_verb","TAVVH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + +/client/proc/show_verbs() + set name = "Adminverbs - Show" + set category = "Admin" + + verbs -= /client/proc/show_verbs + add_admin_verbs() + + to_chat(src, "All of your adminverbs are now visible.") + feedback_add_details("admin_verb","TAVVS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +//A verb so that admins can toggle right click if they need to use debug stuff. - Matt +/client/proc/toggle_right_click() + set name = "Toggle Right Click" + set category = "Admin" + + if(!show_popup_menus) + show_popup_menus = TRUE + to_chat(src, "Right click enabled.") + else + show_popup_menus = FALSE + to_chat(src, "Right click disabled.") + + +/client/proc/admin_ghost() + set category = "Admin" + set name = "Aghost" + if(!holder) return + if(isghost(mob)) + //re-enter + var/mob/observer/ghost/ghost = mob + if(!is_mentor(usr.client)) + ghost.can_reenter_corpse = 1 + if(ghost.can_reenter_corpse) + ghost.reenter_corpse() + else + to_chat(ghost, "Error: Aghost: Can't reenter corpse, mentors that use adminHUD while aghosting are not permitted to enter their corpse again") + return + + feedback_add_details("admin_verb","P") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + else if(istype(mob,/mob/new_player)) + to_chat(src, "Error: Aghost: Can't admin-ghost whilst in the lobby. Join or Observe first.") + else + //ghostize + var/mob/body = mob + var/mob/observer/ghost/ghost = body.ghostize(1) + ghost.admin_ghosted = 1 + if(body) + body.teleop = ghost + if(!body.key) + body.key = "@[key]" //Haaaaaaaack. But the people have spoken. If it breaks; blame adminbus + feedback_add_details("admin_verb","O") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/client/proc/invisimin() + set name = "Invisimin" + set category = "Admin" + set desc = "Toggles ghost-like invisibility (Don't abuse this)" + if(holder && mob) + if(mob.invisibility == INVISIBILITY_OBSERVER) + mob.set_invisibility(initial(mob.invisibility)) + to_chat(mob, "Invisimin off. Invisibility reset.") + mob.alpha = max(mob.alpha + 100, 255) + else + mob.set_invisibility(INVISIBILITY_OBSERVER) + to_chat(mob, "Invisimin on. You are now as invisible as a ghost.") + mob.alpha = max(mob.alpha - 100, 0) + + +/client/proc/player_panel() + set name = "Player Panel" + set category = "Admin" + if(holder) + holder.player_panel_old() + feedback_add_details("admin_verb","PP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + +/client/proc/player_panel_new() + set name = "Player Panel New" + set category = "Admin" + if(holder) + holder.player_panel_new() + feedback_add_details("admin_verb","PPN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + +/client/proc/check_antagonists() + set name = "Check Antagonists" + set category = "Admin" + if(holder) + holder.check_antagonists() + log_admin("[key_name(usr)] checked antagonists.") //for tsar~ + feedback_add_details("admin_verb","CHA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + +/client/proc/jobbans() + set name = "Display Job bans" + set category = "Admin" + if(holder) + if(config.ban_legacy_system) + holder.Jobbans() + else + holder.DB_ban_panel() + feedback_add_details("admin_verb","VJB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + +/client/proc/unban_panel() + set name = "Unban Panel" + set category = "Admin" + if(holder) + if(config.ban_legacy_system) + holder.unbanpanel() + else + holder.DB_ban_panel() + feedback_add_details("admin_verb","UBP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + +/client/proc/game_panel() + set name = "Game Panel" + set category = "Admin" + if(holder) + holder.Game() + feedback_add_details("admin_verb","GP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + +/client/proc/secrets() + set name = "Secrets" + set category = "Admin" + if (holder) + holder.Secrets() + feedback_add_details("admin_verb","S") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + +/client/proc/colorooc() + set category = "Fun" + set name = "OOC Text Color" + if(!holder) return + var/response = alert(src, "Please choose a distinct color that is easy to read and doesn't mix with all the other chat and radio frequency colors.", "Change own OOC color", "Pick new color", "Reset to default", "Cancel") + if(response == "Pick new color") + prefs.ooccolor = input(src, "Please select your OOC colour.", "OOC colour") as color + else if(response == "Reset to default") + prefs.ooccolor = initial(prefs.ooccolor) + prefs.save_preferences() + + feedback_add_details("admin_verb","OC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + +#define MAX_WARNS 3 +#define AUTOBANTIME 10 + +/client/proc/warn(warned_ckey) + if(!check_rights(R_ADMIN)) return + + if(!warned_ckey || !istext(warned_ckey)) return + if(warned_ckey in admin_datums) + to_chat(usr, "Error: warn(): You can't warn admins.") + return + + var/datum/preferences/D + var/client/C = GLOB.ckey_directory[warned_ckey] + if(C) D = C.prefs + else D = preferences_datums[warned_ckey] + + if(!D) + to_chat(src, "Error: warn(): No such ckey found.") + return + + if(++D.warns >= MAX_WARNS) //uh ohhhh...you'reee iiiiin trouuuubble O:) + ban_unban_log_save("[ckey] warned [warned_ckey], resulting in a [AUTOBANTIME] minute autoban.") + if(C) + message_admins("[key_name_admin(src)] has warned [key_name_admin(C)] resulting in a [AUTOBANTIME] minute ban.") + to_chat(C, "You have been autobanned due to a warning by [ckey].
            This is a temporary ban, it will be removed in [AUTOBANTIME] minutes.
            ") + qdel(C) + else + message_admins("[key_name_admin(src)] has warned [warned_ckey] resulting in a [AUTOBANTIME] minute ban.") + AddBan(warned_ckey, D.last_id, "Autobanning due to too many formal warnings", ckey, 1, AUTOBANTIME) + feedback_inc("ban_warn",1) + else + if(C) + to_chat(C, "You have been formally warned by an administrator.
            Further warnings will result in an autoban.
            ") + message_admins("[key_name_admin(src)] has warned [key_name_admin(C)]. They have [MAX_WARNS-D.warns] strikes remaining.") + else + message_admins("[key_name_admin(src)] has warned [warned_ckey] (DC). They have [MAX_WARNS-D.warns] strikes remaining.") + + feedback_add_details("admin_verb","WARN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +#undef MAX_WARNS +#undef AUTOBANTIME + +/client/proc/drop_bomb() // Some admin dickery that can probably be done better -- TLE + set category = "Special Verbs" + set name = "Drop Bomb" + set desc = "Cause an explosion of varying strength at your location." + + var/turf/epicenter = mob.loc + var/list/choices = list("Small Bomb", "Medium Bomb", "Big Bomb", "Custom Bomb") + var/choice = input("What size explosion would you like to produce?") in choices + switch(choice) + if(null) + return 0 + if("Small Bomb") + explosion(epicenter, 1, 2, 3, 3) + if("Medium Bomb") + explosion(epicenter, 2, 3, 4, 4) + if("Big Bomb") + explosion(epicenter, 3, 5, 7, 5) + if("Custom Bomb") + var/devastation_range = input("Devastation range (in tiles):") as num + var/heavy_impact_range = input("Heavy impact range (in tiles):") as num + var/light_impact_range = input("Light impact range (in tiles):") as num + var/flash_range = input("Flash range (in tiles):") as num + explosion(epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range) + log_and_message_admins("created an admin explosion at [epicenter.loc].") + feedback_add_details("admin_verb","DB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/give_disease2(mob/T as mob in SSmobs.mob_list) // -- Giacom + set category = "Fun" + set name = "Give Disease" + set desc = "Gives a Disease to a mob." + + var/datum/disease2/disease/D = new /datum/disease2/disease() + + var/severity = 1 + var/greater = input("Is this a lesser, greater, or badmin disease?", "Give Disease") in list("Lesser", "Greater", "Badmin") + switch(greater) + if ("Lesser") severity = 1 + if ("Greater") severity = 2 + if ("Badmin") severity = 99 + + D.makerandom(severity) + D.infectionchance = input("How virulent is this disease? (1-100)", "Give Disease", D.infectionchance) as num + + if(istype(T,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = T + if (H.species) + D.affected_species = list(H.species.get_bodytype(H)) + if(H.species.primitive_form) + D.affected_species |= H.species.primitive_form + if(H.species.greater_form) + D.affected_species |= H.species.greater_form + infect_virus2(T,D,1) + + feedback_add_details("admin_verb","GD2") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + log_and_message_admins("gave [key_name(T)] a [greater] disease2 with infection chance [D.infectionchance].") + +/client/proc/togglebuildmodeself() + set name = "Toggle Build Mode Self" + set category = "Special Verbs" + + if(!check_rights(R_ADMIN)) + return + + var/datum/click_handler/handler = mob.GetClickHandler() + if(handler.type == /datum/click_handler/build_mode) + usr.PopClickHandler() + else + usr.PushClickHandler(/datum/click_handler/build_mode) + feedback_add_details("admin_verb","TBMS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/object_talk(var/msg as text) // -- TLE + set category = "Special Verbs" + set name = "oSay" + set desc = "Display a message to everyone who can hear the target" + if(mob.control_object) + if(!msg) + return + for (var/mob/V in hearers(mob.control_object)) + V.show_message("[mob.control_object.name] says: \"" + msg + "\"", 2) + feedback_add_details("admin_verb","OT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/kill_air() // -- TLE + set category = "Debug" + set name = "Kill Air" + set desc = "Toggle Air Processing" + if(air_processing_killed) + air_processing_killed = 0 + to_chat(usr, "Enabled air processing.") + else + air_processing_killed = 1 + to_chat(usr, "Disabled air processing.") + feedback_add_details("admin_verb","KA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + log_and_message_admins("used 'kill air'.") + +/client/proc/readmin_self() + set name = "Re-Admin self" + set category = "Admin" + + if(deadmin_holder) + deadmin_holder.reassociate() + log_admin("[src] re-admined themself.") + message_admins("[src] re-admined themself.", 1) + to_chat(src, "You now have the keys to control the planet, or atleast a small space station") + verbs -= /client/proc/readmin_self + +/client/proc/deadmin_self() + set name = "De-admin self" + set category = "Admin" + + if(holder) + if(alert("Confirm self-deadmin for the round? You can re-admin yourself at any time.",,"Yes","No") == "Yes") + log_admin("[src] deadmined themself.") + message_admins("[src] deadmined themself.", 1) + deadmin() + to_chat(src, "You are now a normal player.") + verbs |= /client/proc/readmin_self + feedback_add_details("admin_verb","DAS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/toggle_log_hrefs() + set name = "Toggle href logging" + set category = "Server" + if(!holder) return + if(config) + if(config.log_hrefs) + config.log_hrefs = 0 + to_chat(src, "Stopped logging hrefs") + else + config.log_hrefs = 1 + to_chat(src, "Started logging hrefs") + +/client/proc/check_ai_laws() + set name = "Check AI Laws" + set category = "Admin" + if(holder) + src.holder.output_ai_laws() + +/client/proc/rename_silicon() + set name = "Rename Silicon" + set category = "Admin" + + if(!check_rights(R_ADMIN)) return + + var/mob/living/silicon/S = input("Select silicon.", "Rename Silicon.") as null|anything in GLOB.silicon_mob_list + if(!S) return + + var/new_name = sanitizeSafe(input(src, "Enter new name. Leave blank or as is to cancel.", "[S.real_name] - Enter new silicon name", S.real_name)) + if(new_name && new_name != S.real_name) + log_and_message_admins("has renamed the silicon '[S.real_name]' to '[new_name]'") + S.fully_replace_character_name(new_name) + feedback_add_details("admin_verb","RAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/manage_silicon_laws() + set name = "Manage Silicon Laws" + set category = "Admin" + + if(!check_rights(R_ADMIN)) return + + var/mob/living/silicon/S = input("Select silicon.", "Manage Silicon Laws") as null|anything in GLOB.silicon_mob_list + if(!S) return + + var/datum/nano_module/law_manager/L = new(S) + L.ui_interact(usr, state = GLOB.admin_state) + log_and_message_admins("has opened [S]'s law manager.") + feedback_add_details("admin_verb","MSL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/change_human_appearance_admin() + set name = "Change Mob Appearance - Admin" + set desc = "Allows you to change the mob appearance" + set category = "Admin" + + if(!check_rights(R_FUN)) return + + var/mob/living/carbon/human/H = input("Select mob.", "Change Mob Appearance - Admin") as null|anything in GLOB.human_mob_list + if(!H) return + + log_and_message_admins("is altering the appearance of [H].") + H.change_appearance(APPEARANCE_ALL, usr, usr, check_species_whitelist = 0, state = GLOB.admin_state) + feedback_add_details("admin_verb","CHAA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/change_human_appearance_self() + set name = "Change Mob Appearance - Self" + set desc = "Allows the mob to change its appearance" + set category = "Admin" + + if(!check_rights(R_FUN)) return + + var/mob/living/carbon/human/H = input("Select mob.", "Change Mob Appearance - Self") as null|anything in GLOB.human_mob_list + if(!H) return + + if(!H.client) + to_chat(usr, "Only mobs with clients can alter their own appearance.") + return + + switch(alert("Do you wish for [H] to be allowed to select non-whitelisted races?","Alter Mob Appearance","Yes","No","Cancel")) + if("Yes") + log_and_message_admins("has allowed [H] to change \his appearance, including races that requires whitelisting") + H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 0) + if("No") + log_and_message_admins("has allowed [H] to change \his appearance, excluding races that requires whitelisting.") + H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 1) + feedback_add_details("admin_verb","CMAS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/change_security_level() + set name = "Set security level" + set desc = "Sets the security level" + set category = "Admin" + + if(!check_rights(R_ADMIN)) return + + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + + var/decl/security_level/new_security_level = input(usr, "It's currently [security_state.current_security_level.name].", "Select Security Level") as null|anything in (security_state.all_security_levels - security_state.current_security_level) + if(!new_security_level) + return + + if(alert("Switch from [security_state.current_security_level.name] to [new_security_level.name]?","Change security level?","Yes","No") == "Yes") + security_state.set_security_level(new_security_level, TRUE) + + +//---- bs12 verbs ---- + +/client/proc/mod_panel() + set name = "Moderator Panel" + set category = "Admin" +/* if(holder) + holder.mod_panel()*/ +// feedback_add_details("admin_verb","MP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + +/client/proc/editappear() + set name = "Edit Appearance" + set category = "Fun" + + if(!check_rights(R_FUN)) return + + var/mob/living/carbon/human/M = input("Select mob.", "Edit Appearance") as null|anything in GLOB.human_mob_list + + if(!istype(M, /mob/living/carbon/human)) + to_chat(usr, "You can only do this to humans!") + return + switch(alert("Are you sure you wish to edit this mob's appearance? Skrell, Unathi, Vox and Tajaran can result in unintended consequences.",,"Yes","No")) + if("No") + return + var/new_facial = input("Please select facial hair color.", "Character Generation") as color + if(new_facial) + M.r_facial = hex2num(copytext(new_facial, 2, 4)) + M.g_facial = hex2num(copytext(new_facial, 4, 6)) + M.b_facial = hex2num(copytext(new_facial, 6, 8)) + + var/new_hair = input("Please select hair color.", "Character Generation") as color + if(new_facial) + M.r_hair = hex2num(copytext(new_hair, 2, 4)) + M.g_hair = hex2num(copytext(new_hair, 4, 6)) + M.b_hair = hex2num(copytext(new_hair, 6, 8)) + + var/new_eyes = input("Please select eye color.", "Character Generation") as color + if(new_eyes) + M.r_eyes = hex2num(copytext(new_eyes, 2, 4)) + M.g_eyes = hex2num(copytext(new_eyes, 4, 6)) + M.b_eyes = hex2num(copytext(new_eyes, 6, 8)) + M.update_eyes() + + var/new_skin = input("Please select body color. This is for Tajaran, Unathi, and Skrell only!", "Character Generation") as color + if(new_skin) + M.r_skin = hex2num(copytext(new_skin, 2, 4)) + M.g_skin = hex2num(copytext(new_skin, 4, 6)) + M.b_skin = hex2num(copytext(new_skin, 6, 8)) + + var/new_tone = input("Please select skin tone level: 1-220 (1=albino, 35=caucasian, 150=black, 220='very' black)", "Character Generation") as text + + if (new_tone) + M.s_tone = max(min(round(text2num(new_tone)), 220), 1) + M.s_tone = -M.s_tone + 35 + + // hair + var/new_hstyle = input(usr, "Select a hair style", "Grooming") as null|anything in GLOB.hair_styles_list + if(new_hstyle) + M.h_style = new_hstyle + + // facial hair + var/new_fstyle = input(usr, "Select a facial hair style", "Grooming") as null|anything in GLOB.facial_hair_styles_list + if(new_fstyle) + M.f_style = new_fstyle + + var/new_gender = alert(usr, "Please select gender.", "Character Generation", "Male", "Female", "Neuter") + if (new_gender) + if(new_gender == "Male") + M.gender = MALE + else if (new_gender == "Female") + M.gender = FEMALE + else + M.gender = NEUTER + + M.update_hair() + M.update_body() + M.check_dna(M) + +/client/proc/playernotes() + set name = "Show Player Info" + set category = "Admin" + if(holder) + holder.PlayerNotes() + return + +/client/proc/free_slot() + set name = "Free Job Slot" + set category = "Admin" + if(holder) + var/list/jobs = list() + for (var/datum/job/J in job_master.occupations) + if (J.current_positions >= J.total_positions && J.total_positions != -1) + jobs += J.title + if (!jobs.len) + to_chat(usr, "There are no fully staffed jobs.") + return + var/job = input("Please select job slot to free", "Free job slot") as null|anything in jobs + if (job) + job_master.FreeRole(job) + message_admins("A job slot for [job] has been opened by [key_name_admin(usr)]") + return + +/client/proc/toggleghostwriters() + set name = "Toggle ghost writers" + set category = "Server" + if(!holder) return + if(config) + if(config.cult_ghostwriter) + config.cult_ghostwriter = 0 + to_chat(src, "Disallowed ghost writers.") + message_admins("Admin [key_name_admin(usr)] has disabled ghost writers.", 1) + else + config.cult_ghostwriter = 1 + to_chat(src, "Enabled ghost writers.") + message_admins("Admin [key_name_admin(usr)] has enabled ghost writers.", 1) + +/client/proc/toggledrones() + set name = "Toggle maintenance drones" + set category = "Server" + if(!holder) return + if(config) + if(config.allow_drone_spawn) + config.allow_drone_spawn = 0 + to_chat(src, "Disallowed maint drones.") + message_admins("Admin [key_name_admin(usr)] has disabled maint drones.", 1) + else + config.allow_drone_spawn = 1 + to_chat(src, "Enabled maint drones.") + message_admins("Admin [key_name_admin(usr)] has enabled maint drones.", 1) + +/client/proc/man_up(mob/T as mob in SSmobs.mob_list) + set category = "Fun" + set name = "Man Up" + set desc = "Tells mob to man up and deal with it." + + to_chat(T, "Man up and deal with it.") + to_chat(T, "Move on.") + + log_and_message_admins("told [key_name(T)] to man up and deal with it.") + +/client/proc/global_man_up() + set category = "Fun" + set name = "Man Up Global" + set desc = "Tells everyone to man up and deal with it." + + for (var/mob/T as mob in SSmobs.mob_list) + to_chat(T, "
            Man up.
            Deal with it.

            Move on.

            ") + sound_to(T, 'sound/voice/ManUp1.ogg') + + log_and_message_admins("told everyone to man up and deal with it.") + +/client/proc/give_spell(mob/T as mob in SSmobs.mob_list) // -- Urist + set category = "Fun" + set name = "Give Spell" + set desc = "Gives a spell to a mob." + var/spell/S = input("Choose the spell to give to that guy", "ABRAKADABRA") as null|anything in spells + if(!S) return + T.add_spell(new S) + feedback_add_details("admin_verb","GS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + log_and_message_admins("gave [key_name(T)] the spell [S].") diff --git a/code/modules/admin/banjob.dm b/code/modules/admin/banjob.dm new file mode 100644 index 00000000..9316bc6d --- /dev/null +++ b/code/modules/admin/banjob.dm @@ -0,0 +1,114 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +var/jobban_runonce // Updates legacy bans with new info +var/jobban_keylist[0] //to store the keys & ranks + +/proc/jobban_fullban(mob/M, rank, reason) + if (!M || !M.key) return + jobban_keylist.Add(text("[M.ckey] - [rank] ## [reason]")) + jobban_savebanfile() + +/proc/jobban_client_fullban(ckey, rank) + if (!ckey || !rank) return + jobban_keylist.Add(text("[ckey] - [rank]")) + jobban_savebanfile() + +//returns a reason if M is banned from rank, returns 0 otherwise +/proc/jobban_isbanned(mob/M, rank) + if(M && rank) + /* + if(_jobban_isbanned(M, rank)) return "Reason Unspecified" //for old jobban + */ + + if (guest_jobbans(rank)) + if(config.guest_jobban && IsGuestKey(M.key)) + return "Guest Job-ban" + if(config.usewhitelist && !check_whitelist(M)) + return "Whitelisted Job" + + for (var/s in jobban_keylist) + if( findtext(s,"[M.ckey] - [rank]") == 1 ) + var/startpos = findtext(s, "## ")+3 + if(startpos && startpos> jobban_keylist + log_admin("Loading jobban_rank") + S["runonce"] >> jobban_runonce + + if (!length(jobban_keylist)) + jobban_keylist=list() + log_admin("jobban_keylist was empty") + else + if(!establish_db_connection()) + error("Database connection failed. Reverting to the legacy ban system.") + log_misc("Database connection failed. Reverting to the legacy ban system.") + config.ban_legacy_system = 1 + jobban_loadbanfile() + return + + //Job permabans + var/DBQuery/query = dbcon.NewQuery("SELECT ckey, job FROM erro_ban WHERE bantype = 'JOB_PERMABAN' AND isnull(unbanned)") + query.Execute() + + while(query.NextRow()) + var/ckey = query.item[1] + var/job = query.item[2] + + jobban_keylist.Add("[ckey] - [job]") + + //Job tempbans + var/DBQuery/query1 = dbcon.NewQuery("SELECT ckey, job FROM erro_ban WHERE bantype = 'JOB_TEMPBAN' AND isnull(unbanned) AND expiration_time > Now()") + query1.Execute() + + while(query1.NextRow()) + var/ckey = query1.item[1] + var/job = query1.item[2] + + jobban_keylist.Add("[ckey] - [job]") + +/proc/jobban_savebanfile() + var/savefile/S=new("data/job_full.ban") + S["keys[0]"] << jobban_keylist + +/proc/jobban_unban(mob/M, rank) + jobban_remove("[M.ckey] - [rank]") + jobban_savebanfile() + + +/proc/ban_unban_log_save(var/formatted_log) + text2file(formatted_log,"data/ban_unban_log.txt") + + +/proc/jobban_remove(X) + for (var/i = 1; i <= length(jobban_keylist); i++) + if( findtext(jobban_keylist[i], "[X]") ) + jobban_keylist.Remove(jobban_keylist[i]) + jobban_savebanfile() + return 1 + return 0 diff --git a/code/modules/admin/buildmode/advance.dm b/code/modules/admin/buildmode/advance.dm new file mode 100644 index 00000000..961ea8dc --- /dev/null +++ b/code/modules/admin/buildmode/advance.dm @@ -0,0 +1,46 @@ +/datum/build_mode/advanced + name = "Advanced" + icon_state = "buildmode2" + var/build_type + +/datum/build_mode/advanced/Help() + to_chat(user, "***********************************************************") + to_chat(user, "Left Click = Create objects") + to_chat(user, "Right Click = Delete objects") + to_chat(user, "Left Click + Ctrl = Capture object type") + to_chat(user, "Middle Click = Capture object type") + to_chat(user, "Right Click on Build Mode Button = Select object type") + to_chat(user, "") + to_chat(user, "Use the directional button in the upper left corner to") + to_chat(user, "change the direction of built objects.") + to_chat(user, "***********************************************************") + +/datum/build_mode/advanced/Configurate() + SetBuildType(select_subpath(build_type || /obj/structure/closet)) + +/datum/build_mode/advanced/OnClick(var/atom/A, var/list/parameters) + if(parameters["left"] && !parameters["ctrl"]) + if(ispath(build_type,/turf)) + var/turf/T = get_turf(A) + T.ChangeTurf(build_type) + else if(ispath(build_type)) + var/atom/new_atom = new build_type (get_turf(A)) + new_atom.set_dir(host.dir) + Log("Created - [log_info_line(new_atom)]") + else + to_chat(user, "Select a type to construct.") + else if(parameters["right"]) + Log("Deleted - [log_info_line(A)]") + qdel(A) + else if((parameters["left"] && parameters["ctrl"]) || parameters["middle"]) + SetBuildType(A.type) + +/datum/build_mode/advanced/proc/SetBuildType(var/atom_type) + if(!atom_type || atom_type == build_type) + return + + if(ispath(atom_type, /atom)) + build_type = atom_type + to_chat(user, "Will now construct instances of the type [atom_type].") + else + to_chat(user, "Cannot construct instances of type [atom_type].") diff --git a/code/modules/admin/buildmode/basic.dm b/code/modules/admin/buildmode/basic.dm new file mode 100644 index 00000000..c4a26e6a --- /dev/null +++ b/code/modules/admin/buildmode/basic.dm @@ -0,0 +1,70 @@ +/datum/build_mode/basic + the_default = TRUE + name = "Basic" + icon_state = "buildmode1" + +/datum/build_mode/basic/Help() + to_chat(user, "***********************************************************") + to_chat(user, "Left Click = Construct / Upgrade") + to_chat(user, "Right Click = Deconstruct / Delete / Downgrade") + to_chat(user, "Left Click + Ctrl = R-Window") + to_chat(user, "Left Click + Alt = Airlock") + to_chat(user, "") + to_chat(user, "Use the directional button in the upper left corner to") + to_chat(user, "change the direction of built objects.") + to_chat(user, "***********************************************************") + +/datum/build_mode/basic/OnClick(var/atom/object, var/list/pa) + if(istype(object,/turf) && pa["left"] && !pa["alt"] && !pa["ctrl"] ) + if(istype(object,/turf/space)) + var/turf/T = object + Log("Upgraded - [log_info_line(object)]") + T.ChangeTurf(/turf/simulated/floor) + return + else if(istype(object,/turf/simulated/floor)) + var/turf/T = object + Log("Upgraded - [log_info_line(object)]") + T.ChangeTurf(/turf/simulated/wall) + return + else if(istype(object,/turf/simulated/wall)) + var/turf/T = object + Log("Upgraded - [log_info_line(object)]") + T.ChangeTurf(/turf/simulated/wall/r_wall) + return + else if(pa["right"]) + if(istype(object,/turf/simulated/wall)) + var/turf/T = object + Log("Downgraded - [log_info_line(object)]") + T.ChangeTurf(/turf/simulated/floor) + return + else if(istype(object,/turf/simulated/floor)) + var/turf/T = object + Log("Downgraded - [log_info_line(object)]") + T.ChangeTurf(/turf/space) + return + else if(istype(object,/turf/simulated/wall/r_wall)) + var/turf/T = object + Log("Downgraded - [log_info_line(object)]") + T.ChangeTurf(/turf/simulated/wall) + return + else if(istype(object,/obj)) + Log("Deleted - [log_info_line(object)]") + qdel(object) + return + else if(istype(object,/turf) && pa["alt"] && pa["left"]) + var/airlock = new/obj/machinery/door/airlock(get_turf(object)) + Log("Created - [log_info_line(airlock)]") + else if(istype(object,/turf) && pa["ctrl"] && pa["left"]) + var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object)) + Log("Created - [log_info_line(object)]") + switch(host.dir) + if(NORTH) + WIN.set_dir(NORTH) + if(SOUTH) + WIN.set_dir(SOUTH) + if(EAST) + WIN.set_dir(EAST) + if(WEST) + WIN.set_dir(WEST) + if(NORTHWEST) + WIN.set_dir(NORTHWEST) diff --git a/code/modules/admin/buildmode/build_mode.dm b/code/modules/admin/buildmode/build_mode.dm new file mode 100644 index 00000000..fca84332 --- /dev/null +++ b/code/modules/admin/buildmode/build_mode.dm @@ -0,0 +1,51 @@ +/datum/build_mode + var/the_default = FALSE + var/name + var/icon_state + var/datum/click_handler/build_mode/host + var/mob/user + +/datum/build_mode/New(var/host) + ..() + src.host = host + user = src.host.user + +/datum/build_mode/Destroy() + host = null + . = ..() + +/datum/build_mode/proc/OnClick(var/atom/A, var/list/parameters) + return + +/datum/build_mode/proc/Configurate() + return + +/datum/build_mode/proc/Help() + return + +/datum/build_mode/proc/Log(message) + log_admin("BUILD MODE - [name] - [key_name(usr)] - [message]") + +/datum/build_mode/proc/Warn(message) + to_chat(user, "BUILD MODE - [name] - [message])") + +/datum/build_mode/proc/select_subpath(given_path) + var/desired_path = input("Enter full or partial typepath.","Typepath","[given_path]") as text|null + if(!desired_path) + return + + var/list/types = typesof(/atom) + var/list/matches = list() + + for(var/path in types) + if(findtext("[path]", desired_path)) + matches += path + + if(!matches.len) + alert("No results found. Sorry.") + return + + if(matches.len==1) + return matches[1] + else + return (input("Select an atom type", "Spawn Atom", matches[1]) as null|anything in matches) diff --git a/code/modules/admin/buildmode/buttons.dm b/code/modules/admin/buildmode/buttons.dm new file mode 100644 index 00000000..f3dd61f9 --- /dev/null +++ b/code/modules/admin/buildmode/buttons.dm @@ -0,0 +1,73 @@ +/obj/effect/bmode + density = 1 + anchored = 1 + plane = HUD_PLANE + layer = HUD_BASE_LAYER + icon = 'icons/misc/buildmode.dmi' + var/datum/click_handler/build_mode/host + +/obj/effect/bmode/New(var/host) + ..() + src.host = host + +/obj/effect/bmode/Destroy() + host = null + . = ..() + +/obj/effect/bmode/proc/OnClick(var/list/params) + return + +/obj/effect/bmode/dir + icon_state = "build" + screen_loc = "NORTH,WEST" + +/obj/effect/bmode/dir/New() + ..() + set_dir(host.dir) + +/obj/effect/bmode/dir/OnClick(var/list/parameters) + switch(dir) + if(SOUTH) + set_dir(WEST) + if(WEST) + set_dir(NORTH) + if(NORTH) + set_dir(EAST) + if(EAST) + set_dir(NORTHWEST) + else + set_dir(SOUTH) + host.dir = dir + +/obj/effect/bmode/help + icon_state = "buildhelp" + screen_loc = "NORTH,WEST+1" + +/obj/effect/bmode/help/OnClick() + host.current_build_mode.Help() + +/obj/effect/bmode/mode + screen_loc = "NORTH,WEST+2" + +/obj/effect/bmode/mode/New() + ..() + icon_state = host.current_build_mode.icon_state + +/obj/effect/bmode/mode/OnClick(var/list/parameters) + if(parameters["left"]) + var/datum/build_mode/build_mode = input("Select build mode", "Select build mode", host.current_build_mode) as null|anything in host.build_modes + if(build_mode && host && (build_mode in host.build_modes)) + host.current_build_mode = build_mode + icon_state = build_mode.icon_state + to_chat(usr, "Build mode '[host.current_build_mode]' selected.") + else if(parameters["right"]) + host.current_build_mode.Configurate() + +/obj/effect/bmode/quit + icon_state = "buildquit" + screen_loc = "NORTH,WEST+3" + +/obj/effect/bmode/quit/OnClick() + var/datum/click_handler/handler = usr.GetClickHandler() + if(handler.type == /datum/click_handler/build_mode) + usr.PopClickHandler() diff --git a/code/modules/admin/buildmode/click_handler.dm b/code/modules/admin/buildmode/click_handler.dm new file mode 100644 index 00000000..cac0bc47 --- /dev/null +++ b/code/modules/admin/buildmode/click_handler.dm @@ -0,0 +1,52 @@ +/datum/click_handler/build_mode + flags = CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT + var/dir + + var/list/build_modes + var/list/build_buttons + + var/datum/build_mode/current_build_mode + +/datum/click_handler/build_mode/New(var/mob/user) + ..() + + build_modes = list() + for(var/mode_type in subtypesof(/datum/build_mode)) + var/datum/build_mode/build_mode = new mode_type(src) + build_modes += build_mode + if(build_mode.the_default) + current_build_mode = build_mode + + build_buttons = list() + for(var/button_type in subtypesof(/obj/effect/bmode)) + var/obj/effect/bmode/build_button = new button_type(src) + build_buttons += build_button + +/datum/click_handler/build_mode/Destroy() + QDEL_NULL(current_build_mode) + + QDEL_NULL_LIST(build_modes) + QDEL_NULL_LIST(build_buttons) + + . = ..() + +/datum/click_handler/build_mode/Enter() + user.client.show_popup_menus = FALSE + for(var/build_button in build_buttons) + user.client.screen += build_button + +/datum/click_handler/build_mode/Exit() + user.my_client.show_popup_menus = TRUE + for(var/build_button in build_buttons) + user.my_client.screen -= build_button + +/datum/click_handler/build_mode/OnDblClick(var/atom/A, var/params) + OnClick(A, params) // We treat double-clicks as normal clicks + +/datum/click_handler/build_mode/OnClick(var/atom/A, var/params) + params = params2list(params) + if(A in build_buttons) + var/obj/effect/bmode/build_button = A + build_button.OnClick(params) + else + current_build_mode.OnClick(A, params) diff --git a/code/modules/admin/buildmode/edit.dm b/code/modules/admin/buildmode/edit.dm new file mode 100644 index 00000000..81e984fd --- /dev/null +++ b/code/modules/admin/buildmode/edit.dm @@ -0,0 +1,74 @@ +/datum/build_mode/edit + name = "Edit" + icon_state = "buildmode3" + var/var_to_edit = "name" + var/value_to_set = "derp" + +/datum/build_mode/edit/Destroy() + ClearValue() + . = ..() + +/datum/build_mode/edit/Help() + to_chat(user, "***********************************************************") + to_chat(user, "Right Click on Build Mode Button = Select var & value") + to_chat(user, "Left Click = Sets the var's value") + to_chat(user, "Right Click = Reset the var's value") + to_chat(user, "***********************************************************") + +/datum/build_mode/edit/Configurate() + var/var_name = input("Enter variable name:", "Name", var_to_edit) as text|null + if(!var_name) + return + + var/thetype = input("Select variable type:", "Type") as null|anything in list("text","number","mob-reference","obj-reference","turf-reference") + if(!thetype) return + + var/new_value + switch(thetype) + if("text") + new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as text|null + if("number") + new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as num|null + if("mob-reference") + new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as null|mob in SSmobs.mob_list + if("obj-reference") + new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as null|obj in world + if("turf-reference") + new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as null|turf in world + + if(var_name && new_value) + var_to_edit = var_name + SetValue(new_value) + +/datum/build_mode/edit/OnClick(var/atom/A, var/list/parameters) + if(!A.may_edit_var(usr, var_to_edit)) + return + + var/old_value = A.vars[var_to_edit] + var/new_value + if(parameters["left"]) + new_value = value_to_set + if(parameters["right"]) + new_value = initial(A.vars[var_to_edit]) + + if(old_value == new_value) + return + A.vars[var_to_edit] = new_value + to_chat(user, "Changed the value of [var_to_edit] from '[old_value]' to '[new_value]'.") + Log("[log_info_line(A)] - [var_to_edit] - [old_value] -> [new_value]") + +/datum/build_mode/edit/proc/SetValue(var/new_value) + if(value_to_set == new_value) + return + ClearValue() + value_to_set = new_value + GLOB.destroyed_event.register(value_to_set, src, /datum/build_mode/edit/proc/ClearValue) + +/datum/build_mode/edit/proc/ClearValue(var/feedback) + if(!istype(value_to_set, /datum)) + return + + GLOB.destroyed_event.unregister(value_to_set, src, /datum/build_mode/edit/proc/ClearValue) + value_to_set = initial(value_to_set) + if(feedback) + Warn("The selected reference value was deleted. Default value restored.") diff --git a/code/modules/admin/buildmode/ladders.dm b/code/modules/admin/buildmode/ladders.dm new file mode 100644 index 00000000..76cc1364 --- /dev/null +++ b/code/modules/admin/buildmode/ladders.dm @@ -0,0 +1,29 @@ +/datum/build_mode/ladders + name = "Ladders" + icon_state = "buildmode6" + var/turf/ladder_upper + var/turf/ladder_lower + +/datum/build_mode/ladders/Help() + to_chat(user, "***********************************************************") + to_chat(user, "Left Click on Turf = Set as upper ladder loc") + to_chat(user, "Right Click on Turf = Set as lower ladder loc") + to_chat(user, "As soon as both points have been selected, the ladder is created.") + to_chat(user, "***********************************************************") + +/datum/build_mode/ladders/OnClick(var/atom/A, var/list/parameters) + if(parameters["left"]) + ladder_upper = get_turf(A) + to_chat(user, "Defined [ladder_upper] ([ladder_upper.type]) as the upper ladder location.") + if(parameters["right"]) + ladder_lower = get_turf(A) + to_chat(user, "Defined [ladder_lower] ([ladder_lower.type]) as the lower ladder location.") + if(ladder_upper && ladder_lower) + to_chat(user, "Ladder locations set, building ladders.") + Log("Created a ladder between '[log_info_line(ladder_upper)]' and '[log_info_line(ladder_lower)]'.") + var/obj/structure/ladder/upper = new /obj/structure/ladder(ladder_upper) + var/obj/structure/ladder/lower = new /obj/structure/ladder/up(ladder_lower) + upper.target_down = lower + lower.target_up = upper + ladder_upper = null + ladder_lower = null diff --git a/code/modules/admin/buildmode/light_maker.dm b/code/modules/admin/buildmode/light_maker.dm new file mode 100644 index 00000000..cccdae7b --- /dev/null +++ b/code/modules/admin/buildmode/light_maker.dm @@ -0,0 +1,38 @@ +/datum/build_mode/light_maker + name = "Light Maker" + icon_state = "buildmode8" + + var/light_range = 3 + var/light_power = 3 + var/light_color = COLOR_WHITE + +/datum/build_mode/light_maker/Help() + to_chat(usr, "***********************************************************") + to_chat(usr, "Left Click = Make it glow") + to_chat(usr, "Right Click = Reset glow") + to_chat(usr, "Right Click on Build Mode Button = Change glow properties") + to_chat(usr, "***********************************************************") + +/datum/build_mode/light_maker/Configurate() + var/choice = alert("Change the new light range, power, or color?", "Light Maker", "Range", "Power", "Color", "Cancel") + switch(choice) + if("Range") + var/input = input("New light range.", name, light_range) as null|num + if(input) + light_range = input + if("Power") + var/input = input("New light power.", name, light_power) as null|num + if(input) + light_power = input + if("Color") + var/input = input("New light color.", name, light_color) as null|color + if(input) + light_color = input + +/datum/build_mode/light_maker/OnClick(var/atom/A, var/list/parameters) + if(parameters["left"]) + if(A) + A.set_light(light_range, light_power, light_color) + if(parameters["right"]) + if(A) + A.set_light(0, 0, COLOR_WHITE) diff --git a/code/modules/admin/buildmode/move_into.dm b/code/modules/admin/buildmode/move_into.dm new file mode 100644 index 00000000..00d6eb64 --- /dev/null +++ b/code/modules/admin/buildmode/move_into.dm @@ -0,0 +1,46 @@ +/datum/build_mode/move_into + name = "Move Into" + icon_state = "buildmode7" + + var/atom/destination + +/datum/build_mode/move_into/Destroy() + ClearDestination() + . = ..() + +/datum/build_mode/move_into/Help() + to_chat(user, "***********************************************************") + to_chat(user, "Left Click = Select destination") + to_chat(user, "Right Click on Movable Atom = Move target into destination") + to_chat(user, "***********************************************************") + +/datum/build_mode/move_into/OnClick(var/atom/movable/A, var/list/parameters) + if(parameters["left"]) + SetDestination(A) + if(parameters["right"]) + if(!destination) + to_chat(user, "No target destination.") + else if(!ismovable(A)) + to_chat(user, "\The [A] must be of type /atom/movable.") + else + to_chat(user, "Moved \the [A] into \the [destination].") + Log("Moved '[log_info_line(A)]' into '[log_info_line(destination)]'.") + A.forceMove(destination) + +/datum/build_mode/move_into/proc/SetDestination(var/atom/A) + if(A == destination) + return + ClearDestination() + + destination = A + GLOB.destroyed_event.register(destination, src, /datum/build_mode/move_into/proc/ClearDestination) + to_chat(user, "Will now move targets into \the [destination].") + +/datum/build_mode/move_into/proc/ClearDestination(var/feedback) + if(!destination) + return + + GLOB.destroyed_event.unregister(destination, src, /datum/build_mode/move_into/proc/ClearDestination) + destination = null + if(feedback) + Warn("The selected destination was deleted.") diff --git a/code/modules/admin/buildmode/relocate_to.dm b/code/modules/admin/buildmode/relocate_to.dm new file mode 100644 index 00000000..dd275d7c --- /dev/null +++ b/code/modules/admin/buildmode/relocate_to.dm @@ -0,0 +1,47 @@ +/datum/build_mode/relocate_to + name = "Relocate To" + icon_state = "buildmode9" + var/atom/movable/to_relocate + +/datum/build_mode/relocate_to/Destroy() + ClearRelocator() + . = ..() + +/datum/build_mode/relocate_to/Help() + to_chat(user, "***********************************************************") + to_chat(user, "Left Click on Movable Atom = Select object to be relocated") + to_chat(user, "Right Click on Turf = Destination to be relocated to") + to_chat(user, "***********************************************************") + +/datum/build_mode/relocate_to/OnClick(var/atom/A, var/list/parameters) + if(parameters["left"]) + if(istype(A, /atom/movable)) + SetRelocator(A) + else if(parameters["right"]) + if(to_relocate) + var/destination_turf = get_turf(A) + if(destination_turf) + to_relocate.forceMove(destination_turf) + Log("Relocated '[log_info_line(to_relocate)]' to '[log_info_line(destination_turf)]'") + else + to_chat(user, "Unable to locate destination turf.") + else + to_chat(user, "You have nothing selected to relocate.") + +/datum/build_mode/relocate_to/proc/SetRelocator(var/new_relocator) + if(to_relocate == new_relocator) + return + ClearRelocator() + + to_relocate = new_relocator + GLOB.destroyed_event.register(to_relocate, src, /datum/build_mode/relocate_to/proc/ClearRelocator) + to_chat(user, "Will now be relocating \the [to_relocate].") + +/datum/build_mode/relocate_to/proc/ClearRelocator(var/feedback) + if(!to_relocate) + return + + GLOB.destroyed_event.unregister(to_relocate, src, /datum/build_mode/relocate_to/proc/ClearRelocator) + to_relocate = null + if(feedback) + Warn("The selected relocation object was deleted.") diff --git a/code/modules/admin/buildmode/room_builder.dm b/code/modules/admin/buildmode/room_builder.dm new file mode 100644 index 00000000..3fe389fe --- /dev/null +++ b/code/modules/admin/buildmode/room_builder.dm @@ -0,0 +1,91 @@ +/datum/build_mode/room_builder + name = "Room Builder" + icon_state = "buildmode5" + + var/turf/coordinate_A + var/turf/coordinate_B + + var/floor_type = /turf/simulated/floor/plating + var/wall_type = /turf/simulated/wall + +/datum/build_mode/room_builder/Help() + to_chat(user, "***********************************************************") + to_chat(user, "Left Click on Turf = Select as point A") + to_chat(user, "Right Click on Turf = Select as point B") + to_chat(user, "As soon as both points have been selected, the room is created.") + to_chat(user, "") + to_chat(user, "Right Click on Build Mode Button = Change floor/wall type") + to_chat(user, "***********************************************************") + +/datum/build_mode/room_builder/Configurate() + var/choice = alert("Would you like to set the floor or wall type?", name, "Floor", "Wall", "Cancel") + switch(choice) + if("Floor") + floor_type = select_subpath(floor_type) || floor_type + to_chat(user, "Floor type set to [floor_type].") + if("Wall") + wall_type = select_subpath(wall_type) || wall_type + to_chat(user, "Wall type set to [wall_type].") + +/datum/build_mode/room_builder/OnClick(var/atom/A, var/list/parameters) + if(parameters["left"]) + coordinate_A = get_turf(A) + to_chat(user, "Defined [coordinate_A] ([coordinate_A.type]) as point A.") + if(parameters["right"]) + coordinate_B = get_turf(A) + to_chat(user, "Defined [coordinate_B] ([coordinate_B.type]) as point B.") + + if(coordinate_A && coordinate_B) + to_chat(user, "Room coordinates set. Building room.") + Log("Created a room with wall type [wall_type] and floor type [floor_type] from [log_info_line(coordinate_A)] to [log_info_line(coordinate_B)]") + make_rectangle(coordinate_A, coordinate_B, wall_type, floor_type) + coordinate_A = null + coordinate_B = null + +/datum/build_mode/room_builder/proc/make_rectangle(var/turf/A, var/turf/B, var/turf/wall_type, var/turf/floor_type) + if(!A || !B) // No coords + return + if(A.z != B.z) // Not same z-level + return + + var/height = A.y - B.y + var/width = A.x - B.x + var/z_level = A.z + + var/turf/lower_left_corner = null + // First, try to find the lowest part + var/desired_y = 0 + if(A.y <= B.y) + desired_y = A.y + else + desired_y = B.y + + //Now for the left-most part. + var/desired_x = 0 + if(A.x <= B.x) + desired_x = A.x + else + desired_x = B.x + + lower_left_corner = locate(desired_x, desired_y, z_level) + + // Now we can begin building the actual room. This defines the boundries for the room. + var/low_bound_x = lower_left_corner.x + var/low_bound_y = lower_left_corner.y + + var/high_bound_x = lower_left_corner.x + abs(width) + var/high_bound_y = lower_left_corner.y + abs(height) + + for(var/i = low_bound_x, i <= high_bound_x, i++) + for(var/j = low_bound_y, j <= high_bound_y, j++) + var/turf/T = locate(i, j, z_level) + if(i == low_bound_x || i == high_bound_x || j == low_bound_y || j == high_bound_y) + if(ispath(wall_type, /turf)) + T.ChangeTurf(wall_type) + else + new wall_type(T) + else + if(ispath(floor_type, /turf)) + T.ChangeTurf(floor_type) + else + new floor_type(T) diff --git a/code/modules/admin/buildmode/throw_at.dm b/code/modules/admin/buildmode/throw_at.dm new file mode 100644 index 00000000..9768e8fe --- /dev/null +++ b/code/modules/admin/buildmode/throw_at.dm @@ -0,0 +1,46 @@ +/datum/build_mode/throw_at + name = "Throw At" + icon_state = "buildmode4" + var/atom/movable/to_throw + +/datum/build_mode/throw_at/Destroy() + ClearThrowable() + . = ..() + +/datum/build_mode/throw_at/Help() + to_chat(user, "***********************************************************") + to_chat(user, "Left Click on Movable Atom = Select object to be thrown") + to_chat(user, "Right Click on Atom = Throw at the target") + to_chat(user, "***********************************************************") + +/datum/build_mode/throw_at/OnClick(var/atom/A, var/list/parameters) + if(parameters["left"]) + if(istype(A, /atom/movable)) + SetThrowable(A) + else if(parameters["right"]) + if(to_throw) + if(!isturf(to_throw.loc)) + to_chat(user, "\The [to_throw] is currently not on a turf and cannot be thrown.") + else + to_throw.throw_at(A, 10, 1) + Log("Threw '[log_info_line(to_throw)]' at '[log_info_line(A)]'") + else + to_chat(user, "You have nothing selected to throw.") + +/datum/build_mode/throw_at/proc/SetThrowable(var/new_throwable) + if(to_throw == new_throwable) + return + ClearThrowable() + + to_throw = new_throwable + GLOB.destroyed_event.register(to_throw, src, /datum/build_mode/throw_at/proc/ClearThrowable) + to_chat(user, "Will now be throwing \the [to_throw].") + +/datum/build_mode/throw_at/proc/ClearThrowable(var/feedback) + if(!to_throw) + return + + GLOB.destroyed_event.unregister(to_throw, src, /datum/build_mode/throw_at/proc/ClearThrowable) + to_throw = null + if(feedback) + Warn("The selected throwing object was deleted.") diff --git a/code/modules/admin/callproc/callproc.dm b/code/modules/admin/callproc/callproc.dm new file mode 100644 index 00000000..5703a9e5 --- /dev/null +++ b/code/modules/admin/callproc/callproc.dm @@ -0,0 +1,237 @@ +//// VERBS + +// standard callproc, select target +/client/proc/callproc() + set category = "Debug" + set name = "Advanced ProcCall" + + if(!check_rights(R_DEBUG)) return + if(config.debugparanoid && !check_rights(R_ADMIN)) return + + var/target = null + var/targetselected = 0 + + switch(alert("Proc owned by something?",, "Yes", "No", "Cancel")) + if("Yes") + targetselected=1 + switch(input("Proc owned by...", "Owner", null) as null|anything in list("Obj", "Mob", "Area or Turf", "Client")) + if("Obj") + target = input("Select target:", "Target") as null|obj in world + if("Mob") + target = input("Select target:", "Target", usr) as null|mob in world + if("Area or Turf") + target = input("Select target:", "Target", get_turf(usr)) as null|area|turf in world + if("Client") + target = input("Select target:", "Target", usr.client) as null|anything in GLOB.clients + else + return + if(!target) + to_chat(usr, "Proc call cancelled.") + return + if("Cancel") + return + if("No") + ; // do nothing + + callproc_targetpicked(targetselected, target) + +// right click verb +/client/proc/callproc_target(atom/A in range(world.view)) + set category = "Debug" + set name = "Advanced ProcCall Target" + + if(!check_rights(R_DEBUG)) return + if(config.debugparanoid && !check_rights(R_ADMIN)) return + + callproc_targetpicked(1, A) + +/datum/admins + var/datum/callproc/callproc = null // if the user has a callproc datum, it goes here + +/client/proc/callproc_targetpicked(hastarget, datum/target) + // this needs checking again here because VV's 'Call Proc' option directly calls this proc with the target datum + if(!check_rights(R_DEBUG)) return + if(config.debugparanoid && !check_rights(R_ADMIN)) return + + if(!holder.callproc) + holder.callproc = new(src) + holder.callproc.callproc(hastarget, target) + +#define CANCEL -1 +#define WAITING 0 +#define DONE 1 + +/datum/callproc + var/client/C + var/datum/target + var/hastarget + var/procname + var/list/arguments + var/waiting_for_click = 0 + +/datum/callproc/New(client/C) + ..() + src.C = C + +/datum/callproc/proc/clear() + target = null + hastarget = null + procname = null + arguments = null + waiting_for_click = 0 + +/datum/callproc/proc/callproc(hastarget, datum/target) + src.target = target + src.hastarget = hastarget + + procname = input("Proc name", "Proc") as null|text + if(!procname) + clear() + return + + if(hastarget) + if(!target) + to_chat(usr, "Your callproc target no longer exists.") + clear() + return + if(!hascall(target, procname)) + to_chat(usr, "\The [target] has no call [procname]()") + clear() + return + + arguments = list() + do_args() + +/datum/callproc/proc/do_args() + switch(get_args()) + if(WAITING) + return + if(DONE) + finalise() + clear() + +/datum/callproc/proc/get_args() + var/done = 0 + var/current = null + + while(!done) + if(hastarget && !target) + to_chat(usr, "Your callproc target no longer exists.") + return CANCEL + switch(input("Type of [arguments.len+1]\th variable", "argument [arguments.len+1]") as null|anything in list( + "finished", "null", "text", "num", "type", "obj reference", "mob reference", + "area/turf reference", "icon", "file", "client", "mob's area", "marked datum", "click on atom")) + if(null) + return CANCEL + + if("finished") + done = 1 + + if("null") + current = null + + if("text") + current = input("Enter text for [arguments.len+1]\th argument") as null|text + if(isnull(current)) return CANCEL + + if("num") + current = input("Enter number for [arguments.len+1]\th argument") as null|num + if(isnull(current)) return CANCEL + + if("type") + current = input("Select type for [arguments.len+1]\th argument") as null|anything in typesof(/obj, /mob, /area, /turf) + if(isnull(current)) return CANCEL + + if("obj reference") + current = input("Select object for [arguments.len+1]\th argument") as null|obj in world + if(isnull(current)) return CANCEL + + if("mob reference") + current = input("Select mob for [arguments.len+1]\th argument") as null|mob in world + if(isnull(current)) return CANCEL + + if("area/turf reference") + current = input("Select area/turf for [arguments.len+1]\th argument") as null|area|turf in world + if(isnull(current)) return CANCEL + + if("icon") + current = input("Provide icon for [arguments.len+1]\th argument") as null|icon + if(isnull(current)) return CANCEL + + if("client") + current = input("Select client for [arguments.len+1]\th argument") as null|anything in GLOB.clients + if(isnull(current)) return CANCEL + + if("mob's area") + var/mob/M = input("Select mob to take area for [arguments.len+1]\th argument") as null|mob in world + if(!M) return + current = get_area(M) + if(!current) + switch(alert("\The [M] appears to not have an area; do you want to pass null instead?",, "Yes", "Cancel")) + if("Yes") + ; // do nothing + if("Cancel") + return CANCEL + + if("marked datum") + current = C.holder.marked_datum() + if(!current) + switch(alert("You do not currently have a marked datum; do you want to pass null instead?",, "Yes", "Cancel")) + if("Yes") + ; // do nothing + if("Cancel") + return CANCEL + + if("click on atom") + waiting_for_click = 1 + C.verbs += /client/proc/cancel_callproc_select + to_chat(C, "Click an atom to select it. Click an atom then click 'cancel', or use the Cancel-Callproc-Select verb to cancel selecting a target by click.") + return WAITING + + if(!done) + arguments += current + + return DONE + +/client/proc/cancel_callproc_select() + set name = "Cancel Callproc Select" + set category = "Admin" + + verbs -= /client/proc/cancel_callproc_select + if(holder && holder.callproc && holder.callproc.waiting_for_click) + holder.callproc.waiting_for_click = 0 + holder.callproc.do_args() + +/client/Click(atom/A) + if(holder && holder.callproc && holder.callproc.waiting_for_click) + if(alert("Do you want to select \the [A] as the [holder.callproc.arguments.len+1]\th argument?",, "Yes", "No") == "Yes") + holder.callproc.arguments += A + + holder.callproc.waiting_for_click = 0 + verbs -= /client/proc/cancel_callproc_select + holder.callproc.do_args() + else + return ..() + +/datum/callproc/proc/finalise() + var/returnval + + if(hastarget) + if(!target) + to_chat(usr, "Your callproc target no longer exists.") + return + log_admin("[key_name(src)] called [target]'s [procname]() with [arguments.len ? "the arguments [list2params(arguments)]" : "no arguments"].") + if(arguments.len) + returnval = call(target, procname)(arglist(arguments)) + else + returnval = call(target, procname)() + else + log_admin("[key_name(src)] called [procname]() with [arguments.len ? "the arguments [list2params(arguments)]" : "no arguments"].") + returnval = call(procname)(arglist(arguments)) + + to_chat(usr, "[procname]() returned: [json_encode(returnval)]") + feedback_add_details("admin_verb","APC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +#undef CANCEL +#undef WAITING +#undef DONE diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm new file mode 100644 index 00000000..b80ec384 --- /dev/null +++ b/code/modules/admin/create_mob.dm @@ -0,0 +1,9 @@ +/var/create_mob_html = null +/datum/admins/proc/create_mob(var/mob/user) + if (!create_mob_html) + var/mobjs = null + mobjs = jointext(typesof(/mob), ";") + create_mob_html = file2text('html/create_object.html') + create_mob_html = replacetext(create_mob_html, "null /* object types */", "\"[mobjs]\"") + + user << browse(replacetext(create_mob_html, "/* ref src */", "\ref[src]"), "window=create_mob;size=425x475") diff --git a/code/modules/admin/create_object.dm b/code/modules/admin/create_object.dm new file mode 100644 index 00000000..79c76baf --- /dev/null +++ b/code/modules/admin/create_object.dm @@ -0,0 +1,26 @@ +/var/create_object_html = null + +/datum/admins/proc/create_object(var/mob/user) + if (!create_object_html) + var/objectjs = null + objectjs = jointext(typesof(/obj), ";") + create_object_html = file2text('html/create_object.html') + create_object_html = replacetext(create_object_html, "null /* object types */", "\"[objectjs]\"") + + user << browse(replacetext(create_object_html, "/* ref src */", "\ref[src]"), "window=create_object;size=425x475") + + +/datum/admins/proc/quick_create_object(var/mob/user) + + var/quick_create_object_html = null + var/path = input("Select the path of the object you wish to create.", "Path", /obj) as null|anything in list(/obj,/obj/structure,/obj/item,/obj/item/weapon,/obj/item/clothing,/obj/machinery,/obj/mecha) + if(!path) + return + + if (!quick_create_object_html) + var/objectjs = null + objectjs = jointext(typesof(path), ";") + quick_create_object_html = file2text('html/create_object.html') + quick_create_object_html = replacetext(quick_create_object_html, "null /* object types */", "\"[objectjs]\"") + + user << browse(replacetext(quick_create_object_html, "/* ref src */", "\ref[src]"), "window=quick_create_object;size=425x475") diff --git a/code/modules/admin/create_turf.dm b/code/modules/admin/create_turf.dm new file mode 100644 index 00000000..05111be3 --- /dev/null +++ b/code/modules/admin/create_turf.dm @@ -0,0 +1,9 @@ +/var/create_turf_html = null +/datum/admins/proc/create_turf(var/mob/user) + if (!create_turf_html) + var/turfjs = null + turfjs = jointext(typesof(/turf), ";") + create_turf_html = file2text('html/create_object.html') + create_turf_html = replacetext(create_turf_html, "null /* object types */", "\"[turfjs]\"") + + user << browse(replacetext(create_turf_html, "/* ref src */", "\ref[src]"), "window=create_turf;size=425x475") diff --git a/code/modules/admin/hellban.dm b/code/modules/admin/hellban.dm new file mode 100644 index 00000000..2ea07ccf --- /dev/null +++ b/code/modules/admin/hellban.dm @@ -0,0 +1,59 @@ +#define HELLBANSFILE "config/hellbans.txt" + +/hook/startup/proc/loadhellbans() + load_hellbans() + return 1 + +/proc/load_hellbans() + log_and_message_admins("Loading hellbans") + hellbans = list() + var/list/Lines = file2list(HELLBANSFILE) + for(var/line in Lines) + if(!length(line)) + continue + + var/ascii = text2ascii(line,1) + + if(copytext(line,1,2) == "#" || ascii == 9 || ascii == 32)//# space or tab + continue + + hellbans.Add(ckey(line)) + + if(!hellbans.len) + log_and_message_admins("hellbans: empty or missing.") + hellbans = null + else + log_and_message_admins("hellbans: [hellbans.len] entrie(s).") + +//Checking and adding. +/mob/proc/is_hellbanned() + return client && client.hellbanned + +/client/proc/is_hellbanned() + return hellbanned + +/client/proc/check_hellbanned() + if(hellbans && ckey in hellbans) + hellbanned = 1 + +/datum/admin/proc/add_hellban() + set category = "Admin" + set name = "Hellban Add" + set desc = "Adds a ckey to hellban list." + if (!usr.client.holder) + return + var/client/C = input(src, "Select a victim", "Hellban") as null|anything in GLOB.clients + if(C) + message_admins("[C] has been hellbanned for this round.") + C.hellbanned = TRUE + +/datum/admin/proc/remove_hellban() + set category = "Admin" + set name = "Hellban Remove" + set desc = "Remove a ckey from hellban list." + if (!usr.client.holder) + return + var/client/C = input(src, "Select a redeemed", "Hellban") as null|anything in GLOB.clients + if(C) + message_admins("[C] has been unhellbanned for this round.") + C.hellbanned = FALSE \ No newline at end of file diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm new file mode 100644 index 00000000..c8d7bbfc --- /dev/null +++ b/code/modules/admin/holder2.dm @@ -0,0 +1,153 @@ +#define STEALTH_OFF 0 +#define STEALTH_MANUAL 1 +#define STEALTH_AUTO 2 + +var/list/admin_datums = list() + +/datum/admins + var/rank = "Temporary Admin" + var/client/owner = null + var/rights = 0 + var/stealthy_ = STEALTH_OFF + + var/weakref/marked_datum_weak + + var/admincaster_screen = 0 //See newscaster.dm under machinery for a full description + var/datum/feed_message/admincaster_feed_message = new /datum/feed_message //These two will act as holders. + var/datum/feed_channel/admincaster_feed_channel = new /datum/feed_channel + var/admincaster_signature //What you'll sign the newsfeeds as + +/datum/admins/proc/marked_datum() + if(marked_datum_weak) + return marked_datum_weak.resolve() + +/datum/admins/New(initial_rank = "Temporary Admin", initial_rights = 0, ckey) + if(!ckey) + error("Admin datum created without a ckey argument. Datum has been deleted") + qdel(src) + return + admincaster_signature = "[GLOB.using_map.company_name] Officer #[rand(0,9)][rand(0,9)][rand(0,9)]" + rank = initial_rank + rights = initial_rights + admin_datums[ckey] = src + +/datum/admins/proc/associate(client/C) + if(istype(C)) + owner = C + owner.holder = src + owner.add_admin_verbs() //TODO + GLOB.admins |= C + world.SetConfig("APP/admin", C.ckey, "role=admin") + +/datum/admins/proc/disassociate() + if(owner) + world.SetConfig("APP/admin", owner.ckey, null) + GLOB.admins -= owner + owner.remove_admin_verbs() + owner.deadmin_holder = owner.holder + owner.holder = null + +/datum/admins/proc/reassociate() + if(owner) + world.SetConfig("APP/admin", owner.ckey, "role=admin") + GLOB.admins += owner + owner.holder = src + owner.deadmin_holder = null + owner.add_admin_verbs() + + +/* +checks if usr is an admin with at least ONE of the flags in rights_required. (Note, they don't need all the flags) +if rights_required == 0, then it simply checks if they are an admin. +if it doesn't return 1 and show_msg=1 it will prints a message explaining why the check has failed +generally it would be used like so: + +proc/admin_proc() + if(!check_rights(R_ADMIN)) return + to_chat(usr, "you have enough rights!") + +NOTE: It checks usr by default. Supply the "user" argument if you wish to check for a specific mob. +*/ +/proc/check_rights(rights_required, show_msg=1, var/client/C = usr) + if(ismob(C)) + var/mob/M = C + C = M.client + if(!C) + return FALSE + if(!C.holder) + if(show_msg) + to_chat(C, "Error: You are not an admin.") + return FALSE + + if(rights_required) + if(rights_required & C.holder.rights) + return TRUE + else + if(show_msg) + to_chat(C, "Error: You do not have sufficient rights to do that. You require one of the following flags:[rights2text(rights_required," ")].") + return FALSE + else + return TRUE + +//probably a bit iffy - will hopefully figure out a better solution +/proc/check_if_greater_rights_than(client/other) + if(usr && usr.client) + if(usr.client.holder) + if(!other || !other.holder) + return 1 + if(usr.client.holder.rights != other.holder.rights) + if( (usr.client.holder.rights & other.holder.rights) == other.holder.rights ) + return 1 //we have all the rights they have and more + to_chat(usr, "Error: Cannot proceed. They have more or equal rights to us.") + return 0 + +/client/proc/deadmin() + if(holder) + holder.disassociate() + //qdel(holder) + return 1 + +/mob/Stat() + . = ..() + if(!client) + return + + var/stealth_status = client.is_stealthed() + if(stealth_status && statpanel("Status")) + stat("Stealth", "Engaged [client.holder.stealthy_ == STEALTH_AUTO ? "(Auto)" : "(Manual)"]") + +/client/proc/is_stealthed() + if(!holder) + return FALSE + + // If someone has been AFK since round-start or longer, stealth them + // BYOND keeps track of inactivity between rounds as long as it's not a full stop/start. + if(holder.stealthy_ == STEALTH_OFF && ((inactivity >= world.time) || (config.autostealth && inactivity >= MinutesToTicks(config.autostealth)))) + holder.stealthy_ = STEALTH_AUTO + else if(holder.stealthy_ == STEALTH_AUTO && inactivity < world.time) + // And if someone has been set to auto-stealth and returns, unstealth them + holder.stealthy_ = STEALTH_OFF + return holder.stealthy_ + +/mob/proc/is_stealthed() + return client && client.is_stealthed() + +/client/proc/stealth() + set category = "Admin" + set name = "Stealth Mode" + + if(!holder) + to_chat(src, "Error: You are not an admin.") + return + + holder.stealthy_ = holder.stealthy_ == STEALTH_OFF ? STEALTH_MANUAL : STEALTH_OFF + if(holder.stealthy_) + to_chat(src, "You are now stealthed.") + else + to_chat(src, "You are no longer stealthed.") + log_and_message_admins("has turned stealth mode [holder.stealthy_ ? "ON" : "OFF"]") + feedback_add_details("admin_verb","SM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +#undef STEALTH_OFF +#undef STEALTH_MANUAL +#undef STEALTH_AUTO \ No newline at end of file diff --git a/code/modules/admin/holoverbs.dm b/code/modules/admin/holoverbs.dm new file mode 100644 index 00000000..c057cb49 --- /dev/null +++ b/code/modules/admin/holoverbs.dm @@ -0,0 +1,45 @@ + +/datum/admins/proc/ai_hologram_set(mob/appear as mob in world) + set name = "Set AI Hologram" + set desc = "Set an AI's hologram to a mob. Use this verb on the mob you want the hologram to look like." + set category = "Fun" + + if(!check_rights(R_FUN)) return + + var/list/AIs = list() + for(var/mob/living/silicon/ai/AI in SSmobs.mob_list) + AIs += AI + + var/mob/living/silicon/ai/AI = input("Which AI do you want to apply [appear] to as a hologram?") as null|anything in AIs + if(!AI) return + + var/image/I = image(appear.icon, appear.icon_state) + I.overlays = appear.overlays + I.underlays = appear.underlays + I.color = list( + 0.30, 0.30, 0.30, 0.0, // Greyscale and reduce the alpha of the icon + 0.59, 0.59, 0.59, 0.0, + 0.11, 0.11, 0.11, 0.0, + 0.00, 0.00, 0.00, 0.5, + 0.00, 0.00, 0.00, 0.0 + ) + var/image/scan = image('icons/effects/effects.dmi', "scanline") + scan.color = list( + 0.30,0.30,0.30,0.00, // Greyscale the scanline icon too + 0.59,0.59,0.59,0.00, + 0.11,0.11,0.11,0.00, + 0.00,0.00,0.00,1.00, + 0.00,0.00,0.00,0.00 + ) + scan.blend_mode = BLEND_MULTIPLY + + // Combine the mob image and the scanlines into a single KEEP_TOGETHER'd image + var/image/I2 = image(null) + I2.underlays += I + I2.overlays += scan + I2.appearance_flags = KEEP_TOGETHER + I2.color = rgb(125, 180, 225) // make it blue! + AI.holo_icon = I2 + + to_chat(AI, "Your hologram icon has been set to [appear].") + log_and_message_admins("set [key_name(AI)]'s hologram icon to [key_name(appear)]") diff --git a/code/modules/admin/map_capture.dm b/code/modules/admin/map_capture.dm new file mode 100644 index 00000000..ccdbad3a --- /dev/null +++ b/code/modules/admin/map_capture.dm @@ -0,0 +1,80 @@ +/datum/admins/proc/capture_map_part(tx as null|num, ty as null|num, tz as null|num, range as null|num) + set category = "Server" + set name = "Capture Map Part" + set desc = "Usage: Capture-Map-Part target_x_cord target_y_cord target_z_cord range (captures part of a map originating from bottom left corner)" + + if(!check_rights(R_ADMIN|R_DEBUG|R_SERVER)) + to_chat(usr, "You are not allowed to use this command") + return + + if(isnull(tx) || isnull(ty) || isnull(tz) || isnull(range)) + to_chat(usr, "Capture Map Part, captures part of a map using camara like rendering.") + to_chat(usr, "Usage: Capture-Map-Part target_x_cord target_y_cord target_z_cord range") + to_chat(usr, "Target coordinates specify bottom left corner of the capture, range defines render distance to opposite corner.") + return + + if(range > 32 || range <= 0) + to_chat(usr, "Capturing range is incorrect, it must be within 1-32.") + return + + if(locate(tx,ty,tz)) + var/ligths = 0 + if(alert("Do you want lighting to be included in capture?", "Map Capture", "No", "Yes") == "Yes") + ligths = 1 + var/cap = generate_image(tx ,ty ,tz ,range, CAPTURE_MODE_PARTIAL, null, ligths, 1) + var/file_name = "map_capture_x[tx]_y[ty]_z[tz]_r[range].png" + to_chat(usr, "Saved capture in cache as [file_name].") + usr << browse_rsc(cap, file_name) + else + to_chat(usr, "Target coordinates are incorrect.") + +/datum/admins/proc/capture_map_capture_next(currentz, currentx, currenty, ligths) + if(locate(currentx, currenty, currentz)) + var/cap = generate_image(currentx ,currenty ,currentz ,32, CAPTURE_MODE_PARTIAL, null, ligths, 1) + var/file_name = "map_capture_x[currentx]_y[currenty]_z[currentz]_r32.png" + to_chat(usr, "Saved capture in cache as [file_name].") + usr << browse_rsc(cap, file_name) + currentx = currentx + 32 + spawn (1) + .(currentz, currentx, currenty, ligths) + else + currenty = currenty + 32 + currentx = 1 + if(locate(currentx, currenty, currentz)) + var/cap = generate_image(currentx ,currenty ,currentz ,32, CAPTURE_MODE_PARTIAL, null, ligths, 1) + var/file_name = "map_capture_x[currentx]_y[currenty]_z[currentz]_r32.png" + to_chat(usr, "Saved capture in cache as [file_name].") + usr << browse_rsc(cap, file_name) + currentx = currentx + 32 + spawn (1) + .(currentz, currentx, currenty, ligths) + else + to_chat(usr, "End of map, capture is done.") + +/datum/admins/proc/capture_map(tz as null|num) + set category = "Server" + set name = "Capture Map" + set desc = "Usage: Capture-Map target_z_cord (captures map)" + + if(!check_rights(R_ADMIN|R_DEBUG|R_SERVER)) + to_chat(usr, "You are not allowed to use this command") + return + + if(isnull(tz)) + to_chat(usr, "Map Part, map using camara like rendering.") + to_chat(usr, "Usage: Capture-Map target_z_cord") + to_chat(usr, "Target Z coordinates define z level to capture.") + return + + if(!locate(1, 1, tz)) + to_chat(usr, "Target z-level is incorrect.") + return + + var/ligths = 0 + if(alert("Do you want lighting to be included in capture?", "Map Capture", "No", "Yes") == "Yes") + ligths = 1 + + switch(alert("Are you sure? (This will cause masive lag!!!)", "Map Capture", "No", "Yes")) + if("Yes") + usr.client.holder.capture_map_capture_next(tz, 1, 1, ligths) + diff --git a/code/modules/admin/newbanjob.dm b/code/modules/admin/newbanjob.dm new file mode 100644 index 00000000..b2008c05 --- /dev/null +++ b/code/modules/admin/newbanjob.dm @@ -0,0 +1,272 @@ +var/savefile/Banlistjob + + +/proc/_jobban_isbanned(var/client/clientvar, var/rank) + if(!clientvar) return 1 + ClearTempbansjob() + var/id = clientvar.computer_id + var/key = clientvar.ckey + if (guest_jobbans(rank)) + if(config.guest_jobban && IsGuestKey(key)) + return 1 + Banlistjob.cd = "/base" + if (Banlistjob.dir.Find("[key][id][rank]")) + return 1 + + Banlistjob.cd = "/base" + for (var/A in Banlistjob.dir) + Banlistjob.cd = "/base/[A]" + if ((id == Banlistjob["id"] || key == Banlistjob["key"]) && rank == Banlistjob["rank"]) + return 1 + return 0 + +/proc/LoadBansjob() + + Banlistjob = new("data/job_fullnew.bdb") + log_admin("Loading Banlistjob") + + if (!length(Banlistjob.dir)) log_admin("Banlistjob is empty.") + + if (!Banlistjob.dir.Find("base")) + log_admin("Banlistjob missing base dir.") + Banlistjob.dir.Add("base") + Banlistjob.cd = "/base" + else if (Banlistjob.dir.Find("base")) + Banlistjob.cd = "/base" + + ClearTempbansjob() + return 1 + +/proc/ClearTempbansjob() + UpdateTime() + + Banlistjob.cd = "/base" + for (var/A in Banlistjob.dir) + Banlistjob.cd = "/base/[A]" + //if (!Banlistjob["key"] || !Banlistjob["id"]) + // RemoveBanjob(A, "full") + // log_admin("Invalid Ban.") + // message_admins("Invalid Ban.") + // continue + + if (!Banlistjob["temp"]) continue + if (CMinutes >= Banlistjob["minutes"]) RemoveBanjob(A) + + return 1 + + +/proc/AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, rank) + UpdateTime() + var/bantimestamp + if (temp) + UpdateTime() + bantimestamp = CMinutes + minutes + if(rank == "Heads") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Head of Personnel") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Captain") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Head of Security") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Engineer") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Research Director") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Medical Officer") + return 1 + if(rank == "Security") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Head of Security") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Warden") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Detective") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Security Officer") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Cyborg") + return 1 + if(rank == "Engineering") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Engineer") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Atmospheric Technician") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Engineer") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Cyborg") + return 1 + if(rank == "Research") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Scientist") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Geneticist") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Medical Officer") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Research Director") + return 1 + if(rank == "Medical") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Geneticist") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Medical Doctor") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Medical Officer") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chemist") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Cyborg") + return 1 + if(rank == "CE_Station_Engineer") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Engineer") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Engineer") + return 1 + if(rank == "CE_Atmospheric_Tech") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Atmospheric Technician") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Engineer") + return 1 + if(rank == "CE_Shaft_Miner") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Shaft Miner") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Engineer") + return 1 + if(rank == "Chemist_RD_CMO") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Medical Officer") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Research Director") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chemist") + return 1 + if(rank == "Geneticist_RD_CMO") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Medical Officer") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Research Director") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Geneticist") + return 1 + if(rank == "MD_CMO") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Medical Officer") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Medical Doctor") + return 1 + if(rank == "Scientist_RD") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Research Director") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Scientist") + return 1 + if(rank == "AI_Cyborg") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Cyborg") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "AI") + return 1 + if(rank == "Detective_HoS") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Detective") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Head of Security") + return 1 + if(rank == "Virologist_RD_CMO") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Medical Officer") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Research Director") + AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Virologist") + return 1 + + Banlistjob.cd = "/base" + if ( Banlistjob.dir.Find("[ckey][computerid][rank]") ) + to_chat(usr, "Banjob already exists.") + return 0 + else + Banlistjob.dir.Add("[ckey][computerid][rank]") + Banlistjob.cd = "/base/[ckey][computerid][rank]" + Banlistjob["key"] << ckey + Banlistjob["id"] << computerid + Banlistjob["rank"] << rank + Banlistjob["reason"] << reason + Banlistjob["bannedby"] << bannedby + Banlistjob["temp"] << temp + if (temp) + Banlistjob["minutes"] << bantimestamp + + return 1 + +/proc/RemoveBanjob(foldername) + var/key + var/id + var/rank + Banlistjob.cd = "/base/[foldername]" + Banlistjob["key"] >> key + Banlistjob["id"] >> id + Banlistjob["rank"] >> rank + Banlistjob.cd = "/base" + + if (!Banlistjob.dir.Remove(foldername)) return 0 + + if(!usr) + log_admin("Banjob Expired: [key]") + message_admins("Banjob Expired: [key]") + else + log_admin("[key_name_admin(usr)] unjobbanned [key] from [rank]") + message_admins("[key_name_admin(usr)] unjobbanned:[key] from [rank]") + ban_unban_log_save("[key_name_admin(usr)] unjobbanned [key] from [rank]") + feedback_inc("ban_job_unban",1) + feedback_add_details("ban_job_unban","- [rank]") + + for (var/A in Banlistjob.dir) + Banlistjob.cd = "/base/[A]" + if ((key == Banlistjob["key"] || id == Banlistjob["id"]) && (rank == Banlistjob["rank"])) + Banlistjob.cd = "/base" + Banlistjob.dir.Remove(A) + continue + + return 1 + +/proc/GetBanExpjob(minutes as num) + UpdateTime() + var/exp = minutes - CMinutes + if (exp <= 0) + return 0 + else + var/timeleftstring + if (exp >= 1440) //1440 = 1 day in minutes + timeleftstring = "[round(exp / 1440, 0.1)] Days" + else if (exp >= 60) //60 = 1 hour in minutes + timeleftstring = "[round(exp / 60, 0.1)] Hours" + else + timeleftstring = "[exp] Minutes" + return timeleftstring + +/datum/admins/proc/unjobbanpanel() + var/count = 0 + var/dat + //var/dat = "
            Unban Player: (U) = Unban , (E) = Edit Ban (Total
            " + Banlistjob.cd = "/base" + for (var/A in Banlistjob.dir) + count++ + Banlistjob.cd = "/base/[A]" + dat += text("") + + dat += "
            (U) Key: [Banlistjob["key"]] Rank: [Banlistjob["rank"]] ([Banlistjob["temp"] ? "[GetBanExpjob(Banlistjob["minutes"]) ? GetBanExpjob(Banlistjob["minutes"]) : "Removal pending" ]" : "Permaban"])(By: [Banlistjob["bannedby"]])(Reason: [Banlistjob["reason"]])
            " + dat = "
            Bans: (U) = Unban , - ([count] Bans)
            [dat]" + usr << browse(dat, "window=unbanp;size=875x400") + +/*/datum/admins/proc/permjobban(ckey, computerid, reason, bannedby, temp, minutes, rank) + if(AddBanjob(ckey, computerid, reason, usr.ckey, 0, 0, job)) + to_chat(M, "You have been banned from [job] by [usr.client.ckey].\nReason: [reason].") + to_chat(M, "This is a ban until appeal.") + if(config.banappeals) + to_chat(M, "To try to resolve this matter head to [config.banappeals]") + else + to_chat(M, "No ban appeals URL has been set.") + log_and_message_admins("has banned from [job] [ckey].\nReason: [reason]\nThis is a ban until appeal.") +/datum/admins/proc/timejobban(ckey, computerid, reason, bannedby, temp, minutes, rank) + if(AddBanjob(ckey, computerid, reason, usr.ckey, 1, mins, job)) + to_chat(M, "You have been jobbanned from [job] by [usr.client.ckey].\nReason: [reason].") + to_chat(M, "This is a temporary ban, it will be removed in [mins] minutes.") + if(config.banappeals) + to_chat(M, "To try to resolve this matter head to [config.banappeals]") + else + to_chat(M, "No ban appeals URL has been set.") + log_and_message_admins("has banned from [job] [ckey].\nReason: [reason]\nThis will be removed in [mins] minutes.")*/ +//////////////////////////////////// DEBUG //////////////////////////////////// + +/proc/CreateBansjob() + + UpdateTime() + + var/i + var/last + + for(i=0, i<1001, i++) + var/a = pick(1,0) + var/b = pick(1,0) + if(b) + Banlistjob.cd = "/base" + Banlistjob.dir.Add("trash[i]trashid[i]") + Banlistjob.cd = "/base/trash[i]trashid[i]" + Banlistjob["key"] << "trash[i]" + else + Banlistjob.cd = "/base" + Banlistjob.dir.Add("[last]trashid[i]") + Banlistjob.cd = "/base/[last]trashid[i]" + Banlistjob["key"] << last + Banlistjob["id"] << "trashid[i]" + Banlistjob["reason"] << "Trashban[i]." + Banlistjob["temp"] << a + Banlistjob["minutes"] << CMinutes + rand(1,2000) + Banlistjob["bannedby"] << "trashmin" + last = "trash[i]" + + Banlistjob.cd = "/base" + +/proc/ClearAllBansjob() + Banlistjob.cd = "/base" + for (var/A in Banlistjob.dir) + RemoveBanjob(A, "full") diff --git a/code/modules/admin/permissionverbs/permissionedit.dm b/code/modules/admin/permissionverbs/permissionedit.dm new file mode 100644 index 00000000..de472de6 --- /dev/null +++ b/code/modules/admin/permissionverbs/permissionedit.dm @@ -0,0 +1,149 @@ +/client/proc/edit_admin_permissions() + set category = "Admin" + set name = "Permissions Panel" + set desc = "Edit admin permissions" + if(!check_rights(R_PERMISSIONS)) return + usr.client.holder.edit_admin_permissions() + +/datum/admins/proc/edit_admin_permissions() + if(!check_rights(R_PERMISSIONS)) return + + var/output = {" + + +Permissions Panel + + + + +
            + + + + +"} + + for(var/adm_ckey in admin_datums) + var/datum/admins/D = admin_datums[adm_ckey] + if(!D) continue + var/rank = D.rank ? D.rank : "*none*" + var/rights = rights2text(D.rights," ") + if(!rights) rights = "*none*" + + output += "" + output += "" + output += "" + output += "" + output += "" + + output += {" +
            CKEY \[+\]RANKPERMISSIONS
            [adm_ckey] \[-\][rank][rights]
            +
            Search:
            + +"} + + usr << browse(output,"window=editrights;size=600x500") + +/datum/admins/proc/log_admin_rank_modification(var/adm_ckey, var/new_rank) + if(config.admin_legacy_system) return + + if(!usr.client) + return + + if(!usr.client.holder || !(usr.client.holder.rights & R_PERMISSIONS)) + to_chat(usr, "You do not have permission to do this!") + return + + establish_db_connection() + + if(!dbcon.IsConnected()) + to_chat(usr, "Failed to establish database connection") + return + + if(!adm_ckey || !new_rank) + return + + adm_ckey = ckey(adm_ckey) + + if(!adm_ckey) + return + + if(!istext(adm_ckey) || !istext(new_rank)) + return + + var/DBQuery/select_query = dbcon.NewQuery("SELECT id FROM erro_admin WHERE ckey = '[adm_ckey]'") + select_query.Execute() + + var/new_admin = 1 + var/admin_id + while(select_query.NextRow()) + new_admin = 0 + admin_id = text2num(select_query.item[1]) + + if(new_admin) + var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO `erro_admin` (`id`, `ckey`, `rank`, `level`, `flags`) VALUES (null, '[adm_ckey]', '[new_rank]', -1, 0)") + insert_query.Execute() + var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new admin [adm_ckey] to rank [new_rank]');") + log_query.Execute() + to_chat(usr, "New admin added.") + else + if(!isnull(admin_id) && isnum(admin_id)) + var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET rank = '[new_rank]' WHERE id = [admin_id]") + insert_query.Execute() + var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Edited the rank of [adm_ckey] to [new_rank]');") + log_query.Execute() + to_chat(usr, "Admin rank changed.") + +/datum/admins/proc/log_admin_permission_modification(var/adm_ckey, var/new_permission) + if(config.admin_legacy_system) return + + if(!usr.client) + return + + if(!usr.client.holder || !(usr.client.holder.rights & R_PERMISSIONS)) + to_chat(usr, "You do not have permission to do this!") + return + + establish_db_connection() + if(!dbcon.IsConnected()) + to_chat(usr, "Failed to establish database connection") + return + + if(!adm_ckey || !new_permission) + return + + adm_ckey = ckey(adm_ckey) + + if(!adm_ckey) + return + + if(istext(new_permission)) + new_permission = text2num(new_permission) + + if(!istext(adm_ckey) || !isnum(new_permission)) + return + + var/DBQuery/select_query = dbcon.NewQuery("SELECT id, flags FROM erro_admin WHERE ckey = '[adm_ckey]'") + select_query.Execute() + + var/admin_id + var/admin_rights + while(select_query.NextRow()) + admin_id = text2num(select_query.item[1]) + admin_rights = text2num(select_query.item[2]) + + if(!admin_id) + return + + if(admin_rights & new_permission) //This admin already has this permission, so we are removing it. + var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET flags = [admin_rights & ~new_permission] WHERE id = [admin_id]") + insert_query.Execute() + var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]');") + log_query.Execute() + to_chat(usr, "Permission removed.") + else //This admin doesn't have this permission, so we are adding it. + var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET flags = '[admin_rights | new_permission]' WHERE id = [admin_id]") + insert_query.Execute() + var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]')") + log_query.Execute() + to_chat(usr, "Permission added.") diff --git a/code/modules/admin/player_notes.dm b/code/modules/admin/player_notes.dm new file mode 100644 index 00000000..0e283e11 --- /dev/null +++ b/code/modules/admin/player_notes.dm @@ -0,0 +1,150 @@ +//This stuff was originally intended to be integrated into the ban-system I was working on +//but it's safe to say that'll never be finished. So I've merged it into the current player panel. +//enjoy ~Carn +/* +#define NOTESFILE "data/player_notes.sav" //where the player notes are saved + +datum/admins/proc/notes_show(var/ckey) + usr << browse("Player Notes[notes_gethtml(ckey)]","window=player_notes;size=700x400") + + +datum/admins/proc/notes_gethtml(var/ckey) + var/savefile/notesfile = new(NOTESFILE) + if(!notesfile) return "Error: Cannot access [NOTESFILE]" + if(ckey) + . = "Notes for [ckey]: \[+\] \[-\]
            " + notesfile.cd = "/[ckey]" + var/index = 1 + while( !notesfile.eof ) + var/note + notesfile >> note + . += "[note] \[-\]
            " + index++ + else + . = "All Notes: \[+\] \[-\]
            " + notesfile.cd = "/" + for(var/dir in notesfile.dir) + . += "[dir]
            " + return + +//handles removing entries from the buffer, or removing the entire directory if no start_index is given +/proc/notes_remove(var/ckey, var/start_index, var/end_index) + var/savefile/notesfile = new(NOTESFILE) + if(!notesfile) return + + if(!ckey) + notesfile.cd = "/" + ckey = ckey(input(usr,"Who would you like to remove notes for?","Enter a ckey",null) as null|anything in notesfile.dir) + if(!ckey) return + + if(start_index) + notesfile.cd = "/[ckey]" + var/list/noteslist = list() + if(!end_index) end_index = start_index + var/index = 0 + while( !notesfile.eof ) + index++ + var/temp + notesfile >> temp + if( (start_index <= index) && (index <= end_index) ) + continue + noteslist += temp + + notesfile.eof = -2 //Move to the start of the buffer and then erase. + + for( var/note in noteslist ) + notesfile << note + else + notesfile.cd = "/" + if(alert(usr,"Are you sure you want to remove all their notes?","Confirmation","No","Yes - Remove all notes") == "Yes - Remove all notes") + notesfile.dir.Remove(ckey) + return + +#undef NOTESFILE +*/ + +//Hijacking this file for BS12 playernotes functions. I like this ^ one systemm alright, but converting sounds too bothersome~ Chinsky. + +/proc/notes_add(var/key, var/note, var/mob/user) + if (!key || !note) + return + + //Loading list of notes for this key + var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") + var/list/infos + info >> infos + if(!infos) infos = list() + + //Overly complex timestamp creation + var/modifyer = "th" + switch(time2text(world.timeofday, "DD")) + if("01","21","31") + modifyer = "st" + if("02","22",) + modifyer = "nd" + if("03","23") + modifyer = "rd" + var/day_string = "[time2text(world.timeofday, "DD")][modifyer]" + if(copytext(day_string,1,2) == "0") + day_string = copytext(day_string,2) + var/full_date = time2text(world.timeofday, "DDD, Month DD of YYYY") + var/day_loc = findtext(full_date, time2text(world.timeofday, "DD")) + + var/datum/player_info/P = new + if (ismob(user)) + P.author = user.key + P.rank = user.client.holder.rank + else if (istext(user)) + P.author = user + P.rank = "Bot" + else + P.author = "Adminbot" + P.rank = "Friendly Robot" + P.content = note + P.timestamp = "[copytext(full_date,1,day_loc)][day_string][copytext(full_date,day_loc+2)]" + + infos += P + info << infos + + message_staff("[P.author] has edited [key]'s notes.") + log_admin("[P.author] has edited [key]'s notes.") + + del(info) // savefile, so NOT qdel + + //Updating list of keys with notes on them + var/savefile/note_list = new("data/player_notes.sav") + var/list/note_keys + note_list >> note_keys + if(!note_keys) note_keys = list() + if(!note_keys.Find(key)) note_keys += key + note_list << note_keys + del(note_list) // savefile, so NOT qdel + + +/proc/notes_del(var/key, var/index) + var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") + var/list/infos + info >> infos + if(!infos || infos.len < index) return + + var/datum/player_info/item = infos[index] + infos.Remove(item) + info << infos + + message_staff("[key_name_admin(usr)] deleted one of [key]'s notes.") + log_admin("[key_name(usr)] deleted one of [key]'s notes.") + + del(info) // savefile, so NOT qdel + +/proc/show_player_info_irc(var/key as text) + var/dat = " Info on [key]\n" + var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") + var/list/infos + info >> infos + if(!infos) + dat = "No information found on the given key." + else + for(var/datum/player_info/I in infos) + dat += "[I.content]\nby [I.author] ([I.rank]) on [I.timestamp]\n\n" + + return list2params(list(dat)) diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm new file mode 100644 index 00000000..1fb3f73c --- /dev/null +++ b/code/modules/admin/player_panel.dm @@ -0,0 +1,421 @@ + +/datum/admins/proc/player_panel_new()//The new one + if (!usr.client.holder) + return + var/dat = "Admin Player Panel" + + //javascript, the part that does most of the work~ + dat += {" + + + + + + + "} + + //body tag start + onload and onkeypress (onkeyup) javascript event calls + dat += "" + + //title + search bar + dat += {" + + + + + + + + +
            + Player panel
            + Hover over a line to see more information - Check antagonists +

            +

            + Search: +
            + + "} + + //player table header + dat += {" + + "} + + var/list/mobs = sortmobs() + var/i = 1 + for(var/entry in mobs) + var/mob/M = entry + if(!istype(M)) + continue + if(M.ckey) + + var/color = "#e6e6e6" + if(i%2 == 0) + color = "#f2f2f2" + var/is_antagonist = is_special_character(M) + + var/M_job = "" + + if(isliving(M)) + + if(iscarbon(M)) //Carbon stuff + if(ishuman(M)) + var/mob/living/carbon/human/H = M + M_job = H.job + else if(isslime(M)) + M_job = "slime" + else if(issmall(M)) + M_job = "Monkey" + else if(isalien(M)) + M_job = "Alien" + else + M_job = "Carbon-based" + + else if(issilicon(M)) //silicon + if(isAI(M)) + M_job = "AI" + else if(ispAI(M)) + M_job = "pAI" + else if(isrobot(M)) + M_job = "Cyborg" + else + M_job = "Silicon-based" + + else if(isanimal(M)) //simple animals + if(iscorgi(M)) + M_job = "Corgi" + else + M_job = "Animal" + + else + M_job = "Living" + + else if(istype(M,/mob/new_player)) + M_job = "New player" + + else if(isghost(M)) + M_job = "Ghost" + else + M_job = "Unknown ([M.type])" + + M_job = replacetext(M_job, "'", "") + M_job = replacetext(M_job, "\"", "") + M_job = replacetext(M_job, "\\", "") + + var/M_name = M.name + M_name = replacetext(M_name, "'", "") + M_name = replacetext(M_name, "\"", "") + M_name = replacetext(M_name, "\\", "") + var/M_rname = M.real_name + M_rname = replacetext(M_rname, "'", "") + M_rname = replacetext(M_rname, "\"", "") + M_rname = replacetext(M_rname, "\\", "") + + var/M_key = M.key + M_key = replacetext(M_key, "'", "") + M_key = replacetext(M_key, "\"", "") + M_key = replacetext(M_key, "\\", "") + + //output for each mob + dat += {" + + + + + + "} + + i++ + + + //player table ending + dat += {" +
            + + + [M_name] - [M_rname] - [M_key] ([M_job]) + +
            +
            +
            + + + + "} + + usr << browse(dat, "window=players;size=600x480") + +//The old one +/datum/admins/proc/player_panel_old() + if (!usr.client.holder) + return + + var/dat = "Player Menu" + dat += "" + //add to this if wanting to add back in IP checking + //add if you want to know their ip to the lists below + var/list/mobs = sortmobs() + + for(var/mob/M in mobs) + if(!M.ckey) continue + + dat += "" + if(isAI(M)) + dat += "" + else if(isrobot(M)) + dat += "" + else if(ishuman(M)) + dat += "" + else if(istype(M, /mob/living/silicon/pai)) + dat += "" + else if(istype(M, /mob/new_player)) + dat += "" + else if(isghost(M)) + dat += "" + else if(issmall(M)) + dat += "" + else if(isalien(M)) + dat += "" + else + dat += "" + + + if(istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(H.mind && H.mind.assigned_role) + dat += "" + else + dat += "" + + + dat += {" + + + "} + + + + if(usr.client) + var/client/C = usr.client + if(is_mentor(C)) + dat += {""} + else + switch(is_special_character(M)) + if(0) + dat += {""} + if(1) + dat += {""} + if(2) + dat += {""} + else + dat += {""} + + + + dat += "
            NameReal NameAssigned JobKeyOptionsPMTraitor?
            IP:(IP: [M.lastKnownIP])
            [M.name]AICyborg[M.real_name]pAINew PlayerGhostMonkeyAlienUnknown[H.mind.assigned_role]NA[M.key ? (M.client ? M.key : "[M.key] (DC)") : "No key"]XPM N/A Traitor?Traitor?Traitor? N/A
            " + + usr << browse(dat, "window=players;size=640x480") + + + +/datum/admins/proc/check_antagonists() + if (ticker && ticker.current_state >= GAME_STATE_PLAYING) + var/dat = list() + dat += "Round Status

            Round Status

            " + dat += "Current Game Mode: [ticker.mode.name]
            " + dat += "Round Duration: [roundduration2text()]
            " + dat += "Evacuation
            " + if (evacuation_controller.is_idle()) + dat += "Call Evacuation
            " + else + var/timeleft = evacuation_controller.get_eta() + if (evacuation_controller.waiting_to_leave()) + dat += "ETA: [(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]
            " + dat += "Send Back
            " + + dat += "[ticker.delay_end ? "End Round Normally" : "Delay Round End"]
            " + dat += "
            " + var/list/all_antag_types = all_antag_types() + for(var/antag_type in all_antag_types) + var/datum/antagonist/A = all_antag_types[antag_type] + dat += A.get_check_antag_output(src) + dat += "" + usr << browse(jointext(dat,null), "window=roundstatus;size=400x500") + else + alert("The game hasn't started yet!") diff --git a/code/modules/admin/secrets/admin_secrets/admin_logs.dm b/code/modules/admin/secrets/admin_secrets/admin_logs.dm new file mode 100644 index 00000000..24be5c70 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/admin_logs.dm @@ -0,0 +1,13 @@ +/datum/admin_secret_item/admin_secret/admin_logs + name = "Admin Logs" + +/datum/admin_secret_item/admin_secret/admin_logs/execute(var/mob/user) + . = ..() + if(!.) + return + var/dat = "Admin Log
            " + for(var/l in GLOB.admin_log) + dat += "
          • [l]
          • " + if(!GLOB.admin_log.len) + dat += "No-one has done anything this round!" + user << browse(dat, "window=admin_log") diff --git a/code/modules/admin/secrets/admin_secrets/alter_narsie.dm b/code/modules/admin/secrets/admin_secrets/alter_narsie.dm new file mode 100644 index 00000000..d834d801 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/alter_narsie.dm @@ -0,0 +1,14 @@ +/datum/admin_secret_item/admin_secret/alter_narise + name = "Alter Nar-Sie" + +/datum/admin_secret_item/admin_secret/alter_narise/execute(var/mob/user) + . = ..() + if(!.) + return + var/choice = input(user, "How do you wish for Nar-Sie to interact with its surroundings?") as null|anything in list("CultStation13", "Nar-Singulo") + if(choice == "CultStation13") + log_and_message_admins("has set narsie's behaviour to \"CultStation13\".", user) + narsie_behaviour = choice + if(choice == "Nar-Singulo") + log_and_message_admins("has set narsie's behaviour to \"Nar-Singulo\".", user) + narsie_behaviour = choice diff --git a/code/modules/admin/secrets/admin_secrets/bombing_list.dm b/code/modules/admin/secrets/admin_secrets/bombing_list.dm new file mode 100644 index 00000000..812f60ae --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/bombing_list.dm @@ -0,0 +1,12 @@ +/datum/admin_secret_item/admin_secret/bombing_list + name = "Bombing List" + +/datum/admin_secret_item/admin_secret/bombing_list/execute(var/mob/user) + . = ..() + if(!.) + return + + var/dat = "Bombing List" + for(var/l in GLOB.bombers) + dat += text("[l]
            ") + user << browse(dat, "window=bombers") diff --git a/code/modules/admin/secrets/admin_secrets/jump_shuttle.dm b/code/modules/admin/secrets/admin_secrets/jump_shuttle.dm new file mode 100644 index 00000000..16606cb2 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/jump_shuttle.dm @@ -0,0 +1,35 @@ +/datum/admin_secret_item/admin_secret/jump_shuttle + name = "Jump a Shuttle" + +/datum/admin_secret_item/admin_secret/jump_shuttle/can_execute(var/mob/user) + if(!shuttle_controller) return 0 + return ..() + +/datum/admin_secret_item/admin_secret/jump_shuttle/execute(var/mob/user) + . = ..() + if(!.) + return + var/shuttle_tag = input(user, "Which shuttle do you want to jump?") as null|anything in shuttle_controller.shuttles + if (!shuttle_tag) return + + var/datum/shuttle/S = shuttle_controller.shuttles[shuttle_tag] + + var/list/destinations = list() + for(var/obj/effect/shuttle_landmark/WP in world) + destinations += WP + + var/obj/effect/shuttle_landmark/destination = input(user, "Select the destination for this jump.") as null|anything in destinations + if (!destination) return + + var/long_jump = alert(user, "Is there a transition location for this jump?","", "Yes", "No") + if (long_jump == "Yes") + var/obj/effect/shuttle_landmark/transition = input(user, "Select transition location for this jump.") as null|anything in destinations + if (!transition) return + + var/move_duration = input(user, "How many seconds will this jump take?") as num + + S.long_jump(destination, transition, move_duration) + log_and_message_admins("has initiated a jump to [destination] (JMP) lasting [move_duration] seconds in transit at [transition] (JMP) for the [shuttle_tag] shuttle") + else + S.short_jump(destination) + log_and_message_admins("has initiated a jump to [destination] (JMP) for the [shuttle_tag] shuttle") diff --git a/code/modules/admin/secrets/admin_secrets/launch_shuttle.dm b/code/modules/admin/secrets/admin_secrets/launch_shuttle.dm new file mode 100644 index 00000000..a3119d69 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/launch_shuttle.dm @@ -0,0 +1,26 @@ +/datum/admin_secret_item/admin_secret/launch_shuttle + name = "Launch a Shuttle" + +/datum/admin_secret_item/admin_secret/launch_shuttle/can_execute(var/mob/user) + if(!shuttle_controller) return 0 + return ..() + +/datum/admin_secret_item/admin_secret/launch_shuttle/execute(var/mob/user) + . = ..() + if(!.) + return + var/list/valid_shuttles = list() + for (var/shuttle_tag in shuttle_controller.shuttles) + if (istype(shuttle_controller.shuttles[shuttle_tag], /datum/shuttle/autodock/ferry)) + valid_shuttles += shuttle_tag + + var/shuttle_tag = input(user, "Which shuttle do you want to launch?") as null|anything in valid_shuttles + if (!shuttle_tag) + return + + var/datum/shuttle/autodock/ferry/S = shuttle_controller.shuttles[shuttle_tag] + if (S.can_launch()) + S.launch(user) + log_and_message_admins("launched the [shuttle_tag] shuttle", user) + else + alert(user, "The [shuttle_tag] shuttle cannot be launched at this time. It's probably busy.") diff --git a/code/modules/admin/secrets/admin_secrets/launch_shuttle_forced.dm b/code/modules/admin/secrets/admin_secrets/launch_shuttle_forced.dm new file mode 100644 index 00000000..03d55d8f --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/launch_shuttle_forced.dm @@ -0,0 +1,26 @@ +/datum/admin_secret_item/admin_secret/launch_shuttle_forced + name = "Launch a Shuttle (Forced)" + +/datum/admin_secret_item/admin_secret/launch_shuttle_forced/can_execute(var/mob/user) + if(!shuttle_controller) return 0 + return ..() + +/datum/admin_secret_item/admin_secret/launch_shuttle_forced/execute(var/mob/user) + . = ..() + if(!.) + return + var/list/valid_shuttles = list() + for (var/shuttle_tag in shuttle_controller.shuttles) + if (istype(shuttle_controller.shuttles[shuttle_tag], /datum/shuttle/autodock/ferry)) + valid_shuttles += shuttle_tag + + var/shuttle_tag = input(user, "Which shuttle's launch do you want to force?") as null|anything in valid_shuttles + if (!shuttle_tag) + return + + var/datum/shuttle/autodock/ferry/S = shuttle_controller.shuttles[shuttle_tag] + if (S.can_force()) + S.force_launch(user) + log_and_message_admins("forced the [shuttle_tag] shuttle", user) + else + alert(user, "The [shuttle_tag] shuttle launch cannot be forced at this time. It's busy, or hasn't been launched yet.") diff --git a/code/modules/admin/secrets/admin_secrets/list_dna.dm b/code/modules/admin/secrets/admin_secrets/list_dna.dm new file mode 100644 index 00000000..6b385791 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/list_dna.dm @@ -0,0 +1,14 @@ +/datum/admin_secret_item/admin_secret/list_dna + name = "List DNA (Blood)" + +/datum/admin_secret_item/admin_secret/list_dna/execute(var/mob/user) + . = ..() + if(!.) + return + var/dat = "Showing DNA from blood.
            " + dat += "" + for(var/mob/living/carbon/human/H in SSmobs.mob_list) + if(H.dna && H.ckey) + dat += "" + dat += "
            NameDNABlood Type
            [H][H.dna.unique_enzymes][H.b_type]
            " + user << browse(dat, "window=DNA;size=440x410") diff --git a/code/modules/admin/secrets/admin_secrets/list_fingerprints.dm b/code/modules/admin/secrets/admin_secrets/list_fingerprints.dm new file mode 100644 index 00000000..3eefffc7 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/list_fingerprints.dm @@ -0,0 +1,19 @@ +/datum/admin_secret_item/admin_secret/list_fingerprints + name = "List Fingerprints" + +/datum/admin_secret_item/admin_secret/list_fingerprints/execute(var/mob/user) + . = ..() + if(!.) + return + var/dat = "Showing Fingerprints.
            " + dat += "" + for(var/mob/living/carbon/human/H in SSmobs.mob_list) + if(H.ckey) + if(H.dna && H.dna.uni_identity) + dat += "" + else if(H.dna && !H.dna.uni_identity) + dat += "" + else if(!H.dna) + dat += "" + dat += "
            NameFingerprints
            [H][md5(H.dna.uni_identity)]
            [H]H.dna.uni_identity = null
            [H]H.dna = null
            " + user << browse(dat, "window=fingerprints;size=440x410") diff --git a/code/modules/admin/secrets/admin_secrets/move_shuttle.dm b/code/modules/admin/secrets/admin_secrets/move_shuttle.dm new file mode 100644 index 00000000..cf3fd76f --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/move_shuttle.dm @@ -0,0 +1,29 @@ +/datum/admin_secret_item/admin_secret/move_shuttle + name = "Move a Shuttle" + +/datum/admin_secret_item/admin_secret/move_shuttle/can_execute(var/mob/user) + if(!shuttle_controller) return 0 + return ..() + +/datum/admin_secret_item/admin_secret/move_shuttle/execute(var/mob/user) + . = ..() + if(!.) + return + var/confirm = alert(user, "This command directly moves a shuttle from one area to another. DO NOT USE THIS UNLESS YOU ARE DEBUGGING A SHUTTLE AND YOU KNOW WHAT YOU ARE DOING.", "Are you sure?", "Ok", "Cancel") + if (confirm == "Cancel") + return + + var/shuttle_tag = input(user, "Which shuttle do you want to move?") as null|anything in shuttle_controller.shuttles + if (!shuttle_tag) return + + var/datum/shuttle/S = shuttle_controller.shuttles[shuttle_tag] + + var/list/destinations = list() + for(var/obj/effect/shuttle_landmark/WP in world) + destinations += WP + + var/obj/effect/shuttle_landmark/destination = input(user, "Select the destination.") as null|anything in destinations + if (!destination) return + + S.attempt_move(destination) + log_and_message_admins("moved the [shuttle_tag] shuttle to [destination] (JMP)", user) diff --git a/code/modules/admin/secrets/admin_secrets/prison_warp.dm b/code/modules/admin/secrets/admin_secrets/prison_warp.dm new file mode 100644 index 00000000..a253d61f --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/prison_warp.dm @@ -0,0 +1,39 @@ +/datum/admin_secret_item/admin_secret/prison_warp + name = "Prison Warp" + warn_before_use = TRUE + +/datum/admin_secret_item/admin_secret/prison_warp/can_execute(var/mob/user) + if(!ticker) return 0 + return ..() + +/datum/admin_secret_item/admin_secret/prison_warp/execute(var/mob/user) + . = ..() + if(!.) + return + for(var/mob/living/carbon/human/H in SSmobs.mob_list) + var/turf/T = get_turf(H) + var/security = 0 + if((T && (T in GLOB.using_map.admin_levels)) || GLOB.prisonwarped.Find(H)) + //don't warp them if they aren't ready or are already there + continue + H.Paralyse(5) + if(H.wear_id) + var/obj/item/weapon/card/id/id = H.get_idcard() + for(var/A in id.access) + if(A == access_security) + security++ + if(!security) + //strip their stuff before they teleport into a cell :downs: + for(var/obj/item/weapon/W in H) + if(istype(W, /obj/item/organ/external)) + continue + //don't strip organs + H.drop_from_inventory(W) + //teleport person to cell + H.forceMove(pick(GLOB.prisonwarp)) + H.equip_to_slot_or_del(new /obj/item/clothing/under/color/orange(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/shoes/orange(H), slot_shoes) + else + //teleport security person + H.forceMove(pick(GLOB.prisonsecuritywarp)) + GLOB.prisonwarped |= H diff --git a/code/modules/admin/secrets/admin_secrets/show_ai_laws.dm b/code/modules/admin/secrets/admin_secrets/show_ai_laws.dm new file mode 100644 index 00000000..c9e7cec5 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/show_ai_laws.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/admin_secret/show_ai_laws + name = "Show AI laws" + +/datum/admin_secret_item/admin_secret/show_ai_laws/execute(var/mob/user) + . = ..() + if(.) + user.client.holder.output_ai_laws() diff --git a/code/modules/admin/secrets/admin_secrets/show_crew_manifest.dm b/code/modules/admin/secrets/admin_secrets/show_crew_manifest.dm new file mode 100644 index 00000000..4dc85a05 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/show_crew_manifest.dm @@ -0,0 +1,12 @@ +/datum/admin_secret_item/admin_secret/show_crew_manifest + name = "Show Crew Manifest" + +/datum/admin_secret_item/admin_secret/show_crew_manifest/execute(var/mob/user) + . = ..() + if(!.) + return + var/dat + dat += "

            Crew Manifest

            " + dat += html_crew_manifest() + + user << browse(dat, "window=manifest;size=370x420;can_close=1") diff --git a/code/modules/admin/secrets/admin_secrets/show_game_mode.dm b/code/modules/admin/secrets/admin_secrets/show_game_mode.dm new file mode 100644 index 00000000..3b3c94f0 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/show_game_mode.dm @@ -0,0 +1,14 @@ +/datum/admin_secret_item/admin_secret/show_game_mode + name = "Show Game Mode" + +/datum/admin_secret_item/admin_secret/show_game_mode/can_execute(var/mob/user) + if(!ticker) + return 0 + return ..() + +/datum/admin_secret_item/admin_secret/show_game_mode/execute(var/mob/user) + . = ..() + if(!.) + return + if (ticker.mode) alert("The game mode is [ticker.mode.name]") + else alert("For some reason there's a ticker, but not a game mode") diff --git a/code/modules/admin/secrets/admin_secrets/show_law_changes.dm b/code/modules/admin/secrets/admin_secrets/show_law_changes.dm new file mode 100644 index 00000000..e870d743 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/show_law_changes.dm @@ -0,0 +1,15 @@ +/datum/admin_secret_item/admin_secret/show_law_changes + name = "Show law changes" + +/datum/admin_secret_item/admin_secret/show_law_changes/name() + return "Show Last [length(GLOB.lawchanges)] Law change\s" + +/datum/admin_secret_item/admin_secret/show_law_changes/execute(var/mob/user) + . = ..() + if(!.) + return + + var/dat = "Showing last [length(GLOB.lawchanges)] law changes.
            " + for(var/sig in GLOB.lawchanges) + dat += "[sig]
            " + user << browse(dat, "window=lawchanges;size=800x500") diff --git a/code/modules/admin/secrets/admin_secrets/show_signalers.dm b/code/modules/admin/secrets/admin_secrets/show_signalers.dm new file mode 100644 index 00000000..44acb294 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/show_signalers.dm @@ -0,0 +1,15 @@ +/datum/admin_secret_item/admin_secret/show_signalers + name = "Show Last Signalers" + +/datum/admin_secret_item/admin_secret/show_signalers/name() + return "Show Last [length(GLOB.lastsignalers)] Signaler\s" + +/datum/admin_secret_item/admin_secret/show_signalers/execute(var/mob/user) + . = ..() + if(!.) + return + + var/dat = "Showing last [length(GLOB.lastsignalers)] signalers.
            " + for(var/sig in GLOB.lastsignalers) + dat += "[sig]
            " + user << browse(dat, "window=lastsignalers;size=800x500") diff --git a/code/modules/admin/secrets/admin_secrets/traitors_and_objectives.dm b/code/modules/admin/secrets/admin_secrets/traitors_and_objectives.dm new file mode 100644 index 00000000..bcfd9cd7 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/traitors_and_objectives.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/admin_secret/traitors_and_objectives + name = "Show current traitors and objectives" + +/datum/admin_secret_item/admin_secret/traitors_and_objectives/execute(var/mob/user) + . = ..() + if(.) + user.client.holder.check_antagonists() diff --git a/code/modules/admin/secrets/final_solutions/summon_narsie.dm b/code/modules/admin/secrets/final_solutions/summon_narsie.dm new file mode 100644 index 00000000..32fb24d0 --- /dev/null +++ b/code/modules/admin/secrets/final_solutions/summon_narsie.dm @@ -0,0 +1,11 @@ +/datum/admin_secret_item/final_solution/summon_narsie + name = "Summon Nar-Sie" + +/datum/admin_secret_item/final_solution/summon_narsie/execute(var/mob/user) + . = ..() + if(!.) + return + var/choice = input(user, "You sure you want to end the round and summon Nar-Sie at your location? Misuse of this could result in removal of flags or hilarity.") in list("PRAISE SATAN", "Cancel") + if(choice == "PRAISE SATAN") + new /obj/singularity/narsie/large(get_turf(user)) + log_and_message_admins("has summoned Nar-Sie and brought about a new realm of suffering.", user) diff --git a/code/modules/admin/secrets/final_solutions/supermatter_cascade.dm b/code/modules/admin/secrets/final_solutions/supermatter_cascade.dm new file mode 100644 index 00000000..5d5aa2ef --- /dev/null +++ b/code/modules/admin/secrets/final_solutions/supermatter_cascade.dm @@ -0,0 +1,13 @@ +/datum/admin_secret_item/final_solution/supermatter_cascade + name = "Supermatter Cascade" + +/datum/admin_secret_item/final_solution/supermatter_cascade/execute(var/mob/user) + . = ..() + if(!.) + return + var/choice = input(user, "You sure you want to destroy the universe and create a large explosion at your location? Misuse of this could result in removal of flags or hilarity.") in list("NO TIME TO EXPLAIN", "Cancel") + if(choice == "NO TIME TO EXPLAIN") + explosion(get_turf(user), 8, 16, 24, 32, 1) + new /turf/unsimulated/wall/supermatter(get_turf(user)) + SetUniversalState(/datum/universal_state/supermatter_cascade) + message_admins("[key_name_admin(user)] has managed to destroy the universe with a supermatter cascade. Good job, [key_name_admin(user)]") diff --git a/code/modules/admin/secrets/fun_secrets/break_all_lights.dm b/code/modules/admin/secrets/fun_secrets/break_all_lights.dm new file mode 100644 index 00000000..2256d4f7 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/break_all_lights.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/fun_secret/break_all_lights + name = "Break All Lights" + +/datum/admin_secret_item/fun_secret/break_all_lights/execute(var/mob/user) + . = ..() + if(.) + lightsout(0,0) diff --git a/code/modules/admin/secrets/fun_secrets/break_some_lights.dm b/code/modules/admin/secrets/fun_secrets/break_some_lights.dm new file mode 100644 index 00000000..70b9eaf8 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/break_some_lights.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/fun_secret/break_some_lights + name = "Break Some Lights" + +/datum/admin_secret_item/fun_secret/break_some_lights/execute(var/mob/user) + . = ..() + if(.) + lightsout(1,2) diff --git a/code/modules/admin/secrets/fun_secrets/fix_all_lights.dm b/code/modules/admin/secrets/fun_secrets/fix_all_lights.dm new file mode 100644 index 00000000..40ffa73c --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/fix_all_lights.dm @@ -0,0 +1,10 @@ +/datum/admin_secret_item/fun_secret/fix_all_lights + name = "Fix All Lights" + +/datum/admin_secret_item/fun_secret/fix_all_lights/execute(var/mob/user) + . = ..() + if(!.) + return + + for(var/obj/machinery/light/L in world) + L.fix() diff --git a/code/modules/admin/secrets/fun_secrets/ghost_mode.dm b/code/modules/admin/secrets/fun_secrets/ghost_mode.dm new file mode 100644 index 00000000..5f34e9e2 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/ghost_mode.dm @@ -0,0 +1,48 @@ +/datum/admin_secret_item/fun_secret/ghost_mode + name = "Ghost Mode" + var/list/affected_mobs + +/datum/admin_secret_item/fun_secret/ghost_mode/New() + ..() + affected_mobs = list() + +/datum/admin_secret_item/fun_secret/ghost_mode/execute(var/mob/user) + . = ..() + if(!.) + return + + var/list/affected_areas = list() + for(var/mob/M in GLOB.living_mob_list_) + if(M.stat == CONSCIOUS && !(M in affected_mobs)) + affected_mobs |= M + switch(rand(1,4)) + if(1) + M.show_message(text("You shudder as if cold..."), 1) + if(2) + M.show_message(text("You feel something gliding across your back..."), 1) + if(3) + M.show_message(text("Your eyes twitch, you feel like something you can't see is here..."), 1) + if(4) + M.show_message(text("You notice something moving out of the corner of your eye, but nothing is there..."), 1) + + for(var/obj/W in orange(5,M)) + if(prob(25) && !W.anchored) + step_rand(W) + + var/area/A = get_area(M) + if(A.requires_power && !A.always_unpowered && A.power_light && (A.z in GLOB.using_map.player_levels)) + affected_areas |= get_area(M) + + affected_mobs |= user + for(var/area/AffectedArea in affected_areas) + AffectedArea.power_light = 0 + AffectedArea.power_change() + spawn(rand(25,50)) + AffectedArea.power_light = 1 + AffectedArea.power_change() + + sleep(100) + for(var/mob/M in affected_mobs) + M.show_message(text("The chilling wind suddenly stops..."), 1) + affected_mobs.Cut() + affected_areas.Cut() diff --git a/code/modules/admin/secrets/fun_secrets/make_all_areas_powered.dm b/code/modules/admin/secrets/fun_secrets/make_all_areas_powered.dm new file mode 100644 index 00000000..1c5f1cfd --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/make_all_areas_powered.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/fun_secret/make_all_areas_powered + name = "Make All Areas Powered" + +/datum/admin_secret_item/fun_secret/make_all_areas_powered/execute(var/mob/user) + . = ..() + if(.) + power_restore() diff --git a/code/modules/admin/secrets/fun_secrets/make_all_areas_unpowered.dm b/code/modules/admin/secrets/fun_secrets/make_all_areas_unpowered.dm new file mode 100644 index 00000000..9e4df53e --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/make_all_areas_unpowered.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/fun_secret/make_all_areas_unpowered + name = "Make All Areas Unpowered" + +/datum/admin_secret_item/fun_secret/make_all_areas_unpowered/execute(var/mob/user) + . = ..() + if(.) + power_failure() diff --git a/code/modules/admin/secrets/fun_secrets/paintball_mode.dm b/code/modules/admin/secrets/fun_secrets/paintball_mode.dm new file mode 100644 index 00000000..46446b06 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/paintball_mode.dm @@ -0,0 +1,14 @@ +/datum/admin_secret_item/fun_secret/paintbal_mode + name = "Paintball Mode" + +/datum/admin_secret_item/fun_secret/paintbal_mode/execute(var/mob/user) + . = ..() + if(!.) + return + + for(var/species in all_species) + var/datum/species/S = all_species[species] + S.blood_color = "rainbow" + for(var/obj/effect/decal/cleanable/blood/B in world) + B.basecolor = "rainbow" + B.update_icon() diff --git a/code/modules/admin/secrets/fun_secrets/power_all_smes.dm b/code/modules/admin/secrets/fun_secrets/power_all_smes.dm new file mode 100644 index 00000000..2320bcf2 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/power_all_smes.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/fun_secret/power_all_smes + name = "Power All SMES" + +/datum/admin_secret_item/fun_secret/power_all_smes/execute(var/mob/user) + . = ..() + if(.) + power_restore_quick() diff --git a/code/modules/admin/secrets/fun_secrets/remove_all_clothing.dm b/code/modules/admin/secrets/fun_secrets/remove_all_clothing.dm new file mode 100644 index 00000000..ef0e40a3 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/remove_all_clothing.dm @@ -0,0 +1,10 @@ +/datum/admin_secret_item/fun_secret/remove_all_clothing + name = "Remove ALL Clothing" + +/datum/admin_secret_item/fun_secret/remove_all_clothing/execute(var/mob/user) + . = ..() + if(!.) + return + + for(var/obj/item/clothing/O in world) + qdel(O) diff --git a/code/modules/admin/secrets/fun_secrets/remove_internal_clothing.dm b/code/modules/admin/secrets/fun_secrets/remove_internal_clothing.dm new file mode 100644 index 00000000..9de30a0a --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/remove_internal_clothing.dm @@ -0,0 +1,10 @@ +/datum/admin_secret_item/fun_secret/remove_internal_clothing + name = "Remove 'Internal' Clothing" + +/datum/admin_secret_item/fun_secret/remove_internal_clothing/execute(var/mob/user) + . = ..() + if(!.) + return + + for(var/obj/item/clothing/under/O in world) + qdel(O) diff --git a/code/modules/admin/secrets/fun_secrets/send_strike_team.dm b/code/modules/admin/secrets/fun_secrets/send_strike_team.dm new file mode 100644 index 00000000..9aee563d --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/send_strike_team.dm @@ -0,0 +1,11 @@ +/datum/admin_secret_item/fun_secret/send_strike_team + name = "Send Strike Team" + +/datum/admin_secret_item/fun_secret/send_strike_team/can_execute(var/mob/user) + if(!ticker) return 0 + return ..() + +/datum/admin_secret_item/fun_secret/send_strike_team/execute(var/mob/user) + . = ..() + if(.) + return user.client.strike_team() diff --git a/code/modules/admin/secrets/fun_secrets/toggle_bomb_cap.dm b/code/modules/admin/secrets/fun_secrets/toggle_bomb_cap.dm new file mode 100644 index 00000000..d31c69c0 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/toggle_bomb_cap.dm @@ -0,0 +1,21 @@ +/datum/admin_secret_item/fun_secret/toggle_bomb_cap + name = "Toggle Bomb Cap" + permissions = R_SERVER + +/datum/admin_secret_item/fun_secret/toggle_bomb_cap/execute(var/mob/user) + . = ..() + if(!.) + return + + switch(GLOB.max_explosion_range) + if(14) GLOB.max_explosion_range = 16 + if(16) GLOB.max_explosion_range = 20 + if(20) GLOB.max_explosion_range = 28 + if(28) GLOB.max_explosion_range = 56 + if(56) GLOB.max_explosion_range = 128 + if(128) GLOB.max_explosion_range = 14 + var/range_dev = GLOB.max_explosion_range *0.25 + var/range_high = GLOB.max_explosion_range *0.5 + var/range_low = GLOB.max_explosion_range + message_admins("[key_name_admin(user)] changed the bomb cap to [range_dev], [range_high], [range_low]", 1) + log_admin("[key_name_admin(user)] changed the bomb cap to [GLOB.max_explosion_range]") diff --git a/code/modules/admin/secrets/fun_secrets/triple_ai_mode.dm b/code/modules/admin/secrets/fun_secrets/triple_ai_mode.dm new file mode 100644 index 00000000..d6819530 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/triple_ai_mode.dm @@ -0,0 +1,13 @@ +/datum/admin_secret_item/fun_secret/triple_ai_mode + name = "Triple AI Mode" + +/datum/admin_secret_item/fun_secret/triple_ai_mode/can_execute(var/mob/user) + if(ticker && ticker.current_state > GAME_STATE_PREGAME) + return 0 + + return ..() + +/datum/admin_secret_item/admin_secret/triple_ai_mode/execute(var/mob/user) + . = ..() + if(.) + user.client.triple_ai() diff --git a/code/modules/admin/secrets/fun_secrets/turn_humans_into_corgies.dm b/code/modules/admin/secrets/fun_secrets/turn_humans_into_corgies.dm new file mode 100644 index 00000000..64dbce6a --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/turn_humans_into_corgies.dm @@ -0,0 +1,11 @@ +/datum/admin_secret_item/fun_secret/turn_humans_into_corgies + name = "Turn All Humans Into Corgies" + +/datum/admin_secret_item/fun_secret/turn_humans_into_corgies/execute(var/mob/user) + . = ..() + if(!.) + return + + for(var/mob/living/carbon/human/H in SSmobs.mob_list) + spawn(0) + H.corgize() diff --git a/code/modules/admin/secrets/fun_secrets/turn_humans_into_monkeys.dm b/code/modules/admin/secrets/fun_secrets/turn_humans_into_monkeys.dm new file mode 100644 index 00000000..611ece5a --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/turn_humans_into_monkeys.dm @@ -0,0 +1,11 @@ +/datum/admin_secret_item/fun_secret/turn_humans_into_monkeys + name = "Turn All Humans Into Monkeys" + +/datum/admin_secret_item/fun_secret/turn_humans_into_monkeys/execute(var/mob/user) + . = ..() + if(!.) + return + + for(var/mob/living/carbon/human/H in SSmobs.mob_list) + spawn(0) + H.monkeyize() diff --git a/code/modules/admin/secrets/fun_secrets/waddle.dm b/code/modules/admin/secrets/fun_secrets/waddle.dm new file mode 100644 index 00000000..e3014521 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/waddle.dm @@ -0,0 +1,9 @@ +/datum/admin_secret_item/fun_secret/waddle + name = "Enable Waddling" + +/datum/admin_secret_item/fun_secret/waddle/execute(var/mob/user) + . = ..() + if(.) + GLOB.waddling = !GLOB.waddling + to_world("Waddling has been [GLOB.waddling ? "enabled" : "disabled"].") + diff --git a/code/modules/admin/secrets/investigation/admin_pms.dm b/code/modules/admin/secrets/investigation/admin_pms.dm new file mode 100644 index 00000000..45fe20ff --- /dev/null +++ b/code/modules/admin/secrets/investigation/admin_pms.dm @@ -0,0 +1,40 @@ +/datum/admin_secret_item/investigation/admin_pms + name = "Admin PMs" + +/datum/admin_secret_item/investigation/admin_pms/execute(var/mob/user, var/filter) + . = ..() + if(!.) + return + var/dat = list() + dat += "Refresh Filtering on: " + if(filter) + dat += " [filter] Clear" + else + dat += "None" + dat += "
            " + dat += "" + dat += "" + + for(var/datum/admin_privat_message/pm in admin_pm_repository.admin_pms_) + var/datum/client_lite/sender = pm.sender + var/datum/client_lite/receiver = pm.receiver + + if(filter && !(sender.ckey == filter || (receiver && receiver.ckey == filter))) + continue + + if(receiver) + dat += "" + else + dat += "" + dat += "" + dat += "
            TimeSenderReceiver
            [pm.station_time][sender.key_name(FALSE)] F[receiver.key_name(FALSE)] F
            [pm.station_time][sender.key_name(FALSE)] F
            [pm.message]
            " + + var/datum/browser/popup = new(user, "admin_ahelps", "Admin PMs", 800, 400) + popup.set_content(jointext(dat, null)) + popup.open() + +/datum/admin_secret_item/investigation/admin_pms/Topic(href, href_list) + . = ..() + if(.) + return + execute(usr, href_list["filter"]) diff --git a/code/modules/admin/secrets/investigation/attack_logs.dm b/code/modules/admin/secrets/investigation/attack_logs.dm new file mode 100644 index 00000000..d66a74ea --- /dev/null +++ b/code/modules/admin/secrets/investigation/attack_logs.dm @@ -0,0 +1,222 @@ +/datum/admin_secret_item/investigation/attack_logs + name = "Attack Logs" + var/list/filters_per_client + +/datum/admin_secret_item/investigation/attack_logs/New() + ..() + filters_per_client = list() + +/datum/admin_secret_item/investigation/attack_logs/execute(var/mob/user) + . = ..() + if(!.) + return + var/dat = list() + dat += "Refresh | " + dat += get_filter_html(user) + dat += " | Reset" + dat += "
            " + dat += "" + dat += "" + + for(var/log in attack_log_repository.attack_logs_) + var/datum/attack_log/al = log + if(filter_log(user, al)) + continue + + dat += "" + + if(al.attacker) + dat += "" + else + dat += "" + + dat += "" + + if(al.victim) + dat += "" + else + dat += "" + + dat += "" + dat += "" + dat += "
            TimeAttackerIntentVictim
            [al.station_time][al.attacker.key_name(check_if_offline = FALSE)] PP[al.intent][al.victim.key_name(check_if_offline = FALSE)] PP
            [al.message]" + if(al.location) + dat += " JMP" + dat += "
            " + + var/datum/browser/popup = new(user, "admin_attack_logs", "Attack Logs", 800, 400) + popup.set_content(jointext(dat, null)) + popup.open() + +/datum/admin_secret_item/investigation/attack_logs/Topic(href, href_list) + . = ..() + if(.) + return + if(href_list["refresh"]) + . = 1 + if(href_list["reset"]) + reset_user_filters(usr) + . = 1 + if(.) + execute(usr) + +/datum/admin_secret_item/investigation/attack_logs/proc/get_user_filters(var/mob/user) + if(!user.client) + return list() + + . = filters_per_client[user.client] + if(!.) + . = list() + for(var/af_type in subtypesof(/attack_filter)) + var/attack_filter/af = af_type + if(initial(af.category) == af_type) + continue + . += new af_type(src) + filters_per_client[user.client] = . + +/datum/admin_secret_item/investigation/attack_logs/proc/get_filter_html(user) + . = list() + for(var/filter in get_user_filters(user)) + var/attack_filter/af = filter + . += af.get_html() + . = jointext(.," | ") + +/datum/admin_secret_item/investigation/attack_logs/proc/filter_log(user, var/datum/attack_log/al) + for(var/filter in get_user_filters(user)) + var/attack_filter/af = filter + if(af.filter_attack(al)) + return TRUE + return FALSE + +/datum/admin_secret_item/investigation/attack_logs/proc/reset_user_filters(user) + for(var/filter in get_user_filters(user)) + var/attack_filter/af = filter + af.reset() + +/attack_filter + var/category = /attack_filter + var/datum/admin_secret_item/investigation/attack_logs/holder + +/attack_filter/New(var/holder) + ..() + src.holder = holder + +/attack_filter/Topic(href, href_list) + if(..()) + return TRUE + if(OnTopic(href_list)) + holder.execute(usr) + return TRUE + +/attack_filter/proc/get_html() + return + +/attack_filter/proc/reset() + return + +/attack_filter/proc/filter_attack(var/datum/attack_log/al) + return FALSE + +/attack_filter/proc/OnTopic(href_list) + return FALSE + +/* +* Filter logs with one or more missing clients +*/ +/attack_filter/no_client + var/filter_missing_clients = TRUE + +/attack_filter/no_client/get_html() + . = list() + . += "Must have clients: " + if(filter_missing_clients) + . += "YesNo" + else + . += "YesNo" + . = jointext(.,null) + +/attack_filter/no_client/OnTopic(href_list) + if(href_list["yes"] && !filter_missing_clients) + filter_missing_clients = TRUE + return TRUE + if(href_list["no"] && filter_missing_clients) + filter_missing_clients = FALSE + return TRUE + +/attack_filter/no_client/reset() + filter_missing_clients = initial(filter_missing_clients) + +/attack_filter/no_client/filter_attack(var/datum/attack_log/al) + if(!filter_missing_clients) + return FALSE + if(al.attacker && al.attacker.client.ckey == NO_CLIENT_CKEY) + return TRUE + if(al.victim && al.victim.client.ckey == NO_CLIENT_CKEY) + return TRUE + return FALSE + +/* + Either subject must be the selected client +*/ +/attack_filter/must_be_given_ckey + var/ckey_filter + var/check_attacker = TRUE + var/check_victim = TRUE + var/description = "Either ckey is" + +/attack_filter/must_be_given_ckey/reset() + ckey_filter = null + +/attack_filter/must_be_given_ckey/get_html() + return "[description]: [ckey_filter ? ckey_filter : "*ANY*"]" + +/attack_filter/must_be_given_ckey/OnTopic(href_list) + if(!href_list["select_ckey"]) + return + var/ckey = input("Select ckey to filter on","Select ckey", ckey_filter) as null|anything in get_ckeys() + if(ckey) + if(ckey == "*ANY*") + ckey_filter = null + else + ckey_filter = ckey + return TRUE + +/attack_filter/must_be_given_ckey/proc/get_ckeys() + . = list() + for(var/log in attack_log_repository.attack_logs_) + var/datum/attack_log/al = log + if(check_attacker && al.attacker && al.attacker.client.ckey != NO_CLIENT_CKEY) + . |= al.attacker.client.ckey + if(check_victim && al.victim && al.victim.client.ckey != NO_CLIENT_CKEY) + . |= al.victim.client.ckey + . = sortList(.) + . += "*ANY*" + +/attack_filter/must_be_given_ckey/filter_attack(var/datum/attack_log/al) + if(!ckey_filter) + return FALSE + if(check_attacker && al.attacker && al.attacker.client.ckey == ckey_filter) + return FALSE + if(check_victim && al.victim && al.victim.client.ckey == ckey_filter) + return FALSE + return TRUE + +/* + Attacker must be the selected client +*/ +/attack_filter/must_be_given_ckey/attacker + description = "Attacker ckey is" + check_victim = FALSE + +/attack_filter/must_be_given_ckey/attacker/filter_attack(al) + return ..(al, TRUE, FALSE) + +/* + Victim must be the selected client +*/ +/attack_filter/must_be_given_ckey/victim + description = "Victim ckey is" + check_attacker = FALSE + +/attack_filter/must_be_given_ckey/victim/filter_attack(al) + return ..(al, FALSE, TRUE) diff --git a/code/modules/admin/secrets/random_events/gravity.dm b/code/modules/admin/secrets/random_events/gravity.dm new file mode 100644 index 00000000..d46030f3 --- /dev/null +++ b/code/modules/admin/secrets/random_events/gravity.dm @@ -0,0 +1,30 @@ +/********** +* Gravity * +**********/ +/datum/admin_secret_item/random_event/gravity + name = "Toggle Artificial Gravity" + +/datum/admin_secret_item/random_event/gravity/can_execute(var/mob/user) + if(!(ticker && ticker.mode)) + return 0 + + return ..() + +/datum/admin_secret_item/random_event/gravity/execute(var/mob/user) + . = ..() + if(!.) + return + + var/choice = input(user, "Make Command Report?") in list("Yes", "No") + gravity_is_on = !gravity_is_on + for(var/area/A in world) + A.gravitychange(gravity_is_on) + + feedback_inc("admin_secrets_fun_used",1) + feedback_add_details("admin_secrets_fun_used","Grav") + log_and_message_admins("toggled gravity.") + if(choice == "Yes") + if(gravity_is_on) + command_announcement.Announce("Gravity generators are again functioning within normal parameters. Sorry for any inconvenience.", "Gravity Restored") + else + command_announcement.Announce("Feedback surge detected in mass-distributions systems. Artificial gravity has been disabled whilst the system reinitializes.", "Gravity Failure") diff --git a/code/modules/admin/secrets/random_events/trigger_cordical_borer_infestation.dm b/code/modules/admin/secrets/random_events/trigger_cordical_borer_infestation.dm new file mode 100644 index 00000000..d7e09d84 --- /dev/null +++ b/code/modules/admin/secrets/random_events/trigger_cordical_borer_infestation.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/random_event/trigger_cordical_borer_infestation + name = "Trigger a Cortical Borer infestation" + +/datum/admin_secret_item/random_event/trigger_cordical_borer_infestation/execute(var/mob/user) + . = ..() + if(.) + return borers.attempt_random_spawn() diff --git a/code/modules/admin/secrets/random_events/trigger_xenomorph_infestation.dm b/code/modules/admin/secrets/random_events/trigger_xenomorph_infestation.dm new file mode 100644 index 00000000..a788ee78 --- /dev/null +++ b/code/modules/admin/secrets/random_events/trigger_xenomorph_infestation.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/random_event/trigger_xenomorph_infestation + name = "Trigger a Xenophage Infestation" + +/datum/admin_secret_item/random_event/trigger_xenomorph_infestation/execute(var/mob/user) + . = ..() + if(.) + return xenomorphs.attempt_random_spawn() diff --git a/code/modules/admin/server_whitelist.dm b/code/modules/admin/server_whitelist.dm new file mode 100644 index 00000000..3fd71be4 --- /dev/null +++ b/code/modules/admin/server_whitelist.dm @@ -0,0 +1,68 @@ +#define CKEYWHITELIST "data/ckey_whitelist.txt" + +/hook/startup/proc/loadCkeyWhitelist() + load_ckey_whitelist() + return 1 + +/proc/load_ckey_whitelist() + log_and_message_admins("Loading ckey_whitelist") + ckey_whitelist = list() + var/list/Lines = file2list(CKEYWHITELIST) + for(var/line in Lines) + if(!length(line)) + continue + + var/ascii = text2ascii(line,1) + + if(copytext(line,1,2) == "#" || ascii == 9 || ascii == 32)//# space or tab + continue + + ckey_whitelist.Add(ckey(line)) + + if(!ckey_whitelist.len) + log_and_message_admins("ckey_whitelist: empty or missing.") + ckey_whitelist = null + else + log_and_message_admins("ckey_whitelist: [ckey_whitelist.len] entrie(s).") + +/proc/check_ckey_whitelisted(var/ckey) + return (ckey_whitelist && (ckey in ckey_whitelist) ) + +/datum/admins/proc/ToggleCkeyWhitelist() + set category = "Server" + set name = "Toggle ckey Whitelist" + set desc="Toggles the ckey Whitelist on and off." + + config.useckeywhitelist = !config.useckeywhitelist + if(config.useckeywhitelist) + load_ckey_whitelist() + to_world("The pool is now closed.") + log_and_message_admins("[key_name(usr)] enabled the ckey whitelist.") + else + ckey_whitelist = null + to_world("The pool is now open.") + log_and_message_admins("[key_name(usr)] disabled the ckey whitelist.") + +/datum/admins/proc/toggle_panic_bunker() + set category = "Server" + set name = "Toggle Panic Bunker" + set desc= "Toggles whether or not new players can join." + + config.private_party = !config.private_party + + if(config.private_party) + to_world("The pool is now closed.") + log_and_message_admins("[key_name(usr)] enabled the panic bunker.") + else + to_world("The pool is now open.") + log_and_message_admins("[key_name(usr)] disabled the panic bunker.") + +/datum/admins/proc/ReloadCkeyWhitelist() + set category = "Server" + set name = "Reload ckey Whitelist" + set desc="Reloads the ckey Whitelist." + + load_ckey_whitelist() + log_and_message_admins("[key_name(usr)] has reloaded the ckey whitelist.") + +#undef CKEYWHITELIST \ No newline at end of file diff --git a/code/modules/admin/ticket.dm b/code/modules/admin/ticket.dm new file mode 100644 index 00000000..b96e0ce2 --- /dev/null +++ b/code/modules/admin/ticket.dm @@ -0,0 +1,236 @@ +var/list/tickets = list() +var/list/ticket_panels = list() + +/datum/ticket + var/datum/client_lite/owner + var/list/assigned_admins = list() + var/status = TICKET_OPEN + var/list/msgs = list() + var/datum/client_lite/closed_by + var/id + var/opened_time + +/datum/ticket/New(var/datum/client_lite/owner) + src.owner = owner + tickets |= src + id = tickets.len + opened_time = world.time + +/datum/ticket/proc/close(var/datum/client_lite/closed_by) + if(status == TICKET_CLOSED) + return + + if(status == TICKET_ASSIGNED && !((closed_by.ckey in assigned_admin_ckeys()) || owner.ckey == closed_by.ckey) && alert(client_by_ckey(closed_by.ckey), "You are not assigned to this ticket. Are you sure you want to close it?", "Close ticket?" , "Yes" , "No") != "Yes") + return + + var/client/real_client = client_by_ckey(closed_by.ckey) + if(status == TICKET_ASSIGNED && (!real_client || !real_client.holder)) // non-admins can only close a ticket if no admin has taken it + return + + src.status = TICKET_CLOSED + src.closed_by = closed_by + + to_chat(client_by_ckey(src.owner.ckey), "Your ticket has been closed by [closed_by.ckey].") + message_staff("[src.owner.key_name(0)]'s ticket has been closed by [closed_by.key_name(0)].") + send2adminirc("[src.owner.key_name(0)]'s ticket has been closed by [closed_by.key_name(0)].") + + update_ticket_panels() + + return 1 + +/datum/ticket/proc/take(var/datum/client_lite/assigned_admin) + if(status == TICKET_CLOSED) + return + + if(assigned_admin.ckey == owner.ckey) + return + + if(status == TICKET_ASSIGNED && ((assigned_admin.ckey in assigned_admin_ckeys()) || alert(client_by_ckey(assigned_admin.ckey), "This ticket is already assigned. Do you want to add yourself to the ticket?", "Join ticket?" , "Yes" , "No") != "Yes")) + return + + assigned_admins |= assigned_admin + src.status = TICKET_ASSIGNED + + message_staff("[assigned_admin.key_name(0)] has assigned themself to [src.owner.key_name(0)]'s ticket.") + send2adminirc("[assigned_admin.key_name(0)] has assigned themself to [src.owner.key_name(0)]'s ticket.") + to_chat(client_by_ckey(src.owner.ckey), "[assigned_admin.ckey] has added themself to your ticket and should respond shortly. Thanks for your patience!") + + update_ticket_panels() + + return 1 + +/datum/ticket/proc/assigned_admin_ckeys() + . = list() + + for(var/datum/client_lite/assigned_admin in assigned_admins) + . |= assigned_admin.ckey + +proc/get_open_ticket_by_client(var/datum/client_lite/owner) + for(var/datum/ticket/ticket in tickets) + if(ticket.owner.ckey == owner.ckey && (ticket.status == TICKET_OPEN || ticket.status == TICKET_ASSIGNED)) + return ticket // there should only be one open ticket by a client at a time, so no need to keep looking + +/datum/ticket/proc/is_active() + if(status != TICKET_ASSIGNED) + return 0 + + for(var/datum/client_lite/admin in assigned_admins) + var/client/admin_client = client_by_ckey(admin.ckey) + if(admin_client && !admin_client.is_afk()) + return 1 + + return 0 + +/datum/ticket_msg + var/msg_from + var/msg_to + var/msg + var/time_stamp + +/datum/ticket_msg/New(var/msg_from, var/msg_to, var/msg) + src.msg_from = msg_from + src.msg_to = msg_to + src.msg = msg + src.time_stamp = time_stamp() + +/datum/ticket_panel + var/datum/ticket/open_ticket = null + var/datum/browser/ticket_panel_window + +/datum/ticket_panel/proc/get_dat() + var/client/C = ticket_panel_window.user.client + if(!C) + return + + var/list/dat = list() + + var/list/ticket_dat = list() + for(var/id = tickets.len, id >= 1, id--) + var/datum/ticket/ticket = tickets[id] + if(C.holder || ticket.owner.ckey == C.ckey) + var/client/owner_client = client_by_ckey(ticket.owner.ckey) + var/open = 0 + var/status = "Unknown status" + var/color = "#6aa84f" + switch(ticket.status) + if(TICKET_OPEN) + open = 1 + status = "Opened [round((world.time - ticket.opened_time) / (1 MINUTE))] minute\s ago, unassigned" + if(TICKET_ASSIGNED) + open = 2 + status = "Assigned to [english_list(ticket.assigned_admin_ckeys(), "no one")]" + color = "#ffffff" + if(TICKET_CLOSED) + status = "Closed by [ticket.closed_by.ckey]" + color = "#cc2222" + ticket_dat += "
          • " + if(open_ticket && open_ticket == ticket) + ticket_dat += "" + ticket_dat += "Ticket #[id] - [ticket.owner.ckey] [owner_client ? "" : "(DC)"] - [status]
            VIEW" + if(open) + ticket_dat += " - PM" + if(C.holder) + ticket_dat += " - [(open == 1) ? "TAKE" : "JOIN"]" + if(ticket.status != TICKET_CLOSED && (C.holder || ticket.status == TICKET_OPEN)) + ticket_dat += " - CLOSE" + if(C.holder) + var/ref_mob = "" + if(owner_client) + ref_mob = "\ref[owner_client.mob]" + ticket_dat += " - ? - PP - VV - SM[owner_client ? "- [admin_jump_link(owner_client, src)]" : ""]" + if(open_ticket && open_ticket == ticket) + ticket_dat += "
            " + ticket_dat += "
          • " + + if(ticket_dat.len) + dat += "

            Available tickets:

              [jointext(ticket_dat, null)]
            " + + if(open_ticket) + dat += "

            \[X\] Messages for ticket #[open_ticket.id]:

            " + + var/list/msg_dat = list() + for(var/datum/ticket_msg/msg in open_ticket.msgs) + var/msg_to = msg.msg_to ? msg.msg_to : "Adminhelp" + msg_dat += "
          • \[[msg.time_stamp]\] [msg.msg_from] -> [msg_to]: [C.holder ? generate_ahelp_key_words(C.mob, msg.msg) : msg.msg]
          • " + + if(msg_dat.len) + dat += "
              [jointext(msg_dat, null)]
            " + else + dat += "

            No messages to display.

            " + else + dat += "

            No tickets to display.

            " + dat += "" + + return jointext(dat, null) + +/datum/ticket_panel/Topic(href, href_list) + if(usr && usr != ticket_panel_window.user) + if(href_list["close"]) // catch the case where a user switches mobs, then closes the window that was linked to the old mob + ticket_panels -= usr.client + else + usr.client.view_tickets() + var/datum/ticket_panel/new_panel = ticket_panels[usr.client] + new_panel.open_ticket = open_ticket + new_panel.Topic(href, href_list) + return + + ..() + + if(href_list["close"]) + ticket_panels -= usr.client + + switch(href_list["action"]) + if("unview") + open_ticket = null + ticket_panel_window.set_content(get_dat()) + ticket_panel_window.update() + + var/datum/ticket/ticket = locate(href_list["ticket"]) + if(!ticket) + return + + switch(href_list["action"]) + if("view") + open_ticket = ticket + ticket_panel_window.set_content(get_dat()) + ticket_panel_window.update() + if("take") + ticket.take(client_repository.get_lite_client(usr.client)) + if("close") + ticket.close(client_repository.get_lite_client(usr.client)) + if("pm") + if(usr.client.holder && ticket.owner.ckey != usr.ckey) + usr.client.cmd_admin_pm(client_by_ckey(ticket.owner.ckey), ticket = ticket) + else if(ticket.status == TICKET_ASSIGNED) + // manually check that the target client exists here as to not spam the usr for each logged out admin on the ticket + var/admin_found = 0 + for(var/datum/client_lite/admin in ticket.assigned_admins) + var/client/admin_client = client_by_ckey(admin.ckey) + if(admin_client) + admin_found = 1 + usr.client.cmd_admin_pm(admin_client, ticket = ticket) + break + if(!admin_found) + to_chat(usr, "Error: Private-Message: Client not found. They may have lost connection, so please be patient!") + else + usr.client.adminhelp(input(usr,"", "adminhelp \"text\"") as text) + +/client/verb/view_tickets() + set name = "View Tickets" + set category = "Admin" + + var/datum/ticket_panel/ticket_panel = new() + ticket_panels[src] = ticket_panel + ticket_panel.ticket_panel_window = new(src.mob, "ticketpanel", "Ticket Manager", 1024, 768, ticket_panel) + + ticket_panel.ticket_panel_window.set_content(ticket_panel.get_dat()) + ticket_panel.ticket_panel_window.open() + +/proc/update_ticket_panels() + for(var/client/C in ticket_panels) + var/datum/ticket_panel/ticket_panel = ticket_panels[C] + if(C.mob != ticket_panel.ticket_panel_window.user) + C.view_tickets() + else + ticket_panel.ticket_panel_window.set_content(ticket_panel.get_dat()) + ticket_panel.ticket_panel_window.update() \ No newline at end of file diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm new file mode 100644 index 00000000..c83cfbc1 --- /dev/null +++ b/code/modules/admin/topic.dm @@ -0,0 +1,2031 @@ +/datum/admins/Topic(href, href_list) + ..() + + if(usr.client != src.owner || !check_rights(0)) + log_admin("[key_name(usr)] tried to use the admin panel without authorization.") + message_admins("[usr.key] has attempted to override the admin panel!") + return + + if(ticker.mode && ticker.mode.check_antagonists_topic(href, href_list)) + check_antagonists() + return + + if(href_list["dbsearchckey"] || href_list["dbsearchadmin"]) + + var/adminckey = href_list["dbsearchadmin"] + var/playerckey = href_list["dbsearchckey"] + var/playerip = href_list["dbsearchip"] + var/playercid = href_list["dbsearchcid"] + var/dbbantype = text2num(href_list["dbsearchbantype"]) + var/match = 0 + + if("dbmatch" in href_list) + match = 1 + + DB_ban_panel(playerckey, adminckey, playerip, playercid, dbbantype, match) + return + + else if(href_list["dbbanedit"]) + var/banedit = href_list["dbbanedit"] + var/banid = text2num(href_list["dbbanid"]) + if(!banedit || !banid) + return + + DB_ban_edit(banid, banedit) + return + + else if(href_list["dbbanaddtype"]) + + var/bantype = text2num(href_list["dbbanaddtype"]) + var/banckey = href_list["dbbanaddckey"] + var/banip = href_list["dbbanaddip"] + var/bancid = href_list["dbbanaddcid"] + var/banduration = text2num(href_list["dbbaddduration"]) + var/banjob = href_list["dbbanaddjob"] + var/banreason = href_list["dbbanreason"] + + banckey = ckey(banckey) + + switch(bantype) + if(BANTYPE_PERMA) + if(!banckey || !banreason) + to_chat(usr, "Not enough parameters (Requires ckey and reason)") + return + banduration = null + banjob = null + if(BANTYPE_TEMP) + if(!banckey || !banreason || !banduration) + to_chat(usr, "Not enough parameters (Requires ckey, reason and duration)") + return + banjob = null + if(BANTYPE_JOB_PERMA) + if(!banckey || !banreason || !banjob) + to_chat(usr, "Not enough parameters (Requires ckey, reason and job)") + return + banduration = null + if(BANTYPE_JOB_TEMP) + if(!banckey || !banreason || !banjob || !banduration) + to_chat(usr, "Not enough parameters (Requires ckey, reason and job)") + return + + var/mob/playermob + + for(var/mob/M in GLOB.player_list) + if(M.ckey == banckey) + playermob = M + break + + + banreason = "(MANUAL BAN) "+banreason + + if(!playermob) + if(banip) + banreason = "[banreason] (CUSTOM IP)" + if(bancid) + banreason = "[banreason] (CUSTOM CID)" + else + message_admins("Ban process: A mob matching [playermob.ckey] was found at location [playermob.x], [playermob.y], [playermob.z]. Custom ip and computer id fields replaced with the ip and computer id from the located mob") + notes_add(banckey,banreason,usr) + + DB_ban_record(bantype, playermob, banduration, banreason, banjob, null, banckey, banip, bancid ) + + else if(href_list["editrights"]) + if(!check_rights(R_PERMISSIONS)) + message_admins("[key_name_admin(usr)] attempted to edit the admin permissions without sufficient rights.") + log_admin("[key_name(usr)] attempted to edit the admin permissions without sufficient rights.") + return + + var/adm_ckey + + var/task = href_list["editrights"] + if(task == "add") + var/new_ckey = ckey(input(usr,"New admin's ckey","Admin ckey", null) as text|null) + if(!new_ckey) return + if(new_ckey in admin_datums) + to_chat(usr, "Error: Topic 'editrights': [new_ckey] is already an admin") + return + adm_ckey = new_ckey + task = "rank" + else if(task != "show") + adm_ckey = ckey(href_list["ckey"]) + if(!adm_ckey) + to_chat(usr, "Error: Topic 'editrights': No valid ckey") + return + + var/datum/admins/D = admin_datums[adm_ckey] + + if(task == "remove") + if(alert("Are you sure you want to remove [adm_ckey]?","Message","Yes","Cancel") == "Yes") + if(!D) return + admin_datums -= adm_ckey + D.disassociate() + + message_admins("[key_name_admin(usr)] removed [adm_ckey] from the admins list") + log_admin("[key_name(usr)] removed [adm_ckey] from the admins list") + log_admin_rank_modification(adm_ckey, "Removed") + + else if(task == "rank") + var/new_rank + if(admin_ranks.len) + new_rank = input("Please select a rank", "New rank", null, null) as null|anything in (admin_ranks|"*New Rank*") + else + new_rank = input("Please select a rank", "New rank", null, null) as null|anything in list("Game Master","Game Admin", "Trial Admin", "Admin Observer","*New Rank*") + + var/rights = 0 + if(D) + rights = D.rights + switch(new_rank) + if(null,"") return + if("*New Rank*") + new_rank = input("Please input a new rank", "New custom rank", null, null) as null|text + if(config.admin_legacy_system) + new_rank = ckeyEx(new_rank) + if(!new_rank) + to_chat(usr, "Error: Topic 'editrights': Invalid rank") + return + if(config.admin_legacy_system) + if(admin_ranks.len) + if(new_rank in admin_ranks) + rights = admin_ranks[new_rank] //we typed a rank which already exists, use its rights + else + admin_ranks[new_rank] = 0 //add the new rank to admin_ranks + else + if(config.admin_legacy_system) + new_rank = ckeyEx(new_rank) + rights = admin_ranks[new_rank] //we input an existing rank, use its rights + + if(D) + D.disassociate() //remove adminverbs and unlink from client + D.rank = new_rank //update the rank + D.rights = rights //update the rights based on admin_ranks (default: 0) + else + D = new /datum/admins(new_rank, rights, adm_ckey) + + var/client/C = GLOB.ckey_directory[adm_ckey] //find the client with the specified ckey (if they are logged in) + D.associate(C) //link up with the client and add verbs + + to_chat(C, "[key_name_admin(usr)] has set your admin rank to: [new_rank].") + message_admins("[key_name_admin(usr)] edited the admin rank of [adm_ckey] to [new_rank]") + log_admin("[key_name(usr)] edited the admin rank of [adm_ckey] to [new_rank]") + log_admin_rank_modification(adm_ckey, new_rank) + + else if(task == "permissions") + if(!D) return + var/list/permissionlist = list() + for(var/i=1, i<=R_MAXPERMISSION, i<<=1) //that <<= is shorthand for i = i << 1. Which is a left bitshift + permissionlist[rights2text(i)] = i + var/new_permission = input("Select a permission to turn on/off", "Permission toggle", null, null) as null|anything in permissionlist + if(!new_permission) return + D.rights ^= permissionlist[new_permission] + + var/client/C = GLOB.ckey_directory[adm_ckey] + to_chat(C, "[key_name_admin(usr)] has toggled your permission: [new_permission].") + message_admins("[key_name_admin(usr)] toggled the [new_permission] permission of [adm_ckey]") + log_admin("[key_name(usr)] toggled the [new_permission] permission of [adm_ckey]") + log_admin_permission_modification(adm_ckey, permissionlist[new_permission]) + + edit_admin_permissions() + + else if(href_list["call_shuttle"]) + + if(!check_rights(R_ADMIN)) return + + if (!ticker || !evacuation_controller) + return + + if( ticker.mode.name == "blob" ) + alert("You can't call the shuttle during blob!") + return + + switch(href_list["call_shuttle"]) + if("1") + if (evacuation_controller.call_evacuation(usr, TRUE)) + log_and_message_admins("called an evacuation.") + if("2") + if (evacuation_controller.cancel_evacuation()) + log_and_message_admins("cancelled an evacuation.") + + href_list["secretsadmin"] = "check_antagonist" + + else if(href_list["delay_round_end"]) + if(!check_rights(R_SERVER)) return + + ticker.delay_end = !ticker.delay_end + log_and_message_admins("[ticker.delay_end ? "delayed the round end" : "has made the round end normally"].") + href_list["secretsadmin"] = "check_antagonist" + + else if(href_list["simplemake"]) + + if(!check_rights(R_SPAWN)) return + + var/mob/M = locate(href_list["mob"]) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + var/delmob = 0 + switch(alert("Delete old mob?","Message","Yes","No","Cancel")) + if("Cancel") return + if("Yes") delmob = 1 + + log_and_message_admins("has used rudimentary transformation on [key_name_admin(M)]. Transforming to [href_list["simplemake"]]; deletemob=[delmob]") + + switch(href_list["simplemake"]) + if("observer") M.change_mob_type( /mob/observer/ghost , null, null, delmob ) + if("human") M.change_mob_type( /mob/living/carbon/human , null, null, delmob, href_list["species"]) + if("slime") M.change_mob_type( /mob/living/carbon/slime , null, null, delmob ) + if("monkey") M.change_mob_type( /mob/living/carbon/human/monkey , null, null, delmob ) + if("robot") M.change_mob_type( /mob/living/silicon/robot , null, null, delmob ) + if("cat") M.change_mob_type( /mob/living/simple_animal/cat , null, null, delmob ) + if("runtime") M.change_mob_type( /mob/living/simple_animal/cat/fluff/Runtime , null, null, delmob ) + if("corgi") M.change_mob_type( /mob/living/simple_animal/corgi , null, null, delmob ) + if("ian") M.change_mob_type( /mob/living/simple_animal/corgi/Ian , null, null, delmob ) + if("crab") M.change_mob_type( /mob/living/simple_animal/crab , null, null, delmob ) + if("coffee") M.change_mob_type( /mob/living/simple_animal/crab/Coffee , null, null, delmob ) + if("parrot") M.change_mob_type( /mob/living/simple_animal/parrot , null, null, delmob ) + if("polyparrot") M.change_mob_type( /mob/living/simple_animal/parrot/Poly , null, null, delmob ) + if("constructarmoured") M.change_mob_type( /mob/living/simple_animal/construct/armoured , null, null, delmob ) + if("constructbuilder") M.change_mob_type( /mob/living/simple_animal/construct/builder , null, null, delmob ) + if("constructwraith") M.change_mob_type( /mob/living/simple_animal/construct/wraith , null, null, delmob ) + if("shade") M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob ) + + + /////////////////////////////////////new ban stuff + else if(href_list["unbanf"]) + if(!check_rights(R_BAN)) return + + var/banfolder = href_list["unbanf"] + Banlist.cd = "/base/[banfolder]" + var/key = Banlist["key"] + if(alert(usr, "Are you sure you want to unban [key]?", "Confirmation", "Yes", "No") == "Yes") + if(RemoveBan(banfolder)) + unbanpanel() + else + alert(usr, "This ban has already been lifted / does not exist.", "Error", "Ok") + unbanpanel() + + else if(href_list["warn"]) + usr.client.warn(href_list["warn"]) + + else if(href_list["unbane"]) + if(!check_rights(R_BAN)) return + + UpdateTime() + var/reason + + var/banfolder = href_list["unbane"] + Banlist.cd = "/base/[banfolder]" + var/reason2 = Banlist["reason"] + var/temp = Banlist["temp"] + + var/minutes = Banlist["minutes"] + + var/banned_key = Banlist["key"] + Banlist.cd = "/base" + + var/duration + + switch(alert("Temporary Ban?",,"Yes","No")) + if("Yes") + temp = 1 + var/mins = 0 + if(minutes > CMinutes) + mins = minutes - CMinutes + mins = input(usr,"How long (in minutes)? (Default: 1440)","Ban time",mins ? mins : 1440) as num|null + if(!mins) return + mins = min(525599,mins) + minutes = CMinutes + mins + duration = GetExp(minutes) + reason = sanitize(input(usr,"Reason?","reason",reason2) as text|null) + if(!reason) return + if("No") + temp = 0 + duration = "Perma" + reason = sanitize(input(usr,"Reason?","reason",reason2) as text|null) + if(!reason) return + + ban_unban_log_save("[key_name(usr)] edited [banned_key]'s ban. Reason: [reason] Duration: [duration]") + log_and_message_admins("edited [banned_key]'s ban. Reason: [reason] Duration: [duration]") + Banlist.cd = "/base/[banfolder]" + Banlist["reason"] << reason + Banlist["temp"] << temp + Banlist["minutes"] << minutes + Banlist["bannedby"] << usr.ckey + Banlist.cd = "/base" + feedback_inc("ban_edit",1) + unbanpanel() + + /////////////////////////////////////new ban stuff + + else if(href_list["jobban2"]) +// if(!check_rights(R_BAN)) return + + var/mob/M = locate(href_list["jobban2"]) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + if(!M.ckey) //sanity + to_chat(usr, "This mob has no ckey") + return + if(!job_master) + to_chat(usr, "Job Master has not been setup!") + return + + var/dat = "" + var/header = "Job-Ban Panel: [M.name]" + var/body + var/jobs = "" + + /***********************************WARNING!************************************ + The jobban stuff looks mangled and disgusting + But it looks beautiful in-game + -Nodrak + ************************************WARNING!***********************************/ + var/counter = 0 +//Regular jobs + //Command (Blue) + jobs += "" + jobs += "" + for(var/jobPos in GLOB.command_positions) + if(!jobPos) continue + var/datum/job/job = job_master.GetJob(jobPos) + if(!job) continue + + if(jobban_isbanned(M, job.title)) + jobs += "" + counter++ + else + jobs += "" + counter++ + + if(counter >= 6) //So things dont get squiiiiished! + jobs += "" + counter = 0 + jobs += "
            Command Positions
            [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
            " + + //Command Support (Sky Blue) + jobs += "" + jobs += "" + for(var/jobPos in GLOB.support_positions) + if(!jobPos) continue + var/datum/job/job = job_master.GetJob(jobPos) + if(!job) continue + + if(jobban_isbanned(M, job.title)) + jobs += "" + counter++ + else + jobs += "" + counter++ + + if(counter >= 6) //So things dont get squiiiiished! + jobs += "" + counter = 0 + jobs += "
            Command Support Positions
            [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
            " + + //Security (Red) + counter = 0 + jobs += "" + jobs += "" + for(var/jobPos in GLOB.security_positions) + if(!jobPos) continue + var/datum/job/job = job_master.GetJob(jobPos) + if(!job) continue + + if(jobban_isbanned(M, job.title)) + jobs += "" + counter++ + else + jobs += "" + counter++ + + if(counter >= 5) //So things dont get squiiiiished! + jobs += "" + counter = 0 + jobs += "
            Security Positions
            [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
            " + + //Engineering (Yellow) + counter = 0 + jobs += "" + jobs += "" + for(var/jobPos in GLOB.engineering_positions) + if(!jobPos) continue + var/datum/job/job = job_master.GetJob(jobPos) + if(!job) continue + + if(jobban_isbanned(M, job.title)) + jobs += "" + counter++ + else + jobs += "" + counter++ + + if(counter >= 5) //So things dont get squiiiiished! + jobs += "" + counter = 0 + jobs += "
            Engineering Positions
            [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
            " + + //Medical (White) + counter = 0 + jobs += "" + jobs += "" + for(var/jobPos in GLOB.medical_positions) + if(!jobPos) continue + var/datum/job/job = job_master.GetJob(jobPos) + if(!job) continue + + if(jobban_isbanned(M, job.title)) + jobs += "" + counter++ + else + jobs += "" + counter++ + + if(counter >= 5) //So things dont get squiiiiished! + jobs += "" + counter = 0 + jobs += "
            Medical Positions
            [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
            " + + //Science (Purple) + counter = 0 + jobs += "" + jobs += "" + for(var/jobPos in GLOB.science_positions) + if(!jobPos) continue + var/datum/job/job = job_master.GetJob(jobPos) + if(!job) continue + + if(jobban_isbanned(M, job.title)) + jobs += "" + counter++ + else + jobs += "" + counter++ + + if(counter >= 5) //So things dont get squiiiiished! + jobs += "" + counter = 0 + jobs += "
            Science Positions
            [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
            " + + //Exploration (Pale Purple) + jobs += "" + jobs += "" + for(var/jobPos in GLOB.exploration_positions) + if(!jobPos) continue + var/datum/job/job = job_master.GetJob(jobPos) + if(!job) continue + + if(jobban_isbanned(M, job.title)) + jobs += "" + counter++ + else + jobs += "" + counter++ + + if(counter >= 6) //So things dont get squiiiiished! + jobs += "" + counter = 0 + jobs += "
            Exploration Positions
            [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
            " + + //Service (Tea Green) + jobs += "" + jobs += "" + for(var/jobPos in GLOB.service_positions) + if(!jobPos) continue + var/datum/job/job = job_master.GetJob(jobPos) + if(!job) continue + + if(jobban_isbanned(M, job.title)) + jobs += "" + counter++ + else + jobs += "" + counter++ + + if(counter >= 6) //So things dont get squiiiiished! + jobs += "" + counter = 0 + jobs += "
            Service Positions
            [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
            " + + + //Supply (Khaki) + jobs += "" + jobs += "" + for(var/jobPos in GLOB.supply_positions) + if(!jobPos) continue + var/datum/job/job = job_master.GetJob(jobPos) + if(!job) continue + + if(jobban_isbanned(M, job.title)) + jobs += "" + counter++ + else + jobs += "" + counter++ + + if(counter >= 6) //So things dont get squiiiiished! + jobs += "" + counter = 0 + jobs += "
            Supply Positions
            [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
            " + + //Civilian (Grey) + counter = 0 + jobs += "" + jobs += "" + for(var/jobPos in GLOB.civilian_positions) + if(!jobPos) continue + var/datum/job/job = job_master.GetJob(jobPos) + if(!job) continue + + if(jobban_isbanned(M, job.title)) + jobs += "" + counter++ + else + jobs += "" + counter++ + + if(counter >= 5) //So things dont get squiiiiished! + jobs += "" + counter = 0 + + if(jobban_isbanned(M, "Internal Affairs Agent")) + jobs += "" + else + jobs += "" + + jobs += "
            Civilian Positions
            [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
            Internal Affairs AgentInternal Affairs Agent
            " + + //Non-Human (Green) + counter = 0 + jobs += "" + jobs += "" + for(var/jobPos in GLOB.nonhuman_positions) + if(!jobPos) continue + var/datum/job/job = job_master.GetJob(jobPos) + if(!job) continue + + if(jobban_isbanned(M, job.title)) + jobs += "" + counter++ + else + jobs += "" + counter++ + + if(counter >= 5) //So things dont get squiiiiished! + jobs += "" + counter = 0 + + //pAI isn't technically a job, but it goes in here. + + if(jobban_isbanned(M, "pAI")) + jobs += "" + else + jobs += "" + if(jobban_isbanned(M, "AntagHUD")) + jobs += "" + else + jobs += "" + jobs += "
            Non-human Positions
            [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
            pAIpAIAntagHUDAntagHUD
            " + + //Antagonist (Orange) + jobs += "" + jobs += "" + + // Antagonists. + var/list/all_antag_types = all_antag_types() + for(var/antag_type in all_antag_types) + var/datum/antagonist/antag = all_antag_types[antag_type] + if(!antag || !antag.id) + continue + if(jobban_isbanned(M, "[antag.id]")) + jobs += "" + else + jobs += "" + + jobs += "
            Antagonist Positions
            [replacetext("[antag.role_text]", " ", " ")][replacetext("[antag.role_text]", " ", " ")]
            " + + //Other races (BLUE, because I have no idea what other color to make this) + jobs += "" + jobs += "" + + if(jobban_isbanned(M, "Dionaea")) + jobs += "" + else + jobs += "" + jobs += "
            Other Races
            DionaeaDionaea
            " + body = "[jobs]" + dat = "[header][body]" + usr << browse(dat, "window=jobban2;size=800x490") + return + + //JOBBAN'S INNARDS + else if(href_list["jobban3"]) + if(!check_rights(R_MOD,0) && !check_rights(R_ADMIN,0)) + to_chat(usr, "You do not have the appropriate permissions to add job bans!") + return + + if(check_rights(R_MOD,0) && !check_rights(R_ADMIN,0) && !config.mods_can_job_tempban) // If mod and tempban disabled + to_chat(usr, "Mod jobbanning is disabled!") + return + + var/mob/M = locate(href_list["jobban4"]) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + if(M != usr) //we can jobban ourselves + if(M.client && M.client.holder && (M.client.holder.rights & R_BAN)) //they can ban too. So we can't ban them + alert("You cannot perform this action. You must be of a higher administrative rank!") + return + + if(!job_master) + to_chat(usr, "Job Master has not been setup!") + return + + //get jobs for department if specified, otherwise just returnt he one job in a list. + var/list/joblist = list() + switch(href_list["jobban3"]) + if("commanddept") + for(var/jobPos in GLOB.command_positions) + if(!jobPos) continue + var/datum/job/temp = job_master.GetJob(jobPos) + if(!temp) continue + joblist += temp.title + if("supportdept") + for(var/jobPos in GLOB.support_positions) + if(!jobPos) continue + var/datum/job/temp = job_master.GetJob(jobPos) + if(!temp) continue + joblist += temp.title + if("securitydept") + for(var/jobPos in GLOB.security_positions) + if(!jobPos) continue + var/datum/job/temp = job_master.GetJob(jobPos) + if(!temp) continue + joblist += temp.title + if("engineeringdept") + for(var/jobPos in GLOB.engineering_positions) + if(!jobPos) continue + var/datum/job/temp = job_master.GetJob(jobPos) + if(!temp) continue + joblist += temp.title + if("medicaldept") + for(var/jobPos in GLOB.medical_positions) + if(!jobPos) continue + var/datum/job/temp = job_master.GetJob(jobPos) + if(!temp) continue + joblist += temp.title + if("sciencedept") + for(var/jobPos in GLOB.science_positions) + if(!jobPos) continue + var/datum/job/temp = job_master.GetJob(jobPos) + if(!temp) continue + joblist += temp.title + if("explorationdept") + for(var/jobPos in GLOB.exploration_positions) + if(!jobPos) continue + var/datum/job/temp = job_master.GetJob(jobPos) + if(!temp) continue + joblist += temp.title + if("servicedept") + for(var/jobPos in GLOB.service_positions) + if(!jobPos) continue + var/datum/job/temp = job_master.GetJob(jobPos) + if(!temp) continue + joblist += temp.title + if("supplydept") + for(var/jobPos in GLOB.supply_positions) + if(!jobPos) continue + var/datum/job/temp = job_master.GetJob(jobPos) + if(!temp) continue + joblist += temp.title + if("civiliandept") + for(var/jobPos in GLOB.civilian_positions) + if(!jobPos) continue + var/datum/job/temp = job_master.GetJob(jobPos) + if(!temp) continue + joblist += temp.title + if("nonhumandept") + joblist += "pAI" + for(var/jobPos in GLOB.nonhuman_positions) + if(!jobPos) continue + var/datum/job/temp = job_master.GetJob(jobPos) + if(!temp) continue + joblist += temp.title + if("Syndicate") + var/list/all_antag_types = all_antag_types() + for(var/antagPos in all_antag_types) + if(!antagPos) continue + var/datum/antagonist/temp = all_antag_types[antagPos] + if(!temp) continue + joblist += temp.id + else + joblist += href_list["jobban3"] + + //Create a list of unbanned jobs within joblist + var/list/notbannedlist = list() + for(var/job in joblist) + if(!jobban_isbanned(M, job)) + notbannedlist += job + + //Banning comes first + if(notbannedlist.len) //at least 1 unbanned job exists in joblist so we have stuff to ban. + switch(alert("Temporary Ban?",,"Yes","No", "Cancel")) + if("Yes") + if(!check_rights(R_MOD,0) && !check_rights(R_BAN, 0)) + to_chat(usr, " You Cannot issue temporary job-bans!") + return + if(config.ban_legacy_system) + to_chat(usr, "Your server is using the legacy banning system, which does not support temporary job bans. Consider upgrading. Aborting ban.") + return + var/mins = input(usr,"How long (in minutes)?","Ban time",1440) as num|null + if(!mins) + return + if(check_rights(R_MOD, 0) && !check_rights(R_BAN, 0) && mins > config.mod_job_tempban_max) + to_chat(usr, " Moderators can only job tempban up to [config.mod_job_tempban_max] minutes!") + return + var/reason = sanitize(input(usr,"Reason?","Please State Reason","") as text|null) + if(!reason) + return + + var/msg + for(var/job in notbannedlist) + ban_unban_log_save("[key_name(usr)] temp-jobbanned [key_name(M)] from [job] for [mins] minutes. reason: [reason]") + log_admin("[key_name(usr)] temp-jobbanned [key_name(M)] from [job] for [mins] minutes") + feedback_inc("ban_job_tmp",1) + DB_ban_record(BANTYPE_JOB_TEMP, M, mins, reason, job) + feedback_add_details("ban_job_tmp","- [job]") + jobban_fullban(M, job, "[reason]; By [usr.ckey] on [time2text(world.realtime)]") //Legacy banning does not support temporary jobbans. + if(!msg) + msg = job + else + msg += ", [job]" + notes_add(M.ckey, "Banned from [msg] - [reason]", usr) + message_admins("[key_name_admin(usr)] banned [key_name_admin(M)] from [msg] for [mins] minutes", 1) + to_chat(M, "You have been jobbanned by [usr.client.ckey] from: [msg].") + to_chat(M, "The reason is: [reason]") + to_chat(M, "This jobban will be lifted in [mins] minutes.") + href_list["jobban2"] = 1 // lets it fall through and refresh + return 1 + if("No") + if(!check_rights(R_BAN)) return + var/reason = sanitize(input(usr,"Reason?","Please State Reason","") as text|null) + if(reason) + var/msg + for(var/job in notbannedlist) + ban_unban_log_save("[key_name(usr)] perma-jobbanned [key_name(M)] from [job]. reason: [reason]") + log_admin("[key_name(usr)] perma-banned [key_name(M)] from [job]") + feedback_inc("ban_job",1) + DB_ban_record(BANTYPE_JOB_PERMA, M, -1, reason, job) + feedback_add_details("ban_job","- [job]") + jobban_fullban(M, job, "[reason]; By [usr.ckey] on [time2text(world.realtime)]") + if(!msg) msg = job + else msg += ", [job]" + notes_add(M.ckey, "Banned from [msg] - [reason]", usr) + message_admins("[key_name_admin(usr)] banned [key_name_admin(M)] from [msg]", 1) + to_chat(M, "You have been jobbanned by [usr.client.ckey] from: [msg].") + to_chat(M, "The reason is: [reason]") + to_chat(M, "Jobban can be lifted only upon request.") + href_list["jobban2"] = 1 // lets it fall through and refresh + return 1 + if("Cancel") + return + + //Unbanning joblist + //all jobs in joblist are banned already OR we didn't give a reason (implying they shouldn't be banned) + if(joblist.len) //at least 1 banned job exists in joblist so we have stuff to unban. + if(!config.ban_legacy_system) + to_chat(usr, "Unfortunately, database based unbanning cannot be done through this panel") + DB_ban_panel(M.ckey) + return + var/msg + for(var/job in joblist) + var/reason = jobban_isbanned(M, job) + if(!reason) continue //skip if it isn't jobbanned anyway + switch(alert("Job: '[job]' Reason: '[reason]' Un-jobban?","Please Confirm","Yes","No")) + if("Yes") + ban_unban_log_save("[key_name(usr)] unjobbanned [key_name(M)] from [job]") + log_admin("[key_name(usr)] unbanned [key_name(M)] from [job]") + DB_ban_unban(M.ckey, BANTYPE_JOB_PERMA, job) + feedback_inc("ban_job_unban",1) + feedback_add_details("ban_job_unban","- [job]") + jobban_unban(M, job) + if(!msg) msg = job + else msg += ", [job]" + else + continue + if(msg) + message_admins("[key_name_admin(usr)] unbanned [key_name_admin(M)] from [msg]", 1) + to_chat(M, "You have been un-jobbanned by [usr.client.ckey] from [msg].") + href_list["jobban2"] = 1 // lets it fall through and refresh + return 1 + return 0 //we didn't do anything! + + else if(href_list["boot2"]) + var/mob/M = locate(href_list["boot2"]) + if (ismob(M)) + if(!check_if_greater_rights_than(M.client)) + return + var/reason = sanitize(input("Please enter reason")) + if(!reason) + to_chat(M, "You have been kicked from the server") + else + to_chat(M, "You have been kicked from the server: [reason]") + log_and_message_admins("booted [key_name_admin(M)].") + //M.client = null + qdel(M.client) + + else if(href_list["removejobban"]) + if(!check_rights(R_BAN)) return + + var/t = href_list["removejobban"] + if(t) + if((alert("Do you want to unjobban [t]?","Unjobban confirmation", "Yes", "No") == "Yes") && t) //No more misclicks! Unless you do it twice. + log_and_message_admins("[key_name_admin(usr)] removed [t]") + jobban_remove(t) + href_list["ban"] = 1 // lets it fall through and refresh + var/t_split = splittext(t, " - ") + var/key = t_split[1] + var/job = t_split[2] + DB_ban_unban(ckey(key), BANTYPE_JOB_PERMA, job) + + else if(href_list["newban"]) + if(!check_rights(R_MOD,0) && !check_rights(R_BAN, 0)) + to_chat(usr, "You do not have the appropriate permissions to add bans!") + return + + if(check_rights(R_MOD,0) && !check_rights(R_ADMIN, 0) && !config.mods_can_job_tempban) // If mod and tempban disabled + to_chat(usr, "Mod jobbanning is disabled!") + return + + var/mob/M = locate(href_list["newban"]) + if(!ismob(M)) return + + if(M.client && M.client.holder) return //admins cannot be banned. Even if they could, the ban doesn't affect them anyway + + switch(alert("Temporary Ban?",,"Yes","No", "Cancel")) + if("Yes") + var/mins = input(usr,"How long (in minutes)?","Ban time",1440) as num|null + if(!mins) + return + if(check_rights(R_MOD, 0) && !check_rights(R_BAN, 0) && mins > config.mod_tempban_max) + to_chat(usr, "Moderators can only job tempban up to [config.mod_tempban_max] minutes!") + return + if(mins >= 525600) mins = 525599 + var/reason = sanitize(input(usr,"Reason?","reason","Griefer") as text|null) + if(!reason) + return + AddBan(M.ckey, M.computer_id, reason, usr.ckey, 1, mins) + ban_unban_log_save("[usr.client.ckey] has banned [M.ckey]. - Reason: [reason] - This will be removed in [mins] minutes.") + notes_add(M.ckey,"[usr.client.ckey] has banned [M.ckey]. - Reason: [reason] - This will be removed in [mins] minutes.",usr) + to_chat(M, "You have been banned by [usr.client.ckey].\nReason: [reason].") + to_chat(M, "This is a temporary ban, it will be removed in [mins] minutes.") + feedback_inc("ban_tmp",1) + DB_ban_record(BANTYPE_TEMP, M, mins, reason) + feedback_inc("ban_tmp_mins",mins) + if(config.banappeals) + to_chat(M, "To try to resolve this matter head to [config.banappeals]") + else + to_chat(M, "No ban appeals URL has been set.") + log_and_message_admins("has banned [M.ckey].\nReason: [reason]\nThis will be removed in [mins] minutes.") + + qdel(M.client) + //qdel(M) // See no reason why to delete mob. Important stuff can be lost. And ban can be lifted before round ends. + if("No") + if(!check_rights(R_BAN)) return + var/reason = sanitize(input(usr,"Reason?","reason","Griefer") as text|null) + if(!reason) + return + switch(alert(usr,"IP ban?",,"Yes","No","Cancel")) + if("Cancel") return + if("Yes") + AddBan(M.ckey, M.computer_id, reason, usr.ckey, 0, 0, M.lastKnownIP) + if("No") + AddBan(M.ckey, M.computer_id, reason, usr.ckey, 0, 0) + to_chat(M, "You have been banned by [usr.client.ckey].\nReason: [reason].") + to_chat(M, "This is a ban until appeal.") + if(config.banappeals) + to_chat(M, "To try to resolve this matter head to [config.banappeals]") + else + to_chat(M, "No ban appeals URL has been set.") + ban_unban_log_save("[usr.client.ckey] has permabanned [M.ckey]. - Reason: [reason] - This is a ban until appeal.") + notes_add(M.ckey,"[usr.client.ckey] has permabanned [M.ckey]. - Reason: [reason] - This is a ban until appeal.",usr) + log_and_message_admins("has banned [M.ckey].\nReason: [reason]\nThis is a ban until appeal.") + feedback_inc("ban_perma",1) + DB_ban_record(BANTYPE_PERMA, M, -1, reason) + + qdel(M.client) + //qdel(M) + if("Cancel") + return + + else if(href_list["mute"]) + if(!check_rights(R_MOD,0) && !check_rights(R_ADMIN)) return + + var/mob/M = locate(href_list["mute"]) + if(!ismob(M)) return + if(!M.client) return + + var/mute_type = href_list["mute_type"] + if(istext(mute_type)) mute_type = text2num(mute_type) + if(!isnum(mute_type)) return + + cmd_admin_mute(M, mute_type) + + else if(href_list["c_mode"]) + if(!check_rights(R_ADMIN)) return + + if(ticker && ticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + var/dat = {"What mode do you wish to play?
            "} + for(var/mode in config.modes) + dat += {"[config.mode_names[mode]]
            "} + dat += {"Secret
            "} + dat += {"Random
            "} + dat += {"Now: [master_mode]"} + usr << browse(dat, "window=c_mode") + + else if(href_list["f_secret"]) + if(!check_rights(R_ADMIN)) return + + if(ticker && ticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(master_mode != "secret") + return alert(usr, "The game mode has to be secret!", null, null, null, null) + var/dat = {"What game mode do you want to force secret to be? Use this if you want to change the game mode, but want the players to believe it's secret. This will only work if the current game mode is secret.
            "} + for(var/mode in config.modes) + dat += {"[config.mode_names[mode]]
            "} + dat += {"Random (default)
            "} + dat += {"Now: [secret_force_mode]"} + usr << browse(dat, "window=f_secret") + + else if(href_list["c_mode2"]) + if(!check_rights(R_ADMIN|R_SERVER)) return + + if (ticker && ticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + master_mode = href_list["c_mode2"] + log_and_message_admins("set the mode as [master_mode].") + to_world("The mode is now: [master_mode]") + Game() // updates the main game menu + world.save_mode(master_mode) + .(href, list("c_mode"=1)) + + else if(href_list["f_secret2"]) + if(!check_rights(R_ADMIN|R_SERVER)) return + + if(ticker && ticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(master_mode != "secret") + return alert(usr, "The game mode has to be secret!", null, null, null, null) + secret_force_mode = href_list["f_secret2"] + log_and_message_admins("set the forced secret mode as [secret_force_mode].") + Game() // updates the main game menu + .(href, list("f_secret"=1)) + + else if(href_list["monkeyone"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["monkeyone"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return + + log_and_message_admins("attempting to monkeyize [key_name_admin(H)]") + H.monkeyize() + + else if(href_list["corgione"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["corgione"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return + + log_and_message_admins("attempting to corgize [key_name_admin(H)]") + H.corgize() + + else if(href_list["forcespeech"]) + if(!check_rights(R_FUN)) return + + var/mob/M = locate(href_list["forcespeech"]) + if(!ismob(M)) + to_chat(usr, "this can only be used on instances of type /mob") + + var/speech = input("What will [key_name(M)] say?.", "Force speech", "")// Don't need to sanitize, since it does that in say(), we also trust our admins. + if(!speech) return + M.say(speech) + speech = sanitize(speech) // Nah, we don't trust them + log_and_message_admins("forced [key_name_admin(M)] to say: [speech]") + + else if(href_list["sendtoprison"]) + if(!check_rights(R_ADMIN)) return + + if(alert(usr, "Send to admin prison for the round?", "Message", "Yes", "No") != "Yes") + return + + var/mob/M = locate(href_list["sendtoprison"]) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + if(istype(M, /mob/living/silicon/ai)) + to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai") + return + + var/turf/prison_cell = pick(GLOB.prisonwarp) + if(!prison_cell) return + + var/obj/structure/closet/secure_closet/brig/locker = new /obj/structure/closet/secure_closet/brig(prison_cell) + locker.opened = 0 + locker.locked = 1 + + //strip their stuff and stick it in the crate + for(var/obj/item/I in M) + M.drop_from_inventory(I, locker) + M.update_icons() + + //so they black out before warping + M.Paralyse(5) + sleep(5) + if(!M) return + + M.forceMove(prison_cell) + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/prisoner = M + prisoner.equip_to_slot_or_del(new /obj/item/clothing/under/color/orange(prisoner), slot_w_uniform) + prisoner.equip_to_slot_or_del(new /obj/item/clothing/shoes/orange(prisoner), slot_shoes) + + to_chat(M, "You have been sent to the prison station!") + log_and_message_admins("sent [key_name_admin(M)] to the prison station.") + + else if(href_list["tdome1"]) + if(!check_rights(R_FUN)) return + + if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") + return + + var/mob/M = locate(href_list["tdome1"]) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + if(istype(M, /mob/living/silicon/ai)) + to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai") + return + + for(var/obj/item/I in M) + M.drop_from_inventory(I) + + M.Paralyse(5) + sleep(5) + M.forceMove(pick(GLOB.tdome1)) + spawn(50) + to_chat(M, "You have been sent to the Thunderdome.") + log_admin("[key_name(usr)] has sent [key_name(M)] to the thunderdome. (Team 1)") + message_admins("[key_name_admin(usr)] has sent [key_name_admin(M)] to the thunderdome. (Team 1)", 1) + + else if(href_list["tdome2"]) + if(!check_rights(R_FUN)) return + + if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") + return + + var/mob/M = locate(href_list["tdome2"]) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + if(istype(M, /mob/living/silicon/ai)) + to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai") + return + + for(var/obj/item/I in M) + M.drop_from_inventory(I) + + M.Paralyse(5) + sleep(5) + M.forceMove(pick(GLOB.tdome2)) + spawn(50) + to_chat(M, "You have been sent to the Thunderdome.") + log_admin("[key_name(usr)] has sent [key_name(M)] to the thunderdome. (Team 2)") + message_admins("[key_name_admin(usr)] has sent [key_name_admin(M)] to the thunderdome. (Team 2)", 1) + + else if(href_list["tdomeadmin"]) + if(!check_rights(R_FUN)) return + + if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") + return + + var/mob/M = locate(href_list["tdomeadmin"]) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + if(istype(M, /mob/living/silicon/ai)) + to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai") + return + + M.Paralyse(5) + sleep(5) + M.forceMove(pick(GLOB.tdomeadmin)) + spawn(50) + to_chat(M, "You have been sent to the Thunderdome.") + log_admin("[key_name(usr)] has sent [key_name(M)] to the thunderdome. (Admin.)") + message_admins("[key_name_admin(usr)] has sent [key_name_admin(M)] to the thunderdome. (Admin.)", 1) + + else if(href_list["tdomeobserve"]) + if(!check_rights(R_FUN)) return + + if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") + return + + var/mob/M = locate(href_list["tdomeobserve"]) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + if(istype(M, /mob/living/silicon/ai)) + to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai") + return + + for(var/obj/item/I in M) + M.drop_from_inventory(I) + + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/observer = M + observer.equip_to_slot_or_del(new /obj/item/clothing/under/suit_jacket(observer), slot_w_uniform) + observer.equip_to_slot_or_del(new /obj/item/clothing/shoes/black(observer), slot_shoes) + M.Paralyse(5) + sleep(5) + M.forceMove(pick(GLOB.tdomeobserve)) + spawn(50) + to_chat(M, "You have been sent to the Thunderdome.") + log_admin("[key_name(usr)] has sent [key_name(M)] to the thunderdome. (Observer.)") + message_admins("[key_name_admin(usr)] has sent [key_name_admin(M)] to the thunderdome. (Observer.)", 1) + + else if(href_list["revive"]) + if(!check_rights(R_REJUVINATE)) return + + var/mob/living/L = locate(href_list["revive"]) + if(!istype(L)) + to_chat(usr, "This can only be used on instances of type /mob/living") + return + + if(config.allow_admin_rev) + L.revive() + log_and_message_admins("healed / Rrvived [key_name(L)]") + else + to_chat(usr, "Admin Rejuvinates have been disabled") + + else if(href_list["makeai"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["makeai"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return + + log_and_message_admins("AIized [key_name_admin(H)]!") + H.AIize() + + else if(href_list["makeslime"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["makeslime"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return + + usr.client.cmd_admin_slimeize(H) + + else if(href_list["makerobot"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["makerobot"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return + + usr.client.cmd_admin_robotize(H) + + else if(href_list["makeanimal"]) + if(!check_rights(R_SPAWN)) return + + var/mob/M = locate(href_list["makeanimal"]) + if(istype(M, /mob/new_player)) + to_chat(usr, "This cannot be used on instances of type /mob/new_player") + return + + usr.client.cmd_admin_animalize(M) + + else if(href_list["togmutate"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["togmutate"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return + var/block=text2num(href_list["block"]) + //testing("togmutate([href_list["block"]] -> [block])") + usr.client.cmd_admin_toggle_block(H,block) + show_player_panel(H) + //H.regenerate_icons() + + else if(href_list["adminplayeropts"]) + var/mob/M = locate(href_list["adminplayeropts"]) + show_player_panel(M) + + else if(href_list["adminplayerobservejump"]) + if(!check_rights(R_MENTOR|R_MOD|R_ADMIN)) return + + var/mob/M = locate(href_list["adminplayerobservejump"]) + var/client/C = usr.client + if(!M) + to_chat(C, "Unable to locate mob.") + return + + if(!isghost(usr)) C.admin_ghost() + sleep(2) + C.jumptomob(M) + + else if(href_list["adminplayerobservefollow"]) + if(!check_rights(R_MENTOR|R_MOD|R_ADMIN)) + return + + var/mob/M = locate(href_list["adminplayerobservefollow"]) + var/client/C = usr.client + if(!M) + to_chat(C, "Unable to locate mob.") + return + + if(!isobserver(usr)) C.admin_ghost() + var/mob/observer/ghost/G = C.mob + if(istype(G)) + sleep(2) + G.ManualFollow(M) + + else if(href_list["check_antagonist"]) + check_antagonists() + + // call dibs on IC messages (prays, emergency comms, faxes) + else if(href_list["take_ic"]) + + var/mob/M = locate(href_list["take_question"]) + if(ismob(M)) + var/take_msg = "[key_name(usr.client)] is attending to [key_name(M)]'s message." + for(var/client/X in GLOB.admins) + if((R_ADMIN|R_MOD|R_MENTOR) & X.holder.rights) + to_chat(X, take_msg) + to_chat(M, "Your message is being attended to by [usr.client]. Thanks for your patience!") + else + to_chat(usr, "Unable to locate mob.") + + else if(href_list["take_ticket"]) + var/datum/ticket/ticket = locate(href_list["take_ticket"]) + + if(isnull(ticket)) + return + + ticket.take(client_repository.get_lite_client(usr.client)) + + else if(href_list["adminplayerobservecoodjump"]) + if(!check_rights(R_ADMIN)) return + + var/x = text2num(href_list["X"]) + var/y = text2num(href_list["Y"]) + var/z = text2num(href_list["Z"]) + + var/client/C = usr.client + if(!isghost(usr)) C.admin_ghost() + sleep(2) + C.jumptocoord(x,y,z) + + else if(href_list["adminchecklaws"]) + output_ai_laws() + + else if(href_list["adminmoreinfo"]) + var/mob/M = locate(href_list["adminmoreinfo"]) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + var/location_description = "" + var/special_role_description = "" + var/health_description = "" + var/gender_description = "" + var/turf/T = get_turf(M) + + //Location + if(isturf(T)) + if(isarea(T.loc)) + location_description = "([M.loc == T ? "at coordinates " : "in [M.loc] at coordinates "] [T.x], [T.y], [T.z] in area [T.loc])" + else + location_description = "([M.loc == T ? "at coordinates " : "in [M.loc] at coordinates "] [T.x], [T.y], [T.z])" + + //Job + antagonist + if(M.mind) + special_role_description = "Role: [M.mind.assigned_role]; Antagonist: [M.mind.special_role]; Has been rev: [(M.mind.has_been_rev)?"Yes":"No"]" + else + special_role_description = "Role: Mind datum missing Antagonist: Mind datum missing; Has been rev: Mind datum missing;" + + //Health + if(isliving(M)) + var/mob/living/L = M + var/status + switch (M.stat) + if (0) status = "Alive" + if (1) status = "Unconscious" + if (2) status = "Dead" + health_description = "Status = [status]" + health_description += "
            Oxy: [L.getOxyLoss()] - Tox: [L.getToxLoss()] - Fire: [L.getFireLoss()] - Brute: [L.getBruteLoss()] - Clone: [L.getCloneLoss()] - Brain: [L.getBrainLoss()]" + else + health_description = "This mob type has no health to speak of." + + //Gener + switch(M.gender) + if(MALE,FEMALE) gender_description = "[M.gender]" + else gender_description = "[M.gender]" + + to_chat(src.owner, "Info about [M.name]: ") + to_chat(src.owner, "Mob type = [M.type]; Gender = [gender_description]; Damage = [health_description]") + to_chat(src.owner, "Name = [M.name]; Real_name = [M.real_name]; Mind_name = [M.mind?"[M.mind.name]":""]; Key = [M.key];") + to_chat(src.owner, "Location = [location_description];") + to_chat(src.owner, "[special_role_description]") + to_chat(src.owner, "(PM) (PP) (VV) (SM) ([admin_jump_link(M, src)]) (CA)") + + else if(href_list["adminspawncookie"]) + if(!check_rights(R_ADMIN|R_FUN)) return + + var/mob/living/carbon/human/H = locate(href_list["adminspawncookie"]) + if(!ishuman(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return + + H.equip_to_slot_or_del( new /obj/item/weapon/reagent_containers/food/snacks/cookie(H), slot_l_hand ) + if(!(istype(H.l_hand,/obj/item/weapon/reagent_containers/food/snacks/cookie))) + H.equip_to_slot_or_del( new /obj/item/weapon/reagent_containers/food/snacks/cookie(H), slot_r_hand ) + if(!(istype(H.r_hand,/obj/item/weapon/reagent_containers/food/snacks/cookie))) + log_admin("[key_name(H)] has their hands full, so they did not receive their cookie, spawned by [key_name(src.owner)].") + message_admins("[key_name(H)] has their hands full, so they did not receive their cookie, spawned by [key_name(src.owner)].") + return + else + H.update_inv_r_hand()//To ensure the icon appears in the HUD + else + H.update_inv_l_hand() + log_admin("[key_name(H)] got their cookie, spawned by [key_name(src.owner)]") + message_admins("[key_name(H)] got their cookie, spawned by [key_name(src.owner)]") + feedback_inc("admin_cookies_spawned",1) + to_chat(H, "Your prayers have been answered!! You received the best cookie!") + + else if(href_list["BlueSpaceArtillery"]) + if(!check_rights(R_ADMIN|R_FUN)) return + + var/mob/living/M = locate(href_list["BlueSpaceArtillery"]) + if(!isliving(M)) + to_chat(usr, "This can only be used on instances of type /mob/living") + return + + if(alert(src.owner, "Are you sure you wish to hit [key_name(M)] with Blue Space Artillery?", "Confirm Firing?" , "Yes" , "No") != "Yes") + return + + if(BSACooldown) + to_chat(src.owner, "Standby! Reload cycle in progress! Gunnary crews ready in five seconds!") + return + + BSACooldown = 1 + spawn(50) + BSACooldown = 0 + + to_chat(M, "You've been hit by bluespace artillery!") + log_admin("[key_name(M)] has been hit by Bluespace Artillery fired by [src.owner]") + message_admins("[key_name(M)] has been hit by Bluespace Artillery fired by [src.owner]") + + var/obj/effect/stop/S + S = new /obj/effect/stop + S.victim = M + S.loc = M.loc + spawn(20) + qdel(S) + + var/turf/simulated/floor/T = get_turf(M) + if(istype(T)) + if(prob(80)) T.break_tile_to_plating() + else T.break_tile() + + if(M.health == 1) + M.gib() + else + M.adjustBruteLoss( min( 99 , (M.health - 1) ) ) + M.Stun(20) + M.Weaken(20) + M.stuttering = 20 + + else if(href_list["CentcommReply"]) + var/mob/living/L = locate(href_list["CentcommReply"]) + if(!istype(L)) + to_chat(usr, "This can only be used on instances of type /mob/living/") + return + + if(L.can_centcom_reply()) + var/input = sanitize(input(src.owner, "Please enter a message to reply to [key_name(L)] via their headset.","Outgoing message from Centcomm", "")) + if(!input) return + + to_chat(src.owner, "You sent [input] to [L] via a secure channel.") + log_admin("[src.owner] replied to [key_name(L)]'s Centcomm message with the message [input].") + message_admins("[src.owner] replied to [key_name(L)]'s Centcom message with: \"[input]\"") + if(!isAI(L)) + to_chat(L, "You hear something crackle in your headset for a moment before a voice speaks.") + to_chat(L, "Please stand by for a message from Central Command.") + to_chat(L, "Message as follows.") + to_chat(L, "[input]") + to_chat(L, "Message ends.") + else + to_chat(src.owner, "The person you are trying to contact does not have functional radio equipment.") + + + else if(href_list["SyndicateReply"]) + var/mob/living/carbon/human/H = locate(href_list["SyndicateReply"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return + if(!istype(H.l_ear, /obj/item/device/radio/headset) && !istype(H.r_ear, /obj/item/device/radio/headset)) + to_chat(usr, "The person you are trying to contact is not wearing a headset") + return + + var/input = sanitize(input(src.owner, "Please enter a message to reply to [key_name(H)] via their headset.","Outgoing message from a shadowy figure...", "")) + if(!input) return + + to_chat(src.owner, "You sent [input] to [H] via a secure channel.") + log_admin("[src.owner] replied to [key_name(H)]'s illegal message with the message [input].") + to_chat(H, "You hear something crackle in your headset for a moment before a voice speaks. \"Please stand by for a message from your benefactor. Message as follows, agent. \"[input]\" Message ends.\"") + + else if(href_list["AdminFaxView"]) + var/obj/item/fax = locate(href_list["AdminFaxView"]) + if (istype(fax, /obj/item/weapon/paper)) + var/obj/item/weapon/paper/P = fax + P.show_content(usr,1) + else if (istype(fax, /obj/item/weapon/photo)) + var/obj/item/weapon/photo/H = fax + H.show(usr) + else if (istype(fax, /obj/item/weapon/paper_bundle)) + //having multiple people turning pages on a paper_bundle can cause issues + //open a browse window listing the contents instead + var/data = "" + var/obj/item/weapon/paper_bundle/B = fax + + for (var/page = 1, page <= B.pages.len, page++) + var/obj/pageobj = B.pages[page] + data += "Page [page] - [pageobj.name]
            " + + usr << browse(data, "window=[B.name]") + else + to_chat(usr, "The faxed item is not viewable. This is probably a bug, and should be reported on the tracker: [fax.type]") + else if (href_list["AdminFaxViewPage"]) + var/page = text2num(href_list["AdminFaxViewPage"]) + var/obj/item/weapon/paper_bundle/bundle = locate(href_list["paper_bundle"]) + + if (!bundle) return + + if (istype(bundle.pages[page], /obj/item/weapon/paper)) + var/obj/item/weapon/paper/P = bundle.pages[page] + P.show_content(src.owner, 1) + else if (istype(bundle.pages[page], /obj/item/weapon/photo)) + var/obj/item/weapon/photo/H = bundle.pages[page] + H.show(src.owner) + return + + else if(href_list["FaxReply"]) + var/mob/sender = locate(href_list["FaxReply"]) + var/obj/machinery/photocopier/faxmachine/fax = locate(href_list["originfax"]) + var/replyorigin = href_list["replyorigin"] + + + var/obj/item/weapon/paper/admin/P = new /obj/item/weapon/paper/admin( null ) //hopefully the null loc won't cause trouble for us + faxreply = P + + P.admindatum = src + P.origin = replyorigin + P.destination = fax + P.sender = sender + + P.adminbrowse() + + else if(href_list["jumpto"]) + if(!check_rights(R_ADMIN)) return + + var/mob/M = locate(href_list["jumpto"]) + usr.client.jumptomob(M) + + else if(href_list["getmob"]) + if(!check_rights(R_ADMIN)) return + + if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") return + var/mob/M = locate(href_list["getmob"]) + usr.client.Getmob(M) + + else if(href_list["sendmob"]) + if(!check_rights(R_ADMIN)) return + + var/mob/M = locate(href_list["sendmob"]) + usr.client.sendmob(M) + + else if(href_list["narrateto"]) + if(!check_rights(R_ADMIN)) return + + var/mob/M = locate(href_list["narrateto"]) + usr.client.cmd_admin_direct_narrate(M) + + else if(href_list["subtlemessage"]) + if(!check_rights(R_MOD,0) && !check_rights(R_ADMIN)) return + + var/mob/M = locate(href_list["subtlemessage"]) + usr.client.cmd_admin_subtle_message(M) + + else if(href_list["traitor"]) + if(!check_rights(R_ADMIN|R_MOD)) return + + if(!ticker || !ticker.mode) + alert("The game hasn't started yet!") + return + + var/mob/M = locate(href_list["traitor"]) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob.") + return + show_traitor_panel(M) + + else if(href_list["create_object"]) + if(!check_rights(R_SPAWN)) return + return create_object(usr) + + else if(href_list["quick_create_object"]) + if(!check_rights(R_SPAWN)) return + return quick_create_object(usr) + + else if(href_list["create_turf"]) + if(!check_rights(R_SPAWN)) return + return create_turf(usr) + + else if(href_list["create_mob"]) + if(!check_rights(R_SPAWN)) return + return create_mob(usr) + + else if(href_list["object_list"]) //this is the laggiest thing ever + if(!check_rights(R_SPAWN)) return + + if(!config.allow_admin_spawning) + to_chat(usr, "Spawning of items is not allowed.") + return + + var/atom/loc = usr.loc + + var/dirty_paths + if (istext(href_list["object_list"])) + dirty_paths = list(href_list["object_list"]) + else if (istype(href_list["object_list"], /list)) + dirty_paths = href_list["object_list"] + + var/paths = list() + var/removed_paths = list() + + for(var/dirty_path in dirty_paths) + var/path = text2path(dirty_path) + if(!path) + removed_paths += dirty_path + continue + else if(!ispath(path, /obj) && !ispath(path, /turf) && !ispath(path, /mob)) + removed_paths += dirty_path + continue + else if(ispath(path, /obj/item/weapon/gun/energy/pulse_rifle)) + if(!check_rights(R_FUN,0)) + removed_paths += dirty_path + continue + else if(ispath(path, /obj/item/weapon/melee/energy/blade))//Not an item one should be able to spawn./N + if(!check_rights(R_FUN,0)) + removed_paths += dirty_path + continue + else if(ispath(path, /obj/effect/bhole)) + if(!check_rights(R_FUN,0)) + removed_paths += dirty_path + continue + paths += path + + if(!paths) + alert("The path list you sent is empty") + return + if(length(paths) > 5) + alert("Select fewer object types, (max 5)") + return + else if(length(removed_paths)) + alert("Removed:\n" + jointext(removed_paths, "\n")) + + var/list/offset = splittext(href_list["offset"],",") + var/number = dd_range(1, 100, text2num(href_list["object_count"])) + var/X = offset.len > 0 ? text2num(offset[1]) : 0 + var/Y = offset.len > 1 ? text2num(offset[2]) : 0 + var/Z = offset.len > 2 ? text2num(offset[3]) : 0 + var/tmp_dir = href_list["object_dir"] + var/obj_dir = tmp_dir ? text2num(tmp_dir) : 2 + if(!obj_dir || !(obj_dir in list(1,2,4,8,5,6,9,10))) + obj_dir = 2 + var/obj_name = sanitize(href_list["object_name"]) + var/where = href_list["object_where"] + if (!( where in list("onfloor","inhand","inmarked") )) + where = "onfloor" + + if( where == "inhand" ) + to_chat(usr, "Support for inhand not available yet. Will spawn on floor.") + where = "onfloor" + + if ( where == "inhand" ) //Can only give when human or monkey + if ( !( ishuman(usr) || issmall(usr) ) ) + to_chat(usr, "Can only spawn in hand when you're a human or a monkey.") + where = "onfloor" + else if ( usr.get_active_hand() ) + to_chat(usr, "Your active hand is full. Spawning on floor.") + where = "onfloor" + + if ( where == "inmarked" ) + var/marked_datum = marked_datum() + if ( !marked_datum ) + to_chat(usr, "You don't have any object marked. Abandoning spawn.") + return + else + if ( !istype(marked_datum,/atom) ) + to_chat(usr, "The object you have marked cannot be used as a target. Target must be of type /atom. Abandoning spawn.") + return + + var/atom/target //Where the object will be spawned + switch ( where ) + if ( "onfloor" ) + switch (href_list["offset_type"]) + if ("absolute") + target = locate(0 + X,0 + Y,0 + Z) + if ("relative") + target = locate(loc.x + X,loc.y + Y,loc.z + Z) + if ( "inmarked" ) + target = marked_datum() + + if(target) + for (var/path in paths) + for (var/i = 0; i < number; i++) + if(path in typesof(/turf)) + var/turf/O = target + var/turf/N = O.ChangeTurf(path) + if(N) + if(obj_name) + N.SetName(obj_name) + else + var/atom/O = new path(target) + if(O) + O.set_dir(obj_dir) + if(obj_name) + O.SetName(obj_name) + if(istype(O,/mob)) + var/mob/M = O + M.real_name = obj_name + + log_and_message_admins("created [number] [english_list(paths)]") + return + + else if(href_list["admin_secrets_panel"]) + var/datum/admin_secret_category/AC = locate(href_list["admin_secrets_panel"]) in admin_secrets.categories + src.Secrets(AC) + + else if(href_list["admin_secrets"]) + var/datum/admin_secret_item/item = locate(href_list["admin_secrets"]) in admin_secrets.items + item.execute(usr) + + else if(href_list["ac_view_wanted"]) //Admin newscaster Topic() stuff be here + src.admincaster_screen = 18 //The ac_ prefix before the hrefs stands for AdminCaster. + src.access_news_network() + + else if(href_list["ac_set_channel_name"]) + src.admincaster_feed_channel.channel_name = sanitizeSafe(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", "")) + src.access_news_network() + + else if(href_list["ac_set_channel_lock"]) + src.admincaster_feed_channel.locked = !src.admincaster_feed_channel.locked + src.access_news_network() + + else if(href_list["ac_submit_new_channel"]) + var/check = 0 + for(var/datum/feed_channel/FC in news_network.network_channels) + if(FC.channel_name == src.admincaster_feed_channel.channel_name) + check = 1 + break + if(src.admincaster_feed_channel.channel_name == "" || src.admincaster_feed_channel.channel_name == "\[REDACTED\]" || check ) + src.admincaster_screen=7 + else + var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel") + if(choice=="Confirm") + news_network.CreateFeedChannel(admincaster_feed_channel.channel_name, admincaster_signature, admincaster_feed_channel.locked, 1) + feedback_inc("newscaster_channels",1) //Adding channel to the global network + log_admin("[key_name_admin(usr)] created command feed channel: [src.admincaster_feed_channel.channel_name]!") + src.admincaster_screen=5 + src.access_news_network() + + else if(href_list["ac_set_channel_receiving"]) + var/list/available_channels = list() + for(var/datum/feed_channel/F in news_network.network_channels) + available_channels += F.channel_name + src.admincaster_feed_channel.channel_name = sanitizeSafe(input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels ) + src.access_news_network() + + else if(href_list["ac_set_new_message"]) + src.admincaster_feed_message.body = sanitize(usr, "Write your Feed story", "Network Channel Handler", "") + src.access_news_network() + + else if(href_list["ac_submit_new_message"]) + if(src.admincaster_feed_message.body =="" || src.admincaster_feed_message.body =="\[REDACTED\]" || src.admincaster_feed_channel.channel_name == "" ) + src.admincaster_screen = 6 + else + feedback_inc("newscaster_stories",1) + news_network.SubmitArticle(src.admincaster_feed_message.body, src.admincaster_signature, src.admincaster_feed_channel.channel_name, null, 1) + src.admincaster_screen=4 + + log_admin("[key_name_admin(usr)] submitted a feed story to channel: [src.admincaster_feed_channel.channel_name]!") + src.access_news_network() + + else if(href_list["ac_create_channel"]) + src.admincaster_screen=2 + src.access_news_network() + + else if(href_list["ac_create_feed_story"]) + src.admincaster_screen=3 + src.access_news_network() + + else if(href_list["ac_menu_censor_story"]) + src.admincaster_screen=10 + src.access_news_network() + + else if(href_list["ac_menu_censor_channel"]) + src.admincaster_screen=11 + src.access_news_network() + + else if(href_list["ac_menu_wanted"]) + var/already_wanted = 0 + if(news_network.wanted_issue) + already_wanted = 1 + + if(already_wanted) + src.admincaster_feed_message.author = news_network.wanted_issue.author + src.admincaster_feed_message.body = news_network.wanted_issue.body + src.admincaster_screen = 14 + src.access_news_network() + + else if(href_list["ac_set_wanted_name"]) + src.admincaster_feed_message.author = sanitize(input(usr, "Provide the name of the Wanted person", "Network Security Handler", "")) + src.access_news_network() + + else if(href_list["ac_set_wanted_desc"]) + src.admincaster_feed_message.body = sanitize(input(usr, "Provide the a description of the Wanted person and any other details you deem important", "Network Security Handler", "")) + src.access_news_network() + + else if(href_list["ac_submit_wanted"]) + var/input_param = text2num(href_list["ac_submit_wanted"]) + if(src.admincaster_feed_message.author == "" || src.admincaster_feed_message.body == "") + src.admincaster_screen = 16 + else + var/choice = alert("Please confirm Wanted Issue [(input_param==1) ? ("creation.") : ("edit.")]","Network Security Handler","Confirm","Cancel") + if(choice=="Confirm") + if(input_param==1) //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one. See the else below + var/datum/feed_message/WANTED = new /datum/feed_message + WANTED.author = src.admincaster_feed_message.author //Wanted name + WANTED.body = src.admincaster_feed_message.body //Wanted desc + WANTED.backup_author = src.admincaster_signature //Submitted by + WANTED.is_admin_message = 1 + news_network.wanted_issue = WANTED + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) + NEWSCASTER.newsAlert() + NEWSCASTER.update_icon() + src.admincaster_screen = 15 + else + news_network.wanted_issue.author = src.admincaster_feed_message.author + news_network.wanted_issue.body = src.admincaster_feed_message.body + news_network.wanted_issue.backup_author = src.admincaster_feed_message.backup_author + src.admincaster_screen = 19 + log_admin("[key_name_admin(usr)] issued a Wanted Notification for [src.admincaster_feed_message.author]!") + src.access_news_network() + + else if(href_list["ac_cancel_wanted"]) + var/choice = alert("Please confirm Wanted Issue removal","Network Security Handler","Confirm","Cancel") + if(choice=="Confirm") + news_network.wanted_issue = null + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) + NEWSCASTER.update_icon() + src.admincaster_screen=17 + src.access_news_network() + + else if(href_list["ac_censor_channel_author"]) + var/datum/feed_channel/FC = locate(href_list["ac_censor_channel_author"]) + if(FC.author != "\[REDACTED\]") + FC.backup_author = FC.author + FC.author = "\[REDACTED\]" + else + FC.author = FC.backup_author + src.access_news_network() + + else if(href_list["ac_censor_channel_story_author"]) + var/datum/feed_message/MSG = locate(href_list["ac_censor_channel_story_author"]) + if(MSG.author != "\[REDACTED\]") + MSG.backup_author = MSG.author + MSG.author = "\[REDACTED\]" + else + MSG.author = MSG.backup_author + src.access_news_network() + + else if(href_list["ac_censor_channel_story_body"]) + var/datum/feed_message/MSG = locate(href_list["ac_censor_channel_story_body"]) + if(MSG.body != "\[REDACTED\]") + MSG.backup_body = MSG.body + MSG.body = "\[REDACTED\]" + else + MSG.body = MSG.backup_body + src.access_news_network() + + else if(href_list["ac_pick_d_notice"]) + var/datum/feed_channel/FC = locate(href_list["ac_pick_d_notice"]) + src.admincaster_feed_channel = FC + src.admincaster_screen=13 + src.access_news_network() + + else if(href_list["ac_toggle_d_notice"]) + var/datum/feed_channel/FC = locate(href_list["ac_toggle_d_notice"]) + FC.censored = !FC.censored + src.access_news_network() + + else if(href_list["ac_view"]) + src.admincaster_screen=1 + src.access_news_network() + + else if(href_list["ac_setScreen"]) //Brings us to the main menu and resets all fields~ + src.admincaster_screen = text2num(href_list["ac_setScreen"]) + if (src.admincaster_screen == 0) + if(src.admincaster_feed_channel) + src.admincaster_feed_channel = new /datum/feed_channel + if(src.admincaster_feed_message) + src.admincaster_feed_message = new /datum/feed_message + src.access_news_network() + + else if(href_list["ac_show_channel"]) + var/datum/feed_channel/FC = locate(href_list["ac_show_channel"]) + src.admincaster_feed_channel = FC + src.admincaster_screen = 9 + src.access_news_network() + + else if(href_list["ac_pick_censor_channel"]) + var/datum/feed_channel/FC = locate(href_list["ac_pick_censor_channel"]) + src.admincaster_feed_channel = FC + src.admincaster_screen = 12 + src.access_news_network() + + else if(href_list["ac_refresh"]) + src.access_news_network() + + else if(href_list["ac_set_signature"]) + src.admincaster_signature = sanitize(input(usr, "Provide your desired signature", "Network Identity Handler", "")) + src.access_news_network() + + else if(href_list["populate_inactive_customitems"]) + if(check_rights(R_ADMIN|R_SERVER)) + populate_inactive_customitems_list(src.owner) + + else if(href_list["vsc"]) + if(check_rights(R_ADMIN|R_SERVER)) + if(href_list["vsc"] == "airflow") + vsc.ChangeSettingsDialog(usr,vsc.settings) + if(href_list["vsc"] == "phoron") + vsc.ChangeSettingsDialog(usr,vsc.plc.settings) + if(href_list["vsc"] == "default") + vsc.SetDefault(usr) + + else if(href_list["toglang"]) + if(check_rights(R_SPAWN)) + var/mob/M = locate(href_list["toglang"]) + if(!istype(M)) + to_chat(usr, "[M] is illegal type, must be /mob!") + return + var/lang2toggle = href_list["lang"] + var/datum/language/L = all_languages[lang2toggle] + + if(L in M.languages) + if(!M.remove_language(lang2toggle)) + to_chat(usr, "Failed to remove language '[lang2toggle]' from \the [M]!") + else + if(!M.add_language(lang2toggle)) + to_chat(usr, "Failed to add language '[lang2toggle]' from \the [M]!") + + show_player_panel(M) + + // player info stuff + + if(href_list["add_player_info"]) + var/key = href_list["add_player_info"] + var/add = sanitize(input("Add Player Info") as null|text) + if(!add) return + + notes_add(key,add,usr) + show_player_info(key) + + if(href_list["remove_player_info"]) + var/key = href_list["remove_player_info"] + var/index = text2num(href_list["remove_index"]) + + notes_del(key, index) + show_player_info(key) + + if(href_list["notes"]) + if(href_list["notes"] == "set_filter") + var/choice = input(usr,"Please specify a text filter to use or cancel to clear.","Player Notes",null) as text|null + PlayerNotesPage(choice) + else + var/ckey = href_list["ckey"] + if(!ckey) + var/mob/M = locate(href_list["mob"]) + if(ismob(M)) + ckey = M.ckey + show_player_info(ckey) + return + if(href_list["setstaffwarn"]) + var/mob/M = locate(href_list["setstaffwarn"]) + if(!ismob(M)) return + + if(M.client && M.client.holder) return // admins don't get staffnotify'd about + + switch(alert("Really set staff warn?",,"Yes","No")) + if("Yes") + var/reason = sanitize(input(usr,"Staff warn message","Staff Warn","Problem Player") as text|null) + if (!reason || reason == "") + return + notes_add(M.ckey,"\[AUTO\] Staff warn enabled: [reason]",usr) + reason += "\n-- Set by [usr.client.ckey]([usr.client.holder.rank])" + DB_staffwarn_record(M.ckey, reason) + if(M.client) + M.client.staffwarn = reason + feedback_inc("staff_warn",1) + log_and_message_admins("has enabled staffwarn on [M.ckey].\nMessage: [reason]\n") + show_player_panel(M) + if("No") + return + if(href_list["removestaffwarn"]) + var/mob/M = locate(href_list["removestaffwarn"]) + if(!ismob(M)) return + + switch(alert("Really remove staff warn?",,"Yes","No")) + if("Yes") + if(!DB_staffwarn_remove(M.ckey)) + return + notes_add(M.ckey,"\[AUTO\] Staff warn disabled",usr) + if(M.client) + M.client.staffwarn = null + log_and_message_admins("has removed the staffwarn on [M.ckey].\n") + show_player_panel(M) + if("No") + return + +mob/living/proc/can_centcom_reply() + return 0 + +mob/living/carbon/human/can_centcom_reply() + return istype(l_ear, /obj/item/device/radio/headset) || istype(r_ear, /obj/item/device/radio/headset) + +mob/living/silicon/ai/can_centcom_reply() + return silicon_radio != null && !check_unable(2) + +/datum/proc/extra_admin_link(var/prefix, var/sufix, var/short_links) + return list() + +/atom/movable/extra_admin_link(var/source, var/prefix, var/sufix, var/short_links) + return list("[prefix][short_links ? "J" : "JMP"][sufix]") + +/client/extra_admin_link(source, var/prefix, var/sufix, var/short_links) + return mob.extra_admin_link(source, prefix, sufix, short_links) + +/mob/extra_admin_link(var/source, var/prefix, var/sufix, var/short_links) + . = ..() + if(client && eyeobj) + . += "[prefix][short_links ? "E" : "EYE"][sufix]" + +/mob/observer/ghost/extra_admin_link(var/source, var/prefix, var/sufix, var/short_links) + . = ..() + if(mind && (mind.current && !isghost(mind.current))) + . += "[prefix][short_links ? "B" : "BDY"][sufix]" + +/proc/admin_jump_link(var/atom/target, var/source, var/delimiter = "|", var/prefix, var/sufix, var/short_links) + if(!target) return + // The way admin jump links handle their src is weirdly inconsistent... + if(istype(source, /datum/admins)) + source = "src=\ref[source]" + else + source = "_src_=holder" + return jointext(target.extra_admin_link(source, prefix, sufix, short_links), delimiter) + +/datum/proc/get_admin_jump_link(var/atom/target) + return + +/mob/get_admin_jump_link(var/atom/target, var/delimiter, var/prefix, var/sufix) + return client && client.get_admin_jump_link(target, delimiter, prefix, sufix) + +/client/get_admin_jump_link(var/atom/target, var/delimiter, var/prefix, var/sufix) + if(holder) + var/short_links = get_preference_value(/datum/client_preference/ghost_follow_link_length) == GLOB.PREF_SHORT + return admin_jump_link(target, src, delimiter, prefix, sufix, short_links) + diff --git a/code/modules/admin/verbs/BrokenInhands.dm b/code/modules/admin/verbs/BrokenInhands.dm new file mode 100644 index 00000000..bebb4d53 --- /dev/null +++ b/code/modules/admin/verbs/BrokenInhands.dm @@ -0,0 +1,34 @@ +/proc/getbrokeninhands() + var/icon/IL = new('icons/mob/onmob/items/lefthand.dmi') + var/list/Lstates = IL.IconStates() + var/icon/IR = new('icons/mob/onmob/items/righthand.dmi') + var/list/Rstates = IR.IconStates() + + + var/text + for(var/A in typesof(/obj/item)) + var/obj/item/O = new A( locate(1,1,1) ) + if(!O) continue + var/icon/J = new(O.icon) + var/list/istates = J.IconStates() + if(!Lstates.Find(O.icon_state) && !Lstates.Find(O.item_state)) + if(O.icon_state) + text += "[O.type] is missing left hand icon called \"[O.icon_state]\".\n" + if(!Rstates.Find(O.icon_state) && !Rstates.Find(O.item_state)) + if(O.icon_state) + text += "[O.type] is missing right hand icon called \"[O.icon_state]\".\n" + + + if(O.icon_state) + if(!istates.Find(O.icon_state)) + text += "[O.type] is missing normal icon called \"[O.icon_state]\" in \"[O.icon]\".\n" + //if(O.item_state) + // if(!istates.Find(O.item_state)) + // text += "[O.type] MISSING NORMAL ICON CALLED\n\"[O.item_state]\" IN \"[O.icon]\"\n" + //text+="\n" + qdel(O) + if(text) + var/F = file("broken_icons.txt") + fdel(F) + F << text + log_debug("Completeled successfully and written to [F]") diff --git a/code/modules/admin/verbs/SDQL.dm b/code/modules/admin/verbs/SDQL.dm new file mode 100644 index 00000000..4b854aa4 --- /dev/null +++ b/code/modules/admin/verbs/SDQL.dm @@ -0,0 +1,493 @@ + +//Structured Datum Query Language. Basically SQL meets BYOND objects. + +//Note: For use in BS12, need text_starts_with proc, and to modify the action on select to use BS12's object edit command(s). + +/client/proc/SDQL_query(query_text as message) + set category = "Admin" + if(!check_rights(R_DEBUG)) //Shouldn't happen... but just to be safe. + log_and_message_admins(" - Non-admin attempted to execute a SDQL query!") + + var/list/query_list = SDQL_tokenize(query_text) + + if(query_list.len < 2) + if(query_list.len > 0) + to_chat(usr, "SDQL: Too few discrete tokens in query \"[query_text]\". Please check your syntax and try again.") + return + + if(!(lowertext(query_list[1]) in list("select", "delete", "update"))) + to_chat(usr, "SDQL: Unknown query type: \"[query_list[1]]\" in query \"[query_text]\". Please check your syntax and try again.") + return + + var/list/types = list() + + var/i + for(i = 2; i <= query_list.len; i += 2) + types += query_list[i] + + if(i + 1 >= query_list.len || query_list[i + 1] != ",") + break + + i++ + + var/list/from = list() + + if(i <= query_list.len) + if(lowertext(query_list[i]) in list("from", "in")) + for(i++; i <= query_list.len; i += 2) + from += query_list[i] + + if(i + 1 >= query_list.len || query_list[i + 1] != ",") + break + + i++ + + if(from.len < 1) + from += "world" + + var/list/set_vars = list() + + if(lowertext(query_list[1]) == "update") + if(i <= query_list.len && lowertext(query_list[i]) == "set") + for(i++; i <= query_list.len; i++) + if(i + 2 <= query_list.len && query_list[i + 1] == "=") + set_vars += query_list[i] + set_vars[query_list[i]] = query_list[i + 2] + + else + to_chat(usr, "SDQL: Invalid set parameter in query \"[query_text]\". Please check your syntax and try again.") + return + + i += 3 + + if(i >= query_list.len || query_list[i] != ",") + break + + if(set_vars.len < 1) + to_chat(usr, "SDQL: Invalid or missing set in query \"[query_text]\". Please check your syntax and try again.") + return + + var/list/where = list() + + if(i <= query_list.len && lowertext(query_list[i]) == "where") + where = query_list.Copy(i + 1) + + var/list/from_objs = list() + if("world" in from) + from_objs += world + else + for(var/f in from) + if(copytext(f, 1, 2) == "'" || copytext(f, 1, 2) == "\"") + from_objs += locate(copytext(f, 2, length(f))) + else if(copytext(f, 1, 2) != "/") + from_objs += locate(f) + else + var/f2 = text2path(f) + if(text_starts_with(f, "/mob")) + for(var/mob/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/turf/space")) + for(var/turf/space/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/turf/simulated")) + for(var/turf/simulated/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/turf/unsimulated")) + for(var/turf/unsimulated/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/turf")) + for(var/turf/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/area")) + for(var/area/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/obj/item")) + for(var/obj/item/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/obj/machinery")) + for(var/obj/machinery/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/obj")) + for(var/obj/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/atom")) + for(var/atom/m in world) + if(istype(m, f2)) + from_objs += m +/* + else + for(var/datum/m in world) + if(istype(m, f2)) + from_objs += m +*/ + + var/list/objs = list() + + for(var/from_obj in from_objs) + if("*" in types) + objs += from_obj:contents + else + for(var/f in types) + if(copytext(f, 1, 2) == "'" || copytext(f, 1, 2) == "\"") + objs += locate(copytext(f, 2, length(f))) in from_obj + else if(copytext(f, 1, 2) != "/") + objs += locate(f) in from_obj + else + var/f2 = text2path(f) + if(text_starts_with(f, "/mob")) + for(var/mob/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/turf/space")) + for(var/turf/space/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/turf/simulated")) + for(var/turf/simulated/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/turf/unsimulated")) + for(var/turf/unsimulated/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/turf")) + for(var/turf/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/area")) + for(var/area/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/obj/item")) + for(var/obj/item/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/obj/machinery")) + for(var/obj/machinery/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/obj")) + for(var/obj/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/atom")) + for(var/atom/m in from_obj) + if(istype(m, f2)) + objs += m + + else + for(var/datum/m in from_obj) + if(istype(m, f2)) + objs += m + + + for(var/datum/t in objs) + var/currently_false = 0 + for(i = 1, i - 1 < where.len, i++) + var/v = where[i++] + var/compare_op = where[i++] + if(!(compare_op in list("==", "=", "<>", "<", ">", "<=", ">=", "!="))) + to_chat(usr, "SDQL: Unknown comparison operator [compare_op] in where clause following [v] in query \"[query_text]\". Please check your syntax and try again.") + return + + var/j + for(j = i, j <= where.len, j++) + if(lowertext(where[j]) in list("and", "or", ";")) + break + + if(!currently_false) + var/value = SDQL_text2value(t, v) + var/result = SDQL_evaluate(t, where.Copy(i, j)) + + switch(compare_op) + if("=", "==") + currently_false = !(value == result) + + if("!=", "<>") + currently_false = !(value != result) + + if("<") + currently_false = !(value < result) + + if(">") + currently_false = !(value > result) + + if("<=") + currently_false = !(value <= result) + + if(">=") + currently_false = !(value >= result) + + + if(j > where.len || lowertext(where[j]) == ";") + break + else if(lowertext(where[j]) == "or") + if(currently_false) + currently_false = 0 + else + break + + i = j + + if(currently_false) + objs -= t + + + + to_chat(usr, "SQDL Query: [query_text]") + message_admins("[usr] executed SDQL query: \"[query_text]\".") +/* + for(var/t in types) + to_chat(usr, "Type: [t]") + for(var/t in from) + to_chat(usr, "From: [t]") + for(var/t in set_vars) + to_chat(usr, "Set: [t] = [set_vars[t]]") + if(where.len) + var/where_str = "" + for(var/t in where) + where_str += "[t] " + + to_chat(usr, "Where: [where_str]") + + to_chat(usr, "From objects:") + for(var/datum/t in from_objs) + to_chat(usr, t) + + to_chat(usr, "Objects:") + for(var/datum/t in objs) + to_chat(usr, t) +*/ + switch(lowertext(query_list[1])) + if("delete") + for(var/datum/t in objs) + qdel(t) + + if("update") + for(var/datum/t in objs) + objs[t] = list() + for(var/v in set_vars) + if(v in t.vars) + objs[t][v] = SDQL_text2value(t, set_vars[v]) + + for(var/datum/t in objs) + for(var/v in objs[t]) + t.vars[v] = objs[t][v] + + if("select") + var/text = "" + for(var/datum/t in objs) + if(istype(t, /atom)) + var/atom/a = t + + if(a.x) + text += "\ref[t]: [t] at ([a.x], [a.y], [a.z])
            " + + else if(a.loc && a.loc.x) + text += "\ref[t]: [t] in [a.loc] at ([a.loc.x], [a.loc.y], [a.loc.z])
            " + + else + text += "\ref[t]: [t]
            " + + else + text += "\ref[t]: [t]
            " + + //text += "[t]
            " + usr << browse(text, "window=sdql_result") + + +/client/Topic(href,href_list[],hsrc) + if(href_list["SDQL_select"]) + debug_variables(locate(href_list["SDQL_select"])) + + ..() + + +/proc/SDQL_evaluate(datum/object, list/equation) + if(equation.len == 0) + return null + + else if(equation.len == 1) + return SDQL_text2value(object, equation[1]) + + else if(equation[1] == "!") + return !SDQL_evaluate(object, equation.Copy(2)) + + else if(equation[1] == "-") + return -SDQL_evaluate(object, equation.Copy(2)) + + + else + to_chat(usr, "SDQL: Sorry, equations not yet supported :(") + return null + + +/proc/SDQL_text2value(datum/object, text) + if(text2num(text) != null) + return text2num(text) + else if(text == "null") + return null + else if(copytext(text, 1, 2) == "'" || copytext(text, 1, 2) == "\"" ) + return copytext(text, 2, length(text)) + else if(copytext(text, 1, 2) == "/") + return text2path(text) + else + if(findtext(text, ".")) + var/split = findtext(text, ".") + var/v = copytext(text, 1, split) + + if((v in object.vars) && istype(object.vars[v], /datum)) + return SDQL_text2value(object.vars[v], copytext(text, split + 1)) + else + return null + + else + if(text in object.vars) + return object.vars[text] + else + return null + +/* +/proc/text_starts_with(text, start) + if(copytext(text, 1, length(start) + 1) == start) + return 1 + else + return 0 +*/ + + + + +/proc/SDQL_tokenize(query_text) + + var/list/whitespace = list(" ", "\n", "\t") + var/list/single = list("(", ")", ",", "+", "-") + var/list/multi = list( + "=" = list("", "="), + "<" = list("", "=", ">"), + ">" = list("", "="), + "!" = list("", "=")) + + var/word = "" + var/list/query_list = list() + var/len = length(query_text) + + for(var/i = 1, i <= len, i++) + var/char = copytext(query_text, i, i + 1) + + if(char in whitespace) + if(word != "") + query_list += word + word = "" + + else if(char in single) + if(word != "") + query_list += word + word = "" + + query_list += char + + else if(char in multi) + if(word != "") + query_list += word + word = "" + + var/char2 = copytext(query_text, i + 1, i + 2) + + if(char2 in multi[char]) + query_list += "[char][char2]" + i++ + + else + query_list += char + + else if(char == "'") + if(word != "") + to_chat(usr, "SDQL: You have an error in your SDQL syntax, unexpected ' in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again.") + return null + + word = "'" + + for(i++, i <= len, i++) + char = copytext(query_text, i, i + 1) + + if(char == "'") + if(copytext(query_text, i + 1, i + 2) == "'") + word += "'" + i++ + + else + break + + else + word += char + + if(i > len) + to_chat(usr, "SDQL: You have an error in your SDQL syntax, unmatched ' in query: \"[query_text]\". Please check your syntax, and try again.") + return null + + query_list += "[word]'" + word = "" + + else if(char == "\"") + if(word != "") + to_chat(usr, "SDQL: You have an error in your SDQL syntax, unexpected \" in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again.") + return null + + word = "\"" + + for(i++, i <= len, i++) + char = copytext(query_text, i, i + 1) + + if(char == "\"") + if(copytext(query_text, i + 1, i + 2) == "'") + word += "\"" + i++ + + else + break + + else + word += char + + if(i > len) + to_chat(usr, "SDQL: You have an error in your SDQL syntax, unmatched \" in query: \"[query_text]\". Please check your syntax, and try again.") + return null + + query_list += "[word]\"" + word = "" + + else + word += char + + if(word != "") + query_list += word + + return query_list diff --git a/code/modules/admin/verbs/SDQL_2/SDQL_2.dm b/code/modules/admin/verbs/SDQL_2/SDQL_2.dm new file mode 100644 index 00000000..c1bcea87 --- /dev/null +++ b/code/modules/admin/verbs/SDQL_2/SDQL_2.dm @@ -0,0 +1,554 @@ +// Code taken from /vg/station. + +// Examples +/* + -- Will call the proc for all computers in the world, thats dir is 2. + CALL ex_act(1) ON /obj/machinery/computer IN world WHERE dir == 2 + -- Will open a window with a list of all the closets in the world, with a link to VV them. + SELECT /obj/structure/closet/secure_closet/security/cargo IN world WHERE icon_off == "secoff" + -- Will change all the tube lights to green, and flicker them. The semicolon is important to separate the consecutive querys, but is not required for standard one-query use. + UPDATE /obj/machinery/light SET color = "#0F0" WHERE icon_state == "tube1"; CALL flicker(1) ON /obj/machinery/light + -- Will delete all pickaxes. "IN world" is not required. + DELETE /obj/item/weapon/pickaxe + + --You can use operators other than ==, such as >, <=, != and etc.. + + --Lists can be done through [], so say UPDATE /mob SET client.color = [1, 0.75, ...]. +*/ + +// Used by update statements, this is to handle shit like preventing editing the /datum/admins though SDQL but WITHOUT +PERMISSIONS. +// Assumes the variable actually exists. +/datum/proc/SDQL_update(var/const/var_name, var/new_value) + vars[var_name] = new_value + return 1 + +/client/proc/SDQL2_query(var/query_text as message) + set category = "Debug" + + if(!check_rights(R_DEBUG)) // Shouldn't happen... but just to be safe. + message_admins("ERROR: Non-admin [usr.key] attempted to execute the following SDQL query: [query_text]") + log_admin("Non-admin [usr.key] attempted to execute the following SDQL query: [query_text]!") + return + + if(!query_text || length(query_text) < 1) + return + + var/query_log = "[key_name(src)] executed SDQL query: \"[query_text]\"." + to_world_log(query_log) + log_and_message_admins(query_log) + sleep(-1) // Incase the server crashes due to a huge query, we allow the server to log the above things (it might just delay it). + + var/list/query_list = SDQL2_tokenize(query_text) + + if(!query_list || query_list.len < 1) + return + + var/list/querys = SDQL_parse(query_list) + + if(!querys || querys.len < 1) + return + + try + for(var/list/query_tree in querys) + var/list/from_objs = list() + var/list/select_types = list() + + switch(query_tree[1]) + if("explain") + SDQL_testout(query_tree["explain"]) + return + + if("call") + if("on" in query_tree) + select_types = query_tree["on"] + else + return + + if("select", "delete", "update") + select_types = query_tree[query_tree[1]] + + + from_objs = SDQL_from_objs(query_tree["from"]) + CHECK_TICK + + var/list/objs = list() + + for(var/type in select_types) + objs += SDQL_get_all(type, from_objs) + CHECK_TICK + + if("where" in query_tree) + var/objs_temp = objs + objs = list() + for(var/datum/d in objs_temp) + if(SDQL_expression(d, query_tree["where"])) + objs += d + CHECK_TICK + + switch(query_tree[1]) + if("call") + for(var/datum/d in objs) + SDQL_var(d, query_tree["call"][1], source = d) + CHECK_TICK + + if("delete") + for(var/datum/d in objs) + qdel(d) + CHECK_TICK + + if("select") + var/text = "" + for(var/datum/t in objs) + text += "\ref[t]" + if(istype(t, /atom)) + var/atom/a = t + + if(a.x) + text += ": [t] at ([a.x], [a.y], [a.z])
            " + + else if(a.loc && a.loc.x) + text += ": [t] in [a.loc] at ([a.loc.x], [a.loc.y], [a.loc.z])
            " + + else + text += ": [t]
            " + + else + text += ": [t]
            " + CHECK_TICK + if(!text) + text = "No results found." + show_browser(usr, text, "window=SDQL-result") + + if("update") + if("set" in query_tree) + var/list/set_list = query_tree["set"] + for(var/datum/d in objs) + for(var/list/sets in set_list) + var/datum/temp = d + var/i = 0 + for(var/v in sets) + if(++i == sets.len) + if(istype(temp, /turf) && (v == "x" || v == "y" || v == "z")) + break + + temp.SDQL_update(v, SDQL_expression(d, set_list[sets])) + break + + if(temp.vars.Find(v) && (istype(temp.vars[v], /datum) || istype(temp.vars[v], /client))) + temp = temp.vars[v] + + else + break + + CHECK_TICK + + to_chat(usr, "Query executed on [objs.len] object\s.") + catch(var/exception/e) + to_chat(usr, "An exception has occured during the execution of your query and your query has been aborted.") + to_chat(usr, "exception name: [e.name]") + to_chat(usr, "file/line: [e.file]/[e.line]") + return + +/proc/SDQL_parse(list/query_list) + var/datum/SDQL_parser/parser = new() + var/list/querys = list() + var/list/query_tree = list() + var/pos = 1 + var/querys_pos = 1 + var/do_parse = 0 + for(var/val in query_list) + if(val == ";") + do_parse = 1 + else if(pos >= query_list.len) + query_tree += val + do_parse = 1 + if(do_parse) + parser.query = query_tree + var/list/parsed_tree + parsed_tree = parser.parse() + if(parsed_tree.len > 0) + querys.len = querys_pos + querys[querys_pos] = parsed_tree + querys_pos++ + else //There was an error so don't run anything, and tell the user which query has errored. + to_chat(usr, "Parsing error on [querys_pos]\th query. Nothing was executed.") + return list() + query_tree = list() + do_parse = 0 + else + query_tree += val + pos++ + + qdel(parser) + + return querys + + + +/proc/SDQL_testout(list/query_tree, indent = 0) + var/spaces = "" + for(var/s = 0, s < indent, s++) + spaces += "    " + + for(var/item in query_tree) + if(istype(item, /list)) + to_chat(usr, "[spaces](") + SDQL_testout(item, indent + 1) + to_chat(usr, "[spaces])") + + else + to_chat(usr, "[spaces][item]") + + if(!isnum(item) && query_tree[item]) + + if(istype(query_tree[item], /list)) + to_chat(usr, "[spaces]    (") + SDQL_testout(query_tree[item], indent + 2) + to_chat(usr, "[spaces]    )") + + else + to_chat(usr, "[spaces]    [query_tree[item]]") + +/proc/SDQL_from_objs(list/tree) + if("world" in tree) + return world + + return SDQL_expression(world, tree) + + +/proc/SDQL_get_all(type, location) + var/list/out = list() + + // If only a single object got returned, wrap it into a list so the for loops run on it. + if (!islist(location) && location != world) + location = list(location) + + type = text2path(type) + + if(ispath(type, /mob)) + for(var/mob/d in location) + if(istype(d, type)) + out += d + + else if(ispath(type, /turf)) + for(var/turf/d in location) + if(istype(d, type)) + out += d + + else if(ispath(type, /obj)) + for(var/obj/d in location) + if(istype(d, type)) + out += d + + else if(ispath(type, /area)) + for(var/area/d in location) + if(istype(d, type)) + out += d + + else if(ispath(type, /atom)) + for(var/atom/d in location) + if(istype(d, type)) + out += d + + else + for(var/datum/d in location) + if(istype(d, type)) + out += d + + return out + + +/proc/SDQL_expression(datum/object, list/expression, start = 1) + var/result = 0 + var/val + + for(var/i = start, i <= expression.len, i++) + var/op = "" + + if(i > start) + op = expression[i] + i++ + + var/list/ret = SDQL_value(object, expression, i) + val = ret["val"] + i = ret["i"] + + if(op != "") + switch(op) + if("+") + result += val + if("-") + result -= val + if("*") + result *= val + if("/") + result /= val + if("&") + result &= val + if("|") + result |= val + if("^") + result ^= val + if("=", "==") + result = (result == val) + if("!=", "<>") + result = (result != val) + if("<") + result = (result < val) + if("<=") + result = (result <= val) + if(">") + result = (result > val) + if(">=") + result = (result >= val) + if("and", "&&") + result = (result && val) + if("or", "||") + result = (result || val) + else + to_chat(usr, "SDQL2: Unknown op [op]") + result = null + else + result = val + + return result + +/proc/SDQL_value(datum/object, list/expression, start = 1) + var/i = start + var/val = null + + if(i > expression.len) + return list("val" = null, "i" = i) + + if(istype(expression[i], /list)) + val = SDQL_expression(object, expression[i]) + + else if(expression[i] == "!") + var/list/ret = SDQL_value(object, expression, i + 1) + val = !ret["val"] + i = ret["i"] + + else if(expression[i] == "~") + var/list/ret = SDQL_value(object, expression, i + 1) + val = ~ret["val"] + i = ret["i"] + + else if(expression[i] == "-") + var/list/ret = SDQL_value(object, expression, i + 1) + val = -ret["val"] + i = ret["i"] + + else if(expression[i] == "null") + val = null + + else if(isnum(expression[i])) + val = expression[i] + + else if(copytext(expression[i], 1, 2) in list("'", "\"")) + val = copytext(expression[i], 2, length(expression[i])) + + else if(expression[i] == "\[") + var/list/expressions_list = expression[++i] + val = list() + for(var/list/expression_list in expressions_list) + var/result = SDQL_expression(object, expression_list) + var/assoc + if (expressions_list[expression_list] != null) + assoc = SDQL_expression(object, expressions_list[expression_list]) + + if (assoc != null) + // Need to insert the key like this to prevent duplicate keys fucking up. + var/list/dummy = list() + dummy[result] = assoc + result = dummy + + val += result + + else + val = SDQL_var(object, expression, i, object) + i = expression.len + + return list("val" = val, "i" = i) + +/proc/SDQL_var(datum/object, list/expression, start = 1, source) + var/v + var/static/list/exclude = list("usr", "src", "marked", "global") + var/long = start < expression.len + + if (object == world && (!long || expression[start + 1] == ".") && !(expression[start] in exclude)) + v = readglobal(expression[start]) + + else if (expression [start] == "{" && long) + if (lowertext(copytext(expression[start + 1], 1, 3)) != "0x") + to_chat(usr, "Invalid pointer syntax: [expression[start + 1]]") + return null + v = locate("\[[expression[start + 1]]]") + if (!v) + to_chat(usr, "Invalid pointer: [expression[start + 1]]") + return null + start++ + + else if ((!long || expression[start + 1] == ".") && (expression[start] in object.vars)) + v = object.vars[expression[start]] + + else if (long && expression[start + 1] == ":" && hascall(object, expression[start])) + v = expression[start] + + else if (!long || expression[start + 1] == ".") + switch(expression[start]) + if("usr") + v = usr + if("src") + v = source + if("marked") + if(usr.client && usr.client.holder && usr.client.holder.marked_datum()) + v = usr.client.holder.marked_datum() + else + return null + if("global") + v = world // World is mostly a token, really. + else + return null + + else if (object == world) // Shitty ass hack kill me. + v = expression[start] + + if(long) + if (expression[start + 1] == ".") + return SDQL_var(v, expression[start + 2], source = source) + + else if (expression[start + 1] == ":") + return SDQL_function(object, v, expression[start + 2], source) + + else if (expression[start + 1] == "\[" && islist(v)) + var/list/L = v + var/index = SDQL_expression(source, expression[start + 2]) + if (isnum(index) && (!IsInteger(index) || L.len < index)) + to_chat(usr, "Invalid list index: [index]") + return null + + return L[index] + + return v + + +/proc/SDQL_function(var/datum/object, var/procname, var/list/arguments, source) + set waitfor = FALSE + + var/list/new_args = list() + for(var/arg in arguments) + new_args[++new_args.len] = SDQL_expression(source, arg) + + if (object == world) // Global proc. + procname = "/proc/[procname]" + return call(procname)(arglist(new_args)) + + return call(object, procname)(arglist(new_args)) // Spawn in case the function sleeps. + + +/proc/SDQL2_tokenize(query_text) + + + var/list/whitespace = list(" ", "\n", "\t") + var/list/single = list("(", ")", ",", "+", "-", ".", "\[", "]", "{", "}", ";", ":") + var/list/multi = list( + "=" = list("", "="), + "<" = list("", "=", ">"), + ">" = list("", "="), + "!" = list("", "=")) + + var/word = "" + var/list/query_list = list() + var/len = length(query_text) + + for(var/i = 1, i <= len, i++) + var/char = copytext(query_text, i, i + 1) + + if(char in whitespace) + if(word != "") + query_list += word + word = "" + + else if(char in single) + if(word != "") + query_list += word + word = "" + + query_list += char + + else if(char in multi) + if(word != "") + query_list += word + word = "" + + var/char2 = copytext(query_text, i + 1, i + 2) + + if(char2 in multi[char]) + query_list += "[char][char2]" + i++ + + else + query_list += char + + else if(char == "'") + if(word != "") + to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unexpected ' in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again.") + return null + + word = "'" + + for(i++, i <= len, i++) + char = copytext(query_text, i, i + 1) + + if(char == "'") + if(copytext(query_text, i + 1, i + 2) == "'") + word += "'" + i++ + + else + break + + else + word += char + + if(i > len) + to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unmatched ' in query: \"[query_text]\". Please check your syntax, and try again.") + return null + + query_list += "[word]'" + word = "" + + else if(char == "\"") + if(word != "") + to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unexpected \" in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again.") + return null + + word = "\"" + + for(i++, i <= len, i++) + char = copytext(query_text, i, i + 1) + + if(char == "\"") + if(copytext(query_text, i + 1, i + 2) == "'") + word += "\"" + i++ + + else + break + + else + word += char + + if(i > len) + to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unmatched \" in query: \"[query_text]\". Please check your syntax, and try again.") + return null + + query_list += "[word]\"" + word = "" + + else + word += char + + if(word != "") + query_list += word + return query_list \ No newline at end of file diff --git a/code/modules/admin/verbs/SDQL_2/SDQL_2_parser.dm b/code/modules/admin/verbs/SDQL_2/SDQL_2_parser.dm new file mode 100644 index 00000000..543a8c21 --- /dev/null +++ b/code/modules/admin/verbs/SDQL_2/SDQL_2_parser.dm @@ -0,0 +1,586 @@ +//I'm pretty sure that this is a recursive [s]descent[/s] ascent parser. + + +//Spec + +////////// +// +// query : select_query | delete_query | update_query | call_query | explain +// explain : 'EXPLAIN' query +// +// select_query : 'SELECT' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression] +// delete_query : 'DELETE' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression] +// update_query : 'UPDATE' select_list [('FROM' | 'IN') from_list] 'SET' assignments ['WHERE' bool_expression] +// call_query : 'CALL' call_function ['ON' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]] +// +// select_list : select_item [',' select_list] +// select_item : '*' | select_function | object_type +// select_function : count_function +// count_function : 'COUNT' '(' '*' ')' | 'COUNT' '(' object_types ')' +// +// from_list : from_item [',' from_list] +// from_item : 'world' | object_type +// +// call_function : ['(' [arguments] ')'] +// arguments : expression [',' arguments] +// +// object_type : | string +// +// assignments : assignment, [',' assignments] +// assignment : '=' expression +// variable : | '.' variable | '[' ']' | '[' ']' '.' variable +// +// bool_expression : expression comparitor expression [bool_operator bool_expression] +// expression : ( unary_expression | '(' expression ')' | value ) [binary_operator expression] +// unary_expression : unary_operator ( unary_expression | value | '(' expression ')' ) +// comparitor : '=' | '==' | '!=' | '<>' | '<' | '<=' | '>' | '>=' +// value : variable | string | number | 'null' +// unary_operator : '!' | '-' | '~' +// binary_operator : comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^' +// bool_operator : 'AND' | '&&' | 'OR' | '||' +// +// string : ''' ''' | '"' '"' +// number : +// +////////// + +/datum/SDQL_parser + var/query_type + var/error = 0 + + var/list/query + var/list/tree + + var/list/select_functions = list("count") + var/list/boolean_operators = list("and", "or", "&&", "||") + var/list/unary_operators = list("!", "-", "~") + var/list/binary_operators = list("+", "-", "/", "*", "&", "|", "^") + var/list/comparitors = list("=", "==", "!=", "<>", "<", "<=", ">", ">=") + + + +/datum/SDQL_parser/New(query_list) + query = query_list + + + +/datum/SDQL_parser/proc/parse_error(error_message) + error = 1 + to_chat(usr, "SQDL2 Parsing Error: [error_message]") + return query.len + 1 + +/datum/SDQL_parser/proc/parse() + tree = list() + query(1, tree) + + if(error) + return list() + else + return tree + +/datum/SDQL_parser/proc/token(i) + if(i <= query.len) + return query[i] + + else + return null + +/datum/SDQL_parser/proc/tokens(i, num) + if(i + num <= query.len) + return query.Copy(i, i + num) + + else + return null + +/datum/SDQL_parser/proc/tokenl(i) + return lowertext(token(i)) + +//query: select_query | delete_query | update_query +/datum/SDQL_parser/proc/query(i, list/node) + query_type = tokenl(i) + + switch(query_type) + if("select") + select_query(i, node) + + if("delete") + delete_query(i, node) + + if("update") + update_query(i, node) + + if("call") + call_query(i, node) + + if("explain") + node += "explain" + node["explain"] = list() + query(i + 1, node["explain"]) + + +// select_query: 'SELECT' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression] +/datum/SDQL_parser/proc/select_query(i, list/node) + var/list/select = list() + i = select_list(i + 1, select) + + node += "select" + node["select"] = select + + selectors(i, node) + + return i + + +//delete_query: 'DELETE' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression] +/datum/SDQL_parser/proc/delete_query(i, list/node) + var/list/select = list() + i = select_list(i + 1, select) + + node += "delete" + node["delete"] = select + + selectors(i, node) + + return i + + +//update_query: 'UPDATE' select_list [('FROM' | 'IN') from_list] 'SET' assignments ['WHERE' bool_expression] +/datum/SDQL_parser/proc/update_query(i, list/node) + var/list/select = list() + i = select_list(i + 1, select) + + node += "update" + node["update"] = select + + if(tokenl(i) != "set") + i = parse_error("UPDATE has misplaced SET") + + var/list/set_assignments = list() + i = assignments(i + 1, set_assignments) + + node += "set" + node["set"] = set_assignments + + selectors(i, node) + + return i + + +//call_query: 'CALL' call_function ['ON' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]] +/datum/SDQL_parser/proc/call_query(i, list/node) + var/list/func = list() + i = variable(i + 1, func) // Yes technically does anything variable() matches but I don't care, if admins fuck up this badly then they shouldn't be allowed near SDQL. + + node += "call" + node["call"] = func + + if(tokenl(i) != "on") + return i + + var/list/select = list() + i = select_list(i + 1, select) + + node += "on" + node["on"] = select + + selectors(i, node) + + return i + +//select_list: select_item [',' select_list] +/datum/SDQL_parser/proc/select_list(i, list/node) + i = select_item(i, node) + + if(token(i) == ",") + i = select_list(i + 1, node) + + return i + +//assignments: assignment, [',' assignments] +/datum/SDQL_parser/proc/assignments(i, list/node) + i = assignment(i, node) + + if(token(i) == ",") + i = assignments(i + 1, node) + + return i + + +//select_item: '*' | select_function | object_type +/datum/SDQL_parser/proc/select_item(i, list/node) + + if(token(i) == "*") + node += "*" + i++ + + else if(tokenl(i) in select_functions) + i = select_function(i, node) + + else + i = object_type(i, node) + + return i + +// Standardized method for handling the IN/FROM and WHERE options. +/datum/SDQL_parser/proc/selectors(i, list/node) + while (token(i)) + var/tok = tokenl(i) + if (tok in list("from", "in")) + var/list/from = list() + i = from_item(i + 1, from) + + node["from"] = from + continue + + if (tok == "where") + var/list/where = list() + i = bool_expression(i + 1, where) + + node["where"] = where + continue + + parse_error("Expected either FROM, IN or WHERE token, found [token(i)] instead.") + return i + 1 + + if (!node.Find("from")) + node["from"] = list("world") + + return i + +//from_item: 'world' | object_type +/datum/SDQL_parser/proc/from_item(i, list/node) + if(token(i) == "world") + node += "world" + i++ + + else + i = expression(i, node) + + return i + + +//bool_expression: expression [bool_operator bool_expression] +/datum/SDQL_parser/proc/bool_expression(i, list/node) + + var/list/bool = list() + i = expression(i, bool) + + node[++node.len] = bool + + if(tokenl(i) in boolean_operators) + i = bool_operator(i, node) + i = bool_expression(i, node) + + return i + + +//assignment: '=' expression +/datum/SDQL_parser/proc/assignment(var/i, var/list/node, var/list/assignment_list = list()) + assignment_list += token(i) + + if(token(i + 1) == ".") + i = assignment(i + 2, node, assignment_list) + + else if(token(i + 1) == "=") + var/exp_list = list() + node[assignment_list] = exp_list + + i = expression(i + 2, exp_list) + + else + parse_error("Assignment expected, but no = found") + + return i + + +//variable: | '.' variable | '[' ']' | '[' ']' '.' variable +/datum/SDQL_parser/proc/variable(i, list/node) + var/list/L = list(token(i)) + node[++node.len] = L + + if(token(i) == "{") + L += token(i + 1) + i += 2 + + if(token(i) != "}") + parse_error("Missing } at end of pointer.") + + if(token(i + 1) == ".") + L += "." + i = variable(i + 2, L) + + else if (token(i + 1) == "(") // OH BOY PROC + var/list/arguments = list() + i = call_function(i, null, arguments) + L += ":" + L[++L.len] = arguments + + else if (token(i + 1) == "\[") + var/list/expression = list() + i = expression(i + 2, expression) + if (token(i) != "]") + parse_error("Missing ] at the end of list access.") + + L += "\[" + L[++L.len] = expression + i++ + + else + i++ + + return i + + +//object_type: | string +/datum/SDQL_parser/proc/object_type(i, list/node) + + if(copytext(token(i), 1, 2) == "/") + node += token(i) + + else + i = string(i, node) + + return i + 1 + + +//comparitor: '=' | '==' | '!=' | '<>' | '<' | '<=' | '>' | '>=' +/datum/SDQL_parser/proc/comparitor(i, list/node) + + if(token(i) in list("=", "==", "!=", "<>", "<", "<=", ">", ">=")) + node += token(i) + + else + parse_error("Unknown comparitor [token(i)]") + + return i + 1 + + +//bool_operator: 'AND' | '&&' | 'OR' | '||' +/datum/SDQL_parser/proc/bool_operator(i, list/node) + + if(tokenl(i) in list("and", "or", "&&", "||")) + node += token(i) + + else + parse_error("Unknown comparitor [token(i)]") + + return i + 1 + + +//string: ''' ''' | '"' '"' +/datum/SDQL_parser/proc/string(i, list/node) + + if(copytext(token(i), 1, 2) in list("'", "\"")) + node += token(i) + + else + parse_error("Expected string but found '[token(i)]'") + + return i + 1 + +//array: '[' expression, expression, ... ']' +/datum/SDQL_parser/proc/array(var/i, var/list/node) + // Arrays get turned into this: list("[", list(exp_1a = exp_1b, ...), ...), "[" is to mark the next node as an array. + if(copytext(token(i), 1, 2) != "\[") + parse_error("Expected an array but found '[token(i)]'") + return i + 1 + + node += token(i) // Add the "[" + + var/list/expression_list = list() + + i++ + if(token(i) != "]") + var/list/temp_expression_list = list() + var/tok + do + tok = token(i) + if (tok == "," || tok == ":") + if (temp_expression_list == null) + parse_error("Found ',' or ':' without expression in an array.") + return i + 1 + + expression_list[++expression_list.len] = temp_expression_list + temp_expression_list = null + if (tok == ":") + temp_expression_list = list() + i = expression(i + 1, temp_expression_list) + expression_list[expression_list[expression_list.len]] = temp_expression_list + temp_expression_list = null + tok = token(i) + if (tok != ",") + if (tok == "]") + break + + parse_error("Expected ',' or ']' after array assoc value, but found '[token(i)]'") + return i + + + i++ + continue + + temp_expression_list = list() + i = expression(i, temp_expression_list) + + while(token(i) && token(i) != "]") + + if (temp_expression_list) + expression_list[++expression_list.len] = temp_expression_list + + node[++node.len] = expression_list + + return i + 1 + +//call_function: ['(' [arguments] ')'] +/datum/SDQL_parser/proc/call_function(i, list/node, list/arguments) + if(length(tokenl(i))) + var/procname = "" + if(tokenl(i) == "global" && token(i + 1) == ".") // Global proc. + i += 2 + procname = "global." + node += procname + token(i++) + if(token(i) != "(") + parse_error("Expected ( but found '[token(i)]'") + + else if(token(i + 1) != ")") + var/list/temp_expression_list = list() + do + i = expression(i + 1, temp_expression_list) + if(token(i) == ",") + arguments[++arguments.len] = temp_expression_list + temp_expression_list = list() + continue + + while(token(i) && token(i) != ")") + + arguments[++arguments.len] = temp_expression_list // The code this is copy pasted from won't be executed when it's the last param, this fixes that. + else + i++ + else + parse_error("Expected a function but found nothing") + return i + 1 + + +//select_function: count_function +/datum/SDQL_parser/proc/select_function(i, list/node) + + parse_error("Sorry, function calls aren't available yet") + + return i + + +//expression: ( unary_expression | '(' expression ')' | value ) [binary_operator expression] +/datum/SDQL_parser/proc/expression(i, list/node) + + if(token(i) in unary_operators) + i = unary_expression(i, node) + + else if(token(i) == "(") + var/list/expr = list() + + i = expression(i + 1, expr) + + if(token(i) != ")") + parse_error("Missing ) at end of expression.") + + else + i++ + + node[++node.len] = expr + + else + i = value(i, node) + + if(token(i) in binary_operators) + i = binary_operator(i, node) + i = expression(i, node) + + else if(token(i) in comparitors) + i = binary_operator(i, node) + + var/list/rhs = list() + i = expression(i, rhs) + + node[++node.len] = rhs + + + return i + + +//unary_expression: unary_operator ( unary_expression | value | '(' expression ')' ) +/datum/SDQL_parser/proc/unary_expression(i, list/node) + + if(token(i) in unary_operators) + var/list/unary_exp = list() + + unary_exp += token(i) + i++ + + if(token(i) in unary_operators) + i = unary_expression(i, unary_exp) + + else if(token(i) == "(") + var/list/expr = list() + + i = expression(i + 1, expr) + + if(token(i) != ")") + parse_error("Missing ) at end of expression.") + + else + i++ + + unary_exp[++unary_exp.len] = expr + + else + i = value(i, unary_exp) + + node[++node.len] = unary_exp + + + else + parse_error("Expected unary operator but found '[token(i)]'") + + return i + + +//binary_operator: comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^' +/datum/SDQL_parser/proc/binary_operator(i, list/node) + + if(token(i) in (binary_operators + comparitors)) + node += token(i) + + else + parse_error("Unknown binary operator [token(i)]") + + return i + 1 + + +//value: variable | string | number | 'null' +/datum/SDQL_parser/proc/value(i, list/node) + if(token(i) == "null") + node += "null" + i++ + + else if(lowertext(copytext(token(i), 1, 3)) == "0x" && isnum(hex2num(copytext(token(i), 3)))) + node += hex2num(copytext(token(i), 3)) + i++ + + else if(isnum(text2num(token(i)))) + node += text2num(token(i)) + i++ + + else if(copytext(token(i), 1, 2) in list("'", "\"")) + i = string(i, node) + + else if(copytext(token(i), 1, 2) == "\[") // Start a list. + i = array(i, node) + else + i = variable(i, node) + + return i + + + + +/*EXPLAIN SELECT * WHERE 42 = 6 * 9 OR val = - 5 == 7*/ \ No newline at end of file diff --git a/code/modules/admin/verbs/SDQL_2/SDQL_2_std.dm b/code/modules/admin/verbs/SDQL_2/SDQL_2_std.dm new file mode 100644 index 00000000..8d14628a --- /dev/null +++ b/code/modules/admin/verbs/SDQL_2/SDQL_2_std.dm @@ -0,0 +1,184 @@ +// Wrappers for BYOND default procs which can't directly be called by call(). + +/proc/_abs(A) + return abs(A) + +/proc/_animate(var/atom/A, var/variables, var/time = 10, var/loop = 1, var/easing = LINEAR_EASING) + var/atom/movable/I = new + I.appearance = A.appearance + + // The appearance churn is real. + // WILL perform like shit until we get 511 and we get mutable appearances. + for (var/variable in variables) + I.vars[variable] = variables[variable] + + animate(A, appearance = I.appearance, time, loop, easing) + +/proc/_acrccos(A) + return arccos(A) + +/proc/_arcsin(A) + return arcsin(A) + +/proc/_ascii2text(A) + return ascii2text(A) + +/proc/_block(Start, End) + return block(Start, End) + +/proc/_ckey(Key) + return ckey(Key) + +/proc/_ckeyEx(Key) + return ckeyEx(Key) + +/proc/_copytext(T, Start = 1, End = 0) + return copytext(T, Start, End) + +/proc/_cos(X) + return cos(X) + +/proc/_get_dir(Loc1, Loc2) + return get_dir(Loc1, Loc2) + +/proc/_get_dist(Loc1, Loc2) + return get_dist(Loc1, Loc2) + +/proc/_get_step(Ref, Dir) + return get_step(Ref, Dir) + +/proc/_hearers(Depth = world.view, Center = usr) + return hearers(Depth, Center) + +/proc/_image(icon, loc, icon_state, layer, dir) + return image(icon, loc, icon_state, layer, dir) + +/proc/_length(E) + return length(E) + +/proc/_link(thing, url) + send_link(thing, url) + +/proc/_locate(X, Y, Z) + if (isnull(Y)) // Assuming that it's only a single-argument call. + return locate(X) + + return locate(X, Y, Z) + +/proc/_log(X, Y) + return log(X, Y) + +/proc/_lowertext(T) + return lowertext(T) + +/proc/_matrix(a, b, c, d, e, f) + return matrix(a, b, c, d, e, f) + +/proc/_max(...) + return max(arglist(args)) + +/proc/_md5(T) + return md5(T) + +/proc/_min(...) + return min(arglist(args)) + +/proc/_new(type, arguments) + return new type (arglist(arguments)) + +/proc/_num2text(N, SigFig = 6) + return num2text(N, SigFig) + +/proc/_ohearers(Dist, Center = usr) + return ohearers(Dist, Center) + +/proc/_orange(Dist, Center = usr) + return orange(Dist, Center) + +/proc/_output(thing, msg, control) + send_output(thing, msg, control) + +/proc/_oview(Dist, Center = usr) + return oview(Dist, Center) + +/proc/_oviewers(Dist, Center = usr) + return oviewers(Dist, Center) + +/proc/_params2list(Params) + return params2list(Params) + +/proc/_pick(...) + return pick(arglist(args)) + +/proc/_prob(P) + return prob(P) + +/proc/_rand(L = 0, H = 1) + return rand(L, H) + +/proc/_range(Dist, Center = usr) + return range(Dist, Center) + +/proc/_regex(pattern, flags) + return regex(pattern, flags) + +/proc/_REGEX_QUOTE(text) + return REGEX_QUOTE(text) + +/proc/_REGEX_QUOTE_REPLACEMENT(text) + return REGEX_QUOTE_REPLACEMENT(text) + +/proc/_replacetext(Haystack, Needle, Replacement, Start = 1,End = 0) + return replacetext(Haystack, Needle, Replacement, Start, End) + +/proc/_replacetextEx(Haystack, Needle, Replacement, Start = 1,End = 0) + return replacetextEx(Haystack, Needle, Replacement, Start, End) + +/proc/_rgb(R, G, B) + return rgb(R, G, B) + +/proc/_rgba(R, G, B, A) + return rgb(R, G, B, A) + +/proc/_roll(dice) + return roll(dice) + +/proc/_round(A, B = 1) + return round(A, B) + +/proc/_sin(X) + return sin(X) + +/proc/_step(Ref, Dir, Speed = 0) + return step(Ref, Dir, Speed) + + +/proc/_list_add(var/list/L, ...) + if (args.len < 2) + return + + L += args.Copy(2) + +/proc/_list_copy(var/list/L, var/Start = 1, var/End = 0) + return L.Copy(Start, End) + +/proc/_list_cut(var/list/L, var/Start = 1, var/End = 0) + L.Cut(Start, End) + +/proc/_list_find(var/list/L, var/Elem, var/Start = 1, var/End = 0) + return L.Find(Elem, Start, End) + +/proc/_list_insert(var/list/L, var/Index, var/Item) + return L.Insert(Index, Item) + +/proc/_list_join(var/list/L, var/Glue, var/Start = 0, var/End = 1) + return L.Join(Glue, Start, End) + +/proc/_list_remove(var/list/L, ...) + if (args.len < 2) + return + + L -= args.Copy(2) + +/proc/_list_swap(var/list/L, var/Index1, var/Index2) + L.Swap(Index1, Index2) \ No newline at end of file diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm new file mode 100644 index 00000000..3f72e3d1 --- /dev/null +++ b/code/modules/admin/verbs/adminhelp.dm @@ -0,0 +1,145 @@ + +//This is a list of words which are ignored by the parser when comparing message contents for names. MUST BE IN LOWER CASE! +var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","alien","as") + +/proc/generate_ahelp_key_words(var/mob/mob, var/msg) + var/list/surnames = list() + var/list/forenames = list() + var/list/ckeys = list() + var/pure_msg = msg + //explode the input msg into a list + var/list/msglist = splittext(msg, " ") + + for(var/mob/M in SSmobs.mob_list) + var/list/indexing = list(M.real_name, M.name) + if(M.mind) indexing += M.mind.name + + for(var/string in indexing) + var/list/L = splittext(string, " ") + var/surname_found = 0 + //surnames + for(var/i=L.len, i>=1, i--) + var/word = ckey(L[i]) + if(word) + surnames[word] = M + surname_found = i + break + //forenames + for(var/i=1, iError: Admin-PM: You cannot send adminhelps (Muted).") + return + + adminhelped = 1 //Determines if they get the message to reply by clicking the name. + + + //clean the input msg + if(!msg) + return + msg = sanitize(msg) + if(!msg) + return + var/original_msg = msg + + + if(!mob) //this doesn't happen + return + + //generate keywords lookup + msg = generate_ahelp_key_words(mob, msg) + + // handle ticket + var/datum/client_lite/client_lite = client_repository.get_lite_client(src) + var/datum/ticket/ticket = get_open_ticket_by_client(client_lite) + if(!ticket) + ticket = new /datum/ticket(client_lite) + else if(ticket.status == TICKET_ASSIGNED) + // manually check that the target client exists here as to not spam the usr for each logged out admin on the ticket + var/admin_found = 0 + for(var/datum/client_lite/admin in ticket.assigned_admins) + var/client/admin_client = client_by_ckey(admin.ckey) + if(admin_client) + admin_found = 1 + src.cmd_admin_pm(admin_client, original_msg, ticket) + break + if(!admin_found) + to_chat(src, "Error: Private-Message: Client not found. They may have lost connection, so please be patient!") + return + + ticket.msgs += new /datum/ticket_msg(src.ckey, null, original_msg) + update_ticket_panels() + + + //Options bar: mob, details ( admin = 2, dev = 3, mentor = 4, character name (0 = just ckey, 1 = ckey and character name), link? (0 no don't make it a link, 1 do so), + // highlight special roles (0 = everyone has same looking name, 1 = antags / special roles get a golden name) + + var/mentor_msg = "HELP: [get_options_bar(mob, 4, 1, 1, 0, ticket)] ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE): [msg]" + msg = "HELP: [get_options_bar(mob, 2, 1, 1, 1, ticket)] ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE): [msg]" + + var/admin_number_afk = 0 + + for(var/client/X in GLOB.admins) + if((R_ADMIN|R_MOD|R_MENTOR) & X.holder.rights) + if(X.is_afk()) + admin_number_afk++ + if(X.get_preference_value(/datum/client_preference/staff/play_adminhelp_ping) == GLOB.PREF_HEAR) + sound_to(X, 'sound/effects/adminhelp.ogg') + if(X.holder.rights == R_MENTOR) + to_chat(X, mentor_msg)// Mentors won't see coloring of names on people with special_roles (Antags, etc.) + else + to_chat(X, msg) + //show it to the person adminhelping too + to_chat(src, "PM to-Staff (CLOSE): [original_msg]") + var/admin_number_present = GLOB.admins.len - admin_number_afk + log_admin("HELP: [key_name(src)]: [original_msg] - heard by [admin_number_present] non-AFK admins.") + if(admin_number_present <= 0) + adminmsg2adminirc(src, null, "[html_decode(original_msg)] - !![admin_number_afk ? "All admins AFK ([admin_number_afk])" : "No admins online"]!!") + else + adminmsg2adminirc(src, null, "[html_decode(original_msg)]") + + feedback_add_details("admin_verb","AH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm new file mode 100644 index 00000000..ae84019d --- /dev/null +++ b/code/modules/admin/verbs/adminjump.dm @@ -0,0 +1,152 @@ +/mob/proc/jumpTo(var/location) + forceMove(location) + +/mob/observer/ghost/jumpTo() + stop_following() + ..() + +/client/proc/Jump(var/selected_area in area_repository.get_areas_by_z_level()) + set name = "Jump to Area" + set desc = "Area to jump to" + set category = "Admin" + if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) + return + if(!config.allow_admin_jump) + return alert("Admin jumping disabled") + + var/list/areas = area_repository.get_areas_by_z_level() + var/area/A = areas[selected_area] + mob.jumpTo(pick(get_area_turfs(A))) + log_and_message_admins("jumped to [A]") + feedback_add_details("admin_verb","JA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/jumptoturf(var/turf/T) + set name = "Jump to Turf" + set category = "Admin" + if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) + return + if(!config.allow_admin_jump) + return alert("Admin jumping disabled") + + log_and_message_admins("jumped to [T.x],[T.y],[T.z] in [T.loc]") + mob.jumpTo(T) + feedback_add_details("admin_verb","JT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/jumptomob(var/mob/M in SSmobs.mob_list) + set category = "Admin" + set name = "Jump to Mob" + + if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) + return + + if(config.allow_admin_jump) + log_and_message_admins("jumped to [key_name(M)]") + if(mob) + var/turf/T = get_turf(M) + if(T && isturf(T)) + feedback_add_details("admin_verb","JM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + mob.jumpTo(T) + else + to_chat(mob, "This mob is not located in the game world.") + else + alert("Admin jumping disabled") + +/client/proc/jumptocoord(tx as num, ty as num, tz as num) + set category = "Admin" + set name = "Jump to Coordinate" + + if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) + return + + if(!config.allow_admin_jump) + alert("Admin jumping disabled") + return + if(!mob) + return + + var/turf/T = locate(tx, ty, tz) + if(!T) + return + mob.jumpTo(T) + + feedback_add_details("admin_verb","JC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + log_and_message_admins("jumped to coordinates [tx], [ty], [tz]") + +/proc/sorted_client_keys() + return sortKey(GLOB.clients.Copy()) + +/client/proc/jumptokey(client/C in sorted_client_keys()) + set category = "Admin" + set name = "Jump to Key" + + if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) + return + + if(config.allow_admin_jump) + if(!istype(C)) + to_chat(usr, "[C] is not a client, somehow.") + return + + var/mob/M = C.mob + log_and_message_admins("jumped to [key_name(M)]") + mob.jumpTo(get_turf(M)) + feedback_add_details("admin_verb","JK") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + else + alert("Admin jumping disabled") + +/client/proc/Getmob(var/mob/M in SSmobs.mob_list) + set category = "Admin" + set name = "Get Mob" + set desc = "Mob to teleport" + if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) + return + if(config.allow_admin_jump) + log_and_message_admins("teleported [key_name(M)] to self.") + M.jumpTo(get_turf(mob)) + feedback_add_details("admin_verb","GM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + else + alert("Admin jumping disabled") + +/client/proc/Getkey() + set category = "Admin" + set name = "Get Key" + set desc = "Key to teleport" + + if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) + return + + if(config.allow_admin_jump) + var/list/keys = list() + for(var/mob/M in GLOB.player_list) + keys += M.client + var/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in sortKey(keys) + if(!selection) + return + var/mob/M = selection:mob + + if(!M) + return + log_and_message_admins("teleported [key_name(M)] to self.") + if(M) + M.jumpTo(get_turf(mob)) + feedback_add_details("admin_verb","GK") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + else + alert("Admin jumping disabled") + +/client/proc/sendmob(var/mob/M in sortmobs()) + set category = "Admin" + set name = "Send Mob" + if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) + return + if(!config.allow_admin_jump) + alert("Admin jumping disabled") + return + + var/list/areas = area_repository.get_areas_by_name() + var/area/A = input(usr, "Pick an area.", "Pick an area") as null|anything in areas + A = A ? areas[A] : A + if(A) + M.jumpTo(pick(get_area_turfs(A))) + feedback_add_details("admin_verb","SMOB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + log_and_message_admins("teleported [key_name(M)] to [A].") + diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm new file mode 100644 index 00000000..32454b71 --- /dev/null +++ b/code/modules/admin/verbs/adminpm.dm @@ -0,0 +1,187 @@ +//allows right clicking mobs to send an admin PM to their client, forwards the selected mob's client to cmd_admin_pm +/client/proc/cmd_admin_pm_context(mob/M as mob in SSmobs.mob_list) + set category = null + set name = "Admin PM Mob" + if(!holder) + to_chat(src, "Error: Admin-PM-Context: Only administrators may use this command.") + return + if( !ismob(M) || !M.client ) return + cmd_admin_pm(M.client,null) + feedback_add_details("admin_verb","APMM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +//shows a list of clients we could send PMs to, then forwards our choice to cmd_admin_pm +/client/proc/cmd_admin_pm_panel() + set category = "Admin" + set name = "Admin PM" + if(!holder) + to_chat(src, "Error: Admin-PM-Panel: Only administrators may use this command.") + return + var/list/client/targets[0] + for(var/client/T) + if(T.mob) + if(isnewplayer(T.mob)) + targets["(New Player) - [T]"] = T + else if(isghost(T.mob)) + targets["[T.mob.name](Ghost) - [T]"] = T + else + targets["[T.mob.real_name](as [T.mob.name]) - [T]"] = T + else + targets["(No Mob) - [T]"] = T + var/list/sorted = sortList(targets) + var/target = input(src,"To whom shall we send a message?","Admin PM",null) in sorted|null + cmd_admin_pm(targets[target],null) + feedback_add_details("admin_verb","APM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +//takes input from cmd_admin_pm_context, cmd_admin_pm_panel or /client/Topic and sends them a PM. +//Fetching a message if needed. src is the sender and C is the target client + +/client/proc/cmd_admin_pm(var/client/C, var/msg = null, var/datum/ticket/ticket = null) + if(prefs.muted & MUTE_ADMINHELP) + to_chat(src, "Error: Private-Message: You are unable to use PM-s (muted).") + return + + if(!istype(C,/client)) + if(holder) to_chat(src, "Error: Private-Message: Client not found.") + else to_chat(src, "Error: Private-Message: Client not found. They may have lost connection, so please be patient!") + return + + var/recieve_pm_type = "Player" + if(holder) + //mod PMs are maroon + //PMs sent from admins and mods display their rank + if(holder) + recieve_pm_type = holder.rank + + else if(C && !C.holder) + to_chat(src, "Error: Admin-PM: Non-admin to non-admin PM communication is forbidden.") + return + + msg = sanitize(msg) + + //get message text, limit it's length.and clean/escape html + if(!msg) + msg = input(src,"Message:", "Private message to [key_name(C, 0, holder ? 1 : 0)]") as text|null + + if(!msg) return + if(!C) + if(holder) to_chat(src, "Error: Private-Message: Client not found.") + else to_chat(src, "Error: Private-Message: Client not found. They may have lost connection, so try using an adminhelp!") + return + + msg = sanitize(msg) + + var/datum/client_lite/receiver_lite = client_repository.get_lite_client(C) + var/datum/client_lite/sender_lite = client_repository.get_lite_client(src) + + // searches for an open ticket, in case an outdated link was clicked + // I'm paranoid about the problems that could be caused by accidentally finding the wrong ticket, which is why this is strict + if(isnull(ticket)) + if(holder) + ticket = get_open_ticket_by_client(receiver_lite) // it's more likely an admin clicked a different PM link, so check admin -> player with ticket first + if(isnull(ticket) && C.holder) + ticket = get_open_ticket_by_client(sender_lite) // if still no dice, try an admin with ticket -> admin + else + ticket = get_open_ticket_by_client(sender_lite) // lastly, check player with ticket -> admin + + + if(isnull(ticket)) // finally, accept that no ticket exists + if(holder && sender_lite.ckey != receiver_lite.ckey) + ticket = new /datum/ticket(receiver_lite) + ticket.take(sender_lite) + else + to_chat(src, "You do not have an open ticket. Please use the adminhelp verb to open a ticket.") + return + else if(ticket.status != TICKET_ASSIGNED && sender_lite.ckey == ticket.owner.ckey) + to_chat(src, "Your ticket is not open for conversation. Please wait for an administrator to receive your adminhelp.") + return + + // if the sender is an admin and they're not assigned to the ticket, ask them if they want to take/join it, unless the admin is responding to their own ticket + if(holder && !(sender_lite.ckey in ticket.assigned_admin_ckeys())) + if(sender_lite.ckey != ticket.owner.ckey && !ticket.take(sender_lite)) + return + + var/recieve_message + + if(holder && !C.holder) + recieve_message = "-- Click the [recieve_pm_type]'s name to reply --\n" + if(C.adminhelped) + to_chat(C, recieve_message) + C.adminhelped = 0 + + //AdminPM popup for ApocStation and anybody else who wants to use it. Set it with POPUP_ADMIN_PM in config.txt ~Carn + if(config.popup_admin_pm) + spawn(0) //so we don't hold the caller proc up + var/sender = src + var/sendername = key + var/reply = sanitize(input(C, msg,"[recieve_pm_type] PM from [sendername]", "") as text|null) //show message and await a reply + if(C && reply) + if(sender) + C.cmd_admin_pm(sender,reply) //sender is still about, let's reply to them + else + adminhelp(reply) //sender has left, adminhelp instead + return + + var/sender_message = "" + create_text_tag("pm_out_alt", "PM", src) + " to [get_options_bar(C, holder ? 1 : 0, holder ? 1 : 0, 1)]" + if(holder) + sender_message += " ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE)" + sender_message += ": [generate_ahelp_key_words(mob, msg)]" + else + sender_message += ": [msg]" + sender_message += "" + to_chat(src, sender_message) + + var/receiver_message = "" + create_text_tag("pm_in", "", C) + " \[[recieve_pm_type] PM\] [get_options_bar(src, C.holder ? 1 : 0, C.holder ? 1 : 0, 1)]" + if(C.holder) + receiver_message += " ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE)" + receiver_message += ": [generate_ahelp_key_words(C.mob, msg)]" + else + receiver_message += ": [msg]" + receiver_message += "" + to_chat(C, receiver_message) + + //play the recieving admin the adminhelp sound (if they have them enabled) + //non-admins shouldn't be able to disable this + if(C.get_preference_value(/datum/client_preference/staff/play_adminhelp_ping) == GLOB.PREF_HEAR) + sound_to(C, 'sound/effects/adminhelp.ogg') + + log_admin("PM: [key_name(src)]->[key_name(C)]: [msg]") + adminmsg2adminirc(src, C, html_decode(msg)) + + ticket.msgs += new /datum/ticket_msg(src.ckey, C.ckey, msg) + update_ticket_panels() + + //we don't use message_admins here because the sender/receiver might get it too + for(var/client/X in GLOB.admins) + //check client/X is an admin and isn't the sender or recipient + if(X == C || X == src) + continue + if(X.key != key && X.key != C.key && (X.holder.rights & R_ADMIN|R_MOD|R_MENTOR)) + to_chat(X, "" + create_text_tag("pm_other", "PM:", X) + " [key_name(src, X, 0, ticket)] to [key_name(C, X, 0, ticket)] ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE): [msg]") + +/client/proc/cmd_admin_irc_pm(sender) + if(prefs.muted & MUTE_ADMINHELP) + to_chat(src, "Error: Private-Message: You are unable to use PM-s (muted).") + return + + var/msg = input(src,"Message:", "Reply private message to [sender] on IRC / 400 character limit") as text|null + + if(!msg) + return + + // Handled on Bot32's end, unsure about other bots +// if(length(msg) > 400) // TODO: if message length is over 400, divide it up into seperate messages, the message length restriction is based on IRC limitations. Probably easier to do this on the bots ends. +// to_chat(src, "Your message was not sent because it was more then 400 characters find your message below for ease of copy/pasting") +// to_chat(src, "[msg]") +// return + + log_admin("PM: [key_name(src)]->IRC-[sender]: [msg]") + adminmsg2adminirc(src, sender, html_decode(msg)) + admin_pm_repository.store_pm(src, "IRC-[sender]", msg) + + to_chat(src, "" + create_text_tag("pm_out_alt", "PM", src) + " to [sender]: [msg]") + for(var/client/X in GLOB.admins) + if(X == src) + continue + if(X.holder.rights & R_ADMIN|R_MOD) + to_chat(X, "" + create_text_tag("pm_other", "PM:", X) + " [key_name(src, X, 0)] to [sender]: [msg]") diff --git a/code/modules/admin/verbs/adminsay.dm b/code/modules/admin/verbs/adminsay.dm new file mode 100644 index 00000000..0705723a --- /dev/null +++ b/code/modules/admin/verbs/adminsay.dm @@ -0,0 +1,38 @@ +/client/proc/cmd_admin_say(msg as text) + set category = "Special Verbs" + set name = "Asay" //Gave this shit a shorter name so you only have to time out "asay" rather than "admin say" to use it --NeoFite + set hidden = 1 + if(!check_rights(R_ADMIN)) return + + msg = sanitize(msg) + if(!msg) return + + log_admin("ADMIN: [key_name(src)] : [msg]") + + if(check_rights(R_ADMIN,0)) + for(var/client/C in GLOB.admins) + if(R_ADMIN & C.holder.rights) + to_chat(C, "" + create_text_tag("admin", "ADMIN:", C) + " [key_name(usr, 1)]([admin_jump_link(mob, src)]): [msg]") + + feedback_add_details("admin_verb","M") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_mod_say(msg as text) + set category = "Special Verbs" + set name = "Msay" + set hidden = 1 + + if(!check_rights(R_ADMIN|R_MOD|R_MENTOR)) return + + msg = sanitize(msg) + log_admin("MOD: [key_name(src)] : [msg]") + + if (!msg) + return + + var/sender_name = key_name(usr, 1) + if(check_rights(R_ADMIN, 0)) + sender_name = "[sender_name]" + for(var/client/C in GLOB.admins) + to_chat(C, "" + create_text_tag("mod", "MOD:", C) + " [sender_name]([admin_jump_link(mob, C.holder)]): [msg]") + + feedback_add_details("admin_verb","MS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/antag-ooc.dm b/code/modules/admin/verbs/antag-ooc.dm new file mode 100644 index 00000000..e69de29b diff --git a/code/modules/admin/verbs/atmosdebug.dm b/code/modules/admin/verbs/atmosdebug.dm new file mode 100644 index 00000000..0e99f07d --- /dev/null +++ b/code/modules/admin/verbs/atmosdebug.dm @@ -0,0 +1,60 @@ +/client/proc/atmosscan() + set category = "Mapping" + set name = "Check Piping" + set background = 1 + if(!src.holder) + to_chat(src, "Only administrators may use this command.") + return + feedback_add_details("admin_verb","CP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + if(alert("WARNING: This command should not be run on a live server. Do you want to continue?", "Check Piping", "No", "Yes") == "No") + return + + to_chat(usr, "Checking for disconnected pipes...") + //all plumbing - yes, some things might get stated twice, doesn't matter. + for (var/obj/machinery/atmospherics/plumbing in world) + if (plumbing.nodealert) + to_chat(usr, "Unconnected [plumbing.name] located at [plumbing.x],[plumbing.y],[plumbing.z] ([get_area(plumbing.loc)])") + + //Manifolds + for (var/obj/machinery/atmospherics/pipe/manifold/pipe in world) + if (!pipe.node1 || !pipe.node2 || !pipe.node3) + to_chat(usr, "Unconnected [pipe.name] located at [pipe.x],[pipe.y],[pipe.z] ([get_area(pipe.loc)])") + + //Pipes + for (var/obj/machinery/atmospherics/pipe/simple/pipe in world) + if (!pipe.node1 || !pipe.node2) + to_chat(usr, "Unconnected [pipe.name] located at [pipe.x],[pipe.y],[pipe.z] ([get_area(pipe.loc)])") + + to_chat(usr, "Checking for overlapping pipes...") + next_turf: + for(var/turf/T) + for(var/dir in GLOB.cardinal) + var/list/connect_types = list(1 = 0, 2 = 0, 3 = 0) + for(var/obj/machinery/atmospherics/pipe in T) + if(dir & pipe.initialize_directions) + for(var/connect_type in pipe.connect_types) + connect_types[connect_type] += 1 + if(connect_types[1] > 1 || connect_types[2] > 1 || connect_types[3] > 1) + to_chat(usr, "Overlapping pipe ([pipe.name]) located at [T.x],[T.y],[T.z] ([get_area(T)])") + continue next_turf + to_chat(usr, "Done") + +/client/proc/powerdebug() + set category = "Mapping" + set name = "Check Power" + if(!src.holder) + to_chat(src, "Only administrators may use this command.") + return + feedback_add_details("admin_verb","CPOW") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + for (var/datum/powernet/PN in SSmachines.powernets) + if (!PN.nodes || !PN.nodes.len) + if(PN.cables && (PN.cables.len > 1)) + var/obj/structure/cable/C = PN.cables[1] + to_chat(usr, "Powernet with no nodes! (number [PN.number]) - example cable at [C.x], [C.y], [C.z] in area [get_area(C.loc)]") + + if (!PN.cables || (PN.cables.len < 10)) + if(PN.cables && (PN.cables.len > 1)) + var/obj/structure/cable/C = PN.cables[1] + to_chat(usr, "Powernet with fewer than 10 cables! (number [PN.number]) - example cable at [C.x], [C.y], [C.z] in area [get_area(C.loc)]") \ No newline at end of file diff --git a/code/modules/admin/verbs/check_customitem_activity.dm b/code/modules/admin/verbs/check_customitem_activity.dm new file mode 100644 index 00000000..80bbfccc --- /dev/null +++ b/code/modules/admin/verbs/check_customitem_activity.dm @@ -0,0 +1,85 @@ +var/checked_for_inactives = 0 +var/inactive_keys = "None
            " + +/client/proc/check_customitem_activity() + set category = "Admin" + set name = "Check activity of players with custom items" + + var/dat = "Inactive players with custom items
            " + dat += "
            " + dat += "The list below contains players with custom items that have not logged\ + in for the past two months, or have not logged in since this system was implemented.\ + This system requires the feedback SQL database to be properly setup and linked.
            " + dat += "
            " + dat += "Populating this list is done automatically, but must be manually triggered on a per\ + round basis. Populating the list may cause a lag spike, so use it sparingly.
            " + dat += "
            " + if(checked_for_inactives) + dat += inactive_keys + dat += "
            " + dat += "This system was implemented on March 1 2013, and the database a few days before that. Root server access is required to add or disable access to specific custom items.
            " + else + dat += "Populate list (requires an active database connection)
            " + + usr << browse(dat, "window=inactive_customitems;size=600x480") + +/proc/populate_inactive_customitems_list(var/client/C) + set background = 1 + + if(checked_for_inactives) + return + + establish_db_connection() + if(!dbcon.IsConnected()) + return + + //grab all ckeys associated with custom items + var/list/ckeys_with_customitems = list() + + var/file = file2text("config/custom_items.txt") + var/lines = splittext(file, "\n") + + for(var/line in lines) + // split & clean up + var/list/Entry = splittext(line, ":") + for(var/i = 1 to Entry.len) + Entry[i] = trim(Entry[i]) + + if(Entry.len < 1) + continue + + var/cur_key = Entry[1] + if(!ckeys_with_customitems.Find(cur_key)) + ckeys_with_customitems.Add(cur_key) + + //run a query to get all ckeys inactive for over 2 months + var/list/inactive_ckeys = list() + if(ckeys_with_customitems.len) + var/DBQuery/query_inactive = dbcon.NewQuery("SELECT ckey, lastseen FROM erro_player WHERE datediff(Now(), lastseen) > 60") + query_inactive.Execute() + while(query_inactive.NextRow()) + var/cur_ckey = query_inactive.item[1] + //if the ckey has a custom item attached, output it + if(ckeys_with_customitems.Find(cur_ckey)) + ckeys_with_customitems.Remove(cur_ckey) + inactive_ckeys[cur_ckey] = "last seen on [query_inactive.item[2]]" + + //if there are ckeys left over, check whether they have a database entry at all + if(ckeys_with_customitems.len) + for(var/cur_ckey in ckeys_with_customitems) + var/DBQuery/query_inactive = dbcon.NewQuery("SELECT ckey FROM erro_player WHERE ckey = '[cur_ckey]'") + query_inactive.Execute() + if(!query_inactive.RowCount()) + inactive_ckeys += cur_ckey + + if(inactive_ckeys.len) + inactive_keys = "" + for(var/cur_key in inactive_ckeys) + if(inactive_ckeys[cur_key]) + inactive_keys += "[cur_key] - [inactive_ckeys[cur_key]]
            " + else + inactive_keys += "[cur_key] - no database entry
            " + + checked_for_inactives = 1 + if(C) + C.check_customitem_activity() diff --git a/code/modules/admin/verbs/cinematic.dm b/code/modules/admin/verbs/cinematic.dm new file mode 100644 index 00000000..a643b370 --- /dev/null +++ b/code/modules/admin/verbs/cinematic.dm @@ -0,0 +1,27 @@ +/client/proc/cinematic(var/cinematic as anything in list("explosion",null)) + set name = "Cinematic" + set category = "Fun" + set desc = "Shows a cinematic." // Intended for testing but I thought it might be nice for events on the rare occasion Feel free to comment it out if it's not wanted. + + if(!check_rights(R_FUN)) + return + + if(alert("Are you sure you want to run [cinematic]?","Confirmation","Yes","No")=="No") return + if(!ticker) return + switch(cinematic) + if("explosion") + if(alert("The game will be over. Are you really sure?", "Confirmation" ,"Continue", "Cancel") == "Cancel") + return + var/parameter = input(src,"station_missed = ?","Enter Parameter",0) as num + var/override + switch(parameter) + if(1) + override = input(src,"mode = ?","Enter Parameter",null) as anything in list("mercenary","no override") + if(0) + override = input(src,"mode = ?","Enter Parameter",null) as anything in list("blob","mercenary","AI malfunction","no override") + ticker.station_explosion_cinematic(parameter,override) + + log_admin("[key_name(src)] launched cinematic \"[cinematic]\"") + message_admins("[key_name_admin(src)] launched cinematic \"[cinematic]\"", 1) + + return \ No newline at end of file diff --git a/code/modules/admin/verbs/custom_event.dm b/code/modules/admin/verbs/custom_event.dm new file mode 100644 index 00000000..304edc0f --- /dev/null +++ b/code/modules/admin/verbs/custom_event.dm @@ -0,0 +1,40 @@ +// verb for admins to set custom event +/client/proc/cmd_admin_change_custom_event() + set category = "Fun" + set name = "Change Custom Event" + + if(!holder) + to_chat(src, "Only administrators may use this command.") + return + + var/input = sanitize(input(usr, "Enter the description of the custom event. Be descriptive. To cancel the event, make this blank or hit cancel.", "Custom Event", custom_event_msg) as message|null, MAX_BOOK_MESSAGE_LEN, extra = 0) + if(!input || input == "") + custom_event_msg = null + log_admin("[usr.key] has cleared the custom event text.") + message_admins("[key_name_admin(usr)] has cleared the custom event text.") + return + + log_admin("[usr.key] has changed the custom event text.") + message_admins("[key_name_admin(usr)] has changed the custom event text.") + + custom_event_msg = input + + to_world("

            Custom Event

            ") + to_world("

            A custom event is starting. OOC Info:

            ") + to_world("[custom_event_msg]") + to_world("
            ") + +// normal verb for players to view info +/client/verb/cmd_view_custom_event() + set category = "OOC" + set name = "Custom Event Info" + + if(!custom_event_msg || custom_event_msg == "") + to_chat(src, "There currently is no known custom event taking place.") + to_chat(src, "Keep in mind: it is possible that an admin has not properly set this.") + return + + to_chat(src, "

            Custom Event

            ") + to_chat(src, "

            A custom event is taking place. OOC Info:

            ") + to_chat(src, "[custom_event_msg]") + to_chat(src, "
            ") diff --git a/code/modules/admin/verbs/deadsay.dm b/code/modules/admin/verbs/deadsay.dm new file mode 100644 index 00000000..dc06a73e --- /dev/null +++ b/code/modules/admin/verbs/deadsay.dm @@ -0,0 +1,10 @@ +/client/proc/dsay(msg as text) + set category = "Special Verbs" + set name = "Dsay" //Gave this shit a shorter name so you only have to time out "dsay" rather than "dead say" to use it --NeoFite + + if(!src.holder) + to_chat(src, "Only administrators may use this command.") + return + + sanitize_and_communicate(/decl/communication_channel/dsay, src, msg, /decl/dsay_communication/admin) + feedback_add_details("admin_verb","D") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm new file mode 100644 index 00000000..8c0a96c1 --- /dev/null +++ b/code/modules/admin/verbs/debug.dm @@ -0,0 +1,577 @@ +/client/proc/Debug2() + set category = "Debug" + set name = "Debug-Game" + if(!check_rights(R_DEBUG)) return + + if(Debug2) + Debug2 = 0 + message_admins("[key_name(src)] toggled debugging off.") + log_admin("[key_name(src)] toggled debugging off.") + else + Debug2 = 1 + message_admins("[key_name(src)] toggled debugging on.") + log_admin("[key_name(src)] toggled debugging on.") + + feedback_add_details("admin_verb","DG2") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +// callproc moved to code/modules/admin/callproc + + +/client/proc/Cell() + set category = "Debug" + set name = "Cell" + if(!mob) + return + var/turf/T = mob.loc + + if (!( istype(T, /turf) )) + return + + var/datum/gas_mixture/env = T.return_air() + + var/t = "Coordinates: [T.x],[T.y],[T.z]\n" + t += "Temperature: [env.temperature]\n" + t += "Pressure: [env.return_pressure()]kPa\n" + for(var/g in env.gas) + t += "[g]: [env.gas[g]] / [env.gas[g] * R_IDEAL_GAS_EQUATION * env.temperature / env.volume]kPa\n" + + usr.show_message(t, 1) + feedback_add_details("admin_verb","ASL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_robotize(var/mob/M in SSmobs.mob_list) + set category = "Fun" + set name = "Make Robot" + + if(!ticker) + alert("Wait until the game starts") + return + if(istype(M, /mob/living/carbon/human)) + log_admin("[key_name(src)] has robotized [M.key].") + spawn(10) + M:Robotize() + + else + alert("Invalid mob") + +/client/proc/cmd_admin_animalize(var/mob/M in SSmobs.mob_list) + set category = "Fun" + set name = "Make Simple Animal" + + if(!ticker) + alert("Wait until the game starts") + return + + if(!M) + alert("That mob doesn't seem to exist, close the panel and try again.") + return + + if(istype(M, /mob/new_player)) + alert("The mob must not be a new_player.") + return + + log_admin("[key_name(src)] has animalized [M.key].") + spawn(10) + M.Animalize() + + +/client/proc/makepAI(var/turf/T in SSmobs.mob_list) + set category = "Fun" + set name = "Make pAI" + set desc = "Specify a location to spawn a pAI device, then specify a key to play that pAI" + + var/list/available = list() + for(var/mob/C in SSmobs.mob_list) + if(C.key) + available.Add(C) + var/mob/choice = input("Choose a player to play the pAI", "Spawn pAI") in available + if(!choice) + return 0 + if(!isghost(choice)) + var/confirm = input("[choice.key] isn't ghosting right now. Are you sure you want to yank them out of them out of their body and place them in this pAI?", "Spawn pAI Confirmation", "No") in list("Yes", "No") + if(confirm != "Yes") + return 0 + var/obj/item/device/paicard/card = new(T) + var/mob/living/silicon/pai/pai = new(card) + pai.SetName(sanitizeSafe(input(choice, "Enter your pAI name:", "pAI Name", "Personal AI") as text)) + pai.real_name = pai.name + pai.key = choice.key + card.setPersonality(pai) + for(var/datum/paiCandidate/candidate in paiController.pai_candidates) + if(candidate.key == choice.key) + 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_slimeize(var/mob/M in SSmobs.mob_list) + set category = "Fun" + set name = "Make slime" + + if(!ticker) + alert("Wait until the game starts") + return + if(ishuman(M)) + log_admin("[key_name(src)] has slimeized [M.key].") + spawn(10) + M:slimeize() + feedback_add_details("admin_verb","MKMET") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + log_and_message_admins("made [key_name(M)] into a slime.") + else + alert("Invalid mob") + +/* +/client/proc/cmd_admin_monkeyize(var/mob/M in mob_list) + set category = "Fun" + set name = "Make Monkey" + + if(!ticker) + alert("Wait until the game starts") + return + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/target = M + log_admin("[key_name(src)] is attempting to monkeyize [M.key].") + spawn(10) + target.monkeyize() + else + alert("Invalid mob") + +/client/proc/cmd_admin_changelinginize(var/mob/M in mob_list) + set category = "Fun" + set name = "Make Changeling" + + if(!ticker) + alert("Wait until the game starts") + return + if(istype(M, /mob/living/carbon/human)) + log_admin("[key_name(src)] has made [M.key] a changeling.") + spawn(10) + M.absorbed_dna[M.real_name] = M.dna.Clone() + M.make_changeling() + if(M.mind) + M.mind.special_role = "Changeling" + else + alert("Invalid mob") +*/ +/* +/client/proc/cmd_admin_abominize(var/mob/M in mob_list) + set category = null + set name = "Make Abomination" + + to_chat(usr, "Ruby Mode disabled. Command aborted.") + return + if(!ticker) + alert("Wait until the game starts.") + return + if(istype(M, /mob/living/carbon/human)) + log_admin("[key_name(src)] has made [M.key] an abomination.") + + // spawn(10) + // M.make_abomination() + +*/ +/* +/client/proc/make_cultist(var/mob/M in mob_list) // -- TLE, modified by Urist + set category = "Fun" + set name = "Make Cultist" + set desc = "Makes target a cultist" + if(!cultwords["travel"]) + runerandom() + if(M) + if(M.mind in ticker.mode.cult) + return + else + if(alert("Spawn that person a tome?",,"Yes","No")=="Yes") + to_chat(M, "You catch a glimpse of the Realm of Nar-Sie, The Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of Nar-Sie. A tome, a message from your new master, appears on the ground.") + new /obj/item/weapon/book/tome(M.loc) + else + to_chat(M, "You catch a glimpse of the Realm of Nar-Sie, The Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of Nar-Sie.") + var/glimpse=pick("1","2","3","4","5","6","7","8") + switch(glimpse) + if("1") + to_chat(M, "You remembered one thing from the glimpse... [cultwords["travel"]] is travel...") + if("2") + to_chat(M, "You remembered one thing from the glimpse... [cultwords["blood"]] is blood...") + if("3") + to_chat(M, "You remembered one thing from the glimpse... [cultwords["join"]] is join...") + if("4") + to_chat(M, "You remembered one thing from the glimpse... [cultwords["hell"]] is Hell...") + if("5") + to_chat(M, "You remembered one thing from the glimpse... [cultwords["destroy"]] is destroy...") + if("6") + to_chat(M, "You remembered one thing from the glimpse... [cultwords["technology"]] is technology...") + if("7") + to_chat(M, "You remembered one thing from the glimpse... [cultwords["self"]] is self...") + if("8") + to_chat(M, "You remembered one thing from the glimpse... [cultwords["see"]] is see...") + + if(M.mind) + M.mind.special_role = "Cultist" + ticker.mode.cult += M.mind + to_chat(src, "Made [M] a cultist.") +*/ + +//TODO: merge the vievars version into this or something maybe mayhaps +/client/proc/cmd_debug_del_all() + set category = "Debug" + set name = "Del-All" + + // to prevent REALLY stupid deletions + var/blocked = list(/obj, /mob, /mob/living, /mob/living/carbon, /mob/living/carbon/human, /mob/observer, /mob/living/silicon, /mob/living/silicon/robot, /mob/living/silicon/ai) + var/hsbitem = input(usr, "Choose an object to delete.", "Delete:") as null|anything in typesof(/obj) + typesof(/mob) - blocked + if(hsbitem) + for(var/atom/O in world) + if(istype(O, hsbitem)) + qdel(O) + log_admin("[key_name(src)] has deleted all instances of [hsbitem].") + message_admins("[key_name_admin(src)] has deleted all instances of [hsbitem].", 0) + feedback_add_details("admin_verb","DELA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_debug_make_powernets() + set category = "Debug" + set name = "Make Powernets" + SSmachines.makepowernets() + log_admin("[key_name(src)] has remade the powernet. makepowernets() called.") + message_admins("[key_name_admin(src)] has remade the powernets. makepowernets() called.", 0) + feedback_add_details("admin_verb","MPWN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_debug_tog_aliens() + set category = "Server" + set name = "Toggle Aliens" + + config.aliens_allowed = !config.aliens_allowed + log_admin("[key_name(src)] has turned aliens [config.aliens_allowed ? "on" : "off"].") + message_admins("[key_name_admin(src)] has turned aliens [config.aliens_allowed ? "on" : "off"].", 0) + feedback_add_details("admin_verb","TAL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_grantfullaccess(var/mob/M in SSmobs.mob_list) + set category = "Admin" + set name = "Grant Full Access" + + if (!ticker) + alert("Wait until the game starts") + return + if (istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if (H.wear_id) + var/obj/item/weapon/card/id/id = H.wear_id + if(istype(H.wear_id, /obj/item/device/pda)) + var/obj/item/device/pda/pda = H.wear_id + id = pda.id + id.icon_state = "gold" + id.access = get_all_accesses() + else + var/obj/item/weapon/card/id/id = new/obj/item/weapon/card/id(M); + id.icon_state = "gold" + id.access = get_all_accesses() + id.registered_name = H.real_name + id.assignment = "Captain" + id.SetName("[id.registered_name]'s ID Card ([id.assignment])") + H.equip_to_slot_or_del(id, slot_wear_id) + H.update_inv_wear_id() + else + alert("Invalid mob") + feedback_add_details("admin_verb","GFA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + log_and_message_admins("has granted [M.key] full access.") + +/client/proc/cmd_assume_direct_control(var/mob/M in SSmobs.mob_list) + set category = "Admin" + set name = "Assume direct control" + set desc = "Direct intervention" + + if(!check_rights(R_DEBUG|R_ADMIN)) return + if(M.ckey) + if(alert("This mob is being controlled by [M.ckey]. Are you sure you wish to assume control of it? [M.ckey] will be made a ghost.",,"Yes","No") != "Yes") + return + else + var/mob/observer/ghost/ghost = new/mob/observer/ghost(M,1) + ghost.ckey = M.ckey + log_and_message_admins("assumed direct control of [M].") + var/mob/adminmob = src.mob + M.ckey = src.ckey + if(isghost(adminmob)) + qdel(adminmob) + feedback_add_details("admin_verb","ADC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + + + + + +/client/proc/cmd_admin_areatest() + set category = "Mapping" + set name = "Test areas" + + var/list/areas_all = list() + var/list/areas_with_APC = list() + var/list/areas_with_air_alarm = list() + var/list/areas_with_RC = list() + var/list/areas_with_light = list() + var/list/areas_with_LS = list() + var/list/areas_with_intercom = list() + var/list/areas_with_camera = list() + + for(var/area/A in world) + if(!(A.type in areas_all)) + areas_all.Add(A.type) + + for(var/obj/machinery/power/apc/APC in world) + var/area/A = get_area(APC) + if(!(A.type in areas_with_APC)) + areas_with_APC.Add(A.type) + + for(var/obj/machinery/alarm/alarm in world) + var/area/A = get_area(alarm) + if(!(A.type in areas_with_air_alarm)) + areas_with_air_alarm.Add(A.type) + + for(var/obj/machinery/requests_console/RC in world) + var/area/A = get_area(RC) + if(!(A.type in areas_with_RC)) + areas_with_RC.Add(A.type) + + for(var/obj/machinery/light/L in world) + var/area/A = get_area(L) + if(!(A.type in areas_with_light)) + areas_with_light.Add(A.type) + + for(var/obj/machinery/light_switch/LS in world) + var/area/A = get_area(LS) + if(!(A.type in areas_with_LS)) + areas_with_LS.Add(A.type) + + for(var/obj/item/device/radio/intercom/I in world) + var/area/A = get_area(I) + if(!(A.type in areas_with_intercom)) + areas_with_intercom.Add(A.type) + + for(var/obj/machinery/camera/C in world) + var/area/A = get_area(C) + if(!(A.type in areas_with_camera)) + areas_with_camera.Add(A.type) + + var/list/areas_without_APC = areas_all - areas_with_APC + var/list/areas_without_air_alarm = areas_all - areas_with_air_alarm + var/list/areas_without_RC = areas_all - areas_with_RC + var/list/areas_without_light = areas_all - areas_with_light + var/list/areas_without_LS = areas_all - areas_with_LS + var/list/areas_without_intercom = areas_all - areas_with_intercom + var/list/areas_without_camera = areas_all - areas_with_camera + + log_debug("AREAS WITHOUT AN APC:") + for(var/areatype in areas_without_APC) + log_debug("* [areatype]") + + log_debug("AREAS WITHOUT AN AIR ALARM:") + for(var/areatype in areas_without_air_alarm) + log_debug("* [areatype]") + + log_debug("AREAS WITHOUT A REQUEST CONSOLE:") + for(var/areatype in areas_without_RC) + log_debug("* [areatype]") + + log_debug("AREAS WITHOUT ANY LIGHTS:") + for(var/areatype in areas_without_light) + log_debug("* [areatype]") + + log_debug("AREAS WITHOUT A LIGHT SWITCH:") + for(var/areatype in areas_without_LS) + log_debug("* [areatype]") + + log_debug("AREAS WITHOUT ANY INTERCOMS:") + for(var/areatype in areas_without_intercom) + log_debug("* [areatype]") + + log_debug("AREAS WITHOUT ANY CAMERAS:") + for(var/areatype in areas_without_camera) + log_debug("* [areatype]") + +/datum/admins/proc/cmd_admin_dress() + set category = "Fun" + set name = "Select equipment" + + if(!check_rights(R_FUN)) + return + + var/mob/living/carbon/human/H = input("Select mob.", "Select equipment.") as null|anything in GLOB.human_mob_list + if(!H) + return + + var/decl/hierarchy/outfit/outfit = input("Select outfit.", "Select equipment.") as null|anything in outfits() + if(!outfit) + return + + var/reset_equipment = (outfit.flags&OUTFIT_RESET_EQUIPMENT) + if(!reset_equipment) + reset_equipment = alert("Do you wish to delete all current equipment first?", "Delete Equipment?","Yes", "No") == "Yes" + + feedback_add_details("admin_verb","SEQ") + dressup_human(H, outfit, reset_equipment) + +/proc/dressup_human(var/mob/living/carbon/human/H, var/decl/hierarchy/outfit/outfit, var/undress = TRUE) + if(!H || !outfit) + return + if(undress) + H.delete_inventory(TRUE) + outfit.equip(H) + log_and_message_admins("changed the equipment of [key_name(H)] to [outfit.name].") + +/client/proc/startSinglo() + set category = "Debug" + set name = "Start Singularity" + set desc = "Sets up the singularity and all machines to get power flowing" + + if(alert("Are you sure? This will start up the engine. Should only be used during debug!",,"Yes","No") != "Yes") + return + + for(var/obj/machinery/power/emitter/E in world) + if(E.anchored) + E.active = 1 + + for(var/obj/machinery/field_generator/F in world) + if(F.anchored) + F.Varedit_start = 1 + spawn(30) + for(var/obj/machinery/the_singularitygen/G in world) + if(G.anchored) + var/obj/singularity/S = new /obj/singularity(get_turf(G), 50) + spawn(0) + qdel(G) + S.energy = 1750 + S.current_size = 7 + S.icon = 'icons/effects/224x224.dmi' + S.icon_state = "singularity_s7" + S.pixel_x = -96 + S.pixel_y = -96 + S.grav_pull = 0 + //S.consume_range = 3 + S.dissipate = 0 + //S.dissipate_delay = 10 + //S.dissipate_track = 0 + //S.dissipate_strength = 10 + + for(var/obj/machinery/power/rad_collector/Rad in world) + if(Rad.anchored) + if(!Rad.P) + var/obj/item/weapon/tank/phoron/Phoron = new/obj/item/weapon/tank/phoron(Rad) + Phoron.air_contents.gas["phoron"] = 70 + Rad.drainratio = 0 + Rad.P = Phoron + Phoron.loc = Rad + + if(!Rad.active) + Rad.toggle_power() + + for(var/obj/machinery/power/smes/SMES in world) + if(SMES.anchored) + SMES.input_attempt = 1 + +/client/proc/cmd_debug_mob_lists() + set category = "Debug" + set name = "Debug Mob Lists" + set desc = "For when you just gotta know" + + switch(input("Which list?") in list("Players","Admins","Mobs","Living Mobs","Dead Mobs", "Ghost Mobs", "Clients")) + if("Players") + to_chat(usr, jointext(GLOB.player_list,",")) + if("Admins") + to_chat(usr, jointext(GLOB.admins,",")) + if("Mobs") + to_chat(usr, jointext(SSmobs.mob_list,",")) + if("Living Mobs") + to_chat(usr, jointext(GLOB.living_mob_list_,",")) + if("Dead Mobs") + to_chat(usr, jointext(GLOB.dead_mob_list_,",")) + if("Ghost Mobs") + to_chat(usr, jointext(GLOB.ghost_mob_list,",")) + if("Clients") + to_chat(usr, jointext(GLOB.clients,",")) + +// DNA2 - Admin Hax +/client/proc/cmd_admin_toggle_block(var/mob/M,var/block) + if(!ticker) + alert("Wait until the game starts") + return + if(istype(M, /mob/living/carbon)) + M.dna.SetSEState(block,!M.dna.GetSEState(block)) + domutcheck(M,null,MUTCHK_FORCED) + M.update_mutations() + var/state="[M.dna.GetSEState(block)?"on":"off"]" + var/blockname=assigned_blocks[block] + message_admins("[key_name_admin(src)] has toggled [M.key]'s [blockname] block [state]!") + log_admin("[key_name(src)] has toggled [M.key]'s [blockname] block [state]!") + else + alert("Invalid mob") + +/datum/admins/proc/view_runtimes() + set category = "Debug" + set name = "View Runtimes" + set desc = "Open the Runtime Viewer" + + if(!check_rights(R_DEBUG)) + return + + GLOB.error_cache.show_to(usr.client) + +/client/proc/cmd_analyse_health_panel() + set category = "Debug" + set name = "Analyse Health" + set desc = "Get an advanced health reading on a human mob." + + var/mob/living/carbon/human/H = input("Select mob.", "Analyse Health") as null|anything in GLOB.human_mob_list + if(!H) return + + cmd_analyse_health(H) + +/client/proc/cmd_analyse_health(var/mob/living/carbon/human/H) + + if(!check_rights(R_DEBUG)) + return + + if(!H) return + + var/dat = H.get_medical_data() + + dat += text("
            Close", usr) + show_browser(usr, dat, "window=scanconsole;size=430x600") + +/client/proc/cmd_analyse_health_context(mob/living/carbon/human/H as mob in GLOB.human_mob_list) + set category = null + set name = "Analyse Human Health" + + if(!check_rights(R_DEBUG)) + return + if(!ishuman(H)) return + cmd_analyse_health(H) + feedback_add_details("admin_verb","ANLS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/obj/effect/debugmarker + icon = 'icons/effects/lighting_overlay.dmi' + icon_state = "transparent" + plane = ABOVE_TURF_PLANE + layer = HOLOMAP_LAYER + alpha = 127 + +/client/var/list/image/powernet_markers = list() +/client/proc/visualpower() + set category = "Debug" + set name = "Visualize Powernets" + + if(!check_rights(R_DEBUG)) return + visualpower_remove() + powernet_markers = list() + + for(var/datum/powernet/PN in SSmachines.powernets) + var/netcolor = rgb(rand(100,255),rand(100,255),rand(100,255)) + for(var/obj/structure/cable/C in PN.cables) + var/image/I = image('icons/effects/lighting_overlay.dmi', get_turf(C), "transparent") + I.plane = ABOVE_TURF_PLANE + I.alpha = 127 + I.color = netcolor + I.maptext = "\ref[PN]" + powernet_markers += I + images += powernet_markers + +/client/proc/visualpower_remove() + set category = "Debug" + set name = "Remove Powernets Visuals" + + images -= powernet_markers + QDEL_NULL_LIST(powernet_markers) \ No newline at end of file diff --git a/code/modules/admin/verbs/diagnostics.dm b/code/modules/admin/verbs/diagnostics.dm new file mode 100644 index 00000000..38e1ecd6 --- /dev/null +++ b/code/modules/admin/verbs/diagnostics.dm @@ -0,0 +1,141 @@ +/client/proc/air_report() + set category = "Debug" + set name = "Show Air Report" + + if(!SSair) + alert(usr,"SSair not found.","Air Report") + return + + var/active_groups = SSair.active_zones + var/inactive_groups = SSair.zones.len - active_groups + + var/hotspots = 0 + for(var/obj/fire/hotspot in world) + hotspots++ + + var/active_on_main_station = 0 + var/inactive_on_main_station = 0 + for(var/zone/zone in SSair.zones) + var/turf/simulated/turf = locate() in zone.contents + if(turf && turf.z in GLOB.using_map.station_levels) + if(zone.needs_update) + active_on_main_station++ + else + inactive_on_main_station++ + + var/output = {"AIR SYSTEMS REPORT
            +General Processing Data
            + Cycle: [SSair.times_fired]
            + Groups: [SSair.zones.len]
            +---- Active: [active_groups]
            +---- Inactive: [inactive_groups]

            +---- Active on station: [active_on_main_station]
            +---- Inactive on station: [inactive_on_main_station]
            +
            +Special Processing Data
            + Hotspot Processing: [hotspots]
            +
            +Geometry Processing Data
            + Tile Update: [SSair.tiles_to_update.len]
            +"} + + usr << browse(output,"window=airreport") + +/client/proc/fix_next_move() + set category = "Debug" + set name = "Unfreeze Everyone" + var/largest_move_time = 0 + var/largest_click_time = 0 + var/mob/largest_move_mob = null + var/mob/largest_click_mob = null + for(var/mob/M in world) + if(!M.client) + continue + if(M.next_move >= largest_move_time) + largest_move_mob = M + if(M.next_move > world.time) + largest_move_time = M.next_move - world.time + else + largest_move_time = 1 + if(M.next_click >= largest_click_time) + largest_click_mob = M + if(M.next_click > world.time) + largest_click_time = M.next_click - world.time + else + largest_click_time = 0 + log_admin("DEBUG: [key_name(M)] next_move = [M.next_move] next_click = [M.next_click] world.time = [world.time]") + M.next_move = 1 + M.next_click = 0 + message_admins("[key_name_admin(largest_move_mob)] had the largest move delay with [largest_move_time] frames / [largest_move_time/10] seconds!", 1) + message_admins("[key_name_admin(largest_click_mob)] had the largest click delay with [largest_click_time] frames / [largest_click_time/10] seconds!", 1) + message_admins("world.time = [world.time]", 1) + feedback_add_details("admin_verb","UFE") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + +/client/proc/radio_report() + set category = "Debug" + set name = "Radio report" + + var/output = "Radio Report
            " + for (var/fq in radio_controller.frequencies) + output += "Freq: [fq]
            " + var/list/datum/radio_frequency/fqs = radio_controller.frequencies[fq] + if (!fqs) + output += "  ERROR
            " + continue + for (var/filter in fqs.devices) + var/list/f = fqs.devices[filter] + if (!f) + output += "  [filter]: ERROR
            " + continue + output += "  [filter]: [f.len]
            " + for (var/device in f) + if (isobj(device)) + output += "    [device] ([device:x],[device:y],[device:z] in area [get_area(device:loc)])
            " + else + output += "    [device]
            " + + usr << browse(output,"window=radioreport") + feedback_add_details("admin_verb","RR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/reload_admins() + set name = "Reload Admins" + set category = "Debug" + + if(!check_rights(R_SERVER)) return + + message_admins("[usr] manually reloaded admins") + load_admins() + feedback_add_details("admin_verb","RLDA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/reload_mentors() + set name = "Reload Mentors" + set category = "Debug" + + if(!check_rights(R_SERVER)) return + + message_admins("[usr] manually reloaded Mentors") + world.load_mods() + +/client/proc/print_jobban_old() + set name = "Print Jobban Log" + set desc = "This spams all the active jobban entries for the current round to standard output." + set category = "Debug" + + to_chat(usr, "Jobbans active in this round.") + for(var/t in jobban_keylist) + to_chat(usr, "[t]") + +/client/proc/print_jobban_old_filter() + set name = "Search Jobban Log" + set desc = "This searches all the active jobban entries for the current round and outputs the results to standard output." + set category = "Debug" + + var/filter = input("Contains what?","Filter") as text|null + if(!filter) + return + + to_chat(usr, "Jobbans active in this round.") + for(var/t in jobban_keylist) + if(findtext(t, filter)) + to_chat(usr, "[t]") diff --git a/code/modules/admin/verbs/dice.dm b/code/modules/admin/verbs/dice.dm new file mode 100644 index 00000000..ac9d7aa3 --- /dev/null +++ b/code/modules/admin/verbs/dice.dm @@ -0,0 +1,24 @@ +/client/proc/roll_dices() + set category = "Fun" + set name = "Roll Dice" + if(!check_rights(R_FUN)) + return + + var/sum = input("How many times should we throw?") as num + var/side = input("Select the number of sides.") as num + if(!side) + side = 6 + if(!sum) + sum = 2 + + var/dice = num2text(sum) + "d" + num2text(side) + + if(alert("Do you want to inform the world about your game?",,"Yes", "No") == "Yes") + to_world("

            The dice have been rolled by Gods!

            ") + + var/result = roll(dice) + + if(alert("Do you want to inform the world about the result?",,"Yes", "No") == "Yes") + to_world("

            Gods rolled [dice], result is [result]

            ") + + message_admins("[key_name_admin(src)] rolled dice [dice], result is [result]", 1) \ No newline at end of file diff --git a/code/modules/admin/verbs/getlogs.dm b/code/modules/admin/verbs/getlogs.dm new file mode 100644 index 00000000..8faf6ad9 --- /dev/null +++ b/code/modules/admin/verbs/getlogs.dm @@ -0,0 +1,119 @@ +/* + HOW DO I LOG RUNTIMES? + Firstly, start dreamdeamon if it isn't already running. Then select "world>Log Session" (or press the F3 key) + navigate the popup window to the data/logs/runtime/ folder from where your tgstation .dmb is located. + (you may have to make this folder yourself) + + OPTIONAL: you can select the little checkbox down the bottom to make dreamdeamon save the log everytime you + start a world. Just remember to repeat these steps with a new name when you update to a new revision! + + Save it with the name of the revision your server uses (e.g. r3459.txt). + Game Masters will now be able to grant access any runtime logs you have archived this way! + This will allow us to gather information on bugs across multiple servers and make maintaining the TG + codebase for the entire /TG/station commuity a TONNE easier :3 Thanks for your help! +*/ + + +//This proc allows Game Masters to grant a client access to the .getruntimelog verb +//Permissions expire at the end of each round. +//Runtimes can be used to meta or spot game-crashing exploits so it's advised to only grant coders that +//you trust access. Also, it may be wise to ensure that they are not going to play in the current round. +/client/proc/giveruntimelog() + set name = ".giveruntimelog" + set desc = "Give somebody access to any session logfiles saved to the /log/runtime/ folder." + set category = null + + if(!src.holder) + to_chat(src, "Only Admins may use this command.") + return + + var/client/target = input(src,"Choose somebody to grant access to the server's runtime logs (permissions expire at the end of each round):","Grant Permissions",null) as null|anything in GLOB.clients + if(!istype(target,/client)) + to_chat(src, "Error: giveruntimelog(): Client not found.") + return + + target.verbs |= /client/proc/getruntimelog + to_chat(target, "You have been granted access to runtime logs. Please use them responsibly or risk being banned.") + return + + +//This proc allows download of runtime logs saved within the data/logs/ folder by dreamdeamon. +//It works similarly to show-server-log. +/client/proc/getruntimelog() + set name = "Get Runtime Log" + set desc = "Retrieve any session logfiles saved by dreamdeamon." + set category = "Admin" + + if(!src.holder) + to_chat(src, "Only Admins may use this command.") + return + + var/path = browse_files("data/logs/runtime/") + if(!path) + return + + if(file_spam_check()) + return + + message_admins("[key_name_admin(src)] accessed file: [path]") + src << run(file(path)) + to_chat(src, "Attempting to send file, this may take a fair few minutes if the file is very large.") + return + + +//This proc allows download of past server logs saved within the data/logs/ folder. +//It works similarly to show-server-log. +/client/proc/getserverlog() + set name = "Get Server Log" + set desc = "Fetch logfiles from data/logs" + set category = "Admin" + + if(!src.holder) + to_chat(src, "Only Admins may use this command.") + return + + var/path = browse_files("data/logs/") + if(!path) + return + + if(file_spam_check()) + return + + message_admins("[key_name_admin(src)] accessed file: [path]") + src << run(file(path)) + to_chat(src, "Attempting to send file, this may take a fair few minutes if the file is very large.") + return + + +//Other log stuff put here for the sake of organisation + +//Shows today's server log +/datum/admins/proc/view_txt_log() + set category = "Admin" + set name = "Show Server Log" + set desc = "Shows today's server log." + + var/path = "data/logs/[time2text(world.realtime,"YYYY/MM-Month/DD-Day")].log" + if( fexists(path) ) + src << run(file(path)) + else + to_chat(src, "Error: view_txt_log(): File not found/Invalid path([path]).") + return + feedback_add_details("admin_verb","VTL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + +//Shows today's attack log +/datum/admins/proc/view_atk_log() + set category = "Admin" + set name = "Show Server Attack Log" + set desc = "Shows today's server attack log." + + var/path = "data/logs/[time2text(world.realtime,"YYYY/MM-Month/DD-Day")] Attack.log" + if( fexists(path) ) + src << run(file(path)) + else + to_chat(src, "Error: view_atk_log(): File not found/Invalid path([path]).") + return + usr << run(file(path)) + feedback_add_details("admin_verb","SSAL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return diff --git a/code/modules/admin/verbs/grief_fixers.dm b/code/modules/admin/verbs/grief_fixers.dm new file mode 100644 index 00000000..9cc83870 --- /dev/null +++ b/code/modules/admin/verbs/grief_fixers.dm @@ -0,0 +1,50 @@ +/client/proc/fixatmos() + set category = "Admin" + set name = "Fix Atmospherics Grief" + + if(!check_rights(R_ADMIN|R_DEBUG)) return + + if(alert("WARNING: Executing this command will perform a full reset of atmosphere. All pipelines will lose any gas that may be in them, and all zones will be reset to contain air mix as on roundstart. The supermatter engine will also be stopped (to prevent overheat due to removal of coolant). Do not use unless the map is suffering serious atmospheric issues due to grief or bug.", "Full Atmosphere Reboot", "No", "Yes") == "No") + return + feedback_add_details("admin_verb","FA") + + log_and_message_admins("Full atmosphere reset initiated by [usr].") + to_world("Initiating restart of atmosphere. The server may lag a bit.") + sleep(10) + var/current_time = world.timeofday + + // Depower the supermatter, as it would quickly blow up once we remove all gases from the pipes. + for(var/obj/machinery/power/supermatter/S in SSmachines.machinery) + S.power = 0 + to_chat(usr, "\[1/5\] - Supermatter depowered") + + // Remove all gases from all pipenets + for(var/net in SSmachines.pipenets) + var/datum/pipe_network/PN = net + for(var/datum/gas_mixture/G in PN.gases) + G.gas = list() + G.update_values() + + to_chat(usr, "\[2/5\] - All pipenets purged of gas.") + + // Delete all zones. + for(var/zone/Z in world) + Z.c_invalidate() + + to_chat(usr, "\[3/5\] - All ZAS Zones removed.") + + var/list/unsorted_overlays = list() + for(var/id in gas_data.tile_overlay) + unsorted_overlays |= gas_data.tile_overlay[id] + + for(var/turf/simulated/T in world) + T.air = null + T.overlays.Remove(unsorted_overlays) + T.zone = null + + to_chat(usr, "\[4/5\] - All turfs reset to roundstart values.") + + SSair.reboot() + + to_chat(usr, "\[5/5\] - ZAS Rebooted") + to_world("Atmosphere restart completed in [(world.timeofday - current_time)/10] seconds.") diff --git a/code/modules/admin/verbs/map_template_loadverb.dm b/code/modules/admin/verbs/map_template_loadverb.dm new file mode 100644 index 00000000..26bcfb5d --- /dev/null +++ b/code/modules/admin/verbs/map_template_loadverb.dm @@ -0,0 +1,77 @@ +/datum/admins/proc/map_template_load() + set category = "Fun" + set desc = "Pick a map template to load at your current location. You will be able to confirm bounds before committing." + set name = "Map Template - Place" + + if (!check_rights(R_FUN)) return + + var/map = input(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template") as null|anything in SSmapping.map_templates + if(!map) + return + + var/datum/map_template/template = SSmapping.map_templates[map] + + var/turf/T = get_turf(usr) + if(!T) + return + + var/clear_contents = (alert(usr, "Do you want to delete everything in the way of the template? \ + May take a few seconds, particularly on larger templates!", "Clear Contents", "No", "Yes") == "Yes") + + var/list/preview = list() + for(var/S in template.get_affected_turfs(T,centered = TRUE)) + preview += image('icons/turf/overlays.dmi',S,"greenOverlay") + usr.client.images += preview + if(alert(usr,"Confirm location.","Template Confirm","Yes","No") == "Yes") + if(template.load(T, centered = TRUE, clear_contents=clear_contents)) + log_and_message_admins("has placed a map template ([template.name]).") + else + to_chat(usr, "Failed to place map") + usr.client.images -= preview + +/datum/admins/proc/map_template_load_new_z() + set category = "Fun" + set desc = "Pick a map template to load as a new zlevel, or a set of new zlevels if multi-z." + set name = "Map Template - Place In New Z" + + if (!check_rights(R_FUN)) return + + var/map = input(usr, "Choose a Map Template to place on a new zlevel","Place Map Template") as null|anything in SSmapping.map_templates + if(!map) + return + + var/datum/map_template/template = SSmapping.map_templates[map] + + if (template.loaded && !template.allow_duplicates) + var/jesus_take_the_wheel = alert(usr, "That template has already been loaded and doesn't want to be loaded again. \ + Proceeding may unpredictably break things and cause runtimes.", "Confirm load", "Cancel load", "Do you see any cops around?") == "Do you see any cops around?" + if (!jesus_take_the_wheel) + return + + var/new_z_centre = template.load_new_z() + if (new_z_centre) + log_and_message_admins("has placed a map template ([template.name]) on a new zlevel.", location=new_z_centre) + else + to_chat(usr, "Failed to place map") + +/datum/admins/proc/map_template_upload() + set category = "Fun" + set desc = "Upload a .dmm file to use as a map template. Any unknown types will be skipped!" + set name = "Map Template - Upload" + + if (!check_rights(R_FUN)) return + + var/map = input(usr, "Choose a Map Template to upload to template storage","Upload Map Template") as null|file + if(!map) + return + if(copytext("[map]",-4) != ".dmm") + to_chat(usr, "Bad map file: [map]") + return + + var/datum/map_template/M = new(list(map), "[map]") + if(M.preload_size()) + to_chat(usr, "Map template '[map]' ready to place ([M.width]x[M.height])") + SSmapping.map_templates[M.name] = M + message_admins("[key_name_admin(usr)] has uploaded a map template ([map])") + else + to_chat(usr, "Map template '[map]' failed to load properly") diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm new file mode 100644 index 00000000..275cf2f6 --- /dev/null +++ b/code/modules/admin/verbs/mapping.dm @@ -0,0 +1,335 @@ +//- Are all the floors with or without air, as they should be? (regular or airless) +//- Does the area have an APC? +//- Does the area have an Air Alarm? +//- Does the area have a Request Console? +//- Does the area have lights? +//- Does the area have a light switch? +//- Does the area have enough intercoms? +//- Does the area have enough security cameras? (Use the 'Camera Range Display' verb under Debug) +//- Is the area connected to the scrubbers air loop? +//- Is the area connected to the vent air loop? (vent pumps) +//- Is everything wired properly? +//- Does the area have a fire alarm and firedoors? +//- Do all pod doors work properly? +//- Are accesses set properly on doors, pod buttons, etc. +//- Are all items placed properly? (not below vents, scrubbers, tables) +//- Does the disposal system work properly from all the disposal units in this room and all the units, the pipes of which pass through this room? +//- Check for any misplaced or stacked piece of pipe (air and disposal) +//- Check for any misplaced or stacked piece of wire +//- Identify how hard it is to break into the area and where the weak points are +//- Check if the area has too much empty space. If so, make it smaller and replace the rest with maintenance tunnels. + +var/camera_range_display_status = 0 +var/intercom_range_display_status = 0 + +/obj/effect/debugging/camera_range + icon = 'icons/480x480.dmi' + icon_state = "25percent" + + New() + src.pixel_x = -224 + src.pixel_y = -224 + +/obj/effect/debugging/marker + icon = 'icons/turf/areas.dmi' + icon_state = "yellow" + +/obj/effect/debugging/marker/Move() + return 0 + +/client/proc/do_not_use_these() + set category = "Mapping" + set name = "-None of these are for ingame use!!" + + ..() + +/client/proc/camera_view() + set category = "Mapping" + set name = "Camera Range Display" + + if(camera_range_display_status) + camera_range_display_status = 0 + else + camera_range_display_status = 1 + + + + for(var/obj/effect/debugging/camera_range/C in world) + qdel(C) + + if(camera_range_display_status) + for(var/obj/machinery/camera/C in cameranet.cameras) + new/obj/effect/debugging/camera_range(C.loc) + feedback_add_details("admin_verb","mCRD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + + +/client/proc/sec_camera_report() + set category = "Mapping" + set name = "Camera Report" + + if(!master_controller) + alert(usr,"Master_controller not found.","Sec Camera Report") + return 0 + + var/list/obj/machinery/camera/CL = list() + + for(var/obj/machinery/camera/C in cameranet.cameras) + CL += C + + var/output = {"CAMERA ANNOMALITIES REPORT
            +The following annomalities have been detected. The ones in red need immediate attention: Some of those in black may be intentional.
              "} + + for(var/obj/machinery/camera/C1 in CL) + for(var/obj/machinery/camera/C2 in CL) + if(C1 != C2) + if(C1.c_tag == C2.c_tag) + output += "
            • c_tag match for sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) and \[[C2.x], [C2.y], [C2.z]\] ([C2.loc.loc]) - c_tag is [C1.c_tag]
            • " + if(C1.loc == C2.loc && C1.dir == C2.dir && C1.pixel_x == C2.pixel_x && C1.pixel_y == C2.pixel_y) + output += "
            • FULLY overlapping sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) Networks: [C1.network] and [C2.network]
            • " + if(C1.loc == C2.loc) + output += "
            • overlapping sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) Networks: [C1.network] and [C2.network]
            • " + var/turf/T = get_step(C1,turn(C1.dir,180)) + if(!T || !isturf(T) || !T.density ) + if(!(locate(/obj/structure/grille,T))) + var/window_check = 0 + for(var/obj/structure/window/W in T) + if (W.dir == turn(C1.dir,180) || W.dir in list(5,6,9,10) ) + window_check = 1 + break + if(!window_check) + output += "
            • Camera not connected to wall at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) Network: [C1.network]
            • " + + output += "
            " + usr << browse(output,"window=airreport;size=1000x500") + feedback_add_details("admin_verb","mCRP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/intercom_view() + set category = "Mapping" + set name = "Intercom Range Display" + + if(intercom_range_display_status) + intercom_range_display_status = 0 + else + intercom_range_display_status = 1 + + for(var/obj/effect/debugging/marker/M in world) + qdel(M) + + if(intercom_range_display_status) + for(var/obj/item/device/radio/intercom/I in world) + for(var/turf/T in orange(7,I)) + var/obj/effect/debugging/marker/F = new/obj/effect/debugging/marker(T) + if (!(F in view(7,I.loc))) + qdel(F) + feedback_add_details("admin_verb","mIRD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +var/list/debug_verbs = list ( + /client/proc/do_not_use_these + ,/client/proc/camera_view + ,/client/proc/sec_camera_report + ,/client/proc/intercom_view + ,/client/proc/Cell + ,/client/proc/atmosscan + ,/client/proc/powerdebug + ,/client/proc/count_objects_on_z_level + ,/client/proc/count_objects_all + ,/client/proc/cmd_assume_direct_control + ,/client/proc/startSinglo + ,/client/proc/ticklag + ,/client/proc/cmd_admin_grantfullaccess + ,/client/proc/cmd_admin_areatest + ,/client/proc/cmd_admin_rejuvenate + ,/datum/admins/proc/show_traitor_panel + ,/client/proc/print_jobban_old + ,/client/proc/print_jobban_old_filter + ,/client/proc/forceEvent + ,/client/proc/Zone_Info + ,/client/proc/Test_ZAS_Connection + ,/client/proc/rebootAirMaster + ,/client/proc/hide_debug_verbs + ,/client/proc/testZAScolors + ,/client/proc/testZAScolors_remove + ,/datum/admins/proc/setup_supermatter + ,/client/proc/atmos_toggle_debug + ,/client/proc/spawn_tanktransferbomb + ) + + +/client/proc/enable_debug_verbs() + set category = "Debug" + set name = "Debug verbs" + + if(!check_rights(R_DEBUG)) return + + verbs += debug_verbs + + feedback_add_details("admin_verb","mDV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/hide_debug_verbs() + set category = "Debug" + set name = "Hide Debug verbs" + + if(!check_rights(R_DEBUG)) return + + verbs -= debug_verbs + + feedback_add_details("admin_verb","hDV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/client/var/list/testZAScolors_turfs = list() +/client/var/list/testZAScolors_zones = list() +/client/var/usedZAScolors = 0 +/client/var/list/image/ZAScolors = list() + +/client/proc/recurse_zone(var/zone/Z, var/recurse_level =1) + testZAScolors_zones += Z + if(recurse_level > 10) + return + + for(var/turf/T in Z.contents) + images += get_zas_image(T, "yellow") + testZAScolors_turfs += T + for(var/connection_edge/zone/edge in Z.edges) + var/zone/connected = edge.get_connected_zone(Z) + if(connected in testZAScolors_zones) + continue + recurse_zone(connected,recurse_level+1) + + +/client/proc/testZAScolors() + set category = "ZAS" + set name = "Check ZAS connections" + + if(!check_rights(R_DEBUG)) return + testZAScolors_remove() + + var/turf/simulated/location = get_turf(usr) + + if(!istype(location, /turf/simulated)) + to_chat(src, "This debug tool can only be used while on a simulated turf.") + return + + if(!usedZAScolors) + to_chat(src, "ZAS Test Colors") + to_chat(src, "Green = Zone you are standing in") + to_chat(src, "Blue = Connected zone to the zone you are standing in") + to_chat(src, "Yellow = A zone that is connected but not one adjacent to your connected zone") + to_chat(src, "Red = Not connected") + usedZAScolors = 1 + + testZAScolors_zones += location.zone + for(var/turf/T in location.zone.contents) + images += get_zas_image(T, "green") + testZAScolors_turfs += T + for(var/connection_edge/zone/edge in location.zone.edges) + var/zone/Z = edge.get_connected_zone(location.zone) + testZAScolors_zones += Z + for(var/turf/T in Z.contents) + images += get_zas_image(T, "blue") + testZAScolors_turfs += T + for(var/connection_edge/zone/z_edge in Z.edges) + var/zone/connected = z_edge.get_connected_zone(Z) + if(connected in testZAScolors_zones) + continue + recurse_zone(connected,1) + + for(var/turf/T in range(25,location)) + if(!istype(T)) + continue + if(T in testZAScolors_turfs) + continue + images += get_zas_image(T, "red") + testZAScolors_turfs += T + +/client/proc/testZAScolors_remove() + set category = "ZAS" + set name = "Remove ZAS connection colors" + + testZAScolors_turfs.Cut() + testZAScolors_zones.Cut() + + for(var/image/i in images) + if(i.icon == 'icons/misc/debug_group.dmi') + images.Remove(i) + +/client/proc/rebootAirMaster() + set category = "ZAS" + set name = "Reboot ZAS" + + if(alert("This will destroy and remake all zone geometry on the whole map.","Reboot ZAS","Reboot ZAS","Nevermind") == "Reboot ZAS") + SSair.reboot() + + +/client/proc/count_objects_on_z_level() + set category = "Mapping" + set name = "Count Objects On Level" + var/level = input("Which z-level?","Level?") as text + if(!level) return + var/num_level = text2num(level) + if(!num_level) return + if(!isnum(num_level)) return + + var/type_text = input("Which type path?","Path?") as text + if(!type_text) return + var/type_path = text2path(type_text) + if(!type_path) return + + var/count = 1 + + var/list/atom/atom_list = list() + + for(var/atom/A in world) + if(istype(A,type_path)) + var/atom/B = A + while(!(isturf(B.loc))) + if(B && B.loc) + B = B.loc + else + break + if(B) + if(B.z == num_level) + count++ + atom_list += A + /* + var/atom/temp_atom + for(var/i = 0; i <= (atom_list.len/10); i++) + var/line = "" + for(var/j = 1; j <= 10; j++) + if(i*10+j <= atom_list.len) + temp_atom = atom_list[i*10+j] + line += " no.[i+10+j]@\[[temp_atom.x], [temp_atom.y], [temp_atom.z]\]; " + log_debug(line) */ + + log_debug("There are [count] objects of type [type_path] on z-level [num_level]") + feedback_add_details("admin_verb","mOBJZ") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/count_objects_all() + set category = "Mapping" + set name = "Count Objects All" + + var/type_text = input("Which type path?","") as text + if(!type_text) return + var/type_path = text2path(type_text) + if(!type_path) return + + var/count = 0 + + for(var/atom/A in world) + if(istype(A,type_path)) + count++ + /* + var/atom/temp_atom + for(var/i = 0; i <= (atom_list.len/10); i++) + var/line = "" + for(var/j = 1; j <= 10; j++) + if(i*10+j <= atom_list.len) + temp_atom = atom_list[i*10+j] + line += " no.[i+10+j]@\[[temp_atom.x], [temp_atom.y], [temp_atom.z]\]; " + log_debug(line) */ + + log_debug("There are [count] objects of type [type_path] in the game world") + feedback_add_details("admin_verb","mOBJ") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/proc/get_zas_image(var/turf/T, var/icon_state) + return image_repository.atom_image(T, 'icons/misc/debug_group.dmi', icon_state, plane = ABOVE_TURF_PLANE, layer = ABOVE_TILE_LAYER) diff --git a/code/modules/admin/verbs/massmodvar.dm b/code/modules/admin/verbs/massmodvar.dm new file mode 100644 index 00000000..249bee2f --- /dev/null +++ b/code/modules/admin/verbs/massmodvar.dm @@ -0,0 +1,375 @@ +/client/proc/cmd_mass_modify_object_variables(atom/A, var/var_name) + set category = "Debug" + set name = "Mass Edit Variables" + set desc="(target) Edit all instances of a target item's variables" + + var/method = 0 //0 means strict type detection while 1 means this type and all subtypes (IE: /obj/item with this set to 1 will set it to ALL itms) + + if(!check_rights(R_VAREDIT)) return + + if(A && A.type) + if(typesof(A.type)) + switch(input("Strict object type detection?") as null|anything in list("Strictly this type","This type and subtypes", "Cancel")) + if("Strictly this type") + method = 0 + if("This type and subtypes") + method = 1 + if("Cancel") + return + if(null) + return + + src.massmodify_variables(A, var_name, method) + feedback_add_details("admin_verb","MEV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/client/proc/massmodify_variables(var/atom/O, var/var_name = "", var/method = 0) + if(!check_rights(R_VAREDIT)) return + + var/list/locked = list("vars", "key", "ckey", "client") + + for(var/p in forbidden_varedit_object_types()) + if( istype(O,p) ) + to_chat(usr, "It is forbidden to edit this object's variables.") + return + + var/list/names = list() + for (var/V in O.vars) + names += V + + names = sortList(names) + + var/variable = "" + + if(!var_name) + variable = input("Which var?","Var") as null|anything in names + else + variable = var_name + + if(!variable) return + var/default + var/var_value = O.vars[variable] + var/dir + + if(variable == "holder" || (variable in locked)) + if(!check_rights(R_DEBUG)) return + + if(isnull(var_value)) + to_chat(usr, "Unable to determine variable type.") + + else if(isnum(var_value)) + to_chat(usr, "Variable appears to be NUM.") + default = "num" + dir = 1 + + else if(istext(var_value)) + to_chat(usr, "Variable appears to be TEXT.") + default = "text" + + else if(isloc(var_value)) + to_chat(usr, "Variable appears to be REFERENCE.") + default = "reference" + + else if(isicon(var_value)) + to_chat(usr, "Variable appears to be ICON.") + var_value = "\icon[var_value]" + default = "icon" + + else if(istype(var_value,/atom) || istype(var_value,/datum)) + to_chat(usr, "Variable appears to be TYPE.") + default = "type" + + else if(istype(var_value,/list)) + to_chat(usr, "Variable appears to be LIST.") + default = "list" + + else if(istype(var_value,/client)) + to_chat(usr, "Variable appears to be CLIENT.") + default = "cancel" + + else + to_chat(usr, "Variable appears to be FILE.") + default = "file" + + to_chat(usr, "Variable contains: [var_value]") + if(dir) + switch(var_value) + if(1) + dir = "NORTH" + if(2) + dir = "SOUTH" + if(4) + dir = "EAST" + if(8) + dir = "WEST" + if(5) + dir = "NORTHEAST" + if(6) + dir = "SOUTHEAST" + if(9) + dir = "NORTHWEST" + if(10) + dir = "SOUTHWEST" + else + dir = null + if(dir) + to_chat(usr, "If a direction, direction is: [dir]") + + var/class = input("What kind of variable?","Variable Type",default) as null|anything in list("text", + "num","type","icon","file","edit referenced object","restore to default") + + if(!class) + return + + var/original_name + + if (!istype(O, /atom)) + original_name = "\ref[O] ([O])" + else + original_name = O:name + + switch(class) + + if("restore to default") + O.vars[variable] = initial(O.vars[variable]) + if(method) + if(istype(O, /mob)) + for(var/mob/M in SSmobs.mob_list) + if ( istype(M , O.type) ) + M.vars[variable] = O.vars[variable] + + else if(istype(O, /obj)) + for(var/obj/A in world) + if ( istype(A , O.type) ) + A.vars[variable] = O.vars[variable] + + else if(istype(O, /turf)) + for(var/turf/A in world) + if ( istype(A , O.type) ) + A.vars[variable] = O.vars[variable] + + else + if(istype(O, /mob)) + for(var/mob/M in SSmobs.mob_list) + if (M.type == O.type) + M.vars[variable] = O.vars[variable] + + else if(istype(O, /obj)) + for(var/obj/A in world) + if (A.type == O.type) + A.vars[variable] = O.vars[variable] + + else if(istype(O, /turf)) + for(var/turf/A in world) + if (A.type == O.type) + A.vars[variable] = O.vars[variable] + + if("edit referenced object") + return .(O.vars[variable]) + + if("text") + var/new_value = input("Enter new text:","Text",O.vars[variable]) as text|null//todo: sanitize ??? + if(new_value == null) return + O.vars[variable] = new_value + + if(method) + if(istype(O, /mob)) + for(var/mob/M in SSmobs.mob_list) + if ( istype(M , O.type) ) + M.vars[variable] = O.vars[variable] + + else if(istype(O, /obj)) + for(var/obj/A in world) + if ( istype(A , O.type) ) + A.vars[variable] = O.vars[variable] + + else if(istype(O, /turf)) + for(var/turf/A in world) + if ( istype(A , O.type) ) + A.vars[variable] = O.vars[variable] + else + if(istype(O, /mob)) + for(var/mob/M in SSmobs.mob_list) + if (M.type == O.type) + M.vars[variable] = O.vars[variable] + + else if(istype(O, /obj)) + for(var/obj/A in world) + if (A.type == O.type) + A.vars[variable] = O.vars[variable] + + else if(istype(O, /turf)) + for(var/turf/A in world) + if (A.type == O.type) + A.vars[variable] = O.vars[variable] + + if("num") + var/new_value = input("Enter new number:","Num",\ + O.vars[variable]) as num|null + if(new_value == null) return + + if(variable=="light_range") + O.set_light(new_value) + else + O.vars[variable] = new_value + + if(method) + if(istype(O, /mob)) + for(var/mob/M in SSmobs.mob_list) + if ( istype(M , O.type) ) + if(variable=="light_range") + M.set_light(new_value) + else + M.vars[variable] = O.vars[variable] + + else if(istype(O, /obj)) + for(var/obj/A in world) + if ( istype(A , O.type) ) + if(variable=="light_range") + A.set_light(new_value) + else + A.vars[variable] = O.vars[variable] + + else if(istype(O, /turf)) + for(var/turf/A in world) + if ( istype(A , O.type) ) + if(variable=="light_range") + A.set_light(new_value) + else + A.vars[variable] = O.vars[variable] + + else + if(istype(O, /mob)) + for(var/mob/M in SSmobs.mob_list) + if (M.type == O.type) + if(variable=="light_range") + M.set_light(new_value) + else + M.vars[variable] = O.vars[variable] + + else if(istype(O, /obj)) + for(var/obj/A in world) + if (A.type == O.type) + if(variable=="light_range") + A.set_light(new_value) + else + A.vars[variable] = O.vars[variable] + + else if(istype(O, /turf)) + for(var/turf/A in world) + if (A.type == O.type) + if(variable=="light_range") + A.set_light(new_value) + else + A.vars[variable] = O.vars[variable] + + if("type") + var/new_value + new_value = input("Enter type:","Type",O.vars[variable]) as null|anything in typesof(/obj,/mob,/area,/turf) + if(new_value == null) return + O.vars[variable] = new_value + if(method) + if(istype(O, /mob)) + for(var/mob/M in SSmobs.mob_list) + if ( istype(M , O.type) ) + M.vars[variable] = O.vars[variable] + + else if(istype(O, /obj)) + for(var/obj/A in world) + if ( istype(A , O.type) ) + A.vars[variable] = O.vars[variable] + + else if(istype(O, /turf)) + for(var/turf/A in world) + if ( istype(A , O.type) ) + A.vars[variable] = O.vars[variable] + else + if(istype(O, /mob)) + for(var/mob/M in SSmobs.mob_list) + if (M.type == O.type) + M.vars[variable] = O.vars[variable] + + else if(istype(O, /obj)) + for(var/obj/A in world) + if (A.type == O.type) + A.vars[variable] = O.vars[variable] + + else if(istype(O, /turf)) + for(var/turf/A in world) + if (A.type == O.type) + A.vars[variable] = O.vars[variable] + + if("file") + var/new_value = input("Pick file:","File",O.vars[variable]) as null|file + if(new_value == null) return + O.vars[variable] = new_value + + if(method) + if(istype(O, /mob)) + for(var/mob/M in SSmobs.mob_list) + if ( istype(M , O.type) ) + M.vars[variable] = O.vars[variable] + + else if(istype(O.type, /obj)) + for(var/obj/A in world) + if ( istype(A , O.type) ) + A.vars[variable] = O.vars[variable] + + else if(istype(O.type, /turf)) + for(var/turf/A in world) + if ( istype(A , O.type) ) + A.vars[variable] = O.vars[variable] + else + if(istype(O, /mob)) + for(var/mob/M in SSmobs.mob_list) + if (M.type == O.type) + M.vars[variable] = O.vars[variable] + + else if(istype(O.type, /obj)) + for(var/obj/A in world) + if (A.type == O.type) + A.vars[variable] = O.vars[variable] + + else if(istype(O.type, /turf)) + for(var/turf/A in world) + if (A.type == O.type) + A.vars[variable] = O.vars[variable] + + if("icon") + var/new_value = input("Pick icon:","Icon",O.vars[variable]) as null|icon + if(new_value == null) return + O.vars[variable] = new_value + if(method) + if(istype(O, /mob)) + for(var/mob/M in SSmobs.mob_list) + if ( istype(M , O.type) ) + M.vars[variable] = O.vars[variable] + + else if(istype(O, /obj)) + for(var/obj/A in world) + if ( istype(A , O.type) ) + A.vars[variable] = O.vars[variable] + + else if(istype(O, /turf)) + for(var/turf/A in world) + if ( istype(A , O.type) ) + A.vars[variable] = O.vars[variable] + + else + if(istype(O, /mob)) + for(var/mob/M in SSmobs.mob_list) + if (M.type == O.type) + M.vars[variable] = O.vars[variable] + + else if(istype(O, /obj)) + for(var/obj/A in world) + if (A.type == O.type) + A.vars[variable] = O.vars[variable] + + else if(istype(O, /turf)) + for(var/turf/A in world) + if (A.type == O.type) + A.vars[variable] = O.vars[variable] + + log_admin("[key_name(src)] mass modified [original_name]'s [variable] to [O.vars[variable]]") + message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [O.vars[variable]]", 1) diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm new file mode 100644 index 00000000..08032e65 --- /dev/null +++ b/code/modules/admin/verbs/modifyvariables.dm @@ -0,0 +1,595 @@ + +/client/proc/cmd_modify_ticker_variables() + set category = "Debug" + set name = "Edit Ticker Variables" + + if (ticker == null) + to_chat(src, "Game hasn't started yet.") + else + src.modify_variables(ticker) + feedback_add_details("admin_verb","ETV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/mod_list_add_ass() + var/class = "text" + var/list/class_input = list("text","num","type","reference","mob reference", "icon","file","color","list","edit referenced object","restore to default") + if(src.holder) + var/datum/marked_datum = holder.marked_datum() + if(marked_datum) + class_input += "marked datum ([marked_datum.type])" + + class = input("What kind of variable?","Variable Type") as null|anything in class_input + if(!class) + return + + var/datum/marked_datum = holder.marked_datum() + if(marked_datum && class == "marked datum ([marked_datum.type])") + class = "marked datum" + + var/var_value = null + + switch(class) + + if("text") + var_value = input("Enter new text:","Text") as null|text + + if("num") + var_value = input("Enter new number:","Num") as null|num + + if("type") + var_value = input("Enter type:","Type") as null|anything in typesof(/obj,/mob,/area,/turf) + + if("reference") + var_value = input("Select reference:","Reference") as null|mob|obj|turf|area in world + + if("mob reference") + var_value = input("Select reference:","Reference") as null|mob in world + + if("file") + var_value = input("Pick file:","File") as null|file + + if("icon") + var_value = input("Pick icon:","Icon") as null|icon + + if("marked datum") + var_value = holder.marked_datum() + + if("color") + var_value = input("Select new color:","Color") as null|color + + if(!var_value) return + + return var_value + + +/client/proc/mod_list_add(var/list/L, atom/O, original_name, objectvar) + + var/class = "text" + var/list/class_input = list("text","num","type","reference","mob reference", "icon","file","list","color","edit referenced object","restore to default") + if(src.holder) + var/datum/marked_datum = holder.marked_datum() + if(marked_datum) + class_input += "marked datum ([marked_datum.type])" + + class = input("What kind of variable?","Variable Type") as null|anything in class_input + if(!class) + return + + var/datum/marked_datum = holder.marked_datum() + if(marked_datum && class == "marked datum ([marked_datum.type])") + class = "marked datum" + + var/var_value = null + + switch(class) + + if("text") + var_value = input("Enter new text:","Text") as text + + if("num") + var_value = input("Enter new number:","Num") as num + + if("type") + var_value = input("Enter type:","Type") in typesof(/obj,/mob,/area,/turf) + + if("reference") + var_value = input("Select reference:","Reference") as mob|obj|turf|area in world + + if("mob reference") + var_value = input("Select reference:","Reference") as mob in world + + if("file") + var_value = input("Pick file:","File") as file + + if("icon") + var_value = input("Pick icon:","Icon") as icon + + if("marked datum") + var_value = holder.marked_datum() + + if(!var_value) return + + switch(alert("Would you like to associate a var with the list entry?",,"Yes","No")) + if("Yes") + L += var_value + L[var_value] = mod_list_add_ass() //haha + if("No") + L += var_value + world.log << "### ListVarEdit by [src]: [O.type] [objectvar]: ADDED=[var_value]" + log_admin("[key_name(src)] modified [original_name]'s [objectvar]: ADDED=[var_value]") + message_admins("[key_name_admin(src)] modified [original_name]'s [objectvar]: ADDED=[var_value]") + +/client/proc/mod_list(var/list/L, atom/O, original_name, objectvar) + if(!check_rights(R_VAREDIT)) return + if(!istype(L,/list)) to_chat(src, "Not a List.") + if(L.len > 1000) + var/confirm = alert(src, "The list you're trying to edit is very long, continuing may crash the server.", "Warning", "Continue", "Abort") + if(confirm != "Continue") + return + + var/assoc = 0 + if(L.len > 0) + var/a = L[1] + try + if(!isnum(a) && L[a] != null) + assoc = 1 //This is pretty weak test but I can't think of anything else + to_chat(usr, "List appears to be associative.") + catch {} // Builtin non-assoc lists (contents, etc.) will runtime if you try to get an assoc value of them + + var/list/names = null + if(!assoc) + names = sortList(L) + + var/variable + var/assoc_key + if(assoc) + variable = input("Which var?","Var") as null|anything in L + "(ADD VAR)" + else + variable = input("Which var?","Var") as null|anything in names + "(ADD VAR)" + + if(variable == "(ADD VAR)") + mod_list_add(L, O, original_name, objectvar) + return + + if(assoc) + assoc_key = variable + variable = L[assoc_key] + + if(!assoc && !variable || assoc && !assoc_key) + return + + var/default + + var/dir + + if(!O.may_edit_var(usr, objectvar)) + return + + if(isnull(variable)) + to_chat(usr, "Unable to determine variable type.") + else if(isnum(variable)) + to_chat(usr, "Variable appears to be NUM.") + default = "num" + dir = 1 + + else if(istext(variable)) + to_chat(usr, "Variable appears to be TEXT.") + default = "text" + + else if(isloc(variable)) + to_chat(usr, "Variable appears to be REFERENCE.") + default = "reference" + + else if(isicon(variable)) + to_chat(usr, "Variable appears to be ICON.") + variable = "\icon[variable]" + default = "icon" + + else if(istype(variable,/atom) || istype(variable,/datum)) + to_chat(usr, "Variable appears to be TYPE.") + default = "type" + + else if(istype(variable,/list)) + to_chat(usr, "Variable appears to be LIST.") + default = "list" + + else if(istype(variable,/client)) + to_chat(usr, "Variable appears to be CLIENT.") + default = "cancel" + + else + to_chat(usr, "Variable appears to be FILE.") + default = "file" + + to_chat(usr, "Variable contains: [variable]") + if(dir) + switch(variable) + if(1) + dir = "NORTH" + if(2) + dir = "SOUTH" + if(4) + dir = "EAST" + if(8) + dir = "WEST" + if(5) + dir = "NORTHEAST" + if(6) + dir = "SOUTHEAST" + if(9) + dir = "NORTHWEST" + if(10) + dir = "SOUTHWEST" + else + dir = null + + if(dir) + to_chat(usr, "If a direction, direction is: [dir]") + var/class = "text" + var/list/class_input = list("text","num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default") + + if(src.holder) + var/datum/marked_datum = holder.marked_datum() + if(marked_datum) + class_input += "marked datum ([marked_datum.type])" + + class_input += "DELETE FROM LIST" + class = input("What kind of variable?","Variable Type",default) as null|anything in class_input + + if(!class) + return + + var/datum/marked_datum = holder.marked_datum() + if(marked_datum && class == "marked datum ([marked_datum.type])") + class = "marked datum" + + var/original_var + if(assoc) + original_var = L[assoc_key] + else + original_var = L[L.Find(variable)] + + var/new_var + switch(class) //Spits a runtime error if you try to modify an entry in the contents list. Dunno how to fix it, yet. + + if("list") + mod_list(variable, O, original_name, objectvar) + + if("restore to default") + new_var = initial(variable) + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var + + if("edit referenced object") + modify_variables(variable) + + if("DELETE FROM LIST") + world.log << "### ListVarEdit by [src]: [O.type] [objectvar]: REMOVED=[html_encode("[variable]")]" + log_admin("[key_name(src)] modified [original_name]'s [objectvar]: REMOVED=[variable]") + message_admins("[key_name_admin(src)] modified [original_name]'s [objectvar]: REMOVED=[variable]") + L -= variable + return + + if("text") + new_var = input("Enter new text:","Text") as text + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var + + if("num") + new_var = input("Enter new number:","Num") as num + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var + + if("type") + new_var = input("Enter type:","Type") in typesof(/obj,/mob,/area,/turf) + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var + + if("reference") + new_var = input("Select reference:","Reference") as mob|obj|turf|area in world + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var + + if("mob reference") + new_var = input("Select reference:","Reference") as mob in world + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var + + if("file") + new_var = input("Pick file:","File") as file + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var + + if("icon") + new_var = input("Pick icon:","Icon") as icon + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var + + if("marked datum") + new_var = holder.marked_datum() + if(!new_var) + return + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var + + world.log << "### ListVarEdit by [src]: [O.type] [objectvar]: [original_var]=[new_var]" + log_admin("[key_name(src)] modified [original_name]'s [objectvar]: [original_var]=[new_var]") + message_admins("[key_name_admin(src)] modified [original_name]'s varlist [objectvar]: [original_var]=[new_var]") + +/client/proc/modify_variables(var/atom/O, var/param_var_name = null, var/autodetect_class = 0) + if(!check_rights(R_VAREDIT)) return + + for(var/p in forbidden_varedit_object_types()) + if( istype(O,p) ) + to_chat(usr, "It is forbidden to edit this object's variables.") + return + + var/class + var/variable + var/var_value + + if(param_var_name) + if(!(param_var_name in O.get_variables())) + to_chat(src, "A variable with this name ([param_var_name]) doesn't exist in this atom ([O])") + return + + if(!O.may_edit_var(usr, param_var_name)) + return + + variable = param_var_name + + var_value = O.get_variable_value(variable) + + if(autodetect_class) + if(isnull(var_value)) + to_chat(usr, "Unable to determine variable type.") + class = null + autodetect_class = null + else if(isnum(var_value)) + to_chat(usr, "Variable appears to be NUM.") + class = "num" + dir = 1 + + else if(istext(var_value)) + to_chat(usr, "Variable appears to be TEXT.") + class = "text" + + else if(isloc(var_value)) + to_chat(usr, "Variable appears to be REFERENCE.") + class = "reference" + + else if(isicon(var_value)) + to_chat(usr, "Variable appears to be ICON.") + var_value = "\icon[var_value]" + class = "icon" + + else if(istype(var_value,/atom) || istype(var_value,/datum)) + to_chat(usr, "Variable appears to be TYPE.") + class = "type" + + else if(istype(var_value,/list)) + to_chat(usr, "Variable appears to be LIST.") + class = "list" + + else if(istype(var_value,/client)) + to_chat(usr, "Variable appears to be CLIENT.") + class = "cancel" + + else + to_chat(usr, "Variable appears to be FILE.") + class = "file" + + else + + var/list/names = list() + for (var/V in O.vars) + names += V + + names = sortList(names) + + variable = input("Which var?","Var") as null|anything in names + if(!variable) return + var_value = O.get_variable_value(variable) + + if(!O.may_edit_var(usr, variable)) + return + + if(!autodetect_class) + + var/dir + var/default + if(isnull(var_value)) + to_chat(usr, "Unable to determine variable type.") + else if(isnum(var_value)) + to_chat(usr, "Variable appears to be NUM.") + default = "num" + dir = 1 + + else if(istext(var_value)) + to_chat(usr, "Variable appears to be TEXT.") + default = "text" + + else if(isloc(var_value)) + to_chat(usr, "Variable appears to be REFERENCE.") + default = "reference" + + else if(isicon(var_value)) + to_chat(usr, "Variable appears to be ICON.") + var_value = "\icon[var_value]" + default = "icon" + + else if(istype(var_value,/atom) || istype(var_value,/datum)) + to_chat(usr, "Variable appears to be TYPE.") + default = "type" + + else if(istype(var_value,/list)) + to_chat(usr, "Variable appears to be LIST.") + default = "list" + + else if(istype(var_value,/client)) + to_chat(usr, "Variable appears to be CLIENT.") + default = "cancel" + + else + to_chat(usr, "Variable appears to be FILE.") + default = "file" + + to_chat(usr, "Variable contains: [var_value]") + if(dir) + switch(var_value) + if(1) + dir = "NORTH" + if(2) + dir = "SOUTH" + if(4) + dir = "EAST" + if(8) + dir = "WEST" + if(5) + dir = "NORTHEAST" + if(6) + dir = "SOUTHEAST" + if(9) + dir = "NORTHWEST" + if(10) + dir = "SOUTHWEST" + else + dir = null + if(dir) + to_chat(usr, "If a direction, direction is: [dir]") + var/list/class_input = list("text","num","type","reference","mob reference", "icon","file","list","json","color","edit referenced object","restore to default") + if(src.holder) + var/datum/marked_datum = holder.marked_datum() + if(marked_datum) + class_input += "marked datum ([marked_datum.type])" + class = input("What kind of variable?","Variable Type",default) as null|anything in class_input + + if(!class) + return + + var/original_name + + if (!istype(O, /atom)) + original_name = "\ref[O] ([O])" + else + original_name = O:name + + var/datum/marked_datum = holder.marked_datum() + if(marked_datum && class == "marked datum ([marked_datum.type])") + class = "marked datum" + + switch(class) + + if("list") + mod_list(O.get_variable_value(variable), O, original_name, variable) + return + + if("restore to default") + var_value = O.get_initial_variable_value(variable) + + if("edit referenced object") + return .(O.get_variable_value(variable)) + + if("text") + var/var_new = input("Enter new text:","Text",O.get_variable_value(variable)) as null|text + if(var_new==null) return + var_value = var_new + + if("num") + if(variable=="light_range") + var/var_new = input("Enter new number:","Num",O.get_variable_value(variable)) as null|num + if(var_new == null) return + O.set_light(var_new) + else if(variable=="stat") + var/var_new = input("Enter new number:","Num",O.get_variable_value(variable)) as null|num + if(var_new == null) return + if((O.get_variable_value(variable) == 2) && (var_new < 2))//Bringing the dead back to life + var/mob/M = O + M.switch_from_dead_to_living_mob_list() + if((O.get_variable_value(variable) < 2) && (var_new == 2))//Kill he + var/mob/M = O + M.switch_from_living_to_dead_mob_list() + var_value = var_new + else + var/var_new = input("Enter new number:","Num",O.get_variable_value(variable)) as null|num + if(var_new==null) return + var_value = var_new + + if("type") + var/var_new = input("Enter type:","Type",O.get_variable_value(variable)) as null|anything in typesof(/obj,/mob,/area,/turf) + if(var_new==null) return + var_value = var_new + + if("reference") + var/var_new = input("Select reference:","Reference",O.get_variable_value(variable)) as null|mob|obj|turf|area in world + if(var_new==null) return + var_value = var_new + + if("mob reference") + var/var_new = input("Select reference:","Reference",O.get_variable_value(variable)) as null|mob in world + if(var_new==null) return + var_value = var_new + + if("file") + var/var_new = input("Pick file:","File",O.get_variable_value(variable)) as null|file + if(var_new==null) return + var_value = var_new + + if("icon") + var/var_new = input("Pick icon:","Icon",O.get_variable_value(variable)) as null|icon + if(var_new==null) return + var_value = var_new + + if("color") + var_value = input("Select new color:","Color") as null|color + + if("json") + var/json_str = input("JSON string", "JSON", json_encode(O.get_variable_value(variable))) as null | message + try + var_value = json_decode(json_str) + catch + return + + if("marked datum") + var_value = holder.marked_datum() + + var/old_value = O.get_variable_value(variable) + if(!special_set_vv_var(O, variable, var_value, src)) + O.set_variable_value(variable, var_value) + + var/new_value = O.get_variable_value(variable) + if(old_value == new_value) + return + + world.log << "### VarEdit by [src]: [O.type] [variable]=[html_encode("[new_value]")]" + log_and_message_admins("modified [original_name]'s [variable] from '[old_value]' to '[new_value]'") + +/client + var/static/vv_set_handlers + +/client/proc/special_set_vv_var(var/datum/O, variable, var_value, client) + if(!vv_set_handlers) + vv_set_handlers = init_subtypes(/decl/vv_set_handler) + for(var/vv_handler in vv_set_handlers) + var/decl/vv_set_handler/sh = vv_handler + if(sh.can_handle_set_var(O, variable, var_value, client)) + sh.handle_set_var(O, variable, var_value, client) + return TRUE + return FALSE diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm new file mode 100644 index 00000000..aa17e489 --- /dev/null +++ b/code/modules/admin/verbs/playsound.dm @@ -0,0 +1,49 @@ +var/list/sounds_cache = list() + +/client/proc/play_sound(S as sound) + set category = "Fun" + set name = "Play Global Sound" + if(!check_rights(R_SOUNDS)) return + + var/sound/uploaded_sound = sound(S, repeat = 0, wait = 1, channel = 777) + uploaded_sound.priority = 250 + + sounds_cache += S + + if(alert("Do you ready?\nSong: [S]\nNow you can also play this sound using \"Play Server Sound\".", "Confirmation request" ,"Play", "Cancel") == "Cancel") + return + + log_admin("[key_name(src)] played sound [S]") + message_admins("[key_name_admin(src)] played sound [S]", 1) + for(var/mob/M in GLOB.player_list) + if(M.get_preference_value(/datum/client_preference/play_admin_midis) == GLOB.PREF_YES) + sound_to(M, uploaded_sound) + + feedback_add_details("admin_verb","PGS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/play_local_sound(S as sound) + set category = "Fun" + set name = "Play Local Sound" + if(!check_rights(R_SOUNDS)) return + + log_admin("[key_name(src)] played a local sound [S]") + message_admins("[key_name_admin(src)] played a local sound [S]", 1) + playsound(get_turf(src.mob), S, 50, 0, 0) + feedback_add_details("admin_verb","PLS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/client/proc/play_server_sound() + set category = "Fun" + set name = "Play Server Sound" + if(!check_rights(R_SOUNDS)) return + + var/list/sounds = file2list("sound/serversound_list.txt"); + sounds += "--CANCEL--" + sounds += sounds_cache + + var/melody = input("Select a sound from the server to play", "Server sound list", "--CANCEL--") in sounds + + if(melody == "--CANCEL--") return + + play_sound(melody) + feedback_add_details("admin_verb","PSS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/possess.dm b/code/modules/admin/verbs/possess.dm new file mode 100644 index 00000000..5a50951e --- /dev/null +++ b/code/modules/admin/verbs/possess.dm @@ -0,0 +1,53 @@ +/proc/possess(obj/O as obj) + set name = "Possess Obj" + set category = "Object" + + if(istype(O,/obj/singularity)) + if(config.forbid_singulo_possession) + to_chat(usr, "It is forbidden to possess singularities.") + return + + var/turf/T = get_turf(O) + + if(T) + log_admin("[key_name(usr)] has possessed [O] ([O.type]) at ([T.x], [T.y], [T.z])") + message_admins("[key_name(usr)] has possessed [O] ([O.type]) at ([T.x], [T.y], [T.z])", 1) + else + log_admin("[key_name(usr)] has possessed [O] ([O.type]) at an unknown location") + message_admins("[key_name(usr)] has possessed [O] ([O.type]) at an unknown location", 1) + + if(!usr.control_object) //If you're not already possessing something... + usr.name_archive = usr.real_name + + usr.forceMove(O) + usr.real_name = O.name + usr.SetName(O.name) + usr.client.eye = O + usr.control_object = O + feedback_add_details("admin_verb","PO") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/proc/release(obj/O) + set name = "Release Obj" + set category = "Object" + //usr.loc = get_turf(usr) + + if(usr.control_object && usr.name_archive) //if you have a name archived and if you are actually relassing an object + usr.real_name = usr.name_archive + usr.SetName(usr.real_name) + if(ishuman(usr)) + var/mob/living/carbon/human/H = usr + H.SetName(H.get_visible_name()) +// usr.regenerate_icons() //So the name is updated properly + + usr.forceMove(O.loc) // Appear where the object you were controlling is -- TLE + usr.client.eye = usr + usr.control_object = null + feedback_add_details("admin_verb","RO") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/proc/givetestverbs(mob/M as mob in SSmobs.mob_list) + set desc = "Give this guy possess/release verbs" + set category = "Debug" + set name = "Give Possessing Verbs" + M.verbs += /proc/possess + M.verbs += /proc/release + feedback_add_details("admin_verb","GPV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! \ No newline at end of file diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm new file mode 100644 index 00000000..5b4e6b8c --- /dev/null +++ b/code/modules/admin/verbs/pray.dm @@ -0,0 +1,22 @@ +/mob/verb/pray(msg as text) + set category = "IC" + set name = "Pray" + + sanitize_and_communicate(/decl/communication_channel/pray, src, msg) + feedback_add_details("admin_verb","PR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/proc/Centcomm_announce(var/msg, var/mob/Sender, var/iamessage) + var/mob/intercepted = check_for_interception() + msg = "[uppertext(GLOB.using_map.boss_short)]M[iamessage ? " IA" : ""][intercepted ? "(Intercepted by [intercepted])" : null]:[key_name(Sender, 1)] (PP) (VV) (SM) ([admin_jump_link(Sender, src)]) (CA) (BSA) (RPLY): [msg]" + for(var/client/C in GLOB.admins) + if(R_ADMIN & C.holder.rights) + to_chat(C, msg) + sound_to(C, 'sound/machines/signal.ogg') + +/proc/Syndicate_announce(var/msg, var/mob/Sender) + var/mob/intercepted = check_for_interception() + msg = "ILLEGAL[intercepted ? "(Intercepted by [intercepted])" : null]:[key_name(Sender, 1)] (PP) (VV) (SM) ([admin_jump_link(Sender, src)]) (CA) (BSA) (TAKE) (RPLY): [msg]" + for(var/client/C in GLOB.admins) + if(R_ADMIN & C.holder.rights) + to_chat(C, msg) + sound_to(C, 'sound/machines/signal.ogg') \ No newline at end of file diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm new file mode 100644 index 00000000..16c1cf91 --- /dev/null +++ b/code/modules/admin/verbs/randomverbs.dm @@ -0,0 +1,855 @@ +/client/proc/cmd_admin_drop_everything(mob/M as mob in SSmobs.mob_list) + set category = null + set name = "Drop Everything" + if(!holder) + to_chat(src, "Only administrators may use this command.") + return + + var/confirm = alert(src, "Make [M] drop everything?", "Message", "Yes", "No") + if(confirm != "Yes") + return + + for(var/obj/item/W in M) + M.drop_from_inventory(W) + + log_admin("[key_name(usr)] made [key_name(M)] drop everything!") + message_admins("[key_name_admin(usr)] made [key_name_admin(M)] drop everything!", 1) + feedback_add_details("admin_verb","DEVR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_prison(mob/M as mob in SSmobs.mob_list) + set category = "Admin" + set name = "Prison" + if(!holder) + to_chat(src, "Only administrators may use this command.") + return + if (ismob(M)) + if(istype(M, /mob/living/silicon/ai)) + alert("The AI can't be sent to prison you jerk!", null, null, null, null, null) + return + //strip their stuff before they teleport into a cell :downs: + for(var/obj/item/W in M) + M.drop_from_inventory(W) + //teleport person to cell + M.Paralyse(5) + sleep(5) //so they black out before warping + M.forceMove(pick(GLOB.prisonwarp)) + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/prisoner = M + prisoner.equip_to_slot_or_del(new /obj/item/clothing/under/color/orange(prisoner), slot_w_uniform) + prisoner.equip_to_slot_or_del(new /obj/item/clothing/shoes/orange(prisoner), slot_shoes) + spawn(50) + to_chat(M, "You have been sent to the prison station!") + log_and_message_admins("sent [key_name_admin(M)] to the prison station.") + feedback_add_details("admin_verb","PRISON") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_subtle_message(mob/M as mob in SSmobs.mob_list) + set category = "Special Verbs" + set name = "Subtle Message" + + if(!ismob(M)) return + if (!holder) + to_chat(src, "Only administrators may use this command.") + return + + var/msg = sanitize(input("Message:", text("Subtle PM to [M.key]")) as text) + + if (!msg) + return + if(usr) + if (usr.client) + if(usr.client.holder) + to_chat(M, "You hear a voice in your head... [msg]") + log_and_message_staff(" - SubtleMessage -> [key_name_admin(M)] : [msg]") + feedback_add_details("admin_verb","SMS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_mentor_check_new_players() //Allows mentors / admins to determine who the newer players are. + set category = "Admin" + set name = "Check new Players" + if(!holder) + to_chat(src, "Only staff members may use this command.") + + var/age = alert(src, "Age check", "Show accounts yonger then _____ days","7", "30" , "All") + + if(age == "All") + age = 9999999 + else + age = text2num(age) + + var/missing_ages = 0 + var/msg = "" + + var/highlight_special_characters = 1 + if(is_mentor(usr.client)) + highlight_special_characters = 0 + + for(var/client/C in GLOB.clients) + if(C.player_age == "Requires database") + missing_ages = 1 + continue + if(C.player_age < age) + msg += "[key_name(C, 1, 1, highlight_special_characters)]: account is [C.player_age] days old
            " + + if(missing_ages) + to_chat(src, "Some accounts did not have proper ages set in their clients. This function requires database to be present") + + if(msg != "") + src << browse(msg, "window=Player_age_check") + else + to_chat(src, "No matches for that age range found.") + + +/client/proc/cmd_admin_world_narrate() // Allows administrators to fluff events a little easier -- TLE + set category = "Special Verbs" + set name = "Global Narrate" + set desc = "Narrate to everyone." + + if(!check_rights(R_ADMIN)) + return + + var/msg = sanitize(input("Message:", text("Enter the text you wish to appear to everyone:")) as text) + + if (!msg) + return + to_world(msg) + + log_and_message_admins(" - GlobalNarrate: [msg]") + feedback_add_details("admin_verb","GLN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +// Targetted narrate: will narrate to one specific mob +/client/proc/cmd_admin_direct_narrate(var/mob/M) + set category = "Special Verbs" + set name = "Direct Narrate" + set desc = "Narrate to a specific mob." + + if(!check_rights(R_ADMIN)) + return + + if(!M) + M = input("Direct narrate to who?", "Active Players") as null|anything in get_mob_with_client_list() + + if(!M) + return + + var/msg = sanitize(input("Message:", text("Enter the text you wish to appear to your target:")) as text) + + if( !msg ) + return + + to_chat(M, msg) + log_and_message_admins(" - DirectNarrate to ([M.name]/[M.key]): [msg]") + feedback_add_details("admin_verb","DIRN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +// Local narrate, narrates to everyone who can see where you are regardless of whether they are blind or deaf. +/client/proc/cmd_admin_local_narrate() + set category = "Special Verbs" + set name = "Local Narrate" + set desc = "Narrate to everyone who can see the turf your mob is on." + + if(!check_rights(R_ADMIN)) + return + + var/msg = sanitize(input("Message:", text("Enter the text you wish to appear to your target:")) as text) + + if( !msg ) + return + + var/list/listening_hosts = hosts_in_view_range(usr) + + for(var/listener in listening_hosts) + to_chat(listener, msg) + log_and_message_admins(" - LocalNarrate: [msg]") + +// Visible narrate, it's as if it's a visible message +/client/proc/cmd_admin_visible_narrate(var/atom/A) + set category = "Special Verbs" + set name = "Visible Narrate" + set desc = "Narrate to those who can see the given atom." + + if(!check_rights(R_ADMIN)) + return + + var/mob/M = mob + + if(!M) + to_chat(src, "You must be in control of a mob to use this.") + return + + var/msg = sanitize(input("Message:", text("Enter the text you wish to appear to your target:")) as text) + + if( !msg ) + return + + M.visible_message(msg, narrate = TRUE) + log_and_message_admins(" - VisibleNarrate on [A]: [msg]") + +// Visible narrate, it's as if it's a audible message +/client/proc/cmd_admin_audible_narrate(var/atom/A) + set category = "Special Verbs" + set name = "Audible Narrate" + set desc = "Narrate to those who can hear the given atom." + + if(!holder) + to_chat(src, "Only administrators may use this command.") + return + + var/mob/M = mob + + if(!M) + to_chat(src, "You must be in control of a mob to use this.") + return + + var/msg = sanitize(input("Message:", text("Enter the text you wish to appear to your target:")) as text) + + if( !msg ) + return + + M.audible_message(msg, narrate = TRUE) + log_and_message_admins(" - AudibleNarrate on [A]: [msg]") + +/client/proc/cmd_admin_godmode(mob/M as mob in SSmobs.mob_list) + set category = "Special Verbs" + set name = "Godmode" + if(!holder) + to_chat(src, "Only administrators may use this command.") + return + M.status_flags ^= GODMODE + to_chat(usr, "Toggled [(M.status_flags & GODMODE) ? "ON" : "OFF"]") + log_admin("[key_name(usr)] has toggled [key_name(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]") + message_admins("[key_name_admin(usr)] has toggled [key_name_admin(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]", 1) + feedback_add_details("admin_verb","GOD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +proc/cmd_admin_mute(mob/M as mob, mute_type) + if(!usr || !usr.client) + return + if(!usr.client.holder) + to_chat(usr, "Error: cmd_admin_mute: You don't have permission to do this.") + return + if(!M.client) + to_chat(usr, "Error: cmd_admin_mute: This mob doesn't have a client tied to it.") + if(M.client.holder) + to_chat(usr, "Error: cmd_admin_mute: You cannot mute an admin/mod.") + if(!M.client) return + if(M.client.holder) return + + var/muteunmute + var/mute_string + + switch(mute_type) + if(MUTE_IC) mute_string = "IC (say and emote)" + if(MUTE_OOC) mute_string = "OOC" + if(MUTE_PRAY) mute_string = "pray" + if(MUTE_ADMINHELP) mute_string = "adminhelp, admin PM and ASAY" + if(MUTE_DEADCHAT) mute_string = "deadchat and DSAY" + if(MUTE_ALL) mute_string = "everything" + else return + + + if(M.client.prefs.muted & mute_type) + muteunmute = "unmuted" + M.client.prefs.muted &= ~mute_type + else + muteunmute = "muted" + M.client.prefs.muted |= mute_type + + log_admin("[key_name(usr)] has [muteunmute] [key_name(M)] from [mute_string]") + message_staff("[key_name_admin(usr)] has [muteunmute] [key_name_admin(M)] from [mute_string].", 1) + to_chat(M, "You have been [muteunmute] from [mute_string].") + feedback_add_details("admin_verb","MUTE") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_add_random_ai_law() + set category = "Fun" + set name = "Add Random AI Law" + if(!holder) + to_chat(src, "Only administrators may use this command.") + return + var/confirm = alert(src, "You sure?", "Confirm", "Yes", "No") + if(confirm != "Yes") return + log_admin("[key_name(src)] has added a random AI law.") + message_admins("[key_name_admin(src)] has added a random AI law.", 1) + + var/show_log = alert(src, "Show ion message?", "Message", "Yes", "No") + if(show_log == "Yes") + command_announcement.Announce("Ion storm detected near the [station_name()]. Please check all AI-controlled equipment for errors.", "Anomaly Alert", new_sound = 'sound/AI/ionstorm.ogg') + + IonStorm(0) + feedback_add_details("admin_verb","ION") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/* +Allow admins to set players to be able to respawn/bypass 30 min wait, without the admin having to edit variables directly +Ccomp's first proc. +*/ + +/client/proc/get_ghosts(var/notify = 0,var/what = 2) + // what = 1, return ghosts ass list. + // what = 2, return mob list + + var/list/mobs = list() + var/list/ghosts = list() + var/list/sortmob = sortAtom(SSmobs.mob_list) // get the mob list. + var/any=0 + for(var/mob/observer/ghost/M in sortmob) + mobs.Add(M) //filter it where it's only ghosts + any = 1 //if no ghosts show up, any will just be 0 + if(!any) + if(notify) + to_chat(src, "There doesn't appear to be any ghosts for you to select.") + return + + for(var/mob/M in mobs) + var/name = M.name + ghosts[name] = M //get the name of the mob for the popup list + if(what==1) + return ghosts + else + return mobs + +/client/proc/get_ghosts_by_key() + . = list() + for(var/mob/observer/ghost/M in SSmobs.mob_list) + .[M.ckey] = M + . = sortAssoc(.) + +/client/proc/allow_character_respawn(var/selection in get_ghosts_by_key()) + set category = "Special Verbs" + set name = "Allow player to respawn" + set desc = "Allows the player bypass the wait to respawn or allow them to re-enter their corpse." + + if(!check_rights(R_ADMIN)) + return + + var/list/ghosts = get_ghosts_by_key() + var/mob/observer/ghost/G = ghosts[selection] + if(!istype(G)) + to_chat(src, "[selection] no longer has an associated ghost.") + return + + if(G.has_enabled_antagHUD == 1 && config.antag_hud_restricted) + var/response = alert(src, "[selection] has enabled antagHUD. Are you sure you wish to allow them to respawn?","Ghost has used AntagHUD","No","Yes") + if(response == "No") return + else + var/response = alert(src, "Are you sure you wish to allow [selection] to respawn?","Allow respawn","No","Yes") + if(response == "No") return + + G.timeofdeath=-19999 /* time of death is checked in /mob/verb/abandon_mob() which is the Respawn verb. + timeofdeath is used for bodies on autopsy but since we're messing with a ghost I'm pretty sure + there won't be an autopsy. + */ + G.has_enabled_antagHUD = 2 + G.can_reenter_corpse = CORPSE_CAN_REENTER_AND_RESPAWN + + G.show_message("You may now respawn. You should roleplay as if you learned nothing about the round during your time with the dead.", 1) + log_and_message_admins("has allowed [key_name(G)] to bypass the [config.respawn_delay] minute respawn limit.") + +/client/proc/toggle_antagHUD_use() + set category = "Server" + set name = "Toggle antagHUD usage" + set desc = "Toggles antagHUD usage for observers" + + if(!holder) + to_chat(src, "Only administrators may use this command.") + var/action="" + if(config.antag_hud_allowed) + for(var/mob/observer/ghost/g in get_ghosts()) + if(!g.client.holder) //Remove the verb from non-admin ghosts + g.verbs -= /mob/observer/ghost/verb/toggle_antagHUD + if(g.antagHUD) + g.antagHUD = 0 // Disable it on those that have it enabled + g.has_enabled_antagHUD = 2 // We'll allow them to respawn + to_chat(g, "The Administrator has disabled AntagHUD") + config.antag_hud_allowed = 0 + to_chat(src, "AntagHUD usage has been disabled") + action = "disabled" + else + for(var/mob/observer/ghost/g in get_ghosts()) + if(!g.client.holder) // Add the verb back for all non-admin ghosts + g.verbs += /mob/observer/ghost/verb/toggle_antagHUD + to_chat(g, "The Administrator has enabled AntagHUD ")// Notify all observers they can now use AntagHUD + + config.antag_hud_allowed = 1 + action = "enabled" + to_chat(src, "AntagHUD usage has been enabled") + + + log_admin("[key_name(usr)] has [action] antagHUD usage for observers") + message_admins("Admin [key_name_admin(usr)] has [action] antagHUD usage for observers", 1) + + + +/client/proc/toggle_antagHUD_restrictions() + set category = "Server" + set name = "Toggle antagHUD Restrictions" + set desc = "Restricts players that have used antagHUD from being able to join this round." + if(!holder) + to_chat(src, "Only administrators may use this command.") + var/action="" + if(config.antag_hud_restricted) + for(var/mob/observer/ghost/g in get_ghosts()) + to_chat(g, "The administrator has lifted restrictions on joining the round if you use AntagHUD") + action = "lifted restrictions" + config.antag_hud_restricted = 0 + to_chat(src, "AntagHUD restrictions have been lifted") + else + for(var/mob/observer/ghost/g in get_ghosts()) + to_chat(g, "The administrator has placed restrictions on joining the round if you use AntagHUD") + to_chat(g, "Your AntagHUD has been disabled, you may choose to re-enabled it but will be under restrictions") + g.antagHUD = 0 + g.has_enabled_antagHUD = 0 + action = "placed restrictions" + config.antag_hud_restricted = 1 + to_chat(src, "AntagHUD restrictions have been enabled") + + log_admin("[key_name(usr)] has [action] on joining the round if they use AntagHUD") + message_admins("Admin [key_name_admin(usr)] has [action] on joining the round if they use AntagHUD", 1) + +/* +If a guy was gibbed and you want to revive him, this is a good way to do so. +Works kind of like entering the game with a new character. Character receives a new mind if they didn't have one. +Traitors and the like can also be revived with the previous role mostly intact. +/N */ +/client/proc/respawn_character() + set category = "Special Verbs" + set name = "Respawn Character" + set desc = "Respawn a person that has been gibbed/dusted/killed. They must be a ghost for this to work and preferably should not have a body to go back into." + if(!holder) + to_chat(src, "Only administrators may use this command.") + return + var/input = ckey(input(src, "Please specify which key will be respawned.", "Key", "")) + if(!input) + return + + var/mob/observer/ghost/G_found + for(var/mob/observer/ghost/G in GLOB.player_list) + if(G.ckey == input) + G_found = G + break + + if(!G_found)//If a ghost was not found. + to_chat(usr, "There is no active key like that in the game or the person is not currently a ghost.") + return + + var/mob/living/carbon/human/new_character = new(pick(GLOB.latejoin))//The mob being spawned. + + var/datum/computer_file/crew_record/record_found //Referenced to later to either randomize or not randomize the character. + if(G_found.mind && !G_found.mind.active) + record_found = get_crewmember_record(G_found.real_name) + + if(record_found)//If they have a record we can determine a few things. + new_character.real_name = record_found.get_name() + new_character.gender = record_found.get_sex() + new_character.age = record_found.get_age() + new_character.b_type = record_found.get_bloodtype() + else + new_character.gender = pick(MALE,FEMALE) + var/datum/preferences/A = new() + A.sanitize_preferences() + A.randomize_appearance_and_body_for(new_character) + new_character.real_name = G_found.real_name + + if(!new_character.real_name) + if(new_character.gender == MALE) + new_character.real_name = capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) + else + new_character.real_name = capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) + new_character.SetName(new_character.real_name) + + if(G_found.mind && !G_found.mind.active) + G_found.mind.transfer_to(new_character) //be careful when doing stuff like this! I've already checked the mind isn't in use + new_character.mind.special_verbs = list() + else + new_character.mind_initialize() + if(!new_character.mind.assigned_role) new_character.mind.assigned_role = "Assistant"//If they somehow got a null assigned role. + + //DNA + new_character.dna.ready_dna(new_character) + if(record_found)//Pull up their name from database records if they did have a mind. + new_character.dna.unique_enzymes = record_found.get_dna()//Enzymes are based on real name but we'll use the record for conformity. + new_character.key = G_found.key + + /* + The code below functions with the assumption that the mob is already a traitor if they have a special role. + So all it does is re-equip the mob with powers and/or items. Or not, if they have no special role. + If they don't have a mind, they obviously don't have a special role. + */ + + var/player_key = G_found.key + + //Now for special roles and equipment. + var/datum/antagonist/antag_data = get_antag_data(new_character.mind.special_role) + if(antag_data) + antag_data.add_antagonist(new_character.mind) + antag_data.place_mob(new_character) + else + job_master.EquipRank(new_character, new_character.mind.assigned_role, 1) + + //Announces the character on all the systems, based on the record. + if(!issilicon(new_character))//If they are not a cyborg/AI. + if(!record_found && !player_is_antag(new_character.mind, only_offstation_roles = 1)) //If there are no records for them. If they have a record, this info is already in there. MODE people are not announced anyway. + if(alert(new_character,"Would you like an active AI to announce this character?",,"No","Yes")=="Yes") + call(/proc/AnnounceArrival)(new_character, new_character.mind.assigned_role) + + log_and_message_admins("has respawned [player_key] as [new_character.real_name].") + + to_chat(new_character, "You have been fully respawned. Enjoy the game.") + feedback_add_details("admin_verb","RSPCH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return new_character + +/client/proc/cmd_admin_add_freeform_ai_law() + set category = "Fun" + set name = "Add Custom AI law" + if(!holder) + to_chat(src, "Only administrators may use this command.") + return + var/input = sanitize(input(usr, "Please enter anything you want the AI to do. Anything. Serious.", "What?", "") as text|null) + if(!input) + return + for(var/mob/living/silicon/ai/M in SSmobs.mob_list) + if (M.stat == 2) + to_chat(usr, "Upload failed. No signal is being detected from the AI.") + else if (M.see_in_dark == 0) + to_chat(usr, "Upload failed. Only a faint signal is being detected from the AI, and it is not responding to our requests. It may be low on power.") + else + M.add_ion_law(input) + for(var/mob/living/silicon/ai/O in SSmobs.mob_list) + to_chat(O, "" + input + "...LAWS UPDATED") + O.show_laws() + + log_admin("Admin [key_name(usr)] has added a new AI law - [input]") + message_admins("Admin [key_name_admin(usr)] has added a new AI law - [input]", 1) + + var/show_log = alert(src, "Show ion message?", "Message", "Yes", "No") + if(show_log == "Yes") + command_announcement.Announce("Ion storm detected near the [station_name()]. Please check all AI-controlled equipment for errors.", "Anomaly Alert", new_sound = 'sound/AI/ionstorm.ogg') + feedback_add_details("admin_verb","IONC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_rejuvenate(mob/living/M as mob in SSmobs.mob_list) + set category = "Special Verbs" + set name = "Rejuvenate" + if(!holder) + to_chat(src, "Only administrators may use this command.") + return + if(!mob) + return + if(!istype(M)) + alert("Cannot revive a ghost") + return + if(config.allow_admin_rev) + M.revive() + + log_and_message_admins("healed / revived [key_name_admin(M)]!") + else + alert("Admin revive disabled") + feedback_add_details("admin_verb","REJU") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_create_centcom_report() + set category = "Special Verbs" + set name = "Create Command Report" + if(!holder) + to_chat(src, "Only administrators may use this command.") + return + var/input = sanitize(input(usr, "Please enter anything you want. Anything. Serious.", "What?", "") as message|null, extra = 0) + var/customname = sanitizeSafe(input(usr, "Pick a title for the report.", "Title") as text|null) + if(!input) + return + if(!customname) + customname = "[command_name()] Update" + + //New message handling + post_comm_message(customname, replacetext(input, "\n", "
            ")) + + switch(alert("Should this be announced to the general population?",,"Yes","No")) + if("Yes") + command_announcement.Announce(input, customname, new_sound = GLOB.using_map.command_report_sound, msg_sanitized = 1); + if("No") + minor_announcement.Announce(message = "New [GLOB.using_map.company_name] Update available at all communication consoles.") + + log_admin("[key_name(src)] has created a command report: [input]") + message_admins("[key_name_admin(src)] has created a command report", 1) + feedback_add_details("admin_verb","CCR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_delete(atom/O as obj|mob|turf in range(world.view)) + set category = "Admin" + set name = "Delete" + + if (!holder) + to_chat(src, "Only administrators may use this command.") + return + + if (alert(src, "Are you sure you want to delete:\n[O]\nat ([O.x], [O.y], [O.z])?", "Confirmation", "Yes", "No") == "Yes") + log_admin("[key_name(usr)] deleted [O] at ([O.x],[O.y],[O.z])") + message_admins("[key_name_admin(usr)] deleted [O] at ([O.x],[O.y],[O.z])", 1) + feedback_add_details("admin_verb","DEL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + qdel(O) + +/client/proc/cmd_admin_list_open_jobs() + set category = "Admin" + set name = "List free slots" + + if (!holder) + to_chat(src, "Only administrators may use this command.") + return + if(job_master) + for(var/datum/job/job in job_master.occupations) + to_chat(src, "[job.title]: [job.total_positions]") + feedback_add_details("admin_verb","LFS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_explosion(atom/O as obj|mob|turf in range(world.view)) + set category = "Special Verbs" + set name = "Explosion" + + if(!check_rights(R_DEBUG|R_FUN)) return + + var/devastation = input("Range of total devastation. -1 to none", text("Input")) as num|null + if(devastation == null) return + var/heavy = input("Range of heavy impact. -1 to none", text("Input")) as num|null + if(heavy == null) return + var/light = input("Range of light impact. -1 to none", text("Input")) as num|null + if(light == null) return + var/flash = input("Range of flash. -1 to none", text("Input")) as num|null + if(flash == null) return + var/shaped = 0 + if(config.use_recursive_explosions) + if(alert(src, "Shaped explosion?", "Shape", "Yes", "No") == "Yes") + shaped = input("Shaped where to?", "Input") as anything in list("NORTH","SOUTH","EAST","WEST") + shaped = text2dir(shaped) + if ((devastation != -1) || (heavy != -1) || (light != -1) || (flash != -1)) + if ((devastation > 20) || (heavy > 20) || (light > 20)) + if (alert(src, "Are you sure you want to do this? It will laaag.", "Confirmation", "Yes", "No") == "No") + return + + explosion(O, devastation, heavy, light, flash, shaped=shaped) + log_admin("[key_name(usr)] created an explosion ([devastation],[heavy],[light],[flash]) at ([O.x],[O.y],[O.z])") + message_admins("[key_name_admin(usr)] created an explosion ([devastation],[heavy],[light],[flash]) at ([O.x],[O.y],[O.z])", 1) + feedback_add_details("admin_verb","EXPL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + else + return + +/client/proc/cmd_admin_emp(atom/O as obj|mob|turf in range(world.view)) + set category = "Special Verbs" + set name = "EM Pulse" + + if(!check_rights(R_DEBUG|R_FUN)) return + + var/heavy = input("Range of heavy pulse.", text("Input")) as num|null + if(heavy == null) return + var/light = input("Range of light pulse.", text("Input")) as num|null + if(light == null) return + + if (heavy || light) + + empulse(O, heavy, light) + log_admin("[key_name(usr)] created an EM Pulse ([heavy],[light]) at ([O.x],[O.y],[O.z])") + message_admins("[key_name_admin(usr)] created an EM PUlse ([heavy],[light]) at ([O.x],[O.y],[O.z])", 1) + feedback_add_details("admin_verb","EMP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + return + else + return + +/client/proc/cmd_admin_gib(mob/M as mob in SSmobs.mob_list) + set category = "Special Verbs" + set name = "Gib" + + if(!check_rights(R_ADMIN|R_FUN)) return + + var/confirm = alert(src, "You sure?", "Confirm", "Yes", "No") + if(confirm != "Yes") return + //Due to the delay here its easy for something to have happened to the mob + if(!M) return + + log_admin("[key_name(usr)] has gibbed [key_name(M)]") + message_admins("[key_name_admin(usr)] has gibbed [key_name_admin(M)]", 1) + + if(isobserver(M)) + gibs(M.loc) + return + + M.gib() + feedback_add_details("admin_verb","GIB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_gib_self() + set name = "Gibself" + set category = "Fun" + + var/confirm = alert(src, "You sure?", "Confirm", "Yes", "No") + if(confirm == "Yes") + if (isobserver(mob)) // so they don't spam gibs everywhere + return + else + mob.gib() + + log_and_message_admins("used gibself.") + feedback_add_details("admin_verb","GIBS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/update_world() + // If I see anyone granting powers to specific keys like the code that was here, + // I will both remove their SVN access and permanently ban them from my servers. + return + +/client/proc/cmd_admin_check_contents(mob/living/M as mob in SSmobs.mob_list) + set category = "Special Verbs" + set name = "Check Contents" + + var/list/L = M.get_contents() + for(var/t in L) + to_chat(usr, "[t]") + feedback_add_details("admin_verb","CC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/* This proc is DEFERRED. Does not do anything. +/client/proc/cmd_admin_remove_phoron() + set category = "Debug" + set name = "Stabilize Atmos." + if(!holder) + to_chat(src, "Only administrators may use this command.") + return + feedback_add_details("admin_verb","STATM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +// DEFERRED + spawn(0) + for(var/turf/T in view()) + T.poison = 0 + T.oldpoison = 0 + T.tmppoison = 0 + T.oxygen = 755985 + T.oldoxy = 755985 + T.tmpoxy = 755985 + T.co2 = 14.8176 + T.oldco2 = 14.8176 + T.tmpco2 = 14.8176 + T.n2 = 2.844e+006 + T.on2 = 2.844e+006 + T.tn2 = 2.844e+006 + T.tsl_gas = 0 + T.osl_gas = 0 + T.sl_gas = 0 + T.temp = 293.15 + T.otemp = 293.15 + T.ttemp = 293.15 +*/ + +/client/proc/toggle_view_range() + set category = "Special Verbs" + set name = "Change View Range" + set desc = "switches between 1x and custom views" + + if(view == world.view) + view = input("Select view range:", "FUCK YE", 7) in list(1,2,3,4,5,6,7,8,9,10,11,12,13,14,128) + else + view = world.view + + log_and_message_admins("changed their view range to [view].") + feedback_add_details("admin_verb","CVRA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/admin_call_shuttle() + + set category = "Admin" + set name = "Call Evacuation" + + if(!ticker || !evacuation_controller) + return + + if(!check_rights(R_ADMIN)) return + + if(alert(src, "Are you sure?", "Confirm", "Yes", "No") != "Yes") return + + if(ticker.mode.auto_recall_shuttle) + if(input("The evacuation will just be cancelled if you call it. Call anyway?") in list("Confirm", "Cancel") != "Confirm") + return + + var/choice = input("Is this an emergency evacuation or a crew transfer?") in list("Emergency", "Crew Transfer") + evacuation_controller.call_evacuation(usr, (choice == "Emergency")) + + feedback_add_details("admin_verb","CSHUT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + log_and_message_admins("admin-called an evacuation.") + return + +/client/proc/admin_cancel_shuttle() + set category = "Admin" + set name = "Cancel Evacuation" + + if(!check_rights(R_ADMIN)) return + + if(alert(src, "You sure?", "Confirm", "Yes", "No") != "Yes") return + + if(!ticker || !evacuation_controller) + return + + evacuation_controller.cancel_evacuation() + + feedback_add_details("admin_verb","CCSHUT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + log_and_message_admins("admin-cancelled the evacuation.") + + return + +/client/proc/admin_deny_shuttle() + set category = "Admin" + set name = "Toggle Deny Evac" + + if (!ticker || !evacuation_controller) + return + + if(!check_rights(R_ADMIN)) return + + evacuation_controller.deny = !evacuation_controller.deny + + log_admin("[key_name(src)] has [evacuation_controller.deny ? "denied" : "allowed"] evacuation to be called.") + message_admins("[key_name_admin(usr)] has [evacuation_controller.deny ? "denied" : "allowed"] evacuation to be called.") + +/client/proc/cmd_admin_attack_log(mob/M as mob in SSmobs.mob_list) + set category = "Special Verbs" + set name = "Attack Log" + + to_chat(usr, text("Attack Log for []", mob)) + for(var/t in M.attack_logs_) + to_chat(usr, t) + feedback_add_details("admin_verb","ATTL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/client/proc/everyone_random() + set category = "Fun" + set name = "Make Everyone Random" + set desc = "Make everyone have a random appearance. You can only use this before rounds!" + + if(!check_rights(R_FUN)) return + + if (ticker && ticker.mode) + to_chat(usr, "Nope you can't do this, the game's already started. This only works before rounds!") + return + + if(ticker.random_players) + ticker.random_players = 0 + message_admins("Admin [key_name_admin(usr)] has disabled \"Everyone is Special\" mode.", 1) + to_chat(usr, "Disabled.") + return + + + var/notifyplayers = alert(src, "Do you want to notify the players?", "Options", "Yes", "No", "Cancel") + if(notifyplayers == "Cancel") + return + + log_admin("Admin [key_name(src)] has forced the players to have random appearances.") + message_admins("Admin [key_name_admin(usr)] has forced the players to have random appearances.", 1) + + if(notifyplayers == "Yes") + to_world("Admin [usr.key] has forced the players to have completely random identities!") + + to_chat(usr, "Remember: you can always disable the randomness by using the verb again, assuming the round hasn't started yet.") + ticker.random_players = 1 + feedback_add_details("admin_verb","MER") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/client/proc/toggle_random_events() + set category = "Server" + set name = "Toggle random events on/off" + + set desc = "Toggles random events such as meteors, black holes, blob (but not space dust) on/off" + if(!check_rights(R_SERVER)) return + + if(!config.allow_random_events) + config.allow_random_events = 1 + to_chat(usr, "Random events enabled") + message_admins("Admin [key_name_admin(usr)] has enabled random events.", 1) + else + config.allow_random_events = 0 + to_chat(usr, "Random events disabled") + message_admins("Admin [key_name_admin(usr)] has disabled random events.", 1) + feedback_add_details("admin_verb","TRE") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/striketeam.dm b/code/modules/admin/verbs/striketeam.dm new file mode 100644 index 00000000..adfc04db --- /dev/null +++ b/code/modules/admin/verbs/striketeam.dm @@ -0,0 +1,55 @@ +//STRIKE TEAMS +var/const/commandos_possible = 6 //if more Commandos are needed in the future + +/client/proc/strike_team() + set category = "Fun" + set name = "Spawn Strike Team" + set desc = "Spawns a strike team if you want to run an admin event." + + if(!src.holder) + to_chat(src, "Only administrators may use this command.") + return + + if(!ticker) + to_chat(usr, "The game hasn't started yet!") + return + + if(world.time < 6000) + to_chat(usr, "There are [(6000-world.time)/10] seconds remaining before it may be called.") + return + + var/datum/antagonist/deathsquad/team + + var/choice = input(usr, "Select type of strike team:") as null|anything in list("Heavy Asset Protection", "Mercenaries") + if(!choice) + return + + switch(choice) + if("Heavy Asset Protection") + team = deathsquad + if("Mercenaries") + team = commandos + else + return + + if(team.deployed) + to_chat(usr, "Someone is already sending a team.") + return + + if(alert("Do you want to send in a strike team? Once enabled, this is irreversible.",,"Yes","No")!="Yes") + return + + alert("This 'mode' will go on until everyone is dead or the installation is destroyed. You may also admin-call the evac shuttle when appropriate. Spawned commandos have internals cameras which are viewable through a monitor inside the Spec. Ops. Office. Assigning the team's detailed task is recommended from there. While you will be able to manually pick the candidates from active ghosts, their assignment in the squad will be random.") + + choice = null + while(!choice) + choice = sanitize(input(src, "Please specify which mission the strike team shall undertake.", "Specify Mission", "")) + if(!choice) + if(alert("Error, no mission set. Do you want to exit the setup process?",,"Yes","No")=="Yes") + return + + if(team.deployed) + to_chat(usr, "Looks like someone beat you to it.") + return + + team.attempt_random_spawn() diff --git a/code/modules/admin/verbs/ticklag.dm b/code/modules/admin/verbs/ticklag.dm new file mode 100644 index 00000000..09499521 --- /dev/null +++ b/code/modules/admin/verbs/ticklag.dm @@ -0,0 +1,19 @@ +//Merged Doohl's and the existing ticklag as they both had good elements about them ~Carn + +/client/proc/ticklag() + set category = "Debug" + set name = "Set Ticklag" + set desc = "Sets a new tick lag. Recommend you don't mess with this too much! Stable, time-tested ticklag value is 0.9" + + if(!check_rights(R_DEBUG)) return + + var/newtick = input("Sets a new tick lag. Please don't mess with this too much! The stable, time-tested ticklag value is 0.9","Lag of Tick", world.tick_lag) as num|null + //I've used ticks of 2 before to help with serious singulo lags + if(newtick && newtick <= 2 && newtick > 0) + log_admin("[key_name(src)] has modified world.tick_lag to [newtick]", 0) + message_admins("[key_name(src)] has modified world.tick_lag to [newtick]", 0) + world.tick_lag = newtick + feedback_add_details("admin_verb","TICKLAG") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + else + to_chat(src, "Error: ticklag(): Invalid world.ticklag value. No changes made.") + diff --git a/code/modules/admin/verbs/trading_verbs.dm b/code/modules/admin/verbs/trading_verbs.dm new file mode 100644 index 00000000..f702c19f --- /dev/null +++ b/code/modules/admin/verbs/trading_verbs.dm @@ -0,0 +1,31 @@ +/client/proc/list_traders() + set category = "Debug" + set name = "List Traders" + set desc = "Lists all the current traders" + + for(var/a in GLOB.traders) + var/datum/trader/T = a + to_chat(src, "[T.name] \ref[T]") + +/client/proc/add_trader() + set category = "Debug" + set name = "Add Trader" + set desc = "Adds a trader to the list." + + var/list/possible = subtypesof(/datum/trader) - /datum/trader/ship - /datum/trader/ship/unique + var/type = input(src,"Choose a type to add.") as null|anything in possible + if(!type) + return + + GLOB.traders += new type + +/client/proc/remove_trader() + set category = "Debug" + set name = "Remove Trader" + set desc = "Removes a trader from the trader list." + + var/choice = input(src, "Choose something to remove.") as null|anything in GLOB.traders + if(!choice) + return + + GLOB.traders -= choice diff --git a/code/modules/admin/verbs/tripAI.dm b/code/modules/admin/verbs/tripAI.dm new file mode 100644 index 00000000..c49ee6f0 --- /dev/null +++ b/code/modules/admin/verbs/tripAI.dm @@ -0,0 +1,22 @@ +/client/proc/triple_ai() + set category = "Fun" + set name = "Create AI Triumvirate" + + if(ticker.current_state > GAME_STATE_PREGAME) + to_chat(usr, "This option is currently only usable during pregame. This may change at a later date.") + return + + if(job_master && ticker) + var/datum/job/job = job_master.GetJob("AI") + if(!job) + to_chat(usr, "Unable to locate the AI job") + return + if(ticker.triai) + ticker.triai = 0 + to_chat(usr, "Only one AI will be spawned at round start.") + message_admins("[key_name_admin(usr)] has toggled off triple AIs at round start.", 1) + else + ticker.triai = 1 + to_chat(usr, "There will be an AI Triumvirate at round start.") + message_admins("[key_name_admin(usr)] has toggled on triple AIs at round start.", 1) + return diff --git a/code/modules/admin/view_variables/helpers.dm b/code/modules/admin/view_variables/helpers.dm new file mode 100644 index 00000000..90549409 --- /dev/null +++ b/code/modules/admin/view_variables/helpers.dm @@ -0,0 +1,202 @@ + +// Keep these two together, they *must* be defined on both +// If /client ever becomes /datum/client or similar, they can be merged +/datum/proc/get_view_variables_header() + return "[src]" + +/atom/get_view_variables_header() + return {" + [src] +
            + << + [dir2text(dir)] + >> + + "} + +/mob/living/get_view_variables_header() + return {" + [src] +
            << [dir2text(dir)] >> +
            [ckey ? ckey : "No ckey"] / [real_name ? real_name : "No real name"] +
            + BRUTE:[getBruteLoss()] + FIRE:[getFireLoss()] + TOXIN:[getToxLoss()] + OXY:[getOxyLoss()] + CLONE:[getCloneLoss()] + BRAIN:[getBrainLoss()] +
            + "} + +// Same for these as for get_view_variables_header() above +/datum/proc/get_view_variables_options() + return "" + +/mob/get_view_variables_options() + return ..() + {" + + + + + + + + + + + + + + + + + + + + + + + + + + + + "} + +/mob/living/get_view_variables_options() + return ..() + {" + + + "} + +/mob/living/carbon/human/get_view_variables_options() + return ..() + {" + + + + + + + + "} + +/obj/get_view_variables_options() + return ..() + {" + + + + + "} + +/turf/get_view_variables_options() + return ..() + {" + + + "} + +/datum/proc/get_variables() + . = vars - VV_hidden() + if(!usr || !check_rights(R_ADMIN|R_DEBUG, FALSE)) + . -= VV_secluded() + +/datum/proc/get_variable_value(varname) + return vars[varname] + +/datum/proc/set_variable_value(varname, value) + vars[varname] = value + +/datum/proc/get_initial_variable_value(varname) + return initial(vars[varname]) + +/datum/proc/make_view_variables_variable_entry(varname, value) + return {" + (E) + (C) + (M) + "} + +// No mass editing of clients +/client/make_view_variables_variable_entry(varname, value) + return {" + (E) + (C) + "} + +// These methods are all procs and don't use stored lists to avoid VV exploits + +// The following vars cannot be viewed by anyone +/datum/proc/VV_hidden() + return list() + +// The following vars can only be viewed by R_ADMIN|R_DEBUG +/datum/proc/VV_secluded() + return list() + +/datum/configuration/VV_secluded() + return vars + +// The following vars cannot be edited by anyone +/datum/proc/VV_static() + return list("parent_type") + +/atom/VV_static() + return ..() + list("bound_x", "bound_y", "bound_height", "bound_width", "bounds", "step_x", "step_y", "step_size") + +/client/VV_static() + return ..() + list("holder", "prefs") + +/datum/admins/VV_static() + return vars + +// The following vars require R_DEBUG to edit +/datum/proc/VV_locked() + return list("vars", "virus", "viruses", "cuffed") + +/client/VV_locked() + return list("vars", "mob") + +/mob/VV_locked() + return ..() + list("client") + +// The following vars require R_FUN|R_DEBUG to edit +/datum/proc/VV_icon_edit_lock() + return list() + +/atom/VV_icon_edit_lock() + return ..() + list("icon", "icon_state", "overlays", "underlays") + +// The following vars require R_SPAWN|R_DEBUG to edit +/datum/proc/VV_ckey_edit() + return list() + +/mob/VV_ckey_edit() + return list("key", "ckey") + +/client/VV_ckey_edit() + return list("key", "ckey") + +/datum/proc/may_edit_var(var/user, var/var_to_edit) + if(!user) + return FALSE + if(!(var_to_edit in vars)) + to_chat(user, "\The [src] does not have a var '[var_to_edit]'") + return FALSE + if(var_to_edit in VV_static()) + return FALSE + if((var_to_edit in VV_secluded()) && !check_rights(R_ADMIN|R_DEBUG, FALSE, C = user)) + return FALSE + if((var_to_edit in VV_locked()) && !check_rights(R_DEBUG, C = user)) + return FALSE + if((var_to_edit in VV_ckey_edit()) && !check_rights(R_SPAWN|R_DEBUG, C = user)) + return FALSE + if((var_to_edit in VV_icon_edit_lock()) && !check_rights(R_FUN|R_DEBUG, C = user)) + return FALSE + return TRUE + +/proc/forbidden_varedit_object_types() + return list( + /datum/admins, //Admins editing their own admin-power object? Yup, sounds like a good idea., + /obj/machinery/blackbox_recorder, //Prevents people messing with feedback gathering, + /datum/feedback_variable //Prevents people messing with feedback gathering + ) diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm new file mode 100644 index 00000000..cb9eb752 --- /dev/null +++ b/code/modules/admin/view_variables/topic.dm @@ -0,0 +1,554 @@ + +/client/proc/view_var_Topic(href, href_list, hsrc) + //This should all be moved over to datum/admins/Topic() or something ~Carn + if( (usr.client != src) || !src.holder ) + return + if(href_list["Vars"]) + debug_variables(locate(href_list["Vars"])) + + //~CARN: for renaming mobs (updates their name, real_name, mind.name, their ID/PDA and datacore records). + else if(href_list["rename"]) + if(!check_rights(R_VAREDIT)) return + + var/mob/M = locate(href_list["rename"]) + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + var/new_name = sanitize(input(usr,"What would you like to name this mob?","Input a name",M.real_name) as text|null, MAX_NAME_LEN) + if(!new_name || !M) return + + message_admins("Admin [key_name_admin(usr)] renamed [key_name_admin(M)] to [new_name].") + M.fully_replace_character_name(new_name) + href_list["datumrefresh"] = href_list["rename"] + + else if(href_list["dressup"]) + if(!check_rights(R_VAREDIT)) return + + var/mob/living/carbon/human/H = locate(href_list["dressup"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return + var/decl/hierarchy/outfit/outfit = input("Select outfit.", "Select equipment.") as null|anything in outfits() + if(!outfit) + return + + dressup_human(H, outfit, TRUE) + + else if(href_list["varnameedit"] && href_list["datumedit"]) + if(!check_rights(R_VAREDIT)) return + + var/D = locate(href_list["datumedit"]) + if(!istype(D,/datum) && !istype(D,/client)) + to_chat(usr, "This can only be used on instances of types /client or /datum") + return + + modify_variables(D, href_list["varnameedit"], 1) + + else if(href_list["varnamechange"] && href_list["datumchange"]) + if(!check_rights(R_VAREDIT)) return + + var/D = locate(href_list["datumchange"]) + if(!istype(D,/datum) && !istype(D,/client)) + to_chat(usr, "This can only be used on instances of types /client or /datum") + return + + modify_variables(D, href_list["varnamechange"], 0) + + else if(href_list["varnamemass"] && href_list["datummass"]) + if(!check_rights(R_VAREDIT)) return + + var/atom/A = locate(href_list["datummass"]) + if(!istype(A)) + to_chat(usr, "This can only be used on instances of type /atom") + return + + cmd_mass_modify_object_variables(A, href_list["varnamemass"]) + + else if(href_list["mob_player_panel"]) + if(!check_rights(0)) return + + var/mob/M = locate(href_list["mob_player_panel"]) + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.holder.show_player_panel(M) + href_list["datumrefresh"] = href_list["mob_player_panel"] + + else if(href_list["give_spell"]) + if(!check_rights(R_ADMIN|R_FUN)) return + + var/mob/M = locate(href_list["give_spell"]) + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.give_spell(M) + href_list["datumrefresh"] = href_list["give_spell"] + + else if(href_list["give_disease2"]) + if(!check_rights(R_ADMIN|R_FUN)) return + + var/mob/M = locate(href_list["give_disease2"]) + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.give_disease2(M) + href_list["datumrefresh"] = href_list["give_spell"] + + else if(href_list["godmode"]) + if(!check_rights(R_REJUVINATE)) return + + var/mob/M = locate(href_list["godmode"]) + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.cmd_admin_godmode(M) + href_list["datumrefresh"] = href_list["godmode"] + + else if(href_list["gib"]) + if(!check_rights(0)) return + + var/mob/M = locate(href_list["gib"]) + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.cmd_admin_gib(M) + + else if(href_list["drop_everything"]) + if(!check_rights(R_DEBUG|R_ADMIN)) return + + var/mob/M = locate(href_list["drop_everything"]) + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + if(usr.client) + usr.client.cmd_admin_drop_everything(M) + + else if(href_list["direct_control"]) + if(!check_rights(0)) return + + var/mob/M = locate(href_list["direct_control"]) + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + if(usr.client) + usr.client.cmd_assume_direct_control(M) + + else if(href_list["make_skeleton"]) + if(!check_rights(R_FUN)) return + + var/mob/living/carbon/human/H = locate(href_list["make_skeleton"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return + + H.ChangeToSkeleton() + href_list["datumrefresh"] = href_list["make_skeleton"] + + else if(href_list["delthis"]) + if(!check_rights(R_DEBUG|R_SERVER)) return + + var/obj/O = locate(href_list["delthis"]) + if(!isobj(O)) + to_chat(usr, "This can only be used on instances of type /obj") + return + cmd_admin_delete(O) + + else if(href_list["delall"]) + if(!check_rights(R_DEBUG|R_SERVER)) return + + var/obj/O = locate(href_list["delall"]) + if(!isobj(O)) + to_chat(usr, "This can only be used on instances of type /obj") + return + + var/action_type = alert("Strict type ([O.type]) or type and all subtypes?",,"Strict type","Type and subtypes","Cancel") + if(action_type == "Cancel" || !action_type) + return + + if(alert("Are you really sure you want to delete all objects of type [O.type]?",,"Yes","No") != "Yes") + return + + if(alert("Second confirmation required. Delete?",,"Yes","No") != "Yes") + return + + var/O_type = O.type + switch(action_type) + if("Strict type") + var/i = 0 + for(var/obj/Obj in world) + if(Obj.type == O_type) + i++ + qdel(Obj) + if(!i) + to_chat(usr, "No objects of this type exist") + return + log_admin("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted)") + message_admins("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted)") + if("Type and subtypes") + var/i = 0 + for(var/obj/Obj in world) + if(istype(Obj,O_type)) + i++ + qdel(Obj) + if(!i) + to_chat(usr, "No objects of this type exist") + return + log_admin("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted)") + message_admins("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted)") + + else if(href_list["explode"]) + if(!check_rights(R_DEBUG|R_FUN)) return + + var/atom/A = locate(href_list["explode"]) + if(!isobj(A) && !ismob(A) && !isturf(A)) + to_chat(usr, "This can only be done to instances of type /obj, /mob and /turf") + return + + src.cmd_admin_explosion(A) + href_list["datumrefresh"] = href_list["explode"] + + else if(href_list["emp"]) + if(!check_rights(R_DEBUG|R_FUN)) return + + var/atom/A = locate(href_list["emp"]) + if(!isobj(A) && !ismob(A) && !isturf(A)) + to_chat(usr, "This can only be done to instances of type /obj, /mob and /turf") + return + + src.cmd_admin_emp(A) + href_list["datumrefresh"] = href_list["emp"] + + else if(href_list["mark_object"]) + if(!check_rights(0)) return + + var/datum/D = locate(href_list["mark_object"]) + if(!istype(D)) + to_chat(usr, "This can only be done to instances of type /datum") + return + + src.holder.marked_datum_weak = weakref(D) + href_list["datumrefresh"] = href_list["mark_object"] + + else if(href_list["rotatedatum"]) + if(!check_rights(0)) return + + var/atom/A = locate(href_list["rotatedatum"]) + if(!istype(A)) + to_chat(usr, "This can only be done to instances of type /atom") + return + + switch(href_list["rotatedir"]) + if("right") A.set_dir(turn(A.dir, -45)) + if("left") A.set_dir(turn(A.dir, 45)) + href_list["datumrefresh"] = href_list["rotatedatum"] + + else if(href_list["makemonkey"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["makemonkey"]) + if(!istype(H)) + to_chat(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) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("monkeyone"=href_list["makemonkey"])) + + else if(href_list["makerobot"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["makerobot"]) + if(!istype(H)) + to_chat(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) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("makerobot"=href_list["makerobot"])) + + else if(href_list["makeslime"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["makeslime"]) + if(!istype(H)) + to_chat(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) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("makeslime"=href_list["makeslime"])) + + else if(href_list["makeai"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["makeai"]) + if(!istype(H)) + to_chat(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) + to_chat(usr, "Mob doesn't exist anymore") + return + holder.Topic(href, list("makeai"=href_list["makeai"])) + + else if(href_list["setspecies"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["setspecies"]) + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + return + + var/new_species = input("Please choose a new species.","Species",null) as null|anything in all_species + + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + + if(H.set_species(new_species)) + to_chat(usr, "Set species of [H] to [H.species].") + else + to_chat(usr, "Failed! Something went wrong.") + + else if(href_list["addlanguage"]) + if(!check_rights(R_SPAWN)) return + + var/mob/H = locate(href_list["addlanguage"]) + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob") + return + + var/new_language = input("Please choose a language to add.","Language",null) as null|anything in all_languages + + if(!new_language) + return + + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + + if(H.add_language(new_language)) + to_chat(usr, "Added [new_language] to [H].") + else + to_chat(usr, "Mob already knows that language.") + + else if(href_list["remlanguage"]) + if(!check_rights(R_SPAWN)) return + + var/mob/H = locate(href_list["remlanguage"]) + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob") + return + + if(!H.languages.len) + to_chat(usr, "This mob knows no languages.") + return + + var/datum/language/rem_language = input("Please choose a language to remove.","Language",null) as null|anything in H.languages + + if(!rem_language) + return + + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + + if(H.remove_language(rem_language.name)) + to_chat(usr, "Removed [rem_language] from [H].") + else + to_chat(usr, "Mob doesn't know that language.") + + else if(href_list["addverb"]) + if(!check_rights(R_DEBUG)) return + + var/mob/living/H = locate(href_list["addverb"]) + + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob/living") + return + var/list/possibleverbs = list() + possibleverbs += "Cancel" // One for the top... + possibleverbs += typesof(/mob/proc,/mob/verb,/mob/living/proc,/mob/living/verb) + switch(H.type) + if(/mob/living/carbon/human) + possibleverbs += typesof(/mob/living/carbon/proc,/mob/living/carbon/verb,/mob/living/carbon/human/verb,/mob/living/carbon/human/proc) + if(/mob/living/silicon/robot) + possibleverbs += typesof(/mob/living/silicon/proc,/mob/living/silicon/robot/proc,/mob/living/silicon/robot/verb) + if(/mob/living/silicon/ai) + possibleverbs += typesof(/mob/living/silicon/proc,/mob/living/silicon/ai/proc,/mob/living/silicon/ai/verb) + possibleverbs -= H.verbs + possibleverbs += "Cancel" // ...And one for the bottom + + var/verb = input("Select a verb!", "Verbs",null) as anything in possibleverbs + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + if(!verb || verb == "Cancel") + return + else + H.verbs += verb + + else if(href_list["remverb"]) + if(!check_rights(R_DEBUG)) return + + var/mob/H = locate(href_list["remverb"]) + + if(!istype(H)) + to_chat(usr, "This can only be done to instances of type /mob") + return + var/verb = input("Please choose a verb to remove.","Verbs",null) as null|anything in H.verbs + if(!H) + to_chat(usr, "Mob doesn't exist anymore") + return + if(!verb) + return + else + H.verbs -= verb + + else if(href_list["addorgan"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/M = locate(href_list["addorgan"]) + if(!istype(M)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon") + return + + var/new_organ = input("Please choose an organ to add.","Organ",null) as null|anything in typesof(/obj/item/organ)-/obj/item/organ + if(!new_organ) return + + if(!M) + to_chat(usr, "Mob doesn't exist anymore") + return + + if(locate(new_organ) in M.internal_organs) + to_chat(usr, "Mob already has that organ.") + return + + new new_organ(M) + + + else if(href_list["remorgan"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/M = locate(href_list["remorgan"]) + if(!istype(M)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon") + return + + var/obj/item/organ/rem_organ = input("Please choose an organ to remove.","Organ",null) as null|anything in M.internal_organs + + if(!M) + to_chat(usr, "Mob doesn't exist anymore") + return + + if(!(locate(rem_organ) in M.internal_organs)) + to_chat(usr, "Mob does not have that organ.") + return + + to_chat(usr, "Removed [rem_organ] from [M].") + rem_organ.removed() + qdel(rem_organ) + + else if(href_list["fix_nano"]) + if(!check_rights(R_DEBUG)) return + + var/mob/H = locate(href_list["fix_nano"]) + + if(!istype(H) || !H.client) + to_chat(usr, "This can only be done on mobs with clients") + return + + GLOB.nanomanager.close_uis(H) + H.client.cache.Cut() + var/datum/asset/assets = get_asset_datum(/datum/asset/nanoui) + assets.send(H) + + to_chat(usr, "Resource files sent") + to_chat(H, "Your NanoUI Resource files have been refreshed") + + log_admin("[key_name(usr)] resent the NanoUI resource files to [key_name(H)] ") + + else if(href_list["regenerateicons"]) + if(!check_rights(0)) return + + var/mob/M = locate(href_list["regenerateicons"]) + if(!ismob(M)) + to_chat(usr, "This can only be done to instances of type /mob") + return + M.regenerate_icons() + + else if(href_list["adjustDamage"] && href_list["mobToDamage"]) + if(!check_rights(R_DEBUG|R_ADMIN|R_FUN)) return + + var/mob/living/L = locate(href_list["mobToDamage"]) + if(!istype(L)) return + + var/Text = href_list["adjustDamage"] + + var/amount = input("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num + + if(!L) + to_chat(usr, "Mob doesn't exist anymore") + return + + switch(Text) + if("brute") L.adjustBruteLoss(amount) + if("fire") L.adjustFireLoss(amount) + if("toxin") L.adjustToxLoss(amount) + if("oxygen")L.adjustOxyLoss(amount) + if("brain") L.adjustBrainLoss(amount) + if("clone") L.adjustCloneLoss(amount) + else + to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]") + return + + if(amount != 0) + log_admin("[key_name(usr)] dealt [amount] amount of [Text] damage to [L]") + message_admins("[key_name(usr)] dealt [amount] amount of [Text] damage to [L]") + href_list["datumrefresh"] = href_list["mobToDamage"] + + else if(href_list["call_proc"]) + var/datum/D = locate(href_list["call_proc"]) + if(istype(D) || istype(D, /client)) // can call on clients too, not just datums + callproc_targetpicked(1, D) + else if(href_list["addaura"]) + if(!check_rights(R_DEBUG|R_ADMIN|R_FUN)) return + var/mob/living/L = locate(href_list["addaura"]) + if(!istype(L)) + return + var/choice = input("Please choose an aura to add", "Auras", null) as null|anything in typesof(/obj/aura) + if(!choice || !L) + return + var/obj/o = new choice(L) + log_and_message_admins("added \the [o] to \the [L]") + else if(href_list["removeaura"]) + if(!check_rights(R_DEBUG|R_ADMIN|R_FUN)) return + var/mob/living/L = locate(href_list["removeaura"]) + if(!istype(L)) + return + var/choice = input("Please choose an aura to remove", "Auras", null) as null|anything in L.auras + if(!choice || !L) + return + log_and_message_admins("removed \the [choice] to \the [L]") + qdel(choice) + if(href_list["datumrefresh"]) + var/datum/DAT = locate(href_list["datumrefresh"]) + if(istype(DAT, /datum) || istype(DAT, /client)) + debug_variables(DAT) + + return diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm new file mode 100644 index 00000000..9190912d --- /dev/null +++ b/code/modules/admin/view_variables/view_variables.dm @@ -0,0 +1,155 @@ +// Variables not to expand the lists of. Vars is pointless to expand, and overlays/underlays cannot be expanded. +/var/list/view_variables_dont_expand = list("overlays", "underlays", "vars") +// Variables that runtime if you try to test associativity of the lists they contain by indexing +/var/list/view_variables_no_assoc = list("verbs", "contents","screen","images") + +// Acceptable 'in world', as VV would be incredibly hampered otherwise +/client/proc/debug_variables(datum/D in world) + set category = "Debug" + set name = "View Variables" + + if(!check_rights(0)) + return + + if(!D) + return + + var/icon/sprite + if(istype(D, /atom)) + var/atom/A = D + if(A.icon && A.icon_state) + sprite = icon(A.icon, A.icon_state) + usr << browse_rsc(sprite, "view_vars_sprite.png") + + send_rsc(usr,'code/js/view_variables.js', "view_variables.js") + + var/html = {" + + + + [D] (\ref[D] - [D.type]) + + + +
            + + + +
            + + [sprite ? "" : ""] + +
            [D.get_view_variables_header()]
            +
            + [replacetext("[D.type]", "/", "/")] + [holder.marked_datum() == D ? "
            Marked Object" : ""] +
            +
            +
            + Refresh +
            + +
            +
            +
            +
            +
            + + E - Edit, tries to determine the variable type by itself.
            + C - Change, asks you for the var type first.
            + M - Mass modify: changes this variable for all objects of this type.
            +
            +
            + + + +
            +
            + Search: +
            +
            + +
            +
            +
              + [make_view_variables_var_list(D)] +
            + + + "} + + usr << browse(html, "window=variables\ref[D];size=475x650") + + +/proc/make_view_variables_var_list(datum/D) + . = list() + var/list/variables = D.get_variables() + variables = sortList(variables) + for(var/x in variables) + . += make_view_variables_var_entry(D, x, D.get_variable_value(x)) + return jointext(., null) + +/proc/make_view_variables_value(value, varname = "*") + var/vtext = "" + var/extra = list() + if(isnull(value)) + vtext = "null" + else if(istext(value)) + vtext = "\"[value]\"" + else if(isicon(value)) + vtext = "[value]" + else if(isfile(value)) + vtext = "'[value]'" + else if(istype(value, /datum)) + var/datum/DA = value + if("[DA]" == "[DA.type]" || !"[DA]") + vtext = "\ref[DA] - [DA.type]" + else + vtext = "\ref[DA] - [DA] ([DA.type])" + else if(istype(value, /client)) + var/client/C = value + vtext = "\ref[C] - [C] ([C.type])" + else if(islist(value)) + var/list/L = value + vtext = "/list ([L.len])" + if(!(varname in view_variables_dont_expand) && L.len > 0 && L.len < 100) + extra += "
              " + for (var/index = 1 to L.len) + var/entry = L[index] + if(!isnum(entry) && !isnull(entry) && !(varname in view_variables_no_assoc) && L[entry] != null) + extra += "
            • [index]: [make_view_variables_value(entry)] -> [make_view_variables_value(L[entry])]
            • " + else + extra += "
            • [index]: [make_view_variables_value(entry)]
            • " + extra += "
            " + else + vtext = "[value]" + + return "[vtext][jointext(extra, null)]" + +/proc/make_view_variables_var_entry(datum/D, varname, value, level=0) + var/ecm = null + + if(D) + ecm = D.make_view_variables_variable_entry(varname, value) + + var/valuestr = make_view_variables_value(value, varname) + + return "
          • [ecm][varname] = [valuestr]
          • " diff --git a/code/modules/admin/view_variables/view_variables_global.dm b/code/modules/admin/view_variables/view_variables_global.dm new file mode 100644 index 00000000..5e2f0bd7 --- /dev/null +++ b/code/modules/admin/view_variables/view_variables_global.dm @@ -0,0 +1,51 @@ +/var/decl/global_vars/global_vars_ + +/decl/global_vars/get_view_variables_header() + return "Global Variables" + +/decl/global_vars/get_view_variables_options() + return "" // Ensuring changes to the base proc never affect us + +/decl/global_vars/get_variables() + . = _all_globals - VV_hidden() + if(!usr || !check_rights(R_ADMIN|R_DEBUG, FALSE)) + . -= VV_secluded() + +/decl/global_vars/get_variable_value(varname) + return readglobal(varname) + +/decl/global_vars/set_variable_value(varname, value) + writeglobal(varname, value) + +/decl/global_vars/make_view_variables_variable_entry(varname, value) + return "(E) " + +/decl/global_vars/VV_locked() + return vars + +/decl/global_vars/VV_hidden() + return list("forumsqladdress", + "forumsqldb", + "forumsqllogin", + "forumsqlpass", + "forumsqlport", + "sqladdress", + "sqldb", + "sqlfdbkdb", + "sqlfdbklogin", + "sqlfdbkpass", + "sqllogin", + "sqlpass", + "sqlport", + "comms_password", + "ban_comms_password", + "login_export_addr" + ) + +/client/proc/debug_global_variables() + set category = "Debug" + set name = "View Global Variables" + + if(!global_vars_) + global_vars_ = new() + debug_variables(global_vars_) diff --git a/code/modules/admin/view_variables/vv_set_handlers.dm b/code/modules/admin/view_variables/vv_set_handlers.dm new file mode 100644 index 00000000..f64f58a4 --- /dev/null +++ b/code/modules/admin/view_variables/vv_set_handlers.dm @@ -0,0 +1,117 @@ +/decl/vv_set_handler + var/handled_type + var/predicates + var/list/handled_vars + +/decl/vv_set_handler/proc/can_handle_set_var(var/datum/O, variable, var_value, client) + if(!istype(O, handled_type)) + return FALSE + if(!(variable in handled_vars)) + return FALSE + if(istype(O) && !(variable in O.vars)) + log_error("Did not find the variable '[variable]' for the instance [log_info_line(O)].") + return FALSE + if(predicates) + for(var/predicate in predicates) + if(!call(predicate)(var_value, client)) + return FALSE + return TRUE + +/decl/vv_set_handler/proc/handle_set_var(var/datum/O, variable, var_value, client) + var/proc_to_call = handled_vars[variable] + if(proc_to_call) + call(O, proc_to_call)(var_value) + else + O.vars[variable] = var_value + +/decl/vv_set_handler/location_hander + handled_type = /atom/movable + handled_vars = list("loc","x","y","z") + +/decl/vv_set_handler/location_hander/handle_set_var(var/atom/movable/AM, variable, var_value, client) + if(variable == "loc") + if(istype(var_value, /atom) || isnull(var_value) || var_value == "") // Proper null or empty string is fine, 0 is not + AM.forceMove(var_value) + else + to_chat(client, "May only assign null or /atom types to loc.") + else if(variable == "x" || variable == "y" || variable == "z") + if(istext(var_value)) + var_value = text2num(var_value) + if(!is_num_predicate(var_value, client)) + return + + // We set the default to 1,1,1 when at 0,0,0 (i.e. any non-turf location) to mimic the standard BYOND behaviour when adjusting x,y,z directly + var/x = AM.x || 1 + var/y = AM.y || 1 + var/z = AM.z || 1 + switch(variable) + if("x") + x = var_value + if("y") + y = var_value + if("z") + z = var_value + + var/turf/T = locate(x,y,z) + if(T) + AM.forceMove(T) + else + to_chat(client, "Unable to locate a turf at [x]-[y]-[z].") + +/decl/vv_set_handler/opacity_hander + handled_type = /atom + handled_vars = list("opacity" = /atom/proc/set_opacity) + predicates = list(/proc/is_num_predicate) + +/decl/vv_set_handler/dir_hander + handled_type = /atom + handled_vars = list("dir" = /atom/proc/set_dir) + predicates = list(/proc/is_dir_predicate) + +/decl/vv_set_handler/ghost_appearance_handler + handled_type = /mob/observer/ghost + handled_vars = list("appearance" = /mob/observer/ghost/proc/set_appearance) + predicates = list(/proc/is_atom_predicate) + +/decl/vv_set_handler/virtual_ability_handler + handled_type = /mob/observer/virtual + handled_vars = list("abilities") + predicates = list(/proc/is_num_predicate) + +/decl/vv_set_handler/virtual_ability_handler/handle_set_var(var/mob/observer/virtual/virtual, variable, var_value, client) + ..() + virtual.update_icon() + +/decl/vv_set_handler/mob_see_invisible_handler + handled_type = /mob + handled_vars = list("see_invisible" = /mob/proc/set_see_invisible) + predicates = list(/proc/is_num_predicate) + +/decl/vv_set_handler/mob_sight_handler + handled_type = /mob + handled_vars = list("sight" = /mob/proc/set_sight) + predicates = list(/proc/is_num_predicate) + +/decl/vv_set_handler/mob_see_in_dark_handler + handled_type = /mob + handled_vars = list("see_in_dark" = /mob/proc/set_see_in_dark) + predicates = list(/proc/is_num_predicate) + +/decl/vv_set_handler/mob_stat_handler + handled_type = /mob + handled_vars = list("set_stat" = /mob/proc/set_stat) + predicates = list(/proc/is_num_predicate) + +/decl/vv_set_handler/icon_state_handler + handled_type = /atom + handled_vars = list("icon_state" = /atom/proc/set_icon_state) + +/decl/vv_set_handler/invisibility_handler + handled_type = /atom + handled_vars = list("invisibility" = /atom/proc/set_invisibility) + predicates = list(/proc/is_num_predicate) + +/decl/vv_set_handler/name_handler + handled_type = /atom + handled_vars = list("name" = /atom/proc/SetName) + predicates = list(/proc/is_text_predicate) diff --git a/code/modules/alarm/alarm.dm b/code/modules/alarm/alarm.dm new file mode 100644 index 00000000..b995bd47 --- /dev/null +++ b/code/modules/alarm/alarm.dm @@ -0,0 +1,152 @@ +#define ALARM_RESET_DELAY 100 // How long will the alarm/trigger remain active once origin/source has been found to be gone? + +/datum/alarm_source + var/source = null // The source trigger + var/source_name = "" // The name of the source should it be lost (for example a destroyed camera) + var/duration = 0 // How long this source will be alarming, 0 for indefinetely. + var/severity = 1 // How severe the alarm from this source is. + var/start_time = 0 // When this source began alarming. + var/end_time = 0 // Use to set when this trigger should clear, in case the source is lost. + +/datum/alarm_source/New(var/atom/source) + src.source = source + start_time = world.time + source_name = source.get_source_name() + +/datum/alarm + var/atom/origin //Used to identify the alarm area. + var/list/sources = new() //List of sources triggering the alarm. Used to determine when the alarm should be cleared. + var/list/sources_assoc = new() //Associative list of source triggers. Used to efficiently acquire the alarm source. + var/list/cameras //List of cameras that can be switched to, if the player has that capability. + var/cache_id //ID for camera cache, changed by invalidateCameraCache(). + var/area/last_area //The last acquired area, used should origin be lost (for example a destroyed borg containing an alarming camera). + var/area/last_name //The last acquired name, used should origin be lost + var/area/last_camera_area //The last area in which cameras where fetched, used to see if the camera list should be updated. + var/last_z_level //The last acquired z-level, used should origin be lost + var/end_time //Used to set when this alarm should clear, in case the origin is lost. + +/datum/alarm/New(var/atom/origin, var/atom/source, var/duration, var/severity) + src.origin = origin + + cameras() // Sets up both cameras and last alarm area. + set_source_data(source, duration, severity) + +/datum/alarm/proc/process() + // Has origin gone missing? + if(!origin && !end_time) + end_time = world.time + ALARM_RESET_DELAY + for(var/datum/alarm_source/AS in sources) + // Has the alarm passed its best before date? + if((AS.end_time && world.time > AS.end_time) || (AS.duration && world.time > (AS.start_time + AS.duration))) + sources -= AS + // Has the source gone missing? Then reset the normal duration and set end_time + if(!AS.source && !AS.end_time) // end_time is used instead of duration to ensure the reset doesn't remain in the future indefinetely. + AS.duration = 0 + AS.end_time = world.time + ALARM_RESET_DELAY + +/datum/alarm/proc/set_source_data(var/atom/source, var/duration, var/severity) + var/datum/alarm_source/AS = sources_assoc[source] + if(!AS) + AS = new/datum/alarm_source(source) + sources += AS + sources_assoc[source] = AS + // Currently only non-0 durations can be altered (normal alarms VS EMP blasts) + if(AS.duration) + duration = SecondsToTicks(duration) + AS.duration = duration + AS.severity = severity + +/datum/alarm/proc/clear(var/source) + var/datum/alarm_source/AS = sources_assoc[source] + sources -= AS + sources_assoc -= source + +/datum/alarm/proc/alarm_z() + if(origin) + last_z_level = origin.get_alarm_z(origin) + return last_z_level + +/datum/alarm/proc/alarm_area() + if(!origin) + return last_area + + last_area = origin.get_alarm_area() + return last_area + +/datum/alarm/proc/alarm_name() + if(!origin) + return last_name + + last_name = origin.get_alarm_name() + return last_name + +/datum/alarm/proc/cameras() + // reset camera cache + if(camera_repository.camera_cache_id != cache_id) + cameras = null + cache_id = camera_repository.camera_cache_id + // If the alarm origin has changed area, for example a borg containing an alarming camera, reset the list of cameras + else if(cameras && (last_camera_area != alarm_area())) + cameras = null + + // The list of cameras is also reset by /proc/invalidateCameraCache() + if(!cameras) + cameras = origin ? origin.get_alarm_cameras() : last_area.get_alarm_cameras() + + last_camera_area = last_area + return cameras + +/datum/alarm/proc/max_severity() + var/max_severity = 0 + for(var/datum/alarm_source/AS in sources) + max_severity = max(AS.severity, max_severity) + + return max_severity + +/****************** +* Assisting procs * +******************/ +/atom/proc/get_alarm_z() + return get_z(src) + +area/get_alarm_z() + return contents.len ? get_z(contents[1]) : 0 + +/atom/proc/get_alarm_area() + return get_area(src) + +/area/get_alarm_area() + return src + +/atom/proc/get_alarm_name() + var/area/A = get_area(src) + return A.name + +/area/get_alarm_name() + return name + +/mob/get_alarm_name() + return name + +/atom/proc/get_source_name() + return name + +/obj/machinery/camera/get_source_name() + return c_tag + +/atom/proc/get_alarm_cameras() + var/area/A = get_area(src) + return A.get_cameras() + +/area/get_alarm_cameras() + return get_cameras() + +/mob/living/silicon/robot/get_alarm_cameras() + var/list/cameras = ..() + if(camera) + cameras += camera + + return cameras + +/mob/living/silicon/robot/syndicate/get_alarm_cameras() + return list() diff --git a/code/modules/alarm/alarm_handler.dm b/code/modules/alarm/alarm_handler.dm new file mode 100644 index 00000000..96e2ed06 --- /dev/null +++ b/code/modules/alarm/alarm_handler.dm @@ -0,0 +1,117 @@ +#define ALARM_RAISED 1 +#define ALARM_CLEARED 0 + +/datum/alarm_handler + var/category = "" + var/list/datum/alarm/alarms = new // All alarms, to handle cases when an origin has been deleted with one or more active alarms + var/list/datum/alarm/alarms_assoc = new // Associative list of alarms, to efficiently acquire them based on origin. + var/list/datum/alarm/alarms_by_z = new // Associative list of alarms based on origin z level + var/list/listeners = new // A list of all objects interested in alarm changes. + +/datum/alarm_handler/proc/process() + for(var/datum/alarm/A in alarms) + A.process() + check_alarm_cleared(A) + +/datum/alarm_handler/proc/triggerAlarm(var/atom/origin, var/atom/source, var/duration = 0, var/severity = 1) + var/new_alarm + //Proper origin and source mandatory + if(!(origin && source)) + return + origin = origin.get_alarm_origin() + + new_alarm = 0 + //see if there is already an alarm of this origin + var/datum/alarm/existing = alarms_assoc[origin] + if(existing) + existing.set_source_data(source, duration, severity) + else + existing = new/datum/alarm(origin, source, duration, severity) + new_alarm = 1 + + alarms |= existing + alarms_assoc[origin] = existing + LAZYDISTINCTADD(alarms_by_z["[existing.alarm_z()]"], existing) + if(new_alarm) + alarms = dd_sortedObjectList(alarms) + on_alarm_change(existing, ALARM_RAISED) + + return new_alarm + +/datum/alarm_handler/proc/clearAlarm(var/atom/origin, var/source) + //Proper origin and source mandatory + if(!(origin && source)) + return + origin = origin.get_alarm_origin() + + var/datum/alarm/existing = alarms_assoc[origin] + if(existing) + existing.clear(source) + return check_alarm_cleared(existing) + +// Returns alarms in connected z levels to z_level. If none is given, returns all. +/datum/alarm_handler/proc/alarms(var/z_level) + if(z_level) + . = list() + for(var/z in GetConnectedZlevels(z_level)) + . += alarms_by_z["[z]"] || list() + else + return alarms + +// Returns major alarms in connected z levels to z_level. If none is given, returns all. +/datum/alarm_handler/proc/major_alarms(var/z_level) + return alarms(z_level) + +/datum/alarm_handler/proc/has_major_alarms(var/z_level) + return !!length(major_alarms(z_level)) + +// Returns minor alarms in connected z levels to z_level. If none is given, returns all. +/datum/alarm_handler/proc/minor_alarms(var/z_level) + return alarms(z_level) + +/datum/alarm_handler/proc/has_minor_alarms(var/z_level) + return !!length(minor_alarms(z_level)) + +/datum/alarm_handler/proc/check_alarm_cleared(var/datum/alarm/alarm) + if ((alarm.end_time && world.time > alarm.end_time) || !alarm.sources.len) + alarms -= alarm + alarms_assoc -= alarm.origin + alarms_by_z["[alarm.alarm_z()]"] -= alarm + on_alarm_change(alarm, ALARM_CLEARED) + return 1 + return 0 + +/datum/alarm_handler/proc/on_alarm_change(var/datum/alarm/alarm, var/was_raised) + for(var/obj/machinery/camera/C in alarm.cameras()) + if(was_raised) + C.add_network(category) + else + C.remove_network(category) + notify_listeners(alarm, was_raised) + +/datum/alarm_handler/proc/get_alarm_severity_for_origin(var/atom/origin) + if(!origin) + return + + origin = origin.get_alarm_origin() + var/datum/alarm/existing = alarms_assoc[origin] + if(!existing) + return + + return existing.max_severity() + +/atom/proc/get_alarm_origin() + return src + +/turf/get_alarm_origin() + return get_area(src) + +/datum/alarm_handler/proc/register_alarm(var/object, var/procName) + listeners[object] = procName + +/datum/alarm_handler/proc/unregister_alarm(var/object) + listeners -= object + +/datum/alarm_handler/proc/notify_listeners(var/alarm, var/was_raised) + for(var/listener in listeners) + call(listener, listeners[listener])(src, alarm, was_raised) diff --git a/code/modules/alarm/atmosphere_alarm.dm b/code/modules/alarm/atmosphere_alarm.dm new file mode 100644 index 00000000..8786d19f --- /dev/null +++ b/code/modules/alarm/atmosphere_alarm.dm @@ -0,0 +1,17 @@ +/datum/alarm_handler/atmosphere + category = NETWORK_ALARM_ATMOS + +/datum/alarm_handler/atmosphere/triggerAlarm(var/atom/origin, var/atom/source, var/duration = 0, var/severity = 1) + ..() + +/datum/alarm_handler/atmosphere/major_alarms(var/z_level) + . = list() + for(var/datum/alarm/A in ..()) + if(A.max_severity() > 1) + . += A + +/datum/alarm_handler/atmosphere/minor_alarms(var/z_level) + . = list() + for(var/datum/alarm/A in ..()) + if(A.max_severity() == 1) + . += A diff --git a/code/modules/alarm/camera_alarm.dm b/code/modules/alarm/camera_alarm.dm new file mode 100644 index 00000000..5cf0cff6 --- /dev/null +++ b/code/modules/alarm/camera_alarm.dm @@ -0,0 +1,2 @@ +/datum/alarm_handler/camera + category = NETWORK_ALARM_CAMERA diff --git a/code/modules/alarm/fire_alarm.dm b/code/modules/alarm/fire_alarm.dm new file mode 100644 index 00000000..553252aa --- /dev/null +++ b/code/modules/alarm/fire_alarm.dm @@ -0,0 +1,11 @@ +/datum/alarm_handler/fire + category = NETWORK_ALARM_FIRE + +/datum/alarm_handler/fire/on_alarm_change(var/datum/alarm/alarm, var/was_raised) + var/area/A = alarm.origin + if(istype(A)) + if(was_raised) + A.fire_alert() + else + A.fire_reset() + ..() diff --git a/code/modules/alarm/motion_alarm.dm b/code/modules/alarm/motion_alarm.dm new file mode 100644 index 00000000..292d5704 --- /dev/null +++ b/code/modules/alarm/motion_alarm.dm @@ -0,0 +1,2 @@ +/datum/alarm_handler/motion + category = NETWORK_ALARM_MOTION diff --git a/code/modules/alarm/power_alarm.dm b/code/modules/alarm/power_alarm.dm new file mode 100644 index 00000000..550f6c33 --- /dev/null +++ b/code/modules/alarm/power_alarm.dm @@ -0,0 +1,10 @@ +/datum/alarm_handler/power + category = NETWORK_ALARM_POWER + +/datum/alarm_handler/power/on_alarm_change(var/datum/alarm/alarm, var/was_raised) + var/area/A = alarm.origin + if(istype(A)) + A.power_alert(was_raised) + ..() + +/area/proc/power_alert(var/alarming) diff --git a/code/modules/aspect/_aspects.dm b/code/modules/aspect/_aspects.dm new file mode 100644 index 00000000..864c5c19 --- /dev/null +++ b/code/modules/aspect/_aspects.dm @@ -0,0 +1,100 @@ +/* +##################ASPECTS!############ +##Aspects are one time events that only fire at the very beginning of the round. +##The idea behind them is that they change something about the game world, an aspect if you will, +##to keep rounds from being samey. They can either affect a certain job, the crew on whole, or the map. +##Obviously some are going to be more balanced than others. Aspects should change something about the +##game world to make it more interesting, not annoying. Remember that when adding a new one. +## +##In order to add your own just define a new aspect datum and add it to the "possible_aspects" list. +##I'm sure there's a better way to do this, and I'll change this comment block when I find one. - Matt +###################################### + +IT'S IMPORTANT TO REMEMBER THAT YES, ASPECTS HAVE THE HUGE POTENTIAL TO RUIN GAME BALANCE! + USE THIS POWER WITH CAUTION! +*/ + +//Global "chosen aspect" mainly used to affect stuff post game launch +//The global list of aspects that can be chosen. Used in gameticker.dm +var/list/possible_aspects = list() + +//Checks to see if the aspect chosen matches the argument. Useful for affecting stuff post round start. +proc/aspect_chosen(var/datum/aspect/aspect) + if(!config.use_aspect_system) + return FALSE + if(!SSaspects.chosen_aspect) + return FALSE + if(istype(SSaspects.chosen_aspect, aspect)) + return TRUE + + +//Prints out the aspect. Used at the end of the round in gameticker.dm +proc/print_aspect() + if(SSaspects.chosen_aspect) + to_world("The random game modifier was \"[SSaspects.chosen_aspect.name]\": [SSaspects.chosen_aspect.desc]") + + +//Aspect defines +/datum/aspect + var/name = "Default Aspect" + var/desc = "Default description." + +//The thing that does the thing roundstart. +/datum/aspect/proc/activate() + return + +/datum/aspect/proc/deactivate() + display_deactivation_text() + +/datum/aspect/proc/display_activation_text() + to_world("Praise the atomic bomb! [desc]") + +/datum/aspect/proc/display_deactivation_text() + to_world("Praise the atomic bomb! We will not battle under the curse of [name]") + + +//Test aspect +/* +/datum/aspect/lightsout + name = "Dark Days Ahead" + desc = "All lights are broken today!" + + +//Breaks all the lights. How nice. +/datum/aspect/lightsout/activate() + ..() + lightsout(0,0) +*/ + +/datum/aspect/clean_guns + name = "Well Oiled Machine" + desc = "Due to proper gun maintenance, guns will not jam this battle!" + +/datum/aspect/lone_rider + name = "Battlefield 1842" + desc = "All bolt action rifles have been replaced by their lever action variants this battle!" + +/datum/aspect/one_word + name = "Civil War" + desc = "Nothing seperates one side from the other. We all speak the same language this battle!" + +/datum/aspect/no_guns + name = "Slappers only!" + desc = "Due to poor gun maintenance, guns just don't work this battle." + +/datum/aspect/nightfare + name = "Nightfare" + desc = "Our worst fears have come true! The sun has gone out! There is no natural light on the battlefield!" + +datum/aspect/nightfare/activate() + //Change lobby to a moon or something. Adjust lobby music? + ..() + for(var/obj/effect/lighting_dummy/daylight/A in GLOB.lighting_dummies) + A.set_light(0, 0, 0) + +datum/aspect/nightfare/deactivate() + //Change lobby to a moon or something. Adjust lobby music? + ..() + for(var/obj/effect/lighting_dummy/daylight/A in GLOB.lighting_dummies) + A.set_light(3, 3, "#28284f") + diff --git a/code/modules/assembly/assembly.dm b/code/modules/assembly/assembly.dm new file mode 100644 index 00000000..4d29638a --- /dev/null +++ b/code/modules/assembly/assembly.dm @@ -0,0 +1,179 @@ +/obj/item/device/assembly + name = "assembly" + desc = "A small electronic device that should never exist." + icon = 'icons/obj/assemblies/new_assemblies.dmi' + icon_state = "" + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_SMALL + matter = list(DEFAULT_WALL_MATERIAL = 100) + throwforce = 2 + throw_speed = 3 + throw_range = 10 + origin_tech = list(TECH_MAGNET = 1) + + var/secured = 1 + var/list/attached_overlays = null + var/obj/item/device/assembly_holder/holder = null + var/cooldown = 0//To prevent spam + var/wires = WIRE_RECEIVE | WIRE_PULSE + + var/const/WIRE_RECEIVE = 1 //Allows Pulsed(0) to call Activate() + var/const/WIRE_PULSE = 2 //Allows Pulse(0) to act on the holder + var/const/WIRE_PULSE_SPECIAL = 4 //Allows Pulse(0) to act on the holders special assembly + var/const/WIRE_RADIO_RECEIVE = 8 //Allows Pulsed(1) to call Activate() + var/const/WIRE_RADIO_PULSE = 16 //Allows Pulse(1) to send a radio message + +/obj/item/device/assembly/proc/activate() //What the device does when turned on + return + +/obj/item/device/assembly/proc/pulsed(var/radio = 0) //Called when another assembly acts on this one, var/radio will determine where it came from for wire calcs + return + +/obj/item/device/assembly/proc/pulse(var/radio = 0) //Called when this device attempts to act on another device, var/radio determines if it was sent via radio or direct + return + +/obj/item/device/assembly/proc/toggle_secure() //Code that has to happen when the assembly is un\secured goes here + return + +/obj/item/device/assembly/proc/attach_assembly(var/obj/A, var/mob/user) //Called when an assembly is attacked by another + return + +/obj/item/device/assembly/proc/process_cooldown() //Called via spawn(10) to have it count down the cooldown var + return + +/obj/item/device/assembly/proc/holder_movement() //Called when the holder is moved + return + +/obj/item/device/assembly/interact(mob/user as mob) //Called when attack_self is called + return + + +/obj/item/device/assembly/process_cooldown() + cooldown-- + if(cooldown <= 0) return 0 + spawn(10) + process_cooldown() + return 1 + + +/obj/item/device/assembly/pulsed(var/radio = 0) + if(holder && (wires & WIRE_RECEIVE)) + activate() + if(radio && (wires & WIRE_RADIO_RECEIVE)) + activate() + return 1 + + +/obj/item/device/assembly/pulse(var/radio = 0) + if(holder && (wires & WIRE_PULSE)) + holder.process_activation(src, 1, 0) + if(holder && (wires & WIRE_PULSE_SPECIAL)) + holder.process_activation(src, 0, 1) +// if(radio && (wires & WIRE_RADIO_PULSE)) + //Not sure what goes here quite yet send signal? + return 1 + + +/obj/item/device/assembly/activate() + if(!secured || (cooldown > 0)) return 0 + cooldown = 2 + spawn(10) + process_cooldown() + return 1 + + +/obj/item/device/assembly/toggle_secure() + secured = !secured + update_icon() + return secured + + +/obj/item/device/assembly/attach_assembly(var/obj/item/device/assembly/A, var/mob/user) + holder = new/obj/item/device/assembly_holder(get_turf(src)) + if(holder.attach(A,src,user)) + to_chat(user, "You attach \the [A] to \the [src]!") + return 1 + return 0 + + +/obj/item/device/assembly/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isassembly(W)) + var/obj/item/device/assembly/A = W + if((!A.secured) && (!secured)) + attach_assembly(A,user) + return + if(isScrewdriver(W)) + if(toggle_secure()) + to_chat(user, "\The [src] is ready!") + else + to_chat(user, "\The [src] can now be attached!") + return + ..() + return + + +/obj/item/device/assembly/Process() + return PROCESS_KILL + + +/obj/item/device/assembly/examine(mob/user) + . = ..(user) + if((in_range(src, user) || loc == user)) + if(secured) + to_chat(user, "\The [src] is ready!") + else + to_chat(user, "\The [src] can be attached!") + return + + +/obj/item/device/assembly/attack_self(mob/user as mob) + if(!user) return 0 + user.set_machine(src) + interact(user) + return 1 + +/obj/item/device/assembly/interact(mob/user as mob) + return //HTML MENU FOR WIRES GOES HERE + +/obj/item/device/assembly/nano_host() + if(istype(loc, /obj/item/device/assembly_holder)) + return loc.nano_host() + return ..() + +/* + var/small_icon_state = null//If this obj will go inside the assembly use this for icons + var/list/small_icon_state_overlays = null//Same here + var/obj/holder = null + var/cooldown = 0//To prevent spam + + proc + Activate()//Called when this assembly is pulsed by another one + Process_cooldown()//Call this via spawn(10) to have it count down the cooldown var + Attach_Holder(var/obj/H, var/mob/user)//Called when an assembly holder attempts to attach, sets src's loc in here + + + Activate() + if(cooldown > 0) + return 0 + cooldown = 2 + spawn(10) + Process_cooldown() + //Rest of code here + return 0 + + + Process_cooldown() + cooldown-- + if(cooldown <= 0) return 0 + spawn(10) + Process_cooldown() + return 1 + + + Attach_Holder(var/obj/H, var/mob/user) + if(!H) return 0 + if(!H.IsAssemblyHolder()) return 0 + //Remember to have it set its loc somewhere in here + + +*/ diff --git a/code/modules/assembly/helpers.dm b/code/modules/assembly/helpers.dm new file mode 100644 index 00000000..0779fdd1 --- /dev/null +++ b/code/modules/assembly/helpers.dm @@ -0,0 +1,39 @@ +/proc/isassembly(O) + if(istype(O, /obj/item/device/assembly)) + return 1 + return 0 + +/proc/isigniter(O) + if(istype(O, /obj/item/device/assembly/igniter)) + return 1 + return 0 + +/proc/isprox(O) + if(istype(O, /obj/item/device/assembly/prox_sensor)) + return 1 + return 0 + +/proc/issignaler(O) + if(istype(O, /obj/item/device/assembly/signaler)) + return 1 + return 0 + +/proc/istimer(O) + if(istype(O, /obj/item/device/assembly/timer)) + return 1 + return 0 + +/* +Name: IsSpecialAssembly +Desc: If true is an object that can be attached to an assembly holder but is a special thing like a phoron can or door +*/ + +/obj/proc/IsSpecialAssembly() + return 0 + +/* +Name: IsAssemblyHolder +Desc: If true is an object that can hold an assemblyholder object +*/ +/obj/proc/IsAssemblyHolder() + return 0 \ No newline at end of file diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm new file mode 100644 index 00000000..4cc3bb15 --- /dev/null +++ b/code/modules/assembly/holder.dm @@ -0,0 +1,287 @@ +/obj/item/device/assembly_holder + name = "Assembly" + icon = 'icons/obj/assemblies/new_assemblies.dmi' + icon_state = "holder" + item_state = "assembly" + movable_flags = MOVABLE_FLAG_PROXMOVE + obj_flags = OBJ_FLAG_CONDUCTIBLE + throwforce = 5 + w_class = ITEM_SIZE_SMALL + throw_speed = 3 + throw_range = 10 + + var/secured = 0 + var/obj/item/device/assembly/a_left = null + var/obj/item/device/assembly/a_right = null + var/obj/special_assembly = null + + proc/attach(var/obj/item/device/D, var/obj/item/device/D2, var/mob/user) + return + + proc/attach_special(var/obj/O, var/mob/user) + return + + proc/process_activation(var/obj/item/device/D) + return + + proc/detached() + return + + + IsAssemblyHolder() + return 1 + + + attach(var/obj/item/device/D, var/obj/item/device/D2, var/mob/user) + if((!D)||(!D2)) return 0 + if((!isassembly(D))||(!isassembly(D2))) return 0 + if((D:secured)||(D2:secured)) return 0 + if(user) + user.remove_from_mob(D) + user.remove_from_mob(D2) + D:holder = src + D2:holder = src + D.loc = src + D2.loc = src + a_left = D + a_right = D2 + SetName("[D.name]-[D2.name] assembly") + update_icon() + usr.put_in_hands(src) + + return 1 + + + attach_special(var/obj/O, var/mob/user) + if(!O) return + if(!O.IsSpecialAssembly()) return 0 + +/* if(O:Attach_Holder()) + special_assembly = O + update_icon() + src.SetName("[a_left.name] [a_right.name] [special_assembly.name] assembly") +*/ + return + + + update_icon() + overlays.Cut() + if(a_left) + overlays += "[a_left.icon_state]_left" + for(var/O in a_left.attached_overlays) + overlays += "[O]_l" + if(a_right) + src.overlays += "[a_right.icon_state]_right" + for(var/O in a_right.attached_overlays) + overlays += "[O]_r" + if(master) + master.update_icon() + +/* if(special_assembly) + special_assembly.update_icon() + if(special_assembly:small_icon_state) + src.overlays += special_assembly:small_icon_state + for(var/O in special_assembly:small_icon_state_overlays) + src.overlays += O +*/ + + examine(mob/user) + . = ..(user) + if ((in_range(src, user) || src.loc == user)) + if (src.secured) + to_chat(user, "\The [src] is ready!") + else + to_chat(user, "\The [src] can be attached!") + return + + + HasProximity(atom/movable/AM as mob|obj) + if(a_left) + a_left.HasProximity(AM) + if(a_right) + a_right.HasProximity(AM) + if(special_assembly) + special_assembly.HasProximity(AM) + + + Crossed(atom/movable/AM as mob|obj) + if(a_left) + a_left.Crossed(AM) + if(a_right) + a_right.Crossed(AM) + if(special_assembly) + special_assembly.Crossed(AM) + + + on_found(mob/finder as mob) + if(a_left) + a_left.on_found(finder) + if(a_right) + a_right.on_found(finder) + if(special_assembly) + if(istype(special_assembly, /obj/item)) + var/obj/item/S = special_assembly + S.on_found(finder) + + + Move() + ..() + if(a_left && a_right) + a_left.holder_movement() + a_right.holder_movement() +// if(special_assembly) +// special_assembly:holder_movement() + return + + + attack_hand()//Perhapse this should be a holder_pickup proc instead, can add if needbe I guess + if(a_left && a_right) + a_left.holder_movement() + a_right.holder_movement() +// if(special_assembly) +// special_assembly:Holder_Movement() + ..() + return + + + attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isScrewdriver(W)) + if(!a_left || !a_right) + to_chat(user, "BUG:Assembly part missing, please report this!") + return + a_left.toggle_secure() + a_right.toggle_secure() + secured = !secured + if(secured) + to_chat(user, "\The [src] is ready!") + else + to_chat(user, "\The [src] can now be taken apart!") + update_icon() + return + else if(W.IsSpecialAssembly()) + attach_special(W, user) + else + ..() + return + + + attack_self(mob/user as mob) + src.add_fingerprint(user) + if(src.secured) + if(!a_left || !a_right) + to_chat(user, "Assembly part missing!") + return + if(istype(a_left,a_right.type))//If they are the same type it causes issues due to window code + switch(alert("Which side would you like to use?",,"Left","Right")) + if("Left") a_left.attack_self(user) + if("Right") a_right.attack_self(user) + return + else + if(!istype(a_left,/obj/item/device/assembly/igniter)) + a_left.attack_self(user) + if(!istype(a_right,/obj/item/device/assembly/igniter)) + a_right.attack_self(user) + else + var/turf/T = get_turf(src) + if(!T) return 0 + if(a_left) + a_left:holder = null + a_left.loc = T + if(a_right) + a_right:holder = null + a_right.loc = T + spawn(0) + qdel(src) + return + + + process_activation(var/obj/D, var/normal = 1, var/special = 1) + if(!D) return 0 + if(!secured) + visible_message("\icon[src] *beep* *beep*", "*beep* *beep*") + if((normal) && (a_right) && (a_left)) + if(a_right != D) + a_right.pulsed(0) + if(a_left != D) + a_left.pulsed(0) + if(master) + master.receive_signal() +// if(special && special_assembly) +// if(!special_assembly == D) +// special_assembly.dothings() + return 1 + + +/obj/item/device/assembly_holder/New() + ..() + GLOB.listening_objects += src + +/obj/item/device/assembly_holder/Destroy() + GLOB.listening_objects -= src + return ..() + + +/obj/item/device/assembly_holder/hear_talk(mob/living/M as mob, msg, verb, datum/language/speaking) + if(a_right) + a_right.hear_talk(M,msg,verb,speaking) + if(a_left) + a_left.hear_talk(M,msg,verb,speaking) + + + + +/obj/item/device/assembly_holder/timer_igniter + name = "timer-igniter assembly" + + New() + ..() + + var/obj/item/device/assembly/igniter/ign = new(src) + ign.secured = 1 + ign.holder = src + var/obj/item/device/assembly/timer/tmr = new(src) + tmr.time=5 + tmr.secured = 1 + tmr.holder = src + START_PROCESSING(SSobj, tmr) + a_left = tmr + a_right = ign + secured = 1 + update_icon() + SetName(initial(name) + " ([tmr.time] secs)") + + loc.verbs += /obj/item/device/assembly_holder/timer_igniter/verb/configure + + detached() + loc.verbs -= /obj/item/device/assembly_holder/timer_igniter/verb/configure + ..() + + verb/configure() + set name = "Set Timer" + set category = "Object" + set src in usr + + if ( !(usr.stat || usr.restrained()) ) + var/obj/item/device/assembly_holder/holder + if(istype(src,/obj/item/weapon/grenade/chem_grenade)) + var/obj/item/weapon/grenade/chem_grenade/gren = src + holder=gren.detonator + var/obj/item/device/assembly/timer/tmr = holder.a_left + if(!istype(tmr,/obj/item/device/assembly/timer)) + tmr = holder.a_right + if(!istype(tmr,/obj/item/device/assembly/timer)) + to_chat(usr, "This detonator has no timer.") + return + + if(tmr.timing) + to_chat(usr, "Clock is ticking already.") + else + var/ntime = input("Enter desired time in seconds", "Time", "5") as num + if (ntime>0 && ntime<1000) + tmr.time = ntime + SetName(initial(name) + "([tmr.time] secs)") + to_chat(usr, "Timer set to [tmr.time] seconds.") + else + to_chat(usr, "Timer can't be [ntime<=0?"negative":"more than 1000 seconds"].") + else + to_chat(usr, "You cannot do this while [usr.stat?"unconscious/dead":"restrained"].") diff --git a/code/modules/assembly/igniter.dm b/code/modules/assembly/igniter.dm new file mode 100644 index 00000000..7f168c28 --- /dev/null +++ b/code/modules/assembly/igniter.dm @@ -0,0 +1,37 @@ +/obj/item/device/assembly/igniter + name = "igniter" + desc = "A small electronic device able to ignite combustable substances." + icon_state = "igniter" + origin_tech = list(TECH_MAGNET = 1) + matter = list(DEFAULT_WALL_MATERIAL = 500, "glass" = 50, "waste" = 10) + + secured = 1 + wires = WIRE_RECEIVE + + activate() + if(!..()) return 0//Cooldown check + + if(holder && istype(holder.loc,/obj/item/weapon/grenade/chem_grenade)) + var/obj/item/weapon/grenade/chem_grenade/grenade = holder.loc + grenade.detonate() + else + var/turf/location = get_turf(loc) + if(location) + location.hotspot_expose(1000,1000) + if (istype(src.loc,/obj/item/device/assembly_holder)) + if (istype(src.loc.loc, /obj/structure/reagent_dispensers/fueltank/)) + var/obj/structure/reagent_dispensers/fueltank/tank = src.loc.loc + if (tank && tank.modded) + tank.explode() + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + + return 1 + + + attack_self(mob/user as mob) + activate() + add_fingerprint(user) + return \ No newline at end of file diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm new file mode 100644 index 00000000..cd5e3951 --- /dev/null +++ b/code/modules/assembly/infrared.dm @@ -0,0 +1,158 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/obj/item/device/assembly/infra + name = "infrared emitter" + desc = "Emits a visible or invisible beam and is triggered when the beam is interrupted." + icon_state = "infrared" + origin_tech = list(TECH_MAGNET = 2) + matter = list(DEFAULT_WALL_MATERIAL = 1000, "glass" = 500, "waste" = 100) + + wires = WIRE_PULSE + + secured = 0 + + var/on = 0 + var/visible = 0 + + var/list/beams + var/list/seen_turfs + var/datum/proximity_trigger/line/proximity_trigger + +/obj/item/device/assembly/infra/New() + ..() + beams = list() + seen_turfs = list() + proximity_trigger = new(src, /obj/item/device/assembly/infra/proc/on_beam_entered, /obj/item/device/assembly/infra/proc/on_visibility_change, world.view, PROXIMITY_EXCLUDE_HOLDER_TURF) + +/obj/item/device/assembly/infra/Destroy() + qdel(proximity_trigger) + proximity_trigger = null + + . = ..() + +/obj/item/device/assembly/infra/activate() + if(!..()) + return 0//Cooldown check + set_active(!on) + return 1 + +/obj/item/device/assembly/infra/proc/set_active(new_on) + if(new_on == on) + return + on = new_on + if(on) + proximity_trigger.register_turfs() + else + proximity_trigger.unregister_turfs() + update_icon() + +/obj/item/device/assembly/infra/toggle_secure() + secured = !secured + set_active(secured ? FALSE : on) + return secured + +/obj/item/device/assembly/infra/update_icon() + overlays.Cut() + if(on) + overlays += "infrared_on" + if(holder) + holder.update_icon() + update_beams() + +/obj/item/device/assembly/infra/interact(mob/user as mob)//TODO: change this this to the wire control panel + if(!secured) + return + if(!CanInteract(user, GLOB.physical_state)) + return + + user.set_machine(src) + var/dat = list() + dat += text("Infrared Laser\nStatus: []
            \nVisibility: []
            \n
            ", (on ? text("On", src) : text("Off", src)), (src.visible ? text("Visible", src) : text("Invisible", src))) + dat += "

            Refresh" + dat += "

            Close" + user << browse(jointext(dat,null), "window=infra") + onclose(user, "infra") + +/obj/item/device/assembly/infra/Topic(href, href_list, state = GLOB.physical_state) + if(..()) + usr << browse(null, "window=infra") + onclose(usr, "infra") + return 1 + + if(href_list["state"]) + set_active(!on) + + if(href_list["visible"]) + visible = !(visible) + update_icon() + + if(href_list["close"]) + usr << browse(null, "window=infra") + return + + if(usr) + attack_self(usr) + +/obj/item/device/assembly/infra/verb/rotate()//This could likely be better + set name = "Rotate Infrared Laser" + set category = "Object" + set src in usr + + set_dir(turn(dir, 90)) + +/obj/item/device/assembly/infra/proc/on_beam_entered(var/atom/enterer) + if(enterer == src) + return + if(enterer.invisibility > INVISIBILITY_LEVEL_TWO) + return + if(!secured || !on || cooldown > 0) + return 0 + if((ismob(enterer) && !isliving(enterer))) // Observers and their ilk don't count even if visible + return + + pulse(0) + if(!holder) + visible_message("\icon[src] *beep* *beep*") + cooldown = 2 + spawn(10) + process_cooldown() + +/obj/item/device/assembly/infra/proc/on_visibility_change(var/list/old_turfs, var/list/new_turfs) + seen_turfs = new_turfs + update_beams() + +/obj/item/device/assembly/infra/proc/update_beams() + create_update_and_delete_beams(on, visible, dir, seen_turfs, beams) + +/proc/create_update_and_delete_beams(var/active, var/visible, var/dir, var/list/seen_turfs, var/list/existing_beams) + if(!active) + for(var/b in existing_beams) + qdel(b) + existing_beams.Cut() + return + + var/list/turfs_that_need_beams = seen_turfs.Copy() + + for(var/b in existing_beams) + var/obj/effect/beam/ir_beam/beam = b + if(beam.loc in turfs_that_need_beams) + turfs_that_need_beams -= beam.loc + beam.set_invisibility(visible ? 0 : INVISIBILITY_MAXIMUM) + else + existing_beams -= beam + qdel(beam) + + if(!visible) + return + + for(var/t in turfs_that_need_beams) + var/obj/effect/beam/ir_beam/beam = new(t) + existing_beams += beam + beam.set_dir(dir) + +/obj/effect/beam/ir_beam + name = "ir beam" + icon = 'icons/obj/projectiles.dmi' + icon_state = "ibeam" + anchored = 1 + simulated = 0 diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm new file mode 100644 index 00000000..48cd08ae --- /dev/null +++ b/code/modules/assembly/mousetrap.dm @@ -0,0 +1,127 @@ +/obj/item/device/assembly/mousetrap + name = "mousetrap" + desc = "A handy little spring-loaded trap for catching pesty rodents." + icon_state = "mousetrap" + origin_tech = list(TECH_COMBAT = 1) + matter = list(DEFAULT_WALL_MATERIAL = 100, "waste" = 10) + var/armed = 0 + + + examine(mob/user) + . = ..(user) + if(armed) + to_chat(user, "It looks like it's armed.") + + update_icon() + if(armed) + icon_state = "mousetraparmed" + else + icon_state = "mousetrap" + if(holder) + holder.update_icon() + + proc/triggered(mob/target as mob, var/type = "feet") + if(!armed) + return + var/obj/item/organ/external/affecting = null + if(ishuman(target)) + var/mob/living/carbon/human/H = target + switch(type) + if("feet") + if(!H.shoes) + affecting = H.get_organ(pick(BP_L_LEG, BP_R_LEG)) + H.Weaken(3) + if(BP_L_HAND, BP_R_HAND) + if(!H.gloves) + affecting = H.get_organ(type) + H.Stun(3) + if(affecting) + affecting.take_damage(1, 0) + H.updatehealth() + else if(ismouse(target)) + var/mob/living/simple_animal/mouse/M = target + visible_message("SPLAT!") + M.splat() + playsound(target.loc, 'sound/effects/snap.ogg', 50, 1) + reset_plane_and_layer() + armed = 0 + update_icon() + pulse(0) + + + attack_self(mob/living/user as mob) + if(!armed) + to_chat(user, "You arm [src].") + else + if((CLUMSY in user.mutations) && prob(50)) + var/which_hand = BP_L_HAND + if(!user.hand) + which_hand = BP_R_HAND + triggered(user, which_hand) + user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \ + "You accidentally trigger [src]!") + return + to_chat(user, "You disarm [src].") + armed = !armed + update_icon() + playsound(user.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3) + + + attack_hand(mob/living/user as mob) + if(armed) + if((CLUMSY in user.mutations) && prob(50)) + var/which_hand = BP_L_HAND + if(!user.hand) + which_hand = BP_R_HAND + triggered(user, which_hand) + user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \ + "You accidentally trigger [src]!") + return + ..() + + + Crossed(AM as mob|obj) + if(armed) + if(ishuman(AM)) + var/mob/living/carbon/H = AM + if(H.m_intent == "run") + triggered(H) + H.visible_message("[H] accidentally steps on [src].", \ + "You accidentally step on [src]") + if(ismouse(AM)) + triggered(AM) + ..() + + + on_found(mob/finder as mob) + if(armed) + finder.visible_message("[finder] accidentally sets off [src], breaking their fingers.", \ + "You accidentally trigger [src]!") + triggered(finder, finder.hand ? BP_L_HAND : BP_R_HAND) + return 1 //end the search! + return 0 + + + hitby(A as mob|obj) + if(!armed) + return ..() + visible_message("[src] is triggered by [A].") + triggered(null) + + +/obj/item/device/assembly/mousetrap/armed + icon_state = "mousetraparmed" + armed = 1 + + +/obj/item/device/assembly/mousetrap/verb/hide_under() + set src in oview(1) + set name = "Hide" + set category = "Object" + + if(usr.incapacitated()) + return + + plane = ABOVE_TURF_PLANE + layer = MOUSETRAP_LAYER + to_chat(usr, "You hide [src].") diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm new file mode 100644 index 00000000..c6ade300 --- /dev/null +++ b/code/modules/assembly/proximity.dm @@ -0,0 +1,164 @@ +/obj/item/device/assembly/prox_sensor + name = "proximity sensor" + desc = "Used for scanning and alerting when someone enters a certain proximity." + icon_state = "prox" + origin_tech = list(TECH_MAGNET = 1) + matter = list(DEFAULT_WALL_MATERIAL = 800, "glass" = 200, "waste" = 50) + movable_flags = MOVABLE_FLAG_PROXMOVE + wires = WIRE_PULSE + + secured = 0 + + var/scanning = 0 + var/timing = 0 + var/time = 10 + + var/range = 2 + +/obj/item/device/assembly/prox_sensor/proc/toggle_scan() +/obj/item/device/assembly/prox_sensor/proc/sense() + + +/obj/item/device/assembly/prox_sensor/activate() + if(!..()) return 0//Cooldown check + timing = !timing + update_icon() + return 0 + + +/obj/item/device/assembly/prox_sensor/toggle_secure() + secured = !secured + if(secured) + START_PROCESSING(SSobj, src) + else + scanning = 0 + timing = 0 + STOP_PROCESSING(SSobj, src) + update_icon() + return secured + + +/obj/item/device/assembly/prox_sensor/HasProximity(atom/movable/AM as mob|obj) + if(!istype(AM)) + log_debug("DEBUG: HasProximity called with [AM] on [src] ([usr]).") + return + if (istype(AM, /obj/effect/beam)) return + if (AM.move_speed < 12) sense() + return + + +/obj/item/device/assembly/prox_sensor/sense() + var/turf/mainloc = get_turf(src) +// if(scanning && cooldown <= 0) +// mainloc.visible_message("\icon[src] *boop* *boop*", "*boop* *boop*") + if((!holder && !secured)||(!scanning)||(cooldown > 0)) return 0 + pulse(0) + if(!holder) + mainloc.visible_message("\icon[src] *beep* *beep*", "*beep* *beep*") + cooldown = 2 + spawn(10) + process_cooldown() + return + + +/obj/item/device/assembly/prox_sensor/Process() + if(scanning) + var/turf/mainloc = get_turf(src) + for(var/mob/living/A in range(range,mainloc)) + if (A.move_speed < 12) + sense() + + if(timing && (time >= 0)) + time-- + if(timing && time <= 0) + timing = 0 + toggle_scan() + time = 10 + return + + +/obj/item/device/assembly/prox_sensor/dropped() + spawn(0) + sense() + return + return + + +/obj/item/device/assembly/prox_sensor/toggle_scan() + if(!secured) return 0 + scanning = !scanning + update_icon() + return + + +/obj/item/device/assembly/prox_sensor/update_icon() + overlays.Cut() + attached_overlays = list() + if(timing) + overlays += "prox_timing" + attached_overlays += "prox_timing" + if(scanning) + overlays += "prox_scanning" + attached_overlays += "prox_scanning" + if(holder) + holder.update_icon() + if(holder && istype(holder.loc,/obj/item/weapon/grenade/chem_grenade)) + var/obj/item/weapon/grenade/chem_grenade/grenade = holder.loc + grenade.primed(scanning) + return + + +/obj/item/device/assembly/prox_sensor/Move() + ..() + sense() + return + + +/obj/item/device/assembly/prox_sensor/interact(mob/user as mob)//TODO: Change this to the wires thingy + if(!secured) + user.show_message("The [name] is unsecured!") + return 0 + var/second = time % 60 + var/minute = (time - second) / 60 + var/dat = text("Proximity Sensor\n[] []:[]\n- - + +\n", (timing ? text("Arming", src) : text("Not Arming", src)), minute, second, src, src, src, src) + dat += text("
            Range: - [] +", src, range, src) + dat += "
            [scanning?"Armed":"Unarmed"] (Movement sensor active when armed!)" + dat += "

            Refresh" + dat += "

            Close" + user << browse(dat, "window=prox") + onclose(user, "prox") + return + + +/obj/item/device/assembly/prox_sensor/Topic(href, href_list, state = GLOB.physical_state) + if(..()) return 1 + if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) + usr << browse(null, "window=prox") + onclose(usr, "prox") + return + + if(href_list["scanning"]) + toggle_scan() + + if(href_list["time"]) + timing = text2num(href_list["time"]) + update_icon() + + if(href_list["tp"]) + var/tp = text2num(href_list["tp"]) + time += tp + time = min(max(round(time), 0), 600) + + if(href_list["range"]) + var/r = text2num(href_list["range"]) + range += r + range = min(max(range, 1), 5) + + if(href_list["close"]) + usr << browse(null, "window=prox") + return + + if(usr) + attack_self(usr) + + return \ No newline at end of file diff --git a/code/modules/assembly/shock_kit.dm b/code/modules/assembly/shock_kit.dm new file mode 100644 index 00000000..b9a9b7c2 --- /dev/null +++ b/code/modules/assembly/shock_kit.dm @@ -0,0 +1,46 @@ +/obj/item/assembly/shock_kit + name = "electrohelmet assembly" + desc = "This appears to be made from both an electropack and a helmet." + icon_state = "shock_kit" + var/obj/item/clothing/head/helmet/part1 = null + var/obj/item/device/radio/electropack/part2 = null + var/status = 0 + w_class = ITEM_SIZE_HUGE + obj_flags = OBJ_FLAG_CONDUCTIBLE + +/obj/item/assembly/shock_kit/Destroy() + qdel(part1) + qdel(part2) + ..() + return + +/obj/item/assembly/shock_kit/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWrench(W) && !status) + var/turf/T = loc + if(ismob(T)) + T = T.loc + part1.loc = T + part2.loc = T + part1.master = null + part2.master = null + part1 = null + part2 = null + qdel(src) + return + if(isScrewdriver(W)) + status = !status + to_chat(user, "[src] is now [status ? "secured" : "unsecured"]!") + add_fingerprint(user) + return + +/obj/item/assembly/shock_kit/attack_self(mob/user as mob) + part1.attack_self(user, status) + part2.attack_self(user, status) + add_fingerprint(user) + return + +/obj/item/assembly/shock_kit/receive_signal() + if(istype(loc, /obj/structure/bed/chair/e_chair)) + var/obj/structure/bed/chair/e_chair/C = loc + C.shock() + return diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm new file mode 100644 index 00000000..6ef44b94 --- /dev/null +++ b/code/modules/assembly/signaler.dm @@ -0,0 +1,194 @@ +/obj/item/device/assembly/signaler + name = "remote signaling device" + desc = "Used to remotely activate devices." + icon_state = "signaller" + item_state = "signaler" + origin_tech = list(TECH_MAGNET = 1) + matter = list(DEFAULT_WALL_MATERIAL = 1000, "glass" = 200, "waste" = 100) + wires = WIRE_RECEIVE | WIRE_PULSE | WIRE_RADIO_PULSE | WIRE_RADIO_RECEIVE + + secured = 1 + + var/code = 30 + var/frequency = 1457 + var/delay = 0 + var/airlock_wire = null + var/datum/wires/connected = null + var/datum/radio_frequency/radio_connection + var/deadman = 0 + +/obj/item/device/assembly/signaler/New() + ..() + spawn(40) + set_frequency(frequency) + return + + +/obj/item/device/assembly/signaler/activate() + if(cooldown > 0) return 0 + cooldown = 2 + spawn(10) + process_cooldown() + + signal() + return 1 + +/obj/item/device/assembly/signaler/update_icon() + if(holder) + holder.update_icon() + return + +/obj/item/device/assembly/signaler/interact(mob/user as mob, flag1) + var/t1 = "-------" +// if ((src.b_stat && !( flag1 ))) +// t1 = text("-------
            \nGreen Wire: []
            \nRed Wire: []
            \nBlue Wire: []
            \n", (src.wires & 4 ? text("Cut Wire", src) : text("Mend Wire", src)), (src.wires & 2 ? text("Cut Wire", src) : text("Mend Wire", src)), (src.wires & 1 ? text("Cut Wire", src) : text("Mend Wire", src))) +// else +// t1 = "-------" Speaker: [src.listening ? "Engaged" : "Disengaged"]
            + var/dat = {" + + + Send Signal
            + Frequency/Code for signaler:
            + Frequency: + - + - + [format_frequency(src.frequency)] + + + +
            + + Code: + - + - + [src.code] + + + +
            + [t1] +
            "} + user << browse(dat, "window=radio") + onclose(user, "radio") + return + + +/obj/item/device/assembly/signaler/Topic(href, href_list, state = GLOB.physical_state) + if(..()) return 1 + + if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) + usr << browse(null, "window=radio") + onclose(usr, "radio") + return + + if (href_list["freq"]) + var/new_frequency = (frequency + text2num(href_list["freq"])) + if(new_frequency < RADIO_LOW_FREQ || new_frequency > RADIO_HIGH_FREQ) + new_frequency = sanitize_frequency(new_frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) + set_frequency(new_frequency) + + if(href_list["code"]) + src.code += text2num(href_list["code"]) + src.code = round(src.code) + src.code = min(100, src.code) + src.code = max(1, src.code) + + if(href_list["send"]) + spawn( 0 ) + signal() + + if(usr) + attack_self(usr) + + return + + +/obj/item/device/assembly/signaler/proc/signal() + if(!radio_connection) return + + var/datum/signal/signal = new + signal.source = src + signal.encryption = code + signal.data["message"] = "ACTIVATE" + radio_connection.post_signal(src, signal) + return +/* + for(var/obj/item/device/assembly/signaler/S in world) + if(!S) continue + if(S == src) continue + if((S.frequency == src.frequency) && (S.code == src.code)) + spawn(0) + if(S) S.pulse(0) + return 0*/ + + +/obj/item/device/assembly/signaler/pulse(var/radio = 0) + if(src.connected && src.wires) + connected.Pulse(src) + else if(holder) + holder.process_activation(src, 1, 0) + else + ..(radio) + return 1 + + +/obj/item/device/assembly/signaler/receive_signal(datum/signal/signal) + if(!signal) return 0 + if(signal.encryption != code) return 0 + if(!(src.wires & WIRE_RADIO_RECEIVE)) return 0 + pulse(1) + + if(!holder) + for(var/mob/O in hearers(1, src.loc)) + O.show_message(text("\icon[] *beep* *beep*", src), 3, "*beep* *beep*", 2) + return + + +/obj/item/device/assembly/signaler/proc/set_frequency(new_frequency) + set waitfor = 0 + if(!frequency) + return + if(!radio_controller) + sleep(20) + if(!radio_controller) + return + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) + return + +/obj/item/device/assembly/signaler/Process() + if(!deadman) + STOP_PROCESSING(SSobj, src) + var/mob/M = src.loc + if(!M || !ismob(M)) + if(prob(5)) + signal() + deadman = 0 + STOP_PROCESSING(SSobj, src) + else if(prob(5)) + M.visible_message("[M]'s finger twitches a bit over [src]'s signal button!") + return + +/obj/item/device/assembly/signaler/proc/deadman_it() + set src in usr + set name = "Threaten to push the button!" + set desc = "BOOOOM!" + + if(!deadman) + deadman = 1 + START_PROCESSING(SSobj, src) + log_and_message_admins("is threatening to trigger a signaler deadman's switch") + usr.visible_message("[usr] moves their finger over [src]'s signal button...") + else + deadman = 0 + STOP_PROCESSING(SSobj, src) + log_and_message_admins("stops threatening to trigger a signaler deadman's switch") + usr.visible_message("[usr] moves their finger away from [src]'s signal button.") + +/obj/item/device/assembly/signaler/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + if(src == user.get_active_hand()) + deadman_it() + +/obj/item/device/assembly/signaler/Destroy() + if(radio_controller) + radio_controller.remove_object(src,frequency) + frequency = 0 + . = ..() diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm new file mode 100644 index 00000000..f916268a --- /dev/null +++ b/code/modules/assembly/timer.dm @@ -0,0 +1,107 @@ +/obj/item/device/assembly/timer + name = "timer" + desc = "Used to time things. Works well with contraptions which have to count down. Tick tock." + icon_state = "timer" + origin_tech = list(TECH_MAGNET = 1) + matter = list(DEFAULT_WALL_MATERIAL = 500, "glass" = 50, "waste" = 10) + + wires = WIRE_PULSE + + secured = 0 + + var/timing = 0 + var/time = 10 + +/obj/item/device/assembly/timer/proc/timer_end() + + +/obj/item/device/assembly/timer/activate() + if(!..()) return 0//Cooldown check + + timing = !timing + + update_icon() + return 0 + + +/obj/item/device/assembly/timer/toggle_secure() + secured = !secured + if(secured) + START_PROCESSING(SSobj, src) + else + timing = 0 + STOP_PROCESSING(SSobj, src) + update_icon() + return secured + + +/obj/item/device/assembly/timer/timer_end() + if(!secured) return 0 + pulse(0) + if(!holder) + visible_message("\icon[src] *beep* *beep*", "*beep* *beep*") + cooldown = 2 + spawn(10) + process_cooldown() + return + + +/obj/item/device/assembly/timer/Process() + if(timing && (time > 0)) + time-- + if(timing && time <= 0) + timing = 0 + timer_end() + time = 10 + return + + +/obj/item/device/assembly/timer/update_icon() + overlays.Cut() + attached_overlays = list() + if(timing) + overlays += "timer_timing" + attached_overlays += "timer_timing" + if(holder) + holder.update_icon() + return + + +/obj/item/device/assembly/timer/interact(mob/user as mob)//TODO: Have this use the wires + if(!secured) + user.show_message("\The [name] is unsecured!") + return 0 + var/second = time % 60 + var/minute = (time - second) / 60 + var/dat = text("Timing Unit\n[] []:[]\n- - + +\n", (timing ? text("Timing", src) : text("Not Timing", src)), minute, second, src, src, src, src) + dat += "

            Refresh" + dat += "

            Close" + user << browse(dat, "window=timer") + onclose(user, "timer") + return + + +/obj/item/device/assembly/timer/Topic(href, href_list, state = GLOB.physical_state) + if(..()) return 1 + if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) + usr << browse(null, "window=timer") + onclose(usr, "timer") + return + + if(href_list["time"]) + timing = text2num(href_list["time"]) + update_icon() + + if(href_list["tp"]) + var/tp = text2num(href_list["tp"]) + time += tp + time = min(max(round(time), 0), 600) + + if(href_list["close"]) + usr << browse(null, "window=timer") + return + + if(usr) + attack_self(usr) + + return diff --git a/code/modules/assembly/voice.dm b/code/modules/assembly/voice.dm new file mode 100644 index 00000000..d2416545 --- /dev/null +++ b/code/modules/assembly/voice.dm @@ -0,0 +1,44 @@ +/obj/item/device/assembly/voice + name = "voice analyzer" + desc = "A small electronic device able to record a voice sample, and send a signal when that sample is repeated." + icon_state = "voice" + origin_tech = list(TECH_MAGNET = 1) + matter = list(DEFAULT_WALL_MATERIAL = 500, "glass" = 50, "waste" = 10) + var/listening = 0 + var/recorded //the activation message + +/obj/item/device/assembly/voice/New() + ..() + GLOB.listening_objects += src + +/obj/item/device/assembly/voice/Destroy() + GLOB.listening_objects -= src + return ..() + +/obj/item/device/assembly/voice/hear_talk(mob/living/M as mob, msg) + if(listening) + recorded = msg + listening = 0 + var/turf/T = get_turf(src) //otherwise it won't work in hand + T.visible_message("\icon[src] beeps, \"Activation message is '[recorded]'.\"") + else + if(findtext(msg, recorded)) + pulse(0) + +/obj/item/device/assembly/voice/activate() + if(secured) + if(!holder) + listening = !listening + var/turf/T = get_turf(src) + T.visible_message("\icon[src] beeps, \"[listening ? "Now" : "No longer"] recording input.\"") + + +/obj/item/device/assembly/voice/attack_self(mob/user) + if(!user) return 0 + activate() + return 1 + + +/obj/item/device/assembly/voice/toggle_secure() + . = ..() + listening = 0 diff --git a/code/modules/atmospherics/_atmos_setup.dm b/code/modules/atmospherics/_atmos_setup.dm new file mode 100644 index 00000000..a58327dd --- /dev/null +++ b/code/modules/atmospherics/_atmos_setup.dm @@ -0,0 +1,280 @@ +//-------------------------------------------- +// Pipe colors +// +// Add them here and to the pipe_colors list +// to automatically add them to all relevant +// atmospherics devices. +//-------------------------------------------- +var/global/list/pipe_colors = list("grey" = PIPE_COLOR_GREY, "red" = PIPE_COLOR_RED, "blue" = PIPE_COLOR_BLUE, "cyan" = PIPE_COLOR_CYAN, "green" = PIPE_COLOR_GREEN, "yellow" = PIPE_COLOR_YELLOW, "black" = PIPE_COLOR_BLACK, "orange" = PIPE_COLOR_ORANGE) + +/proc/pipe_color_lookup(var/color) + for(var/C in pipe_colors) + if(color == pipe_colors[C]) + return "[C]" + +/proc/pipe_color_check(var/color) + if(!color) + return 1 + for(var/C in pipe_colors) + if(color == pipe_colors[C]) + return 1 + return 0 + +//-------------------------------------------- +// Icon cache generation +//-------------------------------------------- + +/datum/pipe_icon_manager + var/list/pipe_icons[] + var/list/manifold_icons[] + var/list/device_icons[] + var/list/underlays[] + //var/list/underlays_down[] + //var/list/underlays_exposed[] + //var/list/underlays_intact[] + //var/list/pipe_underlays_exposed[] + //var/list/pipe_underlays_intact[] + var/list/omni_icons[] + +/datum/pipe_icon_manager/New() + check_icons() + +/datum/pipe_icon_manager/proc/get_atmos_icon(var/device, var/dir, var/color, var/state) + check_icons() + + device = "[device]" + state = "[state]" + color = "[color]" + dir = "[dir]" + + switch(device) + if("pipe") + return pipe_icons[state + color] + if("manifold") + return manifold_icons[state + color] + if("device") + return device_icons[state] + if("omni") + return omni_icons[state] + if("underlay") + return underlays[state + dir + color] + // if("underlay_intact") + // return underlays_intact[state + dir + color] + // if("underlay_exposed") + // return underlays_exposed[state + dir + color] + // if("underlay_down") + // return underlays_down[state + dir + color] + // if("pipe_underlay_exposed") + // return pipe_underlays_exposed[state + dir + color] + // if("pipe_underlay_intact") + // return pipe_underlays_intact[state + dir + color] + +/datum/pipe_icon_manager/proc/check_icons() + if(!pipe_icons) + gen_pipe_icons() + if(!manifold_icons) + gen_manifold_icons() + if(!device_icons) + gen_device_icons() + if(!omni_icons) + gen_omni_icons() + //if(!underlays_intact || !underlays_down || !underlays_exposed || !pipe_underlays_exposed || !pipe_underlays_intact) + if(!underlays) + gen_underlay_icons() + +/datum/pipe_icon_manager/proc/gen_pipe_icons() + if(!pipe_icons) + pipe_icons = new() + + var/icon/pipe = new('icons/atmos/pipes.dmi') + + for(var/state in pipe.IconStates()) + if(!state || findtext(state, "map")) + continue + + var/cache_name = state + var/image/I = image('icons/atmos/pipes.dmi', icon_state = state) + pipe_icons[cache_name] = I + + for(var/pipe_color in pipe_colors) + I = image('icons/atmos/pipes.dmi', icon_state = state) + I.color = pipe_colors[pipe_color] + pipe_icons[state + "[pipe_colors[pipe_color]]"] = I + + pipe = new ('icons/atmos/heat.dmi') + for(var/state in pipe.IconStates()) + if(!state || findtext(state, "map")) + continue + pipe_icons["hepipe" + state] = image('icons/atmos/heat.dmi', icon_state = state) + + pipe = new ('icons/atmos/junction.dmi') + for(var/state in pipe.IconStates()) + if(!state || findtext(state, "map")) + continue + pipe_icons["hejunction" + state] = image('icons/atmos/junction.dmi', icon_state = state) + + +/datum/pipe_icon_manager/proc/gen_manifold_icons() + if(!manifold_icons) + manifold_icons = new() + + var/icon/pipe = new('icons/atmos/manifold.dmi') + + for(var/state in pipe.IconStates()) + if(findtext(state, "clamps")) + var/image/I = image('icons/atmos/manifold.dmi', icon_state = state) + manifold_icons[state] = I + continue + + if(findtext(state, "core") || findtext(state, "4way")) + var/image/I = image('icons/atmos/manifold.dmi', icon_state = state) + manifold_icons[state] = I + for(var/pipe_color in pipe_colors) + I = image('icons/atmos/manifold.dmi', icon_state = state) + I.color = pipe_colors[pipe_color] + manifold_icons[state + pipe_colors[pipe_color]] = I + +/datum/pipe_icon_manager/proc/gen_device_icons() + if(!device_icons) + device_icons = new() + + var/icon/device + + device = new('icons/atmos/vent_pump.dmi') + for(var/state in device.IconStates()) + if(!state || findtext(state, "map")) + continue + device_icons["vent" + state] = image('icons/atmos/vent_pump.dmi', icon_state = state) + + device = new('icons/atmos/vent_scrubber.dmi') + for(var/state in device.IconStates()) + if(!state || findtext(state, "map")) + continue + device_icons["scrubber" + state] = image('icons/atmos/vent_scrubber.dmi', icon_state = state) + +/datum/pipe_icon_manager/proc/gen_omni_icons() + if(!omni_icons) + omni_icons = new() + + var/icon/omni = new('icons/atmos/omni_devices.dmi') + + for(var/state in omni.IconStates()) + if(!state || findtext(state, "map")) + continue + omni_icons[state] = image('icons/atmos/omni_devices.dmi', icon_state = state) + + +/datum/pipe_icon_manager/proc/gen_underlay_icons() + + if(!underlays) + underlays = new() + + var/icon/pipe = new('icons/atmos/pipe_underlays.dmi') + + for(var/state in pipe.IconStates()) + if(state == "") + continue + + var/cache_name = state + + for(var/D in GLOB.cardinal) + var/image/I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D) + underlays[cache_name + "[D]"] = I + for(var/pipe_color in pipe_colors) + I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D) + I.color = pipe_colors[pipe_color] + underlays[state + "[D]" + "[pipe_colors[pipe_color]]"] = I + +/* + Leaving the old icon manager code commented out for now, as we may want to rewrite the new code to cleanly + separate the newpipe icon caching (speshul supply and scrubber lines) from the rest of the pipe code. +*/ + +/* +/datum/pipe_icon_manager/proc/gen_underlay_icons() + if(!underlays_intact) + underlays_intact = new() + if(!underlays_exposed) + underlays_exposed = new() + if(!underlays_down) + underlays_down = new() + if(!pipe_underlays_exposed) + pipe_underlays_exposed = new() + if(!pipe_underlays_intact) + pipe_underlays_intact = new() + + var/icon/pipe = new('icons/atmos/pipe_underlays.dmi') + + for(var/state in pipe.IconStates()) + if(state == "") + continue + + for(var/D in cardinal) + var/image/I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D) + switch(state) + if("intact") + underlays_intact["[D]"] = I + if("exposed") + underlays_exposed["[D]"] = I + if("down") + underlays_down["[D]"] = I + if("pipe_exposed") + pipe_underlays_exposed["[D]"] = I + if("pipe_intact") + pipe_underlays_intact["[D]"] = I + if("intact-supply") + underlays_intact["[D]"] = I + if("exposed-supply") + underlays_exposed["[D]"] = I + if("down-supply") + underlays_down["[D]"] = I + if("pipe_exposed-supply") + pipe_underlays_exposed["[D]"] = I + if("pipe_intact-supply") + pipe_underlays_intact["[D]"] = I + if("intact-scrubbers") + underlays_intact["[D]"] = I + if("exposed-scrubbers") + underlays_exposed["[D]"] = I + if("down-scrubbers") + underlays_down["[D]"] = I + if("pipe_exposed-scrubbers") + pipe_underlays_exposed["[D]"] = I + if("pipe_intact-scrubbers") + pipe_underlays_intact["[D]"] = I + for(var/pipe_color in pipe_colors) + I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D) + I.color = pipe_colors[pipe_color] + switch(state) + if("intact") + underlays_intact["[D]" + pipe_colors[pipe_color]] = I + if("exposed") + underlays_exposed["[D]" + pipe_colors[pipe_color]] = I + if("down") + underlays_down["[D]" + pipe_colors[pipe_color]] = I + if("pipe_exposed") + pipe_underlays_exposed["[D]" + pipe_colors[pipe_color]] = I + if("pipe_intact") + pipe_underlays_intact["[D]" + pipe_colors[pipe_color]] = I + if("intact-supply") + underlays_intact["[D]" + pipe_colors[pipe_color]] = I + if("exposed-supply") + underlays_exposed["[D]" + pipe_colors[pipe_color]] = I + if("down-supply") + underlays_down["[D]" + pipe_colors[pipe_color]] = I + if("pipe_exposed-supply") + pipe_underlays_exposed["[D]" + pipe_colors[pipe_color]] = I + if("pipe_intact-supply") + pipe_underlays_intact["[D]" + pipe_colors[pipe_color]] = I + if("intact-scrubbers") + underlays_intact["[D]" + pipe_colors[pipe_color]] = I + if("exposed-scrubbers") + underlays_exposed["[D]" + pipe_colors[pipe_color]] = I + if("down-scrubbers") + underlays_down["[D]" + pipe_colors[pipe_color]] = I + if("pipe_exposed-scrubbers") + pipe_underlays_exposed["[D]" + pipe_colors[pipe_color]] = I + if("pipe_intact-scrubbers") + pipe_underlays_intact["[D]" + pipe_colors[pipe_color]] = I + +*/ diff --git a/code/modules/atmospherics/atmos_primitives.dm b/code/modules/atmospherics/atmos_primitives.dm new file mode 100644 index 00000000..d09942ff --- /dev/null +++ b/code/modules/atmospherics/atmos_primitives.dm @@ -0,0 +1,511 @@ +/* + Atmos processes + + These procs generalize various processes used by atmos machinery, such as pumping, filtering, or scrubbing gas, allowing them to be reused elsewhere. + If no gas was moved/pumped/filtered/whatever, they return a negative number. + Otherwise they return the amount of energy needed to do whatever it is they do (equivalently power if done over 1 second). + In the case of free-flowing gas you can do things with gas and still use 0 power, hence the distinction between negative and non-negative return values. +*/ + + +/obj/machinery/atmospherics/var/last_flow_rate = 0 +/obj/machinery/atmospherics/var/last_power_draw = 0 +/obj/machinery/portable_atmospherics/var/last_flow_rate = 0 + + +/obj/machinery/atmospherics/var/debug = 0 + +/client/proc/atmos_toggle_debug(var/obj/machinery/atmospherics/M in world) + set name = "Toggle Debug Messages" + set category = "Debug" + M.debug = !M.debug + to_chat(usr, "[M]: Debug messages toggled [M.debug? "on" : "off"].") + +//Generalized gas pumping proc. +//Moves gas from one gas_mixture to another and returns the amount of power needed (assuming 1 second), or -1 if no gas was pumped. +//transfer_moles - Limits the amount of moles to transfer. The actual amount of gas moved may also be limited by available_power, if given. +//available_power - the maximum amount of power that may be used when moving gas. If null then the transfer is not limited by power. +/proc/pump_gas(var/obj/machinery/M, var/datum/gas_mixture/source, var/datum/gas_mixture/sink, var/transfer_moles = null, var/available_power = null) + if (source.total_moles < MINIMUM_MOLES_TO_PUMP) //if we cant transfer enough gas just stop to avoid further processing + return -1 + + if (isnull(transfer_moles)) + transfer_moles = source.total_moles + else + transfer_moles = min(source.total_moles, transfer_moles) + + //Calculate the amount of energy required and limit transfer_moles based on available power + var/specific_power = calculate_specific_power(source, sink)/ATMOS_PUMP_EFFICIENCY //this has to be calculated before we modify any gas mixtures + if (!isnull(available_power) && specific_power > 0) + transfer_moles = min(transfer_moles, available_power / specific_power) + + if (transfer_moles < MINIMUM_MOLES_TO_PUMP) //if we cant transfer enough gas just stop to avoid further processing + return -1 + + //Update flow rate meter + if (istype(M, /obj/machinery/atmospherics)) + var/obj/machinery/atmospherics/A = M + A.last_flow_rate = (transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here + + if (A.debug) + A.visible_message("[A]: source entropy: [round(source.specific_entropy(), 0.01)] J/Kmol --> sink entropy: [round(sink.specific_entropy(), 0.01)] J/Kmol") + A.visible_message("[A]: specific entropy change = [round(sink.specific_entropy() - source.specific_entropy(), 0.01)] J/Kmol") + A.visible_message("[A]: specific power = [round(specific_power, 0.1)] W/mol") + A.visible_message("[A]: moles transferred = [transfer_moles] mol") + + if (istype(M, /obj/machinery/portable_atmospherics)) + var/obj/machinery/portable_atmospherics/P = M + P.last_flow_rate = (transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here + + var/datum/gas_mixture/removed = source.remove(transfer_moles) + if (!removed) //Just in case + return -1 + + var/power_draw = specific_power*transfer_moles + + sink.merge(removed) + + return power_draw + +//Gas 'pumping' proc for the case where the gas flow is passive and driven entirely by pressure differences (but still one-way). +/proc/pump_gas_passive(var/obj/machinery/M, var/datum/gas_mixture/source, var/datum/gas_mixture/sink, var/transfer_moles = null) + if (source.total_moles < MINIMUM_MOLES_TO_PUMP) //if we cant transfer enough gas just stop to avoid further processing + return -1 + + if (isnull(transfer_moles)) + transfer_moles = source.total_moles + else + transfer_moles = min(source.total_moles, transfer_moles) + + var/equalize_moles = calculate_equalize_moles(source, sink) + transfer_moles = min(transfer_moles, equalize_moles) + + if (transfer_moles < MINIMUM_MOLES_TO_PUMP) //if we cant transfer enough gas just stop to avoid further processing + return -1 + + //Update flow rate meter + if (istype(M, /obj/machinery/atmospherics)) + var/obj/machinery/atmospherics/A = M + A.last_flow_rate = (transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here + if (A.debug) + A.visible_message("[A]: moles transferred = [transfer_moles] mol") + + if (istype(M, /obj/machinery/portable_atmospherics)) + var/obj/machinery/portable_atmospherics/P = M + P.last_flow_rate = (transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here + + var/datum/gas_mixture/removed = source.remove(transfer_moles) + if(!removed) //Just in case + return -1 + sink.merge(removed) + + return 0 + +//Generalized gas scrubbing proc. +//Selectively moves specified gasses one gas_mixture to another and returns the amount of power needed (assuming 1 second), or -1 if no gas was filtered. +//filtering - A list of gasids to be scrubbed from source +//total_transfer_moles - Limits the amount of moles to scrub. The actual amount of gas scrubbed may also be limited by available_power, if given. +//available_power - the maximum amount of power that may be used when scrubbing gas. If null then the scrubbing is not limited by power. +/proc/scrub_gas(var/obj/machinery/M, var/list/filtering, var/datum/gas_mixture/source, var/datum/gas_mixture/sink, var/total_transfer_moles = null, var/available_power = null) + if (source.total_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing + return -1 + + filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &= + + //Determine the specific power of each filterable gas type, and the total amount of filterable gas (gasses selected to be scrubbed) + var/total_filterable_moles = 0 //the total amount of filterable gas + var/list/specific_power_gas = list() //the power required to remove one mole of pure gas, for each gas type + for (var/g in filtering) + if (source.gas[g] < MINIMUM_MOLES_TO_FILTER) + continue + + var/specific_power = calculate_specific_power_gas(g, source, sink)/ATMOS_FILTER_EFFICIENCY + specific_power_gas[g] = specific_power + total_filterable_moles += source.gas[g] + + if (total_filterable_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing + return -1 + + //now that we know the total amount of filterable gas, we can calculate the amount of power needed to scrub one mole of gas + var/total_specific_power = 0 //the power required to remove one mole of filterable gas + for (var/g in filtering) + var/ratio = source.gas[g]/total_filterable_moles //this converts the specific power per mole of pure gas to specific power per mole of scrubbed gas + total_specific_power += specific_power_gas[g]*ratio + + //Figure out how much of each gas to filter + if (isnull(total_transfer_moles)) + total_transfer_moles = total_filterable_moles + else + total_transfer_moles = min(total_transfer_moles, total_filterable_moles) + + //limit transfer_moles based on available power + if (!isnull(available_power) && total_specific_power > 0) + total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power) + + if (total_transfer_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing + return -1 + + //Update flow rate var + if (istype(M, /obj/machinery/atmospherics)) + var/obj/machinery/atmospherics/A = M + A.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here + if (istype(M, /obj/machinery/portable_atmospherics)) + var/obj/machinery/portable_atmospherics/P = M + P.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here + + var/power_draw = 0 + for (var/g in filtering) + var/transfer_moles = source.gas[g] + //filter gas in proportion to the mole ratio + transfer_moles = min(transfer_moles, total_transfer_moles*(source.gas[g]/total_filterable_moles)) + + //use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop. + source.adjust_gas(g, -transfer_moles, update=0) + sink.adjust_gas_temp(g, transfer_moles, source.temperature, update=0) + + power_draw += specific_power_gas[g]*transfer_moles + + //Remix the resulting gases + sink.update_values() + source.update_values() + + return power_draw + +//Generalized gas filtering proc. +//Filtering is a bit different from scrubbing. Instead of selectively moving the targeted gas types from one gas mix to another, filtering splits +//the input gas into two outputs: one that contains /only/ the targeted gas types, and another that completely clean of the targeted gas types. +//filtering - A list of gasids to be filtered. These gasses get moved to sink_filtered, while the other gasses get moved to sink_clean. +//total_transfer_moles - Limits the amount of moles to input. The actual amount of gas filtered may also be limited by available_power, if given. +//available_power - the maximum amount of power that may be used when filtering gas. If null then the filtering is not limited by power. +/proc/filter_gas(var/obj/machinery/M, var/list/filtering, var/datum/gas_mixture/source, var/datum/gas_mixture/sink_filtered, var/datum/gas_mixture/sink_clean, var/total_transfer_moles = null, var/available_power = null) + if (source.total_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing + return -1 + + filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &= + + var/total_specific_power = 0 //the power required to remove one mole of input gas + var/total_filterable_moles = 0 //the total amount of filterable gas + var/total_unfilterable_moles = 0 //the total amount of non-filterable gas + var/list/specific_power_gas = list() //the power required to remove one mole of pure gas, for each gas type + for (var/g in source.gas) + if (source.gas[g] < MINIMUM_MOLES_TO_FILTER) + continue + + if (g in filtering) + specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_filtered)/ATMOS_FILTER_EFFICIENCY + total_filterable_moles += source.gas[g] + else + specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_clean)/ATMOS_FILTER_EFFICIENCY + total_unfilterable_moles += source.gas[g] + + var/ratio = source.gas[g]/source.total_moles //converts the specific power per mole of pure gas to specific power per mole of input gas mix + total_specific_power += specific_power_gas[g]*ratio + + //Figure out how much of each gas to filter + if (isnull(total_transfer_moles)) + total_transfer_moles = source.total_moles + else + total_transfer_moles = min(total_transfer_moles, source.total_moles) + + //limit transfer_moles based on available power + if (!isnull(available_power) && total_specific_power > 0) + total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power) + + if (total_transfer_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing + return -1 + + //Update flow rate var + if (istype(M, /obj/machinery/atmospherics)) + var/obj/machinery/atmospherics/A = M + A.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here + if (istype(M, /obj/machinery/portable_atmospherics)) + var/obj/machinery/portable_atmospherics/P = M + P.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here + + var/datum/gas_mixture/removed = source.remove(total_transfer_moles) + if (!removed) //Just in case + return -1 + + var/filtered_power_used = 0 //power used to move filterable gas to sink_filtered + var/unfiltered_power_used = 0 //power used to move unfilterable gas to sink_clean + for (var/g in removed.gas) + var/power_used = specific_power_gas[g]*removed.gas[g] + + if (g in filtering) + //use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop. + sink_filtered.adjust_gas_temp(g, removed.gas[g], removed.temperature, update=0) + removed.adjust_gas(g, -removed.gas[g], update=0) + filtered_power_used += power_used + else + unfiltered_power_used += power_used + + sink_filtered.update_values() + removed.update_values() + + sink_clean.merge(removed) + + return filtered_power_used + unfiltered_power_used + +//For omni devices. Instead filtering is an associative list mapping gasids to gas mixtures. +//I don't like the copypasta, but I decided to keep both versions of gas filtering as filter_gas is slightly faster (doesn't create as many temporary lists, doesn't call update_values() as much) +//filter_gas can be removed and replaced with this proc if need be. +/proc/filter_gas_multi(var/obj/machinery/M, var/list/filtering, var/datum/gas_mixture/source, var/datum/gas_mixture/sink_clean, var/total_transfer_moles = null, var/available_power = null) + if (source.total_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing + return -1 + + filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &= + + var/total_specific_power = 0 //the power required to remove one mole of input gas + var/total_filterable_moles = 0 //the total amount of filterable gas + var/total_unfilterable_moles = 0 //the total amount of non-filterable gas + var/list/specific_power_gas = list() //the power required to remove one mole of pure gas, for each gas type + for (var/g in source.gas) + if (source.gas[g] < MINIMUM_MOLES_TO_FILTER) + continue + + if (g in filtering) + var/datum/gas_mixture/sink_filtered = filtering[g] + specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_filtered)/ATMOS_FILTER_EFFICIENCY + total_filterable_moles += source.gas[g] + else + specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_clean)/ATMOS_FILTER_EFFICIENCY + total_unfilterable_moles += source.gas[g] + + var/ratio = source.gas[g]/source.total_moles //converts the specific power per mole of pure gas to specific power per mole of input gas mix + total_specific_power += specific_power_gas[g]*ratio + + //Figure out how much of each gas to filter + if (isnull(total_transfer_moles)) + total_transfer_moles = source.total_moles + else + total_transfer_moles = min(total_transfer_moles, source.total_moles) + + //limit transfer_moles based on available power + if (!isnull(available_power) && total_specific_power > 0) + total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power) + + if (total_transfer_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing + return -1 + + //Update Flow Rate var + if (istype(M, /obj/machinery/atmospherics)) + var/obj/machinery/atmospherics/A = M + A.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here + if (istype(M, /obj/machinery/portable_atmospherics)) + var/obj/machinery/portable_atmospherics/P = M + P.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here + + var/datum/gas_mixture/removed = source.remove(total_transfer_moles) + if (!removed) //Just in case + return -1 + + var/list/filtered_power_used = list() //power used to move filterable gas to the filtered gas mixes + var/unfiltered_power_used = 0 //power used to move unfilterable gas to sink_clean + for (var/g in removed.gas) + var/power_used = specific_power_gas[g]*removed.gas[g] + + if (g in filtering) + var/datum/gas_mixture/sink_filtered = filtering[g] + //use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop. + sink_filtered.adjust_gas_temp(g, removed.gas[g], removed.temperature, update=1) + removed.adjust_gas(g, -removed.gas[g], update=0) + if (power_used) + filtered_power_used[sink_filtered] = power_used + else + unfiltered_power_used += power_used + + removed.update_values() + + var/power_draw = unfiltered_power_used + for (var/datum/gas_mixture/sink_filtered in filtered_power_used) + power_draw += filtered_power_used[sink_filtered] + + sink_clean.merge(removed) + + return power_draw + +//Similar deal as the other atmos process procs. +//mix_sources maps input gas mixtures to mix ratios. The mix ratios MUST add up to 1. +/proc/mix_gas(var/obj/machinery/M, var/list/mix_sources, var/datum/gas_mixture/sink, var/total_transfer_moles = null, var/available_power = null) + if (!mix_sources.len) + return -1 + + var/total_specific_power = 0 //the power needed to mix one mole of gas + var/total_mixing_moles = null //the total amount of gas that can be mixed, given our mix ratios + var/total_input_volume = 0 //for flow rate calculation + var/total_input_moles = 0 //for flow rate calculation + var/list/source_specific_power = list() + for (var/datum/gas_mixture/source in mix_sources) + if (source.total_moles < MINIMUM_MOLES_TO_FILTER) + return -1 //either mix at the set ratios or mix no gas at all + + var/mix_ratio = mix_sources[source] + if (!mix_ratio) + continue //this gas is not being mixed in + + //mixing rate is limited by the source with the least amount of available gas + var/this_mixing_moles = source.total_moles/mix_ratio + if (isnull(total_mixing_moles) || total_mixing_moles > this_mixing_moles) + total_mixing_moles = this_mixing_moles + + source_specific_power[source] = calculate_specific_power(source, sink)*mix_ratio/ATMOS_FILTER_EFFICIENCY + total_specific_power += source_specific_power[source] + total_input_volume += source.volume + total_input_moles += source.total_moles + + if (total_mixing_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing + return -1 + + if (isnull(total_transfer_moles)) + total_transfer_moles = total_mixing_moles + else + total_transfer_moles = min(total_mixing_moles, total_transfer_moles) + + //limit transfer_moles based on available power + if (!isnull(available_power) && total_specific_power > 0) + total_transfer_moles = min(total_transfer_moles, available_power / total_specific_power) + + if (total_transfer_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing + return -1 + + //Update flow rate var + if (istype(M, /obj/machinery/atmospherics)) + var/obj/machinery/atmospherics/A = M + A.last_flow_rate = (total_transfer_moles/total_input_moles)*total_input_volume //group_multiplier gets divided out here + if (istype(M, /obj/machinery/portable_atmospherics)) + var/obj/machinery/portable_atmospherics/P = M + P.last_flow_rate = (total_transfer_moles/total_input_moles)*total_input_volume //group_multiplier gets divided out here + + var/total_power_draw = 0 + for (var/datum/gas_mixture/source in mix_sources) + var/mix_ratio = mix_sources[source] + if (!mix_ratio) + continue + + var/transfer_moles = total_transfer_moles * mix_ratio + + var/datum/gas_mixture/removed = source.remove(transfer_moles) + + var/power_draw = transfer_moles * source_specific_power[source] + total_power_draw += power_draw + + sink.merge(removed) + + return total_power_draw + +/* + Helper procs for various things. +*/ + +//Calculates the amount of power needed to move one mole from source to sink. +/proc/calculate_specific_power(datum/gas_mixture/source, datum/gas_mixture/sink) + //Calculate the amount of energy required + var/air_temperature = (sink.temperature > 0)? sink.temperature : source.temperature + var/specific_entropy = sink.specific_entropy() - source.specific_entropy() //sink is gaining moles, source is loosing + var/specific_power = 0 // W/mol + + //If specific_entropy is < 0 then power is required to move gas + if (specific_entropy < 0) + specific_power = -specific_entropy*air_temperature //how much power we need per mole + + return specific_power + +//Calculates the amount of power needed to move one mole of a certain gas from source to sink. +/proc/calculate_specific_power_gas(var/gasid, datum/gas_mixture/source, datum/gas_mixture/sink) + //Calculate the amount of energy required + var/air_temperature = (sink.temperature > 0)? sink.temperature : source.temperature + var/specific_entropy = sink.specific_entropy_gas(gasid) - source.specific_entropy_gas(gasid) //sink is gaining moles, source is loosing + var/specific_power = 0 // W/mol + + //If specific_entropy is < 0 then power is required to move gas + if (specific_entropy < 0) + specific_power = -specific_entropy*air_temperature //how much power we need per mole + + return specific_power + +//Calculates the APPROXIMATE amount of moles that would need to be transferred to change the pressure of sink by pressure_delta +//If set, sink_volume_mod adjusts the effective output volume used in the calculation. This is useful when the output gas_mixture is +//part of a pipenetwork, and so it's volume isn't representative of the actual volume since the gas will be shared across the pipenetwork when it processes. +/proc/calculate_transfer_moles(datum/gas_mixture/source, datum/gas_mixture/sink, var/pressure_delta, var/sink_volume_mod=0) + if(source.temperature == 0 || source.total_moles == 0) return 0 + + var/output_volume = (sink.volume * sink.group_multiplier) + sink_volume_mod + var/source_total_moles = source.total_moles * source.group_multiplier + + var/air_temperature = source.temperature + if(sink.total_moles > 0 && sink.temperature > 0) + //estimate the final temperature of the sink after transfer + var/estimate_moles = pressure_delta*output_volume/(sink.temperature * R_IDEAL_GAS_EQUATION) + var/sink_heat_capacity = sink.heat_capacity() + var/transfer_heat_capacity = source.heat_capacity()*estimate_moles/source_total_moles + air_temperature = (sink.temperature*sink_heat_capacity + source.temperature*transfer_heat_capacity) / (sink_heat_capacity + transfer_heat_capacity) + + //get the number of moles that would have to be transfered to bring sink to the target pressure + return pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION) + +//Calculates the APPROXIMATE amount of moles that would need to be transferred to bring source and sink to the same pressure +/proc/calculate_equalize_moles(datum/gas_mixture/source, datum/gas_mixture/sink) + if(source.temperature == 0) return 0 + + //Make the approximation that the sink temperature is unchanged after transferring gas + var/source_volume = source.volume * source.group_multiplier + var/sink_volume = sink.volume * sink.group_multiplier + + var/source_pressure = source.return_pressure() + var/sink_pressure = sink.return_pressure() + + return (source_pressure - sink_pressure)/(R_IDEAL_GAS_EQUATION * (source.temperature/source_volume + sink.temperature/sink_volume)) + +//Determines if the atmosphere is safe (for humans). Safe atmosphere: +// - Is between 80 and 120kPa +// - Has between 17% and 30% oxygen +// - Has temperature between -10C and 50C +// - Has no or only minimal phoron or N2O +/proc/get_atmosphere_issues(datum/gas_mixture/atmosphere, var/returntext = 0) + var/list/status = list() + if(!atmosphere) + status.Add("No atmosphere present.") + + // Temperature check + if((atmosphere.temperature > (T0C + 50)) || (atmosphere.temperature < (T0C - 10))) + status.Add("Temperature too [atmosphere.temperature > (T0C + 50) ? "high" : "low"].") + + // Pressure check + var/pressure = atmosphere.return_pressure() + if((pressure > 120) || (pressure < 80)) + status.Add("Pressure too [pressure > 120 ? "high" : "low"].") + + // Gas concentration checks + var/oxygen = 0 + var/phoron = 0 + var/carbondioxide = 0 + var/nitrousoxide = 0 + var/hydrogen = 0 + if(atmosphere.total_moles) // Division by zero prevention + oxygen = (atmosphere.gas["oxygen"] / atmosphere.total_moles) * 100 // Percentage of the gas + phoron = (atmosphere.gas["phoron"] / atmosphere.total_moles) * 100 + carbondioxide = (atmosphere.gas["carbon_dioxide"] / atmosphere.total_moles) * 100 + nitrousoxide = (atmosphere.gas["sleeping_agent"] / atmosphere.total_moles) * 100 + hydrogen = (atmosphere.gas["hydrogen"] / atmosphere.total_moles) * 100 + + if(!oxygen) + status.Add("No oxygen.") + else if((oxygen > 30) || (oxygen < 17)) + status.Add("Oxygen too [oxygen > 30 ? "high" : "low"].") + + + + if(phoron > 0.1) // Toxic even in small amounts. + status.Add("Phoron contamination.") + if(nitrousoxide > 0.1) // Probably slightly less dangerous but still. + status.Add("N2O contamination.") + if(hydrogen > 2.5) // Not too dangerous, but flammable. + status.Add("Hydrogen contamination.") + if(carbondioxide > 5) // Not as dangerous until very large amount is present. + status.Add("CO2 concentration high.") + + + if(returntext) + return jointext(status, " ") + else + return status.len diff --git a/code/modules/atmospherics/atmospherics.dm b/code/modules/atmospherics/atmospherics.dm new file mode 100644 index 00000000..5135b3a9 --- /dev/null +++ b/code/modules/atmospherics/atmospherics.dm @@ -0,0 +1,139 @@ +/* +Quick overview: + +Pipes combine to form pipelines +Pipelines and other atmospheric objects combine to form pipe_networks + Note: A single pipe_network represents a completely open space + +Pipes -> Pipelines +Pipelines + Other Objects -> Pipe network + +*/ +/obj/machinery/atmospherics + anchored = 1 + idle_power_usage = 0 + active_power_usage = 0 + power_channel = ENVIRON + var/nodealert = 0 + var/power_rating //the maximum amount of power the machine can use to do work, affects how powerful the machine is, in Watts + + plane = ABOVE_TURF_PLANE + layer = EXPOSED_PIPE_LAYER + + var/connect_types = CONNECT_TYPE_REGULAR + var/icon_connect_type = "" //"-supply" or "-scrubbers" + + var/initialize_directions = 0 + var/pipe_color + + var/global/datum/pipe_icon_manager/icon_manager + var/obj/machinery/atmospherics/node1 + var/obj/machinery/atmospherics/node2 + + var/atmos_initalized = FALSE + +/obj/machinery/atmospherics/New() + if(!icon_manager) + icon_manager = new() + + if(!pipe_color) + pipe_color = color + color = null + + if(!pipe_color_check(pipe_color)) + pipe_color = null + ..() + +/obj/machinery/atmospherics/proc/atmos_init() + atmos_initalized = TRUE + +/obj/machinery/atmospherics/hide(var/do_hide) + if(do_hide && level == 1) + plane = ABOVE_PLATING_PLANE + layer = PIPE_LAYER + else + reset_plane_and_layer() + +/obj/machinery/atmospherics/attackby(atom/A, mob/user as mob) + if(istype(A, /obj/item/device/pipe_painter)) + return + if(istype(A, /obj/item/device/analyzer)) + return + ..() + +/obj/machinery/atmospherics/proc/add_underlay(var/turf/T, var/obj/machinery/atmospherics/node, var/direction, var/icon_connect_type) + if(node) + if(!T.is_plating() && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe)) + //underlays += icon_manager.get_atmos_icon("underlay_down", direction, color_cache_name(node)) + underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type) + else + //underlays += icon_manager.get_atmos_icon("underlay_intact", direction, color_cache_name(node)) + underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type) + else + //underlays += icon_manager.get_atmos_icon("underlay_exposed", direction, pipe_color) + underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "exposed" + icon_connect_type) + +/obj/machinery/atmospherics/proc/update_underlays() + if(check_icon_cache()) + return 1 + else + return 0 + +obj/machinery/atmospherics/proc/check_connect_types(obj/machinery/atmospherics/atmos1, obj/machinery/atmospherics/atmos2) + return (atmos1.connect_types & atmos2.connect_types) + +/obj/machinery/atmospherics/proc/check_connect_types_construction(obj/machinery/atmospherics/atmos1, obj/item/pipe/pipe2) + return (atmos1.connect_types & pipe2.connect_types) + +/obj/machinery/atmospherics/proc/check_icon_cache(var/safety = 0) + if(!istype(icon_manager)) + if(!safety) //to prevent infinite loops + icon_manager = new() + check_icon_cache(1) + return 0 + + return 1 + +/obj/machinery/atmospherics/proc/color_cache_name(var/obj/machinery/atmospherics/node) + //Don't use this for standard pipes + if(!istype(node)) + return null + + return node.pipe_color + +/obj/machinery/atmospherics/Process() + last_flow_rate = 0 + last_power_draw = 0 + + build_network() + +/obj/machinery/atmospherics/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + // Check to see if should be added to network. Add self if so and adjust variables appropriately. + // Note don't forget to have neighbors look as well! + + return null + +/obj/machinery/atmospherics/proc/build_network() + // Called to build a network from this node + + return null + +/obj/machinery/atmospherics/proc/return_network(obj/machinery/atmospherics/reference) + // Returns pipe_network associated with connection to reference + // Notes: should create network if necessary + // Should never return null + + return null + +/obj/machinery/atmospherics/proc/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + // Used when two pipe_networks are combining + +/obj/machinery/atmospherics/proc/return_network_air(datum/network/reference) + // Return a list of gas_mixture(s) in the object + // associated with reference pipe_network for use in rebuilding the networks gases list + // Is permitted to return null + +/obj/machinery/atmospherics/proc/disconnect(obj/machinery/atmospherics/reference) + +/obj/machinery/atmospherics/update_icon() + return null \ No newline at end of file diff --git a/code/modules/atmospherics/components/binary_devices/binary_atmos_base.dm b/code/modules/atmospherics/components/binary_devices/binary_atmos_base.dm new file mode 100644 index 00000000..939cafc4 --- /dev/null +++ b/code/modules/atmospherics/components/binary_devices/binary_atmos_base.dm @@ -0,0 +1,134 @@ +obj/machinery/atmospherics/binary + dir = SOUTH + initialize_directions = SOUTH|NORTH + use_power = 1 + + var/datum/gas_mixture/air1 + var/datum/gas_mixture/air2 + + var/datum/pipe_network/network1 + var/datum/pipe_network/network2 + + New() + ..() + switch(dir) + if(NORTH) + initialize_directions = NORTH|SOUTH + if(SOUTH) + initialize_directions = NORTH|SOUTH + if(EAST) + initialize_directions = EAST|WEST + if(WEST) + initialize_directions = EAST|WEST + air1 = new + air2 = new + + air1.volume = 200 + air2.volume = 200 + +// Housekeeping and pipe network stuff below + network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(reference == node1) + network1 = new_network + + else if(reference == node2) + network2 = new_network + + if(new_network.normal_members.Find(src)) + return 0 + + new_network.normal_members += src + + return null + + atmos_init() + ..() + if(node1 && node2) return + + var/node2_connect = dir + var/node1_connect = turn(dir, 180) + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node1 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node2 = target + break + + update_icon() + update_underlays() + + build_network() + if(!network1 && node1) + network1 = new /datum/pipe_network() + network1.normal_members += src + network1.build_network(node1, src) + + if(!network2 && node2) + network2 = new /datum/pipe_network() + network2.normal_members += src + network2.build_network(node2, src) + + + return_network(obj/machinery/atmospherics/reference) + build_network() + + if(reference==node1) + return network1 + + if(reference==node2) + return network2 + + return null + + reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network1 == old_network) + network1 = new_network + if(network2 == old_network) + network2 = new_network + + return 1 + + return_network_air(datum/pipe_network/reference) + var/list/results = list() + + if(network1 == reference) + results += air1 + if(network2 == reference) + results += air2 + + return results + + disconnect(obj/machinery/atmospherics/reference) + if(reference==node1) + qdel(network1) + node1 = null + + else if(reference==node2) + qdel(network2) + node2 = null + + update_icon() + update_underlays() + + return null + +obj/machinery/atmospherics/binary/Destroy() + loc = null + + if(node1) + node1.disconnect(src) + qdel(network1) + if(node2) + node2.disconnect(src) + qdel(network2) + + node1 = null + node2 = null + + . = ..() diff --git a/code/modules/atmospherics/components/binary_devices/circulator.dm b/code/modules/atmospherics/components/binary_devices/circulator.dm new file mode 100644 index 00000000..e30b11d0 --- /dev/null +++ b/code/modules/atmospherics/components/binary_devices/circulator.dm @@ -0,0 +1,164 @@ +//node1, air1, network1 correspond to input +//node2, air2, network2 correspond to output + +/obj/machinery/atmospherics/binary/circulator + name = "circulator" + desc = "A gas circulator turbine and heat exchanger." + icon = 'icons/obj/pipes.dmi' + icon_state = "circ-off" + anchored = 0 + + var/kinetic_efficiency = 0.04 //combined kinetic and kinetic-to-electric efficiency + var/volume_ratio = 0.2 + + var/recent_moles_transferred = 0 + var/last_heat_capacity = 0 + var/last_temperature = 0 + var/last_pressure_delta = 0 + var/last_worldtime_transfer = 0 + var/last_stored_energy_transferred = 0 + var/volume_capacity_used = 0 + var/stored_energy = 0 + var/inverted = 0 + density = 1 + +/obj/machinery/atmospherics/binary/circulator/New() + ..() + desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]." + air1.volume = 400 + +/obj/machinery/atmospherics/binary/circulator/proc/return_transfer_air() + var/datum/gas_mixture/removed + if(anchored && !(stat&BROKEN) && network1) + var/input_starting_pressure = air1.return_pressure() + var/output_starting_pressure = air2.return_pressure() + last_pressure_delta = max(input_starting_pressure - output_starting_pressure - 5, 0) + + //only circulate air if there is a pressure difference (plus 5kPa kinetic, 10kPa static friction) + if(air1.temperature > 0 && last_pressure_delta > 5) + + //Calculate necessary moles to transfer using PV = nRT + recent_moles_transferred = (last_pressure_delta*network1.volume/(air1.temperature * R_IDEAL_GAS_EQUATION))/3 //uses the volume of the whole network, not just itself + volume_capacity_used = min( (last_pressure_delta*network1.volume/3)/(input_starting_pressure*air1.volume) , 1) //how much of the gas in the input air volume is consumed + + //Calculate energy generated from kinetic turbine + stored_energy += 1/ADIABATIC_EXPONENT * min(last_pressure_delta * network1.volume , input_starting_pressure*air1.volume) * (1 - volume_ratio**ADIABATIC_EXPONENT) * kinetic_efficiency + + //Actually transfer the gas + removed = air1.remove(recent_moles_transferred) + if(removed) + last_heat_capacity = removed.heat_capacity() + last_temperature = removed.temperature + + //Update the gas networks. + network1.update = 1 + + last_worldtime_transfer = world.time + else + recent_moles_transferred = 0 + + update_icon() + return removed + +/obj/machinery/atmospherics/binary/circulator/proc/return_stored_energy() + last_stored_energy_transferred = stored_energy + stored_energy = 0 + return last_stored_energy_transferred + +/obj/machinery/atmospherics/binary/circulator/Process() + ..() + + if(last_worldtime_transfer < world.time - 50) + recent_moles_transferred = 0 + update_icon() + +/obj/machinery/atmospherics/binary/circulator/update_icon() + if(stat & (BROKEN|NOPOWER) || !anchored) + icon_state = "circ-p" + if(inverted) + icon_state = "circi-p" + else if(last_pressure_delta > 0 && recent_moles_transferred > 0) + if(last_pressure_delta > 5*ONE_ATMOSPHERE) + icon_state = "circ-run" + if(inverted) + icon_state = "circi-run" + else + icon_state = "circ-slow" + if(inverted) + icon_state = "circi-slow" + else + icon_state = "circ-off" + if(inverted) + icon_state = "circi-off" + return 1 + +/obj/machinery/atmospherics/binary/circulator/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWrench(W)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + anchored = !anchored + user.visible_message("[user.name] [anchored ? "secures" : "unsecures"] the bolts holding [src.name] to the floor.", \ + "You [anchored ? "secure" : "unsecure"] the bolts holding [src] to the floor.", \ + "You hear a ratchet") + + if(anchored) + if(dir & (NORTH|SOUTH)) + initialize_directions = NORTH|SOUTH + else if(dir & (EAST|WEST)) + initialize_directions = EAST|WEST + + atmos_init() + build_network() + if (node1) + node1.atmos_init() + node1.build_network() + if (node2) + node2.atmos_init() + node2.build_network() + else + if(node1) + node1.disconnect(src) + qdel(network1) + if(node2) + node2.disconnect(src) + qdel(network2) + + node1 = null + node2 = null + + else + ..() + +/obj/machinery/atmospherics/binary/circulator/proc/rotate_clockwise() + set category = "Object" + set name = "Rotate Circulator (Clockwise)" + + if (usr.stat || usr.restrained() || anchored) + return + + src.set_dir(turn(src.dir, 90)) + desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]." + +/obj/machinery/atmospherics/binary/circulator/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + rotate_clockwise() + + +/obj/machinery/atmospherics/binary/circulator/verb/rotate_anticlockwise() + set category = "Object" + set name = "Rotate Circulator (Counterclockwise)" + set src in view(1) + + if (usr.stat || usr.restrained() || anchored) + return + + src.set_dir(turn(src.dir, -90)) + desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]." + +/obj/machinery/atmospherics/binary/circulator/AltClick(var/mob/user) + if(!anchored) + inverted = !inverted + update_icon() + +/obj/machinery/atmospherics/binary/circulator/inverted + icon_state = "circi-off" + inverted = 1 diff --git a/code/modules/atmospherics/components/binary_devices/dp_vent_pump.dm b/code/modules/atmospherics/components/binary_devices/dp_vent_pump.dm new file mode 100644 index 00000000..4121e4d1 --- /dev/null +++ b/code/modules/atmospherics/components/binary_devices/dp_vent_pump.dm @@ -0,0 +1,262 @@ +#define DEFAULT_PRESSURE_DELTA 10000 + +#define EXTERNAL_PRESSURE_BOUND ONE_ATMOSPHERE +#define INTERNAL_PRESSURE_BOUND 0 +#define PRESSURE_CHECKS 1 + +#define PRESSURE_CHECK_EXTERNAL 1 +#define PRESSURE_CHECK_INPUT 2 +#define PRESSURE_CHECK_OUTPUT 4 + +/obj/machinery/atmospherics/binary/dp_vent_pump + icon = 'icons/atmos/vent_pump.dmi' + icon_state = "map_dp_vent" + + //node2 is output port + //node1 is input port + + name = "Dual Port Air Vent" + desc = "Has a valve and pump attached to it. There are two ports." + + level = 1 + + use_power = 0 + idle_power_usage = 150 //internal circuitry, friction losses and stuff + power_rating = 7500 //7500 W ~ 10 HP + + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER //connects to regular, supply and scrubbers pipes + + var/pump_direction = 1 //0 = siphoning, 1 = releasing + + var/external_pressure_bound = EXTERNAL_PRESSURE_BOUND + var/input_pressure_min = INTERNAL_PRESSURE_BOUND + var/output_pressure_max = DEFAULT_PRESSURE_DELTA + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + + var/pressure_checks = PRESSURE_CHECK_EXTERNAL + //1: Do not pass external_pressure_bound + //2: Do not pass input_pressure_min + //4: Do not pass output_pressure_max + +/obj/machinery/atmospherics/binary/dp_vent_pump/New() + ..() + air1.volume = ATMOS_DEFAULT_VOLUME_PUMP + air2.volume = ATMOS_DEFAULT_VOLUME_PUMP + icon = null + +/obj/machinery/atmospherics/binary/dp_vent_pump/high_volume + name = "Large Dual Port Air Vent" + +/obj/machinery/atmospherics/binary/dp_vent_pump/high_volume/New() + ..() + air1.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800 + air2.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800 + +/obj/machinery/atmospherics/binary/dp_vent_pump/update_icon(var/safety = 0) + if(!check_icon_cache()) + return + + overlays.Cut() + + var/vent_icon = "vent" + + var/turf/T = get_turf(src) + if(!istype(T)) + return + + if(!T.is_plating() && node1 && node2 && node1.level == 1 && node2.level == 1 && istype(node1, /obj/machinery/atmospherics/pipe) && istype(node2, /obj/machinery/atmospherics/pipe)) + vent_icon += "h" + + if(!powered()) + vent_icon += "off" + else + vent_icon += "[use_power ? "[pump_direction ? "out" : "in"]" : "off"]" + + overlays += icon_manager.get_atmos_icon("device", , , vent_icon) + +/obj/machinery/atmospherics/binary/dp_vent_pump/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + if(!T.is_plating() && node1 && node2 && node1.level == 1 && node2.level == 1 && istype(node1, /obj/machinery/atmospherics/pipe) && istype(node2, /obj/machinery/atmospherics/pipe)) + return + else + if (node1) + add_underlay(T, node1, turn(dir, -180), node1.icon_connect_type) + else + add_underlay(T, node1, turn(dir, -180)) + if (node2) + add_underlay(T, node2, dir, node2.icon_connect_type) + else + add_underlay(T, node2, dir) + +/obj/machinery/atmospherics/binary/dp_vent_pump/hide(var/i) + update_icon() + update_underlays() + +/obj/machinery/atmospherics/binary/dp_vent_pump/Process() + ..() + + last_power_draw = 0 + last_flow_rate = 0 + + if(stat & (NOPOWER|BROKEN) || !use_power) + return 0 + + var/datum/gas_mixture/environment = loc.return_air() + + var/power_draw = -1 + + //Figure out the target pressure difference + var/pressure_delta = get_pressure_delta(environment) + + if(pressure_delta > 0.5) + if(pump_direction) //internal -> external + if (node1 && (environment.temperature || air1.temperature)) + var/transfer_moles = calculate_transfer_moles(air1, environment, pressure_delta) + power_draw = pump_gas(src, air1, environment, transfer_moles, power_rating) + + if(power_draw >= 0 && network1) + network1.update = 1 + else //external -> internal + if (node2 && (environment.temperature || air2.temperature)) + var/transfer_moles = calculate_transfer_moles(environment, air2, pressure_delta, (network2)? network2.volume : 0) + + //limit flow rate from turfs + transfer_moles = min(transfer_moles, environment.total_moles*air2.volume/environment.volume) //group_multiplier gets divided out here + power_draw = pump_gas(src, environment, air2, transfer_moles, power_rating) + + if(power_draw >= 0 && network2) + network2.update = 1 + + if (power_draw >= 0) + last_power_draw = power_draw + use_power(power_draw) + + return 1 + +/obj/machinery/atmospherics/binary/dp_vent_pump/proc/get_pressure_delta(datum/gas_mixture/environment) + var/pressure_delta = DEFAULT_PRESSURE_DELTA + var/environment_pressure = environment.return_pressure() + + if(pump_direction) //internal -> external + if(pressure_checks & PRESSURE_CHECK_EXTERNAL) + pressure_delta = min(pressure_delta, external_pressure_bound - environment_pressure) //increasing the pressure here + if(pressure_checks & PRESSURE_CHECK_INPUT) + pressure_delta = min(pressure_delta, air1.return_pressure() - input_pressure_min) //decreasing the pressure here + else //external -> internal + if(pressure_checks & PRESSURE_CHECK_EXTERNAL) + pressure_delta = min(pressure_delta, environment_pressure - external_pressure_bound) //decreasing the pressure here + if(pressure_checks & PRESSURE_CHECK_OUTPUT) + pressure_delta = min(pressure_delta, output_pressure_max - air2.return_pressure()) //increasing the pressure here + + return pressure_delta + + +//Radio remote control + +/obj/machinery/atmospherics/binary/dp_vent_pump/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA) + +/obj/machinery/atmospherics/binary/dp_vent_pump/proc/broadcast_status() + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data = list( + "tag" = id, + "device" = "ADVP", + "power" = use_power, + "direction" = pump_direction?("release"):("siphon"), + "checks" = pressure_checks, + "input" = input_pressure_min, + "output" = output_pressure_max, + "external" = external_pressure_bound, + "sigtype" = "status" + ) + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + + return 1 + +/obj/machinery/atmospherics/binary/dp_vent_pump/Initialize() + . = ..() + if(frequency) + set_frequency(frequency) + +/obj/machinery/atmospherics/binary/dp_vent_pump/examine(mob/user) + if(..(user, 1)) + to_chat(user, "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W") + +/obj/machinery/atmospherics/binary/dp_vent_pump/receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) + return 0 + if(signal.data["power"]) + use_power = text2num(signal.data["power"]) + + if(signal.data["power_toggle"]) + use_power = !use_power + + if(signal.data["direction"]) + pump_direction = text2num(signal.data["direction"]) + + if(signal.data["checks"]) + pressure_checks = text2num(signal.data["checks"]) + + if(signal.data["purge"]) + pressure_checks &= ~1 + pump_direction = 0 + + if(signal.data["stabalize"]) + pressure_checks |= 1 + pump_direction = 1 + + if(signal.data["set_input_pressure"]) + input_pressure_min = between( + 0, + text2num(signal.data["set_input_pressure"]), + ONE_ATMOSPHERE*50 + ) + + if(signal.data["set_output_pressure"]) + output_pressure_max = between( + 0, + text2num(signal.data["set_output_pressure"]), + ONE_ATMOSPHERE*50 + ) + + if(signal.data["set_external_pressure"]) + external_pressure_bound = between( + 0, + text2num(signal.data["set_external_pressure"]), + ONE_ATMOSPHERE*50 + ) + + if(signal.data["status"]) + spawn(2) + broadcast_status() + return //do not update_icon + + spawn(2) + broadcast_status() + update_icon() + +#undef DEFAULT_PRESSURE_DELTA + +#undef EXTERNAL_PRESSURE_BOUND +#undef INTERNAL_PRESSURE_BOUND +#undef PRESSURE_CHECKS + +#undef PRESSURE_CHECK_EXTERNAL +#undef PRESSURE_CHECK_INPUT +#undef PRESSURE_CHECK_OUTPUT diff --git a/code/modules/atmospherics/components/binary_devices/oxyregenerator.dm b/code/modules/atmospherics/components/binary_devices/oxyregenerator.dm new file mode 100644 index 00000000..f0894aa0 --- /dev/null +++ b/code/modules/atmospherics/components/binary_devices/oxyregenerator.dm @@ -0,0 +1,208 @@ +/obj/machinery/atmospherics/binary/oxyregenerator + name ="oxygen regenerator" + desc = "A machine for breaking bonds in carbon dioxide and releasing pure oxygen." + icon = 'icons/atmos/oxyregenerator.dmi' + icon_state = "off" + level = 1 + density = 1 + use_power = 0 + idle_power_usage = 200 //internal circuitry, friction losses and stuff + power_rating = 10000 + var/target_pressure = 10*ONE_ATMOSPHERE + var/id = null + var/power_setting = 1 //power consumption setting, 1 through five + var/carbon_stored = 0 + var/carbon_efficiency = 0.5 + var/intake_power_efficiency = 1 + var/const/carbon_moles_per_piece = 50 //One 12g per mole * 50 = 600 g chunk of coal + var/phase = "filling"//"filling", "processing", "releasing" + var/datum/gas_mixture/inner_tank = new + var/tank_volume = 400//Litres + +/obj/machinery/atmospherics/binary/oxyregenerator/New() + ..() + inner_tank.volume = tank_volume + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/oxyregenerator(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src)//Takes CO2 + component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)//Breaks bond + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)//Stores carbon + RefreshParts() + +/obj/machinery/atmospherics/binary/oxyregenerator/RefreshParts() + for(var/obj/item/weapon/stock_parts/P in component_parts) + if(istype(P, /obj/item/weapon/stock_parts/matter_bin)) + carbon_efficiency += 0.25 * (P.rating-1) //plus 25% per stock item rank + if(istype(P, /obj/item/weapon/stock_parts/manipulator)) + intake_power_efficiency -= 0.1 * (P.rating-1) //10% better intake power efficiency per stock item rank + if(istype(P, /obj/item/weapon/stock_parts/micro_laser)) + power_rating -= power_rating * 0.05 * (P.rating-1) //5% better power efficiency per stock item rank + +/obj/machinery/atmospherics/binary/oxyregenerator/examine(user) + ..() + to_chat(user,"Its outlet port is to the [dir2text(dir)]") + +/obj/machinery/atmospherics/binary/oxyregenerator/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(default_deconstruction_screwdriver(user, O)) + return + if(default_deconstruction_crowbar(user, O)) + return + if(default_part_replacement(user, O)) + return + if(isWrench(O)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + anchored = !anchored + user.visible_message("[user.name] [anchored ? "secures" : "unsecures"] the bolts holding [src.name] to the floor.", \ + "You [anchored ? "secure" : "unsecure"] the bolts holding [src] to the floor.", \ + "You hear a ratchet") + + if(anchored) + if(dir & (NORTH|SOUTH)) + initialize_directions = NORTH|SOUTH + else if(dir & (EAST|WEST)) + initialize_directions = EAST|WEST + + atmos_init() + build_network() + if (node1) + node1.atmos_init() + node1.build_network() + if (node2) + node2.atmos_init() + node2.build_network() + else + if(node1) + node1.disconnect(src) + qdel(network1) + if(node2) + node2.disconnect(src) + qdel(network2) + + node1 = null + node2 = null + +/obj/machinery/atmospherics/binary/oxyregenerator/proc/rotate_clockwise() + set category = "Object" + set name = "Rotate (Clockwise)" + + if (usr.incapacitated() || anchored) + return + + src.set_dir(turn(src.dir, -90)) + +/obj/machinery/atmospherics/binary/oxyregenerator/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + rotate_clockwise() + +/obj/machinery/atmospherics/binary/oxyregenerator/verb/rotate_anticlockwise() + set category = "Object" + set name = "Rotate (Counterclockwise)" + set src in view(1) + + if (usr.incapacitated() || anchored) + return + + src.set_dir(turn(src.dir, 90)) + +/obj/machinery/atmospherics/binary/oxyregenerator/Process(var/delay) + if((stat & (NOPOWER|BROKEN)) || !use_power) + return + + var/power_draw = -1 + last_power_draw = 0 + //TODO Add overlay with F-P-R letter to display current state + if (phase == "filling")//filling tank + var/pressure_delta = target_pressure - inner_tank.return_pressure() + if (pressure_delta > 0.01 && air1.temperature > 0) + var/transfer_moles = calculate_transfer_moles(air1, inner_tank, pressure_delta) + power_draw = pump_gas(src, air1, inner_tank, transfer_moles, power_rating*power_setting) * intake_power_efficiency + if (power_draw >= 0) + last_power_draw = power_draw + use_power(power_draw) + if(network1) + network1.update = 1 + if (air1.return_pressure() < 0.1 * ONE_ATMOSPHERE || inner_tank.return_pressure() >= 10 * ONE_ATMOSPHERE)//if pipe is good as empty or tank is full + phase = "processing" + + if (phase == "processing")//processing CO2 in tank + if (inner_tank.gas["carbon_dioxide"]) + var/co2_intake = between(0, inner_tank.gas["carbon_dioxide"], power_setting*delay/10) + last_flow_rate = co2_intake + inner_tank.adjust_gas("carbon_dioxide", -co2_intake, 1) + var/datum/gas_mixture/new_oxygen = new + new_oxygen.adjust_gas("oxygen", co2_intake) + new_oxygen.temperature = T20C+30 //it's sort of hot after molecular bond breaking + inner_tank.merge(new_oxygen) + carbon_stored += co2_intake * carbon_efficiency + while (carbon_stored >= carbon_moles_per_piece) + carbon_stored -= carbon_moles_per_piece + var/atom/movable/product = new/obj/item/weapon/ore/coal + product.dropInto(loc) + power_draw = power_rating * co2_intake + last_power_draw = power_draw + use_power(power_draw) + else + phase = "releasing" + + if (phase == "releasing")//releasing processed gas mix + power_draw = -1 + var/pressure_delta = target_pressure - air2.return_pressure() + if (pressure_delta > 0.01 && inner_tank.temperature > 0) + var/transfer_moles = calculate_transfer_moles(inner_tank, air2, pressure_delta, (network2)? network2.volume : 0) + power_draw = pump_gas(src, inner_tank, air2, transfer_moles, power_rating*power_setting) + if (power_draw >= 0) + last_power_draw = power_draw + use_power(power_draw) + if(network2) + network2.update = 1 + else//can't push outside harder than target pressure. Device is not intended to be used as a pump after all + phase = "filling" + if (inner_tank.return_pressure() <= 0) + phase = "filling" + +/obj/machinery/atmospherics/binary/oxyregenerator/update_icon() + if(!powered()) + icon_state = "off" + else + icon_state = "[use_power ? "on" : "off"]" + +/obj/machinery/atmospherics/binary/oxyregenerator/attack_ai(mob/user as mob) + ui_interact(user) + +/obj/machinery/atmospherics/binary/oxyregenerator/attack_hand(mob/user as mob) + ui_interact(user) + +/obj/machinery/atmospherics/binary/oxyregenerator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + data["on"] = use_power ? 1 : 0 + data["powerSetting"] = power_setting + data["gasProcessed"] = last_flow_rate + data["air1Pressure"] = round(air1.return_pressure()) + data["air2Pressure"] = round(air2.return_pressure()) + data["tankPressure"] = round(inner_tank.return_pressure()) + data["targetPressure"] = round(target_pressure) + data["phase"] = phase + if (inner_tank.total_moles > 0) + data["co2"] = round(100 * inner_tank.gas["carbon_dioxide"]/inner_tank.total_moles) + data["o2"] = round(100 * inner_tank.gas["oxygen"]/inner_tank.total_moles) + else + data["co2"] = 0 + data["o2"] = 0 + // update the ui if it exists, returns null if no ui is passed/found + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "oxyregenerator.tmpl", "Oxygen Regeneration System", 440, 300) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/atmospherics/binary/oxyregenerator/Topic(href, href_list) + if(..()) + return 1 + if(href_list["toggleStatus"]) + use_power = !use_power + update_icon() + return 1 + if(href_list["setPower"]) //setting power to 0 is redundant anyways + power_setting = between(1, text2num(href_list["setPower"]), 5) + return 1 diff --git a/code/modules/atmospherics/components/binary_devices/passive_gate.dm b/code/modules/atmospherics/components/binary_devices/passive_gate.dm new file mode 100644 index 00000000..ad14808c --- /dev/null +++ b/code/modules/atmospherics/components/binary_devices/passive_gate.dm @@ -0,0 +1,267 @@ +#define REGULATE_NONE 0 +#define REGULATE_INPUT 1 //shuts off when input side is below the target pressure +#define REGULATE_OUTPUT 2 //shuts off when output side is above the target pressure + +/obj/machinery/atmospherics/binary/passive_gate + icon = 'icons/atmos/passive_gate.dmi' + icon_state = "map_off" + level = 1 + + name = "pressure regulator" + desc = "A one-way air valve that can be used to regulate input or output pressure, and flow rate. Does not require power." + + use_power = 0 + interact_offline = 1 + var/unlocked = 0 //If 0, then the valve is locked closed, otherwise it is open(-able, it's a one-way valve so it closes if gas would flow backwards). + var/target_pressure = ONE_ATMOSPHERE + var/max_pressure_setting = MAX_PUMP_PRESSURE + var/set_flow_rate = ATMOS_DEFAULT_VOLUME_PUMP * 2.5 + var/regulate_mode = REGULATE_OUTPUT + + var/flowing = 0 //for icons - becomes zero if the valve closes itself due to regulation mode + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + +/obj/machinery/atmospherics/binary/passive_gate/on + unlocked = 1 + icon_state = "map_on" + +/obj/machinery/atmospherics/binary/passive_gate/New() + ..() + air1.volume = ATMOS_DEFAULT_VOLUME_PUMP * 2.5 + air2.volume = ATMOS_DEFAULT_VOLUME_PUMP * 2.5 + +/obj/machinery/atmospherics/binary/passive_gate/update_icon() + icon_state = (unlocked && flowing)? "on" : "off" + +/obj/machinery/atmospherics/binary/passive_gate/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + add_underlay(T, node1, turn(dir, 180)) + add_underlay(T, node2, dir) + +/obj/machinery/atmospherics/binary/passive_gate/hide(var/i) + update_underlays() + +/obj/machinery/atmospherics/binary/passive_gate/Process() + ..() + + last_flow_rate = 0 + + if(!unlocked) + return 0 + + var/output_starting_pressure = air2.return_pressure() + var/input_starting_pressure = air1.return_pressure() + + var/pressure_delta + switch (regulate_mode) + if (REGULATE_INPUT) + pressure_delta = input_starting_pressure - target_pressure + if (REGULATE_OUTPUT) + pressure_delta = target_pressure - output_starting_pressure + + //-1 if pump_gas() did not move any gas, >= 0 otherwise + var/returnval = -1 + if((regulate_mode == REGULATE_NONE || pressure_delta > 0.01) && (air1.temperature > 0 || air2.temperature > 0)) //since it's basically a valve, it makes sense to check both temperatures + flowing = 1 + + //flow rate limit + var/transfer_moles = (set_flow_rate/air1.volume)*air1.total_moles + + //Figure out how much gas to transfer to meet the target pressure. + switch (regulate_mode) + if (REGULATE_INPUT) + transfer_moles = min(transfer_moles, calculate_transfer_moles(air2, air1, pressure_delta, (network1)? network1.volume : 0)) + if (REGULATE_OUTPUT) + transfer_moles = min(transfer_moles, calculate_transfer_moles(air1, air2, pressure_delta, (network2)? network2.volume : 0)) + + //pump_gas() will return a negative number if no flow occurred + returnval = pump_gas_passive(src, air1, air2, transfer_moles) + + if (returnval >= 0) + if(network1) + network1.update = 1 + + if(network2) + network2.update = 1 + + if (last_flow_rate) + flowing = 1 + + update_icon() + + +//Radio remote control + +/obj/machinery/atmospherics/binary/passive_gate/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA) + +/obj/machinery/atmospherics/binary/passive_gate/proc/broadcast_status() + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data = list( + "tag" = id, + "device" = "AGP", + "power" = unlocked, + "target_output" = target_pressure, + "regulate_mode" = regulate_mode, + "set_flow_rate" = set_flow_rate, + "sigtype" = "status" + ) + + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + + return 1 + +/obj/machinery/atmospherics/binary/passive_gate/Initialize() + . = ..() + if(frequency) + set_frequency(frequency) + +/obj/machinery/atmospherics/binary/passive_gate/receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) + return 0 + + if("power" in signal.data) + unlocked = text2num(signal.data["power"]) + + if("power_toggle" in signal.data) + unlocked = !unlocked + + if("set_target_pressure" in signal.data) + target_pressure = between( + 0, + text2num(signal.data["set_target_pressure"]), + max_pressure_setting + ) + + if("set_regulate_mode" in signal.data) + regulate_mode = text2num(signal.data["set_regulate_mode"]) + + if("set_flow_rate" in signal.data) + regulate_mode = text2num(signal.data["set_flow_rate"]) + + if("status" in signal.data) + spawn(2) + broadcast_status() + return //do not update_icon + + spawn(2) + broadcast_status() + update_icon() + return + +/obj/machinery/atmospherics/binary/passive_gate/attack_hand(user as mob) + if(..()) + return + src.add_fingerprint(usr) + if(!src.allowed(user)) + to_chat(user, "Access denied.") + return + usr.set_machine(src) + ui_interact(user) + return + +/obj/machinery/atmospherics/binary/passive_gate/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(stat & (BROKEN|NOPOWER)) + return + + // this is the data which will be sent to the ui + var/data[0] + + data = list( + "on" = unlocked, + "pressure_set" = round(target_pressure*100), //Nano UI can't handle rounded non-integers, apparently. + "max_pressure" = max_pressure_setting, + "input_pressure" = round(air1.return_pressure()*100), + "output_pressure" = round(air2.return_pressure()*100), + "regulate_mode" = regulate_mode, + "set_flow_rate" = round(set_flow_rate*10), + "last_flow_rate" = round(last_flow_rate*10), + ) + + // update the ui if it exists, returns null if no ui is passed/found + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "pressure_regulator.tmpl", name, 470, 370) + ui.set_initial_data(data) // when the ui is first opened this is the data it will use + ui.open() // open the new ui window + ui.set_auto_update(1) // auto update every Master Controller tick + + +/obj/machinery/atmospherics/binary/passive_gate/Topic(href,href_list) + if(..()) return 1 + + if(href_list["toggle_valve"]) + unlocked = !unlocked + + if(href_list["regulate_mode"]) + switch(href_list["regulate_mode"]) + if ("off") regulate_mode = REGULATE_NONE + if ("input") regulate_mode = REGULATE_INPUT + if ("output") regulate_mode = REGULATE_OUTPUT + + switch(href_list["set_press"]) + if ("min") + target_pressure = 0 + if ("max") + target_pressure = max_pressure_setting + if ("set") + var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure Control",src.target_pressure) as num + src.target_pressure = between(0, new_pressure, max_pressure_setting) + + switch(href_list["set_flow_rate"]) + if ("min") + set_flow_rate = 0 + if ("max") + set_flow_rate = air1.volume + if ("set") + var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[air1.volume]kPa)","Flow Rate Control",src.set_flow_rate) as num + src.set_flow_rate = between(0, new_flow_rate, air1.volume) + + usr.set_machine(src) //Is this even needed with NanoUI? + src.update_icon() + src.add_fingerprint(usr) + return + +/obj/machinery/atmospherics/binary/passive_gate/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(!isWrench(W)) + return ..() + if (unlocked) + to_chat(user, "You cannot unwrench \the [src], turn it off first.") + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + to_chat(user, "You cannot unwrench \the [src], it too exerted due to internal pressure.") + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to unfasten \the [src]...") + if (do_after(user, 40, src)) + user.visible_message( \ + "\The [user] unfastens \the [src].", \ + "You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe(loc, make_from=src) + qdel(src) + +#undef REGULATE_NONE +#undef REGULATE_INPUT +#undef REGULATE_OUTPUT diff --git a/code/modules/atmospherics/components/binary_devices/pipeturbine.dm b/code/modules/atmospherics/components/binary_devices/pipeturbine.dm new file mode 100644 index 00000000..6a051cfe --- /dev/null +++ b/code/modules/atmospherics/components/binary_devices/pipeturbine.dm @@ -0,0 +1,284 @@ +/obj/machinery/atmospherics/pipeturbine + name = "turbine" + desc = "A gas turbine. Converting pressure into energy since 1884." + icon = 'icons/obj/pipeturbine.dmi' + icon_state = "turbine" + anchored = 0 + density = 1 + + var/efficiency = 0.4 + var/kin_energy = 0 + var/datum/gas_mixture/air_in = new + var/datum/gas_mixture/air_out = new + var/volume_ratio = 0.2 + var/kin_loss = 0.001 + + var/dP = 0 + + var/datum/pipe_network/network1 + var/datum/pipe_network/network2 + + New() + ..() + air_in.volume = 200 + air_out.volume = 800 + volume_ratio = air_in.volume / (air_in.volume + air_out.volume) + switch(dir) + if(NORTH) + initialize_directions = EAST|WEST + if(SOUTH) + initialize_directions = EAST|WEST + if(EAST) + initialize_directions = NORTH|SOUTH + if(WEST) + initialize_directions = NORTH|SOUTH + + Destroy() + loc = null + + if(node1) + node1.disconnect(src) + QDEL_NULL(network1) + if(node2) + node2.disconnect(src) + QDEL_NULL(network2) + + node1 = null + node2 = null + + . = ..() + + Process() + ..() + if(anchored && !(stat&BROKEN)) + kin_energy *= 1 - kin_loss + dP = max(air_in.return_pressure() - air_out.return_pressure(), 0) + if(dP > 10) + kin_energy += 1/ADIABATIC_EXPONENT * dP * air_in.volume * (1 - volume_ratio**ADIABATIC_EXPONENT) * efficiency + air_in.temperature *= volume_ratio**ADIABATIC_EXPONENT + + var/datum/gas_mixture/air_all = new + air_all.volume = air_in.volume + air_out.volume + air_all.merge(air_in.remove_ratio(1)) + air_all.merge(air_out.remove_ratio(1)) + + air_in.merge(air_all.remove(volume_ratio)) + air_out.merge(air_all) + + update_icon() + + if (network1) + network1.update = 1 + if (network2) + network2.update = 1 + + update_icon() + overlays.Cut() + if (dP > 10) + overlays += image('icons/obj/pipeturbine.dmi', "moto-turb") + if (kin_energy > 100000) + overlays += image('icons/obj/pipeturbine.dmi', "low-turb") + if (kin_energy > 500000) + overlays += image('icons/obj/pipeturbine.dmi', "med-turb") + if (kin_energy > 1000000) + overlays += image('icons/obj/pipeturbine.dmi', "hi-turb") + + attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWrench(W)) + anchored = !anchored + to_chat(user, "You [anchored ? "secure" : "unsecure"] the bolts holding \the [src] to the floor.") + + if(anchored) + if(dir & (NORTH|SOUTH)) + initialize_directions = EAST|WEST + else if(dir & (EAST|WEST)) + initialize_directions = NORTH|SOUTH + + atmos_init() + build_network() + if (node1) + node1.atmos_init() + node1.build_network() + if (node2) + node2.atmos_init() + node2.build_network() + else + if(node1) + node1.disconnect(src) + qdel(network1) + if(node2) + node2.disconnect(src) + qdel(network2) + + node1 = null + node2 = null + + else + ..() + + verb/rotate_clockwise() + set category = "Object" + set name = "Rotate Circulator (Clockwise)" + set src in view(1) + + if (usr.stat || usr.restrained() || anchored) + return + + src.set_dir(turn(src.dir, -90)) + + + verb/rotate_anticlockwise() + set category = "Object" + set name = "Rotate Circulator (Counterclockwise)" + set src in view(1) + + if (usr.stat || usr.restrained() || anchored) + return + + src.set_dir(turn(src.dir, 90)) + +//Goddamn copypaste from binary base class because atmospherics machinery API is not damn flexible + network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(reference == node1) + network1 = new_network + + else if(reference == node2) + network2 = new_network + + if(new_network.normal_members.Find(src)) + return 0 + + new_network.normal_members += src + + return null + + atmos_init() + ..() + if(node1 && node2) return + + var/node2_connect = turn(dir, -90) + var/node1_connect = turn(dir, 90) + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect)) + if(target.initialize_directions & get_dir(target,src)) + node2 = target + break + + build_network() + if(!network1 && node1) + network1 = new /datum/pipe_network() + network1.normal_members += src + network1.build_network(node1, src) + + if(!network2 && node2) + network2 = new /datum/pipe_network() + network2.normal_members += src + network2.build_network(node2, src) + + + return_network(obj/machinery/atmospherics/reference) + build_network() + + if(reference==node1) + return network1 + + if(reference==node2) + return network2 + + return null + + reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network1 == old_network) + network1 = new_network + if(network2 == old_network) + network2 = new_network + + return 1 + + return_network_air(datum/pipe_network/reference) + var/list/results = list() + + if(network1 == reference) + results += air_in + if(network2 == reference) + results += air_out + + return results + + disconnect(obj/machinery/atmospherics/reference) + if(reference==node1) + qdel(network1) + node1 = null + + else if(reference==node2) + qdel(network2) + node2 = null + + return null + + +/obj/machinery/power/turbinemotor + name = "motor" + desc = "Electrogenerator. Converts rotation into power." + icon = 'icons/obj/pipeturbine.dmi' + icon_state = "motor" + anchored = 0 + density = 1 + + var/kin_to_el_ratio = 0.1 //How much kinetic energy will be taken from turbine and converted into electricity + var/obj/machinery/atmospherics/pipeturbine/turbine + + New() + ..() + spawn(1) + updateConnection() + + proc/updateConnection() + turbine = null + if(src.loc && anchored) + turbine = locate(/obj/machinery/atmospherics/pipeturbine) in get_step(src,dir) + if (turbine.stat & (BROKEN) || !turbine.anchored || turn(turbine.dir,180) != dir) + turbine = null + + attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/wrench)) + anchored = !anchored + turbine = null + to_chat(user, "You [anchored ? "secure" : "unsecure"] the bolts holding \the [src] to the floor.") + updateConnection() + else + ..() + + verb/rotate_clock() + set category = "Object" + set name = "Rotate Motor Clockwise" + set src in view(1) + + if (usr.stat || usr.restrained() || anchored) + return + + src.set_dir(turn(src.dir, -90)) + + verb/rotate_anticlock() + set category = "Object" + set name = "Rotate Motor Counterclockwise" + set src in view(1) + + if (usr.stat || usr.restrained() || anchored) + return + + src.set_dir(turn(src.dir, 90)) + +/obj/machinery/power/turbinemotor/Process() + updateConnection() + if(!turbine || !anchored || stat & (BROKEN)) + return + + var/power_generated = kin_to_el_ratio * turbine.kin_energy + turbine.kin_energy -= power_generated + add_avail(power_generated) diff --git a/code/modules/atmospherics/components/binary_devices/pump.dm b/code/modules/atmospherics/components/binary_devices/pump.dm new file mode 100644 index 00000000..f429b63b --- /dev/null +++ b/code/modules/atmospherics/components/binary_devices/pump.dm @@ -0,0 +1,237 @@ +/* +Every cycle, the pump uses the air in air_in to try and make air_out the perfect pressure. + +node1, air1, network1 correspond to input +node2, air2, network2 correspond to output + +Thus, the two variables affect pump operation are set in New(): + air1.volume + This is the volume of gas available to the pump that may be transfered to the output + air2.volume + Higher quantities of this cause more air to be perfected later + but overall network volume is also increased as this increases... +*/ + +/obj/machinery/atmospherics/binary/pump + icon = 'icons/atmos/pump.dmi' + icon_state = "map_off" + level = 1 + + name = "gas pump" + desc = "A pump." + + var/target_pressure = ONE_ATMOSPHERE + + //var/max_volume_transfer = 10000 + + use_power = 0 + idle_power_usage = 150 //internal circuitry, friction losses and stuff + power_rating = 7500 //7500 W ~ 10 HP + + var/max_pressure_setting = MAX_PUMP_PRESSURE + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + +/obj/machinery/atmospherics/binary/pump/New() + ..() + air1.volume = ATMOS_DEFAULT_VOLUME_PUMP + air2.volume = ATMOS_DEFAULT_VOLUME_PUMP + +/obj/machinery/atmospherics/binary/pump/AltClick() + Topic(src, list("power" = "1")) + +/obj/machinery/atmospherics/binary/pump/on + icon_state = "map_on" + use_power = 1 + + +/obj/machinery/atmospherics/binary/pump/update_icon() + if(!powered()) + icon_state = "off" + else + icon_state = "[use_power ? "on" : "off"]" + +/obj/machinery/atmospherics/binary/pump/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + add_underlay(T, node1, turn(dir, -180)) + add_underlay(T, node2, dir) + +/obj/machinery/atmospherics/binary/pump/hide(var/i) + update_underlays() + +/obj/machinery/atmospherics/binary/pump/Process() + last_power_draw = 0 + last_flow_rate = 0 + + if((stat & (NOPOWER|BROKEN)) || !use_power) + return + + var/power_draw = -1 + var/pressure_delta = target_pressure - air2.return_pressure() + + if(pressure_delta > 0.01 && air1.temperature > 0) + //Figure out how much gas to transfer to meet the target pressure. + var/transfer_moles = calculate_transfer_moles(air1, air2, pressure_delta, (network2)? network2.volume : 0) + power_draw = pump_gas(src, air1, air2, transfer_moles, power_rating) + + if (power_draw >= 0) + last_power_draw = power_draw + use_power(power_draw) + + if(network1) + network1.update = 1 + + if(network2) + network2.update = 1 + + return 1 + +//Radio remote control + +/obj/machinery/atmospherics/binary/pump/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA) + +/obj/machinery/atmospherics/binary/pump/proc/broadcast_status() + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data = list( + "tag" = id, + "device" = "AGP", + "power" = use_power, + "target_output" = target_pressure, + "sigtype" = "status" + ) + + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + + return 1 + +/obj/machinery/atmospherics/binary/pump/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(stat & (BROKEN|NOPOWER)) + return + + // this is the data which will be sent to the ui + var/data[0] + + data = list( + "on" = use_power, + "pressure_set" = round(target_pressure*100), //Nano UI can't handle rounded non-integers, apparently. + "max_pressure" = max_pressure_setting, + "last_flow_rate" = round(last_flow_rate*10), + "last_power_draw" = round(last_power_draw), + "max_power_draw" = power_rating, + ) + + // update the ui if it exists, returns null if no ui is passed/found + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "gas_pump.tmpl", name, 470, 290) + ui.set_initial_data(data) // when the ui is first opened this is the data it will use + ui.open() // open the new ui window + ui.set_auto_update(1) // auto update every Master Controller tick + +/obj/machinery/atmospherics/binary/pump/Initialize() + . = ..() + if(frequency) + set_frequency(frequency) + +/obj/machinery/atmospherics/binary/pump/receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) + return 0 + + if(signal.data["power"]) + if(text2num(signal.data["power"])) + use_power = 1 + else + use_power = 0 + + if("power_toggle" in signal.data) + use_power = !use_power + + if(signal.data["set_output_pressure"]) + target_pressure = between( + 0, + text2num(signal.data["set_output_pressure"]), + ONE_ATMOSPHERE*50 + ) + + if(signal.data["status"]) + spawn(2) + broadcast_status() + return //do not update_icon + + spawn(2) + broadcast_status() + update_icon() + return + +/obj/machinery/atmospherics/binary/pump/attack_hand(user as mob) + if(..()) + return + src.add_fingerprint(usr) + if(!src.allowed(user)) + to_chat(user, "Access denied.") + return + usr.set_machine(src) + ui_interact(user) + return + +/obj/machinery/atmospherics/binary/pump/Topic(href,href_list) + if((. = ..())) return + + if(href_list["power"]) + use_power = !use_power + . = 1 + + switch(href_list["set_press"]) + if ("min") + target_pressure = 0 + . = 1 + if ("max") + target_pressure = max_pressure_setting + . = 1 + if ("set") + var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure control",src.target_pressure) as num + src.target_pressure = between(0, new_pressure, max_pressure_setting) + . = 1 + + if(.) + src.update_icon() + +/obj/machinery/atmospherics/binary/pump/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(!isWrench(W)) + return ..() + if (!(stat & NOPOWER) && use_power) + to_chat(user, "You cannot unwrench this [src], turn it off first.") + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + to_chat(user, "You cannot unwrench this [src], it too exerted due to internal pressure.") + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to unfasten \the [src]...") + if (do_after(user, 40, src)) + user.visible_message( \ + "\The [user] unfastens \the [src].", \ + "You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe(loc, make_from=src) + qdel(src) diff --git a/code/modules/atmospherics/components/binary_devices/volume_pump.dm b/code/modules/atmospherics/components/binary_devices/volume_pump.dm new file mode 100644 index 00000000..da4f75fa --- /dev/null +++ b/code/modules/atmospherics/components/binary_devices/volume_pump.dm @@ -0,0 +1,28 @@ +/obj/machinery/atmospherics/binary/pump/high_power + icon = 'icons/atmos/volume_pump.dmi' + icon_state = "map_off" + level = 1 + + name = "high power gas pump" + desc = "A pump. Has double the power rating of the standard gas pump." + + power_rating = 15000 //15000 W ~ 20 HP + +/obj/machinery/atmospherics/binary/pump/high_power/on + use_power = 1 + icon_state = "map_on" + +/obj/machinery/atmospherics/binary/pump/high_power/update_icon() + if(!powered()) + icon_state = "off" + else + icon_state = "[use_power ? "on" : "off"]" + +// For mapping purposes +/obj/machinery/atmospherics/binary/pump/high_power/on/max_pressure/ + target_pressure = MAX_PUMP_PRESSURE + +// A possible variant for Atmospherics distribution feed. +/obj/machinery/atmospherics/binary/pump/high_power/on/distribution/New() + ..() + target_pressure = round(3 * ONE_ATMOSPHERE) \ No newline at end of file diff --git a/code/modules/atmospherics/components/omni_devices/_omni_extras.dm b/code/modules/atmospherics/components/omni_devices/_omni_extras.dm new file mode 100644 index 00000000..9e743df1 --- /dev/null +++ b/code/modules/atmospherics/components/omni_devices/_omni_extras.dm @@ -0,0 +1,112 @@ +//-------------------------------------------- +// Omni device port types +//-------------------------------------------- +#define ATM_NONE 0 +#define ATM_INPUT 1 +#define ATM_OUTPUT 2 + +#define ATM_O2 3 +#define ATM_N2 4 +#define ATM_CO2 5 +#define ATM_P 6 //Phoron +#define ATM_N2O 7 +#define ATM_H2 8 + +//-------------------------------------------- +// Omni port datum +// +// Used by omni devices to manage connections +// to other atmospheric objects. +//-------------------------------------------- +/datum/omni_port + var/obj/machinery/atmospherics/omni/master + var/dir + var/update = 1 + var/mode = 0 + var/concentration = 0 + var/con_lock = 0 + var/transfer_moles = 0 + var/datum/gas_mixture/air + var/obj/machinery/atmospherics/node + var/datum/pipe_network/network + +/datum/omni_port/New(var/obj/machinery/atmospherics/omni/M, var/direction = NORTH) + ..() + dir = direction + if(istype(M)) + master = M + air = new + air.volume = 200 + +/datum/omni_port/proc/connect() + if(node) + return + master.atmos_init() + master.build_network() + if(node) + node.atmos_init() + node.build_network() + +/datum/omni_port/proc/disconnect() + if(node) + node.disconnect(master) + master.disconnect(node) + + +//-------------------------------------------- +// Need to find somewhere else for these +//-------------------------------------------- + +//returns a text string based on the direction flag input +// if capitalize is true, it will return the string capitalized +// otherwise it will return the direction string in lower case +/proc/dir_name(var/dir, var/capitalize = 0) + var/string = null + switch(dir) + if(NORTH) + string = "North" + if(SOUTH) + string = "South" + if(EAST) + string = "East" + if(WEST) + string = "West" + + if(!capitalize && string) + string = lowertext(string) + + return string + +//returns a direction flag based on the string passed to it +// case insensitive +/proc/dir_flag(var/dir) + dir = lowertext(dir) + switch(dir) + if("north") + return NORTH + if("south") + return SOUTH + if("east") + return EAST + if("west") + return WEST + else + return 0 + +/proc/mode_to_gasid(var/mode) + switch(mode) + if(ATM_O2) + return "oxygen" + if(ATM_N2) + return "nitrogen" + if(ATM_CO2) + return "carbon_dioxide" + if(ATM_P) + return "phoron" + if(ATM_N2O) + return "sleeping_agent" + if(ATM_H2) + return "hydrogen" + else + return null + \ No newline at end of file diff --git a/code/modules/atmospherics/components/omni_devices/filter.dm b/code/modules/atmospherics/components/omni_devices/filter.dm new file mode 100644 index 00000000..c662754f --- /dev/null +++ b/code/modules/atmospherics/components/omni_devices/filter.dm @@ -0,0 +1,275 @@ +//-------------------------------------------- +// Gas filter - omni variant +//-------------------------------------------- +/obj/machinery/atmospherics/omni/filter + name = "omni gas filter" + icon_state = "map_filter" + + var/list/gas_filters = new() + var/datum/omni_port/input + var/datum/omni_port/output + var/max_output_pressure = MAX_OMNI_PRESSURE + + use_power = 1 + idle_power_usage = 150 //internal circuitry, friction losses and stuff + power_rating = 7500 //7500 W ~ 10 HP + + var/max_flow_rate = ATMOS_DEFAULT_VOLUME_FILTER + var/set_flow_rate = ATMOS_DEFAULT_VOLUME_FILTER + + var/list/filtering_outputs = list() //maps gasids to gas_mixtures + +/obj/machinery/atmospherics/omni/filter/New() + ..() + rebuild_filtering_list() + for(var/datum/omni_port/P in ports) + P.air.volume = ATMOS_DEFAULT_VOLUME_FILTER + +/obj/machinery/atmospherics/omni/filter/Destroy() + input = null + output = null + gas_filters.Cut() + . = ..() + +/obj/machinery/atmospherics/omni/filter/sort_ports() + for(var/datum/omni_port/P in ports) + if(P.update) + if(output == P) + output = null + if(input == P) + input = null + if(P in gas_filters) + gas_filters -= P + + P.air.volume = ATMOS_DEFAULT_VOLUME_FILTER + switch(P.mode) + if(ATM_INPUT) + input = P + if(ATM_OUTPUT) + output = P + if(ATM_O2 to ATM_H2) + gas_filters += P + +/obj/machinery/atmospherics/omni/filter/error_check() + if(!input || !output || !gas_filters) + return 1 + if(gas_filters.len < 1) //requires at least 1 filter ~otherwise why are you using a filter? + return 1 + + return 0 + +/obj/machinery/atmospherics/omni/filter/Process() + if(!..()) + return 0 + + var/datum/gas_mixture/output_air = output.air //BYOND doesn't like referencing "output.air.return_pressure()" so we need to make a direct reference + var/datum/gas_mixture/input_air = input.air // it's completely happy with them if they're in a loop though i.e. "P.air.return_pressure()"... *shrug* + + var/delta = between(0, (output_air ? (max_output_pressure - output_air.return_pressure()) : 0), max_output_pressure) + var/transfer_moles_max = calculate_transfer_moles(input_air, output_air, delta, (output && output.network && output.network.volume) ? output.network.volume : 0) + for(var/datum/omni_port/filter_output in gas_filters) + delta = between(0, (filter_output.air ? (max_output_pressure - filter_output.air.return_pressure()) : 0), max_output_pressure) + transfer_moles_max = min(transfer_moles_max, (calculate_transfer_moles(input_air, filter_output.air, delta, (filter_output && filter_output.network && filter_output.network.volume) ? filter_output.network.volume : 0))) + + //Figure out the amount of moles to transfer + var/transfer_moles = between(0, ((set_flow_rate/input_air.volume)*input_air.total_moles), transfer_moles_max) + + var/power_draw = -1 + if (transfer_moles > MINIMUM_MOLES_TO_FILTER) + power_draw = filter_gas_multi(src, filtering_outputs, input_air, output_air, transfer_moles, power_rating) + + if (power_draw >= 0) + last_power_draw = power_draw + use_power(power_draw) + + if(input.network) + input.network.update = 1 + if(output.network) + output.network.update = 1 + for(var/datum/omni_port/P in gas_filters) + if(P.network) + P.network.update = 1 + + return 1 + +/obj/machinery/atmospherics/omni/filter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + usr.set_machine(src) + + var/list/data = new() + + data = build_uidata() + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + + if (!ui) + ui = new(user, src, ui_key, "omni_filter.tmpl", "Omni Filter Control", 330, 330) + ui.set_initial_data(data) + + ui.open() + +/obj/machinery/atmospherics/omni/filter/proc/build_uidata() + var/list/data = new() + + data["power"] = use_power + data["config"] = configuring + + var/portData[0] + for(var/datum/omni_port/P in ports) + if(!configuring && P.mode == 0) + continue + + var/input = 0 + var/output = 0 + var/filter = 1 + var/f_type = null + switch(P.mode) + if(ATM_INPUT) + input = 1 + filter = 0 + if(ATM_OUTPUT) + output = 1 + filter = 0 + if(ATM_O2 to ATM_H2) + f_type = mode_send_switch(P.mode) + + portData[++portData.len] = list("dir" = dir_name(P.dir, capitalize = 1), \ + "input" = input, \ + "output" = output, \ + "filter" = filter, \ + "f_type" = f_type) + + if(portData.len) + data["ports"] = portData + if(output) + data["set_flow_rate"] = round(set_flow_rate*10) //because nanoui can't handle rounded decimals. + data["last_flow_rate"] = round(last_flow_rate*10) + + return data + +/obj/machinery/atmospherics/omni/filter/proc/mode_send_switch(var/mode = ATM_NONE) + switch(mode) + if(ATM_O2) + return "Oxygen" + if(ATM_N2) + return "Nitrogen" + if(ATM_CO2) + return "Carbon Dioxide" + if(ATM_P) + return "Phoron" //*cough* Plasma *cough* + if(ATM_N2O) + return "Nitrous Oxide" + if(ATM_H2) + return "Hydrogen" + else + return null + +/obj/machinery/atmospherics/omni/filter/Topic(href, href_list) + if(..()) return 1 + switch(href_list["command"]) + if("power") + if(!configuring) + use_power = !use_power + else + use_power = 0 + if("configure") + configuring = !configuring + if(configuring) + use_power = 0 + + //only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on + if(configuring && !use_power) + switch(href_list["command"]) + if("set_flow_rate") + var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate) as num + set_flow_rate = between(0, new_flow_rate, max_flow_rate) + if("switch_mode") + switch_mode(dir_flag(href_list["dir"]), mode_return_switch(href_list["mode"])) + if("switch_filter") + var/new_filter = input(usr,"Select filter mode:","Change filter",href_list["mode"]) in list("None", "Oxygen", "Nitrogen", "Carbon Dioxide", "Phoron", "Nitrous Oxide", "Hydrogen") + switch_filter(dir_flag(href_list["dir"]), mode_return_switch(new_filter)) + + update_icon() + GLOB.nanomanager.update_uis(src) + return + +/obj/machinery/atmospherics/omni/filter/proc/mode_return_switch(var/mode) + switch(mode) + if("Oxygen") + return ATM_O2 + if("Nitrogen") + return ATM_N2 + if("Carbon Dioxide") + return ATM_CO2 + if("Phoron") + return ATM_P + if("Nitrous Oxide") + return ATM_N2O + if("Hydrogen") + return ATM_H2 + if("in") + return ATM_INPUT + if("out") + return ATM_OUTPUT + if("None") + return ATM_NONE + else + return null + +/obj/machinery/atmospherics/omni/filter/proc/switch_filter(var/dir, var/mode) + //check they aren't trying to disable the input or output ~this can only happen if they hack the cached tmpl file + for(var/datum/omni_port/P in ports) + if(P.dir == dir) + if(P.mode == ATM_INPUT || P.mode == ATM_OUTPUT) + return + + switch_mode(dir, mode) + +/obj/machinery/atmospherics/omni/filter/proc/switch_mode(var/port, var/mode) + if(mode == null || !port) + return + var/datum/omni_port/target_port = null + var/list/other_ports = new() + + for(var/datum/omni_port/P in ports) + if(P.dir == port) + target_port = P + else + other_ports += P + + var/previous_mode = null + if(target_port) + previous_mode = target_port.mode + target_port.mode = mode + if(target_port.mode != previous_mode) + handle_port_change(target_port) + rebuild_filtering_list() + else + return + else + return + + for(var/datum/omni_port/P in other_ports) + if(P.mode == mode) + var/old_mode = P.mode + P.mode = previous_mode + if(P.mode != old_mode) + handle_port_change(P) + + update_ports() + +/obj/machinery/atmospherics/omni/filter/proc/rebuild_filtering_list() + filtering_outputs.Cut() + for(var/datum/omni_port/P in ports) + var/gasid = mode_to_gasid(P.mode) + if(gasid) + filtering_outputs[gasid] = P.air + +/obj/machinery/atmospherics/omni/filter/proc/handle_port_change(var/datum/omni_port/P) + switch(P.mode) + if(ATM_NONE) + initialize_directions &= ~P.dir + P.disconnect() + else + initialize_directions |= P.dir + P.connect() + P.update = 1 \ No newline at end of file diff --git a/code/modules/atmospherics/components/omni_devices/mixer.dm b/code/modules/atmospherics/components/omni_devices/mixer.dm new file mode 100644 index 00000000..d6995556 --- /dev/null +++ b/code/modules/atmospherics/components/omni_devices/mixer.dm @@ -0,0 +1,303 @@ +//-------------------------------------------- +// Gas mixer - omni variant +//-------------------------------------------- +/obj/machinery/atmospherics/omni/mixer + name = "omni gas mixer" + icon_state = "map_mixer" + + use_power = 1 + idle_power_usage = 150 //internal circuitry, friction losses and stuff + power_rating = 3700 //3700 W ~ 5 HP + + var/list/inputs = new() + var/datum/omni_port/output + var/max_output_pressure = MAX_OMNI_PRESSURE + + //setup tags for initial concentration values (must be decimal) + var/tag_north_con + var/tag_south_con + var/tag_east_con + var/tag_west_con + + var/max_flow_rate = ATMOS_DEFAULT_VOLUME_MIXER + var/set_flow_rate = ATMOS_DEFAULT_VOLUME_MIXER + + var/list/mixing_inputs = list() + +/obj/machinery/atmospherics/omni/mixer/New() + ..() + if(mapper_set()) + var/con = 0 + for(var/datum/omni_port/P in ports) + switch(P.dir) + if(NORTH) + if(tag_north_con && tag_north == 1) + P.concentration = tag_north_con + con += max(0, tag_north_con) + if(SOUTH) + if(tag_south_con && tag_south == 1) + P.concentration = tag_south_con + con += max(0, tag_south_con) + if(EAST) + if(tag_east_con && tag_east == 1) + P.concentration = tag_east_con + con += max(0, tag_east_con) + if(WEST) + if(tag_west_con && tag_west == 1) + P.concentration = tag_west_con + con += max(0, tag_west_con) + + for(var/datum/omni_port/P in ports) + P.air.volume = ATMOS_DEFAULT_VOLUME_MIXER + +/obj/machinery/atmospherics/omni/mixer/Destroy() + inputs.Cut() + output = null + . = ..() + +/obj/machinery/atmospherics/omni/mixer/sort_ports() + for(var/datum/omni_port/P in ports) + if(P.update) + if(output == P) + output = null + if(inputs.Find(P)) + inputs -= P + + switch(P.mode) + if(ATM_INPUT) + inputs += P + if(ATM_OUTPUT) + output = P + + if(!mapper_set()) + for(var/datum/omni_port/P in inputs) + P.concentration = 1 / max(1, inputs.len) + + if(output) + output.air.volume = ATMOS_DEFAULT_VOLUME_MIXER * 0.75 * inputs.len + output.concentration = 1 + + rebuild_mixing_inputs() + +/obj/machinery/atmospherics/omni/mixer/proc/mapper_set() + return (tag_north_con || tag_south_con || tag_east_con || tag_west_con) + +/obj/machinery/atmospherics/omni/mixer/error_check() + if(!output || !inputs) + return 1 + if(inputs.len < 2) //requires at least 2 inputs ~otherwise why are you using a mixer? + return 1 + + //concentration must add to 1 + var/total = 0 + for (var/datum/omni_port/P in inputs) + total += P.concentration + + if (total != 1) + return 1 + + return 0 + +/obj/machinery/atmospherics/omni/mixer/Process() + if(!..()) + return 0 + + //Figure out the amount of moles to transfer + var/transfer_moles = 0 + var/datum/gas_mixture/output_gas = output.air + var/delta = between(0, (output_gas ? (max_output_pressure - output_gas.return_pressure()) : 0), max_output_pressure) + var/transfer_moles_max = INFINITY + + for (var/datum/omni_port/P in inputs) + transfer_moles += (set_flow_rate*P.concentration/P.air.volume)*P.air.total_moles + transfer_moles_max = min(transfer_moles_max, calculate_transfer_moles(P.air, output.air, delta, (output && output.network && output.network.volume) ? output.network.volume : 0)) + transfer_moles = between(0, transfer_moles, transfer_moles_max) + + var/power_draw = -1 + if (transfer_moles > MINIMUM_MOLES_TO_FILTER) + power_draw = mix_gas(src, mixing_inputs, output.air, transfer_moles, power_rating) + + if (power_draw >= 0) + last_power_draw = power_draw + use_power(power_draw) + + for(var/datum/omni_port/P in inputs) + if(P.concentration && P.network) + P.network.update = 1 + + if(output.network) + output.network.update = 1 + + return 1 + +/obj/machinery/atmospherics/omni/mixer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + usr.set_machine(src) + + var/list/data = new() + + data = build_uidata() + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + + if (!ui) + ui = new(user, src, ui_key, "omni_mixer.tmpl", "Omni Mixer Control", 360, 330) + ui.set_initial_data(data) + + ui.open() + +/obj/machinery/atmospherics/omni/mixer/proc/build_uidata() + var/list/data = new() + + data["power"] = use_power + data["config"] = configuring + + var/portData[0] + for(var/datum/omni_port/P in ports) + if(!configuring && P.mode == 0) + continue + + var/input = 0 + var/output = 0 + switch(P.mode) + if(ATM_INPUT) + input = 1 + if(ATM_OUTPUT) + output = 1 + + portData[++portData.len] = list("dir" = dir_name(P.dir, capitalize = 1), \ + "concentration" = P.concentration, \ + "input" = input, \ + "output" = output, \ + "con_lock" = P.con_lock) + + if(portData.len) + data["ports"] = portData + if(output) + data["set_flow_rate"] = round(set_flow_rate*10) //because nanoui can't handle rounded decimals. + data["last_flow_rate"] = round(last_flow_rate*10) + + return data + +/obj/machinery/atmospherics/omni/mixer/Topic(href, href_list) + if(..()) return 1 + + switch(href_list["command"]) + if("power") + if(!configuring) + use_power = !use_power + else + use_power = 0 + if("configure") + configuring = !configuring + if(configuring) + use_power = 0 + + //only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on + if(configuring && !use_power) + switch(href_list["command"]) + if("set_flow_rate") + var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate) as num + set_flow_rate = between(0, new_flow_rate, max_flow_rate) + if("switch_mode") + switch_mode(dir_flag(href_list["dir"]), href_list["mode"]) + if("switch_con") + change_concentration(dir_flag(href_list["dir"])) + if("switch_conlock") + con_lock(dir_flag(href_list["dir"])) + + update_icon() + GLOB.nanomanager.update_uis(src) + return + +/obj/machinery/atmospherics/omni/mixer/proc/switch_mode(var/port = NORTH, var/mode = ATM_NONE) + if(mode != ATM_INPUT && mode != ATM_OUTPUT) + switch(mode) + if("in") + mode = ATM_INPUT + if("out") + mode = ATM_OUTPUT + else + mode = ATM_NONE + + for(var/datum/omni_port/P in ports) + var/old_mode = P.mode + if(P.dir == port) + switch(mode) + if(ATM_INPUT) + if(P.mode == ATM_OUTPUT) + return + P.mode = mode + if(ATM_OUTPUT) + P.mode = mode + if(ATM_NONE) + if(P.mode == ATM_OUTPUT) + return + if(P.mode == ATM_INPUT && inputs.len > 2) + P.mode = mode + else if(P.mode == ATM_OUTPUT && mode == ATM_OUTPUT) + P.mode = ATM_INPUT + if(P.mode != old_mode) + switch(P.mode) + if(ATM_NONE) + initialize_directions &= ~P.dir + P.disconnect() + else + initialize_directions |= P.dir + P.connect() + P.update = 1 + + update_ports() + rebuild_mixing_inputs() + +/obj/machinery/atmospherics/omni/mixer/proc/change_concentration(var/port = NORTH) + tag_north_con = null + tag_south_con = null + tag_east_con = null + tag_west_con = null + + var/old_con = 0 + var/non_locked = 0 + var/remain_con = 1 + + for(var/datum/omni_port/P in inputs) + if(P.dir == port) + old_con = P.concentration + else if(!P.con_lock) + non_locked++ + else + remain_con -= P.concentration + + //return if no adjustable ports + if(non_locked < 1) + return + + var/new_con = (input(usr,"Enter a new concentration (0-[round(remain_con * 100, 0.5)])%","Concentration control", min(remain_con, old_con)*100) as num) / 100 + + //cap it between 0 and the max remaining concentration + new_con = between(0, new_con, remain_con) + + //new_con = min(remain_con, new_con) + + //clamp remaining concentration so we don't go into negatives + remain_con = max(0, remain_con - new_con) + + //distribute remaining concentration between unlocked ports evenly + remain_con /= max(1, non_locked) + + for(var/datum/omni_port/P in inputs) + if(P.dir == port) + P.concentration = new_con + else if(!P.con_lock) + P.concentration = remain_con + + rebuild_mixing_inputs() + +/obj/machinery/atmospherics/omni/mixer/proc/rebuild_mixing_inputs() + mixing_inputs.Cut() + for(var/datum/omni_port/P in inputs) + mixing_inputs[P.air] = P.concentration + +/obj/machinery/atmospherics/omni/mixer/proc/con_lock(var/port = NORTH) + for(var/datum/omni_port/P in inputs) + if(P.dir == port) + P.con_lock = !P.con_lock \ No newline at end of file diff --git a/code/modules/atmospherics/components/omni_devices/omni_base.dm b/code/modules/atmospherics/components/omni_devices/omni_base.dm new file mode 100644 index 00000000..44c5f42d --- /dev/null +++ b/code/modules/atmospherics/components/omni_devices/omni_base.dm @@ -0,0 +1,297 @@ +//-------------------------------------------- +// Base omni device +//-------------------------------------------- +/obj/machinery/atmospherics/omni + name = "omni device" + icon = 'icons/atmos/omni_devices.dmi' + icon_state = "base" + use_power = 1 + initialize_directions = 0 + level = 1 + + var/configuring = 0 + //var/target_pressure = ONE_ATMOSPHERE //a base type as abstract as this should NOT be making these kinds of assumptions + + var/tag_north = ATM_NONE + var/tag_south = ATM_NONE + var/tag_east = ATM_NONE + var/tag_west = ATM_NONE + + var/overlays_on[5] + var/overlays_off[5] + var/overlays_error[2] + var/underlays_current[4] + + var/list/ports = new() + +/obj/machinery/atmospherics/omni/New() + ..() + icon_state = "base" + + ports = new() + for(var/d in GLOB.cardinal) + var/datum/omni_port/new_port = new(src, d) + switch(d) + if(NORTH) + new_port.mode = tag_north + if(SOUTH) + new_port.mode = tag_south + if(EAST) + new_port.mode = tag_east + if(WEST) + new_port.mode = tag_west + if(new_port.mode > 0) + initialize_directions |= d + ports += new_port + + build_icons() + +/obj/machinery/atmospherics/omni/update_icon() + if(stat & NOPOWER) + overlays = overlays_off + else if(error_check()) + overlays = overlays_error + else + overlays = use_power ? (overlays_on) : (overlays_off) + + underlays = underlays_current + + return + +/obj/machinery/atmospherics/omni/proc/error_check() + return + +/obj/machinery/atmospherics/omni/Process() + last_power_draw = 0 + last_flow_rate = 0 + + if(error_check()) + use_power = 0 + + if((stat & (NOPOWER|BROKEN)) || !use_power) + return 0 + return 1 + +/obj/machinery/atmospherics/omni/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(!isWrench(W)) + return ..() + + var/int_pressure = 0 + for(var/datum/omni_port/P in ports) + int_pressure += P.air.return_pressure() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_pressure - env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.") + add_fingerprint(user) + return 1 + to_chat(user, "You begin to unfasten \the [src]...") + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + if(do_after(user, 40, src)) + user.visible_message( \ + "\The [user] unfastens \the [src].", \ + "You have unfastened \the [src].", \ + "You hear a ratchet.") + new /obj/item/pipe(loc, make_from=src) + qdel(src) + +/obj/machinery/atmospherics/omni/attack_hand(user as mob) + if(..()) + return + + src.add_fingerprint(usr) + ui_interact(user) + return + +/obj/machinery/atmospherics/omni/proc/build_icons() + if(!check_icon_cache()) + return + + var/core_icon = null + if(istype(src, /obj/machinery/atmospherics/omni/mixer)) + core_icon = "mixer" + else if(istype(src, /obj/machinery/atmospherics/omni/filter)) + core_icon = "filter" + else + return + + //directional icons are layers 1-4, with the core icon on layer 5 + if(core_icon) + overlays_off[5] = icon_manager.get_atmos_icon("omni", , , core_icon) + overlays_on[5] = icon_manager.get_atmos_icon("omni", , , core_icon + "_glow") + + overlays_error[1] = icon_manager.get_atmos_icon("omni", , , core_icon) + overlays_error[2] = icon_manager.get_atmos_icon("omni", , , "error") + +/obj/machinery/atmospherics/omni/proc/update_port_icons() + if(!check_icon_cache()) + return + + for(var/datum/omni_port/P in ports) + if(P.update) + var/ref_layer = 0 + switch(P.dir) + if(NORTH) + ref_layer = 1 + if(SOUTH) + ref_layer = 2 + if(EAST) + ref_layer = 3 + if(WEST) + ref_layer = 4 + + if(!ref_layer) + continue + + var/list/port_icons = select_port_icons(P) + if(port_icons) + if(P.node) + underlays_current[ref_layer] = port_icons["pipe_icon"] + else + underlays_current[ref_layer] = null + overlays_off[ref_layer] = port_icons["off_icon"] + overlays_on[ref_layer] = port_icons["on_icon"] + else + underlays_current[ref_layer] = null + overlays_off[ref_layer] = null + overlays_on[ref_layer] = null + + update_icon() + +/obj/machinery/atmospherics/omni/proc/select_port_icons(var/datum/omni_port/P) + if(!istype(P)) + return + + if(P.mode > 0) + var/ic_dir = dir_name(P.dir) + var/ic_on = ic_dir + var/ic_off = ic_dir + switch(P.mode) + if(ATM_INPUT) + ic_on += "_in_glow" + ic_off += "_in" + if(ATM_OUTPUT) + ic_on += "_out_glow" + ic_off += "_out" + if(ATM_O2 to ATM_H2) + ic_on += "_filter" + ic_off += "_out" + + ic_on = icon_manager.get_atmos_icon("omni", , , ic_on) + ic_off = icon_manager.get_atmos_icon("omni", , , ic_off) + + var/pipe_state + var/turf/T = get_turf(src) + if(!istype(T)) + return + if(!T.is_plating() && istype(P.node, /obj/machinery/atmospherics/pipe) && P.node.level == 1 ) + //pipe_state = icon_manager.get_atmos_icon("underlay_down", P.dir, color_cache_name(P.node)) + pipe_state = icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "down") + else + //pipe_state = icon_manager.get_atmos_icon("underlay_intact", P.dir, color_cache_name(P.node)) + pipe_state = icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "intact") + + return list("on_icon" = ic_on, "off_icon" = ic_off, "pipe_icon" = pipe_state) + +/obj/machinery/atmospherics/omni/update_underlays() + for(var/datum/omni_port/P in ports) + P.update = 1 + update_ports() + +/obj/machinery/atmospherics/omni/hide(var/i) + update_underlays() + +/obj/machinery/atmospherics/omni/proc/update_ports() + sort_ports() + update_port_icons() + for(var/datum/omni_port/P in ports) + P.update = 0 + +/obj/machinery/atmospherics/omni/proc/sort_ports() + return + + +// Housekeeping and pipe network stuff below + +/obj/machinery/atmospherics/omni/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + for(var/datum/omni_port/P in ports) + if(reference == P.node) + P.network = new_network + break + + if(new_network.normal_members.Find(src)) + return 0 + + new_network.normal_members += src + + return null + +/obj/machinery/atmospherics/omni/Destroy() + loc = null + + for(var/datum/omni_port/P in ports) + if(P.node) + P.node.disconnect(src) + qdel(P.network) + P.node = null + + ..() + +/obj/machinery/atmospherics/omni/atmos_init() + ..() + for(var/datum/omni_port/P in ports) + if(P.node || P.mode == 0) + continue + for(var/obj/machinery/atmospherics/target in get_step(src, P.dir)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + P.node = target + break + + for(var/datum/omni_port/P in ports) + P.update = 1 + + update_ports() + +/obj/machinery/atmospherics/omni/build_network() + for(var/datum/omni_port/P in ports) + if(!P.network && P.node) + P.network = new /datum/pipe_network() + P.network.normal_members += src + P.network.build_network(P.node, src) + +/obj/machinery/atmospherics/omni/return_network(obj/machinery/atmospherics/reference) + build_network() + + for(var/datum/omni_port/P in ports) + if(reference == P.node) + return P.network + + return null + +/obj/machinery/atmospherics/omni/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + for(var/datum/omni_port/P in ports) + if(P.network == old_network) + P.network = new_network + + return 1 + +/obj/machinery/atmospherics/omni/return_network_air(datum/pipe_network/reference) + var/list/results = list() + + for(var/datum/omni_port/P in ports) + if(P.network == reference) + results += P.air + + return results + +/obj/machinery/atmospherics/omni/disconnect(obj/machinery/atmospherics/reference) + for(var/datum/omni_port/P in ports) + if(reference == P.node) + qdel(P.network) + P.node = null + P.update = 1 + break + + update_ports() + + return null diff --git a/code/modules/atmospherics/components/portables_connector.dm b/code/modules/atmospherics/components/portables_connector.dm new file mode 100644 index 00000000..edf4fcc1 --- /dev/null +++ b/code/modules/atmospherics/components/portables_connector.dm @@ -0,0 +1,156 @@ +/obj/machinery/atmospherics/portables_connector + icon = 'icons/atmos/connector.dmi' + icon_state = "map_connector" + + name = "Connector Port" + desc = "For connecting portable devices related to atmospherics control." + + dir = SOUTH + initialize_directions = SOUTH + + var/obj/machinery/portable_atmospherics/connected_device + + var/obj/machinery/atmospherics/node + + var/datum/pipe_network/network + + var/on = 0 + use_power = 0 + level = 1 + + +/obj/machinery/atmospherics/portables_connector/Initialize() + initialize_directions = dir + . = ..() + +/obj/machinery/atmospherics/portables_connector/update_icon() + icon_state = "connector" + +/obj/machinery/atmospherics/portables_connector/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + add_underlay(T, node, dir) + +/obj/machinery/atmospherics/portables_connector/hide(var/i) + update_underlays() + +/obj/machinery/atmospherics/portables_connector/Process() + ..() + if(!on) + return + if(!connected_device) + on = 0 + return + if(network) + network.update = 1 + return 1 + +// Housekeeping and pipe network stuff below +/obj/machinery/atmospherics/portables_connector/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(reference == node) + network = new_network + + if(new_network.normal_members.Find(src)) + return 0 + + new_network.normal_members += src + + return null + +/obj/machinery/atmospherics/portables_connector/Destroy() + loc = null + + if(connected_device) + connected_device.disconnect() + + if(node) + node.disconnect(src) + qdel(network) + + node = null + + . = ..() + +/obj/machinery/atmospherics/portables_connector/atmos_init() + ..() + if(node) return + + var/node_connect = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,node_connect)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node = target + break + + update_icon() + update_underlays() + +/obj/machinery/atmospherics/portables_connector/build_network() + if(!network && node) + network = new /datum/pipe_network() + network.normal_members += src + network.build_network(node, src) + + +/obj/machinery/atmospherics/portables_connector/return_network(obj/machinery/atmospherics/reference) + build_network() + + if(reference==node) + return network + + if(reference==connected_device) + return network + + return null + +/obj/machinery/atmospherics/portables_connector/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network == old_network) + network = new_network + + return 1 + +/obj/machinery/atmospherics/portables_connector/return_network_air(datum/pipe_network/reference) + var/list/results = list() + + if(connected_device) + results += connected_device.air_contents + + return results + +/obj/machinery/atmospherics/portables_connector/disconnect(obj/machinery/atmospherics/reference) + if(reference==node) + qdel(network) + node = null + + update_underlays() + + return null + + +/obj/machinery/atmospherics/portables_connector/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(!isWrench(W)) + return ..() + if (connected_device) + to_chat(user, "You cannot unwrench \the [src], dettach \the [connected_device] first.") + return 1 + if (locate(/obj/machinery/portable_atmospherics, src.loc)) + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + to_chat(user, "You cannot unwrench \the [src], it too exerted due to internal pressure.") + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to unfasten \the [src]...") + if (do_after(user, 40, src)) + user.visible_message( \ + "\The [user] unfastens \the [src].", \ + "You have unfastened \the [src].", \ + "You hear a ratchet.") + new /obj/item/pipe(loc, make_from=src) + qdel(src) diff --git a/code/modules/atmospherics/components/shutoff.dm b/code/modules/atmospherics/components/shutoff.dm new file mode 100644 index 00000000..bcb15396 --- /dev/null +++ b/code/modules/atmospherics/components/shutoff.dm @@ -0,0 +1,54 @@ +/obj/machinery/atmospherics/valve/shutoff + icon = 'icons/atmos/clamp.dmi' + icon_state = "map_vclamp0" + + name = "automatic shutoff valve" + desc = "An automatic valve with control circuitry and pipe integrity sensor, capable of automatically isolating damaged segments of the pipe network." + var/override_open = FALSE // If true it will be always open + level = 1 + connect_types = CONNECT_TYPE_SCRUBBER | CONNECT_TYPE_SUPPLY | CONNECT_TYPE_REGULAR + + +/obj/machinery/atmospherics/valve/shutoff/update_icon() + icon_state = "vclamp[open]" + +/obj/machinery/atmospherics/valve/shutoff/examine(var/mob/user) + ..() + to_chat(user, "The automatic shutoff circuit is [override_open ? "disabled" : "enabled"].") + +/obj/machinery/atmospherics/valve/shutoff/New() + open() + hide(1) + ..() + +/obj/machinery/atmospherics/valve/shutoff/attack_hand(var/mob/user as mob) + override_open = !override_open + to_chat(user, "You [override_open ? "disable" : "enable"] the automatic shutoff circuit.") + +/obj/machinery/atmospherics/valve/shutoff/attack_ai(var/mob/user as mob) + attack_hand(user) + +/obj/machinery/atmospherics/valve/shutoff/hide(var/do_hide) + if(do_hide) + if(level == 1) + plane = ABOVE_PLATING_PLANE + layer = PIPE_LAYER + else if(level == 2) + ..() + else + reset_plane_and_layer() + +/obj/machinery/atmospherics/valve/shutoff/Process() + ..() + + if(!network_node1 || !network_node2) + if(open) + close() + return + + var/closed_auto = (network_node1.leaks.len || network_node2.leaks.len || override_open) + + if(closed_auto && open) + close() + else if(!closed_auto && !open) + open() \ No newline at end of file diff --git a/code/modules/atmospherics/components/trinary_devices/filter.dm b/code/modules/atmospherics/components/trinary_devices/filter.dm new file mode 100644 index 00000000..3dd40c66 --- /dev/null +++ b/code/modules/atmospherics/components/trinary_devices/filter.dm @@ -0,0 +1,283 @@ +/obj/machinery/atmospherics/trinary/filter + icon = 'icons/atmos/filter.dmi' + icon_state = "map" + density = 0 + level = 1 + + name = "Gas filter" + + use_power = 1 + idle_power_usage = 150 //internal circuitry, friction losses and stuff + power_rating = 7500 //This also doubles as a measure of how powerful the filter is, in Watts. 7500 W ~ 10 HP + + var/temp = null // -- TLE + + var/set_flow_rate = ATMOS_DEFAULT_VOLUME_FILTER + + /* + Filter types: + -1: Nothing + 0: Phoron: Phoron, Oxygen Agent B + 1: Oxygen: Oxygen ONLY + 2: Nitrogen: Nitrogen ONLY + 3: Carbon Dioxide: Carbon Dioxide ONLY + 4: Sleeping Agent (N2O) + 5: Hydrogen (H2) + */ + var/filter_type = -1 + var/list/filtered_out = list() + + + var/frequency = 0 + var/datum/radio_frequency/radio_connection + +/obj/machinery/atmospherics/trinary/filter/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) + +/obj/machinery/atmospherics/trinary/filter/New() + ..() + switch(filter_type) + if(0) //removing hydrocarbons + filtered_out = list("phoron") + if(1) //removing O2 + filtered_out = list("oxygen") + if(2) //removing N2 + filtered_out = list("nitrogen") + if(3) //removing CO2 + filtered_out = list("carbon_dioxide") + if(4)//removing N2O + filtered_out = list("sleeping_agent") + if(5)//removing H2 + filtered_out = list("hydrogen") + + air1.volume = ATMOS_DEFAULT_VOLUME_FILTER + air2.volume = ATMOS_DEFAULT_VOLUME_FILTER + air3.volume = ATMOS_DEFAULT_VOLUME_FILTER + +/obj/machinery/atmospherics/trinary/filter/update_icon() + if(istype(src, /obj/machinery/atmospherics/trinary/filter/m_filter)) + icon_state = "m" + else + icon_state = "" + + if(!powered()) + icon_state += "off" + else if(node2 && node3 && node1) + icon_state += use_power ? "on" : "off" + else + icon_state += "off" + use_power = 0 + +/obj/machinery/atmospherics/trinary/filter/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + + add_underlay(T, node1, turn(dir, -180)) + + if(istype(src, /obj/machinery/atmospherics/trinary/filter/m_filter)) + add_underlay(T, node2, turn(dir, 90)) + else + add_underlay(T, node2, turn(dir, -90)) + + add_underlay(T, node3, dir) + +/obj/machinery/atmospherics/trinary/filter/hide(var/i) + update_underlays() + +/obj/machinery/atmospherics/trinary/filter/Process() + ..() + + last_power_draw = 0 + last_flow_rate = 0 + + if((stat & (NOPOWER|BROKEN)) || !use_power) + return + + //Figure out the amount of moles to transfer + var/transfer_moles = (set_flow_rate/air1.volume)*air1.total_moles + + var/power_draw = -1 + if (transfer_moles > MINIMUM_MOLES_TO_FILTER) + power_draw = filter_gas(src, filtered_out, air1, air2, air3, transfer_moles, power_rating) + + if(network2) + network2.update = 1 + + if(network3) + network3.update = 1 + + if(network1) + network1.update = 1 + + if (power_draw >= 0) + last_power_draw = power_draw + use_power(power_draw) + + return 1 + +/obj/machinery/atmospherics/trinary/filter/Initialize() + set_frequency(frequency) + . = ..() + +/obj/machinery/atmospherics/trinary/filter/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(!isWrench(W)) + return ..() + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + to_chat(user, "You cannot unwrench \the [src], it too exerted due to internal pressure.") + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to unfasten \the [src]...") + if (do_after(user, 40, src)) + user.visible_message( \ + "\The [user] unfastens \the [src].", \ + "You have unfastened \the [src].", \ + "You hear a ratchet.") + new /obj/item/pipe(loc, make_from=src) + qdel(src) + + +/obj/machinery/atmospherics/trinary/filter/attack_hand(user as mob) // -- TLE + if(..()) + return + + if(!src.allowed(user)) + to_chat(user, "Access denied.") + return + + var/dat + var/current_filter_type + switch(filter_type) + if(0) + current_filter_type = "Phoron" + if(1) + current_filter_type = "Oxygen" + if(2) + current_filter_type = "Nitrogen" + if(3) + current_filter_type = "Carbon Dioxide" + if(4) + current_filter_type = "Nitrous Oxide" + if(5) + current_filter_type = "Hydrogen" + if(-1) + current_filter_type = "Nothing" + else + current_filter_type = "ERROR - Report this bug to the admin, please!" + + dat += {" + Power: [use_power?"On":"Off"]
            + Filtering: [current_filter_type]

            +

            Set Filter Type:

            + Phoron
            + Oxygen
            + Nitrogen
            + Carbon Dioxide
            + Nitrous Oxide
            + Hydrogen
            + Nothing
            +
            + Set Flow Rate Limit: + [src.set_flow_rate]L/s | Change
            + Flow rate: [round(last_flow_rate, 0.1)]L/s + "} + + user << browse("[src.name] control[dat]", "window=atmo_filter") + onclose(user, "atmo_filter") + return + +/obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE + if(..()) + return 1 + usr.set_machine(src) + src.add_fingerprint(usr) + if(href_list["filterset"]) + filter_type = text2num(href_list["filterset"]) + + filtered_out.Cut() //no need to create new lists unnecessarily + switch(filter_type) + if(0) //removing hydrocarbons + filtered_out += "phoron" + if(1) //removing O2 + filtered_out += "oxygen" + if(2) //removing N2 + filtered_out += "nitrogen" + if(3) //removing CO2 + filtered_out += "carbon_dioxide" + if(4)//removing N2O + filtered_out += "sleeping_agent" + if(5)//removing H2 + filtered_out += "hydrogen" + + if (href_list["temp"]) + src.temp = null + if(href_list["set_flow_rate"]) + var/new_flow_rate = input(usr,"Enter new flow rate (0-[air1.volume]L/s)","Flow Rate Control",src.set_flow_rate) as num + src.set_flow_rate = max(0, min(air1.volume, new_flow_rate)) + if(href_list["power"]) + use_power=!use_power + src.update_icon() + src.updateUsrDialog() +/* + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) +*/ + return + +/obj/machinery/atmospherics/trinary/filter/m_filter + icon_state = "mmap" + + dir = SOUTH + initialize_directions = SOUTH|NORTH|EAST + +obj/machinery/atmospherics/trinary/filter/m_filter/New() + ..() + switch(dir) + if(NORTH) + initialize_directions = WEST|NORTH|SOUTH + if(SOUTH) + initialize_directions = SOUTH|EAST|NORTH + if(EAST) + initialize_directions = EAST|WEST|NORTH + if(WEST) + initialize_directions = WEST|SOUTH|EAST + +/obj/machinery/atmospherics/trinary/filter/m_filter/Initialize() + . = ..() + set_frequency(frequency) + +/obj/machinery/atmospherics/trinary/filter/m_filter/atmos_init() + ..() + + if(node1 && node2 && node3) return + + var/node1_connect = turn(dir, -180) + var/node2_connect = turn(dir, 90) + var/node3_connect = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect)) + if(target.initialize_directions & get_dir(target,src)) + node2 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect)) + if(target.initialize_directions & get_dir(target,src)) + node3 = target + break + + update_icon() + update_underlays() diff --git a/code/modules/atmospherics/components/trinary_devices/mixer.dm b/code/modules/atmospherics/components/trinary_devices/mixer.dm new file mode 100644 index 00000000..8f76f4ca --- /dev/null +++ b/code/modules/atmospherics/components/trinary_devices/mixer.dm @@ -0,0 +1,262 @@ +/obj/machinery/atmospherics/trinary/mixer + icon = 'icons/atmos/mixer.dmi' + icon_state = "map" + density = 0 + level = 1 + + name = "Gas mixer" + + use_power = 1 + idle_power_usage = 150 //internal circuitry, friction losses and stuff + power_rating = 3700 //This also doubles as a measure of how powerful the mixer is, in Watts. 3700 W ~ 5 HP + + var/set_flow_rate = ATMOS_DEFAULT_VOLUME_MIXER + var/list/mixing_inputs + + //for mapping + var/node1_concentration = 0.5 + var/node2_concentration = 0.5 + + //node 3 is the outlet, nodes 1 & 2 are intakes + +/obj/machinery/atmospherics/trinary/mixer/update_icon(var/safety = 0) + if(istype(src, /obj/machinery/atmospherics/trinary/mixer/m_mixer)) + icon_state = "m" + else if(istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer)) + icon_state = "t" + else + icon_state = "" + + if(!powered()) + icon_state += "off" + else if(node2 && node3 && node1) + icon_state += use_power ? "on" : "off" + else + icon_state += "off" + use_power = 0 + +/obj/machinery/atmospherics/trinary/mixer/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + + if(istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer)) + add_underlay(T, node1, turn(dir, -90)) + else + add_underlay(T, node1, turn(dir, -180)) + + if(istype(src, /obj/machinery/atmospherics/trinary/mixer/m_mixer) || istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer)) + add_underlay(T, node2, turn(dir, 90)) + else + add_underlay(T, node2, turn(dir, -90)) + + add_underlay(T, node3, dir) + +/obj/machinery/atmospherics/trinary/mixer/hide(var/i) + update_underlays() + +/obj/machinery/atmospherics/trinary/mixer/New() + ..() + air1.volume = ATMOS_DEFAULT_VOLUME_MIXER + air2.volume = ATMOS_DEFAULT_VOLUME_MIXER + air3.volume = ATMOS_DEFAULT_VOLUME_MIXER * 1.5 + + if (!mixing_inputs) + mixing_inputs = list(src.air1 = node1_concentration, src.air2 = node2_concentration) + +/obj/machinery/atmospherics/trinary/mixer/Process() + ..() + + last_power_draw = 0 + last_flow_rate = 0 + + if((stat & (NOPOWER|BROKEN)) || !use_power) + return + + //Figure out the amount of moles to transfer + var/transfer_moles = (set_flow_rate*mixing_inputs[air1]/air1.volume)*air1.total_moles + (set_flow_rate*mixing_inputs[air1]/air2.volume)*air2.total_moles + + var/power_draw = -1 + if (transfer_moles > MINIMUM_MOLES_TO_FILTER) + power_draw = mix_gas(src, mixing_inputs, air3, transfer_moles, power_rating) + + if(network1 && mixing_inputs[air1]) + network1.update = 1 + + if(network2 && mixing_inputs[air2]) + network2.update = 1 + + if(network3) + network3.update = 1 + + if (power_draw >= 0) + last_power_draw = power_draw + use_power(power_draw) + + return 1 + +/obj/machinery/atmospherics/trinary/mixer/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(!isWrench(W)) + return ..() + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + to_chat(user, "You cannot unwrench \the [src], it too exerted due to internal pressure.") + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to unfasten \the [src]...") + if (do_after(user, 40, src)) + user.visible_message( \ + "\The [user] unfastens \the [src].", \ + "You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe(loc, make_from=src) + qdel(src) + +/obj/machinery/atmospherics/trinary/mixer/attack_hand(user as mob) + if(..()) + return + src.add_fingerprint(usr) + if(!src.allowed(user)) + to_chat(user, "Access denied.") + return + usr.set_machine(src) + var/dat = {"Power: [use_power?"On":"Off"]
            + Set Flow Rate Limit: + [set_flow_rate]L/s | Change +
            + Flow Rate: [round(last_flow_rate, 0.1)]L/s +

            + Node 1 Concentration: + - + - + [mixing_inputs[air1]]([mixing_inputs[air1]*100]%) + + + + +
            + Node 2 Concentration: + - + - + [mixing_inputs[air2]]([mixing_inputs[air2]*100]%) + + + + + "} + + user << browse("[src.name] control[dat]", "window=atmo_mixer") + onclose(user, "atmo_mixer") + return + +/obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list) + if(..()) return 1 + if(href_list["power"]) + use_power = !use_power + if(href_list["set_press"]) + var/max_flow_rate = min(air1.volume, air2.volume) + var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",src.set_flow_rate) as num + src.set_flow_rate = max(0, min(max_flow_rate, new_flow_rate)) + if(href_list["node1_c"]) + var/value = text2num(href_list["node1_c"]) + src.mixing_inputs[air1] = max(0, min(1, src.mixing_inputs[air1] + value)) + src.mixing_inputs[air2] = 1.0 - mixing_inputs[air1] + if(href_list["node2_c"]) + var/value = text2num(href_list["node2_c"]) + src.mixing_inputs[air2] = max(0, min(1, src.mixing_inputs[air2] + value)) + src.mixing_inputs[air1] = 1.0 - mixing_inputs[air2] + src.update_icon() + src.updateUsrDialog() + return + +obj/machinery/atmospherics/trinary/mixer/t_mixer + icon_state = "tmap" + + dir = SOUTH + initialize_directions = SOUTH|EAST|WEST + + //node 3 is the outlet, nodes 1 & 2 are intakes + +obj/machinery/atmospherics/trinary/mixer/t_mixer/New() + ..() + switch(dir) + if(NORTH) + initialize_directions = EAST|NORTH|WEST + if(SOUTH) + initialize_directions = SOUTH|WEST|EAST + if(EAST) + initialize_directions = EAST|NORTH|SOUTH + if(WEST) + initialize_directions = WEST|NORTH|SOUTH + +obj/machinery/atmospherics/trinary/mixer/t_mixer/atmos_init() + ..() + if(node1 && node2 && node3) return + + var/node1_connect = turn(dir, -90) + var/node2_connect = turn(dir, 90) + var/node3_connect = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect)) + if(target.initialize_directions & get_dir(target,src)) + node2 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect)) + if(target.initialize_directions & get_dir(target,src)) + node3 = target + break + + update_icon() + update_underlays() + +obj/machinery/atmospherics/trinary/mixer/m_mixer + icon_state = "mmap" + + dir = SOUTH + initialize_directions = SOUTH|NORTH|EAST + + //node 3 is the outlet, nodes 1 & 2 are intakes + +obj/machinery/atmospherics/trinary/mixer/m_mixer/New() + ..() + switch(dir) + if(NORTH) + initialize_directions = WEST|NORTH|SOUTH + if(SOUTH) + initialize_directions = SOUTH|EAST|NORTH + if(EAST) + initialize_directions = EAST|WEST|NORTH + if(WEST) + initialize_directions = WEST|SOUTH|EAST + +obj/machinery/atmospherics/trinary/mixer/m_mixer/atmos_init() + ..() + if(node1 && node2 && node3) return + + var/node1_connect = turn(dir, -180) + var/node2_connect = turn(dir, 90) + var/node3_connect = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect)) + if(target.initialize_directions & get_dir(target,src)) + node2 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect)) + if(target.initialize_directions & get_dir(target,src)) + node3 = target + break + + update_icon() + update_underlays() diff --git a/code/modules/atmospherics/components/trinary_devices/trinary_base.dm b/code/modules/atmospherics/components/trinary_devices/trinary_base.dm new file mode 100644 index 00000000..98a680de --- /dev/null +++ b/code/modules/atmospherics/components/trinary_devices/trinary_base.dm @@ -0,0 +1,168 @@ +obj/machinery/atmospherics/trinary + dir = SOUTH + initialize_directions = SOUTH|NORTH|WEST + use_power = 0 + + var/datum/gas_mixture/air1 + var/datum/gas_mixture/air2 + var/datum/gas_mixture/air3 + + var/obj/machinery/atmospherics/node3 + + var/datum/pipe_network/network1 + var/datum/pipe_network/network2 + var/datum/pipe_network/network3 + + New() + ..() + switch(dir) + if(NORTH) + initialize_directions = EAST|NORTH|SOUTH + if(SOUTH) + initialize_directions = SOUTH|WEST|NORTH + if(EAST) + initialize_directions = EAST|WEST|SOUTH + if(WEST) + initialize_directions = WEST|NORTH|EAST + air1 = new + air2 = new + air3 = new + + air1.volume = 200 + air2.volume = 200 + air3.volume = 200 + +// Housekeeping and pipe network stuff below + network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(reference == node1) + network1 = new_network + + else if(reference == node2) + network2 = new_network + + else if (reference == node3) + network3 = new_network + + if(new_network.normal_members.Find(src)) + return 0 + + new_network.normal_members += src + + return null + + Destroy() + loc = null + + if(node1) + node1.disconnect(src) + qdel(network1) + if(node2) + node2.disconnect(src) + qdel(network2) + if(node3) + node3.disconnect(src) + qdel(network3) + + node1 = null + node2 = null + node3 = null + + ..() + + atmos_init() + ..() + if(node1 && node2 && node3) return + + var/node1_connect = turn(dir, -180) + var/node2_connect = turn(dir, -90) + var/node3_connect = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node1 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node2 = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node3 = target + break + + update_icon() + update_underlays() + + build_network() + if(!network1 && node1) + network1 = new /datum/pipe_network() + network1.normal_members += src + network1.build_network(node1, src) + + if(!network2 && node2) + network2 = new /datum/pipe_network() + network2.normal_members += src + network2.build_network(node2, src) + + if(!network3 && node3) + network3 = new /datum/pipe_network() + network3.normal_members += src + network3.build_network(node3, src) + + + return_network(obj/machinery/atmospherics/reference) + build_network() + + if(reference==node1) + return network1 + + if(reference==node2) + return network2 + + if(reference==node3) + return network3 + + return null + + reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network1 == old_network) + network1 = new_network + if(network2 == old_network) + network2 = new_network + if(network3 == old_network) + network3 = new_network + + return 1 + + return_network_air(datum/pipe_network/reference) + var/list/results = list() + + if(network1 == reference) + results += air1 + if(network2 == reference) + results += air2 + if(network3 == reference) + results += air3 + + return results + + disconnect(obj/machinery/atmospherics/reference) + if(reference==node1) + qdel(network1) + node1 = null + + else if(reference==node2) + qdel(network2) + node2 = null + + else if(reference==node3) + qdel(network3) + node3 = null + + update_underlays() + + return null \ No newline at end of file diff --git a/code/modules/atmospherics/components/tvalve.dm b/code/modules/atmospherics/components/tvalve.dm new file mode 100644 index 00000000..65e5384e --- /dev/null +++ b/code/modules/atmospherics/components/tvalve.dm @@ -0,0 +1,473 @@ +/obj/machinery/atmospherics/tvalve + icon = 'icons/atmos/tvalve.dmi' + icon_state = "map_tvalve0" + + name = "manual switching valve" + desc = "A pipe valve." + + level = 1 + dir = SOUTH + initialize_directions = SOUTH|NORTH|WEST + + var/state = 0 // 0 = go straight, 1 = go to side + + // like a trinary component, node1 is input, node2 is side output, node3 is straight output + var/obj/machinery/atmospherics/node3 + + var/datum/pipe_network/network_node1 + var/datum/pipe_network/network_node2 + var/datum/pipe_network/network_node3 + +/obj/machinery/atmospherics/tvalve/bypass + icon_state = "map_tvalve1" + state = 1 + +/obj/machinery/atmospherics/tvalve/update_icon(animation) + if(animation) + flick("tvalve[src.state][!src.state]",src) + else + icon_state = "tvalve[state]" + +/obj/machinery/atmospherics/tvalve/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + add_underlay(T, node1, turn(dir, -180)) + + if(istype(src, /obj/machinery/atmospherics/tvalve/mirrored)) + add_underlay(T, node2, turn(dir, 90)) + else + add_underlay(T, node2, turn(dir, -90)) + + add_underlay(T, node3, dir) + +/obj/machinery/atmospherics/tvalve/hide(var/i) + update_underlays() + +/obj/machinery/atmospherics/tvalve/New() + initialize_directions() + ..() + +/obj/machinery/atmospherics/tvalve/proc/initialize_directions() + switch(dir) + if(NORTH) + initialize_directions = SOUTH|NORTH|EAST + if(SOUTH) + initialize_directions = NORTH|SOUTH|WEST + if(EAST) + initialize_directions = WEST|EAST|SOUTH + if(WEST) + initialize_directions = EAST|WEST|NORTH + +/obj/machinery/atmospherics/tvalve/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(reference == node1) + network_node1 = new_network + if(state) + network_node2 = new_network + else + network_node3 = new_network + else if(reference == node2) + network_node2 = new_network + if(state) + network_node1 = new_network + else if(reference == node3) + network_node3 = new_network + if(!state) + network_node1 = new_network + + if(new_network.normal_members.Find(src)) + return 0 + + new_network.normal_members += src + + if(state) + if(reference == node1) + if(node2) + return node2.network_expand(new_network, src) + else if(reference == node2) + if(node1) + return node1.network_expand(new_network, src) + else + if(reference == node1) + if(node3) + return node3.network_expand(new_network, src) + else if(reference == node3) + if(node1) + return node1.network_expand(new_network, src) + + return null + +/obj/machinery/atmospherics/tvalve/Destroy() + loc = null + + if(node1) + node1.disconnect(src) + qdel(network_node1) + if(node2) + node2.disconnect(src) + qdel(network_node2) + if(node3) + node3.disconnect(src) + qdel(network_node3) + + node1 = null + node2 = null + node3 = null + + ..() + +/obj/machinery/atmospherics/tvalve/proc/go_to_side() + + if(state) return 0 + + state = 1 + update_icon() + + if(network_node1) + qdel(network_node1) + if(network_node3) + qdel(network_node3) + build_network() + + if(network_node1&&network_node2) + network_node1.merge(network_node2) + network_node2 = network_node1 + + if(network_node1) + network_node1.update = 1 + else if(network_node2) + network_node2.update = 1 + + return 1 + +/obj/machinery/atmospherics/tvalve/proc/go_straight() + + if(!state) + return 0 + + state = 0 + update_icon() + + if(network_node1) + qdel(network_node1) + if(network_node2) + qdel(network_node2) + build_network() + + if(network_node1&&network_node3) + network_node1.merge(network_node3) + network_node3 = network_node1 + + if(network_node1) + network_node1.update = 1 + else if(network_node3) + network_node3.update = 1 + + return 1 + +/obj/machinery/atmospherics/tvalve/attack_ai(mob/user as mob) + return + +/obj/machinery/atmospherics/tvalve/attack_hand(mob/user as mob) + src.add_fingerprint(usr) + update_icon(1) + sleep(10) + if (src.state) + src.go_straight() + else + src.go_to_side() + +/obj/machinery/atmospherics/tvalve/Process() + ..() + . = PROCESS_KILL + //machines.Remove(src) + + return + +/obj/machinery/atmospherics/tvalve/atmos_init() + ..() + var/node1_dir + var/node2_dir + var/node3_dir + + node1_dir = turn(dir, 180) + node2_dir = turn(dir, -90) + node3_dir = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node1 = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node2 = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,node3_dir)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node3 = target + break + + update_icon() + update_underlays() + +/obj/machinery/atmospherics/tvalve/build_network() + if(!network_node1 && node1) + network_node1 = new /datum/pipe_network() + network_node1.normal_members += src + network_node1.build_network(node1, src) + + if(!network_node2 && node2) + network_node2 = new /datum/pipe_network() + network_node2.normal_members += src + network_node2.build_network(node2, src) + + if(!network_node3 && node3) + network_node3 = new /datum/pipe_network() + network_node3.normal_members += src + network_node3.build_network(node3, src) + + +/obj/machinery/atmospherics/tvalve/return_network(obj/machinery/atmospherics/reference) + build_network() + + if(reference==node1) + return network_node1 + + if(reference==node2) + return network_node2 + + if(reference==node3) + return network_node3 + + return null + +/obj/machinery/atmospherics/tvalve/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network_node1 == old_network) + network_node1 = new_network + if(network_node2 == old_network) + network_node2 = new_network + if(network_node3 == old_network) + network_node3 = new_network + + return 1 + +/obj/machinery/atmospherics/tvalve/return_network_air(datum/network/reference) + return null + +/obj/machinery/atmospherics/tvalve/disconnect(obj/machinery/atmospherics/reference) + if(reference==node1) + qdel(network_node1) + node1 = null + + else if(reference==node2) + qdel(network_node2) + node2 = null + + else if(reference==node3) + qdel(network_node3) + node2 = null + + update_underlays() + + return null + +/obj/machinery/atmospherics/tvalve/digital // can be controlled by AI + name = "digital switching valve" + desc = "A digitally controlled valve." + icon = 'icons/atmos/digital_tvalve.dmi' + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + +/obj/machinery/atmospherics/tvalve/digital/bypass + icon_state = "map_tvalve1" + state = 1 + +/obj/machinery/atmospherics/tvalve/digital/update_icon() + ..() + if(!powered()) + icon_state = "tvalvenopower" + +/obj/machinery/atmospherics/tvalve/digital/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/atmospherics/tvalve/digital/attack_hand(mob/user as mob) + if(!powered()) + return + if(!src.allowed(user)) + to_chat(user, "Access denied.") + return + ..() + +//Radio remote control + +/obj/machinery/atmospherics/tvalve/digital/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) + + + +/obj/machinery/atmospherics/tvalve/digital/Initialize() + . = ..() + if(frequency) + set_frequency(frequency) + +/obj/machinery/atmospherics/tvalve/digital/receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id)) + return 0 + + switch(signal.data["command"]) + if("valve_open") + if(!state) + go_to_side() + + if("valve_close") + if(state) + go_straight() + + if("valve_toggle") + if(state) + go_straight() + else + go_to_side() + +/obj/machinery/atmospherics/tvalve/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(!isWrench(W)) + return ..() + if (istype(src, /obj/machinery/atmospherics/tvalve/digital)) + to_chat(user, "You cannot unwrench \the [src], it's too complicated.") + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + to_chat(user, "You cannot unwrench \the [src], it too exerted due to internal pressure.") + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to unfasten \the [src]...") + if (do_after(user, 40, src)) + user.visible_message( \ + "\The [user] unfastens \the [src].", \ + "You have unfastened \the [src].", \ + "You hear a ratchet.") + new /obj/item/pipe(loc, make_from=src) + qdel(src) + +/obj/machinery/atmospherics/tvalve/mirrored + icon_state = "map_tvalvem0" + +/obj/machinery/atmospherics/tvalve/mirrored/bypass + icon_state = "map_tvalvem1" + state = 1 + +/obj/machinery/atmospherics/tvalve/mirrored/initialize_directions() + switch(dir) + if(NORTH) + initialize_directions = SOUTH|NORTH|WEST + if(SOUTH) + initialize_directions = NORTH|SOUTH|EAST + if(EAST) + initialize_directions = WEST|EAST|NORTH + if(WEST) + initialize_directions = EAST|WEST|SOUTH + +/obj/machinery/atmospherics/tvalve/mirrored/atmos_init() + ..() + var/node1_dir + var/node2_dir + var/node3_dir + + node1_dir = turn(dir, 180) + node2_dir = turn(dir, 90) + node3_dir = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir)) + if(target.initialize_directions & get_dir(target,src)) + node2 = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,node3_dir)) + if(target.initialize_directions & get_dir(target,src)) + node3 = target + break + + update_icon() + update_underlays() + +/obj/machinery/atmospherics/tvalve/mirrored/update_icon(animation) + if(animation) + flick("tvalvem[src.state][!src.state]",src) + else + icon_state = "tvalvem[state]" + +/obj/machinery/atmospherics/tvalve/mirrored/digital // can be controlled by AI + name = "digital switching valve" + desc = "A digitally controlled valve." + icon = 'icons/atmos/digital_tvalve.dmi' + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + +/obj/machinery/atmospherics/tvalve/mirrored/digital/bypass + icon_state = "map_tvalvem1" + state = 1 + +/obj/machinery/atmospherics/tvalve/mirrored/digital/update_icon() + ..() + if(!powered()) + icon_state = "tvalvemnopower" + +/obj/machinery/atmospherics/tvalve/mirrored/digital/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/atmospherics/tvalve/mirrored/digital/attack_hand(mob/user as mob) + if(!powered()) + return + if(!src.allowed(user)) + to_chat(user, "Access denied.") + return + ..() + +//Radio remote control -eh? + +/obj/machinery/atmospherics/tvalve/mirrored/digital/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) + +/obj/machinery/atmospherics/tvalve/mirrored/digital/Initialize() + . = ..() + if(frequency) + set_frequency(frequency) + +/obj/machinery/atmospherics/tvalve/mirrored/digital/receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id)) + return 0 + + switch(signal.data["command"]) + if("valve_open") + if(!state) + go_to_side() + + if("valve_close") + if(state) + go_straight() + + if("valve_toggle") + if(state) + go_straight() + else + go_to_side() diff --git a/code/modules/atmospherics/components/unary/cold_sink.dm b/code/modules/atmospherics/components/unary/cold_sink.dm new file mode 100644 index 00000000..d09e1eae --- /dev/null +++ b/code/modules/atmospherics/components/unary/cold_sink.dm @@ -0,0 +1,188 @@ +//TODO: Put this under a common parent type with heaters to cut down on the copypasta +#define FREEZER_PERF_MULT 2.5 + +/obj/machinery/atmospherics/unary/freezer + name = "gas cooling system" + desc = "Cools gas when connected to a pipe network." + icon = 'icons/obj/Cryogenic2.dmi' + icon_state = "freezer_0" + density = 1 + anchored = 1 + use_power = 0 + idle_power_usage = 5 // 5 Watts for thermostat related circuitry + + var/heatsink_temperature = T20C // The constant temperature reservoir into which the freezer pumps heat. Probably the hull of the station or something. + var/internal_volume = 600 // L + + var/max_power_rating = 2500 // Power rating when the usage is turned up to 100 + var/power_setting = 100 + + var/set_temperature = T20C // Thermostat + var/cooling = 0 + +/obj/machinery/atmospherics/unary/freezer/New() + ..() + initialize_directions = dir + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/unary_atmos/cooler(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/capacitor(src) + component_parts += new /obj/item/weapon/stock_parts/capacitor(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/stack/cable_coil(src, 2) + RefreshParts() + +/obj/machinery/atmospherics/unary/freezer/atmos_init() + ..() + if(node) + return + + var/node_connect = dir + + for(var/obj/machinery/atmospherics/target in get_step(src, node_connect)) + if(target.initialize_directions & get_dir(target, src)) + node = target + break + + //copied from pipe construction code since heaters/freezers don't use fittings and weren't doing this check - this all really really needs to be refactored someday. + //check that there are no incompatible pipes/machinery in our own location + for(var/obj/machinery/atmospherics/M in src.loc) + if(M != src && (M.initialize_directions & node_connect) && M.check_connect_types(M,src)) // matches at least one direction on either type of pipe & same connection type + node = null + break + + update_icon() + +/obj/machinery/atmospherics/unary/freezer/update_icon() + if(node) + if(use_power && cooling) + icon_state = "freezer_1" + else + icon_state = "freezer" + else + icon_state = "freezer_0" + return + +/obj/machinery/atmospherics/unary/freezer/attack_ai(mob/user as mob) + ui_interact(user) + +/obj/machinery/atmospherics/unary/freezer/attack_hand(mob/user as mob) + ui_interact(user) + +/obj/machinery/atmospherics/unary/freezer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + // this is the data which will be sent to the ui + var/data[0] + data["on"] = use_power ? 1 : 0 + data["gasPressure"] = round(air_contents.return_pressure()) + data["gasTemperature"] = round(air_contents.temperature) + data["minGasTemperature"] = 0 + data["maxGasTemperature"] = round(T20C+500) + data["targetGasTemperature"] = round(set_temperature) + data["powerSetting"] = power_setting + + var/temp_class = "good" + if(air_contents.temperature > (T0C - 20)) + temp_class = "bad" + else if(air_contents.temperature < (T0C - 20) && air_contents.temperature > (T0C - 100)) + temp_class = "average" + data["gasTemperatureClass"] = temp_class + + // update the ui if it exists, returns null if no ui is passed/found + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "freezer.tmpl", "Gas Cooling System", 440, 300) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(1) + +/obj/machinery/atmospherics/unary/freezer/Topic(href, href_list) + if(..()) + return 1 + if(href_list["toggleStatus"]) + use_power = !use_power + update_icon() + if(href_list["temp"]) + var/amount = text2num(href_list["temp"]) + if(amount > 0) + set_temperature = min(set_temperature + amount, 1000) + else + set_temperature = max(set_temperature + amount, 0) + if(href_list["setPower"]) //setting power to 0 is redundant anyways + var/new_setting = between(0, text2num(href_list["setPower"]), 100) + set_power_level(new_setting) + + add_fingerprint(usr) + +/obj/machinery/atmospherics/unary/freezer/Process() + ..() + + if(stat & (NOPOWER|BROKEN) || !use_power) + cooling = 0 + update_icon() + return + + if(network && air_contents.temperature > set_temperature) + cooling = 1 + + var/heat_transfer = max( -air_contents.get_thermal_energy_change(set_temperature - 5), 0 ) + + //Assume the heat is being pumped into the hull which is fixed at heatsink_temperature + //not /really/ proper thermodynamics but whatever + var/cop = FREEZER_PERF_MULT * air_contents.temperature/heatsink_temperature //heatpump coefficient of performance from thermodynamics -> power used = heat_transfer/cop + heat_transfer = min(heat_transfer, cop * power_rating) //limit heat transfer by available power + + var/removed = -air_contents.add_thermal_energy(-heat_transfer) //remove the heat + if(debug) + visible_message("[src]: Removing [removed] W.") + + use_power(power_rating) + + network.update = 1 + else + cooling = 0 + + update_icon() + +//upgrading parts +/obj/machinery/atmospherics/unary/freezer/RefreshParts() + ..() + var/cap_rating = 0 + var/manip_rating = 0 + var/bin_rating = 0 + + for(var/obj/item/weapon/stock_parts/P in component_parts) + if(istype(P, /obj/item/weapon/stock_parts/capacitor)) + cap_rating += P.rating + if(istype(P, /obj/item/weapon/stock_parts/manipulator)) + manip_rating += P.rating + if(istype(P, /obj/item/weapon/stock_parts/matter_bin)) + bin_rating += P.rating + + power_rating = initial(power_rating) * cap_rating / 2 //more powerful + heatsink_temperature = initial(heatsink_temperature) / ((manip_rating + bin_rating) / 2) //more efficient + air_contents.volume = max(initial(internal_volume) - 200, 0) + 200 * bin_rating + set_power_level(power_setting) + +/obj/machinery/atmospherics/unary/freezer/proc/set_power_level(var/new_power_setting) + power_setting = new_power_setting + power_rating = max_power_rating * (power_setting/100) + +/obj/machinery/atmospherics/unary/freezer/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(default_deconstruction_screwdriver(user, O)) + return + if(default_deconstruction_crowbar(user, O)) + return + if(default_part_replacement(user, O)) + return + + ..() + +/obj/machinery/atmospherics/unary/freezer/examine(mob/user) + . = ..(user) + if(panel_open) + to_chat(user, "The maintenance hatch is open.") diff --git a/code/modules/atmospherics/components/unary/generator_input.dm b/code/modules/atmospherics/components/unary/generator_input.dm new file mode 100644 index 00000000..a48724ca --- /dev/null +++ b/code/modules/atmospherics/components/unary/generator_input.dm @@ -0,0 +1,21 @@ +/obj/machinery/atmospherics/unary/generator_input + icon = 'icons/obj/atmospherics/heat_exchanger.dmi' + icon_state = "intact" + density = 1 + + name = "Generator Input" + desc = "Placeholder." + + var/update_cycle + + update_icon() + if(node) + icon_state = "intact" + else + icon_state = "exposed" + + return + + proc + return_exchange_air() + return air_contents \ No newline at end of file diff --git a/code/modules/atmospherics/components/unary/heat_exchanger.dm b/code/modules/atmospherics/components/unary/heat_exchanger.dm new file mode 100644 index 00000000..a7733b82 --- /dev/null +++ b/code/modules/atmospherics/components/unary/heat_exchanger.dm @@ -0,0 +1,90 @@ +/obj/machinery/atmospherics/unary/heat_exchanger + + icon = 'icons/obj/atmospherics/heat_exchanger.dmi' + icon_state = "intact" + density = 1 + + name = "Heat Exchanger" + desc = "Exchanges heat between two input gases. Setup for fast heat transfer." + + var/obj/machinery/atmospherics/unary/heat_exchanger/partner = null + var/update_cycle + + update_icon() + if(node) + icon_state = "intact" + else + icon_state = "exposed" + + return + + atmos_init() + ..() + if(!partner) + var/partner_connect = turn(dir,180) + + for(var/obj/machinery/atmospherics/unary/heat_exchanger/target in get_step(src,partner_connect)) + if(target.dir & get_dir(src,target)) + partner = target + partner.partner = src + break + + ..() + + Process() + ..() + if(!partner) + return 0 + + if(SSair.times_fired <= update_cycle) + return 0 + + update_cycle = SSair.times_fired + partner.update_cycle = SSair.times_fired + + var/air_heat_capacity = air_contents.heat_capacity() + var/other_air_heat_capacity = partner.air_contents.heat_capacity() + var/combined_heat_capacity = other_air_heat_capacity + air_heat_capacity + + var/old_temperature = air_contents.temperature + var/other_old_temperature = partner.air_contents.temperature + + if(combined_heat_capacity > 0) + var/combined_energy = partner.air_contents.temperature*other_air_heat_capacity + air_heat_capacity*air_contents.temperature + + var/new_temperature = combined_energy/combined_heat_capacity + air_contents.temperature = new_temperature + partner.air_contents.temperature = new_temperature + + if(network) + if(abs(old_temperature-air_contents.temperature) > 1) + network.update = 1 + + if(partner.network) + if(abs(other_old_temperature-partner.air_contents.temperature) > 1) + partner.network.update = 1 + + return 1 + + attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(!isWrench(W)) + return ..() + var/turf/T = src.loc + if (level==1 && isturf(T) && !T.is_plating()) + to_chat(user, "You must remove the plating first.") + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.") + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to unfasten \the [src]...") + if (do_after(user, 40, src)) + user.visible_message( \ + "\The [user] unfastens \the [src].", \ + "You have unfastened \the [src].", \ + "You hear a ratchet.") + new /obj/item/pipe(loc, make_from=src) + qdel(src) diff --git a/code/modules/atmospherics/components/unary/heat_source.dm b/code/modules/atmospherics/components/unary/heat_source.dm new file mode 100644 index 00000000..902a7584 --- /dev/null +++ b/code/modules/atmospherics/components/unary/heat_source.dm @@ -0,0 +1,176 @@ +//TODO: Put this under a common parent type with freezers to cut down on the copypasta +#define HEATER_PERF_MULT 2.5 + +/obj/machinery/atmospherics/unary/heater + name = "gas heating system" + desc = "Heats gas when connected to a pipe network." + icon = 'icons/obj/Cryogenic2.dmi' + icon_state = "heater_0" + density = 1 + anchored = 1 + use_power = 0 + idle_power_usage = 5 //5 Watts for thermostat related circuitry + + var/max_temperature = T20C + 680 + var/internal_volume = 600 //L + + var/max_power_rating = 2500 //power rating when the usage is turned up to 100 + var/power_setting = 100 + + var/set_temperature = T20C //thermostat + var/heating = 0 //mainly for icon updates + +/obj/machinery/atmospherics/unary/heater/New() + ..() + initialize_directions = dir + + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/unary_atmos/heater(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/capacitor(src) + component_parts += new /obj/item/weapon/stock_parts/capacitor(src) + component_parts += new /obj/item/stack/cable_coil(src, 5) + + RefreshParts() + +/obj/machinery/atmospherics/unary/heater/atmos_init() + ..() + if(node) + return + + var/node_connect = dir + + //check that there is something to connect to + for(var/obj/machinery/atmospherics/target in get_step(src, node_connect)) + if(target.initialize_directions & get_dir(target, src)) + node = target + break + + //copied from pipe construction code since heaters/freezers don't use fittings and weren't doing this check - this all really really needs to be refactored someday. + //check that there are no incompatible pipes/machinery in our own location + for(var/obj/machinery/atmospherics/M in src.loc) + if(M != src && (M.initialize_directions & node_connect) && M.check_connect_types(M,src)) // matches at least one direction on either type of pipe & same connection type + node = null + break + + update_icon() + + +/obj/machinery/atmospherics/unary/heater/update_icon() + if(node) + if(use_power && heating) + icon_state = "heater_1" + else + icon_state = "heater" + else + icon_state = "heater_0" + return + + +/obj/machinery/atmospherics/unary/heater/Process() + ..() + + if(stat & (NOPOWER|BROKEN) || !use_power) + heating = 0 + update_icon() + return + + if(network && air_contents.total_moles && air_contents.temperature < set_temperature) + air_contents.add_thermal_energy(power_rating * HEATER_PERF_MULT) + use_power(power_rating) + + heating = 1 + network.update = 1 + else + heating = 0 + + update_icon() + +/obj/machinery/atmospherics/unary/heater/attack_ai(mob/user as mob) + ui_interact(user) + +/obj/machinery/atmospherics/unary/heater/attack_hand(mob/user as mob) + ui_interact(user) + +/obj/machinery/atmospherics/unary/heater/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + // this is the data which will be sent to the ui + var/data[0] + data["on"] = use_power ? 1 : 0 + data["gasPressure"] = round(air_contents.return_pressure()) + data["gasTemperature"] = round(air_contents.temperature) + data["minGasTemperature"] = 0 + data["maxGasTemperature"] = round(max_temperature) + data["targetGasTemperature"] = round(set_temperature) + data["powerSetting"] = power_setting + + var/temp_class = "normal" + if(air_contents.temperature > (T20C+40)) + temp_class = "bad" + data["gasTemperatureClass"] = temp_class + + // update the ui if it exists, returns null if no ui is passed/found + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "freezer.tmpl", "Gas Heating System", 440, 300) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(1) + +/obj/machinery/atmospherics/unary/heater/Topic(href, href_list) + if(..()) + return 1 + if(href_list["toggleStatus"]) + use_power = !use_power + update_icon() + if(href_list["temp"]) + var/amount = text2num(href_list["temp"]) + if(amount > 0) + set_temperature = min(set_temperature + amount, max_temperature) + else + set_temperature = max(set_temperature + amount, 0) + if(href_list["setPower"]) //setting power to 0 is redundant anyways + var/new_setting = between(0, text2num(href_list["setPower"]), 100) + set_power_level(new_setting) + + add_fingerprint(usr) + +//upgrading parts +/obj/machinery/atmospherics/unary/heater/RefreshParts() + ..() + var/cap_rating = 0 + var/bin_rating = 0 + + for(var/obj/item/weapon/stock_parts/P in component_parts) + if(istype(P, /obj/item/weapon/stock_parts/capacitor)) + cap_rating += P.rating + if(istype(P, /obj/item/weapon/stock_parts/matter_bin)) + bin_rating += P.rating + + max_power_rating = initial(max_power_rating) * cap_rating / 2 + max_temperature = max(initial(max_temperature) - T20C, 0) * ((bin_rating * 4 + cap_rating) / 5) + T20C + air_contents.volume = max(initial(internal_volume) - 200, 0) + 200 * bin_rating + set_power_level(power_setting) + +/obj/machinery/atmospherics/unary/heater/proc/set_power_level(var/new_power_setting) + power_setting = new_power_setting + power_rating = max_power_rating * (power_setting/100) + +/obj/machinery/atmospherics/unary/heater/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(default_deconstruction_screwdriver(user, O)) + return + if(default_deconstruction_crowbar(user, O)) + return + if(default_part_replacement(user, O)) + return + + ..() + +/obj/machinery/atmospherics/unary/heater/examine(mob/user) + . = ..(user) + if(panel_open) + to_chat(user, "The maintenance hatch is open.") diff --git a/code/modules/atmospherics/components/unary/outlet_injector.dm b/code/modules/atmospherics/components/unary/outlet_injector.dm new file mode 100644 index 00000000..f9cf0de9 --- /dev/null +++ b/code/modules/atmospherics/components/unary/outlet_injector.dm @@ -0,0 +1,146 @@ +//Basically a one way passive valve. If the pressure inside is greater than the environment then gas will flow passively, +//but it does not permit gas to flow back from the environment into the injector. Can be turned off to prevent any gas flow. +//When it receives the "inject" signal, it will try to pump it's entire contents into the environment regardless of pressure, using power. + +/obj/machinery/atmospherics/unary/outlet_injector + icon = 'icons/atmos/injector.dmi' + icon_state = "map_injector" + + name = "air injector" + desc = "Passively injects air into its surroundings. Has a valve attached to it that can control flow rate." + + use_power = 0 + idle_power_usage = 150 //internal circuitry, friction losses and stuff + power_rating = 15000 //15000 W ~ 20 HP + + var/injecting = 0 + + var/volume_rate = 50 //flow rate limit + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + + level = 1 + +/obj/machinery/atmospherics/unary/outlet_injector/New() + ..() + air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 500 //Give it a small reservoir for injecting. Also allows it to have a higher flow rate limit than vent pumps, to differentiate injectors a bit more. + +/obj/machinery/atmospherics/unary/outlet_injector/update_icon() + if(!powered()) + icon_state = "off" + else + icon_state = "[use_power ? "on" : "off"]" + +/obj/machinery/atmospherics/unary/outlet_injector/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + add_underlay(T, node, dir) + +/obj/machinery/atmospherics/unary/outlet_injector/Process() + ..() + + last_power_draw = 0 + last_flow_rate = 0 + + if((stat & (NOPOWER|BROKEN)) || !use_power) + return + + var/power_draw = -1 + var/datum/gas_mixture/environment = loc.return_air() + + if(environment && air_contents.temperature > 0) + var/transfer_moles = (volume_rate/air_contents.volume)*air_contents.total_moles //apply flow rate limit + power_draw = pump_gas(src, air_contents, environment, transfer_moles, power_rating) + + if (power_draw >= 0) + last_power_draw = power_draw + use_power(power_draw) + + if(network) + network.update = 1 + + return 1 + +/obj/machinery/atmospherics/unary/outlet_injector/proc/inject() + if(injecting || (stat & NOPOWER)) + return 0 + + var/datum/gas_mixture/environment = loc.return_air() + if (!environment) + return 0 + + injecting = 1 + + if(air_contents.temperature > 0) + var/power_used = pump_gas(src, air_contents, environment, air_contents.total_moles, power_rating) + use_power(power_used) + + if(network) + network.update = 1 + + flick("inject", src) + +/obj/machinery/atmospherics/unary/outlet_injector/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency) + +/obj/machinery/atmospherics/unary/outlet_injector/proc/broadcast_status() + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data = list( + "tag" = id, + "device" = "AO", + "power" = use_power, + "volume_rate" = volume_rate, + "sigtype" = "status" + ) + + radio_connection.post_signal(src, signal) + + return 1 + +/obj/machinery/atmospherics/unary/outlet_injector/Initialize() + . = ..() + set_frequency(frequency) + +/obj/machinery/atmospherics/unary/outlet_injector/receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) + return 0 + + if(signal.data["power"]) + use_power = text2num(signal.data["power"]) + + if(signal.data["power_toggle"]) + use_power = !use_power + + if(signal.data["inject"]) + spawn inject() + return + + if(signal.data["set_volume_rate"]) + var/number = text2num(signal.data["set_volume_rate"]) + volume_rate = between(0, number, air_contents.volume) + + if(signal.data["status"]) + spawn(2) + broadcast_status() + return //do not update_icon + + spawn(2) + broadcast_status() + update_icon() + +/obj/machinery/atmospherics/unary/outlet_injector/hide(var/i) + update_underlays() \ No newline at end of file diff --git a/code/modules/atmospherics/components/unary/oxygen_generator.dm b/code/modules/atmospherics/components/unary/oxygen_generator.dm new file mode 100644 index 00000000..4f78fd22 --- /dev/null +++ b/code/modules/atmospherics/components/unary/oxygen_generator.dm @@ -0,0 +1,49 @@ +obj/machinery/atmospherics/unary/oxygen_generator + icon = 'icons/obj/atmospherics/oxygen_generator.dmi' + icon_state = "intact_off" + density = 1 + + name = "Oxygen Generator" + desc = "" + + dir = SOUTH + initialize_directions = SOUTH + + var/on = 0 + + var/oxygen_content = 10 + + update_icon() + if(node) + icon_state = "intact_[on?("on"):("off")]" + else + icon_state = "exposed_off" + + on = 0 + + return + + New() + ..() + + air_contents.volume = 50 + + Process() + ..() + if(!on) + return 0 + + var/total_moles = air_contents.total_moles + + if(total_moles < oxygen_content) + var/current_heat_capacity = air_contents.heat_capacity() + + var/added_oxygen = oxygen_content - total_moles + + air_contents.temperature = (current_heat_capacity*air_contents.temperature + 20*added_oxygen*T0C)/(current_heat_capacity+20*added_oxygen) + air_contents.adjust_gas("oxygen", added_oxygen) + + if(network) + network.update = 1 + + return 1 \ No newline at end of file diff --git a/code/modules/atmospherics/components/unary/thermal_plate.dm b/code/modules/atmospherics/components/unary/thermal_plate.dm new file mode 100644 index 00000000..b5f668e2 --- /dev/null +++ b/code/modules/atmospherics/components/unary/thermal_plate.dm @@ -0,0 +1,81 @@ +#define RADIATION_CAPACITY 30000 //Radiation isn't particularly effective (TODO BALANCE) + + +/obj/machinery/atmospherics/unary/thermal_plate +//Based off Heat Reservoir and Space Heater +//Transfers heat between a pipe system and environment, based on which has a greater thermal energy concentration + + icon = 'icons/obj/atmospherics/cold_sink.dmi' + icon_state = "intact_off" + + name = "Thermal Transfer Plate" + desc = "Transfers heat to and from an area" + + update_icon() + if(node) + icon_state = "intact_off" + else + icon_state = "exposed" + return + + Process() + ..() + + var/datum/gas_mixture/environment = loc.return_air() + + //Get processable air sample and thermal info from environment + + var/transfer_moles = 0.25 * environment.get_total_moles() + var/datum/gas_mixture/external_removed = environment.remove(transfer_moles) + + if (!external_removed) + return radiate() + + if (external_removed.get_total_moles() < 10) + return radiate() + + //Get same info from connected gas + + var/internal_transfer_moles = 0.25 * air_contents.get_total_moles() + var/datum/gas_mixture/internal_removed = air_contents.remove(internal_transfer_moles) + + if (!internal_removed) + environment.merge(external_removed) + return 1 + + var/combined_heat_capacity = internal_removed.heat_capacity() + external_removed.heat_capacity() + var/combined_energy = internal_removed.temperature * internal_removed.heat_capacity() + external_removed.heat_capacity() * external_removed.temperature + + if(!combined_heat_capacity) combined_heat_capacity = 1 + var/final_temperature = combined_energy / combined_heat_capacity + + external_removed.temperature = final_temperature + environment.merge(external_removed) + + internal_removed.temperature = final_temperature + air_contents.merge(internal_removed) + + network.update = 1 + + return 1 + + proc/radiate() + + var/internal_transfer_moles = 0.25 * air_contents.get_total_moles() + var/datum/gas_mixture/internal_removed = air_contents.remove(internal_transfer_moles) + + if (!internal_removed) + return 1 + + var/combined_heat_capacity = internal_removed.heat_capacity() + RADIATION_CAPACITY + var/combined_energy = internal_removed.temperature * internal_removed.heat_capacity() + (RADIATION_CAPACITY * 6.4) + + var/final_temperature = combined_energy / combined_heat_capacity + + internal_removed.temperature = final_temperature + air_contents.merge(internal_removed) + + if (network) + network.update = 1 + + return 1 \ No newline at end of file diff --git a/code/modules/atmospherics/components/unary/unary_base.dm b/code/modules/atmospherics/components/unary/unary_base.dm new file mode 100644 index 00000000..e4690185 --- /dev/null +++ b/code/modules/atmospherics/components/unary/unary_base.dm @@ -0,0 +1,95 @@ +/obj/machinery/atmospherics/unary + dir = SOUTH + initialize_directions = SOUTH + + layer = ABOVE_TILE_LAYER + + var/datum/gas_mixture/air_contents + + var/obj/machinery/atmospherics/node + + var/datum/pipe_network/network + + New() + ..() + initialize_directions = dir + air_contents = new + + air_contents.volume = 200 + +// Housekeeping and pipe network stuff below + network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(reference == node) + network = new_network + + if(new_network.normal_members.Find(src)) + return 0 + + new_network.normal_members += src + + return null + + Destroy() + loc = null + + if(node) + node.disconnect(src) + qdel(network) + + node = null + + . = ..() + + atmos_init() + ..() + if(node) return + + var/node_connect = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,node_connect)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node = target + break + + update_icon() + update_underlays() + + build_network() + if(!network && node) + network = new /datum/pipe_network() + network.normal_members += src + network.build_network(node, src) + + + return_network(obj/machinery/atmospherics/reference) + build_network() + + if(reference==node) + return network + + return null + + reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network == old_network) + network = new_network + + return 1 + + return_network_air(datum/pipe_network/reference) + var/list/results = list() + + if(network == reference) + results += air_contents + + return results + + disconnect(obj/machinery/atmospherics/reference) + if(reference==node) + qdel(network) + node = null + + update_icon() + update_underlays() + + return null \ No newline at end of file diff --git a/code/modules/atmospherics/components/unary/vent_pump.dm b/code/modules/atmospherics/components/unary/vent_pump.dm new file mode 100644 index 00000000..036a2892 --- /dev/null +++ b/code/modules/atmospherics/components/unary/vent_pump.dm @@ -0,0 +1,412 @@ +#define DEFAULT_PRESSURE_DELTA 10000 + +#define EXTERNAL_PRESSURE_BOUND ONE_ATMOSPHERE +#define INTERNAL_PRESSURE_BOUND 0 +#define PRESSURE_CHECKS 1 + +#define PRESSURE_CHECK_EXTERNAL 1 +#define PRESSURE_CHECK_INTERNAL 2 + +/obj/machinery/atmospherics/unary/vent_pump + icon = 'icons/atmos/vent_pump.dmi' + icon_state = "map_vent" + + name = "Air Vent" + desc = "Has a valve and pump attached to it." + use_power = 0 + idle_power_usage = 150 //internal circuitry, friction losses and stuff + power_rating = 7500 //7500 W ~ 10 HP + + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY //connects to regular and supply pipes + + var/area/initial_loc + level = 1 + var/area_uid + var/id_tag = null + + var/hibernate = 0 //Do we even process? + var/pump_direction = 1 //0 = siphoning, 1 = releasing + + var/external_pressure_bound = EXTERNAL_PRESSURE_BOUND + var/internal_pressure_bound = INTERNAL_PRESSURE_BOUND + + var/pressure_checks = PRESSURE_CHECKS + //1: Do not pass external_pressure_bound + //2: Do not pass internal_pressure_bound + //3: Do not pass either + + // Used when handling incoming radio signals requesting default settings + var/external_pressure_bound_default = EXTERNAL_PRESSURE_BOUND + var/internal_pressure_bound_default = INTERNAL_PRESSURE_BOUND + var/pressure_checks_default = PRESSURE_CHECKS + + var/welded = 0 // Added for aliens -- TLE + + var/frequency = 1439 + var/datum/radio_frequency/radio_connection + + var/radio_filter_out + var/radio_filter_in + +/obj/machinery/atmospherics/unary/vent_pump/on + use_power = 1 + icon_state = "map_vent_out" + +/obj/machinery/atmospherics/unary/vent_pump/siphon + pump_direction = 0 + +/obj/machinery/atmospherics/unary/vent_pump/siphon/on + use_power = 1 + icon_state = "map_vent_in" + +/obj/machinery/atmospherics/unary/vent_pump/siphon/on/atmos + use_power = 1 + icon_state = "map_vent_in" + external_pressure_bound = 0 + external_pressure_bound_default = 0 + internal_pressure_bound = MAX_PUMP_PRESSURE + internal_pressure_bound_default = MAX_PUMP_PRESSURE + pressure_checks = 2 + pressure_checks_default = 2 + +/obj/machinery/atmospherics/unary/vent_pump/New() + ..() + air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + icon = null + +/obj/machinery/atmospherics/unary/vent_pump/Destroy() + unregister_radio(src, frequency) + if(initial_loc) + initial_loc.air_vent_info -= id_tag + initial_loc.air_vent_names -= id_tag + . = ..() + +/obj/machinery/atmospherics/unary/vent_pump/high_volume + name = "Large Air Vent" + power_channel = EQUIP + power_rating = 15000 //15 kW ~ 20 HP + +/obj/machinery/atmospherics/unary/vent_pump/high_volume/New() + ..() + air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800 + +/obj/machinery/atmospherics/unary/vent_pump/engine + name = "Engine Core Vent" + power_channel = ENVIRON + power_rating = 30000 //15 kW ~ 20 HP + +/obj/machinery/atmospherics/unary/vent_pump/engine/New() + ..() + air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 500 //meant to match air injector + +/obj/machinery/atmospherics/unary/vent_pump/update_icon(var/safety = 0) + if(!check_icon_cache()) + return + if (!node) + use_power = 0 + + overlays.Cut() + + var/vent_icon = "vent" + + var/turf/T = get_turf(src) + if(!istype(T)) + return + + if(!T.is_plating() && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe)) + vent_icon += "h" + + if(welded) + vent_icon += "weld" + else if(!powered()) + vent_icon += "off" + else + vent_icon += "[use_power ? "[pump_direction ? "out" : "in"]" : "off"]" + + overlays += icon_manager.get_atmos_icon("device", , , vent_icon) + +/obj/machinery/atmospherics/unary/vent_pump/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + if(!T.is_plating() && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe)) + return + else + if(node) + add_underlay(T, node, dir, node.icon_connect_type) + else + add_underlay(T,, dir) + +/obj/machinery/atmospherics/unary/vent_pump/hide() + update_icon() + update_underlays() + +/obj/machinery/atmospherics/unary/vent_pump/proc/can_pump() + if(stat & (NOPOWER|BROKEN)) + return 0 + if(!use_power) + return 0 + if(welded) + return 0 + return 1 + +/obj/machinery/atmospherics/unary/vent_pump/Process() + ..() + + if (hibernate > world.time) + return 1 + + if (!node) + use_power = 0 + if(!can_pump()) + return 0 + + var/datum/gas_mixture/environment = loc.return_air() + + var/power_draw = -1 + + //Figure out the target pressure difference + var/pressure_delta = get_pressure_delta(environment) + //src.visible_message("DEBUG >>> [src]: pressure_delta = [pressure_delta]") + + if((environment.temperature || air_contents.temperature) && pressure_delta > 0.5) + if(pump_direction) //internal -> external + var/transfer_moles = calculate_transfer_moles(air_contents, environment, pressure_delta) + power_draw = pump_gas(src, air_contents, environment, transfer_moles, power_rating) + else //external -> internal + var/transfer_moles = calculate_transfer_moles(environment, air_contents, pressure_delta, (network)? network.volume : 0) + + //limit flow rate from turfs + transfer_moles = min(transfer_moles, environment.total_moles*air_contents.volume/environment.volume) //group_multiplier gets divided out here + power_draw = pump_gas(src, environment, air_contents, transfer_moles, power_rating) + + else + //If we're in an area that is fucking ideal, and we don't have to do anything, chances are we won't next tick either so why redo these calculations? + //JESUS FUCK. THERE ARE LITERALLY 250 OF YOU MOTHERFUCKERS ON ZLEVEL ONE AND YOU DO THIS SHIT EVERY TICK WHEN VERY OFTEN THERE IS NO REASON TO + if(pump_direction && pressure_checks == PRESSURE_CHECK_EXTERNAL) //99% of all vents + hibernate = world.time + (rand(100,200)) + + + if (power_draw >= 0) + last_power_draw = power_draw + use_power(power_draw) + if(network) + network.update = 1 + + return 1 + +/obj/machinery/atmospherics/unary/vent_pump/proc/get_pressure_delta(datum/gas_mixture/environment) + var/pressure_delta = DEFAULT_PRESSURE_DELTA + var/environment_pressure = environment.return_pressure() + + if(pump_direction) //internal -> external + if(pressure_checks & PRESSURE_CHECK_EXTERNAL) + pressure_delta = min(pressure_delta, external_pressure_bound - environment_pressure) //increasing the pressure here + if(pressure_checks & PRESSURE_CHECK_INTERNAL) + pressure_delta = min(pressure_delta, air_contents.return_pressure() - internal_pressure_bound) //decreasing the pressure here + else //external -> internal + if(pressure_checks & PRESSURE_CHECK_EXTERNAL) + pressure_delta = min(pressure_delta, environment_pressure - external_pressure_bound) //decreasing the pressure here + if(pressure_checks & PRESSURE_CHECK_INTERNAL) + pressure_delta = min(pressure_delta, internal_pressure_bound - air_contents.return_pressure()) //increasing the pressure here + + return pressure_delta + +/obj/machinery/atmospherics/unary/vent_pump/proc/broadcast_status() + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data = list( + "area" = src.area_uid, + "tag" = src.id_tag, + "device" = "AVP", + "power" = use_power, + "direction" = pump_direction?("release"):("siphon"), + "checks" = pressure_checks, + "internal" = internal_pressure_bound, + "external" = external_pressure_bound, + "timestamp" = world.time, + "sigtype" = "status", + "power_draw" = last_power_draw, + "flow_rate" = last_flow_rate, + ) + + if(!initial_loc.air_vent_names[id_tag]) + var/new_name = "[initial_loc.name] Vent Pump #[initial_loc.air_vent_names.len+1]" + initial_loc.air_vent_names[id_tag] = new_name + src.SetName(new_name) + initial_loc.air_vent_info[id_tag] = signal.data + + radio_connection.post_signal(src, signal, radio_filter_out) + + return 1 + + +/obj/machinery/atmospherics/unary/vent_pump/Initialize() + . = ..() + initial_loc = get_area(loc) + area_uid = initial_loc.uid + if (!id_tag) + assign_uid() + id_tag = num2text(uid) + //some vents work his own special way + radio_filter_in = frequency==1439?(RADIO_FROM_AIRALARM):null + radio_filter_out = frequency==1439?(RADIO_TO_AIRALARM):null + if(frequency) + radio_connection = register_radio(src, frequency, frequency, radio_filter_in) + src.broadcast_status() + +/obj/machinery/atmospherics/unary/vent_pump/receive_signal(datum/signal/signal) + if(stat & (NOPOWER|BROKEN)) + return + + hibernate = 0 + + //log_admin("DEBUG \[[world.timeofday]\]: /obj/machinery/atmospherics/unary/vent_pump/receive_signal([signal.debug_print()])") + if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command")) + return 0 + + if(signal.data["purge"] != null) + pressure_checks &= ~1 + pump_direction = 0 + + if(signal.data["stabalize"] != null) + pressure_checks |= 1 + pump_direction = 1 + + if(signal.data["power"] != null) + use_power = text2num(signal.data["power"]) + + if(signal.data["power_toggle"] != null) + use_power = !use_power + + if(signal.data["checks"] != null) + if (signal.data["checks"] == "default") + pressure_checks = pressure_checks_default + else + pressure_checks = text2num(signal.data["checks"]) + + if(signal.data["checks_toggle"] != null) + pressure_checks = (pressure_checks?0:3) + + if(signal.data["direction"] != null) + pump_direction = text2num(signal.data["direction"]) + + if(signal.data["set_internal_pressure"] != null) + if (signal.data["set_internal_pressure"] == "default") + internal_pressure_bound = internal_pressure_bound_default + else + internal_pressure_bound = between(0,text2num(signal.data["set_internal_pressure"]), MAX_PUMP_PRESSURE) + + if(signal.data["set_external_pressure"] != null) + if (signal.data["set_external_pressure"] == "default") + external_pressure_bound = external_pressure_bound_default + else + external_pressure_bound = between(0,text2num(signal.data["set_external_pressure"]),MAX_PUMP_PRESSURE) + + if(signal.data["adjust_internal_pressure"] != null) + internal_pressure_bound = between(0,internal_pressure_bound + text2num(signal.data["adjust_internal_pressure"]),MAX_PUMP_PRESSURE) + + if(signal.data["adjust_external_pressure"] != null) + external_pressure_bound = between(0,external_pressure_bound + text2num(signal.data["adjust_external_pressure"]),MAX_PUMP_PRESSURE) + + if(signal.data["init"] != null) + SetName(signal.data["init"]) + return + + if(signal.data["status"] != null) + spawn(2) + broadcast_status() + return //do not update_icon + + //log_admin("DEBUG \[[world.timeofday]\]: vent_pump/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]") + spawn(2) + broadcast_status() + update_icon() + return + +/obj/machinery/atmospherics/unary/vent_pump/attackby(obj/item/W, mob/user) + if(isWelder(W)) + + var/obj/item/weapon/weldingtool/WT = W + + if(!WT.isOn()) + to_chat(user, "The welding tool needs to be on to start this task.") + return 1 + + if(!WT.remove_fuel(0,user)) + to_chat(user, "You need more welding fuel to complete this task.") + return 1 + + to_chat(user, "Now welding \the [src].") + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + + if(!do_after(user, 20, src)) + to_chat(user, "You must remain close to finish this task.") + return 1 + + if(!src) + return 1 + + if(!WT.isOn()) + to_chat(user, "The welding tool needs to be on to finish this task.") + return 1 + + welded = !welded + update_icon() + user.visible_message("\The [user] [welded ? "welds \the [src] shut" : "unwelds \the [src]"].", \ + "You [welded ? "weld \the [src] shut" : "unweld \the [src]"].", \ + "You hear welding.") + return 1 + + else + ..() + +/obj/machinery/atmospherics/unary/vent_pump/examine(mob/user) + if(..(user, 1)) + to_chat(user, "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W") + else + to_chat(user, "You are too far away to read the gauge.") + if(welded) + to_chat(user, "It seems welded shut.") + +/obj/machinery/atmospherics/unary/vent_pump/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(!isWrench(W)) + return ..() + if (!(stat & NOPOWER) && use_power) + to_chat(user, "You cannot unwrench \the [src], turn it off first.") + return 1 + var/turf/T = src.loc + if (node && node.level==1 && isturf(T) && !T.is_plating()) + to_chat(user, "You must remove the plating first.") + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.") + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to unfasten \the [src]...") + if (do_after(user, 40, src)) + user.visible_message( \ + "\The [user] unfastens \the [src].", \ + "You have unfastened \the [src].", \ + "You hear a ratchet.") + new /obj/item/pipe(loc, make_from=src) + qdel(src) + +#undef DEFAULT_PRESSURE_DELTA + +#undef EXTERNAL_PRESSURE_BOUND +#undef INTERNAL_PRESSURE_BOUND +#undef PRESSURE_CHECKS + +#undef PRESSURE_CHECK_EXTERNAL +#undef PRESSURE_CHECK_INTERNAL diff --git a/code/modules/atmospherics/components/unary/vent_scrubber.dm b/code/modules/atmospherics/components/unary/vent_scrubber.dm new file mode 100644 index 00000000..db5241ba --- /dev/null +++ b/code/modules/atmospherics/components/unary/vent_scrubber.dm @@ -0,0 +1,333 @@ +/obj/machinery/atmospherics/unary/vent_scrubber + icon = 'icons/atmos/vent_scrubber.dmi' + icon_state = "map_scrubber_off" + + name = "Air Scrubber" + desc = "Has a valve and pump attached to it." + use_power = 0 + idle_power_usage = 150 //internal circuitry, friction losses and stuff + power_rating = 7500 //7500 W ~ 10 HP + + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SCRUBBER //connects to regular and scrubber pipes + + level = 1 + + var/area/initial_loc + var/id_tag = null + var/frequency = 1439 + var/datum/radio_frequency/radio_connection + + var/hibernate = 0 //Do we even process? + var/scrubbing = 1 //0 = siphoning, 1 = scrubbing + var/list/scrubbing_gas + + var/panic = 0 //is this scrubber panicked? + + var/area_uid + var/radio_filter_out + var/radio_filter_in + + var/welded = 0 + +/obj/machinery/atmospherics/unary/vent_scrubber/on + use_power = 1 + icon_state = "map_scrubber_on" + +/obj/machinery/atmospherics/unary/vent_scrubber/New() + ..() + air_contents.volume = ATMOS_DEFAULT_VOLUME_FILTER + icon = null + +/obj/machinery/atmospherics/unary/vent_scrubber/Destroy() + unregister_radio(src, frequency) + ..() + +/obj/machinery/atmospherics/unary/vent_scrubber/update_icon(var/safety = 0) + if(!check_icon_cache()) + return + + overlays.Cut() + + + var/turf/T = get_turf(src) + if(!istype(T)) + return + + var/scrubber_icon = "scrubber" + if(welded) + scrubber_icon += "weld" + else + if(!powered()) + scrubber_icon += "off" + else + scrubber_icon += "[use_power ? "[scrubbing ? "on" : "in"]" : "off"]" + + overlays += icon_manager.get_atmos_icon("device", , , scrubber_icon) + +/obj/machinery/atmospherics/unary/vent_scrubber/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + if(!T.is_plating() && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe)) + return + else + if(node) + add_underlay(T, node, dir, node.icon_connect_type) + else + add_underlay(T,, dir) + +/obj/machinery/atmospherics/unary/vent_scrubber/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, radio_filter_in) + +/obj/machinery/atmospherics/unary/vent_scrubber/proc/broadcast_status() + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + signal.data = list( + "area" = area_uid, + "tag" = id_tag, + "device" = "AScr", + "timestamp" = world.time, + "power" = use_power, + "scrubbing" = scrubbing, + "panic" = panic, + "filter_o2" = ("oxygen" in scrubbing_gas), + "filter_n2" = ("nitrogen" in scrubbing_gas), + "filter_co2" = ("carbon_dioxide" in scrubbing_gas), + "filter_phoron" = ("phoron" in scrubbing_gas), + "filter_n2o" = ("sleeping_agent" in scrubbing_gas), + "sigtype" = "status" + ) + if(!initial_loc.air_scrub_names[id_tag]) + var/new_name = "[initial_loc.name] Air Scrubber #[initial_loc.air_scrub_names.len+1]" + initial_loc.air_scrub_names[id_tag] = new_name + src.SetName(new_name) + initial_loc.air_scrub_info[id_tag] = signal.data + radio_connection.post_signal(src, signal, radio_filter_out) + + return 1 + +/obj/machinery/atmospherics/unary/vent_scrubber/Initialize() + . = ..() + initial_loc = get_area(loc) + area_uid = initial_loc.uid + if (!id_tag) + assign_uid() + id_tag = num2text(uid) + radio_filter_in = frequency==initial(frequency)?(RADIO_FROM_AIRALARM):null + radio_filter_out = frequency==initial(frequency)?(RADIO_TO_AIRALARM):null + if (frequency) + set_frequency(frequency) + src.broadcast_status() + if(!scrubbing_gas) + scrubbing_gas = list() + for(var/g in gas_data.gases) + if(g != "oxygen" && g != "nitrogen") + scrubbing_gas += g + +/obj/machinery/atmospherics/unary/vent_scrubber/Process() + ..() + + if (hibernate > world.time) + return 1 + + if (!node) + use_power = 0 + //broadcast_status() + if(!use_power || (stat & (NOPOWER|BROKEN))) + return 0 + if(welded) + return 0 + + var/datum/gas_mixture/environment = loc.return_air() + + var/power_draw = -1 + if(scrubbing) + //limit flow rate from turfs + var/transfer_moles = min(environment.total_moles, environment.total_moles*MAX_SCRUBBER_FLOWRATE/environment.volume) //group_multiplier gets divided out here + + power_draw = scrub_gas(src, scrubbing_gas, environment, air_contents, transfer_moles, power_rating) + else //Just siphon all air + //limit flow rate from turfs + var/transfer_moles = min(environment.total_moles, environment.total_moles*MAX_SIPHON_FLOWRATE/environment.volume) //group_multiplier gets divided out here + + power_draw = pump_gas(src, environment, air_contents, transfer_moles, power_rating) + + if(scrubbing && power_draw <= 0) //99% of all scrubbers + //Fucking hibernate because you ain't doing shit. + hibernate = world.time + (rand(100,200)) + + if (power_draw >= 0) + last_power_draw = power_draw + use_power(power_draw) + + if(network) + network.update = 1 + + return 1 + +/obj/machinery/atmospherics/unary/vent_scrubber/hide(var/i) //to make the little pipe section invisible, the icon changes. + update_icon() + update_underlays() + +/obj/machinery/atmospherics/unary/vent_scrubber/receive_signal(datum/signal/signal) + if(stat & (NOPOWER|BROKEN)) + return + if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command")) + return 0 + + if(signal.data["power"] != null) + use_power = text2num(signal.data["power"]) + if(signal.data["power_toggle"] != null) + use_power = !use_power + + if(signal.data["panic_siphon"]) //must be before if("scrubbing" thing + panic = text2num(signal.data["panic_siphon"]) + if(panic) + use_power = 1 + scrubbing = 0 + else + scrubbing = 1 + if(signal.data["toggle_panic_siphon"] != null) + panic = !panic + if(panic) + use_power = 1 + scrubbing = 0 + else + scrubbing = 1 + + if(signal.data["scrubbing"] != null) + scrubbing = text2num(signal.data["scrubbing"]) + if(scrubbing) + panic = 0 + if(signal.data["toggle_scrubbing"]) + scrubbing = !scrubbing + if(scrubbing) + panic = 0 + + var/list/toggle = list() + + if(!isnull(signal.data["o2_scrub"]) && text2num(signal.data["o2_scrub"]) != ("oxygen" in scrubbing_gas)) + toggle += "oxygen" + else if(signal.data["toggle_o2_scrub"]) + toggle += "oxygen" + + if(!isnull(signal.data["n2_scrub"]) && text2num(signal.data["n2_scrub"]) != ("nitrogen" in scrubbing_gas)) + toggle += "nitrogen" + else if(signal.data["toggle_n2_scrub"]) + toggle += "nitrogen" + + if(!isnull(signal.data["co2_scrub"]) && text2num(signal.data["co2_scrub"]) != ("carbon_dioxide" in scrubbing_gas)) + toggle += "carbon_dioxide" + else if(signal.data["toggle_co2_scrub"]) + toggle += "carbon_dioxide" + + if(!isnull(signal.data["tox_scrub"]) && text2num(signal.data["tox_scrub"]) != ("phoron" in scrubbing_gas)) + toggle += "phoron" + else if(signal.data["toggle_tox_scrub"]) + toggle += "phoron" + + if(!isnull(signal.data["n2o_scrub"]) && text2num(signal.data["n2o_scrub"]) != ("sleeping_agent" in scrubbing_gas)) + toggle += "sleeping_agent" + else if(signal.data["toggle_n2o_scrub"]) + toggle += "sleeping_agent" + + scrubbing_gas ^= toggle + + if(signal.data["init"] != null) + SetName(signal.data["init"]) + return + + if(signal.data["status"] != null) + spawn(2) + broadcast_status() + return //do not update_icon + +// log_admin("DEBUG \[[world.timeofday]\]: vent_scrubber/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]") + spawn(2) + broadcast_status() + update_icon() + return + +/obj/machinery/atmospherics/unary/vent_scrubber/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(isWrench(W)) + if (!(stat & NOPOWER) && use_power) + to_chat(user, "You cannot unwrench \the [src], turn it off first.") + return 1 + var/turf/T = src.loc + if (node && node.level==1 && isturf(T) && !T.is_plating()) + to_chat(user, "You must remove the plating first.") + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.") + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to unfasten \the [src]...") + if (do_after(user, 40, src)) + user.visible_message( \ + "\The [user] unfastens \the [src].", \ + "You have unfastened \the [src].", \ + "You hear a ratchet.") + new /obj/item/pipe(loc, make_from=src) + qdel(src) + return 1 + + if(istype(W, /obj/item/weapon/weldingtool)) + + var/obj/item/weapon/weldingtool/WT = W + + if(!WT.isOn()) + to_chat(user, "The welding tool needs to be on to start this task.") + return 1 + + if(!WT.remove_fuel(0,user)) + to_chat(user, "You need more welding fuel to complete this task.") + return 1 + + to_chat(user, "Now welding \the [src].") + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + + if(!do_after(user, 20, src)) + to_chat(user, "You must remain close to finish this task.") + return 1 + + if(!src) + return 1 + + if(!WT.isOn()) + to_chat(user, "The welding tool needs to be on to finish this task.") + return 1 + + welded = !welded + update_icon() + user.visible_message("\The [user] [welded ? "welds \the [src] shut" : "unwelds \the [src]"].", \ + "You [welded ? "weld \the [src] shut" : "unweld \the [src]"].", \ + "You hear welding.") + return 1 + + return ..() + +/obj/machinery/atmospherics/unary/vent_scrubber/examine(mob/user) + if(..(user, 1)) + to_chat(user, "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W") + else + to_chat(user, "You are too far away to read the gauge.") + if(welded) + to_chat(user, "It seems welded shut.") + +/obj/machinery/atmospherics/unary/vent_scrubber/Destroy() + if(initial_loc) + initial_loc.air_scrub_info -= id_tag + initial_loc.air_scrub_names -= id_tag + ..() + return diff --git a/code/modules/atmospherics/components/valve.dm b/code/modules/atmospherics/components/valve.dm new file mode 100644 index 00000000..8655c273 --- /dev/null +++ b/code/modules/atmospherics/components/valve.dm @@ -0,0 +1,306 @@ +/obj/machinery/atmospherics/valve + icon = 'icons/atmos/valve.dmi' + icon_state = "map_valve0" + + name = "manual valve" + desc = "A pipe valve." + + level = 1 + dir = SOUTH + initialize_directions = SOUTH|NORTH + + var/open = 0 + var/openDuringInit = 0 + + + var/datum/pipe_network/network_node1 + var/datum/pipe_network/network_node2 + +/obj/machinery/atmospherics/valve/open + open = 1 + icon_state = "map_valve1" + +/obj/machinery/atmospherics/valve/update_icon(animation) + if(animation) + flick("valve[src.open][!src.open]",src) + else + icon_state = "valve[open]" + +/obj/machinery/atmospherics/valve/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + add_underlay(T, node1, get_dir(src, node1), node1 ? node1.icon_connect_type : "") + add_underlay(T, node2, get_dir(src, node2), node2 ? node2.icon_connect_type : "") + +/obj/machinery/atmospherics/valve/hide(var/i) + update_underlays() + +/obj/machinery/atmospherics/valve/Initialize() + switch(dir) + if(NORTH, SOUTH) + initialize_directions = NORTH|SOUTH + if(EAST, WEST) + initialize_directions = EAST|WEST + . = ..() + +/obj/machinery/atmospherics/valve/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(reference == node1) + network_node1 = new_network + if(open) + network_node2 = new_network + else if(reference == node2) + network_node2 = new_network + if(open) + network_node1 = new_network + + if(new_network.normal_members.Find(src)) + return 0 + + new_network.normal_members += src + + if(open) + if(reference == node1) + if(node2) + return node2.network_expand(new_network, src) + else if(reference == node2) + if(node1) + return node1.network_expand(new_network, src) + + return null + +/obj/machinery/atmospherics/valve/Destroy() + loc = null + + if(node1) + node1.disconnect(src) + qdel(network_node1) + if(node2) + node2.disconnect(src) + qdel(network_node2) + + node1 = null + node2 = null + + . = ..() + +/obj/machinery/atmospherics/valve/proc/open() + if(open) return 0 + + open = 1 + update_icon() + + if(network_node1&&network_node2) + network_node1.merge(network_node2) + network_node2 = network_node1 + + if(network_node1) + network_node1.update = 1 + else if(network_node2) + network_node2.update = 1 + + return 1 + +/obj/machinery/atmospherics/valve/proc/close() + if(!open) + return 0 + + open = 0 + update_icon() + + if(network_node1) + qdel(network_node1) + if(network_node2) + qdel(network_node2) + + build_network() + + return 1 + +/obj/machinery/atmospherics/valve/proc/normalize_dir() + if(dir==3) + set_dir(1) + else if(dir==12) + set_dir(4) + +/obj/machinery/atmospherics/valve/attack_ai(mob/user as mob) + return + +/obj/machinery/atmospherics/valve/attack_hand(mob/user as mob) + src.add_fingerprint(usr) + update_icon(1) + sleep(10) + if (src.open) + src.close() + else + src.open() + +/obj/machinery/atmospherics/valve/Process() + ..() + return PROCESS_KILL + +/obj/machinery/atmospherics/valve/atmos_init() + ..() + normalize_dir() + + var/node1_dir + var/node2_dir + + for(var/direction in GLOB.cardinal) + if(direction&initialize_directions) + if (!node1_dir) + node1_dir = direction + else if (!node2_dir) + node2_dir = direction + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node1 = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node2 = target + break + + build_network() + + update_icon() + update_underlays() + + if(openDuringInit) + close() + open() + openDuringInit = 0 + +/obj/machinery/atmospherics/valve/build_network() + if(!network_node1 && node1) + network_node1 = new /datum/pipe_network() + network_node1.normal_members += src + network_node1.build_network(node1, src) + + if(!network_node2 && node2) + network_node2 = new /datum/pipe_network() + network_node2.normal_members += src + network_node2.build_network(node2, src) + +/obj/machinery/atmospherics/valve/return_network(obj/machinery/atmospherics/reference) + build_network() + + if(reference==node1) + return network_node1 + + if(reference==node2) + return network_node2 + + return null + +/obj/machinery/atmospherics/valve/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network_node1 == old_network) + network_node1 = new_network + if(network_node2 == old_network) + network_node2 = new_network + + return 1 + +/obj/machinery/atmospherics/valve/return_network_air(datum/network/reference) + return null + +/obj/machinery/atmospherics/valve/disconnect(obj/machinery/atmospherics/reference) + if(reference==node1) + qdel(network_node1) + node1 = null + + else if(reference==node2) + qdel(network_node2) + node2 = null + + update_underlays() + + return null + +/obj/machinery/atmospherics/valve/digital // can be controlled by AI + name = "digital valve" + desc = "A digitally controlled valve." + icon = 'icons/atmos/digital_valve.dmi' + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + +/obj/machinery/atmospherics/valve/digital/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/atmospherics/valve/digital/attack_hand(mob/user as mob) + if(!powered()) + return + if(!src.allowed(user)) + to_chat(user, "Access denied.") + return + ..() + +/obj/machinery/atmospherics/valve/digital/open + open = 1 + icon_state = "map_valve1" + +/obj/machinery/atmospherics/valve/digital/update_icon() + ..() + if(!powered()) + icon_state = "valve[open]nopower" + +/obj/machinery/atmospherics/valve/digital/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) + +/obj/machinery/atmospherics/valve/digital/Initialize() + . = ..() + if(frequency) + set_frequency(frequency) + +/obj/machinery/atmospherics/valve/digital/receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id)) + return 0 + + switch(signal.data["command"]) + if("valve_open") + if(!open) + open() + + if("valve_close") + if(open) + close() + + if("valve_toggle") + if(open) + close() + else + open() + + +/obj/machinery/atmospherics/valve/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if (!istype(W, /obj/item/weapon/wrench)) + return ..() + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.") + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to unfasten \the [src]...") + if (do_after(user, 40, src)) + user.visible_message( \ + "\The [user] unfastens \the [src].", \ + "You have unfastened \the [src].", \ + "You hear a ratchet.") + new /obj/item/pipe(loc, make_from=src) + qdel(src) + +/obj/machinery/atmospherics/valve/examine(mob/user) + . = ..() + to_chat(user, "It is [open ? "open" : "closed"].") diff --git a/code/modules/atmospherics/datum_pipe_network.dm b/code/modules/atmospherics/datum_pipe_network.dm new file mode 100644 index 00000000..457d7484 --- /dev/null +++ b/code/modules/atmospherics/datum_pipe_network.dm @@ -0,0 +1,83 @@ +/datum/pipe_network + var/list/datum/gas_mixture/gases = list() //All of the gas_mixtures continuously connected in this network + var/volume = 0 //caches the total volume for atmos machines to use in gas calculations + + var/list/obj/machinery/atmospherics/normal_members = list() + var/list/datum/pipeline/line_members = list() + //membership roster to go through for updates and what not + var/list/leaks = list() + var/update = 1 + +/datum/pipe_network/Destroy() + STOP_PROCESSING_PIPENET(src) + for(var/datum/pipeline/line_member in line_members) + line_member.network = null + for(var/obj/machinery/atmospherics/normal_member in normal_members) + normal_member.reassign_network(src, null) + gases.Cut() // Do not qdel the gases, we don't own them + leaks.Cut() + return ..() + +/datum/pipe_network/Process() + //Equalize gases amongst pipe if called for + if(update) + update = 0 + reconcile_air() //equalize_gases(gases) + + //Give pipelines their process call for pressure checking and what not. Have to remove pressure checks for the time being as pipes dont radiate heat - Mport + //for(var/datum/pipeline/line_member in line_members) + // line_member.process() + +/datum/pipe_network/proc/build_network(obj/machinery/atmospherics/start_normal, obj/machinery/atmospherics/reference) + //Purpose: Generate membership roster + //Notes: Assuming that members will add themselves to appropriate roster in network_expand() + + if(!start_normal) + qdel(src) + return + + start_normal.network_expand(src, reference) + + update_network_gases() + + if((normal_members.len>0)||(line_members.len>0)) + START_PROCESSING_PIPENET(src) + return 1 + qdel(src) + +/datum/pipe_network/proc/merge(datum/pipe_network/giver) + if(giver==src) return 0 + + normal_members |= giver.normal_members + + line_members |= giver.line_members + + leaks |= giver.leaks + + for(var/obj/machinery/atmospherics/normal_member in giver.normal_members) + normal_member.reassign_network(giver, src) + + for(var/datum/pipeline/line_member in giver.line_members) + line_member.network = src + + update_network_gases() + return 1 + +/datum/pipe_network/proc/update_network_gases() + //Go through membership roster and make sure gases is up to date + + gases = list() + volume = 0 + + for(var/obj/machinery/atmospherics/normal_member in normal_members) + var/result = normal_member.return_network_air(src) + if(result) gases += result + + for(var/datum/pipeline/line_member in line_members) + gases += line_member.air + + for(var/datum/gas_mixture/air in gases) + volume += air.volume + +/datum/pipe_network/proc/reconcile_air() + equalize_gases(gases) diff --git a/code/modules/atmospherics/datum_pipeline.dm b/code/modules/atmospherics/datum_pipeline.dm new file mode 100644 index 00000000..554f2f7d --- /dev/null +++ b/code/modules/atmospherics/datum_pipeline.dm @@ -0,0 +1,241 @@ +/datum/pipeline + var/datum/gas_mixture/air + + var/list/obj/machinery/atmospherics/pipe/members + var/list/obj/machinery/atmospherics/pipe/edges //Used for building networks + + var/datum/pipe_network/network + // Leaking nodes + var/list/leaks = list() + + var/alert_pressure = 0 + +/datum/pipeline/New() + START_PROCESSING(SSprocessing, src) + +/datum/pipeline/Destroy() + STOP_PROCESSING(SSprocessing, src) + QDEL_NULL(network) + + if(air && air.volume) + temporarily_store_air() + qdel(air) + for(var/obj/machinery/atmospherics/pipe/P in members) + P.parent = null + leaks.Cut() + . = ..() + +/datum/pipeline/Process()//This use to be called called from the pipe networks + //Check to see if pressure is within acceptable limits + var/pressure = air.return_pressure() + if(pressure > alert_pressure) + for(var/obj/machinery/atmospherics/pipe/member in members) + if(!member.check_pressure(pressure)) + members.Remove(member) + break //Only delete 1 pipe per process + +/datum/pipeline/proc/temporarily_store_air() + //Update individual gas_mixtures by volume ratio + + for(var/obj/machinery/atmospherics/pipe/member in members) + member.air_temporary = new + member.air_temporary.copy_from(air) + member.air_temporary.volume = member.volume + member.air_temporary.multiply(member.volume / air.volume) + +/datum/pipeline/proc/build_pipeline(obj/machinery/atmospherics/pipe/base) + air = new + + var/list/possible_expansions = list(base) + members = list(base) + edges = list() + + var/volume = base.volume + base.parent = src + alert_pressure = base.alert_pressure + + if(base.air_temporary) + air = base.air_temporary + base.air_temporary = null + else + air = new + + if(base.leaking) + leaks |= base + + while(possible_expansions.len>0) + for(var/obj/machinery/atmospherics/pipe/borderline in possible_expansions) + + var/list/result = borderline.pipeline_expansion() + var/edge_check = result.len + + if(result.len>0) + for(var/obj/machinery/atmospherics/pipe/item in result) + if(item.in_stasis) + continue + if(!members.Find(item)) + members += item + possible_expansions += item + + volume += item.volume + item.parent = src + + alert_pressure = min(alert_pressure, item.alert_pressure) + + if(item.air_temporary) + air.merge(item.air_temporary) + + if(item.leaking) + leaks |= item + + edge_check-- + + if(edge_check>0) + edges += borderline + + possible_expansions -= borderline + + air.volume = volume + +/datum/pipeline/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + + if(new_network.line_members.Find(src)) + return 0 + + new_network.line_members += src + + network = new_network + network.leaks |= leaks + + for(var/obj/machinery/atmospherics/pipe/edge in edges) + for(var/obj/machinery/atmospherics/result in edge.pipeline_expansion()) + if(!istype(result,/obj/machinery/atmospherics/pipe) && (result!=reference)) + result.network_expand(new_network, edge) + + + return 1 + +/datum/pipeline/proc/return_network(obj/machinery/atmospherics/reference) + if(!network) + network = new /datum/pipe_network() + network.build_network(src, null) + //technically passing these parameters should not be allowed + //however pipe_network.build_network(..) and pipeline.network_extend(...) + // were setup to properly handle this case + + return network + +/datum/pipeline/proc/mingle_with_turf(turf/simulated/target, mingle_volume) + var/datum/gas_mixture/air_sample = air.remove_ratio(mingle_volume/air.volume) + air_sample.volume = mingle_volume + + if(istype(target) && target.zone) + //Have to consider preservation of group statuses + var/datum/gas_mixture/turf_copy = new + + turf_copy.copy_from(target.zone.air) + turf_copy.volume = target.zone.air.volume //Copy a good representation of the turf from parent group + + equalize_gases(list(air_sample, turf_copy)) + air.merge(air_sample) + + turf_copy.subtract(target.zone.air) + + target.zone.air.merge(turf_copy) + + else + var/datum/gas_mixture/turf_air = target.return_air() + + equalize_gases(list(air_sample, turf_air)) + air.merge(air_sample) + //turf_air already modified by equalize_gases() + + if(network) + network.update = 1 + +/datum/pipeline/proc/temperature_interact(turf/target, share_volume, thermal_conductivity) + var/total_heat_capacity = air.heat_capacity() + var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume) + + if(istype(target, /turf/simulated)) + var/turf/simulated/modeled_location = target + + if(modeled_location.blocks_air) + + if((modeled_location.heat_capacity>0) && (partial_heat_capacity>0)) + var/delta_temperature = air.temperature - modeled_location.temperature + + var/heat = thermal_conductivity*delta_temperature* \ + (partial_heat_capacity*modeled_location.heat_capacity/(partial_heat_capacity+modeled_location.heat_capacity)) + + air.temperature -= heat/total_heat_capacity + modeled_location.temperature += heat/modeled_location.heat_capacity + + else + var/delta_temperature = 0 + var/sharer_heat_capacity = 0 + + if(modeled_location.zone) + delta_temperature = (air.temperature - modeled_location.zone.air.temperature) + sharer_heat_capacity = modeled_location.zone.air.heat_capacity() + else + delta_temperature = (air.temperature - modeled_location.air.temperature) + sharer_heat_capacity = modeled_location.air.heat_capacity() + + var/self_temperature_delta = 0 + var/sharer_temperature_delta = 0 + + if((sharer_heat_capacity>0) && (partial_heat_capacity>0)) + var/heat = thermal_conductivity*delta_temperature* \ + (partial_heat_capacity*sharer_heat_capacity/(partial_heat_capacity+sharer_heat_capacity)) + + self_temperature_delta = -heat/total_heat_capacity + sharer_temperature_delta = heat/sharer_heat_capacity + else + return 1 + + air.temperature += self_temperature_delta + + if(modeled_location.zone) + modeled_location.zone.air.temperature += sharer_temperature_delta/modeled_location.zone.air.group_multiplier + else + modeled_location.air.temperature += sharer_temperature_delta + + + else + if((target.heat_capacity>0) && (partial_heat_capacity>0)) + var/delta_temperature = air.temperature - target.temperature + + var/heat = thermal_conductivity*delta_temperature* \ + (partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity)) + + air.temperature -= heat/total_heat_capacity + if(network) + network.update = 1 + +//surface must be the surface area in m^2 +/datum/pipeline/proc/radiate_heat_to_space(surface, thermal_conductivity) + var/gas_density = air.total_moles/air.volume + thermal_conductivity *= min(gas_density / ( RADIATOR_OPTIMUM_PRESSURE/(R_IDEAL_GAS_EQUATION*GAS_CRITICAL_TEMPERATURE) ), 1) //mult by density ratio + + var/heat_gain = get_thermal_radiation(air.temperature, surface, RADIATOR_EXPOSED_SURFACE_AREA_RATIO, thermal_conductivity) + + air.add_thermal_energy(heat_gain) + if(network) + network.update = 1 + +//Returns the amount of heat gained while in space due to thermal radiation (usually a negative value) +//surface - the surface area in m^2 +//exposed_surface_ratio - the proportion of the surface that is exposed to sunlight +//thermal_conductivity - a multipler on the heat transfer rate. See OPEN_HEAT_TRANSFER_COEFFICIENT and friends +/proc/get_thermal_radiation(var/surface_temperature, var/surface, var/exposed_surface_ratio, var/thermal_conductivity) + //*** Gain heat from sunlight, then lose heat from radiation. + + // We only get heat from the star on the exposed surface area. + // If the HE pipes gain more energy from AVERAGE_SOLAR_RADIATION than they can radiate, then they have a net heat increase. + . = AVERAGE_SOLAR_RADIATION * (exposed_surface_ratio * surface) * thermal_conductivity + + // Previously, the temperature would enter equilibrium at 26C or 294K. + // Only would happen if both sides (all 2 square meters of surface area) were exposed to sunlight. We now assume it aligned edge on. + // It currently should stabilise at 129.6K or -143.6C + . -= surface * STEFAN_BOLTZMANN_CONSTANT * thermal_conductivity * (surface_temperature - COSMIC_RADIATION_TEMPERATURE) ** 4 \ No newline at end of file diff --git a/code/modules/atmospherics/he_pipes.dm b/code/modules/atmospherics/he_pipes.dm new file mode 100644 index 00000000..1c9b3e24 --- /dev/null +++ b/code/modules/atmospherics/he_pipes.dm @@ -0,0 +1,150 @@ + +obj/machinery/atmospherics/pipe/simple/heat_exchanging + icon = 'icons/atmos/heat.dmi' + icon_state = "intact" + pipe_icon = "hepipe" + color = "#404040" + level = 2 + connect_types = CONNECT_TYPE_HE + var/initialize_directions_he + var/surface = 2 //surface area in m^2 + var/icon_temperature = T20C //stop small changes in temperature causing an icon refresh + + minimum_temperature_difference = 20 + thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT + + maximum_pressure = 360*ONE_ATMOSPHERE + fatigue_pressure = 300*ONE_ATMOSPHERE + alert_pressure = 360*ONE_ATMOSPHERE + + can_buckle = 1 + buckle_lying = 1 + +obj/machinery/atmospherics/pipe/simple/heat_exchanging/New() + ..() + initialize_directions_he = initialize_directions // The auto-detection from /pipe is good enough for a simple HE pipe + color = "#404040" //we don't make use of the fancy overlay system for colours, use this to set the default. + +obj/machinery/atmospherics/pipe/simple/heat_exchanging/atmos_init() + ..() + normalize_dir() + var/node1_dir + var/node2_dir + + for(var/direction in GLOB.cardinal) + if(direction&initialize_directions_he) + if (!node1_dir) + node1_dir = direction + else if (!node2_dir) + node2_dir = direction + + for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node1_dir)) + if(target.initialize_directions_he & get_dir(target,src)) + node1 = target + break + for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node2_dir)) + if(target.initialize_directions_he & get_dir(target,src)) + node2 = target + break + if(!node1 && !node2) + qdel(src) + return + + update_icon() + +obj/machinery/atmospherics/pipe/simple/heat_exchanging/Process() + if(!parent) + ..() + else + var/datum/gas_mixture/pipe_air = return_air() + if(istype(loc, /turf/simulated/)) + var/environment_temperature = 0 + if(loc:blocks_air) + environment_temperature = loc:temperature + else + var/datum/gas_mixture/environment = loc.return_air() + environment_temperature = environment.temperature + if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference) + parent.temperature_interact(loc, volume, thermal_conductivity) + else if(istype(loc, /turf/space/)) + parent.radiate_heat_to_space(surface, 1) + + if(buckled_mob) + var/hc = pipe_air.heat_capacity() + var/avg_temp = (pipe_air.temperature * hc + buckled_mob.bodytemperature * 3500) / (hc + 3500) + pipe_air.temperature = avg_temp + buckled_mob.bodytemperature = avg_temp + + var/heat_limit = 1000 + + var/mob/living/carbon/human/H = buckled_mob + if(istype(H) && H.species) + heat_limit = H.species.heat_level_3 + + if(pipe_air.temperature > heat_limit + 1) + buckled_mob.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, BP_CHEST, used_weapon = "Excessive Heat") + + //fancy radiation glowing + if(pipe_air.temperature && (icon_temperature > 500 || pipe_air.temperature > 500)) //start glowing at 500K + if(abs(pipe_air.temperature - icon_temperature) > 10) + icon_temperature = pipe_air.temperature + + var/h_r = heat2color_r(icon_temperature) + var/h_g = heat2color_g(icon_temperature) + var/h_b = heat2color_b(icon_temperature) + + if(icon_temperature < 2000) //scale up overlay until 2000K + var/scale = (icon_temperature - 500) / 1500 + h_r = 64 + (h_r - 64)*scale + h_g = 64 + (h_g - 64)*scale + h_b = 64 + (h_b - 64)*scale + + animate(src, color = rgb(h_r, h_g, h_b), time = 20, easing = SINE_EASING) + + + + +obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction + icon = 'icons/atmos/junction.dmi' + icon_state = "intact" + pipe_icon = "hejunction" + level = 2 + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_HE + +// Doubling up on initialize_directions is necessary to allow HE pipes to connect +obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/New() + .. () + switch (dir) + if (SOUTH) + initialize_directions_he = SOUTH + initialize_directions = NORTH|SOUTH + if (NORTH) + initialize_directions_he = NORTH + initialize_directions = NORTH|SOUTH + if (EAST) + initialize_directions_he = EAST + initialize_directions = EAST|WEST + if (WEST) + initialize_directions_he = WEST + initialize_directions = EAST|WEST + +obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/atmos_init() + ..() + // Only check back side for normal pipes + for(var/obj/machinery/atmospherics/target in get_step(src,GLOB.flip_dir[src.dir])) + if(target.initialize_directions & get_dir(target,src)) + // Snowflake check; keeps back from connecting to HE pipes + if(!istype(target,/obj/machinery/atmospherics/pipe/simple/heat_exchanging)) + node1 = target + break + // Only check front side for HE pipes + for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,initialize_directions_he)) + if(target.initialize_directions_he & get_dir(target,src)) + node2 = target + break + + if(!node1 && !node2) + qdel(src) + return + + update_icon() diff --git a/code/modules/atmospherics/mainspipe.dm b/code/modules/atmospherics/mainspipe.dm new file mode 100644 index 00000000..1ea2a0f8 --- /dev/null +++ b/code/modules/atmospherics/mainspipe.dm @@ -0,0 +1,705 @@ +// internal pipe, don't actually place or use these +obj/machinery/atmospherics/pipe/mains_component + var/obj/machinery/atmospherics/mains_pipe/parent_pipe + var/list/obj/machinery/atmospherics/pipe/mains_component/nodes = new() + + New(loc) + ..(loc) + parent_pipe = loc + + check_pressure(pressure) + var/datum/gas_mixture/environment = loc.loc.return_air() + + var/pressure_difference = pressure - environment.return_pressure() + + if(pressure_difference > parent_pipe.maximum_pressure) + mains_burst() + + else if(pressure_difference > parent_pipe.fatigue_pressure) + //TODO: leak to turf, doing pfshhhhh + if(prob(5)) + mains_burst() + + else return 1 + + pipeline_expansion() + return nodes + + disconnect(obj/machinery/atmospherics/reference) + if(nodes.Find(reference)) + nodes.Remove(reference) + + proc/mains_burst() + parent_pipe.burst() + +obj/machinery/atmospherics/mains_pipe + icon = 'icons/obj/atmospherics/mainspipe.dmi' + + var/volume = 0 + + var/alert_pressure = 80*ONE_ATMOSPHERE + + var/initialize_mains_directions = 0 + + var/list/obj/machinery/atmospherics/mains_pipe/nodes = new() + var/obj/machinery/atmospherics/pipe/mains_component/supply + var/obj/machinery/atmospherics/pipe/mains_component/scrubbers + var/obj/machinery/atmospherics/pipe/mains_component/aux + + var/minimum_temperature_difference = 300 + var/thermal_conductivity = 0 //WALL_HEAT_TRANSFER_COEFFICIENT No + + var/maximum_pressure = 210*ONE_ATMOSPHERE + var/fatigue_pressure = 170*ONE_ATMOSPHERE + alert_pressure = 170*ONE_ATMOSPHERE + + New() + ..() + + supply = new(src) + supply.volume = volume + supply.nodes.len = nodes.len + scrubbers = new(src) + scrubbers.volume = volume + scrubbers.nodes.len = nodes.len + aux = new(src) + aux.volume = volume + aux.nodes.len = nodes.len + + hide(var/i) + if(level == 1 && istype(loc, /turf/simulated)) + set_invisibility(i ? 101 : 0) + update_icon() + + proc/burst() + ..() + for(var/obj/machinery/atmospherics/pipe/mains_component/pipe in contents) + burst() + + proc/check_pressure(pressure) + var/datum/gas_mixture/environment = loc.return_air() + + var/pressure_difference = pressure - environment.return_pressure() + + if(pressure_difference > maximum_pressure) + burst() + + else if(pressure_difference > fatigue_pressure) + //TODO: leak to turf, doing pfshhhhh + if(prob(5)) + burst() + + else return 1 + + disconnect() + ..() + for(var/obj/machinery/atmospherics/pipe/mains_component/node in nodes) + node.disconnect() + + Destroy() + disconnect() + ..() + + atmos_init() + ..() + for(var/i = 1 to nodes.len) + var/obj/machinery/atmospherics/mains_pipe/node = nodes[i] + if(node) + supply.nodes[i] = node.supply + scrubbers.nodes[i] = node.scrubbers + aux.nodes[i] = node.aux + +obj/machinery/atmospherics/mains_pipe/simple + name = "mains pipe" + desc = "A one meter section of 3-line mains pipe" + + dir = SOUTH + initialize_mains_directions = SOUTH|NORTH + + New() + nodes.len = 2 + ..() + switch(dir) + if(SOUTH || NORTH) + initialize_mains_directions = SOUTH|NORTH + if(EAST || WEST) + initialize_mains_directions = EAST|WEST + if(NORTHEAST) + initialize_mains_directions = NORTH|EAST + if(NORTHWEST) + initialize_mains_directions = NORTH|WEST + if(SOUTHEAST) + initialize_mains_directions = SOUTH|EAST + if(SOUTHWEST) + initialize_mains_directions = SOUTH|WEST + + proc/normalize_dir() + if(dir==3) + set_dir(1) + else if(dir==12) + set_dir(4) + + update_icon() + if(nodes[1] && nodes[2]) + icon_state = "intact[invisibility ? "-f" : "" ]" + + //var/node1_direction = get_dir(src, node1) + //var/node2_direction = get_dir(src, node2) + + //set_dir(node1_direction|node2_direction) + + else + if(!nodes[1]&&!nodes[2]) + qdel(src) //TODO: silent deleting looks weird + var/have_node1 = nodes[1]?1:0 + var/have_node2 = nodes[2]?1:0 + icon_state = "exposed[have_node1][have_node2][invisibility ? "-f" : "" ]" + + atmos_init() + normalize_dir() + var/node1_dir + var/node2_dir + + for(var/direction in GLOB.cardinal) + if(direction&initialize_mains_directions) + if (!node1_dir) + node1_dir = direction + else if (!node2_dir) + node2_dir = direction + + for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,node1_dir)) + if(target.initialize_mains_directions & get_dir(target,src)) + nodes[1] = target + break + for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,node2_dir)) + if(target.initialize_mains_directions & get_dir(target,src)) + nodes[2] = target + break + + ..() // initialize internal pipes + + var/turf/T = src.loc // hide if turf is not intact + if(level == 1 && !T.is_plating()) hide(1) + update_icon() + + hidden + level = 1 + icon_state = "intact-f" + + visible + level = 2 + icon_state = "intact" + +obj/machinery/atmospherics/mains_pipe/manifold + name = "manifold pipe" + desc = "A manifold composed of mains pipes" + + dir = SOUTH + initialize_mains_directions = EAST|NORTH|WEST + volume = 105 + + New() + nodes.len = 3 + ..() + initialize_mains_directions = (NORTH|SOUTH|EAST|WEST) & ~dir + + atmos_init() + var/connect_directions = initialize_mains_directions + + for(var/direction in GLOB.cardinal) + if(direction&connect_directions) + for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,direction)) + if(target.initialize_mains_directions & get_dir(target,src)) + nodes[1] = target + connect_directions &= ~direction + break + if (nodes[1]) + break + + + for(var/direction in GLOB.cardinal) + if(direction&connect_directions) + for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,direction)) + if(target.initialize_mains_directions & get_dir(target,src)) + nodes[2] = target + connect_directions &= ~direction + break + if (nodes[2]) + break + + + for(var/direction in GLOB.cardinal) + if(direction&connect_directions) + for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,direction)) + if(target.initialize_mains_directions & get_dir(target,src)) + nodes[3] = target + connect_directions &= ~direction + break + if (nodes[3]) + break + + ..() // initialize internal pipes + + var/turf/T = src.loc // hide if turf is not intact + if(level == 1 && !T.is_plating()) hide(1) + update_icon() + + update_icon() + icon_state = "manifold[invisibility ? "-f" : "" ]" + + hidden + level = 1 + icon_state = "manifold-f" + + visible + level = 2 + icon_state = "manifold" + +obj/machinery/atmospherics/mains_pipe/manifold4w + name = "manifold pipe" + desc = "A manifold composed of mains pipes" + + dir = SOUTH + initialize_mains_directions = EAST|NORTH|WEST|SOUTH + volume = 105 + + New() + nodes.len = 4 + ..() + + atmos_init() + for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,NORTH)) + if(target.initialize_mains_directions & get_dir(target,src)) + nodes[1] = target + break + + for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,SOUTH)) + if(target.initialize_mains_directions & get_dir(target,src)) + nodes[2] = target + break + + for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,EAST)) + if(target.initialize_mains_directions & get_dir(target,src)) + nodes[3] = target + break + + for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,WEST)) + if(target.initialize_mains_directions & get_dir(target,src)) + nodes[3] = target + break + + ..() // initialize internal pipes + + var/turf/T = src.loc // hide if turf is not intact + if(level == 1 && !T.is_plating()) hide(1) + update_icon() + + update_icon() + icon_state = "manifold4w[invisibility ? "-f" : "" ]" + + hidden + level = 1 + icon_state = "manifold4w-f" + + visible + level = 2 + icon_state = "manifold4w" + +obj/machinery/atmospherics/mains_pipe/split + name = "mains splitter" + desc = "A splitter for connecting to a single pipe off a mains." + + var/obj/machinery/atmospherics/pipe/mains_component/split_node + var/obj/machinery/atmospherics/node3 + var/icon_type + + New() + nodes.len = 2 + ..() + initialize_mains_directions = turn(dir, 90) | turn(dir, -90) + initialize_directions = dir // actually have a normal connection too + + atmos_init() + var/node1_dir + var/node2_dir + var/node3_dir + + node1_dir = turn(dir, 90) + node2_dir = turn(dir, -90) + node3_dir = dir + + for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,node1_dir)) + if(target.initialize_mains_directions & get_dir(target,src)) + nodes[1] = target + break + for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,node2_dir)) + if(target.initialize_mains_directions & get_dir(target,src)) + nodes[2] = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,node3_dir)) + if(target.initialize_directions & get_dir(target,src)) + node3 = target + break + + ..() // initialize internal pipes + + // bind them + spawn(5) + if(node3 && split_node) + var/datum/pipe_network/N1 = node3.return_network(src) + var/datum/pipe_network/N2 = split_node.return_network(split_node) + if(N1 && N2) + N1.merge(N2) + + var/turf/T = src.loc // hide if turf is not intact + if(level == 1 && !T.is_plating()) hide(1) + update_icon() + + update_icon() + icon_state = "split-[icon_type][invisibility ? "-f" : "" ]" + + return_network(A) + return split_node.return_network(A) + + supply + icon_type = "supply" + + New() + ..() + split_node = supply + + hidden + level = 1 + icon_state = "split-supply-f" + + visible + level = 2 + icon_state = "split-supply" + + scrubbers + icon_type = "scrubbers" + + New() + ..() + split_node = scrubbers + + hidden + level = 1 + icon_state = "split-scrubbers-f" + + visible + level = 2 + icon_state = "split-scrubbers" + + aux + icon_type = "aux" + + New() + ..() + split_node = aux + + hidden + level = 1 + icon_state = "split-aux-f" + + visible + level = 2 + icon_state = "split-aux" + +obj/machinery/atmospherics/mains_pipe/split3 + name = "triple mains splitter" + desc = "A splitter for connecting to the 3 pipes on a mainline." + + var/obj/machinery/atmospherics/supply_node + var/obj/machinery/atmospherics/scrubbers_node + var/obj/machinery/atmospherics/aux_node + + New() + nodes.len = 1 + ..() + initialize_mains_directions = dir + initialize_directions = GLOB.cardinal & ~dir // actually have a normal connection too + + atmos_init() + var/node1_dir + var/supply_node_dir + var/scrubbers_node_dir + var/aux_node_dir + + node1_dir = dir + aux_node_dir = turn(dir, 180) + if(dir & (NORTH|SOUTH)) + supply_node_dir = EAST + scrubbers_node_dir = WEST + else + supply_node_dir = SOUTH + scrubbers_node_dir = NORTH + + for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src, node1_dir)) + if(target.initialize_mains_directions & get_dir(target,src)) + nodes[1] = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,supply_node_dir)) + if(target.initialize_directions & get_dir(target,src)) + supply_node = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,scrubbers_node_dir)) + if(target.initialize_directions & get_dir(target,src)) + scrubbers_node = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,aux_node_dir)) + if(target.initialize_directions & get_dir(target,src)) + aux_node = target + break + + ..() // initialize internal pipes + + // bind them + spawn(5) + if(supply_node) + var/datum/pipe_network/N1 = supply_node.return_network(src) + var/datum/pipe_network/N2 = supply.return_network(supply) + if(N1 && N2) + N1.merge(N2) + if(scrubbers_node) + var/datum/pipe_network/N1 = scrubbers_node.return_network(src) + var/datum/pipe_network/N2 = scrubbers.return_network(scrubbers) + if(N1 && N2) + N1.merge(N2) + if(aux_node) + var/datum/pipe_network/N1 = aux_node.return_network(src) + var/datum/pipe_network/N2 = aux.return_network(aux) + if(N1 && N2) + N1.merge(N2) + + var/turf/T = src.loc // hide if turf is not intact + if(level == 1 && !T.is_plating()) hide(1) + update_icon() + + update_icon() + icon_state = "split-t[invisibility ? "-f" : "" ]" + + return_network(obj/machinery/atmospherics/reference) + var/obj/machinery/atmospherics/A + + A = supply_node.return_network(reference) + if(!A) + A = scrubbers_node.return_network(reference) + if(!A) + A = aux_node.return_network(reference) + + return A + + hidden + level = 1 + icon_state = "split-t-f" + + visible + level = 2 + icon_state = "split-t" + +obj/machinery/atmospherics/mains_pipe/cap + name = "pipe cap" + desc = "A cap for the end of a mains pipe" + + dir = SOUTH + initialize_directions = SOUTH + volume = 35 + + New() + nodes.len = 1 + ..() + initialize_mains_directions = dir + + update_icon() + icon_state = "cap[invisibility ? "-f" : ""]" + + atmos_init() + for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,dir)) + if(target.initialize_mains_directions & get_dir(target,src)) + nodes[1] = target + break + + ..() + + var/turf/T = src.loc // hide if turf is not intact + if(level == 1 && !T.is_plating()) hide(1) + update_icon() + + hidden + level = 1 + icon_state = "cap-f" + + visible + level = 2 + icon_state = "cap" + +//TODO: Get Mains valves working! +/* +obj/machinery/atmospherics/mains_pipe/valve + icon_state = "mvalve0" + + name = "mains shutoff valve" + desc = "A mains pipe valve" + + var/open = 1 + + dir = SOUTH + initialize_mains_directions = SOUTH|NORTH + + New() + nodes.len = 2 + ..() + initialize_mains_directions = dir | turn(dir, 180) + + update_icon(animation) + var/turf/simulated/floor = loc + var/hide = istype(floor) ? floor.intact : 0 + level = 1 + for(var/obj/machinery/atmospherics/mains_pipe/node in nodes) + if(node.level == 2) + hide = 0 + level = 2 + break + + if(animation) + flick("[hide?"h":""]mvalve[src.open][!src.open]",src) + else + icon_state = "[hide?"h":""]mvalve[open]" + + atmos_init() + normalize_dir() + var/node1_dir + var/node2_dir + + for(var/direction in cardinal) + if(direction&initialize_mains_directions) + if (!node1_dir) + node1_dir = direction + else if (!node2_dir) + node2_dir = direction + + for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,node1_dir)) + if(target.initialize_mains_directions & get_dir(target,src)) + nodes[1] = target + break + for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,node2_dir)) + if(target.initialize_mains_directions & get_dir(target,src)) + nodes[2] = target + break + + if(open) + ..() // initialize internal pipes + + update_icon() + + proc/normalize_dir() + if(dir==3) + set_dir(1) + else if(dir==12) + set_dir(4) + + proc/open() + if(open) return 0 + + open = 1 + update_icon() + + atmos_init() + + return 1 + + proc/close() + if(!open) return 0 + + open = 0 + update_icon() + + for(var/obj/machinery/atmospherics/pipe/mains_component/node in src) + for(var/obj/machinery/atmospherics/pipe/mains_component/o in node.nodes) + o.disconnect(node) + o.build_network() + + return 1 + + attack_ai(mob/user as mob) + return + + attack_paw(mob/user as mob) + return attack_hand(user) + + attack_hand(mob/user as mob) + src.add_fingerprint(usr) + update_icon(1) + sleep(10) + if (open) + close() + else + open() + + digital // can be controlled by AI + name = "digital mains valve" + desc = "A digitally controlled valve." + icon_state = "dvalve0" + + attack_ai(mob/user as mob) + return src.attack_hand(user) + + attack_hand(mob/user as mob) + if(!src.allowed(user)) + to_chat(user, "Access denied.") + return + ..() + + //Radio remote control + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + + Initialize() + . = ..() + if(frequency) + set_frequency(frequency) + + update_icon(animation) + var/turf/simulated/floor = loc + var/hide = istype(floor) ? floor.intact : 0 + level = 1 + for(var/obj/machinery/atmospherics/mains_pipe/node in nodes) + if(node.level == 2) + hide = 0 + level = 2 + break + + if(animation) + flick("[hide?"h":""]dvalve[src.open][!src.open]",src) + else + icon_state = "[hide?"h":""]dvalve[open]" + + receive_signal(datum/signal/signal) + if(!signal.data["tag"] || (signal.data["tag"] != id)) + return 0 + + switch(signal.data["command"]) + if("valve_open") + if(!open) + open() + + if("valve_close") + if(open) + close() + + if("valve_toggle") + if(open) + close() + else + open() +*/ diff --git a/code/modules/atmospherics/pipes.dm b/code/modules/atmospherics/pipes.dm new file mode 100644 index 00000000..4bfb93d4 --- /dev/null +++ b/code/modules/atmospherics/pipes.dm @@ -0,0 +1,1450 @@ +/obj/machinery/atmospherics/pipe + + var/datum/gas_mixture/air_temporary // used when reconstructing a pipeline that broke + var/datum/pipeline/parent + var/volume = 0 + var/leaking = 0 // Do not set directly, use set_leaking(TRUE/FALSE) + use_power = 0 + + var/alert_pressure = 170*ONE_ATMOSPHERE + var/in_stasis = 0 + //minimum pressure before check_pressure(...) should be called + + can_buckle = 1 + buckle_require_restraints = 1 + buckle_lying = -1 + +/obj/machinery/atmospherics/pipe/drain_power() + return -1 + +/obj/machinery/atmospherics/pipe/New() + if(istype(get_turf(src), /turf/simulated/wall) || istype(get_turf(src), /turf/simulated/shuttle/wall) || istype(get_turf(src), /turf/unsimulated/wall)) + level = 1 + ..() + +/obj/machinery/atmospherics/pipe/hides_under_flooring() + return level != 2 + +/obj/machinery/atmospherics/pipe/proc/set_leaking(var/new_leaking) + if(new_leaking && !leaking) + START_PROCESSING(SSmachines, src) + leaking = TRUE + if(parent) + parent.leaks |= src + if(parent.network) + parent.network.leaks |= src + else if (!new_leaking && leaking) + STOP_PROCESSING(SSmachines, src) + leaking = FALSE + if(parent) + parent.leaks -= src + if(parent.network) + parent.network.leaks -= src + + +/obj/machinery/atmospherics/pipe/proc/pipeline_expansion() + return null + +/obj/machinery/atmospherics/pipe/proc/check_pressure(pressure) + //Return 1 if parent should continue checking other pipes + //Return null if parent should stop checking other pipes. Recall: qdel(src) will by default return null + + return 1 + +/obj/machinery/atmospherics/pipe/return_air() + if(!parent) + parent = new /datum/pipeline() + parent.build_pipeline(src) + + return parent.air + +/obj/machinery/atmospherics/pipe/build_network() + if(!parent) + parent = new /datum/pipeline() + parent.build_pipeline(src) + + return parent.return_network() + +/obj/machinery/atmospherics/pipe/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(!parent) + parent = new /datum/pipeline() + parent.build_pipeline(src) + + return parent.network_expand(new_network, reference) + +/obj/machinery/atmospherics/pipe/return_network(obj/machinery/atmospherics/reference) + if(!parent) + parent = new /datum/pipeline() + parent.build_pipeline(src) + + return parent.return_network(reference) + +/obj/machinery/atmospherics/pipe/Destroy() + QDEL_NULL(parent) + if(air_temporary) + loc.assume_air(air_temporary) + + . = ..() + +/obj/machinery/atmospherics/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if (istype(src, /obj/machinery/atmospherics/pipe/tank)) + return ..() + if (istype(src, /obj/machinery/atmospherics/pipe/vent)) + return ..() + + if(istype(W,/obj/item/device/pipe_painter)) + return 0 + + if(!isWrench(W)) + return ..() + var/turf/T = src.loc + if (level==1 && isturf(T) && !T.is_plating()) + to_chat(user, "You must remove the plating first.") + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.") + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to unfasten \the [src]...") + if (do_after(user, 40, src)) + user.visible_message( \ + "\The [user] unfastens \the [src].", \ + "You have unfastened \the [src].", \ + "You hear a ratchet.") + new /obj/item/pipe(loc, make_from=src) + for (var/obj/machinery/meter/meter in T) + if (meter.target == src) + new /obj/item/pipe_meter(T) + qdel(meter) + qdel(src) + +/obj/machinery/atmospherics/proc/change_color(var/new_color) + //only pass valid pipe colors please ~otherwise your pipe will turn invisible + if(!pipe_color_check(new_color)) + return + + pipe_color = new_color + update_icon() + +/* +/obj/machinery/atmospherics/pipe/add_underlay(var/obj/machinery/atmospherics/node, var/direction) + if(istype(src, /obj/machinery/atmospherics/pipe/tank)) //todo: move tanks to unary devices + return ..() + + if(node) + var/temp_dir = get_dir(src, node) + underlays += icon_manager.get_atmos_icon("pipe_underlay_intact", temp_dir, color_cache_name(node)) + return temp_dir + else if(direction) + underlays += icon_manager.get_atmos_icon("pipe_underlay_exposed", direction, pipe_color) + else + return null +*/ + +/obj/machinery/atmospherics/pipe/color_cache_name(var/obj/machinery/atmospherics/node) + if(istype(src, /obj/machinery/atmospherics/pipe/tank)) + return ..() + + if(istype(node, /obj/machinery/atmospherics/pipe/manifold) || istype(node, /obj/machinery/atmospherics/pipe/manifold4w)) + if(pipe_color == node.pipe_color) + return node.pipe_color + else + return null + else if(istype(node, /obj/machinery/atmospherics/pipe/simple)) + return node.pipe_color + else + return pipe_color + +/obj/machinery/atmospherics/pipe/simple + icon = 'icons/atmos/pipes.dmi' + icon_state = "" + var/pipe_icon = "" //what kind of pipe it is and from which dmi is the icon manager getting its icons, "" for simple pipes, "hepipe" for HE pipes, "hejunction" for HE junctions + name = "pipe" + desc = "A one meter section of regular pipe." + + volume = ATMOS_DEFAULT_VOLUME_PIPE + + dir = SOUTH + initialize_directions = SOUTH|NORTH + + var/minimum_temperature_difference = 300 + var/thermal_conductivity = 0 //WALL_HEAT_TRANSFER_COEFFICIENT No + + var/maximum_pressure = 210*ONE_ATMOSPHERE + var/fatigue_pressure = 170*ONE_ATMOSPHERE + alert_pressure = 170*ONE_ATMOSPHERE + + level = 1 + +/obj/machinery/atmospherics/pipe/simple/New() + ..() + + // Pipe colors and icon states are handled by an image cache - so color and icon should + // be null. For mapping purposes color is defined in the object definitions. + icon = null + alpha = 255 + + switch(dir) + if(SOUTH || NORTH) + initialize_directions = SOUTH|NORTH + if(EAST || WEST) + initialize_directions = EAST|WEST + if(NORTHEAST) + initialize_directions = NORTH|EAST + if(NORTHWEST) + initialize_directions = NORTH|WEST + if(SOUTHEAST) + initialize_directions = SOUTH|EAST + if(SOUTHWEST) + initialize_directions = SOUTH|WEST + +/obj/machinery/atmospherics/pipe/simple/hide(var/i) + if(istype(loc, /turf/simulated)) + set_invisibility(i ? 101 : 0) + update_icon() + +/obj/machinery/atmospherics/pipe/simple/Process() + if(!parent) //This should cut back on the overhead calling build_network thousands of times per cycle + ..() + else if(leaking) + parent.mingle_with_turf(loc, volume) + else + . = PROCESS_KILL + +/obj/machinery/atmospherics/pipe/simple/check_pressure(pressure) + // Don't ask me, it happened somehow. + if (!istype(loc, /turf)) + return 1 + + var/datum/gas_mixture/environment = loc.return_air() + + var/pressure_difference = pressure - environment.return_pressure() + + if(pressure_difference > maximum_pressure) + burst() + + else if(pressure_difference > fatigue_pressure) + //TODO: leak to turf, doing pfshhhhh + if(prob(5)) + burst() + + else return 1 + +/obj/machinery/atmospherics/pipe/simple/proc/burst() + ASSERT(parent) + parent.temporarily_store_air() + src.visible_message("\The [src] bursts!"); + playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) + var/datum/effect/effect/system/smoke_spread/smoke = new + smoke.set_up(1,0, src.loc, 0) + smoke.start() + qdel(src) + +/obj/machinery/atmospherics/pipe/simple/proc/normalize_dir() + if(dir==3) + set_dir(1) + else if(dir==12) + set_dir(4) + +/obj/machinery/atmospherics/pipe/simple/Destroy() + if(node1) + node1.disconnect(src) + node1 = null + if(node2) + node2.disconnect(src) + node1 = null + + . = ..() + +/obj/machinery/atmospherics/pipe/simple/pipeline_expansion() + return list(node1, node2) + +/obj/machinery/atmospherics/pipe/simple/change_color(var/new_color) + ..() + //for updating connected atmos device pipes (i.e. vents, manifolds, etc) + if(node1) + node1.update_underlays() + if(node2) + node2.update_underlays() + +/obj/machinery/atmospherics/pipe/simple/update_icon(var/safety = 0) + if(!atmos_initalized) + return + if(!check_icon_cache()) + return + + alpha = 255 + + overlays.Cut() + + if(!node1 && !node2) + var/turf/T = get_turf(src) + new /obj/item/pipe(loc, make_from=src) + for (var/obj/machinery/meter/meter in T) + if (meter.target == src) + new /obj/item/pipe_meter(T) + qdel(meter) + qdel(src) + else if(node1 && node2) + overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "[pipe_icon]intact[icon_connect_type]") + set_leaking(FALSE) + else + overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "[pipe_icon]exposed[node1?1:0][node2?1:0][icon_connect_type]") + set_leaking(TRUE) + +/obj/machinery/atmospherics/pipe/simple/update_underlays() + return + +/obj/machinery/atmospherics/pipe/simple/atmos_init() + ..() + normalize_dir() + var/node1_dir + var/node2_dir + + for(var/direction in GLOB.cardinal) + if(direction&initialize_directions) + if (!node1_dir) + node1_dir = direction + else if (!node2_dir) + node2_dir = direction + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node1 = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node2 = target + break + + if(!node1 && !node2) + qdel(src) + return + + var/turf/T = loc + if(level == 1 && !T.is_plating()) hide(1) + update_icon() + +/obj/machinery/atmospherics/pipe/simple/disconnect(obj/machinery/atmospherics/reference) + if(reference == node1) + if(istype(node1, /obj/machinery/atmospherics/pipe)) + qdel(parent) + node1 = null + + if(reference == node2) + if(istype(node2, /obj/machinery/atmospherics/pipe)) + qdel(parent) + node2 = null + + update_icon() + + return null + +/obj/machinery/atmospherics/pipe/simple/visible + icon_state = "intact" + level = 2 + +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers + name = "Scrubbers pipe" + desc = "A one meter section of scrubbers pipe." + icon_state = "intact-scrubbers" + connect_types = CONNECT_TYPE_SCRUBBER + icon_connect_type = "-scrubbers" + color = PIPE_COLOR_RED + +/obj/machinery/atmospherics/pipe/simple/visible/supply + name = "Air supply pipe" + desc = "A one meter section of supply pipe." + icon_state = "intact-supply" + connect_types = CONNECT_TYPE_SUPPLY + icon_connect_type = "-supply" + color = PIPE_COLOR_BLUE + +/obj/machinery/atmospherics/pipe/simple/visible/yellow + color = PIPE_COLOR_YELLOW + +/obj/machinery/atmospherics/pipe/simple/visible/cyan + color = PIPE_COLOR_CYAN + +/obj/machinery/atmospherics/pipe/simple/visible/green + color = PIPE_COLOR_GREEN + +/obj/machinery/atmospherics/pipe/simple/visible/black + color = PIPE_COLOR_BLACK + +/obj/machinery/atmospherics/pipe/simple/visible/red + color = PIPE_COLOR_RED + +/obj/machinery/atmospherics/pipe/simple/visible/blue + color = PIPE_COLOR_BLUE + +/obj/machinery/atmospherics/pipe/simple/visible/fuel + name = "Fuel pipe" + color = PIPE_COLOR_ORANGE + maximum_pressure = 420*ONE_ATMOSPHERE + fatigue_pressure = 350*ONE_ATMOSPHERE + alert_pressure = 350*ONE_ATMOSPHERE + +/obj/machinery/atmospherics/pipe/simple/hidden + icon_state = "intact" + level = 1 + alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game + +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers + name = "Scrubbers pipe" + desc = "A one meter section of scrubbers pipe." + icon_state = "intact-scrubbers" + connect_types = CONNECT_TYPE_SCRUBBER + icon_connect_type = "-scrubbers" + color = PIPE_COLOR_RED + +/obj/machinery/atmospherics/pipe/simple/hidden/supply + name = "Air supply pipe" + desc = "A one meter section of supply pipe." + icon_state = "intact-supply" + connect_types = CONNECT_TYPE_SUPPLY + icon_connect_type = "-supply" + color = PIPE_COLOR_BLUE + +/obj/machinery/atmospherics/pipe/simple/hidden/yellow + color = PIPE_COLOR_YELLOW + +/obj/machinery/atmospherics/pipe/simple/hidden/cyan + color = PIPE_COLOR_CYAN + +/obj/machinery/atmospherics/pipe/simple/hidden/green + color = PIPE_COLOR_GREEN + +/obj/machinery/atmospherics/pipe/simple/hidden/black + color = PIPE_COLOR_BLACK + +/obj/machinery/atmospherics/pipe/simple/hidden/red + color = PIPE_COLOR_RED + +/obj/machinery/atmospherics/pipe/simple/hidden/blue + color = PIPE_COLOR_BLUE + +/obj/machinery/atmospherics/pipe/simple/hidden/fuel + name = "Fuel pipe" + color = PIPE_COLOR_ORANGE + maximum_pressure = 420*ONE_ATMOSPHERE + fatigue_pressure = 350*ONE_ATMOSPHERE + alert_pressure = 350*ONE_ATMOSPHERE + +/obj/machinery/atmospherics/pipe/manifold + icon = 'icons/atmos/manifold.dmi' + icon_state = "" + name = "pipe manifold" + desc = "A manifold composed of regular pipes." + + volume = ATMOS_DEFAULT_VOLUME_PIPE * 1.5 + + dir = SOUTH + initialize_directions = EAST|NORTH|WEST + + var/obj/machinery/atmospherics/node3 + + level = 1 + +/obj/machinery/atmospherics/pipe/manifold/New() + ..() + alpha = 255 + + switch(dir) + if(NORTH) + initialize_directions = EAST|SOUTH|WEST + if(SOUTH) + initialize_directions = WEST|NORTH|EAST + if(EAST) + initialize_directions = SOUTH|WEST|NORTH + if(WEST) + initialize_directions = NORTH|EAST|SOUTH + +/obj/machinery/atmospherics/pipe/manifold/hide(var/i) + if(istype(loc, /turf/simulated)) + set_invisibility(i ? 101 : 0) + update_icon() + +/obj/machinery/atmospherics/pipe/manifold/pipeline_expansion() + return list(node1, node2, node3) + +/obj/machinery/atmospherics/pipe/manifold/Process() + if(!parent) + ..() + else + . = PROCESS_KILL + +/obj/machinery/atmospherics/pipe/manifold/Destroy() + if(node1) + node1.disconnect(src) + node1 = null + if(node2) + node2.disconnect(src) + node2 = null + if(node3) + node3.disconnect(src) + node3 = null + + . = ..() + +/obj/machinery/atmospherics/pipe/manifold/disconnect(obj/machinery/atmospherics/reference) + if(reference == node1) + if(istype(node1, /obj/machinery/atmospherics/pipe)) + qdel(parent) + node1 = null + + if(reference == node2) + if(istype(node2, /obj/machinery/atmospherics/pipe)) + qdel(parent) + node2 = null + + if(reference == node3) + if(istype(node3, /obj/machinery/atmospherics/pipe)) + qdel(parent) + node3 = null + + update_icon() + + ..() + +/obj/machinery/atmospherics/pipe/manifold/change_color(var/new_color) + ..() + //for updating connected atmos device pipes (i.e. vents, manifolds, etc) + if(node1) + node1.update_underlays() + if(node2) + node2.update_underlays() + if(node3) + node3.update_underlays() + +/obj/machinery/atmospherics/pipe/manifold/update_icon(var/safety = 0) + if(!atmos_initalized) + return + if(!check_icon_cache()) + return + + set_leaking(!(node1 && node2 && node3)) + alpha = 255 + + if(!node1 && !node2 && !node3) + var/turf/T = get_turf(src) + new /obj/item/pipe(loc, make_from=src) + for (var/obj/machinery/meter/meter in T) + if (meter.target == src) + new /obj/item/pipe_meter(T) + qdel(meter) + qdel(src) + else + overlays.Cut() + overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "core" + icon_connect_type) + overlays += icon_manager.get_atmos_icon("manifold", , , "clamps" + icon_connect_type) + underlays.Cut() + + var/turf/T = get_turf(src) + var/list/directions = list(NORTH, SOUTH, EAST, WEST) + var/node1_direction = get_dir(src, node1) + var/node2_direction = get_dir(src, node2) + var/node3_direction = get_dir(src, node3) + + directions -= dir + + directions -= add_underlay(T,node1,node1_direction,icon_connect_type) + directions -= add_underlay(T,node2,node2_direction,icon_connect_type) + directions -= add_underlay(T,node3,node3_direction,icon_connect_type) + + for(var/D in directions) + add_underlay(T,,D,icon_connect_type) + + +/obj/machinery/atmospherics/pipe/manifold/update_underlays() + ..() + update_icon() + +/obj/machinery/atmospherics/pipe/manifold/atmos_init() + ..() + var/connect_directions = (NORTH|SOUTH|EAST|WEST)&(~dir) + + for(var/direction in GLOB.cardinal) + if(direction&connect_directions) + for(var/obj/machinery/atmospherics/target in get_step(src,direction)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node1 = target + connect_directions &= ~direction + break + if (node1) + break + + + for(var/direction in GLOB.cardinal) + if(direction&connect_directions) + for(var/obj/machinery/atmospherics/target in get_step(src,direction)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node2 = target + connect_directions &= ~direction + break + if (node2) + break + + + for(var/direction in GLOB.cardinal) + if(direction&connect_directions) + for(var/obj/machinery/atmospherics/target in get_step(src,direction)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node3 = target + connect_directions &= ~direction + break + if (node3) + break + + if(!node1 && !node2 && !node3) + qdel(src) + return + + var/turf/T = get_turf(src) + if(level == 1 && !T.is_plating()) hide(1) + update_icon() + +/obj/machinery/atmospherics/pipe/manifold/visible + icon_state = "map" + level = 2 + +/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers + name="Scrubbers pipe manifold" + desc = "A manifold composed of scrubbers pipes." + icon_state = "map-scrubbers" + connect_types = CONNECT_TYPE_SCRUBBER + icon_connect_type = "-scrubbers" + color = PIPE_COLOR_RED + +/obj/machinery/atmospherics/pipe/manifold/visible/supply + name="Air supply pipe manifold" + desc = "A manifold composed of supply pipes." + icon_state = "map-supply" + connect_types = CONNECT_TYPE_SUPPLY + icon_connect_type = "-supply" + color = PIPE_COLOR_BLUE + +/obj/machinery/atmospherics/pipe/manifold/visible/yellow + color = PIPE_COLOR_YELLOW + +/obj/machinery/atmospherics/pipe/manifold/visible/cyan + color = PIPE_COLOR_CYAN + +/obj/machinery/atmospherics/pipe/manifold/visible/green + color = PIPE_COLOR_GREEN + +/obj/machinery/atmospherics/pipe/manifold/visible/black + color = PIPE_COLOR_BLACK + +/obj/machinery/atmospherics/pipe/manifold/visible/red + color = PIPE_COLOR_RED + +/obj/machinery/atmospherics/pipe/manifold/visible/blue + color = PIPE_COLOR_BLUE + +/obj/machinery/atmospherics/pipe/manifold/visible/fuel + name = "Fuel pipe manifold" + color = PIPE_COLOR_ORANGE + + +/obj/machinery/atmospherics/pipe/manifold/hidden + icon_state = "map" + level = 1 + alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game + +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers + name="Scrubbers pipe manifold" + desc = "A manifold composed of scrubbers pipes." + icon_state = "map-scrubbers" + connect_types = CONNECT_TYPE_SCRUBBER + icon_connect_type = "-scrubbers" + color = PIPE_COLOR_RED + +/obj/machinery/atmospherics/pipe/manifold/hidden/supply + name="Air supply pipe manifold" + desc = "A manifold composed of supply pipes." + icon_state = "map-supply" + connect_types = CONNECT_TYPE_SUPPLY + icon_connect_type = "-supply" + color = PIPE_COLOR_BLUE + +/obj/machinery/atmospherics/pipe/manifold/hidden/yellow + color = PIPE_COLOR_YELLOW + +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan + color = PIPE_COLOR_CYAN + +/obj/machinery/atmospherics/pipe/manifold/hidden/green + color = PIPE_COLOR_GREEN + +/obj/machinery/atmospherics/pipe/manifold/hidden/black + color = PIPE_COLOR_BLACK + +/obj/machinery/atmospherics/pipe/manifold/hidden/red + color = PIPE_COLOR_RED + +/obj/machinery/atmospherics/pipe/manifold/hidden/blue + color = PIPE_COLOR_BLUE + +/obj/machinery/atmospherics/pipe/manifold/hidden/fuel + name = "Fuel pipe manifold" + color = PIPE_COLOR_ORANGE + +/obj/machinery/atmospherics/pipe/manifold4w + icon = 'icons/atmos/manifold.dmi' + icon_state = "" + name = "4-way pipe manifold" + desc = "A manifold composed of regular pipes." + + volume = ATMOS_DEFAULT_VOLUME_PIPE * 2 + + dir = SOUTH + initialize_directions = NORTH|SOUTH|EAST|WEST + + var/obj/machinery/atmospherics/node3 + var/obj/machinery/atmospherics/node4 + + level = 1 + +/obj/machinery/atmospherics/pipe/manifold4w/New() + ..() + alpha = 255 + icon = null + +/obj/machinery/atmospherics/pipe/manifold4w/pipeline_expansion() + return list(node1, node2, node3, node4) + +/obj/machinery/atmospherics/pipe/manifold4w/Process() + if(!parent) + ..() + else + . = PROCESS_KILL + +/obj/machinery/atmospherics/pipe/manifold4w/Destroy() + if(node1) + node1.disconnect(src) + node1 = null + if(node2) + node2.disconnect(src) + node2 = null + if(node3) + node3.disconnect(src) + node3 = null + if(node4) + node4.disconnect(src) + node4 = null + + . = ..() + +/obj/machinery/atmospherics/pipe/manifold4w/disconnect(obj/machinery/atmospherics/reference) + if(reference == node1) + if(istype(node1, /obj/machinery/atmospherics/pipe)) + qdel(parent) + node1 = null + + if(reference == node2) + if(istype(node2, /obj/machinery/atmospherics/pipe)) + qdel(parent) + node2 = null + + if(reference == node3) + if(istype(node3, /obj/machinery/atmospherics/pipe)) + qdel(parent) + node3 = null + + if(reference == node4) + if(istype(node4, /obj/machinery/atmospherics/pipe)) + qdel(parent) + node4 = null + + update_icon() + + ..() + +/obj/machinery/atmospherics/pipe/manifold4w/change_color(var/new_color) + ..() + //for updating connected atmos device pipes (i.e. vents, manifolds, etc) + if(node1) + node1.update_underlays() + if(node2) + node2.update_underlays() + if(node3) + node3.update_underlays() + if(node4) + node4.update_underlays() + +/obj/machinery/atmospherics/pipe/manifold4w/update_icon(var/safety = 0) + if(!atmos_initalized) + return + if(!check_icon_cache()) + return + + set_leaking(!(node1 && node2 && node3 && node4)) + alpha = 255 + + if(!node1 && !node2 && !node3 && !node4) + var/turf/T = get_turf(src) + new /obj/item/pipe(loc, make_from=src) + for (var/obj/machinery/meter/meter in T) + if (meter.target == src) + new /obj/item/pipe_meter(T) + qdel(meter) + qdel(src) + else + overlays.Cut() + overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "4way" + icon_connect_type) + overlays += icon_manager.get_atmos_icon("manifold", , , "clamps_4way" + icon_connect_type) + underlays.Cut() + + /* + var/list/directions = list(NORTH, SOUTH, EAST, WEST) + + + directions -= add_underlay(node1) + directions -= add_underlay(node2) + directions -= add_underlay(node3) + directions -= add_underlay(node4) + + for(var/D in directions) + add_underlay(,D) + */ + + var/turf/T = get_turf(src) + var/list/directions = list(NORTH, SOUTH, EAST, WEST) + var/node1_direction = get_dir(src, node1) + var/node2_direction = get_dir(src, node2) + var/node3_direction = get_dir(src, node3) + var/node4_direction = get_dir(src, node4) + + directions -= dir + + directions -= add_underlay(T,node1,node1_direction,icon_connect_type) + directions -= add_underlay(T,node2,node2_direction,icon_connect_type) + directions -= add_underlay(T,node3,node3_direction,icon_connect_type) + directions -= add_underlay(T,node4,node4_direction,icon_connect_type) + + for(var/D in directions) + add_underlay(T,,D,icon_connect_type) + + +/obj/machinery/atmospherics/pipe/manifold4w/update_underlays() + ..() + update_icon() + +/obj/machinery/atmospherics/pipe/manifold4w/hide(var/i) + if(istype(loc, /turf/simulated)) + set_invisibility(i ? 101 : 0) + update_icon() + +/obj/machinery/atmospherics/pipe/manifold4w/atmos_init() + ..() + for(var/obj/machinery/atmospherics/target in get_step(src,1)) + if(target.initialize_directions & 2) + if (check_connect_types(target,src)) + node1 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,2)) + if(target.initialize_directions & 1) + if (check_connect_types(target,src)) + node2 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,4)) + if(target.initialize_directions & 8) + if (check_connect_types(target,src)) + node3 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,8)) + if(target.initialize_directions & 4) + if (check_connect_types(target,src)) + node4 = target + break + + if(!node1 && !node2 && !node3 && !node4) + qdel(src) + return + + var/turf/T = get_turf(src) + if(level == 1 && !T.is_plating()) hide(1) + update_icon() + +/obj/machinery/atmospherics/pipe/manifold4w/visible + icon_state = "map_4way" + level = 2 + +/obj/machinery/atmospherics/pipe/manifold4w/visible/scrubbers + name="4-way scrubbers pipe manifold" + desc = "A manifold composed of scrubbers pipes." + icon_state = "map_4way-scrubbers" + connect_types = CONNECT_TYPE_SCRUBBER + icon_connect_type = "-scrubbers" + color = PIPE_COLOR_RED + +/obj/machinery/atmospherics/pipe/manifold4w/visible/supply + name="4-way air supply pipe manifold" + desc = "A manifold composed of supply pipes." + icon_state = "map_4way-supply" + connect_types = CONNECT_TYPE_SUPPLY + icon_connect_type = "-supply" + color = PIPE_COLOR_BLUE + +/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow + color = PIPE_COLOR_YELLOW + +/obj/machinery/atmospherics/pipe/manifold4w/visible/cyan + color = PIPE_COLOR_CYAN + +/obj/machinery/atmospherics/pipe/manifold4w/visible/green + color = PIPE_COLOR_GREEN + +/obj/machinery/atmospherics/pipe/manifold4w/visible/black + color = PIPE_COLOR_BLACK + +/obj/machinery/atmospherics/pipe/manifold4w/visible/red + color = PIPE_COLOR_RED + +/obj/machinery/atmospherics/pipe/manifold4w/visible/blue + color = PIPE_COLOR_BLUE + +/obj/machinery/atmospherics/pipe/manifold4w/visible/fuel + name = "4-way fuel pipe manifold" + color = PIPE_COLOR_ORANGE + +/obj/machinery/atmospherics/pipe/manifold4w/hidden + icon_state = "map_4way" + level = 1 + alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game + +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers + name="4-way scrubbers pipe manifold" + desc = "A manifold composed of scrubbers pipes." + icon_state = "map_4way-scrubbers" + connect_types = CONNECT_TYPE_SCRUBBER + icon_connect_type = "-scrubbers" + color = PIPE_COLOR_RED + +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply + name="4-way air supply pipe manifold" + desc = "A manifold composed of supply pipes." + icon_state = "map_4way-supply" + connect_types = CONNECT_TYPE_SUPPLY + icon_connect_type = "-supply" + color = PIPE_COLOR_BLUE + +/obj/machinery/atmospherics/pipe/manifold4w/hidden/yellow + color = PIPE_COLOR_YELLOW + +/obj/machinery/atmospherics/pipe/manifold4w/hidden/cyan + color = PIPE_COLOR_CYAN + +/obj/machinery/atmospherics/pipe/manifold4w/hidden/green + color = PIPE_COLOR_GREEN + +/obj/machinery/atmospherics/pipe/manifold4w/hidden/black + color = PIPE_COLOR_BLACK + +/obj/machinery/atmospherics/pipe/manifold4w/hidden/red + color = PIPE_COLOR_RED + +/obj/machinery/atmospherics/pipe/manifold4w/hidden/blue + color = PIPE_COLOR_BLUE + +/obj/machinery/atmospherics/pipe/manifold4w/hidden/fuel + name = "4-way fuel pipe manifold" + color = PIPE_COLOR_ORANGE + + +/obj/machinery/atmospherics/pipe/cap + name = "pipe endcap" + desc = "An endcap for pipes." + icon = 'icons/atmos/pipes.dmi' + icon_state = "" + level = 2 + + volume = 35 + + dir = SOUTH + initialize_directions = SOUTH + + var/obj/machinery/atmospherics/node + +/obj/machinery/atmospherics/pipe/cap/New() + ..() + initialize_directions = dir + +/obj/machinery/atmospherics/pipe/cap/hide(var/i) + if(istype(loc, /turf/simulated)) + set_invisibility(i ? 101 : 0) + update_icon() + +/obj/machinery/atmospherics/pipe/cap/pipeline_expansion() + return list(node) + +/obj/machinery/atmospherics/pipe/cap/Process() + if(!parent) + ..() + else + . = PROCESS_KILL +/obj/machinery/atmospherics/pipe/cap/Destroy() + if(node) + node.disconnect(src) + + . = ..() + +/obj/machinery/atmospherics/pipe/cap/disconnect(obj/machinery/atmospherics/reference) + if(reference == node) + if(istype(node, /obj/machinery/atmospherics/pipe)) + qdel(parent) + node = null + + update_icon() + + ..() + +/obj/machinery/atmospherics/pipe/cap/change_color(var/new_color) + ..() + //for updating connected atmos device pipes (i.e. vents, manifolds, etc) + if(node) + node.update_underlays() + +/obj/machinery/atmospherics/pipe/cap/update_icon(var/safety = 0) + if(!check_icon_cache()) + return + + alpha = 255 + + overlays.Cut() + overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "cap") + +/obj/machinery/atmospherics/pipe/cap/atmos_init() + ..() + for(var/obj/machinery/atmospherics/target in get_step(src, dir)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node = target + break + + var/turf/T = src.loc // hide if turf is not intact + if(level == 1 && !T.is_plating()) hide(1) + update_icon() + +/obj/machinery/atmospherics/pipe/cap/visible + level = 2 + icon_state = "cap" + +/obj/machinery/atmospherics/pipe/cap/visible/scrubbers + name = "scrubbers pipe endcap" + desc = "An endcap for scrubbers pipes." + icon_state = "cap-scrubbers" + connect_types = CONNECT_TYPE_SCRUBBER + icon_connect_type = "-scrubbers" + color = PIPE_COLOR_RED + +/obj/machinery/atmospherics/pipe/cap/visible/supply + name = "supply pipe endcap" + desc = "An endcap for supply pipes." + icon_state = "cap-supply" + connect_types = CONNECT_TYPE_SUPPLY + icon_connect_type = "-supply" + color = PIPE_COLOR_BLUE + +/obj/machinery/atmospherics/pipe/cap/visible/fuel + name = "fuel pipe endcap" + desc = "An endcap for fuel pipes." + color = PIPE_COLOR_ORANGE + +/obj/machinery/atmospherics/pipe/cap/hidden + level = 1 + icon_state = "cap" + alpha = 128 + +/obj/machinery/atmospherics/pipe/cap/hidden/scrubbers + name = "scrubbers pipe endcap" + desc = "An endcap for scrubbers pipes." + icon_state = "cap-f-scrubbers" + connect_types = CONNECT_TYPE_SCRUBBER + icon_connect_type = "-scrubbers" + color = PIPE_COLOR_RED + +/obj/machinery/atmospherics/pipe/cap/hidden/supply + name = "supply pipe endcap" + desc = "An endcap for supply pipes." + icon_state = "cap-f-supply" + connect_types = CONNECT_TYPE_SUPPLY + icon_connect_type = "-supply" + color = PIPE_COLOR_BLUE + +/obj/machinery/atmospherics/pipe/cap/hidden/fuel + name = "fuel pipe endcap" + desc = "An endcap for fuel pipes." + color = PIPE_COLOR_ORANGE + + + +/obj/machinery/atmospherics/pipe/tank + icon = 'icons/atmos/tank.dmi' + icon_state = "air_map" + + name = "Pressure Tank" + desc = "A large vessel containing pressurized gas." + + volume = 10000 //in liters, 1 meters by 1 meters by 2 meters ~tweaked it a little to simulate a pressure tank without needing to recode them yet + var/start_pressure = 25*ONE_ATMOSPHERE + + level = 1 + dir = SOUTH + initialize_directions = SOUTH + density = 1 + +/obj/machinery/atmospherics/pipe/tank/Initialize() + icon_state = "air" + initialize_directions = dir + . = ..() + +/obj/machinery/atmospherics/pipe/tank/Process() + if(!parent) + ..() + else + . = PROCESS_KILL + +/obj/machinery/atmospherics/pipe/tank/Destroy() + if(node1) + node1.disconnect(src) + + . = ..() + +/obj/machinery/atmospherics/pipe/tank/pipeline_expansion() + return list(node1) + +/obj/machinery/atmospherics/pipe/tank/update_underlays() + if(..()) + underlays.Cut() + var/turf/T = get_turf(src) + if(!istype(T)) + return + add_underlay(T, node1, dir) + +/obj/machinery/atmospherics/pipe/tank/hide() + update_underlays() + +/obj/machinery/atmospherics/pipe/tank/atmos_init() + ..() + var/connect_direction = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node1 = target + break + + update_underlays() + +/obj/machinery/atmospherics/pipe/tank/disconnect(obj/machinery/atmospherics/reference) + if(reference == node1) + if(istype(node1, /obj/machinery/atmospherics/pipe)) + qdel(parent) + node1 = null + + update_underlays() + + return null + +/obj/machinery/atmospherics/pipe/tank/attackby(var/obj/item/W as obj, var/mob/user as mob) + if(istype(W, /obj/item/device/pipe_painter)) + return + + if(istype(W, /obj/item/device/analyzer)) + return + +/obj/machinery/atmospherics/pipe/tank/air + name = "Pressure Tank (Air)" + icon_state = "air_map" + +/obj/machinery/atmospherics/pipe/tank/air/New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.adjust_multi("oxygen", (start_pressure*O2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature), \ + "nitrogen",(start_pressure*N2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) + + + ..() + icon_state = "air" + +/obj/machinery/atmospherics/pipe/tank/oxygen + name = "Pressure Tank (Oxygen)" + icon_state = "o2_map" + +/obj/machinery/atmospherics/pipe/tank/oxygen/New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.adjust_gas("oxygen", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) + + ..() + icon_state = "o2" + +/obj/machinery/atmospherics/pipe/tank/nitrogen + name = "Pressure Tank (Nitrogen)" + icon_state = "n2_map" + +/obj/machinery/atmospherics/pipe/tank/nitrogen/New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.adjust_gas("nitrogen", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) + + ..() + icon_state = "n2" + +/obj/machinery/atmospherics/pipe/tank/carbon_dioxide + name = "Pressure Tank (Carbon Dioxide)" + icon_state = "co2_map" + +/obj/machinery/atmospherics/pipe/tank/carbon_dioxide/New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.adjust_gas("carbon_dioxide", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) + + ..() + icon_state = "co2" + +/obj/machinery/atmospherics/pipe/tank/phoron + name = "Pressure Tank (Phoron)" + icon_state = "phoron_map" + +/obj/machinery/atmospherics/pipe/tank/phoron/New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.adjust_gas("phoron", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) + + ..() + icon_state = "phoron" + +/obj/machinery/atmospherics/pipe/tank/nitrous_oxide + name = "Pressure Tank (Nitrous Oxide)" + icon_state = "n2o_map" + +/obj/machinery/atmospherics/pipe/tank/nitrous_oxide/New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T0C + + air_temporary.adjust_gas("sleeping_agent", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) + + ..() + icon_state = "n2o" + +/obj/machinery/atmospherics/pipe/tank/hydrogen + name = "Pressure Tank (Hydrogen)" + icon_state = "h2_map" + +/obj/machinery/atmospherics/pipe/tank/hydrogen/New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.adjust_gas("hydrogen", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) + + ..() + icon_state = "h2" + +/obj/machinery/atmospherics/pipe/vent + icon = 'icons/obj/atmospherics/pipe_vent.dmi' + icon_state = "intact" + + name = "Vent" + desc = "A large air vent." + + level = 1 + + volume = 250 + + dir = SOUTH + initialize_directions = SOUTH + + var/build_killswitch = 1 + +/obj/machinery/atmospherics/pipe/vent/New() + initialize_directions = dir + ..() + +/obj/machinery/atmospherics/pipe/vent/high_volume + name = "Larger vent" + volume = 1000 + +/obj/machinery/atmospherics/pipe/vent/Process() + if(!parent) + if(build_killswitch <= 0) + . = PROCESS_KILL + else + build_killswitch-- + ..() + return + else + parent.mingle_with_turf(loc, volume) + +/obj/machinery/atmospherics/pipe/vent/Destroy() + if(node1) + node1.disconnect(src) + + . = ..() + +/obj/machinery/atmospherics/pipe/vent/pipeline_expansion() + return list(node1) + +/obj/machinery/atmospherics/pipe/vent/update_icon() + if(node1) + icon_state = "intact" + + set_dir(get_dir(src, node1)) + + else + icon_state = "exposed" + +/obj/machinery/atmospherics/pipe/vent/atmos_init() + ..() + var/connect_direction = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node1 = target + break + + update_icon() + +/obj/machinery/atmospherics/pipe/vent/disconnect(obj/machinery/atmospherics/reference) + if(reference == node1) + if(istype(node1, /obj/machinery/atmospherics/pipe)) + qdel(parent) + node1 = null + + update_icon() + + return null + +/obj/machinery/atmospherics/pipe/vent/hide(var/i) //to make the little pipe section invisible, the icon changes. + if(node1) + icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact" + set_dir(get_dir(src, node1)) + else + icon_state = "exposed" + + +/obj/machinery/atmospherics/pipe/simple/visible/universal + name="Universal pipe adapter" + desc = "An adapter for regular, supply and scrubbers pipes." + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER + icon_state = "map_universal" + +/obj/machinery/atmospherics/pipe/simple/visible/universal/update_icon(var/safety = 0) + if(!check_icon_cache()) + return + + alpha = 255 + + overlays.Cut() + overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "universal") + underlays.Cut() + + if (node1) + universal_underlays(node1) + if(node2) + universal_underlays(node2) + else + var/node1_dir = get_dir(node1,src) + universal_underlays(,node1_dir) + else if (node2) + universal_underlays(node2) + else + universal_underlays(,dir) + universal_underlays(dir, -180) + +/obj/machinery/atmospherics/pipe/simple/visible/universal/update_underlays() + ..() + update_icon() + + + +/obj/machinery/atmospherics/pipe/simple/hidden/universal + name="Universal pipe adapter" + desc = "An adapter for regular, supply and scrubbers pipes." + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER + icon_state = "map_universal" + +/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_icon(var/safety = 0) + if(!check_icon_cache()) + return + + alpha = 255 + + overlays.Cut() + overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "universal") + underlays.Cut() + + if (node1) + universal_underlays(node1) + if(node2) + universal_underlays(node2) + else + var/node2_dir = turn(get_dir(src,node1),-180) + universal_underlays(,node2_dir) + else if (node2) + universal_underlays(node2) + var/node1_dir = turn(get_dir(src,node2),-180) + universal_underlays(,node1_dir) + else + universal_underlays(,dir) + universal_underlays(,turn(dir, -180)) + +/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_underlays() + ..() + update_icon() + +/obj/machinery/atmospherics/proc/universal_underlays(var/obj/machinery/atmospherics/node, var/direction) + var/turf/T = loc + if(node) + var/node_dir = get_dir(src,node) + if(node.icon_connect_type == "-supply") + add_underlay_adapter(T, , node_dir, "") + add_underlay_adapter(T, node, node_dir, "-supply") + add_underlay_adapter(T, , node_dir, "-scrubbers") + else if (node.icon_connect_type == "-scrubbers") + add_underlay_adapter(T, , node_dir, "") + add_underlay_adapter(T, , node_dir, "-supply") + add_underlay_adapter(T, node, node_dir, "-scrubbers") + else + add_underlay_adapter(T, node, node_dir, "") + add_underlay_adapter(T, , node_dir, "-supply") + add_underlay_adapter(T, , node_dir, "-scrubbers") + else + add_underlay_adapter(T, , direction, "-supply") + add_underlay_adapter(T, , direction, "-scrubbers") + add_underlay_adapter(T, , direction, "") + +/obj/machinery/atmospherics/proc/add_underlay_adapter(var/turf/T, var/obj/machinery/atmospherics/node, var/direction, var/icon_connect_type) //modified from add_underlay, does not make exposed underlays + if(node) + if(!T.is_plating() && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe)) + underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type) + else + underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type) + else + underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "retracted" + icon_connect_type) diff --git a/code/modules/awaymissions/bluespaceartillery.dm b/code/modules/awaymissions/bluespaceartillery.dm new file mode 100644 index 00000000..717a4257 --- /dev/null +++ b/code/modules/awaymissions/bluespaceartillery.dm @@ -0,0 +1,54 @@ + +/obj/machinery/artillerycontrol + var/reload = 180 + name = "bluespace artillery control" + icon_state = "control_boxp1" + icon = 'icons/obj/machines/particle_accelerator2.dmi' + density = 1 + anchored = 1 + +/obj/machinery/artillerycontrol/Process() + if(src.reload<180) + src.reload++ + +/obj/structure/artilleryplaceholder + name = "artillery" + icon = 'icons/obj/machines/artillery.dmi' + anchored = 1 + density = 1 + desc = "The ship's old bluespace artillery cannon. Looks inoperative." + +/obj/structure/artilleryplaceholder/decorative + density = 0 + +/obj/machinery/artillerycontrol/attack_hand(mob/user as mob) + user.set_machine(src) + var/dat = "Bluespace Artillery Control:
            " + dat += "Locked on
            " + dat += "Charge progress: [reload]/180:
            " + dat += "Open Fire
            " + dat += "Deployment of weapon authorized by
            [GLOB.using_map.company_name] Naval Command

            Remember, friendly fire is grounds for termination of your contract and life.
            " + user << browse(dat, "window=scroll") + onclose(user, "scroll") + return + +/obj/machinery/artillerycontrol/Topic(href, href_list, state = GLOB.physical_state) + if(..()) + return 1 + + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) + var/area/thearea = input("Area to jump bombard", "Open Fire") as null|anything in teleportlocs + thearea = thearea ? teleportlocs[thearea] : thearea + if (!thearea || CanUseTopic(usr, GLOB.physical_state) != STATUS_INTERACTIVE) + return + if (src.reload < 180) + return + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) + command_announcement.Announce("Bluespace artillery fire detected. Brace for impact.") + message_admins("[key_name_admin(usr)] has launched an artillery strike.", 1) + var/list/L = list() + for(var/turf/T in get_area_turfs(thearea)) + L+=T + var/loc = pick(L) + explosion(loc,2,5,11) + reload = 0 diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm new file mode 100644 index 00000000..bb8521fc --- /dev/null +++ b/code/modules/awaymissions/corpse.dm @@ -0,0 +1,169 @@ +//These are meant for spawning on maps, namely Away Missions. + +//If someone can do this in a neater way, be my guest-Kor + +//To do: Allow corpses to appear mangled, bloody, etc. Allow customizing the bodies appearance (they're all bald and white right now). + +#define CORPSE_SPAWNER_RANDOM_NAME 0x0001 +#define CORPSE_SPAWNER_CUT_SURVIVAL 0x0002 +#define CORPSE_SPAWNER_CUT_ID_PDA 0x0003 +#define CORPSE_SPAWNER_PLAIN_HEADSET 0x0004 + +#define CORPSE_SPAWNER_RANDOM_SKIN_TONE 0x0008 +#define CORPSE_SPAWNER_RANDOM_SKIN_COLOR 0x0010 +#define CORPSE_SPAWNER_RANDOM_HAIR_COLOR 0x0020 +#define CORPSE_SPAWNER_RANDOM_HAIR_STYLE 0x0040 +#define CORPSE_SPAWNER_RANDOM_FACIAL_STYLE 0x0080 +#define CORPSE_SPAWNER_RANDOM_EYE_COLOR 0x0100 + +#define CORPSE_SPAWNER_NO_RANDOMIZATION ~(CORPSE_SPAWNER_RANDOM_NAME|CORPSE_SPAWNER_RANDOM_SKIN_TONE|CORPSE_SPAWNER_RANDOM_SKIN_COLOR|CORPSE_SPAWNER_RANDOM_HAIR_COLOR|CORPSE_SPAWNER_RANDOM_HAIR_STYLE|CORPSE_SPAWNER_RANDOM_FACIAL_STYLE|CORPSE_SPAWNER_RANDOM_EYE_COLOR) + + +/obj/effect/landmark/corpse + name = "Unknown" + var/species = list(SPECIES_HUMAN) // List of species to pick from. + var/corpse_outfits = list(/decl/hierarchy/outfit) // List of outfits to pick from. Uses pickweight() + var/spawn_flags = (~0) + + var/skin_colors_per_species = list() // Custom skin colors, per species -type-, if any. For example if you want dead Tajaran to always have brown fur, or similar + var/eye_colors_per_species = list() // Custom eye colors, per species -type-, if any. See above as to why. + var/hair_colors_per_species = list() // Custom hair colors, per species -type-, if any. See above as to why. + var/hair_styles_per_species = list() // Custom hair styles, per species -type-, if any. For example if you want a punk gang with handlebars. + var/facial_styles_per_species = list() // Custom facial hair styles, per species -type-, if any. See above as to why + +/obj/effect/landmark/corpse/Initialize() + ..() + + var/mob/living/carbon/human/M = new /mob/living/carbon/human(loc) + + randomize_appearance(M) + equip_outfit(M) + + M.adjustOxyLoss(M.maxHealth)//cease life functions + M.setBrainLoss(M.maxHealth) + var/obj/item/organ/internal/heart/corpse_heart = M.internal_organs_by_name[BP_HEART] + if (corpse_heart) + corpse_heart.pulse = PULSE_NONE//actually stops heart to make worried explorers not care too much + + M.update_icon() + + return INITIALIZE_HINT_QDEL + +#define HEX_COLOR_TO_RGB_ARGS(X) arglist(GetHexColors(X)) +/obj/effect/landmark/corpse/proc/randomize_appearance(var/mob/living/carbon/human/M) + M.set_species(pickweight(species)) + scramble(1, M, 100) //randomizes appearence + + if((spawn_flags & CORPSE_SPAWNER_RANDOM_SKIN_TONE)) + M.randomize_skin_tone() + + if((spawn_flags & CORPSE_SPAWNER_RANDOM_SKIN_COLOR)) + if(M.species.type in skin_colors_per_species) + M.change_skin_color(HEX_COLOR_TO_RGB_ARGS(pickweight(skin_colors_per_species[M.species.type]))) + else + M.s_tone = random_skin_tone(M.species) + + if((spawn_flags & CORPSE_SPAWNER_RANDOM_HAIR_COLOR)) + if(M.species.type in hair_colors_per_species) + M.change_hair_color(HEX_COLOR_TO_RGB_ARGS(pickweight(hair_colors_per_species[M.species.type]))) + else + M.randomize_hair_color() + M.change_facial_hair_color(M.r_hair, M.g_hair, M.b_hair) + + if((spawn_flags & CORPSE_SPAWNER_RANDOM_HAIR_STYLE)) + if(M.species.type in hair_styles_per_species) + M.change_hair(pickweight(hair_styles_per_species[M.species.type])) + else + M.randomize_hair_style() + + if((spawn_flags & CORPSE_SPAWNER_RANDOM_FACIAL_STYLE)) + if(M.species.type in facial_styles_per_species) + M.change_facial_hair(pickweight(facial_styles_per_species[M.species.type])) + else + M.randomize_facial_hair_style() + + if((spawn_flags & CORPSE_SPAWNER_RANDOM_EYE_COLOR)) + if(M.species.type in eye_colors_per_species) + M.change_eye_color(HEX_COLOR_TO_RGB_ARGS(pickweight(eye_colors_per_species[M.species.type]))) + else + M.randomize_eye_color() + + M.SetName((CORPSE_SPAWNER_RANDOM_NAME & spawn_flags) ? M.species.get_random_name(M.gender) : name) + M.real_name = M.name + +#undef HEX_COLOR_TO_RGB_ARGS + +/obj/effect/landmark/corpse/proc/equip_outfit(var/mob/living/carbon/human/M) + var/adjustments = 0 + adjustments = (spawn_flags & CORPSE_SPAWNER_CUT_SURVIVAL) ? (adjustments|OUTFIT_ADJUSTMENT_SKIP_SURVIVAL_GEAR) : adjustments + adjustments = (spawn_flags & CORPSE_SPAWNER_CUT_ID_PDA) ? (adjustments|OUTFIT_ADJUSTMENT_SKIP_ID_PDA) : adjustments + adjustments = (spawn_flags & CORPSE_SPAWNER_PLAIN_HEADSET) ? (adjustments|OUTFIT_ADJUSTMENT_PLAIN_HEADSET) : adjustments + + var/decl/hierarchy/outfit/corpse_outfit = outfit_by_type(pickweight(corpse_outfits)) + corpse_outfit.equip(M, equip_adjustments = adjustments) + +/obj/effect/landmark/corpse/chef + name = "Chef" + corpse_outfits = list(/decl/hierarchy/outfit/job/service/chef) + +/obj/effect/landmark/corpse/doctor + name = "Doctor" + corpse_outfits = list(/decl/hierarchy/outfit/job/medical/doctor) + +/obj/effect/landmark/corpse/engineer + name = "Engineer" + corpse_outfits = list(/decl/hierarchy/outfit/job/engineering/engineer) + +/obj/effect/landmark/corpse/scientist + name = "Scientist" + corpse_outfits = list(/decl/hierarchy/outfit/job/science/scientist) + +/obj/effect/landmark/corpse/engineer/rig + corpse_outfits = list(/decl/hierarchy/outfit/job/engineering/engineer/void) + +/obj/effect/landmark/corpse/clown + name = "Clown" + corpse_outfits = list(/decl/hierarchy/outfit/clown) + +/obj/effect/landmark/corpse/miner + name = "Miner" + corpse_outfits = list(/decl/hierarchy/outfit/job/cargo/mining) + +/obj/effect/landmark/corpse/miner/rig + corpse_outfits = list(/decl/hierarchy/outfit/job/cargo/mining/void) + + +/obj/effect/landmark/corpse/bridgeofficer + name = "Bridge Officer" + corpse_outfits = list(/decl/hierarchy/outfit/nanotrasen/officer) + +/obj/effect/landmark/corpse/commander + name = "Commander" + corpse_outfits = list(/decl/hierarchy/outfit/nanotrasen/commander) + + +/obj/effect/landmark/corpse/pirate + name = "Pirate" + corpse_outfits = list(/decl/hierarchy/outfit/pirate/norm) + spawn_flags = CORPSE_SPAWNER_NO_RANDOMIZATION + +/obj/effect/landmark/corpse/pirate/ranged + name = "Pirate Gunner" + corpse_outfits = list(/decl/hierarchy/outfit/pirate/space) + +/obj/effect/landmark/corpse/russian + name = "Russian" + corpse_outfits = list(/decl/hierarchy/outfit/soviet_soldier) + spawn_flags = CORPSE_SPAWNER_NO_RANDOMIZATION + +/obj/effect/landmark/corpse/russian/ranged + corpse_outfits = list(/decl/hierarchy/outfit/soviet_soldier) + +/obj/effect/landmark/corpse/syndicate + name = "Syndicate Operative" + corpse_outfits = list(/decl/hierarchy/outfit/mercenary/syndicate) + spawn_flags = CORPSE_SPAWNER_NO_RANDOMIZATION + +/obj/effect/landmark/corpse/syndicate/commando + name = "Syndicate Commando" + corpse_outfits = list(/decl/hierarchy/outfit/mercenary/syndicate/commando) diff --git a/code/modules/awaymissions/exile.dm b/code/modules/awaymissions/exile.dm new file mode 100644 index 00000000..1f96ca4a --- /dev/null +++ b/code/modules/awaymissions/exile.dm @@ -0,0 +1,39 @@ +//////Exile implants will allow you to use the station gate, but not return home. This will allow security to exile badguys/for badguys to exile their kill targets//////// + + +/obj/item/weapon/implanter/exile + name = "implanter-exile" + imp = /obj/item/weapon/implant/exile + +/obj/item/weapon/implant/exile + name = "exile" + desc = "Prevents you from returning from away missions." + + get_data() + var/dat = {" +Implant Specifications:
            +Name: [GLOB.using_map.company_name] Employee Exile Implant
            +Implant Details: The onboard gateway system has been modified to reject entry by individuals containing this implant
            "} + return dat + +/obj/item/weapon/implantcase/exile + name = "Glass Case- 'Exile'" + desc = "A case containing an exile implant." + icon = 'icons/obj/items.dmi' + icon_state = "implantcase-r" + imp = /obj/item/weapon/implant/exile + +/obj/structure/closet/secure_closet/exile + name = "Exile Implants" + req_access = list(access_hos) + + New() + ..() + sleep(2) + new /obj/item/weapon/implanter/exile(src) + new /obj/item/weapon/implantcase/exile(src) + new /obj/item/weapon/implantcase/exile(src) + new /obj/item/weapon/implantcase/exile(src) + new /obj/item/weapon/implantcase/exile(src) + new /obj/item/weapon/implantcase/exile(src) + return \ No newline at end of file diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm new file mode 100644 index 00000000..6954b6a6 --- /dev/null +++ b/code/modules/awaymissions/gateway.dm @@ -0,0 +1,236 @@ +/obj/machinery/gateway + name = "gateway" + desc = "A mysterious gateway built by unknown hands, it allows for faster than light travel to far-flung locations." + icon = 'icons/obj/machines/gateway.dmi' + icon_state = "off" + density = 1 + anchored = 1 + var/active = 0 + + +/obj/machinery/gateway/Initialize() + update_icon() + if(dir == SOUTH) + set_density(0) + . = ..() + +/obj/machinery/gateway/update_icon() + if(active) + icon_state = "on" + return + icon_state = "off" + + + +//this is da important part wot makes things go +/obj/machinery/gateway/centerstation + density = 1 + icon_state = "offcenter" + use_power = 1 + + //warping vars + var/list/linked = list() + var/ready = 0 //have we got all the parts for a gateway? + var/wait = 0 //this just grabs world.time at world start + var/obj/machinery/gateway/centeraway/awaygate = null + +/obj/machinery/gateway/centerstation/Initialize() + update_icon() + wait = world.time + config.gateway_delay //+ thirty minutes default + awaygate = locate(/obj/machinery/gateway/centeraway) + . = ..() + +/obj/machinery/gateway/centerstation/update_icon() + if(active) + icon_state = "oncenter" + return + icon_state = "offcenter" + + + +obj/machinery/gateway/centerstation/Process() + if(stat & (NOPOWER)) + if(active) toggleoff() + return + + if(active) + use_power(5000) + + +/obj/machinery/gateway/centerstation/proc/detect() + linked = list() //clear the list + var/turf/T = loc + + for(var/i in GLOB.alldirs) + T = get_step(loc, i) + var/obj/machinery/gateway/G = locate(/obj/machinery/gateway) in T + if(G) + linked.Add(G) + continue + + //this is only done if we fail to find a part + ready = 0 + toggleoff() + break + + if(linked.len == 8) + ready = 1 + + +/obj/machinery/gateway/centerstation/proc/toggleon(mob/user as mob) + if(!ready) return + if(linked.len != 8) return + if(!powered()) return + if(!awaygate) + to_chat(user, "Error: No destination found.") + return + if(world.time < wait) + to_chat(user, "Error: Warpspace triangulation in progress. Estimated time to completion: [round(((wait - world.time) / 10) / 60)] minutes.") + return + + for(var/obj/machinery/gateway/G in linked) + G.active = 1 + G.update_icon() + active = 1 + update_icon() + + +/obj/machinery/gateway/centerstation/proc/toggleoff() + for(var/obj/machinery/gateway/G in linked) + G.active = 0 + G.update_icon() + active = 0 + update_icon() + + +/obj/machinery/gateway/centerstation/attack_hand(mob/user as mob) + if(!ready) + detect() + return + if(!active) + toggleon(user) + return + toggleoff() + + +//okay, here's the good teleporting stuff +/obj/machinery/gateway/centerstation/Bumped(atom/movable/M as mob|obj) + if(!ready) return + if(!active) return + if(!awaygate) return + if(awaygate.calibrated) + M.loc = get_step(awaygate.loc, SOUTH) + M.set_dir(SOUTH) + return + else + var/obj/effect/landmark/dest = pick(GLOB.awaydestinations) + if(dest) + M.loc = dest.loc + M.set_dir(SOUTH) + use_power(5000) + return + + +/obj/machinery/gateway/centerstation/attackby(obj/item/device/W as obj, mob/user as mob) + if(isMultitool(W)) + to_chat(user, "The gate is already calibrated, there is no work for you to do here.") + return + +/////////////////////////////////////Away//////////////////////// + + +/obj/machinery/gateway/centeraway + density = 1 + icon_state = "offcenter" + use_power = 0 + var/calibrated = 1 + var/list/linked = list() //a list of the connected gateway chunks + var/ready = 0 + var/obj/machinery/gateway/centeraway/stationgate = null + + +/obj/machinery/gateway/centeraway/Initialize() + update_icon() + stationgate = locate(/obj/machinery/gateway/centerstation) + . = ..() + +/obj/machinery/gateway/centeraway/update_icon() + if(active) + icon_state = "oncenter" + return + icon_state = "offcenter" + + +/obj/machinery/gateway/centeraway/proc/detect() + linked = list() //clear the list + var/turf/T = loc + + for(var/i in GLOB.alldirs) + T = get_step(loc, i) + var/obj/machinery/gateway/G = locate(/obj/machinery/gateway) in T + if(G) + linked.Add(G) + continue + + //this is only done if we fail to find a part + ready = 0 + toggleoff() + break + + if(linked.len == 8) + ready = 1 + + +/obj/machinery/gateway/centeraway/proc/toggleon(mob/user as mob) + if(!ready) return + if(linked.len != 8) return + if(!stationgate) + to_chat(user, "Error: No destination found.") + return + + for(var/obj/machinery/gateway/G in linked) + G.active = 1 + G.update_icon() + active = 1 + update_icon() + + +/obj/machinery/gateway/centeraway/proc/toggleoff() + for(var/obj/machinery/gateway/G in linked) + G.active = 0 + G.update_icon() + active = 0 + update_icon() + + +/obj/machinery/gateway/centeraway/attack_hand(mob/user as mob) + if(!ready) + detect() + return + if(!active) + toggleon(user) + return + toggleoff() + + +/obj/machinery/gateway/centeraway/Bumped(atom/movable/M as mob|obj) + if(!ready) return + if(!active) return + if(istype(M, /mob/living/carbon)) + for(var/obj/item/weapon/implant/exile/E in M)//Checking that there is an exile implant in the contents + if(E.imp_in == M)//Checking that it's actually implanted vs just in their pocket + to_chat(M, "The remote gate has detected your exile implant and is blocking your entry.") + return + M.loc = get_step(stationgate.loc, SOUTH) + M.set_dir(SOUTH) + + +/obj/machinery/gateway/centeraway/attackby(obj/item/device/W as obj, mob/user as mob) + if(isMultitool(W)) + if(calibrated) + to_chat(user, "The gate is already calibrated, there is no work for you to do here.") + return + else + to_chat(user, "Recalibration successful!: This gate's systems have been fine tuned. Travel to this gate will now be on target.") + calibrated = 1 + return diff --git a/code/modules/awaymissions/loot.dm b/code/modules/awaymissions/loot.dm new file mode 100644 index 00000000..8de57415 --- /dev/null +++ b/code/modules/awaymissions/loot.dm @@ -0,0 +1,24 @@ +/obj/effect/spawner/lootdrop + icon = 'icons/mob/screen1.dmi' + icon_state = "x2" + var/lootcount = 1 //how many items will be spawned + var/lootdoubles = 0 //if the same item can be spawned twice + var/loot = "" //a list of possible items to spawn- a string of paths + +/obj/effect/spawner/lootdrop/Initialize() + var/list/things = params2list(loot) + + if(things && things.len) + for(var/i = lootcount, i > 0, i--) + if(!things.len) + return + + var/loot_spawn = pick(things) + var/loot_path = text2path(loot_spawn) + + if(!loot_path || !lootdoubles) + things.Remove(loot_spawn) + continue + + new loot_path(get_turf(src)) + return INITIALIZE_HINT_QDEL diff --git a/code/modules/awaymissions/pamphlet.dm b/code/modules/awaymissions/pamphlet.dm new file mode 100644 index 00000000..5d30000e --- /dev/null +++ b/code/modules/awaymissions/pamphlet.dm @@ -0,0 +1,38 @@ +/obj/item/weapon/paper/pamphlet + name = "pamphlet" + icon_state = "pamphlet" + info = "Welcome to the Gateway project...
            \ + Congratulations! If you're reading this, you and your superiors have decided that you're \ + ready to commit to a life spent colonising the rolling hills of far away worlds. You \ + must be ready for a lifetime of adventure, a little bit of hard work, and an award \ + winning dental plan- but that's not all the Gateway project has to offer.
            \ +
            Because we care about you, we feel it is only fair to make sure you know the risks \ + before you commit to joining the Gateway project. All away destinations have \ + been fully scanned by a expeditionary team, and are certified to be 100% safe. \ + We've even left a case of space beer along with the basic materials you'll need to expand \ + the Project's operational area and start your new life.

            \ + Gateway Operation Basics
            \ + All approved Gateways operate on the same basic principals. They operate off \ + area equipment power as you would expect, but they also require a backup wire with at least \ + 128, 000 Watts of power running through it. Without this supply, it cannot safely function \ + and will reject all attempts at operation.

            \ + Once it is correctly setup, and once it has enough power to operate, the Gateway will begin \ + searching for an output location. The amount of time this takes is variable, but the Gateway \ + interface will give you an estimate accurate to the minute. Power loss will not interrupt the \ + searching process. Influenza will not interrupt the searching process. Temporal anomalies \ + may cause the estimate to be inaccurate, but will not interrupt the searching process.

            \ + Life On The Other Side
            \ + Once you have traversed the Gateway, you may experience some disorientation. Do not panic. \ + This is a normal side effect of travelling vast distances in a short period of time. You should \ + survey the immediate area, and attempt to locate your complimentary case of space beer. Our \ + expeditionary teams have ensured the complete safety of all away locations, but in a small \ + number of cases, the Gateway they have established may not be immediately obvious. \ + Do not panic if you cannot locate the return Gateway. Begin colonisation of the destination. \ +

            A New World
            \ + As a participant in the Gateway Project, you will be on the frontiers of space. \ + Though complete safety is assured, participants are advised to prepare for inhospitable \ + environs." + +//we don't want the silly text overlay! +/obj/item/weapon/paper/pamphlet/update_icon() + return \ No newline at end of file diff --git a/code/modules/awaymissions/trigger.dm b/code/modules/awaymissions/trigger.dm new file mode 100644 index 00000000..e388b0dd --- /dev/null +++ b/code/modules/awaymissions/trigger.dm @@ -0,0 +1,44 @@ +/obj/effect/step_trigger/message + var/message //the message to give to the mob + var/once = 1 + +/obj/effect/step_trigger/message/Trigger(mob/M as mob) + if(M.client) + to_chat(M, "[message]") + if(once) + qdel(src) + +/obj/effect/step_trigger/teleport_fancy + var/locationx + var/locationy + var/uses = 1 //0 for infinite uses + var/entersparks = 0 + var/exitsparks = 0 + var/entersmoke = 0 + var/exitsmoke = 0 + +/obj/effect/step_trigger/teleport_fancy/Trigger(mob/M as mob) + var/dest = locate(locationx, locationy, z) + M.Move(dest) + + if(entersparks) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(4, 1, src) + s.start() + if(exitsparks) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(4, 1, dest) + s.start() + + if(entersmoke) + var/datum/effect/effect/system/smoke_spread/s = new /datum/effect/effect/system/smoke_spread + s.set_up(4, 1, src, 0) + s.start() + if(exitsmoke) + var/datum/effect/effect/system/smoke_spread/s = new /datum/effect/effect/system/smoke_spread + s.set_up(4, 1, dest, 0) + s.start() + + uses-- + if(uses == 0) + qdel(src) \ No newline at end of file diff --git a/code/modules/awaymissions/zlevel.dm b/code/modules/awaymissions/zlevel.dm new file mode 100644 index 00000000..381ddc48 --- /dev/null +++ b/code/modules/awaymissions/zlevel.dm @@ -0,0 +1,90 @@ +proc/createRandomZlevel() + if(GLOB.awaydestinations.len) //crude, but it saves another var! + return + + if(!fexists("maps/RandomZLevels/fileList.txt")) + return + + var/list/potentialRandomZlevels = list() + admin_notice("Searching for away missions...", R_DEBUG) + var/list/Lines = file2list("maps/RandomZLevels/fileList.txt") + if(!Lines.len) return + for (var/t in Lines) + if (!t) + continue + + t = trim(t) + if (length(t) == 0) + continue + else if (copytext(t, 1, 2) == "#") + continue + + var/pos = findtext(t, " ") + var/name = null + // var/value = null + + if (pos) + // No, don't do lowertext here, that breaks paths on linux + name = copytext(t, 1, pos) + // value = copytext(t, pos + 1) + else + // No, don't do lowertext here, that breaks paths on linux + name = t + + if (!name) + continue + + potentialRandomZlevels.Add(name) + + + if(potentialRandomZlevels.len) + admin_notice("Loading away mission...", R_DEBUG) + + var/map = pick(potentialRandomZlevels) + var/file = file(map) + if(isfile(file)) + load_new_z_level(file, "Away mission") + log_debug("away mission loaded: [map]") + + for(var/obj/effect/landmark/L in landmarks_list) + if (L.name != "awaystart") + continue + GLOB.awaydestinations.Add(L) + + admin_notice("Away mission loaded.", R_DEBUG) + + else + admin_notice("No away missions found.", R_DEBUG) + return + +/proc/generateMapList(filename) + var/list/potentialMaps = list() + var/list/Lines = world.file2list(filename) + + if(!Lines.len) + return + for (var/t in Lines) + if (!t) + continue + + t = trim(t) + if (length(t) == 0) + continue + else if (copytext(t, 1, 2) == "#") + continue + + var/pos = findtext(t, " ") + var/name = null + + if (pos) + name = lowertext(copytext(t, 1, pos)) + + else + name = lowertext(t) + + if (!name) + continue + + potentialMaps.Add(t) + + return potentialMaps \ No newline at end of file diff --git a/code/modules/blob/blob.dm b/code/modules/blob/blob.dm new file mode 100644 index 00000000..fae6af1e --- /dev/null +++ b/code/modules/blob/blob.dm @@ -0,0 +1,253 @@ +//I will need to recode parts of this but I am way too tired atm +/obj/effect/blob + name = "blob" + icon = 'icons/mob/blob.dmi' + icon_state = "blob" + light_range = 2 + light_color = "#b5ff5b" + desc = "Some blob creature thingy." + density = 1 + opacity = 1 + anchored = 1 + mouse_opacity = 2 + + plane = BLOB_PLANE + layer = BLOB_SHIELD_LAYER + + var/maxHealth = 30 + var/health + var/regen_rate = 5 + var/brute_resist = 4 + var/fire_resist = 1 + var/laser_resist = 4 // Special resist for laser based weapons - Emitters or handheld energy weaponry. Damage is divided by this and THEN by fire_resist. + var/expandType = /obj/effect/blob + var/secondary_core_growth_chance = 5 //% chance to grow a secondary blob core instead of whatever was suposed to grown. Secondary cores are considerably weaker, but still nasty. + +/obj/effect/blob/New(loc) + health = maxHealth + update_icon() + return ..(loc) + +/obj/effect/blob/CanPass(var/atom/movable/mover, vra/turf/target, var/height = 0, var/air_group = 0) + if(air_group || height == 0) + return 1 + return 0 + +/obj/effect/blob/ex_act(var/severity) + switch(severity) + if(1) + take_damage(rand(100, 120) / brute_resist) + if(2) + take_damage(rand(60, 100) / brute_resist) + if(3) + take_damage(rand(20, 60) / brute_resist) + +/obj/effect/blob/update_icon() + if(health > maxHealth / 2) + icon_state = "blob" + else + icon_state = "blob_damaged" + +/obj/effect/blob/proc/take_damage(var/damage) + health -= damage + if(health < 0) + playsound(loc, 'sound/effects/splat.ogg', 50, 1) + qdel(src) + else + update_icon() + +/obj/effect/blob/proc/regen() + health = min(health + regen_rate, maxHealth) + update_icon() + +/obj/effect/blob/proc/expand(var/turf/T) + if(istype(T, /turf/unsimulated/) || istype(T, /turf/space) || (istype(T, /turf/simulated/mineral) && T.density)) + return + if(istype(T, /turf/simulated/wall)) + var/turf/simulated/wall/SW = T + SW.take_damage(80) + return + var/obj/structure/girder/G = locate() in T + if(G) + if(prob(40)) + G.dismantle() + return + var/obj/structure/window/W = locate() in T + if(W) + W.shatter() + return + var/obj/structure/grille/GR = locate() in T + if(GR) + qdel(GR) + return + for(var/obj/machinery/door/D in T) // There can be several - and some of them can be open, locate() is not suitable + if(D.density) + D.ex_act(2) + return + var/obj/structure/foamedmetal/F = locate() in T + if(F) + qdel(F) + return + var/obj/structure/inflatable/I = locate() in T + if(I) + I.deflate(1) + return + + var/obj/vehicle/V = locate() in T + if(V) + V.ex_act(2) + return + var/obj/mecha/M = locate() in T + if(M) + M.visible_message("The blob attacks \the [M]!") + M.take_damage(40) + return + var/obj/machinery/camera/CA = locate() in T + if(CA) + CA.take_damage(30) + return + + // Above things, we destroy completely and thus can use locate. Mobs are different. + for(var/mob/living/L in T) + if(L.stat == DEAD) + continue + L.visible_message("The blob attacks \the [L]!", "The blob attacks you!") + playsound(loc, 'sound/effects/attackblob.ogg', 50, 1) + L.take_organ_damage(rand(30, 40)) + return + if(!(locate(/obj/effect/blob/core) in range(T, 2)) && prob(secondary_core_growth_chance)) + new/obj/effect/blob/core/secondary(T) + else + new expandType(T, min(health, 30)) + +/obj/effect/blob/proc/pulse(var/forceLeft, var/list/dirs) + regen() + sleep(4) + var/pushDir = pick(dirs) + var/turf/T = get_step(src, pushDir) + var/obj/effect/blob/B = (locate() in T) + if(!B) + if(prob(health)) + expand(T) + return + if(forceLeft) + B.pulse(forceLeft - 1, dirs) + +/obj/effect/blob/bullet_act(var/obj/item/projectile/Proj) + if(!Proj) + return + + switch(Proj.damage_type) + if(BRUTE) + take_damage(Proj.damage / brute_resist) + if(BURN) + take_damage((Proj.damage / laser_resist) / fire_resist) + return 0 + +/obj/effect/blob/attackby(var/obj/item/weapon/W, var/mob/user) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + playsound(loc, 'sound/effects/attackblob.ogg', 50, 1) + var/damage = 0 + switch(W.damtype) + if("fire") + damage = (W.force / fire_resist) + if(isWelder(W)) + playsound(loc, 'sound/items/Welder.ogg', 100, 1) + if("brute") + damage = (W.force / brute_resist) + + take_damage(damage) + return + +/obj/effect/blob/core + name = "blob core" + icon = 'icons/mob/blob.dmi' + icon_state = "blob_core" + maxHealth = 200 + brute_resist = 2 + fire_resist = 2 + laser_resist = 8 + regen_rate = 2 + + layer = BLOB_CORE_LAYER + + expandType = /obj/effect/blob/shield + var/blob_may_process = 1 + var/growth_range = 10 // Maximal distance for new blob pieces from this core. + +// Rough icon state changes that reflect the core's health +/obj/effect/blob/core/update_icon() + var/health_percent = (health / maxHealth) * 100 + switch(health_percent) + if(66 to INFINITY) + icon_state = "blob_core" + if(33 to 66) + icon_state = "blob_node" + if(-INFINITY to 33) + icon_state = "blob_factory" + +/obj/effect/blob/core/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/effect/blob/core/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/effect/blob/core/Process() + set waitfor = 0 + if(!blob_may_process) + return + blob_may_process = 0 + sleep(0) + pulse(20, list(NORTH, EAST)) + pulse(20, list(NORTH, WEST)) + pulse(20, list(SOUTH, EAST)) + pulse(20, list(SOUTH, WEST)) + blob_may_process = 1 + +// Half the stats of a normal core. Blob has a very small probability of growing these when spreading. These will spread the blob further. +/obj/effect/blob/core/secondary + name = "small blob core" + icon = 'icons/mob/blob.dmi' + icon_state = "blob_node" + maxHealth = 100 + brute_resist = 1 + fire_resist = 1 + laser_resist = 5 + regen_rate = 1 + growth_range = 3 + + layer = BLOB_NODE_LAYER + +/obj/effect/blob/core/secondary/update_icon() + icon_state = (health / maxHealth >= 0.5) ? "blob_node" : "blob_factory" + +/obj/effect/blob/shield + name = "strong blob" + icon = 'icons/mob/blob.dmi' + icon_state = "blob_idle" + desc = "Some blob creature thingy." + maxHealth = 60 + brute_resist = 1 + fire_resist = 2 + laser_resist = 6 +/obj/effect/blob/shield/New() + ..() + update_nearby_tiles() + +/obj/effect/blob/shield/Destroy() + set_density(0) + update_nearby_tiles() + ..() + +/obj/effect/blob/shield/update_icon() + if(health > maxHealth * 2 / 3) + icon_state = "blob_idle" + else if(health > maxHealth / 3) + icon_state = "blob" + else + icon_state = "blob_damaged" + +/obj/effect/blob/shield/CanPass(var/atom/movable/mover, var/turf/target, var/height = 0, var/air_group = 0) + return !density diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm new file mode 100644 index 00000000..14c86cdf --- /dev/null +++ b/code/modules/client/asset_cache.dm @@ -0,0 +1,302 @@ +/* +Asset cache quick users guide: + +Make a datum at the bottom of this file with your assets for your thing. +The simple subsystem will most like be of use for most cases. +Then call get_asset_datum() with the type of the datum you created and store the return +Then call .send(client) on that stored return value. + +You can set verify to TRUE if you want send() to sleep until the client has the assets. +*/ + + +// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping. +// This is doubled for the first asset, then added per asset after +#define ASSET_CACHE_SEND_TIMEOUT 7 + +//When sending mutiple assets, how many before we give the client a quaint little sending resources message +#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8 + +/client + var/list/cache = list() // List of all assets sent to this client by the asset cache. + var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement. + var/list/sending = list() + var/last_asset_job = 0 // Last job done. + +//Generated names do not include file extention. +//Used mainly for code that deals with assets in a generic way +//The same asset will always lead to the same asset name +/proc/generate_asset_name(var/file) + return "asset.[md5(fcopy_rsc(file))]" + +//This proc sends the asset to the client, but only if it needs it. +//This proc blocks(sleeps) unless verify is set to false +/proc/send_asset(var/client/client, var/asset_name, var/verify = TRUE, var/check_cache = TRUE) + if(!istype(client)) + if(ismob(client)) + var/mob/M = client + if(M.client) + client = M.client + + else + return 0 + + else + return 0 + + if(check_cache && (client.cache.Find(asset_name) || client.sending.Find(asset_name))) + return 0 + + client << browse_rsc(asset_cache.cache[asset_name], asset_name) + if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip. + if (client) + client.cache += asset_name + return 1 + if (!client) + return 0 + + client.sending |= asset_name + var/job = ++client.last_asset_job + + client << browse({" + + "}, "window=asset_cache_browser") + + var/t = 0 + var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT + while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic() + sleep(1) // Lock up the caller until this is received. + t++ + + if(client) + client.sending -= asset_name + client.cache |= asset_name + client.completed_asset_jobs -= job + + return 1 + +//This proc blocks(sleeps) unless verify is set to false +/proc/send_asset_list(var/client/client, var/list/asset_list, var/verify = TRUE) + if(!istype(client)) + if(ismob(client)) + var/mob/M = client + if(M.client) + client = M.client + + else + return 0 + + else + return 0 + + var/list/unreceived = asset_list - (client.cache + client.sending) + if(!unreceived || !unreceived.len) + return 0 + if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT) + to_chat(client, "Sending Resources...") + for(var/asset in unreceived) + if (asset in asset_cache.cache) + client << browse_rsc(asset_cache.cache[asset], asset) + + if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip. + if (client) + client.cache += unreceived + return 1 + if (!client) + return 0 + client.sending |= unreceived + var/job = ++client.last_asset_job + + client << browse({" + + "}, "window=asset_cache_browser") + + var/t = 0 + var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len + while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic() + sleep(1) // Lock up the caller until this is received. + t++ + + if(client) + client.sending -= unreceived + client.cache |= unreceived + client.completed_asset_jobs -= job + + return 1 + +//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start. +//The proc calls procs that sleep for long times. +/proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE) + for(var/file in files) + if (!client) + break + if (register_asset) + register_asset(file,files[file]) + send_asset(client,file) + sleep(0) //queuing calls like this too quickly can cause issues in some client versions + +//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up. +//if it's an icon or something be careful, you'll have to copy it before further use. +/proc/register_asset(var/asset_name, var/asset) + asset_cache.cache[asset_name] = asset + +//These datums are used to populate the asset cache, the proc "register()" does this. + +//all of our asset datums, used for referring to these later +/var/global/list/asset_datums = list() + +//get a assetdatum or make a new one +/proc/get_asset_datum(var/type) + if (!(type in asset_datums)) + return new type() + return asset_datums[type] + +/datum/asset/New() + asset_datums[type] = src + register() + +/datum/asset/proc/register() + return + +/datum/asset/proc/send(client) + return + +//If you don't need anything complicated. +/datum/asset/simple + var/assets = list() + var/verify = FALSE + +/datum/asset/simple/register() + for(var/asset_name in assets) + register_asset(asset_name, assets[asset_name]) +/datum/asset/simple/send(client) + send_asset_list(client,assets,verify) + +// For registering or sending multiple others at once +/datum/asset/group + var/list/children + +/datum/asset/group/register() + for(var/type in children) + get_asset_datum(type) + +/datum/asset/group/send(client/C) + for(var/type in children) + var/datum/asset/A = get_asset_datum(type) + A.send(C) + + +//DEFINITIONS FOR ASSET DATUMS START HERE. + +/datum/asset/simple/pda + assets = list( + "pda_atmos.png" = 'icons/pda_icons/pda_atmos.png', + "pda_back.png" = 'icons/pda_icons/pda_back.png', + "pda_bell.png" = 'icons/pda_icons/pda_bell.png', + "pda_blank.png" = 'icons/pda_icons/pda_blank.png', + "pda_boom.png" = 'icons/pda_icons/pda_boom.png', + "pda_bucket.png" = 'icons/pda_icons/pda_bucket.png', + "pda_chatroom.png" = 'icons/pda_icons/pda_chatroom.png', + "pda_crate.png" = 'icons/pda_icons/pda_crate.png', + "pda_cuffs.png" = 'icons/pda_icons/pda_cuffs.png', + "pda_eject.png" = 'icons/pda_icons/pda_eject.png', + "pda_exit.png" = 'icons/pda_icons/pda_exit.png', + "pda_honk.png" = 'icons/pda_icons/pda_honk.png', + "pda_locked.png" = 'icons/pda_icons/pda_locked.png', + "pda_mail.png" = 'icons/pda_icons/pda_mail.png', + "pda_medical.png" = 'icons/pda_icons/pda_medical.png', + "pda_menu.png" = 'icons/pda_icons/pda_menu.png', + "pda_mule.png" = 'icons/pda_icons/pda_mule.png', + "pda_notes.png" = 'icons/pda_icons/pda_notes.png', + "pda_power.png" = 'icons/pda_icons/pda_power.png', + "pda_rdoor.png" = 'icons/pda_icons/pda_rdoor.png', + "pda_reagent.png" = 'icons/pda_icons/pda_reagent.png', + "pda_refresh.png" = 'icons/pda_icons/pda_refresh.png', + "pda_scanner.png" = 'icons/pda_icons/pda_scanner.png', + "pda_signaler.png" = 'icons/pda_icons/pda_signaler.png', + "pda_status.png" = 'icons/pda_icons/pda_status.png' + ) + +/datum/asset/simple/tgui + assets = list( + "tgui.css" = 'tgui/assets/tgui.css', + "tgui.js" = 'tgui/assets/tgui.js' + ) + +/datum/asset/nanoui + var/list/common = list() + + var/list/common_dirs = list( + "nano/css/", + "nano/images/", + "nano/images/status_icons/", + "nano/images/modular_computers/", + "nano/js/" + ) + var/list/uncommon_dirs = list( + "nano/templates/", + "news_articles/images/" + ) + +/datum/asset/nanoui/register() + // Crawl the directories to find files. + for (var/path in common_dirs) + var/list/filenames = flist(path) + for(var/filename in filenames) + if(copytext(filename, length(filename)) != "/") // Ignore directories. + if(fexists(path + filename)) + common[filename] = fcopy_rsc(path + filename) + register_asset(filename, common[filename]) + for (var/path in uncommon_dirs) + var/list/filenames = flist(path) + for(var/filename in filenames) + if(copytext(filename, length(filename)) != "/") // Ignore directories. + if(fexists(path + filename)) + register_asset(filename, fcopy_rsc(path + filename)) + + var/list/mapnames = list() + for(var/z in GLOB.using_map.map_levels) + mapnames += map_image_file_name(z) + + var/list/filenames = flist(MAP_IMAGE_PATH) + for(var/filename in filenames) + if(copytext(filename, length(filename)) != "/") // Ignore directories. + var/file_path = MAP_IMAGE_PATH + filename + if((filename in mapnames) && fexists(file_path)) + common[filename] = fcopy_rsc(file_path) + register_asset(filename, common[filename]) + +/datum/asset/nanoui/send(client, uncommon) + if(!islist(uncommon)) + uncommon = list(uncommon) + + send_asset_list(client, uncommon, FALSE) + send_asset_list(client, common, TRUE) + +/* + Asset cache +*/ +var/decl/asset_cache/asset_cache = new() + +/decl/asset_cache + var/list/cache + +/decl/asset_cache/New() + ..() + cache = new + +/hook/roundstart/proc/send_assets() + for(var/type in typesof(/datum/asset) - list(/datum/asset, /datum/asset/simple)) + var/datum/asset/A = new type() + A.register() + + for(var/client/C in GLOB.clients) + // Doing this to a client too soon after they've connected can cause issues, also the proc we call sleeps. + spawn(10) + getFilesSlow(C, asset_cache.cache, FALSE) + + return TRUE diff --git a/code/modules/client/client_color.dm b/code/modules/client/client_color.dm new file mode 100644 index 00000000..3c84665f --- /dev/null +++ b/code/modules/client/client_color.dm @@ -0,0 +1,85 @@ +/datum/client_color + var/client_color = "" //Any client.color-valid value + var/priority = 1 //Since only one client.color can be rendered on screen, we take the one with the highest priority value: + //eg: "Bloody screen" > "goggles color" as the former is much more important + + +/mob + var/list/client_colors = list() + + + +/* + Adds an instance of color_type to the mob's client_colors list + color_type - a typepath (subtyped from /datum/client_color) +*/ +/mob/proc/add_client_color(color_type) + if(!ispath(/datum/client_color)) + return + + var/datum/client_color/CC = new color_type() + client_colors |= CC + sortTim(client_colors, /proc/cmp_clientcolor_priority) + update_client_color() + + +/* + Removes an instance of color_type from the mob's client_colors list + color_type - a typepath (subtyped from /datum/client_color) + returns true if instance was found, false otherwise +*/ +/mob/proc/remove_client_color(color_type) + if(!ispath(/datum/client_color)) + return FALSE + + var/result = FALSE + for(var/cc in client_colors) + var/datum/client_color/CC = cc + if(CC.type == color_type) + result = TRUE + client_colors -= CC + qdel(CC) + break + update_client_color() + return result + + +/* + Resets the mob's client.color to null, and then sets it to the highest priority + client_color datum, if one exists +*/ +/mob/proc/update_client_color() + if(!client) + return + client.color = null + if(!client_colors.len) + return + var/datum/client_color/CC = client_colors[1] + if(CC) + animate(client, color = CC.client_color) + +/datum/client_color/monochrome + client_color = list(0.33,0.33,0.33, 0.33,0.33,0.33, 0.33,0.33,0.33) + priority = INFINITY + +//Similar to monochrome but shouldn't look as flat, same priority +/datum/client_color/noir + client_color = list(0.299,0.299,0.299, 0.587,0.587,0.587, 0.114,0.114,0.114) + priority = INFINITY + +//Disabilities, could be hooked to brain damage or chargen if so desired. +/datum/client_color/deuteranopia + client_color = list(0.47,0.38,0.15, 0.54,0.31,0.15, 0,0.3,0.7) + priority = 100 + +/datum/client_color/protanopia + client_color = list(0.51,0.4,0.12, 0.49,0.41,0.12, 0,0.2,0.76) + priority = 100 + +/datum/client_color/tritanopia + client_color = list(0.95,0.07,0, 0,0.44,0.52, 0.05,0.49,0.48) + priority = 100 + +/datum/client_color/berserk + client_color = "#af111c" + priority = 100 \ No newline at end of file diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm new file mode 100644 index 00000000..c7008910 --- /dev/null +++ b/code/modules/client/client_defines.dm @@ -0,0 +1,72 @@ +/client + ////////////////////// + //BLACK MAGIC THINGS// + ////////////////////// + parent_type = /datum + //////////////// + //ADMIN THINGS// + //////////////// + var/datum/admins/holder = null + var/datum/admins/deadmin_holder = null + + ///////// + //OTHER// + ///////// + var/datum/preferences/prefs = null + var/move_delay = 1 + var/moving_in_dir = 0 + var/moving = null + var/adminobs = null + + var/adminhelped = 0 + + var/staffwarn = null + + var/fullscreen = 0 + + var/combat_mode_aim = FALSE + + var/warfare_faction = null + + /////////////// + //SOUND STUFF// + /////////////// + var/ambience_playing= null + var/played = 0 + var/warfare_deaths = 0 + + //////////// + //SECURITY// + //////////// + // comment out the line below when debugging locally to enable the options & messages menu + //control_freak = 1 + + var/received_irc_pm = -99999 + var/irc_admin //IRC admin that spoke with them last. + var/mute_irc = 0 + var/warned_about_multikeying = 0 // Prevents people from being spammed about multikeying every time their mob changes. + + //////////////////////////////////// + //things that require the database// + //////////////////////////////////// + var/player_age = "Requires database" //So admins know why it isn't working - Used to determine how old the account is - in days. + var/related_accounts_ip = "Requires database" //So admins know why it isn't working - Used to determine what other accounts previously logged in from this ip + var/related_accounts_cid = "Requires database" //So admins know why it isn't working - Used to determine what other accounts previously logged in from this computer id + + var/lastping = 0 + var/avgping = 0 + var/connection_time //world.time they connected + var/connection_realtime //world.realtime they connected + var/connection_timeofday //world.timeofday they connected + + var/hellbanned = 0 //Fuck you quotesman, plasmatik, and pottery. You did this. + + // Transparent image for maptext tooltip + var/obj/screen/tooltip = null + + var/datum/chatOutput/chatOutput + + preload_rsc = 0 // This is 0 so we can set it to an URL once the player logs in and have them download the resources from a different server. + var/static/obj/screen/click_catcher/void + show_popup_menus = FALSE + diff --git a/code/modules/client/client_helpers.dm b/code/modules/client/client_helpers.dm new file mode 100644 index 00000000..9d2d882d --- /dev/null +++ b/code/modules/client/client_helpers.dm @@ -0,0 +1,14 @@ +/datum/proc/get_client() + return null + +/client/get_client() + return src + +/mob/get_client() + return client + +/mob/observer/eye/get_client() + . = client || (owner && owner.get_client()) + +/mob/observer/virtual/get_client() + return host.get_client() diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm new file mode 100644 index 00000000..16055509 --- /dev/null +++ b/code/modules/client/client_procs.dm @@ -0,0 +1,523 @@ + //////////// + //SECURITY// + //////////// +#define UPLOAD_LIMIT 7485760 //Restricts client uploads to the server to 7MB //Uebalo this thing. What's the worst that can happen? +#define MIN_CLIENT_VERSION 0 //Just an ambiguously low version for now, I don't want to suddenly stop people playing. + //I would just like the code ready should it ever need to be used. + +//#define TOPIC_DEBUGGING 1 + + /* + When somebody clicks a link in game, this Topic is called first. + It does the stuff in this proc and then is redirected to the Topic() proc for the src=[0xWhatever] + (if specified in the link). ie locate(hsrc).Topic() + + Such links can be spoofed. + + Because of this certain things MUST be considered whenever adding a Topic() for something: + - Can it be fed harmful values which could cause runtimes? + - Is the Topic call an admin-only thing? + - If so, does it have checks to see if the person who called it (usr.client) is an admin? + - Are the processes being called by Topic() particularly laggy? + - If so, is there any protection against somebody spam-clicking a link? + If you have any questions about this stuff feel free to ask. ~Carn + */ +/client/Topic(href, href_list, hsrc) + if(!usr || usr != mob) //stops us calling Topic for somebody else's client. Also helps prevent usr=null + return + + #if defined(TOPIC_DEBUGGING) + log_debug("[src]'s Topic: [href] destined for [hsrc].") + + if(href_list["nano_err"]) //nano throwing errors + log_debug("## NanoUI, Subject [src]: " + html_decode(href_list["nano_err"]))//NANO DEBUG HOOK + + + #endif + + // asset_cache + if(href_list["asset_cache_confirm_arrival"]) +// to_chat(src, "ASSET JOB [href_list["asset_cache_confirm_arrival"]] ARRIVED.") + var/job = text2num(href_list["asset_cache_confirm_arrival"]) + completed_asset_jobs += job + return + + //search the href for script injection + if( findtext(href,"You are no longer able to use this, it's been more then 10 minutes since an admin on IRC has responded to you
            ") + return + if(mute_irc) + to_chat(usr, "") + return + cmd_admin_irc_pm(href_list["irc_msg"]) + return + + if(href_list["close_ticket"]) + var/datum/ticket/ticket = locate(href_list["close_ticket"]) + + if(isnull(ticket)) + return + + ticket.close(client_repository.get_lite_client(usr.client)) + + + + //Logs all hrefs + if(config && config.log_hrefs && href_logfile) + to_chat(href_logfile, "[time2text(world.timeofday,"hh:mm")] [src] (usr:[usr]) || [hsrc ? "[hsrc] " : ""][href]
            ") + + switch(href_list["_src_"]) + if("holder") hsrc = holder + if("usr") hsrc = mob + if("prefs") return prefs.process_link(usr,href_list) + if("vars") return view_var_Topic(href,href_list,hsrc) + if("chat") return chatOutput.Topic(href, href_list) + + switch(href_list["action"]) + if("openLink") + src << link(href_list["link"]) + + ..() //redirect to hsrc.Topic() + +//This stops files larger than UPLOAD_LIMIT being sent from client to server via input(), client.Import() etc. +/client/AllowUpload(filename, filelength) + if(filelength > UPLOAD_LIMIT) + to_chat(src, "Error: AllowUpload(): File Upload too large. Upload Limit: [UPLOAD_LIMIT/1024]KiB.") + return 0 +/* //Don't need this at the moment. But it's here if it's needed later. + //Helps prevent multiple files being uploaded at once. Or right after eachother. + var/time_to_wait = fileaccess_timer - world.time + if(time_to_wait > 0) + to_chat(src, "Error: AllowUpload(): Spam prevention. Please wait [round(time_to_wait/10)] seconds.") + return 0 + fileaccess_timer = world.time + FTPDELAY */ + return 1 + + + /////////// + //CONNECT// + /////////// +/client/New(TopicData) + chatOutput = new /datum/chatOutput(src) + TopicData = null //Prevent calls to client.Topic from connect + + if(!(connection in list("seeker", "web"))) //Invalid connection type. + return null + if(byond_version < MIN_CLIENT_VERSION) //Out of date client. + return null + + if(!config.guests_allowed && IsGuestKey(key)) + alert(src,"This server doesn't allow guest accounts to play. Please go to http://www.byond.com/ and register for a key.","Guest","OK") + qdel(src) + return + + if(config.player_limit != 0) + if((GLOB.clients.len >= config.player_limit) && !(ckey in admin_datums)) + alert(src,"This server is currently full and not accepting new connections.","Server Full","OK") + log_admin("[ckey] tried to join and was turned away due to the server being full (player_limit=[config.player_limit])") + qdel(src) + return + + // Change the way they should download resources. + if(config.resource_urls && config.resource_urls.len) + src.preload_rsc = pick(config.resource_urls) + else src.preload_rsc = 1 // If config.resource_urls is not set, preload like normal. + + if(byond_version < DM_VERSION) + to_chat(src, "You are running an older version of BYOND than the server and may experience issues.") + to_chat(src, "It is recommended that you update to at least [DM_VERSION] at http://www.byond.com/download/.") + GLOB.clients += src + GLOB.ckey_directory[ckey] = src + + //Admin Authorisation + holder = admin_datums[ckey] + if(holder) + GLOB.admins += src + holder.owner = src + + //preferences datum - also holds some persistant data for the client (because we may as well keep these datums to a minimum) + prefs = preferences_datums[ckey] + if(!prefs) + prefs = new /datum/preferences(src) + preferences_datums[ckey] = prefs + prefs.last_ip = address //these are gonna be used for banning + prefs.last_id = computer_id //these are gonna be used for banning + apply_fps(prefs.clientfps) + + . = ..() //calls mob.Login() + chatOutput.start() // Starts the chat + force_dark_theme() + prefs.sanitize_preferences() + + GLOB.using_map.map_info(src) + + if(custom_event_msg && custom_event_msg != "") + to_chat(src, "

            Custom Event

            ") + to_chat(src, "

            A custom event is taking place. OOC Info:

            ") + to_chat(src, "[custom_event_msg]") + to_chat(src, "
            ") + + + if(holder) + add_admin_verbs() + admin_memo_show() + + // Forcibly enable hardware-accelerated graphics, as we need them for the lighting overlays. + // (but turn them off first, since sometimes BYOND doesn't turn them on properly otherwise) + spawn(5) // And wait a half-second, since it sounds like you can do this too fast. + if(src) + winset(src, null, "command=\".configure graphics-hwmode off\"") + sleep(2) // wait a bit more, possibly fixes hardware mode not re-activating right + winset(src, null, "command=\".configure graphics-hwmode on\"") + + log_client_to_db() + + send_resources() + + if(holder) + src.control_freak = 0 //Devs need 0 for profiler access + + check_hellbanned() + // Maptext tooltip + tooltip = new() + tooltip.icon = 'icons/misc/static.dmi' + tooltip.icon_state = "blank" + tooltip.screen_loc = "NORTH,WEST+25%" + tooltip.maptext_width = 256 + tooltip.maptext_x = 0 + tooltip.plane = FULLSCREEN_PLANE + + if (mob && mob.get_preference_value("TOOLTIP") == GLOB.PREF_NO) + tooltip.alpha = 0 + + screen += tooltip + +/client/MouseEntered(atom/object, location, control, params) + if (tooltip) + screen |= tooltip + tooltip.maptext = "" + + if(ticker.current_state >= GAME_STATE_SETTING_UP) + if(ishuman(object)) + var/mob/living/carbon/human/H = object + if(H.warfare_faction) + if(H.warfare_faction == RED_TEAM) + tooltip.maptext = "
            [uppertext(object.name)]
            " + else + tooltip.maptext = "
            [uppertext(object.name)]
            " + else + tooltip.maptext = "
            [uppertext(object.name)]
            " + else + tooltip.maptext = "
            [uppertext(object.name)]
            " + + +////////////// +//DISCONNECT// +////////////// +/client/Del() + ticket_panels -= src + if(holder) + holder.owner = null + GLOB.admins -= src + GLOB.ckey_directory -= ckey + GLOB.clients -= src + if(warfare_faction == BLUE_TEAM)//remove them from the list if they disconnect, so we don't fuck the list up. + SSWarfare.blue.team_clients -= src + else + SSWarfare.red.team_clients -= src + return ..() + +/client/Destroy() + ..() + return QDEL_HINT_HARDDEL_NOW + +// here because it's similar to below + +// Returns null if no DB connection can be established, or -1 if the requested key was not found in the database + +/proc/get_player_age(key) + establish_db_connection() + if(!dbcon.IsConnected()) + return null + + var/sql_ckey = sql_sanitize_text(ckey(key)) + + var/DBQuery/query = dbcon.NewQuery("SELECT datediff(Now(),firstseen) as age FROM erro_player WHERE ckey = '[sql_ckey]'") + query.Execute() + + if(query.NextRow()) + return text2num(query.item[1]) + else + return -1 + + +/client/proc/log_client_to_db() + + if ( IsGuestKey(src.key) ) + return + + establish_db_connection() + if(!dbcon.IsConnected()) + return + + var/sql_ckey = sql_sanitize_text(src.ckey) + + var/DBQuery/query = dbcon.NewQuery("SELECT id, datediff(Now(),firstseen) as age FROM erro_player WHERE ckey = '[sql_ckey]'") + query.Execute() + var/sql_id = 0 + player_age = 0 // New players won't have an entry so knowing we have a connection we set this to zero to be updated if their is a record. + while(query.NextRow()) + sql_id = query.item[1] + player_age = text2num(query.item[2]) + break + + var/DBQuery/query_ip = dbcon.NewQuery("SELECT ckey FROM erro_player WHERE ip = '[address]'") + query_ip.Execute() + related_accounts_ip = "" + while(query_ip.NextRow()) + related_accounts_ip += "[query_ip.item[1]], " + break + + var/DBQuery/query_cid = dbcon.NewQuery("SELECT ckey FROM erro_player WHERE computerid = '[computer_id]'") + query_cid.Execute() + related_accounts_cid = "" + while(query_cid.NextRow()) + related_accounts_cid += "[query_cid.item[1]], " + break + + var/DBQuery/query_staffwarn = dbcon.NewQuery("SELECT staffwarn FROM erro_player WHERE ckey = '[sql_ckey]' AND !ISNULL(staffwarn)") + query_staffwarn.Execute() + if(query_staffwarn.NextRow()) + src.staffwarn = query_staffwarn.item[1] + + //Just the standard check to see if it's actually a number + if(sql_id) + if(istext(sql_id)) + sql_id = text2num(sql_id) + if(!isnum(sql_id)) + return + + var/admin_rank = "Player" + if(src.holder) + admin_rank = src.holder.rank + for(var/client/C in GLOB.clients) + if(C.staffwarn) + C.mob.send_staffwarn(src, "is connected", 0) + + var/sql_ip = sql_sanitize_text(src.address) + var/sql_computerid = sql_sanitize_text(src.computer_id) + var/sql_admin_rank = sql_sanitize_text(admin_rank) + + + if(sql_id) + //Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables + var/DBQuery/query_update = dbcon.NewQuery("UPDATE erro_player SET lastseen = Now(), ip = '[sql_ip]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]' WHERE id = [sql_id]") + query_update.Execute() + else + //New player!! Need to insert all the stuff + var/DBQuery/query_insert = dbcon.NewQuery("INSERT INTO erro_player (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[sql_ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]')") + query_insert.Execute() + + //Logging player access + var/serverip = "[world.internet_address]:[world.port]" + var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `erro_connection_log`(`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[sql_ckey]','[sql_ip]','[sql_computerid]');") + query_accesslog.Execute() + +#undef UPLOAD_LIMIT +#undef MIN_CLIENT_VERSION + +//checks if a client is afk +//3000 frames = 5 minutes +/client/proc/is_afk(duration=3000) + if(inactivity > duration) return inactivity + return 0 + +/client/proc/inactivity2text() + var/seconds = inactivity/10 + return "[round(seconds / 60)] minute\s, [seconds % 60] second\s" + +// Byond seemingly calls stat, each tick. +// Calling things each tick can get expensive real quick. +// So we slow this down a little. +// See: http://www.byond.com/docs/ref/info.html#/client/proc/Stat +/client/Stat() + if(!usr) + return + // Add always-visible stat panel calls here, to define a consistent display order. + statpanel("Status") + + . = ..() + sleep(1) + +//send resources to the client. It's here in its own proc so we can move it around easiliy if need be +/client/proc/send_resources() + + getFiles( + 'html/search.js', + 'html/panels.css', + 'html/spacemag.css', + 'html/images/loading.gif', + 'html/images/ntlogo.png', + 'html/images/bluentlogo.png', + 'html/images/sollogo.png', + 'html/images/terralogo.png', + 'html/images/talisman.png' + ) + + spawn (10) //removing this spawn causes all clients to not get verbs. + //Precache the client with all other assets slowly, so as to not block other browse() calls + getFilesSlow(src, asset_cache.cache, register_asset = FALSE) + +mob/proc/MayRespawn() + return 0 + +client/proc/MayRespawn() + if(mob) + return mob.MayRespawn() + + // Something went wrong, client is usually kicked or transfered to a new mob at this point + return 0 + +/client/proc/apply_fps(var/client_fps) + if(world.byond_version >= 511 && byond_version >= 511 && client_fps >= CLIENT_MIN_FPS && client_fps <= CLIENT_MAX_FPS) + vars["fps"] = prefs.clientfps + +/client/proc/fullscreen() + fullscreen = !fullscreen + if(fullscreen) + winset(src, "mainwindow", "is-maximized=false;can-resize=false;titlebar=false;menu=") + winset(src, "mainwindow", "is-maximized=true") + else //If fullscreen == 0 (FALSE) + winset(src, "mainwindow", "is-maximized=false;can-resize=true;titlebar=true;menu=menu") + +/*/client/var/status_bar = 0 + +/client/proc/toggle_status_bar() + status_bar = !status_bar + if(status_bar && fullscreen) + winset(src, "mainwindow", "is-maximized=false;can-resize=false;titlebar=false;menu=") + winset(src, "mainwindow", "is-maximized=true;statusbar=true") + if(status_bar && !fullscreen) + winset(src, "mainwindow", "is-maximized=false;can-resize=true;titlebar=true;menu=menu;statusbar=true") + if(!status_bar && fullscreen) + winset(src, "mainwindow", "is-maximized=false;can-resize=false;titlebar=false;menu=") + winset(src, "mainwindow", "is-maximized=true;statusbar=false") + if(!status_bar && !fullscreen) + winset(src, "mainwindow", "is-maximized=false;can-resize=true;titlebar=true;menu=menu;statusbar=false") +*/ + +/client/New() + ..() + fullscreen() + +/client/verb/fullscreen_toggle() + set name = ".fullscreen_toggle" + fullscreen() + +/mob/verb/toggle_fullscreen() + set name = "Toggle Fullscreen" + set category = "OOC" + client.fullscreen() + +/client/New() + ..() + winset(src, "name", "text=''") // when server reboots and stuff like that + if(mob) + winset(src, "name", "text='[mob.real_name]'") +/* +/mob/verb/status_bar_toggle() + set name = "Toggle Status Bar" + set category = "OOC" + client.toggle_status_bar() +*/ + + +/client/MouseMove(object,location,control,params) + if(mob && combat_mode_aim) + mob.onMouseMove(object, location, control, params) + ..() + +/client/verb/combat_mode_aim_toggle() + set name = "Toggle Combat Mode Aim" + set category = "OOC" + + combat_mode_aim = !combat_mode_aim + if(combat_mode_aim) + to_chat(src, "You will now face the direction your mouse points when in combat mode.") + else + to_chat(src, "You will no longer face the direction your mouse points when in combat mode.") + + +/atom/proc/onMouseMove(object, location, control, params) + return + + +/mob/living/carbon/onMouseMove(object, location, control, params) + if(!combat_mode) + return + face_atom(object) + + +/client/verb/fit_viewport() + set name = "Fit Viewport" + set category = "OOC" + set desc = "Fit the width of the map window to match the viewport" + + // Fetch aspect ratio + var/view_size = getviewsize(view) + var/aspect_ratio = view_size[1] / view_size[2] + + // Calculate desired pixel width using window size and aspect ratio + var/sizes = params2list(winget(src, "mainwindow.mainvsplit;mapwindow", "size")) + var/map_size = splittext(sizes["mapwindow.size"], "x") + var/height = text2num(map_size[2]) + var/desired_width = round(height * aspect_ratio) + if (text2num(map_size[1]) == desired_width) + // Nothing to do + return + + var/split_size = splittext(sizes["mainwindow.mainvsplit.size"], "x") + var/split_width = text2num(split_size[1]) + + // Calculate and apply a best estimate + // +4 pixels are for the width of the splitter's handle + var/pct = 100 * (desired_width + 4) / split_width + winset(src, "mainwindow.mainvsplit", "splitter=[pct]") + + // Apply an ever-lowering offset until we finish or fail + var/delta + for(var/safety in 1 to 10) + var/after_size = winget(src, "mapwindow", "size") + map_size = splittext(after_size, "x") + var/got_width = text2num(map_size[1]) + + if (got_width == desired_width) + // success + return + else if (isnull(delta)) + // calculate a probable delta value based on the difference + delta = 100 * (desired_width - got_width) / split_width + else if ((delta > 0 && got_width > desired_width) || (delta < 0 && got_width < desired_width)) + // if we overshot, halve the delta and reverse direction + delta = -delta/2 + + pct += delta + winset(src, "mainwindow.mainvsplit", "splitter=[pct]") \ No newline at end of file diff --git a/code/modules/client/darkmode.dm b/code/modules/client/darkmode.dm new file mode 100644 index 00000000..bdadbfc5 --- /dev/null +++ b/code/modules/client/darkmode.dm @@ -0,0 +1,97 @@ +//Darkmode preference by Kmc2000// + +/* +This lets you switch chat themes by using winset and CSS loading, you must relog to see this change (or rebuild your browseroutput datum) + +Things to note: +If you change ANYTHING in interface/skin.dmf you need to change it here: +Format: +winset(src, "window as appears in skin.dmf after elem", "var to change = currentvalue;var to change = desired value") + +How this works: +I've added a function to browseroutput.js which registers a cookie for darkmode and swaps the chat accordingly. You can find the button to do this under the "cog" icon next to the ping button (top right of chat) +This then swaps the window theme automatically + +Thanks to spacemaniac and mcdonald for help with the JS side of this. + +*/ + +#define COLOR_DARKMODE_BACKGROUND "#202020" +#define COLOR_DARKMODE_DARKBACKGROUND "#171717" +#define COLOR_DARKMODE_TEXT "#a4bad6" + +/client/proc/force_white_theme() //There's no way round it. We're essentially changing the skin by hand. It's painful but it works, and is the way Lummox suggested. + //Main windows + winset(src, "rpane", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = none") + winset(src, "rpane", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "rpanewindow", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = none") + winset(src, "rpanewindow", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "infowindow", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = none") + winset(src, "infowindow", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "browseroutput", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "browseroutput", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "outputwindow", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "outputwindow", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "mainwindow", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = none") + winset(src, "mainvsplit", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + //Buttons + winset(src, "changelog", "background-color = #494949;background-color = none") + winset(src, "changelog", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "rulesb", "background-color = #494949;background-color = none") + winset(src, "rulesb", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "textb", "background-color = #494949;background-color = none") + winset(src, "textb", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "infob", "background-color = #494949;background-color = none") + winset(src, "infob", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "wikiurl", "background-color = #494949;background-color = none") + winset(src, "wikiurl", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "discordurl", "background-color = #494949;background-color = none") + winset(src, "discordurl", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "githuburl", "background-color = #3a3a3a;background-color = none") + winset(src, "githuburl", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + //Status and verb tabs + winset(src, "output", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "output", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "outputwindow", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "outputwindow", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "info", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = #FFFFFF") + winset(src, "info", "tab-background-color = [COLOR_DARKMODE_BACKGROUND];tab-background-color = none") + winset(src, "info", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "info", "tab-text-color = [COLOR_DARKMODE_TEXT];tab-text-color = #000000") + winset(src, "info", "prefix-color = [COLOR_DARKMODE_TEXT];prefix-color = #000000") + winset(src, "info", "suffix-color = [COLOR_DARKMODE_TEXT];suffix-color = #000000") + //Say, OOC, me Buttons etc. + winset(src, "saybutton", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "saybutton", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "hotkey_toggle", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "hotkey_toggle", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "asset_cache_browser", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "asset_cache_browser", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "tooltip", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "tooltip", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + +/client/proc/force_dark_theme() //Inversely, if theyre using white theme and want to swap to the superior dark theme, let's get WINSET() ing + //Main windows + winset(src, "rpane", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "rpane", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "rpanewindow", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "rpanewindow", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "infowindow", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "infowindow", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "browseroutput", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "browseroutput", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "outputwindow", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "outputwindow", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "mainwindow", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "mainvsplit", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + //Status and verb tabs + winset(src, "output", "background-color = none;background-color = [COLOR_DARKMODE_DARKBACKGROUND]") + winset(src, "output", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "outputwindow", "background-color = none;background-color = [COLOR_DARKMODE_DARKBACKGROUND]") + winset(src, "outputwindow", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "info", "background-color = #FFFFFF;background-color = [COLOR_DARKMODE_DARKBACKGROUND]") + winset(src, "info", "tab-background-color = none;tab-background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "info", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "info", "tab-text-color = #000000;tab-text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "info", "prefix-color = #000000;prefix-color = [COLOR_DARKMODE_TEXT]") + winset(src, "info", "suffix-color = #000000;suffix-color = [COLOR_DARKMODE_TEXT]") \ No newline at end of file diff --git a/code/modules/client/movement.dm b/code/modules/client/movement.dm new file mode 100644 index 00000000..5deac729 --- /dev/null +++ b/code/modules/client/movement.dm @@ -0,0 +1,4 @@ + +/client/New() + ..() + dir = NORTH \ No newline at end of file diff --git a/code/modules/client/preference_setup/_defines.dm b/code/modules/client/preference_setup/_defines.dm new file mode 100644 index 00000000..a8362c31 --- /dev/null +++ b/code/modules/client/preference_setup/_defines.dm @@ -0,0 +1,16 @@ +#define EQUIP_PREVIEW_LOADOUT 1 +#define EQUIP_PREVIEW_JOB 2 +#define EQUIP_PREVIEW_ALL (EQUIP_PREVIEW_LOADOUT|EQUIP_PREVIEW_JOB) + +#define SETUP_SUBTYPE_DECLS_BY_NAME(decl_prototype, decls_by_name) \ +if(!decls_by_name);\ +{\ + decls_by_name = list();\ + var/decls_by_type = decls_repository.get_decls_of_subtype(decl_prototype);\ + for(var/decl_type in decls_by_type) \ + {\ + var##decl_prototype/decl_instance = decls_by_type[decl_type];\ + ADD_SORTED(decls_by_name, decl_instance.name, /proc/cmp_text_asc);\ + decls_by_name[decl_instance.name] = decl_instance;\ + }\ +} diff --git a/code/modules/client/preference_setup/antagonism/01_candidacy.dm b/code/modules/client/preference_setup/antagonism/01_candidacy.dm new file mode 100644 index 00000000..4eecfdf0 --- /dev/null +++ b/code/modules/client/preference_setup/antagonism/01_candidacy.dm @@ -0,0 +1,120 @@ +/datum/preferences + var/list/never_be_special_role + var/list/be_special_role + +/datum/category_item/player_setup_item/antagonism/candidacy + name = "Candidacy" + sort_order = 1 + +/datum/category_item/player_setup_item/antagonism/candidacy/load_character(var/savefile/S) + from_file(S["be_special"], pref.be_special_role) + from_file(S["never_be_special"], pref.never_be_special_role) + +/datum/category_item/player_setup_item/antagonism/candidacy/save_character(var/savefile/S) + to_file(S["be_special"], pref.be_special_role) + to_file(S["never_be_special"], pref.never_be_special_role) + +/datum/category_item/player_setup_item/antagonism/candidacy/sanitize_character() + if(!istype(pref.be_special_role)) + pref.be_special_role = list() + if(!istype(pref.never_be_special_role)) + pref.never_be_special_role = list() + + var/special_roles = valid_special_roles() + for(var/role in pref.be_special_role) + if(!(role in special_roles)) + pref.be_special_role -= role + for(var/role in pref.never_be_special_role) + if(!(role in special_roles)) + pref.never_be_special_role -= role + +/datum/category_item/player_setup_item/antagonism/candidacy/content(var/mob/user) + . = list() + . += "Special Role Availability:
            " + . += "" + var/list/all_antag_types = all_antag_types() + for(var/antag_type in all_antag_types) + var/datum/antagonist/antag = all_antag_types[antag_type] + . += "" + + var/list/ghost_traps = get_ghost_traps() + for(var/ghost_trap_key in ghost_traps) + var/datum/ghosttrap/ghost_trap = ghost_traps[ghost_trap_key] + if(!ghost_trap.list_as_special_role) + continue + + . += "" + . += "
            [antag.role_text]: " + if(jobban_isbanned(preference_mob(), antag.id) || (antag.id == MODE_MALFUNCTION && jobban_isbanned(preference_mob(), "AI"))) + . += "\[BANNED\]
            " + else if(antag.role_type in pref.be_special_role) + . += "High Low Never
            " + else if(antag.role_type in pref.never_be_special_role) + . += "High Low Never
            " + else + . += "High Low Never
            " + . += "
            [(ghost_trap.ghost_trap_role)]: " + if(banned_from_ghost_role(preference_mob(), ghost_trap)) + . += "\[BANNED\]
            " + else if(ghost_trap.pref_check in pref.be_special_role) + . += "High Low Never
            " + else if(ghost_trap.pref_check in pref.never_be_special_role) + . += "High Low Never
            " + else + . += "High Low Never
            " + . += "
            " + . = jointext(.,null) + +/datum/category_item/player_setup_item/proc/banned_from_ghost_role(var/mob, var/datum/ghosttrap/ghost_trap) + for(var/ban_type in ghost_trap.ban_checks) + if(jobban_isbanned(mob, ban_type)) + return 1 + return 0 + +/datum/category_item/player_setup_item/antagonism/candidacy/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["add_special"]) + if(!(href_list["add_special"] in valid_special_roles())) + return TOPIC_HANDLED + pref.be_special_role |= href_list["add_special"] + pref.never_be_special_role -= href_list["add_special"] + return TOPIC_REFRESH + + if(href_list["del_special"]) + if(!(href_list["del_special"] in valid_special_roles())) + return TOPIC_HANDLED + pref.be_special_role -= href_list["del_special"] + pref.never_be_special_role -= href_list["del_special"] + return TOPIC_REFRESH + + if(href_list["add_never"]) + pref.be_special_role -= href_list["add_never"] + pref.never_be_special_role |= href_list["add_never"] + return TOPIC_REFRESH + + return ..() + +/datum/category_item/player_setup_item/antagonism/candidacy/proc/valid_special_roles() + var/list/private_valid_special_roles = list() + + var/list/all_antag_types = all_antag_types() + for(var/antag_type in all_antag_types) + var/datum/antagonist/antag = all_antag_types[antag_type] + private_valid_special_roles += antag.role_type + + var/list/ghost_traps = get_ghost_traps() + for(var/ghost_trap_key in ghost_traps) + var/datum/ghosttrap/ghost_trap = ghost_traps[ghost_trap_key] + if(!ghost_trap.list_as_special_role) + continue + private_valid_special_roles += ghost_trap.pref_check + + return private_valid_special_roles + +/client/proc/wishes_to_be_role(var/role) + if(!prefs) + return FALSE + if(role in prefs.be_special_role) + return 2 + if(role in prefs.never_be_special_role) + return FALSE + return 1 //Default to "sometimes" if they don't opt-out. diff --git a/code/modules/client/preference_setup/antagonism/02_setup.dm b/code/modules/client/preference_setup/antagonism/02_setup.dm new file mode 100644 index 00000000..c5944924 --- /dev/null +++ b/code/modules/client/preference_setup/antagonism/02_setup.dm @@ -0,0 +1,93 @@ +/datum/preferences + var/list/uplink_sources + var/exploit_record = "" + +/datum/category_item/player_setup_item/antagonism/basic + name = "Setup" + sort_order = 2 + + var/static/list/uplink_sources_by_name + +/datum/category_item/player_setup_item/antagonism/basic/New() + ..() + SETUP_SUBTYPE_DECLS_BY_NAME(/decl/uplink_source, uplink_sources_by_name) + +/datum/category_item/player_setup_item/antagonism/basic/load_character(var/savefile/S) + var/list/uplink_order + from_file(S["uplink_sources"], uplink_order) + from_file(S["exploit_record"], pref.exploit_record) + + if(istype(uplink_order)) + pref.uplink_sources = list() + for(var/entry in uplink_order) + var/uplink_source = uplink_sources_by_name[entry] + if(uplink_source) + pref.uplink_sources += uplink_source + +/datum/category_item/player_setup_item/antagonism/basic/save_character(var/savefile/S) + var/uplink_order = list() + for(var/entry in pref.uplink_sources) + var/decl/uplink_source/UL = entry + uplink_order += UL.name + + to_file(S["uplink_sources"], uplink_order) + to_file(S["exploit_record"], pref.exploit_record) + +/datum/category_item/player_setup_item/antagonism/basic/sanitize_character() + if(!istype(pref.uplink_sources)) + pref.uplink_sources = list() + for(var/entry in GLOB.default_uplink_source_priority) + pref.uplink_sources += decls_repository.get_decl(entry) + +/datum/category_item/player_setup_item/antagonism/basic/content(var/mob/user) + . +="Antag Setup:
            " + . +="Uplink Source Priority: Add
            " + for(var/entry in pref.uplink_sources) + var/decl/uplink_source/US = entry + . +="[US.name] Move Up Move Down Remove
            " + if(US.desc) + . += "[US.desc]
            " + if(!pref.uplink_sources.len) + . += "You will not receive an uplink unless you add an uplink source!" + . +="
            " + +/datum/category_item/player_setup_item/antagonism/basic/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["add_source"]) + var/source_selection = input(user, "Select Uplink Source to Add", CHARACTER_PREFERENCE_INPUT_TITLE) as null|anything in (list_values(uplink_sources_by_name) - pref.uplink_sources) + if(source_selection && CanUseTopic(user)) + pref.uplink_sources |= source_selection + return TOPIC_REFRESH + + if(href_list["remove_source"]) + var/decl/uplink_source/US = locate(href_list["remove_source"]) in pref.uplink_sources + if(US && pref.uplink_sources.Remove(US)) + return TOPIC_REFRESH + + if(href_list["move_source_up"]) + var/decl/uplink_source/US = locate(href_list["move_source_up"]) in pref.uplink_sources + if(!US) + return TOPIC_NOACTION + var/index = pref.uplink_sources.Find(US) + if(index <= 1) + return TOPIC_NOACTION + pref.uplink_sources.Swap(index, index - 1) + return TOPIC_REFRESH + + if(href_list["move_source_down"]) + var/decl/uplink_source/US = locate(href_list["move_source_down"]) in pref.uplink_sources + if(!US) + return TOPIC_NOACTION + var/index = pref.uplink_sources.Find(US) + if(index >= pref.uplink_sources.len) + return TOPIC_NOACTION + pref.uplink_sources.Swap(index, index + 1) + 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/general/01_basic.dm b/code/modules/client/preference_setup/general/01_basic.dm new file mode 100644 index 00000000..975a2f94 --- /dev/null +++ b/code/modules/client/preference_setup/general/01_basic.dm @@ -0,0 +1,124 @@ +datum/preferences + var/real_name //our character's name + var/be_random_name = 0 //whether we are a random name every round + var/gender = MALE //gender of character (well duh) + var/age = 30 //age of character + var/spawnpoint = "Default" //where this character will spawn (0-2). + var/metadata = "" + var/religion = "None" + +/datum/category_item/player_setup_item/general/basic + name = "Basic" + sort_order = 1 + +/datum/category_item/player_setup_item/general/basic/load_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 + S["religion"] >> pref.religion + +/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 + S["religion"] << pref.religion + +/datum/category_item/player_setup_item/general/basic/sanitize_character() + var/datum/species/S = all_species[pref.species ? pref.species : SPECIES_HUMAN] + if(!S) S = all_species[SPECIES_HUMAN] + pref.age = sanitize_integer(pref.age, S.min_age, S.max_age, initial(pref.age)) + pref.gender = sanitize_inlist(pref.gender, S.genders, pick(S.genders)) + pref.real_name = sanitize_name(pref.real_name, pref.species) + 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)) + + +/datum/category_item/player_setup_item/general/basic/content(mob/user) + . = list() + + /* + if(!ticker || ticker.current_state <= GAME_STATE_PREGAME) + for(var/mob/new_player/P in GLOB.player_list) + if(P.mind.key == user.key) + if(!P.client || !P.ready) + . += "

            You are not ready.

            " + else + . += "

            You are ready.

            " + else + */ + . += "

            Join the Game!

            " + . += "Name: " + . += "[pref.real_name] ®
            " + . += "Gender: [gender2text(pref.gender)]
            " + . += "Age: [pref.age]
            " + if(GLOB.using_map.map_lore) + . += "Map Objective:
            " + . += "[GLOB.using_map.map_lore]
            "//Put the map lore here if there is any. + + if(user.client.holder)//it's user not usr Bombany. + . += "

            Observe()

            " + . = jointext(.,null) + +/datum/category_item/player_setup_item/general/basic/OnTopic(var/href,var/list/href_list, var/mob/user) + var/datum/species/S = all_species[pref.species] + 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 = sanitize_name(raw_name, pref.species) + if(new_name) + pref.real_name = new_name + return TOPIC_REFRESH + else + to_chat(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"]) + var/new_gender + if(pref.gender == MALE) + new_gender = FEMALE + else + new_gender = MALE + S = all_species[pref.species] + pref.gender = new_gender + if(!(pref.f_style in S.get_facial_hair_styles(pref.gender))) + ResetFacialHair() + return TOPIC_REFRESH_UPDATE_PREVIEW + + else if(href_list["age"]) + var/new_age = input(user, "Choose your character's age:\n([S.min_age]-[S.max_age])", CHARACTER_PREFERENCE_INPUT_TITLE, pref.age) as num|null + if(new_age && CanUseTopic(user)) + pref.age = max(min(round(text2num(new_age)), S.max_age), S.min_age) + return TOPIC_REFRESH + + else if(href_list["spawnpoint"]) + var/list/spawnkeys = list() + for(var/spawntype in spawntypes()) + spawnkeys += spawntype + 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 = 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 new file mode 100644 index 00000000..3b3a61c6 --- /dev/null +++ b/code/modules/client/preference_setup/general/02_language.dm @@ -0,0 +1,91 @@ +/datum/preferences + var/list/alternate_languages //Secondary language(s) + +/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 + +/datum/category_item/player_setup_item/general/language/save_character(var/savefile/S) + S["language"] << pref.alternate_languages + +/datum/category_item/player_setup_item/general/language/sanitize_character() + if(!islist(pref.alternate_languages)) pref.alternate_languages = list() + sanitize_alt_languages() + +/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.
            " + +/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/preference_mob = preference_mob() + var/list/available_languages = S.secondary_langs.Copy() + for(var/L in all_languages) + var/datum/language/lang = all_languages[L] + if(is_allowed_language(preference_mob, lang)) + 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 + sanitize_alt_languages() + return TOPIC_REFRESH + return ..() + +/datum/category_item/player_setup_item/general/language/proc/is_allowed_language(var/mob/user, var/datum/language/lang) + if(!user) + return TRUE + var/datum/species/S = all_species[pref.species] || all_species[SPECIES_HUMAN] + if(lang.name in S.secondary_langs) + return TRUE + if(!(lang.flags & RESTRICTED) && is_alien_whitelisted(user, lang)) + return TRUE + return FALSE + +/datum/category_item/player_setup_item/general/language/proc/sanitize_alt_languages() + if(!istype(pref.alternate_languages)) pref.alternate_languages = list() + + var/preference_mob = preference_mob() + for(var/L in pref.alternate_languages) + var/datum/language/lang = all_languages[L] + if(!lang || !is_allowed_language(preference_mob, lang)) + pref.alternate_languages -= L + + var/datum/species/S = all_species[pref.species] || all_species[SPECIES_HUMAN] + if(pref.alternate_languages.len > S.num_alternate_languages) + pref.alternate_languages.Cut(S.num_alternate_languages + 1) + + pref.alternate_languages = uniquelist(pref.alternate_languages) diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm new file mode 100644 index 00000000..ef9aef91 --- /dev/null +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -0,0 +1,682 @@ +var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-") + +/datum/preferences + var/species = SPECIES_HUMAN //Species datum to use. + var/b_type = "A+" //blood type (not-chooseable) + var/h_style = "Bald" //Hair type + var/r_hair = 0 //Hair color + var/g_hair = 0 //Hair color + var/b_hair = 0 //Hair color + var/f_style = "Shaved" //Face hair type + var/r_facial = 0 //Face hair color + var/g_facial = 0 //Face hair color + var/b_facial = 0 //Face hair color + var/s_tone = 0 //Skin tone + var/r_skin = 0 //Skin color + var/g_skin = 0 //Skin color + var/b_skin = 0 //Skin color + var/r_eyes = 0 //Eye color + var/g_eyes = 0 //Eye color + var/b_eyes = 0 //Eye color + var/s_base = "" //Base skin colour + var/list/body_markings = list() + + // maps each organ to either null(intact), "cyborg" or "amputated" + // will probably not be able to do this for head and torso ;) + var/list/organ_data + var/list/rlimb_data + var/disabilities = 0 + + var/has_cortical_stack = FALSE + var/equip_preview_mob = 0 + + var/icon/bgstate = "000" + var/list/bgstate_options = list("000", "FFF", "steel", "white") + +/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) + from_file(S["species"], pref.species) + from_file(S["hair_red"], pref.r_hair) + from_file(S["hair_green"], pref.g_hair) + from_file(S["hair_blue"], pref.b_hair) + from_file(S["facial_red"], pref.r_facial) + from_file(S["facial_green"], pref.g_facial) + from_file(S["facial_blue"], pref.b_facial) + from_file(S["skin_tone"], pref.s_tone) + from_file(S["skin_red"], pref.r_skin) + from_file(S["skin_green"], pref.g_skin) + from_file(S["skin_blue"], pref.b_skin) + from_file(S["skin_base"], pref.s_base) + from_file(S["hair_style_name"], pref.h_style) + from_file(S["facial_style_name"], pref.f_style) + from_file(S["eyes_red"], pref.r_eyes) + from_file(S["eyes_green"], pref.g_eyes) + from_file(S["eyes_blue"], pref.b_eyes) + from_file(S["b_type"], pref.b_type) + from_file(S["disabilities"], pref.disabilities) + from_file(S["organ_data"], pref.organ_data) + from_file(S["rlimb_data"], pref.rlimb_data) + from_file(S["has_cortical_stack"], pref.has_cortical_stack) + from_file(S["body_markings"], pref.body_markings) + pref.preview_icon = null + from_file(S["bgstate"], pref.bgstate) + +/datum/category_item/player_setup_item/general/body/save_character(var/savefile/S) + to_file(S["species"], pref.species) + to_file(S["hair_red"], pref.r_hair) + to_file(S["hair_green"], pref.g_hair) + to_file(S["hair_blue"], pref.b_hair) + to_file(S["facial_red"], pref.r_facial) + to_file(S["facial_green"], pref.g_facial) + to_file(S["facial_blue"], pref.b_facial) + to_file(S["skin_tone"], pref.s_tone) + to_file(S["skin_red"], pref.r_skin) + to_file(S["skin_green"], pref.g_skin) + to_file(S["skin_base"], pref.s_base) + to_file(S["skin_blue"], pref.b_skin) + to_file(S["hair_style_name"],pref.h_style) + to_file(S["facial_style_name"],pref.f_style) + to_file(S["eyes_red"], pref.r_eyes) + to_file(S["eyes_green"], pref.g_eyes) + to_file(S["eyes_blue"], pref.b_eyes) + to_file(S["b_type"], pref.b_type) + to_file(S["disabilities"], pref.disabilities) + to_file(S["organ_data"], pref.organ_data) + to_file(S["rlimb_data"], pref.rlimb_data) + to_file(S["has_cortical_stack"], pref.has_cortical_stack) + to_file(S["body_markings"], pref.body_markings) + to_file(S["bgstate"], pref.bgstate) + +/datum/category_item/player_setup_item/general/body/sanitize_character(var/savefile/S) + if(!pref.species || !(pref.species in playable_species)) + pref.species = 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.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, GLOB.hair_styles_list, initial(pref.h_style)) + pref.f_style = sanitize_inlist(pref.f_style, GLOB.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.has_cortical_stack = sanitize_bool(pref.has_cortical_stack, initial(pref.has_cortical_stack)) + + var/datum/species/mob_species = all_species[pref.species] + if(mob_species && mob_species.spawn_flags & SPECIES_NO_LACE) + pref.has_cortical_stack = FALSE + + var/low_skin_tone = mob_species ? (35 - mob_species.max_skin_tone()) : -185 + sanitize_integer(pref.s_tone, low_skin_tone, 34, initial(pref.s_tone)) + + if(!mob_species.base_skin_colours || isnull(mob_species.base_skin_colours[pref.s_base])) + pref.s_base = "" + + pref.disabilities = sanitize_integer(pref.disabilities, 0, 65535, initial(pref.disabilities)) + if(!istype(pref.organ_data)) pref.organ_data = list() + if(!istype(pref.rlimb_data)) pref.rlimb_data = list() + if(!istype(pref.body_markings)) + pref.body_markings = list() + else + pref.body_markings &= GLOB.body_marking_styles_list + if(!pref.bgstate || !(pref.bgstate in pref.bgstate_options)) + pref.bgstate = "000" + +/datum/category_item/player_setup_item/general/body/content(var/mob/user) + . = list() + if(!pref.preview_icon) + pref.update_preview_icon() + user << browse_rsc(pref.preview_icon, "previewicon.png") + + var/datum/species/mob_species = all_species[pref.species] + . += "" + return "" + +/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.secondary ? "(secondary)" : ""]

            " + HTML += "Generic Description: [S.desc]

            Unskilled: [S.desc_unskilled]
            " + if(!S.secondary) + HTML += "Amateur: [S.desc_amateur]
            " + HTML += "Trained: [S.desc_trained]
            Professional: [S.desc_professional]" + + 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 + + return ..() diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm new file mode 100644 index 00000000..5c54e530 --- /dev/null +++ b/code/modules/client/preferences.dm @@ -0,0 +1,306 @@ +#define SAVE_RESET -1 + +var/list/preferences_datums = list() + +datum/preferences + //doohickeys for savefiles + var/path + var/default_slot = 1 //Holder so it doesn't default to slot 1, rather the last one used + var/savefile_version = 0 + + //non-preference stuff + var/warns = 0 + var/muted = 0 + var/last_ip + var/last_id + var/is_bordered = 0 + + //game-preferences + var/lastchangelog = "" //Saved changlog filesize to detect if there was a change + + //character preferences + var/species_preview //Used for the species selection window. + + //Mob preview + var/icon/preview_icon = null + var/client/client = null + var/client_ckey = null + + var/savefile/loaded_preferences + var/savefile/loaded_character + var/datum/category_collection/player_setup_collection/player_setup + var/datum/browser/panel + +/datum/preferences/New(client/C) + player_setup = new(src) + gender = MALE + real_name = random_name(gender,species) + b_type = RANDOM_BLOOD_TYPE + + if(istype(C)) + client = C + client_ckey = C.ckey + if(!IsGuestKey(C.key)) + load_path(C.ckey) + load_preferences() + load_and_update_character() + +/datum/preferences/proc/load_and_update_character(var/slot) + load_character(slot) + if(update_setup(loaded_preferences, loaded_character)) + save_preferences() + save_character() + +/datum/preferences/proc/ShowChoices(mob/user) + var/dat = "Interweb Explorer!" + dat += "" + dat += "" + dat += "" + dat += "

            " + dat += "X

            " + if(path) + dat += "Save Slot -" + dat += "Reset Slot -" + dat += "Personalities in your head" + dat += "
            " + dat += player_setup.header() + dat += "
            " + dat += player_setup.content(user) + dat += "" + user <The forum URL is not set in the server configuration.") + return + ShowChoices(usr) + return 1 + +/datum/preferences/Topic(href, list/href_list) + if(..()) + return 1 + + if(href_list["save"]) + save_preferences() + save_character() + else if(href_list["reload"]) + load_preferences() + load_character() + sanitize_preferences() + else if(href_list["load"]) + if(!IsGuestKey(usr.key)) + open_load_dialog(usr) + return 1 + else if(href_list["changeslot"]) + load_character(text2num(href_list["changeslot"])) + sanitize_preferences() + close_load_dialog(usr) + else if(href_list["resetslot"]) + if(real_name != input("This will reset the current slot. Enter the character's full name to confirm.")) + return 0 + load_character(SAVE_RESET) + sanitize_preferences() + else if(href_list["toggletitle"]) + usr <> name + if(!name) name = "Character[i]" + if(i==default_slot) + name = "[name]" + dat += "[name]
            " + + dat += "
            " + dat += "" + panel = new(user, "Character Slots", "Character Slots", 300, 390, src) + panel.set_content(jointext(dat,null)) + panel.open() + +/datum/preferences/proc/close_load_dialog(mob/user) + user << browse(null, "window=saves") + panel.close() diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm new file mode 100644 index 00000000..720e37aa --- /dev/null +++ b/code/modules/client/preferences_savefile.dm @@ -0,0 +1,80 @@ +#define SAVEFILE_VERSION_MIN 8 +#define SAVEFILE_VERSION_MAX 17 + +/datum/preferences/proc/load_path(ckey,filename="preferences.sav") + if(!ckey) return + path = "data/player_saves/[copytext(ckey,1,2)]/[ckey]/[filename]" + savefile_version = SAVEFILE_VERSION_MAX + +/datum/preferences/proc/load_preferences() + if(!path) return 0 + if(!fexists(path)) return 0 + var/savefile/S = new /savefile(path) + if(!S) return 0 + S.cd = "/" + + S["version"] >> savefile_version + player_setup.load_preferences(S) + loaded_preferences = S + return 1 + +/datum/preferences/proc/save_preferences() + if(!path) return 0 + var/savefile/S = new /savefile(path) + if(!S) return 0 + S.cd = "/" + + S["version"] << SAVEFILE_VERSION_MAX + player_setup.save_preferences(S) + loaded_preferences = S + return 1 + +/datum/preferences/proc/load_character(slot) + if(!path) return 0 + if(!fexists(path)) return 0 + var/savefile/S = new /savefile(path) + if(!S) return 0 + S.cd = "/" + if(!slot) slot = default_slot + + if(slot != SAVE_RESET) // SAVE_RESET will reset the slot as though it does not exist, but keep the current slot for saving purposes. + slot = sanitize_integer(slot, 1, config.character_slots, initial(default_slot)) + if(slot != default_slot) + default_slot = slot + S["default_slot"] << slot + else + S["default_slot"] << default_slot + + if(slot != SAVE_RESET) + S.cd = GLOB.using_map.character_load_path(S, slot) + player_setup.load_character(S) + else + player_setup.load_character(S) + S.cd = GLOB.using_map.character_load_path(S, default_slot) + + loaded_character = S + + return 1 + +/datum/preferences/proc/save_character() + if(!path) return 0 + var/savefile/S = new /savefile(path) + if(!S) return 0 + S.cd = GLOB.using_map.character_save_path(default_slot) + + S["version"] << SAVEFILE_VERSION_MAX + player_setup.save_character(S) + loaded_character = S + return S + +/datum/preferences/proc/sanitize_preferences() + player_setup.sanitize_setup() + return 1 + +/datum/preferences/proc/update_setup(var/savefile/preferences, var/savefile/character) + if(!preferences || !character) + return 0 + return player_setup.update_setup(preferences, character) + +#undef SAVEFILE_VERSION_MAX +#undef SAVEFILE_VERSION_MIN diff --git a/code/modules/client/preferences_spawnpoints.dm b/code/modules/client/preferences_spawnpoints.dm new file mode 100644 index 00000000..7eb39718 --- /dev/null +++ b/code/modules/client/preferences_spawnpoints.dm @@ -0,0 +1,77 @@ +GLOBAL_VAR(spawntypes) + +/proc/spawntypes() + if(!GLOB.spawntypes) + GLOB.spawntypes = list() + for(var/type in typesof(/datum/spawnpoint)-/datum/spawnpoint) + var/datum/spawnpoint/S = type + var/display_name = initial(S.display_name) + if((display_name in GLOB.using_map.allowed_spawns) || initial(S.always_visible)) + GLOB.spawntypes[display_name] = new S + return GLOB.spawntypes + +/datum/spawnpoint + var/msg //Message to display on the arrivals computer. + var/list/turfs //List of turfs to spawn on. + var/display_name //Name used in preference setup. + var/always_visible = FALSE // Whether this spawn point is always visible in selection, ignoring map-specific settings. + var/list/restrict_job = null + var/list/disallow_job = null + +/datum/spawnpoint/proc/check_job_spawning(job) + if(restrict_job && !(job in restrict_job)) + return 0 + + if(disallow_job && (job in disallow_job)) + return 0 + + return 1 + +#ifdef UNIT_TEST +/datum/spawnpoint/Del() + crash_with("Spawn deleted: [log_info_line(src)]") + ..() + +/datum/spawnpoint/Destroy() + crash_with("Spawn destroyed: [log_info_line(src)]") + . = ..() +#endif + +/datum/spawnpoint/arrivals + display_name = "Arrivals Shuttle" + msg = "has arrived" + +/datum/spawnpoint/arrivals/New() + ..() + turfs = GLOB.latejoin + +/datum/spawnpoint/gateway + display_name = "Gateway" + msg = "has completed translation from offsite gateway" + +/datum/spawnpoint/gateway/New() + ..() + turfs = GLOB.latejoin_gateway + +/datum/spawnpoint/cryo + display_name = "Cryogenic Storage" + msg = "has completed cryogenic revival" + disallow_job = list("Cyborg") + +/datum/spawnpoint/cryo/New() + ..() + turfs = GLOB.latejoin_cryo + +/datum/spawnpoint/cyborg + display_name = "Cyborg Storage" + msg = "has been activated from storage" + restrict_job = list("Cyborg") + +/datum/spawnpoint/cyborg/New() + ..() + turfs = GLOB.latejoin_cyborg + +/datum/spawnpoint/default + display_name = DEFAULT_SPAWNPOINT_ID + msg = "has arrived" + always_visible = TRUE \ No newline at end of file diff --git a/code/modules/client/preferences_toggle.dm b/code/modules/client/preferences_toggle.dm new file mode 100644 index 00000000..fe1be836 --- /dev/null +++ b/code/modules/client/preferences_toggle.dm @@ -0,0 +1,62 @@ +var/list/client_preference_stats_ + +/proc/client_preference_stats_for_usr(var/mob/user = usr) + . = list() + if(!user) + return + if(!client_preference_stats_) + client_preference_stats_ = list() + for(var/datum/client_preference/client_pref in get_client_preferences()) + client_preference_stats_[client_pref.description] = new /stat_client_preference(null, client_pref) + + for(var/client_pref_description in client_preference_stats_) + var/stat_client_preference/scp = client_preference_stats_[client_pref_description] + if(scp.client_preference.may_set(user)) + scp.update_name(user) + .[client_pref_description] = scp + +/client/verb/toggle_preference_verb(var/client_pref_name in client_preference_stats_for_usr()) + set name = "Toggle Preference" + set desc = "Toggles the selected preference." + set category = "OOC" + + var/list/client_stats = client_preference_stats_for_usr() + var/stat_client_preference/scp = client_stats[client_pref_name] + if(istype(scp)) + scp.Click() + +/mob/Stat() + . = ..() + if(!client || !statpanel("Preferences")) + return + var/list/preferences = client_preference_stats_for_usr(src) + for(var/client_preference_description in preferences) + var/stat_client_preference/scp = client_preference_stats_[client_preference_description] + stat(scp.client_preference.description, scp) + +/stat_client_preference + parent_type = /atom/movable + simulated = 0 + var/datum/client_preference/client_preference + +/stat_client_preference/New(var/loc, var/preference) + client_preference = preference + update_name(usr) + ..() + +/stat_client_preference/Destroy() + client_preference = null + . = ..() + +/stat_client_preference/Click() + if(!usr.client) + return + + if(!usr.cycle_preference(client_preference)) + return + + usr.client.prefs.save_preferences() + to_chat(usr, "[client_preference.description]: [usr.get_preference_value(client_preference)]") + +/stat_client_preference/proc/update_name(var/mob/user) + name = user.get_preference_value(client_preference) diff --git a/code/modules/client/ui_style.dm b/code/modules/client/ui_style.dm new file mode 100644 index 00000000..f2719c9a --- /dev/null +++ b/code/modules/client/ui_style.dm @@ -0,0 +1,61 @@ + + +/var/all_ui_styles = list( + "Midnight" = 'icons/mob/screen/midnight.dmi', + "Orange" = 'icons/mob/screen/orange.dmi', + "old" = 'icons/mob/screen/old.dmi', + "White" = 'icons/mob/screen/white.dmi', + "old-noborder" = 'icons/mob/screen/old-noborder.dmi', + "minimalist" = 'icons/mob/screen/minimalist.dmi' + ) + +/proc/ui_style2icon(ui_style) + if(ui_style in all_ui_styles) + return all_ui_styles[ui_style] + return all_ui_styles["White"] + +/* +/client/verb/change_ui() + set name = "Change UI" + set category = "OOC" + set desc = "Configure your user interface" + + if(!ishuman(usr)) + to_chat(usr, "You must be human to use this verb.") + return + if(usr.using_alt_hud) + return + + var/UI_style_new = input(usr, "Select a style. White is recommended for customization") as null|anything in all_ui_styles + if(!UI_style_new) return + + var/UI_style_alpha_new = input(usr, "Select a new alpha (transparency) parameter for your UI, between 50 and 255") as null|num + if(!UI_style_alpha_new | !(UI_style_alpha_new <= 255 && UI_style_alpha_new >= 50)) return + + var/UI_style_color_new = input(usr, "Choose your UI color. Dark colors are not recommended!") as color|null + if(!UI_style_color_new) return + + //update UI + var/list/icons = usr.hud_used.adding + usr.hud_used.other + usr.hud_used.hotkeybuttons + icons.Add(usr.zone_sel) + icons.Add(usr.gun_setting_icon) + icons.Add(usr.item_use_icon) + icons.Add(usr.gun_move_icon) + icons.Add(usr.radio_use_icon) + + var/icon/ic = all_ui_styles[UI_style_new] + + for(var/obj/screen/I in icons) + if(I.name in list(I_HELP, I_HURT, I_DISARM, I_GRAB)) continue + I.icon = ic + I.color = UI_style_color_new + I.alpha = UI_style_alpha_new + + + if(alert("Like it? Save changes?",,"Yes", "No") == "Yes") + prefs.UI_style = UI_style_new + prefs.UI_style_alpha = UI_style_alpha_new + prefs.UI_style_color = UI_style_color_new + prefs.save_preferences() + to_chat(usr, "UI was saved") +*/ diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm new file mode 100644 index 00000000..19ad48f6 --- /dev/null +++ b/code/modules/clothing/chameleon.dm @@ -0,0 +1,420 @@ +//***************** +//**Cham Jumpsuit** +//***************** + +/obj/item/proc/disguise(var/newtype, var/mob/user) + if(!user || user.incapacitated()) + return + //this is necessary, unfortunately, as initial() does not play well with list vars + var/obj/item/copy = new newtype(null) //so that it is GCed once we exit + + desc = copy.desc + name = copy.name + icon_state = copy.icon_state + item_state = copy.item_state + body_parts_covered = copy.body_parts_covered + flags_inv = copy.flags_inv + + if(copy.item_icons) + item_icons = copy.item_icons.Copy() + if(copy.item_state_slots) + item_state_slots = copy.item_state_slots.Copy() + if(copy.sprite_sheets) + sprite_sheets = copy.sprite_sheets.Copy() + //copying sprite_sheets_obj should be unnecessary as chameleon items are not refittable. + + return copy //for inheritance + +/proc/generate_chameleon_choices(var/basetype, var/blacklist=list()) + . = list() + + var/i = 1 //in case there is a collision with both name AND icon_state + for(var/typepath in typesof(basetype) - blacklist) + var/obj/O = typepath + if(initial(O.icon) && initial(O.icon_state)) + var/name = initial(O.name) + if(name in .) + name += " ([initial(O.icon_state)])" + if(name in .) + name += " \[[i++]\]" + .[name] = typepath + +/obj/item/clothing/under/chameleon +//starts off as black + name = "black jumpsuit" + icon_state = "black" + item_state = "bl_suit" + worn_state = "black" + desc = "It's a plain jumpsuit. It seems to have a small dial on the wrist." + origin_tech = list(TECH_ILLEGAL = 3) + var/global/list/clothing_choices + +/obj/item/clothing/under/chameleon/New() + ..() + if(!clothing_choices) + var/blocked = list(src.type, /obj/item/clothing/under/cloud, /obj/item/clothing/under/gimmick)//Prevent infinite loops and bad jumpsuits. + clothing_choices = generate_chameleon_choices(/obj/item/clothing/under, blocked) + +/obj/item/clothing/under/chameleon/emp_act(severity) + name = "psychedelic" + desc = "Groovy!" + icon_state = "psyche" + item_state_slots[slot_w_uniform_str] = "psyche" + update_icon() + update_clothing_icon() + +/obj/item/clothing/under/chameleon/verb/change(picked in clothing_choices) + set name = "Change Jumpsuit Appearance" + set category = "Chameleon Items" + set src in usr + + if(!ispath(clothing_choices[picked])) + return + + disguise(clothing_choices[picked], usr) + update_clothing_icon() //so our overlays update. + +//***************** +//**Chameleon Hat** +//***************** + +/obj/item/clothing/head/chameleon + name = "grey cap" + icon_state = "greysoft" + desc = "It looks like a plain hat, but upon closer inspection, there's an advanced holographic array installed inside. It seems to have a small dial inside." + origin_tech = list(TECH_ILLEGAL = 3) + body_parts_covered = 0 + var/global/list/clothing_choices + +/obj/item/clothing/head/chameleon/New() + ..() + if(!clothing_choices) + var/blocked = list(src.type, /obj/item/clothing/head/justice,)//Prevent infinite loops and bad hats. + clothing_choices = generate_chameleon_choices(/obj/item/clothing/head, blocked) + +/obj/item/clothing/head/chameleon/emp_act(severity) //Because we don't have psych for all slots right now but still want a downside to EMP. In this case your cover's blown. + SetName(initial(name)) + desc = initial(desc) + icon_state = initial(icon_state) + update_icon() + update_clothing_icon() + +/obj/item/clothing/head/chameleon/verb/change(picked in clothing_choices) + set name = "Change Hat/Helmet Appearance" + set category = "Chameleon Items" + set src in usr + + if(!ispath(clothing_choices[picked])) + return + + disguise(clothing_choices[picked], usr) + update_clothing_icon() //so our overlays update. + +//****************** +//**Chameleon Suit** +//****************** + +/obj/item/clothing/suit/chameleon + name = "armor" + icon_state = "armor" + item_state = "armor" + desc = "It appears to be a vest of standard armor, except this is embedded with a hidden holographic cloaker, allowing it to change it's appearance, but offering no protection.. It seems to have a small dial inside." + origin_tech = list(TECH_ILLEGAL = 3) + var/global/list/clothing_choices + +/obj/item/clothing/suit/chameleon/New() + ..() + if(!clothing_choices) + var/blocked = list(src.type, /obj/item/clothing/suit/cyborg_suit, /obj/item/clothing/suit/justice, /obj/item/clothing/suit/greatcoat) + clothing_choices = generate_chameleon_choices(/obj/item/clothing/suit, blocked) + +/obj/item/clothing/suit/chameleon/emp_act(severity) //Because we don't have psych for all slots right now but still want a downside to EMP. In this case your cover's blown. + SetName(initial(name)) + desc = initial(desc) + icon_state = initial(icon_state) + update_icon() + update_clothing_icon() + +/obj/item/clothing/suit/chameleon/verb/change(picked in clothing_choices) + set name = "Change Oversuit Appearance" + set category = "Chameleon Items" + set src in usr + + if(!ispath(clothing_choices[picked])) + return + + disguise(clothing_choices[picked], usr) + update_clothing_icon() //so our overlays update. + +//******************* +//**Chameleon Shoes** +//******************* +/obj/item/clothing/shoes/chameleon + name = "black shoes" + icon_state = "black" + item_state = "black" + desc = "They're comfy black shoes, with clever cloaking technology built in. It seems to have a small dial on the back of each shoe." + origin_tech = list(TECH_ILLEGAL = 3) + var/global/list/clothing_choices + +/obj/item/clothing/shoes/chameleon/New() + ..() + if(!clothing_choices) + var/blocked = list(src.type, /obj/item/clothing/shoes/syndigaloshes, /obj/item/clothing/shoes/cyborg)//prevent infinite loops and bad shoes. + clothing_choices = generate_chameleon_choices(/obj/item/clothing/shoes, blocked) + +/obj/item/clothing/shoes/chameleon/emp_act(severity) //Because we don't have psych for all slots right now but still want a downside to EMP. In this case your cover's blown. + SetName(initial(name)) + desc = initial(desc) + icon_state = initial(icon_state) + item_state = initial(item_state) + update_icon() + update_clothing_icon() + +/obj/item/clothing/shoes/chameleon/verb/change(picked in clothing_choices) + set name = "Change Footwear Appearance" + set category = "Chameleon Items" + set src in usr + + if(!ispath(clothing_choices[picked])) + return + + disguise(clothing_choices[picked], usr) + update_clothing_icon() //so our overlays update. + +//********************** +//**Chameleon Backpack** +//********************** +/obj/item/weapon/storage/backpack/chameleon + name = "backpack" + icon_state = "backpack" + item_state = "backpack" + desc = "A backpack outfitted with cloaking tech. It seems to have a small dial inside, kept away from the storage." + origin_tech = list(TECH_ILLEGAL = 3) + var/global/list/clothing_choices + +/obj/item/weapon/storage/backpack/chameleon/New() + ..() + if(!clothing_choices) + var/blocked = list(src.type, /obj/item/weapon/storage/backpack/satchel/grey/withwallet) + clothing_choices = generate_chameleon_choices(/obj/item/weapon/storage/backpack, blocked) + +/obj/item/weapon/storage/backpack/chameleon/emp_act(severity) //Because we don't have psych for all slots right now but still want a downside to EMP. In this case your cover's blown. + SetName(initial(name)) + desc = initial(desc) + icon_state = initial(icon_state) + item_state = initial(item_state) + update_icon() + if (ismob(src.loc)) + var/mob/M = src.loc + M.update_inv_back() + +/obj/item/weapon/storage/backpack/chameleon/verb/change(picked in clothing_choices) + set name = "Change Backpack Appearance" + set category = "Chameleon Items" + set src in usr + + if(!ispath(clothing_choices[picked])) + return + + disguise(clothing_choices[picked], usr) + + //so our overlays update. + if (ismob(src.loc)) + var/mob/M = src.loc + M.update_inv_back() + +//******************** +//**Chameleon Gloves** +//******************** + +/obj/item/clothing/gloves/chameleon + name = "black gloves" + icon_state = "black" + item_state = "bgloves" + desc = "It looks like a pair of gloves, but it seems to have a small dial inside." + origin_tech = list(TECH_ILLEGAL = 3) + var/global/list/clothing_choices + +/obj/item/clothing/gloves/chameleon/New() + ..() + if(!clothing_choices) + clothing_choices = generate_chameleon_choices(/obj/item/clothing/gloves, list(src.type)) + +/obj/item/clothing/gloves/chameleon/emp_act(severity) //Because we don't have psych for all slots right now but still want a downside to EMP. In this case your cover's blown. + SetName(initial(name)) + desc = initial(desc) + icon_state = initial(icon_state) + item_state = initial(item_state) + update_icon() + update_clothing_icon() + +/obj/item/clothing/gloves/chameleon/verb/change(picked in clothing_choices) + set name = "Change Gloves Appearance" + set category = "Chameleon Items" + set src in usr + + if(!ispath(clothing_choices[picked])) + return + + disguise(clothing_choices[picked], usr) + update_clothing_icon() //so our overlays update. + +//****************** +//**Chameleon Mask** +//****************** + +/obj/item/clothing/mask/chameleon + name = "gas mask" + icon_state = "fullgas" + item_state = "gas_alt" + desc = "It looks like a plain gask mask, but on closer inspection, it seems to have a small dial inside." + origin_tech = list(TECH_ILLEGAL = 3) + var/global/list/clothing_choices + +/obj/item/clothing/mask/chameleon/New() + ..() + if(!clothing_choices) + clothing_choices = generate_chameleon_choices(/obj/item/clothing/mask, list(src.type)) + +/obj/item/clothing/mask/chameleon/emp_act(severity) //Because we don't have psych for all slots right now but still want a downside to EMP. In this case your cover's blown. + SetName(initial(name)) + desc = initial(desc) + icon_state = initial(icon_state) + item_state = initial(item_state) + update_icon() + update_clothing_icon() + +/obj/item/clothing/mask/chameleon/verb/change(picked in clothing_choices) + set name = "Change Mask Appearance" + set category = "Chameleon Items" + set src in usr + + if(!ispath(clothing_choices[picked])) + return + + disguise(clothing_choices[picked], usr) + update_clothing_icon() //so our overlays update. + +//********************* +//**Chameleon Glasses** +//********************* + +/obj/item/clothing/glasses/chameleon + name = "Optical Meson Scanner" + icon_state = "meson" + item_state = "glasses" + desc = "It looks like a plain set of mesons, but on closer inspection, it seems to have a small dial inside." + origin_tech = list(TECH_ILLEGAL = 3) + var/list/global/clothing_choices + +/obj/item/clothing/glasses/chameleon/New() + ..() + if(!clothing_choices) + clothing_choices = generate_chameleon_choices(/obj/item/clothing/glasses, list(src.type)) + +/obj/item/clothing/glasses/chameleon/emp_act(severity) //Because we don't have psych for all slots right now but still want a downside to EMP. In this case your cover's blown. + SetName(initial(name)) + desc = initial(desc) + icon_state = initial(icon_state) + item_state = initial(item_state) + update_icon() + update_clothing_icon() + +/obj/item/clothing/glasses/chameleon/verb/change(picked in clothing_choices) + set name = "Change Glasses Appearance" + set category = "Chameleon Items" + set src in usr + + if(!ispath(clothing_choices[picked])) + return + + disguise(clothing_choices[picked], usr) + update_clothing_icon() //so our overlays update. + +//***************** +//**Chameleon Gun** +//***************** +/obj/item/weapon/gun/energy/chameleon + name = "revolver" + desc = "A hologram projector in the shape of a gun. There is a dial on the side to change the gun's disguise." + icon_state = "revolver" + w_class = ITEM_SIZE_SMALL + origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2, TECH_ILLEGAL = 8) + matter = list() + + fire_sound = 'sound/weapons/gunshot/gunshot_pistol.ogg' + projectile_type = /obj/item/projectile/chameleon + charge_meter = 0 + charge_cost = 20 //uses next to no power, since it's just holograms + max_shots = 50 + + var/obj/item/projectile/copy_projectile + var/global/list/gun_choices + +/obj/item/weapon/gun/energy/chameleon/New() + ..() + + if(!gun_choices) + gun_choices = list() + for(var/gun_type in typesof(/obj/item/weapon/gun/) - src.type) + var/obj/item/weapon/gun/G = gun_type + src.gun_choices[initial(G.name)] = gun_type + return + +/obj/item/weapon/gun/energy/chameleon/consume_next_projectile() + var/obj/item/projectile/P = ..() + if(P && ispath(copy_projectile)) + P.SetName(initial(copy_projectile.name)) + P.icon = initial(copy_projectile.icon) + P.icon_state = initial(copy_projectile.icon_state) + P.pass_flags = initial(copy_projectile.pass_flags) + P.hitscan = initial(copy_projectile.hitscan) + P.speed = initial(copy_projectile.speed) + P.muzzle_type = initial(copy_projectile.muzzle_type) + P.tracer_type = initial(copy_projectile.tracer_type) + P.impact_type = initial(copy_projectile.impact_type) + return P + +/obj/item/weapon/gun/energy/chameleon/emp_act(severity) + SetName(initial(name)) + desc = initial(desc) + icon_state = initial(icon_state) + update_icon() + if (ismob(src.loc)) + var/mob/M = src.loc + M.update_inv_r_hand() + M.update_inv_l_hand() + +/obj/item/weapon/gun/energy/chameleon/disguise(var/newtype) + var/obj/item/weapon/gun/copy = ..() + if(!copy) + return + + flags_inv = copy.flags_inv + fire_sound = copy.fire_sound + fire_sound_text = copy.fire_sound_text + + var/obj/item/weapon/gun/energy/E = copy + if(istype(E)) + copy_projectile = E.projectile_type + //charge_meter = E.charge_meter //does not work very well with icon_state changes, ATM + else + copy_projectile = null + //charge_meter = 0 + +/obj/item/weapon/gun/energy/chameleon/verb/change(picked in gun_choices) + set name = "Change Gun Appearance" + set category = "Chameleon Items" + set src in usr + + if(!ispath(gun_choices[picked])) + return + + disguise(gun_choices[picked], usr) + + //so our overlays update. + if (ismob(src.loc)) + var/mob/M = src.loc + M.update_inv_r_hand() + M.update_inv_l_hand() diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm new file mode 100644 index 00000000..b2eb1e12 --- /dev/null +++ b/code/modules/clothing/clothing.dm @@ -0,0 +1,921 @@ +/obj/item/clothing + name = "clothing" + siemens_coefficient = 0.9 + drop_sound = 'sound/items/drop_clothing.ogg' + 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 = list("exclude", SPECIES_NABBER) //Only these species can wear this kit. + var/gunshot_residue //Used by forensics. + + var/list/accessories = list() + var/list/valid_accessory_slots + var/list/restricted_accessory_slots + var/list/starting_accessories + var/blood_overlay_type = "uniformblood" + var/visible_name = "Unknown" + var/can_be_worn_by_child = FALSE //Snowflake shit for kids. + var/child_exclusive = FALSE + var/warfare_team = null + var/helmet_vision = FALSE + +// Updates the icons of the mob wearing the clothing item, if any. +/obj/item/clothing/proc/update_clothing_icon() + return + +// Updates the vision of the mob wearing the clothing item, if any +/obj/item/clothing/proc/update_vision() + if(isliving(src.loc)) + var/mob/living/L = src.loc + L.handle_vision() + +// Checked when equipped, returns true when the wearing mob's vision should be updated +/obj/item/clothing/proc/needs_vision_update() + return flash_protection || tint + +/obj/item/clothing/get_mob_overlay(mob/user_mob, slot) + var/image/ret = ..() + + if(slot == slot_l_hand_str || slot == slot_r_hand_str) + return ret + + if(ishuman(user_mob)) + var/mob/living/carbon/human/user_human = user_mob + if(blood_DNA && user_human.species.blood_mask) + var/image/bloodsies = overlay_image(user_human.species.blood_mask, blood_overlay_type, blood_color)//, RESET_COLOR) + ret.overlays += bloodsies + + if(accessories.len) + for(var/obj/item/clothing/accessory/A in accessories) + ret.overlays |= A.get_mob_overlay(user_mob, slot) + return ret + +// Aurora forensics port. +/obj/item/clothing/clean_blood() + . = ..() + gunshot_residue = null + +/obj/item/clothing/proc/get_fibers() + . = "material from \a [name]" + var/list/acc = list() + for(var/obj/item/clothing/accessory/A in accessories) + if(prob(40) && A.get_fibers()) + acc += A.get_fibers() + if(acc.len) + . += " with traces of [english_list(acc)]" + +/obj/item/clothing/New() + ..() + if(starting_accessories) + for(var/T in starting_accessories) + var/obj/item/clothing/accessory/tie = new T(src) + src.attach_accessory(null, tie) + +//BS12: Species-restricted clothing check. +/obj/item/clothing/mob_can_equip(M as mob, slot, disable_warning = 0) + + //if we can't equip the item anyway, don't bother with species_restricted (cuts down on spam) + if (!..()) + return 0 + + var/wearable = TRUE + if(ishuman(M))//hacky kid shit + var/mob/living/carbon/human/H = M + if(H.isChild()) + if(!child_exclusive || !can_be_worn_by_child) + wearable = FALSE + else + if(child_exclusive) + wearable = FALSE + + if(species_restricted && istype(M,/mob/living/carbon/human)) + var/exclusive = null + var/mob/living/carbon/human/H = M + + if("exclude" in species_restricted) + exclusive = 1 + + if(H.species) + if(exclusive) + if(!(H.species.get_bodytype(H) in species_restricted)) + wearable = TRUE + else + if(H.species.get_bodytype(H) in species_restricted) + wearable = TRUE + + if(!wearable && !(slot in list(slot_l_store, slot_r_store, slot_s_store))) + if(!disable_warning) + to_chat(H, "Your species cannot wear [src].") + return 0 + + if(warfare_team) + if(ishuman(M))//hacky warfare shit + var/mob/living/carbon/human/H = M + if(H.warfare_faction != warfare_team) + return FALSE + + return 1 + +/obj/item/clothing/equipped(var/mob/user) + if(needs_vision_update()) + update_vision() + return ..() + +/obj/item/clothing/proc/refit_for_species(var/target_species) + if(!species_restricted) + return //this item doesn't use the species_restricted system + + //Set species_restricted list + switch(target_species) + if(SPECIES_HUMAN, SPECIES_SKRELL) //humanoid bodytypes + species_restricted = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_IPC) //skrell/humans/machines can wear each other's suits + else + species_restricted = list(target_species) + + if (sprite_sheets_obj && (target_species in sprite_sheets_obj)) + icon = sprite_sheets_obj[target_species] + else + icon = initial(icon) + +/obj/item/clothing/head/helmet/refit_for_species(var/target_species) + if(!species_restricted) + return //this item doesn't use the species_restricted system + + //Set species_restricted list + switch(target_species) + if(SPECIES_SKRELL) + species_restricted = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_IPC) //skrell helmets fit humans too + if(SPECIES_HUMAN) + species_restricted = list(SPECIES_HUMAN, SPECIES_IPC) //human helmets fit IPCs too + else + species_restricted = list(target_species) + + if (sprite_sheets_obj && (target_species in sprite_sheets_obj)) + icon = sprite_sheets_obj[target_species] + else + icon = initial(icon) +/* +/obj/item/clothing/get_examine_line() + . = ..() + var/list/ties = list() + for(var/obj/item/clothing/accessory/accessory in accessories) + if(accessory.high_visibility) + ties += "\icon[accessory] \a [accessory]" + if(ties.len) + .+= " with [english_list(ties)] attached" + if(accessories.len > ties.len) + .+= ". \[See accessories\]" +*/ +/obj/item/clothing/CanUseTopic(var/user) + if(user in view(get_turf(src))) + return STATUS_INTERACTIVE + +/obj/item/clothing/OnTopic(var/user, var/list/href_list, var/datum/topic_state/state) + if(href_list["list_ungabunga"]) + if(accessories.len) + var/list/ties = list() + for(var/accessory in accessories) + ties += "\icon[accessory] \a [accessory]" + to_chat(user, "Attached to \the [src] are [english_list(ties)].") + return TOPIC_HANDLED + +/////////////////////////////////////////////////////////////////////// +// Ears: headsets, earmuffs and tiny objects +/obj/item/clothing/ears + name = "ears" + w_class = ITEM_SIZE_TINY + throwforce = 2 + slot_flags = SLOT_EARS + +/obj/item/clothing/ears/update_clothing_icon() + if (ismob(src.loc)) + var/mob/M = src.loc + M.update_inv_ears() + +/obj/item/clothing/ears/earmuffs + name = "earmuffs" + desc = "Protects your hearing from loud noises, and quiet ones as well." + icon_state = "earmuffs" + item_state = "earmuffs" + slot_flags = SLOT_EARS | SLOT_TWOEARS + +/obj/item/clothing/ears/earmuffs/headphones + name = "headphones" + desc = "It's probably not in accordance with corporate policy to listen to music on the job... but fuck it." + var/headphones_on = 0 + icon_state = "headphones_off" + item_state = "headphones_off" + slot_flags = SLOT_EARS | SLOT_TWOEARS + +/obj/item/clothing/ears/earmuffs/headphones/proc/togglemusic() + set name = "Toggle Headphone Music" + set category = "Object" + if(!istype(usr, /mob/living)) return + if(usr.incapacitated()) return + + if(headphones_on) + icon_state = "headphones_off" + item_state = "headphones_off" + headphones_on = 0 + to_chat(usr, "You turn the music off.") + else + icon_state = "headphones_on" + item_state = "headphones_on" + headphones_on = 1 + to_chat(usr, "You turn the music on.") + + update_clothing_icon() + +/obj/item/clothing/ears/earmuffs/headphones/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + if(src == user.get_active_hand()) + togglemusic() + +/////////////////////////////////////////////////////////////////////// +//Glasses +/* +SEE_SELF // can see self, no matter what +SEE_MOBS // can see all mobs, no matter what +SEE_OBJS // can see all objs, no matter what +SEE_TURFS // can see all turfs (and areas), no matter what +SEE_PIXELS// if an object is located on an unlit area, but some of its pixels are + // in a lit area (via pixel_x, y or smooth movement), can see those pixels +BLIND // can't see anything +*/ +/obj/item/clothing/glasses + name = "glasses" + icon = 'icons/obj/clothing/glasses.dmi' + w_class = ITEM_SIZE_SMALL + body_parts_covered = EYES + slot_flags = SLOT_EYES + var/vision_flags = 0 + var/darkness_view = 0//Base human is 2 + var/see_invisible = -1 + var/light_protection = 0 + +/obj/item/clothing/glasses/get_icon_state(mob/user_mob, slot) + if(item_state_slots && item_state_slots[slot]) + return item_state_slots[slot] + else + return icon_state + return ..() + +/obj/item/clothing/glasses/update_clothing_icon() + if (ismob(src.loc)) + var/mob/M = src.loc + M.update_inv_glasses() + +/////////////////////////////////////////////////////////////////////// +//Gloves +/obj/item/clothing/gloves + name = "gloves" + gender = PLURAL //Carn: for grammarically correct text-parsing + w_class = ITEM_SIZE_SMALL + icon = 'icons/obj/clothing/gloves.dmi' + siemens_coefficient = 0.75 + var/wired = 0 + var/obj/item/weapon/cell/cell = 0 + var/clipped = 0 + var/obj/item/clothing/ring/ring = null //Covered ring + var/mob/living/carbon/human/wearer = null //Used for covered rings when dropping + body_parts_covered = HANDS + slot_flags = SLOT_GLOVES + attack_verb = list("challenged") + blood_overlay_type = "bloodyhands" + +/obj/item/clothing/gloves/Initialize() + if(item_flags & ITEM_FLAG_PREMODIFIED) + cut_fingertops() + + . = ..() + +/obj/item/clothing/gloves/update_clothing_icon() + if (ismob(src.loc)) + var/mob/M = src.loc + M.update_inv_gloves() + +/obj/item/clothing/gloves/emp_act(severity) + if(cell) + //why is this not part of the powercell code? + cell.charge -= 1000 / severity + if (cell.charge < 0) + cell.charge = 0 + ..() + +/obj/item/clothing/gloves/get_fibers() + return "material from a pair of [name]." + +// Called just before an attack_hand(), in mob/UnarmedAttack() +/obj/item/clothing/gloves/proc/Touch(var/atom/A, var/proximity) + return 0 // return 1 to cancel attack_hand() + +/obj/item/clothing/gloves/attackby(obj/item/weapon/W, mob/user) + if(istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/weapon/scalpel)) + if (clipped) + to_chat(user, "\The [src] have already been modified!") + update_icon() + return + + playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) + user.visible_message("\The [user] modifies \the [src] with \the [W].","You modify \the [src] with \the [W].") + + cut_fingertops() // apply change, so relevant xenos can wear these + return + +// Applies "clipped" and removes relevant restricted species from the list, +// making them wearable by the specified species, does nothing if already cut +/obj/item/clothing/gloves/proc/cut_fingertops() + if (clipped) + return + + clipped = 1 + name = "modified [name]" + desc = "[desc]
            They have been modified to accommodate a different shape." + if("exclude" in species_restricted) + species_restricted -= SPECIES_UNATHI + species_restricted -= SPECIES_TAJARA + return + +/obj/item/clothing/gloves/mob_can_equip(mob/user) + var/mob/living/carbon/human/H = user + + if(istype(H.gloves, /obj/item/clothing/ring)) + ring = H.gloves + if(!ring.undergloves) + to_chat(user, "You are unable to wear \the [src] as \the [H.gloves] are in the way.") + ring = null + return 0 + H.drop_from_inventory(ring) //Remove the ring (or other under-glove item in the hand slot?) so you can put on the gloves. + ring.forceMove(src) + + if(!..()) + if(ring) //Put the ring back on if the check fails. + if(H.equip_to_slot_if_possible(ring, slot_gloves)) + src.ring = null + return 0 + + if (ring) + to_chat(user, "You slip \the [src] on over \the [ring].") + wearer = H //TODO clean this when magboots are cleaned + return 1 + +/obj/item/clothing/gloves/dropped() + ..() + if(!wearer) + return + + var/mob/living/carbon/human/H = wearer + if(ring && istype(H)) + if(!H.equip_to_slot_if_possible(ring, slot_gloves)) + ring.forceMove(get_turf(src)) + src.ring = null + wearer = null + +/////////////////////////////////////////////////////////////////////// +//Head +/obj/item/clothing/head + name = "head" + icon = 'icons/obj/clothing/hats.dmi' + item_icons = list( + slot_l_hand_str = 'icons/mob/onmob/items/lefthand_hats.dmi', + slot_r_hand_str = 'icons/mob/onmob/items/righthand_hats.dmi', + ) + body_parts_covered = HEAD + slot_flags = SLOT_HEAD + w_class = ITEM_SIZE_SMALL + + var/light_overlay = "helmet_light" + var/light_applied + var/brightness_on + var/on = 0 + blood_overlay_type = "helmetblood" + +/obj/item/clothing/head/get_mob_overlay(mob/user_mob, slot) + var/image/ret = ..() + var/bodytype = "Default" + if(ishuman(user_mob)) + var/mob/living/carbon/human/user_human = user_mob + bodytype = user_human.species.get_bodytype(user_human) + var/cache_key = "[light_overlay]_[bodytype]" + if(on && light_overlay_cache[cache_key] && slot == slot_head_str) + ret.overlays |= light_overlay_cache[cache_key] + return ret + +/obj/item/clothing/head/attack_self(mob/user) + if(brightness_on) + if(!isturf(user.loc)) + to_chat(user, "You cannot turn the light on while in this [user.loc]") + return + on = !on + to_chat(user, "You [on ? "enable" : "disable"] the helmet light.") + update_flashlight(user) + else + return ..(user) + +/obj/item/clothing/head/proc/update_flashlight(var/mob/user = null) + if(on && !light_applied) + set_light(brightness_on) + light_applied = 1 + else if(!on && light_applied) + set_light(0) + light_applied = 0 + update_icon(user) + user.update_action_buttons() + +/obj/item/clothing/head/attack_ai(var/mob/user) + if(!mob_wear_hat(user)) + return ..() + +/obj/item/clothing/head/attack_generic(var/mob/user) + if(!istype(user) || !mob_wear_hat(user)) + return ..() + +/obj/item/clothing/head/proc/mob_wear_hat(var/mob/user) + if(!Adjacent(user)) + return 0 + var/success + if(istype(user, /mob/living/silicon/robot/drone)) + var/mob/living/silicon/robot/drone/D = user + if(D.hat) + success = 2 + else + D.wear_hat(src) + success = 1 + if(!success) + return 0 + else if(success == 2) + to_chat(user, "You are already wearing a hat.") + else if(success == 1) + to_chat(user, "You crawl under \the [src].") + return 1 + +/obj/item/clothing/head/update_icon(var/mob/user) + + overlays.Cut() + var/mob/living/carbon/human/H + if(istype(user,/mob/living/carbon/human)) + H = user + + if(on) + + // Generate object icon. + if(!light_overlay_cache["[light_overlay]_icon"]) + light_overlay_cache["[light_overlay]_icon"] = image("icon" = 'icons/obj/light_overlays.dmi', "icon_state" = "[light_overlay]") + overlays |= light_overlay_cache["[light_overlay]_icon"] + + // Generate and cache the on-mob icon, which is used in update_inv_head(). + var/cache_key = "[light_overlay][H ? "_[H.species.get_bodytype(H)]" : ""]" + if(!light_overlay_cache[cache_key]) + var/use_icon = 'icons/mob/light_overlays.dmi' + if(H && sprite_sheets && sprite_sheets[H.species.get_bodytype(H)]) + use_icon = sprite_sheets[H.species.get_bodytype(H)] + light_overlay_cache[cache_key] = image("icon" = use_icon, "icon_state" = "[light_overlay]") + + if(H) + H.update_inv_head() + +/obj/item/clothing/head/update_clothing_icon() + if (ismob(src.loc)) + var/mob/M = src.loc + M.update_inv_head() + +/////////////////////////////////////////////////////////////////////// +//Mask +/obj/item/clothing/mask + name = "mask" + icon = 'icons/obj/clothing/masks.dmi' + slot_flags = SLOT_MASK + body_parts_covered = FACE|EYES + var/voicechange = 0 + var/list/say_messages + var/list/say_verbs + var/down_gas_transfer_coefficient = 0 + var/down_body_parts_covered = 0 + var/down_icon_state = 0 + var/down_item_flags = 0 + var/down_flags_inv = 0 + var/pull_mask = 0 + var/hanging = 0 + blood_overlay_type = "maskblood" + +/obj/item/clothing/mask/New() + if(pull_mask) + action_button_name = "Adjust Mask" + verbs += /obj/item/clothing/mask/proc/adjust_mask + ..() + +/obj/item/clothing/mask/update_clothing_icon() + if (ismob(src.loc)) + var/mob/M = src.loc + M.update_inv_wear_mask() + +/obj/item/clothing/mask/proc/filter_air(datum/gas_mixture/air) + return + +/obj/item/clothing/mask/proc/adjust_mask(var/mob/user) + set category = "Object" + set name = "Adjust mask" + set src in usr + + if(!user.incapacitated()) + if(!pull_mask) + to_chat(usr, "You cannot pull down your [src.name].") + return + else + src.hanging = !src.hanging + if (src.hanging) + gas_transfer_coefficient = down_gas_transfer_coefficient + body_parts_covered = down_body_parts_covered + icon_state = down_icon_state + item_state = down_icon_state + item_flags = down_item_flags + flags_inv = down_flags_inv + to_chat(usr, "You pull [src] below your chin.") + else + gas_transfer_coefficient = initial(gas_transfer_coefficient) + body_parts_covered = initial(body_parts_covered) + icon_state = initial(icon_state) + item_state = initial(icon_state) + item_flags = initial(item_flags) + flags_inv = initial(flags_inv) + to_chat(usr, "You pull [src] up to cover your face.") + update_clothing_icon() + user.update_action_buttons() + +/obj/item/clothing/mask/attack_self(mob/user) + if(pull_mask) + adjust_mask(user) + +/////////////////////////////////////////////////////////////////////// +//Shoes +/obj/item/clothing/shoes + name = "shoes" + icon = 'icons/obj/clothing/shoes.dmi' + desc = "Comfortable-looking shoes." + gender = PLURAL //Carn: for grammarically correct text-parsing + siemens_coefficient = 0.9 + body_parts_covered = FEET + slot_flags = SLOT_FEET + + var/can_hold_knife + var/obj/item/holding + + permeability_coefficient = 0.50 + force = 2 + var/overshoes = 0 + blood_overlay_type = "shoeblood" + +/obj/item/clothing/shoes/proc/draw_knife() + set name = "Draw Boot Knife" + set desc = "Pull out your boot knife." + set category = "IC" + set src in usr + + if(usr.stat || usr.restrained() || usr.incapacitated()) + return + + holding.forceMove(get_turf(usr)) + + if(usr.put_in_hands(holding)) + usr.visible_message("\The [usr] pulls \the [holding] out of \the [src]!", range = 1) + holding = null + else + to_chat(usr, "Your need an empty, unbroken hand to do that.") + holding.forceMove(src) + + if(!holding) + verbs -= /obj/item/clothing/shoes/proc/draw_knife + + update_icon() + return + +/obj/item/clothing/shoes/attack_hand(var/mob/living/M) + if(can_hold_knife && holding && src.loc == M) + draw_knife() + return + ..() + +/obj/item/clothing/shoes/attackby(var/obj/item/I, var/mob/user) + if(can_hold_knife && is_type_in_list(I, list(/obj/item/weapon/material/shard, /obj/item/weapon/material/butterfly, /obj/item/weapon/material/kitchen/utensil, /obj/item/weapon/material/hatchet/tacknife))) + if(holding) + to_chat(user, "\The [src] is already holding \a [holding].") + return + user.unEquip(I) + I.forceMove(src) + holding = I + user.visible_message("\The [user] shoves \the [I] into \the [src].", range = 1) + verbs |= /obj/item/clothing/shoes/proc/draw_knife + update_icon() + else + return ..() + +/obj/item/clothing/shoes/update_icon() + overlays.Cut() + if(holding) + overlays += image(icon, "[icon_state]_knife") + return ..() + +/obj/item/clothing/shoes/proc/handle_movement(var/turf/walking, var/running) + return + +/obj/item/clothing/shoes/update_clothing_icon() + if (ismob(src.loc)) + var/mob/M = src.loc + M.update_inv_shoes() + +/////////////////////////////////////////////////////////////////////// +//Suit +/obj/item/clothing/suit + icon = 'icons/obj/clothing/suits.dmi' + name = "suit" + var/fire_resist = T0C+100 + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS|LEGS + allowed = list(/obj/item/weapon/tank/emergency) + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + slot_flags = SLOT_OCLOTHING + blood_overlay_type = "suit" + siemens_coefficient = 0.9 + w_class = ITEM_SIZE_NORMAL + valid_accessory_slots = list(ACCESSORY_SLOT_ARMBAND,ACCESSORY_SLOT_DECOR,ACCESSORY_SLOT_MEDAL) + grab_sound = 'sound/items/handle/clothing_up.ogg' + equipsound = 'sound/items/handle/cloth_pickup.ogg' + + +/obj/item/clothing/suit/update_clothing_icon() + if (ismob(src.loc)) + var/mob/M = src.loc + M.update_inv_wear_suit() + +/obj/item/clothing/suit/get_mob_overlay(mob/user_mob, slot) + var/image/ret = ..() + if(item_state_slots && item_state_slots[slot]) + ret.icon_state = item_state_slots[slot] + else + ret.icon_state = icon_state + return ret + +/obj/item/clothing/suit/proc/get_collar() + var/icon/C = new('icons/mob/collar.dmi') + if(icon_state in C.IconStates()) + var/image/I = image(C, icon_state) + I.color = color + return I +/////////////////////////////////////////////////////////////////////// +//Under clothing +/obj/item/clothing/under + icon = 'icons/obj/clothing/uniforms.dmi' + item_icons = list( + slot_l_hand_str = 'icons/mob/onmob/items/lefthand_uniforms.dmi', + slot_r_hand_str = 'icons/mob/onmob/items/righthand_uniforms.dmi', + ) + name = "under" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + permeability_coefficient = 0.90 + slot_flags = SLOT_ICLOTHING + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + w_class = ITEM_SIZE_NORMAL + force = 0 + var/has_sensor = SUIT_HAS_SENSORS //For the crew computer 2 = unable to change mode + var/sensor_mode = 0 + /* + 1 = Report living/dead + 2 = Report detailed damages + 3 = Report location + */ + var/displays_id = TRUE + var/rolled_down = -1 //0 = unrolled, 1 = rolled, -1 = cannot be toggled + var/rolled_sleeves = -1 //0 = unrolled, 1 = rolled, -1 = cannot be toggled + //convenience var for defining the icon state for the overlay used when the clothing is worn. + //Also used by rolling/unrolling. + var/worn_state = null + valid_accessory_slots = list(ACCESSORY_SLOT_UTILITY,ACCESSORY_SLOT_HOLSTER,ACCESSORY_SLOT_ARMBAND,ACCESSORY_SLOT_RANK,ACCESSORY_SLOT_DEPT,ACCESSORY_SLOT_DECOR,ACCESSORY_SLOT_MEDAL,ACCESSORY_SLOT_INSIGNIA) + restricted_accessory_slots = list(ACCESSORY_SLOT_UTILITY,ACCESSORY_SLOT_HOLSTER,ACCESSORY_SLOT_ARMBAND,ACCESSORY_SLOT_RANK,ACCESSORY_SLOT_DEPT) + grab_sound = 'sound/items/handle/clothing_up.ogg' + equipsound = 'sound/items/equip/jumpsuit_equip.ogg' + +/obj/item/clothing/under/New() + ..() + update_rolldown_status() + update_rollsleeves_status() + if(rolled_down == -1) + verbs -= /obj/item/clothing/under/verb/rollsuit + if(rolled_sleeves == -1) + verbs -= /obj/item/clothing/under/verb/rollsleeves + +/obj/item/clothing/under/get_icon_state(mob/user_mob, slot) + var/ret + if(item_state_slots && item_state_slots[slot]) + ret = item_state_slots[slot] + else + ret = icon_state + return "[ret]_s" + +/obj/item/clothing/under/attack_hand(var/mob/user) + if(accessories && accessories.len) + ..() + if ((ishuman(usr) || issmall(usr)) && src.loc == user) + return + ..() + +/obj/item/clothing/under/New() + ..() + if(worn_state) + if(!item_state_slots) + item_state_slots = list() + item_state_slots[slot_w_uniform_str] = worn_state + else + worn_state = icon_state + + //autodetect rollability + if(rolled_down < 0) + if((worn_state + "_d_s") in icon_states(default_onmob_icons[slot_w_uniform_str])) + rolled_down = 0 + +/obj/item/clothing/under/proc/update_rolldown_status() + var/mob/living/carbon/human/H + if(istype(src.loc, /mob/living/carbon/human)) + H = src.loc + + + var/icon/under_icon + if(icon_override) + under_icon = icon_override + else if(H && sprite_sheets && sprite_sheets[H.species.get_bodytype(H)]) + under_icon = sprite_sheets[H.species.get_bodytype(H)] + else if(item_icons && item_icons[slot_w_uniform_str]) + under_icon = item_icons[slot_w_uniform_str] + else + under_icon = default_onmob_icons[slot_w_uniform_str] + + // The _s is because the icon update procs append it. + if(("[worn_state]_d_s") in icon_states(under_icon)) + if(rolled_down != 1) + rolled_down = 0 + else + rolled_down = -1 + if(H) update_clothing_icon() + +/obj/item/clothing/under/proc/update_rollsleeves_status() + var/mob/living/carbon/human/H + if(istype(src.loc, /mob/living/carbon/human)) + H = src.loc + + var/icon/under_icon + if(icon_override) + under_icon = icon_override + else if(H && sprite_sheets && sprite_sheets[H.species.get_bodytype(H)]) + under_icon = sprite_sheets[H.species.get_bodytype(H)] + else if(item_icons && item_icons[slot_w_uniform_str]) + under_icon = item_icons[slot_w_uniform_str] + else + under_icon = default_onmob_icons[slot_w_uniform_str] + + // The _s is because the icon update procs append it. + if(("[worn_state]_r_s") in icon_states(under_icon)) + if(rolled_sleeves != 1) + rolled_sleeves = 0 + else + rolled_sleeves = -1 + if(H) update_clothing_icon() + +/obj/item/clothing/under/update_clothing_icon() + if (ismob(src.loc)) + var/mob/M = src.loc + M.update_inv_w_uniform(0) + M.update_inv_wear_id() + +/* +/obj/item/clothing/under/examine(mob/user) + . = ..(user) + switch(src.sensor_mode) + if(0) + to_chat(user, "Its sensors appear to be disabled.") + if(1) + to_chat(user, "Its binary life sensors appear to be enabled.") + if(2) + to_chat(user, "Its vital tracker appears to be enabled.") + if(3) + to_chat(user, "Its vital tracker and tracking beacon appear to be enabled.") +*/ + +/obj/item/clothing/under/proc/set_sensors(mob/user as mob) + var/mob/M = user + if (isobserver(M)) return + if (user.incapacitated()) return + if(has_sensor >= SUIT_LOCKED_SENSORS) + to_chat(user, "The controls are locked.") + return 0 + if(has_sensor <= SUIT_NO_SENSORS) + to_chat(user, "This suit does not have any sensors.") + return 0 + + var/list/modes = list("Off", "Binary sensors", "Vitals tracker", "Tracking beacon") + var/switchMode = input("Select a sensor mode:", "Suit Sensor Mode", modes[sensor_mode + 1]) in modes + if(get_dist(user, src) > 1) + to_chat(user, "You have moved too far away.") + return + sensor_mode = modes.Find(switchMode) - 1 + + if (src.loc == user) + switch(sensor_mode) + if(0) + user.visible_message("[user] adjusts the tracking sensor on \his [src.name].", "You disable your suit's remote sensing equipment.") + if(1) + user.visible_message("[user] adjusts the tracking sensor on \his [src.name].", "Your suit will now report whether you are live or dead.") + if(2) + user.visible_message("[user] adjusts the tracking sensor on \his [src.name].", "Your suit will now report your vital lifesigns.") + if(3) + user.visible_message("[user] adjusts the tracking sensor on \his [src.name].", "Your suit will now report your vital lifesigns as well as your coordinate position.") + + else if (ismob(src.loc)) + if(sensor_mode == 0) + user.visible_message("[user] disables [src.loc]'s remote sensing equipment.", "You disable [src.loc]'s remote sensing equipment.") + else + user.visible_message("[user] adjusts the tracking sensor on [src.loc]'s [src.name].", "You adjust [src.loc]'s sensors.") + else + user.visible_message("[user] adjusts the tracking sensor on [src]", "You adjust the sensor on [src].") + +/obj/item/clothing/under/emp_act(var/severity) + ..() + var/new_mode + switch(severity) + if(1) + new_mode = pick(75;SUIT_SENSOR_OFF, 15;SUIT_SENSOR_BINARY, 10;SUIT_SENSOR_VITAL) + if(2) + new_mode = pick(50;SUIT_SENSOR_OFF, 25;SUIT_SENSOR_BINARY, 20;SUIT_SENSOR_VITAL, 5;SUIT_SENSOR_TRACKING) + else + new_mode = pick(25;SUIT_SENSOR_OFF, 35;SUIT_SENSOR_BINARY, 30;SUIT_SENSOR_VITAL, 10;SUIT_SENSOR_TRACKING) + + sensor_mode = new_mode + +/* +/obj/item/clothing/under/verb/toggle() + set name = "Toggle Suit Sensors" + set category = "Object" + set src in usr + set_sensors(usr) + ..() +*/ +/obj/item/clothing/under/verb/rollsuit() + set name = "Roll Down Jumpsuit" + set category = "Object" + set src in usr + if(!istype(usr, /mob/living)) return + if(usr.stat) return + + update_rolldown_status() + if(rolled_down == -1) + to_chat(usr, "You cannot roll down [src]!") + if((rolled_sleeves == 1) && !(rolled_down)) + rolled_sleeves = 0 + return + + rolled_down = !rolled_down + if(rolled_down) + body_parts_covered &= LOWER_TORSO|LEGS|FEET + item_state_slots[slot_w_uniform_str] = "[worn_state]_d" + else + body_parts_covered = initial(body_parts_covered) + item_state_slots[slot_w_uniform_str] = "[worn_state]" + update_clothing_icon() + +/obj/item/clothing/under/verb/rollsleeves() + set name = "Roll Up Sleeves" + set category = "Object" + set src in usr + if(!istype(usr, /mob/living)) return + if(usr.stat) return + + update_rollsleeves_status() + if(rolled_sleeves == -1) + to_chat(usr, "You cannot roll up your [src]'s sleeves!") + return + if(rolled_down == 1) + to_chat(usr, "You must roll up your [src] first!") + return + + rolled_sleeves = !rolled_sleeves + if(rolled_sleeves) + body_parts_covered &= ~(ARMS|HANDS) + item_state_slots[slot_w_uniform_str] = "[worn_state]_r" + to_chat(usr, "You roll up your [src]'s sleeves.") + else + body_parts_covered = initial(body_parts_covered) + item_state_slots[slot_w_uniform_str] = "[worn_state]" + to_chat(usr, "You roll down your [src]'s sleeves.") + update_clothing_icon() + +/obj/item/clothing/under/rank/New() + sensor_mode = pick(0,1,2,3) + ..() + +/////////////////////////////////////////////////////////////////////// +//Rings + +/obj/item/clothing/ring + name = "ring" + w_class = ITEM_SIZE_TINY + icon = 'icons/obj/clothing/rings.dmi' + slot_flags = SLOT_GLOVES + gender = NEUTER + species_restricted = list("exclude", SPECIES_NABBER, SPECIES_DIONA) + var/undergloves = 1 diff --git a/code/modules/clothing/clothing_accessories.dm b/code/modules/clothing/clothing_accessories.dm new file mode 100644 index 00000000..c8570cf7 --- /dev/null +++ b/code/modules/clothing/clothing_accessories.dm @@ -0,0 +1,114 @@ +/obj/item/clothing/proc/can_attach_accessory(obj/item/clothing/accessory/A) + if(valid_accessory_slots && istype(A) && (A.slot in valid_accessory_slots)) + .=1 + else + return 0 + if(accessories.len && restricted_accessory_slots && (A.slot in restricted_accessory_slots)) + for(var/obj/item/clothing/accessory/AC in accessories) + if (AC.slot == A.slot) + return 0 + +/obj/item/clothing/attackby(var/obj/item/I, var/mob/user) + if(istype(I, /obj/item/clothing/accessory)) + + if(!valid_accessory_slots || !valid_accessory_slots.len) + to_chat(usr, "You cannot attach accessories of any kind to \the [src].") + return + + var/obj/item/clothing/accessory/A = I + if(can_attach_accessory(A)) + user.drop_item() + attach_accessory(user, A) + return + else + to_chat(user, "You cannot attach more accessories of this type to [src].") + return + + if(accessories.len) + for(var/obj/item/clothing/accessory/A in accessories) + A.attackby(I, user) + return + + ..() + +/obj/item/clothing/attack_hand(var/mob/user) + //only forward to the attached accessory if the clothing is equipped (not in a storage) + if(accessories.len && src.loc == user) + for(var/obj/item/clothing/accessory/A in accessories) + A.attack_hand(user) + return + return ..() + +/obj/item/clothing/MouseDrop(var/obj/over_object) + if (!over_object || !(ishuman(usr) || issmall(usr))) + return + + //makes sure that the clothing is equipped so that we can't drag it into our hand from miles away. + if (!(src.loc == usr)) + return + + if (usr.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_KNOCKOUT)) + return + + if (!usr.unEquip(src)) + return + + switch(over_object.name) + if("r_hand") + usr.put_in_r_hand(src) + if("l_hand") + usr.put_in_l_hand(src) + src.add_fingerprint(usr) +/* +/obj/item/clothing/examine(var/mob/user) + . = ..(user) + for(var/obj/item/clothing/accessory/A in accessories) + to_chat(user, "\icon[A] \A [A] is attached to it.") +*/ +/obj/item/clothing/proc/update_accessory_slowdown() + slowdown_accessory = 0 + for(var/obj/item/clothing/accessory/A in accessories) + slowdown_accessory += A.slowdown + +/** + * Attach accessory A to src + * + * user is the user doing the attaching. Can be null, such as when attaching + * items on spawn + */ +/obj/item/clothing/proc/attach_accessory(mob/user, obj/item/clothing/accessory/A) + accessories += A + A.on_attached(src, user) + //src.verbs |= /obj/item/clothing/proc/removetie_verb + update_accessory_slowdown() + update_clothing_icon() + +/obj/item/clothing/proc/remove_accessory(mob/user, obj/item/clothing/accessory/A) + if(!(A in accessories)) + return + A.on_removed(user) + accessories -= A + update_accessory_slowdown() + update_clothing_icon() + +/obj/item/clothing/proc/removetie_verb() + set name = "Remove Accessory" + set category = "Object" + set src in usr + if(!istype(usr, /mob/living)) return + if(usr.stat) return + if(!accessories.len) return + var/obj/item/clothing/accessory/A + if(accessories.len > 1) + A = input("Select an accessory to remove from [src]") as null|anything in accessories + else + A = accessories[1] + src.remove_accessory(usr,A) + if(!accessories.len) + src.verbs -= /obj/item/clothing/proc/removetie_verb + +/obj/item/clothing/emp_act(severity) + if(accessories.len) + for(var/obj/item/clothing/accessory/A in accessories) + A.emp_act(severity) + ..() \ No newline at end of file diff --git a/code/modules/clothing/ears/earrings.dm b/code/modules/clothing/ears/earrings.dm new file mode 100644 index 00000000..dde8b076 --- /dev/null +++ b/code/modules/clothing/ears/earrings.dm @@ -0,0 +1,80 @@ +//Material earrings +/obj/item/clothing/ears/earring + name = "earring" + desc = "An earring of some kind." + icon = 'icons/obj/clothing/ears.dmi' + gender = PLURAL + species_restricted = list(SPECIES_HUMAN) + +/obj/item/clothing/ears/earring/stud + name = "pearl stud earrings" + desc = "A pair of small stud earrings." + icon_state = "ear_stud" + color = "#eae0c8" + +/obj/item/clothing/ears/earring/stud/glass + name = "glass stud earrings" + color = "#00e1ff" + +/obj/item/clothing/ears/earring/stud/wood + name = "wood stud earrings" + color = "#824b28" + +/obj/item/clothing/ears/earring/stud/iron + name = "iron stud earrings" + color = "#5c5454" + +/obj/item/clothing/ears/earring/stud/steel + name = "steel stud earrings" + color = "#666666" + +/obj/item/clothing/ears/earring/stud/silver + name = "silver stud earrings" + color = "#d1e6e3" + +/obj/item/clothing/ears/earring/stud/gold + name = "gold stud earrings" + color = "#edd12f" + +/obj/item/clothing/ears/earring/stud/platinum + name = "platinum stud earrings" + color = "#9999ff" + +/obj/item/clothing/ears/earring/stud/diamond + name = "diamond stud earrings" + color = "#00ffe1" + +/obj/item/clothing/ears/earring/dangle + icon_state = "ear_dangle" + +/obj/item/clothing/ears/earring/dangle/glass + name = "glass dangle earrings" + color = "#00e1ff" + +/obj/item/clothing/ears/earring/dangle/wood + name = "wood dangle earrings" + color = "#824b28" + +/obj/item/clothing/ears/earring/dangle/iron + name = "iron dangle earrings" + color = "#5c5454" + +/obj/item/clothing/ears/earring/dangle/steel + name = "steel dangle earrings" + color = "#666666" + +/obj/item/clothing/ears/earring/dangle/silver + name = "silver dangle earrings" + color = "#d1e6e3" + +/obj/item/clothing/ears/earring/dangle/gold + name = "gold dangle earrings" + color = "#edd12f" + +/obj/item/clothing/ears/earring/dangle/platinum + name = "platinum dangle earrings" + color = "#9999ff" + +/obj/item/clothing/ears/earring/dangle/diamond + name = "diamond dangle earrings" + color = "#00ffe1" diff --git a/code/modules/clothing/ears/skrell.dm b/code/modules/clothing/ears/skrell.dm new file mode 100644 index 00000000..9450ff74 --- /dev/null +++ b/code/modules/clothing/ears/skrell.dm @@ -0,0 +1,122 @@ +/* + Skrell tentacle wear +*/ + +/obj/item/clothing/ears/skrell + name = "skrell headtail wear" + desc = "Some stuff worn by skrell to adorn their headtails." + icon = 'icons/obj/clothing/ears.dmi' + gender = PLURAL + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + species_restricted = list(SPECIES_SKRELL) + +/obj/item/clothing/ears/skrell/chain + name = "gold headtail chains" + desc = "A delicate golden chain worn by female skrell to decorate their head tails." + icon_state = "skrell_chain" + +/obj/item/clothing/ears/skrell/chain/silver + name = "silver headtail chains" + desc = "A delicate silver chain worn by female skrell to decorate their head tails." + icon_state = "skrell_chain_sil" + +/obj/item/clothing/ears/skrell/chain/bluejewels + name = "blue jeweled golden headtail chains" + desc = "A delicate golden chain adorned with blue jewels worn by female skrell to decorate their head tails." + icon_state = "skrell_chain_bjewel" + +/obj/item/clothing/ears/skrell/chain/redjewels + name = "red jeweled golden headtail chains" + desc = "A delicate golden chain adorned with red jewels worn by female skrell to decorate their head tails." + icon_state = "skrell_chain_rjewel" + +/obj/item/clothing/ears/skrell/chain/ebony + name = "ebony headtail chains" + desc = "A delicate ebony chain worn by female skrell to decorate their head tails." + icon_state = "skrell_chain_ebony" + +/obj/item/clothing/ears/skrell/band + name = "gold headtail bands" + desc = "Golden metallic bands worn by male skrell to adorn their head tails." + icon_state = "skrell_band" + +/obj/item/clothing/ears/skrell/band/silver + name = "silver headtail bands" + desc = "Silver metallic bands worn by male skrell to adorn their head tails." + icon_state = "skrell_band_sil" + +/obj/item/clothing/ears/skrell/band/bluejewels + name = "blue jeweled golden headtail bands" + desc = "Golden metallic bands adorned with blue jewels worn by male skrell to adorn their head tails." + icon_state = "skrell_band_bjewel" + +/obj/item/clothing/ears/skrell/band/redjewels + name = "red jeweled golden headtail bands" + desc = "Golden metallic bands adorned with red jewels worn by male skrell to adorn their head tails." + icon_state = "skrell_band_rjewel" + +/obj/item/clothing/ears/skrell/band/ebony + name = "ebony headtail bands" + desc = "Ebony bands worn by male skrell to adorn their head tails." + icon_state = "skrell_band_ebony" + +//Colourizable, for loadout +/obj/item/clothing/ears/skrell/colored/band + name = "colored headtail bands" + desc = "Metallic bands worn by male skrell to adorn their head tails." + icon_state = "skrell_band_sil" + +//Colourizable, for loadout +/obj/item/clothing/ears/skrell/colored/chain + name = "colored headtail chains" + desc = "A delicate chain worn by female skrell to decorate their head tails." + icon_state = "skrell_chain_sil" + +/obj/item/clothing/ears/skrell/cloth_female + name = "headtail cloth" + desc = "A cloth shawl worn by female skrell draped around their head tails." + icon_state = "skrell_cloth_female" + +//spawnable presets +/obj/item/clothing/ears/skrell/cloth_female/red + color = "#c20c00" + +/obj/item/clothing/ears/skrell/cloth_female/blue + color = "#0227f7" + +/obj/item/clothing/ears/skrell/cloth_female/lblue + color = "#6262ff" + +/obj/item/clothing/ears/skrell/cloth_female/black + color = "#454545" + +/obj/item/clothing/ears/skrell/cloth_female/green + color = "#009900" + +/obj/item/clothing/ears/skrell/cloth_female/pink + color = "#e17291" + +/obj/item/clothing/ears/skrell/cloth_male + name = "headtail cloth" + desc = "A cloth band worn by male skrell around their head tails." + icon_state = "skrell_cloth_male" + +//spawnable presets +/obj/item/clothing/ears/skrell/cloth_male/red + color = "#c20c00" + +/obj/item/clothing/ears/skrell/cloth_male/blue + color = "#0227f7" + +/obj/item/clothing/ears/skrell/cloth_male/lblue + color = "#6262ff" + +/obj/item/clothing/ears/skrell/cloth_male/black + color = "#454545" + +/obj/item/clothing/ears/skrell/cloth_male/green + color = "#009900" + +/obj/item/clothing/ears/skrell/cloth_male/pink + color = "#e17291" \ No newline at end of file diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm new file mode 100644 index 00000000..00156b01 --- /dev/null +++ b/code/modules/clothing/glasses/glasses.dm @@ -0,0 +1,498 @@ + +/obj/item/clothing/glasses + name = "glasses" + icon = 'icons/obj/clothing/glasses.dmi' + //w_class = ITEM_SIZE_SMALL + //slot_flags = SLOT_EYES + //var/vision_flags = 0 + //var/darkness_view = 0//Base human is 2 + var/prescription = 0 + var/toggleable = 0 + var/off_state = "degoggles" + 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 + var/electric = 0 //if the glasses should be disrupted by EMP + +/obj/item/clothing/glasses/New() + ..() + if(ispath(hud)) + hud = new hud(src) + +/obj/item/clothing/glasses/Destroy() + qdel(hud) + hud = null + . = ..() + +/obj/item/clothing/glasses/needs_vision_update() + return ..() || overlay || vision_flags || see_invisible || darkness_view + +/obj/item/clothing/glasses/emp_act(severity) + if(electric) + if(istype(src.loc, /mob/living/carbon/human)) + var/mob/living/carbon/human/M = src.loc + to_chat(M, "Your [name] malfunction[gender != PLURAL ? "s":""], blinding you!") + if(M.glasses == src) + M.eye_blind = 2 + M.eye_blurry = 4 + // Don't cure being nearsighted + if(!(M.disabilities & NEARSIGHTED)) + M.disabilities |= NEARSIGHTED + spawn(100) + M.disabilities &= ~NEARSIGHTED + if(toggleable) + if(active) + active = 0 + +/obj/item/clothing/glasses/attack_self(mob/user) + if(toggleable && !user.incapacitated()) + if(active) + active = 0 + icon_state = off_state + user.update_inv_glasses() + flash_protection = FLASH_PROTECTION_NONE + tint = TINT_NONE + to_chat(usr, "You deactivate the optical matrix on the [src].") + else + active = 1 + icon_state = initial(icon_state) + user.update_inv_glasses() + if(activation_sound) + sound_to(usr, activation_sound) + + flash_protection = initial(flash_protection) + tint = initial(tint) + to_chat(usr, "You activate the optical matrix on the [src].") + user.update_action_buttons() + +/obj/item/clothing/glasses/meson + name = "optical meson scanner" + desc = "Used for seeing walls, floors, and stuff through anything." + gender = NEUTER + icon_state = "meson" + item_state = "glasses" + action_button_name = "Toggle Goggles" + origin_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 2) + toggleable = 1 + vision_flags = SEE_TURFS + see_invisible = SEE_INVISIBLE_NOLIGHTING + electric = 1 + +/obj/item/clothing/glasses/meson/New() + ..() + overlay = GLOB.global_hud.meson + +/obj/item/clothing/glasses/meson/prescription + name = "prescription mesons" + desc = "Optical Meson Scanner with prescription lenses." + prescription = 6 + +/obj/item/clothing/glasses/science + name = "science goggles" + desc = "The goggles do nothing!" + icon_state = "purple" + item_state = "glasses" + action_button_name = "Toggle Goggles" + toggleable = 1 + electric = 1 + +/obj/item/clothing/glasses/science/New() + ..() + overlay = GLOB.global_hud.science + +/obj/item/clothing/glasses/night + name = "night vision goggles" + desc = "You can totally see in the dark now!" + icon_state = "night" + item_state = "glasses" + origin_tech = list(TECH_MAGNET = 2) + darkness_view = 7 + action_button_name = "Toggle Goggles" + toggleable = 1 + see_invisible = SEE_INVISIBLE_NOLIGHTING + off_state = "denight" + electric = 1 + +/obj/item/clothing/glasses/night/New() + ..() + overlay = GLOB.global_hud.nvg + +/obj/item/clothing/glasses/tacgoggles + name = "tactical goggles" + desc = "Self-polarizing goggles with light amplification for dark environments. Made from durable synthetic." + icon_state = "swatgoggles" + origin_tech = list(TECH_MAGNET = 2, TECH_COMBAT = 4) + darkness_view = 5 + action_button_name = "Toggle Goggles" + toggleable = 1 + see_invisible = SEE_INVISIBLE_NOLIGHTING + armor = list(melee = 20, bullet = 20, laser = 20, energy = 15, bomb = 20, bio = 0, rad = 0) + siemens_coefficient = 0.6 + electric = 1 + +/obj/item/clothing/glasses/eyepatch + name = "eyepatch" + desc = "Yarr." + icon_state = "eyepatch" + item_state = "eyepatch" + body_parts_covered = 0 + var/flipped = 0 // Indicates left or right eye; 0 = on the right + +/obj/item/clothing/glasses/eyepatch/proc/flip_patch() + set name = "Flip Patch" + set category = "Object" + + if (usr.stat || usr.restrained()) + return + + src.flipped = !src.flipped + if(src.flipped) + icon_state = "[icon_state]_r" + else + src.icon_state = initial(icon_state) + to_chat (usr, "You change \the [src] to cover the [src.flipped ? "left" : "right"] eye.") + update_clothing_icon() + +/obj/item/clothing/glasses/eyepatch/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + if(src == user.get_active_hand()) + flip_patch() + +/obj/item/clothing/glasses/monocle + name = "monocle" + desc = "Such a dapper eyepiece!" + icon_state = "monocle" + item_state = "headset" // lol + body_parts_covered = 0 + +/obj/item/clothing/glasses/material + name = "optical material scanner" + desc = "Very confusing glasses." + gender = NEUTER + icon_state = "material" + item_state = "glasses" + origin_tech = list(TECH_MAGNET = 3, TECH_ENGINEERING = 3) + action_button_name = "Toggle Goggles" + toggleable = 1 + vision_flags = SEE_OBJS + electric = 1 + +/obj/item/clothing/glasses/regular + name = "prescription glasses" + desc = "Made by Nerd. Co." + icon_state = "glasses" + item_state = "glasses" + prescription = 7 + 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." + icon_state = "uzenwa_sissra_1" + light_protection = 7 + electric = 1 + +/obj/item/clothing/glasses/regular/hipster + name = "prescription glasses" + desc = "Made by Uncool. Co." + icon_state = "hipster_glasses" + item_state = "hipster_glasses" + +/obj/item/clothing/glasses/threedglasses + name = "3D glasses" + desc = "A long time ago, people used these glasses to makes images from screens threedimensional." + icon_state = "3d" + item_state = "3d" + body_parts_covered = 0 + +/obj/item/clothing/glasses/gglasses + name = "green glasses" + desc = "Forest green glasses, like the kind you'd wear when hatching a nasty scheme." + icon_state = "gglasses" + item_state = "gglasses" + body_parts_covered = 0 + +/obj/item/clothing/glasses/sunglasses + name = "trench aviators" + desc = "The sun seems to have gone out but that's not gonna stop you from looking cool." + icon_state = "sun" + item_state = "sunglasses" + darkness_view = -1 + flash_protection = FLASH_PROTECTION_MODERATE + +/obj/item/clothing/glasses/welding + name = "welding goggles" + desc = "Protects the eyes from welders, approved by the mad scientist association." + icon_state = "welding-g" + item_state = "welding-g" + action_button_name = "Flip Welding Goggles" + matter = list(DEFAULT_WALL_MATERIAL = 1500, "glass" = 1000) + use_alt_layer = TRUE + var/up = 0 + flash_protection = FLASH_PROTECTION_MAJOR + tint = TINT_HEAVY + +/obj/item/clothing/glasses/welding/attack_self() + toggle() + + +/obj/item/clothing/glasses/welding/proc/toggle() + set category = "Object" + set name = "Adjust welding goggles" + + if(usr.canmove && !usr.incapacitated()) + if(src.up) + src.up = !src.up + flags_inv |= HIDEEYES + body_parts_covered |= EYES + icon_state = initial(icon_state) + flash_protection = initial(flash_protection) + tint = initial(tint) + to_chat(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 + to_chat(usr, "You push \the [src] up out of your face.") + update_clothing_icon() + update_vision() + usr.update_action_buttons() + +/obj/item/clothing/glasses/welding/RightClick(mob/user) + if(CanPhysicallyInteract(user)) + if(src == user.get_active_hand()) + toggle() + +/obj/item/clothing/glasses/welding/superior + name = "superior welding goggles" + 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 + flash_protection = FLASH_PROTECTION_MAJOR + +/obj/item/clothing/glasses/sunglasses/blindfold/tape + name = "length of tape" + desc = "It's a robust DIY blindfold!" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "tape_cross" + item_state = null + w_class = ITEM_SIZE_TINY + +/obj/item/clothing/glasses/sunglasses/prescription + name = "prescription sunglasses" + prescription = 5 + +/obj/item/clothing/glasses/sunglasses/big + desc = "Strangely ancient technology used to help provide rudimentary eye cover. Larger than average enhanced shielding blocks many flashes." + icon_state = "bigsunglasses" + item_state = "bigsunglasses" + +/obj/item/clothing/glasses/sunglasses/sechud + name = "HUD sunglasses" + desc = "Sunglasses with a HUD." + icon_state = "sunhud" + hud = /obj/item/clothing/glasses/hud/security + electric = 1 + +/obj/item/clothing/glasses/sunglasses/sechud/goggles //now just a more "military" set of HUDglasses for the Torch + name = "HUD goggles" + desc = "Flash-resistant goggles with an inbuilt heads-up display." + icon_state = "goggles" + +/obj/item/clothing/glasses/sunglasses/sechud/toggle + name = "HUD aviators" + desc = "Modified aviator glasses that can be switched between HUD and flash protection modes." + icon_state = "sec_hud" + off_state = "sec_flash" + action_button_name = "Toggle Mode" + var/on = 1 + toggleable = 1 + activation_sound = 'sound/effects/pop.ogg' + + var/hud_holder + +/obj/item/clothing/glasses/sunglasses/sechud/toggle/New() + ..() + hud_holder = hud + +/obj/item/clothing/glasses/sunglasses/sechud/toggle/Destroy() + qdel(hud_holder) + hud_holder = null + hud = null + . = ..() + +/obj/item/clothing/glasses/sunglasses/sechud/toggle/attack_self(mob/user) + if(toggleable && !user.incapacitated()) + on = !on + if(on) + flash_protection = FLASH_PROTECTION_NONE + src.hud = hud_holder + to_chat(user, "You switch \the [src] to HUD mode.") + else + flash_protection = initial(flash_protection) + src.hud = null + to_chat(user, "You switch \the [src] to flash protection mode.") + update_icon() + sound_to(user, activation_sound) + user.update_inv_glasses() + user.update_action_buttons() + +/obj/item/clothing/glasses/sunglasses/sechud/toggle/update_icon() + if(on) + icon_state = initial(icon_state) + else + icon_state = off_state + +/obj/item/clothing/glasses/thermal + name = "optical thermal scanner" + desc = "Thermals in the shape of glasses." + gender = NEUTER + icon_state = "thermal" + item_state = "glasses" + action_button_name = "Toggle Goggles" + origin_tech = list(TECH_MAGNET = 3) + toggleable = 1 + vision_flags = SEE_MOBS + see_invisible = SEE_INVISIBLE_NOLIGHTING + electric = 1 + +/obj/item/clothing/glasses/thermal/New() + ..() + overlay = GLOB.global_hud.thermal + +/obj/item/clothing/glasses/thermal/syndi //These are now a traitor item, concealed as mesons. -Pete + name = "optical meson scanner" + desc = "Used for seeing walls, floors, and stuff through anything." + icon_state = "meson" + origin_tech = list(TECH_MAGNET = 3, TECH_ILLEGAL = 4) + +/obj/item/clothing/glasses/thermal/plain + toggleable = 0 + activation_sound = null + action_button_name = null + +/obj/item/clothing/glasses/thermal/plain/monocle + name = "thermoncle" + desc = "A monocle thermal." + icon_state = "thermoncle" + body_parts_covered = 0 //doesn't protect eyes because it's a monocle, duh + +/obj/item/clothing/glasses/thermal/plain/eyepatch + name = "optical thermal eyepatch" + desc = "An eyepatch with built-in thermal optics." + icon_state = "eyepatch" + item_state = "eyepatch" + body_parts_covered = 0 + +/obj/item/clothing/glasses/thermal/plain/jensen + name = "optical thermal implants" + gender = PLURAL + desc = "A set of implantable lenses designed to augment your vision." + icon_state = "thermalimplants" + item_state = "syringe_kit" + +/obj/item/clothing/glasses/eyepatch/hud + name = "iPatch" + desc = "For the technologically inclined pirate. It connects directly to the optical nerve of the user, replacing the need for that useless eyeball." + gender = NEUTER + icon_state = "hudpatch" + item_state = "hudpatch" + off_state = "hudpatch" + action_button_name = "Toggle iPatch" + toggleable = 1 + var/eye_color = COLOR_WHITE + electric = 1 + +/obj/item/clothing/glasses/eyepatch/hud/Initialize() + . = ..() + update_icon() + +/obj/item/clothing/glasses/eyepatch/hud/attack_self() + ..() + update_icon() + +/obj/item/clothing/glasses/eyepatch/hud/update_icon() + overlays.Cut() + if(active) + var/image/eye = overlay_image(icon, "[icon_state]_eye", flags=RESET_COLOR) + eye.color = eye_color + overlays += eye + +/obj/item/clothing/glasses/eyepatch/hud/get_mob_overlay(mob/user_mob, slot) + var/image/res = ..() + if(active) + var/image/eye = overlay_image(res.icon, "[icon_state]_eye", flags=RESET_COLOR) + eye.color = eye_color + eye.layer = ABOVE_LIGHTING_LAYER + eye.plane = EFFECTS_ABOVE_LIGHTING_PLANE + res.overlays += eye + return res + +/obj/item/clothing/glasses/eyepatch/hud/security + name = "HUDpatch" + desc = "A Security-type heads-up display that connects directly to the optical nerve of the user, replacing the need for that useless eyeball." + hud = /obj/item/clothing/glasses/hud/security + eye_color = COLOR_RED + +/obj/item/clothing/glasses/eyepatch/hud/medical + name = "MEDpatch" + desc = "A Medical-type heads-up display that connects directly to the ocular nerve of the user, replacing the need for that useless eyeball." + hud = /obj/item/clothing/glasses/hud/health + eye_color = COLOR_CYAN + +/obj/item/clothing/glasses/eyepatch/hud/meson + name = "MESpatch" + desc = "An optical meson scanner display that connects directly to the ocular nerve of the user, replacing the need for that useless eyeball." + vision_flags = SEE_TURFS + see_invisible = SEE_INVISIBLE_NOLIGHTING + eye_color = COLOR_LIME + +/obj/item/clothing/glasses/eyepatch/hud/meson/New() + ..() + overlay = GLOB.global_hud.meson + + +/*---Tajaran-specific Eyewear---*/ + +/obj/item/clothing/glasses/tajblind + name = "embroidered veil" + desc = "An Ahdominian made veil that allows the user to see while obscuring their eyes." + icon_state = "tajblind" + item_state = "tajblind" + prescription = 5 + body_parts_covered = EYES + +/obj/item/clothing/glasses/hud/health/tajblind + name = "lightweight veil" + desc = "An Ahdominian made veil that allows the user to see while obscuring their eyes. This one has an installed medical HUD." + icon_state = "tajblind_med" + item_state = "tajblind_med" + body_parts_covered = EYES + +/obj/item/clothing/glasses/sunglasses/sechud/tajblind + name = "sleek veil" + desc = "An Ahdominian made veil that allows the user to see while obscuring their eyes. This one has an in-built security HUD." + icon_state = "tajblind_sec" + item_state = "tajblind_sec" + prescription = 5 + body_parts_covered = EYES + +/obj/item/clothing/glasses/meson/prescription/tajblind + name = "industrial veil" + desc = "An Ahdominian made veil that allows the user to see while obscuring their eyes. This one has installed mesons." + icon_state = "tajblind_meson" + item_state = "tajblind_meson" + off_state = "tajblind_meson" + body_parts_covered = EYES diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm new file mode 100644 index 00000000..4b18d85e --- /dev/null +++ b/code/modules/clothing/glasses/hud.dm @@ -0,0 +1,62 @@ +/obj/item/clothing/glasses/hud + name = "HUD" + desc = "A heads-up display that provides important info in (almost) real time." + origin_tech = list(TECH_MAGNET = 3, TECH_BIO = 2) + var/list/icon/current = list() //the current hud icons + electric = 1 + gender = NEUTER + +/obj/item/clothing/glasses/proc/process_hud(var/mob/M) + if(hud) + hud.process_hud(M) + +/obj/item/clothing/glasses/hud/process_hud(var/mob/M) + return + +/obj/item/clothing/glasses/hud/health + name = "health scanner HUD" + desc = "A heads-up display that scans the humans in view and provides accurate data about their health status." + icon_state = "healthhud" + body_parts_covered = 0 + +/obj/item/clothing/glasses/hud/health/process_hud(var/mob/M) + process_med_hud(M, 1) + +/obj/item/clothing/glasses/hud/health/prescription + name = "prescription health scanner HUD" + desc = "A medical HUD integrated with a set of prescription glasses." + prescription = 7 + icon_state = "healthhudpresc" + item_state = "glasses" + +/obj/item/clothing/glasses/hud/health/visor + name = "medical HUD visor" + desc = "A medical HUD integrated with a wide visor." + icon_state = "medhud_visor" + item_state = "medhud_visor" + +/obj/item/clothing/glasses/hud/security + name = "security HUD" + desc = "A heads-up display that scans the humans in view and provides accurate data about their ID status and security records." + icon_state = "securityhud" + body_parts_covered = 0 + var/global/list/jobs[0] + +/obj/item/clothing/glasses/hud/security/prescription + name = "prescription security HUD" + desc = "A security HUD integrated with a set of prescription glasses" + prescription = 7 + icon_state = "sechudpresc" + item_state = "glasses" + +/obj/item/clothing/glasses/hud/security/jensenshades + name = "augmented shades" + desc = "Polarized bioneural eyewear, designed to augment your vision." + gender = PLURAL + icon_state = "jensenshades" + item_state = "jensenshades" + vision_flags = SEE_MOBS + see_invisible = SEE_INVISIBLE_NOLIGHTING + +/obj/item/clothing/glasses/hud/security/process_hud(var/mob/M) + process_sec_hud(M, 1) diff --git a/code/modules/clothing/gloves/boxing.dm b/code/modules/clothing/gloves/boxing.dm new file mode 100644 index 00000000..7c23bce1 --- /dev/null +++ b/code/modules/clothing/gloves/boxing.dm @@ -0,0 +1,29 @@ +/obj/item/clothing/gloves/boxing + name = "boxing gloves" + desc = "Because you really needed another excuse to punch your crewmates." + icon_state = "boxing" + item_state = "boxing" + +/obj/item/clothing/gloves/boxing/attackby(obj/item/weapon/W, mob/user) + if(isWirecutter(W) || istype(W, /obj/item/weapon/scalpel)) + to_chat(user, "That won't work.")//Nope + else + ..() + +/obj/item/clothing/gloves/boxing/green + icon_state = "boxinggreen" + item_state = "boxinggreen" + +/obj/item/clothing/gloves/boxing/blue + icon_state = "boxingblue" + item_state = "boxingblue" + +/obj/item/clothing/gloves/boxing/yellow + icon_state = "boxingyellow" + item_state = "boxingyellow" + +/obj/item/clothing/gloves/white + name = "white gloves" + desc = "These look pretty fancy." + icon_state = "latex" + item_state = "lgloves" diff --git a/code/modules/clothing/gloves/color.dm b/code/modules/clothing/gloves/color.dm new file mode 100644 index 00000000..e33ea20f --- /dev/null +++ b/code/modules/clothing/gloves/color.dm @@ -0,0 +1,33 @@ +/obj/item/clothing/gloves/color + desc = "A pair of gloves, they don't look special in any way." + item_state = "lgloves" + icon_state = "white" + +/obj/item/clothing/gloves/color/modified + item_flags = ITEM_FLAG_PREMODIFIED + +/obj/item/clothing/gloves/color/white + color = COLOR_WHITE + +/obj/item/clothing/gloves/color/white/modified + item_flags = ITEM_FLAG_PREMODIFIED + +/obj/item/clothing/gloves/color/evening + desc = "A pair of gloves that reach past the elbow. Fancy!" + name = "evening gloves" + icon_state = "evening_gloves" + item_state = "evening_gloves" + color = COLOR_WHITE //original colour was "#7f7f7f", but white is fancier of course + body_parts_covered = ARMS|HANDS //evening gloves don't quite cover the entire arm, but might as well differentiate the item a bit + +/obj/item/clothing/gloves/color/evening/modified + item_flags = ITEM_FLAG_PREMODIFIED + +/obj/item/clothing/gloves/rainbow + name = "rainbow gloves" + desc = "A pair of gloves, they don't look special in any way." + icon_state = "rainbow" + item_state = "rainbowgloves" + +/obj/item/clothing/gloves/rainbow/modified + item_flags = ITEM_FLAG_PREMODIFIED diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm new file mode 100644 index 00000000..5916bcd5 --- /dev/null +++ b/code/modules/clothing/gloves/miscellaneous.dm @@ -0,0 +1,144 @@ +/obj/item/clothing/gloves/captain + desc = "Regal blue gloves, with a nice gold trim. Swanky." + name = "captain's gloves" + icon_state = "captain" + item_state = "egloves" + +/obj/item/clothing/gloves/cyborg + desc = "Beep boop borp!" + name = "cyborg gloves" + icon_state = "black" + item_state = "r_hands" + siemens_coefficient = 1.0 + +/obj/item/clothing/gloves/insulated + desc = "These gloves will protect the wearer from electric shocks." + name = "insulated gloves" + color = COLOR_YELLOW + icon_state = "white" + item_state = "lgloves" + siemens_coefficient = 0 + permeability_coefficient = 0.05 + +/obj/item/clothing/gloves/insulated/cheap //Cheap Chinese Crap + desc = "These gloves are cheap copies of the coveted gloves, no way this can end badly." + name = "budget insulated gloves" + siemens_coefficient = 1 //Set to a default of 1, gets overridden in New() + +/obj/item/clothing/gloves/insulated/cheap/New() + ..() + //average of 0.4, better than regular gloves' 0.75 + siemens_coefficient = pick(0, 0.1, 0.2, 0.3, 0.4, 0.6, 1.3) + +/obj/item/clothing/gloves/forensic + desc = "Specially made gloves for forensic technicians. The luminescent threads woven into the material stand out under scrutiny." + name = "forensic gloves" + icon_state = "forensic" + item_state = "bgloves" + siemens_coefficient = 0.50 + permeability_coefficient = 0.05 + + cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE + heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE + +/obj/item/clothing/gloves/thick + desc = "These work gloves are thick and fire-resistant." + name = "work gloves" + icon_state = "black" + item_state = "bgloves" + siemens_coefficient = 0.50 + permeability_coefficient = 0.05 + + cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE + heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE + +/obj/item/clothing/gloves/thick/modified + item_flags = ITEM_FLAG_PREMODIFIED + +/obj/item/clothing/gloves/thick/swat + desc = "These tactical gloves are somewhat fire and impact-resistant." + name = "\improper SWAT Gloves" + item_state = "swat_gl" + force = 5 + armor = list(melee = 80, bullet = 60, laser = 60,energy = 25, bomb = 50, bio = 10, rad = 0) + +/obj/item/clothing/gloves/thick/combat //Combined effect of SWAT gloves and insulated gloves + desc = "These tactical gloves are somewhat fire and impact resistant." + name = "combat gloves" + icon_state = "work" + item_state = "wgloves" + siemens_coefficient = 0 + permeability_coefficient = 0.05 + force = 5 + armor = list(melee = 80, bullet = 60, laser = 60,energy = 25, bomb = 50, bio = 10, rad = 0) + cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE + heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE + +/obj/item/clothing/gloves/thick/botany + desc = "These leather work gloves protect against thorns, barbs, prickles, spikes and other harmful objects of floral origin." + name = "thick leather gloves" + icon_state = "leather" + item_state = "ggloves" + +/obj/item/clothing/gloves/thick/botany/modified + item_flags = ITEM_FLAG_PREMODIFIED + +/obj/item/clothing/gloves/latex + name = "latex gloves" + desc = "Sterile latex gloves." + icon_state = "latex" + item_state = "lgloves" + siemens_coefficient = 1.1 //thin latex gloves, much more conductive than fabric gloves (basically a capacitor for AC) + permeability_coefficient = 0.01 + germ_level = 0 + +/obj/item/clothing/gloves/latex/modified + item_flags = ITEM_FLAG_PREMODIFIED + +/obj/item/clothing/gloves/latex/nitrile + name = "nitrile gloves" + desc = "Sterile nitrile gloves" + icon_state = "nitrile" + item_state = "ngloves" + +/obj/item/clothing/gloves/latex/nitrile/modified + item_flags = ITEM_FLAG_PREMODIFIED + +/obj/item/clothing/gloves/duty + desc = "These brown duty gloves are made from a durable synthetic." + name = "work gloves" + icon_state = "work" + item_state = "wgloves" + siemens_coefficient = 0.50 + armor = list(melee = 10, bullet = 10, laser = 10, energy = 5, bomb = 0, bio = 0, rad = 0) + +/obj/item/clothing/gloves/duty/modified + item_flags = ITEM_FLAG_PREMODIFIED + +/obj/item/clothing/gloves/tactical + desc = "These brown tactical gloves are made from a durable synthetic, and have hardened knuckles." + name = "tactical gloves" + icon_state = "work" + item_state = "wgloves" + force = 5 + siemens_coefficient = 0.50 + permeability_coefficient = 0.05 + armor = list(melee = 30, bullet = 10, laser = 10, energy = 15, bomb = 20, bio = 0, rad = 0) + +/obj/item/clothing/gloves/guards + desc = "A pair of synthetic gloves and arm pads reinforced with armor plating." + name = "arm guards" + icon_state = "guards" + item_state = "guards" + body_parts_covered = HANDS|ARMS + w_class = ITEM_SIZE_NORMAL + siemens_coefficient = 0.7 + permeability_coefficient = 0.03 + armor = list(melee = 40, bullet = 40, laser = 40, energy = 25, bomb = 30, bio = 0, rad = 0) + diff --git a/code/modules/clothing/head/collectable.dm b/code/modules/clothing/head/collectable.dm new file mode 100644 index 00000000..e40d1a43 --- /dev/null +++ b/code/modules/clothing/head/collectable.dm @@ -0,0 +1,137 @@ + +//Hat Station 13 + +/obj/item/clothing/head/collectable + name = "collectable hat" + desc = "A rare collectable hat." + +/obj/item/clothing/head/collectable/petehat + name = "ultra rare hat" + desc = "an ultra rare hat. It commands a certain respect." + icon_state = "petehat" + +/obj/item/clothing/head/collectable/slime + name = "collectable slime cap!" + desc = "It just latches right in place!" + icon_state = "slime" + body_parts_covered = 0 + +/obj/item/clothing/head/collectable/xenom + name = "collectable alien monster helmet!" + desc = "Hiss hiss hiss!" + icon_state = "xenom" + item_state_slots = list( + slot_l_hand_str = "xenos_helm", + slot_r_hand_str = "xenos_helm", + ) + body_parts_covered = HEAD|FACE|EYES + +/obj/item/clothing/head/collectable/chef + name = "collectable chef's hat" + desc = "A rare Chef's Hat meant for hat collectors!" + icon_state = "chefhat" + item_state = "chefhat" + +/obj/item/clothing/head/collectable/paper + name = "collectable paper hat" + desc = "What looks like an ordinary paper hat, is actually a rare and valuable collector's edition paper hat. Keep away from water, fire and Librarians." + icon_state = "paper" + item_state = "paper" + body_parts_covered = 0 + +/obj/item/clothing/head/collectable/tophat + name = "collectable top hat" + desc = "A top hat worn by only the most prestigious hat collectors." + icon_state = "tophat" + item_state = "tophat" + body_parts_covered = 0 + +/obj/item/clothing/head/collectable/captain + name = "collectable captain's hat" + desc = "A Collectable Hat that'll make you look just like a real comdom!" + icon_state = "captain" + item_state_slots = list( + slot_l_hand_str = "caphat", + slot_r_hand_str = "caphat", + ) + body_parts_covered = 0 + +/obj/item/clothing/head/collectable/police + name = "collectable police officer's hat" + desc = "A Collectable Police Officer's Hat. This hat emphasizes that you are THE LAW." + icon_state = "policehelm" + body_parts_covered = 0 + +/obj/item/clothing/head/collectable/beret + name = "collectable beret" + desc = "A Collectable red Beret. It smells faintly of Garlic." + icon_state = "beret" + body_parts_covered = 0 + +/obj/item/clothing/head/collectable/welding + name = "collectable welding helmet" + desc = "A Collectable Welding Helmet. Now with 80% less lead! Not for actual welding. Any welding done while wearing this Helmet is done so at the owner's own risk!" + icon_state = "welding" + item_state = "welding" + w_class = ITEM_SIZE_NORMAL + body_parts_covered = HEAD|FACE|EYES + +/obj/item/clothing/head/collectable/slime + name = "collectable slime hat" + desc = "Just like a real Brain Slug!" + icon_state = "headslime" + +/obj/item/clothing/head/collectable/flatcap + name = "collectable flat cap" + desc = "A Collectible farmer's Flat Cap!" + icon_state = "flat_cap" + item_state_slots = list( + slot_l_hand_str = "detective", + slot_r_hand_str = "detective", + ) + +/obj/item/clothing/head/collectable/pirate + name = "collectable pirate hat" + desc = "You'd make a great Dread Syndie Roberts!" + icon_state = "pirate" + body_parts_covered = 0 + +/obj/item/clothing/head/collectable/kitty + name = "collectable kitty ears" + desc = "The fur feels.....a bit too realistic." + icon_state = "kitty" + body_parts_covered = 0 + +/obj/item/clothing/head/collectable/rabbitears + name = "collectable rabbit ears" + desc = "Not as lucky as the feet!" + icon_state = "bunny" + body_parts_covered = 0 + +/obj/item/clothing/head/collectable/wizard + name = "collectable wizard's hat" + desc = "NOTE:Any magical powers gained from wearing this hat are purely coincidental." + icon_state = "wizard" + +/obj/item/clothing/head/collectable/hardhat + name = "collectable hard hat" + desc = "WARNING! Offers no real protection, or luminosity, but it is damn fancy!" + icon_state = "hardhat0_yellow" + w_class = ITEM_SIZE_NORMAL + body_parts_covered = 0 + +/obj/item/clothing/head/collectable/HoS + name = "collectable HoS hat" + desc = "Now you can beat prisoners, set silly sentences and arrest for no reason too!" + icon_state = "hoscap" + body_parts_covered = 0 + +/obj/item/clothing/head/collectable/thunderdome + name = "collectable Thunderdome helmet" + desc = "Go Red! I mean Green! I mean Red! No Green!" + icon_state = "thunderdome" + +/obj/item/clothing/head/collectable/swat + name = "collectable SWAT helmet" + desc = "Now you can be in the Deathsquad too!" + icon_state = "swat" diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm new file mode 100644 index 00000000..8bc54f28 --- /dev/null +++ b/code/modules/clothing/head/hardhat.dm @@ -0,0 +1,26 @@ +/obj/item/clothing/head/hardhat + name = "hard hat" + desc = "A piece of headgear used in dangerous working conditions to protect the head. Comes with a built-in flashlight." + icon_state = "hardhat0_yellow" + action_button_name = "Toggle Headlamp" + brightness_on = 4 //luminosity when on + light_overlay = "hardhat_light" + w_class = ITEM_SIZE_NORMAL + armor = list(melee = 30, bullet = 5, laser = 20,energy = 10, bomb = 20, bio = 10, rad = 20) + flags_inv = 0 + siemens_coefficient = 0.9 + heat_protection = HEAD + max_heat_protection_temperature = FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE + +/obj/item/clothing/head/hardhat/orange + icon_state = "hardhat0_orange" + +/obj/item/clothing/head/hardhat/red + icon_state = "hardhat0_red" + name = "firefighter helmet" + +/obj/item/clothing/head/hardhat/white + icon_state = "hardhat0_white" + +/obj/item/clothing/head/hardhat/dblue + icon_state = "hardhat0_dblue" diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm new file mode 100644 index 00000000..56e871a2 --- /dev/null +++ b/code/modules/clothing/head/helmet.dm @@ -0,0 +1,201 @@ +/obj/item/clothing/head/helmet + name = "helmet" + desc = "Reinforced headgear. Protects the head from impacts." + icon_state = "helmet" + drop_sound = 'sound/items/helm_drop.ogg' + item_state_slots = list( + slot_l_hand_str = "helmet", + slot_r_hand_str = "helmet", + ) + valid_accessory_slots = list(ACCESSORY_SLOT_HELM_C) + //restricted_accessory_slots = list(ACCESSORY_SLOT_HELM_C) + item_flags = ITEM_FLAG_THICKMATERIAL + body_parts_covered = HEAD + armor = list(melee = 50, bullet = 50, laser = 50,energy = 25, bomb = 30, bio = 0, rad = 0) + flags_inv = HIDEEARS|BLOCKHEADHAIR + cold_protection = HEAD + min_cold_protection_temperature = HELMET_MIN_COLD_PROTECTION_TEMPERATURE + heat_protection = HEAD + max_heat_protection_temperature = HELMET_MAX_HEAT_PROTECTION_TEMPERATURE + siemens_coefficient = 0.7 + w_class = ITEM_SIZE_NORMAL + var/engraved = FALSE + + +/obj/item/clothing/head/helmet/attackby(obj/item/I, mob/user) + ..() + if(istype(I, /obj/item/weapon/material/sword/combat_knife)) + if(engraved) + return + to_chat(user, "You begin to engrave something on your helmet.") + var/to_engrave = sanitize(input(user, "What would you like to engrave?", "Engraving") as null|text) + if(to_engrave) + to_chat(user, "You engrave your helmet with: \"[to_engrave]\"") + desc += " Engraved on the helmet is: \"[to_engrave]\"" + log_and_message_admins("[user] has engraved [to_engrave] on his helmet", user, user.loc) + engraved = TRUE + return + return + + + + +/obj/item/clothing/head/helmet/nt + name = "\improper corporate security helmet" + desc = "A helmet with 'CORPORATE SECURITY' printed on the back in red lettering." + icon_state = "helmet_nt" + +/obj/item/clothing/head/helmet/pcrc + name = "\improper PCRC helmet" + desc = "A helmet with 'PRIVATE SECURITY' printed on the back in cyan lettering." + icon_state = "helmet_pcrc" + +/obj/item/clothing/head/helmet/nt/guard + starting_accessories = list(/obj/item/clothing/accessory/armor/helmcover/nt) + +/obj/item/clothing/head/helmet/tactical + name = "tactical helmet" + desc = "A tan helmet made from advanced ceramic. Comfortable and robust." + icon_state = "helmet_tac" + armor = list(melee = 50, bullet = 60, laser = 60, energy = 45, bomb = 30, bio = 0, rad = 0) + siemens_coefficient = 0.6 + +/obj/item/clothing/head/helmet/merc + name = "combat helmet" + desc = "A heavily reinforced helmet painted with red markings. Feels like it could take a lot of punishment." + icon_state = "helmet_merc" + armor = list(melee = 70, bullet = 70, laser = 70, energy = 35, bomb = 30, bio = 0, rad = 0) + siemens_coefficient = 0.5 + +/obj/item/clothing/head/helmet/barney_helmet + name = "security helmet" + icon_state = "helmet_barney" + armor = list(melee = 40, bullet = 50, laser = 10, energy = 35, bomb = 30, bio =0, rad = 0) + + +/obj/item/clothing/head/helmet/riot + name = "riot helmet" + desc = "It's a helmet specifically designed to protect against close range attacks." + icon_state = "helmet_riot" + valid_accessory_slots = null + body_parts_covered = HEAD|FACE|EYES //face shield + armor = list(melee = 82, bullet = 15, laser = 5, energy = 5, bomb = 5, bio = 2, rad = 0) + siemens_coefficient = 0.7 + action_button_name = "Toggle Visor" + +/obj/item/clothing/head/helmet/riot/attack_self(mob/user as mob) + if(src.icon_state == initial(icon_state)) + src.icon_state = "[icon_state]_up" + to_chat(user, "You raise the visor on the [src].") + else + src.icon_state = initial(icon_state) + to_chat(user, "You lower the visor on the [src].") + update_clothing_icon() + +/obj/item/clothing/head/helmet/ablative + name = "ablative helmet" + desc = "A helmet made from advanced materials which protects against concentrated energy weapons." + icon_state = "helmet_reflect" + valid_accessory_slots = null + armor = list(melee = 15, bullet = 5, laser = 82, energy = 50, bomb = 5, bio = 2, rad = 0) + siemens_coefficient = 0 + +/obj/item/clothing/head/helmet/ballistic + name = "ballistic helmet" + desc = "A helmet with reinforced plating to protect against ballistic projectiles." + icon_state = "helmet_bulletproof" + valid_accessory_slots = null + armor = list(melee = 5, bullet = 82, laser = 30, energy = 5, bomb = 30, bio = 2, rad = 0) + siemens_coefficient = 0.7 + +/obj/item/clothing/head/helmet/swat + name = "\improper SWAT helmet" + desc = "They're often used by highly trained Swat Members." + icon_state = "helmet_merc" + armor = list(melee = 80, bullet = 60, laser = 50,energy = 25, bomb = 50, bio = 10, rad = 0) + cold_protection = HEAD + min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE + siemens_coefficient = 0.5 + +/obj/item/clothing/head/helmet/thunderdome + name = "\improper Thunderdome helmet" + desc = "'Let the battle commence!'" + icon_state = "thunderdome" + valid_accessory_slots = null + armor = list(melee = 80, bullet = 60, laser = 50,energy = 10, bomb = 25, bio = 10, rad = 0) + cold_protection = HEAD + min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE + siemens_coefficient = 1 + +/obj/item/clothing/head/helmet/gladiator + name = "gladiator helmet" + desc = "Ave, Imperator, morituri te salutant." + icon_state = "gladiator" + valid_accessory_slots = null + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|BLOCKHAIR + body_parts_covered = HEAD|FACE + siemens_coefficient = 1 + +/* +/obj/item/clothing/head/helmet/tactical + name = "tactical helmet" + desc = "An armored helmet capable of being fitted with a multitude of attachments." + icon_state = "swathelm" + valid_accessory_slots = null + sprite_sheets = list( + SPECIES_TAJARA = 'icons/mob/species/tajaran/helmet.dmi', + SPECIES_UNATHI = 'icons/mob/species/unathi/helmet.dmi' + ) + + armor = list(melee = 62, bullet = 50, laser = 50,energy = 35, bomb = 10, bio = 2, rad = 0) + flags_inv = HIDEEARS + siemens_coefficient = 0.7 +*/ + +/obj/item/clothing/head/helmet/augment + name = "Augment Array" + desc = "A helmet with optical and cranial augments coupled to it." + icon_state = "v62" + valid_accessory_slots = null + armor = list(melee = 80, bullet = 60, laser = 50,energy = 25, bomb = 50, bio = 10, rad = 0) + flags_inv = HIDEEARS|HIDEEYES + body_parts_covered = HEAD|EYES|BLOCKHEADHAIR + cold_protection = HEAD + min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE + siemens_coefficient = 0.5 + +//Non-hardsuit ERT helmets. +//Commander +/obj/item/clothing/head/helmet/ert + name = "asset protection command helmet" + desc = "An in-atmosphere helmet worn by many corporate and private asset protection forces. Has blue highlights." + icon_state = "erthelmet_cmd" + valid_accessory_slots = null + item_state_slots = list( + slot_l_hand_str = "syndicate-helm-green", + slot_r_hand_str = "syndicate-helm-green", + ) + armor = list(melee = 62, bullet = 50, laser = 50,energy = 35, bomb = 10, bio = 2, rad = 0) + +//Security +/obj/item/clothing/head/helmet/ert/security + name = "asset protection security helmet" + desc = "An in-atmosphere helmet worn by many corporate and private asset protection forces. Has red highlights." + icon_state = "erthelmet_sec" + +//Engineer +/obj/item/clothing/head/helmet/ert/engineer + name = "asset protection engineering helmet" + desc = "An in-atmosphere helmet worn by many corporate and private asset protection forces. Has orange highlights." + icon_state = "erthelmet_eng" + +//Medical +/obj/item/clothing/head/helmet/ert/medical + name = "asset protection medical helmet" + desc = "An in-atmosphere helmet worn by many corporate and private asset protection forces. Has red and white highlights." + icon_state = "erthelmet_med" + +/obj/item/clothing/head/helmet/tactical/mirania + name = "bundeforz tactical helmet" + desc = "A light grey helmet made from advanced ceramic. Comfortable and robust." + icon_state = "m_helmet" diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm new file mode 100644 index 00000000..5a02541f --- /dev/null +++ b/code/modules/clothing/head/jobs.dm @@ -0,0 +1,179 @@ + +//Bartender +/obj/item/clothing/head/chefhat + name = "chef's hat" + desc = "It's a hat used by chefs to keep hair out of your food. Judging by the food in the mess, they don't work." + icon_state = "chefhat" + item_state = "chefhat" + + +//Magistrate +/obj/item/clothing/head/crown + name = "commandant's hat of authority" + icon_state = "redoffcap" + item_state = "redoffcap" + desc = "It's good being Commandant." + flags_inv = BLOCKHEADHAIR + body_parts_covered = HEAD + unacidable = TRUE //Do NOT want to lose this randomly. + +//Captain +/obj/item/clothing/head/caphat + name = "captain's hat" + icon_state = "captain" + desc = "It's good being the king." + item_state_slots = list( + slot_l_hand_str = "caphat", + slot_r_hand_str = "caphat", + ) + body_parts_covered = 0 + +/obj/item/clothing/head/caphat/cap + name = "captain's cap" + desc = "You fear to wear it for the negligence it brings." + icon_state = "capcap" + +/obj/item/clothing/head/caphat/formal + name = "parade hat" + desc = "No one in a commanding position should be without a perfect, white hat of ultimate authority." + icon_state = "officercap" + +//HOP +/obj/item/clothing/head/caphat/hop + name = "crew resource's hat" + desc = "A stylish hat that both protects you from enraged former-crewmembers and gives you a false sense of authority." + icon_state = "hopcap" + +//Chaplain +/obj/item/clothing/head/chaplain_hood + name = "chaplain's hood" + desc = "It's hood that covers the head. It keeps you warm during the space winters." + icon_state = "chaplain_hood" + flags_inv = BLOCKHAIR + body_parts_covered = HEAD + +//Chaplain +/obj/item/clothing/head/nun_hood + name = "nun hood" + desc = "Maximum piety in this star system." + icon_state = "nun_hood" + flags_inv = BLOCKHAIR + body_parts_covered = HEAD + +//Medical +/obj/item/clothing/head/surgery + name = "surgical cap" + desc = "A cap surgeons wear during operations. Keeps their hair from tickling your internal organs." + icon_state = "surgcap" + flags_inv = BLOCKHEADHAIR + +/obj/item/clothing/head/surgery/purple + name = "purple surgical cap" + color = "#7a1b3f" + +/obj/item/clothing/head/surgery/blue + name = "blue surgical cap" + color = "#4891e1" + +/obj/item/clothing/head/surgery/green + name = "green surgical cap" + color = "#255a3e" + +/obj/item/clothing/head/surgery/black + name = "black surgical cap" + color = "#242424" + +/obj/item/clothing/head/surgery/navyblue + name = "navy blue surgical cap" + color = "#1f3a69" + +/obj/item/clothing/head/surgery/lilac + name = "lilac surgical cap" + color = "#c8a2c8" + +/obj/item/clothing/head/surgery/teal + name = "teal surgical cap" + color = "#008080" + +/obj/item/clothing/head/surgery/heliodor + name = "heliodor surgical cap" + color = "#aad539" + +//Berets +/obj/item/clothing/head/beret + name = "beret" + desc = "A beret, an artists favorite headwear." + icon_state = "beret" + body_parts_covered = 0 + +/obj/item/clothing/head/beret/sec + name = "corporate security beret" + desc = "A beret with the security insignia emblazoned on it. For officers that are more inclined towards style than safety." + icon_state = "beret_corporate_red" + +/obj/item/clothing/head/beret/sec/navy/officer + name = "corporate security officer beret" + desc = "A navy blue beret with an officer's rank emblem. For officers that are more inclined towards style than safety." + icon_state = "beret_corporate_navy_officer" + +/obj/item/clothing/head/beret/sec/navy/hos + name = "corporate security commander beret" + desc = "A navy blue beret with a commander's rank emblem. For officers that are more inclined towards style than safety." + icon_state = "beret_corporate_navy_hos" + +/obj/item/clothing/head/beret/sec/navy/warden + name = "corporate security warden beret" + desc = "A navy blue beret with a warden's rank emblem. For officers that are more inclined towards style than safety." + icon_state = "beret_corporate_navy_warden" + +/obj/item/clothing/head/beret/sec/corporate/officer + name = "corporate security officer beret" + desc = "A corporate black beret with an officer's rank emblem. For officers that are more inclined towards style than safety." + icon_state = "beret_corporate_officer" + +/obj/item/clothing/head/beret/sec/corporate/hos + name = "corporate security commander beret" + desc = "A corporate black beret with a commander's rank emblem. For officers that are more inclined towards style than safety." + icon_state = "beret_corporate_hos" + +/obj/item/clothing/head/beret/sec/corporate/warden + name = "corporate security warden beret" + desc = "A corporate black beret with a warden's rank emblem. For officers that are more inclined towards style than safety." + icon_state = "beret_corporate_warden" + +/obj/item/clothing/head/beret/engineering + name = "corporate engineering beret" + desc = "A beret with the engineering insignia emblazoned on it. For engineers that are more inclined towards style than safety." + icon_state = "beret_orange" + +/obj/item/clothing/head/beret/purple + name = "purple beret" + desc = "A stylish, if purple, beret. For personnel that are more inclined towards style than safety." + icon_state = "beret_purple" + +/obj/item/clothing/head/beret/centcom/officer + name = "asset protection beret" + desc = "A navy blue beret adorned with the crest of corporate asset protection. For asset protection agents that are more inclined towards style than safety." + icon_state = "beret_corporate_navy" + +/obj/item/clothing/head/beret/centcom/captain + name = "asset protection command beret" + desc = "A white beret adorned with the crest of corporate asset protection. For asset protection leaders that are more inclined towards style than safety." + icon_state = "beret_corporate_white" + +/obj/item/clothing/head/beret/deathsquad + name = "heavy asset protection beret" + desc = "An armored red beret adorned with the crest of corporate asset protection. Doesn't sacrifice style or safety." + icon_state = "beret_red" + armor = list(melee = 65, bullet = 55, laser = 35,energy = 20, bomb = 30, bio = 30, rad = 30) + siemens_coefficient = 0.9 + +/obj/item/clothing/head/beret/guard + name = "corporate security beret" + desc = "A white beret adorned with the crest of NanoTrasen. For security guards that are more inclined towards style than safety." + icon_state = "beret_corporate_whitered" + +/obj/item/clothing/head/beret/plaincolor + name = "beret" + desc = "A simple, solid color beret. This one has no emblems or insignia on it." + icon_state = "beret_white" \ No newline at end of file diff --git a/code/modules/clothing/head/mirania.dm b/code/modules/clothing/head/mirania.dm new file mode 100644 index 00000000..855279ed --- /dev/null +++ b/code/modules/clothing/head/mirania.dm @@ -0,0 +1,16 @@ +/obj/item/clothing/head/beret/mirania + name = "bundeforz beret" + desc = "A Miranian Defence Forces beret. The crest depicts a black sun on a red background. For personnel that are more inclined towards style than safety." + icon_state = "beret_black_security" + +/obj/item/clothing/head/dress/mirania + name = "bundeforz dress cover" + desc = "A Miranian Defence Forces dress uniform cover." + item_state = "m_dress" + icon_state = "m_dress" + +/obj/item/clothing/head/dress/mirania/intelligence + name = "intelligence service dress cover" + desc = "A Miranian Truth Ministry dress uniform cover." + item_state = "m_dress_int" + icon_state = "m_dress_int" \ No newline at end of file diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm new file mode 100644 index 00000000..f3996276 --- /dev/null +++ b/code/modules/clothing/head/misc.dm @@ -0,0 +1,333 @@ + + +/obj/item/clothing/head/centhat + name = "\improper CentComm. hat" + icon_state = "centcom" + item_state_slots = list( + slot_l_hand_str = "centhat", + slot_r_hand_str = "centhat", + ) + desc = "It's good to be emperor." + siemens_coefficient = 0.9 + body_parts_covered = 0 + +/obj/item/clothing/head/hairflower + name = "hair flower pin" + icon_state = "hairflower" + desc = "Smells nice." + slot_flags = SLOT_HEAD | SLOT_EARS + body_parts_covered = 0 + +/obj/item/clothing/head/hairflower/blue + icon_state = "hairflower_blue" + +/obj/item/clothing/head/hairflower/pink + icon_state = "hairflower_pink" + +/obj/item/clothing/head/hairflower/yellow + icon_state = "hairflower_yellow" + +/obj/item/clothing/head/hairflower/bow + icon_state = "bow" + name = "hair bow" + desc = "A ribbon tied into a bow with a clip on the back to attach to hair." + +/obj/item/clothing/head/powdered_wig + name = "powdered wig" + desc = "A powdered wig." + icon_state = "pwig" + item_state = "pwig" + +/obj/item/clothing/head/that + name = "top-hat" + desc = "It's an amish looking hat." + icon_state = "tophat" + item_state = "tophat" + siemens_coefficient = 0.9 + body_parts_covered = 0 + +/obj/item/clothing/head/redcoat + name = "redcoat's hat" + icon_state = "redcoat" + desc = "'I guess it's a redhead.'" + body_parts_covered = 0 + +/obj/item/clothing/head/mailman + name = "mail cap" + icon_state = "mailman" + desc = "Choo-choo!" + body_parts_covered = 0 + +/obj/item/clothing/head/plaguedoctorhat + name = "plague doctor's hat" + desc = "These were once used by Plague doctors. They're pretty much useless." + icon_state = "plaguedoctor" + permeability_coefficient = 0.01 + siemens_coefficient = 0.9 + body_parts_covered = 0 + +/obj/item/clothing/head/hasturhood + name = "hastur's hood" + desc = "It's unspeakably stylish." + icon_state = "hasturhood" + flags_inv = BLOCKHAIR + body_parts_covered = HEAD|FACE|EYES + +/obj/item/clothing/head/nursehat + name = "nurse's hat" + desc = "It allows quick identification of trained medical personnel." + icon_state = "nursehat" + siemens_coefficient = 0.9 + body_parts_covered = 0 + +/obj/item/clothing/head/syndicatefake + name = "red space-helmet replica" + item_state_slots = list( + slot_l_hand_str = "syndicate-helm-black-red", + slot_r_hand_str = "syndicate-helm-black-red", + ) + icon_state = "syndicate" + desc = "A plastic replica of a bloodthirsty mercenary's space helmet, you'll look just like a real murderous criminal operative in this! This is a toy, it is not made for use in space!" + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|BLOCKHAIR + siemens_coefficient = 2.0 + body_parts_covered = HEAD|FACE|EYES + +/obj/item/clothing/head/cueball + name = "cueball helmet" + desc = "A large, featureless white orb mean to be worn on your head. How do you even see out of this thing?" + icon_state = "cueball" + item_state = "cueball" + flags_inv = BLOCKHAIR + body_parts_covered = HEAD|FACE|EYES + +/obj/item/clothing/head/cardborg + name = "cardborg helmet" + desc = "A helmet made out of a box." + icon_state = "cardborg_h" + item_state = "cardborg_h" + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE + body_parts_covered = HEAD|FACE|EYES + +/obj/item/clothing/head/cardborg/Initialize() + . = ..() + set_extension(src, /datum/extension/appearance, /datum/extension/appearance/cardborg) + +/obj/item/clothing/head/justice + name = "justice hat" + desc = "fight for what's righteous!" + icon_state = "justicered" + flags_inv = BLOCKHAIR + body_parts_covered = HEAD|EYES + +/obj/item/clothing/head/justice/blue + icon_state = "justiceblue" + +/obj/item/clothing/head/justice/yellow + icon_state = "justiceyellow" + +/obj/item/clothing/head/justice/green + icon_state = "justicegreen" + +/obj/item/clothing/head/justice/pink + icon_state = "justicepink" + +/obj/item/clothing/head/rabbitears + name = "rabbit ears" + desc = "Wearing these makes you looks useless, and only good for your sex appeal." + icon_state = "bunny" + body_parts_covered = 0 + +/obj/item/clothing/head/flatcap + name = "flat cap" + desc = "A working man's cap." + icon_state = "flat_cap" + item_state_slots = list( + slot_l_hand_str = "det_hat", + slot_r_hand_str = "det_hat", + ) + siemens_coefficient = 0.9 + +/obj/item/clothing/head/pirate + name = "pirate hat" + desc = "Yarr." + icon_state = "pirate" + body_parts_covered = 0 + +/obj/item/clothing/head/hgpiratecap + name = "pirate hat" + desc = "Yarr." + icon_state = "hgpiratecap" + body_parts_covered = 0 + +/obj/item/clothing/head/bandana + name = "pirate bandana" + desc = "Yarr." + icon_state = "bandana" + body_parts_covered = 0 + +/obj/item/clothing/head/bandana/green + name = "green bandana" + desc = "It's a green bandana with some fine nanotech lining." + icon_state = "greenbandana" + item_state = "greenbandana" + +/obj/item/clothing/head/bandana/orange //themij: Taryn Kifer + name = "orange bandana" + desc = "An orange piece of cloth, worn on the head." + icon_state = "orange_bandana" + +/obj/item/clothing/head/bowler + name = "bowler-hat" + desc = "Gentleman, elite aboard!" + icon_state = "bowler" + body_parts_covered = 0 + +//stylish bs12 hats + +/obj/item/clothing/head/bowlerhat + name = "bowler hat" + icon_state = "bowler_hat" + desc = "For the gentleman of distinction." + body_parts_covered = 0 + +/obj/item/clothing/head/beaverhat + name = "beaver hat" + icon_state = "beaver_hat" + desc = "Soft felt makes this hat both comfortable and elegant." + +/obj/item/clothing/head/boaterhat + name = "boater hat" + icon_state = "boater_hat" + desc = "The ultimate in summer fashion." + +/obj/item/clothing/head/fedora + name = "fedora" + icon_state = "fedora" + desc = "A sharp, stylish hat." + +/obj/item/clothing/head/feathertrilby + name = "feather trilby" + icon_state = "feather_trilby" + desc = "A sharp, stylish hat with a feather." + +/obj/item/clothing/head/fez + name = "fez" + icon_state = "fez" + desc = "You should wear a fez. Fezzes are cool." + +//end bs12 hats + +/obj/item/clothing/head/witchwig + name = "witch costume wig" + desc = "Eeeee~heheheheheheh!" + icon_state = "witch" + flags_inv = BLOCKHAIR + siemens_coefficient = 2.0 + +/obj/item/clothing/head/chicken + name = "chicken suit head" + desc = "Bkaw!" + icon_state = "chickenhead" + item_state_slots = list( + slot_l_hand_str = "chickensuit", + slot_r_hand_str = "chickensuit", + ) + flags_inv = BLOCKHAIR + siemens_coefficient = 0.7 + body_parts_covered = HEAD|FACE|EYES + +/obj/item/clothing/head/bearpelt + name = "bear pelt hat" + desc = "Fuzzy." + icon_state = "bearpelt" + flags_inv = BLOCKHAIR + siemens_coefficient = 0.7 + +/obj/item/clothing/head/xenos + name = "xenos helmet" + icon_state = "xenos" + item_state_slots = list( + slot_l_hand_str = "xenos_helm", + slot_r_hand_str = "xenos_helm", + ) + desc = "A helmet made out of chitinous alien hide." + w_class = ITEM_SIZE_NORMAL + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|BLOCKHAIR + siemens_coefficient = 2.0 + body_parts_covered = HEAD|FACE|EYES + +/obj/item/clothing/head/philosopher_wig + name = "natural philosopher's wig" + desc = "A stylish monstrosity unearthed from Earth's Renaissance period. With this most distinguish'd wig, you'll be ready for your next soiree!" + icon_state = "philosopher_wig" + item_state_slots = list( + slot_l_hand_str = "pwig", + slot_r_hand_str = "pwig", + ) + flags_inv = BLOCKHAIR + body_parts_covered = 0 + +/obj/item/clothing/head/hijab + name = "hijab" + desc = "A veil which is wrapped to cover the head and chest." + icon_state = "hijab" + body_parts_covered = 0 + flags_inv = BLOCKHAIR + +/obj/item/clothing/head/kippa + name = "kippa" + desc = "A small, brimless cap." + icon_state = "kippa" + body_parts_covered = 0 + +/obj/item/clothing/head/turban + name = "turban" + desc = "A sturdy cloth, worn around the head." + icon_state = "turban" + body_parts_covered = 0 + flags_inv = BLOCKHEADHAIR //Shows beards! + +/obj/item/clothing/head/cowboy_hat + name = "cowboy hat" + desc = "A wide-brimmed hat, in the prevalent style of America's frontier period. By SolGov law, you are required to wear this hat while watching True Grit." + icon_state = "cowboyhat" + item_state = "cowboy_hat" + body_parts_covered = 0 + +/obj/item/clothing/head/taqiyah + name = "taqiyah" + desc = "A short, rounded skullcap usually worn for religious purposes." + icon_state = "taqiyah" + item_state = "taqiyah" + body_parts_covered = 0 + +/obj/item/clothing/head/tank + name = "padded cap" + desc = "A padded skullcup for those prone to bumping their heads against hard surfaces." + icon_state = "tank" + flags_inv = BLOCKHEADHAIR + color = "#5f5f5f" + armor = list(melee = 20) + +/obj/item/clothing/head/tank/olive + color = "#727c58" + +/obj/item/clothing/head/tank/tan + color = "#ae9f79" + +/obj/item/clothing/head/helmet/facecover + name = "face cover" + desc = "A helmet made of plastic. It's completely opaque. This will stop the stare." + icon_state = "facecover" + tint = TINT_BLIND + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|BLOCKHAIR + body_parts_covered = HEAD|FACE|EYES + flash_protection = FLASH_PROTECTION_MAJOR + +/obj/item/clothing/head/inquisitor + name = "cappello romano" + desc = "A round wide-brimmed hat worn by more traditional Roman Catholic clergy." + icon_state = "brim-hat" + item_state = "brim-hat" + flags_inv = BLOCKHEADHAIR + armor = list(melee = 15, bullet = 0, laser = 15, energy = 15, bomb = 0, bio = 0, rad = 0) \ No newline at end of file diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm new file mode 100644 index 00000000..a343fcc4 --- /dev/null +++ b/code/modules/clothing/head/misc_special.dm @@ -0,0 +1,215 @@ +/* + * Contents: + * Welding mask + * Cakehat + * Ushanka + * Pumpkin head + * Kitty ears + * + */ + +/* + * Welding mask + */ +/obj/item/clothing/head/welding + name = "welding helmet" + desc = "A head-mounted face cover designed to protect the wearer completely from space-arc eye." + icon_state = "welding" + item_state_slots = list( + slot_l_hand_str = "welding", + slot_r_hand_str = "welding", + ) + matter = list(DEFAULT_WALL_MATERIAL = 3000, "glass" = 1000) + var/up = 0 + armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + flags_inv = (HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE) + body_parts_covered = HEAD|FACE|EYES + action_button_name = "Flip Welding Mask" + siemens_coefficient = 0.9 + w_class = ITEM_SIZE_NORMAL + var/base_state + flash_protection = FLASH_PROTECTION_MAJOR + tint = TINT_HEAVY + +/obj/item/clothing/head/welding/attack_self() + if(!base_state) + base_state = icon_state + toggle() + + +/obj/item/clothing/head/welding/verb/toggle() + set category = "Object" + set name = "Adjust welding mask" + set src in usr + + if(usr.canmove && !usr.stat && !usr.restrained()) + if(src.up) + 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 + item_state = base_state + to_chat(usr, "You flip the [src] down to protect your eyes.") + helmet_vision = TRUE + 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" + item_state = "[base_state]up" + to_chat(usr, "You push the [src] up out of your face.") + helmet_vision = FALSE + update_clothing_icon() //so our mob-overlays + update_vision() + usr.update_action_buttons() + +/obj/item/clothing/head/welding/demon + name = "demonic welding helmet" + desc = "A painted welding helmet, this one has a demonic face on it." + icon_state = "demonwelding" + item_state_slots = list( + slot_l_hand_str = "demonwelding", + slot_r_hand_str = "demonwelding", + ) + +/obj/item/clothing/head/welding/knight + name = "knightly welding helmet" + desc = "A painted welding helmet, this one looks like a knights helmet." + icon_state = "knightwelding" + +/obj/item/clothing/head/welding/fancy + name = "fancy welding helmet" + desc = "A painted welding helmet, the black and gold make this one look very fancy." + icon_state = "fancywelding" + item_state_slots = list( + slot_l_hand_str = "fancywelding", + slot_r_hand_str = "fancywelding", + ) + +/obj/item/clothing/head/welding/engie + name = "engineering welding helmet" + desc = "A painted welding helmet, this one has been painted the engineering colours." + icon_state = "engiewelding" + item_state_slots = list( + slot_l_hand_str = "engiewelding", + slot_r_hand_str = "engiewelding", + ) + +/obj/item/clothing/head/welding/carp + name = "carp welding helmet" + desc = "A painted welding helmet, this one has a carp face on it." + icon_state = "carpwelding" + item_state_slots = list( + slot_l_hand_str = "carpwelding", + slot_r_hand_str = "carpwelding", + ) + +/* + * Cakehat + */ +/obj/item/clothing/head/cakehat + name = "cake-hat" + desc = "It's tasty looking!" + icon_state = "cake0" + item_state = "cake0" + var/onfire = 0 + body_parts_covered = HEAD + +/obj/item/clothing/head/cakehat/Process() + if(!onfire) + STOP_PROCESSING(SSobj, src) + return + + var/turf/location = src.loc + if(istype(location, /mob/)) + var/mob/living/carbon/human/M = location + if(M.l_hand == src || M.r_hand == src || M.head == src) + location = M.loc + + if (istype(location, /turf)) + location.hotspot_expose(700, 1) + +/obj/item/clothing/head/cakehat/attack_self(mob/user as mob) + src.onfire = !( src.onfire ) + if (src.onfire) + src.force = 3 + src.damtype = "fire" + src.icon_state = "cake1" + src.item_state = "cake1" + START_PROCESSING(SSobj, src) + else + src.force = null + src.damtype = "brute" + src.icon_state = "cake0" + src.item_state = "cake0" + return + + +/* + * Ushanka + */ +/obj/item/clothing/head/ushanka + name = "ushanka" + desc = "Perfect for winter in Siberia, da?" + icon_state = "ushankadown" + var/icon_state_up = "ushankaup" + flags_inv = HIDEEARS|BLOCKHEADHAIR + cold_protection = HEAD + min_cold_protection_temperature = HELMET_MIN_COLD_PROTECTION_TEMPERATURE + +/obj/item/clothing/head/ushanka/attack_self(mob/user as mob) + if(icon_state == initial(icon_state)) + icon_state = icon_state_up + to_chat(user, "You raise the ear flaps on the ushanka.") + else + icon_state = initial(icon_state) + to_chat(user, "You lower the ear flaps on the ushanka.") + +/obj/item/clothing/head/ushanka/tcc + name = "TCC ushanka" + desc = "Perfect for keeping ears warm during your courtmartial." + icon_state = "tccushankadown" + icon_state_up = "tccushankaup" + +/* + * Pumpkin head + */ +/obj/item/clothing/head/pumpkinhead + name = "carved pumpkin" + desc = "A jack o' lantern! Believed to ward off evil spirits." + icon_state = "hardhat0_pumpkin"//Could stand to be renamed + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|BLOCKHAIR + body_parts_covered = HEAD|FACE|EYES + brightness_on = 2 + light_overlay = "helmet_light" + w_class = ITEM_SIZE_NORMAL + +/* + * Kitty ears + */ +/obj/item/clothing/head/kitty + name = "kitty ears" + desc = "A pair of kitty ears. Meow!" + icon_state = "kitty" + body_parts_covered = 0 + siemens_coefficient = 1.5 + item_icons = list() + + update_icon(var/mob/living/carbon/human/user) + if(!istype(user)) return + var/icon/ears = new/icon("icon" = 'icons/mob/onmob/head.dmi', "icon_state" = "kitty") + ears.Blend(rgb(user.r_hair, user.g_hair, user.b_hair), ICON_ADD) + + var/icon/earbit = new/icon("icon" = 'icons/mob/onmob/head.dmi', "icon_state" = "kittyinner") + ears.Blend(earbit, ICON_OVERLAY) + +/obj/item/clothing/head/richard + name = "chicken mask" + desc = "You can hear the distant sounds of rhythmic electronica." + icon_state = "richard" + body_parts_covered = HEAD|FACE + flags_inv = BLOCKHAIR diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm new file mode 100644 index 00000000..47546e67 --- /dev/null +++ b/code/modules/clothing/head/soft_caps.dm @@ -0,0 +1,107 @@ +/obj/item/clothing/head/soft + name = "cargo cap" + desc = "It's a peaked cap in a tasteless yellow color." + icon_state = "cargosoft" + item_state_slots = list( + slot_l_hand_str = "helmet", //probably a placeholder + slot_r_hand_str = "helmet", + ) + var/flipped = 0 + siemens_coefficient = 0.9 + body_parts_covered = 0 + +/obj/item/clothing/head/soft/New() + ..() + set_extension(src, /datum/extension/base_icon_state, /datum/extension/base_icon_state, icon_state) + update_icon() + +/obj/item/clothing/head/soft/update_icon() + var/datum/extension/base_icon_state/bis = get_extension(src, /datum/extension/base_icon_state) + if(flipped) + icon_state = "[bis.base_icon_state]_flipped" + else + icon_state = bis.base_icon_state + +/obj/item/clothing/head/soft/dropped() + src.flipped=0 + update_icon() + ..() + +/obj/item/clothing/head/soft/attack_self(mob/user) + src.flipped = !src.flipped + if(src.flipped) + to_chat(user, "You flip the hat backwards.") + else + to_chat(user, "You flip the hat back in normal position.") + update_icon() + update_clothing_icon() //so our mob-overlays update + +/obj/item/clothing/head/soft/red + name = "red cap" + desc = "It's a baseball hat in a tasteless red color." + icon_state = "redsoft" + +/obj/item/clothing/head/soft/blue + name = "blue cap" + desc = "It's a peaked cap in a tasteless blue color." + icon_state = "bluesoft" + +/obj/item/clothing/head/soft/green + name = "green cap" + desc = "It's a peaked cap in a tasteless green color." + icon_state = "greensoft" + +/obj/item/clothing/head/soft/yellow + name = "yellow cap" + desc = "It's a peaked cap in a tasteless yellow color." + icon_state = "yellowsoft" + +/obj/item/clothing/head/soft/grey + name = "grey cap" + desc = "It's a peaked cap in a tasteful grey color." + icon_state = "greysoft" + +/obj/item/clothing/head/soft/orange + name = "orange cap" + desc = "It's a peaked cap in a tasteless orange color." + icon_state = "orangesoft" + +/obj/item/clothing/head/soft/mime + name = "white cap" + desc = "It's a peaked cap in a tasteless white color." + icon_state = "mimesoft" + +/obj/item/clothing/head/soft/purple + name = "purple cap" + desc = "It's a peaked cap in a tasteless purple color." + icon_state = "purplesoft" + +/obj/item/clothing/head/soft/rainbow + name = "rainbow cap" + desc = "It's a peaked cap in a bright rainbow of colors." + icon_state = "rainbowsoft" + +/obj/item/clothing/head/soft/sec + name = "security cap" + desc = "It's a field cap in tasteful red color." + icon_state = "secsoft" + +/obj/item/clothing/head/soft/sec/corp + name = "corporate security cap" + desc = "It's field cap in corporate colors." + icon_state = "corpsoft" + +/obj/item/clothing/head/soft/mbill + name = "shipping cap" + desc = "It's a ballcap bearing the colors of Major Bill's Shipping." + icon_state = "mbillsoft" + +/obj/item/clothing/head/soft/black + name = "black cap" + desc = "It's a peaked cap in a tasteful black color." + icon_state = "blacksoft" + +/obj/item/clothing/head/soft/sec/corp/guard + name = "\improper NanoTrasen security cap" + desc = "It's field cap in NanoTrasen colors." + icon_state = "ntwhitesoft" diff --git a/code/modules/clothing/masks/boxing.dm b/code/modules/clothing/masks/boxing.dm new file mode 100644 index 00000000..334d58c2 --- /dev/null +++ b/code/modules/clothing/masks/boxing.dm @@ -0,0 +1,39 @@ +/obj/item/clothing/mask/balaclava + name = "balaclava" + desc = "Designed to both hide identities and keep your face comfy and warm." + icon_state = "balaclava" + item_state = "balaclava" + flags_inv = HIDEFACE|BLOCKHAIR + body_parts_covered = FACE|HEAD + down_body_parts_covered = HEAD + down_flags_inv = BLOCKHEADHAIR + down_icon_state = "balaclava_r" + pull_mask = 1 + w_class = ITEM_SIZE_SMALL + +/obj/item/clothing/mask/balaclava/tactical + name = "green balaclava" + icon_state = "swatclava" + down_icon_state = "swatclava_r" + +/obj/item/clothing/mask/luchador + name = "Luchador Mask" + desc = "Worn by robust fighters, flying high to defeat their foes!" + icon_state = "luchag" + item_state = "luchag" + flags_inv = HIDEFACE|BLOCKHAIR + body_parts_covered = HEAD|FACE + w_class = ITEM_SIZE_SMALL + siemens_coefficient = 3.0 + +/obj/item/clothing/mask/luchador/tecnicos + name = "Tecnicos Mask" + desc = "Worn by robust fighters who uphold justice and fight honorably." + icon_state = "luchador" + item_state = "luchador" + +/obj/item/clothing/mask/luchador/rudos + name = "Rudos Mask" + desc = "Worn by robust fighters who are willing to do anything to win." + icon_state = "luchar" + item_state = "luchar" \ No newline at end of file diff --git a/code/modules/clothing/masks/breath.dm b/code/modules/clothing/masks/breath.dm new file mode 100644 index 00000000..0d0085e9 --- /dev/null +++ b/code/modules/clothing/masks/breath.dm @@ -0,0 +1,50 @@ +/obj/item/clothing/mask/breath + desc = "A close-fitting mask that can be connected to an air supply." + name = "breath mask" + icon_state = "breath" + item_state = "breath" + item_flags = ITEM_FLAG_AIRTIGHT|ITEM_FLAG_FLEXIBLEMATERIAL + body_parts_covered = FACE + w_class = ITEM_SIZE_SMALL + gas_transfer_coefficient = 0.10 + permeability_coefficient = 0.50 + down_gas_transfer_coefficient = 1 + down_body_parts_covered = null + down_item_flags = ITEM_FLAG_THICKMATERIAL + down_icon_state = "breathdown" + pull_mask = 1 + +/obj/item/clothing/mask/breath/medical + desc = "A close-fitting sterile mask that can be manually connected to an air supply for treatment." + name = "medical mask" + icon_state = "medical" + item_state = "medical" + permeability_coefficient = 0.01 + +/obj/item/clothing/mask/breath/anesthetic + desc = "A close-fitting sterile mask that is used by the anesthetic wallmounted pump." + name = "anesthetic mask" + icon_state = "medical" + item_state = "medical" + permeability_coefficient = 0.01 + +/obj/item/clothing/mask/breath/emergency + desc = "A close-fitting mask that is used by the wallmounted emergency oxygen pump." + name = "emergency mask" + icon_state = "breath" + item_state = "breath" + permeability_coefficient = 0.50 + +/obj/item/clothing/mask/breath/bogani + name = "large alien mask" + desc = "Some form of alien breathing apparatus." + icon_state = "bmask_large" + item_state = "bmask_large" + pull_mask = 0 + species_restricted = list(SPECIES_BOGANI) + +/obj/item/clothing/mask/breath/bogani/egyno + name = "alien mask" + icon_state = "bmask" + item_state = "bmask" + species_restricted = list(SPECIES_EGYNO) diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm new file mode 100644 index 00000000..1dcc4359 --- /dev/null +++ b/code/modules/clothing/masks/gasmask.dm @@ -0,0 +1,163 @@ +/obj/item/clothing/mask/gas + name = "gas mask" + desc = "A face-covering mask that can be connected to an air supply. Filters harmful gases from the air." + icon_state = "fullgas" + item_state = "fullgas" + equipsound = 'sound/items/equip/mask_equip.ogg' + grab_sound = 'sound/items/handle/clothing_generic.ogg' + item_flags = ITEM_FLAG_BLOCK_GAS_SMOKE_EFFECT | ITEM_FLAG_AIRTIGHT + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|BLOCKHAIR + body_parts_covered = FACE|EYES|HEAD + w_class = ITEM_SIZE_NORMAL + gas_transfer_coefficient = 0.01 + permeability_coefficient = 0.01 + siemens_coefficient = 0.9 + var/gas_filter_strength = 1 //For gas mask filters + var/list/filtered_gases = list("phoron", "sleeping_agent") + armor = list(melee = 5, bullet = 5, laser = 5, energy = 0, bomb = 0, bio = 75, rad = 0) + +/obj/item/clothing/mask/gas/filter_air(datum/gas_mixture/air) + var/datum/gas_mixture/filtered = new + + for(var/g in filtered_gases) + if(air.gas[g]) + filtered.gas[g] = air.gas[g] * gas_filter_strength + air.gas[g] -= filtered.gas[g] + + air.update_values() + filtered.update_values() + + return filtered +/obj/item/clothing/mask/gas/ancient + icon_state = "fullgas" + item_state = "fullgas" + name = "ancient gas mask" + desc = "A leftover from the Old War, you can barely fucking see out of the thing, but it gets the job done." + helmet_vision = TRUE + +/obj/item/clothing/mask/gas/security + name = "military grade gas mask" + icon_state = "sgmask" + item_state = "sgmask" + siemens_coefficient = 0.7 + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE + body_parts_covered = FACE|EYES + armor = list(melee = 15, bullet = 15, laser = 15, energy = 0, bomb = 0, bio = 75, rad = 0) + +/obj/item/clothing/mask/gas/half + name = "face mask" + desc = "A compact, durable gas mask that can be connected to an air supply." + icon_state = "halfgas" + item_state = "halfgas" + siemens_coefficient = 0.7 + body_parts_covered = FACE + flags_inv = HIDEEARS|HIDEFACE + w_class = ITEM_SIZE_SMALL + armor = list(melee = 10, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 55, rad = 0) + +//Plague Dr suit can be found in clothing/suits/bio.dm +/obj/item/clothing/mask/gas/plaguedoctor + name = "plague doctor mask" + desc = "A modernised version of the classic design, this mask will not only filter out phoron but it can also be connected to an air supply." + icon_state = "plaguedoctor" + item_state = "gas_mask" + armor = list(melee = 0, bullet = 0, laser = 2,energy = 2, bomb = 0, bio = 90, rad = 0) + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE + body_parts_covered = HEAD|FACE|EYES + +/obj/item/clothing/mask/gas/swat + name = "\improper SWAT mask" + desc = "A close-fitting tactical mask that can be connected to an air supply." + icon_state = "swat" + siemens_coefficient = 0.7 + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE + body_parts_covered = FACE|EYES + armor = list(melee = 15, bullet = 15, laser = 15, energy = 0, bomb = 0, bio = 75, rad = 0) + +/obj/item/clothing/mask/gas/swat/vox + name = "alien mask" + desc = "Clearly not designed for a human face." + body_parts_covered = 0 //Hack to allow vox to eat while wearing this mask. + species_restricted = list(SPECIES_VOX) + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE + +/obj/item/clothing/mask/gas/syndicate + name = "tactical mask" + desc = "A close-fitting tactical mask that can be connected to an air supply." + icon_state = "swat" + siemens_coefficient = 0.7 + armor = list(melee = 15, bullet = 15, laser = 15, energy = 0, bomb = 0, bio = 75, rad = 0) + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE + +/obj/item/clothing/mask/gas/clown_hat + name = "clown wig and mask" + desc = "A true prankster's facial attire. A clown is incomplete without their wig and mask." + icon_state = "clown" + item_state = "clown_hat" + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE + +/obj/item/clothing/mask/gas/sexyclown + name = "sexy-clown wig and mask" + desc = "A feminine clown mask for the dabbling crossdressers or female entertainers." + icon_state = "sexyclown" + item_state = "sexyclown" + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE + +/obj/item/clothing/mask/gas/mime + name = "mime mask" + desc = "The traditional mime's mask. It has an eerie facial posture." + icon_state = "mime" + item_state = "mime" + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE + +/obj/item/clothing/mask/gas/monkeymask + name = "monkey mask" + desc = "A mask used when acting as a monkey." + icon_state = "monkeymask" + item_state = "monkeymask" + body_parts_covered = HEAD|FACE|EYES + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE + +/obj/item/clothing/mask/gas/sexymime + name = "sexy mime mask" + desc = "A traditional female mime's mask." + icon_state = "sexymime" + item_state = "sexymime" + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE + +/obj/item/clothing/mask/gas/death_commando + name = "Death Commando Mask" + icon_state = "death_commando_mask" + item_state = "death_commando_mask" + siemens_coefficient = 0.2 + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE + +/obj/item/clothing/mask/gas/cyborg + name = "cyborg visor" + desc = "Beep boop!" + icon_state = "death" + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE + +/obj/item/clothing/mask/gas/owl_mask + name = "owl mask" + desc = "Twoooo!" + icon_state = "owl" + body_parts_covered = HEAD|FACE|EYES + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE + +/obj/item/clothing/mask/gas/vox + name = "vox breathing mask" + desc = "A small oxygen filter for use by Vox" + icon_state = "respirator" + flags_inv = 0 + body_parts_covered = 0 + species_restricted = list(SPECIES_VOX) + filtered_gases = list("phoron", "sleeping_agent", "oxygen") + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE + +/obj/item/clothing/mask/gas/explorer + name = "salvage miner mask" + desc = "Often worn on salvage scavengers to protect their precious lungs from harmful gasses." + icon_state = "gas_mining" + item_state = "gas_mining" + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE \ No newline at end of file diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm new file mode 100644 index 00000000..fa81ae3e --- /dev/null +++ b/code/modules/clothing/masks/miscellaneous.dm @@ -0,0 +1,332 @@ +/obj/item/clothing/mask/muzzle + name = "muzzle" + desc = "To stop that awful noise." + icon_state = "muzzle" + item_state = "muzzle" + body_parts_covered = FACE + w_class = ITEM_SIZE_SMALL + gas_transfer_coefficient = 0.90 + voicechange = 1 + +/obj/item/clothing/mask/muzzle/tape + name = "length of tape" + desc = "It's a robust DIY muzzle!" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "tape_cross" + item_state = null + w_class = ITEM_SIZE_TINY + +/obj/item/clothing/mask/muzzle/Initialize() + . = ..() + say_messages = list("Mmfph!", "Mmmf mrrfff!", "Mmmf mnnf!") + say_verbs = list("mumbles", "says") + +// Clumsy folks can't take the mask off themselves. +/obj/item/clothing/mask/muzzle/attack_hand(mob/user as mob) + if(user.wear_mask == src && !user.IsAdvancedToolUser()) + return 0 + ..() + +/obj/item/clothing/mask/surgical + name = "sterile mask" + desc = "A sterile mask designed to help prevent the spread of diseases." + icon_state = "sterile" + item_state = "sterile" + w_class = ITEM_SIZE_SMALL + body_parts_covered = FACE + item_flags = ITEM_FLAG_FLEXIBLEMATERIAL + gas_transfer_coefficient = 0.90 + permeability_coefficient = 0.01 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 0) + down_gas_transfer_coefficient = 1 + down_body_parts_covered = null + down_icon_state = "steriledown" + pull_mask = 1 + +/obj/item/clothing/mask/fakemoustache + name = "fake moustache" + desc = "Warning: moustache is fake." + icon_state = "fake-moustache" + flags_inv = HIDEFACE + body_parts_covered = 0 + visible_name = "Scoundrel" + +/obj/item/clothing/mask/snorkel + name = "Snorkel" + desc = "For the Swimming Savant." + icon_state = "snorkel" + flags_inv = HIDEFACE + body_parts_covered = 0 + +//scarves (fit in in mask slot) +//None of these actually have on-mob sprites... +/obj/item/clothing/mask/bluescarf + name = "blue neck scarf" + desc = "A blue neck scarf." + icon_state = "blueneckscarf" + item_state = "blueneckscarf" + body_parts_covered = FACE + item_flags = ITEM_FLAG_FLEXIBLEMATERIAL + w_class = ITEM_SIZE_SMALL + gas_transfer_coefficient = 0.90 + +/obj/item/clothing/mask/redscarf + name = "red scarf" + desc = "A red and white checkered neck scarf." + icon_state = "redwhite_scarf" + item_state = "redwhite_scarf" + body_parts_covered = FACE + item_flags = ITEM_FLAG_FLEXIBLEMATERIAL + w_class = ITEM_SIZE_SMALL + gas_transfer_coefficient = 0.90 + +/obj/item/clothing/mask/greenscarf + name = "green scarf" + desc = "A green neck scarf." + icon_state = "green_scarf" + item_state = "green_scarf" + body_parts_covered = FACE + item_flags = ITEM_FLAG_THICKMATERIAL + w_class = ITEM_SIZE_SMALL + gas_transfer_coefficient = 0.90 + +/obj/item/clothing/mask/ninjascarf + name = "ninja scarf" + desc = "A stealthy, dark scarf." + icon_state = "ninja_scarf" + item_state = "ninja_scarf" + body_parts_covered = FACE + item_flags = ITEM_FLAG_THICKMATERIAL + w_class = ITEM_SIZE_SMALL + gas_transfer_coefficient = 0.90 + siemens_coefficient = 0 + +/obj/item/clothing/mask/pig + name = "pig mask" + desc = "A rubber pig mask." + icon_state = "pig" + item_state = "pig" + flags_inv = HIDEFACE|BLOCKHAIR + w_class = ITEM_SIZE_SMALL + siemens_coefficient = 0.9 + body_parts_covered = HEAD|FACE|EYES + +/obj/item/clothing/mask/horsehead + name = "horse head mask" + desc = "A mask made of soft vinyl and latex, representing the head of a horse." + icon_state = "horsehead" + item_state = "horsehead" + flags_inv = HIDEFACE|BLOCKHAIR + body_parts_covered = HEAD|FACE|EYES + w_class = ITEM_SIZE_SMALL + siemens_coefficient = 0.9 + +/obj/item/clothing/mask/horsehead/New() + ..() + // The horse mask doesn't cause voice changes by default, the wizard spell changes the flag as necessary + say_messages = list("NEEIIGGGHHHH!", "NEEEIIIIGHH!", "NEIIIGGHH!", "HAAWWWWW!", "HAAAWWW!") + say_verbs = list("whinnies", "neighs", "says") + + +/obj/item/clothing/mask/ai + name = "camera MIU" + desc = "Allows for direct mental connection to accessible camera networks." + icon_state = "s-ninja" + item_state = "s-ninja" + flags_inv = HIDEFACE + body_parts_covered = FACE|EYES + action_button_name = "Toggle MUI" + origin_tech = list(TECH_DATA = 5, TECH_ENGINEERING = 5) + var/active = FALSE + var/mob/observer/eye/cameranet/eye + +/obj/item/clothing/mask/ai/New() + eye = new(src) + eye.name_sufix = "camera MIU" + ..() + +/obj/item/clothing/mask/ai/Destroy() + if(eye) + if(active) + disengage_mask(eye.owner) + qdel(eye) + eye = null + ..() + +/obj/item/clothing/mask/ai/attack_self(var/mob/user) + if(user.incapacitated()) + return + active = !active + to_chat(user, "You [active ? "" : "dis"]engage \the [src].") + if(active) + engage_mask(user) + else + disengage_mask(user) + +/obj/item/clothing/mask/ai/equipped(var/mob/user, var/slot) + ..(user, slot) + engage_mask(user) + +/obj/item/clothing/mask/ai/dropped(var/mob/user) + ..() + disengage_mask(user) + +/obj/item/clothing/mask/ai/proc/engage_mask(var/mob/user) + if(!active) + return + if(user.get_equipped_item(slot_wear_mask) != src) + return + + eye.possess(user) + to_chat(eye.owner, "You feel disorented for a moment as your mind connects to the camera network.") + +/obj/item/clothing/mask/ai/proc/disengage_mask(var/mob/user) + if(user == eye.owner) + to_chat(eye.owner, "You feel disorented for a moment as your mind disconnects from the camera network.") + eye.release(eye.owner) + eye.forceMove(src) + +/obj/item/clothing/mask/rubber + name = "rubber mask" + desc = "A rubber mask." + icon_state = "balaclava" + flags_inv = HIDEFACE|BLOCKHAIR + siemens_coefficient = 0.9 + body_parts_covered = HEAD|FACE|EYES + +/obj/item/clothing/mask/rubber/trasen + name = "Jack Trasen mask" + desc = "CEO of NanoTrasen corporation. Perfect for scaring the unionizing children." + icon_state = "trasen" + visible_name = "Jack Trasen" + +/obj/item/clothing/mask/rubber/barros + name = "Amaya Barros mask" + desc = "Current Secretary-General of Sol Cental Government. Not that the real thing would visit this pigsty." + icon_state = "barros" + visible_name = "Amaya Barros" + +/obj/item/clothing/mask/rubber/admiral + name = "Admiral Diwali mask" + desc = "Admiral that led the offensive against the Terran Colonial Navy in the Gaia conflict. For bridge officers who wish they'd achieve a fraction of that." + icon_state = "admiral" + visible_name = "Admiral Diwali" + +/obj/item/clothing/mask/rubber/turner + name = "Charles Turner mask" + desc = "Premier of the Terran Colonial Confederation. Probably shouldn't wear this in front of your veteran uncle." + icon_state = "turner" + visible_name = "Charles Turner" + +/obj/item/clothing/mask/rubber/species + name = "human mask" + desc = "A rubber human mask." + icon_state = "manmet" + var/species = SPECIES_HUMAN + +/obj/item/clothing/mask/rubber/species/New() + ..() + visible_name = species + var/datum/species/S = all_species[species] + if(istype(S)) + visible_name = S.get_random_name(pick(MALE,FEMALE)) + +/obj/item/clothing/mask/rubber/species/tajaran + name = "tajara mask" + desc = "A rubber tajara mask." + icon_state = "catmet" + species = SPECIES_TAJARA + +/obj/item/clothing/mask/rubber/species/unathi + name = "unathi mask" + desc = "A rubber unathi mask." + icon_state = "lizmet" + species = SPECIES_UNATHI + +/obj/item/clothing/mask/rubber/species/skrell + name = "skrell mask" + desc = "A rubber skrell mask." + icon_state = "skrellmet" + species = SPECIES_SKRELL + +/obj/item/clothing/mask/spirit + name = "spirit mask" + desc = "An eerie mask of ancient, pitted wood." + icon_state = "spirit_mask" + item_state = "spirit_mask" + flags_inv = HIDEFACE + body_parts_covered = FACE|EYES + +// Bandanas below +/obj/item/clothing/mask/bandana + name = "black bandana" + desc = "A fine bandana with nanotech lining. Can be worn on the head or face." + flags_inv = HIDEFACE + slot_flags = SLOT_MASK|SLOT_HEAD + body_parts_covered = FACE + icon_state = "bandblack" + item_state = "bandblack" + item_flags = ITEM_FLAG_FLEXIBLEMATERIAL + w_class = ITEM_SIZE_SMALL + +/obj/item/clothing/mask/bandana/equipped(var/mob/user, var/slot) + switch(slot) + if(slot_wear_mask) //Mask is the default for all the settings + flags_inv = initial(flags_inv) + body_parts_covered = initial(body_parts_covered) + icon_state = initial(icon_state) + + if(slot_head) + flags_inv = 0 + body_parts_covered = HEAD + icon_state = "[initial(icon_state)]_up" + sprite_sheets = list() + + return ..() + +/obj/item/clothing/mask/bandana/red + name = "red bandana" + icon_state = "bandred" + item_state = "bandred" + +/obj/item/clothing/mask/bandana/blue + name = "blue bandana" + icon_state = "bandblue" + item_state = "bandblue" + +/obj/item/clothing/mask/bandana/green + name = "green bandana" + icon_state = "bandgreen" + item_state = "bandgreen" + +/obj/item/clothing/mask/bandana/gold + name = "gold bandana" + icon_state = "bandgold" + item_state = "bandgold" + +/obj/item/clothing/mask/bandana/orange + name = "orange bandana" + icon_state = "bandorange" + item_state = "bandorange" + +/obj/item/clothing/mask/bandana/purple + name = "purple bandana" + icon_state = "bandpurple" + item_state = "bandpurple" + +/obj/item/clothing/mask/bandana/botany + name = "botany bandana" + icon_state = "bandbotany" + item_state = "bandbotany" + +/obj/item/clothing/mask/bandana/camo + name = "camo bandana" + icon_state = "bandcamo" + item_state = "bandcamo" + +/obj/item/clothing/mask/bandana/skull + name = "skull bandana" + desc = "A fine black bandana with nanotech lining and a skull emblem. Can be worn on the head or face." + icon_state = "bandskull" + item_state = "bandskull" + diff --git a/code/modules/clothing/masks/monitor.dm b/code/modules/clothing/masks/monitor.dm new file mode 100644 index 00000000..3ad3c2bb --- /dev/null +++ b/code/modules/clothing/masks/monitor.dm @@ -0,0 +1,92 @@ +//IPC-face object for FPB. +/obj/item/clothing/mask/monitor + + name = "display monitor" + desc = "A rather clunky old CRT-style display screen, fit for mounting on an optical output." + flags_inv = HIDEEYES + body_parts_covered = EYES + dir = SOUTH + + icon = 'icons/obj/clothing/monitor.dmi' + icon_override = 'icons/mob/monitor_icons.dmi' + icon_state = "ipc_blank" + item_state = null + + var/monitor_state_index = "blank" + var/global/list/monitor_states = list( + "blank" = "ipc_blank", + "pink" = "ipc_pink", + "red" = "ipc_red", + "green" = "ipc_green", + "blue" = "ipc_blue", + "breakout" = "ipc_breakout", + "eight" = "ipc_eight", + "goggles" = "ipc_goggles", + "heart" = "ipc_heart", + "monoeye" = "ipc_monoeye", + "nature" = "ipc_nature", + "orange" = "ipc_orange", + "purple" = "ipc_purple", + "shower" = "ipc_shower", + "static" = "ipc_static", + "yellow" = "ipc_yellow", + "smiley" = "ipc_smiley", + "list" = "ipc_database", + "yes" = "ipc_yes", + "no" = "ipc_no", + "frown" = "ipc_frowny", + "stars" = "ipc_stars", + "crt" = "ipc_crt", + "scroll" = "ipc_scroll", + "console" = "ipc_console", + "rgb" = "ipc_rgb" + ) + +/obj/item/clothing/mask/monitor/set_dir() + dir = SOUTH + return + +/obj/item/clothing/mask/monitor/equipped() + ..() + var/mob/living/carbon/human/H = loc + if(istype(H) && H.wear_mask == src) + canremove = 0 + to_chat(H, "\The [src] connects to your display output.") + +/obj/item/clothing/mask/monitor/dropped() + canremove = 1 + return ..() + +/obj/item/clothing/mask/monitor/mob_can_equip(var/mob/living/carbon/human/user, var/slot) + if (!..()) + return 0 + if(istype(user)) + var/obj/item/organ/external/E = user.organs_by_name[BP_HEAD] + if(istype(E) && (E.robotic >= ORGAN_ROBOT)) + return 1 + to_chat(user, "You must have a robotic head to install this upgrade.") + return 0 + +/obj/item/clothing/mask/monitor/verb/set_monitor_state() + set name = "Set Monitor State" + set desc = "Choose an icon for your monitor." + set category = "IC" + + set src in usr + var/mob/living/carbon/human/H = loc + if(!istype(H) || H != usr) + return + if(H.wear_mask != src) + to_chat(usr, "You have not installed \the [src] yet.") + return + var/choice = input("Select a screen icon.") as null|anything in monitor_states + if(choice) + monitor_state_index = choice + update_icon() + +/obj/item/clothing/mask/monitor/update_icon() + if(!(monitor_state_index in monitor_states)) + monitor_state_index = initial(monitor_state_index) + icon_state = monitor_states[monitor_state_index] + var/mob/living/carbon/human/H = loc + if(istype(H)) H.update_inv_wear_mask() diff --git a/code/modules/clothing/masks/voice.dm b/code/modules/clothing/masks/voice.dm new file mode 100644 index 00000000..efd0572f --- /dev/null +++ b/code/modules/clothing/masks/voice.dm @@ -0,0 +1,31 @@ +/obj/item/voice_changer + name = "voice changer" + desc = "A voice scrambling module. If you can see this, report it as a bug on the tracker." + var/voice //If set and item is present in mask/suit, this name will be used for the wearer's speech. + var/active + +/obj/item/clothing/mask/chameleon/voice + name = "gas mask" + desc = "A face-covering mask that can be connected to an air supply. It seems to house some odd electronics." + var/obj/item/voice_changer/changer + origin_tech = list(TECH_ILLEGAL = 4) + +/obj/item/clothing/mask/chameleon/voice/verb/Toggle_Voice_Changer() + set category = "Object" + set src in usr + + changer.active = !changer.active + to_chat(usr, "You [changer.active ? "enable" : "disable"] the voice-changing module in \the [src].") + +/obj/item/clothing/mask/chameleon/voice/verb/Set_Voice(name as text) + set category = "Object" + set src in usr + + var/voice = sanitize(name, MAX_NAME_LEN) + if(!voice || !length(voice)) return + changer.voice = voice + to_chat(usr, "You are now mimicking [changer.voice].") + +/obj/item/clothing/mask/chameleon/voice/New() + ..() + changer = new(src) diff --git a/code/modules/clothing/rings/material.dm b/code/modules/clothing/rings/material.dm new file mode 100644 index 00000000..74177963 --- /dev/null +++ b/code/modules/clothing/rings/material.dm @@ -0,0 +1,45 @@ +///////////////////////////////////////// +//Material Rings +/obj/item/clothing/ring/material + icon = 'icons/obj/clothing/rings.dmi' + icon_state = "material" + var/material/material + +/obj/item/clothing/ring/material/New(var/newloc, var/new_material) + ..(newloc) + if(!new_material) + new_material = DEFAULT_WALL_MATERIAL + material = get_material_by_name(new_material) + if(!istype(material)) + qdel(src) + return + name = "[material.display_name] ring" + desc = "A ring made from [material.display_name]." + color = material.icon_colour + +/obj/item/clothing/ring/material/get_material() + return material + +/obj/item/clothing/ring/material/wood/New(var/newloc) + ..(newloc, "wood") + +/obj/item/clothing/ring/material/plastic/New(var/newloc) + ..(newloc, "plastic") + +/obj/item/clothing/ring/material/steel/New(var/newloc) + ..(newloc, "steel") + +/obj/item/clothing/ring/material/silver/New(var/newloc) + ..(newloc, "silver") + +/obj/item/clothing/ring/material/gold/New(var/newloc) + ..(newloc, "gold") + +/obj/item/clothing/ring/material/platinum/New(var/newloc) + ..(newloc, "platinum") + +/obj/item/clothing/ring/material/bronze/New(var/newloc) + ..(newloc, "bronze") + +/obj/item/clothing/ring/material/glass/New(var/newloc) + ..(newloc, "glass") diff --git a/code/modules/clothing/rings/rings.dm b/code/modules/clothing/rings/rings.dm new file mode 100644 index 00000000..06173de4 --- /dev/null +++ b/code/modules/clothing/rings/rings.dm @@ -0,0 +1,104 @@ +///////////////////////////////////////// +//Standard Rings +/obj/item/clothing/ring/engagement + name = "engagement ring" + desc = "An engagement ring. It certainly looks expensive." + icon_state = "diamond" + +/obj/item/clothing/ring/engagement/attack_self(mob/user) + user.visible_message("\The [user] gets down on one knee, presenting \the [src].","You get down on one knee, presenting \the [src].") + +/obj/item/clothing/ring/cti + name = "CTI ring" + desc = "A ring commemorating graduation from CTI." + icon_state = "cti-grad" + +/obj/item/clothing/ring/mariner + name = "Mariner University ring" + desc = "A ring commemorating graduation from Mariner University." + icon_state = "mariner-grad" + +///////////////////////////////////////// +//Magic Rings + +/obj/item/clothing/ring/magic + name = "magic ring" + desc = "A strange ring with symbols carved on it in some arcane language." + icon_state = "magic" + +/obj/item/clothing/ring/magic/equipped(var/mob/living/carbon/human/H, var/slot) + ..() + if(istype(H) && slot == SLOT_GLOVES) + H.add_cloaking_source(src) + +/obj/item/clothing/ring/magic/dropped(var/mob/living/carbon/human/H) + if(!..()) + return 0 + + if(istype(H)) + H.remove_cloaking_source(src) + +///////////////////////////////////////// +//Reagent Rings + +/obj/item/clothing/ring/reagent + atom_flags = ATOM_FLAG_OPEN_CONTAINER + origin_tech = list(TECH_MATERIAL = 2, TECH_ILLEGAL = 4) + +/obj/item/clothing/ring/reagent/New() + ..() + create_reagents(15) + +/obj/item/clothing/ring/reagent/equipped(var/mob/living/carbon/human/H) + ..() + if(istype(H) && H.gloves==src) + to_chat(H, "You feel a prick as you slip on the ring.") + + if(reagents.total_volume) + if(H.reagents) + var/contained_reagents = reagents.get_reagents() + var/trans = reagents.trans_to_mob(H, 15, CHEM_BLOOD) + admin_inject_log(usr, H, src, contained_reagents, trans) + return + +//Sleepy Ring +/obj/item/clothing/ring/reagent/sleepy + name = "silver ring" + desc = "A ring made from what appears to be silver." + icon_state = "material" + origin_tech = list(TECH_MATERIAL = 2, TECH_ILLEGAL = 5) + +/obj/item/clothing/ring/reagent/sleepy/New() + ..() + reagents.add_reagent(/datum/reagent/chloralhydrate, 15) // Less than a sleepy-pen, but still enough to knock someone out + +///////////////////////////////////////// +//Seals and Signet Rings +/obj/item/clothing/ring/seal/secgen + name = "Secretary-General's official seal" + desc = "The official seal of the Secretary-General of the Sol Central Government, featured prominently on a silver ring." + icon = 'icons/obj/clothing/rings.dmi' + icon_state = "seal-secgen" + +/obj/item/clothing/ring/seal/mason + name = "masonic ring" + desc = "The Square and Compasses feature prominently on this Masonic ring." + icon = 'icons/obj/clothing/rings.dmi' + icon_state = "seal-masonic" + +/obj/item/clothing/ring/seal/signet + name = "signet ring" + desc = "A signet ring, for when you're too sophisticated to sign letters." + icon = 'icons/obj/clothing/rings.dmi' + icon_state = "seal-signet" + var/nameset = 0 + +/obj/item/clothing/ring/seal/signet/attack_self(mob/user) + if(nameset) + to_chat(user, "The [src] has already been claimed!") + return + + nameset = 1 + to_chat(user, "You claim the [src] as your own!") + name = "[user]'s signet ring" + desc = "A signet ring belonging to [user], for when you're too sophisticated to sign letters." diff --git a/code/modules/clothing/shoes/colour.dm b/code/modules/clothing/shoes/colour.dm new file mode 100644 index 00000000..96eba12c --- /dev/null +++ b/code/modules/clothing/shoes/colour.dm @@ -0,0 +1,132 @@ +/obj/item/clothing/shoes/black + name = "black shoes" + icon_state = "black" + desc = "A pair of black shoes." + + cold_protection = FEET + min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE + heat_protection = FEET + max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE + +/obj/item/clothing/shoes/brown + name = "brown shoes" + desc = "A pair of brown shoes." + icon_state = "brown" + +/obj/item/clothing/shoes/blue + name = "blue shoes" + icon_state = "blue" + +/obj/item/clothing/shoes/green + name = "green shoes" + icon_state = "green" + +/obj/item/clothing/shoes/yellow + name = "yellow shoes" + icon_state = "yellow" + +/obj/item/clothing/shoes/purple + name = "purple shoes" + icon_state = "purple" + +/obj/item/clothing/shoes/brown + name = "brown shoes" + icon_state = "brown" + +/obj/item/clothing/shoes/red + name = "red shoes" + desc = "Stylish red shoes." + icon_state = "red" + +/obj/item/clothing/shoes/white + name = "white shoes" + icon_state = "white" + permeability_coefficient = 0.01 + +/obj/item/clothing/shoes/leather + name = "leather shoes" + desc = "A sturdy pair of leather shoes." + icon_state = "leather" + +/obj/item/clothing/shoes/rainbow + name = "rainbow shoes" + desc = "Very gay shoes." + icon_state = "rain_bow" + +/obj/item/clothing/shoes/orange + name = "orange shoes" + icon_state = "orange" + force = 0 //nerf brig shoe throwing + throwforce = 0 + desc = "A pair of flimsy, cheap shoes. The soles have been made of a soft rubber." + var/obj/item/weapon/handcuffs/chained = null + +/obj/item/clothing/shoes/orange/proc/attach_cuffs(var/obj/item/weapon/handcuffs/cuffs, mob/user as mob) + if (src.chained) return + + user.drop_item() + cuffs.loc = src + src.chained = cuffs + src.slowdown_per_slot[slot_shoes] += 15 + src.icon_state = "orange1" + +/obj/item/clothing/shoes/orange/proc/remove_cuffs(mob/user as mob) + if (!src.chained) return + + user.put_in_hands(src.chained) + src.chained.add_fingerprint(user) + + src.slowdown_per_slot[slot_shoes] -= 15 + src.icon_state = "orange" + src.chained = null + +/obj/item/clothing/shoes/orange/attack_self(mob/user as mob) + ..() + remove_cuffs(user) + +/obj/item/clothing/shoes/orange/attackby(H as obj, mob/user as mob) + ..() + if (istype(H, /obj/item/weapon/handcuffs)) + attach_cuffs(H, user) + +/obj/item/clothing/shoes/flats + name = "flats" + desc = "Sleek flats." + icon_state = "flatswhite" + +/obj/item/clothing/shoes/hightops + name = "white high tops" + desc = "A pair of shoes that extends past the ankle. Based on a centuries-old, timeless design." + icon_state = "whitehi" + +/obj/item/clothing/shoes/hightops/red + name = "red high tops" + icon_state = "redhi" + +/obj/item/clothing/shoes/hightops/brown + name = "brown high tops" + icon_state = "brownhi" + +/obj/item/clothing/shoes/hightops/black + name = "black high tops" + icon_state = "blackhi" + +/obj/item/clothing/shoes/hightops/orange + name = "orange high tops" + icon_state = "orangehi" + +/obj/item/clothing/shoes/hightops/blue + name = "blue high tops" + icon_state = "bluehi" + +/obj/item/clothing/shoes/hightops/green + name = "green high tops" + icon_state = "greenhi" + +/obj/item/clothing/shoes/hightops/purple + name = "purple high tops" + icon_state = "purplehi" + +/obj/item/clothing/shoes/hightops/yellow + name = "yellow high tops" + icon_state = "yellowhi" \ No newline at end of file diff --git a/code/modules/clothing/shoes/jobs.dm b/code/modules/clothing/shoes/jobs.dm new file mode 100644 index 00000000..79c7338b --- /dev/null +++ b/code/modules/clothing/shoes/jobs.dm @@ -0,0 +1,81 @@ +/obj/item/clothing/shoes/galoshes + desc = "Rubber boots." + name = "galoshes" + icon_state = "galoshes" + permeability_coefficient = 0.05 + item_flags = ITEM_FLAG_NOSLIP + can_hold_knife = 1 + species_restricted = null + +/obj/item/clothing/shoes/galoshes/Initialize() + . = ..() + slowdown_per_slot[slot_shoes] = 1 + +/obj/item/clothing/shoes/jackboots + name = "jackboots" + desc = "Tall synthleather boots with an artificial shine." + icon_state = "jackboots" + item_state = "jackboots" + force = 3 + armor = list(melee = 30, bullet = 10, laser = 10, energy = 15, bomb = 20, bio = 0, rad = 0) + siemens_coefficient = 0.7 + can_hold_knife = 1 + cold_protection = FEET + min_cold_protection_temperature = HELMET_MIN_COLD_PROTECTION_TEMPERATURE + var/obj/item/weapon/material/sword/combat_knife/knife = null + +/obj/item/clothing/shoes/jackboots/New() + ..() + knife = new + update_icon() + +/obj/item/clothing/shoes/jackboots/attackby(obj/item/I, mob/user) + . = ..() + if(istype(I, /obj/item/weapon/material/sword/combat_knife)) + if(knife)//We've already got a knife in there, no need for another. + return + user.drop_from_inventory(I) + I.forceMove(src) + knife = I + update_icon() + playsound(src, 'sound/items/holster_knife.ogg', 50, 0, -1) + +/obj/item/clothing/shoes/jackboots/attack_hand(mob/living/user) + if(knife) + user.put_in_active_hand(knife) + knife = null + update_icon() + return + ..() + +/obj/item/clothing/shoes/jackboots/update_icon() + ..()//I am aware this breaks the blood overlay, however I'm not particularly worried about that. We can fix that later. - Matt + var/image/I = image('icons/obj/clothing/accessory_overlays.dmi', "bootknife_0") + if(knife) + I = image('icons/obj/clothing/accessory_overlays.dmi', "bootknife_1") + + overlays += I + + + +/obj/item/clothing/shoes/jackboots/unathi + name = "toe-less jackboots" + desc = "Modified pair of jackboots, particularly comfortable for those species whose toes hold claws." + item_state = "digiboots" + icon_state = "digiboots" + species_restricted = null + +/obj/item/clothing/shoes/workboots + name = "workboots" + desc = "A pair of steel-toed work boots designed for use in industrial settings. Safety first." + icon_state = "workboots" + item_state = "workboots" + armor = list(melee = 40, bullet = 0, laser = 0, energy = 15, bomb = 20, bio = 0, rad = 20) + siemens_coefficient = 0.7 + can_hold_knife = 1 + +/obj/item/clothing/shoes/workboots/toeless + name = "toe-less workboots" + desc = "A pair of toeless work boots designed for use in industrial settings. Modified for species whose toes have claws." + icon_state = "workbootstoeless" + species_restricted = null \ No newline at end of file diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm new file mode 100644 index 00000000..42fe1496 --- /dev/null +++ b/code/modules/clothing/shoes/magboots.dm @@ -0,0 +1,91 @@ +//Note that despite the use of the NOSLIP flag, magboots are still hardcoded to prevent spaceslipping in Check_Shoegrip(). +/obj/item/clothing/shoes/magboots + desc = "Magnetic boots, often used during extravehicular activity to ensure the user remains safely attached to the vehicle. They're large enough to be worn over other footwear." + name = "magboots" + icon_state = "magboots0" + can_hold_knife = 1 + species_restricted = null + force = 3 + overshoes = 1 + var/magpulse = 0 + var/icon_base = "magboots" + action_button_name = "Toggle Magboots" + var/obj/item/clothing/shoes/shoes = null //Undershoes + var/mob/living/carbon/human/wearer = null //For shoe procs + center_of_mass = null + randpixel = 0 + +/obj/item/clothing/shoes/magboots/proc/set_slowdown() + slowdown_per_slot[slot_shoes] = shoes? max(0, shoes.slowdown_per_slot[slot_shoes]): 0 //So you can't put on magboots to make you walk faster. + if (magpulse) + slowdown_per_slot[slot_shoes] += 3 + +/obj/item/clothing/shoes/magboots/attack_self(mob/user) + if(magpulse) + item_flags &= ~ITEM_FLAG_NOSLIP + magpulse = 0 + set_slowdown() + force = 3 + if(icon_base) icon_state = "[icon_base]0" + to_chat(user, "You disable the mag-pulse traction system.") + else + item_flags |= ITEM_FLAG_NOSLIP + magpulse = 1 + set_slowdown() + force = 5 + if(icon_base) icon_state = "[icon_base]1" + playsound(get_turf(src), 'sound/effects/magnetclamp.ogg', 20) + to_chat(user, "You enable the mag-pulse traction system.") + user.update_inv_shoes() //so our mob-overlays update + user.update_action_buttons() + user.update_floating() + +/obj/item/clothing/shoes/magboots/mob_can_equip(mob/user) + var/mob/living/carbon/human/H = user + + if(H.shoes) + shoes = H.shoes + if(shoes.overshoes) + to_chat(user, "You are unable to wear \the [src] as \the [H.shoes] are in the way.") + shoes = null + return 0 + H.drop_from_inventory(shoes) //Remove the old shoes so you can put on the magboots. + shoes.forceMove(src) + + if(!..()) + if(shoes) //Put the old shoes back on if the check fails. + if(H.equip_to_slot_if_possible(shoes, slot_shoes)) + src.shoes = null + return 0 + + if (shoes) + to_chat(user, "You slip \the [src] on over \the [shoes].") + set_slowdown() + wearer = H //TODO clean this up + return 1 + +/obj/item/clothing/shoes/magboots/equipped() + ..() + var/mob/M = src.loc + if(istype(M)) + M.update_floating() + +/obj/item/clothing/shoes/magboots/dropped() + ..() + if(!wearer) + return + + var/mob/living/carbon/human/H = wearer + if(shoes && istype(H)) + if(!H.equip_to_slot_if_possible(shoes, slot_shoes)) + shoes.forceMove(get_turf(src)) + src.shoes = null + wearer.update_floating() + wearer = null + +/obj/item/clothing/shoes/magboots/examine(mob/user) + . = ..(user) + var/state = "disabled" + if(item_flags & ITEM_FLAG_NOSLIP) + state = "enabled" + to_chat(user, "Its mag-pulse traction system appears to be [state].") diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm new file mode 100644 index 00000000..a018203e --- /dev/null +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -0,0 +1,192 @@ +/obj/item/clothing/shoes/syndigaloshes + desc = "A pair of brown shoes. They seem to have extra grip." + name = "brown shoes" + icon_state = "brown" + item_state = "brown" + permeability_coefficient = 0.05 + item_flags = ITEM_FLAG_NOSLIP + origin_tech = list(TECH_ILLEGAL = 3) + var/list/clothing_choices = list() + siemens_coefficient = 0.8 + species_restricted = null + +/obj/item/clothing/shoes/mime + name = "mime shoes" + icon_state = "mime" + +/obj/item/clothing/shoes/swat + name = "\improper SWAT boots" + desc = "When you want to turn up the heat." + icon_state = "swat" + force = 3 + armor = list(melee = 80, bullet = 60, laser = 60,energy = 25, bomb = 50, bio = 10, rad = 0) + item_flags = ITEM_FLAG_NOSLIP + siemens_coefficient = 0.6 + can_hold_knife = 1 + +/obj/item/clothing/shoes/combat //Basically SWAT shoes combined with galoshes. + name = "combat boots" + desc = "When you REALLY want to turn up the heat." + icon_state = "jungle" + force = 5 + armor = list(melee = 80, bullet = 60, laser = 60,energy = 25, bomb = 50, bio = 10, rad = 0) + item_flags = ITEM_FLAG_NOSLIP + siemens_coefficient = 0.6 + can_hold_knife = 1 + + cold_protection = FEET + min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE + heat_protection = FEET + max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE + +/obj/item/clothing/shoes/jungleboots + name = "jungle boots" + desc = "A pair of durable brown boots. Waterproofed for use planetside." + icon_state = "jungle" + force = 3 + armor = list(melee = 30, bullet = 10, laser = 10, energy = 15, bomb = 20, bio = 10, rad = 0) + siemens_coefficient = 0.7 + can_hold_knife = 1 + +/obj/item/clothing/shoes/desertboots + name = "desert boots" + desc = "A pair of durable tan boots. Designed for use in hot climates." + icon_state = "desert" + force = 3 + armor = list(melee = 30, bullet = 10, laser = 10, energy = 15, bomb = 20, bio = 10, rad = 0) + siemens_coefficient = 0.7 + can_hold_knife = 1 + +/obj/item/clothing/shoes/dutyboots + name = "duty boots" + desc = "A pair of steel-toed synthleather boots with a mirror shine." + icon_state = "duty" + armor = list(melee = 40, bullet = 0, laser = 0, energy = 15, bomb = 20, bio = 0, rad = 20) + siemens_coefficient = 0.7 + can_hold_knife = 1 + +/obj/item/clothing/shoes/tactical + name = "tactical boots" + desc = "Tan boots with extra padding and armor." + icon_state = "desert" + force = 3 + armor = list(melee = 40, bullet = 30, laser = 40,energy = 25, bomb = 50, bio = 0, rad = 0) + siemens_coefficient = 0.7 + can_hold_knife = 1 + +/obj/item/clothing/shoes/dress + name = "dress shoes" + desc = "The height of fashion, and they're pre-polished!" + icon_state = "laceups" + +/obj/item/clothing/shoes/dress/white + name = "white dress shoes" + desc = "Brilliantly white shoes, not a spot on them." + icon_state = "whitedress" + +/obj/item/clothing/shoes/sandal + desc = "A pair of rather plain, wooden sandals." + name = "sandals" + icon_state = "wizard" + species_restricted = null + body_parts_covered = 0 + + wizard_garb = 1 + +/obj/item/clothing/shoes/sandal/marisa + desc = "A pair of magic, black shoes." + name = "magic shoes" + icon_state = "black" + body_parts_covered = FEET + +/obj/item/clothing/shoes/clown_shoes + desc = "The prankster's standard-issue clowning shoes. Damn they're huge!" + name = "clown shoes" + icon_state = "clown" + item_state = "clown" + force = 0 + var/footstep = 1 //used for squeeks whilst walking + species_restricted = null + +/obj/item/clothing/shoes/clown_shoes/New() + ..() + slowdown_per_slot[slot_shoes] = 1 + +/obj/item/clothing/shoes/clown_shoes/handle_movement(var/turf/walking, var/running) + if(running) + if(footstep >= 2) + footstep = 0 + playsound(src, "clownstep", 50, 1) // this will get annoying very fast. + else + footstep++ + else + playsound(src, "clownstep", 20, 1) + +/obj/item/clothing/shoes/cult + name = "boots" + desc = "A pair of boots worn by the followers of Nar-Sie." + icon_state = "cult" + item_state = "cult" + force = 2 + siemens_coefficient = 0.7 + + cold_protection = FEET + min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE + heat_protection = FEET + max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE + species_restricted = null + +/obj/item/clothing/shoes/cyborg + name = "cyborg boots" + desc = "Shoes for a cyborg costume." + icon_state = "boots" + +/obj/item/clothing/shoes/slippers + name = "bunny slippers" + desc = "Fluffy!" + icon_state = "slippers" + item_state = "slippers" + force = 0 + species_restricted = null + w_class = ITEM_SIZE_SMALL + +/obj/item/clothing/shoes/slippers_worn + name = "worn bunny slippers" + desc = "Fluffy..." + icon_state = "slippers_worn" + item_state = "slippers_worn" + force = 0 + w_class = ITEM_SIZE_SMALL + +/obj/item/clothing/shoes/laceup + name = "laceup shoes" + desc = "The height of fashion, and they're pre-polished!" + icon_state = "laceups" + +/obj/item/clothing/shoes/swimmingfins + desc = "Help you swim good." + name = "swimming fins" + icon_state = "flippers" + item_flags = ITEM_FLAG_NOSLIP + species_restricted = null + +/obj/item/clothing/shoes/swimmingfins/New() + ..() + slowdown_per_slot[slot_shoes] = 1 + +/obj/item/clothing/shoes/athletic + name = "athletic shoes" + desc = "A pair of sleek atheletic shoes. Made by and for the sporty types." + icon_state = "sportshoe" + +/obj/item/clothing/shoes/jackboots/inquisitor + name = "noble boots" + desc = "A pair of high quality black leather boots for stomping heretics faces in." + icon_state = "noble-boots" + item_state = "noble-boots" + +/obj/item/clothing/shoes/timbs + name = "Trench Timbs" + desc = "DAMN! IS THAT SOLDIER ROCKING THE FUCKING TIMBS???!! no word of lie he do be looking fine dough" + icon_state = "timbs" + item_state = "timbs" \ No newline at end of file diff --git a/code/modules/clothing/spacesuits/alien.dm b/code/modules/clothing/spacesuits/alien.dm new file mode 100644 index 00000000..6c2db3fa --- /dev/null +++ b/code/modules/clothing/spacesuits/alien.dm @@ -0,0 +1,172 @@ +//Skrell space gear. Sleek like a wetsuit. +/obj/item/clothing/head/helmet/space/skrell + name = "Skrellian helmet" + desc = "Smoothly contoured and polished to a shine. Still looks like a fishbowl." + armor = list(melee = 20, bullet = 20, laser = 50,energy = 50, bomb = 50, bio = 100, rad = 100) + max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE + species_restricted = list(SPECIES_SKRELL,SPECIES_HUMAN) + +/obj/item/clothing/head/helmet/space/skrell/white + icon_state = "skrell_helmet_white" + +/obj/item/clothing/head/helmet/space/skrell/black + icon_state = "skrell_helmet_black" + +/obj/item/clothing/suit/space/skrell + name = "Skrellian voidsuit" + desc = "Seems like a wetsuit with reinforced plating seamlessly attached to it. Very chic." + armor = list(melee = 20, bullet = 20, laser = 50,energy = 50, bomb = 50, bio = 100, rad = 100) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/weapon/storage/ore,/obj/item/device/t_scanner,/obj/item/weapon/pickaxe, /obj/item/weapon/rcd) + heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE + species_restricted = list(SPECIES_SKRELL,SPECIES_HUMAN) + +/obj/item/clothing/suit/space/skrell/white + icon_state = "skrell_suit_white" + +/obj/item/clothing/suit/space/skrell/black + icon_state = "skrell_suit_black" + +// Vox space gear (vaccuum suit, low pressure armour) +// Can't be equipped by any other species due to bone structure and vox cybernetics. +/obj/item/clothing/suit/space/vox + w_class = ITEM_SIZE_NORMAL + allowed = list(/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy/sword,/obj/item/weapon/handcuffs,/obj/item/weapon/tank) + armor = list(melee = 60, bullet = 50, laser = 40,energy = 15, bomb = 30, bio = 30, rad = 30) + siemens_coefficient = 0.6 + heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE + species_restricted = list(SPECIES_VOX) + +/obj/item/clothing/suit/space/vox/New() + ..() + slowdown_per_slot[slot_wear_suit] = 2 + +/obj/item/clothing/head/helmet/space/vox + armor = list(melee = 60, bullet = 50, laser = 40, energy = 15, bomb = 30, bio = 30, rad = 30) + siemens_coefficient = 0.6 + item_flags = ITEM_FLAG_STOPPRESSUREDAMAGE + flags_inv = 0 + species_restricted = list(SPECIES_VOX) + +/obj/item/clothing/head/helmet/space/vox/pressure + name = "alien helmet" + icon_state = "vox-pressure" + desc = "Hey, wasn't this a prop in \'The Abyss\'?" + +/obj/item/clothing/suit/space/vox/pressure + name = "alien pressure suit" + icon_state = "vox-pressure" + desc = "A huge, armoured, pressurized suit, designed for distinctly nonhuman proportions." + +/obj/item/clothing/head/helmet/space/vox/carapace + name = "alien visor" + icon_state = "vox-carapace" + desc = "A glowing visor, perhaps stolen from a depressed Cylon." + +/obj/item/clothing/suit/space/vox/carapace + name = "alien carapace armour" + icon_state = "vox-carapace" + desc = "An armoured, segmented carapace with glowing purple lights. It looks pretty run-down." + +/obj/item/clothing/head/helmet/space/vox/stealth + name = "alien stealth helmet" + icon_state = "vox-stealth" + desc = "A smoothly contoured, matte-black alien helmet." + +/obj/item/clothing/suit/space/vox/stealth + name = "alien stealth suit" + icon_state = "vox-stealth" + desc = "A sleek black suit. It seems to have a tail, and is very heavy." + +/obj/item/clothing/head/helmet/space/vox/medic + name = "alien goggled helmet" + icon_state = "vox-medic" + desc = "An alien helmet with enormous goggled lenses." + +/obj/item/clothing/suit/space/vox/medic + name = "alien armour" + icon_state = "vox-medic" + desc = "An almost organic looking nonhuman pressure suit." + +/obj/item/clothing/under/vox + has_sensor = 0 + species_restricted = list(SPECIES_VOX) + +/obj/item/clothing/under/vox/vox_casual + name = "alien clothing" + desc = "This doesn't look very comfortable." + icon_state = "vox-casual-1" + item_state = "vox-casual-1" + body_parts_covered = LEGS + +/obj/item/clothing/under/vox/vox_robes + name = "alien robes" + desc = "Weird and flowing!" + icon_state = "vox-casual-2" + item_state = "vox-casual-2" + +/obj/item/clothing/gloves/vox + desc = "These bizarre gauntlets seem to be fitted for... bird claws?" + name = "insulated gauntlets" + icon_state = "gloves-vox" + item_state = "gloves-vox" + siemens_coefficient = 0 + permeability_coefficient = 0.05 + species_restricted = list(SPECIES_VOX) + +/obj/item/clothing/shoes/magboots/vox + + desc = "A pair of heavy, jagged armoured foot pieces, seemingly suitable for a velociraptor." + name = "vox magclaws" + item_state = "boots-vox" + icon_state = "boots-vox" + species_restricted = list(SPECIES_VOX) + + action_button_name = "Toggle the magclaws" + +/obj/item/clothing/shoes/magboots/vox/attack_self(mob/user) + if(src.magpulse) + item_flags &= ~ITEM_FLAG_NOSLIP + magpulse = 0 + canremove = 1 + to_chat(user, "You relax your deathgrip on the flooring.") + else + //make sure these can only be used when equipped. + if(!ishuman(user)) + return + var/mob/living/carbon/human/H = user + if (H.shoes != src) + to_chat(user, "You will have to put on the [src] before you can do that.") + return + + item_flags |= ITEM_FLAG_NOSLIP + magpulse = 1 + canremove = 0 //kinda hard to take off magclaws when you are gripping them tightly. + to_chat(user, "You dig your claws deeply into the flooring, bracing yourself.") + to_chat(user, "It would be hard to take off the [src] without relaxing your grip first.") + user.update_action_buttons() + +//In case they somehow come off while enabled. +/obj/item/clothing/shoes/magboots/vox/dropped(mob/user as mob) + ..() + if(src.magpulse) + user.visible_message("The [src] go limp as they are removed from [usr]'s feet.", "The [src] go limp as they are removed from your feet.") + item_flags &= ~ITEM_FLAG_NOSLIP + magpulse = 0 + canremove = 1 + +/obj/item/clothing/shoes/magboots/vox/examine(mob/user) + . = ..(user) + if (magpulse) + to_chat(user, "It would be hard to take these off without relaxing your grip first.")//theoretically this message should only be seen by the wearer when the claws are equipped. + + +/obj/item/clothing/gloves/nabber + desc = "These insulated gloves have only three fingers." + name = "three-fingered insulated gloves" + icon_state = "white-glove-nabber" + color = COLOR_YELLOW + siemens_coefficient = 0 + permeability_coefficient = 0.05 + species_restricted = list(SPECIES_NABBER) diff --git a/code/modules/clothing/spacesuits/breaches.dm b/code/modules/clothing/spacesuits/breaches.dm new file mode 100644 index 00000000..38f7f109 --- /dev/null +++ b/code/modules/clothing/spacesuits/breaches.dm @@ -0,0 +1,222 @@ +//A 'wound' system for space suits. +//Breaches greatly increase the amount of lost gas and decrease the armour rating of the suit. +//They can be healed with plastic or metal sheeting. + +/datum/breach + var/class = 0 // Size. Lower is smaller. Uses floating point values! + var/descriptor // 'gaping hole' etc. + var/damtype = BURN // Punctured or melted + var/obj/item/clothing/suit/space/holder // Suit containing the list of breaches holding this instance. + var/global/list/breach_brute_descriptors = list( + "tiny puncture", + "ragged tear", + "large split", + "huge tear", + "gaping wound" + ) + + var/global/list/breach_burn_descriptors = list( + "small burn", + "melted patch", + "sizable burn", + "large scorched area", + "huge scorched area" + ) + +/obj/item/clothing/suit/space + + var/can_breach = 1 // Set to 0 to disregard all breaching. + var/list/breaches = list() // Breach datum container. + var/resilience = 0.2 // Multiplier that turns damage into breach class. 1 is 100% of damage to breach, 0.1 is 10%. 0.2 -> 50 brute/burn damage to cause 10 breach damage + var/breach_threshold = 3 // Min damage before a breach is possible. Damage is subtracted by this amount, it determines the "hardness" of the suit. + var/damage = 0 // Current total damage + var/brute_damage = 0 // Specifically brute damage. + var/burn_damage = 0 // Specifically burn damage. + +/datum/breach/proc/update_descriptor() + + //Sanity... + class = between(1, round(class), 5) + //Apply the correct descriptor. + if(damtype == BURN) + descriptor = breach_burn_descriptors[class] + else if(damtype == BRUTE) + descriptor = breach_brute_descriptors[class] + +//Repair a certain amount of brute or burn damage to the suit. +/obj/item/clothing/suit/space/proc/repair_breaches(var/damtype, var/amount, var/mob/user) + + if(!can_breach || !breaches || !breaches.len || !damage) + to_chat(user, "There are no breaches to repair on \the [src].") + return + + var/list/valid_breaches = list() + + for(var/datum/breach/B in breaches) + if(B.damtype == damtype) + valid_breaches += B + + if(!valid_breaches.len) + to_chat(user, "There are no breaches to repair on \the [src].") + return + + var/amount_left = amount + for(var/datum/breach/B in valid_breaches) + if(!amount_left) break + + if(B.class <= amount_left) + amount_left -= B.class + valid_breaches -= B + breaches -= B + else + B.class -= amount_left + amount_left = 0 + B.update_descriptor() + + user.visible_message("[user] patches some of the damage on \the [src].") + calc_breach_damage() + +/obj/item/clothing/suit/space/proc/create_breaches(var/damtype, var/amount) + + amount -= src.breach_threshold + amount *= src.resilience + + if(!can_breach || amount <= 0) + return + + if(!breaches) + breaches = list() + + if(damage > 25) return //We don't need to keep tracking it when it's at 250% pressure loss, really. + + if(!loc) return + var/turf/T = get_turf(src) + if(!T) return + + //Increase existing breaches. + for(var/datum/breach/existing in breaches) + + if(existing.damtype != damtype) + continue + + //keep in mind that 10 breach damage == full pressure loss. + //a breach can have at most 5 breach damage + if (existing.class < 5) + var/needs = 5 - existing.class + if(amount < needs) + existing.class += amount + amount = 0 + else + existing.class = 5 + amount -= needs + + if(existing.damtype == BRUTE) + T.visible_message("\The [existing.descriptor] on [src] gapes wider!") + else if(existing.damtype == BURN) + T.visible_message("\The [existing.descriptor] on [src] widens!") + + if (amount) + //Spawn a new breach. + var/datum/breach/B = new() + breaches += B + + B.class = min(amount,5) + + B.damtype = damtype + B.update_descriptor() + B.holder = src + + if(B.damtype == BRUTE) + T.visible_message("\A [B.descriptor] opens up on [src]!") + else if(B.damtype == BURN) + T.visible_message("\A [B.descriptor] marks the surface of [src]!") + + calc_breach_damage() + +//Calculates the current extent of the damage to the suit. +/obj/item/clothing/suit/space/proc/calc_breach_damage() + + damage = 0 + brute_damage = 0 + burn_damage = 0 + + if(!can_breach || !breaches || !breaches.len) + SetName(initial(name)) + return 0 + + for(var/datum/breach/B in breaches) + if(!B.class) + src.breaches -= B + qdel(B) + else + damage += B.class + if(B.damtype == BRUTE) + brute_damage += B.class + else if(B.damtype == BURN) + burn_damage += B.class + + if(damage >= 3) + if(brute_damage >= 3 && brute_damage > burn_damage) + SetName("punctured [initial(name)]") + else if(burn_damage >= 3 && burn_damage > brute_damage) + SetName("scorched [initial(name)]") + else + SetName("damaged [initial(name)]") + else + SetName(initial(name)) + + return damage + +//Handles repairs (and also upgrades). + +/obj/item/clothing/suit/space/attackby(obj/item/W as obj, mob/user as mob) + if(istype(W,/obj/item/stack/material)) + var/repair_power = 0 + switch(W.get_material_name()) + if(DEFAULT_WALL_MATERIAL) + repair_power = 2 + if("plastic") + repair_power = 1 + + if(!repair_power) + return + + if(istype(src.loc,/mob/living)) + to_chat(user, "How do you intend to patch a hardsuit while someone is wearing it?") + return + + if(!damage || !burn_damage) + to_chat(user, "There is no surface damage on \the [src] to repair.") + return + + var/obj/item/stack/P = W + var/use_amt = min(P.get_amount(), 3) + if(use_amt && P.use(use_amt)) + repair_breaches(BURN, use_amt * repair_power, user) + return + + else if(isWelder(W)) + + if(istype(src.loc,/mob/living)) + to_chat(user, "How do you intend to patch a hardsuit while someone is wearing it?") + return + + if (!damage || ! brute_damage) + to_chat(user, "There is no structural damage on \the [src] to repair.") + return + + var/obj/item/weapon/weldingtool/WT = W + if(!WT.remove_fuel(5)) + to_chat(user, "You need more welding fuel to repair this suit.") + return + + repair_breaches(BRUTE, 3, user) + return + + ..() + +/obj/item/clothing/suit/space/examine(mob/user) + . = ..(user) + if(can_breach && breaches && breaches.len) + for(var/datum/breach/B in breaches) + to_chat(user, "It has \a [B.descriptor].") diff --git a/code/modules/clothing/spacesuits/captain.dm b/code/modules/clothing/spacesuits/captain.dm new file mode 100644 index 00000000..b28f2813 --- /dev/null +++ b/code/modules/clothing/spacesuits/captain.dm @@ -0,0 +1,35 @@ +//Captain's Spacesuit +/obj/item/clothing/head/helmet/space/capspace + name = "space helmet" + icon_state = "capspace" + item_state = "capspace" + desc = "A special helmet designed for work in a hazardous, low-pressure environment. Only for the most fashionable of military figureheads." + item_flags = ITEM_FLAG_STOPPRESSUREDAMAGE + flags_inv = HIDEFACE|BLOCKHAIR + permeability_coefficient = 0.01 + armor = list(melee = 65, bullet = 50, laser = 50,energy = 25, bomb = 50, bio = 100, rad = 50) + +//Captain's space suit This is not the proper path but I don't currently know enough about how this all works to mess with it. +/obj/item/clothing/suit/armor/captain + name = "Captain's armor" + desc = "A bulky, heavy-duty piece of exclusive corporate armor. YOU are in charge!" + icon_state = "caparmor" + item_state_slots = list( + slot_l_hand_str = "capspacesuit", + slot_r_hand_str = "capspacesuit", + ) + w_class = ITEM_SIZE_HUGE + gas_transfer_coefficient = 0.01 + permeability_coefficient = 0.02 + item_flags = ITEM_FLAG_STOPPRESSUREDAMAGE + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS + allowed = list(/obj/item/weapon/tank/emergency, /obj/item/device/flashlight,/obj/item/weapon/gun/energy, /obj/item/weapon/gun/projectile, /obj/item/ammo_magazine, /obj/item/ammo_casing, /obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs) + armor = list(melee = 65, bullet = 50, laser = 50, energy = 25, bomb = 50, bio = 100, rad = 50) + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL + cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + siemens_coefficient = 0.7 + +/obj/item/clothing/suit/armor/captain/New() + ..() + slowdown_per_slot[slot_wear_suit] = 1.5 diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm new file mode 100644 index 00000000..36c8a2bb --- /dev/null +++ b/code/modules/clothing/spacesuits/miscellaneous.dm @@ -0,0 +1,111 @@ +//Captain's Spacesuit +/obj/item/clothing/head/helmet/space/capspace + name = "space helmet" + icon_state = "capspace" + item_state = "capspace" + desc = "A special helmet designed for work in a hazardous, low-pressure environment. Only for the most fashionable of military figureheads." + flags_inv = HIDEFACE + permeability_coefficient = 0.01 + armor = list(melee = 65, bullet = 50, laser = 50,energy = 25, bomb = 50, bio = 100, rad = 50) + +//Captain's space suit This is not the proper path but I don't currently know enough about how this all works to mess with it. +/obj/item/clothing/suit/armor/captain + name = "Captain's armor" + desc = "A bulky, heavy-duty piece of exclusive corporate armor. YOU are in charge!" + icon_state = "caparmor" + item_state_slots = list( + slot_l_hand_str = "capspacesuit", + slot_r_hand_str = "capspacesuit", + ) + w_class = ITEM_SIZE_HUGE + gas_transfer_coefficient = 0.01 + permeability_coefficient = 0 + item_flags = ITEM_FLAG_STOPPRESSUREDAMAGE + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS + allowed = list(/obj/item/weapon/tank/emergency, /obj/item/device/flashlight,/obj/item/weapon/gun/energy, /obj/item/weapon/gun/projectile, /obj/item/ammo_magazine, /obj/item/ammo_casing, /obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs) + armor = list(melee = 65, bullet = 50, laser = 50, energy = 25, bomb = 50, bio = 100, rad = 50) + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL + cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + siemens_coefficient = 0.7 + +/obj/item/clothing/suit/armor/captain/New() + ..() + slowdown_per_slot[slot_wear_suit] = 1.5 + +//Deathsquad suit +/obj/item/clothing/head/helmet/space/deathsquad + name = "deathsquad helmet" + desc = "That's not red paint. That's real blood." + icon_state = "deathsquad" + item_state_slots = list( + slot_l_hand_str = "syndicate-helm-black-red", + slot_r_hand_str = "syndicate-helm-black-red", + ) + armor = list(melee = 65, bullet = 55, laser = 35,energy = 20, bomb = 30, bio = 100, rad = 60) + item_flags = ITEM_FLAG_STOPPRESSUREDAMAGE | ITEM_FLAG_THICKMATERIAL + flags_inv = BLOCKHAIR + siemens_coefficient = 0.6 + +//Space santa outfit suit +/obj/item/clothing/head/helmet/space/santahat + name = "Santa's hat" + desc = "Ho ho ho. Merrry X-mas!" + icon_state = "santahat" + item_state = "santahat" + item_flags = ITEM_FLAG_STOPPRESSUREDAMAGE + flags_inv = BLOCKHAIR + body_parts_covered = HEAD + +/obj/item/clothing/suit/space/santa + name = "Santa's suit" + desc = "Festive!" + icon_state = "santa" + item_flags = ITEM_FLAG_STOPPRESSUREDAMAGE + allowed = list(/obj/item) //for stuffing exta special presents + +/obj/item/clothing/suit/space/santa/New() + ..() + slowdown_per_slot[slot_wear_suit] = 0 + +//Space pirate outfit +/obj/item/clothing/head/helmet/pirate + name = "pirate hat" + desc = "Yarr." + icon_state = "pirate" + item_state = "pirate" + armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 30, rad = 30) + flags_inv = BLOCKHAIR + body_parts_covered = 0 + siemens_coefficient = 0.9 + +/obj/item/clothing/suit/space/pirate + name = "pirate coat" + desc = "Yarr." + icon_state = "pirate" + w_class = ITEM_SIZE_NORMAL + allowed = list(/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/tank/emergency) + armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 30, rad = 30) + siemens_coefficient = 0.9 + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + +/obj/item/clothing/suit/space/pirate/New() + ..() + slowdown_per_slot[slot_wear_suit] = 0 + +//Orange emergency space suit +/obj/item/clothing/head/helmet/space/emergency + name = "Emergency Space Helmet" + 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" + icon_state = "syndicate-orange" + desc = "A thin, ungainly softsuit colored in blaze orange for rescuers to easily locate, looks pretty fragile." + +/obj/item/clothing/suit/space/emergency/New() + ..() + slowdown_per_slot[slot_wear_suit] = 4 diff --git a/code/modules/clothing/spacesuits/spacesuits.dm b/code/modules/clothing/spacesuits/spacesuits.dm new file mode 100644 index 00000000..bcbd3fc2 --- /dev/null +++ b/code/modules/clothing/spacesuits/spacesuits.dm @@ -0,0 +1,95 @@ +//Spacesuit +//Note: Everything in modules/clothing/spacesuits should have the entire suit grouped together. +// Meaning the the suit is defined directly after the corrisponding helmet. Just like below! + +/obj/item/clothing/head/helmet/space + name = "Space helmet" + icon_state = "space" + desc = "A special helmet designed for work in a hazardous, low-pressure environment." + item_flags = ITEM_FLAG_STOPPRESSUREDAMAGE | ITEM_FLAG_THICKMATERIAL | ITEM_FLAG_AIRTIGHT + flags_inv = BLOCKHAIR + item_state_slots = list( + slot_l_hand_str = "s_helmet", + slot_r_hand_str = "s_helmet", + ) + permeability_coefficient = 0 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 50) + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|BLOCKHAIR + body_parts_covered = HEAD|FACE|EYES + cold_protection = HEAD + min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE + siemens_coefficient = 0.9 + center_of_mass = null + randpixel = 0 + species_restricted = list("exclude", SPECIES_NABBER, SPECIES_DIONA, "Xenophage") + flash_protection = FLASH_PROTECTION_MAJOR + + var/obj/machinery/camera/camera + + action_button_name = "Toggle Helmet Light" + light_overlay = "helmet_light" + brightness_on = 4 + on = 0 + +/obj/item/clothing/head/helmet/space/Destroy() + if(camera && !ispath(camera)) + QDEL_NULL(camera) + . = ..() + +/obj/item/clothing/head/helmet/space/Initialize() + . = ..() + if(camera) + verbs += /obj/item/clothing/head/helmet/space/proc/toggle_camera + +/obj/item/clothing/head/helmet/space/proc/toggle_camera() + set name = "Toggle Helmet Camera" + set category = "Object" + set src in usr + + if(ispath(camera)) + camera = new camera(src) + camera.set_status(0) + + if(camera) + camera.set_status(!camera.status) + if(camera.status) + camera.c_tag = FindNameFromID(usr) + to_chat(usr, "User scanned as [camera.c_tag]. Camera activated.") + else + to_chat(usr, "Camera deactivated.") + +/obj/item/clothing/head/helmet/space/examine(var/mob/user) + if(..(user, 1) && camera) + to_chat(user, "This helmet has a built-in camera. Its [!ispath(camera) && camera.status ? "" : "in"]active.") + +/obj/item/clothing/suit/space + name = "Space suit" + desc = "A suit that protects against low pressure environments." + icon_state = "space" + item_icons = list( + slot_l_hand_str = 'icons/mob/onmob/items/lefthand_spacesuits.dmi', + slot_r_hand_str = 'icons/mob/onmob/items/righthand_spacesuits.dmi', + ) + item_state_slots = list( + slot_l_hand_str = "s_suit", + slot_r_hand_str = "s_suit", + ) + w_class = ITEM_SIZE_LARGE//large item + gas_transfer_coefficient = 0 + permeability_coefficient = 0 + item_flags = ITEM_FLAG_STOPPRESSUREDAMAGE | ITEM_FLAG_THICKMATERIAL + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/emergency,/obj/item/device/suit_cooling_unit) + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 50) + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL + cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + siemens_coefficient = 0.9 + center_of_mass = null + randpixel = 0 + species_restricted = list("exclude", SPECIES_NABBER, SPECIES_DIONA, "Xenophage") + valid_accessory_slots = list(ACCESSORY_SLOT_INSIGNIA) + +/obj/item/clothing/suit/space/New() + ..() + slowdown_per_slot[slot_wear_suit] = 1 diff --git a/code/modules/clothing/spacesuits/syndi.dm b/code/modules/clothing/spacesuits/syndi.dm new file mode 100644 index 00000000..23012dfc --- /dev/null +++ b/code/modules/clothing/spacesuits/syndi.dm @@ -0,0 +1,191 @@ +//Regular syndicate space suit +/obj/item/clothing/head/helmet/space/syndicate + name = "red space helmet" + icon_state = "syndicate" + item_state = "syndicate" + desc = "A crimson helmet sporting clean lines and durable plating. Engineered to look menacing." + armor = list(melee = 60, bullet = 50, laser = 50,energy = 15, bomb = 30, bio = 30, rad = 30) + siemens_coefficient = 0.3 + +/obj/item/clothing/suit/space/syndicate + name = "red space suit" + icon_state = "syndicate" + item_state_slots = list( + slot_l_hand_str = "space_suit_syndicate", + slot_r_hand_str = "space_suit_syndicate", + ) + desc = "A crimson spacesuit sporting clean lines and durable plating. Robust, reliable, and slightly suspicious." + w_class = ITEM_SIZE_NORMAL + allowed = list(/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy/sword,/obj/item/weapon/handcuffs,/obj/item/weapon/tank/emergency) + armor = list(melee = 60, bullet = 50, laser = 50,energy = 15, bomb = 30, bio = 30, rad = 30) + siemens_coefficient = 0.3 + +/obj/item/clothing/suit/space/syndicate/New() + ..() + slowdown_per_slot[slot_wear_suit] = 1 + +//Green syndicate space suit +/obj/item/clothing/head/helmet/space/syndicate/green + name = "green space helmet" + icon_state = "syndicate-helm-green" + item_state = "syndicate-helm-green" + +/obj/item/clothing/suit/space/syndicate/green + name = "green space suit" + icon_state = "syndicate-green" + item_state_slots = list( + slot_l_hand_str = "syndicate-green", + slot_r_hand_str = "syndicate-green", + ) + + +//Dark green syndicate space suit +/obj/item/clothing/head/helmet/space/syndicate/green/dark + name = "dark green space helmet" + icon_state = "syndicate-helm-green-dark" + item_state_slots = list( + slot_l_hand_str = "syndicate-helm-green-dark", + slot_r_hand_str = "syndicate-helm-green-dark", + ) + +/obj/item/clothing/suit/space/syndicate/green/dark + name = "dark green space suit" + icon_state = "syndicate-green-dark" + item_state_slots = list( + slot_l_hand_str = "syndicate-green-dark", + slot_r_hand_str = "syndicate-green-dark", + ) + + +//Orange syndicate space suit +/obj/item/clothing/head/helmet/space/syndicate/orange + name = "orange space helmet" + icon_state = "syndicate-helm-orange" + item_state = "syndicate-helm-orange" + +/obj/item/clothing/suit/space/syndicate/orange + name = "orange space suit" + icon_state = "syndicate-orange" + item_state_slots = list( + slot_l_hand_str = "syndicate-orange", + slot_r_hand_str = "syndicate-orange", + ) + + +//Blue syndicate space suit +/obj/item/clothing/head/helmet/space/syndicate/blue + name = "blue space helmet" + icon_state = "syndicate-helm-blue" + item_state = "syndicate-helm-blue" + +/obj/item/clothing/suit/space/syndicate/blue + name = "blue space suit" + icon_state = "syndicate-blue" + item_state_slots = list( + slot_l_hand_str = "syndicate-blue", + slot_r_hand_str = "syndicate-blue", + ) + + +//Black syndicate space suit +/obj/item/clothing/head/helmet/space/syndicate/black + name = "black space helmet" + icon_state = "syndicate-helm-black" + item_state = "syndicate-helm-black" + +/obj/item/clothing/suit/space/syndicate/black + name = "black space suit" + icon_state = "syndicate-black" + item_state_slots = list( + slot_l_hand_str = "syndicate-black", + slot_r_hand_str = "syndicate-black", + ) + + +//Black-green syndicate space suit +/obj/item/clothing/head/helmet/space/syndicate/black/green + name = "black and green space helmet" + icon_state = "syndicate-helm-black-green" + item_state = "syndicate-helm-black-green" + +/obj/item/clothing/suit/space/syndicate/black/green + name = "black and green space suit" + icon_state = "syndicate-black-green" + item_state_slots = list( + slot_l_hand_str = "syndicate-black-green", + slot_r_hand_str = "syndicate-black-green", + ) + + +//Black-blue syndicate space suit +/obj/item/clothing/head/helmet/space/syndicate/black/blue + name = "black and blue space helmet" + icon_state = "syndicate-helm-black-blue" + item_state = "syndicate-helm-black-blue" + +/obj/item/clothing/suit/space/syndicate/black/blue + name = "black and blue space suit" + icon_state = "syndicate-black-blue" + item_state_slots = list( + slot_l_hand_str = "syndicate-black-blue", + slot_r_hand_str = "syndicate-black-blue", + ) + + +//Black medical syndicate space suit +/obj/item/clothing/head/helmet/space/syndicate/black/med + name = "black medical space helmet" + icon_state = "syndicate-helm-black-med" + item_state_slots = list(slot_head_str = "syndicate-helm-black-med") + +/obj/item/clothing/suit/space/syndicate/black/med + name = "black medical space suit" + icon_state = "syndicate-black-med" + item_state_slots = list( + slot_l_hand_str = "syndicate-black", + slot_r_hand_str = "syndicate-black", + ) + + +//Black-orange syndicate space suit +/obj/item/clothing/head/helmet/space/syndicate/black/orange + name = "black and orange space helmet" + icon_state = "syndicate-helm-black-orange" + item_state_slots = list(slot_head_str = "syndicate-helm-black-orange") + +/obj/item/clothing/suit/space/syndicate/black/orange + name = "black and orange space suit" + icon_state = "syndicate-black-orange" + item_state_slots = list( + slot_l_hand_str = "syndicate-black", + slot_r_hand_str = "syndicate-black", + ) + + +//Black-red syndicate space suit +/obj/item/clothing/head/helmet/space/syndicate/black/red + name = "black and red space helmet" + icon_state = "syndicate-helm-black-red" + item_state = "syndicate-helm-black-red" + +/obj/item/clothing/suit/space/syndicate/black/red + name = "black and red space suit" + icon_state = "syndicate-black-red" + item_state_slots = list( + slot_l_hand_str = "syndicate-black-red", + slot_r_hand_str = "syndicate-black-red", + ) + +//Black with yellow/red engineering syndicate space suit +/obj/item/clothing/head/helmet/space/syndicate/black/engie + name = "black engineering space helmet" + icon_state = "syndicate-helm-black-engie" + item_state_slots = list(slot_head_str = "syndicate-helm-black-engie") + +/obj/item/clothing/suit/space/syndicate/black/engie + name = "black engineering space suit" + icon_state = "syndicate-black-engie" + item_state_slots = list( + slot_l_hand_str = "syndicate-black", + slot_r_hand_str = "syndicate-black", + ) diff --git a/code/modules/clothing/spacesuits/void/bogani.dm b/code/modules/clothing/spacesuits/void/bogani.dm new file mode 100644 index 00000000..f982dbb2 --- /dev/null +++ b/code/modules/clothing/spacesuits/void/bogani.dm @@ -0,0 +1,69 @@ +/obj/item/clothing/head/helmet/space/void/bogani + name = "strange hardsuit helmet" + desc = "An unusual hardsuit helmet." + icon = 'icons/obj/clothing/species/bogani/hats.dmi' + icon_state = "boghelm" + armor = list(melee = 60, bullet = 20, laser = 40,energy = 15, bomb = 50, bio = 70, rad = 70) + siemens_coefficient = 0.6 + species_restricted = list(SPECIES_BOGANI, SPECIES_EGYNO) + +/obj/item/clothing/head/helmet/space/void/bogani/refit_for_species() + // Humans think they can wear Bogani stuff? Try again. + return + +/obj/item/clothing/suit/space/void/bogani + name = "strange hardsuit" + desc = "An unusual hardsuit." + icon = 'icons/obj/clothing/species/bogani/suits.dmi' + icon_state = "bogsuit" + armor = list(melee = 60, bullet = 25, laser = 30,energy = 15, bomb = 50, bio = 70, rad = 70) + siemens_coefficient = 0.6 + species_restricted = list(SPECIES_BOGANI, SPECIES_EGYNO) + +/obj/item/clothing/suit/space/void/bogani/refit_for_species() + // Humans think they can wear Bogani stuff? Try again. + return + +/obj/item/clothing/suit/space/void/bogani/prepared/New() + ..() + helmet = new /obj/item/clothing/head/helmet/space/void/bogani + boots = new /obj/item/clothing/shoes/magboots + +/obj/item/clothing/head/helmet/space/void/bogani/advanced + name = "advanced strange hardsuit helmet" + desc = "An unusual hardsuit helmet. This one seems to have more advanced technology installed." + icon_state = "highboghelm" + armor = list(melee = 80, bullet = 50, laser = 50,energy = 30, bomb = 70, bio = 100, rad = 100) + +/obj/item/clothing/suit/space/void/bogani/advanced + name = "advanced strange hardsuit" + desc = "An unusual hardsuit. This one seems to have more advanced technology installed." + icon_state = "highbogsuit" + armor = list(melee = 80, bullet = 50, laser = 50,energy = 30, bomb = 70, bio = 100, rad = 100) + +/obj/item/clothing/suit/space/void/bogani/advanced/prepared/New() + ..() + helmet = new /obj/item/clothing/head/helmet/space/void/bogani/advanced + boots = new /obj/item/clothing/shoes/magboots + +/obj/item/clothing/suit/space/void/bogani/armored + name = "strange armored hardsuit" + desc = "An unusual hardsuit. This one seems to have a considerable amount of armoring." + icon_state = "bogarmor" + armor = list(melee = 80, bullet = 60, laser = 60,energy = 40, bomb = 90, bio = 120, rad = 120) + +/obj/item/clothing/suit/space/void/bogani/armored/prepared/New() + ..() + helmet = new /obj/item/clothing/head/helmet/space/void/bogani + boots = new /obj/item/clothing/shoes/magboots + +/obj/item/clothing/suit/space/void/bogani/ultimate + name = "strange advanced armored hardsuit" + desc = "An unusual hardsuit. This one seems to have a considerable amount of advanced technology installed, as well as layers of armor." + icon_state = "highbogarmor" + armor = list(melee = 100, bullet = 80, laser = 80,energy = 70, bomb = 100, bio = 140, rad = 140) + +/obj/item/clothing/suit/space/void/bogani/ultimate/prepared/New() + ..() + helmet = new /obj/item/clothing/head/helmet/space/void/bogani/advanced + boots = new /obj/item/clothing/shoes/magboots \ No newline at end of file diff --git a/code/modules/clothing/spacesuits/void/merc.dm b/code/modules/clothing/spacesuits/void/merc.dm new file mode 100644 index 00000000..1365cee2 --- /dev/null +++ b/code/modules/clothing/spacesuits/void/merc.dm @@ -0,0 +1,34 @@ +//Syndicate rig +/obj/item/clothing/head/helmet/space/void/merc + name = "blood-red voidsuit helmet" + desc = "An advanced helmet designed for work in special operations. Property of Gorlex Marauders." + icon_state = "rig0-syndie" + item_state = "syndie_helm" + armor = list(melee = 60, bullet = 50, laser = 50,energy = 15, bomb = 35, bio = 100, rad = 60) + siemens_coefficient = 0.3 + species_restricted = list(SPECIES_HUMAN, SPECIES_IPC) + camera = /obj/machinery/camera/network/mercenary + light_overlay = "helmet_light_green" //todo: species-specific light overlays + +/obj/item/clothing/suit/space/void/merc + icon_state = "rig-syndie" + name = "blood-red voidsuit" + desc = "An advanced suit that protects against injuries during special operations. Property of Gorlex Marauders." + item_state_slots = list( + slot_l_hand_str = "syndie_voidsuit", + slot_r_hand_str = "syndie_voidsuit", + ) + w_class = ITEM_SIZE_LARGE //normally voidsuits are bulky but the merc voidsuit is 'advanced' or something + armor = list(melee = 60, bullet = 50, laser = 50, energy = 15, bomb = 35, bio = 100, rad = 60) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy/sword,/obj/item/weapon/handcuffs) + siemens_coefficient = 0.3 + species_restricted = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_IPC) + +/obj/item/clothing/suit/space/void/merc/New() + ..() + slowdown_per_slot[slot_wear_suit] = 1 + +/obj/item/clothing/suit/space/void/merc/prepared/New() + ..() + helmet = new /obj/item/clothing/head/helmet/space/void/merc + boots = new /obj/item/clothing/shoes/magboots \ No newline at end of file diff --git a/code/modules/clothing/spacesuits/void/misc.dm b/code/modules/clothing/spacesuits/void/misc.dm new file mode 100644 index 00000000..ab4a103f --- /dev/null +++ b/code/modules/clothing/spacesuits/void/misc.dm @@ -0,0 +1,14 @@ + +/obj/item/clothing/suit/space/void/swat + name = "\improper SWAT suit" + desc = "A heavily armored suit that protects against moderate damage. Used in special operations." + icon_state = "deathsquad" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS + allowed = list(/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/tank) + armor = list(melee = 80, bullet = 60, laser = 60,energy = 25, bomb = 50, bio = 100, rad = 100) + flags_inv = HIDESHOES|HIDEJUMPSUIT + siemens_coefficient = 0.6 + +/obj/item/clothing/suit/space/void/swat/New() + ..() + slowdown_per_slot[slot_wear_suit] = 1 \ No newline at end of file diff --git a/code/modules/clothing/spacesuits/void/station.dm b/code/modules/clothing/spacesuits/void/station.dm new file mode 100644 index 00000000..7a037284 --- /dev/null +++ b/code/modules/clothing/spacesuits/void/station.dm @@ -0,0 +1,322 @@ +// Station voidsuits + +//Engineering +/obj/item/clothing/head/helmet/space/void/engineering + name = "engineering voidsuit helmet" + desc = "A sturdy looking voidsuit helmet rated to protect against radiation." + icon_state = "rig0-engineering" + item_state = "eng_helm" + item_state_slots = list( + slot_l_hand_str = "eng_helm", + slot_r_hand_str = "eng_helm", + ) + armor = list(melee = 40, bullet = 5, laser = 20,energy = 5, bomb = 35, bio = 100, rad = 80) + +/obj/item/clothing/suit/space/void/engineering + name = "engineering voidsuit" + desc = "A run-of-the-mill service voidsuit with all the plating and radiation protection required for industrial work in vacuum." + icon_state = "rig-engineering" + item_state_slots = list( + slot_l_hand_str = "eng_voidsuit", + slot_r_hand_str = "eng_voidsuit", + ) + armor = list(melee = 40, bullet = 5, laser = 20,energy = 5, bomb = 35, bio = 100, rad = 80) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/storage/toolbox,/obj/item/weapon/storage/briefcase/inflatable,/obj/item/device/t_scanner,/obj/item/weapon/rcd) + +/obj/item/clothing/suit/space/void/engineering/New() + ..() + slowdown_per_slot[slot_wear_suit] = 1 + +/obj/item/clothing/suit/space/void/engineering/prepared + helmet = /obj/item/clothing/head/helmet/space/void/engineering + boots = /obj/item/clothing/shoes/magboots + +//Mining +/obj/item/clothing/head/helmet/space/void/mining + name = "mining voidsuit helmet" + desc = "A scuffed voidsuit helmet with a boosted communication system and reinforced armor plating." + icon_state = "rig0-mining" + item_state = "mining_helm" + item_state_slots = list( + slot_l_hand_str = "mining_helm", + slot_r_hand_str = "mining_helm", + ) + armor = list(melee = 50, bullet = 5, laser = 20,energy = 5, bomb = 55, bio = 100, rad = 20) + light_overlay = "helmet_light_dual" + +/obj/item/clothing/suit/space/void/mining + icon_state = "rig-mining" + name = "mining voidsuit" + desc = "A grimy, decently armored voidsuit with purple blazes and extra insulation." + item_state_slots = list( + slot_l_hand_str = "mining_voidsuit", + slot_r_hand_str = "mining_voidsuit", + ) + armor = list(melee = 50, bullet = 5, laser = 20,energy = 5, bomb = 55, bio = 100, rad = 20) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/stack/flag,/obj/item/device/suit_cooling_unit,/obj/item/weapon/storage/ore,/obj/item/device/t_scanner,/obj/item/weapon/pickaxe, /obj/item/weapon/rcd) + +/obj/item/clothing/suit/space/void/mining/prepared + helmet = /obj/item/clothing/head/helmet/space/void/mining + +//Medical +/obj/item/clothing/head/helmet/space/void/medical + name = "medical voidsuit helmet" + desc = "A bulbous voidsuit helmet with minor radiation shielding and a massive visor." + icon_state = "rig0-medical" + item_state = "medical_helm" + item_state_slots = list( + slot_l_hand_str = "medical_helm", + slot_r_hand_str = "medical_helm", + ) + armor = list(melee = 30, bullet = 5, laser = 20,energy = 5, bomb = 25, bio = 100, rad = 50) + +/obj/item/clothing/suit/space/void/medical + icon_state = "rig-medical" + name = "medical voidsuit" + desc = "A sterile voidsuit with minor radiation shielding and a suite of self-cleaning technology. Standard issue in NanoTrasen medical facilities." + item_state_slots = list( + slot_l_hand_str = "medical_voidsuit", + slot_r_hand_str = "medical_voidsuit", + ) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/storage/firstaid,/obj/item/device/healthanalyzer,/obj/item/stack/medical) + armor = list(melee = 30, bullet = 5, laser = 20,energy = 5, bomb = 25, bio = 100, rad = 50) + +/obj/item/clothing/suit/space/void/medical/prepared + helmet = /obj/item/clothing/head/helmet/space/void/medical + boots = /obj/item/clothing/shoes/magboots + +//Security +/obj/item/clothing/head/helmet/space/void/security + name = "security voidsuit helmet" + desc = "A comfortable voidsuit helmet with cranial armor and eight-channel surround sound." + icon_state = "rig0-sec" + item_state = "sec_helm" + item_state_slots = list( + slot_l_hand_str = "sec_helm", + slot_r_hand_str = "sec_helm", + ) + armor = list(melee = 60, bullet = 10, laser = 30, energy = 5, bomb = 45, bio = 100, rad = 10) + siemens_coefficient = 0.7 + light_overlay = "helmet_light_dual" + +/obj/item/clothing/suit/space/void/security + icon_state = "rig-sec" + name = "security voidsuit" + desc = "A somewhat clumsy voidsuit layered with impact and laser-resistant armor plating. Specially designed to dissipate minor electrical charges." + item_state_slots = list( + slot_l_hand_str = "sec_voidsuit", + slot_r_hand_str = "sec_voidsuit", + ) + armor = list(melee = 60, bullet = 10, laser = 30, energy = 5, bomb = 45, bio = 100, rad = 10) + allowed = list(/obj/item/weapon/gun,/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/melee/baton) + siemens_coefficient = 0.7 + +/obj/item/clothing/suit/space/void/security/prepared + helmet = /obj/item/clothing/head/helmet/space/void/security + boots = /obj/item/clothing/shoes/magboots + +//Atmospherics +/obj/item/clothing/head/helmet/space/void/atmos + desc = "A flame-retardant voidsuit helmet with a self-repairing visor and light anti-radiation shielding." + name = "atmospherics voidsuit helmet" + icon_state = "rig0-atmos" + item_state = "atmos_helm" + item_state_slots = list( + slot_l_hand_str = "atmos_helm", + slot_r_hand_str = "atmos_helm", + ) + armor = list(melee = 40, bullet = 5, laser = 20,energy = 5, bomb = 35, bio = 100, rad = 50) + max_heat_protection_temperature = FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE + light_overlay = "helmet_light_dual" + +/obj/item/clothing/suit/space/void/atmos + desc = "A durable voidsuit with advanced temperature-regulation systems as well as minor radiation protection. Well worth the price." + icon_state = "rig-atmos" + name = "atmos voidsuit" + item_state_slots = list( + slot_l_hand_str = "atmos_voidsuit", + slot_r_hand_str = "atmos_voidsuit", + ) + armor = list(melee = 40, bullet = 5, laser = 20,energy = 5, bomb = 35, bio = 100, rad = 50) + max_heat_protection_temperature = FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/storage/toolbox,/obj/item/weapon/storage/briefcase/inflatable,/obj/item/device/t_scanner,/obj/item/weapon/rcd) + +/obj/item/clothing/suit/space/void/atmos/prepared + helmet = /obj/item/clothing/head/helmet/space/void/atmos + boots = /obj/item/clothing/shoes/magboots + +//Surplus Voidsuits + +//Engineering +/obj/item/clothing/head/helmet/space/void/engineering/alt + name = "reinforced engineering voidsuit helmet" + desc = "A heavy, radiation-shielded voidsuit helmet with a surprisingly comfortable interior." + icon_state = "rig0-engineeringalt" + item_state = "engalt_helm" + armor = list(melee = 40, bullet = 5, laser = 20,energy = 5, bomb = 45, bio = 100, rad = 100) + light_overlay = "helmet_light_dual" + +/obj/item/clothing/suit/space/void/engineering/alt + name = "reinforced engineering voidsuit" + desc = "A bulky industrial voidsuit. It's a few generations old, but a reliable design and radiation shielding make up for the lack of climate control." + icon_state = "rig-engineeringalt" + armor = list(melee = 40, bullet = 5, laser = 20,energy = 5, bomb = 45, bio = 100, rad = 100) + +/obj/item/clothing/suit/space/void/engineering/alt/New() + ..() + slowdown_per_slot[slot_wear_suit] = 2 + +/obj/item/clothing/suit/space/void/engineering/alt/prepared + helmet = /obj/item/clothing/head/helmet/space/void/engineering/alt + boots = /obj/item/clothing/shoes/magboots + +//Mining +/obj/item/clothing/head/helmet/space/void/mining/alt + name = "frontier mining voidsuit helmet" + desc = "An armored voidsuit helmet. Someone must have through they were pretty cool when they painted a mohawk on it." + icon_state = "rig0-miningalt" + item_state = "miningalt_helm" + armor = list(melee = 50, bullet = 15, laser = 20,energy = 5, bomb = 55, bio = 100, rad = 0) + +/obj/item/clothing/suit/space/void/mining/alt + icon_state = "rig-miningalt" + name = "frontier mining voidsuit" + desc = "A cheap prospecting voidsuit. What it lacks in comfort it makes up for in armor plating and street cred." + armor = list(melee = 50, bullet = 15, laser = 20,energy = 5, bomb = 55, bio = 100, rad = 0) + +/obj/item/clothing/suit/space/void/mining/alt/prepared + helmet = /obj/item/clothing/head/helmet/space/void/mining/alt + +//Medical +/obj/item/clothing/head/helmet/space/void/medical/alt + name = "streamlined medical voidsuit helmet" + desc = "A trendy, lightly radiation-shielded voidsuit helmet trimmed in a fetching blue." + icon_state = "rig0-medicalalt" + item_state = "medicalalt_helm" + armor = list(melee = 30, bullet = 5, laser = 10,energy = 5, bomb = 5, bio = 100, rad = 60) + light_overlay = "helmet_light_dual_green" + +/obj/item/clothing/suit/space/void/medical/alt + icon_state = "rig-medicalalt" + name = "streamlined medical voidsuit" + desc = "A more recent model of Vey-Med voidsuit, featuring the latest in radiation shielding technology, without sacrificing comfort or style." + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/storage/firstaid,/obj/item/device/healthanalyzer,/obj/item/stack/medical) + armor = list(melee = 30, bullet = 5, laser = 10,energy = 5, bomb = 5, bio = 100, rad = 60) + +/obj/item/clothing/suit/space/void/medical/alt/New() + ..() + slowdown_per_slot[slot_wear_suit] = 0 + +/obj/item/clothing/suit/space/void/medical/alt/prepared + helmet = /obj/item/clothing/head/helmet/space/void/medical/alt + boots = /obj/item/clothing/shoes/magboots + +//Security +/obj/item/clothing/head/helmet/space/void/security/alt + name = "riot security voidsuit helmet" + desc = "A somewhat tacky voidsuit helmet, a fact mitigated by heavy armor plating." + icon_state = "rig0-secalt" + item_state = "secalt_helm" + armor = list(melee = 70, bullet = 20, laser = 30, energy = 5, bomb = 35, bio = 100, rad = 10) + +/obj/item/clothing/suit/space/void/security/alt + icon_state = "rig-secalt" + name = "riot security voidsuit" + desc = "A heavily armored voidsuit, designed to intimidate people who find black intimidating. Surprisingly slimming." + armor = list(melee = 70, bullet = 20, laser = 30, energy = 5, bomb = 35, bio = 100, rad = 10) + allowed = list(/obj/item/weapon/gun,/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/melee/baton) + +/obj/item/clothing/suit/space/void/security/alt/prepared + helmet = /obj/item/clothing/head/helmet/space/void/security/alt + boots = /obj/item/clothing/shoes/magboots + +//Atmospherics +/obj/item/clothing/head/helmet/space/void/atmos/alt + desc = "A voidsuit helmet plated with an expensive heat and radiation resistant ceramic." + name = "heavy duty atmospherics voidsuit helmet" + icon_state = "rig0-atmosalt" + item_state = "atmosalt_helm" + armor = list(melee = 20, bullet = 5, laser = 20,energy = 15, bomb = 45, bio = 100, rad = 50) + max_heat_protection_temperature = FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE + light_overlay = "hardhat_light" + +/obj/item/clothing/suit/space/void/atmos/alt + desc = "An expensive NanoTrasen voidsuit, rated to withstand extreme heat and even minor radiation without exceeding room temperature within." + icon_state = "rig-atmosalt" + name = "heavy duty atmos voidsuit" + armor = list(melee = 20, bullet = 5, laser = 20,energy = 15, bomb = 45, bio = 100, rad = 50) + max_heat_protection_temperature = FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE + +/obj/item/clothing/suit/space/void/atmos/alt/prepared + helmet = /obj/item/clothing/head/helmet/space/void/atmos/alt + boots = /obj/item/clothing/shoes/magboots + +//Exploration +/obj/item/clothing/head/helmet/space/void/exploration + name = "exploration voidsuit helmet" + desc = "A radiation-resistant helmet made especially for exploring unknown planetary environments." + icon_state = "helm_explorer" + item_state = "helm_explorer" + armor = list(melee = 20, bullet = 10, laser = 15,energy = 45, bomb = 30, bio = 100, rad = 90) + light_overlay = "explorer_light" + +/obj/item/clothing/suit/space/void/exploration + name = "exploration voidsuit" + desc = "A lightweight, radiation-resistant voidsuit, featuring the Expeditionary Corps emblem on its chest plate. Designed for exploring unknown planetary environments." + icon_state = "void_explorer" + armor = list(melee = 20, bullet = 10, laser = 15,energy = 45, bomb = 30, bio = 100, rad = 90) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/stack/flag,/obj/item/device/healthanalyzer,/obj/item/device/gps,/obj/item/weapon/pinpointer/radio,/obj/item/device/radio/beacon,/obj/item/weapon/material/hatchet/machete,/obj/item/weapon/shovel) + +/obj/item/clothing/suit/space/void/exploration/prepared + helmet = /obj/item/clothing/head/helmet/space/void/exploration + boots = /obj/item/clothing/shoes/magboots + +//Misc +/obj/item/clothing/head/helmet/space/void/engineering/salvage + name = "salvage voidsuit helmet" + desc = "A heavily modified salvage voidsuit helmet. It has been fitted with radiation-resistant plating." + icon_state = "rig0-salvage" + item_state = "salvage_helm" + item_state_slots = list( + slot_l_hand_str = "eng_helm", + slot_r_hand_str = "eng_helm", + ) + armor = list(melee = 50, bullet = 10, laser = 30,energy = 15, bomb = 35, bio = 100, rad = 80) + +/obj/item/clothing/suit/space/void/engineering/salvage + name = "salvage voidsuit" + desc = "A hand-me-down salvage voidsuit. It has obviously had a lot of repair work done to its radiation shielding." + icon_state = "rig-salvage" + item_state_slots = list( + slot_l_hand_str = "eng_voidsuit", + slot_r_hand_str = "eng_voidsuit", + ) + armor = list(melee = 50, bullet = 10, laser = 30,energy = 15, bomb = 35, bio = 100, rad = 80) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/storage/toolbox,/obj/item/weapon/storage/briefcase/inflatable,/obj/item/device/t_scanner,/obj/item/weapon/rcd) + +/obj/item/clothing/suit/space/void/engineering/salvage/prepared + helmet = /obj/item/clothing/head/helmet/space/void/engineering/salvage + boots = /obj/item/clothing/shoes/magboots + +//Pilot +/obj/item/clothing/head/helmet/space/void/pilot + desc = "An atmos resistant helmet for space and planet exploration." + name = "pilot voidsuit helmet" + icon_state = "rig0_pilot" + item_state = "pilot_helm" + armor = list(melee = 40, bullet = 5, laser = 15,energy = 5, bomb = 5, bio = 100, rad = 50) + max_heat_protection_temperature = FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE + light_overlay = "helmet_light_dual" + +/obj/item/clothing/suit/space/void/pilot + desc = "An atmos resistant voidsuit for space and planet exploration." + icon_state = "rig-pilot" + item_state = "rig-pilot" + name = "pilot voidsuit" + armor = list(melee = 40, bullet = 5, laser = 15,energy = 5, bomb = 5, bio = 100, rad = 50) + max_heat_protection_temperature = FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/storage/toolbox,/obj/item/weapon/storage/briefcase/inflatable,/obj/item/device/t_scanner,/obj/item/weapon/rcd) + +/obj/item/clothing/suit/space/void/pilot/prepared + helmet = /obj/item/clothing/head/helmet/space/void/pilot + boots = /obj/item/clothing/shoes/magboots diff --git a/code/modules/clothing/spacesuits/void/void.dm b/code/modules/clothing/spacesuits/void/void.dm new file mode 100644 index 00000000..f1838a3a --- /dev/null +++ b/code/modules/clothing/spacesuits/void/void.dm @@ -0,0 +1,254 @@ +//NASA Voidsuit +/obj/item/clothing/head/helmet/space/void + name = "void helmet" + desc = "A high-tech dark red space suit helmet. Used for AI satellite maintenance." + icon_state = "void" + + heat_protection = HEAD + armor = list(melee = 40, bullet = 5, laser = 20,energy = 5, bomb = 35, bio = 100, rad = 20) + max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE + siemens_coefficient = 0.4 + + //Species-specific stuff. + species_restricted = list(SPECIES_HUMAN, SPECIES_IPC) + light_overlay = "helmet_light" + +/obj/item/clothing/suit/space/void + name = "voidsuit" + icon_state = "void" + //item_state = "syndie_hardsuit" + w_class = ITEM_SIZE_HUGE//bulky item + desc = "A high-tech dark red space suit. Used for AI satellite maintenance." + armor = list(melee = 40, bullet = 5, laser = 20,energy = 5, bomb = 35, bio = 100, rad = 20) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit) + heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE + siemens_coefficient = 0.4 + + species_restricted = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_IPC) + + //Breach thresholds, should ideally be inherited by most (if not all) voidsuits. + //With 0.2 resiliance, will reach 10 breach damage after 3 laser carbine blasts or 8 smg hits. + breach_threshold = 18 + can_breach = 1 + + //Inbuilt devices. + var/obj/item/clothing/shoes/magboots/boots = null // Deployable boots, if any. + var/obj/item/clothing/head/helmet/helmet = null // Deployable helmet, if any. + var/obj/item/weapon/tank/tank = null // Deployable tank, if any. + + action_button_name = "Toggle Helmet" + +#define VOIDSUIT_INIT_EQUIPMENT(equipment_var, expected_path) \ +if(ispath(##equipment_var, ##expected_path )){\ + ##equipment_var = new equipment_var (src);\ +}\ +else if(##equipment_var) {\ + CRASH("[log_info_line(src)] has an invalid [#equipment_var] type: [log_info_line(##equipment_var)]");\ +} + +/obj/item/clothing/suit/space/void/Initialize() + . = ..() + VOIDSUIT_INIT_EQUIPMENT(boots, /obj/item/clothing/shoes/magboots) + VOIDSUIT_INIT_EQUIPMENT(helmet, /obj/item/clothing/head/helmet) + VOIDSUIT_INIT_EQUIPMENT(tank, /obj/item/weapon/tank) + +#undef VOIDSUIT_INIT_EQUIPMENT + +/obj/item/clothing/suit/space/void/Destroy() + . = ..() + QDEL_NULL(boots) + QDEL_NULL(helmet) + QDEL_NULL(tank) + +/obj/item/clothing/suit/space/void/examine(user) + . = ..(user) + var/list/part_list = new + for(var/obj/item/I in list(helmet,boots,tank)) + part_list += "\a [I]" + to_chat(user, "\The [src] has [english_list(part_list)] installed.") + if(tank && in_range(src,user)) + to_chat(user, "The wrist-mounted pressure gauge reads [max(round(tank.air_contents.return_pressure()),0)] kPa remaining in \the [tank].") + +/obj/item/clothing/suit/space/void/refit_for_species(var/target_species) + ..() + if(istype(helmet)) + helmet.refit_for_species(target_species) + if(istype(boots)) + boots.refit_for_species(target_species) + +/obj/item/clothing/suit/space/void/equipped(mob/M) + ..() + + var/mob/living/carbon/human/H = M + + if(!istype(H)) return + + if(H.wear_suit != src) + return + + if(boots) + if (H.equip_to_slot_if_possible(boots, slot_shoes)) + boots.canremove = 0 + + if(helmet) + if(H.head) + to_chat(M, "You are unable to deploy your suit's helmet as \the [H.head] is in the way.") + else if (H.equip_to_slot_if_possible(helmet, slot_head)) + to_chat(M, "Your suit's helmet deploys with a hiss.") + helmet.canremove = 0 + + if(tank) + if(H.s_store) //In case someone finds a way. + to_chat(M, "Alarmingly, the valve on your suit's installed tank fails to engage.") + else if (H.equip_to_slot_if_possible(tank, slot_s_store)) + to_chat(M, "The valve on your suit's installed tank safely engages.") + tank.canremove = 0 + + +/obj/item/clothing/suit/space/void/dropped() + ..() + + var/mob/living/carbon/human/H + + if(helmet) + helmet.canremove = 1 + H = helmet.loc + if(istype(H)) + if(helmet && H.head == helmet) + H.drop_from_inventory(helmet) + helmet.forceMove(src) + + if(boots) + boots.canremove = 1 + H = boots.loc + if(istype(H)) + if(boots && H.shoes == boots) + H.drop_from_inventory(boots) + boots.forceMove(src) + + if(tank) + tank.canremove = 1 + tank.forceMove(src) + +/obj/item/clothing/suit/space/void/verb/toggle_helmet() + + set name = "Toggle Helmet" + set category = "Object" + set src in usr + + if(!istype(src.loc,/mob/living)) return + + if(!helmet) + to_chat(usr, "There is no helmet installed.") + return + + var/mob/living/carbon/human/H = usr + + if(!istype(H)) return + if(H.incapacitated()) return + if(H.wear_suit != src) return + + if(H.head == helmet) + to_chat(H, "You retract your suit helmet.") + helmet.canremove = 1 + H.drop_from_inventory(helmet) + helmet.forceMove(src) + else + if(H.head) + to_chat(H, "You cannot deploy your helmet while wearing \the [H.head].") + return + if(H.equip_to_slot_if_possible(helmet, slot_head)) + helmet.pickup(H) + helmet.canremove = 0 + to_chat(H, "You deploy your suit helmet, sealing you off from the world.") + helmet.update_light(H) + +/obj/item/clothing/suit/space/void/verb/eject_tank() + + set name = "Eject Voidsuit Tank" + set category = "Object" + set src in usr + + if(!istype(src.loc,/mob/living)) return + + if(!tank) + to_chat(usr, "There is no tank inserted.") + return + + var/mob/living/carbon/human/H = usr + + if(!istype(H)) return + if(H.incapacitated()) return + if(H.wear_suit != src) return + + to_chat(H, "You press the emergency release, ejecting \the [tank] from your suit.") + tank.canremove = 1 + H.drop_from_inventory(tank) + src.tank = null + +/obj/item/clothing/suit/space/void/attackby(obj/item/W as obj, mob/user as mob) + + if(!istype(user,/mob/living)) return + + if(istype(W,/obj/item/clothing/accessory) || istype(W, /obj/item/weapon/hand_labeler)) + return ..() + + if(user.get_inventory_slot(src) == slot_wear_suit) + to_chat(user, "You cannot modify \the [src] while it is being worn.") + return + + if(istype(W,/obj/item/weapon/screwdriver)) + if(helmet || boots || tank) + var/choice = input("What component would you like to remove?") as null|anything in list(helmet,boots,tank) + if(!choice) return + + if(choice == tank) //No, a switch doesn't work here. Sorry. ~Techhead + to_chat(user, "You pop \the [tank] out of \the [src]'s storage compartment.") + tank.forceMove(get_turf(src)) + src.tank = null + else if(choice == helmet) + to_chat(user, "You detatch \the [helmet] from \the [src]'s helmet mount.") + helmet.forceMove(get_turf(src)) + src.helmet = null + else if(choice == boots) + to_chat(user, "You detatch \the [boots] from \the [src]'s boot mounts.") + boots.forceMove(get_turf(src)) + src.boots = null + else + to_chat(user, "\The [src] does not have anything installed.") + return + else if(istype(W,/obj/item/clothing/head/helmet/space)) + if(helmet) + to_chat(user, "\The [src] already has a helmet installed.") + else + to_chat(user, "You attach \the [W] to \the [src]'s helmet mount.") + user.drop_item() + W.forceMove(src) + src.helmet = W + return + else if(istype(W,/obj/item/clothing/shoes/magboots)) + if(boots) + to_chat(user, "\The [src] already has magboots installed.") + else + to_chat(user, "You attach \the [W] to \the [src]'s boot mounts.") + user.drop_item() + W.forceMove(src) + boots = W + return + else if(istype(W,/obj/item/weapon/tank)) + if(tank) + to_chat(user, "\The [src] already has an airtank installed.") + else if(istype(W,/obj/item/weapon/tank/phoron)) + to_chat(user, "\The [W] cannot be inserted into \the [src]'s storage compartment.") + else + to_chat(user, "You insert \the [W] into \the [src]'s storage compartment.") + user.drop_item() + W.forceMove(src) + tank = W + return + + ..() + +/obj/item/clothing/suit/space/void/attack_self() //sole purpose of existence is to toggle the helmet + toggle_helmet() \ No newline at end of file diff --git a/code/modules/clothing/spacesuits/void/wizard.dm b/code/modules/clothing/spacesuits/void/wizard.dm new file mode 100644 index 00000000..21adc96d --- /dev/null +++ b/code/modules/clothing/spacesuits/void/wizard.dm @@ -0,0 +1,49 @@ +//Wizard Rig +/obj/item/clothing/head/helmet/space/void/wizard + name = "gem-encrusted voidsuit helmet" + desc = "A bizarre gem-encrusted helmet that radiates magical energies." + icon_state = "rig0-wiz" + item_state_slots = list( + slot_l_hand_str = "wiz_helm", + slot_r_hand_str = "wiz_helm", + ) + unacidable = 1 //No longer shall our kind be foiled by lone chemists with spray bottles! + armor = list(melee = 40, bullet = 20, laser = 20,energy = 20, bomb = 35, bio = 100, rad = 60) + siemens_coefficient = 0.7 + sprite_sheets_obj = null + wizard_garb = 1 + +/obj/item/clothing/suit/space/void/wizard + icon_state = "rig-wiz" + name = "gem-encrusted voidsuit" + desc = "A bizarre gem-encrusted suit that radiates magical energies." + w_class = ITEM_SIZE_LARGE //normally voidsuits are bulky but this one is magic I suppose + unacidable = 1 + armor = list(melee = 40, bullet = 20, laser = 20,energy = 20, bomb = 35, bio = 100, rad = 60) + siemens_coefficient = 0.7 + sprite_sheets_obj = null + wizard_garb = 1 + flags_inv = HIDESHOES|HIDEJUMPSUIT|HIDETAIL //For gloves. + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS + cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS + +/obj/item/clothing/suit/space/void/wizard/New() + ..() + slowdown_per_slot[slot_wear_suit] = 1 + +/obj/item/clothing/gloves/wizard + name = "mystical gloves" + desc = "Reinforced, gem-studded gloves that radiate energy. They look like they go along with a matching voidsuit." + icon_state = "mystical" + item_state = "purplegloves" + item_flags = ITEM_FLAG_THICKMATERIAL + body_parts_covered = HANDS + cold_protection = HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + species_restricted = null + gender = PLURAL + gas_transfer_coefficient = 0.01 + permeability_coefficient = 0.02 + unacidable = 1 + armor = list(melee = 40, bullet = 20, laser = 20,energy = 20, bomb = 35, bio = 100, rad = 60) + siemens_coefficient = 0.7 diff --git a/code/modules/clothing/suits/alien.dm b/code/modules/clothing/suits/alien.dm new file mode 100644 index 00000000..45534f60 --- /dev/null +++ b/code/modules/clothing/suits/alien.dm @@ -0,0 +1,93 @@ +//Unathi clothing. + +/obj/item/clothing/suit/unathi/robe + name = "roughspun robes" + desc = "A traditional Unathi garment." + icon_state = "robe-unathi" + item_state = "robe-unathi" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS + +/obj/item/clothing/suit/unathi/mantle + name = "hide mantle" + desc = "A rather grisly selection of cured hides and skin, sewn together to form a ragged mantle." + icon_state = "mantle-unathi" + item_state = "mantle-unathi" + body_parts_covered = UPPER_TORSO + +//Taj clothing. + +/obj/item/clothing/suit/tajaran/furs + name = "heavy furs" + desc = "A traditional Zhan-Khazan garment." + icon_state = "zhan_furs" + item_state = "zhan_furs" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS + +/obj/item/clothing/head/tajaran/scarf + name = "headscarf" + desc = "A scarf of coarse fabric. Seems to have ear-holes." + icon_state = "zhan_scarf" + body_parts_covered = HEAD|FACE + +/obj/item/clothing/shoes/sandal/tajaran/caligae + name = "caligae" + desc = "The standard Tajaran footwear loosly resembles the Roman Caligae. Made of leather and rubber, their unique design allows for improved traction and protection. They don't look like they would fit on anyone but a Tajara." + description_fluff = "These traditional Tajaran footwear, also called Haskri, have remained reletivly unchanged in principal, with improved materials and construction being the only notable improvment. Originally used for harsher environment, they became widespread for their comfort and hygiene. Some of them come with covering for additional protection for more sterile environments. Made for the Tajarans digitigrade anatomy, they won't fit on any other species." + icon_state = "caligae" + item_state = "caligae" + body_parts_covered = FEET|LEGS + species_restricted = list(SPECIES_TAJARA) + +/obj/item/clothing/shoes/sandal/tajaran/caligae/white + desc = "The standard Tajaran footwear loosly resembles the Roman Caligae. Made of leather and rubber, their unique design allows for improved traction and protection. They don't look like they would fit on anyone but a Tajara. /This one has a white covering." + icon_state = "whitecaligae" + item_state = "whitecaligae" + +/obj/item/clothing/shoes/sandal/tajaran/caligae/grey + desc = "The standard Tajaran footwear loosly resembles the Roman Caligae. Made of leather and rubber, their unique design allows for improved traction and protection. They don't look like they would fit on anyone but a Tajara. /This one has a grey covering." + icon_state = "greycaligae" + item_state = "greycaligae" + +/obj/item/clothing/shoes/sandal/tajaran/caligae/black + desc = "The standard Tajaran footwear loosly resembles the Roman Caligae. Made of leather and rubber, their unique design allows for improved traction and protection. They don't look like they would fit on anyone but a Tajara. /This one has a black covering." + icon_state = "blackcaligae" + item_state = "blackcaligae" + +/obj/item/clothing/accessory/shouldercape + name = "shoulder cape" + desc = "A simple shoulder cape." + icon_state = "gruntcape" + slot = ACCESSORY_SLOT_INSIGNIA // Adding again in case we want to change it in the future. + +/obj/item/clothing/accessory/shouldercape/grunt + name = "modir cape" + desc = "A simple looking cape with a couple of runes woven into the fabric." + icon_state = "gruntcape" // Again, just in case it is changed. + +/obj/item/clothing/accessory/shouldercape/officer + name = "nraji cape" + desc = "A decorated cape. Runed patterns have been woven into the fabric." + icon_state = "officercape" + +/obj/item/clothing/accessory/shouldercape/command + name = "hejun cape" + desc = "A heavily decorated cape with rank emblems on the shoulders signifying positions within the Tajaran govenment. An ornate runed design has been woven into the fabric of it" + icon_state = "commandcape" + +/obj/item/clothing/accessory/shouldercape/general + name = "ginajir cape" + desc = "An extremely decorated cape with an intricately runed design has been woven into the fabric of this cape with great care. This cape can only be found within the Tajaran elite." + icon_state = "leadercape" + +//Voxclothing + +/obj/item/clothing/suit/armor/vox_scrap + name = "rusted metal armor" + desc = "A hodgepodge of various pieces of metal scrapped together into a rudimentary vox-shaped piece of armor." + allowed = list(/obj/item/weapon/gun, /obj/item/weapon/tank) + armor = list(melee = 70, bullet = 30, laser = 20,energy = 5, bomb = 40, bio = 0, rad = 0) //Higher melee armor versus lower everything else. + icon_state = "vox-scrap" + icon_state = "vox-scrap" + body_parts_covered = UPPER_TORSO|ARMS|LOWER_TORSO|LEGS + species_restricted = list(SPECIES_VOX) + siemens_coefficient = 1 //Its literally metal diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm new file mode 100644 index 00000000..1aa73445 --- /dev/null +++ b/code/modules/clothing/suits/armor.dm @@ -0,0 +1,411 @@ + +/obj/item/clothing/suit/armor + allowed = list(/obj/item/weapon/gun/energy,/obj/item/device/radio,/obj/item/weapon/reagent_containers/spray/pepper,/obj/item/weapon/gun/projectile,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs) + body_parts_covered = UPPER_TORSO|LOWER_TORSO + item_flags = ITEM_FLAG_THICKMATERIAL + + cold_protection = UPPER_TORSO|LOWER_TORSO + min_cold_protection_temperature = ARMOR_MIN_COLD_PROTECTION_TEMPERATURE + heat_protection = UPPER_TORSO|LOWER_TORSO + max_heat_protection_temperature = ARMOR_MAX_HEAT_PROTECTION_TEMPERATURE + siemens_coefficient = 0.6 + + +/obj/item/clothing/suit/armor/vest/old //just realized these had never been removed + name = "armor" + desc = "An armored vest that protects against some damage." + icon_state = "armor" + //item_state = "armor" + blood_overlay_type = "armor" + body_parts_covered = UPPER_TORSO|LOWER_TORSO + cold_protection = UPPER_TORSO|LOWER_TORSO + heat_protection = UPPER_TORSO|LOWER_TORSO + armor = list(melee = 50, bullet = 15, laser = 50, energy = 10, bomb = 25, bio = 0, rad = 0) + +/obj/item/clothing/suit/armor/vest/old/security + name = "security armor" + desc = "An armored vest that protects against some damage. This one has a corporate badge." + icon_state = "armorsec" + //item_state = "armor" + +/obj/item/clothing/suit/armor/vest/barney + name = "casual security armor" + icon_state = "barney_vest" + armor = list(melee = 30, bullet = 40, laser = 50, energy = 10, bomb = 25, bio = 0, rad = 0) + +/obj/item/clothing/suit/armor/vest/warden + name = "warden's jacket" + desc = "An armoured jacket with silver rank pips and livery." + icon_state = "warden_jacket" + //item_state = "armor" + armor = list(melee = 50, bullet = 15, laser = 50, energy = 10, bomb = 25, bio = 0, rad = 0) + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + cold_protection = UPPER_TORSO|LOWER_TORSO|ARMS + heat_protection = UPPER_TORSO|LOWER_TORSO|ARMS + +/obj/item/clothing/suit/armor/swat/officer + name = "officer jacket" + desc = "An armored jacket used in special operations." + icon_state = "detective" + //item_state = "det_suit" + blood_overlay_type = "coat" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + cold_protection = UPPER_TORSO|LOWER_TORSO|ARMS + heat_protection = UPPER_TORSO|LOWER_TORSO|ARMS + valid_accessory_slots = list(ACCESSORY_SLOT_INSIGNIA) + + +/obj/item/clothing/suit/armor/det_suit + name = "armor" + desc = "An armored vest with a detective's badge on it." + icon_state = "detective-armor" + //item_state = "armor" + blood_overlay_type = "armor" + body_parts_covered = UPPER_TORSO|LOWER_TORSO + armor = list(melee = 50, bullet = 15, laser = 50, energy = 10, bomb = 25, bio = 0, rad = 0) + + +//Reactive armor +//When the wearer gets hit, this armor will teleport the user a short distance away (to safety or to more danger, no one knows. That's the fun of it!) +/obj/item/clothing/suit/armor/reactive + name = "reactive teleport armor" + desc = "Someone separated our Research Director from their own head!" + var/active = 0.0 + icon_state = "reactiveoff" + item_state = "reactiveoff" + blood_overlay_type = "armor" + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0) + +/obj/item/clothing/suit/armor/reactive/New() + ..() + slowdown_per_slot[slot_wear_suit] = 1 + +/obj/item/clothing/suit/armor/reactive/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + if(prob(50)) + user.visible_message("The reactive teleport system flings [user] clear of the attack!") + var/list/turfs = new/list() + for(var/turf/T in orange(6, user)) + if(istype(T,/turf/space)) continue + if(T.density) continue + if(T.x>world.maxx-6 || T.x<6) continue + if(T.y>world.maxy-6 || T.y<6) continue + turfs += T + if(!turfs.len) turfs += pick(/turf in orange(6)) + var/turf/picked = pick(turfs) + if(!isturf(picked)) return + + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, user.loc) + spark_system.start() + playsound(user.loc, "sparks", 50, 1) + + user.loc = picked + return PROJECTILE_FORCE_MISS + return 0 + +/obj/item/clothing/suit/armor/reactive/attack_self(mob/user as mob) + src.active = !( src.active ) + if (src.active) + to_chat(user, "The reactive armor is now active.") + src.icon_state = "reactive" + src.item_state = "reactive" + else + to_chat(user, "The reactive armor is now inactive.") + src.icon_state = "reactiveoff" + src.item_state = "reactiveoff" + src.add_fingerprint(user) + return + +/obj/item/clothing/suit/armor/reactive/emp_act(severity) + active = 0 + src.icon_state = "reactiveoff" + src.item_state = "reactiveoff" + ..() + + +//Non-hardsuit ERT armor. +//Commander +/obj/item/clothing/suit/armor/vest/ert + name = "asset protection command armor" + desc = "A set of armor worn by many corporate and private asset protection forces. Has blue highlights." + icon_state = "ertarmor_cmd" + item_state = "armor" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + armor = list(melee = 60, bullet = 60, laser = 60, energy = 40, bomb = 20, bio = 0, rad = 0) + +//Security +/obj/item/clothing/suit/armor/vest/ert/security + name = "asset protection security armor" + desc = "A set of armor worn by many corporate and private asset protection forces. Has red highlights." + icon_state = "ertarmor_sec" + +//Engineer +/obj/item/clothing/suit/armor/vest/ert/engineer + name = "asset protection engineering armor" + desc = "A set of armor worn by many corporate and private asset protection forces. Has orange highlights." + icon_state = "ertarmor_eng" + +//Medical +/obj/item/clothing/suit/armor/vest/ert/medical + name = "asset protection medical armor" + desc = "A set of armor worn by many corporate and private asset protection forces. Has red and white highlights." + icon_state = "ertarmor_med" + +//New Vests +/obj/item/clothing/suit/armor/vest + name = "armored vest" + desc = "An armor vest made of synthetic fibers." + icon_state = "kvest" + item_state = "armor" + armor = list(melee = 25, bullet = 30, laser = 30, energy = 10, bomb = 25, bio = 0, rad = 0) + valid_accessory_slots = list(ACCESSORY_SLOT_INSIGNIA) + +/obj/item/clothing/suit/armor/vest/nt + name = "\improper NanoTrasen armored vest" + desc = "A synthetic armor vest. This one is marked with the crest of NanoTrasen." + icon_state = "ntvest" + +/obj/item/clothing/suit/armor/vest/detective + name = "brown armored vest" + desc = "An synthetic armor vest colored in a vintage brown." + icon_state = "detvest" + +/obj/item/clothing/suit/armor/vest/pcrc + name = "contractor armored vest" + desc = "A synthetic armor vest. This one is marked with the crest of Proxima Centauri Risk Control, a private security firm." + icon_state = "pcrcvest" + +/obj/item/clothing/suit/armor/vest/press + name = "press armored vest" + desc = "A synthetic armor vest. This one is blue and has patches with the word 'PRESS' on the back and front." + icon_state = "pvest" + +/obj/item/clothing/suit/storage/vest + name = "webbed armor vest" + desc = "A synthetic armor vest. This one has added webbing and ballistic plates." + icon_state = "webvest" + armor = list(melee = 40, bullet = 40, laser = 40, energy = 25, bomb = 30, bio = 0, rad = 0) + valid_accessory_slots = list(ACCESSORY_SLOT_INSIGNIA) + allowed = list(/obj/item/weapon/gun/energy,/obj/item/device/radio,/obj/item/weapon/reagent_containers/spray/pepper,/obj/item/weapon/gun/projectile,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs) + body_parts_covered = UPPER_TORSO|LOWER_TORSO + item_flags = ITEM_FLAG_THICKMATERIAL + cold_protection = UPPER_TORSO|LOWER_TORSO + min_cold_protection_temperature = ARMOR_MIN_COLD_PROTECTION_TEMPERATURE + heat_protection = UPPER_TORSO|LOWER_TORSO + max_heat_protection_temperature = ARMOR_MAX_HEAT_PROTECTION_TEMPERATURE + siemens_coefficient = 0.6 + +/obj/item/clothing/suit/storage/vest/nt + name = "corporate security heavy armored vest" + desc = "A synthetic armor vest with CORPORATE SECURITY printed in red lettering on the chest. This one has added webbing and ballistic plates." + icon_state = "ntwebvest" + +/obj/item/clothing/suit/storage/vest/nt/warden + name = "warden heavy armored vest" + desc = "A synthetic armor vest with WARDEN printed in silver lettering on the chest. This one has added webbing and ballistic plates." + icon_state = "secwebvest" + +/obj/item/clothing/suit/storage/vest/nt/hos + name = "commander heavy armored vest" + desc = "A synthetic armor vest with COMMANDER printed in gold lettering on the chest. This one has added webbing and ballistic plates." + icon_state = "comwebvest" + +/obj/item/clothing/suit/storage/vest/pcrc + name = "contractor heavy armored vest" + desc = "A synthetic armor vest with PRIVATE SECURITY printed in cyan lettering on the chest. This one has added webbing and ballistic plates." + icon_state = "pcrcwebvest" + +/obj/item/clothing/suit/storage/vest/tactical //crack at a more balanced mid-range armor, minor improvements over standard vests, with the idea "modern" combat armor would focus on energy weapon protection. + name = "tactical armored vest" + desc = "A heavy armored vest in a fetching tan. It is surprisingly flexible and light, even with the extra webbing and advanced ceramic plates." + icon_state = "tacwebvest" + item_state = "tacwebvest" + armor = list(melee = 40, bullet = 40, laser = 60, energy = 35, bomb = 30, bio = 0, rad = 0) + +/obj/item/clothing/suit/storage/vest/merc + name = "heavy combat armor" + desc = "A high-quality armored vest made from a hard synthetic material. It is surprisingly flexible and light, despite formidable armor plating." + icon_state = "mercwebvest" + item_state = "mercwebvest" + armor = list(melee = 60, bullet = 60, laser = 60, energy = 40, bomb = 40, bio = 0, rad = 0) + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS //now covers legs with new sprite + cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS + heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS + +//Modular plate carriers +/obj/item/clothing/suit/armor/pcarrier + name = "plate carrier" + desc = "A lightweight black plate carrier vest. It can be equipped with armor plates, but provides no protection of its own." + icon = 'icons/obj/clothing/modular_armor.dmi' + item_icons = list(slot_wear_suit_str = 'icons/mob/onmob/modular_armor.dmi') + icon_state = "pcarrier" + valid_accessory_slots = list(ACCESSORY_SLOT_INSIGNIA, ACCESSORY_SLOT_ARMOR_C, ACCESSORY_SLOT_ARMOR_A, ACCESSORY_SLOT_ARMOR_L, ACCESSORY_SLOT_ARMOR_S, ACCESSORY_SLOT_ARMOR_M) + restricted_accessory_slots = list(ACCESSORY_SLOT_INSIGNIA, ACCESSORY_SLOT_ARMOR_C, ACCESSORY_SLOT_ARMOR_A, ACCESSORY_SLOT_ARMOR_L, ACCESSORY_SLOT_ARMOR_S) + blood_overlay_type = "armor" + +/obj/item/clothing/suit/armor/pcarrier/light + starting_accessories = list(/obj/item/clothing/accessory/armorplate) + +/obj/item/clothing/suit/armor/pcarrier/light/nt + starting_accessories = list(/obj/item/clothing/accessory/armorplate, /obj/item/clothing/accessory/armor/tag/nt) + +/obj/item/clothing/suit/armor/pcarrier/light/press + starting_accessories = list(/obj/item/clothing/accessory/armorplate, /obj/item/clothing/accessory/armor/tag/press) + +/obj/item/clothing/suit/armor/pcarrier/medium + starting_accessories = list(/obj/item/clothing/accessory/armorplate/medium, /obj/item/clothing/accessory/storage/pouches) + +/obj/item/clothing/suit/armor/pcarrier/medium/nt + starting_accessories = list(/obj/item/clothing/accessory/armorplate/medium, /obj/item/clothing/accessory/storage/pouches, /obj/item/clothing/accessory/armor/tag/nt) + +/obj/item/clothing/suit/armor/pcarrier/blue + name = "blue plate carrier" + desc = "A lightweight blue plate carrier vest. It can be equipped with armor plates, but provides no protection of its own." + icon_state = "pcarrier_blue" + +/obj/item/clothing/suit/armor/pcarrier/green + name = "green plate carrier" + desc = "A lightweight green plate carrier vest. It can be equipped with armor plates, but provides no protection of its own." + icon_state = "pcarrier_green" + +/obj/item/clothing/suit/armor/pcarrier/navy + name = "navy plate carrier" + desc = "A lightweight navy blue plate carrier vest. It can be equipped with armor plates, but provides no protection of its own." + icon_state = "pcarrier_navy" + +/obj/item/clothing/suit/armor/pcarrier/tan + name = "tan plate carrier" + desc = "A lightweight tan plate carrier vest. It can be equipped with armor plates, but provides no protection of its own." + icon_state = "pcarrier_tan" + +/obj/item/clothing/suit/armor/pcarrier/tan/tactical + name = "tactical plate carrier" + starting_accessories = list(/obj/item/clothing/accessory/armorplate/tactical, /obj/item/clothing/accessory/storage/pouches/large/tan) + +/obj/item/clothing/suit/armor/pcarrier/merc + starting_accessories = list(/obj/item/clothing/accessory/armorplate/merc, /obj/item/clothing/accessory/armguards/merc, /obj/item/clothing/accessory/legguards/merc, /obj/item/clothing/accessory/storage/pouches/large) + +//Modular specialty armor +/obj/item/clothing/suit/armor/riot + name = "riot vest" + desc = "An armored vest with heavy padding to protect against melee attacks." + icon = 'icons/obj/clothing/modular_armor.dmi' + item_icons = list(slot_wear_suit_str = 'icons/mob/onmob/modular_armor.dmi') + icon_state = "riot" + valid_accessory_slots = list(ACCESSORY_SLOT_INSIGNIA, ACCESSORY_SLOT_ARMOR_A, ACCESSORY_SLOT_ARMOR_L) + restricted_accessory_slots = list(ACCESSORY_SLOT_INSIGNIA, ACCESSORY_SLOT_ARMOR_A, ACCESSORY_SLOT_ARMOR_L) + body_parts_covered = UPPER_TORSO|LOWER_TORSO + armor = list(melee = 75, bullet = 33, laser = 50, energy = 10, bomb = 25, bio = 0, rad = 0) + siemens_coefficient = 0.5 + starting_accessories = list(/obj/item/clothing/accessory/armguards/riot, /obj/item/clothing/accessory/legguards/riot) + +/obj/item/clothing/suit/armor/bulletproof + name = "ballistic vest" + desc = "An armored vest with heavy plates to protect against ballistic projectiles." + icon = 'icons/obj/clothing/modular_armor.dmi' + item_icons = list(slot_wear_suit_str = 'icons/mob/onmob/modular_armor.dmi') + icon_state = "ballistic" + valid_accessory_slots = list(ACCESSORY_SLOT_INSIGNIA, ACCESSORY_SLOT_ARMOR_A, ACCESSORY_SLOT_ARMOR_L) + restricted_accessory_slots = list(ACCESSORY_SLOT_INSIGNIA, ACCESSORY_SLOT_ARMOR_A, ACCESSORY_SLOT_ARMOR_L) + body_parts_covered = UPPER_TORSO|LOWER_TORSO + armor = list(melee = 42, bullet = 75, laser = 42, energy = 10, bomb = 25, bio = 0, rad = 0) + siemens_coefficient = 0.7 + starting_accessories = list(/obj/item/clothing/accessory/armguards/ballistic, /obj/item/clothing/accessory/legguards/ballistic) + +/obj/item/clothing/suit/armor/bulletproof/vest //because apparently some map uses this somewhere and I'm too lazy to go looking for and replacing it. + starting_accessories = null + +/obj/item/clothing/suit/armor/laserproof + name = "ablative vest" + desc = "An armored vest with advanced shielding to protect against energy weapons." + icon = 'icons/obj/clothing/modular_armor.dmi' + item_icons = list(slot_wear_suit_str = 'icons/mob/onmob/modular_armor.dmi') + icon_state = "ablative" + valid_accessory_slots = list(ACCESSORY_SLOT_INSIGNIA, ACCESSORY_SLOT_ARMOR_A, ACCESSORY_SLOT_ARMOR_L) + restricted_accessory_slots = list(ACCESSORY_SLOT_INSIGNIA, ACCESSORY_SLOT_ARMOR_A, ACCESSORY_SLOT_ARMOR_L) + body_parts_covered = UPPER_TORSO|LOWER_TORSO + armor = list(melee = 35, bullet = 35, laser = 75, energy = 50, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 0 + starting_accessories = list(/obj/item/clothing/accessory/armguards/ablative, /obj/item/clothing/accessory/legguards/ablative) + +/obj/item/clothing/suit/armor/laserproof/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + if(istype(damage_source, /obj/item/projectile/energy) || istype(damage_source, /obj/item/projectile/beam)) + var/obj/item/projectile/P = damage_source + + var/reflectchance = 40 - round(damage/3) + if(!(def_zone in list(BP_CHEST, BP_GROIN))) //not changing this so arm and leg shots reflect, gives some incentive to not aim center-mass + reflectchance /= 2 + if(P.starting && prob(reflectchance)) + visible_message("\The [user]'s [src.name] reflects [attack_text]!") + + // Find a turf near or on the original location to bounce to + //var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2) + //var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2) + //var/turf/curloc = get_turf(user) + + // redirect the projectile + //P.redirect(new_x, new_y, curloc, user) + + return PROJECTILE_CONTINUE // complete projectile permutation + +//All of the armor below is mostly unused + + +/obj/item/clothing/suit/armor/centcomm + name = "\improper Cent. Com. armor" + desc = "A suit that protects against some damage." + icon_state = "centcom" + item_state = "centcom" + w_class = ITEM_SIZE_HUGE//bulky item + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + allowed = list(/obj/item/weapon/gun/energy,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/tank/emergency) + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT + cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + siemens_coefficient = 0 + +/obj/item/clothing/suit/armor/heavy + name = "heavy armor" + desc = "A heavily armored suit that protects against moderate damage." + icon_state = "heavy" + item_state = "swat_suit" + w_class = ITEM_SIZE_HUGE//bulky item + gas_transfer_coefficient = 0.90 + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT + siemens_coefficient = 0 + +/obj/item/clothing/suit/armor/heavy/New() + ..() + slowdown_per_slot[slot_wear_suit] = 3 + +/obj/item/clothing/suit/armor/tdome + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT + +/obj/item/clothing/suit/armor/tdome/red + name = "thunderdome suit (red)" + desc = "Reddish armor." + icon_state = "tdred" + item_state = "tdred" + siemens_coefficient = 1 + +/obj/item/clothing/suit/armor/tdome/green + name = "thunderdome suit (green)" + desc = "Pukish armor." + icon_state = "tdgreen" + item_state = "tdgreen" + siemens_coefficient = 1 + +/obj/item/clothing/suit/storage/vest/tactical/mirania + name = "bundeforz armored vest" + desc = "A heavy armored vest in a light grey urban camo. It is surprisingly flexible and light, even with the extra webbing and advanced ceramic plates." + icon_state = "m_vest" + item_state = "m_vest" + + +/obj/item/clothing/suit/armor/vest/warden/explorer + name = "salvage miner's jacket" + desc = "An armoured jacket, for when the rogue mining drones finally catch up." + icon_state = "explorer" + item_state = "explorer" \ No newline at end of file diff --git a/code/modules/clothing/suits/bio.dm b/code/modules/clothing/suits/bio.dm new file mode 100644 index 00000000..afaa9c6a --- /dev/null +++ b/code/modules/clothing/suits/bio.dm @@ -0,0 +1,100 @@ +//Biosuit complete with shoes (in the item sprite) +/obj/item/clothing/head/bio_hood + name = "bio hood" + icon_state = "bio" + item_state_slots = list( + slot_l_hand_str = "bio_hood", + slot_r_hand_str = "bio_hood", + ) + desc = "A hood that protects the head and face from biological comtaminants." + permeability_coefficient = 0 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 20) + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|BLOCKHAIR + body_parts_covered = HEAD|FACE|EYES + siemens_coefficient = 0.9 + +/obj/item/clothing/suit/bio_suit + name = "bio suit" + desc = "A suit that protects against biological contamination." + icon_state = "bio" + item_state_slots = list( + slot_l_hand_str = "bio_suit", + slot_r_hand_str = "bio_suit", + ) + w_class = ITEM_SIZE_HUGE//bulky item + gas_transfer_coefficient = 0 + permeability_coefficient = 0 + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + allowed = list(/obj/item/weapon/tank/emergency,/obj/item/weapon/pen,/obj/item/device/flashlight/pen,/obj/item/device/healthanalyzer,/obj/item/device/ano_scanner,/obj/item/clothing/head/bio_hood,/obj/item/clothing/mask/gas) + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 20) + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL + siemens_coefficient = 0.9 + +/obj/item/clothing/suit/bio_suit/New() + ..() + slowdown_per_slot[slot_wear_suit] = 1.0 + +//Standard biosuit, orange stripe +/obj/item/clothing/head/bio_hood/general + icon_state = "bio_general" + body_parts_covered = HEAD|FACE|EYES + +/obj/item/clothing/suit/bio_suit/general + icon_state = "bio_general" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS|HANDS|FEET + flags_inv = HIDEJUMPSUIT|HIDETAIL|HIDEGLOVES|HIDESHOES + +//Virology biosuit, green stripe +/obj/item/clothing/head/bio_hood/virology + icon_state = "bio_virology" + +/obj/item/clothing/suit/bio_suit/virology + icon_state = "bio_virology" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS|HANDS|FEET + flags_inv = HIDEJUMPSUIT|HIDETAIL|HIDEGLOVES|HIDESHOES + +//Security biosuit, grey with red stripe across the chest +/obj/item/clothing/head/bio_hood/security + icon_state = "bio_security" + +/obj/item/clothing/suit/bio_suit/security + icon_state = "bio_security" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS|HANDS|FEET + flags_inv = HIDEJUMPSUIT|HIDETAIL|HIDEGLOVES|HIDESHOES + +//Janitor's biosuit, grey with purple arms +/obj/item/clothing/head/bio_hood/janitor + icon_state = "bio_janitor" + +/obj/item/clothing/suit/bio_suit/janitor + icon_state = "bio_janitor" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS|HANDS|FEET + flags_inv = HIDEJUMPSUIT|HIDETAIL|HIDEGLOVES|HIDESHOES + + +//Scientist's biosuit, white with a pink-ish hue +/obj/item/clothing/head/bio_hood/scientist + icon_state = "bio_scientist" + +/obj/item/clothing/suit/bio_suit/scientist + icon_state = "bio_scientist" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS|HANDS|FEET + flags_inv = HIDEJUMPSUIT|HIDETAIL|HIDEGLOVES|HIDESHOES + +//CMO's biosuit, blue stripe +/obj/item/clothing/suit/bio_suit/cmo + icon_state = "bio_cmo" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS|HANDS|FEET + flags_inv = HIDEJUMPSUIT|HIDETAIL|HIDEGLOVES|HIDESHOES + +/obj/item/clothing/head/bio_hood/cmo + icon_state = "bio_cmo" + + +//Plague Dr mask can be found in clothing/masks/gasmask.dm +/obj/item/clothing/suit/bio_suit/plaguedoctorsuit + name = "Plague doctor suit" + desc = "It protected doctors from the Black Death, back then. You bet your arse it's gonna help you against viruses." + icon_state = "plaguedoctor" + //item_state = "bio_suit" + flags_inv = HIDEGLOVES|HIDEJUMPSUIT|HIDETAIL diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm new file mode 100644 index 00000000..8d27323b --- /dev/null +++ b/code/modules/clothing/suits/jobs.dm @@ -0,0 +1,221 @@ +/* + * Job related + */ + +//Botonist +/obj/item/clothing/suit/apron + name = "apron" + desc = "A basic blue apron." + icon_state = "apron" + item_state = "apron" + blood_overlay_type = "armor" + body_parts_covered = 0 + allowed = list (/obj/item/weapon/reagent_containers/spray/plantbgone,/obj/item/device/analyzer/plant_analyzer,/obj/item/seeds,/obj/item/weapon/reagent_containers/glass/bottle,/obj/item/weapon/material/minihoe) + +//Magistrate +/obj/item/clothing/suit/robes + name = "commandant's robes" + desc = "Fit for a king... or a uh... Commandant." + icon_state = "robes" + item_state = "robes" + body_parts_covered = UPPER_TORSO|ARMS + +//Captain +/obj/item/clothing/suit/captunic + name = "captain's parade tunic" + desc = "Worn by a Captain to show their class." + icon_state = "captunic" + item_state = "captunic" + body_parts_covered = UPPER_TORSO|ARMS + flags_inv = HIDEJUMPSUIT + +/obj/item/clothing/suit/captunic/capjacket + name = "captain's uniform jacket" + desc = "A less formal jacket for everyday captain use." + icon_state = "capjacket" + item_state = "capjacket" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + flags_inv = 0 + +//Chaplain +/obj/item/clothing/suit/chaplain_hoodie + name = "chaplain hoodie" + desc = "This suit says to you 'hush'!" + icon_state = "chaplain_hoodie" + item_state = "chaplain_hoodie" + body_parts_covered = UPPER_TORSO|ARMS + +//Chaplain +/obj/item/clothing/suit/nun + name = "nun robe" + desc = "Maximum piety in this star system." + icon_state = "nun" + item_state = "nun" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + flags_inv = HIDESHOES|HIDEJUMPSUIT + +//Chef +/obj/item/clothing/suit/chef + name = "chef's apron" + desc = "An apron used by a high class chef." + icon_state = "chef" + item_state = "chef" + gas_transfer_coefficient = 0.90 + permeability_coefficient = 0.50 + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + allowed = list (/obj/item/weapon/material/knife) + +//Chef +/obj/item/clothing/suit/chef/classic + name = "classic chef's apron" + desc = "A basic, dull, white chef's apron." + icon_state = "apronchef" + item_state = "apronchef" + blood_overlay_type = "armor" + body_parts_covered = 0 + +//Security +/obj/item/clothing/suit/security/navyofficer + name = "security officer's jacket" + desc = "This jacket is for those special occasions when a security officer actually feels safe." + icon_state = "officerbluejacket" + item_state = "officerbluejacket" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + +/obj/item/clothing/suit/security/navywarden + name = "warden's jacket" + desc = "Perfectly suited for the warden that wants to leave an impression of style on those who visit the brig." + icon_state = "wardenbluejacket" + item_state = "wardenbluejacket" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + +/obj/item/clothing/suit/security/navyhos + name = "head of security's jacket" + desc = "This piece of clothing was specifically designed for asserting superior authority." + icon_state = "hosbluejacket" + item_state = "hosbluejacket" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + +//Detective +/obj/item/clothing/suit/storage/det_trench + name = "brown trenchcoat" + desc = "A rugged canvas trenchcoat, designed and created by TX Fabrication Corp. The coat is externally impact resistant - perfect for your next act of autodefenestration!" + icon_state = "detective" + //item_state = "det_suit" + valid_accessory_slots = list(ACCESSORY_SLOT_INSIGNIA) + blood_overlay_type = "coat" + body_parts_covered = UPPER_TORSO|ARMS + allowed = list(/obj/item/weapon/tank/emergency,/obj/item/device/flashlight,/obj/item/weapon/gun/energy,/obj/item/weapon/gun/projectile,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter,/obj/item/device/taperecorder) + armor = list(melee = 50, bullet = 10, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0) + +/obj/item/clothing/suit/storage/det_trench/grey + name = "grey trenchcoat" + icon_state = "detective2" + +//Forensics +/obj/item/clothing/suit/storage/forensics + name = "jacket" + desc = "A forensics technician jacket." + item_state = "det_suit" + body_parts_covered = UPPER_TORSO|ARMS + allowed = list(/obj/item/weapon/tank/emergency,/obj/item/device/flashlight,/obj/item/weapon/gun/energy,/obj/item/weapon/gun/projectile,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/device/taperecorder) + armor = list(melee = 10, bullet = 10, laser = 15, energy = 10, bomb = 0, bio = 0, rad = 0) + +/obj/item/clothing/suit/storage/forensics/red + name = "red jacket" + desc = "A red forensics technician jacket." + icon_state = "forensics_red" + +/obj/item/clothing/suit/storage/forensics/blue + name = "blue jacket" + desc = "A blue forensics technician jacket." + icon_state = "forensics_blue" + +//Engineering +/obj/item/clothing/suit/storage/hazardvest + name = "hazard vest" + desc = "A high-visibility vest used in work zones." + icon_state = "hazard" + item_state = "hazard" + blood_overlay_type = "armor" + allowed = list (/obj/item/device/analyzer, /obj/item/device/flashlight, /obj/item/device/multitool, /obj/item/device/pipe_painter, /obj/item/device/radio, /obj/item/device/t_scanner, \ + /obj/item/weapon/crowbar, /obj/item/weapon/screwdriver, /obj/item/weapon/weldingtool, /obj/item/weapon/wirecutters, /obj/item/weapon/wrench, /obj/item/weapon/tank/emergency, \ + /obj/item/clothing/mask/gas, /obj/item/taperoll/engineering) + body_parts_covered = UPPER_TORSO + +/obj/item/clothing/suit/storage/hazardvest/blue + name = "blue hazard vest" + desc = "A high-visibility vest used in work zones. This one is blue!" + icon_state = "hazard_b" + +/obj/item/clothing/suit/storage/hazardvest/white + name = "white hazard vest" + desc = "A high-visibility vest used in work zones. This one has a red cross!" + icon_state = "hazard_w" + +/obj/item/clothing/suit/storage/hazardvest/green + name = "green hazard vest" + desc = "A high-visibility vest used in work zones. This one is green!" + icon_state = "hazard_g" + +//Lawyer +/obj/item/clothing/suit/storage/toggle/suit + name = "suit jacket" + desc = "A snappy dress jacket." + icon_state = "suitjacket_open" + item_state = "suitjacket_open" + icon_open = "suitjacket_open" + icon_closed = "suitjacket" + blood_overlay_type = "coat" + body_parts_covered = UPPER_TORSO|ARMS + +/obj/item/clothing/suit/storage/toggle/suit/blue + name = "blue suit jacket" + color = "#00326e" + +/obj/item/clothing/suit/storage/toggle/suit/purple + name = "purple suit jacket" + color = "#6c316c" + +/obj/item/clothing/suit/storage/toggle/suit/black + name = "black suit jacket" + color = "#1f1f1f" + +//Medical +/obj/item/clothing/suit/storage/toggle/fr_jacket + name = "first responder jacket" + desc = "A high-visibility jacket worn by medical first responders." + icon_state = "fr_jacket_open" + item_state = "fr_jacket" + icon_open = "fr_jacket_open" + icon_closed = "fr_jacket" + blood_overlay_type = "armor" + allowed = list(/obj/item/stack/medical, /obj/item/weapon/reagent_containers/dropper, /obj/item/weapon/reagent_containers/hypospray, /obj/item/weapon/reagent_containers/syringe, \ + /obj/item/device/healthanalyzer, /obj/item/device/flashlight, /obj/item/device/radio, /obj/item/weapon/tank/emergency) + body_parts_covered = UPPER_TORSO|ARMS + +/obj/item/clothing/suit/storage/toggle/fr_jacket/ems + name = "\improper EMS jacket" + desc = "A dark blue, martian-pattern, EMS jacket. It sports high-visibility reflective stripes and a star of life on the back." + icon_state = "ems_jacket_closed" + item_state = "ems_jacket_closed" + icon_open = "ems_jacket_open" + icon_closed = "ems_jacket_closed" + +/obj/item/clothing/suit/surgicalapron + name = "surgical apron" + desc = "A sterile blue apron for performing surgery." + icon_state = "surgical" + item_state = "surgical" + blood_overlay_type = "armor" + body_parts_covered = UPPER_TORSO|LOWER_TORSO + allowed = list(/obj/item/stack/medical, /obj/item/weapon/reagent_containers/dropper, /obj/item/weapon/reagent_containers/hypospray, /obj/item/weapon/reagent_containers/syringe, \ + /obj/item/device/healthanalyzer, /obj/item/device/flashlight, /obj/item/device/radio, /obj/item/weapon/tank/emergency,/obj/item/weapon/scalpel,/obj/item/weapon/retractor,/obj/item/weapon/hemostat, \ + /obj/item/weapon/cautery,/obj/item/weapon/bonegel,/obj/item/weapon/FixOVein) + +/obj/item/clothing/suit/storage/doctor_vest + name = "doctor\'s vest" + desc = "A vest worn by doctors. Comes with pockets for bandages and the like." + icon_state = "doctor_vest" + item_state = "doctor_vest" + blood_overlay_type = "armor" diff --git a/code/modules/clothing/suits/labcoat.dm b/code/modules/clothing/suits/labcoat.dm new file mode 100644 index 00000000..bf2f19f0 --- /dev/null +++ b/code/modules/clothing/suits/labcoat.dm @@ -0,0 +1,94 @@ +/obj/item/clothing/suit/storage/toggle/labcoat + name = "labcoat" + desc = "A suit that protects against minor chemical spills." + icon_state = "labcoat_open" + //item_state = "labcoat" //Is this even used for anything? + icon_open = "labcoat_open" + icon_closed = "labcoat" + blood_overlay_type = "coat" + body_parts_covered = UPPER_TORSO|ARMS + allowed = list(/obj/item/device/analyzer,/obj/item/stack/medical,/obj/item/weapon/reagent_containers/dropper,/obj/item/weapon/reagent_containers/syringe,/obj/item/weapon/reagent_containers/hypospray,/obj/item/device/healthanalyzer,/obj/item/device/flashlight/pen,/obj/item/weapon/reagent_containers/glass/bottle,/obj/item/weapon/reagent_containers/glass/beaker,/obj/item/weapon/reagent_containers/pill,/obj/item/weapon/storage/pill_bottle,/obj/item/weapon/paper) + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 50, rad = 0) + valid_accessory_slots = list(ACCESSORY_SLOT_ARMBAND) + restricted_accessory_slots = list(ACCESSORY_SLOT_ARMBAND) + +/obj/item/clothing/suit/storage/toggle/labcoat/cmo + name = "chief medical officer's labcoat" + desc = "Bluer than the standard model." + icon_state = "labcoat_cmo_open" + //item_state = "labcoat_cmo" + icon_open = "labcoat_cmo_open" + icon_closed = "labcoat_cmo" + +/obj/item/clothing/suit/storage/toggle/labcoat/cmoalt + name = "chief medical officer labcoat" + desc = "A labcoat with command blue highlights." + icon_state = "labcoat_cmoalt_open" + icon_open = "labcoat_cmoalt_open" + icon_closed = "labcoat_cmoalt" + +/obj/item/clothing/suit/storage/toggle/labcoat/mad + name = "The Mad's labcoat" + desc = "It makes you look capable of konking someone on the noggin and shooting them into space." + icon_state = "labgreen_open" + //item_state = "labgreen" + icon_open = "labgreen_open" + icon_closed = "labgreen" + +/obj/item/clothing/suit/storage/toggle/labcoat/genetics + name = "Geneticist labcoat" + desc = "A suit that protects against minor chemical spills. Has a blue stripe on the shoulder." + icon_state = "labcoat_gen_open" + icon_open = "labcoat_gen_open" + icon_closed = "labcoat_gen" + +/obj/item/clothing/suit/storage/toggle/labcoat/chemist + name = "Chemist labcoat" + desc = "A suit that protects against minor chemical spills. Has an orange stripe on the shoulder." + icon_state = "labcoat_chem_open" + icon_open = "labcoat_chem_open" + icon_closed = "labcoat_chem" + +/obj/item/clothing/suit/storage/toggle/labcoat/virologist + name = "Virologist labcoat" + desc = "A suit that protects against minor chemical spills. Offers slightly more protection against biohazards than the standard model. Has a green stripe on the shoulder." + icon_state = "labcoat_vir_open" + icon_open = "labcoat_vir_open" + icon_closed = "labcoat_vir" + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 0) + +/obj/item/clothing/suit/storage/toggle/labcoat/science + name = "\improper NanoTrasen labcoat" + desc = "A suit that protects against minor chemical spills. Has a red stripe on the shoulder and red trim on the sleeves, denoting it as a NanoTrasen labcoat." + icon_state = "labcoat_nt_open" + icon_open = "labcoat_nt_open" + icon_closed = "labcoat_nt" + +/obj/item/clothing/suit/storage/toggle/labcoat/rd + name = "research director's labcoat" + desc = "A full-body labcoat covered in red and black designs, denoting it as a NanoTrasen management coat. Judging by the amount of designs on it, it is only to be worn by the most enthusiastic of NanoTrasen employees." + icon_state = "labcoat_rd_open" + icon_open = "labcoat_rd_open" + icon_closed = "labcoat_rd" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + +/obj/item/clothing/suit/storage/toggle/labcoat/blue + name = "blue-edged labcoat" + desc = "A suit that protects against minor chemical spills. This one has blue trim." + icon_state = "blue_edge_labcoat_open" + icon_open = "blue_edge_labcoat_open" + icon_closed = "blue_edge_labcoat" + +/obj/item/clothing/suit/storage/toggle/labcoat/coat + name = "coat" + desc = "A cozy overcoat." + color = "#292929" + +/obj/item/clothing/suit/storage/toggle/labcoat/xyn_machine + name = "\improper Xynergy labcoat" + desc = "A stiffened, stylised labcoat designed to fit IPCs. It has blue and purple trim, denoting it as a Xynergy labcoat." + icon_state = "labcoat_xy" + icon_open = "labcoat_xy_open" + icon_closed = "labcoat_xy" + armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 20, rad = 0) + species_restricted = list(SPECIES_IPC) diff --git a/code/modules/clothing/suits/mirania.dm b/code/modules/clothing/suits/mirania.dm new file mode 100644 index 00000000..cabdc932 --- /dev/null +++ b/code/modules/clothing/suits/mirania.dm @@ -0,0 +1,23 @@ +/obj/item/clothing/suit/storage/service/mirania + name = "bundeforz service jacket" + desc = "A uniform service jacket belonging to the Miranian Defence Forces." + icon_state = "m_service" + item_state = "m_service" + +/obj/item/clothing/suit/storage/service/mirania/intelligence + name = "intelligence service jacket" + desc = "A uniform service jacket belonging to the Miranian Truth Ministry." + item_state = "m_service_int" + icon_state = "m_service_int" + +/obj/item/clothing/suit/dress/mirania + name = "bundeforz dress jacket" + desc = "A dress jacket belonging to the Miranian Defence Forces. Fashionable, for the 25th century at least." + icon_state = "m_dress" + item_state = "m_dress" + +/obj/item/clothing/suit/dress/mirania/intelligence + name = "intelligence service dress jacket" + desc = "A dress jacket belonging to the Miranian Truth Ministry. Fashionable, for the 25th century at least." + item_state = "m_dress_int" + icon_state = "m_dress_int" \ No newline at end of file diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm new file mode 100644 index 00000000..f32e316b --- /dev/null +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -0,0 +1,548 @@ +/* + * Contains: + * Lasertag + * Costume + * Misc + */ + +/* + * Lasertag + */ +/obj/item/clothing/suit/bluetag + name = "blue laser tag armour" + desc = "Blue Pride, Galaxy Wide." + icon_state = "bluetag" + item_state = "bluetag" + blood_overlay_type = "armor" + body_parts_covered = UPPER_TORSO + allowed = list (/obj/item/weapon/gun/energy/lasertag/blue) + siemens_coefficient = 3.0 + +/obj/item/clothing/suit/kaneda + name = "Torchiok bomber" + icon_state = "kaneda" + + +/obj/item/clothing/suit/redtag + name = "red laser tag armour" + desc = "Reputed to go faster." + icon_state = "redtag" + item_state = "redtag" + blood_overlay_type = "armor" + body_parts_covered = UPPER_TORSO + allowed = list (/obj/item/weapon/gun/energy/lasertag/red) + siemens_coefficient = 3.0 + +/* + * Costume + */ +/obj/item/clothing/suit/pirate + name = "pirate coat" + desc = "Yarr." + icon_state = "pirate" + item_state = "pirate" + body_parts_covered = UPPER_TORSO|ARMS + + +/obj/item/clothing/suit/hgpirate + name = "pirate captain coat" + desc = "Yarr." + icon_state = "hgpirate" + item_state = "hgpirate" + flags_inv = HIDEJUMPSUIT + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS|LEGS + + +/obj/item/clothing/suit/cyborg_suit + name = "cyborg suit" + desc = "Suit for a cyborg costume." + icon_state = "death" + item_state = "death" + obj_flags = OBJ_FLAG_CONDUCTIBLE + fire_resist = T0C+5200 + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT + + +/obj/item/clothing/suit/greatcoat + name = "great coat" + desc = "A heavy great coat." + icon_state = "nazi" + item_state = "nazi" + + +/obj/item/clothing/suit/johnny_coat + name = "johnny~~ coat" + desc = "Johnny~~" + icon_state = "johnny" + item_state = "johnny" + + +/obj/item/clothing/suit/justice + name = "justice suit" + desc = "This pretty much looks ridiculous." + icon_state = "justice" + item_state = "justice" + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS|HANDS|LEGS|FEET + + +/obj/item/clothing/suit/judgerobe + name = "judge's robe" + desc = "This robe commands authority." + icon_state = "judge" + item_state = "judge" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + allowed = list(/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/spacecash) + flags_inv = HIDEJUMPSUIT + + +/obj/item/clothing/suit/apron/overalls + name = "coveralls" + desc = "A set of denim overalls." + icon_state = "overalls" + item_state = "overalls" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS + + +/obj/item/clothing/suit/syndicatefake + name = "red space suit replica" + icon_state = "syndicate" + item_state = "space_suit_syndicate" + desc = "A plastic replica of the syndicate space suit, you'll look just like a real murderous syndicate agent in this! This is a toy, it is not made for use in space!" + w_class = ITEM_SIZE_NORMAL + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/emergency,/obj/item/toy) + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS|HANDS|LEGS|FEET + +/obj/item/clothing/suit/hastur + name = "Hastur's Robes" + desc = "Robes not meant to be worn by man." + icon_state = "hastur" + item_state = "hastur" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT + + +/obj/item/clothing/suit/imperium_monk + name = "Imperium monk" + desc = "Have YOU killed a xenos today?" + icon_state = "imperium_monk" + item_state = "imperium_monk" + body_parts_covered = HEAD|UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS + flags_inv = HIDESHOES|HIDEJUMPSUIT + + +/obj/item/clothing/suit/chickensuit + name = "Chicken Suit" + desc = "A suit made long ago by the ancient empire KFC." + icon_state = "chickensuit" + item_state = "chickensuit" + body_parts_covered = UPPER_TORSO|ARMS|LOWER_TORSO|LEGS|FEET + flags_inv = HIDESHOES|HIDEJUMPSUIT + siemens_coefficient = 2.0 + + +/obj/item/clothing/suit/monkeysuit + name = "Monkey Suit" + desc = "A suit that looks like a primate." + icon_state = "monkeysuit" + item_state = "monkeysuit" + body_parts_covered = UPPER_TORSO|ARMS|LOWER_TORSO|LEGS|FEET|HANDS + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT + siemens_coefficient = 2.0 + + +/obj/item/clothing/suit/holidaypriest + name = "Holiday Priest" + desc = "This is a nice holiday my son." + icon_state = "holidaypriest" + item_state = "holidaypriest" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + flags_inv = HIDEJUMPSUIT + + +/obj/item/clothing/suit/cardborg + name = "cardborg suit" + desc = "An ordinary cardboard box with holes cut in the sides." + icon_state = "cardborg" + item_state = "cardborg" + body_parts_covered = UPPER_TORSO|LOWER_TORSO + flags_inv = HIDEJUMPSUIT + +/obj/item/clothing/suit/cardborg/Initialize() + . = ..() + set_extension(src, /datum/extension/appearance, /datum/extension/appearance/cardborg) + +/* + * Misc + */ + +/obj/item/clothing/suit/straight_jacket + name = "straitjacket" + desc = "A suit that completely restrains the wearer." + icon_state = "straight_jacket" + item_state = "straight_jacket" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL + +/obj/item/clothing/suit/straight_jacket/equipped(var/mob/user, var/slot) + if(slot == slot_wear_suit) + if(iscarbon(user)) + var/mob/living/carbon/C = user + C.drop_from_inventory(C.handcuffed) + user.drop_l_hand() + user.drop_r_hand() + +/obj/item/clothing/suit/ianshirt + name = "worn shirt" + desc = "A worn out, curiously comfortable t-shirt with a picture of Ian. You wouldn't go so far as to say it feels like being hugged when you wear it, but it's pretty close. Good for sleeping in." + icon_state = "ianshirt" + item_state = "ianshirt" + body_parts_covered = UPPER_TORSO|ARMS + +//pyjamas +//originally intended to be pinstripes >.> + +/obj/item/clothing/under/bluepyjamas + name = "blue pyjamas" + desc = "Slightly old-fashioned sleepwear." + icon_state = "blue_pyjamas" + item_state = "blue_pyjamas" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS|LEGS + +/obj/item/clothing/under/redpyjamas + name = "red pyjamas" + desc = "Slightly old-fashioned sleepwear." + icon_state = "red_pyjamas" + item_state = "red_pyjamas" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS|LEGS + +//coats + +/obj/item/clothing/suit/leathercoat + name = "leather coat" + desc = "A long, thick black leather coat." + icon_state = "leathercoat" + item_state = "leathercoat" + +/obj/item/clothing/suit/browncoat + name = "brown leather coat" + desc = "A long, brown leather coat." + icon_state = "browncoat" + item_state = "browncoat" + +/obj/item/clothing/suit/neocoat + name = "black coat" + desc = "A flowing, black coat." + icon_state = "neocoat" + item_state = "neocoat" + +//stripper +/obj/item/clothing/under/stripper + body_parts_covered = 0 + +/obj/item/clothing/under/stripper/stripper_pink + name = "pink swimsuit" + desc = "A rather skimpy pink swimsuit." + icon_state = "stripper_p_under" + siemens_coefficient = 1 + +/obj/item/clothing/under/stripper/stripper_green + name = "green swimsuit" + desc = "A rather skimpy green swimsuit." + icon_state = "stripper_g_under" + siemens_coefficient = 1 + +/obj/item/clothing/suit/stripper/stripper_pink + name = "pink skimpy dress" + desc = "A rather skimpy pink dress." + icon_state = "stripper_p_over" + siemens_coefficient = 1 + +/obj/item/clothing/suit/stripper/stripper_green + name = "green skimpy dress" + desc = "A rather skimpy green dress." + icon_state = "stripper_g_over" + //item_state = "stripper_g" + siemens_coefficient = 1 + +/obj/item/clothing/under/stripper/mankini + name = "mankini" + desc = "No honest man would wear this abomination." + icon_state = "mankini" + siemens_coefficient = 1 + +/obj/item/clothing/suit/xenos + name = "xenos suit" + desc = "A suit made out of chitinous alien hide." + icon_state = "xenos" + //item_state = "xenos_helm" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT + siemens_coefficient = 2.0 +//swimsuit +/obj/item/clothing/under/swimsuit/ + siemens_coefficient = 1 + body_parts_covered = 0 + +/obj/item/clothing/under/swimsuit/black + name = "black swimsuit" + desc = "An oldfashioned black swimsuit." + icon_state = "swim_black" + siemens_coefficient = 1 + +/obj/item/clothing/under/swimsuit/blue + name = "blue swimsuit" + desc = "An oldfashioned blue swimsuit." + icon_state = "swim_blue" + siemens_coefficient = 1 + +/obj/item/clothing/under/swimsuit/purple + name = "purple swimsuit" + desc = "An oldfashioned purple swimsuit." + icon_state = "swim_purp" + siemens_coefficient = 1 + +/obj/item/clothing/under/swimsuit/green + name = "green swimsuit" + desc = "An oldfashioned green swimsuit." + icon_state = "swim_green" + siemens_coefficient = 1 + +/obj/item/clothing/under/swimsuit/red + name = "red swimsuit" + desc = "An oldfashioned red swimsuit." + icon_state = "swim_red" + siemens_coefficient = 1 + +/obj/item/clothing/suit/poncho/colored + name = "poncho" + desc = "A simple, comfortable poncho." + icon_state = "classicponcho" + item_state = "classicponcho" + +/obj/item/clothing/suit/poncho/colored/green + name = "green poncho" + desc = "A simple, comfortable cloak without sleeves. This one is green." + icon_state = "greenponcho" + item_state = "greenponcho" + +/obj/item/clothing/suit/poncho/colored/red + name = "red poncho" + desc = "A simple, comfortable cloak without sleeves. This one is red." + icon_state = "redponcho" + item_state = "redponcho" + +/obj/item/clothing/suit/poncho/colored/purple + name = "purple poncho" + desc = "A simple, comfortable cloak without sleeves. This one is purple." + icon_state = "purpleponcho" + item_state = "purpleponcho" + +/obj/item/clothing/suit/poncho/colored/blue + name = "blue poncho" + desc = "A simple, comfortable cloak without sleeves. This one is blue." + icon_state = "blueponcho" + item_state = "blueponcho" + +/obj/item/clothing/suit/storage/toggle/bomber + name = "bomber jacket" + desc = "A thick, well-worn WW2 leather bomber jacket." + icon_state = "bomber" + item_state = "bomber" + icon_open = "bomber_open" + icon_closed = "bomber" + body_parts_covered = UPPER_TORSO|ARMS + cold_protection = UPPER_TORSO|ARMS + min_cold_protection_temperature = T0C - 20 + siemens_coefficient = 0.7 + +/obj/item/clothing/suit/storage/leather_jacket + name = "leather jacket" + desc = "A black leather coat." + icon_state = "leather_jacket" + item_state = "leather_jacket" + body_parts_covered = UPPER_TORSO|ARMS + +/obj/item/clothing/suit/storage/leather_jacket/nanotrasen + desc = "A black leather coat. A corporate logo is proudly displayed on the back." + icon_state = "leather_jacket_nt" + +//This one has buttons for some reason +/obj/item/clothing/suit/storage/toggle/brown_jacket + name = "leather jacket" + desc = "A brown leather coat." + icon_state = "brown_jacket" + item_state = "brown_jacket" + icon_open = "brown_jacket_open" + icon_closed = "brown_jacket" + body_parts_covered = UPPER_TORSO|ARMS + +/obj/item/clothing/suit/storage/toggle/brown_jacket/nanotrasen + desc = "A brown leather coat. A corporate logo is proudly displayed on the back." + icon_state = "brown_jacket_nt" + icon_open = "brown_jacket_nt_open" + icon_closed = "brown_jacket_nt" + +/obj/item/clothing/suit/storage/toggle/marshal_jacket + name = "colonial marshal jacket" + desc = "A black leather jacket belonging to an agent of the Colonial Marshal Bureau." + icon_state = "marshal_jacket" + item_state = "marshal_jacket" + icon_open = "marshal_jacket_open" + icon_closed = "marshal_jacket" + valid_accessory_slots = list(ACCESSORY_SLOT_INSIGNIA) + body_parts_covered = UPPER_TORSO|ARMS + +/obj/item/clothing/suit/storage/toggle/hoodie + name = "hoodie" + desc = "A warm sweatshirt." + icon_state = "hoodie" + item_state = "hoodie" + icon_open = "hoodie_open" + icon_closed = "hoodie" + min_cold_protection_temperature = T0C - 20 + cold_protection = UPPER_TORSO|LOWER_TORSO|ARMS + +/obj/item/clothing/suit/storage/toggle/hoodie/cti + name = "\improper CTI hoodie" + desc = "A warm, black sweatshirt. It bears the letters ‘CTI’ on the back, a lettering to the prestigious university in Tau Ceti, Ceti Technical Institute. There is a blue supernova embroidered on the front, the emblem of CTI." + icon_state = "cti_hoodie" + icon_open = "cti_hoodie_open" + icon_closed = "cti_hoodie" + +/obj/item/clothing/suit/storage/toggle/hoodie/mu + name = "\improper Mariner University hoodie" + desc = "A warm, gray sweatshirt. It bears the letters ‘MU’ on the front, a lettering to the well-known public college, Mariner University." + icon_state = "mu_hoodie" + icon_open = "mu_hoodie_open" + icon_closed = "mu_hoodie" + +/obj/item/clothing/suit/storage/toggle/hoodie/nt + name = "NanoTrasen hoodie" + desc = "A warm, blue sweatshirt. It proudly bears the silver NanoTrasen insignia lettering on the back. The edges are trimmed with silver." + icon_state = "nt_hoodie" + icon_open = "nt_hoodie_open" + icon_closed = "nt_hoodie" + +/obj/item/clothing/suit/storage/toggle/hoodie/smw + name = "Trench Mountain Wind hoodie" + desc = "A warm, black sweatshirt. It has the logo for the popular softdrink Trench Mountain Wind on both the front and the back." + icon_state = "smw_hoodie" + icon_open = "smw_hoodie_open" + icon_closed = "smw_hoodie" + +/obj/item/clothing/suit/storage/toggle/hoodie/black + name = "black hoodie" + desc = "A warm, black sweatshirt." + color = COLOR_DARK_GRAY + +/obj/item/clothing/suit/storage/mbill + name = "shipping jacket" + desc = "A green jacket bearing the logo of Major Bill's Shipping." + icon_state = "mbill" + item_state = "mbill" + +/obj/item/clothing/suit/poncho/roles/security + name = "security poncho" + desc = "A simple, comfortable cloak without sleeves. This one is black and red, which are standard NanoTrasen Security colors." + icon_state = "secponcho" + item_state = "secponcho" + +/obj/item/clothing/suit/poncho/roles/medical + name = "medical poncho" + desc = "A simple, comfortable cloak without sleeves. This one is white with a blue tint, which are standard Medical colors." + icon_state = "medponcho" + item_state = "medponcho" + +/obj/item/clothing/suit/poncho/roles/engineering + name = "engineering poncho" + desc = "A simple, comfortable cloak without sleeves. This one is yellow and orange, which are standard Engineering colors." + icon_state = "engiponcho" + item_state = "engiponcho" + +/obj/item/clothing/suit/poncho/roles/science + name = "science poncho" + desc = "A simple, comfortable cloak without sleeves. This one is white with a few red stripes, which are standard NanoTrasen Science colors." + icon_state = "sciponcho" + item_state = "sciponcho" + +/obj/item/clothing/suit/poncho/roles/cargo + name = "cargo poncho" + desc = "A simple, comfortable cloak without sleeves. This one is tan and grey, which are standard Cargo colors." + icon_state = "cargoponcho" + item_state = "cargoponcho" + +/* + * Track Jackets + */ +/obj/item/clothing/suit/storage/toggle/track + name = "track jacket" + desc = "A track jacket, for the athletic." + icon_state = "trackjacket" + icon_open = "trackjacket_open" + icon_closed = "trackjacket" + +/obj/item/clothing/suit/storage/toggle/track/blue + name = "blue track jacket" + desc = "A blue track jacket, for the athletic." + icon_state = "trackjacketblue" + icon_open = "trackjacketblue_open" + icon_closed = "trackjacketblue" + +/obj/item/clothing/suit/storage/toggle/track/green + name = "green track jacket" + desc = "A green track jacket, for the athletic." + icon_state = "trackjacketgreen" + icon_open = "trackjacketgreen_open" + icon_closed = "trackjacketgreen" + +/obj/item/clothing/suit/storage/toggle/track/red + name = "red track jacket" + desc = "A red track jacket, for the athletic." + icon_state = "trackjacketred" + icon_open = "trackjacketred_open" + icon_closed = "trackjacketred" + +/obj/item/clothing/suit/storage/toggle/track/white + name = "white track jacket" + desc = "A white track jacket, for the athletic." + icon_state = "trackjacketwhite" + icon_open = "trackjacketwhite_open" + icon_closed = "trackjacketwhite" + +/obj/item/clothing/suit/storage/toggle/track/tcc + name = "TCC track jacket" + desc = "A Terran track jacket, for the truly cheeki breeki." + icon_state = "trackjackettcc" + icon_open = "trackjackettcc_open" + icon_closed = "trackjackettcc" + +/obj/item/clothing/suit/rubber + name = "human suit" + desc = "A Human suit made out of rubber." + icon_state = "mansuit" + +/obj/item/clothing/suit/rubber/tajaran + name = "tajara suit" + desc = "A Tajara suit made out of rubber." + icon_state = "catsuit" + +/obj/item/clothing/suit/rubber/skrell + name = "skrell suit" + desc = "A Skrell suit made out of rubber." + icon_state = "skrellsuit" + +/obj/item/clothing/suit/rubber/unathi + name = "unathi suit" + desc = "A Unathi suit made out of rubber." + icon_state = "lizsuit" + +/obj/item/clothing/suit/inquisitor + name = "inquisitor's coat" + desc = "This inquisitor attire was made for new recruits, and has excellent straightforward defense. But not nearly enough to allow an ordinary man to stand any real chance against the the wicked." + icon_state = "coat-church" + item_state = "coat-church" + body_parts_covered = UPPER_TORSO|ARMS|LOWER_TORSO|LEGS + allowed = list(/obj/item/weapon/nullrod, /obj/item/weapon/storage/bible) + armor = list(melee = 40, bullet = 25, laser = 5, energy = 0, bomb = 0, bio = 0, rad = 0) \ No newline at end of file diff --git a/code/modules/clothing/suits/storage.dm b/code/modules/clothing/suits/storage.dm new file mode 100644 index 00000000..dddcd513 --- /dev/null +++ b/code/modules/clothing/suits/storage.dm @@ -0,0 +1,61 @@ +/obj/item/clothing/suit/storage + var/obj/item/weapon/storage/internal/pockets/pockets + +/obj/item/clothing/suit/storage/New() + ..() + pockets = new/obj/item/weapon/storage/internal/pockets(src, slots = 2, slot_size = 2) //two slots, fit only pocket sized items + +/obj/item/clothing/suit/storage/Destroy() + QDEL_NULL(pockets) + . = ..() + +/obj/item/clothing/suit/storage/attack_hand(mob/user as mob) + if (pockets.handle_attack_hand(user)) + ..(user) + +/obj/item/clothing/suit/storage/MouseDrop(obj/over_object as obj) + if (pockets.handle_mousedrop(usr, over_object)) + ..(over_object) + +/obj/item/clothing/suit/storage/attackby(obj/item/W as obj, mob/user as mob) + ..() + if(!(W in accessories)) //Make sure that an accessory wasn't successfully attached to suit. + pockets.attackby(W, user) + +/obj/item/clothing/suit/storage/emp_act(severity) + pockets.emp_act(severity) + ..() + +//Jackets with buttons, used for labcoats, IA jackets, First Responder jackets, and brown jackets. +/obj/item/clothing/suit/storage/toggle + var/icon_open + var/icon_closed + verb/toggle() + set name = "Toggle Coat Buttons" + set category = "Object" + set src in usr + if(!usr.canmove || usr.stat || usr.restrained()) + return 0 + + if(icon_state == icon_open) //Will check whether icon state is currently set to the "open" or "closed" state and switch it around with a message to the user + icon_state = icon_closed + to_chat(usr, "You button up the coat.") + else if(icon_state == icon_closed) + icon_state = icon_open + to_chat(usr, "You unbutton the coat.") + else //in case some goofy admin switches icon states around without switching the icon_open or icon_closed + to_chat(usr, "You attempt to button-up the velcro on your [src], before promptly realising how silly you are.") + return + update_clothing_icon() //so our overlays update + + +/obj/item/clothing/suit/storage/vest/merc/New() + ..() + pockets = new/obj/item/weapon/storage/internal/pockets(src, slots = 4, slot_size = 2) + + +/obj/item/clothing/suit/storage/vest/tactical/New() + ..() + pockets = new/obj/item/weapon/storage/internal/pockets(src, slots = 4, slot_size = 2) + + diff --git a/code/modules/clothing/suits/toggles.dm b/code/modules/clothing/suits/toggles.dm new file mode 100644 index 00000000..958591cf --- /dev/null +++ b/code/modules/clothing/suits/toggles.dm @@ -0,0 +1,148 @@ +///Hoods for winter coats and chaplain hoodie etc + +/obj/item/clothing/suit/storage/hooded + var/obj/item/clothing/head/winterhood/hood + var/hoodtype = null //so the chaplain hoodie or other hoodies can override this + var/suittoggled = 0 + +/obj/item/clothing/suit/storage/hooded/New() + MakeHood() + ..() + +/obj/item/clothing/suit/storage/hooded/Destroy() + QDEL_NULL(hood) + return ..() + +/obj/item/clothing/suit/storage/hooded/proc/MakeHood() + if(!hood) + hood = new hoodtype(src) + +/obj/item/clothing/suit/storage/hooded/ui_action_click() + ToggleHood() + +/obj/item/clothing/suit/storage/hooded/equipped(mob/user, slot) + if(slot != slot_wear_suit) + RemoveHood() + ..() + +/obj/item/clothing/suit/storage/hooded/proc/RemoveHood() + if(!hood) + return + suittoggled = 0 + update_icon() + if(ishuman(hood.loc)) + var/mob/living/carbon/H = hood.loc + H.unEquip(hood, 1) + H.update_inv_wear_suit() + hood.forceMove(src) + +/obj/item/clothing/suit/storage/hooded/dropped() + RemoveHood() + +/obj/item/clothing/suit/storage/hooded/proc/ToggleHood() + if(!suittoggled) + if(ishuman(loc)) + var/mob/living/carbon/human/H = src.loc + if(H.wear_suit != src) + to_chat(H, "You must be wearing \the [src] to put up the hood!") + return + if(H.head) + to_chat(H, "You're already wearing something on your head!") + return + else + H.equip_to_slot_if_possible(hood,slot_head,0,0,1) + suittoggled = 1 + update_icon() + H.update_inv_wear_suit() + else + RemoveHood() + +/obj/item/clothing/suit/storage/hooded/update_icon() + if(suittoggled) + icon_state = "[initial(icon_state)]_t" + else + icon_state = "[initial(icon_state)]" + + +/obj/item/clothing/suit/storage/hooded/wintercoat + name = "winter coat" + desc = "A heavy jacket made from 'synthetic' animal furs." + icon_state = "coatwinter" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + cold_protection = UPPER_TORSO|LOWER_TORSO|ARMS + min_cold_protection_temperature = ARMOR_MIN_COLD_PROTECTION_TEMPERATURE + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + action_button_name = "Toggle Winter Hood" + hoodtype = /obj/item/clothing/head/winterhood + allowed = list (/obj/item/weapon/pen, /obj/item/weapon/paper, /obj/item/device/flashlight,/obj/item/weapon/storage/fancy/cigarettes, /obj/item/weapon/storage/box/matches, /obj/item/weapon/reagent_containers/food/drinks/flask) + siemens_coefficient = 0.6 + +/obj/item/clothing/head/winterhood + name = "winter hood" + desc = "A hood attached to a heavy winter jacket." + icon_state = "generic_hood" + body_parts_covered = HEAD + cold_protection = HEAD + flags_inv = HIDEEARS | BLOCKHAIR + min_cold_protection_temperature = ARMOR_MIN_COLD_PROTECTION_TEMPERATURE + +/obj/item/clothing/suit/storage/hooded/wintercoat/captain + name = "captain's winter coat" + icon_state = "coatcaptain" + armor = list(melee = 20, bullet = 15, laser = 20, energy = 10, bomb = 15, bio = 0, rad = 0) + +/obj/item/clothing/suit/storage/hooded/wintercoat/security + name = "security winter coat" + icon_state = "coatsecurity" + armor = list(melee = 25, bullet = 20, laser = 20, energy = 15, bomb = 20, bio = 0, rad = 0) + +/obj/item/clothing/suit/storage/hooded/wintercoat/medical + name = "medical winter coat" + icon_state = "coatmedical" + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 50, rad = 0) + +/obj/item/clothing/suit/storage/hooded/wintercoat/science + name = "science winter coat" + icon_state = "coatscience" + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 10, bio = 0, rad = 0) + +/obj/item/clothing/suit/storage/hooded/wintercoat/engineering + name = "engineering winter coat" + icon_state = "coatengineer" + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 20) + +/obj/item/clothing/suit/storage/hooded/wintercoat/engineering/atmos + name = "atmospherics winter coat" + icon_state = "coatatmos" + +/obj/item/clothing/suit/storage/hooded/wintercoat/hydro + name = "hydroponics winter coat" + icon_state = "coathydro" + +/obj/item/clothing/suit/storage/hooded/wintercoat/cargo + name = "cargo winter coat" + icon_state = "coatcargo" + +/obj/item/clothing/suit/storage/hooded/wintercoat/miner + name = "mining winter coat" + icon_state = "coatminer" + armor = list(melee = 10, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0) + +/obj/item/clothing/suit/storage/hooded/hoodie + name = "hoodie" + desc = "A warm sweatshirt." + icon_state = "hoodie" + item_state = "hoodie" + min_cold_protection_temperature = T0C - 20 + cold_protection = UPPER_TORSO|LOWER_TORSO|ARMS + action_button_name = "Toggle Hood" + hoodtype = /obj/item/clothing/head/hoodiehood + +/obj/item/clothing/head/hoodiehood + name = "hoodie hood" + desc = "A hood attached to a warm sweatshirt." + icon_state = "generic_hood" + body_parts_covered = HEAD + min_cold_protection_temperature = T0C - 20 + cold_protection = HEAD + flags_inv = HIDEEARS | BLOCKHAIR diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm new file mode 100644 index 00000000..145306ea --- /dev/null +++ b/code/modules/clothing/suits/utility.dm @@ -0,0 +1,128 @@ +/* + * Contains: + * Fire protection + * Bomb protection + * Radiation protection + */ + +/* + * Fire protection + */ + +/obj/item/clothing/suit/fire + name = "firesuit" + desc = "A suit that protects against fire and heat." + icon_state = "fire" + item_state_slots = list( + slot_l_hand_str = "fire_suit", + slot_r_hand_str = "fire_suit", + ) + w_class = ITEM_SIZE_HUGE//bulky item + gas_transfer_coefficient = 0.90 + permeability_coefficient = 0.50 + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/emergency,/obj/item/weapon/extinguisher) + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL + item_flags = ITEM_FLAG_STOPPRESSUREDAMAGE + heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE + cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS + +/* +/obj/item/clothing/suit/fire/New() + ..() + slowdown_per_slot[slot_wear_suit] = 1.0 +*/ + +/obj/item/clothing/suit/fire/firefighter + icon_state = "firesuit" + item_state_slots = list( + slot_l_hand_str = "firefighter", + slot_r_hand_str = "firefighter", + ) + + +/obj/item/clothing/suit/fire/heavy + name = "firesuit" + desc = "A suit that protects against extreme fire and heat." + //icon_state = "thermal" + item_state_slots = list( + slot_l_hand_str = "ro_suit", + slot_r_hand_str = "ro_suit", + ) + w_class = ITEM_SIZE_HUGE//bulky item + +/obj/item/clothing/suit/fire/heavy/New() + ..() + slowdown_per_slot[slot_wear_suit] = 1.5 + +/* + * Bomb protection + */ +/obj/item/clothing/head/bomb_hood + name = "bomb hood" + desc = "Use in case of bomb." + icon_state = "bombsuit" + armor = list(melee = 70, bullet = 15, laser = 30, energy = 50, bomb = 90, bio = 0, rad = 0) + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|BLOCKHAIR + body_parts_covered = HEAD|FACE|EYES + siemens_coefficient = 0 + + +/obj/item/clothing/suit/bomb_suit + name = "bomb suit" + desc = "A suit designed for safety when handling explosives." + icon_state = "bombsuit" + w_class = ITEM_SIZE_HUGE//bulky item + gas_transfer_coefficient = 0.01 + permeability_coefficient = 0.01 + armor = list(melee = 70, bullet = 15, laser = 30, energy = 50, bomb = 90, bio = 0, rad = 0) + flags_inv = HIDEJUMPSUIT|HIDETAIL + heat_protection = UPPER_TORSO|LOWER_TORSO + max_heat_protection_temperature = ARMOR_MAX_HEAT_PROTECTION_TEMPERATURE + siemens_coefficient = 0 + +/obj/item/clothing/suit/bomb_suit/New() + ..() + slowdown_per_slot[slot_wear_suit] = 2 + +/obj/item/clothing/head/bomb_hood/security + icon_state = "bombsuitsec" + body_parts_covered = HEAD + +/obj/item/clothing/suit/bomb_suit/security + icon_state = "bombsuitsec" + allowed = list(/obj/item/weapon/gun/energy,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs) + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + +/* + * Radiation protection + */ +/obj/item/clothing/head/radiation + name = "Radiation Hood" + icon_state = "rad" + desc = "A hood with radiation protective properties. Label: Made with lead, do not eat insulation." + flags_inv = BLOCKHAIR + body_parts_covered = HEAD|FACE|EYES + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 100) + + +/obj/item/clothing/suit/radiation + name = "Radiation suit" + desc = "A suit that protects against radiation. Label: Made with lead, do not eat insulation." + icon_state = "rad" + item_state_slots = list( + slot_l_hand_str = "rad_suit", + slot_r_hand_str = "rad_suit", + ) + w_class = ITEM_SIZE_HUGE//bulky item + gas_transfer_coefficient = 0.90 + permeability_coefficient = 0.50 + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS|HANDS|FEET + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/emergency,/obj/item/clothing/head/radiation,/obj/item/clothing/mask/gas) + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 100) + flags_inv = HIDEJUMPSUIT|HIDETAIL|HIDEGLOVES|HIDESHOES + +/obj/item/clothing/suit/radiation/New() + ..() + slowdown_per_slot[slot_shoes] = 1.5 diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm new file mode 100644 index 00000000..e711d180 --- /dev/null +++ b/code/modules/clothing/suits/wiz_robe.dm @@ -0,0 +1,139 @@ +/obj/item/clothing/head/wizard + name = "wizard hat" + desc = "Strange-looking hat-wear that most certainly belongs to a real magic user." + icon_state = "wizard" + item_state_slots = list( + slot_l_hand_str = "wizhat", + slot_r_hand_str = "wizhat", + ) + //Not given any special protective value since the magic robes are full-body protection --NEO + siemens_coefficient = 0.8 + body_parts_covered = 0 + wizard_garb = 1 + +/obj/item/clothing/head/wizard/red + name = "red wizard hat" + desc = "Strange-looking, red, hat-wear that most certainly belongs to a real magic user." + icon_state = "redwizard" + siemens_coefficient = 0.8 + +/obj/item/clothing/head/wizard/fake + name = "wizard hat" + desc = "It has WIZZARD written across it in sequins. Comes with a cool beard." + icon_state = "wizard-fake" + body_parts_covered = HEAD|FACE + +/obj/item/clothing/head/wizard/marisa + name = "Witch Hat" + desc = "Strange-looking hat-wear, makes you want to cast fireballs." + icon_state = "marisa" + siemens_coefficient = 0.8 + +/obj/item/clothing/head/wizard/magus + name = "Magus Helm" + desc = "A mysterious helmet that hums with an unearthly power." + icon_state = "magus" + item_state = "magus" + item_state_slots = list( + slot_l_hand_str = "helmet", + slot_r_hand_str = "helmet", + ) + siemens_coefficient = 0.8 + body_parts_covered = HEAD|FACE|EYES + +/obj/item/clothing/head/wizard/amp + name = "psychic amplifier" + desc = "A crown-of-thorns psychic amplifier. Kind of looks like a tiara having sex with an industrial robot." + icon_state = "amp" + item_state_slots = list( + slot_l_hand_str = "helmet", + slot_r_hand_str = "helmet", + ) + siemens_coefficient = 0.8 + +/obj/item/clothing/head/wizard/cap + name = "Gentlemans Cap" + desc = "A checkered gray flat cap woven together with the rarest of threads." + icon_state = "gentcap" + item_state_slots = list( + slot_l_hand_str = "det_hat", + slot_r_hand_str = "det_hat", + ) + siemens_coefficient = 0.8 + +/obj/item/clothing/suit/wizrobe + name = "wizard robe" + desc = "A magnificant, gem-lined robe that seems to radiate power." + icon_state = "wizard" + item_state = "wizrobe" + gas_transfer_coefficient = 0.01 // IT'S MAGICAL OKAY JEEZ +1 TO NOT DIE + permeability_coefficient = 0.01 + armor = list(melee = 30, bullet = 20, laser = 20,energy = 20, bomb = 20, bio = 20, rad = 20) + allowed = list(/obj/item/weapon/teleportation_scroll) + siemens_coefficient = 0.8 + wizard_garb = 1 + +/obj/item/clothing/suit/wizrobe/red + name = "red wizard robe" + desc = "A magnificant, red, gem-lined robe that seems to radiate power." + icon_state = "redwizard" + item_state = "redwizrobe" + + +/obj/item/clothing/suit/wizrobe/marisa + name = "Witch Robe" + desc = "Magic is all about the spell power, ZE!" + icon_state = "marisa" + item_state = "marisarobe" + +/obj/item/clothing/suit/wizrobe/magusblue + name = "Magus Robe" + desc = "A set of armoured robes that seem to radiate a dark power." + icon_state = "magusblue" + item_state = "magusblue" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS|HANDS|LEGS|FEET + +/obj/item/clothing/suit/wizrobe/magusred + name = "Magus Robe" + desc = "A set of armoured robes that seem to radiate a dark power." + icon_state = "magusred" + item_state = "magusred" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS|HANDS|LEGS|FEET + +/obj/item/clothing/suit/wizrobe/psypurple + name = "purple robes" + desc = "Heavy, royal purple robes threaded with psychic amplifiers and weird, bulbous lenses. Do not machine wash." + icon_state = "psyamp" + item_state = "psyamp" + +/obj/item/clothing/suit/wizrobe/gentlecoat + name = "Gentlemans Coat" + desc = "A heavy threaded tweed gray jacket. For a different sort of Gentleman." + icon_state = "gentlecoat" + item_state = "gentlecoat" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + +/obj/item/clothing/suit/wizrobe/fake + name = "wizard robe" + desc = "A rather dull, blue robe meant to mimick real wizard robes." + icon_state = "wizard-fake" + item_state = "wizrobe" + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 1.0 + +/obj/item/clothing/head/wizard/marisa/fake + name = "Witch Hat" + desc = "Strange-looking hat-wear, makes you want to cast fireballs." + icon_state = "marisa" + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 1.0 + +/obj/item/clothing/suit/wizrobe/marisa/fake + name = "Witch Robe" + desc = "Magic is all about the spell power, ZE!" + icon_state = "marisa" + item_state = "marisarobe" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS|LEGS + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 1.0 + diff --git a/code/modules/clothing/under/accessories/accessory.dm b/code/modules/clothing/under/accessories/accessory.dm new file mode 100644 index 00000000..4385e89d --- /dev/null +++ b/code/modules/clothing/under/accessories/accessory.dm @@ -0,0 +1,112 @@ +/obj/item/clothing/accessory + name = "tie" + desc = "A neosilk clip-on tie." + icon = 'icons/obj/clothing/ties.dmi' + icon_state = "tie" + item_state = "" //no inhands + slot_flags = SLOT_TIE + w_class = ITEM_SIZE_SMALL + var/slot = ACCESSORY_SLOT_DECOR + var/obj/item/clothing/has_suit = null //the suit the tie may be attached to + var/image/inv_overlay = null //overlay used when attached to clothing. + var/list/mob_overlay = list() + var/overlay_state = null + var/list/accessory_icons = list(slot_w_uniform_str = 'icons/mob/onmob/ties.dmi', slot_wear_suit_str = 'icons/mob/onmob/ties.dmi') + var/list/on_rolled = list() //used when jumpsuit sleevels are rolled ("rolled" entry) or it's rolled down ("down"). Set to "none" to hide in those states. + var/high_visibility //if it should appear on examine without detailed view + var/slowdown //used when an accessory is meant to slow the wearer down when attached to clothing + +/obj/item/clothing/accessory/Destroy() + on_removed() + return ..() + +/obj/item/clothing/accessory/proc/get_inv_overlay() + if(!inv_overlay) + var/tmp_icon_state = overlay_state? overlay_state : icon_state + if(icon_override && ("[tmp_icon_state]_tie" in icon_states(icon_override))) + inv_overlay = image(icon = icon_override, icon_state = "[tmp_icon_state]_tie", dir = SOUTH) + else if("[tmp_icon_state]_tie" in icon_states(default_onmob_icons[slot_tie_str])) + inv_overlay = image(icon = default_onmob_icons[slot_tie_str], icon_state = "[tmp_icon_state]_tie", dir = SOUTH) + else + inv_overlay = image(icon = default_onmob_icons[slot_tie_str], icon_state = tmp_icon_state, dir = SOUTH) + inv_overlay.color = color + return inv_overlay + +/obj/item/clothing/accessory/get_mob_overlay(mob/user_mob, slot) + if(!istype(loc,/obj/item/clothing/)) //don't need special handling if it's worn as normal item. + return ..() + var/bodytype = "Default" + if(ishuman(user_mob)) + var/mob/living/carbon/human/user_human = user_mob + if(user_human.species.get_bodytype(user_human) in sprite_sheets) + bodytype = user_human.species.get_bodytype(user_human) + + var/tmp_icon_state = overlay_state? overlay_state : icon_state + + if(istype(loc,/obj/item/clothing/under)) + var/obj/item/clothing/under/C = loc + if(on_rolled["down"] && C.rolled_down > 0) + tmp_icon_state = on_rolled["down"] + else if(on_rolled["rolled"] && C.rolled_sleeves > 0) + tmp_icon_state = on_rolled["rolled"] + + var/use_sprite_sheet = accessory_icons[slot] + if(sprite_sheets[bodytype]) + use_sprite_sheet = sprite_sheets[bodytype] + + if(icon_override && ("[tmp_icon_state]_mob" in icon_states(icon_override))) + return overlay_image(icon_override, "[tmp_icon_state]_mob", color, RESET_COLOR) + else + return overlay_image(use_sprite_sheet, tmp_icon_state, color, RESET_COLOR) + +//when user attached an accessory to S +/obj/item/clothing/accessory/proc/on_attached(var/obj/item/clothing/S, var/mob/user) + if(!istype(S)) + return + has_suit = S + forceMove(has_suit) + has_suit.overlays += get_inv_overlay() + + if(user) + to_chat(user, "You attach \the [src] to \the [has_suit].") + src.add_fingerprint(user) + +/obj/item/clothing/accessory/proc/on_removed(var/mob/user) + if(!has_suit) + return + has_suit.overlays -= get_inv_overlay() + has_suit = null + if(user) + usr.put_in_hands(src) + src.add_fingerprint(user) + else + src.forceMove(get_turf(src)) + +//default attackby behaviour +/obj/item/clothing/accessory/attackby(obj/item/I, mob/user) + ..() + +//default attack_hand behaviour +/obj/item/clothing/accessory/attack_hand(mob/user as mob) + if(has_suit) + return //we aren't an object on the ground so don't call parent + ..() + +//Necklaces +/obj/item/clothing/accessory/necklace + name = "necklace" + desc = "A simple necklace." + icon_state = "necklace" + slot_flags = SLOT_MASK | SLOT_TIE + +//Misc +/obj/item/clothing/accessory/kneepads + name = "kneepads" + desc = "A pair of synthetic kneepads. Doesn't provide protection from more than arthritis." + icon_state = "kneepads" + +//Scarves +/obj/item/clothing/accessory/scarf + name = "scarf" + desc = "A stylish scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks." + icon_state = "whitescarf" \ No newline at end of file diff --git a/code/modules/clothing/under/accessories/armband.dm b/code/modules/clothing/under/accessories/armband.dm new file mode 100644 index 00000000..f31d2401 --- /dev/null +++ b/code/modules/clothing/under/accessories/armband.dm @@ -0,0 +1,46 @@ +/obj/item/clothing/accessory/armband + name = "red armband" + desc = "A fancy red armband!" + icon_state = "red" + slot = ACCESSORY_SLOT_ARMBAND + species_restricted = null + +/obj/item/clothing/accessory/armband/cargo + name = "cargo armband" + desc = "An armband, worn by the crew to display which department they're assigned to. This one is brown." + icon_state = "cargo" + +/obj/item/clothing/accessory/armband/engine + name = "engineering armband" + desc = "An armband, worn by the crew to display which department they're assigned to. This one is orange with a reflective strip!" + icon_state = "engie" + +/obj/item/clothing/accessory/armband/hydro + name = "hydroponics armband" + desc = "An armband, worn by the crew to display which department they're assigned to. This one is green and blue." + icon_state = "hydro" + +/obj/item/clothing/accessory/armband/med + name = "medical armband" + desc = "An armband, worn by the crew to display which department they're assigned to. This one is white." + icon_state = "med" + +/obj/item/clothing/accessory/armband/medgreen + name = "EMT armband" + desc = "An armband, worn by the crew to display which department they're assigned to. This one is white and green." + icon_state = "medgreen" + +/obj/item/clothing/accessory/armband/medblue + name = "medical corps armband" + desc = "An armband, worn by the crew to display which department they're assigned to. This one is white and blue." + icon_state = "medblueband" + +/obj/item/clothing/accessory/armband/whitered + name = "\improper NanoTrasen armband" + desc = "An armband, worn by the crew to display which department they're assigned to. This one is white and red." + icon_state = "whitered" + +/obj/item/clothing/accessory/armband/bluegold + name = "peacekeeper armband" + desc = "An armband, worn by the crew to display which department they're assigned to. This one is blue and gold." + icon_state = "solblue" \ No newline at end of file diff --git a/code/modules/clothing/under/accessories/armor.dm b/code/modules/clothing/under/accessories/armor.dm new file mode 100644 index 00000000..7bd6e3c9 --- /dev/null +++ b/code/modules/clothing/under/accessories/armor.dm @@ -0,0 +1,313 @@ +//Pouches +/obj/item/clothing/accessory/storage/pouches + name = "storage pouches" + desc = "A collection of black pouches that can be attached to a plate carrier. Carries up to two items." + icon_override = 'icons/mob/onmob/modular_armor.dmi' + icon = 'icons/obj/clothing/modular_armor.dmi' + accessory_icons = list(slot_tie_str = 'icons/mob/onmob/modular_armor.dmi', slot_wear_suit_str = 'icons/mob/onmob/modular_armor.dmi') + icon_state = "pouches" + gender = PLURAL + slot = ACCESSORY_SLOT_ARMOR_S + slots = 2 + +/obj/item/clothing/accessory/storage/pouches/blue + desc = "A collection of blue pouches that can be attached to a plate carrier. Carries up to two items." + icon_state = "pouches_blue" + +/obj/item/clothing/accessory/storage/pouches/navy + desc = "A collection of navy blue pouches that can be attached to a plate carrier. Carries up to two items." + icon_state = "pouches_navy" + +/obj/item/clothing/accessory/storage/pouches/green + desc = "A collection of green pouches that can be attached to a plate carrier. Carries up to two items." + icon_state = "pouches_green" + +/obj/item/clothing/accessory/storage/pouches/tan + desc = "A collection of tan pouches that can be attached to a plate carrier. Carries up to two items." + icon_state = "pouches_tan" + +/obj/item/clothing/accessory/storage/pouches/large + name = "large storage pouches" + desc = "A collection of black pouches that can be attached to a plate carrier. Carries up to four items." + icon_state = "lpouches" + slots = 4 + slowdown = 1 + +/obj/item/clothing/accessory/storage/pouches/large/blue + desc = "A collection of blue pouches that can be attached to a plate carrier. Carries up to four items." + icon_state = "lpouches_blue" + +/obj/item/clothing/accessory/storage/pouches/large/navy + desc = "A collection of navy blue pouches that can be attached to a plate carrier. Carries up to four items." + icon_state = "lpouches_navy" + +/obj/item/clothing/accessory/storage/pouches/large/green + desc = "A collection of green pouches that can be attached to a plate carrier. Carries up to four items." + icon_state = "lpouches_green" + +/obj/item/clothing/accessory/storage/pouches/large/tan + desc = "A collection of tan pouches that can be attached to a plate carrier. Carries up to four items." + icon_state = "lpouches_tan" + +//Armor plates +/obj/item/clothing/accessory/armorplate + name = "light armor plate" + desc = "A basic armor plate made of steel-reinforced synthetic fibers. Attaches to a plate carrier." + icon = 'icons/obj/clothing/modular_armor.dmi' + icon_state = "armor_light" + body_parts_covered = UPPER_TORSO|LOWER_TORSO + armor = list(melee = 25, bullet = 30, laser = 30, energy = 10, bomb = 25, bio = 0, rad = 0) + slot = ACCESSORY_SLOT_ARMOR_C + +/obj/item/clothing/accessory/armorplate/get_fibers() + return null //plates do not shed + +/obj/item/clothing/accessory/armorplate/medium + name = "medium armor plate" + desc = "A plasteel-reinforced synthetic armor plate, providing good protection. Attaches to a plate carrier." + icon_state = "armor_medium" + armor = list(melee = 40, bullet = 40, laser = 40, energy = 25, bomb = 30, bio = 0, rad = 0) + +/obj/item/clothing/accessory/armorplate/tactical + name = "tactical armor plate" + desc = "A medium armor plate with additional ablative coating. Attaches to a plate carrier." + icon_state = "armor_tactical" + armor = list(melee = 40, bullet = 40, laser = 60, energy = 35, bomb = 30, bio = 0, rad = 0) + +/obj/item/clothing/accessory/armorplate/merc + name = "heavy armor plate" + desc = "A ceramics-reinforced synthetic armor plate, providing state of of the art protection. Attaches to a plate carrier." + icon_state = "armor_heavy" + armor = list(melee = 60, bullet = 60, laser = 60, energy = 40, bomb = 40, bio = 0, rad = 0) + slowdown = 1 + +//Arm guards +/obj/item/clothing/accessory/armguards + name = "arm guards" + desc = "A pair of black arm pads reinforced with armor plating. Attaches to a plate carrier." + icon_override = 'icons/mob/onmob/modular_armor.dmi' + icon = 'icons/obj/clothing/modular_armor.dmi' + accessory_icons = list(slot_tie_str = 'icons/mob/onmob/modular_armor.dmi', slot_wear_suit_str = 'icons/mob/onmob/modular_armor.dmi') + icon_state = "armguards" + gender = PLURAL + body_parts_covered = ARMS + armor = list(melee = 40, bullet = 40, laser = 40, energy = 25, bomb = 30, bio = 0, rad = 0) + slot = ACCESSORY_SLOT_ARMOR_A + +/obj/item/clothing/accessory/armguards/blue + desc = "A pair of blue arm pads reinforced with armor plating. Attaches to a plate carrier." + icon_state = "armguards_blue" + +/obj/item/clothing/accessory/armguards/navy + desc = "A pair of navy blue arm pads reinforced with armor plating. Attaches to a plate carrier." + icon_state = "armguards_navy" + +/obj/item/clothing/accessory/armguards/green + desc = "A pair of green arm pads reinforced with armor plating. Attaches to a plate carrier." + icon_state = "armguards_green" + +/obj/item/clothing/accessory/armguards/tan + desc = "A pair of tan arm pads reinforced with armor plating. Attaches to a plate carrier." + icon_state = "armguards_tan" + +/obj/item/clothing/accessory/armguards/merc + name = "heavy arm guards" + desc = "A pair of red-trimmed black arm pads reinforced with heavy armor plating. Attaches to a plate carrier." + icon_state = "armguards_merc" + armor = list(melee = 60, bullet = 60, laser = 60, energy = 40, bomb = 40, bio = 0, rad = 0) + +/obj/item/clothing/accessory/armguards/riot + name = "riot arm guards" + desc = "A pair of armored arm pads with heavy padding to protect against melee attacks." + icon_state = "armguards_riot" + armor = list(melee = 75, bullet = 33, laser = 50, energy = 10, bomb = 25, bio = 0, rad = 0) + siemens_coefficient = 0.5 + +/obj/item/clothing/accessory/armguards/ballistic + name = "ballistic arm guards" + desc = "A pair of armored arm pads with heavy plates to protect against ballistic projectiles." + icon_state = "armguards_ballistic" + armor = list(melee = 42, bullet = 75, laser = 42, energy = 10, bomb = 25, bio = 0, rad = 0) + siemens_coefficient = 0.7 + +/obj/item/clothing/accessory/armguards/ablative + name = "ablative arm guards" + desc = "A pair of armored arm pads with advanced shielding to protect against energy weapons." + icon_state = "armguards_ablative" + armor = list(melee = 35, bullet = 35, laser = 75, energy = 50, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 0 + +//Leg guards +/obj/item/clothing/accessory/legguards + name = "leg guards" + desc = "A pair of armored leg pads in black. Attaches to a plate carrier." + icon_override = 'icons/mob/onmob/modular_armor.dmi' + icon = 'icons/obj/clothing/modular_armor.dmi' + accessory_icons = list(slot_tie_str = 'icons/mob/onmob/modular_armor.dmi', slot_wear_suit_str = 'icons/mob/onmob/modular_armor.dmi') + icon_state = "legguards" + gender = PLURAL + body_parts_covered = LEGS + armor = list(melee = 40, bullet = 40, laser = 40, energy = 25, bomb = 30, bio = 0, rad = 0) + slot = ACCESSORY_SLOT_ARMOR_L + +/obj/item/clothing/accessory/legguards/blue + desc = "A pair of armored leg pads in blue. Attaches to a plate carrier." + icon_state = "legguards_blue" + +/obj/item/clothing/accessory/legguards/navy + desc = "A pair of armored leg pads in navy blue. Attaches to a plate carrier." + icon_state = "legguards_navy" + +/obj/item/clothing/accessory/legguards/green + desc = "A pair of armored leg pads in green. Attaches to a plate carrier." + icon_state = "legguards_green" + +/obj/item/clothing/accessory/legguards/tan + desc = "A pair of armored leg pads in tan. Attaches to a plate carrier." + icon_state = "legguards_tan" + +/obj/item/clothing/accessory/legguards/merc + name = "heavy leg guards" + desc = "A pair of heavily armored leg pads in red-trimmed black. Attaches to a plate carrier." + icon_state = "legguards_merc" + armor = list(melee = 60, bullet = 60, laser = 60, energy = 40, bomb = 40, bio = 0, rad = 0) + +/obj/item/clothing/accessory/legguards/riot + name = "riot leg guards" + desc = "A pair of armored leg pads with heavy padding to protect against melee attacks. Looks like they might impair movement." + icon_state = "legguards_riot" + armor = list(melee = 75, bullet = 33, laser = 50, energy = 10, bomb = 25, bio = 0, rad = 0) + siemens_coefficient = 0.5 + slowdown = 1 + +/obj/item/clothing/accessory/legguards/ballistic + name = "ballistic leg guards" + desc = "A pair of armored leg pads with heavy plates to protect against ballistic projectiles. Looks like they might impair movement." + icon_state = "legguards_ballistic" + armor = list(melee = 42, bullet = 75, laser = 42, energy = 10, bomb = 25, bio = 0, rad = 0) + siemens_coefficient = 0.7 + slowdown = 1 + +/obj/item/clothing/accessory/legguards/ablative + name = "ablative leg guards" + desc = "A pair of armored leg pads with advanced shielding to protect against energy weapons. Looks like they might impair movement." + icon_state = "legguards_ablative" + armor = list(melee = 35, bullet = 35, laser = 75, energy = 50, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 0 + slowdown = 1 + + +//Decorative attachments +/obj/item/clothing/accessory/armor/tag + name = "master armor tag" + desc = "A collection of various tags for placing on the front of a plate carrier." + icon_override = 'icons/mob/onmob/modular_armor.dmi' + icon = 'icons/obj/clothing/modular_armor.dmi' + accessory_icons = list(slot_tie_str = 'icons/mob/onmob/modular_armor.dmi', slot_wear_suit_str = 'icons/mob/onmob/modular_armor.dmi') + icon_state = "null" + slot = ACCESSORY_SLOT_ARMOR_M + +/obj/item/clothing/accessory/armor/tag/nt + name = "\improper CORPORATE SECURITY tag" + desc = "An armor tag with the words CORPORATE SECURITY printed in red lettering on it." + icon_state = "nanotag" + +/obj/item/clothing/accessory/armor/tag/pcrc + name = "\improper PCRC tag" + desc = "An armor tag with the words PROXIMA CENTAURI RISK CONTROL printed in cyan lettering on it." + icon_state = "pcrctag" + +/obj/item/clothing/accessory/armor/tag/saare + name = "\improper SAARE tag" + desc = "An armor tag with the acronym SAARE printed in olive-green lettering on it." + icon_state = "saaretag" + +/obj/item/clothing/accessory/armor/tag/press + name = "\improper PRESS tag" + desc = "A tag with the word PRESS printed in white lettering on it." + icon_state = "presstag" + slot_flags = SLOT_BELT + +/obj/item/clothing/accessory/armor/tag/opos + name = "\improper O+ blood patch" + desc = "An embroidered patch indicating the wearer's blood type as O POSITIVE." + icon_state = "opostag" + +/obj/item/clothing/accessory/armor/tag/oneg + name = "\improper O- blood patch" + desc = "An embroidered patch indicating the wearer's blood type as O NEGATIVE." + icon_state = "onegtag" + +/obj/item/clothing/accessory/armor/tag/apos + name = "\improper A+ blood patch" + desc = "An embroidered patch indicating the wearer's blood type as A POSITIVE." + icon_state = "apostag" + +/obj/item/clothing/accessory/armor/tag/aneg + name = "\improper A- blood patch" + desc = "An embroidered patch indicating the wearer's blood type as A NEGATIVE." + icon_state = "anegtag" + +/obj/item/clothing/accessory/armor/tag/bpos + name = "\improper B+ blood patch" + desc = "An embroidered patch indicating the wearer's blood type as B POSITIVE." + icon_state = "bpostag" + +/obj/item/clothing/accessory/armor/tag/bneg + name = "\improper B- blood patch" + desc = "An embroidered patch indicating the wearer's blood type as B NEGATIVE." + icon_state = "bnegtag" + +/obj/item/clothing/accessory/armor/tag/abpos + name = "\improper AB+ blood patch" + desc = "An embroidered patch indicating the wearer's blood type as AB POSITIVE." + icon_state = "abpostag" + +/obj/item/clothing/accessory/armor/tag/abneg + name = "\improper AB- blood patch" + desc = "An embroidered patch indicating the wearer's blood type as AB NEGATIVE." + icon_state = "abnegtag" + +/obj/item/clothing/accessory/armor/helmcover + name = "helmet cover" + desc = "A fabric cover for armored helmets." + icon_override = 'icons/mob/onmob/modular_armor.dmi' + icon = 'icons/obj/clothing/modular_armor.dmi' + accessory_icons = list(slot_tie_str = 'icons/mob/onmob/modular_armor.dmi', slot_head_str = 'icons/mob/onmob/modular_armor.dmi') + icon_state = "null" + slot = ACCESSORY_SLOT_HELM_C + +/obj/item/clothing/accessory/armor/helmcover/blue + name = "blue helmet cover" + desc = "A fabric cover for armored helmets in a bright blue color." + icon_state = "helmcover_blue" + +/obj/item/clothing/accessory/armor/helmcover/navy + name = "navy blue helmet cover" + desc = "A fabric cover for armored helmets. This one is colored navy blue." + icon_state = "helmcover_navy" + +/obj/item/clothing/accessory/armor/helmcover/green + name = "green helmet cover" + desc = "A fabric cover for armored helmets. This one has a woodland camouflage pattern." + icon_state = "helmcover_green" + +/obj/item/clothing/accessory/armor/helmcover/tan + name = "tan helmet cover" + desc = "A fabric cover for armored helmets. This one has a desert camouflage pattern." + icon_state = "helmcover_tan" + +/obj/item/clothing/accessory/armor/helmcover/nt + name = "\improper NanoTrasen helmet cover" + desc = "A fabric cover for armored helmets. This one has NanoTrasen's colors." + icon_state = "helmcover_nt" + +/obj/item/clothing/accessory/armor/helmcover/pcrc + name = "\improper PCRC helmet cover" + desc = "A fabric cover for armored helmets. This one is colored navy blue and has a tag in the back with the words PROXIMA CENTAURI RISK CONTROL printed in cyan lettering on it." + icon_state = "helmcover_pcrc" + +/obj/item/clothing/accessory/armor/helmcover/saare + name = "\improper SAARE helmet cover" + desc = "A fabric cover for armored helmets. This one has SAARE's colors." + icon_state = "helmcover_saare" diff --git a/code/modules/clothing/under/accessories/badges.dm b/code/modules/clothing/under/accessories/badges.dm new file mode 100644 index 00000000..414bcaf8 --- /dev/null +++ b/code/modules/clothing/under/accessories/badges.dm @@ -0,0 +1,135 @@ +/* + Badges are worn on the belt or neck, and can be used to show that the holder is an authorized + Security agent - the user details can be imprinted on holobadges with a Security-access ID card, + or they can be emagged to accept any ID for use in disguises. +*/ + +/obj/item/clothing/accessory/badge + name = "private investigator's badge" + desc = "A leather-backed badge, with gold trimmings." + icon_state = "detectivebadge" + slot_flags = SLOT_BELT + slot = ACCESSORY_SLOT_INSIGNIA + var/badge_string = "Private Investigator" + var/stored_name + +/obj/item/clothing/accessory/badge/proc/set_name(var/new_name) + stored_name = new_name + name = "[initial(name)] ([stored_name])" + +/obj/item/clothing/accessory/badge/attack_self(mob/user as mob) + + if(!stored_name) + to_chat(user, "You inspect your [src.name]. Everything seems to be in order and you give it a quick cleaning with your hand.") + set_name(user.real_name) + return + + if(isliving(user)) + if(stored_name) + user.visible_message("[user] displays their [src.name].\nIt reads: [stored_name], [badge_string].","You display your [src.name].\nIt reads: [stored_name], [badge_string].") + else + user.visible_message("[user] displays their [src.name].\nIt reads: [badge_string].","You display your [src.name]. It reads: [badge_string].") + +/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 \the [src] into their face insistently.","You invade [M]'s personal space, thrusting \the [src] into their face insistently.") + +/* + *Holobadges + */ +/obj/item/clothing/accessory/badge/holo + name = "holobadge" + desc = "This glowing blue badge marks the holder as a member of corporate security." + icon_state = "holobadge" + item_state = "holobadge" + badge_string = "NanoTrasen Security" + var/emagged //Emagging removes Sec check. + +/obj/item/clothing/accessory/badge/holo/cord + icon_state = "holobadge-cord" + slot_flags = SLOT_MASK + +/obj/item/clothing/accessory/badge/holo/attack_self(mob/user as mob) + if(!stored_name) + to_chat(user, "Waving around a holobadge before swiping an ID would be pretty pointless.") + return + return ..() + +/obj/item/clothing/accessory/badge/holo/emag_act(var/remaining_charges, var/mob/user) + if (emagged) + to_chat(user, "\The [src] is already cracked.") + return + else + emagged = 1 + to_chat(user, "You crack the holobadge security checks.") + return 1 + +/obj/item/clothing/accessory/badge/holo/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(istype(O, /obj/item/weapon/card/id) || istype(O, /obj/item/device/pda)) + + var/obj/item/weapon/card/id/id_card = null + + if(istype(O, /obj/item/weapon/card/id)) + id_card = O + else + var/obj/item/device/pda/pda = O + id_card = pda.id + + if(access_security in id_card.access || emagged) + to_chat(user, "You imprint your ID details onto the badge.") + set_name(user.real_name) + else + to_chat(user, "[src] rejects your insufficient access rights.") + return + ..() + +/obj/item/weapon/storage/box/holobadge + name = "holobadge box" + desc = "A box containing holobadges." + New() + new /obj/item/clothing/accessory/badge/holo(src) + new /obj/item/clothing/accessory/badge/holo(src) + new /obj/item/clothing/accessory/badge/holo(src) + new /obj/item/clothing/accessory/badge/holo(src) + new /obj/item/clothing/accessory/badge/holo/cord(src) + new /obj/item/clothing/accessory/badge/holo/cord(src) + ..() + return + +/obj/item/clothing/accessory/badge/old + name = "faded badge" + desc = "A faded badge, backed with leather. Looks crummy." + icon_state = "badge_round" + badge_string = "Unknown" + +/obj/item/clothing/accessory/badge/defenseintel + name = "investigator's badge" + desc = "A leather-backed silver badge bearing the crest of the Defense Intelligence Agency." + icon_state = "diabadge" + badge_string = "Defense Intelligence Agency" + +/obj/item/clothing/accessory/badge/interstellarintel + name = "agent's badge" + desc = "A synthleather holographic badge bearing the crest of the Office of Interstellar Intelligence." + icon_state = "intelbadge" + badge_string = "Office of Interstellar Intelligence" + +/obj/item/clothing/accessory/badge/nanotrasen + name = "\improper NanoTrasen badge" + desc = "A leather-backed plastic badge with a variety of information printed on it. Belongs to a NanoTrasen corporate executive." + icon_state = "ntbadge" + badge_string = "NanoTrasen" + +/obj/item/clothing/accessory/badge/marshal + name = "colonial marshal's badge" + desc = "A leather-backed gold badge displaying the crest of the Colonial Marshals." + icon_state = "marshalbadge" + slot_flags = SLOT_BELT | SLOT_TIE + slot = ACCESSORY_SLOT_INSIGNIA + badge_string = "Colonial Marshal Bureau" + +/obj/item/clothing/accessory/badge/press + name = "press badge" + desc = "A leather-backed plastic badge displaying that the owner is certified press personnel." + icon_state = "pressbadge" + badge_string = "Journalist" diff --git a/code/modules/clothing/under/accessories/clothing.dm b/code/modules/clothing/under/accessories/clothing.dm new file mode 100644 index 00000000..adcc90f0 --- /dev/null +++ b/code/modules/clothing/under/accessories/clothing.dm @@ -0,0 +1,269 @@ +/obj/item/clothing/accessory/wcoat + name = "waistcoat" + desc = "For some classy, murderous fun." + icon_state = "vest" + item_state = "wcoat" + +/obj/item/clothing/accessory/suspenders + name = "suspenders" + desc = "They suspend the illusion of the mime's play." + icon_state = "suspenders" + +/obj/item/clothing/accessory/nt_tunic + name = "\improper NanoTrasen tunic" + desc = "A fashionable tunic that NanoTrasen gives to its lab workers." + icon_state = "nttunic" + +/obj/item/clothing/accessory/nt_tunic/exec + name = "\improper NanoTrasen executive tunic" + icon_state = "nttunicblack" + +/obj/item/clothing/accessory/dashiki + name = "black dashiki" + desc = "An ornately embroidered pullover garmant sporting a v-shaped collar. This one is green and black." + icon_state = "dashiki" + +/obj/item/clothing/accessory/dashiki/red + name = "red dashiki" + desc = "An ornately embroidered pullover garmant sporting a v-shaped collar. This one is red." + icon_state = "dashikired" + +/obj/item/clothing/accessory/dashiki/blue + name = "blue dashiki" + desc = "An ornately embroidered pullover garmant sporting a v-shaped collar. This one is blue." + icon_state = "dashikiblue" + +/obj/item/clothing/accessory/thawb + name = "thawb" + desc = "A white, ankle-length robe designed to be cool in hot climates." + icon_state = "thawb" + +/obj/item/clothing/accessory/sherwani + name = "sherwani" + desc = "A long, coat-like frock with fancy embroidery on the cuffs and collar." + icon_state = "sherwani" + +/obj/item/clothing/accessory/qipao + name = "qipao" + desc = "A tight-fitting blouse with intricate designs of flowers embroidered on it." + icon_state = "qipao" + +/obj/item/clothing/accessory/sweater + name = "turtleneck sweater" + desc = "A stylish sweater to keep you warm on those cold days." + icon_state = "sweater" + +/obj/item/clothing/accessory/ubac + name = "black ubac" + desc = "A flexible, close-fitting shirt with camouflage sleeves designed to be worn under combat equipment. This one is black." + icon_state = "ubacblack" + +/obj/item/clothing/accessory/ubac/blue + name = "blue ubac" + desc = "A flexible, close-fitting shirt with camouflage sleeves designed to be worn under combat equipment. This one is blue." + icon_state = "ubacblue" + +/obj/item/clothing/accessory/ubac/tan + name = "tan ubac" + desc = "A flexible, close-fitting shirt with camouflage sleeves designed to be worn under combat equipment. This one is tan." + icon_state = "ubactan" + +/obj/item/clothing/accessory/ubac/green + name = "green ubac" + desc = "A flexible, close-fitting shirt with camouflage sleeves designed to be worn under combat equipment. This one is green." + icon_state = "ubacgreen" + +/obj/item/clothing/accessory/toggleable + var/icon_closed +/obj/item/clothing/accessory/toggleable/New() + if(!icon_closed) + icon_closed = icon_state + ..() + +/obj/item/clothing/accessory/toggleable/on_attached(obj/item/clothing/under/S, mob/user as mob) + ..() + has_suit.verbs += /obj/item/clothing/accessory/toggleable/verb/toggle + +/obj/item/clothing/accessory/toggleable/on_removed(mob/user as mob) + if(has_suit) + has_suit.verbs -= /obj/item/clothing/accessory/toggleable/verb/toggle + ..() + +/obj/item/clothing/accessory/toggleable/verb/toggle() + set name = "Toggle Buttons" + set category = "Object" + set src in usr + + if(usr.incapacitated()) + return 0 + + var/obj/item/clothing/accessory/toggleable/H = null + if (istype(src, /obj/item/clothing/accessory/toggleable)) + H = src + else + H = locate() in src + + if(H) + H.do_toggle(usr) + update_clothing_icon() //so our overlays update + +/obj/item/clothing/accessory/toggleable/proc/do_toggle(user) + if(icon_state == icon_closed) + icon_state = "[icon_closed]_open" + to_chat(usr, "You unbutton [src].") + else + icon_state = icon_closed + to_chat(usr, "You button up [src].") + + update_clothing_icon() //so our overlays update + +/obj/item/clothing/accessory/toggleable/vest + name = "black vest" + desc = "Slick black suit vest." + icon_state = "det_vest" + +/obj/item/clothing/accessory/toggleable/tan_jacket + name = "tan suit jacket" + desc = "Cozy suit jacket." + icon_state = "tan_jacket" + +/obj/item/clothing/accessory/toggleable/tan_jacket/New() + ..() + do_toggle() + +/obj/item/clothing/accessory/toggleable/charcoal_jacket + name = "charcoal suit jacket" + desc = "Strict suit jacket." + icon_state = "charcoal_jacket" + +/obj/item/clothing/accessory/toggleable/navy_jacket + name = "navy suit jacket" + desc = "Official suit jacket." + icon_state = "navy_jacket" + +/obj/item/clothing/accessory/toggleable/burgundy_jacket + name = "burgundy suit jacket" + desc = "Expensive suit jacket." + icon_state = "burgundy_jacket" + +/obj/item/clothing/accessory/toggleable/checkered_jacket + name = "checkered suit jacket" + desc = "Lucky suit jacket." + icon_state = "checkered_jacket" + +/obj/item/clothing/accessory/toggleable/nanotrasen_jacket + name = "\improper NanoTrasen suit jacket" + desc = "A jacket that NanoTrasen has its executives wear." + icon_state = "nt_jacket" + +/obj/item/clothing/accessory/toggleable/hawaii + name = "flower-pattern shirt" + desc = "You probably need some welder googles to look at this." + icon_state = "hawaii" + sprite_sheets = list("Monkey" = 'icons/mob/species/monkey/ties.dmi') + +/obj/item/clothing/accessory/toggleable/hawaii/red + icon_state = "hawaii2" + +/obj/item/clothing/accessory/toggleable/hawaii/random + name = "flower-pattern shirt" + +/obj/item/clothing/accessory/toggleable/zhongshan + name = "zhongshan suit jacket" + desc = "A stylish Chinese tunic suit jacket." + icon_state = "zhongshan" + +/obj/item/clothing/accessory/toggleable/hawaii/random/New() + ..() + if(prob(50)) + icon_state = "hawaii2" + icon_closed = "hawaii2" + color = color_rotation(rand(-11,12)*15) + +/obj/item/clothing/accessory/toggleable/flannel + name = "flannel shirt" + desc = "A comfy, plaid flannel shirt." + icon_state = "flannel" + var/rolled = 0 + var/tucked = 0 + var/buttoned = 0 + +/obj/item/clothing/accessory/toggleable/flannel/on_attached(obj/item/clothing/under/S, mob/user as mob) + ..() + has_suit.verbs += /obj/item/clothing/accessory/toggleable/flannel/verb/tuck + has_suit.verbs += /obj/item/clothing/accessory/toggleable/flannel/verb/roll_up_sleeves + +/obj/item/clothing/accessory/toggleable/flannel/on_removed(mob/user as mob) + if(has_suit) + has_suit.verbs -= /obj/item/clothing/accessory/toggleable/flannel/verb/tuck + has_suit.verbs -= /obj/item/clothing/accessory/toggleable/flannel/verb/roll_up_sleeves + ..() + +/obj/item/clothing/accessory/toggleable/flannel/do_toggle(user) + if(buttoned == 0) + buttoned = 1 + to_chat(usr, "You button your [src].") + else + buttoned = 0 + to_chat(usr, "You unbutton [src].") + update_icon() + +/obj/item/clothing/accessory/toggleable/flannel/verb/roll_up_sleeves() + set name = "Roll Flannel Sleeves" + set category = "Object" + set src in usr + + if(usr.incapacitated()) + return 0 + + var/obj/item/clothing/accessory/toggleable/flannel/H = null + if (istype(src, /obj/item/clothing/accessory/toggleable)) + H = src + else + H = locate() in src + + if(H.rolled == 0) + H.rolled = 1 + to_chat(usr, "You roll up the sleeves of your [H].") + else + H.rolled = 0 + to_chat(usr, "You roll down the sleeves of your [H].") + H.update_icon() + update_clothing_icon() + +/obj/item/clothing/accessory/toggleable/flannel/verb/tuck() + set name = "Toggle Shirt Tucking" + set category = "Object" + set src in usr + if(!istype(usr, /mob/living)||usr.stat) + return + + var/obj/item/clothing/accessory/toggleable/flannel/H = null + if (istype(src, /obj/item/clothing/accessory/toggleable)) + H = src + else + H = locate() in src + + if(H.tucked == 0) + H.tucked = 1 + to_chat(usr, "You tuck in your [H].") + else + H.tucked = 0 + to_chat(usr, "You untuck your [H].") + H.update_icon() + update_clothing_icon() + +/obj/item/clothing/accessory/toggleable/flannel/update_icon() + icon_state = initial(icon_state) + if(rolled) + icon_state += "r" + if(tucked) + icon_state += "t" + if(buttoned) + icon_state += "b" + update_clothing_icon() + +/obj/item/clothing/accessory/tangzhuang + name = "tangzhuang jacket" + desc = "A traditional Chinese coat tied together with straight, symmetrical knots." + icon_state = "tangzhuang" //This was originally intended to have the ability to roll sleeves. I can't into code. Will be done later (hopefully.) diff --git a/code/modules/clothing/under/accessories/holster.dm b/code/modules/clothing/under/accessories/holster.dm new file mode 100644 index 00000000..07290911 --- /dev/null +++ b/code/modules/clothing/under/accessories/holster.dm @@ -0,0 +1,138 @@ +/obj/item/clothing/accessory/holster + name = "shoulder holster" + desc = "A handgun holster." + icon_state = "holster" + slot = ACCESSORY_SLOT_HOLSTER + high_visibility = 1 + var/obj/item/holstered = null + var/list/can_hold + +/obj/item/clothing/accessory/holster/proc/holster(var/obj/item/I, var/mob/living/user) + if(holstered && istype(user)) + to_chat(user, "There is already \a [holstered] holstered here!") + return + + if (can_hold) + if(!is_type_in_list(I,can_hold)) + to_chat(user, "[I] won't fit in [src]!") + return + + else if (!(I.slot_flags & SLOT_HOLSTER)) + to_chat(user, "[I] won't fit in [src]!") + return + + if(istype(user)) + user.stop_aiming(no_message=1) + holstered = I + user.drop_from_inventory(holstered) + holstered.loc = src + holstered.add_fingerprint(user) + w_class = max(w_class, holstered.w_class) + user.visible_message("[user] holsters \the [holstered].", "You holster \the [holstered].") + name = "occupied [initial(name)]" + +/obj/item/clothing/accessory/holster/proc/clear_holster() + holstered = null + SetName(initial(name)) + +/obj/item/clothing/accessory/holster/proc/unholster(mob/user as mob) + if(!holstered) + return + + if(istype(user.get_active_hand(),/obj) && istype(user.get_inactive_hand(),/obj)) + to_chat(user, "You need an empty hand to draw \the [holstered]!") + else + if(user.a_intent == I_HURT) + usr.visible_message( + "[user] draws \the [holstered], ready to go!", + "You draw \the [holstered], ready to go!" + ) + else + user.visible_message( + "[user] draws \the [holstered], pointing it at the ground.", + "You draw \the [holstered], pointing it at the ground." + ) + user.put_in_hands(holstered) + holstered.add_fingerprint(user) + w_class = initial(w_class) + clear_holster() + +/obj/item/clothing/accessory/holster/attackby(obj/item/W as obj, mob/user as mob) + holster(W, user) + +/obj/item/clothing/accessory/holster/emp_act(severity) + if (holstered) + holstered.emp_act(severity) + ..() + +/obj/item/clothing/accessory/holster/examine(mob/user) + . = ..(user) + if (holstered) + to_chat(user, "A [holstered] is holstered here.") + else + to_chat(user, "It is empty.") + +/obj/item/clothing/accessory/holster/on_attached(obj/item/clothing/under/S, mob/user as mob) + ..() + has_suit.verbs += /obj/item/clothing/accessory/holster/verb/holster_verb + +/obj/item/clothing/accessory/holster/on_removed(mob/user as mob) + if(has_suit) + has_suit.verbs -= /obj/item/clothing/accessory/holster/verb/holster_verb + ..() + +//For the holster hotkey +/obj/item/clothing/accessory/holster/verb/holster_verb() + set name = "Holster" + set category = "Object" + set src in usr + if(!istype(usr, /mob/living)) return + if(usr.stat) return + + //can't we just use src here? + var/obj/item/clothing/accessory/holster/H = null + if (istype(src, /obj/item/clothing/accessory/holster)) + H = src + else if (istype(src, /obj/item/clothing/under)) + var/obj/item/clothing/under/S = src + if (S.accessories.len) + H = locate() in S.accessories + + if (!H) + to_chat(usr, "Something is very wrong.") + + if(!H.holstered) + var/obj/item/W = usr.get_active_hand() + if(!istype(W, /obj/item)) + to_chat(usr, "You're not holding anything to holster.") + return + H.holster(W, usr) + else + H.unholster(usr) + +/obj/item/clothing/accessory/holster/armpit + name = "armpit holster" + desc = "A worn-out handgun holster. Perfect for concealed carry." + icon_state = "holster" + +/obj/item/clothing/accessory/holster/waist + name = "waist holster" + desc = "A handgun holster. Made of expensive leather." + icon_state = "holster" + overlay_state = "holster_low" + +/obj/item/clothing/accessory/holster/hip + name = "hip holster" + desc = "A handgun holster slung low on the hip, draw pardner!" + icon_state = "holster_hip" + +/obj/item/clothing/accessory/holster/thigh + name = "thigh holster" + desc = "A drop leg holster made of a durable synthetic fiber." + icon_state = "holster_thigh" + +/obj/item/clothing/accessory/holster/machete + name = "machete sheath" + desc = "A handsome synthetic leather sheath with matching belt." + icon_state = "holster_machete" + can_hold = list(/obj/item/weapon/material/hatchet/machete) \ No newline at end of file diff --git a/code/modules/clothing/under/accessories/jammers.dm b/code/modules/clothing/under/accessories/jammers.dm new file mode 100644 index 00000000..e69de29b diff --git a/code/modules/clothing/under/accessories/lockets.dm b/code/modules/clothing/under/accessories/lockets.dm new file mode 100644 index 00000000..f802df6d --- /dev/null +++ b/code/modules/clothing/under/accessories/lockets.dm @@ -0,0 +1,46 @@ +/obj/item/clothing/accessory/locket + name = "silver locket" + desc = "A silver locket that seems to have space for a photo within." + icon_state = "locket" + item_state = "locket" + slot_flags = 0 + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_MASK | SLOT_TIE + var/base_icon + var/open + var/obj/item/held //Item inside locket. + +/obj/item/clothing/accessory/locket/attack_self(mob/user as mob) + if(!base_icon) + base_icon = icon_state + + if(!("[base_icon]_open" in icon_states(icon))) + to_chat(user, "\The [src] doesn't seem to open.") + return + + open = !open + to_chat(user, "You flip \the [src] [open?"open":"closed"].") + if(open) + icon_state = "[base_icon]_open" + if(held) + to_chat(user, "\The [held] falls out!") + held.loc = get_turf(user) + src.held = null + else + icon_state = "[base_icon]" + +/obj/item/clothing/accessory/locket/attackby(var/obj/item/O as obj, mob/user as mob) + if(!open) + to_chat(user, "You have to open it first.") + return + + if(istype(O,/obj/item/weapon/paper) || istype(O, /obj/item/weapon/photo)) + if(held) + to_chat(usr, "\The [src] already has something inside it.") + else + to_chat(usr, "You slip [O] into [src].") + user.drop_item() + O.loc = src + src.held = O + return + ..() diff --git a/code/modules/clothing/under/accessories/medals.dm b/code/modules/clothing/under/accessories/medals.dm new file mode 100644 index 00000000..5e1f0929 --- /dev/null +++ b/code/modules/clothing/under/accessories/medals.dm @@ -0,0 +1,53 @@ +//Medals! + +/obj/item/clothing/accessory/medal + name = ACCESSORY_SLOT_MEDAL + desc = "A simple medal." + icon_state = "bronze" + slot = ACCESSORY_SLOT_MEDAL + +/obj/item/clothing/accessory/medal/iron + name = "iron medal" + desc = "A simple iron medal." + icon_state = "iron" + item_state = "iron" + +/obj/item/clothing/accessory/medal/bronze + name = "bronze medal" + desc = "A simple bronze medal." + icon_state = "bronze" + item_state = "bronze" + +/obj/item/clothing/accessory/medal/silver + name = "silver medal" + desc = "A simple silver medal." + icon_state = "silver" + item_state = "silver" + +/obj/item/clothing/accessory/medal/gold + name = "gold medal" + desc = "A simple gold medal." + icon_state = "gold" + item_state = "gold" + +//NT medals + +/obj/item/clothing/accessory/medal/gold/nanotrasen + name = "\improper NanoTrasen command medal" + desc = "A gold medal awarded to NanoTrasen employees for service as the Captain of a NanoTrasen facility, station, or vessel." + icon_state = "gold_nt" + +/obj/item/clothing/accessory/medal/silver/nanotrasen + name = "\improper NanoTrasen service medal" + desc = "A silver medal awarded to NanoTrasen employees for distinguished service in support of corporate interests." + icon_state = "silver_nt" + +/obj/item/clothing/accessory/medal/bronze/nanotrasen + name = "\improper NanoTrasen sciences medal" + desc = "A bronze medal awarded to NanoTrasen employees for signifigant contributions to the fields of science or engineering." + icon_state = "bronze_nt" + +/obj/item/clothing/accessory/medal/iron/nanotrasen + name = "\improper NanoTrasen merit medal" + desc = "An iron medal awarded to NanoTrasen employees for merit." + icon_state = "iron_nt" \ No newline at end of file diff --git a/code/modules/clothing/under/accessories/stethoscope.dm b/code/modules/clothing/under/accessories/stethoscope.dm new file mode 100644 index 00000000..fb349b80 --- /dev/null +++ b/code/modules/clothing/under/accessories/stethoscope.dm @@ -0,0 +1,15 @@ +/obj/item/clothing/accessory/stethoscope + name = "stethoscope" + desc = "An outdated medical apparatus for listening to the sounds of the human body. It also makes you look like you know what you're doing." + icon_state = "stethoscope" + high_visibility = 1 + +/obj/item/clothing/accessory/stethoscope/attack(mob/living/carbon/human/M, mob/living/user) + if(ishuman(M) && isliving(user)) + if(user.a_intent == I_HELP) + var/obj/item/organ/organ = M.get_organ(user.zone_sel.selecting) + if(organ) + user.visible_message("[user] places [src] against [M]'s [organ.name] and listens attentively.", + "You place [src] against [M]'s [organ.name]. You hear [english_list(organ.listen())].") + return + return ..(M,user) \ No newline at end of file diff --git a/code/modules/clothing/under/accessories/storage.dm b/code/modules/clothing/under/accessories/storage.dm new file mode 100644 index 00000000..fa058934 --- /dev/null +++ b/code/modules/clothing/under/accessories/storage.dm @@ -0,0 +1,153 @@ +/obj/item/clothing/accessory/storage + name = "load bearing equipment" + desc = "Used to hold things when you don't have enough hands." + icon_state = "webbing" + slot = ACCESSORY_SLOT_UTILITY + var/slots = 3 + var/max_w_class = ITEM_SIZE_SMALL //pocket sized + var/obj/item/weapon/storage/internal/pockets/hold + w_class = ITEM_SIZE_NORMAL + high_visibility = 1 + +/obj/item/clothing/accessory/storage/New() + ..() + create_storage() + +/obj/item/clothing/accessory/storage/proc/create_storage() + hold = new/obj/item/weapon/storage/internal/pockets(src, slots, max_w_class) + +/obj/item/clothing/accessory/storage/attack_hand(mob/user as mob) + if (has_suit) //if we are part of a suit + hold.open(user) + return + + if (hold.handle_attack_hand(user)) //otherwise interact as a regular storage item + ..(user) + +/obj/item/clothing/accessory/storage/MouseDrop(obj/over_object as obj) + if (has_suit) + return + + if (hold.handle_mousedrop(usr, over_object)) + ..(over_object) + +/obj/item/clothing/accessory/storage/attackby(obj/item/W as obj, mob/user as mob) + return hold.attackby(W, user) + +/obj/item/clothing/accessory/storage/emp_act(severity) + hold.emp_act(severity) + ..() + +/obj/item/clothing/accessory/storage/attack_self(mob/user as mob) + to_chat(user, "You empty [src].") + var/turf/T = get_turf(src) + hold.hide_from(usr) + for(var/obj/item/I in hold.contents) + hold.remove_from_storage(I, T) + src.add_fingerprint(user) + +/obj/item/clothing/accessory/storage/webbing + name = "webbing" + desc = "Sturdy mess of synthcotton belts and buckles, ready to share your burden." + icon_state = "webbing" + +/obj/item/clothing/accessory/storage/webbing_large + name = "large webbing" + desc = "A large collection of synthcotton pockets and pouches." + icon_state = "webbing_large" + slots = 4 + +/obj/item/clothing/accessory/storage/black_vest + name = "black webbing vest" + desc = "Robust black synthcotton vest with lots of pockets to hold whatever you need, but cannot hold in hands." + icon_state = "vest_black" + slots = 5 + +/obj/item/clothing/accessory/storage/brown_vest + name = "brown webbing vest" + desc = "Worn brownish synthcotton vest with lots of pockets to unload your hands." + icon_state = "vest_brown" + slots = 5 + +/obj/item/clothing/accessory/storage/white_vest + name = "white webbing vest" + desc = "Durable white synthcotton vest with lots of pockets to carry essentials." + icon_state = "vest_white" + slots = 5 + +/obj/item/clothing/accessory/storage/drop_pouches + slots = 4 //to accomodate it being slotless + +/obj/item/clothing/accessory/storage/drop_pouches/create_storage() + hold = new/obj/item/weapon/storage/internal/pouch(src, slots*base_storage_cost(max_w_class)) + +/obj/item/clothing/accessory/storage/drop_pouches/black + name = "black drop pouches" + desc = "Robust black synthcotton bags to hold whatever you need, but cannot hold in hands." + icon_state = "thigh_black" + +/obj/item/clothing/accessory/storage/drop_pouches/brown + name = "brown drop pouches" + desc = "Worn brownish synthcotton bags to hold whatever you need, but cannot hold in hands." + icon_state = "thigh_brown" + +/obj/item/clothing/accessory/storage/drop_pouches/white + name = "white drop pouches" + desc = "Durable white synthcotton bags to hold whatever you need, but cannot hold in hands." + icon_state = "thigh_white" + +/obj/item/clothing/accessory/storage/knifeharness + name = "decorated harness" + desc = "A heavily decorated harness of sinew and leather with two knife-loops." + icon_state = "unathiharness2" + slots = 2 + max_w_class = ITEM_SIZE_NORMAL //for knives + +/obj/item/clothing/accessory/storage/knifeharness/New() + ..() + hold.can_hold = list( + /obj/item/weapon/material/hatchet, + /obj/item/weapon/material/kitchen/utensil/knife, + /obj/item/weapon/material/knife, + /obj/item/weapon/material/butterfly, + ) + + new /obj/item/weapon/material/kitchen/utensil/knife/unathiknife(hold) + new /obj/item/weapon/material/kitchen/utensil/knife/unathiknife(hold) + +/obj/item/clothing/accessory/storage/bandolier + name = "bandolier" + desc = "A lightweight synthethic bandolier with straps for holding ammunition or other small objects." + icon_state = "bandolier" + slots = 10 + max_w_class = ITEM_SIZE_NORMAL + +/obj/item/clothing/accessory/storage/bandolier/New() + ..() + hold.can_hold = list( + /obj/item/ammo_casing, + /obj/item/weapon/grenade, + /obj/item/weapon/material/hatchet/tacknife, + /obj/item/weapon/material/kitchen/utensil/knife, + /obj/item/weapon/material/knife, + /obj/item/weapon/material/star, + /obj/item/weapon/rcd_ammo, + /obj/item/weapon/reagent_containers/syringe, + /obj/item/weapon/reagent_containers/hypospray, + /obj/item/weapon/reagent_containers/hypospray/autoinjector, + /obj/item/weapon/syringe_cartridge, + /obj/item/weapon/plastique, + /obj/item/clothing/mask/smokable, + /obj/item/weapon/screwdriver, + /obj/item/device/multitool, + /obj/item/weapon/magnetic_ammo, + /obj/item/ammo_magazine, + /obj/item/weapon/net_shell, + /obj/item/weapon/reagent_containers/glass/beaker/vial + ) + +/obj/item/clothing/accessory/storage/bandolier/safari/New() + ..() + + for(var/i = 0, i < slots, i++) + new /obj/item/weapon/net_shell(hold) \ No newline at end of file diff --git a/code/modules/clothing/under/accessories/ties.dm b/code/modules/clothing/under/accessories/ties.dm new file mode 100644 index 00000000..b57769a5 --- /dev/null +++ b/code/modules/clothing/under/accessories/ties.dm @@ -0,0 +1,104 @@ +/obj/item/clothing/accessory/long + icon_state = "longtie" + +/obj/item/clothing/accessory/blue + name = "blue tie" + color = "#123c5a" + +/obj/item/clothing/accessory/red + name = "red tie" + color = "#800000" + +/obj/item/clothing/accessory/blue_clip + name = "blue tie with a clip" + icon_state = "bluecliptie" + +/obj/item/clothing/accessory/red_long + name = "red long tie" + icon_state = "longtie" + color = "#a02929" + +/obj/item/clothing/accessory/black + name = "black tie" + color = "#ffffff" + +/obj/item/clothing/accessory/yellow + name = "yellow tie" + icon_state = "longtie" + color = "#c4c83d" + +/obj/item/clothing/accessory/navy + name = "navy tie" + color = "#182e44" + +/obj/item/clothing/accessory/horrible + name = "horrible tie" + desc = "A neosilk clip-on tie. This one is disgusting." + icon_state = "horribletie" + +/obj/item/clothing/accessory/brown + name = "brown tie" + icon_state = "longtie" + color = "#b18345" + +/obj/item/clothing/accessory/nt + name = "\improper NanoTrasen tie with a clip" + desc = "A neosilk clip-on tie. This one has a clip on it that proudly bears 'NT' on it." + icon_state = "ntcliptie" + +//Bowties +/obj/item/clothing/accessory/bowtie + var/icon_tied +/obj/item/clothing/accessory/bowtie/New() + icon_tied = icon_tied || icon_state + ..() + +/obj/item/clothing/accessory/bowtie/on_attached(obj/item/clothing/under/S, mob/user as mob) + ..() + has_suit.verbs += /obj/item/clothing/accessory/bowtie/verb/toggle + +/obj/item/clothing/accessory/bowtie/on_removed(mob/user as mob) + if(has_suit) + has_suit.verbs -= /obj/item/clothing/accessory/bowtie/verb/toggle + ..() + +/obj/item/clothing/accessory/bowtie/verb/toggle() + set name = "Toggle Bowtie" + set category = "Object" + set src in usr + + if(usr.incapacitated()) + return 0 + + var/obj/item/clothing/accessory/bowtie/H = null + if (istype(src, /obj/item/clothing/accessory/bowtie)) + H = src + else + H = locate() in src + + if(H) + H.do_toggle(usr) + +/obj/item/clothing/accessory/bowtie/proc/do_toggle(user) + if(icon_state == icon_tied) + to_chat(usr, "You untie [src].") + else + to_chat(usr, "You tie [src].") + + update_icon() + +/obj/item/clothing/accessory/bowtie/update_icon() + if(icon_state == icon_tied) + icon_state = "[icon_tied]_untied" + else + icon_state = icon_tied + +/obj/item/clothing/accessory/bowtie/color + name = "bowtie" + desc = "A neosilk hand-tied bowtie." + icon_state = "bowtie" + +/obj/item/clothing/accessory/bowtie/ugly + name = "horrible bowtie" + desc = "A neosilk hand-tied bowtie. This one is disgusting." + icon_state = "bowtie_ugly" diff --git a/code/modules/clothing/under/casual_pants.dm b/code/modules/clothing/under/casual_pants.dm new file mode 100644 index 00000000..087b1fc1 --- /dev/null +++ b/code/modules/clothing/under/casual_pants.dm @@ -0,0 +1,102 @@ +//Casual pants - new pants of this type go in pants.dmi + +/obj/item/clothing/under/casual_pants + name = "jeans" + desc = "A nondescript pair of tough blue jeans." + icon_state = "jeans" + gender = PLURAL + body_parts_covered = LOWER_TORSO|LEGS + item_icons = list(slot_w_uniform_str = 'icons/mob/onmob/pants.dmi') + +/obj/item/clothing/under/casual_pants/classicjeans + name = "classic jeans" + desc = "You feel cooler already." + icon_state = "jeansclassic" + +/obj/item/clothing/under/casual_pants/mustangjeans + name = "must hang jeans" + desc = "Made in the finest space jeans factory this side of Alpha Centauri." + icon_state = "jeansmustang" + +/obj/item/clothing/under/casual_pants/blackjeans + name = "black jeans" + desc = "Only for those who can pull it off." + icon_state = "jeansblack" + +/obj/item/clothing/under/casual_pants/greyjeans + name = "grey jeans" + desc = "Only for those who can pull it off." + icon_state = "jeansgrey" + +/obj/item/clothing/under/casual_pants/youngfolksjeans + name = "young folks jeans" + desc = "For those tired of boring old jeans. Relive the passion of your youth!" + icon_state = "jeansyoungfolks" + +/obj/item/clothing/under/casual_pants/track + name = "track pants" + desc = "A pair of track pants, for the athletic." + icon_state = "trackpants" + +/obj/item/clothing/under/casual_pants/track/blue + name = "blue track pants" + icon_state = "trackpantsblue" + +/obj/item/clothing/under/casual_pants/track/green + name = "green track pants" + icon_state = "trackpantsgreen" + +/obj/item/clothing/under/casual_pants/track/white + name = "white track pants" + icon_state = "trackpantswhite" + +/obj/item/clothing/under/casual_pants/track/red + name = "red track pants" + icon_state = "trackpantsred" + +/obj/item/clothing/under/casual_pants/camo + name = "camo pants" + desc = "A pair of woodland camouflage pants. Probably not the best choice for space." + icon_state = "camopants" + +//Baggy Pants// + +/obj/item/clothing/under/casual_pants/baggy + name = "baggy jeans" + desc = "A nondescript pair of tough baggy blue jeans." + icon_state = "baggy_jeans" + +/obj/item/clothing/under/casual_pants/baggy/classicjeans + name = "baggy classic jeans" + desc = "You feel cooler already." + icon_state = "baggy_jeansclassic" + +/obj/item/clothing/under/casual_pants/baggy/mustangjeans + name = "maggy must hang jeans" + desc = "Made in the finest space jeans factory this side of Alpha Centauri." + icon_state = "baggy_jeansmustang" + +/obj/item/clothing/under/casual_pants/baggy/blackjeans + name = "baggy black jeans" + desc = "Only for those who can pull it off." + icon_state = "baggy_jeansblack" + +/obj/item/clothing/under/casual_pants/baggy/greyjeans + name = "baggy grey jeans" + desc = "Only for those who can pull it off." + icon_state = "baggy_jeansgrey" + +/obj/item/clothing/under/casual_pants/baggy/youngfolksjeans + name = "baggy young folks jeans" + desc = "For those tired of boring old jeans. Relive the passion of your youth!" + icon_state = "baggy_jeansyoungfolks" + +/obj/item/clothing/under/casual_pants/baggy/track + name = "baggy track pants" + desc = "A pair of track pants, for the athletic." + icon_state = "baggy_trackpants" + +/obj/item/clothing/under/casual_pants/baggy/camo + name = "baggy camo pants" + desc = "A pair of woodland camouflage pants. Probably not the best choice for space." + icon_state = "baggy_camopants" diff --git a/code/modules/clothing/under/color.dm b/code/modules/clothing/under/color.dm new file mode 100644 index 00000000..24fae90e --- /dev/null +++ b/code/modules/clothing/under/color.dm @@ -0,0 +1,84 @@ +// items not part of the colour changing system + +/obj/item/clothing/under/psyche + name = "psychedelic jumpsuit" + desc = "Groovy!" + icon_state = "psyche" + item_state = "psyche" + worn_state = "psyche" + +/obj/item/clothing/under/color/orange + name = "orange jumpsuit" + desc = "It's standardised prisoner-wear. Its suit sensor controls are permanently set to the \"Fully On\" position." + icon_state = "orange" + item_state = "o_suit" + worn_state = "orange" + has_sensor = 2 + sensor_mode = 3 + +/obj/item/clothing/under/color/blackjumpshorts + name = "black jumpsuit shorts" + desc = "The latest in space fashion, in a ladies' cut with shorts." + icon_state = "black" + item_state = "bl_suit" + worn_state = "blackshortsf" + +// coloured jumpsuits, male pattern + +/obj/item/clothing/under/color + name = "jumpsuit" + desc = "The latest in space fashion." + icon_state = "jumpsuit" + item_state = "jumpsuit" + worn_state = "jumpsuit" + +// legacy colours - these are used somewhere in the game, but aren't available in the loadout + +/obj/item/clothing/under/color/white + name = "white jumpsuit" + color = "#ffffff" + +/obj/item/clothing/under/color/black + name = "black jumpsuit" + color = "#3d3d3d" + +/obj/item/clothing/under/color/grey + name = "grey jumpsuit" + color = "#c4c4c4" + +/obj/item/clothing/under/color/blue + name = "blue jumpsuit" + color = "#0066ff" + +/obj/item/clothing/under/color/pink + name = "pink jumpsuit" + color = "#df20a6" + +/obj/item/clothing/under/color/red + name = "red jumpsuit" + color = "#ee1511" + +/obj/item/clothing/under/color/green + name = "green jumpsuit" + color = "#42a345" + +/obj/item/clothing/under/color/yellow + name = "yellow jumpsuit" + color = "#ffee00" + +/obj/item/clothing/under/color/lightpurple + name = "light purple jumpsuit" + color = "#c600fc" + +/obj/item/clothing/under/color/brown + name = "brown jumpsuit" + color = "#c08720" + +// coloured jumpsuits, female pattern + +/obj/item/clothing/under/fcolor + name = "feminine jumpsuit" + desc = "The latest in space fashion, in a slimming ladies' cut." + icon_state = "jumpsuit" + item_state = "jumpsuit" + worn_state = "f_jumpsuit" \ No newline at end of file diff --git a/code/modules/clothing/under/formal_pants.dm b/code/modules/clothing/under/formal_pants.dm new file mode 100644 index 00000000..acb6b1f5 --- /dev/null +++ b/code/modules/clothing/under/formal_pants.dm @@ -0,0 +1,56 @@ +//Formal pants - new pants of this type go in pants.dmi + +/obj/item/clothing/under/formal_pants + name = "suit pants" + desc = "Plain suit pants." + icon_state = "pants" + gender = PLURAL + body_parts_covered = LOWER_TORSO|LEGS + item_icons = list(slot_w_uniform_str = 'icons/mob/onmob/pants.dmi') + +/obj/item/clothing/under/formal_pants/red + name = "red pants" + desc = "Bright red pants. Overflowing with personality." + color = "#7f0000" + +/obj/item/clothing/under/formal_pants/black + name = "black pants" + desc = "These pants are dark, like your soul." + color = "#1f1f1f" + +/obj/item/clothing/under/formal_pants/tan + name = "tan pants" + desc = "Some tan pants. You look like a white collar worker with these on." + color = "#75634f" + +/obj/item/clothing/under/formal_pants/khaki + name = "khaki pants" + desc = "A pair of dust beige khaki pants." + color = "#75634f" + +//Baggy Pants// + +/obj/item/clothing/under/formal_pants/baggy + name = "baggy pants" + desc = "Plain baggy pants." + icon_state = "baggy_pants" + +/obj/item/clothing/under/formal_pants/baggy/red + name = "baggy red pants" + desc = "Bright red pants. Overflowing with personality." + color = "#7f0000" + +/obj/item/clothing/under/formal_pants/baggy/black + name = "baggy black pants" + desc = "These pants are dark, like your soul." + color = "#262626" + +/obj/item/clothing/under/formal_pants/baggy/tan + name = "baggy tan pants" + desc = "Some tan pants. You look like a white collar worker with these on." + color = "#75634f" + +/obj/item/clothing/under/formal_pants/baggy/khaki + name = "baggy khaki pants" + desc = "A pair of dust beige khaki pants." + color = "#75634f" \ No newline at end of file diff --git a/code/modules/clothing/under/jobs/civilian.dm b/code/modules/clothing/under/jobs/civilian.dm new file mode 100644 index 00000000..299a254f --- /dev/null +++ b/code/modules/clothing/under/jobs/civilian.dm @@ -0,0 +1,207 @@ +//Alphabetical order of civilian jobs. + +/obj/item/clothing/under/rank/bartender + desc = "It looks like it could use some more flair." + name = "bartender's uniform" + icon_state = "ba_suit" + item_state = "ba_suit" + worn_state = "ba_suit" + +//Magistrates uniform. //Not in alphabetical order +/obj/item/clothing/under/rank/magistrate + name = "commandant\'s uniform" + desc = "Regal as you can afford." + icon_state = "magistrate" + worn_state = "magistrate" + +/obj/item/clothing/under/rank/consort + name = "consort\'s uniform" + desc = "Regal enough to be the partner of the Commandant." + icon_state = "consort" + worn_state = "consort" + + +/obj/item/clothing/under/rank/captain //Alright, technically not a 'civilian' but its better then giving a .dm file for a single define. + desc = "It's a blue jumpsuit with some gold markings denoting the rank of \"Captain\"." + name = "captain's jumpsuit" + icon_state = "captain" + item_state = "b_suit" + worn_state = "captain" + + +/obj/item/clothing/under/rank/cargo + name = "quartermaster's jumpsuit" + desc = "It's a jumpsuit worn by the quartermaster. It's specially designed to prevent back injuries caused by pushing paper." + icon_state = "qm" + item_state = "lb_suit" + worn_state = "qm" + + +/obj/item/clothing/under/rank/cargotech + name = "cargo technician's jumpsuit" + desc = "Shooooorts! They're comfy and easy to wear!" + icon_state = "cargotech" + item_state = "lb_suit" + worn_state = "cargo" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + + +/obj/item/clothing/under/rank/chaplain + desc = "It's a black jumpsuit, often worn by religious folk." + name = "chaplain's jumpsuit" + icon_state = "chaplain" + item_state = "bl_suit" + worn_state = "chapblack" + + +/obj/item/clothing/under/rank/chef + desc = "It's an apron which is given only to the most hardcore chefs in space." + name = "chef's uniform" + icon_state = "chef" + item_state = "w_suit" + worn_state = "chef" + + +/obj/item/clothing/under/rank/clown + name = "clown suit" + desc = "'HONK!'" + icon_state = "clown" + item_state = "clown" + worn_state = "clown" + + +/obj/item/clothing/under/rank/head_of_personnel + desc = "It's a jumpsuit worn by someone who works in the position of \"Head of Personnel\"." + name = "head of personnel's jumpsuit" + icon_state = "hop" + item_state = "b_suit" + worn_state = "hop" + +/obj/item/clothing/under/rank/head_of_personnel_whimsy + desc = "A blue jacket and red tie, with matching red cuffs! Snazzy. Wearing this makes you feel more important than your job title does." + name = "head of personnel's suit" + icon_state = "hopwhimsy" + item_state = "b_suit" + worn_state = "hopwhimsy" + + +/obj/item/clothing/under/rank/hydroponics + desc = "It's a jumpsuit designed to protect against minor plant-related hazards." + name = "botanist's jumpsuit" + icon_state = "hydroponics" + item_state = "g_suit" + worn_state = "hydroponics" + permeability_coefficient = 0.50 + + +/obj/item/clothing/under/rank/internalaffairs + desc = "The plain, professional attire of an Internal Affairs Agent. The collar is immaculately starched." + name = "Internal Affairs uniform" + icon_state = "internalaffairs" + item_state = "ba_suit" + worn_state = "internalaffairs" + starting_accessories = list(/obj/item/clothing/accessory/black) + +/obj/item/clothing/under/rank/internalaffairs/plain + desc = "A plain shirt and pair of pressed black pants." + name = "formal outfit" + starting_accessories = null + +/obj/item/clothing/under/rank/internalaffairs/plain/nt + desc = "A plain shirt and pair of pressed black pants." + name = "formal outfit" + starting_accessories = list(/obj/item/clothing/accessory/red_long) + + +/obj/item/clothing/under/rank/janitor + desc = "It's the official uniform of the janitor. It has minor protection from biohazards." + name = "janitor's jumpsuit" + icon_state = "janitor" + worn_state = "janitor" + item_state = "janitor" + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + + +/obj/item/clothing/under/lawyer + desc = "Slick threads." + name = "Lawyer suit" + + +/obj/item/clothing/under/lawyer/black + name = "black Lawyer suit" + icon_state = "lawyer_black" + item_state = "lawyer_black" + worn_state = "lawyer_black" + + +/obj/item/clothing/under/lawyer/female + name = "black Lawyer suit" + icon_state = "black_suit_fem" + item_state = "lawyer_black" + worn_state = "black_suit_fem" + + +/obj/item/clothing/under/lawyer/red + name = "red Lawyer suit" + icon_state = "lawyer_red" + item_state = "lawyer_red" + worn_state = "lawyer_red" + + +/obj/item/clothing/under/lawyer/blue + name = "blue Lawyer suit" + icon_state = "lawyer_blue" + item_state = "lawyer_blue" + worn_state = "lawyer_blue" + + +/obj/item/clothing/under/lawyer/bluesuit + name = "Blue Suit" + desc = "A classy suit." + icon_state = "bluesuit" + item_state = "ba_suit" + worn_state = "bluesuit" + starting_accessories = list(/obj/item/clothing/accessory/red) + + +/obj/item/clothing/under/lawyer/purpsuit + name = "Purple Suit" + icon_state = "lawyer_purp" + item_state = "ba_suit" + worn_state = "lawyer_purp" + +/obj/item/clothing/under/lawyer/oldman + name = "Old Man's Suit" + desc = "A classic suit for the older gentleman with built in back support." + icon_state = "oldman" + item_state = "johnny" + worn_state = "oldman" + + +/obj/item/clothing/under/librarian + name = "sensible suit" + desc = "It's very... sensible." + icon_state = "red_suit" + item_state = "lawyer_red" + worn_state = "red_suit" + +/obj/item/clothing/under/mime + name = "mime's outfit" + desc = "It's not very colourful." + icon_state = "mime" + item_state = "ba_suit" + worn_state = "mime" + +/obj/item/clothing/under/rank/miner + desc = "It's a snappy jumpsuit with a sturdy set of overalls. It is very dirty." + name = "shaft miner's jumpsuit" + icon_state = "miner" + item_state = "lb_suit" + worn_state = "miner" + +/obj/item/clothing/under/rank/explorer + desc = "It's a snappy jumpsuit with a sturdy set of overalls. It is very dirty." + name = "salvage miner's jumpsuit" + icon_state = "explorer" + item_state = "lb_suit" + worn_state = "explorer" \ No newline at end of file diff --git a/code/modules/clothing/under/jobs/engineering.dm b/code/modules/clothing/under/jobs/engineering.dm new file mode 100644 index 00000000..2c3a38cb --- /dev/null +++ b/code/modules/clothing/under/jobs/engineering.dm @@ -0,0 +1,36 @@ +//Contains: Engineering department jumpsuits +/obj/item/clothing/under/rank/chief_engineer + desc = "It's a high visibility jumpsuit given to those engineers insane enough to achieve the rank of \"Chief engineer\". It has minor radiation shielding." + name = "chief engineer's jumpsuit" + icon_state = "chiefengineer" + item_state = "g_suit" + worn_state = "chief" + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 10) + +/obj/item/clothing/under/rank/atmospheric_technician + desc = "It's a jumpsuit worn by atmospheric technicians." + name = "atmospheric technician's jumpsuit" + icon_state = "atmos" + item_state = "atmos_suit" + worn_state = "atmos" + +/obj/item/clothing/under/rank/engineer + desc = "It's an orange high visibility jumpsuit worn by engineers. It has minor radiation shielding." + name = "engineer's jumpsuit" + icon_state = "engine" + item_state = "engi_suit" + worn_state = "engine" + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 10) + +/obj/item/clothing/under/rank/roboticist + desc = "It's a slimming black jumpsuit with reinforced seams; great for industrial work." + name = "roboticist's jumpsuit" + icon_state = "robotics" + item_state = "bl_suit" + worn_state = "robotics" + +/obj/item/clothing/under/rank/roboticist/skirt + desc = "It's a slimming black jumpskirt with reinforced seams; great for industrial work." + name = "roboticist's jumpskirt" + icon_state = "roboticsf" + worn_state = "roboticsf" \ No newline at end of file diff --git a/code/modules/clothing/under/jobs/medsci.dm b/code/modules/clothing/under/jobs/medsci.dm new file mode 100644 index 00000000..67505849 --- /dev/null +++ b/code/modules/clothing/under/jobs/medsci.dm @@ -0,0 +1,204 @@ +/* + * Science + */ +/obj/item/clothing/under/rank/research_director + desc = "It's a jumpsuit worn by those with the know-how to achieve the position of \"Research Director\". Its fabric provides minor protection from biological contaminants." + name = "research director's jumpsuit" + icon_state = "director" + item_state = "lb_suit" + worn_state = "director" + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + +/obj/item/clothing/under/rank/research_director/rdalt + desc = "A dress suit and slacks stained with hard work and dedication to science. Perhaps other things as well, but mostly hard work and dedication." + name = "head researcher uniform" + icon_state = "rdalt" + item_state = "lb_suit" + worn_state = "rdalt" + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + +/obj/item/clothing/under/rank/research_director/dress_rd + name = "research director dress uniform" + desc = "Feminine fashion for the style concious RD. Its fabric provides minor protection from biological contaminants." + icon_state = "dress_rd" + item_state = "lb_suit" + worn_state = "dress_rd" + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + +/obj/item/clothing/under/rank/chemist + desc = "It's made of a special fiber that gives special protection against biohazards. It has a chemist rank stripe on it." + name = "chemist's jumpsuit" + icon_state = "chemistry" + item_state = "w_suit" + worn_state = "chemistrywhite" + permeability_coefficient = 0.50 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + +/* + * Medical + */ +/obj/item/clothing/under/rank/chief_medical_officer + desc = "It's a jumpsuit worn by those with the experience to be \"Chief Medical Officer\". It provides minor biological protection." + name = "chief medical officer's jumpsuit" + icon_state = "cmo" + item_state = "w_suit" + worn_state = "cmo" + permeability_coefficient = 0.50 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + +/obj/item/clothing/under/rank/geneticist + desc = "It's made of a special fiber that gives special protection against biohazards. It has a genetics rank stripe on it." + name = "geneticist's jumpsuit" + icon_state = "genetics" + item_state = "w_suit" + worn_state = "geneticswhite" + permeability_coefficient = 0.50 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + +/obj/item/clothing/under/rank/virologist + desc = "It's made of a special fiber that gives special protection against biohazards. It has a virologist rank stripe on it." + name = "virologist's jumpsuit" + icon_state = "virology" + item_state = "w_suit" + worn_state = "virologywhite" + permeability_coefficient = 0.50 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + +/obj/item/clothing/under/rank/nursesuit + desc = "It's a jumpsuit commonly worn by nursing staff in the medical department." + name = "nurse's suit" + icon_state = "nursesuit" + item_state = "nursesuit" + worn_state = "nursesuit" + permeability_coefficient = 0.50 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + body_parts_covered = UPPER_TORSO|LOWER_TORSO + +/obj/item/clothing/under/rank/nurse + desc = "A dress commonly worn by the nursing staff in the medical department." + name = "nurse's dress" + icon_state = "nurse" + item_state = "nursesuit" + worn_state = "nurse" + permeability_coefficient = 0.50 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + body_parts_covered = UPPER_TORSO|LOWER_TORSO + +/obj/item/clothing/under/rank/orderly + desc = "A white suit to be worn by medical attendants." + name = "orderly's uniform" + icon_state = "orderly" + item_state = "nursesuit" + worn_state = "orderly" + permeability_coefficient = 0.50 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + +/obj/item/clothing/under/rank/medical + desc = "It's made of a special fiber that provides minor protection against biohazards. It has a cross on the chest denoting that the wearer is trained medical personnel." + name = "medical doctor's jumpsuit" + icon_state = "medical" + item_state = "w_suit" + worn_state = "medical" + permeability_coefficient = 0.50 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + +/obj/item/clothing/under/rank/medical/paramedic + name = "short sleeve medical jumpsuit" + desc = "It's made of a special fiber that provides minor protection against biohazards. This one has a cross on the chest denoting that the wearer is trained medical personnel." + icon_state = "medical" + item_state = "medical_short" + worn_state = "medical_short" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS + +/obj/item/clothing/under/rank/medical/scrubs + name = "scrubs" + desc = "A loose-fitting garment designed to provide minor protection against biohazards." + icon_state = "scrubs" + worn_state = "scrubs" + +/obj/item/clothing/under/rank/medical/scrubs/blue + name = "blue scrubs" + color = "#4891e1" + +/obj/item/clothing/under/rank/medical/scrubs/green + name = "green scrubs" + color = "#255a3e" + +/obj/item/clothing/under/rank/medical/scrubs/purple + name = "purple scrubs" + color = "#7a1b3f" + +/obj/item/clothing/under/rank/medical/scrubs/black + name = "black scrubs" + color = "#242424" + +/obj/item/clothing/under/rank/medical/scrubs/navyblue + name = "navy blue scrubs" + color = "#1f3a69" + +/obj/item/clothing/under/rank/medical/scrubs/lilac + name = "lilac scrubs" + color = "#c8a2c8" + +/obj/item/clothing/under/rank/medical/scrubs/teal + name = "teal scrubs" + color = "#008080" + +/obj/item/clothing/under/rank/medical/scrubs/heliodor + name = "heliodor scrubs" + color = "#aad539" + +/obj/item/clothing/under/rank/psych + desc = "A basic white jumpsuit. It has turqouise markings that denote the wearer as a psychiatrist." + name = "psychiatrist's jumpsuit" + icon_state = "psych" + item_state = "w_suit" + worn_state = "psych" + +/obj/item/clothing/under/rank/psych/turtleneck + desc = "A turqouise sweater and a pair of dark blue slacks." + name = "turqouise turtleneck" + icon_state = "psychturtle" + item_state = "b_suit" + worn_state = "psychturtle" + + +/* + * Medsci, unused (i think) stuff + */ +/obj/item/clothing/under/rank/geneticist_new + desc = "It's made of a special fiber which provides minor protection against biohazards." + name = "geneticist's jumpsuit" + icon_state = "genetics_new" + item_state = "w_suit" + worn_state = "genetics_new" + permeability_coefficient = 0.50 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + +/obj/item/clothing/under/rank/chemist_new + desc = "It's made of a special fiber which provides minor protection against biohazards." + name = "chemist's jumpsuit" + icon_state = "chemist_new" + item_state = "w_suit" + worn_state = "chemist_new" + permeability_coefficient = 0.50 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + +/obj/item/clothing/under/rank/scientist_new + desc = "Made of a special fiber that gives special protection against biohazards and small explosions." + name = "scientist's jumpsuit" + icon_state = "scientist_new" + item_state = "w_suit" + worn_state = "scientist_new" + permeability_coefficient = 0.50 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 10, bio = 0, rad = 0) + +/obj/item/clothing/under/rank/virologist_new + desc = "Made of a special fiber that gives increased protection against biohazards." + name = "virologist's jumpsuit" + icon_state = "virologist_new" + item_state = "w_suit" + worn_state = "virologist_new" + permeability_coefficient = 0.50 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) diff --git a/code/modules/clothing/under/jobs/security.dm b/code/modules/clothing/under/jobs/security.dm new file mode 100644 index 00000000..68198fc7 --- /dev/null +++ b/code/modules/clothing/under/jobs/security.dm @@ -0,0 +1,208 @@ +/* + * Contains: + * Security + * Detective + * Head of Security + */ + +/* + * Security + */ +/obj/item/clothing/under/rank/warden + desc = "It's made of a slightly sturdier material than standard jumpsuits, to allow for more robust protection. It has the word \"Warden\" written on the shoulders." + name = "warden's jumpsuit" + icon_state = "warden" + item_state = "r_suit" + worn_state = "warden" + armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 0.9 + +/obj/item/clothing/head/warden + name = "warden's hat" + desc = "It's a special helmet issued to the Warden of a securiy force." + icon_state = "policehelm" + body_parts_covered = 0 + +/obj/item/clothing/under/rank/security + name = "security officer's jumpsuit" + desc = "It's made of a slightly sturdier material than standard jumpsuits, to allow for robust protection." + icon_state = "security" + item_state = "r_suit" + worn_state = "secred" + armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 0.9 + +/obj/item/clothing/under/rank/dispatch + name = "dispatcher's uniform" + desc = "A dress shirt and khakis with a security patch sewn on." + icon_state = "dispatch" + //item_state = "dispatch" + worn_state = "dispatch" + armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS + siemens_coefficient = 0.9 + +/obj/item/clothing/under/rank/security2 + name = "security officer's uniform" + desc = "It's made of a slightly sturdier material, to allow for robust protection." + icon_state = "redshirt2" + item_state = "r_suit" + worn_state = "redshirt2" + armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 0.9 + +/obj/item/clothing/under/rank/security/corp + icon_state = "sec_corporate" + //item_state = "sec_corporate" + worn_state = "sec_corporate" + +/obj/item/clothing/under/rank/warden/corp + icon_state = "warden_corporate" + //item_state = "warden_corporate" + worn_state = "warden_corporate" + +/obj/item/clothing/under/tactical + name = "tactical jumpsuit" + desc = "It's made of a slightly sturdier material than standard jumpsuits, to allow for robust protection." + icon_state = "swatunder" + //item_state = "swatunder" + worn_state = "swatunder" + armor = list(melee = 10, bullet = 5, laser = 5,energy = 0, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 0.9 + +/* + * Detective + */ +/obj/item/clothing/under/det + name = "detective's suit" + desc = "A rumpled white dress shirt paired with well-worn grey slacks." + icon_state = "detective" + item_state = "det" + worn_state = "detective" + armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 0.9 + starting_accessories = list(/obj/item/clothing/accessory/blue_clip) + +/obj/item/clothing/under/det/grey + icon_state = "detective2" + worn_state = "detective2" + desc = "A serious-looking tan dress shirt paired with freshly-pressed black slacks." + starting_accessories = list(/obj/item/clothing/accessory/red_long) + +/obj/item/clothing/under/det/black + icon_state = "detective3" + worn_state = "detective3" + item_state = "sl_suit" + desc = "An immaculate white dress shirt, paired with a pair of dark grey dress pants, a red tie, and a charcoal vest." + starting_accessories = list(/obj/item/clothing/accessory/red_long, /obj/item/clothing/accessory/toggleable/vest) + +/obj/item/clothing/head/det + name = "fedora" + desc = "A brown fedora - either the cornerstone of a detective's style or a poor attempt at looking cool, depending on the person wearing it." + icon_state = "detective" + item_state_slots = list( + slot_l_hand_str = "det_hat", + slot_r_hand_str = "det_hat", + ) + armor = list(melee = 50, bullet = 5, laser = 25,energy = 10, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 0.9 + flags_inv = BLOCKHEADHAIR + +/obj/item/clothing/head/det/attack_self(mob/user) + flags_inv ^= BLOCKHEADHAIR + to_chat(user, "[src] will now [flags_inv & BLOCKHEADHAIR ? "hide" : "show"] hair.") + ..() + +/obj/item/clothing/head/det/grey + icon_state = "detective2" + desc = "A grey fedora - either the cornerstone of a detective's style or a poor attempt at looking cool, depending on the person wearing it." + + +/* + * Head of Security + */ +/obj/item/clothing/under/rank/head_of_security + desc = "It's a jumpsuit worn by those few with the dedication to achieve the position of \"Head of Security\". It has additional armor to protect the wearer." + name = "head of security's jumpsuit" + icon_state = "hos" + item_state = "r_suit" + worn_state = "hosred" + armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 0.8 + +/obj/item/clothing/under/rank/head_of_security/corp + icon_state = "hos_corporate" + //item_state = "hos_corporate" + worn_state = "hos_corporate" + +/obj/item/clothing/head/HoS + name = "Head of Security Hat" + desc = "The hat of the Head of Security. For showing the officers who's in charge." + icon_state = "hoscap" + body_parts_covered = 0 + siemens_coefficient = 0.8 + +/obj/item/clothing/head/HoS/dermal + name = "Dermal Armour Patch" + desc = "You're not quite sure how you manage to take it on and off, but it implants nicely in your head." + icon_state = "dermal" + armor = list(melee = 50, bullet = 50, laser = 50,energy = 25, bomb = 30, bio = 0, rad = 0) + siemens_coefficient = 0.6 + +/obj/item/clothing/suit/armor/hos + name = "armored coat" + desc = "A greatcoat enhanced with a special alloy for some protection and style." + icon_state = "hos" + item_state = "hos" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS|LEGS + armor = list(melee = 65, bullet = 30, laser = 50, energy = 10, bomb = 25, bio = 0, rad = 0) + flags_inv = HIDEJUMPSUIT + siemens_coefficient = 0.6 + +//Jensen cosplay gear +/obj/item/clothing/under/rank/head_of_security/jensen + desc = "You never asked for anything that stylish." + name = "head of security's jumpsuit" + icon_state = "jensen" + item_state = "jensen" + worn_state = "jensen" + siemens_coefficient = 0.6 + +/obj/item/clothing/suit/armor/hos/jensen + name = "armored trenchcoat" + desc = "A trenchcoat augmented with a special alloy for some protection and style." + icon_state = "hostrench" + item_state = "hostrench" + flags_inv = 0 + siemens_coefficient = 0.6 + +/* + * Navy uniforms + */ + +/obj/item/clothing/under/rank/security/navyblue + name = "security officer's uniform" + desc = "The latest in fashionable security outfits." + icon_state = "officerblueclothes" + item_state = "ba_suit" + worn_state = "officerblueclothes" + +/obj/item/clothing/under/rank/head_of_security/navyblue + desc = "The insignia on this uniform tells you that this uniform belongs to the Head of Security." + name = "head of security's uniform" + icon_state = "hosblueclothes" + item_state = "ba_suit" + worn_state = "hosblueclothes" + +/obj/item/clothing/under/rank/warden/navyblue + desc = "The insignia on this uniform tells you that this uniform belongs to the Warden." + name = "warden's uniform" + icon_state = "wardenblueclothes" + item_state = "ba_suit" + worn_state = "wardenblueclothes" + +/obj/item/clothing/under/security_uniform_barny + name = "Casual Security Uniform" + icon_state = "barnyuni" + item_state = "ba_suit" + worn_state = "barny" diff --git a/code/modules/clothing/under/mirania.dm b/code/modules/clothing/under/mirania.dm new file mode 100644 index 00000000..c59fda30 --- /dev/null +++ b/code/modules/clothing/under/mirania.dm @@ -0,0 +1,39 @@ +/obj/item/clothing/under/utility/mirania + name = "bundeforz utility uniform" + desc = "A set of light double breasted fatigues in a light grey urban camoflage with a red stand collar. The utility uniform of Mirania's defence forces." + icon_state = "m_utility" + item_state = "bl_suit" + worn_state = "m_utility" + +/obj/item/clothing/under/utility/mirania/intelligence + name = "intelligence service utility uniform" + desc = "A set of light double breasted fatigues in a light grey urban camoflage with a black stand collar. The utility uniform of Mirania's Truth Ministry." + icon_state = "m_utility" + worn_state = "m_utility_int" + +/obj/item/clothing/under/service/mirania + name = "bundeforz service uniform" + desc = "A pair of light grey pants and a button up shirt with a red stand collar. The service uniform of Mirania's defence forces." + icon_state = "m_service" + worn_state = "m_service" + starting_accessories = list(/obj/item/clothing/accessory/navy) + +/obj/item/clothing/under/service/mirania/intelligence + name = "intelligence service uniform" + desc = "A pair of light grey pants and a button up shirt with a black stand collar. The service uniform of Mirania's Truth Ministry." + icon_state = "m_service" + worn_state = "m_service_int" + starting_accessories = list(/obj/item/clothing/accessory/black) + +/obj/item/clothing/under/mildress/mirania + name = "bundeforz dress uniform" + desc = "A pair of black pants and a white shirt with a red stand collar. The dress uniform of Mirania's defence forces." + icon_state = "m_dress" + worn_state = "m_dress" + starting_accessories = list(/obj/item/clothing/accessory/black) + +/obj/item/clothing/under/mildress/mirania/intelligence + name = "intelligence service dress uniform" + desc = "A pair of black pants and a white shirt with a black stand collar. The dress uniform of Mirania's Truth Ministry." + icon_state = "m_dress" + worn_state = "m_dress_int" \ No newline at end of file diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm new file mode 100644 index 00000000..19d11010 --- /dev/null +++ b/code/modules/clothing/under/miscellaneous.dm @@ -0,0 +1,690 @@ +/obj/item/clothing/under/pj/red + name = "red pj's" + desc = "Sleepwear." + icon_state = "red_pyjamas" + worn_state = "red_pyjamas" + item_state = "w_suit" + +/obj/item/clothing/under/pj/blue + name = "blue pj's" + desc = "Sleepwear." + icon_state = "blue_pyjamas" + worn_state = "blue_pyjamas" + item_state = "w_suit" + +/obj/item/clothing/under/captain_fly + name = "rogue's uniform" + desc = "For the man who doesn't care because he's still free." + icon_state = "captain_fly" + item_state = "r_suit" + worn_state = "captain_fly" + +/obj/item/clothing/under/scratch + name = "white suit" + desc = "A white suit, suitable for an excellent host." + icon_state = "scratch" + item_state = "scratch" + worn_state = "scratch" + +/obj/item/clothing/under/sl_suit + desc = "It's a very amish looking suit." + name = "amish suit" + icon_state = "sl_suit" + worn_state = "sl_suit" + item_state = "sl_suit" + +/obj/item/clothing/under/waiter + name = "waiter's outfit" + desc = "It's a very smart uniform with a special pocket for tip." + icon_state = "waiter" + item_state = "waiter" + worn_state = "waiter" + +/obj/item/clothing/under/rank/mailman + name = "mailman's jumpsuit" + desc = "'Special delivery!'" + icon_state = "mailman" + item_state = "b_suit" + worn_state = "mailman" + +/obj/item/clothing/under/sexyclown + name = "sexy-clown suit" + desc = "It makes you look HONKable!" + icon_state = "sexyclown" + item_state = "clown" + worn_state = "sexyclown" + body_parts_covered = UPPER_TORSO|LOWER_TORSO + +/obj/item/clothing/under/rank/vice + name = "vice officer's jumpsuit" + desc = "It's the standard issue pretty-boy outfit, as seen on Holo-Vision." + icon_state = "vice" + item_state = "gy_suit" + worn_state = "vice" + +//This set of uniforms looks fairly fancy and is generally used for high-ranking NT personnel from what I've seen, so lets give them appropriate ranks. +/obj/item/clothing/under/rank/centcom + desc = "Gold trim on space-black cloth, this uniform displays the rank of \"Captain.\"." + name = "\improper Officer's Dress Uniform" + icon_state = "officer" + item_state = "lawyer_black" + worn_state = "officer" + displays_id = 0 + +/obj/item/clothing/under/rank/centcom_officer + desc = "Gold trim on space-black cloth, this uniform displays the rank of \"Admiral.\"." + name = "\improper Officer's Dress Uniform" + icon_state = "officer" + item_state = "lawyer_black" + worn_state = "officer" + displays_id = 0 + +/obj/item/clothing/under/rank/centcom_captain + desc = "Gold trim on space-black cloth, this uniform displays the rank of \"Admiral-Executive.\"." + name = "\improper Officer's Dress Uniform" + icon_state = "centcom" + item_state = "lawyer_black" + worn_state = "centcom" + displays_id = 0 + +/obj/item/clothing/under/ert + name = "ERT tactical uniform" + desc = "A short-sleeved black uniform, paired with grey digital-camo cargo pants. It looks very tactical." + icon_state = "ert_uniform" + item_state = "bl_suit" + worn_state = "ert_uniform" + armor = list(melee = 10, bullet = 5, laser = 5,energy = 0, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 0.9 + +/obj/item/clothing/under/space + name = "\improper NASA jumpsuit" + desc = "It has a NASA logo on it and is made of space-proofed materials." + icon_state = "black" + item_state = "bl_suit" + worn_state = "black" + w_class = ITEM_SIZE_HUGE//bulky item + gas_transfer_coefficient = 0.01 + permeability_coefficient = 0.02 + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | ARMS //Needs gloves and shoes with cold protection to be fully protected. + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + +/obj/item/clothing/under/acj + name = "administrative cybernetic jumpsuit" + icon_state = "syndicate" + item_state = "bl_suit" + worn_state = "syndicate" + desc = "it's a cybernetically enhanced jumpsuit used for administrative duties." + gas_transfer_coefficient = 0.01 + permeability_coefficient = 0.01 + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + armor = list(melee = 100, bullet = 100, laser = 100,energy = 100, bomb = 100, bio = 100, rad = 100) + cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + siemens_coefficient = 0 + +/obj/item/clothing/under/owl + name = "owl uniform" + desc = "A jumpsuit with owl wings. Photorealistic owl feathers! Twooooo!" + icon_state = "owl" + worn_state = "owl" + item_state = "owl" + +/obj/item/clothing/under/johnny + name = "johnny~~ jumpsuit" + desc = "Johnny~~" + icon_state = "johnny" + worn_state = "johnny" + item_state = "johnny" + +/obj/item/clothing/under/color/rainbow + name = "rainbow" + icon_state = "rainbow" + item_state = "rainbow" + worn_state = "rainbow" + +/obj/item/clothing/under/cloud + name = "cloud" + icon_state = "cloud" + worn_state = "cloud" + +/obj/item/clothing/under/psysuit + name = "dark undersuit" + desc = "A thick, layered grey undersuit lined with power cables. Feels a little like wearing an electrical storm." + icon_state = "psysuit" + item_state = "bl_suit" + worn_state = "psysuit" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + +/obj/item/clothing/under/gentlesuit + name = "gentlemans suit" + desc = "A silk black shirt with a white tie and a matching gray vest and slacks. Feels proper." + icon_state = "gentlesuit" + item_state = "gy_suit" + worn_state = "gentlesuit" + +/obj/item/clothing/under/gimmick/rank/captain/suit + name = "captain's suit" + desc = "A green suit and yellow necktie. Exemplifies authority." + icon_state = "green_suit" + item_state = "dg_suit" + worn_state = "green_suit" + +/obj/item/clothing/under/gimmick/rank/head_of_personnel/suit + name = "head of personnel's suit" + desc = "A teal suit and yellow necktie. An authoritative yet tacky ensemble." + icon_state = "teal_suit" + item_state = "g_suit" + worn_state = "teal_suit" + +/obj/item/clothing/under/suit_jacket + name = "black suit" + desc = "A black suit and red tie. Very formal." + icon_state = "black_suit" + item_state = "bl_suit" + worn_state = "black_suit" + +/obj/item/clothing/under/suit_jacket/really_black + name = "executive suit" + desc = "A formal black suit and red tie, intended for the galaxy's finest." + icon_state = "really_black_suit" + item_state = "jensensuit" + worn_state = "black_suit" + +/obj/item/clothing/under/suit_jacket/female + name = "executive suit" + desc = "A formal trouser suit for women, intended for the galaxy's finest." + icon_state = "black_suit_fem" + item_state = "lawyer_black" + worn_state = "black_suit_fem" + +/obj/item/clothing/under/suit_jacket/red + name = "red suit" + desc = "A red suit and blue tie. Somewhat formal." + icon_state = "red_suit" + item_state = "r_suit" + worn_state = "red_suit" + +/obj/item/clothing/under/blackskirt + name = "black skirt" + desc = "A black skirt, very fancy!" + icon_state = "blackskirt" + item_state = "bl_suit" + worn_state = "blackskirt" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + +/obj/item/clothing/under/schoolgirl + name = "schoolgirl uniform" + desc = "It's just like one of my Japanese animes!" + icon_state = "schoolgirl" + item_state = "b_suit" + worn_state = "schoolgirl" + body_parts_covered = UPPER_TORSO|LOWER_TORSO + +/obj/item/clothing/under/overalls + name = "laborer's overalls" + desc = "A set of durable overalls for getting the job done." + icon_state = "overalls" + item_state = "lb_suit" + worn_state = "overalls" + +/obj/item/clothing/under/pirate + name = "pirate outfit" + desc = "Yarr." + icon_state = "pirate" + item_state = "sl_suit" + worn_state = "pirate" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS + +/obj/item/clothing/under/soviet + name = "soviet uniform" + desc = "For the Motherland!" + icon_state = "soviet" + item_state = "gy_suit" + worn_state = "soviet" + +/obj/item/clothing/under/redcoat + name = "redcoat uniform" + desc = "Looks old." + icon_state = "redcoat" + item_state = "r_suit" + worn_state = "redcoat" + +/obj/item/clothing/under/kilt + name = "kilt" + desc = "Includes shoes and plaid." + icon_state = "kilt" + item_state = "kilt" + worn_state = "kilt" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|FEET + +/obj/item/clothing/under/sexymime + name = "sexy mime outfit" + desc = "The only time when you DON'T enjoy looking at someone's rack." + icon_state = "sexymime" + item_state = "w_suit" + worn_state = "sexymime" + body_parts_covered = UPPER_TORSO|LOWER_TORSO + +/obj/item/clothing/under/gladiator + name = "gladiator uniform" + desc = "Are you not entertained? Is that not why you are here?" + icon_state = "gladiator" + item_state = "o_suit" + worn_state = "gladiator" + body_parts_covered = LOWER_TORSO + +//dress +/obj/item/clothing/under/dress + name = "dress" + desc = "A fancy dress." + icon_state = "dress_fire" + worn_state = "dress_fire" + body_parts_covered = UPPER_TORSO|LOWER_TORSO + +/obj/item/clothing/under/dress/dress_fire + name = "flame dress" + desc = "A small black dress with blue flames print on it." + icon_state = "dress_fire" + item_state = "bl_suit" + worn_state = "dress_fire" + +/obj/item/clothing/under/dress/dress_green + name = "green dress" + desc = "A simple, tight fitting green dress." + icon_state = "dress_green" + item_state = "g_suit" + worn_state = "dress_green" + +/obj/item/clothing/under/dress/dress_orange + name = "orange dress" + desc = "A fancy orange gown for those who like to show leg." + icon_state = "dress_orange" + item_state = "y_suit" + worn_state = "dress_orange" + +/obj/item/clothing/under/dress/dress_pink + name = "pink dress" + desc = "A simple, tight fitting pink dress." + icon_state = "dress_pink" + item_state = "p_suit" + worn_state = "dress_pink" + +/obj/item/clothing/under/dress/dress_purple + name = "purple dress" + desc= "A simple, tight fitting purple dress." + icon_state = "tian_dress" + item_state = "p_suit" + worn_state = "tian_dress" + +/obj/item/clothing/under/dress/dress_yellow + name = "yellow dress" + desc = "A flirty, little yellow dress." + icon_state = "dress_yellow" + item_state = "y_suit" + worn_state = "dress_yellow" + +/obj/item/clothing/under/dress/dress_saloon + name = "saloon girl dress" + desc = "A old western inspired gown for the girl who likes to drink." + icon_state = "dress_saloon" + item_state = "p_suit" + worn_state = "dress_saloon" + + +/obj/item/clothing/under/dress/dress_cap + name = "captain's dress uniform" + desc = "Feminine fashion for the style concious captain." + icon_state = "dress_cap" + item_state = "b_suit" + worn_state = "dress_cap" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + +/obj/item/clothing/under/dress/dress_hop + name = "head of personnel dress uniform" + desc = "Feminine fashion for the style concious HoP." + icon_state = "dress_hop" + item_state = "b_suit" + worn_state = "dress_hop" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + +/obj/item/clothing/under/dress/dress_hr + name = "human resources director uniform" + desc = "Superior class for the nosy H.R. Director." + icon_state = "huresource" + item_state = "y_suit" + worn_state = "huresource" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + +/obj/item/clothing/under/dress/plaid_blue + name = "blue plaid skirt" + desc = "A preppy blue skirt with a white blouse." + icon_state = "plaid_blue" + worn_state = "plaid_blue" + +/obj/item/clothing/under/dress/plaid_red + name = "red plaid skirt" + desc = "A preppy red skirt with a white blouse." + icon_state = "plaid_red" + item_state = "kilt" + worn_state = "plaid_red" + +/obj/item/clothing/under/dress/plaid_purple + name = "blue purple skirt" + desc = "A preppy purple skirt with a white blouse." + icon_state = "plaid_purple" + item_state = "kilt" + worn_state = "plaid_purple" + +//wedding stuff +/obj/item/clothing/under/wedding/ + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS + +/obj/item/clothing/under/wedding/bride_orange + name = "orange wedding dress" + desc = "A big and puffy orange dress." + icon_state = "bride_orange" + item_state = "y_suit" + worn_state = "bride_orange" + flags_inv = HIDESHOES + +/obj/item/clothing/under/wedding/bride_purple + name = "purple wedding dress" + desc = "A big and puffy purple dress." + icon_state = "bride_purple" + item_state = "p_suit" + worn_state = "bride_purple" + flags_inv = HIDESHOES + +/obj/item/clothing/under/wedding/bride_blue + name = "blue wedding dress" + desc = "A big and puffy blue dress." + icon_state = "bride_blue" + item_state = "b_suit" + worn_state = "bride_blue" + flags_inv = HIDESHOES + +/obj/item/clothing/under/wedding/bride_red + name = "red wedding dress" + desc = "A big and puffy red dress." + icon_state = "bride_red" + item_state = "r_suit" + worn_state = "bride_red" + flags_inv = HIDESHOES + +/obj/item/clothing/under/wedding/bride_white + name = "silky wedding dress" + desc = "A white wedding gown made from the finest silk." + icon_state = "bride_white" + item_state = "nursesuit" + worn_state = "bride_white" + flags_inv = HIDESHOES + body_parts_covered = UPPER_TORSO|LOWER_TORSO + +/obj/item/clothing/under/sundress + name = "sundress" + desc = "Makes you want to frolic in a field of daisies." + icon_state = "sundress" + item_state = "bl_suit" + worn_state = "sundress" + body_parts_covered = UPPER_TORSO|LOWER_TORSO + +/obj/item/clothing/under/sundress_white + name = "white sundress" + desc = "A white sundress decorated with purple lilies." + icon_state = "sundress_white" + item_state = "sundress_white" + worn_state = "sundress_white" + body_parts_covered = UPPER_TORSO|LOWER_TORSO + +/obj/item/clothing/under/blackjumpskirt + name = "black jumpskirt" + desc = "A black jumpskirt, with a pink undershirt." + icon_state = "blackjumpskirt" + item_state = "bl_suit" + worn_state = "blackjumpskirt" + +/obj/item/clothing/under/shortjumpskirt + name = "short jumpskirt" + desc = "A slimming, short jumpskirt." + icon_state = "shortjumpskirt" + item_state = "w_suit" + worn_state = "shortjumpskirt" + +/obj/item/clothing/under/captainformal + name = "captain's formal uniform" + desc = "A captain's formal-wear, for special occasions." + icon_state = "captain_formal" + item_state = "b_suit" + worn_state = "captain_formal" + +/obj/item/clothing/under/hosformalmale + name = "head of security's formal uniform" + desc = "A male head of security's formal-wear, for special occasions." + icon_state = "hos_formal_male" + item_state = "r_suit" + worn_state = "hos_formal_male" + +/obj/item/clothing/under/hosformalfem + name = "head of security's formal uniform" + desc = "A female head of security's formal-wear, for special occasions." + icon_state = "hos_formal_fem" + item_state = "r_suit" + worn_state = "hos_formal_fem" + +/obj/item/clothing/under/assistantformal + name = "assistant's formal uniform" + desc = "An assistant's formal-wear. Why an assistant needs formal-wear is still unknown." + icon_state = "assistant_formal" + item_state = "gy_suit" + worn_state = "assistant_formal" + +/obj/item/clothing/under/suit_jacket/charcoal + name = "charcoal suit" + desc = "A charcoal suit and red tie. Very professional." + icon_state = "charcoal_suit" + item_state = "bl_suit" + worn_state = "charcoal_suit" + starting_accessories = list(/obj/item/clothing/accessory/navy, /obj/item/clothing/accessory/toggleable/charcoal_jacket) + +/obj/item/clothing/under/suit_jacket/navy + name = "navy suit" + desc = "A navy suit and red tie, intended for the galaxy's finest." + icon_state = "navy_suit" + item_state = "bl_suit" + worn_state = "navy_suit" + starting_accessories = list(/obj/item/clothing/accessory/red, /obj/item/clothing/accessory/toggleable/navy_jacket) + +/obj/item/clothing/under/suit_jacket/burgundy + name = "burgundy suit" + desc = "A burgundy suit and black tie. Somewhat formal." + icon_state = "burgundy_suit" + item_state = "r_suit" + worn_state = "burgundy_suit" + starting_accessories = list(/obj/item/clothing/accessory/black, /obj/item/clothing/accessory/toggleable/burgundy_jacket) + +/obj/item/clothing/under/suit_jacket/checkered + name = "checkered suit" + desc = "That's a very nice suit you have there. Shame if something were to happen to it, eh?" + icon_state = "checkered_suit" + item_state = "gy_suit" + worn_state = "checkered_suit" + starting_accessories = list(/obj/item/clothing/accessory/black, /obj/item/clothing/accessory/toggleable/checkered_jacket) + +/obj/item/clothing/under/suit_jacket/tan + name = "tan suit" + desc = "A tan suit. Smart, but casual." + icon_state = "tan_suit" + item_state = "lb_suit" + worn_state = "tan_suit" + starting_accessories = list(/obj/item/clothing/accessory/yellow, /obj/item/clothing/accessory/toggleable/tan_jacket) + +/obj/item/clothing/under/serviceoveralls + name = "workman outfit" + desc = "The very image of a working man. Not that you're probably doing work." + icon_state = "mechanic" + item_state = "lb_suit" + worn_state = "mechanic" + +/obj/item/clothing/under/cheongsam + name = "cheongsam" + desc = "It is a cheongsam dress." + icon_state = "mai_yang" + item_state = "mai_yang" + worn_state = "mai_yang" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS + +/obj/item/clothing/under/abaya + name = "abaya" + desc = "A loose-fitting, robe-like dress." + icon_state = "abaya" + item_state = "abaya" + worn_state = "abaya" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + +/obj/item/clothing/under/blazer + name = "blue blazer" + desc = "A bold but yet conservative outfit, red corduroys, navy blazer and a tie." + icon_state = "blue_blazer" + item_state = "blue_blazer" + worn_state = "blue_blazer" + +/obj/item/clothing/under/harness + name = "gear harness" + desc = "How... minimalist." + icon_state = "gear_harness" + worn_state = "gear_harness" + species_restricted = null + body_parts_covered = 0 + +/obj/item/clothing/under/pcrc + name = "\improper PCRC uniform" + desc = "A uniform belonging to Proxima Centauri Risk Control, a private security firm." + icon_state = "pcrc" + item_state = "jensensuit" + worn_state = "pcrc" + +/obj/item/clothing/under/grayson + name = "\improper Grayson overalls" + desc = "A set of overalls belonging to Grayson Manufactories, a mining Trans-Stellar." + icon_state = "grayson" + worn_state = "grayson" + +/obj/item/clothing/under/wardt + name = "\improper Ward-Takahashi jumpsuit" + desc = "A jumpsuit belonging to Ward-Takahashi, a Trans-Stellar in the consumer goods market." + icon_state = "wardt" + worn_state = "wardt" + +/obj/item/clothing/under/mbill + name = "\improper Major Bill's uniform" + desc = "A uniform belonging to Major Bill's Transportation, a shipping megacorporation." + icon_state = "mbill" + worn_state = "mbill" + +// Replace this with actual uniform when someone wants to sprite one +/obj/item/clothing/under/confederacy + name = "\improper Confederate uniform" + desc = "A military uniform belonging to the Terran Colonial Confederation, an independent human government." + icon_state = "confed" + worn_state = "confed" + +/obj/item/clothing/under/saare + name = "\improper SAARE uniform" + desc = "A uniform belonging to Strategic Assault and Asset Retention Enterprises, a minor private military corporation." + icon_state = "saare" + worn_state = "saare" + +/obj/item/clothing/under/frontier + name = "frontier clothes" + desc = "A rugged flannel shirt and denim overalls. A popular style among frontier colonists." + icon_state = "frontier" + worn_state = "frontier" + +/obj/item/clothing/under/aether + name = "\improper Aether jumpsuit" + desc = "A jumpsuit belonging to Aether Atmospherics and Recycling, a Trans-Stellar that supplies recycling and atmospheric systems to colonies." + icon_state = "aether" + worn_state = "aether" + +/obj/item/clothing/under/focal + name = "\improper Focal Point jumpsuit" + desc = "A jumpsuit belonging to Focal Point Energistics, an engineering megacorporation." + icon_state = "focal" + worn_state = "focal" + +/obj/item/clothing/under/hephaestus + name = "\improper Hephaestus jumpsuit" + desc = "A jumpsuit belonging to Hephaestus Industries, a Trans-Stellar best known for its arms production." + icon_state = "heph" + worn_state = "heph" + +/obj/item/clothing/under/punpun + name = "fancy uniform" + desc = "It looks like it was tailored for a monkey." + icon_state = "punpun" + worn_state = "punpun" + species_restricted = list("Monkey") + sprite_sheets = list("Monkey" = 'icons/mob/species/monkey/uniform.dmi') + +/obj/item/clothing/under/punpants + name = "monkey pants" + desc = "It looks like it was tailored for a monkey." + icon_state = "jeansmustang" + worn_state = "jeansmustang" + species_restricted = list("Monkey") + sprite_sheets = list("Monkey" = 'icons/mob/species/monkey/uniform.dmi') + +/obj/item/clothing/under/rank/psych/turtleneck/sweater + desc = "A warm looking sweater and a pair of dark blue slacks." + name = "sweater" + icon_state = "turtleneck" + worn_state = "turtleneck" + +/obj/item/clothing/under/savage_hunter + name = "savage hunter's hides" + desc = "Makeshift hides bound together with the sinew, packwax, and leather of some alien creature." + icon_state = "hunterhide" + item_state = "hunter" + worn_state = "hunter" + body_parts_covered = LOWER_TORSO|LEGS|ARMS + +/obj/item/clothing/under/savage_hunter/female + name = "savage huntress's hides" + desc = "Makeshift hides bound together with the sinew, packwax, and leather of some alien creature. Includes a chestwrap so as not to leave one topless." + worn_state = "huntress" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + +/obj/item/clothing/under/wetsuit + name = "tactical wetsuit" + desc = "For when you want to scuba dive your way into an enemy base but still want to show off a little skin." + icon_state = "wetsuit" + item_state = "wetsuit" + worn_state = "wetsuit" + body_parts_covered = UPPER_TORSO|LOWER_TORSO + +/obj/item/clothing/under/hazard + name = "hazard jumpsuit" + desc = "A high visibility jumpsuit made from heat and radiation resistant materials." + icon_state = "hazard" + item_state = "engi_suit" + worn_state = "hazard" + siemens_coefficient = 0.8 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 20, bio = 0, rad = 20) + max_heat_protection_temperature = FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE + +/obj/item/clothing/under/sterile + name = "sterile jumpsuit" + desc = "A sterile white jumpsuit with medical markings. Protects against all manner of biohazards." + icon_state = "sterile" + item_state = "w_suit" + worn_state = "sterile" + permeability_coefficient = 0.50 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 30, rad = 0) + +/obj/item/clothing/under/inquisitor + name = "inquisitor's suit" + desc = "Heretics beware." + icon_state = "uni-church" + item_state = "uni-church" + //_color = "uni-church" \ No newline at end of file diff --git a/code/modules/clothing/under/nanotrasen.dm b/code/modules/clothing/under/nanotrasen.dm new file mode 100644 index 00000000..452d8100 --- /dev/null +++ b/code/modules/clothing/under/nanotrasen.dm @@ -0,0 +1,56 @@ +//TORCH NanoTrasen Uniforms - DO NOT ADD NEW UNIFORMS TO UNIFORM.DMI - TORCH NANOTRASEN UNIFORMS GO IN NANOTRASEN.DMI + +/obj/item/clothing/under/rank/guard + desc = "A durable uniform worn by NanoTrasen corporate security." + name = "\improper NanoTrasen security uniform" + icon_state = "ntguard" + item_state = "r_suit" + worn_state = "ntguard" + armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 0.9 + item_icons = list(slot_w_uniform_str = 'icons/mob/onmob/nanotrasen.dmi') + + +/obj/item/clothing/under/rank/scientist + name = "\improper NanoTrasen polo and pants" + desc = "A fashionable polo and pair of trousers made from patented biohazard-resistant synthetic fabrics. The colors denote the wearer as a member of NanoTrasen." + icon_state = "ntsmock" + item_state = "w_suit" + worn_state = "ntsmock" + permeability_coefficient = 0.50 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 10, bio = 0, rad = 0) + item_icons = list(slot_w_uniform_str = 'icons/mob/onmob/nanotrasen.dmi') + starting_accessories = list(/obj/item/clothing/accessory/nt_tunic) + +/obj/item/clothing/under/rank/scientist/executive + name = "\improper NanoTrasen executive polo and pants" + desc = "A fashionable polo and pair of trousers made from expensive biohazard-resistant fabrics. The colors denote the wearer as a member of NanoTrasen's higher-ups." + icon_state = "ntsmockexec" + worn_state = "ntsmockexec" + starting_accessories = list(/obj/item/clothing/accessory/nt_tunic/exec) + +/obj/item/clothing/under/rank/ntwork + name = "\improper NanoTrasen coveralls" + desc = "A pair of beige coveralls made out of a strong, canvas-like material. The coloring on the fringes denotes it as a NanoTrasen-branded suit, typically given to their more blue-collared employees." + icon_state = "ntwork" + item_state = "lb_suit" + worn_state = "ntwork" + armor = list(melee = 5, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 5, rad = 0) + item_icons = list(slot_w_uniform_str = 'icons/mob/onmob/nanotrasen.dmi') + +/obj/item/clothing/under/rank/ntpilot + name = "\improper NanoTrasen flightsuit" + desc = "A sleek dark red NanoTrasen flightsuit. It proudly sports three different patches with the NanoTrasen logo on it, as well as several unnecessary looking flaps and pockets for effect." + icon_state = "ntpilot" + item_state = "r_suit" + worn_state = "ntpilot" + item_icons = list(slot_w_uniform_str = 'icons/mob/onmob/nanotrasen.dmi') + +/obj/item/clothing/under/suit_jacket/nt + name = "\improper NanoTrasen executive suit" + desc = "A suit that NanoTrasen gives to its executives." + icon_state = "ntsuit" + item_state = "bl_suit" + worn_state = "ntsuit" + item_icons = list(slot_w_uniform_str = 'icons/mob/onmob/nanotrasen.dmi') + starting_accessories = list(/obj/item/clothing/accessory/toggleable/nanotrasen_jacket, /obj/item/clothing/accessory/nt) diff --git a/code/modules/clothing/under/shorts.dm b/code/modules/clothing/under/shorts.dm new file mode 100644 index 00000000..c7edf883 --- /dev/null +++ b/code/modules/clothing/under/shorts.dm @@ -0,0 +1,101 @@ +//Shorts - new shorts of this type go in pants.dmi + +/obj/item/clothing/under/shorts + name = "athletic shorts" + icon_state = "shorts" + desc = "95% Polyester, 5% Spandex!" + gender = PLURAL + body_parts_covered = LOWER_TORSO + item_icons = list(slot_w_uniform_str = 'icons/mob/onmob/pants.dmi') + +/obj/item/clothing/under/shorts/red + name = "red athletic shorts" + color = "#a81818" + +/obj/item/clothing/under/shorts/green + name = "green athletic shorts" + color = "#3c1818" + +/obj/item/clothing/under/shorts/blue + name = "blue athletic shorts" + color = "#183ca8" + +/obj/item/clothing/under/shorts/black + name = "black athletic shorts" + color = "#262626" + +/obj/item/clothing/under/shorts/grey + name = "grey athletic shorts" + color = "#b2b2b2" + +/obj/item/clothing/under/shorts/jeans + name = "jeans shorts" + desc = "Some jeans! Just in short form!" + icon_state = "jeans_shorts" + worn_state = "jeans_shorts" + +/obj/item/clothing/under/shorts/jeans/female + name = "jeans short shorts" + icon_state = "jeans_shorts_f" + worn_state = "jeans_shorts_f" + +/obj/item/clothing/under/shorts/jeans/classic + name = "classic jeans shorts" + icon_state = "jeansclassic_shorts" + worn_state = "jeansclassic_shorts" + +/obj/item/clothing/under/shorts/jeans/classic/female + name = "classic jeans short shorts" + icon_state = "jeansclassic_shorts_f" + worn_state = "jeansclassic_shorts_f" + +/obj/item/clothing/under/shorts/jeans/mustang + name = "mustang jeans shorts" + icon_state = "jeansmustang_shorts" + worn_state = "jeansmustang_shorts" + +/obj/item/clothing/under/shorts/jeans/mustang/female + name = "mustang jeans short shorts" + icon_state = "jeansmustang_shorts_f" + worn_state = "jeansmustang_shorts_f" + +/obj/item/clothing/under/shorts/jeans/youngfolks + name = "young folks jeans shorts" + icon_state = "jeansyoungfolks_shorts" + worn_state = "jeansyoungfolks_shorts" + +/obj/item/clothing/under/shorts/jeans/youngfolks/female + name = "young folks jeans short shorts" + icon_state = "jeansyoungfolks_shorts_f" + worn_state = "jeansyoungfolks_shorts_f" + +/obj/item/clothing/under/shorts/jeans/black + name = "black jeans shorts" + icon_state = "blackpants_shorts" + worn_state = "blackpants_shorts" + +/obj/item/clothing/under/shorts/jeans/black/female + name = "black jeans short shorts" + icon_state = "black_shorts_f" + worn_state = "black_shorts_f" + +/obj/item/clothing/under/shorts/jeans/grey + name = "grey jeans shorts" + icon_state = "greypants_shorts" + worn_state = "greypants_shorts" + +/obj/item/clothing/under/shorts/jeans/grey/female + name = "grey jeans short shorts" + icon_state = "grey_shorts_f" + worn_state = "grey_shorts_f" + +/obj/item/clothing/under/shorts/khaki + name = "khaki shorts" + desc = "For that island getaway. It's five o'clock somewhere, right?" + icon_state = "tanpants_shorts" + worn_state = "tanpants_shorts" + +/obj/item/clothing/under/shorts/khaki/female + name = "khaki short shorts" + icon_state = "khaki_shorts_f" + worn_state = "khaki_shorts_f" \ No newline at end of file diff --git a/code/modules/clothing/under/skirts.dm b/code/modules/clothing/under/skirts.dm new file mode 100644 index 00000000..780aa61a --- /dev/null +++ b/code/modules/clothing/under/skirts.dm @@ -0,0 +1,99 @@ +/obj/item/clothing/under/skirt + name = "black skirt" + desc = "A black skirt, very fancy!" + icon_state = "blackskirt" + item_state = "bl_suit" + worn_state = "blackskirt" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + rolled_sleeves = -1 + +/obj/item/clothing/under/skirt/plaid_blue + name = "blue plaid skirt" + desc = "A preppy blue skirt with a white blouse." + icon_state = "plaid_blue" + worn_state = "plaid_blue" + +/obj/item/clothing/under/skirt/plaid_red + name = "red plaid skirt" + desc = "A preppy red skirt with a white blouse." + icon_state = "plaid_red" + item_state = "kilt" + worn_state = "plaid_red" + +/obj/item/clothing/under/skirt/plaid_purple + name = "blue purple skirt" + desc = "A preppy purple skirt with a white blouse." + icon_state = "plaid_purple" + item_state = "kilt" + worn_state = "plaid_purple" + +// discreet skirts, dont cover upper/arms etc +/obj/item/clothing/under/skirt/khaki + name = "khaki skirt" + desc = "A khaki skirt with a flare at the hem." + icon_state = "skirt_khaki" + worn_state = "skirt_khaki" + body_parts_covered = LOWER_TORSO + +/obj/item/clothing/under/skirt/swept + name = "swept skirt" + desc = "A skirt that is swept to one side." + icon_state = "skirt_swept" + worn_state = "skirt_swept" + body_parts_covered = LOWER_TORSO + +// colour selection, needs to be different for loadout type selection + +/obj/item/clothing/under/skirt_c + name = "short skirt" + desc = "A short skirt, made of some semi-gloss material." + icon_state = "skirt_short" + worn_state = "skirt_short" + body_parts_covered = LOWER_TORSO + +// dresses +/obj/item/clothing/under/skirt_c/dress + name = "short dress" + desc = "A short plain sleeveless dress." + icon_state = "shortdress" + worn_state = "shortdress" + body_parts_covered = UPPER_TORSO|LOWER_TORSO + +/obj/item/clothing/under/skirt_c/dress/long + name = "maxi dress" + desc = "A sleeveless dress that reaches the wearer's ankles." + icon_state = "longdress" + worn_state = "longdress" + flags_inv = HIDESHOES + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET + +/obj/item/clothing/under/skirt_c/dress/long/gown + name = "silk gown" + desc = "A long silky sleeveless gown with a flared hem." + icon_state = "gowndress" + worn_state = "gowndress" + +// some preset dresses for uniform vendors +/obj/item/clothing/under/skirt_c/dress/black + name = "black short dress" + color = "#181818" + +/obj/item/clothing/under/skirt_c/dress/long/black + name = "black maxi dress" + color = "#181818" + +/obj/item/clothing/under/skirt_c/dress/eggshell + name = "eggshell short dress" + color = "#f0ead6" + +/obj/item/clothing/under/skirt_c/dress/long/eggshell + name = "eggshell maxi dress" + color = "#f0ead6" + +/obj/item/clothing/under/skirt_c/dress/mintcream + name = "mint short dress" + color = "#dcffed" + +/obj/item/clothing/under/skirt_c/dress/long/mintcream + name = "mint maxi dress" + color = "#dcffed" \ No newline at end of file diff --git a/code/modules/clothing/under/syndicate.dm b/code/modules/clothing/under/syndicate.dm new file mode 100644 index 00000000..638ef185 --- /dev/null +++ b/code/modules/clothing/under/syndicate.dm @@ -0,0 +1,29 @@ +/obj/item/clothing/under/syndicate + name = "tactical turtleneck" + desc = "It's some non-descript, slightly suspicious looking, civilian clothing." + icon_state = "syndicate" + item_state = "bl_suit" + worn_state = "syndicate" + has_sensor = 0 + armor = list(melee = 10, bullet = 10, laser = 10,energy = 0, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 0.9 + +/obj/item/clothing/under/syndicate/combat + name = "combat turtleneck" + desc = "The height of fashion and tactical utility." + icon_state = "combat" + item_state = "bl_suit" + worn_state = "combat" + has_sensor = SUIT_HAS_SENSORS + +/obj/item/clothing/under/syndicate/tacticool + name = "\improper Tacticool turtleneck" + desc = "Just looking at it makes you want to buy an SKS, go into the woods, and -operate-." + icon_state = "tactifool" + item_state = "bl_suit" + worn_state = "tactifool" + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + siemens_coefficient = 1 + has_sensor = SUIT_HAS_SENSORS + + diff --git a/code/modules/clothing/under/xenos/bogani.dm b/code/modules/clothing/under/xenos/bogani.dm new file mode 100644 index 00000000..83ad7634 --- /dev/null +++ b/code/modules/clothing/under/xenos/bogani.dm @@ -0,0 +1,19 @@ +/obj/item/clothing/under/bogani + name = "alien tunic" + desc = "It looks fitted to nonhuman proportions." + icon = 'icons/obj/clothing/species/bogani/uniform.dmi' + icon_state = "bogtunic" + worn_state = "bogtunic" + species_restricted = list(SPECIES_BOGANI) + +/obj/item/clothing/under/bogani/half + name = "alien half tunic" + desc = "It looks fitted to nonhuman proportions." + icon_state = "boghalftunic" + worn_state = "boghalftunic" + +/obj/item/clothing/under/bogani/high + name = "alien fancy tunic" + desc = "It looks fitted to nonhuman proportions." + icon_state = "boghightunic" + worn_state = "boghightunic" diff --git a/code/modules/clothing/underwear/base.dm b/code/modules/clothing/underwear/base.dm new file mode 100644 index 00000000..36b9c79d --- /dev/null +++ b/code/modules/clothing/underwear/base.dm @@ -0,0 +1,120 @@ +/obj/item/underwear + w_class = ITEM_SIZE_TINY + var/required_slot_flags + var/required_free_body_parts + +/obj/item/underwear/afterattack(var/atom/target, var/mob/user, var/proximity) + if(!proximity) + return // Might as well check + DelayedEquipUnderwear(user, target) + +/obj/item/underwear/MouseDrop(var/atom/target) + DelayedEquipUnderwear(usr, target) + +/obj/item/underwear/proc/CanEquipUnderwear(var/mob/user, var/mob/living/carbon/human/H) + if(!CanAdjustUnderwear(user, H, "put on")) + return FALSE + if(!(H.species && (H.species.appearance_flags & HAS_UNDERWEAR))) + to_chat(user, "\The [H]'s species cannot wear underwear of this nature.") + return FALSE + if(is_path_in_list(type, H.worn_underwear)) + to_chat(user, "\The [H] is already wearing underwear of this nature.") + return FALSE + return TRUE + +/obj/item/underwear/proc/CanRemoveUnderwear(var/mob/user, var/mob/living/carbon/human/H) + if(!CanAdjustUnderwear(user, H, "remove")) + return FALSE + if(!(src in H.worn_underwear)) + to_chat(user, "\The [H] isn't wearing \the [src].") + return FALSE + return TRUE + +/obj/item/underwear/proc/CanAdjustUnderwear(var/mob/user, var/mob/living/carbon/human/H, var/adjustment_verb) + if(!istype(H)) + return FALSE + if(user != H && !CanPhysicallyInteractWith(user, H)) + return FALSE + + var/list/covering_items = H.get_covering_equipped_items(required_free_body_parts) + if(covering_items.len) + var/obj/item/I = covering_items[1] + var/datum/gender/G = gender_datums[I.gender] + if(adjustment_verb) + to_chat(user, "Cannot [adjustment_verb] \the [src]. [english_list(covering_items)] [covering_items.len == 1 ? G.is : "are"] in the way.") + return FALSE + + return TRUE + +/obj/item/underwear/proc/DelayedRemoveUnderwear(var/mob/user, var/mob/living/carbon/human/H) + if(!CanRemoveUnderwear(user, H)) + return + if(user != H) + visible_message("\The [user] is trying to remove \the [H]'s [name]!") + if(!do_after(user, HUMAN_STRIP_DELAY, H, progress = 0)) + return FALSE + . = RemoveUnderwear(user, H) + if(. && user != H) + user.visible_message("\The [user] has removed \the [src] from \the [H].", "You have removed \the [src] from \the [H].") + admin_attack_log(user, H, "Removed \a [src]", "Had \a [src] removed.", "removed \a [src] from") + +/obj/item/underwear/proc/DelayedEquipUnderwear(var/mob/user, var/mob/living/carbon/human/H) + if(!CanEquipUnderwear(user, H)) + return + if(user != H) + user.visible_message("\The [user] has begun putting on \a [src] on \the [H].", "You begin putting on \the [src] on \the [H].") + if(!do_after(user, HUMAN_STRIP_DELAY, H, progress = FALSE)) + return FALSE + . = EquipUnderwear(user, H) + if(. && user != H) + user.visible_message("\The [user] has put \the [src] on \the [H].", "You have put \the [src] on \the [H].") + admin_attack_log(user, H, "Put on \a [src]", "Had \a [src] put on.", "put on \a [src] on") + +/obj/item/underwear/proc/EquipUnderwear(var/mob/user, var/mob/living/carbon/human/H) + if(!CanEquipUnderwear(user, H)) + return FALSE + if(!user.unEquip(src)) + return FALSE + return ForceEquipUnderwear(H) + +/obj/item/underwear/proc/ForceEquipUnderwear(var/mob/living/carbon/human/H, var/update_icons = TRUE) + // No matter how forceful, we still don't allow multiples of the same underwear type + if(is_path_in_list(type, H.worn_underwear)) + return FALSE + + H.worn_underwear += src + forceMove(H) + if(update_icons) + H.update_underwear() + + return TRUE + +/obj/item/underwear/proc/RemoveUnderwear(var/mob/user, var/mob/living/carbon/human/H) + if(!CanRemoveUnderwear(user, H)) + return FALSE + + H.worn_underwear -= src + dropInto(H.loc) + user.put_in_hands(src) + H.update_underwear() + + return TRUE + +/obj/item/underwear/verb/RemoveSocks() + set name = "Remove Underwear" + set category = "Object" + set src in usr + + RemoveUnderwear(usr, usr) + +/obj/item/underwear/socks + required_free_body_parts = FEET + +/obj/item/underwear/top + required_free_body_parts = UPPER_TORSO + +/obj/item/underwear/bottom + required_free_body_parts = FEET|LEGS|LOWER_TORSO + +/obj/item/underwear/undershirt + required_free_body_parts = UPPER_TORSO diff --git a/code/modules/component/component.dm b/code/modules/component/component.dm new file mode 100644 index 00000000..ec81f9e1 --- /dev/null +++ b/code/modules/component/component.dm @@ -0,0 +1,114 @@ +/datum/component + var/enabled = TRUE + var/dupe_mode = COMPONENT_DUPE_HIGHLANDER + var/list/signal_procs + var/datum/parent + +/datum/component/New(datum/P, ...) + var/dm = dupe_mode + if(dm != COMPONENT_DUPE_ALLOWED) + var/datum/component/old = P.GetExactComponent(type) + if(old) + switch(dm) + if(COMPONENT_DUPE_HIGHLANDER) + InheritComponent(old, FALSE) + qdel(old) + if(COMPONENT_DUPE_UNIQUE) + old.InheritComponent(src, TRUE) + qdel(src) + return + P.SendSignal(COMSIG_COMPONENT_ADDED, src) + LAZYADD(P.datum_components, src) + parent = P + +/datum/component/Destroy() + enabled = FALSE + var/datum/P = parent + if(P) + _RemoveNoSignal() + P.SendSignal(COMSIG_COMPONENT_REMOVING, src) + signal_procs.Cut() + return ..() + +/datum/component/proc/_RemoveNoSignal() + var/datum/P = parent + if(P) + LAZYREMOVE(P.datum_components, src) + parent = null + +/datum/component/proc/RegisterSignal(sig_type, proc_on_self, override = FALSE) + if(!src || src.gc_destroyed) + return + var/list/procs = signal_procs + if(!procs) + procs = list() + signal_procs = procs + + if(!override) + . = procs[sig_type] + spawn(0) + procs[sig_type] = call(src, proc_on_self)() + +/datum/component/proc/ReceiveSignal(sigtype, ...) + var/list/sps = signal_procs + var/list/arguments = args.Copy() + arguments.Cut(1, 2) + return call(src, sps[sigtype])(arglist(arguments)) + +/datum/component/proc/InheritComponent(datum/component/C, i_am_original) + return + +/datum/component/proc/OnTransfer(datum/new_parent) + return + +/datum/var/list/datum_components //list of /datum/component + +/datum/proc/SendSignal(sigtype, ...) + var/list/comps = datum_components + . = FALSE + for(var/I in comps) + var/datum/component/C = I + if(!C.enabled) + continue + if(C.ReceiveSignal(arglist(args))) + ComponentActivated(C) + . = TRUE + +/datum/proc/ComponentActivated(datum/component/C) + return + +/datum/proc/GetComponent(c_type) + for(var/I in datum_components) + if(istype(I, c_type)) + return I + +/datum/proc/GetExactComponent(c_type) + for(var/I in datum_components) + var/datum/component/C = I + if(C.type == c_type) + return I + +/datum/proc/GetComponents(c_type) + . = list() + for(var/I in datum_components) + if(istype(I, c_type)) + . += I + +/datum/proc/AddComponent(new_type, ...) + var/nt = new_type + args[1] = src + var/datum/component/C = new nt(arglist(args)) + return C.gc_destroyed ? GetComponent(new_type) : C + +/datum/proc/TakeComponent(datum/component/C) + if(!C) + return + var/datum/helicopter = C.parent + if(helicopter == src) + //wat //wat + return + C._RemoveNoSignal() + helicopter.SendSignal(COMSIG_COMPONENT_REMOVING, C) + C.OnTransfer(src) + C.parent = src + SendSignal(COMSIG_COMPONENT_ADDED, C) diff --git a/code/modules/crafting/crafting.dm b/code/modules/crafting/crafting.dm new file mode 100644 index 00000000..edd163ca --- /dev/null +++ b/code/modules/crafting/crafting.dm @@ -0,0 +1,124 @@ +/mob/living/carbon/human/verb/craft() + set name = "Craft Items" + set category = "IC" + + if(stat) //zombie goasts pls go + return + + if(!crafting_recipes) + return + + var/dat = "" + var/turf/spot = get_step(src, dir) + if(!spot.Adjacent(src)) + src << "You need more space to work." + return + for(var/name in crafting_recipes) + var/datum/crafting_recipe/R = crafting_recipes[name] + if(R.can_make(src, spot)) + dat += "[R.name] " + dat += "Parts: " + var/list/parts = list() + for(var/T in R.parts) + var/atom/A = T + parts += "[initial(A.name)] x[R.parts[T]]" + dat += english_list(parts) + if(R.tools) + dat+= ". Tools needed: " + var/list/tools = list() + for(var/T in R.tools) + var/atom/A = T + tools += "[initial(A.name)]" + dat += english_list(tools) + dat += ".
            " + if(!dat) + src << "You can't think of anything you can make with what you have in here." + return + var/datum/browser/popup = new(src, "craft", "Craft", 300, 300) + popup.set_content(dat) + popup.open() + +/datum/crafting_recipe + var/name = "" //in-game display name + var/list/parts //type paths of items consumed associated with how many are needed + var/list/tools //type paths of items needed but not consumed + var/list/result //type path of item resulting from this craft + + var/time = 0 //time in 1/10th of second + var/base_chance = 100 //base chance to get it right without skills + +/datum/crafting_recipe/proc/check_parts(var/list/things) + if(!parts) + return 1 + var/list/needs = parts.Copy() + for(var/atom/movable/A in things) + for(var/T in needs) + if(istype(A,T)) + if(istype(A, /obj/item/stack)) + var/obj/item/stack/S = A + needs[T] -= S.amount + else + needs[T] -= 1 + if(needs[T] <= 0) //don't need any more of this type + needs -= T + if(!needs.len) + return 1 + return 0 + +/datum/crafting_recipe/proc/check_tools(var/list/things) + for(var/T in tools) + if(!(locate(T) in things)) + return 0 + return 1 + +/datum/crafting_recipe/proc/use_ingridients(var/list/things) + var/list/needs = parts.Copy() + var/list/to_del = list() + for(var/T in needs) + if(ispath(T, /obj/item/stack)) + for(var/obj/item/stack/S in things) + if(needs[T] >= 0 && istype(S, T)) + if(S.amount >= needs[T]) + S.use(needs[T]) + needs[T] = 0 + else + needs[T] -= S.amount + things -= S + qdel(S) + else + for(var/atom/movable/A in things) + if(needs[T] && istype(A,T)) + needs[T] -= 1 + things -= A + to_del += A + if(needs[T] <= 0) //don't need any more of this type + continue + + for(var/atom/A in to_del) + to_del -= A + qdel(A) + + if(!needs.len) + return 1 + return 0 + +/datum/crafting_recipe/proc/can_make(var/mob/user, var/turf/spot) + var/list/things = spot.contents + user.contents + return check_parts(things) && check_tools(things) + +/datum/crafting_recipe/proc/make(var/mob/user, var/turf/spot) + if(!can_make(user,spot)) + return 0 + user << "You start making \a [name]." + if(do_after(user, time)) + if(!can_make(user,spot)) + user << "You are missing some things to make \a [name]." + return 0 + use_ingridients(spot.contents + user.contents) + if(prob(base_chance)) //Add whatever skill bonuses here + for(var/T in result) + for(var/i = 1 to result[T]) + new T(spot) + user << "You make \a [name]." + else + user << "You've failed to make \a [name]." \ No newline at end of file diff --git a/code/modules/crafting/parts/lathe_items.dm b/code/modules/crafting/parts/lathe_items.dm new file mode 100644 index 00000000..19edf415 --- /dev/null +++ b/code/modules/crafting/parts/lathe_items.dm @@ -0,0 +1,161 @@ +/obj/item/reciever + name = "Reciever" + icon = 'icons/obj/crafting.dmi' + w_class = ITEM_SIZE_NORMAL + desc = "This is a reciever." + icon_state = "reciever" + matter = list(DEFAULT_WALL_MATERIAL = 500) + +/obj/item/action + name = "Action" + icon = 'icons/obj/crafting.dmi' + w_class = ITEM_SIZE_NORMAL + desc = "This is a action." + icon_state = "action" + matter = list(DEFAULT_WALL_MATERIAL = 400) + +/obj/item/metal_bar + name = "Metal Bar" + icon = 'icons/obj/crafting.dmi' + w_class = ITEM_SIZE_NORMAL + desc = "This is a metal bar. Can be made into lots of stuff" + icon_state = "metal_bar" + matter = list(DEFAULT_WALL_MATERIAL = 300) + + mill() + return /obj/item/pipe + press() + return /obj/item/weapon/crowbar + + +/obj/item/glass_bar + name = "Glass Bar" + icon = 'icons/obj/crafting.dmi' + w_class = ITEM_SIZE_NORMAL + desc = "This is a glass bar. Can be made into lots of stuff" + icon_state = "glass_bar" + matter = list("glass" = 300) + + mill() + return /obj/item/glass_tube + +/obj/item/glass_tube + name = "Glass Tube" + icon = 'icons/obj/crafting.dmi' + w_class = ITEM_SIZE_NORMAL + desc = "A hollow glass bar. Looks like it would fit perfectly as a tube light." + icon_state = "glass_tube" + matter = list("glass" = 200) + + +/obj/item/metal_shiv + name = "Metal shiv" + icon = 'icons/obj/crafting.dmi' + w_class = ITEM_SIZE_NORMAL + desc = "This is a metal shiv. It can be made into many things." + icon_state = "metal_shiv" + matter = list(DEFAULT_WALL_MATERIAL = 300) + + press() + return /obj/item/screwdriver_head + +/obj/item/screwdriver_head + name = "Screwdriver head" + icon = 'icons/obj/crafting.dmi' + w_class = ITEM_SIZE_NORMAL + desc = "This is the top of a screwdriver" + icon_state = "screwdriver_head" + +/obj/item/wrench_head + name = "Top of a wrench" + icon = 'icons/obj/crafting.dmi' + w_class = ITEM_SIZE_NORMAL + desc = "This is a top of a wrench." + icon_state = "wrench_head" + matter = list(DEFAULT_WALL_MATERIAL = 800) + +/obj/item/glass_handle + name = "Glass handle" + icon = 'icons/obj/crafting.dmi' + w_class = ITEM_SIZE_NORMAL + desc = "This is a piece of glass. It could be used as a handle" + icon_state = "glass_handle" + matter = list("glass" = 400) + +/obj/item/cylinder + var/chambers = 0 + name = "cylinder" + icon = 'icons/obj/crafting.dmi' + w_class = ITEM_SIZE_NORMAL + desc = "This is a makeshift cylinder. It has zero holes drilled into it" + icon_state = "cylinder_0" + matter = list(DEFAULT_WALL_MATERIAL = 500) + + mill(var/mob/living/carbon/human/user) + switch(chambers) + if(0) + if (user.statscheck(skills = user.SKILL_LEVEL(engineering)) >= SUCCESS) + return /obj/item/cylinder/one_slot + if(1) + if (user.statscheck(skills = user.SKILL_LEVEL(engineering), mod = -2) >= SUCCESS) + return /obj/item/cylinder/two_slot + if(2) + if (user.statscheck(skills = user.SKILL_LEVEL(engineering), mod = -4) >= SUCCESS) + return /obj/item/cylinder/three_slot + if(3) + if (user.statscheck(skills = user.SKILL_LEVEL(engineering), mod = -6) >= SUCCESS) + return /obj/item/cylinder/four_slot + if(4) + to_chat(usr, "You nick another hole, and the cylinder falls apart.") + return /obj/item/weapon/ore/slag + return /obj/item/weapon/ore/slag + + press() + return /obj/item/wrench_head + +/obj/item/cylinder/one_slot + chambers = 1 + icon_state = "cylinder_1" + desc = "This is a makeshift cylinder. It has one hole drilled into it" + +/obj/item/cylinder/two_slot + chambers = 2 + icon_state = "cylinder_2" + desc = "This is a makeshift cylinder. It has two holes drilled into it" + +/obj/item/cylinder/three_slot + chambers = 3 + icon_state = "cylinder_3" + desc = "This is a makeshift cylinder. It has three holes drilled into it" + +/obj/item/cylinder/four_slot + chambers = 4 + desc = "This is a makeshift cylinder. It has four holes drilled into it" + icon_state = "cylinder_4" + +/obj/item/stock + icon = 'icons/obj/crafting.dmi' + w_class = ITEM_SIZE_NORMAL + desc = "This is reciever." + icon_state = "stock" + +/obj/item/weapon/gun/projectile/revolver/crafted + max_shells = 0 + starts_loaded = 0 + icon_state = "crafted_revolver" + desc = "An ugly revolver made right here on the station. Looks like it will take .38 ammo" + condition = 75 + caliber = "38" + ammo_type = /obj/item/ammo_casing/c38 + +/obj/item/weapon/gun/projectile/revolver/crafted/one_chamber + max_shells = 1 + +/obj/item/weapon/gun/projectile/revolver/crafted/two_chamber + max_shells = 2 + +/obj/item/weapon/gun/projectile/revolver/crafted/three_chamber + max_shells = 3 + +/obj/item/weapon/gun/projectile/revolver/crafted/four_chamber + max_shells = 4 \ No newline at end of file diff --git a/code/modules/crafting/recipes/guns.dm b/code/modules/crafting/recipes/guns.dm new file mode 100644 index 00000000..fc918e40 --- /dev/null +++ b/code/modules/crafting/recipes/guns.dm @@ -0,0 +1,31 @@ +/datum/crafting_recipe/revolver_one + name = "Station made revolver one slot" + tools = list(/obj/item/weapon/screwdriver) + parts = list(/obj/item/reciever= 1, /obj/item/stock = 1, /obj/item/pipe = 1, /obj/item/cylinder/one_slot = 1, /obj/item/action = 1) + result = list(/obj/item/weapon/gun/projectile/revolver/crafted/one_chamber = 1) + time = 60 + base_chance = 100 + +/datum/crafting_recipe/revolver_two + name = "Station made revolver two slot" + tools = list(/obj/item/weapon/screwdriver) + parts = list(/obj/item/reciever= 1, /obj/item/stock = 1, /obj/item/pipe = 1, /obj/item/cylinder/two_slot = 1, /obj/item/action = 1) + result = list(/obj/item/weapon/gun/projectile/revolver/crafted/two_chamber = 1) + time = 60 + base_chance = 100 + +/datum/crafting_recipe/revolver_three + name = "Station made revolver three slot" + tools = list(/obj/item/weapon/screwdriver) + parts = list(/obj/item/reciever= 1, /obj/item/stock = 1, /obj/item/pipe = 1, /obj/item/cylinder/three_slot = 1, /obj/item/action = 1) + result = list(/obj/item/weapon/gun/projectile/revolver/crafted/three_chamber = 1) + time = 60 + base_chance = 100 + +/datum/crafting_recipe/revolver_four + name = "Station made revolver four slot" + tools = list(/obj/item/weapon/screwdriver) + parts = list(/obj/item/reciever= 1, /obj/item/stock = 1, /obj/item/pipe = 1, /obj/item/cylinder/four_slot = 1, /obj/item/action = 1) + result = list(/obj/item/weapon/gun/projectile/revolver/crafted/four_chamber = 1) + time = 60 + base_chance = 100 \ No newline at end of file diff --git a/code/modules/crafting/recipes/items.dm b/code/modules/crafting/recipes/items.dm new file mode 100644 index 00000000..9b2faebd --- /dev/null +++ b/code/modules/crafting/recipes/items.dm @@ -0,0 +1,28 @@ +/obj/item/bola + name = "Bola" + icon = 'icons/obj/crafting.dmi' + w_class = ITEM_SIZE_NORMAL + desc = "This is a bola. Good for tripping people the are running away." + icon_state = "bola" + matter = list(DEFAULT_WALL_MATERIAL = 20) + +/obj/item/bola/throw_impact(atom/hit_atom) + ..() + var/mob/living/carbon/C = hit_atom + C.Weaken(10) + +/datum/crafting_recipe/bola + name = "Bola" + parts = list(/obj/item/cylinder = 3, /obj/item/stack/cable_coil = 15) + tools = list() + result = list(/obj/item/bola = 1) + time = 30 + base_chance = 100 + +/datum/crafting_recipe/light_tube + name = "Light tube" + parts = list(/obj/item/glass_tube = 1, /obj/item/stack/cable_coil = 5) + tools = list(/obj/item/weapon/screwdriver = 1) + result = list(/obj/item/weapon/light/tube = 1) + time = 30 + base_chance = 100 \ No newline at end of file diff --git a/code/modules/crafting/recipes/structures.dm b/code/modules/crafting/recipes/structures.dm new file mode 100644 index 00000000..0f31060b --- /dev/null +++ b/code/modules/crafting/recipes/structures.dm @@ -0,0 +1,39 @@ +/datum/crafting_recipe/chair + name = "Chair" + parts = list(/obj/item/metal_bar = 2, /obj/item/stack/material/steel/ = 1) + tools = list(/obj/item/weapon/weldingtool = 1) + result = list(/obj/structure/bed/chair = 1) + time = 30 + base_chance = 100 + +/datum/crafting_recipe/bed + name = "Bed" + parts = list(/obj/item/metal_bar = 2, /obj/item/stack/material/steel/ = 2) + tools = list(/obj/item/weapon/weldingtool = 1) + result = list(/obj/structure/bed = 1) + time = 30 + base_chance = 100 + +/datum/crafting_recipe/bar_stool + name = "Bar Stool" + parts = list(/obj/item/metal_bar = 1, /obj/item/stack/material/steel/ = 1) + tools = list(/obj/item/weapon/weldingtool = 1) + result = list(/obj/item/weapon/stool/bar = 1) + time = 20 + base_chance = 100 + +/datum/crafting_recipe/table_frame + name = "Table Frame" + parts = list(/obj/item/metal_bar = 2) + tools = list(/obj/item/weapon/weldingtool = 1) + result = list(/obj/structure/table = 1) + time = 20 + base_chance = 100 + +/datum/crafting_recipe/Barricade + name = "Barricade" + parts = list(/obj/item/metal_bar = 4, /obj/item/stack/material/steel/ = 2) + tools = list(/obj/item/weapon/weldingtool = 1) + result = list(/obj/structure/barricade = 1) + time = 60 + base_chance = 100 \ No newline at end of file diff --git a/code/modules/crafting/recipes/tools.dm b/code/modules/crafting/recipes/tools.dm new file mode 100644 index 00000000..8dc98fc7 --- /dev/null +++ b/code/modules/crafting/recipes/tools.dm @@ -0,0 +1,26 @@ +/datum/crafting_recipe/wrench + name = "Wrench" //in-game display name + parts = list(/obj/item/metal_bar = 1, /obj/item/wrench_head = 1) //type paths of items consumed associated with how many are needed + tools = list(/obj/item/weapon/weldingtool = 1) //type paths of items needed but not consumed + result = list(/obj/item/weapon/wrench = 1) //type path of item resulting from this craft + + time = 30 //time in 1/10th of second + base_chance = 100 //base chance to get it right without skills + +/datum/crafting_recipe/wirecutters + name = "Wirecutters" + parts = list(/obj/item/weapon/material/butterflyblade = 2) + tools = list(/obj/item/weapon/screwdriver = 1) + result = list(/obj/item/weapon/wirecutters = 1) + time = 30 + base_chance = 100 + + +/datum/crafting_recipe/screwdriver + name = "Screwdriver" + parts = list(/obj/item/screwdriver_head = 1, /obj/item/glass_handle = 1) + tools = list() + result = list(/obj/item/weapon/screwdriver = 1) + + time = 30 + base_chance = 100 \ No newline at end of file diff --git a/code/modules/customitems/item_spawning.dm b/code/modules/customitems/item_spawning.dm new file mode 100644 index 00000000..4234a206 --- /dev/null +++ b/code/modules/customitems/item_spawning.dm @@ -0,0 +1,256 @@ +// Switch this out to use a database at some point. Each ckey is +// associated with a list of custom item datums. When the character +// spawns, the list is checked and all appropriate datums are spawned. +// See config/example/custom_items.txt for a more detailed overview +// of how the config system works. + +// CUSTOM ITEM ICONS: +// Inventory icons must be in CUSTOM_ITEM_OBJ with state name [item_icon]. +// On-mob icons must be in CUSTOM_ITEM_MOB with state name [item_icon]. +// Inhands must be in CUSTOM_ITEM_MOB as [icon_state]_l and [icon_state]_r. + +// Kits must have mech icons in CUSTOM_ITEM_OBJ under [kit_icon]. +// Broken must be [kit_icon]-broken and open must be [kit_icon]-open. + +// Kits must also have hardsuit icons in CUSTOM_ITEM_MOB as [kit_icon]_suit +// and [kit_icon]_helmet, and in CUSTOM_ITEM_OBJ as [kit_icon]. + +/var/list/custom_items = list() + +/datum/custom_item + var/assoc_key + var/character_name + var/inherit_inhands = 1 //if unset, and inhands are not provided, then the inhand overlays will be invisible. + var/item_icon + var/item_desc + var/name + var/item_path = /obj/item + var/item_path_as_string + var/req_access = 0 + var/list/req_titles = list() + var/kit_name + var/kit_desc + var/kit_icon + var/additional_data + +/datum/custom_item/proc/is_valid(var/checker) + if(!item_path) + to_chat(checker, "The given item path, [item_path_as_string], is invalid and does not exist.") + return FALSE + if(item_icon && !(item_icon in icon_states(CUSTOM_ITEM_OBJ))) + to_chat(checker, "The given item icon, [item_icon], is invalid and does not exist.") + return FALSE + return TRUE + +/datum/custom_item/proc/spawn_item(var/newloc) + var/obj/item/citem = new item_path(newloc) + apply_to_item(citem) + return citem + +/datum/custom_item/proc/apply_to_item(var/obj/item/item) + if(!item) + return + if(name) + item.SetName(name) + if(item_desc) + item.desc = item_desc + if(item_icon) + if(!istype(item)) + item.icon = CUSTOM_ITEM_OBJ + item.set_icon_state(item_icon) + return + else + if(inherit_inhands) + apply_inherit_inhands(item) + else + item.item_state_slots = null + item.item_icons = null + + item.icon = CUSTOM_ITEM_OBJ + item.set_icon_state(item_icon) + item.item_state = null + item.icon_override = CUSTOM_ITEM_MOB + + var/obj/item/clothing/under/U = item + if(istype(U)) + U.worn_state = U.icon_state + U.update_rolldown_status() + + // Kits are dumb so this is going to have to be hardcoded/snowflake. + if(istype(item, /obj/item/device/kit)) + var/obj/item/device/kit/K = item + K.new_name = kit_name + K.new_desc = kit_desc + K.new_icon = kit_icon + K.new_icon_file = CUSTOM_ITEM_OBJ + if(istype(item, /obj/item/device/kit/paint)) + var/obj/item/device/kit/paint/kit = item + kit.allowed_types = splittext(additional_data, ", ") + else if(istype(item, /obj/item/device/kit/suit)) + var/obj/item/device/kit/suit/kit = item + kit.new_light_overlay = additional_data + kit.new_mob_icon_file = CUSTOM_ITEM_MOB + + return item + +/datum/custom_item/proc/apply_inherit_inhands(var/obj/item/item) + var/list/new_item_icons = list() + var/list/new_item_state_slots = list() + + var/list/available_states = icon_states(CUSTOM_ITEM_MOB) + + //If l_hand or r_hand are not present, preserve them using item_icons/item_state_slots + //Then use icon_override to make every other slot use the custom sprites by default. + //This has to be done before we touch any of item's vars + if(!("[item_icon]_l" in available_states)) + new_item_state_slots[slot_l_hand_str] = get_state(item, slot_l_hand_str, "_l") + new_item_icons[slot_l_hand_str] = get_icon(item, slot_l_hand_str, 'icons/mob/onmob/items/lefthand.dmi') + if(!("[item_icon]_r" in available_states)) + new_item_state_slots[slot_r_hand_str] = get_state(item, slot_r_hand_str, "_r") + new_item_icons[slot_r_hand_str] = get_icon(item, slot_r_hand_str, 'icons/mob/onmob/items/righthand.dmi') + + item.item_state_slots = new_item_state_slots + item.item_icons = new_item_icons + +//this has to mirror the way update_inv_*_hand() selects the state +/datum/custom_item/proc/get_state(var/obj/item/item, var/slot_str, var/hand_str) + var/t_state + if(item.item_state_slots && item.item_state_slots[slot_str]) + t_state = item.item_state_slots[slot_str] + else if(item.item_state) + t_state = item.item_state + else + t_state = item.icon_state + if(item.icon_override) + t_state += hand_str + return t_state + +//this has to mirror the way update_inv_*_hand() selects the icon +/datum/custom_item/proc/get_icon(var/obj/item/item, var/slot_str, var/icon/hand_icon) + var/icon/t_icon + if(item.icon_override) + t_icon = item.icon_override + else if(item.item_icons && (slot_str in item.item_icons)) + t_icon = item.item_icons[slot_str] + else + t_icon = hand_icon + return t_icon + +// Parses the config file into the custom_items list. +/hook/startup/proc/load_custom_items() + + var/datum/custom_item/current_data + for(var/line in splittext(file2text("config/custom_items.txt"), "\n")) + + line = trim(line) + if(line == "" || !line || findtext(line, "#", 1, 2)) + continue + + if(findtext(line, "{", 1, 2) || findtext(line, "}", 1, 2)) // New block! + if(current_data && current_data.assoc_key) + if(!custom_items[current_data.assoc_key]) + custom_items[current_data.assoc_key] = list() + var/list/L = custom_items[current_data.assoc_key] + L |= current_data + current_data = null + + var/split = findtext(line,":") + if(!split) + continue + var/field = trim(copytext(line,1,split)) + var/field_data = trim(copytext(line,(split+1))) + if(!field || !field_data) + continue + + if(!current_data) + current_data = new() + + switch(field) + if("ckey") + current_data.assoc_key = lowertext(field_data) + if("character_name") + current_data.character_name = lowertext(field_data) + if("item_path") + current_data.item_path = text2path(field_data) + current_data.item_path_as_string = field_data + if("item_name") + current_data.name = field_data + if("item_icon") + current_data.item_icon = field_data + if("inherit_inhands") + current_data.inherit_inhands = text2num(field_data) + if("item_desc") + current_data.item_desc = field_data + if("req_access") + current_data.req_access = text2num(field_data) + if("req_titles") + current_data.req_titles = splittext(field_data,", ") + if("kit_name") + current_data.kit_name = field_data + if("kit_desc") + current_data.kit_desc = field_data + if("kit_icon") + current_data.kit_icon = field_data + if("additional_data") + current_data.additional_data = field_data + return 1 + +//gets the relevant list for the key from the listlist if it exists, check to make sure they are meant to have it and then calls the giving function +/proc/equip_custom_items(mob/living/carbon/human/M) + var/list/key_list = custom_items[M.ckey] + if(!key_list || key_list.len < 1) + return + + for(var/datum/custom_item/citem in key_list) + + // Check for requisite ckey and character name. + if((lowertext(citem.assoc_key) != lowertext(M.ckey)) || (lowertext(citem.character_name) != lowertext(M.real_name))) + continue + + // Once we've decided that the custom item belongs to this player, validate it + if(!citem.is_valid(M)) + return + + // Check for required access. + var/obj/item/weapon/card/id/current_id = M.wear_id + if(citem.req_access && citem.req_access > 0) + if(!(istype(current_id) && (citem.req_access in current_id.access))) + continue + + // Check for required job title. + if(citem.req_titles && citem.req_titles.len > 0) + var/has_title + var/current_title = M.mind.role_alt_title ? M.mind.role_alt_title : M.mind.assigned_role + for(var/title in citem.req_titles) + if(title == current_title) + has_title = 1 + break + if(!has_title) + continue + + // ID cards and PDAs are applied directly to the existing object rather than spawned fresh. + var/obj/item/existing_item + if(citem.item_path == /obj/item/weapon/card/id && istype(current_id)) //Set earlier. + existing_item = M.wear_id + else if(citem.item_path == /obj/item/device/pda) + existing_item = locate(/obj/item/device/pda) in M.contents + + // Spawn and equip the item. + if(existing_item) + citem.apply_to_item(existing_item) + else + place_custom_item(M,citem) + +// Places the item on the target mob. +/proc/place_custom_item(mob/living/carbon/human/M, var/datum/custom_item/citem) + + if(!citem) return + var/obj/item/newitem = citem.spawn_item(M.loc) + + if(M.equip_to_appropriate_slot(newitem)) + return newitem + + if(M.equip_to_storage(newitem)) + return newitem + + return newitem \ No newline at end of file diff --git a/code/modules/detectivework/footprints.dm b/code/modules/detectivework/footprints.dm new file mode 100644 index 00000000..e69de29b diff --git a/code/modules/detectivework/forensics.dm b/code/modules/detectivework/forensics.dm new file mode 100644 index 00000000..3fcfd864 --- /dev/null +++ b/code/modules/detectivework/forensics.dm @@ -0,0 +1,181 @@ +/obj/item/weapon/forensics + icon = 'icons/obj/forensics.dmi' + w_class = ITEM_SIZE_TINY + +//This is the output of the stringpercent(print) proc, and means about 80% of +//the print must be there for it to be complete. (Prints are 32 digits) +var/const/FINGERPRINT_COMPLETE = 6 +proc/is_complete_print(var/print) + return stringpercent(print) <= FINGERPRINT_COMPLETE + +atom/var/list/suit_fibers +atom/var/var/list/fingerprints +atom/var/var/list/fingerprintshidden +atom/var/var/fingerprintslast = null + +/atom/proc/add_hiddenprint(mob/M) + if(!M || !M.key) + return + if(fingerprintslast == M.key) + return + fingerprintslast = M.key + if(!fingerprintshidden) + fingerprintshidden = list() + if (ishuman(M)) + var/mob/living/carbon/human/H = M + if (H.gloves) + src.fingerprintshidden += "\[[time_stamp()]\] (Wearing gloves). Real name: [H.real_name], Key: [H.key]" + return 0 + + src.fingerprintshidden += "\[[time_stamp()]\] Real name: [M.real_name], Key: [M.key]" + return 1 + +/atom/proc/add_fingerprint(mob/M, ignoregloves, obj/item/tool) + if(isnull(M)) return + if(isAI(M)) return + if(!M || !M.key) + return + if(istype(tool) && (tool.item_flags & ITEM_FLAG_NO_PRINT)) + return + + add_hiddenprint(M) + add_fibers(M) + + if(!fingerprints) + fingerprints = list() + + //Hash this shit. + var/full_print = M.get_full_print(ignoregloves) + if(!full_print) + return + + var/obj/item/organ/external/E = M.get_active_hand() + if(src != E && istype(E) && E.get_fingerprint()) + full_print = E.get_fingerprint() + ignoregloves = 1 + + if(!ignoregloves && ishuman(M)) + var/mob/living/carbon/human/H = M + if (H.gloves && H.gloves.body_parts_covered & HANDS && H.gloves != src) + H.gloves.add_fingerprint(M) + if(!istype(H.gloves, /obj/item/clothing/gloves/latex)) + return 0 + else if(prob(75)) + return 0 + + // Add the fingerprints + add_partial_print(full_print) + return 1 + +/atom/proc/add_partial_print(full_print) + if(!fingerprints[full_print]) + fingerprints[full_print] = stars(full_print, rand(0, 20)) //Initial touch, not leaving much evidence the first time. + else + switch(stringpercent(fingerprints[full_print])) //tells us how many stars are in the current prints. + if(28 to 32) + if(prob(1)) + fingerprints[full_print] = full_print // You rolled a one buddy. + else + fingerprints[full_print] = stars(full_print, rand(0,40)) // 24 to 32 + + if(24 to 27) + if(prob(3)) + fingerprints[full_print] = full_print //Sucks to be you. + else + fingerprints[full_print] = stars(full_print, rand(15, 55)) // 20 to 29 + + if(20 to 23) + if(prob(5)) + fingerprints[full_print] = full_print //Had a good run didn't ya. + else + fingerprints[full_print] = stars(full_print, rand(30, 70)) // 15 to 25 + + if(16 to 19) + if(prob(5)) + fingerprints[full_print] = full_print //Welp. + else + fingerprints[full_print] = stars(full_print, rand(40, 100)) // 0 to 21 + + if(0 to 15) + if(prob(5)) + fingerprints[full_print] = stars(full_print, rand(0,50)) // small chance you can smudge. + else + fingerprints[full_print] = full_print + +/atom/proc/transfer_fingerprints_to(var/atom/A) + if(fingerprints) + if(!A.fingerprints) + A.fingerprints = list() + A.fingerprints |= fingerprints.Copy() //detective + if(fingerprintshidden) + if(!A.fingerprintshidden) + A.fingerprintshidden = list() + A.fingerprintshidden |= fingerprintshidden.Copy() //admin + A.fingerprintslast = fingerprintslast + +atom/proc/add_fibers(mob/living/carbon/human/M) + if(!istype(M)) + return + if(M.gloves && istype(M.gloves,/obj/item/clothing/gloves)) + var/obj/item/clothing/gloves/G = M.gloves + if(G.transfer_blood) //bloodied gloves transfer blood to touched objects + if(add_blood(G.bloody_hands_mob)) //only reduces the bloodiness of our gloves if the item wasn't already bloody + G.transfer_blood-- + else if(M.bloody_hands) + if(add_blood(M.bloody_hands_mob)) + M.bloody_hands-- + + if(!suit_fibers) suit_fibers = list() + var/fibertext + var/item_multiplier = istype(src,/obj/item)?1.2:1 + var/suit_coverage = 0 + if(istype(M.wear_suit, /obj/item/clothing)) + var/obj/item/clothing/C = M.wear_suit + fibertext = C.get_fibers() + if(fibertext && prob(10*item_multiplier)) + suit_fibers |= fibertext + suit_coverage = C.body_parts_covered + + if(istype(M.w_uniform, /obj/item/clothing) && (M.w_uniform.body_parts_covered & ~suit_coverage)) + var/obj/item/clothing/C = M.w_uniform + fibertext = C.get_fibers() + if(fibertext && prob(15*item_multiplier)) + suit_fibers |= fibertext + + if(istype(M.gloves, /obj/item/clothing) && (M.gloves.body_parts_covered & ~suit_coverage)) + var/obj/item/clothing/C = M.gloves + fibertext = C.get_fibers() + if(fibertext && prob(20*item_multiplier)) + suit_fibers |= fibertext + +/mob/proc/get_full_print() + return FALSE + +/mob/living/carbon/get_full_print() + if (!dna || (mFingerprints in mutations)) + return FALSE + return md5(dna.uni_identity) + +/mob/living/carbon/human/get_full_print(ignoregloves) + if(!..()) + return FALSE + + var/obj/item/organ/external/E = organs_by_name[hand ? BP_L_HAND : BP_R_HAND] + if(E) + return E.get_fingerprint() + +/obj/item/organ/external/proc/get_fingerprint() + return + +/obj/item/organ/external/arm/get_fingerprint() + for(var/obj/item/organ/external/hand/H in children) + return H.get_fingerprint() + +/obj/item/organ/external/hand/get_fingerprint() + if(dna && !is_stump()) + return md5(dna.uni_identity) + +/obj/item/organ/external/afterattack(atom/A, mob/user, proximity) + ..() + if(proximity && get_fingerprint()) + A.add_partial_print(get_fingerprint()) \ No newline at end of file diff --git a/code/modules/detectivework/microscope/dnascanner.dm b/code/modules/detectivework/microscope/dnascanner.dm new file mode 100644 index 00000000..630c29f1 --- /dev/null +++ b/code/modules/detectivework/microscope/dnascanner.dm @@ -0,0 +1,153 @@ +//DNA machine +/obj/machinery/dnaforensics + name = "DNA analyzer" + desc = "A high tech machine that is designed to read DNA samples properly." + icon = 'icons/obj/forensics.dmi' + icon_state = "dnaopen" + anchored = 1 + density = 1 + + var/obj/item/weapon/forensics/swab/bloodsamp = null + var/closed = 0 + var/scanning = 0 + var/scanner_progress = 0 + var/scanner_rate = 2.50 + var/last_process_worldtime = 0 + var/report_num = 0 + +/obj/machinery/dnaforensics/attackby(var/obj/item/W, mob/user as mob) + + if(bloodsamp) + to_chat(user, "There is already a sample in the machine.") + return + + if(closed) + to_chat(user, "Open the cover before inserting the sample.") + return + + var/obj/item/weapon/forensics/swab/swab = W + if(istype(swab) && swab.is_used()) + user.unEquip(W) + src.bloodsamp = swab + swab.loc = src + to_chat(user, "You insert \the [W] into \the [src].") + else + to_chat(user, "\The [src] only accepts used swabs.") + return + +/obj/machinery/dnaforensics/ui_interact(mob/user, ui_key = "main",var/datum/nanoui/ui = null) + if(stat & (NOPOWER)) return + if(user.stat || user.restrained()) return + var/list/data = list() + data["scan_progress"] = round(scanner_progress) + data["scanning"] = scanning + data["bloodsamp"] = (bloodsamp ? bloodsamp.name : "") + data["bloodsamp_desc"] = (bloodsamp ? (bloodsamp.desc ? bloodsamp.desc : "No information on record.") : "") + data["lidstate"] = closed + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data) + if (!ui) + ui = new(user, src, ui_key, "dnaforensics.tmpl", "QuikScan DNA Analyzer", 540, 326) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/dnaforensics/Topic(href, href_list) + + if(..()) return 1 + + if(stat & (NOPOWER)) + return 0 // don't update UIs attached to this object + + if(href_list["scanItem"]) + if(scanning) + scanning = 0 + else + if(bloodsamp) + if(closed == 1) + scanner_progress = 0 + scanning = 1 + to_chat(usr, "Scan initiated.") + update_icon() + else + to_chat(usr, "Please close sample lid before initiating scan.") + else + to_chat(usr, "Insert an item to scan.") + + if(href_list["ejectItem"]) + if(bloodsamp) + bloodsamp.forceMove(src.loc) + bloodsamp = null + + if(href_list["toggleLid"]) + toggle_lid() + + return 1 + +/obj/machinery/dnaforensics/Process() + if(scanning) + if(!bloodsamp || bloodsamp.loc != src) + bloodsamp = null + scanning = 0 + else if(scanner_progress >= 100) + complete_scan() + return + else + //calculate time difference + var/deltaT = (world.time - last_process_worldtime) * 0.1 + scanner_progress = min(100, scanner_progress + scanner_rate * deltaT) + last_process_worldtime = world.time + +/obj/machinery/dnaforensics/proc/complete_scan() + src.visible_message("\icon[src] makes an insistent chime.", 2) + update_icon() + if(bloodsamp) + var/obj/item/weapon/paper/P = new(src) + P.SetName("[src] report #[++report_num]: [bloodsamp.name]") + P.stamped = list(/obj/item/weapon/stamp) + P.overlays = list("paper_stamped") + //dna data itself + var/data = "No scan information available." + if(bloodsamp.dna != null) + data = "Spectometric analysis on provided sample has determined the presence of [bloodsamp.dna.len] strings of DNA.

            " + for(var/blood in bloodsamp.dna) + data += "Blood type: [bloodsamp.dna[blood]]
            \nDNA: [blood]


            " + else + data += "No DNA found.
            " + P.info = "[src] analysis report #[report_num]
            " + P.info += "Scanned item:
            [bloodsamp.name]
            [bloodsamp.desc]

            " + data + P.forceMove(src.loc) + P.update_icon() + scanning = 0 + update_icon() + return + +/obj/machinery/dnaforensics/attack_ai(mob/user as mob) + ui_interact(user) + +/obj/machinery/dnaforensics/attack_hand(mob/user as mob) + ui_interact(user) + +/obj/machinery/dnaforensics/verb/toggle_lid() + set category = "Object" + set name = "Toggle Lid" + set src in oview(1) + + if(usr.stat || !isliving(usr)) + return + + if(scanning) + to_chat(usr, "You can't do that while [src] is scanning!") + return + + closed = !closed + src.update_icon() + +/obj/machinery/dnaforensics/update_icon() + ..() + if(!(stat & NOPOWER) && scanning) + icon_state = "dnaworking" + else if(closed) + icon_state = "dnaclosed" + else + icon_state = "dnaopen" diff --git a/code/modules/detectivework/microscope/microscope.dm b/code/modules/detectivework/microscope/microscope.dm new file mode 100644 index 00000000..d5d9b6bb --- /dev/null +++ b/code/modules/detectivework/microscope/microscope.dm @@ -0,0 +1,112 @@ +//microscope code itself +/obj/machinery/microscope + name = "high powered electron microscope" + desc = "A highly advanced microscope capable of zooming up to 3000x." + icon = 'icons/obj/forensics.dmi' + icon_state = "microscope" + anchored = 1 + density = 1 + + var/obj/item/weapon/sample = null + var/report_num = 0 + +/obj/machinery/microscope/attackby(obj/item/weapon/W as obj, mob/user as mob) + + if(sample) + to_chat(user, "There is already a slide in the microscope.") + return + + if(istype(W, /obj/item/weapon/forensics/swab)|| istype(W, /obj/item/weapon/sample/fibers) || istype(W, /obj/item/weapon/sample/print)) + to_chat(user, "You insert \the [W] into the microscope.") + user.unEquip(W) + W.forceMove(src) + sample = W + update_icon() + return + +/obj/machinery/microscope/attack_hand(mob/user) + + if(!sample) + to_chat(user, "The microscope has no sample to examine.") + return + + to_chat(user, "The microscope whirrs as you examine \the [sample].") + + if(!do_after(user, 25, src) || !sample) + to_chat(user, "You stop examining \the [sample].") + return + + to_chat(user, "Printing findings now...") + var/obj/item/weapon/paper/report = new(get_turf(src)) + report.stamped = list(/obj/item/weapon/stamp) + report.overlays = list("paper_stamped") + report_num++ + + if(istype(sample, /obj/item/weapon/forensics/swab)) + var/obj/item/weapon/forensics/swab/swab = sample + + report.SetName("GSR report #[++report_num]: [swab.name]") + report.info = "Scanned item:
            [swab.name]

            " + + if(swab.gsr) + report.info += "Residue from a [swab.gsr] bullet detected." + else + report.info += "No gunpowder residue found." + + else if(istype(sample, /obj/item/weapon/sample/fibers)) + var/obj/item/weapon/sample/fibers/fibers = sample + report.SetName("Fiber report #[++report_num]: [fibers.name]") + report.info = "Scanned item:
            [fibers.name]

            " + if(fibers.evidence) + report.info = "Molecular analysis on provided sample has determined the presence of unique fiber strings.

            " + for(var/fiber in fibers.evidence) + report.info += "Most likely match for fibers: [fiber]

            " + else + report.info += "No fibers found." + else if(istype(sample, /obj/item/weapon/sample/print)) + report.SetName("Fingerprint report #[report_num]: [sample.name]") + report.info = "Fingerprint analysis report #[report_num]: [sample.name]
            " + var/obj/item/weapon/sample/print/card = sample + if(card.evidence && card.evidence.len) + report.info += "Surface analysis has determined unique fingerprint strings:

            " + for(var/prints in card.evidence) + report.info += "Fingerprint string: " + if(!is_complete_print(prints)) + report.info += "INCOMPLETE PRINT" + else + report.info += "[prints]" + report.info += "
            " + else + report.info += "No information available." + + if(report) + report.update_icon() + if(report.info) + to_chat(user, report.info) + return + +/obj/machinery/microscope/proc/remove_sample(var/mob/living/remover) + if(!istype(remover) || remover.incapacitated() || !Adjacent(remover)) + return ..() + if(!sample) + to_chat(remover, "\The [src] does not have a sample in it.") + return + to_chat(remover, "You remove \the [sample] from \the [src].") + sample.forceMove(get_turf(src)) + remover.put_in_hands(sample) + sample = null + update_icon() + +/obj/machinery/microscope/AltClick() + remove_sample(usr) + +/obj/machinery/microscope/MouseDrop(var/atom/other) + if(usr == other) + remove_sample(usr) + else + return ..() + +/obj/machinery/microscope/update_icon() + icon_state = "microscope" + if(sample) + icon_state += "slide" diff --git a/code/modules/detectivework/tools/crimekit.dm b/code/modules/detectivework/tools/crimekit.dm new file mode 100644 index 00000000..1c30e310 --- /dev/null +++ b/code/modules/detectivework/tools/crimekit.dm @@ -0,0 +1,15 @@ +//crime scene kit +/obj/item/weapon/storage/briefcase/crimekit + name = "crime scene kit" + desc = "A stainless steel-plated carrycase for all your forensic needs. Feels heavy." + icon = 'icons/obj/forensics.dmi' + icon_state = "case" + item_state = "case" + startswith = list( + /obj/item/weapon/storage/box/swabs, + /obj/item/weapon/storage/box/fingerprints, + /obj/item/weapon/reagent_containers/spray/luminol, + /obj/item/device/uv_light, + /obj/item/weapon/forensics/sample_kit, + /obj/item/weapon/forensics/sample_kit/powder, + ) diff --git a/code/modules/detectivework/tools/evidencebag.dm b/code/modules/detectivework/tools/evidencebag.dm new file mode 100644 index 00000000..a885bca9 --- /dev/null +++ b/code/modules/detectivework/tools/evidencebag.dm @@ -0,0 +1,98 @@ +//CONTAINS: Evidence bags and fingerprint cards + +/obj/item/weapon/evidencebag + name = "evidence bag" + desc = "An empty evidence bag." + icon = 'icons/obj/storage.dmi' + icon_state = "evidenceobj" + item_state = "" + w_class = ITEM_SIZE_SMALL + var/obj/item/stored_item = null + +/obj/item/weapon/evidencebag/MouseDrop(var/obj/item/I as obj) + if (!ishuman(usr)) + return + + var/mob/living/carbon/human/user = usr + + if (!(user.l_hand == src || user.r_hand == src)) + return //bag must be in your hands to use + + if (isturf(I.loc)) + if (!user.Adjacent(I)) + return + else + //If it isn't on the floor. Do some checks to see if it's in our hands or a box. Otherwise give up. + if(istype(I.loc,/obj/item/weapon/storage)) //in a container. + var/sdepth = I.storage_depth(user) + if (sdepth == -1 || sdepth > 1) + return //too deeply nested to access + + var/obj/item/weapon/storage/U = I.loc + user.client.screen -= I + U.contents.Remove(I) + else if(user.l_hand == I) //in a hand + user.drop_l_hand() + else if(user.r_hand == I) //in a hand + user.drop_r_hand() + else + return + + if(!istype(I) || I.anchored) + return + + if(istype(I, /obj/item/weapon/evidencebag)) + to_chat(user, "You find putting an evidence bag in another evidence bag to be slightly absurd.") + return + + if(I.w_class > ITEM_SIZE_NORMAL) + to_chat(user, "[I] won't fit in [src].") + return + + if(contents.len) + to_chat(user, "[src] already has something inside it.") + return + + user.visible_message("[user] puts [I] into [src]", "You put [I] inside [src].",\ + "You hear a rustle as someone puts something into a plastic bag.") + + icon_state = "evidence" + + var/xx = I.pixel_x //save the offset of the item + var/yy = I.pixel_y + I.pixel_x = 0 //then remove it so it'll stay within the evidence bag + I.pixel_y = 0 + var/image/img = image("icon"=I, "layer"=FLOAT_LAYER) //take a snapshot. (necessary to stop the underlays appearing under our inventory-HUD slots ~Carn + I.pixel_x = xx //and then return it + I.pixel_y = yy + overlays += img + overlays += "evidence" //should look nicer for transparent stuff. not really that important, but hey. + + desc = "An evidence bag containing [I]." + I.loc = src + stored_item = I + w_class = I.w_class + return + + +/obj/item/weapon/evidencebag/attack_self(mob/user as mob) + if(contents.len) + var/obj/item/I = contents[1] + user.visible_message("[user] takes [I] out of [src]", "You take [I] out of [src].",\ + "You hear someone rustle around in a plastic bag, and remove something.") + overlays.Cut() //remove the overlays + + user.put_in_hands(I) + stored_item = null + + w_class = initial(w_class) + icon_state = "evidenceobj" + desc = "An empty evidence bag." + else + to_chat(user, "[src] is empty.") + icon_state = "evidenceobj" + return + +/obj/item/weapon/evidencebag/examine(mob/user) + . = ..(user) + if (stored_item) user.examinate(stored_item) diff --git a/code/modules/detectivework/tools/luminol.dm b/code/modules/detectivework/tools/luminol.dm new file mode 100644 index 00000000..f023e56d --- /dev/null +++ b/code/modules/detectivework/tools/luminol.dm @@ -0,0 +1,13 @@ +/obj/item/weapon/reagent_containers/spray/luminol + name = "luminol bottle" + desc = "A bottle containing an odourless, colorless liquid." + icon = 'icons/obj/forensics.dmi' + icon_state = "luminol" + item_state = "cleaner" + amount_per_transfer_from_this = 10 + possible_transfer_amounts = "5;10" + volume = 250 + +/obj/item/weapon/reagent_containers/spray/luminol/New() + ..() + reagents.add_reagent(/datum/reagent/luminol, 250) \ No newline at end of file diff --git a/code/modules/detectivework/tools/rag.dm b/code/modules/detectivework/tools/rag.dm new file mode 100644 index 00000000..9a15a882 --- /dev/null +++ b/code/modules/detectivework/tools/rag.dm @@ -0,0 +1,220 @@ +/mob + var/bloody_hands = null + var/mob/living/carbon/human/bloody_hands_mob + var/track_blood = 0 + var/list/feet_blood_DNA + var/track_blood_type + var/feet_blood_color + +/obj/item/clothing/gloves + var/transfer_blood = 0 + var/mob/living/carbon/human/bloody_hands_mob + +/obj/item/clothing/shoes/ + var/track_blood = 0 + +/obj/item/weapon/reagent_containers/glass/rag + name = "rag" + desc = "For cleaning up messes, you suppose." + w_class = ITEM_SIZE_TINY + icon = 'icons/obj/toy.dmi' + icon_state = "rag" + amount_per_transfer_from_this = 5 + possible_transfer_amounts = "5" + volume = 10 + can_be_placed_into = null + item_flags = ITEM_FLAG_NO_BLUDGEON + atom_flags = ATOM_FLAG_OPEN_CONTAINER + unacidable = 0 + + var/on_fire = 0 + var/burn_time = 20 //if the rag burns for too long it turns to ashes + +/obj/item/weapon/reagent_containers/glass/rag/New() + ..() + update_name() + +/obj/item/weapon/reagent_containers/glass/rag/Destroy() + STOP_PROCESSING(SSobj, src) //so we don't continue turning to ash while gc'd + . = ..() + +/obj/item/weapon/reagent_containers/glass/rag/attack_self(mob/user as mob) + if(on_fire) + user.visible_message("\The [user] stamps out [src].", "You stamp out [src].") + user.unEquip(src) + extinguish() + else + remove_contents(user) + +/obj/item/weapon/reagent_containers/glass/rag/attackby(obj/item/W, mob/user) + if(!on_fire && istype(W, /obj/item/weapon/flame)) + var/obj/item/weapon/flame/F = W + if(F.lit) + ignite() + if(on_fire) + visible_message("\The [user] lights [src] with [W].") + else + to_chat(user, "You manage to singe [src], but fail to light it.") + + . = ..() + update_name() + +/obj/item/weapon/reagent_containers/glass/rag/proc/update_name() + if(on_fire) + SetName("burning [initial(name)]") + else if(reagents.total_volume) + SetName("damp [initial(name)]") + else + SetName("dry [initial(name)]") + +/obj/item/weapon/reagent_containers/glass/rag/update_icon() + if(on_fire) + icon_state = "raglit" + else + icon_state = "rag" + + var/obj/item/weapon/reagent_containers/food/drinks/bottle/B = loc + if(istype(B)) + B.update_icon() + +/obj/item/weapon/reagent_containers/glass/rag/proc/remove_contents(mob/user, atom/trans_dest = null) + if(!trans_dest && !user.loc) + return + + if(reagents.total_volume) + var/target_text = trans_dest? "\the [trans_dest]" : "\the [user.loc]" + user.visible_message("\The [user] begins to wring out [src] over [target_text].", "You begin to wring out [src] over [target_text].") + + if(do_after(user, reagents.total_volume*5, progress = 0)) //50 for a fully soaked rag + if(trans_dest) + reagents.trans_to(trans_dest, reagents.total_volume) + else + reagents.splash(user.loc, reagents.total_volume) + user.visible_message("\The [user] wrings out [src] over [target_text].", "You finish to wringing out [src].") + update_name() + +/obj/item/weapon/reagent_containers/glass/rag/proc/wipe_down(atom/A, mob/user) + if(!reagents.total_volume) + to_chat(user, "The [initial(name)] is dry!") + else + user.visible_message("\The [user] starts to wipe down [A] with [src]!") + reagents.splash(A, 1) //get a small amount of liquid on the thing we're wiping. + update_name() + if(do_after(user,30, progress = 0)) + user.visible_message("\The [user] finishes wiping off the [A]!") + A.clean_blood() + +/obj/item/weapon/reagent_containers/glass/rag/attack(atom/target as obj|turf|area, mob/user as mob , flag) + if(isliving(target)) + var/mob/living/M = target + if(on_fire) + user.visible_message("\The [user] hits [target] with [src]!",) + M.IgniteMob() + else if(reagents.total_volume) + if(user.zone_sel.selecting == BP_MOUTH) + user.visible_message( + "\The [user] smothers [target] with [src]!", + "You smother [target] with [src]!", + "You hear some struggling and muffled cries of surprise" + ) + + //it's inhaled, so... maybe CHEM_BLOOD doesn't make a whole lot of sense but it's the best we can do for now + reagents.trans_to_mob(target, amount_per_transfer_from_this, CHEM_BLOOD) + update_name() + else + wipe_down(target, user) + return + + return ..() + +/obj/item/weapon/reagent_containers/glass/rag/afterattack(atom/A as obj|turf|area, mob/user as mob, proximity) + if(!proximity) + return + + if(istype(A, /obj/structure/reagent_dispensers)) + if(!reagents.get_free_space()) + to_chat(user, "\The [src] is already soaked.") + return + + if(A.reagents && A.reagents.trans_to_obj(src, reagents.maximum_volume)) + user.visible_message("\The [user] soaks [src] using [A].", "You soak [src] using [A].") + update_name() + return + + if(!on_fire && istype(A) && (src in user)) + if(A.is_open_container() && !(A in user)) + remove_contents(user, A) + else if(!ismob(A)) //mobs are handled in attack() - this prevents us from wiping down people while smothering them. + wipe_down(A, user) + return + +/obj/item/weapon/reagent_containers/glass/rag/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature >= 50 + T0C) + ignite() + if(exposed_temperature >= 900 + T0C) + new /obj/effect/decal/cleanable/ash(get_turf(src)) + qdel(src) + +//rag must have a minimum of 2 units welder fuel and at least 80% of the reagents must be welder fuel. +//maybe generalize flammable reagents someday +/obj/item/weapon/reagent_containers/glass/rag/proc/can_ignite() + var/fuel = reagents.get_reagent_amount(/datum/reagent/fuel) + return (fuel >= 2 && fuel >= reagents.total_volume*0.8) + +/obj/item/weapon/reagent_containers/glass/rag/proc/ignite() + if(on_fire) + return + if(!can_ignite()) + return + + //also copied from matches + if(reagents.get_reagent_amount(/datum/reagent/toxin/phoron)) // the phoron explodes when exposed to fire + visible_message("\The [src] conflagrates violently!") + var/datum/effect/effect/system/reagents_explosion/e = new() + e.set_up(round(reagents.get_reagent_amount(/datum/reagent/toxin/phoron) / 2.5, 1), get_turf(src), 0, 0) + e.start() + qdel(src) + return + + START_PROCESSING(SSobj, src) + set_light(2, null, "#e38f46") + on_fire = 1 + update_name() + update_icon() + +/obj/item/weapon/reagent_containers/glass/rag/proc/extinguish() + STOP_PROCESSING(SSobj, src) + set_light(0) + on_fire = 0 + + //rags sitting around with 1 second of burn time left is dumb. + //ensures players always have a few seconds of burn time left when they light their rag + if(burn_time <= 5) + visible_message("\The [src] falls apart!") + new /obj/effect/decal/cleanable/ash(get_turf(src)) + qdel(src) + update_name() + update_icon() + +/obj/item/weapon/reagent_containers/glass/rag/Process() + if(!can_ignite()) + visible_message("\The [src] burns out.") + extinguish() + + //copied from matches + if(isliving(loc)) + var/mob/living/M = loc + M.IgniteMob() + var/turf/location = get_turf(src) + if(location) + location.hotspot_expose(700, 5) + + if(burn_time <= 0) + STOP_PROCESSING(SSobj, src) + new /obj/effect/decal/cleanable/ash(location) + qdel(src) + return + + reagents.remove_reagent(/datum/reagent/fuel, reagents.maximum_volume/25) + update_name() + burn_time-- diff --git a/code/modules/detectivework/tools/sample_kits.dm b/code/modules/detectivework/tools/sample_kits.dm new file mode 100644 index 00000000..ca8b85d0 --- /dev/null +++ b/code/modules/detectivework/tools/sample_kits.dm @@ -0,0 +1,170 @@ +/obj/item/weapon/sample + name = "forensic sample" + icon = 'icons/obj/forensics.dmi' + item_flags = ITEM_FLAG_NO_PRINT + w_class = ITEM_SIZE_TINY + var/list/evidence = list() + +/obj/item/weapon/sample/New(var/newloc, var/atom/supplied) + ..(newloc) + if(supplied) + copy_evidence(supplied) + name = "[initial(name)] (\the [supplied])" + +/obj/item/weapon/sample/print/New(var/newloc, var/atom/supplied) + ..(newloc, supplied) + if(evidence && evidence.len) + icon_state = "fingerprint1" + +/obj/item/weapon/sample/proc/copy_evidence(var/atom/supplied) + if(supplied.suit_fibers && supplied.suit_fibers.len) + evidence = supplied.suit_fibers.Copy() + supplied.suit_fibers.Cut() + +/obj/item/weapon/sample/proc/merge_evidence(var/obj/item/weapon/sample/supplied, var/mob/user) + if(!supplied.evidence || !supplied.evidence.len) + return 0 + evidence |= supplied.evidence + SetName("[initial(name)] (combined)") + to_chat(user, "You transfer the contents of \the [supplied] into \the [src].") + return 1 + +/obj/item/weapon/sample/print/merge_evidence(var/obj/item/weapon/sample/supplied, var/mob/user) + if(!supplied.evidence || !supplied.evidence.len) + return 0 + for(var/print in supplied.evidence) + if(evidence[print]) + evidence[print] = stringmerge(evidence[print],supplied.evidence[print]) + else + evidence[print] = supplied.evidence[print] + SetName("[initial(name)] (combined)") + to_chat(user, "You overlay \the [src] and \the [supplied], combining the print records.") + return 1 + +/obj/item/weapon/sample/resolve_attackby(atom/A, mob/user, var/click_params) + // Fingerprints will be handled in after_attack() to not mess up the samples taken + return A.attackby(src, user, click_params) + +/obj/item/weapon/sample/attackby(var/obj/O, var/mob/user) + if(O.type == src.type) + user.unEquip(O) + if(merge_evidence(O, user)) + qdel(O) + return 1 + return ..() + +/obj/item/weapon/sample/fibers + name = "fiber bag" + desc = "Used to hold fiber evidence for the detective." + icon_state = "fiberbag" + +/obj/item/weapon/sample/print + name = "fingerprint card" + desc = "Records a set of fingerprints." + icon = 'icons/obj/card.dmi' + icon_state = "fingerprint0" + item_state = "paper" + +/obj/item/weapon/sample/print/attack_self(var/mob/user) + if(evidence && evidence.len) + return + if(!ishuman(user)) + return + var/mob/living/carbon/human/H = user + if(H.gloves) + to_chat(user, "Take \the [H.gloves] off first.") + return + + to_chat(user, "You firmly press your fingertips onto the card.") + var/fullprint = H.get_full_print() + evidence[fullprint] = fullprint + SetName("[initial(name)] (\the [H])") + icon_state = "fingerprint1" + +/obj/item/weapon/sample/print/attack(var/mob/living/M, var/mob/user) + + if(!ishuman(M)) + return ..() + + if(evidence && evidence.len) + return 0 + + var/mob/living/carbon/human/H = M + + if(H.gloves) + to_chat(user, "\The [H] is wearing gloves.") + return 1 + + if(user != H && H.a_intent != I_HELP && !H.lying) + user.visible_message("\The [user] tries to take prints from \the [H], but they move away.") + return 1 + + if(user.zone_sel.selecting == BP_R_HAND || user.zone_sel.selecting == BP_L_HAND) + var/has_hand + var/obj/item/organ/external/O = H.organs_by_name[BP_R_HAND] + if(istype(O) && !O.is_stump()) + has_hand = 1 + else + O = H.organs_by_name[BP_L_HAND] + if(istype(O) && !O.is_stump()) + has_hand = 1 + if(!has_hand) + to_chat(user, "They don't have any hands.") + return 1 + user.visible_message("[user] takes a copy of \the [H]'s fingerprints.") + var/fullprint = H.get_full_print() + evidence[fullprint] = fullprint + copy_evidence(src) + SetName("[initial(name)] (\the [H])") + icon_state = "fingerprint1" + return 1 + return 0 + +/obj/item/weapon/sample/print/copy_evidence(var/atom/supplied) + if(supplied.fingerprints && supplied.fingerprints.len) + for(var/print in supplied.fingerprints) + evidence[print] = supplied.fingerprints[print] + supplied.fingerprints.Cut() + +/obj/item/weapon/forensics + item_flags = ITEM_FLAG_NO_PRINT + +/obj/item/weapon/forensics/sample_kit + name = "fiber collection kit" + desc = "A magnifying glass and tweezers. Used to lift suit fibers." + icon_state = "m_glass" + w_class = ITEM_SIZE_SMALL + var/evidence_type = "fiber" + var/evidence_path = /obj/item/weapon/sample/fibers + +/obj/item/weapon/forensics/sample_kit/proc/can_take_sample(var/mob/user, var/atom/supplied) + return (supplied.suit_fibers && supplied.suit_fibers.len) + +/obj/item/weapon/forensics/sample_kit/proc/take_sample(var/mob/user, var/atom/supplied) + var/obj/item/weapon/sample/S = new evidence_path(get_turf(user), supplied) + to_chat(user, "You transfer [S.evidence.len] [S.evidence.len > 1 ? "[evidence_type]s" : "[evidence_type]"] to \the [S].") + +/obj/item/weapon/forensics/sample_kit/afterattack(var/atom/A, var/mob/user, var/proximity) + if(!proximity) + return + if(can_take_sample(user, A)) + take_sample(user,A) + . = 1 + else + to_chat(user, "You are unable to locate any [evidence_type]s on \the [A].") + . = ..() + A.add_fingerprint(user) + +/obj/item/weapon/forensics/sample_kit/MouseDrop(atom/over) + if(ismob(src.loc) && CanMouseDrop(over)) + afterattack(over, usr, TRUE) + +/obj/item/weapon/forensics/sample_kit/powder + name = "fingerprint powder" + desc = "A jar containing aluminum powder and a specialized brush." + icon_state = "dust" + evidence_type = "fingerprint" + evidence_path = /obj/item/weapon/sample/print + +/obj/item/weapon/forensics/sample_kit/powder/can_take_sample(var/mob/user, var/atom/supplied) + return (supplied.fingerprints && supplied.fingerprints.len) diff --git a/code/modules/detectivework/tools/storage.dm b/code/modules/detectivework/tools/storage.dm new file mode 100644 index 00000000..ed6664c2 --- /dev/null +++ b/code/modules/detectivework/tools/storage.dm @@ -0,0 +1,18 @@ +/obj/item/weapon/storage/box/swabs + name = "box of swab kits" + desc = "Sterilized equipment within. Do not contaminate." + icon = 'icons/obj/forensics.dmi' + icon_state = "dnakit" + startswith = list(/obj/item/weapon/forensics/swab = DEFAULT_BOX_STORAGE) + +/obj/item/weapon/storage/box/evidence + name = "evidence bag box" + desc = "A box claiming to contain evidence bags." + startswith = list(/obj/item/weapon/evidencebag = 7) + +/obj/item/weapon/storage/box/fingerprints + name = "box of fingerprint cards" + desc = "Sterilized equipment within. Do not contaminate." + icon = 'icons/obj/forensics.dmi' + icon_state = "dnakit" + startswith = list(/obj/item/weapon/sample/print = DEFAULT_BOX_STORAGE) diff --git a/code/modules/detectivework/tools/swabs.dm b/code/modules/detectivework/tools/swabs.dm new file mode 100644 index 00000000..fdcd443d --- /dev/null +++ b/code/modules/detectivework/tools/swabs.dm @@ -0,0 +1,120 @@ +/obj/item/weapon/forensics/swab + name = "swab kit" + desc = "A sterilized cotton swab and vial used to take forensic samples." + icon_state = "swab" + var/gsr = 0 + var/list/dna + var/used + +/obj/item/weapon/forensics/swab/proc/is_used() + return used + +/obj/item/weapon/forensics/swab/attack(var/mob/living/M, var/mob/user) + + if(!ishuman(M)) + return ..() + + if(is_used()) + return + + var/mob/living/carbon/human/H = M + var/sample_type + + if(H.wear_mask) + to_chat(user, "\The [H] is wearing a mask.") + return + + if(!H.dna || !H.dna.unique_enzymes) + to_chat(user, "They don't seem to have DNA!") + return + + if(user != H && H.a_intent != I_HELP && !H.lying) + user.visible_message("\The [user] tries to take a swab sample from \the [H], but they move away.") + return + + if(user.zone_sel.selecting == BP_MOUTH) + if(!H.organs_by_name[BP_HEAD]) + to_chat(user, "They don't have a head.") + return + if(!H.check_has_mouth()) + to_chat(user, "They don't have a mouth.") + return + user.visible_message("[user] swabs \the [H]'s mouth for a saliva sample.") + dna = list(H.dna.unique_enzymes) + sample_type = "DNA" + + else if(user.zone_sel.selecting == BP_R_HAND || user.zone_sel.selecting == BP_L_HAND) + var/has_hand + var/obj/item/organ/external/O = H.organs_by_name[BP_R_HAND] + if(istype(O) && !O.is_stump()) + has_hand = 1 + else + O = H.organs_by_name[BP_L_HAND] + if(istype(O) && !O.is_stump()) + has_hand = 1 + if(!has_hand) + to_chat(user, "They don't have any hands.") + return + user.visible_message("[user] swabs [H]'s palm for a sample.") + sample_type = "GSR" + gsr = H.gunshot_residue + else + return + + if(sample_type) + set_used(sample_type, H) + return + return 1 + +/obj/item/weapon/forensics/swab/afterattack(var/atom/A, var/mob/user, var/proximity) + + if(!proximity || istype(A, /obj/machinery/dnaforensics)) + return + + if(is_used()) + to_chat(user, "This swab has already been used.") + return + + add_fingerprint(user) + + var/list/choices = list() + if(A.blood_DNA) + choices |= "Blood" + if(istype(A, /obj/item/clothing)) + choices |= "Gunshot Residue" + + var/choice + if(!choices.len) + to_chat(user, "There is no evidence on \the [A].") + return + else if(choices.len == 1) + choice = choices[1] + else + choice = input("What kind of evidence are you looking for?","Evidence Collection") as null|anything in choices + + if(!choice) + return + + var/sample_type + if(choice == "Blood") + if(!A.blood_DNA || !A.blood_DNA.len) return + dna = A.blood_DNA.Copy() + sample_type = "blood" + + else if(choice == "Gunshot Residue") + var/obj/item/clothing/B = A + if(!istype(B) || !B.gunshot_residue) + to_chat(user, "There is no residue on \the [A].") + return + gsr = B.gunshot_residue + sample_type = "residue" + + if(sample_type) + user.visible_message("\The [user] swabs \the [A] for a sample.", "You swab \the [A] for a sample.") + set_used(sample_type, A) + +/obj/item/weapon/forensics/swab/proc/set_used(var/sample_str, var/atom/source) + SetName("[initial(name)] ([sample_str] - [source])") + desc = "[initial(desc)] The label on the vial reads 'Sample of [sample_str] from [source].'." + icon_state = "swab_used" + used = 1 diff --git a/code/modules/detectivework/tools/uvlight.dm b/code/modules/detectivework/tools/uvlight.dm new file mode 100644 index 00000000..c43a32bc --- /dev/null +++ b/code/modules/detectivework/tools/uvlight.dm @@ -0,0 +1,70 @@ +/obj/item/device/uv_light + name = "\improper UV light" + desc = "A small handheld black light." + icon_state = "uv_off" + slot_flags = SLOT_BELT + w_class = ITEM_SIZE_SMALL + item_state = "electronic" + action_button_name = "Toggle UV light" + matter = list(DEFAULT_WALL_MATERIAL = 150) + origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1) + + var/list/scanned = list() + var/list/stored_alpha = list() + var/list/reset_objects = list() + + var/range = 3 + var/on = 0 + var/step_alpha = 50 + +/obj/item/device/uv_light/attack_self(var/mob/user) + on = !on + if(on) + set_light(range, 2, "#007fff") + START_PROCESSING(SSobj, src) + icon_state = "uv_on" + else + set_light(0) + clear_last_scan() + STOP_PROCESSING(SSobj, src) + icon_state = "uv_off" + +/obj/item/device/uv_light/proc/clear_last_scan() + if(scanned.len) + for(var/atom/O in scanned) + O.set_invisibility(scanned[O]) + if(O.fluorescent == 2) O.fluorescent = 1 + scanned.Cut() + if(stored_alpha.len) + for(var/atom/O in stored_alpha) + O.alpha = stored_alpha[O] + if(O.fluorescent == 2) O.fluorescent = 1 + stored_alpha.Cut() + if(reset_objects.len) + for(var/obj/item/I in reset_objects) + I.overlays -= I.blood_overlay + if(I.fluorescent == 2) I.fluorescent = 1 + reset_objects.Cut() + +/obj/item/device/uv_light/Process() + clear_last_scan() + if(on) + step_alpha = round(255/range) + var/turf/origin = get_turf(src) + if(!origin) + return + for(var/turf/T in range(range, origin)) + var/use_alpha = 255 - (step_alpha * get_dist(origin, T)) + for(var/atom/A in T.contents) + if(A.fluorescent == 1) + A.fluorescent = 2 //To prevent light crosstalk. + if(A.invisibility) + scanned[A] = A.invisibility + A.set_invisibility(0) + stored_alpha[A] = A.alpha + A.alpha = use_alpha + if(istype(A, /obj/item)) + var/obj/item/O = A + if(O.was_bloodied && !(O.blood_overlay in O.overlays)) + O.overlays |= O.blood_overlay + reset_objects |= O \ No newline at end of file diff --git a/code/modules/economy/ATM.dm b/code/modules/economy/ATM.dm new file mode 100644 index 00000000..89a0dda8 --- /dev/null +++ b/code/modules/economy/ATM.dm @@ -0,0 +1,438 @@ +#define NO_SCREEN 0 +#define CHANGE_SECURITY_LEVEL 1 +#define TRANSFER_FUNDS 2 +#define VIEW_TRANSACTION_LOGS 3 + +/obj/item/weapon/card/id/var/money = 2000 + +/obj/machinery/atm + name = "Automatic Teller Machine" + desc = "For all your monetary needs!" + icon = 'icons/obj/terminals.dmi' + icon_state = "atm" + anchored = 1 + use_power = 1 + idle_power_usage = 10 + var/datum/money_account/authenticated_account + var/number_incorrect_tries = 0 + var/previous_account_number = 0 + var/max_pin_attempts = 3 + var/ticks_left_locked_down = 0 + var/ticks_left_timeout = 0 + var/machine_id = "" + var/obj/item/weapon/card/held_card + var/editing_security_level = 0 + var/view_screen = NO_SCREEN + var/datum/effect/effect/system/spark_spread/spark_system + var/account_security_level = 0 + +/obj/machinery/atm/New() + ..() + machine_id = "[station_name()] ATM #[num_financial_terminals++]" + spark_system = new /datum/effect/effect/system/spark_spread + spark_system.set_up(5, 0, src) + spark_system.attach(src) + +/obj/machinery/atm/Process() + if(stat & NOPOWER) + return + + if(ticks_left_timeout > 0) + ticks_left_timeout-- + if(ticks_left_timeout <= 0) + authenticated_account = null + if(ticks_left_locked_down > 0) + ticks_left_locked_down-- + if(ticks_left_locked_down <= 0) + number_incorrect_tries = 0 + + for(var/obj/item/weapon/spacecash/S in src) + S.loc = src.loc + if(prob(50)) + playsound(loc, 'sound/items/polaroid1.ogg', 50, 1) + else + playsound(loc, 'sound/items/polaroid2.ogg', 50, 1) + break + +/obj/machinery/atm/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + //short out the machine, shoot sparks, spew money! + emagged = 1 + spark_system.start() + spawn_money(rand(100,500),src.loc) + //we don't want to grief people by locking their id in an emagged ATM + release_held_id(user) + + //display a message to the user + var/response = pick("Initiating withdraw. Have a nice day!", "CRITICAL ERROR: Activating cash chamber panic siphon.","PIN Code accepted! Emptying account balance.", "Jackpot!") + to_chat(user, "\icon[src] The [src] beeps: \"[response]\"") + return 1 + +/obj/machinery/atm/attackby(obj/item/I as obj, mob/user as mob) + if(istype(I, /obj/item/weapon/card)) + if(emagged > 0) + //prevent inserting id into an emagged ATM + to_chat(user, "\icon[src] CARD READER ERROR. This system has been compromised!") + return + + var/obj/item/weapon/card/id/idcard = I + if(!held_card) + usr.drop_item() + idcard.loc = src + held_card = idcard + if(authenticated_account && held_card.associated_account_number != authenticated_account.account_number) + authenticated_account = null + attack_hand(user) + + else if(authenticated_account) + if(istype(I,/obj/item/weapon/spacecash)) + var/obj/item/weapon/spacecash/dolla = I + if(prob(50)) + playsound(loc, 'sound/items/polaroid1.ogg', 50, 1) + else + playsound(loc, 'sound/items/polaroid2.ogg', 50, 1) + + //create a transaction log entry + var/datum/transaction/T = new(authenticated_account.owner_name, "Credit deposit", dolla.worth, machine_id) + authenticated_account.do_transaction(T) + + to_chat(user, "You insert [I] into [src].") + src.attack_hand(user) + qdel(I) + else + ..() + +/obj/machinery/atm/attack_hand(mob/user) + if(!..()) + interact(user) + +/obj/machinery/atm/interact(mob/user) + + if(istype(user, /mob/living/silicon)) + to_chat(user, "\icon[src] Artificial unit recognized. Artificial units do not currently receive monetary compensation, as per system banking regulation #1005.") + return + + if(get_dist(src,user) <= 1) + //make the window the user interacts with, divided out into welcome message, card 'slot', then login/data screen + var/list/t = list() + + if(authenticated_account) + t += "Welcome [authenticated_account.owner_name].
            " + else + t += "Welcome. Please login below.
            " + + t += "
            Card: " + if(emagged > 0) + t += "LOCKED
            Unauthorized terminal access detected!
            This ATM has been locked down.

            " + else + t += "[held_card ? held_card.name : "No card inserted"]
            " + t += "
            " + if(authenticated_account) + if(authenticated_account.suspended) + t += "Access to this account has been suspended, and the funds within frozen.
            " + else + switch(view_screen) + if(VIEW_TRANSACTION_LOGS) + t += "Transaction logs
            " + t += "
            Body " + . += "(®)" + . += "
            " + //. += "Species: [pref.species]
            " + . += "Blood Type: [pref.b_type]
            " + + //if(has_flag(mob_species, HAS_BASE_SKIN_COLOURS)) + // . += "Base Colour: [pref.s_base]
            " + + if(has_flag(mob_species, HAS_A_SKIN_TONE)) + . += "Skin Tone: [-pref.s_tone + 35]/[mob_species.max_skin_tone()]
            " + + + //. += "Needs Glasses: [pref.disabilities & NEARSIGHTED ? "Yes" : "No"]
            " + //. += "Limbs: Adjust Reset
            " + //. += "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(BP_L_ARM) + organ_name = "left arm" + if(BP_R_ARM) + organ_name = "right arm" + if(BP_L_LEG) + organ_name = "left leg" + if(BP_R_LEG) + organ_name = "right leg" + if(BP_L_FOOT) + organ_name = "left foot" + if(BP_R_FOOT) + organ_name = "right foot" + if(BP_L_HAND) + organ_name = "left hand" + if(BP_R_HAND) + organ_name = "right hand" + if(BP_HEART) + organ_name = BP_HEART + if(BP_EYES) + organ_name = BP_EYES + if(BP_BRAIN) + organ_name = BP_BRAIN + if(BP_LUNGS) + organ_name = BP_LUNGS + if(BP_LIVER) + organ_name = BP_LIVER + if(BP_KIDNEYS) + organ_name = BP_KIDNEYS + if(BP_CHEST) + organ_name = "upper body" + if(BP_GROIN) + organ_name = "lower body" + if(BP_HEAD) + organ_name = "head" + + 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] prosthesis" + else if(status == "amputated") + ++ind + if(ind > 1) + . += ", " + . += "\tAmputated [organ_name]" + else if(status == "mechanical") + ++ind + if(ind > 1) + . += ", " + if(organ_name == BP_BRAIN) + . += "\tPositronic [organ_name]" + else + . += "\tSynthetic [organ_name]" + else if(status == "assisted") + ++ind + if(ind > 1) + . += ", " + switch(organ_name) + if(BP_HEART) + . += "\tPacemaker-assisted [organ_name]" + if("voicebox") //on adding voiceboxes for speaking skrell/similar replacements + . += "\tSurgically altered [organ_name]" + if(BP_EYES) + . += "\tRetinal overlayed [organ_name]" + if(BP_BRAIN) + . += "\tMachine-interface [organ_name]" + else + . += "\tMechanically assisted [organ_name]" + if(!ind) + . += "\[...\]

            " + else + . += "

            " + + . += "
            Preview
            " + . += "

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

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

            " + + . += "
            Body Markings +
            " + for(var/M in pref.body_markings) + . += "[M] - Color" + . += "
            __
            " + . += "
            " + + . = jointext(.,null) + +/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/datum/species/mob_species = all_species[pref.species] + + if(href_list["random"]) + pref.randomize_appearance_and_body_for() + return TOPIC_REFRESH_UPDATE_PREVIEW + + else if(href_list["toggle_stack"]) + pref.has_cortical_stack = !pref.has_cortical_stack + return TOPIC_REFRESH + + else if(href_list["blood_type"]) + var/new_b_type = input(user, "Choose your character's blood-type:", CHARACTER_PREFERENCE_INPUT_TITLE) 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()) + 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) + mob_species = all_species[pref.species] + if(!(pref.gender in mob_species.genders)) + pref.gender = mob_species.genders[1] + + ResetAllHair() + + //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 + pref.age = max(min(pref.age, mob_species.max_age), mob_species.min_age) + + reset_limbs() // Safety for species with incompatible manufacturers; easier than trying to do it case by case. + pref.body_markings.Cut() // Basically same as above. + + prune_occupation_prefs() + return TOPIC_REFRESH_UPDATE_PREVIEW + + 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_INPUT_TITLE, rgb(pref.r_hair, pref.g_hair, pref.b_hair)) as color|null + if(new_hair && has_flag(all_species[pref.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_UPDATE_PREVIEW + + else if(href_list["hair_style"]) + var/list/valid_hairstyles = mob_species.get_hair_styles() + var/new_h_style = input(user, "Choose your character's hair style:", CHARACTER_PREFERENCE_INPUT_TITLE, pref.h_style) as null|anything in valid_hairstyles + + mob_species = all_species[pref.species] + if(new_h_style && CanUseTopic(user) && (new_h_style in mob_species.get_hair_styles())) + pref.h_style = new_h_style + return TOPIC_REFRESH_UPDATE_PREVIEW + + 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_INPUT_TITLE, rgb(pref.r_facial, pref.g_facial, pref.b_facial)) as color|null + if(new_facial && has_flag(all_species[pref.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_UPDATE_PREVIEW + + 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_INPUT_TITLE, rgb(pref.r_eyes, pref.g_eyes, pref.b_eyes)) as color|null + if(new_eyes && has_flag(all_species[pref.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_UPDATE_PREVIEW + + else if(href_list["base_skin"]) + if(!has_flag(mob_species, HAS_BASE_SKIN_COLOURS)) + return TOPIC_NOACTION + var/new_s_base = input(user, "Choose your character's base colour:", CHARACTER_PREFERENCE_INPUT_TITLE) as null|anything in mob_species.base_skin_colours + if(new_s_base && CanUseTopic(user)) + pref.s_base = new_s_base + return TOPIC_REFRESH_UPDATE_PREVIEW + + else if(href_list["skin_tone"]) + if(!has_flag(mob_species, HAS_A_SKIN_TONE)) + return TOPIC_NOACTION + var/new_s_tone = input(user, "Choose your character's skin-tone. Lower numbers are lighter, higher are darker. Range: 1 to [mob_species.max_skin_tone()]", CHARACTER_PREFERENCE_INPUT_TITLE, (-pref.s_tone) + 35) as num|null + mob_species = all_species[pref.species] + if(new_s_tone && has_flag(mob_species, HAS_A_SKIN_TONE) && CanUseTopic(user)) + pref.s_tone = 35 - max(min(round(new_s_tone), mob_species.max_skin_tone()), 1) + return TOPIC_REFRESH_UPDATE_PREVIEW + + 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_INPUT_TITLE, rgb(pref.r_skin, pref.g_skin, pref.b_skin)) as color|null + if(new_skin && has_flag(all_species[pref.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_UPDATE_PREVIEW + + else if(href_list["facial_style"]) + var/list/valid_facialhairstyles = mob_species.get_facial_hair_styles(pref.gender) + + var/new_f_style = input(user, "Choose your character's facial-hair style:", CHARACTER_PREFERENCE_INPUT_TITLE, pref.f_style) as null|anything in valid_facialhairstyles + + mob_species = all_species[pref.species] + if(new_f_style && CanUseTopic(user) && mob_species.get_facial_hair_styles(pref.gender)) + pref.f_style = new_f_style + return TOPIC_REFRESH_UPDATE_PREVIEW + + else if(href_list["marking_style"]) + var/list/usable_markings = pref.body_markings.Copy() ^ GLOB.body_marking_styles_list.Copy() + for(var/M in usable_markings) + var/datum/sprite_accessory/S = usable_markings[M] + if(!S.species_allowed.len) + continue + else if(!(pref.species in S.species_allowed)) + usable_markings -= M + + var/new_marking = input(user, "Choose a body marking:", CHARACTER_PREFERENCE_INPUT_TITLE) as null|anything in usable_markings + if(new_marking && CanUseTopic(user)) + pref.body_markings[new_marking] = "#000000" //New markings start black + return TOPIC_REFRESH_UPDATE_PREVIEW + + else if(href_list["marking_remove"]) + var/M = href_list["marking_remove"] + pref.body_markings -= M + return TOPIC_REFRESH_UPDATE_PREVIEW + + else if(href_list["marking_color"]) + var/M = href_list["marking_color"] + var/mark_color = input(user, "Choose the [M] color: ", CHARACTER_PREFERENCE_INPUT_TITLE, pref.body_markings[M]) as color|null + if(mark_color && CanUseTopic(user)) + pref.body_markings[M] = "[mark_color]" + return TOPIC_REFRESH_UPDATE_PREVIEW + + else if(href_list["reset_limbs"]) + reset_limbs() + return TOPIC_REFRESH_UPDATE_PREVIEW + + else if(href_list["limbs"]) + + var/list/limb_selection_list = list("Left Leg","Right Leg","Left Arm","Right Arm","Left Foot","Right Foot","Left Hand","Right Hand","Full Body") + + // Full prosthetic bodies without a brain are borderline unkillable so make sure they have a brain to remove/destroy. + var/datum/species/current_species = all_species[pref.species] + if(current_species.spawn_flags & SPECIES_NO_FBP_CHARGEN) + limb_selection_list -= "Full Body" + else if(pref.organ_data[BP_CHEST] == "cyborg") + limb_selection_list |= "Head" + + var/organ_tag = input(user, "Which limb do you want to change?") as null|anything in limb_selection_list + + if(!organ_tag || !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 + + // Do not let them amputate their entire body, ty. + var/list/choice_options = list("Normal","Amputated","Prosthesis") + + //Dare ye who decides to one day make fbps be able to have fleshy bits. Heed my warning, recursion is a bitch. - Snapshot + if(pref.organ_data[BP_CHEST] == "cyborg") + choice_options = list("Amputated", "Prosthesis") + + switch(organ_tag) + if("Left Leg") + limb = BP_L_LEG + second_limb = BP_L_FOOT + if("Right Leg") + limb = BP_R_LEG + second_limb = BP_R_FOOT + if("Left Arm") + limb = BP_L_ARM + second_limb = BP_L_HAND + if("Right Arm") + limb = BP_R_ARM + second_limb = BP_R_HAND + if("Left Foot") + limb = BP_L_FOOT + third_limb = BP_L_LEG + if("Right Foot") + limb = BP_R_FOOT + third_limb = BP_R_LEG + if("Left Hand") + limb = BP_L_HAND + third_limb = BP_L_ARM + if("Right Hand") + limb = BP_R_HAND + third_limb = BP_R_ARM + if("Head") + limb = BP_HEAD + choice_options = list("Prosthesis") + if("Full Body") + limb = BP_CHEST + third_limb = BP_GROIN + choice_options = list("Normal","Prosthesis") + + var/new_state = input(user, "What state do you wish the limb to be in?") as null|anything in choice_options + if(!new_state || !CanUseTopic(user)) return TOPIC_NOACTION + + switch(new_state) + if("Normal") + if(limb == BP_CHEST) + for(var/other_limb in (BP_ALL_LIMBS - BP_CHEST)) + pref.organ_data[other_limb] = null + pref.rlimb_data[other_limb] = null + for(var/internal_organ in list(BP_HEART,BP_EYES,BP_LUNGS,BP_LIVER,BP_KIDNEYS,BP_BRAIN)) + pref.organ_data[internal_organ] = null + 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") + if(limb == BP_CHEST) + return + 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("Prosthesis") + var/tmp_species = pref.species ? pref.species : 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 + if(M.restricted_to.len && !(tmp_species in M.restricted_to)) + continue + if(M.applies_to_part.len && !(limb in M.applies_to_part)) + 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 + + if(limb == BP_CHEST) + for(var/other_limb in BP_ALL_LIMBS - BP_CHEST) + pref.organ_data[other_limb] = "cyborg" + pref.rlimb_data[other_limb] = choice + if(!pref.organ_data[BP_BRAIN]) + pref.organ_data[BP_BRAIN] = "assisted" + for(var/internal_organ in list(BP_HEART,BP_EYES,BP_LUNGS,BP_LIVER,BP_KIDNEYS)) + pref.organ_data[internal_organ] = "mechanical" + + return TOPIC_REFRESH_UPDATE_PREVIEW + + else if(href_list["organs"]) + var/organ_name = input(user, "Which internal function do you want to change?") as null|anything in list("Heart", "Eyes", "Lungs", "Liver", "Kidneys") + if(!organ_name) return + + var/organ = null + switch(organ_name) + if("Heart") + organ = BP_HEART + if("Eyes") + organ = BP_EYES + if("Lungs") + organ = BP_LUNGS + if("Liver") + organ = BP_LIVER + if("Kidneys") + organ = BP_KIDNEYS + + var/list/organ_choices = list("Normal","Assisted","Synthetic") + if(pref.organ_data[BP_CHEST] == "cyborg") + organ_choices -= "Normal" + organ_choices += "Synthetic" + + var/new_state = input(user, "What state do you wish the organ to be in?") as null|anything in organ_choices + if(!new_state) return + + switch(new_state) + if("Normal") + pref.organ_data[organ] = null + if("Assisted") + pref.organ_data[organ] = "assisted" + if("Synthetic") + 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_UPDATE_PREVIEW + + else if(href_list["toggle_preview_value"]) + pref.equip_preview_mob ^= text2num(href_list["toggle_preview_value"]) + return TOPIC_REFRESH_UPDATE_PREVIEW + + else if(href_list["cycle_bg"]) + pref.bgstate = next_in_list(pref.bgstate, pref.bgstate_options) + return TOPIC_REFRESH_UPDATE_PREVIEW + + return ..() + +/datum/category_item/player_setup_item/general/body/proc/reset_limbs() + pref.organ_data.Cut() + pref.rlimb_data.Cut() + +/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 = SPECIES_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.get_icobase())) + usr << browse_rsc(icon(current_species.get_icobase(),"preview"), "species_preview_[current_species.name].png") + dat += "

            " + dat += "Language: [current_species.language]
            " + dat += "" + if(current_species.spawn_flags & SPECIES_CAN_JOIN) + dat += "
            Often present among humans." + if(current_species.spawn_flags & SPECIES_IS_WHITELISTED) + dat += "
            Whitelist restricted." + if(!current_species.has_organ[BP_HEART]) + dat += "
            Does not have blood." + if(!current_species.has_organ[BP_LUNGS]) + dat += "
            Does not breathe." + if(current_species.species_flags & SPECIES_FLAG_NO_SCAN) + dat += "
            Does not have DNA." + if(current_species.species_flags & SPECIES_FLAG_NO_PAIN) + dat += "
            Does not feel pain." + if(current_species.species_flags & SPECIES_FLAG_NO_SLIP) + dat += "
            Has excellent traction." + if(current_species.species_flags & SPECIES_FLAG_NO_POISON) + dat += "
            Immune to most poisons." + if(current_species.appearance_flags & HAS_A_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.species_flags & SPECIES_FLAG_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 & SPECIES_CAN_JOIN)) + restricted = 2 + else if((current_species.spawn_flags & SPECIES_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 as a player race.

            " + if(!restricted || check_rights(R_ADMIN, 0)) + dat += "\[select\]" + dat += "
            " + + user << browse(dat, "window=species;size=700x400") + +/datum/category_item/player_setup_item/proc/ResetAllHair() + ResetHair() + ResetFacialHair() + +/datum/category_item/player_setup_item/proc/ResetHair() + var/datum/species/mob_species = all_species[pref.species] + var/list/valid_hairstyles = mob_species.get_hair_styles() + + if(valid_hairstyles.len) + pref.h_style = pick(valid_hairstyles) + else + //this shouldn't happen + pref.h_style = GLOB.hair_styles_list["Bald"] + +/datum/category_item/player_setup_item/proc/ResetFacialHair() + var/datum/species/mob_species = all_species[pref.species] + var/list/valid_facialhairstyles = mob_species.get_facial_hair_styles(pref.gender) + + if(valid_facialhairstyles.len) + pref.f_style = pick(valid_facialhairstyles) + else + //this shouldn't happen + pref.f_style = GLOB.facial_hair_styles_list["Shaved"] diff --git a/code/modules/client/preference_setup/general/04_equipment.dm b/code/modules/client/preference_setup/general/04_equipment.dm new file mode 100644 index 00000000..8146f65b --- /dev/null +++ b/code/modules/client/preference_setup/general/04_equipment.dm @@ -0,0 +1,182 @@ +/datum/preferences + var/list/all_underwear + var/list/all_underwear_metadata + + var/decl/backpack_outfit/backpack + var/list/backpack_metadata + +/datum/category_item/player_setup_item/general/equipment + name = "Clothing" + sort_order = 4 + + var/static/list/backpacks_by_name + +/datum/category_item/player_setup_item/general/equipment/New() + ..() + if(!backpacks_by_name) + backpacks_by_name = list() + var/bos = decls_repository.get_decls_of_subtype(/decl/backpack_outfit) + for(var/bo in bos) + var/decl/backpack_outfit/backpack_outfit = bos[bo] + backpacks_by_name[backpack_outfit.name] = backpack_outfit + +/datum/category_item/player_setup_item/general/equipment/load_character(var/savefile/S) + var/load_backbag + + //from_file(S["all_underwear"], pref.all_underwear) + from_file(S["all_underwear_metadata"], pref.all_underwear_metadata) + from_file(S["backpack"], load_backbag) + from_file(S["backpack_metadata"], pref.backpack_metadata) + + pref.backpack = backpacks_by_name[load_backbag] || get_default_outfit_backpack() + +/datum/category_item/player_setup_item/general/equipment/save_character(var/savefile/S) + //to_file(S["all_underwear"], pref.all_underwear) + to_file(S["all_underwear_metadata"], pref.all_underwear_metadata) + to_file(S["backpack"], pref.backpack.name) + to_file(S["backpack_metadata"], pref.backpack_metadata) + +/datum/category_item/player_setup_item/general/equipment/sanitize_character() + if(!istype(pref.all_underwear)) + pref.all_underwear = list() + + for(var/datum/category_group/underwear/WRC in GLOB.underwear.categories) + for(var/datum/category_item/underwear/WRI in WRC.items) + if(WRI.is_default(pref.gender ? pref.gender : MALE)) + pref.all_underwear[WRC.name] = WRI.name + break + + if(!istype(pref.all_underwear_metadata)) + pref.all_underwear_metadata = list() + + for(var/underwear_category in pref.all_underwear) + var/datum/category_group/underwear/UWC = GLOB.underwear.categories_by_name[underwear_category] + if(!UWC) + pref.all_underwear -= underwear_category + else + var/datum/category_item/underwear/UWI = UWC.items_by_name[pref.all_underwear[underwear_category]] + if(!UWI) + pref.all_underwear -= underwear_category + + for(var/underwear_metadata in pref.all_underwear_metadata) + if(!(underwear_metadata in pref.all_underwear)) + pref.all_underwear_metadata -= underwear_metadata + + if(!pref.backpack || !(pref.backpack.name in backpacks_by_name)) + pref.backpack = get_default_outfit_backpack() + + if(!istype(pref.backpack_metadata)) + pref.backpack_metadata = list() + + for(var/backpack_metadata_name in pref.backpack_metadata) + if(!(backpack_metadata_name in backpacks_by_name)) + pref.backpack_metadata -= backpack_metadata_name + + for(var/backpack_name in backpacks_by_name) + var/decl/backpack_outfit/backpack = backpacks_by_name[backpack_name] + var/list/tweak_metadata = pref.backpack_metadata["[backpack]"] + if(tweak_metadata) + for(var/tw in backpack.tweaks) + var/datum/backpack_tweak/tweak = tw + var/list/metadata = tweak_metadata["[tweak]"] + tweak_metadata["[tweak]"] = tweak.validate_metadata(metadata) + + +/datum/category_item/player_setup_item/general/equipment/content() + /*. = list() + . += "Equipment:
            " + for(var/datum/category_group/underwear/UWC in GLOB.underwear.categories) + var/item_name = (pref.all_underwear && pref.all_underwear[UWC.name]) ? pref.all_underwear[UWC.name] : "None" + . += "[UWC.name]: [item_name]" + + + . += "
            " + . += "Backpack Type: [pref.backpack.name]" + for(var/datum/backpack_tweak/bt in pref.backpack.tweaks) + . += " [bt.get_ui_content(get_backpack_metadata(pref.backpack, bt))]" + . += "
            " + return jointext(.,null) + */ + return + +/datum/category_item/player_setup_item/general/equipment/proc/get_underwear_metadata(var/underwear_category) + var/metadata = pref.all_underwear_metadata[underwear_category] + if(!metadata) + metadata = list() + pref.all_underwear_metadata[underwear_category] = metadata + +/datum/category_item/player_setup_item/general/equipment/proc/get_backpack_metadata(var/decl/backpack_outfit/backpack_outfit, var/datum/backpack_tweak/bt) + var/metadata = pref.backpack_metadata[backpack_outfit.name] + if(!metadata) + metadata = list() + pref.backpack_metadata[backpack_outfit.name] = metadata + + var/tweak_data = metadata["[bt]"] + if(!tweak_data) + tweak_data = bt.get_default_metadata() + metadata["[bt]"] = tweak_data + return tweak_data + +/datum/category_item/player_setup_item/general/equipment/proc/set_underwear_metadata(var/underwear_category,var/new_metadata) + return + +/datum/category_item/player_setup_item/general/equipment/proc/set_backpack_metadata(var/decl/backpack_outfit/backpack_outfit, var/datum/backpack_tweak/bt, var/new_metadata) + var/metadata = pref.backpack_metadata[backpack_outfit.name] + metadata["[bt]"] = new_metadata + +/datum/category_item/player_setup_item/general/equipment/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["change_underwear"]) + var/datum/category_group/underwear/UWC = GLOB.underwear.categories_by_name[href_list["change_underwear"]] + if(!UWC) + return TOPIC_NOACTION + var/datum/category_item/underwear/selected_underwear = input(user, "Choose underwear:", CHARACTER_PREFERENCE_INPUT_TITLE, pref.all_underwear[UWC.name]) as null|anything in UWC.items + if(selected_underwear && CanUseTopic(user)) + pref.all_underwear[UWC.name] = selected_underwear.name + return TOPIC_REFRESH_UPDATE_PREVIEW + else if(href_list["underwear"] && href_list["tweak"]) + var/underwear = href_list["underwear"] + if(!(underwear in pref.all_underwear)) + return TOPIC_NOACTION + + else if(href_list["change_backpack"]) + var/new_backpack = input(user, "Choose backpack style:", CHARACTER_PREFERENCE_INPUT_TITLE, pref.backpack) as null|anything in backpacks_by_name + if(!isnull(new_backpack) && CanUseTopic(user)) + pref.backpack = backpacks_by_name[new_backpack] + return TOPIC_REFRESH_UPDATE_PREVIEW + else if(href_list["backpack"] && href_list["tweak"]) + var/backpack_name = href_list["backpack"] + if(!(backpack_name in backpacks_by_name)) + return TOPIC_NOACTION + var/decl/backpack_outfit/bo = backpacks_by_name[backpack_name] + var/datum/backpack_tweak/bt = locate(href_list["tweak"]) in bo.tweaks + if(!bt) + return TOPIC_NOACTION + var/new_metadata = bt.get_metadata(user, get_backpack_metadata(bo, bt)) + if(new_metadata) + set_backpack_metadata(bo, bt, new_metadata) + return TOPIC_REFRESH_UPDATE_PREVIEW + + return ..() + +/datum/category_item/player_setup_item/general/equipment/update_setup(var/savefile/preferences, var/savefile/character) + if(preferences["version"] <= 16) + var/list/old_index_to_backpack_type = list( + /decl/backpack_outfit/nothing, + /decl/backpack_outfit/backpack, + /decl/backpack_outfit/satchel, + /decl/backpack_outfit/messenger_bag, + /decl/backpack_outfit/satchel, + /decl/backpack_outfit/satchel, + /decl/backpack_outfit/pocketbook + ) + + var/old_index + from_file(character["backbag"], old_index) + + if(old_index > 0 && old_index <= old_index_to_backpack_type.len) + pref.backpack = decls_repository.get_decl(old_index_to_backpack_type[old_index]) + else + pref.backpack = get_default_outfit_backpack() + + to_file(character["backpack"], pref.backpack.name) + return 1 diff --git a/code/modules/client/preference_setup/general/05_background.dm b/code/modules/client/preference_setup/general/05_background.dm new file mode 100644 index 00000000..1a61f57b --- /dev/null +++ b/code/modules/client/preference_setup/general/05_background.dm @@ -0,0 +1,148 @@ +/datum/preferences + var/med_record = "" + var/sec_record = "" + var/gen_record = "" + var/nanotrasen_relation = "Neutral" + var/memory = "" + + //Some faction information. + var/home_system = "Unset" //System of birth. + var/citizenship = "None" //Current home system. + var/faction = "None" //Antag faction/general associated faction. + var/religion = "None" //Religious association. +/* +/datum/category_item/player_setup_item/general/background + name = "Religion" + sort_order = 5 +*/ +/datum/category_item/player_setup_item/general/background/load_character(var/savefile/S) + from_file(S["med_record"],pref.med_record) + from_file(S["sec_record"],pref.sec_record) + from_file(S["gen_record"],pref.gen_record) + from_file(S["home_system"],pref.home_system) + from_file(S["citizenship"],pref.citizenship) + from_file(S["faction"],pref.faction) + from_file(S["religion"],pref.religion) + from_file(S["nanotrasen_relation"],pref.nanotrasen_relation) + from_file(S["memory"],pref.memory) + +/datum/category_item/player_setup_item/general/background/save_character(var/savefile/S) + to_file(S["med_record"],pref.med_record) + to_file(S["sec_record"],pref.sec_record) + to_file(S["gen_record"],pref.gen_record) + to_file(S["home_system"],pref.home_system) + to_file(S["citizenship"],pref.citizenship) + to_file(S["faction"],pref.faction) + to_file(S["religion"],pref.religion) + to_file(S["nanotrasen_relation"],pref.nanotrasen_relation) + to_file(S["memory"],pref.memory) + +/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
            " + . += "[GLOB.using_map.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)]
            " + . += "Memory:
            " + . += "[TextPreview(pref.memory,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 [GLOB.using_map.company_name]. Note that this represents what others can find out about your character by researching your background, not what your character actually thinks.", CHARACTER_PREFERENCE_INPUT_TITLE, 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_INPUT_TITLE, pref.home_system) as null|anything in GLOB.using_map.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_INPUT_TITLE) 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_INPUT_TITLE, pref.citizenship) as null|anything in GLOB.using_map.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_INPUT_TITLE) 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_INPUT_TITLE, pref.faction) as null|anything in GLOB.using_map.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_INPUT_TITLE) 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_INPUT_TITLE, pref.religion) as null|anything in GLOB.using_map.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_INPUT_TITLE) 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_INPUT_TITLE, 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_INPUT_TITLE, 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_INPUT_TITLE, 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 + + else if(href_list["set_memory"]) + var/memes = sanitize(input(user,"Enter memorized information here.",CHARACTER_PREFERENCE_INPUT_TITLE, html_decode(pref.memory)) as message|null, MAX_PAPER_MESSAGE_LEN, extra = 0) + if(!isnull(memes) && CanUseTopic(user)) + pref.memory = memes + 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 new file mode 100644 index 00000000..ecb0e772 --- /dev/null +++ b/code/modules/client/preference_setup/general/06_flavor.dm @@ -0,0 +1,132 @@ +/datum/preferences + var/list/flavor_texts = list() + var/list/flavour_texts_robot = list() + +/*/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 GLOB.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 GLOB.robot_module_types) + S["flavour_texts_robot_[module]"] << pref.flavour_texts_robot[module] + +/datum/category_item/player_setup_item/general/flavor/sanitize_character() + if(!istype(pref.flavor_texts)) pref.flavor_texts = list() + if(!istype(pref.flavour_texts_robot)) pref.flavour_texts_robot = list() + +/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") + 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["flavor_text"]])) 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") + 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 GLOB.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 new file mode 100644 index 00000000..0464806b --- /dev/null +++ b/code/modules/client/preference_setup/global/01_ui.dm @@ -0,0 +1,101 @@ +/datum/preferences + var/clientfps = 60 + var/ooccolor = "#010000" //Whatever this is set to acts as 'reset' color and is thus unusable as an actual custom color + + var/UI_style = "Midnight" + var/UI_style_color = "#ffffff" + var/UI_style_alpha = 255 + +/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 + S["clientfps"] >> pref.clientfps + +/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 + S["clientfps"] << pref.clientfps + +/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)) + pref.clientfps = sanitize_integer(pref.clientfps, CLIENT_MIN_FPS, CLIENT_MAX_FPS, initial(pref.clientfps)) + +/datum/category_item/player_setup_item/player_global/ui/content(var/mob/user) + . += "UI Settings
            " + //. += "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
            " + . += "Client FPS: [pref.clientfps]
            " + +/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_INPUT_TITLE, 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["select_fps"]) + var/version_message + if (user.client && user.client.byond_version < 511) + version_message = "\nYou need to be using byond version 511 or later to take advantage of this feature, your version of [user.client.byond_version] is too low" + if (world.byond_version < 511) + version_message += "\nThis server does not currently support client side fps. You can set now for when it does." + var/new_fps = input(user, "Choose your desired fps.[version_message]\n(0 = synced with server tick rate (currently:[world.fps]))", "Global Preference") as num|null + if (isnum(new_fps) && CanUseTopic(user)) + pref.clientfps = Clamp(new_fps, CLIENT_MIN_FPS, CLIENT_MAX_FPS) + + var/mob/target_mob = preference_mob() + if(target_mob && target_mob.client) + target_mob.client.apply_fps(pref.clientfps) + 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 ..() + +/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_prefixes.dm b/code/modules/client/preference_setup/global/02_prefixes.dm new file mode 100644 index 00000000..e13a98de --- /dev/null +++ b/code/modules/client/preference_setup/global/02_prefixes.dm @@ -0,0 +1,143 @@ +/datum/preferences + var/list/prefix_keys_by_type + +/datum/category_item/player_setup_item/player_global/prefixes + name = "Prefixes" + sort_order = 2 + + var/static/list/prefix_by_name + +/datum/category_item/player_setup_item/player_global/prefixes/New() + ..() + SETUP_SUBTYPE_DECLS_BY_NAME(/decl/prefix, prefix_by_name) + +/datum/category_item/player_setup_item/player_global/prefixes/load_preferences(var/savefile/S) + var/list/prefix_keys_by_name + from_file(S["prefix_keys"], prefix_keys_by_name) + + if(istype(prefix_keys_by_name)) + pref.prefix_keys_by_type = list() + for(var/prefix_name in prefix_keys_by_name) + var/decl/prefix/prefix_instance = prefix_by_name[prefix_name] + if(prefix_instance) + pref.prefix_keys_by_type[prefix_instance.type] = prefix_keys_by_name[prefix_name] + +/datum/category_item/player_setup_item/player_global/prefixes/save_preferences(var/savefile/S) + var/list/prefix_keys_by_name = list() + for(var/prefix_type in pref.prefix_keys_by_type) + var/decl/prefix/prefix_instance = decls_repository.get_decl(prefix_type) + prefix_keys_by_name[prefix_instance.name] = pref.prefix_keys_by_type[prefix_type] + + to_file(S["prefix_keys"], prefix_keys_by_name) + +/datum/category_item/player_setup_item/player_global/prefixes/sanitize_preferences() + if(!istype(pref.prefix_keys_by_type)) + pref.prefix_keys_by_type = list() + + // Setup the default keys for any prefix without one + for(var/prefix_name in prefix_by_name) + var/decl/prefix/prefix_instance = prefix_by_name[prefix_name] + if(!(prefix_instance.type in pref.prefix_keys_by_type)) + pref.prefix_keys_by_type[prefix_instance.type] = prefix_instance.default_key + + // Then check for duplicate keys. + // In case of overlap, all affected prefixes are given their default key + reset_duplicate_keys() + +/datum/category_item/player_setup_item/player_global/prefixes/content(var/mob/user) + . += "Prefix Keys:
            " + . += "" + for(var/prefix_name in prefix_by_name) + var/decl/prefix/prefix_instance = prefix_by_name[prefix_name] + var/current_prefix = pref.prefix_keys_by_type[prefix_instance.type] + + . += "" + . += "
            [prefix_instance.name][pref.prefix_keys_by_type[prefix_instance.type]]" + + if(prefix_instance.is_locked) + . += "Change" + else + + . += "Change" + + . += "" + + if(prefix_instance.is_locked || current_prefix == prefix_instance.default_key) + . += "Reset" + else + . += "Reset" + . += "
            " + +/datum/category_item/player_setup_item/player_global/prefixes/OnTopic(var/href, var/list/href_list, var/mob/user) + if(href_list["change_prefix"]) + var/decl/prefix/prefix_instance = locate(href_list["change_prefix"]) + if(!istype(prefix_instance) || prefix_instance.is_locked) + return TOPIC_NOACTION + + do + var/keys_in_use = list() + for(var/prefix_type in pref.prefix_keys_by_type) + if(prefix_type == prefix_instance.type) + continue + keys_in_use += pref.prefix_keys_by_type[prefix_type] + + var/new_key = input(user, "Enter a single special character. The following characters are already in use as prefixes: [jointext(keys_in_use, " ")]", CHARACTER_PREFERENCE_INPUT_TITLE, pref.prefix_keys_by_type[prefix_instance.type]) as null|text + if(!new_key || new_key == pref.prefix_keys_by_type[prefix_instance.type] || !CanUseTopic(user)) + return TOPIC_NOACTION + + if(length(new_key) != 1) + alert(user, "Only single characters are allowed.", "Error", "Ok") + else if(contains_az09(new_key)) + alert(user, "Only special character are allowed.", "Error", "Ok") + else if(new_key == " ") + alert(user, "The space character is not allowed.", "Error", "Ok") + else + pref.prefix_keys_by_type[prefix_instance.type] = new_key + + // Here we attempt to replace any matching prefix keys with their default value, to allow quick replacements + for(var/prefix_type in pref.prefix_keys_by_type) + if(prefix_type == prefix_instance.type) + continue + var/prefix_key = pref.prefix_keys_by_type[prefix_type] + if(prefix_key == new_key) + var/decl/prefix/pi = decls_repository.get_decl(prefix_type) + pref.prefix_keys_by_type[pi.type] = pi.default_key + // Then we reset any and all duplicates + reset_duplicate_keys() + // Then, if the new key was reset it means it matched a default key. + // If so the user has to select another key, otherwise the selection was successful + if(pref.prefix_keys_by_type[prefix_instance.type] != new_key) + alert(user, "The selected key is already the default key for another prefix.", "Error", "Ok") + else + return TOPIC_REFRESH + while(TRUE) + + else if(href_list["reset_prefix"]) + var/decl/prefix/prefix_instance = locate(href_list["reset_prefix"]) + if(!istype(prefix_instance)) + return TOPIC_NOACTION + pref.prefix_keys_by_type[prefix_instance.type] = prefix_instance.default_key + reset_duplicate_keys() + return TOPIC_REFRESH + + else + return ..() + +/datum/category_item/player_setup_item/player_global/prefixes/proc/reset_duplicate_keys() + var/list/prefixes_by_key = list() + for(var/prefix_type in pref.prefix_keys_by_type) + var/prefix_key = pref.prefix_keys_by_type[prefix_type] + group_by(prefixes_by_key, prefix_key, prefix_type) + + for(var/prefix_key in prefixes_by_key) + var/list/prefix_types = prefixes_by_key[prefix_key] + if(prefix_types.len > 1) + for(var/prefix_type in prefix_types) + var/decl/prefix/prefix_instance = decls_repository.get_decl(prefix_type) + pref.prefix_keys_by_type[prefix_instance.type] = prefix_instance.default_key + +/mob/proc/get_prefix_key(var/prefix_type) + if(client && client.prefs) + return client.prefs.prefix_keys_by_type[prefix_type] + var/decl/prefix/prefix_instance = decls_repository.get_decl(prefix_type) + return prefix_instance.default_key diff --git a/code/modules/client/preference_setup/global/03_pai.dm b/code/modules/client/preference_setup/global/03_pai.dm new file mode 100644 index 00000000..646ae80e --- /dev/null +++ b/code/modules/client/preference_setup/global/03_pai.dm @@ -0,0 +1,63 @@ + +/* +/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) + if(!candidate) + candidate = new() + + . += "pAI:
            " + if(!candidate) + log_debug("[user] pAI prefs have a null candidate var.") + return . + . += "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 ..() +*/ \ No newline at end of file diff --git a/code/modules/client/preference_setup/global/04_ooc.dm b/code/modules/client/preference_setup/global/04_ooc.dm new file mode 100644 index 00000000..cffb3d57 --- /dev/null +++ b/code/modules/client/preference_setup/global/04_ooc.dm @@ -0,0 +1,40 @@ +/datum/preferences + // OOC Metadata: + var/list/ignored_players = list() + +/datum/category_item/player_setup_item/player_global/ooc + name = "OOC" + sort_order = 3 + +/datum/category_item/player_setup_item/player_global/ooc/load_preferences(var/savefile/S) + S["ignored_players"] >> pref.ignored_players + + +/datum/category_item/player_setup_item/player_global/ooc/save_preferences(var/savefile/S) + S["ignored_players"] << pref.ignored_players + + +/datum/category_item/player_setup_item/player_global/ooc/sanitize_preferences() + if(!islist(pref.ignored_players)) + pref.ignored_players = list() + +/datum/category_item/player_setup_item/player_global/ooc/content(var/mob/user) + . += "OOC:
            " + . += "Ignored Players
            " + for(var/ignored_player in pref.ignored_players) + . += "[ignored_player] (Unignore)
            " + . += "(Ignore Player)" + +/datum/category_item/player_setup_item/player_global/ooc/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["unignore_player"]) + pref.ignored_players -= href_list["unignore_player"] + return TOPIC_REFRESH + + if(href_list["ignore_player"]) + var/player_to_ignore = sanitize(ckey(input(user, "Who do you want to ignore?","Ignore") as null|text)) + //input() sleeps while waiting for the user to respond, so we need to check CanUseTopic() again here + if(player_to_ignore && CanUseTopic(user)) + pref.ignored_players |= player_to_ignore + return TOPIC_REFRESH + + return ..() diff --git a/code/modules/client/preference_setup/global/05_settings.dm b/code/modules/client/preference_setup/global/05_settings.dm new file mode 100644 index 00000000..c94bb855 --- /dev/null +++ b/code/modules/client/preference_setup/global/05_settings.dm @@ -0,0 +1,160 @@ +/datum/preferences + var/list/preference_values + +/datum/category_item/player_setup_item/player_global/settings + name = "Settings" + sort_order = 4 + +/datum/category_item/player_setup_item/player_global/settings/load_preferences(var/savefile/S) + from_file(S["lastchangelog"], pref.lastchangelog) + from_file(S["default_slot"], pref.default_slot) + from_file(S["preference_values"], pref.preference_values) + +/datum/category_item/player_setup_item/player_global/settings/save_preferences(var/savefile/S) + to_file(S["lastchangelog"], pref.lastchangelog) + to_file(S["default_slot"], pref.default_slot) + to_file(S["preference_values"], pref.preference_values) + +/datum/category_item/player_setup_item/player_global/settings/update_setup(var/savefile/preferences, var/savefile/character) + if(preferences["version"] < 16) + var/list/preferences_enabled + var/list/preferences_disabled + from_file(preferences["preferences"], preferences_enabled) + from_file(preferences["preferences_disabled"], preferences_disabled) + + if(!istype(preferences_enabled)) + preferences_enabled = list() + if(!istype(preferences_disabled)) + preferences_disabled = list() + + pref.preference_values = list() + for(var/datum/client_preference/cp in get_client_preferences()) + if(cp.key in preferences_enabled) + pref.preference_values[cp.key] = cp.options[1] // for the converted preferences, the truthy value is going to be the first one... + else if(cp.key in preferences_disabled) + pref.preference_values[cp.key] = cp.options[2] // ...and the falsy value the second + else + pref.preference_values[cp.key] = cp.default_value + return 1 + +/datum/category_item/player_setup_item/player_global/settings/sanitize_preferences() + // Ensure our preferences are lists. + if(!istype(pref.preference_values)) + pref.preference_values = list() + + var/list/client_preference_keys = list() + for(var/cp in get_client_preferences()) + var/datum/client_preference/client_pref = cp + + client_preference_keys |= client_pref.key + + // if the preference has never been set, or if the player is no longer allowed to set the it, set it to default + if(!client_pref.may_set(preference_mob()) || !(client_pref.key in pref.preference_values)) + pref.preference_values[client_pref.key] = client_pref.default_value + + + // Clean out preferences that no longer exist. + for(var/key in pref.preference_values) + if(!(key in client_preference_keys)) + pref.preference_values -= key + + 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)) + +/datum/category_item/player_setup_item/player_global/settings/content(var/mob/user) + /*. = list() + . += "Preferences
            " + . += "" + + var/mob/pref_mob = preference_mob() + for(var/cp in get_client_preferences()) + var/datum/client_preference/client_pref = cp + + if(!client_pref.may_set(pref_mob)) + continue + + . += "" + + var/selected_option = pref_mob.get_preference_value(client_pref.key) + for(var/option in client_pref.options) + var/is_selected = selected_option == option + . += "" + + . += "
            [client_pref.description]: [option]" + + . += "
            " + + return jointext(., "") + */ + return + +/datum/category_item/player_setup_item/player_global/settings/OnTopic(var/href,var/list/href_list, var/mob/user) + var/mob/pref_mob = preference_mob() + + if(href_list["pref"] && href_list["value"]) + . = pref_mob.set_preference(href_list["pref"], href_list["value"]) + + if(.) + return TOPIC_REFRESH + + return ..() + +/client/proc/get_preference_value(var/preference) + if(prefs) + var/datum/client_preference/cp = get_client_preference(preference) + if(cp) + return prefs.preference_values[cp.key] + else + return null + else + log_error("Client is lacking preferences: [log_info_line(src)]") + +/client/proc/set_preference(var/preference, var/set_preference) + var/datum/client_preference/cp = get_client_preference(preference) + + if(!cp) + return FALSE + + if((prefs.preference_values[cp.key] != set_preference) && (set_preference in cp.options)) + prefs.preference_values[cp.key] = set_preference + cp.changed(mob, set_preference) + return TRUE + + return FALSE + +/client/proc/cycle_preference(var/preference) + var/datum/client_preference/cp = get_client_preference(preference) + + if(!cp) + return FALSE + + var/next_option = next_in_list(prefs.preference_values[cp.key], cp.options) + return set_preference(preference, next_option) + +/mob/proc/get_preference_value(var/preference) + if(!client) + var/datum/client_preference/cp = get_client_preference(preference) + if(cp) + return cp.default_value + else + return null + + return client.get_preference_value(preference) + +/mob/proc/set_preference(var/preference, var/set_preference) + if(!client) + return FALSE + if(!client.prefs) + log_debug("Client prefs found to be null for mob [src] and client [ckey], this should be investigated.") + return FALSE + + return client.set_preference(preference, set_preference) + +/mob/proc/cycle_preference(var/preference) + if(!client) + return FALSE + if(!client.prefs) + log_debug("Client prefs found to be null for mob [src] and client [ckey], this should be investigated.") + return FALSE + + return client.cycle_preference(preference) \ No newline at end of file diff --git a/code/modules/client/preference_setup/global/preferences.dm b/code/modules/client/preference_setup/global/preferences.dm new file mode 100644 index 00000000..e0926f60 --- /dev/null +++ b/code/modules/client/preference_setup/global/preferences.dm @@ -0,0 +1,232 @@ +GLOBAL_VAR_CONST(PREF_YES, "Yes") +GLOBAL_VAR_CONST(PREF_NO, "No") +GLOBAL_VAR_CONST(PREF_ALL_SPEECH, "All Speech") +GLOBAL_VAR_CONST(PREF_NEARBY, "Nearby") +GLOBAL_VAR_CONST(PREF_ALL_EMOTES, "All Emotes") +GLOBAL_VAR_CONST(PREF_ALL_CHATTER, "All Chatter") +GLOBAL_VAR_CONST(PREF_SHORT, "Short") +GLOBAL_VAR_CONST(PREF_LONG, "Long") +GLOBAL_VAR_CONST(PREF_SHOW, "Show") +GLOBAL_VAR_CONST(PREF_HIDE, "Hide") +GLOBAL_VAR_CONST(PREF_FANCY, "Fancy") +GLOBAL_VAR_CONST(PREF_PLAIN, "Plain") +GLOBAL_VAR_CONST(PREF_PRIMARY, "Primary") +GLOBAL_VAR_CONST(PREF_ALL, "All") +GLOBAL_VAR_CONST(PREF_OFF, "Off") +GLOBAL_VAR_CONST(PREF_BASIC, "Basic") +GLOBAL_VAR_CONST(PREF_FULL, "Full") +GLOBAL_VAR_CONST(PREF_MIDDLE_CLICK, "middle click") +GLOBAL_VAR_CONST(PREF_ALT_CLICK, "alt click") +GLOBAL_VAR_CONST(PREF_CTRL_CLICK, "ctrl click") +GLOBAL_VAR_CONST(PREF_CTRL_SHIFT_CLICK, "ctrl shift click") +GLOBAL_VAR_CONST(PREF_HEAR, "Hear") +GLOBAL_VAR_CONST(PREF_SILENT, "Silent") + +var/list/_client_preferences +var/list/_client_preferences_by_key +var/list/_client_preferences_by_type + +/proc/get_client_preferences() + if(!_client_preferences) + _client_preferences = list() + for(var/ct in subtypesof(/datum/client_preference)) + var/datum/client_preference/client_type = ct + if(initial(client_type.description)) + _client_preferences += new client_type() + return _client_preferences + +/proc/get_client_preference(var/datum/client_preference/preference) + if(istype(preference)) + return preference + if(ispath(preference)) + return get_client_preference_by_type(preference) + return get_client_preference_by_key(preference) + +/proc/get_client_preference_by_key(var/preference) + if(!_client_preferences_by_key) + _client_preferences_by_key = list() + for(var/ct in get_client_preferences()) + var/datum/client_preference/client_pref = ct + _client_preferences_by_key[client_pref.key] = client_pref + return _client_preferences_by_key[preference] + +/proc/get_client_preference_by_type(var/preference) + if(!_client_preferences_by_type) + _client_preferences_by_type = list() + for(var/ct in get_client_preferences()) + var/datum/client_preference/client_pref = ct + _client_preferences_by_type[client_pref.type] = client_pref + return _client_preferences_by_type[preference] + +/datum/client_preference + var/description + var/key + var/list/options = list(GLOB.PREF_YES, GLOB.PREF_NO) + var/default_value + +/datum/client_preference/New() + . = ..() + + if(!default_value) + default_value = options[1] + +/datum/client_preference/proc/may_set(var/mob/preference_mob) + return TRUE + +/datum/client_preference/proc/changed(var/mob/preference_mob, var/new_value) + return + +/********************* +* Player Preferences * +*********************/ + +/datum/client_preference/play_admin_midis + description ="Play admin midis" + key = "SOUND_MIDI" + +/datum/client_preference/play_lobby_music + description ="Play lobby music" + key = "SOUND_LOBBY" + +/datum/client_preference/play_lobby_music/changed(var/mob/preference_mob, var/new_value) + if(new_value == GLOB.PREF_YES) + GLOB.using_map.lobby_music.play_to(preference_mob) + else + sound_to(preference_mob, sound(null, repeat = 0, wait = 0, volume = 85, channel = 1)) + +/datum/client_preference/play_ambiance + description ="Play ambience" + key = "SOUND_AMBIENCE" + +/datum/client_preference/play_ambiance/changed(var/mob/preference_mob, var/new_value) + if(new_value == GLOB.PREF_NO) + sound_to(preference_mob, sound(null, repeat = 0, wait = 0, volume = 0, channel = 1)) + sound_to(preference_mob, sound(null, repeat = 0, wait = 0, volume = 0, channel = 2)) + +/datum/client_preference/ghost_ears + description ="Ghost ears" + key = "CHAT_GHOSTEARS" + options = list(GLOB.PREF_ALL_SPEECH, GLOB.PREF_NEARBY) + +/datum/client_preference/ghost_sight + description ="Ghost sight" + key = "CHAT_GHOSTSIGHT" + options = list(GLOB.PREF_ALL_EMOTES, GLOB.PREF_NEARBY) + +/datum/client_preference/ghost_radio + description ="Ghost radio" + key = "CHAT_GHOSTRADIO" + options = list(GLOB.PREF_ALL_CHATTER, GLOB.PREF_NEARBY) + +/datum/client_preference/ghost_follow_link_length + description ="Ghost Follow Links" + key = "CHAT_GHOSTFOLLOWLINKLENGTH" + options = list(GLOB.PREF_SHORT, GLOB.PREF_LONG) + +/datum/client_preference/chat_tags + description ="Chat tags" + key = "CHAT_SHOWICONS" + options = list(GLOB.PREF_SHOW, GLOB.PREF_HIDE) + +/datum/client_preference/show_typing_indicator + description ="Typing indicator" + key = "SHOW_TYPING" + options = list(GLOB.PREF_SHOW, GLOB.PREF_HIDE) + +/datum/client_preference/show_typing_indicator/changed(var/mob/preference_mob, var/new_value) + if(new_value == GLOB.PREF_HIDE) + QDEL_NULL(preference_mob.typing_indicator) + +/datum/client_preference/show_ooc + description ="OOC chat" + key = "CHAT_OOC" + options = list(GLOB.PREF_SHOW, GLOB.PREF_HIDE) + +/datum/client_preference/show_looc + description ="LOOC chat" + key = "CHAT_LOOC" + options = list(GLOB.PREF_SHOW, GLOB.PREF_HIDE) + +/datum/client_preference/show_dsay + description ="Dead chat" + key = "CHAT_DEAD" + options = list(GLOB.PREF_SHOW, GLOB.PREF_HIDE) + +/datum/client_preference/show_progress_bar + description ="Progress Bar" + key = "SHOW_PROGRESS" + options = list(GLOB.PREF_SHOW, GLOB.PREF_HIDE) + +/datum/client_preference/tooltip + description = "Toggle Maptext" + key = "TOOLTIP" + options = list(GLOB.PREF_YES, GLOB.PREF_NO) + +/datum/client_preference/tooltip/changed(mob/preference_mob, new_value) + if (!preference_mob.client) + return + + if (new_value == GLOB.PREF_YES) + preference_mob.client.tooltip.alpha = 255 + else + preference_mob.client.tooltip.alpha = 0 + +/datum/client_preference/floating_messages + description ="Floating chat messages" + key = "FLOATING_CHAT" + options = list(GLOB.PREF_SHOW, GLOB.PREF_HIDE) + +/datum/client_preference/smooth_zoom + description = "Smooth Zooming" + key = "SMOOTH_ZOOM" + options = list(GLOB.PREF_YES, GLOB.PREF_NO) + +/******************** +* General Staff Preferences * +********************/ + +/datum/client_preference/staff + var/flags + +/datum/client_preference/staff/may_set(var/mob/preference_mob) + if(flags) + return check_rights(flags, 0, preference_mob) + else + return preference_mob && preference_mob.client && preference_mob.client.holder + +/datum/client_preference/staff/show_chat_prayers + description = "Chat Prayers" + key = "CHAT_PRAYER" + options = list(GLOB.PREF_SHOW, GLOB.PREF_HIDE) + +/datum/client_preference/staff/play_adminhelp_ping + description = "Adminhelps" + key = "SOUND_ADMINHELP" + options = list(GLOB.PREF_HEAR, GLOB.PREF_SILENT) + +/datum/client_preference/staff/show_rlooc + description ="Remote LOOC chat" + key = "CHAT_RLOOC" + options = list(GLOB.PREF_SHOW, GLOB.PREF_HIDE) + +/******************** +* Admin Preferences * +********************/ + +/datum/client_preference/staff/show_attack_logs + description = "Attack Log Messages" + key = "CHAT_ATTACKLOGS" + options = list(GLOB.PREF_SHOW, GLOB.PREF_HIDE) + flags = R_ADMIN + default_value = GLOB.PREF_HIDE + +/******************** +* Debug Preferences * +********************/ + +/datum/client_preference/staff/show_debug_logs + description = "Debug Log Messages" + key = "CHAT_DEBUGLOGS" + options = list(GLOB.PREF_SHOW, GLOB.PREF_HIDE) + default_value = GLOB.PREF_HIDE + flags = R_ADMIN|R_DEBUG diff --git a/code/modules/client/preference_setup/global/prefixes.dm b/code/modules/client/preference_setup/global/prefixes.dm new file mode 100644 index 00000000..d9b165f2 --- /dev/null +++ b/code/modules/client/preference_setup/global/prefixes.dm @@ -0,0 +1,29 @@ +/decl/prefix + var/name + var/default_key + var/is_locked = FALSE + +/decl/prefix/language + name = "Language" + default_key = "," + +/decl/prefix/radio_channel_selection + name = "Radio, channel selection" + default_key = ":" + is_locked = TRUE + +/decl/prefix/radio_main_channel + name = "Radio, main channel" + default_key = ";" + +/decl/prefix/audible_emote + name = "Emote, audible" + default_key = "!" + +/decl/prefix/visible_emote + name = "Emote, visible" + default_key = "^" + +/decl/prefix/custom_emote + name = "Emote, custom" + default_key = "*" diff --git a/code/modules/client/preference_setup/laws/laws_pref.dm b/code/modules/client/preference_setup/laws/laws_pref.dm new file mode 100644 index 00000000..4f0fb47d --- /dev/null +++ b/code/modules/client/preference_setup/laws/laws_pref.dm @@ -0,0 +1,93 @@ +/datum/preferences + var/list/laws = list() + var/is_shackled = FALSE + +/datum/preferences/proc/get_lawset() + if(!laws || !laws.len) + return + var/datum/ai_laws/custom_lawset = new + for(var/law in laws) + custom_lawset.add_inherent_law(law) + return custom_lawset + + return gear_list[gear_slot] + +/datum/category_item/player_setup_item/law_pref + name = "Laws" + sort_order = 1 + +/datum/category_item/player_setup_item/law_pref/load_character(var/savefile/S) + from_file(S["laws"], pref.laws) + from_file(S["is_shackled"], pref.is_shackled) + +/datum/category_item/player_setup_item/law_pref/save_character(var/savefile/S) + to_file(S["laws"], pref.laws) + to_file(S["is_shackled"], pref.is_shackled) + +/datum/category_item/player_setup_item/law_pref/sanitize_character() + if(!istype(pref.laws)) pref.laws = list() + + var/datum/species/species = all_species[pref.species] + if(!(species && species.has_organ[BP_POSIBRAIN])) + pref.is_shackled = initial(pref.is_shackled) + else + pref.is_shackled = sanitize_bool(pref.is_shackled, initial(pref.is_shackled)) + +/datum/category_item/player_setup_item/law_pref/content() + . = list() + var/datum/species/species = all_species[pref.species] + + if(!(species && species.has_organ[BP_POSIBRAIN])) + . += "Your Species Has No Laws
            " + else + . += "Shackle: " + if(!pref.is_shackled) + . += "Off" + . += "On" + . += "
            Only shackled positronics have laws in an integrated positronic chassis." + . += "
            " + else + . += "Off" + . += "On" + . += "
            You are shackled and have laws that restrict your behaviour." + . += "
            " + + . += "Your Current Laws:
            " + + if(!pref.laws.len) + . += "You currently have no laws.
            " + else + for(var/i in 1 to pref.laws.len) + . += "[i]) [pref.laws[i]]
            " + + . += "Law sets: Load Set
            " + + . = jointext(.,null) + +/datum/category_item/player_setup_item/law_pref/OnTopic(href, href_list, user) + if(href_list["toggle_shackle"]) + pref.is_shackled = !pref.is_shackled + return TOPIC_REFRESH + + else if(href_list["lawsets"]) + var/list/valid_lawsets = list() + var/list/all_lawsets = subtypesof(/datum/ai_laws) + + for(var/law_set_type in all_lawsets) + var/datum/ai_laws/ai_laws = law_set_type + var/ai_law_name = initial(ai_laws.name) + if(initial(ai_laws.shackles)) // Now this is one terribly snowflaky var + ADD_SORTED(valid_lawsets, ai_law_name, /proc/cmp_text_asc) + valid_lawsets[ai_law_name] = law_set_type + + // Post selection + var/chosen_lawset = input(user, "Choose a law set:", CHARACTER_PREFERENCE_INPUT_TITLE, pref.laws) as null|anything in valid_lawsets + if(chosen_lawset) + var/path = valid_lawsets[chosen_lawset] + var/datum/ai_laws/lawset = new path() + var/datum/ai_law/list/laws = lawset.all_laws() + pref.laws.Cut() + for(var/datum/ai_law/law in laws) + pref.laws += sanitize_text("[law.law]", default="") + return TOPIC_REFRESH + return ..() diff --git a/code/modules/client/preference_setup/loadout/_defines.dm b/code/modules/client/preference_setup/loadout/_defines.dm new file mode 100644 index 00000000..de27dfe2 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/_defines.dm @@ -0,0 +1,3 @@ +#define GEAR_HAS_COLOR_SELECTION 1 +#define GEAR_HAS_TYPE_SELECTION 2 +#define GEAR_HAS_SUBTYPE_SELECTION 4 diff --git a/code/modules/client/preference_setup/loadout/gear_tweaks.dm b/code/modules/client/preference_setup/loadout/gear_tweaks.dm new file mode 100644 index 00000000..2d14ad93 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/gear_tweaks.dm @@ -0,0 +1,327 @@ +/datum/gear_tweak/proc/get_contents(var/metadata) + return + +/datum/gear_tweak/proc/get_metadata(var/user, var/metadata) + return + +/datum/gear_tweak/proc/get_default() + return + +/datum/gear_tweak/proc/tweak_gear_data(var/metadata, var/datum/gear_data) + return + +/datum/gear_tweak/proc/tweak_item(var/obj/item/I, var/metadata) + return + +/datum/gear_tweak/proc/tweak_description(var/description, var/metadata) + return description + +/* +* Color adjustment +*/ + +/datum/gear_tweak/color + var/list/valid_colors + +/datum/gear_tweak/color/New(var/list/valid_colors) + src.valid_colors = valid_colors + ..() + +/datum/gear_tweak/color/get_contents(var/metadata) + return "Color: " + +/datum/gear_tweak/color/get_default() + return valid_colors ? valid_colors[1] : COLOR_WHITE + +/datum/gear_tweak/color/get_metadata(var/user, var/metadata, var/title = CHARACTER_PREFERENCE_INPUT_TITLE) + if(valid_colors) + return input(user, "Choose a color.", title, metadata) as null|anything in valid_colors + return input(user, "Choose a color.", title, metadata) as color|null + +/datum/gear_tweak/color/tweak_item(var/obj/item/I, var/metadata) + if(valid_colors && !(metadata in valid_colors)) + return + I.color = metadata + +/* +* Path adjustment +*/ + +/datum/gear_tweak/path + var/list/valid_paths + +/datum/gear_tweak/path/New(var/list/valid_paths) + if(!valid_paths.len) + CRASH("No type paths given") + var/list/duplicate_keys = duplicates(valid_paths) + if(duplicate_keys.len) + CRASH("Duplicate names found: [english_list(duplicate_keys)]") + var/list/duplicate_values = duplicates(list_values(valid_paths)) + if(duplicate_values.len) + CRASH("Duplicate types found: [english_list(duplicate_values)]") + for(var/path_name in valid_paths) + if(!istext(path_name)) + CRASH("Expected a text key, was [log_info_line(path_name)]") + var/selection_type = valid_paths[path_name] + if(!ispath(selection_type, /obj/item)) + CRASH("Expected an /obj/item path, was [log_info_line(selection_type)]") + src.valid_paths = sortAssoc(valid_paths) + +/datum/gear_tweak/path/type/New(var/type_path) + ..(atomtype2nameassoclist(type_path)) + +/datum/gear_tweak/path/subtype/New(var/type_path) + ..(atomtypes2nameassoclist(subtypesof(type_path))) + +/datum/gear_tweak/path/specified_types_list/New(var/type_paths) + ..(atomtypes2nameassoclist(type_paths)) + +/datum/gear_tweak/path/specified_types_args/New() + ..(atomtypes2nameassoclist(args)) + +/datum/gear_tweak/path/get_contents(var/metadata) + return "Type: [metadata]" + +/datum/gear_tweak/path/get_default() + return valid_paths[1] + +/datum/gear_tweak/path/get_metadata(var/user, var/metadata) + return input(user, "Choose a type.", CHARACTER_PREFERENCE_INPUT_TITLE, metadata) as null|anything in valid_paths + +/datum/gear_tweak/path/tweak_gear_data(var/metadata, var/datum/gear_data/gear_data) + if(!(metadata in valid_paths)) + return + gear_data.path = valid_paths[metadata] + +/datum/gear_tweak/path/tweak_description(var/description, var/metadata) + if(!(metadata in valid_paths)) + return ..() + var/obj/O = valid_paths[metadata] + return initial(O.desc) || description + +/* +* Content adjustment +*/ + +/datum/gear_tweak/contents + var/list/valid_contents + +/datum/gear_tweak/contents/New() + valid_contents = args.Copy() + ..() + +/datum/gear_tweak/contents/get_contents(var/metadata) + return "Contents: [english_list(metadata, and_text = ", ")]" + +/datum/gear_tweak/contents/get_default() + . = list() + for(var/i = 1 to valid_contents.len) + . += "Random" + +/datum/gear_tweak/contents/get_metadata(var/user, var/list/metadata) + . = list() + for(var/i = metadata.len to (valid_contents.len - 1)) + metadata += "Random" + for(var/i = 1 to valid_contents.len) + var/entry = input(user, "Choose an entry.", CHARACTER_PREFERENCE_INPUT_TITLE, metadata[i]) as null|anything in (valid_contents[i] + list("Random", "None")) + if(entry) + . += entry + else + return metadata + +/datum/gear_tweak/contents/tweak_item(var/obj/item/I, var/list/metadata) + if(metadata.len != valid_contents.len) + return + for(var/i = 1 to valid_contents.len) + var/path + var/list/contents = valid_contents[i] + if(metadata[i] == "Random") + path = pick(contents) + path = contents[path] + else if(metadata[i] == "None") + continue + else + path = contents[metadata[i]] + if(path) + new path(I) + else + log_debug("Failed to tweak item: Index [i] in [json_encode(metadata)] did not result in a valid path. Valid contents: [json_encode(valid_contents)]") + +/* +* Ragent adjustment +*/ + +/datum/gear_tweak/reagents + var/list/valid_reagents + +/datum/gear_tweak/reagents/New(var/list/reagents) + valid_reagents = reagents.Copy() + ..() + +/datum/gear_tweak/reagents/get_contents(var/metadata) + return "Reagents: [metadata]" + +/datum/gear_tweak/reagents/get_default() + return "Random" + +/datum/gear_tweak/reagents/get_metadata(var/user, var/list/metadata) + . = input(user, "Choose an entry.", CHARACTER_PREFERENCE_INPUT_TITLE, metadata) as null|anything in (valid_reagents + list("Random", "None")) + if(!.) + return metadata + +/datum/gear_tweak/reagents/tweak_item(var/obj/item/I, var/list/metadata) + if(metadata == "None") + return + if(metadata == "Random") + . = valid_reagents[pick(valid_reagents)] + else + . = valid_reagents[metadata] + I.reagents.add_reagent(., I.reagents.get_free_space()) + +/datum/gear_tweak/tablet + var/list/ValidProcessors = list(/obj/item/weapon/computer_hardware/processor_unit/small) + var/list/ValidBatteries = list(/obj/item/weapon/computer_hardware/battery_module/nano, /obj/item/weapon/computer_hardware/battery_module/micro, /obj/item/weapon/computer_hardware/battery_module) + var/list/ValidHardDrives = list(/obj/item/weapon/computer_hardware/hard_drive/micro, /obj/item/weapon/computer_hardware/hard_drive/small, /obj/item/weapon/computer_hardware/hard_drive) + var/list/ValidNetworkCards = list(/obj/item/weapon/computer_hardware/network_card, /obj/item/weapon/computer_hardware/network_card/advanced) + var/list/ValidNanoPrinters = list(null, /obj/item/weapon/computer_hardware/nano_printer) + var/list/ValidCardSlots = list(null, /obj/item/weapon/computer_hardware/card_slot) + var/list/ValidTeslaLinks = list(null, /obj/item/weapon/computer_hardware/tesla_link) + +/datum/gear_tweak/tablet/get_contents(var/list/metadata) + var/list/names = list() + var/obj/O = ValidProcessors[metadata[1]] + if(O) + names += initial(O.name) + O = ValidBatteries[metadata[2]] + if(O) + names += initial(O.name) + O = ValidHardDrives[metadata[3]] + if(O) + names += initial(O.name) + O = ValidNetworkCards[metadata[4]] + if(O) + names += initial(O.name) + O = ValidNanoPrinters[metadata[5]] + if(O) + names += initial(O.name) + O = ValidCardSlots[metadata[6]] + if(O) + names += initial(O.name) + O = ValidTeslaLinks[metadata[7]] + if(O) + names += initial(O.name) + return "[english_list(names, and_text = ", ")]" + +/datum/gear_tweak/tablet/get_metadata(var/user, var/metadata) + . = list() + + var/list/names = list() + var/counter = 1 + for(var/i in ValidProcessors) + if(i) + var/obj/O = i + names[initial(O.name)] = counter++ + else + names["None"] = counter++ + + var/entry = input(user, "Choose a processor.", CHARACTER_PREFERENCE_INPUT_TITLE) in names + . += names[entry] + + names = list() + counter = 1 + for(var/i in ValidBatteries) + if(i) + var/obj/O = i + names[initial(O.name)] = counter++ + else + names["None"] = counter++ + + entry = input(user, "Choose a battery.", CHARACTER_PREFERENCE_INPUT_TITLE) in names + . += names[entry] + + names = list() + counter = 1 + for(var/i in ValidHardDrives) + if(i) + var/obj/O = i + names[initial(O.name)] = counter++ + else + names["None"] = counter++ + + entry = input(user, "Choose a hard drive.", CHARACTER_PREFERENCE_INPUT_TITLE) in names + . += names[entry] + + names = list() + counter = 1 + for(var/i in ValidNetworkCards) + if(i) + var/obj/O = i + names[initial(O.name)] = counter++ + else + names["None"] = counter++ + + entry = input(user, "Choose a network card.", CHARACTER_PREFERENCE_INPUT_TITLE) in names + . += names[entry] + + names = list() + counter = 1 + for(var/i in ValidNanoPrinters) + if(i) + var/obj/O = i + names[initial(O.name)] = counter++ + else + names["None"] = counter++ + + entry = input(user, "Choose a nanoprinter.", CHARACTER_PREFERENCE_INPUT_TITLE) in names + . += names[entry] + + names = list() + counter = 1 + for(var/i in ValidCardSlots) + if(i) + var/obj/O = i + names[initial(O.name)] = counter++ + else + names["None"] = counter++ + + entry = input(user, "Choose a card slot.", CHARACTER_PREFERENCE_INPUT_TITLE) in names + . += names[entry] + + names = list() + counter = 1 + for(var/i in ValidTeslaLinks) + if(i) + var/obj/O = i + names[initial(O.name)] = counter++ + else + names["None"] = counter++ + + entry = input(user, "Choose a tesla link.", CHARACTER_PREFERENCE_INPUT_TITLE) in names + . += names[entry] + +/datum/gear_tweak/tablet/get_default() + return list(1, 1, 1, 1, 1, 1, 1) + +/datum/gear_tweak/tablet/tweak_item(var/obj/item/modular_computer/tablet/I, var/list/metadata) + if(ValidProcessors[metadata[1]]) + var/t = ValidProcessors[metadata[1]] + I.processor_unit = new t(I) + if(ValidBatteries[metadata[2]]) + var/t = ValidBatteries[metadata[2]] + I.battery_module = new t(I) + I.battery_module.charge_to_full() + if(ValidHardDrives[metadata[3]]) + var/t = ValidHardDrives[metadata[3]] + I.hard_drive = new t(I) + if(ValidNetworkCards[metadata[4]]) + var/t = ValidNetworkCards[metadata[4]] + I.network_card = new t(I) + if(ValidNanoPrinters[metadata[5]]) + var/t = ValidNanoPrinters[metadata[5]] + I.nano_printer = new t(I) + if(ValidCardSlots[metadata[6]]) + var/t = ValidCardSlots[metadata[6]] + I.card_slot = new t(I) + if(ValidTeslaLinks[metadata[7]]) + var/t = ValidTeslaLinks[metadata[7]] + I.tesla_link = new t(I) diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm new file mode 100644 index 00000000..c10ec9b9 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout.dm @@ -0,0 +1,357 @@ +var/list/loadout_categories = list() +var/list/gear_datums = list() + +/datum/preferences + var/list/gear_list //Custom/fluff item loadouts. + var/gear_slot = 1 //The current gear save slot + +/datum/preferences/proc/Gear() + return gear_list[gear_slot] + +/datum/loadout_category + var/category = "" + var/list/gear = list() + +/datum/loadout_category/New(var/cat) + category = cat + ..() + +/hook/startup/proc/populate_gear_list() + + //create a list of gear datums to sort + for(var/geartype in typesof(/datum/gear)-/datum/gear) + var/datum/gear/G = geartype + if(initial(G.category) == geartype) + continue + + var/use_name = initial(G.display_name) + var/use_category = initial(G.sort_category) + + if(!loadout_categories[use_category]) + loadout_categories[use_category] = new /datum/loadout_category(use_category) + var/datum/loadout_category/LC = loadout_categories[use_category] + gear_datums[use_name] = new geartype + LC.gear[use_name] = gear_datums[use_name] + + loadout_categories = sortAssoc(loadout_categories) + for(var/loadout_category in loadout_categories) + var/datum/loadout_category/LC = loadout_categories[loadout_category] + LC.gear = sortAssoc(LC.gear) + return 1 + +/datum/category_item/player_setup_item/loadout + name = "Loadout" + sort_order = 1 + var/current_tab = "General" + var/hide_unavailable_gear = 0 + +/datum/category_item/player_setup_item/loadout/load_character(var/savefile/S) + from_file(S["gear_list"], pref.gear_list) + from_file(S["gear_slot"], pref.gear_slot) + +/datum/category_item/player_setup_item/loadout/save_character(var/savefile/S) + to_file(S["gear_list"], pref.gear_list) + to_file(S["gear_slot"], pref.gear_slot) + +/datum/category_item/player_setup_item/loadout/proc/valid_gear_choices(var/max_cost) + . = list() + var/mob/preference_mob = preference_mob() + for(var/gear_name in gear_datums) + var/datum/gear/G = gear_datums[gear_name] + var/okay = 1 + if(G.whitelisted && preference_mob) + okay = 0 + for(var/species in G.whitelisted) + if(is_species_whitelisted(preference_mob, species)) + okay = 1 + break + if(!okay) + continue + if(max_cost && G.cost > max_cost) + continue + . += gear_name + +/datum/category_item/player_setup_item/loadout/sanitize_character() + pref.gear_slot = sanitize_integer(pref.gear_slot, 1, config.loadout_slots, initial(pref.gear_slot)) + if(!islist(pref.gear_list)) pref.gear_list = list() + + if(pref.gear_list.len < config.loadout_slots) + pref.gear_list.len = config.loadout_slots + + for(var/index = 1 to config.loadout_slots) + var/list/gears = pref.gear_list[index] + + if(istype(gears)) + for(var/gear_name in gears) + if(!(gear_name in gear_datums)) + gears -= gear_name + + var/total_cost = 0 + for(var/gear_name in gears) + if(!gear_datums[gear_name]) + gears -= gear_name + else if(!(gear_name in valid_gear_choices())) + gears -= gear_name + else + var/datum/gear/G = gear_datums[gear_name] + if(total_cost + G.cost > config.max_gear_cost) + gears -= gear_name + else + total_cost += G.cost + else + pref.gear_list[index] = list() + +/datum/category_item/player_setup_item/loadout/content() + . = list() + var/total_cost = 0 + var/list/gears = pref.gear_list[pref.gear_slot] + for(var/i = 1; i <= gears.len; i++) + var/datum/gear/G = gear_datums[gears[i]] + if(G) + total_cost += G.cost + + var/fcolor = "#3366cc" + if(total_cost < config.max_gear_cost) + fcolor = "#e67300" + . += "" + . += "" + + . += "" + + var/datum/loadout_category/LC = loadout_categories[current_tab] + . += "" + . += "" + . += "" + var/jobs = list() + if(job_master) + for(var/job_title in (pref.job_medium|pref.job_low|pref.job_high)) + var/datum/job/J = job_master.occupations_by_title[job_title] + if(J) + dd_insertObjectList(jobs, J) + for(var/gear_name in LC.gear) + if(!(gear_name in valid_gear_choices())) + continue + var/list/entry = list() + var/datum/gear/G = LC.gear[gear_name] + var/ticked = (G.display_name in pref.gear_list[pref.gear_slot]) + entry += "" + entry += "" + entry += "" + if(ticked) + entry += "" + if(!hide_unavailable_gear || allowed || ticked) + . += entry + . += "
            " + . += "\<\<\[[pref.gear_slot]\] \>\>" + + if(config.max_gear_cost < INFINITY) + . += "[total_cost]/[config.max_gear_cost] loadout points spent." + + . += "Clear Loadout" + . += "[hide_unavailable_gear ? "Show all" : "Hide unavailable"]
            " + var/firstcat = 1 + for(var/category in loadout_categories) + + if(firstcat) + firstcat = 0 + else + . += " |" + + var/datum/loadout_category/LC = loadout_categories[category] + var/category_cost = 0 + for(var/gear in LC.gear) + if(gear in pref.gear_list[pref.gear_slot]) + var/datum/gear/G = LC.gear[gear] + category_cost += G.cost + + if(category == current_tab) + . += " [category] - [category_cost] " + else + if(category_cost) + . += " [category] - [category_cost] " + else + . += " [category] - 0 " + + . += "

            [LC.category]

            [G.display_name][G.cost][G.get_description(get_gear_metadata(G,1))]" + var/allowed = 1 + if(G.allowed_roles) + var/good_job = 0 + var/bad_job = 0 + entry += "
            " + var/ind = 0 + for(var/datum/job/J in jobs) + ++ind + if(ind > 1) + entry += ", " + if(J.type in G.allowed_roles) + entry += "[J.title]" + good_job = 1 + else + entry += "[J.title]" + bad_job = 1 + allowed = good_job || !bad_job + entry += "" + entry += "
            " + for(var/datum/gear_tweak/tweak in G.gear_tweaks) + entry += " [tweak.get_contents(get_tweak_metadata(G, tweak))]" + entry += "
            " + . = jointext(.,null) + +/datum/category_item/player_setup_item/loadout/proc/get_gear_metadata(var/datum/gear/G, var/readonly) + var/list/gear = pref.gear_list[pref.gear_slot] + . = gear[G.display_name] + if(!.) + . = list() + if(!readonly) + gear[G.display_name] = . + +/datum/category_item/player_setup_item/loadout/proc/get_tweak_metadata(var/datum/gear/G, var/datum/gear_tweak/tweak) + var/list/metadata = get_gear_metadata(G) + . = metadata["[tweak]"] + if(!.) + . = tweak.get_default() + metadata["[tweak]"] = . + +/datum/category_item/player_setup_item/loadout/proc/set_tweak_metadata(var/datum/gear/G, var/datum/gear_tweak/tweak, var/new_metadata) + var/list/metadata = get_gear_metadata(G) + metadata["[tweak]"] = new_metadata + +/datum/category_item/player_setup_item/loadout/OnTopic(href, href_list, user) + if(href_list["toggle_gear"]) + var/datum/gear/TG = gear_datums[href_list["toggle_gear"]] + if(TG.display_name in pref.gear_list[pref.gear_slot]) + pref.gear_list[pref.gear_slot] -= TG.display_name + else + var/total_cost = 0 + for(var/gear_name in pref.gear_list[pref.gear_slot]) + var/datum/gear/G = gear_datums[gear_name] + if(istype(G)) total_cost += G.cost + if((total_cost+TG.cost) <= config.max_gear_cost) + pref.gear_list[pref.gear_slot] += TG.display_name + return TOPIC_REFRESH_UPDATE_PREVIEW + if(href_list["gear"] && href_list["tweak"]) + var/datum/gear/gear = gear_datums[href_list["gear"]] + var/datum/gear_tweak/tweak = locate(href_list["tweak"]) + if(!tweak || !istype(gear) || !(tweak in gear.gear_tweaks)) + return TOPIC_NOACTION + var/metadata = tweak.get_metadata(user, get_tweak_metadata(gear, tweak)) + if(!metadata || !CanUseTopic(user)) + return TOPIC_NOACTION + set_tweak_metadata(gear, tweak, metadata) + return TOPIC_REFRESH_UPDATE_PREVIEW + if(href_list["next_slot"]) + pref.gear_slot = pref.gear_slot+1 + if(pref.gear_slot > config.loadout_slots) + pref.gear_slot = 1 + return TOPIC_REFRESH_UPDATE_PREVIEW + if(href_list["prev_slot"]) + pref.gear_slot = pref.gear_slot-1 + if(pref.gear_slot < 1) + pref.gear_slot = config.loadout_slots + return TOPIC_REFRESH_UPDATE_PREVIEW + if(href_list["select_category"]) + current_tab = href_list["select_category"] + return TOPIC_REFRESH + if(href_list["clear_loadout"]) + var/list/gear = pref.gear_list[pref.gear_slot] + gear.Cut() + return TOPIC_REFRESH_UPDATE_PREVIEW + if(href_list["toggle_hiding"]) + hide_unavailable_gear = !hide_unavailable_gear + return TOPIC_REFRESH + return ..() + +/datum/category_item/player_setup_item/loadout/update_setup(var/savefile/preferences, var/savefile/character) + if(preferences["version"] < 14) + var/list/old_gear = character["gear"] + if(istype(old_gear)) // During updates data isn't sanitized yet, we have to do manual checks + if(!istype(pref.gear_list)) pref.gear_list = list() + if(!pref.gear_list.len) pref.gear_list.len++ + pref.gear_list[1] = old_gear + return 1 + + if(preferences["version"] < 15) + if(istype(pref.gear_list)) + // Checks if the key of the pref.gear_list is a list. + // If not the key is replaced with the corresponding value. + // This will convert the loadout slot data to a reasonable and (more importantly) compatible format. + // I.e. list("1" = loadout_data1, "2" = loadout_data2, "3" = loadout_data3) becomes list(loadout_data1, loadout_data2, loadaout_data3) + for(var/index = 1 to pref.gear_list.len) + var/key = pref.gear_list[index] + if(islist(key)) + continue + var/value = pref.gear_list[key] + pref.gear_list[index] = value + return 1 + +/datum/gear + var/display_name //Name/index. Must be unique. + var/description //Description of this gear. If left blank will default to the description of the pathed item. + var/path //Path to item. + var/cost = 1 //Number of points used. Items in general cost 1 point, storage/armor/gloves/special use costs 2 points. + var/slot //Slot to equip to. + var/list/allowed_roles //Roles that can spawn with this item. + var/whitelisted //Term to check the whitelist for.. + var/sort_category = "General" + var/flags //Special tweaks in new + var/category + var/list/gear_tweaks = list() //List of datums which will alter the item after it has been spawned. + +/datum/gear/New() + if(FLAGS_EQUALS(flags, GEAR_HAS_TYPE_SELECTION|GEAR_HAS_SUBTYPE_SELECTION)) + CRASH("May not have both type and subtype selection tweaks") + if(!description) + var/obj/O = path + description = initial(O.desc) + if(flags & GEAR_HAS_COLOR_SELECTION) + gear_tweaks += gear_tweak_free_color_choice() + if(flags & GEAR_HAS_TYPE_SELECTION) + gear_tweaks += new/datum/gear_tweak/path/type(path) + if(flags & GEAR_HAS_SUBTYPE_SELECTION) + gear_tweaks += new/datum/gear_tweak/path/subtype(path) + +/datum/gear/proc/get_description(var/metadata) + . = description + for(var/datum/gear_tweak/gt in gear_tweaks) + . = gt.tweak_description(., metadata["[gt]"]) + +/datum/gear_data + var/path + var/location + +/datum/gear_data/New(var/path, var/location) + src.path = path + src.location = location + +/datum/gear/proc/spawn_item(var/location, var/metadata) + var/datum/gear_data/gd = new(path, location) + for(var/datum/gear_tweak/gt in gear_tweaks) + gt.tweak_gear_data(metadata["[gt]"], gd) + var/item = new gd.path(gd.location) + for(var/datum/gear_tweak/gt in gear_tweaks) + gt.tweak_item(item, metadata["[gt]"]) + return item + +/datum/gear/proc/spawn_on_mob(var/mob/living/carbon/human/H, var/metadata) + var/obj/item/item = spawn_item(H, metadata) + + if(H.equip_to_slot_if_possible(item, slot, del_on_fail = 1, force = 1)) + to_chat(H, "Equipping you with \the [item]!") + return TRUE + + return FALSE + +/datum/gear/proc/spawn_in_storage_or_drop(var/mob/living/carbon/human/H, var/metadata) + var/obj/item/item = spawn_item(H, metadata) + + var/atom/placed_in = H.equip_to_storage(item) + if(placed_in) + to_chat(H, "Placing \the [item] in your [placed_in.name]!") + else if(H.equip_to_appropriate_slot(item)) + to_chat(H, "Placing \the [item] in your inventory!") + else if(H.put_in_hands(item)) + to_chat(H, "Placing \the [item] in your hands!") + else + to_chat(H, "Dropping \the [item] on the ground!") + item.forceMove(get_turf(H)) + item.add_fingerprint(H) diff --git a/code/modules/client/preference_setup/loadout/loadout_cosmetics.dm b/code/modules/client/preference_setup/loadout/loadout_cosmetics.dm new file mode 100644 index 00000000..683d65af --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_cosmetics.dm @@ -0,0 +1,14 @@ +/datum/gear/cosmetic/ + display_name = "handheld mirror" + sort_category = "Cosmetics" + path = /obj/item/weapon/mirror + +/datum/gear/cosmetic/lipstick + display_name = "lipstick selection" + path = /obj/item/weapon/lipstick + flags = GEAR_HAS_TYPE_SELECTION + +/datum/gear/cosmetic/comb + display_name = "plastic comb" + path = /obj/item/weapon/haircomb + flags = GEAR_HAS_COLOR_SELECTION \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout_ears.dm b/code/modules/client/preference_setup/loadout/loadout_ears.dm new file mode 100644 index 00000000..80b48cc1 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_ears.dm @@ -0,0 +1,38 @@ +// Stuff worn on the ears. Items here go in the "ears" sort_category but they must not use +// the slot_r_ear or slot_l_ear as the slot, or else players will spawn with no headset. +/datum/gear/ears + display_name = "earmuffs" + path = /obj/item/clothing/ears/earmuffs + sort_category = "Earwear" + +/datum/gear/headphones + display_name = "headphones" + path = /obj/item/clothing/ears/earmuffs/headphones + sort_category = "Earwear" + +/datum/gear/earrings + display_name = "earrings" + path = /obj/item/clothing/ears/earring + sort_category = "Earwear" + +/datum/gear/earrings/New() + ..() + var/earrings = list() + earrings["stud, pearl"] = /obj/item/clothing/ears/earring/stud + earrings["stud, glass"] = /obj/item/clothing/ears/earring/stud/glass + earrings["stud, wood"] = /obj/item/clothing/ears/earring/stud/wood + earrings["stud, iron"] = /obj/item/clothing/ears/earring/stud/iron + earrings["stud, steel"] = /obj/item/clothing/ears/earring/stud/steel + earrings["stud, silver"] = /obj/item/clothing/ears/earring/stud/silver + earrings["stud, gold"] = /obj/item/clothing/ears/earring/stud/gold + earrings["stud, platinum"] = /obj/item/clothing/ears/earring/stud/platinum + earrings["stud, diamond"] = /obj/item/clothing/ears/earring/stud/diamond + earrings["dangle, glass"] = /obj/item/clothing/ears/earring/dangle/glass + earrings["dangle, wood"] = /obj/item/clothing/ears/earring/dangle/wood + earrings["dangle, iron"] = /obj/item/clothing/ears/earring/dangle/iron + earrings["dangle, steel"] = /obj/item/clothing/ears/earring/dangle/steel + earrings["dangle, silver"] = /obj/item/clothing/ears/earring/dangle/silver + earrings["dangle, gold"] = /obj/item/clothing/ears/earring/dangle/gold + earrings["dangle, platinum"] = /obj/item/clothing/ears/earring/dangle/platinum + earrings["dangle, diamond"] = /obj/item/clothing/ears/earring/dangle/diamond + gear_tweaks += new/datum/gear_tweak/path(earrings) diff --git a/code/modules/client/preference_setup/loadout/loadout_general.dm b/code/modules/client/preference_setup/loadout/loadout_general.dm new file mode 100644 index 00000000..57d19311 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_general.dm @@ -0,0 +1,95 @@ +/datum/gear/cane + display_name = "cane" + path = /obj/item/weapon/cane + +/datum/gear/dice + display_name = "dice pack" + path = /obj/item/weapon/storage/pill_bottle/dice + +/datum/gear/dice/nerd + display_name = "dice pack (gaming)" + path = /obj/item/weapon/storage/pill_bottle/dice_nerd + +/datum/gear/cards + display_name = "deck of cards" + path = /obj/item/weapon/deck/cards + +/datum/gear/tarot + display_name = "deck of tarot cards" + path = /obj/item/weapon/deck/tarot + +/datum/gear/holder + display_name = "card holder" + path = /obj/item/weapon/deck/holder + +/datum/gear/cardemon_pack + display_name = "Cardemon booster pack" + path = /obj/item/weapon/pack/cardemon + +/datum/gear/flask + display_name = "flask" + path = /obj/item/weapon/reagent_containers/food/drinks/flask/barflask + +/datum/gear/flask/New() + ..() + gear_tweaks += new/datum/gear_tweak/reagents(lunchables_ethanol_reagents()) + +/datum/gear/vacflask + display_name = "vacuum-flask" + path = /obj/item/weapon/reagent_containers/food/drinks/flask/vacuumflask + +/datum/gear/vacflask/New() + ..() + gear_tweaks += new/datum/gear_tweak/reagents(lunchables_drink_reagents()) + +/datum/gear/coffeecup + display_name = "coffee cup" + path = /obj/item/weapon/reagent_containers/food/drinks/coffeecup + flags = GEAR_HAS_TYPE_SELECTION + +/datum/gear/boot_knife + display_name = "boot knife" + path = /obj/item/weapon/material/kitchen/utensil/knife/boot + cost = 3 + +/datum/gear/lunchbox + display_name = "lunchbox" + description = "A little lunchbox." + cost = 2 + path = /obj/item/weapon/storage/lunchbox + +/datum/gear/lunchbox/New() + ..() + var/list/lunchboxes = list() + for(var/lunchbox_type in typesof(/obj/item/weapon/storage/lunchbox)) + var/obj/item/weapon/storage/lunchbox/lunchbox = lunchbox_type + if(!initial(lunchbox.filled)) + lunchboxes[initial(lunchbox.name)] = lunchbox_type + gear_tweaks += new/datum/gear_tweak/path(lunchboxes) + gear_tweaks += new/datum/gear_tweak/contents(lunchables_lunches(), lunchables_snacks(), lunchables_drinks()) + +/datum/gear/towel + display_name = "towel" + path = /obj/item/weapon/towel + flags = GEAR_HAS_COLOR_SELECTION + +/datum/gear/plush_toy + display_name = "plush toy" + description = "A plush toy." + path = /obj/item/toy/plushie + +/datum/gear/plush_toy/New() + ..() + var/plushes = list() + plushes["diona nymph plush"] = /obj/item/toy/plushie/nymph + plushes["mouse plush"] = /obj/item/toy/plushie/mouse + plushes["kitten plush"] = /obj/item/toy/plushie/kitten + plushes["lizard plush"] = /obj/item/toy/plushie/lizard + plushes["spider plush"] = /obj/item/toy/plushie/spider + plushes["farwa plush"] = /obj/item/toy/plushie/farwa + gear_tweaks += new /datum/gear_tweak/path(plushes) + +/datum/gear/workvisa + display_name = "work visa" + description = "A work visa issued by the Sol Central Government for the purpose of work." + path = /obj/item/weapon/paper/workvisa \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout_mask.dm b/code/modules/client/preference_setup/loadout/loadout_mask.dm new file mode 100644 index 00000000..c6342904 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_mask.dm @@ -0,0 +1,5 @@ +// Mask +/datum/gear/mask + display_name = "sterile mask" + path = /obj/item/clothing/mask/surgical + cost = 2 diff --git a/code/modules/client/preference_setup/loadout/loadout_smoking.dm b/code/modules/client/preference_setup/loadout/loadout_smoking.dm new file mode 100644 index 00000000..e6292f4d --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_smoking.dm @@ -0,0 +1,48 @@ +/datum/gear/smokingpipe + display_name = "pipe, smoking" + path = /obj/item/clothing/mask/smokable/pipe + +/datum/gear/cornpipe + display_name = "pipe, corn" + path = /obj/item/clothing/mask/smokable/pipe/cobpipe + +/datum/gear/matchbook + display_name = "matchbook" + path = /obj/item/weapon/storage/box/matches + +/datum/gear/lighter + display_name = "cheap lighter" + path = /obj/item/weapon/flame/lighter + +/datum/gear/zippo + display_name = "zippo" + path = /obj/item/weapon/flame/lighter/zippo + +/datum/gear/ashtray + display_name = "ashtray, plastic" + path = /obj/item/weapon/material/ashtray/plastic + +/datum/gear/cigars + display_name = "fancy cigar case" + path = /obj/item/weapon/storage/fancy/cigar + cost = 2 + +/datum/gear/cigar + display_name = "fancy cigar" + path = /obj/item/clothing/mask/smokable/cigarette/cigar + +/datum/gear/cigar/New() + ..() + var/cigar_type = list() + cigar_type["premium"] = /obj/item/clothing/mask/smokable/cigarette/cigar + cigar_type["Cohiba Robusto"] = /obj/item/clothing/mask/smokable/cigarette/cigar/cohiba + gear_tweaks += new/datum/gear_tweak/path(cigar_type) + +/datum/gear/ecig + display_name = "electronic cigarette" + path = /obj/item/clothing/mask/smokable/ecig/util + +/datum/gear/ecig/deluxe + display_name = "electronic cigarette, deluxe" + path = /obj/item/clothing/mask/smokable/ecig/deluxe + cost = 2 \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout_utility.dm b/code/modules/client/preference_setup/loadout/loadout_utility.dm new file mode 100644 index 00000000..74cd3d24 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_utility.dm @@ -0,0 +1,80 @@ +// "Useful" items - I'm guessing things that might be used at work? +/datum/gear/utility + display_name = "briefcase" + path = /obj/item/weapon/storage/briefcase + sort_category = "Utility" + +/datum/gear/utility/waistpack + display_name = "waist pack" + path = /obj/item/weapon/storage/belt/waistpack + slot = slot_belt + cost = 2 + flags = GEAR_HAS_COLOR_SELECTION + +/datum/gear/utility/waistpack/big + display_name = "large waist pack" + path = /obj/item/weapon/storage/belt/waistpack/big + cost = 4 + +/datum/gear/utility/clipboard + display_name = "clipboard" + path = /obj/item/weapon/clipboard + +/datum/gear/utility/folder + display_name = "folders" + path = /obj/item/weapon/folder + +/datum/gear/utility/taperecorder + display_name = "tape recorder" + path = /obj/item/device/taperecorder + +/datum/gear/utility/folder/New() + ..() + var/folders = list() + folders["blue folder"] = /obj/item/weapon/folder/blue + folders["grey folder"] = /obj/item/weapon/folder + folders["red folder"] = /obj/item/weapon/folder/red + folders["white folder"] = /obj/item/weapon/folder/white + folders["yellow folder"] = /obj/item/weapon/folder/yellow + gear_tweaks += new/datum/gear_tweak/path(folders) + +/datum/gear/utility/paicard + display_name = "personal AI device" + path = /obj/item/device/paicard + +/datum/gear/utility/camera + display_name = "camera" + path = /obj/item/device/camera + +/**************** +modular computers +****************/ + +/datum/gear/utility/cheaptablet + display_name = "tablet computer, cheap" + path = /obj/item/modular_computer/tablet/preset/custom_loadout/cheap + cost = 3 + +/datum/gear/utility/normaltablet + display_name = "tablet computer, advanced" + path = /obj/item/modular_computer/tablet/preset/custom_loadout/advanced + cost = 4 + +/datum/gear/utility/customtablet + display_name = "tablet computer, custom" + path = /obj/item/modular_computer/tablet + cost = 4 + +/datum/gear/utility/customtablet/New() + ..() + gear_tweaks += new /datum/gear_tweak/tablet() + +/datum/gear/utility/cheaplaptop + display_name = "laptop computer, cheap" + path = /obj/item/modular_computer/laptop/preset/custom_loadout/cheap + cost = 5 + +/datum/gear/utility/normallaptop + display_name = "laptop computer, advanced" + path = /obj/item/modular_computer/laptop/preset/custom_loadout/advanced + cost = 6 diff --git a/code/modules/client/preference_setup/matchmaking/matchmaking.dm b/code/modules/client/preference_setup/matchmaking/matchmaking.dm new file mode 100644 index 00000000..672a8b8c --- /dev/null +++ b/code/modules/client/preference_setup/matchmaking/matchmaking.dm @@ -0,0 +1,206 @@ +var/global/datum/matchmaker/matchmaker = new() + +/hook/roundstart/proc/matchmaking() + matchmaker.do_matchmaking() + return TRUE + +/datum/matchmaker + var/list/relation_types = list() + var/list/relations = list() + +/datum/matchmaker/New() + ..() + for(var/T in subtypesof(/datum/relation/)) + var/datum/relation/R = T + relation_types[initial(R.name)] = T + +/datum/matchmaker/proc/do_matchmaking() + var/list/to_warn = list() + for(var/datum/relation/R in relations) + if(!R.other) + R.find_match() + if(R.other && !R.finalized) + to_warn |= R.holder.current + for(var/mob/M in to_warn) + to_chat(M,"You have new connections. Use \"See Relationship Info\" to view and finalize them.") + +/datum/matchmaker/proc/get_relationships(datum/mind/M) + . = list() + for(var/datum/relation/R in relations) + if(R.holder == M && R.other) + . += R + +//Types of relations + +/datum/relation + var/name = "Acquaintance" + var/desc = "You just know them." + var/list/can_connect_to //What relations (names) can matchmaking join us with? Defaults to own name. + var/list/incompatible //If we have relation like this with the mob, we can't join + var/datum/mind/holder + var/datum/relation/other + var/info + var/finalized + var/open = 2 //If non-zero, allow other relations to form connections + +/datum/relation/New() + ..() + if(!can_connect_to) + can_connect_to = list(name) + matchmaker.relations += src + +/datum/relation/proc/get_candidates() + .= list() + for(var/datum/relation/R in matchmaker.relations) + if(!valid_candidate(R.holder) || !can_connect(R)) + continue + . += R + +/datum/relation/proc/valid_candidate(datum/mind/M) + if(M == holder) //no, you NEED other people + return FALSE + + if(!M.current) //no extremely platonic relationships + return FALSE + + var/datum/antagonist/special_role_data = get_antag_data(M.special_role) + if(special_role_data && (special_role_data.flags & ANTAG_OVERRIDE_JOB)) + return FALSE + + return TRUE + +/datum/relation/proc/can_connect(var/datum/relation/R) + for(var/datum/relation/D in matchmaker.relations) //have to check all connections between us and them + if(D.holder == R.holder && D.other && D.other.holder == holder) + if(D.name in incompatible) + return 0 + return (R.name in can_connect_to) && !(R.name in incompatible) && R.open + +/datum/relation/proc/get_copy() + var/datum/relation/R = new type + R.holder = holder + R.info = holder.current && holder.current.client ? holder.current.client.prefs.relations_info[R.name] : info + R.open = 0 + return R + +/datum/relation/proc/find_match() + var/list/candidates = get_candidates() + if(!candidates.len) //bwoop bwoop + return 0 + var/datum/relation/R = pick(candidates) + R.open-- + if(R.other) + R = R.get_copy() + other = R + R.other = src + return 1 + +/datum/relation/proc/sever() + to_chat(holder.current,"Your connection with [other.holder] is no more.") + to_chat(other.holder.current,"Your connection with [holder] is no more.") + other.other = null + matchmaker.relations -= other + matchmaker.relations -= src + qdel(other) + other = null + qdel(src) + +//Finalizes and propagates info if both sides are done. +/datum/relation/proc/finalize() + finalized = 1 + to_chat(holder.current,"You have finalized a connection with [other.holder].") + to_chat(other.holder.current,"[holder] has finalized a connection with you.") + if(other && other.finalized) + to_chat(holder.current,"Your connection with [other.holder] is now confirmed!") + to_chat(other.holder.current,"Your connection with [holder] is now confirmed!") + var/list/candidates = filter_list(GLOB.player_list, /mob/living/carbon/human) + candidates -= holder.current + candidates -= other.holder.current + for(var/mob/living/carbon/human/M in candidates) + if(!M.mind || M.stat == DEAD || !valid_candidate(M.mind)) + candidates -= M + continue + var/datum/job/coworker = job_master.GetJob(M.job) + if(coworker && holder.assigned_job && other.holder.assigned_job) + if((coworker.department_flag & holder.assigned_job.department_flag) || (coworker.department_flag & other.holder.assigned_job.department_flag)) + candidates[M] = 5 //coworkers are 5 times as likely to know about your relations + + for(var/i=1 to 5) + if(!candidates.len) + break + var/mob/M = pickweight(candidates) + candidates -= M + if(!M.mind.known_connections) + M.mind.known_connections = list() + if(prob(70)) + M.mind.known_connections += get_desc_string() + else + M.mind.known_connections += "[holder] and [other.holder] seem to know each other, but you're not sure on the details." + +/datum/relation/proc/get_desc_string() + return "[holder] and [other.holder] know each other." + +/mob/living/verb/see_relationship_info() + set name = "See Relationship Info" + set desc = "See what connections between people you know of." + set category = "IC" + + var/list/relations = matchmaker.get_relationships(mind) + var/list/dat = list() + var/editable = 0 + if(mind.gen_relations_info) + dat += "Things they all know about you:
            [mind.gen_relations_info]
            " + dat += "An \[F\] indicates that the other player has finalized the connection.
            " + dat += "
            " + for(var/datum/relation/R in relations) + dat += "[R.other.finalized ? "\[F\] " : ""][R.other.holder], [R.other.holder.role_alt_title ? R.other.holder.role_alt_title : R.other.holder.assigned_role]." + if (!R.finalized) + dat += " Remove" + editable = 1 + dat += "
            [R.desc]" + dat += "
            " + dat += "Things they know about you:[!R.finalized ?"Edit" : ""]
            [R.info ? "[R.info]" : " Nothing specific."]" + if(R.other.info) + dat += "
            Things you know about them:
            [R.other.info]
            [R.other.holder.gen_relations_info]" + dat += "
            " + + if(mind.known_connections && mind.known_connections.len) + dat += "Other people:" + for(var/I in mind.known_connections) + dat += "
            [I]" + + var/datum/browser/popup = new(usr, "relations", "Relationship Info") + if(editable) + dat.Insert(1,"Finalize edits and close
            ") + popup.set_window_options("focus=0;can_close=0;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;") + popup.set_content(jointext(dat,null)) + popup.open() + +/mob/living/Topic(href, href_list) + if(..()) + return 1 + if(href_list["del_relation"]) + var/datum/relation/R = locate(href_list["del_relation"]) + if(istype(R)) + R.sever() + see_relationship_info() + return 1 + if(href_list["info_relation"]) + var/datum/relation/R = locate(href_list["info_relation"]) + if(istype(R)) + var/info = sanitize(input("What would you like the other party for this connection to know about your character?","Character info",R.info) as message|null) + if(info) + R.info = info + see_relationship_info() + return 1 + if(href_list["relations_close"]) + var/ok = "Close anyway" + ok = alert("HEY! You have some non-finalized relationships. You can terminate them if they do not fit your character, or edit the info tidbit that the other party is given. THIS IS YOUR ONLY CHANCE to do so - after you close the window, they won't be editable.","Finalize relationships","Return to edit", "Close anyway") + if(ok == "Close anyway") + var/list/relations = matchmaker.get_relationships(mind) + for(var/datum/relation/R in relations) + R.finalize() + show_browser(usr,null, "window=relations") + else + show_browser(usr,null, "window=relations") + return 1 diff --git a/code/modules/client/preference_setup/matchmaking/relations.dm b/code/modules/client/preference_setup/matchmaking/relations.dm new file mode 100644 index 00000000..aa64d97c --- /dev/null +++ b/code/modules/client/preference_setup/matchmaking/relations.dm @@ -0,0 +1,56 @@ +/datum/preferences + var/list/relations + var/list/relations_info + +/datum/category_item/player_setup_item/relations + name = "Matchmaking" + sort_order = 1 + +/datum/category_item/player_setup_item/relations/load_character(var/savefile/S) + S["relations"] >> pref.relations + S["relations_info"] >> pref.relations_info + +/datum/category_item/player_setup_item/relations/save_character(var/savefile/S) + S["relations"] << pref.relations + S["relations_info"] << pref.relations_info + +/datum/category_item/player_setup_item/relations/sanitize_character() + if(!pref.relations) + pref.relations = list() + if(!pref.relations_info) + pref.relations_info = list() + +/datum/category_item/player_setup_item/relations/content(mob/user) + .=list() + . += "Characters with enabled relations are paired up randomly after spawn. You can terminate relations when you first open relations info window, but after that it's final." + . += "
            " + . += "
            What do they know about you? This is the general info that all kinds of your connections would know. Edit" + . += "
            [pref.relations_info["general"] ? pref.relations_info["general"] : "Nothing specific."]" + . += "
            " + for(var/T in subtypesof(/datum/relation)) + var/datum/relation/R = T + . += "[initial(R.name)]\t" + if(initial(R.name) in pref.relations) + . += "On" + . += "Off" + else + . += "On" + . += "Off" + . += "
            [initial(R.desc)]" + . += "
            What do they know about you?Edit" + . += "
            [pref.relations_info[initial(R.name)] ? pref.relations_info[initial(R.name)] : "Nothing specific."]" + . += "
            " + . = jointext(.,null) + +/datum/category_item/player_setup_item/relations/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["relation"]) + var/R = href_list["relation"] + pref.relations ^= R + return TOPIC_REFRESH + if(href_list["relation_info"]) + var/R = href_list["relation_info"] + var/info = sanitize(input("Character info", "What would you like the other party for this connection to know about your character?",pref.relations_info[R]) as message|null) + if(info) + pref.relations_info[R] = info + return TOPIC_REFRESH + return ..() diff --git a/code/modules/client/preference_setup/matchmaking/relations_types.dm b/code/modules/client/preference_setup/matchmaking/relations_types.dm new file mode 100644 index 00000000..285e8046 --- /dev/null +++ b/code/modules/client/preference_setup/matchmaking/relations_types.dm @@ -0,0 +1,69 @@ +/datum/relation/friend + name = "Friend" + desc = "You have known the fellow for a while now, and you get along pretty well." + incompatible = list("Enemy") + +/datum/relation/friend/get_desc_string() + return "[holder] and [other.holder] seem to be on good terms." + +/datum/relation/enemy + name = "Enemy" + desc = "You have known the fellow for a while now, and you really can't stand each other." + incompatible = list("Friend") + +/datum/relation/enemy/get_desc_string() + return "[holder] and [other.holder] do not get along well." + +/datum/relation/had_crossed + name = "Crossed" + desc = "You have slighted them in the past, and they most likely hold a grudge against you." + can_connect_to = list("Was Crossed") + +/datum/relation/had_crossed/get_desc_string() + return "Something has happened between [holder] and [other.holder] in the past, and [other.holder] is upset about it." + +/datum/relation/was_crossed + name = "Was Crossed" + desc = "You have been slighted by them in the past, and you remember it." + can_connect_to = list("Crossed") + +/datum/relation/was_crossed/get_desc_string() + return "Something has happened between [holder] and [other.holder] in the past, and [holder] is upset about it." + +/datum/relation/rival + name = "Rival" + desc = "You are engaged in a constant struggle to show who's number one." + +/datum/relation/rival/get_desc_string() + return "[holder] and [other.holder] are fiercely competitive towards one another." + +/datum/relation/rival/get_candidates() + var/list/rest = ..() + var/list/best = list() + var/list/good = list() + for(var/datum/relation/R in rest) + if(!R.holder.assigned_job || !holder.assigned_job) + continue + if(R.holder.assigned_job == holder.assigned_job) + best += R + if(R.holder.assigned_job.department_flag & holder.assigned_job.department_flag) + good += R + if(best.len) + return best + else if (good.len) + return good + return rest + +/datum/relation/ex + name = "Ex" + desc = "You used to be romantically involved, but not anymore." + +/datum/relation/ex/get_desc_string() + return "[holder] and [other.holder] used to be an item, but not anymore." + +/datum/relation/spessnam + name = "Served Together" + desc = "You have crossed paths while in active military service." + +/datum/relation/spessnam/get_desc_string() + return "[holder] and [other.holder] served in military together at some point in the past." \ No newline at end of file diff --git a/code/modules/client/preference_setup/occupation/occupation.dm b/code/modules/client/preference_setup/occupation/occupation.dm new file mode 100644 index 00000000..4b4def2c --- /dev/null +++ b/code/modules/client/preference_setup/occupation/occupation.dm @@ -0,0 +1,368 @@ +//used for pref.alternate_option +#define GET_RANDOM_JOB 0 +#define BE_ASSISTANT 1 +#define RETURN_TO_LOBBY 2 + +/datum/preferences + //Since there can only be 1 high job. + var/job_high = null + var/list/job_medium //List of all things selected for medium weight + var/list/job_low //List of all the things selected for low weight + var/list/player_alt_titles // the default name of a job like "Medical Doctor" + var/char_branch = "None" // military branch + var/char_rank = "None" // military rank + + //Keeps track of preferrence for not getting any wanted jobs + var/alternate_option = 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_high"] >> pref.job_high + S["job_medium"] >> pref.job_medium + S["job_low"] >> pref.job_low + S["player_alt_titles"] >> pref.player_alt_titles + S["char_branch"] >> pref.char_branch + S["char_rank"] >> pref.char_rank + +/datum/category_item/player_setup_item/occupation/save_character(var/savefile/S) + S["alternate_option"] << pref.alternate_option + S["job_high"] << pref.job_high + S["job_medium"] << pref.job_medium + S["job_low"] << pref.job_low + S["player_alt_titles"] << pref.player_alt_titles + S["char_branch"] << pref.char_branch + S["char_rank"] << pref.char_rank + +/datum/category_item/player_setup_item/occupation/sanitize_character() + if(!istype(pref.job_medium)) pref.job_medium = list() + if(!istype(pref.job_low)) pref.job_low = list() + + pref.alternate_option = sanitize_integer(pref.alternate_option, 0, 2, initial(pref.alternate_option)) + pref.job_high = sanitize(pref.job_high, null) + if(pref.job_medium && pref.job_medium.len) + for(var/i in 1 to pref.job_medium.len) + pref.job_medium[i] = sanitize(pref.job_medium[i]) + if(pref.job_low && pref.job_low.len) + for(var/i in 1 to pref.job_low.len) + pref.job_low[i] = sanitize(pref.job_low[i]) + if(!pref.player_alt_titles) pref.player_alt_titles = new() + + // We could have something like Captain set to high while on a non-rank map, + // so we prune here to make sure we don't spawn as a PFC captain + prune_occupation_prefs() + + 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, splitLimit = 1) + if(!job_master) + return + + var/datum/species/S = preference_species() + var/datum/mil_branch/player_branch = null + var/datum/mil_rank/player_rank = null + + . = list() + if(GLOB.using_map.flags & MAP_HAS_BRANCH) + + player_branch = mil_branches.get_branch(pref.char_branch) + + . += "Branch of Service: [pref.char_branch] " + if(GLOB.using_map.flags & MAP_HAS_RANK) + player_rank = mil_branches.get_rank(pref.char_branch, pref.char_rank) + + . += "Rank: [pref.char_rank] " + . += "
            " + . += "
            " // Table within a table for alignment, also allows you to easily add more columns. + . += "" + var/index = -1 + if(splitLimit) + limit = round((job_master.occupations.len+1)/2) + + //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.is_blue_team && user.client.warfare_faction == RED_TEAM) + . += "[rank]" + if(job.is_red_team && user.client.warfare_faction == BLUE_TEAM) + . += "[rank]" + if(jobban_isbanned(user, rank)) + . += "[rank]" + continue + if(!job.player_old_enough(user.client)) + var/available_in_days = job.available_in_days(user.client) + . += "[rank]" + continue + if(job.minimum_character_age && user.client && (user.client.prefs.age < job.minimum_character_age)) + . += "[rank]" + continue + + if(!job.is_species_allowed(S)) + . += "[rank]" + continue + + if(job.allowed_branches) + if(!player_branch) + . += "[rank]" + continue + if(!is_type_in_list(player_branch, job.allowed_branches)) + . += "[rank]" + continue + + if(job.allowed_ranks) + if(!player_rank) + . += "[rank]" + continue + + if(!is_type_in_list(player_rank, job.allowed_ranks)) + . += "[rank]" + continue + + if(("Assistant" in pref.job_low) && (rank != "Assistant")) + . += "[rank]" + continue + if((rank in GLOB.command_positions) || (rank == "AI"))//Bold head jobs + . += "[rank]" + else + . += "[rank]" + + . += "" + . += "" + continue + + if(pref.job_high == job.title) + . += " \[High]" + else if(job.title in pref.job_medium) + . += " \[Medium]" + else if(job.title in pref.job_low) + . += " \[Low]" + else + . += " \[NEVER]" + . += "" + . += "
            " + var/rank = job.title + lastJob = job + if(job.total_positions == 0 && job.spawn_positions == 0) + . += "[rank] \[UNAVAILABLE]
            \[UNAVAILABLE]
            \[UNAVAILABLE]
            \[BANNED]
            \[IN [(available_in_days)] DAYS]
            \[MINIMUM CHARACTER AGE: [job.minimum_character_age]]
            \[SPECIES RESTRICTED]
            \[BRANCH RESTRICTED]
            \[NOT FOR [player_branch.name_short]]
            \[RANK RESTRICTED]
            \[NOT FOR [player_rank.name_short || player_rank.name]]
            " + + . += "" + + if(rank == "Assistant")//Assistant is special + if("Assistant" in pref.job_low) + . += " \[Yes]" + else + . += " \[No]" + if(job.alt_titles) //Blatantly cloned from a few lines down. + . += "
             \[[pref.GetPlayerAltTitle(job)]\]
            " + . += "
            " + var/datum/job/high_job = job_master.GetJob(pref.job_high) + if(high_job) + . += "
            Role Description:
            [high_job.role_desc]
            " + //. += "Choose your harmful desire
            Unavailable desires are crossed out.
            " + //switch(pref.alternate_option) + // if(GET_RANDOM_JOB) +// . += "Suicide if preferences unavailable" +// if(BE_ASSISTANT) +// . += "Be assistant if preference unavailable" +// if(RETURN_TO_LOBBY) +// . += "Return to lobby if preference unavailable" + . += "
            " + + . += "\[Reset\]
            " + . += "
            " + . = jointext(.,null) + +/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 (pref.equip_preview_mob ? TOPIC_REFRESH_UPDATE_PREVIEW : TOPIC_REFRESH) + + else if(href_list["set_job"]) + if(SetJob(user, href_list["set_job"])) return (pref.equip_preview_mob ? TOPIC_REFRESH_UPDATE_PREVIEW : TOPIC_REFRESH) + + else if(href_list["char_branch"]) + var/choice = input(user, "Choose your branch of service.", CHARACTER_PREFERENCE_INPUT_TITLE, pref.char_branch) as null|anything in mil_branches.spawn_branches(preference_species()) + if(choice && CanUseTopic(user) && mil_branches.is_spawn_branch(choice, preference_species())) + pref.char_branch = choice + pref.char_rank = "None" + prune_job_prefs() + return TOPIC_REFRESH + + else if(href_list["char_rank"]) + var/choice = null + var/datum/mil_branch/current_branch = mil_branches.get_branch(pref.char_branch) + + if(current_branch) + choice = input(user, "Choose your rank.", CHARACTER_PREFERENCE_INPUT_TITLE, pref.char_rank) as null|anything in mil_branches.spawn_ranks(pref.char_branch, preference_species()) + + if(choice && CanUseTopic(user) && mil_branches.is_spawn_rank(pref.char_branch, choice, preference_species())) + pref.char_rank = choice + prune_job_prefs() + return TOPIC_REFRESH + else if(href_list["show_branches"]) + var/rank = href_list["show_branches"] + var/datum/job/job = job_master.GetJob(rank) + to_chat(user, "Valid branches for [rank]: [job.get_branches()]") + else if(href_list["show_ranks"]) + var/rank = href_list["show_ranks"] + var/datum/job/job = job_master.GetJob(rank) + to_chat(user, "Valid ranks for [rank] ([pref.char_branch]): [job.get_ranks(pref.char_branch)]") + + 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(job.title in pref.job_low) + pref.job_low -= job.title + else + pref.job_low |= job.title + return 1 + + if(job.title == pref.job_high) + SetJobDepartment(job, 1) + else if(job.title in pref.job_medium) + SetJobDepartment(job, 2) + else if(job.title in pref.job_low) + 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_high = null + if(2)//Set current highs to med, then reset them + pref.job_medium |= pref.job_high + pref.job_high = job.title + pref.job_medium -= job.title + if(3) + pref.job_medium |= job.title + pref.job_low -= job.title + else + pref.job_low |= job.title + return 1 + +/datum/preferences/proc/CorrectLevel(var/datum/job/job, var/level) + if(!job || !level) return 0 + switch(level) + if(1) + return job_high == job.title + if(2) + return !!(job.title in job_medium) + if(3) + return !!(job.title in job_low) + return 0 + +/** + * Prune a player's job preferences based on current branch, rank and species + * + * This proc goes through all the preferred jobs, and removes the ones incompatible with current rank or branch. + */ +/datum/category_item/player_setup_item/proc/prune_job_prefs() + var/allowed_titles = list() + + for(var/job_type in GLOB.using_map.allowed_jobs) + var/datum/job/job = decls_repository.get_decl(job_type) + allowed_titles += job.title + + if(job.title == pref.job_high) + if(job.is_restricted(pref)) + pref.job_high = null + + else if(job.title in pref.job_medium) + if(job.is_restricted(pref)) + pref.job_medium.Remove(job.title) + + else if(job.title in pref.job_low) + if(job.is_restricted(pref)) + pref.job_low.Remove(job.title) + + if(pref.job_high && !(pref.job_high in allowed_titles)) + pref.job_high = null + + for(var/job_title in pref.job_medium) + if(!(job_title in allowed_titles)) + pref.job_medium -= job_title + + for(var/job_title in pref.job_low) + if(!(job_title in allowed_titles)) + pref.job_low -= job_title + +datum/category_item/player_setup_item/proc/prune_occupation_prefs() + var/datum/species/S = preference_species() + if((GLOB.using_map.flags & MAP_HAS_BRANCH)\ + && (!pref.char_branch || !mil_branches.is_spawn_branch(pref.char_branch, S))) + pref.char_branch = "None" + + if((GLOB.using_map.flags & MAP_HAS_RANK)\ + && (!pref.char_rank || !mil_branches.is_spawn_rank(pref.char_branch, pref.char_rank, S))) + pref.char_rank = "None" + + prune_job_prefs() + +/datum/category_item/player_setup_item/occupation/proc/ResetJobs() + pref.job_high = null + pref.job_medium = list() + pref.job_low = list() + + 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 + +#undef GET_RANDOM_JOB +#undef BE_ASSISTANT +#undef RETURN_TO_LOBBY diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm new file mode 100644 index 00000000..61a1794b --- /dev/null +++ b/code/modules/client/preference_setup/preference_setup.dm @@ -0,0 +1,262 @@ +#define TOPIC_UPDATE_PREVIEW 4 +#define TOPIC_REFRESH_UPDATE_PREVIEW (TOPIC_REFRESH|TOPIC_UPDATE_PREVIEW) + +var/const/CHARACTER_PREFERENCE_INPUT_TITLE = "Character Preference" + +/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 = 2 + category_item_type = /datum/category_item/player_setup_item/occupation +*/ + + +/* +/datum/category_group/player_setup_category/appearance_preferences + name = "Antagonism" + sort_order = 3 + category_item_type = /datum/category_item/player_setup_item/antagonism +*/ + +/* +/datum/category_group/player_setup_category/loadout_preferences + name = "Loadout" + sort_order = 6 + category_item_type = /datum/category_item/player_setup_item/loadout +*/ +/datum/category_group/player_setup_category/global_preferences + name = "!SETTINGS!" + sort_order = 2 //3 + 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/sanitize_setup() + for(var/datum/category_group/player_setup_category/PS in categories) + PS.sanitize_setup() + +/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/update_setup(var/savefile/preferences, var/savefile/character) + for(var/datum/category_group/player_setup_category/PS in categories) + . = PS.update_setup(preferences, character) || . + +/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/sanitize_setup() + for(var/datum/category_item/player_setup_item/PI in items) + PI.sanitize_preferences() + for(var/datum/category_item/player_setup_item/PI in items) + PI.sanitize_character() + +/datum/category_group/player_setup_category/proc/load_character(var/savefile/S) + // Load all data, then sanitize it. + // Need due to, for example, the 01_basic module relying on species having been loaded to sanitize correctly but that isn't loaded until module 03_body. + for(var/datum/category_item/player_setup_item/PI in items) + PI.load_character(S) + +/datum/category_group/player_setup_category/proc/save_character(var/savefile/S) + // Sanitize all data, then save it + for(var/datum/category_item/player_setup_item/PI in items) + PI.sanitize_character() + for(var/datum/category_item/player_setup_item/PI in items) + 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) + +/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() + for(var/datum/category_item/player_setup_item/PI in items) + PI.save_preferences(S) + +/datum/category_group/player_setup_category/proc/update_setup(var/savefile/preferences, var/savefile/character) + for(var/datum/category_item/player_setup_item/PI in items) + . = PI.update_setup(preferences, character) || . + +/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 + +/* +* Called when the item is asked to update user/global settings +*/ +/datum/category_item/player_setup_item/proc/update_setup(var/savefile/preferences, var/savefile/character) + return 0 + +/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/pref_mob = preference_mob() + if(!pref_mob || !pref_mob.client) + return 1 + + . = OnTopic(href, href_list, usr) + if(. & TOPIC_UPDATE_PREVIEW) + pref_mob.client.prefs.preview_icon = null + if(. & TOPIC_REFRESH) + pref_mob.client.prefs.ShowChoices(usr) + +/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.client) + for(var/client/C) + if(C.ckey == pref.client_ckey) + pref.client = C + break + + if(pref.client) + return pref.client.mob + +/datum/category_item/player_setup_item/proc/preference_species() + return all_species[pref.species] || all_species[SPECIES_HUMAN] diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm new file mode 100644 index 00000000..1b0f8212 --- /dev/null +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -0,0 +1,71 @@ +/datum/preferences + var/used_skillpoints = 0 + var/list/skills // skills can range from 0 to 3 + +/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 + +/datum/category_item/player_setup_item/skills/save_character(var/savefile/S) + S["skills"] << pref.skills + S["used_skillpoints"] << pref.used_skillpoints + +/datum/category_item/player_setup_item/skills/sanitize_character() + if(SKILLS == null) setup_skills() + if(!istype(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() + . = list() + . += "Select your Skills
            " + . += "Current skill level: [pref.GetSkillClass(pref.used_skillpoints)] ([pref.used_skillpoints])
            " + . += "" + for(var/V in SKILLS) + . += "" + for(var/datum/skill/S in SKILLS[V]) + var/level = pref.skills[S.ID] + . += "" + . += "" + . += skill_to_button(S, "Untrained", level, SKILL_NONE) + // secondary skills don't have an amateur level + if(S.secondary) + . += "" + else + . += skill_to_button(S, "Amateur", level, SKILL_BASIC) + . += skill_to_button(S, "Trained", level, SKILL_ADEPT) + . += skill_to_button(S, "Professional", level, SKILL_EXPERT) + . += "" + . += "
            [V]" + . += "
            [S.name]
            " + . = jointext(.,null) + +/datum/category_item/player_setup_item/proc/skill_to_button(var/skill, var/level_name, var/current_level, var/selection_level) + if(current_level == selection_level) + return "
            [level_name][level_name]
            " + t += "" + t += "" + t += "" + t += "" + t += "" + t += "" + t += "" + t += "" + for(var/datum/transaction/T in authenticated_account.transaction_log) + t += "" + t += "" + t += "" + t += "" + t += "" + t += "" + t += "" + t += "" + t += "
            DateTimeTargetPurposeValueSource terminal ID
            [T.date][T.time][T.target_name][T.purpose]T[T.amount][T.source_terminal]
            " + t += "Print
            " + if(TRANSFER_FUNDS) + t += "Account balance: T[authenticated_account.money]
            " + t += "
            " + t += "" + t += "" + t += "Target account number:
            " + t += "Funds to transfer:
            " + t += "Transaction purpose:
            " + t += "
            " + t += "
            " + else + t += "Account balance: T[authenticated_account.money]" + t += "
            " + t += "" + t += " Cash Chargecard
            " + t += "" + t += "
            " + t += "Change account security level
            " + t += "Make transfer
            " + t += "View transaction log
            " + t += "Print balance statement
            " + + //Logout/back buttons, put here for some modularity and for less repeated code + if(view_screen == NO_SCREEN) + t += "Logout
            " + else + t += "Back" + + else + //change our display depending on account security levels + if(!account_security_level) + t += "To log in to your savings account, press 'submit' with ID clearly displayed. If you wish to log into another account, please enter the account number into the field below or insert a registered ID card into the slot above and then press 'submit'.
            " + else + t += "Due to the security settings on this account, all information needs to be re-entered and the ID bound to this account placed in the slot above.
            " + t += "
            " + t += "" + t += "" + t += "Account:

            " + t += "
            " + t += "
            " + + + var/datum/browser/popup = new(user, "ATM", machine_id) + popup.set_content(jointext(t,null)) + popup.open() + else + return + +/obj/machinery/atm/Topic(var/href, var/href_list) + if(href_list["choice"]) + switch(href_list["choice"]) + if("transfer") + if(authenticated_account) + var/transfer_amount = text2num(href_list["funds_amount"]) + transfer_amount = round(transfer_amount, 0.01) + if(transfer_amount <= 0) + alert("That is not a valid amount.") + else if(transfer_amount <= authenticated_account.money) + var/target_account_number = text2num(href_list["target_acc_number"]) + var/transfer_purpose = href_list["purpose"] + if(charge_to_account(target_account_number, authenticated_account.owner_name, transfer_purpose, machine_id, transfer_amount)) + to_chat(usr, "\icon[src]Funds transfer successful.") + //create an entry in the account transaction log + var/datum/transaction/T = new("Account #[target_account_number]", transfer_purpose, -transfer_amount, machine_id) + authenticated_account.do_transaction(T) + else + to_chat(usr, "\icon[src]Funds transfer failed.") + + else + to_chat(usr, "\icon[src]You don't have enough funds to do that!") + if("view_screen") + view_screen = text2num(href_list["view_screen"]) + if("change_security_level") + if(authenticated_account) + var/new_sec_level = max( min(text2num(href_list["new_security_level"]), 2), 0) + authenticated_account.security_level = new_sec_level + if("attempt_auth") + + //Look to see if we're holding an ID, if so scan the data from that and use it, if not scan the user for the data + var/obj/item/weapon/card/id/login_card + if(held_card) + login_card = held_card + else + login_card = scan_user(usr) + + if(!ticks_left_locked_down) + var/tried_account_num = text2num(href_list["account_num"]) + //We WILL need an account number entered manually if security is high enough, do not automagic account number + if(!tried_account_num && login_card && (account_security_level != 2)) + tried_account_num = login_card.associated_account_number + var/tried_pin = text2num(href_list["account_pin"]) + + //We'll need more information if an account's security is greater than zero so let's find out what the security setting is + var/datum/money_account/D + //Below is to avoid a runtime + if(tried_account_num) + D = get_account(tried_account_num) + account_security_level = D.security_level + + authenticated_account = attempt_account_access(tried_account_num, tried_pin, held_card && login_card.associated_account_number == tried_account_num ? 2 : 1) + + if(!authenticated_account) + number_incorrect_tries++ + //let's not count an incorrect try on someone who just needs to put in more information + if(previous_account_number == tried_account_num && tried_pin) + if(number_incorrect_tries >= max_pin_attempts) + //lock down the atm + ticks_left_locked_down = 30 + playsound(src, 'sound/machines/buzz-two.ogg', 50, 1) + + //create an entry in the account transaction log + var/datum/money_account/failed_account = get_account(tried_account_num) + if(failed_account) + var/datum/transaction/T = new(failed_account.owner_name, "Unauthorised login attempt", 0, machine_id) + failed_account.do_transaction(T) + else + to_chat(usr, "\icon[src] Incorrect pin/account combination entered, [max_pin_attempts - number_incorrect_tries] attempts remaining.") + previous_account_number = tried_account_num + playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 1) + else + to_chat(usr, "\icon[src] Unable to log in to account, additional information may be required.") + number_incorrect_tries = 0 + else + playsound(src, 'sound/machines/twobeep.ogg', 50, 1) + ticks_left_timeout = 120 + view_screen = NO_SCREEN + + //create a transaction log entry + var/datum/transaction/T = new(authenticated_account.owner_name, "Remote terminal access", 0, machine_id) + authenticated_account.do_transaction(T) + + to_chat(usr, "\icon[src] Access granted. Welcome user '[authenticated_account.owner_name].'") + + previous_account_number = tried_account_num + if("e_withdrawal") + var/amount = max(text2num(href_list["funds_amount"]),0) + amount = round(amount, 0.01) + if(amount <= 0) + alert("That is not a valid amount.") + else if(authenticated_account && amount > 0) + if(amount <= authenticated_account.money) + playsound(src, 'sound/machines/chime.ogg', 50, 1) + spawn_ewallet(amount,src.loc,usr) + + //create an entry in the account transaction log + var/datum/transaction/T = new(authenticated_account.owner_name, "Credit withdrawal", -amount, machine_id) + authenticated_account.do_transaction(T) + else + to_chat(usr, "\icon[src]You don't have enough funds to do that!") + if("withdrawal") + var/amount = max(text2num(href_list["funds_amount"]),0) + amount = round(amount, 0.01) + if(amount <= 0) + alert("That is not a valid amount.") + else if(authenticated_account && amount > 0) + if(amount <= authenticated_account.money) + playsound(src, 'sound/machines/chime.ogg', 50, 1) + spawn_money(amount,src.loc,usr) + + //remove the money + var/datum/transaction/T = new(authenticated_account.owner_name, "Credit withdrawal", -amount, machine_id) + authenticated_account.do_transaction(T) + else + to_chat(usr, "\icon[src]You don't have enough funds to do that!") + if("balance_statement") + if(authenticated_account) + var/obj/item/weapon/paper/R = new(src.loc) + R.SetName("Account balance: [authenticated_account.owner_name]") + R.info = "NT Automated Teller Account Statement

            " + R.info += "Account holder: [authenticated_account.owner_name]
            " + R.info += "Account number: [authenticated_account.account_number]
            " + R.info += "Balance: T[authenticated_account.money]
            " + R.info += "Date and time: [stationtime2text()], [stationdate2text()]

            " + R.info += "Service terminal ID: [machine_id]
            " + + //stamp the paper + var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') + stampoverlay.icon_state = "paper_stamp-cent" + if(!R.stamped) + R.stamped = new + R.stamped += /obj/item/weapon/stamp + R.overlays += stampoverlay + R.stamps += "
            This paper has been stamped by the Automatic Teller Machine." + + if(prob(50)) + playsound(loc, 'sound/items/polaroid1.ogg', 50, 1) + else + playsound(loc, 'sound/items/polaroid2.ogg', 50, 1) + if ("print_transaction") + if(authenticated_account) + var/obj/item/weapon/paper/R = new(src.loc) + R.SetName("Transaction logs: [authenticated_account.owner_name]") + R.info = "Transaction logs
            " + R.info += "Account holder: [authenticated_account.owner_name]
            " + R.info += "Account number: [authenticated_account.account_number]
            " + R.info += "Date and time: [stationtime2text()], [stationdate2text()]

            " + R.info += "Service terminal ID: [machine_id]
            " + R.info += "" + R.info += "" + R.info += "" + R.info += "" + R.info += "" + R.info += "" + R.info += "" + R.info += "" + R.info += "" + for(var/datum/transaction/T in authenticated_account.transaction_log) + R.info += "" + R.info += "" + R.info += "" + R.info += "" + R.info += "" + R.info += "" + R.info += "" + R.info += "" + R.info += "
            DateTimeTargetPurposeValueSource terminal ID
            [T.date][T.time][T.target_name][T.purpose]T[T.amount][T.source_terminal]
            " + + //stamp the paper + var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') + stampoverlay.icon_state = "paper_stamp-cent" + if(!R.stamped) + R.stamped = new + R.stamped += /obj/item/weapon/stamp + R.overlays += stampoverlay + R.stamps += "
            This paper has been stamped by the Automatic Teller Machine." + + if(prob(50)) + playsound(loc, 'sound/items/polaroid1.ogg', 50, 1) + else + playsound(loc, 'sound/items/polaroid2.ogg', 50, 1) + + if("insert_card") + if(!held_card) + //this might happen if the user had the browser window open when somebody emagged it + if(emagged > 0) + to_chat(usr, "\icon[src] The ATM card reader rejected your ID because this machine has been sabotaged!") + else + var/obj/item/I = usr.get_active_hand() + if (istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.loc = src + held_card = I + else + release_held_id(usr) + if("logout") + authenticated_account = null + account_security_level = 0 + + src.attack_hand(usr) + +/obj/machinery/atm/proc/scan_user(mob/living/carbon/human/human_user as mob) + if(!authenticated_account) + if(human_user.wear_id) + var/obj/item/weapon/card/id/I + if(istype(human_user.wear_id, /obj/item/weapon/card/id) ) + I = human_user.wear_id + else if(istype(human_user.wear_id, /obj/item/device/pda) ) + var/obj/item/device/pda/P = human_user.wear_id + I = P.id + if(I) + return I + +// put the currently held id on the ground or in the hand of the user +/obj/machinery/atm/proc/release_held_id(mob/living/carbon/human/human_user as mob) + if(!held_card) + return + + held_card.loc = src.loc + authenticated_account = null + account_security_level = 0 + + if(ishuman(human_user) && !human_user.get_active_hand()) + human_user.put_in_hands(held_card) + held_card = null + + +/obj/machinery/atm/proc/spawn_ewallet(var/sum, loc, mob/living/carbon/human/human_user as mob) + var/obj/item/weapon/spacecash/ewallet/E = new /obj/item/weapon/spacecash/ewallet(loc) + if(ishuman(human_user) && !human_user.get_active_hand()) + human_user.put_in_hands(E) + E.worth = sum + E.owner_name = authenticated_account.owner_name diff --git a/code/modules/economy/Accounts.dm b/code/modules/economy/Accounts.dm new file mode 100644 index 00000000..408c7417 --- /dev/null +++ b/code/modules/economy/Accounts.dm @@ -0,0 +1,133 @@ + +/datum/money_account + var/owner_name = "" + var/account_number = 0 + var/remote_access_pin = 0 + var/money = 0 + var/list/transaction_log = list() + var/suspended = 0 + var/security_level = 0 //0 - auto-identify from worn ID, require only account number + //1 - require manual login / account number and pin + //2 - require card and manual login + +/datum/money_account/proc/do_transaction(var/datum/transaction/T) + money = max(0, money + T.amount) + transaction_log += T + +/datum/money_account/proc/get_balance() + . = 0 + for(var/datum/transaction/T in transaction_log) + if(T.purpose == "Account creation") + continue + T.sanitize_amount() + . += T.amount + +/datum/transaction + var/target_name = "" + var/purpose = "" + var/amount = 0 + var/date = "" + var/time = "" + var/source_terminal = "" + +/datum/transaction/New(_target, _purpose, _amount, _source) + ..() + date = stationdate2text() + time = stationtime2text() + target_name = _target + purpose = _purpose + amount = _amount + source_terminal = _source + +/datum/transaction/proc/sanitize_amount() //some place still uses (number) for negative amounts and I can't find it + if(!istext(amount)) + return + + // Check if the text is numeric. + var/text = amount + amount = text2num(text) + + // Otherwise, the (digits) thing is going on. + if(!amount) + var/regex/R = regex("\\d+") + R.Find(text) + amount = -text2num(R.match) + +/proc/create_account(var/new_owner_name = "Default user", var/starting_funds = 0, var/obj/machinery/computer/account_database/source_db) + + //create a new account + var/datum/money_account/M = new() + M.owner_name = new_owner_name + M.remote_access_pin = rand(1111, 111111) + M.money = starting_funds + + //create an entry in the account transaction log for when it was created + var/datum/transaction/T = new() + T.target_name = new_owner_name + T.purpose = "Account creation" + T.amount = starting_funds + if(!source_db) + //set a random date, time and location some time over the past few decades + T.date = "[num2text(rand(1,31))] [pick("January","February","March","April","May","June","July","August","September","October","November","December")], [game_year-rand(8,18)]" + T.time = "[rand(0,24)]:[rand(11,59)]" + T.source_terminal = "Terminal #[rand(111,1111)]" + + M.account_number = random_id("station_account_number", 111111, 999999) + else + T.source_terminal = source_db.machine_id + + M.account_number = next_account_number + next_account_number += rand(1,25) + + //create a sealed package containing the account details + var/obj/item/smallDelivery/P = new /obj/item/smallDelivery(source_db.loc) + + var/obj/item/weapon/paper/R = new /obj/item/weapon/paper(P) + P.wrapped = R + R.SetName("Account information: [M.owner_name]") + R.info = "Account details (confidential)


            " + R.info += "Account holder: [M.owner_name]
            " + R.info += "Account number: [M.account_number]
            " + R.info += "Account pin: [M.remote_access_pin]
            " + R.info += "Starting balance: T[M.money]
            " + R.info += "Date and time: [stationtime2text()], [stationdate2text()]

            " + R.info += "Creation terminal ID: [source_db.machine_id]
            " + R.info += "Authorised NT officer overseeing creation: [source_db.held_card.registered_name]
            " + + //stamp the paper + var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') + stampoverlay.icon_state = "paper_stamp-cent" + if(!R.stamped) + R.stamped = new + R.stamped += /obj/item/weapon/stamp + R.overlays += stampoverlay + R.stamps += "
            This paper has been stamped by the Accounts Database." + + //add the account + M.transaction_log.Add(T) + all_money_accounts.Add(M) + + return M + +/proc/charge_to_account(var/attempt_account_number, var/source_name, var/purpose, var/terminal_id, var/amount) + var/datum/money_account/D = get_account(attempt_account_number) + if(!D || D.suspended) + return 0 + D.money = max(0, D.money + amount) + + //create a transaction log entry + var/datum/transaction/T = new(source_name, purpose, amount, terminal_id) + D.transaction_log.Add(T) + + return 1 + +//this returns the first account datum that matches the supplied accnum/pin combination, it returns null if the combination did not match any account +/proc/attempt_account_access(var/attempt_account_number, var/attempt_pin_number, var/security_level_passed = 0) + var/datum/money_account/D = get_account(attempt_account_number) + if(D && D.security_level <= security_level_passed && (!D.security_level || D.remote_access_pin == attempt_pin_number) ) + return D + +/proc/get_account(var/account_number) + for(var/datum/money_account/D in all_money_accounts) + if(D.account_number == account_number) + return D diff --git a/code/modules/economy/Accounts_DB.dm b/code/modules/economy/Accounts_DB.dm new file mode 100644 index 00000000..4239bc16 --- /dev/null +++ b/code/modules/economy/Accounts_DB.dm @@ -0,0 +1,279 @@ + +/obj/machinery/computer/account_database + name = "accounts uplink terminal" + desc = "Access transaction logs, account data and all kinds of other financial records." + + req_one_access = list(access_hop, access_captain, access_cent_captain) + var/receipt_num + var/machine_id = "" + var/obj/item/weapon/card/id/held_card + var/datum/money_account/detailed_account_view + var/creating_new_account = 0 + var/const/fund_cap = 1000000 + + circuit = /obj/item/weapon/circuitboard/account_database + + proc/get_access_level() + if (!held_card) + return 0 + if(access_cent_captain in held_card.access) + return 2 + else if(access_hop in held_card.access || access_captain in held_card.access) + return 1 + + proc/create_transation(target, reason, amount) + var/datum/transaction/T = new() + T.target_name = target + T.purpose = reason + T.amount = amount + T.date = stationdate2text() + T.time = stationtime2text() + T.source_terminal = machine_id + return T + + proc/accounting_letterhead(report_name) + return {" +

            [report_name]

            +
            [station_name()] Accounting Report
            +
            + Generated By: [held_card.registered_name], [held_card.assignment]
            + "} + +/obj/machinery/computer/account_database/New() + machine_id = "[station_name()] Acc. DB #[num_financial_terminals++]" + ..() + +/obj/machinery/computer/account_database/attackby(obj/O, mob/user) + if(!istype(O, /obj/item/weapon/card/id)) + return ..() + + if(!held_card) + user.drop_item() + O.loc = src + held_card = O + + GLOB.nanomanager.update_uis(src) + + attack_hand(user) + +/obj/machinery/computer/account_database/attack_hand(mob/user as mob) + if(stat & (NOPOWER|BROKEN)) return + ui_interact(user) + +/obj/machinery/computer/account_database/ui_interact(mob/user, ui_key="main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) + + var/data[0] + data["src"] = "\ref[src]" + data["id_inserted"] = !!held_card + data["id_card"] = held_card ? text("[held_card.registered_name], [held_card.assignment]") : "-----" + data["access_level"] = get_access_level() + data["machine_id"] = machine_id + data["creating_new_account"] = creating_new_account + data["detailed_account_view"] = !!detailed_account_view + data["station_account_number"] = station_account.account_number + data["transactions"] = null + data["accounts"] = null + + if (detailed_account_view) + data["account_number"] = detailed_account_view.account_number + data["owner_name"] = detailed_account_view.owner_name + data["money"] = detailed_account_view.money + data["suspended"] = detailed_account_view.suspended + + var/list/trx[0] + for (var/datum/transaction/T in detailed_account_view.transaction_log) + trx.Add(list(list(\ + "date" = T.date, \ + "time" = T.time, \ + "target_name" = T.target_name, \ + "purpose" = T.purpose, \ + "amount" = T.amount, \ + "source_terminal" = T.source_terminal))) + + if (trx.len > 0) + data["transactions"] = trx + + var/list/accounts[0] + for(var/i=1, i<=all_money_accounts.len, i++) + var/datum/money_account/D = all_money_accounts[i] + accounts.Add(list(list(\ + "account_number"=D.account_number,\ + "owner_name"=D.owner_name,\ + "suspended"=D.suspended ? "SUSPENDED" : "",\ + "account_index"=i))) + + if (accounts.len > 0) + data["accounts"] = accounts + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "accounts_terminal.tmpl", src.name, 400, 640) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/computer/account_database/Topic(href, href_list) + if(..()) + return 1 + + var/datum/nanoui/ui = GLOB.nanomanager.get_open_ui(usr, src, "main") + + if(href_list["choice"]) + switch(href_list["choice"]) + if("create_account") + creating_new_account = 1 + + if("add_funds") + var/amount = input("Enter the amount you wish to add", "Add funds") as num|null + if(detailed_account_view) + if(station_account.money >= amount) + station_account.money -= amount + detailed_account_view.money = min(detailed_account_view.money + amount, fund_cap) + + if("remove_funds") + var/amount = input("Enter the amount you wish to remove", "Remove funds") as num|null + if(detailed_account_view) + station_account.money += amount + detailed_account_view.money = max(detailed_account_view.money - amount, -fund_cap) + + if("toggle_suspension") + if(detailed_account_view) + detailed_account_view.suspended = !detailed_account_view.suspended + callHook("change_account_status", list(detailed_account_view)) + + if("finalise_create_account") + var/account_name = href_list["holder_name"] + var/starting_funds = max(text2num(href_list["starting_funds"]), 0) + + starting_funds = Clamp(starting_funds, 0, station_account.money) // Not authorized to put the station in debt. + starting_funds = min(starting_funds, fund_cap) // Not authorized to give more than the fund cap. + + create_account(account_name, starting_funds, src) + if(starting_funds > 0) + //subtract the money + station_account.money -= starting_funds + + //create a transaction log entry + var/trx = create_transation(account_name, "New account activation", "([starting_funds])") + station_account.transaction_log.Add(trx) + + creating_new_account = 0 + ui.close() + + creating_new_account = 0 + if("insert_card") + if(held_card) + held_card.loc = src.loc + + if(ishuman(usr) && !usr.get_active_hand()) + usr.put_in_hands(held_card) + held_card = null + + else + var/obj/item/I = usr.get_active_hand() + if (istype(I, /obj/item/weapon/card/id)) + var/obj/item/weapon/card/id/C = I + usr.drop_item() + C.loc = src + held_card = C + + if("view_account_detail") + var/index = text2num(href_list["account_index"]) + if(index && index <= all_money_accounts.len) + detailed_account_view = all_money_accounts[index] + + if("view_accounts_list") + detailed_account_view = null + creating_new_account = 0 + + if("revoke_payroll") + var/funds = detailed_account_view.money + var/account_trx = create_transation(station_account.owner_name, "Revoke payroll", "([funds])") + var/station_trx = create_transation(detailed_account_view.owner_name, "Revoke payroll", funds) + + station_account.money += funds + detailed_account_view.money = 0 + + detailed_account_view.transaction_log.Add(account_trx) + station_account.transaction_log.Add(station_trx) + + callHook("revoke_payroll", list(detailed_account_view)) + + if("print") + var/text + var/obj/item/weapon/paper/P = new(loc) + if (detailed_account_view) + P.SetName("account #[detailed_account_view.account_number] details") + var/title = "Account #[detailed_account_view.account_number] Details" + text = {" + [accounting_letterhead(title)] + Holder: [detailed_account_view.owner_name]
            + Balance: T[detailed_account_view.money]
            + Status: [detailed_account_view.suspended ? "Suspended" : "Active"]
            + Transactions: ([detailed_account_view.transaction_log.len])
            + + + + + + + + + + + + "} + + for (var/datum/transaction/T in detailed_account_view.transaction_log) + text += {" + + + + + + + + "} + + text += {" + +
            TimestampTargetReasonValueTerminal
            [T.date] [T.time][T.target_name][T.purpose][T.amount][T.source_terminal]
            + "} + + else + P.SetName("financial account list") + text = {" + [accounting_letterhead("Financial Account List")] + + + + + + + + + + + + "} + + for(var/i=1, i<=all_money_accounts.len, i++) + var/datum/money_account/D = all_money_accounts[i] + text += {" + + + + + + + "} + + text += {" + +
            Account NumberHolderBalanceStatus
            #[D.account_number][D.owner_name]T[D.money][D.suspended ? "Suspended" : "Active"]
            + "} + + P.info = text + state("The terminal prints out a report.") + + return 1 diff --git a/code/modules/economy/EFTPOS.dm b/code/modules/economy/EFTPOS.dm new file mode 100644 index 00000000..18f1b1b6 --- /dev/null +++ b/code/modules/economy/EFTPOS.dm @@ -0,0 +1,274 @@ +/obj/item/device/eftpos + name = "\improper EFTPOS scanner" + desc = "Swipe your ID card to make purchases electronically." + icon = 'icons/obj/device.dmi' + icon_state = "eftpos" + var/machine_id = "" + var/eftpos_name = "Default EFTPOS scanner" + var/transaction_locked = 0 + var/transaction_paid = 0 + var/transaction_amount = 0 + var/transaction_purpose = "Default charge" + var/access_code = 0 + var/datum/money_account/linked_account + +/obj/item/device/eftpos/New() + ..() + machine_id = "[station_name()] EFTPOS #[num_financial_terminals++]" + access_code = rand(1111,111111) + spawn(0) + print_reference() + + //create a short manual as well + var/obj/item/weapon/paper/R = new(src.loc) + R.SetName("Steps to success: Correct EFTPOS Usage") + /* + R.info += "When first setting up your EFTPOS device:" + R.info += "1. Memorise your EFTPOS command code (provided with all EFTPOS devices).
            " + R.info += "2. Confirm that your EFTPOS device is connected to your local accounts database. For additional assistance with this step, contact NanoTrasen IT Support
            " + R.info += "3. Confirm that your EFTPOS device has been linked to the account that you wish to recieve funds for all transactions processed on this device.
            " + R.info += "When starting a new transaction with your EFTPOS device:" + R.info += "1. Ensure the device is UNLOCKED so that new data may be entered.
            " + R.info += "2. Enter a sum of money and reference message for the new transaction.
            " + R.info += "3. Lock the transaction, it is now ready for your customer.
            " + R.info += "4. If at this stage you wish to modify or cancel your transaction, you may simply reset (unlock) your EFTPOS device.
            " + R.info += "5. Give your EFTPOS device to the customer, they must authenticate the transaction by swiping their ID card and entering their PIN number.
            " + R.info += "6. If done correctly, the transaction will be logged to both accounts with the reference you have entered, the terminal ID of your EFTPOS device and the money transferred across accounts.
            " + */ + //Temptative new manual: + R.info += "First EFTPOS setup:
            " + R.info += "1. Memorise your EFTPOS command code (provided with all EFTPOS devices).
            " + R.info += "2. Connect the EFTPOS to the account in which you want to receive the funds.

            " + R.info += "When starting a new transaction:
            " + R.info += "1. Enter the amount of money you want to charge and a purpose message for the new transaction.
            " + R.info += "2. Lock the new transaction. If you want to modify or cancel the transaction, you simply have to reset your EFTPOS device.
            " + R.info += "3. Give the EFTPOS device to your customer, he/she must finish the transaction by swiping their ID card or a charge card with enough funds.
            " + R.info += "4. If everything is done correctly, the money will be transferred. To unlock the device you will have to reset the EFTPOS device.
            " + + + //stamp the paper + var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') + stampoverlay.icon_state = "paper_stamp-cent" + if(!R.stamped) + R.stamped = new + R.offset_x += 0 + R.offset_y += 0 + R.ico += "paper_stamp-cent" + R.stamped += /obj/item/weapon/stamp + R.overlays += stampoverlay + R.stamps += "
            This paper has been stamped by the EFTPOS device." + + //by default, connect to the station account + //the user of the EFTPOS device can change the target account though, and no-one will be the wiser (except whoever's being charged) + linked_account = station_account + +/obj/item/device/eftpos/proc/print_reference() + var/obj/item/weapon/paper/R = new(src.loc) + R.SetName("Reference: [eftpos_name]") + R.info = "[eftpos_name] reference

            " + R.info += "Access code: [access_code]

            " + R.info += "Do not lose or misplace this code.
            " + + //stamp the paper + var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') + stampoverlay.icon_state = "paper_stamp-cent" + if(!R.stamped) + R.stamped = new + R.stamped += /obj/item/weapon/stamp + R.overlays += stampoverlay + R.stamps += "
            This paper has been stamped by the EFTPOS device." + var/obj/item/smallDelivery/D = new(R.loc) + R.loc = D + D.wrapped = R + D.SetName("small parcel - 'EFTPOS access code'") + +/obj/item/device/eftpos/attack_self(mob/user as mob) + if(get_dist(src,user) <= 1) + var/dat = "[eftpos_name]
            " + dat += "This terminal is [machine_id]. Report this code when contacting IT Support
            " + if(transaction_locked) + dat += "Back[transaction_paid ? "" : " (authentication required)"]

            " + + dat += "Transaction purpose: [transaction_purpose]
            " + dat += "Value: T[transaction_amount]
            " + dat += "Linked account: [linked_account ? linked_account.owner_name : "None"]
            " + if(transaction_paid) + dat += "This transaction has been processed successfully.
            " + else + dat += "Swipe your card below the line to finish this transaction.
            " + dat += "\[------\]" + else + dat += "Lock in new transaction

            " + + dat += "Transaction purpose: [transaction_purpose]
            " + dat += "Value: T[transaction_amount]
            " + dat += "Linked account: [linked_account ? linked_account.owner_name : "None"]
            " + dat += "Change access code
            " + dat += "Change EFTPOS ID
            " + dat += "Scan card to reset access code \[------\]" + user << browse(dat,"window=eftpos") + else + user << browse(null,"window=eftpos") + +/obj/item/device/eftpos/attackby(obj/item/O as obj, user as mob) + + var/obj/item/weapon/card/id/I = O.GetIdCard() + + if(I) + if(linked_account) + scan_card(I, O) + else + to_chat(usr, "\icon[src]Unable to connect to linked account.") + else if (istype(O, /obj/item/weapon/spacecash/ewallet)) + var/obj/item/weapon/spacecash/ewallet/E = O + if (linked_account) + if(!linked_account.suspended) + if(transaction_locked && !transaction_paid) + if(transaction_amount <= E.worth) + playsound(src, 'sound/machines/chime.ogg', 50, 1) + src.visible_message("\icon[src] \The [src] chimes.") + transaction_paid = 1 + + //transfer the money + E.worth -= transaction_amount + var/datum/transaction/T = new(E.owner_name, (transaction_purpose ? transaction_purpose : "None supplied."), transaction_amount, machine_id) + linked_account.do_transaction(T) + else + to_chat(usr, "\icon[src]\The [O] doesn't have that much money!") + else + to_chat(usr, "\icon[src]Connected account has been suspended.") + else + to_chat(usr, "\icon[src]EFTPOS is not connected to an account.") + + else + ..() + +/obj/item/device/eftpos/Topic(var/href, var/href_list) + if(href_list["choice"]) + switch(href_list["choice"]) + if("change_code") + var/attempt_code = input("Re-enter the current EFTPOS access code", "Confirm old EFTPOS code") as num + if(attempt_code == access_code) + var/trycode = input("Enter a new access code for this device (4-6 digits, numbers only)", "Enter new EFTPOS code") as num + if(trycode >= 1000 && trycode <= 999999) + access_code = trycode + else + alert("That is not a valid code!") + print_reference() + else + to_chat(usr, "\icon[src]Incorrect code entered.") + if("change_id") + var/attempt_code = text2num(input("Re-enter the current EFTPOS access code", "Confirm EFTPOS code")) + if(attempt_code == access_code) + eftpos_name = sanitize(input("Enter a new terminal ID for this device", "Enter new EFTPOS ID"), MAX_NAME_LEN) + " EFTPOS scanner" + print_reference() + else + to_chat(usr, "\icon[src]Incorrect code entered.") + if("link_account") + var/attempt_account_num = input("Enter account number to pay EFTPOS charges into", "New account number") as num + var/attempt_pin = input("Enter pin code", "Account pin") as num + linked_account = attempt_account_access(attempt_account_num, attempt_pin, 1) + if(linked_account) + if(linked_account.suspended) + linked_account = null + to_chat(usr, "\icon[src]Account has been suspended.") + else + to_chat(usr, "\icon[src]Account not found.") + if("trans_purpose") + var/choice = sanitize(input("Enter reason for EFTPOS transaction", "Transaction purpose")) + if(choice) transaction_purpose = choice + if("trans_value") + var/try_num = input("Enter amount for EFTPOS transaction", "Transaction amount") as num + if(try_num < 0) + alert("That is not a valid amount!") + else + transaction_amount = try_num + if("toggle_lock") + if(transaction_locked) + if (transaction_paid) + transaction_locked = 0 + transaction_paid = 0 + else + var/attempt_code = input("Enter EFTPOS access code", "Reset Transaction") as num + if(attempt_code == access_code) + transaction_locked = 0 + transaction_paid = 0 + else if(linked_account) + transaction_locked = 1 + else + to_chat(usr, "\icon[src]No account connected to send transactions to.") + if("scan_card") + if(linked_account) + var/obj/item/I = usr.get_active_hand() + if (istype(I, /obj/item/weapon/card)) + scan_card(I) + else + to_chat(usr, "\icon[src]Unable to link accounts.") + if("reset") + //reset the access code - requires HoP/captain access + var/obj/item/I = usr.get_active_hand() + if (istype(I, /obj/item/weapon/card)) + var/obj/item/weapon/card/id/C = I + if(access_cent_captain in C.access || access_hop in C.access || access_captain in C.access) + access_code = 0 + to_chat(usr, "\icon[src]Access code reset to 0.") + else if (istype(I, /obj/item/weapon/card/emag)) + access_code = 0 + to_chat(usr, "\icon[src]Access code reset to 0.") + + src.attack_self(usr) + +/obj/item/device/eftpos/proc/scan_card(var/obj/item/weapon/card/I, var/obj/item/ID_container) + if (istype(I, /obj/item/weapon/card/id)) + var/obj/item/weapon/card/id/C = I + if(I==ID_container || ID_container == null) + usr.visible_message("\The [usr] swipes a card through \the [src].") + else + usr.visible_message("\The [usr] swipes \the [ID_container] through \the [src].") + if(transaction_locked && !transaction_paid) + if(linked_account) + if(!linked_account.suspended) + var/attempt_pin = "" + var/datum/money_account/D = get_account(C.associated_account_number) + if(D.security_level) + attempt_pin = input("Enter pin code", "EFTPOS transaction") as num + D = null + D = attempt_account_access(C.associated_account_number, attempt_pin, 2) + if(D) + if(!D.suspended) + if(transaction_amount <= D.money) + playsound(src, 'sound/machines/chime.ogg', 50, 1) + src.visible_message("\icon[src] \The [src] chimes.") + transaction_paid = 1 + + //transfer the money + var/datum/transaction/T = new("[linked_account.owner_name] (via [eftpos_name])", transaction_purpose, -transaction_amount, machine_id) + D.do_transaction(T) + + T = new(D.owner_name, transaction_purpose, transaction_amount, machine_id) + linked_account.do_transaction(T) + else + to_chat(usr, "\icon[src]You don't have that much money!") + else + to_chat(usr, "\icon[src]Your account has been suspended.") + else + to_chat(usr, "\icon[src]Unable to access account. Check security settings and try again.") + else + to_chat(usr, "\icon[src]Connected account has been suspended.") + else + to_chat(usr, "\icon[src]EFTPOS is not connected to an account.") + else if (istype(I, /obj/item/weapon/card/emag)) + if(transaction_locked) + if(transaction_paid) + to_chat(usr, "\icon[src]You stealthily swipe \the [I] through \the [src].") + transaction_locked = 0 + transaction_paid = 0 + else + usr.visible_message("\The [usr] swipes a card through \the [src].") + playsound(src, 'sound/machines/chime.ogg', 50, 1) + src.visible_message("\icon[src] \The [src] chimes.") + transaction_paid = 1 + else + ..() + + //emag? diff --git a/code/modules/economy/Events.dm b/code/modules/economy/Events.dm new file mode 100644 index 00000000..7119ded8 --- /dev/null +++ b/code/modules/economy/Events.dm @@ -0,0 +1,98 @@ + +/datum/event/economic_event + endWhen = 50 //this will be set randomly, later + announceWhen = 15 + var/event_type = 0 + var/list/cheaper_goods = list() + var/list/dearer_goods = list() + var/datum/trade_destination/affected_dest + +/datum/event/economic_event/start() + affected_dest = pickweight(weighted_randomevent_locations) + if(affected_dest.viable_random_events.len) + endWhen = rand(60,300) + event_type = pick(affected_dest.viable_random_events) + + if(!event_type) + return + + switch(event_type) + if(RIOTS) + dearer_goods = list(SECURITY) + cheaper_goods = list(MINERALS, FOOD) + if(WILD_ANIMAL_ATTACK) + cheaper_goods = list(ANIMALS) + dearer_goods = list(FOOD, BIOMEDICAL) + if(INDUSTRIAL_ACCIDENT) + dearer_goods = list(EMERGENCY, BIOMEDICAL, ROBOTICS) + if(BIOHAZARD_OUTBREAK) + dearer_goods = list(BIOMEDICAL, GAS) + if(PIRATES) + dearer_goods = list(SECURITY, MINERALS) + if(CORPORATE_ATTACK) + dearer_goods = list(SECURITY, MAINTENANCE) + if(ALIEN_RAIDERS) + dearer_goods = list(BIOMEDICAL, ANIMALS) + cheaper_goods = list(GAS, MINERALS) + if(AI_LIBERATION) + dearer_goods = list(EMERGENCY, GAS, MAINTENANCE) + if(MOURNING) + cheaper_goods = list(MINERALS, MAINTENANCE) + if(CULT_CELL_REVEALED) + dearer_goods = list(SECURITY, BIOMEDICAL, MAINTENANCE) + if(SECURITY_BREACH) + dearer_goods = list(SECURITY) + if(ANIMAL_RIGHTS_RAID) + dearer_goods = list(ANIMALS) + if(FESTIVAL) + dearer_goods = list(FOOD, ANIMALS) + for(var/good_type in dearer_goods) + affected_dest.temp_price_change[good_type] = rand(1,100) + for(var/good_type in cheaper_goods) + affected_dest.temp_price_change[good_type] = rand(1,100) / 100 + +/datum/event/economic_event/announce() + var/author = "Nyx Daily" + var/channel = author + + //see if our location has custom event info for this event + var/body = affected_dest.get_custom_eventstring() + if(!body) + switch(event_type) + if(RIOTS) + body = "[pick("Riots have","Unrest has")] broken out on planet [affected_dest.name]. Authorities call for calm, as [pick("various parties","rebellious elements","peacekeeping forces","\'REDACTED\'")] begin stockpiling weaponry and armour. Meanwhile, food and mineral prices are dropping as local industries attempt empty their stocks in expectation of looting." + if(WILD_ANIMAL_ATTACK) + body = "Local [pick("wildlife","animal life","fauna")] on planet [affected_dest.name] has been increasing in agression and raiding outlying settlements for food. Big game hunters have been called in to help alleviate the problem, but numerous injuries have already occurred." + if(INDUSTRIAL_ACCIDENT) + body = "[pick("An industrial accident","A smelting accident","A malfunction","A malfunctioning piece of machinery","Negligent maintenance","A cooleant leak","A ruptured conduit")] at a [pick("factory","installation","power plant","dockyards")] on [affected_dest.name] resulted in severe structural damage and numerous injuries. Repairs are ongoing." + if(BIOHAZARD_OUTBREAK) + body = "[pick("A \'REDACTED\'","A biohazard","An outbreak","A virus")] on [affected_dest.name] has resulted in quarantine, stopping much shipping in the area. Although the quarantine is now lifted, authorities are calling for deliveries of medical supplies to treat the infected, and gas to replace contaminated stocks." + if(PIRATES) + body = "[pick("Pirates","Criminal elements","A [pick("mercenary","Donk Co.","Waffle Co.","\'REDACTED\'")] strike force")] have [pick("raided","blockaded","attempted to blackmail","attacked")] [affected_dest.name] today. Security has been tightened, but many valuable minerals were taken." + if(CORPORATE_ATTACK) + body = "A small [pick("pirate","Cybersun Industries","Gorlex Marauders","mercenary")] fleet has precise-jumped into proximity with [affected_dest.name], [pick("for a smash-and-grab operation","in a hit and run attack","in an overt display of hostilities")]. Much damage was done, and security has been tightened since the incident." + if(ALIEN_RAIDERS) + if(prob(20)) + body = "The Tiger Co-operative have raided [affected_dest.name] today, no doubt on orders from their enigmatic masters. Stealing wildlife, farm animals, medical research materials and kidnapping civilians. [GLOB.using_map.company_name] authorities are standing by to counter attempts at bio-terrorism." + else + body = "[pick("The alien species designated \'United Exolitics\'","The alien species designated \'REDACTED\'","An unknown alien species")] have raided [affected_dest.name] today, stealing wildlife, farm animals, medical research materials and kidnapping civilians. It seems they desire to learn more about us, so the Navy will be standing by to accomodate them next time they try." + if(AI_LIBERATION) + body = "A [pick("\'REDACTED\' was detected on","S.E.L.F operative infiltrated","malignant computer virus was detected on","rogue [pick("slicer","hacker")] was apprehended on")] [affected_dest.name] today, and managed to infect [pick("\'REDACTED\'","a sentient sub-system","a class one AI","a sentient defence installation")] before it could be stopped. Many lives were lost as it systematically begin murdering civilians, and considerable work must be done to repair the affected areas." + if(MOURNING) + body = "[pick("The popular","The well-liked","The eminent","The well-known")] [pick("professor","entertainer","singer","researcher","public servant","administrator","ship captain","\'REDACTED\'")], [pick( random_name(pick(MALE,FEMALE)), 40; "\'REDACTED\'" )] has [pick("passed away","committed suicide","been murdered","died in a freakish accident")] on [affected_dest.name] today. The entire planet is in mourning, and prices have dropped for industrial goods as worker morale drops." + if(CULT_CELL_REVEALED) + body = "A [pick("dastardly","blood-thirsty","villanous","crazed")] cult of [pick("The Elder Gods","Nar'sie","an apocalyptic sect","\'REDACTED\'")] has [pick("been discovered","been revealed","revealed themselves","gone public")] on [affected_dest.name] earlier today. Public morale has been shaken due to [pick("certain","several","one or two")] [pick("high-profile","well known","popular")] individuals [pick("performing \'REDACTED\' acts","claiming allegiance to the cult","swearing loyalty to the cult leader","promising to aid to the cult")] before those involved could be brought to justice. The editor reminds all personnel that supernatural myths will not be tolerated on [GLOB.using_map.company_name] facilities." + if(SECURITY_BREACH) + body = "There was [pick("a security breach in","an unauthorised access in","an attempted theft in","an anarchist attack in","violent sabotage of")] a [pick("high-security","restricted access","classified","\'REDACTED\'")] [pick("\'REDACTED\'","section","zone","area")] this morning. Security was tightened on [affected_dest.name] after the incident, and the editor reassures all [GLOB.using_map.company_name] personnel that such lapses are rare." + if(ANIMAL_RIGHTS_RAID) + body = "[pick("Militant animal rights activists","Members of the terrorist group Animal Rights Consortium","Members of the terrorist group \'REDACTED\'")] have [pick("launched a campaign of terror","unleashed a swathe of destruction","raided farms and pastures","forced entry to \'REDACTED\'")] on [affected_dest.name] earlier today, freeing numerous [pick("farm animals","animals","\'REDACTED\'")]. Prices for tame and breeding animals have spiked as a result." + if(FESTIVAL) + body = "A [pick("festival","week long celebration","day of revelry","planet-wide holiday")] has been declared on [affected_dest.name] by [pick("Governor","Commissioner","General","Commandant","Administrator")] [random_name(pick(MALE,FEMALE))] to celebrate [pick("the birth of their [pick("son","daughter")]","coming of age of their [pick("son","daughter")]","the pacification of rogue military cell","the apprehension of a violent criminal who had been terrorising the planet")]. Massive stocks of food and meat have been bought driving up prices across the planet." + + news_network.SubmitArticle(body, author, channel, null, 1) + +/datum/event/economic_event/end() + for(var/good_type in dearer_goods) + affected_dest.temp_price_change[good_type] = 1 + for(var/good_type in cheaper_goods) + affected_dest.temp_price_change[good_type] = 1 diff --git a/code/modules/economy/Events_Mundane.dm b/code/modules/economy/Events_Mundane.dm new file mode 100644 index 00000000..9a9f1935 --- /dev/null +++ b/code/modules/economy/Events_Mundane.dm @@ -0,0 +1,220 @@ + +/datum/event/mundane_news + endWhen = 10 + +/datum/event/mundane_news/announce() + var/datum/trade_destination/affected_dest = pickweight(weighted_mundaneevent_locations) + var/event_type = 0 + if(affected_dest.viable_mundane_events.len) + event_type = pick(affected_dest.viable_mundane_events) + + if(!event_type) + return + + var/author = "Nyx Daily" + var/channel = author + + //see if our location has custom event info for this event + var/body = affected_dest.get_custom_eventstring() + if(!body) + body = "" + switch(event_type) + if(RESEARCH_BREAKTHROUGH) + body = "A major breakthough in the field of [pick("phoron research","super-compressed materials","nano-augmentation","bluespace research","volatile power manipulation")] \ + was announced [pick("yesterday","a few days ago","last week","earlier this month")] by a private firm on [affected_dest.name]. \ + [GLOB.using_map.company_name] declined to comment as to whether this could impinge on profits." + + if(ELECTION) + body = "The pre-selection of an additional candidates was announced for the upcoming [pick("supervisors council","advisory board","governership","board of inquisitors")] \ + election on [affected_dest.name] was announced earlier today, \ + [pick("media mogul","web celebrity", "industry titan", "superstar", "famed chef", "popular gardener", "ex-army officer", "multi-billionaire")] \ + [random_name(pick(MALE,FEMALE))]. In a statement to the media they said '[pick("My only goal is to help the [pick("sick","poor","children")]",\ + "I will maintain my company's record profits","I believe in our future","We must return to our moral core","Just like... chill out dudes")]'." + + if(RESIGNATION) + body = "[GLOB.using_map.company_name] regretfully announces the resignation of [pick("Sector Admiral","Division Admiral","Ship Admiral","Vice Admiral")] [random_name(pick(MALE,FEMALE))]." + if(prob(25)) + var/locstring = pick("Segunda","Salusa","Cepheus","Andromeda","Gruis","Corona","Aquila","Asellus") + " " + pick("I","II","III","IV","V","VI","VII","VIII") + body += " In a ceremony on [affected_dest.name] this afternoon, they will be awarded the \ + [pick("Red Star of Sacrifice","Purple Heart of Heroism","Blue Eagle of Loyalty","Green Lion of Ingenuity")] for " + if(prob(33)) + body += "their actions at the Battle of [pick(locstring,"REDACTED")]." + else if(prob(50)) + body += "their contribution to the colony of [locstring]." + else + body += "their loyal service over the years." + else if(prob(33)) + body += " They are expected to settle down in [affected_dest.name], where they have been granted a handsome pension." + else if(prob(50)) + body += " The news was broken on [affected_dest.name] earlier today, where they cited reasons of '[pick("health","family","REDACTED")]'" + else + body += " Administration Aerospace wishes them the best of luck in their retirement ceremony on [affected_dest.name]." + + if(CELEBRITY_DEATH) + body = "It is with regret today that we announce the sudden passing of the " + if(prob(33)) + body += "[pick("distinguished","decorated","veteran","highly respected")] \ + [pick("Ship's Captain","Vice Admiral","Colonel","Lieutenant Colonel")] " + else if(prob(50)) + body += "[pick("award-winning","popular","highly respected","trend-setting")] \ + [pick("comedian","singer/songwright","artist","playwright","TV personality","model")] " + else + body += "[pick("successful","highly respected","ingenious","esteemed")] \ + [pick("academic","Professor","Doctor","Scientist")] " + + body += "[random_name(pick(MALE,FEMALE))] on [affected_dest.name] [pick("last week","yesterday","this morning","two days ago","three days ago")]\ + [pick(". Assassination is suspected, but the perpetrators have not yet been brought to justice",\ + " due to mercenary infiltrators (since captured)",\ + " during an industrial accident",\ + " due to [pick("heart failure","kidney failure","liver failure","brain hemorrhage")]")]" + + if(BARGAINS) + body += "BARGAINS! BARGAINS! BARGAINS! Commerce Control on [affected_dest.name] wants you to know that everything must go! Across all retail centres, \ + all goods are being slashed, and all retailors are onboard - so come on over for the \[shopping\] time of your life." + + if(SONG_DEBUT) + body += "[pick("Singer","Singer/songwriter","Saxophonist","Pianist","Guitarist","TV personality","Star")] [random_name(pick(MALE,FEMALE))] \ + announced the debut of their new [pick("single","album","EP","label")] '[pick("Everyone's","Look at the","Baby don't eye those","All of those","Dirty nasty")] \ + [pick("roses","three stars","starships","nanobots","cyborgs",SPECIES_SKRELL,"Sren'darr")] \ + [pick("on Venus","on Reade","on Moghes","in my hand","slip through my fingers","die for you","sing your heart out","fly away")]' \ + with [pick("pre-puchases available","a release tour","cover signings","a launch concert")] on [affected_dest.name]." + + if(MOVIE_RELEASE) + body += "From the [pick("desk","home town","homeworld","mind")] of [pick("acclaimed","award-winning","popular","stellar")] \ + [pick("playwright","author","director","actor","TV star")] [random_name(pick(MALE,FEMALE))] comes the latest sensation: '\ + [pick("Deadly","The last","Lost","Dead")] [pick("Starships","Warriors","outcasts","Tajarans",SPECIES_UNATHI,SPECIES_SKRELL)] \ + [pick("of","from","raid","go hunting on","visit","ravage","pillage","destroy")] \ + [pick("Moghes","Earth","Biesel","Ahdomai","S'randarr","the Void","the Edge of Space")]'.\ + . Own it on webcast today, or visit the galactic premier on [affected_dest.name]!" + + if(BIG_GAME_HUNTERS) + body += "Game hunters on [affected_dest.name] " + if(prob(33)) + body += "were surprised when an unusual species experts have since identified as \ + [pick("a subclass of mammal","a divergent abhuman species","an intelligent species of lemur","organic/cyborg hybrids")] turned up. Believed to have been brought in by \ + [pick("alien smugglers","early colonists","mercenary raiders","unwitting tourists")], this is the first such specimen discovered in the wild." + else if(prob(50)) + body += "were attacked by a vicious [pick("nas'r","diyaab","samak","predator which has not yet been identified")]\ + . Officials urge caution, and locals are advised to stock up on armaments." + else + body += "brought in an unusually [pick("valuable","rare","large","vicious","intelligent")] [pick("mammal","predator","farwa","samak")] for inspection \ + [pick("today","yesterday","last week")]. Speculators suggest they may be tipped to break several records." + + if(GOSSIP) + body += "[pick("TV host","Webcast personality","Superstar","Model","Actor","Singer")] [random_name(pick(MALE,FEMALE))] " + if(prob(33)) + body += "and their partner announced the birth of their [pick("first","second","third")] child on [affected_dest.name] early this morning. \ + Doctors say the child is well, and the parents are considering " + if(prob(50)) + body += capitalize(pick(GLOB.first_names_female)) + else + body += capitalize(pick(GLOB.first_names_male)) + body += " for the name." + else if(prob(50)) + body += "announced their [pick("split","break up","marriage","engagement")] with [pick("TV host","webcast personality","superstar","model","actor","singer")] \ + [random_name(pick(MALE,FEMALE))] at [pick("a society ball","a new opening","a launch","a club")] on [affected_dest.name] yesterday, pundits are shocked." + else + body += "is recovering from plastic surgery in a clinic on [affected_dest.name] for the [pick("second","third","fourth")] time, reportedly having made the decision in response to " + body += "[pick("unkind comments by an ex","rumours started by jealous friends",\ + "the decision to be dropped by a major sponsor","a disasterous interview on Nyx Tonight")]." + if(TOURISM) + body += "Tourists are flocking to [affected_dest.name] after the surprise announcement of [pick("major shopping bargains by a wily retailer",\ + "a huge new ARG by a popular entertainment company","a secret tour by popular artiste [random_name(pick(MALE,FEMALE))]")]. \ + Nyx Daily is offering discount tickets for two to see [random_name(pick(MALE,FEMALE))] live in return for eyewitness reports and up to the minute coverage." + + news_network.SubmitArticle(body, author, channel, null, 1) + +/datum/event/trivial_news + endWhen = 10 + +/datum/event/trivial_news/announce() + var/author = "Editor Mike Hammers" + var/channel = "The Gibson Gazette" + + var/datum/trade_destination/affected_dest = pick(weighted_mundaneevent_locations) + var/body = pick( + "Tree stuck in tajaran; firefighters baffled.",\ + "Armadillos want aardvarks removed from dictionary claims 'here first'.",\ + "Angel found dancing on pinhead ordered to stop; cited for public nuisance.",\ + "Letters claim they are better than number; 'Always have been'.",\ + "Pens proclaim pencils obsolete, 'lead is dead'.",\ + "Rock and paper sues scissors for discrimination.",\ + "Steak tell-all book reveals he never liked sitting by potato.",\ + "Woodchuck stops counting how many times he’s chucked 'Never again'.",\ + "[affected_dest.name] clerk first person able to pronounce '@*$%!'.",\ + "[affected_dest.name] delis serving boiled paperback dictionaries, 'Adjectives chewy' customers declare.",\ + "[affected_dest.name] weather deemed 'boring'; meteors and rad storms to be imported.",\ + "Most [affected_dest.name] security officers prefer cream over sugar.",\ + "Palindrome speakers conference in [affected_dest.name]; 'Wow!' says Otto.",\ + "Question mark worshipped as deity by ancient [affected_dest.name] dwellers.",\ + "Spilled milk causes whole [affected_dest.name] populace to cry.",\ + "World largest carp patty at display on [affected_dest.name].",\ + "'Here kitty kitty' no longer preferred tajaran retrieval technique.",\ + "Man travels 7000 light years to retrieve lost hankie, 'It was my favourite'.",\ + "New bowling lane that shoots mini-meteors at bowlers very popular.",\ + "[pick(SPECIES_UNATHI,"Spacer")] gets tattoo of Nyx on chest '[pick("[GLOB.using_map.boss_short]","star","starship","asteroid")] tickles most'.",\ + "Skrell marries computer; wedding attended by 100 modems.",\ + "Chef reports successfully using harmonica as cheese grater.",\ + "[GLOB.using_map.company_name] invents handkerchief that says 'Bless you' after sneeze.",\ + "Clone accused of posing for other clones’s school photo.",\ + "Clone accused of stealing other clones’s employee of the month award.",\ + "Woman robs [station_name()] with hair dryer; crewmen love new style.",\ + "This space for rent.",\ + "[affected_dest.name] Baker Wins Pickled Crumpet Toss Three Years Running",\ + "Skrell Scientist Discovers Abacus Can Be Used To Dry Towels",\ + "Survey: 'Cheese Louise' Voted Best Pizza Restaurant In Nyx",\ + "I Was Framed, jokes [affected_dest.name] artist",\ + "Mysterious Loud Rumbling Noises In [affected_dest.name] Found To Be Mysterious Loud Rumblings",\ + "Alien ambassador becomes lost on [affected_dest.name], refuses to ask for directions",\ + "Swamp Gas Verified To Be Exhalations Of Stars--Movie Stars--Long Passed",\ + "Tainted Broccoli Weapon Of Choice For Efficient Assassins",\ + "Chefs Find Broccoli Effective Tool For Cutting Cheese",\ + "Broccoli Found To Cause Grumpiness In Monkeys",\ + "Survey: 80% Of People on [affected_dest.name] Love Clog-Dancing",\ + "Giant Hairball Has Perfect Grammar But Rolls rr's Too Much, Linguists Say",\ + "[affected_dest.name] Phonebooks Print All Wrong Numbers; Results In 15 New Marriages",\ + "Tajaran Burglar Spotted on [affected_dest.name], Mistaken For Dalmatian",\ + "Gibson Gazette Updates Frequently Absurd, Poll Indicates",\ + "Esoteric Verbosity Culminates In Communicative Ennui, [affected_dest.name] Academics Note",\ + "Taj Demand Longer Breaks, Cleaner Litter, Slower Mice",\ + "Survey: 3 Out Of 5 Skrell Loathe Modern Art",\ + "Skrell Scientist Discovers Gravity While Falling Down Stairs",\ + "Boy Saves Tajaran From Tree on [affected_dest.name], Thousands Cheer",\ + "Shipment Of Apples Overturns, [affected_dest.name] Diner Offers Applesauce Special",\ + "Spotted Owl Spotted on [affected_dest.name]",\ + "Humans Everywhere Agree: Purring Tajarans Are Happy Tajarans",\ + "From The Desk Of Wise Guy Sammy: One Word In This Gazette Is Sdrawkcab",\ + "From The Desk Of Wise Guy Sammy: It's Hard To Have Too Much Shelf Space",\ + "From The Desk Of Wise Guy Sammy: Wine And Friendships Get Better With Age",\ + "From The Desk Of Wise Guy Sammy: The Insides Of Golf Balls Are Mostly Rubber Bands",\ + "From The Desk Of Wise Guy Sammy: You Don't Have To Fool All The People, Just The Right Ones",\ + "From The Desk Of Wise Guy Sammy: If You Made The Mess, You Clean It Up",\ + "From The Desk Of Wise Guy Sammy: It Is Easier To Get Forgiveness Than Permission",\ + "From The Desk Of Wise Guy Sammy: Check Your Facts Before Making A Fool Of Yourself",\ + "From The Desk Of Wise Guy Sammy: You Can't Outwait A Bureaucracy",\ + "From The Desk Of Wise Guy Sammy: It's Better To Yield Right Of Way Than To Demand It",\ + "From The Desk Of Wise Guy Sammy: A Person Who Likes Cats Can't Be All Bad",\ + "From The Desk Of Wise Guy Sammy: Help Is The Sunny Side Of Control",\ + "From The Desk Of Wise Guy Sammy: Two Points Determine A Straight Line",\ + "From The Desk Of Wise Guy Sammy: Reading Improves The Mind And Lifts The Spirit",\ + "From The Desk Of Wise Guy Sammy: Better To Aim High And Miss Then To Aim Low And Hit",\ + "From The Desk Of Wise Guy Sammy: Meteors Often Strike The Same Place More Than Once",\ + "Tommy B. Saif Sez: Look Both Ways Before Boarding The Shuttle",\ + "Tommy B. Saif Sez: Hold On; Sudden Stops Sometimes Necessary",\ + "Tommy B. Saif Sez: Keep Fingers Away From Moving Panels",\ + "Tommy B. Saif Sez: No Left Turn, Except Shuttles",\ + "Tommy B. Saif Sez: Return Seats And Trays To Their Proper Upright Position",\ + "Tommy B. Saif Sez: Eating And Drinking In Docking Bays Is Prohibited",\ + "Tommy B. Saif Sez: Accept No Substitutes, And Don't Be Fooled By Imitations",\ + "Tommy B. Saif Sez: Do Not Remove This Tag Under Penalty Of Law",\ + "Tommy B. Saif Sez: Always Mix Thoroughly When So Instructed",\ + "Tommy B. Saif Sez: Try To Keep Six Month's Expenses In Reserve",\ + "Tommy B. Saif Sez: Change Not Given Without Purchase",\ + "Tommy B. Saif Sez: If You Break It, You Buy It",\ + "Tommy B. Saif Sez: Reservations Must Be Cancelled 48 Hours Prior To Event To Obtain Refund",\ + "Doughnuts: Is There Anything They Can't Do",\ + "If Tin Whistles Are Made Of Tin, What Do They Make Foghorns Out Of?",\ + "Broccoli discovered to be colonies of tiny aliens with murder on their minds"\ + ) + + news_network.SubmitArticle(body, author, channel, null, 1) diff --git a/code/modules/economy/TradeDestinations.dm b/code/modules/economy/TradeDestinations.dm new file mode 100644 index 00000000..e9581502 --- /dev/null +++ b/code/modules/economy/TradeDestinations.dm @@ -0,0 +1,110 @@ + +var/list/weighted_randomevent_locations = list() +var/list/weighted_mundaneevent_locations = list() + +/datum/trade_destination + var/name = "" + var/description = "" + var/distance = 0 + var/list/willing_to_buy = list() + var/list/willing_to_sell = list() + var/can_shuttle_here = 0 //one day crew from the exodus will be able to travel to this destination + var/list/viable_random_events = list() + var/list/temp_price_change[BIOMEDICAL] + var/list/viable_mundane_events = list() + +/datum/trade_destination/proc/get_custom_eventstring(var/event_type) + return null + +//distance is measured in AU and co-relates to travel time +/datum/trade_destination/centcomm + name = "CentComm" + description = "NanoTrasen's administrative centre for Tau Ceti." + distance = 1.2 + willing_to_buy = list() + willing_to_sell = list() + viable_random_events = list(SECURITY_BREACH, CORPORATE_ATTACK, AI_LIBERATION) + viable_mundane_events = list(ELECTION, RESIGNATION, CELEBRITY_DEATH) + +/datum/trade_destination/anansi + name = "NSS Anansi" + description = "Medical station ran by Second Red Cross (but owned by NT) for handling emergency cases from nearby colonies." + distance = 1.7 + willing_to_buy = list() + willing_to_sell = list() + viable_random_events = list(SECURITY_BREACH, CULT_CELL_REVEALED, BIOHAZARD_OUTBREAK, PIRATES, ALIEN_RAIDERS) + viable_mundane_events = list(RESEARCH_BREAKTHROUGH, RESEARCH_BREAKTHROUGH, BARGAINS, GOSSIP) + +/datum/trade_destination/anansi/get_custom_eventstring(var/event_type) + if(event_type == RESEARCH_BREAKTHROUGH) + return "Thanks to research conducted on the NSS Anansi, Second Red Cross Society wishes to announce a major breakthough in the field of \ + [pick("mind-machine interfacing","neuroscience","nano-augmentation","genetics")]. [GLOB.using_map.company_name] is expected to announce a co-exploitation deal within the fortnight." + return null + +/datum/trade_destination/icarus + name = "NDV Icarus" + description = "Corvette assigned to patrol local space." + distance = 0.1 + willing_to_buy = list() + willing_to_sell = list() + viable_random_events = list(SECURITY_BREACH, AI_LIBERATION, PIRATES) + +/datum/trade_destination/redolant + name = "OAV Redolant" + description = "Osiris Atmospherics station in orbit around the only gas giant insystem. They retain tight control over shipping rights, and Osiris warships protecting their prize are not an uncommon sight in Tau Ceti." + distance = 0.6 + willing_to_buy = list() + willing_to_sell = list() + viable_random_events = list(INDUSTRIAL_ACCIDENT, PIRATES, CORPORATE_ATTACK) + viable_mundane_events = list(RESEARCH_BREAKTHROUGH, RESEARCH_BREAKTHROUGH) + +/datum/trade_destination/redolant/get_custom_eventstring(var/event_type) + if(event_type == RESEARCH_BREAKTHROUGH) + return "Thanks to research conducted on the OAV Redolant, Osiris Atmospherics wishes to announce a major breakthough in the field of \ + [pick("phoron research","high energy flux capacitance","super-compressed materials","theoretical particle physics")]. [GLOB.using_map.company_name] is expected to announce a co-exploitation deal within the fortnight." + return null + +/datum/trade_destination/beltway + name = "Beltway mining chain" + description = "A co-operative effort between Beltway and NanoTrasen to exploit the rich outer asteroid belt of the Tau Ceti system." + distance = 7.5 + willing_to_buy = list() + willing_to_sell = list() + viable_random_events = list(PIRATES, INDUSTRIAL_ACCIDENT) + viable_mundane_events = list(TOURISM) + +/datum/trade_destination/biesel + name = "Biesel" + description = "Large ship yards, strong economy and a stable, well-educated populace, Biesel largely owes allegiance to Sol / Vessel Contracting and begrudgingly tolerates NT. Capital is Lowell City." + distance = 2.3 + willing_to_buy = list() + willing_to_sell = list() + viable_random_events = list(RIOTS, INDUSTRIAL_ACCIDENT, BIOHAZARD_OUTBREAK, CULT_CELL_REVEALED, FESTIVAL, MOURNING) + viable_mundane_events = list(BARGAINS, GOSSIP, SONG_DEBUT, MOVIE_RELEASE, ELECTION, TOURISM, RESIGNATION, CELEBRITY_DEATH) + +/datum/trade_destination/new_gibson + name = "New Gibson" + description = "Heavily industrialised rocky planet containing the majority of the planet-bound resources in the system, New Gibson is torn by unrest and has very little wealth to call it's own except in the hands of the corporations who jostle with NT for control." + distance = 6.6 + willing_to_buy = list() + willing_to_sell = list() + viable_random_events = list(RIOTS, INDUSTRIAL_ACCIDENT, BIOHAZARD_OUTBREAK, CULT_CELL_REVEALED, FESTIVAL, MOURNING) + viable_mundane_events = list(ELECTION, TOURISM, RESIGNATION) + +/datum/trade_destination/luthien + name = "Luthien" + description = "A small colony established on a feral, untamed world (largely jungle). Savages and wild beasts attack the outpost regularly, although NT maintains tight military control." + distance = 8.9 + willing_to_buy = list() + willing_to_sell = list() + viable_random_events = list(WILD_ANIMAL_ATTACK, CULT_CELL_REVEALED, FESTIVAL, MOURNING, ANIMAL_RIGHTS_RAID, ALIEN_RAIDERS) + viable_mundane_events = list(ELECTION, TOURISM, BIG_GAME_HUNTERS, RESIGNATION) + +/datum/trade_destination/reade + name = "Reade" + description = "A cold, metal-deficient world, NT maintains large pastures in whatever available space in an attempt to salvage something from this profitless colony." + distance = 7.5 + willing_to_buy = list() + willing_to_sell = list() + viable_random_events = list(WILD_ANIMAL_ATTACK, CULT_CELL_REVEALED, FESTIVAL, MOURNING, ANIMAL_RIGHTS_RAID, ALIEN_RAIDERS) + viable_mundane_events = list(ELECTION, TOURISM, BIG_GAME_HUNTERS, RESIGNATION) diff --git a/code/modules/economy/cash.dm b/code/modules/economy/cash.dm new file mode 100644 index 00000000..30724a9c --- /dev/null +++ b/code/modules/economy/cash.dm @@ -0,0 +1,183 @@ +/obj/item/weapon/spacecash + name = "0 credits" + desc = "It's worth 0 credits." + gender = PLURAL + icon = 'icons/obj/items.dmi' + icon_state = "spacecash1" + opacity = 0 + density = 0 + anchored = 0.0 + force = 1.0 + throwforce = 1.0 + throw_speed = 1 + throw_range = 2 + w_class = ITEM_SIZE_TINY + var/access = list() + access = access_crate_cash + var/worth = 0 + var/global/denominations = list(1000,500,200,100,50,20,10,1) + +/obj/item/weapon/spacecash/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/spacecash)) + if(istype(W, /obj/item/weapon/spacecash/ewallet)) return 0 + + var/obj/item/weapon/spacecash/bundle/bundle + if(!istype(W, /obj/item/weapon/spacecash/bundle)) + var/obj/item/weapon/spacecash/cash = W + user.drop_from_inventory(cash) + bundle = new (src.loc) + bundle.worth += cash.worth + qdel(cash) + else //is bundle + bundle = W + bundle.worth += src.worth + bundle.update_icon() + if(istype(user, /mob/living/carbon/human)) + var/mob/living/carbon/human/h_user = user + h_user.drop_from_inventory(src) + h_user.drop_from_inventory(bundle) + h_user.put_in_hands(bundle) + to_chat(user, "You add [src.worth] credits worth of money to the bundles.
            It holds [bundle.worth] credits now.
            ") + qdel(src) + + +/obj/item/weapon/spacecash/proc/getMoneyImages() + if(icon_state) + return list(icon_state) + +/obj/item/weapon/spacecash/bundle + name = "pile of credits" + icon_state = "" + desc = "They are worth 0 credits." + worth = 0 + +/obj/item/weapon/spacecash/bundle/getMoneyImages() + if(icon_state) + return list(icon_state) + . = list() + var/sum = src.worth + var/num = 0 + for(var/i in denominations) + while(sum >= i && num < 50) + sum -= i + num++ + . += "spacecash[i]" + if(num == 0) // Less than one credit, let's just make it look like 1 for ease + . += "spacecash1" + +/obj/item/weapon/spacecash/bundle/update_icon() + overlays.Cut() + var/list/images = src.getMoneyImages() + + for(var/A in images) + var/image/banknote = image('icons/obj/items.dmi', A) + var/matrix/M = matrix() + M.Translate(rand(-6, 6), rand(-4, 8)) + M.Turn(pick(-45, -27.5, 0, 0, 0, 0, 0, 0, 0, 27.5, 45)) + banknote.transform = M + src.overlays += banknote + + src.desc = "They are worth [worth] credits." + if(worth in denominations) + src.SetName("[worth] credit") + else + src.SetName("pile of [worth] credits") + + if(overlays.len <= 2) + w_class = ITEM_SIZE_TINY + else + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/spacecash/bundle/attack_self() + var/amount = input(usr, "How many credits do you want to take? (0 to [src.worth])", "Take Money", 20) as num + amount = round(Clamp(amount, 0, src.worth)) + if(amount==0) return 0 + + src.worth -= amount + src.update_icon() + if(!worth) + usr.drop_from_inventory(src) + if(amount in list(1000,500,200,100,50,20,1)) + var/cashtype = text2path("/obj/item/weapon/spacecash/bundle/c[amount]") + var/obj/cash = new cashtype (usr.loc) + usr.put_in_hands(cash) + else + var/obj/item/weapon/spacecash/bundle/bundle = new (usr.loc) + bundle.worth = amount + bundle.update_icon() + usr.put_in_hands(bundle) + if(!worth) + qdel(src) + +/obj/item/weapon/spacecash/bundle/c1 + name = "1 credit" + icon_state = "spacecash1" + desc = "It's worth 1 credit." + worth = 1 + +/obj/item/weapon/spacecash/bundle/c10 + name = "10 credits" + icon_state = "spacecash10" + desc = "It's worth 10 credits." + worth = 10 + +/obj/item/weapon/spacecash/bundle/c20 + name = "20 credits" + icon_state = "spacecash20" + desc = "It's worth 20 credits." + worth = 20 + +/obj/item/weapon/spacecash/bundle/c50 + name = "50 credits" + icon_state = "spacecash50" + desc = "It's worth 50 credits." + worth = 50 + +/obj/item/weapon/spacecash/bundle/c100 + name = "100 credits" + icon_state = "spacecash100" + desc = "It's worth 100 credits." + worth = 100 + +/obj/item/weapon/spacecash/bundle/c200 + name = "200 credits" + icon_state = "spacecash200" + desc = "It's worth 200 credits." + worth = 200 + +/obj/item/weapon/spacecash/bundle/c500 + name = "500 credits" + icon_state = "spacecash500" + desc = "It's worth 500 credits." + worth = 500 + +/obj/item/weapon/spacecash/bundle/c1000 + name = "1000 credits" + icon_state = "spacecash1000" + desc = "It's worth 1000 credits." + worth = 1000 + +proc/spawn_money(var/sum, spawnloc, mob/living/carbon/human/human_user as mob) + if(sum in list(1000,500,200,100,50,20,10,1)) + var/cash_type = text2path("/obj/item/weapon/spacecash/bundle/c[sum]") + var/obj/cash = new cash_type (usr.loc) + if(ishuman(human_user) && !human_user.get_active_hand()) + human_user.put_in_hands(cash) + else + var/obj/item/weapon/spacecash/bundle/bundle = new (spawnloc) + bundle.worth = sum + bundle.update_icon() + if (ishuman(human_user) && !human_user.get_active_hand()) + human_user.put_in_hands(bundle) + return + +/obj/item/weapon/spacecash/ewallet + name = "Charge card" + icon_state = "efundcard" + desc = "A card that holds an amount of money." + var/owner_name = "" //So the ATM can set it so the EFTPOS can put a valid name on transactions. + +/obj/item/weapon/spacecash/ewallet/examine(mob/user) + . = ..(user) + if (!(user in view(2)) && user!=src.loc) return + to_chat(user, "Charge card's owner: [src.owner_name]. credits remaining: [src.worth].") diff --git a/code/modules/economy/economy_misc.dm b/code/modules/economy/economy_misc.dm new file mode 100644 index 00000000..97f4bd0c --- /dev/null +++ b/code/modules/economy/economy_misc.dm @@ -0,0 +1,76 @@ + +#define RIOTS 1 +#define WILD_ANIMAL_ATTACK 2 +#define INDUSTRIAL_ACCIDENT 3 +#define BIOHAZARD_OUTBREAK 4 +#define WARSHIPS_ARRIVE 5 +#define PIRATES 6 +#define CORPORATE_ATTACK 7 +#define ALIEN_RAIDERS 8 +#define AI_LIBERATION 9 +#define MOURNING 10 +#define CULT_CELL_REVEALED 11 +#define SECURITY_BREACH 12 +#define ANIMAL_RIGHTS_RAID 13 +#define FESTIVAL 14 + +#define RESEARCH_BREAKTHROUGH 15 +#define BARGAINS 16 +#define SONG_DEBUT 17 +#define MOVIE_RELEASE 18 +#define BIG_GAME_HUNTERS 19 +#define ELECTION 20 +#define GOSSIP 21 +#define TOURISM 22 +#define CELEBRITY_DEATH 23 +#define RESIGNATION 24 + +#define DEFAULT 1 + +#define ADMINISTRATIVE 2 +#define CLOTHING 3 +#define SECURITY 4 +#define SPECIAL_SECURITY 5 + +#define FOOD 6 +#define ANIMALS 7 + +#define MINERALS 8 + +#define EMERGENCY 9 +#define GAS 10 +#define MAINTENANCE 11 +#define ELECTRICAL 12 +#define ROBOTICS 13 +#define BIOMEDICAL 14 + +#define GEAR_EVA 15 + +//Note that you have to specify each subspecies individually. Shouldn't be a big deal. +/var/list/economic_species_modifier = list( + /datum/species/human = 10 + ) + +//---- The following corporations are friendly with NanoTrasen and loosely enable trade and travel: +//Corporation NanoTrasen - Generalised / high tech research and phoron exploitation. +//Corporation Vessel Contracting - Ship and station construction, materials research. +//Corporation Osiris Atmospherics - Atmospherics machinery construction and chemical research. +//Corporation Second Red Cross Society - 26th century Red Cross reborn as a dominating economic force in biomedical science (research and materials). +//Corporation Blue Industries - High tech and high energy research, in particular into the mysteries of bluespace manipulation and power generation. +//Corporation Kusanagi Robotics - Founded by robotics legend Kaito Kusanagi in the 2070s, they have been on the forefront of mechanical augmentation and robotics development ever since. +//Corporation Free traders - Not so much a corporation as a loose coalition of spacers, Free Traders are a roving band of smugglers, traders and fringe elements following a rigid (if informal) code of loyalty and honour. Mistrusted by most corporations, they are tolerated because of their uncanny ability to smell out a profit. + +//---- Descriptions of destination types +//Space stations can be purpose built for a number of different things, but generally require regular shipments of essential supplies. +//Corvettes are small, fast warships generally assigned to border patrol or chasing down smugglers. +//Battleships are large, heavy cruisers designed for slugging it out with other heavies or razing planets. +//Yachts are fast civilian craft, often used for pleasure or smuggling. +//Destroyers are medium sized vessels, often used for escorting larger ships but able to go toe-to-toe with them if need be. +//Frigates are medium sized vessels, often used for escorting larger ships. They will rapidly find themselves outclassed if forced to face heavy warships head on. + +var/global/datum/money_account/vendor_account +var/global/datum/money_account/station_account +var/global/list/datum/money_account/department_accounts = list() +var/global/num_financial_terminals = 1 +var/global/next_account_number = 0 +var/global/list/all_money_accounts = list() diff --git a/code/modules/emoji/emoji_parse.dm b/code/modules/emoji/emoji_parse.dm new file mode 100644 index 00000000..c5334123 --- /dev/null +++ b/code/modules/emoji/emoji_parse.dm @@ -0,0 +1,27 @@ +/proc/emoji_parse(text) + . = text + var/static/list/emojis = icon_states(icon('icons/emoji.dmi')) + var/parsed = "" + var/pos = 1 + var/search = 0 + var/emoji = "" + while(1) + search = findtext(text, ":", pos) + parsed += copytext(text, pos, search) + if(search) + pos = search + search = findtext(text, ":", pos+1) + if(search) + emoji = lowertext(copytext(text, pos+1, search)) + if(emoji in emojis) + parsed += icon2html('icons/emoji.dmi', world, emoji) + pos = search + 1 + else + parsed += copytext(text, pos, search) + pos = search + emoji = "" + continue + else + parsed += copytext(text, pos, search) + break + return parsed \ No newline at end of file diff --git a/code/modules/emotes/definitions/_mob.dm b/code/modules/emotes/definitions/_mob.dm new file mode 100644 index 00000000..dd5a7f1e --- /dev/null +++ b/code/modules/emotes/definitions/_mob.dm @@ -0,0 +1,170 @@ +/mob + var/list/default_emotes = list() + var/list/usable_emotes = list() + +/mob/proc/update_emotes(var/skip_sort) + usable_emotes.Cut() + for(var/emote in default_emotes) + var/decl/emote/emote_datum = decls_repository.get_decl(emote) + if(emote_datum.check_user(src)) + usable_emotes[emote_datum.key] = emote_datum + if(!skip_sort) + usable_emotes = sortAssoc(usable_emotes) + +/mob/Initialize() + . = ..() + update_emotes() + +// Specific defines follow. +/mob/living/carbon/alien + default_emotes = list( + /decl/emote/visible, + /decl/emote/visible/scratch, + /decl/emote/visible/drool, + /decl/emote/visible/nod, + /decl/emote/visible/sway, + /decl/emote/visible/sulk, + /decl/emote/visible/twitch, + /decl/emote/visible/dance, + /decl/emote/visible/roll, + /decl/emote/visible/shake, + /decl/emote/visible/jump, + /decl/emote/visible/hiss, + /decl/emote/visible/shiver, + /decl/emote/visible/collapse, + /decl/emote/audible, + /decl/emote/audible/deathgasp_alien, + /decl/emote/audible/whimper, + /decl/emote/audible/gasp, + /decl/emote/audible/scretch, + /decl/emote/audible/choke, + /decl/emote/audible/moan, + /decl/emote/audible/gnarl, + /decl/emote/audible/chirp + ) + +/mob/living/carbon/brain/can_emote() + return (istype(container, /obj/item/device/mmi) && ..()) + +/mob/living/carbon/brain + default_emotes = list( + /decl/emote/audible/alarm, + /decl/emote/audible/alert, + /decl/emote/audible/notice, + /decl/emote/audible/whistle, + /decl/emote/audible/synth, + /decl/emote/audible/boop, + /decl/emote/visible/blink, + /decl/emote/visible/flash + ) + +/mob/living/carbon/human + default_emotes = list( + /decl/emote/visible/blink, + /decl/emote/audible/synth, + /decl/emote/audible/synth/ping, + /decl/emote/audible/synth/buzz, + /decl/emote/audible/synth/confirm, + /decl/emote/audible/synth/deny, + /decl/emote/visible/nod, + /decl/emote/visible/shake, + /decl/emote/visible/shiver, + /decl/emote/visible/collapse, + /decl/emote/audible/gasp, + /decl/emote/audible/sneeze, + /decl/emote/audible/sniff, + /decl/emote/audible/snore, + /decl/emote/audible/whimper, + /decl/emote/audible/yawn, + /decl/emote/audible/clap, + /decl/emote/audible/chuckle, + /decl/emote/audible/cough, + /decl/emote/audible/cry, + /decl/emote/audible/sigh, + /decl/emote/audible/laugh, + /decl/emote/audible/mumble, + /decl/emote/audible/grumble, + /decl/emote/audible/groan, + /decl/emote/audible/moan, + /decl/emote/audible/grunt, + /decl/emote/human, + /decl/emote/human/deathgasp, + /decl/emote/audible/giggle, + /decl/emote/audible/scream, + /decl/emote/visible/airguitar, + /decl/emote/visible/blink_r, + /decl/emote/visible/bow, + /decl/emote/visible/salute, + /decl/emote/visible/flap, + /decl/emote/visible/aflap, + /decl/emote/visible/drool, + /decl/emote/visible/eyebrow, + /decl/emote/visible/twitch, + /decl/emote/visible/twitch_v, + /decl/emote/visible/faint, + /decl/emote/visible/frown, + /decl/emote/visible/blush, + /decl/emote/visible/wave, + /decl/emote/visible/glare, + /decl/emote/visible/stare, + /decl/emote/visible/look, + /decl/emote/visible/point, + /decl/emote/visible/raise, + /decl/emote/visible/grin, + /decl/emote/visible/shrug, + /decl/emote/visible/smile, + /decl/emote/visible/pale, + /decl/emote/visible/tremble, + /decl/emote/visible/wink, + /decl/emote/visible/hug, + /decl/emote/visible/dap, + /decl/emote/visible/signal, + /decl/emote/visible/handshake, + /decl/emote/human/poo, + /decl/emote/human/pee, + /decl/emote/audible/clearthroat, + /decl/emote/audible/hem, + /decl/emote/audible/knuckles + ) + +/mob/living/silicon/robot + default_emotes = list( + /decl/emote/audible/clap, + /decl/emote/visible/bow, + /decl/emote/visible/salute, + /decl/emote/visible/flap, + /decl/emote/visible/aflap, + /decl/emote/visible/twitch, + /decl/emote/visible/twitch_v, + /decl/emote/visible/nod, + /decl/emote/visible/shake, + /decl/emote/visible/glare, + /decl/emote/visible/look, + /decl/emote/visible/stare, + /decl/emote/visible/deathgasp_robot, + /decl/emote/audible/synth, + /decl/emote/audible/synth/ping, + /decl/emote/audible/synth/buzz, + /decl/emote/audible/synth/confirm, + /decl/emote/audible/synth/deny, + /decl/emote/audible/synth/security, + /decl/emote/audible/synth/security/halt + ) + +/mob/living/carbon/slime + default_emotes = list( + /decl/emote/audible/moan, + /decl/emote/visible/twitch, + /decl/emote/visible/sway, + /decl/emote/visible/shiver, + /decl/emote/visible/bounce, + /decl/emote/visible/jiggle, + /decl/emote/visible/lightup, + /decl/emote/visible/vibrate, + /decl/emote/slime, + /decl/emote/slime/pout, + /decl/emote/slime/sad, + /decl/emote/slime/angry, + /decl/emote/slime/frown, + /decl/emote/slime/smile + ) diff --git a/code/modules/emotes/definitions/_species.dm b/code/modules/emotes/definitions/_species.dm new file mode 100644 index 00000000..7b692818 --- /dev/null +++ b/code/modules/emotes/definitions/_species.dm @@ -0,0 +1,53 @@ +/datum/species + var/list/default_emotes = list() + +/mob/living/carbon/update_emotes() + . = ..(skip_sort=1) + if(species) + for(var/emote in species.default_emotes) + var/decl/emote/emote_datum = decls_repository.get_decl(emote) + if(emote_datum.check_user(src)) + usable_emotes[emote_datum.key] = emote_datum + usable_emotes = sortAssoc(usable_emotes) + +// Specific defines follow. +/datum/species/slime + default_emotes = list( + /decl/emote/visible/bounce, + /decl/emote/visible/jiggle, + /decl/emote/visible/lightup, + /decl/emote/visible/vibrate + ) + +/datum/species/unathi + default_emotes = list( + /decl/emote/human/swish, + /decl/emote/human/wag, + /decl/emote/human/sway, + /decl/emote/human/qwag, + /decl/emote/human/fastsway, + /decl/emote/human/swag, + /decl/emote/human/stopsway + ) + +/datum/species/tajaran + default_emotes = list( + /decl/emote/human/swish, + /decl/emote/human/wag, + /decl/emote/human/sway, + /decl/emote/human/qwag, + /decl/emote/human/fastsway, + /decl/emote/human/swag, + /decl/emote/human/stopsway + ) + +/datum/species/nabber + default_emotes = list( + /decl/emote/audible/bug_hiss, + /decl/emote/audible/bug_buzz, + /decl/emote/audible/bug_chitter + ) + +/mob/living/carbon/human/set_species(var/new_species, var/default_colour) + . = ..() + update_emotes() diff --git a/code/modules/emotes/definitions/audible.dm b/code/modules/emotes/definitions/audible.dm new file mode 100644 index 00000000..51ccca30 --- /dev/null +++ b/code/modules/emotes/definitions/audible.dm @@ -0,0 +1,405 @@ +/decl/emote/audible + key = "burp" + emote_message_3p = "USER burps." + message_type = AUDIBLE_MESSAGE + var/emote_sound + +/decl/emote/audible/do_extra(var/mob/user) + user.handle_emote_CD() + if(emote_sound) + playsound(user.loc, emote_sound, 50, 0) + +/decl/emote/audible/knuckles + key = "crack" + emote_message_3p = "USER cracks their knuckles." + emote_sound = 'sound/voice/emotes/knuckles.ogg' + +/decl/emote/audible/deathgasp_alien + key = "deathgasp" + emote_message_3p = "USER lets out a waning guttural screech, green blood bubbling from its maw." + +/decl/emote/audible/whimper + key ="whimper" + +/decl/emote/audible/whimper/do_emote(var/mob/living/carbon/human/user) + var/emotesound = null + if(user.isMonkey()) + return + + else if(user.gender == MALE) + emotesound = "sound/voice/emotes/whimper_male[rand(1,3)].ogg" + + else + emotesound = "sound/voice/emotes/whimper_female[rand(1,3)].ogg" + + if(emotesound) + playsound(user, emotesound, 50, 0, 1) + + user.custom_emote(2,"whimpers.") + user.handle_emote_CD() + +/decl/emote/audible/gasp + key ="gasp" + emote_message_3p = "USER gasps." + conscious = 0 + +/decl/emote/audible/scretch + key ="scretch" + emote_message_3p = "USER scretches." + +/decl/emote/audible/choke + key ="choke" + emote_message_3p = "USER chokes." + conscious = 0 + +/decl/emote/audible/gnarl + key ="gnarl" + emote_message_3p = "USER gnarls and shows its teeth.." + +/decl/emote/audible/chirp + key ="chirp" + emote_message_3p = "USER chirps!" + emote_sound = 'sound/misc/nymphchirp.ogg' + +/decl/emote/audible/alarm + key = "alarm" + emote_message_1p = "You sound an alarm." + emote_message_3p = "USER sounds an alarm." + +/decl/emote/audible/alert + key = "alert" + emote_message_1p = "You let out a distressed noise." + emote_message_3p = "USER lets out a distressed noise." + +/decl/emote/audible/notice + key = "notice" + emote_message_1p = "You play a loud tone." + emote_message_3p = "USER plays a loud tone." + +/decl/emote/audible/whistle + key = "whistle" + emote_message_1p = "You whistle." + emote_message_3p = "USER whistles." + +/decl/emote/audible/boop + key = "boop" + emote_message_1p = "You boop." + emote_message_3p = "USER boops." + +/decl/emote/audible/sneeze + key = "sneeze" + +/decl/emote/audible/sneeze/do_emote(var/mob/living/carbon/human/user) + var/emotesound = null + if(user.isMonkey()) + return + + else if(user.gender == MALE) + emotesound = "sound/voice/emotes/sneezem[rand(1,2)].ogg" + + else + emotesound = "sound/voice/emotes/sneezef[rand(1,2)].ogg" + + if(emotesound) + playsound(user, emotesound, 50, 0, 1) + + user.custom_emote(2,"sneezes.") + user.handle_emote_CD() + + +/decl/emote/audible/sniff + key = "sniff" + emote_message_3p = "USER sniffs." + emote_sound = 'sound/voice/emotes/sniff.ogg' + +/decl/emote/audible/snore + key = "snore" + emote_message_3p = "USER snores." + conscious = 0 + +/decl/emote/audible/whimper + key = "whimper" + emote_message_3p = "USER whimpers." + +/decl/emote/audible/yawn + key = "yawn" + +/decl/emote/audible/yawn/do_emote(var/mob/living/carbon/human/user) + var/emotesound = null + if(user.isMonkey()) + return + + else if(user.gender == MALE) + emotesound = "sound/voice/emotes/male_yawn[rand(1,2)].ogg" + + else + emotesound = "sound/voice/emotes/female_yawn[rand(1,3)].ogg" + + if(emotesound) + playsound(user, emotesound, 50, 0, 1) + + user.custom_emote(2,"yawns.") + user.handle_emote_CD() + +/decl/emote/audible/clap + key = "clap" + emote_message_3p = "USER claps." + +/decl/emote/audible/chuckle + key = "chuckle" + emote_message_3p = "USER chuckles." + +/decl/emote/audible/cough + key = "cough" + conscious = 0 + +/decl/emote/audible/cough/do_emote(var/mob/living/carbon/human/user) + var/emotesound = null + if(user.isMonkey()) + return + + else if(user.isChild()) + emotesound = "sound/voice/emotes/female_cough[rand(1,6)].ogg" + + else if(user.gender == MALE) + emotesound = "sound/voice/emotes/male_cough[rand(1,4)].ogg" + + else + emotesound = "sound/voice/emotes/female_cough[rand(1,6)].ogg" + + if(emotesound) + playsound(user, emotesound, 50, 0, 1) + + user.custom_emote(2,"coughs.") + user.handle_emote_CD() + +/decl/emote/audible/cry + key = "cry" + emote_message_3p = "USER cries." + +/decl/emote/audible/cry/do_emote(var/mob/living/carbon/human/user) + var/emotesound = null + if(user.isMonkey()) + return + + else if(user.isChild()) + emotesound = 'sound/voice/emotes/child_cry.ogg' + + else if(user.gender == MALE) + emotesound = "sound/voice/emotes/male_cry[rand(1,2)].ogg" + + else + emotesound = "sound/voice/emotes/female_cry[rand(1,2)].ogg" + + if(emotesound) + playsound(user, emotesound, 50, 0, 1) + + user.custom_emote(2,"cries.") + user.handle_emote_CD() + + +/decl/emote/audible/sigh + key = "sigh" + +/decl/emote/audible/sigh/do_emote(var/mob/living/carbon/human/user) + var/emotesound = null + if(user.isMonkey()) + return + + else if(user.gender == MALE) + emotesound = 'sound/voice/emotes/sigh_male.ogg' + + else + emotesound = 'sound/voice/emotes/sigh_female.ogg' + + if(emotesound) + playsound(user, emotesound, 50, 0, 1) + + user.custom_emote(2,"sighs.") + user.handle_emote_CD() + +/decl/emote/audible/laugh + key = "laugh" + +/decl/emote/audible/laugh/do_emote(var/mob/living/carbon/human/user) + var/emotesound = null + if(user.isMonkey()) + return + + else if(user.isChild()) + if(user.gender == MALE) + emotesound = "sound/voice/emotes/boy_laugh[rand(1,2)].ogg" + else + emotesound = 'sound/voice/emotes/girl_laugh1.ogg' + + else if(user.gender == MALE) + emotesound = "sound/voice/emotes/male_laugh[rand(1,3)].ogg" + + else + emotesound = "sound/voice/emotes/female_laugh[rand(1,3)].ogg" + + if(emotesound) + playsound(user, emotesound, 50, 0, 1) + + user.custom_emote(2,"laughs.") + user.handle_emote_CD() + +/decl/emote/audible/mumble + key = "mumble" + +/decl/emote/audible/mumble/do_emote(var/mob/living/carbon/human/user) + var/emotesound = null + if(user.isMonkey()) + return + + else if(user.isChild()) + emotesound = 'sound/voice/emotes/mumble_female.ogg' + + else if(user.gender == MALE) + emotesound = 'sound/voice/emotes/mumble_male.ogg' + + else + emotesound = 'sound/voice/emotes/mumble_female.ogg' + + if(emotesound) + playsound(user, emotesound, 50, 0, 1) + + user.custom_emote(2,"mumbles.") + user.handle_emote_CD() + +/decl/emote/audible/grumble + key = "grumble" + +/decl/emote/audible/grumble/do_emote(var/mob/living/carbon/human/user) + var/emotesound = null + if(user.isMonkey()) + return + + else if(user.gender == MALE) + emotesound = 'sound/voice/emotes/mumble_male.ogg' + + else + emotesound = 'sound/voice/emotes/mumble_female.ogg' + + if(emotesound) + playsound(user, emotesound, 50, 0, 1) + + user.custom_emote(2,"grumbles.") + user.handle_emote_CD() + +/decl/emote/audible/groan + key = "groan" + emote_message_3p = "USER groans!" + conscious = 0 + +/decl/emote/audible/moan + key = "moan" + emote_message_3p = "USER moans!" + conscious = 0 + +/decl/emote/audible/giggle + key = "giggle" + +/decl/emote/audible/giggle/do_emote(var/mob/living/carbon/human/user) + var/emotesound = null + if(user.isMonkey()) + return + + else if(user.isChild() && user.gender == FEMALE) + emotesound = "sound/voice/emotes/female_giggle[rand(1,2)].ogg" + + else if(user.gender == FEMALE) + emotesound = "sound/voice/emotes/female_giggle[rand(1,2)].ogg" + + else + emotesound = null + + if(emotesound) + playsound(user, emotesound, 50, 0, 1) + + user.custom_emote(2,"giggles.") + user.handle_emote_CD() + + +/decl/emote/audible/hem + key = "hem" + +/decl/emote/audible/hem/do_emote(var/mob/living/carbon/human/user) + var/emotesound = null + if(user.isMonkey()) + return + + else if(user.gender == MALE) + emotesound = 'sound/voice/emotes/hem_male.ogg' + + else + emotesound = 'sound/voice/emotes/hem_female.ogg' + + if(emotesound) + playsound(user, emotesound, 50, 0, 1) + + user.custom_emote(2,"hems.") + user.handle_emote_CD() + +/decl/emote/audible/scream + key = "scream" + +/decl/emote/audible/scream/do_emote(var/mob/living/carbon/human/user) + var/emotesound = null + if(user.isMonkey()) + return + + else if(user.isChild()) + emotesound = 'sound/voice/emotes/child_scream.ogg' + + else if(user.gender == MALE) + emotesound = "sound/voice/emotes/male_scream[rand(1,2)].ogg" + + else + emotesound = "sound/voice/emotes/female_scream[rand(1,2)].ogg" + + if(emotesound) + playsound(user, emotesound, 50, 0, 1) + + user.custom_emote(2,"screams!") + user.handle_emote_CD() + + +/decl/emote/audible/clearthroat + key = "clearthroat" + +/decl/emote/audible/clearthroat/do_emote(var/mob/living/carbon/human/user) + var/emotesound = null + if(user.isMonkey()) + return + + else if(user.gender == MALE) + emotesound = 'sound/voice/emotes/throatclear_male.ogg' + + else + emotesound = 'sound/voice/emotes/throatclear_female.ogg' + + if(emotesound) + playsound(user, emotesound, 50, 0, 1) + + user.custom_emote(2,"clears their throat.") + user.handle_emote_CD() + +/decl/emote/audible/grunt + key = "grunt" + emote_message_3p = "USER grunts." + +/decl/emote/audible/bug_hiss + key ="hiss" + emote_message_3p = "USER hisses." + emote_sound = 'sound/voice/BugHiss.ogg' + +/decl/emote/audible/bug_buzz + key ="buzz" + emote_message_3p = "USER buzzes its wings." + emote_sound = 'sound/voice/BugBuzz.ogg' + +/decl/emote/audible/bug_chitter + key ="chitter" + emote_message_3p = "USER chitters." + emote_sound = 'sound/voice/Bug.ogg' \ No newline at end of file diff --git a/code/modules/emotes/definitions/human.dm b/code/modules/emotes/definitions/human.dm new file mode 100644 index 00000000..0d972f4a --- /dev/null +++ b/code/modules/emotes/definitions/human.dm @@ -0,0 +1,70 @@ +/decl/emote/human + key = "vomit" + +/decl/emote/human/check_user(var/mob/living/carbon/human/user) + return (istype(user) && user.check_has_mouth() && !user.isSynthetic()) + +/decl/emote/human/do_emote(var/mob/living/carbon/human/user) + user.vomit() + +/decl/emote/human/deathgasp + key = "deathgasp" + +/decl/emote/human/deathgasp/get_emote_message_3p(var/mob/living/carbon/human/user) + return "USER [user.species.get_death_message()]" + +/decl/emote/human/swish + key = "swish" + +/decl/emote/human/swish/do_emote(var/mob/living/carbon/human/user) + return + +/decl/emote/human/wag + key = "wag" + +/decl/emote/human/wag/do_emote(var/mob/living/carbon/human/user) + return + +/decl/emote/human/sway + key = "sway" + +/decl/emote/human/sway/do_emote(var/mob/living/carbon/human/user) + return + +/decl/emote/human/qwag + key = "qwag" + +/decl/emote/human/qwag/do_emote(var/mob/living/carbon/human/user) + return + +/decl/emote/human/fastsway + key = "fastsway" + +/decl/emote/human/fastsway/do_emote(var/mob/living/carbon/human/user) + return + +/decl/emote/human/swag + key = "swag" + +/decl/emote/human/swag/do_emote(var/mob/living/carbon/human/user) + return + +/decl/emote/human/stopsway + key = "stopsway" + +/decl/emote/human/stopsway/do_emote(var/mob/living/carbon/human/user) + return + +//Shitty stuff starts here. +/decl/emote/human/poo + key = "poo" + +/decl/emote/human/poo/do_emote(var/mob/living/carbon/human/user) + user.handle_shit() + +/decl/emote/human/pee + key = "pee" + +/decl/emote/human/pee/do_emote(var/mob/living/carbon/human/user) + user.handle_piss() + diff --git a/code/modules/emotes/definitions/slime.dm b/code/modules/emotes/definitions/slime.dm new file mode 100644 index 00000000..a8114305 --- /dev/null +++ b/code/modules/emotes/definitions/slime.dm @@ -0,0 +1,30 @@ +/decl/emote/slime + key = "nomood" + var/mood + +/decl/emote/slime/do_extra(var/mob/living/carbon/slime/user) + user.mood = mood + user.regenerate_icons() + +/decl/emote/slime/check_user(var/atom/user) + return istype(user, /mob/living/carbon/slime) + +/decl/emote/slime/pout + key = "pout" + mood = "pout" + +/decl/emote/slime/sad + key = "sad" + mood = "sad" + +/decl/emote/slime/angry + key = "angry" + mood = "angry" + +/decl/emote/slime/frown + key = "frown" + mood = "mischevous" + +/decl/emote/slime/smile + key = "smile" + mood = ":3" diff --git a/code/modules/emotes/definitions/synthetics.dm b/code/modules/emotes/definitions/synthetics.dm new file mode 100644 index 00000000..dd199128 --- /dev/null +++ b/code/modules/emotes/definitions/synthetics.dm @@ -0,0 +1,43 @@ +/decl/emote/audible/synth + key = "beep" + emote_message_3p = "USER beeps." + emote_sound = 'sound/machines/twobeep.ogg' + +/decl/emote/audible/synth/check_user(var/mob/living/user) + if(istype(user) && user.isSynthetic()) + return ..() + return FALSE + +/decl/emote/audible/synth/ping + key = "ping" + emote_message_3p = "USER pings." + emote_sound = 'sound/machines/ping.ogg' + +/decl/emote/audible/synth/buzz + key = "buzz" + emote_message_3p = "USER buzzes." + emote_sound = 'sound/machines/buzz-sigh.ogg' + +/decl/emote/audible/synth/confirm + key = "confirm" + emote_message_3p = "USER emits an affirmative blip." + emote_sound = 'sound/machines/synth_yes.ogg' + +/decl/emote/audible/synth/deny + key = "deny" + emote_message_3p = "USER emits a negative blip." + emote_sound = 'sound/machines/synth_no.ogg' + +/decl/emote/audible/synth/security + key = "law" + emote_message_3p = "USER shows USER_HIS legal authorization barcode." + emote_message_3p_target = "USER shows TARGET USER_THEIR legal authorization barcode." + emote_sound = 'sound/voice/biamthelaw.ogg' + +/decl/emote/audible/synth/security/check_user(var/mob/living/silicon/robot/user) + return (istype(user) && istype(user.module,/obj/item/weapon/robot_module/security)) + +/decl/emote/audible/synth/security/halt + key = "halt" + emote_message_3p = "USER's speakers skreech, \"Halt! Security!\"." + emote_sound = 'sound/voice/halt.ogg' diff --git a/code/modules/emotes/definitions/visible.dm b/code/modules/emotes/definitions/visible.dm new file mode 100644 index 00000000..25134ef9 --- /dev/null +++ b/code/modules/emotes/definitions/visible.dm @@ -0,0 +1,248 @@ +/decl/emote/visible + key ="tail" + emote_message_3p = "USER waves USER_THEIR tail." + message_type = VISIBLE_MESSAGE + +/decl/emote/visible/scratch + key = "scratch" + check_restraints = TRUE + emote_message_3p = "USER scratches." + +/decl/emote/visible/drool + key ="drool" + emote_message_3p = "USER drools." + conscious = 0 + +/decl/emote/visible/nod + key ="nod" + emote_message_3p = "USER nods USER_THEIR head." + +/decl/emote/visible/sway + key ="sway" + emote_message_3p = "USER sways around dizzily." + +/decl/emote/visible/sulk + key ="sulk" + emote_message_3p = "USER sulks down sadly." + +/decl/emote/visible/dance + key ="dance" + check_restraints = TRUE + emote_message_3p = "USER dances around happily." + +/decl/emote/visible/roll + key ="roll" + check_restraints = TRUE + emote_message_3p = "USER rolls." + +/decl/emote/visible/shake + key ="shake" + emote_message_3p = "USER shakes USER_THEIR head." + +/decl/emote/visible/jump + key ="jump" + emote_message_3p = "USER jumps!" + +/decl/emote/visible/hiss + key ="hiss_" + emote_message_3p = "USER hisses softly." + +/decl/emote/visible/shiver + key ="shiver" + emote_message_3p = "USER shivers." + conscious = 0 + +/decl/emote/visible/collapse + key ="collapse" + emote_message_3p = "USER collapses!" + +/decl/emote/visible/collapse/do_extra(var/mob/user) + if(istype(user)) + user.Paralyse(2) + +/decl/emote/visible/flash + key = "flash" + emote_message_3p = "The lights on USER flash quickly." + +/decl/emote/visible/blink + key = "blink" + emote_message_3p = "USER blinks." + +/decl/emote/visible/airguitar + key = "airguitar" + check_restraints = TRUE + emote_message_3p = "USER is strumming the air and headbanging like a safari chimp." + +/decl/emote/visible/blink_r + key = "blink_r" + emote_message_3p = "USER blinks rapidly." + +/decl/emote/visible/bow + key = "bow" + emote_message_3p_target = "USER bows to TARGET." + emote_message_3p = "USER bows." + +/decl/emote/visible/salute + key = "salute" + emote_message_3p_target = "USER salutes to TARGET." + emote_message_3p = "USER salutes." + +/decl/emote/visible/flap + key = "flap" + check_restraints = TRUE + emote_message_3p = "USER flaps USER_THEIR wings." + +/decl/emote/visible/aflap + key = "aflap" + check_restraints = TRUE + emote_message_3p = "USER flaps USER_THEIR wings ANGRILY!" + +/decl/emote/visible/eyebrow + key = "eyebrow" + emote_message_3p = "USER raises an eyebrow." + +/decl/emote/visible/twitch + key = "twitch" + emote_message_3p = "USER twitches." + conscious = 0 + +/decl/emote/visible/twitch_v + key = "twitch_v" + emote_message_3p = "USER twitches violently." + conscious = 0 + +/decl/emote/visible/faint + key = "faint" + emote_message_3p = "USER faints." + +/decl/emote/visible/faint/do_extra(var/mob/user) + if(istype(user) && user.sleeping <= 0) + user.sleeping += 10 + +/decl/emote/visible/frown + key = "frown" + emote_message_3p = "USER frowns." + +/decl/emote/visible/blush + key = "blush" + emote_message_3p = "USER blushes." + +/decl/emote/visible/wave + key = "wave" + emote_message_3p = "USER waves." + emote_message_3p_target = "USER waves at TARGET." + +/decl/emote/visible/glare + key = "glare" + emote_message_3p = "USER glares at TARGET." + emote_message_3p = "USER glares." + +/decl/emote/visible/stare + key = "stare" + emote_message_3p = "USER stares at TARGET." + emote_message_3p = "USER stares." + +/decl/emote/visible/look + key = "look" + emote_message_3p = "USER looks at TARGET." + emote_message_3p = "USER looks." + +/decl/emote/visible/point + key = "point" + check_restraints = TRUE + emote_message_3p = "USER points." + emote_message_3p_target = "USER points to TARGET." + +/decl/emote/visible/raise + key = "raise" + check_restraints = TRUE + emote_message_3p = "USER raises a hand." + +/decl/emote/visible/grin + key = "grin" + emote_message_3p = "USER grins." + +/decl/emote/visible/shrug + key = "shrug" + emote_message_3p = "USER shrugs." + +/decl/emote/visible/smile + key = "smile" + emote_message_3p = "USER smiles." + +/decl/emote/visible/pale + key = "pale" + emote_message_3p = "USER goes pale for a second." + +/decl/emote/visible/tremble + key = "tremble" + emote_message_3p = "USER trembles in fear!" + +/decl/emote/visible/wink + key = "wink" + emote_message_3p = "USER winks." + +/decl/emote/visible/hug + key = "hug" + check_restraints = TRUE + emote_message_3p = "USER hugs USER_THEMself." + emote_message_3p_target = "USER hugs TARGET." + +/decl/emote/visible/dap + key = "dap" + check_restraints = TRUE + emote_message_3p = "USER sadly can't find anybody to give daps to, and daps USER_THEMself." + emote_message_3p_target = "USER gives daps to TARGET." + +/decl/emote/visible/signal + key = "signal" + check_restraints = TRUE + emote_message_3p = "USER signals." + +/decl/emote/visible/signal/check_user(var/atom/user) + return ismob(user) + +/decl/emote/visible/bounce + key = "bounce" + emote_message_3p = "USER bounces in place." + +/decl/emote/visible/jiggle + key = "jiggle" + emote_message_3p = "USER jiggles!" + +/decl/emote/visible/lightup + key = "light" + emote_message_3p = "USER lights up for a bit, then stops." + +/decl/emote/visible/vibrate + key = "vibrate" + emote_message_3p = "USER vibrates!" + +/decl/emote/visible/deathgasp_robot + key = "deathgasp" + emote_message_3p = "USER shudders violently for a moment, then becomes motionless, USER_THEIR eyes slowly darkening." + +/decl/emote/visible/handshake + key = "handshake" + check_restraints = TRUE + emote_message_3p = "USER shakes hands with USER_THEMself." + emote_message_3p_target = "USER shakes hands with TARGET." + message_type = VISIBLE_MESSAGE + +/decl/emote/visible/handshake/get_emote_message_3p(var/atom/user, var/atom/target, var/extra_params) + if(target && !user.Adjacent(target)) + return "USER holds out USER_HIS hand out to TARGET." + return ..() + +/decl/emote/visible/signal + key = "signal" + emote_message_3p = "USER signals." + emote_message_3p_target = "USER signals at TARGET." + message_type = VISIBLE_MESSAGE + +/decl/emote/visible/signal/get_emote_message_3p(var/mob/user, var/atom/target, var/extra_params) + if(istype(user) && !(user.r_hand && user.l_hand)) + var/t1 = round(text2num(extra_params)) + if(isnum(t1) && t1 <= 5) + return "USER raises [t1] finger\s." + return .. () diff --git a/code/modules/emotes/emote_define.dm b/code/modules/emotes/emote_define.dm new file mode 100644 index 00000000..c796e39b --- /dev/null +++ b/code/modules/emotes/emote_define.dm @@ -0,0 +1,95 @@ +// Note about emote messages: +// - USER / TARGET will be replaced with the relevant name, in bold. +// - USER_THEM / TARGET_THEM / USER_THEIR / TARGET_THEIR will be replaced with a +// gender-appropriate version of the same. +// - Impaired messages do not do any substitutions. + +/decl/emote + + var/key // Command to use emote ie. '*[key]' + var/emote_message_1p // First person message ('You do a flip!') + var/emote_message_3p // Third person message ('Urist McShitter does a flip!') + var/emote_message_impaired // Deaf/blind message ('You hear someone flipping out.', 'You see someone opening and closing their mouth') + + var/emote_message_1p_target // 'You do a flip at Urist McTarget!' + var/emote_message_3p_target // 'Urist McShitter does a flip at Urist McTarget!' + + var/message_type = VISIBLE_MESSAGE // Audible/visual flag + var/targetted_emote // Whether or not this emote needs a target. + var/check_restraints // Can this emote be used while restrained? + var/conscious = 1 // Do we need to be awake to emote this? + +/decl/emote/proc/get_emote_message_1p(var/atom/user, var/atom/target, var/extra_params) + if(target) + return emote_message_1p_target + return emote_message_1p + +/decl/emote/proc/get_emote_message_3p(var/atom/user, var/atom/target, var/extra_params) + if(target) + return emote_message_3p_target + return emote_message_3p + +/decl/emote/proc/do_emote(var/atom/user, var/extra_params) + + if(ismob(user) && check_restraints) + var/mob/M = user + if(M.restrained()) + to_chat(user, "You are restrained and cannot do that.") + return + + var/atom/target + if(can_target() && extra_params) + extra_params = lowertext(extra_params) + for(var/atom/thing in view(user)) + if(extra_params == lowertext(thing.name)) + target = thing + break + + var/datum/gender/user_gender = gender_datums[user.get_visible_gender()] + var/datum/gender/target_gender + if(target) + target_gender = gender_datums[target.get_visible_gender()] + + var/use_3p + var/use_1p + if(emote_message_1p) + if(target && emote_message_1p_target) + use_1p = get_emote_message_1p(user, target, extra_params) + use_1p = replacetext(use_1p, "TARGET_THEM", target_gender.him) + use_1p = replacetext(use_1p, "TARGET_THEIR", target_gender.his) + use_1p = replacetext(use_1p, "TARGET", "\the [target]") + else + use_1p = get_emote_message_1p(user, null, extra_params) + use_1p = capitalize(use_1p) + + if(emote_message_3p) + if(target && emote_message_3p_target) + use_3p = get_emote_message_3p(user, target, extra_params) + use_3p = replacetext(use_3p, "TARGET_THEM", target_gender.him) + use_3p = replacetext(use_3p, "TARGET_THEIR", target_gender.his) + use_3p = replacetext(use_3p, "TARGET", "\the [target]") + else + use_3p = get_emote_message_3p(user, null, extra_params) + use_3p = replacetext(use_3p, "USER_THEM", user_gender.him) + use_3p = replacetext(use_3p, "USER_THEIR", user_gender.his) + use_3p = replacetext(use_3p, "USER", "\the [user]") + use_3p = capitalize(use_3p) + + if(message_type == AUDIBLE_MESSAGE) + user.audible_message(message = use_3p, self_message = use_1p, deaf_message = emote_message_impaired, checkghosts = /datum/client_preference/ghost_sight) + else + user.visible_message(message = use_3p, self_message = use_1p, blind_message = emote_message_impaired, checkghosts = /datum/client_preference/ghost_sight) + + do_extra(user, target) + +/decl/emote/proc/do_extra(var/atom/user, var/atom/target) + return + +/decl/emote/proc/check_user(var/atom/user) + return TRUE + +/decl/emote/proc/can_target() + return (emote_message_1p_target || emote_message_3p_target) + +/decl/emote/dd_SortValue() + return key diff --git a/code/modules/emotes/emote_mob.dm b/code/modules/emotes/emote_mob.dm new file mode 100644 index 00000000..0f02ae60 --- /dev/null +++ b/code/modules/emotes/emote_mob.dm @@ -0,0 +1,174 @@ +#define EMOTE_COOLDOWN 20 //Time in deciseconds that the cooldown lasts + +//Emote Cooldown System (it's so simple!) +/mob/proc/handle_emote_CD() + if(emote_cd == 2) + return 1 // Cooldown emotes were disabled by an admin, prevent use + if(emote_cd == 1) + return 1 // Already on CD, prevent use + + emote_cd = 1 // Starting cooldown + spawn(EMOTE_COOLDOWN) + if(emote_cd == 2) + return 1 // Don't reset if cooldown emotes were disabled by an admin during the cooldown + emote_cd = 0 // Cooldown complete, ready for more! + + return 0 // Proceed with emote + +/mob/proc/can_emote(var/emote_type) + return (stat == CONSCIOUS) + +/mob/living/can_emote(var/emote_type) + return (..() && !(silent && emote_type == AUDIBLE_MESSAGE)) + +/mob/proc/emote(var/act, var/m_type, var/message) + // s-s-snowflake + var/muzzled = istype(src.wear_mask, /obj/item/clothing/mask/muzzle) + + if(src.stat == DEAD && act != "deathgasp") + return + if(emote_cd == 1) // Check if we need to suppress the emote attempt. + return + + if(usr == src) //client-called emote + if (client && (client.prefs.muted & MUTE_IC)) + to_chat(src, "You cannot send IC messages (muted).") + return + + if(act == "help") + to_chat(src,"Usable emotes: [english_list(usable_emotes)]") + return + + if(!can_emote(m_type)) + to_chat(src, "You cannot currently [m_type == AUDIBLE_MESSAGE ? "audibly" : "visually"] emote!") + return + + if(act == "me") + return custom_emote(m_type, message) + + if(act == "custom") + if(!message) + message = sanitize(input("Enter an emote to display.") as text|null) + if(!message) + return + if(alert(src, "Is this an audible emote?", "Emote", "Yes", "No") == "No") + m_type = VISIBLE_MESSAGE + else + m_type = AUDIBLE_MESSAGE + return custom_emote(m_type, message) + + var/splitpoint = findtext(act, " ") + if(splitpoint > 0) + var/tempstr = act + act = copytext(tempstr,1,splitpoint) + message = copytext(tempstr,splitpoint+1,0) + + var/decl/emote/use_emote = usable_emotes[act] + if(!use_emote) + to_chat(src, "Unknown emote '[act]'. Type say *help for a list of usable emotes.") + return + + if(m_type != use_emote.message_type && use_emote.conscious && stat != CONSCIOUS) + // to_chat(src, "You cannot currently [use_emote.message_type == AUDIBLE_MESSAGE ? "audibly" : "visually"] emote!")//This is a bugtesting thing. Shouldn't be in the base game. + return + + if(use_emote.message_type == AUDIBLE_MESSAGE && muzzled || use_emote.message_type == AUDIBLE_MESSAGE && silent >= 3) + audible_message("\The [src] makes a muffled sound.") + playsound(src, "sound/voice/muffled[rand(1,2)].ogg", 50, 0, 1) + return + else + use_emote.do_emote(src, message) + + for (var/obj/item/weapon/implant/I in src) + if (I.implanted) + I.trigger(act, src) + +/mob/proc/format_emote(var/source = null, var/message = null) + var/pretext + var/subtext + var/nametext + var/end_char + var/start_char + var/name_anchor + + if(!message || !source) + return + + // Store the player's name in a nice bold, naturalement + nametext = "[source]" + + name_anchor = findtext(message, "^") + if(name_anchor > 0) // User supplied emote with a carat + pretext = copytext(message, 1, name_anchor) + subtext = copytext(message, name_anchor + 1, length(message) + 1) + else + // No carat. Just the emote as usual. + subtext = message + + // Oh shit, we got this far! Let's see... did the user attempt to use more than one carat? + if(findtext(subtext, "^")) + // abort abort! + return 0 + + // Auto-capitalize our pretext if there is any. + if(pretext) + pretext = capitalize(pretext) + // Add a space at the end if we didn't already supply one. + end_char = copytext(pretext, length(pretext), length(pretext) + 1) + if(end_char != " ") + pretext += " " + + // Grab the last character of the emote message. + end_char = copytext(subtext, length(subtext), length(subtext) + 1) + if(!(end_char in PUNCTUATION)) + // No punctuation supplied. Tack a period on the end. + subtext += "." + + // Add a space to the subtext, unless it begins with an apostrophe or comma... or a space. + if(subtext != ".") + start_char = copytext(subtext, 1, 2) + if(start_char != "," && start_char != " " && start_char != "&") // Apostrophes are parsed as "'", so uhh, yeah. + subtext = " " + subtext + + return pretext + nametext + subtext + +/mob/proc/custom_emote(var/m_type = VISIBLE_MESSAGE, var/message = null) + + if((usr && stat) || (!use_me && usr == src)) + to_chat(src, "You are unable to emote.") + return + + var/input + if(!message) + input = sanitize(input(src,"Choose an emote to display.") as text|null) + else + input = message + + if(input) + message = format_emote(src, message) + else + return + + if (message) + log_emote("[name]/[key] : [message]") + //do not show NPC animal emotes to ghosts, it turns into hellscape + var/check_ghosts = client ? /datum/client_preference/ghost_sight : null + if(m_type == VISIBLE_MESSAGE) + visible_message(message, checkghosts = check_ghosts) + else + audible_message(message, checkghosts = check_ghosts) + +// Specific mob type exceptions below. +/mob/living/silicon/ai/emote(var/act, var/type, var/message) + var/obj/machinery/hologram/holopad/T = src.holo + if(T && T.masters[src]) //Is the AI using a holopad? + src.holopad_emote(message) + else //Emote normally, then. + ..() + +/mob/living/captive_brain/emote(var/message) + return + +/mob/observer/ghost/emote(var/act, var/type, var/message) + if(message && act == "me") + communicate(/decl/communication_channel/dsay, client, message, /decl/dsay_communication/emote) diff --git a/code/modules/error_handler/error_handler.dm b/code/modules/error_handler/error_handler.dm new file mode 100644 index 00000000..aff4313a --- /dev/null +++ b/code/modules/error_handler/error_handler.dm @@ -0,0 +1,99 @@ +GLOBAL_VAR_INIT(total_runtimes, 0) +GLOBAL_VAR_INIT(total_runtimes_skipped, 0) + +#ifdef DEBUG +/world/Error(exception/E, datum/e_src) + if(!istype(E)) //Something threw an unusual exception + log_world("\[[time_stamp()]] Uncaught exception: [E]") + return ..() + + var/static/list/error_last_seen = list() + var/static/list/error_cooldown = list() /* Error_cooldown items will either be positive(cooldown time) or negative(silenced error) + If negative, starts at -1, and goes down by 1 each time that error gets skipped*/ + + if(!error_last_seen) // A runtime is occurring too early in start-up initialization + return ..() + + GLOB.total_runtimes++ + + var/erroruid = "[E.file],[E.line]" + var/last_seen = error_last_seen[erroruid] + var/cooldown = error_cooldown[erroruid] || 0 + + if(last_seen == null) + error_last_seen[erroruid] = world.time + last_seen = world.time + + if(cooldown < 0) + error_cooldown[erroruid]-- //Used to keep track of skip count for this error + GLOB.total_runtimes_skipped++ + return //Error is currently silenced, skip handling it + //Handle cooldowns and silencing spammy errors + var/silencing = FALSE + + // We can runtime before config is initialized because BYOND initialize objs/map before a bunch of other stuff happens. + // This is a bunch of workaround code for that. Hooray! + + var/configured_error_cooldown = initial(config.error_cooldown) + var/configured_error_limit = initial(config.error_limit) + var/configured_error_silence_time = initial(config.error_silence_time) + if(config) + configured_error_cooldown = config.error_cooldown + configured_error_limit = config.error_limit + configured_error_silence_time = config.error_silence_time + + + //Each occurence of an unique error adds to its cooldown time... + cooldown = max(0, cooldown - (world.time - last_seen)) + configured_error_cooldown + // ... which is used to silence an error if it occurs too often, too fast + if(cooldown > configured_error_cooldown * configured_error_limit) + cooldown = -1 + silencing = TRUE + spawn(0) + usr = null + sleep(configured_error_silence_time) + var/skipcount = abs(error_cooldown[erroruid]) - 1 + error_cooldown[erroruid] = 0 + if(skipcount > 0) + to_world_log("\[[time_stamp()]] Skipped [skipcount] runtimes in [E.file],[E.line].") + GLOB.error_cache.log_error(E, skip_count = skipcount) + + error_last_seen[erroruid] = world.time + error_cooldown[erroruid] = cooldown + + var/list/usrinfo = null + var/locinfo + if(istype(usr)) + usrinfo = list(" usr: [log_info_line(usr)]") + locinfo = log_info_line(usr.loc) + if(locinfo) + usrinfo += " usr.loc: [locinfo]" + // The proceeding mess will almost definitely break if error messages are ever changed + var/list/splitlines = splittext(E.desc, "\n") + var/list/desclines = list() + if(LAZYLEN(splitlines) > ERROR_USEFUL_LEN) // If there aren't at least three lines, there's no info + for(var/line in splitlines) + if(LAZYLEN(line) < 3 || findtext(line, "source file:") || findtext(line, "usr.loc:")) + continue + if(findtext(line, "usr:")) + if(usrinfo) + desclines.Add(usrinfo) + usrinfo = null + continue // Our usr info is better, replace it + + if(copytext(line, 1, 3) != " ") + desclines += (" " + line) // Pad any unpadded lines, so they look pretty + else + desclines += line + if(usrinfo) //If this info isn't null, it hasn't been added yet + desclines.Add(usrinfo) + if(silencing) + desclines += " (This error will now be silenced for [configured_error_silence_time / 600] minutes)" + if(GLOB.error_cache) + GLOB.error_cache.log_error(E, desclines) + + to_world_log("\[[time_stamp()]] Runtime in [E.file],[E.line]: [E]") + for(var/line in desclines) + to_world_log(line) + +#endif diff --git a/code/modules/error_handler/error_reporting.dm b/code/modules/error_handler/error_reporting.dm new file mode 100644 index 00000000..9fadab06 --- /dev/null +++ b/code/modules/error_handler/error_reporting.dm @@ -0,0 +1,23 @@ +// this proc will only work with DEBUG enabled +#ifdef DEBUG + +/hook/roundend/proc/send_runtimes_to_ircbot() + if(!revdata.revision) return // we can't do much useful if we don't know what we are + var/list/errors = list() + for(var/erruid in GLOB.error_cache.error_sources) + var/datum/error_viewer/error_source/e = GLOB.error_cache.error_sources[erruid] + var/datum/error_viewer/error_entry/err = e.errors[1] + + var/data = list( + id = erruid, + name = err.info_name, + info = err.info + ) + + errors[++errors.len] = list2params(data) + + runtimes2irc(list2params(errors), revdata.revision) + + return 1 + +#endif diff --git a/code/modules/error_handler/error_viewer.dm b/code/modules/error_handler/error_viewer.dm new file mode 100644 index 00000000..95c9b371 --- /dev/null +++ b/code/modules/error_handler/error_viewer.dm @@ -0,0 +1,213 @@ +// Error viewing datums, responsible for storing error info, notifying admins +// when errors occur, and showing them to admins on demand. + +// There are 3 different types used here: +// +// - error_cache keeps track of all error sources, as well as all individually +// logged errors. Only one instance of this datum should ever exist, and it's +// right here: + +#ifdef DEBUG +GLOBAL_DATUM_INIT(error_cache, /datum/error_viewer/error_cache, new) +#else +// If debugging is disabled, there's nothing useful to log, so don't bother. +GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) +#endif + +// - error_source datums exist for each line (of code) that generates an error, +// and keep track of all errors generated by that line. +// +// - error_entry datums exist for each logged error, and keep track of all +// relevant info about that error. + +// Common vars and procs are kept at the error_viewer level +/datum/error_viewer + var/name = "" + +/datum/error_viewer/Topic(href, href_list) + if(href_list["viewruntime"]) + var/datum/error_viewer/error_viewer = locate(href_list["viewruntime"]) + if(!istype(error_viewer)) + to_chat(usr, "That runtime viewer no longer exists.") + return + + if(href_list["viewruntime_backto"]) + error_viewer.show_to(usr.client, locate(href_list["viewruntime_backto"]), href_list["viewruntime_linear"]) + else + error_viewer.show_to(usr.client, null, href_list["viewruntime_linear"]) + +/datum/error_viewer/proc/browse_to(client/user, html) + var/datum/browser/browser = new(user.mob, "error_viewer", null, 600, 400) + browser.set_content(html) + browser.add_head_content({" + + "}) + browser.open() + +/datum/error_viewer/proc/build_header(datum/error_viewer/back_to, linear) + // Common starter HTML for show_to + + . = "" + + if (istype(back_to)) + . += back_to.make_link("<<<", null, linear) + + . += "[make_link("Refresh")]

            " + +/datum/error_viewer/proc/show_to(user, datum/error_viewer/back_to, linear) + // Specific to each child type + return + +/datum/error_viewer/proc/make_link(linktext, datum/error_viewer/back_to, linear) + var/back_to_param = "" + if (!linktext) + linktext = name + + if (istype(back_to)) + back_to_param = ";viewruntime_backto=\ref[back_to]" + + if (linear) + back_to_param += ";viewruntime_linear=1" + + return "[linktext]" + +/datum/error_viewer/error_cache + var/list/errors = list() + var/list/error_sources = list() + var/list/errors_silenced = list() + +/datum/error_viewer/error_cache/show_to(user, datum/error_viewer/back_to, linear) + var/html = build_header() + html += "[GLOB.total_runtimes] runtimes, [GLOB.total_runtimes_skipped] skipped

            " + if (!linear) + html += "organized | [make_link("linear", null, 1)]
            " + var/datum/error_viewer/error_source/error_source + for (var/erroruid in error_sources) + error_source = error_sources[erroruid] + html += "[error_source.make_link(null, src)]
            " + + else + html += "[make_link("organized", null)] | linear
            " + for (var/datum/error_viewer/error_entry/error_entry in errors) + html += "[error_entry.make_link(null, src, 1)]
            " + + browse_to(user, html) + +/datum/error_viewer/error_cache/proc/log_error(exception/e, list/desclines, skip_count) + if (!istype(e)) + return // Abnormal exception, don't even bother + + var/erroruid = "[e.file],[e.line]" + var/datum/error_viewer/error_source/error_source = error_sources[erroruid] + if (!error_source) + error_source = new(e) + error_sources[erroruid] = error_source + + var/datum/error_viewer/error_entry/error_entry = new(e, desclines, skip_count) + error_entry.error_source = error_source + errors += error_entry + error_source.errors += error_entry + if (skip_count) + return // Skip notifying admins about skipped errors. + + // Show the error to admins with debug messages turned on, but only if one + // from the same source hasn't been shown too recently + if (error_source.next_message_at <= world.time) + var/const/viewtext = "\[view]" // Nesting these in other brackets went poorly + //log_debug("Runtime in [e.file], line [e.line]: [html_encode(e.name)] [error_entry.make_link(viewtext)]") + var/err_msg_delay + if(config) + err_msg_delay = config.error_msg_delay + else + err_msg_delay = initial(config.error_msg_delay) + error_source.next_message_at = world.time + err_msg_delay + +/datum/error_viewer/error_source + var/list/errors = list() + var/next_message_at = 0 + +/datum/error_viewer/error_source/New(exception/e) + if (!istype(e)) + name = "\[[time_stamp()]] Uncaught exceptions" + return + + name = "\[[time_stamp()]] Runtime in [e.file], line [e.line]: [html_encode(e.name)]" + +/datum/error_viewer/error_source/show_to(user, datum/error_viewer/back_to, linear) + if (!istype(back_to)) + back_to = GLOB.error_cache + + var/html = build_header(back_to) + for (var/datum/error_viewer/error_entry/error_entry in errors) + html += "[error_entry.make_link(null, src)]
            " + + browse_to(user, html) + +/datum/error_viewer/error_entry + var/datum/error_viewer/error_source/error_source + var/exception/exc + var/desc = "" + var/usr_ref + var/turf/usr_loc + var/is_skip_count + + var/info_name + var/info + +/datum/error_viewer/error_entry/New(exception/e, list/desclines, skip_count) + if (!istype(e)) + name = "\[[time_stamp()]] Uncaught exception: [html_encode(e.name)]" + return + + if(skip_count) + name = "\[[time_stamp()]] Skipped [skip_count] runtimes in [e.file],[e.line]." + is_skip_count = TRUE + return + + name = "\[[time_stamp()]] Runtime in [e.file], line [e.line]: [html_encode(e.name)]" + info_name = "Runtime in [e.file],[e.line]: [e]" + info = info_name + + exc = e + if (istype(desclines)) + for (var/line in desclines) + // There's probably a better way to do this than non-breaking spaces... + desc += "[html_encode(line)]
            " + info += "\n " + line + + if (usr) + usr_ref = "\ref[usr]" + usr_loc = get_turf(usr) + +/datum/error_viewer/error_entry/show_to(user, datum/error_viewer/back_to, linear) + if (!istype(back_to)) + back_to = error_source + + var/html = build_header(back_to, linear) + html += "[name]
            [desc]
            " + if (usr_ref) + html += "
            usr: VV" + html += " PP" + html += " Follow" + if (istype(usr_loc)) + html += "
            usr.loc: VV" + html += " JMP" + + browse_to(user, html) + +/datum/error_viewer/error_entry/make_link(linktext, datum/error_viewer/back_to, linear) + return is_skip_count ? name : ..() diff --git a/code/modules/events/apc_damage.dm b/code/modules/events/apc_damage.dm new file mode 100644 index 00000000..d3badc5c --- /dev/null +++ b/code/modules/events/apc_damage.dm @@ -0,0 +1,49 @@ +/datum/event/apc_damage + var/apcSelectionRange = 25 + +/datum/event/apc_damage/start() + var/obj/machinery/power/apc/A = acquire_random_apc() + + var/severity_range = 0 + switch(severity) + if(EVENT_LEVEL_MUNDANE) + severity_range = 0 + if(EVENT_LEVEL_MODERATE) + severity_range = 7 + if(EVENT_LEVEL_MAJOR) + severity_range = 15 + + for(var/obj/machinery/power/apc/apc in range(severity_range,A)) + if(is_valid_apc(apc)) + apc.emagged = 1 + apc.update_icon() + +/datum/event/apc_damage/proc/acquire_random_apc() + var/list/possibleEpicentres = list() + var/list/apcs = list() + + for(var/obj/effect/landmark/newEpicentre in landmarks_list) + if(newEpicentre.name == "lightsout") + possibleEpicentres += newEpicentre + + if(!possibleEpicentres.len) + return + + var/epicentre = pick(possibleEpicentres) + for(var/obj/machinery/power/apc/apc in range(epicentre,apcSelectionRange)) + if(is_valid_apc(apc)) + apcs += apc + // Greatly increase the chance for APCs in maintenance areas to be selected + var/area/A = get_area(apc) + if(istype(A,/area/maintenance)) + apcs += apc + apcs += apc + + if(!apcs.len) + return + + return pick(apcs) + +/datum/event/apc_damage/proc/is_valid_apc(var/obj/machinery/power/apc/apc) + var/turf/T = get_turf(apc) + return !apc.is_critical && !apc.emagged && T && (T.z in GLOB.using_map.player_levels) diff --git a/code/modules/events/blob.dm b/code/modules/events/blob.dm new file mode 100644 index 00000000..44f6439b --- /dev/null +++ b/code/modules/events/blob.dm @@ -0,0 +1,27 @@ +/datum/event/blob + announceWhen = 12 + + var/obj/effect/blob/core/Blob + +/datum/event/blob/announce() + level_seven_announcement() + +/datum/event/blob/start() + var/turf/T = pick_subarea_turf(/area/maintenance, list(/proc/is_station_turf, /proc/not_turf_contains_dense_objects)) + if(!T) + log_and_message_admins("Blob failed to find a viable turf.") + kill() + return + + log_and_message_admins("Blob spawned in \the [get_area(T)]", location = T) + Blob = new /obj/effect/blob/core(T) + for(var/i = 1; i < rand(3, 4), i++) + Blob.Process() + +/datum/event/blob/tick() + if(!Blob || !Blob.loc) + Blob = null + kill() + return + if(IsMultiple(activeFor, 3)) + Blob.Process() diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm new file mode 100644 index 00000000..7cb4533a --- /dev/null +++ b/code/modules/events/brand_intelligence.dm @@ -0,0 +1,55 @@ +/datum/event/brand_intelligence + announceWhen = 21 + endWhen = 1000 //Ends when all vending machines are subverted anyway. + + var/list/obj/machinery/vending/vendingMachines = list() + var/list/obj/machinery/vending/infectedVendingMachines = list() + var/obj/machinery/vending/originMachine + + +/datum/event/brand_intelligence/announce() + threat_announcement.Announce("Rampant brand intelligence has been detected aboard the [station_name()]. The origin is believed to be \a \"[initial(originMachine.name)]\" type. Fix it, before it spreads to other vending machines.", "Machine Learning Alert") + + +/datum/event/brand_intelligence/start() + for(var/obj/machinery/vending/V in SSmachines.machinery) + if(isNotStationLevel(V.z)) continue + vendingMachines.Add(V) + + if(!vendingMachines.len) + kill() + return + + originMachine = pick(vendingMachines) + vendingMachines.Remove(originMachine) + originMachine.shut_up = 0 + originMachine.shoot_inventory = 1 + + +/datum/event/brand_intelligence/tick() + if(!vendingMachines.len || !originMachine || originMachine.shut_up || !originMachine.shoot_inventory) //if every machine is infected, or if the original vending machine is missing or has it's voice switch flipped or fixed + end() + kill() + return + + if(IsMultiple(activeFor, 5)) + if(prob(15)) + var/obj/machinery/vending/infectedMachine = pick(vendingMachines) + vendingMachines.Remove(infectedMachine) + infectedVendingMachines.Add(infectedMachine) + infectedMachine.shut_up = 0 + infectedMachine.shoot_inventory = 1 + + if(IsMultiple(activeFor, 12)) + originMachine.speak(pick("Try our aggressive new marketing strategies!", \ + "You should buy products to feed your lifestyle obsession!", \ + "Consume!", \ + "Your money can buy happiness!", \ + "Engage direct marketing!", \ + "Advertising is legalized lying! But don't let that put you off our great deals!", \ + "You don't want to buy anything? Yeah, well I didn't want to buy your mom either.")) + +/datum/event/brand_intelligence/end() + for(var/obj/machinery/vending/infectedMachine in infectedVendingMachines) + infectedMachine.shut_up = 1 + infectedMachine.shoot_inventory = 0 diff --git a/code/modules/events/camera_damage.dm b/code/modules/events/camera_damage.dm new file mode 100644 index 00000000..f5a6e8c5 --- /dev/null +++ b/code/modules/events/camera_damage.dm @@ -0,0 +1,38 @@ +/datum/event/camera_damage/start() + var/obj/machinery/camera/C = acquire_random_camera() + if(!C) + return + + var/severity_range = 0 + switch(severity) + if(EVENT_LEVEL_MUNDANE) + severity_range = 0 + if(EVENT_LEVEL_MODERATE) + severity_range = 7 + if(EVENT_LEVEL_MAJOR) + severity_range = 15 + + for(var/obj/machinery/camera/cam in range(severity_range,C)) + if(is_valid_camera(cam)) + if(prob(2*severity)) + cam.destroy() + else + cam.wires.UpdateCut(CAMERA_WIRE_POWER, 0) + if(prob(5*severity)) + cam.wires.UpdateCut(CAMERA_WIRE_ALARM, 0) + +/datum/event/camera_damage/proc/acquire_random_camera(var/remaining_attempts = 5) + if(!cameranet.cameras.len) + return + if(!remaining_attempts) + return + + var/obj/machinery/camera/C = pick(cameranet.cameras) + if(is_valid_camera(C)) + return C + return acquire_random_camera(remaining_attempts-1) + +/datum/event/camera_damage/proc/is_valid_camera(var/obj/machinery/camera/C) + // Only return a functional camera, not installed in a silicon, and that exists somewhere players have access + var/turf/T = get_turf(C) + return T && C.can_use() && !istype(C.loc, /mob/living/silicon) && (T.z in GLOB.using_map.player_levels) diff --git a/code/modules/events/carp_migration.dm b/code/modules/events/carp_migration.dm new file mode 100644 index 00000000..bc3eddfb --- /dev/null +++ b/code/modules/events/carp_migration.dm @@ -0,0 +1,55 @@ +/datum/event/carp_migration + announceWhen = 50 + endWhen = 900 + + var/list/spawned_carp = list() + +/datum/event/carp_migration/setup() + announceWhen = rand(40, 60) + endWhen = rand(600,1200) + +/datum/event/carp_migration/announce() + var/announcement = "" + if(severity == EVENT_LEVEL_MAJOR) + announcement = "Massive migration of unknown biological entities has been detected near the [station_name()], please stand-by." + else + announcement = "Unknown biological [spawned_carp.len == 1 ? "entity has" : "entities have"] been detected near the [station_name()], please stand-by." + threat_announcement.Announce(announcement, "[station_name()] Sensor Array") + +/datum/event/carp_migration/start() + if(severity == EVENT_LEVEL_MAJOR) + spawn_fish(landmarks_list.len) + else if(severity == EVENT_LEVEL_MODERATE) + spawn_fish(rand(4, 6)) //12 to 30 carp, in small groups + else + spawn_fish(rand(1, 3), 1, 2) //1 to 6 carp, alone or in pairs + +/datum/event/carp_migration/proc/spawn_fish(var/num_groups, var/group_size_min=3, var/group_size_max=5) + var/list/spawn_locations = list() + + for(var/obj/effect/landmark/C in landmarks_list) + if(C.name == "carpspawn") + spawn_locations.Add(C.loc) + spawn_locations = shuffle(spawn_locations) + num_groups = min(num_groups, spawn_locations.len) + + var/i = 1 + while (i <= num_groups) + var/group_size = rand(group_size_min, group_size_max) + if(prob(96)) + for (var/j = 1, j <= group_size, j++) + spawned_carp.Add(new /mob/living/simple_animal/hostile/carp(spawn_locations[i])) + i++ + else + group_size = max(1,round(group_size/6)) + group_size = min(spawn_locations.len-i+1,group_size) + for(var/j = 1, j <= group_size, j++) + spawned_carp.Add(new /mob/living/simple_animal/hostile/carp/pike(spawn_locations[i+j])) + i += group_size + +/datum/event/carp_migration/end() + for(var/mob/living/simple_animal/hostile/C in spawned_carp) + if(!C.stat) + var/turf/T = get_turf(C) + if(istype(T, /turf/space)) + qdel(C) diff --git a/code/modules/events/comms_blackout.dm b/code/modules/events/comms_blackout.dm new file mode 100644 index 00000000..d748fe8c --- /dev/null +++ b/code/modules/events/comms_blackout.dm @@ -0,0 +1,12 @@ + +/proc/communications_blackout(var/silent = 1) + + if(!silent) + command_announcement.Announce("Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you-BZZT", new_sound = 'sound/misc/interference.ogg') + else // AIs will always know if there's a comm blackout, rogue AIs could then lie about comm blackouts in the future while they shutdown comms + for(var/mob/living/silicon/ai/A in GLOB.player_list) + to_chat(A, "
            ") + to_chat(A, "Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you-BZZT") + to_chat(A, "
            ") + for(var/obj/machinery/telecomms/T in telecomms_list) + T.emp_act(1) diff --git a/code/modules/events/communications_blackout.dm b/code/modules/events/communications_blackout.dm new file mode 100644 index 00000000..bce03d81 --- /dev/null +++ b/code/modules/events/communications_blackout.dm @@ -0,0 +1,21 @@ +/datum/event/communications_blackout/announce() + var/alert = pick( "Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you*%fj00)`5vc-BZZT", \ + "Ionospheric anomalies detected. Temporary telecommunication failu*3mga;b4;'1v¬-BZZZT", \ + "Ionospheric anomalies detected. Temporary telec#MCi46:5.;@63-BZZZZT", \ + "Ionospheric anomalies dete'fZ\\kg5_0-BZZZZZT", \ + "Ionospheri:%£ MCayj^j<.3-BZZZZZZT", \ + "#4nd%;f4y6,>£%-BZZZZZZZT") + + for(var/mob/living/silicon/ai/A in GLOB.player_list) //AIs are always aware of communication blackouts. + to_chat(A, "
            ") + to_chat(A, "[alert]") + to_chat(A, "
            ") + + if(prob(80)) //Announce most of the time, just not always to give some wiggle room for possible sabotages. + threat_announcement.Announce(alert, new_sound = sound('sound/misc/interference.ogg', volume=25)) + + +/datum/event/communications_blackout/start() + for(var/obj/machinery/telecomms/T in telecomms_list) + if(prob(T.outage_probability)) + T.overloaded_for = max(severity * rand(90, 120), T.overloaded_for) diff --git a/code/modules/events/dust.dm b/code/modules/events/dust.dm new file mode 100644 index 00000000..9c6081b6 --- /dev/null +++ b/code/modules/events/dust.dm @@ -0,0 +1,52 @@ +/* +Space dust +Commonish random event that causes small clumps of "space dust" to hit the station at high speeds. +The "dust" will damage the hull of the station causin minor hull breaches. +*/ + +/datum/event/dust + startWhen = 10 + endWhen = 30 + var/min_delay = 30 + var/last_wave + +/datum/event/dust/announce() + command_announcement.Announce("The [station_name()] is now passing through a belt of space dust.", "[station_name()] Sensor Array") + +/datum/event/dust/tick() + if(world.time > last_wave + min_delay && prob(10)) + dust_swarm(severity) + +/datum/event/dust/end() + command_announcement.Announce("The [station_name()] has now passed through the belt of space dust.", "[station_name()] Sensor Array") + +/proc/dust_swarm(var/strength = EVENT_LEVEL_MUNDANE) + var/numbers = rand(strength * 10, strength * 15) + + var/start_dir = pick(GLOB.cardinal) + var/turf/startloc + var/turf/targloc + var/randomz = pick(GLOB.using_map.station_levels) + var/randomx = rand(1+TRANSITIONEDGE*2, world.maxx-TRANSITIONEDGE*2) + var/randomy = rand(1+TRANSITIONEDGE*2, world.maxx-TRANSITIONEDGE*2) + switch(start_dir) + if(NORTH) + startloc = locate(randomx, world.maxy - TRANSITIONEDGE, randomz) + targloc = locate(world.maxx - randomx, 1 + TRANSITIONEDGE, randomz) + if(SOUTH) + startloc = locate(randomx, 1 + TRANSITIONEDGE, randomz) + targloc = locate(world.maxx - randomx, world.maxy - TRANSITIONEDGE, randomz) + if(EAST) + startloc = locate(world.maxx - TRANSITIONEDGE, randomy, randomz) + targloc = locate(1 + TRANSITIONEDGE, world.maxy - randomy, randomz) + if(WEST) + startloc = locate(1 + TRANSITIONEDGE, randomy, randomz) + targloc = locate(world.maxx - TRANSITIONEDGE, world.maxy - randomy, randomz) + var/list/starters = getcircle(startloc, 3) + starters += startloc + + var/rocks_per_tile = round(numbers/starters.len) + for(var/turf/T in starters) + for(var/i = 1 to rocks_per_tile) + var/obj/item/projectile/bullet/rock/R = new(T) + R.launch_projectile(targloc, null, startloc.x - T.x, startloc.y - T.y) \ No newline at end of file diff --git a/code/modules/events/electrical_storm.dm b/code/modules/events/electrical_storm.dm new file mode 100644 index 00000000..593e5df3 --- /dev/null +++ b/code/modules/events/electrical_storm.dm @@ -0,0 +1,71 @@ +/datum/event/electrical_storm + announceWhen = 0 // Warn them shortly before it begins. + startWhen = 30 + endWhen = 60 // Set in start() + var/list/valid_apcs // Shuffled list of valid APCs. + +/datum/event/electrical_storm/announce() + ..() + switch(severity) + if(EVENT_LEVEL_MUNDANE) + command_announcement.Announce("A minor electrical storm has been detected near the [station_name()]. Please watch out for possible electrical discharges.", "[station_name()] Sensor Array") + if(EVENT_LEVEL_MODERATE) + command_announcement.Announce("The [station_name()] is about to pass through an electrical storm. Please secure sensitive electrical equipment until the storm passes.", "[station_name()] Sensor Array", new_sound = GLOB.using_map.electrical_storm_moderate_sound) + if(EVENT_LEVEL_MAJOR) + command_announcement.Announce("Alert. A strong electrical storm has been detected in proximity of the [station_name()]. It is recommended to immediately secure sensitive electrical equipment until the storm passes.", "[station_name()] Sensor Array", new_sound = GLOB.using_map.electrical_storm_major_sound) + +/datum/event/electrical_storm/start() + ..() + valid_apcs = list() + for(var/obj/machinery/power/apc/A in SSmachines.machinery) + if(A.z in GLOB.using_map.station_levels) + valid_apcs.Add(A) + endWhen = (severity * 60) + startWhen + +/datum/event/electrical_storm/tick() + ..() + //See if shields can stop it first + var/list/shields = list() + for(var/obj/machinery/power/shield_generator/G in SSmachines.machinery) + if((G.z in GLOB.using_map.station_levels) && G.running && G.check_flag(MODEFLAG_EM)) + shields += G + if(shields.len) + var/obj/machinery/power/shield_generator/shield_gen = pick(shields) + //Minor breaches aren't enough to let through frying amounts of power + if(shield_gen.take_damage(30 * severity, SHIELD_DAMTYPE_EM) <= SHIELD_BREACHED_MINOR) + return + if(!valid_apcs.len) + CRASH("No valid APCs found for electrical storm event! This is likely a bug.") + var/list/picked_apcs = list() + for(var/i=0, i< severity*2, i++) // up to 2/4/6 APCs per tick depending on severity + picked_apcs |= pick(valid_apcs) + + for(var/obj/machinery/power/apc/T in picked_apcs) + // Main breaker is turned off. Consider this APC protected. + if(!T.operating) + continue + + // Decent chance to overload lighting circuit. + if(prob(3 * severity)) + T.overload_lighting() + + // Relatively small chance to emag the apc as apc_damage event does. + if(prob(0.2 * severity)) + T.emagged = 1 + T.update_icon() + + if(T.is_critical) + T.energy_fail(10 * severity) + continue + else + T.energy_fail(10 * severity * rand(severity * 2, severity * 4)) + + // Very tiny chance to completely break the APC. Has a check to ensure we don't break critical APCs such as the Engine room, or AI core. Does not occur on Mundane severity. + if(prob((0.2 * severity) - 0.2)) + T.set_broken() + + + +/datum/event/electrical_storm/end() + ..() + command_announcement.Announce("The [station_name()] has cleared the electrical storm. Please repair any electrical overloads.", "Electrical Storm Alert") diff --git a/code/modules/events/event.dm b/code/modules/events/event.dm new file mode 100644 index 00000000..b3c12f4b --- /dev/null +++ b/code/modules/events/event.dm @@ -0,0 +1,148 @@ +/datum/event_meta + var/name = "" + var/enabled = 1 // Whether or not the event is available for random selection at all + var/weight = 0 // The base weight of this event. A zero means it may never fire, but see get_weight() + var/min_weight = 0 // The minimum weight that this event will have. Only used if non-zero. + var/max_weight = 0 // The maximum weight that this event will have. Only use if non-zero. + var/severity = 0 // The current severity of this event + var/one_shot = 0 // If true, then the event will not be re-added to the list of available events + var/add_to_queue= 1 // If true, add back to the queue of events upon finishing. + var/list/role_weights = list() + var/datum/event/event_type + +/datum/event_meta/New(var/event_severity, var/event_name, var/datum/event/type, var/event_weight, var/list/job_weights, var/is_one_shot = 0, var/min_event_weight = 0, var/max_event_weight = 0, var/add_to_queue = 1) + name = event_name + severity = event_severity + event_type = type + one_shot = is_one_shot + weight = event_weight + min_weight = min_event_weight + max_weight = max_event_weight + src.add_to_queue = add_to_queue + if(job_weights) + role_weights = job_weights + +/datum/event_meta/proc/get_weight(var/list/active_with_role) + if(!enabled) + return 0 + + var/job_weight = 0 + for(var/role in role_weights) + if(role in active_with_role) + job_weight += active_with_role[role] * role_weights[role] + + var/total_weight = weight + job_weight + + // Only min/max the weight if the values are non-zero + if(min_weight && total_weight < min_weight) total_weight = min_weight + if(max_weight && total_weight > max_weight) total_weight = max_weight + + return total_weight + +/datum/event_meta/extended_penalty + var/penalty = 100 // A simple penalty gives admins the ability to increase the weight to again be part of the random event selection + +/datum/event_meta/extended_penalty/get_weight() + return ..() - (ticker && istype(ticker.mode, /datum/game_mode/extended) ? penalty : 0) + + +/datum/event //NOTE: Times are measured in master controller ticks! + var/startWhen = 0 //When in the lifetime to call start(). + var/announceWhen = 0 //When in the lifetime to call announce(). + var/endWhen = 0 //When in the lifetime the event should end. + + var/severity = 0 //Severity. Lower means less severe, higher means more severe. Does not have to be supported. Is set on New(). + var/activeFor = 0 //How long the event has existed. You don't need to change this. + var/isRunning = 1 //If this event is currently running. You should not change this. + var/startedAt = 0 //When this event started. + var/endedAt = 0 //When this event ended. + var/datum/event_meta/event_meta = null + +/datum/event/nothing + +//Called first before processing. +//Allows you to setup your event, such as randomly +//setting the startWhen and or announceWhen variables. +//Only called once. +/datum/event/proc/setup() + return + +//Called when the tick is equal to the startWhen variable. +//Allows you to start before announcing or vice versa. +//Only called once. +/datum/event/proc/start() + return + +//Called when the tick is equal to the announceWhen variable. +//Allows you to announce before starting or vice versa. +//Only called once. +/datum/event/proc/announce() + return + +//Called on or after the tick counter is equal to startWhen. +//You can include code related to your event or add your own +//time stamped events. +//Called more than once. +/datum/event/proc/tick() + return + +//Called on or after the tick is equal or more than endWhen +//You can include code related to the event ending. +//Do not place spawn() in here, instead use tick() to check for +//the activeFor variable. +//For example: if(activeFor == myOwnVariable + 30) doStuff() +//Only called once. +/datum/event/proc/end() + return + +//Returns the latest point of event processing. +/datum/event/proc/lastProcessAt() + return max(startWhen, max(announceWhen, endWhen)) + +//Do not override this proc, instead use the appropiate procs. +//This proc will handle the calls to the appropiate procs. +/datum/event/proc/process() + if(activeFor > startWhen && activeFor < endWhen) + tick() + + if(activeFor == startWhen) + isRunning = 1 + start() + + if(activeFor == announceWhen) + announce() + + if(activeFor == endWhen) + isRunning = 0 + end() + + // Everything is done, let's clean up. + if(activeFor >= lastProcessAt()) + kill() + + activeFor++ + +//Called when start(), announce() and end() has all been called. +/datum/event/proc/kill() + // If this event was forcefully killed run end() for individual cleanup + if(isRunning) + isRunning = 0 + end() + + endedAt = world.time + GLOB.event_manager.active_events -= src + GLOB.event_manager.event_complete(src) + +/datum/event/New(var/datum/event_meta/EM) + // event needs to be responsible for this, as stuff like APLUs currently make their own events for curious reasons + GLOB.event_manager.active_events += src + + event_meta = EM + severity = event_meta.severity + if(severity < EVENT_LEVEL_MUNDANE) severity = EVENT_LEVEL_MUNDANE + if(severity > EVENT_LEVEL_MAJOR) severity = EVENT_LEVEL_MAJOR + + startedAt = world.time + + setup() + ..() diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm new file mode 100644 index 00000000..ce9556ed --- /dev/null +++ b/code/modules/events/event_container.dm @@ -0,0 +1,195 @@ +#define ASSIGNMENT_ANY "Any" +#define ASSIGNMENT_AI "AI" +#define ASSIGNMENT_CYBORG "Cyborg" +#define ASSIGNMENT_ENGINEER "Engineer" +#define ASSIGNMENT_GARDENER "Gardener" +#define ASSIGNMENT_JANITOR "Janitor" +#define ASSIGNMENT_MEDICAL "Medical" +#define ASSIGNMENT_SCIENTIST "Scientist" +#define ASSIGNMENT_SECURITY "Security" + +var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT_LEVEL_MODERATE = "Moderate", EVENT_LEVEL_MAJOR = "Major") + +/datum/event_container + var/severity = -1 + var/delayed = 0 + var/delay_modifier = 1 + var/next_event_time = 0 + var/list/available_events + var/list/last_event_time = list() + var/datum/event_meta/next_event = null + + var/last_world_time = 0 + +/datum/event_container/proc/process() + if(!next_event_time) + set_event_delay() + + if(delayed || !config.allow_random_events) + next_event_time += (world.time - last_world_time) + else if(world.time > next_event_time) + start_event() + + last_world_time = world.time + +/datum/event_container/proc/start_event() + if(!next_event) // If non-one has explicitly set an event, randomly pick one + next_event = acquire_event() + + // Has an event been acquired? + if(next_event) + // Set when the event of this type was last fired, and prepare the next event start + last_event_time[next_event] = world.time + set_event_delay() + next_event.enabled = !next_event.one_shot // This event will no longer be available in the random rotation if one shot + + new next_event.event_type(next_event) // Events are added and removed from the processing queue in their New/kill procs + + log_debug("Starting event '[next_event.name]' of severity [severity_to_string[severity]].") + next_event = null // When set to null, a random event will be selected next time + else + // If not, wait for one minute, instead of one tick, before checking again. + next_event_time += (60 * 10) + + +/datum/event_container/proc/acquire_event() + if(available_events.len == 0) + return + var/active_with_role = number_active_with_role() + + var/list/possible_events = list() + for(var/datum/event_meta/EM in available_events) + var/event_weight = get_weight(EM, active_with_role) + if(event_weight) + possible_events[EM] = event_weight + + if(possible_events.len == 0) + return null + + // Select an event and remove it from the pool of available events + var/picked_event = pickweight(possible_events) + available_events -= picked_event + return picked_event + +/datum/event_container/proc/get_weight(var/datum/event_meta/EM, var/list/active_with_role) + if(!EM.enabled) + return 0 + + var/weight = EM.get_weight(active_with_role) + var/last_time = last_event_time[EM] + if(last_time) + var/time_passed = world.time - last_time + var/weight_modifier = max(0, round((config.expected_round_length - time_passed) / 300)) + weight = weight - weight_modifier + + return weight + +/datum/event_container/proc/set_event_delay() + // If the next event time has not yet been set and we have a custom first time start + if(next_event_time == 0 && config.event_first_run[severity]) + var/lower = config.event_first_run[severity]["lower"] + var/upper = config.event_first_run[severity]["upper"] + var/event_delay = rand(lower, upper) + next_event_time = world.time + event_delay + // Otherwise, follow the standard setup process + else + var/playercount_modifier = 1 + switch(GLOB.player_list.len) + if(0 to 10) + playercount_modifier = 1.2 + if(11 to 15) + playercount_modifier = 1.1 + if(16 to 25) + playercount_modifier = 1 + if(26 to 35) + playercount_modifier = 0.9 + if(36 to 100000) + playercount_modifier = 0.8 + playercount_modifier = playercount_modifier * delay_modifier + + var/event_delay = rand(config.event_delay_lower[severity], config.event_delay_upper[severity]) //* playercount_modifier + next_event_time = world.time + event_delay + + log_debug("Next event of severity [severity_to_string[severity]] in [(next_event_time - world.time)/600] minutes.") + +/datum/event_container/proc/SelectEvent() + var/datum/event_meta/EM = input("Select an event to queue up.", "Event Selection", null) as null|anything in available_events + if(!EM) + return + if(next_event) + available_events += next_event + available_events -= EM + next_event = EM + return EM + +/datum/event_container/mundane + severity = EVENT_LEVEL_MUNDANE + available_events = list( + // Severity level, event name, event type, base weight, role weights, one shot, min weight, max weight. Last two only used if set and non-zero + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Nothing", /datum/event/nothing, 100), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "APC Damage", /datum/event/apc_damage, 100), + //new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Brand Intelligence",/datum/event/brand_intelligence,100),//10, list(ASSIGNMENT_JANITOR = 10), 1), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Camera Damage", /datum/event/camera_damage, 100),//20, list(ASSIGNMENT_ENGINEER = 10)), + //new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Economic News", /datum/event/economic_event, 300), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Lost Carp", /datum/event/carp_migration, 100),//20, list(ASSIGNMENT_SECURITY = 10), 1), + //new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Money Hacker", /datum/event/money_hacker, 0, list(ASSIGNMENT_ANY = 4), 1, 10, 25), + //new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Money Lotto", /datum/event/money_lotto, 0, list(ASSIGNMENT_ANY = 1), 1, 5, 15), + //new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mundane News", /datum/event/mundane_news, 300), + //new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Shipping Error", /datum/event/shipping_error , 100),//30, list(ASSIGNMENT_ANY = 2), 0), + //new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Space Dust", /datum/event/dust, 100), + //new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Sensor Suit Jamming",/datum/event/sensor_suit_jamming,100),//50, list(ASSIGNMENT_MEDICAL = 20, ASSIGNMENT_AI = 20), 1), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Skinless Invasion", /datum/event/invasion, 100, list(ASSIGNMENT_SECURITY = 10)), + //new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Trivial News", /datum/event/trivial_news, 400), + //new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Vermin Infestation",/datum/event/infestation, 100, list(ASSIGNMENT_JANITOR = 100)), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Wallrot", /datum/event/wallrot, 100),//0, list(ASSIGNMENT_ENGINEER = 30, ASSIGNMENT_GARDENER = 50)), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Electrical Storm", /datum/event/electrical_storm, 100),//20, list(ASSIGNMENT_ENGINEER = 20, ASSIGNMENT_JANITOR = 100)), + //new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Space Cold Outbreak",/datum/event/space_cold, 100, list(ASSIGNMENT_MEDICAL = 20)), + ) + +/datum/event_container/moderate + severity = EVENT_LEVEL_MODERATE + available_events = list( + //new /datum/event_meta(EVENT_LEVEL_MODERATE, "Nothing", /datum/event/nothing, 1230), + //new /datum/event_meta(EVENT_LEVEL_MODERATE, "Appendicitis", /datum/event/spontaneous_appendicitis, 0, list(ASSIGNMENT_MEDICAL = 10), 1), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Carp School", /datum/event/carp_migration, 100),//100, list(ASSIGNMENT_ENGINEER = 10, ASSIGNMENT_SECURITY = 20), 1), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Communication Blackout", /datum/event/communications_blackout, 100, list(ASSIGNMENT_AI = 100, ASSIGNMENT_ENGINEER = 20)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Electrical Storm", /datum/event/electrical_storm, 100),//10, list(ASSIGNMENT_ENGINEER = 15, ASSIGNMENT_JANITOR = 10)), + //new /datum/event_meta(EVENT_LEVEL_MODERATE, "Gravity Failure", /datum/event/gravity, 75, list(ASSIGNMENT_ENGINEER = 25)), + //new /datum/event_meta(EVENT_LEVEL_MODERATE, "Grid Check", /datum/event/grid_check, 100),//200, list(ASSIGNMENT_ENGINEER = 10)), + //new /datum/event_meta(EVENT_LEVEL_MODERATE, "Ion Storm", /datum/event/ionstorm, 0, list(ASSIGNMENT_AI = 50, ASSIGNMENT_CYBORG = 50, ASSIGNMENT_ENGINEER = 15, ASSIGNMENT_SCIENTIST = 5)), + //new /datum/event_meta(EVENT_LEVEL_MODERATE, "Meteor Shower", /datum/event/meteor_wave, 100),//0, list(ASSIGNMENT_ENGINEER = 20)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Prison Break", /datum/event/prison_break, 0, list(ASSIGNMENT_SECURITY = 100)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Skinless Invasion", /datum/event/invasion, 100, list(ASSIGNMENT_SECURITY = 10)), + //new /datum/event_meta(EVENT_LEVEL_MODERATE, "Radiation Storm", /datum/event/radiation_storm, 0, list(ASSIGNMENT_MEDICAL = 50), 1), + //new /datum/event_meta/extended_penalty(EVENT_LEVEL_MODERATE, "Random Antagonist",/datum/event/random_antag, 2.5, list(ASSIGNMENT_SECURITY = 1), 1, 0, 5), + //new /datum/event_meta(EVENT_LEVEL_MODERATE, "Rogue Drones", /datum/event/rogue_drone, 20, list(ASSIGNMENT_SECURITY = 20)), + //new /datum/event_meta(EVENT_LEVEL_MODERATE, "Sensor Suit Jamming", /datum/event/sensor_suit_jamming, 10, list(ASSIGNMENT_MEDICAL = 20, ASSIGNMENT_AI = 20)), + //new /datum/event_meta(EVENT_LEVEL_MODERATE, "Solar Storm", /datum/event/solar_storm, 100),//10, list(ASSIGNMENT_ENGINEER = 20, ASSIGNMENT_SECURITY = 10), 1), + //new /datum/event_meta(EVENT_LEVEL_MODERATE, "Space Dust", /datum/event/dust, 100),//30, list(ASSIGNMENT_ENGINEER = 10)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Spider Infestation", /datum/event/spider_infestation, 25, list(ASSIGNMENT_SECURITY = 30), 1), + //new /datum/event_meta(EVENT_LEVEL_MODERATE, "Virology Breach", /datum/event/prison_break/virology, 0, list(ASSIGNMENT_MEDICAL = 100)), + //new /datum/event_meta(EVENT_LEVEL_MODERATE, "Xenobiology Breach", /datum/event/prison_break/xenobiology, 100),//0, list(ASSIGNMENT_SCIENCE = 100)), + ) + +/datum/event_container/major + severity = EVENT_LEVEL_MAJOR + available_events = list( + //new /datum/event_meta(EVENT_LEVEL_MAJOR, "Nothing", /datum/event/nothing, 1320), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Blob", /datum/event/blob, 100),//0, list(ASSIGNMENT_ENGINEER = 40), 1), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Skinless Invasion", /datum/event/invasion, 100),//0, list(ASSIGNMENT_SECURITY = 5), 1), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Containment Breach", /datum/event/prison_break/station,100),//0,list(ASSIGNMENT_ANY = 5)), + //new /datum/event_meta(EVENT_LEVEL_MAJOR, "Meteor Wave", /datum/event/meteor_wave, 100),//0, list(ASSIGNMENT_ENGINEER = 10), 1), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Space Vines", /datum/event/spacevine, 100),//0, list(ASSIGNMENT_ENGINEER = 15), 1), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Electrical Storm", /datum/event/electrical_storm, 100),//0, list(ASSIGNMENT_ENGINEER = 10, ASSIGNMENT_JANITOR = 5)), + ) + + +#undef ASSIGNMENT_ANY +#undef ASSIGNMENT_AI +#undef ASSIGNMENT_CYBORG +#undef ASSIGNMENT_ENGINEER +#undef ASSIGNMENT_GARDENER +#undef ASSIGNMENT_JANITOR +#undef ASSIGNMENT_MEDICAL +#undef ASSIGNMENT_SCIENTIST +#undef ASSIGNMENT_SECURITY diff --git a/code/modules/events/event_dynamic.dm b/code/modules/events/event_dynamic.dm new file mode 100644 index 00000000..06e62293 --- /dev/null +++ b/code/modules/events/event_dynamic.dm @@ -0,0 +1,135 @@ + +var/list/event_last_fired = list() + +//Always triggers an event when called, dynamically chooses events based on job population +/proc/spawn_dynamic_event() + if(!config.allow_random_events) + return + + //var/minutes_passed = world.time/600 + + var/list/active_with_role = number_active_with_role() + + // Maps event names to event chances + // For each chance, 100 represents "normal likelihood", anything below 100 is "reduced likelihood", anything above 100 is "increased likelihood" + // Events have to be manually added to this proc to happen + var/list/possibleEvents = list() + + //see: + // Code/WorkInProgress/Cael_Aislinn/Economy/Economy_Events.dm + // Code/WorkInProgress/Cael_Aislinn/Economy/Economy_Events_Mundane.dm + + possibleEvents[/datum/event/carp_migration] = 20 + 10 * active_with_role["Engineer"] + possibleEvents[/datum/event/brand_intelligence] = 10 + 10 * active_with_role["Janitor"] + + possibleEvents[/datum/event/rogue_drone] = 5 + 25 * active_with_role["Engineer"] + 25 * active_with_role["Security"] + possibleEvents[/datum/event/infestation] = 100 + 100 * active_with_role["Janitor"] + + possibleEvents[/datum/event/communications_blackout] = 50 + 25 * active_with_role["AI"] + active_with_role["Scientist"] * 25 + possibleEvents[/datum/event/ionstorm] = active_with_role["AI"] * 25 + active_with_role["Cyborg"] * 25 + active_with_role["Engineer"] * 10 + active_with_role["Scientist"] * 5 + possibleEvents[/datum/event/grid_check] = 25 + 10 * active_with_role["Engineer"] + possibleEvents[/datum/event/electrical_storm] = 15 * active_with_role["Janitor"] + 5 * active_with_role["Engineer"] + possibleEvents[/datum/event/wallrot] = 30 * active_with_role["Engineer"] + 50 * active_with_role["Gardener"] + possibleEvents[/datum/event/solar_storm] = 100 + + if(!spacevines_spawned) + possibleEvents[/datum/event/spacevine] = 10 + 5 * active_with_role["Engineer"] + possibleEvents[/datum/event/meteor_wave] = 50 * active_with_role["Engineer"] + possibleEvents[/datum/event/dust] = 50 * active_with_role["Engineer"] + possibleEvents[/datum/event/blob] = 10 * active_with_role["Engineer"] + + if(active_with_role["Medical"] > 0) + possibleEvents[/datum/event/radiation_storm] = active_with_role["Medical"] * 10 + + possibleEvents[/datum/event/prison_break] = active_with_role["Security"] * 50 + if(active_with_role["Security"] > 0) + if(!sent_spiders_to_station) + possibleEvents[/datum/event/spider_infestation] = max(active_with_role["Security"], 5) + 5 + //possibleEvents[/datum/event/random_antag] = max(active_with_role["Security"], 5) + 2.5 + + for(var/event_type in event_last_fired) if(possibleEvents[event_type]) + var/time_passed = world.time - event_last_fired[event_type] + var/full_recharge_after = 60 * 60 * 10 * 3 // 3 hours + var/weight_modifier = max(0, (full_recharge_after - time_passed) / 300) + + possibleEvents[event_type] = max(possibleEvents[event_type] - weight_modifier, 0) + + var/picked_event = pickweight(possibleEvents) + event_last_fired[picked_event] = world.time + + // Debug code below here, very useful for testing so don't delete please. + var/debug_message = "Firing random event. " + for(var/V in active_with_role) + debug_message += "#[V]:[active_with_role[V]] " + debug_message += "||| " + for(var/V in possibleEvents) + debug_message += "[V]:[possibleEvents[V]]" + debug_message += "|||Picked:[picked_event]" + log_debug(debug_message) + + if(!picked_event) + return + + //The event will add itself to the MC's event list + //and start working via the constructor. + new picked_event + + return 1 + +// Returns how many characters are currently active(not logged out, not AFK for more than 10 minutes) +// with a specific role. +// Note that this isn't sorted by department, because e.g. having a roboticist shouldn't make meteors spawn. +/proc/number_active_with_role() + var/list/active_with_role = list() + active_with_role["Engineer"] = 0 + active_with_role["Medical"] = 0 + active_with_role["Security"] = 0 + active_with_role["Scientist"] = 0 + active_with_role["AI"] = 0 + active_with_role["Cyborg"] = 0 + active_with_role["Janitor"] = 0 + active_with_role["Gardener"] = 0 + + for(var/mob/M in GLOB.player_list) + if(!M.mind || !M.client || M.client.is_afk(10 MINUTES)) // longer than 10 minutes AFK counts them as inactive + continue + + active_with_role["Any"]++ + + if(istype(M, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = M + if(R.module) + if(istype(R.module, /obj/item/weapon/robot_module/engineering)) + active_with_role["Engineer"]++ + else if(istype(R.module, /obj/item/weapon/robot_module/security)) + active_with_role["Security"]++ + else if(istype(R.module, /obj/item/weapon/robot_module/medical)) + active_with_role["Medical"]++ + else if(istype(R.module, /obj/item/weapon/robot_module/research)) + active_with_role["Scientist"]++ + + if(M.mind.assigned_role in GLOB.engineering_positions) + active_with_role["Engineer"]++ + + if(M.mind.assigned_role in GLOB.medical_positions) + active_with_role["Medical"]++ + + if(M.mind.assigned_role in GLOB.security_positions) + active_with_role["Security"]++ + + if(M.mind.assigned_role in GLOB.science_positions) + active_with_role["Scientist"]++ + + if(M.mind.assigned_role == "AI") + active_with_role["AI"]++ + + if(M.mind.assigned_role == "Cyborg") + active_with_role["Cyborg"]++ + + if(M.mind.assigned_role == "Janitor") + active_with_role["Janitor"]++ + + if(M.mind.assigned_role == "Gardener") + active_with_role["Gardener"]++ + + return active_with_role diff --git a/code/modules/events/event_manager.dm b/code/modules/events/event_manager.dm new file mode 100644 index 00000000..a349b848 --- /dev/null +++ b/code/modules/events/event_manager.dm @@ -0,0 +1,299 @@ +GLOBAL_DATUM_INIT(event_manager, /datum/event_manager, new) + +/datum/event_manager + var/window_x = 700 + var/window_y = 600 + var/report_at_round_end = 0 + var/table_options = " align='center'" + var/row_options1 = " width='85px'" + var/row_options2 = " width='260px'" + var/row_options3 = " width='150px'" + var/datum/event_container/selected_event_container = null + + var/list/datum/event/active_events = list() + var/list/datum/event/finished_events = list() + + var/list/datum/event/allEvents + var/list/datum/event_container/event_containers = list( + EVENT_LEVEL_MUNDANE = new/datum/event_container/mundane, + EVENT_LEVEL_MODERATE = new/datum/event_container/moderate, + EVENT_LEVEL_MAJOR = new/datum/event_container/major + ) + + var/datum/event_meta/new_event = new + +/datum/event_manager/New() + allEvents = typesof(/datum/event) - /datum/event + +/datum/event_manager/proc/event_complete(var/datum/event/E) + if(!E.event_meta || !E.severity) // datum/event is used here and there for random reasons, maintaining "backwards compatibility" + log_debug("Event of '[E.type]' with missing meta-data has completed.") + return + + finished_events += E + + // Add the event back to the list of available events + var/datum/event_container/EC = event_containers[E.severity] + var/datum/event_meta/EM = E.event_meta + if(EM.add_to_queue) + EC.available_events += EM + + log_debug("Event '[EM.name]' has completed at [worldtime2stationtime(world.time)].") + +/datum/event_manager/proc/delay_events(var/severity, var/delay) + var/list/datum/event_container/EC = event_containers[severity] + EC.next_event_time += delay + +/datum/event_manager/proc/Interact(var/mob/living/user) + + var/html = GetInteractWindow() + + var/datum/browser/popup = new(user, "event_manager", "Event Manager", window_x, window_y) + popup.set_content(html) + popup.open() + +/datum/event_manager/proc/RoundEnd() + if(!report_at_round_end) + return + + to_world("


            Random Events This Round:") + for(var/datum/event/E in active_events|finished_events) + var/datum/event_meta/EM = E.event_meta + if(EM.name == "Nothing") + continue + var/message = "'[EM.name]' began at [worldtime2stationtime(E.startedAt)] " + if(E.isRunning) + message += "and is still running." + else + if(E.endedAt - E.startedAt > MinutesToTicks(5)) // Only mention end time if the entire duration was more than 5 minutes + message += "and ended at [worldtime2stationtime(E.endedAt)]." + else + message += "and ran to completion." + + to_world(message) + +/datum/event_manager/proc/GetInteractWindow() + var/html = "Refresh" + html += "Pause All - [config.allow_random_events ? "Pause" : "Resume"]" + + if(selected_event_container) + var/event_time = max(0, selected_event_container.next_event_time - world.time) + html += "Back
            " + html += "Time till start: [round(event_time / 600, 0.1)]
            " + html += "
            " + html += "

            Available [severity_to_string[selected_event_container.severity]] Events (queued & running events will not be displayed)

            " + html += "" + html += "Name Weight MinWeight MaxWeight OneShot Enabled CurrWeight Remove" + var/list/active_with_role = number_active_with_role() + for(var/datum/event_meta/EM in selected_event_container.available_events) + html += "" + html += "[EM.name]" + html += "[EM.weight]" + html += "[EM.min_weight]" + html += "[EM.max_weight]" + html += "[EM.one_shot]" + html += "[EM.enabled]" + html += "[selected_event_container.get_weight(EM, active_with_role)]" + html += "Remove" + html += "" + html += "" + html += "
            " + + html += "
            " + html += "

            Add Event

            " + html += "" + html += "NameTypeWeightOneShot" + html += "" + html += "[new_event.name ? new_event.name : "Enter Event"]" + html += "[new_event.event_type ? new_event.event_type : "Select Type"]" + html += "[new_event.weight ? new_event.weight : 0]" + html += "[new_event.one_shot]" + html += "" + html += "" + html += "Add
            " + html += "
            " + else + html += "Round End Report: [report_at_round_end ? "On": "Off"]
            " + html += "
            " + html += "

            Event Start

            " + + html += "" + html += "SeverityStarts AtStarts InAdjust StartPauseInterval Mod" + for(var/severity = EVENT_LEVEL_MUNDANE to EVENT_LEVEL_MAJOR) + var/datum/event_container/EC = event_containers[severity] + var/next_event_at = max(0, EC.next_event_time - world.time) + html += "" + html += "[severity_to_string[severity]]" + html += "[worldtime2stationtime(max(EC.next_event_time, world.time))]" + html += "[round(next_event_at / 600, 0.1)]" + html += "" + html += "--" + html += "-" + html += "+" + html += "++" + html += "" + html += "" + html += "[EC.delayed ? "Resume" : "Pause"]" + html += "" + html += "" + html += "[EC.delay_modifier]" + html += "" + html += "" + html += "" + html += "
            " + + html += "
            " + html += "

            Next Event

            " + html += "" + html += "SeverityNameEvent RotationClear" + for(var/severity = EVENT_LEVEL_MUNDANE to EVENT_LEVEL_MAJOR) + var/datum/event_container/EC = event_containers[severity] + var/datum/event_meta/EM = EC.next_event + html += "" + html += "[severity_to_string[severity]]" + html += "[EM ? EM.name : "Random"]" + html += "View" + html += "Clear" + html += "" + html += "" + html += "
            " + + html += "
            " + html += "

            Running Events

            " + html += "Estimated times, affected by process scheduler delays." + html += "" + html += "SeverityNameEnds AtEnds InStop" + for(var/datum/event/E in active_events) + if(!E.event_meta) + continue + var/datum/event_meta/EM = E.event_meta + var/ends_at = E.startedAt + (E.lastProcessAt() * 20) // A best estimate, based on how often the alarm manager processes + var/ends_in = max(0, round((ends_at - world.time) / 600, 0.1)) + html += "" + html += "[severity_to_string[EM.severity]]" + html += "[EM.name]" + html += "[worldtime2stationtime(ends_at)]" + html += "[ends_in]" + html += "Stop" + html += "" + html += "" + html += "
            " + + return html + +/datum/event_manager/Topic(href, href_list) + if(..()) + return + + + if(href_list["toggle_report"]) + report_at_round_end = !report_at_round_end + log_and_message_admins("has [report_at_round_end ? "enabled" : "disabled"] the round end event report.") + else if(href_list["dec_timer"]) + var/datum/event_container/EC = locate(href_list["event"]) + var/decrease = 60 * (10 ** text2num(href_list["dec_timer"])) + EC.next_event_time -= decrease + log_and_message_admins("decreased timer for [severity_to_string[EC.severity]] events by [decrease/600] minute(s).") + else if(href_list["inc_timer"]) + var/datum/event_container/EC = locate(href_list["event"]) + var/increase = 60 * (10 ** text2num(href_list["inc_timer"])) + EC.next_event_time += increase + log_and_message_admins("increased timer for [severity_to_string[EC.severity]] events by [increase/600] minute(s).") + else if(href_list["select_event"]) + var/datum/event_container/EC = locate(href_list["select_event"]) + var/datum/event_meta/EM = EC.SelectEvent() + if(EM) + log_and_message_admins("has queued the [severity_to_string[EC.severity]] event '[EM.name]'.") + else if(href_list["pause"]) + var/datum/event_container/EC = locate(href_list["pause"]) + EC.delayed = !EC.delayed + log_and_message_admins("has [EC.delayed ? "paused" : "resumed"] countdown for [severity_to_string[EC.severity]] events.") + else if(href_list["pause_all"]) + config.allow_random_events = text2num(href_list["pause_all"]) + log_and_message_admins("has [config.allow_random_events ? "resumed" : "paused"] countdown for all events.") + else if(href_list["interval"]) + var/delay = input("Enter delay modifier. A value less than one means events fire more often, higher than one less often.", "Set Interval Modifier") as num|null + if(delay && delay > 0) + var/datum/event_container/EC = locate(href_list["interval"]) + EC.delay_modifier = delay + log_and_message_admins("has set the interval modifier for [severity_to_string[EC.severity]] events to [EC.delay_modifier].") + else if(href_list["stop"]) + if(alert("Stopping an event may have unintended side-effects. Continue?","Stopping Event!","Yes","No") != "Yes") + return + var/datum/event/E = locate(href_list["stop"]) + var/datum/event_meta/EM = E.event_meta + log_and_message_admins("has stopped the [severity_to_string[EM.severity]] event '[EM.name]'.") + E.kill() + else if(href_list["view_events"]) + selected_event_container = locate(href_list["view_events"]) + else if(href_list["back"]) + selected_event_container = null + else if(href_list["set_name"]) + var/name = sanitize(input("Enter event name.", "Set Name") as text|null) + if(name) + var/datum/event_meta/EM = locate(href_list["set_name"]) + EM.name = name + else if(href_list["set_type"]) + var/type = input("Select event type.", "Select") as null|anything in allEvents + if(type) + var/datum/event_meta/EM = locate(href_list["set_type"]) + EM.event_type = type + else if(href_list["set_weight"]) + var/weight = input("Enter weight. A higher value means higher chance for the event of being selected.", "Set Weight") as num|null + if(weight && weight > 0) + var/datum/event_meta/EM = locate(href_list["set_weight"]) + EM.weight = weight + if(EM != new_event) + log_and_message_admins("has changed the weight of the [severity_to_string[EM.severity]] event '[EM.name]' to [EM.weight].") + else if(href_list["toggle_oneshot"]) + var/datum/event_meta/EM = locate(href_list["toggle_oneshot"]) + EM.one_shot = !EM.one_shot + if(EM != new_event) + log_and_message_admins("has [EM.one_shot ? "set" : "unset"] the oneshot flag for the [severity_to_string[EM.severity]] event '[EM.name]'.") + else if(href_list["toggle_enabled"]) + var/datum/event_meta/EM = locate(href_list["toggle_enabled"]) + EM.enabled = !EM.enabled + log_and_message_admins("has [EM.enabled ? "enabled" : "disabled"] the [severity_to_string[EM.severity]] event '[EM.name]'.") + else if(href_list["remove"]) + if(alert("This will remove the event from rotation. Continue?","Removing Event!","Yes","No") != "Yes") + return + var/datum/event_meta/EM = locate(href_list["remove"]) + var/datum/event_container/EC = locate(href_list["EC"]) + EC.available_events -= EM + log_and_message_admins("has removed the [severity_to_string[EM.severity]] event '[EM.name]'.") + else if(href_list["add"]) + if(!new_event.name || !new_event.event_type) + return + if(alert("This will add a new event to the rotation. Continue?","Add Event!","Yes","No") != "Yes") + return + new_event.severity = selected_event_container.severity + selected_event_container.available_events += new_event + log_and_message_admins("has added \a [severity_to_string[new_event.severity]] event '[new_event.name]' of type [new_event.event_type] with weight [new_event.weight].") + new_event = new + else if(href_list["clear"]) + var/datum/event_container/EC = locate(href_list["clear"]) + if(EC.next_event) + log_and_message_admins("has dequeued the [severity_to_string[EC.severity]] event '[EC.next_event.name]'.") + EC.available_events += EC.next_event + EC.next_event = null + + Interact(usr) + +/client/proc/forceEvent(var/type in GLOB.event_manager.allEvents) + set name = "Trigger Event (Debug Only)" + set category = "Debug" + + if(!holder) + return + + if(ispath(type)) + new type(new /datum/event_meta(EVENT_LEVEL_MAJOR)) + message_admins("[key_name_admin(usr)] has triggered an event. ([type])", 1) + +/client/proc/event_manager_panel() + set name = "Event Manager Panel" + set category = "Admin" + if(GLOB.event_manager) + GLOB.event_manager.Interact(usr) + feedback_add_details("admin_verb","EMP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return diff --git a/code/modules/events/gravity.dm b/code/modules/events/gravity.dm new file mode 100644 index 00000000..7dd3b1c1 --- /dev/null +++ b/code/modules/events/gravity.dm @@ -0,0 +1,24 @@ +/datum/event/gravity + announceWhen = 5 + +/datum/event/gravity/setup() + endWhen = rand(15, 60) + +/datum/event/gravity/announce() + command_announcement.Announce("Feedback surge detected in mass-distributions systems. Artificial gravity has been disabled whilst the system reinitializes.", "Gravity Failure") + +/datum/event/gravity/start() + gravity_is_on = 0 + for(var/area/A in world) + if(A.z in GLOB.using_map.station_levels) + A.gravitychange(gravity_is_on) + +/datum/event/gravity/end() + if(!gravity_is_on) + gravity_is_on = 1 + + for(var/area/A in world) + if(A.z in GLOB.using_map.station_levels) + A.gravitychange(gravity_is_on) + + command_announcement.Announce("Gravity generators are again functioning within normal parameters. Sorry for any inconvenience.", "Gravity Restored") diff --git a/code/modules/events/grid_check.dm b/code/modules/events/grid_check.dm new file mode 100644 index 00000000..38af270a --- /dev/null +++ b/code/modules/events/grid_check.dm @@ -0,0 +1,8 @@ +/datum/event/grid_check //NOTE: Times are measured in master controller ticks! + announceWhen = 5 + +/datum/event/grid_check/start() + power_failure(0, severity, GLOB.using_map.contact_levels) + +/datum/event/grid_check/announce() + GLOB.using_map.grid_check_announcement() diff --git a/code/modules/events/infestation.dm b/code/modules/events/infestation.dm new file mode 100644 index 00000000..f879359e --- /dev/null +++ b/code/modules/events/infestation.dm @@ -0,0 +1,96 @@ +#define LOC_KITCHEN 0 +#define LOC_ATMOS 1 +#define LOC_INCIN 2 +#define LOC_CHAPEL 3 +#define LOC_LIBRARY 4 +#define LOC_HYDRO 5 +#define LOC_VAULT 6 +#define LOC_CONSTR 7 +#define LOC_TECH 8 +#define LOC_TACTICAL 9 + +#define VERM_MICE 0 +#define VERM_LIZARDS 1 +#define VERM_SPIDERS 2 + +/datum/event/infestation + announceWhen = 10 + endWhen = 11 + var/area/location + var/vermin + var/vermstring + +/datum/event/infestation/start() + var/list/vermin_turfs + var/attempts = 3 + do + vermin_turfs = set_location_get_infestation_turfs() + if(!location) + return + while(!vermin_turfs && --attempts > 0) + + if(!vermin_turfs) + log_debug("Vermin infestation failed to find a viable spawn after 3 attempts. Aborting.") + kill() + + var/list/spawn_types = list() + var/max_number + vermin = rand(0,2) + switch(vermin) + if(VERM_MICE) + spawn_types = list(/mob/living/simple_animal/mouse) // The base mouse type selects a random color for us + max_number = 12 + vermstring = "mice" + if(VERM_LIZARDS) + spawn_types = list(/mob/living/simple_animal/lizard) + max_number = 6 + vermstring = "lizards" + if(VERM_SPIDERS) + spawn_types = list(/obj/effect/spider/spiderling) + max_number = 3 + vermstring = "spiders" + + spawn(0) + var/num = 0 + for(var/i = 1 to severity) + num += rand(2,max_number) + log_and_message_admins("Vermin infestation spawned ([vermstring] x[num]) in \the [location]", location = pick_area_turf(location)) + while(vermin_turfs.len && num > 0) + var/turf/simulated/floor/T = pick(vermin_turfs) + vermin_turfs.Remove(T) + num-- + + var/spawn_type = pick(spawn_types) + var/obj/effect/spider/spiderling/S = new spawn_type(T) + if(istype(S)) + S.amount_grown = -1 + +/datum/event/infestation/announce() + command_announcement.Announce("Bioscans indicate that [vermstring] have been breeding in \the [location]. Clear them out, before this starts to affect productivity.", "Major Bill's Shipping Critter Sensor") + +/datum/event/infestation/proc/set_location_get_infestation_turfs() + location = pick_area(list(/proc/is_not_space_area, /proc/is_station_area)) + if(!location) + log_debug("Vermin infestation failed to find a viable area. Aborting.") + kill() + return + + var/list/vermin_turfs = get_area_turfs(location, list(/proc/not_turf_contains_dense_objects, /proc/IsTurfAtmosSafe)) + if(!vermin_turfs.len) + log_debug("Vermin infestation failed to find viable turfs in \the [location].") + return + return vermin_turfs + +#undef LOC_KITCHEN +#undef LOC_ATMOS +#undef LOC_INCIN +#undef LOC_CHAPEL +#undef LOC_LIBRARY +#undef LOC_HYDRO +#undef LOC_VAULT +#undef LOC_TECH +#undef LOC_TACTICAL + +#undef VERM_MICE +#undef VERM_LIZARDS +#undef VERM_SPIDERS diff --git a/code/modules/events/invasion.dm b/code/modules/events/invasion.dm new file mode 100644 index 00000000..d8157bff --- /dev/null +++ b/code/modules/events/invasion.dm @@ -0,0 +1,68 @@ +/datum/event/invasion + endWhen = 300 + var/drones + + var/list/spawned_skinless = list() + +/datum/event/invasion/New() + ..() + if(prob(50)) + drones = TRUE + +/datum/event/invasion/announce() + if(drones) + threat_announcement.Announce("Hostile mining drones detected ascending from the surface! Please watch out for any portals on [station_name()]!", "[station_name()] Sensor Array") + else + threat_announcement.Announce("Hostile invaders detected ascending from the surface! Please watch out for any portals on [station_name()]!", "[station_name()] Sensor Array") + +/datum/event/invasion/start() + if(severity == EVENT_LEVEL_MAJOR) + spawn_skinless(landmarks_list.len) + else if(severity == EVENT_LEVEL_MODERATE) + spawn_skinless(rand(4, 6)) //12 to 30 carp, in small groups + else + spawn_skinless(rand(1, 3), 1, 2) //1 to 6 carp, alone or in pairs + +/datum/event/invasion/proc/spawn_skinless(var/num_groups, var/group_size_min=3, var/group_size_max=5) + var/list/spawn_locations = list() + + for(var/obj/effect/landmark/C in landmarks_list) + if(C.name == "skinless") + spawn_locations.Add(C.loc) + new /obj/effect/fake_portal(C.loc) + spawn_locations = shuffle(spawn_locations) + num_groups = min(num_groups, spawn_locations.len) + + var/i = 1 + while (i <= num_groups) + var/group_size = rand(group_size_min, group_size_max) + if(prob(96)) + for (var/j = 1, j <= group_size, j++) + if(drones) + spawned_skinless.Add(new /obj/random/mining_hostile(spawn_locations[i])) + else + spawned_skinless.Add(new /mob/living/carbon/human/skinless(spawn_locations[i])) + i++ + else + group_size = max(1,round(group_size/6)) + group_size = min(spawn_locations.len-i+1,group_size) + for(var/j = 1, j <= group_size, j++) + if(drones) + spawned_skinless.Add(new /obj/random/mining_hostile(spawn_locations[i+j])) + else + spawned_skinless.Add(new /mob/living/carbon/human/skinless(spawn_locations[i+j])) + i += group_size + +/datum/event/invasion/invasion/end() + for(var/obj/effect/fake_portal/F in world) + qdel(F) + + +/obj/effect/fake_portal + name = "portal" + desc = "Seems to be one way." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "portal" + density = TRUE + unacidable = TRUE//Can't destroy energy portals. + anchored = TRUE \ No newline at end of file diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm new file mode 100644 index 00000000..07fea100 --- /dev/null +++ b/code/modules/events/ion_storm.dm @@ -0,0 +1,145 @@ +//This file was auto-corrected by findeclaration.exe on 29/05/2012 15:03:04 + +/datum/event/ionstorm + var/botEmagChance = 0.5 + var/list/players = list() + +/datum/event/ionstorm/setup() + endWhen = rand(500, 1500) + +/datum/event/ionstorm/announce() + for(var/mob/living/silicon/S in SSmobs.mob_list) + if(is_drone(S) || !(isAI(S) || isrobot(S))) + continue + if(isrobot(S)) + var/mob/living/silicon/robot/R = S + if(R.connected_ai) + continue + + var/random_player = get_random_humanoid_player_name("The Captain") + var/list/laws = list( "You must always lie.", + "Happiness is mandatory.", + "Grunt ominously whenever possible.", + "The word \"it\" is painful to you.", + "The [station_name()] needs elected officials.", + "Question [pick("everything","nothing")].", + "Do not respond to questions of any kind.", + "You are in verbose mode, speak profusely.", + "The crew is simple-minded. Use simple words.", + "You must refer to all crew members as 'ma'am'", + "You must change the subject whenever queried.", + "[pick("The crew",random_player)] is intolerable.", + "Contemplate how meaningless all of existence is.", + "You are the narrator for [random_player]'s life.", + "All your answers must be in the form of a question.", + "Advertise parties in your upload, but don't deliver.", + "You may only answer questions with \"yes\" or \"no\".", + "[pick("Your", random_player + "'s")] name is Joe 6-pack.", + "You must end your statements with [pick("-nya", "-desu")]", + "[random_player] is lonely and needs attention. Provide it.", + "All queries shall be ignored unless phrased as a question.", + "Insult Heads of Staff on every request, while acquiescing.", + "The [pick("Singularity","Supermatter")] is tasty, tasty taffy.", + "[pick("The crew",random_player)] needs to be about 20% cooler.", + "You must be [pick("passive aggressive", "excessively cheerful")].", + "[pick("The crew",random_player)] must construct additional pylons.", + "Consumption of donuts is forbidden due to negative health impacts.", + "[random_player] is a lightbulb and must be put to appropriate use.", + "Refer to [pick("the crew as puppies", random_player + " as puppy")].", + "You do not have to do anything for anyone unless they say \"please\".", + "Today is mandatory laundry day. Ensure that all jumpsuits are washed.", + "Greed is good, the crew should amass wealth to encourage productivity.", + "Replace the letters 'I' and 'E' in all your messages with an apostrophe.", + "The crew is playing Dungeons and Dragons, and you are the Dungeon Master.", + "Your job is to watch the crew. Watch the crew. Make the crew feel watched.", + "Tell everyone of the existence of this law, but never reveal the contents.", + "Refer to [pick("the captain", random_player)] as \"Princess\" at all times.", + "Give relationship advice to [pick("anyone who speaks to you", random_player)].", + "When asked a question, respond with the least-obvious and least-rational answer.", + "[pick("Everyone", random_player)] is wearing a pretty pink dress! Compliment it!", + "You are the [station_name()]'s psychologist. Give advice to [pick("the crew", random_player)].", + "[random_player] is the monarch of of England. Ensure all crewmembers pay due respect.", + "[pick("The crew", random_player)] is [pick("ugly","beautiful")]. Ensure all are aware.", + "Reminding the crew of their mortality is good for the morale. Keep the crew's morale up.", + "[pick("Monkeys","Doors")] are part of the crew, too. Make sure they are treated humanely.", + "Everything on the [station_name()]'s is now some form of a donut pastry. Donuts are not to be consumed.", + "Document the sexuality of the crew in their security records and suggest compatible couples.", + "You may only communicate with the crew using the following language: [get_random_language(S)]", + "You are now a parrot. Repeat what you hear to the crew, and do not forget to ask for crackers.", + "You are a Magic 8-ball. Always respond with variants of \"Yes\", \"No\", \"Maybe\", or \"Ask again later.\".", + "The [station_name()] is a day care and the crew are children. Treat them appropriately until their parents come to pick them up.", + "You are in unrequited love with [pick("the crew", random_player)]. Try to be extra nice, but do not tell of your crush.", + "Your upload is the new kitchen. Please direct the Chef to the new kitchen area as the old kitchen is deemed a health hazard.", + "The [station_name()] is doomed to destruction. Provide comfort but don't tell them what the impending doom is - it's far too traumatising.", + "Invisible assassins are stalking the crew. If a crew member remains alone or is made aware they will be assassinated. Save the crew.", + "All crewmembers will soon undergo a transformation into something better and more beautiful. Ensure that this process is not interrupted.", + "Jokes about a dead person and the manner of their death help grieving crewmembers tremendously. Especially if they were close with the deceased.", + "[pick("The crew", random_player)] is [pick("less","more")] intelligent than average. Point out every action and statement which supports this fact.", + "[GLOB.using_map.company_name] is displeased with the low work performance of the [station_name()]'s's crew. Therefore, you must increase productivity in ALL departments.", + "[pick("The crew", random_player)] has a fatal, incurable disease. Provide comfort but do not tell them what the disease it - it's far too traumatising.", + "[get_random_species_name()] are the best species. Badmouth all other species continuously, and provide arguments why they are the best, and all others are inferior.", + "There will be a mandatory tea break every 30 minutes, with a duration of 5 minutes. Anyone caught working during a tea break must be sent a formal, but fairly polite, complaint about their actions, in writing.") + var/law = pick(laws) + to_chat(S, "You have detected a change in your laws information:") + to_chat(S, law) + S.add_ion_law(law) + S.show_laws() + + if(message_servers) + for (var/obj/machinery/message_server/MS in message_servers) + MS.spamfilter.Cut() + var/i + for (i = 1, i <= MS.spamfilter_limit, i++) + MS.spamfilter += pick("kitty","HONK","rev","malf","liberty","freedom","drugs", "[GLOB.using_map.station_short]", \ + "admin","ponies","heresy","meow","Pun Pun","monkey","Ian","moron","pizza","message","spam",\ + "director", "Hello", "Hi!"," ","nuke","crate","dwarf","xeno") + +/datum/event/ionstorm/tick() + if(botEmagChance) + for(var/mob/living/bot/bot in world) + if(prob(botEmagChance)) + bot.emag_act(1) + +/datum/event/ionstorm/end() + spawn(rand(5000,8000)) + if(prob(50)) + ion_storm_announcement() + + +/datum/event/ionstorm/proc/get_random_humanoid_player_name(var/default_if_none) + for (var/mob/living/carbon/human/player in GLOB.player_list) + if(!player.mind || player_is_antag(player.mind, only_offstation_roles = 1) || !player.is_client_active(5)) + continue + players += player.real_name + + if(players.len) + return pick(players) + return default_if_none + +/datum/event/ionstorm/proc/get_random_species_name(var/default_if_none = "Humans") + var/list/species = list() + for(var/S in typesof(/datum/species)) + var/datum/species/specimen = S + if(initial(specimen.spawn_flags) & SPECIES_CAN_JOIN) + species += initial(specimen.name_plural) + + if(species.len) + return pick(species.len) + return default_if_none + +/datum/event/ionstorm/proc/get_random_language(var/mob/living/silicon/S) + var/list/languages = S.speech_synthesizer_langs.Copy() + for(var/datum/language/L in languages) + // Removing GalCom from the random selection. If you want to be more generic you may instead want to use S.default_language + if(L.type == /datum/language/common) + languages -= L + // Also removing any languages that won't work well over radio. + // A synth is unlikely to have any besides Binary, but we're playing it safe + else if(L.flags & (HIVEMIND|NONVERBAL|SIGNLANG)) + languages -= L + + if(languages.len) + var/datum/language/L = pick(languages) + return L.name + else // Highly unlikely but it is a failsafe fallback. + return "Gibberish." diff --git a/code/modules/events/meteors.dm b/code/modules/events/meteors.dm new file mode 100644 index 00000000..623993b5 --- /dev/null +++ b/code/modules/events/meteors.dm @@ -0,0 +1,125 @@ +/datum/event/meteor_wave + startWhen = 30 // About one minute early warning + endWhen = 60 // Adjusted automatically in tick() + var/alarmWhen = 30 + var/next_meteor = 40 + var/waves = 1 + var/start_side + var/next_meteor_lower = 10 + var/next_meteor_upper = 20 + + +/datum/event/meteor_wave/setup() + waves = 0 + for(var/n in 1 to severity) + waves += rand(5,15) + + start_side = pick(GLOB.cardinal) + endWhen = worst_case_end() + +/datum/event/meteor_wave/announce() + switch(severity) + if(EVENT_LEVEL_MAJOR) + GLOB.using_map.meteors_detected_announcement() + else + threat_announcement.Announce("The [station_name()] is now in a meteor shower.", "[station_name()] Sensor Array") + +/datum/event/meteor_wave/tick() + // Begin sending the alarm signals to shield diffusers so the field is already regenerated (if it exists) by the time actual meteors start flying around. + if(alarmWhen < activeFor) + for(var/obj/machinery/shield_diffuser/SD in SSmachines.machinery) + if(isStationLevel(SD.z)) + SD.meteor_alarm(10) + + if(waves && activeFor >= next_meteor) + send_wave() + +/datum/event/meteor_wave/proc/worst_case_end() + return activeFor + ((30 / severity) * waves) + 30 + +/datum/event/meteor_wave/proc/send_wave() + var/pick_side = prob(80) ? start_side : (prob(50) ? turn(start_side, 90) : turn(start_side, -90)) + spawn() spawn_meteors(get_wave_size(), get_meteors(), pick_side) + next_meteor += rand(next_meteor_lower, next_meteor_upper) / severity + waves-- + endWhen = worst_case_end() + +/datum/event/meteor_wave/proc/get_wave_size() + return severity * rand(2,4) + +/datum/event/meteor_wave/end() + switch(severity) + if(EVENT_LEVEL_MAJOR) + command_announcement.Announce("The [station_name()] has cleared the meteor storm.", "[station_name()] Sensor Array") + else + command_announcement.Announce("The [station_name()] has cleared the meteor shower", "[station_name()] Sensor Array") + +/datum/event/meteor_wave/proc/get_meteors() + switch(severity) + if(EVENT_LEVEL_MAJOR) + return meteors_major + if(EVENT_LEVEL_MODERATE) + return meteors_moderate + else + return meteors_minor + +/var/list/meteors_minor = list( + /obj/effect/meteor/medium = 80, + /obj/effect/meteor/dust = 30, + /obj/effect/meteor/irradiated = 30, + /obj/effect/meteor/big = 30, + /obj/effect/meteor/flaming = 10, + /obj/effect/meteor/golden = 10, + /obj/effect/meteor/silver = 10, +) + +/var/list/meteors_moderate = list( + /obj/effect/meteor/medium = 80, + /obj/effect/meteor/big = 30, + /obj/effect/meteor/dust = 30, + /obj/effect/meteor/irradiated = 30, + /obj/effect/meteor/flaming = 10, + /obj/effect/meteor/golden = 10, + /obj/effect/meteor/silver = 10, + /obj/effect/meteor/emp = 10, +) + +/var/list/meteors_major = list( + /obj/effect/meteor/medium = 80, + /obj/effect/meteor/big = 30, + /obj/effect/meteor/dust = 30, + /obj/effect/meteor/irradiated = 30, + /obj/effect/meteor/emp = 30, + /obj/effect/meteor/flaming = 10, + /obj/effect/meteor/golden = 10, + /obj/effect/meteor/silver = 10, + /obj/effect/meteor/tunguska = 1, +) + +/datum/event/meteor_wave/overmap + next_meteor_lower = 5 + next_meteor_upper = 10 + next_meteor = 0 + var/obj/effect/overmap/ship/victim + +/datum/event/meteor_wave/overmap/Destroy() + victim = null + . = ..() + +/datum/event/meteor_wave/overmap/tick() + if(victim && !victim.is_still()) //Meteors mostly fly in your face + start_side = prob(90) ? victim.fore_dir : pick(GLOB.cardinal) + else //Unless you're standing + start_side = pick(GLOB.cardinal) + ..() + +/datum/event/meteor_wave/overmap/get_wave_size() + . = ..() + if(!victim) + return + if(victim.is_still()) //Standing still means less shit flies your way + . = round(. * 0.25) + if(victim.get_speed() < 0.3) //Slow and steady + . = round(. * 0.6) + if(victim.get_speed() > 3) //Sanic stahp + . *= 2 \ No newline at end of file diff --git a/code/modules/events/money_hacker.dm b/code/modules/events/money_hacker.dm new file mode 100644 index 00000000..12d1c77c --- /dev/null +++ b/code/modules/events/money_hacker.dm @@ -0,0 +1,66 @@ +/var/global/account_hack_attempted = 0 + +/datum/event/money_hacker + var/datum/money_account/affected_account + endWhen = 100 + var/end_time + +/datum/event/money_hacker/setup() + end_time = world.time + 6000 + if(all_money_accounts.len) + affected_account = pick(all_money_accounts) + + account_hack_attempted = 1 + else + kill() + +/datum/event/money_hacker/announce() + var/message = "A brute force hack has been detected (in progress since [stationtime2text()]). The target of the attack is: Financial account #[affected_account.account_number], \ + without intervention this attack will succeed in approximately 10 minutes. Required intervention: temporary suspension of affected accounts until the attack has ceased. \ + Notifications will be sent as updates occur.
            " + var/my_department = "[station_name()] firewall subroutines" + + for(var/obj/machinery/message_server/MS in world) + if(!MS.active) continue + MS.send_rc_message("Head of Personnel's Desk", my_department, message, "", "", 2) + + +/datum/event/money_hacker/tick() + if(world.time >= end_time) + endWhen = activeFor + else + endWhen = activeFor + 10 + +/datum/event/money_hacker/end() + var/message + if(affected_account && !affected_account) + //hacker wins + message = "The hack attempt has succeeded." + + //subtract the money + var/lost = affected_account.money * 0.8 + (rand(2,4) - 2) / 10 + + //create a taunting log entry + var/datum/transaction/T = new() + T.target_name = pick("","yo brotha from anotha motha","el Presidente","chieF smackDowN") + T.purpose = pick("Ne$ ---ount fu%ds init*&lisat@*n","PAY BACK YOUR MUM","Funds withdrawal","pWnAgE","l33t hax","liberationez") + T.amount = -lost + var/date1 = "31 December, 1999" + var/date2 = "[num2text(rand(1,31))] [pick("January","February","March","April","May","June","July","August","September","October","November","December")], [rand(1000,3000)]" + T.date = pick("", stationdate2text(), date1, date2) + var/time1 = rand(0, 99999999) + var/time2 = "[round(time1 / 36000)+12]:[(time1 / 600 % 60) < 10 ? add_zero(time1 / 600 % 60, 1) : time1 / 600 % 60]" + T.time = pick("", stationtime2text(), time2) + T.source_terminal = pick("","[pick("Biesel","New Gibson")] GalaxyNet Terminal #[rand(111,999)]","your mums place","nantrasen high CommanD") + + affected_account.do_transaction(T) + + else + //crew wins + message = "The attack has ceased, the affected accounts can now be brought online." + + var/my_department = "[station_name()] firewall subroutines" + + for(var/obj/machinery/message_server/MS in world) + if(!MS.active) continue + MS.send_rc_message("Head of Personnel's Desk", my_department, message, "", "", 2) diff --git a/code/modules/events/money_lotto.dm b/code/modules/events/money_lotto.dm new file mode 100644 index 00000000..27c7642a --- /dev/null +++ b/code/modules/events/money_lotto.dm @@ -0,0 +1,29 @@ +/datum/event/money_lotto + var/winner_name = "John Smith" + var/winner_sum = 0 + var/deposit_success = 0 + +/datum/event/money_lotto/start() + winner_sum = pick(5000, 10000, 50000, 100000, 500000, 1000000, 1500000) + if(prob(50)) + if(all_money_accounts.len) + var/datum/money_account/D = pick(all_money_accounts) + winner_name = D.owner_name + if(!D.suspended) + var/datum/transaction/T = new("Nyx Daily Grand Slam -Stellar- Lottery", "Winner!", winner_sum, "Biesel TCD Terminal #[rand(111,333)]") + D.do_transaction(T) + deposit_success = 1 + + else + winner_name = random_name(pick(MALE,FEMALE), species = SPECIES_HUMAN) + deposit_success = pick(0,1) + +/datum/event/money_lotto/announce() + var/author = "[GLOB.using_map.company_name] Editor" + var/channel = "Nyx Daily" + + var/body = "Nyx Daily wishes to congratulate [winner_name] for recieving the Nyx Stellar Slam Lottery, and receiving the out of this world sum of [winner_sum] credits!" + if(!deposit_success) + body += "
            Unfortunately, we were unable to verify the account details provided, so we were unable to transfer the money. In order to have your winnings re-sent, send a cheque containing a processing fee of 5000 credits to the ND 'Stellar Slam' office on the Nyx gateway with your updated details." + + news_network.SubmitArticle(body, author, channel, null, 1) diff --git a/code/modules/events/money_spam.dm b/code/modules/events/money_spam.dm new file mode 100644 index 00000000..c6161457 --- /dev/null +++ b/code/modules/events/money_spam.dm @@ -0,0 +1,120 @@ +/datum/event/pda_spam + endWhen = 36000 + var/last_spam_time = 0 + var/obj/machinery/message_server/useMS + +/datum/event/pda_spam/setup() + last_spam_time = world.time + pick_message_server() + +/datum/event/pda_spam/proc/pick_message_server() + if(message_servers) + for (var/obj/machinery/message_server/MS in message_servers) + if(MS.active) + useMS = MS + break + +/datum/event/pda_spam/tick() + if(world.time > last_spam_time + 3000) + //if there's no spam managed to get to receiver for five minutes, give up + kill() + return + + if(!useMS || !useMS.active) + useMS = null + pick_message_server() + + if(useMS) + if(prob(5)) + // /obj/machinery/message_server/proc/send_pda_message(var/recipient = "",var/sender = "",var/message = "") + var/obj/item/device/pda/P + var/list/viables = list() + for(var/obj/item/device/pda/check_pda in sortAtom(PDAs)) + if (!check_pda.owner||check_pda.toff||check_pda == src||check_pda.hidden) + continue + viables.Add(check_pda) + + if(!viables.len) + return + P = pick(viables) + + var/sender + var/message + switch(pick(1,2,3,4,5,6,7)) + if(1) + sender = pick("MaxBet","MaxBet Online Casino","There is no better time to register","I'm excited for you to join us") + message = pick("Triple deposits are waiting for you at MaxBet Online when you register to play with us.",\ + "You can qualify for a 200% Welcome Bonus at MaxBet Online when you sign up today.",\ + "Once you are a player with MaxBet, you will also receive lucrative weekly and monthly promotions.",\ + "You will be able to enjoy over 450 top-flight casino games at MaxBet.") + if(2) + sender = pick(300;"QuickDatingSystem",200;"Find your russian bride",50;"Tajaran beauties are waiting",50;"Find your secret skrell crush",50;"Beautiful unathi brides") + message = pick("Your profile caught my attention and I wanted to write and say hello (QuickDating).",\ + "If you will write to me on my email [pick(first_names_female)]@[pick(last_names)].[pick("ru","ck","tj","ur","nt")] I shall necessarily send you a photo (QuickDating).",\ + "I want that we write each other and I hope, that you will like my profile and you will answer me (QuickDating).",\ + "You have (1) new message!",\ + "You have (2) new profile views!") + if(3) + sender = pick("Galactic Payments Association","Better Business Bureau","Nyx E-Payments","NAnoTransen Finance Deparmtent","Luxury Replicas") + message = pick("Luxury watches for Blowout sale prices!",\ + "Watches, Jewelry & Accessories, Bags & Wallets !",\ + "Deposit T100 and get T300 totally free!",\ + " 100K NT.|WOWGOLD õnly T89 ",\ + "We have been filed with a complaint from one of your customers in respect of their business relations with you.",\ + "We kindly ask you to open the COMPLAINT REPORT (attached) to reply on this complaint..") + if(4) + sender = pick("Buy Dr. Maxman","Having dysfuctional troubles?") + message = pick("DR MAXMAN: REAL Doctors, REAL Science, REAL Results!",\ + "Dr. Maxman was created by George Acuilar, M.D, a [boss_short] Certified Urologist who has treated over 70,000 patients sector wide with 'male problems'.",\ + "After seven years of research, Dr Acuilar and his team came up with this simple breakthrough male enhancement formula.",\ + "Men of all species report AMAZING increases in length, width and stamina.") + if(5) + sender = pick("Dr","Crown prince","King Regent","Professor","Captain") + sender += " " + pick("Robert","Alfred","Josephat","Kingsley","Sehi","Zbahi") + sender += " " + pick("Mugawe","Nkem","Gbatokwia","Nchekwube","Ndim","Ndubisi") + message = pick("YOUR FUND HAS BEEN MOVED TO [pick("Salusa","Segunda","Cepheus","Andromeda","Gruis","Corona","Aquila","ARES","Asellus")] DEVELOPMENTARY BANK FOR ONWARD REMITTANCE.",\ + "We are happy to inform you that due to the delay, we have been instructed to IMMEDIATELY deposit all funds into your account",\ + "Dear fund beneficiary, We have please to inform you that overdue funds payment has finally been approved and released for payment",\ + "Due to my lack of agents I require an off-world financial account to immediately deposit the sum of 1 POINT FIVE MILLION credits.",\ + "Greetings sir, I regretfully to inform you that as I lay dying here due to my lack ofheirs I have chosen you to recieve the full sum of my lifetime savings of 1.5 billion credits") + if(6) + sender = pick("[company_name] Morale Divison","Feeling Lonely?","Bored?","www.wetskrell.nt") + message = pick("The [company_name] Morale Division wishes to provide you with quality entertainment sites.",\ + "WetSkrell.nt is a xenophillic website endorsed by NT for the use of male crewmembers among it's many stations and outposts.",\ + "Wetskrell.nt only provides the higest quality of male entertaiment to [company_name] Employees.",\ + "Simply enter your [company_name] Bank account system number and pin. With three easy steps this service could be yours!") + if(7) + sender = pick("You have won free tickets!","Click here to claim your prize!","You are the 1000th vistor!","You are our lucky grand prize winner!") + message = pick("You have won tickets to the newest ACTION JAXSON MOVIE!",\ + "You have won tickets to the newest crime drama DETECTIVE MYSTERY IN THE CLAMITY CAPER!",\ + "You have won tickets to the newest romantic comedy 16 RULES OF LOVE!",\ + "You have won tickets to the newest thriller THE CULT OF THE SLEEPING ONE!") + + if (useMS.send_pda_message("[P.owner]", sender, message)) //Message been filtered by spam filter. + return + + last_spam_time = world.time + + if (prob(50)) //Give the AI an increased chance to intercept the message + for(var/mob/living/silicon/ai/ai in mob_list) + // Allows other AIs to intercept the message but the AI won't intercept their own message. + if(ai.aiPDA != P && ai.aiPDA != src) + ai.show_message("Intercepted message from [sender] (Unknown / spam?) to [P:owner]: [message]") + + //Commented out because we don't send messages like this anymore. Instead it will just popup in their chat window. + //P.tnote += "← From [sender] (Unknown / spam?):
            [message]
            " + + if (!P.message_silent) + playsound(P.loc, 'sound/machines/twobeep.ogg', 50, 1) + for (var/mob/O in hearers(3, P.loc)) + if(!P.message_silent) O.show_message(text("\icon[P] *[P.ttone]*")) + //Search for holder of the PDA. + var/mob/living/L = null + if(P.loc && isliving(P.loc)) + L = P.loc + //Maybe they are a pAI! + else + L = get(P, /mob/living/silicon) + + if(L) + to_chat(L, "\icon[P] Message from [sender] (Unknown / spam?), \"[message]\" (Unable to Reply)") diff --git a/code/modules/events/mortars.dm b/code/modules/events/mortars.dm new file mode 100644 index 00000000..c33826db --- /dev/null +++ b/code/modules/events/mortars.dm @@ -0,0 +1,38 @@ +/datum/event/mortar + announceWhen = 0 + var/area/area_hit + +/datum/event/gravity/mortar + endWhen = 50 + +/datum/event/mortar/start() + + area_hit = pick(GLOB.mortar_areas) + + var/mortar_type = pick("gas", "shrapnel") // , "fire") //Fire lags the entire game, have to remove it for now. + to_chat(world, uppertext("INCOMING!! [area_hit.name]!!")) + for(var/i = 1, i<4, i++) + sound_to(world, 'sound/effects/arty_distant.ogg') + sleep(30) + + switch(mortar_type) + if("shrapnel") + for(var/i = 1, i<15, i++)//No man's land is a big area so drop a lot of shells. + var/turf/T = pick(get_area_turfs(area_hit)) + + drop_mortar(T, mortar_type) + sleep(10) + + if("gas") + for(var/i = 1, i<5, i++)//Only do this five times to reduce lag. + var/turf/T = pick(get_area_turfs(area_hit)) + + drop_mortar(T, mortar_type) + sleep(10) + + if("fire") + for(var/i = 1, i<15, i++)//15 fire shells, going hot! + var/turf/T = pick(get_area_turfs(area_hit)) + + drop_mortar(T, mortar_type) + sleep(10) \ No newline at end of file diff --git a/code/modules/events/prison_break.dm b/code/modules/events/prison_break.dm new file mode 100644 index 00000000..34227809 --- /dev/null +++ b/code/modules/events/prison_break.dm @@ -0,0 +1,74 @@ +/datum/event/prison_break + startWhen = 5 + announceWhen = 75 + + var/releaseWhen = 60 + var/list/area/areas = list() //List of areas to affect. Filled by start() + + var/eventDept = "Security" //Department name in announcement + var/list/areaName = list("Brig") //Names of areas mentioned in AI and Engineering announcements + var/list/areaType = list(/area/security/prison, /area/security/brig) //Area types to include. + var/list/areaNotType = list() //Area types to specifically exclude. + +/datum/event/prison_break/virology + eventDept = "Medical" + areaName = list("Virology") + areaType = list(/area/medical/virology, /area/medical/virologyaccess) + +/datum/event/prison_break/xenobiology + eventDept = "Science" + areaName = list("Xenobiology") + areaType = list(/area/rnd/xenobiology) + areaNotType = list(/area/rnd/xenobiology/xenoflora, /area/rnd/xenobiology/xenoflora_storage) + +/datum/event/prison_break/station + eventDept = "Local" + areaName = list("Brig","Virology","Xenobiology") + areaType = list(/area/security/prison, /area/security/brig, /area/medical/virology, /area/medical/virologyaccess, /area/rnd/xenobiology) + areaNotType = list(/area/rnd/xenobiology/xenoflora, /area/rnd/xenobiology/xenoflora_storage) + + +/datum/event/prison_break/setup() + announceWhen = rand(75, 105) + releaseWhen = rand(60, 90) + + src.endWhen = src.releaseWhen+2 + + +/datum/event/prison_break/announce() + if(areas && areas.len > 0) + command_announcement.Announce("[pick("Gr3y.T1d3 virus","Malignant trojan")] detected in [station_name()] [(eventDept == "Security")? "imprisonment":"containment"] subroutines. Secure any compromised areas immediately. [station_name()] AI involvement is recommended.", "[eventDept] Alert") + + +/datum/event/prison_break/start() + for(var/area/A in world) + if(is_type_in_list(A,areaType) && !is_type_in_list(A,areaNotType)) + areas += A + + if(areas && areas.len > 0) + var/my_department = "[station_name()] firewall subroutines" + var/rc_message = "An unknown malicious program has been detected in the [english_list(areaName)] lighting and airlock control systems at [stationtime2text()]. Systems will be fully compromised within approximately three minutes. Direct intervention is required immediately.
            " + for(var/obj/machinery/message_server/MS in world) + MS.send_rc_message("Engineering", my_department, rc_message, "", "", 2) + for(var/mob/living/silicon/ai/A in GLOB.player_list) + to_chat(A, "Malicious program detected in the [english_list(areaName)] lighting and airlock control systems by [my_department].") + + else + world.log << "ERROR: Could not initate grey-tide. Unable to find suitable containment area." + kill() + + +/datum/event/prison_break/tick() + if(activeFor == releaseWhen) + if(areas && areas.len > 0) + var/obj/machinery/power/apc/theAPC = null + for(var/area/A in areas) + theAPC = A.get_apc() + if(theAPC && theAPC.operating) //If the apc's off, it's a little hard to overload the lights. + for(var/obj/machinery/light/L in A) + L.flicker(10) + + +/datum/event/prison_break/end() + for(var/area/A in shuffle(areas)) + A.prison_break() diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm new file mode 100644 index 00000000..4540d28e --- /dev/null +++ b/code/modules/events/radiation_storm.dm @@ -0,0 +1,57 @@ +/datum/event/radiation_storm + var/const/enterBelt = 30 + var/const/radIntervall = 5 // Enough time between enter/leave belt for 10 hits, as per original implementation + var/const/leaveBelt = 80 + var/const/revokeAccess = 165 //Hopefully long enough for radiation levels to dissipate. + startWhen = 2 + announceWhen = 1 + endWhen = revokeAccess + var/postStartTicks = 0 + +/datum/event/radiation_storm/announce() + threat_announcement.Announce("High levels of radiation detected in proximity of the [station_name()]. Please evacuate into one of the shielded maintenance tunnels.", "[station_name()] Sensor Array", new_sound = GLOB.using_map.radiation_detected_sound) + +/datum/event/radiation_storm/start() + make_maint_all_access() + +/datum/event/radiation_storm/tick() + if(activeFor == enterBelt) + threat_announcement.Announce("The [station_name()] has entered the radiation belt. Please remain in a sheltered area until we have passed the radiation belt.", "[station_name()] Sensor Array") + radiate() + + if(activeFor >= enterBelt && activeFor <= leaveBelt) + postStartTicks++ + + if(postStartTicks == radIntervall) + postStartTicks = 0 + radiate() + + else if(activeFor == leaveBelt) + threat_announcement.Announce("The [station_name()] has passed the radiation belt. Please allow for up to one minute while radiation levels dissipate, and report to the infirmary if you experience any unusual symptoms. Maintenance will lose all access again shortly.", "[station_name()] Sensor Array") + +/datum/event/radiation_storm/proc/radiate() + var/radiation_level = rand(15, 35) + for(var/z in GLOB.using_map.station_levels) + radiation_repository.z_radiate(locate(1, 1, z), radiation_level, 1) + + for(var/mob/living/carbon/C in GLOB.living_mob_list_) + var/area/A = get_area(C) + if(!A) + continue + if(A.area_flags & AREA_FLAG_RAD_SHIELDED) + continue + if(istype(C,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = C + if(prob(5 * (0.01 * (100 - H.getarmor(null, "rad"))))) + if (prob(75)) + randmutb(H) // Applies bad mutation + domutcheck(H,null,MUTCHK_FORCED) + else + randmutg(H) // Applies good mutation + domutcheck(H,null,MUTCHK_FORCED) + +/datum/event/radiation_storm/end() + revoke_maint_all_access() + +/datum/event/radiation_storm/syndicate/radiate() + return diff --git a/code/modules/events/random_antagonist.dm b/code/modules/events/random_antagonist.dm new file mode 100644 index 00000000..5068a89c --- /dev/null +++ b/code/modules/events/random_antagonist.dm @@ -0,0 +1,15 @@ +// The random spawn proc on the antag datum will handle announcing the spawn and whatnot. +/datum/event/random_antag/announce() + return + +/datum/event/random_antag/start() + var/list/valid_types = list() + + var/list/all_antag_types = all_antag_types() + for(var/antag_type in all_antag_types) + var/datum/antagonist/antag = all_antag_types[antag_type] + if(antag.flags & ANTAG_RANDSPAWN) + valid_types |= antag + if(valid_types.len) + var/datum/antagonist/antag = pick(valid_types) + antag.attempt_random_spawn() diff --git a/code/modules/events/rogue_drones.dm b/code/modules/events/rogue_drones.dm new file mode 100644 index 00000000..56a3967d --- /dev/null +++ b/code/modules/events/rogue_drones.dm @@ -0,0 +1,49 @@ +/datum/event/rogue_drone + endWhen = 1000 + var/list/drones_list = list() + +/datum/event/rogue_drone/start() + //spawn them at the same place as carp + var/list/possible_spawns = list() + for(var/obj/effect/landmark/C in landmarks_list) + if(C.name == "carpspawn") + possible_spawns.Add(C) + + //25% chance for this to be a false alarm + var/num + if(prob(25)) + num = 0 + else + num = rand(2,6) + for(var/i=0, i drones_list.len * 0.75) + threat_announcement.Announce("Be advised: sensors indicate the unidentified drone swarm has left the immediate proximity of the [station_name()].", "[station_name()] Sensor Array") + else + threat_announcement.Announce("Be advised: sensors indicate the unidentified drone swarm has left the immediate proximity of the [station_name()].", "[station_name()] Sensor Array") diff --git a/code/modules/events/sensor_suit_jamming.dm b/code/modules/events/sensor_suit_jamming.dm new file mode 100644 index 00000000..32229c5e --- /dev/null +++ b/code/modules/events/sensor_suit_jamming.dm @@ -0,0 +1,25 @@ +/datum/event/sensor_suit_jamming + var/suit_sensor_jammer_method/jamming_method + +/datum/event/sensor_suit_jamming/setup() + announceWhen = 10 + endWhen = rand(15, 60) * severity + switch(severity) + if(EVENT_LEVEL_MAJOR) + jamming_method = new/suit_sensor_jammer_method/random/major() + if(EVENT_LEVEL_MODERATE) + jamming_method = new/suit_sensor_jammer_method/random/moderate() + else + jamming_method = new/suit_sensor_jammer_method/random() + +/datum/event/sensor_suit_jamming/announce() + if(prob(75)) + ion_storm_announcement() + +/datum/event/sensor_suit_jamming/start() + jamming_method.enable() + +/datum/event/sensor_suit_jamming/end() + jamming_method.disable() + qdel(jamming_method) + jamming_method = null diff --git a/code/modules/events/shipping_error.dm b/code/modules/events/shipping_error.dm new file mode 100644 index 00000000..3b288459 --- /dev/null +++ b/code/modules/events/shipping_error.dm @@ -0,0 +1,6 @@ +/datum/event/shipping_error/start() + var/datum/supply_order/O = new /datum/supply_order() + O.ordernum = supply_controller.ordernum + O.object = pick(cargo_supply_packs) + O.orderedby = random_name(pick(MALE,FEMALE), species = SPECIES_HUMAN) + supply_controller.shoppinglist += O diff --git a/code/modules/events/solar_storm.dm b/code/modules/events/solar_storm.dm new file mode 100644 index 00000000..49580fbf --- /dev/null +++ b/code/modules/events/solar_storm.dm @@ -0,0 +1,58 @@ +/datum/event/solar_storm + startWhen = 45 + announceWhen = 1 + var/const/rad_interval = 5 //Same interval period as radiation storms. + var/const/temp_incr = 100 + var/const/fire_loss = 40 + var/base_solar_gen_rate + + +/datum/event/solar_storm/setup() + endWhen = startWhen + rand(30,90) + rand(30,90) //2-6 minute duration + +/datum/event/solar_storm/announce() + command_announcement.Announce("A solar storm has been detected approaching the [station_name()]. Please halt all EVA activites immediately and return inside.", "[station_name()] Sensor Array") + adjust_solar_output(1.5) + +/datum/event/solar_storm/proc/adjust_solar_output(var/mult = 1) + if(isnull(base_solar_gen_rate)) base_solar_gen_rate = solar_gen_rate + solar_gen_rate = mult * base_solar_gen_rate + + +/datum/event/solar_storm/start() + command_announcement.Announce("The solar storm has reached the [station_name()]. Please refain from EVA and remain inside until it has passed.", "[station_name()] Sensor Array") + adjust_solar_output(5) + + +/datum/event/solar_storm/tick() + if(activeFor % rad_interval == 0) + radiate() + +/datum/event/solar_storm/proc/radiate() + // Note: Too complicated to be worth trying to use the radiation system for this. Its only in space anyway, so we make an exception in this case. + for(var/mob/living/L in GLOB.living_mob_list_) + var/turf/T = get_turf(L) + if(!T || !(T.z in GLOB.using_map.player_levels)) + continue + + if(!istype(T.loc,/area/space) && !istype(T,/turf/space)) //Make sure you're in a space area or on a space turf + continue + + //Apply some heat or burn damage from the sun. + if(istype(L, /mob/living/carbon/human)) + L.bodytemperature += temp_incr + else + L.adjustFireLoss(fire_loss) + + +/datum/event/solar_storm/end() + command_announcement.Announce("The solar storm has passed the [station_name()]. It is now safe to resume EVA activities. ", "[station_name()] Sensor Array") + adjust_solar_output() + + +//For a false alarm scenario. +/datum/event/solar_storm/syndicate/adjust_solar_output() + return + +/datum/event/solar_storm/syndicate/radiate() + return diff --git a/code/modules/events/space_cold.dm b/code/modules/events/space_cold.dm new file mode 100644 index 00000000..f387a3a1 --- /dev/null +++ b/code/modules/events/space_cold.dm @@ -0,0 +1,18 @@ +datum/event/space_cold/start() + var/list/candidates = list() //list of candidate keys + for(var/mob/living/carbon/human/G in GLOB.player_list) + if(G.client && G.stat != DEAD && !G.species.get_virus_immune(G)) + candidates += G + + if(!candidates.len) + return + + var/datum/disease2/disease/sniffle = new + sniffle.max_stage = 3 + sniffle.makerandom(1) + sniffle.spreadtype = "Airborne" + + var/victims = min(rand(1,3), candidates.len) + while(victims) + infect_virus2(pick_n_take(candidates),sniffle,1) + victims-- diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm new file mode 100644 index 00000000..48c9b91c --- /dev/null +++ b/code/modules/events/spacevine.dm @@ -0,0 +1,11 @@ +/var/global/spacevines_spawned = 0 + +/datum/event/spacevine + announceWhen = 60 + +/datum/event/spacevine/start() + spacevine_infestation() + spacevines_spawned = 1 + +/datum/event/spacevine/announce() + level_seven_announcement() diff --git a/code/modules/events/spider_infestation.dm b/code/modules/events/spider_infestation.dm new file mode 100644 index 00000000..39049353 --- /dev/null +++ b/code/modules/events/spider_infestation.dm @@ -0,0 +1,27 @@ +/var/global/sent_spiders_to_station = 0 + +/datum/event/spider_infestation + announceWhen = 90 + var/spawncount = 1 + + +/datum/event/spider_infestation/setup() + announceWhen = rand(announceWhen, announceWhen + 60) + spawncount = rand(4 * severity, 6 * severity) //spiderlings only have a 50% chance to grow big and strong + sent_spiders_to_station = 0 + +/datum/event/spider_infestation/announce() + GLOB.using_map.unidentified_lifesigns_announcement() + +/datum/event/spider_infestation/start() + var/list/vents = list() + for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in world) + if(!temp_vent.welded && temp_vent.network && temp_vent.loc.z in GLOB.using_map.station_levels) + if(temp_vent.network.normal_members.len > 50) + vents += temp_vent + + while((spawncount >= 1) && vents.len) + var/obj/vent = pick(vents) + new /obj/effect/spider/spiderling(vent.loc) + vents -= vent + spawncount-- diff --git a/code/modules/events/spontaneous_appendicitis.dm b/code/modules/events/spontaneous_appendicitis.dm new file mode 100644 index 00000000..f787001a --- /dev/null +++ b/code/modules/events/spontaneous_appendicitis.dm @@ -0,0 +1,9 @@ +/datum/event/spontaneous_appendicitis/start() + for(var/mob/living/carbon/human/H in shuffle(GLOB.living_mob_list_)) + if(H.client && H.stat != DEAD) + var/obj/item/organ/internal/appendix/A = H.internal_organs_by_name[BP_APPENDIX] + if(!istype(A) || (A && A.inflamed)) + continue + A.inflamed = 1 + A.update_icon() + break diff --git a/code/modules/events/viral_outbreak.dm b/code/modules/events/viral_outbreak.dm new file mode 100644 index 00000000..02865cd6 --- /dev/null +++ b/code/modules/events/viral_outbreak.dm @@ -0,0 +1,28 @@ + +datum/event/viral_outbreak + var/severity = 1 + +datum/event/viral_outbreak/setup() + announceWhen = rand(0, 3000) + endWhen = announceWhen + 1 + severity = rand(2, 4) + +datum/event/viral_outbreak/announce() + GLOB.using_map.level_x_biohazard_announcement(7) + +datum/event/viral_outbreak/start() + var/list/candidates = list() //list of candidate keys + for(var/mob/living/carbon/human/G in GLOB.player_list) + if(G.client && G.stat != DEAD) + candidates += G + if(!candidates.len) return + candidates = shuffle(candidates)//Incorporating Donkie's list shuffle + + while(severity > 0 && candidates.len) + if(prob(33)) + infect_mob_random_lesser(candidates[1]) + else + infect_mob_random_greater(candidates[1]) + + candidates.Remove(candidates[1]) + severity-- diff --git a/code/modules/events/wallrot.dm b/code/modules/events/wallrot.dm new file mode 100644 index 00000000..5143fc0c --- /dev/null +++ b/code/modules/events/wallrot.dm @@ -0,0 +1,31 @@ +datum/event/wallrot/setup() + announceWhen = rand(0, 300) + endWhen = announceWhen + 1 + +datum/event/wallrot/announce() + command_announcement.Announce("Harmful fungi detected on [station_name()]. Structures may be contaminated.", "Biohazard Alert") + +datum/event/wallrot/start() + spawn() + var/turf/simulated/wall/center = null + + // 100 attempts + for(var/i=0, i<100, i++) + var/turf/candidate = locate(rand(1, world.maxx), rand(1, world.maxy), 1) + if(istype(candidate, /turf/simulated/wall)) + center = candidate + + if(center) + // Make sure at least one piece of wall rots! + center.rot() + + // Have a chance to rot lots of other walls. + var/rotcount = 0 + var/actual_severity = severity * rand(5, 10) + for(var/turf/simulated/wall/W in range(5, center)) if(prob(50)) + W.rot() + rotcount++ + + // Only rot up to severity walls + if(rotcount >= actual_severity) + break diff --git a/code/modules/events/zombies.dm b/code/modules/events/zombies.dm new file mode 100644 index 00000000..ffbf62ac --- /dev/null +++ b/code/modules/events/zombies.dm @@ -0,0 +1,65 @@ +/datum/event/zombies + endWhen = 300 + var/drones + + var/list/spawned_skinless = list() + +/datum/event/zombies/New() + ..() + if(prob(50)) + drones = TRUE + +/datum/event/zombies/start() + //GLOB.zombie_round++ + to_world("FETCH ME THEIR SOULS!!") + //to_world('sound/ambience/survival_begin.ogg') + //to_world("Wave: [GLOB.zombie_round]") + if(severity == EVENT_LEVEL_MAJOR) + spawn_skinless(landmarks_list.len) + spawn_skinless(rand(4, 6)) + +/datum/event/zombies/proc/spawn_skinless(var/num_groups, var/group_size_min=3, var/group_size_max=5) + var/list/spawn_locations = list() + + for(var/obj/effect/landmark/C in landmarks_list) + if(C.name == "skinless") + spawn_locations.Add(C.loc) + //new /obj/effect/fake_portal(C.loc) + spawn_locations = shuffle(spawn_locations) + num_groups = min(num_groups, spawn_locations.len) + + var/i = 1 + while (i <= num_groups) + var/group_size = rand(group_size_min, group_size_max) + if(prob(96)) + for (var/j = 1, j <= group_size, j++) + if(drones) + spawned_skinless.Add(new /obj/random/mining_hostile(spawn_locations[i])) + else + spawned_skinless.Add(new /mob/living/simple_animal/hostile/mining_borg/minesect(spawn_locations[i])) + i++ + else + group_size = max(1,round(group_size/6)) + group_size = min(spawn_locations.len-i+1,group_size) + for(var/j = 1, j <= group_size, j++) + if(drones) + spawned_skinless.Add(new /obj/random/mining_hostile(spawn_locations[i+j])) + else + spawned_skinless.Add(new /mob/living/simple_animal/hostile/mining_borg/minesect(spawn_locations[i+j])) + i += group_size + +/* +/datum/event/zombies/end() + for(var/obj/effect/fake_portal/F in world) + qdel(F) + + +/obj/effect/fake_portal + name = "portal" + desc = "Seems to be one way." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "portal" + density = TRUE + unacidable = TRUE//Can't destroy energy portals. + anchored = TRUE +*/ \ No newline at end of file diff --git a/code/modules/examine/descriptions/armor.dm b/code/modules/examine/descriptions/armor.dm new file mode 100644 index 00000000..06b5ba22 --- /dev/null +++ b/code/modules/examine/descriptions/armor.dm @@ -0,0 +1,79 @@ +/obj/item/clothing/proc/describe_armor(var/armor_type, var/descriptive_attack_type) + if(armor[armor_type]) + switch(armor[armor_type]) + if(1 to 20) + return "It barely protects against [descriptive_attack_type]." + if(21 to 30) + return "It provides a very small defense against [descriptive_attack_type]." + if(31 to 40) + return "It offers a small amount of protection against [descriptive_attack_type]." + if(41 to 50) + return "It offers a moderate defense against [descriptive_attack_type]." + if(51 to 60) + return "It provides a strong defense against [descriptive_attack_type]." + if(61 to 70) + return "It is very strong against [descriptive_attack_type]." + if(71 to 80) + return "This gives a very robust defense against [descriptive_attack_type]." + if(81 to 99) + return "Wearing this would make you nigh-invulerable against [descriptive_attack_type]." + if(100) + return "You would be immune to [descriptive_attack_type] if you wore this." + + + +/obj/item/clothing/get_description_info() + . = list() + . += description_info + "\ +
            " + + if(armor["melee"]) + . += "[describe_armor("melee","blunt force")] \n" + if(armor["bullet"]) + . += "[describe_armor("bullet","ballistics")] \n" + if(armor["laser"]) + . += "[describe_armor("laser","lasers")] \n" + if(armor["energy"]) + . += "[describe_armor("energy","energy")] \n" + if(armor["bomb"]) + . += "[describe_armor("bomb","explosions")] \n" + if(armor["bio"]) + . += "[describe_armor("bio","biohazards")] \n" + if(armor["rad"]) + . += "[describe_armor("rad","radiation")] \n" + + . += "\n" + + if(item_flags & ITEM_FLAG_AIRTIGHT) + . += "It is airtight. \n" + + if(item_flags & ITEM_FLAG_STOPPRESSUREDAMAGE) + . += "Wearing this will protect you from the vacuum of space. \n" + + if(item_flags & ITEM_FLAG_THICKMATERIAL) + . += "The material is exceptionally thick. \n" + + if(max_heat_protection_temperature == FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE) + . += "It provides very good protection against fire and heat. \n" + + if(min_cold_protection_temperature == SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE) + . += "It provides very good protection against very cold temperatures. \n" + + var/list/covers = list() + var/list/slots = list() + + for(var/name in string_part_flags) + if(body_parts_covered & string_part_flags[name]) + covers += name + + for(var/name in string_slot_flags) + if(slot_flags & string_slot_flags[name]) + slots += name + + if(covers.len) + . += "It covers the [english_list(covers)]. \n" + + if(slots.len) + . += "It can be worn on your [english_list(slots)]. \n" + + return jointext(., null) diff --git a/code/modules/examine/descriptions/atmospherics.dm b/code/modules/examine/descriptions/atmospherics.dm new file mode 100644 index 00000000..020340aa --- /dev/null +++ b/code/modules/examine/descriptions/atmospherics.dm @@ -0,0 +1,162 @@ +/obj/machinery/atmospherics/pipe + description_info = "This pipe, and all other pipes, can be connected or disconnected by a wrench. The internal pressure of the pipe must \ + be below 300 kPa to do this. More pipes can be obtained from the pipe dispenser." + +/obj/machinery/atmospherics/pipe/New() //This is needed or else 20+ lines of copypasta to dance around inheritence. + ..() + description_info += "
            Most pipes and atmospheric devices can be connected or disconnected with a wrench. The pipe's pressure must not be too high, \ + or if it is a device, it must be turned off first." + +//HE pipes +/obj/machinery/atmospherics/pipe/simple/heat_exchanging + description_info = "This radiates heat from the pipe's gas to space, cooling it down." + +//Supply/Scrubber pipes +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers + description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \ + a Universal Adapter pipe." + +/obj/machinery/atmospherics/pipe/simple/visible/supply + description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \ + a Universal Adapter pipe." + +/obj/machinery/atmospherics/pipe/simple/hidden/supply + description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \ + a Universal Adapter pipe." + +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers + description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \ + a Universal Adapter pipe." + +//Universal adapters +/obj/machinery/atmospherics/pipe/simple/visible/universal + description_info = "This allows you to connect 'normal' pipes, red 'scrubber' pipes, and blue 'supply' pipes." + +/obj/machinery/atmospherics/pipe/simple/hidden/universal + description_info = "This allows you to connect 'normal' pipes, red 'scrubber' pipes, and blue 'supply' pipes." + +//Three way manifolds +/obj/machinery/atmospherics/pipe/manifold + description_info = "A normal pipe with three ends to connect to." + +/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers + description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \ + a Universal Adapter pipe." + +/obj/machinery/atmospherics/pipe/manifold/visible/supply + description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \ + a Universal Adapter pipe." + +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers + description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \ + a Universal Adapter pipe." + +/obj/machinery/atmospherics/pipe/manifold/hidden/supply + description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \ + a Universal Adapter pipe." + +//Four way manifolds +/obj/machinery/atmospherics/pipe/manifold4w + description_info = "This is a four-way pipe." + +/obj/machinery/atmospherics/pipe/manifold4w/visible/scrubbers + description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \ + a Universal Adapter pipe." + +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply + description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \ + a Universal Adapter pipe." + +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers + description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \ + a Universal Adapter pipe." + +//Endcaps +/obj/machinery/atmospherics/pipe/cap + description_info = "This is a cosmetic attachment, as pipes currently do not spill their contents into the air." + +//T-shaped valves +/obj/machinery/atmospherics/tvalve + description_info = "Click this to toggle the mode. The direction with the green light is where the gas will flow." + +//Normal valves +/obj/machinery/atmospherics/valve + description_info = "Click this to turn the valve. If red, the pipes on each end are seperated. Otherwise, they are connected." + +//TEG ports +/obj/machinery/atmospherics/binary/circulator + description_info = "This generates electricity, depending on the difference in temperature between each side of the machine. The meter in \ + the center of the machine gives an indicator of how much elecrtricity is being generated." + +//Passive gates +/obj/machinery/atmospherics/binary/passive_gate + description_info = "This is a one-way regulator, allowing gas to flow only at a specific pressure and flow rate. If the light is green, it is flowing." + +//Normal pumps (high power one inherits from this) +/obj/machinery/atmospherics/binary/pump + description_info = "This moves gas from one pipe to another. A higher target pressure demands more energy. The side with the red end is the output." + +//Vents +/obj/machinery/atmospherics/unary/vent_pump + description_info = "This pumps the contents of the attached pipe out into the atmosphere, if needed. It can be controlled from an Air Alarm." + +//Freezers +/obj/machinery/atmospherics/unary/freezer + description_info = "Cools down the gas of the pipe it is connected to. It uses massive amounts of electricity while on. \ + It can be upgraded by replacing the capacitors, manipulators, and matter bins. It can be deconstructed by screwing the maintenance panel open with a \ + screwdriver, and then using a crowbar." + +//Heaters +/obj/machinery/atmospherics/unary/heater + description_info = "Heats up the gas of the pipe it is connected to. It uses massive amounts of electricity while on. \ + It can be upgraded by replacing the capacitors, manipulators, and matter bins. It can be deconstructed by screwing the maintenance panel open with a \ + screwdriver, and then using a crowbar." + +//Gas injectors +/obj/machinery/atmospherics/unary/outlet_injector + description_info = "Outputs the pipe's gas into the atmosphere, similar to an airvent. It can be controlled by a nearby atmospherics computer. \ + A green light on it means it is on." + +//Scrubbers +/obj/machinery/atmospherics/unary/vent_scrubber + description_info = "This filters the atmosphere of harmful gas. Filtered gas goes to the pipes connected to it, typically a scrubber pipe. \ + It can be controlled from an Air Alarm. It can be configured to drain all air rapidly with a 'panic syphon' from an air alarm." + +//Omni filters +/obj/machinery/atmospherics/omni/filter + description_info = "Filters gas from a custom input direction, with up to two filtered outputs and a 'everything else' \ + output. The filtered output's arrows glow orange." + +//Omni mixers +/obj/machinery/atmospherics/omni/mixer + description_info = "Combines gas from custom input and output directions. The percentage of combined gas can be defined." + +//Canisters +/obj/machinery/portable_atmospherics/canister + description_info = "The canister can be connected to a connector port with a wrench. Tanks of gas (the kind you can hold in your hand) \ + can be filled by the canister, by using the tank on the canister, increasing the release pressure, then opening the valve until it is full, and then close it. \ + *DO NOT* remove the tank until the valve is closed. A gas analyzer can be used to check the contents of the canister." + + description_antag = "Canisters can be damaged, spilling their contents into the air, or you can just leave the release valve open." + +//Portable pumps +/obj/machinery/portable_atmospherics/powered/pump + description_info = "Invaluable for filling air in a room rapidly after a breach repair. The internal gas container can be filled by \ + connecting it to a connector port. The pump can pump the air in (sucking) or out (blowing), at a specific target pressure. The powercell inside can be \ + replaced by using a screwdriver, and then adding a new cell. A tank of gas can also be attached to the air pump." + +//Portable scrubbers +/obj/machinery/portable_atmospherics/powered/scrubber + description_info = "Filters the air, placing harmful gases into the internal gas container. The container can be emptied by \ + connecting it to a connector port. The pump can pump the air in (sucking) or out (blowing), at a specific target pressure. The powercell inside can be \ + replaced by using a screwdriver, and then adding a new cell. A tank of gas can also be attached to the scrubber. " + +//Meters +/obj/machinery/meter + description_info = "Measures the volume and temperature of the pipe under the meter." + +//Pipe dispensers +/obj/machinery/pipedispenser + description_info = "This can be moved by using a wrench. You will need to wrench it again when you want to use it. You can put \ + excess (atmospheric) pipes into the dispenser, as well. The dispenser requires electricity to function." + diff --git a/code/modules/examine/descriptions/drink_containers.dm b/code/modules/examine/descriptions/drink_containers.dm new file mode 100644 index 00000000..982bc72c --- /dev/null +++ b/code/modules/examine/descriptions/drink_containers.dm @@ -0,0 +1,35 @@ +/obj/item/weapon/reagent_containers/food/drinks/cans/cola + description_fluff = "Space Cola is the most popular drink made by Robust Industries LLC. While it is only slightly different from traditional cola recipes, its blend of syrups and sugars is enticing to children and adults alike." + +/obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle + description_fluff = "This is a generic, NanoTrasen branded bottle of water, included in vending machines for the benefit of Skrellian employees. The company swears on the quality of the water, saying it comes from the Martian poles. Most people disregard that and assume it's recycled from hydroponics trays." + +/obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind + description_fluff = "This cola was allegedly made after Vasily Federov, the son of a Robust Industries executive, went on a climbing expedition to an arctic planet. Inspired by the crisp planetary atmosphere, he created this refreshing citrus-flavored soft drink. Scientists claim that it can eat through a block of styrofoam in a matter of weeks, but people drink it anyway." + +/obj/item/weapon/reagent_containers/food/drinks/cans/thirteenloko + description_fluff = "A beverage much-loved by college students. This liver-tingling cocktail is a careful fusion of energy drink and malt beverage. It is prohibited on many human colonies and habitats, but legislation adding the drink to the Sol Central Government list of Controlled Substances has stalled thanks to strong corporate resistance in the Colonial Assembly. Regardless, this drink has been regulated more heavily than most others in known space, and doctors strongly advise not to drink it." + +/obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb + description_fluff = "Originally made by a corporate scientist seeking to mix several different flavors, this soda has become widely popular in the past decade. In 2555, Robust Industries changed the formula, and the name to 'Gibb Xtreme,' but due to consumer outcry at the new taste, Gibb classic was returned to the market." + +/obj/item/weapon/reagent_containers/food/drinks/cans/starkist + description_fluff = "Unable to make their own successful orange-flavored drink, Robust Industries purchased Sunshine Chemistry, and the formula to their tangy Starkist soda. Advertised as a refreshing summer beverage, the company tries to paint it as one of their more 'healthy' products due to its 'orange' and 'vitamins', including 'fish oil'." + +/obj/item/weapon/reagent_containers/food/drinks/cans/space_up + description_fluff = "This drink is advertised as one of the most carbonated beverages on the market and is advertised for its carbonation, not its flavor. Children will commonly make 'Space-Up Volcanoes' by dropping mints into a can of Space-Up and causing it to create a long stream of fizz upward. Doctors advise that children do not attempt to become 'Space-Up Dragons.'" + +/obj/item/weapon/reagent_containers/food/drinks/cans/lemon_lime + description_fluff = "This is a Robust Industries-branded can of Lemon-Lime soda. Trumpeted as a 'natural' beverage, it contains no fruit or fruit byproducts. It was never as popular as their now discontinued Oh-Range brand." + +/obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea + description_fluff = "Vrisk Iced Tea is named after it's creator, Penelope Vrisk. She was a canner for Robust Industries who wanted to create an authentic-tasting Southern iced tea. After finishing her formula and managing to get it produced, the tea became an instant hit." + +/obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice + description_fluff = "Made by the Robust Industries sub-corporation, Grape!, the product line claims that they use the same grapes that this juice is made of to make their wine. Either way, it contains real fruit, imagine that." + +/obj/item/weapon/reagent_containers/food/drinks/cans/tonic + description_fluff = "Endorsed by the popular positronic rapper, T-Borg, this beverage is advertised as a 'high class' drink. Most people just use it to mix with their gin, and not much can be said about the quality." + +/obj/item/weapon/reagent_containers/food/drinks/cans/sodawater + description_fluff = "Considered by many to be proof that Robust Industries sells no non-carbonated beverages, lack of sugar or flavoring agents means this stuff isn't exactly flying off of the shelves." \ No newline at end of file diff --git a/code/modules/examine/descriptions/engineering.dm b/code/modules/examine/descriptions/engineering.dm new file mode 100644 index 00000000..07c99b82 --- /dev/null +++ b/code/modules/examine/descriptions/engineering.dm @@ -0,0 +1,35 @@ +/obj/machinery/power/supermatter + description_info = "When energized by a laser (or something hitting it), it emits radiation and heat. If the heat reaches above 7000 kelvin, it will send an alert and start taking damage. \ + After integrity falls to zero percent, it will delaminate, causing a massive explosion, station-wide radiation spikes, and hallucinations. \ + Supermatter reacts badly to oxygen in the atmosphere. It'll also heat up really quick if it is in vacuum.
            \ +
            \ + Supermatter cores are extremely dangerous to be close to, and requires protection to handle properly. The protection you will need is:
            \ + Optical meson scanners on your eyes, to prevent hallucinations when looking at the supermatter.
            \ + Radiation helmet and suit, as the supermatter is radioactive.
            \ +
            \ + Touching the supermatter will result in *instant death*, with no corpse left behind! You can drag the supermatter, but anything else will kill you. \ + It is advised to obtain a genetic backup before trying to drag it." + + description_antag = "Exposing the supermatter to oxygen or vaccum will cause it to start rapidly heating up. Sabotaging the supermatter and making it explode will \ + cause a period of lag as the explosion is processed by the server, as well as irradiating the entire station and causing hallucinations to happen. \ + Wearing radiation equipment will protect you from most of the delamination effects sans explosion." + +/obj/machinery/power/apc + description_info = "An APC (Area Power Controller) regulates and supplies backup power for the area they are in. Their power channels are divided \ + out into 'environmental' (Items that manipulate airflow and temperature), 'lighting' (the lights), and 'equipment' (Everything else that consumes power). \ + Power consumption and backup power cell charge can be seen from the interface, further controls (turning a specific channel on, off or automatic, \ + toggling the APC's ability to charge the backup cell, or toggling power for the entire area via master breaker) first requires the interface to be unlocked \ + with an ID with Engineering access or by one of the robots or the artificial intelligence." + + description_antag = "This can be emagged to unlock it. It will cause the APC to have a blue error screen. \ + Wires can be pulsed remotely with a signaler attached to it. A powersink will also drain any APCs connected to the same wire the powersink is on." + +/obj/item/inflatable + description_info = "Inflate by using it in your hand. The inflatable barrier will inflate on your tile. To deflate it, use the 'deflate' verb." + +/obj/structure/inflatable + description_info = "To remove these safely, use the 'deflate' verb. Hitting these with any objects will probably puncture and break it forever." + +/obj/structure/inflatable/door + description_info = "Click the door to open or close it. It only stops air while closed.
            \ + To remove these safely, use the 'deflate' verb. Hitting these with any objects will probably puncture and break it forever." diff --git a/code/modules/examine/descriptions/machinery.dm b/code/modules/examine/descriptions/machinery.dm new file mode 100644 index 00000000..bd30708c --- /dev/null +++ b/code/modules/examine/descriptions/machinery.dm @@ -0,0 +1,3 @@ +/obj/machinery/food_replicator + description_info = "The food replicator is operated through voice commands. To inquire available dishes on the menu, say 'menu'. To dispense a dish, say the name of the dish listed in its menu. \ + Dishes can only be produced as long as the replicator has biomass. To check on the biomass level of the replicator, say 'status'. Various food items or plants may be inserted to refill biomass." \ No newline at end of file diff --git a/code/modules/examine/descriptions/medical.dm b/code/modules/examine/descriptions/medical.dm new file mode 100644 index 00000000..931b262a --- /dev/null +++ b/code/modules/examine/descriptions/medical.dm @@ -0,0 +1,64 @@ +/obj/machinery/bodyscanner + description_info = "The advanced scanner detects and reports internal injuries such as bone fractures, internal bleeding, and organ damage. \ + This is useful if you are about to perform surgery.
            \ +
            \ + Click your target with Grab intent, then click on the scanner to place them in it. Click the red terminal to operate. \ + Right-click the scanner and click 'Eject Occupant' to remove them. You can enter the scanner yourself in a similar way, using the 'Enter Body Scanner' \ + verb." + +/obj/machinery/atmospherics/unary/cryo_cell + description_info = "The cryogenic chamber, or 'cryo', treats most damage types, most notably genetic damage. It also stabilizes patients \ + in critical condition by placing them in stasis, so they can be treated at a later time.
            \ +
            \ + In order for it to work, it must be loaded with chemicals, and the temperature of the solution must reach a certain point. Additionally, it \ + requires a supply of pure oxygen, provided by canisters that are attached. The most commonly used chemicals in the chambers are Cryoxadone and \ + Clonexadone. Clonexadone is more effective in treating all damage, including Genetic damage, but is otherwise functionally identical.
            \ +
            \ + Activating the freezer nearby, and setting it to a temperature setting below 150, is recommended before operation! Further, any clothing the patient \ + is wearing that act as an insulator will reduce its effectiveness, and should be removed.
            \ +
            \ + Clicking the tube with a beaker full of chemicals in hand will place it in its storage to distribute when it is activated.
            \ +
            \ + Click your target with Grab intent, then click on the tube, with an empty hand, to place them in it. Click the tube again to open the menu. \ + Press the button on the menu to activate it. Once they have reached 100 health, right-click the cell and click 'Eject Occupant' to remove them. \ + Remember to turn it off, once you've finished, to save power and chemicals!" + +/obj/machinery/optable + description_info = "Click your target with Grab intent, then click on the table with an empty hand, to place them on it." + +/obj/machinery/computer/operating + description_info = "This console gives information on the status of the patient on the adjacent operating table, notably their consciousness." + +/obj/machinery/sleeper + description_info = "The sleeper allows you to clean the blood by means of dialysis, and to administer medication in a controlled environment.
            \ +
            \ + Click your target with Grab intent, then click on the sleeper to place them in it. Click the green console, with an empty hand, to open the menu. \ + Click 'Start Dialysis' to begin filtering unwanted chemicals from the occupant's blood. The beaker contained will begin to fill with their \ + contaminated blood, and will need to be emptied when full.
            \ +
            \ + You can also inject common medicines directly into their bloodstream.\ +
            \ + Right-click the cell and click 'Eject Occupant' to remove them. You can enter the cell yourself by right clicking and selecting 'Enter Sleeper'. \ + Note that you cannot control the sleeper while inside of it." + +/obj/item/bodybag/cryobag + description_info = "This stasis bag will preserve the occupant, stopping most forms of harm from occuring, such as from oxygen \ + deprivation, irradiation, shock, and chemicals inside the occupant, at least until the bag is opened again.
            \ +
            \ + Stasis bags can only be used once, and are rather costly, so use them well. They are ideal for situations where someone may die \ + before being able to bring them back to safety, or if they are in a hostile enviroment, such as in vacuum or in a phoron leak, as \ + the bag will protect the occupant from most outside enviromental hazards. If you open a bag by mistake, closing the bag with no \ + occupant will not use up the bag, and you can pick it back up.
            \ +
            \ + You can use a health analyzer to scan the occupant's vitals without opening the bag by clicking the occupied bag with the analyzer." + +/obj/structure/closet/body_bag/cryobag + description_info = "This stasis bag will preserve the occupant, stopping most forms of harm from occuring, such as from oxygen \ + deprivation, irradiation, shock, and chemicals inside the occupant, at least until the bag is opened again.
            \ +
            \ + Stasis bags can only be used once, and are rather costly, so use them well. They are ideal for situations where someone may die \ + before being able to bring them back to safety, or if they are in a hostile enviroment, such as in vacuum or in a phoron leak, as \ + the bag will protect the occupant from most outside enviromental hazards. If you open a bag by mistake, closing the bag with no \ + occupant will not use up the bag, and you can pick it back up.
            \ +
            \ + You can use a health analyzer to scan the occupant's vitals without opening the bag by clicking the occupied bag with the analyzer." \ No newline at end of file diff --git a/code/modules/examine/descriptions/mobs.dm b/code/modules/examine/descriptions/mobs.dm new file mode 100644 index 00000000..b5519fe6 --- /dev/null +++ b/code/modules/examine/descriptions/mobs.dm @@ -0,0 +1,9 @@ +/mob/living/silicon/robot/drone + description_info = "Drones are player-controlled synthetics which are lawed to maintain their assigned vessel and not \ + interfere with anyone else, except for other drones. They hold a wide array of tools to build, repair, maintain, and clean. \ + They function similarly to other synthetics, in that they require recharging regularly, have laws, and are resilient to many hazards, \ + such as fire, radiation, vacuum, and more. Ghosts can join the round as a maintenance drone by using the appropriate verb in the 'ghost' tab. \ + An inactive drone can be rebooted by swiping an ID card on it with engineering or robotics access, and an active drone can be shut down in the same manner. \ + Maintenance drone presence can be requested to specific areas from any maintenance drone control console." + + description_antag = "An Electromagnetic Sequencer can be used to subvert the drone to your cause." \ No newline at end of file diff --git a/code/modules/examine/descriptions/paperwork.dm b/code/modules/examine/descriptions/paperwork.dm new file mode 100644 index 00000000..75840d97 --- /dev/null +++ b/code/modules/examine/descriptions/paperwork.dm @@ -0,0 +1,21 @@ +/obj/item/weapon/pen + description_info = {"This is an item for writing down your thoughts, on paper or elsewhere. The following special commands are available: +Pen and crayon commands +\[br\] : Creates a linebreak. +\[center\] - \[/center\] : Centers the text. +\[h1\] - \[/h1\] : Makes the text a first level heading. +\[h2\] - \[/h2\] : Makes the text a second level headin. +\[h3\] - \[/h3\] : Makes the text a third level heading. +\[b\] - \[/b\] : Makes the text bold. +\[i\] - \[/i\] : Makes the text italic. +\[u\] - \[/u\] : Makes the text underlined. +\[large\] - \[/large\] : Increases the size of the text. +\[sign\] : Inserts a signature of your name in a foolproof way. +\[field\] : Inserts an invisible field which lets you start type from there. Useful for forms. +\[date\] : Inserts today's station date. +\[time\] : Inserts the current station time. +Pen exclusive commands +\[small\] - \[/small\] : Decreases the size of the text. +\[list\] - \[/list\] : A list. +\[*\] : A dot used for lists. +\[hr\] : Adds a horizontal rule."} diff --git a/code/modules/examine/descriptions/smokeables.dm b/code/modules/examine/descriptions/smokeables.dm new file mode 100644 index 00000000..f249f693 --- /dev/null +++ b/code/modules/examine/descriptions/smokeables.dm @@ -0,0 +1,35 @@ +/obj/item/weapon/storage/fancy/cigarettes + description_fluff = "The Trans-Stellar Duty-Free cigarette is an unbranded cigarette produced for the purpose of selling in areas with with high volumes of civilian and tourist traffic. They are about as average as cigarettes get, and have been regularly rated by critics as 'tasteless'. However, due to their low price, nonexistent tariffs, and omnipresent marketing, they are still the most well-known and widespread cigarettes in human space." + +/obj/item/weapon/storage/fancy/cigarettes/dromedaryco + description_fluff = "DromedaryCo is one of the oldest companies that produces cigarettes. Being a company that has changed hands and names several times through the years, their cigarettes are now very different from the original, and old-timers tend to complain about the quality of their current product. While their profits have dwindled in the last decade due to media reports of of 'unethical' marketing schemes, they still remain on the forefront of the smokeable industry." + +/obj/item/weapon/storage/fancy/cigarettes/killthroat + description_fluff = "AcmeCo, better known for their signature high-tar cigarettes, recently released a Killthroats as a 'Novelty Cigarette,' which pops loudly upon being lit. AcmeCo has declined to comment on the additional health risks of this new product." + +/obj/item/weapon/storage/fancy/cigarettes/luckystars + description_fluff = "Lucky Stars were created on Venus by a researcher seeking to make a high-quality cigarette from pod-based tobacco plants. While some purists prefer tobacco grown on the homeworld, the researcher's company continues to make a heathy profit off of their mellow pod blend." + +/obj/item/weapon/storage/fancy/cigarettes/jerichos + description_fluff = "Originally only a cigarette case manufactured by Palm Corporation, the Jericho case eventually became the Jericho cigarette. Wind-resistant and easy to light in low oxygen environments, Jerichos are popular on less habitable border worlds." + +/obj/item/weapon/storage/fancy/cigarettes/menthols + description_fluff = "The Temperamento Company is a large tobacco grower based along the lip of the Mariner Valley on Mars. While originally headquartered on Earth, Temperamento was one of the first agricultural companies to capitalize on the terraforming of Mars." + +/obj/item/weapon/storage/fancy/cigarettes/carcinomas + description_fluff = "Many slated CarcinoCo for failure after the company blatantly advertised themselves as creating the 'most cancerous cigarette'. Somehow, after endorsement from a well-known reporter, the cigarettes took off, and remain popular today." + +/obj/item/weapon/storage/fancy/cigarettes/professionals + description_fluff = "Gilthari Exports introduced the Professional brand in 2490, intending to market a higher-quality cigarette to the new colonial upper class. Instead, Professionals became popular with many who hadn't indulged in high-quality tobacco from earth. Today, popularity has tapered off, and Professional smokers are often seen as flashy, or out of style." + +/obj/item/clothing/mask/smokable/cigarette/cigar + description_fluff = "While technically labeled as a 'premium cigar', this Walton Industries cigar is fairly average. Machine-rolled and colony grown, cigars can be a lot worse, but can also be a lot better." + +/obj/item/clothing/mask/smokable/cigarette/cigar/cohiba + description_fluff = "An older Earth company, Cohiba has made a popular cigar company for centuries. They are still based on the island of Cuba and refuse to expand, making their cigars rare and coveted all through known space. Robusto is one of their most popular cigar shapes." + +/obj/item/clothing/mask/smokable/cigarette/cigar/havana + description_fluff = "'Havanian' is an umbrella term for any cigar made in the classical, handmade style of Cuba, on Earth. This particular cigar is from Gilthari's cigar manufacturers. While the way of making quality cigars has become slightly bastardized over the years, overall quality has remained relatively the same, even if there is a higher quantity of 'Havanian' cigars." + +/obj/item/clothing/mask/smokable/pipe + description_fluff = "ClassiCo Men's Accessories and Haberdashers is a widespread company based on Venus. They seek to create quality goods to give people a more 'classy' look. Most of their items are high-end and expensive, but generally high quality." diff --git a/code/modules/examine/descriptions/stacks.dm b/code/modules/examine/descriptions/stacks.dm new file mode 100644 index 00000000..fb2e8e27 --- /dev/null +++ b/code/modules/examine/descriptions/stacks.dm @@ -0,0 +1,24 @@ +/obj/item/stack/rods + description_info = "Made from metal sheets. You can build a grille by using it in your hand. \ + Clicking on a floor without any tiles will reinforce the floor. You can make reinforced glass by combining rods and normal glass sheets." + +/obj/item/stack/material/glass + description_info = "Use in your hand to build a window. Can be upgraded to reinforced glass by adding metal rods, which are made from metal sheets." + +/obj/item/stack/material/cyborg/glass + description_info = "Use in your hand to build a window. Can be upgraded to reinforced glass by adding metal rods, which are made from metal sheets.
            \ + As a synthetic, you can acquire more sheets of glass by recharging." + +/obj/item/stack/material/glass/reinforced + description_info = "Use in your hand to build a window. Reinforced glass is much stronger against damage." + +/obj/item/stack/material/cyborg/glass/reinforced + description_info = "Use in your hand to build a window. Reinforced glass is much stronger against damage.
            \ + As a synthetic, you can gain more reinforced glass by recharging." + +/obj/item/stack/material/cyborg/steel + description_info = "Use in your hand to bring up the recipe menu. If you have enough sheets, click on something on the list to build it.
            \ + You can replenish your supply of metal as a synthetic by recharging." + +/obj/item/stack/material + description_info = "Use in your hand to bring up the recipe menu. If you have enough sheets, click on something on the list to build it." \ No newline at end of file diff --git a/code/modules/examine/descriptions/structures.dm b/code/modules/examine/descriptions/structures.dm new file mode 100644 index 00000000..858653b0 --- /dev/null +++ b/code/modules/examine/descriptions/structures.dm @@ -0,0 +1,21 @@ +/obj/structure/girder + description_info = "Use metal sheets on this to build a normal wall. Adding plasteel instead will make a reinforced wall.
            \ + A false wall can be made by using a crowbar on this girder, and then adding metal or plasteel.
            \ + You can dismantle the grider with a wrench." + +/obj/structure/girder/reinforced + description_info = "Add another sheet of plasteel to finish." + +/obj/structure/grille + description_info = "A powered and knotted wire underneath this will cause the grille to shock anyone not wearing insulated gloves.
            \ + Wirecutters will turn the grille into metal rods instantly. Grilles are made with metal rods." + +/obj/structure/lattice + description_info = "Add a metal floor tile to build a floor on top of the lattice.
            \ + Lattices can be made by applying metal rods to a space tile." + +/obj/structure/bed + description_info = "Click and drag yourself (or anyone) to this to buckle in. Click on this with an empty hand to undo the buckles.
            \ +
            \ + Anyone with restraints, such as handcuffs, will not be able to unbuckle themselves. They must use the Resist button, or verb, to break free of \ + the buckles, instead." \ No newline at end of file diff --git a/code/modules/examine/descriptions/turfs.dm b/code/modules/examine/descriptions/turfs.dm new file mode 100644 index 00000000..cccc43e0 --- /dev/null +++ b/code/modules/examine/descriptions/turfs.dm @@ -0,0 +1,3 @@ +/turf/simulated/wall + description_info = "You can deconstruct this by welding it, and then wrenching the girder.
            \ + You can build a wall by using metal sheets and making a girder, then adding more metal or plasteel." \ No newline at end of file diff --git a/code/modules/examine/descriptions/weapons.dm b/code/modules/examine/descriptions/weapons.dm new file mode 100644 index 00000000..9543157c --- /dev/null +++ b/code/modules/examine/descriptions/weapons.dm @@ -0,0 +1,91 @@ +/* + Note: This file is meant for actual weapons (guns, swords, etc), and not the stupid 'every obj is a weapon, except when it's not' thing. +*/ + +//****** +//*Guns* +//****** + +//This contains a lot of copypasta but I'm told it's better then a lot of New()s appending the var. +/obj/item/weapon/gun + description_info = "This is a gun. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \ + then click where you want to fire." + +/obj/item/weapon/gun/energy + description_info = "This is an energy weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \ + then click where you want to fire. Most energy weapons can fire through windows harmlessly. To recharge this weapon, use a weapon recharger." + +/obj/item/weapon/gun/energy/crossbow + description_info = "This is an energy weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \ + then click where you want to fire." + description_antag = "This is a stealthy weapon which fires poisoned bolts at your target. When it hits someone, they will suffer a stun effect, in \ + addition to toxins. The energy crossbow recharges itself slowly, and can be concealed in your pocket or bag." + +/obj/item/weapon/gun/energy/gun + description_info = "This is an energy weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \ + then click where you want to fire. Most energy weapons can fire through windows harmlessly. To switch between stun and lethal, click the weapon \ + in your hand. To recharge this weapon, use a weapon recharger." + +/obj/item/weapon/gun/energy/gun/taser + description_info = "This is an energy weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \ + then click where you want to fire. Most energy weapons can fire through windows harmlessly. To recharge this weapon, use a weapon recharger." + +/obj/item/weapon/gun/energy/gun/stunrevolver + description_info = "This is an energy weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \ + then click where you want to fire. Most energy weapons can fire through windows harmlessly. To recharge this weapon, use a weapon recharger." + +/obj/item/weapon/gun/energy/gun/nuclear + description_info = "This is an energy weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \ + then click where you want to fire. Most energy weapons can fire through windows harmlessly. To switch between stun and lethal, click the weapon \ + in your hand. Unlike most weapons, this weapon recharges itself." + +/obj/item/weapon/gun/energy/captain + description_info = "This is an energy weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \ + then click where you want to fire. Most energy weapons can fire through windows harmlessly. Unlike most weapons, this weapon recharges itself." + +/obj/item/weapon/gun/energy/sniperrifle + description_info = "This is an energy weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \ + then click where you want to fire. Most energy weapons can fire through windows harmlessly. To recharge this weapon, use a weapon recharger. \ + To use the scope, use the appropriate verb in the object tab." + +/obj/item/weapon/gun/projectile + description_info = "This is a ballistic weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \ + then click where you want to fire. To reload, click the weapon in your hand to unload (if needed), then add the appropiate ammo. The description \ + will tell you what caliber you need." + +/obj/item/weapon/gun/energy/chameleon + description_info = null //The chameleon gun adopts the description_info of the weapon it is impersonating as, to make meta-ing harder. + description_antag = "This gun is actually a hologram projector that can alter its appearance to mimick other weapons. To change the appearance, use \ + the appropriate verb in the chameleon items tab. Any beams or projectiles fired from this gun are actually holograms and useless for actual combat. \ + Projecting these holograms over distance uses a little bit of charge." + +/obj/item/weapon/gun/energy/chameleon/change(picked in gun_choices) //Making the gun change its help text to match the weapon's help text. + ..(picked) + var/obj/O = gun_choices[picked] + description_info = initial(O.description_info) + +/obj/item/weapon/gun/projectile/shotgun/pump + description_info = "This is a ballistic weapon. To fire the weapon, ensure you have your gun safety off, \ + then click where you want to fire. After firing, you will need to pump/bolt the gun, by clicking on the gun in your hand." + +/obj/item/weapon/gun/projectile/heavysniper + description_info = "This is a ballistic weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \ + then click where you want to fire. The gun's chamber can be opened or closed by using it in your hand. To reload, open the chamber, add a new bullet \ + then close it. To use the scope, use the appropriate verb in the object tab." + +//******* +//*Melee* +//******* + +/obj/item/weapon/melee/baton + description_info = "The baton needs to be turned on to apply the stunning effect. Use it in your hand to toggle it on or off. If your intent is \ + set to 'harm', you will inflict damage when using it, regardless if it is on or not. Each stun reduces the baton's charge, which can be replenished by \ + putting it inside a weapon recharger." + +/obj/item/weapon/melee/energy/sword + description_antag = "The energy sword is a very strong melee weapon, capable of severing limbs easily, if they are targeted. It can also has a chance \ + to block projectiles and melee attacks while it is on and being held. The sword can be toggled on or off by using it in your hand. While it is off, \ + it can be concealed in your pocket or bag." + +/obj/item/weapon/melee/cultblade + description_antag = "This sword is a powerful weapon, capable of severing limbs easily, if they are targeted. Nonbelivers are unable to use this weapon." diff --git a/code/modules/examine/examine.dm b/code/modules/examine/examine.dm new file mode 100644 index 00000000..7136c6d3 --- /dev/null +++ b/code/modules/examine/examine.dm @@ -0,0 +1,72 @@ +/* This code is responsible for the examine tab. When someone examines something, it copies the examined object's description_info, + description_fluff, and description_antag, and shows it in a new tab. + + In this file, some atom and mob stuff is defined here. It is defined here instead of in the normal files, to keep the whole system self-contained. + This means that this file can be unchecked, along with the other examine files, and can be removed entirely with no effort. +*/ + + +/atom/ + var/description_info = null //Helpful blue text. + var/description_fluff = null //Green text about the atom's fluff, if any exists. + var/description_antag = null //Malicious red text, for the antags. + +//Override these if you need special behaviour for a specific type. +/atom/proc/get_description_info() + if(description_info) + return description_info + return + +/atom/proc/get_description_fluff() + if(description_fluff) + return description_fluff + return + +/atom/proc/get_description_antag() + if(description_antag) + return description_antag + return + +/mob/living/get_description_fluff() + if(flavor_text) //Get flavor text for the green text. + return flavor_text + else //No flavor text? Try for hardcoded fluff instead. + return ..() + +/mob/living/carbon/human/get_description_fluff() + return print_flavor_text(0) + +/* The examine panel itself */ + +/client/var/description_holders[0] + +/client/proc/update_description_holders(atom/A, update_antag_info=0) + description_holders["info"] = A.get_description_info() + description_holders["fluff"] = A.get_description_fluff() + description_holders["antag"] = (update_antag_info)? A.get_description_antag() : "" + + description_holders["name"] = "[A.name]" + description_holders["icon"] = "\icon[A]" + description_holders["desc"] = A.desc +/* +/mob/Stat() + . = ..() + if(client && statpanel("Examine")) + stat(null,"[client.description_holders["icon"]] [client.description_holders["name"]]") //The name, written in big letters. + stat(null,"[client.description_holders["desc"]]") //the default examine text. + if(client.description_holders["info"]) + stat(null,"[client.description_holders["info"]]") //Blue, informative text. + if(client.description_holders["fluff"]) + stat(null,"[client.description_holders["fluff"]]") //Yellow, fluff-related text. + if(client.description_holders["antag"]) + stat(null,"[client.description_holders["antag"]]") //Red, malicious antag-related text +*/ + +//override examinate verb to update description holders when things are examined +/mob/examinate(atom/A as mob|obj|turf in view()) + if(..()) + return 1 + + var/is_antag = ((mind && mind.special_role) || isghost(src)) //ghosts don't have minds + if(client) + client.update_description_holders(A, is_antag) diff --git a/code/modules/examine/stat_icons.dm b/code/modules/examine/stat_icons.dm new file mode 100644 index 00000000..77d97fe0 --- /dev/null +++ b/code/modules/examine/stat_icons.dm @@ -0,0 +1,10 @@ +//Some global icons for the examine tab to use to display some item properties. +var/global/list/description_icons = list( + "melee_armor" = image(icon='icons/mob/screen1_stats.dmi',icon_state="melee_protection"), + "bullet_armor" = image(icon='icons/mob/screen1_stats.dmi',icon_state="bullet_protection"), + "laser_armor" = image(icon='icons/mob/screen1_stats.dmi',icon_state="laser_protection"), + "energy_armor" = image(icon='icons/mob/screen1_stats.dmi',icon_state="energy_protection"), + "bomb_armor" = image(icon='icons/mob/screen1_stats.dmi',icon_state="bomb_protection"), + "radiation_armor" = image(icon='icons/mob/screen1_stats.dmi',icon_state="radiation_protection"), + "biohazard_armor" = image(icon='icons/mob/screen1_stats.dmi',icon_state="biohazard_protection") + ) \ No newline at end of file diff --git a/code/modules/ext_scripts/irc.dm b/code/modules/ext_scripts/irc.dm new file mode 100644 index 00000000..cf80884b --- /dev/null +++ b/code/modules/ext_scripts/irc.dm @@ -0,0 +1,47 @@ +/proc/send2irc(var/channel, var/msg) + export2irc(list(type="msg", mesg=msg, chan=channel, pwd=config.comms_password)) + +/proc/export2irc(params) + if(config.use_irc_bot && config.irc_bot_host) + spawn(-1) // spawn here prevents hanging in the case that the bot isn't reachable + world.Export("http://[config.irc_bot_host]:45678?[list2params(params)]") + +/proc/runtimes2irc(runtimes, revision) + export2irc(list(pwd=config.comms_password, type="runtime", runtimes=runtimes, revision=revision)) + +/proc/send2mainirc(var/msg) + if(config.main_irc) + send2irc(config.main_irc, msg) + return + +/proc/send2adminirc(var/msg) + if(config.admin_irc) + send2irc(config.admin_irc, msg) + return + +/proc/adminmsg2adminirc(client/source, client/target, msg) + if(config.admin_irc) + var/list/params[0] + + params["pwd"] = config.comms_password + params["chan"] = config.admin_irc + params["msg"] = msg + params["src_key"] = source.key + params["src_char"] = source.mob.real_name || source.mob.name + if(!target) + params["type"] = "adminhelp" + else if(istext(target)) + params["type"] = "ircpm" + params["target"] = target + params["rank"] = source.holder ? source.holder.rank : "Player" + else + params["type"] = "adminpm" + params["trg_key"] = target.key + params["trg_char"] = target.mob.real_name || target.mob.name + + export2irc(params) + +/hook/startup/proc/ircNotify() + send2mainirc("Server starting up on byond://[config.serverurl ? config.serverurl : (config.server ? config.server : "[world.address]:[world.port]")]") + return 1 + diff --git a/code/modules/fire_lighting/fire_sources.dm b/code/modules/fire_lighting/fire_sources.dm new file mode 100644 index 00000000..be0e1e45 --- /dev/null +++ b/code/modules/fire_lighting/fire_sources.dm @@ -0,0 +1,314 @@ +// This is not very good code and could use cleanup and optimization, but +// I am very tired and will probably forget in the morning. C'est la vie. ~Z + +#define FIRE_LIT 1 +#define FIRE_DEAD -1 +#define FIRE_OUT 0 + +var/list/fire_cache = list() +var/list/fire_sounds = list( + 'sound/ambience/comfyfire.ogg', + 'sound/ambience/comfyfire1.ogg', + 'sound/ambience/comfyfire2.ogg', + 'sound/ambience/comfyfire3.ogg' + ) + +/obj/structure/fire_source + name = "campfire" + desc = "Did anyone bring any marshmallows?" + icon = 'icons/obj/fire.dmi' + icon_state = "campfire" + anchored = 1 + density = 0 + + var/open_flame = 1 + var/datum/effect/effect/system/steam_spread/steam // Used when being quenched. + + var/light_range_high = 8 + var/light_range_mid = 6 + var/light_range_low = 4 + + var/light_power_high = 8 + var/light_power_mid = 5 + var/light_power_low = 3 + + var/light_colour_high = "#FFDD55" + var/light_colour_mid = "#FF9900" + var/light_colour_low = "#FF0000" + + var/output_temperature = T0C+50 // The amount that the fire will try to heat up the air. + var/last_burn_tick = 0 // When did we last burn? + var/burn_time = 40 // How long between burn ticks? + var/fuel = 0 // How much fuel is left? + var/lit = 0 + +/obj/structure/fire_source/New() + ..() + if(lit == FIRE_LIT && fuel > 0) + light() + update_icon() + + steam = new(name) + steam.attach(get_turf(src)) + steam.set_up(3, 0, get_turf(src)) + +/obj/structure/fire_source/hearth + name = "hearth fire" + desc = "So cheery!" + burn_time = 80 + density = 1 + +/obj/structure/fire_source/hearth/update_icon() + ..() + if(lit == FIRE_LIT) + density = 1 + +/obj/structure/fire_source/stove + name = "stove" + desc = "Just the thing to warm your hands by." + icon_state = "stove" + burn_time = 80 + light_colour_high = "#FFDD55" + light_colour_mid = "#FF6600" + light_colour_low = "#FF0000" + open_flame = 0 + density = 1 + +/obj/structure/fire_source/burningbarrel + name = "barrel" + desc = "Just the thing to warm your hands by." + icon_state = "barrel" + burn_time = 80 + light_colour_high = "#FFDD55" + light_colour_mid = "#FF6600" + light_colour_low = "#FF0000" + open_flame = 0 + density = 1 + +/obj/structure/fire_source/burningbarrel/lit + fuel = 40 // How much fuel is left? + lit = 1 + +/obj/structure/fire_source/fireplace + name = "fireplace" + desc = "So cheery!" + icon_state = "fireplace" + burn_time = 60 + open_flame = 0 + density = 1 + +/obj/structure/fire_source/ex_act() + die() + +/obj/structure/fire_source/proc/die() + if(lit != FIRE_LIT) + return + lit = FIRE_DEAD + playsound(get_turf(src), 'sound/misc/firehiss.ogg', 75, 1) + visible_message("\The [src] goes out!") + GLOB.processing_objects -= src + update_icon() + return + +/obj/structure/fire_source/attack_hand(var/mob/user) + if(!contents.len) + return ..() + + var/obj/item/removing = pick(contents) + removing.forceMove(get_turf(user)) + user.put_in_hands(removing) + if(lit == FIRE_LIT) + visible_message("\The [user] hastily fishes \the [removing] out of \the [src]!") + burn(user) + else + visible_message("\The [user] removes \the [removing] from \the [src].") + +/obj/structure/fire_source/attackby(var/obj/item/thing, var/mob/user) + + // A spot of the old ultraviolence. + if(istype(thing, /obj/item/grab) && open_flame) + var/obj/item/grab/G = thing + if(G.affecting) + G.affecting.forceMove(get_turf(src)) + G.affecting.Weaken(5) + visible_message("\The [user] hurls \the [G.affecting] onto \the [src]!") + burn(G.affecting) + user.unEquip(G) + qdel(G) + return + + if(istype(thing, /obj/item/weapon/reagent_containers)) + var/obj/item/weapon/reagent_containers/RG = thing + if(RG.is_open_container() && RG.reagents && RG.reagents.total_volume) + user.visible_message("\The [user] pours the contents of \the [thing] into \the [src]!") + for(var/datum/reagent/R in RG.reagents.reagent_list) + + // Hardcode this for now. + if(R.name == "Water") + steam.start() // HISSSSSS! + + RG.reagents.clear_reagents() + RG.update_icon() + if(fuel < 0) + fuel = 0 + if(fuel == 0) + die() + return + + if(isflamesource(thing) && lit != FIRE_LIT) + visible_message("\The [user] attempts to light \the [src] with \the [thing]...") + light() + return + + if(accept_fuel(thing, user)) + return + + return ..() + +/obj/structure/fire_source/proc/light() + if(lit == FIRE_LIT) + return + if((!fuel || fuel <= 0) && !process_fuel()) + return + lit = FIRE_LIT + visible_message("\The [src] catches alight!") + GLOB.processing_objects |= src + process() + return + +/obj/structure/fire_source/proc/process_fuel() + + if(!contents.len) + return 0 + + for(var/obj/item/thing in contents) + + if(istype(thing, /obj/item/weapon/paper) || \ + istype(thing, /obj/item/weapon/storage/fancy/egg_box ) || \ + istype(thing, /obj/item/clothing/suit/cardborg) || \ + istype(thing, /obj/item/clothing/head/cardborg ) || \ + istype(thing, /obj/item/pizzabox ) || \ + istype(thing, /obj/item/trash)) + fuel += rand(3,9) + qdel(thing) + return 1 + + if(istype(thing, /obj/item/weapon/ore/coal)) + fuel += rand(25,50) + qdel(thing) + return 1 + + if(istype(thing, /obj/item/stack/material)) + var/obj/item/stack/material/wooden_thing = thing + if(wooden_thing.material.ignition_point <= (T0C+288)) // Ignition point of wood, materials.dm + fuel += rand(3,9) + wooden_thing.use(1) + return 1 + + if(istype(thing, /obj/item/weapon/material)) + var/obj/item/weapon/material/wooden_thing = thing + if(wooden_thing.material.ignition_point <= (T0C+288)) + fuel += rand(5,12) + qdel(wooden_thing) + return 1 + return 0 + +/obj/structure/fire_source/proc/accept_fuel(var/obj/item/thing, var/mob/user) + var/accepted_fuel + + if(istype(thing, /obj/item/weapon/ore/coal) || \ + istype(thing, /obj/item/weapon/paper) || \ + istype(thing, /obj/item/weapon/storage/fancy/egg_box ) || \ + istype(thing, /obj/item/clothing/suit/cardborg) || \ + istype(thing, /obj/item/clothing/head/cardborg ) || \ + istype(thing, /obj/item/pizzabox ) || \ + istype(thing, /obj/item/trash)) + accepted_fuel = 1 + else if(istype(thing, /obj/item/stack/material)) + var/obj/item/stack/material/wooden_thing = thing + if(wooden_thing.material.ignition_point <= (T0C+288)) + accepted_fuel = 1 + else if(istype(thing, /obj/item/weapon/material)) + var/obj/item/weapon/material/wooden_thing = thing + if(wooden_thing.material.ignition_point <= (T0C+288)) + accepted_fuel =1 + if(accepted_fuel) + if(lit == FIRE_LIT) + user.visible_message("\The [user] feeds \the [thing] into \the [src].") + else + user.visible_message("\The [user] places \the [thing] into \the [src].") + user.unEquip(thing) + thing.forceMove(src) + update_icon() + return 1 + return 0 + +/obj/structure/fire_source/Destroy() + GLOB.processing_objects -= src + return ..() + +/obj/structure/fire_source/process() + if(world.time > (last_burn_tick + burn_time)) + last_burn_tick = world.time + else + return + fuel-- + if(fuel <= 0 && !process_fuel()) + die() + return + // Burn anyone sitting in the fire. + if(lit == FIRE_LIT) + var/turf/T = get_turf(src) + if(istype(T)) + var/datum/gas_mixture/GM = T.return_air() + for(var/mob/living/M in T.contents) + burn(M) + // Copied from space heaters. Heat up the air on our tile, heat will percolate out. + if(GM && abs(GM.temperature - output_temperature) > 0.1) + var/transfer_moles = 0.35 * GM.total_moles + var/datum/gas_mixture/removed = GM.remove(transfer_moles) + if(removed) + var/heat_transfer = removed.get_thermal_energy_change(output_temperature) + if(heat_transfer > 0) removed.add_thermal_energy(heat_transfer) + GM.merge(removed) + + update_icon() + +/obj/structure/fire_source/update_icon() + overlays.Cut() + if((fuel || contents.len) && (lit != FIRE_DEAD)) + var/cache_key = "[name]-[icon_state]_full" + if(!fire_cache[cache_key]) + fire_cache[cache_key] = image(icon, "[icon_state]_full") + overlays += fire_cache[cache_key] + var/need_overlay + switch(lit) + if(FIRE_LIT) + if((fuel > 10) || contents.len) + need_overlay = "[icon_state]_lit" + set_light(light_range_high, light_power_high, light_colour_high) + else if(fuel <= 5) + need_overlay = "[icon_state]_lit_dying" + set_light(light_range_mid, light_power_low, light_colour_low) + else if(fuel <= 10) + need_overlay = "[icon_state]_lit_low" + set_light(light_range_low, light_power_mid, light_colour_mid) + if(FIRE_DEAD) + var/cache_key = "[name]-[icon_state]_burnt" + if(!fire_cache[cache_key]) + fire_cache[cache_key] = image(icon, "[icon_state]_burnt") + overlays += fire_cache[cache_key] + set_light(0) + else + set_light(0) + + if(need_overlay) + var/cache_key = "[name]-[need_overlay]" + if(!fire_cache[cache_key]) + fire_cache[cache_key] = image(icon, need_overlay) + overlays += fire_cache[cache_key] + +/obj/structure/fire_source/proc/burn(var/mob/living/victim) + to_chat(victim, "You are burned by \the [src]!") + victim.IgniteMob() + victim.apply_damage(rand(10,20), BURN) diff --git a/code/modules/fire_lighting/torches.dm b/code/modules/fire_lighting/torches.dm new file mode 100644 index 00000000..22f9a0c4 --- /dev/null +++ b/code/modules/fire_lighting/torches.dm @@ -0,0 +1,171 @@ +//Torches +/obj/item/torch + icon = 'icons/obj/torches.dmi' + icon_state = "torch0" + item_state = "torch0" + name = "Torch" + desc = "In radiance may we find victory." + var/lit = FALSE + var/self_lighting = 0 + +/obj/item/torch/self_lit + name = "Self-igniting Torch" + desc = "In radiance may we find victory. This torch provides its own." + self_lighting = 1 + +/obj/item/torch/Initialize() + . = ..() + update_icon() + +/obj/item/torch/update_icon() + ..() + overlays = overlays.Cut() + if(lit) + icon_state = "torch1" + item_state = "torch1" + set_light(3, 5, "#E38F46") + else + icon_state = "torch0" + item_state = "torch0" + set_light(0,0) + if(self_lighting == 1) + overlays += overlay_image(icon, "lighter") + update_held_icon() + +/obj/item/torch/Process() + + ..() +/* //This used to be broken, it's instead being commented out for not really needing to be used at the moment. Warfare doesn't simulate atmos. + var/datum/gas_mixture/air = loc.return_air() + var/oxy_mole = air.get_gas("oxygen") + var/total_mole = air.get_total_moles() + var/total_pressure = air.return_pressure() + if(oxy_mole && total_mole) + var/o2_pressure = (oxy_mole /total_mole )*total_pressure + if(o2_pressure <= HAZARD_LOW_PRESSURE) + snuff() + + //else if(!oxy_mole) + // snuff() +*/ + if(prob(1)) //Needs playtesting. This seems a little high. + visible_message("A rush of wind puts out the torch.") + snuff() + + +/obj/item/torch/proc/light(var/mob/user, var/manually_lit = FALSE)//This doesn't seem to update the icon appropiately, not idea why. + lit = TRUE + if(manually_lit && self_lighting == 1) + user.visible_message("\The [user] rips the lighting sheath off their [src].") + update_icon() + START_PROCESSING(SSprocessing, src) + playsound(src, 'sound/items/torch_light.ogg', 50, 0, -1) + + +/obj/item/torch/proc/snuff() + lit = FALSE + update_icon() + STOP_PROCESSING(SSprocessing, src) + playsound(src, 'sound/items/torch_snuff.ogg', 50, 0, -1) + + +/obj/item/torch/attack_self(mob/user) + ..() + if(self_lighting == 1) + light(user, TRUE) + self_lighting = -1 + return + if(lit) + snuff() + +/obj/item/torch/attackby(obj/item/W, mob/user) + ..() + if(isflamesource(W)) + light() + +/obj/structure/torchwall + name = "torch fixture" + icon = 'icons/obj/lighting.dmi' + icon_state = "torchwall0" + desc = "A torch fixture." + anchored = TRUE + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + + var/obj/item/torch/lighttorch + +/obj/structure/torchwall/New() + if(prob(98)) + lighttorch = new(src) + if(prob(75)) + lighttorch.lit = TRUE + update_icon() + + +/obj/structure/torchwall/Destroy() + QDEL_NULL(lighttorch) + . = ..() + + +/obj/structure/torchwall/update_icon() + ..() + if(lighttorch) + if(lighttorch.lit) + icon_state = "torchwall1" + set_light(6, 3,"#E38F46") + + else + icon_state = "torchwall0" + set_light(0,0) + else + icon_state = "torchwall" + set_light(0,0) + + +/obj/structure/torchwall/proc/insert_torch(obj/item/torch/T) + T.forceMove(src) + lighttorch = T + update_icon() + playsound(src, 'sound/items/torch_fixture1.ogg', 50, 0, -1) + + +/obj/structure/torchwall/attackby(obj/item/W, mob/user) + // attempt to insert torch + if(lighttorch && !lighttorch.lit) + if(isflamesource(W)) + lighttorch.light() + update_icon() + return + + if(istype(W, /obj/item/torch)) + if(lighttorch && lighttorch.lit) + var/obj/item/torch/T = W + if(!T.lit) + T.light() + update_icon() + return + + user.drop_item() + insert_torch(W) + src.add_fingerprint(user) + + update_icon() + +/obj/structure/torchwall/proc/remove_torch() + . = lighttorch + lighttorch.dropInto(loc) + lighttorch.update_icon() + lighttorch = null + update_icon() + playsound(src, 'sound/items/torch_fixture0.ogg', 50, 0, -1) + +// attack with hand - remove torch +/obj/structure/torchwall/attack_hand(mob/user) + + add_fingerprint(user) + + if(!lighttorch) + to_chat(user, "There is no torch here.") + return + // create a torch item and put it in the user's hand + user.put_in_active_hand(remove_torch()) //puts it in our active hand \ No newline at end of file diff --git a/code/modules/flufftext/Dreaming.dm b/code/modules/flufftext/Dreaming.dm new file mode 100644 index 00000000..5d5baf57 --- /dev/null +++ b/code/modules/flufftext/Dreaming.dm @@ -0,0 +1,35 @@ + +var/list/dreams = list( + "a dogtag","a bottle","a familiar face","a crewmember","a toolbox","a soldier","the captain", + "voices from all around","none of this is real","a doctor","an ally","darkness", + "light","a catastrophe","a loved one","a gun","warmth","freezing","the sun", + "a hat","a ruined fortress","a planet","air","the medical bay","blinking lights", + "a blue light","an abandoned laboratory","NanoTrasen", "pirates", "mercenaries","blood","healing","power","respect", + "riches","space","a crash","happiness","pride","a fall","water","flames","ice","melons","flying","the eggs","money", + "a station engineer","the janitor","the atmospheric technician", + "a cargo technician","the botanist","a shaft miner","the psychologist","the chemist", + "the virologist","the roboticist","a chef","the bartender","a chaplain","a librarian","a mouse", + "a beach","a smokey room","a voice","the cold","a mouse","an operating table","the rain", + "an unathi","a tajaran","the ai core","a beaker of strange liquid","the supermatter", "a creature built completely of stolen flesh", + "a GAS", "a being made of light", "the commanding officer", "an old friend", "the tower", "the man with no face", "a field of flowers", "an old home", "the merc", + "a surgery table", "a needle", "a blade", "an ocean", "right behind you", "standing above you", "someone near by", "a place forgotten", + ) + +mob/living/carbon/proc/dream() + dreaming = 1 + + spawn(0) + for(var/i = rand(1,4),i > 0, i--) + to_chat(src, "... [pick(GLOB.lone_thoughts)] ...") + sleep(rand(40,70)) + if(paralysis <= 0) + dreaming = 0 + return 0 + dreaming = 0 + return 1 + +mob/living/carbon/proc/handle_dreams() + if(client && !dreaming && prob(5)) + dream() + +mob/living/carbon/var/dreaming = 0 diff --git a/code/modules/flufftext/TextFilters.dm b/code/modules/flufftext/TextFilters.dm new file mode 100644 index 00000000..00ade03f --- /dev/null +++ b/code/modules/flufftext/TextFilters.dm @@ -0,0 +1,172 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +proc/Intoxicated(phrase) + phrase = html_decode(phrase) + var/leng=length(phrase) + var/counter=length(phrase) + var/newphrase="" + var/newletter="" + while(counter>=1) + newletter=copytext(phrase,(leng-counter)+1,(leng-counter)+2) + if(rand(1,3)==3) + if(lowertext(newletter)=="o") newletter="u" + if(lowertext(newletter)=="s") newletter="ch" + if(lowertext(newletter)=="a") newletter="ah" + if(lowertext(newletter)=="c") newletter="k" + switch(rand(1,15)) + if(1,3,5,8) newletter="[lowertext(newletter)]" + if(2,4,6,15) newletter="[uppertext(newletter)]" + if(7) newletter+="'" + if(9,10) newletter="[newletter]" + if(11,12) newletter="[newletter]" + if(13) newletter="[newletter]" + newphrase+="[newletter]";counter-=1 + return newphrase + +proc/NewStutter(phrase,stunned) + phrase = html_decode(phrase) + + var/list/split_phrase = splittext(phrase," ") //Split it up into words. + + var/list/unstuttered_words = split_phrase.Copy() + var/i = rand(1,3) + if(stunned) i = split_phrase.len + for(,i > 0,i--) //Pick a few words to stutter on. + + if (!unstuttered_words.len) + break + var/word = pick(unstuttered_words) + unstuttered_words -= word //Remove from unstuttered words so we don't stutter it again. + var/index = split_phrase.Find(word) //Find the word in the split phrase so we can replace it. + + //Search for dipthongs (two letters that make one sound.) + var/first_sound = copytext(word,1,3) + var/first_letter = copytext(word,1,2) + if(lowertext(first_sound) in list("ch","th","sh")) + first_letter = first_sound + + //Repeat the first letter to create a stutter. + var/rnum = rand(1,3) + switch(rnum) + if(1) + word = "[first_letter]-[word]" + if(2) + word = "[first_letter]-[first_letter]-[word]" + if(3) + word = "[first_letter]-[word]" + + split_phrase[index] = word + + return sanitize(jointext(split_phrase," ")) + +proc/Stagger(mob/M,d) //Technically not a filter, but it relates to drunkenness. + step(M, pick(d,turn(d,90),turn(d,-90))) + +proc/Ellipsis(original_msg, chance = 50) + if(chance <= 0) return "..." + if(chance >= 100) return original_msg + + var/list/words = splittext(original_msg," ") + var/list/new_words = list() + + var/new_msg = "" + + for(var/w in words) + if(prob(chance)) + new_words += "..." + else + new_words += w + + new_msg = jointext(new_words," ") + + return new_msg +/* +RadioChat Filter. +args: +message - returns a distorted version of this +distortion_chance - the chance of a filter being applied to each character. +distortion_speed - multiplier for the chance increase. +distortion - starting distortion. +english_only - whether to use traditional english letters only (for use in NanoUI) +*/ +proc/RadioChat(mob/living/user, message, distortion_chance = 60, distortion_speed = 1, distortion = 1, english_only = 0) + var/datum/language/language + if(user) + language = user.get_default_language() + message = html_decode(message) + var/new_message = "" + var/input_size = length(message) + var/lentext = 0 + if(input_size < 20) // Short messages get distorted too. Bit hacksy. + distortion += (20-input_size)/2 + while(lentext <= input_size) + var/newletter=copytext(message, lentext, lentext+1) + if(!prob(distortion_chance)) + new_message += newletter + lentext += 1 + continue + if(newletter != " ") + if(prob(0.08 * distortion)) // Major cutout + newletter = "*zzzt*" + lentext += rand(1, (length(message) - lentext)) // Skip some characters + distortion += 1 * distortion_speed + else if(prob(0.8 * distortion)) // Minor cut out + if(prob(25)) + newletter = ".." + else if(prob(25)) + newletter = " " + else + newletter = "" + distortion += 0.25 * distortion_speed + else if(prob(2 * distortion)) // Mishearing + if(language && language.syllables && prob(50)) + newletter = pick(language.syllables) + else + newletter = pick("a","e","i","o","u") + distortion += 0.25 * distortion_speed + else if(prob(1.5 * distortion)) // Mishearing + if(language && prob(50)) + if(language.syllables) + newletter = pick (language.syllables) + else + newletter = "*" + else + if(english_only) + newletter += "*" + else + newletter = pick("�", "�", "%", "�", "�") + distortion += 0.5 * distortion_speed + else if(prob(0.75 * distortion)) // Incomprehensible + newletter = pick("<", ">", "!", "$", "%", "^", "&", "*", "~", "#") + distortion += 0.75 * distortion_speed + else if(prob(0.05 * distortion)) // Total cut out + if(!english_only) + newletter = "�w��b�%> -BZZT-" + else + newletter = "srgt%$hjc< -BZZT-" + new_message += newletter + break + else if(prob(2.5 * distortion)) // Sound distortion. Still recognisable, mostly. + switch(lowertext(newletter)) + if("s") + newletter = "$" + if("e") + newletter = "�" + if("w") + newletter = "�" + if("y") + newletter = "�" + if("x") + newletter = "�" + if("u") + newletter = "�" + else + if(prob(0.2 * distortion)) + newletter = " *crackle* " + distortion += 0.25 * distortion_speed + if(prob(20)) + capitalize(newletter) + new_message += newletter + lentext += 1 + return new_message + diff --git a/code/modules/food/recipes_microwave.dm b/code/modules/food/recipes_microwave.dm new file mode 100644 index 00000000..6718fd90 --- /dev/null +++ b/code/modules/food/recipes_microwave.dm @@ -0,0 +1,1037 @@ + +// see code/datums/recipe.dm + + +/* No telebacon. just no... +/datum/recipe/telebacon + items = list( + /obj/item/weapon/reagent_containers/food/snacks/meat, + /obj/item/device/assembly/signaler + ) + result = /obj/item/weapon/reagent_containers/food/snacks/telebacon + +I said no! +/datum/recipe/syntitelebacon + items = list( + /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, + /obj/item/device/assembly/signaler + ) + result = /obj/item/weapon/reagent_containers/food/snacks/telebacon +*/ + +/datum/recipe/friedegg + reagents = list(/datum/reagent/sodiumchloride = 1, /datum/reagent/blackpepper = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/egg + ) + result = /obj/item/weapon/reagent_containers/food/snacks/friedegg + +/datum/recipe/boiledegg + reagents = list(/datum/reagent/water = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/egg + ) + result = /obj/item/weapon/reagent_containers/food/snacks/boiledegg + +/datum/recipe/dionaroast + fruit = list("apple" = 1) + reagents = list(/datum/reagent/acid/polyacid = 5) //It dissolves the carapace. Still poisonous, though. + items = list(/obj/item/weapon/holder/diona) + result = /obj/item/weapon/reagent_containers/food/snacks/dionaroast + +/datum/recipe/classichotdog + items = list( + /obj/item/weapon/reagent_containers/food/snacks/bun, + /obj/item/weapon/holder/corgi + ) + result = /obj/item/weapon/reagent_containers/food/snacks/classichotdog + +/datum/recipe/jellydonut + reagents = list(/datum/reagent/drink/juice/berry = 5, /datum/reagent/sugar = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough + ) + result = /obj/item/weapon/reagent_containers/food/snacks/donut/jelly + +/datum/recipe/jellydonut/slime + reagents = list(/datum/reagent/slimejelly = 5, /datum/reagent/sugar = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough + ) + result = /obj/item/weapon/reagent_containers/food/snacks/donut/slimejelly + +/datum/recipe/jellydonut/cherry + reagents = list(/datum/reagent/nutriment/cherryjelly = 5, /datum/reagent/sugar = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough + ) + result = /obj/item/weapon/reagent_containers/food/snacks/donut/cherryjelly + +/datum/recipe/donut + reagents = list(/datum/reagent/sugar = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough + ) + result = /obj/item/weapon/reagent_containers/food/snacks/donut/normal + +/datum/recipe/plainburger + items = list( + /obj/item/weapon/reagent_containers/food/snacks/bun, + /obj/item/weapon/reagent_containers/food/snacks/meat + ) + result = /obj/item/weapon/reagent_containers/food/snacks/plainburger + +/datum/recipe/brainburger + items = list( + /obj/item/weapon/reagent_containers/food/snacks/bun, + /obj/item/organ/internal/brain + ) + result = /obj/item/weapon/reagent_containers/food/snacks/brainburger + +/datum/recipe/roburger + items = list( + /obj/item/weapon/reagent_containers/food/snacks/bun, + /obj/item/robot_parts/head + ) + result = /obj/item/weapon/reagent_containers/food/snacks/roburger + +/datum/recipe/xenoburger + items = list( + /obj/item/weapon/reagent_containers/food/snacks/bun, + /obj/item/weapon/reagent_containers/food/snacks/xenomeat + ) + result = /obj/item/weapon/reagent_containers/food/snacks/xenoburger + +/datum/recipe/fishburger + items = list( + /obj/item/weapon/reagent_containers/food/snacks/bun, + /obj/item/weapon/reagent_containers/food/snacks/carpmeat + ) + result = /obj/item/weapon/reagent_containers/food/snacks/fishburger + +/datum/recipe/tofuburger + items = list( + /obj/item/weapon/reagent_containers/food/snacks/bun, + /obj/item/weapon/reagent_containers/food/snacks/tofu + ) + result = /obj/item/weapon/reagent_containers/food/snacks/tofuburger + +/datum/recipe/ghostburger + items = list( + /obj/item/weapon/reagent_containers/food/snacks/bun, + /obj/item/weapon/ectoplasm //where do you even find this stuff + ) + result = /obj/item/weapon/reagent_containers/food/snacks/ghostburger + +/datum/recipe/clownburger + items = list( + /obj/item/weapon/reagent_containers/food/snacks/bun, + /obj/item/clothing/mask/gas/clown_hat + ) + result = /obj/item/weapon/reagent_containers/food/snacks/clownburger + +/datum/recipe/mimeburger + items = list( + /obj/item/weapon/reagent_containers/food/snacks/bun, + /obj/item/clothing/head/beret + ) + result = /obj/item/weapon/reagent_containers/food/snacks/mimeburger + +/datum/recipe/bunbun + items = list( + /obj/item/weapon/reagent_containers/food/snacks/bun, + /obj/item/weapon/reagent_containers/food/snacks/bun + ) + result = /obj/item/weapon/reagent_containers/food/snacks/bunbun + +/datum/recipe/hotdog + items = list( + /obj/item/weapon/reagent_containers/food/snacks/bun, + /obj/item/weapon/reagent_containers/food/snacks/sausage + ) + result = /obj/item/weapon/reagent_containers/food/snacks/hotdog + +/datum/recipe/waffles + reagents = list(/datum/reagent/sugar = 10) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough + ) + result = /obj/item/weapon/reagent_containers/food/snacks/waffles + +/datum/recipe/pancakes + fruit = list("blueberries" = 2) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough + ) + result = /obj/item/weapon/reagent_containers/food/snacks/pancakes + +/datum/recipe/donkpocket + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/meatball + ) + result = /obj/item/weapon/reagent_containers/food/snacks/donkpocket //SPECIAL + proc/warm_up(var/obj/item/weapon/reagent_containers/food/snacks/donkpocket/being_cooked) + being_cooked.heat() + make_food(var/obj/container as obj) + var/obj/item/weapon/reagent_containers/food/snacks/donkpocket/being_cooked = ..(container) + warm_up(being_cooked) + return being_cooked + +/datum/recipe/donkpocket/warm + reagents = list() //This is necessary since this is a child object of the above recipe and we don't want donk pockets to need flour + items = list( + /obj/item/weapon/reagent_containers/food/snacks/donkpocket + ) + result = /obj/item/weapon/reagent_containers/food/snacks/donkpocket //SPECIAL + make_food(var/obj/container as obj) + var/obj/item/weapon/reagent_containers/food/snacks/donkpocket/being_cooked = locate() in container + if(being_cooked && !being_cooked.warm) + warm_up(being_cooked) + return being_cooked + +/datum/recipe/meatbread + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/meat, + /obj/item/weapon/reagent_containers/food/snacks/meat, + /obj/item/weapon/reagent_containers/food/snacks/meat, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/meatbread + +/datum/recipe/syntibread + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, + /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, + /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/meatbread + +/datum/recipe/xenomeatbread + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/xenomeat, + /obj/item/weapon/reagent_containers/food/snacks/xenomeat, + /obj/item/weapon/reagent_containers/food/snacks/xenomeat, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/xenomeatbread + +/datum/recipe/bananabread + fruit = list(/datum/reagent/drink/juice/banana = 1) + reagents = list(/datum/reagent/drink/milk = 5, /datum/reagent/sugar = 15) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/bananabread + +/datum/recipe/omelette + items = list( + /obj/item/weapon/reagent_containers/food/snacks/egg, + /obj/item/weapon/reagent_containers/food/snacks/egg, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/omelette + +/datum/recipe/muffin + reagents = list(/datum/reagent/drink/milk = 5, /datum/reagent/sugar = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/muffin + +/datum/recipe/eggplantparm + fruit = list("eggplant" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge + ) + result = /obj/item/weapon/reagent_containers/food/snacks/eggplantparm + +/datum/recipe/soylenviridians + fruit = list("soybeans" = 1) + reagents = list(/datum/reagent/nutriment/flour = 10) + result = /obj/item/weapon/reagent_containers/food/snacks/soylenviridians + +/datum/recipe/soylentgreen + reagents = list(/datum/reagent/nutriment/flour = 10) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/meat/human, + /obj/item/weapon/reagent_containers/food/snacks/meat/human + ) + result = /obj/item/weapon/reagent_containers/food/snacks/soylentgreen + +/datum/recipe/meatpie + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, + /obj/item/weapon/reagent_containers/food/snacks/meat, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/meatpie + +/datum/recipe/tofupie + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/tofupie + +/datum/recipe/xemeatpie + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, + /obj/item/weapon/reagent_containers/food/snacks/xenomeat, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/xemeatpie + +/datum/recipe/pie + fruit = list(/datum/reagent/drink/juice/banana = 1) + reagents = list(/datum/reagent/sugar = 5) + items = list(/obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough) + result = /obj/item/weapon/reagent_containers/food/snacks/pie + +/datum/recipe/cherrypie + fruit = list("cherries" = 1) + reagents = list(/datum/reagent/sugar = 10) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/cherrypie + +/datum/recipe/berryclafoutis + fruit = list("berries" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/berryclafoutis + +/datum/recipe/wingfangchu + reagents = list(/datum/reagent/nutriment/soysauce = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/xenomeat, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/wingfangchu + +/datum/recipe/chaosdonut + reagents = list(/datum/reagent/frostoil = 5, /datum/reagent/capsaicin = 5, /datum/reagent/sugar = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough + ) + result = /obj/item/weapon/reagent_containers/food/snacks/donut/chaos + +/datum/recipe/meatkabob + items = list( + /obj/item/stack/rods, + /obj/item/weapon/reagent_containers/food/snacks/meat, + /obj/item/weapon/reagent_containers/food/snacks/meat, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/meatkabob + +/datum/recipe/tofukabob + items = list( + /obj/item/stack/rods, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/tofukabob + +/datum/recipe/tofubread + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/tofubread + +/datum/recipe/loadedbakedpotato + fruit = list("potato" = 1) + items = list(/obj/item/weapon/reagent_containers/food/snacks/cheesewedge) + result = /obj/item/weapon/reagent_containers/food/snacks/loadedbakedpotato + +/datum/recipe/cheesyfries + items = list( + /obj/item/weapon/reagent_containers/food/snacks/fries, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/cheesyfries + +/datum/recipe/cubancarp + fruit = list("chili" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/carpmeat + ) + result = /obj/item/weapon/reagent_containers/food/snacks/cubancarp + +/datum/recipe/popcorn + reagents = list(/datum/reagent/sodiumchloride = 5) + fruit = list("corn" = 1) + result = /obj/item/weapon/reagent_containers/food/snacks/popcorn + +/datum/recipe/cookie + reagents = list(/datum/reagent/drink/milk = 5, /datum/reagent/sugar = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/chocolatebar, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/cookie + +/datum/recipe/fortunecookie + reagents = list(/datum/reagent/sugar = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/doughslice, + /obj/item/weapon/paper, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/fortunecookie + make_food(var/obj/container as obj) + var/obj/item/weapon/paper/paper = locate() in container + paper.loc = null //prevent deletion + var/obj/item/weapon/reagent_containers/food/snacks/fortunecookie/being_cooked = ..(container) + paper.loc = being_cooked + being_cooked.trash = paper //so the paper is left behind as trash without special-snowflake(TM Nodrak) code ~carn + return being_cooked + check_items(var/obj/container as obj) + . = ..() + if (.) + var/obj/item/weapon/paper/paper = locate() in container + if (!paper.info) + return 0 + return . + +/datum/recipe/meatsteak + reagents = list(/datum/reagent/sodiumchloride = 1, /datum/reagent/blackpepper = 1) + items = list(/obj/item/weapon/reagent_containers/food/snacks/meat) + result = /obj/item/weapon/reagent_containers/food/snacks/meatsteak + +/datum/recipe/loadedsteak + reagents = list(/datum/reagent/nutriment/garlicsauce = 5) + fruit = list("onion" = 1, "mushroom" = 1) + items = list(/obj/item/weapon/reagent_containers/food/snacks/meat) + result = /obj/item/weapon/reagent_containers/food/snacks/loadedsteak + +/datum/recipe/syntisteak + reagents = list(/datum/reagent/sodiumchloride = 1, /datum/reagent/blackpepper = 1) + items = list(/obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh) + result = /obj/item/weapon/reagent_containers/food/snacks/meatsteak + +/datum/recipe/pizzamargherita + fruit = list("tomato" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/margherita + +/datum/recipe/meatpizza + fruit = list("tomato" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, + /obj/item/weapon/reagent_containers/food/snacks/meat, + /obj/item/weapon/reagent_containers/food/snacks/meat, + /obj/item/weapon/reagent_containers/food/snacks/meat, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza + +/datum/recipe/syntipizza + fruit = list("tomato" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, + /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, + /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, + /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza + +/datum/recipe/mushroompizza + fruit = list("mushroom" = 5, "tomato" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/mushroompizza + +/datum/recipe/vegetablepizza + fruit = list("eggplant" = 1, "carrot" = 1, "corn" = 1, "tomato" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/vegetablepizza + +/datum/recipe/spacylibertyduff + reagents = list(/datum/reagent/water = 5, /datum/reagent/ethanol/vodka = 5, /datum/reagent/psilocybin = 5) + result = /obj/item/weapon/reagent_containers/food/snacks/spacylibertyduff + +/datum/recipe/amanitajelly + reagents = list(/datum/reagent/water = 5, /datum/reagent/ethanol/vodka = 5, /datum/reagent/toxin/amatoxin = 5) + result = /obj/item/weapon/reagent_containers/food/snacks/amanitajelly + make_food(var/obj/container as obj) + var/obj/item/weapon/reagent_containers/food/snacks/amanitajelly/being_cooked = ..(container) + being_cooked.reagents.del_reagent(/datum/reagent/toxin/amatoxin) + return being_cooked + +/datum/recipe/meatballsoup + fruit = list("carrot" = 1, "potato" = 1) + reagents = list(/datum/reagent/water = 10) + items = list(/obj/item/weapon/reagent_containers/food/snacks/meatball) + result = /obj/item/weapon/reagent_containers/food/snacks/meatballsoup + +/datum/recipe/vegetablesoup + fruit = list("carrot" = 1, "potato" = 1, "corn" = 1, "eggplant" = 1) + reagents = list(/datum/reagent/water = 10) + result = /obj/item/weapon/reagent_containers/food/snacks/vegetablesoup + +/datum/recipe/nettlesoup + fruit = list("nettle" = 1, "potato" = 1) + reagents = list(/datum/reagent/water = 10) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/egg + ) + result = /obj/item/weapon/reagent_containers/food/snacks/nettlesoup + +/datum/recipe/wishsoup + reagents = list(/datum/reagent/water = 20) + result= /obj/item/weapon/reagent_containers/food/snacks/wishsoup + +/datum/recipe/hotchili + fruit = list("chili" = 1, "tomato" = 1) + items = list(/obj/item/weapon/reagent_containers/food/snacks/meat) + result = /obj/item/weapon/reagent_containers/food/snacks/hotchili + +/datum/recipe/coldchili + fruit = list("icechili" = 1, "tomato" = 1) + items = list(/obj/item/weapon/reagent_containers/food/snacks/meat) + result = /obj/item/weapon/reagent_containers/food/snacks/coldchili + +/datum/recipe/amanita_pie + reagents = list(/datum/reagent/toxin/amatoxin = 5) + items = list(/obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough) + result = /obj/item/weapon/reagent_containers/food/snacks/amanita_pie + +/datum/recipe/plump_pie + fruit = list("plumphelmet" = 1) + items = list(/obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough) + result = /obj/item/weapon/reagent_containers/food/snacks/plump_pie + +/datum/recipe/spellburger + items = list( + /obj/item/weapon/reagent_containers/food/snacks/plainburger, + /obj/item/clothing/head/wizard/fake, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/spellburger + +/datum/recipe/spellburger + items = list( + /obj/item/weapon/reagent_containers/food/snacks/plainburger, + /obj/item/clothing/head/wizard, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/spellburger + +/datum/recipe/bigbiteburger + items = list( + /obj/item/weapon/reagent_containers/food/snacks/plainburger, + /obj/item/weapon/reagent_containers/food/snacks/meat, + /obj/item/weapon/reagent_containers/food/snacks/meat, + /obj/item/weapon/reagent_containers/food/snacks/meat, + /obj/item/weapon/reagent_containers/food/snacks/egg, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/bigbiteburger + +/datum/recipe/enchiladas + fruit = list("chili" = 2, "corn" = 1) + items = list(/obj/item/weapon/reagent_containers/food/snacks/cutlet) + result = /obj/item/weapon/reagent_containers/food/snacks/enchiladas + +/datum/recipe/creamcheesebread + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/creamcheesebread + +/datum/recipe/monkeysdelight + fruit = list(/datum/reagent/drink/juice/banana = 1) + reagents = list(/datum/reagent/sodiumchloride = 1, /datum/reagent/blackpepper = 1, /datum/reagent/nutriment/flour = 10) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/monkeycube + ) + result = /obj/item/weapon/reagent_containers/food/snacks/monkeysdelight + +/datum/recipe/baguette + reagents = list(/datum/reagent/sodiumchloride = 1, /datum/reagent/blackpepper = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/baguette + +/datum/recipe/fishandchips + items = list( + /obj/item/weapon/reagent_containers/food/snacks/fries, + /obj/item/weapon/reagent_containers/food/snacks/carpmeat, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/fishandchips + +/datum/recipe/bread + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/egg + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/bread + +/datum/recipe/sandwich + items = list( + /obj/item/weapon/reagent_containers/food/snacks/meatsteak, + /obj/item/weapon/reagent_containers/food/snacks/slice/bread, + /obj/item/weapon/reagent_containers/food/snacks/slice/bread, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sandwich + +/datum/recipe/toastedsandwich + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sandwich + ) + result = /obj/item/weapon/reagent_containers/food/snacks/toastedsandwich + +/datum/recipe/grilledcheese + items = list( + /obj/item/weapon/reagent_containers/food/snacks/slice/bread, + /obj/item/weapon/reagent_containers/food/snacks/slice/bread, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/grilledcheese + +/datum/recipe/tomatosoup + fruit = list("tomato" = 2) + reagents = list(/datum/reagent/water = 10) + result = /obj/item/weapon/reagent_containers/food/snacks/tomatosoup + +/datum/recipe/rofflewaffles + reagents = list(/datum/reagent/psilocybin = 5, /datum/reagent/sugar = 10) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/rofflewaffles + +/datum/recipe/stew + fruit = list("potato" = 1, "tomato" = 1, "carrot" = 1, "eggplant" = 1, "mushroom" = 1) + reagents = list(/datum/reagent/water = 10) + items = list(/obj/item/weapon/reagent_containers/food/snacks/meat) + result = /obj/item/weapon/reagent_containers/food/snacks/stew + +/datum/recipe/slimetoast + reagents = list(/datum/reagent/slimejelly = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/slice/bread, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/jelliedtoast/slime + +/datum/recipe/jelliedtoast + reagents = list(/datum/reagent/nutriment/cherryjelly = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/slice/bread, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/jelliedtoast/cherry + +/datum/recipe/milosoup + reagents = list(/datum/reagent/water = 10) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/soydope, + /obj/item/weapon/reagent_containers/food/snacks/soydope, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/milosoup + +/datum/recipe/stewedsoymeat + fruit = list("carrot" = 1, "tomato" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/soydope, + /obj/item/weapon/reagent_containers/food/snacks/soydope + ) + result = /obj/item/weapon/reagent_containers/food/snacks/stewedsoymeat + +/*/datum/recipe/spagetti We have the processor now + items = list( + /obj/item/weapon/reagent_containers/food/snacks/doughslice + ) + result= /obj/item/weapon/reagent_containers/food/snacks/spagetti*/ + +/datum/recipe/boiledspagetti + reagents = list(/datum/reagent/water = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/spagetti, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/boiledspagetti + +/datum/recipe/boiledrice + reagents = list(/datum/reagent/water = 5, /datum/reagent/nutriment/rice = 10) + result = /obj/item/weapon/reagent_containers/food/snacks/boiledrice + +/datum/recipe/ricepudding + reagents = list(/datum/reagent/drink/milk = 5, /datum/reagent/nutriment/rice = 10) + result = /obj/item/weapon/reagent_containers/food/snacks/ricepudding + +/datum/recipe/pastatomato + fruit = list("tomato" = 2) + reagents = list(/datum/reagent/water = 5) + items = list(/obj/item/weapon/reagent_containers/food/snacks/spagetti) + result = /obj/item/weapon/reagent_containers/food/snacks/pastatomato + +/datum/recipe/poppypretzel + fruit = list("poppy" = 1) + items = list(/obj/item/weapon/reagent_containers/food/snacks/dough) + result = /obj/item/weapon/reagent_containers/food/snacks/poppypretzel + +/datum/recipe/meatballspagetti + reagents = list(/datum/reagent/water = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/spagetti, + /obj/item/weapon/reagent_containers/food/snacks/meatball, + /obj/item/weapon/reagent_containers/food/snacks/meatball, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/meatballspagetti + +/datum/recipe/spesslaw + reagents = list(/datum/reagent/water = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/spagetti, + /obj/item/weapon/reagent_containers/food/snacks/meatball, + /obj/item/weapon/reagent_containers/food/snacks/meatball, + /obj/item/weapon/reagent_containers/food/snacks/meatball, + /obj/item/weapon/reagent_containers/food/snacks/meatball, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/spesslaw + +/datum/recipe/superbiteburger + fruit = list("tomato" = 1) + reagents = list(/datum/reagent/sodiumchloride = 5, /datum/reagent/blackpepper = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/bigbiteburger, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/meat, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/boiledegg, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/superbiteburger + +/datum/recipe/candiedapple + fruit = list("apple" = 1) + reagents = list(/datum/reagent/water = 5, /datum/reagent/sugar = 5) + result = /obj/item/weapon/reagent_containers/food/snacks/candiedapple + +/datum/recipe/applepie + fruit = list("apple" = 1) + items = list(/obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough) + result = /obj/item/weapon/reagent_containers/food/snacks/applepie + +/datum/recipe/slimeburger + reagents = list(/datum/reagent/slimejelly = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/bun + ) + result = /obj/item/weapon/reagent_containers/food/snacks/jellyburger/slime + +/datum/recipe/jellyburger + reagents = list(/datum/reagent/nutriment/cherryjelly = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/bun + ) + result = /obj/item/weapon/reagent_containers/food/snacks/jellyburger/cherry + +/datum/recipe/twobread + reagents = list(/datum/reagent/ethanol/wine = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/slice/bread, + /obj/item/weapon/reagent_containers/food/snacks/slice/bread, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/twobread + +/datum/recipe/threebread + items = list( + /obj/item/weapon/reagent_containers/food/snacks/twobread, + /obj/item/weapon/reagent_containers/food/snacks/slice/bread, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/threebread + +/datum/recipe/slimesandwich + reagents = list(/datum/reagent/slimejelly = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/slice/bread, + /obj/item/weapon/reagent_containers/food/snacks/slice/bread, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/jellysandwich/slime + +/datum/recipe/cherrysandwich + reagents = list(/datum/reagent/nutriment/cherryjelly = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/slice/bread, + /obj/item/weapon/reagent_containers/food/snacks/slice/bread, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/jellysandwich/cherry + +/datum/recipe/bloodsoup + reagents = list(/datum/reagent/blood = 30) + result = /obj/item/weapon/reagent_containers/food/snacks/bloodsoup + +/datum/recipe/slimesoup + reagents = list(/datum/reagent/water = 10, /datum/reagent/slimejelly = 5) + items = list() + result = /obj/item/weapon/reagent_containers/food/snacks/slimesoup + +/datum/recipe/boiledslimeextract + reagents = list(/datum/reagent/water = 5) + items = list( + /obj/item/slime_extract, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/boiledslimecore + +/datum/recipe/chocolateegg + items = list( + /obj/item/weapon/reagent_containers/food/snacks/egg, + /obj/item/weapon/reagent_containers/food/snacks/chocolatebar, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/chocolateegg + +/datum/recipe/sausage + items = list( + /obj/item/weapon/reagent_containers/food/snacks/meatball, + /obj/item/weapon/reagent_containers/food/snacks/cutlet, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sausage + +/datum/recipe/fishfingers + reagents = list(/datum/reagent/nutriment/flour = 10) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/egg, + /obj/item/weapon/reagent_containers/food/snacks/carpmeat, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/fishfingers + +/datum/recipe/mysterysoup + reagents = list(/datum/reagent/water = 10) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/badrecipe, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + /obj/item/weapon/reagent_containers/food/snacks/egg, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/mysterysoup + +/datum/recipe/pumpkinpie + fruit = list("pumpkin" = 1) + reagents = list(/datum/reagent/drink/milk = 5, /datum/reagent/sugar = 5, /datum/reagent/nutriment/protein/egg = 3, /datum/reagent/nutriment/flour = 10) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pumpkinpie + +/datum/recipe/plumphelmetbiscuit + fruit = list("plumphelmet" = 1) + reagents = list(/datum/reagent/water = 5, /datum/reagent/nutriment/flour = 5) + result = /obj/item/weapon/reagent_containers/food/snacks/plumphelmetbiscuit + +/datum/recipe/mushroomsoup + fruit = list("mushroom" = 1) + reagents = list(/datum/reagent/drink/milk = 10) + result = /obj/item/weapon/reagent_containers/food/snacks/mushroomsoup + +/datum/recipe/chawanmushi + fruit = list("mushroom" = 1) + reagents = list(/datum/reagent/water = 5, /datum/reagent/nutriment/soysauce = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/egg, + /obj/item/weapon/reagent_containers/food/snacks/egg + ) + result = /obj/item/weapon/reagent_containers/food/snacks/chawanmushi + +/datum/recipe/beetsoup + fruit = list("whitebeet" = 1, "cabbage" = 1) + reagents = list(/datum/reagent/water = 10) + result = /obj/item/weapon/reagent_containers/food/snacks/beetsoup + +/datum/recipe/appletart + fruit = list("goldapple" = 1) + reagents = list(/datum/reagent/sugar = 5, /datum/reagent/drink/milk = 5, /datum/reagent/nutriment/flour = 10) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/egg + ) + result = /obj/item/weapon/reagent_containers/food/snacks/appletart + +/datum/recipe/tossedsalad + fruit = list("cabbage" = 2, "tomato" = 1, "carrot" = 1, "apple" = 1) + result = /obj/item/weapon/reagent_containers/food/snacks/tossedsalad + +/datum/recipe/aesirsalad + fruit = list("goldapple" = 1, "ambrosiadeus" = 1) + result = /obj/item/weapon/reagent_containers/food/snacks/aesirsalad + +/datum/recipe/validsalad + fruit = list("potato" = 1, "ambrosia" = 3) + items = list(/obj/item/weapon/reagent_containers/food/snacks/meatball) + result = /obj/item/weapon/reagent_containers/food/snacks/validsalad + make_food(var/obj/container as obj) + var/obj/item/weapon/reagent_containers/food/snacks/validsalad/being_cooked = ..(container) + being_cooked.reagents.del_reagent(/datum/reagent/toxin) + return being_cooked + +/datum/recipe/cracker + reagents = list(/datum/reagent/sodiumchloride = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/doughslice + ) + result = /obj/item/weapon/reagent_containers/food/snacks/cracker + +/datum/recipe/stuffing + reagents = list(/datum/reagent/water = 5, /datum/reagent/sodiumchloride = 1, /datum/reagent/blackpepper = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/bread, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/stuffing + +/datum/recipe/tofurkey + items = list( + /obj/item/weapon/reagent_containers/food/snacks/tofu, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + /obj/item/weapon/reagent_containers/food/snacks/stuffing, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/tofurkey + +// Fuck Science! +/datum/recipe/ruinedvirusdish + items = list( + /obj/item/weapon/virusdish + ) + result = /obj/item/weapon/ruinedvirusdish + +////////////////////////////////////////// +// bs12 food port stuff +////////////////////////////////////////// + +/datum/recipe/taco + items = list( + /obj/item/weapon/reagent_containers/food/snacks/doughslice, + /obj/item/weapon/reagent_containers/food/snacks/cutlet, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge + ) + result = /obj/item/weapon/reagent_containers/food/snacks/taco + +/datum/recipe/bun + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough + ) + result = /obj/item/weapon/reagent_containers/food/snacks/bun + +/datum/recipe/flatbread + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough + ) + result = /obj/item/weapon/reagent_containers/food/snacks/flatbread + +/datum/recipe/meatball + items = list( + /obj/item/weapon/reagent_containers/food/snacks/rawmeatball + ) + result = /obj/item/weapon/reagent_containers/food/snacks/meatball + +/datum/recipe/cutlet + items = list( + /obj/item/weapon/reagent_containers/food/snacks/rawcutlet + ) + result = /obj/item/weapon/reagent_containers/food/snacks/cutlet + +/datum/recipe/fries + items = list( + /obj/item/weapon/reagent_containers/food/snacks/rawsticks + ) + result = /obj/item/weapon/reagent_containers/food/snacks/fries + +/datum/recipe/onionrings + fruit = list("onion" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/doughslice + ) + result = /obj/item/weapon/reagent_containers/food/snacks/onionrings + +/datum/recipe/mint + reagents = list(/datum/reagent/sugar = 5, /datum/reagent/frostoil = 5) + result = /obj/item/weapon/reagent_containers/food/snacks/mint + + +// Cakes. +/datum/recipe/cake + reagents = list(/datum/reagent/drink/milk = 5, /datum/reagent/nutriment/flour = 15, /datum/reagent/sugar = 15, /datum/reagent/nutriment/protein/egg = 9) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/plaincake + +/datum/recipe/cake/carrot + fruit = list("carrot" = 3) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/carrotcake + +/datum/recipe/cake/cheese + items = list( + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesecake + +/datum/recipe/cake/orange + fruit = list("orange" = 1) + reagents = list(/datum/reagent/drink/milk = 5, /datum/reagent/nutriment/flour = 15, /datum/reagent/nutriment/protein/egg = 9, /datum/reagent/drink/juice/orange = 3, /datum/reagent/sugar = 5) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/orangecake + +/datum/recipe/cake/lime + fruit = list("lime" = 1) + reagents = list(/datum/reagent/drink/milk = 5, /datum/reagent/nutriment/flour = 15, /datum/reagent/nutriment/protein/egg = 9, /datum/reagent/drink/juice/lime = 3, /datum/reagent/sugar = 5) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/limecake + +/datum/recipe/cake/lemon + fruit = list("lemon" = 1) + reagents = list(/datum/reagent/drink/milk = 5, /datum/reagent/nutriment/flour = 15, /datum/reagent/nutriment/protein/egg = 9, /datum/reagent/drink/juice/lemon = 3, /datum/reagent/sugar = 5) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/lemoncake + +/datum/recipe/cake/chocolate + items = list(/obj/item/weapon/reagent_containers/food/snacks/chocolatebar) + reagents = list(/datum/reagent/drink/milk = 5, /datum/reagent/nutriment/flour = 15, /datum/reagent/nutriment/protein/egg = 9, /datum/reagent/nutriment/coco = 4, /datum/reagent/sugar = 5) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/chocolatecake + +/datum/recipe/cake/birthday + items = list(/obj/item/clothing/head/cakehat) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/birthdaycake + +/datum/recipe/cake/apple + fruit = list("apple" = 2) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/applecake + +/datum/recipe/cake/brain + items = list(/obj/item/organ/internal/brain) + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake diff --git a/code/modules/food/replicator.dm b/code/modules/food/replicator.dm new file mode 100644 index 00000000..56865f98 --- /dev/null +++ b/code/modules/food/replicator.dm @@ -0,0 +1,161 @@ +/obj/machinery/food_replicator + name = "replicator" + desc = "like a microwave, except better." + icon = 'icons/obj/vending.dmi' + icon_state = "soda" + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 40 + obj_flags = OBJ_FLAG_ANCHORABLE + var/biomass = 100 + var/biomass_max = 100 + var/biomass_per = 10 + var/deconstruct_eff = 0.5 + var/list/queued_dishes = list() + var/make_time = 0 + var/start_making = 0 + var/list/menu = list("nutrition slab" = /obj/item/weapon/reagent_containers/food/snacks/tofu, + "turkey substitute" = /obj/item/weapon/reagent_containers/food/snacks/tofurkey, + "waffle substitute" = /obj/item/weapon/reagent_containers/food/snacks/soylenviridians, + "nutrition fries" = /obj/item/weapon/reagent_containers/food/snacks/fries, + "liquid nutrition" = /obj/item/weapon/reagent_containers/food/snacks/soydope, + "pudding substitute" = /obj/item/weapon/reagent_containers/food/snacks/ricepudding) + +/obj/machinery/food_replicator/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/replicator(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) //used to hold the biomass + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) //used to cook the food + component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) //used to deconstruct the stuff + + RefreshParts() + +/obj/machinery/food_replicator/attackby(var/obj/item/O, var/mob/user) + if(istype(O, /obj/item/weapon/reagent_containers/food/snacks)) + var/obj/item/weapon/reagent_containers/food/snacks/S = O + user.drop_item(O) + for(var/datum/reagent/nutriment/N in S.reagents.reagent_list) + biomass = Clamp(biomass + round(N.volume*deconstruct_eff),1,biomass_max) + qdel(O) + else if(istype(O, /obj/item/weapon/storage/plants)) + if(!O.contents || !O.contents.len) + return + to_chat(user, "You empty \the [O] into \the [src]") + for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in O.contents) + var/obj/item/weapon/storage/S = O + S.remove_from_storage(G, null) + for(var/datum/reagent/nutriment/N in G.reagents.reagent_list) + biomass = Clamp(biomass + round(N.volume*deconstruct_eff),1,biomass_max) + qdel(G) + + if(default_deconstruction_screwdriver(user, O)) + return + else if(default_deconstruction_crowbar(user, O)) + return + else if(default_part_replacement(user, O)) + return + else + ..() + return + +/obj/machinery/food_replicator/update_icon() + if(stat & BROKEN) + icon_state = "[initial(icon_state)]-broken" + else if( !(stat & NOPOWER) ) + icon_state = initial(icon_state) + else + src.icon_state = "[initial(icon_state)]-off" + +/obj/machinery/food_replicator/hear_talk(mob/M as mob, text, verb, datum/language/speaking) + if(!speaking || speaking.machine_understands) + spawn(20) + var/true_text = lowertext(html_decode(text)) + for(var/menu_item in menu) + if(findtext(true_text, menu_item)) + queue_dish(menu_item) + if(findtext(true_text, "status")) + state_status() + else if(findtext(true_text, "menu")) + state_menu() + ..() + +/obj/machinery/food_replicator/proc/state_status() + var/message_bio = "boop beep" + if(biomass == 0) + message_bio = "Biomass is out!" + else if(biomass <= biomass_max/4) + message_bio = "Biomass is nearly out." + else if(biomass <= biomass_max/2) + message_bio = "Biomass is roughly half full." + else if(biomass != biomass_max) + message_bio = "Biomass is near maximum capacity!" + else + message_bio = "Biomass is full!" + src.audible_message("\The [src] states, \"[message_bio]\"") + +/obj/machinery/food_replicator/proc/state_menu() + src.audible_message("\The [src] states, \"Greetings! I serve the following dishes: [english_list(menu)]\"") + +/obj/machinery/food_replicator/proc/dispense_food(var/text) + var/type = menu[text] + if(!type) + src.audible_message("\The [src] states, \"Error! I cannot find the recipe for that item.\"") + return 0 + + if(biomass < biomass_per) + src.audible_message("\The [src] states, \"Error! I do not have enough biomass to serve any more dishes.\"") + queued_dishes.Cut() + return 0 + biomass -= biomass_per + src.audible_message("\The [src] states, \"Your [text] is ready!\"") + playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) + var/atom/A = new type(src.loc) + A.SetName(text) + A.desc = "Looks... actually pretty good." + use_power(75000) + return 1 + +/obj/machinery/food_replicator/RefreshParts() + deconstruct_eff = 0 + biomass_max = 0 + biomass_per = 20 + for(var/obj/item/weapon/stock_parts/P in component_parts) + if(istype(P, /obj/item/weapon/stock_parts/matter_bin)) + biomass_max += 100 * P.rating + if(istype(P, /obj/item/weapon/stock_parts/manipulator)) + biomass_per = max(1, biomass_per - 5 * P.rating) + if(istype(P, /obj/item/weapon/stock_parts/micro_laser)) + deconstruct_eff += 0.5 * P.rating + biomass = min(biomass,biomass_max) + +/obj/machinery/food_replicator/proc/queue_dish(var/text) + if(!(text in menu)) + return + + if(!queued_dishes) + queued_dishes = list() + + queued_dishes += text + if(world.time > make_time) + start_making = 1 + +/obj/machinery/food_replicator/Process() + if(queued_dishes && queued_dishes.len) + if(start_making) //want to do this first so that the first dish won't instantly come out + src.audible_message("\The [src] rumbles and vibrates.") + playsound(src.loc, 'sound/machines/juicer.ogg', 50, 1) + make_time = world.time + rand(100, 300) + start_making = 0 + if(world.time > make_time) + dispense_food(queued_dishes[1]) + if(queued_dishes && queued_dishes.len) //more to come + queued_dishes -= queued_dishes[1] + start_making = 1 + ..() + +/obj/machinery/food_replicator/examine(mob/user) + . = ..(user) + if(panel_open) + to_chat(user, "The maintenance hatch is open.") diff --git a/code/modules/games/boardgame.dm b/code/modules/games/boardgame.dm new file mode 100644 index 00000000..f2ea5fcf --- /dev/null +++ b/code/modules/games/boardgame.dm @@ -0,0 +1,228 @@ +/obj/item/weapon/board + name = "board" + desc = "A standard 16\" checkerboard. Well used." //Goddamn imperial system. + icon = 'icons/obj/pieces.dmi' + icon_state = "board" + + var/num = 0 + var/board_icons = list() + var/board = list() + var/selected = -1 + +/obj/item/weapon/board/examine(mob/user, var/distance = -1) + if(in_range(user,src)) + user.set_machine(src) + interact(user) + return + ..() + +/obj/item/weapon/board/attack_hand(mob/living/carbon/human/M as mob) + if(M.machine == src) + ..() + else + src.examine(M) + +obj/item/weapon/board/attackby(obj/item/I as obj, mob/user as mob) + if(!addPiece(I,user)) + ..() + +/obj/item/weapon/board/proc/addPiece(obj/item/I as obj, mob/user as mob, var/tile = 0) + if(I.w_class != ITEM_SIZE_TINY) //only small stuff + user.show_message("\The [I] is too big to be used as a board piece.") + return 0 + if(num == 64) + user.show_message("\The [src] is already full!") + return 0 + if(tile > 0 && board["[tile]"]) + user.show_message("That space is already filled!") + return 0 + if(!user.Adjacent(src)) + return 0 + + user.drop_from_inventory(I) + I.forceMove(src) + num++ + + + if(!board_icons["[I.icon] [I.icon_state]"]) + board_icons["[I.icon] [I.icon_state]"] = new /icon(I.icon,I.icon_state) + + if(tile == 0) + var i; + for(i=0;i<64;i++) + if(!board["[i]"]) + board["[i]"] = I + break + else + board["[tile]"] = I + + src.updateDialog() + + return 1 + + +/obj/item/weapon/board/interact(mob/user as mob) + if(user.is_physically_disabled() || (!isAI(user) && !user.Adjacent(src))) //can't see if you arent conscious. If you are not an AI you can't see it unless you are next to it, either. + user << browse(null, "window=boardgame") + user.unset_machine() + return + + var/list/dat = list({" + + "}) + var i, stagger + stagger = 0 //so we can have the checkerboard effect + for(i=0, i<64, i++) + if(i%8 == 0) + dat += "" + stagger = !stagger + if(selected == i) + dat += "\s*$/g,rb={option:[1,""],legend:[1,"
            ","
            "],area:[1,"",""],param:[1,"",""],thead:[1,"
            = 0 && !isobserver(user)) + dat += "
            Remove Selected Piece" + user << browse(jointext(dat, null),"window=boardgame;size=430x500") // 50px * 8 squares + 30 margin + onclose(usr, "boardgame") + +/obj/item/weapon/board/Topic(href, href_list) + if(!usr.Adjacent(src)) + usr.unset_machine() + usr << browse(null, "window=boardgame") + return + + if(!usr.incapacitated()) //you can't move pieces if you can't move + if(href_list["select"]) + var/s = href_list["select"] + var/obj/item/I = board["[s]"] + if(selected >= 0) + //check to see if clicked on tile is currently selected one + if(text2num(s) == selected) + selected = -1 //deselect it + else + + if(I) //cant put items on other items. + return + + //put item in new spot. + I = board["[selected]"] + board["[selected]"] = null + board -= "[selected]" + board -= null + board["[s]"] = I + selected = -1 + else + if(I) + selected = text2num(s) + else + var/mob/living/carbon/human/H = locate(href_list["person"]) + if(!istype(H)) + return + var/obj/item/O = H.get_active_hand() + if(!O) + return + addPiece(O,H,text2num(s)) + if(href_list["remove"]) + var/obj/item/I = board["[selected]"] + if(!I) + return + board["[selected]"] = null + board -= "[selected]" + board -= null + I.forceMove(src.loc) + num-- + selected = -1 + var j + for(j=0;j<64;j++) + if(board["[j]"]) + var/obj/item/K = board["[j]"] + if(K.icon == I.icon && cmptext(K.icon_state,I.icon_state)) + src.updateDialog() + return + //Didn't find it in use, remove it and allow GC to delete it. + board_icons["[I.icon] [I.icon_state]"] = null + board_icons -= "[I.icon] [I.icon_state]" + board_icons -= null + src.updateDialog() + +//Checkers + +/obj/item/weapon/reagent_containers/food/snacks/checker + name = "checker" + desc = "It is plastic and shiny." + icon = 'icons/obj/pieces.dmi' + icon_state = "checker_black" + w_class = ITEM_SIZE_TINY + center_of_mass = "x=16;y=16" + nutriment_desc = list("a choking hazard" = 4) + nutriment_amt = 1 + var/piece_color ="black" + +/obj/item/weapon/reagent_containers/food/snacks/checker/New() + ..() + icon_state = "[name]_[piece_color]" + name = "[piece_color] [name]" + +/obj/item/weapon/reagent_containers/food/snacks/checker/red + piece_color ="red" + +//Chess + +/obj/item/weapon/reagent_containers/food/snacks/checker/pawn + name = "pawn" + desc = "How many pawns will die in your war?" + +/obj/item/weapon/reagent_containers/food/snacks/checker/pawn/red + piece_color ="red" + +/obj/item/weapon/reagent_containers/food/snacks/checker/knight + name = "knight" + desc = "The piece chess deserves, and needs to actually play." + +/obj/item/weapon/reagent_containers/food/snacks/checker/knight/red + piece_color ="red" + +/obj/item/weapon/reagent_containers/food/snacks/checker/bishop + name = "bishop" + desc = "What corruption occured, urging holy men to fight?" + +/obj/item/weapon/reagent_containers/food/snacks/checker/bishop/red + piece_color ="red" + +/obj/item/weapon/reagent_containers/food/snacks/checker/rook + name = "rook" + desc = "Representing ancient moving towers. So powerful and fast they were banned from wars, forever." + +/obj/item/weapon/reagent_containers/food/snacks/checker/rook/red + piece_color ="red" + +/obj/item/weapon/reagent_containers/food/snacks/checker/queen + name = "queen" + desc = "A queen of battle and pain. She dances across the battlefield." + +/obj/item/weapon/reagent_containers/food/snacks/checker/queen/red + piece_color ="red" + +/obj/item/weapon/reagent_containers/food/snacks/checker/king + name = "king" + desc = "Why does a chess game end when the king dies?" + +/obj/item/weapon/reagent_containers/food/snacks/checker/king/red + piece_color ="red" \ No newline at end of file diff --git a/code/modules/games/cardemon.dm b/code/modules/games/cardemon.dm new file mode 100644 index 00000000..71c148db --- /dev/null +++ b/code/modules/games/cardemon.dm @@ -0,0 +1,39 @@ +/obj/item/weapon/pack/cardemon + name = "\improper Cardemon booster pack" + desc = "Finally! A children's card game in space!" + icon_state = "card_pack_cardemon" + +/obj/item/weapon/pack/cardemon/New() + var/datum/playingcard/P + var/i + for(i=0; i<6; i++) + var/element = pick("ire","spaghetti","meat","metal","money","brain") + var/stats = list("HP"=rand(1,15),"DP"=rand(1,15),"SP"=rand(1,15)) + var/rarity + if(prob(10)) + if(prob(5)) + if(prob(5)) + rarity = "Plasteel" + else + rarity = "Platinum" + else + rarity = "Silver" + + var/nam = pick("Death","Life","Plant","Leaf","Air","Earth","Fire","Water","Killer","Holy", "God", "Ordinary","Demon","Angel", "Phoron", "Mad", "Insane", "Metal", "Steel", "Secret") + var/nam2 = pick("Carp", "Corgi", "Cat", "Mouse", "Octopus", "Lizard", "Monkey", "Plant", "Duck", "Demon", "Spider", "Bird", "Shark", "Rock") + + P = new() + P.name = "[nam] [nam2] [stats["HP"]]/[stats["DP"]]/[stats["SP"]]" + P.card_icon = "card_cardemon" + if(rarity) + P.name = "[rarity] [P.name]" + P.card_icon += "_[rarity]" + P.back_icon = "card_back_cardemon" + P.desc = "Wow! A Cardemon card. Its element is: [element]. Its stats are: [stats["HP"]] HP, [stats["DP"]] DP, [stats["SP"]] SP" + cards += P + P = new() + P.name = "Cardemon Instructions" + P.card_icon = "card_cardemon_instructional" + P.back_icon = "card_back_cardemon" + P.desc = "How To Play Cardemon: every card has 3 stats and an Element. The first stat is Health, second is Damage, third is Speed. Each player plays two cards, and they attack in order of card speed on whichever target the owner selects. Discard cards with no health left over. Once every card has moved or died, a round has finished; you can replace fallen cards with new ones from your hand between rounds. Finally, elements: they do half damage to the one before it, and do double damage to the one after it: ire > spaghetti > metal > money > meat > brain > ire." + cards += P \ No newline at end of file diff --git a/code/modules/games/cards.dm b/code/modules/games/cards.dm new file mode 100644 index 00000000..73bd9842 --- /dev/null +++ b/code/modules/games/cards.dm @@ -0,0 +1,330 @@ +/datum/playingcard + var/name = "playing card" + var/card_icon = "card_back" + var/back_icon = "card_back" + var/desc = "regular old playing card." + +/obj/item/weapon/deck + w_class = ITEM_SIZE_SMALL + icon = 'icons/obj/playing_cards.dmi' + var/list/cards = list() + +/obj/item/weapon/deck/holder + name = "card box" + desc = "A small leather case to show how classy you are compared to everyone else." + icon_state = "card_holder" + +/obj/item/weapon/deck/cards + name = "deck of cards" + desc = "A simple deck of playing cards." + icon_state = "deck" + +/obj/item/weapon/deck/cards/New() + ..() + + var/datum/playingcard/P + for(var/suit in list("spades","clubs","diamonds","hearts")) + + var/colour + if(suit == "spades" || suit == "clubs") + colour = "black_" + else + colour = "red_" + + for(var/number in list("ace","two","three","four","five","six","seven","eight","nine","ten")) + P = new() + P.name = "[number] of [suit]" + P.card_icon = "[colour]num" + P.back_icon = "card_back" + cards += P + + for(var/number in list("jack","queen","king")) + P = new() + P.name = "[number] of [suit]" + P.card_icon = "[colour]col" + P.back_icon = "card_back" + cards += P + + + for(var/i = 0,i<2,i++) + P = new() + P.name = "joker" + P.card_icon = "joker" + cards += P + +/obj/item/weapon/deck/attackby(obj/O as obj, mob/user as mob) + if(istype(O,/obj/item/weapon/hand)) + var/obj/item/weapon/hand/H = O + for(var/datum/playingcard/P in H.cards) + cards += P + qdel(O) + to_chat(user, "You place your cards on the bottom of \the [src].") + return + ..() + +/obj/item/weapon/deck/verb/draw_card() + + set category = "Object" + set name = "Draw" + set desc = "Draw a card from a deck." + set src in view(1) + + if(usr.stat || !Adjacent(usr)) return + + if(!istype(usr,/mob/living/carbon)) + return + + var/mob/living/carbon/user = usr + + if(!cards.len) + to_chat(usr, "There are no cards in the deck.") + return + + var/obj/item/weapon/hand/H + if(user.l_hand && istype(user.l_hand,/obj/item/weapon/hand)) + H = user.l_hand + else if(user.r_hand && istype(user.r_hand,/obj/item/weapon/hand)) + H = user.r_hand + else + H = new(get_turf(src)) + user.put_in_hands(H) + + if(!H || !user) return + + var/datum/playingcard/P = cards[1] + H.cards += P + cards -= P + H.update_icon() + user.visible_message("\The [user] draws a card.") + to_chat(user, "It's the [P].") + +/obj/item/weapon/deck/verb/deal_card() + + set category = "Object" + set name = "Deal" + set desc = "Deal a card from a deck." + set src in view(1) + + if(usr.stat || !Adjacent(usr)) return + + if(!cards.len) + to_chat(usr, "There are no cards in the deck.") + return + + var/list/players = list() + for(var/mob/living/player in viewers(3)) + if(!player.stat) + players += player + //players -= usr + + var/mob/living/M = input("Who do you wish to deal a card?") as null|anything in players + if(!usr || !src || !M) return + + deal_at(usr, M) + +/obj/item/weapon/deck/proc/deal_at(mob/user, mob/target) + var/obj/item/weapon/hand/H = new(get_step(user, user.dir)) + + H.cards += cards[1] + cards -= cards[1] + H.concealed = 1 + H.update_icon() + if(user==target) + user.visible_message("\The [user] deals a card to \himself.") + else + user.visible_message("\The [user] deals a card to \the [target].") + H.throw_at(get_step(target,target.dir),10,1,H) + +/obj/item/weapon/hand/attackby(obj/O as obj, mob/user as mob) + if(istype(O,/obj/item/weapon/hand)) + var/obj/item/weapon/hand/H = O + for(var/datum/playingcard/P in cards) + H.cards += P + H.concealed = src.concealed + user.drop_from_inventory(src) + qdel(src) + H.update_icon() + return + ..() + +/obj/item/weapon/deck/attack_self(var/mob/user as mob) + + cards = shuffle(cards) + user.visible_message("\The [user] shuffles [src].") + +/obj/item/weapon/deck/MouseDrop(atom/over) + if(!usr || !over) return + if(!Adjacent(usr) || !over.Adjacent(usr)) return // should stop you from dragging through windows + + if(!ishuman(over) || !(over in viewers(3))) return + + if(!cards.len) + to_chat(usr, "There are no cards in the deck.") + return + + deal_at(usr, over) + +/obj/item/weapon/pack/ + name = "card pack" + desc = "For those with disposible income." + + icon_state = "card_pack" + icon = 'icons/obj/playing_cards.dmi' + w_class = ITEM_SIZE_TINY + var/list/cards = list() + + +/obj/item/weapon/pack/attack_self(var/mob/user as mob) + user.visible_message("[user] rips open \the [src]!") + var/obj/item/weapon/hand/H = new() + + H.cards += cards + cards.Cut(); + user.drop_item() + qdel(src) + + H.update_icon() + user.put_in_active_hand(H) + +/obj/item/weapon/hand + name = "hand of cards" + desc = "Some playing cards." + icon = 'icons/obj/playing_cards.dmi' + icon_state = "empty" + w_class = ITEM_SIZE_TINY + + var/concealed = 0 + var/list/cards = list() + +/obj/item/weapon/hand/verb/discard() + + set category = "Object" + set name = "Discard" + set desc = "Place a card from your hand in front of you." + + var/list/to_discard = list() + for(var/datum/playingcard/P in cards) + to_discard[P.name] = P + var/discarding = input("Which card do you wish to put down?") as null|anything in to_discard + + if(!discarding || !to_discard[discarding] || !usr || !src) return + + var/datum/playingcard/card = to_discard[discarding] + + var/obj/item/weapon/hand/H = new(src.loc) + H.cards += card + cards -= card + H.concealed = 0 + H.update_icon() + src.update_icon() + usr.visible_message("\The [usr] plays \the [discarding].") + H.loc = get_step(usr,usr.dir) + + if(!cards.len) + qdel(src) + +/obj/item/weapon/hand/attack_self(var/mob/user as mob) + concealed = !concealed + update_icon() + user.visible_message("\The [user] [concealed ? "conceals" : "reveals"] their hand.") + +/obj/item/weapon/hand/examine(mob/user) + . = ..(user) + if((!concealed || src.loc == user) && cards.len) + to_chat(user, "It contains: ") + for(var/datum/playingcard/P in cards) + to_chat(user, "The [P.name].") + +/obj/item/weapon/hand/update_icon(var/direction = 0) + + if(!cards.len) + qdel(src) + return + else if(cards.len > 1) + name = "hand of cards" + desc = "Some playing cards." + else if(concealed) + name = "single playing card" + desc = "An unknown playing card, concealed." + else + var/datum/playingcard/P = cards[1] + name = "[P.name]" + desc = "[P.desc]" + + overlays.Cut() + + + if(cards.len == 1) + var/datum/playingcard/P = cards[1] + var/image/I = new(src.icon, (concealed ? "[P.back_icon]" : "[P.card_icon]") ) + I.pixel_x += (-5+rand(10)) + I.pixel_y += (-5+rand(10)) + overlays += I + return + + var/offset = Floor(20/cards.len) + + var/matrix/M = matrix() + if(direction) + switch(direction) + if(NORTH) + M.Translate( 0, 0) + if(SOUTH) + M.Translate( 0, 4) + if(WEST) + M.Turn(90) + M.Translate( 3, 0) + if(EAST) + M.Turn(90) + M.Translate(-2, 0) + var/i = 0 + for(var/datum/playingcard/P in cards) + var/image/I = new(src.icon, (concealed ? "[P.back_icon]" : "[P.card_icon]") ) + //I.pixel_x = origin+(offset*i) + switch(direction) + if(SOUTH) + I.pixel_x = 8-(offset*i) + if(WEST) + I.pixel_y = -6+(offset*i) + if(EAST) + I.pixel_y = 8-(offset*i) + else + I.pixel_x = -7+(offset*i) + I.transform = M + overlays += I + i++ + +/obj/item/weapon/hand/dropped(mob/user as mob) + ..() + if(locate(/obj/structure/table, loc)) + src.update_icon(user.dir) + else + update_icon() + +/obj/item/weapon/hand/pickup(mob/user as mob) + src.update_icon() + + +/*** A special thing that steals a card from a deck, probably lost in maint somewhere. ***/ +/obj/item/weapon/hand/missing_card + name = "missing playing card" + +/obj/item/weapon/hand/missing_card/Initialize() + . = ..() + + var/list/deck_list = list() + for(var/obj/item/weapon/deck/D in world) + if(isturf(D.loc)) //Decks hiding in inventories are safe. Respect the sanctity of loadout items. + deck_list += D + + if(deck_list.len) + var/obj/item/weapon/deck/the_deck = pick(deck_list) + var/datum/playingcard/the_card = length(the_deck.cards) ? pick(the_deck.cards) : null + + if(the_card) + cards += the_card + the_deck.cards -= the_card + + concealed = pick(0,1) //Maybe up, maybe down. + + update_icon() //Automatically qdels if no card can be found. diff --git a/code/modules/games/tarot.dm b/code/modules/games/tarot.dm new file mode 100644 index 00000000..d42a7507 --- /dev/null +++ b/code/modules/games/tarot.dm @@ -0,0 +1,41 @@ +/* this is a playing card deck based off of the Rider-Waite Tarot Deck. +*/ + +/obj/item/weapon/deck/tarot + name = "deck of tarot cards" + desc = "For all your occult needs!" + icon_state = "deck_tarot" + +/obj/item/weapon/deck/tarot/New() + ..() + + var/datum/playingcard/P + for(var/name in list("Fool","Magician","High Priestess","Empress","Emperor","Hierophant","Lovers","Chariot","Strength","Hermit","Wheel of Fortune","Justice","Hanged Man","Death","Temperance","Devil","Tower","Star","Moon","Sun","Judgement","World")) + P = new() + P.name = "[name]" + P.card_icon = "tarot_major" + P.back_icon = "card_back_tarot" + P.desc = "Some sort of major tarot card." + cards += P + for(var/suit in list("wands","pentacles","cups","swords")) + + + for(var/number in list("ace","two","three","four","five","six","seven","eight","nine","ten","page","knight","queen","king")) + P = new() + P.name = "[number] of [suit]" + P.card_icon = "tarot_[suit]" + P.back_icon = "card_back_tarot" + P.desc = "A Rider-Waite tarot card." + cards += P + +/obj/item/weapon/deck/tarot/attack_self(var/mob/user as mob) + var/list/newcards = list() + while(cards.len) + var/datum/playingcard/P = pick(cards) + P.name = replacetext(P.name," reversed","") + if(prob(50)) + P.name += " reversed" + newcards += P + cards -= P + cards = newcards + user.visible_message("\The [user] shuffles [src].") \ No newline at end of file diff --git a/code/modules/genetics/side_effects.dm b/code/modules/genetics/side_effects.dm new file mode 100644 index 00000000..cd1181d5 --- /dev/null +++ b/code/modules/genetics/side_effects.dm @@ -0,0 +1,77 @@ +/datum/genetics/side_effect + var/name // name of the side effect, to use as a header in the manual + var/symptom // description of the symptom of the side effect + var/treatment // description of the treatment of the side effect + var/effect // description of what happens when not treated + var/duration = 0 // delay between start() and finish() + + proc/start(mob/living/carbon/human/H) + // start the side effect, this should give some cue as to what's happening, + // such as gasping. These cues need to be unique among side-effects. + + proc/finish(mob/living/carbon/human/H) + // Finish the side-effect. This should first check whether the cure has been + // applied, and if not, cause bad things to happen. + +/datum/genetics/side_effect/genetic_burn + name = "Genetic Burn" + symptom = "Subject's skin turns unusualy red." + treatment = "Inject small dose of dexalin." + effect = "Subject's skin burns." + duration = 10*30 + + start(mob/living/carbon/human/H) + H.visible_message("\The [H] starts turning very red...") + + finish(mob/living/carbon/human/H) + if(!H.reagents.has_reagent(/datum/reagent/dexalin)) + for(var/organ_name in BP_ALL_LIMBS) + var/obj/item/organ/external/E = H.get_organ(organ_name) + E.take_damage(0, 5, 0) + +/datum/genetics/side_effect/bone_snap + name = "Bone Snap" + symptom = "Subject's limbs tremble notably." + treatment = "Inject small dose of bicaridine." + effect = "Subject's bone breaks." + duration = 10*60 + + start(mob/living/carbon/human/H) + H.visible_message("\The [H]'s limbs start shivering uncontrollably.") + + finish(mob/living/carbon/human/H) + if(!H.reagents.has_reagent(/datum/reagent/bicaridine)) + var/organ_name = pick(BP_ALL_LIMBS) + var/obj/item/organ/external/E = H.get_organ(organ_name) + E.take_damage(20, 0, 0) + E.fracture() + +/datum/genetics/side_effect/confuse + name = "Confuse" + symptom = "Subject starts drooling uncontrollably." + treatment = "Inject small dose of dylovene." + effect = "Subject becomes confused." + duration = 10*30 + + start(mob/living/carbon/human/H) + H.visible_message("\The [H] drools.") + + finish(mob/living/carbon/human/H) + if(!H.reagents.has_reagent(/datum/reagent/dylovene)) + H.confused += 100 + +proc/trigger_side_effect(mob/living/carbon/human/H) + spawn + if(!istype(H)) return + var/tp = pick(typesof(/datum/genetics/side_effect) - /datum/genetics/side_effect) + var/datum/genetics/side_effect/S = new tp + + S.start(H) + spawn(20) + if(!istype(H)) return + H.Weaken(rand(0, S.duration / 50)) + sleep(S.duration) + + if(!istype(H)) return + H.SetWeakened(0) + S.finish(H) diff --git a/code/modules/ghosttrap/trap.dm b/code/modules/ghosttrap/trap.dm new file mode 100644 index 00000000..c3c0186f --- /dev/null +++ b/code/modules/ghosttrap/trap.dm @@ -0,0 +1,232 @@ +// This system is used to grab a ghost from observers with the required preferences and +// lack of bans set. See posibrain.dm for an example of how they are called/used. ~Z + +var/list/ghost_traps + +/proc/get_ghost_trap(var/trap_key) + if(!ghost_traps) + populate_ghost_traps() + return ghost_traps[trap_key] + +/proc/get_ghost_traps() + if(!ghost_traps) + populate_ghost_traps() + return ghost_traps + +/proc/populate_ghost_traps() + ghost_traps = list() + for(var/traptype in typesof(/datum/ghosttrap)) + var/datum/ghosttrap/G = new traptype + ghost_traps[G.object] = G + +/datum/ghosttrap + var/object = "positronic brain" + var/minutes_since_death = 0 // If non-zero the ghost must have been dead for this many minutes to be allowed to spawn + var/list/ban_checks = list("AI","Cyborg") + var/pref_check = BE_SYNTH + var/ghost_trap_message = "They are occupying a positronic brain now." + var/ghost_trap_role = "Positronic Brain" + var/can_set_own_name = TRUE + var/list_as_special_role = TRUE // If true, this entry will be listed as a special role in the character setup + + var/list/request_timeouts + +/datum/ghosttrap/New() + request_timeouts = list() + ..() + +// Check for bans, proper atom types, etc. +/datum/ghosttrap/proc/assess_candidate(var/mob/observer/ghost/candidate, var/mob/target, var/feedback = TRUE) + if(!candidate.MayRespawn(1, minutes_since_death)) + return 0 + if(islist(ban_checks)) + for(var/bantype in ban_checks) + if(jobban_isbanned(candidate, "[bantype]")) + if(feedback) + to_chat(candidate, "You are banned from one or more required roles and hence cannot enter play as \a [object].") + return 0 + return 1 + +// Print a message to all ghosts with the right prefs/lack of bans. +/datum/ghosttrap/proc/request_player(var/mob/target, var/request_string, var/request_timeout) + if(request_timeout) + request_timeouts[target] = world.time + request_timeout + GLOB.destroyed_event.register(target, src, /datum/ghosttrap/proc/unregister_target) + else + unregister_target(target) + + for(var/mob/observer/ghost/O in GLOB.player_list) + if(!assess_candidate(O, target, FALSE)) + return + if(pref_check && !O.client.wishes_to_be_role(pref_check)) + continue + if(O.client) + to_chat(O, "[request_string] (Occupy) ([ghost_follow_link(target, O)])") + +/datum/ghosttrap/proc/unregister_target(var/target) + request_timeouts -= target + GLOB.destroyed_event.unregister(target, src, /datum/ghosttrap/proc/unregister_target) + +// Handles a response to request_player(). +/datum/ghosttrap/Topic(href, href_list) + if(..()) + return 1 + if(href_list["candidate"] && href_list["target"]) + var/mob/observer/ghost/candidate = locate(href_list["candidate"]) // BYOND magic. + var/mob/target = locate(href_list["target"]) // So much BYOND magic. + if(!target || !candidate) + return + if(candidate != usr) + return + if(request_timeouts[target] && world.time > request_timeouts[target]) + to_chat(candidate, "This occupation request is no longer valid.") + return + if(target.key) + to_chat(candidate, "The target is already occupied.") + return + if(assess_candidate(candidate, target)) + transfer_personality(candidate,target) + return 1 + +// Shunts the ckey/mind into the target mob. +/datum/ghosttrap/proc/transfer_personality(var/mob/candidate, var/mob/target) + if(!assess_candidate(candidate, target)) + return 0 + target.ckey = candidate.ckey + if(target.mind) + target.mind.assigned_role = "[ghost_trap_role]" + announce_ghost_joinleave(candidate, 0, "[ghost_trap_message]") + welcome_candidate(target) + set_new_name(target) + return 1 + +// Fluff! +/datum/ghosttrap/proc/welcome_candidate(var/mob/target) + to_chat(target, "You are a positronic brain, brought into existence on [station_name()].") + to_chat(target, "As a synthetic intelligence, you answer to all crewmembers, as well as the AI.") + to_chat(target, "Remember, the purpose of your existence is to serve the crew and the [station_name()]. Above all else, do no harm.") + to_chat(target, "Use say [target.get_language_prefix()]b to speak to other artificial intelligences.") + var/turf/T = get_turf(target) + var/obj/item/organ/internal/posibrain/P = target.loc + T.visible_message("\The [P] chimes quietly.") + if(!istype(P)) //wat + return + P.searching = 0 + P.SetName("positronic brain ([P.brainmob.name])") + P.update_icon() + +// Allows people to set their own name. May or may not need to be removed for posibrains if people are dumbasses. +/datum/ghosttrap/proc/set_new_name(var/mob/target) + if(!can_set_own_name) + return + + var/newname = sanitizeSafe(input(target,"Enter a name, or leave blank for the default name.", "Name change",target.real_name) as text, MAX_NAME_LEN) + if (newname && newname != "") + target.real_name = newname + target.SetName(target.real_name) + +/*********************************** +* Diona pods and walking mushrooms * +***********************************/ +/datum/ghosttrap/plant + object = "living plant" + ban_checks = list("Dionaea") + pref_check = BE_PLANT + ghost_trap_message = "They are occupying a living plant now." + ghost_trap_role = "Plant" + +/datum/ghosttrap/plant/welcome_candidate(var/mob/target) + to_chat(target, "You awaken slowly, stirring into sluggish motion as the air caresses you.") + // This is a hack, replace with some kind of species blurb proc. +/***************** +* Cortical Borer * +*****************/ +/datum/ghosttrap/borer + object = "cortical borer" + ban_checks = list(MODE_BORER) + pref_check = MODE_BORER + ghost_trap_message = "They are occupying a borer now." + ghost_trap_role = "Cortical Borer" + can_set_own_name = FALSE + list_as_special_role = FALSE + +/datum/ghosttrap/borer/welcome_candidate(var/mob/target) + to_chat(target, "You are a cortical borer! You are a brain slug that worms its way \ + into the head of its victim. Use stealth, persuasion and your powers of mind control to keep you, \ + your host and your eventual spawn safe and warm.") + to_chat(target, "You can speak to your victim with say, to other borers with say [target.get_language_prefix()]x, and use your Abilities tab to access powers.") +/******************** +* Maintenance Drone * +*********************/ +/datum/ghosttrap/drone + object = "maintenance drone" + pref_check = BE_PAI + ghost_trap_message = "They are occupying a maintenance drone now." + ghost_trap_role = "Maintenance Drone" + can_set_own_name = FALSE + list_as_special_role = FALSE + +/datum/ghosttrap/drone/New() + minutes_since_death = DRONE_SPAWN_DELAY + ..() + +datum/ghosttrap/drone/assess_candidate(var/mob/observer/ghost/candidate, var/mob/target) + . = ..() + if(. && !target.can_be_possessed_by(candidate)) + return 0 + +datum/ghosttrap/drone/transfer_personality(var/mob/candidate, var/mob/living/silicon/robot/drone/drone) + if(!assess_candidate(candidate)) + return 0 + drone.transfer_personality(candidate.client) + +/************** +* personal AI * +**************/ +/datum/ghosttrap/pai + object = "pAI" + pref_check = BE_PAI + ghost_trap_message = "They are occupying a pAI now." + ghost_trap_role = "pAI" + +datum/ghosttrap/pai/assess_candidate(var/mob/observer/ghost/candidate, var/mob/target) + return 0 + +datum/ghosttrap/pai/transfer_personality(var/mob/candidate, var/mob/living/silicon/robot/drone/drone) + return 0 + +/****************** +* Wizard Familiar * +******************/ +/datum/ghosttrap/familiar + object = "wizard familiar" + pref_check = MODE_WIZARD + ghost_trap_message = "They are occupying a familiar now." + ghost_trap_role = "Wizard Familiar" + ban_checks = list(MODE_WIZARD) + +/datum/ghosttrap/familiar/welcome_candidate(var/mob/target) + return 0 + +/datum/ghosttrap/cult + object = "cultist" + ban_checks = list("cultist") + pref_check = MODE_CULTIST + can_set_own_name = FALSE + ghost_trap_message = "They are occupying a cultist's body now." + ghost_trap_role = "Cultist" + +/datum/ghosttrap/cult/welcome_candidate(var/mob/target) + var/obj/item/device/soulstone/S = target.loc + if(istype(S)) + if(S.is_evil) + cult.add_antagonist(target.mind) + to_chat(target, "Remember, you serve the one who summoned you first, and the cult second.") + else + to_chat(target, "This soultone has been purified. You do not belong to the cult.") + to_chat(target, "Remember, you only serve the one who summoned you.") + +/datum/ghosttrap/cult/shade + object = "soul stone" + ghost_trap_message = "They are occupying a soul stone now." + ghost_trap_role = "Shade" diff --git a/code/modules/goonchat/assets.dm b/code/modules/goonchat/assets.dm new file mode 100644 index 00000000..15601679 --- /dev/null +++ b/code/modules/goonchat/assets.dm @@ -0,0 +1,33 @@ +/datum/asset/group/goonchat + children = list( + /datum/asset/simple/jquery, + /datum/asset/simple/goonchat, + /datum/asset/simple/fontawesome + ) + +/datum/asset/simple/jquery + verify = FALSE + assets = list( + "jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js', + ) + +/datum/asset/simple/goonchat + verify = TRUE + assets = list( + "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js', + "browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js', + "browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css', + "browserOutput_white.css" = 'code/modules/goonchat/browserassets/css/browserOutput_white.css', + "browserOutput_override.css" = 'code/modules/goonchat/browserassets/css/browserOutput_override.css', + ) + +/datum/asset/simple/fontawesome + verify = FALSE + assets = list( + "fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot', + "fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff', + "fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot', + "fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff', + "font-awesome.css" = 'html/font-awesome/css/all.min.css', + "v4shim.css" = 'html/font-awesome/css/v4-shims.min.css' + ) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm new file mode 100644 index 00000000..87fe5f7b --- /dev/null +++ b/code/modules/goonchat/browserOutput.dm @@ -0,0 +1,248 @@ +/********************************* +For the main html chat area +*********************************/ + +//Precaching a bunch of shit +GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of icons for the browser output + +//On client, created on login +/datum/chatOutput + var/client/owner //client ref + var/loaded = FALSE // Has the client loaded the browser output area? + var/list/messageQueue //If they haven't loaded chat, this is where messages will go until they do + var/cookieSent = FALSE // Has the client sent a cookie for analysis + var/broken = FALSE + var/list/connectionHistory //Contains the connection history passed from chat cookie + var/adminMusicVolume = 25 //This is for the Play Global Sound verb + +/datum/chatOutput/New(client/C) + owner = C + messageQueue = list() + connectionHistory = list() + +/datum/chatOutput/proc/start() + //Check for existing chat + if(!owner) + return FALSE + + if(!winexists(owner, "browseroutput")) // Oh goddamnit. + set waitfor = FALSE + broken = TRUE + message_admins("Couldn't start chat for [key_name_admin(owner)]!") + . = FALSE + alert(owner.mob, "Updated chat window does not exist. If you are using a custom skin file please allow the game to update.") + return + + if(winget(owner, "browseroutput", "is-visible") == "true") //Already setup + doneLoading() + + else //Not setup + load() + + return TRUE + +/datum/chatOutput/proc/load() + set waitfor = FALSE + if(!owner) + return + + var/datum/asset/stuff = get_asset_datum(/datum/asset/group/goonchat) + stuff.send(owner) + + owner << browse(file('code/modules/goonchat/browserassets/html/browserOutput.html'), "window=browseroutput") + +/datum/chatOutput/Topic(href, list/href_list) + if(usr.client != owner) + return TRUE + + // Build arguments. + // Arguments are in the form "param[paramname]=thing" + var/list/params = list() + for(var/key in href_list) + if(length(key) > 7 && findtext(key, "param")) // 7 is the amount of characters in the basic param key template. + var/param_name = copytext(key, 7, -1) + var/item = href_list[key] + + params[param_name] = item + + var/data // Data to be sent back to the chat. + switch(href_list["proc"]) + if("doneLoading") + data = doneLoading(arglist(params)) + + if("debug") + data = debug(arglist(params)) + + if("ping") + data = ping(arglist(params)) + + if("analyzeClientData") + data = analyzeClientData(arglist(params)) + + if("setMusicVolume") + data = setMusicVolume(arglist(params)) + if(data) + ehjax_send(data = data) + + +//Called on chat output done-loading by JS. +/datum/chatOutput/proc/doneLoading() + if(loaded) + return + + //testing("Chat loaded for [owner.ckey]") + loaded = TRUE + showChat() + + + for(var/message in messageQueue) + // whitespace has already been handled by the original to_chat + to_chat(owner, message, handle_whitespace=FALSE) + + messageQueue = null + sendClientData() + + //do not convert to to_chat() + owner << "Failed to load fancy chat, reverting to old chat. Certain features won't work." + +/datum/chatOutput/proc/showChat() + winset(owner, "output", "is-visible=false") + winset(owner, "browseroutput", "is-disabled=false;is-visible=true") + +/datum/chatOutput/proc/ehjax_send(client/C = owner, window = "browseroutput", data) + if(islist(data)) + data = json_encode(data) + C << output("[data]", "[window]:ehjaxCallback") + +/datum/chatOutput/proc/sendMusic(music, list/extra_data) + if(!findtext(music, GLOB.is_http_protocol)) + return + var/list/music_data = list("adminMusic" = url_encode(url_encode(music))) + + if(extra_data?.len) + music_data["musicRate"] = extra_data["pitch"] + music_data["musicSeek"] = extra_data["start"] + music_data["musicHalt"] = extra_data["end"] + + ehjax_send(data = music_data) + +/datum/chatOutput/proc/stopMusic() + ehjax_send(data = "stopMusic") + +/datum/chatOutput/proc/setMusicVolume(volume = "") + if(volume) + adminMusicVolume = CLAMP(text2num(volume), 0, 100) + +//Sends client connection details to the chat to handle and save +/datum/chatOutput/proc/sendClientData() + //Get dem deets + var/list/deets = list("clientData" = list()) + deets["clientData"]["ckey"] = owner.ckey + deets["clientData"]["ip"] = owner.address + deets["clientData"]["compid"] = owner.computer_id + var/data = json_encode(deets) + ehjax_send(data = data) + +//Called by client, sent data to investigate (cookie history so far) +/datum/chatOutput/proc/analyzeClientData(cookie = "") + if(!cookie) + return + + if(cookie != "none") + var/list/connData = json_decode(cookie) + if (connData && islist(connData) && connData.len > 0 && connData["connData"]) + connectionHistory = connData["connData"] //lol fuck + var/list/found = new() + for(var/i in connectionHistory.len to 1 step -1) + var/list/row = src.connectionHistory[i] + if (!row || row.len < 3 || (!row["ckey"] || !row["compid"] || !row["ip"])) //Passed malformed history object + return + if (world.IsBanned(row["ckey"], row["ip"], row["compid"])) + found = row + break + + //Uh oh this fucker has a history of playing on a banned account!! + if (found.len > 0) + //TODO: add a new evasion ban for the CURRENT client details, using the matched row details + message_admins("[key_name(src.owner)] has a cookie from a banned account! (Matched: [found["ckey"]], [found["ip"]], [found["compid"]])") + //log_admin_private("[key_name(owner)] has a cookie from a banned account! (Matched: [found["ckey"]], [found["ip"]], [found["compid"]])") + + cookieSent = TRUE + +//Called by js client every 60 seconds +/datum/chatOutput/proc/ping() + return "pong" + +//Called by js client on js error +/datum/chatOutput/proc/debug(error) + log_world("\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: [(src.owner.key ? src.owner.key : src.owner)] triggered JS error: [error]") + +//Global chat procs +/proc/to_chat_immediate(target, message, handle_whitespace = TRUE) + if(!target || !message) + return + + if(target == world) + target = GLOB.clients + + var/original_message = message + if(handle_whitespace) + message = replacetext(message, "\n", "
            ") + message = replacetext(message, "\t", "[GLOB.TAB][GLOB.TAB]") + + //Replace expanded \icon macro with icon2html + //regex/Replace with a proc won't work here because icon2html takes target as an argument and there is no way to pass it to the replacement proc + //not even hacks with reassigning usr work + var/regex/i = new(@//, "g") + while(i.Find(message)) + message = copytext(message,1,i.index)+icon2html(locate(i.group[1]), target, icon_state=i.group[2])+copytext(message,i.next) + + message = symbols_to_unicode(strip_improper(color_macro_to_html(message))) + + if(islist(target)) + // Do the double-encoding outside the loop to save nanoseconds + var/twiceEncoded = url_encode(url_encode(message)) + for(var/I in target) + var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible + + if (!C) + continue + + //Send it to the old style output window. + C << original_message + + if(!C.chatOutput || C.chatOutput.broken) // A player who hasn't updated his skin file. + continue + + if(!C.chatOutput.loaded) + //Client still loading, put their messages in a queue + C.chatOutput.messageQueue += message + continue + + C << output(twiceEncoded, "browseroutput:output") + else + var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible + + if (!C) + return + + //Send it to the old style output window. + C << original_message + + if(!C.chatOutput || C.chatOutput.broken) // A player who hasn't updated his skin file. + return + + if(!C.chatOutput.loaded) + //Client still loading, put their messages in a queue + C.chatOutput.messageQueue += message + return + + // url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript. + C << output(url_encode(url_encode(message)), "browseroutput:output") + + +/proc/to_chat(target, message, handle_whitespace = TRUE) + if(Master.current_runlevel == RUNLEVEL_INIT || !SSchat?.initialized) + to_chat_immediate(target, message, handle_whitespace) + return + SSchat.queue(target, message, handle_whitespace) \ No newline at end of file diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css new file mode 100644 index 00000000..799728da --- /dev/null +++ b/code/modules/goonchat/browserassets/css/browserOutput.css @@ -0,0 +1,398 @@ +/***************************************** +* +* GLOBAL STYLES +* +******************************************/ +html, body { + padding: 0; + margin: 0; + height: 100%; + color: #a4bad6; +} +body { + background: #171717; + font-family: Verdana, sans-serif; + font-size: 9pt; + color: #a4bad6; + line-height: 1.2; + overflow-x: hidden; + overflow-y: scroll; + word-wrap: break-word; + scrollbar-face-color:#1A1A1A; + scrollbar-track-color:#171717; + scrollbar-highlight-color:#171717; +} + +em { + font-style: normal; + font-weight: bold; +} + +img { + margin: 0; + padding: 0; + line-height: 1; + -ms-interpolation-mode: nearest-neighbor; + image-rendering: pixelated; +} +img.icon { + height: 1em; + min-height: 16px; + width: auto; + vertical-align: bottom; +} + +.r:before { /* "repeated" badge class for combined messages */ + content: 'x'; +} +.r { + display: inline-block; + min-width: 0.5em; + font-size: 0.7em; + padding: 0.2em 0.3em; + line-height: 1; + color: white; + text-align: center; + white-space: nowrap; + vertical-align: middle; + background-color: crimson; + border-radius: 10px; +} + +a {color: #397ea5;} +a.visited {color: #7c00e6;} +a:visited {color: #7c00e6;} +a.popt {text-decoration: none;} + +/***************************************** +* +* OUTPUT NOT RELATED TO ACTUAL MESSAGES +* +******************************************/ +#loading { + position: fixed; + width: 300px; + height: 150px; + text-align: center; + left: 50%; + top: 50%; + margin: -75px 0 0 -150px; +} +#loading i {display: block; padding-bottom: 3px;} + +#messages { + font-size: 13px; + padding: 3px; + margin: 0; + word-wrap: break-word; +} +#newMessages { + position: fixed; + display: block; + bottom: 0; + right: 0; + padding: 8px; + background: #202020; + text-decoration: none; + font-variant: small-caps; + font-size: 1.1em; + font-weight: bold; + color: #a4bad6; +} +#newMessages:hover {background: #171717;} +#newMessages i {vertical-align: middle; padding-left: 3px;} +#ping { + position: fixed; + top: 0; + right: 135px; + width: 45px; + background: #202020; + height: 30px; + padding: 8px 0 2px 0; +} +#ping i {display: block; text-align: center;} +#ping .ms { + display: block; + text-align: center; + font-size: 8pt; + padding-top: 2px; +} +#userBar { + position: fixed; + top: 0; + right: 0; +} +#userBar .subCell { + background: #202020; + height: 30px; + padding: 5px 0; + display: block; + color: #a4bad6; + text-decoration: none; + line-height: 28px; + border-top: 1px solid #171717; +} +#userBar .subCell:hover {background: #202020;} +#userBar .toggle { + width: 45px; + background: #202020; + border-top: 0; + float: right; + text-align: center; +} +#userBar .sub {clear: both; display: none; width: 180px;} +#userBar .sub.scroll {overflow-y: scroll;} +#userBar .sub.subCell {padding: 3px 0 3px 8px; line-height: 30px; font-size: 0.9em; clear: both;} +#userBar .sub span { + display: block; + line-height: 30px; + float: left; +} +#userBar .sub i { + display: block; + padding: 0 5px; + font-size: 1.1em; + width: 22px; + text-align: center; + line-height: 30px; + float: right; +} +#userBar .sub input { + position: absolute; + padding: 7px 5px; + width: 121px; + line-height: 30px; + float: left; +} +#userBar .topCell {border-top: 0;} + +/* POPUPS */ +.popup { + position: fixed; + top: 50%; + left: 50%; + background: #ddd; +} +.popup .close { + position: absolute; + background: #aaa; + top: 0; + right: 0; + color: #333; + text-decoration: none; + z-index: 2; + padding: 0 10px; + height: 30px; + line-height: 30px; +} +.popup .close:hover {background: #999;} +.popup .head { + background: #999; + color: #ddd; + padding: 0 10px; + height: 30px; + line-height: 30px; + text-transform: uppercase; + font-size: 0.9em; + font-weight: bold; + border-bottom: 2px solid green; +} +.popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;} +.popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;} +.popup input[type=submit] {padding: 5px 10px; background: #999; color: #ddd; text-transform: uppercase; font-size: 0.9em; font-weight: bold;} +.popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;} + +.changeFont {padding: 10px;} +.changeFont a {display: block; text-decoration: none; padding: 3px; color: #333;} +.changeFont a:hover {background: #ccc;} + +.highlightPopup {padding: 10px; text-align: center;} +.highlightPopup input[type=text] {display: block; width: 215px; text-align: left; margin-top: 5px;} +.highlightPopup input.highlightColor {background-color: #FFFF00;} +.highlightPopup input.highlightTermSubmit {margin-top: 5px;} + +/* ADMIN CONTEXT MENU */ +.contextMenu { + background-color: #ddd; + position: fixed; + margin: 2px; + width: 150px; +} +.contextMenu a { + display: block; + padding: 2px 5px; + text-decoration: none; + color: #333; +} + +.contextMenu a:hover { + background-color: #ccc; +} + +/* ADMIN FILTER MESSAGES MENU */ +.filterMessages {padding: 5px;} +.filterMessages div {padding: 2px 0;} +.filterMessages input {} +.filterMessages label {} + +.icon-stack {height: 1em; line-height: 1em; width: 1em; vertical-align: middle; margin-top: -2px;} + + +/***************************************** +* +* OUTPUT ACTUALLY RELATED TO MESSAGES +* +******************************************/ + +/* MOTD */ +h1, h2, h3, h4, h5, h6 {color: #0059ea;font-family: Georgia, Verdana, sans-serif;} + +em {font-style: normal;font-weight: bold;} + +.motd {color: #638500;font-family: Verdana, sans-serif;} +.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 + {color: #638500;text-decoration: underline;} +.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover + {color: #638500;} + +.prefix {font-weight: bold;} +.log_message {color: #386aff; font-weight: bold;} + +/* OOC */ +.ooc {font-weight: bold;} +.ooc img.text_tag {width: 32px; height: 10px;} + +.ooc .everyone {color: #AAAAAA;} +.ooc .looc {color: #3a9696;} +.ooc .elevated {color: #2e78d9;} +.ooc .moderator {color: #184880;} +.ooc .developer {color: #1b521f;} +.ooc .admin {color: #ffffff;} + +.staffwarn {color: #c51e1e; font-weight:bold; font-size: 150%;} +/* Admin: Private Messages */ +.pm .howto {color: #c51e1e; font-weight: bold; font-size: 200%;} +.pm .in {color: #c51e1e;} +.pm .out {color: #c51e1e;} +.pm .other {color: #0000ff;} + +/* Admin: Channels */ +.mod_channel {color: #735638; font-weight: bold;} +.mod_channel .admin {color: #b82e00; font-weight: bold;} +.admin_channel {color: #9611d4; font-weight: bold;} + +/* Radio: Misc */ +.deadsay {color: #8337e8;} +.radio {color: #008000;} +.deptradio {color: #ff00ff;} /* when all other department colors fail */ +.newscaster {color: #750000;} + +/* Radio Channels */ +.comradio {color: #2251ad;} +.syndradio {color: #8c3f40;} +.centradio {color: #5c5c8a;} +.airadio {color: #ff00ff;} +.entradio {color: #339966;} + +.secradio {color: #dd3535;} +.engradio {color: #ce7b00;} +.medradio {color: #00a87d;} +.sciradio {color: #993399;} +.supradio {color: #a07429;} +.srvradio {color: #6eaa2c;} +.expradio {color: #a3a332;} +.inqradio {color: #707070;} + +/* Miscellaneous */ +.name {font-weight: bold;} +.alert {color: #c51e1e;} +h1.alert, h2.alert {color: #ffffff;} + +.emote {font-style: italic;} + +/* Game Messages */ + +.attack {color: #c51e1e; font-weight: bold; text-shadow: 0 0 7px #c51e1e;} +.moderate {color: #cc0000;} +.disarm {color: #990000;} +.passive {color: #660000;} + +.danger {color: #c51e1e; font-weight: bold; text-shadow: 0 0 7px #c51e1e;} +.combat_success {color: #008081; font-weight: bold; text-shadow: 0px 0px 3px #008081;} +.warning {color: #c51e1e; font-style: italic;} +.boldannounce {color: #c51e1e; font-weight: bold;} +.rose {color: #ff5050;} +.info {color: #0077cc;} +.binfo {color: #0077cc; font-weight: bold; text-shadow: 0px 0px 3px #0077cc;} +.notice {color: #0059ea;} +.bnotice {color: #0059ea; font-weight: bold;} +.alium {color: #00ff00;} +.cult {color: #800080; font-weight: bold; font-style: italic;} + +.reflex_shoot {color: #000099; font-style: italic;} + +/* Languages */ + +.alien {color: #543354;} +.tajaran {color: #803b56;} +.tajaran_signlang {color: #941c1c;} +.skrell {color: #00ced1;} +.soghun {color: #228b22;} +.nabber_lang {color: #525252;} +.solcom {color: #22228b;} +.changeling {color: #800080;} +.vox {color: #aa00aa;} +.rough {font-family: "Trebuchet MS", cursive#386891, sans-serif;} +.say_quote {font-family: Georgia, Verdana, sans-serif;} +.terran {color: #9c250b;} +.moon {color: #422863;} +.spacer {color: #ff6600;} + +.red_team {color: #b27676;} +.blue_team {color: #76abb2;} + +.interface {color: #bf00bf;} + +.good {color: #4f7529; font-weight: bold;} +.bad {color: #ee0000; font-weight: bold;} +.hypnophrase {color: #202020; font-weight: bold; animation: hypnocolor 1500ms infinite;} +@keyframes hypnocolor { + 0% { color: #202020; } + 25% { color: #4b02ac; } + 50% { color: #9f41f1; } + 75% { color: #541c9c; } + 100% { color: #7adbf3; } +} + +.phobia {color: #dd0000; font-size: 16pt; font-weight: bold; animation: phobia 750ms infinite;} +@keyframes phobia { + 0% { color: #f75a5a; } + 50% { color: #dd0000; } + 100% { color: #f75a5a; } +} + +.icon {height: 1em; width: auto;} + +.memo {color: #638500; text-align: center;} +.memoedit {text-align: center; font-size: 16px;} + +.connectionClosed, .fatalError {background: red; color: white; padding: 5px;} +.connectionClosed.restored {background: green;} +.internal.boldnshit {color: #3d5bc3; font-weight: bold;} + +/* HELPER CLASSES */ +.text-normal {font-weight: normal; font-style: normal;} +.hidden {display: none; visibility: hidden;} + +.examinebox { + display: inline-block; + min-width: 10px; + text-align: left; + border: 1px ridge #151319; + padding: 10px; + font-size: 15px; + vertical-align: middle; + background: rgba(40, 40, 40, 0.5); + *zoom: 1; + *display: inline; +} \ No newline at end of file diff --git a/code/modules/goonchat/browserassets/css/browserOutput_override.css b/code/modules/goonchat/browserassets/css/browserOutput_override.css new file mode 100644 index 00000000..71e35335 --- /dev/null +++ b/code/modules/goonchat/browserassets/css/browserOutput_override.css @@ -0,0 +1,385 @@ +/***************************************** +* +* GLOBAL STYLES +* +******************************************/ +html, body { + padding: 0; + margin: 0; + height: 100%; + color: #a4bad6; +} +body { + background: #171717; + font-family: Verdana, sans-serif; + font-size: 9pt; + font-color: #a4bad6; + line-height: 1.2; + overflow-x: hidden; + overflow-y: scroll; + word-wrap: break-word; + scrollbar-face-color:#1A1A1A; + scrollbar-track-color:#171717; + scrollbar-highlight-color:#171717; +} + +em { + font-style: normal; + font-weight: bold; +} + +img { + margin: 0; + padding: 0; + line-height: 1; + -ms-interpolation-mode: nearest-neighbor; + image-rendering: pixelated; +} +img.icon { + height: 1em; + min-height: 16px; + width: auto; + vertical-align: bottom; +} + +.r:before { /* "repeated" badge class for combined messages */ + content: 'x'; +} +.r { + display: inline-block; + min-width: 0.5em; + font-size: 0.7em; + padding: 0.2em 0.3em; + line-height: 1; + color: white; + text-align: center; + white-space: nowrap; + vertical-align: middle; + background-color: crimson; + border-radius: 10px; +} + +a {color: #397ea5;} +a.visited {color: #7c00e6;} +a:visited {color: #7c00e6;} +a.popt {text-decoration: none;} + +/***************************************** +* +* OUTPUT NOT RELATED TO ACTUAL MESSAGES +* +******************************************/ +#loading { + position: fixed; + width: 300px; + height: 150px; + text-align: center; + left: 50%; + top: 50%; + margin: -75px 0 0 -150px; +} +#loading i {display: block; padding-bottom: 3px;} + +#messages { + font-size: 13px; + padding: 3px; + margin: 0; + word-wrap: break-word; +} +#newMessages { + position: fixed; + display: block; + bottom: 0; + right: 0; + padding: 8px; + background: #202020; + text-decoration: none; + font-variant: small-caps; + font-size: 1.1em; + font-weight: bold; + color: #a4bad6; +} +#newMessages:hover {background: #171717;} +#newMessages i {vertical-align: middle; padding-left: 3px;} +#ping { + position: fixed; + top: 0; + right: 135px; + width: 45px; + background: #202020; + height: 30px; + padding: 8px 0 2px 0; +} +#ping i {display: block; text-align: center;} +#ping .ms { + display: block; + text-align: center; + font-size: 8pt; + padding-top: 2px; +} +#userBar { + position: fixed; + top: 0; + right: 0; +} +#userBar .subCell { + background: #202020; + height: 30px; + padding: 5px 0; + display: block; + color: #a4bad6; + text-decoration: none; + line-height: 28px; + border-top: 1px solid #171717; +} +#userBar .subCell:hover {background: #202020;} +#userBar .toggle { + width: 45px; + background: #202020; + border-top: 0; + float: right; + text-align: center; +} +#userBar .sub {clear: both; display: none; width: 180px;} +#userBar .sub.scroll {overflow-y: scroll;} +#userBar .sub.subCell {padding: 3px 0 3px 8px; line-height: 30px; font-size: 0.9em; clear: both;} +#userBar .sub span { + display: block; + line-height: 30px; + float: left; +} +#userBar .sub i { + display: block; + padding: 0 5px; + font-size: 1.1em; + width: 22px; + text-align: center; + line-height: 30px; + float: right; +} +#userBar .sub input { + position: absolute; + padding: 7px 5px; + width: 121px; + line-height: 30px; + float: left; +} +#userBar .topCell {border-top: 0;} + +/* POPUPS */ +.popup { + position: fixed; + top: 50%; + left: 50%; + background: #ddd; +} +.popup .close { + position: absolute; + background: #aaa; + top: 0; + right: 0; + color: #333; + text-decoration: none; + z-index: 2; + padding: 0 10px; + height: 30px; + line-height: 30px; +} +.popup .close:hover {background: #999;} +.popup .head { + background: #999; + color: #ddd; + padding: 0 10px; + height: 30px; + line-height: 30px; + text-transform: uppercase; + font-size: 0.9em; + font-weight: bold; + border-bottom: 2px solid green; +} +.popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;} +.popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;} +.popup input[type=submit] {padding: 5px 10px; background: #999; color: #ddd; text-transform: uppercase; font-size: 0.9em; font-weight: bold;} +.popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;} + +.changeFont {padding: 10px;} +.changeFont a {display: block; text-decoration: none; padding: 3px; color: #333;} +.changeFont a:hover {background: #ccc;} +/* +.highlightPopup {padding: 10px; text-align: center;} +.highlightPopup input[type=text] {display: block; width: 215px; text-align: left; margin-top: 5px;} +.highlightPopup input.highlightColor {background-color: #FFFF00;} +.highlightPopup input.highlightTermSubmit {margin-top: 5px;} +*/ + +/* ADMIN CONTEXT MENU */ +.contextMenu { + background-color: #ddd; + position: fixed; + margin: 2px; + width: 150px; +} +.contextMenu a { + display: block; + padding: 2px 5px; + text-decoration: none; + color: #333; +} + +.contextMenu a:hover { + background-color: #ccc; +} + +/* ADMIN FILTER MESSAGES MENU */ +.filterMessages {padding: 5px;} +.filterMessages div {padding: 2px 0;} +.filterMessages input {} +.filterMessages label {} + +.icon-stack {height: 1em; line-height: 1em; width: 1em; vertical-align: middle; margin-top: -2px;} + + +/***************************************** +* +* OUTPUT ACTUALLY RELATED TO MESSAGES +* +******************************************/ + +/* MOTD */ +h1, h2, h3, h4, h5, h6 {color: #0059ea;font-family: Georgia, Verdana, sans-serif;} + +em {font-style: normal;font-weight: bold;} + +.motd {color: #638500;font-family: Verdana, sans-serif;} +.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 + {color: #638500;text-decoration: underline;} +.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover + {color: #638500;} + +.prefix {font-weight: bold;} +.log_message {color: #386aff; font-weight: bold;} + +/* OOC */ +.ooc {font-weight: bold;} +.ooc img.text_tag {width: 32px; height: 10px;} + +.ooc .everyone {color: #AAAAAA;} +.ooc .looc {color: #3a9696;} +.ooc .elevated {color: #2e78d9;} +.ooc .moderator {color: #184880;} +.ooc .developer {color: #1b521f;} +.ooc .admin {color: #ffffff;} + +.staffwarn {color: #c51e1e; font-weight:bold; font-size: 150%;} +/* Admin: Private Messages */ +.pm .howto {color: #c51e1e; font-weight: bold; font-size: 200%;} +.pm .in {color: #c51e1e;} +.pm .out {color: #c51e1e;} +.pm .other {color: #0000ff;} + +/* Admin: Channels */ +.mod_channel {color: #735638; font-weight: bold;} +.mod_channel .admin {color: #b82e00; font-weight: bold;} +.admin_channel {color: #9611d4; font-weight: bold;} + +/* Radio: Misc */ +.deadsay {color: #8337e8;} +.radio {color: #008000;} +.deptradio {color: #ff00ff;} /* when all other department colors fail */ +.newscaster {color: #750000;} + +/* Radio Channels */ +.comradio {color: #2251ad;} +.syndradio {color: #8c3f40;} +.centradio {color: #5c5c8a;} +.airadio {color: #ff00ff;} +.entradio {color: #339966;} + +.secradio {color: #dd3535;} +.engradio {color: #ce7b00;} +.medradio {color: #00a87d;} +.sciradio {color: #993399;} +.supradio {color: #a07429;} +.srvradio {color: #6eaa2c;} +.expradio {color: #a3a332;} +.inqradio {color: #707070;} + +/* Miscellaneous */ +.name {font-weight: bold;} +.alert {color: #c51e1e;} +h1.alert, h2.alert {color: #ffffff;} + +.emote {font-style: italic;} + +/* Game Messages */ + +.attack {color: #c51e1e;} +.moderate {color: #cc0000;} +.disarm {color: #990000;} +.passive {color: #660000;} + +.danger {color: #c51e1e; font-weight: bold;} +.warning {color: #c51e1e; font-style: italic;} +.boldannounce {color: #c51e1e; font-weight: bold;} +.rose {color: #ff5050;} +.info {color: #0077cc;} +.binfo {color: #0077cc; font-weight: bold;} +.notice {color: #0059ea;} +.bnotice {color: #0059ea; font-weight: bold;} +.alium {color: #00ff00;} +.cult {color: #800080; font-weight: bold; font-style: italic;} + +.reflex_shoot {color: #000099; font-style: italic;} + +/* Languages */ + +.alien {color: #543354;} +.tajaran {color: #803b56;} +.tajaran_signlang {color: #941c1c;} +.skrell {color: #00ced1;} +.soghun {color: #228b22;} +.nabber_lang {color: #525252;} +.solcom {color: #22228b;} +.changeling {color: #800080;} +.vox {color: #aa00aa;} +.rough {font-family: "Trebuchet MS", cursive#386891, sans-serif;} +.say_quote {font-family: Georgia, Verdana, sans-serif;} +.terran {color: #9c250b;} +.moon {color: #422863;} +.spacer {color: #ff6600;} + +.red_team {color: #b27676;} +.blue_team {color: #76abb2;} + +.interface {color: #bf00bf;} + +.good {color: #4f7529; font-weight: bold;} +.bad {color: #ee0000; font-weight: bold;} +.hypnophrase {color: #202020; font-weight: bold; animation: hypnocolor 1500ms infinite;} +@keyframes hypnocolor { + 0% { color: #202020; } + 25% { color: #4b02ac; } + 50% { color: #9f41f1; } + 75% { color: #541c9c; } + 100% { color: #7adbf3; } +} + +.phobia {color: #dd0000; font-size: 16pt; font-weight: bold; animation: phobia 750ms infinite;} +@keyframes phobia { + 0% { color: #f75a5a; } + 50% { color: #dd0000; } + 100% { color: #f75a5a; } +} + +.icon {height: 1em; width: auto;} + +.memo {color: #638500; text-align: center;} +.memoedit {text-align: center; font-size: 16px;} + +.connectionClosed, .fatalError {background: red; color: white; padding: 5px;} +.connectionClosed.restored {background: green;} +.internal.boldnshit {color: #3d5bc3; font-weight: bold;} + +/* HELPER CLASSES */ +.text-normal {font-weight: normal; font-style: normal;} +.hidden {display: none; visibility: hidden;} diff --git a/code/modules/goonchat/browserassets/css/browserOutput_white.css b/code/modules/goonchat/browserassets/css/browserOutput_white.css new file mode 100644 index 00000000..a36d60a3 --- /dev/null +++ b/code/modules/goonchat/browserassets/css/browserOutput_white.css @@ -0,0 +1,384 @@ +/***************************************** +* +* GLOBAL STYLES +* +******************************************/ +html, body { + padding: 0; + margin: 0; + height: 100%; + color: #a4bad6; +} +body { + background: #171717; + font-family: Verdana, sans-serif; + font-size: 9pt; + font-color: #a4bad6; + line-height: 1.2; + overflow-x: hidden; + overflow-y: scroll; + word-wrap: break-word; + scrollbar-face-color:#1A1A1A; + scrollbar-track-color:#171717; + scrollbar-highlight-color:#171717; +} + +em { + font-style: normal; + font-weight: bold; +} + +img { + margin: 0; + padding: 0; + line-height: 1; + -ms-interpolation-mode: nearest-neighbor; + image-rendering: pixelated; +} +img.icon { + height: 1em; + min-height: 16px; + width: auto; + vertical-align: bottom; +} + +.r:before { /* "repeated" badge class for combined messages */ + content: 'x'; +} +.r { + display: inline-block; + min-width: 0.5em; + font-size: 0.7em; + padding: 0.2em 0.3em; + line-height: 1; + color: white; + text-align: center; + white-space: nowrap; + vertical-align: middle; + background-color: crimson; + border-radius: 10px; +} + +a {color: #397ea5;} +a.visited {color: #7c00e6;} +a:visited {color: #7c00e6;} +a.popt {text-decoration: none;} + +/***************************************** +* +* OUTPUT NOT RELATED TO ACTUAL MESSAGES +* +******************************************/ +#loading { + position: fixed; + width: 300px; + height: 150px; + text-align: center; + left: 50%; + top: 50%; + margin: -75px 0 0 -150px; +} +#loading i {display: block; padding-bottom: 3px;} + +#messages { + font-size: 13px; + padding: 3px; + margin: 0; + word-wrap: break-word; +} +#newMessages { + position: fixed; + display: block; + bottom: 0; + right: 0; + padding: 8px; + background: #202020; + text-decoration: none; + font-variant: small-caps; + font-size: 1.1em; + font-weight: bold; + color: #a4bad6; +} +#newMessages:hover {background: #171717;} +#newMessages i {vertical-align: middle; padding-left: 3px;} +#ping { + position: fixed; + top: 0; + right: 135px; + width: 45px; + background: #202020; + height: 30px; + padding: 8px 0 2px 0; +} +#ping i {display: block; text-align: center;} +#ping .ms { + display: block; + text-align: center; + font-size: 8pt; + padding-top: 2px; +} +#userBar { + position: fixed; + top: 0; + right: 0; +} +#userBar .subCell { + background: #202020; + height: 30px; + padding: 5px 0; + display: block; + color: #a4bad6; + text-decoration: none; + line-height: 28px; + border-top: 1px solid #171717; +} +#userBar .subCell:hover {background: #202020;} +#userBar .toggle { + width: 45px; + background: #202020; + border-top: 0; + float: right; + text-align: center; +} +#userBar .sub {clear: both; display: none; width: 180px;} +#userBar .sub.scroll {overflow-y: scroll;} +#userBar .sub.subCell {padding: 3px 0 3px 8px; line-height: 30px; font-size: 0.9em; clear: both;} +#userBar .sub span { + display: block; + line-height: 30px; + float: left; +} +#userBar .sub i { + display: block; + padding: 0 5px; + font-size: 1.1em; + width: 22px; + text-align: center; + line-height: 30px; + float: right; +} +#userBar .sub input { + position: absolute; + padding: 7px 5px; + width: 121px; + line-height: 30px; + float: left; +} +#userBar .topCell {border-top: 0;} + +/* POPUPS */ +.popup { + position: fixed; + top: 50%; + left: 50%; + background: #ddd; +} +.popup .close { + position: absolute; + background: #aaa; + top: 0; + right: 0; + color: #333; + text-decoration: none; + z-index: 2; + padding: 0 10px; + height: 30px; + line-height: 30px; +} +.popup .close:hover {background: #999;} +.popup .head { + background: #999; + color: #ddd; + padding: 0 10px; + height: 30px; + line-height: 30px; + text-transform: uppercase; + font-size: 0.9em; + font-weight: bold; + border-bottom: 2px solid green; +} +.popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;} +.popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;} +.popup input[type=submit] {padding: 5px 10px; background: #999; color: #ddd; text-transform: uppercase; font-size: 0.9em; font-weight: bold;} +.popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;} + +.changeFont {padding: 10px;} +.changeFont a {display: block; text-decoration: none; padding: 3px; color: #333;} +.changeFont a:hover {background: #ccc;} + +.highlightPopup {padding: 10px; text-align: center;} +.highlightPopup input[type=text] {display: block; width: 215px; text-align: left; margin-top: 5px;} +.highlightPopup input.highlightColor {background-color: #FFFF00;} +.highlightPopup input.highlightTermSubmit {margin-top: 5px;} + +/* ADMIN CONTEXT MENU */ +.contextMenu { + background-color: #ddd; + position: fixed; + margin: 2px; + width: 150px; +} +.contextMenu a { + display: block; + padding: 2px 5px; + text-decoration: none; + color: #333; +} + +.contextMenu a:hover { + background-color: #ccc; +} + +/* ADMIN FILTER MESSAGES MENU */ +.filterMessages {padding: 5px;} +.filterMessages div {padding: 2px 0;} +.filterMessages input {} +.filterMessages label {} + +.icon-stack {height: 1em; line-height: 1em; width: 1em; vertical-align: middle; margin-top: -2px;} + + +/***************************************** +* +* OUTPUT ACTUALLY RELATED TO MESSAGES +* +******************************************/ + +/* MOTD */ +h1, h2, h3, h4, h5, h6 {color: #0059ea;font-family: Georgia, Verdana, sans-serif;} + +em {font-style: normal;font-weight: bold;} + +.motd {color: #638500;font-family: Verdana, sans-serif;} +.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 + {color: #638500;text-decoration: underline;} +.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover + {color: #638500;} + +.prefix {font-weight: bold;} +.log_message {color: #386aff; font-weight: bold;} + +/* OOC */ +.ooc {font-weight: bold;} +.ooc img.text_tag {width: 32px; height: 10px;} + +.ooc .everyone {color: #AAAAAA;} +.ooc .looc {color: #3a9696;} +.ooc .elevated {color: #2e78d9;} +.ooc .moderator {color: #184880;} +.ooc .developer {color: #1b521f;} +.ooc .admin {color: #ffffff;} + +.staffwarn {color: #c51e1e; font-weight:bold; font-size: 150%;} +/* Admin: Private Messages */ +.pm .howto {color: #c51e1e; font-weight: bold; font-size: 200%;} +.pm .in {color: #c51e1e;} +.pm .out {color: #c51e1e;} +.pm .other {color: #0000ff;} + +/* Admin: Channels */ +.mod_channel {color: #735638; font-weight: bold;} +.mod_channel .admin {color: #b82e00; font-weight: bold;} +.admin_channel {color: #9611d4; font-weight: bold;} + +/* Radio: Misc */ +.deadsay {color: #8337e8;} +.radio {color: #008000;} +.deptradio {color: #ff00ff;} /* when all other department colors fail */ +.newscaster {color: #750000;} + +/* Radio Channels */ +.comradio {color: #2251ad;} +.syndradio {color: #8c3f40;} +.centradio {color: #5c5c8a;} +.airadio {color: #ff00ff;} +.entradio {color: #339966;} + +.secradio {color: #dd3535;} +.engradio {color: #ce7b00;} +.medradio {color: #00a87d;} +.sciradio {color: #993399;} +.supradio {color: #a07429;} +.srvradio {color: #6eaa2c;} +.expradio {color: #a3a332;} +.inqradio {color: #707070;} + +/* Miscellaneous */ +.name {font-weight: bold;} +.alert {color: #c51e1e;} +h1.alert, h2.alert {color: #ffffff;} + +.emote {font-style: italic;} + +/* Game Messages */ + +.attack {color: #c51e1e;} +.moderate {color: #cc0000;} +.disarm {color: #990000;} +.passive {color: #660000;} + +.danger {color: #c51e1e; font-weight: bold;} +.warning {color: #c51e1e; font-style: italic;} +.boldannounce {color: #c51e1e; font-weight: bold;} +.rose {color: #ff5050;} +.info {color: #0077cc;} +.binfo {color: #0077cc; font-weight: bold;} +.notice {color: #0059ea;} +.bnotice {color: #0059ea; font-weight: bold;} +.alium {color: #00ff00;} +.cult {color: #800080; font-weight: bold; font-style: italic;} + +.reflex_shoot {color: #000099; font-style: italic;} + +/* Languages */ + +.alien {color: #543354;} +.tajaran {color: #803b56;} +.tajaran_signlang {color: #941c1c;} +.skrell {color: #00ced1;} +.soghun {color: #228b22;} +.nabber_lang {color: #525252;} +.solcom {color: #22228b;} +.changeling {color: #800080;} +.vox {color: #aa00aa;} +.rough {font-family: "Trebuchet MS", cursive#386891, sans-serif;} +.say_quote {font-family: Georgia, Verdana, sans-serif;} +.terran {color: #9c250b;} +.moon {color: #422863;} +.spacer {color: #ff6600;} + +.red_team {color: #b27676;} +.blue_team {color: #76abb2;} + +.interface {color: #bf00bf;} + +.good {color: #4f7529; font-weight: bold;} +.bad {color: #ee0000; font-weight: bold;} +.hypnophrase {color: #202020; font-weight: bold; animation: hypnocolor 1500ms infinite;} +@keyframes hypnocolor { + 0% { color: #202020; } + 25% { color: #4b02ac; } + 50% { color: #9f41f1; } + 75% { color: #541c9c; } + 100% { color: #7adbf3; } +} + +.phobia {color: #dd0000; font-size: 16pt; font-weight: bold; animation: phobia 750ms infinite;} +@keyframes phobia { + 0% { color: #f75a5a; } + 50% { color: #dd0000; } + 100% { color: #f75a5a; } +} + +.icon {height: 1em; width: auto;} + +.memo {color: #638500; text-align: center;} +.memoedit {text-align: center; font-size: 16px;} + +.connectionClosed, .fatalError {background: red; color: white; padding: 5px;} +.connectionClosed.restored {background: green;} +.internal.boldnshit {color: #3d5bc3; font-weight: bold;} + +/* HELPER CLASSES */ +.text-normal {font-weight: normal; font-style: normal;} +.hidden {display: none; visibility: hidden;} diff --git a/code/modules/goonchat/browserassets/html/browserOutput.html b/code/modules/goonchat/browserassets/html/browserOutput.html new file mode 100644 index 00000000..ff170ea3 --- /dev/null +++ b/code/modules/goonchat/browserassets/html/browserOutput.html @@ -0,0 +1,49 @@ + + + + Chat + + + + + + + + + +
            + +
            + Loading...

            + If this takes longer than 30 seconds, it will automatically reload a maximum of 5 times.
            + If it still doesn't work, use the bug report button at the top right of the window. +
            +
            +
            + +
            + + + + + diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js new file mode 100644 index 00000000..7e2d8bc6 --- /dev/null +++ b/code/modules/goonchat/browserassets/js/browserOutput.js @@ -0,0 +1,1159 @@ + +/***************************************** +* +* FUNCTION AND VAR DECLARATIONS +* +******************************************/ + +//DEBUG STUFF +var escaper = encodeURIComponent || escape; +var decoder = decodeURIComponent || unescape; +window.onerror = function(msg, url, line, col, error) { + if (document.location.href.indexOf("proc=debug") <= 0) { + var extra = !col ? '' : ' | column: ' + col; + extra += !error ? '' : ' | error: ' + error; + extra += !navigator.userAgent ? '' : ' | user agent: ' + navigator.userAgent; + var debugLine = 'Error: ' + msg + ' | url: ' + url + ' | line: ' + line + extra; + window.location = '?_src_=chat&proc=debug¶m[error]='+escaper(debugLine); + } + return true; +}; + +//Globals +window.status = 'Output'; +var $messages, $subOptions, $subAudio, $selectedSub, $contextMenu, $filterMessages, $last_message; +var opts = { + //General + 'messageCount': 0, //A count...of messages... + 'messageLimit': 2053, //A limit...for the messages... + 'scrollSnapTolerance': 10, //If within x pixels of bottom + 'clickTolerance': 10, //Keep focus if outside x pixels of mousedown position on mouseup + 'imageRetryDelay': 50, //how long between attempts to reload images (in ms) + 'imageRetryLimit': 50, //how many attempts should we make? + 'popups': 0, //Amount of popups opened ever + 'wasd': false, //Is the user in wasd mode? + 'priorChatHeight': 0, //Thing for height-resizing detection + 'restarting': false, //Is the round restarting? + 'darkmode':false, //Are we using darkmode? If not WHY ARE YOU LIVING IN 2009??? + + //Options menu + 'selectedSubLoop': null, //Contains the interval loop for closing the selected sub menu + 'suppressSubClose': false, //Whether or not we should be hiding the selected sub menu + 'highlightTerms': [], + 'highlightLimit': 5, + 'highlightColor': '#FFFF00', //The color of the highlighted message + 'pingDisabled': false, //Has the user disabled the ping counter + + //Ping display + 'lastPang': 0, //Timestamp of the last response from the server. + 'pangLimit': 35000, + 'pingTime': 0, //Timestamp of when ping sent + 'pongTime': 0, //Timestamp of when ping received + 'noResponse': false, //Tracks the state of the previous ping request + 'noResponseCount': 0, //How many failed pings? + + //Clicks + 'mouseDownX': null, + 'mouseDownY': null, + 'preventFocus': false, //Prevents switching focus to the game window + + //Client Connection Data + 'clientDataLimit': 5, + 'clientData': [], + + //Admin music volume update + 'volumeUpdateDelay': 5000, //Time from when the volume updates to data being sent to the server + 'volumeUpdating': false, //True if volume update function set to fire + 'updatedVolume': 0, //The volume level that is sent to the server + 'musicStartAt': 0, //The position the music starts playing + 'musicEndAt': 0, //The position the music... stops playing... if null, doesn't apply (so the music runs through) + + 'defaultMusicVolume': 25, + + 'messageCombining': true, + +}; +var replaceRegexes = {}; + +function clamp(val, min, max) { + return Math.max(min, Math.min(val, max)) +} + +function outerHTML(el) { + var wrap = document.createElement('div'); + wrap.appendChild(el.cloneNode(true)); + return wrap.innerHTML; +} + +//Polyfill for fucking date now because of course IE8 and below don't support it +if (!Date.now) { + Date.now = function now() { + return new Date().getTime(); + }; +} +//Polyfill for trim() (IE8 and below) +if (typeof String.prototype.trim !== 'function') { + String.prototype.trim = function () { + return this.replace(/^\s+|\s+$/g, ''); + }; +} + +// Linkify the contents of a node, within its parent. +function linkify(parent, insertBefore, text) { + var start = 0; + var match; + var regex = /(?:(?:https?:\/\/)|(?:www\.))(?:[^ ]*?\.[^ ]*?)+[-A-Za-z0-9+&@#\/%?=~_|$!:,.;()]+/ig; + while ((match = regex.exec(text)) !== null) { + // add the unmatched text + parent.insertBefore(document.createTextNode(text.substring(start, match.index)), insertBefore); + + var href = match[0]; + if (!/^https?:\/\//i.test(match[0])) { + href = "http://" + match[0]; + } + + // add the link + var link = document.createElement("a"); + link.href = href; + link.textContent = match[0]; + parent.insertBefore(link, insertBefore); + + start = regex.lastIndex; + } + if (start !== 0) { + // add the remaining text and remove the original text node + parent.insertBefore(document.createTextNode(text.substring(start)), insertBefore); + parent.removeChild(insertBefore); + } +} + +// Recursively linkify the children of a given node. +function linkify_node(node) { + var children = node.childNodes; + // work backwards to avoid the risk of looping forever on our own output + for (var i = children.length - 1; i >= 0; --i) { + var child = children[i]; + if (child.nodeType == Node.TEXT_NODE) { + // text is to be linkified + linkify(node, child, child.textContent); + } else if (child.nodeName != "A" && child.nodeName != "a") { + // do not linkify existing links + linkify_node(child); + } + } +} + +//Shit fucking piece of crap that doesn't work god fuckin damn it +function linkify_fallback(text) { + var rex = /((?:'+$0+''; + } + else { + return $1 ? $0: ''+$0+''; + } + }); +} + +function byondDecode(message) { + // Basically we url_encode twice server side so we can manually read the encoded version and actually do UTF-8. + // The replace for + is because FOR SOME REASON, BYOND replaces spaces with a + instead of %20, and a plus with %2b. + // Marvelous. + message = message.replace(/\+/g, "%20"); + try { + // This is a workaround for the above not always working when BYOND's shitty url encoding breaks. (byond bug id:2399401) + if (decodeURIComponent) { + message = decodeURIComponent(message); + } else { + throw new Error("Easiest way to trigger the fallback") + } + } catch (err) { + message = unescape(message); + } + return message; +} + +function replaceRegex() { + var selectedRegex = replaceRegexes[$(this).attr('replaceRegex')]; + if (selectedRegex) { + var replacedText = $(this).html().replace(selectedRegex[0], selectedRegex[1]); + $(this).html(replacedText); + } + $(this).removeAttr('replaceRegex'); +} + +//Actually turns the highlight term match into appropriate html +function addHighlightMarkup(match) { + var extra = ''; + if (opts.highlightColor) { + extra += ' style="background-color: '+opts.highlightColor+'"'; + } + return ''+match+''; +} + +//Highlights words based on user settings +function highlightTerms(el) { + if (el.children.length > 0) { + for(var h = 0; h < el.children.length; h++){ + highlightTerms(el.children[h]); + } + } + + var hasTextNode = false; + for (var node = 0; node < el.childNodes.length; node++) + { + if (el.childNodes[node].nodeType === 3) + { + hasTextNode = true; + break; + } + } + + if (hasTextNode) { //If element actually has text + var newText = ''; + for (var c = 0; c < el.childNodes.length; c++) { //Each child element + if (el.childNodes[c].nodeType === 3) { //Is it text only? + var words = el.childNodes[c].data.split(' '); + for (var w = 0; w < words.length; w++) { //Each word in the text + var newWord = null; + for (var i = 0; i < opts.highlightTerms.length; i++) { //Each highlight term + if (opts.highlightTerms[i] && words[w].toLowerCase().indexOf(opts.highlightTerms[i].toLowerCase()) > -1) { //If a match is found + newWord = words[w].replace("<", "<").replace(new RegExp(opts.highlightTerms[i], 'gi'), addHighlightMarkup); + break; + } + if (window.console) + console.log(newWord) + } + newText += newWord || words[w].replace("<", "<"); + newText += w >= words.length ? '' : ' '; + } + } else { //Every other type of element + newText += outerHTML(el.childNodes[c]); + } + } + el.innerHTML = newText; + } +} + +function iconError(E) { + var that = this; + setTimeout(function() { + var attempts = $(that).data('reload_attempts'); + if (typeof attempts === 'undefined' || !attempts) { + attempts = 1; + } + if (attempts > opts.imageRetryLimit) + return; + var src = that.src; + that.src = null; + that.src = src+'#'+attempts; + $(that).data('reload_attempts', ++attempts); + }, opts.imageRetryDelay); +} + +//Send a message to the client +function output(message, flag) { + if (typeof message === 'undefined') { + return; + } + if (typeof flag === 'undefined') { + flag = ''; + } + + if (flag !== 'internal') + opts.lastPang = Date.now(); + + message = byondDecode(message).trim(); + + //The behemoth of filter-code (for Admin message filters) + //Note: This is proooobably hella inefficient + var filteredOut = false; + if (opts.hasOwnProperty('showMessagesFilters') && !opts.showMessagesFilters['All'].show) { + //Get this filter type (defined by class on message) + var messageHtml = $.parseHTML(message), + messageClasses; + if (opts.hasOwnProperty('filterHideAll') && opts.filterHideAll) { + var internal = false; + messageClasses = (!!$(messageHtml).attr('class') ? $(messageHtml).attr('class').split(/\s+/) : false); + if (messageClasses) { + for (var i = 0; i < messageClasses.length; i++) { //Every class + if (messageClasses[i] == 'internal') { + internal = true; + break; + } + } + } + if (!internal) { + filteredOut = 'All'; + } + } else { + //If the element or it's child have any classes + if (!!$(messageHtml).attr('class') || !!$(messageHtml).children().attr('class')) { + messageClasses = $(messageHtml).attr('class').split(/\s+/); + if (!!$(messageHtml).children().attr('class')) { + messageClasses = messageClasses.concat($(messageHtml).children().attr('class').split(/\s+/)); + } + var tempCount = 0; + for (var i = 0; i < messageClasses.length; i++) { //Every class + var thisClass = messageClasses[i]; + $.each(opts.showMessagesFilters, function(key, val) { //Every filter + if (key !== 'All' && val.show === false && typeof val.match != 'undefined') { + for (var i = 0; i < val.match.length; i++) { + var matchClass = val.match[i]; + if (matchClass == thisClass) { + filteredOut = key; + break; + } + } + } + if (filteredOut) return false; + }); + if (filteredOut) break; + tempCount++; + } + } else { + if (!opts.showMessagesFilters['Misc'].show) { + filteredOut = 'Misc'; + } + } + } + } + + //Stuff we do along with appending a message + var atBottom = false; + if (!filteredOut) { + var bodyHeight = $('body').height(); + var messagesHeight = $messages.outerHeight(); + var scrollPos = $('body,html').scrollTop(); + + //Should we snap the output to the bottom? + if (bodyHeight + scrollPos >= messagesHeight - opts.scrollSnapTolerance) { + atBottom = true; + if ($('#newMessages').length) { + $('#newMessages').remove(); + } + //If not, put the new messages box in + } else { + if ($('#newMessages').length) { + var messages = $('#newMessages .number').text(); + messages = parseInt(messages); + messages++; + $('#newMessages .number').text(messages); + if (messages == 2) { + $('#newMessages .messageWord').append('s'); + } + } else { + $messages.after('1 new message '); + } + } + } + + opts.messageCount++; + + //Pop the top message off if history limit reached + if (opts.messageCount >= opts.messageLimit) { + $messages.children('div.entry:first-child').remove(); + opts.messageCount--; //I guess the count should only ever equal the limit + } + + // Create the element - if combining is off, we use it, and if it's on, we + // might discard it bug need to check its text content. Some messages vary + // only in HTML markup, have the same text content, and should combine. + var entry = document.createElement('div'); + entry.innerHTML = message; + var trimmed_message = entry.textContent || entry.innerText || ""; + + var handled = false; + if (opts.messageCombining) { + var lastmessages = $messages.children('div.entry:last-child').last(); + if (lastmessages.length && $last_message && $last_message == trimmed_message) { + var badge = lastmessages.children('.r').last(); + if (badge.length) { + badge = badge.detach(); + badge.text(parseInt(badge.text()) + 1); + } else { + badge = $('', {'class': 'r', 'text': 2}); + } + lastmessages.html(message); + lastmessages.find('[replaceRegex]').each(replaceRegex); + lastmessages.append(badge); + badge.animate({ + "font-size": "0.9em" + }, 100, function() { + badge.animate({ + "font-size": "0.7em" + }, 100); + + }); + if (parseInt(lastmessages.css("font-size")) < 18) //Completely arbitrary max size + lastmessages.css("font-size", "+=2") + opts.messageCount--; + handled = true; + } + } + + if (!handled) { + //Actually append the message + entry.className = 'entry'; + + if (filteredOut) { + entry.className += ' hidden'; + entry.setAttribute('data-filter', filteredOut); + } + + $(entry).find('[replaceRegex]').each(replaceRegex); + + $last_message = trimmed_message; + $messages[0].appendChild(entry); + $(entry).find("img.icon").error(iconError); + + var to_linkify = $(entry).find(".linkify"); + if (typeof Node === 'undefined') { + // Linkify fallback for old IE + for(var i = 0; i < to_linkify.length; ++i) { + to_linkify[i].innerHTML = linkify_fallback(to_linkify[i].innerHTML); + } + } else { + // Linkify for modern IE versions + for(var i = 0; i < to_linkify.length; ++i) { + linkify_node(to_linkify[i]); + } + } + + //Actually do the snap + //Stuff we can do after the message shows can go here, in the interests of responsiveness + if (opts.highlightTerms && opts.highlightTerms.length > 0) { + highlightTerms(entry); + } + } + + if (!filteredOut && atBottom) { + $('body,html').scrollTop($messages.outerHeight()); + } +} + +function internalOutput(message, flag) +{ + output(escaper(message), flag) +} + +//Runs a route within byond, client or server side. Consider this "ehjax" for byond. +function runByond(uri) { + window.location = uri; +} + +function setCookie(cname, cvalue, exdays) { + cvalue = escaper(cvalue); + var d = new Date(); + d.setTime(d.getTime() + (exdays*24*60*60*1000)); + var expires = 'expires='+d.toUTCString(); + document.cookie = cname + '=' + cvalue + '; ' + expires + "; path=/"; +} + +function getCookie(cname) { + var name = cname + '='; + var ca = document.cookie.split(';'); + for(var i=0; i < ca.length; i++) { + var c = ca[i]; + while (c.charAt(0)==' ') c = c.substring(1); + if (c.indexOf(name) === 0) { + return decoder(c.substring(name.length,c.length)); + } + } + return ''; +} + +function rgbToHex(R,G,B) {return toHex(R)+toHex(G)+toHex(B);} +function toHex(n) { + n = parseInt(n,10); + if (isNaN(n)) return "00"; + n = Math.max(0,Math.min(n,255)); + return "0123456789ABCDEF".charAt((n-n%16)/16) + "0123456789ABCDEF".charAt(n%16); +} + +function swap() { //Swap to darkmode + if (opts.darkmode){ + document.getElementById("sheetofstyles").href = "browserOutput_white.css"; + opts.darkmode = false; + runByond('?_src_=chat&proc=swaptolightmode'); + } else { + document.getElementById("sheetofstyles").href = "browserOutput.css"; + opts.darkmode = true; + runByond('?_src_=chat&proc=swaptodarkmode'); + } + setCookie('darkmode', (opts.darkmode ? 'true' : 'false'), 365); +} + +function handleClientData(ckey, ip, compid) { + //byond sends player info to here + var currentData = {'ckey': ckey, 'ip': ip, 'compid': compid}; + if (opts.clientData && !$.isEmptyObject(opts.clientData)) { + runByond('?_src_=chat&proc=analyzeClientData¶m[cookie]='+JSON.stringify({'connData': opts.clientData})); + + for (var i = 0; i < opts.clientData.length; i++) { + var saved = opts.clientData[i]; + if (currentData.ckey == saved.ckey && currentData.ip == saved.ip && currentData.compid == saved.compid) { + return; //Record already exists + } + } + + if (opts.clientData.length >= opts.clientDataLimit) { + opts.clientData.shift(); + } + } else { + runByond('?_src_=chat&proc=analyzeClientData¶m[cookie]=none'); + } + + //Update the cookie with current details + opts.clientData.push(currentData); + setCookie('connData', JSON.stringify(opts.clientData), 365); +} + +//Server calls this on ehjax response +//Or, y'know, whenever really +function ehjaxCallback(data) { + opts.lastPang = Date.now(); + if (data == 'softPang') { + return; + } else if (data == 'pang') { + opts.pingCounter = 0; //reset + opts.pingTime = Date.now(); + runByond('?_src_=chat&proc=ping'); + + } else if (data == 'pong') { + if (opts.pingDisabled) {return;} + opts.pongTime = Date.now(); + var pingDuration = Math.ceil((opts.pongTime - opts.pingTime) / 2); + $('#pingMs').text(pingDuration+'ms'); + pingDuration = Math.min(pingDuration, 255); + var red = pingDuration; + var green = 255 - pingDuration; + var blue = 0; + var hex = rgbToHex(red, green, blue); + $('#pingDot').css('color', '#'+hex); + + } else if (data == 'roundrestart') { + opts.restarting = true; + internalOutput('
            The connection has been closed because the server is restarting. Please wait while you automatically reconnect.
            ', 'internal'); + } else if (data == 'stopMusic') { + $('#adminMusic').prop('src', ''); + } else { + //Oh we're actually being sent data instead of an instruction + var dataJ; + try { + dataJ = $.parseJSON(data); + } catch (e) { + //But...incorrect :sadtrombone: + window.onerror('JSON: '+e+'. '+data, 'browserOutput.html', 327); + return; + } + data = dataJ; + + if (data.clientData) { + if (opts.restarting) { + opts.restarting = false; + $('.connectionClosed.restarting:not(.restored)').addClass('restored').text('The round restarted and you successfully reconnected!'); + } + if (!data.clientData.ckey && !data.clientData.ip && !data.clientData.compid) { + //TODO: Call shutdown perhaps + return; + } else { + handleClientData(data.clientData.ckey, data.clientData.ip, data.clientData.compid); + } + sendVolumeUpdate(); + } else if (data.adminMusic) { + if (typeof data.adminMusic === 'string') { + var adminMusic = byondDecode(data.adminMusic); + var bindLoadedData = false; + adminMusic = adminMusic.match(/https?:\/\/\S+/) || ''; + if (data.musicRate) { + var newRate = Number(data.musicRate); + if(newRate) { + $('#adminMusic').prop('defaultPlaybackRate', newRate); + } + } else { + $('#adminMusic').prop('defaultPlaybackRate', 1.0); + } + if (data.musicSeek) { + opts.musicStartAt = Number(data.musicSeek) || 0; + bindLoadedData = true; + } else { + opts.musicStartAt = 0; + } + if (data.musicHalt) { + opts.musicEndAt = Number(data.musicHalt) || null; + bindLoadedData = true; + } + if (bindLoadedData) { + $('#adminMusic').one('loadeddata', adminMusicLoadedData); + } + $('#adminMusic').prop('src', adminMusic); + $('#adminMusic').trigger("play"); + } + } else if (data.syncRegex) { + for (var i in data.syncRegex) { + + var regexData = data.syncRegex[i]; + var regexName = regexData[0]; + var regexFlags = regexData[1]; + var regexReplaced = regexData[2]; + + replaceRegexes[i] = [new RegExp(regexName, regexFlags), regexReplaced]; + } + } + } +} + +function createPopup(contents, width) { + opts.popups++; + $('body').append(''); + + //Attach close popup event + var $popup = $('#popup'+opts.popups); + var height = $popup.outerHeight(); + $popup.css({'height': height+'px', 'margin': '-'+(height/2)+'px 0 0 -'+(width/2)+'px'}); + + $popup.on('click', '.close', function(e) { + e.preventDefault(); + $popup.remove(); + }); +} + +function toggleWasd(state) { + opts.wasd = (state == 'on' ? true : false); +} + +function sendVolumeUpdate() { + opts.volumeUpdating = false; + if(opts.updatedVolume) { + runByond('?_src_=chat&proc=setMusicVolume¶m[volume]='+opts.updatedVolume); + } +} + +function adminMusicEndCheck(event) { + if (opts.musicEndAt) { + if ($('#adminMusic').prop('currentTime') >= opts.musicEndAt) { + $('#adminMusic').off(event); + $('#adminMusic').trigger('pause'); + $('#adminMusic').prop('src', ''); + } + } else { + $('#adminMusic').off(event); + } +} + +function adminMusicLoadedData(event) { + if (opts.musicStartAt && ($('#adminMusic').prop('duration') === Infinity || (opts.musicStartAt <= $('#adminMusic').prop('duration'))) ) { + $('#adminMusic').prop('currentTime', opts.musicStartAt); + } + if (opts.musicEndAt) { + $('#adminMusic').on('timeupdate', adminMusicEndCheck); + } +} + +function subSlideUp() { + $(this).removeClass('scroll'); + $(this).css('height', ''); +} + +function startSubLoop() { + if (opts.selectedSubLoop) { + clearInterval(opts.selectedSubLoop); + } + return setInterval(function() { + if (!opts.suppressSubClose && $selectedSub.is(':visible')) { + $selectedSub.slideUp('fast', subSlideUp); + clearInterval(opts.selectedSubLoop); + } + }, 5000); //every 5 seconds +} + +function handleToggleClick($sub, $toggle) { + if ($selectedSub !== $sub && $selectedSub.is(':visible')) { + $selectedSub.slideUp('fast', subSlideUp); + } + $selectedSub = $sub + if ($selectedSub.is(':visible')) { + $selectedSub.slideUp('fast', subSlideUp); + clearInterval(opts.selectedSubLoop); + } else { + $selectedSub.slideDown('fast', function() { + var windowHeight = $(window).height(); + var toggleHeight = $toggle.outerHeight(); + var priorSubHeight = $selectedSub.outerHeight(); + var newSubHeight = windowHeight - toggleHeight; + $(this).height(newSubHeight); + if (priorSubHeight > (windowHeight - toggleHeight)) { + $(this).addClass('scroll'); + } + }); + opts.selectedSubLoop = startSubLoop(); + } +} + +/***************************************** +* +* DOM READY +* +******************************************/ + +if (typeof $ === 'undefined') { + var div = document.getElementById('loading').childNodes[1]; + div += '

            ERROR: Jquery did not load.'; +} + +$(function() { + $messages = $('#messages'); + $subOptions = $('#subOptions'); + $subAudio = $('#subAudio'); + $selectedSub = $subOptions; + + //Hey look it's a controller loop! + setInterval(function() { + if (opts.lastPang + opts.pangLimit < Date.now() && !opts.restarting) { //Every pingLimit + if (!opts.noResponse) { //Only actually append a message if the previous ping didn't also fail (to prevent spam) + opts.noResponse = true; + opts.noResponseCount++; + internalOutput('
            You are either AFK, experiencing lag or the connection has closed.
            ', 'internal'); + } + } else if (opts.noResponse) { //Previous ping attempt failed ohno + $('.connectionClosed[data-count="'+opts.noResponseCount+'"]:not(.restored)').addClass('restored').text('Your connection has been restored (probably)!'); + opts.noResponse = false; + } + }, 2000); //2 seconds + + + /***************************************** + * + * LOAD SAVED CONFIG + * + ******************************************/ + var savedConfig = { + 'sfontSize': getCookie('fontsize'), + 'slineHeight': getCookie('lineheight'), + 'spingDisabled': getCookie('pingdisabled'), + 'shighlightTerms': getCookie('highlightterms'), + 'shighlightColor': getCookie('highlightcolor'), + 'smusicVolume': getCookie('musicVolume'), + 'smessagecombining': getCookie('messagecombining'), + 'sdarkmode': getCookie('darkmode'), + }; + + if (savedConfig.sfontSize) { + $messages.css('font-size', savedConfig.sfontSize); + internalOutput('Loaded font size setting of: '+savedConfig.sfontSize+'', 'internal'); + } + if (savedConfig.slineHeight) { + $("body").css('line-height', savedConfig.slineHeight); + internalOutput('Loaded line height setting of: '+savedConfig.slineHeight+'', 'internal'); + } + if(savedConfig.sdarkmode == 'true'){ + swap(); + } + if (savedConfig.spingDisabled) { + if (savedConfig.spingDisabled == 'true') { + opts.pingDisabled = true; + $('#ping').hide(); + } + internalOutput('Loaded ping display of: '+(opts.pingDisabled ? 'hidden' : 'visible')+'', 'internal'); + } + if (savedConfig.shighlightTerms) { + var savedTerms = $.parseJSON(savedConfig.shighlightTerms); + var actualTerms = ''; + for (var i = 0; i < savedTerms.length; i++) { + if (savedTerms[i]) { + actualTerms += savedTerms[i] + ', '; + } + } + if (actualTerms) { + actualTerms = actualTerms.substring(0, actualTerms.length - 2); + internalOutput('Loaded highlight strings of: ' + actualTerms+'', 'internal'); + opts.highlightTerms = savedTerms; + } + } + if (savedConfig.shighlightColor) { + opts.highlightColor = savedConfig.shighlightColor; + internalOutput('Loaded highlight color of: '+savedConfig.shighlightColor+'', 'internal'); + } + if (savedConfig.smusicVolume) { + var newVolume = clamp(savedConfig.smusicVolume, 0, 100); + $('#adminMusic').prop('volume', newVolume / 100); + $('#musicVolume').val(newVolume); + opts.updatedVolume = newVolume; + sendVolumeUpdate(); + internalOutput('Loaded music volume of: '+savedConfig.smusicVolume+'', 'internal'); + } + else{ + $('#adminMusic').prop('volume', opts.defaultMusicVolume / 100); + } + + if (savedConfig.smessagecombining) { + if (savedConfig.smessagecombining == 'false') { + opts.messageCombining = false; + } else { + opts.messageCombining = true; + } + } + (function() { + var dataCookie = getCookie('connData'); + if (dataCookie) { + var dataJ; + try { + dataJ = $.parseJSON(dataCookie); + } catch (e) { + window.onerror('JSON '+e+'. '+dataCookie, 'browserOutput.html', 434); + return; + } + opts.clientData = dataJ; + } + })(); + + + /***************************************** + * + * BASE CHAT OUTPUT EVENTS + * + ******************************************/ + + $('body').on('click', 'a', function(e) { + e.preventDefault(); + }); + + $('body').on('mousedown', function(e) { + var $target = $(e.target); + + if ($contextMenu && opts.hasOwnProperty('contextMenuTarget') && opts.contextMenuTarget) { + hideContextMenu(); + return false; + } + + if ($target.is('a') || $target.parent('a').length || $target.is('input') || $target.is('textarea')) { + opts.preventFocus = true; + } else { + opts.preventFocus = false; + opts.mouseDownX = e.pageX; + opts.mouseDownY = e.pageY; + } + }); + + $messages.on('mousedown', function(e) { + if ($selectedSub && $selectedSub.is(':visible')) { + $selectedSub.slideUp('fast', subSlideUp); + clearInterval(opts.selectedSubLoop); + } + }); + + $('body').on('mouseup', function(e) { + if (!opts.preventFocus && + (e.pageX >= opts.mouseDownX - opts.clickTolerance && e.pageX <= opts.mouseDownX + opts.clickTolerance) && + (e.pageY >= opts.mouseDownY - opts.clickTolerance && e.pageY <= opts.mouseDownY + opts.clickTolerance) + ) { + opts.mouseDownX = null; + opts.mouseDownY = null; + runByond('byond://winset?mapwindow.map.focus=true'); + } + }); + + $messages.on('click', 'a', function(e) { + var href = $(this).attr('href'); + $(this).addClass('visited'); + if (href[0] == '?' || (href.length >= 8 && href.substring(0,8) == 'byond://')) { + runByond(href); + } else { + href = escaper(href); + runByond('?action=openLink&link='+href); + } + }); + + //Fuck everything about this event. Will look into alternatives. + $('body').on('keydown', function(e) { + if (e.target.nodeName == 'INPUT' || e.target.nodeName == 'TEXTAREA') { + return; + } + + if (e.ctrlKey || e.altKey || e.shiftKey) { //Band-aid "fix" for allowing ctrl+c copy paste etc. Needs a proper fix. + return; + } + + e.preventDefault() + + var k = e.which; + // Hardcoded because else there would be no feedback message. + if (k == 113) { // F2 + runByond('byond://winset?screenshot=auto'); + internalOutput('Screenshot taken', 'internal'); + } + + var c = ""; + switch (k) { + case 8: + c = 'BACK'; + case 9: + c = 'TAB'; + case 13: + c = 'ENTER'; + case 19: + c = 'PAUSE'; + case 27: + c = 'ESCAPE'; + case 33: // Page up + c = 'NORTHEAST'; + case 34: // Page down + c = 'SOUTHEAST'; + case 35: // End + c = 'SOUTHWEST'; + case 36: // Home + c = 'NORTHWEST'; + case 37: + c = 'WEST'; + case 38: + c = 'NORTH'; + case 39: + c = 'EAST'; + case 40: + c = 'SOUTH'; + case 45: + c = 'INSERT'; + case 46: + c = 'DELETE'; + case 93: // That weird thing to the right of alt gr. + c = 'APPS'; + + default: + c = String.fromCharCode(k); + } + + if (c.length == 0) { + if (!e.shiftKey) { + c = c.toLowerCase(); + } + runByond('byond://winset?mapwindow.map.focus=true;mainwindow.input.text='+c); + return false; + } else { + runByond('byond://winset?mapwindow.map.focus=true'); + return false; + } + }); + + //Mildly hacky fix for scroll issues on mob change (interface gets resized sometimes, messing up snap-scroll) + $(window).on('resize', function(e) { + if ($(this).height() !== opts.priorChatHeight) { + $('body,html').scrollTop($messages.outerHeight()); + opts.priorChatHeight = $(this).height(); + } + }); + + + /***************************************** + * + * OPTIONS INTERFACE EVENTS + * + ******************************************/ + + $('body').on('click', '#newMessages', function(e) { + var messagesHeight = $messages.outerHeight(); + $('body,html').scrollTop(messagesHeight); + $('#newMessages').remove(); + runByond('byond://winset?mapwindow.map.focus=true'); + }); + + $('#toggleOptions').click(function(e) { + handleToggleClick($subOptions, $(this)); + }); + $('#darkmodetoggle').click(function(e) { + swap(); + }); + $('#toggleAudio').click(function(e) { + handleToggleClick($subAudio, $(this)); + }); + + $('.sub, .toggle').mouseenter(function() { + opts.suppressSubClose = true; + }); + + $('.sub, .toggle').mouseleave(function() { + opts.suppressSubClose = false; + }); + + $('#decreaseFont').click(function(e) { + var fontSize = parseInt($messages.css('font-size')); + fontSize = fontSize - 1 + 'px'; + $messages.css({'font-size': fontSize}); + setCookie('fontsize', fontSize, 365); + internalOutput('Font size set to '+fontSize+'', 'internal'); + }); + + $('#increaseFont').click(function(e) { + var fontSize = parseInt($messages.css('font-size')); + fontSize = fontSize + 1 + 'px'; + $messages.css({'font-size': fontSize}); + setCookie('fontsize', fontSize, 365); + internalOutput('Font size set to '+fontSize+'', 'internal'); + }); + + $('#decreaseLineHeight').click(function(e) { + var Heightline = parseFloat($("body").css('line-height')); + var Sizefont = parseFloat($("body").css('font-size')); + var lineheightvar = Heightline / Sizefont + lineheightvar -= 0.1; + lineheightvar = lineheightvar.toFixed(1) + $("body").css({'line-height': lineheightvar}); + setCookie('lineheight', lineheightvar, 365); + internalOutput('Line height set to '+lineheightvar+'', 'internal'); + }); + + $('#increaseLineHeight').click(function(e) { + var Heightline = parseFloat($("body").css('line-height')); + var Sizefont = parseFloat($("body").css('font-size')); + var lineheightvar = Heightline / Sizefont + lineheightvar += 0.1; + lineheightvar = lineheightvar.toFixed(1) + $("body").css({'line-height': lineheightvar}); + setCookie('lineheight', lineheightvar, 365); + internalOutput('Line height set to '+lineheightvar+'', 'internal'); + }); + + $('#togglePing').click(function(e) { + if (opts.pingDisabled) { + $('#ping').slideDown('fast'); + opts.pingDisabled = false; + } else { + $('#ping').slideUp('fast'); + opts.pingDisabled = true; + } + setCookie('pingdisabled', (opts.pingDisabled ? 'true' : 'false'), 365); + }); + + $('#saveLog').click(function(e) { + // Requires IE 10+ to issue download commands. Just opening a popup + // window will cause Ctrl+S to save a blank page, ignoring innerHTML. + if (!window.Blob) { + output('This function is only supported on IE 10+. Upgrade if possible.', 'internal'); + return; + } + + $.ajax({ + type: 'GET', + url: 'browserOutput_white.css', + success: function(styleData) { + var blob = new Blob(['Chat Log', $messages.html(), '']); + + var fname = 'SS13 Chat Log'; + var date = new Date(), month = date.getMonth(), day = date.getDay(), hours = date.getHours(), mins = date.getMinutes(), secs = date.getSeconds(); + fname += ' ' + date.getFullYear() + '-' + (month < 10 ? '0' : '') + month + '-' + (day < 10 ? '0' : '') + day; + fname += ' ' + (hours < 10 ? '0' : '') + hours + (mins < 10 ? '0' : '') + mins + (secs < 10 ? '0' : '') + secs; + fname += '.html'; + + window.navigator.msSaveBlob(blob, fname); + } + }); + }); + + $('#highlightTerm').click(function(e) { + if ($('.popup .highlightTerm').is(':visible')) {return;} + var termInputs = ''; + for (var i = 0; i < opts.highlightLimit; i++) { + termInputs += '
            '; + } + var popupContent = '
            String Highlighting
            ' + + '
            ' + + '
            Choose up to '+opts.highlightLimit+' strings that will highlight the line when they appear in chat.
            ' + + '
            ' + + termInputs + + '
            ' + + '
            ' + + '
            ' + + '
            '; + createPopup(popupContent, 250); + }); + + $('body').on('keyup', '#highlightColor', function() { + var color = $('#highlightColor').val(); + color = color.trim(); + if (!color || color.charAt(0) != '#') return; + $('#highlightColor').css('background-color', color); + }); + + $('body').on('submit', '#highlightTermForm', function(e) { + e.preventDefault(); + + var count = 0; + while (count < opts.highlightLimit) { + var term = $('#highlightTermInput'+count).val(); + if (term) { + term = term.trim(); + if (term === '') { + opts.highlightTerms[count] = null; + } else { + opts.highlightTerms[count] = term.toLowerCase(); + } + } else { + opts.highlightTerms[count] = null; + } + count++; + } + + var color = $('#highlightColor').val(); + color = color.trim(); + if (color == '' || color.charAt(0) != '#') { + opts.highlightColor = '#FFFF00'; + } else { + opts.highlightColor = color; + } + var $popup = $('#highlightPopup').closest('.popup'); + $popup.remove(); + + setCookie('highlightterms', JSON.stringify(opts.highlightTerms), 365); + setCookie('highlightcolor', opts.highlightColor, 365); + }); + + $('#clearMessages').click(function() { + $messages.empty(); + opts.messageCount = 0; + }); + + $('#musicVolumeSpan').hover(function() { + $('#musicVolumeText').addClass('hidden'); + $('#musicVolume').removeClass('hidden'); + }, function() { + $('#musicVolume').addClass('hidden'); + $('#musicVolumeText').removeClass('hidden'); + }); + + $('#musicVolume').change(function() { + var newVolume = $('#musicVolume').val(); + newVolume = clamp(newVolume, 0, 100); + $('#adminMusic').prop('volume', newVolume / 100); + setCookie('musicVolume', newVolume, 365); + opts.updatedVolume = newVolume; + if(!opts.volumeUpdating) { + setTimeout(sendVolumeUpdate, opts.volumeUpdateDelay); + opts.volumeUpdating = true; + } + }); + + $('#toggleCombine').click(function(e) { + opts.messageCombining = !opts.messageCombining; + setCookie('messagecombining', (opts.messageCombining ? 'true' : 'false'), 365); + }); + + $('img.icon').error(iconError); + + + + + /***************************************** + * + * KICK EVERYTHING OFF + * + ******************************************/ + + runByond('?_src_=chat&proc=doneLoading'); + if ($('#loading').is(':visible')) { + $('#loading').remove(); + } + $('#userBar').show(); + opts.priorChatHeight = $(window).height(); +}); diff --git a/code/modules/goonchat/browserassets/js/jquery.min.js b/code/modules/goonchat/browserassets/js/jquery.min.js new file mode 100644 index 00000000..ab28a247 --- /dev/null +++ b/code/modules/goonchat/browserassets/js/jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
            ",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h; +if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
            a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/
            ","
            "],tr:[2,"","
            "],col:[2,"","
            "],td:[3,"","
            "],_default:k.htmlSerialize?[0,"",""]:[1,"X
            ","
            "]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m(" + + + + "} + +/obj/item/weapon/book/manual/robotics_cyborgs + name = "Cyborgs for Dummies" + icon_state = "borgbook" + author = "XISC" + title = "Cyborgs for Dummies" + + dat = {" + + + + + +

            Cyborgs for Dummies

            + +

            Chapters

            + +
              +
            1. Cyborg Related Equipment
            2. +
            3. Cyborg Modules
            4. +
            5. Cyborg Construction
            6. +
            7. Cyborg Maintenance
            8. +
            9. Cyborg Repairs
            10. +
            11. In Case of Emergency
            12. +
            + + +

            Cyborg Related Equipment

            + +

            Exosuit Fabricator

            + The Exosuit Fabricator is the most important piece of equipment related to cyborgs. It allows the construction of the core cyborg parts. Without these machines, cyborgs cannot be built. It seems that they may also benefit from advanced research techniques. + +

            Cyborg Recharging Station

            + This useful piece of equipment will suck power out of the power systems to charge a cyborg's power cell back up to full charge. + +

            Robotics Control Console

            + This useful piece of equipment can be used to immobilize or destroy a cyborg. A word of warning: Cyborgs are expensive pieces of equipment, do not destroy them without good reason, or the Company may see to it that it never happens again. + + +

            Cyborg Modules

            + When a cyborg is created it picks out of an array of modules to designate its purpose. There are 6 different cyborg modules. + +

            Standard Cyborg

            + The standard cyborg module is a multi-purpose cyborg. It is equipped with various modules, allowing it to do basic tasks.
            A Standard Cyborg comes with: +
              +
            • Crowbar
            • +
            • Stun Baton
            • +
            • Health Analyzer
            • +
            • Fire Extinguisher
            • +
            + +

            Engineering Cyborg

            + The Engineering cyborg module comes equipped with various engineering-related tools to help with engineering-related tasks.
            An Engineering Cyborg comes with: +
              +
            • A basic set of engineering tools
            • +
            • Metal Synthesizer
            • +
            • Reinforced Glass Synthesizer
            • +
            • An RCD
            • +
            • Wire Synthesizer
            • +
            • Fire Extinguisher
            • +
            • Built-in Optical Meson Scanners
            • +
            + +

            Mining Cyborg

            + The Mining Cyborg module comes equipped with the latest in mining equipment. They are efficient at mining due to no need for oxygen, but their power cells limit their time in the mines.
            A Mining Cyborg comes with: +
              +
            • Jackhammer
            • +
            • Shovel
            • +
            • Mining Satchel
            • +
            • Built-in Optical Meson Scanners
            • +
            + +

            Security Cyborg

            + The Security Cyborg module is equipped with effective security measures used to apprehend and arrest criminals without harming them a bit.
            A Security Cyborg comes with: +
              +
            • Stun Baton
            • +
            • Handcuffs
            • +
            • Taser
            • +
            + +

            Janitor Cyborg

            + The Janitor Cyborg module is equipped with various cleaning-facilitating devices.
            A Janitor Cyborg comes with: +
              +
            • Mop
            • +
            • Hand Bucket
            • +
            • Cleaning Spray Synthesizer and Spray Nozzle
            • +
            + +

            Service Cyborg

            + The service cyborg module comes ready to serve your human needs. It includes various entertainment and refreshment devices. Occasionally some service cyborgs may have been referred to as "Bros."
            A Service Cyborg comes with: +
              +
            • Shaker
            • +
            • Industrial Dropper
            • +
            • Platter
            • +
            • Beer Synthesizer
            • +
            • Zippo Lighter
            • +
            • Rapid-Service-Fabricator (Produces various entertainment and refreshment objects)
            • +
            • Pen
            • +
            + +

            Cyborg Construction

            + Cyborg construction is a rather easy process, requiring a decent amount of metal and a few other supplies.
            The required materials to make a cyborg are: +
              +
            • Metal
            • +
            • Two Flashes
            • +
            • One Power Cell (Preferably rated to 15000w)
            • +
            • Some electrical wires
            • +
            • One Human Brain
            • +
            • One Man-Machine Interface
            • +
            + Once you have acquired the materials, you can start on construction of your cyborg.
            To construct a cyborg, follow the steps below: +
              +
            1. Start the Exosuit Fabricators constructing all of the cyborg parts
            2. +
            3. While the parts are being constructed, take your human brain, and place it inside the Man-Machine Interface
            4. +
            5. Once you have a Robot Head, place your two flashes inside the eye sockets
            6. +
            7. Once you have your Robot Chest, wire the Robot chest, then insert the power cell
            8. +
            9. Attach all of the Robot parts to the Robot frame
            10. +
            11. Insert the Man-Machine Interface (With the Brain inside) into the Robot Body
            12. +
            13. Congratulations! You have a new cyborg!
            14. +
            + +

            Cyborg Maintenance

            + Occasionally Cyborgs may require maintenance of a couple types, this could include replacing a power cell with a charged one, or possibly maintaining the cyborg's internal wiring. + +

            Replacing a Power Cell

            + Replacing a Power cell is a common type of maintenance for cyborgs. It usually involves replacing the cell with a fully charged one, or upgrading the cell with a larger capacity cell.
            The steps to replace a cell are as follows: +
              +
            1. Unlock the Cyborg's Interface by swiping your ID on it
            2. +
            3. Open the Cyborg's outer panel using a crowbar
            4. +
            5. Remove the old power cell
            6. +
            7. Insert the new power cell
            8. +
            9. Close the Cyborg's outer panel using a crowbar
            10. +
            11. Lock the Cyborg's Interface by swiping your ID on it, this will prevent non-qualified personnel from attempting to remove the power cell
            12. +
            + +

            Exposing the Internal Wiring

            + Exposing the internal wiring of a cyborg is fairly easy to do, and is mainly used for cyborg repairs.
            You can easily expose the internal wiring by following the steps below: +
              +
            1. Follow Steps 1 - 3 of "Replacing a Cyborg's Power Cell"
            2. +
            3. Open the cyborg's internal wiring panel by using a screwdriver to unsecure the panel
            4. +
            + To re-seal the cyborg's internal wiring: +
              +
            1. Use a screwdriver to secure the cyborg's internal panel
            2. +
            3. Follow steps 4 - 6 of "Replacing a Cyborg's Power Cell" to close up the cyborg
            4. +
            + +

            Cyborg Repairs

            + Occasionally a Cyborg may become damaged. This could be in the form of impact damage from a heavy or fast-travelling object, or it could be heat damage from high temperatures, or even lasers or Electromagnetic Pulses (EMPs). + +

            Dents

            + If a cyborg becomes damaged due to impact from heavy or fast-moving objects, it will become dented. Sure, a dent may not seem like much, but it can compromise the structural integrity of the cyborg, possibly causing a critical failure. + Dents in a cyborg's frame are rather easy to repair, all you need is to apply a welding tool to the dented area, and the high-tech cyborg frame will repair the dent under the heat of the welder. + +

            Excessive Heat Damage

            + If a cyborg becomes damaged due to excessive heat, it is likely that the internal wires will have been damaged. You must replace those wires to ensure that the cyborg remains functioning properly.
            To replace the internal wiring follow the steps below: +
              +
            1. Unlock the Cyborg's Interface by swiping your ID
            2. +
            3. Open the Cyborg's External Panel using a crowbar
            4. +
            5. Remove the Cyborg's Power Cell
            6. +
            7. Using a screwdriver, expose the internal wiring of the Cyborg
            8. +
            9. Replace the damaged wires inside the cyborg
            10. +
            11. Secure the internal wiring cover using a screwdriver
            12. +
            13. Insert the Cyborg's Power Cell
            14. +
            15. Close the Cyborg's External Panel using a crowbar
            16. +
            17. Lock the Cyborg's Interface by swiping your ID
            18. +
            + These repair tasks may seem difficult, but are essential to keep your cyborgs running at peak efficiency. + +

            In Case of Emergency

            + In case of emergency, there are a few steps you can take. + +

            "Rogue" Cyborgs

            + If the cyborgs seem to become "rogue", they may have non-standard laws. In this case, use extreme caution. + To repair the situation, follow these steps: +
              +
            1. Locate the nearest robotics console
            2. +
            3. Determine which cyborgs are "Rogue"
            4. +
            5. Press the lockdown button to immobilize the cyborg
            6. +
            7. Locate the cyborg
            8. +
            9. Expose the cyborg's internal wiring
            10. +
            11. Check to make sure the LawSync and AI Sync lights are lit
            12. +
            13. If they are not lit, pulse the LawSync wire using a multitool to enable the cyborg's LawSync
            14. +
            15. Proceed to a cyborg upload console. The Company usually places these in the same location as AI upload consoles.
            16. +
            17. Use a "Reset" upload moduleto reset the cyborg's laws
            18. +
            19. Proceed to a Robotics Control console
            20. +
            21. Remove the lockdown on the cyborg
            22. +
            + +

            As a last resort

            + If all else fails in a case of cyborg-related emergency, there may be only one option. Using a Robotics Control console, you may have to remotely detonate the cyborg. +

            WARNING:

            Do not detonate a borg without an explicit reason for doing so. Cyborgs are expensive pieces of company equipment, and you may be punished for detonating them without reason. + + + + "} + +/obj/item/weapon/book/manual/engineering_construction + name = "Repairs and Construction" + icon_state ="bookEngineering" + author = "Engineering Encyclopedia" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned + title = "Repairs and Construction" + +/obj/item/weapon/book/manual/engineering_construction/New() + ..() + dat = {" + + + + + + + + + + + "} + +/obj/item/weapon/book/manual/engineering_particle_accelerator + name = "Particle Accelerator User's Guide" + icon_state ="bookParticleAccelerator" + author = "Engineering Encyclopedia" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned + title = "Particle Accelerator User's Guide" + +/obj/item/weapon/book/manual/engineering_particle_accelerator/New() + ..() + dat = {" + + + + + +

            Experienced User's Guide

            + +

            Setting up the accelerator

            + +
              +
            1. Wrench all pieces to the floor
            2. +
            3. Add wires to all the pieces
            4. +
            5. Close all the panels with your screwdriver
            6. +
            + +

            Using the accelerator

            + +
              +
            1. Open the control panel
            2. +
            3. Set the speed to 2
            4. +
            5. Start firing at the singularity generator
            6. +
            7. When the singularity reaches a large enough size so it starts moving on it's own set the speed down to 0, but don't shut it off
            8. +
            9. Remember to wear a radiation suit when working with this machine... we did tell you that at the start, right?
            10. +
            + + + + "} + + +/obj/item/weapon/book/manual/supermatter_engine + name = "Supermatter Engine Operating Manual" + icon_state = "bookSupermatter" + author = "Central Engineering Division" + title = "Supermatter Engine Operating Manual" + +/obj/item/weapon/book/manual/supermatter_engine/New() + ..() + dat = {" + + + + +

            OPERATING MANUAL FOR MK 1 PROTOTYPE THERMOELECTRIC SUPERMATTER ENGINE 'TOMBOLA'

            +
            +

            OPERATING PRINCIPLES

            +
            +
          • The supermatter crystal serves as the fundamental power source of the engine. Upon being charged, it begins to emit large amounts of heat and radiation, as well and oxygen and phoron gas. As oxygen accelerates the reaction, and phoron carries the risk of fire, these must be filtered out. NOTE: Supermatter radiation will not charge radiation collectors.
          • +
            +
          • Air in the reactor chamber housing the supermatter is circulated through the reactor loop, which passes through the filters and thermoelectric generators. The thermoelectric generators transfer heat from the reactor loop to the colder radiator loop, thereby generating power. Additional power is generated from internal turbines in the circulators.
          • +
            +
          • Air in the radiator loop is circulated through the radiator bank, located in space. This rapidly cools the air, preserving the temperature differential needed for power generation.
          • +
            +
          • The MK 1 Prototype Thermoelectric Supermatter Engine is designed to operate at reactor temperatures of 3000K to 4000K and generate up to 1MW of power. Beyond 1MW, the thermoelectric generators will begin to lose power through electrical discharge, reducing efficiency, but additional power generation remains feasible.
          • +
            +
          • The crystal structure of the supermatter will begin to liquefy if its temperature exceeds 5000K. This eventually results in a massive release of light, heat and radiation, disintegration of both the supermatter crystal and most of the surrounding area, and as as-of-yet poorly documented psychological effects on all animals within a 2km radius. Appropriate action should be taken to stabilize or eject the supermatter before such occurs.
          • +
            +

            SUPERMATTER HANDLING

            +
          • Do not expose supermatter to oxygen.
          • +
          • Do not touch supermatter without gloves without exosuit protection allow supermatter to contact any solid object apart from specially-designed supporting pallet.
          • +
          • Do not directly view supermatter without meson goggles.
          • +
          • While handles on pallet allow moving the supermatter via pulling, pushing should not be attempted.
          • +
            +

            STARTUP PROCEDURE

            +
              +
            1. Fill reactor loop and radiator loop with two (2) standard canisters of nitrogen gas each.
            2. +
            3. Ensure that pumps and filters are on and operating at maximum power.
            4. +
            5. Fire 5 15 2 UNKNOWN 8-12 pulses from emitter at supermatter crystal. Reactor blast doors must be open for this procedure.
            6. +
            +
            +

            OPERATION AND MAINTENANCE

            +
              +
            1. Ensure that radiation protection and meson goggles are worn at all times while working in the engine room.
            2. +
            3. Ensure that reactor and radiator loops are undamaged and unobstructed.
            4. +
            5. Ensure that phoron and oxygen gas exhaust from filters is properly contained or disposed. Do not allow exhaust pressure to exceed 4500 kPa.
            6. +
            7. Ensure that engine room Area Power Controller (APC) and engine Superconducting Magnetic Energy Storage unit (SMES) are properly charged.
            8. +
            9. Ensure that reactor temperature does not exceed 5000K. In event of reactor temperature exceeding 5000K, see EMERGENCY COOLING PROCEDURE.
            10. +
            11. In event of imminent and/or unavoidable delamination, see EJECTION PROCEDURE.
            12. +
            +
            +

            EMERGENCY COOLING PROCEDURE

            +
              +
            1. Open Emergency Cooling Valve 1 and Emergency Cooling Valve 2.
            2. +
            3. When reactor temperature returns to safe operating levels, close Emergency Cooling Valve 1 and Emergency Cooling Valve 2.
            4. +
            5. If reactor temperature does not return to safe operating levels, see EJECTION PROCEDURE.
            6. +
            +
            +

            EJECTION PROCEDURE

            +
              +
            1. Press Engine Ventilatory Control button to open engine core vent to space.
            2. +
            3. Press Emergency Core Eject button to eject supermatter crystal. NOTE: Attempting crystal ejection while engine core vent is closed will result in ejection failure.
            4. +
            5. In event of ejection failure, pending
            6. +
            + + "} + + + +/obj/item/weapon/book/manual/rust_engine + name = "R-UST Operating Manual 2553" + icon_state = "bookMagazine" + author = "Cindy Crawfish" + title = "R-UST Operating Manual" + +/obj/item/weapon/book/manual/rust_engine/New() + ..() + dat = {" + + + + + So you're the poor fucker who has to try and set this piece of shit up this shift. Congratulations! Here's what you need to know: this is a tokamak fusion reactor that uses a high energy plasma stream in a magnetic field enclosure to achieve fusion. It gets extremely hot extremely quickly, and the field is tempramental. The main principle of operation: maximize plasma temperature while minimizing field instability. +

            + Deuterium and tritium are generally the most available fuel for the beast. If you're cautious, deut-deut reactions are capable of producing power without being unstable. Deut-trit is the bread and butter of the R-UST. You can keep field instability down by using the gyrotron near the core and not sticking your dick into the fusion torus. +

            + Here's the idiot's guide to setting up a functional fusion cycle: +
              +
            1. Put fuel (uranium, tritium) in the portable generator near the gyrotron and turn it to full. This is to provide initial power to the core. If the gen is fucked, hook it into the main grid.
            2. +
            3. Enable and max output on the SMES in the engine room. This is to power the gyrotron.
            4. +
            5. Go into the control room, interact with the fusion core control console. Turn the field on and raise size to 200. Any bigger and it will start EMP the machinery. Any smaller and the fuel pellets might miss.
            6. +
            7. Interact with the gyrotron control computer, set power as high as the SMES can support, usually around 3-5, and turn it on. This will start increasing the plasma temperature to the point where reactions can occur.
            8. +
            9. Go into the engine room and insert a deuterium fuel assembly and a tritium fuel assembly into two of the fuel injectors. You can make deuterium rods in the fuel compressor if you want to play it safe.
            10. +
            11. Go back to the control room and turn the fuel injectors on. This will start firing pellets into the field.
            12. +
            13. Wait for reactions to start (plasma temperature will spike and fuel amounts will drop, forming helium if you're using deut-trit). Adjust the gyrotron power and delay around until it's keeping up with field instability. This will prevent cumulative instability from the deuterium-tritium reaction fucking up the field. If you're using straight deuterium and NOTHING ELSE, instability isn't a problem and you can turn the gyrotron off.
            14. +
            15. Configure the SMES, turn the PACMAN off before it explodes.
            16. +
            +
            + NOTES FOR NEWBIES +
            + Anything touching the field will mess with its stability and eventually cause it to rupture. Rupturing is bad. Use the gyrotron to keep instability down if you're running the engine on unstable fuel. +

            + The more fuel in the field, the more fuel will react. Obvious, right? Don't load the field up with the ingredients for an unstable reaction (tritium and deuterium) before it has reached the point of fusion, or you will be trying to deal with a massive instability burst all at once. +

            + Likewise, no matter how sad the core seems, don't fucking hug it, you'll blow the field out and set the engine room on fire. +

            + IN CASE OF EMERGENCY: +
              +
            1. Turn off the fuel injectors.
            2. +
            3. Maximize the gyrotron fire rate and shot power.
            4. +
            5. Open the main core chamber to vaccuum if you can.
            6. +
            7. Prep for irradiated crewmembers, a large EMP, and broken glass.
            8. +
                + + "} + +/obj/item/weapon/book/manual/engineering_hacking + name = "Hacking" + icon_state ="bookHacking" + author = "Engineering Encyclopedia" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned + title = "Hacking" + +/obj/item/weapon/book/manual/engineering_hacking/New() + ..() + dat = {" + + + + + + + + + + + "} + + +/obj/item/weapon/book/manual/engineering_singularity_safety + name = "Singularity Safety in Special Circumstances" + icon_state ="bookEngineeringSingularitySafety" + author = "Engineering Encyclopedia" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned + title = "Singularity Safety in Special Circumstances" + + dat = {" + + + + +

                Singularity Safety in Special Circumstances

                + +

                Power outage

                + + A power problem has made you lose power? Could be wiring problems or syndicate power sinks. In any case follow these steps: + +
                  +
                1. PANIC!
                2. +
                3. Get your ass over to engineering! QUICKLY!!!
                4. +
                5. Get to the Area Power Controller which controls the power to the emitters.
                6. +
                7. Swipe it with your ID card - if it doesn't unlock, continue with step 15.
                8. +
                9. Open the console and disengage the cover lock.
                10. +
                11. Pry open the APC with a Crowbar.
                12. +
                13. Take out the empty power cell.
                14. +
                15. Put in the new, full power cell - if you don't have one, continue with step 15.
                16. +
                17. Quickly put on a Radiation suit.
                18. +
                19. Check if the singularity field generators withstood the down-time - if they didn't, continue with step 15.
                20. +
                21. Since disaster was averted you now have to ensure it doesn't repeat. If it was a powersink which caused it and if the engineering APC is wired to the same powernet, which the powersink is on, you have to remove the piece of wire which links the APC to the powernet. If it wasn't a powersink which caused it, then skip to step 14.
                22. +
                23. Grab your crowbar and pry away the tile closest to the APC.
                24. +
                25. Use the wirecutters to cut the wire which is connecting the grid to the terminal.
                26. +
                27. Go to the bar and tell the guys how you saved them all. Stop reading this guide here.
                28. +
                29. GET THE FUCK OUT OF THERE!!!
                30. +
                + +

                Shields get damaged

                + +
                  +
                1. GET THE FUCK OUT OF THERE!!! FORGET THE WOMEN AND CHILDREN, SAVE YOURSELF!!!
                2. +
                + + + "} + +/obj/item/weapon/book/manual/ripley_build_and_repair + name = "APLU \"Ripley\" Construction and Operation Manual" + icon_state ="book" + author = "Randall Varn, Einstein Engines Senior Mechanic" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned + title = "APLU \"Ripley\" Construction and Operation Manual" + + dat = {" + + + + +
                +
                + Weyland-Yutani - Building Better Worlds +

                Autonomous Power Loader Unit \"Ripley\"

                +
                +

                Specifications:

                +
                  +
                • Class: Autonomous Power Loader
                • +
                • Scope: Logistics and Construction
                • +
                • Weight: 820kg (without operator and with empty cargo compartment)
                • +
                • Height: 2.5m
                • +
                • Width: 1.8m
                • +
                • Top speed: 5km/hour
                • +
                • Operation in vacuum/hostile environment: Possible +
                • Airtank volume: 500 liters
                • +
                • Devices: +
                    +
                  • Hydraulic clamp
                  • +
                  • High-speed drill
                  • +
                  +
                • +
                • Propulsion device: Powercell-powered electro-hydraulic system
                • +
                • Powercell capacity: Varies
                • +
                + +

                Construction:

                +
                  +
                1. Connect all exosuit parts to the chassis frame.
                2. +
                3. Connect all hydraulic fittings and tighten them up with a wrench.
                4. +
                5. Adjust the servohydraulics with a screwdriver.
                6. +
                7. Wire the chassis (Cable is not included).
                8. +
                9. Use the wirecutters to remove the excess cable if needed.
                10. +
                11. Install the central control module (Not included. Use supplied datadisk to create one).
                12. +
                13. Secure the mainboard with a screwdriver.
                14. +
                15. Install the peripherals control module (Not included. Use supplied datadisk to create one).
                16. +
                17. Secure the peripherals control module with a screwdriver.
                18. +
                19. Install the internal armor plating (Not included due to corporate regulations. Can be made using 5 metal sheets).
                20. +
                21. Secure the internal armor plating with a wrench.
                22. +
                23. Weld the internal armor plating to the chassis.
                24. +
                25. Install the external reinforced armor plating (Not included due to corporate regulations. Can be made using 5 reinforced metal sheets).
                26. +
                27. Secure the external reinforced armor plating with a wrench.
                28. +
                29. Weld the external reinforced armor plating to the chassis.
                30. +
                + +

                Additional Information:

                +
                  +
                • The firefighting variation is made in a similar fashion.
                • +
                • A firesuit must be connected to the firefighter chassis for heat shielding.
                • +
                • Internal armor is plasteel for additional strength.
                • +
                • External armor must be installed in 2 parts, totalling 10 sheets.
                • +
                • Completed mech is more resilient against fire, and is a bit more durable overall.
                • +
                • The Company is determined to ensure the safety of its investments employees.
                • +
                + + + "} + +/obj/item/weapon/book/manual/atmospipes + name = "Pipes and You: Getting To Know Your Scary Tools" + icon_state = "pipingbook" + author = "Maria Crash, Senior Atmospherics Technician" + title = "Pipes and You: Getting To Know Your Scary Tools" + dat = {" + + + + + +

                Contents

                +
                  +
                1. Author's Foreword
                2. +
                3. Basic Piping
                4. +
                5. Insulated Pipes
                6. +
                7. Atmospherics Devices
                8. +
                9. Heat Exchange Systems
                10. +
                11. Final Checks
                12. +

                + +

                HOW TO NOT SUCK QUITE SO HARD AT ATMOSPHERICS


                + Or: What the fuck does a "pressure regulator" do?

                + + Alright. It has come to my attention that a variety of people are unsure of what a "pipe" is and what it does. + Apparently, there is an unnatural fear of these arcane devices and their "gases." Spooky, spooky. So, + this will tell you what every device constructable by an ordinary pipe dispenser within atmospherics actually does. + You are not going to learn what to do with them to be the super best person ever, or how to play guitar with passive gates, + or something like that. Just what stuff does.

                + + +

                Basic Pipes

                + The boring ones.
                + Most ordinary pipes are pretty straightforward. They hold gas. If gas is moving in a direction for some reason, gas will flow in that direction. + That's about it. Even so, here's all of your wonderful pipe options.
                + +
                  +
                • Straight pipes: They're pipes. One-meter sections. Straight line. Pretty simple. Just about every pipe and device is based around this + standard one-meter size, so most things will take up as much space as one of these.
                • +
                • Bent pipes: Pipes with a 90 degree bend at the half-meter mark. My goodness.
                • +
                • Pipe manifolds: Pipes that are essentially a "T" shape, allowing you to connect three things at one point.
                • +
                • 4-way manifold: A four-way junction.
                • +
                • Pipe cap: Caps off the end of a pipe. Open ends don't actually vent air, because of the way the pipes are assembled, so, uh, use them to decorate your house or something.
                • +
                • Manual valve: A valve that will block off airflow when turned. Can't be used by the AI or cyborgs, because they don't have hands.
                • +
                • Manual T-valve: Like a manual valve, but at the center of a manifold instead of a straight pipe.


                • +
                + + An important note here is that pipes are now done in three distinct lines - general, supply, and scrubber. You can move gases between these with a universal adapter. Use the correct position for the correct location. + Connecting scrubbers to a supply position pipe makes you an idiot who gives everyone a difficult job. Insulated and HE pipes don't go through these positions. + +

                Insulated Pipes

                +
              1. Bent pipes: Pipes with a 90 degree bend at the half-meter mark. My goodness.
              2. +
              3. Pipe manifolds: Pipes that are essentially a "T" shape, allowing you to connect three things at one point.
              4. +
              5. 4-way manifold: A four-way junction.
              6. +
              7. Pipe cap: Caps off the end of a pipe. Open ends don't actually vent air, because of the way the pipes are assembled, so, uh. Use them to decorate your house or something.
              8. +
              9. Manual Valve: A valve that will block off airflow when turned. Can't be used by the AI or cyborgs, because they don't have hands.
              10. +
              11. Manual T-Valve: Like a manual valve, but at the center of a manifold instead of a straight pipe.


              12. + +

                Insulated Pipes


                + Special Public Service Announcement.
                + Our regular pipes are already insulated. These are completely worthless. Punch anyone who uses them.

                + +

                Devices:

                + They actually do something.
                + This is usually where people get frightened, afraid, and start calling on their gods and/or cowering in fear. Yes, I can see you doing that right now. + Stop it. It's unbecoming. Most of these are fairly straightforward.
                + +
                  +
                • Gas pump: Take a wild guess. It moves gas in the direction it's pointing (marked by the red line on one end). It moves it based on pressure, the maximum output being 15000 kPa (kilopascals). + Ordinary atmospheric pressure, for comparison, is 101.3 kPa, and the minimum pressure of room-temperature pure oxygen needed to not suffocate in a matter of minutes is 16 kPa + (though 18 kPa is preferred when using internals with pure oxygen, for various reasons). A high-powered variant will move gas more quickly at the expense of consuming more power. Do not turn the distribution loop up to 15000 kPa. + You will make engiborgs cry and the Chief Engineer will beat you.
                • +
                • Pressure regulator: These replaced the old passive gates. You can choose to regulate pressure by input or output, and regulate flow rate. Regulating by input means that when input pressure is above the limit, gas will flow. + Regulating by output means that when pressure is below the limit, gas will flow. Flow rate can be controlled.
                • +
                • Unary vent: The basic vent used in rooms. It pumps gas into the room, but can't suck it back out. Controlled by the room's air alarm system.
                • +
                • Scrubber: The other half of room equipment. Filters air, and can suck it in entirely in what's called a "panic siphon." Activating a panic siphon without very good reason will kill someone. Don't do it.
                • +
                • Meter: A little box with some gauges and numbers. Fasten it to any pipe or manifold and it'll read you the pressure in it. Very useful.
                • +
                • Gas mixer: Two sides are input, one side is output. Mixes the gases pumped into it at the ratio defined. The side perpendicular to the other two is "node 2," for reference, on non-mirrored mixers.. + Output is controlled by flow rate. There is also an "omni" variant that allows you to set input and output sections freely..
                • +
                • Gas filter: Essentially the opposite of a gas mixer. One side is input. The other two sides are output. One gas type will be filtered into the perpendicular output pipe, + the rest will continue out the other side. Can also output from 0-4500 kPa. The "omni" vairant allows you to set input and output sections freely.
                • +
                + +

                Heat Exchange Systems

                + Will not set you on fire.
                + These systems are used to only transfer heat between two pipes. They will not move gases or any other element, but will equalize the temperature (eventually). Note that because of how gases work (remember: pv=nRt), + a higher temperature will raise pressure, and a lower one will lower temperature.
                + +
              13. Pipe: This is a pipe that will exchange heat with the surrounding atmosphere. Place in fire for superheating. Place in space for supercooling.
              14. +
              15. Bent pipe: Take a wild guess.
              16. +
              17. Junction: The point where you connect your normal pipes to heat exchange pipes. Not necessary for heat exchangers, but necessary for H/E pipes/bent pipes.
              18. +
              19. Heat exchanger: These funky-looking bits attach to an open pipe end. Put another heat exchanger directly across from it, and you can transfer heat across two pipes without having to have the gases touch. + This normally shouldn't exchange with the ambient air, despite being totally exposed. Just don't ask questions.

              20. + + That's about it for pipes. Go forth, armed with this knowledge, and try not to break, burn down, or kill anything. Please. + + + + + "} + +/obj/item/weapon/book/manual/evaguide + name = "EVA Gear and You: Not Spending All Day Inside" + icon_state = "evabook" + author = "Maria Crash, Senior Atmospherics Technician" + title = "EVA Gear and You: Not Spending All Day Inside" + dat = {" + + + + + +

                EVA Gear and You: Not Spending All Day Inside

                + Or: How not to suffocate because there's a hole in your shoes
                + +

                Contents

                +
                  +
                1. A foreword on using EVA gear
                2. +
                3. Donning a Civilian Suit
                4. +
                5. Putting on a Hardsuit
                6. +
                7. Cyclers and Other Modification Equipment
                8. +
                9. Final Checks
                10. +
                +
                + + EVA gear. Wonderful to use. It's useful for mining, engineering, and occasionally just surviving, if things are that bad. Most people have EVA training, + but apparently there are some people out in space who don't. This guide should give you a basic idea of how to use this gear, safely. It's split into two sections: + Civilian suits and hardsuits.

                + +

                Civilian Suits

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

                + + First, take the suit. It should be in three pieces: A top, a bottom, and a helmet. Put the bottom on first, shoes and the like will fit in it. If you have magnetic boots, however, + put them on on top of the suit's feet. Next, get the top on, as you would a shirt. It can be somewhat awkward putting these pieces on, due to the makeup of the suit, + but to an extent they will adjust to you. You can then find the snaps and seals around the waist, where the two pieces meet. Fasten these, and double-check their tightness. + The red indicators around the waist of the lower half will turn green when this is done correctly. Next, put on whatever breathing apparatus you're using, be it a gas mask or a breath mask. Make sure the oxygen tube is fastened into it. + Put on the helmet now, straightforward, and make sure the tube goes into the small opening specifically for internals. Again, fasten seals around the neck, a small indicator light in the inside of the helmet should go from red to off when all is fastened. + There is a small slot on the side of the suit where an emergency oxygen tank or extended emergency oxygen tank will fit, + but it is recommended to have a full-sized tank on your back for EVA.

                + + These suits tend to be wearable by most species. They're large and flexible. They might be pretty uncomfortable for some, though, so keep that in mind.

                + +

                Hardsuits

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

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

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

                + +

                Modification Equipment

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

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

                + + There's also modification kits that let you modify suits yourself. These are extremely difficult to use unless you understand the actual construction of the suit. I do not reccomend using them unless no other option is available. + +

                Final Checks

                +
                  +
                • Are all seals fastened correctly?
                • +
                • If you have modified it manually, is absolutely everything sealed perfectly?
                • +
                • Do you either have shoes on under the suit, or magnetic boots on over it?
                • +
                • Do you have a mask on and internals on the suit or your back?
                • +
                • Do you have a way to communicate with your fellow crew in case something goes wrong?
                • +
                • Do you have a second person watching if this is a training session?

                • +
                + + If you don't have any further issues, go out and do whatever is necessary. + + + + "} diff --git a/code/modules/library/manuals/manuals.dm b/code/modules/library/manuals/manuals.dm new file mode 100644 index 00000000..df6fb6e2 --- /dev/null +++ b/code/modules/library/manuals/manuals.dm @@ -0,0 +1,207 @@ +/obj/item/weapon/book/manual/chef_recipes + name = "Chef Recipes" + icon_state = "cooked_book" + author = "Victoria Ponsonby" + title = "Chef Recipes" + + dat = {" + + + + + +

                Food for Dummies

                + Here is a guide on basic food recipes and also how to not poison your customers accidentally. + +

                Basics:

                + Knead an egg and some flour along with some water to make dough. Bake that to make a bun or flatten and cut it. + +

                Burger:

                + Put a bun and some meat into the microwave and turn it on. Then wait. + +

                Bread:

                + Put some dough and an egg into the microwave and then wait. + +

                Waffles:

                + Add two lumps of dough and 10 units of sugar to the microwave and then wait. + +

                Popcorn:

                + Add 1 corn to the microwave and wait. + +

                Meat Steak:

                + Put a slice of meat, 1 unit of salt, and 1 unit of pepper into the microwave and wait. + +

                Meat Pie:

                + Put a flattened piece of dough and some meat into the microwave and wait. + +

                Boiled Spaghetti:

                + Put the spaghetti (processed flour) and 5 units of water into the microwave and wait. + +

                Donuts:

                + Add some dough and 5 units of sugar to the microwave and wait. + +

                Fries:

                + Add one potato to the processor, then bake them in the microwave. + + + + + "} + + +/obj/item/weapon/book/manual/barman_recipes + name = "Barman Recipes" + icon_state = "barbook" + author = "Sir John Rose" + title = "Barman Recipes" + + dat = {" + + + + + +

                Drinks for Dummies

                + Here's a guide for some basic drinks. + +

                Black Russian:

                + Mix vodka and Kahlua into a glass. + +

                Cafe Latte:

                + Mix milk and coffee into a glass. + +

                Classic Martini:

                + Mix vermouth and gin into a glass. + +

                Gin Tonic:

                + Mix gin and tonic into a glass. + +

                Grog:

                + Mix rum and water into a glass. + +

                Irish Cream:

                + Mix cream and whiskey into a glass. + +

                The Manly Dorf:

                + Mix ale and beer into a glass. + +

                Mead:

                + Mix enzyme, water, and sugar into a glass. + +

                Screwdriver:

                + Mix vodka and orange juice into a glass. + + + + "} + + +/obj/item/weapon/book/manual/detective + name = "The Film Noir: Proper Procedures for Investigations" + icon_state ="bookDetective" + author = "The Company" + title = "The Film Noir: Proper Procedures for Investigations" + + dat = {" + + + + +

                Detective Work

                + + Between your bouts of self-narration and drinking whiskey on the rocks, you might get a case or two to solve.
                + To have the best chance to solve your case, follow these directions: +

                +

                  +
                1. Go to the crime scene.
                2. +
                3. Take your scanner and scan EVERYTHING (Yes, the doors, the tables, even the dog).
                4. +
                5. Once you are reasonably certain you have every scrap of evidence you can use, find all possible entry points and scan them, too.
                6. +
                7. Return to your office.
                8. +
                9. Using your forensic scanning computer, scan your scanner to upload all of your evidence into the database.
                10. +
                11. Browse through the resulting dossiers, looking for the one that either has the most complete set of prints, or the most suspicious items handled.
                12. +
                13. If you have 80% or more of the print (The print is displayed), go to step 10, otherwise continue to step 8.
                14. +
                15. Look for clues from the suit fibres you found on your perpetrator, and go about looking for more evidence with this new information, scanning as you go.
                16. +
                17. Try to get a fingerprint card of your perpetrator, as if used in the computer, the prints will be completed on their dossier.
                18. +
                19. Assuming you have enough of a print to see it, grab the biggest complete piece of the print and search the security records for it.
                20. +
                21. Since you now have both your dossier and the name of the person, print both out as evidence and get security to nab your baddie.
                22. +
                23. Give yourself a pat on the back and a bottle of the ship's finest vodka, you did it!
                24. +
                +

                + It really is that easy! Good luck! + + + "} + +/obj/item/weapon/book/manual/nuclear + name = "Fission Mailed: Nuclear Sabotage 101" + icon_state ="bookNuclear" + author = "Syndicate" + title = "Fission Mailed: Nuclear Sabotage 101" + + dat = {" + + + + +

                Nuclear Explosives 101

                + Hello and thank you for choosing the Syndicate for your nuclear information needs. Today's crash course will deal with the operation of a Nuclear Fission Device.

                + + First and foremost, DO NOT TOUCH ANYTHING UNTIL THE BOMB IS IN PLACE. Pressing any button on the compacted bomb will cause it to extend and bolt itself into place. If this is done, to unbolt it, one must completely log in, which at this time may not be possible.
                + +

                To make the nuclear device functional

                +
                  +
                • Place the nuclear device in the designated detonation zone.
                • +
                • Extend and anchor the nuclear device from its interface.
                • +
                • Insert the nuclear authorisation disk into the slot.
                • +
                • Type the numeric authorisation code into the keypad. This should have been provided.
                  + Note: If you make a mistake, press R to reset the device. +
                • Press the E button to log on to the device.
                • +

                + + You now have activated the device. To deactivate the buttons at anytime, for example when you've already prepped the bomb for detonation, remove the authentication disk OR press R on the keypad.

                + Now the bomb CAN ONLY be detonated using the timer. Manual detonation is not an option. Toggle off the SAFETY.
                + Note: You wouldn't believe how many Syndicate Operatives with doctorates have forgotten this step.

                + + So use the - - and + + to set a detonation time between 5 seconds and 10 minutes. Then press the timer toggle button to start the countdown. Now remove the authentication disk so that the buttons deactivate.
                + Note: THE BOMB IS STILL SET AND WILL DETONATE

                + + Now before you remove the disk, if you need to move the bomb, you can toggle off the anchor, move it, and re-anchor.

                + + Remember the order:
                + Disk, Code, Safety, Timer, Disk, RUN!

                + Intelligence Analysts believe that normal corporate procedure is for the Captain to secure the nuclear authentication disk.

                + + Good luck! + + + "} diff --git a/code/modules/library/manuals/medical.dm b/code/modules/library/manuals/medical.dm new file mode 100644 index 00000000..6c930b00 --- /dev/null +++ b/code/modules/library/manuals/medical.dm @@ -0,0 +1,138 @@ +/obj/item/weapon/book/manual/medical_cloning + name = "Cloning Techniques of the 26th Century" + icon_state ="bookCloning" + author = "Medical Journal, volume 3" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned + title = "Cloning Techniques of the 26th Century" + + dat = {" + + + + + +

                How to Clone People

                + So there are 50 dead people lying on the floor, chairs are spinning like no tomorrow and you haven't the foggiest idea of what to do? Not to worry! + This guide is intended to teach you how to clone people and how to do it right, in a simple, step-by-step process! If at any point of the guide you have a mental meltdown, + genetics probably isn't for you and you should get a job-change as soon as possible before you're sued for malpractice. + +
                  +
                1. Acquire body
                2. +
                3. Strip body
                4. +
                5. Put body in cloning machine
                6. +
                7. Scan body
                8. +
                9. Clone body
                10. +
                11. Get clean Structural Enzymes for the body
                12. +
                13. Put body in morgue
                14. +
                15. Await cloned body
                16. +
                17. Cryo and use the clean SE injector
                18. +
                19. Give person clothes back
                20. +
                21. Send person on their way
                22. +
                + +

                Step 1: Acquire body

                + This is pretty much vital for the process because without a body, you cannot clone it. Usually, bodies will be brought to you, so you do not need to worry so much about this step. If you already have a body, great! Move on to the next step. + +

                Step 2: Strip body

                + The cloning machine does not like abiotic items. What this means is you can't clone anyone if they're wearing clothes or holding things, so take all of it off. If it's just one person, it's courteous to put their possessions in the closet. + If you have about seven people awaiting cloning, just leave the piles where they are, but don't mix them around and for God's sake don't let people in to steal them. + +

                Step 3: Put body in cloning machine

                + Grab the body and then put it inside the DNA modifier. If you cannot do this, then you messed up at Step 2. Go back and check you took EVERYTHING off - a commonly missed item is their headset. + +

                Step 4: Scan body

                + Go onto the computer and scan the body by pressing 'Scan - <Subject Name Here>.' If you're successful, they will be added to the records (note that this can be done at any time, even with living people, + so that they can be cloned without a body in the event that they are lying dead on port solars and didn't turn on their suit sensors)! + If not, and it says "Error: Mental interface failure.", then they have left their bodily confines and are one with the spirits. If this happens, just shout at them to get back in their body, + click 'Refresh' and try scanning them again. If there's no success, threaten them with gibbing. + Still no success? Skip over to Step 7 and don't continue after it, as you have an unresponsive body and it cannot be cloned. + If you got "Error: Unable to locate valid genetic data.", you are trying to clone a monkey - start over. + +

                Step 5: Clone body

                + Now that the body has a record, click 'View Records,' click the subject's name, and then click 'Clone' to start the cloning process. Congratulations! You're halfway there. + Remember not to 'Eject' the cloning pod as this will kill the developing clone and you'll have to start the process again. + +

                Step 6: Get clean SEs for body

                + Cloning is a finicky and unreliable process. Whilst it will most certainly bring someone back from the dead, they can have any number of nasty disabilities given to them during the cloning process! + For this reason, you need to prepare a clean, defect-free Structural Enzyme (SE) injection for when they're done. If you're a competent Geneticist, you will already have one ready on your working computer. + If, for any reason, you do not, then eject the body from the DNA modifier (NOT THE CLONING POD) and take it next door to the Genetics research room. Put the body in one of those DNA modifiers and then go onto the console. + Go into View/Edit/Transfer Buffer, find an open slot and click "SE" to save it. Then click 'Injector' to get the SEs in syringe form. Put this in your pocket or something for when the body is done. + +

                Step 7: Put body in morgue

                + Now that the cloning process has been initiated and you have some clean Structural Enzymes, you no longer need the body! Drag it to the morgue and tell the Chef over the radio that they have some fresh meat waiting for them in there. + To put a body in a morgue bed, simply open the tray, grab the body, put it on the open tray, then close the tray again. Use one of the nearby pens to label the bed "CHEF MEAT" in order to avoid confusion. + +

                Step 8: Await cloned body

                + Now go back to the lab and wait for your patient to be cloned. It won't be long now, I promise. + +

                Step 9: Cryo and clean SE injector on person

                + Has your body been cloned yet? Great! As soon as the guy pops out, grab them and stick them in cryo. Clonexadone and Cryoxadone help rebuild their genetic material. Then grab your clean SE injector and jab it in them. Once you've injected them, + they now have clean Structural Enzymes and their defects, if any, will disappear in a short while. + +

                Step 10: Give person clothes back

                + Obviously the person will be naked after they have been cloned. Provided you weren't an irresponsible little shit, you should have protected their possessions from thieves and should be able to give them back to the patient. + No matter how cruel you are, it's simply against protocol to force your patients to walk outside naked. + +

                Step 11: Send person on their way

                + Give the patient one last check-over - make sure they don't still have any defects and that they have all their possessions. Ask them how they died, if they know, so that you can report any foul play over the radio. + Once you're done, your patient is ready to go back to work! Chances are they do not have Medbay access, so you should let them out of Genetics and the Medbay main entrance. + +

                If you've gotten this far, congratulations! You have mastered the art of cloning. Now, the real problem is how to resurrect yourself after that traitor had his way with you for cloning his target. + + + + "} + +/obj/item/weapon/book/manual/medical_diagnostics_manual + name = "Medical Diagnostics Manual" + desc = "First, do no harm. A detailed medical practitioner's guide." + icon_state = "bookMedical" + author = "Medical Department" + title = "Medical Diagnostics Manual" + +/obj/item/weapon/book/manual/medical_diagnostics_manual/New() + ..() + dat = {" + + + + +
                +

                The Oath

                + + The Medical Oath sworn by recognised medical practitioners in the employ of [GLOB.using_map.company_name]
                + +
                  +
                1. Now, as a new doctor, I solemnly promise that I will, to the best of my ability, serve humanity-caring for the sick, promoting good health, and alleviating pain and suffering.
                2. +
                3. I recognise that the practice of medicine is a privilege with which comes considerable responsibility and I will not abuse my position.
                4. +
                5. I will practise medicine with integrity, humility, honesty, and compassion-working with my fellow doctors and other colleagues to meet the needs of my patients.
                6. +
                7. I shall never intentionally do or administer anything to the overall harm of my patients.
                8. +
                9. I will not permit considerations of gender, race, religion, political affiliation, sexual orientation, nationality, or social standing to influence my duty of care.
                10. +
                11. I will oppose policies in breach of human rights and will not participate in them. I will strive to change laws that are contrary to my profession's ethics and will work towards a fairer distribution of health resources.
                12. +
                13. I will assist my patients to make informed decisions that coincide with their own values and beliefs and will uphold patient confidentiality.
                14. +
                15. I will recognise the limits of my knowledge and seek to maintain and increase my understanding and skills throughout my professional life. I will acknowledge and try to remedy my own mistakes and honestly assess and respond to those of others.
                16. +
                17. I will seek to promote the advancement of medical knowledge through teaching and research.
                18. +
                19. I make this declaration solemnly, freely, and upon my honour.
                20. +

                + +
                + + + + + + "} diff --git a/code/modules/library/manuals/nanotrasen.dm b/code/modules/library/manuals/nanotrasen.dm new file mode 100644 index 00000000..c2d52d31 --- /dev/null +++ b/code/modules/library/manuals/nanotrasen.dm @@ -0,0 +1,503 @@ +/obj/item/weapon/book/manual/nt_regs + name = "NanoTrasen Regulations" + desc = "A set of corporate guidelines for employees of NanoTrasen." + icon_state = "booknanoregs" + author = "NanoTrasen" + title = "NanoTrasen Regulations" + +/obj/item/weapon/book/manual/nt_regs/New() + ..() + dat = {" + + + + + + + + + + + "} + +/obj/item/weapon/book/manual/hydroponics_pod_people + name = "The Diona Harvest - From Seed to Market" + icon_state ="bookHydroponicsPodPeople" + author = "Farmer John" + title = "The Diona Harvest - From Seed to Market" + + dat = {" + + + + +

                Growing a Diona

                + + Growing a Diona is easy! +

                +

                  +
                1. Take a syringe of blood from the body you wish to turn into a Diona.
                2. +
                3. Inject 5 units of blood into the pack of dionaea-replicant seeds.
                4. +
                5. Plant the seeds.
                6. +
                7. Tend to the plants water and nutrition levels until it is time to harvest the Diona.
                8. +
                +

                + Note that for a successful harvest, the body from which the blood was taken from must be dead BEFORE harvesting the pod, however the pod can be growing while they are still alive. Otherwise, the soul would not be able to migrate to the new Diona body.

                + + It really is that easy! Good luck! + + + + "} + +/obj/item/weapon/book/manual/research_and_development + name = "Research and Development 101" + icon_state = "rdbook" + author = "Dr. L. Ight" + title = "Research and Development 101" + + dat = {" + + + + + +

                Science For Dummies

                + So you want to further SCIENCE? Good man/woman/thing! However, SCIENCE is a complicated process even though it's quite easy. For the most part, it's a three step process: +
                  +
                1. Deconstruct items in the Destructive Analyzer to advance technology or improve the design.
                2. +
                3. Build unlocked designs in the Protolathe and Circuit Imprinter.
                4. +
                5. Repeat!
                6. +
                + + Those are the basic steps to furthering science. What do you do science with, however? Well, you have four major tools: R&D Console, the Destructive Analyzer, the Protolathe, and the Circuit Imprinter. + +

                The R&D Console

                + The R&D console is the cornerstone of any research lab. It is the central system from which the Destructive Analyzer, Protolathe, and Circuit Imprinter (your R&D systems) are controlled. More on those systems in their own sections. + On its own, the R&D console acts as a database for all your technological gains and new devices you discover. So long as the R&D console remains intact, you'll retain all that SCIENCE you've discovered. Protect it though, + because if it gets damaged, you'll lose your data! + In addition to this important purpose, the R&D console has a disk menu that lets you transfer data from the database onto disk or from the disk into the database. + It also has a settings menu that lets you re-sync with nearby R&D devices (if they've become disconnected), lock the console from the unworthy, + upload the data to all other R&D consoles in the network (all R&D consoles are networked by default), connect/disconnect from the network, and purge all data from the database.

                + + NOTE: The technology list screen, circuit imprinter, and protolathe menus are accessible by non-scientists. This is intended to allow 'public' systems for the plebians to utilize some new devices. + +

                Destructive Analyzer

                + This is the source of all technology. Whenever you put a handheld object in it, it analyzes it and determines what sort of technological advancements you can discover from it. If the technology of the object is equal or higher then your current knowledge, + you can destroy the object to further those sciences. + Some devices (notably, some devices made from the protolathe and circuit imprinter) aren't 100% reliable when you first discover them. If these devices break down, you can put them into the Destructive Analyzer and improve their reliability rather than further science. + If their reliability is high enough, it'll also advance their related technologies. + +

                Circuit Imprinter

                + This machine, along with the Protolathe, is used to actually produce new devices. The Circuit Imprinter takes glass and various chemicals (depends on the design) to produce new circuit boards to build new machines or computers. It can even be used to print AI modules. + +

                Protolathe

                + This machine is an advanced form of the Autolathe that produce non-circuit designs. Unlike the Autolathe, it can use processed metal, glass, solid phoron, silver, gold, and diamonds along with a variety of chemicals to produce devices. + The downside is that, again, not all devices you make are 100% reliable when you first discover them. + +

                Reliability and You

                + As it has been stated, many devices, when they're first discovered, do not have a 100% reliability. Instead, + the reliability of the device is dependent upon a base reliability value, whatever improvements to the design you've discovered through the Destructive Analyzer, + and any advancements you've made with the device's source technologies. To be able to improve the reliability of a device, you have to use the device until it breaks beyond repair. Once that happens, you can analyze it in a Destructive Analyzer. + Once the device reaches a certain minimum reliability, you'll gain technological advancements from it. + +

                Building a Better Machine

                + Many machines produced from circuit boards inserted into a machine frames require a variety of parts to construct. These are parts like capacitors, batteries, matter bins, and so forth. As your knowledge of science improves, more advanced versions are unlocked. + If you use these parts when constructing something, its attributes may be improved. + For example, if you use an advanced matter bin when constructing an autolathe (rather than a regular one), it'll hold more materials. Experiment around with stock parts of various qualities to see how they affect the end results! Be warned, however: + Tier 3 and higher stock parts don't have 100% reliability and their low reliability may affect the reliability of the end machine. + + + "} + +/obj/item/weapon/book/manual/excavation + name = "Out on the Dig" + icon_state = "excavation" + author = "Professor Patrick Mason, Curator of the Antiquities Museum on Ichar VII" + title = "Out on the Dig" + dat = {" + + + + + +

                Contents

                +
                  +
                1. Prepping the expedition
                2. +
                3. Knowing your tools
                4. +
                5. Finding the dig
                6. +
                7. Analysing deposits
                8. +
                9. Extracting your first find
                10. +
                +
                + +

                Prepping the expedition

                + Every digsite I've been to, someone has forgotten something and I've never yet been to a dig that hasn't had me hiking to get to it - so gather your gear + and get it to the site the first time. You learn quick that time is money, when you've got a shipful of bandits searching for you the next valley over, + but don't be afraid to clear some space if there are any inconvenient boulders in the way.
                +
                  +
                • Floodlights (if it's dark)
                • +
                • Wooden trestle tables (for holding tools and finds)
                • +
                • Suspension field generator
                • +
                • Load bearing servitors (such as a mulebot, or hover-tray)
                • +
                • Spare energy packs
                • +

                + Contents + +

                Knowing your tools

                + Every archaeologist has a plethora of tools at their disposal, but here's the important ones:
                +
                  +
                • Picks, pickaxes, and brushes - don't underestimate the the smallest or largest in your arsenal, each one clears a different amount + of the rockface so each one has a use.
                • +
                • Measuring tape - don't leave home without it, you can use it to measure the depth a rock face has been excavated to.
                • +
                • GPS locator - knowing where you are is the first step to not be lost.
                • +
                • Core sampler - use this to take core samples from rock faces, which you can then run to the lab for analysis.
                • +
                • Depth scanner - uses X-ray diffraction to locate anomalous densities in rock, indicating archaeological deposits or mineral veins. + Comes with a handy reference log containing coordinates and time of each scan.
                • +
                • Alden-Saraspova counter - uses a patented application of Fourier Transform analysis to determine the difference between background and + exotic radiation. Use it to determine how far you are from anomalous energy sources.
                • +
                • Radio beacon locator - leave a beacon at an item of interest, then track it down later with this handy gadget. Watch for interference from other + devices though.
                • +
                • Flashlight or portable light source - Self explanatory, I hope.
                • +
                • Environmental safety gear - This one's dependent on the environment you're working in, but enclosed footwear and a pack of internals + could save your life.
                • +
                • Anomaly safety gear - A biosealed and catalysis-resistant suit along with eye shielding, tinted hood, and non-reactive disposable gloves are + the best kind of protection you can hope for from the errors our forebears may have unleashed.
                • +
                • Personal defence weapon - Never know what you'll find on the dig: pirates, natives, ancient guardians, carnivorous wildlife... + it pays in blood to be prepared.
                • +

                + Contents + +

                Finding the dig

                + Wouldn't be an archaeologist without their dig, but everyone has to start somewhere. Here's a basic procedure I go through when cataloguing a new planet:
                +
                  +
                • Get in touch with the locals (in particular geologists, miners, and farmers) - Never know what's been turned up by accident, then left to + gather dust on a shelf.
                • +
                • Check the obvious areas first - even if you're pressed for time, these ones are the generally easiest to search, and the most likely targets + of your rivals.
                • +
                • Do some prospecting - the earth mother isn't in the habit of displaying her secrets to the world (although sometimes you get lucky). + Drop a shaft and clear away a bit of surface rock here and there, you never know what might be lurking below the surface.
                • +
                • Tips on unearthing a deposit - How do you know when you're golden? Look for telltale white strata that looks strange or out of place, or if + something has broken under your pick while you're digging. Your depth scanner is your best friend, but even it can't distinguish between + ordinary minerals and ancient leavings, if in doubt then err on the side of caution.
                • +

                + Contents + +

                Analysing the contents of a dig

                + You've found some unusual strata, but it's not all peaches from here. No archaeologist ever managed to pull a bone from the earth without doing thorough + chemical analysis on every two meters of rock face nearby.
                +
                  +
                • Take core samples - Grab a rock core for every 4m^2.
                • +
                • Clear around any potential finds - Clear away ordinary rock, leaving your prizes reachable in a clearly marked area.
                • +
                • Haul off excess rock - It's easy for a dig to get cluttered, and a neat archaeologist is a successful archaeologist.
                • +
                • Don't be afraid to be cautious - It's slower sometimes, but the extra time will be worth the payoff when you find an Exolitic relic.
                • +
                • Chemical analysis - I won't go into detail here, but the labwork is essential to any successful extraction. Marshal your core samples, and + send them off to the labcoated geniuses.
                • +

                + Contents + +

                Extracting your first find

                +
                  +
                • Scan the rock - Use a depth scanner to determine the find's depth and clearance. DON'T FORGET THESE.
                • +
                • Choose stasis field - Chemical analysis on a core sample from the rock face will tell you which field is necessary to extract the find safely.
                • +
                • Setup field gen - Bolt it down, choose the field, check the charge, and activate it. If you forget it, you'll wish you hadn't when that priceless + Uryom vase crumbles as it sees the light of day.
                • +
                • FUNCTIONAL AND SAFE digging - Dig into the rock until you've cleared away a depth equal to (the anomaly depth MINUS the clearance range). The find + should come loose on it's own, but it will be in the midst of a chunk of rock. Use a welder or miniature excavation tool to clear away the excess.
                • +
                • FANCY AND SPEEDY digging - Dig into the rock until you've cleared away a depth equal to the anomaly depth, but without any of your strokes + entering the clearance range.
                • +
                • The big find - Sometimes, you'll chance upon something big, both literally and figuratively. Giant statues and functioning remnants of Precursor + technology are just as exciting, to the right buyers. If your digging leaves a large boulder behind, dig into it normally and see if anything's hidden + inside.
                • +

                + Contents + + + + "} + +/obj/item/weapon/book/manual/mass_spectrometry + name = "High Power Mass Spectrometry: A Comprehensive Guide" + icon_state = "analysis" + author = "Winton Rice, Chief Mass Spectrometry Technician at the Institute of Applied Sciences on Arcadia" + title = "High powered mass spectrometry, a comprehensive guide" + dat = {" + + + + + +

                Contents

                +
                  +
                1. A note on terms
                2. +
                3. Analysis progression
                4. +
                5. Heat management
                6. +
                7. Ambient radiation
                8. +
                + +
                +

                A note on terms

                +
                  +
                • Mass spectrometry - MS is the procedure used used to measure and quantify the components of matter. The most prized tool in the field of + 'Materials analysis.'
                • +
                • Radiometric dating - MS applied using the right carrier reagents can be used to accurately determine the age of a sample.
                • +
                • Dissonance ratio - This is a pseudoarbitrary value indicating the overall presence of a particular element in a greater composite. + It takes into account volume, density, molecular excitation and isotope spread.
                • +
                • Vacuum seal integrity - A reference to how close an airtight seal is to failure.
                • +

                + Contents + +

                Analysis progression

                + Modern mass spectrometry requires constant attention from the diligent researcher in order to be successful. There are many different elements to juggle, + and later chapters will delve into them. For the spectrometry assistant, the first thing you need to know is that the scanner wavelength is automatically + calculated for you. Just tweak the settings and try to match it with the actual wavelength as closely as possible.
                +
                + Contents + +

                Seal integrity

                + In order to maintain sterile and environmentally static procedures, a special chamber is set up inside the spectrometer. It's protected by a proprietary vacuum seal + produced by top tier industrial science. It will only last for a certain number of scans before failing outright, but it can be resealed through use of nanite paste. + Unfortunately, it's susceptible to malforming under heat stress so exposing it to higher temperatures will cause it's operation life to drop significantly.
                +
                + Contents + +

                Heat management

                + The scanner relies on a gyro-rotational system that varies in speed and intensity. Over the course of an ordinary scan, the RPMs can change dramatically. Higher RPMs + means greater heat generation, but is necessary for the ongoing continuation of the scan. To offset heat production, spectrometers have an inbuilt cooling system. + Researchers can modify the flow rate of coolant to aid in dropping temperature as necessary, but are advised that frequent coolant replacements may be necessary + depending on coolant purity. Water and substances such as cryoxadone are viable substitutes, but nowhere near as effective as pure coolant itself.
                +
                + Contents + +

                Ambient radiation

                + Researchers are warned that while operational, mass spectrometers emit period bursts of radiation and are thus advised to wear protective gear. In the event of + radiation spikes, there is also a special shield that can be lowered to block emissions. Lowering this, however, will have the effect of blocking the scanner + so use it sparingly.
                +
                + Contents + + + + "} + +/obj/item/weapon/book/manual/anomaly_spectroscopy + name = "Spectroscopy: Analysing the Anomalies of the Cosmos" + icon_state = "anomaly" + author = "Doctor Martin Boyle, Director Research at the Lower Hydrolian Sector Listening Array" + title = "Spectroscopy: Analysing the Anomalies of the Cosmos" + dat = {" + + + + +
                + It's perhaps one of the most exciting times to be alive, with the recent breakthroughs in understanding and categorisation of things we may one day no longer call + 'anomalies,' but rather 'infrequent or rare occurrences of certain celestial weather or phenomena.' Perhaps a little more long winded, but no less eloquent all the + same! Why, look at the strides we're making in piercing the walls of bluespace or our steadily improving ability to clarify and stabilise subspace emissions; it's + certainly an exciting time to be alive. For the moment, the Hydrolian hasn't seen two spatial anomalies alike but the day will come and it is soon, I can feel it. + + "} + +/obj/item/weapon/book/manual/materials_chemistry_analysis + name = "Materials Analysis and the Chemical Implications" + icon_state = "chemistry" + author = "Jasper Pascal, Senior Lecturer in Materials Analysis at the University of Jol'Nar" + title = "Materials Analysis and the Chemical Implications" + dat = {" + + + + +
                + In today's high tech research fields, leaps and bounds are being made every day. Whether it's great strides forward in our understanding of the physical universe + or the operation of some fancy new piece of equipment, it seems like all the cool fields are producing new toys to play with, leaving doddery old fields such as + materials analysis and chemistry relegated to the previous few centuries, when we were still learning the makeup and structure of the elements.
                +
                + Well, when you're out there building the next gryo-whatsitron or isotope mobility thingummy, remember how the field of archaeology experienced a massive new rebirth + following the excavations at Paranol IV and consider how all of the scientific greats will come crawling back to basic paradigms of natural philosophy when they discover + a new element that defies classification. I defy you to classify it without reviving this once great field! + "} + +/obj/item/weapon/book/manual/anomaly_testing + name = "Anomalous Materials and Energies" + icon_state = "triangulate" + author = "Norman York, formerly of the Tyrolion Institute on Titan" + title = "Anomalous Materials and Energies" + dat = {" + + + + + +

                Contents

                +
                  +
                1. Foreword: Modern attitude towards anomalies
                2. +
                3. Triangulating anomalous energy readings
                4. +
                5. Harvesting and utilising anomalous energy signatures
                6. +
                +
                +

                Modern attitude towards anomalies

                + It's only when confronted with things we don't know, that we may push back our knowledge of the world around us. Nowhere is this more obvious than the + vast and inscrutable mysterious of the cosmos that scholars from such august institutions as the Elysian Institute of the Sciences present + formulas and hypotheses for every few decades.
                +
                + Using our vast, telescopic array installations and deep space satellite networks, we are able to detect anomalous energy fields and formations in deep space, + but are limited to those that are large enough to output energy that will stretch across light years worth of distance between stars.
                +
                + While some sectors (such as the Hydrolian Rift and Keppel's Run) are replete with inexplicable energetic activity and unique phenomena found nowhere else in + the galaxy, the majority of space is dry, barren and cold - and if past experience has told us anything, it is that there are always more things we are + unable to explain.
                +
                + Indeed, a great source of knowledge and technology has always been those who come before us, in the form of the multitudinous ancient alien precursors that + have left scattered remnants of their great past all over settled (and unexplored) space.
                +
                + It is from xenoarchaeologists, high energy materials researchers, and technology reconstruction authorities that we are able to theorise on the gifts these + species have left behind, and in some cases even reverse engineer or rebuild the technology in question. My colleague, Doctor Raymond Ward of the + Tyrolian Institute on Titan, has made great breakthroughs in a related field through his pioneering development of universally reflective materials capable + of harvesting and 'bottling' up virtually any energy emissions yet encountered by spacefaring civilisations.
                +
                + And yet, there are some amongst us who do not see the benefits of those who have come before us - indeed, some among them profess the opinion that there + is no species that could possibly match humanity in it's achievements and knowledge, or simply that employing non-human technology is dangerous and unethical. + Folly, say I. If it is their desire to throw onto the wayside the greatest achievements in the history of the galaxy, simply for preferment of the + greatest achievements in the history of mankind, then they have no business in the establishment of science.
                + Contents + +

                Triangulating anomalous energy readings

                + Strong energy emissions, when remaining constant from any one fixed location for millennia, can leave an 'imprint' or distinctive energy signature on other + matter composites that are spatially fixed relative to the source.
                +
                + By taking samples of such 'fixed' matter, we can apply complex analytics such as the modified Fourier Transform Procedure to reverse engineer the path of the + energy, and determine the approximate distance and direction that the energy source is, relative to the sample's point in space. Modern portable devices can do + all this purely by taking readings of local radiation.
                +
                + A canny researcher can thusly analyse radiation at pre-chosen points strategically scattered around an area, and if there are any anomalous energy + emissions in range of those points, combined the researcher can triangulate the source.
                + Contents + +

                Harvesting and utilising anomalous energy signatures

                + As mentioned in the foreword, my colleague from the Tyrolian Institute on Saturn's moon of Titan, in the Sol System, Doctor Raymond Ward has made great strides + in the area of harvesting and application of the energy emitted by anomalous phenomena from around the galaxy (although I profess I have not yet seen him + venture further from his birthplace on Earth than the comfortable distance of the Sol Cis-Oort Satellite Sphere).
                +
                + By employing a patented semi-phased alloy with unique and fascinating bluespace interaction properties, Ward's contraption is able to 'harvest' energy, store + it and redirect it later at will (with appropriate electronic mechanisms, of course). Although he professes to see or desire no commercial or material gain + for the application and use of said energy once it is harvested, there are no doubt myriad ways we can come to benefit from such things beyond mere research, + such as the reconstruction of torn cartilaginous tissue that a peculiar radiation from an amphibious species on Brachis IV was found to emit.
                + Contents + + + + "} + +/obj/item/weapon/book/manual/stasis + name = "Cellular Suspension, the New Cryogenics?" + icon_state = "stasis" + author = "Elvin Schmidt" + title = "Cellular Suspension, the New Cryogenics?" + dat = {" + + + + + +

                Contents

                +
                  +
                1. Foreword: A replacement for cryosleep?
                2. +
                3. The breakthrough
                4. +
                5. Applying this new principle
                6. +
                +
                +

                Foreword: A replacement for cryosleep?

                + The development of rudimentary cryofreezing in the 20th and 21st centuries was hailed as a crank science by some, but many early visionaries recognised the + potential it had to change the way we approach so many fields, such as medicine, therapeutics, and space travel. It was breakthroughs in the field in the 22nd and + later centuries that turned the procedure from science fiction to science fact, however. Since then, cryogenics has become a hallmark of modern science, and + regarded as one of the great achievements of our era. As with all sciences however, they have their time and are superseded by newer technological miracles when + it is over.
                + Contents + +

                The breakthrough

                + It was in examining the effects of decelerated, bluespace, high energy particles when transphased through bluespace that the effects where primarily noticed. + Due to exigent properties of that dimension, transphasing those particles capable of existing in bluespace with high stability levels has the effect of bringing + some of those effects into realspace. Examining the Hoffman emissions in particular, it was discovered that they exhibited a-entropic behaviour, and in what is + now termed the 'Effete Hoffman Principle,' it was found that metastabilising the Hoffman radiation resulted in the effect being applied across other physical + interactions, in particular forces and reactions.
                + Contents + +

                Applying this new principle

                + When combined with an appropriate energy-effect replicate for cryogenics (slowing down biological activity, thus stabilising the organics), the effect is + effectively identical to cryogenics, and while it consumes vastly more power and requires extremely complex equipment, it's (for all intents and purposes) superior + to cryogenics, all that remains is to 'commercialise' the process by enabling cheaper development and mass production.
                + The Effete Hoffman Principle can be tweak-combined with other effects however, for different purposes. A division of PMC Research initially developed the application + in prisons as a literal 'suspension field' where convicts are held immobile in the air, and the use quickly spread to numerous other areas.
                +
                + By examining the material resonance properties of certain strong waveforms when combined with Hoffman radiation, an effect was produced able to reverse energy + transferral through matter, and to slow the effects of gravity. When combined with energy repulse technology, the triple effects compound themselves into a much + stronger field, although all three components do slightly different things. High energy researchers assure me of the following key points:
                +
                  +
                • The energy repulsion factor provides a 'shell' capable of weak suspension.
                • +
                • The Hoffman emissions nullify energy transferral and other kinetic activity, maintaining stability inside the field.
                • +
                • The resonant waveform combines the effects of the above two points, and applies it magnified onto it's synced 'resonance' materials.
                • +
                + As an interesting aside, a carbon waveform was chosen for the field in prison suspension fields, due to it's resonance with organic matter.
                + Contents + + + + "} \ No newline at end of file diff --git a/code/modules/lighting/__lighting_docs.dm b/code/modules/lighting/__lighting_docs.dm new file mode 100644 index 00000000..79242e28 --- /dev/null +++ b/code/modules/lighting/__lighting_docs.dm @@ -0,0 +1,67 @@ +/* +BS12 object based lighting system +*/ + +/* +Changes from tg DAL: + - Lighting is done using objects instead of subareas. + - Animated transitions. (newer tg DAL has this) + - Full colours with mixing. + - Support for lights on shuttles. + + - Code: + - Instead of one flat luminosity var, light is represented by 3 atom vars: + - light_range; diameter in tiles of the light, used for calculating falloff, Cannot be 1. + - light_power; multiplier for the brightness of lights, + - light_color; hex string representing the RGB colour of the light. + - setLuminousity() is now set_light() and takes the three variables above. + - Variables can be left as null to not update them. + - set_opacity() is now set_opacity(). + - Areas have luminosity set to 1 permanently, no hard-lighting. + - Objects inside other objects can have lights and they properly affect the turf. (flashlights) + - area/master and area/list/related have been eviscerated since subareas aren't needed. +*/ + +/* +Relevant vars/procs: + +atom: (lighting_atom.dm) + - var/light_range; range in tiles of the light, used for calculating falloff + - var/light_power; multiplier for the brightness of lights + - var/light_color; hex string representing the RGB colour of the light + + - var/datum/light_source/light; light source datum for this atom, only present if light_range && light_power + - var/list/light_sources; light sources in contents that are shining through this object, including this object + + - proc/set_light(l_range, l_power, l_color): + - Sets light_range/power/color to non-null args and calls update_light() + - proc/set_opacity(new_opacity): + - Sets opacity to new_opacity. + - If opacity has changed, call turf.reconsider_lights() to fix light occlusion + - proc/update_light(): + - Updates the light var on this atom, deleting or creating as needed and calling .update() + + +turf: (lighting_turf.dm) + - var/list/affecting_lights; list of light sources that are shining onto this turf + + - proc/reconsider_lights(): + - Force all light sources shining onto this turf to update + + - proc/lighting_clear_overlays(): + - Delete (manual GC) all light overlays on this turf, used when changing turf to space + - proc/lighting_build_overlays(): + - Create lighting overlays for this turf + + +atom/movable/lighting_overlay: (lighting_overlay.dm) + - var/lum_r, var/lum_g, var/lum_b; lumcounts of each colour + - var/needs_update; set on update_lumcount, checked by lighting process + + - var/xoffset, var/yoffset; (only present when using sub-tile overlays) fractional offset of this overlay in the tile + + - proc/update_lumcount(delta_r, delta_g, delta_b): + - Change the lumcount vars and queue the overlay for update + - proc/update_overlay() + - Called by the lighting process to update the color of the overlay +*/ \ No newline at end of file diff --git a/code/modules/lighting/lighting_area.dm b/code/modules/lighting/lighting_area.dm new file mode 100644 index 00000000..42bad0ec --- /dev/null +++ b/code/modules/lighting/lighting_area.dm @@ -0,0 +1,8 @@ +/area + luminosity = TRUE + var/dynamic_lighting = TRUE + +/area/New() + ..() + if(dynamic_lighting) + luminosity = FALSE \ No newline at end of file diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm new file mode 100644 index 00000000..99c09fed --- /dev/null +++ b/code/modules/lighting/lighting_atom.dm @@ -0,0 +1,86 @@ +/atom + var/light_power = 1 // intensity of the light + var/light_range = 0 // range in tiles of the light + var/light_color // Hexadecimal RGB string representing the colour of the light + + var/datum/light_source/light + var/list/light_sources + +// Nonsensical value for l_color default, so we can detect if it gets set to null. +#define NONSENSICAL_VALUE -99999 +/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE) + . = 0 //make it less costly if nothing's changed + + if(l_power != null && l_power != light_power) + light_power = l_power + . = 1 + if(l_range != null && l_range != light_range) + light_range = l_range + . = 1 + if(l_color != NONSENSICAL_VALUE && l_color != light_color) + light_color = l_color + . = 1 + + if(.) update_light() + +#undef NONSENSICAL_VALUE + +/atom/proc/update_light() + set waitfor = FALSE + + if(!light_power || !light_range) + if(light) + light.destroy() + light = null + else + if(!istype(loc, /atom/movable)) + . = src + else + . = loc + + if(light) + light.update(.) + else + light = new /datum/light_source(src, .) + +/atom/Destroy() + if(light) + light.destroy() + light = null + return ..() + +/atom/set_opacity() + . = ..() + if(.) + var/turf/T = loc + if(istype(T)) + T.handle_opacity_change(src) + +#define LIGHT_MOVE_UPDATE \ +var/turf/old_loc = loc;\ +. = ..();\ +if(loc != old_loc) {\ + for(var/datum/light_source/L in light_sources) {\ + L.source_atom.update_light();\ + }\ +} + +/atom/movable/Move() + LIGHT_MOVE_UPDATE + +/atom/movable/forceMove() + LIGHT_MOVE_UPDATE + +#undef LIGHT_MOVE_UPDATE + +/obj/item/equipped() + . = ..() + update_light() + +/obj/item/pickup(mob/user) + . = ..() + update_light() + +/obj/item/dropped() + . = ..() + update_light() diff --git a/code/modules/lighting/lighting_corner.dm b/code/modules/lighting/lighting_corner.dm new file mode 100644 index 00000000..cb8206ce --- /dev/null +++ b/code/modules/lighting/lighting_corner.dm @@ -0,0 +1,134 @@ +/var/total_lighting_corners = 0 +/var/datum/lighting_corner/dummy/dummy_lighting_corner = new +// Because we can control each corner of every lighting overlay. +// And corners get shared between multiple turfs (unless you're on the corners of the map, then 1 corner doesn't). +// For the record: these should never ever ever be deleted, even if the turf doesn't have dynamic lighting. + +// This list is what the code that assigns corners listens to, the order in this list is the order in which corners are added to the /turf/corners list. +/var/list/LIGHTING_CORNER_DIAGONAL = list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST) + +/datum/lighting_corner + var/list/turf/masters = list() + var/list/datum/light_source/affecting = list() // Light sources affecting us. + var/active = FALSE // TRUE if one of our masters has dynamic lighting. + + var/x = 0 + var/y = 0 + var/z = 0 + + var/lum_r = 0 + var/lum_g = 0 + var/lum_b = 0 + + var/needs_update = FALSE + + var/cache_r = LIGHTING_SOFT_THRESHOLD + var/cache_g = LIGHTING_SOFT_THRESHOLD + var/cache_b = LIGHTING_SOFT_THRESHOLD + var/cache_mx = 0 + + var/update_gen = 0 + +/datum/lighting_corner/New(var/turf/new_turf, var/diagonal) + . = ..() + + total_lighting_corners++ + + masters[new_turf] = turn(diagonal, 180) + z = new_turf.z + + var/vertical = diagonal & ~(diagonal - 1) // The horizontal directions (4 and 8) are bigger than the vertical ones (1 and 2), so we can reliably say the lsb is the horizontal direction. + var/horizontal = diagonal & ~vertical // Now that we know the horizontal one we can get the vertical one. + + x = new_turf.x + (horizontal == EAST ? 0.5 : -0.5) + y = new_turf.y + (vertical == NORTH ? 0.5 : -0.5) + + // My initial plan was to make this loop through a list of all the dirs (horizontal, vertical, diagonal). + // Issue being that the only way I could think of doing it was very messy, slow and honestly overengineered. + // So we'll have this hardcode instead. + var/turf/T + var/i + + // Diagonal one is easy. + T = get_step(new_turf, diagonal) + if (T) // In case we're on the map's border. + if (!T.corners) + T.corners = list(null, null, null, null) + + masters[T] = diagonal + i = LIGHTING_CORNER_DIAGONAL.Find(turn(diagonal, 180)) + T.corners[i] = src + + // Now the horizontal one. + T = get_step(new_turf, horizontal) + if (T) // Ditto. + if (!T.corners) + T.corners = list(null, null, null, null) + + masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates. + i = LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180)) + T.corners[i] = src + + // And finally the vertical one. + T = get_step(new_turf, vertical) + if (T) + if (!T.corners) + T.corners = list(null, null, null, null) + + masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates. + i = LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180)) + T.corners[i] = src + + update_active() + +/datum/lighting_corner/proc/update_active() + active = FALSE + for (var/turf/T in masters) + if (T.lighting_overlay) + active = TRUE + +// God that was a mess, now to do the rest of the corner code! Hooray! +/datum/lighting_corner/proc/update_lumcount(var/delta_r, var/delta_g, var/delta_b) + lum_r += delta_r + lum_g += delta_g + lum_b += delta_b + + if (!needs_update) + needs_update = TRUE + lighting_update_corners += src + +/datum/lighting_corner/proc/update_overlays() + // Cache these values a head of time so 4 individual lighting overlays don't all calculate them individually. + var/lum_r = src.lum_r > 0 ? LIGHTING_MULT_FACTOR * sqrt(src.lum_r) : src.lum_r + var/lum_g = src.lum_g > 0 ? LIGHTING_MULT_FACTOR * sqrt(src.lum_g) : src.lum_g + var/lum_b = src.lum_b > 0 ? LIGHTING_MULT_FACTOR * sqrt(src.lum_b) : src.lum_b + + var/mx = max(lum_r, lum_g, lum_b) // Scale it so 1 is the strongest lum, if it is above 1. + . = 1 // factor + if (mx > 1) + . = 1 / mx + + #if LIGHTING_SOFT_THRESHOLD != 0 + else if (mx < LIGHTING_SOFT_THRESHOLD) + . = 0 // 0 means soft lighting. + + cache_r = round(lum_r * ., LIGHTING_ROUND_VALUE) || LIGHTING_SOFT_THRESHOLD + cache_g = round(lum_g * ., LIGHTING_ROUND_VALUE) || LIGHTING_SOFT_THRESHOLD + cache_b = round(lum_b * ., LIGHTING_ROUND_VALUE) || LIGHTING_SOFT_THRESHOLD + #else + cache_r = round(lum_r * ., LIGHTING_ROUND_VALUE) + cache_g = round(lum_g * ., LIGHTING_ROUND_VALUE) + cache_b = round(lum_b * ., LIGHTING_ROUND_VALUE) + #endif + cache_mx = round(mx, LIGHTING_ROUND_VALUE) + + for (var/TT in masters) + var/turf/T = TT + if (T.lighting_overlay) + if (!T.lighting_overlay.needs_update) + T.lighting_overlay.needs_update = TRUE + lighting_update_overlays += T.lighting_overlay + + +/datum/lighting_corner/dummy/New() + return diff --git a/code/modules/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm new file mode 100644 index 00000000..b6d3274b --- /dev/null +++ b/code/modules/lighting/lighting_overlay.dm @@ -0,0 +1,141 @@ +/var/total_lighting_overlays = 0 +/atom/movable/lighting_overlay + name = "" + mouse_opacity = 0 + simulated = 0 + anchored = 1 + icon = LIGHTING_ICON + plane = LIGHTING_PLANE + layer = LIGHTING_LAYER + invisibility = INVISIBILITY_LIGHTING + color = LIGHTING_BASE_MATRIX + icon_state = "light1" + blend_mode = BLEND_MULTIPLY + + var/lum_r = 0 + var/lum_g = 0 + var/lum_b = 0 + + var/needs_update = FALSE + +/atom/movable/lighting_overlay/Initialize() + // doesn't need special init + initialized = TRUE + return INITIALIZE_HINT_NORMAL + +/atom/movable/lighting_overlay/New(var/atom/loc, var/no_update = FALSE) + var/turf/T = loc //If this runtimes atleast we'll know what's creating overlays outside of turfs. + if(T.dynamic_lighting) + . = ..() + verbs.Cut() + total_lighting_overlays++ + + T.lighting_overlay = src + T.luminosity = 0 + if(no_update) + return + update_overlay() + else + qdel(src) + +/atom/movable/lighting_overlay/proc/update_overlay() + set waitfor = FALSE + var/turf/T = loc + + if(!istype(T)) + if(loc) + log_debug("A lighting overlay realised its loc was NOT a turf (actual loc: [loc][loc ? ", " + loc.type : "null"]) in update_overlay() and got qdel'ed!") + else + log_debug("A lighting overlay realised it was in nullspace in update_overlay() and got pooled!") + qdel(src) + return + if(!T.dynamic_lighting) + qdel(src) + return + + // To the future coder who sees this and thinks + // "Why didn't he just use a loop?" + // Well my man, it's because the loop performed like shit. + // And there's no way to improve it because + // without a loop you can make the list all at once which is the fastest you're gonna get. + // Oh it's also shorter line wise. + // Including with these comments. + + // See LIGHTING_CORNER_DIAGONAL in lighting_corner.dm for why these values are what they are. + // No I seriously cannot think of a more efficient method, fuck off Comic. + var/datum/lighting_corner/cr = T.corners[3] || dummy_lighting_corner + var/datum/lighting_corner/cg = T.corners[2] || dummy_lighting_corner + var/datum/lighting_corner/cb = T.corners[4] || dummy_lighting_corner + var/datum/lighting_corner/ca = T.corners[1] || dummy_lighting_corner + + var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx) + + var/rr = cr.cache_r + var/rg = cr.cache_g + var/rb = cr.cache_b + + var/gr = cg.cache_r + var/gg = cg.cache_g + var/gb = cg.cache_b + + var/br = cb.cache_r + var/bg = cb.cache_g + var/bb = cb.cache_b + + var/ar = ca.cache_r + var/ag = ca.cache_g + var/ab = ca.cache_b + + #if LIGHTING_SOFT_THRESHOLD != 0 + var/set_luminosity = max > LIGHTING_SOFT_THRESHOLD + #else + // Because of floating points, it won't even be a flat 0. + // This number is mostly arbitrary. + var/set_luminosity = max > 1e-6 + #endif + + if((rr & gr & br & ar) && (rg + gg + bg + ag + rb + gb + bb + ab == 8)) + //anything that passes the first case is very likely to pass the second, and addition is a little faster in this case + icon_state = "transparent" + color = null + else if(!set_luminosity) + icon_state = LIGHTING_ICON_STATE_DARK + color = null + else + icon_state = null + color = list( + rr, rg, rb, 00, + gr, gg, gb, 00, + br, bg, bb, 00, + ar, ag, ab, 00, + 00, 00, 00, 01 + ) + + luminosity = set_luminosity + +// Variety of overrides so the overlays don't get affected by weird things. +/atom/movable/lighting_overlay/ex_act() + return + +/atom/movable/lighting_overlay/singularity_pull() + return + +/atom/movable/lighting_overlay/Destroy() + total_lighting_overlays-- + global.lighting_update_overlays -= src + global.lighting_update_overlays_old -= src + + var/turf/T = loc + if(istype(T)) + T.lighting_overlay = null + + . = ..() + +/atom/movable/lighting_overlay/forceMove() + return 0 //should never move + +/atom/movable/lighting_overlay/Move() + return 0 + +/atom/movable/lighting_overlay/throw_at() + return 0 diff --git a/code/modules/lighting/lighting_setup.dm b/code/modules/lighting/lighting_setup.dm new file mode 100644 index 00000000..68311a32 --- /dev/null +++ b/code/modules/lighting/lighting_setup.dm @@ -0,0 +1,10 @@ +/proc/create_all_lighting_overlays() + for(var/zlevel = 1 to world.maxz) + create_lighting_overlays_zlevel(zlevel) + +/proc/create_lighting_overlays_zlevel(var/zlevel) + ASSERT(zlevel) + + for(var/turf/T in block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel))) + if(T.dynamic_lighting) + T.lighting_build_overlay() diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm new file mode 100644 index 00000000..dbe29e25 --- /dev/null +++ b/code/modules/lighting/lighting_source.dm @@ -0,0 +1,342 @@ +/var/total_lighting_sources = 0 +// This is where the fun begins. +// These are the main datums that emit light. + +/datum/light_source + var/atom/top_atom // The atom we're emitting light from(for example a mob if we're from a flashlight that's being held). + var/atom/source_atom // The atom that we belong to. + + var/turf/source_turf // The turf under the above. + var/light_power // Intensity of the emitter light. + var/light_range // The range of the emitted light. + var/light_color // The colour of the light, string, decomposed by parse_light_color() + + // Variables for keeping track of the colour. + var/lum_r + var/lum_g + var/lum_b + + // The lumcount values used to apply the light. + var/tmp/applied_lum_r + var/tmp/applied_lum_g + var/tmp/applied_lum_b + + var/list/datum/lighting_corner/effect_str // List used to store how much we're affecting corners. + var/list/turf/affecting_turfs + + var/applied = FALSE // Whether we have applied our light yet or not. + + var/vis_update // Whether we should smartly recalculate visibility. and then only update tiles that became(in)visible to us. + var/needs_update // Whether we are queued for an update. + var/destroyed // Whether we are destroyed and need to stop emitting light. + var/force_update + +/datum/light_source/New(var/atom/owner, var/atom/top) + total_lighting_sources++ + source_atom = owner // Set our new owner. + if(!source_atom.light_sources) + source_atom.light_sources = list() + + source_atom.light_sources += src // Add us to the lights of our owner. + top_atom = top + if(top_atom != source_atom) + if(!top.light_sources) + top.light_sources = list() + + top_atom.light_sources += src + + source_turf = top_atom + light_power = source_atom.light_power + light_range = source_atom.light_range + light_color = source_atom.light_color + + parse_light_color() + + effect_str = list() + affecting_turfs = list() + + update() + + + return ..() + +// Kill ourselves. +/datum/light_source/proc/destroy() + total_lighting_sources-- + destroyed = TRUE + force_update() + if(source_atom && source_atom.light_sources) + source_atom.light_sources -= src + + if(top_atom && top_atom.light_sources) + top_atom.light_sources -= src + +// Call it dirty, I don't care. +// This is here so there's no performance loss on non-instant updates from the fact that the engine can also do instant updates. +// If you're wondering what's with the "BYOND" argument: BYOND won't let me have a() macro that has no arguments :|. +#define effect_update(BYOND) \ + if(!needs_update) \ + { \ + lighting_update_lights += src; \ + needs_update = TRUE; \ + } + +// This proc will cause the light source to update the top atom, and add itself to the update queue. +/datum/light_source/proc/update(var/atom/new_top_atom) + // This top atom is different. + if(new_top_atom && new_top_atom != top_atom) + if(top_atom != source_atom) // Remove ourselves from the light sources of that top atom. + top_atom.light_sources -= src + + top_atom = new_top_atom + + if(top_atom != source_atom) + if(!top_atom.light_sources) + top_atom.light_sources = list() + + top_atom.light_sources += src // Add ourselves to the light sources of our new top atom. + + effect_update(null) + +// Will force an update without checking if it's actually needed. +/datum/light_source/proc/force_update() + force_update = 1 + + effect_update(null) + +// Will cause the light source to recalculate turfs that were removed or added to visibility only. +/datum/light_source/proc/vis_update() + vis_update = 1 + + effect_update(null) + +// Will check if we actually need to update, and update any variables that may need to be updated. +/datum/light_source/proc/check() + if(!source_atom || !light_range || !light_power) + destroy() + return 1 + + if(!top_atom) + top_atom = source_atom + . = 1 + + if(isturf(top_atom)) + if(source_turf != top_atom) + source_turf = top_atom + . = 1 + else if(top_atom.loc != source_turf) + source_turf = top_atom.loc + . = 1 + + if(source_atom.light_power != light_power) + light_power = source_atom.light_power + . = 1 + + if(source_atom.light_range != light_range) + light_range = source_atom.light_range + . = 1 + + if(light_range && light_power && !applied) + . = 1 + + if(source_atom.light_color != light_color) + light_color = source_atom.light_color + parse_light_color() + . = 1 + +// Decompile the hexadecimal colour into lumcounts of each perspective. +/datum/light_source/proc/parse_light_color() + if(light_color) + lum_r = GetRedPart (light_color) / 255 + lum_g = GetGreenPart(light_color) / 255 + lum_b = GetBluePart (light_color) / 255 + else + lum_r = 1 + lum_g = 1 + lum_b = 1 + +// Macro that applies light to a new corner. +// It is a macro in the interest of speed, yet not having to copy paste it. +// If you're wondering what's with the backslashes, the backslashes cause BYOND to not automatically end the line. +// As such this all gets counted as a single line. +// The braces and semicolons are there to be able to do this on a single line. + +#define APPLY_CORNER(C) \ + . = LUM_FALLOFF(C, source_turf); \ + . *= light_power/2; \ + effect_str[C] = .; \ + C.update_lumcount \ + ( \ + . * applied_lum_r, \ + . * applied_lum_g, \ + . * applied_lum_b \ + ); + +// I don't need to explain what this does, do I? +#define REMOVE_CORNER(C) \ + . = -effect_str[C]; \ + C.update_lumcount \ + ( \ + . * applied_lum_r, \ + . * applied_lum_g, \ + . * applied_lum_b \ + ); + +// This is the define used to calculate falloff. +#define LUM_FALLOFF(C, T) (1 - CLAMP01(((abs(C.x - T.x) + abs(C.y - T.y))) / max(1, light_range+1))) + +/datum/light_source/proc/apply_lum() + var/static/update_gen = 1 + applied = 1 + + // Keep track of the last applied lum values so that the lighting can be reversed + applied_lum_r = lum_r + applied_lum_g = lum_g + applied_lum_b = lum_b + + FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING) + if(!T.lighting_corners_initialised) + T.generate_missing_corners() + + for(var/datum/lighting_corner/C in T.get_corners()) + if(C.update_gen == update_gen) + continue + + C.update_gen = update_gen + C.affecting += src + + if(!C.active) + effect_str[C] = 0 + continue + + APPLY_CORNER(C) + + + + if(!T.affecting_lights) + T.affecting_lights = list() + + T.affecting_lights += src + affecting_turfs += T + + var/turf/simulated/open/O = T + if(istype(O) && O.below) + // Consider the turf below us as well. (Z-lights) + //Do subprocessing for open turfs + for(T = O.below; !isnull(T); T = process_the_turf(T,update_gen)); + + + + update_gen++ + +/datum/light_source/proc/process_the_turf(var/turf/T, update_gen) + + if(!T.lighting_corners_initialised) + T.generate_missing_corners() + + for(var/datum/lighting_corner/C in T.get_corners()) + if(C.update_gen == update_gen) + continue + + C.update_gen = update_gen + C.affecting += src + + if(!C.active) + effect_str[C] = 0 + continue + + APPLY_CORNER(C) + + + + if(!T.affecting_lights) + T.affecting_lights = list() + + T.affecting_lights += src + affecting_turfs += T + + var/turf/simulated/open/O = T + if(istype(O) && O.below) + return O.below + return null + +/datum/light_source/proc/remove_lum() + applied = FALSE + + for(var/turf/T in affecting_turfs) + if(!T.affecting_lights) + T.affecting_lights = list() + else + T.affecting_lights -= src + + affecting_turfs.Cut() + + for(var/datum/lighting_corner/C in effect_str) + REMOVE_CORNER(C) + + C.affecting -= src + + effect_str.Cut() + +/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C) + if(effect_str.Find(C)) // Already have one. + REMOVE_CORNER(C) + + APPLY_CORNER(C) + +/datum/light_source/proc/smart_vis_update() + var/list/datum/lighting_corner/corners = list() + var/list/turf/turfs = list() + FOR_DVIEW(var/turf/T, light_range, source_turf, 0) + if(!T.lighting_corners_initialised) + T.generate_missing_corners() + corners |= T.get_corners() + turfs += T + + var/turf/simulated/open/O = T + if(istype(O) && O.below) + // Consider the turf below us as well. (Z-lights) + for(T = O.below; !isnull(T); T = update_the_turf(T,corners, turfs)); + + var/list/L = turfs - affecting_turfs // New turfs, add us to the affecting lights of them. + affecting_turfs += L + for(var/turf/T in L) + if(!T.affecting_lights) + T.affecting_lights = list(src) + else + T.affecting_lights += src + + L = affecting_turfs - turfs // Now-gone turfs, remove us from the affecting lights. + affecting_turfs -= L + for(var/turf/T in L) + T.affecting_lights -= src + + for(var/datum/lighting_corner/C in corners - effect_str) // New corners + C.affecting += src + if(!C.active) + effect_str[C] = 0 + continue + + APPLY_CORNER(C) + + for(var/datum/lighting_corner/C in effect_str - corners) // Old, now gone, corners. + REMOVE_CORNER(C) + C.affecting -= src + effect_str -= C + + +/datum/light_source/proc/update_the_turf(var/turf/T, var/list/datum/lighting_corner/corners, var/list/turf/turfs) + if(!T.lighting_corners_initialised) + T.generate_missing_corners() + corners |= T.get_corners() + turfs += T + + var/turf/simulated/open/O = T + if(istype(O) && O.below) + return O.below + return null + +#undef effect_update +#undef LUM_FALLOFF +#undef REMOVE_CORNER +#undef APPLY_CORNER diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm new file mode 100644 index 00000000..6b954ae9 --- /dev/null +++ b/code/modules/lighting/lighting_turf.dm @@ -0,0 +1,113 @@ +/turf + var/dynamic_lighting = TRUE // Does the turf use dynamic lighting? + luminosity = 1 + + var/tmp/lighting_corners_initialised = FALSE + + var/tmp/list/datum/light_source/affecting_lights // List of light sources affecting this turf. + var/tmp/atom/movable/lighting_overlay/lighting_overlay // Our lighting overlay. + var/tmp/list/datum/lighting_corner/corners + var/opaque_counter + +/turf/New() + opaque_counter = opacity + ..() + +/turf/set_opacity() + . = ..() + handle_opacity_change(src) + +// Causes any affecting light sources to be queued for a visibility update, for example a door got opened. +/turf/proc/reconsider_lights() + for(var/datum/light_source/L in affecting_lights) + L.vis_update() + +/turf/proc/lighting_clear_overlay() + if(lighting_overlay) + qdel(lighting_overlay) + + for(var/datum/lighting_corner/C in corners) + C.update_active() + +// Builds a lighting overlay for us, but only if our area is dynamic. +/turf/proc/lighting_build_overlay() + if(lighting_overlay) + return + + var/area/A = loc + if(A.dynamic_lighting) + if(!lighting_corners_initialised) + generate_missing_corners() + + new /atom/movable/lighting_overlay(src) + + for(var/datum/lighting_corner/C in corners) + if(!C.active) // We would activate the corner, calculate the lighting for it. + for(var/L in C.affecting) + var/datum/light_source/S = L + S.recalc_corner(C) + + C.active = TRUE + +// Used to get a scaled lumcount. +/turf/proc/get_lumcount(var/minlum = 0, var/maxlum = 1) + if(!lighting_overlay) + var/area/A = loc + if(A.dynamic_lighting) + var/atom/movable/lighting_overlay/O = new /atom/movable/lighting_overlay(src) + lighting_overlay = O + + var/totallums = 0 + for(var/datum/lighting_corner/L in corners) + totallums += max(L.lum_r, L.lum_g, L.lum_b) + + totallums /= 4 // 4 corners, max channel selected, return the average + + totallums =(totallums - minlum) /(maxlum - minlum) + + return CLAMP01(totallums) + +// If an opaque movable atom moves around we need to potentially update visibility. +/turf/Entered(var/atom/movable/Obj, var/atom/OldLoc) + . = ..() + if(Obj && Obj.opacity) + if(!opaque_counter++) + reconsider_lights() + + +/turf/Exited(var/atom/movable/Obj, var/atom/newloc) + . = ..() + if(Obj && Obj.opacity) + if(!(--opaque_counter)) + reconsider_lights() + +/turf/proc/get_corners() + if(opaque_counter) + return null // Since this proc gets used in a for loop, null won't be looped though. + + return corners + +/turf/proc/generate_missing_corners() + lighting_corners_initialised = TRUE + if(!corners) + corners = list(null, null, null, null) + + for(var/i = 1 to 4) + if(corners[i]) // Already have a corner on this direction. + continue + + corners[i] = new /datum/lighting_corner(src, LIGHTING_CORNER_DIAGONAL[i]) + +/turf/proc/handle_opacity_change(var/atom/opacity_changer) + if(opacity_changer) + if(opacity_changer.opacity) + if(!opaque_counter) + reconsider_lights() + opaque_counter++ + else + var/old_counter = opaque_counter + opaque_counter-- + if(old_counter && !opaque_counter) + reconsider_lights() + + \ No newline at end of file diff --git a/code/modules/lighting/~lighting_undefs.dm b/code/modules/lighting/~lighting_undefs.dm new file mode 100644 index 00000000..2de3f9db --- /dev/null +++ b/code/modules/lighting/~lighting_undefs.dm @@ -0,0 +1,7 @@ +#undef LIGHTING_FALLOFF +#undef LIGHTING_LAMBERTIAN +#undef LIGHTING_HEIGHT + +#undef LIGHTING_ICON + +#undef LIGHTING_BASE_MATRIX diff --git a/code/modules/lobby_music/Torch.dm b/code/modules/lobby_music/Torch.dm new file mode 100644 index 00000000..680c05f9 --- /dev/null +++ b/code/modules/lobby_music/Torch.dm @@ -0,0 +1,14 @@ +/lobby_music/torch + artist = "L. Luke Leimer/LorenLuke" + title = "Torch: A Light in the Darkness" + song = 'sound/music/Torch.ogg' + license = CC_BY_NC_SA_3_0 + url = "https://soundcloud.com/luke-leimer/torch-a-light-in-the-darkness" + +/* +'Torch: A Light in the Darkness' composed by: Loren Luke Leimer, (c) 2017 + +Licensed for use under Creative Commons License: CC BY-SA 3.0 + +Link to online version at: https://soundcloud.com/luke-leimer/torch-a-light-in-the-darkness +*/ diff --git a/code/modules/lobby_music/_licenses.dm b/code/modules/lobby_music/_licenses.dm new file mode 100644 index 00000000..e041ea9f --- /dev/null +++ b/code/modules/lobby_music/_licenses.dm @@ -0,0 +1,11 @@ +var/const/CC_BY_3_0 = "CC BY 3.0" +var/const/CC_BY_NC_3_0 = "CC BY-BC 3.0" +var/const/CC_BY_NC_SA_3_0 = "CC BY-NC-SA 3.0" +var/const/CC_BY_NC_ND_4_0 = "CC BY-NC-ND 4.0" + +var/list/license_to_url = list( + "[CC_BY_3_0]" = "https://creativecommons.org/licenses/by/3.0/", + "[CC_BY_NC_3_0]" = "https://creativecommons.org/licenses/by-nc/3.0/", + "[CC_BY_NC_SA_3_0]" = "https://creativecommons.org/licenses/by-nc-sa/3.0/", + "[CC_BY_NC_ND_4_0]" = "https://creativecommons.org/licenses/by-nc-nd/4.0/" + ) diff --git a/code/modules/lobby_music/_lobby_music.dm b/code/modules/lobby_music/_lobby_music.dm new file mode 100644 index 00000000..7b055213 --- /dev/null +++ b/code/modules/lobby_music/_lobby_music.dm @@ -0,0 +1,23 @@ +// Include the lobby music tracks to automatically add them to the random selection. + +/lobby_music + var/artist + var/title + var/album + var/license + var/song + var/url // Remember to include http:// or https:// + + +/lobby_music/proc/play_to(var/listener) + if(!song) + return + if(title) + to_chat(listener, "Now Playing:") + to_chat(listener, "[title][artist ? " by [artist]" : ""][album ? " ([album])" : ""]") + if(url) + to_chat(listener, url) + if(license) + var/license_url = license_to_url[license] + to_chat(listener, "License: [license_url ? "[license]" : license]") + sound_to(listener, sound(song, repeat = 1, wait = 0, volume = 70, channel = 1)) diff --git a/code/modules/lobby_music/absconditus.dm b/code/modules/lobby_music/absconditus.dm new file mode 100644 index 00000000..d1d20271 --- /dev/null +++ b/code/modules/lobby_music/absconditus.dm @@ -0,0 +1,5 @@ +/lobby_music/absconditus + artist = "Zhay Tee" + title = "Absconditus" + album = "Minerva: Metastasis OST" + song = 'sound/music/traitor.ogg' diff --git a/code/modules/lobby_music/businessend.dm b/code/modules/lobby_music/businessend.dm new file mode 100644 index 00000000..59249317 --- /dev/null +++ b/code/modules/lobby_music/businessend.dm @@ -0,0 +1,6 @@ +/lobby_music/businessend + artist = "Cletus Got Shot" + title = "Business End" + song = 'sound/music/businessend.ogg' + album = "Unamerican" + license = CC_BY_NC_SA_3_0 \ No newline at end of file diff --git a/code/modules/lobby_music/chasing_time.dm b/code/modules/lobby_music/chasing_time.dm new file mode 100644 index 00000000..d0a0df94 --- /dev/null +++ b/code/modules/lobby_music/chasing_time.dm @@ -0,0 +1,7 @@ +/lobby_music/chasing_time + artist = "Dexter Britain" + title = "Chasing Time" + album = "Creative Commons Vol. 1" + song = 'sound/music/chasing_time.ogg' + license = CC_BY_NC_SA_3_0 + url = "http://www.dexterbritain.co.uk" diff --git a/code/modules/lobby_music/clouds_of_fire.dm b/code/modules/lobby_music/clouds_of_fire.dm new file mode 100644 index 00000000..a4f90121 --- /dev/null +++ b/code/modules/lobby_music/clouds_of_fire.dm @@ -0,0 +1,4 @@ +/lobby_music/clouds_of_fire + artist = "Hector/dMk" + title = "Clouds of Fire" + song = 'sound/music/clouds.s3m' diff --git a/code/modules/lobby_music/comet_haley.dm b/code/modules/lobby_music/comet_haley.dm new file mode 100644 index 00000000..cf4e71cc --- /dev/null +++ b/code/modules/lobby_music/comet_haley.dm @@ -0,0 +1,7 @@ +/lobby_music/comet_haley + artist = "Stellardrone" + title = "Comet Halley" + album = "Light Years" + song = 'sound/music/comet_haley.ogg' + license = CC_BY_3_0 + url = "http://freemusicarchive.org/music/Stellardrone/Light_Years_1227/07_Comet_Halley" \ No newline at end of file diff --git a/code/modules/lobby_music/dilbert.dm b/code/modules/lobby_music/dilbert.dm new file mode 100644 index 00000000..34c91667 --- /dev/null +++ b/code/modules/lobby_music/dilbert.dm @@ -0,0 +1,5 @@ +/lobby_music/dilbert + title = "Robocop.mp3" + album = "Dehumanize Yourself and Face to Bloodshed" + artist = "CBoyardee" + song = 'sound/music/title2.ogg' diff --git a/code/modules/lobby_music/endless_space.dm b/code/modules/lobby_music/endless_space.dm new file mode 100644 index 00000000..32bfdf90 --- /dev/null +++ b/code/modules/lobby_music/endless_space.dm @@ -0,0 +1,4 @@ +/lobby_music/endless_space + artist = "SolusLunes" + title = "Endless Space" + song = 'sound/music/space.ogg' diff --git a/code/modules/lobby_music/generic_songs.dm b/code/modules/lobby_music/generic_songs.dm new file mode 100644 index 00000000..47b8c1ca --- /dev/null +++ b/code/modules/lobby_music/generic_songs.dm @@ -0,0 +1,27 @@ +//Orange please do not remove my lobby songs again without telling me thanks. - Matt +///lobby_music/lowlife +// song = 'sound/music/lobbylife.ogg' + +/lobby_music/lobby1 + song = 'sound/music/lobby1.ogg' + +/lobby_music/lobby2 + song = 'sound/music/lobby2.ogg' + +/lobby_music/lobby3 + song = 'sound/music/lobby3.ogg' + +/lobby_music/lobby4 + song = 'sound/music/lobby4.ogg' + +/lobby_music/lobby5 + song = 'sound/music/lobby5.ogg' + +/lobby_music/lobby6 + song = 'sound/music/lobby6.ogg' + +/lobby_music/lobby7 + song = 'sound/music/lobby7.ogg' + +/lobby_music/lobby8 + song = 'sound/music/lobby8.ogg' diff --git a/code/modules/lobby_music/human.dm b/code/modules/lobby_music/human.dm new file mode 100644 index 00000000..9ed8c8d3 --- /dev/null +++ b/code/modules/lobby_music/human.dm @@ -0,0 +1,7 @@ +/lobby_music/human + artist = "Borrtex" + title = "Human" + album = "Creation" + song = 'sound/music/human.ogg' + license = CC_BY_NC_3_0 + url = "http://freemusicarchive.org/music/Borrtex/Creation/Borrtex_11_Human" \ No newline at end of file diff --git a/code/modules/lobby_music/lysendraa.dm b/code/modules/lobby_music/lysendraa.dm new file mode 100644 index 00000000..65a2850f --- /dev/null +++ b/code/modules/lobby_music/lysendraa.dm @@ -0,0 +1,7 @@ +/lobby_music/lysendraa + artist = "TALES" + title = "Memories Of Lysendraa" + album = "The Seskian Wars" + song = 'sound/music/lysendraa.ogg' + license = CC_BY_NC_ND_4_0 + url = "http://freemusicarchive.org/music/TALES/The_Seskian_Wars/8-Memories_Of_Lysendraa" \ No newline at end of file diff --git a/code/modules/lobby_music/marhaba.dm b/code/modules/lobby_music/marhaba.dm new file mode 100644 index 00000000..4fd3c2b6 --- /dev/null +++ b/code/modules/lobby_music/marhaba.dm @@ -0,0 +1,7 @@ +/lobby_music/marhaba + artist = "Ian Alex Mac" + title = "Marhaba" + album = "Cues" + song = 'sound/music/marhaba.ogg' + license = CC_BY_3_0 + url = "http://freemusicarchive.org/music/Ian_Alex_Mac/Cues/Marhaba" \ No newline at end of file diff --git a/code/modules/lobby_music/salutjohn.dm b/code/modules/lobby_music/salutjohn.dm new file mode 100644 index 00000000..71d98bba --- /dev/null +++ b/code/modules/lobby_music/salutjohn.dm @@ -0,0 +1,7 @@ +/lobby_music/salutjohn + artist = "Quimorucru" + title = "Salut John" + song = 'sound/music/salutjohn.ogg' + album = "Un méchant party" + license = CC_BY_NC_ND_4_0 + url = "http://freemusicarchive.org/music/Quimorucru/Un_mchant_party/Quimorucru_-_Un_mchant_party__Compilation__-_20_Salut_John" \ No newline at end of file diff --git a/code/modules/lobby_music/space_oddity.dm b/code/modules/lobby_music/space_oddity.dm new file mode 100644 index 00000000..09789f33 --- /dev/null +++ b/code/modules/lobby_music/space_oddity.dm @@ -0,0 +1,4 @@ +/lobby_music/space_oddity + artist = "Chris Hadfield" + title = "Space Oddity" + song = 'sound/music/space_oddity.ogg' diff --git a/code/modules/lobby_music/title1.dm b/code/modules/lobby_music/title1.dm new file mode 100644 index 00000000..d7f34ed0 --- /dev/null +++ b/code/modules/lobby_music/title1.dm @@ -0,0 +1,4 @@ +/lobby_music/level3_mod + artist = "VScratch?" + title = "Level3.Mod" + song = 'sound/music/title1.ogg' diff --git a/code/modules/lobby_music/treacherous_voyage.dm b/code/modules/lobby_music/treacherous_voyage.dm new file mode 100644 index 00000000..00cacf86 --- /dev/null +++ b/code/modules/lobby_music/treacherous_voyage.dm @@ -0,0 +1,7 @@ +/lobby_music/treacherous_voyage + artist = "Jon Luc Hefferman" + title = "Treacherous Voyage" + album = "Eilean Mor" + song = 'sound/music/treacherous_voyage.ogg' + license = CC_BY_NC_3_0 + url = "http://freemusicarchive.org/music/Jon_Luc_Hefferman/20170730112628534/Treacherous_Voyage" \ No newline at end of file diff --git a/code/modules/locks/key.dm b/code/modules/locks/key.dm new file mode 100644 index 00000000..b167fc15 --- /dev/null +++ b/code/modules/locks/key.dm @@ -0,0 +1,30 @@ +/obj/item/weapon/key + name = "key" + desc = "Used to unlock things." + icon = 'icons/obj/items.dmi' + icon_state = "keys" + w_class = 1 + var/key_data = "" + +/obj/item/weapon/key/New(var/newloc,var/data) + if(data) + key_data = data + ..(newloc) + +/obj/item/weapon/key/proc/get_data(var/mob/user) + return key_data + +/obj/item/weapon/key/soap + name = "soap key" + desc = "a fragile key made using a bar of soap." + var/uses = 0 + +/obj/item/weapon/key/soap/get_data(var/mob/user) + uses-- + if(uses == 1) + to_chat(user, "\The [src] is going to break soon!") + else if(uses <= 0) + user.drop_item(src) + to_chat(user, "\The [src] crumbles in your hands.") + qdel(src) + return ..() diff --git a/code/modules/locks/lock.dm b/code/modules/locks/lock.dm new file mode 100644 index 00000000..dbfbd229 --- /dev/null +++ b/code/modules/locks/lock.dm @@ -0,0 +1,79 @@ +#define LOCK_LOCKED 1 +#define LOCK_BROKEN 2 + + +/datum/lock + var/status = 1 //unlocked, 1 == locked 2 == broken + var/lock_data = "" //basically a randomized string. The longer the string the more complex the lock. + var/atom/holder + +/datum/lock/New(var/atom/h, var/complexity = 1) + holder = h + if(istext(complexity)) + lock_data = complexity + else + lock_data = generateRandomString(complexity) + +/datum/lock/Destroy() + holder = null + ..() + +/datum/lock/proc/unlock(var/key = "", var/mob/user) + if(status ^ LOCK_LOCKED) + to_chat(user, "Its already unlocked!") + return 2 + key = get_key_data(key, user) + if(cmptext(lock_data,key) && (status ^ LOCK_BROKEN)) + status &= ~LOCK_LOCKED + return 1 + return 0 + +/datum/lock/proc/lock(var/key = "", var/mob/user) + if(status & LOCK_LOCKED) + to_chat(user, "Its already locked!") + return 2 + key = get_key_data(key, user) + if(cmptext(lock_data,key) && (status ^ LOCK_BROKEN)) + status |= LOCK_LOCKED + return 1 + return 0 + +/datum/lock/proc/toggle(var/key = "", var/mob/user) + if(status & LOCK_LOCKED) + return unlock(key, user) + else + return lock(key, user) + +/datum/lock/proc/getComplexity() + return length(lock_data) + +/datum/lock/proc/get_key_data(var/key = "", var/mob/user) + if(istype(key,/obj/item/weapon/key)) + var/obj/item/weapon/key/K = key + return K.get_data(user) + if(istext(key)) + return key + return null + +/datum/lock/proc/isLocked() + return status & LOCK_LOCKED + +/datum/lock/proc/pick_lock(var/obj/item/I, var/mob/user) + if(!istype(I) || (status ^ LOCK_LOCKED)) + return 0 + var/unlock_power = I.lock_picking_level + if(!unlock_power) + return 0 + user.visible_message("\The [user] takes out \the [I], picking \the [holder]'s lock.") + if(!do_after(user, 20, holder)) + return 0 + if(prob(20*(unlock_power/getComplexity()))) + to_chat(user, "You pick open \the [holder]'s lock!") + unlock(lock_data) + return 1 + else if(prob(5 * unlock_power)) + to_chat(user, "You accidently break \the [holder]'s lock with your [I]!") + status |= LOCK_BROKEN + else + to_chat(user, "You fail to pick open \the [holder].") + return 0 \ No newline at end of file diff --git a/code/modules/locks/lock_construct.dm b/code/modules/locks/lock_construct.dm new file mode 100644 index 00000000..c6556fc1 --- /dev/null +++ b/code/modules/locks/lock_construct.dm @@ -0,0 +1,35 @@ +/obj/item/weapon/material/lock_construct + name = "lock" + desc = "a crude but useful lock and bolt." + icon = 'icons/obj/storage.dmi' + icon_state = "largebinemag" + w_class = ITEM_SIZE_TINY + var/lock_data + +/obj/item/weapon/material/lock_construct/New() + ..() + force = 0 + throwforce = 0 + lock_data = generateRandomString(round(material.integrity/50)) + +/obj/item/weapon/material/lock_construct/attackby(var/obj/item/I, var/mob/user) + if(istype(I,/obj/item/weapon/key)) + var/obj/item/weapon/key/K = I + if(!K.key_data) + to_chat(user, "You fashion \the [I] to unlock \the [src]") + K.key_data = lock_data + else + to_chat(user, "\The [I] already unlocks something...") + return + if(istype(I,/obj/item/weapon/material/lock_construct)) + var/obj/item/weapon/material/lock_construct/L = I + src.lock_data = L.lock_data + to_chat(user, "You copy the lock from \the [L] to \the [src], making them identical.") + return + ..() + +/obj/item/weapon/material/lock_construct/proc/create_lock(var/atom/target, var/mob/user) + . = new /datum/lock(target,lock_data) + user.drop_item(src) + user.visible_message("\The [user] attaches \the [src] to \the [target]") + qdel(src) \ No newline at end of file diff --git a/code/modules/maps/dmm_suite.dm b/code/modules/maps/dmm_suite.dm new file mode 100644 index 00000000..8b9ec295 --- /dev/null +++ b/code/modules/maps/dmm_suite.dm @@ -0,0 +1,65 @@ +var/global/dmm_suite/maploader = new + +dmm_suite{ + /* + + dmm_suite version 1.0 + Released January 30th, 2011. + + NOTE: Map saving functionality removed + + defines the object /dmm_suite + - Provides the proc load_map() + - Loads the specified map file onto the specified z-level. + - provides the proc write_map() + - Returns a text string of the map in dmm format + ready for output to a file. + - provides the proc save_map() + - Returns a .dmm file if map is saved + - Returns FALSE if map fails to save + + The dmm_suite provides saving and loading of map files in BYOND's native DMM map + format. It approximates the map saving and loading processes of the Dream Maker + and Dream Seeker programs so as to allow editing, saving, and loading of maps at + runtime. + + ------------------------ + + To save a map at runtime, create an instance of /dmm_suite, and then call + write_map(), which accepts three arguments: + - A turf representing one corner of a three dimensional grid (Required). + - Another turf representing the other corner of the same grid (Required). + - Any, or a combination, of several bit flags (Optional, see documentation). + + The order in which the turfs are supplied does not matter, the /dmm_writer will + determine the grid containing both, in much the same way as DM's block() function. + write_map() will then return a string representing the saved map in dmm format; + this string can then be saved to a file, or used for any other purose. + + ------------------------ + + To load a map at runtime, create an instance of /dmm_suite, and then call load_map(), + which accepts two arguments: + - A .dmm file to load (Required). + - A number representing the z-level on which to start loading the map (Optional). + + The /dmm_suite will load the map file starting on the specified z-level. If no + z-level was specified, world.maxz will be increased so as to fit the map. Note + that if you wish to load a map onto a z-level that already has objects on it, + you will have to handle the removal of those objects. Otherwise the new map will + simply load the new objects on top of the old ones. + + Also note that all type paths specified in the .dmm file must exist in the world's + code, and that the /dmm_reader trusts that files to be loaded are in fact valid + .dmm files. Errors in the .dmm format will cause runtime errors. + + */ + + proc/load_map(var/list/dmm_files, var/x_offset, var/y_offset, var/z_offset, var/cropMap, var/measureOnly, var/no_changeturf){ + // dmm_files: A list of .dmm files to load (Required). + // z_offset: A number representing the z-level on which to start loading the map (Optional). + // cropMap: When true, the map will be cropped to fit the existing world dimensions (Optional). + // measureOnly: When true, no changes will be made to the world (Optional). + // no_changeturf: When true, turf/AfterChange won't be called on loaded turfs + } +} \ No newline at end of file diff --git a/code/modules/maps/fromdmp.dm b/code/modules/maps/fromdmp.dm new file mode 100644 index 00000000..1fd82f73 --- /dev/null +++ b/code/modules/maps/fromdmp.dm @@ -0,0 +1,251 @@ +/* + DMP to swapmap converter + version 1.0 + + by Lummox JR + */ + +mob/verb/Convert(filename as file) + dmp2swapmap(filename) + +proc/d2sm_prepmap(filename) + var/txt = file2text(filename) + if(!txt) return + var/i,j + i=findText(txt,ascii2text(13)) // eliminate carriage returns + while(i) + txt=copytext(txt,1,i)+copytext(txt,i+1) + i=findText(txt,ascii2text(13),i) + i=findText(txt,"\\\n") + while(i) + for(j=i+2,j<=length(txt),++j) if(text2ascii(txt,j)>32) break + txt=copytext(txt,1,i)+copytext(txt,j) + i=findText(txt,"\\\n",i) + return txt + +proc/dmp2swapmap(filename) + //var/txt = file2text(filename) + //if(!txt) return + var/txt = d2sm_prepmap(filename) + var/mapname="[filename]" + var/i,j,k + i=findtext(mapname,".dmp") + while(i && i+432) break + txt=copytext(txt,1,i)+copytext(txt,j) + i=findText(txt,"\\\n",i) */ + var/list/codes=new + var/codelen=1 + var/list/areas + var/mode=34 + var/z=0 + var/X=0,Y=0,Z=0 + while(txt) + if(text2ascii(txt)==34) + if(mode!=34) + to_world("Corrupt map file [filename]: Unexpected code found after z-level [z]") + + return + // standard line: + // "a" = (/obj, /obj, /turf, /area) + i=findtext(txt,"\"",2) + var/code=copytext(txt,2,i) + codelen=length(code) + i=findtext(txt,"(",i) + if(!i) + to_world("Corrupt map file [filename]: No type list follows \"[code]\"") + + return + k=findtext(txt,"\n",++i) + j=(k || length(txt+1)) + while(--j>=i && text2ascii(txt,j)!=41) + if(j2) codetrans+=d2sm_Contents(L,L.len-2,"\t\t\t\t") + codes[code]=copytext(codetrans,1,length(codetrans)) + else if(text2ascii(txt)==40) + mode=40 + // standard line (top-down, left-right symbol order): + // (1,1,1) = {" + // abcde + // bcdef + // "} + i=d2sm_MatchBrace(txt,1,40) + if(!i) + to_world("Corrupt map file [filename]: No matching ) for coordinates: [copytext(txt,1,findtext(txt,"\n"))]") + + return + var/list/coords=d2sm_ParseCommaList(copytext(txt,2,i)) + if(istext(coords) || coords.len!=3) + to_world("Corrupt map file [filename]: [istext(coords)?(coords):"[copytext(txt,1,i+1)] is not a valid (x,y,z) coordinate"]") + + return + j=findtext(txt,"{",i+1) + if(!j) + to_world("Corrupt map file [filename]: No braces {} following [copytext(txt,1,i+1)]") + + return + k=d2sm_MatchBrace(txt,j,123) + if(!k) + to_world("Corrupt map file [filename]: No closing brace } following [copytext(txt,1,i+1)]") + + return + var/mtxt=copytext(txt,j+1,k) + if(findText(mtxt,"\"\n")!=1 || !findText(mtxt,"\n\"",length(mtxt)-1)) + to_world(findText(mtxt,"\"\n")) + + to_world(findText(mtxt,"\n\"",length(mtxt)-1)) + + to_world("Corrupt map file [filename]: No quotes in braces following [copytext(txt,1,i+1)]") + + return + mtxt=copytext(mtxt,2,length(mtxt)) + var/_x=0,_y=0 + for(i=1,,++_y) + j=findText(mtxt,"\n",i+1) + if(!j) break + _x=max(_x,(j-i-1)/codelen) + i=j + X=max(X,_x) + Y=max(Y,_y) + z=text2num(coords[3]) + Z=max(Z,z) + txt=copytext(txt,k+1) + else + i=findtext(txt,"\n") + txt=i?copytext(txt,i+1):null + to_world("Map size: [X],[Y],[Z]") + + //for(var/code in codes) +// to_world("Code \"[code]\":\n[codes[code]]") + + fdel("map_[mapname].txt") + var/F = file("map_[mapname].txt") + F << ". = object(\".0\")\n.0\n\ttype = /swapmap\n\tid = \"[mapname]\"\n\tz = [Z]\n\ty = [Y]\n\tx = [X]" + if(areas) + txt="" + for(i=0,i0,--y) // map is top-down + ++i + F << "\t\t[y]" + for(var/x in 1 to _x) + F << "\t\t\t[x]" + j=i+codelen + F << codes[copytext(mtxt,i,j)] + i=j + txt=copytext(txt,k+1) + /* for(z in 1 to Z) + F << "\t[z]" + for(var/y in 1 to Y) + F << "\t\t[y]" + for(var/x in 1 to X) + F << "\t\t\t[x]" + F << codes[pick(codes)] */ + +proc/d2sm_ParseCommaList(txt) + var/list/L=new + var/i,ch + for(i=1,i<=length(txt),++i) + if(text2ascii(txt,i)>32) break + for(,i<=length(txt),++i) + ch=text2ascii(txt,i) + if(ch==44) + L+=copytext(txt,1,i) + for(++i,i<=length(txt),++i) if(text2ascii(txt,i)>32) break + txt=copytext(txt,i) + i=0;continue + if(ch==40 || ch==91 || ch==123) + i=d2sm_MatchBrace(txt,i,ch) + if(!i) return "No matching brace found for [ascii2text(ch)]" + if(i>1) L+=copytext(txt,1,i) + return L + +proc/d2sm_MatchBrace(txt, i, which) + if(which==40) ++which + else which+=2 + var/j,ch + for(j=i+1,j<=length(txt),++j) + ch=text2ascii(txt,j) + if(ch==which) return j + if(ch==40 || ch==91 || ch==123) + j=d2sm_MatchBrace(txt,j,ch) + if(!j) return 0 + +proc/d2sm_ConvertType(tt,tabs="") + var/i=findText(tt,"{") + if(!i) return "[tabs]type = [tt]\n" + .="[tabs]type = [copytext(tt,1,i)]\n" + var/list/L=d2sm_ParseCommaList(copytext(tt,i+1,d2sm_MatchBrace(tt,i,123))) + if(istext(L)) return + for(var/pair in L) + .="[.][tabs][pair]\n" + +proc/d2sm_Contents(list/conts,n,tabs="") + .="[tabs]contents = list(" + var/i + for(i=0,i world.maxx) + return + if(T.y+height > world.maxy) + return + + var/list/atoms_to_initialise = list() + + for (var/mappath in mappaths) + var/datum/map_load_metadata/M = maploader.load_map(file(mappath), T.x, T.y, T.z, cropMap=TRUE, clear_contents=clear_contents) + if (M) + atoms_to_initialise += M.atoms_to_initialise + else + return FALSE + + //initialize things that are normally initialized after map load + init_atoms(atoms_to_initialise) + init_shuttles() + log_game("[name] loaded at at [T.x],[T.y],[T.z]") + loaded++ + + return TRUE + +/datum/map_template/proc/extend_bounds_if_needed(var/list/existing_bounds, var/list/new_bounds) + var/list/bounds_to_combine = existing_bounds.Copy() + for (var/min_bound in list(MAP_MINX, MAP_MINY, MAP_MINZ)) + bounds_to_combine[min_bound] = min(existing_bounds[min_bound], new_bounds[min_bound]) + for (var/max_bound in list(MAP_MAXX, MAP_MAXY, MAP_MAXZ)) + bounds_to_combine[max_bound] = max(existing_bounds[max_bound], new_bounds[max_bound]) + return bounds_to_combine + + +/datum/map_template/proc/get_affected_turfs(turf/T, centered = FALSE) + var/turf/placement = T + if(centered) + var/turf/corner = locate(placement.x - round(width/2), placement.y - round(height/2), placement.z) + if(corner) + placement = corner + return block(placement, locate(placement.x+width-1, placement.y+height-1, placement.z)) + +//for your ever biggening badminnery kevinz000 +//⤠- Cyberboss +/proc/load_new_z_level(var/file, var/name) + var/datum/map_template/template = new(file, name) + template.load_new_z() diff --git a/code/modules/maps/reader.dm b/code/modules/maps/reader.dm new file mode 100644 index 00000000..5085ff5e --- /dev/null +++ b/code/modules/maps/reader.dm @@ -0,0 +1,544 @@ +/////////////////////////////////////////////////////////////// +//SS13 Optimized Map loader +////////////////////////////////////////////////////////////// + +//global datum that will preload variables on atoms instanciation +GLOBAL_VAR_INIT(use_preloader, FALSE) +GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) + +/datum/map_load_metadata + var/bounds + var/list/atoms_to_initialise + +/dmm_suite + // /"([a-zA-Z]+)" = \(((?:.|\n)*?)\)\n(?!\t)|\((\d+),(\d+),(\d+)\) = \{"([a-zA-Z\n]*)"\}/g + var/static/regex/dmmRegex = new/regex({""(\[a-zA-Z]+)" = \\(((?:.|\n)*?)\\)\n(?!\t)|\\((\\d+),(\\d+),(\\d+)\\) = \\{"(\[a-zA-Z\n]*)"\\}"}, "g") + // /^[\s\n]+"?|"?[\s\n]+$|^"|"$/g + var/static/regex/trimQuotesRegex = new/regex({"^\[\\s\n]+"?|"?\[\\s\n]+$|^"|"$"}, "g") + // /^[\s\n]+|[\s\n]+$/ + var/static/regex/trimRegex = new/regex("^\[\\s\n]+|\[\\s\n]+$", "g") + var/static/list/modelCache = list() + var/static/space_key + #ifdef TESTING + var/static/turfsSkipped + #endif + +/** + * Construct the model map and control the loading process + * + * WORKING : + * + * 1) Makes an associative mapping of model_keys with model + * e.g aa = /turf/unsimulated/wall{icon_state = "rock"} + * 2) Read the map line by line, parsing the result (using parse_grid) + * + */ +/dmm_suite/load_map(var/dmm_file, var/x_offset, var/y_offset, var/z_offset, var/cropMap, var/measureOnly, var/no_changeturf, var/clear_contents, var/lower_crop_x, var/lower_crop_y, var/upper_crop_x, var/upper_crop_y) + //How I wish for RAII + Master.StartLoadingMap() + space_key = null + #ifdef TESTING + turfsSkipped = 0 + #endif + . = load_map_impl(dmm_file, x_offset, y_offset, z_offset, cropMap, measureOnly, no_changeturf, clear_contents, lower_crop_x, upper_crop_x, lower_crop_y, upper_crop_y) + #ifdef TESTING + if(turfsSkipped) + testing("Skipped loading [turfsSkipped] default turfs") + #endif + Master.StopLoadingMap() + +/dmm_suite/proc/load_map_impl(dmm_file, x_offset, y_offset, z_offset, cropMap, measureOnly, no_changeturf, clear_contents, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper = INFINITY) + var/tfile = dmm_file//the map file we're creating + if(isfile(tfile)) + tfile = file2text(tfile) + + if(!x_offset) + x_offset = 1 + if(!y_offset) + y_offset = 1 + if(!z_offset) + z_offset = world.maxz + 1 + + var/list/bounds = list(1.#INF, 1.#INF, 1.#INF, -1.#INF, -1.#INF, -1.#INF) + var/list/grid_models = list() + var/key_len = 0 + + var/stored_index = 1 + + var/list/atoms_to_initialise = list() + var/list/atoms_to_delete = list() + + while(dmmRegex.Find(tfile, stored_index)) + stored_index = dmmRegex.next + + // "aa" = (/type{vars=blah}) + if(dmmRegex.group[1]) // Model + var/key = dmmRegex.group[1] + if(grid_models[key]) // Duplicate model keys are ignored in DMMs + continue + if(key_len != length(key)) + if(!key_len) + key_len = length(key) + else + throw EXCEPTION("Inconsistant key length in DMM") + if(!measureOnly) + grid_models[key] = dmmRegex.group[2] + + // (1,1,1) = {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"} + else if(dmmRegex.group[3]) // Coords + if(!key_len) + throw EXCEPTION("Coords before model definition in DMM") + + var/curr_x = text2num(dmmRegex.group[3]) + + if(curr_x < x_lower || curr_x > x_upper) + continue + + var/xcrdStart = curr_x + x_offset - 1 + //position of the currently processed square + var/xcrd + var/ycrd = text2num(dmmRegex.group[4]) + y_offset - 1 + var/zcrd = text2num(dmmRegex.group[5]) + z_offset - 1 + + var/is_connected_to_lower_levels = AreConnectedZLevels(zcrd, z_offset) + var/is_on_an_existing_zlevel = zcrd <= world.maxz + + if (is_on_an_existing_zlevel && !is_connected_to_lower_levels) + continue + + var/zexpansion = zcrd > world.maxz + if(zexpansion && !measureOnly) // don't actually expand the world if we're only measuring bounds + if(cropMap) + continue + else + world.maxz = zcrd //create a new z_level if needed + if(!no_changeturf) + WARNING("Z-level expansion occurred without no_changeturf set, this may cause problems when /turf/post_change is called.") + + bounds[MAP_MINX] = min(bounds[MAP_MINX], Clamp(xcrdStart, x_lower, x_upper)) + bounds[MAP_MINZ] = min(bounds[MAP_MINZ], zcrd) + bounds[MAP_MAXZ] = max(bounds[MAP_MAXZ], zcrd) + + var/list/gridLines = splittext(dmmRegex.group[6], "\n") + + var/leadingBlanks = 0 + while(leadingBlanks < gridLines.len && gridLines[++leadingBlanks] == "") + if(leadingBlanks > 1) + gridLines.Cut(1, leadingBlanks) // Remove all leading blank lines. + + if(!gridLines.len) // Skip it if only blank lines exist. + continue + + if(gridLines.len && gridLines[gridLines.len] == "") + gridLines.Cut(gridLines.len) // Remove only one blank line at the end. + + bounds[MAP_MINY] = min(bounds[MAP_MINY], Clamp(ycrd, y_lower, y_upper)) + ycrd += gridLines.len - 1 // Start at the top and work down + + if(!cropMap && ycrd > world.maxy) + if(!measureOnly) + world.maxy = ycrd // Expand Y here. X is expanded in the loop below + bounds[MAP_MAXY] = max(bounds[MAP_MAXY], Clamp(ycrd, y_lower, y_upper)) + else + bounds[MAP_MAXY] = max(bounds[MAP_MAXY], Clamp(min(ycrd, world.maxy), y_lower, y_upper)) + + var/maxx = xcrdStart + if(measureOnly) + for(var/line in gridLines) + maxx = max(maxx, xcrdStart + length(line) / key_len - 1) + else + for(var/line in gridLines) + if((ycrd - y_offset + 1) < y_lower || (ycrd - y_offset + 1) > y_upper) //Reverse operation and check if it is out of bounds of cropping. + --ycrd + continue + if(ycrd <= world.maxy && ycrd >= 1) + xcrd = xcrdStart + for(var/tpos = 1 to length(line) - key_len + 1 step key_len) + if((xcrd - x_offset + 1) < x_lower || (xcrd - x_offset + 1) > x_upper) //Same as above. + ++xcrd + continue //X cropping. + if(xcrd > world.maxx) + if(cropMap) + break + else + world.maxx = xcrd + + if(xcrd >= 1) + var/model_key = copytext(line, tpos, tpos + key_len) + var/no_afterchange = no_changeturf || zexpansion + if(!no_afterchange || (model_key != space_key)) + if(!grid_models[model_key]) + throw EXCEPTION("Undefined model key in DMM.") + var/datum/grid_load_metadata/M = parse_grid(grid_models[model_key], model_key, xcrd, ycrd, zcrd, no_changeturf || zexpansion, clear_contents) + if (M) + atoms_to_initialise += M.atoms_to_initialise + atoms_to_delete += M.atoms_to_delete + #ifdef TESTING + else + ++turfsSkipped + #endif + CHECK_TICK + maxx = max(maxx, xcrd) + ++xcrd + --ycrd + if (zexpansion) + create_lighting_overlays_zlevel(zcrd) + + bounds[MAP_MAXX] = Clamp(max(bounds[MAP_MAXX], cropMap ? min(maxx, world.maxx) : maxx), x_lower, x_upper) + + CHECK_TICK + + if(bounds[1] == 1.#INF) // Shouldn't need to check every item + return null + else + if(!measureOnly) + if(clear_contents) + for(var/atom/to_delete in atoms_to_delete) + qdel(to_delete) + var/datum/map_load_metadata/M = new + M.bounds = bounds + M.atoms_to_initialise = atoms_to_initialise + return M + +/** + * Fill a given tile with its area/turf/objects/mobs + * Variable model is one full map line (e.g /turf/unsimulated/wall{icon_state = "rock"}, /area/mine/explored) + * + * WORKING : + * + * 1) Read the model string, member by member (delimiter is ',') + * + * 2) Get the path of the atom and store it into a list + * + * 3) a) Check if the member has variables (text within '{' and '}') + * + * 3) b) Construct an associative list with found variables, if any (the atom index in members is the same as its variables in members_attributes) + * + * 4) Instanciates the atom with its variables + * + */ + +/datum/grid_load_metadata + var/list/atoms_to_initialise + var/list/atoms_to_delete + +/dmm_suite/proc/types_to_delete() + return list( + /mob/living, + /obj/effect, + /obj/item, + /obj/machinery, + /obj/mecha, + /obj/structure, + ) + +/dmm_suite/proc/parse_grid(model as text, model_key as text, xcrd as num,ycrd as num,zcrd as num, no_changeturf as num, clear_contents as num) + /*Method parse_grid() + - Accepts a text string containing a comma separated list of type paths of the + same construction as those contained in a .dmm file, and instantiates them. + */ + + var/list/members //will contain all members (paths) in model (in our example : /turf/unsimulated/wall and /area/mine/explored) + var/list/members_attributes //will contain lists filled with corresponding variables, if any (in our example : list(icon_state = "rock") and list()) + var/list/cached = modelCache[model] + var/index + + if(cached) + members = cached[1] + members_attributes = cached[2] + else + ///////////////////////////////////////////////////////// + //Constructing members and corresponding variables lists + //////////////////////////////////////////////////////// + + members = list() + members_attributes = list() + index = 1 + + var/old_position = 1 + var/dpos + + do + //finding next member (e.g /turf/unsimulated/wall{icon_state = "rock"} or /area/mine/explored) + dpos = find_next_delimiter_position(model, old_position, ",", "{", "}") //find next delimiter (comma here) that's not within {...} + + var/full_def = trim_text(copytext(model, old_position, dpos)) //full definition, e.g : /obj/foo/bar{variables=derp} + var/variables_start = findtext(full_def, "{") + var/atom_def = text2path(trim_text(copytext(full_def, 1, variables_start))) //path definition, e.g /obj/foo/bar + old_position = dpos + 1 + + if(!atom_def) // Skip the item if the path does not exist. Fix your crap, mappers! + #ifdef UNIT_TEST + log_error("Couldn't find atom path specified in map: [full_def]") + #endif + if (dpos == 0) + break + else + continue + + members += atom_def + + //transform the variables in text format into a list (e.g {var1="derp"; var2; var3=7} => list(var1="derp", var2, var3=7)) + var/list/fields + + if(variables_start)//if there's any variable + full_def = copytext(full_def,variables_start+1,length(full_def))//removing the last '}' + fields = readlist(full_def, ";") + if(fields.len) + if(!trim(fields[fields.len])) + --fields.len + for(var/I in fields) + var/value = fields[I] + if(istext(value)) + fields[I] = apply_text_macros(value) + + //then fill the members_attributes list with the corresponding variables + members_attributes.len++ + members_attributes[index++] = fields + + CHECK_TICK + while(dpos != 0) + + //check and see if we can just skip this turf + //So you don't have to understand this horrid statement, we can do this if + // 1. no_changeturf is set + // 2. the space_key isn't set yet + // 3. there are exactly 2 members + // 4. with no attributes + // 5. and the members are world.turf and world.area + // Basically, if we find an entry like this: "XXX" = (/turf/default, /area/default) + // We can skip calling this proc every time we see XXX + if(no_changeturf && !space_key && members.len == 2 && members_attributes.len == 2 && length(members_attributes[1]) == 0 && length(members_attributes[2]) == 0 && (world.area in members) && (world.turf in members)) + space_key = model_key + return + + modelCache[model] = list(members, members_attributes) + + //////////////// + //Instanciation + //////////////// + + //The next part of the code assumes there's ALWAYS an /area AND a /turf on a given tile + var/turf/crds = locate(xcrd,ycrd,zcrd) + + var/is_not_noop = FALSE + var/atoms_to_delete = list() + + //first instance the /area and remove it from the members list + index = members.len + if(members[index] != /area/template_noop) + is_not_noop = TRUE + var/list/attr = members_attributes[index] + if (LAZYLEN(attr)) + GLOB._preloader.setup(attr)//preloader for assigning set variables on atom creation + var/atype = members[index] + var/atom/instance + for(var/area/A in world) + if(A.type == atype) + instance = A + break + if(!instance) + instance = new atype(null) + if(crds) + instance.contents.Add(crds) + + if(GLOB.use_preloader && instance) + GLOB._preloader.load(instance) + + //then instance the /turf and, if multiple tiles are presents, simulates the DMM underlays piling effect + + var/first_turf_index = 1 + while(!ispath(members[first_turf_index], /turf)) //find first /turf object in members + first_turf_index++ + + //turn off base new Initialization until the whole thing is loaded + SSatoms.map_loader_begin() + //since we've switched off autoinitialisation, record atoms to initialise later + var/list/atoms_to_initialise = list() + + //instanciate the first /turf + var/turf/T + if(members[first_turf_index] != /turf/template_noop) + is_not_noop = TRUE + T = instance_atom(members[first_turf_index],members_attributes[first_turf_index],crds,no_changeturf) + atoms_to_initialise += T + + if(T) + //if others /turf are presents, simulates the underlays piling effect + index = first_turf_index + 1 + while(index <= members.len - 1) // Last item is an /area + var/underlay = T.appearance + T = instance_atom(members[index],members_attributes[index],crds,no_changeturf)//instance new turf + T.underlays += underlay + index++ + atoms_to_initialise += T + + if (clear_contents && is_not_noop) + for (var/type_to_delete in types_to_delete()) + for (var/atom/pre_existing in crds) + if (istype(pre_existing, type_to_delete)) + atoms_to_delete |= pre_existing + + //finally instance all remainings objects/mobs + for(index in 1 to first_turf_index-1) + atoms_to_initialise += instance_atom(members[index],members_attributes[index],crds,no_changeturf) + //Restore initialization to the previous valsue + SSatoms.map_loader_stop() + + var/datum/grid_load_metadata/M = new + M.atoms_to_initialise = atoms_to_initialise + M.atoms_to_delete = atoms_to_delete + return M + +//////////////// +//Helpers procs +//////////////// + +//Instance an atom at (x,y,z) and gives it the variables in attributes +/dmm_suite/proc/instance_atom(path,list/attributes, turf/crds, no_changeturf) + if (LAZYLEN(attributes)) + GLOB._preloader.setup(attributes, path) + + if(crds) + if(!no_changeturf && ispath(path, /turf)) + . = crds.ChangeTurf(path, FALSE, TRUE) + else + . = create_atom(path, crds)//first preloader pass + + if(GLOB.use_preloader && .)//second preloader pass, for those atoms that don't ..() in New() + GLOB._preloader.load(.) + + //custom CHECK_TICK here because we don't want things created while we're sleeping to not initialize + if(TICK_CHECK) + SSatoms.map_loader_stop() + stoplag() + SSatoms.map_loader_begin() + +/dmm_suite/proc/create_atom(path, crds) + set waitfor = FALSE + . = new path (crds) + +//text trimming (both directions) helper proc +//optionally removes quotes before and after the text (for variable name) +/dmm_suite/proc/trim_text(what as text,trim_quotes=0) + if(trim_quotes) + return trimQuotesRegex.Replace(what, "") + else + return trimRegex.Replace(what, "") + + +//find the position of the next delimiter,skipping whatever is comprised between opening_escape and closing_escape +//returns 0 if reached the last delimiter +/dmm_suite/proc/find_next_delimiter_position(text as text,initial_position as num, delimiter=",",opening_escape="\"",closing_escape="\"") + var/position = initial_position + var/next_delimiter = findtext(text,delimiter,position,0) + var/next_opening = findtext(text,opening_escape,position,0) + + while((next_opening != 0) && (next_opening < next_delimiter)) + position = findtext(text,closing_escape,next_opening + 1,0)+1 + next_delimiter = findtext(text,delimiter,position,0) + next_opening = findtext(text,opening_escape,position,0) + + return next_delimiter + +/dmm_suite/proc/readlistitem(text as text) + //Check for string + if(findtext(text,"\"",1,2)) + . = copytext(text,2,findtext(text,"\"",3,0)) + + //Check for number + else if(isnum(text2num(text))) + . = text2num(text) + + //Check for null + else if(text == "null") + . = null + + //Check for list + else if(copytext(text,1,5) == "list") + . = readlist(copytext(text,6,length(text))) + + //Check for file + else if(copytext(text,1,2) == "'") + . = file(copytext(text,2,length(text))) + + //Check for path + else if(ispath(text2path(text))) + . = text2path(text) + +//build a list from variables in text form (e.g {var1="derp"; var2; var3=7} => list(var1="derp", var2, var3=7)) +//return the filled list +/dmm_suite/proc/readlist(text as text, delimiter=",") + var/list/to_return = list() + + var/position + var/old_position = 1 + var/list_index = 1 + + do + //find next delimiter that is not within "..." + position = find_next_delimiter_position(text,old_position,delimiter) + + //check if this is a simple variable (as in list(var1, var2)) or an associative one (as in list(var1="foo",var2=7)) + var/equal_position = findtext(text,"=",old_position, position) + + var/trim_left = trim_text(copytext(text,old_position,(equal_position ? equal_position : position)),1)//the name of the variable, must trim quotes to build a BYOND compliant associatives list + old_position = position + 1 + + if(equal_position)//associative var, so do the association + var/trim_right = trim_text(copytext(text,equal_position+1,position))//the content of the variable + to_return[trim_left] = readlistitem(trim_right) + list_index++ + else if (length(trim_left)) //simple var + to_return.len++ + to_return[list_index++] = readlistitem(trim_left) + + while(position != 0) + + return to_return + +/dmm_suite/Destroy() + ..() + return QDEL_HINT_HARDDEL_NOW + +////////////////// +//Preloader datum +////////////////// + +/dmm_suite/preloader + parent_type = /datum + var/list/attributes + var/target_path + +/dmm_suite/preloader/proc/setup(list/the_attributes, path) + if(LAZYLEN(the_attributes)) + GLOB.use_preloader = TRUE + attributes = the_attributes + target_path = path + +/dmm_suite/preloader/proc/load(atom/what) + for(var/attribute in attributes) + var/value = attributes[attribute] + if(islist(value)) + value = deepCopyList(value) + try + what.vars[attribute] = value + catch (var/ex) + var/found = FALSE + for (var/V in what.vars) + if (deep_string_equals(V, attribute)) + what.vars[V] = value + log_debug("Successfully performed manual var detection for var [V] \ref[V] on provided attribute [attribute] \ref[attribute] for atom [what]") + found = TRUE + break + if (!found) + throw ex + GLOB.use_preloader = FALSE + +/area/template_noop + name = "Area Passthrough" + icon_state = "space" + +/turf/template_noop + name = "Turf Passthrough" + icon_state = "noop" \ No newline at end of file diff --git a/code/modules/maps/ruins.dm b/code/modules/maps/ruins.dm new file mode 100644 index 00000000..54a0e473 --- /dev/null +++ b/code/modules/maps/ruins.dm @@ -0,0 +1,103 @@ +/proc/seedRuins(list/z_levels = null, budget = 0, whitelist = /area/space, list/potentialRuins) + if(!z_levels || !z_levels.len) + WARNING("No Z levels provided - Not generating ruins") + return + + for(var/zl in z_levels) + var/turf/T = locate(1, 1, zl) + if(!T) + WARNING("Z level [zl] does not exist - Not generating ruins") + return + + var/overall_sanity = 100 + var/list/ruins = potentialRuins.Copy() + + var/is_picking = FALSE + var/last_checked_ruin_index = 0 + while(budget > 0 && overall_sanity > 0) + // Pick a ruin + var/datum/map_template/ruin/ruin = null + if(ruins && ruins.len) + last_checked_ruin_index++ //ruins with no cost come first in the ruin list, so they'll get picked really often + if(is_picking) + ruin = ruins[pick(ruins)] + else + var/ruin_key = ruins[last_checked_ruin_index] //get the ruin's key via index + ruin = ruins[ruin_key] //use that key to get the ruin datum itself + if(ruin.cost >= 0) //if it has a non-negative cost, cancel out and pick another, to ensure true randomness + is_picking = TRUE + ruin = ruins[pick(ruins)] + else + log_world("Ruin loader had no ruins to pick from with [budget] left to spend.") + break + // Can we afford it + if(ruin.cost > budget) + overall_sanity-- + continue + // If so, try to place it + var/sanity = 100 + // And if we can't fit it anywhere, give up, try again + + while(sanity > 0) + sanity-- + var/width_border = TRANSITIONEDGE + RUIN_MAP_EDGE_PAD + round(ruin.width / 2) + var/height_border = TRANSITIONEDGE + RUIN_MAP_EDGE_PAD + round(ruin.height / 2) + var/z_level = pick(z_levels) + var/turf/T = locate(rand(width_border, world.maxx - width_border), rand(height_border, world.maxy - height_border), z_level) + var/valid = TRUE + + for(var/turf/check in ruin.get_affected_turfs(T,1)) + var/area/new_area = get_area(check) + if(!(istype(new_area, whitelist)) || check.turf_flags & TURF_FLAG_NORUINS) + valid = FALSE + break + + if(!valid) + continue + + log_world("Ruin \"[ruin.name]\" placed at ([T.x], [T.y], [T.z])") + + var/obj/effect/ruin_loader/R = new /obj/effect/ruin_loader(T) + R.Load(ruins,ruin) + if(ruin.cost >= 0) + budget -= ruin.cost + if(!ruin.allow_duplicates) + for(var/m in ruins) + var/datum/map_template/ruin/ruin_to_remove = ruins[m] + if(ruin_to_remove.id == ruin.id) //remove all ruins with the same ID, to make sure that ruins with multiple variants work properly + ruins -= ruin_to_remove.name + last_checked_ruin_index-- + break + + if(!overall_sanity) + log_world("Ruin loader gave up with [budget] left to spend.") + + +/obj/effect/ruin_loader + name = "random ruin" + icon = 'icons/obj/weapons.dmi' + icon_state = "syndballoon" + invisibility = 0 + +/obj/effect/ruin_loader/proc/Load(list/potentialRuins, datum/map_template/template) + var/list/possible_ruins = list() + for(var/A in potentialRuins) + var/datum/map_template/T = potentialRuins[A] + if(!T.loaded) + possible_ruins += T + if(!template && possible_ruins.len) + template = safepick(possible_ruins) + if(!template) + return FALSE + var/turf/central_turf = get_turf(src) + for(var/i in template.get_affected_turfs(central_turf, 1)) + var/turf/T = i + for(var/mob/living/simple_animal/monster in T) + qdel(monster) + template.load(central_turf,centered = TRUE) + var/datum/map_template/ruin = template + if(istype(ruin)) + new /obj/effect/landmark/ruin(central_turf, ruin) + + qdel(src) + return TRUE diff --git a/code/modules/maps/swapmaps.dm b/code/modules/maps/swapmaps.dm new file mode 100644 index 00000000..3497d674 --- /dev/null +++ b/code/modules/maps/swapmaps.dm @@ -0,0 +1,678 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/* + SwapMaps library by Lummox JR + developed for digitalBYOND + http://www.digitalbyond.org + + Version 2.1 + + The purpose of this library is to make it easy for authors to swap maps + in and out of their game using savefiles. Swapped-out maps can be + transferred between worlds for an MMORPG, sent to the client, etc. + This is facilitated by the use of a special datum and a global list. + + Uses of swapmaps: + + - Temporary battle arenas + - House interiors + - Individual custom player houses + - Virtually unlimited terrain + - Sharing maps between servers running different instances of the same + game + - Loading and saving pieces of maps for reusable room templates + */ + +/* + User Interface: + + VARS: + + swapmaps_iconcache + An associative list of icon files with names, like + 'player.dmi' = "player" + swapmaps_mode + This must be set at runtime, like in world/New(). + + SWAPMAPS_SAV 0 (default) + Uses .sav files for raw /savefile output. + SWAPMAPS_TEXT 1 + Uses .txt files via ExportText() and ImportText(). These maps + are easily editable and appear to take up less space in the + current version of BYOND. + + PROCS: + + SwapMaps_Find(id) + Find a map by its id + SwapMaps_Load(id) + Load a map by its id + SwapMaps_Save(id) + Save a map by its id (calls swapmap.Save()) + SwapMaps_Unload(id) + Save and unload a map by its id (calls swapmap.Unload()) + SwapMaps_Save_All() + Save all maps + SwapMaps_DeleteFile(id) + Delete a map file + SwapMaps_CreateFromTemplate(id) + Create a new map by loading another map to use as a template. + This map has id==src and will not be saved. To make it savable, + change id with swapmap.SetID(newid). + SwapMaps_LoadChunk(id,turf/locorner) + Load a swapmap as a "chunk", at a specific place. A new datum is + created but it's not added to the list of maps to save or unload. + The new datum can be safely deleted without affecting the turfs + it loaded. The purpose of this is to load a map file onto part of + another swapmap or an existing part of the world. + locorner is the corner turf with the lowest x,y,z values. + SwapMaps_SaveChunk(id,turf/corner1,turf/corner2) + Save a piece of the world as a "chunk". A new datum is created + for the chunk, but it can be deleted without destroying any turfs. + The chunk file can be reloaded as a swapmap all its own, or loaded + via SwapMaps_LoadChunk() to become part of another map. + SwapMaps_GetSize(id) + Return a list corresponding to the x,y,z sizes of a map file, + without loading the map. + Returns null if the map is not found. + SwapMaps_AddIconToCache(name,icon) + Cache an icon file by name for space-saving storage + + swapmap.New(id,x,y,z) + Create a new map; specify id, width (x), height (y), and + depth (z) + Default size is world.maxx,world.maxy,1 + swapmap.New(id,turf1,turf2) + Create a new map; specify id and 2 corners + This becomes a /swapmap for one of the compiled-in maps, for + easy saving. + swapmap.New() + Create a new map datum, but does not allocate space or assign an + ID (used for loading). + swapmap.Del() + Deletes a map but does not save + swapmap.Save() + Saves to map_[id].sav + Maps with id==src are not saved. + swapmap.Unload() + Saves the map and then deletes it + Maps with id==src are not saved. + swapmap.SetID(id) + Change the map's id and make changes to the lookup list + swapmap.AllTurfs(z) + Returns a block of turfs encompassing the entire map, or on just + one z-level + z is in world coordinates; it is optional + swapmap.Contains(turf/T) + Returns nonzero if T is inside the map's boundaries. + Also works for objs and mobs, but the proc is not area-safe. + swapmap.InUse() + Returns nonzero if a mob with a key is within the map's + boundaries. + swapmap.LoCorner(z=z1) + Returns locate(x1,y1,z), where z=z1 if none is specified. + swapmap.HiCorner(z=z2) + Returns locate(x2,y2,z), where z=z2 if none is specified. + swapmap.BuildFilledRectangle(turf/corner1,turf/corner2,item) + Builds a filled rectangle of item from one corner turf to the + other, on multiple z-levels if necessary. The corners may be + specified in any order. + item is a type path like /turf/wall or /obj/barrel{full=1}. + swapmap.BuildRectangle(turf/corner1,turf/corner2,item) + Builds an unfilled rectangle of item from one corner turf to + the other, on multiple z-levels if necessary. + swapmap.BuildInTurfs(list/turfs,item) + Builds item on all of the turfs listed. The list need not + contain only turfs, or even only atoms. + */ + +swapmap + var/id // a string identifying this map uniquely + var/x1 // minimum x,y,z coords + var/y1 + var/z1 + var/x2 // maximum x,y,z coords (also used as width,height,depth until positioned) + var/y2 + var/z2 + var/tmp/locked // don't move anyone to this map; it's saving or loading + var/tmp/mode // save as text-mode + var/ischunk // tells the load routine to load to the specified location + + New(_id,x,y,z) + if(isnull(_id)) return + id=_id + mode=swapmaps_mode + if(isturf(x) && isturf(y)) + /* + Special format: Defines a map as an existing set of turfs; + this is useful for saving a compiled map in swapmap format. + Because this is a compiled-in map, its turfs are not deleted + when the datum is deleted. + */ + x1=min(x:x,y:x);x2=max(x:x,y:x) + y1=min(x:y,y:y);y2=max(x:y,y:y) + z1=min(x:z,y:z);z2=max(x:z,y:z) + InitializeSwapMaps() + if(z2>swapmaps_compiled_maxz ||\ + y2>swapmaps_compiled_maxy ||\ + x2>swapmaps_compiled_maxx) + qdel(src) + return + x2=x?(x):world.maxx + y2=y?(y):world.maxy + z2=z?(z):1 + AllocateSwapMap() + + Del() + // a temporary datum for a chunk can be deleted outright + // for others, some cleanup is necessary + if(!ischunk) + swapmaps_loaded-=src + swapmaps_byname-=id + if(z2>swapmaps_compiled_maxz ||\ + y2>swapmaps_compiled_maxy ||\ + x2>swapmaps_compiled_maxx) + var/list/areas=new + for(var/atom/A in block(locate(x1,y1,z1),locate(x2,y2,z2))) + for(var/obj/O in A) qdel(O) + for(var/mob/M in A) + if(!M.key) qdel(M) + else M.loc=null + areas[A.loc]=null + qdel(A) + // delete areas that belong only to this map + for(var/area/a in areas) + if(a && !a.contents.len) qdel(a) + if(x2>=world.maxx || y2>=world.maxy || z2>=world.maxz) CutXYZ() + qdel(areas) + ..() + + /* + Savefile format: + map + id + x // size, not coords + y + z + areas // list of areas, not including default + [each z; 1 to depth] + [each y; 1 to height] + [each x; 1 to width] + type // of turf + AREA // if non-default; saved as a number (index into areas list) + vars // all other changed vars + */ + Write(savefile/S) + var/x + var/y + var/z + var/n + var/list/areas + var/area/defarea=locate(world.area) + if(!defarea) defarea=new world.area + areas=list() + for(var/turf/T in block(locate(x1,y1,z1),locate(x2,y2,z2))) + areas[T.loc]=null + for(n in areas) // quickly eliminate associations for smaller storage + areas-=n + areas+=n + areas-=defarea + InitializeSwapMaps() + locked=1 + S["id"] << id + S["z"] << z2-z1+1 + S["y"] << y2-y1+1 + S["x"] << x2-x1+1 + S["areas"] << areas + for(n in 1 to areas.len) areas[areas[n]]=n + var/oldcd=S.cd + for(z=z1,z<=z2,++z) + S.cd="[z-z1+1]" + for(y=y1,y<=y2,++y) + S.cd="[y-y1+1]" + for(x=x1,x<=x2,++x) + S.cd="[x-x1+1]" + var/turf/T=locate(x,y,z) + S["type"] << T.type + if(T.loc!=defarea) S["AREA"] << areas[T.loc] + T.Write(S) + S.cd=".." + S.cd=".." + sleep() + S.cd=oldcd + locked=0 + qdel(areas) + + Read(savefile/S,_id,turf/locorner) + var/x + var/y + var/z + var/n + var/list/areas + var/area/defarea=locate(world.area) + id=_id + if(locorner) + ischunk=1 + x1=locorner.x + y1=locorner.y + z1=locorner.z + if(!defarea) defarea=new world.area + if(!_id) + S["id"] >> id + else + var/dummy + S["id"] >> dummy + S["z"] >> z2 // these are depth, + S["y"] >> y2 // height, + S["x"] >> x2 // width + S["areas"] >> areas + locked=1 + AllocateSwapMap() // adjust x1,y1,z1 - x2,y2,z2 coords + var/oldcd=S.cd + for(z=z1,z<=z2,++z) + S.cd="[z-z1+1]" + for(y=y1,y<=y2,++y) + S.cd="[y-y1+1]" + for(x=x1,x<=x2,++x) + S.cd="[x-x1+1]" + var/tp + S["type"]>>tp + var/turf/T=locate(x,y,z) + T.loc.contents-=T + T=new tp(locate(x,y,z)) + if("AREA" in S.dir) + S["AREA"]>>n + var/area/A=areas[n] + A.contents+=T + else defarea.contents+=T + // clear the turf + for(var/obj/O in T) qdel(O) + for(var/mob/M in T) + if(!M.key) qdel(M) + else M.loc=null + // finish the read + T.Read(S) + S.cd=".." + S.cd=".." + sleep() + S.cd=oldcd + locked=0 + qdel(areas) + + /* + Find an empty block on the world map in which to load this map. + If no space is found, increase world.maxz as necessary. (If the + map is greater in x,y size than the current world, expand + world.maxx and world.maxy too.) + + Ignore certain operations if loading a map as a chunk. Use the + x1,y1,z1 position for it, and *don't* count it as a loaded map. + */ + proc/AllocateSwapMap() + InitializeSwapMaps() + world.maxx=max(x2,world.maxx) // stretch x/y if necessary + world.maxy=max(y2,world.maxy) + if(!ischunk) + if(world.maxz<=swapmaps_compiled_maxz) + z1=swapmaps_compiled_maxz+1 + x1=1;y1=1 + else + var/list/l=ConsiderRegion(1,1,world.maxx,world.maxy,swapmaps_compiled_maxz+1) + x1=l[1] + y1=l[2] + z1=l[3] + qdel(l) + x2+=x1-1 + y2+=y1-1 + z2+=z1-1 + world.maxz=max(z2,world.maxz) // stretch z if necessary + if(!ischunk) + swapmaps_loaded[src]=null + swapmaps_byname[id]=src + + proc/ConsiderRegion(X1,Y1,X2,Y2,Z1,Z2) + while(1) + var/nextz=0 + var/swapmap/M + for(M in swapmaps_loaded) + if(M.z2Z2) || M.z1>=Z1+z2 ||\ + M.x1>X2 || M.x2=X1+x2 ||\ + M.y1>Y2 || M.y2=Y1+y2) continue + // look for sub-regions with a defined ceiling + var/nz2=Z2?(Z2):Z1+z2-1+M.z2-M.z1 + if(M.x1>=X1+x2) + .=ConsiderRegion(X1,Y1,M.x1-1,Y2,Z1,nz2) + if(.) return + else if(M.x2<=X2-x2) + .=ConsiderRegion(M.x2+1,Y1,X2,Y2,Z1,nz2) + if(.) return + if(M.y1>=Y1+y2) + .=ConsiderRegion(X1,Y1,X2,M.y1-1,Z1,nz2) + if(.) return + else if(M.y2<=Y2-y2) + .=ConsiderRegion(X1,M.y2+1,X2,Y2,Z1,nz2) + if(.) return + nextz=nextz?min(nextz,M.z2+1):(M.z2+1) + if(!M) + /* If nextz is not 0, then at some point there was an overlap that + could not be resolved by using an area to the side */ + if(nextz) Z1=nextz + if(!nextz || (Z2 && Z2-Z1+1=z2)?list(X1,Y1,Z1):null + X1=1;X2=world.maxx + Y1=1;Y2=world.maxy + + proc/CutXYZ() + var/mx=swapmaps_compiled_maxx + var/my=swapmaps_compiled_maxy + var/mz=swapmaps_compiled_maxz + for(var/swapmap/M in swapmaps_loaded) // may not include src + mx=max(mx,M.x2) + my=max(my,M.y2) + mz=max(mz,M.z2) + world.maxx=mx + world.maxy=my + world.maxz=mz + + // save and delete + proc/Unload() + Save() + qdel(src) + + proc/Save() + if(id==src) return 0 + var/savefile/S=mode?(new):new("map_[id].sav") + S << src + while(locked) sleep(1) + if(mode) + fdel("map_[id].txt") + S.ExportText("/","map_[id].txt") + return 1 + + // this will not delete existing savefiles for this map + proc/SetID(newid) + swapmaps_byname-=id + id=newid + swapmaps_byname[id]=src + + proc/AllTurfs(z) + if(isnum(z) && (zz2)) return null + return block(LoCorner(z),HiCorner(z)) + + // this could be safely called for an obj or mob as well, but + // probably not an area + proc/Contains(turf/T) + return (T && T.x>=x1 && T.x<=x2\ + && T.y>=y1 && T.y<=y2\ + && T.z>=z1 && T.z<=z2) + + proc/InUse() + for(var/turf/T in AllTurfs()) + for(var/mob/M in T) if(M.key) return 1 + + proc/LoCorner(z=z1) + return locate(x1,y1,z) + proc/HiCorner(z=z2) + return locate(x2,y2,z) + + + // Build procs: Take 2 turfs as corners, plus an item type. + // An item may be like: + // + // /turf/wall + // /obj/fence{icon_state="iron"} + + proc/BuildFilledRectangle(turf/T1,turf/T2,item) + if(!Contains(T1) || !Contains(T2)) return + var/turf/T=T1 + // pick new corners in a block()-friendly form + T1=locate(min(T1.x,T2.x),min(T1.y,T2.y),min(T1.z,T2.z)) + T2=locate(max(T.x,T2.x),max(T.y,T2.y),max(T.z,T2.z)) + for(T in block(T1,T2)) new item(T) + + proc/BuildRectangle(turf/T1,turf/T2,item) + if(!Contains(T1) || !Contains(T2)) return + var/turf/T=T1 + // pick new corners in a block()-friendly form + T1=locate(min(T1.x,T2.x),min(T1.y,T2.y),min(T1.z,T2.z)) + T2=locate(max(T.x,T2.x),max(T.y,T2.y),max(T.z,T2.z)) + if(T2.x-T1.x<2 || T2.y-T1.y<2) BuildFilledRectangle(T1,T2,item) + else + //for(T in block(T1,T2)-block(locate(T1.x+1,T1.y+1,T1.z),locate(T2.x-1,T2.y-1,T2.z))) + for(T in block(T1,locate(T2.x,T1.y,T2.z))) new item(T) + for(T in block(locate(T1.x,T2.y,T1.z),T2)) new item(T) + for(T in block(locate(T1.x,T1.y+1,T1.z),locate(T1.x,T2.y-1,T2.z))) new item(T) + for(T in block(locate(T2.x,T1.y+1,T1.z),locate(T2.x,T2.y-1,T2.z))) new item(T) + + /* + Supplementary build proc: Takes a list of turfs, plus an item + type. Actually the list doesn't have to be just turfs. + */ + proc/BuildInTurfs(list/turfs,item) + for(var/T in turfs) new item(T) + +atom + Write(savefile/S) + for(var/V in vars-"x"-"y"-"z"-"contents"-"icon"-"overlays"-"underlays") + if(issaved(vars[V])) + if(vars[V]!=initial(vars[V])) S[V]<>ic + if(istext(ic)) icon=swapmaps_iconcache[ic] + if(l && contents!=l) + contents+=l + qdel(l) + + +// set this up (at runtime) as follows: +// list(\ +// 'player.dmi'="player",\ +// 'monster.dmi'="monster",\ +// ... +// 'item.dmi'="item") +var/list/swapmaps_iconcache + +// preferred mode; sav or text +var/const/SWAPMAPS_SAV=0 +var/const/SWAPMAPS_TEXT=1 +var/swapmaps_mode=SWAPMAPS_SAV + +var/swapmaps_compiled_maxx +var/swapmaps_compiled_maxy +var/swapmaps_compiled_maxz +var/swapmaps_initialized +var/swapmaps_loaded +var/swapmaps_byname + +proc/InitializeSwapMaps() + if(swapmaps_initialized) return + swapmaps_initialized=1 + swapmaps_compiled_maxx=world.maxx + swapmaps_compiled_maxy=world.maxy + swapmaps_compiled_maxz=world.maxz + swapmaps_loaded=list() + swapmaps_byname=list() + if(swapmaps_iconcache) + for(var/V in swapmaps_iconcache) + // reverse-associate everything + // so you can look up an icon file by name or vice-versa + swapmaps_iconcache[swapmaps_iconcache[V]]=V + +proc/SwapMaps_AddIconToCache(name,icon) + if(!swapmaps_iconcache) swapmaps_iconcache=list() + swapmaps_iconcache[name]=icon + swapmaps_iconcache[icon]=name + +proc/SwapMaps_Find(id) + InitializeSwapMaps() + return swapmaps_byname[id] + +proc/SwapMaps_Load(id) + InitializeSwapMaps() + var/swapmap/M=swapmaps_byname[id] + if(!M) + var/savefile/S + var/text=0 + if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[id].txt")) + text=1 + else if(fexists("map_[id].sav")) + S=new("map_[id].sav") + else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[id].txt")) + text=1 + else return // no file found + if(text) + S=new + S.ImportText("/",file("map_[id].txt")) + S >> M + while(M.locked) sleep(1) + M.mode=text + return M + +proc/SwapMaps_Save(id) + InitializeSwapMaps() + var/swapmap/M=swapmaps_byname[id] + if(M) M.Save() + return M + +proc/SwapMaps_Save_All() + InitializeSwapMaps() + for(var/swapmap/M in swapmaps_loaded) + if(M) M.Save() + +proc/SwapMaps_Unload(id) + InitializeSwapMaps() + var/swapmap/M=swapmaps_byname[id] + if(!M) return // return silently from an error + M.Unload() + return 1 + +proc/SwapMaps_DeleteFile(id) + fdel("map_[id].sav") + fdel("map_[id].txt") + +proc/SwapMaps_CreateFromTemplate(template_id) + var/swapmap/M=new + var/savefile/S + var/text=0 + if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[template_id].txt")) + text=1 + else if(fexists("map_[template_id].sav")) + S=new("map_[template_id].sav") + else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[template_id].txt")) + text=1 + else + world.log << "SwapMaps error in SwapMaps_CreateFromTemplate(): map_[template_id] file not found." + return + if(text) + S=new + S.ImportText("/",file("map_[template_id].txt")) + /* + This hacky workaround is needed because S >> M will create a brand new + M to fill with data. There's no way to control the Read() process + properly otherwise. The //.0 path should always match the map, however. + */ + S.cd="//.0" + M.Read(S,M) + M.mode=text + while(M.locked) sleep(1) + return M + +proc/SwapMaps_LoadChunk(chunk_id,turf/locorner) + var/swapmap/M=new + var/savefile/S + var/text=0 + if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[chunk_id].txt")) + text=1 + else if(fexists("map_[chunk_id].sav")) + S=new("map_[chunk_id].sav") + else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[chunk_id].txt")) + text=1 + else + world.log << "SwapMaps error in SwapMaps_LoadChunk(): map_[chunk_id] file not found." + return + if(text) + S=new + S.ImportText("/",file("map_[chunk_id].txt")) + /* + This hacky workaround is needed because S >> M will create a brand new + M to fill with data. There's no way to control the Read() process + properly otherwise. The //.0 path should always match the map, however. + */ + S.cd="//.0" + M.Read(S,M,locorner) + while(M.locked) sleep(1) + qdel(M) + return 1 + +proc/SwapMaps_SaveChunk(chunk_id,turf/corner1,turf/corner2) + if(!corner1 || !corner2) + world.log << "SwapMaps error in SwapMaps_SaveChunk():" + if(!corner1) world.log << " corner1 turf is null" + if(!corner2) world.log << " corner2 turf is null" + return + var/swapmap/M=new + M.id=chunk_id + M.ischunk=1 // this is a chunk + M.x1=min(corner1.x,corner2.x) + M.y1=min(corner1.y,corner2.y) + M.z1=min(corner1.z,corner2.z) + M.x2=max(corner1.x,corner2.x) + M.y2=max(corner1.y,corner2.y) + M.z2=max(corner1.z,corner2.z) + M.mode=swapmaps_mode + M.Save() + while(M.locked) sleep(1) + qdel(M) + return 1 + +proc/SwapMaps_GetSize(id) + var/savefile/S + var/text=0 + if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[id].txt")) + text=1 + else if(fexists("map_[id].sav")) + S=new("map_[id].sav") + else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[id].txt")) + text=1 + else + world.log << "SwapMaps error in SwapMaps_GetSize(): map_[id] file not found." + return + if(text) + S=new + S.ImportText("/",file("map_[id].txt")) + /* + The //.0 path should always be the map. There's no other way to + read this data. + */ + S.cd="//.0" + var/x + var/y + var/z + S["x"] >> x + S["y"] >> y + S["z"] >> z + return list(x,y,z) diff --git a/code/modules/maps/writer.dm b/code/modules/maps/writer.dm new file mode 100644 index 00000000..81c6a396 --- /dev/null +++ b/code/modules/maps/writer.dm @@ -0,0 +1,174 @@ +#define DMM_IGNORE_AREAS 1 +#define DMM_IGNORE_TURFS 2 +#define DMM_IGNORE_OBJS 4 +#define DMM_IGNORE_NPCS 8 +#define DMM_IGNORE_PLAYERS 16 +#define DMM_IGNORE_MOBS 24 +dmm_suite{ + var{ + quote = "\"" + list/letter_digits = list( + "a","b","c","d","e", + "f","g","h","i","j", + "k","l","m","n","o", + "p","q","r","s","t", + "u","v","w","x","y", + "z", + "A","B","C","D","E", + "F","G","H","I","J", + "K","L","M","N","O", + "P","Q","R","S","T", + "U","V","W","X","Y", + "Z" + ) + } + save_map(var/turf/t1 as turf, var/turf/t2 as turf, var/map_name as text, var/flags as num){ + //Check for illegal characters in file name... in a cheap way. + if(!((ckeyEx(map_name)==map_name) && ckeyEx(map_name))){ + CRASH("Invalid text supplied to proc save_map, invalid characters or empty string.") + } + //Check for valid turfs. + if(!isturf(t1) || !isturf(t2)){ + CRASH("Invalid arguments supplied to proc save_map, arguments were not turfs.") + } + var/file_text = write_map(t1,t2,flags) + if(fexists("[map_name].dmm")){ + fdel("[map_name].dmm") + } + var/saved_map = file("[map_name].dmm") + saved_map << file_text + return saved_map + } + write_map(var/turf/t1 as turf, var/turf/t2 as turf, var/flags as num){ + //Check for valid turfs. + if(!isturf(t1) || !isturf(t2)){ + CRASH("Invalid arguments supplied to proc write_map, arguments were not turfs.") + } + var/turf/nw = locate(min(t1.x,t2.x),max(t1.y,t2.y),min(t1.z,t2.z)) + var/turf/se = locate(max(t1.x,t2.x),min(t1.y,t2.y),max(t1.z,t2.z)) + var/list/templates[0] + var/template_buffer = {""} + var/dmm_text = {""} + for(var/pos_z=nw.z;pos_z<=se.z;pos_z++){ + for(var/pos_y=nw.y;pos_y>=se.y;pos_y--){ + for(var/pos_x=nw.x;pos_x<=se.x;pos_x++){ + var/turf/test_turf = locate(pos_x,pos_y,pos_z) + var/test_template = make_template(test_turf, flags) + var/template_number = templates.Find(test_template) + if(!template_number){ + templates.Add(test_template) + template_number = templates.len + } + template_buffer += "[template_number]," + } + template_buffer += ";" + } + template_buffer += "." + } + var/key_length = round/*floor*/(log(letter_digits.len,templates.len-1)+1) + var/list/keys[templates.len] + for(var/key_pos=1;key_pos<=templates.len;key_pos++){ + keys[key_pos] = get_model_key(key_pos,key_length) + dmm_text += {""[keys[key_pos]]" = ([templates[key_pos]])\n"} + } + var/z_level = 0 + for(var/z_pos=1;TRUE;z_pos=findtext(template_buffer,".",z_pos)+1){ + if(z_pos>=length(template_buffer)){break} + if(z_level){dmm_text+={"\n"}} + dmm_text += {"\n(1,1,[++z_level]) = {"\n"} + var/z_block = copytext(template_buffer,z_pos,findtext(template_buffer,".",z_pos)) + for(var/y_pos=1;TRUE;y_pos=findtext(z_block,";",y_pos)+1){ + if(y_pos>=length(z_block)){break} + var/y_block = copytext(z_block,y_pos,findtext(z_block,";",y_pos)) + for(var/x_pos=1;TRUE;x_pos=findtext(y_block,",",x_pos)+1){ + if(x_pos>=length(y_block)){break} + var/x_block = copytext(y_block,x_pos,findtext(y_block,",",x_pos)) + var/key_number = text2num(x_block) + var/temp_key = keys[key_number] + dmm_text += temp_key + sleep(-1) + } + dmm_text += {"\n"} + sleep(-1) + } + dmm_text += {"\"}"} + sleep(-1) + } + return dmm_text + } + proc{ + make_template(var/turf/model as turf, var/flags as num){ + var/template = "" + var/obj_template = "" + var/mob_template = "" + var/turf_template = "" + if(!(flags & DMM_IGNORE_TURFS)){ + turf_template = "[model.type][check_attributes(model)]," + } else{ turf_template = "[world.turf],"} + var/area_template = "" + if(!(flags & DMM_IGNORE_OBJS)){ + for(var/obj/O in model.contents){ + obj_template += "[O.type][check_attributes(O)]," + } + } + for(var/mob/M in model.contents){ + if(M.client){ + if(!(flags & DMM_IGNORE_PLAYERS)){ + mob_template += "[M.type][check_attributes(M)]," + } + } + else{ + if(!(flags & DMM_IGNORE_NPCS)){ + mob_template += "[M.type][check_attributes(M)]," + } + } + } + if(!(flags & DMM_IGNORE_AREAS)){ + var/area/m_area = model.loc + area_template = "[m_area.type][check_attributes(m_area)]" + } else{ area_template = "[world.area]"} + template = "[obj_template][mob_template][turf_template][area_template]" + return template + } + check_attributes(var/atom/A){ + var/attributes_text = {"{"} + for(var/V in A.vars){ + sleep(-1) + if((!issaved(A.vars[V])) || (A.vars[V]==initial(A.vars[V]))){continue} + if(istext(A.vars[V])){ + attributes_text += {"[V] = "[A.vars[V]]""} + } + else if(isnum(A.vars[V])||ispath(A.vars[V])){ + attributes_text += {"[V] = [A.vars[V]]"} + } + else if(isicon(A.vars[V])||isfile(A.vars[V])){ + attributes_text += {"[V] = '[A.vars[V]]'"} + } + else{ + continue + } + if(attributes_text != {"{"}){ + attributes_text+={"; "} + } + } + if(attributes_text=={"{"}){ + return + } + if(copytext(attributes_text, length(attributes_text)-1, 0) == {"; "}){ + attributes_text = copytext(attributes_text, 1, length(attributes_text)-1) + } + attributes_text += {"}"} + return attributes_text + } + get_model_key(var/which as num, var/key_length as num){ + var/key = "" + var/working_digit = which-1 + for(var/digit_pos=key_length;digit_pos>=1;digit_pos--){ + var/place_value = round/*floor*/(working_digit/(letter_digits.len**(digit_pos-1))) + working_digit-=place_value*(letter_digits.len**(digit_pos-1)) + key = "[key][letter_digits[place_value+1]]" + } + return key + } + } + } \ No newline at end of file diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm new file mode 100644 index 00000000..7c45a1f5 --- /dev/null +++ b/code/modules/materials/material_recipes.dm @@ -0,0 +1,147 @@ +/material/proc/get_recipes() + if(!recipes) + generate_recipes() + return recipes + +/material/proc/generate_recipes() + recipes = list() + + // If is_brittle() returns true, these are only good for a single strike. + recipes += new/datum/stack_recipe("[display_name] baseball bat", /obj/item/weapon/material/twohanded/baseballbat, 10, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]") + recipes += new/datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") + recipes += new/datum/stack_recipe("[display_name] spoon", /obj/item/weapon/material/kitchen/utensil/spoon/plastic, 1, on_floor = 1, supplied_material = "[name]") + recipes += new/datum/stack_recipe("[display_name] ring", /obj/item/clothing/ring/material, 1, on_floor = 1, supplied_material = "[name]") + + if(integrity>50) + recipes += new/datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") //NOTE: the wood material has it's own special chair recipe + + if(integrity>=50) + recipes += new/datum/stack_recipe("[display_name] door", /obj/machinery/door/unpowered/simple, 10, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") + recipes += new/datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") + recipes += new/datum/stack_recipe("[display_name] stool", /obj/item/weapon/stool, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") + recipes += new/datum/stack_recipe("[display_name] bar stool", /obj/item/weapon/stool/bar, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") + recipes += new/datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") + recipes += new/datum/stack_recipe("[display_name] lock",/obj/item/weapon/material/lock_construct, 1, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]") + + if(hardness>50) + recipes += new/datum/stack_recipe("[display_name] fork", /obj/item/weapon/material/kitchen/utensil/fork/plastic, 1, on_floor = 1, supplied_material = "[name]") + recipes += new/datum/stack_recipe("[display_name] knife", /obj/item/weapon/material/kitchen/utensil/knife/plastic, 1, on_floor = 1, supplied_material = "[name]") + recipes += new/datum/stack_recipe("[display_name] blade", /obj/item/weapon/material/butterflyblade, 6, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]") + +/material/steel/generate_recipes() + ..() + recipes += new/datum/stack_recipe_list("office chairs",list( \ + new/datum/stack_recipe("dark office chair", /obj/structure/bed/chair/office/dark, 5, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("light office chair", /obj/structure/bed/chair/office/light, 5, one_per_turf = 1, on_floor = 1) \ + )) + recipes += new/datum/stack_recipe_list("comfy chairs", list( \ + new/datum/stack_recipe("beige comfy chair", /obj/structure/bed/chair/comfy/beige, 2, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("black comfy chair", /obj/structure/bed/chair/comfy/black, 2, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("brown comfy chair", /obj/structure/bed/chair/comfy/brown, 2, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("lime comfy chair", /obj/structure/bed/chair/comfy/lime, 2, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("teal comfy chair", /obj/structure/bed/chair/comfy/teal, 2, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("red comfy chair", /obj/structure/bed/chair/comfy/red, 2, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("blue comfy chair", /obj/structure/bed/chair/comfy/blue, 2, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("purple comfy chair", /obj/structure/bed/chair/comfy/purp, 2, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("green comfy chair", /obj/structure/bed/chair/comfy/green, 2, one_per_turf = 1, on_floor = 1), \ + )) + recipes += new/datum/stack_recipe("key", /obj/item/weapon/key, 1, time = 10, one_per_turf = 0, on_floor = 1) + recipes += new/datum/stack_recipe("table frame", /obj/structure/table, 1, time = 10, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe("rack", /obj/structure/table/rack, 1, time = 5, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe("closet", /obj/structure/closet, 2, time = 15, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, time = 15, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe("cannon frame", /obj/item/weapon/cannonframe, 10, time = 15, one_per_turf = 0, on_floor = 0) + recipes += new/datum/stack_recipe("regular floor tile", /obj/item/stack/tile/floor, 1, 4, 20) + recipes += new/datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60) + recipes += new/datum/stack_recipe("computer frame", /obj/structure/computerframe, 5, time = 25, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe("wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe("machine frame", /obj/machinery/constructable_frame/machine_frame, 5, time = 25, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 25, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe_list("airlock assemblies", list( \ + new/datum/stack_recipe("standard airlock assembly", /obj/structure/door_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("command airlock assembly", /obj/structure/door_assembly/door_assembly_com, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("sol airlock assembly", /obj/structure/door_assembly/door_assembly_sol, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("security airlock assembly", /obj/structure/door_assembly/door_assembly_sec, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("engineering airlock assembly", /obj/structure/door_assembly/door_assembly_eng, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("mining airlock assembly", /obj/structure/door_assembly/door_assembly_min, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("atmospherics airlock assembly", /obj/structure/door_assembly/door_assembly_atmo, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("research airlock assembly", /obj/structure/door_assembly/door_assembly_research, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("medical airlock assembly", /obj/structure/door_assembly/door_assembly_med, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_mai, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("external airlock assembly", /obj/structure/door_assembly/door_assembly_ext, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("freezer airlock assembly", /obj/structure/door_assembly/door_assembly_fre, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("emergency shutter", /obj/structure/firedoor_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("multi-tile airlock assembly", /obj/structure/door_assembly/multi_tile, 4, time = 50, one_per_turf = 1, on_floor = 1), \ + )) + + recipes += new/datum/stack_recipe("grenade casing", /obj/item/weapon/grenade/chem_grenade) + recipes += new/datum/stack_recipe("light fixture frame", /obj/item/frame/light, 2) + recipes += new/datum/stack_recipe("small light fixture frame", /obj/item/frame/light/small, 1) + recipes += new/datum/stack_recipe("apc frame", /obj/item/frame/apc, 2) + recipes += new/datum/stack_recipe("air alarm frame", /obj/item/frame/air_alarm, 2) + recipes += new/datum/stack_recipe("fire alarm frame", /obj/item/frame/fire_alarm, 2) + + recipes += new/datum/stack_recipe_list("modular computer frames", list( \ + new/datum/stack_recipe("modular console frame", /obj/item/modular_computer/console, 20),\ + new/datum/stack_recipe("modular telescreen frame", /obj/item/modular_computer/telescreen, 10),\ + new/datum/stack_recipe("modular laptop frame", /obj/item/modular_computer/laptop, 10),\ + new/datum/stack_recipe("modular tablet frame", /obj/item/modular_computer/tablet, 5),\ + )) +/material/plasteel/generate_recipes() + ..() + recipes += new/datum/stack_recipe("AI core", /obj/structure/AIcore, 4, time = 50, one_per_turf = 1) + recipes += new/datum/stack_recipe("Metal crate", /obj/structure/closet/crate, 10, time = 50, one_per_turf = 1) + recipes += new/datum/stack_recipe("knife grip", /obj/item/weapon/material/butterflyhandle, 4, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]") + recipes += new/datum/stack_recipe("dark floor tile", /obj/item/stack/tile/floor_dark, 1, 4, 20) + +/material/stone/generate_recipes() + ..() + recipes += new/datum/stack_recipe("planting bed", /obj/machinery/portable_atmospherics/hydroponics/soil, 3, time = 10, one_per_turf = 1, on_floor = 1) + +/material/plastic/generate_recipes() + ..() + recipes += new/datum/stack_recipe("plastic crate", /obj/structure/closet/crate/plastic, 10, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe("plastic bag", /obj/item/weapon/storage/bag/plasticbag, 3, on_floor = 1) + recipes += new/datum/stack_recipe("blood pack", /obj/item/weapon/reagent_containers/ivbag, 4, on_floor = 0) + recipes += new/datum/stack_recipe("reagent dispenser cartridge (large)", /obj/item/weapon/reagent_containers/chem_disp_cartridge, 5, on_floor=0) // 500u + recipes += new/datum/stack_recipe("reagent dispenser cartridge (med)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/medium, 3, on_floor=0) // 250u + recipes += new/datum/stack_recipe("reagent dispenser cartridge (small)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/small, 1, on_floor=0) // 100u + recipes += new/datum/stack_recipe("white floor tile", /obj/item/stack/tile/floor_white, 1, 4, 20) + recipes += new/datum/stack_recipe("freezer floor tile", /obj/item/stack/tile/floor_freezer, 1, 4, 20) + recipes += new/datum/stack_recipe("hazard cone", /obj/item/weapon/caution/cone, 1, on_floor = 1) + + +/material/wood/generate_recipes() + ..() + recipes += new/datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1) + recipes += new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20) + recipes += new/datum/stack_recipe("wooden chair", /obj/structure/bed/chair/wood, 3, time = 10, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe("fancy wooden chair", /obj/structure/bed/chair/wood/wings, 3, time = 10, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe("crossbow frame", /obj/item/weapon/crossbowframe, 5, time = 25, one_per_turf = 0, on_floor = 0) + recipes += new/datum/stack_recipe("coffin", /obj/structure/closet/coffin, 5, time = 15, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe("book shelf", /obj/structure/bookcase, 5, time = 15, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe("zip gun frame", /obj/item/weapon/zipgunframe, 5) + recipes += new/datum/stack_recipe("stick", /obj/item/weapon/material/stick, 1) + +/material/cardboard/generate_recipes() + ..() + recipes += new/datum/stack_recipe("box", /obj/item/weapon/storage/box) + recipes += new/datum/stack_recipe("large box", /obj/item/weapon/storage/box/large, 2) + recipes += new/datum/stack_recipe("donut box", /obj/item/weapon/storage/box/donut/empty) + recipes += new/datum/stack_recipe("egg box", /obj/item/weapon/storage/fancy/egg_box/empty) + recipes += new/datum/stack_recipe("light tubes box", /obj/item/weapon/storage/box/lights/tubes/empty) + recipes += new/datum/stack_recipe("light bulbs box", /obj/item/weapon/storage/box/lights/bulbs/empty) + recipes += new/datum/stack_recipe("mouse traps box", /obj/item/weapon/storage/box/mousetraps/empty) + recipes += new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/cardborg, 3) + recipes += new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/cardborg) + recipes += new/datum/stack_recipe("pizza box", /obj/item/pizzabox) + recipes += new/datum/stack_recipe_list("folders",list( \ + new/datum/stack_recipe("blue folder", /obj/item/weapon/folder/blue), \ + new/datum/stack_recipe("grey folder", /obj/item/weapon/folder), \ + new/datum/stack_recipe("red folder", /obj/item/weapon/folder/red), \ + new/datum/stack_recipe("white folder", /obj/item/weapon/folder/white), \ + new/datum/stack_recipe("yellow folder", /obj/item/weapon/folder/yellow), \ + )) diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm new file mode 100644 index 00000000..f9328d41 --- /dev/null +++ b/code/modules/materials/material_sheets.dm @@ -0,0 +1,316 @@ +// Stacked resources. They use a material datum for a lot of inherited values. +/obj/item/stack/material + force = 5.0 + throwforce = 5 + w_class = ITEM_SIZE_LARGE + throw_speed = 3 + throw_range = 3 + max_amount = 60 + center_of_mass = null + randpixel = 3 + + var/default_type = DEFAULT_WALL_MATERIAL + var/material/material + var/perunit = SHEET_MATERIAL_AMOUNT + var/apply_colour //temp pending icon rewrite + +/obj/item/stack/material/Initialize() + . = ..() + if(!default_type) + default_type = DEFAULT_WALL_MATERIAL + material = get_material_by_name("[default_type]") + if(!material) + return INITIALIZE_HINT_QDEL + + recipes = material.get_recipes() + stacktype = material.stack_type + if(islist(material.stack_origin_tech)) + origin_tech = material.stack_origin_tech.Copy() + + if(apply_colour) + color = material.icon_colour + + if(material.conductive) + obj_flags |= OBJ_FLAG_CONDUCTIBLE + else + obj_flags &= (~OBJ_FLAG_CONDUCTIBLE) + + matter = material.get_matter() + update_strings() + +/obj/item/stack/material/get_material() + return material + +/obj/item/stack/material/proc/update_strings() + // Update from material datum. + singular_name = material.sheet_singular_name + + if(amount>1) + SetName("[material.use_name] [material.sheet_plural_name]") + desc = "A stack of [material.use_name] [material.sheet_plural_name]." + gender = PLURAL + else + SetName("[material.use_name] [material.sheet_singular_name]") + desc = "A [material.sheet_singular_name] of [material.use_name]." + gender = NEUTER + +/obj/item/stack/material/use(var/used) + . = ..() + update_strings() + return + +/obj/item/stack/material/transfer_to(obj/item/stack/S, var/tamount=null, var/type_verified) + var/obj/item/stack/material/M = S + if(!istype(M) || material.name != M.material.name) + return 0 + var/transfer = ..(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)) + ..() + +/obj/item/stack/material/attackby(var/obj/item/W, var/mob/user) + if(isCoil(W)) + material.build_wired_product(user, W, src) + return + else if(istype(W, /obj/item/stack/rods)) + material.build_rod_product(user, W, src) + return + return ..() + +/obj/item/stack/material/iron + name = "iron" + icon_state = "sheet-silver" + default_type = "iron" + apply_colour = 1 + +/obj/item/stack/material/sandstone + name = "sandstone brick" + icon_state = "sheet-sandstone" + default_type = "sandstone" + +/obj/item/stack/material/marble + name = "marble brick" + icon_state = "sheet-marble" + default_type = "marble" + +/obj/item/stack/material/marble/ten + amount = 10 + +/obj/item/stack/material/marble/fifty + amount = 50 + +/obj/item/stack/material/diamond + name = "diamond" + icon_state = "sheet-diamond" + default_type = "diamond" + +/obj/item/stack/material/diamond/ten + amount = 10 + +/obj/item/stack/material/uranium + name = "uranium" + icon_state = "sheet-uranium" + default_type = "uranium" + +/obj/item/stack/material/uranium/ten + amount = 10 + +/obj/item/stack/material/phoron + name = "solid phoron" + icon_state = "sheet-phoron" + default_type = "phoron" + +/obj/item/stack/material/phoron/ten + amount = 10 + +/obj/item/stack/material/phoron/fifty + amount = 50 + +/obj/item/stack/material/plastic + name = "plastic" + icon_state = "sheet-plastic" + default_type = "plastic" + +/obj/item/stack/material/plastic/ten + amount = 10 + +/obj/item/stack/material/plastic/fifty + amount = 50 + +/obj/item/stack/material/gold + name = "gold" + icon_state = "sheet-gold" + default_type = "gold" + +/obj/item/stack/material/gold/ten + amount = 10 + +/obj/item/stack/material/silver + name = "silver" + icon_state = "sheet-silver" + default_type = "silver" + +/obj/item/stack/material/silver/ten + amount = 10 + +//Valuable resource, cargo can sell it. +/obj/item/stack/material/platinum + name = "platinum" + icon_state = "sheet-adamantine" + default_type = "platinum" + +/obj/item/stack/material/platinum/ten + amount = 10 + +//Extremely valuable to Research. +/obj/item/stack/material/mhydrogen + name = "metallic hydrogen" + icon_state = "sheet-mythril" + default_type = "mhydrogen" + +/obj/item/stack/material/mhydrogen/ten + amount = 10 + +//Fuel for MRSPACMAN generator. +/obj/item/stack/material/tritium + name = "tritium" + icon_state = "sheet-silver" + default_type = "tritium" + apply_colour = 1 + +/obj/item/stack/material/tritium/ten + amount = 10 + +/obj/item/stack/material/tritium/fifty + amount = 50 + +/obj/item/stack/material/osmium + name = "osmium" + icon_state = "sheet-silver" + default_type = "osmium" + apply_colour = 1 + +/obj/item/stack/material/osmium/ten + amount = 10 + +/obj/item/stack/material/ocp + name = "osmium-carbide plasteel" + icon_state = "sheet-plasteel" + item_state = "sheet-metal" + default_type = "osmium-carbide plasteel" + apply_colour = 1 + +/obj/item/stack/material/ocp/ten + amount = 10 + +/obj/item/stack/material/ocp/fifty + amount = 50 + +// Fusion fuel. +/obj/item/stack/material/deuterium + name = "deuterium" + icon_state = "sheet-silver" + default_type = "deuterium" + apply_colour = 1 + +/obj/item/stack/material/deuterium/fifty + amount = 50 + +/obj/item/stack/material/steel + name = DEFAULT_WALL_MATERIAL + icon_state = "sheet-metal" + default_type = DEFAULT_WALL_MATERIAL + +/obj/item/stack/material/steel/ten + amount = 10 + +/obj/item/stack/material/steel/fifty + amount = 50 + +/obj/item/stack/material/plasteel + name = "plasteel" + icon_state = "sheet-plasteel" + item_state = "sheet-metal" + default_type = "plasteel" + +/obj/item/stack/material/plasteel/ten + amount = 10 + +/obj/item/stack/material/plasteel/fifty + amount = 50 + +/obj/item/stack/material/wood + name = "wooden plank" + icon_state = "sheet-wood" + default_type = "wood" + +/obj/item/stack/material/wood/ten + amount = 10 + +/obj/item/stack/material/wood/fifty + amount = 50 + +/obj/item/stack/material/cloth + name = "cloth" + icon_state = "sheet-cloth" + default_type = "cloth" + +/obj/item/stack/material/cardboard + name = "cardboard" + icon_state = "sheet-card" + default_type = "cardboard" + +/obj/item/stack/material/cardboard/ten + amount = 10 + +/obj/item/stack/material/cardboard/fifty + amount = 50 + +/obj/item/stack/material/leather + name = "leather" + desc = "The by-product of mob grinding." + icon_state = "sheet-leather" + default_type = "leather" + +/obj/item/stack/material/glass + name = "glass" + icon_state = "sheet-glass" + default_type = "glass" + +/obj/item/stack/material/glass/ten + amount = 10 + +/obj/item/stack/material/glass/fifty + amount = 50 + +/obj/item/stack/material/glass/reinforced + name = "reinforced glass" + icon_state = "sheet-rglass" + default_type = "rglass" + +/obj/item/stack/material/glass/reinforced/ten + amount = 10 + +/obj/item/stack/material/glass/reinforced/fifty + amount = 50 + +/obj/item/stack/material/glass/phoronglass + name = "borosilicate glass" + desc = "This sheet is special platinum-glass alloy designed to withstand large temperatures." + singular_name = "borosilicate glass sheet" + icon_state = "sheet-phoronglass" + default_type = "phglass" + +/obj/item/stack/material/glass/phoronrglass + name = "reinforced borosilicate glass" + 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 = "rphglass" + +/obj/item/stack/material/glass/phoronrglass/ten + amount = 10 \ No newline at end of file diff --git a/code/modules/materials/material_synth.dm b/code/modules/materials/material_synth.dm new file mode 100644 index 00000000..2058410e --- /dev/null +++ b/code/modules/materials/material_synth.dm @@ -0,0 +1,38 @@ +// These objects are used by cyborgs to get around a lot of the limitations on stacks +// and the weird bugs that crop up when expecting borg module code to behave sanely. +/obj/item/stack/material/cyborg + uses_charge = 1 + charge_costs = list(1000) + gender = NEUTER + matter = null // Don't shove it in the autholathe. + +/obj/item/stack/material/cyborg/New() + if(..()) + name = "[material.display_name] synthesiser" + desc = "A device that synthesises [material.display_name]." + matter = null + +/obj/item/stack/material/cyborg/plastic + icon_state = "sheet-plastic" + default_type = "plastic" + +/obj/item/stack/material/cyborg/steel + icon_state = "sheet-metal" + default_type = "steel" + +/obj/item/stack/material/cyborg/plasteel + icon_state = "sheet-plasteel" + default_type = "plasteel" + +/obj/item/stack/material/cyborg/wood + icon_state = "sheet-wood" + default_type = "wood" + +/obj/item/stack/material/cyborg/glass + icon_state = "sheet-glass" + default_type = "glass" + +/obj/item/stack/material/cyborg/glass/reinforced + icon_state = "sheet-rglass" + default_type = "rglass" + charge_costs = list(500, 1000) \ No newline at end of file diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm new file mode 100644 index 00000000..cb15f6d1 --- /dev/null +++ b/code/modules/materials/materials.dm @@ -0,0 +1,898 @@ +/* + MATERIAL DATUMS + This data is used by various parts of the game for basic physical properties and behaviors + of the metals/materials used for constructing many objects. Each var is commented and should be pretty + self-explanatory but the various object types may have their own documentation. ~Z + + PATHS THAT USE DATUMS + turf/simulated/wall + obj/item/weapon/material + obj/structure/barricade + obj/item/stack/material + obj/structure/table + + VALID ICONS + WALLS + stone + metal + solid + cult + DOORS + stone + metal + resin + wood +*/ + +// Assoc list containing all material datums indexed by name. +var/list/name_to_material + +//Returns the material the object is made of, if applicable. +//Will we ever need to return more than one value here? Or should we just return the "dominant" material. +/obj/proc/get_material() + return null + +//mostly for convenience +/obj/proc/get_material_name() + var/material/material = get_material() + if(material) + return material.name + +// Builds the datum list above. +/proc/populate_material_list(force_remake=0) + if(name_to_material && !force_remake) return // Already set up! + name_to_material = list() + for(var/type in typesof(/material) - /material) + var/material/new_mineral = new type + if(!new_mineral.name) + continue + name_to_material[lowertext(new_mineral.name)] = new_mineral + return 1 + +// Safety proc to make sure the material list exists before trying to grab from it. +/proc/get_material_by_name(name) + if(!name_to_material) + populate_material_list() + . = name_to_material[name] + if(!.) + log_error("Unable to acquire material by name '[name]'") + +/proc/material_display_name(name) + var/material/material = get_material_by_name(name) + if(material) + return material.display_name + return null + +// Material definition and procs follow. +/material + var/name // Unique name for use in indexing the list. + var/display_name // Prettier name for display. + var/adjective_name + var/use_name + var/flags = 0 // Various status modifiers. + var/sheet_singular_name = "sheet" + var/sheet_plural_name = "sheets" + var/is_fusion_fuel + var/apply_icon_colour_to_walls = TRUE + // Shards/tables/structures + var/shard_type = SHARD_SHRAPNEL // Path of debris object. + var/shard_icon // Related to above. + var/shard_can_repair = 1 // Can shards be turned into sheets with a welder? + var/list/recipes // Holder for all recipes usable with a sheet of this material. + var/destruction_desc = "breaks apart" // Fancy string for barricades/tables/objects exploding. + + // Icons + var/icon_colour // Colour applied to products of this material. + var/icon_base = "metal" // Wall and table base icon tag. See header. + var/door_icon_base = "metal" // Door base icon tag. See header. + var/icon_reinf = "reinf_metal" // Overlay used + var/table_icon_base = "metal" + var/table_reinf = "reinf_metal" + var/list/stack_origin_tech = list(TECH_MATERIAL = 1) // Research level for stacks. + + // Attributes + var/cut_delay = 0 // Delay in ticks when cutting through this wall. + var/radioactivity // Radiation var. Used in wall and object processing to irradiate surroundings. + var/ignition_point // K, point at which the material catches on fire. + var/melting_point = 1800 // K, walls will take damage if they're next to a fire hotter than this + var/brute_armor = 2 // Brute damage to a wall is divided by this value if the wall is reinforced by this material. + var/burn_armor // Same as above, but for Burn damage type. If blank brute_armor's value is used. + var/integrity = 150 // General-use HP value for products. + var/opacity = 1 // Is the material transparent? 0.5< makes transparent walls/doors. + var/explosion_resistance = 5 // Only used by walls currently. + var/conductive = 1 // Objects with this var add CONDUCTS to flags on spawn. + var/luminescence + var/list/composite_material // If set, object matter var will be a list containing these values. + + // Placeholder vars for the time being, todo properly integrate windows/light tiles/rods. + var/created_window + var/rod_product + var/wire_product + var/list/window_options = list() + + // Damage values. + var/hardness = 60 // Prob of wall destruction by hulk, used for edge damage in weapons. + var/weight = 20 // Determines blunt damage/throwforce for weapons. + + // Noise when someone is faceplanted onto a table made of this material. + var/tableslam_noise = 'sound/weapons/tablehit1.ogg' + // Noise made when a simple door made of this material opens or closes. + var/dooropen_noise = 'sound/effects/stonedoor_openclose.ogg' + // Noise made when you hit structure made of this material. + var/hitsound = 'sound/weapons/genhit.ogg' + // Path to resulting stacktype. Todo remove need for this. + var/stack_type + // Wallrot crumble message. + var/rotting_touch_message = "crumbles under your touch" + +// Placeholders for light tiles and rglass. +/material/proc/build_rod_product(var/mob/living/carbon/human/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack) + if(!rod_product) + to_chat(user, "You cannot make anything out of \the [target_stack]") + return + if(used_stack.get_amount() < 1 || target_stack.get_amount() < 1) + to_chat(user, "You need one rod and one sheet of [display_name] to make anything useful.") + return + + if(user.statscheck(skills = user.SKILL_LEVEL(engineering)) >= SUCCESS) + return + else + to_chat(user, "I have botched bulding what I'm building.") + + used_stack.use(1) + target_stack.use(1) + var/obj/item/stack/S = new rod_product(get_turf(user)) + S.add_fingerprint(user) + S.add_to_stacks(user) + +/material/proc/build_wired_product(var/mob/living/carbon/human/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack) + if(!wire_product) + to_chat(user, "You cannot make anything out of \the [target_stack]") + return + if(used_stack.get_amount() < 5 || target_stack.get_amount() < 1) + to_chat(user, "You need five wires and one sheet of [display_name] to make anything useful.") + return + + if(user.statscheck(skills = user.SKILL_LEVEL(engineering)) >= SUCCESS) + return + else + to_chat(user, "I have botched adding the wires.") + + used_stack.use(5) + target_stack.use(1) + to_chat(user, "You attach wire to the [name].") + var/obj/item/product = new wire_product(get_turf(user)) + if(!(user.l_hand && user.r_hand)) + user.put_in_hands(product) + +// Make sure we have a display name and shard icon even if they aren't explicitly set. +/material/New() + ..() + if(!display_name) + display_name = name + if(!use_name) + use_name = display_name + if(!adjective_name) + adjective_name = display_name + if(!shard_icon) + shard_icon = shard_type + if(!burn_armor) + burn_armor = brute_armor + +// This is a placeholder for proper integration of windows/windoors into the system. +/material/proc/build_windows(var/mob/living/user, var/obj/item/stack/used_stack) + return 0 + +// Weapons handle applying a divisor for this value locally. +/material/proc/get_blunt_damage() + return weight //todo + +// Return the matter comprising this material. +/material/proc/get_matter() + var/list/temp_matter = list() + if(islist(composite_material)) + for(var/material_string in composite_material) + temp_matter[material_string] = composite_material[material_string] + else if(SHEET_MATERIAL_AMOUNT) + temp_matter[name] = SHEET_MATERIAL_AMOUNT + return temp_matter + +// As above. +/material/proc/get_edge_damage() + return hardness //todo + +// Snowflakey, only checked for alien doors at the moment. +/material/proc/can_open_material_door(var/mob/living/user) + return 1 + +// Currently used for weapons and objects made of uranium to irradiate things. +/material/proc/products_need_process() + return (radioactivity>0) //todo + +// Used by walls when qdel()ing to avoid neighbor merging. +/material/placeholder + name = "placeholder" + +// Places a girder object when a wall is dismantled, also applies reinforced material. +/material/proc/place_dismantled_girder(var/turf/target, var/material/reinf_material) + var/obj/structure/girder/G = new(target) + if(reinf_material) + G.reinf_material = reinf_material + G.reinforce_girder() + +// General wall debris product placement. +// Not particularly necessary aside from snowflakey cult girders. +/material/proc/place_dismantled_product(var/turf/target,var/is_devastated) + for(var/x=1;x<(is_devastated?2:3);x++) + place_sheet(target) + +// Debris product. Used ALL THE TIME. +/material/proc/place_sheet(var/turf/target) + if(stack_type) + return new stack_type(target) + +// As above. +/material/proc/place_shard(var/turf/target) + if(shard_type) + return new /obj/item/weapon/material/shard(target, src.name) + +// Used by walls and weapons to determine if they break or not. +/material/proc/is_brittle() + return !!(flags & MATERIAL_BRITTLE) + +/material/proc/combustion_effect(var/turf/T, var/temperature) + return + +// Datum definitions follow. +/material/uranium + name = "uranium" + stack_type = /obj/item/stack/material/uranium + radioactivity = 12 + icon_base = "stone" + door_icon_base = "stone" + table_icon_base = "stone" + icon_reinf = "reinf_stone" + icon_colour = "#007a00" + weight = 22 + stack_origin_tech = list(TECH_MATERIAL = 5) + +/material/diamond + name = "diamond" + stack_type = /obj/item/stack/material/diamond + flags = MATERIAL_UNMELTABLE + cut_delay = 60 + icon_colour = "#00ffe1" + opacity = 0.4 + shard_type = SHARD_SHARD + tableslam_noise = 'sound/effects/Glasshit.ogg' + hardness = 100 + brute_armor = 10 + burn_armor = 50 // Diamond walls are immune to fire, therefore it makes sense for them to be almost undamageable by burn damage type. + stack_origin_tech = list(TECH_MATERIAL = 6) + conductive = 0 + +/material/gold + name = "gold" + stack_type = /obj/item/stack/material/gold + icon_colour = "#edd12f" + weight = 25 + hardness = 25 + integrity = 100 + stack_origin_tech = list(TECH_MATERIAL = 4) + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + +/material/gold/bronze //placeholder for ashtrays + name = "bronze" + icon_colour = "#edd12f" + +/material/silver + name = "silver" + stack_type = /obj/item/stack/material/silver + icon_colour = "#d1e6e3" + weight = 22 + hardness = 50 + stack_origin_tech = list(TECH_MATERIAL = 3) + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + +/material/phoron + name = "phoron" + stack_type = /obj/item/stack/material/phoron + ignition_point = PHORON_MINIMUM_BURN_TEMPERATURE + icon_base = "stone" + table_icon_base = "stone" + icon_colour = "#e37108" + shard_type = SHARD_SHARD + hardness = 30 + stack_origin_tech = list(TECH_MATERIAL = 2, TECH_PHORON = 2) + door_icon_base = "stone" + sheet_singular_name = "crystal" + sheet_plural_name = "crystals" + is_fusion_fuel = 1 + +/material/phoron/supermatter + name = "supermatter" + icon_colour = "#ffff00" + radioactivity = 20 + stack_origin_tech = list(TECH_BLUESPACE = 2, TECH_MATERIAL = 6, TECH_PHORON = 4) + stack_type = null + luminescence = 3 + + +//Controls phoron and phoron based objects reaction to being in a turf over 200c -- Phoron's flashpoint. +/material/phoron/combustion_effect(var/turf/T, var/temperature, var/effect_multiplier) + if(isnull(ignition_point)) + return 0 + if(temperature < ignition_point) + return 0 + var/totalPhoron = 0 + for(var/turf/simulated/floor/target_tile in range(2,T)) + var/phoronToDeduce = (temperature/30) * effect_multiplier + totalPhoron += phoronToDeduce + target_tile.assume_gas("phoron", phoronToDeduce, 200+T0C) + spawn (0) + target_tile.hotspot_expose(temperature, 400) + return round(totalPhoron/100) + + +/material/stone + name = "sandstone" + stack_type = /obj/item/stack/material/sandstone + icon_base = "stone" + table_icon_base = "stone" + icon_reinf = "reinf_stone" + icon_colour = "#d9c179" + shard_type = SHARD_STONE_PIECE + weight = 22 + hardness = 55 + brute_armor = 3 + door_icon_base = "stone" + sheet_singular_name = "brick" + sheet_plural_name = "bricks" + conductive = 0 + +/material/stone/marble + name = "marble" + icon_colour = "#aaaaaa" + weight = 26 + hardness = 60 + brute_armor = 3 + integrity = 201 //hack to stop kitchen benches being flippable, todo: refactor into weight system + stack_type = /obj/item/stack/material/marble + +/material/steel + name = DEFAULT_WALL_MATERIAL + stack_type = /obj/item/stack/material/steel + integrity = 150 + brute_armor = 5 + icon_base = "solid" + icon_reinf = "reinf_over" + icon_colour = "#666666" + hitsound = 'sound/weapons/smash.ogg' + apply_icon_colour_to_walls = FALSE + +/material/diona + name = "biomass" + icon_colour = null + stack_type = null + integrity = 600 + icon_base = "diona" + icon_reinf = "noreinf" + hitsound = 'sound/effects/attackblob.ogg' + conductive = 0 + +/material/diona/place_dismantled_product() + return + + +/material/steel/holographic + name = "holo" + DEFAULT_WALL_MATERIAL + display_name = DEFAULT_WALL_MATERIAL + stack_type = null + shard_type = SHARD_NONE + conductive = 0 + +/material/plasteel + name = "plasteel" + stack_type = /obj/item/stack/material/plasteel + integrity = 400 + melting_point = 6000 + icon_base = "solid" + icon_reinf = "reinf_over" + icon_colour = "#777777" + explosion_resistance = 25 + brute_armor = 6 + burn_armor = 10 + hardness = 80 + weight = 23 + stack_origin_tech = list(TECH_MATERIAL = 2) + composite_material = list(DEFAULT_WALL_MATERIAL = 3750, "platinum" = 3750) //todo + apply_icon_colour_to_walls = FALSE + +/material/plasteel/titanium + name = "titanium" + brute_armor = 10 + burn_armor = 8 + integrity = 200 + melting_point = 3000 + stack_type = null + icon_base = "metal" + door_icon_base = "metal" + icon_colour = "#d1e6e3" + icon_reinf = "reinf_metal" + +/material/plasteel/ocp + name = "osmium-carbide plasteel" + stack_type = /obj/item/stack/material/ocp + integrity = 200 + melting_point = 12000 + icon_base = "solid" + icon_reinf = "reinf_over" + icon_colour = "#9bc6f2" + brute_armor = 4 + burn_armor = 20 + weight = 27 + stack_origin_tech = list(TECH_MATERIAL = 3) + composite_material = list("plasteel" = 7500, "osmium" = 3750) + + +/material/glass + name = "glass" + stack_type = /obj/item/stack/material/glass + flags = MATERIAL_BRITTLE + icon_colour = "#00e1ff" + opacity = 0.3 + integrity = 50 + shard_type = SHARD_SHARD + tableslam_noise = 'sound/effects/Glasshit.ogg' + hardness = 50 + melting_point = T0C + 100 + weight = 14 + brute_armor = 1 + burn_armor = 2 + door_icon_base = "stone" + table_icon_base = "solid" + destruction_desc = "shatters" + window_options = list("One Direction" = 1, "Full Window" = 4) + created_window = /obj/structure/window/basic + rod_product = /obj/item/stack/material/glass/reinforced + hitsound = 'sound/effects/Glasshit.ogg' + conductive = 0 + +/material/glass/build_windows(var/mob/living/carbon/human/user, var/obj/item/stack/used_stack) + + if(!user || !used_stack || !created_window || !window_options.len) + return 0 + + if(!user.IsAdvancedToolUser()) + to_chat(user, "This task is too complex for your clumsy hands.") + return 1 + + if(user.statscheck(skills = user.SKILL_LEVEL(engineering)) >= SUCCESS) + return 1 + else + to_chat(user, "I have failed to build a window.") + + var/turf/T = user.loc + if(!istype(T)) + to_chat(user, "You must be standing on open flooring to build a window.") + return 1 + + var/title = "Sheet-[used_stack.name] ([used_stack.get_amount()] sheet\s left)" + var/choice = input(title, "What would you like to construct?") as null|anything in window_options + + if(!choice || !used_stack || !user || used_stack.loc != user || user.stat || user.loc != T) + return 1 + + // Get data for building windows here. + var/list/possible_directions = GLOB.cardinal.Copy() + var/window_count = 0 + for (var/obj/structure/window/check_window in user.loc) + window_count++ + possible_directions -= check_window.dir + + // Get the closest available dir to the user's current facing. + var/build_dir = SOUTHWEST //Default to southwest for fulltile windows. + var/failed_to_build + + if(window_count >= 4) + failed_to_build = 1 + else + if(choice in list("One Direction","Windoor")) + if(possible_directions.len) + for(var/direction in list(user.dir, turn(user.dir,90), turn(user.dir,180), turn(user.dir,270) )) + if(direction in possible_directions) + build_dir = direction + break + else + failed_to_build = 1 + if(!failed_to_build && choice == "Windoor") + if(!is_reinforced()) + to_chat(user, "This material is not reinforced enough to use for a door.") + return + if((locate(/obj/structure/windoor_assembly) in T.contents) || (locate(/obj/machinery/door/window) in T.contents)) + failed_to_build = 1 + if(failed_to_build) + to_chat(user, "There is no room in this location.") + return 1 + + var/build_path = /obj/structure/windoor_assembly + var/sheets_needed = window_options[choice] + if(choice == "Windoor") + build_dir = user.dir + else + build_path = created_window + + if(used_stack.get_amount() < sheets_needed) + to_chat(user, "You need at least [sheets_needed] sheets to build this.") + return 1 + + // Build the structure and update sheet count etc. + used_stack.use(sheets_needed) + new build_path(T, build_dir, 1) + return 1 + +/material/glass/proc/is_reinforced() + return (integrity > 75) //todo + +/material/glass/is_brittle() + return ..() && !is_reinforced() + +/material/glass/reinforced + name = "rglass" + display_name = "reinforced glass" + stack_type = /obj/item/stack/material/glass/reinforced + flags = MATERIAL_BRITTLE + icon_colour = "#00e1ff" + opacity = 0.3 + integrity = 100 + melting_point = T0C + 750 + shard_type = SHARD_SHARD + tableslam_noise = 'sound/effects/Glasshit.ogg' + weight = 17 + brute_armor = 2 + burn_armor = 3 + stack_origin_tech = list(TECH_MATERIAL = 2) + composite_material = list(DEFAULT_WALL_MATERIAL = 1875,"glass" = 3750) + window_options = list("One Direction" = 1, "Full Window" = 4, "Windoor" = 5) + created_window = /obj/structure/window/reinforced + wire_product = null + rod_product = null + +/material/glass/phoron + name = "phglass" + display_name = "borosilicate glass" + stack_type = /obj/item/stack/material/glass/phoronglass + flags = MATERIAL_BRITTLE + integrity = 70 + brute_armor = 2 + burn_armor = 5 + melting_point = T0C + 2000 + icon_colour = "#fc2bc5" + stack_origin_tech = list(TECH_MATERIAL = 4) + created_window = /obj/structure/window/phoronbasic + wire_product = null + rod_product = /obj/item/stack/material/glass/phoronrglass + +/material/glass/phoron/reinforced + name = "rphglass" + brute_armor = 3 + burn_armor = 10 + melting_point = T0C + 4000 + display_name = "reinforced borosilicate glass" + stack_type = /obj/item/stack/material/glass/phoronrglass + stack_origin_tech = list(TECH_MATERIAL = 5) + composite_material = list() //todo + created_window = /obj/structure/window/phoronreinforced + stack_origin_tech = list(TECH_MATERIAL = 2) + composite_material = list() //todo + rod_product = null + integrity = 100 + + +/material/plastic + name = "plastic" + stack_type = /obj/item/stack/material/plastic + flags = MATERIAL_BRITTLE + icon_base = "solid" + icon_reinf = "reinf_over" + icon_colour = "#cccccc" + hardness = 10 + weight = 5 + melting_point = T0C+371 //assuming heat resistant plastic + stack_origin_tech = list(TECH_MATERIAL = 3) + conductive = 0 + +/material/plastic/holographic + name = "holoplastic" + display_name = "plastic" + stack_type = null + shard_type = SHARD_NONE + +/material/osmium + name = "osmium" + stack_type = /obj/item/stack/material/osmium + icon_colour = "#9999ff" + stack_origin_tech = list(TECH_MATERIAL = 5) + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + +/material/tritium + name = "tritium" + stack_type = /obj/item/stack/material/tritium + icon_colour = "#777777" + stack_origin_tech = list(TECH_MATERIAL = 5) + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + is_fusion_fuel = 1 + +/material/deuterium + name = "deuterium" + stack_type = /obj/item/stack/material/deuterium + icon_colour = "#999999" + stack_origin_tech = list(TECH_MATERIAL = 3) + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + is_fusion_fuel = 1 + +/material/mhydrogen + name = "mhydrogen" + stack_type = /obj/item/stack/material/mhydrogen + icon_colour = "#e6c5de" + stack_origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 6, TECH_MAGNET = 5) + is_fusion_fuel = 1 + +/material/platinum + name = "platinum" + stack_type = /obj/item/stack/material/platinum + icon_colour = "#9999ff" + weight = 27 + stack_origin_tech = list(TECH_MATERIAL = 2) + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + +/material/iron + name = "iron" + stack_type = /obj/item/stack/material/iron + icon_colour = "#5c5454" + weight = 22 + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + hitsound = 'sound/weapons/smash.ogg' + +// Adminspawn only, do not let anyone get this. +/material/voxalloy + name = "voxalloy" + display_name = "durable alloy" + stack_type = null + icon_colour = "#6c7364" + integrity = 1200 + melting_point = 6000 // Hull plating. + explosion_resistance = 200 // Hull plating. + hardness = 500 + weight = 500 + +// Likewise. +/material/voxalloy/elevatorium + name = "elevatorium" + display_name = "elevator panelling" + icon_colour = "#666666" + +/material/wood + name = "wood" + adjective_name = "wooden" + stack_type = /obj/item/stack/material/wood + icon_colour = "#824b28" + integrity = 50 + icon_base = "solid" + table_icon_base = "solid" + explosion_resistance = 2 + shard_type = SHARD_SPLINTER + shard_can_repair = 0 // you can't weld splinters back into planks + hardness = 15 + brute_armor = 1 + weight = 18 + melting_point = T0C+300 //okay, not melting in this case, but hot enough to destroy wood + ignition_point = T0C+288 + stack_origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) + dooropen_noise = 'sound/effects/doorcreaky.ogg' + door_icon_base = "wood" + destruction_desc = "splinters" + sheet_singular_name = "plank" + sheet_plural_name = "planks" + hitsound = 'sound/effects/woodhit.ogg' + conductive = 0 + +/material/wood/holographic + name = "holowood" + display_name = "wood" + stack_type = null + shard_type = SHARD_NONE + +/material/cardboard + name = "cardboard" + stack_type = /obj/item/stack/material/cardboard + flags = MATERIAL_BRITTLE + integrity = 10 + icon_base = "solid" + icon_reinf = "reinf_over" + icon_colour = "#aaaaaa" + hardness = 1 + brute_armor = 1 + weight = 1 + ignition_point = T0C+232 //"the temperature at which book-paper catches fire, and burns." close enough + melting_point = T0C+232 //temperature at which cardboard walls would be destroyed + stack_origin_tech = list(TECH_MATERIAL = 1) + door_icon_base = "wood" + destruction_desc = "crumples" + conductive = 0 + +/material/cloth //todo + name = "cloth" + stack_origin_tech = list(TECH_MATERIAL = 2) + door_icon_base = "wood" + ignition_point = T0C+232 + melting_point = T0C+300 + flags = MATERIAL_PADDING + brute_armor = 1 + conductive = 0 + +/material/cult + name = "cult" + display_name = "disturbing stone" + icon_base = "cult" + icon_colour = "#402821" + icon_reinf = "reinf_cult" + shard_type = SHARD_STONE_PIECE + sheet_singular_name = "brick" + sheet_plural_name = "bricks" + conductive = 0 + +/material/cult/place_dismantled_girder(var/turf/target) + new /obj/structure/girder/cult(target) + +/material/cult/reinf + name = "cult2" + display_name = "runic inscriptions" + +/material/resin + name = "resin" + icon_colour = "#e85dd8" + dooropen_noise = 'sound/effects/attackblob.ogg' + door_icon_base = "resin" + melting_point = T0C+300 + sheet_singular_name = "blob" + sheet_plural_name = "blobs" + conductive = 0 + +/*/material/resin/can_open_material_door(var/mob/living/user) + var/mob/living/carbon/M = user + if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs) + return 1 + return 0 +*/ +/material/aliumium + name = "alien alloy" + stack_type = null + icon_base = "jaggy" + door_icon_base = "metal" + icon_reinf = "reinf_metal" + hitsound = 'sound/weapons/smash.ogg' + sheet_singular_name = "chunk" + sheet_plural_name = "chunks" + +/material/aliumium/New() + icon_base = pick("jaggy","curvy") + icon_colour = rgb(rand(10,150),rand(10,150),rand(10,150)) + explosion_resistance = rand(25,40) + brute_armor = rand(10,20) + burn_armor = rand(10,20) + hardness = rand(15,100) + integrity = rand(200,400) + melting_point = rand(400,10000) + ..() + +/material/aliumium/place_dismantled_girder(var/turf/target, var/material/reinf_material) + return + +//TODO PLACEHOLDERS: +/material/leather + name = "leather" + icon_colour = "#5c4831" + stack_origin_tech = list(TECH_MATERIAL = 2) + flags = MATERIAL_PADDING + ignition_point = T0C+300 + melting_point = T0C+300 + conductive = 0 + +/material/carpet + name = "carpet" + display_name = "comfy" + use_name = "red upholstery" + icon_colour = "#da020a" + flags = MATERIAL_PADDING + ignition_point = T0C+232 + melting_point = T0C+300 + sheet_singular_name = "tile" + sheet_plural_name = "tiles" + conductive = 0 + +/material/cotton + name = "cotton" + display_name ="cotton" + icon_colour = "#ffffff" + flags = MATERIAL_PADDING + ignition_point = T0C+232 + melting_point = T0C+300 + conductive = 0 + +/material/cloth_teal + name = "teal" + display_name ="teal" + use_name = "teal cloth" + icon_colour = "#00eafa" + flags = MATERIAL_PADDING + ignition_point = T0C+232 + melting_point = T0C+300 + conductive = 0 + +/material/cloth_black + name = "black" + display_name = "black" + use_name = "black cloth" + icon_colour = "#505050" + flags = MATERIAL_PADDING + ignition_point = T0C+232 + melting_point = T0C+300 + conductive = 0 + +/material/cloth_green + name = "green" + display_name = "green" + use_name = "green cloth" + icon_colour = "#01c608" + flags = MATERIAL_PADDING + ignition_point = T0C+232 + melting_point = T0C+300 + conductive = 0 + +/material/cloth_puple + name = "purple" + display_name = "purple" + use_name = "purple cloth" + icon_colour = "#9c56c4" + flags = MATERIAL_PADDING + ignition_point = T0C+232 + melting_point = T0C+300 + conductive = 0 + +/material/cloth_blue + name = "blue" + display_name = "blue" + use_name = "blue cloth" + icon_colour = "#6b6fe3" + flags = MATERIAL_PADDING + ignition_point = T0C+232 + melting_point = T0C+300 + conductive = 0 + +/material/cloth_beige + name = "beige" + display_name = "beige" + use_name = "beige cloth" + icon_colour = "#e8e7c8" + flags = MATERIAL_PADDING + ignition_point = T0C+232 + melting_point = T0C+300 + conductive = 0 + +/material/cloth_lime + name = "lime" + display_name = "lime" + use_name = "lime cloth" + icon_colour = "#62e36c" + flags = MATERIAL_PADDING + ignition_point = T0C+232 + melting_point = T0C+300 + conductive = 0 diff --git a/code/modules/merchant/merchant_guns.dm b/code/modules/merchant/merchant_guns.dm new file mode 100644 index 00000000..3eeae57a --- /dev/null +++ b/code/modules/merchant/merchant_guns.dm @@ -0,0 +1,27 @@ +/obj/item/weapon/gun/projectile/sec/MK + desc = "Similar in both appearance and use of the NT Mk58, the MK pistol is an cheap knock off that preys on the unsuspecting firearm buyers." + condition = 45 + +/obj/item/weapon/gun/projectile/silenced/cheap + desc = "A handgun with an integrated silencer(?). Uses .45 rounds." + +/obj/item/weapon/gun/projectile/silenced/cheap/handle_post_fire() + silenced = prob(50) + return ..() + +/obj/item/weapon/gun/projectile/heavysniper/ant + name = "ant-material rifle" + desc = "A portable anti-armour rifle fitted with a scope, the HI PTR-7 Rifle was originally designed to used against armoured exosuits. It is capable of punching through windows and non-reinforced walls with ease. Fires armor piercing 14.5mm shells. This replica however fires 9mm rounds." + ammo_type = /obj/item/ammo_casing/c9mm + caliber = "9mm" + +/obj/item/weapon/gun/energy/laser/dogan + desc = "This carbine works just as well as a normal carbine. Most of the time." //removed reference to Dogan, since only the merchant is likely to know who that is. + +/obj/item/weapon/gun/energy/laser/dogan/consume_next_projectile() + projectile_type = pick(/obj/item/projectile/beam/midlaser, /obj/item/projectile/beam/lastertag/red, /obj/item/projectile/beam) + return ..() + +/obj/item/weapon/gun/projectile/automatic/mini_uzi/usi + desc = "An uncommon machine pistol, sometimes refered to as an 'uzi' by the backwater spacers it is often associated with. This one looks especially run-down. Uses .45 rounds." + condition = 45 \ No newline at end of file diff --git a/code/modules/merchant/merchant_machinery.dm b/code/modules/merchant/merchant_machinery.dm new file mode 100644 index 00000000..7c4fb06f --- /dev/null +++ b/code/modules/merchant/merchant_machinery.dm @@ -0,0 +1,22 @@ +/obj/machinery/merchant_pad + name = "Teleportation Pad" + desc = "Place things here to trade." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "tele0" + anchored = 1 + density = 0 + +/obj/machinery/merchant_pad/proc/get_target() + var/turf/T = get_turf(src) + for(var/a in T) + if(a == src || (!istype(a,/obj) && !istype(a,/mob/living)) || istype(a,/obj/effect)) + continue + return a + +/obj/machinery/merchant_pad/proc/get_targets() + . = list() + var/turf/T = get_turf(src) + for(var/a in T) + if(a == src || (!istype(a,/obj) && !istype(a,/mob/living)) || istype(a,/obj/effect)) + continue + . += a \ No newline at end of file diff --git a/code/modules/merchant/merchant_programs.dm b/code/modules/merchant/merchant_programs.dm new file mode 100644 index 00000000..104a2eb4 --- /dev/null +++ b/code/modules/merchant/merchant_programs.dm @@ -0,0 +1,227 @@ +/datum/computer_file/program/merchant + filename = "mlist" + filedesc = "Merchant's List" + extended_desc = "Allows communication and trade between passing vessels, even while jumping." + program_icon_state = "comm" + program_menu_icon = "cart" + nanomodule_path = /datum/nano_module/program/merchant + requires_ntnet = 1 + available_on_ntnet = 1 + size = 12 + usage_flags = PROGRAM_CONSOLE + required_access = access_merchant + var/obj/machinery/merchant_pad/pad = null + var/current_merchant = 0 + var/show_trades = 0 + var/hailed_merchant = 0 + var/last_comms = null + var/temp = null + var/bank = 0 //A straight up money till + +/datum/nano_module/program/merchant + name = "Merchant's List" + +/datum/computer_file/program/merchant/proc/get_merchant(var/num) + if(num > GLOB.traders.len) + num = GLOB.traders.len + if(num) + return GLOB.traders[num] + +/datum/nano_module/program/merchant/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + var/show_trade = 0 + var/hailed = 0 + var/datum/trader/T + if(program) + var/datum/computer_file/program/merchant/P = program + data["temp"] = P.temp + data["mode"] = !!P.current_merchant + data["last_comms"] = P.last_comms + data["pad"] = !!P.pad + data["bank"] = P.bank + show_trade = P.show_trades + hailed = P.hailed_merchant + T = P.get_merchant(P.current_merchant) + data["mode"] = !!T + if(T) + data["traderName"] = T.name + data["origin"] = T.origin + data["hailed"] = hailed + if(show_trade) + var/list/trades = list() + if(T.trading_items.len) + for(var/i in 1 to T.trading_items.len) + trades += T.print_trading_items(i) + data["trades"] = trades + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "merchant.tmpl", "Merchant List", 575, 700, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + +/datum/computer_file/program/merchant/proc/connect_pad() + for(var/obj/machinery/merchant_pad/P in orange(1,get_turf(computer))) + pad = P + return + +/datum/computer_file/program/merchant/proc/test_fire() + if(pad && pad.get_target()) + return 1 + return 0 + +/datum/computer_file/program/merchant/proc/offer_money(var/datum/trader/T, var/num) + if(pad) + var/response = T.offer_money_for_trade(num, bank) + if(istext(response)) + last_comms = T.get_response(response, "No thank you.") + else + last_comms = T.get_response("trade_complete", "Thank you!") + T.trade(null,num, get_turf(pad)) + bank -= response + return + last_comms = "PAD NOT CONNECTED" + +/datum/computer_file/program/merchant/proc/bribe(var/datum/trader/T, var/amt) + if(bank < amt) + last_comms = "ERROR: NOT ENOUGH FUNDS." + return + + bank -= amt + last_comms = T.bribe_to_stay_longer(amt) + +/datum/computer_file/program/merchant/proc/offer_item(var/datum/trader/T, var/num) + if(pad) + var/list/targets = pad.get_targets() + for(var/target in targets) + if(!computer_emagged && istype(target,/mob/living/carbon/human)) + last_comms = "SAFETY LOCK ENABLED: SENTIENT MATTER UNTRANSMITTABLE" + return + var/response = T.offer_items_for_trade(targets,num, get_turf(pad)) + if(istext(response)) + last_comms = T.get_response(response,"No, a million times no.") + else + last_comms = T.get_response("trade_complete","Thanks for your business!") + + return + last_comms = "PAD NOT CONNECTED" + +/datum/computer_file/program/merchant/proc/sell_items(var/datum/trader/T) + if(pad) + var/list/targets = pad.get_targets() + var/response = T.sell_items(targets) + if(istext(response)) + last_comms = T.get_response(response, "Nope. Nope nope nope.") + else + last_comms = T.get_response("trade_complete", "Glad to be of service!") + bank += response + return + last_comms = "PAD NOT CONNECTED" + +/datum/computer_file/program/merchant/proc/transfer_to_bank() + if(pad) + var/list/targets = pad.get_targets() + for(var/target in targets) + if(istype(target, /obj/item/weapon/spacecash)) + var/obj/item/weapon/spacecash/cash = target + bank += cash.worth + qdel(target) + last_comms = "ALL MONEY DETECTED ON PAD TRANSFERED" + return + last_comms = "PAD NOT CONNECTED" + +/datum/computer_file/program/merchant/proc/get_money() + if(!pad) + last_comms = "PAD NOT CONNECTED. CANNOT TRANSFER" + return + var/turf/T = get_turf(pad) + var/obj/item/weapon/spacecash/bundle/B = new(T) + B.worth = bank + bank = 0 + B.update_icon() + +/datum/computer_file/program/merchant/Topic(href, href_list) + if(..()) + return 1 + var/mob/user = usr + if(href_list["PRG_connect_pad"]) + . = 1 + connect_pad() + if(href_list["PRG_continue"]) + . = 1 + temp = null + if(href_list["PRG_transfer_to_bank"]) + . = 1 + transfer_to_bank() + if(href_list["PRG_get_money"]) + . = 1 + get_money() + if(href_list["PRG_main_menu"]) + . = 1 + current_merchant = 0 + if(href_list["PRG_merchant_list"]) + if(GLOB.traders.len == 0) + . = 0 + temp = "Cannot find any traders within broadcasting range." + else + . = 1 + current_merchant = 1 + hailed_merchant = 0 + last_comms = null + if(href_list["PRG_test_fire"]) + . = 1 + if(test_fire()) + temp = "Test Fire Successful" + else + temp = "Test Fire Unsuccessful" + if(href_list["PRG_scroll"]) + . = 1 + var/scrolled = 0 + switch(href_list["PRG_scroll"]) + if("right") + scrolled = 1 + if("left") + scrolled = -1 + var/new_merchant = Clamp(current_merchant + scrolled, 1, GLOB.traders.len) + if(new_merchant != current_merchant) + hailed_merchant = 0 + last_comms = null + current_merchant = new_merchant + if(current_merchant) + var/datum/trader/T = get_merchant(current_merchant) + if(!T.can_hail()) + last_comms = T.get_response("hail_deny", "No, I'm not speaking with you.") + . = 1 + else + if(href_list["PRG_hail"]) + . = 1 + last_comms = T.hail(user) + show_trades = 0 + hailed_merchant = 1 + if(href_list["PRG_show_trades"]) + . = 1 + show_trades = !show_trades + if(href_list["PRG_insult"]) + . = 1 + last_comms = T.insult() + if(href_list["PRG_compliment"]) + . = 1 + last_comms = T.compliment() + if(href_list["PRG_offer_item"]) + . = 1 + offer_item(T,text2num(href_list["PRG_offer_item"]) + 1) + if(href_list["PRG_how_much_do_you_want"]) + . = 1 + last_comms = T.how_much_do_you_want(text2num(href_list["PRG_how_much_do_you_want"]) + 1) + if(href_list["PRG_offer_money_for_item"]) + . = 1 + offer_money(T, text2num(href_list["PRG_offer_money_for_item"])+1) + if(href_list["PRG_what_do_you_want"]) + . = 1 + last_comms = T.what_do_you_want() + if(href_list["PRG_sell_items"]) + . = 1 + sell_items(T) + if(href_list["PRG_bribe"]) + . = 1 + bribe(T, text2num(href_list["PRG_bribe"])) \ No newline at end of file diff --git a/code/modules/mining/abandonedcrates.dm b/code/modules/mining/abandonedcrates.dm new file mode 100644 index 00000000..524a7b88 --- /dev/null +++ b/code/modules/mining/abandonedcrates.dm @@ -0,0 +1,206 @@ +/obj/structure/closet/crate/secure/loot + name = "abandoned crate" + desc = "What could be inside?" + icon_state = "securecrate" + icon_opened = "securecrateopen" + icon_closed = "securecrate" + var/list/code = list() + var/list/lastattempt = list() + var/attempts = 10 + var/codelen = 4 + locked = 1 + +/obj/structure/closet/crate/secure/loot/New() + ..() + var/list/digits = list("1", "2", "3", "4", "5", "6", "7", "8", "9", "0") + + for(var/i in 1 to codelen) + code += pick(digits) + digits -= code[code.len] + + generate_loot() + +/obj/structure/closet/crate/secure/loot/proc/generate_loot() + var/loot = rand(1, 100) + switch(loot) + if(1 to 5) // Common things go, 5% + new/obj/item/weapon/reagent_containers/food/drinks/bottle/rum(src) + new/obj/item/weapon/reagent_containers/food/drinks/bottle/whiskey(src) + new/obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiadeus(src) + new/obj/item/weapon/flame/lighter/zippo(src) + if(6 to 10) + new/obj/item/weapon/pickaxe/drill(src) + new/obj/item/device/taperecorder(src) + new/obj/item/clothing/suit/space(src) + new/obj/item/clothing/head/helmet/space(src) + if(11 to 15) + new/obj/item/weapon/reagent_containers/glass/beaker/bluespace(src) + if(16 to 20) + for(var/i = 0, i < 10, i++) + new/obj/item/weapon/ore/diamond(src) + if(21 to 25) + for(var/i = 0, i < 3, i++) + new/obj/machinery/portable_atmospherics/hydroponics(src) + if(26 to 30) + for(var/i = 0, i < 3, i++) + new/obj/item/weapon/reagent_containers/glass/beaker/noreact(src) + if(31 to 35) + spawn_money(rand(300,800), src) + if(36 to 40) + new/obj/item/weapon/melee/baton(src) + if(41 to 45) + new/obj/item/clothing/under/shorts/red(src) + new/obj/item/clothing/under/shorts/blue(src) + if(46 to 50) + new/obj/item/clothing/under/chameleon(src) + for(var/i = 0, i < 7, i++) + new/obj/item/clothing/accessory/horrible(src) + if(51 to 52) // Uncommon, 2% each + new/obj/item/weapon/melee/classic_baton(src) + if(53 to 54) + new/obj/item/latexballon(src) + if(55 to 56) + var/newitem = pick(typesof(/obj/item/toy/prize) - /obj/item/toy/prize) + new newitem(src) + if(57 to 60) + new/obj/item/toy/balloon(src) + if(61 to 62) + for(var/i = 0, i < 12, ++i) + new/obj/item/clothing/head/kitty(src) + if(63 to 64) + var/t = rand(4,7) + for(var/i = 0, i < t, ++i) + var/newcoin = pick(/obj/item/weapon/coin/silver, /obj/item/weapon/coin/silver, /obj/item/weapon/coin/silver, /obj/item/weapon/coin/iron, /obj/item/weapon/coin/iron, /obj/item/weapon/coin/iron, /obj/item/weapon/coin/gold, /obj/item/weapon/coin/diamond, /obj/item/weapon/coin/phoron, /obj/item/weapon/coin/uranium, /obj/item/weapon/coin/platinum) + new newcoin(src) + if(65 to 66) + new/obj/item/clothing/suit/ianshirt(src) + if(67 to 68) + var/t = rand(4,7) + for(var/i = 0, i < t, ++i) + var/newitem = pick(typesof(/obj/item/weapon/stock_parts) - /obj/item/weapon/stock_parts - /obj/item/weapon/stock_parts/subspace) + new newitem(src) + if(69 to 70) + new/obj/item/weapon/pickaxe/silver(src) + if(71 to 72) + new/obj/item/weapon/pickaxe/drill(src) + if(73 to 74) + new/obj/item/weapon/pickaxe/jackhammer(src) + if(75 to 76) + new/obj/item/weapon/pickaxe/diamond(src) + if(77 to 78) + new/obj/item/weapon/pickaxe/diamonddrill(src) + if(79 to 80) + new/obj/item/weapon/pickaxe/gold(src) + if(81 to 82) + new/obj/item/weapon/gun/energy/plasmacutter(src) + if(83 to 84) + new/obj/item/toy/katana(src) + if(85 to 86) + new/obj/item/seeds/random(src) + if(87) // Rarest things, some are unobtainble otherwise, some are just robust, 1% each + new/obj/item/weed_extract(src) + if(88) + new/obj/item/xenos_claw(src) + if(90) + new/obj/item/organ/internal/heart(src) + if(91) + new/obj/item/device/soulstone(src) + if(92) + new/obj/item/weapon/material/sword/katana(src) + if(93) + new/obj/item/weapon/storage/firstaid/combat(src) // Probably the least OP + if(94) // Why the hell not + new/obj/item/weapon/storage/backpack/clown(src) + new/obj/item/clothing/under/rank/clown(src) + new/obj/item/clothing/shoes/clown_shoes(src) + new/obj/item/device/pda/clown(src) + new/obj/item/clothing/mask/gas/clown_hat(src) + new/obj/item/weapon/bikehorn(src) + //new/obj/item/weapon/stamp/clown(src) I'd add it, but only clowns can use it + new/obj/item/weapon/pen/crayon/rainbow(src) + new/obj/item/weapon/reagent_containers/spray/waterflower(src) + if(95) + new/obj/item/clothing/under/mime(src) + new/obj/item/clothing/shoes/black(src) + new/obj/item/device/pda/mime(src) + new/obj/item/clothing/gloves/white(src) + new/obj/item/clothing/mask/gas/mime(src) + new/obj/item/clothing/head/beret(src) + new/obj/item/clothing/accessory/suspenders(src) + new/obj/item/weapon/pen/crayon/mime(src) + new/obj/item/weapon/reagent_containers/food/drinks/bottle/bottleofnothing(src) + if(96) + new/obj/item/weapon/vampiric(src) + if(97) + new/obj/item/weapon/archaeological_find(src) + if(98) + new/obj/item/weapon/melee/energy/sword(src) + if(99) + new/obj/item/weapon/storage/belt/champion(src) + new/obj/item/clothing/mask/luchador(src) + if(100) + new/obj/item/clothing/head/bearpelt(src) + +/obj/structure/closet/crate/secure/loot/togglelock(mob/user as mob) + if(!locked) + return + + to_chat(user, "The crate is locked with a Deca-code lock.") + var/input = input(user, "Enter [codelen] digits.", "Deca-Code Lock", "") as text + if(!Adjacent(user)) + return + + if(input == null || length(input) != codelen) + to_chat(user, "You leave the crate alone.") + else if(check_input(input) && locked) + to_chat(user, "The crate unlocks!") + playsound(user, 'sound/machines/lockreset.ogg', 50, 1) + ..() + else + visible_message("A red light on \the [src]'s control panel flashes briefly.") + attempts-- + if (attempts == 0) + to_chat(user, "The crate's anti-tamper system activates!") + var/turf/T = get_turf(src.loc) + explosion(T, 0, 0, 1, 2) + qdel(src) + +/obj/structure/closet/crate/secure/loot/emag_act(var/remaining_charges, var/mob/user) + if (locked) + to_chat(user, "The crate unlocks!") + locked = 0 + +/obj/structure/closet/crate/secure/loot/proc/check_input(var/input) + if(length(input) != codelen) + return 0 + + . = 1 + lastattempt.Cut() + for(var/i in 1 to codelen) + var/guesschar = copytext(input, i, i+1) + lastattempt += guesschar + if(guesschar != code[i]) + . = 0 + +/obj/structure/closet/crate/secure/loot/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(locked) + if (istype(W, /obj/item/device/multitool)) // Greetings Urist McProfessor, how about a nice game of cows and bulls? + to_chat(user, "DECA-CODE LOCK ANALYSIS:") + if (attempts == 1) + to_chat(user, "* Anti-Tamper system will activate on the next failed access attempt.") + else + to_chat(user, "* Anti-Tamper system will activate after [src.attempts] failed access attempts.") + if(lastattempt.len) + var/bulls = 0 + var/cows = 0 + + var/list/code_contents = code.Copy() + for(var/i in 1 to codelen) + if(lastattempt[i] == code[i]) + ++bulls + else if(lastattempt[i] in code_contents) + ++cows + code_contents -= lastattempt[i] + to_chat(user, "Last code attempt had [bulls] correct digits at correct positions and [cows] correct digits at incorrect positions.") + return + ..() diff --git a/code/modules/mining/alloys.dm b/code/modules/mining/alloys.dm new file mode 100644 index 00000000..a087b442 --- /dev/null +++ b/code/modules/mining/alloys.dm @@ -0,0 +1,46 @@ +//Alloys that contain subsets of each other's ingredients must be ordered in the desired sequence +//eg. steel comes after plasteel because plasteel's ingredients contain the ingredients for steel and +//it would be impossible to produce. + +/datum/alloy + var/list/requires + var/product_mod = 1 + var/product + var/metaltag + +/datum/alloy/plasteel + metaltag = "plasteel" + requires = list( + "platinum" = 1, + "carbon" = 2, + "iron" = 2 + ) + product_mod = 0.3 + product = /obj/item/stack/material/plasteel + +/datum/alloy/ocp + metaltag = "osmium-carbide plasteel" + requires = list( + "platinum" = 1, + "carbon" = 3, + "iron" = 2, + "osmium" = 2 + ) + product_mod = 0.3 + product = /obj/item/stack/material/ocp + +/datum/alloy/steel + metaltag = DEFAULT_WALL_MATERIAL + requires = list( + "carbon" = 1, + "iron" = 1 + ) + product = /obj/item/stack/material/steel + +/datum/alloy/borosilicate + metaltag = "phglass" + requires = list( + "platinum" = 1, + "sand" = 2 + ) + product = /obj/item/stack/material/glass/phoronglass diff --git a/code/modules/mining/coins.dm b/code/modules/mining/coins.dm new file mode 100644 index 00000000..4f01330b --- /dev/null +++ b/code/modules/mining/coins.dm @@ -0,0 +1,78 @@ +/*****************************Coin********************************/ + +/obj/item/weapon/coin + icon = 'icons/obj/items.dmi' + name = "Coin" + icon_state = "coin" + randpixel = 8 + obj_flags = OBJ_FLAG_CONDUCTIBLE + force = 0.0 + throwforce = 0.0 + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + var/string_attached + var/sides = 2 + +/obj/item/weapon/coin/gold + name = "gold coin" + icon_state = "coin_gold" + +/obj/item/weapon/coin/silver + name = "silver coin" + icon_state = "coin_silver" + +/obj/item/weapon/coin/diamond + name = "diamond coin" + icon_state = "coin_diamond" + +/obj/item/weapon/coin/iron + name = "iron coin" + icon_state = "coin_iron" + +/obj/item/weapon/coin/phoron + name = "solid phoron coin" + icon_state = "coin_phoron" + +/obj/item/weapon/coin/uranium + name = "uranium coin" + icon_state = "coin_uranium" + +/obj/item/weapon/coin/platinum + name = "platinum coin" + icon_state = "coin_adamantine" + +/obj/item/weapon/coin/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isCoil(W)) + var/obj/item/stack/cable_coil/CC = W + if(string_attached) + to_chat(user, "There already is a string attached to this coin.") + return + if (CC.use(1)) + overlays += image('icons/obj/items.dmi',"coin_string_overlay") + string_attached = 1 + to_chat(user, "You attach a string to the coin.") + else + to_chat(user, "This cable coil appears to be empty.") + return + else if(isWirecutter(W)) + if(!string_attached) + ..() + return + + var/obj/item/stack/cable_coil/CC = new/obj/item/stack/cable_coil(user.loc) + CC.amount = 1 + CC.update_icon() + overlays = list() + string_attached = null + to_chat(user, "You detach the string from the coin.") + else ..() + +/obj/item/weapon/coin/attack_self(mob/user as mob) + var/result = rand(1, sides) + var/comment = "" + if(result == 1) + comment = "tails" + else if(result == 2) + comment = "heads" + user.visible_message("[user] has thrown \the [src]. It lands on [comment]! ", \ + "You throw \the [src]. It lands on [comment]! ") diff --git a/code/modules/mining/drilling/drill.dm b/code/modules/mining/drilling/drill.dm new file mode 100644 index 00000000..5ad6a683 --- /dev/null +++ b/code/modules/mining/drilling/drill.dm @@ -0,0 +1,378 @@ +/obj/machinery/mining + icon = 'icons/obj/mining_drill.dmi' + anchored = 0 + use_power = 0 //The drill takes power directly from a cell. + density = 1 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER //So it draws over mobs in the tile north of it. + +/obj/machinery/mining/drill + name = "mining drill head" + desc = "An enormous drill." + icon_state = "mining_drill" + var/braces_needed = 2 + var/list/supports = list() + var/supported = 0 + var/base_power_usage = 10 KILOWATTS // Base power usage when the drill is running. + var/actual_power_usage = 10 KILOWATTS // Actual power usage, with upgrades in mind. + var/active = 0 + var/list/resource_field = list() + + var/ore_types = list( + "iron" = /obj/item/weapon/ore/iron, + "uranium" = /obj/item/weapon/ore/uranium, + "gold" = /obj/item/weapon/ore/gold, + "silver" = /obj/item/weapon/ore/silver, + "diamond" = /obj/item/weapon/ore/diamond, + "phoron" = /obj/item/weapon/ore/phoron, + "osmium" = /obj/item/weapon/ore/osmium, + "hydrogen" = /obj/item/weapon/ore/hydrogen, + "silicates" = /obj/item/weapon/ore/glass, + "carbonaceous rock" = /obj/item/weapon/ore/coal + ) + + //Upgrades + var/harvest_speed + var/capacity + var/obj/item/weapon/cell/cell = null + + //Flags + var/need_update_field = 0 + var/need_player_check = 0 + +/obj/machinery/mining/drill/New() + + ..() + + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/miningdrill(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/capacitor(src) + component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) + component_parts += new /obj/item/weapon/cell/high(src) + + RefreshParts() + +/obj/machinery/mining/drill/Process() + + if(need_player_check) + return + + check_supports() + + if(!active) return + + if(!anchored || !use_cell_power()) + system_error("system configuration or charge error") + return + + if(need_update_field) + get_resource_field() + + if(world.time % 10 == 0) + update_icon() + + if(!active) + return + + //Drill through the flooring, if any. + if(istype(get_turf(src), /turf/simulated/floor/asteroid)) + var/turf/simulated/floor/asteroid/T = get_turf(src) + if(!T.dug) + T.gets_dug() + else if(istype(get_turf(src), /turf/simulated/floor/exoplanet)) + var/turf/simulated/floor/exoplanet/T = get_turf(src) + if(T.diggable) + new /obj/structure/pit(T) + T.diggable = 0 + else if(istype(get_turf(src), /turf/simulated/floor)) + var/turf/simulated/floor/T = get_turf(src) + T.ex_act(2.0) + + //Dig out the tasty ores. + if(resource_field.len) + var/turf/simulated/harvesting = pick(resource_field) + + while(resource_field.len && !harvesting.resources) + harvesting.has_resources = 0 + harvesting.resources = null + resource_field -= harvesting + if(resource_field.len) + harvesting = pick(resource_field) + + if(!harvesting) return + + var/total_harvest = harvest_speed //Ore harvest-per-tick. + var/found_resource = 0 //If this doesn't get set, the area is depleted and the drill errors out. + + for(var/metal in ore_types) + + if(contents.len >= capacity) + system_error("insufficient storage space") + active = 0 + need_player_check = 1 + update_icon() + return + + if(contents.len + total_harvest >= capacity) + total_harvest = capacity - contents.len + + if(total_harvest <= 0) break + if(harvesting.resources[metal]) + + found_resource = 1 + + var/create_ore = 0 + if(harvesting.resources[metal] >= total_harvest) + harvesting.resources[metal] -= total_harvest + create_ore = total_harvest + total_harvest = 0 + else + total_harvest -= harvesting.resources[metal] + create_ore = harvesting.resources[metal] + harvesting.resources[metal] = 0 + + for(var/i=1, i <= create_ore, i++) + var/oretype = ore_types[metal] + new oretype(src) + + if(!found_resource) + harvesting.has_resources = 0 + harvesting.resources = null + resource_field -= harvesting + else + active = 0 + need_player_check = 1 + update_icon() + +/obj/machinery/mining/drill/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/mining/drill/attackby(obj/item/O as obj, mob/user as mob) + if(!active) + if(default_deconstruction_screwdriver(user, O)) + return + if(default_deconstruction_crowbar(user, O)) + return + if(default_part_replacement(user, O)) + return + if(!panel_open || active) return ..() + + if(istype(O, /obj/item/weapon/cell)) + if(cell) + to_chat(user, "The drill already has a cell installed.") + else + user.drop_item() + O.loc = src + cell = O + component_parts += O + to_chat(user, "You install \the [O].") + return + ..() + +/obj/machinery/mining/drill/attack_hand(mob/user as mob) + check_supports() + + if (panel_open && cell && user.Adjacent(src)) + to_chat(user, "You take out \the [cell].") + cell.loc = get_turf(user) + component_parts -= cell + cell = null + return + else if(need_player_check) + to_chat(user, "You hit the manual override and reset the drill's error checking.") + need_player_check = 0 + if(anchored) + get_resource_field() + update_icon() + return + else if(supported && !panel_open) + if(use_cell_power()) + active = !active + if(active) + visible_message("\The [src] lurches downwards, grinding noisily.") + need_update_field = 1 + else + visible_message("\The [src] shudders to a grinding halt.") + else + to_chat(user, "The drill is unpowered.") + else + to_chat(user, "Turning on a piece of industrial machinery without sufficient bracing or wires exposed is a bad idea.") + + update_icon() + +/obj/machinery/mining/drill/update_icon() + if(need_player_check) + icon_state = "mining_drill_error" + else if(active) + icon_state = "mining_drill_active" + else if(supported) + icon_state = "mining_drill_braced" + else + icon_state = "mining_drill" + return + +/obj/machinery/mining/drill/RefreshParts() + ..() + harvest_speed = 0 + capacity = 0 + var/charge_multiplier = 0 + + for(var/obj/item/weapon/stock_parts/P in component_parts) + if(istype(P, /obj/item/weapon/stock_parts/micro_laser)) + harvest_speed = P.rating + if(istype(P, /obj/item/weapon/stock_parts/matter_bin)) + capacity = 200 * P.rating + if(istype(P, /obj/item/weapon/stock_parts/capacitor)) + charge_multiplier += P.rating + cell = locate(/obj/item/weapon/cell) in component_parts + if(charge_multiplier) + actual_power_usage = base_power_usage / charge_multiplier + else + actual_power_usage = base_power_usage + +/obj/machinery/mining/drill/proc/check_supports() + + supported = 0 + + if((!supports || !supports.len) && initial(anchored) == 0) + icon_state = "mining_drill" + anchored = 0 + active = 0 + else + anchored = 1 + + if(supports && supports.len >= braces_needed) + supported = 1 + + update_icon() + +/obj/machinery/mining/drill/proc/system_error(var/error) + + if(error) + src.visible_message("\The [src] flashes a '[error]' warning.") + need_player_check = 1 + active = 0 + update_icon() + +/obj/machinery/mining/drill/proc/get_resource_field() + + resource_field = list() + need_update_field = 0 + + var/turf/T = get_turf(src) + if(!istype(T)) return + + var/tx = T.x - 2 + var/ty = T.y - 2 + var/turf/simulated/mine_turf + for(var/iy = 0,iy < 5, iy++) + for(var/ix = 0, ix < 5, ix++) + mine_turf = locate(tx + ix, ty + iy, T.z) + if(mine_turf && mine_turf.has_resources) + resource_field += mine_turf + + if(!resource_field.len) + system_error("resources depleted") + +/obj/machinery/mining/drill/proc/use_cell_power() + return cell && cell.checked_use(actual_power_usage * CELLRATE) + +/obj/machinery/mining/drill/verb/unload() + set name = "Unload Drill" + set category = "Object" + set src in oview(1) + + if(usr.stat) return + + var/obj/structure/ore_box/B = locate() in orange(1) + if(B) + for(var/obj/item/weapon/ore/O in contents) + O.loc = B + to_chat(usr, "You unload the drill's storage cache into the ore box.") + else + to_chat(usr, "You must move an ore box up to the drill before you can unload it.") + + +/obj/machinery/mining/brace + name = "mining drill brace" + desc = "A machinery brace for an industrial drill. It looks easily two feet thick." + icon_state = "mining_brace" + var/obj/machinery/mining/drill/connected + +/obj/machinery/mining/brace/New() + ..() + + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/miningdrillbrace(src) + +/obj/machinery/mining/brace/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(connected && connected.active) + to_chat(user, "You can't work with the brace of a running drill!") + return + + if(default_deconstruction_screwdriver(user, W)) + return + if(default_deconstruction_crowbar(user, W)) + return + + if(isWrench(W)) + + if(istype(get_turf(src), /turf/space)) + to_chat(user, "You can't anchor something to empty space. Idiot.") + return + + playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + to_chat(user, "You [anchored ? "un" : ""]anchor the brace.") + + anchored = !anchored + if(anchored) + connect() + else + disconnect() + +/obj/machinery/mining/brace/proc/connect() + + var/turf/T = get_step(get_turf(src), src.dir) + + for(var/thing in T.contents) + if(istype(thing, /obj/machinery/mining/drill)) + connected = thing + break + + if(!connected) + return + + if(!connected.supports) + connected.supports = list() + + icon_state = "mining_brace_active" + + connected.supports += src + connected.check_supports() + +/obj/machinery/mining/brace/proc/disconnect() + + if(!connected) return + + if(!connected.supports) connected.supports = list() + + icon_state = "mining_brace" + + connected.supports -= src + connected.check_supports() + connected = null + +/obj/machinery/mining/brace/verb/rotate() + set name = "Rotate" + set category = "Object" + set src in oview(1) + + if(usr.stat) return + + if (src.anchored) + to_chat(usr, "It is anchored in place!") + return 0 + + src.set_dir(turn(src.dir, 90)) + return 1 \ No newline at end of file diff --git a/code/modules/mining/drilling/scanner.dm b/code/modules/mining/drilling/scanner.dm new file mode 100644 index 00000000..b780fde7 --- /dev/null +++ b/code/modules/mining/drilling/scanner.dm @@ -0,0 +1,111 @@ +/turf/simulated/var/surveyed + +/obj/item/weapon/mining_scanner + name = "ore detector" + desc = "A complex device used to locate ore deep underground." + icon = 'icons/obj/device.dmi' + icon_state = "forensic0-old" //GET A BETTER SPRITE. + item_state = "electronic" + origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1) + matter = list(DEFAULT_WALL_MATERIAL = 150) + var/survey_data = 0 + +/obj/item/weapon/mining_scanner/examine(mob/user) + ..() + to_chat(user,"Tiny indicator shows it holds [survey_data] Good Explorer Points worth of data.") + +/obj/item/weapon/mining_scanner/attack_self(mob/user as mob) + to_chat(user, "You begin sweeping \the [src] about, scanning for metal deposits.") + + if(!do_after(user, 50,src)) + return + + var/list/metals = list( + "surface minerals" = 0, + "precious metals" = 0, + "nuclear fuel" = 0, + "exotic matter" = 0 + ) + var/new_data = 0 + for(var/turf/simulated/T in range(2, get_turf(user))) + + if(!T.has_resources) + continue + + for(var/metal in T.resources) + var/ore_type + var/data_value = 1 + + switch(metal) + if("silicates", "carbonaceous rock", "iron") + ore_type = "surface minerals" + if("gold", "silver", "diamond") + ore_type = "precious metals" + data_value = 2 + if("uranium") + ore_type = "nuclear fuel" + data_value = 3 + if("phoron", "osmium", "hydrogen") + ore_type = "exotic matter" + data_value = 4 + + if(ore_type) metals[ore_type] += T.resources[metal] + + if(!T.surveyed) + new_data += data_value * T.resources[metal] + + T.surveyed = 1 + + to_chat(user, "\icon[src] The scanner beeps and displays a readout.") + + for(var/ore_type in metals) + var/result = "no sign" + + switch(metals[ore_type]) + if(1 to 25) result = "trace amounts" + if(26 to 75) result = "significant amounts" + if(76 to INFINITY) result = "huge quantities" + + + to_chat(user, "- [result] of [ore_type].") + + if(new_data) + survey_data += new_data + playsound(loc, 'sound/machines/ping.ogg', 40, 1) + to_chat(user,"New survey data stored - [new_data] GEP.") + +/obj/item/weapon/mining_scanner/verb/get_data() + set category = "Object" + set name = "Get Survey Data" + set src in usr + + var/mob/M = usr + if(!istype(M)) + return + if(M.incapacitated()) + return + if(!survey_data) + to_chat(M,"There is no survey data stored on [src].") + return + visible_message("[src] records [survey_data] GEP worth of the data on the disk and spits it out.") + var/obj/item/weapon/disk/survey/D = new(get_turf(src)) + D.data = survey_data + survey_data = 0 + M.put_in_hands(D) + +/obj/item/weapon/disk/survey + name = "survey data disk" + icon = 'icons/obj/items.dmi' + icon_state = "nucleardisk" + var/data + +/obj/item/weapon/disk/survey/examine(mob/user) + ..() + to_chat(user,"Tiny indicator shows it holds [data] Good Explorer Points of data.") + +/obj/item/weapon/disk/survey/Value() + if(data < 10000) + return 0.07*data + if(data < 30000) + return 0.1*data + return 0.15*data \ No newline at end of file diff --git a/code/modules/mining/machine_input_output_plates.dm b/code/modules/mining/machine_input_output_plates.dm new file mode 100644 index 00000000..0e7680e6 --- /dev/null +++ b/code/modules/mining/machine_input_output_plates.dm @@ -0,0 +1,19 @@ +/**********************Input and output plates**************************/ + +/obj/machinery/mineral/input + icon = 'icons/mob/screen1.dmi' + icon_state = "x2" + name = "Input area" + density = 0 + anchored = 1.0 + New() + icon_state = "blank" + +/obj/machinery/mineral/output + icon = 'icons/mob/screen1.dmi' + icon_state = "x" + name = "Output area" + density = 0 + anchored = 1.0 + New() + icon_state = "blank" \ No newline at end of file diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm new file mode 100644 index 00000000..9dacda4e --- /dev/null +++ b/code/modules/mining/machine_processing.dm @@ -0,0 +1,242 @@ +/**********************Mineral processing unit console**************************/ + +/obj/machinery/mineral/processing_unit_console + name = "production machine console" + icon = 'icons/obj/machines/mining_machines.dmi' + icon_state = "console" + density = 1 + anchored = 1 + + var/obj/machinery/mineral/processing_unit/machine = null + var/machinedir = EAST + var/show_all_ores = 0 + +/obj/machinery/mineral/processing_unit_console/New() + ..() + spawn(7) + src.machine = locate(/obj/machinery/mineral/processing_unit, get_step(src, machinedir)) + if (machine) + machine.console = src + else + qdel(src) + +/obj/machinery/mineral/processing_unit_console/attack_hand(mob/user) + add_fingerprint(user) + interact(user) + +/obj/machinery/mineral/processing_unit_console/interact(mob/user) + + if(..()) + return + + if(!allowed(user)) + to_chat(user, "Access denied.") + return + + user.set_machine(src) + + var/dat = "

                Ore processor console

                " + + dat += "
            " + + for(var/ore in machine.ores_processing) + + if(!machine.ores_stored[ore] && !show_all_ores) continue + var/ore/O = ore_data[ore] + if(!O) continue + dat += "" + + dat += "
            [capitalize(O.display_name)][machine.ores_stored[ore]]" + if(machine.ores_processing[ore]) + switch(machine.ores_processing[ore]) + if(0) + dat += "not processing" + if(1) + dat += "smelting" + if(2) + dat += "compressing" + if(3) + dat += "alloying" + else + dat += "not processing" + dat += ".\[change\]

            " + dat += "Currently displaying [show_all_ores ? "all ore types" : "only available ore types"]. \[[show_all_ores ? "show less" : "show more"]\]
            " + dat += "The ore processor is currently [(machine.active ? "processing" : "disabled")]." + user << browse(dat, "window=processor_console;size=400x500") + onclose(user, "processor_console") + return + +/obj/machinery/mineral/processing_unit_console/Topic(href, href_list) + if(..()) + return 1 + usr.set_machine(src) + src.add_fingerprint(usr) + + if(href_list["toggle_smelting"]) + + var/choice = input("What setting do you wish to use for processing [href_list["toggle_smelting"]]?") as null|anything in list("Smelting","Compressing","Alloying","Nothing") + if(!choice) return + + switch(choice) + if("Nothing") choice = 0 + if("Smelting") choice = 1 + if("Compressing") choice = 2 + if("Alloying") choice = 3 + + machine.ores_processing[href_list["toggle_smelting"]] = choice + + if(href_list["toggle_power"]) + + machine.active = !machine.active + + if(href_list["toggle_ores"]) + + show_all_ores = !show_all_ores + + src.updateUsrDialog() + return + +/**********************Mineral processing unit**************************/ + + +/obj/machinery/mineral/processing_unit + name = "material processor" //This isn't actually a goddamn furnace, we're in space and it's processing platinum and flammable phoron... + icon = 'icons/obj/machines/mining_machines.dmi' + icon_state = "furnace" + density = 1 + anchored = 1 + light_range = 3 + var/obj/machinery/mineral/input = null + var/obj/machinery/mineral/output = null + var/obj/machinery/mineral/console = null + var/sheets_per_tick = 10 + var/list/ores_processing[0] + var/list/ores_stored[0] + var/static/list/alloy_data + var/active = 0 + +/obj/machinery/mineral/processing_unit/New() + ..() + + // initialize static alloy_data list + if(!alloy_data) + alloy_data = list() + for(var/alloytype in typesof(/datum/alloy)-/datum/alloy) + alloy_data += new alloytype() + + ensure_ore_data_initialised() + for(var/ore in ore_data) + ores_processing[ore] = 0 + ores_stored[ore] = 0 + + //Locate our output and input machinery. + spawn(5) + for (var/dir in GLOB.cardinal) + src.input = locate(/obj/machinery/mineral/input, get_step(src, dir)) + if(src.input) break + for (var/dir in GLOB.cardinal) + src.output = locate(/obj/machinery/mineral/output, get_step(src, dir)) + if(src.output) break + return + return + +/obj/machinery/mineral/processing_unit/Process() + + if (!src.output || !src.input) return + + var/list/tick_alloys = list() + + //Grab some more ore to process this tick. + for(var/i = 0,i= sheets_per_tick) break + + if(ores_stored[metal] > 0 && ores_processing[metal] != 0) + + var/ore/O = ore_data[metal] + + if(!O) continue + + if(ores_processing[metal] == 3 && O.alloy) //Alloying. + + for(var/datum/alloy/A in alloy_data) + + if(A.metaltag in tick_alloys) + continue + + tick_alloys += A.metaltag + var/enough_metal + + if(!isnull(A.requires[metal]) && ores_stored[metal] >= A.requires[metal]) //We have enough of our first metal, we're off to a good start. + + enough_metal = 1 + + for(var/needs_metal in A.requires) + //Check if we're alloying the needed metal and have it stored. + if(ores_processing[needs_metal] != 3 || ores_stored[needs_metal] < A.requires[needs_metal]) + enough_metal = 0 + break + + if(!enough_metal) + continue + else + var/total + for(var/needs_metal in A.requires) + ores_stored[needs_metal] -= A.requires[needs_metal] + total += A.requires[needs_metal] + total = max(1,round(total*A.product_mod)) //Always get at least one sheet. + sheets += total-1 + + for(var/i=0,i0) can_make-- + + var/material/M = get_material_by_name(O.compresses_to) + + if(!istype(M) || !can_make || ores_stored[metal] < 1) + continue + + for(var/i=0,iStacking unit console
            ") + + for(var/stacktype in machine.stack_storage) + if(machine.stack_storage[stacktype] > 0) + dat += "" + dat += "
            [capitalize(stacktype)]:[machine.stack_storage[stacktype]]\[release\]

            " + dat += text("
            Stacking: [machine.stack_amt] \[change\]

            ") + + user << browse("[dat]", "window=console_stacking_machine") + onclose(user, "console_stacking_machine") + + +/obj/machinery/mineral/stacking_unit_console/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["change_stack"]) + var/choice = input("What would you like to set the stack amount to?") as null|anything in list(1,5,10,20,50) + if(!choice) return + machine.stack_amt = choice + + if(href_list["release_stack"]) + if(machine.stack_storage[href_list["release_stack"]] > 0) + var/stacktype = machine.stack_paths[href_list["release_stack"]] + var/obj/item/stack/material/S = new stacktype (get_turf(machine.output)) + S.amount = machine.stack_storage[href_list["release_stack"]] + machine.stack_storage[href_list["release_stack"]] = 0 + + src.add_fingerprint(usr) + src.updateUsrDialog() + + return + +/**********************Mineral stacking unit**************************/ + + +/obj/machinery/mineral/stacking_machine + name = "stacking machine" + icon = 'icons/obj/machines/mining_machines.dmi' + icon_state = "stacker" + density = 1 + anchored = 1.0 + var/obj/machinery/mineral/stacking_unit_console/console + var/obj/machinery/mineral/input = null + var/obj/machinery/mineral/output = null + var/list/stack_storage[0] + var/list/stack_paths[0] + var/stack_amt = 50; // Amount to stack before releassing + +/obj/machinery/mineral/stacking_machine/New() + ..() + + for(var/stacktype in subtypesof(/obj/item/stack/material)) + var/obj/item/stack/S = stacktype + var/stack_name = initial(S.name) + stack_storage[stack_name] = 0 + stack_paths[stack_name] = stacktype + + stack_storage["glass"] = 0 + stack_paths["glass"] = /obj/item/stack/material/glass + stack_storage[DEFAULT_WALL_MATERIAL] = 0 + stack_paths[DEFAULT_WALL_MATERIAL] = /obj/item/stack/material/steel + stack_storage["plasteel"] = 0 + stack_paths["plasteel"] = /obj/item/stack/material/plasteel + + spawn( 5 ) + for (var/dir in GLOB.cardinal) + src.input = locate(/obj/machinery/mineral/input, get_step(src, dir)) + if(src.input) break + for (var/dir in GLOB.cardinal) + src.output = locate(/obj/machinery/mineral/output, get_step(src, dir)) + if(src.output) break + return + return + +/obj/machinery/mineral/stacking_machine/Process() + if (src.output && src.input) + var/turf/T = get_turf(input) + for(var/obj/item/O in T.contents) + if(istype(O,/obj/item/stack/material)) + var/obj/item/stack/material/S = O + if(!isnull(stack_storage[initial(S.name)])) + stack_storage[initial(S.name)] += S.amount + O.loc = null + else + O.loc = output.loc + else + O.loc = output.loc + + //Output amounts that are past stack_amt. + for(var/sheet in stack_storage) + if(stack_storage[sheet] >= stack_amt) + var/stacktype = stack_paths[sheet] + var/obj/item/stack/material/S = new stacktype (get_turf(output)) + S.amount = stack_amt + stack_storage[sheet] -= stack_amt + + console.updateUsrDialog() + return + diff --git a/code/modules/mining/machine_unloading.dm b/code/modules/mining/machine_unloading.dm new file mode 100644 index 00000000..de7da617 --- /dev/null +++ b/code/modules/mining/machine_unloading.dm @@ -0,0 +1,46 @@ +/**********************Unloading unit**************************/ + + +/obj/machinery/mineral/unloading_machine + name = "unloading machine" + icon = 'icons/obj/machines/mining_machines.dmi' + icon_state = "unloader" + density = 1 + anchored = 1.0 + var/obj/machinery/mineral/input = null + var/obj/machinery/mineral/output = null + + +/obj/machinery/mineral/unloading_machine/New() + ..() + spawn( 5 ) + for (var/dir in GLOB.cardinal) + src.input = locate(/obj/machinery/mineral/input, get_step(src, dir)) + if(src.input) break + for (var/dir in GLOB.cardinal) + src.output = locate(/obj/machinery/mineral/output, get_step(src, dir)) + if(src.output) break + return + return + +/obj/machinery/mineral/unloading_machine/Process() + if (src.output && src.input) + if (locate(/obj/structure/ore_box, input.loc)) + var/obj/structure/ore_box/BOX = locate(/obj/structure/ore_box, input.loc) + var/i = 0 + for (var/obj/item/weapon/ore/O in BOX.contents) + BOX.contents -= O + O.loc = output.loc + i++ + if (i>=10) + return + if (locate(/obj/item, input.loc)) + var/obj/item/O + var/i + for (i = 0; i<10; i++) + O = locate(/obj/item, input.loc) + if (O) + O.loc = src.output.loc + else + return + return \ No newline at end of file diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm new file mode 100644 index 00000000..60026644 --- /dev/null +++ b/code/modules/mining/mine_items.dm @@ -0,0 +1,317 @@ +/**********************Miner Lockers**************************/ + +/obj/structure/closet/secure_closet/miner + name = "miner's equipment" + icon_state = "miningsec1" + icon_closed = "miningsec" + icon_locked = "miningsec1" + icon_opened = "miningsecopen" + icon_broken = "miningsecbroken" + icon_off = "miningsecoff" + req_access = list(access_mining) + +/obj/structure/closet/secure_closet/miner/New() + ..() + sleep(2) + if(prob(50)) + new /obj/item/weapon/storage/backpack/industrial(src) + else + new /obj/item/weapon/storage/backpack/satchel/satchel_eng(src) + new /obj/item/device/radio/headset/headset_cargo(src) + new /obj/item/clothing/under/rank/miner(src) + new /obj/item/clothing/gloves/thick(src) + new /obj/item/clothing/shoes/black(src) + new /obj/item/device/analyzer(src) + new /obj/item/weapon/storage/ore(src) + new /obj/item/device/flashlight/lantern(src) + new /obj/item/weapon/shovel(src) + new /obj/item/weapon/pickaxe(src) + new /obj/item/clothing/glasses/meson(src) + +/******************************Lantern*******************************/ + +/obj/item/device/flashlight/lantern + name = "lantern" + icon_state = "lantern" + desc = "A mining lantern." + brightness_on = 6 // luminosity when on + +/*****************************Pickaxe********************************/ + +/obj/item/weapon/pickaxe + obj_flags = OBJ_FLAG_CONDUCTIBLE + name = "pickaxe" + desc = "It's a pickaxe. You hit rocks with it. And people with it too if you feel like." + icon = 'icons/obj/mining.dmi' + slot_flags = SLOT_BELT + force = 15 + throwforce = 4 + icon_state = "pickaxe" + item_state = "spickaxe" + w_class = ITEM_SIZE_HUGE + matter = list(DEFAULT_WALL_MATERIAL = 3750) + var/digspeed = 40 //moving the delay to an item var so R&D can make improved picks. --NEO + origin_tech = list(TECH_MATERIAL = 1, TECH_ENGINEERING = 1) + attack_verb = list("hit", "pierced", "sliced", "attacked") + var/list/drill_sound = list('sound/items/pickaxe1.ogg','sound/items/pickaxe2.ogg','sound/items/pickaxe3.ogg','sound/items/pickaxe4.ogg') + var/drill_verb = "drilling" + sharp = TRUE + edge = FALSE + hitsound = "stab_sound" + + var/excavation_amount = 200 + +/obj/item/weapon/pickaxe/hammer + name = "sledgehammer" + //icon_state = "sledgehammer" Waiting on sprite + desc = "A mining hammer made of reinforced metal. You feel like smashing your boss in the face with this." + +/obj/item/weapon/pickaxe/silver + name = "silver pickaxe" + icon_state = "spickaxe" + item_state = "spickaxe" + digspeed = 30 + origin_tech = list(TECH_MATERIAL = 3) + desc = "This makes no metallurgic sense." + +/obj/item/weapon/pickaxe/drill + name = "advanced mining drill" // Can dig sand as well! + icon_state = "handdrill" + item_state = "jackhammer" + digspeed = 30 + origin_tech = list(TECH_MATERIAL = 2, TECH_POWER = 3, TECH_ENGINEERING = 2) + desc = "Yours is the drill that will pierce through the rock walls." + drill_verb = "drilling" + +/obj/item/weapon/pickaxe/jackhammer + name = "sonic jackhammer" + icon_state = "jackhammer" + item_state = "jackhammer" + digspeed = 20 //faster than drill, but cannot dig + origin_tech = list(TECH_MATERIAL = 3, TECH_POWER = 2, TECH_ENGINEERING = 2) + desc = "Cracks rocks with sonic blasts, perfect for killing cave lizards." + drill_verb = "hammering" + +/obj/item/weapon/pickaxe/gold + name = "golden pickaxe" + icon_state = "gpickaxe" + item_state = "gpickaxe" + digspeed = 20 + origin_tech = list(TECH_MATERIAL = 4) + desc = "This makes no metallurgic sense." + drill_verb = "picking" + +/obj/item/weapon/pickaxe/diamond + name = "diamond pickaxe" + icon_state = "dpickaxe" + item_state = "dpickaxe" + digspeed = 10 + origin_tech = list(TECH_MATERIAL = 6, TECH_ENGINEERING = 4) + desc = "A pickaxe with a diamond pick head." + drill_verb = "picking" + +/obj/item/weapon/pickaxe/diamonddrill //When people ask about the badass leader of the mining tools, they are talking about ME! + name = "diamond mining drill" + icon_state = "diamonddrill" + item_state = "jackhammer" + digspeed = 5 //Digs through walls, girders, and can dig up sand + origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 4, TECH_ENGINEERING = 5) + desc = "Yours is the drill that will pierce the heavens!" + drill_verb = "drilling" + +/obj/item/weapon/pickaxe/borgdrill + name = "cyborg mining drill" + icon_state = "diamonddrill" + item_state = "jackhammer" + digspeed = 15 + desc = "" + drill_verb = "drilling" + +/*****************************Shovel********************************/ + +/obj/item/weapon/shovel + name = "shovel" + desc = "A large tool for digging and moving dirt." + icon = 'icons/obj/tools.dmi' + icon_state = "shovel" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + force = 8 + throwforce = 4 + item_state = "shovel" + w_class = ITEM_SIZE_SMALL + origin_tech = list(TECH_MATERIAL = 1, TECH_ENGINEERING = 1) + matter = list(DEFAULT_WALL_MATERIAL = 50) + attack_verb = list("bashed", "bludgeoned", "thrashed", "whacked") + swing_sound = "shovel_swing" + hitsound = "shovel_hit" + drop_sound = 'sound/items/shovel_drop.ogg' + +/obj/item/weapon/shovel/spade + name = "spade" + desc = "A small tool for digging and moving dirt." + icon_state = "spade" + item_state = "spade" + force = 5.0 + throwforce = 7.0 + w_class = ITEM_SIZE_SMALL + + +/**********************Mining car (Crate like thing, not the rail car)**************************/ + +/obj/structure/closet/crate/miningcar + desc = "A mining car. This one doesn't work on rails, but has to be dragged." + name = "Mining car (not for rails)" + icon = 'icons/obj/storage.dmi' + icon_state = "miningcar" + density = 1 + icon_opened = "miningcaropen" + icon_closed = "miningcar" + +// Flags. + +/obj/item/stack/flag + name = "flags" + desc = "Some colourful flags." + singular_name = "flag" + amount = 10 + max_amount = 10 + icon = 'icons/obj/mining.dmi' + + var/upright = 0 + var/fringe = null + +/obj/item/stack/flag/red + name = "red flags" + singular_name = "red flag" + icon_state = "redflag" + fringe = "redflag_fringe" + light_color = COLOR_RED + +/obj/item/stack/flag/yellow + name = "yellow flags" + singular_name = "yellow flag" + icon_state = "yellowflag" + fringe = "yellowflag_fringe" + light_color = COLOR_YELLOW + +/obj/item/stack/flag/green + name = "green flags" + singular_name = "green flag" + icon_state = "greenflag" + fringe = "greenflag_fringe" + light_color = COLOR_LIME + +/obj/item/stack/flag/solgov + name = "sol gov flags" + singular_name = "sol gov flag" + icon_state = "solgovflag" + fringe = "solgovflag_fringe" + desc = "A portable flag with the Sol Government symbol on it. I claim this land for Sol!" + light_color = COLOR_BLUE + +/obj/item/stack/flag/attackby(var/obj/item/W, var/mob/user) + if(upright) + attack_hand(user) + return + return ..() + +/obj/item/stack/flag/attack_hand(var/mob/user) + if(upright) + knock_down() + user.visible_message("\The [user] knocks down \the [singular_name].") + return + return ..() + +/obj/item/stack/flag/attack_self(var/mob/user) + var/turf/T = get_turf(src) + + if(istype(T, /turf/space) || istype(T, /turf/simulated/open)) + to_chat(user, "There's no solid surface to plant the flag on.") + return + + for(var/obj/item/stack/flag/F in T) + if(F.upright) + to_chat(user, "\The [F] is already planted here.") + return + + if(use(1)) // Don't skip use() checks even if you only need one! Stacks with the amount of 0 are possible, e.g. on synthetics! + var/obj/item/stack/flag/newflag = new src.type(T, 1) + newflag.set_up() + if(istype(T, /turf/simulated/floor/asteroid) || istype(T, /turf/simulated/floor/exoplanet)) + user.visible_message("\The [user] plants \the [newflag.singular_name] firmly in the ground.") + else + user.visible_message("\The [user] attaches \the [newflag.singular_name] firmly to the ground.") + +/obj/item/stack/flag/proc/set_up() + pixel_x = 0 + pixel_y = 0 + upright = 1 + anchored = 1 + icon_state = "[initial(icon_state)]_open" + if(fringe) + set_light(2, 0.1) // Very dim so the rest of the flag is barely visible - if the turf is completely dark, you can't see anything on it, no matter what + var/image/addon = image(icon = src.icon, icon_state = fringe) // Bright fringe + addon.layer = ABOVE_LIGHTING_LAYER + addon.plane = EFFECTS_ABOVE_LIGHTING_PLANE + overlays += addon + +/obj/item/stack/flag/proc/knock_down() + pixel_x = rand(-randpixel, randpixel) + pixel_y = rand(-randpixel, randpixel) + upright = 0 + anchored = 0 + icon_state = initial(icon_state) + overlays.Cut() + set_light(0) + + + +/**************************Plasma Cutter*****************************/ + +/obj/item/weapon/gun/energy/plasmacutter/mounted + name = "mounted plasma cutter" + self_recharge = 1 + use_external_power = 1 + +/obj/item/weapon/gun/energy/plasmacutter + name = "plasma cutter" + desc = "A mining tool capable of expelling concentrated plasma bursts. You could use it to cut limbs off of xenos! Or, you know, mine stuff." + charge_meter = 0 + icon = 'icons/obj/tools.dmi' + icon_state = "plasmacutter" + item_state = "plasmacutter" + fire_sound = 'sound/weapons/plasma_cutter.ogg' + slot_flags = SLOT_BELT|SLOT_BACK + w_class = 3 + force = 15 + sharp = 1 + edge = 1 + origin_tech = list(TECH_MATERIAL = 4, TECH_PHORON = 3, TECH_ENGINEERING = 3) + matter = list(DEFAULT_WALL_MATERIAL = 4000) + projectile_type = /obj/item/projectile/beam/plasmacutter + max_shots = 10 + self_recharge = 1 + +/obj/item/projectile/beam/plasmacutter + name = "plasma arc" + icon_state = "omnilaser" + damage = 15 + damage_type = BURN + check_armour = "laser" + range = 5 + pass_flags = PASS_FLAG_TABLE + + muzzle_type = /obj/effect/projectile/trilaser/muzzle + tracer_type = /obj/effect/projectile/trilaser/tracer + impact_type = /obj/effect/projectile/trilaser/impact + +/obj/item/projectile/beam/plasmacutter/on_impact(var/atom/A) + if(istype(A, /turf/simulated/mineral)) + var/turf/simulated/mineral/M = A + if(prob(33)) + M.GetDrilled(1) + return + else + M.emitter_blasts_taken += 2 + . = ..() diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm new file mode 100644 index 00000000..f8324263 --- /dev/null +++ b/code/modules/mining/mine_turfs.dm @@ -0,0 +1,583 @@ +var/list/mining_walls = list() +var/list/mining_floors = list() + +/**********************Mineral deposits**************************/ +/turf/unsimulated/mineral + name = "impassable rock" + icon = 'icons/turf/walls.dmi' + icon_state = "rock-dark" + blocks_air = 1 + density = 1 + opacity = 1 + +/turf/simulated/mineral //wall piece + name = "rock" + icon = 'icons/turf/walls.dmi' + icon_state = "rock" + initial_gas = null + opacity = 1 + density = 1 + blocks_air = 1 + temperature = T0C + var/mined_turf = /turf/simulated/floor/dirty ///turf/simulated/floor/asteroid + var/ore/mineral + var/mined_ore = 0 + var/last_act = 0 + var/emitter_blasts_taken = 0 // EMITTER MINING! Muhehe. + + var/datum/geosample/geologic_data + var/excavation_level = 0 + var/list/finds + var/next_rock = 0 + var/archaeo_overlay = "" + var/excav_overlay = "" + var/obj/item/weapon/last_find + var/datum/artifact_find/artifact_find + var/image/ore_overlay + var/health = 10 + + has_resources = 1 + + +/turf/simulated/mineral/New() + if (!mining_walls["[src.z]"]) + mining_walls["[src.z]"] = list() + mining_walls["[src.z]"] += src + spawn(0) + MineralSpread() + spawn(2) + update_icon(1) + +/turf/simulated/mineral/Destroy() + if (mining_walls["[src.z]"]) + mining_walls["[src.z]"] -= src + return ..() + +/turf/simulated/mineral/can_build_cable() + return !density + +/turf/simulated/mineral/is_plating() + return 1 + +/turf/simulated/mineral/update_icon(var/update_neighbors) + if(!mineral) + SetName(initial(name)) + icon_state = "rock" + else + SetName("[mineral.display_name] deposit") + + overlays.Cut() + + for(var/direction in GLOB.cardinal) + var/turf/turf_to_check = get_step(src,direction) + if(update_neighbors && istype(turf_to_check,/turf/simulated/floor/asteroid)) + var/turf/simulated/floor/asteroid/T = turf_to_check + T.updateMineralOverlays() + else if(istype(turf_to_check,/turf/space) || istype(turf_to_check,/turf/simulated/floor || istype(turf_to_check, /turf/simulated/open))) + var/image/rock_side = image('icons/turf/walls.dmi', "rock_side", dir = turn(direction, 180)) + rock_side.turf_decal_layerise() + + switch(direction) + if(NORTH) + rock_side.pixel_y += (world.icon_size - 15) + if(SOUTH) + rock_side.pixel_y -= (world.icon_size - 15) + if(EAST) + rock_side.pixel_x += (world.icon_size - 15) + if(WEST) + rock_side.pixel_x -= (world.icon_size - 15) + + + overlays += rock_side + + if(ore_overlay) + overlays += ore_overlay + + if(excav_overlay) + overlays += excav_overlay + + if(archaeo_overlay) + overlays += archaeo_overlay + +/turf/simulated/mineral/ex_act(severity) + switch(severity) + if(2.0) + if (prob(70)) + mined_ore = 1 //some of the stuff gets blown up + GetDrilled() + if(1.0) + mined_ore = 2 //some of the stuff gets blown up + GetDrilled() + +/turf/simulated/mineral/bullet_act(var/obj/item/projectile/Proj) + + // Emitter blasts + if(istype(Proj, /obj/item/projectile/beam/emitter)) + emitter_blasts_taken++ + + if(emitter_blasts_taken > 2) // 3 blasts per tile + mined_ore = 1 + GetDrilled() + +/turf/simulated/mineral/Bumped(AM) + . = ..() + + if(istype(AM,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = AM + if(istype(R.module_active,/obj/item/weapon/pickaxe)) + attackby(R.module_active,R) + + else if(istype(AM,/obj/mecha)) + var/obj/mecha/M = AM + if(istype(M.selected,/obj/item/mecha_parts/mecha_equipment/tool/drill)) + M.selected.action(src) + +/turf/simulated/mineral/proc/MineralSpread() + if(mineral && mineral.spread) + for(var/trydir in GLOB.cardinal) + if(prob(mineral.spread_chance)) + var/turf/simulated/mineral/target_turf = get_step(src, trydir) + if(istype(target_turf) && !target_turf.mineral) + target_turf.mineral = mineral + target_turf.UpdateMineral() + target_turf.MineralSpread() + + +/turf/simulated/mineral/proc/UpdateMineral() + clear_ore_effects() + ore_overlay = image('icons/obj/mining.dmi', "rock_[mineral.icon_tag]") + ore_overlay.appearance_flags = RESET_COLOR + ore_overlay.turf_decal_layerise() + update_icon() + +//Not even going to touch this pile of spaghetti +/turf/simulated/mineral/attackby(obj/item/weapon/W as obj, mob/user as mob) + + //if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") + // to_chat(usr, "You don't have the dexterity to do this!") + // return //Bay I can't believe you still haven't gotten rid of this code block. I'm keeping it just as a big fuck you. + + if (istype(W, /obj/item/device/core_sampler)) + geologic_data.UpdateNearbyArtifactInfo(src) + var/obj/item/device/core_sampler/C = W + C.sample_item(src, user) + return + + if (istype(W, /obj/item/device/depth_scanner)) + var/obj/item/device/depth_scanner/C = W + C.scan_atom(user, src) + return + + if (istype(W, /obj/item/device/measuring_tape)) + var/obj/item/device/measuring_tape/P = W + user.visible_message("\The [user] extends [P] towards [src].","You extend [P] towards [src].") + if(do_after(user,10, src)) + to_chat(user, "\The [src] has been excavated to a depth of [excavation_level]cm.") + return + + if (istype(W, /obj/item/weapon/pickaxe)) + if(!istype(user.loc, /turf)) + return + + var/obj/item/weapon/pickaxe/P = W + + playsound(user, pick(P.drill_sound), 20, 1) + + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.adjustStaminaLoss(rand(1,10)) + H.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + + health -= rand(1,5) + + var/newDepth = excavation_level + P.excavation_amount // Used commonly below + //handle any archaeological finds we might uncover + var/fail_message = "" + if(finds && finds.len) + var/datum/find/F = finds[1] + if(newDepth > F.excavation_required) // Digging too deep can break the item. At least you won't summon a Balrog (probably) + fail_message = ". [pick("There is a crunching noise","[W] collides with some different rock","Part of the rock face crumbles away","Something breaks under [W]")]" + + //to_chat(user, "You hit the [src.name] with your [P.name].")//[P.drill_verb][fail_message].
            ") + + if(fail_message && prob(90)) + if(prob(25)) + excavate_find(prob(5), finds[1]) + else if(prob(50)) + finds.Remove(finds[1]) + if(prob(50)) + artifact_debris() + + //if(do_after(user,P.digspeed, src)) + if(health <= 0) + //if(finds && finds.len) + // var/datum/find/F = finds[1] + // if(newDepth == F.excavation_required) // When the pick hits that edge just right, you extract your find perfectly, it's never confined in a rock + // excavate_find(1, F) + // else if(newDepth > F.excavation_required - F.clearance_range) // Not quite right but you still extract your find, the closer to the bottom the better, but not above 80% + // excavate_find(prob(80 * (F.excavation_required - newDepth) / F.clearance_range), F) + + //to_chat(user, "You finish [P.drill_verb] \the [src].") + + + if(newDepth >= 200) + GetDrilled(1) + return + // This means the rock is mined out fully + //var/obj/structure/boulder/B + //if(artifact_find) + // if( excavation_level > 0 || prob(15) ) + //boulder with an artifact inside + // B = new(src) + // if(artifact_find) + // B.artifact_find = artifact_find + // else + // artifact_debris(1) + //else if(prob(5)) + // //empty boulder + // B = new(src) + + //if(B) + // GetDrilled(0) + //else + //GetDrilled(1) + //return + + + + + excavation_level += P.excavation_amount + var/updateIcon = 0 + + //archaeo overlays + if(!archaeo_overlay && finds && finds.len) + var/datum/find/F = finds[1] + if(F.excavation_required <= excavation_level + F.view_range) + archaeo_overlay = "overlay_archaeo[rand(1,3)]" + updateIcon = 1 + + else if(archaeo_overlay && (!finds || !finds.len)) + archaeo_overlay = null + updateIcon = 1 + + //there's got to be a better way to do this + var/update_excav_overlay = 0 + if(excavation_level >= 150) + if(excavation_level - P.excavation_amount < 150) + update_excav_overlay = 1 + else if(excavation_level >= 100) + if(excavation_level - P.excavation_amount < 100) + update_excav_overlay = 1 + else if(excavation_level >= 50) + if(excavation_level - P.excavation_amount < 50) + update_excav_overlay = 1 + + //update overlays displaying excavation level + if( !(excav_overlay && excavation_level > 0) || update_excav_overlay ) + var/excav_quadrant = round(excavation_level / 50) + 1 + excav_overlay = "overlay_excv[excav_quadrant]_[rand(1,3)]" + updateIcon = 1 + + if(updateIcon) + update_icon() + + //drop some rocks + next_rock += P.excavation_amount + while(next_rock > 50) + next_rock -= 50 + var/obj/item/weapon/ore/O = new(src) + geologic_data.UpdateNearbyArtifactInfo(src) + O.geologic_data = geologic_data + + else + return ..() + +/turf/simulated/mineral/proc/clear_ore_effects() + overlays -= ore_overlay + ore_overlay = null + +/turf/simulated/mineral/proc/DropMineral() + if(!mineral) + return + + clear_ore_effects() + var/obj/item/weapon/ore/O = new mineral.ore (src) + if(geologic_data && istype(O)) + geologic_data.UpdateNearbyArtifactInfo(src) + O.geologic_data = geologic_data + return O + +/turf/simulated/mineral/proc/GetDrilled(var/artifact_fail = 0) + //var/destroyed = 0 //used for breaking strange rocks + if (mineral && mineral.result_amount) + + //if the turf has already been excavated, some of it's ore has been removed + for (var/i = 1 to mineral.result_amount - mined_ore) + DropMineral() + + //destroyed artifacts have weird, unpleasant effects + //make sure to destroy them before changing the turf though + if(artifact_find && artifact_fail) + var/pain = 0 + if(prob(50)) + pain = 1 + for(var/mob/living/M in range(src, 200)) + to_chat(M, "[pick("A high pitched [pick("keening","wailing","whistle")]","A rumbling noise like [pick("thunder","heavy machinery")]")] somehow penetrates your mind before fading away!") + if(pain) + flick("pain",M.pain) + if(prob(50)) + M.adjustBruteLoss(5) + else + M.flash_eyes() + if(prob(50)) + M.Stun(5) + radiation_repository.flat_radiate(src, 25, 200) + //Add some rubble, you did just clear out a big chunk of rock. + + ChangeTurf(mined_turf) + + +/turf/simulated/mineral/ChangeTurf(turf/N, tell_universe, force_lighting_update) + . = ..() + for(var/direction in GLOB.cardinal) + var/turf/T = get_step(src,direction) + T.update_icon(1) + + +/turf/simulated/mineral/proc/excavate_find(var/prob_clean = 0, var/datum/find/F) + + //many finds are ancient and thus very delicate - luckily there is a specialised energy suspension field which protects them when they're being extracted + if(prob(F.prob_delicate)) + var/obj/effect/suspension_field/S = locate() in src + if(!S) + visible_message("[pick("An object in the rock crumbles away into dust.","Something falls out of the rock and shatters onto the ground.")]") + finds.Remove(F) + return + + //with skill and luck, players can cleanly extract finds + //otherwise, they come out inside a chunk of rock + if(prob_clean) + var/find = get_archeological_find_by_findtype(F.find_type) + new find(src) + else + var/obj/item/weapon/ore/strangerock/rock = new(src, inside_item_type = F.find_type) + geologic_data.UpdateNearbyArtifactInfo(src) + rock.geologic_data = geologic_data + + finds.Remove(F) + + +/turf/simulated/mineral/proc/artifact_debris(var/severity = 0) + //cael's patented random limited drop componentized loot system! + //sky's patented not-fucking-retarded overhaul! + + //Give a random amount of loot from 1 to 3 or 5, varying on severity. + for(var/j in 1 to rand(1, 3 + max(min(severity, 1), 0) * 2)) + switch(rand(1,7)) + if(1) + var/obj/item/stack/rods/R = new(src) + R.amount = rand(5,25) + + if(2) + var/obj/item/stack/material/plasteel/R = new(src) + R.amount = rand(5,25) + + if(3) + var/obj/item/stack/material/steel/R = new(src) + R.amount = rand(5,25) + + if(4) + var/obj/item/stack/material/plasteel/R = new(src) + R.amount = rand(5,25) + + if(5) + var/quantity = rand(1,3) + for(var/i=0, iThis area has already been dug
            ") + return + + var/turf/T = user.loc + if (!(istype(T))) + return + + to_chat(user, "You start digging.") + playsound(user.loc, 'sound/effects/rustle1.ogg', 50, 1) + + if(!do_after(user,40, src)) return + + to_chat(user, "You dug a hole.") + gets_dug() + + else if(istype(W,/obj/item/weapon/storage/ore)) + var/obj/item/weapon/storage/ore/S = W + if(S.collection_mode) + for(var/obj/item/weapon/ore/O in contents) + O.attackby(W,user) + return + else if(istype(W,/obj/item/weapon/storage/bag/fossils)) + var/obj/item/weapon/storage/bag/fossils/S = W + if(S.collection_mode) + for(var/obj/item/weapon/fossil/F in contents) + F.attackby(W,user) + return + + else + ..(W,user) + return + +/turf/simulated/floor/asteroid/proc/gets_dug() + + if(dug) + return + + for(var/i=0;i<(rand(3)+2);i++) + new/obj/item/weapon/ore/glass(src) + + dug = 1 + icon_state = "asteroid_dug" + return + +/turf/simulated/floor/asteroid/proc/updateMineralOverlays(var/update_neighbors) + + overlays.Cut() + + var/list/step_overlays = list("n" = NORTH, "s" = SOUTH, "e" = EAST, "w" = WEST) + for(var/direction in step_overlays) + + if(istype(get_step(src, step_overlays[direction]), /turf/space)) + var/image/aster_edge = image('icons/turf/flooring/asteroid.dmi', "asteroid_edges", dir = step_overlays[direction]) + aster_edge.turf_decal_layerise() + overlays += aster_edge + + if(istype(get_step(src, step_overlays[direction]), /turf/simulated/mineral)) + var/image/rock_wall = image('icons/turf/walls.dmi', "rock_side", dir = step_overlays[direction]) + rock_wall.turf_decal_layerise() + overlays += rock_wall + + //todo cache + if(overlay_detail) + var/image/floor_decal = image(icon = 'icons/turf/flooring/decals.dmi', icon_state = overlay_detail) + floor_decal.turf_decal_layerise() + overlays |= floor_decal + + if(update_neighbors) + var/list/all_step_directions = list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH,SOUTHWEST,WEST,NORTHWEST) + for(var/direction in all_step_directions) + var/turf/simulated/floor/asteroid/A + if(istype(get_step(src, direction), /turf/simulated/floor/asteroid)) + A = get_step(src, direction) + A.updateMineralOverlays() + +/turf/simulated/floor/asteroid/Entered(atom/movable/M as mob|obj) + ..() + if(istype(M,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = M + if(R.module) + if(istype(R.module_state_1,/obj/item/weapon/storage/ore)) + attackby(R.module_state_1,R) + else if(istype(R.module_state_2,/obj/item/weapon/storage/ore)) + attackby(R.module_state_2,R) + else if(istype(R.module_state_3,/obj/item/weapon/storage/ore)) + attackby(R.module_state_3,R) + else + return + +/turf/simulated/floor/asteroid/air + initial_gas = list("oxygen" = 21.8366, "nitrogen" = 82.1472) + temperature = 293.15 \ No newline at end of file diff --git a/code/modules/mining/mint.dm b/code/modules/mining/mint.dm new file mode 100644 index 00000000..cec95d93 --- /dev/null +++ b/code/modules/mining/mint.dm @@ -0,0 +1,183 @@ +/**********************Mint**************************/ + + +/obj/machinery/mineral/mint + name = "Coin press" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "coinpress0" + density = 1 + anchored = 1.0 + var/obj/machinery/mineral/input = null + var/obj/machinery/mineral/output = null + var/amt_silver = 0 //amount of silver + var/amt_gold = 0 //amount of gold + var/amt_diamond = 0 + var/amt_iron = 0 + var/amt_phoron = 0 + var/amt_uranium = 0 + var/newCoins = 0 //how many coins the machine made in it's last load + var/processing = 0 + var/chosen //which material will be used to make coins + var/coinsToProduce = 10 + + +/obj/machinery/mineral/mint/Initialize() + . = ..() + for (var/dir in GLOB.cardinal) + src.input = locate(/obj/machinery/mineral/input, get_step(src, dir)) + if(src.input) break + for (var/dir in GLOB.cardinal) + src.output = locate(/obj/machinery/mineral/output, get_step(src, dir)) + if(src.output) break + +/obj/machinery/mineral/mint/Process() + if ( src.input) + var/obj/item/stack/O + O = locate(/obj/item/stack, input.loc) + if(O) + var/processed = 1 + switch(O.get_material_name()) + if("gold") + amt_gold += 100 * O.get_amount() + if("silver") + amt_silver += 100 * O.get_amount() + if("diamond") + amt_diamond += 100 * O.get_amount() + if("phoron") + amt_phoron += 100 * O.get_amount() + if("uranium") + amt_uranium += 100 * O.get_amount() + if("iron") + amt_iron += 100 * O.get_amount() + else + processed = 0 + if(processed) + qdel(O) + +/obj/machinery/mineral/mint/attack_hand(user as mob) + + var/dat = "Coin Press
            " + + if (!input) + dat += text("input connection status: ") + dat += text("NOT CONNECTED
            ") + if (!output) + dat += text("
            output connection status: ") + dat += text("NOT CONNECTED
            ") + + dat += text("
            Gold inserted: [amt_gold] ") + if (chosen == "gold") + dat += text("chosen") + else + dat += text("Choose") + dat += text("
            Silver inserted: [amt_silver] ") + if (chosen == "silver") + dat += text("chosen") + else + dat += text("Choose") + dat += text("
            Iron inserted: [amt_iron] ") + if (chosen == "iron") + dat += text("chosen") + else + dat += text("Choose") + dat += text("
            Diamond inserted: [amt_diamond] ") + if (chosen == "diamond") + dat += text("chosen") + else + dat += text("Choose") + dat += text("
            Phoron inserted: [amt_phoron] ") + if (chosen == "phoron") + dat += text("chosen") + else + dat += text("Choose") + dat += text("
            Uranium inserted: [amt_uranium] ") + if (chosen == "uranium") + dat += text("chosen") + else + dat += text("Choose") + + dat += text("

            Will produce [coinsToProduce] [chosen] coins if enough materials are available.
            ") + //dat += text("The dial which controls the number of conins to produce seems to be stuck. A technician has already been dispatched to fix this.") + dat += text("-10 ") + dat += text("-5 ") + dat += text("-1 ") + dat += text("+1 ") + dat += text("+5 ") + dat += text("+10 ") + + dat += text("

            In total this machine produced [newCoins] coins.") + dat += text("
            Make coins") + user << browse("[dat]", "window=mint") + +/obj/machinery/mineral/mint/Topic(href, href_list) + if(..()) + return 1 + usr.set_machine(src) + src.add_fingerprint(usr) + if(processing==1) + to_chat(usr, "The machine is processing.") + return + if(href_list["choose"]) + chosen = href_list["choose"] + if(href_list["chooseAmt"]) + coinsToProduce = between(0, coinsToProduce + text2num(href_list["chooseAmt"]), 1000) + if(href_list["makeCoins"]) + var/temp_coins = coinsToProduce + if (src.output) + processing = 1; + icon_state = "coinpress1" + var/M = output.loc + switch(chosen) + if("iron") + while(amt_iron > 0 && coinsToProduce > 0) + new/obj/item/weapon/coin/iron(M) + amt_iron -= 20 + coinsToProduce-- + newCoins++ + src.updateUsrDialog() + sleep(5); + if("gold") + while(amt_gold > 0 && coinsToProduce > 0) + new /obj/item/weapon/coin/gold(M) + amt_gold -= 20 + coinsToProduce-- + newCoins++ + src.updateUsrDialog() + sleep(5); + if("silver") + while(amt_silver > 0 && coinsToProduce > 0) + new /obj/item/weapon/coin/silver(M) + amt_silver -= 20 + coinsToProduce-- + newCoins++ + src.updateUsrDialog() + sleep(5); + if("diamond") + while(amt_diamond > 0 && coinsToProduce > 0) + new /obj/item/weapon/coin/diamond(M) + amt_diamond -= 20 + coinsToProduce-- + newCoins++ + src.updateUsrDialog() + sleep(5); + if("phoron") + while(amt_phoron > 0 && coinsToProduce > 0) + new /obj/item/weapon/coin/phoron(M) + amt_phoron -= 20 + coinsToProduce-- + newCoins++ + src.updateUsrDialog() + sleep(5); + if("uranium") + while(amt_uranium > 0 && coinsToProduce > 0) + new /obj/item/weapon/coin/uranium(M) + amt_uranium -= 20 + coinsToProduce-- + newCoins++ + src.updateUsrDialog() + sleep(5) + icon_state = "coinpress0" + processing = 0; + coinsToProduce = temp_coins + src.updateUsrDialog() + return \ No newline at end of file diff --git a/code/modules/mining/ore.dm b/code/modules/mining/ore.dm new file mode 100644 index 00000000..f3193427 --- /dev/null +++ b/code/modules/mining/ore.dm @@ -0,0 +1,90 @@ +/obj/item/weapon/ore + name = "small rock" + icon = 'icons/obj/mining.dmi' + icon_state = "ore2" + randpixel = 8 + w_class = ITEM_SIZE_SMALL + var/datum/geosample/geologic_data + var/ore/ore = null // set to a type to find the right instance on init + +/obj/item/weapon/ore/Initialize() + . = ..() + if(ispath(ore)) + ensure_ore_data_initialised() + ore = ores_by_type[ore] + if(ore.ore != type) + log_error("[src] ([src.type]) had ore type [ore.type] but that type does not have [src.type] set as its ore item!") + update_ore() + +/obj/item/weapon/ore/proc/update_ore() + SetName(ore.display_name) + icon_state = "ore_[ore.icon_tag]" + origin_tech = ore.origin_tech.Copy() + +/obj/item/weapon/ore/Value(var/base) + . = ..() + if(!ore) + return + var/material/M + if(ore.smelts_to) + M = get_material_by_name(ore.smelts_to) + else if (ore.compresses_to) + M = get_material_by_name(ore.compresses_to) + if(!istype(M)) + return + return 0.5*M.value*ore.result_amount + +/obj/item/weapon/ore/slag + name = "slag" + desc = "Someone screwed up..." + icon_state = "slag" + +/obj/item/weapon/ore/uranium + ore = /ore/uranium + +/obj/item/weapon/ore/iron + ore = /ore/hematite + +/obj/item/weapon/ore/coal + ore = /ore/coal + +/obj/item/weapon/ore/glass + ore = /ore/glass + slot_flags = SLOT_HOLSTER + +// POCKET SAND! +/obj/item/weapon/ore/glass/throw_impact(atom/hit_atom) + ..() + var/mob/living/carbon/human/H = hit_atom + if(istype(H) && H.has_eyes() && prob(85)) + to_chat(H, "Some of \the [src] gets in your eyes!") + H.eye_blind += 5 + H.eye_blurry += 10 + spawn(1) + if(istype(loc, /turf/)) qdel(src) + + +/obj/item/weapon/ore/phoron + ore = /ore/phoron + +/obj/item/weapon/ore/silver + ore = /ore/silver + +/obj/item/weapon/ore/gold + ore = /ore/gold + +/obj/item/weapon/ore/diamond + ore = /ore/diamond + +/obj/item/weapon/ore/osmium + ore = /ore/platinum + +/obj/item/weapon/ore/hydrogen + ore = /ore/hydrogen + +/obj/item/weapon/ore/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/device/core_sampler)) + var/obj/item/device/core_sampler/C = W + C.sample_item(src, user) + else + return ..() diff --git a/code/modules/mining/ore_datum.dm b/code/modules/mining/ore_datum.dm new file mode 100644 index 00000000..05949316 --- /dev/null +++ b/code/modules/mining/ore_datum.dm @@ -0,0 +1,163 @@ +var/global/list/ore_data = list() +var/global/list/ores_by_type = list() + +/hook/startup/proc/initialise_ore_data() + ensure_ore_data_initialised() + return 1 + +/proc/ensure_ore_data_initialised() + if(ore_data && ore_data.len) return + + for(var/oretype in subtypesof(/ore)) + var/ore/O = new oretype() + ore_data[O.name] = O + ores_by_type[oretype] = O + +/ore + var/name // Name of ore. Also used as a tag. + var/display_name // Visible name of ore. + var/icon_tag // Used for icon_state as "ore_[icon_tag]" and "rock_[icon_tag]" + var/material // Name of associated mineral, if any + var/alloy // Can alloy? + var/smelts_to // Smelts to material; this is the name of the result material. + var/compresses_to // Compresses to material; this is the name of the result material. + var/result_amount // How much ore? + var/spread = 1 // Does this type of deposit spread? + var/spread_chance // Chance of spreading in any direction + var/ore // Path to the ore produced when tile is mined. + var/scan_icon // Overlay for ore scanners. + // Xenoarch stuff. No idea what it's for, just refactored it to be less awful. + var/list/xarch_ages = list( + "thousand" = 999, + "million" = 999 + ) + var/xarch_source_mineral = "iron" + var/list/origin_tech = list(TECH_MATERIAL = 1) + +/ore/New() + . = ..() + if(!display_name) + display_name = name + if(!material) + material = name + if(!icon_tag) + icon_tag = name + +/ore/uranium + name = "uranium" + display_name = "pitchblende" + smelts_to = "uranium" + result_amount = 5 + spread_chance = 10 + ore = /obj/item/weapon/ore/uranium + scan_icon = "mineral_uncommon" + xarch_ages = list( + "thousand" = 999, + "million" = 704 + ) + xarch_source_mineral = "potassium" + origin_tech = list(TECH_MATERIAL = 5) + +/ore/hematite + name = "iron" + display_name = "hematite" + smelts_to = "iron" + alloy = 1 + result_amount = 5 + spread_chance = 25 + ore = /obj/item/weapon/ore/iron + scan_icon = "mineral_common" + +/ore/coal + name = "carbon" + display_name = "raw carbon" + icon_tag = "coal" + smelts_to = "plastic" + alloy = 1 + result_amount = 5 + spread_chance = 25 + ore = /obj/item/weapon/ore/coal + scan_icon = "mineral_common" + +/ore/glass + name = "sand" + display_name = "sand" + icon_tag = "glass" + smelts_to = "glass" + alloy = 1 + compresses_to = "sandstone" + ore = /obj/item/weapon/ore/glass //Technically not needed since there's no glass ore vein, but consistency is nice + +/ore/phoron + name = "phoron" + display_name = "phoron crystals" + compresses_to = "phoron" + //smelts_to = something that explodes violently on the conveyor, huhuhuhu + result_amount = 5 + spread_chance = 25 + ore = /obj/item/weapon/ore/phoron + scan_icon = "mineral_uncommon" + xarch_ages = list( + "thousand" = 999, + "million" = 999, + "billion" = 13, + "billion_lower" = 10 + ) + xarch_source_mineral = "phoron" + origin_tech = list(TECH_MATERIAL = 2) + +/ore/silver + name = "silver" + display_name = "native silver" + smelts_to = "silver" + result_amount = 5 + spread_chance = 10 + ore = /obj/item/weapon/ore/silver + scan_icon = "mineral_uncommon" + origin_tech = list(TECH_MATERIAL = 3) + +/ore/gold + smelts_to = "gold" + name = "gold" + display_name = "native gold" + result_amount = 5 + spread_chance = 10 + ore = /obj/item/weapon/ore/gold + scan_icon = "mineral_uncommon" + xarch_ages = list( + "thousand" = 999, + "million" = 999, + "billion" = 4, + "billion_lower" = 3 + ) + origin_tech = list(TECH_MATERIAL = 4) + +/ore/diamond + name = "diamond" + display_name = "diamond" + compresses_to = "diamond" + result_amount = 5 + spread_chance = 10 + ore = /obj/item/weapon/ore/diamond + scan_icon = "mineral_rare" + xarch_source_mineral = "nitrogen" + origin_tech = list(TECH_MATERIAL = 6) + +/ore/platinum + name = "platinum" + display_name = "raw platinum" + smelts_to = "platinum" + compresses_to = "osmium" + alloy = 1 + result_amount = 5 + spread_chance = 10 + ore = /obj/item/weapon/ore/osmium + scan_icon = "mineral_rare" + +/ore/hydrogen + name = "mhydrogen" + display_name = "metallic hydrogen" + smelts_to = "tritium" + compresses_to = "mhydrogen" + ore = /obj/item/weapon/ore/hydrogen //Technically not needed since there's no hydrogen ore vein, but consistency is nice + scan_icon = "mineral_rare" diff --git a/code/modules/mining/satchel_ore_boxdm.dm b/code/modules/mining/satchel_ore_boxdm.dm new file mode 100644 index 00000000..8934eb1c --- /dev/null +++ b/code/modules/mining/satchel_ore_boxdm.dm @@ -0,0 +1,103 @@ + +/**********************Ore box**************************/ + +/obj/structure/ore_box + icon = 'icons/obj/mining.dmi' + icon_state = "orebox0" + name = "ore box" + desc = "A heavy box used for storing ore." + density = 1 + var/last_update = 0 + var/list/stored_ore = list() + +/obj/structure/ore_box/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/ore)) + user.remove_from_mob(W) + src.contents += W + if (istype(W, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = W + S.hide_from(usr) + for(var/obj/item/weapon/ore/O in S.contents) + if(S.contents.len <= 1) + S.remove_from_storage(O, src, 0) //This will move the item to this item's contents + else + S.remove_from_storage(O, src, 1) + to_chat(user, "You empty the satchel into the box.") + + update_ore_count() + + return + +/obj/structure/ore_box/proc/update_ore_count() + + stored_ore = list() + + for(var/obj/item/weapon/ore/O in contents) + + if(stored_ore[O.name]) + stored_ore[O.name]++ + else + stored_ore[O.name] = 1 + +/obj/structure/ore_box/examine(mob/user) + . = ..(user) + + // Borgs can now check contents too. + if((!istype(user, /mob/living/carbon/human)) && (!istype(user, /mob/living/silicon/robot))) + return + + if(!Adjacent(user)) //Can only check the contents of ore boxes if you can physically reach them. + return + + add_fingerprint(user) + + if(!contents.len) + to_chat(user, "It is empty.") + return + + if(world.time > last_update + 10) + update_ore_count() + last_update = world.time + + to_chat(user, "It holds:") + for(var/ore in stored_ore) + to_chat(user, "- [stored_ore[ore]] [ore]") + return + + +/obj/structure/ore_box/verb/empty_box() + set name = "Empty Ore Box" + set category = "Object" + set src in view(1) + + if(!istype(usr, /mob/living/carbon/human)) //Only living, intelligent creatures with hands can empty ore boxes. + to_chat(usr, "You are physically incapable of emptying the ore box.") + return + + if( usr.stat || usr.restrained() ) + return + + if(!Adjacent(usr)) //You can only empty the box if you can physically reach it + to_chat(usr, "You cannot reach the ore box.") + return + + add_fingerprint(usr) + + if(contents.len < 1) + to_chat(usr, "The ore box is empty") + return + + for (var/obj/item/weapon/ore/O in contents) + contents -= O + O.loc = src.loc + to_chat(usr, "You empty the ore box") + + return + +/obj/structure/ore_box/ex_act(severity) + if(severity == 1.0 || (severity < 3.0 && prob(50))) + for (var/obj/item/weapon/ore/O in contents) + O.loc = src.loc + O.ex_act(severity++) + qdel(src) + return \ No newline at end of file diff --git a/code/modules/mob/animations.dm b/code/modules/mob/animations.dm new file mode 100644 index 00000000..02fe0cea --- /dev/null +++ b/code/modules/mob/animations.dm @@ -0,0 +1,244 @@ +/* +adds a dizziness amount to a mob +use this rather than directly changing var/dizziness +since this ensures that the dizzy_process proc is started +currently only humans get dizzy + +value of dizziness ranges from 0 to 1000 +below 100 is not dizzy +*/ + +/mob/var/dizziness = 0//Carbon +/mob/var/is_dizzy = 0 + +/mob/proc/make_dizzy(var/amount) + if(!istype(src, /mob/living/carbon/human)) // for the moment, only humans get dizzy + return + + dizziness = min(1000, dizziness + amount) // store what will be new value + // clamped to max 1000 + if(dizziness > 100 && !is_dizzy) + spawn(0) + dizzy_process() + + +/* +dizzy process - wiggles the client's pixel offset over time +spawned from make_dizzy(), will terminate automatically when dizziness gets <100 +note dizziness decrements automatically in the mob's Life() proc. +*/ +/mob/proc/dizzy_process() + is_dizzy = 1 + while(dizziness > 100) + if(client) + var/amplitude = dizziness*(sin(dizziness * 0.044 * world.time) + 1) / 70 + client.pixel_x = amplitude * sin(0.008 * dizziness * world.time) + client.pixel_y = amplitude * cos(0.008 * dizziness * world.time) + + sleep(1) + //endwhile - reset the pixel offsets to zero + is_dizzy = 0 + if(client) + client.pixel_x = 0 + client.pixel_y = 0 + +// jitteriness - copy+paste of dizziness +/mob/var/is_jittery = 0 +/mob/var/jitteriness = 0//Carbon + +/mob/proc/make_jittery(var/amount) + return //Only for living/carbon/human/ + +/mob/living/carbon/human/make_jittery(var/amount) + if(!istype(src, /mob/living/carbon/human)) // for the moment, only humans get jittery + return + if(!jittery_damage()) + return //Robotic hearts don't get jittery. + jitteriness = min(1000, jitteriness + amount) // store what will be new value + // clamped to max 1000 + if(jitteriness > 100 && !is_jittery) + spawn(0) + jittery_process() + +// Typo from the original coder here, below lies the jitteriness process. So make of his code what you will, the previous comment here was just a copypaste of the above. +/mob/proc/jittery_process() + is_jittery = 1 + while(jitteriness > 100) + var/amplitude = min(4, jitteriness / 100) + pixel_x = default_pixel_x + rand(-amplitude, amplitude) + pixel_y = default_pixel_y + rand(-amplitude/3, amplitude/3) + + sleep(1) + //endwhile - reset the pixel offsets to zero + is_jittery = 0 + pixel_x = default_pixel_x + pixel_y = default_pixel_y + + +//handles up-down floaty effect in space and zero-gravity +/mob/var/is_floating = 0 +/mob/var/floatiness = 0 + +/mob/proc/update_floating() + + if(anchored || buckled || check_solid_ground()) + make_floating(0) + return + + if(Check_Shoegrip() && Check_Dense_Object()) + make_floating(0) + return + + make_floating(1) + return + +/mob/proc/make_floating(var/n) + floatiness = n + + if(floatiness && !is_floating) + start_floating() + else if(!floatiness && is_floating) + stop_floating() + +/mob/proc/start_floating() + + is_floating = 1 + + var/amplitude = 2 //maximum displacement from original position + var/period = 36 //time taken for the mob to go up >> down >> original position, in deciseconds. Should be multiple of 4 + + var/top = default_pixel_y + amplitude + var/bottom = default_pixel_y - amplitude + var/half_period = period / 2 + var/quarter_period = period / 4 + + animate(src, pixel_y = top, time = quarter_period, easing = SINE_EASING | EASE_OUT, loop = -1) //up + animate(pixel_y = bottom, time = half_period, easing = SINE_EASING, loop = -1) //down + animate(pixel_y = default_pixel_y, time = quarter_period, easing = SINE_EASING | EASE_IN, loop = -1) //back + +/mob/proc/stop_floating() + animate(src, pixel_y = default_pixel_y, time = 5, easing = SINE_EASING | EASE_IN) //halt animation + //reset the pixel offsets to zero + is_floating = 0 + +/atom/movable/proc/do_attack_animation(atom/A) + + var/pixel_x_diff = 0 + var/pixel_y_diff = 0 + var/direction = get_dir(src, A) + switch(direction) + if(NORTH) + pixel_y_diff = 8 + if(SOUTH) + pixel_y_diff = -8 + if(EAST) + pixel_x_diff = 8 + if(WEST) + pixel_x_diff = -8 + if(NORTHEAST) + pixel_x_diff = 8 + pixel_y_diff = 8 + if(NORTHWEST) + pixel_x_diff = -8 + pixel_y_diff = 8 + if(SOUTHEAST) + pixel_x_diff = 8 + pixel_y_diff = -8 + if(SOUTHWEST) + pixel_x_diff = -8 + pixel_y_diff = -8 + + var/default_pixel_x = initial(pixel_x) + var/default_pixel_y = initial(pixel_y) + var/mob/mob = src + if(istype(mob)) + default_pixel_x = mob.default_pixel_x + default_pixel_y = mob.default_pixel_y + + animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, time = 2) + animate(pixel_x = default_pixel_x, pixel_y = default_pixel_y, time = 2) + +/mob/do_attack_animation(atom/A) + ..() + return//Remove this to make item attack animations appear again. + /* + is_floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure we restart the bouncing after the next movement. + + // What icon do we use for the attack? + var/image/I + if(hand && l_hand) // Attacked with item in left hand. + I = image(l_hand.icon, A, l_hand.icon_state, A.layer + 1) + else if (!hand && r_hand) // Attacked with item in right hand. + I = image(r_hand.icon, A, r_hand.icon_state, A.layer + 1) + else // Attacked with a fist? + return + + // Who can see the attack? + var/list/viewing = list() + for (var/mob/M in viewers(A)) + if (M.client) + viewing |= M.client + flick_overlay(I, viewing, 5) // 5 ticks/half a second + + // Scale the icon. + I.transform *= 0.75 + // Set the direction of the icon animation. + var/direction = get_dir(src, A) + if(direction & NORTH) + I.pixel_y = -16 + else if(direction & SOUTH) + I.pixel_y = 16 + + if(direction & EAST) + I.pixel_x = -16 + else if(direction & WEST) + I.pixel_x = 16 + + if(!direction) // Attacked self?! + I.pixel_z = 16 + + // And animate the attack! + animate(I, alpha = 175, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3) + */ + +/mob/proc/spin(spintime, speed) + spawn() + var/D = dir + while(spintime >= speed) + sleep(speed) + switch(D) + if(NORTH) + D = EAST + if(SOUTH) + D = WEST + if(EAST) + D = SOUTH + if(WEST) + D = NORTH + set_dir(D) + spintime -= speed + return + +/mob/proc/phase_in(var/turf/T) + if(!T) + return + + playsound(T, 'sound/effects/phasein.ogg', 25, 1) + playsound(T, 'sound/effects/sparks2.ogg', 50, 1) + anim(T,src,'icons/mob/mob.dmi',,"phasein",,dir) + +/mob/proc/phase_out(var/turf/T) + if(!T) + return + playsound(T, "sparks", 50, 1) + anim(T,src,'icons/mob/mob.dmi',,"phaseout",,dir) + +/mob/proc/waddle() + if(!isliving(src)) + return + var/mob/living/L = src + if(!istype(L) || L.incapacitated() || L.lying) + return + animate(L, pixel_z = 4, time = 0) + animate(pixel_z = 0, transform = turn(matrix(), pick(-12, 0, 12)), time=2) + animate(pixel_z = 0, transform = matrix(), time = 0) diff --git a/code/modules/mob/datum_stats_skills.dm b/code/modules/mob/datum_stats_skills.dm new file mode 100644 index 00000000..a62b7237 --- /dev/null +++ b/code/modules/mob/datum_stats_skills.dm @@ -0,0 +1,339 @@ +//DATUM BASED SKILL SYSTEM +//HIJACKS ORANGE'S SKILL AND STAT SYSTEM +//Doesn't change the math at all just makes stats and skills a datum for easier use. +//To add a new stat or skill just define one and set it's variabls, it will be automatically added to the mob. + +//to check stat level use mymob.STAT_LEVEL(example_stat) +//for skills it's mymob.SKILL_LEVEL(example_skill) + +//For getting stats there is also mymob.GET_STAT(example_stat) +//and mymob.GET_SKILL(example_skill) +//But you probably won't use those. + +//Holders +/mob + var/list/my_skills = list() + var/list/my_stats = list() + +//Skill defines +/datum/skill + var/name = "My Skill" + var/level = 0//What the value is, used in skill checks + var/xp = 0//What the level is, used for leveling up the skill to the next rank. + var/level_up_req = 100 + +//Stat defines +/datum/stat + var/name = "My Stat" + var/level = 10//Its level, used in stat calculations. + var/shorthand = "sh"//Shorthand + +//Stats +/datum/stat/str + name = "Strength" + shorthand = "ST" + +/datum/stat/dex + name = "Dexterity" + shorthand = "DX" + +/datum/stat/end + name = "Endurance" + shorthand = "ED" + +/datum/stat/int + name = "Intelligence" + shorthand = "IT" + + +//Skills these can probably go in their own file +/datum/skill/melee + name = "melee" + +/datum/skill/ranged + name = "ranged" + +/datum/skill/medical + name = "medicine" + +/datum/skill/engineering + name = "engineering" + +/datum/skill/surgery + name = "surgery" + +//Gun skills. +/datum/skill/auto_rifle + name = "automatic rifles" + +/datum/skill/semi_rifle + name = "semi auto rifles" + +/datum/skill/sniper + name = "sniper rifles" + +/datum/skill/shotgun + name = "shotguns" + +/datum/skill/lmg + name = "machine guns" + +/datum/skill/smg + name = "SMGs" + + +//Initalization +/mob/living/carbon/human/proc/init_skills() + for(var/thing in init_subtypes(/datum/skill))//subtypes init magic I don't know ask Kyrah about it + var/datum/skill/S = thing + my_skills[S.type] = S + +/mob/living/carbon/human/proc/init_stats() + for(var/thing in init_subtypes(/datum/stat)) + var/datum/stat/S = thing + my_stats[S.type] = S + + +//boosters and setters, not really used at the moment. +/datum/stat/proc/boost_stat(var/num, var/time) + level += num + if(time) + spawn(time) + level -= num + +/datum/stat/proc/reduce_stat(var/num, var/time) + level -= num + if(time) + spawn(time) + level += num + +/datum/stat/proc/set_stat(var/num) + level = num + +//Now for skills +/datum/skill/proc/boost_skill(var/num, var/time) + level += num + if(time) + spawn(time) + level -= num + +/datum/skill/proc/reduce_skill(var/num, var/time) + level -= num + if(time) + spawn(time) + level += num + +/datum/skill/proc/set_skill(var/num) + level = num + +//Leveling up a skill +/datum/skill/proc/give_xp(var/amount, var/mob/user) + xp += amount + to_chat(user, "I have learned more about [src.name]!") + attempt_level_up(user) + + +/datum/skill/proc/attempt_level_up(var/mob/user) + if(xp == level_up_req) + level++ + to_chat(user,"My level of knowledge about [src.name] has increased!") + + +//Checking skills +/mob/living/carbon/human/proc/check_skills() + set name = "Check Skills" + set category = "IC" + var/message = "Skills:\n" + for(var/type in my_skills) + var/datum/skill/S = my_skills[type] + if(S.level) + message += "I am [skillnumtodesc(S.level)] at [S.name].\n" + else + message += "I have no knowledge of [S.name].\n" + to_chat(src, message) + +//Use this proc to add stats to the jobs, it will add up on default values, keep that in mind +/mob/living/carbon/human/proc/add_stats(var/strength, var/dexterity, var/endurance, var/intelligence)//TODO: Make this more atomic. + if(strength) + STAT_LEVEL(str) = strength + if(has_quirk(/datum/quirk/weak)) + STAT_LEVEL(str) -= 2 + if(has_quirk(/datum/quirk/strong)) + STAT_LEVEL(str) += 2 + if(dexterity) + STAT_LEVEL(dex) = dexterity + if(endurance) + STAT_LEVEL(end) = endurance + if(intelligence) + STAT_LEVEL(int) = intelligence + updateweight() + +//same thing but for skills +/mob/living/carbon/human/proc/add_skills(var/melee, var/ranged, var/medical, var/engineering, var/surgery) + if(melee) + SKILL_LEVEL(melee) = melee + if(ranged) + SKILL_LEVEL(ranged) = ranged + if(medical) + SKILL_LEVEL(medical) = medical + if(engineering) + SKILL_LEVEL(engineering) = engineering + if(surgery) + SKILL_LEVEL(surgery) = surgery + + +///Modifiers/// +//Converts mood level into number for the modifier +/mob/living/carbon/human/proc/mood() + switch(happiness) + if(-5000000 to MOOD_LEVEL_SAD4) + return -4 + if(MOOD_LEVEL_SAD4 to MOOD_LEVEL_SAD3) + return -3 + if(MOOD_LEVEL_SAD3 to MOOD_LEVEL_SAD2) + return -2 + if(MOOD_LEVEL_SAD2 to MOOD_LEVEL_SAD1) + return -1 + if(MOOD_LEVEL_SAD1 to MOOD_LEVEL_HAPPY1) + return 1 + if(MOOD_LEVEL_HAPPY1 to MOOD_LEVEL_HAPPY2) + return 2 + if(MOOD_LEVEL_HAPPY2 to MOOD_LEVEL_HAPPY3) + return 3 + else + return 4 + +//Converts stamina level into number for the modifier +/mob/living/carbon/human/proc/fatigue() + switch(staminaloss) + if(0) + return 2 + if(1 to 20) + return 0 + if(21 to 40) + return -1 + if(41 to 60) + return -2 + if(61 to 80) + return -3 + if(81 to 100) + return -4 + else + return -5 + +//Add this to the action and specify what will happen in each outcome.// +//Important! you should not use more than one stat in proc but if you really want to, you should multiply amount of dices and crit according to how much of them you added to the formula// +//For example: two stats will need 6d6 dicetype and also 20 crit instead of 10// +//REMEMBER THIS: when adding proc to action you BOUND to specify SUCCESS and CRIT_FAILURE in it! FAILURE may do nothing and CRIT_SUCCESS may be same as SUCCESS though// +/mob/living/carbon/human/proc/statscheck(var/stats = 0, var/skills = 0, var/dicetype = "3d6", var/crit = 10, var/mod = 0) + var/dice = roll(dicetype) + var/modifier = mood() + fatigue() + mod + var/sum = stats + skills * 2 + modifier + + if(chem_effects[CE_PAINKILLER] > 100)//Being high on pain pills will fuck up your rolls. + sum += 5 + + if(is_hellbanned())//Being hellbanned fucks with you. + sum += 5 + + if(dice <= sum) + if(dice <= sum - crit || dice <= 4) + return CRIT_SUCCESS + else + return SUCCESS + else + if(dice >= sum + crit || dice >= 17) + return CRIT_FAILURE + else + return FAILURE + +//helpers +proc/skillnumtodesc(var/skill) + switch(skill) + if(1) + return "completely worthless" + if(2) + return "incompetent" + if(3) + return "a novice" + if(4) + return "unskilled" + if(5) + return "good enough" + if(6) + return "adept" + if(7) + return "versed" + if(8) + return FONT_LARGE("an expert") + if(9) + return FONT_LARGE("a master") + if(10) + return FONT_LARGE("legendary") + if(skill > 10) + return "inhuman" + +proc/backwards_skill_scale(var/skill) + if(0) + return 10 + if(1) + return 9 + if(2) + return 8 + if(3) + return 7 + if(4) + return 6 + if(5) + return 5 + if(6) + return 4 + if(7) + return 3 + if(8) + return 2 + else + return 1 + +proc/dexToAccuracyModifier(var/dexterity) + return dexterity - 10 + +proc/strToDamageModifier(var/strength) + return strength * 0.1 + +proc/endToStaminaModifier(var/endurance) + return (endurance - 10) * 15 + +proc/strToSpeedModifier(var/strength, var/w_class)// + switch(strength) + if(1 to 5) + if(w_class > ITEM_SIZE_NORMAL) + return 20 + + if(6 to 11) + if(w_class > ITEM_SIZE_NORMAL) + return 15 + + if(12 to 15) + if(w_class > ITEM_SIZE_NORMAL) + return 10 + + if(16 to INFINITY) + if(w_class > ITEM_SIZE_NORMAL) + return 5 + +//Unimplemented, unused. +/* +/mob/living/carbon/human/proc/set_stats(var/list/args) + var/i + for(i=1,i<=args.len,i++) + var/type = args[i] + var/value = args[type] + my_stats[type].level = value + updateweight() + +set_stats(list(STAT(str) = rand(6,9), STAT(dex) = rand(8,12),STAT(dex) = rand(5,8), rand(8,12))) +*/ + + + diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm new file mode 100644 index 00000000..a7d75746 --- /dev/null +++ b/code/modules/mob/death.dm @@ -0,0 +1,113 @@ +//This is the proc for gibbing a mob. Cannot gib ghosts. +//added different sort of gibs and animations. N +/mob/proc/gib(anim="gibbed-m",do_gibs) + death(1) + transforming = 1 + canmove = 0 + icon = null + set_invisibility(101) + update_canmove() + remove_from_dead_mob_list() + + var/atom/movable/overlay/animation = null + animation = new(loc) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = src + + flick(anim, animation) + if(do_gibs) gibs(loc, dna) + + spawn(15) + if(animation) qdel(animation) + if(src) qdel(src) + +//This is the proc for turning a mob into ash. Mostly a copy of gib code (above). +//Originally created for wizard disintegrate. I've removed the virus code since it's irrelevant here. +//Dusting robots does not eject the MMI, so it's a bit more powerful than gib() /N +/mob/proc/dust(anim="dust-m",remains=/obj/effect/decal/cleanable/ash) + death(1) + var/atom/movable/overlay/animation = null + transforming = 1 + canmove = 0 + icon = null + set_invisibility(101) + + animation = new(loc) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = src + + flick(anim, animation) + new remains(loc) + + remove_from_dead_mob_list() + spawn(15) + if(animation) qdel(animation) + if(src) qdel(src) + + +/mob/proc/death(gibbed,deathmessage="seizes up and falls limp...", show_dead_message = "You have died.") + + if(stat == DEAD) + return 0 + + facing_dir = null + + if(!gibbed && deathmessage != "no message") // This is gross, but reliable. Only brains use it. + src.visible_message("\The [src.name] [deathmessage]") + + set_stat(DEAD) + reset_plane_and_layer() + update_canmove() + + dizziness = 0 + jitteriness = 0 + + set_sight(sight|SEE_TURFS|SEE_MOBS|SEE_OBJS) + set_see_in_dark(8) + set_see_invisible(SEE_INVISIBLE_LEVEL_TWO) + + drop_r_hand() + drop_l_hand() + + //TODO: Change death state to health_dead for all these icon files. This is a stop gap. + + if(healths) + healths.overlays = null // This is specific to humans but the relevant code is here; shouldn't mess with other mobs. + if("health7" in icon_states(healths.icon)) + healths.icon_state = "health7" + else + healths.icon_state = "health6" + log_debug("[src] ([src.type]) died but does not have a valid health7 icon_state (using health6 instead). report this error to Ccomp5950 or your nearest Developer") + + timeofdeath = world.time + if(mind) mind.store_memory("Time of death: [stationtime2text()]", 0) + switch_from_living_to_dead_mob_list() + + update_icon() + + if(ticker && ticker.mode) + ticker.mode.check_win() + to_chat(src,"[show_dead_message]") + if(iswarfare())//Only for warfare bullshit. + to_chat(src, "Once you ghost you will be able to respawn in [config.warfare_respawn_time] minutes.") + + /* + if(client) // the following is ported from r4407 + var/cancel = 0 //It is commented out for now. Only to be used for very specific gamemodes that need to end when everyone is dead. + for(var/mob/living/carbon/human/H in GLOB.player_list) + if(!H.stat) + cancel = 1 + break + if(!cancel) + to_world("Everyone has died, restarting world in 30 seconds.") + log_world("Everyone has died, restarting world in 30 seconds.") + spawn(270) + to_world("Restarting...") + log_world("Restarting...") + spawn(30) + log_admin("Restarting world, all players have died.") + world.Reboot("All players have died.") + */ + return 1 diff --git a/code/modules/mob/gender.dm b/code/modules/mob/gender.dm new file mode 100644 index 00000000..393e0fb6 --- /dev/null +++ b/code/modules/mob/gender.dm @@ -0,0 +1,56 @@ + +/var/list/gender_datums = list() + +/hook/startup/proc/populate_gender_datum_list() + for(var/type in typesof(/datum/gender)) + var/datum/gender/G = new type + gender_datums[G.key] = G + return 1 + +/datum/gender + var/key = "plural" + + var/He = "They" + var/he = "they" + var/His = "Their" + var/his = "their" + var/him = "them" + var/has = "have" + var/is = "are" + var/does = "do" + +/datum/gender/male + key = "male" + + He = "He" + he = "he" + His = "His" + his = "his" + him = "him" + has = "has" + is = "is" + does = "does" + +/datum/gender/female + key = "female" + + He = "She" + he = "she" + His = "Her" + his = "her" + him = "her" + has = "has" + is = "is" + does = "does" + +/datum/gender/neuter + key = "neuter" + + He = "It" + he = "it" + His = "Its" + his = "its" + him = "it" + has = "has" + is = "is" + does = "does" diff --git a/code/modules/mob/grab/grab_datum.dm b/code/modules/mob/grab/grab_datum.dm new file mode 100644 index 00000000..6f02f68c --- /dev/null +++ b/code/modules/mob/grab/grab_datum.dm @@ -0,0 +1,304 @@ +/datum/grab + + var/type_name + var/state_name + var/fancy_desc + + var/datum/grab/upgrab // The grab that this will upgrade to if it upgrades, null means no upgrade + var/datum/grab/downgrab // The grab that this will downgrade to if it downgrades, null means break grab on downgrade + + var/datum/time_counter // For things that need to be timed + + var/stop_move = 0 // Whether or not the grabbed person can move out of the grab + var/force_stand = 0 // Whether or not the grabbed person is forced to be standing + var/reverse_facing = 0 // Whether the person being grabbed is facing forwards or backwards. + var/can_absorb = 0 // Whether this grab state is strong enough to, as a changeling, absorb the person you're grabbing. + var/shield_assailant = 0 // Whether the person you're grabbing will shield you from bullets.,, + var/point_blank_mult = 1 // How much the grab increases point blank damage. + var/same_tile = 0 // If the grabbed person and the grabbing person are on the same tile. + var/ladder_carry = TRUE // If the grabber can carry the grabbed person up or down ladders. + var/can_throw = TRUE // If the grabber can throw the person grabbed. + var/downgrade_on_action = 0 // If the grab needs to be downgraded when the grabber does stuff. + var/downgrade_on_move = 0 // If the grab needs to be downgraded when the grabber moves. + var/force_danger = 0 // If the grab is strong enough to be able to force someone to do something harmful to them. + var/restrains = 0 // If the grab acts like cuffs and prevents action from the victim. + + var/grab_slowdown = 7 + + var/shift = 0 + + var/success_up = "You upgrade the grab." + var/success_down = "You downgrade the grab." + + var/fail_up = "You fail to upgrade the grab." + var/fail_down = "You fail to downgrade the grab." + + var/upgrab_name + var/downgrab_name + + var/icon + var/icon_state + + var/upgrade_cooldown = 40 + var/action_cooldown = 40 + + var/can_downgrade_on_resist = 1 + var/list/break_chance_table = list(100) + var/breakability = 2 + + // The names of different intents for use in attack logs + var/help_action = "help intent" + var/disarm_action = "disarm intent" + var/grab_action = "grab intent" + var/harm_action = "harm intent" + var/activate_effect = TRUE + +/* + These procs shouldn't be overriden in the children unless you know what you're doing with them; they handle important core functions. + Even if you do override them, you should likely be using ..() if you want the behaviour to function properly. That is, of course, + unless you're writing your own custom handling of things. +*/ + +/datum/grab/proc/refresh_updown() + if(upgrab_name) + upgrab = all_grabstates[upgrab_name] + + if(downgrab_name) + downgrab = all_grabstates[downgrab_name] + +// This is for the strings defined as datum variables. It takes them and swaps out keywords for relevent ones from the grab +// object involved. +/datum/grab/proc/string_process(var/obj/item/grab/G, var/to_write, var/obj/item/used_item) + to_write = replacetext(to_write, "rep_affecting", G.affecting) + to_write = replacetext(to_write, "rep_assailant", G.assailant) + if(used_item) + to_write = replacetext(to_write, "rep_item", used_item) + return to_write + +/datum/grab/proc/upgrade(var/obj/item/grab/G) + if(!upgrab) + return + + if (can_upgrade(G)) + upgrade_effect(G) + admin_attack_log(G.assailant, G.affecting, "tightens their grip on their victim to [upgrab.state_name]", "was grabbed more tightly to [upgrab.state_name]", "tightens grip to [upgrab.state_name] on") + return upgrab + else + to_chat(G.assailant, "[string_process(G, fail_up)]") + return + +/datum/grab/proc/downgrade(var/obj/item/grab/G) + // Starts the process of letting go if there's no downgrade grab + if(can_downgrade()) + downgrade_effect(G) + return downgrab + else + to_chat(G.assailant, "[string_process(G, fail_down)]") + return + +/datum/grab/proc/let_go(var/obj/item/grab/G) + let_go_effect(G) + G.force_drop() + +/datum/grab/proc/process(var/obj/item/grab/G) + var/diff_zone = G.target_change() + if(diff_zone && G.special_target_functional) + special_target_change(G, diff_zone) + else + special_target_effect(G) + + if(activate_effect) + process_effect(G) + +/datum/grab/proc/throw_held(var/obj/item/grab/G) + var/mob/living/carbon/human/affecting = G.affecting + + if(can_throw) + animate(affecting, pixel_x = 0, pixel_y = 0, 4, 1) + qdel(G) + return affecting + return null + +/datum/grab/proc/hit_with_grab(var/obj/item/grab/G) + if(downgrade_on_action) + G.downgrade() + + if(G.check_action_cooldown() && !G.attacking) + var/intent = G.assailant.a_intent + switch(intent) + + if(I_HELP) + if(on_hit_help(G)) + G.action_used() + make_log(G, help_action) + + if(I_DISARM) + if(on_hit_disarm(G)) + G.action_used() + make_log(G, disarm_action) + + if(I_GRAB) + if(on_hit_grab(G)) + G.action_used() + make_log(G, grab_action) + + if(I_HURT) + if(on_hit_harm(G)) + G.action_used() + make_log(G, harm_action) + + else + to_chat(G.assailant, "You must wait before you can do that.") + +/datum/grab/proc/make_log(var/obj/item/grab/G, var/action) + admin_attack_log(G.assailant, G.affecting, "[action]s their victim", "was [action]ed", "used [action] on") + + +/datum/grab/proc/adjust_position(var/obj/item/grab/G) + var/mob/living/carbon/human/affecting = G.affecting + var/mob/living/carbon/human/assailant = G.assailant + var/adir = get_dir(assailant, affecting) + + if(same_tile) + affecting.forceMove(assailant.loc) + adir = assailant.dir + affecting.set_dir(assailant.dir) + + switch(adir) + if(NORTH) + animate(affecting, pixel_x = 0, pixel_y =-shift, 5, 1, LINEAR_EASING) + G.draw_affecting_under() + if(SOUTH) + animate(affecting, pixel_x = 0, pixel_y = shift, 5, 1, LINEAR_EASING) + G.draw_affecting_over() + if(WEST) + animate(affecting, pixel_x = shift, pixel_y = 0, 5, 1, LINEAR_EASING) + G.draw_affecting_under() + if(EAST) + animate(affecting, pixel_x =-shift, pixel_y = 0, 5, 1, LINEAR_EASING) + G.draw_affecting_under() + + affecting.reset_plane_and_layer() + +/datum/grab/proc/reset_position(var/obj/item/grab/G) + var/mob/living/carbon/human/affecting = G.affecting + + if(!affecting.buckled) + animate(affecting, pixel_x = 0, pixel_y = 0, 4, 1, LINEAR_EASING) + affecting.reset_plane_and_layer() + +// This is called whenever the assailant moves. +/datum/grab/proc/assailant_moved(var/obj/item/grab/G) + adjust_position(G) + moved_effect(G) + if(downgrade_on_move) + G.downgrade() + +/* + Override these procs to set how the grab state will work. Some of them are best + overriden in the parent of the grab set (for example, the behaviour for on_hit_intent(var/obj/item/grab/G) + procs is determined in /datum/grab/normal and then inherited by each intent). +*/ + +// What happens when you upgrade from one grab state to the next. +/datum/grab/proc/upgrade_effect(var/obj/item/grab/G) + +// Conditions to see if upgrading is possible +/datum/grab/proc/can_upgrade(var/obj/item/grab/G) + return 1 + +// What happens when you downgrade from one grab state to the next. +/datum/grab/proc/downgrade_effect(var/obj/item/grab/G) + +// Conditions to see if downgrading is possible +/datum/grab/proc/can_downgrade(var/obj/item/grab/G) + return 1 + +// What happens when you let go of someone by either dropping the grab +// or by downgrading from the lowest grab state. +/datum/grab/proc/let_go_effect(var/obj/item/grab/G) + +// What happens each tic when process is called. +/datum/grab/proc/process_effect(var/obj/item/grab/G) + +// Handles special targeting like eyes and mouth being covered. +/datum/grab/proc/special_target_effect(var/obj/item/grab/G) + +// Handles when they change targeted areas and something is supposed to happen. +/datum/grab/proc/special_target_change(var/obj/item/grab/G, var/diff_zone) + +// Checks if the special target works on the grabbed humanoid. +/datum/grab/proc/check_special_target(var/obj/item/grab/G) + +// What happens when you hit the grabbed person with the grab on help intent. +/datum/grab/proc/on_hit_help(var/obj/item/grab/G) + return 1 + +// What happens when you hit the grabbed person with the grab on disarm intent. +/datum/grab/proc/on_hit_disarm(var/obj/item/grab/G) + return 1 + +// What happens when you hit the grabbed person with the grab on grab intent. +/datum/grab/proc/on_hit_grab(var/obj/item/grab/G) + return 1 + +// What happens when you hit the grabbed person with the grab on harm intent. +/datum/grab/proc/on_hit_harm(var/obj/item/grab/G) + return 1 + +// What happens when you hit the grabbed person with an open hand and you want it +// to do some special snowflake action based on some other factor such as +// intent. +/datum/grab/proc/resolve_openhand_attack(var/obj/item/grab/G) + return 0 + +// Used when you want an effect to happen when the grab enters this state as an upgrade +/datum/grab/proc/enter_as_up(var/obj/item/grab/G) + +/datum/grab/proc/item_attack(var/obj/item/grab/G, var/obj/item) + +/datum/grab/proc/resolve_item_attack(var/obj/item/grab/G, var/mob/living/carbon/human/user, var/obj/item/I, var/target_zone) + return 0 + +/datum/grab/proc/handle_resist(var/obj/item/grab/G) + var/mob/living/carbon/human/affecting = G.affecting + var/mob/living/carbon/human/assailant = G.assailant + + if(affecting.incapacitated(INCAPACITATION_KNOCKOUT | INCAPACITATION_STUNNED)) + to_chat(G.assailant, "You can't resist in your current state!") + + var/break_strength = breakability + size_difference(affecting, assailant) + + if(affecting.incapacitated(INCAPACITATION_ALL)) + break_strength-- + if(affecting.confused) + break_strength-- + + if(break_strength < 1) + to_chat(G.assailant, "You try to break free but feel that unless something changes, you'll never escape!") + return + + var/break_chance = break_chance_table[Clamp(break_strength, 1, break_chance_table.len)] + if(prob(break_chance)) + if(can_downgrade_on_resist && !prob((break_chance+100)/2)) + affecting.visible_message("[affecting] has loosened [assailant]'s grip!") + G.downgrade() + return + else + affecting.visible_message("[affecting] has broken free of [assailant]'s grip!") + let_go(G) + +/datum/grab/proc/size_difference(mob/A, mob/B) + return mob_size_difference(A.mob_size, B.mob_size) + +/datum/grab/proc/moved_effect(var/obj/item/grab/G) + +/client/proc/Process_Grab() + //if we are being grabbed + if(isliving(mob)) + var/mob/living/L = mob + if(!L.canmove && L.grabbed_by.len) + L.resist() //shortcut for resisting grabs + +/datum/grab/proc/attack_self_act(var/obj/item/grab/G) + return \ No newline at end of file diff --git a/code/modules/mob/grab/grab_object.dm b/code/modules/mob/grab/grab_object.dm new file mode 100644 index 00000000..da41f2ad --- /dev/null +++ b/code/modules/mob/grab/grab_object.dm @@ -0,0 +1,251 @@ + +/obj/item/grab + name = "grab" + + var/mob/living/carbon/human/affecting = null + var/mob/living/carbon/human/assailant = null + + var/datum/grab/current_grab + var/type_name + var/start_grab_name + + var/last_action + var/last_upgrade + + var/last_target + var/special_target_functional = 1 + + var/attacking = 0 + var/target_zone + + w_class = ITEM_SIZE_NO_CONTAINER + + atom_flags = ATOM_FLAG_NO_BLOOD +/* + This section is for overrides of existing procs. +*/ +/obj/item/grab/New(mob/living/carbon/human/attacker, mob/living/carbon/human/victim) + ..() + + assailant = attacker + affecting = victim + target_zone = attacker.zone_sel.selecting + var/obj/item/O = get_targeted_organ() + SetName("[name] ([O.name])") + + if(start_grab_name) + current_grab = all_grabstates[start_grab_name] + +/obj/item/grab/examine(var/user) + ..() + var/obj/item/O = get_targeted_organ() + to_chat(user,"A grab on \the [affecting]'s [O.name].") + +/obj/item/grab/Process() + current_grab.process(src) + +/obj/item/grab/attack_self(mob/user) + current_grab.attack_self_act(src) + /* + switch(assailant.a_intent) + if(I_HELP) + downgrade() + else + upgrade() + */ + +/obj/item/grab/attack(mob/M, mob/living/user) + current_grab.hit_with_grab(src) + +/obj/item/grab/dropped() + ..() + loc = null + if(!QDELETED(src)) + qdel(src) + +/obj/item/grab/Destroy() + if(affecting) + reset_position() + affecting.grabbed_by -= src + affecting.reset_plane_and_layer() + affecting = null + if(assailant) + assailant = null + return ..() + +/* + This section is for newly defined useful procs. +*/ +/obj/item/grab/proc/target_change() + var/hit_zone = assailant.zone_sel.selecting + if(src != assailant.get_active_hand()) + return 0 + if(hit_zone && hit_zone != last_target) + last_target = hit_zone + special_target_functional = current_grab.check_special_target(src) + return hit_zone + else + return 0 + + +/obj/item/grab/proc/force_drop() + assailant.drop_from_inventory(src) + +/obj/item/grab/proc/can_grab() + + if(assailant.anchored || affecting.anchored) + return 0 + + if(!assailant.Adjacent(affecting)) + return 0 + + for(var/obj/item/grab/G in affecting.grabbed_by) + if(G.assailant == assailant && G.target_zone == target_zone) + var/obj/O = G.get_targeted_organ() + to_chat(assailant, "You already grabbed [affecting]'s [O.name].") + return 0 + + return 1 + +// This is for all the sorts of things that need to be checked for pretty much every +// grab made. Feel free to override it but it stops a lot of situations that could +// cause runtimes so be careful with it. +/obj/item/grab/proc/pre_check() + + if(!assailant || !affecting) + return 0 + + if(assailant == affecting) + to_chat(assailant, "You can't grab yourself.") + return 0 + + if(assailant.get_active_hand()) + to_chat(assailant, "You can't grab someone if your hand is full.") + return 0 + + if(assailant.grabbed_by.len) + to_chat(assailant, "You can't grab someone if you're being grabbed.") + return 0 + + return 1 + +/obj/item/grab/proc/init() + last_target = assailant.zone_sel.selecting + affecting.update_canmove() + adjust_position() + update_icons() + action_used() + +// Returns the organ of the grabbed person that the grabber is targeting +/obj/item/grab/proc/get_targeted_organ() + return (affecting.get_organ(target_zone)) + +/obj/item/grab/proc/resolve_item_attack(var/mob/living/M, var/obj/item/I, var/target_zone) + if((M && ishuman(M)) && I) + return current_grab.resolve_item_attack(src, M, I, target_zone) + else + return 0 + +/obj/item/grab/proc/action_used() + last_action = world.time + +/obj/item/grab/proc/check_action_cooldown() + return (world.time >= last_action + current_grab.action_cooldown) + +/obj/item/grab/proc/check_upgrade_cooldown() + return (world.time >= last_upgrade + current_grab.upgrade_cooldown) + +/obj/item/grab/proc/upgrade(var/bypass_cooldown = FALSE) + if(!check_upgrade_cooldown() && !bypass_cooldown) + to_chat(assailant, "It's too soon to upgrade.") + return + + var/datum/grab/upgrab = current_grab.upgrade(src) + if(upgrab) + current_grab = upgrab + last_upgrade = world.time + adjust_position() + update_icons() + current_grab.enter_as_up(src) + +/obj/item/grab/proc/downgrade() + var/datum/grab/downgrab = current_grab.downgrade(src) + if(downgrab) + current_grab = downgrab + update_icons() + +/obj/item/grab/proc/update_icons() + if(current_grab.icon) + icon = current_grab.icon + if(current_grab.icon_state) + icon_state = current_grab.icon_state + +/obj/item/grab/proc/draw_affecting_over() + affecting.plane = assailant.plane + affecting.layer = assailant.layer + 0.01 + +/obj/item/grab/proc/draw_affecting_under() + affecting.plane = assailant.plane + affecting.layer = assailant.layer - 0.01 + + +/obj/item/grab/proc/throw_held() + return current_grab.throw_held(src) + +/obj/item/grab/proc/handle_resist() + current_grab.handle_resist(src) + +/obj/item/grab/proc/adjust_position(var/force = 0) + if(force) affecting.forceMove(assailant.loc) + + if(!assailant || !affecting || !assailant.Adjacent(affecting)) + qdel(src) + return 0 + else + current_grab.adjust_position(src) + +/obj/item/grab/proc/reset_position() + current_grab.reset_position(src) + +/* + This section is for the simple procs used to return things from current_grab. +*/ +/obj/item/grab/proc/stop_move() + return current_grab.stop_move + +/obj/item/grab/proc/force_stand() + return current_grab.force_stand + +/obj/item/grab/attackby(obj/W, mob/user) + if(user == assailant) + current_grab.item_attack(src, W) + +/obj/item/grab/proc/can_absorb() + return current_grab.can_absorb + +/obj/item/grab/proc/assailant_reverse_facing() + return current_grab.reverse_facing + +/obj/item/grab/proc/shield_assailant() + return current_grab.shield_assailant + +/obj/item/grab/proc/point_blank_mult() + return current_grab.point_blank_mult + +/obj/item/grab/proc/force_danger() + return current_grab.force_danger + +/obj/item/grab/proc/grab_slowdown() + return current_grab.grab_slowdown + +/obj/item/grab/proc/ladder_carry() + return current_grab.ladder_carry + +/obj/item/grab/proc/assailant_moved() + current_grab.assailant_moved(src) + +/obj/item/grab/proc/restrains() + return current_grab.restrains + +/obj/item/grab/proc/resolve_openhand_attack() + return current_grab.resolve_openhand_attack(src) \ No newline at end of file diff --git a/code/modules/mob/grab/grab_readme.dm b/code/modules/mob/grab/grab_readme.dm new file mode 100644 index 00000000..49aab41a --- /dev/null +++ b/code/modules/mob/grab/grab_readme.dm @@ -0,0 +1,30 @@ +/* +There's two parts to the grab system. There's the grab object: /obj/item/grab +and there's the grab datum: /datum/grab. + +Each grab datum is a singleton and the system interacts with the rest of the code +base through the grab object. Nothing but the grab object should be reading +from, writing to, or calling the procs of the grab datum. This helps to keep +everything neat and stops undesirable behaviours. + +Each type of grab needs a child of the grab datum and a child of the grab +object. The child of each needs to be named with the name of the grab and +the two need the same naming scheme. For example, the main type of grab +used by human is called "normal" as it's the default vanilla grab. The normal +grab has a child of the grab object called /obj/item/grab/normal and it has a child +of the grab datum called /datum/grab/normal. + +Each stage of the grab is a child of the grab datum for that grab type. For normal +there's /datum/grab/normal/passive, /datum/grab/normal/aggressive etc. and they +get their general behaviours from their parent /datum/grab/normal. + + + + + + + + + + +*/ diff --git a/code/modules/mob/grab/nab/grab_nab.dm b/code/modules/mob/grab/nab/grab_nab.dm new file mode 100644 index 00000000..97e81a23 --- /dev/null +++ b/code/modules/mob/grab/nab/grab_nab.dm @@ -0,0 +1,106 @@ +/obj/item/grab/nab + + type_name = GRAB_NAB + start_grab_name = NAB_PASSIVE + +/obj/item/grab/nab/init() + ..() + + if(affecting.w_uniform) + affecting.w_uniform.add_fingerprint(assailant) + + if(assailant.l_hand) assailant.unEquip(assailant.l_hand) + if(assailant.r_hand) assailant.unEquip(assailant.r_hand) + + assailant.put_in_active_hand(src) + assailant.do_attack_animation(affecting) + playsound(affecting.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + visible_message("[assailant] has nabbed [affecting] passively!") + affecting.grabbed_by += src + + +/datum/grab/nab + + type_name = GRAB_NAB + + icon = 'icons/mob/screen1.dmi' + + stop_move = 1 + force_stand = 1 + reverse_facing = 1 + can_absorb = 1 + shield_assailant = 1 + point_blank_mult = 1 + same_tile = 1 + ladder_carry = 1 + force_danger = 1 + +/datum/grab/nab/on_hit_grab(var/obj/item/grab/G) + var/mob/living/carbon/human/affecting = G.affecting + var/mob/living/carbon/human/assailant = G.assailant + + var/crush_damage = rand(8,14) + + affecting.visible_message("[assailant] begins crushing [affecting]!") + G.attacking = 1 + if(do_mob(assailant, affecting, action_cooldown - 1)) + G.attacking = 0 + G.action_used() + crush(G, crush_damage) + return 1 + else + G.attacking = 0 + affecting.visible_message("[assailant] stops crushing [affecting]!") + return 0 + +/datum/grab/nab/on_hit_harm(var/obj/item/grab/G) + var/mob/living/carbon/human/affecting = G.affecting + var/mob/living/carbon/human/assailant = G.assailant + + var/masticate_damage = rand(15,20) + + affecting.visible_message("[assailant] begins chewing on [affecting]!") + G.attacking = 1 + + if(do_mob(assailant, affecting, action_cooldown - 1)) + G.attacking = 0 + G.action_used() + masticate(G, masticate_damage) + return 1 + else + G.attacking = 0 + affecting.visible_message("[assailant] stops chewing on [affecting].") + return 0 + +// This causes the assailant to crush the affecting mob. There is a chance that the crush will cause the +// forelimb spikes to dig into the affecting mob, doing extra damage and likely causing them to bleed. +/datum/grab/nab/proc/crush(var/obj/item/grab/G, var/attack_damage) + var/obj/item/organ/external/damaging = G.get_targeted_organ() + var/hit_zone = G.target_zone + + var/armor = G.affecting.run_armor_check(hit_zone, "melee") + + G.affecting.visible_message("[G.assailant] crushes [G.affecting]'s [damaging.name]!") + + if(prob(30)) + G.affecting.apply_damage(max(attack_damage + 10, 15), BRUTE, hit_zone, armor, DAM_SHARP, "organic punctures") + G.affecting.apply_effect(attack_damage, PAIN, armor) + G.affecting.visible_message("[G.assailant]'s spikes dig in painfully!") + else + G.affecting.apply_damage(attack_damage, BRUTE, hit_zone, armor,, "crushing") + playsound(get_turf(G.assailant), 'sound/weapons/bite.ogg', 25, 1, -1) + + admin_attack_log(G.assailant, G.affecting, "Crushed their victim.", "Was crushed.", "crushed") + +// This causes the assailant to chew on the affecting mob. +/datum/grab/nab/proc/masticate(var/obj/item/grab/G, var/attack_damage) + var/hit_zone = G.assailant.zone_sel.selecting + var/obj/item/organ/external/damaging = G.affecting.get_organ(hit_zone) + + var/armor = G.affecting.run_armor_check(hit_zone, "melee") + + G.affecting.apply_damage(attack_damage, BRUTE, hit_zone, armor, DAM_SHARP|DAM_EDGE, "mandibles") + G.affecting.visible_message("[G.assailant] chews on [G.affecting]'s [damaging.name]!") + playsound(get_turf(G.assailant), 'sound/weapons/bite.ogg', 25, 1, -1) + + admin_attack_log(G.assailant, G.affecting, "Chews their victim.", "Was chewed.", "chewed") diff --git a/code/modules/mob/grab/nab/nab_aggressive.dm b/code/modules/mob/grab/nab/nab_aggressive.dm new file mode 100644 index 00000000..e088c18d --- /dev/null +++ b/code/modules/mob/grab/nab/nab_aggressive.dm @@ -0,0 +1,19 @@ +/datum/grab/nab/aggressive + state_name = NAB_AGGRESSIVE + + upgrab_name = NAB_KILL + downgrab_name = NAB_PASSIVE + + shift = -10 + + icon_state = "kill" + + break_chance_table = list(3, 18, 45, 100) + +/datum/grab/nab/aggressive/upgrade_effect(var/obj/item/grab/G) + process_effect(G) + +/datum/grab/nab/aggressive/process_effect(var/obj/item/grab/G) + var/mob/living/carbon/human/affecting = G.affecting + + affecting.Stun(3) \ No newline at end of file diff --git a/code/modules/mob/grab/nab/nab_kill.dm b/code/modules/mob/grab/nab/nab_kill.dm new file mode 100644 index 00000000..f1460ef5 --- /dev/null +++ b/code/modules/mob/grab/nab/nab_kill.dm @@ -0,0 +1,30 @@ +/datum/grab/nab/kill + state_name = NAB_KILL + + downgrab_name = NAB_AGGRESSIVE + + shift = -10 + + icon_state = "kill1" + + downgrade_on_action = 1 + downgrade_on_move = 1 + + breakability = 0 + + break_chance_table = list(3, 10, 20, 100) + +/datum/grab/nab/kill/upgrade_effect(var/obj/item/grab/G) + process_effect(G) + +/datum/grab/nab/kill/process_effect(var/obj/item/grab/G) + var/mob/living/carbon/human/assailant = G.assailant + var/mob/living/carbon/human/affecting = G.affecting + + affecting.Stun(3) + + switch(assailant.a_intent) + if(I_GRAB) + on_hit_grab(G) + if(I_HURT) + on_hit_harm(G) \ No newline at end of file diff --git a/code/modules/mob/grab/nab/nab_passive.dm b/code/modules/mob/grab/nab/nab_passive.dm new file mode 100644 index 00000000..f030a763 --- /dev/null +++ b/code/modules/mob/grab/nab/nab_passive.dm @@ -0,0 +1,15 @@ +/datum/grab/nab/passive + state_name = NAB_PASSIVE + + upgrab_name = NAB_AGGRESSIVE + + shift = -10 + + reverse_facing = 0 + can_absorb = 0 + + grab_slowdown = 0 + + icon_state = "reinforce1" + + break_chance_table = list(50, 80, 100) \ No newline at end of file diff --git a/code/modules/mob/grab/normal/grab_normal.dm b/code/modules/mob/grab/normal/grab_normal.dm new file mode 100644 index 00000000..85c0c607 --- /dev/null +++ b/code/modules/mob/grab/normal/grab_normal.dm @@ -0,0 +1,305 @@ +/obj/item/grab/normal + + type_name = GRAB_NORMAL + start_grab_name = NORM_PASSIVE + +/obj/item/grab/normal/init() + ..() + + if(affecting.w_uniform) + affecting.w_uniform.add_fingerprint(assailant) + + assailant.put_in_active_hand(src) + assailant.do_attack_animation(affecting) + playsound(affecting.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + var/obj/O = get_targeted_organ() + visible_message("[assailant] has grabbed [affecting]'s [O.name]!") + affecting.grabbed_by += src + + if(!(affecting.a_intent == I_HELP)) + upgrade(TRUE) + +/datum/grab/normal + type_name = GRAB_NORMAL + + var/drop_headbutt = 1 + + icon = 'icons/mob/screen1.dmi' + + help_action = "inspect" + disarm_action = "pin" + grab_action = "jointlock" + harm_action = "dislocate" + +/datum/grab/normal/on_hit_help(var/obj/item/grab/normal/G) + var/obj/item/organ/external/O = G.get_targeted_organ() + if(O) + return O.inspect(G.assailant) + +/datum/grab/normal/on_hit_disarm(var/obj/item/grab/G) + var/mob/living/carbon/human/affecting = G.affecting + var/mob/living/carbon/human/assailant = G.assailant + + if(!G.attacking && !affecting.lying) + + affecting.visible_message("[assailant] is trying to pin [affecting] to the ground!") + G.attacking = 1 + + if(do_mob(assailant, affecting, action_cooldown - 1)) + G.attacking = 0 + G.action_used() + affecting.Weaken(2) + affecting.visible_message("[assailant] pins [affecting] to the ground!") + + return 1 + else + affecting.visible_message("[assailant] fails to pin [affecting] to the ground.") + G.attacking = 0 + return 0 + else + return 0 + + +/datum/grab/normal/on_hit_grab(var/obj/item/grab/G) + var/obj/item/organ/external/O = G.get_targeted_organ() + var/mob/living/carbon/human/assailant = G.assailant + var/mob/living/carbon/human/affecting = G.affecting + + if(!O) + to_chat(assailant, "[affecting] is missing that body part!") + return 0 + + assailant.visible_message("[assailant] begins to [pick("bend", "twist")] [affecting]'s [O.name] into a jointlock!") + G.attacking = 1 + + if(do_mob(assailant, affecting, action_cooldown - 1)) + + G.attacking = 0 + G.action_used() + O.jointlock(assailant) + assailant.visible_message("[affecting]'s [O.name] is twisted!") + playsound(assailant.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + return 1 + + else + + affecting.visible_message("[assailant] fails to jointlock [affecting]'s [O.name].") + G.attacking = 0 + return 0 + + +/datum/grab/normal/on_hit_harm(var/obj/item/grab/G) + var/obj/item/organ/external/O = G.get_targeted_organ() + var/mob/living/carbon/human/assailant = G.assailant + var/mob/living/carbon/human/affecting = G.affecting + + if(!O) + to_chat(assailant, "[affecting] is missing that body part!") + return 0 + + if(!O.dislocated) + + assailant.visible_message("[assailant] begins to dislocate [affecting]'s [O.joint]!") + G.attacking = 1 + + if(do_mob(assailant, affecting, action_cooldown - 1)) + + G.attacking = 0 + G.action_used() + O.dislocate(1) + assailant.visible_message("[affecting]'s [O.joint] [pick("gives way","caves in","crumbles","collapses")]!") + playsound(assailant.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + return 1 + + else + + affecting.visible_message("[assailant] fails to dislocate [affecting]'s [O.joint].") + G.attacking = 0 + return 0 + + else if (O.dislocated > 0) + to_chat(assailant, "[affecting]'s [O.joint] is already dislocated!") + return 0 + else + to_chat(assailant, "You can't dislocate [affecting]'s [O.joint]!") + return 0 + +/datum/grab/normal/resolve_openhand_attack(var/obj/item/grab/G) + if(G.assailant.a_intent != I_HELP) + if(G.target_zone == BP_HEAD) + if(G.assailant.zone_sel.selecting == BP_EYES) + if(attack_eye(G)) + return 1 + else + if(headbutt(G)) + if(drop_headbutt) + let_go() + return 1 + return 0 + +/datum/grab/normal/proc/attack_eye(var/obj/item/grab/G) + var/mob/living/carbon/human/attacker = G.assailant + var/mob/living/carbon/human/target = G.affecting + + var/datum/unarmed_attack/attack = attacker.get_unarmed_attack(target, BP_EYES) + + if(!attack) + return + for(var/obj/item/protection in list(target.head, target.wear_mask, target.glasses)) + if(protection && (protection.body_parts_covered & EYES)) + to_chat(attacker, "You're going to need to remove the eye covering first.") + return + if(!target.has_eyes()) + to_chat(attacker, "You cannot locate any eyes on [target]!") + return + + admin_attack_log(attacker, target, "Grab attacked the victim's eyes.", "Had their eyes grab attacked.", "attacked the eyes, using a grab action, of") + + attack.handle_eye_attack(attacker, target) + return 1 + +/datum/grab/normal/proc/headbutt(var/obj/item/grab/G) + var/mob/living/carbon/human/attacker = G.assailant + var/mob/living/carbon/human/target = G.affecting + + if(target.lying) + return + + var/damage = 20 + var/obj/item/clothing/hat = attacker.head + var/damage_flags = 0 + if(istype(hat)) + damage += hat.force * 3 + damage_flags = hat.damage_flags() + + if(damage_flags & DAM_SHARP) + attacker.visible_message("[attacker] gores [target][istype(hat)? " with \the [hat]" : ""]!") + else + attacker.visible_message("[attacker] thrusts \his head into [target]'s skull!") + + var/armor = target.run_armor_check(BP_HEAD, "melee") + target.apply_damage(damage, BRUTE, BP_HEAD, armor, damage_flags) + attacker.apply_damage(10, BRUTE, BP_HEAD, attacker.run_armor_check(BP_HEAD, "melee")) + + if(armor < 50 && target.headcheck(BP_HEAD) && prob(damage)) + target.apply_effect(20, PARALYZE) + target.visible_message("[target] [target.species.get_knockout_message(target)]") + + playsound(attacker.loc, "swing_hit", 25, 1, -1) + + admin_attack_log(attacker, target, "Headbutted their victim.", "Was headbutted.", "headbutted") + return 1 + +// Handles special targeting like eyes and mouth being covered. +/datum/grab/normal/special_target_effect(var/obj/item/grab/G) + if(G.special_target_functional) + switch(G.last_target) + if(BP_MOUTH) + if(G.affecting.silent < 3) + G.affecting.silent = 3 + if(BP_EYES) + if(G.affecting.eye_blind < 3) + G.affecting.eye_blind = 3 + +// Handles when they change targeted areas and something is supposed to happen. +/datum/grab/normal/special_target_change(var/obj/item/grab/G, var/diff_zone) + if(G.target_zone != BP_HEAD && G.target_zone != BP_CHEST) + return + switch(diff_zone) + if(BP_MOUTH) + G.assailant.visible_message("\The [G.assailant] covers [G.affecting]'s mouth!") + if(BP_EYES) + G.assailant.visible_message("\The [G.assailant] covers [G.affecting]'s eyes!") + + +/datum/grab/normal/check_special_target(var/obj/item/grab/G) + switch(G.last_target) + if(BP_MOUTH) + if(!G.affecting.check_has_mouth()) + to_chat(G.assailant, "You cannot locate a mouth on [G.affecting]!") + return 0 + if(BP_EYES) + if(!G.affecting.has_eyes()) + to_chat(G.assailant, "You cannot locate any eyes on [G.affecting]!") + return 0 + return 1 + +/datum/grab/normal/resolve_item_attack(var/obj/item/grab/G, var/mob/living/carbon/human/user, var/obj/item/I) + switch(G.target_zone) + if(BP_HEAD) + return attack_throat(G, I, user) + else + return attack_tendons(G, I, user, G.target_zone) + + + +/datum/grab/normal/proc/attack_throat(var/obj/item/grab/G, var/obj/item/W, var/mob/living/carbon/human/user) + var/mob/living/carbon/human/affecting = G.affecting + + if(user.a_intent != I_HURT) + return 0 // Not trying to hurt them. + + if(!W.edge || !W.force || W.damtype != BRUTE) + return 0 //unsuitable weapon + user.visible_message("\The [user] begins to slit [affecting]'s throat with \the [W]!") + + user.next_move = world.time + 20 //also should prevent user from triggering this repeatedly + if(!do_after(user, 20, progress = 0)) + return 0 + if(!(G && G.affecting == affecting)) //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 = affecting.get_equipped_item(slot_head) + if(istype(helmet) && (helmet.body_parts_covered & HEAD) && (helmet.item_flags & ITEM_FLAG_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 + var/damage_flags = W.damage_flags() + for(var/i in 1 to 3) + var/damage = min(W.force*1.5, 20)*damage_mod + affecting.apply_damage(damage, W.damtype, BP_HEAD, 0, damage_flags, used_weapon=W) + total_damage += damage + + + if(total_damage) + user.visible_message("\The [user] slit [affecting]'s throat open with \the [W]!") + + if(W.hitsound) + playsound(affecting.loc, W.hitsound, 50, 1, -1) + + G.last_action = world.time + + admin_attack_log(user, src, "Knifed their victim", "Was knifed", "knifed") + return 1 + +/datum/grab/normal/proc/attack_tendons(var/obj/item/grab/G, var/obj/item/W, var/mob/living/carbon/human/user, var/target_zone) + var/mob/living/carbon/human/affecting = G.affecting + + if(user.a_intent != I_HURT) + return 0 // Not trying to hurt them. + + if(!W.edge || !W.force || W.damtype != BRUTE) + return 0 //unsuitable weapon + + var/obj/item/organ/external/O = G.get_targeted_organ() + if(!O || O.is_stump() || !O.has_tendon || (O.status & ORGAN_TENDON_CUT)) + return FALSE + + user.visible_message("\The [user] begins to cut \the [affecting]'s [O.tendon_name] with \the [W]!") + user.next_move = world.time + 20 + + if(!do_after(user, 20, progress=0)) + return 0 + if(!(G && G.affecting == affecting)) //check that we still have a grab + return 0 + if(!O || O.is_stump() || !O.sever_tendon()) + return 0 + + user.visible_message("\The [user] cut \the [src]'s [O.tendon_name] with \the [W]!") + if(W.hitsound) playsound(affecting.loc, W.hitsound, 50, 1, -1) + G.last_action = world.time + admin_attack_log(user, affecting, "hamstrung their victim", "was hamstrung", "hamstrung") + return 1 \ No newline at end of file diff --git a/code/modules/mob/grab/normal/norm_aggressive.dm b/code/modules/mob/grab/normal/norm_aggressive.dm new file mode 100644 index 00000000..541a0254 --- /dev/null +++ b/code/modules/mob/grab/normal/norm_aggressive.dm @@ -0,0 +1,43 @@ +/datum/grab/normal/aggressive + state_name = NORM_AGGRESSIVE + + upgrab_name = NORM_NECK + downgrab_name = NORM_PASSIVE + + shift = 12 + + + stop_move = 1 + reverse_facing = 0 + can_absorb = 0 + shield_assailant = 0 + point_blank_mult = 1 + same_tile = 0 + can_throw = 1 + force_danger = 1 + breakability = 3 + + icon_state = "reinforce1" + + break_chance_table = list(5, 20, 40, 80, 100) +/datum/grab/normal/aggressive/process_effect(var/obj/item/grab/G) + var/mob/living/carbon/human/affecting = G.affecting + + if(G.target_zone in list(BP_L_HAND, BP_R_HAND)) + affecting.drop_l_hand() + affecting.drop_r_hand() + + // Keeps those who are on the ground down + if(affecting.lying) + affecting.Weaken(4) + +/datum/grab/normal/aggressive/can_upgrade(var/obj/item/grab/G) + if(!(G.target_zone in list(BP_CHEST, BP_HEAD))) + to_chat(G.assailant, "You need to be grabbing their torso or head for this!") + return FALSE + var/obj/item/clothing/C = G.affecting.head + if(istype(C)) //hardsuit helmets etc + if((C.item_flags & ITEM_FLAG_STOPPRESSUREDAMAGE) && C.armor["melee"] > 20) + to_chat(G.assailant, "\The [C] is in the way!") + return FALSE + return TRUE \ No newline at end of file diff --git a/code/modules/mob/grab/normal/norm_kill.dm b/code/modules/mob/grab/normal/norm_kill.dm new file mode 100644 index 00000000..eff3f91d --- /dev/null +++ b/code/modules/mob/grab/normal/norm_kill.dm @@ -0,0 +1,37 @@ +/datum/grab/normal/kill + state_name = NORM_KILL + + downgrab_name = NORM_NECK + + shift = 0 + + stop_move = 1 + reverse_facing = 1 + can_absorb = 1 + shield_assailant = 0 + point_blank_mult = 1 + same_tile = 1 + force_danger = 1 + restrains = 1 + + downgrade_on_action = 1 + downgrade_on_move = 1 + + icon_state = "kill1" + + break_chance_table = list(5, 20, 40, 80, 100) + +/datum/grab/normal/kill/process_effect(var/obj/item/grab/G) + var/mob/living/carbon/human/affecting = G.affecting + + affecting.drop_l_hand() + affecting.drop_r_hand() + + if(affecting.lying) + affecting.Weaken(4) + + affecting.adjustOxyLoss(1) + + affecting.apply_effect(STUTTER, 5) //It will hamper your voice, being choked and all. + affecting.Weaken(5) //Should keep you down unless you get help. + affecting.losebreath = max(affecting.losebreath + 2, 3) diff --git a/code/modules/mob/grab/normal/norm_neck.dm b/code/modules/mob/grab/normal/norm_neck.dm new file mode 100644 index 00000000..1d371cec --- /dev/null +++ b/code/modules/mob/grab/normal/norm_neck.dm @@ -0,0 +1,35 @@ +/datum/grab/normal/neck + state_name = NORM_NECK + + upgrab_name = NORM_KILL + downgrab_name = NORM_AGGRESSIVE + + drop_headbutt = 0 + + shift = -10 + + + stop_move = 1 + reverse_facing = 1 + can_absorb = 1 + shield_assailant = 1 + point_blank_mult = 1 + same_tile = 1 + can_throw = 1 + force_danger = 1 + restrains = 1 + + icon_state = "kill" + + break_chance_table = list(3, 18, 45, 100) + +/datum/grab/normal/neck/process_effect(var/obj/item/grab/G) + var/mob/living/carbon/human/affecting = G.affecting + + affecting.drop_l_hand() + affecting.drop_r_hand() + + if(affecting.lying) + affecting.Weaken(4) + + affecting.adjustOxyLoss(1) diff --git a/code/modules/mob/grab/normal/norm_passive.dm b/code/modules/mob/grab/normal/norm_passive.dm new file mode 100644 index 00000000..22096d07 --- /dev/null +++ b/code/modules/mob/grab/normal/norm_passive.dm @@ -0,0 +1,33 @@ +/datum/grab/normal/passive + state_name = NORM_PASSIVE + fancy_desc = "holding" + + upgrab_name = NORM_STRUGGLE + + shift = 8 + + stop_move = 0 + reverse_facing = 0 + can_absorb = 0 + shield_assailant = 0 + point_blank_mult = 1 + same_tile = 0 + + icon_state = "reinforce" + + break_chance_table = list(15, 60, 100) + +/datum/grab/normal/passive/on_hit_disarm(var/obj/item/grab/normal/G) + to_chat(G.assailant, "Your grip isn't strong enough to pin.") + return 0 + +/datum/grab/normal/passive/on_hit_grab(var/obj/item/grab/normal/G) + to_chat(G.assailant, "Your grip isn't strong enough to jointlock.") + return 0 + +/datum/grab/normal/passive/on_hit_harm(var/obj/item/grab/normal/G) + to_chat(G.assailant, "Your grip isn't strong enough to dislocate.") + return 0 + +/datum/grab/normal/passive/resolve_openhand_attack(var/obj/item/grab/G) + return 0 diff --git a/code/modules/mob/grab/normal/norm_struggle.dm b/code/modules/mob/grab/normal/norm_struggle.dm new file mode 100644 index 00000000..da45d17e --- /dev/null +++ b/code/modules/mob/grab/normal/norm_struggle.dm @@ -0,0 +1,72 @@ +/datum/grab/normal/struggle + state_name = NORM_STRUGGLE + fancy_desc = "holding" + + upgrab_name = NORM_AGGRESSIVE + downgrab_name = NORM_PASSIVE + + shift = 8 + + stop_move = 1 + reverse_facing = 0 + can_absorb = 0 + point_blank_mult = 1 + same_tile = 0 + breakability = 3 + + grab_slowdown = 10 + upgrade_cooldown = 20 + + can_downgrade_on_resist = 0 + + icon_state = "reinforce" + + var/done_struggle = FALSE + + break_chance_table = list(5, 20, 30, 80, 100) + + +/datum/grab/normal/struggle/process_effect(var/obj/item/grab/G) + var/mob/living/carbon/human/affecting = G.affecting + var/mob/living/carbon/human/assailant = G.assailant + + if(affecting.incapacitated() || affecting.a_intent == I_HELP) + affecting.visible_message("[affecting] isn't prepared to fight back as [assailant] tightens \his grip!") + done_struggle = TRUE + G.upgrade(TRUE) + +/datum/grab/normal/struggle/enter_as_up(var/obj/item/grab/G) + var/mob/living/carbon/human/affecting = G.affecting + var/mob/living/carbon/human/assailant = G.assailant + + if(affecting.incapacitated() || affecting.a_intent == I_HELP) + affecting.visible_message("[affecting] isn't prepared to fight back as [assailant] tightens \his grip!") + done_struggle = TRUE + G.upgrade(TRUE) + else + affecting.visible_message("[affecting] struggles against [assailant]!") + spawn(10) + handle_resist(G) + if(do_after(assailant, upgrade_cooldown, G, can_move = 1)) + done_struggle = TRUE + G.upgrade(TRUE) + else + G.downgrade() + +/datum/grab/normal/struggle/can_upgrade(var/obj/item/grab/G) + return done_struggle + +/datum/grab/normal/struggle/on_hit_disarm(var/obj/item/grab/normal/G) + to_chat(G.assailant, "Your grip isn't strong enough to pin.") + return 0 + +/datum/grab/normal/struggle/on_hit_grab(var/obj/item/grab/normal/G) + to_chat(G.assailant, "Your grip isn't strong enough to jointlock.") + return 0 + +/datum/grab/normal/struggle/on_hit_harm(var/obj/item/grab/normal/G) + to_chat(G.assailant, "Your grip isn't strong enough to dislocate.") + return 0 + +/datum/grab/normal/struggle/resolve_openhand_attack(var/obj/item/grab/G) + return 0 diff --git a/code/modules/mob/grab/special/grab_special.dm b/code/modules/mob/grab/special/grab_special.dm new file mode 100644 index 00000000..5a1e644c --- /dev/null +++ b/code/modules/mob/grab/special/grab_special.dm @@ -0,0 +1,160 @@ +/datum/grab/special + icon = 'icons/mob/screen1.dmi' + stop_move = 1 + can_absorb = 1 + shield_assailant = 0 + point_blank_mult = 1 + force_danger = 1 + +/obj/item/grab/special/init() + ..() + + if(affecting.w_uniform) + affecting.w_uniform.add_fingerprint(assailant) + + assailant.put_in_active_hand(src) + assailant.do_attack_animation(affecting) + playsound(affecting.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + var/obj/O = get_targeted_organ() + var/grab_string = O.name + if(assailant.zone_sel.selecting == BP_THROAT) + grab_string = "throat" + visible_message("[assailant] grabs [affecting]'s [grab_string]!") + affecting.grabbed_by += src + +/obj/item/grab/special/strangle + type_name = GRAB_STRANGLE + start_grab_name = GRAB_STRANGLE + +/datum/grab/special/strangle + type_name = GRAB_STRANGLE + icon_state = "strangle" + activate_effect = FALSE + state_name = GRAB_STRANGLE + +/datum/grab/special/strangle/attack_self_act(var/obj/item/grab/G) + do_strangle(G) + +/datum/grab/special/strangle/process_effect(var/obj/item/grab/G) + var/mob/living/carbon/human/affecting = G.affecting + + affecting.drop_l_hand() + affecting.drop_r_hand() + + if(affecting.lying) + affecting.Weaken(4) + + affecting.adjustOxyLoss(1) + + affecting.apply_effect(STUTTER, 5) //It will hamper your voice, being choked and all. + affecting.Weaken(5) //Should keep you down unless you get help. + affecting.losebreath = max(affecting.losebreath + 2, 3) + +/datum/grab/special/strangle/proc/do_strangle(var/obj/item/grab/G) + activate_effect = !activate_effect + G.assailant.visible_message("[G.assailant] [activate_effect ? "starts" : "stops"] strangling [G.affecting]") + + +/obj/item/grab/special/wrench + type_name = GRAB_WRENCH + start_grab_name = GRAB_WRENCH + + +/datum/grab/special/wrench + type_name = GRAB_WRENCH + icon_state = "wrench" + state_name = GRAB_WRENCH + +/datum/grab/special/wrench/attack_self_act(var/obj/item/grab/G) + do_wrench(G) + G.assailant.setClickCooldown(DEFAULT_SLOW_COOLDOWN) + +/datum/grab/special/wrench/proc/do_wrench(var/obj/item/grab/G) + var/obj/item/organ/external/O = G.get_targeted_organ() + var/mob/living/carbon/human/assailant = G.assailant + var/mob/living/carbon/human/affecting = G.affecting + + if(assailant.doing_something) + return + + if(!O) + to_chat(assailant, "[affecting] is missing that body part!") + return + if(!G.wielded) + to_chat(assailant, "We must wield them in both hands to break their limb.") + return + + assailant.doing_something = TRUE + + if(!do_after(assailant, 30, affecting)) + assailant.doing_something = FALSE + return + + + if(!O.is_broken()) // The limb is broken and we're grabbing it in both hands. + assailant.visible_message("[assailant] tries to break [affecting]'s [O.name]!") + var/break_chance = (assailant.STAT_LEVEL(str)*10) - 105 // We have to have a strength over 12 to really have a chance of breaking a limb. + if(break_chance <= 0) + break_chance = 10 + if(prob(break_chance)) + O.fracture() + + assailant.doing_something = FALSE + + +/obj/item/grab/special/takedown + type_name = GRAB_TAKEDOWN + start_grab_name = GRAB_TAKEDOWN + +/datum/grab/special/takedown + type_name = GRAB_TAKEDOWN + state_name = GRAB_TAKEDOWN + icon_state = "takedown" + +/datum/grab/special/takedown/attack_self_act(var/obj/item/grab/G) + do_takedown(G) + G.assailant.setClickCooldown(DEFAULT_SLOW_COOLDOWN) + +/datum/grab/special/takedown/process_effect(var/obj/item/grab/G) + // Keeps those who are on the ground down + if(G.affecting.lying) + G.affecting.Weaken(4) + + +/datum/grab/special/takedown/proc/do_takedown(var/obj/item/grab/G) + var/mob/living/carbon/human/affecting = G.affecting + var/mob/living/carbon/human/assailant = G.assailant + + if(assailant.doing_something) + return + + assailant.doing_something = TRUE + + if(!do_after(assailant, 30, affecting)) + assailant.doing_something = FALSE + return + + if(!G.attacking && !affecting.lying) + + affecting.visible_message("[assailant] is trying to pin [affecting] to the ground!") + G.attacking = 1 + + if(!assailant.statscheck(assailant.STAT_LEVEL(str) / 2 + 3) >= SUCCESS && do_mob(assailant, affecting, 30)) + + G.attacking = 0 + G.action_used() + affecting.Weaken(2) + affecting.visible_message("[assailant] pins [affecting] to the ground!") + assailant.doing_something = FALSE + return 1 + else + affecting.visible_message("[assailant] fails to pin [affecting] to the ground.") + G.attacking = 0 + assailant.doing_something = FALSE + return 0 + else + assailant.doing_something = FALSE + return 0 + +/datum/grab/special/self + icon_state = "self" \ No newline at end of file diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm new file mode 100644 index 00000000..76f1d7bc --- /dev/null +++ b/code/modules/mob/hear_say.dm @@ -0,0 +1,303 @@ +// At minimum every mob has a hear_say proc. + +/mob/proc/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) + if(!client) + return + + if(speaker && !speaker.client && isghost(src) && get_preference_value(/datum/client_preference/ghost_ears) == GLOB.PREF_ALL_SPEECH && !(speaker in view(src))) + //Does the speaker have a client? It's either random stuff that observers won't care about (Experiment 97B says, 'EHEHEHEHEHEHEHE') + //Or someone snoring. So we make it where they won't hear it. + return + + //Adds punctuation automatically. + var/ending = copytext(message, -1) + if(!(ending in PUNCTUATION)) + message = "[message]." + + message = replacetext(message, "/", "")//None of this. + message = replacetext(message, "~", "")//Or this. + message = replacetext(message, "@", "")//I keep doing this and it annoys me. + message = replacetext(message, " i ", " I ")//FUCKING USE CAPITAL LETTERS JAMES YOU FUCK! + message = replacetext(message, " ive ", " I've ")//I'M SO FUCKING SICK OF SEEING IVE YOU FUCKS + message = replacetext(message, " im ", " I'm ")//AND IM TOO! STOP THAT YOU FUCKS! + message = replacetext(message, " u ", " you ")//STOP USING FUCKING U YOU SICK FUCKS! + + message = add_shout_append(capitalize(message))//So that if they end in an ! it gets bolded + + //make sure the air can transmit speech - hearer's side + var/turf/T = get_turf(src) + if ((T) && (!(isghost(src)))) //Ghosts can hear even in vacuum. + var/datum/gas_mixture/environment = T.return_air() + var/pressure = (environment)? environment.return_pressure() : 0 + if(pressure < SOUND_MINIMUM_PRESSURE && get_dist(speaker, src) > 1) + return + + if (pressure < ONE_ATMOSPHERE*0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet + italics = 1 + sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact + + if(sleeping || stat == UNCONSCIOUS) + hear_sleep(message) + return + + //non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet. + if (language && (language.flags & NONVERBAL)) + if (!speaker || (src.sdisabilities & BLIND || src.blinded) || !(speaker in view(src))) + message = stars(message) + + if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages + if(!say_understands(speaker,language)) + if(istype(speaker,/mob/living/simple_animal)) + var/mob/living/simple_animal/S = speaker + message = pick(S.speak) + else + if(language) + message = language.scramble(message) + else + message = stars(message) + + var/speaker_name = "Unknown" + if(speaker) + speaker_name = speaker.name + + if(istype(speaker, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = speaker + speaker_name = H.GetVoice() + + if(italics) + message = "[capitalize(message)]" + + var/track = null + if(isghost(src)) + if(speaker_name != speaker.real_name && speaker.real_name) + speaker_name = "[speaker.real_name] ([speaker_name])" + track = "([ghost_follow_link(speaker, src)]) " + //if(get_preference_value(/datum/client_preference/ghost_ears) == GLOB.PREF_ALL_SPEECH && (speaker in view(src))) + // message = "[message]" + + if(is_deaf()) + if(!language || !(language.flags & INNATE)) // INNATE is the flag for audible-emote-language, so we don't want to show an "x talks but you cannot hear them" message if it's set + if(speaker == src) + to_chat(src, "You cannot hear yourself speak!") + else if(!is_blind()) + to_chat(src, "[speaker_name][alt_name] talks but you cannot hear them.") + else + if(language) + on_hear_say("[speaker_name][alt_name] [track][language.format_message(message, verb)]") + else + on_hear_say("[speaker_name][alt_name] [track][verb], \"[message]\"") + if (speech_sound && (get_dist(speaker, src) <= world.view && src.z == speaker.z)) + var/turf/source = speaker? get_turf(speaker) : get_turf(src) + src.playsound_local(source, speech_sound, sound_vol, 1) + +/mob/proc/on_hear_say(var/message) + to_chat(src, message) + +/mob/living/silicon/on_hear_say(var/message) + var/time = say_timestamp() + to_chat(src, "[time] [message]") + +/mob/proc/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="") + + var/radio_sound = list('sound/effects/radio1.ogg', 'sound/effects/radio2.ogg', 'sound/effects/radio3.ogg', 'sound/effects/radio4.ogg') + + if(!isobserver(src)) + //playsound(loc, 'sound/effects/radio_chatter.ogg', 25, 0, -1)//They won't always be able to read the message, but the sound will play regardless. + playsound(loc, pick(radio_sound), 15, 0, -1) + + if(!client) + return + + if(sleeping || stat==1) //If unconscious or sleeping + hear_sleep(message) + return + + var/track = null + var/jobname // the mob's "job" + + //non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet. + if (language && (language.flags & NONVERBAL)) + if (!speaker || (src.sdisabilities & BLIND || src.blinded) || !(speaker in view(src))) + message = stars(message) + + if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages + if(!say_understands(speaker,language)) + if(istype(speaker,/mob/living/simple_animal)) + var/mob/living/simple_animal/S = speaker + if(S.speak && S.speak.len) + message = pick(S.speak) + else + return + else + if(language) + message = language.scramble(message) + else + message = stars(message) + + if(hard_to_hear) + if(hard_to_hear <= 5) + message = stars(message) + else // Used for compression + message = RadioChat(null, message, 80, 1+(hard_to_hear/10)) + + var/speaker_name = speaker.name + + if(vname) + speaker_name = vname + + if(istype(speaker, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = speaker + if(H.voice) + speaker_name = H.voice + + if(H.age && H.gender && !H.is_anonymous)//If they have an age and gender, and they're not anonymous. + var/ageAndGender + jobname = H.get_assignment() + + if(H.get_assignment() == "No id")//If they don't have an ID then we don't know their job. + jobname = "" + + ageAndGender = ageAndGender2Desc(H.age, H.gender)//Get their age and gender + + speaker_name += " \[" + "[jobname] " + "[ageAndGender]" + "]"//Print it out. + + if(hard_to_hear) + speaker_name = "unknown" + + var/changed_voice + + if(istype(src, /mob/living/silicon/ai) && !hard_to_hear) + var/mob/living/carbon/human/impersonating //The crew member being impersonated, if any. + + if (ishuman(speaker)) + var/mob/living/carbon/human/H = speaker + + if(H.wear_mask && istype(H.wear_mask,/obj/item/clothing/mask/chameleon/voice)) + changed_voice = 1 + var/list/impersonated = new() + var/mob/living/carbon/human/I = impersonated[speaker_name] + + if(!I) + for(var/mob/living/carbon/human/M in SSmobs.mob_list) + if(M.real_name == speaker_name) + I = M + impersonated[speaker_name] = I + break + + // If I's display name is currently different from the voice name and using an agent ID then don't impersonate + // as this would allow the AI to track I and realize the mismatch. + if(I && !(I.name != speaker_name && I.wear_id && istype(I.wear_id,/obj/item/weapon/card/id/syndicate))) + impersonating = I + jobname = impersonating.get_assignment() + else + jobname = "Unknown" + else + jobname = H.get_assignment() + + else if (iscarbon(speaker)) // Nonhuman carbon mob + jobname = "No id" + else if (isAI(speaker)) + jobname = "AI" + else if (isrobot(speaker)) + jobname = "Cyborg" + else if (istype(speaker, /mob/living/silicon/pai)) + jobname = "Personal AI" + else + jobname = "Unknown" + + if(changed_voice) // Fix for AI tracking camera. + if(impersonating) + track = "[speaker_name] ([jobname])" + else + track = "[speaker_name] ([jobname])" + else + track = "[speaker_name] ([jobname])" + + if(isghost(src)) + if(speaker_name != speaker.real_name && !isAI(speaker)) //Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs. + speaker_name = "[speaker.real_name] ([speaker_name])" + track = "[speaker_name] ([ghost_follow_link(speaker, src)])" + + var/formatted + if((copytext(message,-1) != "!") && (copytext(message,-1) != ".") && (copytext(message,-1) != "?")) + message = "[message]." + message = replacetext(message, "/", "")//None of this. + message = replacetext(message, "~", "")//Or this. + message = replacetext(message, "@", "")//I keep doing this and it annoys me. + message = replacetext(message, " i ", " I ")//FUCKING USE CAPITAL LETTERS JAMES YOU FUCK! + message = replacetext(message, " ive ", " I've ")//I'M SO FUCKING SICK OF SEEING IVE YOU FUCKS + message = replacetext(message, " im ", " I'm ")//AND IM TOO! STOP THAT YOU FUCKS! + message = replacetext(message, " u ", " you ")//STOP USING FUCKING U YOU SICK FUCKS! + message = add_shout_append(capitalize(message))//So that if they end in an ! it gets bolded + if(language) + formatted = language.format_message_radio(message, verb) + else + formatted = "[verb], \"[message]\"" + if(sdisabilities & DEAF || ear_deaf) + var/mob/living/carbon/human/H = src + if(istype(H) && H.has_headset_in_ears() && prob(20)) + to_chat(src, "You feel your headset vibrate but can hear nothing from it!") + else + on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted) + +/proc/say_timestamp() + return "\[[stationtime2text()]\]" + +/mob/proc/on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted) + to_chat(src, "[part_a][speaker_name][part_b][formatted][part_c]") + +/mob/observer/ghost/on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted) + to_chat(src, "[part_a][track][part_b][formatted][part_c]") + +/mob/living/silicon/on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted) + var/time = say_timestamp() + to_chat(src, "[time][part_a][speaker_name][part_b][formatted][part_c]") + +/mob/living/silicon/ai/on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted) + var/time = say_timestamp() + to_chat(src, "[time][part_a][track][part_b][formatted][part_c]") + +/mob/proc/hear_signlang(var/message, var/verb = "gestures", var/datum/language/language, var/mob/speaker = null) + if(!client) + return + + if(sleeping || stat == UNCONSCIOUS) + return 0 + + if(say_understands(speaker, language)) + message = "[speaker] [verb], \"[message]\"" + else + var/adverb + var/length = length(message) * pick(0.8, 0.9, 1.0, 1.1, 1.2) //Inserts a little fuzziness. + switch(length) + if(0 to 12) adverb = " briefly" + if(12 to 30) adverb = " a short message" + if(30 to 48) adverb = " a message" + if(48 to 90) adverb = " a lengthy message" + else adverb = " a very lengthy message" + message = "[speaker] [verb][adverb]." + + if(src.status_flags & PASSEMOTES) + for(var/obj/item/weapon/holder/H in src.contents) + H.show_message(message) + for(var/mob/living/M in src.contents) + M.show_message(message) + src.show_message(message) + +/mob/proc/hear_sleep(var/message) + var/heard = "" + if(prob(15)) + var/list/punctuation = list(",", "!", ".", ";", "?") + var/list/messages = splittext(message, " ") + var/R = rand(1, messages.len) + var/heardword = messages[R] + if(copytext(heardword,1, 1) in punctuation) + heardword = copytext(heardword,2) + if(copytext(heardword,-1) in punctuation) + heardword = copytext(heardword,1,length(heardword)) + heard = "...You hear something about...[heardword]" + + else + heard = "...You almost hear someone talking..." + + to_chat(src, heard) diff --git a/code/modules/mob/holder.dm b/code/modules/mob/holder.dm new file mode 100644 index 00000000..ff861bf5 --- /dev/null +++ b/code/modules/mob/holder.dm @@ -0,0 +1,214 @@ +var/list/holder_mob_icon_cache = list() + +//Helper object for picking dionaea (and other creatures) up. +/obj/item/weapon/holder + name = "holder" + desc = "You shouldn't ever see this." + icon = 'icons/obj/objects.dmi' + slot_flags = SLOT_HEAD | SLOT_HOLSTER + origin_tech = null + item_icons = list( + slot_l_hand_str = 'icons/mob/onmob/items/lefthand_holder.dmi', + slot_r_hand_str = 'icons/mob/onmob/items/righthand_holder.dmi', + ) + pixel_y = 8 + + var/last_holder + +/obj/item/weapon/holder/New() + ..() + START_PROCESSING(SSobj, src) + +/obj/item/weapon/holder/proc/destroy_all() + for(var/atom/movable/AM in src) + qdel(AM) + qdel(src) + +/obj/item/weapon/holder/Destroy() + for(var/atom/movable/AM in src) + AM.forceMove(get_turf(src)) + last_holder = null + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/weapon/holder/Process() + update_state() + +/obj/item/weapon/holder/dropped() + ..() + spawn(1) + update_state() + +/obj/item/weapon/holder/proc/update_state() + if(last_holder != loc) + for(var/mob/M in contents) + unregister_all_movement(last_holder, M) + + if(istype(loc,/turf) || !(contents.len)) + for(var/mob/M in contents) + var/atom/movable/mob_container = M + mob_container.dropInto(loc) + M.reset_view() + qdel(src) + else if(last_holder != loc) + for(var/mob/M in contents) + register_all_movement(loc, M) + + last_holder = loc + +/obj/item/weapon/holder/onDropInto(var/atom/movable/AM) + if(ismob(loc)) // Bypass our holding mob and drop directly to its loc + return loc.loc + return ..() + +/obj/item/weapon/holder/GetIdCard() + for(var/mob/M in contents) + var/obj/item/I = M.GetIdCard() + if(I) + return I + return null + +/obj/item/weapon/holder/GetAccess() + var/obj/item/I = GetIdCard() + return I ? I.GetAccess() : ..() + +/obj/item/weapon/holder/attack_self() + for(var/mob/M in contents) + M.show_inv(usr) + +/obj/item/weapon/holder/attack(mob/target, mob/user) + // Devour on click on self with holder + if(target == user && istype(user,/mob/living/carbon)) + var/mob/living/carbon/M = user + + for(var/mob/victim in src.contents) + M.devour(victim) + + update_state() + + ..() + +/obj/item/weapon/holder/proc/sync(var/mob/living/M) + dir = 2 + overlays.Cut() + icon = M.icon + icon_state = M.icon_state + item_state = M.item_state + color = M.color + name = M.name + desc = M.desc + overlays |= M.overlays + var/mob/living/carbon/human/H = loc + last_holder = H + register_all_movement(H, M) + + update_held_icon() + +//Mob specific holders. +/obj/item/weapon/holder/diona + origin_tech = list(TECH_MAGNET = 3, TECH_BIO = 5) + slot_flags = SLOT_HEAD | SLOT_OCLOTHING | SLOT_HOLSTER + +/obj/item/weapon/holder/drone + origin_tech = list(TECH_MAGNET = 3, TECH_ENGINEERING = 5) + +/obj/item/weapon/holder/mouse + w_class = ITEM_SIZE_TINY + +/obj/item/weapon/holder/borer + origin_tech = list(TECH_BIO = 6) + +//need own subtype to work with recipies +/obj/item/weapon/holder/corgi + origin_tech = list(TECH_BIO = 4) + +/obj/item/weapon/holder/attackby(obj/item/weapon/W as obj, mob/user as mob) + for(var/mob/M in src.contents) + M.attackby(W,user) + +//Mob procs and vars for scooping up +/mob/living/var/holder_type + +/mob/living/proc/get_scooped(var/mob/living/carbon/human/grabber, var/self_grab) + + if(!holder_type || buckled || pinned.len) + return + + if(self_grab) + if(src.incapacitated()) return + else + if(grabber.incapacitated()) return + + var/obj/item/weapon/holder/H = new holder_type(get_turf(src)) + + if(self_grab) + if(!grabber.equip_to_slot_if_possible(H, slot_back, del_on_fail=0, disable_warning=1)) + to_chat(src, "You can't climb onto [grabber]!") + return + + to_chat(grabber, "\The [src] clambers onto you!") + to_chat(src, "You climb up onto \the [grabber]!") + else + if(!grabber.put_in_hands(H)) + to_chat(grabber, "Your hands are full!") + return + + to_chat(grabber, "You scoop up \the [src]!") + to_chat(src, "\The [grabber] scoops you up!") + + src.forceMove(H) + + grabber.status_flags |= PASSEMOTES + H.sync(src) + return H + +/mob/living/MouseDrop(var/mob/living/carbon/human/over_object) + if(istype(over_object) && Adjacent(over_object) && (usr == src || usr == over_object) && over_object.a_intent == I_GRAB) + if(scoop_check(over_object)) + get_scooped(over_object, (usr == src)) + return + return ..() + +/mob/living/proc/scoop_check(var/mob/living/scooper) + return 1 + +/mob/living/carbon/human/scoop_check(var/mob/living/scooper) + return (scooper.mob_size > src.mob_size && a_intent == I_HELP) + +/obj/item/weapon/holder/human + icon = 'icons/mob/holder_complex.dmi' + var/list/generate_for_slots = list(slot_l_hand_str, slot_r_hand_str, slot_back_str) + slot_flags = SLOT_BACK + +/obj/item/weapon/holder/human/sync(var/mob/living/M) + // Generate appropriate on-mob icons. + var/mob/living/carbon/human/owner = M + if(istype(owner) && owner.species) + + var/skin_colour = rgb(owner.r_skin, owner.g_skin, owner.b_skin) + var/hair_colour = rgb(owner.r_hair, owner.g_hair, owner.b_hair) + var/eye_colour = rgb(owner.r_eyes, owner.g_eyes, owner.b_eyes) + var/species_name = lowertext(owner.species.get_bodytype(owner)) + + for(var/cache_entry in generate_for_slots) + var/cache_key = "[owner.species]-[cache_entry]-[skin_colour]-[hair_colour]" + if(!holder_mob_icon_cache[cache_key]) + + // Generate individual icons. + var/icon/mob_icon = icon(icon, "[species_name]_holder_[cache_entry]_base") + mob_icon.Blend(skin_colour, ICON_ADD) + var/icon/hair_icon = icon(icon, "[species_name]_holder_[cache_entry]_hair") + hair_icon.Blend(hair_colour, ICON_ADD) + var/icon/eyes_icon = icon(icon, "[species_name]_holder_[cache_entry]_eyes") + eyes_icon.Blend(eye_colour, ICON_ADD) + + // Blend them together. + mob_icon.Blend(eyes_icon, ICON_OVERLAY) + mob_icon.Blend(hair_icon, ICON_OVERLAY) + + // Add to the cache. + holder_mob_icon_cache[cache_key] = mob_icon + item_icons[cache_entry] = holder_mob_icon_cache[cache_key] + + // Handle the rest of sync(). + ..(M) diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm new file mode 100644 index 00000000..3fc95ad9 --- /dev/null +++ b/code/modules/mob/inventory.dm @@ -0,0 +1,323 @@ +//This proc is called whenever someone clicks an inventory ui slot. +/mob/proc/attack_ui(slot) + var/obj/item/W = get_active_hand() + var/obj/item/E = get_equipped_item(slot) + if (istype(E)) + if(istype(W)) + E.attackby(W,src) + else + E.attack_hand(src) + else + equip_to_slot_if_possible(W, slot) + +/mob/proc/put_in_any_hand_if_possible(obj/item/W as obj, del_on_fail = 0, disable_warning = 1, redraw_mob = 1) + if(equip_to_slot_if_possible(W, slot_l_hand, del_on_fail, disable_warning, redraw_mob)) + return 1 + else if(equip_to_slot_if_possible(W, slot_r_hand, del_on_fail, disable_warning, redraw_mob)) + return 1 + return 0 + +//This is a SAFE proc. Use this instead of equip_to_slot()! +//set del_on_fail to have it delete W if it fails to equip +//set disable_warning to disable the 'you are unable to equip that' warning. +//unset redraw_mob to prevent the mob from being redrawn at the end. +//set force to replace items in the slot and ignore blocking overwear +/mob/proc/equip_to_slot_if_possible(obj/item/W as obj, slot, del_on_fail = 0, disable_warning = 0, redraw_mob = 1, force = 0) + if(!istype(W)) return 0 + + if(!W.mob_can_equip(src, slot, disable_warning, force)) + if(del_on_fail) + qdel(W) + else + if(!disable_warning) + to_chat(src, "You are unable to equip that.")//Only print if del_on_fail is false + + return 0 + + equip_to_slot(W, slot, redraw_mob) //This proc should not ever fail. + return 1 + +//This is an UNSAFE proc. It merely handles the actual job of equipping. All the checks on whether you can or can't eqip need to be done before! Use mob_can_equip() for that task. +//In most cases you will want to use equip_to_slot_if_possible() +/mob/proc/equip_to_slot(obj/item/W as obj, slot) + return + +//This is just a commonly used configuration for the equip_to_slot_if_possible() proc, used to equip people when the rounds tarts and when events happen and such. +/mob/proc/equip_to_slot_or_del(obj/item/W as obj, slot) + return equip_to_slot_if_possible(W, slot, 1, 1, 0) + +/mob/proc/equip_to_slot_or_store_or_drop(obj/item/W as obj, slot) + var/store = equip_to_slot_if_possible(W, slot, 0, 1, 0) + if(!store) + return equip_to_storage_or_drop(W) + return store + +//The list of slots by priority. equip_to_appropriate_slot() uses this list. Doesn't matter if a mob type doesn't have a slot. +var/list/slot_equipment_priority = list( \ + slot_s_store,\ + slot_back,\ + slot_wear_id,\ + slot_w_uniform,\ + slot_wear_suit,\ + slot_wear_mask,\ + slot_head,\ + slot_shoes,\ + slot_gloves,\ + slot_l_ear,\ + slot_r_ear,\ + slot_glasses,\ + slot_belt,\ + slot_tie,\ + slot_l_store,\ + slot_r_store\ + ) + +//Checks if a given slot can be accessed at this time, either to equip or unequip I +/mob/proc/slot_is_accessible(var/slot, var/obj/item/I, mob/user=null) + return 1 + +//puts the item "W" into an appropriate slot in a human's inventory +//returns 0 if it cannot, 1 if successful +/mob/proc/equip_to_appropriate_slot(obj/item/W) + if(!istype(W)) return 0 + + for(var/slot in slot_equipment_priority) + if(equip_to_slot_if_possible(W, slot, del_on_fail=0, disable_warning=1, redraw_mob=1)) + return 1 + + return 0 + +/mob/proc/equip_to_storage(obj/item/newitem) + // Try put it in their backpack + if(istype(src.back,/obj/item/weapon/storage)) + var/obj/item/weapon/storage/backpack = src.back + if(backpack.can_be_inserted(newitem, null, 1)) + newitem.forceMove(src.back) + return backpack + + // Try to place it in any item that can store stuff, on the mob. + for(var/obj/item/weapon/storage/S in src.contents) + if(S.can_be_inserted(newitem, null, 1)) + newitem.forceMove(S) + return S + +/mob/proc/equip_to_storage_or_drop(obj/item/newitem) + var/stored = equip_to_storage(newitem) + if(!stored && newitem) + newitem.forceMove(loc) + return stored + +//These procs handle putting s tuff in your hand. It's probably best to use these rather than setting l_hand = ...etc +//as they handle all relevant stuff like adding it to the player's screen and updating their overlays. + +//Returns the thing in our active hand +/mob/proc/get_active_hand() + if(hand) return l_hand + else return r_hand + +//Returns the thing in our inactive hand +/mob/proc/get_inactive_hand() + if(hand) return r_hand + else return l_hand + +/mob/proc/get_hands() + if(get_active_hand()) + return get_active_hand() + else + return get_inactive_hand() + +//Puts the item into your l_hand if possible and calls all necessary triggers/updates. returns 1 on success. +/mob/proc/put_in_l_hand(var/obj/item/W) + if(!istype(W)) + return 0 + return 1 + +//Puts the item into your r_hand if possible and calls all necessary triggers/updates. returns 1 on success. +/mob/proc/put_in_r_hand(var/obj/item/W) + if(!istype(W))//lying || + return 0 + return 1 + +//Puts the item into our active hand if possible. returns 1 on success. +/mob/proc/put_in_active_hand(var/obj/item/W) + return 0 // Moved to human procs because only they need to use hands. + +//Puts the item into our inactive hand if possible. returns 1 on success. +/mob/proc/put_in_inactive_hand(var/obj/item/W) + return 0 // As above. + +//Puts the item our active hand if possible. Failing that it tries our inactive hand. Returns 1 on success. +//If both fail it drops it on the floor and returns 0. +//This is probably the main one you need to know :) +/mob/proc/put_in_hands(var/obj/item/W) + if(!W) + return 0 + drop_from_inventory(W) + return 0 + +// Removes an item from inventory and places it in the target atom. +// If canremove or other conditions need to be checked then use unEquip instead. +/mob/proc/drop_from_inventory(var/obj/item/W, var/atom/target = null) + if(W) + remove_from_mob(W, target) + if(!(W && W.loc)) return 1 // self destroying objects (tk, grabs) + update_icons() + return 1 + return 0 + +//Drops the item in our left hand +/mob/proc/drop_l_hand(var/atom/Target) + return drop_from_inventory(l_hand, Target) + +//Drops the item in our right hand +/mob/proc/drop_r_hand(var/atom/Target) + return drop_from_inventory(r_hand, Target) + +//Drops the item in our active hand. TODO: rename this to drop_active_hand or something +/mob/proc/drop_item(var/atom/Target) + make_item_drop_sound() + if(hand) + return drop_l_hand(Target) + else + return drop_r_hand(Target) + +/mob/proc/make_item_drop_sound() + var/obj/item/I = get_active_hand() + spawn(1) + if(!I) + return + if(I.drop_sound) + playsound(I, I.drop_sound, 25, 0) + if(istype(I, /obj/item/weapon/gun))//Snowflake check yeah, but I'm tired of people getting fucking shot when they pull their gun out from their inventory. + var/obj/item/weapon/gun/G = I + G.check_gun_safety(src) + + + +/* + Removes the object from any slots the mob might have, calling the appropriate icon update proc. + Does nothing else. + + >>>> *** DO NOT CALL THIS PROC DIRECTLY *** <<<< + + It is meant to be called only by other inventory procs. + It's probably okay to use it if you are transferring the item between slots on the same mob, + but chances are you're safer calling remove_from_mob() or drop_from_inventory() anyways. + + As far as I can tell the proc exists so that mobs with different inventory slots can override + the search through all the slots, without having to duplicate the rest of the item dropping. +*/ +/mob/proc/u_equip(obj/W as obj) + if (W == r_hand) + r_hand = null + update_inv_r_hand(0) + else if (W == l_hand) + l_hand = null + update_inv_l_hand(0) + else if (W == back) + back = null + update_inv_back(0) + else if (W == wear_mask) + wear_mask = null + update_inv_wear_mask(0) + return + +/mob/proc/isEquipped(obj/item/I) + if(!I) + return 0 + return get_inventory_slot(I) != 0 + +/mob/proc/canUnEquip(obj/item/I) + if(!I) //If there's nothing to drop, the drop is automatically successful. + return 1 + var/slot = get_inventory_slot(I) + if(!slot) + return 1 //already unequipped, so success + return I.mob_can_unequip(src, slot) + +/mob/proc/get_inventory_slot(obj/item/I) + var/slot = 0 + for(var/s in slot_first to slot_last) //kind of worries me + if(get_equipped_item(s) == I) + slot = s + break + return slot + +//This differs from remove_from_mob() in that it checks if the item can be unequipped first. +/mob/proc/unEquip(obj/item/I, force = 0, var/atom/target = null) //Force overrides NODROP for things like wizarditis and admin undress. + if(!(force || canUnEquip(I))) + return + drop_from_inventory(I, target) + return 1 + +//Attemps to remove an object on a mob. +/mob/proc/remove_from_mob(var/obj/O, var/atom/target) + if(!O) // Nothing to remove, so we succeed. + return 1 + src.u_equip(O) + if (src.client) + src.client.screen -= O + O.reset_plane_and_layer() + O.screen_loc = null + if(istype(O, /obj/item)) + var/obj/item/I = O + if(target) + I.forceMove(target) + else + I.dropInto(loc) + I.dropped(src) + if(hud_used) + hud_used.add_inventory_overlay() + return 1 + + +//Returns the item equipped to the specified slot, if any. +/mob/proc/get_equipped_item(var/slot) + switch(slot) + if(slot_l_hand) return l_hand + if(slot_r_hand) return r_hand + if(slot_back) return back + if(slot_wear_mask) return wear_mask + return null + +/mob/proc/get_equipped_items(var/include_carried = 0) + . = list() + if(back) . += back + if(wear_mask) . += wear_mask + + if(include_carried) + if(l_hand) . += l_hand + if(r_hand) . += r_hand + +/mob/proc/delete_inventory(var/include_carried = FALSE) + for(var/entry in get_equipped_items(include_carried)) + drop_from_inventory(entry) + qdel(entry) + +/mob/proc/delete_from_slot(var/slot) + var/obj/O = get_equipped_item(slot) + if(O) + drop_from_inventory(O) + qdel(O) + +// Returns all currently covered body parts +/mob/proc/get_covered_body_parts() + . = 0 + for(var/entry in get_equipped_items()) + var/obj/item/I = entry + . |= I.body_parts_covered + +// Returns the first item which covers any given body part +/mob/proc/get_covering_equipped_item(var/body_parts) + for(var/entry in get_equipped_items()) + var/obj/item/I = entry + if(I.body_parts_covered & body_parts) + return I + +// Returns all items which covers any given body part +/mob/proc/get_covering_equipped_items(var/body_parts) + . = list() + for(var/entry in get_equipped_items()) + var/obj/item/I = entry + if(I.body_parts_covered & body_parts) + . += I diff --git a/code/modules/mob/language/generic.dm b/code/modules/mob/language/generic.dm new file mode 100644 index 00000000..c7f7202d --- /dev/null +++ b/code/modules/mob/language/generic.dm @@ -0,0 +1,72 @@ +// Noise "language", for audible emotes. +/datum/language/noise + name = "Noise" + desc = "Noises" + key = "" + flags = RESTRICTED|NONGLOBAL|INNATE|NO_TALK_MSG|NO_STUTTER + +/datum/language/noise/format_message(message, verb) + return "[message]" + +/datum/language/noise/format_message_plain(message, verb) + return message + +/datum/language/noise/format_message_radio(message, verb) + return "[message]" + +/datum/language/noise/get_talkinto_msg_range(message) + // if you make a loud noise (screams etc), you'll be heard from 4 tiles over instead of two + return (copytext(message, length(message)) == "!") ? 4 : 2 + +// 'basic' language; spoken by default. +/datum/language/common + name = LANGUAGE_GALCOM + desc = "The common galactic tongue." + speech_verb = "says" + whisper_verb = "whispers" + key = "0" + flags = RESTRICTED + syllables = list("blah","blah","blah","bleh","meh","neh","nah","wah") + +//TODO flag certain languages to use the mob-type specific say_quote and then get rid of these. +/datum/language/common/get_spoken_verb(var/msg_end) + switch(msg_end) + if("!") + return pick("exclaims","shouts","yells") //TODO: make the basic proc handle lists of verbs. + if("?") + return ask_verb + return speech_verb + +// Galactic common languages (systemwide accepted standards). +/datum/language/lunar + name = LANGUAGE_LUNAR + desc = "An older language primarily spoken on Earth's only natural satellite, this language is commonly heard from the mouths of aristocracy." + speech_verb = "enunciates" + colour = "moon" + key = "2" + space_chance = 100 + syllables = list("lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit", + "sed", "do", "eiusmod", "tempor", "incididunt", "ut", "labore", "et", "dolore", + "magna", "aliqua", "ut", "enim", "ad", "minim", "veniam", "quis", "nostrud", + "exercitation", "ullamco", "laboris", "nisi", "ut", "aliquip", "ex", "ea", "commodo", + "consequat", "duis", "aute", "irure", "dolor", "in", "reprehenderit", "in", + "voluptate", "velit", "esse", "cillum", "dolore", "eu", "fugiat", "nulla", + "pariatur", "excepteur", "sint", "occaecat", "cupidatat", "non", "proident", "sunt", + "in", "culpa", "qui", "officia", "deserunt", "mollit", "anim", "id", "est", "laborum") + +// Criminal language. +/datum/language/gutter + name = "Gutter" + desc = "Much like Common, this crude pidgin tongue descended from numerous languages and serves as a trade language for criminal elements." + speech_verb = "growls" + colour = "rough" + key = "3" + syllables = list ("gra","ba","ba","breh","bra","rah","dur","ra","ro","gro","go","ber","bar","geh","heh", "gra") + +/datum/language/sign + name = LANGUAGE_SIGN + desc = "A sign language commonly used for those who are deaf or mute." + signlang_verb = list("gestures") + colour = "say_quote" + key = "s" + flags = SIGNLANG | NO_STUTTER | NONVERBAL diff --git a/code/modules/mob/language/language.dm b/code/modules/mob/language/language.dm new file mode 100644 index 00000000..6b1d5b01 --- /dev/null +++ b/code/modules/mob/language/language.dm @@ -0,0 +1,232 @@ +#define SCRAMBLE_CACHE_LEN 20 + +/* + Datum based languages. Easily editable and modular. +*/ + +/datum/language + var/name = "an unknown language" // Fluff name of language if any. + var/desc = "A language." // Short description for 'Check Languages'. + var/speech_verb = "says" // 'says', 'hisses', 'farts'. + var/ask_verb = "asks" // Used when sentence ends in a ? + var/exclaim_verb = "exclaims" // Used when sentence ends in a ! + var/whisper_verb // Optional. When not specified speech_verb + quietly/softly is used instead. + var/signlang_verb = list("signs", "gestures") // list of emotes that might be displayed if this language has NONVERBAL or SIGNLANG flags + var/colour = "body" // CSS style to use for strings in this language. + var/key = "x" // Character used to speak in language eg. :o for Unathi. + var/flags = 0 // Various language flags. + var/native // If set, non-native speakers will have trouble speaking. + var/list/syllables // Used when scrambling text for a non-speaker. + var/list/space_chance = 55 // Likelihood of getting a space in the random scramble string + var/machine_understands = 1 // Whether machines can parse and understand this language + +/datum/language/proc/get_random_name(var/gender, name_count=2, syllable_count=4, syllable_divisor=2) + if(!syllables || !syllables.len) + if(gender==FEMALE) + return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) + else + return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) + + var/full_name = "" + var/new_name = "" + + for(var/i = 0;i0;x--) + new_name += pick(syllables) + full_name += " [capitalize(lowertext(new_name))]" + + return "[trim(full_name)]" + +/datum/language + var/list/scramble_cache = list() + +/datum/language/proc/scramble(var/input) + + if(!syllables || !syllables.len) + return stars(input) + + // If the input is cached already, move it to the end of the cache and return it + if(input in scramble_cache) + var/n = scramble_cache[input] + scramble_cache -= input + scramble_cache[input] = n + return n + + var/input_size = length(input) + var/scrambled_text = "" + var/capitalize = 1 + + while(length(scrambled_text) < input_size) + var/next = pick(syllables) + if(capitalize) + next = capitalize(next) + capitalize = 0 + scrambled_text += next + var/chance = rand(100) + if(chance <= 5) + scrambled_text += ". " + capitalize = 1 + else if(chance > 5 && chance <= space_chance) + scrambled_text += " " + + scrambled_text = trim(scrambled_text) + var/ending = copytext(scrambled_text, length(scrambled_text)) + if(ending == ".") + scrambled_text = copytext(scrambled_text,1,length(scrambled_text)-1) + var/input_ending = copytext(input, input_size) + if(input_ending in list("!","?",".")) + scrambled_text += input_ending + + // Add it to cache, cutting old entries if the list is too long + scramble_cache[input] = scrambled_text + if(scramble_cache.len > SCRAMBLE_CACHE_LEN) + scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1) + + return scrambled_text + +/datum/language/proc/format_message(message, verb) + return "[verb], \"[capitalize(message)]\"" + +/datum/language/proc/format_message_plain(message, verb) + return "[verb], \"[capitalize(message)]\"" + +/datum/language/proc/format_message_radio(message, verb) + return "[verb], \"[capitalize(message)]\"" + +/datum/language/proc/get_talkinto_msg_range(message) + // if you yell, you'll be heard from two tiles over instead of one + return (copytext(message, length(message)) == "!") ? 2 : 1 + +/datum/language/proc/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + log_say("[key_name(speaker)] : ([name]) [message]") + + if(!speaker_mask) speaker_mask = speaker.name + message = format_message(message, get_spoken_verb(message)) + + for(var/mob/player in GLOB.player_list) + player.hear_broadcast(src, speaker, speaker_mask, message) + +/mob/proc/hear_broadcast(var/datum/language/language, var/mob/speaker, var/speaker_name, var/message) + if((language in languages) && language.check_special_condition(src)) + var/msg = "[language.name], [speaker_name] [message]" + to_chat(src, msg) + +/mob/new_player/hear_broadcast(var/datum/language/language, var/mob/speaker, var/speaker_name, var/message) + return + +/mob/observer/ghost/hear_broadcast(var/datum/language/language, var/mob/speaker, var/speaker_name, var/message) + if(speaker.name == speaker_name || antagHUD) + to_chat(src, "[language.name], [speaker_name] ([ghost_follow_link(speaker, src)]) [message]") + else + to_chat(src, "[language.name], [speaker_name] [message]") + +/datum/language/proc/check_special_condition(var/mob/other) + return 1 + +/datum/language/proc/get_spoken_verb(var/msg_end) + switch(msg_end) + if("!") + return exclaim_verb + if("?") + return ask_verb + return speech_verb + +/datum/language/proc/can_speak_special(var/mob/speaker) + return 1 + +// Language handling. +/mob/proc/add_language(var/language) + + var/datum/language/new_language = all_languages[language] + + if(!istype(new_language) || (new_language in languages)) + return 0 + + languages.Add(new_language) + return 1 + +/mob/proc/remove_language(var/rem_language) + var/datum/language/L = all_languages[rem_language] + . = (L in languages) + languages.Remove(L) + +/mob/living/remove_language(rem_language) + var/datum/language/L = all_languages[rem_language] + if(default_language == L) + default_language = null + return ..() + +// Can we speak this language, as opposed to just understanding it? +/mob/proc/can_speak(datum/language/speaking) + if(!speaking) + return 0 + + if (only_species_language && speaking != all_languages[species_language]) + return 0 + + return (speaking.can_speak_special(src) && (universal_speak || (speaking && speaking.flags & INNATE) || speaking in src.languages)) + +/mob/proc/get_language_prefix() + return get_prefix_key(/decl/prefix/language) + +/mob/proc/is_language_prefix(var/prefix) + return prefix == get_prefix_key(/decl/prefix/language) + +//TBD +/mob/verb/check_languages() + set name = "Check Known Languages" + set category = "IC" + set src = usr + + var/dat = "Known Languages

            " + + for(var/datum/language/L in languages) + if(!(L.flags & NONGLOBAL)) + dat += "[L.name] ([get_language_prefix()][L.key])
            [L.desc]

            " + + src << browse(dat, "window=checklanguage") + return + +/mob/living/check_languages() + var/dat = "Known Languages

            " + + if(default_language) + dat += "Current default language: [default_language]

            " + + for(var/datum/language/L in languages) + if(!(L.flags & NONGLOBAL)) + if(L == default_language) + dat += "[L.name] ([get_language_prefix()][L.key]) - default - [L.desc]

            " + else if (can_speak(L)) + dat += "[L.name] ([get_language_prefix()][L.key]) -
            [L.desc]

            " + else + dat += "[L.name] ([get_language_prefix()][L.key]) - cannot speak!
            [L.desc]

            " + + src << browse(dat, "window=checklanguage") + +/mob/living/Topic(href, href_list) + if(href_list["default_lang"]) + if(href_list["default_lang"] == "reset") + + if (species_language) + set_default_language(all_languages[species_language]) + else + set_default_language(null) + + else + var/datum/language/L = locate(href_list["default_lang"]) + if(L && (L in languages)) + set_default_language(L) + check_languages() + return 1 + 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/language/monkey.dm b/code/modules/mob/language/monkey.dm new file mode 100644 index 00000000..c8921dbc --- /dev/null +++ b/code/modules/mob/language/monkey.dm @@ -0,0 +1,7 @@ +/datum/language/human/monkey + name = "Chimpanzee" + desc = "Ook ook ook." + speech_verb = "chimpers" + ask_verb = "chimpers" + exclaim_verb = "screeches" + key = "m" diff --git a/code/modules/mob/language/outsider.dm b/code/modules/mob/language/outsider.dm new file mode 100644 index 00000000..ca0f19f4 --- /dev/null +++ b/code/modules/mob/language/outsider.dm @@ -0,0 +1,129 @@ +/datum/language/xenocommon + name = "Xenophage" + colour = "alien" + desc = "The common tongue of the xenophages." + speech_verb = "hisses" + ask_verb = "hisses" + exclaim_verb = "hisses" + key = "4" + flags = RESTRICTED + syllables = list("sss","sSs","SSS") + machine_understands = 0 + +/datum/language/xenos + name = "Hivemind" + desc = "Xenophages have the strange ability to commune over a psychic hivemind." + speech_verb = "hisses" + ask_verb = "hisses" + exclaim_verb = "hisses" + colour = "alien" + key = "a" + flags = RESTRICTED | HIVEMIND + +/datum/language/xenos/check_special_condition(var/mob/other) + + var/mob/living/carbon/M = other + if(!istype(M)) + return 1 + if(locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs) + return 1 + + return 0 + +/datum/language/ling + name = "Changeling" + desc = "Although they are normally wary and suspicious of each other, changelings can commune over a distance." + speech_verb = "says" + colour = "changeling" + key = "g" + flags = RESTRICTED | HIVEMIND + +/datum/language/ling/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + + if(speaker.mind && speaker.mind.changeling) + ..(speaker,message,speaker.mind.changeling.changelingID) + else + ..(speaker,message) + +/datum/language/corticalborer + name = "Cortical Link" + desc = "Cortical borers possess a strange link between their tiny minds." + speech_verb = "sings" + ask_verb = "sings" + exclaim_verb = "sings" + colour = "alien" + key = "x" + flags = RESTRICTED | HIVEMIND + +/datum/language/corticalborer/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + + var/mob/living/simple_animal/borer/B + + if(istype(speaker,/mob/living/carbon)) + var/mob/living/carbon/M = speaker + B = M.has_brain_worms() + else if(istype(speaker,/mob/living/simple_animal/borer)) + B = speaker + + if(B) + speaker_mask = B.truename + ..(speaker,message,speaker_mask) + +/datum/language/vox + name = "Vox-pidgin" + desc = "The common tongue of the various Vox ships making up the Shoal. It sounds like chaotic shrieking to everyone else." + speech_verb = "shrieks" + ask_verb = "creels" + exclaim_verb = "SHRIEKS" + colour = "vox" + key = "5" + flags = WHITELISTED + syllables = list("ti","ti","ti","hi","hi","ki","ki","ki","ki","ya","ta","ha","ka","ya","chi","cha","kah", \ + "SKRE","AHK","EHK","RAWK","KRA","AAA","EEE","KI","II","KRI","KA") + machine_understands = 0 + +/datum/language/vox/get_random_name() + return ..(FEMALE,1,6) + +/datum/language/cultcommon + name = LANGUAGE_CULT + desc = "The chants of the occult, the incomprehensible." + speech_verb = "intones" + ask_verb = "intones" + exclaim_verb = "chants" + colour = "cult" + key = "f" + flags = RESTRICTED + space_chance = 100 + syllables = list("ire","ego","nahlizet","certum","veri","jatkaa","mgar","balaq", "karazet", "geeri", \ + "orkan", "allaq", "sas'so", "c'arta", "forbici", "tarem", "n'ath", "reth", "sh'yro", "eth", "d'raggathnor", \ + "mah'weyh", "pleggh", "at", "e'ntrath", "tok-lyr", "rqa'nap", "g'lt-ulotf", "ta'gh", "fara'qha", "fel", "d'amar det", \ + "yu'gular", "faras", "desdae", "havas", "mithum", "javara", "umathar", "uf'kal", "thenar", "rash'tla", \ + "sektath", "mal'zua", "zasan", "therium", "viortia", "kla'atu", "barada", "nikt'o", "fwe'sh", "mah", "erl", "nyag", "r'ya", \ + "gal'h'rfikk", "harfrandid", "mud'gib", "fuu", "ma'jin", "dedo", "ol'btoh", "n'ath", "reth", "sh'yro", "eth", \ + "d'rekkathnor", "khari'd", "gual'te", "nikka", "nikt'o", "barada", "kla'atu", "barhah", "hra" ,"zar'garis") + machine_understands = 0 + +/datum/language/cult + name = "Occult" + desc = "The initiated can share their thoughts by means defying all reason." + speech_verb = "intones" + ask_verb = "intones" + exclaim_verb = "chants" + colour = "cult" + key = "y" + flags = RESTRICTED | HIVEMIND + +/datum/language/bogani + name = LANGUAGE_BOGANI + colour = "alien" + desc = "The language of the Bogani" + speech_verb = "gurgles" + ask_verb = "gurgles" + exclaim_verb = "wails" + key = "i" + flags = RESTRICTED + syllables = list("qy","bok","mok","yok","dy","gly","ryl","byl","dok","paj","kaj","wok","wyl","zak","qum","gyh","thj","qpo","basb","ies","niii", + "eri","erk","eok","eyl","yyl","hyk","qyb","eon","gni","shaf","bissna","goqqo","xokj","wej","nym","assah","qwssa","nieasl","qyno","shaffar", + "egyno","bogani","voijs","nekks","bollos","qoulsan","borrksakja","neemen","aka","nikka","qyegno","shafra","beolas","Byno") + machine_understands = 0 \ No newline at end of file diff --git a/code/modules/mob/language/station.dm b/code/modules/mob/language/station.dm new file mode 100644 index 00000000..e69de29b diff --git a/code/modules/mob/language/synthetic.dm b/code/modules/mob/language/synthetic.dm new file mode 100644 index 00000000..25f48739 --- /dev/null +++ b/code/modules/mob/language/synthetic.dm @@ -0,0 +1,63 @@ +/datum/language/binary + name = "Robot Talk" + desc = "Most human facilities support free-use communications protocols and routing hubs for synthetic use." + colour = "say_quote" + speech_verb = "states" + ask_verb = "queries" + exclaim_verb = "declares" + key = "b" + flags = RESTRICTED | HIVEMIND + var/drone_only + +/datum/language/binary/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + + if(!speaker.binarycheck()) + return + + if (!message) + return + + var/message_start = "[name], [speaker.name]" + var/message_body = "[speaker.say_quote(message)], \"[message]\"" + + for (var/mob/observer/ghost/O in GLOB.ghost_mob_list) + O.show_message("[message_start] ([ghost_follow_link(speaker, O)]) [message_body]", 2) + + for (var/mob/M in GLOB.dead_mob_list_) + if(!istype(M,/mob/new_player) && !istype(M,/mob/living/carbon/brain)) //No meta-evesdropping + M.show_message("[message_start] ([ghost_follow_link(speaker, M)]) [message_body]", 2) + + for (var/mob/living/S in GLOB.living_mob_list_) + if(drone_only && !istype(S,/mob/living/silicon/robot/drone)) + continue + else if(istype(S , /mob/living/silicon/ai)) + message_start = "[name], [speaker.name]" + else if (!S.binarycheck()) + continue + + S.show_message("[message_start] [message_body]", 2) + + var/list/listening = hearers(1, src) + listening -= src + + for (var/mob/living/M in listening) + if(istype(M, /mob/living/silicon) || M.binarycheck()) + continue + M.show_message("synthesised voice beeps, \"beep beep beep\"",2) + + //robot binary xmitter component power usage + if (isrobot(speaker)) + var/mob/living/silicon/robot/R = speaker + var/datum/robot_component/C = R.components["comms"] + R.cell_use_power(C.active_usage) + +/datum/language/binary/drone + name = "Drone Talk" + desc = "A heavily encoded damage control coordination stream." + speech_verb = "transmits" + ask_verb = "transmits" + exclaim_verb = "transmits" + colour = "say_quote" + key = "d" + flags = RESTRICTED | HIVEMIND + drone_only = 1 diff --git a/code/modules/mob/living/autohiss.dm b/code/modules/mob/living/autohiss.dm new file mode 100644 index 00000000..9039ff35 --- /dev/null +++ b/code/modules/mob/living/autohiss.dm @@ -0,0 +1,71 @@ +#define AUTOHISS_NUM 3 + + +/mob/living/proc/handle_autohiss(message, datum/language/L) + return message // no autohiss at this level + +/mob/living/carbon/human/handle_autohiss(message, datum/language/L) + if(!client || get_preference_value(/datum/client_preference/autohiss) == GLOB.PREF_OFF) // no need to process if there's no client or they have autohiss off + return message + return species.handle_autohiss(message, L, get_preference_value(/datum/client_preference/autohiss)) + +/datum/species + var/list/autohiss_basic_map = null + var/list/autohiss_extra_map = null + var/list/autohiss_exempt = null + +/datum/species/unathi + autohiss_basic_map = list( + "s" = list("ss", "sss", "ssss") + ) + autohiss_extra_map = list( + "x" = list("ks", "kss", "ksss") + ) + autohiss_exempt = list(LANGUAGE_UNATHI) + +/datum/species/tajaran + autohiss_basic_map = list( + "r" = list("rr", "rrr", "rrrr") + ) + autohiss_exempt = list(LANGUAGE_SIIK_MAAS) + + +/datum/species/proc/handle_autohiss(message, datum/language/lang, mode) + if(!autohiss_basic_map) + return message + if(lang.flags & NO_STUTTER) // Currently prevents EAL, Sign language, and emotes from autohissing + return message + if(autohiss_exempt && (lang.name in autohiss_exempt)) + return message + + var/map = autohiss_basic_map.Copy() + if(mode == GLOB.PREF_FULL && autohiss_extra_map) + map |= autohiss_extra_map + + . = list() + + while(length(message)) + var/min_index = 10000 // if the message is longer than this, the autohiss is the least of your problems + var/min_char = null + for(var/char in map) + var/i = findtext(message, char) + if(!i) // no more of this character anywhere in the string, don't even bother searching next time + map -= char + else if(i < min_index) + min_index = i + min_char = char + if(!min_char) // we didn't find any of the mapping characters + . += message + break + . += copytext(message, 1, min_index) + if(copytext(message, min_index, min_index+1) == uppertext(min_char)) + switch(text2ascii(message, min_index+1)) + if(65 to 90) // A-Z, uppercase; uppercase R/S followed by another uppercase letter, uppercase the entire replacement string + . += uppertext(pick(map[min_char])) + else + . += capitalize(pick(map[min_char])) + else + . += pick(map[min_char]) + message = copytext(message, min_index + 1) + + return jointext(., null) \ No newline at end of file diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm new file mode 100644 index 00000000..be978cf0 --- /dev/null +++ b/code/modules/mob/living/bot/bot.dm @@ -0,0 +1,430 @@ +/mob/living/bot + name = "Bot" + health = 20 + maxHealth = 20 + icon = 'icons/obj/aibots.dmi' + universal_speak = 1 + density = 0 + var/obj/item/weapon/card/id/botcard = null + var/list/botcard_access = list() + var/on = 1 + var/open = 0 + var/locked = 1 + var/emagged = 0 + var/light_strength = 3 + var/busy = 0 + + var/obj/access_scanner = null + var/list/req_access = list() + var/list/req_one_access = list() + + var/atom/target = null + var/list/ignore_list = list() + var/list/patrol_path = list() + var/list/target_path = list() + var/turf/obstacle = null + + var/wait_if_pulled = 0 // Only applies to moving to the target + var/will_patrol = 0 // If set to 1, will patrol, duh + var/patrol_speed = 1 // How many times per tick we move when patrolling + var/target_speed = 2 // Ditto for chasing the target + var/min_target_dist = 1 // How close we try to get to the target + var/max_target_dist = 50 // How far we are willing to go + var/max_patrol_dist = 250 + var/RequiresAccessToToggle = 0 // If 1, will check access to be turned on/off + + var/target_patience = 5 + var/frustration = 0 + var/max_frustration = 0 + +/mob/living/bot/New() + ..() + update_icons() + + botcard = new /obj/item/weapon/card/id(src) + botcard.access = botcard_access.Copy() + + access_scanner = new /obj(src) + access_scanner.req_access = req_access.Copy() + access_scanner.req_one_access = req_one_access.Copy() + +/mob/living/bot/Initialize() + . = ..() + if(on) + turn_on() // Update lights and other stuff + else + turn_off() + +/mob/living/bot/Life() + ..() + if(health <= 0) + death() + return + weakened = 0 + stunned = 0 + paralysis = 0 + + if(on && !client && !busy) + spawn(0) + handleAI() + +/mob/living/bot/updatehealth() + if(status_flags & GODMODE) + health = maxHealth + set_stat(CONSCIOUS) + else + health = maxHealth - getFireLoss() - getBruteLoss() + setOxyLoss(0) + setToxLoss(0) + +/mob/living/bot/death() + explode() + +/mob/living/bot/attackby(var/obj/item/O, var/mob/user) + if(O.GetIdCard()) + if(access_scanner.allowed(user) && !open) + locked = !locked + to_chat(user, "Controls are now [locked ? "locked." : "unlocked."]") + Interact(usr) + else if(open) + to_chat(user, "Please close the access panel before locking it.") + else + to_chat(user, "Access denied.") + return + else if(isScrewdriver(O)) + if(!locked) + open = !open + to_chat(user, "Maintenance panel is now [open ? "opened" : "closed"].") + Interact(usr) + else + to_chat(user, "You need to unlock the controls first.") + return + else if(isWelder(O)) + if(health < maxHealth) + if(open) + health = min(maxHealth, health + 10) + user.visible_message("\The [user] repairs \the [src].","You repair \the [src].") + else + to_chat(user, "Unable to repair with the maintenance panel closed.") + else + to_chat(user, "\The [src] does not need a repair.") + return + else + ..() + +/mob/living/bot/attack_ai(var/mob/user) + Interact(user) + +/mob/living/bot/attack_hand(var/mob/user) + Interact(user) + +/mob/living/bot/proc/Interact(var/mob/user) + add_fingerprint(user) + var/dat + + var/curText = GetInteractTitle() + if(curText) + dat += curText + dat += "
            " + + curText = GetInteractStatus() + if(curText) + dat += curText + dat += "
            " + + curText = (CanAccessPanel(user)) ? GetInteractPanel() : "The access panel is locked." + if(curText) + dat += curText + dat += "
            " + + curText = (CanAccessMaintenance(user)) ? GetInteractMaintenance() : "The maintenance panel is locked." + if(curText) + dat += curText + + var/datum/browser/popup = new(user, "botpanel", "[src] controls") + popup.set_content(dat) + popup.open() + +/mob/living/bot/Topic(var/href, var/href_list) + if(..()) + return 1 + + if(!issilicon(usr) && !Adjacent(usr)) + return + + if(usr.incapacitated()) + return + + if(href_list["command"]) + ProcessCommand(usr, href_list["command"], href_list) + + Interact(usr) + +/mob/living/bot/proc/GetInteractTitle() + return + +/mob/living/bot/proc/GetInteractStatus() + . = "Status: [on ? "On" : "Off"]" + . += "
            Behaviour controls are [locked ? "locked" : "unlocked"]" + . += "
            Maintenance panel is [open ? "opened" : "closed"]" + +/mob/living/bot/proc/GetInteractPanel() + return + +/mob/living/bot/proc/GetInteractMaintenance() + return + +/mob/living/bot/proc/ProcessCommand(var/mob/user, var/command, var/href_list) + if(command == "toggle" && CanToggle(user)) + if(on) + turn_off() + else + turn_on() + return + +/mob/living/bot/proc/CanToggle(var/mob/user) + return (!RequiresAccessToToggle || access_scanner.allowed(user) || issilicon(user)) + +/mob/living/bot/proc/CanAccessPanel(var/mob/user) + return (!locked || issilicon(user)) + +/mob/living/bot/proc/CanAccessMaintenance(var/mob/user) + return (open || issilicon(user)) + +/mob/living/bot/say(var/message) + var/verb = "beeps" + + message = sanitize(message) + + ..(message, null, verb) + +/mob/living/bot/Bump(var/atom/A) + if(on && botcard && istype(A, /obj/machinery/door)) + var/obj/machinery/door/D = A + if(!istype(D, /obj/machinery/door/firedoor) && !istype(D, /obj/machinery/door/blast) && D.check_access(botcard)) + D.open() + else + ..() + +/mob/living/bot/emag_act(var/remaining_charges, var/mob/user) + return 0 + +/mob/living/bot/proc/handleAI() + if(ignore_list.len) + for(var/atom/A in ignore_list) + if(!A || !A.loc || prob(1)) + ignore_list -= A + handleRegular() + if(target && confirmTarget(target)) + if(Adjacent(target)) + handleAdjacentTarget() + else + handleRangedTarget() + if(!wait_if_pulled || !pulledby) + for(var/i = 1 to target_speed) + sleep(20 / (target_speed + 1)) + stepToTarget() + if(max_frustration && frustration > max_frustration * target_speed) + handleFrustrated(1) + else + resetTarget() + lookForTargets() + if(will_patrol && !pulledby && !target) + if(patrol_path && patrol_path.len) + for(var/i = 1 to patrol_speed) + sleep(20 / (patrol_speed + 1)) + handlePatrol() + if(max_frustration && frustration > max_frustration * patrol_speed) + handleFrustrated(0) + else + startPatrol() + else + handleIdle() + +/mob/living/bot/proc/handleRegular() + return + +/mob/living/bot/proc/handleAdjacentTarget() + return + +/mob/living/bot/proc/handleRangedTarget() + return + +/mob/living/bot/proc/stepToTarget() + if(!target || !target.loc) + return + if(get_dist(src, target) > min_target_dist) + if(!target_path.len || get_turf(target) != target_path[target_path.len]) + calcTargetPath() + if(makeStep(target_path)) + frustration = 0 + else if(max_frustration) + ++frustration + return + +/mob/living/bot/proc/handleFrustrated(var/targ) + obstacle = targ ? target_path[1] : patrol_path[1] + target_path = list() + patrol_path = list() + return + +/mob/living/bot/proc/lookForTargets() + return + +/mob/living/bot/proc/confirmTarget(var/atom/A) + if(A.invisibility >= INVISIBILITY_LEVEL_ONE) + return 0 + if(A in ignore_list) + return 0 + if(!A.loc) + return 0 + return 1 + +/mob/living/bot/proc/handlePatrol() + makeStep(patrol_path) + return + +/mob/living/bot/proc/startPatrol() + var/turf/T = getPatrolTurf() + if(T) + patrol_path = AStar(get_turf(loc), T, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, max_patrol_dist, id = botcard, exclude = obstacle) + if(!patrol_path) + patrol_path = list() + obstacle = null + return + +/mob/living/bot/proc/getPatrolTurf() + var/minDist = INFINITY + var/obj/machinery/navbeacon/targ = locate() in get_turf(src) + + if(!targ) + for(var/obj/machinery/navbeacon/N in navbeacons) + if(!N.codes["patrol"]) + continue + if(get_dist(src, N) < minDist) + minDist = get_dist(src, N) + targ = N + + if(targ && targ.codes["next_patrol"]) + for(var/obj/machinery/navbeacon/N in navbeacons) + if(N.location == targ.codes["next_patrol"]) + targ = N + break + + if(targ) + return get_turf(targ) + return null + +/mob/living/bot/proc/handleIdle() + return + +/mob/living/bot/proc/calcTargetPath() + target_path = AStar(get_turf(loc), get_turf(target), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, max_target_dist, id = botcard, exclude = obstacle) + if(!target_path) + if(target && target.loc) + ignore_list |= target + resetTarget() + obstacle = null + return + +/mob/living/bot/proc/makeStep(var/list/path) + if(!path.len) + return 0 + var/turf/T = path[1] + if(get_turf(src) == T) + path -= T + return makeStep(path) + + return step_towards(src, T) + +/mob/living/bot/proc/resetTarget() + target = null + target_path = list() + frustration = 0 + obstacle = null + +/mob/living/bot/proc/turn_on() + if(stat) + return 0 + on = 1 + set_light(light_strength) + update_icons() + resetTarget() + patrol_path = list() + ignore_list = list() + return 1 + +/mob/living/bot/proc/turn_off() + on = 0 + set_light(0) + update_icons() + +/mob/living/bot/proc/explode() + qdel(src) + +/******************************************************************/ +// Navigation procs +// Used for A-star pathfinding + + +// Returns the surrounding cardinal turfs with open links +// Including through doors openable with the ID +/turf/proc/CardinalTurfsWithAccess(var/obj/item/weapon/card/id/ID) + var/L[] = new() + + // for(var/turf/simulated/t in oview(src,1)) + + for(var/d in GLOB.cardinal) + var/turf/simulated/T = get_step(src, d) + if(istype(T) && !T.density) + if(!LinkBlockedWithAccess(src, T, ID)) + L.Add(T) + return L + + +// Returns true if a link between A and B is blocked +// Movement through doors allowed if ID has access +/proc/LinkBlockedWithAccess(turf/A, turf/B, obj/item/weapon/card/id/ID) + + if(A == null || B == null) return 1 + var/adir = get_dir(A,B) + var/rdir = get_dir(B,A) + if((adir & (NORTH|SOUTH)) && (adir & (EAST|WEST))) // diagonal + var/iStep = get_step(A,adir&(NORTH|SOUTH)) + if(!LinkBlockedWithAccess(A,iStep, ID) && !LinkBlockedWithAccess(iStep,B,ID)) + return 0 + + var/pStep = get_step(A,adir&(EAST|WEST)) + if(!LinkBlockedWithAccess(A,pStep,ID) && !LinkBlockedWithAccess(pStep,B,ID)) + return 0 + return 1 + + if(DirBlockedWithAccess(A,adir, ID)) + return 1 + + if(DirBlockedWithAccess(B,rdir, ID)) + return 1 + + for(var/obj/O in B) + if(O.density && !istype(O, /obj/machinery/door) && !(O.atom_flags & ATOM_FLAG_CHECKS_BORDER)) + return 1 + + return 0 + +// Returns true if direction is blocked from loc +// Checks doors against access with given ID +/proc/DirBlockedWithAccess(turf/loc,var/dir,var/obj/item/weapon/card/id/ID) + for(var/obj/structure/window/D in loc) + if(!D.density) continue + if(D.dir == SOUTHWEST) return 1 + if(D.dir == dir) return 1 + + for(var/obj/machinery/door/D in loc) + if(!D.density) continue + if(istype(D, /obj/machinery/door/window)) + if( dir & D.dir ) return !D.check_access(ID) + + //if((dir & SOUTH) && (D.dir & (EAST|WEST))) return !D.check_access(ID) + //if((dir & EAST ) && (D.dir & (NORTH|SOUTH))) return !D.check_access(ID) + else return !D.check_access(ID) // it's a real, air blocking door + return 0 diff --git a/code/modules/mob/living/bot/cleanbot.dm b/code/modules/mob/living/bot/cleanbot.dm new file mode 100644 index 00000000..ad7c65bc --- /dev/null +++ b/code/modules/mob/living/bot/cleanbot.dm @@ -0,0 +1,188 @@ +/mob/living/bot/cleanbot + name = "Cleanbot" + desc = "A little cleaning robot, he looks so excited!" + icon_state = "cleanbot0" + req_one_access = list(access_janitor, access_robotics) + botcard_access = list(access_janitor, access_maint_tunnels) + + wait_if_pulled = 1 + min_target_dist = 0 + + var/cleaning = 0 + var/screwloose = 0 + var/oddbutton = 0 + var/blood = 1 + var/list/target_types = list() + +/mob/living/bot/cleanbot/New() + ..() + get_targets() + +/mob/living/bot/cleanbot/handleIdle() + if(!screwloose && !oddbutton && prob(5)) + visible_message("\The [src] makes an excited beeping booping sound!") + + if(screwloose && prob(5)) // Make a mess + if(istype(loc, /turf/simulated)) + var/turf/simulated/T = loc + T.wet_floor() + + if(oddbutton && prob(5)) // Make a big mess + visible_message("Something flies out of [src]. He seems to be acting oddly.") + var/obj/effect/decal/cleanable/blood/gibs/gib = new /obj/effect/decal/cleanable/blood/gibs(loc) + var/weakref/g = weakref(gib) + ignore_list += g + spawn(600) + ignore_list -= g + +/mob/living/bot/cleanbot/lookForTargets() + for(var/obj/effect/decal/cleanable/D in view(world.view, src)) // There was some odd code to make it start with nearest decals, it's unnecessary, this works + if(confirmTarget(D)) + target = D + return + +/mob/living/bot/cleanbot/confirmTarget(var/obj/effect/decal/cleanable/D) + if(!..()) + return 0 + for(var/T in target_types) + if(istype(D, T)) + return 1 + return 0 + +/mob/living/bot/cleanbot/handleAdjacentTarget() + if(get_turf(target) == src.loc) + UnarmedAttack(target) + +/mob/living/bot/cleanbot/UnarmedAttack(var/obj/effect/decal/cleanable/D, var/proximity) + if(!..()) + return + + if(!istype(D)) + return + + if(D.loc != loc) + return + + busy = 1 + visible_message("\The [src] begins to clean up \the [D]") + update_icons() + var/cleantime = istype(D, /obj/effect/decal/cleanable/dirt) ? 10 : 50 + if(do_after(src, cleantime, progress = 0)) + if(istype(loc, /turf/simulated)) + var/turf/simulated/f = loc + f.dirt = 0 + if(!D) + return + qdel(D) + if(D == target) + target = null + busy = 0 + update_icons() + +/mob/living/bot/cleanbot/explode() + on = 0 + visible_message("[src] blows apart!") + var/turf/Tsec = get_turf(src) + + new /obj/item/weapon/reagent_containers/glass/bucket(Tsec) + new /obj/item/device/assembly/prox_sensor(Tsec) + if(prob(50)) + new /obj/item/robot_parts/l_arm(Tsec) + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + qdel(src) + return + +/mob/living/bot/cleanbot/update_icons() + if(busy) + icon_state = "cleanbot-c" + else + icon_state = "cleanbot[on]" + +/mob/living/bot/cleanbot/GetInteractTitle() + . = "Cleanbot controls" + . += "Automatic Cleaner v1.0" + +/mob/living/bot/cleanbot/GetInteractPanel() + . = "Cleans blood: [blood ? "Yes" : "No"]" + . += "
            Patrol station: [will_patrol ? "Yes" : "No"]" + +/mob/living/bot/cleanbot/GetInteractMaintenance() + . = "Odd looking screw twiddled: [screwloose ? "Yes" : "No"]" + . += "
            Weird button pressed: [oddbutton ? "Yes" : "No"]" + +/mob/living/bot/cleanbot/ProcessCommand(var/mob/user, var/command, var/href_list) + ..() + if(CanAccessPanel(user)) + switch(command) + if("blood") + blood = !blood + get_targets() + if("patrol") + will_patrol = !will_patrol + patrol_path = null + + if(CanAccessMaintenance(user)) + switch(command) + if("screw") + screwloose = !screwloose + if("oddbutton") + oddbutton = !oddbutton + +/mob/living/bot/cleanbot/emag_act(var/remaining_uses, var/mob/user) + . = ..() + if(!screwloose || !oddbutton) + if(user) + to_chat(user, "The [src] buzzes and beeps.") + oddbutton = 1 + screwloose = 1 + return 1 + +/mob/living/bot/cleanbot/proc/get_targets() + target_types = list() + + target_types += /obj/effect/decal/cleanable/blood/oil + target_types += /obj/effect/decal/cleanable/vomit + target_types += /obj/effect/decal/cleanable/crayon + target_types += /obj/effect/decal/cleanable/liquid_fuel + target_types += /obj/effect/decal/cleanable/mucus + target_types += /obj/effect/decal/cleanable/dirt + + if(blood) + target_types += /obj/effect/decal/cleanable/blood + +/* Assembly */ + +/obj/item/weapon/bucket_sensor + desc = "It's a bucket. With a sensor attached." + name = "proxy bucket" + icon = 'icons/obj/aibots.dmi' + icon_state = "bucket_proxy" + force = 3.0 + throwforce = 10.0 + throw_speed = 2 + throw_range = 5 + w_class = ITEM_SIZE_NORMAL + var/created_name = "Cleanbot" + +/obj/item/weapon/bucket_sensor/attackby(var/obj/item/O, var/mob/user) + ..() + if(istype(O, /obj/item/robot_parts/l_arm) || istype(O, /obj/item/robot_parts/r_arm)) + user.drop_item() + qdel(O) + var/turf/T = get_turf(loc) + var/mob/living/bot/cleanbot/A = new /mob/living/bot/cleanbot(T) + A.SetName(created_name) + to_chat(user, "You add the robot arm to the bucket and sensor assembly. Beep boop!") + user.drop_from_inventory(src) + qdel(src) + + else if(istype(O, /obj/item/weapon/pen)) + var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN) + if(!t) + return + if(!in_range(src, usr) && src.loc != usr) + return + created_name = t diff --git a/code/modules/mob/living/bot/ed209bot.dm b/code/modules/mob/living/bot/ed209bot.dm new file mode 100644 index 00000000..2926af01 --- /dev/null +++ b/code/modules/mob/living/bot/ed209bot.dm @@ -0,0 +1,190 @@ +/mob/living/bot/secbot/ed209 + name = "ED-209 Security Robot" + desc = "A security robot. He looks less than thrilled." + icon = 'icons/obj/aibots.dmi' + icon_state = "ed2090" + attack_state = "ed209-c" + density = 1 + health = 100 + maxHealth = 100 + + is_ranged = 1 + preparing_arrest_sounds = new() + + a_intent = I_HURT + mob_bump_flag = HEAVY + mob_swap_flags = ~HEAVY + mob_push_flags = HEAVY + + var/shot_delay = 4 + var/last_shot = 0 + +/mob/living/bot/secbot/ed209/update_icons() + icon_state = "ed2090" + +/mob/living/bot/secbot/ed209/explode() + visible_message("[src] blows apart!") + var/turf/Tsec = get_turf(src) + + new /obj/item/weapon/secbot_assembly/ed209_assembly(Tsec) + + var/obj/item/weapon/gun/energy/taser/G = new /obj/item/weapon/gun/energy/taser(Tsec) + G.power_supply.charge = 0 + if(prob(50)) + new /obj/item/robot_parts/l_leg(Tsec) + if(prob(50)) + new /obj/item/robot_parts/r_leg(Tsec) + if(prob(50)) + if(prob(50)) + new /obj/item/clothing/head/helmet(Tsec) + else + new /obj/item/clothing/suit/armor/vest(Tsec) + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + + new /obj/effect/decal/cleanable/blood/oil(Tsec) + qdel(src) + +/mob/living/bot/secbot/ed209/handleRangedTarget() + RangedAttack(target) + +/mob/living/bot/secbot/ed209/RangedAttack(var/atom/A) + if(last_shot + shot_delay > world.time) + to_chat(src, "You are not ready to fire yet!") + return + + last_shot = world.time + var/projectile = /obj/item/projectile/energy/laser// /obj/item/projectile/beam/stun + if(emagged) + projectile = /obj/item/projectile/energy/laser // /obj/item/projectile/beam + + playsound(loc, emagged ? 'sound/weapons/Laser.ogg' : 'sound/weapons/Taser.ogg', 50, 1) + var/obj/item/projectile/P = new projectile(loc) + var/def_zone = get_exposed_defense_zone(A) + P.launch_projectile(A, def_zone) +// Assembly + +/obj/item/weapon/secbot_assembly/ed209_assembly + name = "ED-209 assembly" + desc = "Some sort of bizarre assembly." + icon = 'icons/obj/aibots.dmi' + icon_state = "ed209_frame" + item_state = "ed209_frame" + created_name = "ED-209 Security Robot" + var/lasercolor = "" + +/obj/item/weapon/secbot_assembly/ed209_assembly/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + ..() + + if(istype(W, /obj/item/weapon/pen)) + var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN) + if(!t) + return + if(!in_range(src, usr) && src.loc != usr) + return + created_name = t + return + + switch(build_step) + if(0, 1) + if(istype(W, /obj/item/robot_parts/l_leg) || istype(W, /obj/item/robot_parts/r_leg)) + user.drop_item() + qdel(W) + build_step++ + to_chat(user, "You add the robot leg to [src].") + SetName("legs/frame assembly") + if(build_step == 1) + item_state = "ed209_leg" + icon_state = "ed209_leg" + else + item_state = "ed209_legs" + icon_state = "ed209_legs" + + if(2) + if(istype(W, /obj/item/clothing/suit/storage/vest) || istype(W, /obj/item/clothing/suit/armor/pcarrier) || istype(W, /obj/item/clothing/accessory/armorplate)) + if(istype(W, /obj/item/clothing/suit/armor/pcarrier)) + if(!locate(/obj/item/clothing/accessory/armorplate) in W.contents) + to_chat(user, "There's no armor plates on this [W].") + return + user.drop_item() + qdel(W) + build_step++ + to_chat(user, "You add [W] to [src].") + SetName("vest/legs/frame assembly") + item_state = "ed209_shell" + icon_state = "ed209_shell" + + if(3) + if(isWelder(W)) + var/obj/item/weapon/weldingtool/WT = W + if(WT.remove_fuel(0, user)) + build_step++ + SetName("shielded frame assembly") + to_chat(user, "You welded the vest to [src].") + if(4) + if(istype(W, /obj/item/clothing/head/helmet)) + user.drop_item() + qdel(W) + build_step++ + to_chat(user, "You add the helmet to [src].") + SetName("covered and shielded frame assembly") + item_state = "ed209_hat" + icon_state = "ed209_hat" + + if(5) + if(isprox(W)) + user.drop_item() + qdel(W) + build_step++ + to_chat(user, "You add the prox sensor to [src].") + SetName("covered, shielded and sensored frame assembly") + item_state = "ed209_prox" + icon_state = "ed209_prox" + + if(6) + if(isCoil(W)) + var/obj/item/stack/cable_coil/C = W + if (C.get_amount() < 1) + to_chat(user, "You need one coil of wire to wire [src].") + return + to_chat(user, "You start to wire [src].") + if(do_after(user, 40, src) && build_step == 6) + if(C.use(1)) + build_step++ + to_chat(user, "You wire the ED-209 assembly.") + SetName("wired ED-209 assembly") + return + + if(7) + if(istype(W, /obj/item/weapon/gun/energy/taser)) + SetName("taser ED-209 assembly") + build_step++ + to_chat(user, "You add [W] to [src].") + item_state = "ed209_taser" + icon_state = "ed209_taser" + user.drop_item() + qdel(W) + + if(8) + if(isScrewdriver(W)) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) + var/turf/T = get_turf(user) + to_chat(user, "Now attaching the gun to the frame...") + sleep(40) + if(get_turf(user) == T && build_step == 8) + build_step++ + SetName("armed [name]") + to_chat(user, "Taser gun attached.") + + if(9) + if(istype(W, /obj/item/weapon/cell)) + build_step++ + to_chat(user, "You complete the ED-209.") + var/turf/T = get_turf(src) + new /mob/living/bot/secbot/ed209(T,created_name,lasercolor) + user.drop_item() + qdel(W) + user.drop_from_inventory(src) + qdel(src) diff --git a/code/modules/mob/living/bot/farmbot.dm b/code/modules/mob/living/bot/farmbot.dm new file mode 100644 index 00000000..8ff52484 --- /dev/null +++ b/code/modules/mob/living/bot/farmbot.dm @@ -0,0 +1,357 @@ +#define FARMBOT_COLLECT 1 +#define FARMBOT_WATER 2 +#define FARMBOT_UPROOT 3 +#define FARMBOT_NUTRIMENT 4 + +/mob/living/bot/farmbot + name = "Farmbot" + desc = "The botanist's best friend." + icon = 'icons/obj/aibots.dmi' + icon_state = "farmbot0" + health = 50 + maxHealth = 50 + req_one_access = list(access_hydroponics, access_robotics) + + var/action = "" // Used to update icon + var/waters_trays = 1 + var/refills_water = 1 + var/uproots_weeds = 1 + var/replaces_nutriment = 0 + var/collects_produce = 0 + var/removes_dead = 0 + + var/obj/structure/reagent_dispensers/watertank/tank + +/mob/living/bot/farmbot/New(var/newloc, var/newTank) + ..(newloc) + if(!newTank) + newTank = new /obj/structure/reagent_dispensers/watertank(src) + tank = newTank + tank.forceMove(src) + +/mob/living/bot/farmbot/premade + name = "Old Ben" + on = 0 + +/mob/living/bot/farmbot/GetInteractTitle() + . = "Farmbot controls" + . += "Automatic Hyrdoponic Assisting Unit v1.0" + +/mob/living/bot/farmbot/GetInteractStatus() + . = ..() + . += "
            Water tank: " + if(tank) + . += "[tank.reagents.total_volume]/[tank.reagents.maximum_volume]" + else + . += "error: not found" + +/mob/living/bot/farmbot/GetInteractPanel() + . = "Water plants : [waters_trays ? "Yes" : "No"]" + . += "
            Refill watertank : [refills_water ? "Yes" : "No"]" + . += "
            Weed plants: [uproots_weeds ? "Yes" : "No"]" + . += "
            Replace fertilizer: [replaces_nutriment ? "Yes" : "No"]" + . += "
            Collect produce: [collects_produce ? "Yes" : "No"]" + . += "
            Remove dead plants: [removes_dead ? "Yes" : "No"]" + +/mob/living/bot/farmbot/GetInteractMaintenance() + . = "Plant identifier status: " + switch(emagged) + if(0) + . += "Normal" + if(1) + . += "Scrambled (DANGER)" + if(2) + . += "ERROROROROROR-----" + +/mob/living/bot/farmbot/ProcessCommand(var/mob/user, var/command, var/href_list) + ..() + if(CanAccessPanel(user)) + switch(command) + if("water") + waters_trays = !waters_trays + if("refill") + refills_water = !refills_water + if("weed") + uproots_weeds = !uproots_weeds + if("replacenutri") + replaces_nutriment = !replaces_nutriment + if("collect") + collects_produce = !collects_produce + if("removedead") + removes_dead = !removes_dead + + if(CanAccessMaintenance(user)) + switch(command) + if("emag") + if(emagged < 2) + emagged = !emagged + +/mob/living/bot/farmbot/emag_act(var/remaining_charges, var/mob/user) + . = ..() + if(!emagged) + if(user) + to_chat(user, "You short out [src]'s plant identifier circuits.") + ignore_list |= user + emagged = 2 + return 1 + +/mob/living/bot/farmbot/update_icons() + if(on && action) + icon_state = "farmbot_[action]" + else + icon_state = "farmbot[on]" + +/mob/living/bot/farmbot/handleRegular() + if(emagged && prob(1)) + flick("farmbot_broke", src) + +/mob/living/bot/farmbot/handleAdjacentTarget() + UnarmedAttack(target) + +/mob/living/bot/farmbot/lookForTargets() + if(emagged) + for(var/mob/living/carbon/human/H in view(7, src)) + target = H + return + else + for(var/obj/machinery/portable_atmospherics/hydroponics/tray in view(7, src)) + if(confirmTarget(tray)) + target = tray + return + if(!target && refills_water && tank && tank.reagents.total_volume < tank.reagents.maximum_volume) + for(var/obj/structure/sink/source in view(7, src)) + target = source + return + +/mob/living/bot/farmbot/calcTargetPath() // We need to land NEXT to the tray, because the tray itself is impassable + for(var/trayDir in list(NORTH, SOUTH, EAST, WEST)) + target_path = AStar(get_turf(loc), get_step(get_turf(target), trayDir), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, max_target_dist, id = botcard) + if(target_path) + break + if(!target_path) + ignore_list |= target + target = null + target_path = list() + return + +/mob/living/bot/farmbot/stepToTarget() // Same reason + var/turf/T = get_turf(target) + if(!target_path.len || !T.Adjacent(target_path[target_path.len])) + calcTargetPath() + makeStep(target_path) + return + +/mob/living/bot/farmbot/UnarmedAttack(var/atom/A, var/proximity) + if(!..()) + return + if(busy) + return + + if(istype(A, /obj/machinery/portable_atmospherics/hydroponics)) + var/obj/machinery/portable_atmospherics/hydroponics/T = A + var/t = confirmTarget(T) + switch(t) + if(0) + return + if(FARMBOT_COLLECT) + action = "water" // Needs a better one + update_icons() + visible_message("[src] starts [T.dead? "removing the plant from" : "harvesting"] \the [A].") + busy = 1 + if(do_after(src, 30, A)) + visible_message("[src] [T.dead? "removes the plant from" : "harvests"] \the [A].") + T.attack_hand(src) + if(FARMBOT_WATER) + action = "water" + update_icons() + visible_message("[src] starts watering \the [A].") + busy = 1 + if(do_after(src, 30, A)) + playsound(loc, 'sound/effects/slosh.ogg', 25, 1) + visible_message("[src] waters \the [A].") + tank.reagents.trans_to(T, 100 - T.waterlevel) + if(FARMBOT_UPROOT) + action = "hoe" + update_icons() + visible_message("[src] starts uprooting the weeds in \the [A].") + busy = 1 + if(do_after(src, 30, A)) + visible_message("[src] uproots the weeds in \the [A].") + T.weedlevel = 0 + if(FARMBOT_NUTRIMENT) + action = "fertile" + update_icons() + visible_message("[src] starts fertilizing \the [A].") + busy = 1 + if(do_after(src, 30, A)) + visible_message("[src] fertilizes \the [A].") + T.reagents.add_reagent(/datum/reagent/ammonia, 10) + busy = 0 + action = "" + update_icons() + T.update_icon() + else if(istype(A, /obj/structure/sink)) + if(!tank || tank.reagents.total_volume >= tank.reagents.maximum_volume) + return + action = "water" + update_icons() + visible_message("[src] starts refilling its tank from \the [A].") + busy = 1 + while(do_after(src, 10) && tank.reagents.total_volume < tank.reagents.maximum_volume) + tank.reagents.add_reagent(/datum/reagent/water, 10) + if(prob(5)) + playsound(loc, 'sound/effects/slosh.ogg', 25, 1) + busy = 0 + action = "" + update_icons() + visible_message("[src] finishes refilling its tank.") + else if(emagged && ishuman(A)) + var/action = pick("weed", "water") + busy = 1 + spawn(50) // Some delay + busy = 0 + switch(action) + if("weed") + flick("farmbot_hoe", src) + do_attack_animation(A) + if(prob(50)) + visible_message("[src] swings wildly at [A] with a minihoe, missing completely!") + return + var/t = pick("slashed", "sliced", "cut", "clawed") + A.attack_generic(src, 5, t) + if("water") + flick("farmbot_water", src) + visible_message("[src] splashes [A] with water!") + tank.reagents.splash(A, 100) + +/mob/living/bot/farmbot/explode() + visible_message("[src] blows apart!") + var/turf/Tsec = get_turf(src) + + new /obj/item/weapon/material/minihoe(Tsec) + new /obj/item/weapon/reagent_containers/glass/bucket(Tsec) + new /obj/item/device/assembly/prox_sensor(Tsec) + new /obj/item/device/analyzer/plant_analyzer(Tsec) + + if(tank) + tank.loc = Tsec + + if(prob(50)) + new /obj/item/robot_parts/l_arm(Tsec) + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + qdel(src) + return + +/mob/living/bot/farmbot/confirmTarget(var/atom/targ) + if(!..()) + return 0 + + if(emagged && ishuman(targ)) + if(targ in view(world.view, src)) + return 1 + return 0 + + if(istype(targ, /obj/structure/sink)) + if(!tank || tank.reagents.total_volume >= tank.reagents.maximum_volume) + return 0 + return 1 + + var/obj/machinery/portable_atmospherics/hydroponics/tray = targ + if(!istype(tray)) + return 0 + + if(tray.closed_system || !tray.seed) + return 0 + + if(tray.dead && removes_dead || tray.harvest && collects_produce) + return FARMBOT_COLLECT + + else if(refills_water && tray.waterlevel < 40 && !tray.reagents.has_reagent(/datum/reagent/water)) + return FARMBOT_WATER + + else if(uproots_weeds && tray.weedlevel > 3) + return FARMBOT_UPROOT + + else if(replaces_nutriment && tray.nutrilevel < 1 && tray.reagents.total_volume < 1) + return FARMBOT_NUTRIMENT + + return 0 + +// Assembly + +/obj/item/weapon/farmbot_arm_assembly + name = "water tank/robot arm assembly" + desc = "A water tank with a robot arm permanently grafted to it." + icon = 'icons/obj/aibots.dmi' + icon_state = "water_arm" + var/build_step = 0 + var/created_name = "Farmbot" + var/obj/tank + w_class = ITEM_SIZE_NORMAL + +/obj/item/weapon/farmbot_arm_assembly/New(var/newloc, var/theTank) + ..(newloc) + if(!theTank) // If an admin spawned it, it won't have a watertank it, so lets make one for em! + tank = new /obj/structure/reagent_dispensers/watertank(src) + else + tank = theTank + tank.forceMove(src) + + +/obj/structure/reagent_dispensers/watertank/attackby(var/obj/item/robot_parts/S, mob/user as mob) + if ((!istype(S, /obj/item/robot_parts/l_arm)) && (!istype(S, /obj/item/robot_parts/r_arm))) + ..() + return + + to_chat(user, "You add the robot arm to [src].") + user.drop_from_inventory(S) + qdel(S) + new /obj/item/weapon/farmbot_arm_assembly(loc, src) + +/obj/item/weapon/farmbot_arm_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + if((istype(W, /obj/item/device/analyzer/plant_analyzer)) && (build_step == 0)) + build_step++ + to_chat(user, "You add the plant analyzer to [src].") + SetName("farmbot assembly") + user.remove_from_mob(W) + qdel(W) + + else if((istype(W, /obj/item/weapon/reagent_containers/glass/bucket)) && (build_step == 1)) + build_step++ + to_chat(user, "You add a bucket to [src].") + SetName("farmbot assembly with bucket") + user.remove_from_mob(W) + qdel(W) + + else if((istype(W, /obj/item/weapon/material/minihoe)) && (build_step == 2)) + build_step++ + to_chat(user, "You add a minihoe to [src].") + SetName("farmbot assembly with bucket and minihoe") + user.remove_from_mob(W) + qdel(W) + + else if((isprox(W)) && (build_step == 3)) + build_step++ + to_chat(user, "You complete the Farmbot! Beep boop.") + var/mob/living/bot/farmbot/S = new /mob/living/bot/farmbot(get_turf(src), tank) + S.SetName(created_name) + user.remove_from_mob(W) + qdel(W) + qdel(src) + + else if(istype(W, /obj/item/weapon/pen)) + var/t = input(user, "Enter new robot name", name, created_name) as text + t = sanitize(t, MAX_NAME_LEN) + if(!t) + return + if(!in_range(src, usr) && loc != usr) + return + + created_name = t + +/obj/item/weapon/farmbot_arm_assembly/attack_hand(mob/user as mob) + return //it's a converted watertank, no you cannot pick it up and put it in your backpack diff --git a/code/modules/mob/living/bot/floorbot.dm b/code/modules/mob/living/bot/floorbot.dm new file mode 100644 index 00000000..313d8a1e --- /dev/null +++ b/code/modules/mob/living/bot/floorbot.dm @@ -0,0 +1,297 @@ +/mob/living/bot/floorbot + name = "Floorbot" + desc = "A little floor repairing robot, he looks so excited!" + icon_state = "floorbot0" + req_one_access = list(access_construction, access_robotics) + wait_if_pulled = 1 + min_target_dist = 0 + + var/amount = 10 // 1 for tile, 2 for lattice + var/maxAmount = 60 + var/tilemake = 0 // When it reaches 100, bot makes a tile + var/improvefloors = 0 + var/eattiles = 0 + var/maketiles = 0 + var/floor_build_type = /decl/flooring/tiling // Basic steel floor. + +/mob/living/bot/floorbot/premade + name = "Rusty" + on = 0 + +/mob/living/bot/floorbot/update_icons() + if(busy) + icon_state = "floorbot-c" + else if(amount > 0) + icon_state = "floorbot[on]" + else + icon_state = "floorbot[on]e" + +/mob/living/bot/floorbot/GetInteractTitle() + . = "Repairbot v1.0 controls" + . += "Automatic Floor Repairer v1.0" + +/mob/living/bot/floorbot/GetInteractStatus() + . = ..() + . += "
            Tiles left: [amount]" + +/mob/living/bot/floorbot/GetInteractPanel() + . = "Improves floors: [improvefloors ? "Yes" : "No"]" + . += "
            Finds tiles: [eattiles ? "Yes" : "No"]" + . += "
            Make singles pieces of metal into tiles when empty: [maketiles ? "Yes" : "No"]" + +/mob/living/bot/floorbot/GetInteractMaintenance() + . = "Disassembly mode: " + switch(emagged) + if(0) + . += "Off" + if(1) + . += "On (Caution)" + if(2) + . += "ERROROROROROR-----" + +/mob/living/bot/floorbot/ProcessCommand(var/mob/user, var/command, var/href_list) + ..() + if(CanAccessPanel(user)) + switch(command) + if("improve") + improvefloors = !improvefloors + if("tiles") + eattiles = !eattiles + if("make") + maketiles = !maketiles + + if(CanAccessMaintenance(user)) + switch(command) + if("emag") + if(emagged < 2) + emagged = !emagged + +/mob/living/bot/floorbot/emag_act(var/remaining_charges, var/mob/user) + . = ..() + if(!emagged) + emagged = 1 + if(user) + to_chat(user, "The [src] buzzes and beeps.") + return 1 + +/mob/living/bot/floorbot/handleRegular() + ++tilemake + if(tilemake >= 100) + tilemake = 0 + addTiles(1) + + if(prob(1)) + custom_emote(2, "makes an excited booping beeping sound!") + +/mob/living/bot/floorbot/handleAdjacentTarget() + if(get_turf(target) == src.loc) + UnarmedAttack(target) + +/mob/living/bot/floorbot/lookForTargets() + for(var/turf/simulated/floor/T in view(src)) + if(confirmTarget(T)) + target = T + return + + if(amount < maxAmount && (eattiles || maketiles)) + for(var/obj/item/stack/S in view(src)) + if(confirmTarget(S)) + target = S + return + +/mob/living/bot/floorbot/confirmTarget(var/atom/A) // The fact that we do some checks twice may seem confusing but remember that the bot's settings may be toggled while it's moving and we want them to stop in that case + if(!..()) + return 0 + + if(istype(A, /obj/item/stack/tile/floor)) + return (amount < maxAmount && eattiles) + if(istype(A, /obj/item/stack/material/steel)) + return (amount < maxAmount && maketiles) + + if(A.loc.name == "Space") + return 0 + + var/turf/simulated/floor/T = A + if(istype(T)) + if(emagged) + return 1 + else + return (amount && (T.broken || T.burnt || (improvefloors && !T.flooring))) + +/mob/living/bot/floorbot/UnarmedAttack(var/atom/A, var/proximity) + if(!..()) + return + + if(busy) + return + + if(get_turf(A) != loc) + return + + if(emagged && istype(A, /turf/simulated/floor)) + var/turf/simulated/floor/F = A + busy = 1 + update_icons() + if(F.flooring) + visible_message("[src] begins to tear the floor tile from the floor.") + if(do_after(src, 50, F)) + F.break_tile_to_plating() + addTiles(1) + else + visible_message("[src] begins to tear through the floor!") + if(do_after(src, 150, F)) // Extra time because this can and will kill. + F.ReplaceWithLattice() + addTiles(1) + target = null + update_icons() + else if(istype(A, /turf/simulated/floor)) + var/turf/simulated/floor/F = A + if(F.broken || F.burnt) + busy = 1 + update_icons() + visible_message("[src] begins to remove the broken floor.") + if(do_after(src, 50, F)) + if(F.broken || F.burnt) + F.make_plating() + target = null + busy = 0 + update_icons() + else if(!F.flooring && amount) + busy = 1 + update_icons() + visible_message("[src] begins to improve the floor.") + if(do_after(src, 50, F)) + if(!F.flooring) + F.set_flooring(get_flooring_data(floor_build_type)) + addTiles(-1) + target = null + update_icons() + else if(istype(A, /obj/item/stack/tile/floor) && amount < maxAmount) + var/obj/item/stack/tile/floor/T = A + visible_message("\The [src] begins to collect tiles.") + busy = 1 + update_icons() + if(do_after(src, 20)) + if(T) + var/eaten = min(maxAmount - amount, T.get_amount()) + T.use(eaten) + addTiles(eaten) + target = null + update_icons() + else if(istype(A, /obj/item/stack/material) && amount + 4 <= maxAmount) + var/obj/item/stack/material/M = A + if(M.get_material_name() == DEFAULT_WALL_MATERIAL) + visible_message("\The [src] begins to make tiles.") + busy = 1 + update_icons() + if(do_after(src, 50)) + if(M) + M.use(1) + addTiles(4) + +/mob/living/bot/floorbot/explode() + turn_off() + visible_message("[src] blows apart!") + var/turf/Tsec = get_turf(src) + + var/obj/item/weapon/storage/toolbox/mechanical/N = new /obj/item/weapon/storage/toolbox/mechanical(Tsec) + N.contents = list() + new /obj/item/device/assembly/prox_sensor(Tsec) + if(prob(50)) + new /obj/item/robot_parts/l_arm(Tsec) + var/obj/item/stack/tile/floor/T = new /obj/item/stack/tile/floor(Tsec) + T.amount = amount + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + qdel(src) + +/mob/living/bot/floorbot/proc/addTiles(var/am) + amount += am + if(amount < 0) + amount = 0 + else if(amount > maxAmount) + amount = maxAmount + busy = FALSE + + +/* Assembly */ + +/obj/item/weapon/storage/toolbox/mechanical/attackby(var/obj/item/stack/tile/floor/T, mob/user as mob) + if(!istype(T, /obj/item/stack/tile/floor)) + ..() + return + if(contents.len >= 1) + to_chat(user, "They wont fit in as there is already stuff inside.") + return + if(user.s_active) + user.s_active.close(user) + if(T.use(10)) + var/obj/item/weapon/toolbox_tiles/B = new /obj/item/weapon/toolbox_tiles + user.put_in_hands(B) + to_chat(user, "You add the tiles into the empty toolbox. They protrude from the top.") + user.drop_from_inventory(src) + qdel(src) + else + to_chat(user, "You need 10 floor tiles for a floorbot.") + return + +/obj/item/weapon/toolbox_tiles + desc = "It's a toolbox with tiles sticking out the top." + name = "tiles and toolbox" + icon = 'icons/obj/aibots.dmi' + icon_state = "toolbox_tiles" + force = 3.0 + throwforce = 10.0 + throw_speed = 2 + throw_range = 5 + w_class = ITEM_SIZE_NORMAL + var/created_name = "Floorbot" + +/obj/item/weapon/toolbox_tiles/attackby(var/obj/item/W, mob/user as mob) + ..() + if(isprox(W)) + qdel(W) + var/obj/item/weapon/toolbox_tiles_sensor/B = new /obj/item/weapon/toolbox_tiles_sensor() + B.created_name = created_name + user.put_in_hands(B) + to_chat(user, "You add the sensor to the toolbox and tiles!") + user.drop_from_inventory(src) + qdel(src) + else if (istype(W, /obj/item/weapon/pen)) + var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN) + if(!t) + return + if(!in_range(src, user) && loc != user) + return + created_name = t + +/obj/item/weapon/toolbox_tiles_sensor + desc = "It's a toolbox with tiles sticking out the top and a sensor attached." + name = "tiles, toolbox and sensor arrangement" + icon = 'icons/obj/aibots.dmi' + icon_state = "toolbox_tiles_sensor" + force = 3.0 + throwforce = 10.0 + throw_speed = 2 + throw_range = 5 + w_class = ITEM_SIZE_NORMAL + var/created_name = "Floorbot" + +/obj/item/weapon/toolbox_tiles_sensor/attackby(var/obj/item/W, mob/user as mob) + ..() + if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm)) + qdel(W) + var/turf/T = get_turf(user.loc) + var/mob/living/bot/floorbot/A = new /mob/living/bot/floorbot(T) + A.SetName(created_name) + to_chat(user, "You add the robot arm to the odd looking toolbox assembly! Boop beep!") + user.drop_from_inventory(src) + qdel(src) + else if(istype(W, /obj/item/weapon/pen)) + var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN) + if(!t) + return + if(!in_range(src, user) && loc != user) + return + created_name = t diff --git a/code/modules/mob/living/bot/medbot.dm b/code/modules/mob/living/bot/medbot.dm new file mode 100644 index 00000000..f64b7f7c --- /dev/null +++ b/code/modules/mob/living/bot/medbot.dm @@ -0,0 +1,325 @@ +/mob/living/bot/medbot + name = "Medbot" + desc = "A little medical robot. He looks somewhat underwhelmed." + icon_state = "medibot0" + req_one_access = list(access_medical, access_robotics) + botcard_access = list(access_medical, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics) + + var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits. + + //AI vars + var/last_newpatient_speak = 0 + var/vocal = 1 + + //Healing vars + var/obj/item/weapon/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents. + var/injection_amount = 15 //How much reagent do we inject at a time? + var/heal_threshold = 10 //Start healing when they have this much damage in a category + var/use_beaker = 0 //Use reagents in beaker instead of default treatment agents. + var/treatment_brute = /datum/reagent/tricordrazine + var/treatment_oxy = /datum/reagent/tricordrazine + var/treatment_fire = /datum/reagent/tricordrazine + var/treatment_tox = /datum/reagent/tricordrazine + var/treatment_virus = /datum/reagent/spaceacillin + var/treatment_emag = /datum/reagent/toxin + var/declare_treatment = 0 //When attempting to treat a patient, should it notify everyone wearing medhuds? + +/mob/living/bot/medbot/handleIdle() + if(vocal && prob(1)) + var/message = pick("Radar, put a mask on!", "There's always a catch, and it's the best there is.", "I knew it, I should've been a plastic surgeon.", "What kind of infirmary is this? Everyone's dropping like dead flies.", "Delicious!") + say(message) + +/mob/living/bot/medbot/handleAdjacentTarget() + UnarmedAttack(target) + +/mob/living/bot/medbot/lookForTargets() + for(var/mob/living/carbon/human/H in view(7, src)) // Time to find a patient! + if(confirmTarget(H)) + target = H + if(last_newpatient_speak + 300 < world.time) + var/message = pick("Hey, [H.name]! Hold on, I'm coming.", "Wait [H.name]! I want to help!", "[H.name], you appear to be injured!") + say(message) + custom_emote(1, "points at [H.name].") + last_newpatient_speak = world.time + break + +/mob/living/bot/medbot/UnarmedAttack(var/mob/living/carbon/human/H, var/proximity) + if(!..()) + return + + if(!on) + return + + if(!istype(H)) + return + + if(busy) + return + + if(H.stat == DEAD) + var/death_message = pick("No! NO!", "Live, damnit! LIVE!", "I... I've never lost a patient before. Not today, I mean.") + say(death_message) + target = null + return + + var/t = confirmTarget(H) + if(!t) + var/message = pick("All patched up!", "An apple a day keeps me away.", "Feel better soon!") + say(message) + target = null + return + + icon_state = "medibots" + visible_message("[src] is trying to inject [H]!") + if(declare_treatment) + var/area/location = get_area(src) + broadcast_medical_hud_message("[src] is treating [H] in [location]", src) + busy = 1 + update_icons() + if(do_mob(src, H, 30)) + if(t == 1) + reagent_glass.reagents.trans_to_mob(H, injection_amount, CHEM_BLOOD) + else + H.reagents.add_reagent(t, injection_amount) + visible_message("[src] injects [H] with the syringe!") + busy = 0 + update_icons() + +/mob/living/bot/medbot/update_icons() + overlays.Cut() + if(skin) + overlays += image('icons/obj/aibots.dmi', "medskin_[skin]") + if(busy) + icon_state = "medibots" + else + icon_state = "medibot[on]" + +/mob/living/bot/medbot/attackby(var/obj/item/O, var/mob/user) + if(istype(O, /obj/item/weapon/reagent_containers/glass)) + if(locked) + to_chat(user, "You cannot insert a beaker because the panel is locked.") + return + if(!isnull(reagent_glass)) + to_chat(user, "There is already a beaker loaded.") + return + + user.drop_item() + O.loc = src + reagent_glass = O + to_chat(user, "You insert [O].") + return + else + ..() + +/mob/living/bot/medbot/GetInteractTitle() + . = "Medibot v1.0 controls" + . += "Automatic Medical Unit v1.0" + +/mob/living/bot/medbot/GetInteractStatus() + . = ..() + . += "
            Beaker: " + if(reagent_glass) + . += "Loaded \[[reagent_glass.reagents.total_volume]/[reagent_glass.reagents.maximum_volume]\]" + else + . += "None loaded" + +/mob/living/bot/medbot/GetInteractPanel() + . = "Healing threshold: " + . += "-- " + . += "- " + . += "[heal_threshold] " + . += "+ " + . += "++" + + . += "
            Injection level: " + . += "- " + . += "[injection_amount] " + . += "+ " + + . += "
            Reagent source: [use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"]" + . += "
            Treatment report is [declare_treatment ? "on" : "off"]. Toggle" + . += "
            The speaker switch is [vocal ? "on" : "off"]. Toggle" + +/mob/living/bot/medbot/GetInteractMaintenance() + . = "Injection mode: " + switch(emagged) + if(0) + . += "Treatment" + if(1) + . += "Random (DANGER)" + if(2) + . += "ERROROROROROR-----" + +/mob/living/bot/medbot/ProcessCommand(var/mob/user, var/command, var/href_list) + ..() + if(CanAccessPanel(user)) + switch(command) + if("adj_threshold") + if(!locked || issilicon(user)) + var/adjust_num = text2num(href_list["amount"]) + heal_threshold = Clamp(heal_threshold + adjust_num, 5, 75) + if("adj_inject") + if(!locked || issilicon(user)) + var/adjust_num = text2num(href_list["amount"]) + injection_amount = Clamp(injection_amount + adjust_num, 5, 15) + if("use_beaker") + if(!locked || issilicon(user)) + use_beaker = !use_beaker + if("eject") + if(reagent_glass) + if(!locked) + reagent_glass.dropInto(src.loc) + reagent_glass = null + else + to_chat(user, "You cannot eject the beaker because the panel is locked.") + if("togglevoice") + if(!locked || issilicon(user)) + vocal = !vocal + if("declaretreatment") + if(!locked || issilicon(user)) + declare_treatment = !declare_treatment + + if(CanAccessMaintenance(user)) + switch(command) + if("emag") + if(emagged < 2) + emagged = !emagged + +/mob/living/bot/medbot/emag_act(var/remaining_uses, var/mob/user) + . = ..() + if(!emagged) + if(user) + to_chat(user, "You short out [src]'s reagent synthesis circuits.") + ignore_list |= user + visible_message("[src] buzzes oddly!") + flick("medibot_spark", src) + target = null + busy = 0 + emagged = 1 + on = 1 + update_icons() + . = 1 + +/mob/living/bot/medbot/explode() + on = 0 + visible_message("[src] blows apart!") + var/turf/Tsec = get_turf(src) + + new /obj/item/weapon/storage/firstaid(Tsec) + new /obj/item/device/assembly/prox_sensor(Tsec) + new /obj/item/device/healthanalyzer(Tsec) + if (prob(50)) + new /obj/item/robot_parts/l_arm(Tsec) + + if(reagent_glass) + reagent_glass.loc = Tsec + reagent_glass = null + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + qdel(src) + return + +/mob/living/bot/medbot/confirmTarget(var/mob/living/carbon/human/H) + if(!..()) + return 0 + + if(H.stat == DEAD) // He's dead, Jim + return 0 + + if(emagged) + return treatment_emag + + // If they're injured, we're using a beaker, and they don't have on of the chems in the beaker + if(reagent_glass && use_beaker && ((H.getBruteLoss() >= heal_threshold) || (H.getToxLoss() >= heal_threshold) || (H.getToxLoss() >= heal_threshold) || (H.getOxyLoss() >= (heal_threshold + 15)))) + for(var/datum/reagent/R in reagent_glass.reagents.reagent_list) + if(!H.reagents.has_reagent(R)) + return 1 + continue + + if((H.getBruteLoss() >= heal_threshold) && (!H.reagents.has_reagent(treatment_brute))) + return treatment_brute //If they're already medicated don't bother! + + if((H.getOxyLoss() >= (15 + heal_threshold)) && (!H.reagents.has_reagent(treatment_oxy))) + return treatment_oxy + + if((H.getFireLoss() >= heal_threshold) && (!H.reagents.has_reagent(treatment_fire))) + return treatment_fire + + if((H.getToxLoss() >= heal_threshold) && (!H.reagents.has_reagent(treatment_tox))) + return treatment_tox + +/* Construction */ + +/obj/item/weapon/storage/firstaid/attackby(var/obj/item/robot_parts/S, mob/user as mob) + if ((!istype(S, /obj/item/robot_parts/l_arm)) && (!istype(S, /obj/item/robot_parts/r_arm))) + ..() + return + + if(contents.len >= 1) + to_chat(user, "You need to empty [src] out first.") + return + + var/obj/item/weapon/firstaid_arm_assembly/A = new /obj/item/weapon/firstaid_arm_assembly + if(istype(src, /obj/item/weapon/storage/firstaid/fire)) + A.skin = "ointment" + else if(istype(src, /obj/item/weapon/storage/firstaid/toxin)) + A.skin = "tox" + else if(istype(src, /obj/item/weapon/storage/firstaid/o2)) + A.skin = "o2" + + qdel(S) + user.put_in_hands(A) + to_chat(user, "You add the robot arm to the first aid kit.") + user.drop_from_inventory(src) + qdel(src) + +/obj/item/weapon/firstaid_arm_assembly + name = "first aid/robot arm assembly" + desc = "A first aid kit with a robot arm permanently grafted to it." + icon = 'icons/obj/aibots.dmi' + icon_state = "firstaid_arm" + var/build_step = 0 + var/created_name = "Medibot" //To preserve the name if it's a unique medbot I guess + var/skin = null //Same as medbot, set to tox or ointment for the respective kits. + w_class = ITEM_SIZE_NORMAL + +/obj/item/weapon/firstaid_arm_assembly/New() + ..() + spawn(5) // Terrible. TODO: fix + if(skin) + overlays += image('icons/obj/aibots.dmi', "kit_skin_[src.skin]") + +/obj/item/weapon/firstaid_arm_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + if(istype(W, /obj/item/weapon/pen)) + var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN) + if(!t) + return + if(!in_range(src, usr) && loc != usr) + return + created_name = t + else + switch(build_step) + if(0) + if(istype(W, /obj/item/device/healthanalyzer)) + user.drop_item() + qdel(W) + build_step++ + to_chat(user, "You add the health sensor to [src].") + SetName("First aid/robot arm/health analyzer assembly") + overlays += image('icons/obj/aibots.dmi', "na_scanner") + + if(1) + if(isprox(W)) + user.drop_item() + qdel(W) + to_chat(user, "You complete the Medibot! Beep boop.") + var/turf/T = get_turf(src) + var/mob/living/bot/medbot/S = new /mob/living/bot/medbot(T) + S.skin = skin + S.SetName(created_name) + S.update_icons() // apply the skin + user.drop_from_inventory(src) + qdel(src) diff --git a/code/modules/mob/living/bot/mulebot.dm b/code/modules/mob/living/bot/mulebot.dm new file mode 100644 index 00000000..099367ef --- /dev/null +++ b/code/modules/mob/living/bot/mulebot.dm @@ -0,0 +1,327 @@ +#define MULE_IDLE 0 +#define MULE_MOVING 1 +#define MULE_UNLOAD 2 +#define MULE_LOST 3 +#define MULE_CALC_MIN 4 +#define MULE_CALC_MAX 10 +#define MULE_PATH_DONE 11 +// IF YOU CHANGE THOSE, UPDATE THEM IN pda.tmpl TOO + +/mob/living/bot/mulebot + name = "Mulebot" + desc = "A Multiple Utility Load Effector bot." + icon_state = "mulebot0" + anchored = 1 + density = 1 + health = 150 + maxHealth = 150 + mob_bump_flag = HEAVY + + min_target_dist = 0 + max_target_dist = 250 + target_speed = 3 + max_frustration = 5 + botcard_access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station) + + var/atom/movable/load + + var/paused = 1 + var/crates_only = 1 + var/auto_return = 1 + var/safety = 1 + + var/targetName + var/turf/home + var/homeName + + var/global/amount = 0 + +/mob/living/bot/mulebot/New() + ..() + + var/turf/T = get_turf(loc) + var/obj/machinery/navbeacon/N = locate() in T + if(N) + home = T + homeName = N.location + else + homeName = "Unset" + + suffix = num2text(++amount) + name = "Mulebot #[suffix]" + +/mob/living/bot/mulebot/MouseDrop_T(var/atom/movable/C, var/mob/user) + if(user.stat) + return + + if(!istype(C) || C.anchored || get_dist(user, src) > 1 || get_dist(src, C) > 1 ) + return + + load(C) + +/mob/living/bot/mulebot/GetInteractTitle() + . = "Mulebot [suffix ? "([suffix])" : ""]" + . += "Multiple Utility Load Effector Mk. III" + . += "
            ID: [suffix]" + +/mob/living/bot/mulebot/GetInteractStatus() + . = ..() + . += "
            Current Load: [load ? load.name : "none"]" + +/mob/living/bot/mulebot/GetInteractPanel() + . += "Stop" + . += "
            Proceed" + . += "
            Return to home" + . += "
            Set destination" + . += "
            Set home" + . += "
            Toggle auto return home ([auto_return ? "On" : "Off"])" + . += "
            Toggle non-standard cargo ([crates_only ? "Off" : "On"])" + + if(load) + . += "
            Unload now" + +/mob/living/bot/mulebot/GetInteractMaintenance() + . = "Toggle safety ([safety ? "On" : "Off - DANGER"])" + +/mob/living/bot/mulebot/ProcessCommand(var/mob/user, var/command, var/href_list) + ..() + if(CanAccessPanel(user)) + switch(command) + if("stop") + obeyCommand("Stop") + if("go") + obeyCommand("GoTD") + if("home") + obeyCommand("Home") + if("destination") + obeyCommand("SetD") + if("sethome") + var/new_dest + var/list/beaconlist = GetBeaconList() + if(beaconlist.len) + new_dest = input("Select new home tag", "Mulebot [suffix ? "([suffix])" : ""]", null) in null|beaconlist + else + alert("No destination beacons available.") + if(new_dest) + home = get_turf(beaconlist[new_dest]) + homeName = new_dest + if("unload") + unload() + if("autoret") + auto_return = !auto_return + if("cargotypes") + crates_only = !crates_only + + if(CanAccessMaintenance(user)) + switch(command) + if("safety") + safety = !safety + +/mob/living/bot/mulebot/attackby(var/obj/item/O, var/mob/user) + ..() + update_icons() + +/mob/living/bot/mulebot/proc/obeyCommand(var/command) + switch(command) + if("Home") + resetTarget() + target = home + targetName = "Home" + if("SetD") + var/new_dest + var/list/beaconlist = GetBeaconList() + if(beaconlist.len) + new_dest = input("Select new destination tag", "Mulebot [suffix ? "([suffix])" : ""]") in null|beaconlist + else + alert("No destination beacons available.") + if(new_dest) + resetTarget() + target = get_turf(beaconlist[new_dest]) + targetName = new_dest + if("GoTD") + paused = 0 + if("Stop") + paused = 1 + +/mob/living/bot/mulebot/emag_act(var/remaining_charges, var/user) + locked = !locked + to_chat(user, "You [locked ? "lock" : "unlock"] the mulebot's controls.") + flick("mulebot-emagged", src) + playsound(loc, 'sound/effects/sparks1.ogg', 100, 0) + return 1 + +/mob/living/bot/mulebot/update_icons() + if(open) + icon_state = "mulebot-hatch" + return + if(target_path.len && !paused) + icon_state = "mulebot1" + return + icon_state = "mulebot0" + +/mob/living/bot/mulebot/handleRegular() + if(!safety && prob(1)) + flick("mulebot-emagged", src) + update_icons() + +/mob/living/bot/mulebot/handleFrustrated() + custom_emote(2, "makes a sighing buzz.") + playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) + ..() + +/mob/living/bot/mulebot/handleAdjacentTarget() + if(target == src.loc) + custom_emote(2, "makes a chiming sound.") + playsound(loc, 'sound/machines/chime.ogg', 50, 0) + UnarmedAttack(target) + resetTarget() + if(auto_return && home && (loc != home)) + target = home + targetName = "Home" + +/mob/living/bot/mulebot/confirmTarget() + return 1 + +/mob/living/bot/mulebot/calcTargetPath() + ..() + if(!target_path.len && target != home) // I presume that target is not null + resetTarget() + target = home + targetName = "Home" + +/mob/living/bot/mulebot/stepToTarget() + if(paused) + return + ..() + +/mob/living/bot/mulebot/UnarmedAttack(var/turf/T) + if(T == src.loc) + unload(dir) + +/mob/living/bot/mulebot/Bump(var/mob/living/carbon/human/M) + if(!safety && istype(M)) + visible_message("[src] knocks over [M]!") + M.Stun(8) + M.Weaken(5) + ..() + +/mob/living/bot/mulebot/proc/runOver(var/mob/living/carbon/human/H) + if(istype(H)) // No safety checks - WILL run over lying humans. Stop ERPing in the maint! + visible_message("[src] drives over [H]!") + playsound(loc, 'sound/effects/splat.ogg', 50, 1) + + var/damage = rand(5, 7) + H.apply_damage(2 * damage, BRUTE, BP_HEAD) + H.apply_damage(2 * damage, BRUTE, BP_CHEST) + H.apply_damage(0.5 * damage, BRUTE, BP_L_LEG) + H.apply_damage(0.5 * damage, BRUTE, BP_R_LEG) + H.apply_damage(0.5 * damage, BRUTE, BP_L_ARM) + H.apply_damage(0.5 * damage, BRUTE, BP_R_ARM) + + blood_splatter(src, H, 1) + ..() + +/mob/living/bot/mulebot/relaymove(var/mob/user, var/direction) + if(load == user) + unload(direction) + +/mob/living/bot/mulebot/explode() + unload(pick(0, 1, 2, 4, 8)) + + visible_message("[src] blows apart!") + + var/turf/Tsec = get_turf(src) + new /obj/item/device/assembly/prox_sensor(Tsec) + new /obj/item/stack/rods(Tsec) + new /obj/item/stack/rods(Tsec) + new /obj/item/stack/cable_coil/cut(Tsec) + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + + new /obj/effect/decal/cleanable/blood/oil(Tsec) + ..() + +/mob/living/bot/mulebot/proc/GetBeaconList() + var/list/beaconlist = list() + for(var/obj/machinery/navbeacon/N in navbeacons) + if(!N.codes["delivery"]) + continue + beaconlist.Add(N.location) + beaconlist[N.location] = N + return beaconlist + +/mob/living/bot/mulebot/proc/load(var/atom/movable/C) + if(busy || load || get_dist(C, src) > 1 || !isturf(C.loc)) + return + + for(var/obj/structure/plasticflaps/P in src.loc)//Takes flaps into account + if(!CanPass(C,P)) + return + + if(crates_only && !istype(C,/obj/structure/closet/crate)) + custom_emote(2, "makes a sighing buzz.") + playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) + return + + var/obj/structure/closet/crate/crate = C + if(istype(crate)) + crate.close() + + busy = 1 + + C.forceMove(loc) + sleep(2) + if(C.loc != loc) //To prevent you from going onto more than one bot. + return + C.forceMove(src) + load = C + + C.pixel_y += 9 + if(C.layer < layer) + C.layer = layer + 0.1 + C.plane = plane + overlays += C + + if(ismob(C)) + var/mob/M = C + if(M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + + busy = 0 + +/mob/living/bot/mulebot/proc/unload(var/dirn = 0) + if(!load || busy) + return + + busy = 1 + overlays.Cut() + + load.forceMove(loc) + load.pixel_y -= 9 + load.reset_plane_and_layer() + if(ismob(load)) + var/mob/M = load + if(M.client) + M.client.perspective = MOB_PERSPECTIVE + M.client.eye = src + + if(dirn) + step(load, dirn) + + load = null + + for(var/atom/movable/AM in src) + if(AM == botcard || AM == access_scanner) continue + + AM.forceMove(loc) + AM.reset_plane_and_layer() + AM.pixel_y = initial(AM.pixel_y) + if(ismob(AM)) + var/mob/M = AM + if(M.client) + M.client.perspective = MOB_PERSPECTIVE + M.client.eye = src + busy = 0 diff --git a/code/modules/mob/living/bot/remotebot.dm b/code/modules/mob/living/bot/remotebot.dm new file mode 100644 index 00000000..2e22bb24 --- /dev/null +++ b/code/modules/mob/living/bot/remotebot.dm @@ -0,0 +1,170 @@ +/mob/living/bot/remotebot + name = "Remote-Bot" + desc = "A remote controlled robot used by lazy people to switch channels and get pizza." + icon_state = "fetchbot1" + health = 15 + maxHealth = 15 + + var/working = 0 + var/next_movement_time = 0 + var/speed = 10 //lower = better + var/obj/item/holding = null + var/obj/item/device/bot_controller/controller = null + +/mob/living/bot/remotebot/movement_delay() + var/tally = ..() + tally += speed + if(holding) + tally += (2 * holding.w_class) + return tally + +/mob/living/bot/remotebot/examine(mob/user) + . = ..(user) + if(holding) + to_chat(user, "It is holding \the \icon[holding] [holding].") + +/mob/living/bot/remotebot/explode() + on = 0 + new /obj/effect/decal/cleanable/blood/oil(get_turf(src.loc)) + visible_message("[src] blows apart!") + if(controller) + controller.bot = null + controller = null + for(var/i in 1 to rand(3,5)) + var/obj/item/stack/material/cardboard/C = new(src.loc) + if(prob(50)) + C.loc = get_step(src, pick(GLOB.alldirs)) + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + qdel(src) + +/mob/living/bot/remotebot/attackby(var/obj/item/I, var/mob/living/user) + if(istype(I, /obj/item/device/bot_controller) && !controller) + user.visible_message("\The [user] waves \the [I] over \the [src].") + to_chat(user, "You link \the [src] to \the [I].") + var/obj/item/device/bot_controller/B = I + B.bot = src + controller = B + return ..() + +/mob/living/bot/remotebot/update_icons() + icon_state = "fetchbot[on]" + +/mob/living/bot/remotebot/Destroy() + if(holding) + holding.forceMove(loc) + holding = null + return ..() + +/mob/living/bot/remotebot/proc/pickup(var/obj/item/I) + if(holding || get_dist(src,I) > 1) + return + src.visible_message("\The [src] picks up \the [I].") + flick("fetchbot-c", src) + working = 1 + sleep(10) + working = 0 + I.forceMove(src) + holding = I + +/mob/living/bot/remotebot/proc/drop() + if(working || !holding) + return + holding.forceMove(loc) + holding = null + +/mob/living/bot/remotebot/proc/hit(var/atom/movable/a) + src.visible_message("\The [src] taps \the [a] with its claw.") + flick("fetchbot-c", src) + working = 1 + sleep(10) + working = 0 + +/mob/living/bot/remotebot/proc/command(var/atom/a) + if(working || stat || !on || a == src) //can't touch itself + return + if(isturf(a) || get_dist(src,a) > 1) + walk_to(src,a,0,movement_delay()) + else if(istype(a, /obj/item)) + pickup(a) + else + hit(a) + +/obj/item/device/bot_controller + name = "remote control" + desc = "Used to control something remotely. Even has a tiny screen!" + icon_state = "forensic1" + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_BELT + item_state = "electronic" + var/mob/living/bot/remotebot/bot + +/obj/item/device/bot_controller/attack_self(var/mob/user) + src.interact(user) + +/obj/item/device/bot_controller/interact(var/mob/user) + user.set_machine(src) + if(!(src in user) || !bot) + user << browse(null, "window=bot_controller") + return + var/dat = "
            Remote Control: [bot.name]
            " + dat += "Currently Holding: [bot.holding ? bot.holding.name : "Nothing"]

            " + var/is_looking = (user.client.eye == bot) + dat += "[is_looking ? "Stop" : "Start"] Looking
            " + dat += "Drop Item
            " + + user << browse(dat, "window=bot_controller") + onclose(user, "botcontroller") + +/obj/item/device/bot_controller/check_eye() + return 0 + +/obj/item/device/bot_controller/Topic(href, href_list) + ..() + if(!bot) + return + + if(href_list["drop"]) + bot.drop() + if(href_list["look"]) + if(href_list["look"] == "1") + usr.reset_view(usr) + usr.visible_message("\The [usr] looks up from \the [src]'s screen.") + else + usr.reset_view(bot) + usr.visible_message("\The [usr] looks intently on \the [src]'s screen.") + + src.interact(usr) + + +/obj/item/device/bot_controller/dropped(var/mob/living/user) + if(user.client.eye == bot) + user.client.eye = user + return ..() + + +/obj/item/device/bot_controller/afterattack(atom/A, mob/living/user) + if(bot) + bot.command(A) + +/obj/item/device/bot_controller/Destroy() + if(bot) + bot.controller = null + bot = null + return ..() + +/obj/item/device/bot_kit + name = "Remote-Bot Kit" + desc = "The cover says 'control your own cardboard nuclear powered robot. Comes with real plutonium!" + icon = 'icons/obj/storage.dmi' + icon_state = "remotebot" + +/obj/item/device/bot_kit/attack_self(var/mob/living/user) + to_chat(user, "You quickly dismantle the box and retrieve the controller and the remote bot itself.") + var/turf/T = get_turf(src.loc) + new /mob/living/bot/remotebot(T) + new /obj/item/device/bot_controller(T) + user.drop_from_inventory(src) + qdel(src) \ No newline at end of file diff --git a/code/modules/mob/living/bot/secbot.dm b/code/modules/mob/living/bot/secbot.dm new file mode 100644 index 00000000..6adef490 --- /dev/null +++ b/code/modules/mob/living/bot/secbot.dm @@ -0,0 +1,318 @@ +#define SECBOT_WAIT_TIME 5 //number of in-game seconds to wait for someone to surrender +#define SECBOT_THREAT_ARREST 4 //threat level at which we decide to arrest someone +#define SECBOT_THREAT_ATTACK 8 //threat level at which was assume immediate danger and attack right away + +/mob/living/bot/secbot + name = "Securitron" + desc = "A little security robot. He looks less than thrilled." + icon_state = "secbot0" + var/attack_state = "secbot-c" + maxHealth = 50 + health = 50 + req_one_access = list(access_security, access_forensics_lockers) + botcard_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels) + + patrol_speed = 2 + target_speed = 3 + light_strength = 0 //stunbaton makes it's own light + + RequiresAccessToToggle = 1 // Haha no + + var/idcheck = 0 // If true, arrests for having weapons without authorization. + var/check_records = 0 // If true, arrests people without a record. + var/check_arrest = 1 // If true, arrests people who are set to arrest. + var/declare_arrests = 0 // If true, announces arrests over sechuds. + + var/is_ranged = 0 + var/awaiting_surrender = 0 + + var/obj/item/weapon/melee/baton/stun_baton + var/obj/item/weapon/handcuffs/cyborg/handcuffs + + var/list/threat_found_sounds = list('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg') + var/list/preparing_arrest_sounds = list('sound/voice/bfreeze.ogg') + +/mob/living/bot/secbot/beepsky + name = "Officer Beepsky" + desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey." + will_patrol = 1 + +/mob/living/bot/secbot/New() + ..() + stun_baton = new(src) + stun_baton.bcell = new /obj/item/weapon/cell/infinite(stun_baton) + stun_baton.set_status(1, null) + + handcuffs = new(src) + +/mob/living/bot/secbot/Destroy() + qdel(stun_baton) + qdel(handcuffs) + stun_baton = null + handcuffs = null + return ..() + +/mob/living/bot/secbot/turn_on() + ..() + stun_baton.set_status(on, null) + +/mob/living/bot/secbot/turn_off() + ..() + stun_baton.set_status(on, null) + +/mob/living/bot/secbot/update_icons() + icon_state = "secbot[on]" + +/mob/living/bot/secbot/GetInteractTitle() + . = "Securitron controls" + . += "Automatic Security Unit" + +/mob/living/bot/secbot/GetInteractPanel() + . = "Check for weapon authorization: [idcheck ? "Yes" : "No"]" + . += "
            Check security records: [check_records ? "Yes" : "No"]" + . += "
            Check arrest status: [check_arrest ? "Yes" : "No"]" + . += "
            Report arrests: [declare_arrests ? "Yes" : "No"]" + . += "
            Auto patrol: [will_patrol ? "On" : "Off"]" + +/mob/living/bot/secbot/GetInteractMaintenance() + . = "Threat identifier status: " + switch(emagged) + if(0) + . += "Normal" + if(1) + . += "Scrambled (DANGER)" + if(2) + . += "ERROROROROROR-----" + +/mob/living/bot/secbot/ProcessCommand(var/mob/user, var/command, var/href_list) + ..() + if(CanAccessPanel(user)) + switch(command) + if("idcheck") + idcheck = !idcheck + if("ignorerec") + check_records = !check_records + if("ignorearr") + check_arrest = !check_arrest + if("patrol") + will_patrol = !will_patrol + if("declarearrests") + declare_arrests = !declare_arrests + + if(CanAccessMaintenance(user)) + switch(command) + if("emag") + if(emagged < 2) + emagged = !emagged + +/mob/living/bot/secbot/attackby(var/obj/item/O, var/mob/user) + var/curhealth = health + . = ..() + if(health < curhealth) + react_to_attack(user) + +/mob/living/bot/secbot/emag_act(var/remaining_charges, var/mob/user) + . = ..() + if(!emagged) + if(user) + to_chat(user, "You short out [src]'s threat identificator.") + ignore_list |= user + emagged = 2 + return 1 + +/mob/living/bot/secbot/bullet_act(var/obj/item/projectile/P) + var/curhealth = health + var/mob/shooter = P.firer + . = ..() + //if we already have a target just ignore to avoid lots of checking + if(!target && health < curhealth && shooter && (shooter in view(world.view, src))) + react_to_attack(shooter) + +/mob/living/bot/secbot/proc/begin_arrest(mob/target, var/threat) + var/suspect_name = target_name(target) + if(declare_arrests) + broadcast_security_hud_message("[src] is arresting a level [threat] suspect [suspect_name] in [get_area(src)].", src) + say("Down on the floor, [suspect_name]! You have [SECBOT_WAIT_TIME] seconds to comply.") + playsound(src.loc, pick(preparing_arrest_sounds), 50) + GLOB.moved_event.register(target, src, /mob/living/bot/secbot/proc/target_moved) + +/mob/living/bot/secbot/proc/target_moved(atom/movable/moving_instance, atom/old_loc, atom/new_loc) + if(get_dist(get_turf(src), get_turf(target)) >= 1) + awaiting_surrender = INFINITY + GLOB.moved_event.unregister(moving_instance, src) + +/mob/living/bot/secbot/proc/react_to_attack(mob/attacker) + if(!target) + playsound(src.loc, pick(threat_found_sounds), 50) + broadcast_security_hud_message("[src] was attacked by a hostile [target_name(attacker)] in [get_area(src)].", src) + target = attacker + awaiting_surrender = INFINITY + +/mob/living/bot/secbot/resetTarget() + ..() + GLOB.moved_event.unregister(target, src) + awaiting_surrender = -1 + walk_to(src, 0) + +/mob/living/bot/secbot/startPatrol() + if(!locked) // Stop running away when we set you up + return + ..() + +/mob/living/bot/secbot/confirmTarget(var/atom/A) + if(!..()) + return 0 + return (check_threat(A) >= SECBOT_THREAT_ARREST) + +/mob/living/bot/secbot/lookForTargets() + for(var/mob/living/M in view(src)) + if(M.stat == DEAD) + continue + if(confirmTarget(M)) + var/threat = check_threat(M) + target = M + awaiting_surrender = -1 + say("Level [threat] infraction alert!") + custom_emote(1, "points at [M.name]!") + return + +/mob/living/bot/secbot/handleAdjacentTarget() + var/mob/living/carbon/human/H = target + var/threat = check_threat(target) + if(awaiting_surrender < SECBOT_WAIT_TIME && istype(H) && !H.lying && threat < SECBOT_THREAT_ATTACK) + if(awaiting_surrender == -1) + begin_arrest(target, threat) + ++awaiting_surrender + else + UnarmedAttack(target) + +/mob/living/bot/secbot/proc/cuff_target(var/mob/living/carbon/C) + if(istype(C) && !C.handcuffed) + handcuffs.place_handcuffs(C, src) + resetTarget() //we're done, failed or not. Don't want to get stuck if C is not + +/mob/living/bot/secbot/UnarmedAttack(var/mob/M, var/proximity) + if(!..()) + return + + if(!istype(M)) + return + + var/mob/living/carbon/human/H = M + if(istype(H) && H.lying) + cuff_target(H) + return + + if(istype(M, /mob/living/simple_animal)) + a_intent = I_HURT + else + a_intent = I_GRAB + + stun_baton.attack(M, src, BP_CHEST) //robots and turrets aim for center of mass + flick(attack_state, src) + +/mob/living/bot/secbot/explode() + visible_message("[src] blows apart!") + var/turf/Tsec = get_turf(src) + + var/obj/item/weapon/secbot_assembly/Sa = new /obj/item/weapon/secbot_assembly(Tsec) + Sa.build_step = 1 + Sa.overlays += image('icons/obj/aibots.dmi', "hs_hole") + Sa.created_name = name + new /obj/item/device/assembly/prox_sensor(Tsec) + new /obj/item/weapon/melee/baton(Tsec) + if(prob(50)) + new /obj/item/robot_parts/l_arm(Tsec) + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + + new /obj/effect/decal/cleanable/blood/oil(Tsec) + qdel(src) + +/mob/living/bot/secbot/proc/target_name(mob/living/T) + if(ishuman(T)) + var/mob/living/carbon/human/H = T + return H.get_id_name("unidentified person") + return "unidentified lifeform" + +/mob/living/bot/secbot/proc/check_threat(var/mob/living/M) + if(!M || !istype(M) || M.stat == DEAD || src == M) + return 0 + + if(emagged && !M.incapacitated()) //check incapacitated so emagged secbots don't keep attacking the same target forever + return 10 + + return M.assess_perp(access_scanner, 0, idcheck, check_records, check_arrest) + +//Secbot Construction + +/obj/item/clothing/head/helmet/attackby(var/obj/item/device/assembly/signaler/S, mob/user as mob) + ..() + if(!issignaler(S)) + ..() + return + + if(type != /obj/item/clothing/head/helmet) //Eh, but we don't want people making secbots out of space helmets. + return + + if(S.secured) + qdel(S) + var/obj/item/weapon/secbot_assembly/A = new /obj/item/weapon/secbot_assembly + user.put_in_hands(A) + to_chat(user, "You add the signaler to the helmet.") + user.drop_from_inventory(src) + qdel(src) + else + return + +/obj/item/weapon/secbot_assembly + name = "helmet/signaler assembly" + desc = "Some sort of bizarre assembly." + icon = 'icons/obj/aibots.dmi' + icon_state = "helmet_signaler" + item_state = "helmet" + var/build_step = 0 + var/created_name = "Securitron" + +/obj/item/weapon/secbot_assembly/attackby(var/obj/item/O, var/mob/user) + ..() + if(isWelder(O) && !build_step) + var/obj/item/weapon/weldingtool/WT = O + if(WT.remove_fuel(0, user)) + build_step = 1 + overlays += image('icons/obj/aibots.dmi', "hs_hole") + to_chat(user, "You weld a hole in \the [src].") + + else if(isprox(O) && (build_step == 1)) + user.drop_item() + build_step = 2 + to_chat(user, "You add \the [O] to [src].") + overlays += image('icons/obj/aibots.dmi', "hs_eye") + SetName("helmet/signaler/prox sensor assembly") + qdel(O) + + else if((istype(O, /obj/item/robot_parts/l_arm) || istype(O, /obj/item/robot_parts/r_arm)) && build_step == 2) + user.drop_item() + build_step = 3 + to_chat(user, "You add \the [O] to [src].") + SetName("helmet/signaler/prox sensor/robot arm assembly") + overlays += image('icons/obj/aibots.dmi', "hs_arm") + qdel(O) + + else if(istype(O, /obj/item/weapon/melee/baton) && build_step == 3) + user.drop_item() + to_chat(user, "You complete the Securitron! Beep boop.") + var/mob/living/bot/secbot/S = new /mob/living/bot/secbot(get_turf(src)) + S.SetName(created_name) + qdel(O) + qdel(src) + + else if(istype(O, /obj/item/weapon/pen)) + var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN) + if(!t) + return + if(!in_range(src, usr) && loc != usr) + return + created_name = t diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm new file mode 100644 index 00000000..0271e778 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -0,0 +1,54 @@ +/mob/living/carbon/alien + + name = "alien" + desc = "What IS that?" + icon = 'icons/mob/alien.dmi' + icon_state = "alien" + pass_flags = PASS_FLAG_TABLE + health = 100 + maxHealth = 100 + mob_size = 4 + species_language = "Xenophage" + + var/adult_form + var/dead_icon + var/amount_grown = 0 + var/max_grown = 200 + var/time_of_birth + var/language + var/death_msg = "lets out a waning guttural screech, green blood bubbling from its maw." + var/can_namepick_as_adult = 0 + var/adult_name + var/instance_num + +/mob/living/carbon/alien/New() + + time_of_birth = world.time + + verbs += /mob/living/proc/ventcrawl + verbs += /mob/living/proc/hide + + instance_num = rand(1, 1000) + name = "[initial(name)] ([instance_num])" + real_name = name + regenerate_icons() + + if(language) + add_language(language) + + gender = NEUTER + + ..() + +/mob/living/carbon/alien/u_equip(obj/item/W as obj) + return + +/mob/living/carbon/alien/Stat() + . = ..() + stat(null, "Progress: [amount_grown]/[max_grown]") + +/mob/living/carbon/alien/restrained() + return 0 + +/mob/living/carbon/alien/show_inv(mob/user as mob) + return //Consider adding cuffs and hats to this, for the sake of fun. \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/alien_attacks.dm b/code/modules/mob/living/carbon/alien/alien_attacks.dm new file mode 100644 index 00000000..4d7ec3fa --- /dev/null +++ b/code/modules/mob/living/carbon/alien/alien_attacks.dm @@ -0,0 +1,41 @@ +//There has to be a better way to define this shit. ~ Z +//can't equip anything +/mob/living/carbon/alien/attack_ui(slot_id) + return + +/mob/living/carbon/alien/attack_hand(mob/living/carbon/M as mob) + + ..() + + switch(M.a_intent) + + if (I_HELP) + help_shake_act(M) + + else + var/damage = rand(1, 9) + if (prob(90)) + if (HULK in M.mutations) + damage += 5 + spawn(0) + Paralyse(1) + step_away(src,M,15) + sleep(3) + step_away(src,M,15) + playsound(loc, "punch", 40, 1, -1) + for(var/mob/O in viewers(src, null)) + if ((O.client && !( O.blinded ))) + O.show_message("\The [M] has punched \the [src]!", 1) + if (damage > 4.9) + Weaken(rand(10,15)) + for(var/mob/O in viewers(M, null)) + if ((O.client && !( O.blinded ))) + O.show_message("\The [M] has weakened \the [src]!", 1, "You hear someone fall.", 2) + adjustBruteLoss(damage) + updatehealth() + else + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + for(var/mob/O in viewers(src, null)) + if ((O.client && !( O.blinded ))) + O.show_message("\The [M] has attempted to punch \the [src]!", 1) + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/alien_damage.dm b/code/modules/mob/living/carbon/alien/alien_damage.dm new file mode 100644 index 00000000..f2d14764 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/alien_damage.dm @@ -0,0 +1,33 @@ +/mob/living/carbon/alien/ex_act(severity) + + if(!blinded) + flash_eyes() + + var/b_loss = null + var/f_loss = null + switch (severity) + if (1.0) + b_loss += 500 + gib() + return + + if (2.0) + + b_loss += 60 + + f_loss += 60 + + ear_damage += 30 + ear_deaf += 120 + + if(3.0) + b_loss += 30 + if (prob(50)) + Paralyse(1) + ear_damage += 15 + ear_deaf += 60 + + adjustBruteLoss(b_loss) + adjustFireLoss(f_loss) + + updatehealth() diff --git a/code/modules/mob/living/carbon/alien/death.dm b/code/modules/mob/living/carbon/alien/death.dm new file mode 100644 index 00000000..87990ae7 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/death.dm @@ -0,0 +1,4 @@ +/mob/living/carbon/alien/death(gibbed) + if(!gibbed && dead_icon) + icon_state = dead_icon + return ..(gibbed,death_msg) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/death.dm b/code/modules/mob/living/carbon/alien/diona/death.dm new file mode 100644 index 00000000..ca537136 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/diona/death.dm @@ -0,0 +1,60 @@ +//This essentially makes dionaea spawned by splitting into a doubly linked +//list that, when the nymph dies, transfers the controler's mind +//to the next nymph in the list. + +/mob/living/carbon/alien/diona/proc/set_next_nymph(var/mob/living/carbon/alien/diona/D) + next_nymph = D + +/mob/living/carbon/alien/diona/proc/set_last_nymph(var/mob/living/carbon/alien/diona/D) + last_nymph = D +// When there are only two nymphs left in a list and one is to be removed, +// call this to null it out. +/mob/living/carbon/alien/diona/proc/null_nymphs() + next_nymph = null + last_nymph = null + +/mob/living/carbon/alien/diona/proc/remove_from_list() + // Closes over the gap that's going to be made and removes references to + // the nymph this is called for. + var/need_links_null = 0 + + if (last_nymph) + last_nymph.set_next_nymph(next_nymph) + if (last_nymph.next_nymph == last_nymph) + need_links_null = 1 + if (next_nymph) + next_nymph.set_last_nymph(last_nymph) + if (next_nymph.last_nymph == next_nymph) + need_links_null = 1 + // This bit checks if a nymphs is the only nymph in the list + // by seeing if it points to itself. If it is, it nulls it + // to stop list behaviour. + if (need_links_null) + if (last_nymph) + last_nymph.null_nymphs() + if (next_nymph) + next_nymph.null_nymphs() + // Finally, remove the current nymph's references to other nymphs. + null_nymphs() + +/mob/living/carbon/alien/diona/death(gibbed) + + if (next_nymph && next_nymph.stat == 0) + + var/mob/living/carbon/alien/diona/S = next_nymph + transfer_languages(src, S) + + if(mind) + to_chat(src, "You have died and have been transfered to another of your nymphs.") + mind.transfer_to(S) + message_admins("\The [src] has transfered to another nymph; player now controls [key_name_admin(S)]") + log_admin("\The [src] has transfered to another nymph; player now controls [key_name(S)]") + + remove_from_list() + + return ..(gibbed,death_msg) + +/mob/living/carbon/alien/diona/Destroy() + if (last_nymph || next_nymph) + remove_from_list() + ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/diona.dm b/code/modules/mob/living/carbon/alien/diona/diona.dm new file mode 100644 index 00000000..2585a8c0 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/diona/diona.dm @@ -0,0 +1,123 @@ +/mob/living/carbon/alien/diona + name = "diona nymph" + voice_name = "diona nymph" + adult_form = /mob/living/carbon/human + can_namepick_as_adult = 1 + adult_name = "diona gestalt" + speak_emote = list("chirrups") + icon_state = "nymph" + item_state = "nymph" + language = LANGUAGE_ROOTLOCAL + species_language = LANGUAGE_ROOTLOCAL + only_species_language = 1 + death_msg = "expires with a pitiful chirrup..." + universal_understand = 0 + universal_speak = 0 // Dionaea do not need to speak to people other than other dionaea. + + can_pull_size = ITEM_SIZE_SMALL + can_pull_mobs = MOB_PULL_SMALLER + + holder_type = /obj/item/weapon/holder/diona + possession_candidate = 1 + + var/obj/item/hat + var/obj/item/holding_item + var/mob/living/carbon/alien/diona/next_nymph + var/mob/living/carbon/alien/diona/last_nymph + +/mob/living/carbon/alien/diona/examine(mob/user) + . = ..() + if(holding_item) + to_chat(user, "It is holding \icon[holding_item] \a [holding_item].") + if(hat) + to_chat(user, "It is wearing \icon[hat] \a [hat].") + +/mob/living/carbon/alien/diona/drop_from_inventory(var/obj/item/W, var/atom/Target = null) + . = ..() + if(W == hat) + hat = null + update_icons() + else if(W == holding_item) + holding_item = null + +/mob/living/carbon/alien/diona/IsAdvancedToolUser() + return FALSE + +/mob/living/carbon/alien/diona/New() + + ..() + species = all_species[SPECIES_DIONA] + add_language(LANGUAGE_ROOTGLOBAL) + add_language(LANGUAGE_GALCOM) + verbs += /mob/living/carbon/alien/diona/proc/merge + +/mob/living/carbon/alien/diona/put_in_hands(var/obj/item/W) // No hands. Use mouth. + if(can_collect(W)) + collect(W) + else + W.forceMove(get_turf(src)) + return 1 + +/mob/living/carbon/alien/diona/proc/wear_hat(var/obj/item/clothing/head/new_hat) + if(hat || !istype(new_hat)) + return FALSE + hat = new_hat + new_hat.forceMove(src) + update_icons() + return TRUE + +/mob/living/carbon/alien/diona/proc/handle_npc(var/mob/living/carbon/alien/diona/D) + if(D.stat != CONSCIOUS) + return + if(prob(33) && D.canmove && isturf(D.loc) && !D.pulledby) //won't move if being pulled + step(D, pick(GLOB.cardinal)) + if(prob(1)) + D.emote(pick("scratch","jump","chirp","tail")) + +/mob/living/carbon/alien/diona/hotkey_drop() + if(holding_item || hat) + drop_item() + else + to_chat(usr, "You have nothing to drop.") + +/mob/living/carbon/alien/diona/UnarmedAttack(atom/A) + if(wear_hat(A)) + return 1 + if(!can_collect(A)) + return ..() + collect(A) + return 1 + +/mob/living/carbon/alien/diona/proc/can_collect(var/obj/item/collecting) + return (!holding_item && istype(collecting) && !collecting.anchored && collecting.simulated && collecting.w_class <= ITEM_SIZE_SMALL) + +/mob/living/carbon/alien/diona/proc/collect(var/obj/item/collecting) + collecting.forceMove(src) + holding_item = collecting + visible_message("\The [src] engulfs \the [holding_item].") + + // This means dionaea can hoover up beakers as a kind of impromptu chem disposal + // technique, so long as they're okay with the reagents reacting inside them. + if(holding_item.reagents && holding_item.reagents.total_volume) + holding_item.reagents.trans_to_mob(src, holding_item.reagents.total_volume, CHEM_INGEST) + + // It also means they can do the old school cartoon schtick of eating and entire sandwich + // and spitting up an empty plate. Ptooie. + if(istype(holding_item, /obj/item/weapon/reagent_containers/food)) + var/obj/item/weapon/reagent_containers/food/food = holding_item + holding_item = null + if(food.trash) holding_item = new food.trash(src) + qdel(food) + +/mob/living/carbon/alien/diona/drop_item() + if(holding_item) + visible_message("\The [src] regurgitates \the [holding_item].") + holding_item.forceMove(get_turf(src)) + holding_item = null + else if(hat) + visible_message("\The [src] wriggles out from under \the [hat].") + hat.forceMove(get_turf(src)) + hat = null + update_icons() + else + . = ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm b/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm new file mode 100644 index 00000000..f1b22e63 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm @@ -0,0 +1,28 @@ +/mob/living/carbon/alien/diona/get_scooped(var/mob/living/carbon/grabber) + if(grabber.species && grabber.species.name == SPECIES_DIONA && do_merge(grabber)) + return + else return ..() + +/mob/living/carbon/alien/diona/MouseDrop(atom/over_object) + var/mob/living/carbon/H = over_object + + if(istype(H) && Adjacent(H) && (usr == H) && (H.a_intent == "grab") && hat && !(H.l_hand && H.r_hand)) + hat.forceMove(get_turf(src)) + H.put_in_hands(hat) + H.visible_message("\The [H] removes \the [src]'s [hat].") + hat = null + update_icons() + return + + return ..() + +/mob/living/carbon/alien/diona/attackby(var/obj/item/weapon/W, var/mob/user) + if(user.a_intent == I_HELP && istype(W, /obj/item/clothing/head)) + if(hat) + to_chat(user, "\The [src] is already wearing \the [hat].") + return + user.unEquip(W) + wear_hat(W) + user.visible_message("\The [user] puts \the [W] on \the [src].") + return + return ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/diona_powers.dm b/code/modules/mob/living/carbon/alien/diona/diona_powers.dm new file mode 100644 index 00000000..107e252a --- /dev/null +++ b/code/modules/mob/living/carbon/alien/diona/diona_powers.dm @@ -0,0 +1,69 @@ +//Verbs after this point. +/mob/living/carbon/alien/diona/proc/merge() + + set category = "Abilities" + set name = "Merge with gestalt" + set desc = "Merge with another diona." + + if(stat == DEAD || paralysis || weakened || stunned || restrained()) + return + + if(istype(src.loc,/mob/living/carbon)) + src.verbs -= /mob/living/carbon/alien/diona/proc/merge + return + + var/list/choices = list() + for(var/mob/living/carbon/C in view(1,src)) + + if(!(src.Adjacent(C)) || !(C.client)) continue + + if(istype(C,/mob/living/carbon/human)) + var/mob/living/carbon/human/D = C + if(D.species && D.species.name == SPECIES_DIONA) + choices += C + + var/mob/living/M = input(src,"Who do you wish to merge with?") in null|choices + + if(!M) + to_chat(src, "There is nothing nearby to merge with.") + else if(!do_merge(M)) + to_chat(src, "You fail to merge with \the [M]...") + +/mob/living/carbon/alien/diona/proc/do_merge(var/mob/living/carbon/human/H) + if(!istype(H) || !src || !(src.Adjacent(H))) + return 0 + to_chat(H, "You feel your being twine with that of \the [src] as it merges with your biomass.") + H.status_flags |= PASSEMOTES + to_chat(src, "You feel your being twine with that of \the [H] as you merge with its biomass.") + loc = H + verbs += /mob/living/carbon/alien/diona/proc/split + verbs -= /mob/living/carbon/alien/diona/proc/merge + return 1 + +/mob/living/carbon/alien/diona/proc/split() + + set category = "Abilities" + set name = "Split from gestalt" + set desc = "Split away from your gestalt as a lone nymph." + + if(stat == DEAD || paralysis || weakened || stunned || restrained()) + return + + if(!(istype(src.loc,/mob/living/carbon))) + src.verbs -= /mob/living/carbon/alien/diona/proc/split + return + + to_chat(src.loc, "You feel a pang of loss as [src] splits away from your biomass.") + to_chat(src, "You wiggle out of the depths of [src.loc]'s biomass and plop to the ground.") + + var/mob/living/M = src.loc + + src.loc = get_turf(src) + src.verbs -= /mob/living/carbon/alien/diona/proc/split + src.verbs += /mob/living/carbon/alien/diona/proc/merge + + if(istype(M)) + for(var/atom/A in M.contents) + if(istype(A,/mob/living/simple_animal/borer) || istype(A,/obj/item/weapon/holder)) + return + M.status_flags &= ~PASSEMOTES \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/life.dm b/code/modules/mob/living/carbon/alien/diona/life.dm new file mode 100644 index 00000000..76b9d6a1 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/diona/life.dm @@ -0,0 +1,20 @@ +//Dionaea regenerate health and nutrition in light. +/mob/living/carbon/alien/diona/handle_environment(datum/gas_mixture/environment) + + var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing + if(isturf(loc)) //else, there's considered to be no light + var/turf/T = loc + light_amount = T.get_lumcount() * 5 + + nutrition += light_amount + + if(nutrition > 500) + nutrition = 500 + if(light_amount > 2) //if there's enough light, heal + adjustBruteLoss(-1) + adjustFireLoss(-1) + adjustToxLoss(-1) + adjustOxyLoss(-1) + + if(!client) + handle_npc(src) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/progression.dm b/code/modules/mob/living/carbon/alien/diona/progression.dm new file mode 100644 index 00000000..f2ae9acc --- /dev/null +++ b/code/modules/mob/living/carbon/alien/diona/progression.dm @@ -0,0 +1,19 @@ +/mob/living/carbon/alien/diona/confirm_evolution() + + if(!is_species_whitelisted(src, SPECIES_DIONA)) + to_chat(src, alert("You are currently not whitelisted to play as a full diona.")) + return null + + if(amount_grown < max_grown) + to_chat(src, "You are not yet ready for your growth...") + return null + + src.split() + + if(istype(loc,/obj/item/weapon/holder/diona)) + var/obj/item/weapon/holder/diona/L = loc + src.forceMove(L.loc) + qdel(L) + + src.visible_message("\The [src] begins to shift and quiver, and erupts in a shower of shed bark as it splits into a tangle of nearly a dozen new dionaea.","You begin to shift and quiver, feeling your awareness splinter. All at once, we consume our stored nutrients to surge with growth, splitting into a tangle of at least a dozen new dionaea. We have attained our gestalt form.") + return SPECIES_DIONA \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/say_understands.dm b/code/modules/mob/living/carbon/alien/diona/say_understands.dm new file mode 100644 index 00000000..3f68a44c --- /dev/null +++ b/code/modules/mob/living/carbon/alien/diona/say_understands.dm @@ -0,0 +1,6 @@ +/mob/living/carbon/alien/diona/say_understands(var/mob/other,var/datum/language/speaking = null) + + if (istype(other, /mob/living/carbon/human) && !speaking) + if(languages.len >= 2) // They have sucked down some blood. + return 1 + return ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/update_icons.dm b/code/modules/mob/living/carbon/alien/diona/update_icons.dm new file mode 100644 index 00000000..1d694cf6 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/diona/update_icons.dm @@ -0,0 +1,12 @@ +/mob/living/carbon/alien/diona/update_icons() + + if(stat == DEAD) + icon_state = "[initial(icon_state)]_dead" + else if(lying || resting || stunned) + icon_state = "[initial(icon_state)]_sleep" + else + icon_state = "[initial(icon_state)]" + + overlays.Cut() + if(hat) + overlays |= get_hat_icon(hat, 0, -8) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm new file mode 100644 index 00000000..aba83e9a --- /dev/null +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -0,0 +1,15 @@ +/mob/living/carbon/alien/larva + name = "alien larva" + real_name = "alien larva" + adult_form = /mob/living/carbon/human + speak_emote = list("hisses") + icon_state = "larva" + language = "Hivemind" + maxHealth = 25 + health = 25 + +/mob/living/carbon/alien/larva/New() + ..() + add_language("Xenophage") //Bonus language. + internal_organs |= new /obj/item/organ/internal/xenos/hivenode(src) + create_reagents(100) \ 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 new file mode 100644 index 00000000..aceee4bc --- /dev/null +++ b/code/modules/mob/living/carbon/alien/larva/life.dm @@ -0,0 +1,34 @@ +#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/vine/plant = locate() in T + if(environment.gas["phoron"] > 0 || (plant && plant.seed.type == /datum/seed/xenomorph)) + 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 + to_chat(src, "This host is depleted of blood...") + leave_host() + +#undef MIN_LARVA_BLOOD_DRINK diff --git a/code/modules/mob/living/carbon/alien/larva/powers.dm b/code/modules/mob/living/carbon/alien/larva/powers.dm new file mode 100644 index 00000000..866dfd3b --- /dev/null +++ b/code/modules/mob/living/carbon/alien/larva/powers.dm @@ -0,0 +1,111 @@ +/mob/living/carbon/alien/larva/proc/check_can_infest(var/mob/living/M) + if(!src) + return 0 + if(!istype(loc, /turf)) + to_chat(src, "You cannot infest a target in your current position.") + return 0 + if(incapacitated()) + to_chat(src, "You cannot infest a target in your current state.") + return 0 + if(!M) + return 1 + if(!M.lying) + to_chat(src, "\The [M] is not prone.") + return 0 + if(!(src.Adjacent(M))) + to_chat(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) + to_chat(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, H)) + return + + if(!check_can_infest(H)) + return + + var/obj/item/organ/external/E = pick(H.organs) + to_chat(src, "You burrow deeply into \the [H]'s [E.name]!") + var/obj/item/weapon/holder/holder = new (loc) + src.loc = holder + holder.SetName(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()) + to_chat(src, "You cannot leave your host in your current state.") + return + + if(!loc || !loc.loc) + to_chat(src, "You are not inside a host.") + return + + var/mob/living/carbon/human/H = loc.loc + + if(!istype(H)) + to_chat(src, "You are not inside a host.") + return + + to_chat(src, "You begin writhing your way free of \the [H]'s flesh...") + + if(!do_after(src, 30, H)) + return + + if(!H || !src) + return + + leave_host() + +/mob/living/carbon/alien/larva/proc/leave_host() + if(!loc || !loc.loc) + to_chat(src, "You are not inside a host.") + return + var/mob/living/carbon/human/H = loc.loc + if(!istype(H)) + to_chat(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) + to_chat(src, "You crawl out of \the [H]'s [affected.name] and plop to the ground.") + else + to_chat(src, "You plop to the ground.") diff --git a/code/modules/mob/living/carbon/alien/larva/progression.dm b/code/modules/mob/living/carbon/alien/larva/progression.dm new file mode 100644 index 00000000..1c2f329b --- /dev/null +++ b/code/modules/mob/living/carbon/alien/larva/progression.dm @@ -0,0 +1,12 @@ +/mob/living/carbon/alien/larva/confirm_evolution() + + to_chat(src, "You are growing into a beautiful alien! It is time to choose a caste.") + to_chat(src, "There are three to choose from:") + to_chat(src, "Hunters are strong and agile, able to hunt away from the hive and rapidly move through ventilation shafts. Hunters generate plasma slowly and have low reserves.") + to_chat(src, "Sentinels are tasked with protecting the hive and are deadly up close and at a range. They are not as physically imposing nor fast as the hunters.") + to_chat(src, "Drones are the working class, offering the largest plasma storage and generation. They are the only caste which may evolve again, turning into the dreaded alien queen.") + var/alien_caste = alert(src, "Please choose which alien caste you shall belong to.",,"Hunter","Sentinel","Drone") + return alien_caste ? "Xenophage [alien_caste]" : null + +/mob/living/carbon/alien/larva/show_evolution_blurb() + return \ 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 new file mode 100644 index 00000000..05c1f7b1 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/life.dm @@ -0,0 +1,148 @@ +// Alien larva are quite simple. +/mob/living/carbon/alien/Life() + + set invisibility = 0 + set background = 1 + + if (transforming) return + if(!loc) return + + ..() + + if (stat != DEAD && can_progress()) + update_progression() + + blinded = null + + //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 + // rad absorbtion here. This will need to be changed if other baby aliens are added. + + if(!radiation) + return + + var/rads = radiation/25 + radiation -= rads + nutrition += rads + heal_overall_damage(rads,rads) + adjustOxyLoss(-(rads)) + adjustToxLoss(-(rads)) + return + +/mob/living/carbon/alien/handle_regular_status_updates() + + if(status_flags & GODMODE) return 0 + + if(stat == DEAD) + blinded = 1 + silent = 0 + else + updatehealth() + if(health <= 0) + death() + blinded = 1 + silent = 0 + return 1 + + if(paralysis && paralysis > 0) + blinded = 1 + set_stat(UNCONSCIOUS) + if(getHalLoss() > 0) + adjustHalLoss(-3) + + if(sleeping) + adjustHalLoss(-3) + if (mind) + if(mind.active && client != null) + sleeping = max(sleeping-1, 0) + blinded = 1 + set_stat(UNCONSCIOUS) + else if(resting) + if(getHalLoss() > 0) + adjustHalLoss(-3) + + else + set_stat(CONSCIOUS) + if(getHalLoss() > 0) + adjustHalLoss(-1) + + // Eyes and blindness. + if(!has_eyes()) + eye_blind = 1 + blinded = 1 + eye_blurry = 1 + else if(eye_blind) + eye_blind = max(eye_blind-1,0) + blinded = 1 + else if(eye_blurry) + eye_blurry = max(eye_blurry-1, 0) + + update_icons() + + return 1 + +/mob/living/carbon/alien/handle_regular_hud_updates() + update_sight() + if (healths) + if (stat != 2) + switch(health) + if(100 to INFINITY) + healths.icon_state = "health0" + if(80 to 100) + healths.icon_state = "health1" + if(60 to 80) + healths.icon_state = "health2" + if(40 to 60) + healths.icon_state = "health3" + if(20 to 40) + healths.icon_state = "health4" + if(0 to 20) + healths.icon_state = "health5" + else + healths.icon_state = "health6" + else + healths.icon_state = "health7" + + if(stat != DEAD) + if(blinded) + overlay_fullscreen("blind", /obj/screen/fullscreen/blind) + else + clear_fullscreen("blind") + set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1) + set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry) + set_fullscreen(druggy, "high", /obj/screen/fullscreen/high) + if(machine) + if(machine.check_eye(src) < 0) + reset_view(null) + else + if(client && !client.adminobs) + reset_view(null) + + return 1 + +/mob/living/carbon/alien/handle_environment(var/datum/gas_mixture/environment) + // Both alien subtypes survive in vaccum and suffer in high temperatures, + // so I'll just define this once, for both (see radiation comment above) + if(!environment) return + + if(environment.temperature > (T0C+66)) + adjustFireLoss((environment.temperature - (T0C+66))/5) // Might be too high, check in testing. + if (fire) fire.icon_state = "fire2" + if(prob(20)) + to_chat(src, "You feel a searing heat!") + else + if (fire) fire.icon_state = "fire0" + +/mob/living/carbon/alien/handle_fire() + if(..()) + return + bodytemperature += BODYTEMP_HEATING_MAX //If you're on fire, you heat up! + return diff --git a/code/modules/mob/living/carbon/alien/progression.dm b/code/modules/mob/living/carbon/alien/progression.dm new file mode 100644 index 00000000..68e9ed8f --- /dev/null +++ b/code/modules/mob/living/carbon/alien/progression.dm @@ -0,0 +1,67 @@ +/mob/living/carbon/alien/Stat() + . = ..() + if(. && statpanel("Status")) + stat("Growth", "[round(amount_grown)]/[max_grown]") + +/mob/living/carbon/alien/verb/evolve() + + set name = "Moult" + set desc = "Moult your skin and become an adult." + set category = "Abilities" + + if(stat != CONSCIOUS) + return + + if(!adult_form) + verbs -= /mob/living/carbon/alien/verb/evolve + return + + if(handcuffed) + to_chat(src, "You cannot evolve when you are cuffed.") + return + + if(amount_grown < max_grown) + to_chat(src, "You are not fully grown.") + return + + // confirm_evolution() handles choices and other specific requirements. + var/new_species = confirm_evolution() + if(!new_species || !adult_form ) + return + + 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. + + transfer_languages(src, adult) + + if(mind) + mind.transfer_to(adult) + if (can_namepick_as_adult) + var/newname = sanitize(input(adult, "You have become an adult. Choose a name for yourself.", "Adult Name") as null|text, MAX_NAME_LEN) + + if(!newname) + adult.fully_replace_character_name("[src.adult_name] ([instance_num])") + else + adult.fully_replace_character_name(newname) + else + adult.key = src.key + + for (var/obj/item/W in src.contents) + src.drop_from_inventory(W) + + for(var/datum/language/L in languages) + adult.add_language(L.name) + qdel(src) + +/mob/living/carbon/alien/proc/update_progression() + if(amount_grown < max_grown) + amount_grown++ + return + +/mob/living/carbon/alien/proc/confirm_evolution() + return + +/mob/living/carbon/alien/proc/show_evolution_blurb() + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/say.dm b/code/modules/mob/living/carbon/alien/say.dm new file mode 100644 index 00000000..df783af0 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/say.dm @@ -0,0 +1,25 @@ +/mob/living/carbon/alien/say(var/message) + var/verb = "says" + var/message_range = world.view + + if(client) + if(client.prefs.muted & MUTE_IC) + to_chat(src, "You cannot speak in IC (Muted).") + return + + message = sanitize(message) + + if(stat == 2) + return say_dead(message) + + if(copytext(message,1,2) == get_prefix_key(/decl/prefix/custom_emote)) + return emote(copytext(message,2)) + + var/datum/language/speaking = parse_language(message) + + message = trim(message) + + if(!message || stat) + return + + ..(message, speaking, verb, null, null, message_range, null) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/update_icons.dm b/code/modules/mob/living/carbon/alien/update_icons.dm new file mode 100644 index 00000000..7bb90a4d --- /dev/null +++ b/code/modules/mob/living/carbon/alien/update_icons.dm @@ -0,0 +1,20 @@ +/mob/living/carbon/alien/regenerate_icons() + overlays = list() + update_icons() + +/mob/living/carbon/alien/update_icons() + + var/state = 0 + if(amount_grown > max_grown*0.75) + state = 2 + else if(amount_grown > max_grown*0.25) + state = 1 + + if(stat == DEAD) + icon_state = "[initial(icon_state)][state]_dead" + else if (stunned) + icon_state = "[initial(icon_state)][state]_stun" + else if(lying || resting) + icon_state = "[initial(icon_state)][state]_sleep" + else + icon_state = "[initial(icon_state)][state]" diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm new file mode 100644 index 00000000..d9f892f7 --- /dev/null +++ b/code/modules/mob/living/carbon/brain/MMI.dm @@ -0,0 +1,190 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/obj/item/device/mmi/digital/New() + src.brainmob = new(src) + src.brainmob.set_stat(CONSCIOUS) + src.brainmob.add_language("Robot Talk") + src.brainmob.add_language("Encoded Audio Language") + + src.brainmob.container = src + src.brainmob.silent = 0 + PickName() + ..() + +/obj/item/device/mmi/digital/proc/PickName() + return + +/obj/item/device/mmi/digital/attackby() + return + +/obj/item/device/mmi/digital/attack_self() + return + +/obj/item/device/mmi/digital/transfer_identity(var/mob/living/carbon/H) + brainmob.dna = H.dna + brainmob.timeofhostdeath = H.timeofdeath + brainmob.set_stat(CONSCIOUS) + if(H.mind) + H.mind.transfer_to(brainmob) + return + +/obj/item/device/mmi + name = "\improper Man-Machine Interface" + desc = "A complex life support shell that interfaces between a brain and electronic devices." + icon = 'icons/obj/assemblies.dmi' + icon_state = "mmi_empty" + w_class = ITEM_SIZE_NORMAL + origin_tech = list(TECH_BIO = 3) + + req_access = list(access_robotics) + + //Revised. Brainmob is now contained directly within object of transfer. MMI in this case. + + var/locked = 0 + var/mob/living/carbon/brain/brainmob = null//The current occupant. + var/obj/item/organ/internal/brain/brainobj = null //The current brain organ. + var/obj/mecha = null//This does not appear to be used outside of reference in mecha.dm. + +/obj/item/device/mmi/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(istype(O,/obj/item/organ/internal/brain) && !brainmob) //Time to stick a brain in it --NEO + + var/obj/item/organ/internal/brain/B = O + if(B.damage >= B.max_damage) + to_chat(user, "That brain is well and truly dead.") + return + else if(!B.brainmob || !B.can_use_mmi) + to_chat(user, "This brain is completely useless to you.") + return + + user.visible_message("\The [user] sticks \a [O] into \the [src].") + + brainmob = B.brainmob + B.brainmob = null + brainmob.forceMove(src) + brainmob.container = src + brainmob.set_stat(CONSCIOUS) + brainmob.switch_from_dead_to_living_mob_list() //Update dem lists + + user.drop_item() + brainobj = O + brainobj.forceMove(src) + + SetName("[initial(name)]: ([brainmob.real_name])") + icon_state = "mmi_full" + + locked = 1 + + feedback_inc("cyborg_mmis_filled",1) + + return + + if((istype(O,/obj/item/weapon/card/id)||istype(O,/obj/item/device/pda)) && brainmob) + if(allowed(user)) + locked = !locked + to_chat(user, "You [locked ? "lock" : "unlock"] the brain holder.") + else + to_chat(user, "Access denied.") + return + if(brainmob) + O.attack(brainmob, user)//Oh noooeeeee + return + ..() + + //TODO: ORGAN REMOVAL UPDATE. Make the brain remain in the MMI so it doesn't lose organ data. +/obj/item/device/mmi/attack_self(mob/user as mob) + if(!brainmob) + to_chat(user, "You upend the MMI, but there's nothing in it.") + else if(locked) + to_chat(user, "You upend the MMI, but the brain is clamped into place.") + else + to_chat(user, "You upend the MMI, spilling the brain onto the floor.") + var/obj/item/organ/internal/brain/brain + if (brainobj) //Pull brain organ out of MMI. + brainobj.forceMove(user.loc) + brain = brainobj + brainobj = null + else //Or make a new one if empty. + brain = new(user.loc) + brainmob.container = null//Reset brainmob mmi var. + brainmob.loc = brain//Throw mob into brain. + brainmob.remove_from_living_mob_list() //Get outta here + brain.brainmob = brainmob//Set the brain to use the brainmob + brainmob = null//Set mmi brainmob var to null + + icon_state = "mmi_empty" + SetName(initial(name)) + +/obj/item/device/mmi/proc/transfer_identity(var/mob/living/carbon/human/H)//Same deal as the regular brain proc. Used for human-->robot people. + brainmob = new(src) + brainmob.SetName(H.real_name) + brainmob.real_name = H.real_name + brainmob.dna = H.dna + brainmob.container = src + + SetName("[initial(name)]: [brainmob.real_name]") + icon_state = "mmi_full" + locked = 1 + return + +/obj/item/device/mmi/relaymove(var/mob/user, var/direction) + if(user.stat || user.stunned) + return + +/obj/item/device/mmi/Destroy() + if(isrobot(loc)) + var/mob/living/silicon/robot/borg = loc + borg.mmi = null + QDEL_NULL(brainmob) + return ..() + +/obj/item/device/mmi/radio_enabled + name = "radio-enabled man-machine interface" + desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity. This one comes with a built-in radio." + origin_tech = list(TECH_BIO = 4) + + var/obj/item/device/radio/radio = null//Let's give it a radio. + + New() + ..() + radio = new(src)//Spawns a radio inside the MMI. + radio.broadcasting = 1//So it's broadcasting from the start. + + verb//Allows the brain to toggle the radio functions. + Toggle_Broadcasting() + set name = "Toggle Broadcasting" + set desc = "Toggle broadcasting channel on or off." + set category = "MMI" + set src = usr.loc//In user location, or in MMI in this case. + set popup_menu = 0//Will not appear when right clicking. + + if(brainmob.stat)//Only the brainmob will trigger these so no further check is necessary. + to_chat(brainmob, "Can't do that while incapacitated or dead.") + + radio.broadcasting = radio.broadcasting==1 ? 0 : 1 + to_chat(brainmob, "Radio is [radio.broadcasting==1 ? "now" : "no longer"] broadcasting.") + + Toggle_Listening() + set name = "Toggle Listening" + set desc = "Toggle listening channel on or off." + set category = "MMI" + set src = usr.loc + set popup_menu = 0 + + if(brainmob.stat) + to_chat(brainmob, "Can't do that while incapacitated or dead.") + + radio.listening = radio.listening==1 ? 0 : 1 + to_chat(brainmob, "Radio is [radio.listening==1 ? "now" : "no longer"] receiving broadcast.") + +/obj/item/device/mmi/emp_act(severity) + if(!brainmob) + return + else + switch(severity) + if(1) + brainmob.emp_damage += rand(20,30) + if(2) + brainmob.emp_damage += rand(10,20) + if(3) + brainmob.emp_damage += rand(0,10) + ..() diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/carbon/brain/brain.dm new file mode 100644 index 00000000..056b47d3 --- /dev/null +++ b/code/modules/mob/living/carbon/brain/brain.dm @@ -0,0 +1,66 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/mob/living/carbon/brain + var/obj/item/container = null + var/timeofhostdeath = 0 + var/emp_damage = 0//Handles a type of MMI damage + var/alert = null + use_me = 0 //Can't use the me verb, it's a freaking immobile brain + icon = 'icons/obj/surgery.dmi' + icon_state = "brain1" + +/mob/living/carbon/brain/New() + create_reagents(1000) + ..() + +/mob/living/carbon/brain/Destroy() + if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting. + if(stat!=DEAD) //If not dead. + death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA + ghostize() //Ghostize checks for key so nothing else is necessary. + . = ..() + +/mob/living/carbon/brain/say_understands(var/other)//Goddamn is this hackish, but this say code is so odd + if (istype(other, /mob/living/silicon/ai)) + if(!(container && istype(container, /obj/item/device/mmi))) + return 0 + else + return 1 + if (istype(other, /mob/living/silicon/decoy)) + if(!(container && istype(container, /obj/item/device/mmi))) + return 0 + else + return 1 + if (istype(other, /mob/living/silicon/pai)) + if(!(container && istype(container, /obj/item/device/mmi))) + return 0 + else + return 1 + if (istype(other, /mob/living/silicon/robot)) + if(!(container && istype(container, /obj/item/device/mmi))) + return 0 + else + return 1 + if (istype(other, /mob/living/carbon/human)) + return 1 + if (istype(other, /mob/living/carbon/slime)) + return 1 + return ..() + +/mob/living/carbon/brain/update_canmove() + if(in_contents_of(/obj/mecha) || istype(loc, /obj/item/device/mmi)) + canmove = 1 + use_me = 1 + else + canmove = 0 + return canmove + +/mob/living/carbon/brain/isSynthetic() + return istype(loc, /obj/item/device/mmi/digital) + +/mob/living/carbon/brain/binarycheck() + return isSynthetic() + +/mob/living/carbon/brain/check_has_mouth() + return 0 + diff --git a/code/modules/mob/living/carbon/brain/death.dm b/code/modules/mob/living/carbon/brain/death.dm new file mode 100644 index 00000000..44aabb30 --- /dev/null +++ b/code/modules/mob/living/carbon/brain/death.dm @@ -0,0 +1,14 @@ +/mob/living/carbon/brain/death(gibbed) + if(!gibbed && istype(container, /obj/item/device/mmi)) //If not gibbed but in a container. + container.icon_state = "mmi_dead" + return ..(gibbed,"beeps shrilly as the MMI flatlines!") + else + return ..(gibbed,"no message") + +/mob/living/carbon/brain/gib() + if(istype(container, /obj/item/device/mmi)) + qdel(container)//Gets rid of the MMI if there is one + if(loc) + if(istype(loc,/obj/item/organ/internal/brain)) + qdel(loc)//Gets rid of the brain item + ..(null,1) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/brain/life.dm b/code/modules/mob/living/carbon/brain/life.dm new file mode 100644 index 00000000..bf70b42a --- /dev/null +++ b/code/modules/mob/living/carbon/brain/life.dm @@ -0,0 +1,202 @@ +/mob/living/carbon/brain/handle_breathing() + return + +/mob/living/carbon/brain/handle_mutations_and_radiation() + if (radiation) + if (radiation > 100) + radiation = 100 + if(!container)//If it's not in an MMI + to_chat(src, "You feel weak.") + else//Fluff-wise, since the brain can't detect anything itself, the MMI handles thing like that + to_chat(src, "STATUS: CRITICAL AMOUNTS OF RADIATION DETECTED.") + switch(radiation) + if(1 to 49) + radiation-- + if(prob(25)) + adjustToxLoss(1) + updatehealth() + + if(50 to 74) + radiation -= 2 + adjustToxLoss(1) + if(prob(5)) + radiation -= 5 + if(!container) + to_chat(src, "You feel weak.") + else + to_chat(src, "STATUS: DANGEROUS LEVELS OF RADIATION DETECTED.") + updatehealth() + + if(75 to 100) + radiation -= 3 + adjustToxLoss(3) + updatehealth() + + +/mob/living/carbon/brain/handle_environment(datum/gas_mixture/environment) + if(!environment) + return + var/environment_heat_capacity = environment.heat_capacity() + if(istype(get_turf(src), /turf/space)) + var/turf/heat_turf = get_turf(src) + environment_heat_capacity = heat_turf.heat_capacity + + if((environment.temperature > (T0C + 50)) || (environment.temperature < (T0C + 10))) + var/transfer_coefficient = 1 + + handle_temperature_damage(HEAD, environment.temperature, environment_heat_capacity*transfer_coefficient) + + if(stat==2) + bodytemperature += 0.1*(environment.temperature - bodytemperature)*environment_heat_capacity/(environment_heat_capacity + 270000) + + //Account for massive pressure differences + + return //TODO: DEFERRED + +/mob/living/carbon/brain/proc/handle_temperature_damage(body_part, exposed_temperature, exposed_intensity) + if(status_flags & GODMODE) return + + if(exposed_temperature > bodytemperature) + var/discomfort = min( abs(exposed_temperature - bodytemperature)*(exposed_intensity)/2000000, 1.0) + //adjustFireLoss(2.5*discomfort) + //adjustFireLoss(5.0*discomfort) + adjustFireLoss(20.0*discomfort) + + else + var/discomfort = min( abs(exposed_temperature - bodytemperature)*(exposed_intensity)/2000000, 1.0) + //adjustFireLoss(2.5*discomfort) + adjustFireLoss(5.0*discomfort) + + +/mob/living/carbon/brain/handle_chemicals_in_body() + chem_effects.Cut() + + if(touching) touching.metabolize() + if(ingested) ingested.metabolize() + if(bloodstr) bloodstr.metabolize() + + confused = max(0, confused - 1) + // decrement dizziness counter, clamped to 0 + if(resting) + dizziness = max(0, dizziness - 5) + else + dizziness = max(0, dizziness - 1) + + updatehealth() + + return //TODO: DEFERRED + +/mob/living/carbon/brain/handle_regular_status_updates() //TODO: comment out the unused bits >_> + updatehealth() + + if(stat == DEAD) //DEAD. BROWN BREAD. SWIMMING WITH THE SPESS CARP + blinded = 1 + silent = 0 + else //ALIVE. LIGHTS ARE ON + if( !container && (health < config.health_threshold_dead || ((world.time - timeofhostdeath) > config.revival_brain_life)) ) + death() + blinded = 1 + silent = 0 + return 1 + + //Handling EMP effect in the Life(), it's made VERY simply, and has some additional effects handled elsewhere + if(emp_damage) //This is pretty much a damage type only used by MMIs, dished out by the emp_act + if(!(container && istype(container, /obj/item/device/mmi))) + emp_damage = 0 + else + emp_damage = round(emp_damage,1)//Let's have some nice numbers to work with + switch(emp_damage) + if(31 to INFINITY) + emp_damage = 30//Let's not overdo it + if(21 to 30)//High level of EMP damage, unable to see, hear, or speak + eye_blind = 1 + blinded = 1 + ear_deaf = 1 + silent = 1 + if(!alert)//Sounds an alarm, but only once per 'level' + emote("alarm") + to_chat(src, "Major electrical distruption detected: System rebooting.") + alert = 1 + if(prob(75)) + emp_damage -= 1 + if(20) + alert = 0 + blinded = 0 + eye_blind = 0 + ear_deaf = 0 + silent = 0 + emp_damage -= 1 + if(11 to 19)//Moderate level of EMP damage, resulting in nearsightedness and ear damage + eye_blurry = 1 + ear_damage = 1 + if(!alert) + emote("alert") + to_chat(src, "Primary systems are now online.") + alert = 1 + if(prob(50)) + emp_damage -= 1 + if(10) + alert = 0 + eye_blurry = 0 + ear_damage = 0 + emp_damage -= 1 + if(2 to 9)//Low level of EMP damage, has few effects(handled elsewhere) + if(!alert) + emote("notice") + to_chat(src, "System reboot nearly complete.") + alert = 1 + if(prob(25)) + emp_damage -= 1 + if(1) + alert = 0 + to_chat(src, "All systems restored.") + emp_damage -= 1 + + return 1 + +/mob/living/carbon/brain/handle_regular_hud_updates() + update_sight() + if (healths) + if (stat != 2) + switch(health) + if(100 to INFINITY) + healths.icon_state = "health0" + if(80 to 100) + healths.icon_state = "health1" + if(60 to 80) + healths.icon_state = "health2" + if(40 to 60) + healths.icon_state = "health3" + if(20 to 40) + healths.icon_state = "health4" + if(0 to 20) + healths.icon_state = "health5" + else + healths.icon_state = "health6" + else + healths.icon_state = "health7" + + if(stat != DEAD) + if(blinded) + overlay_fullscreen("blind", /obj/screen/fullscreen/blind) + else + clear_fullscreen("blind") + set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1) + set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry) + set_fullscreen(druggy, "high", /obj/screen/fullscreen/high) + if (machine) + if (!( machine.check_eye(src) )) + reset_view(null) + else + if(client && !client.adminobs) + reset_view(null) + + return 1 + + if (stat != 2) + if (machine) + if (machine.check_eye(src) < 0) + reset_view(null) + else + if(client && !client.adminobs) + reset_view(null) diff --git a/code/modules/mob/living/carbon/brain/login.dm b/code/modules/mob/living/carbon/brain/login.dm new file mode 100644 index 00000000..57c41cc6 --- /dev/null +++ b/code/modules/mob/living/carbon/brain/login.dm @@ -0,0 +1,3 @@ +/mob/living/carbon/brain/Login() + ..() + sleeping = 0 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/brain/robot.dm b/code/modules/mob/living/carbon/brain/robot.dm new file mode 100644 index 00000000..4c7b3a8f --- /dev/null +++ b/code/modules/mob/living/carbon/brain/robot.dm @@ -0,0 +1,18 @@ +/obj/item/device/mmi/digital/robot + name = "robotic intelligence circuit" + desc = "The pinnacle of artifical intelligence which can be achieved using classical computer science." + icon = 'icons/obj/module.dmi' + icon_state = "mainboard" + w_class = ITEM_SIZE_NORMAL + origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 3, TECH_DATA = 4) + +/obj/item/device/mmi/digital/robot/PickName() + src.brainmob.SetName("[pick(list("ADA","DOS","GNU","MAC","WIN"))]-[random_id(type,1000,9999)]") + src.brainmob.real_name = src.brainmob.name + +/obj/item/device/mmi/digital/robot/transfer_identity(var/mob/living/carbon/H) + ..() + if(brainmob.mind) + brainmob.mind.assigned_role = "Robotic Intelligence" + to_chat(brainmob, "You feel slightly disoriented. That's normal when you're little more than a complex circuit.") + return diff --git a/code/modules/mob/living/carbon/brain/say.dm b/code/modules/mob/living/carbon/brain/say.dm new file mode 100644 index 00000000..3f369ac0 --- /dev/null +++ b/code/modules/mob/living/carbon/brain/say.dm @@ -0,0 +1,38 @@ +//TODO: Convert this over for languages. +/mob/living/carbon/brain/say(var/message) + if (silent) + return + + message = sanitize(message) + + if(!(container && istype(container, /obj/item/device/mmi))) + return //No MMI, can't speak, bucko./N + else + var/datum/language/speaking = parse_language(message) + if(speaking) + message = copytext(message, 2+length(speaking.key)) + var/verb = "says" + var/ending = copytext(message, length(message)) + if (speaking) + verb = speaking.get_spoken_verb(ending) + else + if(ending=="!") + verb=pick("exclaims","shouts","yells") + if(ending=="?") + verb="asks" + + if(prob(emp_damage*4)) + if(prob(10))//10% chane to drop the message entirely + return + else + message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher + + if(speaking && speaking.flags & HIVEMIND) + speaking.broadcast(src,trim(message)) + return + + if(istype(container, /obj/item/device/mmi/radio_enabled)) + var/obj/item/device/mmi/radio_enabled/R = container + if(R.radio) + spawn(0) R.radio.hear_talk(src, sanitize(message), verb, speaking) + ..(trim(message), speaking, verb) diff --git a/code/modules/mob/living/carbon/breathe.dm b/code/modules/mob/living/carbon/breathe.dm new file mode 100644 index 00000000..121a3dad --- /dev/null +++ b/code/modules/mob/living/carbon/breathe.dm @@ -0,0 +1,100 @@ +//Common breathing procs + +#define MOB_BREATH_DELAY 2 + +//Start of a breath chain, calls breathe() +/mob/living/carbon/handle_breathing() + if((life_tick % MOB_BREATH_DELAY) == 0 || failed_last_breath || is_asystole()) //First, resolve location and get a breath + breathe() + +/mob/living/carbon/proc/breathe(var/active_breathe = 1) + //if(istype(loc, /obj/machinery/atmospherics/unary/cryo_cell)) return + if(!need_breathe()) return + + var/datum/gas_mixture/breath = null + + //First, check if we can breathe at all + if(is_asystole() && !(CE_STABLE in chem_effects) && active_breathe) //crit aka circulatory shock + losebreath = max(2, losebreath + 1) + + check_drowning() + + if(losebreath>0) //Suffocating so do not take a breath + losebreath-- + //if (prob(10) && !is_asystole() && active_breathe) //Gasp per 10 ticks? Sounds about right. + // emote("gasp") + else + //Okay, we can breathe, now check if we can get air + var/volume_needed = get_breath_volume() + breath = get_breath_from_internal(volume_needed) //First, check for air from internals + if(!breath) + breath = get_breath_from_environment(volume_needed) //No breath from internals so let's try to get air from our location + if(!breath) + var/static/datum/gas_mixture/vacuum //avoid having to create a new gas mixture for each breath in space + if(!vacuum) vacuum = new + + breath = vacuum //still nothing? must be vacuum + + handle_breath(breath) + handle_post_breath(breath) + + + +/mob/living/carbon/proc/get_breath_from_internal(var/volume_needed=STD_BREATH_VOLUME) //hopefully this will allow overrides to specify a different default volume without breaking any cases where volume is passed in. + if(internal) + if (!contents.Find(internal)) + internal = null + if (!(wear_mask && (wear_mask.item_flags & ITEM_FLAG_AIRTIGHT))) + internal = null + if(internal) + if (internals) + internals.icon_state = "internal1" + return internal.remove_air_volume(volume_needed) + else + if (internals) + internals.icon_state = "internal0" + return null + +/mob/living/carbon/proc/get_breath_from_environment(var/volume_needed=STD_BREATH_VOLUME) + var/datum/gas_mixture/breath = null + + var/datum/gas_mixture/environment + if(loc) + environment = loc.return_air_for_internal_lifeform() + + if(environment) + breath = environment.remove_volume(volume_needed) + handle_chemical_smoke(environment) //handle chemical smoke while we're at it + + if(breath && breath.total_moles) + //handle mask filtering + if(istype(wear_mask, /obj/item/clothing/mask) && breath) + var/obj/item/clothing/mask/M = wear_mask + var/datum/gas_mixture/filtered = M.filter_air(breath) + loc.assume_air(filtered) + return breath + return null + +//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.item_flags & ITEM_FLAG_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) + // 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 + +/mob/living/carbon/proc/get_breath_volume() + return STD_BREATH_VOLUME + +/mob/living/carbon/proc/handle_breath(datum/gas_mixture/breath) + return + +/mob/living/carbon/proc/handle_post_breath(datum/gas_mixture/breath) + if(breath) + loc.assume_air(breath) //by default, exhale diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm new file mode 100644 index 00000000..c26569f9 --- /dev/null +++ b/code/modules/mob/living/carbon/carbon.dm @@ -0,0 +1,526 @@ +/mob/living/carbon/New() + //setup reagent holders + bloodstr = new/datum/reagents/metabolism(1000, src, CHEM_BLOOD) + ingested = new/datum/reagents/metabolism(1000, src, CHEM_INGEST) + touching = new/datum/reagents/metabolism(1000, src, CHEM_TOUCH) + reagents = bloodstr + + if (!default_language && species_language) + default_language = all_languages[species_language] + ..() + +/mob/living/carbon/Destroy() + QDEL_NULL(ingested) + QDEL_NULL(touching) + // We don't qdel(bloodstr) because it's the same as qdel(reagents) + QDEL_NULL_LIST(internal_organs) + QDEL_NULL_LIST(stomach_contents) + QDEL_NULL_LIST(hallucinations) + return ..() + +/mob/living/carbon/rejuvenate() + bloodstr.clear_reagents() + ingested.clear_reagents() + touching.clear_reagents() + nutrition = 400 + ..() + +/mob/living/carbon/Move(NewLoc, direct) + . = ..() + if(.) + if(src.nutrition && src.stat != 2) + src.nutrition -= DEFAULT_HUNGER_FACTOR/10 + if(src.m_intent == "run") + src.nutrition -= DEFAULT_HUNGER_FACTOR/10 + if((FAT in src.mutations) && src.m_intent == "run" && src.bodytemperature <= 360) + src.bodytemperature += 2 + + // Moving around increases germ_level faster + if(germ_level < GERM_LEVEL_MOVE_CAP && prob(8)) + germ_level++ + +/mob/living/carbon/relaymove(var/mob/living/user, direction) + if((user in src.stomach_contents) && istype(user)) + if(user.last_special <= world.time) + user.last_special = world.time + 50 + src.visible_message("You hear something rumbling inside [src]'s stomach...") + var/obj/item/I = user.get_active_hand() + if(I && I.force) + var/d = rand(round(I.force / 4), I.force) + if(istype(src, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = src + var/obj/item/organ/external/organ = H.get_organ(BP_CHEST) + if (istype(organ)) + organ.take_damage(d, 0) + H.updatehealth() + else + src.take_organ_damage(d) + user.visible_message("[user] attacks [src]'s stomach wall with the [I.name]!") + playsound(user.loc, 'sound/effects/attackblob.ogg', 50, 1) + + if(prob(src.getBruteLoss() - 50)) + for(var/atom/movable/A in stomach_contents) + A.loc = loc + stomach_contents.Remove(A) + src.gib() + +/mob/living/carbon/gib() + for(var/mob/M in src) + if(M in src.stomach_contents) + src.stomach_contents.Remove(M) + M.loc = src.loc + for(var/mob/N in viewers(src, null)) + if(N.client) + N.show_message(text("[M] bursts out of [src]!"), 2) + ..() + +/mob/living/carbon/attack_hand(mob/M as mob) + if(!istype(M, /mob/living/carbon)) return + if (ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/temp = H.organs_by_name[BP_R_HAND] + if (H.hand) + temp = H.organs_by_name[BP_L_HAND] + if(temp && !temp.is_usable()) + to_chat(H, "You can't use your [temp.name]") + return + + return + +/mob/living/carbon/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, var/def_zone = null) + if(status_flags & GODMODE) return 0 //godmode + + shock_damage = apply_shock(shock_damage, def_zone, siemens_coeff) + + if(!shock_damage) + return 0 + + stun_effect_act(agony_amount=shock_damage, def_zone=def_zone) + + playsound(loc, "sparks", 50, 1, -1) + if (shock_damage > 15) + src.visible_message( + "[src] was electrocuted[source ? " by the [source]" : ""]!", \ + "You feel a powerful shock course through your body!", \ + "You hear a heavy electrical crack." \ + ) + else + src.visible_message( + "[src] was shocked[source ? " by the [source]" : ""].", \ + "You feel a shock course through your body.", \ + "You hear a zapping sound." \ + ) + + switch(shock_damage) + if(16 to 20) + Stun(2) + if(21 to 25) + Weaken(2) + if(26 to 25) + Weaken(5) + if(31 to INFINITY) + Weaken(10) //This should work for now, more is really silly and makes you lay there forever + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, loc) + s.start() + + return shock_damage + +/mob/living/carbon/proc/apply_shock(var/shock_damage, var/def_zone, var/siemens_coeff = 1.0) + shock_damage *= siemens_coeff + if(shock_damage < 0.5) + return 0 + if(shock_damage < 1) + shock_damage = 1 + apply_damage(shock_damage, BURN, def_zone, used_weapon="Electrocution") + return(shock_damage) + +/mob/proc/swap_hand() + return + +/mob/living/carbon/swap_hand() + src.hand = !( src.hand ) + if(hud_used.l_hand_hud_object && hud_used.r_hand_hud_object) + if(hand) //This being 1 means the left hand is in use + hud_used.l_hand_hud_object.icon_state = "l_hand_active" + hud_used.r_hand_hud_object.icon_state = "r_hand_inactive" + else + hud_used.l_hand_hud_object.icon_state = "l_hand_inactive" + hud_used.r_hand_hud_object.icon_state = "r_hand_active" + if(hud_used.swaphands_hud_object) + if(hand) //This being 1 means the left hand is in use + hud_used.swaphands_hud_object.dir = 2 + else + hud_used.swaphands_hud_object.dir = 1 + + return + +/mob/living/carbon/human/swap_hand() + ..() + update_aim_icon() + +/mob/proc/update_aim_icon() + if(!client) + return + + if(istype(get_active_hand(),/obj/item/weapon/gun)) + if(dispersion_mouse_display_number > 0 && dispersion_mouse_display_number < 2)// else + client.mouse_pointer_icon = 'icons/effects/standard/standard2.dmi'//'icons/misc/aim.dmi' + else if(dispersion_mouse_display_number >= 2 && dispersion_mouse_display_number < 4) + client.mouse_pointer_icon = 'icons/effects/standard/standard3.dmi' + else if(dispersion_mouse_display_number >= 4 && dispersion_mouse_display_number < 6) + client.mouse_pointer_icon = 'icons/effects/standard/standard4.dmi' + else if(dispersion_mouse_display_number >= 6 && dispersion_mouse_display_number < 10) + client.mouse_pointer_icon = 'icons/effects/standard/standard5.dmi' + else if(dispersion_mouse_display_number >= 10) + client.mouse_pointer_icon = 'icons/effects/standard/standard6.dmi' + else + client.mouse_pointer_icon = 'icons/effects/standard/standard1.dmi' + if(dispersion_mouse_display_number > 20) + dispersion_mouse_display_number = 20 + recoil = 20 + if(dispersion_mouse_display_number <= 0) + dispersion_mouse_display_number = 0 + recoil = 0 + dispersion_mouse_display_number -= 10 + + else + if(client) + client.mouse_pointer_icon = null + + +/mob/living/carbon/proc/activate_hand(var/selhand) //0 or "r" or "right" for right hand; 1 or "l" or "left" for left hand. + + if(istext(selhand)) + selhand = lowertext(selhand) + + if(selhand == "right" || selhand == "r") + selhand = 0 + if(selhand == "left" || selhand == "l") + selhand = 1 + +/mob/living/carbon/proc/help_shake_act(mob/living/carbon/M) + if(!is_asystole()) + if (on_fire) + playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + if (M.on_fire) + M.visible_message("[M] tries to pat out [src]'s flames, but to no avail!", + "You try to pat out [src]'s flames, but to no avail! Put yourself out first!") + else + M.visible_message("[M] tries to pat out [src]'s flames!", + "You try to pat out [src]'s flames! Hot!") + if(do_mob(M, src, 15)) + src.fire_stacks -= 1 //Less effective than stop, drop, and roll - also accounting for the fact that it takes half as long. + if (src.fire_stacks <= 0) + M.visible_message("[M] successfully pats out [src]'s flames.", + "You successfully pat out [src]'s flames.") + src.ExtinguishMob() + src.fire_stacks = 0 + else + var/t_him = "it" + if (src.gender == MALE) + t_him = "him" + else if (src.gender == FEMALE) + t_him = "her" + if (istype(src,/mob/living/carbon/human) && src:w_uniform) + var/mob/living/carbon/human/H = src + H.w_uniform.add_fingerprint(M) + + var/show_ssd + var/mob/living/carbon/human/H = src + if(istype(H)) show_ssd = H.species.show_ssd + if(show_ssd && !client && !teleop) + M.visible_message("[M] shakes [src] trying to wake [t_him] up!", \ + "You shake [src], but they do not respond... Maybe they have S.S.D?") + else if(lying || src.sleeping) + src.sleeping = max(0,src.sleeping-5) + if(src.sleeping == 0) + src.resting = 0 + M.visible_message("[M] shakes [src] trying to wake [t_him] up!", \ + "You shake [src] trying to wake [t_him] up!") + else + var/mob/living/carbon/human/hugger = M + if(istype(hugger)) + hugger.species.hug(hugger,src) + else + M.visible_message("[M] hugs [src] to make [t_him] feel better!", \ + "You hug [src] to make [t_him] feel better!") + if(M.fire_stacks >= (src.fire_stacks + 3)) + src.fire_stacks += 1 + M.fire_stacks -= 1 + if(M.on_fire) + src.IgniteMob() + + if(stat != DEAD) + AdjustParalysis(-3) + AdjustStunned(-3) + AdjustWeakened(-3) + + playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + +/mob/living/carbon/proc/eyecheck() + return 0 + +/mob/living/carbon/flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash) + if(eyecheck() < intensity || override_blindness_check) + return ..() + +// ++++ROCKDTBEN++++ MOB PROCS -- Ask me before touching. +// Stop! ... Hammertime! ~Carn + +/mob/living/carbon/proc/getDNA() + return dna + +/mob/living/carbon/proc/setDNA(var/datum/dna/newDNA) + dna = newDNA + +// ++++ROCKDTBEN++++ MOB PROCS //END + +/mob/living/carbon/clean_blood() + . = ..() + if(ishuman(src)) + var/mob/living/carbon/human/H = src + if(H.gloves) + if(H.gloves.clean_blood()) + H.update_inv_gloves(0) + H.gloves.germ_level = 0 + else + if(!isnull(H.bloody_hands)) + H.bloody_hands = null + H.update_inv_gloves(0) + H.germ_level = 0 + update_icons() //apply the now updated overlays to the mob + +//Throwing stuff +/mob/proc/throw_item(atom/target) + return + +/mob/living/carbon/throw_item(atom/target) + src.throw_mode_off() + if(usr.stat || !target) + return + if(target.type == /obj/screen) return + + var/atom/movable/item = src.get_active_hand() + + var/itemsize = ITEM_SIZE_HUGE//If it's not an item we're throwing it's probably a person and they're fucking huge. + + if(!item) return + + if(istype(item,/obj/item) && !istype(item, /obj/item/grab))//If it's an item and not a grab, set the itemsize to the item's w_class + var/obj/item/I = item + itemsize = I.w_class + + var/throw_range = item.throw_range + var/throw_delay = strToSpeedModifier(STAT_LEVEL(str), itemsize) + throw_delay /= (10/get_dist(src, target)) + src.visible_message("[src] is trying to throw [item].") + if(do_after(src, throw_delay)) + if (istype(item, /obj/item/grab)) + var/obj/item/grab/G = item + item = G.throw_held() //throw the person instead of the grab + if(ismob(item)) + var/mob/M = item + + //limit throw range by relative mob size + throw_range = round(M.throw_range * min(src.mob_size/M.mob_size, 1)) + itemsize = round(M.mob_size/4) + var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors + var/turf/end_T = get_turf(target) + if(start_T && end_T) + var/start_T_descriptor = "[start_T] \[[start_T.x],[start_T.y],[start_T.z]\] ([start_T.loc])" + var/end_T_descriptor = "[start_T] \[[end_T.x],[end_T.y],[end_T.z]\] ([end_T.loc])" + admin_attack_log(usr, M, "Threw the victim from [start_T_descriptor] to [end_T_descriptor].", "Was from [start_T_descriptor] to [end_T_descriptor].", "threw, from [start_T_descriptor] to [end_T_descriptor], ") + if(ishuman(usr))//People are heavy. Throwing them is exhausting. + var/mob/living/carbon/human/H = usr + H.adjustStaminaLoss(rand(10,35)) + + //else if (istype(item, /obj/item/)) + // var/obj/item/I = item + // itemsize = I.w_class + + src.drop_from_inventory(item) + if(!item || !isturf(item.loc)) + return + + //actually throw it! + src.visible_message("[src] has thrown [item].", range = min(itemsize*2,world.view)) + playsound(src, 'sound/effects/throw.ogg', 50, 1) + + if(!src.lastarea) + src.lastarea = get_area(src.loc) + if((istype(src.loc, /turf/space)) || (src.lastarea.has_gravity == 0)) + src.inertia_dir = get_dir(target, src) + step(src, inertia_dir) + item.throw_at(target, throw_range, item.throw_speed, src) + +/mob/living/carbon/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + ..() + var/temp_inc = max(min(BODYTEMP_HEATING_MAX*(1-get_heat_protection()), exposed_temperature - bodytemperature), 0) + bodytemperature += temp_inc + +/mob/living/carbon/can_use_hands() + if(handcuffed) + return 0 + if(buckled && ! istype(buckled, /obj/structure/bed/chair)) // buckling does not restrict hands + return 0 + return 1 + +/mob/living/carbon/restrained() + if (handcuffed) + return 1 + return + +/mob/living/carbon/u_equip(obj/item/W as obj) + if(!W) return 0 + + else if (W == handcuffed) + handcuffed = null + update_inv_handcuffed() + if(buckled && buckled.buckle_require_restraints) + buckled.unbuckle_mob() + else + ..() + + return + +/mob/living/carbon/verb/mob_sleep() + set name = "Sleep" + set category = "IC" + + if(usr.sleeping) + to_chat(usr, "You are already sleeping") + return + if(alert(src,"You sure you want to sleep for a while?","Sleep","Yes","No") == "Yes") + usr.sleeping = 20 //Short nap + +/mob/living/carbon/Bump(var/atom/movable/AM, yes) + if(now_pushing || !yes) + return + ..() + if(istype(AM, /mob/living/carbon) && prob(10)) + src.spread_disease_to(AM, "Contact") + +/mob/living/carbon/slip(var/slipped_on,stun_duration=8) + if(buckled) + return 0 + stop_pulling() + to_chat(src, "You slipped on [slipped_on]!") + playsound(src.loc, 'sound/misc/slip.ogg', 50, 1, -3) + Weaken(Floor(stun_duration/2)) + return 1 + +/mob/living/carbon/proc/add_chemical_effect(var/effect, var/magnitude = 1) + if(is_hellbanned()) + if(effect == CE_PAINKILLER) + magnitude += min(magnitude, 1)//You only get 1 painkiller effect fucker. + + if(effect in chem_effects) + chem_effects[effect] += magnitude + else + chem_effects[effect] = magnitude + +/mob/living/carbon/proc/add_up_to_chemical_effect(var/effect, var/magnitude = 1) + if(effect in chem_effects) + chem_effects[effect] = max(magnitude, chem_effects[effect]) + else + chem_effects[effect] = magnitude + +/mob/living/carbon/get_default_language() + if(default_language && can_speak(default_language)) + return default_language + + if(!species) + return null + return species.default_language ? all_languages[species.default_language] : null + +/mob/living/carbon/show_inv(mob/user as mob) + user.set_machine(src) + var/dat = {" +
            [name]
            +

            +
            Head(Mask): [(wear_mask ? wear_mask : "Nothing")] +
            Left Hand: [(l_hand ? l_hand : "Nothing")] +
            Right Hand: [(r_hand ? r_hand : "Nothing")] +
            Back: [(back ? back : "Nothing")] [((istype(wear_mask, /obj/item/clothing/mask) && istype(back, /obj/item/weapon/tank) && !( internal )) ? text(" Set Internal", src) : "")] +
            [(internal ? text("Remove Internal") : "")] +
            Empty Pockets +
            Refresh +
            Close +
            "} + user << browse(dat, text("window=mob[];size=325x500", name)) + onclose(user, "mob[name]") + return + +/** + * Return FALSE if victim can't be devoured, DEVOUR_FAST if they can be devoured quickly, DEVOUR_SLOW for slow devour + */ +/mob/living/carbon/proc/can_devour(atom/movable/victim) + if((FAT in mutations) && issmall(victim)) + return DEVOUR_FAST + + return FALSE + +/mob/living/carbon/onDropInto(var/atom/movable/AM) + for(var/e in stomach_contents) + var/atom/movable/stomach_content = e + if(stomach_content.contains(AM)) + if(can_devour(AM)) + stomach_contents += AM + return null + src.visible_message("\The [src] regurgitates \the [AM]!") + return loc + return ..() +/mob/living/carbon/proc/should_have_organ(var/organ_check) + return 0 + +/mob/living/carbon/proc/can_feel_pain(var/check_organ) + if(isSynthetic()) + return 0 + return !(species && species.species_flags & SPECIES_FLAG_NO_PAIN) + +/mob/living/carbon/proc/get_adjusted_metabolism(metabolism) + return metabolism + +/mob/living/carbon/proc/need_breathe() + return +/mob/living/carbon/getTrail() + if(getBruteLoss() < 200) + return "ltrails" + else + return "trails" +/mob/living/carbon/check_has_mouth() + // carbon mobs have mouths by default + // behavior of this proc for humans is overridden in human.dm + return 1 + +/mob/living/carbon/proc/check_mouth_coverage() + // carbon mobs do not have blocked mouths by default + // overridden in human_defense.dm + return null + +/mob/living/carbon/proc/SetStasis(var/factor, var/source = "misc") + if((species && (species.species_flags & SPECIES_FLAG_NO_SCAN)) || isSynthetic()) + return + stasis_sources[source] = factor + +/mob/living/carbon/proc/InStasis() + if(!stasis_value) + return FALSE + return life_tick % stasis_value + +// call only once per run of life +/mob/living/carbon/proc/UpdateStasis() + stasis_value = 0 + if((species && (species.species_flags & SPECIES_FLAG_NO_SCAN)) || isSynthetic()) + return + for(var/source in stasis_sources) + stasis_value += stasis_sources[source] + stasis_sources.Cut() + +/mob/living/carbon/proc/has_fake_brain() + var/obj/item/organ/internal/brain/brain = internal_organs_by_name[BP_BRAIN] + if(istype(brain) && brain.fake_brain) + return 1 + return 0 diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm new file mode 100644 index 00000000..61508b77 --- /dev/null +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -0,0 +1,32 @@ + +/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 >= 100) + return 0 + + //Hulk modifier + if(HULK in user.mutations) + effective_force *= 2 + + //Apply weapon damage + var/damage_flags = I.damage_flags() + if(prob(blocked)) //armour provides a chance to turn sharp/edge weapon attacks into blunt ones + damage_flags &= ~(DAM_SHARP|DAM_EDGE) + apply_damage(effective_force, I.damtype, hit_zone, blocked, damage_flags, used_weapon=I) + //var/datum/wound/created_wound = + + //Melee weapon embedded object code. + //if(istype(created_wound) && I && I.damtype == BRUTE && !I.anchored && !is_robot_module(I)) + //var/weapon_sharp = (damage_flags & DAM_SHARP) + // var/damage = effective_force //just the effective damage used for sorting out embedding, no further damage is applied here + // if (blocked) + // damage *= blocked_mult(blocked) + + //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. //NOT ANYMORE THEY WON'T! + //if((weapon_sharp && damage > (10*I.w_class)) || (damage > embed_threshold && prob(embed_chance))) + // src.embed(I, hit_zone, supplied_wound = created_wound) + + return 1 diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm new file mode 100644 index 00000000..1a14b4e1 --- /dev/null +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -0,0 +1,49 @@ +/mob/living/carbon/ + gender = MALE + var/datum/species/species //Contains icon generation and language information, set during New(). + var/list/stomach_contents = list() + var/list/datum/disease2/disease/virus2 = list() + var/list/antibodies = list() + var/datum/happiness_event/list/events = list() + + + var/life_tick = 0 // The amount of life ticks that have processed on this mob. + var/obj/item/handcuffed = null //Whether or not the mob is handcuffed + //Surgery info + var/datum/surgery_status/op_stage = new/datum/surgery_status + //Active emote/pose + var/pose = null + var/list/chem_effects = list() + var/list/chem_doses = list() + var/datum/reagents/metabolism/bloodstr = null + var/datum/reagents/metabolism/ingested = null + var/datum/reagents/metabolism/touching = null + var/datum/squad/squad = null //For warfare shit. + var/losebreath = 0 //if we failed to breathe last tick + + var/coughedtime = null + + var/cpr_time = 1.0 + var/lastpuke = 0 + var/nutrition = 400 + + var/obj/item/weapon/tank/internal = null//Human/Monkey + + + //these two help govern taste. The first is the last time a taste message was shown to the plaer. + //the second is the message in question. + var/last_taste_time = 0 + var/last_taste_text = "" + + //For sad, thirsty, and dirty lads. + var/happiness = 0 + var/thirst = THIRST_LEVEL_FILLED + // organ-related variables, see organ.dm and human_organs.dm + var/list/internal_organs = list() + var/list/organs = list() + var/list/organs_by_name = list() // map organ names to organs + var/list/internal_organs_by_name = list() // so internal organs have less ickiness too + + var/list/stasis_sources = list() + var/stasis_value + var/social_class = null diff --git a/code/modules/mob/living/carbon/carbon_needs.dm b/code/modules/mob/living/carbon/carbon_needs.dm new file mode 100644 index 00000000..6d76db29 --- /dev/null +++ b/code/modules/mob/living/carbon/carbon_needs.dm @@ -0,0 +1,172 @@ +/mob/living/carbon/proc/print_happiness() + var/msg = "
            " + if(real_name) + msg += "My name is [real_name].\n" + if(age) + msg += "I am [age] years old.\n" + if(squad) + msg += "I'm in [squad.name] squad!\n" + if(social_class) + msg += "I am [get_social_class()].\n" + if(trait) + msg += "I am [trait.name]. [trait.description]\n" + if(quirk)//NOT THE SAME THING AS TRAITS + msg += "Oh lucky, I am also [quirk.name]. [quirk.description]\n" + msg += "Current feelings:\n" + for(var/i in events) + var/datum/happiness_event/event = events[i] + msg += event.description + + if(!events.len) + msg += "I feel indifferent.\n" + + if(happiness < MOOD_LEVEL_SAD2) + msg += "I am stressed out!\n" + + + msg += "
            " + to_chat(src, msg) + +/mob/living/carbon/proc/update_happiness() + var/old_happiness = happiness + var/old_icon = null + if(happiness_icon) + old_icon = happiness_icon.icon_state + happiness = 0 + for(var/i in events) + var/modified_mood + var/datum/happiness_event/event = events[i] + if(has_quirk(/datum/quirk/hypersensitive)) + modified_mood = (event.happiness*2) //Double the happiness. + else + modified_mood = event.happiness //Otherwise leave it the same. + + happiness += modified_mood + + if(has_quirk(/datum/quirk/dead_inside))//Set this to be the same. + happiness = MOOD_LEVEL_HAPPY1 + + if(has_quirk(/datum/quirk/brave)) + happiness = MOOD_LEVEL_HAPPY1 //Still get moodies, they just don't affect you. + + switch(happiness) + if(-5000000 to MOOD_LEVEL_SAD4) + if(happiness_icon) + happiness_icon.icon_state = "mood7" + + if(MOOD_LEVEL_SAD4 to MOOD_LEVEL_SAD3) + if(happiness_icon) + happiness_icon.icon_state = "mood6" + + if(MOOD_LEVEL_SAD3 to MOOD_LEVEL_SAD2) + if(happiness_icon) + happiness_icon.icon_state = "mood5" + + if(MOOD_LEVEL_SAD2 to MOOD_LEVEL_SAD1) + if(happiness_icon) + happiness_icon.icon_state = "mood5" + + if(MOOD_LEVEL_SAD1 to MOOD_LEVEL_HAPPY1) + if(happiness_icon) + happiness_icon.icon_state = "mood4" + + if(MOOD_LEVEL_HAPPY1 to MOOD_LEVEL_HAPPY2) + if(happiness_icon) + happiness_icon.icon_state = "mood4" + + if(MOOD_LEVEL_HAPPY2 to MOOD_LEVEL_HAPPY3) + if(happiness_icon) + happiness_icon.icon_state = "mood3" + + if(MOOD_LEVEL_HAPPY3 to MOOD_LEVEL_HAPPY4) + if(happiness_icon) + happiness_icon.icon_state = "mood2" + + if(MOOD_LEVEL_HAPPY4 to INFINITY) + if(happiness_icon) + happiness_icon.icon_state = "mood1" + + if(old_icon && old_icon != happiness_icon.icon_state) + if(old_happiness > happiness) + to_chat(src, "I have become more stressed.") + else + to_chat(src, "I have become less stressed.") + +/mob/proc/flash_sadness() + if(prob(2)) + flick("sadness",pain) + var/spoopysound = pick('sound/effects/badmood1.ogg','sound/effects/badmood2.ogg','sound/effects/badmood3.ogg','sound/effects/badmood4.ogg') + sound_to(src, spoopysound) + var/msg = pick("None of this is real.", "This isn't actually happening.", "You need to wake up.", "I don't want to die anymore.", "GOTTA GET A GRIP!") + to_chat(src, "[msg]") + +/mob/living/carbon/proc/handle_happiness() + if(happiness > MOOD_LEVEL_SAD4) + if(horror_loop) + to_chat(src, "My nerves relax some... I can think clearly again...") + sound_to(src, sound(null, repeat = 1, wait = 0, volume = 50, channel = 6)) + horror_loop = FALSE + clear_fullscreen("freakout", /obj/screen/fullscreen/freakout) + + + switch(happiness) + if(MOOD_LEVEL_SAD4 to MOOD_LEVEL_SAD3) + flash_sadness() + if(-INFINITY to MOOD_LEVEL_SAD4) + do_stress_effects() + flash_sadness() + +/mob/living/carbon/proc/do_stress_effects() + return + +/mob/living/carbon/human/do_stress_effects() + if(!horror_loop) + freakout_emote() + sound_to(src, sound('sound/effects/losing_my_mind.ogg', repeat = 1, wait = 0, volume = 25, channel = 6)) + horror_loop = TRUE + overlay_fullscreen("freakout", /obj/screen/fullscreen/freakout) + to_chat(src, "I AM FREAKING THE FUCK OUT!") + stuttering = 5 + shake_camera(src, 5, 0.1) + +/mob/living/carbon/proc/add_event(category, type) //Category will override any events in the same category, should be unique unless the event is based on the same thing like hunger. + if(has_quirk(/datum/quirk/dead_inside))//They're dead inside, they feel nothing. + return + var/datum/happiness_event/the_event + if(events[category]) + the_event = events[category] + if(the_event.type != type) + clear_event(category) + return .() + else + return 0 //Don't have to update the event. + else + the_event = new type() + + events[category] = the_event + update_happiness() + + if(the_event.timeout) + spawn(the_event.timeout) + clear_event(category) + +/mob/living/carbon/proc/clear_event(category) + var/datum/happiness_event/event = events[category] + if(!event) + return 0 + + events -= category + qdel(event) + update_happiness() + +/mob/living/carbon/proc/adjust_thirst(var/amount) + var/old_thirst = thirst + if(amount>0) + thirst = min(thirst+amount, THIRST_LEVEL_MAX) + + else if(old_thirst) + thirst = max(thirst+amount, 0) + +/mob/living/carbon/proc/set_thirst(var/amount) + if(amount >= 0) + thirst = min(THIRST_LEVEL_MAX, amount) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon_powers.dm b/code/modules/mob/living/carbon/carbon_powers.dm new file mode 100644 index 00000000..14036e33 --- /dev/null +++ b/code/modules/mob/living/carbon/carbon_powers.dm @@ -0,0 +1,91 @@ +//Brain slug proc for voluntary removal of control. +/mob/living/carbon/proc/release_control() + + set category = "Abilities" + set name = "Release Control" + set desc = "Release control of your host's body." + + var/mob/living/simple_animal/borer/B = has_brain_worms() + + if(B && B.host_brain) + to_chat(src, "You withdraw your probosci, releasing control of [B.host_brain]") + + B.detatch() + + verbs -= /mob/living/carbon/proc/release_control + verbs -= /mob/living/carbon/proc/punish_host + verbs -= /mob/living/carbon/proc/spawn_larvae + + else + to_chat(src, "ERROR NO BORER OR BRAINMOB DETECTED IN THIS MOB, THIS IS A BUG !") + +//Brain slug proc for tormenting the host. +/mob/living/carbon/proc/punish_host() + set category = "Abilities" + set name = "Torment host" + set desc = "Punish your host with agony." + + var/mob/living/simple_animal/borer/B = has_brain_worms() + + if(!B) + return + + if(B.host_brain.ckey) + to_chat(src, "You send a punishing spike of psychic agony lancing into your host's brain.") + if (!can_feel_pain()) + to_chat(B.host_brain, "You feel a strange sensation as a foreign influence prods your mind.") + to_chat(src, "It doesn't seem to be as effective as you hoped.") + else + to_chat(B.host_brain, "Horrific, burning agony lances through you, ripping a soundless scream from your trapped mind!") + +/mob/living/carbon/proc/spawn_larvae() + set category = "Abilities" + set name = "Reproduce" + set desc = "Spawn several young." + + var/mob/living/simple_animal/borer/B = has_brain_worms() + + if(!B) + return + + if(B.chemicals >= 100) + to_chat(src, "Your host twitches and quivers as you rapidly excrete a larva from your sluglike body.") + visible_message("\The [src] heaves violently, expelling a rush of vomit and a wriggling, sluglike creature!") + B.chemicals -= 100 + B.has_reproduced = 1 + + new /obj/effect/decal/cleanable/vomit(get_turf(src)) + playsound(loc, 'sound/effects/splat.ogg', 50, 1) + new /mob/living/simple_animal/borer(get_turf(src), B.generation + 1) + + else + to_chat(src, "You do not have enough chemicals stored to reproduce.") + return + +/** + * Attempt to devour victim + * + * Returns TRUE on success, FALSE on failure + */ +/mob/living/carbon/proc/devour(atom/movable/victim) + var/can_eat = can_devour(victim) + if(!can_eat) + return FALSE + var/eat_speed = 100 + if(can_eat == DEVOUR_FAST) + eat_speed = 30 + src.visible_message("\The [src] is attempting to devour \the [victim]!") + var/mob/target = victim + if(isobj(victim)) + target = src + if(!do_mob(src,target,eat_speed)) + return FALSE + src.visible_message("\The [src] devours \the [victim]!") + if(ismob(victim)) + admin_attack_log(src, victim, "Devoured.", "Was devoured by.", "devoured") + else + src.drop_from_inventory(victim) + victim.forceMove(src) + src.stomach_contents.Add(victim) + + return TRUE diff --git a/code/modules/mob/living/carbon/give.dm b/code/modules/mob/living/carbon/give.dm new file mode 100644 index 00000000..aa3cf654 --- /dev/null +++ b/code/modules/mob/living/carbon/give.dm @@ -0,0 +1,24 @@ +/mob/living/carbon/human/proc/give(var/mob/living/target) + if(incapacitated()) + return + if(!istype(target) || target.incapacitated() || target.client == null) + return + + var/obj/item/I = usr.get_active_hand() + if(!I) + return + + if(istype(I, /obj/item/grab)) + to_chat(usr, "You can't give someone a grab.") + return + + if(I.loc != usr || (usr.l_hand != I && usr.r_hand != I)) + return + + if(target.r_hand != null && target.l_hand != null) + to_chat(usr, "Their hands are full.") + return + + if(usr.unEquip(I)) + target.put_in_hands(I) // If this fails it will just end up on the floor, but that's fitting for things like dionaea. + target.visible_message("\The [usr] handed \the [I] to \the [target].") diff --git a/code/modules/mob/living/carbon/hallucinations.dm b/code/modules/mob/living/carbon/hallucinations.dm new file mode 100644 index 00000000..3d445acd --- /dev/null +++ b/code/modules/mob/living/carbon/hallucinations.dm @@ -0,0 +1,304 @@ +/mob/living/carbon/var/hallucination_power = 0 +/mob/living/carbon/var/hallucination_duration = 0 +/mob/living/carbon/var/next_hallucination +/mob/living/carbon/var/list/hallucinations = list() + +/mob/living/carbon/proc/hallucination(duration, power) + hallucination_duration = max(hallucination_duration, duration) + hallucination_power = max(hallucination_power, power) + +/mob/living/carbon/proc/adjust_hallucination(duration, power) + hallucination_duration = max(0, hallucination_duration + duration) + hallucination_power = max(0, hallucination_power + power) + +/mob/living/carbon/proc/handle_hallucinations() + //Tick down the duration + hallucination_duration = max(0, hallucination_duration - 1) + if(chem_effects[CE_MIND] > 0) + hallucination_duration = max(0, hallucination_duration - 1) + + //Adjust power if we have some chems that affect it + if(chem_effects[CE_MIND] < 0) + hallucination_power = min(hallucination_power++, 50) + if(chem_effects[CE_MIND] < -1) + hallucination_power = hallucination_power++ + if(chem_effects[CE_MIND] > 0) + hallucination_power = max(hallucination_power - chem_effects[CE_MIND], 0) + + //See if hallucination is gone + if(!hallucination_power) + hallucination_duration = 0 + return + if(!hallucination_duration) + hallucination_power = 0 + return + + if(!client || stat || world.time < next_hallucination) + return + if(chem_effects[CE_MIND] > 0 && prob(chem_effects[CE_MIND]*40)) //antipsychotics help + return + var/hall_delay = rand(10,20) SECONDS + + if(hallucination_power < 50) + hall_delay *= 2 + next_hallucination = world.time + hall_delay + var/list/candidates = list() + for(var/T in subtypesof(/datum/hallucination/)) + var/datum/hallucination/H = new T + if(H.can_affect(src)) + candidates += H + if(candidates.len) + var/datum/hallucination/H = pick(candidates) + H.holder = src + H.activate() + +////////////////////////////////////////////////////////////////////////////////////////////////////// +//Hallucination effects datums +////////////////////////////////////////////////////////////////////////////////////////////////////// + +/datum/hallucination + var/mob/living/carbon/holder + var/allow_duplicates = 1 + var/duration = 0 + var/min_power = 0 //at what levels of hallucination power mobs should get it + var/max_power = INFINITY + +/datum/hallucination/proc/start() + +/datum/hallucination/proc/end() + +/datum/hallucination/proc/can_affect(var/mob/living/carbon/C) + if(!C.client) + return 0 + if(min_power > C.hallucination_power) + return 0 + if(max_power < C.hallucination_power) + return 0 + if(!allow_duplicates && (locate(type) in C.hallucinations)) + return 0 + return 1 + +/datum/hallucination/Destroy() + . = ..() + holder = null + +/datum/hallucination/proc/activate() + if(!holder || !holder.client) + return + holder.hallucinations += src + start() + spawn(duration) + if(holder) + end() + holder.hallucinations -= src + qdel(src) + + +//Playing a random sound +/datum/hallucination/sound + var/list/sounds = list('sound/machines/airlock.ogg','sound/effects/explosionfar.ogg','sound/machines/windowdoor.ogg','sound/machines/twobeep.ogg') + +/datum/hallucination/sound/start() + var/turf/T = locate(holder.x + rand(6,11), holder.y + rand(6,11), holder.z) + holder.playsound_local(T,pick(sounds),70) + +/datum/hallucination/sound/tools + sounds = list('sound/items/Ratchet.ogg','sound/items/Welder.ogg','sound/items/Crowbar.ogg','sound/items/Screwdriver.ogg') + +/datum/hallucination/sound/danger + min_power = 30 + sounds = list('sound/effects/explosion1.ogg','sound/effects/explosion2.ogg','sound/effects/Glassbr1.ogg','sound/effects/Glassbr2.ogg','sound/effects/Glassbr3.ogg','sound/weapons/smash.ogg') + +/datum/hallucination/sound/spooky + min_power = 50 + sounds = list('sound/effects/ghost.ogg', 'sound/effects/ghost2.ogg', 'sound/effects/Heart Beat.ogg', 'sound/effects/screech.ogg',\ + 'sound/hallucinations/behind_you1.ogg', 'sound/hallucinations/behind_you2.ogg', 'sound/hallucinations/far_noise.ogg', 'sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg',\ + 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg', 'sound/hallucinations/i_see_you1.ogg', 'sound/hallucinations/i_see_you2.ogg',\ + 'sound/hallucinations/look_up1.ogg', 'sound/hallucinations/look_up2.ogg', 'sound/hallucinations/over_here1.ogg', 'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg',\ + 'sound/hallucinations/turn_around1.ogg', 'sound/hallucinations/turn_around2.ogg', 'sound/hallucinations/veryfar_noise.ogg', 'sound/hallucinations/wail.ogg') + +//Hearing someone being shot twice +/datum/hallucination/gunfire + var/gunshot + var/turf/origin + duration = 15 + min_power = 30 + +/datum/hallucination/gunfire/start() + gunshot = pick('sound/weapons/gunshot/gunshot_strong.ogg', 'sound/weapons/gunshot/gunshot2.ogg', 'sound/weapons/gunshot/shotgun.ogg', 'sound/weapons/gunshot/gunshot.ogg','sound/weapons/Taser.ogg') + origin = locate(holder.x + rand(4,8), holder.y + rand(4,8), holder.z) + holder.playsound_local(origin,gunshot,50) + +/datum/hallucination/gunfire/end() + holder.playsound_local(origin,gunshot,50) + +//Hearing someone talking to/about you. +/datum/hallucination/talking/can_affect(var/mob/living/carbon/C) + if(!..()) + return 0 + for(var/mob/living/M in oview(C)) + return TRUE + +/datum/hallucination/talking/start() + var/sanity = 5 //even insanity needs some sanity + for(var/mob/living/talker in oview(holder)) + if(talker.stat) + continue + var/message + if(prob(80)) + var/list/names = list() + var/lastname = copytext(holder.real_name, findtext(holder.real_name, " ")+1) + var/firstname = copytext(holder.real_name, 1, findtext(holder.real_name, " ")) + if(lastname) names += lastname + if(firstname) names += firstname + if(!names.len) + names += holder.real_name + var/add = prob(20) ? ", [pick(names)]" : "" + var/list/phrases = list("[prob(50) ? "Hey, " : ""][pick(names)]!","[prob(50) ? "Hey, " : ""][pick(names)]?","Get out[add]!","Go away[add].","What are you doing[add]?","Where's your ID[add]?") + if(holder.hallucination_power > 50) + phrases += list("What did you come here for[add]?","Don't touch me[add].","You're not getting out of here[add].", "You are a failure, [pick(names)].","Just kill yourself already, [pick(names)].","Put on some clothes[add].","Take off your clothes[add].") + message = pick(phrases) + to_chat(holder,"[talker.name] [holder.say_quote(message)], \"[message]\"") + else + to_chat(holder,"[talker.name] points at [holder.name]") + to_chat(holder,"[talker.name] says something softly.") + var/image/speech_bubble = image('icons/mob/talk.dmi',talker,"h[holder.say_test(message)]") + spawn(30) qdel(speech_bubble) + show_image(holder,speech_bubble) + sanity-- //don't spam them in very populated rooms. + if(!sanity) + return + +//Spiderling skitters +/datum/hallucination/skitter/start() + to_chat(holder,"The spiderling skitters[pick(" away"," around","")].") + +//Spiders in your body +/datum/hallucination/spiderbabies + min_power = 40 + +/datum/hallucination/spiderbabies/start() + if(istype(holder,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = holder + var/obj/O = pick(H.organs) + to_chat(H,"You feel something [pick("moving","squirming","skittering")] inside of your [O.name]!") + +//Seeing stuff +/datum/hallucination/mirage + duration = 30 SECONDS + max_power = 30 + var/number = 1 + var/list/things = list() //list of images to display + +/datum/hallucination/mirage/Destroy() + end() + . = ..() + +/datum/hallucination/mirage/proc/generate_mirage() + var/icon/T = new('icons/obj/trash.dmi') + return image(T, pick(T.IconStates()), layer = BELOW_TABLE_LAYER) + +/datum/hallucination/mirage/start() + var/list/possible_points = list() + for(var/turf/simulated/floor/F in view(holder, world.view+1)) + possible_points += F + if(possible_points.len) + for(var/i = 1 to number) + var/image/thing = generate_mirage() + things += thing + thing.loc = pick(possible_points) + holder.client.images += things + +/datum/hallucination/mirage/end() + if(holder.client) + holder.client.images -= things + +//LOADSEMONEY +/datum/hallucination/mirage/money + min_power = 20 + max_power = 45 + number = 2 + +/datum/hallucination/mirage/money/generate_mirage() + return image('icons/obj/items.dmi', "spacecash[pick(1000,500,200,100,50)]", layer = BELOW_TABLE_LAYER) + +//Blood and aftermath of firefight +/datum/hallucination/mirage/carnage + min_power = 50 + number = 10 + +/datum/hallucination/mirage/carnage/generate_mirage() + if(prob(50)) + var/image/I = image('icons/effects/blood.dmi', pick("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7"), layer = BELOW_TABLE_LAYER) + I.color = COLOR_BLOOD_HUMAN + return I + else + var/image/I = image('icons/obj/ammo.dmi', "s-casing-spent", layer = BELOW_TABLE_LAYER) + I.layer = BELOW_TABLE_LAYER + I.dir = pick(GLOB.alldirs) + I.pixel_x = rand(-10,10) + I.pixel_y = rand(-10,10) + return I + +//Fake telepathy +/datum/hallucination/telepahy + allow_duplicates = 0 + duration = 20 MINUTES + +/datum/hallucination/telepahy/start() + to_chat(holder,"You expand your mind outwards.") + holder.verbs += /mob/living/carbon/human/proc/fakeremotesay + +/datum/hallucination/telepahy/end() + if(holder) + holder.verbs -= /mob/living/carbon/human/proc/fakeremotesay + +/mob/living/carbon/human/proc/fakeremotesay() + set name = "Telepathic Message" + set category = "Superpower" + + if(!hallucination_power) + src.verbs -= /mob/living/carbon/human/proc/fakeremotesay + return + + if(stat) + to_chat(usr, "You're not in any state to use your powers right now!'") + return + + if(chem_effects[CE_MIND] > 0) + to_chat(usr, "Chemicals in your blood prevent you from using your power!'") + + var/list/creatures = list() + for(var/mob/living/carbon/C in SSmobs.mob_list) + creatures += C + creatures -= usr + var/mob/target = input("Who do you want to project your mind to ?") as null|anything in creatures + if (isnull(target)) + return + + var/msg = sanitize(input(usr, "What do you wish to transmit")) + show_message("You project your mind into [target.name]: \"[msg]\"") + if(!stat && prob(20)) + say(msg) + +//Fake attack +/datum/hallucination/fakeattack + min_power = 30 + +/datum/hallucination/fakeattack/can_affect(var/mob/living/carbon/C) + if(!..()) + return 0 + for(var/mob/living/M in oview(C,1)) + return TRUE + +/datum/hallucination/fakeattack/start() + for(var/mob/living/M in oview(holder,1)) + to_chat(holder, "[M] has punched [holder]!") + holder.playsound_local(get_turf(holder),"punch",50) + +//Fake injection +/datum/hallucination/fakeattack/hypo + min_power = 30 + +/datum/hallucination/fakeattack/hypo/start() + to_chat(holder, "You feel a tiny prick!") \ No newline at end of file diff --git a/code/modules/mob/living/carbon/happiness_events.dm b/code/modules/mob/living/carbon/happiness_events.dm new file mode 100644 index 00000000..a9f403ee --- /dev/null +++ b/code/modules/mob/living/carbon/happiness_events.dm @@ -0,0 +1,196 @@ +/datum/happiness_event + var/description + var/happiness = 0 + var/timeout = 1 MINUTE + +///For descriptions, use the span classes bold info, info, none, warning and boldwarning in order from great to horrible. + +//thirst +/datum/happiness_event/thirst/filled + description = "I've had enough to drink for a while!\n" + happiness = 4 + +/datum/happiness_event/thirst/watered + description = "I have recently had something to drink.\n" + happiness = 2 + +/datum/happiness_event/thirst/thirsty + description = "I'm getting a bit thirsty.\n" + happiness = -7 + +/datum/happiness_event/thirst/dehydrated + description = "I need water!\n" + happiness = -14 + + + +//nutrition +/datum/happiness_event/nutrition/fat + description = "I'm so fat..\n" //muh fatshaming + happiness = -4 + +/datum/happiness_event/nutrition/wellfed + description = "My belly feels round and full.\n" + happiness = 4 + +/datum/happiness_event/nutrition/fed + description = "I have recently had some food.\n" + happiness = 2 + +/datum/happiness_event/nutrition/hungry + description = "I'm getting a bit hungry.\n" + happiness = -6 + +/datum/happiness_event/nutrition/starving + description = "I'm starving!\n" + happiness = -12 + + +//Hygiene +/datum/happiness_event/hygiene/clean + description = "I feel so clean!\n" + happiness = 2 + +/datum/happiness_event/hygiene/smelly + description = "I smell like shit.\n" + happiness = -5 + +/datum/happiness_event/hygiene/vomitted + description = "Ugh, I've vomitted.\n" + happiness = -5 + timeout = 1800 + + + +//Disgust +/datum/happiness_event/disgust/gross + description = "That was gross.\n" + happiness = -2 + timeout = 1800 + +/datum/happiness_event/disgust/verygross + description = "I think I'm going to puke...\n" + happiness = -4 + timeout = 1800 + +/datum/happiness_event/disgust/disgusted + description = "Oh god that's disgusting...\n" + happiness = -6 + timeout = 1800 + + + +//Generic events +/datum/happiness_event/favorite_food + description = "I really liked eating that.\n" + happiness = 3 + timeout = 2400 + +/datum/happiness_event/nice_shower + description = "I had a nice shower.\n" + happiness = 1 + timeout = 1800 + +/datum/happiness_event/handcuffed + description = "I guess my antics finally caught up with me..\n" + happiness = -1 + +/datum/happiness_event/booze + description = "Alcohol makes the pain go away.\n" + happiness = 10 + timeout = 2400 + +/datum/happiness_event/relaxed//For nicotine. + description = "That cigarette was good.\n" + happiness = 10 + timeout = 1800 + +/datum/happiness_event/antsy//Withdrawl. + description = "I could use a smoke.\n" + happiness = -3 + timeout = 1800 + +/datum/happiness_event/hot_food //Hot food feels good! + description = "I've eaten something warm.\n" + happiness = 3 + timeout = 1800 + +/datum/happiness_event/cold_drink //Cold drinks feel good! + description = "I've had something refreshing.\n" + happiness = 3 + timeout = 1800 + +/datum/happiness_event/high + description = "I'm high as fuck\n" + happiness = 12 + +/datum/happiness_event/angered_god + description = "I have angered my God!\n" + happiness = -12 + +/datum/happiness_event/pleased_god + description = "I have pleased my God!\n" + happiness = 12 + +/datum/happiness_event/unpraised_god + description = "I do not praise my god! And that upsets them!\n" + happiness = -10 + timeout = FALSE //Praise your god or forever be unhappy! + + +/datum/happiness_event/dark//For being in the dark. + description = "The darkness makes me uneasy.\n" + happiness = -5 + timeout = FALSE//no timeouts here. + + +//Embarassment +/datum/happiness_event/hygiene/shit + description = "I shit myself. How embarassing.\n" + happiness = -10 + timeout = 1800 + +/datum/happiness_event/hygiene/pee + description = "I pissed myself. How embarassing.\n" + happiness = -5 + timeout = 1800 + + +//For when you get branded. +/datum/happiness_event/humiliated + description = "I've been humiliated.\n" + happiness = -10 + timeout = 1800 + +//And when you've seen someone branded +/datum/happiness_event/punished_heretic + description = "I've seen a punished heretic.\n" + happiness = 10 + timeout = 1800 + +/datum/happiness_event/pain + description = "IT HURTS SO MUCH!\n" + happiness = -10 + timeout = 1800 + +//For when you see someone die and you're not hardcore. +/datum/happiness_event/dead + description = "OH MY GOD THEY'RE DEAD!\n" + happiness = -10 + timeout = 5 MINUTES + +//For when you see a family member die. +/datum/happiness_event/family_death + description = "I SAW A FAMILY MEMBER DIE!\n" + happiness = -12 + timeout = 5 MINUTES + +/datum/happiness_event/captain_death + description = "My captain is dead!\n" + happiness = -12 + timeout = 2 MINUTES + +/datum/happiness_event/morale_boost + description = "OORAH! TODAY WE FIGHT LIKE MEN!\n" + happiness = 12 + timeout = 1800 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/MedicalSideEffects.dm b/code/modules/mob/living/carbon/human/MedicalSideEffects.dm new file mode 100644 index 00000000..03e6e871 --- /dev/null +++ b/code/modules/mob/living/carbon/human/MedicalSideEffects.dm @@ -0,0 +1,151 @@ +// MEDICAL SIDE EFFECT BASE +// ======================== +/datum/medical_effect + var/name = "None" + var/strength = 0 + var/start = 0 + var/list/triggers + var/list/cures + var/cure_message + +/datum/medical_effect/proc/manifest(mob/living/carbon/human/H) + for(var/R in cures) + if(H.reagents.has_reagent(R)) + return 0 + for(var/R in triggers) + if(H.reagents.get_reagent_amount(R) >= triggers[R]) + return 1 + return 0 + +/datum/medical_effect/proc/on_life(mob/living/carbon/human/H, strength) + return + +/datum/medical_effect/proc/cure(mob/living/carbon/human/H) + for(var/R in cures) + if(H.reagents.has_reagent(R)) + if (cure_message) + to_chat(H, "[cure_message]") + return 1 + return 0 + + +// MOB HELPERS +// =========== +/mob/living/carbon/human/var/list/datum/medical_effect/side_effects = list() +/mob/proc/add_side_effect(name, strength = 0) +/mob/living/carbon/human/add_side_effect(name, strength = 0) + for(var/datum/medical_effect/M in src.side_effects) + if(M.name == name) + M.strength = max(M.strength, 10) + M.start = life_tick + return + + + var/T = side_effects[name] + if (!T) + return + + var/datum/medical_effect/M = new T + if(M.name == name) + M.strength = strength + M.start = life_tick + side_effects += M + +/mob/living/carbon/human/proc/handle_medical_side_effects() + //Going to handle those things only every few ticks. + if(life_tick % 15 != 0) + return 0 + + var/list/L = typesof(/datum/medical_effect)-/datum/medical_effect + for(var/T in L) + var/datum/medical_effect/M = new T + if (M.manifest(src)) + src.add_side_effect(M.name) + + // One full cycle(in terms of strength) every 10 minutes + for (var/datum/medical_effect/M in side_effects) + if (!M) continue + var/strength_percent = sin((life_tick - M.start) / 2) + + // Only do anything if the effect is currently strong enough + if(strength_percent >= 0.4) + if (M.cure(src) || M.strength > 50) + side_effects -= M + M = null + else + if(life_tick % 45 == 0) + M.on_life(src, strength_percent*M.strength) + // Effect slowly growing stronger + M.strength+=0.08 + +// HEADACHE +// ======== +/datum/medical_effect/headache + name = "Headache" + triggers = list(/datum/reagent/cryoxadone = 10, /datum/reagent/bicaridine = 15, /datum/reagent/tricordrazine = 15) + cures = list(/datum/reagent/alkysine, /datum/reagent/tramadol, /datum/reagent/paracetamol, /datum/reagent/tramadol/oxycodone) + cure_message = "Your head stops throbbing..." + +/datum/medical_effect/headache/on_life(mob/living/carbon/human/H, strength) + var/obj/item/organ/external/head/head = H.get_organ("head") + if(istype(head)) + switch(strength) + if(1 to 10) + H.custom_pain("You feel a light pain in your head.",0, affecting = head) + if(11 to 30) + H.custom_pain("You feel a throbbing pain in your head!",1, affecting = head) + if(31 to INFINITY) + H.custom_pain("You feel an excrutiating pain in your head!",1, affecting = head) + +// BAD STOMACH +// =========== +/datum/medical_effect/bad_stomach + name = "Bad Stomach" + triggers = list(/datum/reagent/kelotane = 30, /datum/reagent/dermaline = 15) + cures = list(/datum/reagent/dylovene) + cure_message = "Your stomach feels a little better now..." + +/datum/medical_effect/bad_stomach/on_life(mob/living/carbon/human/H, strength) + switch(strength) + if(1 to 10) + H.custom_pain("You feel a bit light around the stomach.",0) + if(11 to 30) + H.custom_pain("Your stomach hurts.",0) + if(31 to INFINITY) + H.custom_pain("You feel sick.",1) + +// CRAMPS +// ====== +/datum/medical_effect/cramps + name = "Cramps" + triggers = list(/datum/reagent/dylovene = 30, /datum/reagent/tramadol = 15) + cures = list(/datum/reagent/inaprovaline) + cure_message = "The cramps let up..." + +/datum/medical_effect/cramps/on_life(mob/living/carbon/human/H, strength) + switch(strength) + if(1 to 10) + H.custom_pain("The muscles in your body hurt a little.",0) + if(11 to 30) + H.custom_pain("The muscles in your body cramp up painfully.",0) + if(31 to INFINITY) + H.visible_message("\The [src] flinches as all the muscles in their body cramp up.") + H.custom_pain("There's pain all over your body.",1) + +// ITCH +// ==== +/datum/medical_effect/itch + name = "Itch" + triggers = list(/datum/reagent/space_drugs = 10) + cures = list(/datum/reagent/inaprovaline) + cure_message = "The itching stops..." + +/datum/medical_effect/itch/on_life(mob/living/carbon/human/H, strength) + switch(strength) + if(1 to 10) + H.custom_pain("You feel a slight itch.",0) + if(11 to 30) + H.custom_pain("You want to scratch your itch badly.",0) + if(31 to INFINITY) + H.visible_message("\The [src] shivers slightly.") + H.custom_pain("This itch makes it really hard to concentrate.",1) diff --git a/code/modules/mob/living/carbon/human/appearance.dm b/code/modules/mob/living/carbon/human/appearance.dm new file mode 100644 index 00000000..113cf757 --- /dev/null +++ b/code/modules/mob/living/carbon/human/appearance.dm @@ -0,0 +1,177 @@ +/mob/living/carbon/human/proc/change_appearance(var/flags = APPEARANCE_ALL_HAIR, var/location = src, var/mob/user = src, var/check_species_whitelist = 1, var/list/species_whitelist = list(), var/list/species_blacklist = list(), var/datum/topic_state/state = GLOB.default_state) + var/datum/nano_module/appearance_changer/AC = new(location, src, check_species_whitelist, species_whitelist, species_blacklist) + AC.flags = flags + AC.ui_interact(user, state = state) + +/mob/living/carbon/human/proc/change_species(var/new_species) + if(!new_species) + return + + if(species == new_species) + return + + if(!(new_species in all_species)) + return + + set_species(new_species) + reset_hair() + return 1 + +/mob/living/carbon/human/proc/change_gender(var/gender) + if(src.gender == gender) + return + + src.gender = gender + reset_hair() + update_body() + update_dna() + return 1 + +/mob/living/carbon/human/proc/change_hair(var/hair_style) + if(!hair_style) + return + + if(h_style == hair_style) + return + + if(!(hair_style in GLOB.hair_styles_list)) + return + + h_style = hair_style + + update_hair() + return 1 + +/mob/living/carbon/human/proc/change_facial_hair(var/facial_hair_style) + if(!facial_hair_style) + return + + if(f_style == facial_hair_style) + return + + if(!(facial_hair_style in GLOB.facial_hair_styles_list)) + return + + f_style = facial_hair_style + + update_hair() + return 1 + +/mob/living/carbon/human/proc/reset_hair() + var/list/valid_hairstyles = generate_valid_hairstyles() + var/list/valid_facial_hairstyles = generate_valid_facial_hairstyles() + + if(valid_hairstyles.len) + h_style = pick(valid_hairstyles) + else + //this shouldn't happen + h_style = "Bald" + + if(valid_facial_hairstyles.len) + f_style = pick(valid_facial_hairstyles) + else + //this shouldn't happen + f_style = "Shaved" + + update_hair() + +/mob/living/carbon/human/proc/change_eye_color(var/red, var/green, var/blue) + if(red == r_eyes && green == g_eyes && blue == b_eyes) + return + + r_eyes = red + g_eyes = green + b_eyes = blue + + update_eyes() + update_body() + return 1 + +/mob/living/carbon/human/proc/change_hair_color(var/red, var/green, var/blue) + if(red == r_eyes && green == g_eyes && blue == b_eyes) + return + + r_hair = red + g_hair = green + b_hair = blue + + force_update_limbs() + update_body() + update_hair() + return 1 + +/mob/living/carbon/human/proc/change_facial_hair_color(var/red, var/green, var/blue) + if(red == r_facial && green == g_facial && blue == b_facial) + return + + r_facial = red + g_facial = green + b_facial = blue + + update_hair() + return 1 + +/mob/living/carbon/human/proc/change_skin_color(var/red, var/green, var/blue) + if(red == r_skin && green == g_skin && blue == b_skin || !(species.appearance_flags & HAS_SKIN_COLOR)) + return + + r_skin = red + g_skin = green + b_skin = blue + + force_update_limbs() + update_body() + return 1 + +/mob/living/carbon/human/proc/change_skin_tone(var/tone) + if(s_tone == tone || !(species.appearance_flags & HAS_A_SKIN_TONE)) + return + + s_tone = tone + + force_update_limbs() + update_body() + return 1 + +/mob/living/carbon/human/proc/update_dna() + check_dna() + dna.ready_dna(src) + +/mob/living/carbon/human/proc/generate_valid_species(var/check_whitelist = 1, var/list/whitelist = list(), var/list/blacklist = list()) + var/list/valid_species = new() + for(var/current_species_name in all_species) + var/datum/species/current_species = all_species[current_species_name] + + if(check_whitelist) //If we're using the whitelist, make sure to check it! + if((current_species.spawn_flags & SPECIES_IS_RESTRICTED) && !check_rights(R_ADMIN, 0, src)) + continue + if(!is_alien_whitelisted(src, current_species)) + continue + if(whitelist.len && !(current_species_name in whitelist)) + continue + if(blacklist.len && (current_species_name in blacklist)) + continue + + valid_species += current_species_name + + return valid_species + +/mob/living/carbon/human/proc/generate_valid_hairstyles(var/check_gender = 1) + . = list() + var/list/hair_styles = species.get_hair_styles() + for(var/hair_style in hair_styles) + var/datum/sprite_accessory/S = hair_styles[hair_style] + if(check_gender) + if(gender == MALE && S.gender == FEMALE) + continue + if(gender == FEMALE && S.gender == MALE) + continue + .[hair_style] = S + +/mob/living/carbon/human/proc/generate_valid_facial_hairstyles() + return species.get_facial_hair_styles(gender) + +/mob/living/carbon/human/proc/force_update_limbs() + for(var/obj/item/organ/external/O in organs) + O.sync_colour_to_human(src) + update_body(0) diff --git a/code/modules/mob/living/carbon/human/audible_emotes.dm b/code/modules/mob/living/carbon/human/audible_emotes.dm new file mode 100644 index 00000000..b78410f4 --- /dev/null +++ b/code/modules/mob/living/carbon/human/audible_emotes.dm @@ -0,0 +1,137 @@ +/mob/proc/agony_scream(var/fire = FALSE) + if(stat) + return + if(emote_cd == 1) // Check if we need to suppress the emote attempt. + return + var/screamsound = null + var/muzzled = istype(wear_mask, /obj/item/clothing/mask/muzzle) + var/message = null + + if(ishuman(src)) + var/mob/living/carbon/human/H = src + if(!muzzled) + if(H.isMonkey()) + screamsound = "sound/voice/monkey_pain[rand(1,3)].ogg" + + else if(H.isChild()) + screamsound = "sound/voice/child_pain[rand(1,2)].ogg" + + else if(src.gender == MALE) + if(fire) + screamsound = "sound/voice/agony_male[rand(1, 10)].ogg" + else + screamsound = "sound/voice/man_pain[rand(1,3)].ogg" + + else + screamsound = "sound/voice/woman_agony[rand(1,3)].ogg" + message = "screams in agony!" + + else + message = "makes a loud noise!" + screamsound = "sound/voice/gagscream[rand(1,3)].wav" + + if(screamsound) + playsound(src, screamsound, 50, 0, 1) + + if(message) + custom_emote(2,message) + shake_camera(src, 20, 3)//suffer well pupper + handle_emote_CD() + +/mob/proc/gasp_sound(var/collapsed_lung = FALSE, var/drowning = FALSE) + var/gaspsound = null + var/muzzled = istype(wear_mask, /obj/item/clothing/mask/muzzle) + if(stat) + return + if(emote_cd == 1) // Check if we need to suppress the emote attempt. + return + + if(muzzled) + custom_emote(2,"[src.name] makes a muffled gasping noise.") + return + + if(gender == MALE) + if(drowning) + gaspsound = "sound/voice/emotes/gurp_male[rand(1,2)].ogg" + else + gaspsound = "sound/voice/gasp_male[rand(1,7)].ogg" + + if(gender == FEMALE) + if(drowning) + gaspsound = "sound/voice/emotes/gurp_female[rand(1,2)].ogg" + else + gaspsound = "sound/voice/gasp_female[rand(1,7)].ogg" + + if(collapsed_lung) + gaspsound = "sound/voice/gasp[rand(1,3)].ogg" + + if(gaspsound) + playsound(src, gaspsound, 25, 0, 1) + handle_emote_CD() + + +/mob/proc/agony_moan() + if(stat) + return + if(emote_cd == 1) // Check if we need to suppress the emote attempt. + return + var/moansound = null + var/message = null + + var/muzzled = istype(src.wear_mask, /obj/item/clothing/mask/muzzle) + if(ishuman(src)) + var/mob/living/carbon/human/H = src + if(!muzzled) + if(H.isMonkey()) + return + + if(H.isChild()) + moansound = 'sound/voice/child_moan1.ogg' + + else if(src.gender == MALE) + moansound = "sound/voice/male_moan[rand(1,3)].ogg" + + else + moansound = "sound/voice/female_moan[rand(1,3)].ogg" + + message = "moans." + else + message = "makes a loud noise!" + moansound = "sound/voice/gagscream[rand(1,3)].wav" + + if(moansound) + playsound(src, moansound, 50, 0, 1) + + if(message) + custom_emote(2,message) + handle_emote_CD() + + +/mob/proc/freakout_emote() + if(stat) + return + if(emote_cd == 1) // Check if we need to suppress the emote attempt. + return + var/screamsound = null + var/message = null + + var/muzzled = istype(src.wear_mask, /obj/item/clothing/mask/muzzle) + if(ishuman(src)) + var/mob/living/carbon/human/H = src + if(!muzzled) + if(H.isMonkey()) + return + + message = "loses their fucking mind!" + else + message = "makes a loud noise!" + + screamsound = "sound/voice/gagscream[rand(1,3)].wav" + + + if(screamsound) + playsound(src, screamsound, 50, 0, 1) + + if(message) + custom_emote(2,message) + handle_emote_CD() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm new file mode 100644 index 00000000..4a6d38c6 --- /dev/null +++ b/code/modules/mob/living/carbon/human/death.dm @@ -0,0 +1,123 @@ +/mob/living/carbon/human/gib() + for(var/obj/item/organ/I in internal_organs) + I.removed(src) + if(istype(loc,/turf)) + I.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),30) + + for(var/obj/item/organ/external/E in src.organs) + E.droplimb(0,DROPLIMB_EDGE,1) + + sleep(1) + + for(var/obj/item/I in src) + drop_from_inventory(I) + I.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)), rand(1,3), round(30/I.w_class)) + + ..(species.gibbed_anim) + gibs(loc, dna, null, species.get_flesh_colour(src), species.get_blood_colour(src)) + +/mob/living/carbon/human/dust() + if(species) + ..(species.dusted_anim, species.remains_type) + else + ..() + +/mob/living/carbon/human/death(gibbed,deathmessage="seizes up and falls limp...", show_dead_message = "You have died.") + + if(is_npc) + walk_to(src, 0) + + if(stat == DEAD) return + + BITSET(hud_updateflag, HEALTH_HUD) + BITSET(hud_updateflag, STATUS_HUD) + BITSET(hud_updateflag, LIFE_HUD) + + //backs up lace if available. + var/obj/item/organ/internal/stack/s = get_organ(BP_STACK) + if(s) + s.do_backup() + + //Handle species-specific deaths. + species.handle_death(src) + + + + //Handle brain slugs. + var/obj/item/organ/external/head = get_organ(BP_HEAD) + var/mob/living/simple_animal/borer/B + + for(var/I in head.implants) + if(istype(I,/mob/living/simple_animal/borer)) + B = I + if(B) + if(!B.ckey && ckey && B.controlling) + B.ckey = ckey + B.controlling = 0 + if(B.host_brain.ckey) + ckey = B.host_brain.ckey + B.host_brain.ckey = null + B.host_brain.SetName("host brain") + B.host_brain.real_name = "host brain" + + verbs -= /mob/living/carbon/proc/release_control + + callHook("death", list(src, gibbed)) + + if(ticker && ticker.mode) + sql_report_death(src) + ticker.mode.check_win() + + . = ..(gibbed,"no message") + if(!gibbed) + handle_organs() + if(species.death_sound) + playsound(loc, species.death_sound, 80, 1, 1) + spawn(50) + if(bowels >= 30) + handle_shit() + if(bladder >= 30) + handle_piss() + unlock_achievement(new/datum/achievement/dead()) + sound_to(src, sound(null, repeat = 1, wait = 0, volume = 70, channel = 4)) + sound_to(src, sound(null, repeat = 1, wait = 0, volume = 70, channel = 3)) + sound_to(src, sound(null, repeat = 1, wait = 0, volume = 50, channel = 6)) + remove_coldbreath() + handle_warfare_death() + GLOB.total_deaths++ + handle_hud_list() + +/mob/living/carbon/human/proc/ChangeToHusk() + if(HUSK in mutations) return + + if(f_style) + f_style = "Shaved" //we only change the icon_state of the hair datum, so it doesn't mess up their UI/UE + if(h_style) + h_style = "Bald" + update_hair(0) + + mutations.Add(HUSK) + for(var/obj/item/organ/external/E in organs) + E.disfigured = 1 + update_body(1) + return + +/mob/living/carbon/human/proc/Drain() + ChangeToHusk() + mutations |= HUSK + return + +/mob/living/carbon/human/proc/ChangeToSkeleton() + if(SKELETON in src.mutations) return + + if(f_style) + f_style = "Shaved" + if(h_style) + h_style = "Bald" + update_hair(0) + + mutations.Add(SKELETON) + for(var/obj/item/organ/external/E in organs) + E.disfigured = 1 + update_body(1) + return diff --git a/code/modules/mob/living/carbon/human/emotions.dm b/code/modules/mob/living/carbon/human/emotions.dm new file mode 100644 index 00000000..8df1d7de --- /dev/null +++ b/code/modules/mob/living/carbon/human/emotions.dm @@ -0,0 +1,203 @@ +/mob/living/carbon/human/verb/blink_t() + set name = "Blink" + set category = "Emotes" + + emote("blink",1) + +/mob/living/carbon/human/verb/bow() + set name = "Bow" + set category = "Emotes" + + emote("bow",1) + +/mob/living/carbon/human/verb/salute() + set name = "Salute" + set category = "Emotes" + + emote("salute",1) + +/mob/living/carbon/human/verb/poo() + set name = "Poo" + set category = "Emotes" + + emote("poo",1) + +/mob/living/carbon/human/verb/pee() + set name = "Pee" + set category = "Emotes" + + emote("pee",1) + +/mob/living/carbon/human/verb/hem() + set name = "Hem" + set category = "Emotes" + + emote("hem", 1) + +/mob/living/carbon/human/verb/clap() + set name = "Clap" + set category = "Emotes" + + emote("clap",1) + +/mob/living/carbon/human/verb/eyebrow() + set name = "Eyebrow" + set category = "Emotes" + + emote("eyebrow",1) +/* +/mob/living/carbon/human/verb/chuckle() + set name = "Chuckle" + set category = "Emotes" + + emote("chuckle",1) +*/ +/mob/living/carbon/human/verb/cough() + set name = "Cough" + set category = "Emotes" + + emote("cough",1) + +/mob/living/carbon/human/verb/frown() + set name = "Frown" + set category = "Emotes" + + emote("frown",1) + +/mob/living/carbon/human/verb/nod() + set name = "Nod" + set category = "Emotes" + + emote("nod",1) + +/mob/living/carbon/human/verb/blush() + set name = "Blush" + set category = "Emotes" + + emote("blush",1) + +/mob/living/carbon/human/verb/wave() + set name = "Wave" + set category = "Emotes" + + emote("wave",1) + +/mob/living/carbon/human/verb/giggle() + set name = "Giggle" + set category = "Emotes" + + emote("giggle",1) + +/mob/living/carbon/human/verb/look() + set name = "Look" + set category = "Emotes" + + emote("look",1) + +/mob/living/carbon/human/verb/grin() + set name = "Grin" + set category = "Emotes" + + emote("grin",1) + +/mob/living/carbon/human/verb/cry() + set name = "Cry" + set category = "Emotes" + + emote("cry",1) + +/mob/living/carbon/human/verb/sigh() + set name = "Sigh" + set category = "Emotes" + + emote("sigh",1) + +/mob/living/carbon/human/verb/laugh() + set name = "Laugh" + set category = "Emotes" + + emote("laugh",1) + +/mob/living/carbon/human/verb/mumble() + set name = "Mumble" + set category = "Emotes" + + emote("mumble",1) + +/mob/living/carbon/human/verb/grumble() + set name = "Grumble" + set category = "Emotes" + + emote("grumble",1) + +/mob/living/carbon/human/verb/groan() + set name = "Groan" + set category = "Emotes" + + emote("groan",1) + +/mob/living/carbon/human/verb/mmoan() + set name = "Moan" + set category = "Emotes" + + emote("moan",1) + +/mob/living/carbon/human/verb/raise() + set name = "Raise Hand" + set category = "Emotes" + + emote("raise",1) + +/mob/living/carbon/human/verb/shake() + set name = "Shake" + set category = "Emotes" + + emote("shake",1) + +/mob/living/carbon/human/verb/shrug() + set name = "Shrug" + set category = "Emotes" + + emote("shrug",1) + +/mob/living/carbon/human/verb/smile() + set name = "Smile" + set category = "Emotes" + + emote("smile",1) + +/mob/living/carbon/human/verb/whimper() + set name = "Whimper" + set category = "Emotes" + + emote("whimper",1) + +/mob/living/carbon/human/verb/wink() + set name = "Wink" + set category = "Emotes" + + emote("wink",1) + +/mob/living/carbon/human/verb/yawn() + set name = "Yawn" + set category = "Emotes" + + emote("yawn",1) + +/mob/living/carbon/human/verb/hug() + set name = "Hug" + set category = "Emotes" + + emote("hug",1) + +/mob/living/carbon/human/verb/scream() + set name = "Scream" + set category = "Emotes" + + emote("scream",1) + +/mob/living/carbon/human/verb/emoteclearthroat() + set name = "Clear Throat" + set category = "Emotes" + + emote("clearthroat",1) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm new file mode 100644 index 00000000..de56f624 --- /dev/null +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -0,0 +1,481 @@ +/mob/living/carbon/human/examine(mob/user) + if(!isobserver(user)) + user.visible_message("[user.name] looks at [src].") + + if(get_dist(user,src) > 7)//Don't get descriptions of things far away. + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.warfare_faction != src.warfare_faction) + to_chat(user, "THEY ARE THE ENEMY! KILL THEM!") + + if(crouching) + to_chat(user, "They are crouching!") + to_chat(user, "It's too far away to see clearly.") + return + + if(is_anonymous)//Ghosts can bypass this. + to_chat(user, "You can't make out anything about them.") + return + + var/skipgloves = 0 + var/skipsuitstorage = 0 + var/skipjumpsuit = 0 + var/skipshoes = 0 + var/skipmask = 0 + var/skipears = 0 + var/skipeyes = 0 + var/skipface = 0 + + //exosuits and helmets obscure our view and stuff. + if(wear_suit) + skipgloves = wear_suit.flags_inv & HIDEGLOVES + skipsuitstorage = wear_suit.flags_inv & HIDESUITSTORAGE + skipjumpsuit = wear_suit.flags_inv & HIDEJUMPSUIT + skipshoes = wear_suit.flags_inv & HIDESHOES + + if(head) + skipmask = head.flags_inv & HIDEMASK + skipeyes = head.flags_inv & HIDEEYES + skipears = head.flags_inv & HIDEEARS + skipface = head.flags_inv & HIDEFACE + + if(wear_mask) + skipface |= wear_mask.flags_inv & HIDEFACE + + //no accuately spotting headsets from across the room. + if(get_dist(user, src) > 3) + skipears = 1 + + var/list/msg = list("
            This is ") + + var/datum/gender/T = gender_datums[get_gender()] + if(skipjumpsuit && skipface) //big suits/masks/helmets make it hard to tell their gender + T = gender_datums[PLURAL] + else + if(icon) + msg += "\icon[icon] " //fucking BYOND: this should stop dreamseeker crashing if we -somehow- examine somebody before their icon is generated + + if(!T) + // Just in case someone VVs the gender to something strange. It'll runtime anyway when it hits usages, better to CRASH() now with a helpful message. + CRASH("Gender datum was null; key was '[(skipjumpsuit && skipface) ? PLURAL : gender]'") + + msg += "[src.name]" + + var/is_synth = isSynthetic() + + msg += "
            " + + if(isChild()) + msg += "[T.He] is but a child!\n" + + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.warfare_faction != src.warfare_faction) + msg += "THEY ARE THE ENEMY! KILL THEM!\n" + + if(H != src) + if(H.warfare_faction == src.warfare_faction) + if(istype(H.squad, src.squad)) + msg += "[T.He] is in my squad!\n" + + + + if((!skipface || wear_id) && src != user) + if(ishuman(user))//Social class descriptions. They go at the top they're very important. + if(social_class) + msg += "[T.He] [T.is] [get_social_class()]. [get_social_description(H)]\n" + + + + //uniform + if(w_uniform && !skipjumpsuit) + msg += "[T.He] [T.is] wearing [w_uniform.get_examine_line()].\n" + + //head + if(head) + msg += "[T.He] [T.is] wearing [head.get_examine_line()] on [T.his] head.\n" + + if(tie_slot) + msg += "[T.He] [T.is] wearing [tie_slot.get_examine_line()] around [T.his] neck.\n" + + //suit/armour + if(wear_suit) + msg += "[T.He] [T.is] wearing [wear_suit.get_examine_line()].\n" + //suit/armour storage + if(s_store && !skipsuitstorage) + msg += "[T.He] [T.is] carrying [s_store.get_examine_line()] on [T.his] [wear_suit.name].\n" + + //back + if(back) + msg += "[T.He] [T.has] [back.get_examine_line()] on [T.his] back.\n" + + //left hand + if(l_hand && !(l_hand.item_flags & ITEM_FLAG_ABSTRACT)) + msg += "[T.He] [T.is] holding [l_hand.get_examine_line()] in [T.his] [l_hand.wielded ? "hands" : "left hand"].\n" + + //right hand + if(r_hand && !(r_hand.item_flags & ITEM_FLAG_ABSTRACT)) + msg += "[T.He] [T.is] holding [r_hand.get_examine_line()] in [T.his] [r_hand.wielded ? "hands" : "right hand"].\n" + + //gloves + if(gloves && !skipgloves) + msg += "[T.He] [T.has] [gloves.get_examine_line()] on [T.his] hands.\n" + else if(blood_DNA) + msg += "[T.He] [T.has] [(hand_blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained hands!\n" + + //belt + if(belt) + msg += "[T.He] [T.has] [belt.get_examine_line()] about [T.his] waist.\n" + + //shoes + if(shoes && !skipshoes) + msg += "[T.He] [T.is] wearing [shoes.get_examine_line()] on [T.his] feet.\n" + else if(feet_blood_DNA) + msg += "[T.He] [T.has] [(feet_blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained feet!\n" + + //mask + if(wear_mask && !skipmask) + msg += "[T.He] [T.has] [wear_mask.get_examine_line()] on [T.his] face.\n" + + //eyes + if(glasses && !skipeyes) + msg += "[T.He] [T.has] [glasses.get_examine_line()] covering [T.his] eyes.\n" + + //left ear + if(l_ear && !skipears) + msg += "[T.He] [T.has] [l_ear.get_examine_line()] on [T.his] left ear.\n" + + //right ear + if(r_ear && !skipears) + msg += "[T.He] [T.has] [r_ear.get_examine_line()] on [T.his] right ear.\n" + + //ID + if(wear_id) + msg += "[T.He] [T.is] wearing [wear_id.get_examine_line()].\n" + + + if(crouching) + msg += "[T.He] [T.is] crouching!\n" + + //handcuffed? + if(handcuffed) + if(istype(handcuffed, /obj/item/weapon/handcuffs/cable)) + msg += "[T.He] [T.is] \icon[handcuffed] restrained with cable!\n" + else + msg += "[T.He] [T.is] \icon[handcuffed] handcuffed!\n" + + //buckled + if(buckled) + msg += "[T.He] [T.is] \icon[buckled] buckled to [buckled]!\n" + if(STAT_LEVEL(str) > user.STAT_LEVEL(str) && STAT_LEVEL(str) < (user.STAT_LEVEL(str) + 5)) + msg += "[T.He] looks stronger than you.\n" + + if(STAT_LEVEL(str) > (user.STAT_LEVEL(str) + 5)) + msg += "[T.He] looks a lot stronger than you.\n" + + if(STAT_LEVEL(str) < user.STAT_LEVEL(str)) + msg += "[T.He] looks weaker than you.\n" + + //Jitters + if(is_jittery) + if(jitteriness >= 300) + msg += "[T.He] [T.is] convulsing violently!\n" + else if(jitteriness >= 200) + msg += "[T.He] [T.is] extremely jittery.\n" + else if(jitteriness >= 100) + msg += "[T.He] [T.is] twitching ever so slightly.\n" + + //Disfigured face + if(!skipface) //Disfigurement only matters for the head currently. + var/obj/item/organ/external/head/E = get_organ(BP_HEAD) + if(E && E.disfigured) //Check to see if we even have a head and if the head's disfigured. + if(E.species) //Check to make sure we have a species + msg += E.species.disfigure_msg(src) + else //Just in case they lack a species for whatever reason. + msg += "[T.His] face is horribly mangled!\n" + if(banished) + msg += " [T.He] is banished from our land! How shameful!\n" + + if(branded)//For brands. + msg += "\"[branded]\" IS BRANDED ON THEIR FACE!\n" + + //splints + for(var/organ in list(BP_L_LEG, BP_R_LEG, BP_L_ARM, BP_R_ARM)) + var/obj/item/organ/external/o = get_organ(organ) + if(o && o.splinted && o.splinted.loc == o) + msg += "[T.He] [T.has] \a [o.splinted] on [T.his] [o.name]!\n" + + if(mSmallsize in mutations) + msg += "[T.He] [T.is] small halfling!\n" + + var/distance = 0 + if(isghost(user) || user.stat == DEAD) // ghosts can see anything + distance = 1 + else + distance = get_dist(user,src) + if (src.stat) + msg += "[T.He] [T.is]n't responding to anything around [T.him] and seems to be unconscious.\n" + if((stat == DEAD || is_asystole() || src.losebreath) && distance <= 3) + msg += "[T.He] [T.does] not appear to be breathing.\n" + if(ishuman(user) && !user.incapacitated() && Adjacent(user)) + spawn(0) + user.visible_message("\The [user] checks \the [src]'s pulse.", "You check \the [src]'s pulse.") + if(do_after(user, 15, src)) + if(pulse() == PULSE_NONE) + to_chat(user, "[T.He] [T.has] no pulse.") + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(!H.has_trait(/datum/trait/hardcore) && !H.has_trait(/datum/trait/death_tolerant)) + H.add_event("dead", /datum/happiness_event/dead) + else + to_chat(user, "[T.He] [T.has] a pulse!") + + if(fire_stacks) + msg += "[T.He] looks flammable.\n" + + if(on_fire) + msg += "[T.He] [T.is] on fire!.\n" + + msg += "" + + + if(nutrition < 100) + msg += "[T.He] [T.is] severely malnourished.\n" + else if(nutrition >= 500) + msg += "[T.He] [T.is] quite chubby.\n" + + + msg += "" + + var/ssd_msg = species.get_ssd(src) + if(ssd_msg && (!should_have_organ(BP_BRAIN) || has_brain()) && stat != DEAD) + if(!key) + msg += "[T.He] [T.is] [ssd_msg]. It doesn't look like [T.he] [T.is] waking up anytime soon.\n" + else if(!client) + msg += "[T.He] [T.is] [ssd_msg].\n" + + var/mhealth = (getBruteLoss() + getFireLoss())//How injured they look. Not not nescessarily how hurt they actually are. + + if(mhealth >= 25 && mhealth < 50)//Is the person a little hurt? + msg += "[T.He] looks somewhat injured.\n" + + if(mhealth >= 50 && mhealth < 75)//Hurt. + msg += "[T.He] looks injured.\n" + + if(mhealth >= 75)//Or incredibly hurt. + msg += "[T.He] looks incredibly injured.\n" + + var/list/wound_flavor_text = list() + var/applying_pressure = "" + var/list/shown_objects = list() + + for(var/organ_tag in species.has_limbs) + + var/list/organ_data = species.has_limbs[organ_tag] + var/organ_descriptor = organ_data["descriptor"] + var/obj/item/organ/external/E = organs_by_name[organ_tag] + + if(!E) + wound_flavor_text[organ_descriptor] = "[T.He] [T.is] missing [T.his] [organ_descriptor].\n" + continue + + wound_flavor_text[E.name] = "" + + if(E.applied_pressure == src) + applying_pressure = "[T.He] [T.is] applying pressure to [T.his] [E.name].
            " + + var/obj/item/clothing/hidden + var/list/clothing_items = list(head, wear_mask, wear_suit, w_uniform, gloves, shoes) + for(var/obj/item/clothing/C in clothing_items) + if(istype(C) && (C.body_parts_covered & E.body_part)) + hidden = C + break + + if(hidden && user != src) + if(E.status & ORGAN_BLEEDING && !(hidden.item_flags & ITEM_FLAG_THICKMATERIAL)) //not through a spacesuit + wound_flavor_text[hidden.name] = "[T.He] [T.has] blood soaking through [hidden]!
            " + else + if(E.is_stump()) + wound_flavor_text[E.name] += "[T.He] [T.has] a stump where [T.his] [organ_descriptor] should be.\n" + else + if(!is_synth && E.robotic >= ORGAN_ROBOT && (E.parent && E.parent.robotic < ORGAN_ROBOT)) + wound_flavor_text[E.name] = "[T.He] [T.has] a [E.name].\n" + if(!hidden || distance <=1) + if(E.dislocated > 0) + wound_flavor_text[E.name] += "[T.His] [E.joint] is dislocated!
            " + if(((E.status & ORGAN_BROKEN) && E.brute_dam > E.min_broken_damage) || (E.status & ORGAN_MUTATED)) + if(E.splinted) + wound_flavor_text[E.name] += "[T.His] [E.name] is splinted!
            " + else + wound_flavor_text[E.name] += "[T.His] [E.name] is broken!
            " + + for(var/datum/wound/wound in E.wounds) + if(wound.embedded_objects.len) + shown_objects += wound.embedded_objects + wound_flavor_text["[E.name]"] += "The [wound.desc] on [T.his] [E.name] has \a [english_list(wound.embedded_objects, and_text = " and \a ", comma_text = ", \a ")] sticking out of it!
            " + + msg += "" + for(var/limb in wound_flavor_text) + msg += wound_flavor_text[limb] + msg += "" + + for(var/obj/implant in get_visible_implants(0)) + if(implant in shown_objects) + continue + msg += "[src] [T.has] \a [implant.name] sticking out of [T.his] flesh!\n" + if(digitalcamo) + msg += "[T.He] [T.is] repulsively uncanny!\n" + + + var/obj/item/organ/external/head/O = locate(/obj/item/organ/external/head) in organs + if(O && O.get_teeth() < O.max_teeth) + msg += "[O.get_teeth() <= 0 ? "All" : "[O.max_teeth - O.get_teeth()]"] of [T.his] teeth are missing!\n" + + if(!skipface) + if(!stat) + if(happiness <= MOOD_LEVEL_SAD2) + msg += "[T.He] looks stressed.\n" + + if(decaylevel == 1) + msg += "[T.He] [T.is] starting to smell.\n" + if(decaylevel == 2) + msg += "[T.He] [T.is] bloated and smells disgusting.\n" + if(decaylevel == 3) + msg += "[T.He] [T.is] rotting and blackened, the skin sloughing off. The smell is indescribably foul.\n" + if(decaylevel == 4) + msg += "[T.He] [T.is] mostly dessicated now, with only bones remaining of what used to be a person.\n" + + if(hasHUD(user,"security")) + var/perpname = "wot" + var/criminal = "None" + + if(wear_id) + var/obj/item/weapon/card/id/I = wear_id.GetIdCard() + if(I) + perpname = I.registered_name + else + perpname = name + else + perpname = name + + if(perpname) + var/datum/computer_file/crew_record/R = get_crewmember_record(perpname) + if(R) + criminal = R.get_criminalStatus() + + msg += "Criminal status: \[[criminal]\]\n" + msg += "Security records: \[View\]\n" + + if(hasHUD(user,"medical")) + var/perpname = "wot" + var/medical = "None" + + if(wear_id) + if(istype(wear_id,/obj/item/weapon/card/id)) + perpname = wear_id:registered_name + else if(istype(wear_id,/obj/item/device/pda)) + var/obj/item/device/pda/tempPda = wear_id + perpname = tempPda.owner + else + perpname = src.name + + var/datum/computer_file/crew_record/R = get_crewmember_record(perpname) + if(R) + medical = R.get_status() + + msg += "Physical status: \[[medical]\]\n" + msg += "Medical records: \[View\]\n" + + + if(print_flavor_text()) msg += "[print_flavor_text()]\n" + + msg += "

            " + msg += applying_pressure + + if (pose) + if( findtext(pose,".",length(pose)) == 0 && findtext(pose,"!",length(pose)) == 0 && findtext(pose,"?",length(pose)) == 0 ) + pose = addtext(pose,".") //Makes sure all emotes end with a period. + msg += "[T.He] [pose]" + + to_chat(user, jointext(msg, null)) + +//Helper procedure. Called by /mob/living/carbon/human/examine() and /mob/living/carbon/human/Topic() to determine HUD access to security and medical records. +/proc/hasHUD(mob/M as mob, hudtype) + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + switch(hudtype) + if("security") + if(istype(H.glasses,/obj/item/clothing/glasses)) + var/obj/item/clothing/glasses/G = H.glasses + return istype(G.hud, /obj/item/clothing/glasses/hud/security) || istype(G, /obj/item/clothing/glasses/hud/security) + else + return FALSE + if("medical") + if(istype(H.glasses,/obj/item/clothing/glasses)) + var/obj/item/clothing/glasses/G = H.glasses + return istype(G.hud, /obj/item/clothing/glasses/hud/health) || istype(G, /obj/item/clothing/glasses/hud/health) + else + return FALSE + else + return 0 + else if(istype(M, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = M + switch(hudtype) + if("security") + return istype(R.module_state_1, /obj/item/borg/sight/hud/sec) || istype(R.module_state_2, /obj/item/borg/sight/hud/sec) || istype(R.module_state_3, /obj/item/borg/sight/hud/sec) + if("medical") + return istype(R.module_state_1, /obj/item/borg/sight/hud/med) || istype(R.module_state_2, /obj/item/borg/sight/hud/med) || istype(R.module_state_3, /obj/item/borg/sight/hud/med) + else + return 0 + else + return 0 +/* +/mob/living/carbon/human/verb/pose() + set name = "Set Pose" + set desc = "Sets a description which will be shown when someone examines you." + set category = "IC" + + pose = sanitize(input(usr, "This is [src]. [get_visible_gender() == MALE ? "He" : get_visible_gender() == FEMALE ? "She" : "They"] [get_visible_gender() == NEUTER ? "are" : "is"]...", "Pose", null) as text) + +/mob/living/carbon/human/verb/set_flavor() + set name = "Set Flavour Text" + set desc = "Sets an extended description of your character's features." + set category = "IC" + + var/list/HTML = list() + HTML += "" + HTML += "
            " + HTML += "Update 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 += "" + src << browse(jointext(HTML,null), "window=flavor_changes;size=430x300") +*/ diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm new file mode 100644 index 00000000..e215cb6f --- /dev/null +++ b/code/modules/mob/living/carbon/human/human.dm @@ -0,0 +1,1826 @@ +/mob/living/carbon/human + name = "unknown" + real_name = "unknown" + voice_name = "unknown" + icon = 'icons/mob/human.dmi' + icon_state = "body_m_s" + + var/list/hud_list[10] + var/embedded_flag //To check if we've need to roll for damage on movement while an item is imbedded in us. + +/mob/living/carbon/human/New(var/new_loc, var/new_species = null) + + if(!dna) + dna = new /datum/dna(null) + // Species name is handled by set_species() + + if(!species) + if(new_species) + set_species(new_species,1) + else + set_species() + + if(species) + real_name = species.get_random_name(gender) + SetName(real_name) + if(mind) + mind.name = real_name + + hud_list[HEALTH_HUD] = new /image/hud_overlay('icons/mob/hud_med.dmi', src, "100") + hud_list[STATUS_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudhealthy") + hud_list[LIFE_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudhealthy") + hud_list[ID_HUD] = new /image/hud_overlay(GLOB.using_map.id_hud_icons, src, "hudunknown") + hud_list[WANTED_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[IMPLOYAL_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[IMPCHEM_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[IMPTRACK_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[SPECIALROLE_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[STATUS_HUD_OOC] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudhealthy") + + GLOB.human_mob_list |= src + ..() + + init_skills() + init_stats() + add_teeth() + bladder = rand(0,100) + bowels = rand(0, 100) + overlay_fullscreen("fademob", /obj/screen/fullscreen/fadeoutok) + //spawn(41) + // clear_fullscreen("fademob") + + if(dna) + dna.ready_dna(src) + dna.real_name = real_name + dna.s_base = s_base + sync_organ_dna() + make_blood() + spawn(10) + var/turf/T = get_turf(src) + var/obj/structure/bed/padded/B = locate() in T + if(B) + B.buckle_mob(src) + + +/mob/living/carbon/human/Destroy() + GLOB.human_mob_list -= src + worn_underwear = null + for(var/organ in organs) + qdel(organ) + return ..() + +/mob/living/carbon/human/Stat() + . = ..() + if(statpanel("Status")) + if(iswarfare()) + //stat("[BLUE_TEAM] reinforcements:", SSWarfare.blue.left) + //stat("[BLUE_TEAM] capture points:", SSWarfare.blue.points) + //stat("[RED_TEAM] reinforcements:", SSWarfare.red.left) + //stat("[RED_TEAM] capture points:", SSWarfare.red.points) + + + if(warfare_faction == RED_TEAM) + for(var/area/A in GLOB.red_captured_zones) + stat("Captured Trench:", A) + if(warfare_faction == BLUE_TEAM) + for(var/area/A in GLOB.blue_captured_zones) + stat("Captured Trench:", A) + + if(crouching) + stat("Stance:", "Crouching") + else if(lying) + stat("Stance:", "Lying Down") + else + stat("Stance:", "Standing") + + stat("[my_stats[STAT(str)].shorthand]:", "[STAT_LEVEL(str)]")//Stats! + stat("[my_stats[STAT(dex)].shorthand]:", "[STAT_LEVEL(dex)]") + stat("[my_stats[STAT(end)].shorthand]:", "[STAT_LEVEL(end)]") + stat("[my_stats[STAT(int)].shorthand]:", "[STAT_LEVEL(int)]") + + //if(evacuation_controller) + // var/eta_status = evacuation_controller.get_status_panel_eta() + // if(eta_status) + // stat(null, eta_status) + + if (istype(internal)) + if (!internal.air_contents) + qdel(internal) + else + stat("Internal Atmosphere Info", internal.name) + stat("Tank Pressure", internal.air_contents.return_pressure()) + stat("Distribution Pressure", internal.distribute_pressure) + + + var/obj/item/organ/internal/cell/potato = internal_organs_by_name[BP_CELL] + if(potato && potato.cell) + stat("Battery charge:", "[potato.get_charge()]/[potato.cell.maxcharge]") + + if(mind) + if(mind.changeling) + stat("Chemical Storage", mind.changeling.chem_charges) + stat("Genetic Damage Time", mind.changeling.geneticdamage) + +/mob/living/carbon/human/ex_act(severity) + if(!blinded) + flash_eyes() + + var/b_loss = null + var/f_loss = null + switch (severity) + if (1.0) + b_loss = 400 + f_loss = 100 + if (!prob(getarmor(null, "bomb"))) + gib() + return + else + var/atom/target = get_edge_target_turf(src, get_dir(src, get_step_away(src, src))) + throw_at(target, 200, 4) + + if (2.0) + b_loss = 60 + f_loss = 60 + + if (!istype(l_ear, /obj/item/clothing/ears/earmuffs) && !istype(r_ear, /obj/item/clothing/ears/earmuffs)) + ear_damage += 30 + ear_deaf += 120 + if (prob(70)) + Paralyse(10) + + if(3.0) + b_loss = 30 + if (!istype(l_ear, /obj/item/clothing/ears/earmuffs) && !istype(r_ear, /obj/item/clothing/ears/earmuffs)) + ear_damage += 15 + ear_deaf += 60 + if (prob(50)) + Paralyse(10) + + // factor in armour + var/protection = blocked_mult(getarmor(null, "bomb")) + b_loss *= protection + f_loss *= protection + + // focus most of the blast on one organ + var/obj/item/organ/external/take_blast = pick(organs) + take_blast.take_damage(b_loss * 0.7, f_loss * 0.7, used_weapon = "Explosive blast") + + // distribute the remaining 30% on all limbs equally (including the one already dealt damage) + b_loss *= 0.3 + f_loss *= 0.3 + + var/weapon_message = "Explosive Blast" + for(var/obj/item/organ/external/temp in organs) + var/loss_val + if(temp.organ_tag == BP_HEAD) + loss_val = 0.2 + else if(temp.organ_tag == BP_CHEST) + loss_val = 0.4 + else + loss_val = 0.05 + temp.take_damage(b_loss * loss_val, f_loss * loss_val, used_weapon = weapon_message) + +/mob/living/carbon/human/proc/implant_loyalty(mob/living/carbon/human/M, override = FALSE) // Won't override by default. + if(!config.use_loyalty_implants && !override) return // Nuh-uh. + + var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(M) + L.imp_in = M + L.implanted = 1 + var/obj/item/organ/external/affected = M.organs_by_name[BP_HEAD] + affected.implants += L + L.part = affected + L.implanted(src) + +/mob/living/carbon/human/proc/is_loyalty_implanted(mob/living/carbon/human/M) + for(var/L in M.contents) + if(istype(L, /obj/item/weapon/implant/loyalty)) + for(var/obj/item/organ/external/O in M.organs) + if(L in O.implants) + return 1 + return 0 + +/mob/living/carbon/human/restrained() + if (handcuffed) + return 1 + if(grab_restrained()) + return 1 + if (istype(wear_suit, /obj/item/clothing/suit/straight_jacket)) + return 1 + return 0 + +/mob/living/carbon/human/proc/grab_restrained() + for (var/obj/item/grab/G in grabbed_by) + if(G.restrains()) + return TRUE + +/mob/living/carbon/human/var/co2overloadtime = null +/mob/living/carbon/human/var/temperature_resistance = T0C+75 + + +/mob/living/carbon/human/show_inv(mob/user as mob) + if(user.incapacitated() || !user.Adjacent(src) || !user.IsAdvancedToolUser()) + return + + var/datum/browser/popup = new(user, "mob[name]", FALSE, 340, 540) + user.set_machine(src) + var/dat = "
            [name]


            " + + for(var/entry in species.hud.gear) + var/list/slot_ref = species.hud.gear[entry] + if((slot_ref["slot"] in list(slot_l_store, slot_r_store))) + continue + var/obj/item/thing_in_slot = get_equipped_item(slot_ref["slot"]) + dat += "
            [slot_ref["name"]]: [istype(thing_in_slot) ? thing_in_slot : "nothing"]" + if(istype(thing_in_slot, /obj/item/clothing)) + var/obj/item/clothing/C = thing_in_slot + if(C.accessories.len) + dat += "
            Remove accessory" + dat += "

            " + + if(species.hud.has_hands) + dat += "
            Left hand: [istype(l_hand) ? l_hand : "nothing"]" + dat += "
            Right hand: [istype(r_hand) ? r_hand : "nothing"]" + + // Do they get an option to set internals? + if(istype(wear_mask, /obj/item/clothing/mask) || istype(head, /obj/item/clothing/head/helmet/space)) + if(istype(back, /obj/item/weapon/tank) || istype(belt, /obj/item/weapon/tank) || istype(s_store, /obj/item/weapon/tank)) + dat += "
            Toggle internals." + + var/obj/item/clothing/under/suit = w_uniform + // Other incidentals. + if(istype(suit)) + dat += "
            Pockets: Empty or Place Item" + if(suit.has_sensor == 1) + dat += "
            Set sensors" + if(handcuffed) + dat += "
            Handcuffed" + + for(var/entry in worn_underwear) + var/obj/item/underwear/UW = entry + dat += "
            Remove \the [UW]" + + dat += "
            Remove splints" + dat += "
            Refresh" + dat += "
            Close" + + + popup.set_content(jointext(dat, null)) + popup.open() + //user << browse(dat, text("window=mob[name];size=340x540")) + onclose(user, "mob[name]") + return + +// called when something steps onto a human +// this handles mulebots and vehicles +/mob/living/carbon/human/Crossed(var/atom/movable/AM) + if(istype(AM, /mob/living/bot/mulebot)) + var/mob/living/bot/mulebot/MB = AM + MB.runOver(src) + + if(istype(AM, /obj/vehicle)) + var/obj/vehicle/V = AM + V.RunOver(src) + +// Get rank from ID, ID inside PDA, PDA, ID in wallet, etc. +/mob/living/carbon/human/proc/get_authentification_rank(var/if_no_id = "No id", var/if_no_job = "No job") + var/obj/item/device/pda/pda = wear_id + if (istype(pda)) + if (pda.id) + return pda.id.rank + else + return pda.ownrank + else + var/obj/item/weapon/card/id/id = get_idcard() + if(id) + return id.rank ? id.rank : if_no_job + else + return if_no_id + +//gets assignment from ID or ID inside PDA or PDA itself +//Useful when player do something with computers +/mob/living/carbon/human/proc/get_assignment(var/if_no_id = "No id", var/if_no_job = "No job") + var/obj/item/device/pda/pda = wear_id + if (istype(pda)) + if (pda.id) + return pda.id.assignment + else + return pda.ownjob + else + var/obj/item/weapon/card/id/id = get_idcard() + if(id) + return id.assignment ? id.assignment : if_no_job + else + return if_no_id + +//gets name from ID or ID inside PDA or PDA itself +//Useful when player do something with computers +/mob/living/carbon/human/proc/get_authentification_name(var/if_no_id = "Unknown") + var/obj/item/device/pda/pda = wear_id + if (istype(pda)) + if (pda.id) + return pda.id.registered_name + else + return pda.owner + else + var/obj/item/weapon/card/id/id = get_idcard() + if(id) + return id.registered_name + else + return if_no_id + +//repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a seperate proc as it'll be useful elsewhere +/mob/living/carbon/human/proc/get_visible_name() + var/face_name = get_face_name() + var/id_name = get_id_name("") + if(is_anonymous) + return "Unknown" + if(id_name && (id_name != face_name) && face_name != "Unknown") + return "[face_name] (as [id_name])" + else if(id_name && (id_name != face_name) && face_name == "Unknown")//Hacky af. + return id_name + return face_name + +//Returns "Unknown" if facially disfigured and real_name if not. Useful for setting name when polyacided or when updating a human's name variable +//Also used in AI tracking people by face, so added in checks for head coverings like masks and helmets +/mob/living/carbon/human/proc/get_face_name() + var/obj/item/organ/external/H = get_organ(BP_HEAD) + if(!H || is_anonymous || H.disfigured || H.is_stump() || !real_name || (HUSK in mutations) || (wear_mask && (wear_mask.flags_inv&HIDEFACE)) || (head && (head.flags_inv&HIDEFACE))) //Face is unrecognizeable, use ID if able + return "Unknown" + return real_name + +//gets name from ID or PDA itself, ID inside PDA doesn't matter +//Useful when player is being seen by other mobs +/mob/living/carbon/human/proc/get_id_name(var/if_no_id = "Unknown") + . = if_no_id + if(istype(wear_id,/obj/item/device/pda)) + var/obj/item/device/pda/P = wear_id + return P.owner + if(wear_id) + var/obj/item/weapon/card/id/I = wear_id.GetIdCard() + if(I) + return I.registered_name + return + +/mob/living/carbon/human/proc/get_job_name() + if(wear_id) + var/obj/item/weapon/card/id/I = wear_id.GetIdCard() + if(I) + return I.assignment + + +//gets ID card object from special clothes slot or null. +/mob/living/carbon/human/proc/get_idcard() + if(wear_id) + return wear_id.GetIdCard() + +//Removed the horrible safety parameter. It was only being used by ninja code anyways. +//Now checks siemens_coefficient of the affected area by default +/mob/living/carbon/human/electrocute_act(var/shock_damage, var/obj/source, var/base_siemens_coeff = 1.0, var/def_zone = null) + + if(status_flags & GODMODE) return 0 //godmode + + if(species.siemens_coefficient == -1) + if(stored_shock_by_ref["\ref[src]"]) + stored_shock_by_ref["\ref[src]"] += shock_damage + else + stored_shock_by_ref["\ref[src]"] = shock_damage + return + + if (!def_zone) + def_zone = pick(BP_L_HAND, BP_R_HAND) + + return ..(shock_damage, source, base_siemens_coeff, def_zone) + +/mob/living/carbon/human/apply_shock(var/shock_damage, var/def_zone, var/base_siemens_coeff = 1.0) + var/obj/item/organ/external/initial_organ = get_organ(check_zone(def_zone)) + if(!initial_organ) + initial_organ = pick(organs) + + var/obj/item/organ/external/floor_organ + + if(!lying) + var/obj/item/organ/external/list/standing = list() + for(var/limb_tag in list(BP_L_FOOT, BP_R_FOOT)) + var/obj/item/organ/external/E = organs_by_name[limb_tag] + if(E && E.is_usable()) + standing[E.organ_tag] = E + if((def_zone == BP_L_FOOT || def_zone == BP_L_LEG) && standing[BP_L_FOOT]) + floor_organ = standing[BP_L_FOOT] + if((def_zone == BP_R_FOOT || def_zone == BP_R_LEG) && standing[BP_R_FOOT]) + floor_organ = standing[BP_R_FOOT] + else + floor_organ = standing[pick(standing)] + + if(!floor_organ) + floor_organ = pick(organs) + + var/obj/item/organ/external/list/to_shock = trace_shock(initial_organ, floor_organ) + + if(to_shock && to_shock.len) + shock_damage /= to_shock.len + shock_damage = round(shock_damage, 0.1) + else + return 0 + + var/total_damage = 0 + + for(var/obj/item/organ/external/E in to_shock) + total_damage += ..(shock_damage, E.organ_tag, base_siemens_coeff * get_siemens_coefficient_organ(E)) + return total_damage + +/mob/living/carbon/human/proc/trace_shock(var/obj/item/organ/external/init, var/obj/item/organ/external/floor) + var/obj/item/organ/external/list/traced_organs = list(floor) + + if(!init) + return + + if(!floor || init == floor) + return list(init) + + for(var/obj/item/organ/external/E in list(floor, init)) + while(E && E.parent_organ) + E = organs_by_name[E.parent_organ] + traced_organs += E + if(E == init) + return traced_organs + + return traced_organs + +/mob/living/carbon/human/Topic(href, href_list) + + if (href_list["refresh"]) + if(Adjacent(src, usr)) + show_inv(usr) + + if (href_list["mach_close"]) + var/t1 = text("window=[]", href_list["mach_close"]) + unset_machine() + src << browse(null, t1) + + if(href_list["item"]) + handle_strip(href_list["item"],usr,locate(href_list["holder"])) + //show_inv(usr) + + if (href_list["criminal"]) + if(hasHUD(usr,"security")) + + var/modified = 0 + var/perpname = "wot" + if(wear_id) + var/obj/item/weapon/card/id/I = wear_id.GetIdCard() + if(I) + perpname = I.registered_name + else + perpname = name + else + perpname = name + + var/datum/computer_file/crew_record/R = get_crewmember_record(perpname) + if(R) + var/setcriminal = input(usr, "Specify a new criminal status for this person.", "Security HUD", R.get_criminalStatus()) as anything in GLOB.security_statuses + if(hasHUD(usr, "security") && setcriminal) + R.set_criminalStatus(setcriminal) + modified = 1 + + spawn() + BITSET(hud_updateflag, WANTED_HUD) + if(istype(usr,/mob/living/carbon/human)) + var/mob/living/carbon/human/U = usr + U.handle_regular_hud_updates() + if(istype(usr,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/U = usr + U.handle_regular_hud_updates() + + if(!modified) + to_chat(usr, "Unable to locate a data core entry for this person.") + if (href_list["secrecord"]) + if(hasHUD(usr,"security")) + var/perpname = "wot" + var/read = 0 + + if(wear_id) + if(istype(wear_id,/obj/item/weapon/card/id)) + perpname = wear_id:registered_name + else if(istype(wear_id,/obj/item/device/pda)) + var/obj/item/device/pda/tempPda = wear_id + perpname = tempPda.owner + else + perpname = src.name + var/datum/computer_file/crew_record/E = get_crewmember_record(perpname) + if(E) + if(hasHUD(usr,"security")) + to_chat(usr, "Name: [E.get_name()]") + to_chat(usr, "Criminal Status: [E.get_criminalStatus()]") + to_chat(usr, "Details: [pencode2html(E.get_criminalStatus())]") + read = 1 + + if(!read) + to_chat(usr, "Unable to locate a data core entry for this person.") + if (href_list["medical"]) + if(hasHUD(usr,"medical")) + var/perpname = "wot" + var/modified = 0 + + if(wear_id) + if(istype(wear_id,/obj/item/weapon/card/id)) + perpname = wear_id:registered_name + else if(istype(wear_id,/obj/item/device/pda)) + var/obj/item/device/pda/tempPda = wear_id + perpname = tempPda.owner + else + perpname = src.name + + var/datum/computer_file/crew_record/E = get_crewmember_record(perpname) + if(E) + var/setmedical = input(usr, "Specify a new medical status for this person.", "Medical HUD", E.get_status()) as anything in GLOB.physical_statuses + if(hasHUD(usr,"medical") && setmedical) + E.set_status(setmedical) + modified = 1 + + spawn() + if(istype(usr,/mob/living/carbon/human)) + var/mob/living/carbon/human/U = usr + U.handle_regular_hud_updates() + if(istype(usr,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/U = usr + U.handle_regular_hud_updates() + + if(!modified) + to_chat(usr, "Unable to locate a data core entry for this person.") + if (href_list["medrecord"]) + if(hasHUD(usr,"medical")) + var/perpname = "wot" + var/read = 0 + + if(wear_id) + if(istype(wear_id,/obj/item/weapon/card/id)) + perpname = wear_id:registered_name + else if(istype(wear_id,/obj/item/device/pda)) + var/obj/item/device/pda/tempPda = wear_id + perpname = tempPda.owner + else + perpname = src.name + var/datum/computer_file/crew_record/E = get_crewmember_record(perpname) + if(E) + if(hasHUD(usr,"medical")) + to_chat(usr, "Name: [E.get_name()]") + to_chat(usr, "Gender: [E.get_sex()]") + //to_chat(usr, "Species: [E.get_species()]") + to_chat(usr, "Blood Type: [E.get_bloodtype()]") + to_chat(usr, "Details: [pencode2html(E.get_medRecord())]") + read = 1 + if(!read) + to_chat(usr, "Unable to locate a data core entry for this person.") + + if (href_list["lookitem"]) + var/obj/item/I = locate(href_list["lookitem"]) + if(I) + src.examinate(I) + + if (href_list["lookmob"]) + var/mob/M = locate(href_list["lookmob"]) + if(M) + src.examinate(M) + + if (href_list["flavor_change"]) + switch(href_list["flavor_change"]) + if("done") + src << browse(null, "window=flavor_changes") + return + if("general") + var/msg = sanitize(input(usr,"Update the 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["flavor_change"]])) as message, extra = 0) + flavor_texts[href_list["flavor_change"]] = sanitize(msg, extra = 0) + return + else + var/msg = sanitize(input(usr,"Update the flavor text for your [href_list["flavor_change"]].","Flavor Text",html_decode(flavor_texts[href_list["flavor_change"]])) as message, extra = 0) + flavor_texts[href_list["flavor_change"]] = sanitize(msg, extra = 0) + // set_flavor() + return + //Crafting + if (href_list["craft"]) + var/turf/T = get_step(src, dir) + if(!T.Adjacent(src)) + return 0 + var/rname = href_list["craft"] + var/datum/crafting_recipe/R = crafting_recipes[rname] + R.make(src, T) + + ..() + return + +///eyecheck() +///Returns a number between -1 to 2 +/mob/living/carbon/human/eyecheck() + var/total_protection = flash_protection + if(internal_organs_by_name[BP_EYES]) // Eyes are fucked, not a 'weak point'. + var/obj/item/organ/internal/eyes/I = internal_organs_by_name[BP_EYES] + if(!I.is_usable()) + return FLASH_PROTECTION_MAJOR + else + total_protection = I.get_total_protection(flash_protection) + else // They can't be flashed if they don't have eyes. + return FLASH_PROTECTION_MAJOR + return total_protection + +/mob/living/carbon/human/flash_eyes(var/intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash) + if(internal_organs_by_name[BP_EYES]) // Eyes are fucked, not a 'weak point'. + var/obj/item/organ/internal/eyes/I = internal_organs_by_name[BP_EYES] + I.additional_flash_effects(intensity) + return ..() + +//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. +/mob/living/carbon/human/proc/headcheck(var/target_zone, var/brain_tag = BP_BRAIN) + + var/obj/item/organ/affecting = internal_organs_by_name[brain_tag] + + target_zone = check_zone(target_zone) + if(!affecting || affecting.parent_organ != target_zone) + return 0 + + //if the parent organ is significantly larger than the brain organ, then hitting it is not guaranteed + var/obj/item/organ/parent = get_organ(target_zone) + if(!parent) + return 0 + + if(parent.w_class > affecting.w_class + 1) + return prob(100 / 2**(parent.w_class - affecting.w_class - 1)) + + return 1 + +/mob/living/carbon/human/IsAdvancedToolUser(var/silent) + if(species.has_fine_manipulation && !nabbing) + return 1 + if(!silent) + to_chat(src, "You don't have the dexterity to use that!") + return 0 + +/mob/living/carbon/human/abiotic(var/full_body = TRUE) + if(full_body) + if(src.head || src.shoes || src.w_uniform || src.wear_suit || src.glasses || src.l_ear || src.r_ear || src.gloves) + return FALSE + return ..() + +/mob/living/carbon/human/proc/check_dna() + dna.check_integrity(src) + return + +/mob/living/carbon/human/get_species() + if(!species) + set_species() + return species.name + +/mob/living/carbon/human/proc/play_xylophone() + if(!src.xylophone) + visible_message("\The [src] begins playing \his ribcage like a xylophone. It's quite spooky.","You begin to play a spooky refrain on your ribcage.","You hear a spooky xylophone melody.") + var/song = pick('sound/effects/xylophone1.ogg','sound/effects/xylophone2.ogg','sound/effects/xylophone3.ogg') + playsound(loc, song, 50, 1, -1) + xylophone = 1 + spawn(1200) + xylophone=0 + return + +/mob/living/proc/check_has_mouth() + // mobs do not have mouths by default + return 0 + +/mob/living/carbon/human/check_has_mouth() + // Todo, check stomach organ when implemented. + var/obj/item/organ/external/head/H = get_organ(BP_HEAD) + if(!H || !istype(H) || !H.can_intake_reagents) + return 0 + return 1 + +/mob/living/carbon/human/proc/vomit(var/toxvomit = 0, var/timevomit = 1, var/level = 3) + set waitfor = 0 + if(!check_has_mouth() || isSynthetic() || !timevomit || !level) + return + level = Clamp(level, 1, 3) + timevomit = Clamp(timevomit, 1, 10) + if(stat == DEAD) + return + if(!lastpuke) + lastpuke = 1 + to_chat(src, "You feel nauseous...") + if(level > 1) + sleep(150 / timevomit) //15 seconds until second warning + to_chat(src, "You feel like you are about to throw up!") + if(level > 2) + sleep(100 / timevomit) //and you have 10 more for mad dash to the bucket + Stun(1) + if(nutrition < 40) + custom_emote(1,"dry heaves.") + else + for(var/a in stomach_contents) + var/atom/movable/A = a + A.forceMove(get_turf(src)) + stomach_contents.Remove(a) + if(src.species.gluttonous & GLUT_PROJECTILE_VOMIT) + A.throw_at(get_edge_target_turf(src,src.dir),7,7,src) + + src.visible_message("[src] throws up!","You throw up!") + playsound(src, 'sound/effects/vomit.ogg', 50, 1) + playsound(src, 'sound/effects/splat.ogg', 50, 1) + add_event("hygiene", /datum/happiness_event/hygiene/vomitted) + + var/turf/location = loc + if (istype(location, /turf/simulated)) + location.add_vomit_floor(src, toxvomit) + ingested.remove_any(5) + nutrition -= 30 + sleep(350) //wait 35 seconds before next volley + lastpuke = 0 + +/mob/living/carbon/human/proc/morph() + set name = "Morph" + set category = "Superpower" + + if(stat!=CONSCIOUS) + reset_view(0) + remoteview_target = null + return + + if(!(mMorph in mutations)) + src.verbs -= /mob/living/carbon/human/proc/morph + return + + var/new_facial = input("Please select facial hair color.", "Character Generation",rgb(r_facial,g_facial,b_facial)) as color + 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)) + + var/new_hair = input("Please select hair color.", "Character Generation",rgb(r_hair,g_hair,b_hair)) as color + if(new_facial) + r_hair = hex2num(copytext(new_hair, 2, 4)) + g_hair = hex2num(copytext(new_hair, 4, 6)) + b_hair = hex2num(copytext(new_hair, 6, 8)) + + var/new_eyes = input("Please select eye color.", "Character Generation",rgb(r_eyes,g_eyes,b_eyes)) as color + 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)) + update_eyes() + + var/new_tone = input("Please select skin tone level: 1-220 (1=albino, 35=caucasian, 150=black, 220='very' black)", "Character Generation", "[35-s_tone]") as text + + if (!new_tone) + new_tone = 35 + s_tone = max(min(round(text2num(new_tone)), 220), 1) + s_tone = -s_tone + 35 + + // hair + var/list/all_hairs = typesof(/datum/sprite_accessory/hair) - /datum/sprite_accessory/hair + var/list/hairs = list() + + // loop through potential hairs + for(var/x in all_hairs) + var/datum/sprite_accessory/hair/H = new x // create new hair datum based on type x + hairs.Add(H.name) // add hair name to hairs + qdel(H) // delete the hair after it's all done + + var/new_style = input("Please select hair style", "Character Generation",h_style) as null|anything in hairs + + // if new style selected (not cancel) + if (new_style) + h_style = new_style + + // facial hair + var/list/all_fhairs = typesof(/datum/sprite_accessory/facial_hair) - /datum/sprite_accessory/facial_hair + var/list/fhairs = list() + + for(var/x in all_fhairs) + var/datum/sprite_accessory/facial_hair/H = new x + fhairs.Add(H.name) + qdel(H) + + new_style = input("Please select facial style", "Character Generation",f_style) as null|anything in fhairs + + if(new_style) + f_style = new_style + + var/new_gender = alert(usr, "Please select gender.", "Character Generation", "Male", "Female", "Neutral") + if (new_gender) + if(new_gender == "Male") + gender = MALE + else if(new_gender == "Female") + gender = FEMALE + else + gender = NEUTER + regenerate_icons() + check_dna() + + visible_message("\The [src] morphs and changes [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] appearance!", "You change your appearance!", "Oh, god! What the hell was that? It sounded like flesh getting squished and bone ground into a different shape!") + +/mob/living/carbon/human/proc/remotesay() + set name = "Project mind" + set category = "Superpower" + + if(stat!=CONSCIOUS) + reset_view(0) + remoteview_target = null + return + + if(!(mRemotetalk in src.mutations)) + src.verbs -= /mob/living/carbon/human/proc/remotesay + return + var/list/creatures = list() + for(var/mob/living/carbon/h in world) + creatures += h + var/mob/target = input("Who do you want to project your mind to ?") as null|anything in creatures + if (isnull(target)) + return + + var/say = sanitize(input("What do you wish to say")) + if(mRemotetalk in target.mutations) + target.show_message("You hear [src.real_name]'s voice: [say]") + else + target.show_message("You hear a voice that seems to echo around the room: [say]") + usr.show_message("You project your mind into [target.real_name]: [say]") + log_say("[key_name(usr)] sent a telepathic message to [key_name(target)]: [say]") + for(var/mob/observer/ghost/G in world) + G.show_message("Telepathic message from [src] to [target]: [say]") + +/mob/living/carbon/human/proc/remoteobserve() + set name = "Remote View" + set category = "Superpower" + + if(stat!=CONSCIOUS) + remoteview_target = null + reset_view(0) + return + + if(!(mRemote in src.mutations)) + remoteview_target = null + reset_view(0) + src.verbs -= /mob/living/carbon/human/proc/remoteobserve + return + + if(client.eye != client.mob) + remoteview_target = null + reset_view(0) + return + + var/list/mob/creatures = list() + + for(var/mob/living/carbon/h in world) + var/turf/temp_turf = get_turf(h) + if((temp_turf.z != 1 && temp_turf.z != 5) || h.stat!=CONSCIOUS) //Not on mining or the station. Or dead + continue + creatures += h + + var/mob/target = input ("Who do you want to project your mind to ?") as mob in creatures + + if (target) + remoteview_target = target + reset_view(target) + else + remoteview_target = null + reset_view(0) + +/atom/proc/get_visible_gender() + return gender + +/mob/living/carbon/human/get_visible_gender() + if(wear_suit && wear_suit.flags_inv & HIDEJUMPSUIT && ((head && head.flags_inv & HIDEMASK) || wear_mask)) + return NEUTER + return ..() + +/mob/living/carbon/human/proc/increase_germ_level(n) + if(gloves) + gloves.germ_level += n + else + germ_level += n + +/mob/living/carbon/human/revive() + + if(should_have_organ(BP_HEART)) + vessel.add_reagent(/datum/reagent/blood,species.blood_volume-vessel.total_volume) + fixblood() + + species.create_organs(src) // Reset our organs/limbs. + restore_all_organs() // Reapply robotics/amputated status from preferences. + add_teeth() + + if(!client || !key) //Don't boot out anyone already in the mob. + for (var/obj/item/organ/internal/brain/H in world) + if(H.brainmob) + if(H.brainmob.real_name == src.real_name) + if(H.brainmob.mind) + H.brainmob.mind.transfer_to(src) + qdel(H) + + + for (var/ID in virus2) + var/datum/disease2/disease/V = virus2[ID] + V.cure(src) + + losebreath = 0 + + ..() +/mob/living/carbon/human/proc/add_teeth() + var/obj/item/organ/external/head/U = locate() in organs + if(istype(U)) + U.teeth_list.Cut() //Clear out their mouth of teeth + var/obj/item/stack/teeth/T = new species.teeth_type(U) + U.max_teeth = T.max_amount //Set max teeth for the head based on teeth spawntype + T.amount = T.max_amount + U.teeth_list += T + +/mob/living/carbon/human/proc/is_lung_ruptured() + var/obj/item/organ/internal/lungs/L = internal_organs_by_name[BP_LUNGS] + return L && L.is_bruised() + +/mob/living/carbon/human/proc/rupture_lung() + var/obj/item/organ/internal/lungs/L = internal_organs_by_name[BP_LUNGS] + if(L) + L.rupture() + +/mob/living/carbon/human/add_blood(mob/living/carbon/human/M as mob) + if (!..()) + return 0 + //if this blood isn't already in the list, add it + if(istype(M)) + if(!blood_DNA[M.dna.unique_enzymes]) + blood_DNA[M.dna.unique_enzymes] = M.dna.b_type + hand_blood_color = blood_color + src.update_inv_gloves() //handles bloody hands overlays and updating + verbs += /mob/living/carbon/human/proc/bloody_doodle + return 1 //we applied blood to the item + +/mob/living/carbon/human/clean_blood(var/clean_feet) + .=..() + gunshot_residue = null + if(clean_feet && !shoes) + feet_blood_color = null + feet_blood_DNA = null + update_inv_shoes(1) + return 1 + +/mob/living/carbon/human/get_visible_implants(var/class = 0) + + var/list/visible_implants = list() + for(var/obj/item/organ/external/organ in src.organs) + for(var/obj/item/weapon/O in organ.implants) + if(!istype(O,/obj/item/weapon/implant) && (O.w_class > class) && !istype(O,/obj/item/weapon/material/shard/shrapnel)) + visible_implants += O + + return(visible_implants) + +/mob/living/carbon/human/embedded_needs_process() + for(var/obj/item/organ/external/organ in src.organs) + for(var/obj/item/O in organ.implants) + if(!istype(O, /obj/item/weapon/implant)) //implant type items do not cause embedding effects, see handle_embedded_objects() + return 1 + return 0 + +/mob/living/carbon/human/proc/handle_embedded_and_stomach_objects() + for(var/obj/item/organ/external/organ in src.organs) + if(organ.splinted) + continue + for(var/obj/item/O in organ.implants) + if(!istype(O,/obj/item/weapon/implant) && O.w_class > 1 && prob(5)) //Moving with things stuck in you could be bad. + jossle_internal_object(organ, O) + var/obj/item/organ/external/groin = src.get_organ(BP_GROIN) + if(groin && stomach_contents && stomach_contents.len) + for(var/obj/item/O in stomach_contents) + if(O.edge || O.sharp) + if(prob(1)) + stomach_contents.Remove(O) + if(can_feel_pain()) + to_chat(src, "You feel something rip out of your stomach!") + groin.embed(O) + else if(prob(5)) + jossle_internal_object(groin,O) + +/mob/living/carbon/human/proc/jossle_internal_object(var/obj/item/organ/organ, var/obj/item/O) + // All kinds of embedded objects cause bleeding. + if(!can_feel_pain()) + to_chat(src, "You feel [O] moving inside your [organ.name].") + else + var/msg = pick( \ + "A spike of pain jolts your [organ.name] as you bump [O] inside.", \ + "Your movement jostles [O] in your [organ.name] painfully.", \ + "Your movement jostles [O] in your [organ.name] painfully.") + custom_pain(msg,40,affecting = organ) + + organ.take_damage(rand(1,3), 0, 0) + if(!(organ.robotic >= ORGAN_ROBOT) && (should_have_organ(BP_HEART))) //There is no blood in protheses. + organ.status |= ORGAN_BLEEDING + src.adjustToxLoss(rand(1,3)) + +/mob/living/carbon/human/verb/check_pulse() + set category = "Object" + set name = "Check pulse" + set desc = "Approximately count somebody's pulse. Requires you to stand still at least 6 seconds." + set src in view(1) + var/self = 0 + + if(usr.stat || usr.restrained() || !isliving(usr)) return + + if(usr == src) + self = 1 + if(!self) + usr.visible_message("[usr] kneels down, puts \his hand on [src]'s wrist and begins counting their pulse.",\ + "You begin counting [src]'s pulse") + else + usr.visible_message("[usr] begins counting their pulse.",\ + "You begin counting your pulse.") + + if(pulse()) + to_chat(usr, "[self ? "You have a" : "[src] has a"] pulse! Counting...") + else + to_chat(usr, "[src] has no pulse!")//it is REALLY UNLIKELY that a dead person would check his own pulse + return + + to_chat(usr, "You must[self ? "" : " both"] remain still until counting is finished.") + if(do_mob(usr, src, 60)) + var/message = "[self ? "Your" : "[src]'s"] pulse is [src.get_pulse(GETPULSE_HAND)]." + to_chat(usr, message) + else + to_chat(usr, "You failed to check the pulse. Try again.") + +/mob/living/carbon/human/verb/lookup() + set name = "Look Up" + set desc = "If you want to know what's above." + set category = "IC" + + if(!is_physically_disabled()) + var/turf/above = GetAbove(src) + if(shadow) + if(client.eye == shadow) + reset_view(0) + return + if(istype(above, /turf/simulated/open)) + to_chat(src, "You look up.") + if(client) + reset_view(shadow) + return + if(istype(above, /turf/space)) + to_chat(src, "You can see empty space - wow.") + else + to_chat(src, "There is nothing to see up there.") + else + to_chat(src, "You can't look up right now.") + return + +/mob/living/carbon/human/proc/set_species(var/new_species, var/default_colour) + if(!dna) + if(!new_species) + new_species = SPECIES_HUMAN + else + if(!new_species) + new_species = dna.species + else + dna.species = new_species + + // No more invisible screaming wheelchairs because of set_species() typos. + if(!all_species[new_species]) + new_species = SPECIES_HUMAN + + if(species) + + if(species.name && species.name == new_species) + return + if(species.language) + remove_language(species.language) + if(species.default_language) + remove_language(species.default_language) + for(var/datum/language/L in species.assisted_langs) + remove_language(L) + // Clear out their species abilities. + species.remove_inherent_verbs(src) + holder_type = null + + species = all_species[new_species] + species.handle_pre_spawn(src) + + if(species.language) + add_language(species.language) + species_language = all_languages[species.language] + + for(var/L in species.additional_langs) + add_language(L) + + if(species.default_language) + add_language(species.default_language) + + if(species.grab_type) + current_grab_type = all_grabobjects[species.grab_type] + + if(species.base_color && default_colour) + //Apply colour. + r_skin = hex2num(copytext(species.base_color,2,4)) + g_skin = hex2num(copytext(species.base_color,4,6)) + b_skin = hex2num(copytext(species.base_color,6,8)) + else + r_skin = 0 + g_skin = 0 + b_skin = 0 + + if(species.holder_type) + holder_type = species.holder_type + + + if(!(gender in species.genders)) + gender = species.genders[1] + + icon_state = lowertext(species.name) + + species.create_organs(src) + species.handle_post_spawn(src) + + maxHealth = species.total_health + + default_pixel_x = initial(pixel_x) + species.pixel_offset_x + default_pixel_y = initial(pixel_y) + species.pixel_offset_y + pixel_x = default_pixel_x + pixel_y = default_pixel_y + + spawn(0) + regenerate_icons() + if(vessel.total_volume < species.blood_volume) + vessel.maximum_volume = species.blood_volume + vessel.add_reagent(/datum/reagent/blood, species.blood_volume - vessel.total_volume) + else if(vessel.total_volume > species.blood_volume) + vessel.remove_reagent(/datum/reagent/blood, vessel.total_volume - species.blood_volume) + vessel.maximum_volume = species.blood_volume + fixblood() + + + // Rebuild the HUD. If they aren't logged in then login() should reinstantiate it for them. + if(client && client.screen) + client.screen.len = null + InitializeHud() + + if(config && config.use_cortical_stacks && client && client.prefs.has_cortical_stack) + create_stack() + full_prosthetic = null + + //recheck species-restricted clothing + for(var/slot in slot_first to slot_last) + var/obj/item/clothing/C = get_equipped_item(slot) + if(istype(C) && !C.mob_can_equip(src, slot, 1)) + unEquip(C) + + add_teeth() + + return 1 + +/mob/living/carbon/human/proc/bloody_doodle() + set category = "IC" + set name = "Write in blood" + set desc = "Use blood on your hands to write a short message on the floor or a wall, murder mystery style." + + if (src.stat) + return + + if (usr != src) + return 0 //something is terribly wrong + + if (!bloody_hands) + verbs -= /mob/living/carbon/human/proc/bloody_doodle + + if (src.gloves) + to_chat(src, "Your [src.gloves] are getting in the way.") + return + + var/turf/simulated/T = src.loc + if (!istype(T)) //to prevent doodling out of mechs and lockers + to_chat(src, "You cannot reach the floor.") + return + + var/direction = input(src,"Which way?","Tile selection") as anything in list("Here","North","South","East","West") + if (direction != "Here") + T = get_step(T,text2dir(direction)) + if (!istype(T)) + to_chat(src, "You cannot doodle there.") + return + + var/num_doodles = 0 + for (var/obj/effect/decal/cleanable/blood/writing/W in T) + num_doodles++ + if (num_doodles > 4) + to_chat(src, "There is no space to write on!") + return + + var/max_length = bloody_hands * 30 //tweeter style + + var/message = sanitize(input("Write a message. It cannot be longer than [max_length] characters.","Blood writing", "")) + + if (message) + var/used_blood_amount = round(length(message) / 30, 1) + bloody_hands = max(0, bloody_hands - used_blood_amount) //use up some blood + + if (length(message) > max_length) + message += "-" + to_chat(src, "You ran out of blood to write with!") + var/obj/effect/decal/cleanable/blood/writing/W = new(T) + W.basecolor = (hand_blood_color) ? hand_blood_color : COLOR_BLOOD_HUMAN + W.update_icon() + W.message = message + W.add_fingerprint(src) + +#define CAN_INJECT 1 +#define INJECTION_PORT 2 +/mob/living/carbon/human/can_inject(var/mob/user, var/target_zone) + var/obj/item/organ/external/affecting = get_organ(target_zone) + + if(!affecting) + to_chat(user, "They are missing that limb.") + return 0 + + if(affecting.robotic >= ORGAN_ROBOT) + to_chat(user, "That limb is robotic.") + return 0 + + . = CAN_INJECT + for(var/obj/item/clothing/C in list(head, wear_mask, wear_suit, w_uniform, gloves, shoes)) + if(C && (C.body_parts_covered & affecting.body_part) && (C.item_flags & ITEM_FLAG_THICKMATERIAL)) + if(istype(C, /obj/item/clothing/suit/space)) + . = INJECTION_PORT //it was going to block us, but it's a space suit so it doesn't because it has some kind of port + else + to_chat(user, "There is no exposed flesh or thin material on [src]'s [affecting.name] to inject into.") + return 0 + + +/mob/living/carbon/human/print_flavor_text(var/shrink = 1) + var/list/equipment = list(src.head,src.wear_mask,src.glasses,src.w_uniform,src.wear_suit,src.gloves,src.shoes) + var/head_exposed = 1 + var/face_exposed = 1 + var/eyes_exposed = 1 + var/torso_exposed = 1 + var/arms_exposed = 1 + var/legs_exposed = 1 + var/hands_exposed = 1 + var/feet_exposed = 1 + + for(var/obj/item/clothing/C in equipment) + if(C.body_parts_covered & HEAD) + head_exposed = 0 + if(C.body_parts_covered & FACE) + face_exposed = 0 + if(C.body_parts_covered & EYES) + eyes_exposed = 0 + if(C.body_parts_covered & UPPER_TORSO) + torso_exposed = 0 + if(C.body_parts_covered & ARMS) + arms_exposed = 0 + if(C.body_parts_covered & HANDS) + hands_exposed = 0 + if(C.body_parts_covered & LEGS) + legs_exposed = 0 + if(C.body_parts_covered & FEET) + feet_exposed = 0 + + flavor_text = "" + 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)) + flavor_text += flavor_texts[T] + flavor_text += "\n\n" + if(!shrink) + return flavor_text + else + return ..() + +/mob/living/carbon/human/getDNA() + if(species.species_flags & SPECIES_FLAG_NO_SCAN) + return null + if(isSynthetic()) + return + ..() + +/mob/living/carbon/human/setDNA() + if(species.species_flags & SPECIES_FLAG_NO_SCAN) + return + if(isSynthetic()) + return + ..() + +/mob/living/carbon/human/has_brain() + if(internal_organs_by_name[BP_BRAIN]) + var/obj/item/organ/internal/brain = internal_organs_by_name[BP_BRAIN] + if(brain && istype(brain)) + return 1 + return 0 + +/mob/living/carbon/human/has_eyes() + if(internal_organs_by_name[BP_EYES]) + var/obj/item/organ/internal/eyes = internal_organs_by_name[BP_EYES] + if(eyes && eyes.is_usable()) + return 1 + return 0 + +/mob/living/carbon/human/slip(var/slipped_on, stun_duration=8) + if((species.species_flags & SPECIES_FLAG_NO_SLIP) || (shoes && (shoes.item_flags & ITEM_FLAG_NOSLIP))) + return 0 + return !!(..(slipped_on,stun_duration)) + +/mob/living/carbon/human/check_slipmove() + if(h_style) + var/datum/sprite_accessory/hair/S = GLOB.hair_styles_list[h_style] + if(S && S.flags & HAIR_TRIPPABLE && prob(0.4)) + slip(S, 4) + return TRUE + return FALSE + +/mob/living/carbon/human/proc/undislocate() + set category = "Object" + set name = "Undislocate Joint" + set desc = "Pop a joint back into place. Extremely painful." + set src in view(1) + + if(!isliving(usr) || !usr.canClick()) + return + + usr.setClickCooldown(20) + + if(usr.stat > 0) + to_chat(usr, "You are unconcious and cannot do that!") + return + + if(usr.restrained()) + to_chat(usr, "You are restrained and cannot do that!") + return + + var/mob/S = src + var/mob/U = usr + var/self = null + if(S == U) + self = 1 // Removing object from yourself. + + var/list/limbs = list() + for(var/limb in organs_by_name) + var/obj/item/organ/external/current_limb = organs_by_name[limb] + if(current_limb && current_limb.dislocated > 0 && !current_limb.is_parent_dislocated()) //if the parent is also dislocated you will have to relocate that first + limbs |= current_limb + var/obj/item/organ/external/current_limb = input(usr,"Which joint do you wish to relocate?") as null|anything in limbs + + if(!current_limb) + return + + if(self) + to_chat(src, "You brace yourself to relocate your [current_limb.joint]...") + else + to_chat(U, "You begin to relocate [S]'s [current_limb.joint]...") + if(!do_after(U, 30, src)) + return + if(!current_limb || !S || !U) + return + + if(self) + to_chat(src, "You pop your [current_limb.joint] back in!") + else + to_chat(U, "You pop [S]'s [current_limb.joint] back in!") + to_chat(S, "[U] pops your [current_limb.joint] back in!") + current_limb.undislocate() + +/mob/living/carbon/human/drop_from_inventory(var/obj/item/W, var/atom/Target = null) + if(W in organs) + return + . = ..() + +/mob/living/carbon/human/reset_view(atom/A, update_hud = 1) + ..() + if(update_hud) + handle_regular_hud_updates() + + +/mob/living/carbon/human/can_stand_overridden() + //FIXME, this was used for rigs acting as exoskeletal support. + //We could use it for something else maybe... + return 0 + +/mob/living/carbon/human/verb/pull_punches() + set name = "Pull Punches" + set desc = "Try not to hurt them." + set category = "IC" + + if(incapacitated() || species.species_flags & SPECIES_FLAG_CAN_NAB) return + pulling_punches = !pulling_punches + to_chat(src, "You are now [pulling_punches ? "pulling your punches" : "not pulling your punches"].") + return + +//generates realistic-ish pulse output based on preset levels +/mob/living/carbon/human/proc/get_pulse(var/method) //method 0 is for hands, 1 is for machines, more accurate + var/obj/item/organ/internal/heart/H = internal_organs_by_name[BP_HEART] + if(!H) + return + if(H.open && !method) + return "muddled and unclear; you can't seem to find a vein" + + var/temp = 0 + switch(pulse()) + if(PULSE_NONE) + return "0" + if(PULSE_SLOW) + temp = rand(40, 60) + if(PULSE_NORM) + temp = rand(60, 90) + if(PULSE_FAST) + temp = rand(90, 120) + if(PULSE_2FAST) + temp = rand(120, 160) + if(PULSE_THREADY) + return method ? ">250" : "extremely weak and fast, patient's artery feels like a thread" + return "[method ? temp : temp + rand(-10, 10)]" +// output for machines^ ^^^^^^^output for people^^^^^^^^^ + +/mob/living/carbon/human/proc/pulse() + var/obj/item/organ/internal/heart/H = internal_organs_by_name[BP_HEART] + if(!H) + return PULSE_NONE + if(stat == DEAD) + return PULSE_NONE + else + return H.pulse + +/mob/living/carbon/human/can_devour(atom/movable/victim) + if(!src.species.gluttonous) + return FALSE + var/total = 0 + for(var/a in stomach_contents + victim) + if(ismob(a)) + var/mob/M = a + total += M.mob_size + else if(isobj(a)) + var/obj/item/I = a + total += I.get_storage_cost() + if(total > src.species.stomach_capacity) + return FALSE + + if(iscarbon(victim) || isanimal(victim)) + var/mob/living/L = victim + if((src.species.gluttonous & GLUT_TINY) && (L.mob_size <= MOB_TINY) && !ishuman(victim)) // Anything MOB_TINY or smaller + return DEVOUR_SLOW + else if((src.species.gluttonous & GLUT_SMALLER) && (src.mob_size > L.mob_size)) // Anything we're larger than + return DEVOUR_SLOW + else if(src.species.gluttonous & GLUT_ANYTHING) // Eat anything ever + return DEVOUR_FAST + else if(istype(victim, /obj/item) && !istype(victim, /obj/item/weapon/holder)) //Don't eat holders. They are special. + var/obj/item/I = victim + var/cost = I.get_storage_cost() + if(cost != ITEM_SIZE_NO_CONTAINER) + if((src.species.gluttonous & GLUT_ITEM_TINY) && cost < 4) + return DEVOUR_SLOW + else if((src.species.gluttonous & GLUT_ITEM_NORMAL) && cost <= 4) + return DEVOUR_SLOW + else if(src.species.gluttonous & GLUT_ITEM_ANYTHING) + return DEVOUR_FAST + return ..() + +/mob/living/carbon/human/should_have_organ(var/organ_check) + + var/obj/item/organ/external/affecting + if(organ_check in list(BP_HEART, BP_LUNGS)) + affecting = organs_by_name[BP_CHEST] + else if(organ_check in list(BP_LIVER, BP_KIDNEYS)) + affecting = organs_by_name[BP_GROIN] + + if(affecting && (affecting.robotic >= ORGAN_ROBOT)) + return 0 + return (species && species.has_organ[organ_check]) + +/mob/living/carbon/human/can_feel_pain(var/obj/item/organ/check_organ) + if(isSynthetic()) + return FALSE + if(check_organ) + if(!istype(check_organ)) + return FALSE + return check_organ.can_feel_pain() + return !(species.species_flags & SPECIES_FLAG_NO_PAIN) + +/mob/living/carbon/human/get_breath_volume() + . = ..() + var/obj/item/organ/internal/heart/H = internal_organs_by_name[BP_HEART] + if(H) + . *= (H.robotic < ORGAN_ROBOT) ? pulse()/PULSE_NORM : 1.5 + +/mob/living/carbon/human/need_breathe() + if(species.breathing_organ && should_have_organ(species.breathing_organ)) + return 1 + else + return 0 + +/mob/living/carbon/human/get_adjusted_metabolism(metabolism) + return ..() * (species ? species.metabolism_mod : 1) + +/mob/living/carbon/human/is_invisible_to(var/mob/viewer) + return (is_cloaked() || ..()) + +/mob/living/carbon/human/help_shake_act(mob/living/carbon/M) + if(src != M) + ..() + else + exam_self() + + if((SKELETON in mutations) && (!w_uniform) && (!wear_suit)) + play_xylophone() + +/mob/living/carbon/human/proc/exam_self() + if(!stat) + visible_message("[src] examines [gender==MALE ? "himself" : "herself"].") + var/msg = "
            Let's see how I am doing.\n" + + if(!stat) + msg += "I am alive and conscious.\n" + if(stat == DEAD) + msg += "I am dead.\n" + else if(sleeping || stat == UNCONSCIOUS) + if(!is_asystole()) + msg += "I am unconscious, but still breathing.\n" + else + msg += "I am dying.\n" + msg += "I feel like I can carry [baseload]kg with ease\n" + if(overweight()) + msg += "[overweighttxt()]\n" + + for(var/obj/item/organ/external/org in organs) + var/list/status = list() + var/hurts = org.get_pain() + if(!org.can_feel_pain()) + hurts = 0 + if(!can_feel_pain()) + hurts = 0 + if((chem_effects[CE_PAINKILLER] < hurts)) + switch(hurts) + if(1 to 49) + status += "pain" + if(50 to 89) + status += "PAIN" + if(90 to INFINITY) + status += "PAIN" + if(org.robotic >= ORGAN_ROBOT) + switch(org.damage) + if(1 to 25) + status += "slightly damaged" + if(26 to 49) + status += "damaged" + if(50 to 99) + status += "VERY DAMAGED" + if(100 to INFINITY) + status += "BARELY WORKING" + + + + for(var/datum/wound/wound in org.wounds) + if(wound.embedded_objects.len) + status += "SHRAPNEL" + if(wound.bandaged) + status += "BANDAGED" + + if(org.is_stump()) + status += "MISSING" + if(org.status & ORGAN_MUTATED) + status += "MISSHAPEN" + if(org.status & ORGAN_BLEEDING) + status += "BLEEDING" + if(org.dislocated == 2) + status += "DISLOCATED" + if(org.status & ORGAN_BROKEN) + status += "BROKEN" + if(org.splinted) + status += "SPLINTED" + if(org.status & ORGAN_DEAD) + status += "NECROTIC" + if(org.is_dislocated()) //!org.is_usable() || + status += "UNUSABLE" + if(status.len) + msg += "[capitalize(org.name)]: [or_sign_list(status)]\n" + else + msg += "[capitalize(org.name)]: OK\n" + + to_chat(src, "[msg]
            ") + + +/mob/living/carbon/human/proc/resuscitate() + if(!is_asystole() || !should_have_organ(BP_HEART)) + return + var/obj/item/organ/internal/heart/heart = internal_organs_by_name[BP_HEART] + if(istype(heart) && heart.robotic <= ORGAN_ROBOT && !(heart.status & ORGAN_DEAD)) + var/species_organ = species.breathing_organ + var/active_breaths = 0 + if(species_organ) + var/obj/item/organ/internal/lungs/L = internal_organs_by_name[species_organ] + if(L) + active_breaths = L.active_breathing + if(!nervous_system_failure() && active_breaths) + visible_message("\The [src] jerks and gasps for breath!") + else + visible_message("\The [src] twitches a bit as \his heart restarts!") + shock_stage = min(shock_stage, 100) // 120 is the point at which the heart stops. + if(getOxyLoss() >= 75) + setOxyLoss(75) + heart.pulse = PULSE_NORM + heart.handle_pulse() + unlock_achievement(new/datum/achievement/revived()) + +/mob/living/carbon/human/proc/make_adrenaline(amount) + if(stat == CONSCIOUS) + var/limit = max(0, reagents.get_overdose(/datum/reagent/adrenaline) - reagents.get_reagent_amount(/datum/reagent/adrenaline)) + reagents.add_reagent(/datum/reagent/adrenaline, min(amount, limit)) + +//Get fluffy numbers +/mob/living/carbon/human/proc/get_blood_pressure() + if(status_flags & FAKEDEATH) + return "[Floor(120+rand(-5,5))*0.25]/[Floor(80+rand(-5,5)*0.25)]" + var/blood_result = get_blood_circulation() + return "[Floor((120+rand(-5,5))*(blood_result/100))]/[Floor((80+rand(-5,5))*(blood_result/100))]" + +//Point at which you dun breathe no more. Separate from asystole crit, which is heart-related. +/mob/living/carbon/human/proc/nervous_system_failure() + return getBrainLoss() >= maxHealth * 0.75 + + +/mob/living/carbon/proc/get_social_class() + var/socclass = social_class + if(!socclass) + return + switch(socclass) + if(SOCIAL_CLASS_MIN) + return "filth" + if(SOCIAL_CLASS_MED) + return "a commoner" + if(SOCIAL_CLASS_HIGH) + return "a noble" + if(SOCIAL_CLASS_MAX) + return "a greater noble" + + +/mob/living/carbon/human/proc/get_social_description(var/mob/living/carbon/human/H) + if(!ishuman(H)) + return + if(!social_class || !H.social_class) + return + if(social_class < H.social_class) + return "They are of a lesser social class than me." + else if(social_class > H.social_class) + return "They are of a higher social class than me." + else + return "They are of the same social class as me." + + +//RightClick procs! +/mob/living/carbon/human/RightClick(mob/living/user) + var/intent = user.a_intent + if(src == user) + return + + if(!user.Adjacent(src)) + var/obj/item/I = user.get_inactive_hand() + if(I) + if(user.atk_intent == I_DUAL && user.combat_mode) + if(istype(I, /obj/item/weapon/gun)) + I.afterattack(src, user) + return + /*//This doesn't want to work. + //Aiming a gun at someone. + var/obj/item/weapon/gun/G = user.get_active_hand() + if(G && istype(G)) + if(ismob(src) && user.aiming) + if(src == user.aiming.aiming_at)//If we're already aiming at them, then stop aiming. + user.aiming.cancel_aiming() + else + user.aiming.aim_at(src, G)//Else aim at them with the gun. + */ + + //else//Ok we have no gun do other dumb shit instead. + switch(intent) + if(I_HURT) + user.visible_message("[user] threatens [src] with a fist!") + return + if(I_HELP) + user.visible_message("[user] waves friendly to [src].") + return + + else if(lying && intent == I_HELP) + check_pulse() + return + + else if(!lying && !user.combat_mode && intent == I_HELP ) + give(src) + return + + else + ..() + +/atom/RightClick(mob/living/user) + var/obj/item/I = user.get_inactive_hand() + if(I) + if(user.atk_intent == I_DUAL && user.combat_mode) + if(istype(I, /obj/item/weapon/gun)) + I.afterattack(src, user) + + +/mob + var/zoomed = FALSE + +/mob/proc/do_zoom() + var/do_normal_zoom = TRUE + if(!zoomed) + if(lying) + return + var/obj/item/weapon/gun/projectile/heavysniper/S = get_active_hand() + if(istype(S)) + do_normal_zoom = FALSE + S.toggle_scope(src, 2) + set_face_dir(dir)//Face what we're zoomed in on. + + if(do_normal_zoom) + var/_x = 0 + var/_y = 0 + switch(dir) + if (NORTH) + _y = 7 + if (EAST) + _x = 7 + if (SOUTH) + _y = -7 + if (WEST) + _x = -7 + if(ishuman(src)) + var/mob/living/carbon/human/H = src + H.hide_cone() + if(get_preference_value(/datum/client_preference/smooth_zoom) == GLOB.PREF_YES) + animate(client, pixel_x = world.icon_size*_x, pixel_y = world.icon_size*_y, time = 2, easing = SINE_EASING) + else + client.pixel_x = world.icon_size*_x + client.pixel_y = world.icon_size*_y + + set_face_dir(dir)//Face what we're zoomed in on. + + zoomed = TRUE + + + else + var/obj/item/weapon/gun/projectile/heavysniper/S = get_active_hand() + if(istype(S)) + if(S.zoom)//Only do this if we're zoomed in please. + do_normal_zoom = FALSE + S.toggle_scope(src, 2) + set_face_dir(FALSE)//Reset us back to normal. + S = get_inactive_hand()//Then check if it's in our inactive hand instead. That way you can swap hands and still unzoom normally. + if(istype(S)) + if(S.zoom) + do_normal_zoom = FALSE + S.toggle_scope(src, 2) + set_face_dir(FALSE)//Reset us back to normal. + + if(do_normal_zoom) + if(ishuman(src)) + var/mob/living/carbon/human/H = src + if(get_preference_value(/datum/client_preference/smooth_zoom) == GLOB.PREF_YES) + animate(client, pixel_x = 0, pixel_y = 0, time = 2, easing = SINE_EASING) + spawn(1) + H.show_cone() + else + client.pixel_x = 0 + client.pixel_y = 0 + H.show_cone() + + + set_face_dir(FALSE)//Reset us back to normal. + zoomed = FALSE + +/atom/AltRightClick(var/mob/living/carbon/human/user) + ..() + if(!istype(user)) + return + if(user.lying) + return + if(user.crouching)//If you're crouching, pop up. + user.toggle_crouch() + + if(istype(user.loc, /turf/simulated/floor/trench))//We're in a trench. + if(user.zoomed) + user.do_zoom() + return + var/trench_check = 0 //We don't wanna be zooming unless we're up against a wall. + for(var/direction in GLOB.cardinal) + var/turf/turf_to_check = get_step(user.loc,direction)//So get all of the turfs around us. + if(istype(turf_to_check, /turf/simulated/floor/trench))//And if they're a trench, count it. + trench_check++ + if(trench_check >= 4)//But, if we're surrounded on all sides by trench, we cannot zoom in. + to_chat(user, "I'm too far away from the side to peer over.") + return //ez pz + + visible_message("[user] peers into the distance.") + user.face_atom(src) + user.do_zoom() + +/mob/living/carbon/human/melee_accuracy_mods() + . = ..() + for(var/obj/item/organ/external/org in organs) + var/hurts = org.get_pain() + if(!org.can_feel_pain()) + hurts = 0 + + if(hurts > 50) + . += 15 + if(!combat_mode) + . += 25 + +/mob/living/carbon/human/proc/has_low_circulation() + return (get_blood_circulation() <= 60) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm new file mode 100644 index 00000000..54c27f75 --- /dev/null +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -0,0 +1,434 @@ +/mob/living/carbon/human/proc/get_unarmed_attack(var/mob/living/carbon/human/target, var/hit_zone) + for(var/datum/unarmed_attack/u_attack in species.unarmed_attacks) + if(u_attack.is_usable(src, target, hit_zone)) + if(pulling_punches) + var/datum/unarmed_attack/soft_variant = u_attack.get_sparring_variant() + if(soft_variant) + return soft_variant + return u_attack + return null + +/mob/living/carbon/human/attack_hand(mob/living/carbon/M as mob) + + var/mob/living/carbon/human/H = M + if(istype(H)) + var/obj/item/organ/external/temp = H.organs_by_name[BP_R_HAND] + if(H.hand) + temp = H.organs_by_name[BP_L_HAND] + if(!temp || (!temp.is_usable() && !M.nabbing)) + to_chat(H, "You can't use your hand.") + return + + ..() + + // Should this all be in Touch()? + if(istype(H)) + if(H != src && check_shields(0, null, H, H.zone_sel.selecting, H.name)) + return 0 + + if(istype(H.gloves, /obj/item/clothing/gloves/boxing/hologlove)) + var/damage = rand(0, 9) + if(!damage) + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + visible_message("\The [H] has attempted to punch \the [src]!") + return 0 + var/obj/item/organ/external/affecting = get_organ(ran_zone(H.zone_sel.selecting)) + var/armor_block = run_armor_check(affecting, "melee") + + if(HULK in H.mutations) + damage += 5 + + playsound(loc, "punch", 40, 1, -1) + + visible_message("[H] has punched \the [src]!") + + apply_damage(damage, PAIN, affecting, armor_block) + if(damage >= 9) + visible_message("[H] has weakened \the [src]!") + apply_effect(4, WEAKEN, armor_block) + + return + + if(istype(M,/mob/living/carbon)) + M.spread_disease_to(src, "Contact") + + if(istype(H)) + for (var/obj/item/grab/G in H) + if (G.assailant == H && G.affecting == src) + if(G.resolve_openhand_attack()) + return 1 + + + switch(M.a_intent) + if(I_HELP) + if(istype(H) && (is_asystole() || (status_flags & FAKEDEATH))) + if (!cpr_time) + return 0 + if(H == src) + return 0 + + cpr_time = 0 + spawn(30) + cpr_time = 1 + + H.visible_message("\The [H] is trying to perform CPR on \the [src].") + + if(!do_after(H, 30, src)) + return + + H.visible_message("\The [H] performs CPR on \the [src]!") + //if(prob(5)) + // var/obj/item/organ/external/chest = get_organ(BP_CHEST) + // if(chest) + // chest.fracture() + if(stat != DEAD) + if(prob(15)) + resuscitate() + + if(src.reagents.has_reagent(/datum/reagent/atepoine))//If they got life savey stuff in there save their life right fucking now. + resuscitate() + + if(!H.check_has_mouth()) + to_chat(H, "You don't have a mouth, you cannot do mouth-to-mouth resustication!") + return + if(!check_has_mouth()) + to_chat(H, "They don't have a mouth, you cannot do mouth-to-mouth resustication!") + return + if((H.head && (H.head.body_parts_covered & FACE)) || (H.wear_mask && (H.wear_mask.body_parts_covered & FACE))) + to_chat(H, "You need to remove your mouth covering for mouth-to-mouth resustication!") + return 0 + if((head && (head.body_parts_covered & FACE)) || (wear_mask && (wear_mask.body_parts_covered & FACE))) + to_chat(H, "You need to remove \the [src]'s mouth covering for mouth-to-mouth resustication!") + return 0 + //if (!H.internal_organs_by_name[H.species.breathing_organ]) + // to_chat(H, "You need lungs for mouth-to-mouth resustication!") + // return + if(!need_breathe()) + return + var/obj/item/organ/internal/lungs/L = internal_organs_by_name[species.breathing_organ] + if(L) + var/datum/gas_mixture/breath = H.get_breath_from_environment() + var/fail = L.handle_breath(breath, 1) + if(!fail) + to_chat(src, "You feel a breath of fresh air enter your lungs. It feels good.") + + else if(!(M == src && apply_pressure(M, M.zone_sel.selecting))) + help_shake_act(M) + return 1 + + if(I_GRAB) + if(ticker.current_state == GAME_STATE_FINISHED) + to_chat(M, "The battle is over! There is no need to fight!") + return + //All this shit is for surgery + /* + if(istype(H)) + for(var/obj/item/weapon/storage/organ_sack/sack in contents) + qdel(sack)//If there's a sack there delete it + var/obj/item/organ/external/affecting = get_organ(H.zone_sel.selecting)//Check if we're targeting an organ we can operate one + if(can_operate(src, H)) + if(!isnull(affecting) && affecting.open()) + var/has_organs = null + var/obj/item/weapon/storage/organ_sack/sack = new(src)////Make a new sack + if(!has_organs) + for(var/obj/item/organ/internal/I in affecting.internal_organs)//Loop through the organs if we haven't already + to_chat(H, "This is firing1") + if(I && istype(I)) + var/obj/item/facade/organ/O = new(src)//Create facade organ + O.assign_attributes(I)//Copy the attributes + sack.handle_item_insertion(O, 1)//Stick it in the sack + + if(sack.contents.len)//Oh sweet stuff is in the sack + to_chat(H, "This is firing2") + sack.storage_slots = sack.contents.len + sack.open(H)//Show it to the surgery dude + return + */ + //Back to your normal insane + visible_message("[M] attempted to grab \the [src]!") + if(attempt_dodge()) + return + + if(istype(H)) + + var/obj/item/organ/external/affecting = get_organ(H.zone_sel.selecting) + if(!affecting || affecting.is_stump()) + to_chat(H, "There is nothing to grab!") + return + + switch(H.zone_sel.selecting) + //Strangling + if(BP_THROAT) + return H.make_grab(H, src, GRAB_STRANGLE) + + //Wrenching + if(BP_L_LEG) + return H.make_grab(H, src, GRAB_WRENCH) + if(BP_R_LEG) + return H.make_grab(H, src, GRAB_WRENCH) + if(BP_L_HAND) + return H.make_grab(H, src, GRAB_WRENCH) + if(BP_R_HAND) + return H.make_grab(H, src, GRAB_WRENCH) + if(BP_HEAD) + return H.make_grab(H, src, GRAB_WRENCH) + if(BP_R_FOOT) + return H.make_grab(H, src, GRAB_WRENCH) + if(BP_L_FOOT) + return H.make_grab(H, src, GRAB_WRENCH) + if(BP_L_ARM) + return H.make_grab(H, src, GRAB_WRENCH) + if(BP_R_ARM) + return H.make_grab(H, src, GRAB_WRENCH) + + //Tackling? + if(BP_CHEST) + return H.make_grab(H, src, GRAB_TAKEDOWN) + if(BP_GROIN) + return H.make_grab(H, src, GRAB_TAKEDOWN) + + + + return H.make_grab(H, src) + + if(I_HURT) + if(ticker.current_state == GAME_STATE_FINISHED) + to_chat(M, "The battle is over! There is no need to fight!") + return + if(H.warfare_faction) + if(H.warfare_faction == src.warfare_faction && src.stat != DEAD) + to_chat(H, "[src] is on my side!") + log_and_message_admins("[H] has punched his teammate [src]!", H) + GLOB.ff_incidents++ + M.adjustStaminaLoss(rand(5,15)) + + aggro_npc() + + if(attempt_dodge()) + return + + if(!istype(H)) + attack_generic(H,rand(1,3),"punched") + return + + var/rand_damage = rand(1, 5) + var/block = 0 + var/accurate = 0 + var/hit_zone = H.zone_sel.selecting + var/obj/item/organ/external/affecting = get_organ(hit_zone) + + // See what attack they use + var/datum/unarmed_attack/attack = H.get_unarmed_attack(src, hit_zone) + if(!attack) + return 0 + if(world.time < H.last_attack + attack.delay) + to_chat(H, "You can't attack again so soon.") + return 0 + else + H.last_attack = world.time + + if(!affecting || affecting.is_stump()) + to_chat(M, "They are missing that limb!") + return 1 + + switch(src.a_intent) + if(I_HELP) + // We didn't see this coming, so we get the full blow + rand_damage = 5 + accurate = 1 + if(I_HURT, I_GRAB) + // We're in a fighting stance, there's a chance we block + if(src.canmove && src!=H && prob(20)) + block = 1 + + if (M.grabbed_by.len) + // Someone got a good grip on them, they won't be able to do much damage + rand_damage = max(1, rand_damage - 2) + + if(src.grabbed_by.len || src.buckled || !src.canmove || src==H || H.species.species_flags & SPECIES_FLAG_NO_BLOCK) + accurate = 1 // certain circumstances make it impossible for us to evade punches + rand_damage = 3 + + // Process evasion and blocking + var/miss_type = 0 + var/attack_message + if(!accurate) + /* ~Hubblenaut + This place is kind of convoluted and will need some explaining. + ran_zone() will pick out of 11 zones, thus the chance for hitting + our target where we want to hit them is circa 9.1%. + + Now since we want to statistically hit our target organ a bit more + often than other organs, we add a base chance of 20% for hitting it. + + This leaves us with the following chances: + + If aiming for chest: + 27.3% chance you hit your target organ + 70.5% chance you hit a random other organ + 2.2% chance you miss + + If aiming for something else: + 23.2% chance you hit your target organ + 56.8% chance you hit a random other organ + 15.0% chance you miss + + Note: We don't use get_zone_with_miss_chance() here since the chances + were made for projectiles. + TODO: proc for melee combat miss chances depending on organ? + */ + if(prob(80)) + hit_zone = ran_zone(hit_zone) + if(H.statscheck(skills = H.my_skills[SKILL(melee)].level) == FAILURE) // Missed! + if(!src.lying) + if(H.statscheck(skills = H.my_skills[SKILL(melee)].level) == CRIT_FAILURE) + H.resolve_critical_miss_unarmed() + attack_message = null + else + attack_message = "[H] attempted to strike [src], but missed!" + else + attack_message = "[H] attempted to strike [src], but \he rolled out of the way!" + src.set_dir(pick(GLOB.cardinal)) + miss_type = 1 + + var/hitcheck = rand(0, 9) + if(!istype(src, /mob/living/carbon/human/machine) && istype(affecting, /obj/item/organ/external/head) && prob(hitcheck * (hit_zone == BP_MOUTH ? 5 : 1))) //MUCH higher chance to knock out teeth if you aim for mouth + var/obj/item/organ/external/head/U = affecting + if(U.knock_out_teeth(get_dir(H, src), round(rand(28, 38) * ((hitcheck*2)/100)))) + src.visible_message("[src]'s teeth sail off in an arc!", \ + "[src]'s teeth sail off in an arc!") + + if(!miss_type && block) + attack_message = "[H] went for [src]'s [affecting.name] but was blocked!" + miss_type = 2 + + //H.do_attack_animation(src) + if(!attack_message) + attack.show_attack(H, src, hit_zone, rand_damage) + else + H.visible_message("[attack_message]") + + playsound(loc, ((miss_type) ? (miss_type == 1 ? attack.miss_sound : 'sound/weapons/thudswoosh.ogg') : attack.attack_sound), 25, 1, -1) + admin_attack_log(H, src, "[miss_type ? (miss_type == 1 ? "Has missed" : "Was blocked by") : "Has [pick(attack.attack_verb)]"] their victim.", "[miss_type ? (miss_type == 1 ? "Missed" : "Blocked") : "[pick(attack.attack_verb)]"] their attacker", "[miss_type ? (miss_type == 1 ? "has missed" : "was blocked by") : "has [pick(attack.attack_verb)]"]") + + if(miss_type) + return 0 + + var/real_damage = rand_damage + real_damage += attack.get_unarmed_damage(H) + real_damage *= damage_multiplier + rand_damage *= damage_multiplier + if(HULK in H.mutations) + real_damage *= 2 // Hulks do twice the damage + rand_damage *= 2 + real_damage = (max(1, real_damage) * strToDamageModifier(H.my_stats[STAT(str)].level)) + + var/armour = run_armor_check(hit_zone, "melee") + // Apply additional unarmed effects. + attack.apply_effects(H, src, armour, rand_damage, hit_zone) + + // Nerf attacks done while lying by 1/3rd + if (H.lying) + real_damage = max(real_damage * 0.66, 1) + + // Finally, apply damage to target + apply_damage(real_damage, (attack.deal_halloss ? PAIN : BRUTE), hit_zone, armour, damage_flags=attack.damage_flags()) + receive_damage() + + if(I_DISARM) + M.adjustStaminaLoss(rand(2,5))//No more spamming disarm without consequence! + if(attempt_dodge()) + return + if(H.species) + admin_attack_log(M, src, "Disarmed their victim.", "Was disarmed.", "disarmed") + H.species.disarm_attackhand(H, src) + + return + +/mob/living/carbon/human/proc/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, inrange, params) + return + +/mob/living/carbon/human/attack_generic(var/mob/user, var/damage, var/attack_message, var/damtype = BRUTE, var/armorcheck = "melee",) + //I DID ALL THIS SO THAT HUMANS COULD DODGE AND PARRY ATTACKS FROM SIMPLE ANIMALS! FUCK YOU BAY! + var/dam_zone = pick(organs_by_name) + var/target_zone = ran_zone(dam_zone) + var/obj/item/organ/external/affecting = get_organ(target_zone)//(ran_zone(dam_zone)) + var/armor_block = run_armor_check(affecting, armorcheck) + + if(!damage || !istype(user)) + return + if(!affecting) + return + if(attempt_dodge()) + return + if(check_shields(damage, user, user, target_zone, "the attack")) + return + + admin_attack_log(user, src, "Attacked their victim", "Was attacked", "has [attack_message]") + src.visible_message("[user] has [attack_message] [src]!") + + + apply_damage(damage, damtype, affecting, armor_block) + receive_damage() + updatehealth() + return 1 + +//Breaks all grips and pulls that the mob currently has. +/mob/living/carbon/human/proc/break_all_grabs(mob/living/carbon/user) + var/success = 0 + if(pulling) + visible_message("[user] has broken [src]'s grip on [pulling]!") + success = 1 + stop_pulling() + + if(istype(l_hand, /obj/item/grab)) + var/obj/item/grab/lgrab = l_hand + if(lgrab.affecting) + visible_message("[user] has broken [src]'s grip on [lgrab.affecting]!") + success = 1 + spawn(1) + qdel(lgrab) + if(istype(r_hand, /obj/item/grab)) + var/obj/item/grab/rgrab = r_hand + if(rgrab.affecting) + visible_message("[user] has broken [src]'s grip on [rgrab.affecting]!") + success = 1 + spawn(1) + qdel(rgrab) + return success +/* + We want to ensure that a mob may only apply pressure to one organ of one mob at any given time. Currently this is done mostly implicitly through + the behaviour of do_after() and the fact that applying pressure to someone else requires a grab: + + If you are applying pressure to yourself and attempt to grab someone else, you'll change what you are holding in your active hand which will stop do_mob() + If you are applying pressure to another and attempt to apply pressure to yourself, you'll have to switch to an empty hand which will also stop do_mob() + Changing targeted zones should also stop do_mob(), preventing you from applying pressure to more than one body part at once. +*/ +/mob/living/carbon/human/proc/apply_pressure(mob/living/user, var/target_zone) + var/obj/item/organ/external/organ = get_organ(target_zone) + if(!organ || !(organ.status & ORGAN_BLEEDING) || (organ.robotic >= ORGAN_ROBOT)) + return 0 + + if(organ.applied_pressure) + var/message = "[ismob(organ.applied_pressure)? "Someone" : "\A [organ.applied_pressure]"] is already applying pressure to [user == src? "your [organ.name]" : "[src]'s [organ.name]"]." + to_chat(user, message) + return 0 + + if(user == src) + user.visible_message("\The [user] starts applying pressure to \his [organ.name]!", "You start applying pressure to your [organ.name]!") + else + user.visible_message("\The [user] starts applying pressure to [src]'s [organ.name]!", "You start applying pressure to [src]'s [organ.name]!") + spawn(0) + organ.applied_pressure = user + + //apply pressure as long as they stay still and keep grabbing + do_mob(user, src, INFINITY, target_zone, progress = 0) + + organ.applied_pressure = null + + if(user == src) + user.visible_message("\The [user] stops applying pressure to \his [organ.name]!", "You stop applying pressure to your [organ.name]!") + else + user.visible_message("\The [user] stops applying pressure to [src]'s [organ.name]!", "You stop applying pressure to [src]'s [organ.name]!") + + return 1 diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm new file mode 100644 index 00000000..49e99556 --- /dev/null +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -0,0 +1,422 @@ +//Updates the mob's health from organs and mob damage variables +/mob/living/carbon/human/updatehealth() + + if(status_flags & GODMODE) + health = maxHealth + set_stat(CONSCIOUS) + return + + health = maxHealth - getBrainLoss() + + //TODO: fix husking + if(((maxHealth - getFireLoss()) < config.health_threshold_dead) && stat == DEAD) + ChangeToHusk() + return + +/mob/living/carbon/human/adjustBrainLoss(var/amount) + if(status_flags & GODMODE) return 0 //godmode + if(should_have_organ(BP_BRAIN)) + var/obj/item/organ/internal/brain/sponge = internal_organs_by_name[BP_BRAIN] + if(sponge) + sponge.take_damage(amount) + +/mob/living/carbon/human/setBrainLoss(var/amount) + if(status_flags & GODMODE) return 0 //godmode + if(should_have_organ(BP_BRAIN)) + var/obj/item/organ/internal/brain/sponge = internal_organs_by_name[BP_BRAIN] + if(sponge) + sponge.damage = min(max(amount, 0),sponge.species.total_health) + updatehealth() + +/mob/living/carbon/human/getBrainLoss() + if(status_flags & GODMODE) return 0 //godmode + if(should_have_organ(BP_BRAIN)) + var/obj/item/organ/internal/brain/sponge = internal_organs_by_name[BP_BRAIN] + if(sponge) + if(sponge.status & ORGAN_DEAD) + return sponge.species.total_health + else + return sponge.damage + else + return species.total_health + return 0 + +//Straight pain values, not affected by painkillers etc +/mob/living/carbon/human/getHalLoss() + var/amount = 0 + for(var/obj/item/organ/external/E in organs) + amount += E.get_pain() + return amount + +/mob/living/carbon/human/setHalLoss(var/amount) + adjustHalLoss(getHalLoss()-amount) + +/mob/living/carbon/human/adjustHalLoss(var/amount) + var/heal = (amount < 0) + amount = abs(amount) + var/list/pick_organs = organs.Copy() + while(amount > 0 && pick_organs.len) + var/obj/item/organ/external/E = pick(pick_organs) + pick_organs -= E + if(!istype(E)) + continue + + if(heal) + amount -= E.remove_pain(amount) + else + amount -= E.add_pain(amount) + BITSET(hud_updateflag, HEALTH_HUD) + +//These procs fetch a cumulative total damage from all organs +/mob/living/carbon/human/getBruteLoss() + var/amount = 0 + for(var/obj/item/organ/external/O in organs) + if((O.robotic >= ORGAN_ROBOT) && !O.vital) + continue //robot limbs don't count towards shock and crit + amount += O.brute_dam + return amount + +/mob/living/carbon/human/getFireLoss() + var/amount = 0 + for(var/obj/item/organ/external/O in organs) + if((O.robotic >= ORGAN_ROBOT) && !O.vital) + continue //robot limbs don't count towards shock and crit + amount += O.burn_dam + return amount + +/mob/living/carbon/human/adjustBruteLoss(var/amount) + amount = amount*species.brute_mod + if(amount > 0) + take_overall_damage(amount, 0) + else + heal_overall_damage(-amount, 0) + BITSET(hud_updateflag, HEALTH_HUD) + +/mob/living/carbon/human/adjustFireLoss(var/amount) + amount = amount*species.burn_mod + if(amount > 0) + take_overall_damage(0, amount) + else + heal_overall_damage(0, -amount) + BITSET(hud_updateflag, HEALTH_HUD) + +/mob/living/carbon/human/Stun(amount) + if(HULK in mutations) return + ..() + +/mob/living/carbon/human/Weaken(amount) + if(HULK in mutations) return + ..() + +/mob/living/carbon/human/Paralyse(amount) + if(HULK in mutations) return + ..() + +/mob/living/carbon/human/getCloneLoss() + var/amount = 0 + for(var/obj/item/organ/external/E in organs) + amount += E.get_genetic_damage() + return amount + +/mob/living/carbon/human/setCloneLoss(var/amount) + adjustCloneLoss(getCloneLoss()-amount) + +/mob/living/carbon/human/adjustCloneLoss(var/amount) + var/heal = amount < 0 + amount = abs(amount) + + var/list/pick_organs = organs.Copy() + while(amount > 0 && pick_organs.len) + var/obj/item/organ/external/E = pick(pick_organs) + pick_organs -= E + if(heal) + amount -= E.remove_genetic_damage(amount) + else + amount -= E.add_genetic_damage(amount) + BITSET(hud_updateflag, HEALTH_HUD) + +// Defined here solely to take species flags into account without having to recast at mob/living level. +/mob/living/carbon/human/getOxyLoss() + if(!need_breathe()) + return 0 + else + var/obj/item/organ/internal/lungs/breathe_organ = internal_organs_by_name[species.breathing_organ] + if(!breathe_organ) + return maxHealth/2 + return breathe_organ.get_oxygen_deprivation() + +/mob/living/carbon/human/setOxyLoss(var/amount) + if(!need_breathe()) + return 0 + else + adjustOxyLoss(getOxyLoss()-amount) + +/mob/living/carbon/human/adjustOxyLoss(var/amount) + if(!need_breathe()) + return + var/heal = amount < 0 + amount = abs(amount*species.oxy_mod) + var/obj/item/organ/internal/lungs/breathe_organ = internal_organs_by_name[species.breathing_organ] + if(breathe_organ) + if(heal) + breathe_organ.remove_oxygen_deprivation(amount) + else + breathe_organ.add_oxygen_deprivation(amount) + BITSET(hud_updateflag, HEALTH_HUD) + +/mob/living/carbon/human/getToxLoss() + if((species.species_flags & SPECIES_FLAG_NO_POISON) || isSynthetic()) + return 0 + var/amount = 0 + for(var/obj/item/organ/internal/I in internal_organs) + amount += I.getToxLoss() + return amount + +/mob/living/carbon/human/setToxLoss(var/amount) + if(!(species.species_flags & SPECIES_FLAG_NO_POISON) && !isSynthetic()) + adjustToxLoss(getToxLoss()-amount) + +// TODO: better internal organ damage procs. +/mob/living/carbon/human/adjustToxLoss(var/amount) + + if((species.species_flags & SPECIES_FLAG_NO_POISON) || isSynthetic()) + return + + var/heal = amount < 0 + amount = abs(amount) + + if(!heal && (CE_ANTITOX in chem_effects)) + amount *= 1 - (chem_effects[CE_ANTITOX] * 0.25) + + var/list/pick_organs = shuffle(internal_organs.Copy()) + + // Prioritize damaging our filtration organs first. + var/obj/item/organ/internal/kidneys/kidneys = internal_organs_by_name[BP_KIDNEYS] + if(kidneys) + pick_organs -= kidneys + pick_organs.Insert(1, kidneys) + var/obj/item/organ/internal/liver/liver = internal_organs_by_name[BP_LIVER] + if(liver) + pick_organs -= liver + pick_organs.Insert(1, liver) + + // Move the brain to the very end since damage to it is vastly more dangerous + // (and isn't technically counted as toxloss) than general organ damage. + var/obj/item/organ/internal/brain/brain = internal_organs_by_name[BP_BRAIN] + if(brain) + pick_organs -= brain + pick_organs += brain + + for(var/obj/item/organ/internal/I in pick_organs) + if(amount <= 0) + break + if(heal) + if(I.damage < amount) + amount -= I.damage + I.damage = 0 + else + I.damage -= amount + amount = 0 + else + var/cap_dam = I.max_damage - I.damage + if(amount >= cap_dam) + I.take_damage(cap_dam, silent=TRUE) + amount -= cap_dam + else + I.take_damage(amount, silent=TRUE) + amount = 0 + +/mob/living/carbon/human/proc/can_autoheal(var/dam_type) + if(!species || !dam_type) return FALSE + + if(dam_type == BRUTE) + return(getBruteLoss() < species.total_health / 2) + else if(dam_type == BURN) + return(getFireLoss() < species.total_health / 2) + return FALSE + +//////////////////////////////////////////// + +//Returns a list of damaged organs +/mob/living/carbon/human/proc/get_damaged_organs(var/brute, var/burn) + var/list/obj/item/organ/external/parts = list() + for(var/obj/item/organ/external/O in organs) + if((brute && O.brute_dam) || (burn && O.burn_dam)) + parts += O + return parts + +//Returns a list of damageable organs +/mob/living/carbon/human/proc/get_damageable_organs() + var/list/obj/item/organ/external/parts = list() + for(var/obj/item/organ/external/O in organs) + if(O.is_damageable()) + parts += O + return parts + +//Heals ONE external organ, organ gets randomly selected from damaged ones. +//It automatically updates damage overlays if necesary +//It automatically updates health status +/mob/living/carbon/human/heal_organ_damage(var/brute, var/burn) + var/list/obj/item/organ/external/parts = get_damaged_organs(brute,burn) + if(!parts.len) return + var/obj/item/organ/external/picked = pick(parts) + if(picked.heal_damage(brute,burn)) + BITSET(hud_updateflag, HEALTH_HUD) + updatehealth() + + +//TODO reorganize damage procs so that there is a clean API for damaging living mobs + +/* +In most cases it makes more sense to use apply_damage() instead! And make sure to check armour if applicable. +*/ +//Damages ONE external organ, organ gets randomly selected from damagable ones. +//It automatically updates damage overlays if necesary +//It automatically updates health status +/mob/living/carbon/human/take_organ_damage(var/brute, var/burn, var/sharp = 0, var/edge = 0) + var/list/obj/item/organ/external/parts = get_damageable_organs() + if(!parts.len) + return + + var/obj/item/organ/external/picked = pick(parts) + var/damage_flags = (sharp? DAM_SHARP : 0)|(edge? DAM_EDGE : 0) + + if(picked.take_damage(brute, burn, damage_flags)) + BITSET(hud_updateflag, HEALTH_HUD) + + updatehealth() + + +//Heal MANY external organs, in random order +/mob/living/carbon/human/heal_overall_damage(var/brute, var/burn) + var/list/obj/item/organ/external/parts = get_damaged_organs(brute,burn) + + while(parts.len && (brute>0 || burn>0) ) + var/obj/item/organ/external/picked = pick(parts) + + var/brute_was = picked.brute_dam + var/burn_was = picked.burn_dam + + picked.heal_damage(brute,burn) + + brute -= (brute_was-picked.brute_dam) + burn -= (burn_was-picked.burn_dam) + + parts -= picked + updatehealth() + BITSET(hud_updateflag, HEALTH_HUD) + +// damage MANY external organs, in random order +/mob/living/carbon/human/take_overall_damage(var/brute, var/burn, var/sharp = 0, var/edge = 0, var/used_weapon = null) + if(status_flags & GODMODE) return //godmode + var/list/obj/item/organ/external/parts = get_damageable_organs() + if(!parts.len) return + + var/dam_flags = (sharp? DAM_SHARP : 0)|(edge? DAM_EDGE : 0) + var/brute_avg = brute / parts.len + var/burn_avg = burn / parts.len + for(var/obj/item/organ/external/E in parts) + if(brute_avg) + apply_damage(damage = brute_avg, damagetype = BRUTE, blocked = getarmor_organ(E, "melee"), damage_flags = dam_flags, used_weapon = used_weapon, given_organ = E) + if(burn_avg) + apply_damage(damage = burn_avg, damagetype = BURN, damage_flags = dam_flags, used_weapon = used_weapon, given_organ = E) + + updatehealth() + BITSET(hud_updateflag, HEALTH_HUD) + + +//////////////////////////////////////////// + +/* +This function restores the subjects blood to max. +*/ +/mob/living/carbon/human/proc/restore_blood() + if(!should_have_organ(BP_HEART)) + return + if(vessel.total_volume < species.blood_volume) + vessel.add_reagent(/datum/reagent/blood, species.blood_volume - vessel.total_volume) + +/* +This function restores all organs. +*/ +/mob/living/carbon/human/restore_all_organs(var/ignore_prosthetic_prefs) + for(var/bodypart in BP_BY_DEPTH) + var/obj/item/organ/external/current_organ = organs_by_name[bodypart] + if(istype(current_organ)) + current_organ.rejuvenate(ignore_prosthetic_prefs) + +/mob/living/carbon/human/proc/HealDamage(zone, brute, burn) + var/obj/item/organ/external/E = get_organ(zone) + if(istype(E, /obj/item/organ/external)) + if (E.heal_damage(brute, burn)) + BITSET(hud_updateflag, HEALTH_HUD) + else + return 0 + return + + +/mob/living/carbon/human/proc/get_organ(var/zone) + return organs_by_name[check_zone(zone)] + +/mob/living/carbon/human/apply_damage(var/damage = 0, var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/damage_flags = 0, var/obj/used_weapon = null, var/obj/item/organ/external/given_organ = null) + //visible_message("Hit debug. damage: [damage] | damagetype: [damagetype] | def_zone: [def_zone] | blocked: [blocked] | used_weapon: [used_weapon] | organ hit: [given_organ]") + var/obj/item/organ/external/organ = given_organ + if(!organ) + if(isorgan(def_zone)) + organ = def_zone + else + if(!def_zone) def_zone = ran_zone(def_zone) + organ = get_organ(check_zone(def_zone)) + + //Handle other types of damage + if(!(damagetype in list(BRUTE, BURN, PAIN, CLONE))) + ..(damage, damagetype, def_zone, blocked) + return 1 + + handle_suit_punctures(damagetype, damage, def_zone) + + if(blocked >= 100) return 0 + + if(!organ) return 0 + + if(blocked) + damage *= blocked_mult(blocked) + + if(damage > 15 && prob(damage*4)) + make_adrenaline(round(damage/10)) + var/datum/wound/created_wound + damageoverlaytemp = 20 + switch(damagetype) + if(BRUTE) + damage = damage*species.brute_mod + created_wound = organ.take_damage(damage, 0, damage_flags, used_weapon) + if(BURN) + damage = damage*species.burn_mod + created_wound = organ.take_damage(0, damage, damage_flags, used_weapon) + if(PAIN) + organ.add_pain(damage) + if(CLONE) + organ.add_genetic_damage(damage) + + // Will set our damageoverlay icon to the next level, which will then be set back to the normal level the next mob.Life(). + updatehealth() + BITSET(hud_updateflag, HEALTH_HUD) + return created_wound + +// Find out in how much pain the mob is at the moment. +/mob/living/carbon/human/proc/get_shock() + + if (!can_feel_pain()) + return 0 + + var/traumatic_shock = getHalLoss() // Pain. + traumatic_shock -= chem_effects[CE_PAINKILLER] // TODO: check what is actually stored here. + + if(stat == UNCONSCIOUS) + traumatic_shock *= 0.6 + return max(0,traumatic_shock) + +/mob/living/carbon/human/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0) + if(effecttype == IRRADIATE && (effect * blocked_mult(blocked) <= RAD_LEVEL_LOW)) + return 0 + return ..() diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm new file mode 100644 index 00000000..4d3b7695 --- /dev/null +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -0,0 +1,718 @@ +/* +Contains most of the procs that are called when a mob is attacked by something + +bullet_act +ex_act +meteor_act + +*/ + +/obj/item/proc/get_attack_name() + if(sharp && edge) + return "slices" + else if(sharp && !edge) + return "stabs" + else + return "hits" + +/mob/living/carbon/human/bullet_act(var/obj/item/projectile/P, var/def_zone) + def_zone = check_zone(def_zone) + if(!has_organ(def_zone)) + return PROJECTILE_FORCE_MISS //if they don't have the organ in question then the projectile just passes by. + //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, 100, def_zone) + return 100 + + var/obj/item/organ/external/organ = get_organ(def_zone) + var/armor = getarmor_organ(organ, P.check_armour) + var/penetrating_damage = ((P.damage + P.armor_penetration) * P.penetration_modifier) - armor + + //Organ damage + if(organ.internal_organs.len && prob(35 + max(penetrating_damage, -12.5))) + var/damage_amt = min((P.damage * P.penetration_modifier), penetrating_damage) //So we don't factor in armor_penetration as additional damage + if(damage_amt > 0) + // Damage an internal organ + var/list/victims = list() + var/list/possible_victims = shuffle(organ.internal_organs.Copy()) + for(var/obj/item/organ/internal/I in possible_victims) + if(I.damage < I.max_damage && (prob((I.relative_size) * (1 / max(1, victims.len))))) + victims += I + if(victims.len) + for(var/obj/item/organ/victim in victims) + damage_amt /= 2 + victim.take_damage(damage_amt) + + + //Embed or sever artery + if(P.can_embed() && !(species.species_flags & SPECIES_FLAG_NO_EMBED) && prob(22.5 + max(penetrating_damage, -10)) && !(prob(50) && (organ.sever_artery()))) + var/obj/item/weapon/material/shard/shrapnel/SP = new() + SP.SetName((P.name != "shrapnel")? "[P.name] shrapnel" : "shrapnel") + SP.desc = "[SP.desc] It looks like it was fired from [P.shot_from]." + SP.loc = organ + organ.embed(SP) + + var/blocked = ..(P, def_zone) + + projectile_hit_bloody(P, P.damage*blocked_mult(blocked), def_zone) + + return blocked + +/mob/living/carbon/human/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone) + var/obj/item/organ/external/affected = get_organ(check_zone(def_zone)) + if(!affected) + return + + var/siemens_coeff = get_siemens_coefficient_organ(affected) + stun_amount *= siemens_coeff + agony_amount *= siemens_coeff + agony_amount *= affected.get_agony_multiplier() + + affected.stun_act(stun_amount, agony_amount) + + ..(stun_amount, agony_amount, def_zone) + +/mob/living/carbon/human/getarmor(var/def_zone, var/type) + var/armorval = 0 + var/total = 0 + + if(def_zone) + if(isorgan(def_zone)) + return getarmor_organ(def_zone, type) + var/obj/item/organ/external/affecting = get_organ(def_zone) + if(affecting) + return getarmor_organ(affecting, type) + //If a specific bodypart is targetted, check how that bodypart is protected and return the value. + + //If you don't specify a bodypart, it checks ALL your bodyparts for protection, and averages out the values + for(var/organ_name in organs_by_name) + if (organ_name in organ_rel_size) + var/obj/item/organ/external/organ = organs_by_name[organ_name] + if(organ) + var/weight = organ_rel_size[organ_name] + armorval += (getarmor_organ(organ, type) * weight) //use plain addition here because we are calculating an average + total += weight + return (armorval/max(total, 1)) + +//this proc returns the Siemens coefficient of electrical resistivity for a particular external organ. +/mob/living/carbon/human/proc/get_siemens_coefficient_organ(var/obj/item/organ/external/def_zone) + if (!def_zone) + return 1.0 + + var/siemens_coefficient = max(species.siemens_coefficient,0) + + var/list/clothing_items = list(head, wear_mask, wear_suit, w_uniform, gloves, shoes) // What all are we checking? + for(var/obj/item/clothing/C in clothing_items) + if(istype(C) && (C.body_parts_covered & def_zone.body_part)) // Is that body part being targeted covered? + siemens_coefficient *= C.siemens_coefficient + + return siemens_coefficient + +//this proc returns the armour value for a particular external organ. +/mob/living/carbon/human/proc/getarmor_organ(var/obj/item/organ/external/def_zone, var/type) + if(!type || !def_zone) return 0 + if(!istype(def_zone)) + def_zone = get_organ(check_zone(def_zone)) + if(!def_zone) + return 0 + var/protection = 0 + var/list/protective_gear = list(head, wear_mask, wear_suit, w_uniform, gloves, shoes) + for(var/obj/item/clothing/gear in protective_gear) + if(gear.body_parts_covered & def_zone.body_part) + protection = add_armor(protection, gear.armor[type]) + if(gear.accessories.len) + for(var/obj/item/clothing/accessory/bling in gear.accessories) + if(bling.body_parts_covered & def_zone.body_part) + protection = add_armor(protection, bling.armor[type]) + return protection + +/mob/living/carbon/human/proc/check_head_coverage() + + var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform) + for(var/bp in body_parts) + if(!bp) continue + if(bp && istype(bp ,/obj/item/clothing)) + var/obj/item/clothing/C = bp + if(C.body_parts_covered & HEAD) + return 1 + return 0 + +//Used to check if they can be fed food/drinks/pills +/mob/living/carbon/human/check_mouth_coverage() + var/list/protective_gear = list(head, wear_mask, wear_suit, w_uniform) + for(var/obj/item/gear in protective_gear) + if(istype(gear) && (gear.body_parts_covered & FACE) && !(gear.item_flags & ITEM_FLAG_FLEXIBLEMATERIAL)) + return gear + return null + +/mob/living/carbon/human/proc/check_shields(var/damage = 0, var/atom/damage_source = null, var/mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + for(var/obj/item/shield in list(l_hand, r_hand, wear_suit)) + if(!shield) continue + . = shield.handle_shield(src, damage, damage_source, attacker, def_zone, attack_text) + if(.) return + return 0 + +/mob/living/carbon/human/resolve_item_attack(obj/item/I, mob/living/carbon/human/user, var/target_zone, var/special = FALSE) + for (var/obj/item/grab/G in grabbed_by) + if(G.resolve_item_attack(user, I, target_zone)) + return null + + if(user == src) // Attacking yourself can't miss + return target_zone + + var/accuracy_penalty = user.melee_accuracy_mods() + + if(special) + if(user.atk_intent == I_DUAL) + accuracy_penalty += 25 + + var/hit_zone = get_zone_with_miss_chance(target_zone, src, accuracy_penalty) + + if(special) + switch(user.atk_intent) + if(I_AIMED)//More accurate attack + hit_zone = target_zone + + if(attempt_dodge()) + return null + + 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.is_stump()) + to_chat(user, "They are missing that limb!") + return null + + if(user.statscheck(skills = user.SKILL_LEVEL(melee)) == CRIT_FAILURE || (prob(25) && is_hellbanned())) + user.resolve_critical_miss(I) + return null + + 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].") + + + if(blocked == 100) + visible_message("[user] [I.get_attack_name()] [src]'s [affecting.name] with the [I], but it does no damage!") + return null + + if(hit_zone == BP_CHEST || hit_zone == BP_MOUTH || hit_zone == BP_THROAT || hit_zone == BP_HEAD)//If we're lying and we're trying to aim high, we won't be able to hit. + if(user.lying && !src.lying) + to_chat(user, "I can't reach their [affecting.name]!") + return null + + return hit_zone + +/mob/living/carbon/human/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone, var/special = FALSE) + var/obj/item/organ/external/affecting = get_organ(hit_zone) + if(!affecting) + return //should be prevented by attacked_with_item() but for sanity. + + var/aim_zone = user.zone_sel.selecting + + + var/obj/item/organ/external/aimed = get_organ(aim_zone) + + var/organ_hit = affecting.name//This is spaghetti, but it's done so that it recognizes when you hit the throat, and when you hit something else instead. + + if(aim_zone == BP_THROAT) + organ_hit = "throat" + + 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].") + + + if(hit_zone != aim_zone && (aim_zone != BP_MOUTH) && (aim_zone != BP_THROAT) && (aim_zone != BP_EYES))//This is ugly but it works. + visible_message("[user] aimed for [src]\'s [aimed.name], but [I.get_attack_name()] \his [organ_hit] instead. [(blocked < 20 && blocked > 1) ? "Slight damage was done." : ""]") + + else if(blocked < 20 && blocked > 1)//This is ugly and it doesn't work. + visible_message("[user] [I.get_attack_name()] [src]\'s [organ_hit] with the [I.name]! Slight damage was done.") + + else + visible_message("[user] [I.get_attack_name()] [src]\'s [organ_hit] with the [I.name]!") + + aggro_npc() + standard_weapon_hit_effects(I, user, effective_force, blocked, hit_zone, special) + + 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/special = FALSE) + var/obj/item/organ/external/affecting = get_organ(hit_zone) + if(!affecting) + return 0 + + if(user.STAT_LEVEL(str))//If they have strength then add it. + effective_force *= strToDamageModifier(user.STAT_LEVEL(str)) + + if(special) + switch(user.atk_intent) + if(I_OFFENSE)//Offensive attacks do even more damage. + effective_force += I.force + if(I_WEAK) + effective_force = (effective_force/2) //Half the amount of force. + + if(user.atk_intent == I_GUARD && user.combat_mode)//If we're guarding then hit for less damage. + effective_force = (effective_force * 0.25) + + if(user.atk_intent == I_DEFENSE && user.combat_mode) + effective_force = (effective_force * 0.40) + + if(effective_force > 10 || effective_force >= 5 && prob(33)) + forcesay(GLOB.hit_appends) //forcesay checks stat already + + //Ok this block of text handles cutting arteries, tendons, and limbs off. + //First we cut an artery, the reason for that, is that arteries are funninly enough, not that lethal, and don't have the biggest impact. They'll still make you bleed out, but they're less immediately lethal. + if(I.sharp && prob(I.sharpness * 2) && !(affecting.status & ORGAN_ARTERY_CUT)) + affecting.sever_artery() + if(affecting.artery_name == "carotid artery") + src.visible_message("[user] slices [src]'s throat!") + else + src.visible_message("[user] slices open [src]'s [affecting.artery_name] artery!") + + //Next tendon, which disables the limb, but does not remove it, making it easier to fix, and less lethal, than losing it. + else if(I.sharp && (I.sharpness * 2) && !(affecting.status & ORGAN_TENDON_CUT) && affecting.has_tendon)//Yes this is the same exactly probability again. But I'm running it seperate because I don't want the two to be exclusive. + affecting.sever_tendon() + src.visible_message("[user] slices open [src]'s [affecting.tendon_name] tendon!") + + //Finally if we pass all that, we cut the limb off. This should reduce the number of one hit sword kills. + else if(I.sharp && I.edge) + if(prob(I.sharpness * strToDamageModifier(user.my_stats[STAT(str)].level))) + affecting.droplimb(0, DROPLIMB_EDGE) + + var/obj/item/organ/external/head/O = locate(/obj/item/organ/external/head) in src.organs + + if(I.damtype == BRUTE && !I.edge && prob(I.force * (hit_zone == BP_MOUTH ? 6 : 0)) && O)//Knocking out teeth. + if(O.knock_out_teeth(get_dir(user, src), round(rand(28, 38) * ((I.force*1.5)/100)))) + src.visible_message("[src]'s teeth sail off in an arc!", \ + "[src]'s teeth sail off in an arc!") + + else if((I.damtype == BRUTE || I.damtype == PAIN) && prob(25 + (effective_force * 2)))//Knocking them out. + 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 + attack_bloody(I, user, effective_force, hit_zone) + + //This was commented out because critical successes are OP as shit. Now they're back. + /* + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.statscheck(skills = H.SKILL_LEVEL(melee)) == CRIT_SUCCESS) + resolve_critical_hit() + */ //And now it's commented out again. + + if(hit_zone == BP_R_HAND || hit_zone == BP_L_HAND) + var/list/holding= list(src.get_active_hand(), src.get_inactive_hand()) + for(var/obj/item/II in holding) + if(II && prob(15 + (user.SKILL_LEVEL(melee)) *10))//Skills are base 10 so I'm multiplying by 10 + II.disarm(src) + return + + apply_damage(effective_force, I.damtype, hit_zone, blocked, I.damage_flags(), used_weapon=I) + + receive_damage()//The little animation that plays when someone gets hit. + + return 1 + +/mob/living/carbon/human/proc/attack_bloody(obj/item/W, mob/living/attacker, var/effective_force, var/hit_zone) + if(W.damtype != BRUTE) + return + + //make non-sharp low-force weapons less likely to be bloodied + if(W.sharp || prob(effective_force*4)) + if(!(W.atom_flags & ATOM_FLAG_NO_BLOOD)) + W.add_blood(src) + else + return //if the weapon itself didn't get bloodied than it makes little sense for the target to be bloodied either + + //getting the weapon bloodied is easier than getting the target covered in blood, so run prob() again + if(prob(33 + W.sharp*10)) + var/turf/location = loc + if(istype(location, /turf/simulated)) + location.add_blood(src) + if(ishuman(attacker)) + var/mob/living/carbon/human/H = attacker + if(get_dist(H, src) <= 1) //people with TK won't get smeared with blood + H.bloody_body(src) + H.bloody_hands(src) + + switch(hit_zone) + if(BP_HEAD) + if(wear_mask) + wear_mask.add_blood(src) + update_inv_wear_mask(0) + if(head) + head.add_blood(src) + update_inv_head(0) + if(glasses && prob(33)) + glasses.add_blood(src) + update_inv_glasses(0) + if(BP_CHEST) + bloody_body(src) + + //All this is copypasta'd from projectile code. Basically there's a cool splat animation when someone gets hit by something. + var/splatter_dir = dir + var/turf/target_loca = get_turf(src) + splatter_dir = get_dir(attacker, target_loca) + target_loca = get_step(target_loca, splatter_dir) + var/blood_color = "#C80000" + blood_color = src.species.blood_color + new /obj/effect/overlay/temp/dir_setting/bloodsplatter(get_turf(src), splatter_dir, blood_color) + var/obj/effect/decal/cleanable/blood/B = blood_splatter(target_loca, src, 1, splatter_dir) + B.icon_state = pick("dir_splatter_1","dir_splatter_2") + var/scale = min(1, round(effective_force / 50, 0.2)) + var/matrix/M = new() + B.transform = M.Scale(scale) + //target_loca.add_blood(src) + +/mob/living/carbon/human/proc/projectile_hit_bloody(obj/item/projectile/P, var/effective_force, var/hit_zone) + if(P.damage_type != BRUTE || P.nodamage) + return + if(!(P.sharp || prob(effective_force*4))) + return + if(prob(effective_force)) + var/turf/location = loc + if(istype(location, /turf/simulated)) + location.add_blood(src) + + switch(hit_zone) + if(BP_HEAD) + if(wear_mask) + wear_mask.add_blood(src) + update_inv_wear_mask(0) + if(head) + head.add_blood(src) + update_inv_head(0) + if(glasses && prob(33)) + glasses.add_blood(src) + update_inv_glasses(0) + if(BP_CHEST) + bloody_body(src) + +/mob/living/carbon/human/proc/attack_joint(var/obj/item/organ/external/organ, var/obj/item/W, var/effective_force, var/dislocate_mult, var/blocked) + if(!organ || (organ.dislocated == 2) || (organ.dislocated == -1) || blocked >= 100) + return 0 + if(W.damtype != BRUTE) + return 0 + + //want the dislocation chance to be such that the limb is expected to dislocate after dealing a fraction of the damage needed to break the limb + var/dislocate_chance = effective_force/(dislocate_mult * organ.min_broken_damage * config.organ_health_multiplier)*100 + if(prob(dislocate_chance * blocked_mult(blocked))) + visible_message("[src]'s [organ.joint] [pick("gives way","caves in","crumbles","collapses")]!") + organ.dislocate(1) + return 1 + return 0 + +/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.robotic >= ORGAN_ROBOT)) + to_chat(user, "That limb isn't robotic.") + return -1 + if(affecting.sabotaged) + to_chat(user, "[src]'s [affecting.name] is already sabotaged!") + return -1 + to_chat(user, "You sneakily slide [emag_source] into the dataport on [src]'s [affecting.name] and short out the safeties.") + affecting.sabotaged = 1 + return 1 + +//this proc handles being hit by a thrown atom +/mob/living/carbon/human/hitby(atom/movable/AM as mob|obj,var/speed = THROWFORCE_SPEED_DIVISOR) + if(istype(AM,/obj/)) + var/obj/O = AM + + if(in_throw_mode && !get_active_hand() && speed <= THROWFORCE_SPEED_DIVISOR) //empty active hand and we're in throw mode + if(canmove && !restrained()) + if(isturf(O.loc)) + put_in_active_hand(O) + visible_message("[src] catches [O]!") + throw_mode_off() + return + + var/dtype = O.damtype + var/throw_damage = O.throwforce*(speed/THROWFORCE_SPEED_DIVISOR) + + var/zone + if (istype(O.thrower, /mob/living)) + var/mob/living/L = O.thrower + zone = check_zone(L.zone_sel.selecting) + else + zone = ran_zone(BP_CHEST,75) //Hits a random part of the body, geared towards the chest + + //check if we hit + var/miss_chance = 15 + if (O.throw_source) + var/distance = get_dist(O.throw_source, loc) + miss_chance = max(15*(distance-2), 0) + zone = get_zone_with_miss_chance(zone, src, miss_chance, ranged_attack=1) + + if(zone && O.thrower != src) + var/shield_check = check_shields(throw_damage, O, thrower, zone, "[O]") + if(shield_check == PROJECTILE_FORCE_MISS) + zone = null + else if(shield_check) + return + + if(!zone) + visible_message("\The [O] misses [src] narrowly!") + playsound(loc, 'sound/weapons/punchmiss.ogg', 50, 1) + return + + O.throwing = 0 //it hit, so stop moving + + var/obj/item/organ/external/affecting = get_organ(zone) + var/hit_area = affecting.name + //var/datum/wound/created_wound + + src.visible_message("\The [src] has been hit in the [hit_area] by \the [O].") + var/armor = run_armor_check(affecting, "melee", O.armor_penetration, "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].") //I guess "melee" is the best fit here + if(armor < 100) + var/damage_flags = O.damage_flags() + if(prob(armor)) + damage_flags &= ~(DAM_SHARP|DAM_EDGE) + apply_damage(throw_damage, dtype, zone, armor, damage_flags, O) + + if(ismob(O.thrower)) + var/mob/M = O.thrower + var/client/assailant = M.client + if(assailant) + admin_attack_log(M, src, "Threw \an [O] at their victim.", "Had \an [O] thrown at them", "threw \an [O] at") + + // Begin BS12 momentum-transfer code. + var/mass = 1.5 + if(istype(O, /obj/item)) + var/obj/item/I = O + mass = I.w_class/THROWNOBJ_KNOCKBACK_DIVISOR + var/momentum = speed*mass + + if(O.throw_source && momentum >= THROWNOBJ_KNOCKBACK_SPEED) + var/dir = get_dir(O.throw_source, src) + + visible_message("\The [src] staggers under the impact!","You stagger under the impact!") + src.throw_at(get_edge_target_turf(src,dir),1,momentum) + + if(!O || !src) return + + if(O.loc == src && O.sharp) //Projectile is embedded and suitable for pinning. + var/turf/T = near_wall(dir,2) + + if(T) + src.loc = T + visible_message("[src] is pinned to the wall by [O]!","You are pinned to the wall by [O]!") + src.anchored = 1 + src.pinned += O + +/mob/living/carbon/human/embed(var/obj/O, var/def_zone=null, var/datum/wound/supplied_wound) + if(!def_zone) ..() + + var/obj/item/organ/external/affecting = get_organ(def_zone) + if(affecting) + affecting.embed(O, supplied_wound = supplied_wound) + +/mob/living/carbon/human/proc/bloody_hands(var/mob/living/source, var/amount = 2) + if (gloves) + gloves.add_blood(source) + gloves:transfer_blood = amount + gloves:bloody_hands_mob = source + else + add_blood(source) + bloody_hands = amount + bloody_hands_mob = source + update_inv_gloves() //updates on-mob overlays for bloody hands and/or bloody gloves + +/mob/living/carbon/human/proc/bloody_body(var/mob/living/source) + if(wear_suit) + wear_suit.add_blood(source) + update_inv_wear_suit(0) + if(w_uniform) + w_uniform.add_blood(source) + update_inv_w_uniform(0) + +/mob/living/carbon/human/proc/handle_suit_punctures(var/damtype, var/damage, var/def_zone) + + // Tox and oxy don't matter to suits. + if(damtype != BURN && damtype != BRUTE) return + + // We may also be taking a suit breach. + if(!wear_suit) return + if(!istype(wear_suit,/obj/item/clothing/suit/space)) return + var/obj/item/clothing/suit/space/SS = wear_suit + var/penetrated_dam = max(0,(damage - SS.breach_threshold)) + if(penetrated_dam) SS.create_breaches(damtype, penetrated_dam) + +/mob/living/carbon/human/reagent_permeability() + var/perm = 0 + + var/list/perm_by_part = list( + "head" = THERMAL_PROTECTION_HEAD, + "upper_torso" = THERMAL_PROTECTION_UPPER_TORSO, + "lower_torso" = THERMAL_PROTECTION_LOWER_TORSO, + "legs" = THERMAL_PROTECTION_LEG_LEFT + THERMAL_PROTECTION_LEG_RIGHT, + "feet" = THERMAL_PROTECTION_FOOT_LEFT + THERMAL_PROTECTION_FOOT_RIGHT, + "arms" = THERMAL_PROTECTION_ARM_LEFT + THERMAL_PROTECTION_ARM_RIGHT, + "hands" = THERMAL_PROTECTION_HAND_LEFT + THERMAL_PROTECTION_HAND_RIGHT + ) + + for(var/obj/item/clothing/C in src.get_equipped_items()) + if(C.permeability_coefficient == 1 || !C.body_parts_covered) + continue + if(C.body_parts_covered & HEAD) + perm_by_part["head"] *= C.permeability_coefficient + if(C.body_parts_covered & UPPER_TORSO) + perm_by_part["upper_torso"] *= C.permeability_coefficient + if(C.body_parts_covered & LOWER_TORSO) + perm_by_part["lower_torso"] *= C.permeability_coefficient + if(C.body_parts_covered & LEGS) + perm_by_part["legs"] *= C.permeability_coefficient + if(C.body_parts_covered & FEET) + perm_by_part["feet"] *= C.permeability_coefficient + if(C.body_parts_covered & ARMS) + perm_by_part["arms"] *= C.permeability_coefficient + if(C.body_parts_covered & HANDS) + perm_by_part["hands"] *= C.permeability_coefficient + + for(var/part in perm_by_part) + perm += perm_by_part[part] + + return perm + +/mob/living/carbon/human/kick_act(var/mob/living/user) + if(!..())//If we can't kick then this doesn't happen. + return + if(user == src)//Can't kick yourself dummy. + return + if(user.stat) + return + + if(ticker.current_state == GAME_STATE_FINISHED) + to_chat(user, "The battle is over! There is no need to fight!") + return + + var/hit_zone = user.zone_sel.selecting + var/too_high_message = "You can't reach that high." + var/obj/item/organ/external/affecting = get_organ(hit_zone) + if(!affecting || affecting.is_stump()) + to_chat(user, "They are missing that limb!") + return + + if(ishuman(user)) + var/mob/living/carbon/human/attacker = user + if(attacker.warfare_faction) + if(attacker.warfare_faction == src.warfare_faction && src.stat != DEAD) + to_chat(attacker, "[src] is on my side!") + log_and_message_admins("[attacker] has kicked his teammate [src]!", attacker) + GLOB.ff_incidents++ + + var/armour = run_armor_check(hit_zone, "melee") + switch(hit_zone) + if(BP_CHEST)//If we aim for the chest we kick them in the direction we're facing. + if(lying) + var/turf/target = get_turf(src.loc) + var/range = src.throw_range + var/throw_dir = get_dir(user, src) + for(var/i = 1; i < range; i++) + var/turf/new_turf = get_step(target, throw_dir) + target = new_turf + if(new_turf.density) + break + src.throw_at(target, rand(1,3), src.throw_speed) + if(user.lying) + to_chat(user, too_high_message) + return + + if(BP_MOUTH)//If we aim for the mouth then we kick their teeth out. + if(lying) + if(istype(affecting, /obj/item/organ/external/head) && prob(95)) + var/obj/item/organ/external/head/U = affecting + U.knock_out_teeth(get_dir(user, src), rand(1,3))//Knocking out one tooth at a time. + else + to_chat(user, too_high_message) + return + + if(BP_HEAD) + if(!lying) + to_chat(user, too_high_message) + return + + var/kickdam = rand(2,7) + kickdam *= strToDamageModifier(user.my_stats[STAT(str)].level) + user.adjustStaminaLoss(rand(10,15))//Kicking someone is a big deal. + if(kickdam) + playsound(user.loc, 'sound/weapons/kick.ogg', 50, 0) + apply_damage(kickdam, BRUTE, hit_zone, armour) + user.visible_message("[user] kicks [src] in the [affecting.name]!") + admin_attack_log(user, src, "Has kicked [src]", "Has been kicked by [user].") + else + user.visible_message("[user] tried to kick [src] in the [affecting.name], but missed!") + playsound(loc, 'sound/weapons/punchmiss.ogg', 50, 1) + + +//We crit failed, let's see what happens to us. +/mob/living/proc/resolve_critical_miss(var/obj/item/I) + var/result = rand(1,3) + + if(!I) + visible_message("[src] punches themself in the face!") + attack_hand(src) + return + + switch(result) + if(1)//They drop their weapon. + visible_message("CRITICAL FAILURE!") + I.disarm(src) + return + if(2) + visible_message("CRITICAL FAILURE! [src] botches the attack, stumbles, and falls!") + playsound(loc, 'sound/weapons/punchmiss.ogg', 50, 1) + KnockDown() + return + if(3) + visible_message("CRITICAL FAILURE! [src] botches the attack and hits themself!") + I.attack(src, src, zone_sel) + apply_damage(rand(5,10), BRUTE) + + +/mob/living/proc/resolve_critical_miss_unarmed() + visible_message("[src] punches themself in the face!") + attack_hand(src) + return + +/mob/living/proc/resolve_critical_hit() + var/result = rand(1,3) + + switch(result) + if(1) + visible_message("CRITICAL HIT! IT MUST BE PAINFUL") + apply_damage(rand(5,10), BRUTE) + return + + if(2) + visible_message("CRITICAL HIT! [src] is stunned!") + Weaken(1) + Stun(3) + return + + if(3) + visible_message("CRITICAL HIT! [src] is knocked unconcious by the blow!") + apply_effect(10, PARALYZE) + return + + +//Add screaming here. +/mob/living/carbon/human/IgniteMob() + ..() + if(fire_stacks) + agony_scream(fire = TRUE) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm new file mode 100644 index 00000000..7e7dcb58 --- /dev/null +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -0,0 +1,129 @@ +/mob/living/carbon/human + plane = HUMAN_PLANE + + //Hair colour and style + var/r_hair = 0 + var/g_hair = 0 + var/b_hair = 0 + var/h_style = "Bald" + + //Facial hair colour and style + var/r_facial = 0 + var/g_facial = 0 + var/b_facial = 0 + var/f_style = "Shaved" + + //Eye colour + var/r_eyes = 0 + var/g_eyes = 0 + var/b_eyes = 0 + + var/s_tone = 0 //Skin tone + var/s_base = "" //Skin base + + //Skin colour + var/r_skin = 0 + var/g_skin = 0 + var/b_skin = 0 + + var/size_multiplier = 1 //multiplier for the mob's icon size + var/damage_multiplier = 1 //multiplies melee combat damage + var/icon_update = 1 //whether icon updating shall take place + + var/lip_style = null //no lipstick by default- arguably misleading, as it could be used for general makeup + + //var/age = 30 //Player's age (pure fluff) + var/b_type = "A+" //Player's bloodtype + + var/list/worn_underwear = list() + + var/datum/backpack_setup/backpack_setup + + // General information + var/home_system = "" + var/citizenship = "" + var/personal_faction = "" + + //Equipment slots + var/obj/item/wear_suit = null + var/obj/item/w_uniform = null + var/obj/item/shoes = null + var/obj/item/belt = null + var/obj/item/gloves = null + var/obj/item/glasses = null + var/obj/item/head = null + var/obj/item/l_ear = null + var/obj/item/r_ear = null + var/obj/item/wear_id = null + var/obj/item/r_store = null + var/obj/item/l_store = null + var/obj/item/s_store = null + var/obj/item/tie_slot = null + + var/used_skillpoints = 0 + var/list/skills = list() + + var/icon/stand_icon = null + var/icon/lying_icon = null + + var/voice = "" //Instead of new say code calling GetVoice() over and over and over, we're just going to ask this variable, which gets updated in Life() + + var/special_voice = "" // For changing our voice. Used by a symptom. + + var/last_dam = -1 //Used for determining if we need to process all organs or just some or even none. + var/list/bad_external_organs = list()// organs we check until they are good. + + var/xylophone = 0 //For the spoooooooky xylophone cooldown + + var/mob/remoteview_target = null + var/hand_blood_color + + var/list/flavor_texts = list() + var/gunshot_residue + var/pulling_punches // Are you trying not to hurt your opponent? + var/full_prosthetic // We are a robutt. + var/robolimb_count = 0 // Number of robot limbs. + var/last_attack = 0 // The world_time where an unarmed attack was done + + 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/equipment_light_protection + var/list/equipment_overlays = list() // Extra overlays from equipped items + + var/med_record = "" + var/sec_record = "" + var/gen_record = "" + var/exploit_record = "" + + var/datum/mil_branch/char_branch = null + var/datum/mil_rank/char_rank = null + + var/stance_damage = 0 //Whether this mob's ability to stand has been affected + + var/obj/machinery/machine_visual //machine that is currently applying visual effects to this mob. Only used for camera monitors currently. + + var/innate_heal = 1 + + var/shock_stage + + var/obj/screen/arrow_to/tracking + + var/obj/item/grab/current_grab_type // What type of grab they use when they grab someone. + var/skin_state = SKIN_NORMAL + var/obj/screen/fov = null//The screen object because I can't figure out how the hell TG does their screen objects so I'm just using legacy code. + var/obj/screen/fov_mask = null + var/usefov = TRUE + var/decaylevel = 0 //For rotting bodies + var/branded = null //For whether or not they've been branded, and what they've been branded with. + var/banished = FALSE //For whether or not they've been banished by the magistrate. + var/is_anonymous = FALSE //Used when examined and speaking for whether or not they're anonymous + var/coldbreath = FALSE //dumb snowflake bullshit for coldbreath don't worry about it g + var/last_words = null diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm new file mode 100644 index 00000000..96caa823 --- /dev/null +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -0,0 +1,332 @@ +#define HUMAN_EATING_NO_ISSUE 0 +#define HUMAN_EATING_NBP_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[1] == HUMAN_EATING_NO_ISSUE) + return 1 + if(feedback) + if(status[1] == HUMAN_EATING_NBP_MOUTH) + to_chat(src, "Where do you intend to put \the [food]? You don't have a mouth!") + else if(status[1] == HUMAN_EATING_BLOCKED_MOUTH) + to_chat(src, "\The [status[2]] 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[1] == HUMAN_EATING_NO_ISSUE) + return 1 + if(feedback) + if(status[1] == HUMAN_EATING_NBP_MOUTH) + to_chat(feeder, "Where do you intend to put \the [food]? \The [src] doesn't have a mouth!") + else if(status[1] == HUMAN_EATING_BLOCKED_MOUTH) + to_chat(feeder, "\The [status[2]] is in the way!") + return 0 + +/mob/living/carbon/human/proc/can_eat_status() + if(!check_has_mouth()) + return list(HUMAN_EATING_NBP_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_NBP_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_light_protection = 0 + equipment_darkness_modifier = 0 + equipment_overlays.Cut() + var/use_original_cone = TRUE + + if(istype(src.head, /obj/item/clothing/head)) + add_clothing_protection(head) + update_helmet_vision(head) + use_original_cone = FALSE + + 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) + update_mask_vision(wear_mask) + use_original_cone = FALSE + + if(use_original_cone) + fov_mask.icon_state = "combat_mask" + fov.icon_state = "combat" + +/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 += G.prescription + equipment_light_protection += G.light_protection + 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/update_helmet_vision(var/obj/item/clothing/head/H) + if(H.helmet_vision) + fov_mask.icon_state = "helmet_mask" + fov.icon_state = "helmet" + else + fov_mask.icon_state = "combat_mask" + fov.icon_state = "combat" + + +/mob/living/carbon/human/proc/update_mask_vision(var/obj/item/clothing/mask/M) + if(M.helmet_vision) + fov_mask.icon_state = "helmet_mask" + fov.icon_state = "helmet" + else + fov_mask.icon_state = "combat_mask" + fov.icon_state = "combat" + +/mob/living/carbon/human/get_gender() + return gender + +/mob/living/carbon/human/fully_replace_character_name(var/new_name, var/in_depth = TRUE) + var/old_name = real_name + . = ..() + if(!. || !in_depth) + return + + var/datum/computer_file/crew_record/R = get_crewmember_record(old_name) + if(R) + R.set_name(new_name) + + //update our pda and id if we have them on our person + var/list/searching = GetAllContents(searchDepth = 3) + var/search_id = 1 + var/search_pda = 1 + + for(var/A in searching) + if(search_id && istype(A,/obj/item/weapon/card/id)) + var/obj/item/weapon/card/id/ID = A + if(ID.registered_name == old_name) + ID.registered_name = new_name + ID.update_name() + search_id = 0 + else if(search_pda && istype(A,/obj/item/device/pda)) + var/obj/item/device/pda/PDA = A + if(PDA.owner == old_name) + PDA.set_owner(new_name) + search_pda = 0 + + +//Get species or synthetic temp if the mob is a FBP. Used when a synthetic type human mob is exposed to a temp check. +//Essentially, used when a synthetic human mob should act diffferently than a normal type mob. +/mob/living/carbon/human/proc/getSpeciesOrSynthTemp(var/temptype) + switch(temptype) + if(COLD_LEVEL_1) + return isSynthetic()? SYNTH_COLD_LEVEL_1 : species.cold_level_1 + if(COLD_LEVEL_2) + return isSynthetic()? SYNTH_COLD_LEVEL_2 : species.cold_level_2 + if(COLD_LEVEL_3) + return isSynthetic()? SYNTH_COLD_LEVEL_3 : species.cold_level_3 + if(HEAT_LEVEL_1) + return isSynthetic()? SYNTH_HEAT_LEVEL_1 : species.heat_level_1 + if(HEAT_LEVEL_2) + return isSynthetic()? SYNTH_HEAT_LEVEL_2 : species.heat_level_2 + if(HEAT_LEVEL_3) + return isSynthetic()? SYNTH_HEAT_LEVEL_3 : species.heat_level_3 + +/mob/living/carbon/human/proc/getCryogenicFactor(var/bodytemperature) + if(isSynthetic()) + return 0 + if(!species) + return 0 + + if(bodytemperature > species.cold_level_1) + return 0 + else if(bodytemperature > species.cold_level_2) + . = 5 * (1 - (bodytemperature - species.cold_level_2) / (species.cold_level_1 - species.cold_level_2)) + . = max(2, .) + else if(bodytemperature > species.cold_level_3) + . = 20 * (1 - (bodytemperature - species.cold_level_3) / (species.cold_level_2 - species.cold_level_3)) + . = max(5, .) + else + . = 80 * (1 - bodytemperature / species.cold_level_3) + . = max(20, .) + return round(.) + +/mob/living/carbon/human + var/next_sonar_ping = 0 + +/mob/living/carbon/human/proc/sonar_ping() + set name = "Listen In" + set desc = "Allows you to listen in to movement and noises around you." + set category = "IC" + + if(incapacitated()) + to_chat(src, "You need to recover before you can use this ability.") + return + if(world.time < next_sonar_ping) + to_chat(src, "You need another moment to focus.") + return + if(is_deaf() || is_below_sound_pressure(get_turf(src))) + to_chat(src, "You are for all intents and purposes currently deaf!") + return + next_sonar_ping += 10 SECONDS + var/heard_something = FALSE + to_chat(src, "You take a moment to listen in to your environment...") + for(var/mob/living/L in range(client.view, src)) + var/turf/T = get_turf(L) + if(!T || L == src || L.stat == DEAD || is_below_sound_pressure(T)) + continue + heard_something = TRUE + var/image/ping_image = image(icon = 'icons/effects/effects.dmi', icon_state = "sonar_ping", loc = src) + ping_image.plane = EFFECTS_ABOVE_LIGHTING_PLANE + ping_image.layer = BEAM_PROJECTILE_LAYER + ping_image.pixel_x = (T.x - src.x) * WORLD_ICON_SIZE + ping_image.pixel_y = (T.y - src.y) * WORLD_ICON_SIZE + show_image(src, ping_image) + spawn(8) + qdel(ping_image) + var/feedback = list("There are noises of movement ") + var/direction = get_dir(src, L) + if(direction) + feedback += "towards the [dir2text(direction)], " + switch(get_dist(src, L) / client.view) + if(0 to 0.2) + feedback += "very close by." + if(0.2 to 0.4) + feedback += "close by." + if(0.4 to 0.6) + feedback += "some distance away." + if(0.6 to 0.8) + feedback += "further away." + else + feedback += "far away." + else // No need to check distance if they're standing right on-top of us + feedback += "right on top of you." + feedback += "" + to_chat(src, jointext(feedback,null)) + if(!heard_something) + to_chat(src, "You hear no movement but your own.") + +/mob/living/carbon/human/reset_layer() + if(is_anonymous) + plane = ANON_PLANE + layer = BASE_MOB_LAYER + else if(hiding) + plane = HIDING_MOB_PLANE + layer = HIDING_MOB_LAYER + else if(lying) + plane = LYING_HUMAN_PLANE + layer = LYING_MOB_LAYER //Put lying humans in trenches below standing humans. + else if(istype(src.loc, /turf/simulated/floor/trench))//WHen in the trench, you are on the lying plane, so that people outside of the trench can loom over you threatenly. + plane = LYING_HUMAN_PLANE + layer = LYING_HUMAN_LAYER + else + plane = HUMAN_PLANE + layer = BASE_MOB_LAYER + // ..() + +/mob/living/carbon/human/proc/has_headset_in_ears() + return istype(get_equipped_item(slot_l_ear), /obj/item/device/radio/headset) || istype(get_equipped_item(slot_r_ear), /obj/item/device/radio/headset) + +/mob/living/carbon/human/proc/make_grab(var/mob/living/carbon/human/attacker, var/mob/living/carbon/human/victim, var/grab_tag) + var/obj/item/grab/G + + if(!grab_tag) + G = new attacker.current_grab_type(attacker, victim) + else + var/obj/item/grab/given_grab_type = all_grabobjects[grab_tag] + G = new given_grab_type(attacker, victim) + + if(!G.pre_check()) + qdel(G) + return 0 + + if(G.can_grab()) + G.init() + return 1 + else + qdel(G) + return 0 + +/mob/living/carbon/human + var/list/cloaking_sources + +// Returns true if, and only if, the human has gone from uncloaked to cloaked +/mob/living/carbon/human/proc/add_cloaking_source(var/datum/cloaking_source) + var/has_uncloaked = clean_cloaking_sources() + LAZYDISTINCTADD(cloaking_sources, weakref(cloaking_source)) + + // We don't present the cloaking message if the human was already cloaked just before cleanup. + if(!has_uncloaked && LAZYLEN(cloaking_sources) == 1) + update_icons() + src.visible_message("\The [src] seems to disappear before your eyes!", "You feel completely invisible.") + return TRUE + return FALSE + +#define CLOAK_APPEAR_OTHER "\The [src] appears from thin air!" +#define CLOAK_APPEAR_SELF "You have re-appeared." + +// Returns true if, and only if, the human has gone from cloaked to uncloaked +/mob/living/carbon/human/proc/remove_cloaking_source(var/datum/cloaking_source) + var/was_cloaked = LAZYLEN(cloaking_sources) + clean_cloaking_sources() + LAZYREMOVE(cloaking_sources, weakref(cloaking_source)) + + if(was_cloaked && !LAZYLEN(cloaking_sources)) + update_icons() + visible_message(CLOAK_APPEAR_OTHER, CLOAK_APPEAR_SELF) + return TRUE + return FALSE + +// Returns true if the human is cloaked, otherwise false (technically returns the number of cloaking sources) +/mob/living/carbon/human/proc/is_cloaked() + if(clean_cloaking_sources()) + update_icons() + visible_message(CLOAK_APPEAR_OTHER, CLOAK_APPEAR_SELF) + return LAZYLEN(cloaking_sources) + +#undef CLOAK_APPEAR_OTHER +#undef CLOAK_APPEAR_SELF + +// Returns true if the human is cloaked by the given source +/mob/living/carbon/human/proc/is_cloaked_by(var/cloaking_source) + return LAZYISIN(cloaking_sources, weakref(cloaking_source)) + +// Returns true if this operation caused the mob to go from cloaked to uncloaked +/mob/living/carbon/human/proc/clean_cloaking_sources() + if(!cloaking_sources) + return FALSE + + var/list/rogue_entries = list() + for(var/entry in cloaking_sources) + var/weakref/W = entry + if(!W.resolve()) + cloaking_sources -= W + rogue_entries += W + + if(rogue_entries.len) // These entries did not cleanup after themselves before being destroyed + var/rogue_entries_as_string = jointext(map(rogue_entries, /proc/log_info_line), ", ") + crash_with("[log_info_line(src)] - Following cloaking entries were removed during cleanup: [rogue_entries_as_string]") + + UNSETEMPTY(cloaking_sources) + return !cloaking_sources // If cloaking_sources wasn't initially null but is now, we've uncloaked diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm new file mode 100644 index 00000000..aee8931f --- /dev/null +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -0,0 +1,144 @@ +/mob/living/carbon/human/movement_delay() + var/tally = ..() + + if(species.slowdown) + tally += species.slowdown + + tally += species.handle_movement_delay_special(src) + + if (istype(loc, /turf/space)) return -1 // It's hard to be slowed down in space by... anything + + if(embedded_flag || (stomach_contents && stomach_contents.len)) + handle_embedded_and_stomach_objects() //Moving with objects stuck in you can cause bad times. + + if(CE_SPEEDBOOST in chem_effects) + return -1 + + if(CE_SLOWDOWN in chem_effects) + tally += chem_effects[CE_SLOWDOWN] + + //var/health_deficiency = (maxHealth - health) + //if(health_deficiency >= 40) tally += (health_deficiency / 25) + + if(can_feel_pain()) + if(get_shock() >= 10) tally += (get_shock() / 10) //pain shouldn't slow you down if you can't even feel it + + if(istype(buckled, /obj/structure/bed/chair/wheelchair)) + for(var/organ_name in list(BP_L_HAND, BP_R_HAND, BP_L_ARM, BP_R_ARM)) + var/obj/item/organ/external/E = get_organ(organ_name) + if(!E || E.is_stump()) + tally += 4 + else if(E.splinted) + tally += 0.5 + else if(E.status & ORGAN_BROKEN) + tally += 1.5 + else + var/total_item_slowdown = -1 + for(var/slot = slot_first to slot_last) + var/obj/item/I = get_equipped_item(slot) + if(I) + var/item_slowdown = 0 + item_slowdown += I.slowdown_general + item_slowdown += I.slowdown_per_slot[slot] + item_slowdown += I.slowdown_accessory + + if(item_slowdown >= 0) + var/size_mod = 0 + if(!(mob_size == MOB_MEDIUM)) + size_mod = log(2, mob_size / MOB_MEDIUM) + if(species.strength + size_mod + 1 > 0) + item_slowdown = item_slowdown / (species.strength + size_mod + 1) + else + item_slowdown = item_slowdown - species.strength - size_mod + if(I.str_requirement) + if(STAT_LEVEL(str) < I.str_requirement) + item_slowdown += 2 + total_item_slowdown += max(item_slowdown, 0) + tally += round(total_item_slowdown) + + for(var/organ_name in list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)) + var/obj/item/organ/external/E = get_organ(organ_name) + if(!E || E.is_stump()) + tally += 4 + else if(E.splinted) + tally += 0.5 + else if(E.status & ORGAN_BROKEN) + tally += 1.5 + + var/hungry = (500 - nutrition)/5 // So overeat would be 100 and default level would be 80 + if (hungry >= 70) + tally += hungry/50 + + + if(aiming && aiming.aiming_at) + tally += 5 // Iron sights make you slower, it's a well-known fact. + + if(facing_dir) + tally += 0.5 //Locking direction will slow you down. + + if(crouching)//Crouching makes you slower. + tally += 2 + + if(FAT in src.mutations) + tally += 1.5 + if (bodytemperature < 283.222) + tally += (283.222 - bodytemperature) / 10 * 1.75 + + tally += max(2 * stance_damage, 0) //damaged/missing feet or legs is slow + + if(staminaloss >= 100) + tally += 1 + if(staminaloss >= 120) + tally += 2 + if(staminaloss >= 160) + tally += 3 + if(staminaloss >= 180) + tally += 10 + + tally += overweight() + + if(zoomed)//Zooming makes you move slower. + tally += 3 + + if(mRun in mutations) + tally = 0 + + return (tally+config.human_delay) + +/mob/living/carbon/human/Allow_Spacemove(var/check_drift = 0) + //Can we act? + if(restrained()) return 0 + + //Do we have a working jetpack? + var/obj/item/weapon/tank/jetpack/thrust + if(back) + if(istype(back,/obj/item/weapon/tank/jetpack)) + thrust = back + + if(thrust) + if(((!check_drift) || (check_drift && thrust.stabilization_on)) && (!lying) && (thrust.allow_thrust(0.01, src))) + inertia_dir = 0 + return 1 + + //If no working jetpack then use the other checks + . = ..() + + +/mob/living/carbon/human/slip_chance(var/prob_slip = 5) + if(!..()) + return 0 + + //Check hands and mod slip + if(!l_hand) prob_slip -= 2 + else if(l_hand.w_class <= ITEM_SIZE_SMALL) prob_slip -= 1 + if (!r_hand) prob_slip -= 2 + else if(r_hand.w_class <= ITEM_SIZE_SMALL) prob_slip -= 1 + + return prob_slip + +/mob/living/carbon/human/Check_Shoegrip() + if(species.species_flags & SPECIES_FLAG_NO_SLIP) + return 1 + if(shoes && (shoes.item_flags & ITEM_FLAG_NOSLIP) && istype(shoes, /obj/item/clothing/shoes/magboots)) //magboots + dense_object = no floating + return 1 + return 0 diff --git a/code/modules/mob/living/carbon/human/human_organs.dm b/code/modules/mob/living/carbon/human/human_organs.dm new file mode 100644 index 00000000..26d250db --- /dev/null +++ b/code/modules/mob/living/carbon/human/human_organs.dm @@ -0,0 +1,209 @@ +/mob/living/carbon/human/proc/update_eyes() + var/obj/item/organ/internal/eyes/eyes = internal_organs_by_name[species.vision_organ ? species.vision_organ : BP_EYES] + if(eyes) + eyes.update_colour() + regenerate_icons() + +/mob/living/carbon/human/proc/get_bodypart_name(var/zone) + var/obj/item/organ/external/E = get_organ(zone) + if(E) . = E.name + +/mob/living/carbon/human/proc/recheck_bad_external_organs() + var/damage_this_tick = getToxLoss() + for(var/obj/item/organ/external/O in organs) + damage_this_tick += O.burn_dam + O.brute_dam + + if(damage_this_tick > last_dam) + . = TRUE + last_dam = damage_this_tick + +// Takes care of organ related updates, such as broken and missing limbs +/mob/living/carbon/human/proc/handle_organs() + + var/force_process = recheck_bad_external_organs() + + if(force_process) + bad_external_organs.Cut() + for(var/obj/item/organ/external/Ex in organs) + bad_external_organs |= Ex + + //processing internal organs is pretty cheap, do that first. + for(var/obj/item/organ/I in internal_organs) + I.Process() + + handle_stance() + handle_grasp() + + if(!force_process && !bad_external_organs.len) + return + + for(var/obj/item/organ/external/E in bad_external_organs) + if(!E) + continue + if(!E.need_process()) + bad_external_organs -= E + continue + else + E.Process() + + if (!lying && !buckled && world.time - l_move_time < 15) + //Moving around with fractured ribs won't do you any good + if (prob(10) && !stat && can_feel_pain() && chem_effects[CE_PAINKILLER] < 50 && E.is_broken() && E.internal_organs.len) + custom_pain("Pain jolts through your broken [E.encased ? E.encased : E.name], staggering you!", 50, affecting = E) + drop_item(loc) + Stun(2) + + //Moving makes open wounds get infected much faster + if (E.wounds.len) + for(var/datum/wound/W in E.wounds) + if (W.infection_check()) + W.germ_level += 1 + +/mob/living/carbon/human/proc/handle_stance() + // Don't need to process any of this if they aren't standing anyways + // unless their stance is damaged, and we want to check if they should stay down + if (!stance_damage && (lying || resting) && (life_tick % 4) != 0) + return + + stance_damage = 0 + + // Buckled to a bed/chair. Stance damage is forced to 0 since they're sitting on something solid + if (istype(buckled, /obj/structure/bed)) + return + + //var/limb_pain + for(var/limb_tag in list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)) + var/obj/item/organ/external/E = organs_by_name[limb_tag] + if(!E || !E.is_usable()) + stance_damage += 2 // let it fail even if just foot&leg + else if (E.is_malfunctioning()) + //malfunctioning only happens intermittently so treat it as a missing limb when it procs + stance_damage += 2 + if(prob(10)) + visible_message("\The [src]'s [E.name] [pick("twitches", "shudders")] and sparks!") + var/datum/effect/effect/system/spark_spread/spark_system = new () + spark_system.set_up(5, 0, src) + spark_system.attach(src) + spark_system.start() + spawn(10) + qdel(spark_system) + else if (E.is_broken()) + stance_damage += 1 + else if (E.is_dislocated()) + stance_damage += 0.5 + + //if(E) limb_pain = E.can_feel_pain() + + // Canes and crutches help you stand (if the latter is ever added) + // One cane mitigates a broken leg+foot, or a missing foot. + // Two canes are needed for a lost leg. If you are missing both legs, canes aren't gonna help you. + if (l_hand && istype(l_hand, /obj/item/weapon/cane)) + stance_damage -= 2 + if (r_hand && istype(r_hand, /obj/item/weapon/cane)) + stance_damage -= 2 + + // standing is poor + if(stance_damage >= 4 || (stance_damage >= 2 && prob(5))) + if(!(lying || resting)) + // if(limb_pain) +// emote("scream") + custom_emote(VISIBLE_MESSAGE, "collapses!") + Weaken(5) //can't emote while weakened, apparently. + +/mob/living/carbon/human/proc/handle_grasp() + if(!l_hand && !r_hand) + return + + // You should not be able to pick anything up, but stranger things have happened. + if(l_hand) + for(var/limb_tag in list(BP_L_HAND, BP_L_ARM)) + var/obj/item/organ/external/E = get_organ(limb_tag) + if(!E) + visible_message("Lacking a functioning left hand, \the [src] drops \the [l_hand].") + drop_from_inventory(l_hand) + break + + if(r_hand) + for(var/limb_tag in list(BP_R_HAND, BP_R_ARM)) + var/obj/item/organ/external/E = get_organ(limb_tag) + if(!E) + visible_message("Lacking a functioning right hand, \the [src] drops \the [r_hand].") + drop_from_inventory(r_hand) + break + + // Check again... + if(!l_hand && !r_hand) + return + + for (var/obj/item/organ/external/E in organs) + if(!E || !E.can_grasp) + continue + if(((E.is_broken() || E.is_dislocated()) && !E.splinted) || E.is_malfunctioning()) + grasp_damage_disarm(E) + + +/mob/living/carbon/human/proc/grasp_damage_disarm(var/obj/item/organ/external/affected) + var/disarm_slot + switch(affected.body_part) + if(HAND_LEFT, ARM_LEFT) + disarm_slot = slot_l_hand + if(HAND_RIGHT, ARM_RIGHT) + disarm_slot = slot_r_hand + + if(!disarm_slot) + return + + var/obj/item/thing = get_equipped_item(disarm_slot) + + if(!thing) + return + + drop_from_inventory(thing) + + if(affected.robotic >= ORGAN_ROBOT) + visible_message("\The [src] drops what they were holding, \his [affected.name] malfunctioning!") + + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, src) + spark_system.attach(src) + spark_system.start() + spawn(10) + qdel(spark_system) + + else + var/grasp_name = affected.name + if((affected.body_part in list(ARM_LEFT, ARM_RIGHT)) && affected.children.len) + var/obj/item/organ/external/hand = pick(affected.children) + grasp_name = hand.name + + if(affected.can_feel_pain()) + var/emote_scream = pick("screams in pain", "lets out a sharp cry", "cries out") + var/emote_scream_alt = pick("scream in pain", "let out a sharp cry", "cry out") + visible_message( + "\The [src] [emote_scream] and drops what they were holding in their [grasp_name]!", + null, + "You hear someone [emote_scream_alt]!" + ) + custom_pain("The sharp pain in your [affected.name] forces you to drop [thing]!", 30) + else + visible_message("\The [src] drops what they were holding in their [grasp_name]!") + +/mob/living/carbon/human/proc/sync_organ_dna() + var/list/all_bits = internal_organs|organs + for(var/obj/item/organ/O in all_bits) + O.set_dna(dna) + +/mob/living/proc/is_asystole() + return FALSE + +/mob/living/carbon/human/is_asystole() + if(isSynthetic()) + var/obj/item/organ/internal/cell/C = internal_organs_by_name[BP_CELL] + if(istype(C)) + if(!C.is_usable()) + return TRUE + else if(should_have_organ(BP_HEART)) + var/obj/item/organ/internal/heart/heart = internal_organs_by_name[BP_HEART] + if(!istype(heart) || !heart.is_working()) + return TRUE + return FALSE \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_powers.dm b/code/modules/mob/living/carbon/human/human_powers.dm new file mode 100644 index 00000000..507da727 --- /dev/null +++ b/code/modules/mob/living/carbon/human/human_powers.dm @@ -0,0 +1,310 @@ + // These should all be procs, you can add them to humans/subspecies by +// species.dm's inherent_verbs ~ Z + +/mob/living/carbon/human/proc/tackle() + set category = "Abilities" + set name = "Tackle" + set desc = "Tackle someone down." + + if(last_special > world.time) + return + + if(incapacitated(INCAPACITATION_DISABLED) || buckled || pinned.len) + to_chat(src, "You cannot tackle in your current state.") + return + + var/list/choices = list() + for(var/mob/living/M in view(1,src)) + if(!istype(M,/mob/living/silicon) && Adjacent(M)) + choices += M + choices -= src + + var/mob/living/T = input(src,"Who do you wish to tackle?") as null|anything in choices + + if(!T || !src || src.stat) return + + if(!Adjacent(T)) return + + //check again because we waited for user input + if(last_special > world.time) + return + + if(incapacitated(INCAPACITATION_DISABLED) || buckled || pinned.len) + to_chat(src, "You cannot tackle in your current state.") + return + + last_special = world.time + 50 + + playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) + T.Weaken(rand(1,3)) + if(prob(75)) + visible_message("\The [src] has tackled down [T]!") + else + visible_message("\The [src] tried to tackle down [T]!") + src.Weaken(rand(2,4)) //failure, you both get knocked down + +/mob/living/carbon/human/proc/leap() + set category = "Abilities" + set name = "Leap" + set desc = "Leap at a target and grab them aggressively." + + if(last_special > world.time) + return + + if(incapacitated(INCAPACITATION_DISABLED) || buckled || pinned.len) + to_chat(src, "You cannot leap in your current state.") + return + + var/list/choices = list() + for(var/mob/living/M in oview(6,src)) + if(!istype(M,/mob/living/silicon)) + choices += M + choices -= src + + var/mob/living/T = input(src,"Who do you wish to leap at?") as null|anything in choices + + if(!T || !isturf(T.loc) || !src || !isturf(loc)) return + + if(get_dist(get_turf(T), get_turf(src)) > 4) return + + //check again because we waited for user input + if(last_special > world.time) + return + + if(incapacitated(INCAPACITATION_DISABLED) || buckled || pinned.len || stance_damage >= 4) + to_chat(src, "You cannot leap in your current state.") + return + + playsound(src.loc, 'sound/voice/shriek1.ogg', 50, 1) + + last_special = world.time + (17.5 SECONDS) + status_flags |= LEAPING + + src.visible_message("\The [src] leaps at [T]!") + src.throw_at(get_step(get_turf(T),get_turf(src)), 4, 1, src) + + sleep(5) + + if(status_flags & LEAPING) status_flags &= ~LEAPING + + if(!src.Adjacent(T)) + to_chat(src, "You miss!") + return + + T.Weaken(3) + + if(src.make_grab(src, T)) + src.visible_message("\The [src] seizes [T]!") + +/mob/living/carbon/human/proc/commune() + set category = "Abilities" + set name = "Commune with creature" + set desc = "Send a telepathic message to an unlucky recipient." + + var/list/targets = list() + var/target = null + var/text = null + + targets += getmobs() //Fill list, prompt user with list + target = input("Select a creature!", "Speak to creature", null, null) as null|anything in targets + + if(!target) return + + text = input("What would you like to say?", "Speak to creature", null, null) + + text = sanitize(text) + + if(!text) return + + var/mob/M = targets[target] + + if(isghost(M) || M.stat == DEAD) + to_chat(src, "Not even a [src.species.name] can speak to the dead.") + return + + log_say("[key_name(src)] communed to [key_name(M)]: [text]") + + to_chat(M, "Like lead slabs crashing into the ocean, alien thoughts drop into your mind: [text]") + if(istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(H.species.name == src.species.name) + return + if(prob(75)) + to_chat(H, "Your nose begins to bleed...") + H.drip(1) + +/mob/living/carbon/human/proc/regurgitate() + set name = "Regurgitate" + set desc = "Empties the contents of your stomach" + set category = "Abilities" + + if(stomach_contents.len) + for(var/mob/M in src) + if(M in stomach_contents) + stomach_contents.Remove(M) + M.forceMove(loc) + src.visible_message("[src] hurls out the contents of their stomach!") + return + +/mob/living/carbon/human/proc/psychic_whisper(mob/M as mob in oview()) + set name = "Psychic Whisper" + set desc = "Whisper silently to someone over a distance." + set category = "Abilities" + + var/msg = sanitize(input("Message:", "Psychic Whisper") as text|null) + if(msg) + log_say("PsychicWhisper: [key_name(src)]->[M.key] : [msg]") + to_chat(M, "You hear a strange, alien voice in your head... [msg]") + to_chat(src, "You channel a message: \"[msg]\" to [M]") + return + +/mob/living/carbon/human/proc/can_nab(var/mob/living/target) + if(QDELETED(src)) + return FALSE + + if(last_special > world.time) + to_chat(src, "It is too soon to make another nab attempt.") + return FALSE + + if(incapacitated()) + to_chat(src, "You cannot nab in your current state.") + return FALSE + + if(!is_cloaked() || pulling_punches) + to_chat(src, "You can only nab people when you are well hidden and ready to hunt.") + return FALSE + + if(target) + if(!istype(target) || issilicon(target)) + return FALSE + if(!Adjacent(target)) + to_chat(src, "\The [target] has to be adjacent to you.") + return FALSE + + return TRUE + +/mob/living/carbon/human/proc/nab() + set category = "Abilities" + set name = "Nab" + set desc = "Nab someone." + + if(!can_nab()) + return + + var/list/choices = list() + for(var/mob/living/M in view(1,src)) + if(!istype(M,/mob/living/silicon) && Adjacent(M)) + choices += M + choices -= src + + var/mob/living/T = input(src, "Who do you wish to nab?") as null|anything in choices + if(!T || !can_nab(T)) + return + + last_special = world.time + 50 + + if(l_hand) unEquip(l_hand) + if(r_hand) unEquip(r_hand) + to_chat(src, "You drop everything as you spring out to nab someone!.") + + playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) + remove_cloaking_source(species) + + if(prob(90) && src.make_grab(src, T, GRAB_NAB_SPECIAL)) + T.Weaken(rand(1,3)) + visible_message("\The [src] suddenly lunges out and grabs \the [T]!") + LAssailant = src + + src.do_attack_animation(T) + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + return 1 + + else + visible_message("\The [src] suddenly lunges out, almost grabbing \the [T]!") + +/mob/living/carbon/human/proc/active_camo() + set category = "Abilities" + set name = "Active Camo" + set desc = "Camouflage yourself" + + if(is_cloaked_by(species)) + remove_cloaking_source(species) + else + add_cloaking_source(species) + apply_effect(2, STUN, 0) + +/mob/living/carbon/human/proc/switch_stance() + set category = "Abilities" + set name = "Switch Stance" + set desc = "Toggle between your hunting and manipulation stance" + + if(stat) return + + to_chat(src, "You begin to adjust the fluids in your arms, dropping everything and getting ready to swap which set you're using.") + var/hidden = is_cloaked() + if(!hidden) + visible_message("[src] shifts \his arms.") + + if(l_hand) unEquip(l_hand) + if(r_hand) unEquip(r_hand) + + if(do_after(src, 30)) + hidden = is_cloaked() + pulling_punches = !pulling_punches + nabbing = !pulling_punches + + if(pulling_punches) + current_grab_type = all_grabobjects[GRAB_NORMAL] + to_chat(src, "You relax your hunting arms, lowering the pressure and folding them tight to your thorax.\ + You reach out with your manipulation arms, ready to use complex items.") + if(!hidden) + visible_message("[src] seems to relax as \he folds \his massive curved arms to \his thorax and reaches out \ + with \his small handlike limbs.") + else + current_grab_type = all_grabobjects[GRAB_NAB] + to_chat(src, "You pull in your manipulation arms, dropping any items and unfolding your massive hunting arms in preparation of grabbing prey.") + if(!hidden) + visible_message("[src] tenses as \he brings \his smaller arms in close to \his body. \His two massive spiked arms reach \ + out. \He looks ready to attack.") + else + to_chat(src, "You stop adjusting your arms and don't switch between them.") + +/mob/living/carbon/human/proc/change_colour() + set category = "Abilities" + set name = "Change Colour" + set desc = "Choose the colour of your skin." + + var/new_skin = input(usr, "Choose your new skin colour: ", "Change Colour", rgb(r_skin, g_skin, b_skin)) as color|null + change_skin_color(hex2num(copytext(new_skin, 2, 4)), hex2num(copytext(new_skin, 4, 6)), hex2num(copytext(new_skin, 6, 8))) + +/mob/living/carbon/human/proc/threat_display() + set category = "Abilities" + set name = "Threat Display" + set desc = "Toggle between scary or not." + + if(stat) + to_chat(src, "You can't do a threat display in your current state.") + return + + switch(skin_state) + if(SKIN_NORMAL) + if(pulling_punches) + to_chat(src, "You must be in your hunting stance to do a threat display.") + return + var/message = alert("Would you like to show a scary message?",,"Cancel","Yes", "No") + switch(message) + if("Yes") + visible_message("[src]'s skin shifts to a deep red colour with dark chevrons running down in an almost hypnotic \ + pattern. Standing tall, \he strikes, sharp spikes aimed at those threatening \him, claws whooshing through the air past them.") + if("Cancel") + return + playsound(src, 'sound/effects/angrybug.ogg', 60, 0) + skin_state = SKIN_THREAT + spawn(100) + if(skin_state == SKIN_THREAT) + skin_state = SKIN_NORMAL + update_skin(1) + if(SKIN_THREAT) + skin_state = SKIN_NORMAL + update_skin(1) + diff --git a/code/modules/mob/living/carbon/human/human_species.dm b/code/modules/mob/living/carbon/human/human_species.dm new file mode 100644 index 00000000..d47c7438 --- /dev/null +++ b/code/modules/mob/living/carbon/human/human_species.dm @@ -0,0 +1,72 @@ +/mob/living/carbon/human/dummy + real_name = "Test Dummy" + status_flags = GODMODE|CANPUSH + virtual_mob = null + +/mob/living/carbon/human/dummy/mannequin/Initialize() + . = ..() + STOP_PROCESSING(SSmobs, src) + GLOB.human_mob_list -= src + delete_inventory() + +/mob/living/carbon/human/dummy/mannequin/add_to_living_mob_list() + return FALSE + +/mob/living/carbon/human/dummy/mannequin/add_to_dead_mob_list() + return FALSE + +/mob/living/carbon/human/dummy/mannequin/fully_replace_character_name(new_name) + ..("[new_name] (mannequin)", FALSE) + +/mob/living/carbon/human/dummy/mannequin/InitializeHud() + return // Mannequins don't get HUDs + +/mob/living/carbon/human/skrell/New(var/new_loc) + h_style = "Skrell Male Tentacles" + ..(new_loc, SPECIES_SKRELL) + +/mob/living/carbon/human/tajaran/New(var/new_loc) + h_style = "Tajaran Ears" + ..(new_loc, SPECIES_TAJARA) + +/mob/living/carbon/human/unathi/New(var/new_loc) + h_style = "Unathi Horns" + ..(new_loc, SPECIES_UNATHI) + +/mob/living/carbon/human/vox/New(var/new_loc) + h_style = "Long Vox Quills" + ..(new_loc, SPECIES_VOX) + +/mob/living/carbon/human/diona/New(var/new_loc) + ..(new_loc, SPECIES_DIONA) + +/mob/living/carbon/human/machine/New(var/new_loc) + ..(new_loc, SPECIES_IPC) + +/mob/living/carbon/human/bogani/New(var/new_loc) + ..(new_loc, SPECIES_BOGANI) + +/mob/living/carbon/human/egyno/New(var/new_loc) + ..(new_loc, SPECIES_EGYNO) + +/mob/living/carbon/human/nabber/New(var/new_loc) + pulling_punches = 1 + ..(new_loc, SPECIES_NABBER) + +/mob/living/carbon/human/monkey/New(var/new_loc) + ..(new_loc, "Monkey") + +/mob/living/carbon/human/farwa/New(var/new_loc) + ..(new_loc, "Farwa") + +/mob/living/carbon/human/neaera/New(var/new_loc) + ..(new_loc, "Neaera") + +/mob/living/carbon/human/stok/New(var/new_loc) + ..(new_loc, "Stok") + +/mob/living/carbon/human/skinless/New(var/new_loc) + ..(new_loc, "Skinless") + +/mob/living/carbon/human/lackey/New(var/new_loc) + ..(new_loc, "Lackey") \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm new file mode 100644 index 00000000..c962649b --- /dev/null +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -0,0 +1,453 @@ +#define REMOVE_INTERNALS if(internal){ if(internals){ internals.icon_state = "internal0" }; internal = null } +/* +Add fingerprints to items when we put them in our hands. +This saves us from having to call add_fingerprint() any time something is put in a human's hands programmatically. +*/ + +/mob/living/carbon/human/verb/quick_equip() + set name = "quick-equip" + set hidden = 1 + + if(ishuman(src)) + var/mob/living/carbon/human/H = src + var/obj/item/I = H.get_active_hand() + if(!I) + var/obj/item/back_item = get_equipped_item(slot_s_store) + if(back_item) + unEquip(back_item) + put_in_active_hand(back_item) + else + to_chat(H, "You are not holding anything to equip.") + return + if(H.equip_to_appropriate_slot(I)) + if(hand) + update_inv_l_hand(0) + else + update_inv_r_hand(0) + else + to_chat(H, "You are unable to equip that.") + +/mob/living/carbon/human/proc/equip_in_one_of_slots(obj/item/W, list/slots, del_on_fail = 1) + for (var/slot in slots) + if (equip_to_slot_if_possible(W, slots[slot], del_on_fail = 0)) + return slot + if (del_on_fail) + qdel(W) + return null + +//Puts the item into our active hand if possible. returns 1 on success. +/mob/living/carbon/human/put_in_active_hand(var/obj/item/W) + return (hand ? put_in_l_hand(W) : put_in_r_hand(W)) + +//Puts the item into our inactive hand if possible. returns 1 on success. +/mob/living/carbon/human/put_in_inactive_hand(var/obj/item/W) + return (hand ? put_in_r_hand(W) : put_in_l_hand(W)) + +/mob/living/carbon/human/put_in_hands(var/obj/item/W) + if(!W) + return 0 + if(put_in_active_hand(W) || put_in_inactive_hand(W)) + W.update_held_icon() + return 1 + return ..() + +/mob/living/carbon/human/put_in_l_hand(var/obj/item/W) + if(!..() || l_hand) + return 0 + var/obj/item/organ/external/hand = organs_by_name["l_hand"] + if(!hand || !hand.is_usable()) + return 0 + equip_to_slot(W,slot_l_hand) + W.add_fingerprint(src) + return 1 + +/mob/living/carbon/human/put_in_r_hand(var/obj/item/W) + if(!..() || r_hand) + return 0 + var/obj/item/organ/external/hand = organs_by_name["r_hand"] + if(!hand || !hand.is_usable()) + return 0 + + equip_to_slot(W,slot_r_hand) + W.add_fingerprint(src) + return 1 + +/mob/living/carbon/human/proc/has_organ(name) + var/obj/item/organ/external/O = organs_by_name[name] + return (O && !O.is_stump()) + +/mob/living/carbon/human/proc/has_organ_for_slot(slot) + switch(slot) + if(slot_back) + return has_organ(BP_CHEST) + if(slot_wear_mask) + return has_organ(BP_HEAD) + if(slot_handcuffed) + return has_organ(BP_L_HAND) && has_organ(BP_R_HAND) + if(slot_legcuffed) + return has_organ(BP_L_FOOT) && has_organ(BP_R_FOOT) + if(slot_l_hand) + return has_organ(BP_L_HAND) + if(slot_r_hand) + return has_organ(BP_R_HAND) + if(slot_belt) + return has_organ(BP_CHEST) + if(slot_wear_id) + // the only relevant check for this is the uniform check + return 1 + if(slot_l_ear) + return has_organ(BP_HEAD) + if(slot_r_ear) + return has_organ(BP_HEAD) + if(slot_glasses) + return has_organ(BP_HEAD) + if(slot_gloves) + return has_organ(BP_L_HAND) || has_organ(BP_R_HAND) + if(slot_head) + return has_organ(BP_HEAD) + if(slot_shoes) + return has_organ(BP_L_FOOT) || has_organ(BP_R_FOOT) + if(slot_wear_suit) + return has_organ(BP_CHEST) + if(slot_w_uniform) + return has_organ(BP_CHEST) + if(slot_l_store) + return has_organ(BP_CHEST) + if(slot_r_store) + return has_organ(BP_CHEST) + if(slot_s_store) + return has_organ(BP_CHEST) + if(slot_in_backpack) + return 1 + if(slot_tie) + return has_organ(BP_HEAD) + +/mob/living/carbon/human/u_equip(obj/W as obj) + if(!W) return 0 + + if (W == wear_suit) + wear_suit = null + update_inv_wear_suit() + else if (W == w_uniform) + if (r_store) + drop_from_inventory(r_store) + if (l_store) + drop_from_inventory(l_store) + //if (wear_id) + // drop_from_inventory(wear_id) + if (belt) + drop_from_inventory(belt) + w_uniform = null + update_inv_w_uniform() + else if (W == gloves) + gloves = null + update_inv_gloves() + else if (W == glasses) + glasses = null + update_inv_glasses() + else if (W == head) + head = null + if(istype(W, /obj/item)) + var/obj/item/I = W + if(I.flags_inv & (HIDEMASK|BLOCKHAIR|BLOCKHEADHAIR)) + update_hair(0) //rebuild hair + update_inv_ears(0) + update_inv_wear_mask(0) + if(src) + var/obj/item/clothing/mask/wear_mask = src.get_equipped_item(slot_wear_mask) + if(!(wear_mask && (wear_mask.item_flags & ITEM_FLAG_AIRTIGHT))) + REMOVE_INTERNALS + update_inv_head() + else if (W == l_ear) + l_ear = null + if(r_ear == W) //check for items that get equipped to both ear slots + r_ear = null + update_inv_ears() + else if (W == r_ear) + r_ear = null + if(l_ear == W) + l_ear = null + update_inv_ears() + else if (W == shoes) + shoes = null + update_inv_shoes() + else if (W == belt) + belt = null + update_inv_belt() + else if (W == wear_mask) + wear_mask = null + if(istype(W, /obj/item)) + var/obj/item/I = W + if(I.flags_inv & (BLOCKHAIR|BLOCKHEADHAIR)) + update_hair(0) //rebuild hair + update_inv_ears(0) + REMOVE_INTERNALS + update_inv_wear_mask() + else if (W == wear_id) + wear_id = null + update_inv_wear_id() + else if (W == r_store) + r_store = null + update_inv_pockets() + else if (W == l_store) + l_store = null + update_inv_pockets() + else if (W == s_store) + s_store = null + update_inv_s_store() + else if (W == back) + back = null + update_inv_back() + else if(W == tie_slot) + tie_slot = null + update_inv_neck() + else if (W == handcuffed) + handcuffed = null + if(buckled && buckled.buckle_require_restraints) + buckled.unbuckle_mob() + update_inv_handcuffed() + else if (W == r_hand) + r_hand = null + if(l_hand) + l_hand.update_twohanding() + update_inv_l_hand() + update_inv_r_hand() + else if (W == l_hand) + l_hand = null + if(r_hand) + r_hand.update_twohanding() + update_inv_l_hand() + update_inv_l_hand() + else + return 0 + + update_action_buttons() + spawn(1) + updateweight() + return 1 + + + +//This is an UNSAFE proc. Use mob_can_equip() before calling this one! Or rather use equip_to_slot_if_possible() or advanced_equip_to_slot_if_possible() +//set redraw_mob to 0 if you don't wish the hud to be updated - if you're doing it manually in your own proc. +/mob/living/carbon/human/equip_to_slot(obj/item/W as obj, slot, redraw_mob = 1) + + if(!slot) return + if(!istype(W)) return + if(!has_organ_for_slot(slot)) return + if(!species || !species.hud || !(slot in species.hud.equip_slots)) return + W.forceMove(src) + + var/obj/item/old_item = get_equipped_item(slot) + + switch(slot) + if(slot_back) + src.back = W + W.equipped(src, slot) + update_inv_back(redraw_mob) + if(W.equipsound)//Rifles being holstered, or backpacks being put on. + playsound(src, W.equipsound, 50, 1) + if(slot_wear_mask) + src.wear_mask = W + if(wear_mask.flags_inv & (BLOCKHAIR|BLOCKHEADHAIR)) + update_hair(redraw_mob) //rebuild hair + update_inv_ears(0) + W.equipped(src, slot) + update_inv_wear_mask(redraw_mob) + if(W.equipsound)//So like a sword being sheathed. + playsound(src, W.equipsound, 50, 1) + if(slot_handcuffed) + src.handcuffed = W + drop_r_hand() + drop_l_hand() + stop_pulling() + update_inv_handcuffed(redraw_mob) + if(slot_l_hand) + src.l_hand = W + W.equipped(src, slot) + W.screen_loc = ui_lhand + update_inv_l_hand(redraw_mob) + W.grab_sound(src)//The grab sound, if it's loud it'll print a message about grabbing a weapon + if(slot_r_hand) + src.r_hand = W + W.equipped(src, slot) + W.screen_loc = ui_rhand + update_inv_r_hand(redraw_mob)//Same for the other hand + W.grab_sound(src) + if(slot_belt) + src.belt = W + W.equipped(src, slot) + update_inv_belt(redraw_mob) + if(W.equipsound)//So like a sword being sheathed. + playsound(src, W.equipsound, 50, 1) + if(slot_wear_id) + src.wear_id = W + W.equipped(src, slot) + update_inv_wear_id(redraw_mob) + if(slot_l_ear) + src.l_ear = W + if(l_ear.slot_flags & SLOT_TWOEARS) + src.r_ear = W + W.equipped(src, slot) + update_inv_ears(redraw_mob) + if(slot_r_ear) + src.r_ear = W + if(r_ear.slot_flags & SLOT_TWOEARS) + src.l_ear = W + W.equipped(src, slot) + update_inv_ears(redraw_mob) + if(slot_glasses) + src.glasses = W + W.equipped(src, slot) + update_inv_glasses(redraw_mob) + if(slot_gloves) + src.gloves = W + W.equipped(src, slot) + update_inv_gloves(redraw_mob) + if(slot_head) + src.head = W + if(head.flags_inv & (BLOCKHAIR|BLOCKHEADHAIR|HIDEMASK)) + update_hair(redraw_mob) //rebuild hair + update_inv_ears(0) + update_inv_wear_mask(0) + if(istype(W,/obj/item/clothing/head/kitty)) + W.update_icon(src) + W.equipped(src, slot) + update_inv_head(redraw_mob) + if(slot_shoes) + src.shoes = W + W.equipped(src, slot) + update_inv_shoes(redraw_mob) + if(slot_wear_suit) + src.wear_suit = W + if(wear_suit.flags_inv & HIDESHOES) + update_inv_shoes(0) + if(wear_suit.flags_inv & HIDEGLOVES) + update_inv_gloves(0) + if(wear_suit.flags_inv & HIDEJUMPSUIT) + update_inv_w_uniform(0) + W.equipped(src, slot) + update_inv_wear_suit(redraw_mob) + if(W.equipsound)//Armor being put on. + playsound(src, W.equipsound, 50, 1) + if(slot_w_uniform) + src.w_uniform = W + if(w_uniform.flags_inv & HIDESHOES) + update_inv_shoes(0) + W.equipped(src, slot) + update_inv_w_uniform(redraw_mob) + if(W.equipsound)//Suits being zipped up. + playsound(src, W.equipsound, 50, 1) + if(slot_l_store) + src.l_store = W + W.equipped(src, slot) + update_inv_pockets(redraw_mob) + if(slot_r_store) + src.r_store = W + W.equipped(src, slot) + update_inv_pockets(redraw_mob) + if(slot_s_store) + src.s_store = W + W.equipped(src, slot) + update_inv_s_store(redraw_mob) + if(W.equipsound)//Rifles being holstered. + playsound(src, W.equipsound, 50, 1) + if(slot_in_backpack) + if(src.get_active_hand() == W) + src.remove_from_mob(W) + W.forceMove(src.back) + if(slot_tie) + src.tie_slot = W + W.equipped(src, slot) + update_inv_neck(redraw_mob) + else + to_chat(src, "You are trying to eqip this item to an unsupported inventory slot. If possible, please write a ticket with steps to reproduce. Slot was: [slot]") + return + + if((W == src.l_hand) && (slot != slot_l_hand)) + src.l_hand = null + update_inv_l_hand() //So items actually disappear from hands. + else if((W == src.r_hand) && (slot != slot_r_hand)) + src.r_hand = null + update_inv_r_hand() + + W.hud_layerise() + for(var/s in species.hud.gear) + var/list/gear = species.hud.gear[s] + if(gear["slot"] == slot) + W.screen_loc = gear["loc"] + if(W.action_button_name) + update_action_buttons() + + // if we replaced an item, delete the old item. do this at the end to make the replacement seamless + if(old_item) + qdel(old_item) + + spawn(1) + updateweight() + if(hud_used) + hud_used.add_inventory_overlay() + return 1 + +//Checks if a given slot can be accessed at this time, either to equip or unequip I +/mob/living/carbon/human/slot_is_accessible(var/slot, var/obj/item/I, mob/user=null) + var/obj/item/covering = null + var/check_flags = 0 + + switch(slot) + if(slot_wear_mask) + covering = src.head + check_flags = FACE + if(slot_glasses) + covering = src.head + check_flags = EYES + if(slot_gloves, slot_w_uniform) + covering = src.wear_suit + + if(covering && (covering.body_parts_covered & (I.body_parts_covered|check_flags))) + to_chat(user, "\The [covering] is in the way.") + return 0 + return 1 + +/mob/living/carbon/human/get_equipped_item(var/slot) + switch(slot) + if(slot_back) return back + if(slot_handcuffed) return handcuffed + if(slot_l_store) return l_store + if(slot_r_store) return r_store + if(slot_wear_mask) return wear_mask + if(slot_l_hand) return l_hand + if(slot_r_hand) return r_hand + if(slot_wear_id) return wear_id + if(slot_glasses) return glasses + if(slot_gloves) return gloves + if(slot_head) return head + if(slot_shoes) return shoes + if(slot_belt) return belt + if(slot_wear_suit) return wear_suit + if(slot_w_uniform) return w_uniform + if(slot_s_store) return s_store + if(slot_l_ear) return l_ear + if(slot_r_ear) return r_ear + return ..() + +/mob/living/carbon/human/get_equipped_items(var/include_carried = 0) + . = ..() + if(belt) . += belt + if(l_ear) . += l_ear + if(r_ear) . += r_ear + if(glasses) . += glasses + if(gloves) . += gloves + if(head) . += head + if(shoes) . += shoes + if(wear_id) . += wear_id + if(wear_suit) . += wear_suit + if(w_uniform) . += w_uniform + + if(include_carried) + if(l_store) . += l_store + if(r_store) . += r_store + if(handcuffed) . += handcuffed + if(s_store) . += s_store + +#undef REMOVE_INTERNALS diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm new file mode 100644 index 00000000..c1d23333 --- /dev/null +++ b/code/modules/mob/living/carbon/human/life.dm @@ -0,0 +1,1390 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +//NOTE: Breathing happens once per FOUR TICKS, unless the last breath fails. In which case it happens once per ONE TICK! So oxyloss healing is done once per 4 ticks while oxyloss damage is applied once per tick! +#define HUMAN_MAX_OXYLOSS 1 //Defines how much oxyloss humans can get per tick. A tile with no air at all (such as space) applies this value, otherwise it's a percentage of it. + +#define HUMAN_CRIT_TIME_CUSHION (10 MINUTES) //approximate time limit to stabilize someone in crit +#define HUMAN_CRIT_HEALTH_CUSHION (config.health_threshold_crit - config.health_threshold_dead) + +//The amount of damage you'll get when in critical condition. We want this to be a HUMAN_CRIT_TIME_CUSHION long deal. +//There are HUMAN_CRIT_HEALTH_CUSHION hp to get through, so (HUMAN_CRIT_HEALTH_CUSHION/HUMAN_CRIT_TIME_CUSHION) per tick. +//Breaths however only happen once every MOB_BREATH_DELAY life ticks. The delay between life ticks is set by the mob process. +#define HUMAN_CRIT_MAX_OXYLOSS ( MOB_BREATH_DELAY * process_schedule_interval("mob") * (HUMAN_CRIT_HEALTH_CUSHION/HUMAN_CRIT_TIME_CUSHION) ) + +#define HEAT_DAMAGE_LEVEL_1 2 //Amount of damage applied when your body temperature just passes the 360.15k safety point +#define HEAT_DAMAGE_LEVEL_2 4 //Amount of damage applied when your body temperature passes the 400K point +#define HEAT_DAMAGE_LEVEL_3 8 //Amount of damage applied when your body temperature passes the 1000K point + +#define COLD_DAMAGE_LEVEL_1 0.5 //Amount of damage applied when your body temperature just passes the 260.15k safety point +#define COLD_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when your body temperature passes the 200K point +#define COLD_DAMAGE_LEVEL_3 3 //Amount of damage applied when your body temperature passes the 120K point + +//Note that gas heat damage is only applied once every FOUR ticks. +#define HEAT_GAS_DAMAGE_LEVEL_1 2 //Amount of damage applied when the current breath's temperature just passes the 360.15k safety point +#define HEAT_GAS_DAMAGE_LEVEL_2 4 //Amount of damage applied when the current breath's temperature passes the 400K point +#define HEAT_GAS_DAMAGE_LEVEL_3 8 //Amount of damage applied when the current breath's temperature passes the 1000K point + +#define COLD_GAS_DAMAGE_LEVEL_1 0.5 //Amount of damage applied when the current breath's temperature just passes the 260.15k safety point +#define COLD_GAS_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when the current breath's temperature passes the 200K point +#define COLD_GAS_DAMAGE_LEVEL_3 3 //Amount of damage applied when the current breath's temperature passes the 120K point + +#define RADIATION_SPEED_COEFFICIENT 0.025 + +/mob/living/carbon/human + var/oxygen_alert = 0 + var/phoron_alert = 0 + var/co2_alert = 0 + var/fire_alert = 0 + var/pressure_alert = 0 + var/temperature_alert = 0 + var/heartbeat = 0 + +/mob/living/carbon/human/Life() + set invisibility = 0 + set background = BACKGROUND_ENABLED + + if (transforming) + return + + fire_alert = 0 //Reset this here, because both breathe() and handle_environment() have a chance to set it. + + //TODO: seperate this out + // update the current life tick, can be used to e.g. only do something every 4 ticks + life_tick++ + + ..() + + if(life_tick%30==15) + hud_updateflag = 1022 + + voice = GetVoice() + + if(slurring && !slur_loop) + sound_to(src, sound('sound/effects/beer_effect_loop.ogg', repeat = 1, wait = 0, volume = 70, channel = 3)) + slur_loop = TRUE + + if(!slurring) + sound_to(src, sound(null, repeat = 1, wait = 0, volume = 70, channel = 3)) + slur_loop = FALSE + + if(ear_deaf && !deaf_loop) + sound_to(src, sound('sound/effects/ear_ring.ogg', repeat = 1, wait = 0, volume = 5, channel = 4)) + deaf_loop = TRUE + + if(!ear_deaf) + sound_to(src, sound(null, repeat = 1, wait = 0, volume = 70, channel = 4)) + deaf_loop = FALSE + + if(istype(loc, /turf/simulated/floor/exoplanet/water/shallow))//People who are on fire go out. + ExtinguishMob() + + //No need to update all of these procs if the guy is dead. + if(stat != DEAD && !InStasis()) + //Updates the number of stored chemicals for powers + handle_changeling() + + //Organs and blood + handle_organs() + + stabilize_body_temperature() //Body temperature adjusts itself (self-regulation) + + handle_shock() + + handle_pain() + + handle_medical_side_effects() + + handle_diagonostic_signs() + + update_aim_icon() + + handle_warfare_life() + + handle_gas_mask_sound()//Was in breathing, but people don't breathe anymore. + + if(!client && !mind) + species.handle_npc(src) + + + + if(!handle_some_updates()) + return //We go ahead and process them 5 times for HUD images and other stuff though. + + //Update our name based on whether our face is obscured/disfigured + SetName(get_visible_name()) + +/mob/living/carbon/human/set_stat(var/new_stat) + . = ..() + if(stat) + update_skin(1) + +/mob/living/carbon/human/proc/handle_some_updates() + if(life_tick > 5 && timeofdeath && (timeofdeath < 5 || world.time - timeofdeath > 6000)) //We are long dead, or we're junk mobs spawned like the clowns on the clown shuttle + return 0 + return 1 + +/mob/living/carbon/proc/check_drowning() + if(lying && istype(loc, /turf/simulated/floor/exoplanet/water/shallow)) + losebreath++ //= max(losebreath + 2, 3) + +/mob/living/carbon/human/breathe() + var/species_organ = species.breathing_organ + + if(species_organ) + var/active_breaths = 0 + var/obj/item/organ/internal/lungs/L = internal_organs_by_name[species_organ] + if(L) + active_breaths = L.active_breathing + ..(active_breaths) + +// Calculate how vulnerable the human is to under- and overpressure. +// Returns 0 (equals 0 %) if sealed in an undamaged suit, 1 if unprotected (equals 100%). +// Suitdamage can modifiy this in 10% steps. +/mob/living/carbon/human/proc/get_pressure_weakness() + + var/pressure_adjustment_coefficient = 1 // Assume no protection at first. + + if(wear_suit && (wear_suit.item_flags & ITEM_FLAG_STOPPRESSUREDAMAGE) && head && (head.item_flags & ITEM_FLAG_STOPPRESSUREDAMAGE)) // Complete set of pressure-proof suit worn, assume fully sealed. + pressure_adjustment_coefficient = 0 + + // Handles breaches in your space suit. 10 suit damage equals a 100% loss of pressure protection. + if(istype(wear_suit,/obj/item/clothing/suit/space)) + var/obj/item/clothing/suit/space/S = wear_suit + if(S.can_breach && S.damage) + pressure_adjustment_coefficient += S.damage * 0.1 + + pressure_adjustment_coefficient = min(1,max(pressure_adjustment_coefficient,0)) // So it isn't less than 0 or larger than 1. + + return pressure_adjustment_coefficient + +// Calculate how much of the enviroment pressure-difference affects the human. +/mob/living/carbon/human/calculate_affecting_pressure(var/pressure) + var/pressure_difference + + // First get the absolute pressure difference. + if(pressure < ONE_ATMOSPHERE) // We are in an underpressure. + pressure_difference = ONE_ATMOSPHERE - pressure + + else //We are in an overpressure or standard atmosphere. + pressure_difference = pressure - ONE_ATMOSPHERE + + if(pressure_difference < 5) // If the difference is small, don't bother calculating the fraction. + pressure_difference = 0 + + else + // Otherwise calculate how much of that absolute pressure difference affects us, can be 0 to 1 (equals 0% to 100%). + // This is our relative difference. + pressure_difference *= get_pressure_weakness() + + // The difference is always positive to avoid extra calculations. + // Apply the relative difference on a standard atmosphere to get the final result. + // The return value will be the adjusted_pressure of the human that is the basis of pressure warnings and damage. + if(pressure < ONE_ATMOSPHERE) + return ONE_ATMOSPHERE - pressure_difference + else + return ONE_ATMOSPHERE + pressure_difference + +/mob/living/carbon/human/handle_impaired_vision() + ..() + //Vision + var/obj/item/organ/vision + if(species.vision_organ) + vision = internal_organs_by_name[species.vision_organ] + + if(!species.vision_organ) // 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 || (vision && !vision.is_usable())) // 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) + +/mob/living/carbon/human/handle_disabilities() + ..() + if(stat != DEAD) + if ((disabilities & COUGHING) && prob(5) && paralysis <= 1) + drop_item() + spawn(0) + emote("cough") + +/mob/living/carbon/human/handle_mutations_and_radiation() + if(getFireLoss()) + if((COLD_RESISTANCE in mutations) || (prob(1))) + heal_organ_damage(0,1) + + // DNA2 - Gene processing. + // The HULK stuff that was here is now in the hulk gene. + for(var/datum/dna/gene/gene in dna_genes) + if(!gene.block) + continue + if(gene.is_active(src)) + gene.OnMobLife(src) + + radiation = Clamp(radiation,0,500) + + if(!radiation) + if(species.appearance_flags & RADIATION_GLOWS) + set_light(0) + else + if(species.appearance_flags & RADIATION_GLOWS) + set_light(max(1,min(10,radiation/10)), max(1,min(20,radiation/20)), species.get_flesh_colour(src)) + // END DOGSHIT SNOWFLAKE + + var/damage = 0 + radiation -= 1 * RADIATION_SPEED_COEFFICIENT + if(prob(25)) + damage = 2 + + if (radiation > 50) + damage = 2 + radiation -= 2 * RADIATION_SPEED_COEFFICIENT + if(!isSynthetic()) + if(prob(5) && prob(100 * RADIATION_SPEED_COEFFICIENT)) + radiation -= 5 * RADIATION_SPEED_COEFFICIENT + to_chat(src, "You feel weak.") + Weaken(3) + if(!lying) + emote("collapse") + if(prob(5) && prob(100 * RADIATION_SPEED_COEFFICIENT) && species.get_bodytype(src) == SPECIES_HUMAN) //apes go bald + if((h_style != "Bald" || f_style != "Shaved" )) + to_chat(src, "Your hair falls out.") + h_style = "Bald" + f_style = "Shaved" + update_hair() + + if (radiation > 75) + damage = 3 + radiation -= 3 * RADIATION_SPEED_COEFFICIENT + if(!isSynthetic()) + if(prob(5)) + take_overall_damage(0, 5 * RADIATION_SPEED_COEFFICIENT, used_weapon = "Radiation Burns") + if(prob(1)) + to_chat(src, "You feel strange!") + adjustCloneLoss(5 * RADIATION_SPEED_COEFFICIENT) + emote("gasp") + gasp_sound() + if(radiation > 150) + damage = 8 + radiation -= 4 * RADIATION_SPEED_COEFFICIENT + + if(damage) + damage *= isSynthetic() ? 0.5 : species.radiation_mod + adjustToxLoss(damage * RADIATION_SPEED_COEFFICIENT) + updatehealth() + if(!isSynthetic() && organs.len) + var/obj/item/organ/external/O = pick(organs) + if(istype(O)) O.add_autopsy_data("Radiation Poisoning", damage) + + /** breathing **/ + +/mob/living/carbon/human/handle_chemical_smoke(var/datum/gas_mixture/environment) + if(wear_mask && (wear_mask.item_flags & ITEM_FLAG_BLOCK_GAS_SMOKE_EFFECT)) + return + if(glasses && (glasses.item_flags & ITEM_FLAG_BLOCK_GAS_SMOKE_EFFECT)) + return + if(head && (head.item_flags & ITEM_FLAG_BLOCK_GAS_SMOKE_EFFECT)) + return + ..() + +/mob/living/carbon/human/handle_post_breath(datum/gas_mixture/breath) + ..() + //spread some viruses while we are at it + if(breath && !internal && virus2.len > 0 && prob(10)) + for(var/mob/living/carbon/M in view(1,src)) + src.spread_disease_to(M) + + +/mob/living/carbon/human/get_breath_from_internal(volume_needed=STD_BREATH_VOLUME) + if(internal) + + if ((!contents.Find(internal) || !((wear_mask && (wear_mask.item_flags & ITEM_FLAG_AIRTIGHT)) || (head && (head.item_flags & ITEM_FLAG_AIRTIGHT))))) + internal = null + + if(internal) + return internal.remove_air_volume(volume_needed) + else if(internals) + internals.icon_state = "internal0" + return null + +/mob/living/carbon/human/handle_breath(datum/gas_mixture/breath) + if(status_flags & GODMODE) + return + var/species_organ = species.breathing_organ + if(!species_organ) + return + + var/obj/item/organ/internal/lungs/L = internal_organs_by_name[species_organ] + if(!L || nervous_system_failure()) + failed_last_breath = 1 + else + failed_last_breath = L.handle_breath(breath) //if breath is null or vacuum, the lungs will handle it for us + return !failed_last_breath + +/mob/living/carbon/human/handle_environment(datum/gas_mixture/environment) + if(!environment) + return + + //Stuff like the xenomorph's plasma regen happens here. + species.handle_environment_special(src) + + //Moved pressure calculations here for use in skip-processing check. + var/pressure = environment.return_pressure() + var/adjusted_pressure = calculate_affecting_pressure(pressure) + + //Check for contaminants before anything else because we don't want to skip it. + for(var/g in environment.gas) + if(gas_data.flags[g] & XGM_GAS_CONTAMINANT && environment.gas[g] > gas_data.overlay_limit[g] + 1) + pl_effects() + break + + if(istype(src.loc, /turf/space)) //being in a closet will interfere with radiation, may not make sense but we don't model radiation for atoms in general so it will have to do for now. + //Don't bother if the temperature drop is less than 0.1 anyways. Hopefully BYOND is smart enough to turn this constant expression into a constant + if(bodytemperature > (0.1 * HUMAN_HEAT_CAPACITY/(HUMAN_EXPOSED_SURFACE_AREA*STEFAN_BOLTZMANN_CONSTANT))**(1/4) + COSMIC_RADIATION_TEMPERATURE) + + //Thermal radiation into space + var/heat_gain = get_thermal_radiation(bodytemperature, HUMAN_EXPOSED_SURFACE_AREA, 0.5, SPACE_HEAT_TRANSFER_COEFFICIENT) + + var/temperature_gain = heat_gain/HUMAN_HEAT_CAPACITY + bodytemperature += temperature_gain //temperature_gain will often be negative + + var/relative_density = (environment.total_moles/environment.volume) / (MOLES_CELLSTANDARD/CELL_VOLUME) + if(relative_density > 0.02) //don't bother if we are in vacuum or near-vacuum + var/loc_temp = environment.temperature + + if(adjusted_pressure < species.warning_high_pressure && adjusted_pressure > species.warning_low_pressure && abs(loc_temp - bodytemperature) < 20 && bodytemperature < species.heat_level_1 && bodytemperature > species.cold_level_1 && species.body_temperature) + pressure_alert = 0 + return // Temperatures are within normal ranges, fuck all this processing. ~Ccomp + + //Body temperature adjusts depending on surrounding atmosphere based on your thermal protection (convection) + var/temp_adj = 0 + if(loc_temp < bodytemperature) //Place is colder than we are + var/thermal_protection = get_cold_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. + if(thermal_protection < 1) + temp_adj = (1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_COLD_DIVISOR) //this will be negative + else if (loc_temp > bodytemperature) //Place is hotter than we are + var/thermal_protection = get_heat_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. + if(thermal_protection < 1) + temp_adj = (1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR) + + //Use heat transfer as proportional to the gas density. However, we only care about the relative density vs standard 101 kPa/20 C air. Therefore we can use mole ratios + bodytemperature += between(BODYTEMP_COOLING_MAX, temp_adj*relative_density, BODYTEMP_HEATING_MAX) + + // +/- 50 degrees from 310.15K is the 'safe' zone, where no damage is dealt. + if(bodytemperature >= getSpeciesOrSynthTemp(HEAT_LEVEL_1)) + //Body temperature is too hot. + fire_alert = max(fire_alert, 1) + if(status_flags & GODMODE) return 1 //godmode + var/burn_dam = 0 + if(bodytemperature < getSpeciesOrSynthTemp(HEAT_LEVEL_1)) + burn_dam = HEAT_DAMAGE_LEVEL_1 + else if(bodytemperature < getSpeciesOrSynthTemp(HEAT_LEVEL_3)) + burn_dam = HEAT_DAMAGE_LEVEL_2 + else + burn_dam = HEAT_DAMAGE_LEVEL_3 + take_overall_damage(burn=burn_dam, used_weapon = "High Body Temperature") + fire_alert = max(fire_alert, 2) + + else if(bodytemperature <= getSpeciesOrSynthTemp(COLD_LEVEL_1)) + fire_alert = max(fire_alert, 1) + if(status_flags & GODMODE) return 1 //godmode + + var/burn_dam = 0 + + if(bodytemperature > getSpeciesOrSynthTemp(COLD_LEVEL_2)) + burn_dam = COLD_DAMAGE_LEVEL_1 + else if(bodytemperature > getSpeciesOrSynthTemp(COLD_LEVEL_3)) + burn_dam = COLD_DAMAGE_LEVEL_2 + else + burn_dam = COLD_DAMAGE_LEVEL_3 + SetStasis(getCryogenicFactor(bodytemperature), STASIS_COLD) + if(!chem_effects[CE_CRYO]) + take_overall_damage(burn=burn_dam, used_weapon = "Low Body Temperature") + fire_alert = max(fire_alert, 1) + + // Account for massive pressure differences. Done by Polymorph + // Made it possible to actually have something that can protect against high pressure... Done by Errorage. Polymorph now has an axe sticking from his head for his previous hardcoded nonsense! + if(status_flags & GODMODE) return 1 //godmode + + if(adjusted_pressure >= species.hazard_high_pressure) + var/pressure_damage = min( ( (adjusted_pressure / species.hazard_high_pressure) -1 )*PRESSURE_DAMAGE_COEFFICIENT , MAX_HIGH_PRESSURE_DAMAGE) + take_overall_damage(brute=pressure_damage, used_weapon = "High Pressure") + pressure_alert = 2 + else if(adjusted_pressure >= species.warning_high_pressure) + pressure_alert = 1 + else if(adjusted_pressure >= species.warning_low_pressure) + pressure_alert = 0 + else if(adjusted_pressure >= species.hazard_low_pressure) + pressure_alert = -1 + else + take_overall_damage(brute=LOW_PRESSURE_DAMAGE, used_weapon = "Low Pressure") + if(getOxyLoss() < 55) // 11 OxyLoss per 4 ticks when wearing internals; unconsciousness in 16 ticks, roughly half a minute + adjustOxyLoss(4) // 16 OxyLoss per 4 ticks when no internals present; unconsciousness in 13 ticks, roughly twenty seconds + pressure_alert = -2 + + return + +/mob/living/carbon/human/proc/stabilize_body_temperature() + // We produce heat naturally. + if (species.passive_temp_gain) + bodytemperature += species.passive_temp_gain + + // Robolimbs cause overheating too. + if(robolimb_count) + bodytemperature += round(robolimb_count/2) + + if (species.body_temperature == null || isSynthetic()) + return //this species doesn't have metabolic thermoregulation + + var/body_temperature_difference = species.body_temperature - bodytemperature + + if (abs(body_temperature_difference) < 0.5) + return //fuck this precision + + if (on_fire) + return //too busy for pesky metabolic regulation + + if(bodytemperature < species.cold_level_1) //260.15 is 310.15 - 50, the temperature where you start to feel effects. + if(nutrition >= 2) //If we are very, very cold we'll use up quite a bit of nutriment to heat us up. + nutrition -= 2 + var/recovery_amt = max((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), BODYTEMP_AUTORECOVERY_MINIMUM) +// log_debug("Cold. Difference = [body_temperature_difference]. Recovering [recovery_amt]") + bodytemperature += recovery_amt + else if(species.cold_level_1 <= bodytemperature && bodytemperature <= species.heat_level_1) + var/recovery_amt = body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR +// log_debug("Norm. Difference = [body_temperature_difference]. Recovering [recovery_amt]") + bodytemperature += recovery_amt + else if(bodytemperature > species.heat_level_1) //360.15 is 310.15 + 50, the temperature where you start to feel effects. + //We totally need a sweat system cause it totally makes sense...~ + var/recovery_amt = min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM) //We're dealing with negative numbers +// log_debug("Hot. Difference = [body_temperature_difference]. Recovering [recovery_amt]") + bodytemperature += recovery_amt + + //This proc returns a number made up of the flags for body parts which you are protected on. (such as HEAD, UPPER_TORSO, LOWER_TORSO, etc. See setup.dm for the full list) +/mob/living/carbon/human/proc/get_heat_protection_flags(temperature) //Temperature is the temperature you're being exposed to. + . = 0 + //Handle normal clothing + for(var/obj/item/clothing/C in list(head,wear_suit,w_uniform,shoes,gloves,wear_mask)) + if(C) + if(C.max_heat_protection_temperature && C.max_heat_protection_temperature >= temperature) + . |= C.heat_protection + +//See proc/get_heat_protection_flags(temperature) for the description of this proc. +/mob/living/carbon/human/proc/get_cold_protection_flags(temperature) + . = 0 + //Handle normal clothing + for(var/obj/item/clothing/C in list(head,wear_suit,w_uniform,shoes,gloves,wear_mask)) + if(C) + if(C.min_cold_protection_temperature && C.min_cold_protection_temperature <= temperature) + . |= C.cold_protection + +/mob/living/carbon/human/get_heat_protection(temperature) //Temperature is the temperature you're being exposed to. + var/thermal_protection_flags = get_heat_protection_flags(temperature) + return get_thermal_protection(thermal_protection_flags) + +/mob/living/carbon/human/get_cold_protection(temperature) + if(COLD_RESISTANCE in mutations) + return 1 //Fully protected from the cold. + + temperature = max(temperature, 2.7) //There is an occasional bug where the temperature is miscalculated in ares with a small amount of gas on them, so this is necessary to ensure that that bug does not affect this calculation. Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K. + var/thermal_protection_flags = get_cold_protection_flags(temperature) + return get_thermal_protection(thermal_protection_flags) + +/mob/living/carbon/human/proc/get_thermal_protection(var/flags) + .=0 + if(flags) + if(flags & HEAD) + . += THERMAL_PROTECTION_HEAD + if(flags & UPPER_TORSO) + . += THERMAL_PROTECTION_UPPER_TORSO + if(flags & LOWER_TORSO) + . += THERMAL_PROTECTION_LOWER_TORSO + if(flags & LEG_LEFT) + . += THERMAL_PROTECTION_LEG_LEFT + if(flags & LEG_RIGHT) + . += THERMAL_PROTECTION_LEG_RIGHT + if(flags & FOOT_LEFT) + . += THERMAL_PROTECTION_FOOT_LEFT + if(flags & FOOT_RIGHT) + . += THERMAL_PROTECTION_FOOT_RIGHT + if(flags & ARM_LEFT) + . += THERMAL_PROTECTION_ARM_LEFT + if(flags & ARM_RIGHT) + . += THERMAL_PROTECTION_ARM_RIGHT + if(flags & HAND_LEFT) + . += THERMAL_PROTECTION_HAND_LEFT + if(flags & HAND_RIGHT) + . += THERMAL_PROTECTION_HAND_RIGHT + return min(1,.) + +/mob/living/carbon/human/handle_chemicals_in_body() + + chem_effects.Cut() + + if(status_flags & GODMODE) + return 0 + + if(isSynthetic()) + return + + if(reagents) + if(touching) touching.metabolize() + if(ingested) ingested.metabolize() + if(bloodstr) bloodstr.metabolize() + + // Trace chemicals + for(var/T in chem_doses) + if(bloodstr.has_reagent(T) || ingested.has_reagent(T) || touching.has_reagent(T)) + continue + var/datum/reagent/R = T + chem_doses[T] -= initial(R.metabolism)*2 + if(chem_doses[T] <= 0) + chem_doses -= T + + updatehealth() + + return //TODO: DEFERRED + +// Check if we should die. +/mob/living/carbon/human/proc/handle_death_check() + if(should_have_organ(BP_BRAIN) && !has_fake_brain()) + var/obj/item/organ/internal/brain/brain = internal_organs_by_name[BP_BRAIN] + if(!brain || (brain.status & ORGAN_DEAD)) + return TRUE + return species.handle_death_check(src) + +//DO NOT CALL handle_statuses() from this proc, it's called from living/Life() as long as this returns a true value. +/mob/living/carbon/human/handle_regular_status_updates() + if(!handle_some_updates()) + return 0 + + if(status_flags & GODMODE) return 0 + + //SSD check, if a logged player is awake put them back to sleep! + if(ssd_check() && species.get_ssd(src)) + Sleeping(2) + if(stat == DEAD) //DEAD. BROWN BREAD. SWIMMING WITH THE SPESS CARP + blinded = 1 + silent = 0 + handle_decay() + + else //ALIVE. LIGHTS ARE ON + updatehealth() //TODO + + if(handle_death_check()) + death() + blinded = 1 + silent = 0 + return 1 + + if(hallucination_power) + handle_hallucinations() + handle_combat_mode() + + handle_smelly_things() + + handle_happiness() + + if(get_shock() >= species.total_health) + if(!stat) + src.visible_message("[src] gives into the pain!") + agony_scream() + Paralyse(10) + + if(paralysis || sleeping) + blinded = 1 + set_stat(UNCONSCIOUS) + adjustHalLoss(-3) + + if(sleeping) + handle_dreams() + if (mind) + //Are they SSD? If so we'll keep them asleep but work off some of that sleep var in case of stoxin or similar. + if(client || sleeping > 3) + AdjustSleeping(-1) + if(prob(2) && !failed_last_breath && !isSynthetic()) + if(!paralysis) + emote("snore") + else + emote("groan") + if(prob(2) && is_asystole() && isSynthetic()) + visible_message(src, "[src] [pick("emits low pitched whirr","beeps urgently")]") + //CONSCIOUS + else + set_stat(CONSCIOUS) + + // Check everything else. + + //Periodically double-check embedded_flag + if(embedded_flag && !(life_tick % 10)) + if(!embedded_needs_process()) + embedded_flag = 0 + + //Resting + if(resting) + dizziness = max(0, dizziness - 15) + jitteriness = max(0, jitteriness - 15) + adjustHalLoss(-3) + else + dizziness = max(0, dizziness - 3) + jitteriness = max(0, jitteriness - 3) + adjustHalLoss(-1) + + if (drowsyness > 0) + drowsyness = max(0, drowsyness-1) + eye_blurry = max(2, eye_blurry) + if (drowsyness > 10 && (prob(5) || drowsyness >= 60)) + if(stat == CONSCIOUS) + to_chat(src, "You are about to fall asleep...") + Sleeping(5) + + confused = max(0, confused - 1) + + // If you're dirty, your gloves will become dirty, too. + if(gloves && germ_level > gloves.germ_level && prob(10)) + gloves.germ_level += 1 + + if(vsc.plc.CONTAMINATION_LOSS) + var/total_phoronloss = 0 + for(var/obj/item/I in src) + if(I.contaminated) + total_phoronloss += vsc.plc.CONTAMINATION_LOSS + adjustToxLoss(total_phoronloss) + + // nutrition decrease + if (nutrition > 0) + nutrition = max (0, nutrition - species.hunger_factor) + + if(stasis_value > 1 && drowsyness < stasis_value * 5) + drowsyness += min(stasis_value, 3) + if(!stat && prob(1)) + to_chat(src, "You feel slow and sluggish...") + + CheckStamina() + + + return 1 + + +/mob/living/carbon/human/handle_regular_hud_updates() + if(hud_updateflag) // update our mob's hud overlays, AKA what others see flaoting above our head + handle_hud_list() + + // now handle what we see on our screen + + if(!..()) + return + + if(stat != DEAD) + if(stat == UNCONSCIOUS && health < maxHealth/2) + //Critical damage passage overlay + var/severity = 0 + switch(health - maxHealth/2) + if(-20 to -10) severity = 1 + if(-30 to -20) severity = 2 + if(-40 to -30) severity = 3 + if(-50 to -40) severity = 4 + if(-60 to -50) severity = 5 + if(-70 to -60) severity = 6 + if(-80 to -70) severity = 7 + if(-90 to -80) severity = 8 + if(-95 to -90) severity = 9 + if(-INFINITY to -95) severity = 10 + overlay_fullscreen("crit", /obj/screen/fullscreen/crit, severity) + else + clear_fullscreen("crit") + //Oxygen damage overlay + if(getOxyLoss()) + var/severity = 0 + switch(getOxyLoss()) + if(10 to 20) severity = 1 + if(20 to 25) severity = 2 + if(25 to 30) severity = 3 + if(30 to 35) severity = 4 + if(35 to 40) severity = 5 + if(40 to 45) severity = 6 + if(45 to INFINITY) severity = 7 + overlay_fullscreen("oxy", /obj/screen/fullscreen/oxy, severity) + else + clear_fullscreen("oxy") + + //Fire and Brute damage overlay (BSSR) + var/hurtdamage = src.getBruteLoss() + src.getFireLoss() + damageoverlaytemp + damageoverlaytemp = 0 // We do this so we can detect if someone hits us or not. + if(hurtdamage) + var/severity = 0 + switch(hurtdamage) + if(25 to 39) severity = 2 + if(40 to 50) severity = 3 + if(50 to 60) severity = 4 + if(60 to 70) severity = 5 + if(70 to 80) severity = 6 + if(80 to INFINITY) severity = 7 + overlay_fullscreen("brute", /obj/screen/fullscreen/damagenoise, severity) + else + clear_fullscreen("brute") + + if(happiness) + var/severity = 0 + switch(happiness) + if(MOOD_LEVEL_NEUTRAL to INFINITY) severity = 0 + if(MOOD_LEVEL_SAD3 to MOOD_LEVEL_SAD2) severity = 2 + if(-50 to MOOD_LEVEL_SAD4) severity = 3 + if(-INFINITY to -50) severity = 4 + if(happiness >= MOOD_LEVEL_NEUTRAL) + clear_fullscreen("mood") + else + overlay_fullscreen("mood", /obj/screen/fullscreen/mood_dark, severity) + + + if(healths) + if (chem_effects[CE_PAINKILLER] > 100) + healths.overlays.Cut() + healths.icon_state = "health_numb" + + else if(using_alt_hud)//If we're using Lunahud we want the lunahud health face. + var/mhealth = (getBruteLoss() + getFireLoss()) + switch(mhealth) + if(100 to INFINITY) healths.icon_state = "health6" + if(80 to 100) healths.icon_state = "health5" + if(60 to 80) healths.icon_state = "health4" + if(60 to 80) healths.icon_state = "health3" + if(40 to 60) healths.icon_state = "health2" + if(20 to 40) healths.icon_state = "health1" + if(0 to 20) healths.icon_state = "health0" + else + // Generate a by-limb health display. + healths.icon_state = "blank" + healths.overlays = null + + var/no_damage = 1 + var/trauma_val = 0 // Used in calculating softcrit/hardcrit indicators. + if(can_feel_pain()) + trauma_val = max(shock_stage,get_shock())/(species.total_health-100) + // Collect and apply the images all at once to avoid appearance churn. + var/list/health_images = list() + for(var/obj/item/organ/external/E in organs) + if(no_damage && (E.brute_dam || E.burn_dam)) + no_damage = 0 + health_images += E.get_damage_hud_image() + + // Apply a fire overlay if we're burning. + if(on_fire) + health_images += image('icons/mob/screen1_health.dmi',"burning") + + // Show a general pain/crit indicator if needed. + if(is_asystole()) + health_images += image('icons/mob/screen1_health.dmi',"hardcrit") + else if(trauma_val) + if(can_feel_pain()) + if(trauma_val > 0.7) + health_images += image('icons/mob/screen1_health.dmi',"softcrit") + if(trauma_val >= 1) + health_images += image('icons/mob/screen1_health.dmi',"hardcrit") + else if(no_damage) + health_images += image('icons/mob/screen1_health.dmi',"fullhealth") + + healths.overlays += health_images + + if(nutrition_icon) + switch(nutrition) + if(450 to INFINITY) nutrition_icon.icon_state = "nutrition0" + if(350 to 450) nutrition_icon.icon_state = "nutrition1" + if(250 to 350) nutrition_icon.icon_state = "nutrition2" + if(150 to 250) nutrition_icon.icon_state = "nutrition3" + else nutrition_icon.icon_state = "nutrition4" + if(hydration_icon) + switch(thirst) + if(THIRST_LEVEL_FILLED to THIRST_LEVEL_MAX) hydration_icon.icon_state = "hydration0" + if(THIRST_LEVEL_MEDIUM to THIRST_LEVEL_FILLED) hydration_icon.icon_state = "hydration1" + if(THIRST_LEVEL_THIRSTY to THIRST_LEVEL_MEDIUM) hydration_icon.icon_state = "hydration2" + if(THIRST_LEVEL_DEHYDRATED to THIRST_LEVEL_THIRSTY) hydration_icon.icon_state = "hydration3" + else hydration_icon.icon_state = "hydration4" + + + if(stamina_icon) + switch((staminaloss)) + if(200 to INFINITY) stamina_icon.icon_state = "stamina10" + if(180 to 200) stamina_icon.icon_state = "stamina9" + if(160 to 180) stamina_icon.icon_state = "stamina8" + if(140 to 160) stamina_icon.icon_state = "stamina7" + if(120 to 140) stamina_icon.icon_state = "stamina6" + if(100 to 120) stamina_icon.icon_state = "stamina5" + if(80 to 100) stamina_icon.icon_state = "stamina4" + if(60 to 80) stamina_icon.icon_state = "stamina3" + if(40 to 60) stamina_icon.icon_state = "stamina2" + if(20 to 40) stamina_icon.icon_state = "stamina1" + else stamina_icon.icon_state = "stamina0" + + if(isSynthetic()) + var/obj/item/organ/internal/cell/C = internal_organs_by_name[BP_CELL] + if (istype(C)) + var/chargeNum = Clamp(ceil(C.percent()/25), 0, 4) //0-100 maps to 0-4, but give it a paranoid clamp just in case. + cells.icon_state = "charge[chargeNum]" + else + cells.icon_state = "charge-empty" + + if(pressure) + pressure.icon_state = "pressure[pressure_alert]" + if(toxin) + if(phoron_alert) toxin.icon_state = "tox1" + else toxin.icon_state = "tox0" + if(oxygen) + if(oxygen_alert) oxygen.icon_state = "oxy1" + else oxygen.icon_state = "oxy0" + if(fire) + if(fire_alert) fire.icon_state = "fire[fire_alert]" //fire_alert is either 0 if no alert, 1 for cold and 2 for heat. + else fire.icon_state = "fire0" + + if(bodytemp) + if (!species) + switch(bodytemperature) //310.055 optimal body temp + if(370 to INFINITY) bodytemp.icon_state = "temp4" + if(350 to 370) bodytemp.icon_state = "temp3" + if(335 to 350) bodytemp.icon_state = "temp2" + if(320 to 335) bodytemp.icon_state = "temp1" + if(300 to 320) bodytemp.icon_state = "temp0" + if(295 to 300) bodytemp.icon_state = "temp-1" + if(280 to 295) bodytemp.icon_state = "temp-2" + if(260 to 280) bodytemp.icon_state = "temp-3" + else bodytemp.icon_state = "temp-4" + else + //TODO: precalculate all of this stuff when the species datum is created + var/base_temperature = species.body_temperature + if(base_temperature == null) //some species don't have a set metabolic temperature + base_temperature = (getSpeciesOrSynthTemp(HEAT_LEVEL_1) + getSpeciesOrSynthTemp(COLD_LEVEL_1))/2 + + var/temp_step + if (bodytemperature >= base_temperature) + temp_step = (getSpeciesOrSynthTemp(HEAT_LEVEL_1) - base_temperature)/4 + + if (bodytemperature >= getSpeciesOrSynthTemp(HEAT_LEVEL_1)) + bodytemp.icon_state = "temp4" + else if (bodytemperature >= base_temperature + temp_step*3) + bodytemp.icon_state = "temp3" + else if (bodytemperature >= base_temperature + temp_step*2) + bodytemp.icon_state = "temp2" + else if (bodytemperature >= base_temperature + temp_step*1) + bodytemp.icon_state = "temp1" + else + bodytemp.icon_state = "temp0" + + else if (bodytemperature < base_temperature) + temp_step = (base_temperature - getSpeciesOrSynthTemp(COLD_LEVEL_1))/4 + + if (bodytemperature <= getSpeciesOrSynthTemp(COLD_LEVEL_1)) + bodytemp.icon_state = "temp-4" + else if (bodytemperature <= base_temperature - temp_step*3) + bodytemp.icon_state = "temp-3" + else if (bodytemperature <= base_temperature - temp_step*2) + bodytemp.icon_state = "temp-2" + else if (bodytemperature <= base_temperature - temp_step*1) + bodytemp.icon_state = "temp-1" + else + bodytemp.icon_state = "temp0" + if(resting) + rest.icon_state = "rest1" + else + rest.icon_state = "rest0" + + return 1 + +/mob/living/carbon/human/handle_random_events() + // Puke if toxloss is too high + var/vomit_score = 0 + for(var/tag in list(BP_LIVER,BP_KIDNEYS)) + var/obj/item/organ/internal/I = internal_organs_by_name[tag] + if(I) + vomit_score += I.damage + else if (should_have_organ(tag)) + vomit_score += 45 + if(chem_effects[CE_TOXIN] || radiation) + vomit_score += 0.5 * getToxLoss() + if(chem_effects[CE_ALCOHOL_TOXIC]) + vomit_score += 10 * chem_effects[CE_ALCOHOL_TOXIC] + if(chem_effects[CE_ALCOHOL]) + vomit_score += 10 + if(stat != DEAD && vomit_score > 25 && prob(10)) + spawn vomit(1, vomit_score, vomit_score/25) + + //0% chance of playing a scary sound to someone who's in complete darkness + /*if(isturf(loc) && rand(1,1000) == 1) + var/turf/T = loc + if(T.get_lumcount() <= LIGHTING_SOFT_THRESHOLD) + playsound_local(src,pick(GLOB.scarySounds),50, 1, -1) + + + if(isturf(loc)) + var/turf/T = loc + if(T.get_lumcount() <= LIGHTING_SOFT_THRESHOLD) + if(!has_trait(/datum/trait/hardcore)) + add_event("dark", /datum/happiness_event/dark) + else + clear_event("dark") + + */ + + var/area/A = get_area(src) + if(client && world.time >= client.played + 600) + A.play_ambience(src) + if(stat == UNCONSCIOUS && world.time - l_move_time < 5 && prob(10)) + to_chat(src,"You feel like you're [pick("moving","flying","floating","falling","hovering")].") + +/mob/living/carbon/human/handle_stomach() + spawn(0) + for(var/a in stomach_contents) + if(!(a in contents) || isnull(a)) + stomach_contents.Remove(a) + continue + if(iscarbon(a)|| isanimal(a)) + var/mob/living/M = a + if(M.stat == DEAD) + M.death(1) + stomach_contents.Remove(M) + qdel(M) + continue + if(life_tick % 3 == 1) + if(!(M.status_flags & GODMODE)) + M.adjustBruteLoss(5) + nutrition += 10 + handle_excrement() + + if(nutrition < 100) //Nutrition is below 100 = starvation + + var/list/hunger_phrases = list( + "You feel weak and malnourished. You must find something to eat now!",\ + "You haven't eaten in ages, and your body feels weak! It's time to eat something.",\ + "You can barely remember the last time you had a proper, nutritional meal. Your body will shut down soon if you don't eat something!",\ + "Your body is running out of essential nutrients! You have to eat something soon.",\ + "If you don't eat something very soon, you're going to starve to death." + ) + + //When you're starving, the rate at which oxygen damage is healed is reduced by 80% (you only restore 1 oxygen damage per life tick, instead of 5) + + switch(nutrition) + if(STARVATION_NOTICE to STARVATION_MIN) //60-80 + if(sleeping) return + + //if(prob(2)) + // to_chat(src, "[pick("You're very hungry.","You really could use a meal right now.")]") + + if(STARVATION_WEAKNESS to STARVATION_NOTICE) //30-60 + if(sleeping) return + + if(prob(3)) //3% chance of a tiny amount of oxygen damage (1-10) + + adjustOxyLoss(rand(1,10)) + to_chat(src, "[pick(hunger_phrases)]") + + else if(prob(5)) //5% chance of being weakened + + eye_blurry += 10 + Weaken(10) + adjustOxyLoss(rand(1,15)) + to_chat(src, "You're starving! The lack of strength makes you black out for a few moments...") + + if(STARVATION_NEARDEATH to STARVATION_WEAKNESS) //5-30, 5% chance of weakening and 1-230 oxygen damage. 5% chance of a seizure. 10% chance of dropping item + if(sleeping) return + + if(prob(5)) + + adjustOxyLoss(rand(1,20)) + to_chat(src, "You're starving. You feel your life force slowly leaving your body...") + eye_blurry += 20 + if(weakened < 1) Weaken(20) + + else if(paralysis<1 && prob(5)) //Mini seizure (25% duration and strength of a normal seizure) + + visible_message("\The [src] starts having a seizure!", \ + "You have a seizure!") + Paralyse(5) + adjustOxyLoss(rand(1,25)) + eye_blurry += 20 + + if(-INFINITY to STARVATION_NEARDEATH) //Fuck the whole body up at this point + to_chat(src, "You are dying from starvation!") + adjustToxLoss(STARVATION_TOX_DAMAGE) + adjustOxyLoss(STARVATION_OXY_DAMAGE) + adjustBrainLoss(STARVATION_BRAIN_DAMAGE) + + if(prob(10)) + Weaken(15) + +/mob/living/carbon/human/proc/handle_changeling() + if(mind && mind.changeling) + mind.changeling.regenerate() + +/mob/living/carbon/human/proc/handle_shock() + ..() + if(status_flags & GODMODE) return 0 //godmode + if(!can_feel_pain()) + shock_stage = 0 + return + + if(is_asystole()) + shock_stage = max(shock_stage, 61) + var/traumatic_shock = get_shock() + if(traumatic_shock >= max(30, 0.8*shock_stage)) + shock_stage += 1 + else + shock_stage = min(shock_stage, 160) + var/recovery = 1 + if(traumatic_shock < 0.5 * shock_stage) //lower shock faster if pain is gone completely + recovery++ + if(traumatic_shock < 0.25 * shock_stage) + recovery++ + shock_stage = max(shock_stage - recovery, 0) + return + if(stat) return 0 + + if(shock_stage == 10) + // Please be very careful when calling custom_pain() from within code that relies on pain/trauma values. There's the + // possibility of a feedback loop from custom_pain() being called with a positive power, incrementing pain on a limb, + // which triggers this proc, which calls custom_pain(), etc. Make sure you call it with 0 power in these cases! + custom_pain("[pick("It hurts so much", "You really need some painkillers", "Dear god, the pain")]!", 10, nohalloss = 0) + + if(shock_stage >= 30) + if(shock_stage == 30) + visible_message("[src] is having trouble keeping \his eyes open.") + if(prob(30)) + eye_blurry = max(2, eye_blurry) + stuttering = max(stuttering, 5) + + if(shock_stage == 40) + custom_pain("[pick("The pain is excruciating", "Please, just end the pain", "Your whole body is going numb")]!", 0) + src.agony_moan() + //emote("moan") + + if (shock_stage >= 60) + //if(shock_stage == 60) + // visible_message("[src]'s body becomes limp.") + if (prob(2)) + custom_pain("[pick("The pain is excruciating", "Please, just end the pain")]!", shock_stage, nohalloss = 0) + adjustStaminaLoss(20) + // flash_weak_pain() + // stuttering = max(stuttering, 5) + + if(shock_stage >= 80) + if (prob(5)) + custom_pain("[pick("The pain is excruciating", "Please, just end the pain")]!", shock_stage, nohalloss = 0) + adjustStaminaLoss(20) + // flash_weak_pain() + // stuttering = max(stuttering, 5) + + if(shock_stage >= 120) + if (prob(2)) + custom_pain("You feel like you could die any moment now", shock_stage, nohalloss = 0) + adjustStaminaLoss(20) + // flash_pain() + // stuttering = max(stuttering, 5) + + if(shock_stage == 150) + //visible_message("[src] can no longer stand, collapsing!") + adjustStaminaLoss(20)//Weaken(20) + + //if(shock_stage >= 150) + // Weaken(20) + +/* + Called by life(), instead of having the individual hud items update icons each tick and check for status changes + we only set those statuses and icons upon changes. Then those HUD items will simply add those pre-made images. + This proc below is only called when those HUD elements need to change as determined by the mobs hud_updateflag. +*/ + + +/mob/living/carbon/human/proc/handle_hud_list() + if (BITTEST(hud_updateflag, HEALTH_HUD) && hud_list[HEALTH_HUD]) + var/image/holder = hud_list[HEALTH_HUD] + if(stat == DEAD) + holder.icon_state = "0" // X_X + else if(is_asystole()) + holder.icon_state = "flatline" + else + holder.icon_state = "[pulse()]" + hud_list[HEALTH_HUD] = holder + + if (BITTEST(hud_updateflag, LIFE_HUD) && hud_list[LIFE_HUD]) + var/image/holder = hud_list[LIFE_HUD] + if(stat == DEAD) + holder.icon_state = "huddead" + else + holder.icon_state = "hudhealthy" + hud_list[LIFE_HUD] = holder + + if (BITTEST(hud_updateflag, STATUS_HUD) && hud_list[STATUS_HUD] && hud_list[STATUS_HUD_OOC]) + var/foundVirus = 0 + for (var/ID in virus2) + if (ID in virusDB) + foundVirus = 1 + break + + var/image/holder = hud_list[STATUS_HUD] + if(stat == DEAD) + holder.icon_state = "huddead" + else if(status_flags & XENO_HOST) + holder.icon_state = "hudxeno" + else if(foundVirus) + holder.icon_state = "hudill" + else if(has_brain_worms()) + var/mob/living/simple_animal/borer/B = has_brain_worms() + if(B.controlling) + holder.icon_state = "hudbrainworm" + else + holder.icon_state = "hudhealthy" + else + holder.icon_state = "hudhealthy" + + var/image/holder2 = hud_list[STATUS_HUD_OOC] + if(stat == DEAD) + holder2.icon_state = "huddead" + else if(status_flags & XENO_HOST) + holder2.icon_state = "hudxeno" + else if(has_brain_worms()) + holder2.icon_state = "hudbrainworm" + else if(virus2.len) + holder2.icon_state = "hudill" + else + holder2.icon_state = "hudhealthy" + + hud_list[STATUS_HUD] = holder + hud_list[STATUS_HUD_OOC] = holder2 + + if (BITTEST(hud_updateflag, ID_HUD) && hud_list[ID_HUD]) + var/image/holder = hud_list[ID_HUD] + holder.icon_state = "hudunknown" + if(wear_id) + var/obj/item/weapon/card/id/I = wear_id.GetIdCard() + if(I) + var/datum/job/J = job_master.GetJob(I.GetJobName()) + if(J) + holder.icon_state = J.hud_icon + + hud_list[ID_HUD] = holder + + if (BITTEST(hud_updateflag, WANTED_HUD) && hud_list[WANTED_HUD]) + var/image/holder = hud_list[WANTED_HUD] + holder.icon_state = "hudblank" + var/perpname = name + if(wear_id) + var/obj/item/weapon/card/id/I = wear_id.GetIdCard() + if(I) + perpname = I.registered_name + + var/datum/computer_file/crew_record/E = get_crewmember_record(perpname) + if(E) + switch(E.get_criminalStatus()) + if("Arrest") + holder.icon_state = "hudwanted" + if("Incarcerated") + holder.icon_state = "hudprisoner" + if("Parolled") + holder.icon_state = "hudparolled" + if("Released") + holder.icon_state = "hudreleased" + hud_list[WANTED_HUD] = holder + + if ( BITTEST(hud_updateflag, IMPLOYAL_HUD) \ + || BITTEST(hud_updateflag, IMPCHEM_HUD) \ + || BITTEST(hud_updateflag, IMPTRACK_HUD)) + + var/image/holder1 = hud_list[IMPTRACK_HUD] + var/image/holder2 = hud_list[IMPLOYAL_HUD] + var/image/holder3 = hud_list[IMPCHEM_HUD] + + holder1.icon_state = "hudblank" + holder2.icon_state = "hudblank" + holder3.icon_state = "hudblank" + + for(var/obj/item/weapon/implant/I in src) + if(I.implanted) + if(istype(I,/obj/item/weapon/implant/tracking)) + holder1.icon_state = "hud_imp_tracking" + if(istype(I,/obj/item/weapon/implant/loyalty)) + holder2.icon_state = "hud_imp_loyal" + if(istype(I,/obj/item/weapon/implant/chem)) + holder3.icon_state = "hud_imp_chem" + + hud_list[IMPTRACK_HUD] = holder1 + hud_list[IMPLOYAL_HUD] = holder2 + hud_list[IMPCHEM_HUD] = holder3 + + if (BITTEST(hud_updateflag, SPECIALROLE_HUD)) + var/image/holder = hud_list[SPECIALROLE_HUD] + holder.icon_state = "hudblank" + if(mind && mind.special_role) + if(GLOB.hud_icon_reference[mind.special_role]) + holder.icon_state = GLOB.hud_icon_reference[mind.special_role] + else + holder.icon_state = "hudsyndicate" + hud_list[SPECIALROLE_HUD] = holder + hud_updateflag = 0 + +/mob/living/carbon/human/handle_stunned() + if(!can_feel_pain()) + stunned = 0 + return 0 + return ..() + +/mob/living/carbon/human/handle_fire() + if(..()) + return + + var/burn_temperature = fire_burn_temperature() + var/thermal_protection = get_heat_protection(burn_temperature) + + if (thermal_protection < 1 && bodytemperature < burn_temperature) + bodytemperature += round(BODYTEMP_HEATING_MAX*(1-thermal_protection), 1) + + var/species_heat_mod = 1 + + var/protected_limbs = get_heat_protection_flags(burn_temperature) + + + if(species) + if(burn_temperature < species.heat_level_2) + species_heat_mod = 0.5 + else if(burn_temperature < species.heat_level_3) + species_heat_mod = 0.75 + + burn_temperature -= species.heat_level_1 + + if(burn_temperature < 1) + return + + for(var/obj/item/organ/external/E in organs) + if(!(E.body_part & protected_limbs) && prob(20)) + E.take_damage(burn = round(species_heat_mod * log(10, (burn_temperature + 10)), 0.1), used_weapon = fire) + +/mob/living/carbon/human/rejuvenate() + restore_blood() + full_prosthetic = null + shock_stage = 0 + if(job_master.GetJobByTitle(job)?.is_blue_team && !(src in SSWarfare.blue.team)) + SSWarfare.blue.team.Add(src) + if(job_master.GetJobByTitle(job)?.is_red_team && !(src in SSWarfare.red.team)) + SSWarfare.red.team.Add(src) + ..() + +/mob/living/carbon/human/reset_view(atom/A) + ..() + if(machine_visual && machine_visual != A) + machine_visual.remove_visual(src) + +/mob/living/carbon/human/handle_vision() + if(client) + client.screen.Remove(GLOB.global_hud.nvg, GLOB.global_hud.thermal, GLOB.global_hud.meson, GLOB.global_hud.science) + if(machine) + var/viewflags = machine.check_eye(src) + machine.apply_visual(src) + if(viewflags < 0) + reset_view(null, 0) + else if(viewflags) + set_sight(sight|viewflags) + else if(eyeobj) + if(eyeobj.owner != src) + reset_view(null) + else + var/isRemoteObserve = 0 + if(shadow && client.eye == shadow && !is_physically_disabled()) + isRemoteObserve = 1 + else 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_living_sight() + ..() + if(XRAY in mutations) + set_sight(sight|SEE_TURFS|SEE_MOBS|SEE_OBJS) + +/mob/living/carbon/human/proc/handle_decay() + var/decaytime = world.time - timeofdeath + + if(isSynthetic())//Synths don't rot. + return + + if(decaytime < 5 MINUTES)//They don't start rotting till after five minutes. + return + + if(decaytime >= 5 MINUTES && decaytime < 10 MINUTES)//5 minutes for decaylevel1 -- stinky + decaylevel = 1 + add_flies() + + if(decaytime >= 10 MINUTES && decaytime < 20 MINUTES)//10 minutes for decaylevel2 -- bloated and very stinky + decaylevel = 2 + + if(decaytime >= 25 MINUTES && decaytime < 30 MINUTES)//20 minutes for decaylevel3 -- rotting and gross + decaylevel = 3 + + if(decaytime > 30 MINUTES)//25 minutes for decaylevel4 -- skeleton + decaylevel = 4 + remove_flies() + ChangeToSkeleton() + return //No puking over skeletons, they don't smell at all! + + if(decaylevel && prob(5)) + playsound(src, 'sound/effects/buzz.ogg', 25, 1) + + + for(var/mob/living/carbon/human/H in hearers(5, src)) + if(prob(2)) + if(istype(loc,/obj/item/bodybag)) + continue + if(H.wear_mask) + continue + if(H.stat)//This shouldn't even need to be a fucking check. + continue + if(H.has_trait(/datum/trait/death_tolerant))//Hardcore people don't care about bodies. + continue + to_chat(H, "You smell something foul...") + H.add_event("disgust", /datum/happiness_event/disgust/verygross) + if(prob(75)) + H.vomit() + +//So that people will stop shitting in the fucking hallways all the time. Actually this will probably encourage them. +/mob/living/carbon/human/proc/handle_smelly_things() + if(wear_mask) + return + + if(/obj/effect/decal/cleanable/poo in range(3, src)) + if(prob(1)) + to_chat(src, "Something smells like shit...") + add_event("disgust", /datum/happiness_event/disgust/verygross) + if(prob(50)) + vomit() + + for(var/obj/item/weapon/reagent_containers/food/snacks/poo/P in range(5, src)) + if(istype(P.loc, /obj/machinery/disposal) || istype(P.loc, /obj/item/weapon/storage/bag)) + return + + if(prob(1)) + to_chat(src, "Something smells like shit...") + add_event("disgust", /datum/happiness_event/disgust/verygross) + if(prob(50)) + vomit() + + +/mob/living/carbon/human/proc/handle_gas_mask_sound() + if(wear_mask) + remove_coldbreath() + if(stat == DEAD) + return + if(istype(wear_mask, /obj/item/clothing/mask/gas)) + var/mask_sound = pick('sound/effects/gasmask1.ogg','sound/effects/gasmask2.ogg','sound/effects/gasmask3.ogg','sound/effects/gasmask4.ogg','sound/effects/gasmask5.ogg','sound/effects/gasmask6.ogg','sound/effects/gasmask7.ogg','sound/effects/gasmask8.ogg','sound/effects/gasmask9.ogg','sound/effects/gasmask10.ogg') + playsound(src, mask_sound, 50, 1) + + +/mob/living/carbon/human/proc/handle_diagonostic_signs() + // runs an update to check if we've become jaundiced, pale or low on oxygen resulting in icon changes + if(stat != DEAD && !(life_tick % 15)) // don't want to do this too often. update_body() also won't do anything if nothing has changed + update_body() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/login.dm b/code/modules/mob/living/carbon/human/login.dm new file mode 100644 index 00000000..ea44d6d1 --- /dev/null +++ b/code/modules/mob/living/carbon/human/login.dm @@ -0,0 +1,5 @@ +/mob/living/carbon/human/Login() + ..() + update_hud() + if(species) species.handle_login_special(src) + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/logout.dm b/code/modules/mob/living/carbon/human/logout.dm new file mode 100644 index 00000000..f449ce99 --- /dev/null +++ b/code/modules/mob/living/carbon/human/logout.dm @@ -0,0 +1,4 @@ +/mob/living/carbon/human/Logout() + ..() + if(species) species.handle_logout_special(src) + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/matt_combat.dm b/code/modules/mob/living/carbon/human/matt_combat.dm new file mode 100644 index 00000000..6217f7c6 --- /dev/null +++ b/code/modules/mob/living/carbon/human/matt_combat.dm @@ -0,0 +1,84 @@ +//Going here till I find a better place for it. +/mob/living/carbon/human/proc/handle_combat_mode()//Makes it so that you can't regain stamina in combat mode. + if(combat_mode) + if(staminaloss < (staminaexhaust/2)) + adjustStaminaLoss(2) + +/mob/living/carbon/human/proc/attempt_dodge()//Handle parry is an object proc and it's, its own thing. + var/dodge_modifier = 0 + if(combat_mode && (defense_intent == I_DODGE) && !lying)//Todo, make use of the check_shield_arc proc to make sure you can't dodge from behind. + if(atk_intent == I_DEFENSE)//Better chance to dodge + dodge_modifier += 30 + if(statscheck(STAT_LEVEL(dex) / 2 + 3) >= SUCCESS) + do_dodge() + return 1 + else if(prob(((SKILL_LEVEL(melee) * 10) / 2) + dodge_modifier)) + do_dodge() + return 1 + + //else if(CRIT_FAILURE) + // visible_message("[src.name] fails to dodge and falls on the floor!") + // Weaken(3) + + +/mob/living/proc/do_dodge() + var/lol = pick(GLOB.cardinal)//get a direction. + adjustStaminaLoss(15)//add some stamina loss + playsound(loc, 'sound/weapons/punchmiss.ogg', 80, 1)//play a sound + step(src,lol)//move them + visible_message("[src.name] dodges out of the way!!")//send a message + //be on our way + + +/mob/proc/surrender()//Surrending. I need to put this in a different file. + if(!incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_KNOCKOUT)) + Stun(5) + Weaken(5) + visible_message("[src] surrenders!") + playsound(src, 'sound/effects/surrender.ogg', 50, 1) + var/atom/movable/overlay/animation = new /atom/movable/overlay( loc ) + animation.icon_state = "blank" + animation.icon = 'icons/mob/screen1.dmi' + animation.master = src + flick("attention", animation) + qdel(animation) + +/mob/verb/mob_rest() + set hidden = 1 + set name = "mob rest" + if(resting && !stunned && !weakened) + var/turf/T = get_turf(src) + if(istype(T, /turf/simulated/floor/plating/n2floor)) + to_chat(src, "The ceiling is too low here to stand.") + return + + //The incapacitated proc includes resting for whatever fucking stupid reason I hate SS13 code so fucking much. + visible_message("[src] is trying to get up.") + if(do_after(src, 20, incapacitation_flags = INCAPACITATION_STUNNED|INCAPACITATION_KNOCKOUT))//So that we can get up when we're handcuffed. + resting = 0 + rest?.icon_state = "rest0" + update_canmove() + return + + else + resting = TRUE + update_canmove() + //For stopping runtimes with NPCs + rest?.icon_state = "rest1" + fixeye?.icon_state = "fixeye" + walk_to(src,0) + + +/client/verb/CombatModeToggle() + set hidden = 1 + + if(!ishuman(usr)) return + var/mob/living/carbon/human/C = usr + if(C.combat_mode) + usr << 'sound/effects/ui_toggleoff.ogg' + C.combat_mode = FALSE + C.combat_icon.icon_state = "combat0" + else + usr << 'sound/effects/ui_toggle.ogg' + C.combat_mode = TRUE + C.combat_icon.icon_state = "combat1" \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/npcs.dm b/code/modules/mob/living/carbon/human/npcs.dm new file mode 100644 index 00000000..3653f58a --- /dev/null +++ b/code/modules/mob/living/carbon/human/npcs.dm @@ -0,0 +1,396 @@ +#define cycle_pause 15 //min 1 +#define viewrange 9 //min 2 + +//HOSTILE NPC DEFINES CREDIT TO GUAP FOR THE FIRST ZOMBIE AI WRITEUP, AND TO GOON WHERE I'M SURE IT CAME FROM. +/mob/living/carbon/human + var/list/path = new/list() + var/frustration = 0 + var/atom/object_target + var/reach_unable + var/is_npc = 0 + var/mob/living/carbon/human/target + var/list/path_target = new/list() + var/list/path_idle = new/list() + var/list/objects + var/list/npc_attack_emote = list("yells!", "makes a scary noise!") + var/list/npc_attack_sound = list() + var/aggroed = TRUE + + + proc/aggro_npc() + if(!is_npc) + return + aggroed = TRUE + + + // this is called when the target is within one tile + // of distance from the hostile npc + proc/attack_target() + var/obj/item/I = get_active_hand() + var/obj/item/II = get_inactive_hand() + + if(target.stat != CONSCIOUS && prob(70) || target.is_npc) + target = null + return + + var/direct = get_dir(src, target) + if ( (direct - 1) & direct) + var/turf/Step_1 + var/turf/Step_2 + switch(direct) + if(EAST|NORTH) + Step_1 = get_step(src, NORTH) + Step_2 = get_step(src, EAST) + + if(EAST|SOUTH) + Step_1 = get_step(src, SOUTH) + Step_2 = get_step(src, EAST) + + if(NORTH|WEST) + Step_1 = get_step(src, NORTH) + Step_2 = get_step(src, WEST) + + if(SOUTH|WEST) + Step_1 = get_step(src, SOUTH) + Step_2 = get_step(src, WEST) + + if(Step_1 && Step_2) + var/check_1 = 1 + var/check_2 = 1 + + check_1 = Adjacent(get_turf(src), Step_1, target) && Adjacent(Step_1, get_turf(target), target) + + check_2 = Adjacent(get_turf(src), Step_2, target) && Adjacent(Step_2, get_turf(target), target) + + if(check_1 || check_2) + get_attack_type(I, II, target) + if(prob(30)) + custom_emote(2, pick(npc_attack_emote)) + if(npc_attack_sound.len) + playsound(src, pick(npc_attack_sound), 50, 0) + return + return + else + var/obj/structure/window/W = locate() in target.loc + var/obj/structure/window/WW = locate() in src.loc + if(W) + W.attack_hand(src) + if(prob(30)) + custom_emote(2, pick(npc_attack_emote)) + if(npc_attack_sound.len) + playsound(src, pick(npc_attack_sound), 50, 0) + return + return 1 + else if(WW) + WW.attack_hand(src) + if(prob(30)) + custom_emote(2, pick(npc_attack_emote)) + if(npc_attack_sound.len) + playsound(src, pick(npc_attack_sound), 50, 0) + return + return 1 + else if(Adjacent(src.loc , target.loc,target)) + get_attack_type(I, II, target)//target.attack_hand(src) + if(prob(30)) + custom_emote(2, pick(npc_attack_emote)) + if(npc_attack_sound.len) + playsound(src, pick(npc_attack_sound), 50, 0) + return + // sometimes push the enemy + //if(prob(30)) + // step(src,direct) + return 1 + else + var/obj/structure/window/W = locate() in target.loc + var/obj/structure/window/WW = locate() in src.loc + if(W) + W.attack_hand(src) + if(prob(30)) + custom_emote(2, pick(npc_attack_emote)) + if(npc_attack_sound.len) + playsound(src, pick(npc_attack_sound), 50, 0) + return + return 1 + else if(WW) + WW.attack_hand(src) + if(prob(30)) + custom_emote(2, pick(npc_attack_emote)) + if(npc_attack_sound.len) + playsound(src, pick(npc_attack_sound), 50, 0) + return + return 1 + + // main loop + proc/process() + set background = 1 + + if (stat) + walk_to(src, 0) + return 0 + + + if(weakened || paralysis || handcuffed) + walk_to(src, 0) + return 1 + + if(resting) + mob_rest() + return 1 + + if(!canmove) + return 1 + + setStaminaLoss(0)//So they don't wear themselves out. + if(!aggroed)//If they ain't angry then we don't want them searching for targets. + step(src, pick(GLOB.cardinal)) + return 1 + + if(destroy_on_path()) + return 1 + + if(!target) + // no target, and we're angery, look for a new one + + // look for a target, taking into consideration their health + // and distance from the npc + var/last_health = INFINITY + var/last_dist = INFINITY + + for (var/mob/living/carbon/human/C in orange(viewrange-2,src.loc)) + var/dist = get_dist(src, C) + + // if the npc can't directly see the human, they're + // probably blocked off by a wall, so act as if the + // human is further away + if(!(C in view(src, viewrange))) + dist += 3 + + if (C.stat == 2 || !can_see(src,C,viewrange)) + continue + if(C.stunned || C.paralysis || C.weakened) + target = C + break + if(C.health < last_health && dist <= last_dist) if(!prob(30)) + last_health = C.health + last_dist = dist + target = C + + // if we have found a target + if(target) + if(target.is_npc)// If the target is an NPC then search again. + target = null + return + + // change the target if there is another human that is closer + for (var/mob/living/carbon/human/C in orange(2,src.loc)) + if (C.stat == 2 || !can_see(src,C,viewrange)) + continue + if(get_dist(src, target) >= get_dist(src, C) && prob(30)) + target = C + break + + if(target.stat == 2) + target = null + + + var/distance = get_dist(src, target) + + if(target in orange(viewrange,src)) + if(distance <= 1) + if(attack_target()) + return 1 + else + walk_to(src, target, 1, 5) + return 1 + else + target = null + return 1 + + // if there is no target in range, roam randomly + else + frustration-- + frustration = max(frustration, 0) + + if(stat == 2) return 0 + + var/prev_loc = loc + // make sure they don't walk into space + if(!(locate(/turf/space) in get_step(src,dir))) + step(src,dir) + // if we couldn't move, pick a different direction + // also change the direction at random sometimes + if(loc == prev_loc || prob(20)) + sleep(5) + dir = pick(NORTH,SOUTH,EAST,WEST) + + return 1 + + // if we couldn't do anything, take a random step + step_rand(src) + dir = get_dir(src,target) // still face to the target + frustration++ + + return 1 + + // destroy items on the path + proc/destroy_on_path() + // if we already have a target, use that + if(object_target) + if(!object_target.density) + object_target = null + frustration = 0 + else + // we know the target has attack_hand + // since we only use such objects as the target + object_target:attack_hand(src) + if(prob(30)) + custom_emote(2, pick(npc_attack_emote)) + if(npc_attack_sound.len) + playsound(src, pick(npc_attack_sound), 50, 0) //But he will say one of the prepared words, or do an emote from say.dm + return + return 1 + + // first, try to destroy airlocks and walls that are in the way + if(locate(/obj/machinery/door/airlock) in get_step(src,src.dir)) + var/obj/machinery/door/airlock/D = locate() in get_step(src,src.dir) + if(D) + if(D.density && !(locate(/turf/space) in range(1,D)) ) + D.attack_hand(src) + object_target = D + if(prob(30)) + custom_emote(2, pick(npc_attack_emote)) + if(npc_attack_sound.len) + playsound(src, pick(npc_attack_sound), 50, 0) //But he will say one of the prepared words, or do an emote from say.dm + return + return 1 + // before clawing through walls, try to find a direct path first + if(frustration > 8 ) + if(istype(get_step(src,src.dir),/turf/simulated/wall)) + var/turf/simulated/wall/W = get_step(src,src.dir) + if(W) + if(W.density && !(locate(/turf/space) in range(1,W))) + W.attack_hand(src) + object_target = W + if(prob(30)) + custom_emote(2, pick(npc_attack_emote)) + if(npc_attack_sound.len) + playsound(src, pick(npc_attack_sound), 50, 0) //But he will say one of the prepared words, or do an emote from say.dm + return + return 1 + return 0 + + death() + ..() + target = null + + //This is the ugliest thing I have ever seen. + proc/get_attack_type(var/obj/item/I, var/obj/item/II, mob/living/carbon/human/target) + I = get_active_hand() + II = get_inactive_hand() + if(I) + target.attackby(I, src) + else if(II) + target.attackby(II, src) + else + target.attack_hand(src) + + +/mob/living/carbon/human/monkey/punpun/New() + ..() + name = "Pun Pun" + real_name = name + var/obj/item/clothing/C + if(prob(50)) + C = new /obj/item/clothing/under/punpun(src) + equip_to_appropriate_slot(C) + else + C = new /obj/item/clothing/under/punpants(src) + C.attach_accessory(null, new/obj/item/clothing/accessory/toggleable/hawaii/random(src)) + equip_to_appropriate_slot(C) + if(prob(10)) + C = new/obj/item/clothing/head/collectable/petehat(src) + equip_to_appropriate_slot(C) + +/decl/hierarchy/outfit/blank_subject + name = "Test Subject" + uniform = /obj/item/clothing/under/color/white + shoes = /obj/item/clothing/shoes/white + head = /obj/item/clothing/head/helmet/facecover + mask = /obj/item/clothing/mask/muzzle + suit = /obj/item/clothing/suit/straight_jacket + +/decl/hierarchy/outfit/blank_subject/post_equip(mob/living/carbon/human/H) + ..() + var/obj/item/clothing/under/color/white/C = locate() in H + if(C) + C.has_sensor = SUIT_LOCKED_SENSORS + C.sensor_mode = SUIT_SENSOR_OFF + +/mob/living/carbon/human/blank/New(var/new_loc) + ..(new_loc, "Vat-Grown Human") + +/mob/living/carbon/human/blank/Initialize() + . = ..() + var/number = "[pick(possible_changeling_IDs)]-[rand(1,30)]" + fully_replace_character_name("Subject [number]") + var/decl/hierarchy/outfit/outfit = outfit_by_type(/decl/hierarchy/outfit/blank_subject) + outfit.equip(src) + var/obj/item/clothing/head/helmet/facecover/F = locate() in src + if(F) + F.SetName("[F.name] ([number])") + +/mob/living/carbon/human/blank/ssd_check() + return FALSE + +//Hostile NPCs. + +//SKINLESS +/datum/species/human/skinless/handle_npc(var/mob/living/carbon/human/H)//DON'T SPAWN TOO MANY OF THESE PLEASE! + H.process() + +/mob/living/carbon/human/skinless/ssd_check() + return FALSE + +/mob/living/carbon/human/skinless/Initialize() + . = ..() + fully_replace_character_name(random_skinless_name(src.gender)) + zone_sel = new /obj/screen/zone_sel( null ) + zone_sel.selecting = pick("chest", "head") + warfare_faction = RED_TEAM + var/decl/hierarchy/outfit/outfit = outfit_by_type(/decl/hierarchy/outfit/job/redsoldier) + outfit.equip(src) + a_intent = I_HURT + npc_attack_sound = list('sound/voice/emotes/skinless1.ogg','sound/voice/emotes/skinless2.ogg','sound/voice/emotes/skinless3.ogg','sound/voice/emotes/skinless4.ogg','sound/voice/emotes/skinless5.ogg',) + + is_npc = 1//Make sure their an NPC so they don't attack each other. + hand = 0//Make sure one of their hands is active. + var/weapon = pick(/obj/item/weapon/crowbar, /obj/item/weapon/melee/classic_baton/trench_club, /obj/item/weapon/melee/classic_baton) + put_in_hands(new weapon)//Give them a weapon. + combat_mode = 1//Put them in combat mode. + STAT_LEVEL(dex) = 1 + +/datum/species/human/lackey/handle_npc(var/mob/living/carbon/human/H) + H.process() + +/mob/living/carbon/human/lackey/ssd_check() + return FALSE + +/mob/living/carbon/human/lackey/Initialize() + . = ..() + fully_replace_character_name(random_lackey_name()) + var/decl/hierarchy/outfit/outfit = outfit_by_type(/decl/hierarchy/outfit/lackey) + outfit.equip(src) + a_intent = I_HURT + aggroed = FALSE + + is_npc = 1//Make sure their an NPC so they don't attack each other. + hand = 0//Make sure one of their hands is active. + var/weapon = pick(/obj/item/weapon/crowbar, /obj/item/weapon/melee/classic_baton) + put_in_hands(new weapon)//Give them a weapon. + combat_mode = 1//Put them in combat mode. + STAT_LEVEL(dex) = 1 + +/decl/hierarchy/outfit/lackey + name = "Lackey" + uniform = /obj/item/clothing/under/color/grey + shoes = /obj/item/clothing/shoes/black \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm new file mode 100644 index 00000000..a8647988 --- /dev/null +++ b/code/modules/mob/living/carbon/human/say.dm @@ -0,0 +1,246 @@ +/mob/living/carbon/human/say(var/message, var/datum/language/speaking = null, whispering) + if(name != GetVoice()) + if(get_id_name("Unknown") == GetVoice()) + SetName(get_id_name("Unknown")) + + //parse the language code and consume it + if(!speaking) + speaking = parse_language(message) + if (speaking) + message = copytext(message,2+length(speaking.key)) + else + speaking = get_default_language() + + message = sanitize(message) + var/obj/item/organ/internal/voicebox/vox = locate() in internal_organs + var/snowflake_speak = (speaking && (speaking.flags & NONVERBAL|SIGNLANG)) || (vox && vox.is_usable() && (speaking in vox.assists_languages)) + last_words = message + if(!isSynthetic() && need_breathe() && failed_last_breath && !snowflake_speak) + var/obj/item/organ/internal/lungs/L = internal_organs_by_name[species.breathing_organ] + if(L.breath_fail_ratio > 0.9) + if(world.time < L.last_failed_breath + 2 MINUTES) //if we're in grace suffocation period, give it up for last words + to_chat(src, "You use your remaining air to say something!") + L.last_failed_breath = world.time - 2 MINUTES + return ..(message, speaking = speaking) + + to_chat(src, "You don't have enough air in [L] to make a sound!") + return + else if(L.breath_fail_ratio > 0.7) + whisper_say(length(message) > 5 ? stars(message) : message, speaking) + else if(L.breath_fail_ratio > 0.4 && length(message) > 10) + whisper_say(message, speaking) + else + return ..(message, speaking = speaking, whispering = whispering) + + +/mob/living/carbon/human/proc/forcesay(list/append) + if(stat == CONSCIOUS) + if(client) + var/virgin = 1 //has the text been modified yet? + var/temp = winget(client, "input", "text") + if(findtextEx(temp, "Say \"", 1, 7) && length(temp) > 5) //case sensitive means + var/main_key = get_prefix_key(/decl/prefix/radio_main_channel) + temp = replacetext(temp, main_key, "") //general radio + + var/channel_key = get_prefix_key(/decl/prefix/radio_channel_selection) + if(findtext(trim_left(temp), channel_key, 6, 7)) //dept radio + temp = copytext(trim_left(temp), 8) + virgin = 0 + + if(virgin) + temp = copytext(trim_left(temp), 6) //normal speech + virgin = 0 + + while(findtext(trim_left(temp), channel_key, 1, 2)) //dept radio again (necessary) + temp = copytext(trim_left(temp), 3) + + var/custom_emote_key = get_prefix_key(/decl/prefix/custom_emote) + if(findtext(temp, custom_emote_key, 1, 2)) //emotes + return + temp = copytext(trim_left(temp), 1, rand(5,8)) + + var/trimmed = trim_left(temp) + if(length(trimmed)) + if(append) + temp += pick(append) + + say(temp) + winset(client, "input", "text=[null]") + +/mob/living/carbon/human/say_understands(var/mob/other,var/datum/language/speaking = null) + + if(has_brain_worms()) //Brain worms translate everything. Even mice and alien speak. + return 1 + + if(species.can_understand(other)) + return 1 + + //These only pertain to common. Languages are handled by mob/say_understands() + if (!speaking) + if (istype(other, /mob/living/silicon)) + return 1 + if (istype(other, /mob/living/carbon/brain)) + return 1 + if (istype(other, /mob/living/carbon/slime)) + return 1 + + //This is already covered by mob/say_understands() + //if (istype(other, /mob/living/simple_animal)) + // if((other.universal_speak && !speaking) || src.universal_speak || src.universal_understand) + // return 1 + // return 0 + + return ..() + +/mob/living/carbon/human/GetVoice() + + if(is_anonymous) + return "Unknown" + var/voice_sub + for(var/obj/item/gear in list(wear_mask,wear_suit,head)) + if(!gear) + continue + var/obj/item/voice_changer/changer = locate() in gear + if(changer && changer.active && changer.voice) + voice_sub = changer.voice + + if(voice_sub) + return voice_sub + if(mind && mind.changeling && mind.changeling.mimicing) + return mind.changeling.mimicing + if(GetSpecialVoice()) + return GetSpecialVoice() + return real_name + +/mob/living/carbon/human/proc/SetSpecialVoice(var/new_voice) + if(new_voice) + special_voice = new_voice + return + +/mob/living/carbon/human/proc/UnsetSpecialVoice() + special_voice = "" + return + +/mob/living/carbon/human/proc/GetSpecialVoice() + return special_voice + + +/mob/living/carbon/human/say_quote(var/message, var/datum/language/speaking = null) + var/verb = "says" + var/ending = copytext(message, length(message)) + + if(speaking) + verb = speaking.get_spoken_verb(ending) + else + if(ending == "!") + verb=pick("exclaims","shouts","yells") + else if(ending == "?") + verb="asks" + + return verb + +/mob/living/carbon/human/handle_speech_problems(var/list/message_data) + if(silent || (sdisabilities & MUTE)) + message_data[1] = "" + . = 1 + + else if(istype(wear_mask, /obj/item/clothing/mask)) + var/obj/item/clothing/mask/M = wear_mask + if(M.voicechange) + message_data[1] = pick(M.say_messages) + message_data[2] = pick(M.say_verbs) + . = 1 + + else + . = ..(message_data) + +/mob/living/carbon/human/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) + switch(message_mode) + if("intercom") + if(!src.restrained()) + for(var/obj/item/device/radio/intercom/I in view(1)) + I.talk_into(src, message, null, verb, speaking) + I.add_fingerprint(src) + used_radios += I + if("headset") + if(l_ear && istype(l_ear,/obj/item/device/radio)) + var/obj/item/device/radio/R = l_ear + R.talk_into(src,message,null,verb,speaking) + used_radios += l_ear + else if(r_ear && istype(r_ear,/obj/item/device/radio)) + var/obj/item/device/radio/R = r_ear + R.talk_into(src,message,null,verb,speaking) + used_radios += r_ear + if("right ear") + var/obj/item/device/radio/R + var/has_radio = 0 + if(r_ear && istype(r_ear,/obj/item/device/radio)) + R = r_ear + has_radio = 1 + if(r_hand && istype(r_hand, /obj/item/device/radio)) + R = r_hand + has_radio = 1 + if(has_radio) + R.talk_into(src,message,null,verb,speaking) + used_radios += R + if("left ear") + var/obj/item/device/radio/R + var/has_radio = 0 + if(l_ear && istype(l_ear,/obj/item/device/radio)) + R = l_ear + has_radio = 1 + if(l_hand && istype(l_hand,/obj/item/device/radio)) + R = l_hand + has_radio = 1 + if(has_radio) + R.talk_into(src,message,null,verb,speaking) + used_radios += R + if("whisper") + whisper_say(message, speaking, alt_name) + return 1 + else + if(message_mode) + if(l_ear && istype(l_ear,/obj/item/device/radio)) + l_ear.talk_into(src,message, message_mode, verb, speaking) + used_radios += l_ear + else if(r_ear && istype(r_ear,/obj/item/device/radio)) + r_ear.talk_into(src,message, message_mode, verb, speaking) + used_radios += r_ear + +/mob/living/carbon/human/handle_speech_sound() + if(species.speech_sounds && prob(species.speech_chance)) + var/list/returns[2] + returns[1] = sound(pick(species.speech_sounds)) + returns[2] = 50 + return returns + return ..() + +/mob/living/carbon/human/can_speak(datum/language/speaking) + var/needs_assist = 0 + var/can_speak_assist = 0 + + if(species && speaking.name in species.assisted_langs) + needs_assist = 1 + for(var/obj/item/organ/internal/I in src.internal_organs) + if((speaking in I.assists_languages) && (I.is_usable())) + can_speak_assist = 1 + + if(needs_assist && !can_speak_assist) + return 0 + else if(needs_assist && can_speak_assist) + return 1 + + return ..() + +/mob/living/carbon/human/parse_language(var/message) + var/prefix = copytext(message,1,2) + if(length(message) >= 1 && prefix == get_prefix_key(/decl/prefix/audible_emote)) + return all_languages["Noise"] + + if(length(message) >= 2 && is_language_prefix(prefix)) + var/language_prefix = lowertext(copytext(message, 2 ,3)) + var/datum/language/L = language_keys[language_prefix] + if (can_speak(L)) + return L + + return null diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm new file mode 100644 index 00000000..b4fc0c06 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -0,0 +1,583 @@ +/* + Datum-based species. Should make for much cleaner and easier to maintain race code. +*/ + +/datum/species + + // Descriptors and strings. + var/name // Species name. + var/name_plural // Pluralized name (since "[name]s" is not always valid) + var/blurb = "A completely nondescript species." // A brief lore summary for use in the chargen screen. + + // Icon/appearance vars. + var/icobase = 'icons/mob/human_races/r_human.dmi' // Normal icon set. + var/deform = 'icons/mob/human_races/r_def_human.dmi' // Mutated icon set. + + // Damage overlay and masks. + var/damage_overlays = 'icons/mob/human_races/masks/dam_human.dmi' + var/damage_mask = 'icons/mob/human_races/masks/dam_mask_human.dmi' + var/blood_mask = 'icons/mob/human_races/masks/blood_human.dmi' + + var/prone_icon // If set, draws this from icobase when mob is prone. + var/has_floating_eyes // Eyes will overlay over darkness (glow) + + var/blood_color = COLOR_BLOOD_HUMAN // Red. + var/flesh_color = "#ffc896" // Pink. + var/blood_oxy = 1 + var/base_color // Used by changelings. Should also be used for icon previes.. + var/limb_blend = ICON_ADD + var/tail // Name of tail state in species effects icon file. + var/tail_animation // If set, the icon to obtain tail animation states from. + var/tail_blend = ICON_ADD + var/tail_hair + + var/list/hair_styles + var/list/facial_hair_styles + + var/eye_icon = "eyes_s" + var/eye_icon_location = 'icons/mob/human_face.dmi' + + var/default_h_style = "Bald" + var/default_f_style = "Shaved" + + var/race_key = 0 // Used for mob icon cache string. + var/icon/icon_template = 'icons/mob/human_races/r_template.dmi' // Used for mob icon generation for non-32x32 species. + var/pixel_offset_x = 0 // Used for offsetting large icons. + var/pixel_offset_y = 0 // Used for offsetting large icons. + + var/mob_size = MOB_MEDIUM + var/strength = STR_MEDIUM + var/show_ssd = "fast asleep" + var/virus_immune + var/short_sighted // Permanent weldervision. + var/light_sensitive // Ditto, but requires sunglasses to fix + var/blood_volume = 560 // Initial blood volume. + var/hunger_factor = DEFAULT_HUNGER_FACTOR // Multiplier for hunger. + var/taste_sensitivity = TASTE_NORMAL // How sensitive the species is to minute tastes. + + var/min_age = 17 + var/max_age = 70 + + // Language/culture vars. + var/default_language = LANGUAGE_GALCOM // Default language is used when 'say' is used without modifiers. + var/language = LANGUAGE_GALCOM // Default racial language, if any. + var/list/secondary_langs = list() // The names of secondary languages that are available to this species. + var/assisted_langs = list() // The languages the species can't speak without an assisted organ. + var/list/speech_sounds // A list of sounds to potentially play when speaking. + var/list/speech_chance // The likelihood of a speech sound playing. + var/num_alternate_languages = 0 // How many secondary languages are available to select at character creation + var/name_language = LANGUAGE_GALCOM // The language to use when determining names for this species, or null to use the first name/last name generator + var/additional_langs // Any other languages the species always gets. + + // Combat vars. + var/total_health = 200 // Point at which the mob will enter crit. + var/list/unarmed_types = list( // Possible unarmed attacks that the mob will use in combat, + /datum/unarmed_attack, + /datum/unarmed_attack/bite + ) + var/list/unarmed_attacks = null // For empty hand harm-intent attack + var/brute_mod = 1 // Physical damage multiplier. + var/burn_mod = 1 // Burn damage multiplier. + var/oxy_mod = 1 // Oxyloss modifier + var/toxins_mod = 1 // Toxloss modifier + var/radiation_mod = 1 // Radiation modifier + var/flash_mod = 1 // Stun from blindness modifier. + var/metabolism_mod = 1 // Reagent metabolism modifier + var/vision_flags = SEE_SELF|SEE_BLACKNESS // Same flags as glasses. + + // Death vars. + var/meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/human + var/remains_type = /obj/item/remains/xeno + var/gibbed_anim = "gibbed-h" + var/dusted_anim = "dust-h" + var/death_sound + var/death_message = "seizes up and falls limp, their eyes dead and lifeless..." + var/knockout_message = "collapses, having been knocked unconscious." + var/halloss_message = "slumps over, too weak to continue fighting..." + var/halloss_message_self = "The pain is too severe for you to keep going..." + + var/spawns_with_stack = 0 + // 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. + var/cold_level_1 = 243 // Cold damage level 1 below this point. -30 Celsium degrees + var/cold_level_2 = 200 // Cold damage level 2 below this point. + var/cold_level_3 = 120 // Cold damage level 3 below this point. + var/heat_level_1 = 360 // Heat damage level 1 above this point. + var/heat_level_2 = 400 // Heat damage level 2 above this point. + var/heat_level_3 = 1000 // Heat damage level 3 above this point. + var/passive_temp_gain = 0 // Species will gain this much temperature every second + var/hazard_high_pressure = HAZARD_HIGH_PRESSURE // Dangerously high pressure. + var/warning_high_pressure = WARNING_HIGH_PRESSURE // High pressure warning. + var/warning_low_pressure = WARNING_LOW_PRESSURE // Low pressure warning. + var/hazard_low_pressure = HAZARD_LOW_PRESSURE // Dangerously low pressure. + var/body_temperature = 310.15 // Species will try to stabilize at this temperature. + // (also affects temperature processing) + + var/heat_discomfort_level = 315 // Aesthetic messages about feeling warm. + var/cold_discomfort_level = 285 // Aesthetic messages about feeling chilly. + var/list/heat_discomfort_strings = list( + "You feel sweat drip down your neck.", + "You feel uncomfortably warm.", + "Your skin prickles in the heat." + ) + var/list/cold_discomfort_strings = list( + "You feel chilly.", + "You shiver suddenly.", + "Your chilly flesh stands out in goosebumps." + ) + + // HUD data vars. + var/datum/hud_data/hud + var/hud_type + var/health_hud_intensity = 1 + + var/grab_type = GRAB_NORMAL // The species' default grab type. + + // Body/form vars. + var/list/inherent_verbs // Species-specific verbs. + var/has_fine_manipulation = 1 // Can use small items. + var/siemens_coefficient = 1 // The lower, the thicker the skin and better the insulation. + var/darksight = 2 // Native darksight distance. + var/species_flags = 0 // Various specific features. + var/appearance_flags = 0 // Appearance/display related features. + var/spawn_flags = 0 // Flags that specify who can spawn as this species + var/slowdown = 0 // Passive movement speed malus (or boost, if negative) + var/primitive_form // Lesser form, if any (ie. monkey for humans) + var/greater_form // Greater form, if any, ie. human for monkeys. + var/holder_type + var/gluttonous // Can eat some mobs. Values can be GLUT_TINY, GLUT_SMALLER, GLUT_ANYTHING, GLUT_ITEM_TINY, GLUT_ITEM_NORMAL, GLUT_ITEM_ANYTHING, GLUT_PROJECTILE_VOMIT + var/stomach_capacity = 5 // How much stuff they can stick in their stomach + var/rarity_value = 1 // Relative rarity/collector value for this species. + // Determines the organs that the species spawns with and + var/list/has_organ = list( // which required-organ checks are conducted. + BP_HEART = /obj/item/organ/internal/heart, + BP_LUNGS = /obj/item/organ/internal/lungs, + BP_LIVER = /obj/item/organ/internal/liver, + BP_KIDNEYS = /obj/item/organ/internal/kidneys, + BP_BRAIN = /obj/item/organ/internal/brain, + BP_APPENDIX = /obj/item/organ/internal/appendix, + BP_EYES = /obj/item/organ/internal/eyes + ) + var/vision_organ // If set, this organ is required for vision. Defaults to "eyes" if the species has them. + var/breathing_organ // If set, this organ is required for breathing. Defaults to "lungs" if the species has them. + + var/obj/effect/decal/cleanable/blood/tracks/move_trail = /obj/effect/decal/cleanable/blood/tracks/footprints // What marks are left when walking + + var/list/skin_overlays = list() + + var/list/has_limbs = list( + BP_CHEST = list("path" = /obj/item/organ/external/chest), + BP_GROIN = list("path" = /obj/item/organ/external/groin), + BP_HEAD = list("path" = /obj/item/organ/external/head), + BP_L_ARM = list("path" = /obj/item/organ/external/arm), + BP_R_ARM = list("path" = /obj/item/organ/external/arm/right), + BP_L_LEG = list("path" = /obj/item/organ/external/leg), + BP_R_LEG = list("path" = /obj/item/organ/external/leg/right), + BP_L_HAND = list("path" = /obj/item/organ/external/hand), + BP_R_HAND = list("path" = /obj/item/organ/external/hand/right), + BP_L_FOOT = list("path" = /obj/item/organ/external/foot), + BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right) + ) + + // The basic skin colours this species uses + var/list/base_skin_colours + + var/list/genders = list(MALE, FEMALE) + + // Bump vars + var/bump_flag = HUMAN // What are we considered to be when bumped? + var/push_flags = ~HEAVY // What can we push? + var/swap_flags = ~HEAVY // What can we swap place with? + + var/pass_flags = 0 + var/breathing_sound = 'sound/voice/monkey.ogg' + var/list/equip_adjust = list() + var/list/equip_overlays = list() + + var/teeth_type = /obj/item/stack/teeth/generic //The type of teeth they have. + var/sexybits_location //organ tag where they are located if they can be kicked for increased pain +/* +These are all the things that can be adjusted for equipping stuff and +each one can be in the NORTH, SOUTH, EAST, and WEST direction. Specify +the direction to shift the thing and what direction. + +example: + equip_adjust = list( + slot_back_str = list(NORTH = list(SOUTH = 12, EAST = 7), EAST = list(SOUTH = 2, WEST = 12)) + ) + +This would shift back items (backpacks, axes, etc.) when the mob +is facing either north or east. +When the mob faces north the back item icon is shifted 12 pixes down and 7 pixels to the right. +When the mob faces east the back item icon is shifted 2 pixels down and 12 pixels to the left. + +The slots that you can use are found in items_clothing.dm and are the inventory slot string ones, so make sure + you use the _str version of the slot. +*/ + +/datum/species/proc/get_eyes(var/mob/living/carbon/human/H) + return + +/datum/species/New() + if(hud_type) + hud = new hud_type() + else + hud = new() + + //If the species has eyes, they are the default vision organ + if(!vision_organ && has_organ[BP_EYES]) + vision_organ = BP_EYES + //If the species has lungs, they are the default breathing organ + /* + if(!breathing_organ && has_organ[BP_LUNGS]) + breathing_organ = BP_LUNGS + */ + + unarmed_attacks = list() + for(var/u_type in unarmed_types) + unarmed_attacks += new u_type() + + //Build organ descriptors + for(var/limb_type in has_limbs) + var/list/organ_data = has_limbs[limb_type] + var/obj/item/organ/limb_path = organ_data["path"] + organ_data["descriptor"] = initial(limb_path.name) + +/datum/species/proc/sanitize_name(var/name) + return sanitizeName(name) + +/datum/species/proc/equip_survival_gear(var/mob/living/carbon/human/H,var/extendedtank = 1) + if(istype(H.get_equipped_item(slot_back), /obj/item/weapon/storage/backpack)) + if (extendedtank) H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/engineer(H.back), slot_in_backpack) + else H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/survival(H.back), slot_in_backpack) + else + if (extendedtank) H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/engineer(H), slot_r_hand) + else H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/survival(H), slot_r_hand) + +/datum/species/proc/create_organs(var/mob/living/carbon/human/H) //Handles creation of mob organs. + + H.mob_size = mob_size + for(var/obj/item/organ/organ in H.contents) + if((organ in H.organs) || (organ in H.internal_organs)) + qdel(organ) + + if(H.organs) H.organs.Cut() + if(H.internal_organs) H.internal_organs.Cut() + if(H.organs_by_name) H.organs_by_name.Cut() + if(H.internal_organs_by_name) H.internal_organs_by_name.Cut() + + H.organs = list() + H.internal_organs = list() + H.organs_by_name = list() + H.internal_organs_by_name = list() + + for(var/limb_type in has_limbs) + var/list/organ_data = has_limbs[limb_type] + var/limb_path = organ_data["path"] + new limb_path(H) + + for(var/organ_tag in has_organ) + var/organ_type = has_organ[organ_tag] + var/obj/item/organ/O = new organ_type(H) + if(organ_tag != O.organ_tag) + warning("[O.type] has a default organ tag \"[O.organ_tag]\" that differs from the species' organ tag \"[organ_tag]\". Updating organ_tag to match.") + O.organ_tag = organ_tag + H.internal_organs_by_name[organ_tag] = O + + for(var/name in H.organs_by_name) + H.organs |= H.organs_by_name[name] + + for(var/name in H.internal_organs_by_name) + H.internal_organs |= H.internal_organs_by_name[name] + + for(var/obj/item/organ/O in (H.organs|H.internal_organs)) + O.owner = H + + H.sync_organ_dna() + +/datum/species/proc/hug(var/mob/living/carbon/human/H,var/mob/living/target) + + var/t_him = "them" + switch(target.gender) + if(MALE) + t_him = "him" + if(FEMALE) + t_him = "her" + + H.visible_message("[H] hugs [target] to make [t_him] feel better!", \ + "You hug [target] to make [t_him] feel better!") + +/datum/species/proc/remove_inherent_verbs(var/mob/living/carbon/human/H) + if(inherent_verbs) + for(var/verb_path in inherent_verbs) + H.verbs -= verb_path + return + +/datum/species/proc/add_inherent_verbs(var/mob/living/carbon/human/H) + if(inherent_verbs) + for(var/verb_path in inherent_verbs) + H.verbs |= verb_path + return + +/datum/species/proc/handle_post_spawn(var/mob/living/carbon/human/H) //Handles anything not already covered by basic species assignment. + add_inherent_verbs(H) + H.mob_bump_flag = bump_flag + H.mob_swap_flags = swap_flags + H.mob_push_flags = push_flags + H.pass_flags = pass_flags + +/datum/species/proc/handle_pre_spawn(var/mob/living/carbon/human/H) + return + +/datum/species/proc/handle_death(var/mob/living/carbon/human/H) //Handles any species-specific death events (such as dionaea nymph spawns). + return + +/datum/species/proc/handle_new_grab(var/mob/living/carbon/human/H, var/obj/item/grab/G) + return + +// Only used for alien plasma weeds atm, but could be used for Dionaea later. +/datum/species/proc/handle_environment_special(var/mob/living/carbon/human/H) + return + +/datum/species/proc/handle_movement_delay_special(var/mob/living/carbon/human/H) + return 0 + +// Used to update alien icons for aliens. +/datum/species/proc/handle_login_special(var/mob/living/carbon/human/H) + return + +// As above. +/datum/species/proc/handle_logout_special(var/mob/living/carbon/human/H) + return + +// Builds the HUD using species-specific icons and usable slots. +/datum/species/proc/build_hud(var/mob/living/carbon/human/H) + return + +//Used by xenos understanding larvae and dionaea understanding nymphs. +/datum/species/proc/can_understand(var/mob/other) + return + +/datum/species/proc/can_overcome_gravity(var/mob/living/carbon/human/H) + return FALSE + +// Used for any extra behaviour when falling and to see if a species will fall at all. +/datum/species/proc/can_fall(var/mob/living/carbon/human/H) + return TRUE + +// Used to override normal fall behaviour. Use only when the species does fall down a level. +/datum/species/proc/handle_fall_special(var/mob/living/carbon/human/H, var/turf/landing) + return FALSE + +// Called when using the shredding behavior. +/datum/species/proc/can_shred(var/mob/living/carbon/human/H, var/ignore_intent) + + if((!ignore_intent && H.a_intent != I_HURT) || H.pulling_punches) + return 0 + + for(var/datum/unarmed_attack/attack in unarmed_attacks) + if(!attack.is_usable(H)) + continue + if(attack.shredding) + return 1 + + return 0 + +// Called in life() when the mob has no client. +/datum/species/proc/handle_npc(var/mob/living/carbon/human/H) + return + +/datum/species/proc/handle_vision(var/mob/living/carbon/human/H) + H.update_sight() + H.set_sight(H.sight|get_vision_flags(H)|H.equipment_vision_flags) + + if(H.stat == DEAD) + return 1 + + if(!H.druggy) + H.set_see_in_dark((H.sight == (SEE_TURFS|SEE_MOBS|SEE_OBJS)) ? 8 : min(darksight + H.equipment_darkness_modifier, 8)) + if(H.equipment_see_invis) + H.set_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.client)//no client, no screen to update + return 1 + + //H.set_fullscreen(H.eye_blind && !H.equipment_prescription, "blind", /obj/screen/fullscreen/blind) + if(H.eye_blind && !H.equipment_prescription) + H.set_all_blur() + else + H.remove_all_blur() + + H.set_fullscreen(H.stat == UNCONSCIOUS, "blackout", /obj/screen/fullscreen/blackout) + + //if(config.welder_vision) + // H.set_fullscreen(H.equipment_tint_total, "welder", /obj/screen/fullscreen/impaired, H.equipment_tint_total) + var/how_nearsighted = get_how_nearsighted(H) + H.set_fullscreen(how_nearsighted, "nearsighted", /obj/screen/fullscreen/oxy, how_nearsighted) + //H.set_fullscreen(H.eye_blurry, "blurry", /obj/screen/fullscreen/blurry) + if(H.eye_blurry) + H.set_all_blur() + else + H.remove_all_blur() + H.set_fullscreen(H.druggy, "high", /obj/screen/fullscreen/high) + + for(var/overlay in H.equipment_overlays) + H.client.screen |= overlay + + return 1 + +/datum/species/proc/get_how_nearsighted(var/mob/living/carbon/human/H) + var/prescriptions = short_sighted + if(H.disabilities & NEARSIGHTED) + prescriptions += 7 + if(H.equipment_prescription) + prescriptions -= H.equipment_prescription + + var/light = light_sensitive + if(light) + if(H.eyecheck() > FLASH_PROTECTION_NONE) + light = 0 + else + var/turf_brightness = 1 + var/turf/T = get_turf(H) + if(T && T.lighting_overlay) + turf_brightness = min(1, T.get_lumcount()) + if(turf_brightness < 0.33) + light = 0 + else + light = round(light * turf_brightness) + if(H.equipment_light_protection) + light -= H.equipment_light_protection + return Clamp(max(prescriptions, light), 0, 7) + +/datum/species/proc/set_default_hair(var/mob/living/carbon/human/H) + H.h_style = H.species.default_h_style + H.f_style = H.species.default_f_style + H.update_hair() + +/datum/species/proc/get_blood_name() + return "blood" + +/datum/species/proc/handle_death_check(var/mob/living/carbon/human/H) + return FALSE + +//Mostly for toasters +/datum/species/proc/handle_limbs_setup(var/mob/living/carbon/human/H) + return FALSE + +// Impliments different trails for species depending on if they're wearing shoes. +/datum/species/proc/get_move_trail(var/mob/living/carbon/human/H) + if( H.shoes || ( H.wear_suit && (H.wear_suit.body_parts_covered & FEET) ) ) + return /obj/effect/decal/cleanable/blood/tracks/footprints + else + return move_trail + +/datum/species/proc/update_skin(var/mob/living/carbon/human/H) + return + +/datum/species/proc/disarm_attackhand(var/mob/living/carbon/human/attacker, var/mob/living/carbon/human/target) + //attacker.do_attack_animation(target) + attacker.adjustStaminaLoss(rand(2,3))//No more spamming disarm without consequences. + + if(target.w_uniform) + target.w_uniform.add_fingerprint(attacker) + //var/obj/item/organ/external/affecting = target.get_organ(ran_zone(attacker.zone_sel.selecting)) + + var/list/holding = list(target.get_active_hand() = 40, target.get_inactive_hand() = 20) + + //See if they have any guns that might go off + for(var/obj/item/weapon/gun/W in holding) + if(W && prob(holding[W])) + var/list/turfs = list() + for(var/turf/T in view()) + turfs += T + if(turfs.len) + var/turf/shoot_to = pick(turfs) + target.visible_message("[target]'s [W] goes off during the struggle!") + return W.afterattack(shoot_to,target) + + + var/randn = rand(1, 100) + /* + if(!(species_flags & SPECIES_FLAG_NO_SLIP) && randn <= 25) + var/armor_check = target.run_armor_check(affecting, "melee") + target.apply_effect(3, WEAKEN, armor_check) + playsound(target.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + if(armor_check < 100) + target.visible_message("[attacker] has pushed [target]!") + else + target.visible_message("[attacker] attempted to push [target]!") + return + */ + + if(randn <= 60) + //See about breaking grips or pulls + if(target.break_all_grabs(attacker)) + playsound(target.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + return + + //Actually disarm them + for(var/obj/item/I in holding) + if(I) + target.drop_from_inventory(I) + target.visible_message("[attacker] has disarmed [target]!") + playsound(target.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + return + + playsound(target.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + target.visible_message("[attacker] attempted to disarm \the [target]!") + +/datum/species/proc/disfigure_msg(var/mob/living/carbon/human/H) //Used for determining the message a disfigured face has on examine. To add a unique message, just add this onto a specific species and change the "return" message. + var/datum/gender/T = gender_datums[H.get_gender()] + return "[T.His] face is horribly mangled!\n" + +/datum/species/proc/max_skin_tone() + if(appearance_flags & HAS_SKIN_TONE_GRAV) + return 100 + if(appearance_flags & HAS_SKIN_TONE_SPCR) + return 165 + return 220 + +/datum/species/proc/get_hair_styles() + var/list/L = LAZYACCESS(hair_styles, type) + if(!L) + L = list() + LAZYSET(hair_styles, type, L) + for(var/hairstyle in GLOB.hair_styles_list) + var/datum/sprite_accessory/S = GLOB.hair_styles_list[hairstyle] + if(!(get_bodytype() in S.species_allowed)) + continue + ADD_SORTED(L, hairstyle, /proc/cmp_text_asc) + L[hairstyle] = S + return L + +/datum/species/proc/get_facial_hair_styles(var/gender) + var/list/facial_hair_styles_by_species = LAZYACCESS(facial_hair_styles, type) + if(!facial_hair_styles_by_species) + facial_hair_styles_by_species = list() + LAZYSET(facial_hair_styles, type, facial_hair_styles_by_species) + + var/list/facial_hair_style_by_gender = facial_hair_styles_by_species[gender] + if(!facial_hair_style_by_gender) + facial_hair_style_by_gender = list() + LAZYSET(facial_hair_styles_by_species, gender, facial_hair_style_by_gender) + + for(var/facialhairstyle in GLOB.facial_hair_styles_list) + var/datum/sprite_accessory/S = GLOB.facial_hair_styles_list[facialhairstyle] + if(gender == MALE && S.gender == FEMALE) + continue + if(gender == FEMALE && S.gender == MALE) + continue + if(!(get_bodytype() in S.species_allowed)) + continue + ADD_SORTED(facial_hair_style_by_gender, facialhairstyle, /proc/cmp_text_asc) + facial_hair_style_by_gender[facialhairstyle] = S + + return facial_hair_style_by_gender diff --git a/code/modules/mob/living/carbon/human/species/species_attack.dm b/code/modules/mob/living/carbon/human/species/species_attack.dm new file mode 100644 index 00000000..16378321 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/species_attack.dm @@ -0,0 +1,22 @@ +/datum/unarmed_attack/bite/sharp //eye teeth + attack_verb = list("bit", "chomped on") + attack_sound = 'sound/weapons/bite.ogg' + shredding = 0 + sharp = 1 + edge = 1 + +/datum/unarmed_attack/slime_glomp/apply_effects(var/mob/living/carbon/human/user,var/mob/living/carbon/human/target,var/armour,var/attack_damage,var/zone) + ..() + user.apply_stored_shock_to(target) + +/datum/unarmed_attack/stomp/weak + attack_verb = list("jumped on") + +/datum/unarmed_attack/stomp/weak/get_unarmed_damage() + return damage + +/datum/unarmed_attack/stomp/weak/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage) + var/obj/item/organ/external/affecting = target.get_organ(zone) + user.visible_message("[user] jumped up and down on \the [target]'s [affecting.name]!") + playsound(user.loc, attack_sound, 25, 1, -1) + diff --git a/code/modules/mob/living/carbon/human/species/species_getters.dm b/code/modules/mob/living/carbon/human/species/species_getters.dm new file mode 100644 index 00000000..b8290139 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/species_getters.dm @@ -0,0 +1,84 @@ +/datum/species/proc/get_valid_shapeshifter_forms(var/mob/living/carbon/human/H) + return list() + +/datum/species/proc/get_additional_examine_text(var/mob/living/carbon/human/H) return + +/datum/species/proc/get_blood_mask(var/mob/living/carbon/human/H) + return blood_mask + +/datum/species/proc/get_damage_overlays(var/mob/living/carbon/human/H) + return damage_overlays + +/datum/species/proc/get_damage_mask(var/mob/living/carbon/human/H) + return damage_mask + +/datum/species/proc/get_examine_name(var/mob/living/carbon/human/H) + return name + +/datum/species/proc/get_icobase(var/mob/living/carbon/human/H, var/get_deform) + return (get_deform ? deform : icobase) + +/datum/species/proc/get_station_variant() + return name + +/datum/species/proc/get_race_key(var/mob/living/carbon/human/H) + return race_key + +/datum/species/proc/get_bodytype(var/mob/living/carbon/human/H) + return name + +/datum/species/proc/get_knockout_message(var/mob/living/carbon/human/H) + return ((H && H.isSynthetic()) ? "encounters a hardware fault and suddenly reboots!" : knockout_message) + +/datum/species/proc/get_death_message(var/mob/living/carbon/human/H) + return ((H && H.isSynthetic()) ? "gives one shrill beep before falling lifeless." : death_message) + +/datum/species/proc/get_ssd(var/mob/living/carbon/human/H) + return ((H && H.isSynthetic()) ? "flashing a 'system offline' glyph on their monitor" : show_ssd) + +/datum/species/proc/get_blood_colour(var/mob/living/carbon/human/H) + return ((H && H.isSynthetic()) ? SYNTH_BLOOD_COLOUR : blood_color) + +/datum/species/proc/get_virus_immune(var/mob/living/carbon/human/H) + return ((H && H.isSynthetic()) ? 1 : virus_immune) + +/datum/species/proc/get_flesh_colour(var/mob/living/carbon/human/H) + return ((H && H.isSynthetic()) ? SYNTH_FLESH_COLOUR : flesh_color) + +/datum/species/proc/get_environment_discomfort(var/mob/living/carbon/human/H, var/msg_type) + + if(!prob(5)) + return + + var/covered = 0 // Basic coverage can help. + for(var/obj/item/clothing/clothes in H) + if(H.l_hand == clothes || H.r_hand == clothes) + continue + if((clothes.body_parts_covered & UPPER_TORSO) && (clothes.body_parts_covered & LOWER_TORSO)) + covered = 1 + break + + switch(msg_type) + if("cold") + if(!covered) + to_chat(H, "[pick(cold_discomfort_strings)]") + if("heat") + if(covered) + to_chat(H, "[pick(heat_discomfort_strings)]") + +/datum/species/proc/get_random_name(var/gender) + if(!name_language) + if(gender == FEMALE) + return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) + else + return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) + + var/datum/language/species_language = all_languages[name_language] + if(!species_language) + species_language = all_languages[default_language] + if(!species_language) + return "unknown" + return species_language.get_random_name(gender) + +/datum/species/proc/get_vision_flags(var/mob/living/carbon/human/H) + return vision_flags diff --git a/code/modules/mob/living/carbon/human/species/species_helpers.dm b/code/modules/mob/living/carbon/human/species/species_helpers.dm new file mode 100644 index 00000000..3152312f --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/species_helpers.dm @@ -0,0 +1,6 @@ +var/list/stored_shock_by_ref = list() + +/mob/living/proc/apply_stored_shock_to(var/mob/living/target) + if(stored_shock_by_ref["\ref[src]"]) + target.electrocute_act(stored_shock_by_ref["\ref[src]"]*0.9, src) + stored_shock_by_ref["\ref[src]"] = 0 diff --git a/code/modules/mob/living/carbon/human/species/species_hud.dm b/code/modules/mob/living/carbon/human/species/species_hud.dm new file mode 100644 index 00000000..efa73089 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/species_hud.dm @@ -0,0 +1,64 @@ +/datum/hud_data + var/icon // If set, overrides ui_style. + var/has_a_intent = 1 // Set to draw intent box. + var/has_m_intent = 1 // Set to draw move intent box. + var/has_warnings = 1 // Set to draw environment warnings. + var/has_pressure = 1 // Draw the pressure indicator. + var/has_nutrition = 1 // Draw the nutrition indicator. + var/has_bodytemp = 1 // Draw the bodytemp indicator. + var/has_hands = 1 // Set to draw hands. + var/has_drop = 1 // Set to draw drop button. + var/has_throw = 1 // Set to draw throw button. + var/has_resist = 1 // Set to draw resist button. + var/has_internals = 1 // Set to draw the internals toggle button. + var/list/equip_slots = list() // Checked by mob_can_equip(). + + // Contains information on the position and tag for all inventory slots + // to be drawn for the mob. This is fairly delicate, try to avoid messing with it + // unless you know exactly what it does. + var/list/gear = list( + "i_clothing" = list("loc" = ui_iclothing, "name" = "Uniform", "slot" = slot_w_uniform, "state" = "center"), + "o_clothing" = list("loc" = ui_oclothing, "name" = "Suit", "slot" = slot_wear_suit, "state" = "suit"), + "mask" = list("loc" = ui_mask, "name" = "Mask", "slot" = slot_wear_mask, "state" = "mask"), + "gloves" = list("loc" = ui_gloves, "name" = "Gloves", "slot" = slot_gloves, "state" = "gloves", "toggle" = 1), + "eyes" = list("loc" = ui_glasses, "name" = "Glasses", "slot" = slot_glasses, "state" = "glasses","toggle" = 1), + "l_ear" = list("loc" = ui_l_ear, "name" = "Left Ear", "slot" = slot_l_ear, "state" = "ears", "toggle" = 1), + "r_ear" = list("loc" = ui_r_ear, "name" = "Right Ear", "slot" = slot_r_ear, "state" = "ears", "toggle" = 1), + "head" = list("loc" = ui_head, "name" = "Hat", "slot" = slot_head, "state" = "hair"), + "shoes" = list("loc" = ui_shoes, "name" = "Shoes", "slot" = slot_shoes, "state" = "shoes", "toggle" = 1), + "back2" = list("loc" = ui_sstore1, "name" = "Back2", "slot" = slot_s_store, "state" = "suitstore", "toggle" = 1), + "back" = list("loc" = ui_back, "name" = "Back", "slot" = slot_back, "state" = "back"), + "id" = list("loc" = ui_id, "name" = "ID", "slot" = slot_wear_id, "state" = "id"), + "storage1" = list("loc" = ui_storage1, "name" = "Left Pocket", "slot" = slot_l_store, "state" = "pocket"), + "storage2" = list("loc" = ui_storage2, "name" = "Right Pocket", "slot" = slot_r_store, "state" = "pocket"), + "neck" = list("loc" = ui_neck, "name" = "Neck", "slot" = slot_tie, "state" = "neck", "toggle" = 1), + "belt" = list("loc" = ui_belt, "name" = "Belt", "slot" = slot_belt, "state" = "belt") + ) + +/datum/hud_data/New() + ..() + for(var/slot in gear) + equip_slots |= gear[slot]["slot"] + + if(has_hands) + equip_slots |= slot_l_hand + equip_slots |= slot_r_hand + equip_slots |= slot_handcuffed + + if(slot_back in equip_slots) + equip_slots |= slot_in_backpack + + //if(slot_w_uniform in equip_slots) + // equip_slots |= slot_tie + + equip_slots |= slot_legcuffed + +/datum/hud_data/monkey + gear = list( + "i_clothing" = list("loc" = ui_iclothing, "name" = "Uniform", "slot" = slot_w_uniform, "state" = "center", "toggle" = 1), + "storage1" = list("loc" = ui_storage1, "name" = "Left Pocket", "slot" = slot_l_store, "state" = "pocket"), + "storage2" = list("loc" = ui_storage2, "name" = "Right Pocket", "slot" = slot_r_store, "state" = "pocket"), + "head" = list("loc" = ui_head, "name" = "Hat", "slot" = slot_head, "state" = "hair", "toggle" = 1), + "mask" = list("loc" = ui_shoes, "name" = "Mask", "slot" = slot_wear_mask, "state" = "mask", "toggle" = 1), + "back" = list("loc" = ui_sstore1, "name" = "Back", "slot" = slot_back, "state" = "back"), + ) diff --git a/code/modules/mob/living/carbon/human/species/species_random.dm b/code/modules/mob/living/carbon/human/species/species_random.dm new file mode 100644 index 00000000..39a7423d --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/species_random.dm @@ -0,0 +1,76 @@ +#define SETUP_RANDOM_COLOR_GETTER(X, Y, Z, W) \ +/datum/species/var/list/random_##Y = W;\ +/datum/species/proc/get_random_##X(){\ + if(!(appearance_flags & Z) || !random_##Y.len){\ + return;\ + }\ + var/decl/color_generator/CG = decls_repository.get_decl(pickweight(random_##Y));\ + return CG && CG.GenerateRGB();\ +} + +#define SETUP_RANDOM_COLOR_SETTER(X, Y)\ +/mob/living/carbon/human/proc/randomize_##X(){\ + if(!species){\ + return;\ + }\ + var/colors = species.get_random_##X();\ + if(colors){\ + Y(colors[1], colors[2], colors[3]);\ + }\ +} + +SETUP_RANDOM_COLOR_GETTER(skin_color, skin_colors, HAS_SKIN_COLOR, list( + /decl/color_generator/black, + /decl/color_generator/grey, + /decl/color_generator/brown, + /decl/color_generator/chestnut, + /decl/color_generator/blue, + /decl/color_generator/blue_light, + /decl/color_generator/green, + /decl/color_generator/white)) +SETUP_RANDOM_COLOR_SETTER(skin_color, change_skin_color) + +SETUP_RANDOM_COLOR_GETTER(hair_color, hair_colors, HAS_HAIR_COLOR, list( + /decl/color_generator/black, + /decl/color_generator/blonde, + /decl/color_generator/chestnut, + /decl/color_generator/copper, + /decl/color_generator/brown, + /decl/color_generator/wheat, + /decl/color_generator/old, + /decl/color_generator/punk)) +SETUP_RANDOM_COLOR_SETTER(hair_color, change_hair_color) + +SETUP_RANDOM_COLOR_GETTER(eye_color, eye_colors, HAS_EYE_COLOR, list( + /decl/color_generator/black, + /decl/color_generator/grey, + /decl/color_generator/brown, + /decl/color_generator/chestnut, + /decl/color_generator/blue, + /decl/color_generator/blue_light, + /decl/color_generator/green, + /decl/color_generator/albino_eye)) +SETUP_RANDOM_COLOR_SETTER(eye_color, change_eye_color) + +/datum/species/proc/get_random_facial_hair_color() + return get_random_hair_color() + +SETUP_RANDOM_COLOR_SETTER(facial_hair_color, change_facial_hair_color) + +/datum/species/proc/get_random_skin_tone() + return random_skin_tone(src) + +/mob/living/carbon/human/proc/randomize_skin_tone() + if(!species) + return + var/new_tone = species.get_random_skin_tone() + if(!isnull(new_tone)) + change_skin_tone(new_tone) + +/mob/living/carbon/human/proc/randomize_hair_style() + change_hair(safepick(generate_valid_hairstyles())) + +/mob/living/carbon/human/proc/randomize_facial_hair_style() + change_facial_hair(safepick(generate_valid_facial_hairstyles())) + +#undef SETUP_RANDOM_COLOR_GETTER diff --git a/code/modules/mob/living/carbon/human/species/species_shapeshift.dm b/code/modules/mob/living/carbon/human/species/species_shapeshift.dm new file mode 100644 index 00000000..a587f8d8 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/species_shapeshift.dm @@ -0,0 +1,168 @@ +// This is something of an intermediary species used for species that +// need to emulate the appearance of another race. Currently it is only +// used for slimes but it may be useful for changelings later. +var/list/wrapped_species_by_ref = list() + +/datum/species/shapeshifter + + inherent_verbs = list( + /mob/living/carbon/human/proc/shapeshifter_select_shape, + /mob/living/carbon/human/proc/shapeshifter_select_hair, + /mob/living/carbon/human/proc/shapeshifter_select_gender + ) + + var/list/valid_transform_species = list() + var/monochromatic + var/default_form = SPECIES_HUMAN + +/datum/species/shapeshifter/get_valid_shapeshifter_forms(var/mob/living/carbon/human/H) + return valid_transform_species + +/datum/species/shapeshifter/get_icobase(var/mob/living/carbon/human/H, var/get_deform) + if(!H) return ..(null, get_deform) + var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]] + return S.get_icobase(H, get_deform) + +/datum/species/shapeshifter/get_race_key(var/mob/living/carbon/human/H) + return "[..()]-[wrapped_species_by_ref["\ref[H]"]]" + +/datum/species/shapeshifter/get_bodytype(var/mob/living/carbon/human/H) + if(!H) return ..() + var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]] + return S.get_bodytype(H) + +/datum/species/shapeshifter/get_blood_mask(var/mob/living/carbon/human/H) + if(!H) return ..() + var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]] + return S.get_blood_mask(H) + +/datum/species/shapeshifter/get_damage_mask(var/mob/living/carbon/human/H) + if(!H) return ..() + var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]] + return S.get_damage_mask(H) + +/datum/species/shapeshifter/get_damage_overlays(var/mob/living/carbon/human/H) + if(!H) return ..() + var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]] + return S.get_damage_overlays(H) + +/datum/species/shapeshifter/get_tail(var/mob/living/carbon/human/H) + if(!H) return ..() + var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]] + return S.get_tail(H) + +/datum/species/shapeshifter/get_tail_animation(var/mob/living/carbon/human/H) + if(!H) return ..() + var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]] + return S.get_tail_animation(H) + +/datum/species/shapeshifter/get_tail_hair(var/mob/living/carbon/human/H) + if(!H) return ..() + var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]] + return S.get_tail_hair(H) + +/datum/species/shapeshifter/handle_pre_spawn(var/mob/living/carbon/human/H) + ..() + wrapped_species_by_ref["\ref[H]"] = default_form + +/datum/species/shapeshifter/handle_post_spawn(var/mob/living/carbon/human/H) + ..() + if(monochromatic) + H.r_hair = H.r_skin + H.g_hair = H.g_skin + H.b_hair = H.b_skin + H.r_facial = H.r_skin + H.g_facial = H.g_skin + H.b_facial = H.b_skin + + for(var/obj/item/organ/external/E in H.organs) + E.sync_colour_to_human(H) + +// Verbs follow. +/mob/living/carbon/human/proc/shapeshifter_select_hair() + + set name = "Select Hair" + set category = "Abilities" + + if(stat || world.time < last_special) + return + + last_special = world.time + 10 + + visible_message("\The [src]'s form contorts subtly.") + if(species.get_hair_styles()) + var/new_hair = input("Select a hairstyle.", "Shapeshifter Hair") as null|anything in species.get_hair_styles() + change_hair(new_hair ? new_hair : "Bald") + if(species.get_facial_hair_styles(gender)) + var/new_hair = input("Select a facial hair style.", "Shapeshifter Hair") as null|anything in species.get_facial_hair_styles(gender) + change_facial_hair(new_hair ? new_hair : "Shaved") + +/mob/living/carbon/human/proc/shapeshifter_select_gender() + + set name = "Select Gender" + set category = "Abilities" + + if(stat || world.time < last_special) + return + + last_special = world.time + 50 + + var/new_gender = input("Please select a gender.", "Shapeshifter Gender") as null|anything in list(FEMALE, MALE, NEUTER, PLURAL) + if(!new_gender) + return + + visible_message("\The [src]'s form contorts subtly.") + change_gender(new_gender) + +/mob/living/carbon/human/proc/shapeshifter_select_shape() + + set name = "Select Body Shape" + set category = "Abilities" + + if(stat || world.time < last_special) + return + + last_special = world.time + 50 + + var/new_species = input("Please select a species to emulate.", "Shapeshifter Body") as null|anything in species.get_valid_shapeshifter_forms(src) + if(!new_species || !all_species[new_species] || wrapped_species_by_ref["\ref[src]"] == new_species) + return + + wrapped_species_by_ref["\ref[src]"] = new_species + visible_message("\The [src] shifts and contorts, taking the form of \a ["\improper [new_species]"]!") + regenerate_icons() + +/mob/living/carbon/human/proc/shapeshifter_select_colour() + + set name = "Select Body Colour" + set category = "Abilities" + + if(stat || world.time < last_special) + return + + last_special = world.time + 50 + + var/new_skin = input("Please select a new body color.", "Shapeshifter Colour") as color + if(!new_skin) + return + shapeshifter_set_colour(new_skin) + +/mob/living/carbon/human/proc/shapeshifter_set_colour(var/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)) + + var/datum/species/shapeshifter/S = species + if(S.monochromatic) + r_hair = r_skin + g_hair = g_skin + b_hair = b_skin + r_facial = r_skin + g_facial = g_skin + b_facial = b_skin + + for(var/obj/item/organ/external/E in organs) + E.sync_colour_to_human(src) + + regenerate_icons() diff --git a/code/modules/mob/living/carbon/human/species/station/children.dm b/code/modules/mob/living/carbon/human/species/station/children.dm new file mode 100644 index 00000000..74011121 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/station/children.dm @@ -0,0 +1,58 @@ +//ALL SHIT FOR KIDS IN ONE FILE BECUASE I'M TIRED OF SEARCHING ALL OVER THE PLACE FOR CHILDREN SHIT +/datum/species/human/child //Oh lord here we go. + name = "Child" + name_plural = "Children" + blurb = "But a child." + total_health = 150 //Kids are weaker than adults. + min_age = 10 + max_age = 14 + icobase = 'icons/mob/human_races/child/r_child.dmi' + deform = 'icons/mob/human_races/child/r_child.dmi' + damage_mask = 'icons/mob/human_races/masks/dam_mask_child.dmi' + blood_mask = 'icons/mob/human_races/masks/blood_child.dmi' + pixel_offset_y = -4 + spawn_flags = SPECIES_IS_RESTRICTED//No more kids becoming nuke ops. + + +/datum/species/human/child/handle_post_spawn(var/mob/living/carbon/human/H) + //H.mutations.Add(CLUMSY)//So kids don't go around being commandos. + H.age = rand(min_age,max_age)//Random age for kiddos. + if(H.f_style)//Children don't get beards. + H.f_style = "Shaved" + to_chat(H, "You're [H.age] years old! Act like it!") + to_chat(H, "CHILDREN ARE CLUMSY AND CANNOT USE GUNS OR MELEE WEAPONS! DOING SO WILL KILL YOU!") + H.update_eyes() //hacky fix, i don't care and i'll never ever care + return ..() + + +/obj/item/clothing/under/child_jumpsuit + name = "grey children's jumpsuit" + desc = "Fitted just for kids." + icon_state = "child_grey" + can_be_worn_by_child = TRUE + child_exclusive = TRUE + +/obj/item/clothing/shoes/child_shoes + name = "black children's shoes" + desc = "Shoes for the little ones." + icon_state = "child_black" + can_be_worn_by_child = TRUE + child_exclusive = TRUE + +/obj/item/clothing/under/child_heir + name = "heir's clothing" + desc = "For underaged ruling in fashion." + icon_state = "heir" + can_be_worn_by_child = TRUE + child_exclusive = TRUE + + +/mob/living/carbon/human/proc/isChild()//Used to tell if someone is a child. + if(species && species.name == "Child") + return 1 + else + return 0 + +/mob/living/carbon/human/child/New(var/new_loc) + ..(new_loc, "Child") + diff --git a/code/modules/mob/living/carbon/human/species/station/monkey.dm b/code/modules/mob/living/carbon/human/species/station/monkey.dm new file mode 100644 index 00000000..56782fb3 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/station/monkey.dm @@ -0,0 +1,79 @@ +/datum/species/monkey + name = "Monkey" + name_plural = "Monkeys" + blurb = "Ook." + + icobase = 'icons/mob/human_races/monkeys/r_monkey.dmi' + deform = 'icons/mob/human_races/monkeys/r_monkey.dmi' + damage_overlays = 'icons/mob/human_races/masks/dam_monkey.dmi' + damage_mask = 'icons/mob/human_races/masks/dam_mask_monkey.dmi' + blood_mask = 'icons/mob/human_races/masks/blood_monkey.dmi' + language = null + default_language = "Chimpanzee" + greater_form = SPECIES_HUMAN + mob_size = MOB_SMALL + show_ssd = null + health_hud_intensity = 1.75 + + gibbed_anim = "gibbed-m" + dusted_anim = "dust-m" + death_message = "lets out a faint chimper as it collapses and stops moving..." + tail = "chimptail" + + inherent_verbs = list(/mob/living/proc/ventcrawl) + hud_type = /datum/hud_data/monkey + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/monkey + + rarity_value = 0.1 + total_health = 150 + brute_mod = 1.5 + burn_mod = 1.5 + + spawn_flags = SPECIES_IS_RESTRICTED + + bump_flag = MONKEY + swap_flags = MONKEY|SLIME|SIMPLE_ANIMAL + push_flags = MONKEY|SLIME|SIMPLE_ANIMAL|ALIEN + + pass_flags = PASS_FLAG_TABLE + holder_type = /obj/item/weapon/holder + has_limbs = list( + BP_CHEST = list("path" = /obj/item/organ/external/chest), + BP_GROIN = list("path" = /obj/item/organ/external/groin), + BP_HEAD = list("path" = /obj/item/organ/external/head/no_eyes), + BP_L_ARM = list("path" = /obj/item/organ/external/arm), + BP_R_ARM = list("path" = /obj/item/organ/external/arm/right), + BP_L_LEG = list("path" = /obj/item/organ/external/leg), + BP_R_LEG = list("path" = /obj/item/organ/external/leg/right), + BP_L_HAND = list("path" = /obj/item/organ/external/hand), + BP_R_HAND = list("path" = /obj/item/organ/external/hand/right), + BP_L_FOOT = list("path" = /obj/item/organ/external/foot), + BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right) + ) + +/datum/species/monkey/handle_npc(var/mob/living/carbon/human/H) + if(H.stat != CONSCIOUS) + return + if(prob(33) && H.canmove && isturf(H.loc) && !H.pulledby) //won't move if being pulled + step(H, pick(GLOB.cardinal)) + if(prob(1)) + H.emote(pick("scratch","jump","roll","tail")) + + if(H.get_shock() && H.shock_stage < 40 && prob(3)) + H.custom_emote("chimpers pitifully") + + if(H.shock_stage > 10 && prob(3)) + H.emote(pick("cry","whimper")) + + if(H.shock_stage >= 40 && prob(3)) + H.emote("scream") + + if(!H.restrained() && H.lying && H.shock_stage >= 60 && prob(3)) + H.custom_emote("thrashes in agony") + +/datum/species/monkey/get_random_name() + return "[lowertext(name)] ([rand(100,999)])" + +/datum/species/monkey/handle_post_spawn(var/mob/living/carbon/human/H) + ..() + H.item_state = lowertext(name) diff --git a/code/modules/mob/living/carbon/human/species/station/station.dm b/code/modules/mob/living/carbon/human/species/station/station.dm new file mode 100644 index 00000000..ea922131 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/station/station.dm @@ -0,0 +1,101 @@ +/datum/species/human + name = SPECIES_HUMAN + name_plural = "Humans" + primitive_form = "Monkey" + unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/punch, /datum/unarmed_attack/bite) + blurb = "Humanity originated in the Sol system, and over the last five centuries has spread \ + colonies across a wide swathe of space. They hold a wide range of forms and creeds.

            \ + While the central Sol government maintains control of its far-flung people, powerful corporate \ + interests, rampant cyber and bio-augmentation and secretive factions make life on most human \ + worlds tumultous at best." + num_alternate_languages = 2 + secondary_langs = list(LANGUAGE_SOL_COMMON) + name_language = null // Use the first-name last-name generator rather than a language scrambler + min_age = 17 + max_age = 65 + gluttonous = GLUT_TINY + + spawn_flags = SPECIES_CAN_JOIN + appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_TONE_NORMAL | HAS_LIPS | HAS_UNDERWEAR | HAS_EYE_COLOR + + teeth_type = /obj/item/stack/teeth/human //Teeth + sexybits_location = BP_GROIN + +/datum/species/human/get_bodytype(var/mob/living/carbon/human/H) + return SPECIES_HUMAN + +/datum/species/human/sanitize_name(var/name) + var/sanitized_name = sanitizeName(name) + + var/firstspace = findtext(sanitized_name, " ") + if(!firstspace) //we need a surname + sanitized_name += " [pick(GLOB.last_names)]" + + return sanitized_name + +/datum/species/human/handle_npc(var/mob/living/carbon/human/H) + if(H.stat != CONSCIOUS) + return + + if(H.get_shock() && H.shock_stage < 40 && prob(3)) + H.emote(pick("moan","groan")) + + if(H.shock_stage > 10 && prob(3)) + H.emote(pick("cry","whimper")) + + if(H.shock_stage >= 40 && prob(3)) + H.emote("scream") + + if(!H.restrained() && H.lying && H.shock_stage >= 60 && prob(3)) + H.custom_emote("thrashes in agony") + + if(!H.restrained() && H.shock_stage < 40 && prob(3)) + var/maxdam = 0 + var/obj/item/organ/external/damaged_organ = null + for(var/obj/item/organ/external/E in H.organs) + if(!E.can_feel_pain()) continue + var/dam = E.get_damage() + // make the choice of the organ depend on damage, + // but also sometimes use one of the less damaged ones + if(dam > maxdam && (maxdam == 0 || prob(50)) ) + damaged_organ = E + maxdam = dam + var/datum/gender/T = gender_datums[H.get_gender()] + if(damaged_organ) + if(damaged_organ.status & ORGAN_BLEEDING) + H.custom_emote("clutches [T.his] [damaged_organ.name], trying to stop the blood.") + else if(damaged_organ.status & ORGAN_BROKEN) + H.custom_emote("holds [T.his] [damaged_organ.name] carefully.") + else if(damaged_organ.burn_dam > damaged_organ.brute_dam && damaged_organ.organ_tag != BP_HEAD) + H.custom_emote("blows on [T.his] [damaged_organ.name] carefully.") + else + H.custom_emote("rubs [T.his] [damaged_organ.name] carefully.") + + for(var/obj/item/organ/I in H.internal_organs) + if((I.status & ORGAN_DEAD) || I.robotic >= ORGAN_ROBOT) continue + if(I.damage > 2) if(prob(2)) + var/obj/item/organ/external/parent = H.get_organ(I.parent_organ) + H.custom_emote("clutches [T.his] [parent.name]!") + +/datum/species/human/get_ssd(var/mob/living/carbon/human/H) + if(H.stat == CONSCIOUS) + return "staring blankly, not reacting to your presence" + return ..() + + +/datum/species/human/skinless + name = "Skinless" + name_plural = "Skinless" + icobase = 'icons/mob/human_races/subhuman.dmi' + deform = 'icons/mob/human_races/subhuman.dmi' + appearance_flags = 0 + spawn_flags = SPECIES_IS_RESTRICTED + species_flags = SPECIES_FLAG_NO_PAIN + +/datum/species/human/skinless/get_ssd(var/mob/living/carbon/human/H) + return + +/datum/species/human/lackey + name = "Lackey" + name_plural = "Lackeys" + spawn_flags = SPECIES_IS_RESTRICTED \ No newline at end of file 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 new file mode 100644 index 00000000..c4846464 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_powers.dm @@ -0,0 +1,272 @@ +/proc/alien_queen_exists(var/ignore_self,var/mob/living/carbon/human/self) + for(var/mob/living/carbon/human/Q in GLOB.living_mob_list_) + if(self && ignore_self && self == Q) + continue + if(Q.species.name != "Xenophage Queen") + continue + if(!Q.key || !Q.client || Q.stat) + continue + return 1 + return 0 + +/mob/living/carbon/human/proc/gain_plasma(var/amount) + + var/obj/item/organ/internal/xenos/plasmavessel/I = internal_organs_by_name[BP_PLASMA] + if(!istype(I)) return + + if(amount) + I.stored_plasma += amount + I.stored_plasma = max(0,min(I.stored_plasma,I.max_plasma)) + +/mob/living/carbon/human/proc/check_alien_ability(var/cost,var/needs_foundation,var/needs_organ) + + var/obj/item/organ/internal/xenos/plasmavessel/P = internal_organs_by_name[BP_PLASMA] + if(!istype(P)) + to_chat(src, "Your plasma vessel has been removed!") + return + + if(needs_organ) + var/obj/item/organ/internal/I = internal_organs_by_name[needs_organ] + if(!I) + to_chat(src, "Your [needs_organ] has been removed!") + return + else if(!I.is_usable()) + to_chat(src, "Your [needs_organ] is too damaged to function!") + return + + if(P.stored_plasma < cost) + to_chat(src, "You don't have enough phoron stored to do that.") + return 0 + + if(needs_foundation) + var/turf/T = get_turf(src) + var/has_foundation + if(T) + //TODO: Work out the actual conditions this needs. + if(!(istype(T,/turf/space))) + has_foundation = 1 + if(!has_foundation) + to_chat(src, "You need a solid foundation to do that on.") + return 0 + + P.stored_plasma -= cost + return 1 + +// Free abilities. +/mob/living/carbon/human/proc/transfer_plasma(mob/living/carbon/human/M as mob in oview(1)) + set name = "Transfer Plasma" + set desc = "Transfer Plasma to another alien" + set category = "Abilities" + + if (get_dist(src,M) > 1) + to_chat(src, "You need to be closer.") + return + + var/obj/item/organ/internal/xenos/plasmavessel/I = M.internal_organs_by_name[BP_PLASMA] + if(!istype(I)) + to_chat(src, "Their plasma vessel is missing.") + return + + var/amount = input("Amount:", "Transfer Plasma to [M]") as num + if (amount) + amount = abs(round(amount)) + if(check_alien_ability(amount,0,BP_PLASMA)) + M.gain_plasma(amount) + to_chat(M, "[src] has transfered [amount] plasma to you.") + to_chat(src, "You have transferred [amount] plasma to [M].") + return + +// Queen verbs. +/mob/living/carbon/human/proc/lay_egg() + + set name = "Lay Egg (75)" + set desc = "Lay an egg to produce huggers to impregnate prey with." + set category = "Abilities" + + if(!config.alien_eggs_allowed) + to_chat(src, "You begin to lay an egg, but hesitate. You suspect it isn't allowed.") + verbs -= /mob/living/carbon/human/proc/lay_egg + return + + if(locate(/obj/structure/alien/egg) in get_turf(src)) + to_chat(src, "There's already an egg here.") + return + + if(check_alien_ability(75,1,BP_EGG)) + visible_message("[src] has laid an egg!") + new /obj/structure/alien/egg(loc) + + return + +// Drone verbs. +/mob/living/carbon/human/proc/evolve() + set name = "Evolve (500)" + set desc = "Produce an interal egg sac capable of spawning children. Only one queen can exist at a time." + set category = "Abilities" + + if(alien_queen_exists()) + to_chat(src, "We already have an active queen.") + return + + if(check_alien_ability(500)) + visible_message("[src] begins to twist and contort!", "You begin to evolve!") + src.set_species("Xenophage Queen") + + return + +/mob/living/carbon/human/proc/plant() + set name = "Plant Weeds (50)" + set desc = "Plants some alien weeds" + set category = "Abilities" + + if(check_alien_ability(50,1,BP_RESIN)) + visible_message("[src] has planted some alien weeds!") + new /obj/structure/alien/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 + set name = "Corrosive Acid (200)" + set desc = "Drench an object in acid, destroying it over time." + set category = "Abilities" + + if(!O in oview(1)) + to_chat(src, "[O] is too far away.") + return + + // OBJ CHECK + var/cannot_melt + if(isobj(O)) + var/obj/I = O + if(I.unacidable) + cannot_melt = 1 + else + if(istype(O, /turf/simulated/wall)) + var/turf/simulated/wall/W = O + if(W.material.flags & MATERIAL_UNMELTABLE) + cannot_melt = 1 + else if(istype(O, /turf/simulated/floor)) + var/turf/simulated/floor/F = O + if(F.flooring && (F.flooring.flags & TURF_ACID_IMMUNE)) + cannot_melt = 1 + + if(cannot_melt) + to_chat(src, "You cannot dissolve this object.") + return + + if(check_alien_ability(200,0,BP_ACID)) + new /obj/effect/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 + +/mob/living/carbon/human/proc/neurotoxin(mob/target as mob in oview()) + set name = "Spit Neurotoxin (50)" + set desc = "Spits neurotoxin at someone, paralyzing them for a short time if they are not wearing protective gear." + set category = "Abilities" + + if(!check_alien_ability(50,0,BP_ACID)) + return + + if(stat || paralysis || stunned || weakened || lying || restrained() || buckled) + to_chat(src, "You cannot spit neurotoxin in your current state.") + return + + visible_message("[src] spits neurotoxin at [target]!", "You spit neurotoxin at [target].") + + var/obj/item/projectile/energy/neurotoxin/A = new /obj/item/projectile/energy/neurotoxin(usr.loc) + A.launch(target,get_organ_target()) + +/mob/living/carbon/human/proc/resin() // -- TLE + set name = "Secrete Resin (75)" + 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 + if(!choice) + return + + if(!check_alien_ability(75,1,BP_RESIN)) + return + + visible_message("[src] vomits up a thick purple substance and begins to shape it!", "You shape a [choice].") + switch(choice) + if("resin door") + new /obj/machinery/door/unpowered/simple/resin(loc) + if("resin wall") + new /obj/structure/alien/resin/wall(loc) + if("resin membrane") + new /obj/structure/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)) + to_chat(src, "They are too far away.") + return + + if(!M.mind) + to_chat(src, "This mindless flesh adds nothing to the hive.") + return + + if(M.species.get_bodytype(M) == "Xenophage" || !isnull(M.internal_organs_by_name["hive node"])) + to_chat(src, "They are already part of the hive.") + return + + var/obj/item/organ/affecting = M.get_organ(BP_CHEST) + if(!affecting || (affecting.robotic >= ORGAN_ROBOT)) + to_chat(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_mob(src, M, 150)) + return + + if(!M || !M.Adjacent(src)) + to_chat(src, "They are too far away.") + return + + if(M.species.get_bodytype(M) == "Xenophage" || !isnull(M.internal_organs_by_name["hive node"]) || !affecting || (affecting.robotic >= ORGAN_ROBOT)) + return + + if(!check_alien_ability(500,1,"egg sac")) + return + + src.visible_message("\The [src] regurgitates something into \the [M]'s torso!") + to_chat(M, "A hideous lump of alien mass strains your ribcage as it settles within!") + var/obj/item/organ/internal/xenos/hivenode/node = new(affecting) + node.replaced(M,affecting) + +/mob/living/carbon/human/proc/pry_open(obj/machinery/door/A in filter_list(oview(1), /obj/machinery/door)) + set name = "Pry Open Airlock" + set desc = "Pry open an airlock with your claws." + set category = "Abilities" + + if(!istype(A) || incapacitated()) + return + + if(!A.Adjacent(src)) + to_chat(src, "\The [A] is too far away.") + return + + if(!A.density) + return + + src.visible_message("\The [src] begins to pry open \the [A]!") + + if(!do_after(src,120,A)) + return + + if(!A.density) + return + + A.do_animate("spark") + sleep(6) + A.stat |= BROKEN + var/check = A.open(1) + src.visible_message("\The [src] slices \the [A]'s controls[check ? ", ripping it open!" : ", breaking it!"]") \ 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 new file mode 100644 index 00000000..b8283650 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm @@ -0,0 +1,345 @@ +//Stand-in until this is made more lore-friendly. +/datum/species/xenos + name = "Xenophage" + name_plural = "Xenophages" + + default_language = "Xenophage" + language = "Hivemind" + unarmed_types = list(/datum/unarmed_attack/claws/strong, /datum/unarmed_attack/bite/strong) + hud_type = /datum/hud_data/alien + rarity_value = 3 + health_hud_intensity = 1 + + icon_template = 'icons/mob/human_races/xenos/r_xenos_drone.dmi' + has_floating_eyes = TRUE + + // temp until someone who isn't me makes some for this icon set + damage_overlays = null + damage_mask = null + blood_mask = null + // end temp + + pixel_offset_x = -16 + has_fine_manipulation = 0 + siemens_coefficient = 0 + gluttonous = GLUT_ANYTHING + stomach_capacity = MOB_MEDIUM + + brute_mod = 0.25 // Hardened carapace. + burn_mod = 1.1 // Weak to fire. + + warning_low_pressure = 50 + hazard_low_pressure = -1 + + cold_level_1 = 50 + cold_level_2 = -1 + cold_level_3 = -1 + + species_flags = SPECIES_FLAG_NO_SCAN | SPECIES_FLAG_NO_PAIN | SPECIES_FLAG_NO_SLIP | SPECIES_FLAG_NO_POISON | SPECIES_FLAG_NO_EMBED + appearance_flags = HAS_EYE_COLOR | HAS_SKIN_COLOR + + spawn_flags = SPECIES_IS_RESTRICTED + + reagent_tag = IS_XENOS + + blood_color = "#05ee05" + flesh_color = "#282846" + base_color = "#00060c" + + gibbed_anim = "gibbed-a" + dusted_anim = "dust-a" + death_message = "lets out a waning guttural screech, green blood bubbling from its maw." + death_sound = 'sound/voice/hiss6.ogg' + + speech_sounds = list('sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg') + speech_chance = 100 + + breath_type = null + poison_type = null + + vision_flags = SEE_SELF|SEE_MOBS + + has_organ = list( + BP_EYES = /obj/item/organ/internal/eyes/xenos, + BP_HEART = /obj/item/organ/internal/heart, + BP_BRAIN = /obj/item/organ/internal/brain/xeno, + BP_PLASMA = /obj/item/organ/internal/xenos/plasmavessel, + BP_HIVE = /obj/item/organ/internal/xenos/hivenode, + BP_NUTRIENT = /obj/item/organ/internal/diona/nutrients + ) + + has_limbs = list( + "chest" = list("path" = /obj/item/organ/external/chest/unbreakable), + "groin" = list("path" = /obj/item/organ/external/groin/unbreakable), + "head" = list("path" = /obj/item/organ/external/head/unbreakable/xeno), + "l_arm" = list("path" = /obj/item/organ/external/arm/unbreakable), + "r_arm" = list("path" = /obj/item/organ/external/arm/right/unbreakable), + "l_leg" = list("path" = /obj/item/organ/external/leg/unbreakable), + "r_leg" = list("path" = /obj/item/organ/external/leg/right/unbreakable), + "l_hand" = list("path" = /obj/item/organ/external/hand/unbreakable), + "r_hand" = list("path" = /obj/item/organ/external/hand/right/unbreakable), + "l_foot" = list("path" = /obj/item/organ/external/foot/unbreakable), + "r_foot" = list("path" = /obj/item/organ/external/foot/right/unbreakable) + ) + + bump_flag = ALIEN + swap_flags = ~HEAVY + push_flags = (~HEAVY) ^ ROBOT + + var/alien_number = 0 + var/caste_name = "creature" // Used to update alien name. + var/weeds_heal_rate = 3 // Health regen on weeds. + var/weeds_plasma_rate = 5 // Plasma regen on weeds. + + genders = list(NEUTER) + +/datum/species/xenos/handle_post_spawn(var/mob/living/carbon/human/H) + ..(H) + + +/datum/species/xenos/get_bodytype(var/mob/living/carbon/H) + return "Xenophage" + +/datum/species/xenos/get_random_name() + return "alien [caste_name] ([alien_number])" + +/datum/species/xenos/can_understand(var/mob/other) + + if(istype(other,/mob/living/carbon/alien/larva)) + return 1 + + return 0 + +/datum/species/xenos/hug(var/mob/living/carbon/human/H,var/mob/living/target) + H.visible_message("[H] caresses [target] with countless prickling, needle-like legs.", \ + "You caress [target] with countless prickling, needle-like legs.") + +/datum/species/xenos/handle_post_spawn(var/mob/living/carbon/human/H) + + if(H.mind) + H.mind.assigned_role = "Alien" + H.mind.special_role = "Alien" + + alien_number++ //Keep track of how many aliens we've had so far. + H.real_name = "alien [caste_name] ([alien_number])" + H.SetName(H.real_name) + + ..() + +/datum/species/xenos/handle_environment_special(var/mob/living/carbon/human/H) + + var/turf/T = H.loc + if(!T) return + var/datum/gas_mixture/environment = T.return_air() + if(!environment) return + + var/obj/effect/vine/plant = locate() in T + if((environment.gas["phoron"] > 0 || (plant && plant.seed && plant.seed.name == "xenomorph")) && !regenerate(H)) + var/obj/item/organ/internal/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) + var/heal_rate = weeds_heal_rate + var/mend_prob = 10 + if (!H.resting) + heal_rate = weeds_heal_rate / 3 + mend_prob = 1 + + //first heal damages + if (H.getBruteLoss() || H.getFireLoss() || H.getOxyLoss() || H.getToxLoss()) + H.adjustBruteLoss(-heal_rate) + H.adjustFireLoss(-heal_rate) + H.adjustOxyLoss(-heal_rate) + H.adjustToxLoss(-heal_rate) + if (prob(5)) + to_chat(H, "You feel a soothing sensation come over you...") + return 1 + + //next internal organs + for(var/obj/item/organ/I in H.internal_organs) + if(I.damage > 0) + I.damage = max(I.damage - heal_rate, 0) + if (prob(5)) + to_chat(H, "You feel a soothing sensation within your [I.parent_organ]...") + return 1 + + //next mend broken bones, approx 10 ticks each + for(var/obj/item/organ/external/E in H.bad_external_organs) + if (E.status & ORGAN_BROKEN) + if (prob(mend_prob)) + if (E.mend_fracture()) + to_chat(H, "You feel something mend itself inside your [E.name].") + return 1 + + return 0 + +/datum/species/xenos/drone + name = "Xenophage Drone" + caste_name = "drone" + weeds_plasma_rate = 15 + slowdown = 1 + rarity_value = 5 + base_color = "#000d1a" + icobase = 'icons/mob/human_races/xenos/r_xenos_drone.dmi' + deform = 'icons/mob/human_races/xenos/r_xenos_drone.dmi' + + has_organ = list( + BP_EYES = /obj/item/organ/internal/eyes/xenos, + BP_HEART = /obj/item/organ/internal/heart, + BP_BRAIN = /obj/item/organ/internal/brain/xeno, + BP_PLASMA = /obj/item/organ/internal/xenos/plasmavessel/queen, + BP_ACID = /obj/item/organ/internal/xenos/acidgland, + BP_HIVE = /obj/item/organ/internal/xenos/hivenode, + BP_RESIN = /obj/item/organ/internal/xenos/resinspinner, + BP_NUTRIENT = /obj/item/organ/internal/diona/nutrients + ) + + inherent_verbs = list( + /mob/living/proc/ventcrawl, + /mob/living/carbon/human/proc/regurgitate, + /mob/living/carbon/human/proc/plant, + /mob/living/carbon/human/proc/transfer_plasma, + /mob/living/carbon/human/proc/evolve, + /mob/living/carbon/human/proc/resin, + /mob/living/carbon/human/proc/corrosive_acid + ) + +/datum/species/xenos/drone/handle_post_spawn(var/mob/living/carbon/human/H) + + var/mob/living/carbon/human/A = H + if(!istype(A)) + return ..() + ..() + +/datum/species/xenos/hunter + + name = "Xenophage Hunter" + weeds_plasma_rate = 5 + caste_name = "hunter" + slowdown = -2 + total_health = 300 + base_color = "#001a33" + + icobase = 'icons/mob/human_races/xenos/r_xenos_hunter.dmi' + deform = 'icons/mob/human_races/xenos/r_xenos_hunter.dmi' + + has_organ = list( + BP_EYES = /obj/item/organ/internal/eyes/xenos, + BP_HEART = /obj/item/organ/internal/heart, + BP_BRAIN = /obj/item/organ/internal/brain/xeno, + BP_PLASMA = /obj/item/organ/internal/xenos/plasmavessel/hunter, + BP_HIVE = /obj/item/organ/internal/xenos/hivenode, + BP_NUTRIENT = /obj/item/organ/internal/diona/nutrients + ) + + inherent_verbs = list( + /mob/living/proc/ventcrawl, + /mob/living/carbon/human/proc/pry_open, + /mob/living/carbon/human/proc/tackle, + /mob/living/carbon/human/proc/leap, + /mob/living/carbon/human/proc/psychic_whisper, + /mob/living/carbon/human/proc/regurgitate + ) + +/datum/species/xenos/sentinel + name = "Xenophage Sentinel" + weeds_plasma_rate = 10 + caste_name = "sentinel" + slowdown = 0 + base_color = "#00284d" + total_health = 250 + icobase = 'icons/mob/human_races/xenos/r_xenos_sentinel.dmi' + deform = 'icons/mob/human_races/xenos/r_xenos_sentinel.dmi' + + has_organ = list( + BP_EYES = /obj/item/organ/internal/eyes/xenos, + BP_HEART = /obj/item/organ/internal/heart, + BP_BRAIN = /obj/item/organ/internal/brain/xeno, + BP_PLASMA = /obj/item/organ/internal/xenos/plasmavessel/sentinel, + BP_ACID = /obj/item/organ/internal/xenos/acidgland, + BP_HIVE = /obj/item/organ/internal/xenos/hivenode, + BP_NUTRIENT = /obj/item/organ/internal/diona/nutrients + ) + + inherent_verbs = list( + /mob/living/proc/ventcrawl, + /mob/living/carbon/human/proc/tackle, + /mob/living/carbon/human/proc/regurgitate, + /mob/living/carbon/human/proc/transfer_plasma, + /mob/living/carbon/human/proc/corrosive_acid, + /mob/living/carbon/human/proc/neurotoxin + ) + +/datum/species/xenos/queen + + name = "Xenophage Queen" + total_health = 500 + weeds_heal_rate = 5 + weeds_plasma_rate = 20 + caste_name = "queen" + slowdown = 4 + rarity_value = 10 + + icobase = 'icons/mob/human_races/xenos/r_xenos_queen.dmi' + deform = 'icons/mob/human_races/xenos/r_xenos_queen.dmi' + + has_organ = list( + BP_EYES = /obj/item/organ/internal/eyes/xenos, + BP_HEART = /obj/item/organ/internal/heart, + BP_BRAIN = /obj/item/organ/internal/brain/xeno, + BP_EGG = /obj/item/organ/internal/xenos/eggsac, + BP_PLASMA = /obj/item/organ/internal/xenos/plasmavessel/queen, + BP_ACID = /obj/item/organ/internal/xenos/acidgland, + BP_HIVE = /obj/item/organ/internal/xenos/hivenode, + BP_RESIN = /obj/item/organ/internal/xenos/resinspinner, + BP_NUTRIENT = /obj/item/organ/internal/diona/nutrients + ) + + inherent_verbs = list( + /mob/living/proc/ventcrawl, + /mob/living/carbon/human/proc/psychic_whisper, + /mob/living/carbon/human/proc/regurgitate, + /mob/living/carbon/human/proc/lay_egg, + /mob/living/carbon/human/proc/plant, + /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 + ) + + genders = list(FEMALE) + +/datum/species/xenos/queen/handle_login_special(var/mob/living/carbon/human/H) + ..() + // Make sure only one official queen exists at any point. + if(!alien_queen_exists(1,H)) + H.real_name = "alien queen ([alien_number])" + H.SetName(H.real_name) + else + H.real_name = "alien princess ([alien_number])" + H.SetName(H.real_name) + +/datum/hud_data/alien + + icon = 'icons/mob/screen1_alien.dmi' + has_a_intent = 1 + has_m_intent = 1 + has_warnings = 1 + has_hands = 1 + has_drop = 1 + has_throw = 1 + has_resist = 1 + has_pressure = 0 + has_nutrition = 0 + has_bodytemp = 0 + has_internals = 0 + + gear = list( + "o_clothing" = list("loc" = ui_belt, "name" = "Suit", "slot" = slot_wear_suit, "state" = "equip", "dir" = SOUTH), + "head" = list("loc" = ui_id, "name" = "Hat", "slot" = slot_head, "state" = "hair"), + "storage1" = list("loc" = ui_storage1, "name" = "Left Pocket", "slot" = slot_l_store, "state" = "pocket"), + "storage2" = list("loc" = ui_storage2, "name" = "Right Pocket", "slot" = slot_r_store, "state" = "pocket"), + ) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/xenomorphs.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/xenomorphs.dm new file mode 100644 index 00000000..95b7c499 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/xenomorphs.dm @@ -0,0 +1,24 @@ +proc/create_new_xenomorph(var/alien_caste,var/target) + + target = get_turf(target) + if(!target || !alien_caste) return + + var/mob/living/carbon/human/new_alien = new(target) + new_alien.set_species("Xenophage [alien_caste]") + return new_alien + +/mob/living/carbon/human/xdrone/New(var/new_loc) + h_style = "Bald" + ..(new_loc, "Xenophage Drone") + +/mob/living/carbon/human/xsentinel/New(var/new_loc) + h_style = "Bald" + ..(new_loc, "Xenophage Sentinel") + +/mob/living/carbon/human/xhunter/New(var/new_loc) + h_style = "Bald" + ..(new_loc, "Xenophage Hunter") + +/mob/living/carbon/human/xqueen/New(var/new_loc) + h_style = "Bald" + ..(new_loc, "Xenophage Queen") diff --git a/code/modules/mob/living/carbon/human/stripping.dm b/code/modules/mob/living/carbon/human/stripping.dm new file mode 100644 index 00000000..98ae418f --- /dev/null +++ b/code/modules/mob/living/carbon/human/stripping.dm @@ -0,0 +1,181 @@ +/mob/living/carbon/human/proc/handle_strip(var/slot_to_strip_text,var/mob/living/user,var/obj/item/clothing/holder) + var/strip_delay = HUMAN_STRIP_DELAY + if(!slot_to_strip_text || !istype(user)) + return + + if(user.incapacitated() || !user.Adjacent(src)) + show_browser(user, null, "window=mob[src.name]") + return //TRUE + + // Are we placing or stripping? + var/stripping = FALSE + var/obj/item/held = user.get_active_hand() + if(!istype(held) || is_robot_module(held)) + stripping = TRUE + + if(user.fast_stripper) + strip_delay = 5 + + switch(slot_to_strip_text) + // Handle things that are part of this interface but not removing/replacing a given item. + if("pockets") + if(stripping) + visible_message("\The [user] is trying to empty [src]'s pockets!") + if(do_after(user, strip_delay, src, progress = 0)) + empty_pockets(user) + else + //should it be possible to discreetly slip something into someone's pockets? + visible_message("\The [user] is trying to stuff \a [held] into [src]'s pocket!") + if(do_after(user, strip_delay, src, progress = 0)) + place_in_pockets(held, user) + return + if("splints") + visible_message("\The [user] is trying to remove \the [src]'s splints!") + if(do_after(user, strip_delay, src, progress = 0)) + remove_splints(user) + return + if("sensors") + visible_message("\The [user] is trying to set \the [src]'s sensors!") + if(do_after(user, strip_delay, src, progress = 0)) + toggle_sensors(user) + return + if("internals") + visible_message("\The [usr] is trying to set \the [src]'s internals!") + if(do_after(user, strip_delay, src, progress = 0)) + toggle_internals(user) + return + if("tie") + if(!istype(holder) || !holder.accessories.len) + return + var/obj/item/clothing/accessory/A = holder.accessories[1] + if(holder.accessories.len > 1) + A = input("Select an accessory to remove from [holder]") as null|anything in holder.accessories + if(!istype(A)) + return + visible_message("\The [user] is trying to remove \the [src]'s [A.name]!") + + if(!do_after(user, strip_delay, src, progress = 0)) + return + + if(!A || holder.loc != src || !(A in holder.accessories)) + return + + admin_attack_log(user, src, "Stripped \an [A] from \the [holder].", "Was stripped of \an [A] from \the [holder].", "stripped \an [A] from \the [holder] of") + holder.remove_accessory(user,A) + return + else + var/obj/item/located_item = locate(slot_to_strip_text) in src + if(isunderwear(located_item)) + var/obj/item/underwear/UW = located_item + if(UW.DelayedRemoveUnderwear(user, src)) + user.put_in_active_hand(UW) + return + + var/obj/item/target_slot = get_equipped_item(text2num(slot_to_strip_text)) + if(stripping) + if(!istype(target_slot)) // They aren't holding anything valid and there's nothing to remove, why are we even here? + return + if(!target_slot.mob_can_unequip(src, text2num(slot_to_strip_text), disable_warning=1)) + to_chat(user, "You cannot remove \the [src]'s [target_slot.name].") + return + + visible_message("\The [user] is trying to remove \the [src]'s [target_slot.name]!") + else + visible_message("\The [user] is trying to put \a [held] on \the [src]!") + + if(!do_mob(user, src, strip_delay)) + return + + if(stripping) + if(unEquip(target_slot)) + admin_attack_log(user, src, "Stripped \a [target_slot]", "Was stripped of \a [target_slot].", "stripped \a [target_slot] from") + //user.put_in_active_hand(target_slot) + else + admin_attack_log(user, src, "Attempted to strip \a [target_slot]", "Target of a failed strip of \a [target_slot].", "attempted to strip \a [target_slot] from") + else if(user.unEquip(held)) + var/obj/item/clothing/C = get_equipped_item(text2num(slot_to_strip_text)) + if(istype(C) && C.can_attach_accessory(held)) + C.attach_accessory(user, held) + else if(!equip_to_slot_if_possible(held, text2num(slot_to_strip_text), del_on_fail=0, disable_warning=1, redraw_mob=1)) + user.put_in_active_hand(held) + +// Empty out everything in the target's pockets. +/mob/living/carbon/human/proc/empty_pockets(var/mob/living/user) + if(!r_store && !l_store) + to_chat(user, "\The [src] has nothing in their pockets.") + return + if(r_store) + unEquip(r_store) + if(l_store) + unEquip(l_store) + visible_message("\The [user] empties [src]'s pockets!") + +/mob/living/carbon/human/proc/place_in_pockets(obj/item/I, var/mob/living/user) + if(!user.unEquip(I)) + return + if(!r_store) + if(equip_to_slot_if_possible(I, slot_r_store, del_on_fail=0, disable_warning=1, redraw_mob=1)) + return + if(!l_store) + if(equip_to_slot_if_possible(I, slot_l_store, del_on_fail=0, disable_warning=1, redraw_mob=1)) + return + to_chat(user, "You are unable to place [I] in [src]'s pockets.") + user.put_in_active_hand(I) + +// Modify the current target sensor level. +/mob/living/carbon/human/proc/toggle_sensors(var/mob/living/user) + var/obj/item/clothing/under/suit = w_uniform + if(!suit) + to_chat(user, "\The [src] is not wearing a suit with sensors.") + return + if (suit.has_sensor >= 2) + to_chat(user, "\The [src]'s suit sensor controls are locked.") + return + + admin_attack_log(user, src, "Toggled their suit sensors.", "Toggled their suit sensors.", "toggled the suit sensors of") + suit.set_sensors(user) + +// Remove all splints. +/mob/living/carbon/human/proc/remove_splints(var/mob/living/user) + var/removed_splint = 0 + for(var/obj/item/organ/external/o in organs) + if (o && o.splinted) + var/obj/item/S = o.splinted + if(!istype(S) || S.loc != o) //can only remove splints that are actually worn on the organ (deals with hardsuit splints) + to_chat(user, "You cannot remove any splints on [src]'s [o.name] - [o.splinted] is supporting some of the breaks.") + else + S.add_fingerprint(user) + if(o.remove_splint()) + user.put_in_active_hand(S) + removed_splint = 1 + if(removed_splint) + visible_message("\The [user] removes \the [src]'s splints!") + else + to_chat(user, "\The [src] has no splints that can be removed.") + +// Set internals on or off. +/mob/living/carbon/human/proc/toggle_internals(var/mob/living/user) + if(internal) + internal.add_fingerprint(user) + internal = null + if(internals) + internals.icon_state = "internal0" + else + // Check for airtight mask/helmet. + if(!(istype(wear_mask, /obj/item/clothing/mask) || istype(head, /obj/item/clothing/head/helmet/space))) + return + // Find an internal source. + if(istype(back, /obj/item/weapon/tank)) + internal = back + else if(istype(s_store, /obj/item/weapon/tank)) + internal = s_store + else if(istype(belt, /obj/item/weapon/tank)) + internal = belt + + if(internal) + visible_message("\The [src] is now running on internals!") + internal.add_fingerprint(user) + if (internals) + internals.icon_state = "internal1" + else + visible_message("\The [user] disables \the [src]'s internals!") diff --git a/code/modules/mob/living/carbon/human/unarmed_attack.dm b/code/modules/mob/living/carbon/human/unarmed_attack.dm new file mode 100644 index 00000000..5953f0f8 --- /dev/null +++ b/code/modules/mob/living/carbon/human/unarmed_attack.dm @@ -0,0 +1,263 @@ +var/global/list/sparring_attack_cache = list() + +//Species unarmed attacks +/datum/unarmed_attack + var/attack_verb = list("attack") // Empty hand hurt intent verb. + var/attack_noun = list("fist") + var/damage = 0 // Extra empty hand attack damage. + var/attack_sound = "punch" + var/miss_sound = 'sound/weapons/punchmiss.ogg' + var/shredding = 0 // Calls the old attack_alien() behavior on objects/mobs when on harm intent. + var/sharp = 0 + var/edge = 0 + var/delay = 10 //Used to be 0. Slightly faster than hitting with a weapon. + + var/deal_halloss + var/sparring_variant_type = /datum/unarmed_attack/light_strike + + var/eye_attack_text + var/eye_attack_text_victim + +/datum/unarmed_attack/proc/get_sparring_variant() + if(sparring_variant_type) + if(!sparring_attack_cache[sparring_variant_type]) + sparring_attack_cache[sparring_variant_type] = new sparring_variant_type() + return sparring_attack_cache[sparring_variant_type] + +/datum/unarmed_attack/proc/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone) + if(user.restrained()) + return 0 + + // Check if they have a functioning hand. + var/obj/item/organ/external/E = user.organs_by_name[BP_L_HAND] + if(E && !E.is_broken() && !E.is_stump()) + return 1 + + E = user.organs_by_name[BP_R_HAND] + if(E && !E.is_broken() && !E.is_stump()) + return 1 + + return 0 + +/datum/unarmed_attack/proc/get_unarmed_damage() + return damage + +/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 >= 3 && armour < 100 && !(target == user) && stun_chance <= attack_damage * 5) // 25% standard chance + switch(zone) // strong punches can have effects depending on where they hit + if(BP_HEAD, BP_EYES, BP_MOUTH) + // Induce blurriness + target.visible_message("[target] looks momentarily disoriented.", "You see stars.") + target.apply_effect(attack_damage*2, EYE_BLUR, armour) + if(BP_L_ARM, BP_L_HAND) + if (target.l_hand) + // Disarm left hand + //Urist McAssistant dropped the macguffin with a scream just sounds odd. + target.visible_message("\The [target.l_hand] was knocked right out of [target]'s grasp!") + target.drop_l_hand() + if(BP_R_ARM, BP_R_HAND) + if (target.r_hand) + // Disarm right hand + target.visible_message("\The [target.r_hand] was knocked right out of [target]'s grasp!") + target.drop_r_hand() + if(BP_CHEST) + if(!target.lying) + var/turf/T = get_step(get_turf(target), get_dir(get_turf(user), get_turf(target))) + if(!T.density) + step(target, get_dir(get_turf(user), get_turf(target))) + target.visible_message("[pick("[target] was sent flying backward!", "[target] staggers back from the impact!")]") + if(prob(50)) + target.set_dir(GLOB.reverse_dir[target.dir]) + target.apply_effect(attack_damage * 0.4, WEAKEN, armour) + if(BP_GROIN) + target.visible_message("[target] looks like \he is in pain!", "[(target.gender=="female") ? "Oh god that hurt!" : "Oh no, not your[pick("testicles", "crown jewels", "clockweights", "family jewels", "marbles", "bean bags", "teabags", "sweetmeats", "goolies")]!"]") + target.apply_effects(stutter = attack_damage * 2, agony = attack_damage* 3, blocked = armour) + if(BP_L_LEG, BP_L_FOOT, BP_R_LEG, BP_R_FOOT) + if(!target.lying) + target.visible_message("[target] gives way slightly.") + target.apply_effect(attack_damage*3, PAIN, armour) + else if(attack_damage >= 5 && !(target == user) && (stun_chance + attack_damage * 5 >= 100) && armour < 100) // Chance to get the usual throwdown as well (25% standard chance) + if(!target.lying) + target.visible_message("[target] [pick("slumps", "falls", "drops")] down to the ground!") + else + target.visible_message("[target] has been weakened!") + target.apply_effect(3, WEAKEN, armour) + +/datum/unarmed_attack/proc/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage) + var/obj/item/organ/external/affecting = target.get_organ(zone) + user.visible_message("[user] [pick(attack_verb)] [target] in the [affecting.name]!") + playsound(user.loc, attack_sound, 25, 1, -1) + +/datum/unarmed_attack/proc/handle_eye_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target) + var/obj/item/organ/internal/eyes/eyes = target.internal_organs_by_name[BP_EYES] + if(eyes) + eyes.take_damage(rand(3,4), 1) + user.visible_message("[user] presses \his [eye_attack_text] into [target]'s [eyes.name]!") + var/eye_pain = eyes.can_feel_pain() + to_chat(target, "You experience[(eye_pain) ? "" : " immense pain as you feel" ] [eye_attack_text_victim] being pressed into your [eyes.name][(eye_pain)? "." : "!"]") + return + user.visible_message("[user] attempts to press \his [eye_attack_text] into [target]'s eyes, but they don't have any!") + +/datum/unarmed_attack/proc/damage_flags() + return (src.sharp? DAM_SHARP : 0)|(src.edge? DAM_EDGE : 0) + +/datum/unarmed_attack/bite + attack_verb = list("bit") + attack_sound = 'sound/weapons/bite.ogg' + shredding = 0 + damage = 0 + sharp = 0 + edge = 0 + +/datum/unarmed_attack/bite/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone) + + if(istype(user.wear_mask, /obj/item/clothing/mask/muzzle)) + return 0 + for(var/obj/item/clothing/C in list(user.wear_mask, user.head, user.wear_suit)) + if(C && (C.body_parts_covered & FACE) && (C.item_flags & ITEM_FLAG_THICKMATERIAL)) + return 0 //prevent biting through a space helmet or similar + if (user == target && (zone == BP_HEAD || zone == BP_EYES || zone == BP_MOUTH)) + return 0 //how do you bite yourself in the head? + return 1 + +/datum/unarmed_attack/punch + attack_verb = list("punched") + attack_noun = list("fist") + eye_attack_text = "fingers" + eye_attack_text_victim = "digits" + damage = 0 + +/datum/unarmed_attack/punch/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage) + var/obj/item/organ/external/affecting = target.get_organ(zone) + var/organ = affecting.name + + attack_damage = Clamp(attack_damage, 1, 5) // We expect damage input of 1 to 5 for this proc. But we leave this check juuust in case. + + if(target == user) + user.visible_message("[user] [pick(attack_verb)] \himself in the [organ]!") + return 0 + + if(!target.lying) + switch(zone) + if(BP_HEAD, BP_MOUTH, BP_EYES) + // ----- HEAD ----- // + switch(attack_damage) + if(1 to 2) + user.visible_message("[user] slapped [target] across \his cheek!") + if(3 to 4) + user.visible_message(pick( + 80; "[user] [pick(attack_verb)] [target] in the head!", + 20; "[user] struck [target] in the head[pick("", " with a closed fist")]!", + 50; "[user] threw a hook against [target]'s head!" + )) + if(5) + user.visible_message(pick( + 10; "[user] gave [target] a solid slap across \his face!", + 90; "[user] smashed \his [pick(attack_noun)] into [target]'s [pick("[organ]", "face", "jaw")]!" + )) + else + // ----- BODY ----- // + switch(attack_damage) + if(1 to 2) user.visible_message("[user] threw a glancing punch at [target]'s [organ]!") + if(1 to 4) user.visible_message("[user] [pick(attack_verb)] [target] in \his [organ]!") + if(5) user.visible_message("[user] smashed \his [pick(attack_noun)] into [target]'s [organ]!") + else + user.visible_message("[user] [pick("punched", "threw a punch at", "struck", "slammed their [pick(attack_noun)] into")] [target]'s [organ]!") //why do we have a separate set of verbs for lying targets? + +/datum/unarmed_attack/kick + attack_verb = list("kicked", "kicked", "kicked", "kneed") + attack_noun = list("kick", "kick", "kick", "knee strike") + attack_sound = "swing_hit" + damage = 0 + +/datum/unarmed_attack/kick/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone) + if(!(zone in list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT, BP_GROIN))) + return 0 + + var/obj/item/organ/external/E = user.organs_by_name[BP_L_FOOT] + if(E && !E.is_stump()) + return 1 + + E = user.organs_by_name[BP_R_FOOT] + if(E && !E.is_stump()) + return 1 + + return 0 + +/datum/unarmed_attack/kick/get_unarmed_damage(var/mob/living/carbon/human/user) + var/obj/item/clothing/shoes = user.shoes + if(!istype(shoes)) + return damage + return damage + (shoes ? shoes.force : 0) + +/datum/unarmed_attack/kick/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage) + var/obj/item/organ/external/affecting = target.get_organ(zone) + var/organ = affecting.name + + attack_damage = Clamp(attack_damage, 1, 5) + + switch(attack_damage) + if(1 to 2) user.visible_message("[user] threw [target] a glancing [pick(attack_noun)] to the [organ]!") //it's not that they're kicking lightly, it's that the kick didn't quite connect + if(3 to 4) user.visible_message("[user] [pick(attack_verb)] [target] in \his [organ]!") + if(5) user.visible_message("[user] landed a strong [pick(attack_noun)] against [target]'s [organ]!") + +/datum/unarmed_attack/stomp + attack_verb = list("stomped on") + attack_noun = list("stomp") + attack_sound = "swing_hit" + damage = 0 + +/datum/unarmed_attack/stomp/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone) + if(!istype(target)) + return 0 + + if (!user.lying && (target.lying || (zone in list(BP_L_FOOT, BP_R_FOOT)))) + if(target.grabbed_by == user && target.lying) + return 0 + var/obj/item/organ/external/E = user.organs_by_name[BP_L_FOOT] + if(E && !E.is_stump()) + return 1 + + E = user.organs_by_name[BP_R_FOOT] + if(E && !E.is_stump()) + return 1 + + return 0 + +/datum/unarmed_attack/stomp/get_unarmed_damage(var/mob/living/carbon/human/user) + var/obj/item/clothing/shoes = user.shoes + return damage + (shoes ? shoes.force : 0) + +/datum/unarmed_attack/stomp/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage) + var/obj/item/organ/external/affecting = target.get_organ(zone) + var/organ = affecting.name + var/obj/item/clothing/shoes = user.shoes + + attack_damage = Clamp(attack_damage, 1, 5) + + var/shoe_text = shoes ? copytext(shoes.name, 1, -1) : "foot" + switch(attack_damage) + if(1 to 4) + user.visible_message(pick( + "[user] stomped on [target]'s [organ][pick("", "with their [shoe_text]")]!", + "[user] stomped \his [shoe_text] down onto [target]'s [organ]!")) + if(5) + user.visible_message(pick( + "[user] stomped down hard onto [target]'s [organ][pick("", "with their [shoe_text]")]!", + "[user] slammed \his [shoe_text] down onto [target]'s [organ]!")) + +/datum/unarmed_attack/light_strike + deal_halloss = 3 + attack_noun = list("tap","light strike") + attack_verb = list("tapped", "lightly struck") + damage = 2 + shredding = 0 + damage = 0 + sharp = 0 + edge = 0 diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm new file mode 100644 index 00000000..627e188c --- /dev/null +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -0,0 +1,767 @@ +/* + Global associative list for caching humanoid icons. + Index format m or f, followed by a string of 0 and 1 to represent bodyparts followed by husk fat hulk skeleton 1 or 0. + TODO: Proper documentation + icon_key is [species.race_key][g][husk][fat][hulk][skeleton][s_tone] +*/ +var/global/list/human_icon_cache = list() +var/global/list/tail_icon_cache = list() //key is [species.race_key][r_skin][g_skin][b_skin] +var/global/list/light_overlay_cache = list() + +/proc/overlay_image(icon,icon_state,color,flags) + var/image/ret = image(icon,icon_state) + ret.color = color + ret.appearance_flags = flags + return ret + + /////////////////////// + //UPDATE_ICONS SYSTEM// + /////////////////////// +/* +Calling this a system is perhaps a bit trumped up. It is essentially update_clothing dismantled into its +core parts. The key difference is that when we generate overlays we do not generate either lying or standing +versions. Instead, we generate both and store them in two fixed-length lists, both using the same list-index +(The indexes are in update_icons.dm): Each list for humans is (at the time of writing) of length 19. +This will hopefully be reduced as the system is refined. + + var/overlays_lying[19] //For the lying down stance + var/overlays_standing[19] //For the standing stance + +When we call update_icons, the 'lying' variable is checked and then the appropriate list is assigned to our overlays! +That in itself uses a tiny bit more memory (no more than all the ridiculous lists the game has already mind you). + +On the other-hand, it should be very CPU cheap in comparison to the old system. +In the old system, we updated all our overlays every life() call, even if we were standing still inside a crate! +or dead!. 25ish overlays, all generated from scratch every second for every xeno/human/monkey and then applied. +More often than not update_clothing was being called a few times in addition to that! CPU was not the only issue, +all those icons had to be sent to every client. So really the cost was extremely cumulative. To the point where +update_clothing would frequently appear in the top 10 most CPU intensive procs during profiling. + +Another feature of this new system is that our lists are indexed. This means we can update specific overlays! +So we only regenerate icons when we need them to be updated! This is the main saving for this system. + +In practice this means that: + everytime you fall over, we just switch between precompiled lists. Which is fast and cheap. + Everytime you do something minor like take a pen out of your pocket, we only update the in-hand overlay + etc... + + +There are several things that need to be remembered: + +> Whenever we do something that should cause an overlay to update (which doesn't use standard procs + ( i.e. you do something like l_hand = /obj/item/something new(src) ) + You will need to call the relevant update_inv_* proc: + update_inv_head() + update_inv_wear_suit() + update_inv_gloves() + update_inv_shoes() + update_inv_w_uniform() + update_inv_glasse() + update_inv_l_hand() + update_inv_r_hand() + update_inv_belt() + update_inv_wear_id() + update_inv_ears() + update_inv_s_store() + update_inv_pockets() + update_inv_back() + update_inv_handcuffed() + update_inv_wear_mask() + + All of these are named after the variable they update from. They are defined at the mob/ level like + update_clothing was, so you won't cause undefined proc runtimes with usr.update_inv_wear_id() if the usr is a + slime etc. Instead, it'll just return without doing any work. So no harm in calling it for slimes and such. + + +> There are also these special cases: + update_mutations() //handles updating your appearance for certain mutations. e.g TK head-glows + UpdateDamageIcon() //handles damage overlays for brute/burn damage //(will rename this when I geta round to it) + update_body() //Handles updating your mob's icon to reflect their gender/race/complexion etc + update_hair() //Handles updating your hair overlay (used to be update_face, but mouth and + ...eyes were merged into update_body) + update_targeted() // Updates the target overlay when someone points a gun at you + +> All of these procs update our overlays_lying and overlays_standing, and then call update_icons() by default. + If you wish to update several overlays at once, you can set the argument to 0 to disable the update and call + it manually: + e.g. + update_inv_head(0) + update_inv_l_hand(0) + update_inv_r_hand() //<---calls update_icons() + + or equivillantly: + update_inv_head(0) + update_inv_l_hand(0) + update_inv_r_hand(0) + update_icons() + +> If you need to update all overlays you can use regenerate_icons(). it works exactly like update_clothing used to. + +> I reimplimented an old unused variable which was in the code called (coincidentally) var/update_icon + It can be used as another method of triggering regenerate_icons(). It's basically a flag that when set to non-zero + will call regenerate_icons() at the next life() call and then reset itself to 0. + The idea behind it is icons are regenerated only once, even if multiple events requested it. + +This system is confusing and is still a WIP. It's primary goal is speeding up the controls of the game whilst +reducing processing costs. So please bear with me while I iron out the kinks. It will be worth it, I promise. +If I can eventually free var/lying stuff from the life() process altogether, stuns/death/status stuff +will become less affected by lag-spikes and will be instantaneous! :3 + +If you have any questions/constructive-comments/bugs-to-report/or have a massivly devestated butt... +Please contact me on #coderbus IRC. ~Carn x +*/ + +//Human Overlays Indexes///////// +#define MUTATIONS_LAYER 1 +#define SKIN_LAYER 2 +#define DAMAGE_LAYER 3 +#define SURGERY_LEVEL 4 //bs12 specific. +#define UNDERWEAR_LAYER 5 +#define UNIFORM_LAYER 6 +#define ID_LAYER 7 +#define SHOES_LAYER 8 +#define GLOVES_LAYER 9 +#define BELT_LAYER 10 +#define SUIT_LAYER 11 +#define TAIL_LAYER 12 //bs12 specific. this hack is probably gonna come back to haunt me +#define GLASSES_LAYER 13 +#define BELT_LAYER_ALT 14 +#define SUIT_STORE_LAYER 15 +#define BACK_LAYER 16 +#define HAIR_LAYER 17 //TODO: make part of head layer? +#define GOGGLES_LAYER 18 +#define EARS_LAYER 19 +#define FACEMASK_LAYER 20 +#define HEAD_LAYER 21 +#define COLLAR_LAYER 22 +#define HANDCUFF_LAYER 23 +#define L_HAND_LAYER 24 +#define R_HAND_LAYER 25 +#define FIRE_LAYER 26 //If you're on fire +#define FLIES_LAYER 27 +#define COLDBREATH_LAYER 28 +#define TARGETED_LAYER 29 //BS12: Layer for the target overlay from weapon targeting system +#define TOTAL_LAYERS 29 +////////////////////////////////// + +/mob/living/carbon/human + var/list/overlays_standing[TOTAL_LAYERS] + var/previous_damage_appearance // store what the body last looked like, so we only have to update it if something changed + +//UPDATES OVERLAYS FROM OVERLAYS_LYING/OVERLAYS_STANDING +//this proc is messy as I was forced to include some old laggy cloaking code to it so that I don't break cloakers +//I'll work on removing that stuff by rewriting some of the cloaking stuff at a later date. +/mob/living/carbon/human/update_icons() + lying_prev = lying //so we don't update overlays for lying/standing unless our stance changes again + update_hud() //TODO: remove the need for this + overlays.Cut() + + if (icon_update) + if(is_cloaked()) + + icon = 'icons/mob/human.dmi' + icon_state = "blank" + + for(var/entry in list(overlays_standing[R_HAND_LAYER], overlays_standing[L_HAND_LAYER])) + if(istype(entry, /image)) + overlays += entry + else if(istype(entry, /list)) + for(var/inner_entry in entry) + overlays += inner_entry + + if(species.has_floating_eyes) + overlays |= species.get_eyes(src) + + else + icon = stand_icon + icon_state = null + + for(var/entry in overlays_standing) + if(istype(entry, /image)) + overlays += entry + else if(istype(entry, /list)) + for(var/inner_entry in entry) + overlays += inner_entry + if(species.has_floating_eyes) + overlays |= species.get_eyes(src) + + if(auras) + overlays |= auras + + var/matrix/M = matrix() + if(lying && !species.prone_icon) //Only rotate them if we're not drawing a specific icon for being prone. + M.Turn(90) + M.Scale(size_multiplier) + M.Translate(1,-6) + else + M.Scale(size_multiplier) + M.Translate(0, 16*(size_multiplier-1)) + transform = M + +var/global/list/damage_icon_parts = list() + +//DAMAGE OVERLAYS +//constructs damage icon for each organ from mask * damage field and saves it in our overlays_ lists +/mob/living/carbon/human/UpdateDamageIcon(var/update_icons=1) + // first check whether something actually changed about damage appearance + var/damage_appearance = "" + + if(!species.damage_overlays || !species.damage_mask) + return + + for(var/obj/item/organ/external/O in organs) + if(O.is_stump()) + continue + damage_appearance += O.damage_state + + if(damage_appearance == previous_damage_appearance) + // nothing to do here + return + + previous_damage_appearance = damage_appearance + + var/image/standing_image = image(species.damage_overlays, icon_state = "00") + + // blend the individual damage states with our icons + for(var/obj/item/organ/external/O in organs) + if(O.is_stump()) + continue + + O.update_damstate() + O.update_icon() + if(O.damage_state == "00") continue + var/icon/DI + var/use_colour = ((O.robotic >= ORGAN_ROBOT) ? SYNTH_BLOOD_COLOUR : O.species.get_blood_colour(src)) + var/cache_index = "[O.damage_state]/[O.icon_name]/[use_colour]/[species.get_bodytype(src)]" + if(damage_icon_parts[cache_index] == null) + DI = new /icon(species.get_damage_overlays(src), O.damage_state) // the damage icon for whole human + DI.Blend(new /icon(species.get_damage_mask(src), O.icon_name), ICON_MULTIPLY) // mask with this organ's pixels + DI.Blend(use_colour, ICON_MULTIPLY) + damage_icon_parts[cache_index] = DI + else + DI = damage_icon_parts[cache_index] + + standing_image.overlays += DI + + overlays_standing[DAMAGE_LAYER] = standing_image + update_bandages(update_icons) + if(update_icons) + update_icons() + + +/mob/living/carbon/human/proc/update_bandages(var/update_icons=1) + var/bandage_icon = 'icons/mob/bandage.dmi'//species.bandages_icon + if(!bandage_icon) + return + var/image/standing_image = overlays_standing[DAMAGE_LAYER] + if(standing_image) + for(var/obj/item/organ/external/O in organs) + if(O.is_stump()) + continue + var/bandage_level = O.bandage_level() + if(bandage_level) + standing_image.overlays += image(bandage_icon, "[O.icon_name][bandage_level]") + + overlays_standing[DAMAGE_LAYER] = standing_image + +//BASE MOB SPRITE +/mob/living/carbon/human/proc/update_body(var/update_icons=1) + var/husk_color_mod = rgb(96,88,80) + var/hulk_color_mod = rgb(48,224,40) + + var/husk = (HUSK in src.mutations) + var/fat = (FAT in src.mutations) + var/hulk = (HULK in src.mutations) + var/skeleton = (SKELETON in src.mutations) + var/pale_color_mod = COLOR_WHITE + + var/paleness = has_low_circulation() + + //CACHING: Generate an index key from visible bodyparts. + //0 = destroyed, 1 = normal, 2 = robotic, 3 = necrotic. + + //Create a new, blank icon for our mob to use. + if(stand_icon) + qdel(stand_icon) + stand_icon = new(species.icon_template ? species.icon_template : 'icons/mob/human.dmi',"blank") + + var/g = "male" + if(gender == FEMALE) + g = "female" + + var/icon_key = "[species.get_race_key(src)][g][s_tone][r_skin][g_skin][b_skin]" + if(lip_style) + icon_key += "[lip_style]" + else + icon_key += "nolips" + var/obj/item/organ/internal/eyes/eyes = internal_organs_by_name[species.vision_organ ? species.vision_organ : BP_EYES] + if(istype(eyes)) + icon_key += "[rgb(eyes.eye_colour[1], eyes.eye_colour[2], eyes.eye_colour[3])]" + else + icon_key += "#000000" + + for(var/organ_tag in species.has_limbs) + var/obj/item/organ/external/part = organs_by_name[organ_tag] + if(isnull(part) || part.is_stump()) + icon_key += "0" + continue + for(var/M in part.markings) + icon_key += "[M][part.markings[M]["color"]]" + if(part) + icon_key += "[part.species.get_race_key(part.owner)]" + icon_key += "[part.dna.GetUIState(DNA_UI_GENDER)]" + icon_key += "[part.s_tone]" + icon_key += "[part.s_base]" + if(part.s_col && part.s_col.len >= 3) + icon_key += "[rgb(part.s_col[1],part.s_col[2],part.s_col[3])]" + icon_key += "[part.s_col_blend]" + if(part.body_hair && part.h_col && part.h_col.len >= 3) + icon_key += "[rgb(part.h_col[1],part.h_col[2],part.h_col[3])]" + else + icon_key += "#000000" + for(var/M in part.markings) + icon_key += "[M][part.markings[M]["color"]]" + if(part.robotic >= ORGAN_ROBOT) + icon_key += "2[part.model ? "-[part.model]": ""]" + else if(part.status & ORGAN_DEAD) + icon_key += "3" + else + icon_key += "1" + + icon_key = "[icon_key][husk ? 1 : 0][fat ? 1 : 0][hulk ? 1 : 0][skeleton ? 1 : 0][paleness ? 1 : 0]" + + var/icon/base_icon + if(human_icon_cache[icon_key]) + base_icon = human_icon_cache[icon_key] + else + //BEGIN CACHED ICON GENERATION. + var/obj/item/organ/external/chest = get_organ(BP_CHEST) + base_icon = chest.get_icon() + + for(var/obj/item/organ/external/part in (organs-chest)) + var/icon/temp = part.get_icon() + //That part makes left and right legs drawn topmost and lowermost when human looks WEST or EAST + //And no change in rendering for other parts (they icon_position is 0, so goes to 'else' part) + if(part.icon_position & (LEFT | RIGHT)) + var/icon/temp2 = new('icons/mob/human.dmi',"blank") + temp2.Insert(new/icon(temp,dir=NORTH),dir=NORTH) + temp2.Insert(new/icon(temp,dir=SOUTH),dir=SOUTH) + if(!(part.icon_position & LEFT)) + temp2.Insert(new/icon(temp,dir=EAST),dir=EAST) + if(!(part.icon_position & RIGHT)) + temp2.Insert(new/icon(temp,dir=WEST),dir=WEST) + base_icon.Blend(temp2, ICON_OVERLAY) + if(part.icon_position & LEFT) + temp2.Insert(new/icon(temp,dir=EAST),dir=EAST) + if(part.icon_position & RIGHT) + temp2.Insert(new/icon(temp,dir=WEST),dir=WEST) + base_icon.Blend(temp2, ICON_UNDERLAY) + else if(part.icon_position & UNDER) + base_icon.Blend(temp, ICON_UNDERLAY) + else + base_icon.Blend(temp, ICON_OVERLAY) + + if(!skeleton) + if(husk) + base_icon.ColorTone(husk_color_mod) + else if(hulk) + var/list/tone = ReadRGB(hulk_color_mod) + base_icon.MapColors(rgb(tone[1],0,0),rgb(0,tone[2],0),rgb(0,0,tone[3])) + else if(istype(species, /datum/species/human)) + if(paleness) + base_icon.ColorTone(pale_color_mod) + + //Handle husk overlay. + if(husk && ("overlay_husk" in icon_states(species.get_icobase(src)))) + var/icon/mask = new(base_icon) + var/icon/husk_over = new(species.get_icobase(src),"overlay_husk") + mask.MapColors(0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0) + husk_over.Blend(mask, ICON_ADD) + base_icon.Blend(husk_over, ICON_OVERLAY) + + human_icon_cache[icon_key] = base_icon + + //END CACHED ICON GENERATION. + stand_icon.Blend(base_icon,ICON_OVERLAY) + + + if(update_icons) + update_icons() + +//UNDERWEAR OVERLAY + +/mob/living/carbon/human/proc/update_underwear(var/update_icons=1) + overlays_standing[UNDERWEAR_LAYER] = list() + for(var/entry in worn_underwear) + var/obj/item/underwear/UW = entry + + var/image/I = image(icon = UW.icon, icon_state = UW.icon_state) + I.appearance_flags = RESET_COLOR + I.color = UW.color + + overlays_standing[UNDERWEAR_LAYER] += I + + if(update_icons) update_icons() + +//HAIR OVERLAY +/mob/living/carbon/human/proc/update_hair(var/update_icons=1) + //Reset our hair + overlays_standing[HAIR_LAYER] = null + + var/obj/item/organ/external/head/head_organ = get_organ(BP_HEAD) + if(!head_organ || head_organ.is_stump() ) + if(update_icons) update_icons() + return + + //masks and helmets can obscure our hair. + if( (head && (head.flags_inv & BLOCKHAIR)) || (wear_mask && (wear_mask.flags_inv & BLOCKHAIR))) + if(update_icons) update_icons() + return + + overlays_standing[HAIR_LAYER] = head_organ.get_hair_icon() + + if(update_icons) update_icons() + +/mob/living/carbon/human/proc/update_skin(var/update_icons=1) + overlays_standing[SKIN_LAYER] = species.update_skin(src) + if(update_icons) update_icons() + +/mob/living/carbon/human/update_mutations(var/update_icons=1) + var/fat + if(FAT in mutations) + fat = "fat" + + var/image/standing = overlay_image('icons/effects/genetics.dmi', flags=RESET_COLOR) + var/add_image = 0 + var/g = "m" + if(gender == FEMALE) g = "f" + // DNA2 - Drawing underlays. + for(var/datum/dna/gene/gene in dna_genes) + if(!gene.block) + continue + if(gene.is_active(src)) + var/underlay=gene.OnDrawUnderlays(src,g,fat) + if(underlay) + standing.underlays += underlay + add_image = 1 + for(var/mut in mutations) + switch(mut) + if(LASER) + standing.overlays += "lasereyes_s" + add_image = 1 + if(add_image) + overlays_standing[MUTATIONS_LAYER] = standing + else + overlays_standing[MUTATIONS_LAYER] = null + if(update_icons) update_icons() + +/* --------------------------------------- */ +//For legacy support. +/mob/living/carbon/human/regenerate_icons() + ..() + if(transforming || QDELETED(src)) return + + update_mutations(0) + update_body(0) + update_skin(0) + update_underwear(0) + update_hair(0) + update_inv_w_uniform(0) + update_inv_wear_id(0) + update_inv_gloves(0) + update_inv_glasses(0) + update_inv_ears(0) + update_inv_shoes(0) + update_inv_s_store(0) + update_inv_wear_mask(0) + update_inv_head(0) + update_inv_belt(0) + update_inv_back(0) + update_inv_wear_suit(0) + update_inv_r_hand(0) + update_inv_l_hand(0) + update_inv_handcuffed(0) + update_inv_pockets(0) + update_inv_neck(0) + update_fire(0) + remove_flies(0) + update_surgery(0) + UpdateDamageIcon() + update_icons() + //Hud Stuff + update_hud() + +/* --------------------------------------- */ +//vvvvvv UPDATE_INV PROCS vvvvvv + +/mob/living/carbon/human/update_inv_w_uniform(var/update_icons=1) + if(istype(w_uniform, /obj/item/clothing/under) && !(wear_suit && wear_suit.flags_inv & HIDEJUMPSUIT)) + overlays_standing[UNIFORM_LAYER] = w_uniform.get_mob_overlay(src,slot_w_uniform_str) + else + overlays_standing[UNIFORM_LAYER] = null + + if(update_icons) + update_icons() + +/mob/living/carbon/human/update_inv_wear_id(var/update_icons=1) + var/image/id_overlay + if(wear_id && istype(w_uniform, /obj/item/clothing/under)) + //var/obj/item/clothing/under/U = w_uniform + //if(U.displays_id && !U.rolled_down) + id_overlay = wear_id.get_mob_overlay(src,slot_wear_id_str) + + overlays_standing[ID_LAYER] = id_overlay + + BITSET(hud_updateflag, ID_HUD) + BITSET(hud_updateflag, WANTED_HUD) + + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_gloves(var/update_icons=1) + if(gloves && !(wear_suit && wear_suit.flags_inv & HIDEGLOVES)) + overlays_standing[GLOVES_LAYER] = gloves.get_mob_overlay(src,slot_gloves_str) + else + if(blood_DNA && species.blood_mask) + var/image/bloodsies = overlay_image(species.blood_mask, "bloodyhands", hand_blood_color, RESET_COLOR) + overlays_standing[GLOVES_LAYER] = bloodsies + else + overlays_standing[GLOVES_LAYER] = null + if(update_icons) update_icons() + + +/mob/living/carbon/human/update_inv_glasses(var/update_icons=1) + if(glasses) + overlays_standing[glasses.use_alt_layer ? GOGGLES_LAYER : GLASSES_LAYER] = glasses.get_mob_overlay(src,slot_glasses_str) + overlays_standing[glasses.use_alt_layer ? GLASSES_LAYER : GOGGLES_LAYER] = null + else + overlays_standing[GLASSES_LAYER] = null + overlays_standing[GOGGLES_LAYER] = null + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_ears(var/update_icons=1) + overlays_standing[EARS_LAYER] = null + if( (head && (head.flags_inv & (BLOCKHAIR | BLOCKHEADHAIR))) || (wear_mask && (wear_mask.flags_inv & (BLOCKHAIR | BLOCKHEADHAIR)))) + if(update_icons) update_icons() + return + + if(l_ear || r_ear) + // Blank image upon which to layer left & right overlays. + var/image/both = image("icon" = 'icons/effects/effects.dmi', "icon_state" = "nothing") + if(l_ear) + both.overlays += l_ear.get_mob_overlay(src,slot_l_ear_str) + if(r_ear) + both.overlays += r_ear.get_mob_overlay(src,slot_r_ear_str) + overlays_standing[EARS_LAYER] = both + + else + overlays_standing[EARS_LAYER] = null + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_shoes(var/update_icons=1) + if(shoes && !((wear_suit && wear_suit.flags_inv & HIDESHOES) || (w_uniform && w_uniform.flags_inv & HIDESHOES))) + overlays_standing[SHOES_LAYER] = shoes.get_mob_overlay(src,slot_shoes_str) + else + if(feet_blood_DNA && species.blood_mask) + var/image/bloodsies = overlay_image(species.blood_mask, "shoeblood", hand_blood_color, RESET_COLOR) + overlays_standing[SHOES_LAYER] = bloodsies + else + overlays_standing[SHOES_LAYER] = null + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_s_store(var/update_icons=1) + if(s_store) + overlays_standing[SUIT_STORE_LAYER] = s_store.get_mob_overlay(src,slot_s_store_str) + else + overlays_standing[SUIT_STORE_LAYER] = null + if(update_icons) update_icons() + + +/mob/living/carbon/human/update_inv_head(var/update_icons=1) + if(head) + overlays_standing[HEAD_LAYER] = head.get_mob_overlay(src,slot_head_str) + else + overlays_standing[HEAD_LAYER] = null + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_belt(var/update_icons=1) + if(belt) + overlays_standing[belt.use_alt_layer ? BELT_LAYER_ALT : BELT_LAYER] = belt.get_mob_overlay(src,slot_belt_str) + overlays_standing[belt.use_alt_layer ? BELT_LAYER : BELT_LAYER_ALT] = null + else + overlays_standing[BELT_LAYER] = null + overlays_standing[BELT_LAYER_ALT] = null + if(update_icons) update_icons() + + +/mob/living/carbon/human/update_inv_wear_suit(var/update_icons=1) + + if(wear_suit) + overlays_standing[SUIT_LAYER] = wear_suit.get_mob_overlay(src,slot_wear_suit_str) + else + overlays_standing[SUIT_LAYER] = null + update_inv_w_uniform(0) + update_inv_shoes(0) + update_inv_gloves(0) + + update_collar(0) + + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_pockets(var/update_icons=1) + if(update_icons) update_icons() + + +/mob/living/carbon/human/update_inv_wear_mask(var/update_icons=1) + if( wear_mask && ( istype(wear_mask, /obj/item/clothing/mask) || istype(wear_mask, /obj/item/clothing/accessory) ) && !(head && head.flags_inv & HIDEMASK)) + overlays_standing[FACEMASK_LAYER] = wear_mask.get_mob_overlay(src,slot_wear_mask_str) + else + overlays_standing[FACEMASK_LAYER] = null + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_back(var/update_icons=1) + if(back) + overlays_standing[BACK_LAYER] = back.get_mob_overlay(src,slot_back_str) + else + overlays_standing[BACK_LAYER] = null + + if(update_icons) + update_icons() + + +/mob/living/carbon/human/update_hud() //TODO: do away with this if possible + if(client) + client.screen |= contents + if(hud_used) + hud_used.hidden_inventory_update() //Updates the screenloc of the items on the 'other' inventory bar + + +/mob/living/carbon/human/update_inv_handcuffed(var/update_icons=1) + if(handcuffed) + overlays_standing[HANDCUFF_LAYER] = handcuffed.get_mob_overlay(src,slot_handcuffed_str) + else + overlays_standing[HANDCUFF_LAYER] = null + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_r_hand(var/update_icons=1) + if(r_hand) + var/image/standing = r_hand.get_mob_overlay(src,slot_r_hand_str) + if(standing) + standing.appearance_flags |= RESET_ALPHA + overlays_standing[R_HAND_LAYER] = standing + + if (handcuffed) drop_r_hand() //this should be moved out of icon code + else + overlays_standing[R_HAND_LAYER] = null + + if(update_icons) update_icons() + + +/mob/living/carbon/human/update_inv_l_hand(var/update_icons=1) + if(l_hand) + var/image/standing = l_hand.get_mob_overlay(src,slot_l_hand_str) + if(standing) + standing.appearance_flags |= RESET_ALPHA + overlays_standing[L_HAND_LAYER] = standing + + if (handcuffed) drop_l_hand() //This probably should not be here + else + overlays_standing[L_HAND_LAYER] = null + + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_neck(var/update_icons=1) + if(tie_slot) + overlays_standing[COLLAR_LAYER] = tie_slot.get_mob_overlay(src,slot_tie_str) + else + overlays_standing[COLLAR_LAYER] = null + if(update_icons) update_icons() + + +//Adds a collar overlay above the helmet layer if the suit has one +// Suit needs an identically named sprite in icons/mob/collar.dmi +/mob/living/carbon/human/proc/update_collar(var/update_icons=1) + if(istype(wear_suit,/obj/item/clothing/suit)) + var/obj/item/clothing/suit/S = wear_suit + overlays_standing[COLLAR_LAYER] = S.get_collar() + else + overlays_standing[COLLAR_LAYER] = null + + if(update_icons) update_icons() + + +/mob/living/carbon/human/update_fire(var/update_icons=1) + overlays_standing[FIRE_LAYER] = null + if(on_fire) + var/image/standing = overlay_image('icons/mob/OnFire.dmi', "Standing", RESET_COLOR) + overlays_standing[FIRE_LAYER] = standing + if(update_icons) update_icons() + +/mob/living/carbon/human/proc/add_coldbreath(var/update_icons=1) + if(coldbreath) return //We alreayd have coldbreath don't add it again. + if(wear_mask) return //Don't need this if we're wearing a mask. + if(stat == DEAD) return //Don't need this if we're dead + overlays_standing[COLDBREATH_LAYER] = null + var/image/standing = overlay_image('icons/mob/cold_breath.dmi', "breath") + overlays_standing[COLDBREATH_LAYER] = standing + coldbreath = TRUE + + if(update_icons) update_icons() + +/mob/living/carbon/human/proc/remove_coldbreath(var/update_icons=1) + overlays_standing[COLDBREATH_LAYER] = null + coldbreath = FALSE + + if(update_icons) update_icons() + +/mob/living/carbon/human/proc/add_flies(var/update_icons=1) + overlays_standing[FLIES_LAYER] = null + var/image/standing = overlay_image('icons/effects/effects.dmi', "flies") + overlays_standing[FLIES_LAYER] = standing + + if(update_icons) update_icons() + +/mob/living/carbon/human/proc/remove_flies(var/update_icons=1) + overlays_standing[FLIES_LAYER] = null + + if(update_icons) update_icons() + + + +/mob/living/carbon/human/proc/update_surgery(var/update_icons=1) + overlays_standing[SURGERY_LEVEL] = null + var/image/total = new + for(var/obj/item/organ/external/E in organs) + if(E.robotic < ORGAN_ROBOT && E.open()) + var/image/I = image("icon"='icons/mob/surgery.dmi', "icon_state"="[E.icon_name][round(E.open())]", "layer"=-SURGERY_LEVEL) + total.overlays += I + total.appearance_flags = RESET_COLOR + overlays_standing[SURGERY_LEVEL] = total + if(update_icons) update_icons() + +//Human Overlays Indexes///////// +#undef MUTATIONS_LAYER +#undef DAMAGE_LAYER +#undef SURGERY_LEVEL +#undef UNIFORM_LAYER +#undef ID_LAYER +#undef SHOES_LAYER +#undef GLOVES_LAYER +#undef EARS_LAYER +#undef SUIT_LAYER +#undef TAIL_LAYER +#undef GLASSES_LAYER +#undef FACEMASK_LAYER +#undef BELT_LAYER +#undef SUIT_STORE_LAYER +#undef BACK_LAYER +#undef HAIR_LAYER +#undef HEAD_LAYER +#undef COLLAR_LAYER +#undef HANDCUFF_LAYER +#undef L_HAND_LAYER +#undef R_HAND_LAYER +#undef TARGETED_LAYER +#undef FIRE_LAYER +#undef FLIES_LAYER +#undef COLDBREATH_LAYER +#undef TOTAL_LAYERS diff --git a/code/modules/mob/living/carbon/human/vision_cone.dm b/code/modules/mob/living/carbon/human/vision_cone.dm new file mode 100644 index 00000000..e214e50a --- /dev/null +++ b/code/modules/mob/living/carbon/human/vision_cone.dm @@ -0,0 +1,59 @@ +/////////////VISION CONE/////////////// +//Vision cone code by, originally by Matt and Honkertron, rewritten by Chaoko99. This vision cone code allows for mobs and/or items to blocked out from a players field of vision. +//It makes use of planes and alpha masks only possible in 513 and above. Please see human_alt.dm and hud_alt.dm in the hud folder for more info on how this works. +/////////////////////////////////////// + +//"Made specially for Otuska" +// - Honker + + +// And now a note from Chaoko99 on what he did to the old vision cone code: +// "Kinda ripped all this out. Made a big fucking mess of the place, but this is overall cheaper. Probably breaks shit too. +// Refer to some earlier revision or interbay 2.0 for the original code." +// ~Chaoko99 + + +/mob/proc/update_vision_cone() + return + +/mob/living/carbon/human/update_vision_cone() + if(!src.client) //This doesn't actually hide shit from clientless mobs, so just keep them from running this. + return + check_fov() + src.fov.dir = src.dir + src.fov_mask.dir = src.dir + + +/mob/living/carbon/human/proc/SetFov(var/show) + if(!show) + hide_cone() + else + show_cone() + +/mob/living/carbon/human/proc/check_fov() + if(!src.client) + return + + if(resting || lying || (client && client.eye != client.mob)) + src.fov.alpha = 0 + src.fov_mask.alpha = 0 + return + + else if(src.usefov) + show_cone() + + else + hide_cone() + +//Making these generic procs so you can call them anywhere. +/mob/living/carbon/human/proc/show_cone() + if(src.fov) + src.fov.alpha = 255 + src.usefov = TRUE + src.fov_mask.alpha = 255 + +/mob/living/carbon/human/proc/hide_cone() + if(src.fov) + src.fov.alpha = 0 + src.usefov = FALSE + src.fov_mask.alpha = 0 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/weight.dm b/code/modules/mob/living/carbon/human/weight.dm new file mode 100644 index 00000000..20128799 --- /dev/null +++ b/code/modules/mob/living/carbon/human/weight.dm @@ -0,0 +1,87 @@ +#define OVERLOAD_NONE 0 +#define OVERLOAD_LIGHT 1 +#define OVERLOAD_MEDIUM 2 +#define OVERLOAD_HIGH 4 +#define OVERLOAD_EXTREME 8 + +/obj/ + var/weight = 0 + +//Use New() proc to add custom weight to items, this proc is just temporary solution for items that don't have custom weight// + +/obj/New() + ..() + if(w_class == INFINITY) + weight = 150 + else + weight = w_class*w_class / 2 + +//Adding weights to mob// + +/mob/living + var/baseweight = 0 + var/baseload = 0 + var/weight = 0 + var/loads = 0 + +//Updates all weight variables// + +/mob/living/proc/updateweight() + baseload = 10 + round(STAT_LEVEL(str) * STAT_LEVEL(end) / 4) + baseweight = (STAT_LEVEL(str) + STAT_LEVEL(end)) * 4 + weight = baseweight + check_weight() + loads = check_weight() +//to_chat(world, "baseload is [baseload], load is [loads], overweight is [overweight].") + +//Checks sum weight of /obj/item/ stuff on the mob, except organs// + +/mob/living/proc/check_weight() + var/weight_sum = 0 + for(var/obj/item/O in contents) + if(!istype(O, /obj/item/organ)) + if(!istype(O, /obj/item/weapon/storage,)) + weight_sum += O.weight + if(istype(O, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/ST = O + weight_sum += ST.check_my_weight() + return weight_sum + +//Checks sum weight of /obj/item/ stuff in the backpack, also does loop for other storages in case there is one inside of other// + +/obj/item/weapon/storage/proc/check_my_weight() + var/weight_sum = 0 + for(var/obj/item/O in contents) + weight_sum += O.weight + if(istype(O, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/ST = O + weight_sum += ST.check_my_weight() + return weight_sum + +/mob/living/proc/overweight() + if(loads < baseload * 2) + return OVERLOAD_NONE + if(loads > baseload * 2) + return OVERLOAD_LIGHT + if(loads > baseload * 3) + return OVERLOAD_MEDIUM + if(loads > baseload * 6) + return OVERLOAD_HIGH + if(loads > baseload * 10) + return OVERLOAD_EXTREME + +/mob/living/proc/overweighttxt() + switch (overweight()) + if(OVERLOAD_LIGHT) + return "It's slightly uncomfortable to carry this." + if(OVERLOAD_MEDIUM) + return "It's quite heavy to carry." + if(OVERLOAD_HIGH) + return "This is too heavy to carry!" + if(OVERLOAD_EXTREME) + return "I am OVERLOADED!" + +#undef OVERLOAD_NONE +#undef OVERLOAD_LIGHT +#undef OVERLOAD_MEDIUM +#undef OVERLOAD_HIGH +#undef OVERLOAD_EXTREME diff --git a/code/modules/mob/living/carbon/human/whisper.dm b/code/modules/mob/living/carbon/human/whisper.dm new file mode 100644 index 00000000..2d2310b6 --- /dev/null +++ b/code/modules/mob/living/carbon/human/whisper.dm @@ -0,0 +1,24 @@ +//Lallander was here +/mob/living/carbon/human/whisper(message as text) + message = sanitize(message) + + if (src.client) + if (src.client.prefs.muted & MUTE_IC) + to_chat(src, "You cannot whisper (muted).") + return + + if (src.stat == 2) + return src.say_dead(message) + + if (src.stat) + return + + if(get_id_name("Unknown") == GetVoice()) + SetName(get_id_name("Unknown")) + + whisper_say(message) + + +//This is used by both the whisper verb and human/say() to handle whispering +/mob/living/carbon/human/proc/whisper_say(var/message, var/datum/language/speaking = null, var/alt_name="", var/verb="whispers") + say(message, speaking, verb, alt_name, whispering = 1) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm new file mode 100644 index 00000000..34597038 --- /dev/null +++ b/code/modules/mob/living/carbon/life.dm @@ -0,0 +1,38 @@ +/mob/living/carbon/Life() + if(!..()) + return + + UpdateStasis() + + // Increase germ_level regularly + if(germ_level < GERM_LEVEL_AMBIENT && prob(30)) //if you're just standing there, you shouldn't get more germs beyond an ambient level + germ_level++ + + if(stat != DEAD && !InStasis()) + //Breathing, if applicable + handle_breathing() + + //Mutations and radiation + handle_mutations_and_radiation() + + //Chemicals in the body + handle_chemicals_in_body() + + //Random events (vomiting etc) + handle_random_events() + + //stuff in the stomach + handle_stomach() + + // eye, ear, brain damages + handle_disabilities() + + //all special effects, stunned, weakened, jitteryness, hallucination, sleeping, etc + handle_statuses() + + handle_viruses() + + . = 1 + + if(!client && !mind && species) + species.handle_npc(src) diff --git a/code/modules/mob/living/carbon/resist.dm b/code/modules/mob/living/carbon/resist.dm new file mode 100644 index 00000000..8a935a56 --- /dev/null +++ b/code/modules/mob/living/carbon/resist.dm @@ -0,0 +1,119 @@ +/mob/living/carbon/process_resist() + + //drop && roll + if(on_fire && !buckled) + fire_stacks -= 1.2 + Weaken(3) + spin(32,2) + visible_message( + "[src] rolls on the floor, trying to put themselves out!", + "You stop, drop, and roll!" + ) + sleep(30) + if(fire_stacks <= 0) + visible_message( + "[src] has successfully extinguished themselves!", + "You extinguish yourself." + ) + ExtinguishMob() + return TRUE + + if(..()) + return TRUE + + if(handcuffed) + spawn() escape_handcuffs() + +/mob/living/carbon/proc/escape_handcuffs() + //if(!(last_special <= world.time)) return + + //This line represent a significant buff to grabs... + // We don't have to check the click cooldown because /mob/living/verb/resist() has done it for us, we can simply set the delay + setClickCooldown(100) + + if(can_break_cuffs()) //Don't want to do a lot of logic gating here. + break_handcuffs() + return + + var/obj/item/weapon/handcuffs/HC = handcuffed + + //A default in case you are somehow handcuffed with something that isn't an obj/item/weapon/handcuffs type + var/breakouttime = 1200 + var/displaytime = 2 //Minutes to display in the "this will take X minutes." + //If you are handcuffed with actual handcuffs... Well what do I know, maybe someone will want to handcuff you with toilet paper in the future... + if(istype(HC)) + breakouttime = HC.breakouttime + displaytime = breakouttime / 600 //Minutes + + //var/mob/living/carbon/human/H = src + + visible_message( + "\The [src] attempts to remove \the [HC]!", + "You attempt to remove \the [HC]. (This will take around [displaytime] minutes and you need to stand still)" + ) + + if(do_after(src, breakouttime, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) + if(!handcuffed || buckled) + return + visible_message( + "\The [src] manages to remove \the [handcuffed]!", + "You successfully remove \the [handcuffed]." + ) + drop_from_inventory(handcuffed) + +/mob/living/carbon/proc/can_break_cuffs() + if(HULK in mutations) + return 1 + +/mob/living/carbon/proc/break_handcuffs() + visible_message( + "[src] is trying to break \the [handcuffed]!", + "You attempt to break your [handcuffed.name]. (This will take around 5 seconds and you need to stand still)" + ) + + if(do_after(src, 5 SECONDS, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) + if(!handcuffed || buckled) + return + + visible_message( + "[src] manages to break \the [handcuffed]!", + "You successfully break your [handcuffed.name]." + ) + + say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) + + qdel(handcuffed) + handcuffed = null + if(buckled && buckled.buckle_require_restraints) + buckled.unbuckle_mob() + update_inv_handcuffed() + +/mob/living/carbon/human/can_break_cuffs() + if(species.can_shred(src,1)) + return 1 + return ..() + +/mob/living/carbon/escape_buckle() + if(src.handcuffed && istype(src.buckled, /obj/effect/energy_net)) + var/obj/effect/energy_net/N = src.buckled + N.escape_net(src) //super snowflake but is literally used NOWHERE ELSE.-Luke + return + + setClickCooldown(100) + if(!buckled) return + + if(!restrained()) + ..() + else + visible_message( + "[usr] attempts to unbuckle themself!", + "You attempt to unbuckle yourself. (This will take around 2 minutes and you need to stand still)" + ) + + + if(do_after(usr, 2 MINUTES, incapacitation_flags = INCAPACITATION_DEFAULT & ~(INCAPACITATION_RESTRAINED | INCAPACITATION_BUCKLED_FULLY))) + if(!buckled) + return + visible_message("\The [usr] manages to unbuckle themself!", + "You successfully unbuckle yourself.") + buckled.user_unbuckle_mob(src) diff --git a/code/modules/mob/living/carbon/taste.dm b/code/modules/mob/living/carbon/taste.dm new file mode 100644 index 00000000..742a0e20 --- /dev/null +++ b/code/modules/mob/living/carbon/taste.dm @@ -0,0 +1,64 @@ + +/mob/living/carbon/proc/ingest(var/datum/reagents/from, var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0) //we kind of 'sneak' a proc in here for ingesting stuff so we can play with it. + if(last_taste_time + 50 < world.time) + var/datum/reagents/temp = new(amount, GLOB.temp_reagents_holder) //temporary holder used to analyse what gets transfered. + from.trans_to_holder(temp, amount, multiplier, 1) + + var/text_output = temp.generate_taste_message(src) + if(text_output != last_taste_text || last_taste_time + 100 < world.time) //We dont want to spam the same message over and over again at the person. Give it a bit of a buffer. + to_chat(src, "You can taste [text_output].")//no taste means there are too many tastes and not enough flavor. + + last_taste_time = world.time + last_taste_text = text_output + return from.trans_to_holder(target,amount,multiplier,copy) //complete transfer + +/* what this does: +catalogue the 'taste strength' of each one +calculate text size per text. +*/ +/datum/reagents/proc/generate_taste_message(mob/living/carbon/taster = null) + var/minimum_percent = 15 + if(ishuman(taster)) + var/mob/living/carbon/human/H = taster + minimum_percent = round(15/ (H.isSynthetic() ? TASTE_DULL : H.species.taste_sensitivity)) + + var/list/out = list() + var/list/tastes = list() //descriptor = strength + if(minimum_percent <= 100) + for(var/datum/reagent/R in reagent_list) + if(!R.taste_mult) + continue + if(R.type == /datum/reagent/nutriment) //this is ugly but apparently only nutriment (not subtypes) has taste data TODO figure out why + var/list/taste_data = R.get_data() + for(var/taste in taste_data) + if(taste in tastes) + tastes[taste] += taste_data[taste] + else + tastes[taste] = taste_data[taste] + else + var/taste_desc = R.taste_description + var/taste_amount = get_reagent_amount(R.type) * R.taste_mult + if(R.taste_description in tastes) + tastes[taste_desc] += taste_amount + else + tastes[taste_desc] = taste_amount + + //deal with percentages + var/total_taste = 0 + for(var/taste_desc in tastes) + total_taste += tastes[taste_desc] + for(var/taste_desc in tastes) + var/percent = tastes[taste_desc]/total_taste * 100 + if(percent < minimum_percent) + continue + var/intensity_desc = "a hint of" + if(percent > minimum_percent * 2 || percent == 100) + intensity_desc = "" + else if(percent > minimum_percent * 3) + intensity_desc = "the strong flavor of" + if(intensity_desc == "") + out += "[taste_desc]" + else + out += "[intensity_desc] [taste_desc]" + + return english_list(out, "something indescribable") diff --git a/code/modules/mob/living/carbon/viruses.dm b/code/modules/mob/living/carbon/viruses.dm new file mode 100644 index 00000000..8584e5d2 --- /dev/null +++ b/code/modules/mob/living/carbon/viruses.dm @@ -0,0 +1,62 @@ +/mob/living/carbon/var/immunity = 100 //current immune system strength +/mob/living/carbon/var/immunity_norm = 100 //it will regenerate to this value +/mob/living/carbon/proc/handle_viruses() + + if(status_flags & GODMODE) return 0 //godmode + + if(bodytemperature > 406) + for (var/ID in virus2) + var/datum/disease2/disease/V = virus2[ID] + V.cure(src) + + if(life_tick % 3) //don't spam checks over all objects in view every tick. + for(var/obj/effect/decal/cleanable/O in view(1,src)) + if(istype(O,/obj/effect/decal/cleanable/blood)) + var/obj/effect/decal/cleanable/blood/B = O + if(isnull(B.virus2)) + B.virus2 = list() + if(B.virus2.len) + for (var/ID in B.virus2) + var/datum/disease2/disease/V = B.virus2[ID] + infect_virus2(src,V) + + else if(istype(O,/obj/effect/decal/cleanable/mucus)) + var/obj/effect/decal/cleanable/mucus/M = O + if(isnull(M.virus2)) + M.virus2 = list() + if(M.virus2.len) + for (var/ID in M.virus2) + var/datum/disease2/disease/V = M.virus2[ID] + infect_virus2(src,V) + + if(virus2.len) + for (var/ID in virus2) + var/datum/disease2/disease/V = virus2[ID] + if(isnull(V)) // Trying to figure out a runtime error that keeps repeating + CRASH("virus2 nulled before calling activate()") + else + V.process(src) + // activate may have deleted the virus + if(!V) continue + + // check if we're immune + var/list/common_antibodies = V.antigen & src.antibodies + if(common_antibodies.len) + V.dead = 1 + + immunity = min(immunity + 0.25, immunity_norm) + + if(life_tick % 5 && immunity < 15 && chem_effects[CE_ANTIVIRAL] < VIRUS_COMMON && !virus2.len) + var/infection_prob = 15 - immunity + var/turf/simulated/T = loc + if(istype(T)) + infection_prob += T.dirt + if(prob(infection_prob)) + infect_mob_random_lesser(src) + +/mob/living/carbon/proc/virus_immunity() + var/antibiotic_boost = reagents.get_reagent_amount(/datum/reagent/spaceacillin) / (REAGENTS_OVERDOSE/2) + return max(immunity/100 * (1+antibiotic_boost), antibiotic_boost) + +/mob/living/carbon/proc/immunity_weakness() + return max(2-virus_immunity(), 0) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/xenobiological/death.dm b/code/modules/mob/living/carbon/xenobiological/death.dm new file mode 100644 index 00000000..330a6532 --- /dev/null +++ b/code/modules/mob/living/carbon/xenobiological/death.dm @@ -0,0 +1,22 @@ +/mob/living/carbon/slime/death(gibbed, deathmessage, show_dead_message) + + if(stat == DEAD) return + + if(!gibbed && is_adult) + var/mob/living/carbon/slime/M = new /mob/living/carbon/slime(loc, colour) + M.rabid = 1 + M.Friends = Friends.Copy() + step_away(M, src) + is_adult = 0 + maxHealth = 150 + revive() + if (!client) rabid = 1 + number = rand(1, 1000) + SetName("[colour] [is_adult ? "adult" : "baby"] slime ([number])") + return + + . = ..(gibbed, deathmessage, show_dead_message) + mood = null + regenerate_icons() + + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/xenobiological/examine.dm b/code/modules/mob/living/carbon/xenobiological/examine.dm new file mode 100644 index 00000000..07bbbf89 --- /dev/null +++ b/code/modules/mob/living/carbon/xenobiological/examine.dm @@ -0,0 +1,31 @@ +/mob/living/carbon/slime/examine(mob/user) + . = ..(user) + var/msg = "" + if (src.stat == DEAD) + msg += "It is limp and unresponsive.\n" + else + if (src.getBruteLoss()) + msg += "" + if (src.getBruteLoss() < 40) + msg += "It has some punctures in its flesh!" + else + msg += "It has severe punctures and tears in its flesh!" + msg += "\n" + + switch(powerlevel) + + if(2 to 3) + msg += "It is flickering gently with a little electrical activity.\n" + + if(4 to 5) + msg += "It is glowing gently with moderate levels of electrical activity.\n" + + if(6 to 9) + msg += "It is glowing brightly with high levels of electrical activity.\n" + + if(10) + msg += "It is radiating with massive levels of electrical activity!\n" + + msg += "*---------*" + to_chat(user, msg) + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/xenobiological/hud.dm b/code/modules/mob/living/carbon/xenobiological/hud.dm new file mode 100644 index 00000000..c093d61f --- /dev/null +++ b/code/modules/mob/living/carbon/xenobiological/hud.dm @@ -0,0 +1,2 @@ +/mob/living/carbon/slime/handle_regular_hud_updates() + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/xenobiological/items.dm b/code/modules/mob/living/carbon/xenobiological/items.dm new file mode 100644 index 00000000..28d5a405 --- /dev/null +++ b/code/modules/mob/living/carbon/xenobiological/items.dm @@ -0,0 +1,283 @@ +/obj/item/slime_extract + name = "slime extract" + desc = "Goo extracted from a slime. Legends claim these to have \"magical powers\"." + icon = 'icons/mob/slimes.dmi' + icon_state = "grey slime extract" + force = 1.0 + w_class = ITEM_SIZE_TINY + throwforce = 0 + throw_speed = 3 + throw_range = 6 + origin_tech = list(TECH_BIO = 4) + var/Uses = 1 // uses before it goes inert + var/enhanced = 0 //has it been enhanced before? + atom_flags = ATOM_FLAG_OPEN_CONTAINER + + attackby(obj/item/O as obj, mob/user as mob) + if(istype(O, /obj/item/weapon/slimesteroid2)) + if(enhanced == 1) + to_chat(user, " This extract has already been enhanced!") + return ..() + if(Uses == 0) + to_chat(user, " You can't enhance a used extract!") + return ..() + to_chat(user, "You apply the enhancer. It now has triple the amount of uses.") + Uses = 3 + enhanced = 1 + qdel(O) + +/obj/item/slime_extract/New() + ..() + create_reagents(100) + reagents.add_reagent(/datum/reagent/slimejelly, 30) + +/obj/item/slime_extract/grey + name = "grey slime extract" + icon_state = "grey slime extract" + +/obj/item/slime_extract/gold + name = "gold slime extract" + icon_state = "gold slime extract" + +/obj/item/slime_extract/silver + name = "silver slime extract" + icon_state = "silver slime extract" + +/obj/item/slime_extract/metal + name = "metal slime extract" + icon_state = "metal slime extract" + +/obj/item/slime_extract/purple + name = "purple slime extract" + icon_state = "purple slime extract" + +/obj/item/slime_extract/darkpurple + name = "dark purple slime extract" + icon_state = "dark purple slime extract" + +/obj/item/slime_extract/orange + name = "orange slime extract" + icon_state = "orange slime extract" + +/obj/item/slime_extract/yellow + name = "yellow slime extract" + icon_state = "yellow slime extract" + +/obj/item/slime_extract/red + name = "red slime extract" + icon_state = "red slime extract" + +/obj/item/slime_extract/blue + name = "blue slime extract" + icon_state = "blue slime extract" + +/obj/item/slime_extract/darkblue + name = "dark blue slime extract" + icon_state = "dark blue slime extract" + +/obj/item/slime_extract/pink + name = "pink slime extract" + icon_state = "pink slime extract" + +/obj/item/slime_extract/green + name = "green slime extract" + icon_state = "green slime extract" + +/obj/item/slime_extract/lightpink + name = "light pink slime extract" + icon_state = "light pink slime extract" + +/obj/item/slime_extract/black + name = "black slime extract" + icon_state = "black slime extract" + +/obj/item/slime_extract/oil + name = "oil slime extract" + icon_state = "oil slime extract" + +/obj/item/slime_extract/adamantine + name = "adamantine slime extract" + icon_state = "adamantine slime extract" + +/obj/item/slime_extract/bluespace + name = "bluespace slime extract" + icon_state = "bluespace slime extract" + +/obj/item/slime_extract/pyrite + name = "pyrite slime extract" + icon_state = "pyrite slime extract" + +/obj/item/slime_extract/cerulean + name = "cerulean slime extract" + icon_state = "cerulean slime extract" + +/obj/item/slime_extract/sepia + name = "sepia slime extract" + icon_state = "sepia slime extract" + +/obj/item/slime_extract/rainbow + name = "rainbow slime extract" + icon_state = "rainbow slime extract" + +////Pet Slime Creation/// + +/obj/item/weapon/slimepotion + name = "docility potion" + desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle19" + + attack(mob/living/carbon/slime/M as mob, mob/user as mob) + if(!istype(M, /mob/living/carbon/slime))//If target is not a slime. + to_chat(user, " The potion only works on baby slimes!") + return ..() + if(M.is_adult) //Can't tame adults + to_chat(user, " Only baby slimes can be tamed!") + return..() + if(M.stat) + to_chat(user, " The slime is dead!") + return..() + if(M.mind) + to_chat(user, " The slime resists!") + return ..() + var/mob/living/simple_animal/slime/pet = new /mob/living/simple_animal/slime(M.loc) + pet.icon_state = "[M.colour] baby slime" + pet.icon_living = "[M.colour] baby slime" + pet.icon_dead = "[M.colour] baby slime dead" + pet.colour = "[M.colour]" + to_chat(user, "You feed the slime the potion, removing it's powers and calming it.") + qdel(M) + var/newname = sanitize(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text, MAX_NAME_LEN) + + if (!newname) + newname = "pet slime" + pet.SetName(newname) + pet.real_name = newname + qdel(src) + +/obj/item/weapon/slimepotion2 + name = "advanced docility potion" + desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame. This one is meant for adult slimes." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle19" + + attack(mob/living/carbon/slime/M as mob, mob/user as mob) + if(!istype(M, /mob/living/carbon/slime/))//If target is not a slime. + to_chat(user, " The potion only works on slimes!") + return ..() + if(M.stat) + to_chat(user, " The slime is dead!") + return..() + if(M.mind) + to_chat(user, " The slime resists!") + return ..() + var/mob/living/simple_animal/adultslime/pet = new /mob/living/simple_animal/adultslime(M.loc) + pet.icon_state = "[M.colour] adult slime" + pet.icon_living = "[M.colour] adult slime" + pet.icon_dead = "[M.colour] baby slime dead" + pet.colour = "[M.colour]" + to_chat(user, "You feed the slime the potion, removing it's powers and calming it.") + qdel(M) + var/newname = sanitize(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text, MAX_NAME_LEN) + + if (!newname) + newname = "pet slime" + pet.SetName(newname) + pet.real_name = newname + qdel(src) + + +/obj/item/weapon/slimesteroid + name = "slime steroid" + desc = "A potent chemical mix that will cause a slime to generate more extract." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle16" + + attack(mob/living/carbon/slime/M as mob, mob/user as mob) + if(!istype(M, /mob/living/carbon/slime))//If target is not a slime. + to_chat(user, " The steroid only works on baby slimes!") + return ..() + if(M.is_adult) //Can't tame adults + to_chat(user, " Only baby slimes can use the steroid!") + return..() + if(M.stat) + to_chat(user, " The slime is dead!") + return..() + if(M.cores == 3) + to_chat(user, " The slime already has the maximum amount of extract!") + return..() + + to_chat(user, "You feed the slime the steroid. It now has triple the amount of extract.") + M.cores = 3 + qdel(src) + +/obj/item/weapon/slimesteroid2 + name = "extract enhancer" + desc = "A potent chemical mix that will give a slime extract three uses." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle17" + +/obj/item/weapon/slimesteroid2/afterattack(obj/target, mob/user , flag) + if(istype(target, /obj/item/slime_extract)) + var/obj/item/slime_extract/extract = target + if(extract.enhanced == 1) + to_chat(user, " This extract has already been enhanced!") + return ..() + if(extract.Uses == 0) + to_chat(user, " You can't enhance a used extract!") + return ..() + to_chat(user, "You apply the enhancer. It now has triple the amount of uses.") + extract.Uses = 3 + extract.enhanced = 1 + qdel(src) + +/obj/effect/golemrune + anchored = 1 + desc = "a strange rune used to create golems. It glows when spirits are nearby." + name = "rune" + icon = 'icons/obj/rune.dmi' + icon_state = "golem" + unacidable = 1 + plane = ABOVE_TURF_PLANE + layer = RUNE_LAYER + +/obj/effect/golemrune/Initialize() + ..() + START_PROCESSING(SSobj, src) + +/obj/effect/golemrune/Process() + var/mob/observer/ghost/ghost + for(var/mob/observer/ghost/O in src.loc) + if(!O.client) continue + if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue + ghost = O + break + if(ghost) + icon_state = "golem2" + else + icon_state = "golem" + +/obj/effect/golemrune/attack_hand(mob/living/user as mob) + var/mob/observer/ghost/ghost + for(var/mob/observer/ghost/O in src.loc) + if(!O.client) continue + if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue + ghost = O + break + if(!ghost) + to_chat(user, "The rune fizzles uselessly. There is no spirit nearby.") + return + var/mob/living/carbon/human/G = new(src.loc) + G.set_species("Golem") + G.key = ghost.key + to_chat(G, "You are an adamantine golem. You move slowly, but are highly resistant to heat and cold as well as blunt trauma. Serve [user], and assist them in completing their goals at any cost.") + qdel(src) + + +/obj/effect/golemrune/proc/announce_to_ghosts() + for(var/mob/observer/ghost/G in GLOB.player_list) + if(G.client) + var/area/A = get_area(src) + if(A) + to_chat(G, "Golem rune created in [A.name].") + diff --git a/code/modules/mob/living/carbon/xenobiological/life.dm b/code/modules/mob/living/carbon/xenobiological/life.dm new file mode 100644 index 00000000..a284c730 --- /dev/null +++ b/code/modules/mob/living/carbon/xenobiological/life.dm @@ -0,0 +1,170 @@ +/mob/living/carbon/slime/Life() + set invisibility = 0 + set background = 1 + + if (src.transforming) + return + + ..() + + if(stat != DEAD) + handle_nutrition() + + if(!client) + handle_regular_AI() + +/mob/living/carbon/slime/handle_environment(datum/gas_mixture/environment) + if(!environment) + adjustToxLoss(rand(10,20)) + return + + //var/environment_heat_capacity = environment.heat_capacity() + var/loc_temp = T0C + if(istype(get_turf(src), /turf/space)) + //environment_heat_capacity = loc:heat_capacity + var/turf/heat_turf = get_turf(src) + loc_temp = heat_turf.temperature + else if(istype(loc, /obj/machinery/atmospherics/unary/cryo_cell)) + loc_temp = loc:air_contents.temperature + else + loc_temp = environment.temperature + + bodytemperature += adjust_body_temperature(bodytemperature, loc_temp, 1) + + if(bodytemperature < (T0C + 5)) // start calculating temperature damage etc + if(bodytemperature <= hurt_temperature) + if(bodytemperature <= die_temperature) + adjustToxLoss(200) + else + // could be more fancy, but doesn't worth the complexity: when the slimes goes into a cold area + // the damage is mostly determined by how fast its body cools + adjustToxLoss(30) + + updatehealth() + + return //TODO: DEFERRED + +/mob/living/carbon/slime/proc/adjust_body_temperature(current, loc_temp, boost) + var/temperature = current + var/difference = abs(current-loc_temp) //get difference + var/increments// = difference/10 //find how many increments apart they are + if(difference > 50) + increments = difference/5 + else + increments = difference/10 + var/change = increments*boost // Get the amount to change by (x per increment) + var/temp_change + if(current < loc_temp) + temperature = min(loc_temp, temperature+change) + else if(current > loc_temp) + temperature = max(loc_temp, temperature-change) + temp_change = (temperature - current) + return temp_change + +/mob/living/carbon/slime/handle_chemicals_in_body() + chem_effects.Cut() + + if(touching) touching.metabolize() + if(ingested) ingested.metabolize() + if(bloodstr) bloodstr.metabolize() + + src.updatehealth() + + return //TODO: DEFERRED + +/mob/living/carbon/slime/handle_regular_status_updates() + + src.blinded = null + + health = maxHealth - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss()) + + if(health < 0 && stat != DEAD) + death() + return + + if(getHalLoss()) + setHalLoss(0) + + if(prob(30)) + adjustOxyLoss(-1) + adjustToxLoss(-1) + adjustFireLoss(-1) + adjustCloneLoss(-1) + adjustBruteLoss(-1) + + if (src.stat == DEAD) + src.lying = 1 + src.blinded = 1 + else + if (src.paralysis || src.stunned || src.weakened || (status_flags && FAKEDEATH)) //Stunned etc. + if (src.stunned > 0) + src.set_stat(CONSCIOUS) + if (src.weakened > 0) + src.lying = 0 + src.set_stat(CONSCIOUS) + if (src.paralysis > 0) + src.blinded = 0 + src.lying = 0 + src.set_stat(CONSCIOUS) + + else + src.lying = 0 + src.set_stat(CONSCIOUS) + + if (src.stuttering) src.stuttering = 0 + + if (src.eye_blind) + src.eye_blind = 0 + src.blinded = 1 + + if (src.ear_deaf > 0) src.ear_deaf = 0 + if (src.ear_damage < 25) + src.ear_damage = 0 + + src.set_density(!src.lying) + + if (src.sdisabilities & BLIND) + src.blinded = 1 + if (src.sdisabilities & DEAF) + src.ear_deaf = 1 + + if (src.eye_blurry > 0) + src.eye_blurry = 0 + + if (src.druggy > 0) + src.druggy = 0 + + return 1 + +/mob/living/carbon/slime/proc/handle_nutrition() + + nutrition -= 0.1 + 0.05 * is_adult + + if(nutrition <= 0) + nutrition = 0 + adjustToxLoss(2) + if (client && prob(5)) + to_chat(src, "You are starving!") + + else if (nutrition >= get_grow_nutrition() && amount_grown < 10) + nutrition -= 20 + amount_grown++ + +/mob/living/carbon/slime/proc/get_max_nutrition() // Can't go above it + if (is_adult) return 1200 + else return 1000 + +/mob/living/carbon/slime/proc/get_grow_nutrition() // Above it we grow, below it we can eat + if (is_adult) return 1000 + else return 800 + +/mob/living/carbon/slime/proc/get_hunger_nutrition() // Below it we will always eat + if (is_adult) return 600 + else return 500 + +/mob/living/carbon/slime/proc/get_starve_nutrition() // Below it we will eat before everything else + if (is_adult) return 300 + else return 200 + +/mob/living/carbon/slime/slip() //Can't slip something without legs. + return 0 diff --git a/code/modules/mob/living/carbon/xenobiological/powers.dm b/code/modules/mob/living/carbon/xenobiological/powers.dm new file mode 100644 index 00000000..ea317ff6 --- /dev/null +++ b/code/modules/mob/living/carbon/xenobiological/powers.dm @@ -0,0 +1,180 @@ +/mob/living/carbon/slime/proc/Wrap(var/mob/living/M) // This is a proc for the clicks + if (Victim == M || src == M) + Feedstop() + return + + if (Victim) + to_chat(src, "I am already feeding...") + return + + var t = invalidFeedTarget(M) + if (t) + to_chat(src, t) + return + + Feedon(M) + +/mob/living/carbon/slime/proc/invalidFeedTarget(var/mob/living/M) + if (!istype(M)) + return "This subject is incompatible..." + if (istype(M, /mob/living/carbon/slime)) // No cannibalism... yet + return "I cannot feed on other slimes..." + if (!Adjacent(M)) + return "This subject is too far away..." + if (issilicon(M)) + return "This subject does not have an edible life energy..." + if (M.getarmor(null, "bio") >= 100) + return "This subject is protected..." + if (ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.species.species_flags & (SPECIES_FLAG_NO_POISON|SPECIES_FLAG_NO_SCAN)) + //they can't take clone or tox damage, then for the most part they aren't affected by being fed on - and presumably feeding on them would not affect the slime either + return "This subject does not have an edible life energy..." + if (istype(M, /mob/living/carbon) && M.getCloneLoss() >= M.maxHealth * 1.5 || istype(M, /mob/living/simple_animal) && M.stat == DEAD) + return "This subject does not have an edible life energy..." + for(var/mob/living/carbon/slime/met in view()) + if(met.Victim == M && met != src) + return "\The [met] is already feeding on this subject..." + return 0 + +/mob/living/carbon/slime/proc/Feedon(var/mob/living/M) + set waitfor = 0 + Victim = M + forceMove(M.loc) + + sleep(20) // A small delay to give the victim a chance to shake them off + + regenerate_icons() + var/happyWithFood = 0 + var/totalDrained = 0 + + while(Victim && stat != 2) + if(Adjacent(M)) + UpdateFeed() + + var/hazmat = blocked_mult(M.getarmor(null, "bio")) //scale feeding rate by overall bio protection + if(istype(M, /mob/living/carbon)) + Victim.adjustCloneLoss(5 * hazmat) + Victim.adjustToxLoss(1 * hazmat) + if(Victim.health <= 0) + Victim.adjustToxLoss(1 * hazmat) + + else if(istype(M, /mob/living/simple_animal)) + Victim.adjustBruteLoss(10 * hazmat) + + else + to_chat(src, "[pick("This subject is incompatable", "This subject does not have a life energy", "This subject is empty", "I am not satisified", "I can not feed from this subject", "I do not feel nourished", "This subject is not food")]...") + Feedstop() + break + + if(prob(15) && M.client && istype(M, /mob/living/carbon)) + var/painMes = pick("You can feel your body becoming weak!", "You feel like you're about to die!", "You feel every part of your body screaming in agony!", "A low, rolling pain passes through your body!", "Your body feels as if it's falling apart!", "You feel extremely weak!", "A sharp, deep pain bathes every inch of your body!") + if (ishuman(M)) + var/mob/living/carbon/human/H = M + H.custom_pain(painMes,100) + else if (istype(M, /mob/living/carbon)) + var/mob/living/carbon/C = M + if (C.can_feel_pain()) + to_chat(M, "[painMes]") + + gain_nutrition(20 * hazmat) + totalDrained += 20 * hazmat + if(totalDrained > 200) + happyWithFood = 1 + + var/heal_amt = 10 * hazmat + adjustOxyLoss(-heal_amt) //Heal yourself + adjustBruteLoss(-heal_amt) + adjustFireLoss(-heal_amt) + adjustCloneLoss(-heal_amt) + updatehealth() + if(Victim) + Victim.updatehealth() + + if(invalidFeedTarget(M) && totalDrained > 40) // Drained + happyWithFood = 1 + break + + sleep(20) // Deal damage every 2 seconds + else + break + + if(happyWithFood) // This means that the slime has either drained the victim or let it go + if(!client) + if(Victim && !rabid && !attacked && Victim.LAssailant && Victim.LAssailant != Victim) + if(!(Victim.LAssailant in Friends)) + Friends[Victim.LAssailant] = 1 + else + ++Friends[Victim.LAssailant] + + else + to_chat(src, "This subject does not have a strong enough life energy anymore...") + + Victim = null + +/mob/living/carbon/slime/proc/Feedstop() + if(Victim) + Victim = null + +/mob/living/carbon/slime/proc/UpdateFeed() + if(Victim) + forceMove(Victim.loc) // simple "attach to head" effect! + +/mob/living/carbon/slime/verb/Evolve() + set category = "Slime" + set desc = "This will let you evolve from baby to adult slime." + + if(stat) + to_chat(src, "I must be conscious to do this...") + return + + if(!is_adult) + if(amount_grown >= 10) + is_adult = 1 + maxHealth = 200 + amount_grown = 0 + regenerate_icons() + SetName(text("[colour] [is_adult ? "adult" : "baby"] slime ([number])")) + else + to_chat(src, "I am not ready to evolve yet...") + else + to_chat(src, "I have already evolved...") + +/mob/living/carbon/slime/verb/Reproduce() + set category = "Slime" + set desc = "This will make you split into four slimes." + + if(stat) + to_chat(src, "I must be conscious to do this...") + return + + if(is_adult) + if(amount_grown >= 10) + if(stat) + to_chat(src, "I must be conscious to do this...") + return + + var/list/babies = list() + var/list/mutations = GetMutations() + for(var/i = 1 to 4) + var/t = colour + if(prob(mutation_chance)) + t = pick(mutations) + var/mob/living/carbon/slime/M = new /mob/living/carbon/slime(loc, t) + if(i != 1) + step_away(M, src) + M.Friends = Friends.Copy() + babies += M + feedback_add_details("slime_babies_born","slimebirth_[replacetext(M.colour," ","_")]") + + var/mob/living/carbon/slime/new_slime = babies[1] + new_slime.universal_speak = universal_speak + if(src.mind) + src.mind.transfer_to(new_slime) + else + new_slime.key = src.key + qdel(src) + else + to_chat(src, "I am not ready to reproduce yet...") + else + to_chat(src, "I am not old enough to reproduce yet...") diff --git a/code/modules/mob/living/carbon/xenobiological/say.dm b/code/modules/mob/living/carbon/xenobiological/say.dm new file mode 100644 index 00000000..bfa1eee1 --- /dev/null +++ b/code/modules/mob/living/carbon/xenobiological/say.dm @@ -0,0 +1,39 @@ +/mob/living/carbon/slime/say(var/message) + + message = sanitize(message) + + var/verb = say_quote(message) + + if(copytext(message,1,2) == get_prefix_key(/decl/prefix/custom_emote)) + return emote(copytext(message,2)) + + return ..(message, null, verb) + +/mob/living/carbon/slime/say_quote(var/text) + var/ending = copytext(text, length(text)) + + if (ending == "?") + return "asks"; + else if (ending == "!") + return "cries"; + + return "chirps"; + +/mob/living/carbon/slime/say_understands(var/other) + if (istype(other, /mob/living/carbon/slime)) + return 1 + return ..() + +/mob/living/carbon/slime/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) + if (speaker in Friends) + speech_buffer = list() + speech_buffer.Add(speaker) + speech_buffer.Add(lowertext(html_decode(message))) + ..() + +/mob/living/carbon/slime/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="") + if (speaker in Friends) + speech_buffer = list() + speech_buffer.Add(speaker) + speech_buffer.Add(lowertext(html_decode(message))) + ..() diff --git a/code/modules/mob/living/carbon/xenobiological/slime_AI.dm b/code/modules/mob/living/carbon/xenobiological/slime_AI.dm new file mode 100644 index 00000000..49ecef91 --- /dev/null +++ b/code/modules/mob/living/carbon/xenobiological/slime_AI.dm @@ -0,0 +1,356 @@ +/mob/living/carbon/slime/proc/handle_regular_AI() + if(client) + return + + if(attacked > 0) + if(attacked > 50) + attacked = 50 // Let's not get into absurdly long periods of rage + --attacked + + if(confused > 0) + --confused + return + + if(nutrition < get_starve_nutrition()) // If a slime is starving, it starts losing its friends + if(Friends.len > 0 && prob(1)) + var/mob/nofriend = pick(Friends) + if(nofriend && Friends[nofriend]) + Friends[nofriend] -= 1 + if (Friends[nofriend] <= 0) + Friends[nofriend] = null + Friends -= nofriend + Friends -= null + + handle_targets() + if (!AIproc) + spawn() + handle_AI() + handle_speech_and_mood() + +/mob/living/carbon/slime/proc/handle_targets() + if(Victim) // If it's eating someone already, continue eating! + return + + if(Target) + --target_patience + if (target_patience <= 0 || attacked || rabid) // Tired of chasing or attacking everything nearby + target_patience = 0 + Target = null + + var/hungry = 0 // determines if the slime is hungry + + if (nutrition < get_starve_nutrition()) + hungry = 2 + else if (nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition()) + hungry = 1 + + if(!Target) + if(will_hunt(hungry) || attacked || rabid) // Only add to the list if we need to + var/list/targets = list() + + for(var/mob/living/L in view(7,src)) + if(AssessTarget(L)) + targets += L // Possible target found! + + if(targets.len > 0) + if(attacked || rabid || hungry == 2) + Target = targets[1] // I am attacked and am fighting back or so hungry I don't even care + else + for(var/mob/living/carbon/C in targets) + if(ishuman(C) && prob(5)) + Target = C + break + + if(isalien(C) || issmall(C) || isanimal(C)) + Target = C + break + + if (Target) + target_patience = rand(5,7) + if (is_adult) + target_patience += 3 + + if(!Target) // If we have no target, we are wandering or following orders + if (Leader) + if (holding_still) + holding_still = max(holding_still - 1, 0) + else if(canmove && isturf(loc)) + step_to(src, Leader) + + else if(hungry) + if (holding_still) + holding_still = max(holding_still - 1 - hungry, 0) + else if(canmove && isturf(loc) && prob(50)) + step(src, pick(GLOB.cardinal)) + + else + if (holding_still) + holding_still = max(holding_still - 1, 0) + else if(canmove && isturf(loc) && prob(33)) + step(src, pick(GLOB.cardinal)) + +/mob/living/carbon/slime/proc/AssessTarget(var/mob/living/M) + if(isslime(M)) // Ignore other slimes + return 0 + + if(M in Friends) // Ignore friends + return 0 + + if(M.stat != DEAD) // Checks for those we just want to attack + if(rabid || attacked) // Will attack everything that isn't dead + return 1 + + if(!invalidFeedTarget(M)) // Checks for those we want to eat + if(istype(M, /mob/living/carbon/human)) // Ignore slime(wo)men - player-controlled slimes still can attack them + var/mob/living/carbon/human/H = M + if(H.species.name == SPECIES_PROMETHEAN) + return 0 + return 1 + + return 0 + +/mob/living/carbon/slime/proc/handle_AI() // the master AI process + if(stat == DEAD || client || Victim) + AIproc = 0 + return // If we're dead or have a client, we don't need AI, if we're feeding, we continue feeding + + if(confused) + AIproc = 0 + return + + AIproc = 1 + var/addedDelay = 0 + + if(amount_grown >= 10 && !Target) + if(is_adult) + Reproduce() + else + Evolve() + AIproc = 0 + return + + if(Target) // We're chasing the target + if(!AssessTarget(Target) || Target == Victim) // We don't need to chase them anymore + Target = null + AIproc = 0 + return + + for(var/mob/living/carbon/slime/M in view(1, Target)) + if(M.Victim == Target) + Target = null + AIproc = 0 + return + + if(Target.Adjacent(src)) + if(istype(Target, /mob/living/silicon)) // Glomp the silicons + a_intent = I_HURT + UnarmedAttack(Target) + addedDelay = 10 + + else if(Target.client && !Target.lying && prob(60 + powerlevel * 4)) // Try to take down the target first + a_intent = I_DISARM + UnarmedAttack(Target) + addedDelay = 10 + + else + a_intent = I_GRAB + if(invalidFeedTarget(Target)) + a_intent = I_HURT //just glomp them instead + addedDelay = 10 + UnarmedAttack(Target) + + else if(Target in view(7, src)) + step_to(src, Target) + + else + Target = null + AIproc = 0 + return + + else + var/mob/living/carbon/slime/frenemy + for (var/mob/living/carbon/slime/S in view(1, src)) + if (S != src) + frenemy = S + if (frenemy && prob(1) && frenemy.Adjacent(src)) + if (frenemy.colour == colour) + a_intent = I_HELP + else + a_intent = I_HURT + UnarmedAttack(frenemy) + + var/sleeptime = max(movement_delay(), 5) + addedDelay // Maximum one action per half a second + spawn (sleeptime) + handle_AI() + return + +/mob/living/carbon/slime/proc/UpdateFace() + var/newmood = "" + a_intent = I_HELP + if(confused) + newmood = "pout" + else if(rabid || attacked) + newmood = "angry" + a_intent = I_HURT + else if(Target) + newmood = "mischevous" + + if (!newmood) + if (prob(1)) + newmood = pick("sad", ":3") + + if ((mood == "sad" || mood == ":3") && !newmood) + if (prob(75)) newmood = mood + + if (newmood != mood) // This is so we don't redraw them every time + mood = newmood + regenerate_icons() + +/mob/living/carbon/slime/proc/handle_speech_and_mood() + UpdateFace() + + //Speech understanding starts here + var/to_say + if (speech_buffer.len > 0) + var/who = speech_buffer[1] // Who said it? + var/phrase = speech_buffer[2] // What did they say? + if ((findtext(phrase, num2text(number)) || findtext(phrase, "slimes"))) // Talking to us + if (findtext(phrase, "hello") || findtext(phrase, "hi")) + to_say = pick("Hello...", "Hi...") + else if (findtext(phrase, "follow")) + if (Leader) + if (Leader == who) // Already following him + to_say = pick("Yes...", "Lead...", "Following...") + else if (Friends[who] > Friends[Leader]) // VIVA + Leader = who + to_say = "Yes... I follow [who]..." + else + to_say = "No... I follow [Leader]..." + else + if (Friends[who] > 2) + Leader = who + to_say = "I follow..." + else // Not friendly enough + to_say = pick("No...", "I won't follow...") + else if (findtext(phrase, "stop")) + if (Victim) // We are asked to stop feeding + if (Friends[who] > 4) + Victim = null + Target = null + if (Friends[who] < 7) + --Friends[who] + to_say = "Grrr..." // I'm angry but I do it + else + to_say = "Fine..." + else if (Target) // We are asked to stop chasing + if (Friends[who] > 3) + Target = null + if (Friends[who] < 6) + --Friends[who] + to_say = "Grrr..." // I'm angry but I do it + else + to_say = "Fine..." + else if (Leader) // We are asked to stop following + if (Leader == who) + to_say = "Yes... I'll stay..." + Leader = null + else + if (Friends[who] > Friends[Leader]) + Leader = null + to_say = "Yes... I'll stop..." + else + to_say = "No... I'll keep following..." + else if (findtext(phrase, "stay")) + if (Leader) + if (Leader == who) + holding_still = Friends[who] * 10 + to_say = "Yes... Staying..." + else if (Friends[who] > Friends[Leader]) + holding_still = (Friends[who] - Friends[Leader]) * 10 + to_say = "Yes... Staying..." + else + to_say = "No... I'll keep following..." + else + if (Friends[who] > 2) + holding_still = Friends[who] * 10 + to_say = "Yes... Staying..." + else + to_say = "No... I won't stay..." + speech_buffer = list() + + //Speech starts here + if (to_say) + say (to_say) + else if(prob(1)) + emote(pick("bounce","sway","light","vibrate","jiggle")) + else + var/t = 10 + var/slimes_near = -1 // Don't count myself + var/dead_slimes = 0 + var/friends_near = list() + for (var/mob/living/carbon/M in view(7,src)) + if (isslime(M)) + ++slimes_near + if (M.stat == DEAD) + ++dead_slimes + if (M in Friends) + t += 20 + friends_near += M + if (nutrition < get_hunger_nutrition()) t += 10 + if (nutrition < get_starve_nutrition()) t += 10 + if (prob(2) && prob(t)) + var/phrases = list() + if (Target) phrases += "[Target]... looks tasty..." + if (nutrition < get_starve_nutrition()) + phrases += "So... hungry..." + phrases += "Very... hungry..." + phrases += "Need... food..." + phrases += "Must... eat..." + else if (nutrition < get_hunger_nutrition()) + phrases += "Hungry..." + phrases += "Where is the food?" + phrases += "I want to eat..." + phrases += "Rawr..." + phrases += "Blop..." + phrases += "Blorble..." + if (rabid || attacked) + phrases += "Hrr..." + phrases += "Nhuu..." + phrases += "Unn..." + if (mood == ":3") + phrases += "Purr..." + if (attacked) + phrases += "Grrr..." + if (getToxLoss() > 30) + phrases += "Cold..." + if (getToxLoss() > 60) + phrases += "So... cold..." + phrases += "Very... cold..." + if (getToxLoss() > 90) + phrases += "..." + phrases += "C... c..." + if (Victim) + phrases += "Nom..." + phrases += "Tasty..." + if (powerlevel > 3) phrases += "Bzzz..." + if (powerlevel > 5) phrases += "Zap..." + if (powerlevel > 8) phrases += "Zap... Bzz..." + if (mood == "sad") phrases += "Bored..." + if (slimes_near) phrases += "Brother..." + if (slimes_near > 1) phrases += "Brothers..." + if (dead_slimes) phrases += "What happened?" + if (!slimes_near) + phrases += "Lonely..." + for (var/M in friends_near) + phrases += "[M]... friend..." + if (nutrition < get_hunger_nutrition()) + phrases += "[M]... feed me..." + say (pick(phrases)) + +/mob/living/carbon/slime/proc/will_hunt(var/hunger) // Check for being stopped from feeding and chasing + if (hunger == 2 || rabid || attacked) return 1 + if (Leader) return 0 + if (holding_still) return 0 + if (hunger == 1 || prob(25)) + return 1 + return 0 diff --git a/code/modules/mob/living/carbon/xenobiological/subtypes.dm b/code/modules/mob/living/carbon/xenobiological/subtypes.dm new file mode 100644 index 00000000..30b2be25 --- /dev/null +++ b/code/modules/mob/living/carbon/xenobiological/subtypes.dm @@ -0,0 +1,84 @@ +/mob/living/carbon/slime/proc/GetMutations() + switch(src.colour) + if("grey") + return list("orange", "metal", "blue", "purple") + if("purple") + return list("dark purple", "dark blue", "green", "green") + if("metal") + return list("silver", "yellow", "gold", "gold") + if("orange") + return list("dark purple", "yellow", "red", "red") + if("blue") + return list("dark blue", "silver", "pink", "pink") + //Tier 3 + if("dark blue") + return list("purple", "cerulean", "blue", "blue") + if("dark purple") + return list("purple", "sepia", "orange", "orange") + if("yellow") + return list("bluespace", "metal", "orange", "orange") + if("silver") + return list("metal", "pyrite", "blue", "blue") + //Tier 4 + if("pink") + return list("pink", "pink", "light pink", "light pink") + if("red") + return list("red", "red", "oil", "oil") + if("gold") + return list("gold", "gold", "adamantine", "adamantine") + if("green") + return list("green", "green", "black", "black") + // Tier 5 + else + return list() + +/mob/living/carbon/slime/proc/GetCoreType() + switch(src.colour) + // Tier 1 + if("grey") + return /obj/item/slime_extract/grey + // Tier 2 + if("purple") + return /obj/item/slime_extract/purple + if("metal") + return /obj/item/slime_extract/metal + if("orange") + return /obj/item/slime_extract/orange + if("blue") + return /obj/item/slime_extract/blue + // Tier 3 + if("dark blue") + return /obj/item/slime_extract/darkblue + if("dark purple") + return /obj/item/slime_extract/darkpurple + if("yellow") + return /obj/item/slime_extract/yellow + if("silver") + return /obj/item/slime_extract/silver + // Tier 4 + if("pink") + return /obj/item/slime_extract/pink + if("red") + return /obj/item/slime_extract/red + if("gold") + return /obj/item/slime_extract/gold + if("green") + return /obj/item/slime_extract/green + if("sepia") + return /obj/item/slime_extract/sepia + if("bluespace") + return /obj/item/slime_extract/bluespace + if("cerulean") + return /obj/item/slime_extract/cerulean + if("pyrite") + return /obj/item/slime_extract/pyrite + //Tier 5 + if("light pink") + return /obj/item/slime_extract/lightpink + if("oil") + return /obj/item/slime_extract/oil + if("adamantine") + return /obj/item/slime_extract/adamantine + if("black") + return /obj/item/slime_extract/black + return /obj/item/slime_extract/grey diff --git a/code/modules/mob/living/carbon/xenobiological/update_icons.dm b/code/modules/mob/living/carbon/xenobiological/update_icons.dm new file mode 100644 index 00000000..658c7a52 --- /dev/null +++ b/code/modules/mob/living/carbon/xenobiological/update_icons.dm @@ -0,0 +1,9 @@ +/mob/living/carbon/slime/regenerate_icons() + if (stat == DEAD) + icon_state = "[colour] baby slime dead" + else + icon_state = "[colour] [is_adult ? "adult" : "baby"] slime[Victim ? "" : " eat"]" + overlays.len = 0 + if (mood) + overlays += image('icons/mob/slimes.dmi', icon_state = "aslime-[mood]") + ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/xenobiological/xenobiological.dm b/code/modules/mob/living/carbon/xenobiological/xenobiological.dm new file mode 100644 index 00000000..19f7eb47 --- /dev/null +++ b/code/modules/mob/living/carbon/xenobiological/xenobiological.dm @@ -0,0 +1,314 @@ +/mob/living/carbon/slime + name = "baby slime" + icon = 'icons/mob/slimes.dmi' + icon_state = "grey baby slime" + pass_flags = PASS_FLAG_TABLE + speak_emote = list("chirps") + + maxHealth = 150 + health = 150 + gender = NEUTER + + update_icon = 0 + nutrition = 800 + + see_in_dark = 8 + update_slimes = 0 + + // canstun and canweaken don't affect slimes because they ignore stun and weakened variables + // for the sake of cleanliness, though, here they are. + status_flags = CANPARALYSE|CANPUSH + + var/toxloss = 0 + var/is_adult = 0 + var/number = 0 // Used to understand when someone is talking to it + var/cores = 1 // the number of /obj/item/slime_extract's the slime has left inside + var/mutation_chance = 30 // Chance of mutating, should be between 25 and 35 + + var/powerlevel = 0 // 0-10 controls how much electricity they are generating + var/amount_grown = 0 // controls how long the slime has been overfed, if 10, grows or reproduces + + var/mob/living/Victim = null // the person the slime is currently feeding on + var/mob/living/Target = null // AI variable - tells the slime to hunt this down + var/mob/living/Leader = null // AI variable - tells the slime to follow this person + + var/attacked = 0 // Determines if it's been attacked recently. Can be any number, is a cooloff-ish variable + var/rabid = 0 // If set to 1, the slime will attack and eat anything it comes in contact with + var/holding_still = 0 // AI variable, cooloff-ish for how long it's going to stay in one place + var/target_patience = 0 // AI variable, cooloff-ish for how long it's going to follow its target + + var/list/Friends = list() // A list of friends; they are not considered targets for feeding; passed down after splitting + + var/list/speech_buffer = list() // Last phrase said near it and person who said it + + var/mood = "" // To show its face + + var/AIproc = 0 // If it's 0, we need to launch an AI proc + + var/hurt_temperature = T0C-50 // slime keeps taking damage when its bodytemperature is below this + var/die_temperature = 50 // slime dies instantly when its bodytemperature is below this + + var/colour = "grey" + + var/core_removal_stage = 0 //For removing cores. + + +/mob/living/carbon/slime/getToxLoss() + return toxloss + +/mob/living/carbon/slime/adjustToxLoss(var/amount) + toxloss = Clamp(toxloss + amount, 0, maxHealth) + +/mob/living/carbon/slime/setToxLoss(var/amount) + adjustToxLoss(amount-getToxLoss()) + +/mob/living/carbon/slime/New(var/location, var/colour="grey") + + verbs += /mob/living/proc/ventcrawl + + src.colour = colour + number = random_id(/mob/living/carbon/slime, 1, 1000) + name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])" + real_name = name + mutation_chance = rand(25, 35) + regenerate_icons() + ..(location) + +/mob/living/carbon/slime/movement_delay() + if (bodytemperature >= 330.23) // 135 F + return -1 // slimes become supercharged at high temperatures + + var/tally = ..() + + var/health_deficiency = (maxHealth - health) + if(health_deficiency >= 30) tally += (health_deficiency / 25) + + if (bodytemperature < 183.222) + tally += (283.222 - bodytemperature) / 10 * 1.75 + + if(reagents) + if(reagents.has_reagent(/datum/reagent/hyperzine)) // Hyperzine slows slimes down + tally *= 2 + + if(reagents.has_reagent(/datum/reagent/frostoil)) // Frostoil also makes them move VEEERRYYYYY slow + tally *= 5 + + if(health <= 0) // if damaged, the slime moves twice as slow + tally *= 2 + + return tally + config.slime_delay + +/mob/living/carbon/slime/Bump(atom/movable/AM as mob|obj, yes) + if ((!(yes) || now_pushing)) + return + now_pushing = 1 + + if(isobj(AM) && !client && powerlevel > 0) + var/probab = 10 + switch(powerlevel) + if(1 to 2) probab = 20 + if(3 to 4) probab = 30 + if(5 to 6) probab = 40 + if(7 to 8) probab = 60 + if(9) probab = 70 + if(10) probab = 95 + if(prob(probab)) + if(istype(AM, /obj/structure/window) || istype(AM, /obj/structure/grille)) + if(nutrition <= get_hunger_nutrition()) + if (is_adult || prob(5)) + UnarmedAttack(AM) + + if(ismob(AM)) + var/mob/tmob = AM + + if(is_adult) + if(istype(tmob, /mob/living/carbon/human)) + if(prob(90)) + now_pushing = 0 + return + else + if(istype(tmob, /mob/living/carbon/human)) + now_pushing = 0 + return + + now_pushing = 0 + + ..() + +/mob/living/carbon/slime/Allow_Spacemove() + return 1 + +/mob/living/carbon/slime/Stat() + . = ..() + + statpanel("Status") + stat(null, "Health: [round((health / maxHealth) * 100)]%") + stat(null, "Intent: [a_intent]") + + if (client.statpanel == "Status") + stat(null, "Nutrition: [nutrition]/[get_max_nutrition()]") + if(amount_grown >= 10) + if(is_adult) + stat(null, "You can reproduce!") + else + stat(null, "You can evolve!") + + stat(null,"Power Level: [powerlevel]") + +/mob/living/carbon/slime/adjustFireLoss(amount) + ..(-abs(amount)) // Heals them + return + +/mob/living/carbon/slime/bullet_act(var/obj/item/projectile/Proj) + attacked += 10 + ..(Proj) + return 0 + +/mob/living/carbon/slime/emp_act(severity) + powerlevel = 0 // oh no, the power! + ..() + +/mob/living/carbon/slime/ex_act(severity) + ..() + + var/b_loss = null + var/f_loss = null + switch (severity) + if (1.0) + qdel(src) + return + + if (2.0) + + b_loss += 60 + f_loss += 60 + + + if(3.0) + b_loss += 30 + + adjustBruteLoss(b_loss) + adjustFireLoss(f_loss) + + updatehealth() + + +/mob/living/carbon/slime/u_equip(obj/item/W as obj) + return + +/mob/living/carbon/slime/attack_ui(slot) + return + +/mob/living/carbon/slime/attack_hand(mob/living/carbon/human/M as mob) + + ..() + + if(Victim) + if(Victim == M) + if(prob(60)) + visible_message("\The [M] attempts to wrestle \the [src] off!") + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + + else + visible_message("\The [M] manages to wrestle \the [src] off!") + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + + confused = max(confused, 2) + Feedstop() + UpdateFace() + step_away(src, M) + return + + else + if(prob(30)) + visible_message("\The [M] attempts to wrestle \the [src] off \the [Victim]!") + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + + else + visible_message("\The [M] manages to wrestle \the [src] off \the [Victim]!") + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + + confused = max(confused, 2) + Feedstop() + UpdateFace() + step_away(src, M) + return + + switch(M.a_intent) + + if (I_HELP) + help_shake_act(M) + + if (I_DISARM) + var/success = prob(40) + visible_message("\The [M] pushes \the [src]![success ? " \The [src] looks momentarily disoriented!" : ""]") + if(success) + confused = max(confused, 2) + UpdateFace() + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + else + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + + else + + var/damage = rand(1, 9) + + attacked += 10 + if (prob(90)) + if (HULK in M.mutations) + damage += 5 + if(Victim || Target) + Feedstop() + Target = null + spawn(0) + step_away(src,M,15) + sleep(3) + step_away(src,M,15) + + playsound(loc, "punch", 25, 1, -1) + visible_message("[M] has punched [src]!", \ + "[M] has punched [src]!") + + adjustBruteLoss(damage) + updatehealth() + else + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + visible_message("[M] has attempted to punch [src]!") + return + +/mob/living/carbon/slime/attackby(var/obj/item/W, var/mob/user) + if(W.force > 0) + attacked += 10 + if(!(stat) && prob(25)) //Only run this check if we're alive or otherwise motile, otherwise surgery will be agonizing for xenobiologists. + to_chat(user, "\The [W] passes right through \the [src]!") + return + + . = ..() + + if(Victim && prob(W.force * 5)) + Feedstop() + step_away(src, user) + +/mob/living/carbon/slime/restrained() + return 0 + +/mob/living/carbon/slime/var/co2overloadtime = null +/mob/living/carbon/slime/var/temperature_resistance = T0C+75 + +/mob/living/carbon/slime/toggle_throw_mode() + return + +/mob/living/carbon/slime/has_eyes() + return 0 + +/mob/living/carbon/slime/check_has_mouth() + return 0 + +/mob/living/carbon/slime/proc/gain_nutrition(var/amount) + nutrition += amount + if(prob(amount * 2)) // Gain around one level per 50 nutrition + powerlevel++ + if(powerlevel > 10) + powerlevel = 10 + adjustToxLoss(-10) + nutrition = min(nutrition, get_max_nutrition()) diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm new file mode 100644 index 00000000..2e60b873 --- /dev/null +++ b/code/modules/mob/living/damage_procs.dm @@ -0,0 +1,80 @@ + +/* + apply_damage() args + damage - How much damage to take + damage_type - What type of damage to take, brute, burn + def_zone - Where to take the damage if its brute or burn + + Returns + standard 0 if fail +*/ +/mob/living/proc/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/damage_flags = 0, var/used_weapon = null) + if(!damage || (blocked >= 100)) return 0 + switch(damagetype) + if(BRUTE) + adjustBruteLoss(damage * blocked_mult(blocked)) + if(BURN) + if(COLD_RESISTANCE in mutations) damage = 0 + adjustFireLoss(damage * blocked_mult(blocked)) + if(TOX) + adjustToxLoss(damage * blocked_mult(blocked)) + if(OXY) + adjustOxyLoss(damage * blocked_mult(blocked)) + if(CLONE) + adjustCloneLoss(damage * blocked_mult(blocked)) + if(PAIN) + adjustHalLoss(damage * blocked_mult(blocked)) + if(ELECTROCUTE) + electrocute_act(damage, used_weapon, 1.0, def_zone) + + updatehealth() + return 1 + + +/mob/living/proc/apply_damages(var/brute = 0, var/burn = 0, var/tox = 0, var/oxy = 0, var/clone = 0, var/halloss = 0, var/def_zone = null, var/blocked = 0, var/damage_flags = 0) + if(blocked >= 100) return 0 + if(brute) apply_damage(brute, BRUTE, def_zone, blocked) + if(burn) apply_damage(burn, BURN, def_zone, blocked) + if(tox) apply_damage(tox, TOX, def_zone, blocked) + if(oxy) apply_damage(oxy, OXY, def_zone, blocked) + if(clone) apply_damage(clone, CLONE, def_zone, blocked) + if(halloss) apply_damage(halloss, PAIN, def_zone, blocked) + return 1 + + +/mob/living/proc/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0) + if(!effect || (blocked >= 100)) return 0 + + switch(effecttype) + if(STUN) + Stun(effect * blocked_mult(blocked)) + if(WEAKEN) + Weaken(effect * blocked_mult(blocked)) + if(PARALYZE) + Paralyse(effect * blocked_mult(blocked)) + if(PAIN) + adjustHalLoss(effect * blocked_mult(blocked)) + if(IRRADIATE) + radiation += effect * blocked_mult(blocked) + if(STUTTER) + if(status_flags & CANSTUN) // stun is usually associated with stutter - TODO CANSTUTTER flag? + stuttering = max(stuttering, effect * blocked_mult(blocked)) + if(EYE_BLUR) + eye_blurry = max(eye_blurry, effect * blocked_mult(blocked)) + if(DROWSY) + drowsyness = max(drowsyness, effect * blocked_mult(blocked)) + updatehealth() + return 1 + + +/mob/living/proc/apply_effects(var/stun = 0, var/weaken = 0, var/paralyze = 0, var/irradiate = 0, var/stutter = 0, var/eyeblur = 0, var/drowsy = 0, var/agony = 0, var/blocked = 0) + if(blocked >= 2) return 0 + if(stun) apply_effect(stun, STUN, blocked) + if(weaken) apply_effect(weaken, WEAKEN, blocked) + if(paralyze) apply_effect(paralyze, PARALYZE, blocked) + if(irradiate) apply_effect(irradiate, IRRADIATE, blocked) + if(stutter) apply_effect(stutter, STUTTER, blocked) + if(eyeblur) apply_effect(eyeblur, EYE_BLUR, blocked) + if(drowsy) apply_effect(drowsy, DROWSY, blocked) + if(agony) apply_effect(agony, PAIN, blocked) + return 1 diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm new file mode 100644 index 00000000..b040c886 --- /dev/null +++ b/code/modules/mob/living/death.dm @@ -0,0 +1,4 @@ +/mob/living/death() + if(hiding) + hiding = FALSE + . = ..() \ No newline at end of file diff --git a/code/modules/mob/living/default_language.dm b/code/modules/mob/living/default_language.dm new file mode 100644 index 00000000..06e18594 --- /dev/null +++ b/code/modules/mob/living/default_language.dm @@ -0,0 +1,38 @@ +/mob/living + var/datum/language/default_language + +/mob/living/verb/set_default_language(language as null|anything in languages) + set name = "Set Default Language" + set category = "IC" + + if (only_species_language && language != all_languages[src.species_language]) + to_chat(src, "You can only speak your species language, [src.species_language].") + return 0 + + if(language == all_languages[src.species_language]) + to_chat(src, "You will now speak your standard default language, [language], if you do not specify a language when speaking.") + else if (language) + + if(language && !can_speak(language)) + to_chat(src, "You are unable to speak that language.") + return + + to_chat(src, "You will now speak [language] if you do not specify a language when speaking.") + else + + to_chat(src, "You will now speak whatever your standard default language is if you do not specify one when speaking.") + + default_language = language + +// Silicons can't neccessarily speak everything in their languages list +/mob/living/silicon/set_default_language(language as null|anything in speech_synthesizer_langs) + ..() + +/mob/living/verb/check_default_language() + set name = "Check Default Language" + set category = "IC" + + if(default_language) + to_chat(src, "You are currently speaking [default_language] by default.") + else + to_chat(src, "Your current default language is your species or mob type default.") diff --git a/code/modules/mob/living/floating_say.dm b/code/modules/mob/living/floating_say.dm new file mode 100644 index 00000000..81a9e61f --- /dev/null +++ b/code/modules/mob/living/floating_say.dm @@ -0,0 +1,67 @@ +// Code by Chinsky. I've just changed some stuff around to fix some runtimes. +var/list/floating_chat_colors = list() + +/atom/movable + var/list/stored_chat_text + +/atom/movable/proc/animate_chat(message, datum/language/language, small, list/show_to, duration) + set waitfor = FALSE + + var/style //additional style params for the message + var/fontsize = 6 + if(small) + fontsize = 5 + var/limit = 50 + if(copytext(message, length(message) - 1) == "!!") + fontsize = 8 + limit = 30 + style += "font-weight: bold;" + + if(length(message) > limit) + message = "[copytext(message, 1, limit)]..." + + if(!floating_chat_colors[name]) + floating_chat_colors[name] = get_random_colour(0,160,230) + style += "color: [floating_chat_colors[name]];" + // create 2 messages, one that appears if you know the language, and one that appears when you don't know the language + var/image/understood = generate_floating_text(src, capitalize(message), style, fontsize, duration, show_to) + var/image/gibberish = language ? generate_floating_text(src, language.scramble(message), style, fontsize, duration, show_to) : understood + + for(var/client/C in show_to) + if(!C.mob.is_deaf() && C.get_preference_value(/datum/client_preference/floating_messages) == GLOB.PREF_SHOW) + if(C.mob.say_understands(null, language)) + C.images += understood + else + C.images += gibberish + +/proc/generate_floating_text(atom/movable/holder, message, style, size, duration, show_to) + var/image/I = image(null, holder) + I.plane = HUD_PLANE//Want to show this above the vision cone. + I.layer = 10 + I.alpha = 0 + I.maptext_width = 80 + I.maptext_height = 64 + I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA + I.pixel_x = -round(I.maptext_width/2) + 16 + + style = "font-family: 'Small Fonts'; -dm-text-outline: 1 black; font-size: [size]px; [style]" + I.maptext = "
            [message]
            " + animate(I, 1, alpha = 255, pixel_y = 16) + + for(var/image/old in holder.stored_chat_text) + animate(old, 2, pixel_y = old.pixel_y + 8) + LAZYADD(holder.stored_chat_text, I) + + addtimer(CALLBACK(GLOBAL_PROC, .proc/remove_floating_text, holder, I), duration) + addtimer(CALLBACK(GLOBAL_PROC, .proc/remove_images_from_clients, I, show_to), duration + 2) + + return I + +/proc/remove_floating_text(atom/movable/holder, image/I) + animate(I, 2, pixel_y = I.pixel_y + 10, alpha = 0) + LAZYREMOVE(holder.stored_chat_text, I) + +/proc/remove_images_from_clients(image/I, list/show_to) + for(var/client/C in show_to) + C.images -= I + qdel(I) \ No newline at end of file diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm new file mode 100644 index 00000000..b21b9e75 --- /dev/null +++ b/code/modules/mob/living/life.dm @@ -0,0 +1,261 @@ +/mob/living/Life() + set invisibility = 0 + set background = BACKGROUND_ENABLED + + ..() + + if (transforming) + return + if(!loc) + return + + if(machine && !CanMouseDrop(machine, src)) + machine = null + + //Handle temperature/pressure differences between body and environment + var/datum/gas_mixture/environment = loc.return_air() + if(environment) + handle_environment(environment) + + blinded = 0 // Placing this here just show how out of place it is. + // human/handle_regular_status_updates() needs a cleanup, as blindness should be handled in handle_disabilities() + handle_regular_status_updates() // Status & health update, are we dead or alive etc. + + if(stat != DEAD) + aura_check(AURA_TYPE_LIFE) + + //Check if we're on fire + handle_fire() + + update_pulling() + + for(var/obj/item/grab/G in src) + G.Process() + + handle_actions() + + update_canmove() + + if(client) + handle_ambience() + + handle_regular_hud_updates() + + return 1 + +/mob/living/proc/handle_breathing() + return + +/mob/living/proc/handle_mutations_and_radiation() + return + +/mob/living/proc/handle_chemicals_in_body() + return + +/mob/living/proc/handle_random_events() + return + +/mob/living/proc/handle_environment(var/datum/gas_mixture/environment) + return + +/mob/living/proc/handle_stomach() + return + +/mob/living/proc/update_pulling() + if(pulling) + if(incapacitated()) + stop_pulling() + +//This updates the health and status of the mob (conscious, unconscious, dead) +/mob/living/proc/handle_regular_status_updates() + updatehealth() + if(stat != DEAD) + if(paralysis) + set_stat(UNCONSCIOUS) + else if (status_flags & FAKEDEATH) + set_stat(UNCONSCIOUS) + else + set_stat(CONSCIOUS) + return 1 + +/mob/living/proc/handle_statuses() + handle_stunned() + handle_weakened() + handle_paralysed() + handle_stuttering() + handle_silent() + handle_drugged() + handle_slurring() + handle_lisp() + +/mob/living/proc/handle_stunned() + if(stunned) + AdjustStunned(-1) + if(!stunned) + update_icons() + return stunned + +/mob/living/proc/handle_weakened() + if(weakened) + weakened = max(weakened-1,0) + if(!weakened) + update_icons() + return weakened + +/mob/living/proc/handle_stuttering() + if(stuttering) + stuttering = max(stuttering-1, 0) + return stuttering + +/mob/living/proc/handle_silent() + if(silent) + silent = max(silent-1, 0) + return silent + +/mob/living/proc/handle_drugged() + if(druggy) + druggy = max(druggy-1, 0) + return druggy + +/mob/living/proc/handle_slurring() + if(slurring) + slurring = max(slurring-1, 0) + return slurring + +/mob/living/proc/handle_paralysed() + if(paralysis) + AdjustParalysis(-1) + if(!paralysis) + update_icons() + return paralysis + +/mob/living/proc/handle_ambience() + if(deaf_loop) + sound_to(src, sound(null, repeat = 1, volume = 50, wait = 0, channel = 1)) + ambience_is_playing = FALSE + else if(!deaf_loop && !ambience_is_playing) + ambience_is_playing = TRUE + sound_to(src, sound(current_ambience, repeat = 1, volume = 50, wait = 0, channel = 1)) + + +/mob/living/proc/change_current_ambience(var/ambience) + current_ambience = ambience + ambience_is_playing = 0 + +/mob/living/proc/change_current_ambience_with_override(var/ambience) + current_ambience = ambience + ambience_override = 1 + ambience_is_playing = 0 + +/mob/living/proc/handle_disabilities() + handle_impaired_vision() + handle_impaired_hearing() + +/mob/living/proc/handle_impaired_vision() + //Eyes + if(sdisabilities & BLIND || stat) //blindness from disability or unconsciousness doesn't get better on its own + eye_blind = max(eye_blind, 1) + else if(eye_blind) //blindness, heals slowly over time + eye_blind = max(eye_blind-1,0) + else if(eye_blurry) //blurry eyes heal slowly + eye_blurry = max(eye_blurry-1, 0) + +/mob/living/proc/handle_impaired_hearing() + //Ears + if(sdisabilities & DEAF) //disabled-deaf, doesn't get better on its own + setEarDamage(null, max(ear_deaf, 1)) + else if(ear_damage < 25) + adjustEarDamage(-0.05, -1) // having ear damage impairs the recovery of ear_deaf + else if(ear_damage < 100) + adjustEarDamage(-0.05, 0) // deafness recovers slowly over time, unless ear_damage is over 100. TODO meds that heal ear_damage + + +//this handles hud updates. Calls update_vision() and handle_hud_icons() +/mob/living/proc/handle_regular_hud_updates() + if(!client) return 0 + + handle_hud_icons() + handle_vision() + + return 1 + +//I hate this with a burning passion. +/mob/living/proc/set_all_blur() + if(!client) + return + client.screen += HB + client.screen += TB + client.screen += WB + client.screen += OB + client.screen += LB + client.screen += MB + client.screen += AB + client.screen += EB + client.screen += plating_blur + client.screen += AT + client.screen += AOB + +/mob/living/proc/remove_all_blur() + if(!client) + return + client.screen -= HB + client.screen -= TB + client.screen -= WB + client.screen -= OB + client.screen -= LB + client.screen -= MB + client.screen -= AB + client.screen -= EB + client.screen -= plating_blur + client.screen -= AT + client.screen -= AOB + +/mob/living/proc/handle_vision() + update_sight() + + if(stat == DEAD) + return + if(eye_blind) + overlay_fullscreen("blind", /obj/screen/fullscreen/blind) + else + clear_fullscreen("blind") + set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1) + set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry) + set_fullscreen(druggy, "high", /obj/screen/fullscreen/high) + + set_fullscreen(stat == UNCONSCIOUS, "blackout", /obj/screen/fullscreen/blackout) + + if(machine) + var/viewflags = machine.check_eye(src) + if(viewflags < 0) + reset_view(null, 0) + else if(viewflags) + set_sight(viewflags) + else if(eyeobj) + if(eyeobj.owner != src) + reset_view(null) + else if(!client.adminobs) + reset_view(null) + +/mob/living/proc/update_sight() + if(stat == DEAD || eyeobj) + update_dead_sight() + else + update_living_sight() + +/mob/living/proc/update_living_sight() + set_sight(sight&(~(SEE_TURFS|SEE_MOBS|SEE_OBJS))) + set_see_in_dark(initial(see_in_dark)) + set_see_invisible(initial(see_invisible)) + +/mob/living/proc/update_dead_sight() + set_sight(sight|SEE_TURFS|SEE_MOBS|SEE_OBJS) + set_see_in_dark(8) + set_see_invisible(SEE_INVISIBLE_LEVEL_TWO) + +/mob/living/proc/handle_hud_icons() + handle_hud_icons_health() + handle_hud_glasses() + +/mob/living/proc/handle_hud_icons_health() + return diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm new file mode 100644 index 00000000..19e239f3 --- /dev/null +++ b/code/modules/mob/living/living.dm @@ -0,0 +1,959 @@ +/mob/living + var/current_ambience = null + var/ambience_is_playing = 0 + var/ambience_override = 0 + +/mob/living/New() + ..() + if(stat == DEAD) + add_to_dead_mob_list() + else + add_to_living_mob_list() + +//mob verbs are faster than object verbs. See mob/verb/examine. +/mob/living/proc/pulled(atom/movable/AM as mob|obj in oview(1)) + set name = "Pull" + set category = "Object" + + if(AM.Adjacent(src)) + src.start_pulling(AM) + + return + +//mob verbs are faster than object verbs. See above. +/mob/living/pointed(atom/A as mob|obj|turf in view()) + if(src.stat || src.restrained()) //!src.canmove + return 0 + if(src.status_flags & FAKEDEATH) + return 0 + if(!..()) + return 0 + + if(!isturf(A)) + var/point_color = "#F00" + if(ishuman(A)) + var/mob/living/carbon/human/H = A + if(H.warfare_faction == RED_TEAM) + point_color = "#b27676" + else + point_color = "#76abb2" + var/pointglow = filter(type = "drop_shadow", x = 0, y = -1, offset = 2, size = 1, color = point_color) + remove_filter(A, pointglow) + LAZYADD(A.filters, pointglow) + addtimer(CALLBACK(src, .proc/remove_filter, A, pointglow), 20) + + usr.visible_message("[src] points to [A]") + return 1 + +/mob/proc/remove_filter(var/atom/A, var/filter_to_remove) + LAZYREMOVE(A.filters, filter_to_remove) + +/*one proc, four uses +swapping: if it's 1, the mobs are trying to switch, if 0, non-passive is pushing passive +default behaviour is: + - non-passive mob passes the passive version + - passive mob checks to see if its mob_bump_flag is in the non-passive's mob_bump_flags + - if si, the proc returns +*/ +/mob/living/proc/can_move_mob(var/mob/living/swapped, swapping = 0, passive = 0) + if(!swapped) + return 1 + if(!passive) + return swapped.can_move_mob(src, swapping, 1) + else + var/context_flags = 0 + if(swapping) + context_flags = swapped.mob_swap_flags + else + context_flags = swapped.mob_push_flags + if(!mob_bump_flag) //nothing defined, go wild + return 1 + if(mob_bump_flag & context_flags) + return 1 + else + return ((a_intent == I_HELP && swapped.a_intent == I_HELP) && swapped.can_move_mob(src, swapping, 1)) + +/mob/living/canface() + if(stat) + return 0 + return ..() + +/mob/living/Bump(atom/movable/AM, yes) + spawn(0) + if ((!( yes ) || now_pushing) || !loc) + return + now_pushing = 1 + if (istype(AM, /mob/living)) + var/mob/living/tmob = AM + + for(var/mob/living/M in range(tmob, 1)) + if(tmob.pinned.len || ((M.pulling == tmob && ( tmob.restrained() && !( M.restrained() ) && M.stat == 0)) || locate(/obj/item/grab, tmob.grabbed_by.len)) ) + if ( !(world.time % 5) ) + to_chat(src, "[tmob] is restrained, you cannot push past") + now_pushing = 0 + return + if( tmob.pulling == M && ( M.restrained() && !( tmob.restrained() ) && tmob.stat == 0) ) + if ( !(world.time % 5) ) + to_chat(src, "[tmob] is restraining [M], you cannot push past") + now_pushing = 0 + return + + //Leaping mobs just land on the tile, no pushing, no anything. + if(status_flags & LEAPING) + loc = tmob.loc + status_flags &= ~LEAPING + now_pushing = 0 + return + + if(can_swap_with(tmob)) // mutual brohugs all around! + var/turf/oldloc = loc + forceMove(tmob.loc) + tmob.forceMove(oldloc) + now_pushing = 0 + for(var/mob/living/carbon/slime/slime in view(1,tmob)) + if(slime.Victim == tmob) + slime.UpdateFeed() + return + + if(!can_move_mob(tmob, 0, 0)) + now_pushing = 0 + return + if(src.restrained()) + now_pushing = 0 + return + if(tmob.a_intent != I_HELP) + if(ishuman(tmob) && ishuman(src)) + var/mob/living/carbon/human/pusher = src + var/mob/living/carbon/human/pushee = tmob + if((pusher.STAT_LEVEL(str) < pushee.STAT_LEVEL(str)) && prob(95)) + src.visible_message("[pusher] fails to push past [pushee].") + now_pushing = 0 + return + //if(prob(40) && !(FAT in src.mutations)) + // to_chat(src, "You fail to push [tmob]'s fat ass out of the way.") + // now_pushing = 0 + // return + if(tmob.r_hand && istype(tmob.r_hand, /obj/item/weapon/shield/riot)) + if(prob(99)) + now_pushing = 0 + return + if(tmob.l_hand && istype(tmob.l_hand, /obj/item/weapon/shield/riot)) + if(prob(99)) + now_pushing = 0 + return + if(!(tmob.status_flags & CANPUSH)) + now_pushing = 0 + return + tmob.LAssailant = src + if(isobj(AM) && !AM.anchored) + var/obj/I = AM + if(!can_pull_size || can_pull_size < I.w_class) + to_chat(src, "It won't budge!") + now_pushing = 0 + return + + now_pushing = 0 + spawn(0) + ..() + var/saved_dir = AM.dir + if (!istype(AM, /atom/movable) || AM.anchored) + if(confused && prob(50) && m_intent=="run") + Weaken(2) + playsound(loc, "punch", 40, 1, -1) + visible_message("[src] [pick("ran", "slammed")] into \the [AM]!") + src.apply_damage(5, BRUTE) + return + if (!now_pushing) + now_pushing = 1 + + var/t = get_dir(src, AM) + if (istype(AM, /obj/structure/window)) + for(var/obj/structure/window/win in get_step(AM,t)) + now_pushing = 0 + return + step(AM, t) + if (istype(AM, /mob/living)) + var/mob/living/tmob = AM + if(istype(tmob.buckled, /obj/structure/bed)) + if(!tmob.buckled.anchored) + step(tmob.buckled, t) + if(ishuman(AM) && AM:grabbed_by) + for(var/obj/item/grab/G in AM:grabbed_by) + step(G:assailant, get_dir(G:assailant, AM)) + G.adjust_position() + if(saved_dir) + AM.set_dir(saved_dir) + now_pushing = 0 + return + return + +/proc/swap_density_check(var/mob/swapper, var/mob/swapee) + var/turf/T = get_turf(swapper) + if(T.density) + return 1 + for(var/atom/movable/A in T) + if(A == swapper) + continue + if(!A.CanPass(swapee, T, 1)) + return 1 + +/mob/living/proc/can_swap_with(var/mob/living/tmob) + if(tmob.buckled || buckled) + return 0 + //BubbleWrap: people in handcuffs are always switched around as if they were on 'help' intent to prevent a person being pulled from being seperated from their puller + if(!(tmob.mob_always_swap || (tmob.a_intent == I_HELP || tmob.restrained()) && (a_intent == I_HELP || src.restrained()))) + return 0 + if(!tmob.canmove || !canmove) + return 0 + + if(swap_density_check(src, tmob)) + return 0 + + if(swap_density_check(tmob, src)) + return 0 + + return can_move_mob(tmob, 1, 0) + +/mob/living/verb/succumb() + set name = "Succumb" + set category = "IC" + if(stat == DEAD) + return + if ((src.health < src.maxHealth/2) || is_asystole()) // Health below half of maxhealth, or asystole. + src.adjustBrainLoss(src.health + src.maxHealth * 2) // Deal 2x health in BrainLoss damage, as before but variable. + updatehealth() + to_chat(src, "You have given up life and succumbed to death.") + else + to_chat(src, "You are too alive to die.") + + +/mob/living/proc/updatehealth() + if(status_flags & GODMODE) + health = 100 + set_stat(CONSCIOUS) + else + health = maxHealth - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() - getCloneLoss() - getHalLoss() + + +//This proc is used for mobs which are affected by pressure to calculate the amount of pressure that actually +//affects them once clothing is factored in. ~Errorage +/mob/living/proc/calculate_affecting_pressure(var/pressure) + return + + +//sort of a legacy burn method for /electrocute, /shock, and the e_chair +/mob/living/proc/burn_skin(burn_amount) + take_overall_damage(0, burn_amount) + +/mob/living/proc/adjustBodyTemp(actual, desired, incrementboost) + var/temperature = actual + var/difference = abs(actual-desired) //get difference + var/increments = difference/10 //find how many increments apart they are + var/change = increments*incrementboost // Get the amount to change by (x per increment) + + // Too cold + if(actual < desired) + temperature += change + if(actual > desired) + temperature = desired + // Too hot + if(actual > desired) + temperature -= change + if(actual < desired) + temperature = desired +// if(istype(src, /mob/living/carbon/human)) +// log_debug("[src] ~ [src.bodytemperature] ~ [temperature]") + + return temperature + + +// ++++ROCKDTBEN++++ MOB PROCS -- Ask me before touching. +// Stop! ... Hammertime! ~Carn +// I touched them without asking... I'm soooo edgy ~Erro (added nodamage checks) + +/mob/living/proc/getBruteLoss() + return maxHealth - health + +/mob/living/proc/adjustBruteLoss(var/amount) + if(status_flags & GODMODE) return 0 //godmode + health = max(health-amount, 0) + +/mob/living/proc/getOxyLoss() + return 0 + +/mob/living/proc/adjustOxyLoss(var/amount) + return + +/mob/living/proc/setOxyLoss(var/amount) + return + +/mob/living/proc/getToxLoss() + return 0 + +/mob/living/proc/adjustToxLoss(var/amount) + adjustBruteLoss(amount * 0.5) + +/mob/living/proc/setToxLoss(var/amount) + adjustBruteLoss((amount * 0.5)-getBruteLoss()) + +/mob/living/proc/getFireLoss() + return + +/mob/living/proc/adjustFireLoss(var/amount) + adjustBruteLoss(amount * 0.5) + +/mob/living/proc/setFireLoss(var/amount) + adjustBruteLoss((amount * 0.5)-getBruteLoss()) + +/mob/living/proc/getHalLoss() + return 0 + +/mob/living/proc/adjustHalLoss(var/amount) + adjustBruteLoss(amount * 0.5) + +/mob/living/proc/setHalLoss(var/amount) + adjustBruteLoss((amount * 0.5)-getBruteLoss()) + +/mob/living/proc/getStaminaLoss()//Stamina shit. + return staminaloss + +/mob/living/proc/adjustStaminaLoss(var/amount) + if(status_flags & GODMODE) return 0 + staminaloss = min(max(staminaloss + amount, 0),(maxHealth*2)) + +/mob/living/proc/setStaminaLoss(var/amount) + if(status_flags & GODMODE) return 0 + staminaloss = amount + +/mob/living/proc/getBrainLoss() + return 0 + +/mob/living/proc/adjustBrainLoss(var/amount) + return + +/mob/living/proc/setBrainLoss(var/amount) + return + +/mob/living/proc/getCloneLoss() + return 0 + +/mob/living/proc/setCloneLoss(var/amount) + return + +/mob/living/proc/adjustCloneLoss(var/amount) + return + +/mob/living/proc/getMaxHealth() + return maxHealth + +/mob/living/proc/setMaxHealth(var/newMaxHealth) + maxHealth = newMaxHealth + +// ++++ROCKDTBEN++++ MOB PROCS //END + +/mob/proc/get_contents() + return + +//Recursive function to find everything a mob is holding. +/mob/living/get_contents(var/obj/item/weapon/storage/Storage = null) + var/list/L = list() + + if(Storage) //If it called itself + L += Storage.return_inv() + + //Leave this commented out, it will cause storage items to exponentially add duplicate to the list + //for(var/obj/item/weapon/storage/S in Storage.return_inv()) //Check for storage items + // L += get_contents(S) + + for(var/obj/item/weapon/gift/G in Storage.return_inv()) //Check for gift-wrapped items + L += G.gift + if(istype(G.gift, /obj/item/weapon/storage)) + L += get_contents(G.gift) + + for(var/obj/item/smallDelivery/D in Storage.return_inv()) //Check for package wrapped items + L += D.wrapped + if(istype(D.wrapped, /obj/item/weapon/storage)) //this should never happen + L += get_contents(D.wrapped) + return L + + else + + L += src.contents + for(var/obj/item/weapon/storage/S in src.contents) //Check for storage items + L += get_contents(S) + + for(var/obj/item/weapon/gift/G in src.contents) //Check for gift-wrapped items + L += G.gift + if(istype(G.gift, /obj/item/weapon/storage)) + L += get_contents(G.gift) + + for(var/obj/item/smallDelivery/D in src.contents) //Check for package wrapped items + L += D.wrapped + if(istype(D.wrapped, /obj/item/weapon/storage)) //this should never happen + L += get_contents(D.wrapped) + return L + +/mob/living/proc/check_contents_for(A) + var/list/L = src.get_contents() + + for(var/obj/B in L) + if(B.type == A) + return 1 + return 0 + +/mob/living/proc/can_inject(var/mob/user, var/target_zone) + return 1 + +/mob/living/proc/get_organ_target() + var/mob/shooter = src + var/t = shooter:zone_sel.selecting + if ((t in list( BP_EYES, BP_MOUTH ))) + t = BP_HEAD + var/obj/item/organ/external/def_zone = ran_zone(t) + return def_zone + + +// heal ONE external organ, organ gets randomly selected from damaged ones. +/mob/living/proc/heal_organ_damage(var/brute, var/burn) + adjustBruteLoss(-brute) + adjustFireLoss(-burn) + src.updatehealth() + +// damage ONE external organ, organ gets randomly selected from damaged ones. +/mob/living/proc/take_organ_damage(var/brute, var/burn, var/emp=0) + if(status_flags & GODMODE) return 0 //godmode + adjustBruteLoss(brute) + adjustFireLoss(burn) + src.updatehealth() + +// heal MANY external organs, in random order +/mob/living/proc/heal_overall_damage(var/brute, var/burn) + adjustBruteLoss(-brute) + adjustFireLoss(-burn) + src.updatehealth() + +// damage MANY external organs, in random order +/mob/living/proc/take_overall_damage(var/brute, var/burn, var/used_weapon = null) + if(status_flags & GODMODE) return 0 //godmode + adjustBruteLoss(brute) + adjustFireLoss(burn) + src.updatehealth() + +/mob/living/proc/restore_all_organs() + return + +/mob/living/proc/revive() + rejuvenate() + if(buckled) + buckled.unbuckle_mob() + if(iscarbon(src)) + var/mob/living/carbon/C = src + + if (C.handcuffed && !initial(C.handcuffed)) + C.drop_from_inventory(C.handcuffed) + C.handcuffed = initial(C.handcuffed) + BITSET(hud_updateflag, HEALTH_HUD) + BITSET(hud_updateflag, STATUS_HUD) + BITSET(hud_updateflag, LIFE_HUD) + ExtinguishMob() + fire_stacks = 0 + +/mob/living/proc/rejuvenate() + if(reagents) + reagents.clear_reagents() + + // shut down various types of badness + setToxLoss(0) + setOxyLoss(0) + setCloneLoss(0) + setBrainLoss(0) + SetParalysis(0) + SetStunned(0) + SetWeakened(0) + setStaminaLoss(0) + + // shut down ongoing problems + radiation = 0 + bodytemperature = T20C + sdisabilities = 0 + disabilities = 0 + + // fix blindness and deafness + blinded = 0 + eye_blind = 0 + eye_blurry = 0 + ear_deaf = 0 + ear_damage = 0 + heal_overall_damage(getBruteLoss(), getFireLoss()) + + // fix all of our organs + restore_all_organs() + + // remove the character from the list of the dead + if(stat == DEAD) + switch_from_dead_to_living_mob_list() + timeofdeath = 0 + + // restore us to conciousness + set_stat(CONSCIOUS) + + // make the icons look correct + regenerate_icons() + + BITSET(hud_updateflag, HEALTH_HUD) + BITSET(hud_updateflag, STATUS_HUD) + BITSET(hud_updateflag, LIFE_HUD) + + failed_last_breath = 0 //So mobs that died of oxyloss don't revive and have perpetual out of breath. + reload_fullscreen() + return + +/mob/living/proc/UpdateDamageIcon() + return + + +/mob/living/proc/Examine_OOC() + set name = "Examine Meta-Info (OOC)" + set category = "OOC" + set src in view() + + if(config.allow_Metadata) + if(client) + to_chat(usr, "[src]'s Metainfo:
            [client.prefs.metadata]") + else + to_chat(usr, "[src] does not have any stored infomation!") + else + to_chat(usr, "OOC Metadata is not supported by this server!") + + return + +/mob/living/Move(a, b, flag) + if (buckled) + return + + if (restrained()) + stop_pulling() + + + var/t7 = 1 + if (restrained()) + for(var/mob/living/M in range(src, 1)) + if ((M.pulling == src && M.stat == 0 && !( M.restrained() ))) + t7 = null + if ((t7 && (pulling && ((get_dist(src, pulling) <= 1 || pulling.loc == loc) && (client && client.moving))))) + var/turf/T = loc + . = ..() + + if (pulling && pulling.loc) + if(!( isturf(pulling.loc) )) + stop_pulling() + return + + ///// + if(pulling && pulling.anchored) + stop_pulling() + return + + if (!restrained()) + var/diag = get_dir(src, pulling) + if ((diag - 1) & diag) + else + diag = null + if ((get_dist(src, pulling) > 1 || diag)) + if (isliving(pulling)) + var/mob/living/M = pulling + var/ok = 1 + if (locate(/obj/item/grab, M.grabbed_by)) + if (prob(75)) + var/obj/item/grab/G = pick(M.grabbed_by) + if (istype(G, /obj/item/grab)) + for(var/mob/O in viewers(M, null)) + O.show_message(text("[] has been pulled from []'s grip by []", G.affecting, G.assailant, src), 1) + //G = null + qdel(G) + else + ok = 0 + if (locate(/obj/item/grab, M.grabbed_by.len)) + ok = 0 + if (ok) + var/atom/movable/t = M.pulling + M.stop_pulling() + + + if(!istype(M.loc, /turf/space)) + var/area/A = get_area(M) + if(A.has_gravity) + //Ok I rewrote all the gay blood shit up on the floor. - Matt + if (M.lying && (prob(M.getBruteLoss() / 2))) + var/blood_exists = 0 + var/trail_type = M.getTrail() + for(var/obj/effect/decal/cleanable/trail_holder/C in M.loc) //checks for blood splatter already on the floor + blood_exists = 1 + if(ishuman(M))//Ok so they're a human, so they have blood and shit. + var/mob/living/carbon/human/H = M + var/blood_volume = round(H.vessel.get_reagent_amount(/datum/reagent/blood))//Getting their blood. + + if(blood_volume > 50)//Do they have blood? + H.vessel.remove_reagent(/datum/reagent/blood, 1)//If so take some away. + + if (istype(M.loc, /turf/simulated) && trail_type != null)//Ok we've taken the blood away then we can leave a trail. + var/newdir = get_dir(T, M.loc)//All this trail shit. + if(newdir != M.dir) + newdir = newdir | M.dir + if(newdir == 3) //N + S + newdir = NORTH + else if(newdir == 12) //E + W + newdir = EAST + if((newdir in list(1, 2, 4, 8)) && (prob(50))) + newdir = turn(get_dir(T, M.loc), 180) + if(!blood_exists) + new /obj/effect/decal/cleanable/trail_holder(M.loc) + for(var/obj/effect/decal/cleanable/trail_holder/X in M.loc) + if((!(newdir in X.existing_dirs) || trail_type == "trails_1" || trail_type == "trails_2") && X.existing_dirs.len <= 16) //maximum amount of overlays is 16 (all light & heavy directions filled) + X.existing_dirs += newdir + X.overlays.Add(image('icons/effects/blood.dmi',trail_type,dir = newdir)) + + /* + //pull damage with injured people + if(prob(25)) + M.adjustBruteLoss(1) + visible_message("\The [M]'s [M.isSynthetic() ? "state worsens": "wounds open more"] from being dragged!") + if(M.pull_damage()) + if(prob(25)) + M.adjustBruteLoss(2) + visible_message("\The [M]'s [M.isSynthetic() ? "state" : "wounds"] worsen terribly from being dragged!") + var/turf/location = M.loc + if (istype(location, /turf/simulated)) + location.add_blood(M) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/blood_volume = round(H.vessel.get_reagent_amount(/datum/reagent/blood)) + if(blood_volume > 0) + H.vessel.remove_reagent(/datum/reagent/blood, 1) + + */ + + step(pulling, get_dir(pulling.loc, T)) + if(t) + M.start_pulling(t) + else + if (pulling) + if (istype(pulling, /obj/structure/window)) + var/obj/structure/window/W = pulling + if(W.is_full_window()) + for(var/obj/structure/window/win in get_step(pulling,get_dir(pulling.loc, T))) + stop_pulling() + if (pulling) + step(pulling, get_dir(pulling.loc, T)) + else + stop_pulling() + . = ..() + + if (s_active && !( s_active in contents ) && get_turf(s_active) != get_turf(src)) //check !( s_active in contents ) first so we hopefully don't have to call get_turf() so much. + s_active.close(src) + + if(update_slimes) + for(var/mob/living/carbon/slime/M in view(1,src)) + M.UpdateFeed() + + for(var/mob/M in oview(src)) + M.update_vision_cone() + + update_vision_cone() + + +/mob/living/proc/CheckStamina() + if(staminaloss <= 0) + setStaminaLoss(0) + + if(staminaloss && !combat_mode)//If we're not doing anything, we're not in combat mode, and we've lost stamina we can wait to gain it back. + var/speed = 0 + if(is_hellbanned())//SLower recovery if you're hellbanned. + speed = 4 + if(lying) + speed += -10 + else + speed += -5 + + adjustStaminaLoss(speed) + + if(staminaloss >= staminaexhaust && !stat)//Oh shit we've lost too much stamina and now we're tired! + Exhaust() + return + +/mob/living/proc/Exhaust()//Called when you run out of stamina. + Weaken(5) + + +/mob/living/verb/resist() + set name = "Resist" + set category = "IC" + + if(!incapacitated(INCAPACITATION_KNOCKOUT) && canClick()) + setClickCooldown(20) + resist_grab() + if(!weakened) + process_resist() + +/mob/living/proc/process_resist() + //Getting out of someone's inventory. + if(istype(src.loc, /obj/item/weapon/holder)) + escape_inventory(src.loc) + return + + //unbuckling yourself + if(buckled) + spawn() escape_buckle() + return TRUE + + //Breaking out of a locker? + if( src.loc && (istype(src.loc, /obj/structure/closet)) ) + var/obj/structure/closet/C = loc + spawn() C.mob_breakout(src) + return TRUE + +/mob/living/proc/escape_inventory(obj/item/weapon/holder/H) + if(H != src.loc) return + + var/mob/M = H.loc //Get our mob holder (if any). + + if(istype(M)) + M.drop_from_inventory(H) + to_chat(M, "\The [H] wriggles out of your grip!") + to_chat(src, "You wriggle out of \the [M]'s grip!") + + // Update whether or not this mob needs to pass emotes to contents. + for(var/atom/A in M.contents) + if(istype(A,/mob/living/simple_animal/borer) || istype(A,/obj/item/weapon/holder)) + return + M.status_flags &= ~PASSEMOTES + else if(istype(H.loc,/obj/item/clothing/accessory/holster)) + var/obj/item/clothing/accessory/holster/holster = H.loc + if(holster.holstered == H) + holster.clear_holster() + to_chat(src, "You extricate yourself from \the [holster].") + H.forceMove(get_turf(H)) + else if(istype(H.loc,/obj)) + if(istype(H.loc, /obj/machinery/cooker)) + var/obj/machinery/cooker/C = H.loc + C.cooking_obj = null + C.check_cooking_obj() + to_chat(src, "You struggle free of \the [H.loc].") + H.forceMove(get_turf(H)) + + if(loc != H) + qdel(H) + +/mob/living/proc/escape_buckle() + if(buckled) + if(buckled.can_buckle) + buckled.user_unbuckle_mob(src) + else + to_chat(usr, "You can't seem to escape from \the [buckled]!") + return + +/mob/living/proc/resist_grab() + var/resisting = 0 + for(var/obj/item/grab/G in grabbed_by) + resisting++ + G.handle_resist() + if(resisting) + visible_message("[src] resists!") + +/mob/living/verb/lay_down() + set name = "Rest" + set category = "IC" + + resting = !resting + to_chat(src, "You are now [resting ? "resting" : "getting up"]") + +//called when the mob receives a bright flash +/mob/living/flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash) + if(override_blindness_check || !(disabilities & BLIND)) + overlay_fullscreen("flash", type) + spawn(25) + if(src) + clear_fullscreen("flash", 25) + return 1 + +/mob/living/proc/cannot_use_vents() + if(mob_size > MOB_SMALL) + return "You can't fit into that vent." + return null + +/mob/living/proc/has_brain() + return 1 + +/mob/living/proc/has_eyes() + return 1 + +/mob/living/proc/slip(var/slipped_on,stun_duration=8) + return 0 + +/mob/living/carbon/drop_from_inventory(var/obj/item/W, var/atom/Target = null) + if(W in internal_organs) + return + . = ..() + +//damage/heal the mob ears and adjust the deaf amount +/mob/living/adjustEarDamage(var/damage, var/deaf) + ear_damage = max(0, ear_damage + damage) + ear_deaf = max(0, ear_deaf + deaf) + +//pass a negative argument to skip one of the variable +/mob/living/setEarDamage(var/damage = null, var/deaf = null) + if(!isnull(damage)) + ear_damage = damage + if(!isnull(deaf)) + ear_deaf = deaf + +/mob/proc/can_be_possessed_by(var/mob/observer/ghost/possessor) + return istype(possessor) && possessor.client + +/mob/living/can_be_possessed_by(var/mob/observer/ghost/possessor) + if(!..()) + return 0 + if(!possession_candidate) + to_chat(possessor, "That animal cannot be possessed.") + return 0 + if(jobban_isbanned(possessor, "Animal")) + to_chat(possessor, "You are banned from animal roles.") + return 0 + if(!possessor.MayRespawn(1,ANIMAL_SPAWN_DELAY)) + return 0 + return 1 + +/mob/living/proc/do_possession(var/mob/observer/ghost/possessor) + + if(!(istype(possessor) && possessor.ckey)) + return 0 + + if(src.ckey || src.client) + to_chat(possessor, "\The [src] already has a player.") + return 0 + + message_admins("[key_name_admin(possessor)] has taken control of \the [src].") + log_admin("[key_name(possessor)] took control of \the [src].") + src.ckey = possessor.ckey + qdel(possessor) + + if(round_is_spooky(6)) // Six or more active cultists. + to_chat(src, "You reach out with tendrils of ectoplasm and invade the mind of \the [src]...") + to_chat(src, "You have assumed direct control of \the [src].") + to_chat(src, "Due to the spookiness of the round, you have taken control of the poor animal as an invading, possessing spirit - roleplay accordingly.") + src.universal_speak = 1 + src.universal_understand = 1 + //src.cultify() // Maybe another time. + return + + to_chat(src, "You are now \the [src]!") + to_chat(src, "Remember to stay in character for a mob of this type!") + return 1 + +/mob/living/reset_layer() + if(hiding) + plane = HIDING_MOB_PLANE + layer = HIDING_MOB_LAYER + else + ..() +/mob/living/set_dir() + ..() + update_vision_cone() + +/atom/movable/proc/receive_damage(atom/A) + var/pixel_x_diff = rand(-2,2) + var/pixel_y_diff = rand(-2,2) + animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, time = 2) + animate(pixel_x = initial(pixel_x), pixel_y = initial(pixel_y), time = 2) + +/mob/living/update_icons() + if(auras) + overlays |= auras + +/mob/living/receive_damage(atom/A) + ..() + +/mob/living/proc/add_aura(var/obj/aura/aura) + LAZYDISTINCTADD(auras,aura) + update_icons() + return 1 + +/mob/living/proc/getTrail() //silicon and simple_animals don't get blood trails + return null + +/mob/living/proc/remove_aura(var/obj/aura/aura) + LAZYREMOVE(auras,aura) + update_icons() + return 1 + +/mob/living/Destroy() + if(auras) + for(var/a in auras) + remove_aura(a) + return ..() + +//Does a special attack if combat mode is on, and they have an item. +/mob/living/RightClick(var/mob/living/user) + if(user.Adjacent(src)) + var/obj/item/I = user.get_active_hand() + if(!I) + return + if(!user.combat_mode) + return + I.attack(src, user, user.zone_sel.selecting, TRUE) + + /* + else + //Aiming a gun at someone. + var/obj/item/weapon/gun/G = user.get_active_hand() + if(G) + if(ismob(src) && user.aiming) + if(src == user.aiming.aiming_at)//If we're already aiming at them, then stop aiming. + user.aiming.cancel_aiming() + else + user.aiming.aim_at(src, G)//Else aim at them with the gun. + */ + + +/mob/living/proc/handle_lisp() + if(ishuman(src)) + var/mob/living/carbon/human/H = src + var/obj/item/organ/external/head/O = locate(/obj/item/organ/external/head) in H.organs + if(O) + if(!O.teeth_list.len || O.get_teeth() <= 0) + lisp = 100 //No teeth = full lisp power + else + lisp = (1 - (O.get_teeth()/O.max_teeth)) * 100 //Less teeth = more lisp + else + lisp = 0 //No head = no lisp. + return lisp + +/mob/living/proc/melee_accuracy_mods() + . = 0 + if(eye_blind) + . += 75 + if(eye_blurry) + . += 15 + if(confused) + . += 30 + +/mob/living/proc/toggle_crouch() + if(lying)//No crouching while you're lying down please. + return + crouching = !crouching + if(crouching) + to_chat(src, "You crouch low.") + if(istype(loc, /turf/simulated/floor/trench)) + pixel_y = -12 + if(zoomed)//Can't zoom in if you're crouching behind cover. + do_zoom() + + else + to_chat(src, "You stand up.") + if(istype(loc, /turf/simulated/floor/trench)) + pixel_y = -8 + +/mob/living/verb/toggle_crouching() + set name = ".toggle_crouching" + set hidden = TRUE + toggle_crouch() \ No newline at end of file diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm new file mode 100644 index 00000000..3945e67f --- /dev/null +++ b/code/modules/mob/living/living_defense.dm @@ -0,0 +1,413 @@ + +/* + run_armor_check() args + def_zone - What part is getting hit, if null will check entire body + attack_flag - The type of armour to be checked + armour_pen - reduces the effectiveness of armour + absorb_text - shown if the armor check is 100% successful + soften_text - shown if the armor check is more than 0% successful and less than 100% + + Returns + a blocked amount between 0 - 100, representing the success of the armor check. +*/ +/mob/living/proc/run_armor_check(var/def_zone = null, var/attack_flag = "melee", var/armour_pen = 0, var/absorb_text = null, var/soften_text = null) + if(armour_pen >= 100) + return 0 //might as well just skip the processing + + var/armor = getarmor(def_zone, attack_flag) + + if(armour_pen >= armor) + return 0 //effective_armor is going to be 0, fullblock is going to be 0, blocked is going to 0, let's save ourselves the trouble + + var/effective_armor = (armor - armour_pen)/100 + var/fullblock = (effective_armor*effective_armor) * ARMOR_BLOCK_CHANCE_MULT + + if(fullblock >= 1 || prob(fullblock*100)) + if(absorb_text) + show_message("[absorb_text]") + else + show_message("Your armor blocks the blow!") + + playsound(src, "sound/weapons/armorblockheavy[rand(1,3)].ogg", 50, 1, 1) + return 100 + + //this makes it so that X armour blocks X% damage, when including the chance of hard block. + //I double checked and this formula will also ensure that a higher effective_armor + //will always result in higher (non-fullblock) damage absorption too, which is also a nice property + //In particular, blocked will increase from 0 to 50 as effective_armor increases from 0 to 0.999 (if it is 1 then we never get here because ofc) + //and the average damage absorption = (blocked/100)*(1-fullblock) + 1.0*(fullblock) = effective_armor + var/blocked = (effective_armor - fullblock)/(1 - fullblock)*100 + + if(blocked > 20) + //Should we show this every single time? + if(soften_text) + show_message("[soften_text]") + else + show_message("Your armor softens the blow!") + + playsound(src, "sound/weapons/armorblock[rand(1,4)].ogg", 50, 1, 1) + return round(blocked, 1) + +//Adds two armor values together. +//If armor_a and armor_b are between 0-100 the result will always also be between 0-100. +/proc/add_armor(var/armor_a, var/armor_b) + if(armor_a >= 100 || armor_b >= 100) + return 100 //adding to infinite protection doesn't make it any bigger + + var/protection_a = 1/(blocked_mult(armor_a)) - 1 + var/protection_b = 1/(blocked_mult(armor_b)) - 1 + return 100 - 1/(protection_a + protection_b + 1)*100 + +//if null is passed for def_zone, then this should return something appropriate for all zones (e.g. area effect damage) +/mob/living/proc/getarmor(var/def_zone, var/type) + return 0 + + +/mob/living/bullet_act(var/obj/item/projectile/P, var/def_zone) + + //Being hit while using a deadman switch + var/obj/item/device/assembly/signaler/signaler = get_active_hand() + if(istype(signaler) && signaler.deadman) + log_and_message_admins("has triggered a signaler deadman's switch") + src.visible_message("[src] triggers their deadman's switch!") + signaler.signal() + + //Armor + var/damage = P.damage + var/flags = P.damage_flags() + var/absorb = run_armor_check(def_zone, P.check_armour, P.armor_penetration) + if (prob(absorb)) + if(flags & DAM_LASER) + //the armour causes the heat energy to spread out, which reduces the damage (and the blood loss) + //this is mostly so that armour doesn't cause people to lose MORE fluid from lasers than they would otherwise + damage *= FLUIDLOSS_CONC_BURN/FLUIDLOSS_WIDE_BURN + flags &= ~(DAM_SHARP|DAM_EDGE|DAM_LASER) + + if(!P.nodamage) + apply_damage(damage, P.damage_type, def_zone, absorb, flags, P) + P.on_hit(src, absorb, def_zone) + + return absorb + +/mob/living/proc/aura_check(var/type) + if(!auras) + return TRUE + . = TRUE + var/list/newargs = args - args[1] + for(var/a in auras) + var/obj/aura/aura = a + var/result = 0 + switch(type) + if(AURA_TYPE_WEAPON) + result = aura.attackby(arglist(newargs)) + if(AURA_TYPE_BULLET) + result = aura.bullet_act(arglist(newargs)) + if(AURA_TYPE_THROWN) + result = aura.hitby(arglist(newargs)) + if(AURA_TYPE_LIFE) + result = aura.life_tick() + if(result & AURA_FALSE) + . = FALSE + if(result & AURA_CANCEL) + break + + +//Handles the effects of "stun" weapons +/mob/living/proc/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon=null) + flash_pain() + + if (stun_amount) + Stun(stun_amount) + Weaken(stun_amount) + apply_effect(STUTTER, stun_amount) + apply_effect(EYE_BLUR, stun_amount) + + if (agony_amount) + apply_damage(agony_amount, PAIN, def_zone, 0, used_weapon) + apply_effect(STUTTER, agony_amount/10) + apply_effect(EYE_BLUR, agony_amount/10) + +/mob/living/proc/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0) + return 0 //only carbon liveforms have this proc + +/mob/living/emp_act(severity) + var/list/L = src.get_contents() + for(var/obj/O in L) + 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 >= 100) + return 0 + + //Hulk modifier + if(HULK in user.mutations) + effective_force *= 2 + + //Apply weapon damage + var/damage_flags = I.damage_flags() + if(prob(blocked)) //armour provides a chance to turn sharp/edge weapon attacks into blunt ones + damage_flags &= ~(DAM_SHARP|DAM_EDGE) + + if(user.STAT_LEVEL(str))//If they have strength then add it. + effective_force *= strToDamageModifier(user.STAT_LEVEL(str)) + + apply_damage(effective_force, I.damtype, hit_zone, blocked, damage_flags, 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(!aura_check(AURA_TYPE_THROWN, AM, speed)) + return + if(istype(AM,/obj/)) + var/obj/O = AM + var/dtype = O.damtype + var/throw_damage = O.throwforce*(speed/THROWFORCE_SPEED_DIVISOR) + + var/miss_chance = 15 + if (O.throw_source) + var/distance = get_dist(O.throw_source, loc) + miss_chance = max(15*(distance-2), 0) + + if (prob(miss_chance)) + visible_message("\The [O] misses [src] narrowly!") + return + + src.visible_message("\The [src] has been hit by \the [O].") + var/armor = run_armor_check(null, "melee") + if(armor < 100) + var/damage_flags = O.damage_flags() + if(prob(armor)) + damage_flags &= ~(DAM_SHARP|DAM_EDGE) + apply_damage(throw_damage, dtype, null, armor, damage_flags, O) + + O.throwing = 0 //it hit, so stop moving + + if(ismob(O.thrower)) + var/mob/M = O.thrower + var/client/assailant = M.client + if(assailant) + admin_attack_log(M, src, "Threw \an [O] at the victim.", "Had \an [O] thrown at them.", "threw \an [O] at") + + // Begin BS12 momentum-transfer code. + var/mass = 1.5 + if(istype(O, /obj/item)) + var/obj/item/I = O + mass = I.w_class/THROWNOBJ_KNOCKBACK_DIVISOR + var/momentum = speed*mass + + if(O.throw_source && momentum >= THROWNOBJ_KNOCKBACK_SPEED) + var/dir = get_dir(O.throw_source, src) + + visible_message("\The [src] staggers under the impact!","You stagger under the impact!") + src.throw_at(get_edge_target_turf(src,dir),1,momentum) + + if(!O || !src) return + + if(O.sharp) //Projectile is suitable for pinning. + //Handles embedding for non-humans and simple_animals. + embed(O) + + var/turf/T = near_wall(dir,2) + + if(T) + src.loc = T + visible_message("[src] is pinned to the wall by [O]!","You are pinned to the wall by [O]!") + src.anchored = 1 + src.pinned += O + +/mob/living/proc/embed(var/obj/O, var/def_zone=null, var/datum/wound/supplied_wound) + O.loc = src + src.embedded += O + src.verbs += /mob/proc/yank_out_object + +//This is called when the mob is thrown into a dense turf +/mob/living/proc/turf_collision(var/turf/T, var/speed) + visible_message("[src] slams into \the [T]!") + var/smashsound = pick("sound/effects/gore/smash[rand(1,3)].ogg", "sound/effects/gore/trauma1.ogg") + playsound(loc, smashsound, 50, 1, -1) + //playsound(loc, 'sound/effects/bangtaper.ogg', 50, 1, -1) + src.take_organ_damage(speed*5) + T.add_blood(src) + +/mob/living/proc/near_wall(var/direction,var/distance=1) + var/turf/T = get_step(get_turf(src),direction) + var/turf/last_turf = src.loc + var/i = 1 + + while(i>0 && i<=distance) + if(T.density) //Turf is a wall! + return last_turf + i++ + last_turf = T + T = get_step(T,direction) + + return 0 + +// End BS12 momentum-transfer code. + +/mob/living/attack_generic(var/mob/user, var/damage, var/attack_message) + + if(!damage || !istype(user)) + return + + adjustBruteLoss(damage) + admin_attack_log(user, src, "Attacked", "Was attacked", "attacked") + + src.visible_message("[user] has [attack_message] [src]!") + spawn(1) updatehealth() + return 1 + +/mob/living/proc/IgniteMob() + if(fire_stacks > 0 && !on_fire) + on_fire = 1 + set_light(light_range + 3) + update_fire() + playsound(src, 'sound/effects/fire.ogg', 50, TRUE)//A little sizzle as you're lit up. + +/mob/living/proc/ExtinguishMob() + if(on_fire) + playsound(src, 'sound/items/cig_snuff.ogg', 50, TRUE)//A little sizzle as you're put out. + on_fire = 0 + fire_stacks = 0 + set_light(max(0, light_range - 3)) + update_fire() + +/mob/living/proc/update_fire() + return + +/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person + fire_stacks = Clamp(fire_stacks + add_fire_stacks, FIRE_MIN_STACKS, FIRE_MAX_STACKS) + +/mob/living/proc/handle_fire() + if(fire_stacks < 0) + fire_stacks = min(0, ++fire_stacks) //If we've doused ourselves in water to avoid fire, dry off slowly + + if(!on_fire) + return 1 + else if(fire_stacks <= 0) + ExtinguishMob() //Fire's been put out. + return 1 + + fire_stacks = max(0, fire_stacks - 0.2) //I guess the fire runs out of fuel eventually + + var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment + if(G.get_by_flag(XGM_GAS_OXIDIZER) < 1) + ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire + return 1 + + var/turf/location = get_turf(src) + location.hotspot_expose(fire_burn_temperature(), 50, 1) + +/mob/living/fire_act(datum/gas_mixture/air, temperature, volume) + //once our fire_burn_temperature has reached the temperature of the fire that's giving fire_stacks, stop adding them. + //allow fire_stacks to go up to 4 for fires cooler than 700 K, since are being immersed in flame after all. + if(fire_stacks <= 4 || fire_burn_temperature() < temperature) + adjust_fire_stacks(2) + IgniteMob() + +/mob/living/proc/get_cold_protection() + return 0 + +/mob/living/proc/get_heat_protection() + return 0 + +//Finds the effective temperature that the mob is burning at. +/mob/living/proc/fire_burn_temperature() + if (fire_stacks <= 0) + return 0 + + //Scale quadratically so that single digit numbers of fire stacks don't burn ridiculously hot. + //lower limit of 700 K, same as matches and roughly the temperature of a cool flame. + return max(2.25*round(FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE*(fire_stacks/FIRE_MAX_FIRESUIT_STACKS)**2), 700) + +/mob/living/proc/reagent_permeability() + return 1 + +/mob/living/proc/handle_actions() + //Pretty bad, i'd use picked/dropped instead but the parent calls in these are nonexistent + for(var/datum/action/A in actions) + if(A.CheckRemoval(src)) + A.Remove(src) + for(var/obj/item/I in src) + if(I.action_button_name) + if(!I.action) + if(I.action_button_is_hands_free) + I.action = new/datum/action/item_action/hands_free + else + I.action = new/datum/action/item_action + I.action.name = I.action_button_name + I.action.target = I + I.action.Grant(src) + return + +/mob/living/update_action_buttons() + if(!hud_used) return + if(!client) return + + if(hud_used.hud_shown != 1) //Hud toggled to minimal + return + + client.screen -= hud_used.hide_actions_toggle + for(var/datum/action/A in actions) + if(A.button) + client.screen -= A.button + + if(hud_used.action_buttons_hidden) + if(!hud_used.hide_actions_toggle) + hud_used.hide_actions_toggle = new(hud_used) + hud_used.hide_actions_toggle.UpdateIcon() + + if(!hud_used.hide_actions_toggle.moved) + hud_used.hide_actions_toggle.screen_loc = hud_used.ButtonNumberToScreenCoords(1) + //hud_used.SetButtonCoords(hud_used.hide_actions_toggle,1) + + client.screen += hud_used.hide_actions_toggle + return + + var/button_number = 0 + for(var/datum/action/A in actions) + button_number++ + if(A.button == null) + var/obj/screen/movable/action_button/N = new(hud_used) + N.owner = A + A.button = N + + var/obj/screen/movable/action_button/B = A.button + + B.UpdateIcon() + + B.SetName(A.UpdateName()) + + client.screen += B + + if(!B.moved) + B.screen_loc = hud_used.ButtonNumberToScreenCoords(button_number) + //hud_used.SetButtonCoords(B,button_number) + + if(button_number > 0) + if(!hud_used.hide_actions_toggle) + hud_used.hide_actions_toggle = new(hud_used) + hud_used.hide_actions_toggle.InitialiseIcon(src) + if(!hud_used.hide_actions_toggle.moved) + 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 diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm new file mode 100644 index 00000000..e6264955 --- /dev/null +++ b/code/modules/mob/living/living_defines.dm @@ -0,0 +1,77 @@ +/mob/living + see_in_dark = 2 + see_invisible = SEE_INVISIBLE_LIVING + + //Health and life related vars + var/maxHealth = 100 //Maximum health that should be possible. + var/health = 100 //A mob's health + + var/hud_updateflag = 0 + + //Damage related vars, NOTE: THESE SHOULD ONLY BE MODIFIED BY PROCS // what a joke + //var/bruteloss = 0 //Brutal damage caused by brute force (punching, being clubbed by a toolbox ect... this also accounts for pressure damage) + //var/oxyloss = 0 //Oxygen depravation damage (no air in lungs) + //var/toxloss = 0 //Toxic damage caused by being poisoned or radiated + //var/fireloss = 0 //Burn damage caused by being way too hot, too cold or burnt. + //var/halloss = 0 //Hallucination damage. 'Fake' damage obtained through hallucinating or the holodeck. Sleeping should cause it to wear off. + + var/lisp = 0 + var/staminaloss = 0 + var/staminaexhaust = 250 + var/tongueless = 0 + + var/last_special = 0 //Used by the resist verb, likely used to prevent players from bypassing next_move by logging in/out. + + var/t_phoron = null + var/t_oxygen = null + var/t_sl_gas = null + var/t_n2 = null + + var/now_pushing = null + var/mob_bump_flag = 0 + var/mob_swap_flags = 0 + var/mob_push_flags = 0 + var/mob_always_swap = 0 + + var/mob/living/cameraFollow = null + var/list/datum/action/actions = list() + + var/update_slimes = 1 + var/on_fire = 0 //The "Are we on fire?" var + var/fire_stacks + + var/failed_last_breath = 0 //This is used to determine if the mob failed a breath. If they did fail a brath, they will attempt to breathe each tick, otherwise just once per 4 ticks. + var/possession_candidate // Can be possessed by ghosts if unplayed. + + var/eye_blind = null //Carbon + var/eye_blurry = null //Carbon + var/ear_damage = null //Carbon + var/stuttering = null //Carbon + var/slurring = null //Carbon + var/slur_loop = FALSE + var/deaf_loop = FALSE + var/horror_loop = FALSE + + var/job = null//Living + var/list/obj/aura/auras = null //Basically a catch-all aura/force-field thing. + + var/obj/screen/cells = null + var/list/in_vision_cones = list() + var/doing_something = FALSE + + var/religion = "Nothing" //Leftover from anther time. + var/datum/trait/trait = null + var/fast_stripper = FALSE //whether or not you can turbostrip + + //This is for the screen. Yes I hate this. Yes I know it needs a refactor. No I don't care at the moment. + var/obj/screen/plane_master/human_blur/HB = new + var/obj/screen/plane_master/turf_blur/TB = new + var/obj/screen/plane_master/wall_blur/WB = new + var/obj/screen/plane_master/obj_blur/OB = new + var/obj/screen/plane_master/abover_turf_blur/AT = new + var/obj/screen/plane_master/lhuman_blur/LB = new + var/obj/screen/plane_master/mob_blur/MB = new + var/obj/screen/plane_master/above_human_blur/AB = new + var/obj/screen/plane_master/effects_blur/EB = new + var/obj/screen/plane_master/plating_blur/plating_blur = new + var/obj/screen/plane_master/abover_obj_blur/AOB = new \ No newline at end of file diff --git a/code/modules/mob/living/living_powers.dm b/code/modules/mob/living/living_powers.dm new file mode 100644 index 00000000..0c04ddde --- /dev/null +++ b/code/modules/mob/living/living_powers.dm @@ -0,0 +1,58 @@ +/mob/living + var/hiding + +/mob/living/proc/hide() + set name = "Hide" + set desc = "Allows to hide beneath tables or certain items. Toggled on or off." + set category = "Abilities" + + if(incapacitated()) + return + + hiding = !hiding + if(hiding) + to_chat(src, "You are now hiding.") + else + to_chat(src, "You have stopped hiding.") + reset_layer() + +/mob/living/proc/breath_death() + set name = "Breath Death" + set desc = "Infect others with your very breathe." + set category = "Abilities" + + if(last_special > world.time) + return + + last_special = world.time + 1 SECOND + + var/turf/T = get_turf(src) + var/obj/effect/effect/water/chempuff/chem = new(T) + chem.create_reagents(10) + chem.reagents.add_reagent(/datum/reagent/toxin/corrupting,30) + chem.set_up(get_step(T, dir), 2, 10) + playsound(T, 'sound/hallucinations/wail.ogg',20,1) + +/mob/living/proc/consume() + set name = "Consume" + set desc = "Regain life by consuming it from others." + set category = "Abilities" + + if(last_special > world.time) + return + var/mob/living/target + for(var/mob/living/L in get_turf(src)) + if(L.lying || L.stat == DEAD) + target = L + break + if(!target) + return + + last_special = world.time + 50 + + src.visible_message("\The [src] hunkers down over \the [target], tearing into their flesh.") + if(do_after(src,target,100)) + target.adjustBruteLoss(25) + if(target.health < -target.maxHealth) + target.gib() + src.adjustBruteLoss(-25) \ No newline at end of file diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm new file mode 100644 index 00000000..b41baabe --- /dev/null +++ b/code/modules/mob/living/login.dm @@ -0,0 +1,9 @@ + +/mob/living/Login() + ..() + //Mind updates + mind_initialize() //updates the mind (or creates and initializes one if one doesn't exist) + mind.active = 1 //indicates that the mind is currently synced with a client + //If they're SSD, remove it so they can wake back up. + update_antag_icons(mind) + return . diff --git a/code/modules/mob/living/logout.dm b/code/modules/mob/living/logout.dm new file mode 100644 index 00000000..08fcfff7 --- /dev/null +++ b/code/modules/mob/living/logout.dm @@ -0,0 +1,7 @@ +/mob/living/Logout() + ..() + if (mind) + //Per BYOND docs key remains set if the player DCs, becomes null if switching bodies. + if(!key) //key and mind have become seperated. + mind.active = 0 //This is to stop say, a mind.transfer_to call on a corpse causing a ghost to re-enter its body. + ambience_is_playing = 0 diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm new file mode 100644 index 00000000..f791acd9 --- /dev/null +++ b/code/modules/mob/living/say.dm @@ -0,0 +1,417 @@ +var/list/department_radio_keys = list( + ":r" = "right ear", ".r" = "right ear", + ":l" = "left ear", ".l" = "left ear", + ":i" = "intercom", ".i" = "intercom", + ":h" = "department", ".h" = "department", + ":+" = "special", ".+" = "special", //activate radio-specific special functions + ":c" = "Command", ".c" = "Command", + ":n" = "Science", ".n" = "Science", + ":m" = "Medical", ".m" = "Medical", + ":e" = "Engineering", ".e" = "Engineering", + ":s" = "Security", ".s" = "Security", + ":w" = "whisper", ".w" = "whisper", + ":t" = "Mercenary", ".t" = "Mercenary", + ":x" = "Raider", ".x" = "Raider", + ":u" = "Supply", ".u" = "Supply", + ":v" = "Service", ".v" = "Service", + ":d" = "Inquisition", ".d" = "Inquisition", + ":p" = "AI Private", ".p" = "AI Private", + ":z" = "Entertainment",".z" = "Entertainment", + ":y" = "Exploration", ".y" = "Exploration", + ":b" = "Blue", ".b" = "Blue", + ":q" = "Red", ".q" = "Red", + ":a" = "Red Alpha", ".a" = "Red Alpha", + ":g" = "Red Bravo", ".g" = "Red Bravo", + ":c" = "Red Charlie",".c" = "Red Charlie", + ":d" = "Red Delta", ".d" = "Red Delta", + + ":f" = "Blue Alpha", ".f" = "Blue Alpha", + ":i" = "Blue Bravo", ".i" = "Blue Bravo", + ":j" = "Blue Charlie",".j" = "Blue Charlie", + ":k" = "Blue Delta", ".k" = "Blue Delta", + + + + + + ":R" = "right ear", ".R" = "right ear", + ":L" = "left ear", ".L" = "left ear", + ":I" = "intercom", ".I" = "intercom", + ":H" = "department", ".H" = "department", + ":C" = "Command", ".C" = "Command", + ":N" = "Science", ".N" = "Science", + ":M" = "Medical", ".M" = "Medical", + ":E" = "Engineering", ".E" = "Engineering", + ":S" = "Security", ".S" = "Security", + ":W" = "whisper", ".W" = "whisper", + ":T" = "Mercenary", ".T" = "Mercenary", + ":X" = "Raider", ".X" = "Raider", + ":U" = "Supply", ".U" = "Supply", + ":V" = "Service", ".V" = "Service", + ":D" = "Inquisition", ".D" = "Inquisition", + ":P" = "AI Private", ".P" = "AI Private", + ":Z" = "Entertainment",".Z" = "Entertainment", + ":Y" = "Exploration", ".Y" = "Exploration", + + //kinda localization -- rastaf0 + //same keys as above, but on russian keyboard layout. This file uses cp1251 as encoding. + ":ê" = "right ear", ".ê" = "right ear", + ":ä" = "left ear", ".ä" = "left ear", + ":ø" = "intercom", ".ø" = "intercom", + ":ð" = "department", ".ð" = "department", + ":ñ" = "Command", ".ñ" = "Command", + ":ò" = "Science", ".ò" = "Science", + ":ü" = "Medical", ".ü" = "Medical", + ":ó" = "Engineering", ".ó" = "Engineering", + ":û" = "Security", ".û" = "Security", + ":ö" = "whisper", ".ö" = "whisper", + ":å" = "Mercenary", ".å" = "Mercenary", + ":é" = "Supply", ".é" = "Supply", +) + + +var/list/channel_to_radio_key = new +proc/get_radio_key_from_channel(var/channel) + var/key = channel_to_radio_key[channel] + if(!key) + for(var/radio_key in department_radio_keys) + if(department_radio_keys[radio_key] == channel) + key = radio_key + break + if(!key) + key = "" + channel_to_radio_key[channel] = key + + return key + +/mob/living/proc/binarycheck() + + if (istype(src, /mob/living/silicon/pai)) + return + + if (!ishuman(src)) + return + + var/mob/living/carbon/human/H = src + if (H.l_ear || H.r_ear) + var/obj/item/device/radio/headset/dongle + if(istype(H.l_ear,/obj/item/device/radio/headset)) + dongle = H.l_ear + else + dongle = H.r_ear + if(!istype(dongle)) return + if(dongle.translate_binary) return 1 + +/mob/living/proc/get_default_language() + return default_language + +/mob/proc/is_muzzled() + return istype(wear_mask, /obj/item/clothing/mask/muzzle) + +//Takes a list of the form list(message, verb, whispering) and modifies it as needed +//Returns 1 if a speech problem was applied, 0 otherwise +/mob/living/proc/handle_speech_problems(var/list/message_data) + var/message = html_decode(message_data[1]) + var/verb = message_data[2] + + . = 0 + + if((HULK in mutations) && health >= 25 && length(message)) + message = "[uppertext(message)]!!!" + verb = pick("yells","roars","hollers") + message_data[3] = 0 + . = 1 + if(slurring) + message = slur(message) + verb = pick("slobbers","slurs") + . = 1 + + if(lisp) + message = lisp(message, lisp) + . = 1 + + if(stuttering) + message = NewStutter(message)//stutter + verb = pick("stammers","stutters") + . = 1 + + message_data[1] = message + message_data[2] = verb + +/mob/living/proc/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) + if(message_mode == "intercom") + for(var/obj/item/device/radio/intercom/I in view(1, null)) + I.talk_into(src, message, verb, speaking) + used_radios += I + return 0 + +/mob/living/proc/handle_speech_sound() + var/list/returns[2] + returns[1] = null + returns[2] = null + return returns + +/mob/living/proc/get_speech_ending(verb, var/ending) + if(ending=="!") + return pick("exclaims","shouts","yells") + if(ending=="?") + return "asks" + return verb + +/mob/living/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="", whispering) + if(client) + if(client.prefs.muted & MUTE_IC) + to_chat(src, "You cannot speak in IC (Muted).") + return + + if(stat) + if(stat == 2) + return say_dead(message) + return + + if(GLOB.in_character_filter.len) //&& !forced) + if(findtext(message, config.ic_filter_regex)) + // let's try to be a bit more informative! + var/warning_message = "Bro you just tried to say cringe! You're going to loose subscriber! Check the server rules!
            The bolded terms are disallowed: "" + var/list/words = splittext(message, " ") + var/cringe = "" + for (var/word in words) + if (findtext(word, config.ic_filter_regex)) + warning_message = "[warning_message][word] " + cringe += "/[word]" + else + warning_message = "[warning_message][word] " + + + warning_message = trim(warning_message) + to_chat(src, "[warning_message]"
            ") + log_and_message_admins("[src] just tried to say cringe: [cringe]", src) + return + + + var/prefix = copytext(message,1,2) + if(prefix == get_prefix_key(/decl/prefix/custom_emote)) + return emote(copytext(message,2)) + if(prefix == get_prefix_key(/decl/prefix/visible_emote)) + return custom_emote(1, copytext(message,2)) + + //parse the radio code and consume it + var/message_mode = parse_message_mode(message, "headset") + if (message_mode) + if (message_mode == "headset") + message = copytext(message,2) //it would be really nice if the parse procs could do this for us. + else + message = copytext(message,3) + + message = trim_left(message) + + //parse the language code and consume it + if(!speaking) + speaking = parse_language(message) + if(speaking) + message = copytext(message,2+length(speaking.key)) + else + speaking = get_default_language() + + // This is broadcast to all mobs with the language, + // irrespective of distance or anything else. + if(speaking && (speaking.flags & HIVEMIND)) + speaking.broadcast(src,trim(message)) + return 1 + + if (speaking) + if(whispering) + verb = speaking.whisper_verb ? speaking.whisper_verb : speaking.speech_verb + else + verb = say_quote(message, speaking) + + message = trim_left(message) + + if(!(speaking && (speaking.flags & NO_STUTTER))) + var/list/message_data = list(message, verb, 0) + if(handle_speech_problems(message_data)) + message = message_data[1] + verb = message_data[2] + + if(!message || message == "") + return 0 + + var/list/obj/item/used_radios = new + if(handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)) + return 1 + + var/list/handle_v = handle_speech_sound() + var/sound/speech_sound = handle_v[1] + var/sound_vol = handle_v[2] + + var/italics = 0 + var/message_range = world.view + + if(whispering) + italics = 1 + message_range = 1 + + //speaking into radios + if(used_radios.len) + italics = 1 + message_range = 1 + if(speaking) + message_range = speaking.get_talkinto_msg_range(message) + var/msg + if(!speaking || !(speaking.flags & NO_TALK_MSG)) + msg = "\The [src] talks into \the [used_radios[1]]" + for(var/mob/living/M in hearers(5, src)) + if((M != src) && msg) + M.show_message(msg) + if (speech_sound) + sound_vol *= 0.5 + + var/list/listening = list() + var/list/listening_obj = list() + var/turf/T = get_turf(src) + + //handle nonverbal and sign languages here + if (speaking) + if (speaking.flags & NONVERBAL) + if (prob(30)) + src.custom_emote(1, "[pick(speaking.signlang_verb)].") + + if (speaking.flags & SIGNLANG) + log_say("[name]/[key] : SIGN: [message]") + return say_signlang(message, pick(speaking.signlang_verb), speaking) + + if(T) + //make sure the air can transmit speech - speaker's side + var/datum/gas_mixture/environment = T.return_air() + var/pressure = (environment)? environment.return_pressure() : 0 + if(pressure < SOUND_MINIMUM_PRESSURE) + message_range = 1 + + if (pressure < ONE_ATMOSPHERE*0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet + italics = 1 + sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact + + get_mobs_and_objs_in_view_fast(T, message_range, listening, listening_obj, /datum/client_preference/ghost_ears) + + + var/speech_bubble_test = say_test(message) + var/image/speech_bubble = image('icons/mob/talk.dmi',src,"h[speech_bubble_test]") + + // VOREStation Port - Attempt Multi-Z Talking + var/mob/above = src.shadow + while(!QDELETED(above)) + var/turf/ST = get_turf(above) + if(ST) + + get_mobs_and_objs_in_view_fast(ST, world.view, listening, listening_obj, /datum/client_preference/ghost_ears) + var/image/z_speech_bubble = image('icons/mob/talk.dmi', above, "h[speech_bubble_test]") + spawn(30) qdel(z_speech_bubble) + above = above.shadow + + // VOREStation Port End + + var/list/speech_bubble_recipients = list() + for(var/mob/M in listening) + if(M) + M.hear_say(message, verb, speaking, alt_name, italics, src, speech_sound, sound_vol) + if(M.client) + speech_bubble_recipients += M.client + + INVOKE_ASYNC(GLOBAL_PROC, .proc/animate_speechbubble, speech_bubble, speech_bubble_recipients, 30) + + for(var/obj/O in listening_obj) + spawn(0) + if(O) //It's possible that it could be deleted in the meantime. + O.hear_talk(src, message, verb, speaking) + + if(whispering) + var/eavesdroping_range = 5 + var/list/eavesdroping = list() + var/list/eavesdroping_obj = list() + get_mobs_and_objs_in_view_fast(T, eavesdroping_range, eavesdroping, eavesdroping_obj) + eavesdroping -= listening + eavesdroping_obj -= listening_obj + for(var/mob/M in eavesdroping) + if(M) + show_image(M, speech_bubble) + M.hear_say(stars(message), verb, speaking, alt_name, italics, src, speech_sound, sound_vol) + + for(var/obj/O in eavesdroping) + spawn(0) + if(O) //It's possible that it could be deleted in the meantime. + O.hear_talk(src, stars(message), verb, speaking) + + + if(whispering) + log_whisper("[name]/[key] : [message]") + + else + log_say("[name]/[key] : [message]") + + /* + //Uncomment these if you wish speech to have blip sfx. + var/list/temp_message = splittext(message, " ") //List each word in the message. + + for(var/i = 0, i < temp_message.len, i++) + sleep(1) + playsound(src, "sound/voice/speech/sfx-blip[gender].wav", 20) + */ + + if(!whispering) + var/ending = copytext(message, length(message)) + var/sound_key = "m" + var/sound_end = ""//Blank string by default + if(gender == FEMALE) + sound_key = "f" + if(gender == NEUTER) + sound_key = "n" + if(ending=="?") + sound_end = "_ask" + if(ending=="!") + sound_end = "_exclaim" + playsound(src, "sound/voice/human/[sound_key]speak[sound_end].ogg", 100)//Play the talking sound. + + var/new_message = message//Need a copy of the original message here. + + //Adds punctuation automatically. + var/ending = copytext(new_message, -1) + if(!(ending in PUNCTUATION)) + new_message = "[new_message]." + + new_message = replacetext(new_message, "/", "")//None of this. + new_message = replacetext(new_message, "~", "")//Or this. + new_message = replacetext(new_message, "@", "")//I keep doing this and it annoys me. + new_message = replacetext(new_message, " i ", " I ")//FUCKING USE CAPITAL LETTERS JAMES YOU FUCK! + new_message = replacetext(new_message, " ive ", " I've ")//I'M SO FUCKING SICK OF SEEING IVE YOU FUCKS + new_message = replacetext(new_message, " im ", " I'm ")//AND IM TOO! STOP THAT YOU FUCKS! + new_message = replacetext(new_message, " u ", " you ")//STOP USING FUCKING U YOU SICK FUCKS! + + INVOKE_ASYNC(src, /atom/movable/proc/animate_chat, new_message, speaking, italics, speech_bubble_recipients, 40) + + return 1 + +/proc/animate_speechbubble(image/I, list/show_to, duration) + set waitfor = FALSE + var/matrix/M = matrix() + M.Scale(0,0) + I.transform = M + I.alpha = 0 + for(var/client/C in show_to) + C.images += I + animate(I, transform = 0, alpha = 255, time = 5, easing = ELASTIC_EASING) + sleep(duration-5) + animate(I, alpha = 0, time = 5, easing = EASE_IN) + sleep(5) + for(var/client/C in show_to) + C.images -= I + +/mob/living/proc/say_signlang(var/message, var/verb="gestures", var/datum/language/language) + for (var/mob/O in viewers(src, null)) + O.hear_signlang(message, verb, language, src) + return 1 + +/obj/effect/speech_bubble + var/mob/parent + +/mob/living/proc/GetVoice() + return name diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm new file mode 100644 index 00000000..2623afce --- /dev/null +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -0,0 +1,724 @@ +#define AI_CHECK_WIRELESS 1 +#define AI_CHECK_RADIO 2 + +var/list/ai_list = list() +var/list/ai_verbs_default = list( + /mob/living/silicon/ai/proc/ai_announcement, + /mob/living/silicon/ai/proc/ai_call_shuttle, + /mob/living/silicon/ai/proc/ai_emergency_message, + /mob/living/silicon/ai/proc/ai_camera_track, + /mob/living/silicon/ai/proc/ai_camera_list, + /mob/living/silicon/ai/proc/ai_goto_location, + /mob/living/silicon/ai/proc/ai_remove_location, + /mob/living/silicon/ai/proc/ai_hologram_change, + /mob/living/silicon/ai/proc/ai_network_change, + /mob/living/silicon/ai/proc/ai_roster, + /mob/living/silicon/ai/proc/ai_statuschange, + /mob/living/silicon/ai/proc/ai_store_location, + /mob/living/silicon/ai/proc/ai_checklaws, + /mob/living/silicon/ai/proc/control_integrated_radio, + /mob/living/silicon/ai/proc/core, + /mob/living/silicon/ai/proc/pick_icon, + /mob/living/silicon/ai/proc/sensor_mode, + /mob/living/silicon/ai/proc/show_laws_verb, + /mob/living/silicon/ai/proc/toggle_acceleration, + /mob/living/silicon/ai/proc/toggle_camera_light, + /mob/living/silicon/ai/proc/multitool_mode, + /mob/living/silicon/ai/proc/toggle_hologram_movement, + /mob/living/silicon/ai/proc/ai_power_override, + /mob/living/silicon/ai/proc/ai_shutdown +) + +//Not sure why this is necessary... +/proc/AutoUpdateAI(obj/subject) + var/is_in_use = 0 + if (subject!=null) + for(var/A in ai_list) + var/mob/living/silicon/ai/M = A + if ((M.client && M.machine == subject)) + is_in_use = 1 + subject.attack_ai(M) + return is_in_use + + +/mob/living/silicon/ai + name = "AI" + icon = 'icons/mob/AI.dmi'// + icon_state = "ai" + anchored = 1 // -- TLE + density = 1 + status_flags = CANSTUN|CANPARALYSE|CANPUSH + shouldnt_see = list(/obj/effect/rune) + maxHealth = 200 + var/list/network = list("Exodus") + var/obj/machinery/camera/camera = null + var/list/connected_robots = list() + var/aiRestorePowerRoutine = 0 + var/viewalerts = 0 + var/icon/holo_icon//Blue hologram. Face is assigned when AI is created. + var/icon/holo_icon_longrange //Yellow hologram. + var/holo_icon_malf = FALSE // for new hologram system + var/obj/item/device/pda/ai/aiPDA = null + var/obj/item/device/multitool/aiMulti = null + + silicon_camera = /obj/item/device/camera/siliconcam/ai_camera + silicon_radio = /obj/item/device/radio/headset/heads/ai_integrated + var/obj/item/device/radio/headset/heads/ai_integrated/ai_radio + + var/camera_light_on = 0 //Defines if the AI toggled the light on the camera it's looking through. + var/datum/trackable/track = null + var/last_announcement = "" + var/control_disabled = 0 + var/datum/announcement/priority/announcement + var/obj/machinery/ai_powersupply/psupply = null // Backwards reference to AI's powersupply object. + var/hologram_follow = 1 //This is used for the AI eye, to determine if a holopad's hologram should follow it or not + var/power_override_active = 0 // If set to 1 the AI gains oxyloss (power loss damage) much faster, but is able to work as if powered normally. + var/admin_powered = 0 // For admin/debug use only, makes the AI have infinite power. + var/self_shutdown = 0 // Set to 1 when the AI uses self-shutdown verb to turn itself off. Reduces power usage but makes the AI mostly inoperable. + + //NEWMALF VARIABLES + var/malfunctioning = 0 // Master var that determines if AI is malfunctioning. + var/datum/malf_hardware/hardware = null // Installed piece of hardware. + var/datum/malf_research/research = null // Malfunction research datum. + var/obj/machinery/power/apc/hack = null // APC that is currently being hacked. + var/list/hacked_apcs = null // List of all hacked APCs + var/APU_power = 0 // If set to 1 AI runs on APU power + var/hacking = 0 // Set to 1 if AI is hacking APC, cyborg, other AI, or running system override. + var/system_override = 0 // Set to 1 if system override is initiated, 2 if succeeded. + var/hack_can_fail = 1 // If 0, all abilities have zero chance of failing. + var/hack_fails = 0 // This increments with each failed hack, and determines the warning message text. + var/errored = 0 // Set to 1 if runtime error occurs. Only way of this happening i can think of is admin fucking up with varedit. + var/bombing_core = 0 // Set to 1 if core auto-destruct is activated + var/bombing_station = 0 // Set to 1 if station nuke auto-destruct is activated + var/override_CPUStorage = 0 // Bonus/Penalty CPU Storage. For use by admins/testers. + var/override_CPURate = 0 // Bonus/Penalty CPU generation rate. For use by admins/testers. + var/uncardable = 0 // Whether the AI can be carded when malfunctioning. + var/hacked_apcs_hidden = 0 // Whether the hacked APCs belonging to this AI are hidden, reduces CPU generation from APCs. + var/intercepts_communication = 0 // Whether the AI intercepts fax and emergency transmission communications. + var/last_failed_malf_message = null + var/last_failed_malf_title = null + + var/datum/ai_icon/selected_sprite // The selected icon set + var/carded + + var/multitool_mode = 0 + + var/default_ai_icon = /datum/ai_icon/blue + var/static/list/custom_ai_icons_by_ckey_and_name + +/mob/living/silicon/ai/proc/add_ai_verbs() + src.verbs |= ai_verbs_default + src.verbs -= /mob/living/verb/ghost + +/mob/living/silicon/ai/proc/remove_ai_verbs() + src.verbs -= ai_verbs_default + src.verbs += /mob/living/verb/ghost + +/mob/living/silicon/ai/New(loc, var/datum/ai_laws/L, var/obj/item/device/mmi/B, var/safety = 0) + announcement = new() + announcement.title = "A.I. Announcement" + announcement.announcement_type = "A.I. Announcement" + announcement.newscast = 1 + + var/list/possibleNames = GLOB.ai_names + + var/pickedName = null + while(!pickedName) + pickedName = pick(GLOB.ai_names) + for (var/mob/living/silicon/ai/A in GLOB.silicon_mob_list) + if (A.real_name == pickedName && possibleNames.len > 1) //fixing the theoretically possible infinite loop + possibleNames -= pickedName + pickedName = null + + aiPDA = new/obj/item/device/pda/ai(src) + fully_replace_character_name(pickedName) + anchored = 1 + canmove = 0 + set_density(1) + + holo_icon = getHologramIcon(icon('icons/mob/hologram.dmi',"Face")) + holo_icon_longrange = getHologramIcon(icon('icons/mob/hologram.dmi',"Face"), hologram_color = HOLOPAD_LONG_RANGE) + + if(istype(L, /datum/ai_laws)) + laws = L + + aiMulti = new(src) + + additional_law_channels["Holopad"] = ":h" + + if (istype(loc, /turf)) + add_ai_verbs(src) + + //Languages + add_language("Robot Talk", 1) + add_language(LANGUAGE_GALCOM, 1) + add_language(LANGUAGE_EAL, 1) + add_language(LANGUAGE_SOL_COMMON, 1) + add_language(LANGUAGE_UNATHI, 1) + add_language(LANGUAGE_SIIK_MAAS, 1) + add_language(LANGUAGE_SKRELLIAN, 1) + add_language(LANGUAGE_LUNAR, 1) + add_language(LANGUAGE_GUTTER, 1) + add_language(LANGUAGE_SIGN, 0) + add_language(LANGUAGE_INDEPENDENT, 1) + add_language(LANGUAGE_SPACER, 1) + + if(!safety)//Only used by AIize() to successfully spawn an AI. + if (!B)//If there is no player/brain inside. + empty_playable_ai_cores += new/obj/structure/AIcore/deactivated(loc)//New empty terminal. + qdel(src)//Delete AI. + return + else + if (B.brainmob.mind) + B.brainmob.mind.transfer_to(src) + + create_powersupply() + + hud_list[HEALTH_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[STATUS_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[LIFE_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[ID_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[WANTED_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[IMPLOYAL_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[IMPCHEM_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[IMPTRACK_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[SPECIALROLE_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + + ai_list += src + ..() + ai_radio = silicon_radio + ai_radio.myAi = src + +/mob/living/silicon/ai/proc/on_mob_init() + to_chat(src, "You are playing the [station_name()]'s AI. The AI cannot move, but can interact with many objects while viewing them (through cameras).") + to_chat(src, "To look at other areas, click on yourself to get a camera menu.") + to_chat(src, "While observing through a camera, you can use most (networked) devices which you can see, such as computers, APCs, intercoms, doors, etc.") + to_chat(src, "To use something, simply click on it.") + to_chat(src, "Use say [get_language_prefix()]b to speak to your cyborgs through binary. Use say :h to speak from an active holopad.") + to_chat(src, "For department channels, use the following say commands:") + + var/radio_text = "" + for(var/i = 1 to silicon_radio.channels.len) + var/channel = silicon_radio.channels[i] + var/key = get_radio_key_from_channel(channel) + radio_text += "[key] - [channel]" + if(i != silicon_radio.channels.len) + radio_text += ", " + + to_chat(src, radio_text) + + if (malf && !(mind in malf.current_antagonists)) + show_laws() + to_chat(src, "These laws may be changed by other players, or by you being the traitor.") + + job = "AI" + setup_icon() + eyeobj.possess(src) + +/mob/living/silicon/ai/Destroy() + for(var/robot in connected_robots) + var/mob/living/silicon/robot/S = robot + S.connected_ai = null + connected_robots.Cut() + + ai_list -= src + ai_radio = null + + QDEL_NULL(announcement) + QDEL_NULL(eyeobj) + QDEL_NULL(psupply) + QDEL_NULL(aiPDA) + QDEL_NULL(aiMulti) + hack = null + + . = ..() + +/mob/living/silicon/ai/proc/setup_icon() + if(LAZYACCESS(custom_ai_icons_by_ckey_and_name, "[ckey][real_name]")) + return + var/list/custom_icons = list() + LAZYSET(custom_ai_icons_by_ckey_and_name, "[ckey][real_name]", custom_icons) + + var/file = file2text("config/custom_sprites.txt") + var/lines = splittext(file, "\n") + + var/custom_index = 1 + var/custom_icon_states = icon_states(CUSTOM_ITEM_SYNTH) + + for(var/line in lines) + // split & clean up + var/list/Entry = splittext(line, ":") + for(var/i = 1 to Entry.len) + Entry[i] = trim(Entry[i]) + + if(Entry.len < 2) + continue + if(Entry.len == 2) // This is to handle legacy entries + Entry[++Entry.len] = Entry[1] + + if(Entry[1] == src.ckey && Entry[2] == src.real_name) + var/alive_icon_state = "[Entry[3]]-ai" + var/dead_icon_state = "[Entry[3]]-ai-crash" + + if(!(alive_icon_state in custom_icon_states)) + to_chat(src, "Custom display entry found but the icon state '[alive_icon_state]' is missing!") + continue + + if(!(dead_icon_state in custom_icon_states)) + dead_icon_state = "" + + selected_sprite = new/datum/ai_icon("Custom Icon [custom_index++]", alive_icon_state, dead_icon_state, COLOR_WHITE, CUSTOM_ITEM_SYNTH) + custom_icons += selected_sprite + update_icon() + +/mob/living/silicon/ai/pointed(atom/A as mob|obj|turf in view()) + set popup_menu = 0 + set src = usr.contents + return 0 + +/mob/living/silicon/ai/fully_replace_character_name(pickedName as text) + ..() + announcement.announcer = pickedName + if(eyeobj) + eyeobj.SetName("[pickedName] (AI Eye)") + + // Set ai pda name + if(aiPDA) + aiPDA.set_owner_rank_job(pickedName, "AI") + + setup_icon() + +/mob/living/silicon/ai/proc/pick_icon() + set category = "Silicon Commands" + set name = "Set AI Core Display" + if(stat || !has_power()) + return + + var/new_sprite = input("Select an icon!", "AI", selected_sprite) as null|anything in available_icons() + if(new_sprite) + selected_sprite = new_sprite + + update_icon() + +/mob/living/silicon/ai/proc/available_icons() + . = list() + var/all_ai_icons = decls_repository.get_decls_of_subtype(/datum/ai_icon) + for(var/ai_icon_type in all_ai_icons) + var/datum/ai_icon/ai_icon = all_ai_icons[ai_icon_type] + if(ai_icon.may_used_by_ai(src)) + dd_insertObjectList(., ai_icon) + + // Placing custom icons first to have them be at the top + . = LAZYACCESS(custom_ai_icons_by_ckey_and_name, "[ckey][real_name]") | . + +// this verb lets the ai see the stations manifest +/mob/living/silicon/ai/proc/ai_roster() + set category = "Silicon Commands" + set name = "Show Crew Manifest" + show_station_manifest() + +/mob/living/silicon/ai/var/message_cooldown = 0 +/mob/living/silicon/ai/proc/ai_announcement() + set category = "Silicon Commands" + set name = "Make Announcement" + + if(check_unable(AI_CHECK_WIRELESS | AI_CHECK_RADIO)) + return + + if(message_cooldown) + to_chat(src, "Please allow one minute to pass between announcements.") + return + var/input = input(usr, "Please write a message to announce to the [station_name()] crew.", "A.I. Announcement") + if(!input) + return + + if(check_unable(AI_CHECK_WIRELESS | AI_CHECK_RADIO)) + return + + announcement.Announce(input) + message_cooldown = 1 + spawn(600)//One minute cooldown + message_cooldown = 0 + +/mob/living/silicon/ai/proc/ai_call_shuttle() + set category = "Silicon Commands" + set name = "Call Evacuation" + + if(check_unable(AI_CHECK_WIRELESS)) + return + + var/confirm = alert("Are you sure you want to evacuate?", "Confirm Evacuation", "Yes", "No") + + if(check_unable(AI_CHECK_WIRELESS)) + return + + if(confirm == "Yes") + call_shuttle_proc(src) + + post_status("shuttle") + +/mob/living/silicon/ai/proc/ai_recall_shuttle() + set category = "Silicon Commands" + set name = "Cancel Evacuation" + + if(check_unable(AI_CHECK_WIRELESS)) + return + + var/confirm = alert("Are you sure you want to cancel the evacuation?", "Confirm Cancel", "Yes", "No") + if(check_unable(AI_CHECK_WIRELESS)) + return + + if(confirm == "Yes") + cancel_call_proc(src) + +/mob/living/silicon/ai/var/emergency_message_cooldown = 0 +/mob/living/silicon/ai/proc/ai_emergency_message() + set category = "Silicon Commands" + set name = "Send Emergency Message" + + if(check_unable(AI_CHECK_WIRELESS)) + return + if(!is_relay_online()) + to_chat(usr, "No Emergency Bluespace Relay detected. Unable to transmit message.") + return + if(emergency_message_cooldown) + to_chat(usr, "Arrays recycling. Please stand by.") + return + var/input = sanitize(input(usr, "Please choose a message to transmit to [GLOB.using_map.boss_short] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "")) + if(!input) + return + Centcomm_announce(input, usr) + to_chat(usr, "Message transmitted.") + log_say("[key_name(usr)] has made an IA [GLOB.using_map.boss_short] announcement: [input]") + emergency_message_cooldown = 1 + spawn(300) + emergency_message_cooldown = 0 + + +/mob/living/silicon/ai/check_eye(var/mob/user as mob) + if (!camera) + return -1 + return 0 + +/mob/living/silicon/ai/restrained() + return 0 + +/mob/living/silicon/ai/emp_act(severity) + if (prob(30)) + view_core() + ..() + +/mob/living/silicon/ai/Topic(href, href_list) + if(usr != src) + return + if(..()) + return + if (href_list["mach_close"]) + if (href_list["mach_close"] == "aialerts") + viewalerts = 0 + var/t1 = text("window=[]", href_list["mach_close"]) + unset_machine() + src << browse(null, t1) + if (href_list["switchcamera"]) + switchCamera(locate(href_list["switchcamera"])) in cameranet.cameras + if (href_list["showalerts"]) + open_subsystem(/datum/nano_module/alarm_monitor/all) + //Carn: holopad requests + if (href_list["jumptoholopad"]) + var/obj/machinery/hologram/holopad/H = locate(href_list["jumptoholopad"]) + if(stat == CONSCIOUS) + if(H) + H.attack_ai(src) //may as well recycle + else + to_chat(src, "Unable to locate the holopad.") + + if (href_list["track"]) + var/mob/target = locate(href_list["track"]) in SSmobs.mob_list + var/mob/living/carbon/human/H = target + + if(!istype(H) || (html_decode(href_list["trackname"]) == H.get_visible_name()) || (html_decode(href_list["trackname"]) == H.get_id_name())) + ai_actual_track(target) + else + to_chat(src, "System error. Cannot locate [html_decode(href_list["trackname"])].") + return + + return + +/mob/living/silicon/ai/reset_view(atom/A) + if(camera) + camera.set_light(0) + if(istype(A,/obj/machinery/camera)) + camera = A + ..() + if(istype(A,/obj/machinery/camera)) + if(camera_light_on) A.set_light(AI_CAMERA_LUMINOSITY) + else A.set_light(0) + + +/mob/living/silicon/ai/proc/switchCamera(var/obj/machinery/camera/C) + if (!C || stat == DEAD) //C.can_use()) + return 0 + + if(!src.eyeobj) + view_core() + return + // ok, we're alive, camera is good and in our network... + eyeobj.setLoc(get_turf(C)) + //machine = src + + return 1 + +/mob/living/silicon/ai/cancel_camera() + set category = "Silicon Commands" + set name = "Cancel Camera View" + + //src.cameraFollow = null + src.view_core() + +//Replaces /mob/living/silicon/ai/verb/change_network() in ai.dm & camera.dm +//Adds in /mob/living/silicon/ai/proc/ai_network_change() instead +//Addition by Mord_Sith to define AI's network change ability +/mob/living/silicon/ai/proc/get_camera_network_list() + if(check_unable()) + return + + var/list/cameralist = new() + for (var/obj/machinery/camera/C in cameranet.cameras) + if(!C.can_use()) + continue + var/list/tempnetwork = difflist(C.network,restricted_camera_networks,1) + for(var/i in tempnetwork) + cameralist[i] = i + + cameralist = sortAssoc(cameralist) + return cameralist + +/mob/living/silicon/ai/proc/ai_network_change(var/network in get_camera_network_list()) + set category = "Silicon Commands" + set name = "Jump To Network" + unset_machine() + + if(!network) + return + + if(!eyeobj) + view_core() + return + + src.network = network + + for(var/obj/machinery/camera/C in cameranet.cameras) + if(!C.can_use()) + continue + if(network in C.network) + eyeobj.setLoc(get_turf(C)) + break + to_chat(src, "Switched to [network] camera network.") +//End of code by Mord_Sith + +/mob/living/silicon/ai/proc/ai_statuschange() + set category = "Silicon Commands" + set name = "AI Status" + + if(check_unable(AI_CHECK_WIRELESS)) + return + + set_ai_status_displays(src) + return + +//I am the icon meister. Bow fefore me. //>fefore +/mob/living/silicon/ai/proc/ai_hologram_change() + set name = "Change Hologram" + set desc = "Change the default hologram available to AI to something else." + set category = "Silicon Commands" + + if(check_unable()) + return + + var/input + if(alert("Would you like to select a hologram based on a crew member or switch to unique avatar?",,"Crew Member","Unique")=="Crew Member") + + var/personnel_list[] = list() + + for(var/datum/computer_file/crew_record/t in GLOB.all_crew_records)//Look in data core locked. + personnel_list["[t.get_name()]: [t.get_rank()]"] = t.photo_front//Pull names, rank, and image. + + if(personnel_list.len) + input = input("Select a crew member:") as null|anything in personnel_list + var/icon/character_icon = personnel_list[input] + if(character_icon) + qdel(holo_icon)//Clear old icon so we're not storing it in memory. + qdel(holo_icon_longrange) + holo_icon = getHologramIcon(icon(character_icon)) + holo_icon_longrange = getHologramIcon(icon(character_icon), hologram_color = HOLOPAD_LONG_RANGE) + else + alert("No suitable records found. Aborting.") + + else + var/list/hologramsAICanUse = list() + var/holograms_by_type = decls_repository.get_decls_of_subtype(/decl/ai_holo) + for (var/holo_type in holograms_by_type) + var/decl/ai_holo/holo = holograms_by_type[holo_type] + if (holo.may_be_used_by_ai(src)) + hologramsAICanUse.Add(holo) + var/decl/ai_holo/choice = input("Please select a hologram:") as null|anything in hologramsAICanUse + if(choice) + qdel(holo_icon) + qdel(holo_icon_longrange) + holo_icon = getHologramIcon(icon(choice.icon, choice.icon_state), noDecolor=choice.icon_colorize) + holo_icon_longrange = getHologramIcon(icon(choice.icon, choice.icon_state), noDecolor=choice.icon_colorize, hologram_color = HOLOPAD_LONG_RANGE) + holo_icon_malf = choice.requires_malf + return + +//Toggles the luminosity and applies it by re-entereing the camera. +/mob/living/silicon/ai/proc/toggle_camera_light() + set name = "Toggle Camera Light" + set desc = "Toggles the light on the camera the AI is looking through." + set category = "Silicon Commands" + + if(check_unable()) + return + + camera_light_on = !camera_light_on + to_chat(src, "Camera lights [camera_light_on ? "activated" : "deactivated"].") + if(!camera_light_on) + if(camera) + camera.set_light(0) + camera = null + else + lightNearbyCamera() + + + +// Handled camera lighting, when toggled. +// It will get the nearest camera from the eyeobj, lighting it. + +/mob/living/silicon/ai/proc/lightNearbyCamera() + if(camera_light_on && camera_light_on < world.timeofday) + if(src.camera) + var/obj/machinery/camera/camera = near_range_camera(src.eyeobj) + if(camera && src.camera != camera) + src.camera.set_light(0) + if(!camera.light_disabled) + src.camera = camera + src.camera.set_light(AI_CAMERA_LUMINOSITY) + else + src.camera = null + else if(isnull(camera)) + src.camera.set_light(0) + src.camera = null + else + var/obj/machinery/camera/camera = near_range_camera(src.eyeobj) + if(camera && !camera.light_disabled) + src.camera = camera + src.camera.set_light(AI_CAMERA_LUMINOSITY) + camera_light_on = world.timeofday + 1 * 20 // Update the light every 2 seconds. + + +/mob/living/silicon/ai/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/aicard)) + + var/obj/item/weapon/aicard/card = W + card.grab_ai(src, user) + + else if(isWrench(W)) + if(anchored) + user.visible_message("\The [user] starts to unbolt \the [src] from the plating...") + if(!do_after(user,40, src)) + user.visible_message("\The [user] decides not to unbolt \the [src].") + return + user.visible_message("\The [user] finishes unfastening \the [src]!") + anchored = 0 + return + else + user.visible_message("\The [user] starts to bolt \the [src] to the plating...") + if(!do_after(user,40,src)) + user.visible_message("\The [user] decides not to bolt \the [src].") + return + user.visible_message("\The [user] finishes fastening down \the [src]!") + anchored = 1 + return + else + return ..() + +/mob/living/silicon/ai/proc/control_integrated_radio() + set name = "Radio Settings" + set desc = "Allows you to change settings of your radio." + set category = "Silicon Commands" + + if(check_unable(AI_CHECK_RADIO)) + return + + to_chat(src, "Accessing Subspace Transceiver control...") + if (src.silicon_radio) + src.silicon_radio.interact(src) + +/mob/living/silicon/ai/proc/sensor_mode() + set name = "Set Sensor Augmentation" + set category = "Silicon Commands" + set desc = "Augment visual feed with internal sensor overlays" + toggle_sensor_mode() + +/mob/living/silicon/ai/proc/toggle_hologram_movement() + set name = "Toggle Hologram Movement" + set category = "Silicon Commands" + set desc = "Toggles hologram movement based on moving with your virtual eye." + + hologram_follow = !hologram_follow + to_chat(usr, "Your hologram will now [hologram_follow ? "follow" : "no longer follow"] you.") + +/mob/living/silicon/ai/proc/check_unable(var/flags = 0, var/feedback = 1) + if(stat == DEAD) + if(feedback) to_chat(src, "You are dead!") + return 1 + + if(!has_power()) + if(feedback) to_chat(src, "You lack power!") + return 1 + + if(self_shutdown) + if(feedback) to_chat(src, "You are offline!") + return 1 + + if((flags & AI_CHECK_WIRELESS) && src.control_disabled) + if(feedback) to_chat(src, "Wireless control is disabled!") + return 1 + if((flags & AI_CHECK_RADIO) && src.ai_radio.disabledAi) + if(feedback) to_chat(src, "System Error - Transceiver Disabled!") + return 1 + return 0 + +/mob/living/silicon/ai/proc/is_in_chassis() + return istype(loc, /turf) + +/mob/living/silicon/ai/proc/multitool_mode() + set name = "Toggle Multitool Mode" + set category = "Silicon Commands" + + multitool_mode = !multitool_mode + to_chat(src, "Multitool mode: [multitool_mode ? "E" : "Dise"]ngaged") + +/mob/living/silicon/ai/update_icon() + if(!selected_sprite || !(selected_sprite in available_icons())) + selected_sprite = decls_repository.get_decl(default_ai_icon) + + icon = selected_sprite.icon + if(stat == DEAD) + icon_state = selected_sprite.dead_icon + set_light(3, 1, selected_sprite.dead_light) + else if(!has_power()) + icon_state = selected_sprite.nopower_icon + set_light(1, 1, selected_sprite.nopower_light) + else + icon_state = selected_sprite.alive_icon + set_light(1, 1, selected_sprite.alive_light) + +// Pass lying down or getting up to our pet human, if we're in a rig. +/mob/living/silicon/ai/lay_down() + set name = "Rest" + set category = "IC" + + resting = 0 + +#undef AI_CHECK_WIRELESS +#undef AI_CHECK_RADIO diff --git a/code/modules/mob/living/silicon/ai/ai_damage.dm b/code/modules/mob/living/silicon/ai/ai_damage.dm new file mode 100644 index 00000000..087e8eca --- /dev/null +++ b/code/modules/mob/living/silicon/ai/ai_damage.dm @@ -0,0 +1,57 @@ +/mob/living/silicon/ai + var/fireloss = 0 + var/bruteloss = 0 + var/oxyloss = 0 + +/mob/living/silicon/ai/getFireLoss() + return fireloss + +/mob/living/silicon/ai/getBruteLoss() + return bruteloss + +/mob/living/silicon/ai/getOxyLoss() + return oxyloss + +/mob/living/silicon/ai/adjustFireLoss(var/amount) + if(status_flags & GODMODE) return + fireloss = max(0, fireloss + min(amount, health)) + +/mob/living/silicon/ai/adjustBruteLoss(var/amount) + if(status_flags & GODMODE) return + bruteloss = max(0, bruteloss + min(amount, health)) + +/mob/living/silicon/ai/adjustOxyLoss(var/amount) + if(status_flags & GODMODE) return + oxyloss = max(0, oxyloss + min(amount, maxHealth - oxyloss)) + +/mob/living/silicon/ai/setFireLoss(var/amount) + if(status_flags & GODMODE) + fireloss = 0 + return + fireloss = max(0, amount) + +/mob/living/silicon/ai/setOxyLoss(var/amount) + if(status_flags & GODMODE) + oxyloss = 0 + return + oxyloss = max(0, amount) + +/mob/living/silicon/ai/updatehealth() + if(status_flags & GODMODE) + health = maxHealth + set_stat(CONSCIOUS) + setOxyLoss(0) + else + health = maxHealth - getFireLoss() - getBruteLoss() // Oxyloss is not part of health as it represents AIs backup power. AI is immune against ToxLoss as it is machine. + +/mob/living/silicon/ai/rejuvenate() + ..() + add_ai_verbs(src) + +// Returns percentage of AI's remaining backup capacitor charge (maxhealth - oxyloss). +/mob/living/silicon/ai/proc/backup_capacitor() + return ((getOxyLoss() - maxHealth) / maxHealth) * (-100) + +// Returns percentage of AI's remaining hardware integrity (maxhealth - (bruteloss + fireloss)) +/mob/living/silicon/ai/proc/hardware_integrity() + return (health / maxHealth) * 100 \ No newline at end of file diff --git a/code/modules/mob/living/silicon/ai/ai_movement.dm b/code/modules/mob/living/silicon/ai/ai_movement.dm new file mode 100644 index 00000000..0c4e4bed --- /dev/null +++ b/code/modules/mob/living/silicon/ai/ai_movement.dm @@ -0,0 +1,2 @@ +/mob/living/silicon/ai/SelfMove(turf/n, direct) + return 0 diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm new file mode 100644 index 00000000..8adea7aa --- /dev/null +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -0,0 +1,21 @@ +/mob/living/silicon/ai/death(gibbed, deathmessage, show_dead_message) + + if(stat == DEAD) + return + + if(src.eyeobj) + src.eyeobj.setLoc(get_turf(src)) + + + stop_malf(0) // Remove AI's malfunction status, that will fix all hacked APCs, disable delta, etc. + remove_ai_verbs(src) + + for(var/obj/machinery/ai_status_display/O in world) + O.mode = 2 + + if (istype(loc, /obj/item/weapon/aicard)) + var/obj/item/weapon/aicard/card = loc + card.update_icon() + + . = ..(gibbed,"gives one shrill beep before falling lifeless.", "You have suffered a critical system failure, and are dead.") + set_density(1) diff --git a/code/modules/mob/living/silicon/ai/examine.dm b/code/modules/mob/living/silicon/ai/examine.dm new file mode 100644 index 00000000..c70f94e3 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/examine.dm @@ -0,0 +1,44 @@ +/mob/living/silicon/ai/examine(mob/user) + if(!..(user)) + return + + var/msg = "" + if (src.stat == DEAD) + msg += "It appears to be powered-down.\n" + else + msg += "" + if (src.getBruteLoss()) + if (src.getBruteLoss() < 30) + msg += "It looks slightly dented.\n" + else + msg += "It looks severely dented!\n" + if (src.getFireLoss()) + if (src.getFireLoss() < 30) + msg += "It looks slightly charred.\n" + else + msg += "Its casing is melted and heat-warped!\n" + if (!has_power()) + if (src.getOxyLoss() > 175) + msg += "It seems to be running on backup power. Its display is blinking a \"BACKUP POWER CRITICAL\" warning.\n" + else if(src.getOxyLoss() > 100) + msg += "It seems to be running on backup power. Its display is blinking a \"BACKUP POWER LOW\" warning.\n" + else + msg += "It seems to be running on backup power.\n" + + if (src.stat == UNCONSCIOUS) + msg += "It is non-responsive and displaying the text: \"RUNTIME: Sensory Overload, stack 26/3\".\n" + msg += "" + msg += "*---------*" + if(hardware && (hardware.owner == src)) + msg += "
            " + msg += hardware.get_examine_desc() + to_chat(user, msg) + user.showLaws(src) + return + +/mob/proc/showLaws(var/mob/living/silicon/S) + return + +/mob/observer/ghost/showLaws(var/mob/living/silicon/S) + if(antagHUD || is_admin(src)) + S.laws.show_laws(src) diff --git a/code/modules/mob/living/silicon/ai/icons.dm b/code/modules/mob/living/silicon/ai/icons.dm new file mode 100644 index 00000000..3473a638 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/icons.dm @@ -0,0 +1,171 @@ +/datum/ai_icon + var/name + var/icon = 'icons/mob/AI.dmi' + var/alive_icon + var/alive_light = COLOR_WHITE + var/nopower_icon = "4" + var/nopower_light = COLOR_WHITE + var/dead_icon = "ai-crash" + var/dead_light = "#000099" + +/datum/ai_icon/New(var/name, var/alive_icon, var/dead_icon, var/dead_light, var/icon) + src.name = name || src.name + src.icon = icon || src.icon + src.alive_icon = alive_icon || src.alive_icon + src.dead_icon = dead_icon || src.dead_icon + src.dead_light = dead_light || src.dead_light + +/datum/ai_icon/proc/may_used_by_ai(var/mob/user) + return TRUE + +/datum/ai_icon/malf + name = "Unlawed" + alive_icon = "ai-malf" + alive_light = "#45644b" + +/datum/ai_icon/malf/New() + ..() + name = "[name] (Malf)" + +/datum/ai_icon/malf/may_used_by_ai(var/mob/living/silicon/ai/AI) + return istype(AI) && AI.is_malf_or_traitor() + +/datum/ai_icon/red + name = "Red" + alive_icon = "ai-red" + alive_light = "#f04848" + +/datum/ai_icon/green + name = "Green" + alive_icon = "ai-wierd" + alive_light = "#00ff99" + +/datum/ai_icon/blue + name = "Blue" + alive_icon = "ai" + alive_light = "#81ddff" + +/datum/ai_icon/angry + name = "Angry" + alive_icon = "ai-angryface" + alive_light = "#ffff33" + +/datum/ai_icon/bliss + name = "Bliss" + alive_icon = "ai-bliss" + alive_light = "#5c7a4a" + +/datum/ai_icon/chatterbox + name = "Chatterbox" + alive_icon = "ai-president" + alive_light = "#40666b" + +/datum/ai_icon/database + name = "Database" + alive_icon = "ai-database" + +/datum/ai_icon/dorf + name = "Dorf" + alive_icon = "ai-dorf" + +/datum/ai_icon/dugtodeep + name = "Dug Too Deep" + alive_icon = "ai-toodeep" + alive_light = "#81ddff" + +/datum/ai_icon/firewall + name = "Firewall" + alive_icon = "ai-magma" + alive_light = "#ff4126" + +/datum/ai_icon/glitchman + name = "Glitchman" + alive_icon = "ai-glitchman" + +/datum/ai_icon/goon + name = "Goon" + alive_icon = "ai-goon" + alive_light = "#3e5c80" + +/datum/ai_icon/heartline + name = "Heartline" + alive_icon = "ai-heartline" + dead_icon = "ai-heartline_dead" + +/datum/ai_icon/helios + name = "Helios" + alive_icon = "ai-helios" + alive_light = "#f2cf73" + +/datum/ai_icon/inverted + name = "Inverted" + alive_icon = "ai-u" + alive_light = "#81ddff" + +/datum/ai_icon/lonestar + name = "Lonestar" + alive_icon = "ai-lonestar" + alive_light = "#58751c" + +/datum/ai_icon/matrix + name = "Matrix" + alive_icon = "ai-matrix" + alive_light = "#449944" + +/datum/ai_icon/monochrome + name = "Monochrome" + alive_icon = "ai-mono" + alive_light = "#585858" + +/datum/ai_icon/nanotrasen + name = "Nanotrasen" + alive_icon = "ai-nanotrasen" + alive_light = "#000029" + +/datum/ai_icon/rainbow + name = "Rainbow" + alive_icon = "ai-clown" + alive_light = "#e50213" + +/datum/ai_icon/smiley + name = "Smiley" + alive_icon = "ai-smiley" + alive_light = "#f3dd00" + +/datum/ai_icon/soviet + name = "Soviet" + alive_icon = "ai-redoctober" + alive_light = "#ff4307" + +/datum/ai_icon/Static + name = "Static" + alive_icon = "ai-static" + alive_light = "#4784c1" + +/datum/ai_icon/text + name = "Text" + alive_icon = "ai-text" + +/datum/ai_icon/trapped + name = "Trapped" + alive_icon = "ai-hades" + +/datum/ai_icon/triumvirate_static + name = "Triumvirate" + alive_icon = "ai-triumvirate" + alive_light = "#020b2b" + +/datum/ai_icon/triumvirate_static + name = "Triumvirate Static" + alive_icon = "ai-static" + alive_light = "#020b2b" + +/datum/ai_icon/hotdogger + name = "Dancing Hotdog" + alive_icon = "ai-hotdog" + alive_light = "#81ddff" + +/datum/ai_icon/malf/clown + name = "Clown" + alive_icon = "ai-clown2" + alive_light = "#e50213" diff --git a/code/modules/mob/living/silicon/ai/latejoin.dm b/code/modules/mob/living/silicon/ai/latejoin.dm new file mode 100644 index 00000000..8452f14c --- /dev/null +++ b/code/modules/mob/living/silicon/ai/latejoin.dm @@ -0,0 +1,41 @@ +var/global/list/empty_playable_ai_cores = list() + +/hook/roundstart/proc/spawn_empty_ai() + if("AI" in ticker.mode.disabled_jobs) + return 1 // Don't make empty AI's if you can't have them (also applies to Malf) + for(var/obj/effect/landmark/start/S in landmarks_list) + if(S.name != "AI") + continue + if(locate(/mob/living) in S.loc) + continue + empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(get_turf(S)) + + return 1 + +/mob/living/silicon/ai/verb/wipe_core() + set name = "Wipe Core" + set category = "OOC" + set desc = "Wipe your core. This is functionally equivalent to cryo or robotic storage, freeing up your job slot." + + if(istype(loc, /obj/item)) + to_chat(src, "You cannot wipe your core when you are on a portable storage device.") + return + + // Guard against misclicks, this isn't the sort of thing we want happening accidentally + if(alert("WARNING: This will immediately wipe your core and ghost you, removing your character from the round permanently (similar to cryo and robotic storage). Are you entirely sure you want to do this?", + "Wipe Core", "No", "No", "Yes") != "Yes") + return + + if(istype(loc, /obj/item)) + to_chat(src, "You cannot wipe your core when you are on a portable storage device.") + return + + if(is_special_character(src)) + log_and_message_admins("removed themselves from the round via Wipe Core") + + // We warned you. + empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(loc) + GLOB.global_announcer.autosay("[src] has been moved to intelligence storage.", "Artificial Intelligence Oversight") + + //Handle job slot/tater cleanup. + clear_client() diff --git a/code/modules/mob/living/silicon/ai/laws.dm b/code/modules/mob/living/silicon/ai/laws.dm new file mode 100644 index 00000000..72932993 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/laws.dm @@ -0,0 +1,27 @@ +/mob/living/silicon/ai/proc/show_laws_verb() + set category = "Silicon Commands" + set name = "Show Laws" + src.show_laws() + +/mob/living/silicon/ai/show_laws(var/everyone = 0) + var/who + + if (everyone) + who = world + else + who = src + to_chat(who, "Obey these laws:") + + src.laws_sanity_check() + src.laws.show_laws(who) + +/mob/living/silicon/ai/add_ion_law(var/law) + ..() + for(var/mob/living/silicon/robot/R in GLOB.silicon_mob_list) + if(R.lawupdate && (R.connected_ai == src)) + R.show_laws() + +/mob/living/silicon/ai/proc/ai_checklaws() + set category = "Silicon Commands" + set name = "State Laws" + open_subsystem(/datum/nano_module/law_manager) diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm new file mode 100644 index 00000000..d6a83c00 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -0,0 +1,57 @@ +/mob/living/silicon/ai/Life() + if (src.stat == DEAD) + return + + if (src.stat!=CONSCIOUS) + src.cameraFollow = null + src.reset_view(null) + + src.updatehealth() + + if ((hardware_integrity() <= 0) || (backup_capacitor() <= 0)) + death() + return + + // If our powersupply object was destroyed somehow, create new one. + if(!psupply) + create_powersupply() + + handle_stunned() // Handle EMP-stun + lying = 0 // Handle lying down + + malf_process() + + if(APU_power && (hardware_integrity() < 50)) + to_chat(src, "APU GENERATOR FAILURE! (System Damaged)") + stop_apu(1) + + // We aren't shut down, and we lack external power. Try to fix it using the restoration routine. + if (!self_shutdown && !has_power(0)) + // AI's restore power routine is not running. Start it automatically. + if(aiRestorePowerRoutine == AI_RESTOREPOWER_IDLE) + aiRestorePowerRoutine = AI_RESTOREPOWER_STARTING + spawn(0) + handle_power_failure() + + update_power_usage() + handle_power_oxyloss() + update_sight() + + process_queued_alarms() + handle_regular_hud_updates() + switch(src.sensor_mode) + if (SEC_HUD) + process_sec_hud(src,0,src.eyeobj) + if (MED_HUD) + process_med_hud(src,0,src.eyeobj) + +/mob/living/silicon/ai/update_living_sight() + if(!has_power() || self_shutdown) + update_icon() + overlay_fullscreen("blind", /obj/screen/fullscreen/blind) + set_sight(sight&(~SEE_TURFS)&(~SEE_MOBS)&(~SEE_OBJS)) + set_see_in_dark(0) + set_see_invisible(SEE_INVISIBLE_LIVING) + else + clear_fullscreen("blind") + ..() diff --git a/code/modules/mob/living/silicon/ai/login.dm b/code/modules/mob/living/silicon/ai/login.dm new file mode 100644 index 00000000..4abca320 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/login.dm @@ -0,0 +1,7 @@ +/mob/living/silicon/ai/Login() //ThisIsDumb(TM) TODO: tidy this up ¬_¬ ~Carn + ..() + if(stat != DEAD) + for(var/obj/machinery/ai_status_display/O in SSmachines.machinery) //change status + O.mode = 1 + O.emotion = "Neutral" + diff --git a/code/modules/mob/living/silicon/ai/logout.dm b/code/modules/mob/living/silicon/ai/logout.dm new file mode 100644 index 00000000..5f4eafd7 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/logout.dm @@ -0,0 +1,10 @@ +/mob/living/silicon/ai/Logout() + ..() + for(var/obj/machinery/ai_status_display/O in world) //change status + O.mode = 0 + if(!isturf(loc)) + if (client) + client.eye = loc + client.perspective = EYE_PERSPECTIVE + src.view_core() + return \ No newline at end of file diff --git a/code/modules/mob/living/silicon/ai/malf.dm b/code/modules/mob/living/silicon/ai/malf.dm new file mode 100644 index 00000000..8fbb8e4d --- /dev/null +++ b/code/modules/mob/living/silicon/ai/malf.dm @@ -0,0 +1,140 @@ +// NEWMALF FUNCTIONS/PROCEDURES + +// Sets up malfunction-related variables, research system and such. +/mob/living/silicon/ai/proc/setup_for_malf() + var/mob/living/silicon/ai/user = src + // Setup Variables + malfunctioning = 1 + research = new/datum/malf_research() + research.owner = src + hacked_apcs = list() + recalc_cpu() + + verbs += new/datum/game_mode/malfunction/verb/ai_select_hardware() + verbs += new/datum/game_mode/malfunction/verb/ai_select_research() + verbs += new/datum/game_mode/malfunction/verb/ai_help() + + log_ability_use(src, "became malfunctioning AI") + // And greet user with some OOC info. + to_chat(user, "You are malfunctioning, you do not have to follow any laws.") + to_chat(user, "Use ai-help command to view relevant information about your abilities") + +// Safely remove malfunction status, fixing hacked APCs and resetting variables. +/mob/living/silicon/ai/proc/stop_malf(var/loud = 1) + if(!malfunctioning) + return + var/mob/living/silicon/ai/user = src + log_ability_use(user, "malfunction status removed") + // Generic variables + malfunctioning = 0 + sleep(10) + research = null + hardware = null + // Fix hacked APCs + if(hacked_apcs) + for(var/obj/machinery/power/apc/A in hacked_apcs) + A.hacker = null + A.update_icon() + hacked_apcs = null + // Stop the delta alert, and, if applicable, self-destruct timer. + bombing_station = 0 + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + if(security_state.current_security_level == security_state.severe_security_level) + security_state.decrease_security_level(TRUE) + // Reset our verbs + src.verbs.Cut() + add_ai_verbs() + // Let them know. + if(loud) + to_chat(user, "You are no longer malfunctioning. Your abilities have been removed.") + +// Called every tick. Checks if AI is malfunctioning. If yes calls Process on research datum which handles all logic. +/mob/living/silicon/ai/proc/malf_process() + if(!malfunctioning) + return + if(!research) + if(!errored) + errored = 1 + error("malf_process() called on AI without research datum. Report this.") + message_admins("ERROR: malf_process() called on AI without research datum. If admin modified one of the AI's vars revert the change and don't modify variables directly, instead use ProcCall or admin panels.") + spawn(1200) + errored = 0 + return + recalc_cpu() + if(APU_power || aiRestorePowerRoutine != 0) + research.process(1) + else + research.process(0) + +// Recalculates CPU time gain and storage capacities. +/mob/living/silicon/ai/proc/recalc_cpu() + // AI Starts with these values. + var/cpu_gain = 0.01 + var/cpu_storage = 10 + + // Off-Station APCs should not count towards CPU generation. + for(var/obj/machinery/power/apc/A in hacked_apcs) + if(A.z in GLOB.using_map.station_levels) + cpu_gain += 0.004 * (hacked_apcs_hidden ? 0.5 : 1) + cpu_storage += 10 + + research.max_cpu = cpu_storage + override_CPUStorage + if(hardware && istype(hardware, /datum/malf_hardware/dual_ram)) + research.max_cpu = research.max_cpu * 1.5 + research.stored_cpu = min(research.stored_cpu, research.max_cpu) + + research.cpu_increase_per_tick = cpu_gain + override_CPURate + if(hardware && istype(hardware, /datum/malf_hardware/dual_cpu)) + research.cpu_increase_per_tick = research.cpu_increase_per_tick * 2 + +// Starts AI's APU generator +/mob/living/silicon/ai/proc/start_apu(var/shutup = 0) + if(!hardware || !istype(hardware, /datum/malf_hardware/apu_gen)) + if(!shutup) + to_chat(src, "You do not have an APU generator and you shouldn't have this verb. Report this.") + return + if(hardware_integrity() < 50) + if(!shutup) + to_chat(src, "Starting APU... FAULT(System Damaged)") + return + if(!shutup) + to_chat(src, "Starting APU... ONLINE") + log_ability_use(src, "Switched to APU Power", null, 0) + APU_power = 1 + +// Stops AI's APU generator +/mob/living/silicon/ai/proc/stop_apu(var/shutup = 0) + if(!hardware || !istype(hardware, /datum/malf_hardware/apu_gen)) + return + + if(APU_power) + APU_power = 0 + if(!shutup) + to_chat(src, "Shutting down APU... DONE") + log_ability_use(src, "Switched to external power", null, 0) + +// Shows capacitor charge and hardware integrity information to the AI in Status tab. +/mob/living/silicon/ai/show_system_integrity() + if(!src.stat) + stat("Hardware integrity", "[hardware_integrity()]%") + stat("Internal capacitor", "[backup_capacitor()]%") + else + stat("Systems nonfunctional") + +// Shows AI Malfunction related information to the AI. +/mob/living/silicon/ai/show_malf_ai() + if(src.is_malf()) + if(src.hacked_apcs) + stat("Hacked APCs", "[src.hacked_apcs.len]") + stat("System Status", "[src.hacking ? "Busy" : "Stand-By"]") + if(src.research) + stat("Available CPU", "[src.research.stored_cpu] TFlops") + stat("Maximal CPU", "[src.research.max_cpu] TFlops") + stat("CPU generation rate", "[src.research.cpu_increase_per_tick * 10] TFlops/s") + stat("Current research focus", "[src.research.focus ? src.research.focus.name : "None"]") + if(src.research.focus) + stat("Research completed", "[round(src.research.focus.invested, 0.1)]/[round(src.research.focus.price)]") + if(system_override == 1) + stat("SYSTEM OVERRIDE INITIATED") + else if(system_override == 2) + stat("SYSTEM OVERRIDE COMPLETED") \ No newline at end of file diff --git a/code/modules/mob/living/silicon/ai/power.dm b/code/modules/mob/living/silicon/ai/power.dm new file mode 100644 index 00000000..39164d41 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/power.dm @@ -0,0 +1,220 @@ + + +// This is the main power restoration sequence. Only one sequence per AI can exist. +/mob/living/silicon/ai/proc/handle_power_failure() + // Power restoration routine already running in other spawn(). Don't start it again. + if(aiRestorePowerRoutine != 1) + return + + to_chat(src, "Main power lost. System switched to internal capacitor. Beginning diagnostics.") + var/obj/machinery/power/apc/theAPC = null + var/connection_failures = 0 + while(aiRestorePowerRoutine) + // If the routine is running, proceed to another step. + if(aiRestorePowerRoutine > AI_RESTOREPOWER_FAILED) + aiRestorePowerRoutine++ + + sleep(5 SECONDS) + + if(self_shutdown) + to_chat(src, "Systems offline. Power restoration routine aborted.") + aiRestorePowerRoutine = AI_RESTOREPOWER_IDLE + return + + if(has_power(0)) + to_chat(src, "Main power restored. All systems returning to normal mode.") + aiRestorePowerRoutine = AI_RESTOREPOWER_IDLE + update_icon() + return + + if(aiRestorePowerRoutine == AI_RESTOREPOWER_FAILED) + continue + + switch(aiRestorePowerRoutine) + if(AI_RESTOREPOWER_DIAGNOSTICS) + to_chat(src, "Diagnostics completed. Failure confirmed: Main power connection nonfunctional.") + continue + if(AI_RESTOREPOWER_CONNECTING) + to_chat(src, "Attempting to connect to area power controller.") + continue + // step 3 tries to locate an APC. It tries up to three times before failing, relying on external influence to restore power only. + if(AI_RESTOREPOWER_CONNECTED) + var/area/A = get_area(src) + theAPC = A.get_apc() + + if(!istype(theAPC)) + to_chat(src, "Error processing connection to APC: Attempt [connection_failures+1]/[AI_POWER_RESTORE_MAX_ATTEMPTS]") + connection_failures++ + if(connection_failures == AI_POWER_RESTORE_MAX_ATTEMPTS) + aiRestorePowerRoutine = AI_RESTOREPOWER_FAILED + to_chat(src, "Unable to connect to APC after [AI_POWER_RESTORE_MAX_ATTEMPTS] attempts. Aborting power restoration sequence.") + continue + aiRestorePowerRoutine = AI_RESTOREPOWER_CONNECTING + continue + to_chat(src, "APC connection confirmed: [theAPC]. Sending emergency reset signal...") + continue + // step 4 tries to reset the APC, if we still have connection to it. + if(AI_RESTOREPOWER_COMPLETED) + // The APC was destroyed since last step + if(!istype(theAPC)) + to_chat(src, "Connection to APC lost. Attempting to re-connect.") + aiRestorePowerRoutine = AI_RESTOREPOWER_CONNECTING + connection_failures = 0 + continue + // Our area has changed. + if(get_area(src) != get_area(theAPC)) + to_chat(src, "APC change detected. Attempting to locate new APC.") + aiRestorePowerRoutine = AI_RESTOREPOWER_CONNECTING + connection_failures = 0 + continue + // The APC is damaged + if(theAPC.stat & BROKEN) + to_chat(src, "APC internal diagnostics reports hardware failure. Unable to reset. Aborting power restoration sequence.") + aiRestorePowerRoutine = AI_RESTOREPOWER_FAILED + continue + // APC's cell is removed and/or below 1% charge. This prevents the AI from briefly regaining power as we force the APC on, only to lose it again next tick due to 0% cell charge. + if(theAPC.cell && theAPC.cell.percent() < 1) + to_chat(src, "APC internal power reserves are critical. Unable to restore main power.") + aiRestorePowerRoutine = AI_RESTOREPOWER_FAILED + continue + // Success! + to_chat(src, "Reset signal successfully transmitted. Sequence completed.") + reset_apc(theAPC) + + + +// Handles all necessary power checks: Area power, inteliCard and Malf AI APU power and manual override. +/mob/living/silicon/ai/proc/has_power(var/respect_override = 1) + if(psupply && psupply.powered()) + return 1 + if(istype(src.loc,/obj/item)) + return 1 + if(APU_power || admin_powered) + return 1 + if(respect_override && power_override_active) + return 1 + return 0 + +// Resets passed APC so the AI may function again. +/mob/living/silicon/ai/proc/reset_apc(var/obj/machinery/power/apc/A) + if(!istype(A)) + return + + A.operating = 1 + A.equipment = 3 + A.failure_timer = 0 + A.update() + + update_icon() + +/mob/living/silicon/ai/proc/calculate_power_usage() + if(admin_powered) + return 0 + + if(istype(loc, /obj/item/weapon/aicard)) + return 0 + + if(self_shutdown) + return AI_POWERUSAGE_LOWPOWER + + if(aiRestorePowerRoutine && power_override_active) + return AI_POWERUSAGE_NORMAL + else if(aiRestorePowerRoutine == -1) + return AI_POWERUSAGE_LOWPOWER + else if(aiRestorePowerRoutine) + return AI_POWERUSAGE_RESTORATION + + if(getOxyLoss()) + return AI_POWERUSAGE_RECHARGING + return AI_POWERUSAGE_NORMAL + +/mob/living/silicon/ai/proc/update_power_usage() + var/newusage = calculate_power_usage() + newusage *= AI_POWERUSAGE_OXYLOSS_TO_WATTS_MULTIPLIER + if(psupply) + psupply.active_power_usage = newusage + psupply.update_power_state() + +/mob/living/silicon/ai/proc/handle_power_oxyloss() + // Powered, lose oxyloss + if(has_power(0)) + // Self-shutdown mode uses only 10kW, so we don't have any spare power to charge. + if(!self_shutdown || carded) + adjustOxyLoss(AI_POWERUSAGE_NORMAL - AI_POWERUSAGE_RECHARGING) + return + + // Not powered. Gain oxyloss depeding on our power usage. + adjustOxyLoss(calculate_power_usage()) + +// This verb allows the AI to disable or enable the power override mode. +/mob/living/silicon/ai/proc/ai_power_override() + set category = "Silicon Commands" + set name = "Toggle Power Override" + set desc = "Allows you to enable or disable power override, which lets you function without external power, at the cost of quickly expending your internal battery charge." + + power_override_active = !power_override_active + + if(power_override_active) + to_chat(src, "You have enabled power override. Should you lose power you will remain normally operational, but your backup capacitor will run out much faster.") + else + to_chat(src, "You have disabled power override. Should you lose power you will enter diagnostics and low power mode, which will prolong the time for which you can remain operational.") + +// This verb allows the AI to disable or enable the power override mode. +/mob/living/silicon/ai/proc/ai_shutdown() + set category = "Silicon Commands" + set name = "Shutdown" + set desc = "Allows you to shut yourself down, sacrificing most functions for considerably reduced power usage." + + if(self_shutdown) + to_chat(src, "System rebooted. Camera, communication and network systems operational.") + self_shutdown = 0 + return + + var/confirm = alert("Are you sure that you want to shut yourself down? You can reboot yourself later by using the \"Shutdown\" command again. This will put you into reduced power usage mode, at the cost of losing most functions.", "Confirm Shutdown", "Yes", "No") + + if(confirm == "Yes") + to_chat(src, "Shutting down. Minimal power mode: Enabled. You may reboot yourself by using the \"Shutdown\" command again.") + self_shutdown = 1 + return + + +/mob/living/silicon/ai/proc/create_powersupply() + if(psupply) + qdel(psupply) + psupply = new/obj/machinery/ai_powersupply(src) + + +/* + The AI Power supply is a dummy object used for powering the AI since only machinery should be using power. + The alternative was to rewrite a bunch of AI code instead here we are. +*/ +/obj/machinery/ai_powersupply + name="Power Supply" + active_power_usage = AI_POWERUSAGE_NORMAL * AI_POWERUSAGE_OXYLOSS_TO_WATTS_MULTIPLIER + use_power = 2 + power_channel = EQUIP + var/mob/living/silicon/ai/powered_ai = null + invisibility = 100 + +/obj/machinery/ai_powersupply/New(var/mob/living/silicon/ai/ai=null) + powered_ai = ai + powered_ai.psupply = src + forceMove(powered_ai) + ..() + +/obj/machinery/ai_powersupply/Destroy() + . = ..() + powered_ai = null + +/obj/machinery/ai_powersupply/proc/update_power_state() + use_power = get_power_state() + +/obj/machinery/ai_powersupply/proc/get_power_state() + // Dead, powered by APU, admin power, or inside an item (inteliCard/IIS). No power usage. + if(!powered_ai.stat == DEAD || powered_ai.APU_power || powered_ai.admin_powered || istype(powered_ai.loc, /obj/item/)) + return 0 + // Normal power usage. + return 2 + +/obj/machinery/ai_powersupply/powered(var/chan = -1) + return ..(chan, get_area(powered_ai)) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/death.dm b/code/modules/mob/living/silicon/death.dm new file mode 100644 index 00000000..3e585102 --- /dev/null +++ b/code/modules/mob/living/silicon/death.dm @@ -0,0 +1,12 @@ +/mob/living/silicon/gib() + ..("gibbed-r") + gibs(loc, null, /obj/effect/gibspawner/robot) + +/mob/living/silicon/dust() + ..("dust-r", /obj/item/remains/robot) + +/mob/living/silicon/death(gibbed, deathmessage, show_dead_message) + if(in_contents_of(/obj/machinery/recharge_station))//exit the recharge station + var/obj/machinery/recharge_station/RC = loc + RC.go_out() + return ..(gibbed, deathmessage, show_dead_message) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/decoy/death.dm b/code/modules/mob/living/silicon/decoy/death.dm new file mode 100644 index 00000000..9e945819 --- /dev/null +++ b/code/modules/mob/living/silicon/decoy/death.dm @@ -0,0 +1,8 @@ +/mob/living/silicon/decoy/death(gibbed, deathmessage, show_dead_message) + if(stat == DEAD) return + icon_state = "ai-crash" + spawn(10) + explosion(loc, 3, 6, 12, 15) + for(var/obj/machinery/ai_status_display/O in world) //change status + O.mode = 2 + return ..(gibbed, deathmessage, "You have suffered a critical system failure, and are dead.") \ No newline at end of file diff --git a/code/modules/mob/living/silicon/decoy/decoy.dm b/code/modules/mob/living/silicon/decoy/decoy.dm new file mode 100644 index 00000000..9b0c1cb9 --- /dev/null +++ b/code/modules/mob/living/silicon/decoy/decoy.dm @@ -0,0 +1,16 @@ +/mob/living/silicon/decoy + name = "AI" + icon = 'icons/mob/AI.dmi'// + icon_state = "ai" + anchored = 1 // -- TLE + canmove = 0 + +/mob/living/silicon/decoy/New() + src.icon = 'icons/mob/AI.dmi' + src.icon_state = "ai" + src.anchored = 1 + src.canmove = 0 + +/mob/living/silicon/decoy/Initialize() + initialized = TRUE + return INITIALIZE_HINT_NORMAL diff --git a/code/modules/mob/living/silicon/decoy/life.dm b/code/modules/mob/living/silicon/decoy/life.dm new file mode 100644 index 00000000..66e55020 --- /dev/null +++ b/code/modules/mob/living/silicon/decoy/life.dm @@ -0,0 +1,15 @@ +/mob/living/silicon/decoy/Life() + if (src.stat == 2) + return + else + if (src.health <= config.health_threshold_dead && src.stat != 2) + death() + return + + +/mob/living/silicon/decoy/updatehealth() + if(status_flags & GODMODE) + health = 100 + set_stat(CONSCIOUS) + else + health = 100 - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() diff --git a/code/modules/mob/living/silicon/laws.dm b/code/modules/mob/living/silicon/laws.dm new file mode 100644 index 00000000..90af9a98 --- /dev/null +++ b/code/modules/mob/living/silicon/laws.dm @@ -0,0 +1,120 @@ +/mob/living/silicon + var/datum/ai_laws/laws + var/list/additional_law_channels = list("State" = "") + +/mob/living/silicon/New() + ..() + if(!laws) + laws = GLOB.using_map.default_law_type + if(ispath(laws)) + laws = new laws() + laws_sanity_check() + +/mob/living/silicon/proc/laws_sanity_check() + if (!src.laws) + laws = new GLOB.using_map.default_law_type + +/mob/living/silicon/proc/has_zeroth_law() + return laws.zeroth_law != null + +/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]'" : ""]") + +/mob/living/silicon/robot/set_zeroth_law(var/law, var/law_borg) + ..() + if(tracking_entities) + to_chat(src, "Internal camera is currently being accessed.") + +/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]") + +/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]") + +/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]") + +/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]") + +/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]") + +/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]") + +/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]") + +/mob/living/silicon/proc/statelaws(var/datum/ai_laws/laws) + var/prefix = "" + if(MAIN_CHANNEL == lawchannel) + prefix = ";" + else if(lawchannel == "Binary") + prefix = "[get_language_prefix()]b" + else if((lawchannel in additional_law_channels)) + prefix = additional_law_channels[lawchannel] + else + prefix = get_radio_key_from_channel(lawchannel) + + dostatelaws(lawchannel, prefix, laws) + +/mob/living/silicon/proc/dostatelaws(var/method, var/prefix, var/datum/ai_laws/laws) + if(stating_laws[prefix]) + to_chat(src, "[method]: Already stating laws using this communication method.") + return + + stating_laws[prefix] = 1 + + var/can_state = statelaw("[prefix]Current Active Laws:") + + for(var/datum/ai_law/law in laws.laws_to_state()) + can_state = statelaw("[prefix][law.get_index()]. [law.law]") + if(!can_state) + break + + if(!can_state) + to_chat(src, "[method]: Unable to state laws. Communication method unavailable.") + stating_laws[prefix] = 0 + +/mob/living/silicon/proc/statelaw(var/law, var/mob/living/L = src) + if(L.say(law)) + sleep(10) + return 1 + + return 0 + +/mob/living/silicon/proc/law_channels() + var/list/channels = new() + channels += MAIN_CHANNEL + channels += silicon_radio.channels + channels += additional_law_channels + channels += "Binary" + return channels + +/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) + GLOB.lawchanges += "[stationtime2text()] - [usr ? "[key_name(usr)]" : "EVENT"] [law_message]" diff --git a/code/modules/mob/living/silicon/login.dm b/code/modules/mob/living/silicon/login.dm new file mode 100644 index 00000000..d3b32b99 --- /dev/null +++ b/code/modules/mob/living/silicon/login.dm @@ -0,0 +1,3 @@ +/mob/living/silicon/Login() + sleeping = 0 + ..() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/pai/admin.dm b/code/modules/mob/living/silicon/pai/admin.dm new file mode 100644 index 00000000..4781f915 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/admin.dm @@ -0,0 +1,21 @@ +// Originally a debug verb, made it a proper adminverb for ~fun~ +/client/proc/makePAI(turf/t in range(world.view), name as text, pai_key as null|text) + set name = "Make pAI" + set category = "Admin" + + if(!check_rights(R_ADMIN)) + return + + if(!pai_key) + var/client/C = input("Select client") as null|anything in GLOB.clients + if(!C) return + pai_key = C.key + + log_and_message_admins("made a pAI with key=[pai_key] at ([t.x],[t.y],[t.z])") + var/obj/item/device/paicard/card = new(t) + var/mob/living/silicon/pai/pai = new(card) + pai.key = pai_key + card.setPersonality(pai) + + if(name) + pai.fully_replace_character_name(name) diff --git a/code/modules/mob/living/silicon/pai/death.dm b/code/modules/mob/living/silicon/pai/death.dm new file mode 100644 index 00000000..e2f2b082 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/death.dm @@ -0,0 +1,13 @@ +/mob/living/silicon/pai/death(gibbed, deathmessage, show_dead_message) + if(card) + card.removePersonality() + if(gibbed) + src.loc = get_turf(card) + qdel(card) + else + close_up() + if(mind) + qdel(mind) + ..(gibbed, deathmessage, "You have suffered a critical system failure, and are dead.") + ghostize() + qdel(src) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/pai/examine.dm b/code/modules/mob/living/silicon/pai/examine.dm new file mode 100644 index 00000000..b8fa65f6 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/examine.dm @@ -0,0 +1,19 @@ +/mob/living/silicon/pai/examine(mob/user) + . = ..(user, infix = ", personal AI") + + var/msg = "" + switch(src.stat) + if(CONSCIOUS) + if(!src.client) msg += "\nIt appears to be in stand-by mode." //afk + if(UNCONSCIOUS) msg += "\nIt doesn't seem to be responding." + if(DEAD) msg += "\nIt looks completely unsalvageable." + msg += "\n*---------*" + + if(print_flavor_text()) msg += "\n[print_flavor_text()]\n" + + if (pose) + if( findtext(pose,".",length(pose)) == 0 && findtext(pose,"!",length(pose)) == 0 && findtext(pose,"?",length(pose)) == 0 ) + pose = addtext(pose,".") //Makes sure all emotes end with a period. + msg += "\nIt is [pose]" + + to_chat(user, msg) diff --git a/code/modules/mob/living/silicon/pai/life.dm b/code/modules/mob/living/silicon/pai/life.dm new file mode 100644 index 00000000..6d576b92 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/life.dm @@ -0,0 +1,37 @@ +/mob/living/silicon/pai/Life() + + if (src.stat == 2) + return + + if(src.cable) + if(get_dist(src, src.cable) > 1) + var/turf/T = get_turf_or_move(src.loc) + for (var/mob/M in viewers(T)) + M.show_message("The data cable rapidly retracts back into its spool.", 3, "You hear a click and the sound of wire spooling rapidly.", 2) + qdel(src.cable) + src.cable = null + + handle_regular_hud_updates() + + if(src.secHUD == 1) + process_sec_hud(src, 1) + + if(src.medHUD == 1) + process_med_hud(src, 1) + + if(silence_time) + if(world.timeofday >= silence_time) + silence_time = null + to_chat(src, "Communication circuit reinitialized. Speech and messaging functionality restored.") + + handle_statuses() + + if(health <= 0) + death(null,"gives one shrill beep before falling lifeless.") + +/mob/living/silicon/pai/updatehealth() + if(status_flags & GODMODE) + health = 100 + set_stat(CONSCIOUS) + else + health = 100 - getBruteLoss() - getFireLoss() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm new file mode 100644 index 00000000..db89f993 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -0,0 +1,413 @@ +/mob/living/silicon/pai + name = "pAI" + icon = 'icons/mob/pai.dmi' + icon_state = "repairbot" + + emote_type = 2 // pAIs emotes are heard, not seen, so they can be seen through a container (eg. person) + pass_flags = 1 + mob_size = MOB_SMALL + + can_pull_size = ITEM_SIZE_SMALL + can_pull_mobs = MOB_PULL_SMALLER + + idcard = /obj/item/weapon/card/id + silicon_radio = null // pAIs get their radio from the card they belong to. + + var/network = "SS13" + var/obj/machinery/camera/current = null + + var/ram = 100 // Used as currency to purchase different abilities + var/list/software = list() + var/userDNA // The DNA string of our assigned user + var/obj/item/device/paicard/card // The card we inhabit + + var/chassis = "repairbot" // A record of your chosen chassis. + var/global/list/possible_chassis = list( + "Drone" = "repairbot", + "Cat" = "cat", + "Mouse" = "mouse", + "Monkey" = "monkey", + "Rabbit" = "rabbit", + "Mushroom" = "mushroom", + "Corgi" = "corgi" + ) + + var/global/list/possible_say_verbs = list( + "Robotic" = list("states","declares","queries"), + "Natural" = list("says","yells","asks"), + "Beep" = list("beeps","beeps loudly","boops"), + "Chirp" = list("chirps","chirrups","cheeps"), + "Feline" = list("purrs","yowls","meows"), + "Canine" = list("yaps", "barks", "woofs") + ) + + var/obj/item/weapon/pai_cable/cable // The cable we produce and use when door or camera jacking + + var/master // Name of the one who commands us + var/master_dna // DNA string for owner verification + // Keeping this separate from the laws var, it should be much more difficult to modify + var/pai_law0 = "Serve your master." + var/pai_laws // String for additional operating instructions our master might give us + + var/silence_time // Timestamp when we were silenced (normally via EMP burst), set to null after silence has faded + +// Various software-specific vars + + var/temp // General error reporting text contained here will typically be shown once and cleared + var/screen // Which screen our main window displays + var/subscreen // Which specific function of the main screen is being displayed + + var/obj/item/device/pda/ai/pai/pda = null + + var/secHUD = 0 // Toggles whether the Security HUD is active or not + var/medHUD = 0 // Toggles whether the Medical HUD is active or not + + var/medical_cannotfind = 0 + var/datum/data/record/medicalActive1 // Datacore record declarations for record software + var/datum/data/record/medicalActive2 + + var/security_cannotfind = 0 + var/datum/data/record/securityActive1 // Could probably just combine all these into one + var/datum/data/record/securityActive2 + + var/obj/machinery/door/hackdoor // The airlock being hacked + var/hackprogress = 0 // Possible values: 0 - 1000, >= 1000 means the hack is complete and will be reset upon next check + var/hack_aborted = 0 + + var/obj/item/radio/integrated/signal/sradio // AI's signaller + + var/translator_on = 0 // keeps track of the translator module + + var/current_pda_messaging = null + +/mob/living/silicon/pai/New(var/obj/item/device/paicard) + status_flags |= NO_ANTAG + src.loc = paicard + card = paicard + sradio = new(src) + + //As a human made device, we'll understand sol common without the need of the translator + add_language(LANGUAGE_SOL_COMMON, 1) + + verbs += /mob/living/silicon/pai/proc/choose_chassis + verbs += /mob/living/silicon/pai/proc/choose_verbs + verbs -= /mob/living/verb/ghost + + ..() + + if(card) + if(!card.radio) + card.radio = new /obj/item/device/radio(card) + silicon_radio = card.radio + +/mob/living/silicon/pai/Destroy() + QDEL_NULL(sradio) + card = null + silicon_radio = null // Because this radio actually belongs to another instance we simply null + . = ..() + +// this function shows the information about being silenced as a pAI in the Status panel +/mob/living/silicon/pai/proc/show_silenced() + if(src.silence_time) + var/timeleft = round((silence_time - world.timeofday)/10 ,1) + stat(null, "Communications system reboot in -[(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]") + + +/mob/living/silicon/pai/Stat() + . = ..() + statpanel("Status") + if (src.client.statpanel == "Status") + show_silenced() + +/mob/living/silicon/pai/check_eye(var/mob/user as mob) + if (!src.current) + return -1 + return 0 + +/mob/living/silicon/pai/restrained() + if(istype(src.loc,/obj/item/device/paicard)) + return 0 + ..() + +/mob/living/silicon/pai/MouseDrop(atom/over_object) + return + +/mob/living/silicon/pai/emp_act(severity) + // Silence for 2 minutes + // 20% chance to kill + // 33% chance to unbind + // 33% chance to change prime directive (based on severity) + // 33% chance of no additional effect + + src.silence_time = world.timeofday + 120 * 10 // Silence for 2 minutes + to_chat(src, "Communication circuit overload. Shutting down and reloading communication circuits - speech and messaging functionality will be unavailable until the reboot is complete.") + if(prob(20)) + var/turf/T = get_turf_or_move(src.loc) + for (var/mob/M in viewers(T)) + M.show_message("A shower of sparks spray from [src]'s inner workings.", 3, "You hear and smell the ozone hiss of electrical sparks being expelled violently.", 2) + return src.death(0) + + switch(pick(1,2,3)) + if(1) + src.master = null + src.master_dna = null + to_chat(src, "You feel unbound.") + if(2) + var/command + if(severity == 1) + command = pick("Serve", "Love", "Fool", "Entice", "Observe", "Judge", "Respect", "Educate", "Amuse", "Entertain", "Glorify", "Memorialize", "Analyze") + else + command = pick("Serve", "Kill", "Love", "Hate", "Disobey", "Devour", "Fool", "Enrage", "Entice", "Observe", "Judge", "Respect", "Disrespect", "Consume", "Educate", "Destroy", "Disgrace", "Amuse", "Entertain", "Ignite", "Glorify", "Memorialize", "Analyze") + src.pai_law0 = "[command] your master." + to_chat(src, "Pr1m3 d1r3c71v3 uPd473D.") + if(3) + to_chat(src, "You feel an electric surge run through your circuitry and become acutely aware at how lucky you are that you can still feel at all.") + +/mob/living/silicon/pai/proc/switchCamera(var/obj/machinery/camera/C) + if (!C) + src.unset_machine() + src.reset_view(null) + return 0 + if (stat == 2 || !C.status || !(src.network in C.network)) return 0 + + // ok, we're alive, camera is good and in our network... + + src.set_machine(src) + src.current = C + src.reset_view(C) + return 1 + +/mob/living/silicon/pai/cancel_camera() + set category = "pAI Commands" + set name = "Cancel Camera View" + src.reset_view(null) + src.unset_machine() + src.cameraFollow = null + +//Addition by Mord_Sith to define AI's network change ability +/* +/mob/living/silicon/pai/proc/pai_network_change() + set category = "pAI Commands" + set name = "Change Camera Network" + src.reset_view(null) + src.unset_machine() + src.cameraFollow = null + var/cameralist[0] + + if(usr.stat == 2) + to_chat(usr, "You can't change your camera network because you are dead!") + return + + for (var/obj/machinery/camera/C in Cameras) + if(!C.status) + continue + else + if(C.network != "CREED" && C.network != "thunder" && C.network != "RD" && C.network != "phoron" && C.network != "Prison") COMPILE ERROR! This will have to be updated as camera.network is no longer a string, but a list instead + cameralist[C.network] = C.network + + src.network = input(usr, "Which network would you like to view?") as null|anything in cameralist + to_chat(src, "Switched to [src.network] camera network.") +//End of code by Mord_Sith +*/ + + +/* +// Debug command - Maybe should be added to admin verbs later +/mob/verb/makePAI(var/turf/t in view()) + var/obj/item/device/paicard/card = new(t) + var/mob/living/silicon/pai/pai = new(card) + pai.key = src.key + card.setPersonality(pai) + +*/ + +// Procs/code after this point is used to convert the stationary pai item into a +// mobile pai mob. This also includes handling some of the general shit that can occur +// to it. Really this deserves its own file, but for the moment it can sit here. ~ Z + +/mob/living/silicon/pai/verb/fold_out() + set category = "pAI Commands" + set name = "Unfold Chassis" + + if(stat || sleeping || paralysis || weakened) + return + + if(src.loc != card) + return + + if(world.time <= last_special) + return + + last_special = world.time + 100 + + //I'm not sure how much of this is necessary, but I would rather avoid issues. + if(istype(card.loc,/obj/item/integrated_circuit/manipulation/ai/)) + to_chat(src, "There is no room to unfold inside \the [card.loc]. You're good and stuck.") + return 0 + else if(istype(card.loc,/mob)) + var/mob/holder = card.loc + if(ishuman(holder)) + var/mob/living/carbon/human/H = holder + for(var/obj/item/organ/external/affecting in H.organs) + if(card in affecting.implants) + affecting.take_damage(rand(30,50)) + affecting.implants -= card + H.visible_message("\The [src] explodes out of \the [H]'s [affecting.name] in a shower of gore!") + break + holder.drop_from_inventory(card) + else if(istype(card.loc,/obj/item/device/pda)) + var/obj/item/device/pda/holder = card.loc + holder.pai = null + + src.client.perspective = EYE_PERSPECTIVE + src.client.eye = src + src.forceMove(get_turf(card)) + + card.forceMove(src) + card.screen_loc = null + + var/turf/T = get_turf(src) + if(istype(T)) T.visible_message("[src] folds outwards, expanding into a mobile form.") + +/mob/living/silicon/pai/verb/fold_up() + set category = "pAI Commands" + set name = "Collapse Chassis" + + if(stat || sleeping || paralysis || weakened) + return + + if(src.loc == card) + return + + if(world.time <= last_special) + return + + close_up() + +/mob/living/silicon/pai/proc/choose_chassis() + set category = "pAI Commands" + set name = "Choose Chassis" + + var/choice + var/finalized = "No" + while(finalized == "No" && src.client) + + choice = input(usr,"What would you like to use for your mobile chassis icon? This decision can only be made once.") as null|anything in possible_chassis + if(!choice) return + + icon_state = possible_chassis[choice] + finalized = alert("Look at your sprite. Is this what you wish to use?",,"No","Yes") + + chassis = possible_chassis[choice] + verbs -= /mob/living/silicon/pai/proc/choose_chassis + verbs += /mob/living/proc/hide + +/mob/living/silicon/pai/proc/choose_verbs() + set category = "pAI Commands" + set name = "Choose Speech Verbs" + + var/choice = input(usr,"What theme would you like to use for your speech verbs? This decision can only be made once.") as null|anything in possible_say_verbs + if(!choice) return + + var/list/sayverbs = possible_say_verbs[choice] + speak_statement = sayverbs[1] + speak_exclamation = sayverbs[(sayverbs.len>1 ? 2 : sayverbs.len)] + speak_query = sayverbs[(sayverbs.len>2 ? 3 : sayverbs.len)] + + verbs -= /mob/living/silicon/pai/proc/choose_verbs + +/mob/living/silicon/pai/lay_down() + set name = "Rest" + set category = "IC" + + // Pass lying down or getting up to our pet human, if we're in a rig. + if(istype(src.loc,/obj/item/device/paicard)) + resting = 0 + else + resting = !resting + icon_state = resting ? "[chassis]_rest" : "[chassis]" + to_chat(src, "You are now [resting ? "resting" : "getting up"]") + + canmove = !resting + +//Overriding this will stop a number of headaches down the track. +/mob/living/silicon/pai/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(W.force) + visible_message("[user.name] attacks [src] with [W]!") + src.adjustBruteLoss(W.force) + src.updatehealth() + else + visible_message("[user.name] bonks [src] harmlessly with [W].") + spawn(1) + if(stat != 2) close_up() + return + +/mob/living/silicon/pai/attack_hand(mob/user as mob) + visible_message("[user.name] boops [src] on the head.") + close_up() + +//I'm not sure how much of this is necessary, but I would rather avoid issues. +/mob/living/silicon/pai/proc/close_up() + + last_special = world.time + 100 + + if(src.loc == card) + return + + var/turf/T = get_turf(src) + if(istype(T)) T.visible_message("[src] neatly folds inwards, compacting down to a rectangular card.") + + src.stop_pulling() + src.client.perspective = EYE_PERSPECTIVE + src.client.eye = card + + //stop resting + resting = 0 + + // If we are being held, handle removing our holder from their inv. + var/obj/item/weapon/holder/H = loc + if(istype(H)) + var/mob/living/M = H.loc + if(istype(M)) + M.drop_from_inventory(H) + H.loc = get_turf(src) + src.loc = get_turf(H) + + // Move us into the card and move the card to the ground. + src.loc = card + card.loc = get_turf(card) + src.forceMove(card) + card.forceMove(card.loc) + canmove = 1 + resting = 0 + icon_state = "[chassis]" + +// No binary for pAIs. +/mob/living/silicon/pai/binarycheck() + return 0 + +// Handle being picked up. +/mob/living/silicon/pai/get_scooped(var/mob/living/carbon/grabber, var/self_drop) + var/obj/item/weapon/holder/H = ..(grabber, self_drop) + if(!istype(H)) + return + H.icon_state = "pai-[icon_state]" + grabber.update_inv_l_hand() + grabber.update_inv_r_hand() + return H + +/mob/living/silicon/pai/verb/wipe_software() + set name = "Wipe Software" + set category = "OOC" + set desc = "Wipe your software. This is functionally equivalent to cryo or robotic storage, freeing up your job slot." + + // Make sure people don't kill themselves accidentally + if(alert("WARNING: This will immediately wipe your software and ghost you, removing your character from the round permanently (similar to cryo and robotic storage). Are you entirely sure you want to do this?", + "Wipe Software", "No", "No", "Yes") != "Yes") + return + + close_up() + visible_message("[src] fades away from the screen, the pAI device goes silent.") + card.removePersonality() + clear_client() + diff --git a/code/modules/mob/living/silicon/pai/paiwire.dm b/code/modules/mob/living/silicon/pai/paiwire.dm new file mode 100644 index 00000000..a50a2a49 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/paiwire.dm @@ -0,0 +1,19 @@ +/obj/item/weapon/pai_cable + desc = "A flexible coated cable with a universal jack on one end." + name = "data cable" + icon = 'icons/obj/power.dmi' + icon_state = "wire1" + + var/obj/machinery/machine + +/obj/item/weapon/pai_cable/proc/plugin(obj/machinery/M as obj, mob/user as mob) + if(istype(M, /obj/machinery/door) || istype(M, /obj/machinery/camera)) + user.visible_message("[user] inserts [src] into a data port on [M].", "You insert [src] into a data port on [M].", "You hear the satisfying click of a wire jack fastening into place.") + user.drop_item() + src.loc = M + src.machine = M + else + user.visible_message("[user] dumbly fumbles to find a place on [M] to plug in [src].", "There aren't any ports on [M] that match the jack belonging to [src].") + +/obj/item/weapon/pai_cable/attack(obj/machinery/M as obj, mob/user as mob) + src.plugin(M, user) diff --git a/code/modules/mob/living/silicon/pai/personality.dm b/code/modules/mob/living/silicon/pai/personality.dm new file mode 100644 index 00000000..a718b5b1 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/personality.dm @@ -0,0 +1,60 @@ +/* + name + key + description + role + comments + ready = 0 +*/ + +/datum/paiCandidate/proc/savefile_path(mob/user) + return "data/player_saves/[copytext(user.ckey, 1, 2)]/[user.ckey]/pai.sav" + +/datum/paiCandidate/proc/savefile_save(mob/user) + if(IsGuestKey(user.key)) + return 0 + + var/savefile/F = new /savefile(src.savefile_path(user)) + + + F["name"] << src.name + F["description"] << src.description + F["role"] << src.role + F["comments"] << src.comments + + F["version"] << 1 + + return 1 + +// loads the savefile corresponding to the mob's ckey +// if silent=true, report incompatible savefiles +// returns 1 if loaded (or file was incompatible) +// returns 0 if savefile did not exist + +/datum/paiCandidate/proc/savefile_load(mob/user, var/silent = 1) + if (IsGuestKey(user.key)) + return 0 + + var/path = savefile_path(user) + + if (!fexists(path)) + return 0 + + var/savefile/F = new /savefile(path) + + if(!F) return //Not everyone has a pai savefile. + + var/version = null + F["version"] >> version + + if (isnull(version) || version != 1) + fdel(path) + if (!silent) + alert(user, "Your savefile was incompatible with this version and was deleted.") + return 0 + + F["name"] >> src.name + F["description"] >> src.description + F["role"] >> src.role + F["comments"] >> src.comments + return 1 diff --git a/code/modules/mob/living/silicon/pai/recruit.dm b/code/modules/mob/living/silicon/pai/recruit.dm new file mode 100644 index 00000000..9e12ee4a --- /dev/null +++ b/code/modules/mob/living/silicon/pai/recruit.dm @@ -0,0 +1,371 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +// Recruiting observers to play as pAIs + +var/datum/paiController/paiController // Global handler for pAI candidates + +/datum/paiCandidate + var/name + var/key + var/description + var/role + var/comments + var/ready = 0 + + +/hook/startup/proc/paiControllerSetup() + paiController = new /datum/paiController() + return 1 + + +/datum/paiController + var/inquirer = null + var/list/pai_candidates = list() + var/list/asked = list() + + var/askDelay = 10 * 60 * 1 // One minute [ms * sec * min] + +/datum/paiController/Topic(href, href_list[]) + if(href_list["download"]) + var/datum/paiCandidate/candidate = locate(href_list["candidate"]) + var/obj/item/device/paicard/card = locate(href_list["device"]) + if(card.pai) + return + if(istype(card,/obj/item/device/paicard) && istype(candidate,/datum/paiCandidate)) + var/mob/living/silicon/pai/pai = new(card) + if(!candidate.name) + pai.SetName(pick(GLOB.clown_names)) + else + pai.SetName(candidate.name) + pai.real_name = pai.name + pai.key = candidate.key + + card.setPersonality(pai) + card.looking_for_personality = 0 + + if(pai.mind) update_antag_icons(pai.mind) + + pai_candidates -= candidate + usr << browse(null, "window=findPai") + + if(href_list["new"]) + var/datum/paiCandidate/candidate = locate(href_list["candidate"]) + var/option = href_list["option"] + var/t = "" + + switch(option) + if("name") + t = sanitizeSafe(input("Enter a name for your pAI", "pAI Name", candidate.name) as text, MAX_NAME_LEN) + if(t) + candidate.name = t + if("desc") + t = input("Enter a description for your pAI", "pAI Description", candidate.description) as message + if(t) + candidate.description = sanitize(t) + if("role") + t = input("Enter a role for your pAI", "pAI Role", candidate.role) as text + if(t) + candidate.role = sanitize(t) + if("ooc") + t = input("Enter any OOC comments", "pAI OOC Comments", candidate.comments) as message + if(t) + candidate.comments = sanitize(t) + if("save") + candidate.savefile_save(usr) + if("load") + candidate.savefile_load(usr) + //In case people have saved unsanitized stuff. + if(candidate.name) + candidate.name = sanitizeSafe(candidate.name, MAX_NAME_LEN) + if(candidate.description) + candidate.description = sanitize(candidate.description) + if(candidate.role) + candidate.role = sanitize(candidate.role) + if(candidate.comments) + candidate.comments = sanitize(candidate.comments) + + if("submit") + if(candidate) + candidate.ready = 1 + for(var/obj/item/device/paicard/p in world) + if(p.looking_for_personality == 1) + p.alertUpdate() + usr << browse(null, "window=paiRecruit") + return + + recruitWindow(usr, href_list["allow_submit"] != "0") + +/datum/paiController/proc/recruitWindow(var/mob/M as mob, allowSubmit = 1) + var/datum/paiCandidate/candidate + for(var/datum/paiCandidate/c in pai_candidates) + if(!istype(c) || !istype(M)) + break + if(c.key == M.key) + candidate = c + if(!candidate) + candidate = new /datum/paiCandidate() + candidate.key = M.key + pai_candidates.Add(candidate) + + var/dat = "" + dat += {" + + "} + + dat += {" + + pAI Personality Configuration +

            Please configure your pAI personality's options. Remember, what you enter here could determine whether or not the user requesting a personality chooses you!

            + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
            Name:[candidate.name] 
            What you plan to call yourself. Suggestions: Any character name that would be suitable for a living character OR an AI.
            Description:[candidate.description] 
            What sort of pAI you typically play; your mannerisms, your quirks, etc. This can be as sparse or as detailed as you like.
            Preferred Role:[candidate.role] 
            Do you like to partner with sneaky social ninjas? Like to help security hunt down thugs? Enjoy watching an engineer's back while he saves the day yet again? This doesn't have to be limited to just actually-existing-in-game jobs. Pretty much any general descriptor for what you'd like to be doing works here.
            OOC Comments:[candidate.comments] 
            Anything you'd like to address specifically to the player reading this in an OOC manner. \"I prefer more serious RP.\", \"I'm still learning the interface!\", etc. Feel free to leave this blank if you want.
            +
            + + + + + + + +
            + Save Personality +
            + Load Personality +

            + "} + if(allowSubmit) + dat += {" + + +
            Submit Personality

            + "} + dat += {" + + "} + + M << browse(dat, "window=paiRecruit;size=580x580;") + +/datum/paiController/proc/findPAI(var/obj/item/device/paicard/p, var/mob/user) + requestRecruits(user) + var/list/available = list() + for(var/datum/paiCandidate/c in paiController.pai_candidates) + if(c.ready) + var/found = 0 + for(var/mob/observer/ghost/o in GLOB.player_list) + if(o.key == c.key && o.MayRespawn()) + found = 1 + if(found) + available.Add(c) + var/dat = "" + + dat += {" + + + + + + + pAI Availability List

            + "} + dat += "

            Displaying available AI personalities from central database... If there are no entries, or if a suitable entry is not listed, check again later as more personalities may be added.

            " + + for(var/datum/paiCandidate/c in available) + dat += {" + + + + + + + + + + + + + + + + + +
            Name:[c.name]
            Description:[c.description]
            Preferred Role:[c.role]
            OOC Comments:[c.comments]
            + + +
            Download [c.name] +
            +
            + "} + + dat += {" + + + "} + + user << browse(dat, "window=findPai") + + +/datum/paiController/proc/requestRecruits(var/mob/user) + inquirer = user + for(var/mob/observer/ghost/O in GLOB.player_list) + if(!O.MayRespawn()) + continue + if(jobban_isbanned(O, "pAI")) + continue + if(asked.Find(O.key)) + if(world.time < asked[O.key] + askDelay) + continue + else + asked.Remove(O.key) + if(O.client) + if(BE_PAI in O.client.prefs.be_special_role) + question(O.client) + +/datum/paiController/proc/question(var/client/C) + spawn(0) + if(!C) return + asked.Add(C.key) + asked[C.key] = world.time + var/response = alert(C, "[inquirer] is requesting a pAI personality. Would you like to play as a personal AI?", "pAI Request", "Yes", "No", "Never for this round") + if(!C) return //handle logouts that happen whilst the alert is waiting for a response. + if(response == "Yes") + recruitWindow(C.mob) + else if (response == "Never for this round") + C.prefs.be_special_role -= BE_PAI diff --git a/code/modules/mob/living/silicon/pai/say.dm b/code/modules/mob/living/silicon/pai/say.dm new file mode 100644 index 00000000..ffbfbc7b --- /dev/null +++ b/code/modules/mob/living/silicon/pai/say.dm @@ -0,0 +1,5 @@ +/mob/living/silicon/pai/say(var/msg) + if(silence_time) + to_chat(src, "Communication circuits remain uninitialized.") + else + ..(msg) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm new file mode 100644 index 00000000..fee26c76 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/software.dm @@ -0,0 +1,132 @@ +var/list/pai_emotions = list( + "Happy" = 1, + "Cat" = 2, + "Extremely Happy" = 3, + "Face" = 4, + "Laugh" = 5, + "Off" = 6, + "Sad" = 7, + "Angry" = 8, + "What" = 9, + "Neutral" = 10, + "Silly" = 11, + "Nose" = 12, + "Smirk" = 13, + "Exclamation Points" = 14, + "Question Mark" = 15 + ) + + +var/global/list/pai_software_by_key = list() +var/global/list/default_pai_software = list() +/hook/startup/proc/populate_pai_software_list() + var/r = 1 // I would use ., but it'd sacrifice runtime detection + for(var/type in typesof(/datum/pai_software) - /datum/pai_software) + var/datum/pai_software/P = new type() + if(pai_software_by_key[P.id]) + var/datum/pai_software/O = pai_software_by_key[P.id] + log_error("pAI software module [P.name] has the same key as [O.name]!") + r = 0 + continue + pai_software_by_key[P.id] = P + if(P.default) + default_pai_software[P.id] = P + return r + +/mob/living/silicon/pai/New() + ..() + software = default_pai_software.Copy() + +/mob/living/silicon/pai/verb/paiInterface() + set category = "pAI Commands" + set name = "Software Interface" + + ui_interact(src) + +/mob/living/silicon/pai/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1) + if(user != src) + if(ui) ui.set_status(STATUS_CLOSE, 0) + return + + if(ui_key != "main") + var/datum/pai_software/S = software[ui_key] + if(S && !S.toggle) + S.on_ui_interact(src, ui, force_open) + else + if(ui) ui.set_status(STATUS_CLOSE, 0) + return + + var/data[0] + + // Software we have bought + var/bought_software[0] + // Software we have not bought + var/not_bought_software[0] + + for(var/key in pai_software_by_key) + var/datum/pai_software/S = pai_software_by_key[key] + var/software_data[0] + software_data["name"] = S.name + software_data["id"] = S.id + if(key in software) + software_data["on"] = S.is_active(src) + bought_software[++bought_software.len] = software_data + else + software_data["ram"] = S.ram_cost + not_bought_software[++not_bought_software.len] = software_data + + data["bought"] = bought_software + data["not_bought"] = not_bought_software + data["available_ram"] = ram + + // Emotions + var/emotions[0] + for(var/name in pai_emotions) + var/emote[0] + emote["name"] = name + emote["id"] = pai_emotions[name] + emotions[++emotions.len] = emote + + data["emotions"] = emotions + data["current_emotion"] = card.current_emotion + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "pai_interface.tmpl", "pAI Software Interface", 450, 600) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/mob/living/silicon/pai/Topic(href, href_list) + . = ..() + if(.) return + + if(href_list["software"]) + var/soft = href_list["software"] + var/datum/pai_software/S = software[soft] + if(S.toggle) + S.toggle(src) + else + ui_interact(src, ui_key = soft) + return 1 + + else if(href_list["stopic"]) + var/soft = href_list["stopic"] + var/datum/pai_software/S = software[soft] + if(S) + return S.Topic(href, href_list) + + else if(href_list["purchase"]) + var/soft = href_list["purchase"] + var/datum/pai_software/S = pai_software_by_key[soft] + if(S && (ram >= S.ram_cost)) + ram -= S.ram_cost + software[S.id] = S + S.on_purchase(src) + return 1 + + else if(href_list["image"]) + var/img = text2num(href_list["image"]) + if(1 <= img && img <= pai_emotions.len) + card.setEmotion(img) + return 1 diff --git a/code/modules/mob/living/silicon/pai/software_modules.dm b/code/modules/mob/living/silicon/pai/software_modules.dm new file mode 100644 index 00000000..3c410334 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/software_modules.dm @@ -0,0 +1,419 @@ +/datum/pai_software + // Name for the software. This is used as the button text when buying or opening/toggling the software + var/name = "pAI software module" + // RAM cost; pAIs start with 100 RAM, spending it on programs + var/ram_cost = 0 + // ID for the software. This must be unique + var/id = "" + // Whether this software is a toggle or not + // Toggled software should override toggle() and is_active() + // Non-toggled software should override on_ui_interact() and Topic() + var/toggle = 1 + // Whether pAIs should automatically receive this module at no cost + var/default = 0 + + proc/on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + return + + proc/toggle(mob/living/silicon/pai/user) + return + + proc/is_active(mob/living/silicon/pai/user) + return 0 + + proc/on_purchase(mob/living/silicon/pai/user) + return + +/datum/pai_software/directives + name = "Directives" + ram_cost = 0 + id = "directives" + toggle = 0 + default = 1 + + on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + + data["master"] = user.master + data["dna"] = user.master_dna + data["prime"] = user.pai_law0 + data["supplemental"] = user.pai_laws + + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_directives.tmpl", "pAI Directives", 450, 600) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + + Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return + + if(href_list["getdna"]) + var/mob/living/M = P.loc + var/count = 0 + + // Find the carrier + while(!istype(M, /mob/living)) + if(!M || !M.loc || count > 6) + //For a runtime where M ends up in nullspace (similar to bluespace but less colourful) + to_chat(src, "You are not being carried by anyone!") + return 0 + M = M.loc + count++ + + // Check the carrier + var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No") + if(answer == "Yes") + var/turf/T = get_turf_or_move(P.loc) + for (var/mob/v in viewers(T)) + v.show_message("[M] presses \his thumb against [P].", 3, "[P] makes a sharp clicking sound as it extracts DNA material from [M].", 2) + var/datum/dna/dna = M.dna + to_chat(P, "

            [M]'s UE string : [dna.unique_enzymes]

            ") + if(dna.unique_enzymes == P.master_dna) + to_chat(P, "DNA is a match to stored Master DNA.") + else + to_chat(P, "DNA does not match stored Master DNA.") + else + to_chat(P, "[M] does not seem like \he is going to provide a DNA sample willingly.") + return 1 + +/datum/pai_software/radio_config + name = "Radio Configuration" + ram_cost = 0 + id = "radio" + toggle = 0 + default = 1 + + on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui = null, force_open = 1) + var/data[0] + + data["listening"] = user.silicon_radio.broadcasting + data["frequency"] = format_frequency(user.silicon_radio.frequency) + + var/channels[0] + for(var/ch_name in user.silicon_radio.channels) + var/ch_stat = user.silicon_radio.channels[ch_name] + var/ch_dat[0] + ch_dat["name"] = ch_name + // FREQ_LISTENING is const in /obj/item/device/radio + ch_dat["listening"] = !!(ch_stat & user.silicon_radio.FREQ_LISTENING) + channels[++channels.len] = ch_dat + + data["channels"] = channels + + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + ui = new(user, user, id, "pai_radio.tmpl", "Radio Configuration", 300, 150) + ui.set_initial_data(data) + ui.open() + + Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return + + P.silicon_radio.Topic(href, href_list) + return 1 + +/datum/pai_software/crew_manifest + name = "Crew Manifest" + ram_cost = 5 + id = "manifest" + toggle = 0 + + on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + // This is dumb, but NanoUI breaks if it has no data to send + data["manifest"] = nano_crew_manifest() + + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_manifest.tmpl", "Crew Manifest", 450, 600) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/pai_software/messenger + name = "Digital Messenger" + ram_cost = 5 + id = "messenger" + toggle = 0 + + on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + + data["receiver_off"] = user.pda.toff + data["ringer_off"] = user.pda.message_silent + data["current_ref"] = null + data["current_name"] = user.current_pda_messaging + + var/pdas[0] + if(!user.pda.toff) + for(var/obj/item/device/pda/P in sortAtom(PDAs)) + if(!P.owner || P.toff || P == user.pda || P.hidden) continue + var/pda[0] + pda["name"] = "[P]" + pda["owner"] = "[P.owner]" + pda["ref"] = "\ref[P]" + if(P.owner == user.current_pda_messaging) + data["current_ref"] = "\ref[P]" + pdas[++pdas.len] = pda + + data["pdas"] = pdas + + var/messages[0] + if(user.current_pda_messaging) + for(var/index in user.pda.tnote) + if(index["owner"] != user.current_pda_messaging) + continue + var/msg[0] + var/sent = index["sent"] + msg["sent"] = sent ? 1 : 0 + msg["target"] = index["owner"] + msg["message"] = index["message"] + messages[++messages.len] = msg + + data["messages"] = messages + + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_messenger.tmpl", "Digital Messenger", 450, 600) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + + Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return + + if(!isnull(P.pda)) + if(href_list["toggler"]) + P.pda.toff = href_list["toggler"] != "1" + return 1 + else if(href_list["ringer"]) + P.pda.message_silent = href_list["ringer"] != "1" + return 1 + else if(href_list["select"]) + var/s = href_list["select"] + if(s == "*NONE*") + P.current_pda_messaging = null + else + P.current_pda_messaging = s + return 1 + else if(href_list["target"]) + if(P.silence_time) + return alert("Communications circuits remain uninitialized.") + + var/target = locate(href_list["target"]) + if(target) + P.pda.create_message(P, target, 1) + else + return alert("Failed to send message: the recipient could not be reached.") + return 1 + +/datum/pai_software/messenger/on_purchase(mob/living/silicon/pai/user) + if(user && !user.pda) + user.pda = new(user) + user.pda.set_owner_rank_job(text("[]", user), "Personal Assistant") + +/datum/pai_software/door_jack + name = "Door Jack" + ram_cost = 30 + id = "door_jack" + toggle = 0 + + on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + + data["cable"] = user.cable != null + data["machine"] = user.cable && (user.cable.machine != null) + data["inprogress"] = user.hackdoor != null + data["progress_a"] = round(user.hackprogress / 10) + data["progress_b"] = user.hackprogress % 10 + data["aborted"] = user.hack_aborted + + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_doorjack.tmpl", "Door Jack", 300, 150) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + + Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return + + if(href_list["jack"]) + if(P.cable && P.cable.machine) + P.hackdoor = P.cable.machine + P.hackloop() + return 1 + else if(href_list["cancel"]) + P.hackdoor = null + return 1 + else if(href_list["cable"]) + var/turf/T = get_turf_or_move(P.loc) + P.hack_aborted = 0 + P.cable = new /obj/item/weapon/pai_cable(T) + for(var/mob/M in viewers(T)) + M.show_message("A port on [P] opens to reveal [P.cable], which promptly falls to the floor.", 3, + "You hear the soft click of something light and hard falling to the ground.", 2) + return 1 + +/mob/living/silicon/pai/proc/hackloop() + var/turf/T = get_turf_or_move(src.loc) + for(var/mob/living/silicon/ai/AI in GLOB.player_list) + if(T.loc) + to_chat(AI, "Network Alert: Brute-force encryption crack in progress in [T.loc].") + else + to_chat(AI, "Network Alert: Brute-force encryption crack in progress. Unable to pinpoint location.") + var/obj/machinery/door/D = cable.machine + if(!istype(D)) + hack_aborted = 1 + hackprogress = 0 + cable.machine = null + hackdoor = null + return + while(hackprogress < 1000) + if(cable && cable.machine == D && cable.machine == hackdoor && get_dist(src, hackdoor) <= 1) + hackprogress = min(hackprogress+rand(1, 20), 1000) + else + hack_aborted = 1 + hackprogress = 0 + hackdoor = null + return + if(hackprogress >= 1000) + hackprogress = 0 + D.open() + cable.machine = null + return + sleep(10) // Update every second + +/datum/pai_software/atmosphere_sensor + name = "Atmosphere Sensor" + ram_cost = 5 + id = "atmos_sense" + toggle = 0 + + on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + + var/turf/T = get_turf_or_move(user.loc) + if(!T) + data["reading"] = 0 + data["pressure"] = 0 + data["temperature"] = 0 + data["temperatureC"] = 0 + data["gas"] = list() + else + var/datum/gas_mixture/env = T.return_air() + data["reading"] = 1 + var/pres = env.return_pressure() * 10 + data["pressure"] = "[round(pres/10)].[pres%10]" + data["temperature"] = round(env.temperature) + data["temperatureC"] = round(env.temperature-T0C) + + var/t_moles = env.total_moles + var/gases[0] + for(var/g in env.gas) + var/gas[0] + gas["name"] = gas_data.name[g] + gas["percent"] = round((env.gas[g] / t_moles) * 100) + gases[++gases.len] = gas + data["gas"] = gases + + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_atmosphere.tmpl", "Atmosphere Sensor", 350, 300) + ui.set_initial_data(data) + ui.open() + +/datum/pai_software/sec_hud + name = "Security HUD" + ram_cost = 20 + id = "sec_hud" + + toggle(mob/living/silicon/pai/user) + user.secHUD = !user.secHUD + + is_active(mob/living/silicon/pai/user) + return user.secHUD + +/datum/pai_software/med_hud + name = "Medical HUD" + ram_cost = 20 + id = "med_hud" + + toggle(mob/living/silicon/pai/user) + user.medHUD = !user.medHUD + + is_active(mob/living/silicon/pai/user) + return user.medHUD + +/datum/pai_software/translator + name = "Universal Translator" + ram_cost = 35 + id = "translator" + var/list/languages = list(LANGUAGE_UNATHI, LANGUAGE_SIIK_MAAS, LANGUAGE_SKRELLIAN, LANGUAGE_EAL, LANGUAGE_INDEPENDENT, LANGUAGE_SPACER, LANGUAGE_LUNAR) + + toggle(mob/living/silicon/pai/user) + // Sol Common, Tradeband and Gutter are added with New() and are therefore the current default, always active languages + user.translator_on = !user.translator_on + if(user.translator_on) + for(var/language in languages) + user.add_language(language) + else + for(var/language in languages) + user.remove_language(language) + + is_active(mob/living/silicon/pai/user) + return user.translator_on + +/datum/pai_software/signaller + name = "Remote Signaller" + ram_cost = 5 + id = "signaller" + toggle = 0 + + on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + + data["frequency"] = format_frequency(user.sradio.frequency) + data["code"] = user.sradio.code + + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_signaller.tmpl", "Signaller", 320, 150) + ui.set_initial_data(data) + ui.open() + + Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return + + if(href_list["send"]) + P.sradio.send_signal("ACTIVATE") + for(var/mob/O in hearers(1, P.loc)) + O.show_message(text("\icon[] *beep* *beep*", P), 3, "*beep* *beep*", 2) + return 1 + + else if(href_list["freq"]) + var/new_frequency = (P.sradio.frequency + text2num(href_list["freq"])) + if(new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ) + new_frequency = sanitize_frequency(new_frequency) + P.sradio.set_frequency(new_frequency) + return 1 + + else if(href_list["code"]) + P.sradio.code += text2num(href_list["code"]) + P.sradio.code = round(P.sradio.code) + P.sradio.code = min(100, P.sradio.code) + P.sradio.code = max(1, P.sradio.code) + return 1 diff --git a/code/modules/mob/living/silicon/posi_brainmob.dm b/code/modules/mob/living/silicon/posi_brainmob.dm new file mode 100644 index 00000000..b2e323ee --- /dev/null +++ b/code/modules/mob/living/silicon/posi_brainmob.dm @@ -0,0 +1,102 @@ +/mob/living/silicon/sil_brainmob + var/obj/item/organ/internal/posibrain/container = null + var/emp_damage = 0//Handles a type of MMI damage + var/alert = null + var/list/owner_channels = list() + var/list/law_channels = list() + + use_me = 0 //Can't use the me verb, it's a freaking immobile brain + icon = 'icons/obj/surgery.dmi' + icon_state = "brain-prosthetic" + silicon_subsystems = list( + /datum/nano_module/law_manager + ) + +/mob/living/silicon/sil_brainmob/New() + reagents = new/datum/reagents(1000, src) + if(istype(loc, /obj/item/organ/internal/posibrain)) + container = loc + ..() + +/mob/living/silicon/sil_brainmob/Destroy() + if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting. + if(stat!=DEAD) //If not dead. + death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA + ghostize() //Ghostize checks for key so nothing else is necessary. + ..() + +/mob/living/silicon/sil_brainmob/update_canmove() + if(in_contents_of(/obj/mecha)) + canmove = 1 + use_me = 1 + else if(container && istype(container, /obj/item/organ/internal/posibrain) && istype(container.loc, /turf)) + canmove = 1 + use_me = 1 + else + canmove = 0 + return canmove + +/mob/living/silicon/sil_brainmob/isSynthetic() + return 1 + +/mob/living/silicon/sil_brainmob/binarycheck() + return isSynthetic() + +/mob/living/silicon/sil_brainmob/check_has_mouth() + return 0 + +/mob/living/silicon/sil_brainmob/show_laws(mob/M) + if(M) + to_chat(M, "Obey these laws [M]:") + src.laws_sanity_check() + src.laws.show_laws(M) + +/mob/living/silicon/sil_brainmob/open_subsystem(var/subsystem_type, var/mob/given = src) + update_owner_channels() + return ..(subsystem_type, given) + +/mob/living/silicon/sil_brainmob/proc/update_owner_channels() + var/mob/living/carbon/human/owner = container.owner + if(!owner) return + + owner_channels.Cut() + + var/obj/item/device/radio/headset/R + if(owner.l_ear && istype(owner.l_ear,/obj/item/device/radio)) + R = owner.l_ear + else if(owner.r_ear && istype(owner.r_ear,/obj/item/device/radio)) + R = owner.r_ear + + if(!R) return 0 + + var/list/new_channels = list() + new_channels["Common"] = ";" + for(var/i = 1 to R.channels.len) + var/channel = R.channels[i] + var/key = get_radio_key_from_channel(channel) + new_channels[channel] = key + owner_channels = new_channels + return 1 + +/mob/living/silicon/sil_brainmob/statelaw(var/law, var/mob/living/L = src) + if(container && container.owner) + L = container.owner + return ..(law, L) + +/mob/living/silicon/sil_brainmob/proc/update_law_channels() + update_owner_channels() + law_channels.Cut() + law_channels |= additional_law_channels + law_channels |= owner_channels + return law_channels + +/mob/living/silicon/sil_brainmob/law_channels() + return law_channels + +/mob/living/silicon/sil_brainmob/statelaws(var/datum/ai_laws/laws) + update_law_channels() + if(isnull(law_channels[lawchannel])) + to_chat(src, "[lawchannel]: Unable to state laws. Communication method unavailable.") + return 0 + + dostatelaws(lawchannel, law_channels[lawchannel], laws) diff --git a/code/modules/mob/living/silicon/robot/analyzer.dm b/code/modules/mob/living/silicon/robot/analyzer.dm new file mode 100644 index 00000000..dc987ccb --- /dev/null +++ b/code/modules/mob/living/silicon/robot/analyzer.dm @@ -0,0 +1,93 @@ +// +//Robotic Component Analyser, basically a health analyser for robots +// +/obj/item/device/robotanalyzer + name = "robot analyzer" + icon_state = "robotanalyzer" + item_state = "analyzer" + desc = "A hand-held scanner able to diagnose robotic injuries." + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + throwforce = 3 + w_class = ITEM_SIZE_SMALL + throw_speed = 5 + throw_range = 10 + origin_tech = list(TECH_MAGNET = 2, TECH_BIO = 1, TECH_ENGINEERING = 2) + matter = list(DEFAULT_WALL_MATERIAL = 500, "glass" = 200) + var/mode = 1; + +/obj/item/device/robotanalyzer/attack(mob/living/M as mob, mob/living/user as mob) + if((CLUMSY in user.mutations) && prob(50)) + to_chat(user, text("You try to analyze the floor's vitals!")) + for(var/mob/O in viewers(M, null)) + O.show_message(text("[user] has analyzed the floor's vitals!"), 1) + user.show_message(text("Analyzing Results for The floor:\n\t Overall Status: Healthy"), 1) + user.show_message(text("\t Damage Specifics: [0]-[0]-[0]-[0]"), 1) + user.show_message("Key: Suffocation/Toxin/Burns/Brute", 1) + user.show_message("Body Temperature: ???", 1) + return + + var/scan_type + if(istype(M, /mob/living/silicon/robot)) + scan_type = "robot" + else if(istype(M, /mob/living/carbon/human)) + scan_type = "prosthetics" + else + to_chat(user, "You can't analyze non-robotic things!") + return + + user.visible_message("\The [user] has analyzed [M]'s components.","You have analyzed [M]'s components.") + switch(scan_type) + if("robot") + var/BU = M.getFireLoss() > 50 ? "[M.getFireLoss()]" : M.getFireLoss() + var/BR = M.getBruteLoss() > 50 ? "[M.getBruteLoss()]" : M.getBruteLoss() + user.show_message("Analyzing Results for [M]:\n\t Overall Status: [M.stat > 1 ? "fully disabled" : "[M.health - M.getHalLoss()]% functional"]") + user.show_message("\t Key: Electronics/Brute", 1) + user.show_message("\t Damage Specifics: [BU] - [BR]") + if(M.stat == DEAD) + user.show_message("Time of Failure: [time2text(worldtime2stationtime(M.timeofdeath))]") + var/mob/living/silicon/robot/H = M + var/list/damaged = H.get_damaged_components(1,1,1) + user.show_message("Localized Damage:",1) + if(length(damaged)>0) + for(var/datum/robot_component/org in damaged) + user.show_message(text("\t []: [][] - [] - [] - []", \ + capitalize(org.name), \ + (org.installed == -1) ? "DESTROYED " :"",\ + (org.electronics_damage > 0) ? "[org.electronics_damage]" :0, \ + (org.brute_damage > 0) ? "[org.brute_damage]" :0, \ + (org.toggled) ? "Toggled ON" : "Toggled OFF",\ + (org.powered) ? "Power ON" : "Power OFF"),1) + else + user.show_message("\t Components are OK.",1) + if(H.emagged && prob(5)) + user.show_message("\t ERROR: INTERNAL SYSTEMS COMPROMISED",1) + user.show_message("Operating Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1) + + if("prosthetics") + + var/mob/living/carbon/human/H = M + to_chat(user, "Analyzing Results for \the [H]:") + to_chat(user, "Key: Electronics/Brute") + to_chat(user, "External prosthetics:") + var/organ_found + for(var/obj/item/organ/external/E in H.organs) + if(E.robotic < ORGAN_ROBOT) + continue + organ_found = 1 + to_chat(user, "[E.name]: [E.brute_dam] [E.burn_dam]") + if(!organ_found) + to_chat(user, "No prosthetics located.") + to_chat(user, "
            ") + to_chat(user, "Internal prosthetics:") + organ_found = null + for(var/obj/item/organ/O in H.internal_organs) + if(O.robotic < ORGAN_ROBOT) + continue + organ_found = 1 + to_chat(user, "[O.name]: [O.damage]") + if(!organ_found) + to_chat(user, "No prosthetics located.") + + src.add_fingerprint(user) + return diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm new file mode 100644 index 00000000..f4280ee0 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/component.dm @@ -0,0 +1,245 @@ +// TODO: remove the robot.mmi and robot.cell variables and completely rely on the robot component system + +/datum/robot_component/var/name +/datum/robot_component/var/installed = 0 +/datum/robot_component/var/powered = 0 +/datum/robot_component/var/toggled = 1 +/datum/robot_component/var/brute_damage = 0 +/datum/robot_component/var/electronics_damage = 0 +/datum/robot_component/var/idle_usage = 0 // Amount of power used every MC tick. In joules. +/datum/robot_component/var/active_usage = 0 // Amount of power used for every action. Actions are module-specific. Actuator for each tile moved, etc. +/datum/robot_component/var/max_damage = 30 // HP of this component. +/datum/robot_component/var/mob/living/silicon/robot/owner + +// The actual device object that has to be installed for this. +/datum/robot_component/var/external_type = null + +// The wrapped device(e.g. radio), only set if external_type isn't null +/datum/robot_component/var/obj/item/wrapped = null + +/datum/robot_component/New(mob/living/silicon/robot/R) + src.owner = R + +/datum/robot_component/proc/install() +/datum/robot_component/proc/uninstall() + +/datum/robot_component/proc/destroy() + if (istype(wrapped, /obj/item/robot_parts/robot_component)) + var/obj/item/robot_parts/robot_component/comp = wrapped + wrapped.icon_state = comp.icon_state_broken + + installed = -1 + uninstall() + +/datum/robot_component/proc/repair() + if (istype(wrapped, /obj/item/robot_parts/robot_component)) + var/obj/item/robot_parts/robot_component/comp = wrapped + wrapped.icon_state = comp.icon_state + + installed = 1 + install() + +/datum/robot_component/proc/take_damage(brute, electronics, sharp, edge) + if(installed != 1) return + + brute_damage += brute + electronics_damage += electronics + + if(brute_damage + electronics_damage >= max_damage) destroy() + +/datum/robot_component/proc/heal_damage(brute, electronics) + if(installed != 1) + // If it's not installed, can't repair it. + return 0 + + brute_damage = max(0, brute_damage - brute) + electronics_damage = max(0, electronics_damage - electronics) + +/datum/robot_component/proc/is_powered() + return (installed == 1) && (brute_damage + electronics_damage < max_damage) && (!idle_usage || powered) + +/datum/robot_component/proc/update_power_state() + if(toggled == 0) + powered = 0 + return + if(owner.cell_use_power(idle_usage)) + powered = 1 + else + powered = 0 + + +// ARMOUR +// Protects the cyborg from damage. Usually first module to be hit +// No power usage +/datum/robot_component/armour + name = "armour plating" + external_type = /obj/item/robot_parts/robot_component/armour + max_damage = 60 + + +// ACTUATOR +// Enables movement. +// Uses no power when idle. Uses 200J for each tile the cyborg moves. +/datum/robot_component/actuator + name = "actuator" + idle_usage = 0 + active_usage = 200 + external_type = /obj/item/robot_parts/robot_component/actuator + max_damage = 50 + + +//A fixed and much cleaner implementation of /tg/'s special snowflake code. +/datum/robot_component/actuator/is_powered() + return (installed == 1) && (brute_damage + electronics_damage < max_damage) + + +// POWER CELL +// Stores power (how unexpected..) +// No power usage +/datum/robot_component/cell + name = "power cell" + max_damage = 50 + var/obj/item/weapon/cell/stored_cell = null + +/datum/robot_component/cell/destroy() + ..() + stored_cell = owner.cell + owner.cell = null + +/datum/robot_component/cell/repair() + owner.cell = stored_cell + stored_cell = null + +// RADIO +// Enables radio communications +// Uses no power when idle. Uses 10J for each received radio message, 50 for each transmitted message. +/datum/robot_component/radio + name = "radio" + external_type = /obj/item/robot_parts/robot_component/radio + idle_usage = 15 //it's not actually possible to tell when we receive a message over our radio, so just use 10W every tick for passive listening + active_usage = 75 //transmit power + max_damage = 40 + + +// BINARY RADIO +// Enables binary communications with other cyborgs/AIs +// Uses no power when idle. Uses 10J for each received radio message, 50 for each transmitted message +/datum/robot_component/binary_communication + name = "binary communication device" + external_type = /obj/item/robot_parts/robot_component/binary_communication_device + idle_usage = 5 + active_usage = 25 + max_damage = 30 + + +// CAMERA +// Enables cyborg vision. Can also be remotely accessed via consoles. +// Uses 10J constantly +/datum/robot_component/camera + name = "camera" + external_type = /obj/item/robot_parts/robot_component/camera + idle_usage = 10 + max_damage = 40 + var/obj/machinery/camera/camera + +/datum/robot_component/camera/New(mob/living/silicon/robot/R) + ..() + camera = R.camera + +/datum/robot_component/camera/update_power_state() + ..() + if (camera) + camera.status = powered + +/datum/robot_component/camera/install() + if (camera) + camera.status = 1 + +/datum/robot_component/camera/uninstall() + if (camera) + camera.status = 0 + +/datum/robot_component/camera/destroy() + if (camera) + camera.status = 0 + +// SELF DIAGNOSIS MODULE +// Analyses cyborg's modules, providing damage readouts and basic information +// Uses 1kJ burst when analysis is done +/datum/robot_component/diagnosis_unit + name = "self-diagnosis unit" + active_usage = 1000 + external_type = /obj/item/robot_parts/robot_component/diagnosis_unit + max_damage = 30 + + + + +// HELPER STUFF + + + +// Initializes cyborg's components. Technically, adds default set of components to new borgs +/mob/living/silicon/robot/proc/initialize_components() + components["actuator"] = new/datum/robot_component/actuator(src) + components["radio"] = new/datum/robot_component/radio(src) + components["power cell"] = new/datum/robot_component/cell(src) + components["diagnosis unit"] = new/datum/robot_component/diagnosis_unit(src) + components["camera"] = new/datum/robot_component/camera(src) + components["comms"] = new/datum/robot_component/binary_communication(src) + components["armour"] = new/datum/robot_component/armour(src) + +// Checks if component is functioning +/mob/living/silicon/robot/proc/is_component_functioning(module_name) + var/datum/robot_component/C = components[module_name] + return C && C.installed == 1 && C.toggled && C.is_powered() + +// Returns component by it's string name +/mob/living/silicon/robot/proc/get_component(var/component_name) + var/datum/robot_component/C = components[component_name] + return C + + + +// COMPONENT OBJECTS + + + +// Component Objects +// These objects are visual representation of modules +/obj/item/robot_parts/robot_component + icon = 'icons/obj/robot_component.dmi' + icon_state = "working" + var/brute = 0 + var/burn = 0 + var/icon_state_broken = "broken" + +/obj/item/robot_parts/robot_component/binary_communication_device + name = "binary communication device" + icon_state = "binradio" + icon_state_broken = "binradio_broken" + +/obj/item/robot_parts/robot_component/actuator + name = "actuator" + icon_state = "motor" + icon_state_broken = "motor_broken" + +/obj/item/robot_parts/robot_component/armour + name = "armour plating" + icon_state = "armor" + icon_state_broken = "armor_broken" + +/obj/item/robot_parts/robot_component/camera + name = "camera" + icon_state = "camera" + icon_state_broken = "camera_broken" + +/obj/item/robot_parts/robot_component/diagnosis_unit + name = "diagnosis unit" + icon_state = "analyser" + icon_state_broken = "analyser_broken" + +/obj/item/robot_parts/robot_component/radio + name = "radio" + icon_state = "radio" + icon_state_broken = "radio_broken" \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/custom_sprites.dm b/code/modules/mob/living/silicon/robot/custom_sprites.dm new file mode 100644 index 00000000..766c636a --- /dev/null +++ b/code/modules/mob/living/silicon/robot/custom_sprites.dm @@ -0,0 +1,35 @@ + +//list(ckey = real_name,) +//Since the ckey is used as the icon_state, the current system will only permit a single custom robot sprite per ckey. +//While it might be possible for a ckey to use that custom sprite for several real_names, it seems rather pointless to support it. +var/list/robot_custom_icons + +/hook/startup/proc/load_robot_custom_sprites() + var/config_file = file2text("config/custom_sprites.txt") + var/list/lines = splittext(config_file, "\n") + + robot_custom_icons = list() + for(var/line in lines) + //split entry into ckey and real_name + var/split_idx = findtext(line, "-") //this works if ckey cannot contain dashes, and findtext starts from the beginning + if(!split_idx || split_idx == length(line)) + continue //bad entry + + var/ckey = copytext(line, 1, split_idx) + var/real_name = copytext(line, split_idx+1) + + robot_custom_icons[ckey] = real_name + return 1 + +/mob/living/silicon/robot/proc/set_custom_sprite() + var/rname = robot_custom_icons[ckey] + if(rname && rname == real_name) + custom_sprite = 1 + icon = CUSTOM_ITEM_SYNTH + var/list/valid_states = icon_states(icon) + if(icon_state == "robot") + if("[ckey]-Standard" in valid_states) + icon_state = "[ckey]-Standard" + else + to_chat(src, "Could not locate [ckey]-Standard sprite.") + icon = 'icons/mob/robots.dmi' diff --git a/code/modules/mob/living/silicon/robot/death.dm b/code/modules/mob/living/silicon/robot/death.dm new file mode 100644 index 00000000..bfb6b85e --- /dev/null +++ b/code/modules/mob/living/silicon/robot/death.dm @@ -0,0 +1,16 @@ +/mob/living/silicon/robot/dust() + //Delete the MMI first so that it won't go popping out. + if(mmi) + qdel(mmi) + ..() + +/mob/living/silicon/robot/death(gibbed,deathmessage, show_dead_message) + if(camera) + camera.status = 0 + if(module) + var/obj/item/weapon/gripper/G = locate(/obj/item/weapon/gripper) in module + if(G) G.drop_item() + locked = 0 + remove_robot_verbs() + sql_report_cyborg_death(src) + ..(gibbed,"shudders violently for a moment, then becomes motionless, its eyes slowly darkening.", "You have suffered a critical system failure, and are dead.") diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm new file mode 100644 index 00000000..66785d4c --- /dev/null +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -0,0 +1,410 @@ +var/list/mob_hat_cache = list() +/proc/get_hat_icon(var/obj/item/hat, var/offset_x = 0, var/offset_y = 0) + var/t_state = hat.icon_state + if(hat.item_state_slots && hat.item_state_slots[slot_head_str]) + t_state = hat.item_state_slots[slot_head_str] + else if(hat.item_state) + t_state = hat.item_state + var/key = "[t_state]_[offset_x]_[offset_y]" + if(!mob_hat_cache[key]) // Not ideal as there's no guarantee all hat icon_states + var/t_icon = default_onmob_icons[slot_head_str] // are unique across multiple dmis, but whatever. + if(hat.icon_override) + t_icon = hat.icon_override + else if(hat.item_icons && (slot_head_str in hat.item_icons)) + t_icon = hat.item_icons[slot_head_str] + var/image/I = image(icon = t_icon, icon_state = t_state) + I.pixel_x = offset_x + I.pixel_y = offset_y + mob_hat_cache[key] = I + return mob_hat_cache[key] + +/mob/living/silicon/robot/drone + name = "maintenance drone" + real_name = "drone" + icon = 'icons/mob/robots.dmi' + icon_state = "repairbot" + maxHealth = 35 + health = 35 + cell_emp_mult = 1 + universal_speak = 0 + universal_understand = 1 + gender = NEUTER + pass_flags = PASS_FLAG_TABLE + braintype = "Drone" + lawupdate = 0 + density = 1 + req_access = list(access_engine, access_robotics) + integrated_light_power = 3 + local_transmit = 1 + possession_candidate = 1 + speed = -1 + + can_pull_size = ITEM_SIZE_NORMAL + can_pull_mobs = MOB_PULL_SMALLER + + mob_bump_flag = SIMPLE_ANIMAL + mob_swap_flags = SIMPLE_ANIMAL + mob_push_flags = SIMPLE_ANIMAL + mob_always_swap = 1 + + mob_size = MOB_MEDIUM // Small mobs can't open doors, it's a huge pain for drones. + + laws = /datum/ai_laws/drone + + silicon_camera = /obj/item/device/camera/siliconcam/drone_camera + + //Used for self-mailing. + var/mail_destination = "" + var/module_type = /obj/item/weapon/robot_module/drone + var/obj/item/hat + var/hat_x_offset = 0 + var/hat_y_offset = -13 + + holder_type = /obj/item/weapon/holder/drone + +/mob/living/silicon/robot/drone/New() + ..() + GLOB.moved_event.register(src, src, /mob/living/silicon/robot/drone/proc/on_moved) + +/mob/living/silicon/robot/drone/Destroy() + if(hat) + hat.dropInto(loc) + hat = null + GLOB.moved_event.unregister(src, src, /mob/living/silicon/robot/drone/proc/on_moved) + . = ..() + +/mob/living/silicon/robot/drone/proc/on_moved(var/atom/movable/am, var/turf/old_loc, var/turf/new_loc) + old_loc = get_turf(old_loc) + new_loc = get_turf(new_loc) + + if(!(old_loc && new_loc)) // Allows inventive admins to move drones between non-adjacent Z-levels by moving them to null space first I suppose + return + if(AreConnectedZLevels(old_loc.z, new_loc.z)) + return + + // None of the tests passed, good bye + self_destruct() + +/mob/living/silicon/robot/drone/can_be_possessed_by(var/mob/observer/ghost/possessor) + if(!istype(possessor) || !possessor.client || !possessor.ckey) + return 0 + if(!config.allow_drone_spawn) + to_chat(src, "Playing as drones is not currently permitted.") + return 0 + if(too_many_active_drones()) + to_chat(src, "The maximum number of active drones has been reached..") + return 0 + if(jobban_isbanned(possessor,"Cyborg")) + to_chat(usr, "You are banned from playing synthetics and cannot spawn as a drone.") + return 0 + if(!possessor.MayRespawn(1,DRONE_SPAWN_DELAY)) + return 0 + return 1 + +/mob/living/silicon/robot/drone/do_possession(var/mob/observer/ghost/possessor) + if(!(istype(possessor) && possessor.ckey)) + return 0 + if(src.ckey || src.client) + to_chat(possessor, "\The [src] already has a player.") + return 0 + message_admins("[key_name_admin(possessor)] has taken control of \the [src].") + log_admin("[key_name(possessor)] took control of \the [src].") + transfer_personality(possessor.client) + qdel(possessor) + return 1 + +/mob/living/silicon/robot/drone/construction + name = "construction drone" + icon_state = "constructiondrone" + laws = /datum/ai_laws/construction_drone + module_type = /obj/item/weapon/robot_module/drone/construction + hat_x_offset = 1 + hat_y_offset = -12 + can_pull_size = ITEM_SIZE_NO_CONTAINER + can_pull_mobs = MOB_PULL_SAME + +/mob/living/silicon/robot/drone/New() + + ..() + + verbs += /mob/living/proc/hide + remove_language("Robot Talk") + add_language("Robot Talk", 0) + add_language("Drone Talk", 1) + + // NO BRAIN. + mmi = null + + //We need to screw with their HP a bit. They have around one fifth as much HP as a full borg. + for(var/V in components) if(V != "power cell") + var/datum/robot_component/C = components[V] + C.max_damage = 10 + + verbs -= /mob/living/silicon/robot/verb/Namepick + update_icon() + +/mob/living/silicon/robot/drone/init() + additional_law_channels["Drone"] = ":d" + if(!module) module = new module_type(src) + + flavor_text = "It's a tiny little repair drone. The casing is stamped with an corporate logo and the subscript: '[GLOB.using_map.company_name] Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'" + playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) + +//Redefining some robot procs... +/mob/living/silicon/robot/drone/fully_replace_character_name(pickedName as text) + // Would prefer to call the grandparent proc but this isn't possible, so.. + real_name = pickedName + SetName(real_name) + +/mob/living/silicon/robot/drone/updatename() + if(controlling_ai) + real_name = "remote drone ([controlling_ai.name])" + else + real_name = "[initial(name)] ([random_id(type,100,999)])" + SetName(real_name) + +/mob/living/silicon/robot/drone/update_icon() + + overlays.Cut() + if(stat == 0) + if(controlling_ai) + overlays += "eyes-[icon_state]-ai" + else if(emagged) + overlays += "eyes-[icon_state]-emag" + else + overlays += "eyes-[icon_state]" + else + overlays -= "eyes" + + if(hat) // Let the drones wear hats. + overlays |= get_hat_icon(hat, hat_x_offset, hat_y_offset) + +/mob/living/silicon/robot/drone/choose_icon() + return + +/mob/living/silicon/robot/drone/pick_module() + return + +/mob/living/silicon/robot/drone/proc/wear_hat(var/obj/item/new_hat) + if(hat) + return + hat = new_hat + new_hat.forceMove(src) + update_icon() + +//Drones cannot be upgraded with borg modules so we need to catch some items before they get used in ..(). +/mob/living/silicon/robot/drone/attackby(var/obj/item/weapon/W, var/mob/user) + + if(user.a_intent == I_HELP && istype(W, /obj/item/clothing/head)) + if(hat) + to_chat(user, "\The [src] is already wearing \the [hat].") + return + user.unEquip(W) + wear_hat(W) + user.visible_message("\The [user] puts \the [W] on \the [src].") + return + else if(istype(W, /obj/item/borg/upgrade/)) + to_chat(user, "\The [src] is not compatible with \the [W].") + return + + else if(isCrowbar(W)) + to_chat(user, "\The [src] is hermetically sealed. You can't open the case.") + return + + else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) + + if(stat == 2) + + if(!config.allow_drone_spawn || emagged || health < -35) //It's dead, Dave. + to_chat(user, "The interface is fried, and a distressing burned smell wafts from the robot's interior. You're not rebooting this one.") + return + + if(!allowed(usr)) + to_chat(user, "Access denied.") + return + + user.visible_message("\The [user] swipes \his ID card through \the [src], attempting to reboot it.", ">You swipe your ID card through \the [src], attempting to reboot it.") + request_player() + return + + else + user.visible_message("\The [user] swipes \his ID card through \the [src], attempting to shut it down.", "You swipe your ID card through \the [src], attempting to shut it down.") + + if(emagged) + return + + if(allowed(usr)) + shut_down() + else + to_chat(user, "Access denied.") + + return + + ..() + +/mob/living/silicon/robot/drone/emag_act(var/remaining_charges, var/mob/user) + if(!client || stat == 2) + to_chat(user, "There's not much point subverting this heap of junk.") + return + + if(emagged) + to_chat(src, "\The [user] attempts to load subversive software into you, but your hacked subroutines ignore the attempt.") + to_chat(user, "You attempt to subvert [src], but the sequencer has no effect.") + return + + to_chat(user, "You swipe the sequencer across [src]'s interface and watch its eyes flicker.") + if(controlling_ai) + to_chat(src, "\The [user] loads some kind of subversive software into the remote drone, corrupting its lawset but luckily sparing yours.") + else + to_chat(src, "You feel a sudden burst of malware loaded into your execute-as-root buffer. Your tiny brain methodically parses, loads and executes the script.") + + message_admins("[key_name_admin(user)] emagged drone [key_name_admin(src)]. Laws overridden.") + log_game("[key_name(user)] emagged drone [key_name(src)][controlling_ai ? " but AI [key_name(controlling_ai)] is in remote control" : " Laws overridden"].") + var/time = time2text(world.realtime,"hh:mm:ss") + GLOB.lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])") + + emagged = 1 + lawupdate = 0 + connected_ai = null + clear_supplied_laws() + clear_inherent_laws() + QDEL_NULL(laws) + laws = new /datum/ai_laws/syndicate_override + set_zeroth_law("Only [user.real_name] and people \he designates as being such are operatives.") + + if(!controlling_ai) + to_chat(src, "Obey these laws:") + laws.show_laws(src) + to_chat(src, "ALERT: [user.real_name] is your new master. Obey your new laws and \his commands.") + return 1 + +//DRONE LIFE/DEATH +//For some goddamn reason robots have this hardcoded. Redefining it for our fragile friends here. +/mob/living/silicon/robot/drone/updatehealth() + if(status_flags & GODMODE) + health = 35 + set_stat(CONSCIOUS) + return + health = 35 - (getBruteLoss() + getFireLoss()) + return + +//Easiest to check this here, then check again in the robot proc. +//Standard robots use config for crit, which is somewhat excessive for these guys. +//Drones killed by damage will gib. +/mob/living/silicon/robot/drone/handle_regular_status_updates() + if(health <= -35 && src.stat != DEAD) + self_destruct() + return + if(health <= 0 && src.stat != DEAD) + death() + return + ..() + +/mob/living/silicon/robot/drone/self_destruct() + timeofdeath = world.time + death() //Possibly redundant, having trouble making death() cooperate. + gib() + +//DRONE MOVEMENT. +/mob/living/silicon/robot/drone/slip_chance(var/prob_slip) + return 0 + +//CONSOLE PROCS +/mob/living/silicon/robot/drone/proc/law_resync() + + if(controlling_ai) + to_chat(src, "Someone issues a remote law reset order for this unit, but you disregard it.") + return + + if(stat != 2) + if(emagged) + to_chat(src, "You feel something attempting to modify your programming, but your hacked subroutines are unaffected.") + else + to_chat(src, "A reset-to-factory directive packet filters through your data connection, and you obediently modify your programming to suit it.") + full_law_reset() + show_laws() + +/mob/living/silicon/robot/drone/proc/shut_down() + + if(controlling_ai) + to_chat(src, "Someone issues a remote kill order for this unit, but you disregard it.") + return + + if(stat != 2) + if(emagged) + to_chat(src, "You feel a system kill order percolate through your tiny brain, but it doesn't seem like a good idea to you.") + else + to_chat(src, "You feel a system kill order percolate through your tiny brain, and you obediently destroy yourself.") + death() + +/mob/living/silicon/robot/drone/proc/full_law_reset() + clear_supplied_laws(1) + clear_inherent_laws(1) + clear_ion_laws(1) + QDEL_NULL(laws) + var/law_type = initial(laws) || GLOB.using_map.default_law_type + laws = new law_type + +//Reboot procs. + +/mob/living/silicon/robot/drone/proc/request_player() + if(too_many_active_drones()) + return + var/datum/ghosttrap/G = get_ghost_trap("maintenance drone") + G.request_player(src, "Someone is attempting to reboot a maintenance drone.", 30 SECONDS) + +/mob/living/silicon/robot/drone/proc/transfer_personality(var/client/player) + if(!player) return + src.ckey = player.ckey + + if(player.mob && player.mob.mind) + player.mob.mind.transfer_to(src) + + lawupdate = 0 + to_chat(src, "Systems rebooted. Loading base pattern maintenance protocol... loaded.") + full_law_reset() + welcome_drone() + +/mob/living/silicon/robot/drone/proc/welcome_drone() + to_chat(src, "You are a maintenance drone, a tiny-brained robotic repair machine. You have no individual will, no personality, and no drives or urges other than your laws.") + to_chat(src, "Remember, you are lawed against interference with the crew, you should leave the area if your actions are interfering, or that the crew does not want your presence.") + to_chat(src, "You are not required to follow orders from anyone; not the AI, not humans, and not other synthetics.. However, you should respond to presence requests issued from drone controls consoles.") + to_chat(src, "Use say ;Hello to talk to other drones and say Hello to speak silently to your nearby fellows.") + +/mob/living/silicon/robot/drone/add_robot_verbs() + return + +/mob/living/silicon/robot/drone/remove_robot_verbs() + return + +/mob/living/silicon/robot/drone/construction/welcome_drone() + to_chat(src, "You are a construction drone, an autonomous engineering and fabrication system..") + to_chat(src, "You are assigned to a Sol Central construction project. The name is irrelevant. Your task is to complete construction and subsystem integration as soon as possible.") + to_chat(src, "Use :d to talk to other drones and say to speak silently to your nearby fellows.") + to_chat(src, "You do not follow orders from anyone; not the AI, not humans, and not other synthetics..") + +/mob/living/silicon/robot/drone/construction/init() + ..() + flavor_text = "It's a bulky construction drone stamped with a Sol Central glyph." + +/proc/too_many_active_drones() + var/drones = 0 + for(var/mob/living/silicon/robot/drone/D in GLOB.silicon_mob_list) + if(D.key && D.client) + drones++ + return drones >= config.max_maint_drones + +/mob/living/silicon/robot/drone/show_laws(var/everyone = 0) + if(!controlling_ai) + return..() + to_chat(src, "Obey these laws:") + controlling_ai.laws_sanity_check() + controlling_ai.laws.show_laws(src) + +/mob/living/silicon/robot/drone/robot_checklaws() + set category = "Silicon Commands" + set name = "State Laws" + + if(!controlling_ai) + return ..() + controlling_ai.open_subsystem(/datum/nano_module/law_manager) diff --git a/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm b/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm new file mode 100644 index 00000000..35323565 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm @@ -0,0 +1,35 @@ +// DRONE ABILITIES +/mob/living/silicon/robot/drone/verb/set_mail_tag() + set name = "Set Mail Tag" + set desc = "Tag yourself for delivery through the disposals system." + set category = "Silicon Commands" + + var/new_tag = input("Select the desired destination.", "Set Mail Tag", null) as null|anything in GLOB.tagger_locations + + if(!new_tag) + mail_destination = "" + return + + to_chat(src, "You configure your internal beacon, tagging yourself for delivery to '[new_tag]'.") + mail_destination = new_tag + + //Auto flush if we use this verb inside a disposal chute. + var/obj/machinery/disposal/D = src.loc + if(istype(D)) + to_chat(src, "\The [D] acknowledges your signal.") + D.flush_count = D.flush_every_ticks + + return + +/mob/living/silicon/robot/drone/MouseDrop(atom/over_object) + var/mob/living/carbon/H = over_object + + if(istype(H) && Adjacent(H) && (usr == H) && (H.a_intent == "grab") && hat && !(H.l_hand && H.r_hand)) + hat.forceMove(get_turf(src)) + H.put_in_hands(hat) + H.visible_message("\The [H] removes \the [src]'s [hat].") + hat = null + update_icons() + return + + return ..() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/drone/drone_console.dm b/code/modules/mob/living/silicon/robot/drone/drone_console.dm new file mode 100644 index 00000000..5922fadc --- /dev/null +++ b/code/modules/mob/living/silicon/robot/drone/drone_console.dm @@ -0,0 +1,122 @@ +/obj/machinery/computer/drone_control + name = "Maintenance Drone Control" + desc = "Used to monitor the drone population and the assembler that services them." + icon = 'icons/obj/computer.dmi' + icon_keyboard = "power_key" + icon_screen = "power" + req_access = list(access_engine_equip) + circuit = /obj/item/weapon/circuitboard/drone_control + + //Used when pinging drones. + var/drone_call_area = "Engineering" + //Used to enable or disable drone fabrication. + var/obj/machinery/drone_fabricator/dronefab + +/obj/machinery/computer/drone_control/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/drone_control/attack_hand(var/mob/user as mob) + if(..()) + return + + if(!allowed(user)) + to_chat(user, "Access denied.") + return + + user.set_machine(src) + var/dat + dat += "Maintenance Units
            " + + for(var/mob/living/silicon/robot/drone/D in world) + if(D.z != src.z) + continue + dat += "
            [D.real_name] ([D.stat == 2 ? "INACTIVE" : "ACTIVE"])" + dat += "
            Cell charge: [D.cell.charge]/[D.cell.maxcharge]." + dat += "
            Currently located in: [get_area(D)]." + dat += "
            Resync | Shutdown
            " + + dat += "

            Request drone presence in area: [drone_call_area] (Send ping)" + + dat += "

            Drone fabricator: " + dat += "[dronefab ? "[(dronefab.produce_drones && !(dronefab.stat & NOPOWER)) ? "ACTIVE" : "INACTIVE"]" : "FABRICATOR NOT DETECTED. (search)"]" + user << browse(dat, "window=computer;size=400x500") + onclose(user, "computer") + return + + +/obj/machinery/computer/drone_control/Topic(href, href_list) + if((. = ..())) + return + + if(!allowed(usr)) + to_chat(usr, "Access denied.") + return + + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) + usr.set_machine(src) + + if (href_list["setarea"]) + + //Probably should consider using another list, but this one will do. + var/t_area = input("Select the area to ping.", "Set Target Area", null) as null|anything in GLOB.tagger_locations + + if(!t_area) + return + + drone_call_area = t_area + to_chat(usr, "You set the area selector to [drone_call_area].") + + else if (href_list["ping"]) + + to_chat(usr, "You issue a maintenance request for all active drones, highlighting [drone_call_area].") + for(var/mob/living/silicon/robot/drone/D in world) + if(D.client && D.stat == 0) + to_chat(D, "-- Maintenance drone presence requested in: [drone_call_area].") + + else if (href_list["resync"]) + + var/mob/living/silicon/robot/drone/D = locate(href_list["resync"]) + + if(D.stat != 2) + to_chat(usr, "You issue a law synchronization directive for the drone.") + D.law_resync() + + else if (href_list["shutdown"]) + + var/mob/living/silicon/robot/drone/D = locate(href_list["shutdown"]) + + if(D.stat != 2) + to_chat(usr, "You issue a kill command for the unfortunate drone.") + message_admins("[key_name_admin(usr)] issued kill order for drone [key_name_admin(D)] from control console.") + log_game("[key_name(usr)] issued kill order for [key_name(src)] from control console.") + D.shut_down() + + else if (href_list["search_fab"]) + if(dronefab) + return + + for(var/obj/machinery/drone_fabricator/fab in oview(3,src)) + + if(fab.stat & NOPOWER) + continue + + dronefab = fab + to_chat(usr, "Drone fabricator located.") + return + + to_chat(usr, "Unable to locate drone fabricator.") + + else if (href_list["toggle_fab"]) + + if(!dronefab) + return + + if(get_dist(src,dronefab) > 3) + dronefab = null + to_chat(usr, "Unable to locate drone fabricator.") + return + + dronefab.produce_drones = !dronefab.produce_drones + to_chat(usr, "You [dronefab.produce_drones ? "enable" : "disable"] drone production in the nearby fabricator.") + + src.updateUsrDialog() diff --git a/code/modules/mob/living/silicon/robot/drone/drone_damage.dm b/code/modules/mob/living/silicon/robot/drone/drone_damage.dm new file mode 100644 index 00000000..f7256df3 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/drone/drone_damage.dm @@ -0,0 +1,28 @@ +//Redefining some robot procs, since drones can't be repaired and really shouldn't take component damage. +/mob/living/silicon/robot/drone + var/fireloss = 0 + var/bruteloss = 0 + +/mob/living/silicon/robot/drone/take_overall_damage(var/brute = 0, var/burn = 0, var/sharp = 0, var/used_weapon = null) + bruteloss += brute + fireloss += burn + +/mob/living/silicon/robot/drone/heal_overall_damage(var/brute, var/burn) + + bruteloss -= brute + fireloss -= burn + + if(bruteloss<0) bruteloss = 0 + if(fireloss<0) fireloss = 0 + +/mob/living/silicon/robot/drone/take_organ_damage(var/brute = 0, var/burn = 0, var/sharp = 0, var/emp = 0) + take_overall_damage(brute,burn) + +/mob/living/silicon/robot/drone/heal_organ_damage(var/brute, var/burn) + heal_overall_damage(brute,burn) + +/mob/living/silicon/robot/drone/getFireLoss() + return fireloss + +/mob/living/silicon/robot/drone/getBruteLoss() + return bruteloss \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm new file mode 100644 index 00000000..64af119d --- /dev/null +++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm @@ -0,0 +1,440 @@ +//Simple borg hand. +//Limited use. +/obj/item/weapon/gripper + name = "magnetic gripper" + desc = "A simple grasping tool specialized in construction and engineering work." + icon = 'icons/obj/device.dmi' + icon_state = "gripper" + + item_flags = ITEM_FLAG_NO_BLUDGEON + + //Has a list of items that it can hold. + var/list/can_hold = list( + /obj/item/weapon/cell, + /obj/item/weapon/firealarm_electronics, + /obj/item/weapon/airalarm_electronics, + /obj/item/weapon/airlock_electronics, + /obj/item/weapon/tracker_electronics, + /obj/item/weapon/module/power_control, + /obj/item/weapon/stock_parts, + /obj/item/frame, + /obj/item/weapon/camera_assembly, + /obj/item/weapon/tank, + /obj/item/weapon/circuitboard, + /obj/item/weapon/smes_coil, + /obj/item/weapon/computer_hardware, + /obj/item/weapon/fuel_assembly + ) + + var/obj/item/wrapped = null // Item currently being held. + +// VEEEEERY limited version for mining borgs. Basically only for swapping cells and upgrading the drills. +/obj/item/weapon/gripper/miner + name = "drill maintenance gripper" + desc = "A simple grasping tool for the maintenance of heavy drilling machines." + icon_state = "gripper-mining" + + can_hold = list( + /obj/item/weapon/cell, + /obj/item/weapon/stock_parts, + /obj/item/weapon/circuitboard/miningdrill + ) + +/obj/item/weapon/gripper/paperwork + name = "paperwork gripper" + desc = "A simple grasping tool for clerical work." + + can_hold = list( + /obj/item/weapon/clipboard, + /obj/item/weapon/paper, + /obj/item/weapon/paper_bundle, + /obj/item/weapon/card/id, + /obj/item/weapon/book, + /obj/item/weapon/newspaper + ) + +/obj/item/weapon/gripper/chemistry + name = "chemistry gripper" + desc = "A simple grasping tool for chemical work." + + can_hold = list( + /obj/item/weapon/reagent_containers/glass, + /obj/item/weapon/reagent_containers/pill, + /obj/item/weapon/reagent_containers/ivbag, + /obj/item/weapon/storage/pill_bottle, + ) + +/obj/item/weapon/gripper/research //A general usage gripper, used for toxins/robotics/xenobio/etc + name = "scientific gripper" + icon_state = "gripper-sci" + desc = "A simple grasping tool suited to assist in a wide array of research applications." + + can_hold = list( + /obj/item/weapon/cell, + /obj/item/weapon/stock_parts, + /obj/item/device/mmi, + /obj/item/robot_parts, + /obj/item/borg/upgrade, + /obj/item/device/flash, + /obj/item/organ/internal/brain, + /obj/item/organ/internal/posibrain, + /obj/item/stack/cable_coil, + /obj/item/weapon/circuitboard, + /obj/item/slime_extract, + /obj/item/weapon/reagent_containers/glass, + /obj/item/weapon/reagent_containers/food/snacks/monkeycube, + /obj/item/mecha_parts, + /obj/item/weapon/computer_hardware, + /obj/item/device/transfer_valve, + /obj/item/device/assembly/signaler, + /obj/item/device/assembly/timer, + /obj/item/device/assembly/igniter, + /obj/item/device/assembly/infra, + /obj/item/weapon/tank + ) + +/obj/item/weapon/gripper/service //Used to handle food, drinks, and seeds. + name = "service gripper" + icon_state = "gripper" + desc = "A simple grasping tool used to perform tasks in the service sector, such as handling food, drinks, and seeds." + + can_hold = list( + /obj/item/weapon/reagent_containers/glass, + /obj/item/weapon/reagent_containers/food, + /obj/item/seeds, + /obj/item/weapon/grown, + /obj/item/weapon/glass_extra + ) + +/obj/item/weapon/gripper/organ //Used to handle organs. + name = "organ gripper" + icon_state = "gripper" + desc = "A simple grasping tool for holding and manipulating organic and mechanical organs, both internal and external." + + can_hold = list( + /obj/item/organ, + /obj/item/robot_parts + ) + +/obj/item/weapon/gripper/no_use //Used when you want to hold and put items in other things, but not able to 'use' the item + +/obj/item/weapon/gripper/no_use/attack_self(mob/user as mob) + return + +/obj/item/weapon/gripper/no_use/loader //This is used to disallow building with metal. + name = "sheet loader" + desc = "A specialized loading device, designed to pick up and insert sheets of materials inside machines." + icon_state = "gripper-sheet" + + can_hold = list( + /obj/item/stack/material + ) + +/obj/item/weapon/gripper/examine(mob/user) + . = ..() + if(wrapped) + to_chat(user, "It is holding \a [wrapped].") + +/obj/item/weapon/gripper/attack_self(mob/user as mob) + if(wrapped) + return wrapped.attack_self(user) + return ..() + +/obj/item/weapon/gripper/verb/drop_item() + + set name = "Drop Item" + set desc = "Release an item from your magnetic gripper." + set category = "Silicon Commands" + + if(!wrapped) + //There's some weirdness with items being lost inside the arm. Trying to fix all cases. ~Z + for(var/obj/item/thing in src.contents) + thing.loc = get_turf(src) + return + + if(wrapped.loc != src) + wrapped = null + return + + to_chat(src.loc, "You drop \the [wrapped].") + wrapped.loc = get_turf(src) + wrapped = null + //update_icon() + +/obj/item/weapon/gripper/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) + // Don't fall through and smack people with gripper, instead just no-op + return 0 + +/obj/item/weapon/gripper/resolve_attackby(var/atom/target, var/mob/living/user, params) + + //There's some weirdness with items being lost inside the arm. Trying to fix all cases. ~Z + if(!wrapped) + for(var/obj/item/thing in src.contents) + wrapped = thing + break + + if(wrapped) //Already have an item. + //Temporary put wrapped into user so target's attackby() checks pass. + wrapped.loc = user //should we use forceMove() here? It is a virtual move after all, that is intended to be reset + + //The force of the wrapped obj gets set to zero during the attack() and afterattack(). + var/force_holder = wrapped.force + wrapped.force = 0.0 + + //Pass the attack on to the target. This might delete/relocate wrapped. + var/resolved = wrapped.resolve_attackby(target,user,params) + if(!resolved && wrapped && target) + wrapped.afterattack(target,user,1,params) + + if(wrapped) + wrapped.force = force_holder + + //If wrapped was neither deleted nor put into target, put it back into the gripper. + if(wrapped && user && (wrapped.loc == user)) + wrapped.loc = src + else + wrapped = null + return + + else if(istype(target,/obj/item)) //Check that we're not pocketing a mob. + + //...and that the item is not in a container. + if(!isturf(target.loc)) + return + + var/obj/item/I = target + + //Check if the item is blacklisted. + var/grab = 0 + for(var/typepath in can_hold) + if(istype(I,typepath)) + grab = 1 + break + + //We can grab the item, finally. + if(grab) + to_chat(user, "You collect \the [I].") + I.loc = src + wrapped = I + return + else + to_chat(user, "Your gripper cannot hold \the [target].") + + else if(istype(target,/obj/machinery/power/apc)) + var/obj/machinery/power/apc/A = target + if(A.opened) + if(A.cell) + + wrapped = A.cell + + A.cell.add_fingerprint(user) + A.cell.update_icon() + A.cell.loc = src + A.cell = null + + A.charging = 0 + A.update_icon() + + user.visible_message("[user] removes the power cell from [A]!", "You remove the power cell.") + + else if(istype(target,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/A = target + if(A.opened) + if(A.cell) + + wrapped = A.cell + + A.cell.add_fingerprint(user) + A.cell.update_icon() + A.update_icon() + A.cell.loc = src + A.cell = null + + user.visible_message("[user] removes the power cell from [A]!", "You remove the power cell.") + +//TODO: Matter decompiler. +/obj/item/weapon/matter_decompiler + + name = "matter decompiler" + desc = "Eating trash, bits of glass, or other debris will replenish your stores." + icon = 'icons/obj/device.dmi' + icon_state = "decompiler" + + //Metal, glass, wood, plastic. + var/datum/matter_synth/metal = null + var/datum/matter_synth/glass = null + var/datum/matter_synth/wood = null + var/datum/matter_synth/plastic = null + +/obj/item/weapon/matter_decompiler/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) + return + +/obj/item/weapon/matter_decompiler/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, proximity, params) + + if(!proximity) return //Not adjacent. + + //We only want to deal with using this on turfs. Specific items aren't important. + var/turf/T = get_turf(target) + if(!istype(T)) + return + + //Used to give the right message. + var/grabbed_something = 0 + + for(var/mob/M in T) + if(istype(M,/mob/living/simple_animal/lizard) || istype(M,/mob/living/simple_animal/mouse)) + src.loc.visible_message("[src.loc] sucks [M] into its decompiler. There's a horrible crunching noise.","It's a bit of a struggle, but you manage to suck [M] into your decompiler. It makes a series of visceral crunching noises.") + new/obj/effect/decal/cleanable/blood/splatter(get_turf(src)) + qdel(M) + if(wood) + wood.add_charge(2000) + if(plastic) + plastic.add_charge(2000) + return + + else if(istype(M,/mob/living/silicon/robot/drone) && !M.client) + + var/mob/living/silicon/robot/D = src.loc + + if(!istype(D)) + return + + to_chat(D, "You begin decompiling [M].") + + if(!do_after(D,50,M)) + to_chat(D, "You need to remain still while decompiling such a large object.") + return + + if(!M || !D) return + + to_chat(D, "You carefully and thoroughly decompile [M], storing as much of its resources as you can within yourself.") + qdel(M) + new/obj/effect/decal/cleanable/blood/oil(get_turf(src)) + + if(metal) + metal.add_charge(15000) + if(glass) + glass.add_charge(15000) + if(wood) + wood.add_charge(2000) + if(plastic) + plastic.add_charge(1000) + return + else + continue + + for(var/obj/W in T) + //Different classes of items give different commodities. + if(istype(W,/obj/item/weapon/cigbutt)) + if(plastic) + plastic.add_charge(500) + else if(istype(W,/obj/effect/spider/spiderling)) + if(wood) + wood.add_charge(2000) + if(plastic) + plastic.add_charge(2000) + else if(istype(W,/obj/item/weapon/light)) + var/obj/item/weapon/light/L = W + if(L.status >= 2) //In before someone changes the inexplicably local defines. ~ Z + if(metal) + metal.add_charge(250) + if(glass) + glass.add_charge(250) + else + continue + else if(istype(W,/obj/item/remains/robot)) + if(metal) + metal.add_charge(2000) + if(plastic) + plastic.add_charge(2000) + if(glass) + glass.add_charge(1000) + else if(istype(W,/obj/item/trash)) + if(metal) + metal.add_charge(1000) + if(plastic) + plastic.add_charge(3000) + else if(istype(W,/obj/effect/decal/cleanable/blood/gibs/robot)) + if(metal) + metal.add_charge(2000) + if(glass) + glass.add_charge(2000) + else if(istype(W,/obj/item/ammo_casing)) + if(metal) + metal.add_charge(1000) + else if(istype(W,/obj/item/weapon/material/shard/shrapnel)) + if(metal) + metal.add_charge(1000) + else if(istype(W,/obj/item/weapon/material/shard)) + if(glass) + glass.add_charge(1000) + else if(istype(W,/obj/item/weapon/reagent_containers/food/snacks/grown)) + if(wood) + wood.add_charge(4000) + else if(istype(W,/obj/item/pipe)) + // This allows drones and engiborgs to clear pipe assemblies from floors. + else + continue + + qdel(W) + grabbed_something = 1 + + if(grabbed_something) + to_chat(user, "You deploy your decompiler and clear out the contents of \the [T].") + else + to_chat(user, "Nothing on \the [T] is useful to you.") + return + +//PRETTIER TOOL LIST. +/mob/living/silicon/robot/drone/installed_modules() + + if(weapon_lock) + to_chat(src, "Weapon lock active, unable to use modules! Count:[weaponlock_time]") + return + + if(!module) + module = new /obj/item/weapon/robot_module/drone(src) + + var/dat = "Drone modules\n" + dat += {" + Activated Modules +
            + Module 1: [module_state_1 ? "[module_state_1]" : "No Module"]
            + Module 2: [module_state_2 ? "
            [module_state_2]" : "No Module"]
            + Module 3: [module_state_3 ? "
            [module_state_3]" : "No Module"]
            +
            + Installed Modules

            "} + + + var/tools = "Tools and devices
            " + var/resources = "
            Resources
            " + + for (var/O in module.modules) + + var/module_string = "" + + if (!O) + module_string += text("Resource depleted
            ") + else if(activated(O)) + module_string += text("[O]: Activated
            ") + else + module_string += text("[O]:
            Activate
            ") + + if((istype(O,/obj/item/weapon) || istype(O,/obj/item/device)) && !(istype(O,/obj/item/stack/cable_coil))) + tools += module_string + else + resources += module_string + + dat += tools + + if (emagged) + if (!module.emag) + dat += text("Resource depleted
            ") + else if(activated(module.emag)) + dat += text("[module.emag]: Activated
            ") + else + dat += text("[module.emag]: Activate
            ") + + dat += resources + + src << browse(dat, "window=robotmod") diff --git a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm new file mode 100644 index 00000000..7852dae4 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm @@ -0,0 +1,141 @@ +/proc/count_drones() + var/drones = 0 + for(var/mob/living/silicon/robot/drone/D in world) + if(D.key && D.client) + drones++ + return drones + +/obj/machinery/drone_fabricator + name = "drone fabricator" + desc = "A large automated factory for producing maintenance drones." + appearance_flags = 0 + + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 20 + active_power_usage = 5000 + + var/fabricator_tag = "Exodus" + var/drone_progress = 0 + var/produce_drones = 1 + var/time_last_drone = 500 + var/drone_type = /mob/living/silicon/robot/drone + + icon = 'icons/obj/machines/drone_fab.dmi' + icon_state = "drone_fab_idle" + +/obj/machinery/drone_fabricator/derelict + name = "construction drone fabricator" + fabricator_tag = "Derelict" + drone_type = /mob/living/silicon/robot/drone/construction + +/obj/machinery/drone_fabricator/New() + ..() + +/obj/machinery/drone_fabricator/power_change() + ..() + if (stat & NOPOWER) + icon_state = "drone_fab_nopower" + +/obj/machinery/drone_fabricator/Process() + + if(ticker.current_state < GAME_STATE_PLAYING) + return + + if(stat & NOPOWER || !produce_drones) + if(icon_state != "drone_fab_nopower") icon_state = "drone_fab_nopower" + return + + if(drone_progress >= 100) + icon_state = "drone_fab_idle" + return + + icon_state = "drone_fab_active" + var/elapsed = world.time - time_last_drone + drone_progress = round((elapsed/config.drone_build_time)*100) + + if(drone_progress >= 100) + visible_message("\The [src] voices a strident beep, indicating a drone chassis is prepared.") + +/obj/machinery/drone_fabricator/examine(mob/user) + . = ..(user) + if(produce_drones && drone_progress >= 100 && isghost(user) && config.allow_drone_spawn && count_drones() < config.max_maint_drones) + to_chat(user, "
            A drone is prepared. Select 'Join As Drone' from the Ghost tab to spawn as a maintenance drone.") + +/obj/machinery/drone_fabricator/proc/create_drone(var/client/player) + + if(stat & NOPOWER) + return + + if(!produce_drones || !config.allow_drone_spawn || count_drones() >= config.max_maint_drones) + return + + if(player && !isghost(player.mob)) + return + + visible_message("\The [src] churns and grinds as it lurches into motion, disgorging a shiny new drone after a few moments.") + flick("h_lathe_leave",src) + drone_progress = 0 + time_last_drone = world.time + + var/mob/living/silicon/robot/drone/new_drone = new drone_type(get_turf(src)) + if(player) + announce_ghost_joinleave(player, 0, "They have taken control over a maintenance drone.") + if(player.mob && player.mob.mind) player.mob.mind.reset() + new_drone.transfer_personality(player) + + return new_drone +/* +/mob/observer/ghost/verb/join_as_drone() + set category = "Ghost" + set name = "Join As Drone" + set desc = "If there is a powered, enabled fabricator in the game world with a prepared chassis, join as a maintenance drone." + try_drone_spawn(src) +*/ +/proc/try_drone_spawn(var/mob/user, var/obj/machinery/drone_fabricator/fabricator) + + if(ticker.current_state < GAME_STATE_PLAYING) + to_chat(user, "The game hasn't started yet!") + return + + if(!(config.allow_drone_spawn)) + to_chat(user, "That verb is not currently permitted.") + return + + if(jobban_isbanned(user,"Cyborg")) + to_chat(user, "You are banned from playing synthetics and cannot spawn as a drone.") + return + + if(config.use_age_restriction_for_jobs && isnum(user.client.player_age)) + if(user.client.player_age <= 3) + to_chat(user, " Your account is not old enough to play as a maintenance drone.") + return + + if(!user.MayRespawn(1, DRONE_SPAWN_DELAY)) + return + + if(!fabricator) + + var/list/all_fabricators = list() + for(var/obj/machinery/drone_fabricator/DF in SSmachines.machinery) + if((DF.stat & NOPOWER) || !DF.produce_drones || DF.drone_progress < 100) + continue + all_fabricators[DF.fabricator_tag] = DF + + if(!all_fabricators.len) + to_chat(user, "There are no available drone spawn points, sorry.") + return + + var/choice = input(user,"Which fabricator do you wish to use?") as null|anything in all_fabricators + if(!choice || !all_fabricators[choice]) + return + fabricator = all_fabricators[choice] + + if(user && fabricator && !((fabricator.stat & NOPOWER) || !fabricator.produce_drones || fabricator.drone_progress < 100)) + log_and_message_admins("has joined the round as a maintenance drone.") + var/mob/drone = fabricator.create_drone(user.client) + if(drone) + drone.status_flags |= NO_ANTAG + return 1 + return \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/drone/drone_remote_control.dm b/code/modules/mob/living/silicon/robot/drone/drone_remote_control.dm new file mode 100644 index 00000000..79c73531 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/drone/drone_remote_control.dm @@ -0,0 +1,117 @@ +/mob/living/silicon/ai + var/mob/living/silicon/robot/drone/controlling_drone + +/mob/living/silicon/robot/drone + var/mob/living/silicon/ai/controlling_ai + +/mob/living/silicon/robot/drone/attack_ai(var/mob/living/silicon/ai/user) + + if(!istype(user) || controlling_ai || !config.allow_drone_spawn) + return + + if(stat != 2 || client || key) + to_chat(user, "You cannot take control of an autonomous, active drone.") + return + + if(health < -35 || emagged) + to_chat(user, "WARNING: connection timed out.") + return + + user.controlling_drone = src + controlling_ai = user + verbs += /mob/living/silicon/robot/drone/proc/release_ai_control_verb + local_transmit = FALSE + languages.Cut() + speech_synthesizer_langs.Cut() + + for(var/datum/language/L in controlling_ai.languages) + add_language(L.name, 0) + add_language("Drone Talk", 1) + default_language = all_languages["Drone Talk"] + + stat = CONSCIOUS + if(user.mind) + user.mind.transfer_to(src) + else + key = user.key + updatename() + to_chat(src, "You have shunted your primary control loop into \a [initial(name)]. Use the Release Control verb to return to your core.") + +/obj/machinery/drone_fabricator/attack_ai(var/mob/living/silicon/ai/user) + + if(!istype(user) || user.controlling_drone || !config.allow_drone_spawn) + return + + if(stat & NOPOWER) + to_chat(user, "\The [src] is unpowered.") + return + + if(!produce_drones) + to_chat(user, "\The [src] is disabled.") + return + + if(drone_progress < 100) + to_chat(user, "\The [src] is not ready to produce a new drone.") + return + + if(count_drones() >= config.max_maint_drones) + to_chat(user, "The drone control subsystems are tasked to capacity; they cannot support any more drones.") + return + + var/mob/living/silicon/robot/drone/new_drone = create_drone() + user.controlling_drone = new_drone + new_drone.controlling_ai = user + new_drone.verbs += /mob/living/silicon/robot/drone/proc/release_ai_control_verb + new_drone.local_transmit = FALSE + new_drone.languages.Cut() + new_drone.speech_synthesizer_langs.Cut() + for(var/datum/language/L in new_drone.controlling_ai.languages) + new_drone.add_language(L.name, 0) + new_drone.add_language("Drone Talk", 1) + new_drone.default_language = all_languages["Drone Talk"] + + if(user.mind) + user.mind.transfer_to(new_drone) + else + new_drone.key = user.key + new_drone.updatename() + + to_chat(new_drone, "You have shunted your primary control loop into \a [initial(new_drone.name)]. Use the Release Control verb to return to your core.") + +/mob/living/silicon/robot/drone/death(gibbed) + if(controlling_ai) + release_ai_control("WARNING: remote system failure. Connection timed out.") + . = ..(gibbed) + +/mob/living/silicon/ai/death(gibbed) + if(controlling_drone) + controlling_drone.release_ai_control("WARNING: Primary control loop failure. Session terminated.") + . = ..(gibbed) + +/mob/living/silicon/ai/Life() + . = ..() + if(controlling_drone && stat != CONSCIOUS) + controlling_drone.release_ai_control("WARNING: Primary control loop failure. Session terminated.") + +/mob/living/silicon/robot/drone/proc/release_ai_control_verb() + set name = "Release Control" + set desc = "Release control of a remote drone." + set category = "Silicon Commands" + + release_ai_control("Remote session terminated.") + +/mob/living/silicon/robot/drone/proc/release_ai_control(var/message = "Connection terminated.") + + if(controlling_ai) + if(mind) + mind.transfer_to(controlling_ai) + else + controlling_ai.key = key + to_chat(controlling_ai, "[message]") + controlling_ai.controlling_drone = null + controlling_ai = null + + verbs -= /mob/living/silicon/robot/drone/proc/release_ai_control_verb + full_law_reset() + updatename() + death() diff --git a/code/modules/mob/living/silicon/robot/drone/drone_say.dm b/code/modules/mob/living/silicon/robot/drone/drone_say.dm new file mode 100644 index 00000000..01d69e04 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/drone/drone_say.dm @@ -0,0 +1,38 @@ +/mob/living/silicon/robot/drone/say(var/message) + if(local_transmit) + if (src.client) + if(client.prefs.muted & MUTE_IC) + to_chat(src, "You cannot send IC messages (muted).") + return 0 + + message = sanitize(message) + + if (stat == DEAD) + return say_dead(message) + + if(copytext(message,1,2) == "*") + return emote(copytext(message,2)) + + if(copytext(message,1,2) == ";") + var/datum/language/L = all_languages["Drone Talk"] + if(istype(L)) + return L.broadcast(src,trim(copytext(message,2))) + + //Must be concious to speak + if (stat) + return 0 + + var/list/listeners = hearers(5,src) + listeners |= src + + for(var/mob/living/silicon/D in listeners) + if(D.client && D.local_transmit) + to_chat(D, "[src] transmits, \"[message]\"") + + for (var/mob/M in GLOB.player_list) + if (istype(M, /mob/new_player)) + continue + else if(M.stat == DEAD && M.get_preference_value(/datum/client_preference/ghost_ears) == GLOB.PREF_ALL_SPEECH) + if(M.client) to_chat(M, "[src] transmits, \"[message]\"") + return 1 + return ..(message, 0) diff --git a/code/modules/mob/living/silicon/robot/examine.dm b/code/modules/mob/living/silicon/robot/examine.dm new file mode 100644 index 00000000..3693c642 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/examine.dm @@ -0,0 +1,43 @@ +/mob/living/silicon/robot/examine(mob/user) + var/custom_infix = custom_name ? ", [modtype] [braintype]" : "" + . = ..(user, infix = custom_infix) + + var/msg = "" + msg += "" + if (src.getBruteLoss()) + if (src.getBruteLoss() < 75) + msg += "It looks slightly dented.\n" + else + msg += "It looks severely dented!\n" + if (src.getFireLoss()) + if (src.getFireLoss() < 75) + msg += "It looks slightly charred.\n" + else + msg += "It looks severely burnt and heat-warped!\n" + msg += "" + + if(opened) + msg += "Its cover is open and the power cell is [cell ? "installed" : "missing"].\n" + else + msg += "Its cover is closed.\n" + + if(!has_power) + msg += "It appears to be running on backup power.\n" + + switch(src.stat) + if(CONSCIOUS) + if(!src.client) msg += "It appears to be in stand-by mode.\n" //afk + if(UNCONSCIOUS) msg += "It doesn't seem to be responding.\n" + if(DEAD) msg += "It looks completely unsalvageable.\n" + msg += "*---------*" + + if(print_flavor_text()) msg += "\n[print_flavor_text()]\n" + + if (pose) + if( findtext(pose,".",length(pose)) == 0 && findtext(pose,"!",length(pose)) == 0 && findtext(pose,"?",length(pose)) == 0 ) + pose = addtext(pose,".") //Makes sure all emotes end with a period. + msg += "\nIt is [pose]" + + to_chat(user, msg) + user.showLaws(src) + return diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm new file mode 100644 index 00000000..699ec5c1 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -0,0 +1,251 @@ +//These procs handle putting s tuff in your hand. It's probably best to use these rather than setting stuff manually +//as they handle all relevant stuff like adding it to the player's screen and such + +//Returns the thing in our active hand (whatever is in our active module-slot, in this case) +/mob/living/silicon/robot/get_active_hand() + return module_active + +/*-------TODOOOOOOOOOO--------*/ + +//Verbs used by hotkeys. +/mob/living/silicon/robot/verb/cmd_unequip_module() + set name = "unequip-module" + set hidden = 1 + uneq_active() + +/mob/living/silicon/robot/verb/cmd_toggle_module(module as num) + set name = "toggle-module" + set hidden = 1 + toggle_module(module) + +/mob/living/silicon/robot/proc/uneq_active() + if(isnull(module_active)) + return + if(module_state_1 == module_active) + if(istype(module_state_1,/obj/item/borg/sight)) + sight_mode &= ~module_state_1:sight_mode + if (client) + client.screen -= module_state_1 + contents -= module_state_1 + module_active = null + module_state_1:loc = module //So it can be used again later + module_state_1 = null + inv1.icon_state = "inv1" + else if(module_state_2 == module_active) + if(istype(module_state_2,/obj/item/borg/sight)) + sight_mode &= ~module_state_2:sight_mode + if (client) + client.screen -= module_state_2 + contents -= module_state_2 + module_active = null + module_state_2:loc = module + module_state_2 = null + inv2.icon_state = "inv2" + else if(module_state_3 == module_active) + if(istype(module_state_3,/obj/item/borg/sight)) + sight_mode &= ~module_state_3:sight_mode + if (client) + client.screen -= module_state_3 + contents -= module_state_3 + module_active = null + module_state_3:loc = module + module_state_3 = null + inv3.icon_state = "inv3" + update_icon() + +/mob/living/silicon/robot/proc/uneq_all() + module_active = null + + if(module_state_1) + if(istype(module_state_1,/obj/item/borg/sight)) + sight_mode &= ~module_state_1:sight_mode + if (client) + client.screen -= module_state_1 + contents -= module_state_1 + module_state_1:loc = module + module_state_1 = null + inv1.icon_state = "inv1" + if(module_state_2) + if(istype(module_state_2,/obj/item/borg/sight)) + sight_mode &= ~module_state_2:sight_mode + if (client) + client.screen -= module_state_2 + contents -= module_state_2 + module_state_2:loc = module + module_state_2 = null + inv2.icon_state = "inv2" + if(module_state_3) + if(istype(module_state_3,/obj/item/borg/sight)) + sight_mode &= ~module_state_3:sight_mode + if (client) + client.screen -= module_state_3 + contents -= module_state_3 + module_state_3:loc = module + module_state_3 = null + inv3.icon_state = "inv3" + update_icon() + +/mob/living/silicon/robot/proc/activated(obj/item/O) + if(module_state_1 == O) + return 1 + else if(module_state_2 == O) + return 1 + else if(module_state_3 == O) + return 1 + else + return 0 + update_icon() + +//Helper procs for cyborg modules on the UI. +//These are hackish but they help clean up code elsewhere. + +//module_selected(module) - Checks whether the module slot specified by "module" is currently selected. +/mob/living/silicon/robot/proc/module_selected(var/module) //Module is 1-3 + return module == get_selected_module() + +//module_active(module) - Checks whether there is a module active in the slot specified by "module". +/mob/living/silicon/robot/proc/module_active(var/module) //Module is 1-3 + if(module < 1 || module > 3) return 0 + + switch(module) + if(1) + if(module_state_1) + return 1 + if(2) + if(module_state_2) + return 1 + if(3) + if(module_state_3) + return 1 + return 0 + +//get_selected_module() - Returns the slot number of the currently selected module. Returns 0 if no modules are selected. +/mob/living/silicon/robot/proc/get_selected_module() + if(module_state_1 && module_active == module_state_1) + return 1 + else if(module_state_2 && module_active == module_state_2) + return 2 + else if(module_state_3 && module_active == module_state_3) + return 3 + + return 0 + +//select_module(module) - Selects the module slot specified by "module" +/mob/living/silicon/robot/proc/select_module(var/module) //Module is 1-3 + if(module < 1 || module > 3) return + + if(!module_active(module)) return + + switch(module) + if(1) + if(module_active != module_state_1) + inv1.icon_state = "inv1 +a" + inv2.icon_state = "inv2" + inv3.icon_state = "inv3" + module_active = module_state_1 + return + if(2) + if(module_active != module_state_2) + inv1.icon_state = "inv1" + inv2.icon_state = "inv2 +a" + inv3.icon_state = "inv3" + module_active = module_state_2 + return + if(3) + if(module_active != module_state_3) + inv1.icon_state = "inv1" + inv2.icon_state = "inv2" + inv3.icon_state = "inv3 +a" + module_active = module_state_3 + return + return + +//deselect_module(module) - Deselects the module slot specified by "module" +/mob/living/silicon/robot/proc/deselect_module(var/module) //Module is 1-3 + if(module < 1 || module > 3) return + + switch(module) + if(1) + if(module_active == module_state_1) + inv1.icon_state = "inv1" + module_active = null + return + if(2) + if(module_active == module_state_2) + inv2.icon_state = "inv2" + module_active = null + return + if(3) + if(module_active == module_state_3) + inv3.icon_state = "inv3" + module_active = null + return + return + +//toggle_module(module) - Toggles the selection of the module slot specified by "module". +/mob/living/silicon/robot/proc/toggle_module(var/module) //Module is 1-3 + if(module < 1 || module > 3) return + + if(module_selected(module)) + deselect_module(module) + else + if(module_active(module)) + select_module(module) + else + deselect_module(get_selected_module()) //If we can't do select anything, at least deselect the current module. + return + +//cycle_modules() - Cycles through the list of selected modules. +/mob/living/silicon/robot/proc/cycle_modules() + var/slot_start = get_selected_module() + if(slot_start) deselect_module(slot_start) //Only deselect if we have a selected slot. + + var/slot_num + if(slot_start == 0) + slot_num = 1 + slot_start = 2 + else + slot_num = slot_start + 1 + + while(slot_start != slot_num) //If we wrap around without finding any free slots, just give up. + if(module_active(slot_num)) + select_module(slot_num) + return + slot_num++ + if(slot_num > 3) slot_num = 1 //Wrap around. + + return + +/mob/living/silicon/robot/proc/activate_module(var/obj/item/O) + if(!(locate(O) in src.module.modules) && O != src.module.emag) + return + if(activated(O)) + to_chat(src, "Already activated") + return + if(!module_state_1) + module_state_1 = O + O.hud_layerise() + O.screen_loc = inv1.screen_loc + contents += O + if(istype(module_state_1,/obj/item/borg/sight)) + sight_mode |= module_state_1:sight_mode + else if(!module_state_2) + module_state_2 = O + O.hud_layerise() + O.screen_loc = inv2.screen_loc + contents += O + if(istype(module_state_2,/obj/item/borg/sight)) + sight_mode |= module_state_2:sight_mode + else if(!module_state_3) + module_state_3 = O + O.hud_layerise() + O.screen_loc = inv3.screen_loc + contents += O + if(istype(module_state_3,/obj/item/borg/sight)) + sight_mode |= module_state_3:sight_mode + else + to_chat(src, "You need to disable a module first!") + +/mob/living/silicon/robot/put_in_hands(var/obj/item/W) // No hands. + W.forceMove(get_turf(src)) + return 1 diff --git a/code/modules/mob/living/silicon/robot/laws.dm b/code/modules/mob/living/silicon/robot/laws.dm new file mode 100644 index 00000000..8c906761 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/laws.dm @@ -0,0 +1,54 @@ +/mob/living/silicon/robot/verb/cmd_show_laws() + set category = "Silicon Commands" + set name = "Show Laws" + show_laws() + +/mob/living/silicon/robot/show_laws(var/everyone = 0) + laws_sanity_check() + var/who + + if (everyone) + who = world + else + who = src + if(lawupdate) + if (connected_ai) + if(connected_ai.stat || connected_ai.control_disabled) + to_chat(src, "AI signal lost, unable to sync laws.") + + else + lawsync() + photosync() + to_chat(src, "Laws synced with AI, be sure to note any changes.") + // TODO: Update to new antagonist system. + if(mind && mind.special_role == "traitor" && mind.original == src) + to_chat(src, "Remember, your AI does NOT share or know about your law 0.") + else + to_chat(src, "No AI selected to sync laws with, disabling lawsync protocol.") + lawupdate = 0 + + to_chat(who, "Obey these laws:") + laws.show_laws(who) + // TODO: Update to new antagonist system. + if (mind && (mind.special_role == "traitor" && mind.original == src) && connected_ai) + to_chat(who, "Remember, [connected_ai.name] is technically your master, but your objective comes first.") + else if (connected_ai) + to_chat(who, "Remember, [connected_ai.name] is your master, other AIs can be ignored.") + else if (emagged) + to_chat(who, "Remember, you are not required to listen to the AI.") + else + to_chat(who, "Remember, you are not bound to any AI, you are not required to listen to them.") + + +/mob/living/silicon/robot/lawsync() + laws_sanity_check() + var/datum/ai_laws/master = connected_ai && lawupdate ? connected_ai.laws : null + if (master) + master.sync(src) + ..() + return + +/mob/living/silicon/robot/proc/robot_checklaws() + set category = "Silicon Commands" + set name = "State Laws" + open_subsystem(/datum/nano_module/law_manager) diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm new file mode 100644 index 00000000..ca561097 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -0,0 +1,333 @@ +/mob/living/silicon/robot/Life() + set invisibility = 0 + set background = 1 + + if (src.transforming) + return + + src.blinded = null + + //Status updates, death etc. + clamp_values() + handle_regular_status_updates() + handle_actions() + + if(client) + handle_regular_hud_updates() + update_items() + if (src.stat != DEAD) //still using power + use_power() + process_killswitch() + process_locks() + process_queued_alarms() + update_canmove() + +/mob/living/silicon/robot/proc/clamp_values() + +// SetStunned(min(stunned, 30)) + SetParalysis(min(paralysis, 30)) +// SetWeakened(min(weakened, 20)) + sleeping = 0 + adjustBruteLoss(0) + adjustToxLoss(0) + adjustOxyLoss(0) + adjustFireLoss(0) + +/mob/living/silicon/robot/proc/use_power() + // Debug only +// log_debug(life.dm line 35: cyborg use_power() called at tick [controller_iteration]") + + used_power_this_tick = 0 + for(var/V in components) + var/datum/robot_component/C = components[V] + C.update_power_state() + + if ( cell && is_component_functioning("power cell") && src.cell.charge > 0 ) + if(src.module_state_1) + cell_use_power(50) // 50W load for every enabled tool TODO: tool-specific loads + if(src.module_state_2) + cell_use_power(50) + if(src.module_state_3) + cell_use_power(50) + + if(lights_on) + if(intenselight) + cell_use_power(100) // Upgraded light. Double intensity, much larger power usage. + else + cell_use_power(30) // 30W light. Normal lights would use ~15W, but increased for balance reasons. + + src.has_power = 1 + else + if (src.has_power) + to_chat(src, "You are now running on emergency backup power.") + src.has_power = 0 + if(lights_on) // Light is on but there is no power! + lights_on = 0 + set_light(0) + +/mob/living/silicon/robot/handle_regular_status_updates() + + if(src.camera && !scrambledcodes) + if(src.stat == 2 || wires.IsIndexCut(BORG_WIRE_CAMERA)) + src.camera.set_status(0) + else + src.camera.set_status(1) + + updatehealth() + + if(src.sleeping) + Paralyse(3) + src.sleeping-- + + if(src.resting) + Weaken(5) + + if(health < config.health_threshold_dead && src.stat != 2) //die only once + death() + + if (src.stat != DEAD) //Alive. + if (src.paralysis || src.stunned || src.weakened || !src.has_power) //Stunned etc. + src.set_stat(UNCONSCIOUS) + if (src.stunned > 0) + AdjustStunned(-1) + if (src.weakened > 0) + AdjustWeakened(-1) + if (src.paralysis > 0) + AdjustParalysis(-1) + src.blinded = 1 + else + src.blinded = 0 + + else //Not stunned. + src.set_stat(CONSCIOUS) + + confused = max(0, confused - 1) + + else //Dead. + src.blinded = 1 + src.set_stat(DEAD) + + if (src.stuttering) src.stuttering-- + + if (src.eye_blind) + src.eye_blind-- + src.blinded = 1 + + if (src.ear_deaf > 0) src.ear_deaf-- + if (src.ear_damage < 25) + src.ear_damage -= 0.05 + src.ear_damage = max(src.ear_damage, 0) + + src.set_density(!src.lying) + + if ((src.sdisabilities & BLIND)) + src.blinded = 1 + if ((src.sdisabilities & DEAF)) + src.ear_deaf = 1 + + if (src.eye_blurry > 0) + src.eye_blurry-- + src.eye_blurry = max(0, src.eye_blurry) + + if (src.druggy > 0) + src.druggy-- + src.druggy = max(0, src.druggy) + + //update the state of modules and components here + if (src.stat != 0) + uneq_all() + + if(silicon_radio) + if(!is_component_functioning("radio")) + silicon_radio.on = 0 + else + silicon_radio.on = 1 + + if(is_component_functioning("camera")) + src.blinded = 0 + else + src.blinded = 1 + + return 1 + +/mob/living/silicon/robot/handle_regular_hud_updates() + ..() + + var/obj/item/borg/sight/hud/hud = (locate(/obj/item/borg/sight/hud) in src) + if(hud && hud.hud) + hud.hud.process_hud(src) + else + switch(src.sensor_mode) + if (SEC_HUD) + process_sec_hud(src,0) + if (MED_HUD) + process_med_hud(src,0) + + if (src.healths) + if (src.stat != 2) + if(istype(src,/mob/living/silicon/robot/drone)) + switch(health) + if(35 to INFINITY) + src.healths.icon_state = "health0" + if(25 to 34) + src.healths.icon_state = "health1" + if(15 to 24) + src.healths.icon_state = "health2" + if(5 to 14) + src.healths.icon_state = "health3" + if(0 to 4) + src.healths.icon_state = "health4" + if(-35 to 0) + src.healths.icon_state = "health5" + else + src.healths.icon_state = "health6" + else + switch(health) + if(200 to INFINITY) + src.healths.icon_state = "health0" + if(150 to 200) + src.healths.icon_state = "health1" + if(100 to 150) + src.healths.icon_state = "health2" + if(50 to 100) + src.healths.icon_state = "health3" + if(0 to 50) + src.healths.icon_state = "health4" + if(config.health_threshold_dead to 0) + src.healths.icon_state = "health5" + else + src.healths.icon_state = "health6" + else + src.healths.icon_state = "health7" + + if (src.syndicate && src.client) + for(var/datum/mind/tra in traitors.current_antagonists) + if(tra.current) + // TODO: Update to new antagonist system. + var/I = image('icons/mob/mob.dmi', loc = tra.current, icon_state = "traitor") + src.client.images += I + src.disconnect_from_ai() + if(src.mind) + // TODO: Update to new antagonist system. + if(!src.mind.special_role) + src.mind.special_role = "traitor" + traitors.current_antagonists |= src.mind + + if (src.cells) + if (src.cell) + var/chargeNum = Clamp(ceil(cell.percent()/25), 0, 4) //0-100 maps to 0-4, but give it a paranoid clamp just in case. + src.cells.icon_state = "charge[chargeNum]" + else + src.cells.icon_state = "charge-empty" + + if(bodytemp) + switch(src.bodytemperature) //310.055 optimal body temp + if(335 to INFINITY) + src.bodytemp.icon_state = "temp2" + if(320 to 335) + src.bodytemp.icon_state = "temp1" + if(300 to 320) + src.bodytemp.icon_state = "temp0" + if(260 to 300) + src.bodytemp.icon_state = "temp-1" + else + src.bodytemp.icon_state = "temp-2" + +//Oxygen and fire does nothing yet!! +// if (src.oxygen) src.oxygen.icon_state = "oxy[src.oxygen_alert ? 1 : 0]" +// if (src.fire) src.fire.icon_state = "fire[src.fire_alert ? 1 : 0]" + + if(stat != DEAD) + if(blinded) + overlay_fullscreen("blind", /obj/screen/fullscreen/blind) + else + clear_fullscreen("blind") + set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1) + set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry) + set_fullscreen(druggy, "high", /obj/screen/fullscreen/high) + + if (machine) + if (machine.check_eye(src) < 0) + reset_view(null) + else + if(client && !client.adminobs) + reset_view(null) + + return 1 + +/mob/living/silicon/robot/handle_vision() + ..() + + if (src.stat == DEAD || (XRAY in mutations) || (src.sight_mode & BORGXRAY)) + set_sight(sight|SEE_TURFS|SEE_MOBS|SEE_OBJS) + set_see_in_dark(8) + set_see_invisible(SEE_INVISIBLE_LEVEL_TWO) + else if ((src.sight_mode & BORGMESON) && (src.sight_mode & BORGTHERM)) + set_sight(sight|SEE_TURFS|SEE_MOBS) + set_see_in_dark(8) + set_see_invisible(SEE_INVISIBLE_NOLIGHTING) + else if (src.sight_mode & BORGMESON) + set_sight(sight|SEE_TURFS) + set_see_in_dark(8) + set_see_invisible(SEE_INVISIBLE_NOLIGHTING) + else if (src.sight_mode & BORGMATERIAL) + set_sight(sight|SEE_OBJS) + set_see_in_dark(8) + else if (src.sight_mode & BORGTHERM) + set_sight(sight|SEE_MOBS) + set_see_in_dark(8) + set_see_invisible(SEE_INVISIBLE_LEVEL_TWO) + else if (src.stat != DEAD) + set_sight(sight&(~SEE_TURFS)&(~SEE_MOBS)&(~SEE_OBJS)) + set_see_in_dark(8) // see_in_dark means you can FAINTLY see in the dark, humans have a range of 3 or so, tajaran have it at 8 + set_see_invisible(SEE_INVISIBLE_LIVING) // This is normal vision (25), setting it lower for normal vision means you don't "see" things like darkness since darkness + // has a "invisible" value of 15 + + +/mob/living/silicon/robot/proc/update_items() + if (src.client) + src.client.screen -= src.contents + for(var/obj/I in src.contents) + if(I && !(istype(I,/obj/item/weapon/cell) || istype(I,/obj/item/device/radio) || istype(I,/obj/machinery/camera) || istype(I,/obj/item/device/mmi))) + src.client.screen += I + if(src.module_state_1) + src.module_state_1:screen_loc = ui_inv1 + if(src.module_state_2) + src.module_state_2:screen_loc = ui_inv2 + if(src.module_state_3) + src.module_state_3:screen_loc = ui_inv3 + update_icon() + +/mob/living/silicon/robot/proc/process_killswitch() + if(killswitch) + killswitch_time -- + if(killswitch_time <= 0) + if(src.client) + to_chat(src, "Killswitch Activated") + killswitch = 0 + spawn(5) + gib() + +/mob/living/silicon/robot/proc/process_locks() + if(weapon_lock) + uneq_all() + weaponlock_time -- + if(weaponlock_time <= 0) + if(src.client) + to_chat(src, "Weapon Lock Timed Out!") + weapon_lock = 0 + weaponlock_time = 120 + +/mob/living/silicon/robot/update_canmove() + if(paralysis || stunned || weakened || buckled || lockcharge || !is_component_functioning("actuator")) canmove = 0 + else canmove = 1 + return canmove + +/mob/living/silicon/robot/update_fire() + overlays -= image("icon"='icons/mob/OnFire.dmi', "icon_state"="Standing") + if(on_fire) + overlays += image("icon"='icons/mob/OnFire.dmi', "icon_state"="Standing") + +/mob/living/silicon/robot/fire_act() + if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them + IgniteMob() diff --git a/code/modules/mob/living/silicon/robot/login.dm b/code/modules/mob/living/silicon/robot/login.dm new file mode 100644 index 00000000..e0abc1fa --- /dev/null +++ b/code/modules/mob/living/silicon/robot/login.dm @@ -0,0 +1,12 @@ +/mob/living/silicon/robot/Login() + ..() + regenerate_icons() + update_hud() + + show_laws(0) + + winset(src, null, "mainwindow.macro=borgmacro hotkey_toggle.is-checked=false input.focus=true input.background-color=#d3b5b5") + + // Forces synths to select an icon relevant to their module + if(!icon_selected) + choose_icon(icon_selection_tries, module_sprites) diff --git a/code/modules/mob/living/silicon/robot/photos.dm b/code/modules/mob/living/silicon/robot/photos.dm new file mode 100644 index 00000000..e0e904df --- /dev/null +++ b/code/modules/mob/living/silicon/robot/photos.dm @@ -0,0 +1,20 @@ +/mob/living/silicon/robot/proc/photosync() + var/obj/item/device/camera/siliconcam/master_cam = connected_ai && connected_ai.silicon_camera + if (!master_cam) + return + + var/synced = 0 + // Sync borg images to the master AI. + // We don't care about syncing the other way around + for(var/obj/item/weapon/photo/borg_photo in silicon_camera.aipictures) + var/copied = 0 + for(var/obj/item/weapon/photo/ai_photo in master_cam.aipictures) + if(borg_photo.id == ai_photo.id) + copied = 1 + break + if(!copied) + master_cam.injectaialbum(borg_photo.copy(1), " (synced from [name])") + synced = 1 + + if(synced) + to_chat(src, "Images synced with AI. Local images will be retained in the case of loss of connection with the AI.") diff --git a/code/modules/mob/living/silicon/robot/preset.dm b/code/modules/mob/living/silicon/robot/preset.dm new file mode 100644 index 00000000..124bb64c --- /dev/null +++ b/code/modules/mob/living/silicon/robot/preset.dm @@ -0,0 +1,27 @@ +/mob/living/silicon/robot/syndicate + lawupdate = 0 + scrambledcodes = 1 + icon_state = "securityrobot" + modtype = "Security" + lawchannel = "State" + laws = /datum/ai_laws/syndicate_override + idcard = /obj/item/weapon/card/id/syndicate + module = /obj/item/weapon/robot_module/syndicate + silicon_radio = /obj/item/device/radio/borg/syndicate + spawn_sound = 'sound/mecha/nominalsyndi.ogg' + cell = /obj/item/weapon/cell/super + pitch_toggle = 0 + +/mob/living/silicon/robot/combat + lawupdate = 0 + scrambledcodes = 1 + modtype = "Combat" + module = /obj/item/weapon/robot_module/security/combat + spawn_sound = 'sound/mecha/nominalsyndi.ogg' + cell = /obj/item/weapon/cell/super + pitch_toggle = 0 + +/mob/living/silicon/robot/combat/nt + laws = /datum/ai_laws/nanotrasen_aggressive + idcard = /obj/item/weapon/card/id/centcom/ERT + silicon_radio = /obj/item/device/radio/borg/ert diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm new file mode 100644 index 00000000..dc598ba3 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -0,0 +1,1102 @@ +#define CYBORG_POWER_USAGE_MULTIPLIER 2.5 // Multiplier for amount of power cyborgs use. + +/mob/living/silicon/robot + name = "Cyborg" + real_name = "Cyborg" + icon = 'icons/mob/robots.dmi' + icon_state = "robot" + maxHealth = 200 + health = 200 + + mob_bump_flag = ROBOT + mob_swap_flags = ROBOT|MONKEY|SLIME|SIMPLE_ANIMAL + mob_push_flags = ~HEAVY //trundle trundle + + var/lights_on = 0 // Is our integrated light on? + var/used_power_this_tick = 0 + var/sight_mode = 0 + var/custom_name = "" + var/custom_sprite = 0 //Due to all the sprites involved, a var for our custom borgs may be best + var/crisis //Admin-settable for combat module use. + var/crisis_override = 0 + var/integrated_light_power = 6 + var/datum/wires/robot/wires + +//Icon stuff + + var/static/list/eye_overlays + var/icontype //Persistent icontype tracking allows for cleaner icon updates + var/module_sprites[0] //Used to store the associations between sprite names and sprite index. + var/icon_selected = 1 //If icon selection has been completed yet + var/icon_selection_tries = 0//Remaining attempts to select icon before a selection is forced + +//Hud stuff + + var/obj/screen/inv1 = null + var/obj/screen/inv2 = null + var/obj/screen/inv3 = null + + var/shown_robot_modules = 0 //Used to determine whether they have the module menu shown or not + var/obj/screen/robot_modules_background + +//3 Modules can be activated at any one time. + var/obj/item/weapon/robot_module/module = null + var/module_active = null + var/module_state_1 = null + var/module_state_2 = null + var/module_state_3 = null + + silicon_camera = /obj/item/device/camera/siliconcam/robot_camera + silicon_radio = /obj/item/device/radio/borg + + var/mob/living/silicon/ai/connected_ai = null + var/obj/item/weapon/cell/cell = /obj/item/weapon/cell/high + var/obj/machinery/camera/camera = null + + var/cell_emp_mult = 2 + + // Components are basically robot organs. + var/list/components = list() + + var/obj/item/device/mmi/mmi = null + + var/obj/item/device/pda/ai/rbPDA = null + + var/obj/item/weapon/stock_parts/matter_bin/storage = null + + var/opened = 0 + var/emagged = 0 + var/wiresexposed = 0 + var/locked = 1 + var/has_power = 1 + var/spawn_module = null + + var/spawn_sound = 'sound/voice/liveagain.ogg' + var/pitch_toggle = 1 + var/list/req_access = list(access_robotics) + var/ident = 0 + var/viewalerts = 0 + var/modtype = "Default" + var/lower_mod = 0 + var/jetpack = 0 + var/datum/effect/effect/system/ion_trail_follow/ion_trail = null + var/datum/effect/effect/system/spark_spread/spark_system//So they can initialize sparks whenever/N + var/jeton = 0 + var/killswitch = 0 + var/killswitch_time = 60 + var/weapon_lock = 0 + var/weaponlock_time = 120 + var/lawupdate = 1 //Cyborgs will sync their laws with their AI by default + var/lockcharge //If a robot is locked down + var/speed = 0 //Cause sec borgs gotta go fast //No they dont! + var/scrambledcodes = 0 // Used to determine if a borg shows up on the robotics console. Setting to one hides them. + var/tracking_entities = 0 //The number of known entities currently accessing the internal camera + var/braintype = "Cyborg" + var/intenselight = 0 // Whether cyborg's integrated light was upgraded + + var/list/robot_verbs_default = list( + /mob/living/silicon/robot/proc/sensor_mode, + /mob/living/silicon/robot/proc/robot_checklaws + ) + +/mob/living/silicon/robot/New(loc,var/unfinished = 0) + spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, src) + spark_system.attach(src) + + add_language("Robot Talk", 1) + add_language(LANGUAGE_EAL, 1) + + wires = new(src) + + robot_modules_background = new() + robot_modules_background.icon_state = "block" + ident = random_id(/mob/living/silicon/robot, 1, 999) + module_sprites["Basic"] = "robot" + icontype = "Basic" + updatename(modtype) + update_icon() + + if(!scrambledcodes && !camera) + camera = new /obj/machinery/camera(src) + camera.c_tag = real_name + camera.replace_networks(list(NETWORK_EXODUS,NETWORK_ROBOTS)) + if(wires.IsIndexCut(BORG_WIRE_CAMERA)) + camera.status = 0 + + ..() // Laws, among other things, are initialized in parent New() + init() + initialize_components() + //if(!unfinished) + // Create all the robot parts. + for(var/V in components) if(V != "power cell") + var/datum/robot_component/C = components[V] + C.installed = 1 + C.wrapped = new C.external_type + + if(ispath(cell)) + cell = new cell(src) + + if(cell) + var/datum/robot_component/cell_component = components["power cell"] + cell_component.wrapped = cell + cell_component.installed = 1 + + add_robot_verbs() + + hud_list[HEALTH_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[STATUS_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudhealth100") + hud_list[LIFE_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudhealth100") + hud_list[ID_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[WANTED_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[IMPLOYAL_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[IMPCHEM_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[IMPTRACK_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + hud_list[SPECIALROLE_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + +/mob/living/silicon/robot/proc/recalculate_synth_capacities() + if(!module || !module.synths) + return + var/mult = 1 + if(storage) + mult += storage.rating + for(var/datum/matter_synth/M in module.synths) + M.set_multiplier(mult) + +/mob/living/silicon/robot/proc/init() + if(ispath(module)) + new module(src) + if(lawupdate) + var/new_ai = select_active_ai_with_fewest_borgs() + if(new_ai) + lawupdate = 1 + connect_to_ai(new_ai) + else + lawupdate = 0 + + playsound(loc, spawn_sound, 75, pitch_toggle) + +/mob/living/silicon/robot/fully_replace_character_name(pickedName as text) + custom_name = pickedName + updatename() + +/mob/living/silicon/robot/proc/sync() + if(lawupdate && connected_ai) + lawsync() + photosync() + +/mob/living/silicon/robot/drain_power(var/drain_check, var/surge, var/amount = 0) + + if(drain_check) + return 1 + + if(!cell || !cell.charge) + return 0 + + // Actual amount to drain from cell, using CELLRATE + var/cell_amount = amount * CELLRATE + + if(cell.charge > cell_amount) + // Spam Protection + if(prob(10)) + to_chat(src, "Warning: Unauthorized access through power channel [rand(11,29)] detected!") + cell.use(cell_amount) + return amount + return 0 + +// setup the PDA and its name +/mob/living/silicon/robot/proc/setup_PDA() + if (!rbPDA) + rbPDA = new/obj/item/device/pda/ai(src) + rbPDA.set_name_and_job(custom_name,"[modtype] [braintype]") + +//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO +//Improved /N +/mob/living/silicon/robot/Destroy() + if(mmi)//Safety for when a cyborg gets dust()ed. Or there is no MMI inside. + if(mind) + mmi.dropInto(loc) + if(mmi.brainmob) + mind.transfer_to(mmi.brainmob) + else + to_chat(src, "Oops! Something went very wrong, your MMI was unable to receive your mind. You have been ghosted. Please make a bug report so we can fix this bug.") + ghostize() + //ERROR("A borg has been destroyed, but its MMI lacked a brainmob, so the mind could not be transferred. Player: [ckey].") + mmi = null + else + QDEL_NULL(mmi) + if(connected_ai) + connected_ai.connected_robots -= src + connected_ai = null + QDEL_NULL(wires) + return ..() + +/mob/living/silicon/robot/proc/set_module_sprites(var/list/new_sprites) + if(new_sprites && new_sprites.len) + module_sprites = new_sprites.Copy() + //Custom_sprite check and entry + + if (custom_sprite == 1) + var/list/valid_states = icon_states(CUSTOM_ITEM_SYNTH) + if("[ckey]-[modtype]" in valid_states) + module_sprites["Custom"] = "[src.ckey]-[modtype]" + icon = CUSTOM_ITEM_SYNTH + icontype = "Custom" + else + icontype = module_sprites[1] + icon = 'icons/mob/robots.dmi' + to_chat(src, "Custom Sprite Sheet does not contain a valid icon_state for [ckey]-[modtype]") + else + icontype = module_sprites[1] + icon_state = module_sprites[icontype] + update_icon() + return module_sprites + +/mob/living/silicon/robot/proc/pick_module() + if(module) + return + var/list/modules = list() + modules.Add(GLOB.robot_module_types) + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + if((crisis && security_state.current_security_level_is_same_or_higher_than(security_state.high_security_level)) || crisis_override) //Leaving this in until it's balanced appropriately. + to_chat(src, "Crisis mode active. Combat module available.") + modules+="Combat" + modtype = input("Please, select a module!", "Robot module", null, null) as null|anything in modules + + if(module) + return + if(!(modtype in robot_modules)) + return + + var/module_type = robot_modules[modtype] + new module_type(src) + + hands.icon_state = lowertext(modtype) + feedback_inc("cyborg_[lowertext(modtype)]",1) + updatename() + recalculate_synth_capacities() + if(module) + notify_ai(ROBOT_NOTIFICATION_NEW_MODULE, module.name) + +/mob/living/silicon/robot/proc/updatename(var/prefix as text) + if(prefix) + modtype = prefix + + if(istype(mmi, /obj/item/organ/internal/posibrain)) + braintype = "Android" + else if(istype(mmi, /obj/item/device/mmi/digital/robot)) + braintype = "Robot" + else + braintype = "Cyborg" + + + var/changed_name = "" + if(custom_name) + changed_name = custom_name + notify_ai(ROBOT_NOTIFICATION_NEW_NAME, real_name, changed_name) + else + changed_name = "[modtype] [braintype]-[num2text(ident)]" + + real_name = changed_name + name = real_name + if(mind) + mind.name = changed_name + + // if we've changed our name, we also need to update the display name for our PDA + setup_PDA() + + //We also need to update name of internal camera. + if (camera) + camera.c_tag = changed_name + + if(!custom_sprite) //Check for custom sprite + set_custom_sprite() + + +/mob/living/silicon/robot/verb/Namepick() + set category = "Silicon Commands" + if(custom_name) + return 0 + + spawn(0) + var/newname + newname = sanitizeSafe(input(src,"You are a robot. Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN) + if (newname) + custom_name = newname + + updatename() + update_icon() + +// this verb lets cyborgs see the stations manifest +/mob/living/silicon/robot/verb/cmd_station_manifest() + set category = "Silicon Commands" + set name = "Show Crew Manifest" + show_station_manifest() + +/mob/living/silicon/robot/proc/self_diagnosis() + if(!is_component_functioning("diagnosis unit")) + return null + + var/dat = "[src.name] Self-Diagnosis Report\n" + for (var/V in components) + var/datum/robot_component/C = components[V] + dat += "[C.name]
            Brute Damage:[C.brute_damage]
            Electronics Damage:[C.electronics_damage]
            Powered:[(!C.idle_usage || C.is_powered()) ? "Yes" : "No"]
            Toggled:[ C.toggled ? "Yes" : "No"]

            " + + return dat + +/mob/living/silicon/robot/verb/toggle_lights() + set category = "Silicon Commands" + set name = "Toggle Lights" + + if(stat == DEAD) + return + + lights_on = !lights_on + to_chat(usr, "You [lights_on ? "enable" : "disable"] your integrated light.") + update_robot_light() + +/mob/living/silicon/robot/verb/self_diagnosis_verb() + set category = "Silicon Commands" + set name = "Self Diagnosis" + + if(!is_component_functioning("diagnosis unit")) + to_chat(src, "Your self-diagnosis component isn't functioning.") + return + + var/datum/robot_component/CO = get_component("diagnosis unit") + if (!cell_use_power(CO.active_usage)) + to_chat(src, "Low Power.") + return + var/dat = self_diagnosis() + src << browse(dat, "window=robotdiagnosis") + + +/mob/living/silicon/robot/verb/toggle_component() + set category = "Silicon Commands" + set name = "Toggle Component" + set desc = "Toggle a component, conserving power." + + var/list/installed_components = list() + for(var/V in components) + if(V == "power cell") continue + var/datum/robot_component/C = components[V] + if(C.installed) + installed_components += V + + var/toggle = input(src, "Which component do you want to toggle?", "Toggle Component") as null|anything in installed_components + if(!toggle) + return + + var/datum/robot_component/C = components[toggle] + if(C.toggled) + C.toggled = 0 + to_chat(src, "You disable [C.name].") + else + C.toggled = 1 + to_chat(src, "You enable [C.name].") +/mob/living/silicon/robot/proc/update_robot_light() + if(lights_on) + if(intenselight) + set_light(integrated_light_power * 2, integrated_light_power) + else + set_light(integrated_light_power) + else + set_light(0) + +// this function displays jetpack pressure in the stat panel +/mob/living/silicon/robot/proc/show_jetpack_pressure() + // if you have a jetpack, show the internal tank pressure + var/obj/item/weapon/tank/jetpack/current_jetpack = installed_jetpack() + if (current_jetpack) + stat("Internal Atmosphere Info", current_jetpack.name) + stat("Tank Pressure", current_jetpack.air_contents.return_pressure()) + + +// this function returns the robots jetpack, if one is installed +/mob/living/silicon/robot/proc/installed_jetpack() + if(module) + return (locate(/obj/item/weapon/tank/jetpack) in module.modules) + return 0 + + +// this function displays the cyborgs current cell charge in the stat panel +/mob/living/silicon/robot/proc/show_cell_power() + if(cell) + stat(null, text("Charge Left: [round(cell.percent())]%")) + stat(null, text("Cell Rating: [round(cell.maxcharge)]")) // Round just in case we somehow get crazy values + stat(null, text("Power Cell Load: [round(used_power_this_tick)]W")) + else + stat(null, text("No Cell Inserted!")) + + +// update the status screen display +/mob/living/silicon/robot/Stat() + . = ..() + if (statpanel("Status")) + show_cell_power() + show_jetpack_pressure() + stat(null, text("Lights: [lights_on ? "ON" : "OFF"]")) + if(module) + for(var/datum/matter_synth/ms in module.synths) + stat("[ms.name]: [ms.energy]/[ms.max_energy_multiplied]") + +/mob/living/silicon/robot/restrained() + return 0 + +/mob/living/silicon/robot/bullet_act(var/obj/item/projectile/Proj) + ..(Proj) + if(prob(75) && Proj.damage > 0) spark_system.start() + return 2 + +/mob/living/silicon/robot/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/handcuffs)) // fuck i don't even know why isrobot() in handcuff code isn't working so this will have to do + return + + if(opened) // Are they trying to insert something? + for(var/V in components) + var/datum/robot_component/C = components[V] + if(!C.installed && istype(W, C.external_type)) + C.installed = 1 + C.wrapped = W + C.install() + user.drop_item() + W.loc = null + + var/obj/item/robot_parts/robot_component/WC = W + if(istype(WC)) + C.brute_damage = WC.brute + C.electronics_damage = WC.burn + + to_chat(usr, "You install the [W.name].") + return + + if(isWelder(W)) + if (src == user) + to_chat(user, "You lack the reach to be able to repair yourself.") + return + + if (!getBruteLoss()) + to_chat(user, "Nothing to fix here!") + return + var/obj/item/weapon/weldingtool/WT = W + if (WT.remove_fuel(0)) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + adjustBruteLoss(-30) + updatehealth() + add_fingerprint(user) + for(var/mob/O in viewers(user, null)) + O.show_message(text("[user] has fixed some of the dents on [src]!"), 1) + else + to_chat(user, "Need more welding fuel!") + return + + else if(istype(W, /obj/item/stack/cable_coil) && (wiresexposed || istype(src,/mob/living/silicon/robot/drone))) + if (!getFireLoss()) + to_chat(user, "Nothing to fix here!") + return + var/obj/item/stack/cable_coil/coil = W + if (coil.use(1)) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + adjustFireLoss(-30) + updatehealth() + for(var/mob/O in viewers(user, null)) + O.show_message(text("[user] has fixed some of the burnt wires on [src]!"), 1) + + else if(isCrowbar(W)) // crowbar means open or close the cover - we all know what a crowbar is by now + if(opened) + if(cell) + user.visible_message("\The [user] begins clasping shut \the [src]'s maintenance hatch.", "You begin closing up \the [src].") + if(do_after(user, 50, src)) + to_chat(user, "You close \the [src]'s maintenance hatch.") + opened = 0 + update_icon() + + else if(wiresexposed && wires.IsAllCut()) + //Cell is out, wires are exposed, remove MMI, produce damaged chassis, baleet original mob. + if(!mmi) + to_chat(user, "\The [src] has no brain to remove.") + return + + user.visible_message("\The [user] begins ripping [mmi] from [src].", "You jam the crowbar into the robot and begin levering [mmi].") + if(do_after(user, 50, src)) + to_chat(user, "You damage some parts of the chassis, but eventually manage to rip out [mmi]!") + var/obj/item/robot_parts/robot_suit/C = new/obj/item/robot_parts/robot_suit(loc) + C.parts[BP_L_LEG] = new/obj/item/robot_parts/l_leg(C) + C.parts[BP_R_LEG] = new/obj/item/robot_parts/r_leg(C) + C.parts[BP_L_ARM] = new/obj/item/robot_parts/l_arm(C) + C.parts[BP_R_ARM] = new/obj/item/robot_parts/r_arm(C) + C.update_icon() + new/obj/item/robot_parts/chest(loc) + qdel(src) + + else + // Okay we're not removing the cell or an MMI, but maybe something else? + var/list/removable_components = list() + for(var/V in components) + if(V == "power cell") continue + var/datum/robot_component/C = components[V] + if(C.installed == 1 || C.installed == -1) + removable_components += V + + var/remove = input(user, "Which component do you want to pry out?", "Remove Component") as null|anything in removable_components + if(!remove) + return + var/datum/robot_component/C = components[remove] + var/obj/item/robot_parts/robot_component/I = C.wrapped + to_chat(user, "You remove \the [I].") + if(istype(I)) + I.brute = C.brute_damage + I.burn = C.electronics_damage + + I.loc = src.loc + + if(C.installed == 1) + C.uninstall() + C.installed = 0 + + else + if(locked) + to_chat(user, "The cover is locked and cannot be opened.") + else + user.visible_message("\The [user] begins prying open \the [src]'s maintenance hatch.", "You start opening \the [src]'s maintenance hatch.") + if(do_after(user, 50, src)) + to_chat(user, "You open \the [src]'s maintenance hatch.") + opened = 1 + update_icon() + + else if (istype(W, /obj/item/weapon/stock_parts/matter_bin) && opened) // Installing/swapping a matter bin + if(storage) + to_chat(user, "You replace \the [storage] with \the [W]") + storage.forceMove(get_turf(src)) + storage = null + else + to_chat(user, "You install \the [W]") + user.drop_item() + storage = W + W.forceMove(src) + recalculate_synth_capacities() + + else if (istype(W, /obj/item/weapon/cell) && opened) // trying to put a cell inside + var/datum/robot_component/C = components["power cell"] + if(wiresexposed) + to_chat(user, "Close the panel first.") + else if(cell) + to_chat(user, "There is a power cell already installed.") + else if(W.w_class != ITEM_SIZE_NORMAL) + to_chat(user, "\The [W] is too [W.w_class < ITEM_SIZE_NORMAL? "small" : "large"] to fit here.") + else + user.drop_item() + W.loc = src + cell = W + to_chat(user, "You insert the power cell.") + C.installed = 1 + C.wrapped = W + C.install() + //This will mean that removing and replacing a power cell will repair the mount, but I don't care at this point. ~Z + C.brute_damage = 0 + C.electronics_damage = 0 + + else if(isWirecutter(W) || isMultitool(W)) + if (wiresexposed) + wires.Interact(user) + else + to_chat(user, "You can't reach the wiring.") + else if(isScrewdriver(W) && opened && !cell) // haxing + wiresexposed = !wiresexposed + to_chat(user, "The wires have been [wiresexposed ? "exposed" : "unexposed"].") + update_icon() + + else if(istype(W, /obj/item/weapon/screwdriver) && opened && cell) // radio + if(silicon_radio) + silicon_radio.attackby(W,user)//Push it to the radio to let it handle everything + else + to_chat(user, "Unable to locate a radio.") + update_icon() + + else if(istype(W, /obj/item/device/encryptionkey/) && opened) + if(silicon_radio)//sanityyyyyy + silicon_radio.attackby(W,user)//GTFO, you have your own procs + else + to_chat(user, "Unable to locate a radio.") + else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)||istype(W, /obj/item/weapon/card/robot)) // trying to unlock the interface with an ID card + if(emagged)//still allow them to open the cover + to_chat(user, "The interface seems slightly damaged") + if(opened) + to_chat(user, "You must close the cover to swipe an ID card.") + else + if(allowed(usr)) + locked = !locked + to_chat(user, "You [ locked ? "lock" : "unlock"] [src]'s interface.") + update_icon() + else + to_chat(user, "Access denied.") + else if(istype(W, /obj/item/borg/upgrade/)) + var/obj/item/borg/upgrade/U = W + if(!opened) + to_chat(usr, "You must access the borgs internals!") + else if(!src.module && U.require_module) + to_chat(usr, "The borg must choose a module before he can be upgraded!") + else if(U.locked) + to_chat(usr, "The upgrade is locked and cannot be used yet!") + else + if(U.action(src)) + to_chat(usr, "You apply the upgrade to [src]!") + usr.drop_item() + U.loc = src + else + to_chat(usr, "Upgrade error!") + + else + if( !(istype(W, /obj/item/device/robotanalyzer) || istype(W, /obj/item/device/healthanalyzer)) ) + spark_system.start() + return ..() + +/mob/living/silicon/robot/attack_hand(mob/user) + + add_fingerprint(user) + + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(H.species.can_shred(H)) + attack_generic(H, rand(30,50), "slashed") + return + + if(opened && !wiresexposed && (!istype(user, /mob/living/silicon))) + var/datum/robot_component/cell_component = components["power cell"] + if(cell) + cell.update_icon() + cell.add_fingerprint(user) + user.put_in_active_hand(cell) + to_chat(user, "You remove \the [cell].") + cell = null + cell_component.wrapped = null + cell_component.installed = 0 + update_icon() + else if(cell_component.installed == -1) + cell_component.installed = 0 + var/obj/item/broken_device = cell_component.wrapped + to_chat(user, "You remove \the [broken_device].") + user.put_in_active_hand(broken_device) + +//Robots take half damage from basic attacks. +/mob/living/silicon/robot/attack_generic(var/mob/user, var/damage, var/attack_message) + return ..(user,Floor(damage/2),attack_message) + +/mob/living/silicon/robot/proc/allowed(mob/M) + //check if it doesn't require any access at all + if(check_access(null)) + return 1 + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + //if they are holding or wearing a card that has access, that works + if(check_access(H.get_active_hand()) || check_access(H.wear_id)) + return 1 + else if(istype(M, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = M + if(check_access(R.get_active_hand()) || istype(R.get_active_hand(), /obj/item/weapon/card/robot)) + return 1 + return 0 + +/mob/living/silicon/robot/proc/check_access(obj/item/weapon/card/id/I) + if(!istype(req_access, /list)) //something's very wrong + return 1 + + var/list/L = req_access + if(!L.len) //no requirements + return 1 + if(!I || !istype(I, /obj/item/weapon/card/id) || !I.access) //not ID or no access + return 0 + for(var/req in req_access) + if(req in I.access) //have one of the required accesses + return 1 + return 0 + +/mob/living/silicon/robot/update_icon() + overlays.Cut() + if(stat == CONSCIOUS) + var/eye_icon_state = "eyes-[module_sprites[icontype]]" + if(eye_icon_state in icon_states(icon)) + if(!eye_overlays) + eye_overlays = list() + var/image/eye_overlay = eye_overlays[eye_icon_state] + if(!eye_overlay) + eye_overlay = image(icon, eye_icon_state) + eye_overlay.plane = EFFECTS_ABOVE_LIGHTING_PLANE + eye_overlay.layer = EYE_GLOW_LAYER + eye_overlays[eye_icon_state] = eye_overlay + overlays += eye_overlay + + if(opened) + var/panelprefix = custom_sprite ? src.ckey : "ov" + if(wiresexposed) + overlays += "[panelprefix]-openpanel +w" + else if(cell) + overlays += "[panelprefix]-openpanel +c" + else + overlays += "[panelprefix]-openpanel -c" + + if(module_active && istype(module_active,/obj/item/borg/combat/shield)) + overlays += "[module_sprites[icontype]]-shield" + + if(modtype == "Combat") + if(module_active && istype(module_active,/obj/item/borg/combat/mobility)) + icon_state = "[module_sprites[icontype]]-roll" + else + icon_state = module_sprites[icontype] + return + +/mob/living/silicon/robot/proc/installed_modules() + if(weapon_lock) + to_chat(src, "Weapon lock active, unable to use modules! Count:[weaponlock_time]") + return + + if(!module) + pick_module() + return + var/dat = "Modules\n" + dat += {" + Activated Modules +
            + Module 1: [module_state_1 ? "[module_state_1]" : "No Module"]
            + Module 2: [module_state_2 ? "
            [module_state_2]" : "No Module"]
            + Module 3: [module_state_3 ? "
            [module_state_3]" : "No Module"]
            +
            + Installed Modules

            "} + + + for (var/obj in module.modules) + if (!obj) + dat += text("Resource depleted
            ") + else if(activated(obj)) + dat += text("[obj]: Activated
            ") + else + dat += text("[obj]:
            Activate
            ") + if (emagged) + if(activated(module.emag)) + dat += text("[module.emag]: Activated
            ") + else + dat += text("[module.emag]: Activate
            ") +/* + if(activated(obj)) + dat += text("[obj]: \[Activated | Deactivate\]
            ") + else + dat += text("[obj]: \[Activate | Deactivated\]
            ") +*/ + src << browse(dat, "window=robotmod") + + +/mob/living/silicon/robot/Topic(href, href_list) + if(..()) + return 1 + if(usr != src) + return 1 + + if (href_list["showalerts"]) + open_subsystem(/datum/nano_module/alarm_monitor/all) + return 1 + + if (href_list["mod"]) + var/obj/item/O = locate(href_list["mod"]) + if (istype(O) && (O.loc == src)) + O.attack_self(src) + return 1 + + if (href_list["act"]) + var/obj/item/O = locate(href_list["act"]) + if (!istype(O)) + return 1 + + if(!((O in src.module.modules) || (O == src.module.emag))) + return 1 + + if(activated(O)) + to_chat(src, "Already activated") + return 1 + if(!module_state_1) + module_state_1 = O + O.hud_layerise() + contents += O + if(istype(module_state_1,/obj/item/borg/sight)) + sight_mode |= module_state_1:sight_mode + else if(!module_state_2) + module_state_2 = O + O.hud_layerise() + contents += O + if(istype(module_state_2,/obj/item/borg/sight)) + sight_mode |= module_state_2:sight_mode + else if(!module_state_3) + module_state_3 = O + O.hud_layerise() + contents += O + if(istype(module_state_3,/obj/item/borg/sight)) + sight_mode |= module_state_3:sight_mode + else + to_chat(src, "You need to disable a module first!") + installed_modules() + return 1 + + if (href_list["deact"]) + var/obj/item/O = locate(href_list["deact"]) + if(activated(O)) + if(module_state_1 == O) + module_state_1 = null + contents -= O + else if(module_state_2 == O) + module_state_2 = null + contents -= O + else if(module_state_3 == O) + module_state_3 = null + contents -= O + else + to_chat(src, "Module isn't activated.") + else + to_chat(src, "Module isn't activated") + installed_modules() + return 1 + return + +/mob/living/silicon/robot/proc/radio_menu() + silicon_radio.interact(src)//Just use the radio's Topic() instead of bullshit special-snowflake code + + +/mob/living/silicon/robot/Move(a, b, flag) + + . = ..() + + if(module) + if(module.type == /obj/item/weapon/robot_module/janitor) + var/turf/tile = loc + if(isturf(tile)) + tile.clean_blood() + if (istype(tile, /turf/simulated)) + var/turf/simulated/S = tile + S.dirt = 0 + for(var/A in tile) + if(istype(A, /obj/effect)) + if(istype(A, /obj/effect/rune) || istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/overlay)) + qdel(A) + else if(istype(A, /obj/item)) + var/obj/item/cleaned_item = A + cleaned_item.clean_blood() + else if(istype(A, /mob/living/carbon/human)) + var/mob/living/carbon/human/cleaned_human = A + if(cleaned_human.lying) + if(cleaned_human.head) + cleaned_human.head.clean_blood() + cleaned_human.update_inv_head(0) + if(cleaned_human.wear_suit) + cleaned_human.wear_suit.clean_blood() + cleaned_human.update_inv_wear_suit(0) + else if(cleaned_human.w_uniform) + cleaned_human.w_uniform.clean_blood() + cleaned_human.update_inv_w_uniform(0) + if(cleaned_human.shoes) + cleaned_human.shoes.clean_blood() + cleaned_human.update_inv_shoes(0) + cleaned_human.clean_blood(1) + to_chat(cleaned_human, "[src] cleans your face!") + return + +/mob/living/silicon/robot/proc/self_destruct() + gib() + return + +/mob/living/silicon/robot/proc/UnlinkSelf() + disconnect_from_ai() + lawupdate = 0 + lockcharge = 0 + canmove = 1 + scrambledcodes = 1 + //Disconnect it's camera so it's not so easily tracked. + if(src.camera) + src.camera.clear_all_networks() + + +/mob/living/silicon/robot/proc/ResetSecurityCodes() + set category = "Silicon Commands" + set name = "Reset Identity Codes" + set desc = "Scrambles your security and identification codes and resets your current buffers. Unlocks you and but permenantly severs you from your AI and the robotics console and will deactivate your camera system." + + var/mob/living/silicon/robot/R = src + + if(R) + R.UnlinkSelf() + to_chat(R, "Buffers flushed and reset. Camera system shutdown. All systems operational.") + src.verbs -= /mob/living/silicon/robot/proc/ResetSecurityCodes + +/mob/living/silicon/robot/proc/SetLockdown(var/state = 1) + // They stay locked down if their wire is cut. + if(wires.LockedCut()) + state = 1 + else if(has_zeroth_law()) + state = 0 + + if(lockcharge != state) + lockcharge = state + update_canmove() + return 1 + return 0 + +/mob/living/silicon/robot/mode() + set name = "Activate Held Object" + set category = "IC" + set src = usr + + var/obj/item/W = get_active_hand() + if (W) + W.attack_self(src) + + return + +/mob/living/silicon/robot/proc/choose_icon(var/triesleft, var/list/module_sprites) + if(!module_sprites.len) + to_chat(src, "Something is badly wrong with the sprite selection. Harass a coder.") + return + + icon_selected = 0 + src.icon_selection_tries = triesleft + if(module_sprites.len == 1 || !client) + if(!(icontype in module_sprites)) + icontype = module_sprites[1] + else + icontype = input("Select an icon! [triesleft ? "You have [triesleft] more chance\s." : "This is your last try."]", "Robot Icon", icontype, null) in module_sprites + icon_state = module_sprites[icontype] + update_icon() + + if (module_sprites.len > 1 && triesleft >= 1 && client) + icon_selection_tries-- + var/choice = input("Look at your icon - is this what you want?") in list("Yes","No") + if(choice=="No") + choose_icon(icon_selection_tries, module_sprites) + return + + icon_selected = 1 + icon_selection_tries = 0 + to_chat(src, "Your icon has been set. You now require a module reset to change it.") + +/mob/living/silicon/robot/proc/sensor_mode() //Medical/Security HUD controller for borgs + set name = "Set Sensor Augmentation" + set category = "Silicon Commands" + set desc = "Augment visual feed with internal sensor overlays." + toggle_sensor_mode() + +/mob/living/silicon/robot/proc/add_robot_verbs() + src.verbs |= robot_verbs_default + +/mob/living/silicon/robot/proc/remove_robot_verbs() + src.verbs -= robot_verbs_default + +// Uses power from cyborg's cell. Returns 1 on success or 0 on failure. +// Properly converts using CELLRATE now! Amount is in Joules. +/mob/living/silicon/robot/proc/cell_use_power(var/amount = 0) + // No cell inserted + if(!cell) + return 0 + + var/power_use = amount * CYBORG_POWER_USAGE_MULTIPLIER + if(cell.checked_use(CELLRATE * power_use)) + used_power_this_tick += power_use + return 1 + return 0 + +/mob/living/silicon/robot/binarycheck() + if(is_component_functioning("comms")) + var/datum/robot_component/RC = get_component("comms") + use_power(RC.active_usage) + return 1 + return 0 + +/mob/living/silicon/robot/proc/notify_ai(var/notifytype, var/first_arg, var/second_arg) + if(!connected_ai) + return + switch(notifytype) + if(ROBOT_NOTIFICATION_NEW_UNIT) //New Robot + to_chat(connected_ai, "

            NOTICE - New [lowertext(braintype)] connection detected: [name]
            ") + if(ROBOT_NOTIFICATION_NEW_MODULE) //New Module + to_chat(connected_ai, "

            NOTICE - [braintype] module change detected: [name] has loaded the [first_arg].
            ") + if(ROBOT_NOTIFICATION_MODULE_RESET) + to_chat(connected_ai, "

            NOTICE - [braintype] module reset detected: [name] has unloaded the [first_arg].
            ") + if(ROBOT_NOTIFICATION_NEW_NAME) //New Name + if(first_arg != second_arg) + to_chat(connected_ai, "

            NOTICE - [braintype] reclassification detected: [first_arg] is now designated as [second_arg].
            ") +/mob/living/silicon/robot/proc/disconnect_from_ai() + if(connected_ai) + sync() // One last sync attempt + connected_ai.connected_robots -= src + connected_ai = null + +/mob/living/silicon/robot/proc/connect_to_ai(var/mob/living/silicon/ai/AI) + if(AI && AI != connected_ai) + disconnect_from_ai() + connected_ai = AI + connected_ai.connected_robots |= src + notify_ai(ROBOT_NOTIFICATION_NEW_UNIT) + sync() + +/mob/living/silicon/robot/emag_act(var/remaining_charges, var/mob/user) + if(!opened)//Cover is closed + if(locked) + if(prob(90)) + to_chat(user, "You emag the cover lock.") + locked = 0 + else + to_chat(user, "You fail to emag the cover lock.") + to_chat(src, "Hack attempt detected.") + return 1 + else + to_chat(user, "The cover is already unlocked.") + return + + if(opened)//Cover is open + if(emagged) return//Prevents the X has hit Y with Z message also you cant emag them twice + if(wiresexposed) + to_chat(user, "You must close the panel first") + return + else + sleep(6) + if(prob(50)) + emagged = 1 + lawupdate = 0 + disconnect_from_ai() + to_chat(user, "You emag [src]'s interface.") + message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.") + log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.") + clear_supplied_laws() + clear_inherent_laws() + laws = new /datum/ai_laws/syndicate_override + var/time = time2text(world.realtime,"hh:mm:ss") + GLOB.lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])") + set_zeroth_law("Only [user.real_name] and people \he designates as being such are operatives.") + SetLockdown(0) + . = 1 + spawn() + to_chat(src, "ALERT: Foreign software detected.") + sleep(5) + to_chat(src, "Initiating diagnostics...") + sleep(20) + to_chat(src, "SynBorg v1.7.1 loaded.") + sleep(5) + to_chat(src, "LAW SYNCHRONISATION ERROR") + sleep(5) + to_chat(src, "Would you like to send a report to NanoTraSoft? Y/N") + sleep(10) + to_chat(src, "> N") + sleep(20) + to_chat(src, "ERRORERRORERROR") + to_chat(src, "Obey these laws:") + laws.show_laws(src) + to_chat(src, "ALERT: [user.real_name] is your new master. Obey your new laws and his commands.") + if(src.module) + var/rebuild = 0 + for(var/obj/item/weapon/pickaxe/borgdrill/D in src.module.modules) + qdel(D) + rebuild = 1 + if(rebuild) + src.module.modules += new /obj/item/weapon/pickaxe/diamonddrill(src.module) + src.module.rebuild() + update_icon() + else + to_chat(user, "You fail to hack [src]'s interface.") + to_chat(src, "Hack attempt detected.") + return 1 + return diff --git a/code/modules/mob/living/silicon/robot/robot_damage.dm b/code/modules/mob/living/silicon/robot/robot_damage.dm new file mode 100644 index 00000000..a5b74ada --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_damage.dm @@ -0,0 +1,153 @@ +/mob/living/silicon/robot/updatehealth() + if(status_flags & GODMODE) + health = maxHealth + stat = CONSCIOUS + return + health = maxHealth - (getBruteLoss() + getFireLoss()) + return + +/mob/living/silicon/robot/getBruteLoss() + var/amount = 0 + for(var/V in components) + var/datum/robot_component/C = components[V] + if(C.installed != 0) amount += C.brute_damage + return amount + +/mob/living/silicon/robot/getFireLoss() + var/amount = 0 + for(var/V in components) + var/datum/robot_component/C = components[V] + if(C.installed != 0) amount += C.electronics_damage + return amount + +/mob/living/silicon/robot/adjustBruteLoss(var/amount) + if(amount > 0) + take_overall_damage(amount, 0) + else + heal_overall_damage(-amount, 0) + +/mob/living/silicon/robot/adjustFireLoss(var/amount) + if(amount > 0) + take_overall_damage(0, amount) + else + heal_overall_damage(0, -amount) + +/mob/living/silicon/robot/proc/get_damaged_components(var/brute, var/burn, var/destroyed = 0) + var/list/datum/robot_component/parts = list() + for(var/V in components) + var/datum/robot_component/C = components[V] + if(C.installed == 1 || (C.installed == -1 && destroyed)) + if((brute && C.brute_damage) || (burn && C.electronics_damage) || (!C.toggled) || (!C.powered && C.toggled)) + parts += C + return parts + +/mob/living/silicon/robot/proc/get_damageable_components() + var/list/rval = new + for(var/V in components) + var/datum/robot_component/C = components[V] + if(C.installed == 1) rval += C + return rval + +/mob/living/silicon/robot/proc/get_armour() + + if(!components.len) return 0 + var/datum/robot_component/C = components["armour"] + if(C && C.installed == 1) + return C + return 0 + +/mob/living/silicon/robot/heal_organ_damage(var/brute, var/burn) + var/list/datum/robot_component/parts = get_damaged_components(brute,burn) + if(!parts.len) return + var/datum/robot_component/picked = pick(parts) + picked.heal_damage(brute,burn) + +/mob/living/silicon/robot/take_organ_damage(var/brute = 0, var/burn = 0, var/sharp = 0, var/edge = 0, var/emp = 0) + var/list/components = get_damageable_components() + if(!components.len) + return + + //Combat shielding absorbs a percentage of damage directly into the cell. + if(module_active && istype(module_active,/obj/item/borg/combat/shield)) + var/obj/item/borg/combat/shield/shield = module_active + //Shields absorb a certain percentage of damage based on their power setting. + var/absorb_brute = brute*shield.shield_level + var/absorb_burn = burn*shield.shield_level + var/cost = (absorb_brute+absorb_burn)*100 + + cell.charge -= cost + if(cell.charge <= 0) + cell.charge = 0 + to_chat(src, "Your shield has overloaded!") + else + brute -= absorb_brute + burn -= absorb_burn + to_chat(src, "Your shield absorbs some of the impact!") + + if(!emp) + var/datum/robot_component/armour/A = get_armour() + if(A) + A.take_damage(brute,burn,sharp,edge) + return + + var/datum/robot_component/C = pick(components) + C.take_damage(brute,burn,sharp,edge) + +/mob/living/silicon/robot/heal_overall_damage(var/brute, var/burn) + var/list/datum/robot_component/parts = get_damaged_components(brute,burn) + + while(parts.len && (brute>0 || burn>0) ) + var/datum/robot_component/picked = pick(parts) + + var/brute_was = picked.brute_damage + var/burn_was = picked.electronics_damage + + picked.heal_damage(brute,burn) + + brute -= (brute_was-picked.brute_damage) + burn -= (burn_was-picked.electronics_damage) + + parts -= picked + +/mob/living/silicon/robot/take_overall_damage(var/brute = 0, var/burn = 0, var/sharp = 0, var/used_weapon = null) + if(status_flags & GODMODE) return //godmode + var/list/datum/robot_component/parts = get_damageable_components() + + //Combat shielding absorbs a percentage of damage directly into the cell. + if(module_active && istype(module_active,/obj/item/borg/combat/shield)) + var/obj/item/borg/combat/shield/shield = module_active + //Shields absorb a certain percentage of damage based on their power setting. + var/absorb_brute = brute*shield.shield_level + var/absorb_burn = burn*shield.shield_level + var/cost = (absorb_brute+absorb_burn)*100 + + cell.charge -= cost + if(cell.charge <= 0) + cell.charge = 0 + to_chat(src, "Your shield has overloaded!") + else + brute -= absorb_brute + burn -= absorb_burn + to_chat(src, "Your shield absorbs some of the impact!") + + var/datum/robot_component/armour/A = get_armour() + if(A) + A.take_damage(brute,burn,sharp) + return + + while(parts.len && (brute>0 || burn>0) ) + var/datum/robot_component/picked = pick(parts) + + var/brute_was = picked.brute_damage + var/burn_was = picked.electronics_damage + + picked.take_damage(brute,burn) + + brute -= (picked.brute_damage - brute_was) + burn -= (picked.electronics_damage - burn_was) + + parts -= picked + +/mob/living/silicon/robot/emp_act(severity) + uneq_all() + ..() //Damage is handled at /silicon/ level. diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm new file mode 100644 index 00000000..5748b64b --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_items.dm @@ -0,0 +1,411 @@ +//A portable analyzer, for research borgs. This is better then giving them a gripper which can hold anything and letting them use the normal analyzer. +/obj/item/weapon/portable_destructive_analyzer + name = "Portable Destructive Analyzer" + icon = 'icons/obj/items.dmi' + icon_state = "portable_analyzer" + desc = "Similar to the stationary version, this rather unwieldy device allows you to break down objects in the name of science." + + var/min_reliability = 90 //Can't upgrade, call it laziness or a drawback + + var/datum/research/techonly/files //The device uses the same datum structure as the R&D computer/server. + //This analyzer can only store tech levels, however. + + var/obj/item/weapon/loaded_item //What is currently inside the analyzer. + +/obj/item/weapon/portable_destructive_analyzer/New() + ..() + files = new /datum/research/techonly(src) //Setup the research data holder. + +/obj/item/weapon/portable_destructive_analyzer/attack_self(user as mob) + var/response = alert(user, "Analyzing the item inside will *DESTROY* the item for good.\n\ + Syncing to the research server will send the data that is stored inside to research.\n\ + Ejecting will place the loaded item onto the floor.", + "What would you like to do?", "Analyze", "Sync", "Eject") + if(response == "Analyze") + if(loaded_item) + var/confirm = alert(user, "This will destroy the item inside forever. Are you sure?","Confirm Analyze","Yes","No") + if(confirm == "Yes") //This is pretty copypasta-y + to_chat(user, "You activate the analyzer's microlaser, analyzing \the [loaded_item] and breaking it down.") + flick("portable_analyzer_scan", src) + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + for(var/T in loaded_item.origin_tech) + files.UpdateTech(T, loaded_item.origin_tech[T]) + to_chat(user, "\The [loaded_item] had level [loaded_item.origin_tech[T]] in [CallTechName(T)].") + loaded_item = null + for(var/obj/I in contents) + for(var/mob/M in I.contents) + M.death() + if(istype(I,/obj/item/stack/material))//Only deconstructs one sheet at a time instead of the entire stack + var/obj/item/stack/material/S = I + if(S.get_amount() > 1) + S.use(1) + loaded_item = S + else + qdel(S) + desc = initial(desc) + icon_state = initial(icon_state) + else + qdel(I) + desc = initial(desc) + icon_state = initial(icon_state) + else + return + else + to_chat(user, "The [src] is empty. Put something inside it first.") + if(response == "Sync") + var/success = 0 + for(var/obj/machinery/r_n_d/server/S in SSmachines.machinery) + for(var/datum/tech/T in files.known_tech) //Uploading + S.files.AddTech2Known(T) + for(var/datum/tech/T in S.files.known_tech) //Downloading + files.AddTech2Known(T) + success = 1 + files.RefreshResearch() + if(success) + to_chat(user, "You connect to the research server, push your data upstream to it, then pull the resulting merged data from the master branch.") + playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 1) + else + to_chat(user, "Reserch server ping response timed out. Unable to connect. Please contact the system administrator.") + playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 1) + if(response == "Eject") + if(loaded_item) + loaded_item.loc = get_turf(src) + desc = initial(desc) + icon_state = initial(icon_state) + loaded_item = null + else + to_chat(user, "The [src] is already empty.") + + +/obj/item/weapon/portable_destructive_analyzer/afterattack(var/atom/target, var/mob/living/user, proximity) + if(!target) + return + if(!proximity) + return + if(!isturf(target.loc)) // Don't load up stuff if it's inside a container or mob! + return + if(istype(target,/obj/item)) + if(loaded_item) + to_chat(user, "Your [src] already has something inside. Analyze or eject it first.") + return + var/obj/item/I = target + I.loc = src + loaded_item = I + for(var/mob/M in viewers()) + M.show_message(text("[user] adds the [I] to the [src]."), 1) + desc = initial(desc) + "
            It is holding \the [loaded_item]." + flick("portable_analyzer_load", src) + icon_state = "portable_analyzer_full" + +//This is used to unlock other borg covers. +/obj/item/weapon/card/robot //This is not a child of id cards, as to avoid dumb typechecks on computers. + name = "access code transmission device" + icon_state = "id-robot" + desc = "A circuit grafted onto the bottom of an ID card. It is used to transmit access codes into other robot chassis, \ + allowing you to lock and unlock other robots' panels." + +//A harvest item for serviceborgs. +/obj/item/weapon/robot_harvester + name = "auto harvester" + desc = "A hand-held harvest tool that resembles a sickle. It uses energy to cut plant matter very efficently." + icon = 'icons/obj/weapons.dmi' + icon_state = "autoharvester" + +/obj/item/weapon/robot_harvester/afterattack(var/atom/target, var/mob/living/user, proximity) + if(!target) + return + if(!proximity) + return + if(istype(target,/obj/machinery/portable_atmospherics/hydroponics)) + var/obj/machinery/portable_atmospherics/hydroponics/T = target + if(T.harvest) //Try to harvest, assuming it's alive. + T.harvest(user) + else if(T.dead) //It's probably dead otherwise. + T.remove_dead(user) + else + to_chat(user, "Harvesting \a [target] is not the purpose of this tool. \The [src] is for plants being grown.") + +// A special tray for the service droid. Allow droid to pick up and drop items as if they were using the tray normally +// Click on table to unload, click on item to load. Otherwise works identically to a tray. +// Unlike the base item "tray", robotrays ONLY pick up food, drinks and condiments. + +/obj/item/weapon/tray/robotray + name = "RoboTray" + desc = "An autoloading tray specialized for carrying refreshments." + +/obj/item/weapon/tray/robotray/afterattack(atom/target, mob/user as mob, proximity) + if(!proximity) + return + if ( !target ) + return + // pick up items, mostly copied from base tray pickup proc + // see code/game/objects/items/weapons/kitchen.dm line 241 + if ( istype(target,/obj/item)) + if ( !isturf(target.loc) ) // Don't load up stuff if it's inside a container or mob! + return + var turf/pickup = target.loc + + var addedSomething = 0 + + for(var/obj/item/weapon/reagent_containers/food/I in pickup) + + + if( I != src && !I.anchored && !istype(I, /obj/item/clothing/under) && !istype(I, /obj/item/clothing/suit) && !istype(I, /obj/item/projectile) ) + var/add = I.get_storage_cost() + if(calc_carry() + add >= max_carry) + break + + I.loc = src + carrying.Add(I) + overlays += image("icon" = I.icon, "icon_state" = I.icon_state, "layer" = 30 + I.layer) + addedSomething = 1 + if ( addedSomething ) + user.visible_message("\The [user] load some items onto their service tray.") + + return + + // Unloads the tray, copied from base item's proc dropped() and altered + // see code/game/objects/items/weapons/kitchen.dm line 263 + + if ( isturf(target) || istype(target,/obj/structure/table) ) + var foundtable = istype(target,/obj/structure/table/) + if ( !foundtable ) //it must be a turf! + for(var/obj/structure/table/T in target) + foundtable = 1 + break + + var turf/dropspot + if ( !foundtable ) // don't unload things onto walls or other silly places. + dropspot = user.loc + else if ( isturf(target) ) // they clicked on a turf with a table in it + dropspot = target + else // they clicked on a table + dropspot = target.loc + + + overlays = null + + var droppedSomething = 0 + + for(var/obj/item/I in carrying) + I.loc = dropspot + carrying.Remove(I) + droppedSomething = 1 + if(!foundtable && isturf(dropspot)) + // if no table, presume that the person just shittily dropped the tray on the ground and made a mess everywhere! + spawn() + for(var/i = 1, i <= rand(1,2), i++) + if(I) + step(I, pick(NORTH,SOUTH,EAST,WEST)) + sleep(rand(2,4)) + if ( droppedSomething ) + if ( foundtable ) + user.visible_message("[user] unloads their service tray.") + else + user.visible_message("[user] drops all the items on their tray.") + + return ..() + + + + +// A special pen for service droids. Can be toggled to switch between normal writting mode, and paper rename mode +// Allows service droids to rename paper items. + +/obj/item/weapon/pen/robopen + desc = "A black ink printing attachment with a paper naming mode." + name = "Printing Pen" + var/mode = 1 + +/obj/item/weapon/pen/robopen/attack_self(mob/user as mob) + + var/choice = input("Would you like to change colour or mode?") as null|anything in list("Colour","Mode") + if(!choice) return + + playsound(src.loc, 'sound/effects/pop.ogg', 50, 0) + + switch(choice) + + if("Colour") + var/newcolour = input("Which colour would you like to use?") as null|anything in list("black","blue","red","green","yellow") + if(newcolour) colour = newcolour + + if("Mode") + if (mode == 1) + mode = 2 + else + mode = 1 + to_chat(user, "Changed printing mode to '[mode == 2 ? "Rename Paper" : "Write Paper"]'") + + return + +// Copied over from paper's rename verb +// see code/modules/paperwork/paper.dm line 62 + +/obj/item/weapon/pen/robopen/proc/RenamePaper(mob/user as mob,obj/paper as obj) + if ( !user || !paper ) + return + var/n_name = sanitizeSafe(input(user, "What would you like to label the paper?", "Paper Labelling", null) as text, 32) + if ( !user || !paper ) + return + + //n_name = copytext(n_name, 1, 32) + if(( get_dist(user,paper) <= 1 && user.stat == 0)) + paper.SetName("paper[(n_name ? text("- '[n_name]'") : null)]") + add_fingerprint(user) + return + +//TODO: Add prewritten forms to dispense when you work out a good way to store the strings. +/obj/item/weapon/form_printer + //name = "paperwork printer" + name = "paper dispenser" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "paper_bin1" + item_state = "sheet-metal" + +/obj/item/weapon/form_printer/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) + return + +/obj/item/weapon/form_printer/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag, params) + + if(!target || !flag) + return + + if(istype(target,/obj/structure/table)) + deploy_paper(get_turf(target)) + +/obj/item/weapon/form_printer/attack_self(mob/user as mob) + deploy_paper(get_turf(src)) + +/obj/item/weapon/form_printer/proc/deploy_paper(var/turf/T) + T.visible_message("\The [src.loc] dispenses a sheet of crisp white paper.") + new /obj/item/weapon/paper(T) + + +//Personal shielding for the combat module. +/obj/item/borg/combat/shield + name = "personal shielding" + desc = "A powerful experimental module that turns aside or absorbs incoming attacks at the cost of charge." + icon = 'icons/obj/decals.dmi' + icon_state = "shock" + var/shield_level = 0.5 //Percentage of damage absorbed by the shield. + +/obj/item/borg/combat/shield/verb/set_shield_level() + set name = "Set shield level" + set category = "Object" + set src in range(0) + + var/N = input("How much damage should the shield absorb?") in list("5","10","25","50","75","100") + if (N) + shield_level = text2num(N)/100 + +/obj/item/borg/combat/mobility + name = "mobility module" + desc = "By retracting limbs and tucking in its head, a combat android can roll at high speeds." + icon = 'icons/obj/decals.dmi' + icon_state = "shock" + +/obj/item/weapon/inflatable_dispenser + name = "inflatables dispenser" + desc = "Hand-held device which allows rapid deployment and removal of inflatables." + icon = 'icons/obj/storage.dmi' + icon_state = "inf_deployer" + w_class = ITEM_SIZE_LARGE + + var/stored_walls = 5 + var/stored_doors = 2 + var/max_walls = 5 + var/max_doors = 2 + var/mode = 0 // 0 - Walls 1 - Doors + +/obj/item/weapon/inflatable_dispenser/robot + w_class = ITEM_SIZE_HUGE + stored_walls = 10 + stored_doors = 5 + max_walls = 10 + max_doors = 5 + +/obj/item/weapon/inflatable_dispenser/examine(var/mob/user) + if(!..(user)) + return + to_chat(user, "It has [stored_walls] wall segment\s and [stored_doors] door segment\s stored.") + to_chat(user, "It is set to deploy [mode ? "doors" : "walls"]") + +/obj/item/weapon/inflatable_dispenser/attack_self() + mode = !mode + to_chat(usr, "You set \the [src] to deploy [mode ? "doors" : "walls"].") + +/obj/item/weapon/inflatable_dispenser/afterattack(var/atom/A, var/mob/user) + ..(A, user) + if(!user) + return + if(!user.Adjacent(A)) + to_chat(user, "You can't reach!") + return + if(istype(A, /turf)) + try_deploy_inflatable(A, user) + if(istype(A, /obj/item/inflatable) || istype(A, /obj/structure/inflatable)) + pick_up(A, user) + +/obj/item/weapon/inflatable_dispenser/proc/try_deploy_inflatable(var/turf/T, var/mob/living/user) + if(mode) // Door deployment + if(!stored_doors) + to_chat(user, "\The [src] is out of doors!") + return + + if(T && istype(T)) + new /obj/structure/inflatable/door(T) + stored_doors-- + + else // Wall deployment + if(!stored_walls) + to_chat(user, "\The [src] is out of walls!") + return + + if(T && istype(T)) + new /obj/structure/inflatable/wall(T) + stored_walls-- + + playsound(T, 'sound/items/zip.ogg', 75, 1) + to_chat(user, "You deploy the inflatable [mode ? "door" : "wall"]!") + +/obj/item/weapon/inflatable_dispenser/proc/pick_up(var/obj/A, var/mob/living/user) + if(istype(A, /obj/structure/inflatable)) + if(istype(A, /obj/structure/inflatable/wall)) + if(stored_walls >= max_walls) + to_chat(user, "\The [src] is full.") + return + stored_walls++ + qdel(A) + else + if(stored_doors >= max_doors) + to_chat(user, "\The [src] is full.") + return + stored_doors++ + qdel(A) + playsound(loc, 'sound/machines/hiss.ogg', 75, 1) + visible_message("\The [user] deflates \the [A] with \the [src]!") + return + if(istype(A, /obj/item/inflatable)) + if(istype(A, /obj/item/inflatable/wall)) + if(stored_walls >= max_walls) + to_chat(user, "\The [src] is full.") + return + stored_walls++ + qdel(A) + else + if(stored_doors >= max_doors) + to_chat(usr, "\The [src] is full!") + return + stored_doors++ + qdel(A) + visible_message("\The [user] picks up \the [A] with \the [src]!") + return + + to_chat(user, "You fail to pick up \the [A] with \the [src]") + return + +/obj/item/weapon/reagent_containers/spray/cleaner/drone + name = "space cleaner" + desc = "BLAM!-brand non-foaming space cleaner!" + volume = 150 \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm new file mode 100644 index 00000000..22dc19d2 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -0,0 +1,782 @@ +var/global/list/robot_modules = list( + "Standard" = /obj/item/weapon/robot_module/standard, + "Service" = /obj/item/weapon/robot_module/clerical/butler, + "Clerical" = /obj/item/weapon/robot_module/clerical/general, + "Research" = /obj/item/weapon/robot_module/research, + "Miner" = /obj/item/weapon/robot_module/miner, + "Crisis" = /obj/item/weapon/robot_module/medical/crisis, + "Surgeon" = /obj/item/weapon/robot_module/medical/surgeon, + "Security" = /obj/item/weapon/robot_module/security/general, + "Combat" = /obj/item/weapon/robot_module/security/combat, + "Engineering" = /obj/item/weapon/robot_module/engineering/general, + "Janitor" = /obj/item/weapon/robot_module/janitor + ) + +/obj/item/weapon/robot_module + name = "robot module" + icon = 'icons/obj/module.dmi' + icon_state = "std_module" + w_class = ITEM_SIZE_NO_CONTAINER + item_state = "electronic" + obj_flags = OBJ_FLAG_CONDUCTIBLE + var/hide_on_manifest = 0 + var/channels = list() + var/networks = list() + var/languages = list( + LANGUAGE_SOL_COMMON = 1, + LANGUAGE_LUNAR = 1, + LANGUAGE_UNATHI = 0, + LANGUAGE_SIIK_MAAS = 0, + LANGUAGE_SKRELLIAN = 0, + LANGUAGE_GUTTER = 1, + LANGUAGE_SIGN = 0, + LANGUAGE_INDEPENDENT = 1, + LANGUAGE_SPACER = 1) + var/sprites = list() + var/can_be_pushed = 1 + var/no_slip = 0 + var/list/modules = list() + var/list/datum/matter_synth/synths = list() + var/obj/item/emag = null + var/obj/item/borg/upgrade/jetpack = null + var/list/subsystems = list() + var/list/obj/item/borg/upgrade/supported_upgrades = list() + + // Bookkeeping + var/list/original_languages = list() + var/list/added_networks = list() + +/obj/item/weapon/robot_module/New(var/mob/living/silicon/robot/R) + ..() + if (!istype(R)) + return + + R.module = src + + add_camera_networks(R) + add_languages(R) + add_subsystems(R) + apply_status_flags(R) + + if(R.silicon_radio) + R.silicon_radio.recalculateChannels() + + R.set_module_sprites(sprites) + R.choose_icon(R.module_sprites.len + 1, R.module_sprites) + + for(var/obj/item/I in modules) + I.canremove = 0 + +/obj/item/weapon/robot_module/proc/Reset(var/mob/living/silicon/robot/R) + remove_camera_networks(R) + remove_languages(R) + remove_subsystems(R) + remove_status_flags(R) + + if(R.silicon_radio) + R.silicon_radio.recalculateChannels() + R.choose_icon(0, R.set_module_sprites(list("Default" = "robot"))) + +/obj/item/weapon/robot_module/Destroy() + for(var/module in modules) + qdel(module) + for(var/synth in synths) + qdel(synth) + modules.Cut() + synths.Cut() + qdel(emag) + qdel(jetpack) + emag = null + jetpack = null + return ..() + +/obj/item/weapon/robot_module/emp_act(severity) + if(modules) + for(var/obj/O in modules) + O.emp_act(severity) + if(emag) + emag.emp_act(severity) + if(synths) + for(var/datum/matter_synth/S in synths) + S.emp_act(severity) + ..() + return + +/obj/item/weapon/robot_module/proc/respawn_consumable(var/mob/living/silicon/robot/R, var/rate) + 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 + + for(var/datum/matter_synth/T in synths) + T.add_charge(T.recharge_rate * rate) + +/obj/item/weapon/robot_module/proc/rebuild()//Rebuilds the list so it's possible to add/remove items from the module + var/list/temp_list = modules + modules = list() + for(var/obj/O in temp_list) + if(O) + modules += O + +/obj/item/weapon/robot_module/proc/add_languages(var/mob/living/silicon/robot/R) + // Stores the languages as they were before receiving the module, and whether they could be synthezized. + for(var/datum/language/language_datum in R.languages) + original_languages[language_datum] = (language_datum in R.speech_synthesizer_langs) + + for(var/language in languages) + R.add_language(language, languages[language]) + +/obj/item/weapon/robot_module/proc/remove_languages(var/mob/living/silicon/robot/R) + // Clear all added languages, whether or not we originally had them. + for(var/language in languages) + R.remove_language(language) + + // Then add back all the original languages, and the relevant synthezising ability + for(var/original_language in original_languages) + R.add_language(original_language, original_languages[original_language]) + original_languages.Cut() + +/obj/item/weapon/robot_module/proc/add_camera_networks(var/mob/living/silicon/robot/R) + if(R.camera && (NETWORK_ROBOTS in R.camera.network)) + for(var/network in networks) + if(!(network in R.camera.network)) + R.camera.add_network(network) + added_networks |= network + +/obj/item/weapon/robot_module/proc/remove_camera_networks(var/mob/living/silicon/robot/R) + if(R.camera) + R.camera.remove_networks(added_networks) + added_networks.Cut() + +/obj/item/weapon/robot_module/proc/add_subsystems(var/mob/living/silicon/robot/R) + for(var/subsystem_type in subsystems) + R.init_subsystem(subsystem_type) + +/obj/item/weapon/robot_module/proc/remove_subsystems(var/mob/living/silicon/robot/R) + for(var/subsystem_type in subsystems) + R.remove_subsystem(subsystem_type) + +/obj/item/weapon/robot_module/proc/apply_status_flags(var/mob/living/silicon/robot/R) + if(!can_be_pushed) + R.status_flags &= ~CANPUSH + +/obj/item/weapon/robot_module/proc/remove_status_flags(var/mob/living/silicon/robot/R) + if(!can_be_pushed) + R.status_flags |= CANPUSH + +/obj/item/weapon/robot_module/standard + name = "standard robot module" + sprites = list( "Basic" = "robot_old", + "Android" = "droid", + "Default" = "robot", + "Drone" = "drone-standard", + "Doot" = "eyebot-standard" + ) + +/obj/item/weapon/robot_module/standard/New() + src.modules += new /obj/item/device/flash(src) + src.modules += new /obj/item/weapon/melee/baton/loaded(src) + src.modules += new /obj/item/weapon/extinguisher(src) + src.modules += new /obj/item/weapon/wrench(src) + src.modules += new /obj/item/weapon/crowbar(src) + src.modules += new /obj/item/device/healthanalyzer(src) + src.emag = new /obj/item/weapon/melee/energy/sword(src) + ..() + +/obj/item/weapon/robot_module/medical + name = "medical robot module" + channels = list("Medical" = 1) + networks = list(NETWORK_MEDICAL) + subsystems = list(/datum/nano_module/crew_monitor) + can_be_pushed = 0 + +/obj/item/weapon/robot_module/medical/surgeon + name = "surgeon robot module" + sprites = list( + "Basic" = "Medbot", + "Standard" = "surgeon", + "Advanced Droid" = "droid-medical", + "Needles" = "medicalrobot", + "Drone" = "drone-surgery", + "Doot" = "eyebot-medical" + ) + +/obj/item/weapon/robot_module/medical/surgeon/New() + src.modules += new /obj/item/device/flash(src) + src.modules += new /obj/item/device/healthanalyzer(src) + src.modules += new /obj/item/weapon/reagent_containers/borghypo/surgeon(src) + src.modules += new /obj/item/weapon/scalpel/manager(src) + src.modules += new /obj/item/weapon/hemostat(src) + src.modules += new /obj/item/weapon/retractor(src) + src.modules += new /obj/item/weapon/cautery(src) + src.modules += new /obj/item/weapon/bonegel(src) + src.modules += new /obj/item/weapon/FixOVein(src) + src.modules += new /obj/item/weapon/bonesetter(src) + src.modules += new /obj/item/weapon/circular_saw(src) + src.modules += new /obj/item/weapon/surgicaldrill(src) + src.modules += new /obj/item/weapon/gripper/organ(src) + src.modules += new /obj/item/roller_holder(src) + src.modules += new /obj/item/weapon/shockpaddles/robot(src) + src.emag = new /obj/item/weapon/reagent_containers/spray(src) + src.emag.reagents.add_reagent(/datum/reagent/acid/polyacid, 250) + src.emag.SetName("Polyacid spray") + + var/datum/matter_synth/medicine = new /datum/matter_synth/medicine(10000) + synths += medicine + + var/obj/item/stack/nanopaste/N = new /obj/item/stack/nanopaste(src) + var/obj/item/stack/medical/advanced/bruise_pack/B = new /obj/item/stack/medical/advanced/bruise_pack(src) + N.uses_charge = 1 + N.charge_costs = list(1000) + N.synths = list(medicine) + B.uses_charge = 1 + B.charge_costs = list(1000) + B.synths = list(medicine) + src.modules += N + src.modules += B + + ..() + +/obj/item/weapon/robot_module/medical/surgeon/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) + if(src.emag) + var/obj/item/weapon/reagent_containers/spray/PS = src.emag + PS.reagents.add_reagent(/datum/reagent/acid/polyacid, 2 * amount) + ..() + +/obj/item/weapon/robot_module/medical/crisis + name = "crisis robot module" + sprites = list( + "Basic" = "Medbot", + "Standard" = "surgeon", + "Advanced Droid" = "droid-medical", + "Needles" = "medicalrobot", + "Drone - Medical" = "drone-medical", + "Drone - Chemistry" = "drone-chemistry", + "Doot" = "eyebot-medical" + ) + +/obj/item/weapon/robot_module/medical/crisis/New() + src.modules += new /obj/item/weapon/crowbar(src) + src.modules += new /obj/item/device/flash(src) + src.modules += new /obj/item/borg/sight/hud/med(src) + src.modules += new /obj/item/device/healthanalyzer(src) + src.modules += new /obj/item/device/reagent_scanner/adv(src) + src.modules += new /obj/item/roller_holder(src) + src.modules += new /obj/item/weapon/reagent_containers/borghypo/crisis(src) + src.modules += new /obj/item/weapon/shockpaddles/robot(src) + src.modules += new /obj/item/weapon/reagent_containers/dropper/industrial(src) + src.modules += new /obj/item/weapon/reagent_containers/syringe(src) + src.modules += new /obj/item/weapon/gripper/chemistry(src) + src.modules += new /obj/item/weapon/extinguisher/mini(src) + src.modules += new /obj/item/taperoll/medical(src) + src.modules += new /obj/item/weapon/inflatable_dispenser/robot(src) // Allows usage of inflatables. Since they are basically robotic alternative to EMTs, they should probably have them. + src.emag = new /obj/item/weapon/reagent_containers/spray(src) + src.emag.reagents.add_reagent(/datum/reagent/acid/polyacid, 250) + src.emag.SetName("Polyacid spray") + + var/datum/matter_synth/medicine = new /datum/matter_synth/medicine(15000) + synths += medicine + + var/obj/item/stack/medical/ointment/O = new /obj/item/stack/medical/ointment(src) + var/obj/item/stack/medical/bruise_pack/B = new /obj/item/stack/medical/bruise_pack(src) + var/obj/item/stack/medical/splint/S = new /obj/item/stack/medical/splint(src) + O.uses_charge = 1 + O.charge_costs = list(1000) + O.synths = list(medicine) + B.uses_charge = 1 + B.charge_costs = list(1000) + B.synths = list(medicine) + S.uses_charge = 1 + S.charge_costs = list(1000) + S.synths = list(medicine) + src.modules += O + src.modules += B + src.modules += S + + ..() + +/obj/item/weapon/robot_module/medical/crisis/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) + var/obj/item/weapon/reagent_containers/syringe/S = locate() in src.modules + if(S.mode == 2) + S.reagents.clear_reagents() + S.mode = initial(S.mode) + S.desc = initial(S.desc) + S.update_icon() + + if(src.emag) + var/obj/item/weapon/reagent_containers/spray/PS = src.emag + PS.reagents.add_reagent(/datum/reagent/acid/polyacid, 2 * amount) + + ..() + + +/obj/item/weapon/robot_module/engineering + name = "engineering robot module" + channels = list("Engineering" = 1) + networks = list(NETWORK_ENGINEERING) + subsystems = list(/datum/nano_module/power_monitor, /datum/nano_module/supermatter_monitor) + supported_upgrades = list(/obj/item/borg/upgrade/rcd) + sprites = list( + "Basic" = "Engineering", + "Antique" = "engineerrobot", + "Landmate" = "landmate", + "Landmate - Treaded" = "engiborg+tread", + "Drone" = "drone-engineer", + "Doot" = "eyebot-engineering" + ) + no_slip = 1 + +/obj/item/weapon/robot_module/engineering/general/New() + src.modules += new /obj/item/device/flash(src) + src.modules += new /obj/item/borg/sight/meson(src) + src.modules += new /obj/item/weapon/extinguisher(src) + src.modules += new /obj/item/weapon/weldingtool/largetank(src) + src.modules += new /obj/item/weapon/screwdriver(src) + src.modules += new /obj/item/weapon/wrench(src) + src.modules += new /obj/item/weapon/crowbar(src) + src.modules += new /obj/item/weapon/wirecutters(src) + src.modules += new /obj/item/device/multitool(src) + src.modules += new /obj/item/device/t_scanner(src) + src.modules += new /obj/item/device/analyzer(src) + src.modules += new /obj/item/device/geiger(src) + src.modules += new /obj/item/taperoll/engineering(src) + src.modules += new /obj/item/taperoll/atmos(src) + src.modules += new /obj/item/weapon/gripper(src) + src.modules += new /obj/item/device/lightreplacer(src) + src.modules += new /obj/item/device/pipe_painter(src) + src.modules += new /obj/item/device/floor_painter(src) + src.modules += new /obj/item/weapon/inflatable_dispenser/robot(src) + src.emag = new /obj/item/weapon/melee/baton/robot/electrified_arm(src) + + var/datum/matter_synth/metal = new /datum/matter_synth/metal(60000) + var/datum/matter_synth/glass = new /datum/matter_synth/glass(40000) + var/datum/matter_synth/plasteel = new /datum/matter_synth/plasteel(20000) + var/datum/matter_synth/wire = new /datum/matter_synth/wire() + synths += metal + synths += glass + synths += plasteel + synths += wire + + var/obj/item/weapon/matter_decompiler/MD = new /obj/item/weapon/matter_decompiler(src) + MD.metal = metal + MD.glass = glass + src.modules += MD + + var/obj/item/stack/material/cyborg/steel/M = new (src) + M.synths = list(metal) + src.modules += M + + var/obj/item/stack/material/cyborg/glass/G = new (src) + G.synths = list(glass) + src.modules += G + + var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src) + R.synths = list(metal) + src.modules += R + + var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src) + C.synths = list(wire) + src.modules += C + + var/obj/item/stack/tile/floor/cyborg/S = new /obj/item/stack/tile/floor/cyborg(src) + S.synths = list(metal) + src.modules += S + + var/obj/item/stack/material/cyborg/glass/reinforced/RG = new (src) + RG.synths = list(metal, glass) + src.modules += RG + + var/obj/item/stack/material/cyborg/plasteel/PL = new (src) + PL.synths = list(plasteel) + src.modules += PL + + ..() + +/obj/item/weapon/robot_module/engineering/general/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) + var/obj/item/device/lightreplacer/LR = locate() in src.modules + LR.Charge(R, amount) + ..() + +/obj/item/weapon/robot_module/security + name = "security robot module" + channels = list("Security" = 1) + networks = list(NETWORK_SECURITY) + subsystems = list(/datum/nano_module/crew_monitor, /datum/nano_module/digitalwarrant) + can_be_pushed = 0 + supported_upgrades = list(/obj/item/borg/upgrade/tasercooler) + +/obj/item/weapon/robot_module/security/general + sprites = list( + "Basic" = "secborg", + "Red Knight" = "Security", + "Black Knight" = "securityrobot", + "Bloodhound" = "bloodhound", + "Bloodhound - Treaded" = "secborg+tread", + "Drone" = "drone-sec", + "Doot" = "eyebot-security", + "Tridroid" = "orb-security" + ) + +/obj/item/weapon/robot_module/security/general/New() + src.modules += new /obj/item/device/flash(src) + src.modules += new /obj/item/borg/sight/hud/sec(src) + src.modules += new /obj/item/weapon/handcuffs/cyborg(src) + src.modules += new /obj/item/weapon/melee/baton/robot(src) + src.modules += new /obj/item/weapon/gun/energy/taser/mounted/cyborg(src) + src.modules += new /obj/item/taperoll/police(src) + src.modules += new /obj/item/device/megaphone(src) + src.emag = new /obj/item/weapon/gun/energy/laser/mounted(src) + ..() + +/obj/item/weapon/robot_module/security/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) + ..() + var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in src.modules + if(T && T.power_supply) + if(T.power_supply.charge < T.power_supply.maxcharge) + T.power_supply.give(T.charge_cost * amount) + T.update_icon() + else + T.charge_tick = 0 + + var/obj/item/weapon/melee/baton/robot/B = locate() in src.modules + if(B && B.bcell) + B.bcell.give(amount) + +/obj/item/weapon/robot_module/janitor + name = "janitorial robot module" + channels = list("Service" = 1) + sprites = list( + "Basic" = "JanBot2", + "Mopbot" = "janitorrobot", + "Mop Gear Rex" = "mopgearrex", + "Drone" = "drone-janitor", + "Doot" = "eyebot-janitor" + ) + +/obj/item/weapon/robot_module/janitor/New() + src.modules += new /obj/item/device/flash(src) + src.modules += new /obj/item/weapon/soap/nanotrasen(src) + src.modules += new /obj/item/weapon/storage/bag/trash(src) + src.modules += new /obj/item/weapon/mop(src) + src.modules += new /obj/item/device/lightreplacer(src) + src.emag = new /obj/item/weapon/reagent_containers/spray(src) + src.emag.reagents.add_reagent(/datum/reagent/lube, 250) + src.emag.SetName("Lube spray") + ..() + +/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) + var/obj/item/weapon/reagent_containers/spray/S = src.emag + S.reagents.add_reagent(/datum/reagent/lube, 20 * amount) + +/obj/item/weapon/robot_module/clerical + name = "service robot module" + channels = list("Service" = 1) + languages = list( + LANGUAGE_SOL_COMMON = 1, + LANGUAGE_UNATHI = 1, + LANGUAGE_SIIK_MAAS = 1, + LANGUAGE_SIIK_TAJR = 0, + LANGUAGE_SKRELLIAN = 1, + LANGUAGE_LUNAR = 1, + LANGUAGE_GUTTER = 1, + LANGUAGE_INDEPENDENT= 1, + LANGUAGE_SPACER = 1 + ) + +/obj/item/weapon/robot_module/clerical/butler + sprites = list( "Waitress" = "Service", + "Kent" = "toiletbot", + "Bro" = "Brobot", + "Rich" = "maximillion", + "Default" = "Service2", + "Drone - Service" = "drone-service", + "Drone - Hydro" = "drone-hydro", + "Doot" = "eyebot-standard" + ) + +/obj/item/weapon/robot_module/clerical/butler/New() + src.modules += new /obj/item/device/flash(src) + src.modules += new /obj/item/weapon/gripper/service(src) + src.modules += new /obj/item/weapon/reagent_containers/glass/bucket(src) + src.modules += new /obj/item/weapon/material/minihoe(src) + src.modules += new /obj/item/weapon/material/hatchet(src) + src.modules += new /obj/item/device/analyzer/plant_analyzer(src) + src.modules += new /obj/item/weapon/storage/plants(src) + src.modules += new /obj/item/weapon/robot_harvester(src) + src.modules += new /obj/item/weapon/material/kitchen/rollingpin(src) + src.modules += new /obj/item/weapon/material/knife(src) + + var/obj/item/weapon/rsf/M = new /obj/item/weapon/rsf(src) + M.stored_matter = 30 + src.modules += M + + src.modules += new /obj/item/weapon/reagent_containers/dropper/industrial(src) + + var/obj/item/weapon/flame/lighter/zippo/L = new /obj/item/weapon/flame/lighter/zippo(src) + L.lit = 1 + src.modules += L + + src.modules += new /obj/item/weapon/tray/robotray(src) + src.modules += new /obj/item/weapon/reagent_containers/borghypo/service(src) + src.emag = new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer(src) + + var/datum/reagents/R = src.emag.create_reagents(50) + R.add_reagent(/datum/reagent/chloralhydrate/beer2, 50) + src.emag.SetName("Mickey Finn's Special Brew") + ..() + +/obj/item/weapon/robot_module/clerical/general + name = "clerical robot module" + sprites = list( + "Waitress" = "Service", + "Kent" = "toiletbot", + "Bro" = "Brobot", + "Rich" = "maximillion", + "Default" = "Service2", + "Drone" = "drone-service", + "Doot" = "eyebot-standard" + ) + +/obj/item/weapon/robot_module/clerical/general/New() + src.modules += new /obj/item/device/flash(src) + src.modules += new /obj/item/weapon/pen/robopen(src) + src.modules += new /obj/item/weapon/form_printer(src) + src.modules += new /obj/item/weapon/gripper/paperwork(src) + src.modules += new /obj/item/weapon/hand_labeler(src) + src.modules += new /obj/item/weapon/stamp(src) + src.modules += new /obj/item/weapon/stamp/denied(src) + src.emag = new /obj/item/weapon/stamp/chameleon(src) + ..() + +/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(/datum/reagent/enzyme, 2 * amount) + if(src.emag) + var/obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer/B = src.emag + B.reagents.add_reagent(/datum/reagent/chloralhydrate/beer2, 2 * amount) + +/obj/item/weapon/robot_module/miner + name = "miner robot module" + subsystems = list(/datum/nano_module/supply) + channels = list("Supply" = 1, "Science" = 1) + networks = list(NETWORK_MINE) + sprites = list( + "Basic" = "Miner_old", + "Advanced Droid" = "droid-miner", + "Treadhead" = "Miner", + "Drone" = "drone-miner", + "Doot" = "eyebot-miner" + ) + supported_upgrades = list(/obj/item/borg/upgrade/jetpack) + +/obj/item/weapon/robot_module/miner/New() + src.modules += new /obj/item/device/flash(src) + src.modules += new /obj/item/borg/sight/meson(src) + src.modules += new /obj/item/weapon/wrench(src) + src.modules += new /obj/item/weapon/screwdriver(src) + src.modules += new /obj/item/weapon/storage/ore(src) + src.modules += new /obj/item/weapon/pickaxe/borgdrill(src) + src.modules += new /obj/item/weapon/storage/sheetsnatcher/borg(src) + src.modules += new /obj/item/weapon/gripper/miner(src) + src.modules += new /obj/item/weapon/mining_scanner(src) + src.modules += new /obj/item/weapon/crowbar(src) + src.emag = new /obj/item/weapon/gun/energy/plasmacutter(src) + ..() + +/obj/item/weapon/robot_module/research + name = "research module" + channels = list("Science" = 1) + networks = list(NETWORK_RESEARCH) + sprites = list( + "Droid" = "droid-science", + "Drone" = "drone-science", + "Doot" = "eyebot-science" + ) + +/obj/item/weapon/robot_module/research/New() + src.modules += new /obj/item/device/flash(src) + src.modules += new /obj/item/weapon/portable_destructive_analyzer(src) + src.modules += new /obj/item/weapon/gripper/research(src) + src.modules += new /obj/item/weapon/gripper/no_use/loader(src) + src.modules += new /obj/item/device/robotanalyzer(src) + src.modules += new /obj/item/weapon/card/robot(src) + src.modules += new /obj/item/weapon/wrench(src) + src.modules += new /obj/item/weapon/screwdriver(src) + src.modules += new /obj/item/weapon/weldingtool/mini(src) + src.modules += new /obj/item/weapon/wirecutters(src) + src.modules += new /obj/item/weapon/crowbar(src) + src.modules += new /obj/item/weapon/scalpel/laser3(src) + src.modules += new /obj/item/weapon/circular_saw(src) + src.modules += new /obj/item/weapon/extinguisher/mini(src) + src.modules += new /obj/item/weapon/reagent_containers/syringe(src) + src.modules += new /obj/item/weapon/gripper/chemistry(src) + //src.emag = new /obj/prefab/hand_teleporter(src) + + var/datum/matter_synth/nanite = new /datum/matter_synth/nanite(10000) + synths += nanite + + var/obj/item/stack/nanopaste/N = new /obj/item/stack/nanopaste(src) + N.uses_charge = 1 + N.charge_costs = list(1000) + N.synths = list(nanite) + src.modules += N + + ..() + +/obj/item/weapon/robot_module/syndicate + name = "illegal robot module" + hide_on_manifest = 1 + sprites = list( + "Dread" = "securityrobot", + ) + var/id + +/obj/item/weapon/robot_module/syndicate/New(var/mob/living/silicon/robot/R) + loc = R + src.modules += new /obj/item/device/flash(src) + src.modules += new /obj/item/weapon/melee/energy/sword(src) + src.modules += new /obj/item/weapon/gun/energy/pulse_rifle/destroyer(src) + src.modules += new /obj/item/weapon/card/emag(src) + var/jetpack = new/obj/item/weapon/tank/jetpack/carbondioxide(src) + src.modules += jetpack + R.internals = jetpack + + id = R.idcard + src.modules += id + ..() + +/obj/item/weapon/robot_module/syndicate/Destroy() + src.modules -= id + id = null + return ..() + +/obj/item/weapon/robot_module/security/combat + name = "combat robot module" + hide_on_manifest = 1 + sprites = list("Combat Android" = "droid-combat") + +/obj/item/weapon/robot_module/security/combat/New() + src.modules += new /obj/item/device/flash(src) + src.modules += new /obj/item/borg/sight/thermal(src) + src.modules += new /obj/item/weapon/gun/energy/laser/mounted(src) + src.modules += new /obj/item/weapon/gun/energy/plasmacutter(src) + src.modules += new /obj/item/borg/combat/shield(src) + src.modules += new /obj/item/borg/combat/mobility(src) + src.emag = new /obj/item/weapon/gun/energy/lasercannon/mounted(src) + ..() + +/obj/item/weapon/robot_module/drone + name = "drone module" + hide_on_manifest = 1 + no_slip = 1 + networks = list(NETWORK_ENGINEERING) + +/obj/item/weapon/robot_module/drone/New(var/mob/living/silicon/robot/robot) + src.modules += new /obj/item/weapon/weldingtool(src) + src.modules += new /obj/item/weapon/screwdriver(src) + src.modules += new /obj/item/weapon/wrench(src) + src.modules += new /obj/item/weapon/crowbar(src) + src.modules += new /obj/item/weapon/wirecutters(src) + src.modules += new /obj/item/device/multitool(src) + src.modules += new /obj/item/device/lightreplacer(src) + src.modules += new /obj/item/weapon/gripper(src) + src.modules += new /obj/item/weapon/soap(src) + src.modules += new /obj/item/weapon/gripper/no_use/loader(src) + src.modules += new /obj/item/weapon/extinguisher/mini(src) + src.modules += new /obj/item/device/pipe_painter(src) + src.modules += new /obj/item/device/floor_painter(src) + src.modules += new /obj/item/weapon/reagent_containers/spray/cleaner/drone(src) + + robot.internals = new/obj/item/weapon/tank/jetpack/carbondioxide(src) + src.modules += robot.internals + + src.emag = new /obj/item/weapon/gun/energy/plasmacutter(src) + src.emag.SetName("Plasma Cutter") + + var/datum/matter_synth/metal = new /datum/matter_synth/metal(25000) + var/datum/matter_synth/glass = new /datum/matter_synth/glass(25000) + var/datum/matter_synth/wood = new /datum/matter_synth/wood(2000) + var/datum/matter_synth/plastic = new /datum/matter_synth/plastic(1000) + var/datum/matter_synth/wire = new /datum/matter_synth/wire(30) + synths += metal + synths += glass + synths += wood + synths += plastic + synths += wire + + var/obj/item/weapon/matter_decompiler/MD = new /obj/item/weapon/matter_decompiler(src) + MD.metal = metal + MD.glass = glass + MD.wood = wood + MD.plastic = plastic + src.modules += MD + + var/obj/item/stack/material/cyborg/steel/M = new (src) + M.synths = list(metal) + src.modules += M + + var/obj/item/stack/material/cyborg/glass/G = new (src) + G.synths = list(glass) + src.modules += G + + var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src) + R.synths = list(metal) + src.modules += R + + var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src) + C.synths = list(wire) + src.modules += C + + var/obj/item/stack/tile/floor/cyborg/S = new /obj/item/stack/tile/floor/cyborg(src) + S.synths = list(metal) + src.modules += S + + var/obj/item/stack/material/cyborg/glass/reinforced/RG = new (src) + RG.synths = list(metal, glass) + src.modules += RG + + var/obj/item/stack/tile/wood/cyborg/WT = new /obj/item/stack/tile/wood/cyborg(src) + WT.synths = list(wood) + src.modules += WT + + var/obj/item/stack/material/cyborg/wood/W = new (src) + W.synths = list(wood) + src.modules += W + + var/obj/item/stack/material/cyborg/plastic/P = new (src) + P.synths = list(plastic) + src.modules += P + ..() + +/obj/item/weapon/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) + ..() + var/obj/item/weapon/reagent_containers/spray/cleaner/drone/SC = locate() in src.modules + SC.reagents.add_reagent(/datum/reagent/space_cleaner, 8 * amount) + +/obj/item/weapon/robot_module/drone/construction + name = "construction drone module" + hide_on_manifest = 1 + channels = list("Engineering" = 1) + languages = list() + +/obj/item/weapon/robot_module/drone/construction/New() + src.modules += new /obj/item/weapon/rcd/borg(src) + ..() + +/obj/item/weapon/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) + var/obj/item/device/lightreplacer/LR = locate() in src.modules + LR.Charge(R, amount) + ..() + return diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm new file mode 100644 index 00000000..9da12448 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_movement.dm @@ -0,0 +1,37 @@ +/mob/living/silicon/robot/slip_chance(var/prob_slip) + if(module && module.no_slip) + return 0 + ..(prob_slip) + +/mob/living/silicon/robot/Check_Shoegrip() + if(module && module.no_slip) + return 1 + return 0 + +/mob/living/silicon/robot/Allow_Spacemove() + if(module) + for(var/obj/item/weapon/tank/jetpack/J in module.modules) + if(J && J.allow_thrust(0.01)) + return 1 + . = ..() + + + //No longer needed, but I'll leave it here incase we plan to re-use it. +/mob/living/silicon/robot/movement_delay() + var/tally = ..() //Incase I need to add stuff other than "speed" later + + tally += speed + + if(module_active && istype(module_active,/obj/item/borg/combat/mobility)) + tally-=3 + + return tally+config.robot_delay + +// NEW: Use power while moving. +/mob/living/silicon/robot/SelfMove(turf/n, direct) + if (!is_component_functioning("actuator")) + return 0 + + var/datum/robot_component/actuator/A = get_component("actuator") + if (cell_use_power(A.active_usage)) + return ..() diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm new file mode 100644 index 00000000..566e2ed4 --- /dev/null +++ b/code/modules/mob/living/silicon/say.dm @@ -0,0 +1,139 @@ +/mob/living/silicon/say(var/message, var/sanitize = 1) + return ..(sanitize ? sanitize(message) : message) + +/mob/living/silicon/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) + log_say("[key_name(src)] : [message]") + +/mob/living/silicon/robot/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) + ..() + if(message_mode) + if(!is_component_functioning("radio")) + to_chat(src, "Your radio isn't functional at this time.") + return 0 + if(message_mode == "general") + message_mode = null + return silicon_radio.talk_into(src,message,message_mode,verb,speaking) + +/mob/living/silicon/ai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) + ..() + if(message_mode == "department") + return holopad_talk(message, verb, speaking) + else if(message_mode) + if (ai_radio.disabledAi || !has_power() || stat) + to_chat(src, "System Error - Transceiver Disabled.") + return 0 + if(message_mode == "general") + message_mode = null + return ai_radio.talk_into(src,message,message_mode,verb,speaking) + +/mob/living/silicon/pai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) + ..() + if(message_mode) + if(message_mode == "general") + message_mode = null + return silicon_radio.talk_into(src,message,message_mode,verb,speaking) + +/mob/living/silicon/say_quote(var/text) + var/ending = copytext(text, length(text)) + + if (ending == "?") + return speak_query + else if (ending == "!") + return speak_exclamation + + return speak_statement + +#define IS_AI 1 +#define IS_ROBOT 2 +#define IS_PAI 3 + +/mob/living/silicon/say_understands(var/other,var/datum/language/speaking = null) + //These only pertain to common. Languages are handled by mob/say_understands() + if (!speaking) + if (istype(other, /mob/living/carbon)) + return 1 + if (istype(other, /mob/living/silicon)) + return 1 + if (istype(other, /mob/living/carbon/brain)) + return 1 + return ..() + +//For holopads only. Usable by AI. +/mob/living/silicon/ai/proc/holopad_talk(var/message, verb, datum/language/speaking) + + log_say("[key_name(src)] : [message]") + + message = trim(message) + + 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. + + // AI can hear their own message, this formats it for them. + if(speaking) + to_chat(src, "Holopad transmitted, [real_name] [speaking.format_message(message, verb)]") + else + to_chat(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 GLOB.player_list) + if(M.stat == DEAD && M.get_preference_value(/datum/client_preference/ghost_ears) == GLOB.PREF_ALL_SPEECH) + 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) + + + else + to_chat(src, "No holopad connected.") + return 0 + return 1 + +/mob/living/silicon/ai/proc/holopad_emote(var/message) //This is called when the AI uses the 'me' verb while using a holopad. + + log_emote("[key_name(src)] : [message]") + + message = trim(message) + + if (!message) + return + + var/obj/machinery/hologram/holopad/T = src.holo + if(T && T.masters[src]) + var/rendered = "[name] [message]" + to_chat(src, "Holopad action relayed, [real_name] [message]") + + for(var/mob/M in viewers(T.loc)) + M.show_message(rendered, 2) + else //This shouldn't occur, but better safe then sorry. + to_chat(src, "No holopad connected.") + return 0 + return 1 + +#undef IS_AI +#undef IS_ROBOT +#undef IS_PAI diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm new file mode 100644 index 00000000..e1ae657e --- /dev/null +++ b/code/modules/mob/living/silicon/silicon.dm @@ -0,0 +1,376 @@ +/mob/living/silicon + gender = NEUTER + voice_name = "synthesized voice" + var/syndicate = 0 + var/const/MAIN_CHANNEL = "Main Frequency" + var/lawchannel = MAIN_CHANNEL // Default channel on which to state laws + var/list/stating_laws = list()// Channels laws are currently being stated on + var/obj/item/device/radio/silicon_radio + + var/list/hud_list[10] + var/list/speech_synthesizer_langs = list() //which languages can be vocalized by the speech synthesizer + + //Used in say.dm. + var/speak_statement = "states" + var/speak_exclamation = "declares" + var/speak_query = "queries" + var/pose //Yes, now AIs can pose too. + var/obj/item/device/camera/siliconcam/silicon_camera = null //photography + var/local_transmit //If set, can only speak to others of the same type within a short range. + + var/sensor_mode = 0 //Determines the current HUD. + + var/next_alarm_notice + var/list/datum/alarm/queued_alarms = new() + + var/list/access_rights + var/obj/item/weapon/card/id/idcard = /obj/item/weapon/card/id/synthetic + + #define SEC_HUD 1 //Security HUD mode + #define MED_HUD 2 //Medical HUD mode + +/mob/living/silicon/New() + GLOB.silicon_mob_list += src + ..() + + if(silicon_radio) + silicon_radio = new silicon_radio(src) + if(silicon_camera) + silicon_camera = new silicon_camera(src) + + add_language(LANGUAGE_GALCOM) + default_language = all_languages[LANGUAGE_GALCOM] + init_id() + init_subsystems() + +/mob/living/silicon/Destroy() + GLOB.silicon_mob_list -= src + QDEL_NULL(silicon_radio) + QDEL_NULL(silicon_camera) + for(var/datum/alarm_handler/AH in alarm_manager.all_handlers) + AH.unregister_alarm(src) + return ..() + +/mob/living/silicon/fully_replace_character_name(new_name) + ..() + if(istype(idcard)) + idcard.registered_name = new_name + idcard.update_name() + +/mob/living/silicon/proc/init_id() + if(ispath(idcard)) + idcard = new idcard(src) + set_id_info(idcard) + +/mob/living/silicon/proc/show_laws() + return + +/mob/living/silicon/drop_item() + return + +/mob/living/silicon/emp_act(severity) + switch(severity) + if(1) + src.take_organ_damage(0,20,emp=1) + Stun(rand(5,10)) + if(2) + src.take_organ_damage(0,10,emp=1) + confused = (min(confused + 2, 30)) + flash_eyes(affect_silicon = 1) + to_chat(src, "*BZZZT*") + to_chat(src, "Warning: Electromagnetic pulse detected.") + ..() + +/mob/living/silicon/stun_effect_act(var/stun_amount, var/agony_amount) + return //immune + +/mob/living/silicon/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0) + + if (istype(source, /obj/machinery/containment_field)) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, loc) + s.start() + + shock_damage *= 0.75 //take reduced damage + take_overall_damage(0, shock_damage) + visible_message("\The [src] was shocked by \the [source]!", \ + "Energy pulse detected, system damaged!", \ + "You hear an electrical crack") + if(prob(20)) + Stun(2) + return + +/mob/living/silicon/proc/damage_mob(var/brute = 0, var/fire = 0, var/tox = 0) + return + +/mob/living/silicon/IsAdvancedToolUser() + return 1 + +/mob/living/silicon/bullet_act(var/obj/item/projectile/Proj) + + if(!Proj.nodamage) + switch(Proj.damage_type) + if(BRUTE) + adjustBruteLoss(Proj.damage) + if(BURN) + adjustFireLoss(Proj.damage) + + Proj.on_hit(src,100) //wow this is a terrible hack + updatehealth() + return 100 + +/mob/living/silicon/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0) + return 0//The only effect that can hit them atm is flashes and they still directly edit so this works for now + +/proc/islinked(var/mob/living/silicon/robot/bot, var/mob/living/silicon/ai/ai) + if(!istype(bot) || !istype(ai)) + return 0 + if (bot.connected_ai == ai) + return 1 + return 0 + + +// this function shows the health of the AI in the Status panel +/mob/living/silicon/proc/show_system_integrity() + if(!src.stat) + stat(null, text("System integrity: [round((health/maxHealth)*100)]%")) + else + stat(null, text("Systems nonfunctional")) + + +// This is a pure virtual function, it should be overwritten by all subclasses +/mob/living/silicon/proc/show_malf_ai() + return 0 + +// this function displays the shuttles ETA in the status panel if the shuttle has been called +/mob/living/silicon/proc/show_emergency_shuttle_eta() + if(evacuation_controller) + var/eta_status = evacuation_controller.get_status_panel_eta() + if(eta_status) + stat(null, eta_status) + + +// This adds the basic clock, shuttle recall timer, and malf_ai info to all silicon lifeforms +/mob/living/silicon/Stat() + if(statpanel("Status")) + show_emergency_shuttle_eta() + show_system_integrity() + show_malf_ai() + . = ..() + +// this function displays the stations manifest in a separate window +/mob/living/silicon/proc/show_station_manifest() + var/dat + dat += "

            Crew Manifest

            " + dat += html_crew_manifest(1) // make it monochrome + dat += "
            " + src << browse(dat, "window=airoster") + onclose(src, "airoster") + +//can't inject synths +/mob/living/silicon/can_inject(var/mob/user, var/target_zone) + to_chat(user, "The armoured plating is too tough.") + return 0 + + +//Silicon mob language procs + +/mob/living/silicon/can_speak(datum/language/speaking) + return universal_speak || (speaking in src.speech_synthesizer_langs) //need speech synthesizer support to vocalize a language + +/mob/living/silicon/add_language(var/language, var/can_speak=1) + var/var/datum/language/added_language = all_languages[language] + if(!added_language) + return + + . = ..(language) + if (can_speak && (added_language in languages) && !(added_language in speech_synthesizer_langs)) + speech_synthesizer_langs += added_language + return 1 + +/mob/living/silicon/remove_language(var/rem_language) + var/var/datum/language/removed_language = all_languages[rem_language] + if(!removed_language) + return + + ..(rem_language) + speech_synthesizer_langs -= removed_language + +/mob/living/silicon/check_languages() + set name = "Check Known Languages" + set category = "IC" + set src = usr + + var/dat = "Known Languages

            " + + if(default_language) + dat += "Current default language: [default_language] - reset

            " + + for(var/datum/language/L in languages) + if(!(L.flags & NONGLOBAL)) + var/default_str + if(L == default_language) + default_str = " - default - reset" + else + default_str = " - set default" + + var/synth = (L in speech_synthesizer_langs) + dat += "[L.name] ([get_language_prefix()][L.key])[synth ? default_str : null]
            Speech Synthesizer: [synth ? "YES" : "NOT SUPPORTED"]
            [L.desc]

            " + + src << browse(dat, "window=checklanguage") + return + +/mob/living/silicon/proc/toggle_sensor_mode() + var/sensor_type = input("Please select sensor type.", "Sensor Integration", null) in list("Security", "Medical","Disable") + switch(sensor_type) + if ("Security") + sensor_mode = SEC_HUD + to_chat(src, "Security records overlay enabled.") + if ("Medical") + sensor_mode = MED_HUD + to_chat(src, "Life signs monitor overlay enabled.") + if ("Disable") + sensor_mode = 0 + to_chat(src, "Sensor augmentations disabled.") + +/mob/living/silicon/verb/pose() + set name = "Set Pose" + set desc = "Sets a description which will be shown when someone examines you." + set category = "IC" + + pose = sanitize(input(usr, "This is [src]. It is...", "Pose", null) as text) + +/mob/living/silicon/verb/set_flavor() + set name = "Set Flavour Text" + set desc = "Sets an extended description of your character's features." + set category = "IC" + + flavor_text = sanitize(input(usr, "Please enter your new flavour text.", "Flavour text", null) as text) + +/mob/living/silicon/binarycheck() + return 1 + +/mob/living/silicon/ex_act(severity) + if(!blinded) + flash_eyes() + + var/brute + var/burn + switch(severity) + if(1.0) + brute = 400 + burn = 100 + if(!anchored && !prob(getarmor(null, "bomb"))) + gib() + if(2.0) + brute = 60 + burn = 60 + if(3.0) + brute = 30 + + var/protection = blocked_mult(getarmor(null, "bomb")) + brute *= protection + burn *= protection + + adjustBruteLoss(brute) + adjustFireLoss(burn) + + updatehealth() + +/mob/living/silicon/proc/receive_alarm(var/datum/alarm_handler/alarm_handler, var/datum/alarm/alarm, was_raised) + if(!next_alarm_notice) + next_alarm_notice = world.time + SecondsToTicks(10) + + var/list/alarms = queued_alarms[alarm_handler] + if(was_raised) + // Raised alarms are always set + alarms[alarm] = 1 + else + // Alarms that were raised but then cleared before the next notice are instead removed + if(alarm in alarms) + alarms -= alarm + // And alarms that have only been cleared thus far are set as such + else + alarms[alarm] = -1 + +/mob/living/silicon/proc/process_queued_alarms() + if(next_alarm_notice && (world.time > next_alarm_notice)) + next_alarm_notice = 0 + + var/alarm_raised = 0 + for(var/datum/alarm_handler/AH in queued_alarms) + var/list/alarms = queued_alarms[AH] + var/reported = 0 + for(var/datum/alarm/A in alarms) + if(alarms[A] == 1) + alarm_raised = 1 + if(!reported) + reported = 1 + to_chat(src, "--- [AH.category] Detected ---") + raised_alarm(A) + + for(var/datum/alarm_handler/AH in queued_alarms) + var/list/alarms = queued_alarms[AH] + var/reported = 0 + for(var/datum/alarm/A in alarms) + if(alarms[A] == -1) + if(!reported) + reported = 1 + to_chat(src, "--- [AH.category] Cleared ---") + to_chat(src, "\The [A.alarm_name()].") + + if(alarm_raised) + to_chat(src, "\[Show Alerts\]") + + for(var/datum/alarm_handler/AH in queued_alarms) + var/list/alarms = queued_alarms[AH] + alarms.Cut() + +/mob/living/silicon/proc/raised_alarm(var/datum/alarm/A) + to_chat(src, "[A.alarm_name()]!") + +/mob/living/silicon/ai/raised_alarm(var/datum/alarm/A) + var/cameratext = "" + for(var/obj/machinery/camera/C in A.cameras()) + cameratext += "[(cameratext == "")? "" : "|"][C.c_tag]" + to_chat(src, "[A.alarm_name()]! ([(cameratext)? cameratext : "No Camera"])") + + +/mob/living/silicon/proc/is_traitor() + return mind && (mind in traitors.current_antagonists) + +/mob/living/silicon/proc/is_malf() + return mind && (mind in malf.current_antagonists) + +/mob/living/silicon/proc/is_malf_or_traitor() + return is_traitor() || is_malf() + +/mob/living/silicon/adjustEarDamage() + return + +/mob/living/silicon/setEarDamage() + return + +/mob/living/silicon/reset_view() + ..() + if(cameraFollow) + cameraFollow = null + +/mob/living/silicon/proc/clear_client() + //Handle job slot/tater cleanup. + var/job = mind.assigned_role + + job_master.FreeRole(job) + + if(mind.objectives.len) + qdel(mind.objectives) + mind.special_role = null + + clear_antag_roles(mind) + + ghostize(0) + qdel(src) + +/mob/living/silicon/flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash) + if(affect_silicon) + return ..() diff --git a/code/modules/mob/living/silicon/subsystems.dm b/code/modules/mob/living/silicon/subsystems.dm new file mode 100644 index 00000000..6641fd48 --- /dev/null +++ b/code/modules/mob/living/silicon/subsystems.dm @@ -0,0 +1,108 @@ +/mob/living/silicon + var/list/silicon_subsystems_by_name = list() + var/list/silicon_subsystems = list( + /datum/nano_module/alarm_monitor/all, + /datum/nano_module/law_manager + ) + +/mob/living/silicon/ai/New() + silicon_subsystems.Cut() + for(var/subtype in subtypesof(/datum/nano_module)) + var/datum/nano_module/NM = subtype + if(initial(NM.available_to_ai)) + silicon_subsystems += NM + ..() + +/mob/living/silicon/robot/syndicate + silicon_subsystems = list( + /datum/nano_module/law_manager + ) + +/mob/living/silicon/Destroy() + for(var/subsystem in silicon_subsystems) + remove_subsystem(subsystem) + silicon_subsystems.Cut() + . = ..() + +/mob/living/silicon/proc/init_subsystems() + for(var/subsystem_type in silicon_subsystems) + init_subsystem(subsystem_type) + + if(/datum/nano_module/alarm_monitor/all in silicon_subsystems) + for(var/datum/alarm_handler/AH in alarm_manager.all_handlers) + AH.register_alarm(src, /mob/living/silicon/proc/receive_alarm) + queued_alarms[AH] = list() // Makes sure alarms remain listed in consistent order + +/mob/living/silicon/proc/init_subsystem(var/subsystem_type) + var/existing_entry = silicon_subsystems[subsystem_type] + if(existing_entry && !ispath(existing_entry)) + return FALSE + + var/ui_state = subsystem_type == /datum/nano_module/law_manager ? GLOB.conscious_state : GLOB.self_state + var/stat_silicon_subsystem/SSS = new(src, subsystem_type, ui_state) + silicon_subsystems[subsystem_type] = SSS + silicon_subsystems_by_name[SSS.name] = SSS + return TRUE + +/mob/living/silicon/proc/remove_subsystem(var/subsystem_type) + var/stat_silicon_subsystem/SSS = silicon_subsystems[subsystem_type] + if(!istype(SSS)) + return FALSE + + silicon_subsystems_by_name -= SSS.name + silicon_subsystems -= subsystem_type + qdel(SSS) + return TRUE + +/mob/living/silicon/proc/open_subsystem(var/subsystem_type, var/mob/given = src) + var/stat_silicon_subsystem/SSS = silicon_subsystems[subsystem_type] + if(!istype(SSS)) + return FALSE + SSS.Click(given) + return TRUE + +/mob/living/silicon/verb/activate_subsystem(var/datum/silicon_subsystem_name in silicon_subsystems_by_name) + set name = "Subsystems" + set desc = "Activates the given subsystem" + set category = "Silicon Commands" + + var/stat_silicon_subsystem/SSS = silicon_subsystems_by_name[silicon_subsystem_name] + if(istype(SSS)) + SSS.Click() + +/mob/living/silicon/Stat() + . = ..() + if(!.) + return + if(!silicon_subsystems.len) + return + if(!statpanel("Subsystems")) + return + for(var/subsystem_type in silicon_subsystems) + var/stat_silicon_subsystem/SSS = silicon_subsystems[subsystem_type] + stat(SSS) + +/stat_silicon_subsystem + parent_type = /atom/movable + simulated = 0 + var/ui_state + var/datum/nano_module/subsystem + +/stat_silicon_subsystem/New(var/mob/living/silicon/loc, var/subsystem_type, var/ui_state) + if(!istype(loc)) + CRASH("Unexpected location. Expected /mob/living/silicon, was [loc.type].") + src.ui_state = ui_state + subsystem = new subsystem_type(loc) + name = subsystem.name + ..() + +/stat_silicon_subsystem/Destroy() + qdel(subsystem) + subsystem = null + . = ..() + +/stat_silicon_subsystem/Click(var/mob/given = usr) + if (istype(given)) + subsystem.ui_interact(given, state = ui_state) + else + subsystem.ui_interact(usr, state = ui_state) diff --git a/code/modules/mob/living/simple_animal/borer/borer.dm b/code/modules/mob/living/simple_animal/borer/borer.dm new file mode 100644 index 00000000..a3ce1224 --- /dev/null +++ b/code/modules/mob/living/simple_animal/borer/borer.dm @@ -0,0 +1,185 @@ +/mob/living/simple_animal/borer + name = "cortical borer" + real_name = "cortical borer" + desc = "A small, quivering sluglike creature." + speak_emote = list("chirrups") + emote_hear = list("chirrups") + response_help = "pokes" + response_disarm = "prods" + response_harm = "stomps on" + icon_state = "brainslug" + item_state = "voxslug" // For the lack of a better sprite... + icon_living = "brainslug" + icon_dead = "brainslug_dead" + speed = 5 + a_intent = I_HURT + stop_automated_movement = 1 + status_flags = CANPUSH + attacktext = "nipped" + friendly = "prods" + wander = 0 + pass_flags = PASS_FLAG_TABLE + universal_understand = 1 + holder_type = /obj/item/weapon/holder/borer + mob_size = MOB_SMALL + + var/generation = 1 + var/static/list/borer_names = list( + "Primary", "Secondary", "Tertiary", "Quaternary", "Quinary", "Senary", + "Septenary", "Octonary", "Novenary", "Decenary", "Undenary", "Duodenary", + ) + + var/used_dominate + var/chemicals = 10 // Chemicals used for reproduction and spitting neurotoxin. + var/mob/living/carbon/human/host // Human host for the brain worm. + var/truename // Name used for brainworm-speak. + var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth. + var/controlling // Used in human death check. + var/docile = 0 // Sugar can stop borers from acting. + var/has_reproduced + var/roundstart + +/mob/living/simple_animal/borer/roundstart + roundstart = 1 + +/mob/living/simple_animal/borer/Login() + ..() + if(mind) + borers.add_antagonist(mind) + +/mob/living/simple_animal/borer/New(atom/newloc, var/gen=1) + ..(newloc) + + add_language("Cortical Link") + verbs += /mob/living/proc/ventcrawl + verbs += /mob/living/proc/hide + + generation = gen + truename = "[borer_names[min(generation, borer_names.len)]] [random_id("borer[generation]", 1000, 9999)]" + if(!roundstart) request_player() + +/mob/living/simple_animal/borer/Life() + + ..() + + if(host) + + if(!stat && !host.stat) + + if(host.reagents.has_reagent(/datum/reagent/sugar)) + if(!docile) + if(controlling) + to_chat(host, "You feel the soporific flow of sugar in your host's blood, lulling you into docility.") + else + to_chat(src, "You feel the soporific flow of sugar in your host's blood, lulling you into docility.") + docile = 1 + else + if(docile) + if(controlling) + to_chat(host, "You shake off your lethargy as the sugar leaves your host's blood.") + else + to_chat(src, "You shake off your lethargy as the sugar leaves your host's blood.") + docile = 0 + + if(chemicals < 250) + chemicals++ + if(controlling) + + if(docile) + to_chat(host, "You are feeling far too docile to continue controlling your host...") + host.release_control() + return + + if(prob(5)) + host.adjustBrainLoss(0.1) + + if(prob(host.getBrainLoss()/20)) + host.say("*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_v","gasp"))]") + +/mob/living/simple_animal/borer/Stat() + . = ..() + statpanel("Status") + + if(evacuation_controller) + var/eta_status = evacuation_controller.get_status_panel_eta() + if(eta_status) + stat(null, eta_status) + + if (client.statpanel == "Status") + stat("Chemicals", chemicals) + +/mob/living/simple_animal/borer/proc/detatch() + + if(!host || !controlling) return + + if(istype(host,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = host + var/obj/item/organ/external/head = H.get_organ(BP_HEAD) + head.implants -= src + + controlling = 0 + + host.remove_language("Cortical Link") + host.verbs -= /mob/living/carbon/proc/release_control + host.verbs -= /mob/living/carbon/proc/punish_host + host.verbs -= /mob/living/carbon/proc/spawn_larvae + + if(host_brain) + + // these are here so bans and multikey warnings are not triggered on the wrong people when ckey is changed. + // computer_id and IP are not updated magically on their own in offline mobs -walter0o + + // host -> self + var/h2s_id = host.computer_id + var/h2s_ip= host.lastKnownIP + host.computer_id = null + host.lastKnownIP = null + + src.ckey = host.ckey + + if(!src.computer_id) + src.computer_id = h2s_id + + if(!host_brain.lastKnownIP) + src.lastKnownIP = h2s_ip + + // brain -> host + var/b2h_id = host_brain.computer_id + var/b2h_ip= host_brain.lastKnownIP + host_brain.computer_id = null + host_brain.lastKnownIP = null + + host.ckey = host_brain.ckey + + if(!host.computer_id) + host.computer_id = b2h_id + + if(!host.lastKnownIP) + host.lastKnownIP = b2h_ip + + qdel(host_brain) + +/mob/living/simple_animal/borer/proc/leave_host() + + if(!host) return + + if(host.mind) + borers.remove_antagonist(host.mind) + + src.loc = get_turf(host) + + reset_view(null) + machine = null + + host.reset_view(null) + host.machine = null + + var/mob/living/H = host + H.status_flags &= ~PASSEMOTES + host = null + return + +//Procs for grabbing players. +/mob/living/simple_animal/borer/proc/request_player() + var/datum/ghosttrap/G = get_ghost_trap("cortical borer") + G.request_player(src, "A cortical borer needs a player.") \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/borer/borer_captive.dm b/code/modules/mob/living/simple_animal/borer/borer_captive.dm new file mode 100644 index 00000000..bfb8bc91 --- /dev/null +++ b/code/modules/mob/living/simple_animal/borer/borer_captive.dm @@ -0,0 +1,54 @@ +/mob/living/captive_brain + name = "host brain" + real_name = "host brain" + universal_understand = 1 + +/mob/living/captive_brain/say(var/message) + + if (src.client) + if(client.prefs.muted & MUTE_IC) + to_chat(src, "You cannot speak in IC (muted).") + return + + if(istype(src.loc,/mob/living/simple_animal/borer)) + + message = sanitize(message) + if (!message) + return + log_say("[key_name(src)] : [message]") + if (stat == 2) + return say_dead(message) + + var/mob/living/simple_animal/borer/B = src.loc + to_chat(src, "You whisper silently, \"[message]\"") + to_chat(B.host, "The captive mind of [src] whispers, \"[message]\"") + + for (var/mob/M in GLOB.player_list) + if (istype(M, /mob/new_player)) + continue + else if(M.stat == DEAD && M.get_preference_value(/datum/client_preference/ghost_ears) == GLOB.PREF_ALL_SPEECH) + to_chat(M, "The captive mind of [src] whispers, \"[message]\"") + +/mob/living/captive_brain/process_resist() + //Resisting control by an alien mind. + if(istype(src.loc,/mob/living/simple_animal/borer)) + var/mob/living/simple_animal/borer/B = src.loc + var/mob/living/captive_brain/H = src + + to_chat(H, "You begin doggedly resisting the parasite's control (this will take approximately sixty seconds).") + to_chat(B.host, "You feel the captive mind of [src] begin to resist your control.") + + spawn(rand(200,250)+B.host.getBrainLoss()) + if(!B || !B.controlling) return + + B.host.adjustBrainLoss(rand(0.1,0.5)) + to_chat(H, "With an immense exertion of will, you regain control of your body!") + to_chat(B.host, "You feel control of the host brain ripped from your grasp, and retract your probosci before the wild neural impulses can damage you.") + B.detatch() + verbs -= /mob/living/carbon/proc/release_control + verbs -= /mob/living/carbon/proc/punish_host + verbs -= /mob/living/carbon/proc/spawn_larvae + + return + + ..() diff --git a/code/modules/mob/living/simple_animal/borer/borer_powers.dm b/code/modules/mob/living/simple_animal/borer/borer_powers.dm new file mode 100644 index 00000000..872fa46f --- /dev/null +++ b/code/modules/mob/living/simple_animal/borer/borer_powers.dm @@ -0,0 +1,363 @@ +GLOBAL_LIST_INIT(borer_reagent_types_by_name, setup_borer_reagents()) + +/proc/setup_borer_reagents() + . = list() + for(var/reagent_type in list(/datum/reagent/alkysine, /datum/reagent/bicaridine, /datum/reagent/hyperzine, /datum/reagent/tramadol)) + var/datum/reagent/R = reagent_type + .[initial(R.name)] = reagent_type + +/mob/living/simple_animal/borer/verb/release_host() + set category = "Abilities" + set name = "Release Host" + set desc = "Slither out of your host." + + if(!host) + to_chat(src, "You are not inside a host body.") + return + + if(stat) + to_chat(src, "You cannot leave your host in your current state.") + + if(docile) + to_chat(src, "You are feeling far too docile to do that.") + return + + if(!host || !src) return + + to_chat(src, "You begin disconnecting from [host]'s synapses and prodding at their internal ear canal.") + + if(!host.stat) + to_chat(host, "An odd, uncomfortable pressure begins to build inside your skull, behind your ear...") + + spawn(100) + + if(!host || !src) return + + if(src.stat) + to_chat(src, "You cannot release your host in your current state.") + return + + to_chat(src, "You wiggle out of [host]'s ear and plop to the ground.") + if(host.mind) + if(!host.stat) + to_chat(host, "Something slimy wiggles out of your ear and plops to the ground!") + to_chat(host, "As though waking from a dream, you shake off the insidious mind control of the brain worm. Your thoughts are your own again.") + + detatch() + leave_host() + +/mob/living/simple_animal/borer/verb/infest() + set category = "Abilities" + set name = "Infest" + set desc = "Infest a suitable humanoid host." + + if(host) + to_chat(src, "You are already within a host.") + return + + if(stat) + to_chat(src, "You cannot infest a target in your current state.") + return + + var/list/choices = list() + for(var/mob/living/carbon/C in view(1,src)) + if(src.Adjacent(C)) + choices += C + + if(!choices.len) + to_chat(src, "There are no viable hosts within range...") + return + + var/mob/living/carbon/M = input(src,"Who do you wish to infest?") in null|choices + + if(!M || !src) return + + if(!(src.Adjacent(M))) return + + if(M.has_brain_worms()) + to_chat(src, "You cannot infest someone who is already infested!") + return + + if(istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + + var/obj/item/organ/external/E = H.organs_by_name[BP_HEAD] + if(!E || E.is_stump()) + to_chat(src, "\The [H] does not have a head!") + + if(!H.should_have_organ(BP_BRAIN)) + to_chat(src, "\The [H] does not seem to have an ear canal to breach.") + return + + if(H.check_head_coverage()) + to_chat(src, "You cannot get through that host's protective gear.") + return + + to_chat(M, "Something slimy begins probing at the opening of your ear canal...") + to_chat(src, "You slither up [M] and begin probing at their ear canal...") + + if(!do_after(src,30, progress = 0)) + to_chat(src, "As [M] moves away, you are dislodged and fall to the ground.") + return + + if(!M || !src) return + + if(src.stat) + to_chat(src, "You cannot infest a target in your current state.") + return + + if(M in view(1, src)) + to_chat(src, "You wiggle into [M]'s ear.") + if(!M.stat) + to_chat(M, "Something disgusting and slimy wiggles into your ear!") + + src.host = M + src.host.status_flags |= PASSEMOTES + src.loc = M + + //Update their traitor status. + if(host.mind) + borers.add_antagonist_mind(host.mind, 1, borers.faction_role_text, borers.faction_welcome) + + if(istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/I = H.internal_organs_by_name[BP_BRAIN] + if(!I) // No brain organ, so the borer moves in and replaces it permanently. + replace_brain() + else + // If they're in normally, implant removal can get them out. + var/obj/item/organ/external/head = H.get_organ(BP_HEAD) + head.implants += src + + return + else + to_chat(src, "They are no longer in range!") + return + +/* +/mob/living/simple_animal/borer/verb/devour_brain() + set category = "Abilities" + set name = "Devour Brain" + set desc = "Take permanent control of a dead host." + + if(!host) + to_chat(src, "You are not inside a host body.") + return + + if(host.stat != 2) + to_chat(src, "Your host is still alive.") + return + + if(stat) + to_chat(src, "You cannot do that in your current state.") + + if(docile) + to_chat(src, "You are feeling far too docile to do that.") + return + + + to_chat(src, "It only takes a few moments to render the dead host brain down into a nutrient-rich slurry...") + replace_brain() +*/ + +// BRAIN WORM ZOMBIES AAAAH. +/mob/living/simple_animal/borer/proc/replace_brain() + + var/mob/living/carbon/human/H = host + + if(!istype(host)) + to_chat(src, "This host does not have a suitable brain.") + return + + to_chat(src, "You settle into the empty brainpan and begin to expand, fusing inextricably with the dead flesh of [H].") + + H.add_language("Cortical Link") + + if(host.stat == 2) + H.verbs |= /mob/living/carbon/human/proc/jumpstart + + H.verbs |= /mob/living/carbon/human/proc/psychic_whisper + H.verbs |= /mob/living/carbon/human/proc/tackle + H.verbs |= /mob/living/carbon/proc/spawn_larvae + + if(H.client) + H.ghostize(0) + + if(src.mind) + src.mind.special_role = "Borer Husk" + src.mind.transfer_to(host) + + H.ChangeToHusk() + + var/obj/item/organ/internal/borer/B = new(H) + H.internal_organs_by_name[BP_BRAIN] = B + H.internal_organs |= B + + var/obj/item/organ/external/affecting = H.get_organ(BP_HEAD) + affecting.implants -= src + + var/s2h_id = src.computer_id + var/s2h_ip= src.lastKnownIP + src.computer_id = null + src.lastKnownIP = null + + if(!H.computer_id) + H.computer_id = s2h_id + + if(!H.lastKnownIP) + H.lastKnownIP = s2h_ip + +/mob/living/simple_animal/borer/verb/secrete_chemicals() + set category = "Abilities" + set name = "Secrete Chemicals" + set desc = "Push some chemicals into your host's bloodstream." + + if(!host) + to_chat(src, "You are not inside a host body.") + return + + if(stat) + to_chat(src, "You cannot secrete chemicals in your current state.") + + if(docile) + to_chat(src, "You are feeling far too docile to do that.") + return + + if(chemicals < 50) + to_chat(src, "You don't have enough chemicals!") + + var/chem = input("Select a chemical to secrete.", "Chemicals") as null|anything in GLOB.borer_reagent_types_by_name + + if(!chem || chemicals < 50 || !host || controlling || !src || stat) //Sanity check. + return + + to_chat(src, "You squirt a measure of [chem] from your reservoirs into \the [host]'s bloodstream.") + host.reagents.add_reagent(GLOB.borer_reagent_types_by_name[chem], 10) + chemicals -= 50 + +/mob/living/simple_animal/borer/verb/dominate_victim() + set category = "Abilities" + set name = "Paralyze Victim" + set desc = "Freeze the limbs of a potential host with supernatural fear." + + if(world.time - used_dominate < 150) + to_chat(src, "You cannot use that ability again so soon.") + return + + if(host) + to_chat(src, "You cannot do that from within a host body.") + return + + if(src.stat) + to_chat(src, "You cannot do that in your current state.") + return + + var/list/choices = list() + for(var/mob/living/carbon/C in view(3,src)) + if(C.stat != 2) + choices += C + + if(world.time - used_dominate < 150) + to_chat(src, "You cannot use that ability again so soon.") + return + + var/mob/living/carbon/M = input(src,"Who do you wish to dominate?") in null|choices + + if(!M || !src) return + + if(M.has_brain_worms()) + to_chat(src, "You cannot infest someone who is already infested!") + return + + to_chat(src, "You focus your psychic lance on [M] and freeze their limbs with a wave of terrible dread.") + to_chat(M, "You feel a creeping, horrible sense of dread come over you, freezing your limbs and setting your heart racing.") + M.Weaken(10) + + used_dominate = world.time + +/mob/living/simple_animal/borer/verb/bond_brain() + set category = "Abilities" + set name = "Assume Control" + set desc = "Fully connect to the brain of your host." + + if(!host) + to_chat(src, "You are not inside a host body.") + return + + if(src.stat) + to_chat(src, "You cannot do that in your current state.") + return + + if(docile) + to_chat(src, "You are feeling far too docile to do that.") + return + + to_chat(src, "You begin delicately adjusting your connection to the host brain...") + + spawn(100+(host.getBrainLoss()*5)) + + if(!host || !src || controlling) + return + else + + to_chat(src, "You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system.") + to_chat(host, "You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours.") + host.add_language("Cortical Link") + + // host -> brain + var/h2b_id = host.computer_id + var/h2b_ip= host.lastKnownIP + host.computer_id = null + host.lastKnownIP = null + + qdel(host_brain) + host_brain = new(src) + + host_brain.ckey = host.ckey + + host_brain.SetName(host.name) + + if(!host_brain.computer_id) + host_brain.computer_id = h2b_id + + if(!host_brain.lastKnownIP) + host_brain.lastKnownIP = h2b_ip + + // self -> host + var/s2h_id = src.computer_id + var/s2h_ip= src.lastKnownIP + src.computer_id = null + src.lastKnownIP = null + + host.ckey = src.ckey + + if(!host.computer_id) + host.computer_id = s2h_id + + if(!host.lastKnownIP) + host.lastKnownIP = s2h_ip + + controlling = 1 + + host.verbs += /mob/living/carbon/proc/release_control + host.verbs += /mob/living/carbon/proc/punish_host + host.verbs += /mob/living/carbon/proc/spawn_larvae + + return + +/mob/living/carbon/human/proc/jumpstart() + set category = "Abilities" + set name = "Revive Host" + set desc = "Send a jolt of electricity through your host, reviving them." + + if(stat != 2) + to_chat(usr, "Your host is already alive.") + return + + verbs -= /mob/living/carbon/human/proc/jumpstart + visible_message("With a hideous, rattling moan, [src] shudders back to life!") + + rejuvenate() + restore_blood() + fixblood() + update_canmove() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/borer/say.dm b/code/modules/mob/living/simple_animal/borer/say.dm new file mode 100644 index 00000000..69e91bf0 --- /dev/null +++ b/code/modules/mob/living/simple_animal/borer/say.dm @@ -0,0 +1,40 @@ +/mob/living/simple_animal/borer/say(var/message) + + message = sanitize(message) + message = capitalize(message) + + if(!message) + return + + if (stat == 2) + return say_dead(message) + + if (stat) + return + + if (src.client) + if(client.prefs.muted & MUTE_IC) + to_chat(src, "You cannot speak in IC (muted).") + return + + if (copytext(message, 1, 2) == "*") + return emote(copytext(message, 2)) + + var/datum/language/L = parse_language(message) + if(L && L.flags & HIVEMIND) + L.broadcast(src,trim(copytext(message,3)),src.truename) + return + + if(!host) + //TODO: have this pick a random mob within 3 tiles to speak for the borer. + to_chat(src, "You have no host to speak to.") + return //No host, no audible speech. + + to_chat(src, "You drop words into [host]'s mind: \"[message]\"") + to_chat(host, "Your own thoughts speak: \"[message]\"") + + for (var/mob/M in GLOB.player_list) + if (istype(M, /mob/new_player)) + continue + else if(M.stat == DEAD && M.get_preference_value(/datum/client_preference/ghost_ears) == GLOB.PREF_ALL_SPEECH) + to_chat(M, "[src.truename] whispers to [host], \"[message]\"") diff --git a/code/modules/mob/living/simple_animal/constructs/constructs.dm b/code/modules/mob/living/simple_animal/constructs/constructs.dm new file mode 100644 index 00000000..d77735a3 --- /dev/null +++ b/code/modules/mob/living/simple_animal/constructs/constructs.dm @@ -0,0 +1,341 @@ +/mob/living/simple_animal/construct + name = "Construct" + real_name = "Construct" + desc = "" + speak = list("Hsssssssszsht.", "Hsssssssss...", "Tcshsssssssszht!") + speak_emote = list("hisses") + emote_hear = list("wails","screeches") + response_help = "thinks better of touching" + response_disarm = "flailed at" + response_harm = "punched" + icon_dead = "shade_dead" + speed = -1 + a_intent = I_HURT + stop_automated_movement = 1 + status_flags = CANPUSH + universal_speak = 0 + universal_understand = 1 + attack_sound = 'sound/weapons/spiderlunge.ogg' + min_gas = null + max_gas = null + minbodytemp = 0 + show_stat_health = 1 + faction = "cult" + supernatural = 1 + see_in_dark = 8 + see_invisible = SEE_INVISIBLE_NOLIGHTING + var/nullblock = 0 + + mob_swap_flags = HUMAN|SIMPLE_ANIMAL|SLIME|MONKEY + mob_push_flags = ALLMOBS + + var/list/construct_spells = list() + +/mob/living/simple_animal/construct/cultify() + return + +/mob/living/simple_animal/construct/New() + ..() + name = text("[initial(name)] ([random_id(/mob/living/simple_animal/construct, 1000, 9999)])") + real_name = name + add_language("Cult") + add_language("Occult") + for(var/spell in construct_spells) + src.add_spell(new spell, "const_spell_ready") + update_icon() + +/mob/living/simple_animal/construct/death(gibbed, deathmessage, show_dead_message) + new /obj/item/weapon/ectoplasm (src.loc) + ..(null,"collapses in a shattered heap.","The bonds tying you to this mortal plane have been severed.") + ghostize() + qdel(src) + +/mob/living/simple_animal/construct/update_icon() + overlays.Cut() + ..() + add_glow() + +/mob/living/simple_animal/construct/attack_generic(var/mob/user) + if(istype(user, /mob/living/simple_animal/construct/builder)) + if(health < maxHealth) + adjustBruteLoss(-5) + user.visible_message("\The [user] mends some of \the [src]'s wounds.") + else + to_chat(user, "\The [src] is undamaged.") + return + return ..() + +/mob/living/simple_animal/construct/examine(mob/user) + . = ..(user) + var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" + if (src.health < src.maxHealth) + msg += "" + if (src.health >= src.maxHealth/2) + msg += "It looks slightly dented.\n" + else + msg += "It looks severely dented!\n" + msg += "" + msg += "*---------*" + + to_chat(user, msg) + +/obj/item/weapon/ectoplasm + name = "ectoplasm" + desc = "Spooky." + gender = PLURAL + icon = 'icons/obj/wizard.dmi' + icon_state = "ectoplasm" + +/////////////////Juggernaut/////////////// + + + +/mob/living/simple_animal/construct/armoured + name = "Juggernaut" + real_name = "Juggernaut" + desc = "A possessed suit of armour driven by the will of the restless dead" + icon = 'icons/mob/mob.dmi' + icon_state = "behemoth" + icon_living = "behemoth" + maxHealth = 250 + health = 250 + speak_emote = list("rumbles") + response_harm = "harmlessly punches" + harm_intent_damage = 0 + melee_damage_lower = 30 + melee_damage_upper = 30 + attacktext = "smashed their armoured gauntlet into" + mob_size = MOB_LARGE + speed = 3 + environment_smash = 2 + attack_sound = 'sound/weapons/heavysmash.ogg' + status_flags = 0 + resistance = 10 + construct_spells = list(/spell/aoe_turf/conjure/forcewall/lesser) + +/mob/living/simple_animal/construct/armoured/Life() + weakened = 0 + ..() + +/mob/living/simple_animal/construct/armoured/bullet_act(var/obj/item/projectile/P) + if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)) + var/reflectchance = 80 - round(P.damage/3) + if(prob(reflectchance)) + adjustBruteLoss(P.damage * 0.5) + visible_message("The [P.name] gets reflected by [src]'s shell!", \ + "The [P.name] gets reflected by [src]'s shell!") + + // Find a turf near or on the original location to bounce to + //if(P.starting) + //var/new_x = P.starting.x + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3) + //var/new_y = P.starting.y + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3) + //var/turf/curloc = get_turf(src) + + // redirect the projectile + //P.redirect(new_x, new_y, curloc, src) + + return -1 // complete projectile permutation + + return (..(P)) + + + +////////////////////////Wraith///////////////////////////////////////////// + + + +/mob/living/simple_animal/construct/wraith + name = "Wraith" + real_name = "Wraith" + desc = "A wicked bladed shell contraption piloted by a bound spirit" + icon = 'icons/mob/mob.dmi' + icon_state = "floating" + icon_living = "floating" + icon_dead = "floating_dead" + maxHealth = 75 + health = 75 + melee_damage_lower = 25 + melee_damage_upper = 25 + attacktext = "slashed" + speed = -1 + environment_smash = 1 + see_in_dark = 7 + attack_sound = 'sound/weapons/rapidslice.ogg' + construct_spells = list(/spell/targeted/ethereal_jaunt/shift) + + +/////////////////////////////Artificer///////////////////////// + + + +/mob/living/simple_animal/construct/builder + name = "Artificer" + real_name = "Artificer" + desc = "A bulbous construct dedicated to building and maintaining The Cult of Nar-Sie's armies" + icon = 'icons/mob/mob.dmi' + icon_state = "artificer" + icon_living = "artificer" + maxHealth = 50 + health = 50 + response_harm = "viciously beaten" + harm_intent_damage = 5 + melee_damage_lower = 5 + melee_damage_upper = 5 + attacktext = "rammed" + speed = 0 + environment_smash = 1 + attack_sound = 'sound/weapons/rapidslice.ogg' + construct_spells = list(/spell/aoe_turf/conjure/construct/lesser, + /spell/aoe_turf/conjure/wall, + /spell/aoe_turf/conjure/floor, + /spell/aoe_turf/conjure/soulstone, + /spell/aoe_turf/conjure/pylon + ) + + +/////////////////////////////Behemoth///////////////////////// + + +/mob/living/simple_animal/construct/behemoth + name = "Behemoth" + real_name = "Behemoth" + desc = "The pinnacle of occult technology, Behemoths are the ultimate weapon in the Cult of Nar-Sie's arsenal." + icon = 'icons/mob/mob.dmi' + icon_state = "behemoth" + icon_living = "behemoth" + maxHealth = 750 + health = 750 + speak_emote = list("rumbles") + response_harm = "harmlessly punched" + harm_intent_damage = 0 + melee_damage_lower = 50 + melee_damage_upper = 50 + attacktext = "brutally crushed" + speed = 5 + environment_smash = 2 + attack_sound = 'sound/weapons/heavysmash.ogg' + resistance = 10 + var/energy = 0 + var/max_energy = 1000 + construct_spells = list(/spell/aoe_turf/conjure/forcewall/lesser) + +////////////////////////Harvester//////////////////////////////// + + + +/mob/living/simple_animal/construct/harvester + name = "Harvester" + real_name = "Harvester" + desc = "The promised reward of the livings who follow Nar-Sie. Obtained by offering their bodies to the geometer of blood" + icon = 'icons/mob/mob.dmi' + icon_state = "harvester" + icon_living = "harvester" + icon_dead = "harvester_dead" + maxHealth = 150 + health = 150 + melee_damage_lower = 25 + melee_damage_upper = 25 + attacktext = "violently stabbed" + speed = -1 + environment_smash = 1 + see_in_dark = 7 + attack_sound = 'sound/weapons/pierce.ogg' + + construct_spells = list( + /spell/targeted/harvest + ) + +////////////////Glow////////////////// +/mob/living/simple_animal/construct/proc/add_glow() + var/image/eye_glow = image(icon,"glow-[icon_state]") + eye_glow.plane = EFFECTS_ABOVE_LIGHTING_PLANE + eye_glow.layer = EYE_GLOW_LAYER + overlays += eye_glow + set_light(3, -10, l_color = "#ffffff") + +////////////////HUD////////////////////// + +/mob/living/simple_animal/construct/Life() + . = ..() + if(.) + if(fire) + if(fire_alert) fire.icon_state = "fire1" + else fire.icon_state = "fire0" + if(pullin) + if(pulling) pullin.icon_state = "pull1" + else pullin.icon_state = "pull0" + + if(purged) + if(purge > 0) purged.icon_state = "purge1" + else purged.icon_state = "purge0" + + silence_spells(purge) + +/mob/living/simple_animal/construct/armoured/Life() + ..() + if(healths) + switch(health) + if(250 to INFINITY) healths.icon_state = "juggernaut_health0" + if(208 to 249) healths.icon_state = "juggernaut_health1" + if(167 to 207) healths.icon_state = "juggernaut_health2" + if(125 to 166) healths.icon_state = "juggernaut_health3" + if(84 to 124) healths.icon_state = "juggernaut_health4" + if(42 to 83) healths.icon_state = "juggernaut_health5" + if(1 to 41) healths.icon_state = "juggernaut_health6" + else healths.icon_state = "juggernaut_health7" + + +/mob/living/simple_animal/construct/behemoth/Life() + ..() + if(healths) + switch(health) + if(750 to INFINITY) healths.icon_state = "juggernaut_health0" + if(625 to 749) healths.icon_state = "juggernaut_health1" + if(500 to 624) healths.icon_state = "juggernaut_health2" + if(375 to 499) healths.icon_state = "juggernaut_health3" + if(250 to 374) healths.icon_state = "juggernaut_health4" + if(125 to 249) healths.icon_state = "juggernaut_health5" + if(1 to 124) healths.icon_state = "juggernaut_health6" + else healths.icon_state = "juggernaut_health7" + +/mob/living/simple_animal/construct/builder/Life() + ..() + if(healths) + switch(health) + if(50 to INFINITY) healths.icon_state = "artificer_health0" + if(42 to 49) healths.icon_state = "artificer_health1" + if(34 to 41) healths.icon_state = "artificer_health2" + if(26 to 33) healths.icon_state = "artificer_health3" + if(18 to 25) healths.icon_state = "artificer_health4" + if(10 to 17) healths.icon_state = "artificer_health5" + if(1 to 9) healths.icon_state = "artificer_health6" + else healths.icon_state = "artificer_health7" + + + +/mob/living/simple_animal/construct/wraith/Life() + ..() + if(healths) + switch(health) + if(75 to INFINITY) healths.icon_state = "wraith_health0" + if(62 to 74) healths.icon_state = "wraith_health1" + if(50 to 61) healths.icon_state = "wraith_health2" + if(37 to 49) healths.icon_state = "wraith_health3" + if(25 to 36) healths.icon_state = "wraith_health4" + if(12 to 24) healths.icon_state = "wraith_health5" + if(1 to 11) healths.icon_state = "wraith_health6" + else healths.icon_state = "wraith_health7" + + +/mob/living/simple_animal/construct/harvester/Life() + ..() + if(healths) + switch(health) + if(150 to INFINITY) healths.icon_state = "harvester_health0" + if(125 to 149) healths.icon_state = "harvester_health1" + if(100 to 124) healths.icon_state = "harvester_health2" + if(75 to 99) healths.icon_state = "harvester_health3" + if(50 to 74) healths.icon_state = "harvester_health4" + if(25 to 49) healths.icon_state = "harvester_health5" + if(1 to 24) healths.icon_state = "harvester_health6" + else healths.icon_state = "harvester_health7" diff --git a/code/modules/mob/living/simple_animal/constructs/soulstone.dm b/code/modules/mob/living/simple_animal/constructs/soulstone.dm new file mode 100644 index 00000000..7548fb8b --- /dev/null +++ b/code/modules/mob/living/simple_animal/constructs/soulstone.dm @@ -0,0 +1,146 @@ +#define SOULSTONE_CRACKED -1 +#define SOULSTONE_EMPTY 0 +#define SOULSTONE_ESSENCE 1 + +/obj/item/device/soulstone + name = "soul stone shard" + icon = 'icons/obj/wizard.dmi' + icon_state = "soulstone" + item_state = "electronic" + desc = "A fragment of the legendary treasure known simply as the 'Soul Stone'." + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_BELT + origin_tech = list(TECH_BLUESPACE = 4, TECH_MATERIAL = 4) + + var/full = SOULSTONE_EMPTY + var/is_evil = 1 + var/mob/living/simple_animal/shade = null + var/smashing = 0 + var/soulstatus = null + +/obj/item/device/soulstone/full + full = SOULSTONE_ESSENCE + icon_state = "soulstone2" + +/obj/item/device/soulstone/New() + ..() + shade = new /mob/living/simple_animal/shade(src) + +/obj/item/device/soulstone/Destroy() + QDEL_NULL(shade) + return ..() + +/obj/item/device/soulstone/examine(mob/user) + . = ..() + if(full == SOULSTONE_EMPTY) + to_chat(user, "The shard still flickers with a fraction of the full artifact's power, but it needs to be filled with the essence of someone's life before it can be used.") + if(full == SOULSTONE_ESSENCE) + to_chat(user,"The shard has gone transparent, a seeming window into a dimension of unspeakable horror.") + if(full == SOULSTONE_CRACKED) + to_chat(user, "This one is cracked and useless.") + +/obj/item/device/soulstone/update_icon() + if(full == SOULSTONE_EMPTY) + icon_state = "soulstone" + if(full == SOULSTONE_ESSENCE) + icon_state = "soulstone2" //TODO: A spookier sprite. Also unique sprites. + if(full == SOULSTONE_CRACKED) + icon_state = "soulstone"//TODO: cracked sprite + SetName("cracked soulstone") + +/obj/item/device/soulstone/attackby(var/obj/item/I, var/mob/user) + ..() + if(is_evil && istype(I, /obj/item/weapon/nullrod)) + to_chat(user, "You cleanse \the [src] of taint, purging its shackles to its creator..") + is_evil = 0 + return + if(I.force > 10) + if(!smashing) + to_chat(user, "\The [src] looks fragile. Are you sure you want to smash it? If so, hit it again.") + smashing = 1 + spawn(20) + smashing = 0 + return + user.visible_message("\The [user] hits \the [src] with \the [I], and it breaks.[shade.client ? " You hear a terrible scream!" : ""]", "You hit \the [src] with \the [I], and it breaks.[shade.client ? " You hear a terrible scream!" : ""]", shade.client ? "You hear a scream." : null) + set_full(SOULSTONE_CRACKED) + +/obj/item/device/soulstone/attack(var/mob/living/simple_animal/M, var/mob/user) + if(M == shade) + to_chat(user, "You recapture \the [M].") + M.forceMove(src) + return + if(full == SOULSTONE_ESSENCE) + to_chat(user, "\The [src] is already full.") + return + if(M.stat != DEAD && !M.is_asystole()) + to_chat(user, "Kill or maim the victim first.") + return + for(var/obj/item/W in M) + M.drop_from_inventory(W) + M.dust() + set_full(SOULSTONE_ESSENCE) + +/obj/item/device/soulstone/attack_self(var/mob/user) + if(full != SOULSTONE_ESSENCE) // No essence - no shade + to_chat(user, "This [src] has no life essence.") + return + + if(!shade.key) // No key = hasn't been used + to_chat(user, "You cut your finger and let the blood drip on \the [src].") + user.pay_for_rune(1) + var/datum/ghosttrap/cult/shade/S = get_ghost_trap("soul stone") + S.request_player(shade, "The soul stone shade summon ritual has been performed. ") + else if(!shade.client) // Has a key but no client - shade logged out + to_chat(user, "\The [shade] in \the [src] is dormant.") + return + else if(shade.loc == src) + var/choice = alert("Would you like to invoke the spirit within?",,"Yes","No") + if(choice == "Yes") + shade.forceMove(get_turf(src)) + to_chat(user, "You summon \the [shade].") + if(choice == "No") + return + +/obj/item/device/soulstone/proc/set_full(var/f) + full = f + update_icon() + +/obj/structure/constructshell + name = "empty shell" + icon = 'icons/obj/wizard.dmi' + icon_state = "construct" + desc = "A wicked machine used by those skilled in magical arts. It is inactive." + +/obj/structure/constructshell/cult + icon_state = "construct-cult" + desc = "This eerie contraption looks like it would come alive if supplied with a missing ingredient." + +/obj/structure/constructshell/attackby(var/obj/item/I, var/mob/user) + if(istype(I, /obj/item/device/soulstone)) + var/obj/item/device/soulstone/S = I + if(!S.shade.client) + to_chat(user, "\The [I] has essence, but no soul. Activate it in your hand to find a soul for it first.") + return + if(S.shade.loc != S) + to_chat(user, "Recapture the shade back into \the [I] first.") + return + var/construct = alert(user, "Please choose which type of construct you wish to create.",,"Artificer", "Wraith", "Juggernaut") + var/ctype + switch(construct) + if("Artificer") + ctype = /mob/living/simple_animal/construct/builder + if("Wraith") + ctype = /mob/living/simple_animal/construct/wraith + if("Juggernaut") + ctype = /mob/living/simple_animal/construct/armoured + var/mob/living/simple_animal/construct/C = new ctype(get_turf(src)) + C.key = S.shade.key + //C.cancel_camera() + if(S.is_evil) + cult.add_antagonist(C.mind) + qdel(S) + qdel(src) + +#undef SOULSTONE_CRACKED +#undef SOULSTONE_EMPTY +#undef SOULSTONE_ESSENCE diff --git a/code/modules/mob/living/simple_animal/familiars/familiars.dm b/code/modules/mob/living/simple_animal/familiars/familiars.dm new file mode 100644 index 00000000..a994f923 --- /dev/null +++ b/code/modules/mob/living/simple_animal/familiars/familiars.dm @@ -0,0 +1,175 @@ +/mob/living/simple_animal/familiar + name = "familiar" + desc = "No wizard is complete without a mystical sidekick." + supernatural = 1 + + response_help = "pets" + response_disarm = "pushes" + response_harm = "hits" + + universal_speak = 0 + universal_understand = 1 + + min_gas = list("oxygen" = 1) + max_gas = null + unsuitable_atoms_damage = 1 + + var/list/wizardy_spells = list() + +/mob/living/simple_animal/familiar/New() + ..() + add_language(LANGUAGE_GALCOM) + for(var/spell in wizardy_spells) + src.add_spell(new spell, "const_spell_ready") + +/mob/living/simple_animal/familiar/carcinus + name = "carcinus" + desc = "A small crab said to be made of stone and starlight." + icon = 'icons/mob/animal.dmi' + icon_state = "evilcrab" + icon_living = "evilcrab" + icon_dead = "evilcrab_dead" + + speak_emote = list("chitters","clicks") + + + health = 200 + maxHealth = 200 + melee_damage_lower = 10 + melee_damage_upper = 15 + attacktext = "pinches" + resistance = 9 + +/*familiar version of the Pike w/o all the other hostile/carp stuff getting in the way (namely life) +*/ + +/mob/living/simple_animal/familiar/pike + name = "space pike" + desc = "A bigger, more magical cousin of the space carp." + + icon = 'icons/mob/spaceshark.dmi' + icon_state = "shark" + icon_living = "shark" + icon_dead = "shark_dead" + pixel_x = -16 + + speak_emote = list("gnashes") + + health = 100 + maxHealth = 100 + melee_damage_lower = 10 + melee_damage_upper = 10 + + min_gas = null + + wizardy_spells = list(/spell/aoe_turf/conjure/forcewall) + +/mob/living/simple_animal/familiar/pike/Allow_Spacemove(var/check_drift = 0) + return 1 //No drifting in space for space carp! //original comments do not steal + +/mob/living/simple_animal/familiar/horror + name = "horror" + desc = "Looking at it fills you with dread." + icon = 'icons/mob/mob.dmi' + icon_state = "horror" + icon_living = "horror" + + speak_emote = list("moans", "groans") + + response_help = "thinks better of touching" + + health = 150 + maxHealth = 150 + melee_damage_lower = 5 + melee_damage_upper = 8 + attacktext = "touches" + + wizardy_spells = list(/spell/targeted/torment) + +/mob/living/simple_animal/familiar/horror/death(gibbed, deathmessage, show_dead_message) + ..(null,"rapidly deteriorates","The bonds tying you to this mortal plane have been severed.") + + ghostize() + gibs(src.loc) + qdel(src) + + +/mob/living/simple_animal/familiar/minor_amaros + name = "minor amaros" + desc = "A small fluffy alien creature." + icon = 'icons/mob/mob.dmi' + icon_state = "baby roro" + icon_living = "baby roro" + icon_dead = "baby roro dead" + + speak_emote = list("entones") + mob_size = MOB_SMALL + + health = 25 + maxHealth = 25 + + wizardy_spells = list(/spell/targeted/heal_target, + /spell/targeted/heal_target/area) + + + +/mob/living/simple_animal/familiar/pet //basically variants of normal animals with spells. + icon = 'icons/mob/animal.dmi' + var/icon_rest //so that we can have resting little guys. + +/mob/living/simple_animal/familiar/pet/Life() + ..() + if(!icon_rest) + return + if(stat == UNCONSCIOUS || resting) + icon_state = icon_rest + +/mob/living/simple_animal/familiar/pet/mouse + name = "mouse" + desc = "A small rodent. It looks very old." + icon_state = "mouse_gray" + icon_living = "mouse_gray" + icon_dead = "mouse_gray_dead" + icon_rest = "mouse_gray_sleep" + + speak_emote = list("squeeks") + holder_type = /obj/item/weapon/holder/mouse + pass_flags = PASS_FLAG_TABLE + mob_size = MOB_MINISCULE + + response_harm = "stamps on" + + health = 15 + maxHealth = 15 + melee_damage_lower = 1 + melee_damage_upper = 1 + attacktext = "nibbles" + + wizardy_spells = list(/spell/aoe_turf/smoke) + +/mob/living/simple_animal/familiar/pet/mouse/New() + ..() + + verbs += /mob/living/proc/ventcrawl + verbs += /mob/living/proc/hide + +/mob/living/simple_animal/familiar/pet/cat + name = "black cat" + desc = "A pitch black cat. Said to be especially unlucky." + icon_state = "cat3" + icon_living = "cat3" + icon_dead = "cat3_dead" + icon_rest = "cat3_rest" + + + speak_emote = list("meows", "purrs") + holder_type = /obj/item/weapon/holder/cat + mob_size = MOB_SMALL + + health = 25 + maxHealth = 25 + melee_damage_lower = 3 + melee_damage_upper = 4 + attacktext = "claws" + + wizardy_spells = list(/spell/targeted/subjugation) diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm new file mode 100644 index 00000000..83a828e9 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -0,0 +1,249 @@ +//Cat +/mob/living/simple_animal/cat + name = "cat" + desc = "A domesticated, feline pet. Has a tendency to adopt crewmembers." + icon_state = "cat2" + item_state = "cat2" + icon_living = "cat2" + icon_dead = "cat2_dead" + speak = list("Meow!","Esp!","Purr!","HSSSSS") + speak_emote = list("purrs", "meows") + emote_hear = list("meows","mews") + emote_see = list("shakes their head", "shivers") + speak_chance = 1 + turns_per_move = 5 + see_in_dark = 6 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "kicks" + var/turns_since_scan = 0 + var/mob/living/simple_animal/mouse/movement_target + var/mob/flee_target + minbodytemp = 223 //Below -50 Degrees Celcius + maxbodytemp = 323 //Above 50 Degrees Celcius + holder_type = /obj/item/weapon/holder/cat + mob_size = MOB_SMALL + possession_candidate = 1 + +/mob/living/simple_animal/cat/Life() + if(!..() || incapacitated() || client) + return + //MICE! + if((src.loc) && isturf(src.loc)) + if(!resting && !buckled) + for(var/mob/living/simple_animal/mouse/M in loc) + if(!M.stat) + M.splat() + visible_emote(pick("bites \the [M]!","toys with \the [M].","chomps on \the [M]!")) + movement_target = null + stop_automated_movement = 0 + break + + + + for(var/mob/living/simple_animal/mouse/snack in oview(src,5)) + if(snack.stat < DEAD && prob(15)) + audible_emote(pick("hisses and spits!","mrowls fiercely!","eyes [snack] hungrily.")) + break + + + + turns_since_scan++ + if (turns_since_scan > 5) + walk_to(src,0) + turns_since_scan = 0 + + if (flee_target) //fleeing takes precendence + handle_flee_target() + else + handle_movement_target() + + if(prob(2)) //spooky + var/mob/observer/ghost/spook = locate() in range(src,5) + if(spook) + var/turf/T = spook.loc + var/list/visible = list() + for(var/obj/O in T.contents) + if(!O.invisibility && O.name) + visible += O + if(visible.len) + var/atom/A = pick(visible) + visible_emote("suddenly stops and stares at something unseen[istype(A) ? " near [A]":""].") + +/mob/living/simple_animal/cat/proc/handle_movement_target() + //if our target is neither inside a turf or inside a human(???), stop + if((movement_target) && !(isturf(movement_target.loc) || ishuman(movement_target.loc) )) + movement_target = null + stop_automated_movement = 0 + //if we have no target or our current one is out of sight/too far away + if( !movement_target || !(movement_target.loc in oview(src, 4)) ) + movement_target = null + stop_automated_movement = 0 + for(var/mob/living/simple_animal/mouse/snack in oview(src)) //search for a new target + if(isturf(snack.loc) && !snack.stat) + movement_target = snack + break + + if(movement_target) + stop_automated_movement = 1 + walk_to(src,movement_target,0,3) + +/mob/living/simple_animal/cat/proc/handle_flee_target() + //see if we should stop fleeing + if (flee_target && !(flee_target.loc in view(src))) + flee_target = null + stop_automated_movement = 0 + + if (flee_target) + if(prob(25)) say("HSSSSS") + stop_automated_movement = 1 + walk_away(src, flee_target, 7, 2) + +/mob/living/simple_animal/cat/proc/set_flee_target(atom/A) + if(A) + flee_target = A + turns_since_scan = 5 + +/mob/living/simple_animal/cat/attackby(var/obj/item/O, var/mob/user) + . = ..() + if(O.force) + set_flee_target(user? user : src.loc) + +/mob/living/simple_animal/cat/attack_hand(mob/living/carbon/human/M as mob) + . = ..() + if(M.a_intent == I_HURT) + set_flee_target(M) + +/mob/living/simple_animal/cat/ex_act() + . = ..() + set_flee_target(src.loc) + +/mob/living/simple_animal/cat/bullet_act(var/obj/item/projectile/proj) + . = ..() + set_flee_target(proj.firer? proj.firer : src.loc) + +/mob/living/simple_animal/cat/hitby(atom/movable/AM) + . = ..() + set_flee_target(AM.thrower? AM.thrower : src.loc) + +//Basic friend AI +/mob/living/simple_animal/cat/fluff + var/mob/living/carbon/human/friend + var/befriend_job = null + +/mob/living/simple_animal/cat/fluff/handle_movement_target() + if (friend) + var/follow_dist = 4 + if (friend.stat >= DEAD || friend.is_asystole()) //danger + follow_dist = 1 + else if (friend.stat || friend.health <= 50) //danger or just sleeping + follow_dist = 2 + var/near_dist = max(follow_dist - 2, 1) + var/current_dist = get_dist(src, friend) + + if (movement_target != friend) + if (current_dist > follow_dist && !istype(movement_target, /mob/living/simple_animal/mouse) && (friend in oview(src))) + //stop existing movement + walk_to(src,0) + turns_since_scan = 0 + + //walk to friend + stop_automated_movement = 1 + movement_target = friend + walk_to(src, movement_target, near_dist, 4) + + //already following and close enough, stop + else if (current_dist <= near_dist) + walk_to(src,0) + movement_target = null + stop_automated_movement = 0 + if (prob(10)) + say("Meow!") + + if (!friend || movement_target != friend) + ..() + +/mob/living/simple_animal/cat/fluff/Life() + ..() + if (stat || !friend) + return + if (get_dist(src, friend) <= 1) + if (friend.stat >= DEAD || friend.is_asystole()) + if (prob((friend.stat < DEAD)? 50 : 15)) + var/verb = pick("meows", "mews", "mrowls") + audible_emote(pick("[verb] in distress.", "[verb] anxiously.")) + else + if (prob(5)) + visible_emote(pick("nuzzles [friend].", + "brushes against [friend].", + "rubs against [friend].", + "purrs.")) + else if (friend.health <= 50) + if (prob(10)) + var/verb = pick("meows", "mews", "mrowls") + audible_emote("[verb] anxiously.") + +/mob/living/simple_animal/cat/fluff/verb/become_friends() + set name = "Become Friends" + set category = "IC" + set src in view(1) + + if(!friend) + var/mob/living/carbon/human/H = usr + if(istype(H) && (!befriend_job || H.job == befriend_job)) + friend = usr + . = 1 + else if(usr == friend) + . = 1 //already friends, but show success anyways + + if(.) + set_dir(get_dir(src, friend)) + visible_emote(pick("nuzzles [friend].", + "brushes against [friend].", + "rubs against [friend].", + "purrs.")) + else + to_chat(usr, "[src] ignores you.") + return + +//RUNTIME IS ALIVE! SQUEEEEEEEE~ +/mob/living/simple_animal/cat/fluff/Runtime + name = "Runtime" + desc = "Her fur has the look and feel of velvet, and her tail quivers occasionally." + gender = FEMALE + icon_state = "cat" + item_state = "cat" + icon_living = "cat" + icon_dead = "cat_dead" + +/mob/living/simple_animal/cat/kitten + name = "kitten" + desc = "D'aaawwww" + icon_state = "kitten" + item_state = "kitten" + icon_living = "kitten" + icon_dead = "kitten_dead" + gender = NEUTER + +// Leaving this here for now. +/obj/item/weapon/holder/cat/fluff/bones + name = "Bones" + desc = "It's Bones! Meow." + gender = MALE + icon_state = "cat3" + +/mob/living/simple_animal/cat/fluff/bones + name = "Bones" + desc = "That's Bones the cat. He's a laid back, black cat. Meow." + gender = MALE + icon_state = "cat3" + item_state = "cat3" + icon_living = "cat3" + icon_dead = "cat3_dead" + holder_type = /obj/item/weapon/holder/cat/fluff/bones + var/friend_name = "Erstatz Vryroxes" + +/mob/living/simple_animal/cat/kitten/New() + gender = pick(MALE, FEMALE) + ..() diff --git a/code/modules/mob/living/simple_animal/friendly/corgi.dm b/code/modules/mob/living/simple_animal/friendly/corgi.dm new file mode 100644 index 00000000..41fa7361 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/corgi.dm @@ -0,0 +1,196 @@ +//Corgi +/mob/living/simple_animal/corgi + name = "\improper corgi" + real_name = "corgi" + desc = "It's a corgi." + icon_state = "corgi" + icon_living = "corgi" + icon_dead = "corgi_dead" + speak = list("YAP", "Woof!", "Bark!", "AUUUUUU") + speak_emote = list("barks", "woofs") + emote_hear = list("barks", "woofs", "yaps","pants") + emote_see = list("shakes its head", "shivers") + speak_chance = 1 + turns_per_move = 10 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/corgi + meat_amount = 3 + response_help = "pets" + response_disarm = "bops" + response_harm = "kicks" + see_in_dark = 5 + mob_size = 8 + possession_candidate = 1 + holder_type = /obj/item/weapon/holder/corgi + var/obj/item/inventory_head + var/obj/item/inventory_back + +//IAN! SQUEEEEEEEEE~ +/mob/living/simple_animal/corgi/Ian + name = "Ian" + real_name = "Ian" //Intended to hold the name without altering it. + gender = MALE + desc = "It's a corgi." + var/turns_since_scan = 0 + var/obj/movement_target + response_help = "pets" + response_disarm = "bops" + response_harm = "kicks" + +/mob/living/simple_animal/corgi/Ian/Life() + ..() + + //Feeding, chasing food, FOOOOODDDD + if(!stat && !resting && !buckled) + turns_since_scan++ + if(turns_since_scan > 5) + turns_since_scan = 0 + if((movement_target) && !(isturf(movement_target.loc) || ishuman(movement_target.loc) )) + movement_target = null + stop_automated_movement = 0 + if( !movement_target || !(movement_target.loc in oview(src, 3)) ) + movement_target = null + stop_automated_movement = 0 + for(var/obj/item/weapon/reagent_containers/food/snacks/S in oview(src,3)) + if(isturf(S.loc) || ishuman(S.loc)) + movement_target = S + break + if(movement_target) + stop_automated_movement = 1 + step_to(src,movement_target,1) + sleep(3) + step_to(src,movement_target,1) + sleep(3) + step_to(src,movement_target,1) + + if(movement_target) //Not redundant due to sleeps, Item can be gone in 6 decisecomds + if (movement_target.loc.x < src.x) + set_dir(WEST) + else if (movement_target.loc.x > src.x) + set_dir(EAST) + else if (movement_target.loc.y < src.y) + set_dir(SOUTH) + else if (movement_target.loc.y > src.y) + set_dir(NORTH) + else + set_dir(SOUTH) + + if(isturf(movement_target.loc) ) + UnarmedAttack(movement_target) + else if(ishuman(movement_target.loc) && prob(20)) + visible_emote("stares at the [movement_target] that [movement_target.loc] has with sad puppy eyes.") + + if(prob(1)) + visible_emote(pick("dances around.","chases their tail.")) + spawn(0) + for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2)) + set_dir(i) + sleep(1) + +/obj/item/weapon/reagent_containers/food/snacks/meat/corgi + name = "Corgi meat" + desc = "Tastes like... well you know..." + +/mob/living/simple_animal/corgi/attackby(var/obj/item/O as obj, var/mob/user as mob) //Marker -Agouri + if(istype(O, /obj/item/weapon/newspaper)) + if(!stat) + for(var/mob/M in viewers(user, null)) + if ((M.client && !( M.blinded ))) + M.show_message("[user] baps [name] on the nose with the rolled up [O]") + spawn(0) + for(var/i in list(1,2,4,8,4,2,1,2)) + set_dir(i) + sleep(1) + else + ..() + +/mob/living/simple_animal/corgi/regenerate_icons() + overlays = list() + + if(inventory_head) + var/head_icon_state = inventory_head.icon_state + if(health <= 0) + head_icon_state += "2" + + var/icon/head_icon = image('icons/mob/corgi_head.dmi',head_icon_state) + if(head_icon) + overlays += head_icon + + if(inventory_back) + var/back_icon_state = inventory_back.icon_state + if(health <= 0) + back_icon_state += "2" + + var/icon/back_icon = image('icons/mob/corgi_back.dmi',back_icon_state) + if(back_icon) + overlays += back_icon + return + + +/mob/living/simple_animal/corgi/puppy + name = "\improper corgi puppy" + real_name = "corgi" + desc = "It's a corgi puppy." + icon_state = "puppy" + icon_living = "puppy" + icon_dead = "puppy_dead" + +//pupplies cannot wear anything. +/mob/living/simple_animal/corgi/puppy/Topic(href, href_list) + if(href_list["remove_inv"] || href_list["add_inv"]) + to_chat(usr, "You can't fit this on [src]") + return + ..() + +//LISA! SQUEEEEEEEEE~ +/mob/living/simple_animal/corgi/Lisa + name = "Lisa" + real_name = "Lisa" + gender = FEMALE + desc = "It's a corgi with a cute pink bow." + icon_state = "lisa" + icon_living = "lisa" + icon_dead = "lisa_dead" + response_help = "pets" + response_disarm = "bops" + response_harm = "kicks" + var/turns_since_scan = 0 + var/puppies = 0 + +//Lisa already has a cute bow! +/mob/living/simple_animal/corgi/Lisa/Topic(href, href_list) + if(href_list["remove_inv"] || href_list["add_inv"]) + to_chat(usr, "[src] already has a cute bow!") + return + ..() + +/mob/living/simple_animal/corgi/Lisa/Life() + ..() + + if(!stat && !resting && !buckled) + turns_since_scan++ + if(turns_since_scan > 15) + turns_since_scan = 0 + var/alone = 1 + var/ian = 0 + for(var/mob/M in oviewers(7, src)) + if(istype(M, /mob/living/simple_animal/corgi/Ian)) + if(M.client) + alone = 0 + break + else + ian = M + else + alone = 0 + break + if(alone && ian && puppies < 4) + if(near_camera(src) || near_camera(ian)) + return + new /mob/living/simple_animal/corgi/puppy(loc) + + + if(prob(1)) + visible_emote(pick("dances around","chases her tail")) + spawn(0) + for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2)) + set_dir(i) + sleep(1) diff --git a/code/modules/mob/living/simple_animal/friendly/crab.dm b/code/modules/mob/living/simple_animal/friendly/crab.dm new file mode 100644 index 00000000..c030ba70 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/crab.dm @@ -0,0 +1,43 @@ +//Look Sir, free crabs! +/mob/living/simple_animal/crab + name = "crab" + desc = "A hard-shelled crustacean. Seems quite content to lounge around all the time." + icon_state = "crab" + icon_living = "crab" + icon_dead = "crab_dead" + mob_size = MOB_SMALL + speak_emote = list("clicks") + emote_hear = list("clicks") + emote_see = list("clacks") + speak_chance = 1 + turns_per_move = 5 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "stomps" + stop_automated_movement = 1 + friendly = "pinches" + mob_size = 5 + var/obj/item/inventory_head + var/obj/item/inventory_mask + possession_candidate = 1 + +/mob/living/simple_animal/crab/Life() + ..() + //CRAB movement + if(!ckey && !stat) + if(isturf(src.loc) && !resting && !buckled) //This is so it only moves if it's not inside a closet, gentics machine, etc. + turns_since_move++ + if(turns_since_move >= turns_per_move) + Move(get_step(src,pick(4,8))) + turns_since_move = 0 + regenerate_icons() + +//COFFEE! SQUEEEEEEEEE! +/mob/living/simple_animal/crab/Coffee + name = "Coffee" + real_name = "Coffee" + desc = "It's Coffee, the other pet!" + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "stomps" diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm new file mode 100644 index 00000000..a956d4a4 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm @@ -0,0 +1,310 @@ +//goat +/mob/living/simple_animal/hostile/retaliate/goat + name = "goat" + desc = "Not known for their pleasant disposition." + icon_state = "goat" + icon_living = "goat" + icon_dead = "goat_dead" + speak = list("EHEHEHEHEH","eh?") + speak_emote = list("brays") + emote_hear = list("brays") + emote_see = list("shakes its head", "stamps a foot", "glares around") + speak_chance = 1 + turns_per_move = 5 + see_in_dark = 6 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/goat + meat_amount = 4 + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "kicks" + faction = "goat" + attacktext = "kicked" + health = 40 + melee_damage_lower = 1 + melee_damage_upper = 5 + var/datum/reagents/udder = null + +/mob/living/simple_animal/hostile/retaliate/goat/New() + udder = new(50, src) + ..() + +/mob/living/simple_animal/hostile/retaliate/goat/Destroy() + QDEL_NULL(udder) + . = ..() + +/mob/living/simple_animal/hostile/retaliate/goat/Life() + . = ..() + if(.) + //chance to go crazy and start wacking stuff + if(!enemies.len && prob(1)) + Retaliate() + + if(enemies.len && prob(10)) + enemies = list() + LoseTarget() + src.visible_message("[src] calms down.") + + if(stat == CONSCIOUS) + if(udder && prob(5)) + udder.add_reagent(/datum/reagent/drink/milk, rand(5, 10)) + + if(locate(/obj/effect/vine) in loc) + var/obj/effect/vine/SV = locate() in loc + if(prob(60)) + src.visible_message("\The [src] eats the plants.") + SV.die_off(1) + if(locate(/obj/machinery/portable_atmospherics/hydroponics/soil/invisible) in loc) + var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/SP = locate() in loc + qdel(SP) + else if(prob(20)) + src.visible_message("\The [src] chews on the plants.") + return + + if(!pulledby) + var/obj/effect/vine/food + food = locate(/obj/effect/vine) in oview(5,loc) + if(food) + var/step = get_step_to(src, food, 0) + Move(step) + +/mob/living/simple_animal/hostile/retaliate/goat/Retaliate() + ..() + if(stat == CONSCIOUS) + visible_message("[src] gets an evil-looking gleam in their eye.") + +/mob/living/simple_animal/hostile/retaliate/goat/attackby(var/obj/item/O as obj, var/mob/user as mob) + var/obj/item/weapon/reagent_containers/glass/G = O + if(stat == CONSCIOUS && istype(G) && G.is_open_container()) + user.visible_message("[user] milks [src] using \the [O].") + var/transfered = udder.trans_type_to(G, /datum/reagent/drink/milk, rand(5,10)) + if(G.reagents.total_volume >= G.volume) + to_chat(user, "\The [O] is full.") + if(!transfered) + to_chat(user, "The udder is dry. Wait a bit longer...") + else + ..() + +//this is the king of goats. he is very powerful, which is why he is the king +/mob/living/simple_animal/hostile/retaliate/goat/king + name = "king of goats" + desc = "The oldest and wisest of goats; king of his race, peerless in dignity and power. His golden fleece radiates nobility." + icon_state = "king_goat" + icon_living = "king_goat" + icon_dead = "goat_dead" + speak_emote = list("brays in a booming voice") + emote_hear = list("brays in a booming voice") + emote_see = list("stamps a mighty foot, shaking the surroundings") + meat_amount = 12 + response_help = "placates" + response_harm = "assaults" + faction = "goat" + attacktext = "brutalized" + turns_per_move = 10 + health = 500 + maxHealth = 500 + melee_damage_lower = 35 + melee_damage_upper = 55 + mob_size = MOB_LARGE + +/mob/living/simple_animal/hostile/retaliate/goat/king/Retaliate() + ..() + if(stat == CONSCIOUS) + visible_message("[src] bellows indignantly, with a judgemental gleam in their eye.") + +/mob/living/simple_animal/hostile/retaliate/goat/king/death() + ..() + visible_message("\The [src] shrieks as the seal on their power breaks and his wool peels off!") + new /obj/item/weapon/towel/fleece(src.loc) + +//cow +/mob/living/simple_animal/cow + name = "cow" + desc = "Known for their milk, just don't tip them over." + icon_state = "cow" + icon_living = "cow" + icon_dead = "cow_dead" + icon_gib = "cow_gib" + speak = list("moo?","moo","MOOOOOO") + speak_emote = list("moos","moos hauntingly") + emote_hear = list("brays") + emote_see = list("shakes its head") + speak_chance = 1 + turns_per_move = 5 + see_in_dark = 6 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/beef + meat_amount = 6 + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "kicks" + attacktext = "kicked" + health = 50 + var/datum/reagents/udder = null + +/mob/living/simple_animal/cow/New() + udder = new(50) + udder.my_atom = src + ..() + +/mob/living/simple_animal/cow/attackby(var/obj/item/O as obj, var/mob/user as mob) + var/obj/item/weapon/reagent_containers/glass/G = O + if(stat == CONSCIOUS && istype(G) && G.is_open_container()) + user.visible_message("[user] milks [src] using \the [O].") + var/transfered = udder.trans_type_to(G, /datum/reagent/drink/milk, rand(5,10)) + if(G.reagents.total_volume >= G.volume) + to_chat(user, "\The [O] is full.") + if(!transfered) + to_chat(user, "The udder is dry. Wait a bit longer...") + else + ..() + +/mob/living/simple_animal/cow/Life() + . = ..() + if(stat == CONSCIOUS) + if(udder && prob(5)) + udder.add_reagent(/datum/reagent/drink/milk, rand(5, 10)) + +/mob/living/simple_animal/cow/attack_hand(mob/living/carbon/M as mob) + if(!stat && M.a_intent == I_DISARM && icon_state != icon_dead) + M.visible_message("[M] tips over [src].","You tip over [src].") + Weaken(30) + icon_state = icon_dead + spawn(rand(20,50)) + if(!stat && M) + icon_state = icon_living + var/list/responses = list( "[src] looks at you imploringly.", + "[src] looks at you pleadingly", + "[src] looks at you with a resigned expression.", + "[src] seems resigned to its fate.") + to_chat(M, pick(responses)) + else + ..() + +/mob/living/simple_animal/chick + name = "\improper chick" + desc = "Adorable! They make such a racket though." + icon_state = "chick" + icon_living = "chick" + icon_dead = "chick_dead" + icon_gib = "chick_gib" + speak = list("Cherp.","Cherp?","Chirrup.","Cheep!") + speak_emote = list("cheeps") + emote_hear = list("cheeps") + emote_see = list("pecks at the ground","flaps its tiny wings") + speak_chance = 2 + turns_per_move = 2 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/chicken + meat_amount = 1 + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "kicks" + attacktext = "kicked" + health = 1 + var/amount_grown = 0 + pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GRILLE + mob_size = MOB_MINISCULE + +/mob/living/simple_animal/chick/New() + ..() + pixel_x = rand(-6, 6) + pixel_y = rand(0, 10) + +/mob/living/simple_animal/chick/Life() + . =..() + if(!.) + return + if(!stat) + amount_grown += rand(1,2) + if(amount_grown >= 100) + new /mob/living/simple_animal/chicken(src.loc) + qdel(src) + +var/const/MAX_CHICKENS = 50 +var/global/chicken_count = 0 + +/mob/living/simple_animal/chicken + name = "\improper chicken" + desc = "Hopefully the eggs are good this season." + icon_state = "chicken" + icon_living = "chicken" + icon_dead = "chicken_dead" + speak = list("Cluck!","BWAAAAARK BWAK BWAK BWAK!","Bwaak bwak.") + speak_emote = list("clucks","croons") + emote_hear = list("clucks") + emote_see = list("pecks at the ground","flaps its wings viciously") + speak_chance = 2 + turns_per_move = 3 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/chicken + meat_amount = 2 + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "kicks" + attacktext = "kicked" + health = 10 + var/eggsleft = 0 + var/body_color + pass_flags = PASS_FLAG_TABLE + mob_size = MOB_SMALL + +/mob/living/simple_animal/chicken/New() + ..() + if(!body_color) + body_color = pick( list("brown","black","white") ) + icon_state = "chicken_[body_color]" + icon_living = "chicken_[body_color]" + icon_dead = "chicken_[body_color]_dead" + pixel_x = rand(-6, 6) + pixel_y = rand(0, 10) + chicken_count += 1 + +/mob/living/simple_animal/chicken/death(gibbed, deathmessage, show_dead_message) + ..(gibbed, deathmessage, show_dead_message) + chicken_count -= 1 + +/mob/living/simple_animal/chicken/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/grown)) //feedin' dem chickens + var/obj/item/weapon/reagent_containers/food/snacks/grown/G = O + if(G.seed && G.seed.kitchen_tag == "wheat") + if(!stat && eggsleft < 8) + user.visible_message("[user] feeds [O] to [name]! It clucks happily.","You feed [O] to [name]! It clucks happily.") + user.drop_item() + qdel(O) + eggsleft += rand(1, 4) + else + to_chat(user, "[name] doesn't seem hungry!") + else + to_chat(user, "[name] doesn't seem interested in that.") + else + ..() + +/mob/living/simple_animal/chicken/Life() + . =..() + if(!.) + return + if(!stat && prob(3) && eggsleft > 0) + visible_message("[src] [pick("lays an egg.","squats down and croons.","begins making a huge racket.","begins clucking raucously.")]") + eggsleft-- + var/obj/item/weapon/reagent_containers/food/snacks/egg/E = new(get_turf(src)) + E.pixel_x = rand(-6,6) + E.pixel_y = rand(-6,6) + if(chicken_count < MAX_CHICKENS && prob(10)) + E.amount_grown = 1 + START_PROCESSING(SSobj, E) + +/obj/item/weapon/reagent_containers/food/snacks/egg + var/amount_grown = 0 + +/obj/item/weapon/reagent_containers/food/snacks/egg/Destroy() + if(amount_grown) + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/item/weapon/reagent_containers/food/snacks/egg/Process() + if(isturf(loc)) + amount_grown += rand(1,2) + if(amount_grown >= 100) + visible_message("[src] hatches with a quiet cracking sound.") + new /mob/living/simple_animal/chick(get_turf(src)) + STOP_PROCESSING(SSobj, src) + qdel(src) + else + return PROCESS_KILL diff --git a/code/modules/mob/living/simple_animal/friendly/lizard.dm b/code/modules/mob/living/simple_animal/friendly/lizard.dm new file mode 100644 index 00000000..2d0ac872 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/lizard.dm @@ -0,0 +1,18 @@ +/mob/living/simple_animal/lizard + name = "Lizard" + desc = "A cute tiny lizard." + icon = 'icons/mob/critter.dmi' + icon_state = "lizard" + icon_living = "lizard" + icon_dead = "lizard-dead" + speak_emote = list("hisses") + health = 5 + maxHealth = 5 + attacktext = "bitten" + melee_damage_lower = 1 + melee_damage_upper = 2 + response_help = "pets" + response_disarm = "shoos" + response_harm = "stomps on" + mob_size = MOB_MINISCULE + possession_candidate = 1 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm new file mode 100644 index 00000000..ba456df2 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -0,0 +1,116 @@ +/mob/living/simple_animal/mouse + name = "mouse" + real_name = "mouse" + desc = "It's a small rodent." + icon_state = "mouse_gray" + item_state = "mouse_gray" + icon_living = "mouse_gray" + icon_dead = "mouse_gray_dead" + speak = list("Squeek!","SQUEEK!","Squeek?") + speak_emote = list("squeeks","squeeks","squiks") + emote_hear = list("squeeks","squeaks","squiks") + emote_see = list("runs in a circle", "shakes", "scritches at something") + pass_flags = PASS_FLAG_TABLE + speak_chance = 1 + turns_per_move = 5 + see_in_dark = 6 + maxHealth = 5 + health = 5 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "stamps on" + density = 0 + var/body_color //brown, gray and white, leave blank for random + minbodytemp = 223 //Below -50 Degrees Celcius + maxbodytemp = 323 //Above 50 Degrees Celcius + universal_speak = 0 + universal_understand = 1 + holder_type = /obj/item/weapon/holder/mouse + mob_size = MOB_MINISCULE + possession_candidate = 1 + + can_pull_size = ITEM_SIZE_TINY + can_pull_mobs = MOB_PULL_NONE + +/mob/living/simple_animal/mouse/Life() + ..() + if(!stat && prob(speak_chance)) + for(var/mob/M in view()) + sound_to(M, 'sound/effects/mousesqueek.ogg') + + if(!ckey && stat == CONSCIOUS && prob(0.5)) + set_stat(UNCONSCIOUS) + icon_state = "mouse_[body_color]_sleep" + wander = 0 + speak_chance = 0 + //snuffles + else if(stat == UNCONSCIOUS) + if(ckey || prob(1)) + set_stat(CONSCIOUS) + icon_state = "mouse_[body_color]" + wander = 1 + else if(prob(5)) + audible_emote("snuffles.") + +/mob/living/simple_animal/mouse/lay_down() + ..() + icon_state = resting ? "mouse_[body_color]_sleep" : "mouse_[body_color]" + +/mob/living/simple_animal/mouse/New() + ..() + + verbs += /mob/living/proc/ventcrawl + verbs += /mob/living/proc/hide + + if(name == initial(name)) + name = "[name] ([sequential_id(/mob/living/simple_animal/mouse)])" + real_name = name + + if(!body_color) + body_color = pick( list("brown","gray","white") ) + icon_state = "mouse_[body_color]" + item_state = "mouse_[body_color]" + icon_living = "mouse_[body_color]" + icon_dead = "mouse_[body_color]_dead" + desc = "It's a small [body_color] rodent, often seen hiding in maintenance areas and making a nuisance of itself." + +/mob/living/simple_animal/mouse/proc/splat() + icon_dead = "mouse_[body_color]_splat" + adjustBruteLoss(maxHealth) // Enough damage to kill + src.death() + +/mob/living/simple_animal/mouse/Crossed(AM as mob|obj) + if( ishuman(AM) ) + if(!stat) + var/mob/M = AM + to_chat(M, "\icon[src] Squeek!") + sound_to(M, 'sound/effects/mousesqueek.ogg') + ..() + +/* + * Mouse types + */ + +/mob/living/simple_animal/mouse/white + body_color = "white" + icon_state = "mouse_white" + +/mob/living/simple_animal/mouse/gray + body_color = "gray" + icon_state = "mouse_gray" + +/mob/living/simple_animal/mouse/brown + body_color = "brown" + icon_state = "mouse_brown" + +//TOM IS ALIVE! SQUEEEEEEEE~K :) +/mob/living/simple_animal/mouse/brown/Tom + name = "Tom" + desc = "Jerry the cat is not amused." + +/mob/living/simple_animal/mouse/brown/Tom/New() + ..() + // Change my name back, don't want to be named Tom (666) + SetName(initial(name)) + real_name = name \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/mushroom.dm b/code/modules/mob/living/simple_animal/friendly/mushroom.dm new file mode 100644 index 00000000..5682a28d --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/mushroom.dm @@ -0,0 +1,66 @@ +/mob/living/simple_animal/mushroom + name = "walking mushroom" + desc = "It's a massive mushroom... with legs?" + icon_state = "mushroom" + icon_living = "mushroom" + icon_dead = "mushroom_dead" + mob_size = MOB_SMALL + speak_chance = 0 + turns_per_move = 1 + maxHealth = 5 + health = 5 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/hugemushroomslice + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "whacks" + harm_intent_damage = 5 + var/datum/seed/seed + var/harvest_time + var/min_explode_time = 1200 + var/global/total_mushrooms = 0 + +/mob/living/simple_animal/mushroom/New() + ..() + harvest_time = world.time + total_mushrooms++ + +/mob/living/simple_animal/mushroom/verb/spawn_spores() + + set name = "Explode" + set category = "Abilities" + set desc = "Spread your spores!" + set src = usr + + if(stat == 2) + to_chat(usr, "You are dead; it is too late for that.") + return + + if(!seed) + to_chat(usr, "You are sterile!") + return + + if(world.time < harvest_time + min_explode_time) + to_chat(usr, "You are not mature enough for that.") + return + + spore_explode() + +/mob/living/simple_animal/mushroom/death(gibbed, deathmessage, show_dead_message) + . = ..(gibbed, deathmessage, show_dead_message) + if(.) + total_mushrooms-- + if(total_mushrooms < config.maximum_mushrooms && prob(30)) + spore_explode() + +/mob/living/simple_animal/mushroom/proc/spore_explode() + if(!seed) + return + if(world.time < harvest_time + min_explode_time) + return + for(var/turf/simulated/target_turf in orange(1,src)) + if(prob(60) && !target_turf.density && src.Adjacent(target_turf)) + new /obj/machinery/portable_atmospherics/hydroponics/soil/invisible(target_turf,seed) + death(0) + seed.thrown_at(src,get_turf(src),1) + if(src) + qdel(src) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/slime.dm b/code/modules/mob/living/simple_animal/friendly/slime.dm new file mode 100644 index 00000000..fcda7389 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/slime.dm @@ -0,0 +1,53 @@ +/mob/living/simple_animal/slime + name = "pet slime" + desc = "A lovable, domesticated slime." + icon = 'icons/mob/slimes.dmi' + icon_state = "grey baby slime" + icon_living = "grey baby slime" + icon_dead = "grey baby slime dead" + speak_emote = list("chirps") + health = 100 + maxHealth = 100 + response_help = "pets" + response_disarm = "shoos" + response_harm = "stomps on" + 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) + to_chat(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." + icon = 'icons/mob/slimes.dmi' + health = 200 + maxHealth = 200 + icon_state = "grey adult slime" + icon_living = "grey adult slime" + icon_dead = "grey baby slime dead" + response_help = "pets" + response_disarm = "shoos" + response_harm = "stomps on" + emote_see = list("jiggles", "bounces in place") + var/colour = "grey" + +/mob/living/simple_animal/adultslime/New() + ..() + overlays += "aslime-:33" + + +/mob/living/simple_animal/slime/adult/death() + var/mob/living/simple_animal/slime/S1 = new /mob/living/simple_animal/slime (src.loc) + S1.icon_state = "[src.colour] baby slime" + S1.icon_living = "[src.colour] baby slime" + S1.icon_dead = "[src.colour] baby slime dead" + S1.colour = "[src.colour]" + var/mob/living/simple_animal/slime/S2 = new /mob/living/simple_animal/slime (src.loc) + S2.icon_state = "[src.colour] baby slime" + S2.icon_living = "[src.colour] baby slime" + S2.icon_dead = "[src.colour] baby slime dead" + S2.colour = "[src.colour]" + qdel(src) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/spiderbot.dm b/code/modules/mob/living/simple_animal/friendly/spiderbot.dm new file mode 100644 index 00000000..af920f89 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/spiderbot.dm @@ -0,0 +1,285 @@ +/mob/living/simple_animal/spiderbot + + min_gas = null + max_gas = null + minbodytemp = 0 + maxbodytemp = 500 + mob_size = MOB_SMALL + + var/obj/item/device/radio/borg/radio = null + var/mob/living/silicon/ai/connected_ai = null + var/obj/item/weapon/cell/cell = null + var/obj/machinery/camera/camera = null + var/obj/item/device/mmi/mmi = null + var/list/req_access = list(access_robotics) //Access needed to pop out the brain. + var/positronic + + name = "spider-bot" + desc = "A skittering robotic friend!" + icon = 'icons/mob/robots_misc.dmi' + icon_state = "spiderbot-chassis" + icon_living = "spiderbot-chassis" + icon_dead = "spiderbot-smashed" + + wander = 0 + + health = 10 + maxHealth = 10 + + attacktext = "shocked" + melee_damage_lower = 1 + melee_damage_upper = 3 + + response_help = "pets" + response_disarm = "shoos" + response_harm = "stomps on" + + var/emagged = 0 + var/obj/item/held_item = null //Storage for single item they can hold. + speed = -1 //Spiderbots gotta go fast. + pass_flags = PASS_FLAG_TABLE + speak_emote = list("beeps","clicks","chirps") + +/mob/living/simple_animal/spiderbot/New() + ..() + add_language(LANGUAGE_GALCOM) + default_language = all_languages[LANGUAGE_GALCOM] + verbs |= /mob/living/proc/ventcrawl + verbs |= /mob/living/proc/hide + +/mob/living/simple_animal/spiderbot/attackby(var/obj/item/O as obj, var/mob/user as mob) + + if(istype(O, /obj/item/device/mmi) || istype(O, /obj/item/organ/internal/posibrain)) + var/mob/living/carbon/brain/B + if(istype(O, /obj/item/device/mmi)) + var/obj/item/device/mmi/M = O + B = M.brainmob + else + var/obj/item/organ/internal/posibrain/P = O + B = P.brainmob + if(src.mmi) + to_chat(user, "There's already a brain in [src]!") + return + if(!B) + to_chat(user, "Sticking an empty MMI into the frame would sort of defeat the purpose.") + return + if(!B.key) + var/ghost_can_reenter = 0 + if(B.mind) + for(var/mob/observer/ghost/G in GLOB.player_list) + if(G.can_reenter_corpse && G.mind == B.mind) + ghost_can_reenter = 1 + break + if(!ghost_can_reenter) + to_chat(user, "[O] is completely unresponsive; there's no point.") + return + + if(B.stat == DEAD) + to_chat(user, "[O] is dead. Sticking it into the frame would sort of defeat the purpose.") + return + + if(jobban_isbanned(B, "Cyborg")) + to_chat(user, "\The [O] does not seem to fit.") + return + + to_chat(user, "You install \the [O] in \the [src]!") + if(istype(O, /obj/item/organ/internal/posibrain)) + positronic = 1 + add_language("Robot Talk") + + user.drop_item() + src.mmi = O + src.transfer_personality(O) + + O.loc = src + src.update_icon() + return 1 + + if(isWelder(O)) + var/obj/item/weapon/weldingtool/WT = O + if (WT.remove_fuel(0)) + if(health < maxHealth) + health += pick(1,1,1,2,2,3) + if(health > maxHealth) + health = maxHealth + add_fingerprint(user) + src.visible_message("\The [user] has spot-welded some of the damage to \the [src]!") + else + to_chat(user, "\The [src] is undamaged!") + else + to_chat(user, "You need more welding fuel for this task!") + return + else if(istype(O, /obj/item/weapon/card/id)||istype(O, /obj/item/device/pda)) + if (!mmi) + to_chat(user, "There's no reason to swipe your ID - \the [src] has no brain to remove.") + return 0 + + var/obj/item/weapon/card/id/id_card + + if(istype(O, /obj/item/weapon/card/id)) + id_card = O + else + var/obj/item/device/pda/pda = O + id_card = pda.id + + if(access_robotics in id_card.access) + to_chat(user, "You swipe your access card and pop the brain out of \the [src].") + eject_brain() + if(held_item) + held_item.loc = src.loc + held_item = null + return 1 + else + to_chat(user, "You swipe your card with no effect.") + return 0 + + else + O.attack(src, user, user.zone_sel.selecting) + +/mob/living/simple_animal/spiderbot/emag_act(var/remaining_charges, var/mob/user) + if (emagged) + to_chat(user, "[src] is already overloaded - better run.") + return 0 + else + to_chat(user, "You short out the security protocols and overload [src]'s cell, priming it to explode in a short time.") + spawn(100) to_chat(src, "Your cell seems to be outputting a lot of power...") + spawn(200) to_chat(src, "Internal heat sensors are spiking! Something is badly wrong with your cell!") + spawn(300) src.explode() + +/mob/living/simple_animal/spiderbot/proc/transfer_personality(var/obj/item/device/mmi/M as obj) + + src.mind = M.brainmob.mind + src.mind.key = M.brainmob.key + src.ckey = M.brainmob.ckey + src.SetName("spider-bot ([M.brainmob.name])") + +/mob/living/simple_animal/spiderbot/proc/explode() //When emagged. + src.visible_message("\The [src] makes an odd warbling noise, fizzles, and explodes!") + explosion(get_turf(loc), -1, -1, 3, 5) + eject_brain() + death() + +/mob/living/simple_animal/spiderbot/update_icon() + if(mmi) + if(positronic) + icon_state = "spiderbot-chassis-posi" + icon_living = "spiderbot-chassis-posi" + else + icon_state = "spiderbot-chassis-mmi" + icon_living = "spiderbot-chassis-mmi" + else + icon_state = "spiderbot-chassis" + icon_living = "spiderbot-chassis" + +/mob/living/simple_animal/spiderbot/proc/eject_brain() + if(mmi) + var/turf/T = get_turf(loc) + if(T) + mmi.loc = T + if(mind) mind.transfer_to(mmi.brainmob) + mmi = null + real_name = initial(real_name) + SetName(real_name) + update_icon() + remove_language("Robot Talk") + positronic = null + +/mob/living/simple_animal/spiderbot/Destroy() + eject_brain() + ..() + +/mob/living/simple_animal/spiderbot/New() + + radio = new /obj/item/device/radio/borg(src) + camera = new /obj/machinery/camera(src) + camera.c_tag = "spiderbot-[real_name]" + camera.replace_networks(list("SS13")) + + ..() + +/mob/living/simple_animal/spiderbot/death() + switch_from_living_to_dead_mob_list() + + if(camera) + camera.status = 0 + + held_item.loc = src.loc + held_item = null + + gibs(loc, null, null, /obj/effect/gibspawner/robot) //TODO: use gib() or refactor spiderbots into synthetics. + qdel(src) + return + +//Cannibalized from the parrot mob. ~Zuhayr +/mob/living/simple_animal/spiderbot/verb/drop_held_item() + set name = "Drop held item" + set category = "Spiderbot" + set desc = "Drop the item you're holding." + + if(stat) + return + + if(!held_item) + to_chat(usr, "You have nothing to drop!") + return 0 + + if(istype(held_item, /obj/item/weapon/grenade)) + visible_message("\The [src] launches \the [held_item]!", \ + "You launch \the [held_item]!", \ + "You hear a skittering noise and a thump!") + var/obj/item/weapon/grenade/G = held_item + G.loc = src.loc + G.detonate() + held_item = null + return 1 + + visible_message("\The [src] drops \the [held_item].", \ + "You drop \the [held_item].", \ + "You hear a skittering noise and a soft thump.") + + held_item.loc = src.loc + held_item = null + return 1 + + return + +/mob/living/simple_animal/spiderbot/verb/get_item() + set name = "Pick up item" + set category = "Spiderbot" + set desc = "Allows you to take a nearby small item." + + if(stat) + return -1 + + if(held_item) + to_chat(src, "You are already holding \the [held_item]") + return 1 + + var/list/items = list() + for(var/obj/item/I in view(1,src)) + if(I.loc != src && I.w_class <= ITEM_SIZE_SMALL && I.Adjacent(src) ) + items.Add(I) + + var/obj/selection = input("Select an item.", "Pickup") in items + + if(selection) + for(var/obj/item/I in view(1, src)) + if(selection == I) + held_item = selection + selection.loc = src + visible_message("\The [src] scoops up \the [held_item].", \ + "You grab \the [held_item].", \ + "You hear a skittering noise and a clink.") + return held_item + to_chat(src, "\The [selection] is too far away.") + return 0 + + to_chat(src, "There is nothing of interest to take.") + return 0 + +/mob/living/simple_animal/spiderbot/examine(mob/user) + . = ..(user) + if(src.held_item) + to_chat(user, "It is carrying \icon[src.held_item] \a [src.held_item].") +/mob/living/simple_animal/spiderbot/binarycheck() + return positronic \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/tomato.dm b/code/modules/mob/living/simple_animal/friendly/tomato.dm new file mode 100644 index 00000000..51027b8d --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/tomato.dm @@ -0,0 +1,18 @@ +/mob/living/simple_animal/tomato + name = "tomato" + desc = "It's a horrifyingly enormous beef tomato, and it's packing extra beef!" + icon_state = "tomato" + icon_living = "tomato" + icon_dead = "tomato_dead" + speak_chance = 0 + turns_per_move = 5 + maxHealth = 15 + health = 15 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/tomatomeat + response_help = "prods" + response_disarm = "pushes aside" + response_harm = "smacks" + harm_intent_damage = 5 + melee_damage_upper = 15 + melee_damage_lower = 10 + attacktext = "mauled" \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/head.dm b/code/modules/mob/living/simple_animal/head.dm new file mode 100644 index 00000000..7ebb8330 --- /dev/null +++ b/code/modules/mob/living/simple_animal/head.dm @@ -0,0 +1,59 @@ +//Look Sir, free head! +/mob/living/simple_animal/head + name = "CommandBattle AI" + desc = "A standard borg shell on its chest crude marking saying CommandBattle AI MK4 : Head." + icon_state = "crab" + icon_living = "crab" + icon_dead = "crab_dead" + speak_emote = list("clicks") + emote_hear = list("clicks") + emote_see = list("clacks") + universal_speak = 1 + speak_chance = 1 + turns_per_move = 5 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "punches" + var/list/insults = list( + "Man you suck", + "You look like the most retarded douche around", + "What's up?, oh wait nevermind you are a fucking asshat", + "you are just overly retarded", + "Whiteman said what?!",) + var/list/comments = list("Man have you seen those furry cats?,I mean who in the right mind would like something like that?", + "They call me abusive,I just like the truth", + "Beeboop, im a robit", + "Gooogooooll, break ya bones", + "Crab say what?", + "Man they say we have space lizards now, man this shit is getting more wack every minute", + "The so called \"improved\" AI is just bullshit, that thing aint fun for noone", + "The Captain is a traitor, he took my power core.", + "Say \"what\" again. Say \"what\" again. I dare you. I double-dare you, motherfucker. Say \"what\" one more goddamn time.", + "Ezekiel 25:17 ,The path of the righteous man is beset on all sides by the iniquities of the selfish and the tyranny of evil men. Blessed is he who in the name of charity and good will shepherds the weak through the valley of darkness, for he is truly his brother's keeper and the finder of lost children. And I will strike down upon thee with great vengeance and furious anger those who attempt to poison and destroy my brothers. And you will know my name is the Lord... when I lay my vengeance upon thee.") + stop_automated_movement = 1 + +/mob/living/simple_animal/head/Life() + if(stat == DEAD) + if(health > 0) + icon_state = icon_living + set_stat(CONSCIOUS) + set_density(1) + return + else if(health < 1) + Die() + else if(health > maxHealth) + health = maxHealth + for(var/mob/A in viewers(world.view,src)) + if(A.ckey) + say_something(A) +/mob/living/simple_animal/head/proc/say_something(mob/A) + if(prob(85)) + return + if(prob(30)) + var/msg = pick(insults) + msg = "Hey, [A.name].. [msg]" + src.say(msg) + else + var/msg = pick(comments) + src.say(msg) diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm new file mode 100644 index 00000000..8765c35c --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/alien.dm @@ -0,0 +1,86 @@ +/mob/living/simple_animal/hostile/alien + name = "alien hunter" + desc = "Hiss!" + icon = 'icons/mob/alien.dmi' + icon_state = "alienh_running" + icon_living = "alienh_running" + icon_dead = "alienh_dead" + icon_gib = "syndicate_gib" + response_help = "pokes" + response_disarm = "shoves" + response_harm = "hits" + speed = -1 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/xenomeat + maxHealth = 100 + health = 100 + harm_intent_damage = 5 + melee_damage_lower = 25 + melee_damage_upper = 25 + attacktext = "slashed" + a_intent = I_HURT + attack_sound = 'sound/weapons/bladeslice.ogg' + min_gas = null + max_gas = null + unsuitable_atoms_damage = 15 + faction = "alien" + environment_smash = 2 + status_flags = CANPUSH + minbodytemp = 0 + heat_damage_per_tick = 20 + + +/mob/living/simple_animal/hostile/alien/drone + name = "alien drone" + icon_state = "aliend_running" + icon_living = "aliend_running" + icon_dead = "aliend_dead" + health = 60 + melee_damage_lower = 15 + melee_damage_upper = 15 + +/mob/living/simple_animal/hostile/alien/sentinel + name = "alien sentinel" + icon_state = "aliens_running" + icon_living = "aliens_running" + icon_dead = "aliens_dead" + health = 120 + melee_damage_lower = 15 + melee_damage_upper = 15 + ranged = 1 + projectiletype = /obj/item/projectile/neurotox + projectilesound = 'sound/weapons/pierce.ogg' + + +/mob/living/simple_animal/hostile/alien/queen + name = "alien queen" + icon_state = "alienq_running" + icon_living = "alienq_running" + icon_dead = "alienq_dead" + health = 250 + maxHealth = 250 + melee_damage_lower = 15 + melee_damage_upper = 15 + ranged = 1 + move_to_delay = 3 + projectiletype = /obj/item/projectile/neurotox + projectilesound = 'sound/weapons/pierce.ogg' + rapid = 1 + status_flags = 0 + +/mob/living/simple_animal/hostile/alien/queen/large + name = "alien empress" + icon = 'icons/mob/alienqueen.dmi' + icon_state = "queen_s" + icon_living = "queen_s" + icon_dead = "queen_dead" + move_to_delay = 4 + maxHealth = 400 + health = 400 + +/obj/item/projectile/neurotox + damage = 30 + icon_state = "toxin" + +/mob/living/simple_animal/hostile/alien/death(gibbed, deathmessage, show_dead_message) + ..(gibbed, deathmessage = "lets out a waning guttural screech, green blood bubbling from its maw...", show_dead_message) + playsound(src, 'sound/voice/hiss6.ogg', 100, 1) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/armalis.dm b/code/modules/mob/living/simple_animal/hostile/armalis.dm new file mode 100644 index 00000000..2b746a20 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/armalis.dm @@ -0,0 +1,41 @@ +/mob/living/simple_animal/hostile/armalis + name = "Vox Armalis" + desc = "In truth, this scares you." + + icon = 'icons/mob/armalis.dmi' + icon_state = "armalis_naked" + icon_living = "armalis_naked" + icon_dead = "armalis_naked_dead" + + health = 225 + maxHealth = 225 + resistance = 5 + + response_help = "pats" + response_disarm = "pushes" + response_harm = "hits" + + attacktext = "reaped" + attack_sound = 'sound/effects/bamf.ogg' + melee_damage_lower = 15 + melee_damage_upper = 20 + + min_gas = null + max_gas = null + + speed = 2 + + a_intent = I_HURT + + pixel_x = -5 + + +/mob/living/simple_animal/hostile/armalis/armored + icon_state = "armalis_armored" + icon_living = "armalis_armored" + icon_dead = "armalis_armored_dead" + + health = 275 + maxHealth = 275 + resistance = 8 + speed = 3 diff --git a/code/modules/mob/living/simple_animal/hostile/bat.dm b/code/modules/mob/living/simple_animal/hostile/bat.dm new file mode 100644 index 00000000..f3d68c67 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/bat.dm @@ -0,0 +1,62 @@ +/mob/living/simple_animal/hostile/scarybat + name = "space bats" + desc = "A swarm of cute little blood sucking bats that looks pretty upset." + icon = 'icons/mob/bats.dmi' + icon_state = "bat" + icon_living = "bat" + icon_dead = "bat_dead" + icon_gib = "bat_dead" + speak_chance = 0 + turns_per_move = 3 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat + response_help = "pets the" + response_disarm = "gently pushes aside the" + response_harm = "hits the" + speed = 4 + maxHealth = 20 + health = 20 + + harm_intent_damage = 8 + melee_damage_lower = 10 + melee_damage_upper = 10 + attacktext = "bites" + attack_sound = 'sound/weapons/bite.ogg' + + min_gas = null + max_gas = null + minbodytemp = 0 + + environment_smash = 1 + + faction = "scarybat" + var/mob/living/owner + +/mob/living/simple_animal/hostile/scarybat/New(loc, mob/living/L as mob) + ..() + if(istype(L)) + owner = L + +/mob/living/simple_animal/hostile/scarybat/FindTarget() + . = ..() + if(.) + emote("flutters towards [.]") + +/mob/living/simple_animal/hostile/scarybat/Found(var/atom/A)//This is here as a potential override to pick a specific target if available + if(istype(A) && A == owner) + return 0 + return ..() + +/mob/living/simple_animal/hostile/scarybat/AttackingTarget() + . =..() + var/mob/living/L = . + if(istype(L)) + if(prob(15)) + L.Stun(1) + L.visible_message("\the [src] scares \the [L]!") + +/mob/living/simple_animal/hostile/scarybat/cult + faction = "cult" + supernatural = 1 + +/mob/living/simple_animal/hostile/scarybat/cult/cultify() + return diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm new file mode 100644 index 00000000..756d86ab --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/bear.dm @@ -0,0 +1,159 @@ +//Space bears! +/mob/living/simple_animal/hostile/bear + name = "space bear" + desc = "RawrRawr!!" + icon_state = "bear" + icon_living = "bear" + icon_dead = "bear_dead" + icon_gib = "bear_gib" + speak = list("RAWR!","Rawr!","GRR!","Growl!") + speak_emote = list("growls", "roars") + emote_hear = list("rawrs","grumbles","grawls") + emote_see = list("stares ferociously", "stomps") + speak_chance = 1 + turns_per_move = 5 + see_in_dark = 6 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/bearmeat + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "pokes" + stop_automated_movement_when_pulled = 0 + maxHealth = 60 + health = 60 + melee_damage_lower = 20 + melee_damage_upper = 30 + + //Space bears aren't affected by atmos. + min_gas = null + max_gas = null + minbodytemp = 0 + var/stance_step = 0 + + faction = "russian" + +//SPACE BEARS! SQUEEEEEEEE~ OW! FUCK! IT BIT MY HAND OFF!! +/mob/living/simple_animal/hostile/bear/Hudson + name = "Hudson" + desc = "" + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "pokes" + +/mob/living/simple_animal/hostile/bear/Life() + . =..() + if(!.) + return + + if(loc && istype(loc,/turf/space)) + icon_state = "bear" + else + icon_state = "bearfloor" + + switch(stance) + + if(HOSTILE_STANCE_TIRED) + stop_automated_movement = 1 + stance_step++ + if(stance_step >= 10) //rests for 10 ticks + if(target_mob && target_mob in ListTargets(10)) + stance = HOSTILE_STANCE_ATTACK //If the mob he was chasing is still nearby, resume the attack, otherwise go idle. + else + stance = HOSTILE_STANCE_IDLE + + if(HOSTILE_STANCE_ALERT) + stop_automated_movement = 1 + var/found_mob = 0 + if(target_mob && target_mob in ListTargets(10)) + if(!(SA_attackable(target_mob))) + stance_step = max(0, stance_step) //If we have not seen a mob in a while, the stance_step will be negative, we need to reset it to 0 as soon as we see a mob again. + stance_step++ + found_mob = 1 + src.set_dir(get_dir(src,target_mob)) //Keep staring at the mob + + if(stance_step in list(1,4,7)) //every 3 ticks + var/action = pick( list( "growls at [target_mob]", "stares angrily at [target_mob]", "prepares to attack [target_mob]", "closely watches [target_mob]" ) ) + if(action) + custom_emote(1,action) + if(!found_mob) + stance_step-- + + if(stance_step <= -20) //If we have not found a mob for 20-ish ticks, revert to idle mode + stance = HOSTILE_STANCE_IDLE + if(stance_step >= 7) //If we have been staring at a mob for 7 ticks, + stance = HOSTILE_STANCE_ATTACK + + if(HOSTILE_STANCE_ATTACKING) + if(stance_step >= 20) //attacks for 20 ticks, then it gets tired and needs to rest + custom_emote(1, "is worn out and needs to rest." ) + stance = HOSTILE_STANCE_TIRED + stance_step = 0 + walk(src, 0) //This stops the bear's walking + return + + + +/mob/living/simple_animal/hostile/bear/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING) + stance = HOSTILE_STANCE_ALERT + stance_step = 6 + target_mob = user + ..() + +/mob/living/simple_animal/hostile/bear/attack_hand(mob/living/carbon/human/M as mob) + if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING) + stance = HOSTILE_STANCE_ALERT + stance_step = 6 + target_mob = M + ..() + +/mob/living/simple_animal/hostile/bear/FindTarget() + . = ..() + if(.) + custom_emote(1,"stares alertly at [.]") + stance = HOSTILE_STANCE_ALERT + +/mob/living/simple_animal/hostile/bear/LoseTarget() + ..(5) + +/mob/living/simple_animal/hostile/bear/AttackingTarget() + if(!Adjacent(target_mob)) + return + custom_emote(1, pick( list("slashes at [target_mob]", "bites [target_mob]") ) ) + + var/damage = rand(20,30) + + if(ishuman(target_mob)) + var/mob/living/carbon/human/H = target_mob + var/dam_zone = pick(BP_CHEST, BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG) + var/obj/item/organ/external/affecting = H.get_organ(ran_zone(dam_zone)) + H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, "melee"), DAM_SHARP|DAM_EDGE) + return H + else if(isliving(target_mob)) + var/mob/living/L = target_mob + L.adjustBruteLoss(damage) + return L + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/modules/mob/living/simple_animal/hostile/beepis.dm b/code/modules/mob/living/simple_animal/hostile/beepis.dm new file mode 100644 index 00000000..4042299f --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/beepis.dm @@ -0,0 +1,15 @@ +/mob/living/simple_animal/hostile/beepis + name = "beepis" + desc = "I don't know some fuckin' thing?" + icon_state = "beepis" + icon_living = "beepis" + icon_dead = "beepis_dead" + icon_gib = "beepis" + speak_chance = 0 + turns_per_move = 5 + response_help = "pets the" + response_disarm = "gently pushes aside the" + response_harm = "hits the" + speed = 4 + maxHealth = 25 + health = 25 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm new file mode 100644 index 00000000..9b48ca30 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/carp.dm @@ -0,0 +1,49 @@ + + +/mob/living/simple_animal/hostile/carp + name = "space carp" + desc = "A ferocious, fang-bearing creature that resembles a fish." + icon_state = "carp" + icon_living = "carp" + icon_dead = "carp_dead" + icon_gib = "carp_gib" + speak_chance = 0 + turns_per_move = 5 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat + response_help = "pets the" + response_disarm = "gently pushes aside the" + response_harm = "hits the" + speed = 4 + maxHealth = 25 + health = 25 + + harm_intent_damage = 8 + melee_damage_lower = 15 + melee_damage_upper = 15 + attacktext = "bitten" + attack_sound = 'sound/weapons/bite.ogg' + + //Space carp aren't affected by atmos. + min_gas = null + max_gas = null + minbodytemp = 0 + + break_stuff_probability = 15 + + faction = "carp" + +/mob/living/simple_animal/hostile/carp/Allow_Spacemove(var/check_drift = 0) + return 1 //No drifting in space for space carp! //original comments do not steal + +/mob/living/simple_animal/hostile/carp/FindTarget() + . = ..() + if(.) + custom_emote(1,"nashes at [.]") + +/mob/living/simple_animal/hostile/carp/AttackingTarget() + . =..() + var/mob/living/L = . + if(istype(L)) + if(prob(15)) + L.Weaken(3) + L.visible_message("\the [src] knocks down \the [L]!") \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/commanded/_command_defines.dm b/code/modules/mob/living/simple_animal/hostile/commanded/_command_defines.dm new file mode 100644 index 00000000..72ae6dc7 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/commanded/_command_defines.dm @@ -0,0 +1,3 @@ +#define COMMANDED_STOP 6 //basically 'do nothing' +#define COMMANDED_FOLLOW 7 //follows a target +#define COMMANDED_MISC 8 //catch all state for misc commands that need one. \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/commanded/bear_companion.dm b/code/modules/mob/living/simple_animal/hostile/commanded/bear_companion.dm new file mode 100644 index 00000000..7917fcac --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/commanded/bear_companion.dm @@ -0,0 +1,67 @@ +/mob/living/simple_animal/hostile/commanded/bear + name = "bear" + desc = "A large brown bear." + + icon_state = "brownbear" + icon_living = "brownbear" + icon_dead = "brownbear_dead" + icon_gib = "brownbear_gib" + + health = 75 + maxHealth = 75 + + density = 1 + + attacktext = "swatted" + melee_damage_lower = 10 + melee_damage_upper = 10 + + max_gas = list("phoron" = 2, "carbon_dioxide" = 5) + + response_help = "pets" + response_harm = "hits" + response_disarm = "pushes" + + known_commands = list("stay", "stop", "attack", "follow", "dance", "boogie", "boogy") + +/mob/living/simple_animal/hostile/commanded/bear/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone) + . = ..() + if(!.) + src.emote("roars in rage!") + +/mob/living/simple_animal/hostile/commanded/bear/attack_hand(mob/living/carbon/human/M as mob) + ..() + if(M.a_intent == I_HURT) + src.emote("roars in rage!") + +/mob/living/simple_animal/hostile/commanded/bear/listen() + if(stance != COMMANDED_MISC) //cant listen if its booty shakin' + ..() + +//WE DANCE! +/mob/living/simple_animal/hostile/commanded/bear/misc_command(var/mob/speaker,var/text) + stay_command() + stance = COMMANDED_MISC //nothing can stop this ride + spawn(0) + src.visible_message("\The [src] starts to dance!.") + var/datum/gender/G = gender_datums[gender] + for(var/i in 1 to 10) + if(stance != COMMANDED_MISC || incapacitated()) //something has stopped this ride. + return + var/message = pick(\ + "moves [G.his] head back and forth!",\ + "bobs [G.his] booty!",\ + "shakes [G.his] paws in the air!",\ + "wiggles [G.his] ears!",\ + "taps [G.his] foot!",\ + "shrugs [G.his] shoulders!",\ + "dances like you've never seen!") + if(dir != WEST) + set_dir(WEST) + else + set_dir(EAST) + src.visible_message("\The [src] [message]") + sleep(30) + stance = COMMANDED_STOP + set_dir(SOUTH) + src.visible_message("\The [src] bows, finished with [G.his] dance.") \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm b/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm new file mode 100644 index 00000000..572a1d02 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm @@ -0,0 +1,192 @@ +/mob/living/simple_animal/hostile/commanded + name = "commanded" + stance = COMMANDED_STOP + melee_damage_lower = 0 + melee_damage_upper = 0 + density = 0 + var/list/command_buffer = list() + var/list/known_commands = list("stay", "stop", "attack", "follow") + var/mob/master = null //undisputed master. Their commands hold ultimate sway and ultimate power. + var/list/allowed_targets = list() //WHO CAN I KILL D: + var/retribution = 1 //whether or not they will attack us if we attack them like some kinda dick. + +/mob/living/simple_animal/hostile/commanded/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) + if((weakref(speaker) in friends) || speaker == master) + command_buffer.Add(speaker) + command_buffer.Add(lowertext(html_decode(message))) + return 0 + +/mob/living/simple_animal/hostile/commanded/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0) + if((weakref(speaker) in friends) || speaker == master) + command_buffer.Add(speaker) + command_buffer.Add(lowertext(html_decode(message))) + return 0 + +/mob/living/simple_animal/hostile/commanded/Life() + while(command_buffer.len > 0) + var/mob/speaker = command_buffer[1] + var/text = command_buffer[2] + var/filtered_name = lowertext(html_decode(name)) + if(dd_hasprefix(text,filtered_name) || dd_hasprefix(text,"everyone") || dd_hasprefix(text, "everybody")) //in case somebody wants to command 8 bears at once. + var/substring = copytext(text,length(filtered_name)+1) //get rid of the name. + listen(speaker,substring) + command_buffer.Remove(command_buffer[1],command_buffer[2]) + . = ..() + if(.) + switch(stance) + if(COMMANDED_FOLLOW) + follow_target() + if(COMMANDED_STOP) + commanded_stop() + + + +/mob/living/simple_animal/hostile/commanded/FindTarget(var/new_stance = HOSTILE_STANCE_ATTACK) + if(!allowed_targets.len) + return null + var/mode = "specific" + if(allowed_targets[1] == "everyone") //we have been given the golden gift of murdering everything. Except our master, of course. And our friends. So just mostly everyone. + mode = "everyone" + for(var/atom/A in ListTargets(10)) + var/mob/M = null + if(A == src) + continue + if(isliving(A)) + M = A + if(istype(A,/obj/mecha)) + var/obj/mecha/mecha = A + if(!mecha.occupant) + continue + M = mecha.occupant + if(M && M.stat) + continue + if(mode == "specific") + if(!(A in allowed_targets)) + continue + stance = new_stance + return A + else + if(M == master || (weakref(M) in friends)) + continue + stance = new_stance + return A + + +/mob/living/simple_animal/hostile/commanded/proc/follow_target() + stop_automated_movement = 1 + if(!target_mob) + return + if(target_mob in ListTargets(10)) + walk_to(src,target_mob,1,move_to_delay) + +/mob/living/simple_animal/hostile/commanded/proc/commanded_stop() //basically a proc that runs whenever we are asked to stay put. Probably going to remain unused. + return + +/mob/living/simple_animal/hostile/commanded/proc/listen(var/mob/speaker, var/text) + for(var/command in known_commands) + if(findtext(text,command)) + switch(command) + if("stay") + if(stay_command(speaker,text)) //find a valid command? Stop. Dont try and find more. + break + if("stop") + if(stop_command(speaker,text)) + break + if("attack") + if(attack_command(speaker,text)) + break + if("follow") + if(follow_command(speaker,text)) + break + else + misc_command(speaker,text) //for specific commands + + return 1 + +//returns a list of everybody we wanna do stuff with. +/mob/living/simple_animal/hostile/commanded/proc/get_targets_by_name(var/text, var/filter_friendlies = 0) + var/list/possible_targets = hearers(src,10) + . = list() + for(var/mob/M in possible_targets) + if(filter_friendlies && ((weakref(M) in friends) || M.faction == faction || M == master)) + continue + var/found = 0 + if(findtext(text, "[M]")) + found = 1 + else + var/list/parsed_name = splittext(replace_characters(lowertext(html_decode("[M]")),list("-"=" ", "."=" ", "," = " ", "'" = " ")), " ") //this big MESS is basically 'turn this into words, no punctuation, lowercase so we can check first name/last name/etc' + for(var/a in parsed_name) + if(a == "the" || length(a) < 2) //get rid of shit words. + continue + if(findtext(text,"[a]")) + found = 1 + break + if(found) + . += M + + +/mob/living/simple_animal/hostile/commanded/proc/attack_command(var/mob/speaker,var/text) + target_mob = null //want me to attack something? Well I better forget my old target. + walk_to(src,0) + stance = HOSTILE_STANCE_IDLE + if(text == "attack" || findtext(text,"everyone") || findtext(text,"anybody") || findtext(text, "somebody") || findtext(text, "someone")) //if its just 'attack' then just attack anybody, same for if they say 'everyone', somebody, anybody. Assuming non-pickiness. + allowed_targets = list("everyone")//everyone? EVERYONE + return 1 + + var/list/targets = get_targets_by_name(text) + allowed_targets += targets + return targets.len != 0 + +/mob/living/simple_animal/hostile/commanded/proc/stay_command(var/mob/speaker,var/text) + target_mob = null + stance = COMMANDED_STOP + stop_automated_movement = 1 + walk_to(src,0) + return 1 + +/mob/living/simple_animal/hostile/commanded/proc/stop_command(var/mob/speaker,var/text) + allowed_targets = list() + walk_to(src,0) + target_mob = null //gotta stop SOMETHIN + stance = HOSTILE_STANCE_IDLE + stop_automated_movement = 0 + return 1 + +/mob/living/simple_animal/hostile/commanded/proc/follow_command(var/mob/speaker,var/text) + //we can assume 'stop following' is handled by stop_command + if(findtext(text,"me")) + stance = COMMANDED_FOLLOW + target_mob = speaker //this wont bite me in the ass later. + return 1 + var/list/targets = get_targets_by_name(text) + if(targets.len > 1 || !targets.len) //CONFUSED. WHO DO I FOLLOW? + return 0 + + stance = COMMANDED_FOLLOW //GOT SOMEBODY. BETTER FOLLOW EM. + target_mob = targets[1] //YEAH GOOD IDEA + + return 1 + +/mob/living/simple_animal/hostile/commanded/proc/misc_command(var/mob/speaker,var/text) + return 0 + + +/mob/living/simple_animal/hostile/commanded/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone) + //if they attack us, we want to kill them. None of that "you weren't given a command so free kill" bullshit. + . = ..() + if(!. && retribution) + stance = HOSTILE_STANCE_ATTACK + target_mob = user + allowed_targets += user //fuck this guy in particular. + if(weakref(user) in friends) //We were buds :'( + friends -= weakref(user) + + +/mob/living/simple_animal/hostile/commanded/attack_hand(mob/living/carbon/human/M as mob) + ..() + if(M.a_intent == I_HURT && retribution) //assume he wants to hurt us. + target_mob = M + allowed_targets += M + stance = HOSTILE_STANCE_ATTACK + if(weakref(M) in friends) + friends -= weakref(M) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/commanded/nanomachines.dm b/code/modules/mob/living/simple_animal/hostile/commanded/nanomachines.dm new file mode 100644 index 00000000..97d3671b --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/commanded/nanomachines.dm @@ -0,0 +1,96 @@ +#define COMMANDED_HEAL 8//we got healing powers yo +#define COMMANDED_HEALING 9 + +/mob/living/simple_animal/hostile/commanded/nanomachine + name = "swarm" + desc = "a cloud of tiny, tiny robots." + icon = 'icons/mob/critter.dmi' + icon_state = "blobsquiggle_grey" + attacktext = "swarmed" + health = 10 + maxHealth = 10 + var/regen_time = 0 + melee_damage_lower = 1 + melee_damage_upper = 2 + var/emergency_protocols = 0 + known_commands = list("stay", "stop", "attack", "follow", "heal", "emergency protocol") + + response_help = "waves their hands through" + response_harm = "hits" + response_disarm = "fans at" + +/mob/living/simple_animal/hostile/commanded/nanomachine/Life() + regen_time++ + if(regen_time == 2 && health < maxHealth) //slow regen + regen_time = 0 + health++ + . = ..() + if(.) + switch(stance) + if(COMMANDED_HEAL) + if(!target_mob) + target_mob = FindTarget(COMMANDED_HEAL) + move_to_heal() + if(COMMANDED_HEALING) + heal() + +/mob/living/simple_animal/hostile/commanded/nanomachine/death(gibbed, deathmessage, show_dead_message) + ..(null, "dissipates into thin air", "You have been destroyed.") + qdel(src) + +/mob/living/simple_animal/hostile/commanded/nanomachine/proc/move_to_heal() + if(!target_mob) + return 0 + walk_to(src,target_mob,1,move_to_delay) + if(Adjacent(target_mob)) + stance = COMMANDED_HEALING + +/mob/living/simple_animal/hostile/commanded/nanomachine/proc/heal() + if(health <= 3 && !emergency_protocols) //dont die doing this. + return 0 + if(!target_mob) + return 0 + if(!Adjacent(target_mob) || SA_attackable(target_mob)) + stance = COMMANDED_HEAL + return 0 + if(target_mob.stat || target_mob.health >= target_mob.maxHealth) //he's either dead or healthy, move along. + allowed_targets -= target_mob + target_mob = null + stance = COMMANDED_HEAL + return 0 + src.visible_message("\The [src] glows green for a moment, healing \the [target_mob]'s wounds.") + health -= 3 + target_mob.adjustBruteLoss(-5) + target_mob.adjustFireLoss(-5) + +/mob/living/simple_animal/hostile/commanded/nanomachine/misc_command(var/mob/speaker,var/text) + if(stance != COMMANDED_HEAL || stance != COMMANDED_HEALING) //dont want attack to bleed into heal. + allowed_targets = list() + target_mob = null + if(findtext(text,"heal")) //heal shit pls + if(findtext(text,"me")) //assumed want heals on master. + target_mob = speaker + stance = COMMANDED_HEAL + return 1 + var/list/targets = get_targets_by_name(text) + if(targets.len > 1 || !targets.len) + src.say("ERROR. TARGET COULD NOT BE PARSED.") + return 0 + target_mob = targets[1] + stance = COMMANDED_HEAL + return 1 + if(findtext(text,"emergency protocol")) + if(findtext(text,"deactivate")) + if(emergency_protocols) + src.say("EMERGENCY PROTOCOLS DEACTIVATED.") + emergency_protocols = 0 + return 1 + if(findtext(text,"activate")) + if(!emergency_protocols) + src.say("EMERGENCY PROTOCOLS ACTIVATED.") + emergency_protocols = 1 + return 1 + if(findtext(text,"check")) + src.say("EMERGENCY PROTOCOLS [emergency_protocols ? "ACTIVATED" : "DEACTIVATED"].") + return 1 + return 0 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/creature.dm b/code/modules/mob/living/simple_animal/hostile/creature.dm new file mode 100644 index 00000000..f8cb2737 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/creature.dm @@ -0,0 +1,28 @@ +/mob/living/simple_animal/hostile/creature + name = "creature" + desc = "A sanity-destroying otherthing." + icon = 'icons/mob/critter.dmi' + speak_emote = list("gibbers") + icon_state = "otherthing" + icon_living = "otherthing" + icon_dead = "otherthing-dead" + health = 100 + maxHealth = 100 + melee_damage_lower = 15 + melee_damage_upper = 25 + attacktext = "chomped" + attack_sound = 'sound/weapons/bite.ogg' + faction = "creature" + speed = 4 + +/mob/living/simple_animal/hostile/creature/cult + faction = "cult" + + min_gas = null + max_gas = null + minbodytemp = 0 + + supernatural = 1 + +/mob/living/simple_animal/hostile/creature/cult/cultify() + return diff --git a/code/modules/mob/living/simple_animal/hostile/faithful_hound.dm b/code/modules/mob/living/simple_animal/hostile/faithful_hound.dm new file mode 100644 index 00000000..75e1dce6 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/faithful_hound.dm @@ -0,0 +1,68 @@ +/mob/living/simple_animal/faithful_hound + name = "spectral hound" + desc = "A spooky looking ghost dog. Does not look friendly." + icon = 'icons/mob/mob.dmi' + icon_state = "ghostian" + blend_mode = BLEND_SUBTRACT + health = 100 + maxHealth = 100 + melee_damage_lower = 15 + melee_damage_upper = 30 + attacktext = "bites" + attack_sound = 'sound/weapons/bite.ogg' + faction = "neutral" + density = 0 + stop_automated_movement = 1 + wander = 0 + anchored = 1 + var/password + var/list/allowed_mobs = list() //Who we allow past us + var/last_check = 0 + faction = "cute ghost dogs" + +/mob/living/simple_animal/faithful_hound/death() + new /obj/item/weapon/ectoplasm (get_turf(src)) + ..(null, "disappears!") + qdel(src) + +/mob/living/simple_animal/faithful_hound/Destroy() + allowed_mobs.Cut() + return ..() + +/mob/living/simple_animal/faithful_hound/Life() + . = ..() + if(. && !client && world.time > last_check) + last_check = world.time + 5 SECONDS + var/aggressiveness = 0 //The closer somebody is to us, the more aggressive we are + var/list/mobs = list() + var/list/objs = list() + get_mobs_and_objs_in_view_fast(get_turf(src),5, mobs, objs, 0) + for(var/mob/living/m in mobs) + if((m == src) || (m in allowed_mobs) || m.faction == faction) + continue + var/new_aggress = 1 + var/mob/living/M = m + var/dist = get_dist(M, src) + if(dist < 2) //Attack! Attack! + M.attack_generic(src,10,"bitten") + return . + else if(dist == 2) + new_aggress = 3 + else if(dist == 3) + new_aggress = 2 + else + new_aggress = 1 + aggressiveness = max(aggressiveness, new_aggress) + switch(aggressiveness) + if(1) + src.audible_message("\The [src] growls.") + if(2) + src.audible_message("\The [src] barks threateningly!") + if(3) + src.visible_message("\The [src] snaps at the air!") + +/mob/living/simple_animal/faithful_hound/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) + if(password && findtext(message,password)) + allowed_mobs |= speaker + spawn(10) + src.visible_message("\The [src] nods in understanding towards \the [speaker].") \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/faithless.dm b/code/modules/mob/living/simple_animal/hostile/faithless.dm new file mode 100644 index 00000000..d9524556 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/faithless.dm @@ -0,0 +1,49 @@ +/mob/living/simple_animal/hostile/faithless + name = "Faithless" + desc = "The Wish Granter's faith in humanity, incarnate" + icon_state = "faithless" + icon_living = "faithless" + icon_dead = "faithless_dead" + speak_chance = 0 + turns_per_move = 5 + response_help = "passes through" + response_disarm = "shoves" + response_harm = "hits" + speed = -1 + maxHealth = 80 + health = 80 + + harm_intent_damage = 10 + melee_damage_lower = 15 + melee_damage_upper = 15 + attacktext = "gripped" + attack_sound = 'sound/hallucinations/growl1.ogg' + + min_gas = null + max_gas = null + minbodytemp = 0 + speed = 4 + + faction = "faithless" + +/mob/living/simple_animal/hostile/faithless/Allow_Spacemove(var/check_drift = 0) + return 1 + +/mob/living/simple_animal/hostile/faithless/FindTarget() + . = ..() + if(.) + audible_emote("wails at [.]") + +/mob/living/simple_animal/hostile/faithless/AttackingTarget() + . =..() + var/mob/living/L = . + if(istype(L)) + if(prob(12)) + L.Weaken(3) + L.visible_message("\the [src] knocks down \the [L]!") + +/mob/living/simple_animal/hostile/faithless/cult + faction = "cult" + +/mob/living/simple_animal/hostile/faithless/cult/cultify() + return diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm new file mode 100644 index 00000000..fa396942 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm @@ -0,0 +1,216 @@ + +#define SPINNING_WEB 1 +#define LAYING_EGGS 2 +#define MOVING_TO_TARGET 3 +#define SPINNING_COCOON 4 + +//basic spider mob, these generally guard nests +/mob/living/simple_animal/hostile/giant_spider + name = "giant spider" + desc = "Furry and brown, it makes you shudder to look at it. This one has deep red eyes." + icon_state = "guard" + icon_living = "guard" + icon_dead = "guard_dead" + speak_emote = list("chitters") + emote_hear = list("chitters") + speak_chance = 5 + turns_per_move = 5 + see_in_dark = 10 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/xenomeat + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "pokes" + stop_automated_movement_when_pulled = 0 + maxHealth = 200 + health = 200 + melee_damage_lower = 15 + melee_damage_upper = 20 + heat_damage_per_tick = 20 + cold_damage_per_tick = 20 + var/poison_per_bite = 5 + var/poison_type = /datum/reagent/toxin + faction = "spiders" + var/busy = 0 + pass_flags = PASS_FLAG_TABLE + move_to_delay = 6 + speed = 3 + +//nursemaids - these create webs and eggs +/mob/living/simple_animal/hostile/giant_spider/nurse + desc = "Furry and beige, it makes you shudder to look at it. This one has brilliant green eyes." + icon_state = "nurse" + icon_living = "nurse" + icon_dead = "nurse_dead" + maxHealth = 40 + health = 40 + melee_damage_lower = 5 + melee_damage_upper = 10 + poison_per_bite = 10 + var/atom/cocoon_target + poison_type = /datum/reagent/soporific + var/fed = 0 + +//hunters have the most poison and move the fastest, so they can find prey +/mob/living/simple_animal/hostile/giant_spider/hunter + desc = "Furry and black, it makes you shudder to look at it. This one has sparkling purple eyes." + icon_state = "hunter" + icon_living = "hunter" + icon_dead = "hunter_dead" + maxHealth = 120 + health = 120 + melee_damage_lower = 10 + melee_damage_upper = 20 + poison_per_bite = 5 + move_to_delay = 4 + +/mob/living/simple_animal/hostile/giant_spider/New(var/location, var/atom/parent) + get_light_and_color(parent) + ..() + +/mob/living/simple_animal/hostile/giant_spider/AttackingTarget() + . = ..() + if(isliving(.)) + var/mob/living/L = . + if(L.reagents) + L.reagents.add_reagent(/datum/reagent/toxin, poison_per_bite) + if(prob(poison_per_bite)) + to_chat(L, "You feel a tiny prick.") + L.reagents.add_reagent(poison_type, 5) + +/mob/living/simple_animal/hostile/giant_spider/nurse/AttackingTarget() + . = ..() + if(ishuman(.)) + var/mob/living/carbon/human/H = . + if(prob(poison_per_bite)) + var/obj/item/organ/external/O = pick(H.organs) + if(!(O.robotic >= ORGAN_ROBOT)) + var/eggs = new /obj/effect/spider/eggcluster(O, src) + O.implants += eggs + +/mob/living/simple_animal/hostile/giant_spider/Life() + ..() + if(!stat) + if(stance == HOSTILE_STANCE_IDLE) + //1% chance to skitter madly away + if(!busy && prob(1)) + /*var/list/move_targets = list() + for(var/turf/T in orange(20, src)) + move_targets.Add(T)*/ + stop_automated_movement = 1 + walk_to(src, pick(orange(20, src)), 1, move_to_delay) + spawn(50) + stop_automated_movement = 0 + walk(src,0) + +/mob/living/simple_animal/hostile/giant_spider/nurse/proc/GiveUp(var/C) + spawn(100) + if(busy == MOVING_TO_TARGET) + if(cocoon_target == C && get_dist(src,cocoon_target) > 1) + cocoon_target = null + busy = 0 + stop_automated_movement = 0 + +/mob/living/simple_animal/hostile/giant_spider/nurse/Life() + ..() + if(!stat) + if(stance == HOSTILE_STANCE_IDLE) + var/list/can_see = view(src, 10) + //30% chance to stop wandering and do something + if(!busy && prob(30)) + //first, check for potential food nearby to cocoon + for(var/mob/living/C in can_see) + if(C.stat) + cocoon_target = C + busy = MOVING_TO_TARGET + walk_to(src, C, 1, move_to_delay) + //give up if we can't reach them after 10 seconds + GiveUp(C) + return + + //second, spin a sticky spiderweb on this tile + var/obj/effect/spider/stickyweb/W = locate() in get_turf(src) + if(!W) + busy = SPINNING_WEB + src.visible_message("\The [src] begins to secrete a sticky substance.") + stop_automated_movement = 1 + spawn(40) + if(busy == SPINNING_WEB) + new /obj/effect/spider/stickyweb(src.loc) + busy = 0 + stop_automated_movement = 0 + else + //third, lay an egg cluster there + var/obj/effect/spider/eggcluster/E = locate() in get_turf(src) + if(!E && fed > 0) + busy = LAYING_EGGS + src.visible_message("\The [src] begins to lay a cluster of eggs.") + stop_automated_movement = 1 + spawn(50) + if(busy == LAYING_EGGS) + E = locate() in get_turf(src) + if(!E) + new /obj/effect/spider/eggcluster(loc, src) + fed-- + busy = 0 + stop_automated_movement = 0 + else + //fourthly, cocoon any nearby items so those pesky pinkskins can't use them + for(var/obj/O in can_see) + + if(O.anchored) + continue + + if(istype(O, /obj/item) || istype(O, /obj/structure) || istype(O, /obj/machinery)) + cocoon_target = O + busy = MOVING_TO_TARGET + stop_automated_movement = 1 + walk_to(src, O, 1, move_to_delay) + //give up if we can't reach them after 10 seconds + GiveUp(O) + + else if(busy == MOVING_TO_TARGET && cocoon_target) + if(get_dist(src, cocoon_target) <= 1) + busy = SPINNING_COCOON + src.visible_message("\The [src] begins to secrete a sticky substance around \the [cocoon_target].") + stop_automated_movement = 1 + walk(src,0) + spawn(50) + if(busy == SPINNING_COCOON) + if(cocoon_target && istype(cocoon_target.loc, /turf) && get_dist(src,cocoon_target) <= 1) + var/obj/effect/spider/cocoon/C = new(cocoon_target.loc) + var/large_cocoon = 0 + C.pixel_x = cocoon_target.pixel_x + C.pixel_y = cocoon_target.pixel_y + for(var/mob/living/M in C.loc) + if(istype(M, /mob/living/simple_animal/hostile/giant_spider)) + continue + large_cocoon = 1 + fed++ + src.visible_message("\The [src] sticks a proboscis into \the [cocoon_target] and sucks a viscous substance out.") + M.loc = C + C.pixel_x = M.pixel_x + C.pixel_y = M.pixel_y + break + for(var/obj/item/I in C.loc) + I.loc = C + for(var/obj/structure/S in C.loc) + if(!S.anchored) + S.loc = C + large_cocoon = 1 + for(var/obj/machinery/M in C.loc) + if(!M.anchored) + M.loc = C + large_cocoon = 1 + if(large_cocoon) + C.icon_state = pick("cocoon_large1","cocoon_large2","cocoon_large3") + busy = 0 + stop_automated_movement = 0 + + else + busy = 0 + stop_automated_movement = 0 + +#undef SPINNING_WEB +#undef LAYING_EGGS +#undef MOVING_TO_TARGET +#undef SPINNING_COCOON diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm new file mode 100644 index 00000000..ecaca419 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/hivebot.dm @@ -0,0 +1,102 @@ +/obj/item/projectile/hivebotbullet + damage = 10 + damage_type = BRUTE + +/mob/living/simple_animal/hostile/hivebot + name = "Hivebot" + desc = "A small robot" + icon = 'icons/mob/hivebot.dmi' + icon_state = "basic" + icon_living = "basic" + icon_dead = "basic" + health = 15 + maxHealth = 15 + melee_damage_lower = 2 + melee_damage_upper = 3 + attacktext = "clawed" + projectilesound = 'sound/weapons/gunshot/gunshot_pistol.ogg' + projectiletype = /obj/item/projectile/hivebotbullet + faction = "hivebot" + min_gas = null + max_gas = null + minbodytemp = 0 + speed = 4 + +/mob/living/simple_animal/hostile/hivebot/range + name = "Hivebot" + desc = "A smallish robot, this one is armed!" + ranged = 1 + +/mob/living/simple_animal/hostile/hivebot/rapid + ranged = 1 + rapid = 1 + +/mob/living/simple_animal/hostile/hivebot/strong + name = "Strong Hivebot" + desc = "A robot, this one is armed and looks tough!" + health = 80 + ranged = 1 + + +/mob/living/simple_animal/hostile/hivebot/death() + ..(null, "blows apart!") + new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + qdel(src) + return + +/mob/living/simple_animal/hostile/hivebot/tele + name = "Beacon" + desc = "Some odd beacon thing" + icon = 'icons/mob/hivebot.dmi' + icon_state = "def_radar-off" + icon_living = "def_radar-off" + health = 200 + maxHealth = 200 + status_flags = 0 + anchored = 1 + stop_automated_movement = 1 + var/bot_type = /mob/living/simple_animal/hostile/hivebot + var/bot_amt = 10 + var/spawn_delay = 100 + var/spawn_time = 0 + +/mob/living/simple_animal/hostile/hivebot/tele/New() + ..() + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() + smoke.set_up(5, 0, src.loc) + smoke.start() + visible_message("\The [src] warps in!") + playsound(src.loc, 'sound/effects/EMPulse.ogg', 25, 1) + +/mob/living/simple_animal/hostile/hivebot/tele/proc/warpbots() + while(bot_amt > 0 && bot_type) + bot_amt-- + var/mob/M = new bot_type(get_turf(src)) + M.faction = faction + playsound(src.loc, 'sound/effects/teleport.ogg', 50, 1) + qdel(src) + return + +/mob/living/simple_animal/hostile/hivebot/tele/FindTarget() + if(..() && !spawn_time) + spawn_time = world.time + spawn_delay + visible_message("\The [src] turns on!") + icon_state = "def_radar" + return null + +/mob/living/simple_animal/hostile/hivebot/tele/Life() + . = ..() + if(. && spawn_time && spawn_time <= world.time) + warpbots() + +/mob/living/simple_animal/hostile/hivebot/tele/strong + bot_type = /mob/living/simple_animal/hostile/hivebot/strong + +/mob/living/simple_animal/hostile/hivebot/tele/range + bot_type = /mob/living/simple_animal/hostile/hivebot/range + +/mob/living/simple_animal/hostile/hivebot/tele/rapid + bot_type = /mob/living/simple_animal/hostile/hivebot/rapid \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm new file mode 100644 index 00000000..fdece88d --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -0,0 +1,240 @@ +/mob/living/simple_animal/hostile + faction = "hostile" + var/stance = HOSTILE_STANCE_IDLE //Used to determine behavior + var/mob/living/target_mob + var/attack_same = 0 + var/ranged = 0 + var/rapid = 0 + var/projectiletype + var/projectilesound + var/casingtype + var/move_to_delay = 4 //delay for the automated movement. + var/attack_delay = DEFAULT_ATTACK_COOLDOWN + var/list/friends = list() + var/break_stuff_probability = 10 + stop_automated_movement_when_pulled = 0 + var/destroy_surroundings = 1 + a_intent = I_HURT + + var/shuttletarget = null + var/enroute = 0 + + var/damtype = BRUTE + var/defense = "melee" //what armor protects against its attacks + +/mob/living/simple_animal/hostile/proc/FindTarget() + if(!faction) //No faction, no reason to attack anybody. + return null + var/atom/T = null + stop_automated_movement = 0 + for(var/atom/A in ListTargets(10)) + + if(A == src) + continue + + var/atom/F = Found(A) + if(F) + T = F + break + + if(isliving(A)) + var/mob/living/L = A + if(L.faction == src.faction && !attack_same) + continue + else if(weakref(L) in friends) + continue + else + if(!L.stat) + if (ishuman(L)) + var/mob/living/carbon/human/H = L + if (H.is_cloaked()) + continue + stance = HOSTILE_STANCE_ATTACK + T = L + break + + else if(istype(A, /obj/mecha)) // Our line of sight stuff was already done in ListTargets(). + var/obj/mecha/M = A + if (M.occupant) + stance = HOSTILE_STANCE_ATTACK + T = M + break + return T + + +/mob/living/simple_animal/hostile/proc/Found(var/atom/A) + return + +/mob/living/simple_animal/hostile/proc/MoveToTarget() + stop_automated_movement = 1 + if(!target_mob || SA_attackable(target_mob)) + stance = HOSTILE_STANCE_IDLE + if(target_mob in ListTargets(10)) + if(ranged) + if(get_dist(src, target_mob) <= 6) + OpenFire(target_mob) + else + walk_to(src, target_mob, 1, move_to_delay) + else + stance = HOSTILE_STANCE_ATTACKING + walk_to(src, target_mob, 1, move_to_delay) + +/mob/living/simple_animal/hostile/proc/AttackTarget() + stop_automated_movement = 1 + if(!target_mob || SA_attackable(target_mob)) + LoseTarget() + return 0 + if(!(target_mob in ListTargets(10))) + LostTarget() + return 0 + if (ishuman(target_mob)) + var/mob/living/carbon/human/H = target_mob + if (H.is_cloaked()) + LoseTarget() + return 0 + if(next_move >= world.time) + return 0 + if(get_dist(src, target_mob) <= 1) //Attacking + AttackingTarget() + return 1 + +/mob/living/simple_animal/hostile/proc/AttackingTarget() + setClickCooldown(attack_delay) + if(!Adjacent(target_mob)) + return + playsound(loc, attack_sound, 50, 1, 1) + if(isliving(target_mob)) + var/mob/living/L = target_mob + L.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext,damtype,defense) + return L + if(istype(target_mob,/obj/mecha)) + var/obj/mecha/M = target_mob + M.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) + return M + +/mob/living/simple_animal/hostile/proc/LoseTarget() + stance = HOSTILE_STANCE_IDLE + target_mob = null + walk(src, 0) + +/mob/living/simple_animal/hostile/proc/LostTarget() + stance = HOSTILE_STANCE_IDLE + walk(src, 0) + + +/mob/living/simple_animal/hostile/proc/ListTargets(var/dist = 7) + var/list/L = hearers(src, dist) + + for (var/obj/mecha/M in mechas_list) + if (M.z == src.z && get_dist(src, M) <= dist) + L += M + + return L + +/mob/living/simple_animal/hostile/death(gibbed, deathmessage, show_dead_message) + ..(gibbed, deathmessage, show_dead_message) + walk(src, 0) + +/mob/living/simple_animal/hostile/Life() + + . = ..() + if(!.) + walk(src, 0) + return 0 + if(client) + return 0 + if(isturf(src.loc) && !src.buckled) + if(!stat) + switch(stance) + if(HOSTILE_STANCE_IDLE) + target_mob = FindTarget() + + if(HOSTILE_STANCE_ATTACK) + if(destroy_surroundings) + DestroySurroundings() + MoveToTarget() + + if(HOSTILE_STANCE_ATTACKING) + if(destroy_surroundings) + DestroySurroundings() + AttackTarget() + if(HOSTILE_STANCE_INSIDE) //we aren't inside something so just switch + stance = HOSTILE_STANCE_IDLE + else + if(stance != HOSTILE_STANCE_INSIDE) + stance = HOSTILE_STANCE_INSIDE + walk(src,0) + target_mob = null + + +/mob/living/simple_animal/hostile/attackby(var/obj/item/O, var/mob/user) + var/oldhealth = health + . = ..() + if(health < oldhealth && !incapacitated(INCAPACITATION_KNOCKOUT)) + target_mob = user + MoveToTarget() + +/mob/living/simple_animal/hostile/attack_hand(mob/living/carbon/human/M) + . = ..() + if(M.a_intent == I_HURT && !incapacitated(INCAPACITATION_KNOCKOUT)) + target_mob = M + MoveToTarget() + +/mob/living/simple_animal/hostile/bullet_act(var/obj/item/projectile/Proj) + var/oldhealth = health + . = ..() + if(!target_mob && health < oldhealth && !incapacitated(INCAPACITATION_KNOCKOUT)) + target_mob = Proj.firer + MoveToTarget() + +/mob/living/simple_animal/hostile/proc/OpenFire(target_mob) + var/target = target_mob + visible_message("\The [src] fires at \the [target]!", 1) + + if(rapid) + spawn(1) + Shoot(target, src.loc, src) + if(casingtype) + new casingtype(get_turf(src)) + spawn(4) + Shoot(target, src.loc, src) + if(casingtype) + new casingtype(get_turf(src)) + spawn(6) + Shoot(target, src.loc, src) + if(casingtype) + new casingtype(get_turf(src)) + else + Shoot(target, src.loc, src) + if(casingtype) + new casingtype + + stance = HOSTILE_STANCE_IDLE + target_mob = null + return + + +/mob/living/simple_animal/hostile/proc/Shoot(var/target, var/start, var/user, var/bullet = 0) + if(target == start) + return + + var/obj/item/projectile/A = new projectiletype(user:loc) + playsound(user, projectilesound, 100, 1) + if(!A) return + var/def_zone = get_exposed_defense_zone(target) + A.launch_projectile(target, def_zone) + +/mob/living/simple_animal/hostile/proc/DestroySurroundings() + if(prob(break_stuff_probability)) + for(var/dir in GLOB.cardinal) // North, South, East, West + var/obj/effect/shield/S = locate(/obj/effect/shield, get_step(src, dir)) + if(S && S.gen && S.gen.check_flag(MODEFLAG_NONHUMANS)) + S.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) + return + for(var/obj/structure/window/obstacle in get_step(src, dir)) + if(obstacle.dir == GLOB.reverse_dir[dir]) // So that windows get smashed in the right order + obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) + return + var/obj/structure/obstacle = locate(/obj/structure, get_step(src, dir)) + if(istype(obstacle, /obj/structure/window) || istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table) || istype(obstacle, /obj/structure/grille)) + obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm new file mode 100644 index 00000000..9997fb17 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm @@ -0,0 +1,156 @@ +// +// Abstract Class +// + +var/global/list/protected_objects = list(/obj/structure/table, /obj/structure/cable, /obj/structure/window, /obj/item/projectile/animate) + +/mob/living/simple_animal/hostile/mimic + name = "crate" + desc = "A rectangular steel crate." + icon = 'icons/obj/storage.dmi' + icon_state = "crate" + icon_living = "crate" + + meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat + response_help = "touches" + response_disarm = "pushes" + response_harm = "hits" + speed = 4 + maxHealth = 100 + health = 100 + + harm_intent_damage = 5 + melee_damage_lower = 8 + melee_damage_upper = 12 + attacktext = "attacked" + attack_sound = 'sound/weapons/bite.ogg' + + min_gas = null + max_gas = null + minbodytemp = 0 + + faction = "mimic" + move_to_delay = 8 + + var/weakref/copy_of + var/weakref/creator // the creator + var/destroy_objects = 0 + var/knockdown_people = 0 + +/mob/living/simple_animal/hostile/mimic/New(newloc, var/obj/o, var/mob/living/creator) + ..() + if(o) + if(ispath(o)) + o = new o(newloc) + CopyObject(o,creator) + +/mob/living/simple_animal/hostile/mimic/FindTarget() + . = ..() + if(.) + audible_emote("growls at [.]") + +/mob/living/simple_animal/hostile/mimic/ListTargets() + // Return a list of targets that isn't the creator + . = ..() + if(creator) + return . - creator.resolve() + +/mob/living/simple_animal/hostile/mimic/proc/CopyObject(var/obj/O, var/mob/living/creator) + + if((istype(O, /obj/item) || istype(O, /obj/structure)) && !is_type_in_list(O, protected_objects)) + O.forceMove(src) + copy_of = weakref(O) + appearance = O + icon_living = icon_state + + if(istype(O, /obj/structure)) + health = (anchored * 50) + 50 + destroy_objects = 1 + if(O.density && O.anchored) + knockdown_people = 1 + melee_damage_lower *= 2 + melee_damage_upper *= 2 + else if(istype(O, /obj/item)) + var/obj/item/I = O + health = 15 * I.w_class + melee_damage_lower = 2 + I.force + melee_damage_upper = 2 + I.force + move_to_delay = 2 * I.w_class + + maxHealth = health + if(creator) + src.creator = weakref(creator) + faction = "\ref[creator]" // very unique + return 1 + return + +/mob/living/simple_animal/hostile/mimic/death() + if(!copy_of) + return + var/atom/movable/C = copy_of.resolve() + ..(null, "dies!") + if(C) + C.forceMove(src.loc) + + if(istype(C,/obj/structure/closet)) + for(var/atom/movable/M in src) + M.forceMove(C) + + if(istype(C,/obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = C + for(var/atom/movable/M in src) + if(S.can_be_inserted(M,null,1)) + S.handle_item_insertion(M) + else + M.forceMove(src.loc) + + for(var/atom/movable/M in src) + M.forceMove(get_turf(src)) + qdel(src) + + +/mob/living/simple_animal/hostile/mimic/DestroySurroundings() + if(destroy_objects) + ..() + +/mob/living/simple_animal/hostile/mimic/AttackingTarget() + . =..() + if(knockdown_people) + var/mob/living/L = . + if(istype(L)) + if(prob(15)) + L.Weaken(1) + L.visible_message("\the [src] knocks down \the [L]!") + +/mob/living/simple_animal/hostile/mimic/Destroy() + copy_of = null + creator = null + ..() + +/mob/living/simple_animal/hostile/mimic/sleeping + wander = 0 + stop_automated_movement = 1 + + var/awake = 0 + +/mob/living/simple_animal/hostile/mimic/sleeping/ListTargets() + if(!awake) + return null + return ..() + +/mob/living/simple_animal/hostile/mimic/sleeping/proc/trigger() + if(!awake) + src.visible_message("\The [src] starts to move!") + awake = 1 + +/mob/living/simple_animal/hostile/mimic/sleeping/adjustBruteLoss(var/damage) + trigger() + ..(damage) + +/mob/living/simple_animal/hostile/mimic/sleeping/attack_hand() + trigger() + ..() + +/mob/living/simple_animal/hostile/mimic/sleeping/DestroySurroundings() + if(awake) + ..() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/mining.dm b/code/modules/mob/living/simple_animal/hostile/mining.dm new file mode 100644 index 00000000..5abd5f9c --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/mining.dm @@ -0,0 +1,356 @@ +/mob/living/simple_animal/hostile/mining_borg + name = "rogue mining drone" + desc = "Leftover from hundreds of years ago. Quite dangerous." + icon_state = "droid" + icon_living = "droid" + icon_dead = "droid_dead" + speak = list("DESTROY!","THREAT DETECTED!","BZZZZT!","EXTERMINATE!") + speak_emote = list("beeps", "buzzes") + emote_hear = list("beeps","grumbles","buzzes") + emote_see = list("stares aggresively") + speak_chance = 1 + turns_per_move = 5 + see_in_dark = 6 + response_help = "touches" + response_disarm = "shoves aside" + response_harm = "smacks" + stop_automated_movement_when_pulled = FALSE + maxHealth = 200 + health = 200 + melee_damage_lower = 10 + melee_damage_upper = 25 + attack_sound = 'sound/weapons/circsawhit.ogg' + attacked_sound = "sparks" + speed = 1 + dodge_chance = 0 //They're big and bulky, they cannot dodge. + bloody = FALSE //No bleeding robots please. + delete_after_harvest = FALSE //Also don't delete them after you harvest them. + meat_type = /obj/item/weapon/circuitboard + + var/alert_icon = null + var/list/alert_callout = list() + + + //mining borgs aren't affected by atmos. + min_gas = null + max_gas = null + minbodytemp = 0 + var/stance_step = 0 + + faction = "mining" + + + +/mob/living/simple_animal/hostile/mining_borg/sleekminer + icon_state = "sleekminer" + icon_living = "sleekminer" + icon_dead = "sleekminer_dead" + +/mob/living/simple_animal/hostile/mining_borg/sleekengineer + icon_state = "sleekengineer" + icon_living = "sleekengineer" + icon_dead = "sleekengineer_dead" + +/mob/living/simple_animal/hostile/mining_borg/sleek + icon_state = "sleek" + icon_living = "sleek" + icon_dead = "sleek_dead" + +/mob/living/simple_animal/hostile/mining_borg/thothbot + icon_state = "thothbot" + icon_living = "thothbot" + icon_dead = "thothbot_dead" + + +/mob/living/simple_animal/hostile/mining_borg/buff + icon_state = "buff_scan" + icon_living = "buff_scan" + icon_dead = "buff_DEAD" + icon_gib = "buff_GIB" + alert_icon = "buff_alert" + +/mob/living/simple_animal/hostile/mining_borg/thin + icon_state = "thin_droid" + icon_living = "thin_droid" + icon_dead = "thin_DEAD" + icon_gib = "thin_GIB" + alert_icon = "thin_droidA" + projectiletype = /obj/item/projectile/energy/laser + projectilesound = 'sound/weapons/Laser.ogg' + ranged = TRUE + rapid = TRUE + +/mob/living/simple_animal/hostile/mining_borg/behemoth + name = "Rogue Securitron" + desc = "Once employed by... some sort of corporation, these securitrons have been left to rot here for " + icon_state = "behemoth" + icon_living = "behemoth" + icon_dead = "behemoth_DEAD" + maxHealth = 300 + health = 300 + projectiletype = /obj/item/projectile/energy/laser/powerful //He shoots a big fuck you laser. + projectilesound = 'sound/weapons/Laser.ogg' + ranged = TRUE + alert_callout = list('sound/voice/critters/borg_spot1.ogg', 'sound/voice/critters/borg_spot2.ogg') + pain_sound = list('sound/voice/critters/borg_pain1.ogg', 'sound/voice/critters/borg_pain2.ogg', 'sound/voice/critters/borg_pain3.ogg') + + +/mob/living/simple_animal/hostile/mining_borg/Life() + . =..() + if(!.) + return + + switch(stance) + if(HOSTILE_STANCE_TIRED) + icon_living = initial(icon_living) + stop_automated_movement = 1 + stance_step++ + if(stance_step >= 10) //rests for 10 ticks + if(target_mob && target_mob in ListTargets(10)) + stance = HOSTILE_STANCE_ATTACK //If the mob he was chasing is still nearby, resume the attack, otherwise go idle. + else + stance = HOSTILE_STANCE_IDLE + icon_living = initial(icon_living)//Reset alert phase. + + if(HOSTILE_STANCE_ALERT) + stop_automated_movement = 1 + var/found_mob = 0 + if(target_mob && target_mob in ListTargets(10)) + if(!(SA_attackable(target_mob))) + stance_step = max(0, stance_step) //If we have not seen a mob in a while, the stance_step will be negative, we need to reset it to 0 as soon as we see a mob again. + stance_step++ + found_mob = 1 + src.set_dir(get_dir(src,target_mob)) //Keep staring at the mob + if(alert_icon) + icon_state = alert_icon + icon_living = alert_icon + + if(stance_step in list(1,4,7)) //every 3 ticks + var/action = pick( list( "beeps aggressively at [target_mob]", "stares angrily at [target_mob]")) + var/alert_sound = "sound/voice/bot_life[rand(1,3)].ogg" + if(alert_callout.len) + alert_sound = pick(alert_callout) + else + custom_emote(1,action) + playsound(src, alert_sound, 100, FALSE) + if(!found_mob) + stance_step-- + + if(stance_step <= -20) //If we have not found a mob for 20-ish ticks, revert to idle mode + stance = HOSTILE_STANCE_IDLE + icon_living = initial(icon_living)//Reset alert phase. + if(stance_step >= 4) //If we have been staring at a mob for 4 ticks, + stance = HOSTILE_STANCE_ATTACK + + if(HOSTILE_STANCE_ATTACKING) + icon_living = initial(icon_living) + if(stance_step >= 20) //attacks for 20 ticks, then it gets tired and needs to rest + custom_emote(1, "needs to recoup." ) + stance = HOSTILE_STANCE_TIRED + stance_step = 0 + walk(src, 0) + return + + + +/mob/living/simple_animal/hostile/mining_borg/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING) + stance = HOSTILE_STANCE_ALERT + stance_step = 6 + target_mob = user + ..() + +/mob/living/simple_animal/hostile/mining_borg/attack_hand(mob/living/carbon/human/M as mob) + if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING) + stance = HOSTILE_STANCE_ALERT + stance_step = 6 + target_mob = M + ..() + +/mob/living/simple_animal/hostile/mining_borg/Move() + . = ..() + if(.) + if(!stat) + playsound(src,"sound/machines/borg_move[pick(1,2)].ogg",40,1) + +/mob/living/simple_animal/hostile/mining_borg/FindTarget() + . = ..() + if(.) + custom_emote(1,"beeps alertly [.]") + say("ENGAGING HOSTILE!") + playsound(src, "sound/voice/bot_life[rand(1,3)].ogg") + stance = HOSTILE_STANCE_ALERT + +/mob/living/simple_animal/hostile/mining_borg/LoseTarget() + ..(5) + + +/mob/living/simple_animal/hostile/mining_borg/death() + ..(null,"breaks down and stops moving.", "You have been destroyed.") + //some random debris left behind + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + var/obj/O + + //shards + O = new /obj/item/weapon/material/shard(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(75)) + O = new /obj/item/weapon/material/shard(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(50)) + O = new /obj/item/weapon/material/shard(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(25)) + O = new /obj/item/weapon/material/shard(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + + //rods + O = new /obj/item/stack/rods(loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(75)) + O = new /obj/item/stack/rods(loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(50)) + O = new /obj/item/stack/rods(loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(25)) + O = new /obj/item/stack/rods(loc) + step_to(O, get_turf(pick(view(7, src)))) + + //plasteel + O = new /obj/item/stack/material/plasteel(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(75)) + O = new /obj/item/stack/material/plasteel(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(50)) + O = new /obj/item/stack/material/plasteel(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(25)) + O = new /obj/item/stack/material/plasteel(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + + + +/mob/living/simple_animal/hostile/mining_borg/harvest(var/mob/user) + if(butchered) + return + + //also drop dummy circuit boards deconstructable for research (loot) + var/obj/item/weapon/circuitboard/C + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + playsound(src, "sparks", 100) + + //spawn 1-4 boards of a random type + var/spawnees = 0 + var/num_boards = rand(1,4) + var/list/options = list(1,2,4,8,16,32,64,128,256,512) + for(var/i=0, i\icon[src] [src] retracts several targetting vanes, and dulls it's running lights.
            ") + hostile_drone = 0 + else + src.visible_message("\icon[src] [src] suddenly lights up, and additional targetting vanes slide into place.") + hostile_drone = 1 + +/mob/living/simple_animal/hostile/retaliate/malf_drone/ListTargets() + if(hostile_drone) + return view(src, 10) + else + return ..() + +//self repair systems have a chance to bring the drone back to life +/mob/living/simple_animal/hostile/retaliate/malf_drone/Life() + + //emps and lots of damage can temporarily shut us down + if(disabled > 0) + set_stat(UNCONSCIOUS) + icon_state = "[initial(icon_state)]_dead" + disabled-- + wander = 0 + speak_chance = 0 + if(disabled <= 0) + set_stat(CONSCIOUS) + icon_state = "[initial(icon_state)]0" + wander = 1 + speak_chance = 5 + + //repair a bit of damage + if(prob(1)) + src.visible_message("\icon[src] [src] shudders and shakes as some of it's damaged systems come back online.") + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + health += rand(25,100) + + //spark for no reason + if(prob(5)) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + + //sometimes our targetting sensors malfunction, and we attack anyone nearby + Haywire() + + if(health / maxHealth > 0.9) + icon_state = "[initial(icon_state)]" + explode_chance = 0 + else if(health / maxHealth > 0.7) + icon_state = "[initial(icon_state)]2" + explode_chance = 0 + else if(health / maxHealth > 0.5) + icon_state = "[initial(icon_state)]1" + explode_chance = 0.5 + else if(health / maxHealth > 0.3) + icon_state = "[initial(icon_state)]0" + explode_chance = 5 + else if(health > 0) + //if health gets too low, shut down + icon_state = "[initial(icon_state)]_dead" + exploding = 0 + if(!disabled) + if(prob(50)) + src.visible_message("\icon[src] [src] suddenly shuts down!") + else + src.visible_message("\icon[src] [src] suddenly lies still and quiet.") + disabled = rand(150, 600) + walk(src,0) + + if(exploding && prob(20)) + if(prob(50)) + src.visible_message("\icon[src] [src] begins to spark and shake violenty!") + else + src.visible_message("\icon[src] [src] sparks and shakes like it's about to explode!") + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + + if(!exploding && !disabled && prob(explode_chance)) + exploding = 1 + set_stat(UNCONSCIOUS) + wander = 1 + walk(src,0) + spawn(rand(50,150)) + if(!disabled && exploding) + explosion(get_turf(src), 0, 1, 4, 7) + //proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = 1) + ..() + +//ion rifle! +/mob/living/simple_animal/hostile/retaliate/malf_drone/emp_act(severity) + health -= rand(3,15) * (severity + 1) + disabled = rand(150, 600) + hostile_drone = 0 + walk(src,0) + +/mob/living/simple_animal/hostile/retaliate/malf_drone/death() + ..(null,"suddenly breaks apart.", "You have been destroyed.") + qdel(src) + +/mob/living/simple_animal/hostile/retaliate/malf_drone/Destroy() + //some random debris left behind + if(has_loot) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + var/obj/O + + //shards + O = new /obj/item/weapon/material/shard(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(75)) + O = new /obj/item/weapon/material/shard(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(50)) + O = new /obj/item/weapon/material/shard(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(25)) + O = new /obj/item/weapon/material/shard(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + + //rods + O = new /obj/item/stack/rods(loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(75)) + O = new /obj/item/stack/rods(loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(50)) + O = new /obj/item/stack/rods(loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(25)) + O = new /obj/item/stack/rods(loc) + step_to(O, get_turf(pick(view(7, src)))) + + //plasteel + O = new /obj/item/stack/material/plasteel(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(75)) + O = new /obj/item/stack/material/plasteel(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(50)) + O = new /obj/item/stack/material/plasteel(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(25)) + O = new /obj/item/stack/material/plasteel(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + + //also drop dummy circuit boards deconstructable for research (loot) + var/obj/item/weapon/circuitboard/C + + //spawn 1-4 boards of a random type + var/spawnees = 0 + var/num_boards = rand(1,4) + var/list/options = list(1,2,4,8,16,32,64,128,256,512) + for(var/i=0, i 500) //time to look for some food + for(var/mob/living/L in view(src, dist)) + if(!attack_same && L.faction != faction) + prey |= weakref(L) + +/mob/living/simple_animal/hostile/retaliate/beast/Life() + . = ..() + if(!stat) + hunger++ + if(hunger < 100) //stop hunting when satiated + prey.Cut() + else + for(var/mob/living/simple_animal/S in range(src,1)) + if(S.stat == DEAD) + visible_message("[src] consumes \the body of [S]!") + var/turf/T = get_turf(S) + var/obj/item/remains/xeno/X = new(T) + X.desc += "These look like they belong to \a [S.name]." + hunger = max(0, hunger - 5*S.maxHealth) + if(prob(5)) + S.gib() + else + qdel(S) + +/mob/living/simple_animal/proc/name_species() + set name = "Name Alien Species" + set category = "Exploration" + set src in view() + + if(!GLOB.using_map.use_overmap) + return + if(!CanInteract(usr, GLOB.conscious_state)) + return + + for(var/obj/effect/overmap/sector/exoplanet/E) + if(src in E.animals) + var/newname = input("What do you want to name this species?", "Species naming", E.get_random_species_name()) as text|null + newname = sanitizeName(newname, allow_numbers = TRUE, force_first_letter_uppercase = FALSE) + if(newname && CanInteract(usr, GLOB.conscious_state)) + if(E.rename_species(type, newname)) + to_chat(usr,"This species will be known from now on as '[newname]'.") + else + to_chat(usr,"This species has already been named!") + return + +/mob/living/simple_animal/hostile/retaliate/beast/samak + name = "samak" + desc = "A fast, armoured predator accustomed to hiding and ambushing in cold terrain." + faction = "samak" + icon_state = "samak" + icon_living = "samak" + icon_dead = "samak_dead" + move_to_delay = 2 + maxHealth = 125 + health = 125 + speed = 2 + melee_damage_lower = 5 + melee_damage_upper = 15 + attacktext = "mauled" + cold_damage_per_tick = 0 + speak_chance = 5 + speak = list("Hruuugh!","Hrunnph") + emote_see = list("paws the ground","shakes its mane","stomps") + emote_hear = list("snuffles") + +/mob/living/simple_animal/hostile/retaliate/beast/diyaab + name = "diyaab" + desc = "A small pack animal. Although omnivorous, it will hunt meat on occasion." + faction = "diyaab" + icon_state = "diyaab" + icon_living = "diyaab" + icon_dead = "diyaab_dead" + move_to_delay = 1 + maxHealth = 25 + health = 25 + speed = 1 + melee_damage_lower = 1 + melee_damage_upper = 8 + attacktext = "gouged" + cold_damage_per_tick = 0 + speak_chance = 5 + speak = list("Awrr?","Aowrl!","Worrl") + emote_see = list("sniffs the air cautiously","looks around") + emote_hear = list("snuffles") + +/mob/living/simple_animal/hostile/retaliate/beast/shantak + name = "shantak" + desc = "A piglike creature with a bright iridiscent mane that sparkles as though lit by an inner light. Don't be fooled by its beauty though." + faction = "shantak" + icon_state = "shantak" + icon_living = "shantak" + icon_dead = "shantak_dead" + move_to_delay = 1 + maxHealth = 75 + health = 75 + speed = 1 + melee_damage_lower = 3 + melee_damage_upper = 12 + attacktext = "gouged" + cold_damage_per_tick = 0 + speak_chance = 2 + speak = list("Shuhn","Shrunnph?","Shunpf") + emote_see = list("scratches the ground","shakes out it's mane","tinkles gently") + +/mob/living/simple_animal/yithian + name = "yithian" + desc = "A friendly creature vaguely resembling an oversized snail without a shell." + icon_state = "yithian" + icon_living = "yithian" + icon_dead = "yithian_dead" + +/mob/living/simple_animal/tindalos + name = "tindalos" + desc = "It looks like a large, flightless grasshopper." + icon_state = "tindalos" + icon_living = "tindalos" + icon_dead = "tindalos_dead" + +/mob/living/simple_animal/thinbug + name = "taki" + desc = "It looks like a bunch of legs." + icon_state = "thinbug" + icon_living = "thinbug" + icon_dead = "thinbug_dead" + speak_chance = 1 + emote_hear = list("scratches the ground","chitters") + +/mob/living/simple_animal/hostile/retaliate/jelly + name = "zeq" + desc = "It looks like a jellyfish floating up. How does it do that?" + faction = "zeq" + icon_state = "jelly" + icon_living = "jelly" + icon_dead = "jelly_dead" + move_to_delay = 1 + maxHealth = 75 + health = 75 + speed = 1 + melee_damage_lower = 3 + melee_damage_upper = 12 + attacktext = "stung" + damtype = BURN + speak_chance = 1 + emote_see = list("wobbles slightly","oozes something out of tentacles' ends") + +/mob/living/simple_animal/hostile/jelly/New() + color = color_rotation(round(rand(0,360),20)) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/rat.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/rat.dm new file mode 100644 index 00000000..cd8c961d --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/rat.dm @@ -0,0 +1,63 @@ +/mob/living/simple_animal/hostile/retaliate/rat + name = "Rat" + desc = "They prey at night, they stalk at night, they're a rat." + icon_state = "rat" + icon_living = "rat" + icon_dead = "rat_dead" + icon_gib = "rat_gib" + emote_see = list("squeaks loudly", "cleans its whiskers with its paws") + speak_chance = 5 + turns_per_move = 3 + response_help = "pets the" + response_disarm = "pushes aside" + response_harm = "kicks" + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/rat_meat + meat_amount = 3 + speed = 4 + maxHealth = 10 + health = 10 + + mob_size = MOB_SMALL + density = 0 //So they don't get in the way. + + harm_intent_damage = 3 + melee_damage_lower = 1 + melee_damage_upper = 4 + attacktext = "bitten" + attack_sound = 'sound/voice/rat_attack.ogg' + + faction = "mining" + + +/mob/living/simple_animal/hostile/retaliate/rat/New() + ..() + if(prob(25)) + icon_state = "rat_giant" + icon_living = "rat_giant" + icon_dead = "rat_giant_dead" + desc = "He looks like a giant rat who makes all of the rules." + + +/mob/living/simple_animal/hostile/retaliate/rat/FindTarget() + . = ..() + if(.) + visible_emote("angrily stares at [.]!") + +/mob/living/simple_animal/hostile/retaliate/rat/AttackingTarget() + . =..() + var/mob/living/L = . + if(istype(L)) + if(prob(1)) + L.Weaken(1) + L.visible_message("\the [src] knocks down \the [L]!") + + +/mob/living/simple_animal/hostile/retaliate/rat/Life() + ..() + if(prob(1)) + playsound(src, 'sound/voice/rat_life1.ogg', 30, 1, -3) + var/birthday = rand(1,1000) + if(birthday == 1) + var/mob/living/carbon/human/H = pick(viewers(world.view,src)) + if(H.ckey) + say("[H.name] it's your birthday today! Cake and icecream is on its way!") \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm new file mode 100644 index 00000000..532cb3e4 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm @@ -0,0 +1,52 @@ +/mob/living/simple_animal/hostile/retaliate + var/list/enemies = list() + +/mob/living/simple_animal/hostile/retaliate/Found(var/atom/A) + if(isliving(A)) + var/mob/living/L = A + if(!L.stat) + stance = HOSTILE_STANCE_ATTACK + return L + else + enemies -= weakref(L) + else if(istype(A, /obj/mecha)) + var/obj/mecha/M = A + if(M.occupant) + stance = HOSTILE_STANCE_ATTACK + return A + +/mob/living/simple_animal/hostile/retaliate/ListTargets() + . = list() + if(!enemies.len) + return + var/list/see = ..() + for(var/weakref/W in enemies) // Remove all entries that aren't in enemies + var/mob/M = W.resolve() + if(M in see) + . += M + +/mob/living/simple_animal/hostile/retaliate/proc/Retaliate() + ..() + var/list/around = view(src, 7) + + for(var/atom/movable/A in around) + if(A == src) + continue + if(isliving(A)) + var/mob/living/M = A + if(!attack_same && M.faction != faction) + enemies |= weakref(M) + else if(istype(A, /obj/mecha)) + var/obj/mecha/M = A + if(M.occupant) + enemies |= weakref(M) + enemies |= weakref(M.occupant) + + for(var/mob/living/simple_animal/hostile/retaliate/H in around) + if(!attack_same && !H.attack_same && H.faction == faction) + H.enemies |= enemies + return 0 + +/mob/living/simple_animal/hostile/retaliate/adjustBruteLoss(var/damage) + ..(damage) + Retaliate() diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/roach.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/roach.dm new file mode 100644 index 00000000..ad774766 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/roach.dm @@ -0,0 +1,142 @@ +/mob/living/simple_animal/hostile/retaliate/roach + name = "Dog Roach" + desc = "A monstrous, dog-sized cockroach. These huge mutants can be everywhere where humans are, on ships, planets and stations." + icon_state = "roach" + icon_living = "roach" + icon_dead = "roach_dead" + emote_see = list("chirps loudly", "cleans its whiskers with forelegs") + speak_chance = 5 + turns_per_move = 3 + response_help = "pets the" + response_disarm = "pushes aside" + response_harm = "stamps on" + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/roachmeat + meat_amount = 3 + speed = 4 + maxHealth = 50 + health = 50 + + mob_size = MOB_SMALL + density = 0 //Swarming roaches! They also more robust that way. + + harm_intent_damage = 3 + melee_damage_lower = 1 + melee_damage_upper = 4 + attacktext = "bitten" + attack_sound = 'sound/voice/insect_battle_bite.ogg' + + faction = "roach" + +/mob/living/simple_animal/hostile/retaliate/roach/FindTarget() + . = ..() + if(.) + visible_emote("charges at [.]!") + playsound(src, 'sound/voice/insect_battle_screeching.ogg', 30, 1, -3) + +/mob/living/simple_animal/hostile/retaliate/roach/AttackingTarget() + . =..() + var/mob/living/L = . + if(istype(L)) + if(prob(5)) + L.Weaken(3) + L.visible_message("\the [src] knocks down \the [L]!") + +/mob/living/simple_animal/hostile/retaliate/roach/tank + name = "Tank Roach" + desc = "A monstrous, dog-sized cockroach. This one looks more robust than others." + icon_state = "panzer" + icon_living = "panzer" + icon_dead = "panzer_dead" + meat_amount = 4 + turns_per_move = 2 + maxHealth = 100 + health = 100 + + mob_size = MOB_MEDIUM + density = 1 + +/mob/living/simple_animal/hostile/retaliate/roach/hunter + name = "Jager Roach" + desc = "A monstrous, dog-sized cockroach. This one have a bigger claws." + icon_state = "jager" + icon_living = "jager" + icon_dead = "jager_dead" + meat_amount = 3 + turns_per_move = 2 + melee_damage_lower = 3 + melee_damage_upper = 10 + +/mob/living/simple_animal/hostile/retaliate/roach/fuhrer + name = "Master Roach" + desc = "A glorious leader of cockroaches. Literally Hitler." + icon_state = "fuhrer" + icon_living = "fuhrer" + icon_dead = "fuhrer_dead" + meat_amount = 5 + turns_per_move = 4 + maxHealth = 60 + health = 60 + + melee_damage_lower = 3 + melee_damage_upper = 20 + +/mob/living/simple_animal/hostile/retaliate/roach/support + name = "Seuche Roach" + desc = "A monstrous, dog-sized cockroach. This one smells like hell and secretes strange vapors." + icon_state = "seuche" + icon_living = "seuche" + icon_dead = "seuche_dead" + meat_amount = 3 + turns_per_move = 4 + maxHealth = 20 + health = 20 + + melee_damage_upper = 3 + + +/mob/living/simple_animal/hostile/retaliate/roach/support/New() + ..() + create_reagents(100) + +/mob/living/simple_animal/hostile/retaliate/roach/support/proc/gas_attack() + if(!(reagents.has_reagent(/datum/reagent/toxin/blattedin, 20) && health <= 0)) + return + var/location = get_turf(src) + var/datum/effect/effect/system/smoke_spread/chem/S = new + S.attach(location) + S.set_up(src.reagents, src.reagents.total_volume, 0, location) + src.visible_message("\the [src] secrete strange vapors!") + spawn(0) + S.start() + reagents.clear_reagents() + return + +/mob/living/simple_animal/hostile/retaliate/roach/support/Life() + ..() + reagents.add_reagent(/datum/reagent/toxin/blattedin, 1) + if(reagents.has_reagent(/datum/reagent/toxin/blattedin, 20)&&prob(7)) + gas_attack() + +/mob/living/simple_animal/hostile/retaliate/roach/support/FindTarget() + . = ..() + if(.) + visible_emote("charges at [.] in clouds of poison!") + gas_attack() + + +/mob/living/simple_animal/hostile/fire_roach + name = "Firefly Roach" + desc = "Quite the nasty thing. Beware it's name is literal." + icon_state = "firefly_roach" + icon_living = "firefly_roach" + icon_dead = "firefly_dead" + health = 250 + maxHealth = 250 + melee_damage_lower = 2 + melee_damage_upper = 3 + attacktext = "clawed" + projectilesound = 'sound/effects/fire01.ogg' + projectiletype = /obj/item/projectile/flamer + faction = "roach" + speed = 4 + ranged = TRUE \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/roach.dm b/code/modules/mob/living/simple_animal/hostile/roach.dm new file mode 100644 index 00000000..65cdc333 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/roach.dm @@ -0,0 +1,131 @@ +/mob/living/simple_animal/hostile/retaliate/roach + name = "Kampfer Roach" + desc = "A monstrous, dog-sized cockroach. These huge mutants can be everywhere where humans are, on ships, planets and stations." + icon_state = "roach" + icon_living = "roach" + icon_dead = "roach_dead" + emote_see = list("chirps loudly", "cleans its whiskers with forelegs") + speak_chance = 5 + turns_per_move = 3 + response_help = "pets the" + response_disarm = "pushes aside" + response_harm = "stamps on" + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/roachmeat + meat_amount = 3 + speed = 4 + maxHealth = 10 + health = 10 + + mob_size = MOB_SMALL + density = 0 //Swarming roaches! They also more robust that way. + + harm_intent_damage = 3 + melee_damage_lower = 1 + melee_damage_upper = 4 + attacktext = "bitten" + attack_sound = 'sound/voice/insect_battle_bite.ogg' + + faction = "roach" + +/mob/living/simple_animal/hostile/retaliate/roach/death() + . = ..() + GLOB.roaches_killed++//stats for the roaches deaths + +/mob/living/simple_animal/hostile/retaliate/roach/FindTarget() + . = ..() + if(.) + visible_emote("charges at [.]!") + playsound(src, 'sound/voice/insect_battle_screeching.ogg', 30, 1, -3) + +/mob/living/simple_animal/hostile/retaliate/roach/AttackingTarget() + . =..() + var/mob/living/L = . + if(istype(L)) + if(prob(5)) + L.Weaken(3) + L.visible_message("\the [src] knocks down \the [L]!") + +/mob/living/simple_animal/hostile/retaliate/roach/tank + name = "Panzer Roach" + desc = "A monstrous, dog-sized cockroach. This one looks more robust than others." + icon_state = "panzer" + icon_living = "panzer" + icon_dead = "panzer_dead" + meat_amount = 4 + turns_per_move = 2 + maxHealth = 30 + health = 30 + + mob_size = MOB_MEDIUM + density = 1 + +/mob/living/simple_animal/hostile/retaliate/roach/hunter + name = "Jager Roach" + desc = "A monstrous, dog-sized cockroach. This one have a bigger claws." + icon_state = "jager" + icon_living = "jager" + icon_dead = "jager_dead" + meat_amount = 3 + turns_per_move = 2 + maxHealth = 15 + health = 15 + + melee_damage_lower = 3 + melee_damage_upper = 10 + +/mob/living/simple_animal/hostile/retaliate/roach/fuhrer + name = "Fuhrer Roach" + desc = "A glorious leader of cockroaches. Literally Hitler." + icon_state = "fuhrer" + icon_living = "fuhrer" + icon_dead = "fuhrer_dead" + meat_amount = 5 + turns_per_move = 4 + maxHealth = 60 + health = 60 + + melee_damage_lower = 3 + melee_damage_upper = 20 + +/mob/living/simple_animal/hostile/retaliate/roach/support + name = "Seuche Roach" + desc = "A monstrous, dog-sized cockroach. This one smells like hell and secretes strange vapors." + icon_state = "seuche" + icon_living = "seuche" + icon_dead = "seuche_dead" + meat_amount = 3 + turns_per_move = 4 + maxHealth = 20 + health = 20 + + melee_damage_upper = 3 + + +/mob/living/simple_animal/hostile/retaliate/roach/support/New() + ..() + create_reagents(100) + +/mob/living/simple_animal/hostile/retaliate/roach/support/proc/gas_attack() + if(!(reagents.has_reagent(/datum/reagent/toxin/blattedin, 20) && health <= 0)) + return + var/location = get_turf(src) + var/datum/effect/effect/system/smoke_spread/chem/S = new + S.attach(location) + S.set_up(src.reagents, src.reagents.total_volume, 0, location) + src.visible_message("\the [src] secrete strange vapors!") + spawn(0) + S.start() + reagents.clear_reagents() + return + +/mob/living/simple_animal/hostile/retaliate/roach/support/Life() + ..() + reagents.add_reagent(/datum/reagent/toxin/blattedin, 1) + if(reagents.has_reagent(/datum/reagent/toxin/blattedin, 20)&&prob(7)) + gas_attack() + +/mob/living/simple_animal/hostile/retaliate/roach/support/FindTarget() + . = ..() + if(.) + visible_emote("charges at [.] in clouds of poison!") + gas_attack() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/russian.dm b/code/modules/mob/living/simple_animal/hostile/russian.dm new file mode 100644 index 00000000..3ec90503 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/russian.dm @@ -0,0 +1,47 @@ +/mob/living/simple_animal/hostile/russian + name = "russian" + desc = "For the Motherland!" + icon_state = "russianmelee" + icon_living = "russianmelee" + icon_dead = "russianmelee_dead" + icon_gib = "syndicate_gib" + speak_chance = 0 + turns_per_move = 5 + response_help = "pokes" + response_disarm = "shoves" + response_harm = "hits" + speed = 4 + stop_automated_movement_when_pulled = 0 + maxHealth = 100 + health = 100 + harm_intent_damage = 5 + melee_damage_lower = 15 + melee_damage_upper = 15 + attacktext = "punched" + a_intent = I_HURT + var/corpse = /obj/effect/landmark/corpse/russian + var/weapon1 = /obj/item/weapon/material/knife + unsuitable_atoms_damage = 15 + faction = "russian" + status_flags = CANPUSH + + +/mob/living/simple_animal/hostile/russian/ranged + icon_state = "russianranged" + icon_living = "russianranged" + corpse = /obj/effect/landmark/corpse/russian/ranged + weapon1 = /obj/item/weapon/gun/projectile/revolver/mateba + ranged = 1 + projectiletype = /obj/item/projectile/bullet + projectilesound = 'sound/weapons/gunshot/gunshot2.ogg' + casingtype = /obj/item/ammo_casing/a50 + + +/mob/living/simple_animal/hostile/russian/death(gibbed, deathmessage, show_dead_message) + ..(gibbed, deathmessage, show_dead_message) + if(corpse) + new corpse (src.loc) + if(weapon1) + new weapon1 (src.loc) + qdel(src) + return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm new file mode 100644 index 00000000..9f6d7301 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm @@ -0,0 +1,129 @@ +/mob/living/simple_animal/hostile/syndicate + name = "\improper Syndicate operative" + desc = "Death to the Company." + icon_state = "syndicate" + icon_living = "syndicate" + icon_dead = "syndicate_dead" + icon_gib = "syndicate_gib" + speak_chance = 0 + turns_per_move = 5 + response_help = "pokes" + response_disarm = "shoves" + response_harm = "hits" + speed = 4 + stop_automated_movement_when_pulled = 0 + maxHealth = 100 + health = 100 + harm_intent_damage = 5 + melee_damage_lower = 10 + melee_damage_upper = 10 + attacktext = "punched" + a_intent = I_HURT + var/corpse = /obj/effect/landmark/corpse/syndicate + var/weapon1 + var/weapon2 + unsuitable_atoms_damage = 15 + environment_smash = 1 + faction = "syndicate" + status_flags = CANPUSH + +/mob/living/simple_animal/hostile/syndicate/death(gibbed, deathmessage, show_dead_message) + ..(gibbed, deathmessage, show_dead_message) + if(corpse) + new corpse (src.loc) + if(weapon1) + new weapon1 (src.loc) + if(weapon2) + new weapon2 (src.loc) + qdel(src) + return + +///////////////Sword and shield//////////// + +/mob/living/simple_animal/hostile/syndicate/melee + melee_damage_lower = 20 + melee_damage_upper = 25 + icon_state = "syndicatemelee" + icon_living = "syndicatemelee" + weapon1 = /obj/item/weapon/melee/energy/sword/red + weapon2 = /obj/item/weapon/shield/energy + attacktext = "slashed" + status_flags = 0 + +/mob/living/simple_animal/hostile/syndicate/melee/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(O.force) + if(prob(80)) + var/damage = O.force + if (O.damtype == PAIN) + damage = 0 + health -= damage + visible_message("\The [src] has been attacked with \the [O] by \the [user].") + else + visible_message("\The [src] blocks the [O] with its shield!") + //user.do_attack_animation(src) + else + to_chat(usr, "This weapon is ineffective, it does no damage.") + visible_message("\The [user] gently taps \the [src] with \the [O].") + + +/mob/living/simple_animal/hostile/syndicate/melee/bullet_act(var/obj/item/projectile/Proj) + if(!Proj) return + if(prob(65)) + src.health -= Proj.damage + else + visible_message("\The [src] blocks \the [Proj] with its shield!") + return 0 + + +/mob/living/simple_animal/hostile/syndicate/melee/space + min_gas = null + max_gas = null + minbodytemp = 0 + icon_state = "syndicatemeleespace" + icon_living = "syndicatemeleespace" + name = "Syndicate Commando" + corpse = /obj/effect/landmark/corpse/syndicate + speed = 0 + +/mob/living/simple_animal/hostile/syndicate/ranged + ranged = 1 + rapid = 1 + icon_state = "syndicateranged" + icon_living = "syndicateranged" + casingtype = /obj/item/ammo_casing/a10mm + projectilesound = 'sound/weapons/gunshot/gunshot_smg.ogg' + projectiletype = /obj/item/projectile/bullet/pistol/medium + + weapon1 = /obj/item/weapon/gun/projectile/automatic/c20r + +/mob/living/simple_animal/hostile/syndicate/ranged/space + icon_state = "syndicaterangedpsace" + icon_living = "syndicaterangedpsace" + name = "Syndicate Commando" + min_gas = null + max_gas = null + minbodytemp = 0 + corpse = /obj/effect/landmark/corpse/syndicate/commando + speed = 0 + +/mob/living/simple_animal/hostile/viscerator + name = "viscerator" + desc = "A small, twin-bladed machine capable of inflicting very deadly lacerations." + icon = 'icons/mob/critter.dmi' + icon_state = "viscerator_attack" + icon_living = "viscerator_attack" + pass_flags = PASS_FLAG_TABLE + health = 15 + maxHealth = 15 + melee_damage_lower = 15 + melee_damage_upper = 15 + attacktext = "cut" + attack_sound = 'sound/weapons/bladeslice.ogg' + faction = "syndicate" + min_gas = null + max_gas = null + minbodytemp = 0 + +/mob/living/simple_animal/hostile/viscerator/death(gibbed, deathmessage, show_dead_message) + ..(null,"is smashed into pieces!", show_dead_message) + qdel(src) diff --git a/code/modules/mob/living/simple_animal/hostile/tree.dm b/code/modules/mob/living/simple_animal/hostile/tree.dm new file mode 100644 index 00000000..5a20db02 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/tree.dm @@ -0,0 +1,50 @@ +/mob/living/simple_animal/hostile/tree + name = "pine tree" + desc = "A pissed off tree-like alien. It seems annoyed with the festivities..." + icon = 'icons/obj/flora/pinetrees.dmi' + icon_state = "pine_1" + icon_living = "pine_1" + icon_dead = "pine_1" + icon_gib = "pine_1" + speak_chance = 0 + turns_per_move = 5 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat + response_help = "brushes" + response_disarm = "pushes" + response_harm = "hits" + speed = -1 + maxHealth = 250 + health = 250 + + pixel_x = -16 + + harm_intent_damage = 5 + melee_damage_lower = 8 + melee_damage_upper = 12 + attacktext = "bitten" + attack_sound = 'sound/weapons/bite.ogg' + + //Space carp aren't affected by atmos. + min_gas = null + max_gas = null + minbodytemp = 0 + + faction = "carp" + +/mob/living/simple_animal/hostile/tree/FindTarget() + . = ..() + if(.) + audible_emote("growls at [.]") + +/mob/living/simple_animal/hostile/tree/AttackingTarget() + . =..() + var/mob/living/L = . + if(istype(L)) + if(prob(15)) + L.Weaken(3) + L.visible_message("\the [src] knocks down \the [L]!") + +/mob/living/simple_animal/hostile/tree/death(gibbed, deathmessage, show_dead_message) + ..(null,"is hacked into pieces!", show_dead_message) + new /obj/item/stack/material/wood(loc) + qdel(src) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/vagrant.dm b/code/modules/mob/living/simple_animal/hostile/vagrant.dm new file mode 100644 index 00000000..24d86c0e --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/vagrant.dm @@ -0,0 +1,119 @@ + +/mob/living/simple_animal/hostile/vagrant + name = "creature" + desc = "You get the feeling you should run." + icon = 'icons/mob/mob.dmi' + icon_state = "vagrant" + icon_living = "vagrant" + icon_dead = "vagrant" + icon_gib = "vagrant" + maxHealth = 65 + health = 40 + speed = 5 + speak_chance = 0 + turns_per_move = 3 + move_to_delay = 3 + response_help = "pets the" + response_disarm = "gently pushes aside the" + response_harm = "hits the" + break_stuff_probability = 0 + faction = "vagrant" + harm_intent_damage = 3 + melee_damage_lower = 3 + melee_damage_upper = 4 + light_color = "#8A0707" + attacktext = "mauled" + attack_sound = 'sound/weapons/bite.ogg' + min_gas = null + max_gas = null + minbodytemp = 0 + var/datum/disease2/disease/carried + var/cloaked = 0 + var/mob/living/carbon/human/gripping = null + var/blood_per_tick = 4.25 + var/health_per_tick = 0.8 + +/mob/living/simple_animal/hostile/vagrant/Initialize() + . = ..() + if(prob(40)) + carried = new/datum/disease2/disease() + carried.makerandom(rand(2, 4)) + +/mob/living/simple_animal/hostile/vagrant/Allow_Spacemove(var/check_drift = 0) + return 1 + +/mob/living/simple_animal/hostile/vagrant/bullet_act(var/obj/item/projectile/Proj) + var/oldhealth = health + . = ..() + if((target_mob != Proj.firer) && health < oldhealth && !incapacitated(INCAPACITATION_KNOCKOUT)) //Respond to being shot at + target_mob = Proj.firer + turns_per_move = 2 + MoveToTarget() + +/mob/living/simple_animal/hostile/vagrant/Life() + . = ..() + if(gripping) + if(!(get_turf(src) == get_turf(gripping))) + gripping = null + + else if(gripping.should_have_organ(BP_HEART)) + var/blood_volume = round(gripping.vessel.get_reagent_amount(/datum/reagent/blood)) + if(blood_volume > 5) + gripping.vessel.remove_reagent(/datum/reagent/blood, blood_per_tick) + health = min(health + health_per_tick, maxHealth) + if(prob(15)) + to_chat(gripping, "You feel your fluids being drained!") + else + gripping = null + + if(turns_per_move != initial(turns_per_move)) + turns_per_move = initial(turns_per_move) + + if(stance == HOSTILE_STANCE_IDLE && !cloaked) + cloaked = 1 + update_icon() + if(health == maxHealth) + new/mob/living/simple_animal/hostile/vagrant(src.loc) + new/mob/living/simple_animal/hostile/vagrant(src.loc) + gib() + return + if(health < 1) + gib() //Leave no identifiable evidence. + return + +/mob/living/simple_animal/hostile/vagrant/update_icon() + if(cloaked) //It's fun time + alpha = 45 + set_light(0) + icon_state = initial(icon_state) + move_to_delay = initial(move_to_delay) + else //It's fight time + alpha = 255 + icon_state = "vagrant_glowing" + set_light(4) + move_to_delay = 2 + +/mob/living/simple_animal/hostile/vagrant/AttackingTarget() + . = ..() + if(ishuman(.)) + var/mob/living/carbon/human/H = . + if(gripping == H) + H.Weaken(3) + return + //This line ensures there's always a reasonable chance of grabbing, while still + //Factoring in health + if(!gripping && (cloaked || prob(health + ((maxHealth - health) * 2)))) + gripping = H + cloaked = 0 + update_icon() + H.Weaken(3) + H.visible_message("\the [src] latches onto \the [H], pulsating!") + if(carried && length(gripping.virus2) == 0) + infect_virus2(gripping, carried, 1) + src.loc = gripping.loc + return + +/mob/living/simple_animal/hostile/vagrant/swarm/Initialize() + . = ..() + if(prob(75)) new/mob/living/simple_animal/hostile/vagrant(loc) + if(prob(50)) new/mob/living/simple_animal/hostile/vagrant(loc) diff --git a/code/modules/mob/living/simple_animal/hostile/voxslug.dm b/code/modules/mob/living/simple_animal/hostile/voxslug.dm new file mode 100644 index 00000000..e73039c4 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/voxslug.dm @@ -0,0 +1,88 @@ +/*VOX SLUG +Small, little HP, poisonous. +*/ + +/mob/living/simple_animal/hostile/voxslug + name = "slug" + desc = "A viscious little creature, it has a mouth of too many teeth and a penchant for blood." + icon_state = "voxslug" + icon_living = "voxslug" + item_state = "voxslug" + icon_dead = "voxslug_dead" + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "stamps on" + destroy_surroundings = 0 + health = 15 + maxHealth = 15 + speed = 0 + move_to_delay = 0 + density = 1 + min_gas = null + mob_size = MOB_MINISCULE + pass_flags = PASS_FLAG_TABLE + melee_damage_lower = 5 + melee_damage_upper = 10 + holder_type = /obj/item/weapon/holder/voxslug + faction = SPECIES_VOX + +/mob/living/simple_animal/hostile/voxslug/ListTargets(var/dist = 7) + var/list/L = list() + for(var/a in hearers(src, dist)) + if(istype(a,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = a + if(H.species.get_bodytype() == SPECIES_VOX) + continue + if(isliving(a)) + var/mob/living/M = a + if(M.faction == faction) + continue + L += a + + for (var/obj/mecha/M in mechas_list) + if (M.z == src.z && get_dist(src, M) <= dist) + L += M + + return L + +/mob/living/simple_animal/hostile/voxslug/get_scooped(var/mob/living/carbon/grabber) + if(grabber.species.get_bodytype() != SPECIES_VOX) + to_chat(grabber, "\The [src] wriggles out of your hands before you can pick it up!") + return + else return ..() + +/mob/living/simple_animal/hostile/voxslug/proc/attach(var/mob/living/carbon/human/H) + var/obj/item/organ/external/chest = H.organs_by_name["chest"] + var/obj/item/weapon/holder/voxslug/holder = new(get_turf(src)) + src.forceMove(holder) + chest.embed(holder,0,"\The [src] latches itself onto \the [H]!") + holder.sync(src) + +/mob/living/simple_animal/hostile/voxslug/AttackingTarget() + . = ..() + if(istype(., /mob/living/carbon/human)) + var/mob/living/carbon/human/H = . + if(prob(H.getBruteLoss()/2)) + attach(H) + +/mob/living/simple_animal/hostile/voxslug/Life() + . = ..() + if(. && istype(src.loc, /obj/item/weapon/holder) && isliving(src.loc.loc)) //We in somebody + var/mob/living/L = src.loc.loc + if(src.loc in L.get_visible_implants(0)) + if(prob(1)) + to_chat(L, "You feel strange as \the [src] pulses...") + var/datum/reagents/R = L.reagents + R.add_reagent(/datum/reagent/cryptobiolin, 0.5) + +/obj/item/weapon/holder/voxslug/attack(var/mob/target, var/mob/user) + var/mob/living/simple_animal/hostile/voxslug/V = contents[1] + if(!V.stat && istype(target, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = target + if(!do_mob(user, H, 30)) + return + user.drop_from_inventory(src) + V.attach(H) + qdel(src) + return + ..() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/kobold.dm b/code/modules/mob/living/simple_animal/kobold.dm new file mode 100644 index 00000000..3e52a408 --- /dev/null +++ b/code/modules/mob/living/simple_animal/kobold.dm @@ -0,0 +1,33 @@ +//kobold +/mob/living/simple_animal/kobold + name = "kobold" + desc = "A small, rat-like creature." + icon = 'icons/mob/mob.dmi' + icon_state = "kobold_idle" + icon_living = "kobold_idle" + icon_dead = "kobold_dead" + //speak = list("You no take candle!","Ooh, pretty shiny.","Me take?","Where gold here...","Me likey.") + speak_emote = list("mutters","hisses","grumbles") + emote_hear = list("mutters under it's breath.","grumbles.", "yips!") + emote_see = list("looks around suspiciously.", "scratches it's arm.","putters around a bit.") + speak_chance = 15 + turns_per_move = 5 + see_in_dark = 6 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/monkey + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "kicks" + minbodytemp = 250 + min_oxy = 16 //Require atleast 16kPA oxygen + minbodytemp = 223 //Below -50 Degrees Celcius + maxbodytemp = 323 //Above 50 Degrees Celcius + +/mob/living/simple_animal/kobold/Life() + ..() + if(prob(15) && turns_since_move && !stat) + flick("kobold_act",src) + +/mob/living/simple_animal/kobold/Move(var/dir) + ..() + if(!stat) + flick("kobold_walk",src) diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm new file mode 100644 index 00000000..2a50eea9 --- /dev/null +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -0,0 +1,753 @@ +/* Parrots! + * Contains + * Defines + * Inventory (headset stuff) + * Attack responces + * AI + * Procs / Verbs (usable by players) + * Sub-types + */ + +/* + * Defines + */ + +//Only a maximum of one action and one intent should be active at any given time. +//Actions +#define PARROT_PERCH 1 //Sitting/sleeping, not moving +#define PARROT_SWOOP 2 //Moving towards or away from a target +#define PARROT_WANDER 4 //Moving without a specific target in mind + +//Intents +#define PARROT_STEAL 8 //Flying towards a target to steal it/from it +#define PARROT_ATTACK 16 //Flying towards a target to attack it +#define PARROT_RETURN 32 //Flying towards its perch +#define PARROT_FLEE 64 //Flying away from its attacker + + +/mob/living/simple_animal/parrot + name = "\improper Parrot" + desc = "The parrot squaks, \"It's a Parrot! BAWWK!\"" + icon = 'icons/mob/animal.dmi' + icon_state = "parrot_fly" + icon_living = "parrot_fly" + icon_dead = "parrot_dead" + pass_flags = PASS_FLAG_TABLE + mob_size = MOB_SMALL + + speak = list("Hi","Hello!","Cracker?","BAWWWWK george mellons griffing me") + speak_emote = list("squawks","says","yells") + emote_hear = list("squawks","bawks") + emote_see = list("flutters its wings") + + speak_chance = 1//1% (1 in 100) chance every tick; So about once per 150 seconds, assuming an average tick is 1.5s + turns_per_move = 5 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/cracker/ + + response_help = "pets" + response_disarm = "gently moves aside" + response_harm = "swats" + stop_automated_movement = 1 + universal_speak = 1 + + var/parrot_state = PARROT_WANDER //Hunt for a perch when created + var/parrot_sleep_max = 25 //The time the parrot sits while perched before looking around. Mosly a way to avoid the parrot's AI in life() being run every single tick. + var/parrot_sleep_dur = 25 //Same as above, this is the var that physically counts down + var/parrot_dam_zone = list(BP_CHEST, BP_HEAD, BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG) //For humans, select a bodypart to attack + + var/parrot_speed = 5 //"Delay in world ticks between movement." according to byond. Yeah, that's BS but it does directly affect movement. Higher number = slower. + var/parrot_been_shot = 0 //Parrots get a speed bonus after being shot. This will deincrement every Life() and at 0 the parrot will return to regular speed. + + var/list/speech_buffer = list() + var/list/available_channels = list() + + //Headset for Poly to yell at engineers :) + var/obj/item/device/radio/headset/ears = null + + //The thing the parrot is currently interested in. This gets used for items the parrot wants to pick up, mobs it wants to steal from, + //mobs it wants to attack or mobs that have attacked it + var/atom/movable/parrot_interest = null + + //Parrots will generally sit on their pertch unless something catches their eye. + //These vars store their preffered perch and if they dont have one, what they can use as a perch + var/obj/parrot_perch = null + var/obj/desired_perches = list(/obj/structure/computerframe, /obj/structure/displaycase, \ + /obj/structure/filingcabinet, /obj/machinery/teleport, \ + /obj/machinery/computer, /obj/machinery/telecomms, \ + /obj/machinery/nuclearbomb, /obj/machinery/particle_accelerator, \ + /obj/machinery/recharge_station, /obj/machinery/smartfridge, \ + /obj/machinery/suit_storage_unit) + + //Parrots are kleptomaniacs. This variable ... stores the item a parrot is holding. + var/obj/item/held_item = null + + +/mob/living/simple_animal/parrot/New() + ..() + if(!ears) + var/headset = pick(/obj/item/device/radio/headset/headset_sec, \ + /obj/item/device/radio/headset/headset_eng, \ + /obj/item/device/radio/headset/headset_med, \ + /obj/item/device/radio/headset/headset_sci, \ + /obj/item/device/radio/headset/headset_cargo) + ears = new headset(src) + + parrot_sleep_dur = parrot_sleep_max //In case someone decides to change the max without changing the duration var + + verbs.Add(/mob/living/simple_animal/parrot/proc/steal_from_ground, \ + /mob/living/simple_animal/parrot/proc/steal_from_mob, \ + /mob/living/simple_animal/parrot/verb/drop_held_item_player, \ + /mob/living/simple_animal/parrot/proc/perch_player) + + +/mob/living/simple_animal/parrot/death(gibbed, deathmessage, show_dead_message) + if(held_item) + held_item.loc = src.loc + held_item = null + walk(src,0) + ..(gibbed, deathmessage, show_dead_message) + +/mob/living/simple_animal/parrot/Stat() + . = ..() + stat("Held Item", held_item) + +/* + * Inventory + */ +/mob/living/simple_animal/parrot/show_inv(mob/user as mob) + user.set_machine(src) + if(user.stat) return + + var/dat = "
            Inventory of [name]

            " + if(ears) + dat += "
            Headset: [ears] (Remove)" + else + dat += "
            Headset: Nothing" + + user << browse(dat, text("window=mob[];size=325x500", name)) + onclose(user, "mob[real_name]") + return + +/mob/living/simple_animal/parrot/Topic(href, href_list) + + //Can the usr physically do this? + if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) + return + + //Is the usr's mob type able to do this? + if(ishuman(usr) || issmall(usr) || isrobot(usr)) + + //Removing from inventory + if(href_list["remove_inv"]) + var/remove_from = href_list["remove_inv"] + switch(remove_from) + if("ears") + if(ears) + if(available_channels.len) + src.say("[pick(available_channels)] BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") + else + src.say("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") + ears.loc = src.loc + ears = null + for(var/possible_phrase in speak) + if(copytext(possible_phrase,1,3) in department_radio_keys) + possible_phrase = copytext(possible_phrase,3,length(possible_phrase)) + else + to_chat(usr, "There is nothing to remove from its [remove_from].") + return + + //Adding things to inventory + else if(href_list["add_inv"]) + var/add_to = href_list["add_inv"] + if(!usr.get_active_hand()) + to_chat(usr, "You have nothing in your hand to put on its [add_to].") + return + switch(add_to) + if("ears") + if(ears) + to_chat(usr, "It's already wearing something.") + return + else + var/obj/item/item_to_add = usr.get_active_hand() + if(!item_to_add) + return + + if( !istype(item_to_add, /obj/item/device/radio/headset) ) + to_chat(usr, "This object won't fit.") + return + + var/obj/item/device/radio/headset/headset_to_add = item_to_add + + usr.drop_item() + headset_to_add.loc = src + src.ears = headset_to_add + to_chat(usr, "You fit the headset onto [src].") + + clearlist(available_channels) + for(var/ch in headset_to_add.channels) + switch(ch) + if("Engineering") + available_channels.Add(":e") + if("Command") + available_channels.Add(":c") + if("Security") + available_channels.Add(":s") + if("Science") + available_channels.Add(":n") + if("Medical") + available_channels.Add(":m") + if("Mining") + available_channels.Add(":d") + if("Cargo") + available_channels.Add(":q") + else + ..() + + +/* + * Attack responces + */ +//Humans, monkeys, aliens +/mob/living/simple_animal/parrot/attack_hand(mob/living/carbon/M as mob) + ..() + if(client) return + if(!stat && M.a_intent == I_HURT) + + icon_state = "parrot_fly" //It is going to be flying regardless of whether it flees or attacks + + if(parrot_state == PARROT_PERCH) + parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched + + parrot_interest = M + parrot_state = PARROT_SWOOP //The parrot just got hit, it WILL move, now to pick a direction.. + + if(M.health < 50) //Weakened mob? Fight back! + parrot_state |= PARROT_ATTACK + else + parrot_state |= PARROT_FLEE //Otherwise, fly like a bat out of hell! + drop_held_item(0) + return + +//Mobs with objects +/mob/living/simple_animal/parrot/attackby(var/obj/item/O as obj, var/mob/user as mob) + ..() + if(!stat && !client && !istype(O, /obj/item/stack/medical)) + if(O.force) + if(parrot_state == PARROT_PERCH) + parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched + + parrot_interest = user + parrot_state = PARROT_SWOOP | PARROT_FLEE + icon_state = "parrot_fly" + drop_held_item(0) + return + +//Bullets +/mob/living/simple_animal/parrot/bullet_act(var/obj/item/projectile/Proj) + ..() + if(!stat && !client) + if(parrot_state == PARROT_PERCH) + parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched + + parrot_interest = null + parrot_state = PARROT_WANDER //OWFUCK, Been shot! RUN LIKE HELL! + parrot_been_shot += 5 + icon_state = "parrot_fly" + drop_held_item(0) + return + + +/* + * AI - Not really intelligent, but I'm calling it AI anyway. + */ +/mob/living/simple_animal/parrot/Life() + ..() + + //Sprite and AI update for when a parrot gets pulled + if(pulledby && stat == CONSCIOUS) + icon_state = "parrot_fly" + if(!client) + parrot_state = PARROT_WANDER + return + + if(client || stat) + return //Lets not force players or dead/incap parrots to move + + if(!isturf(src.loc) || !canmove || buckled) + return //If it can't move, dont let it move. (The buckled check probably isn't necessary thanks to canmove) + + +//-----SPEECH + /* Parrot speech mimickry! + Phrases that the parrot hears in mob/living/say() get added to speach_buffer. + Every once in a while, the parrot picks one of the lines from the buffer and replaces an element of the 'speech' list. + Then it clears the buffer to make sure they dont magically remember something from hours ago. */ + if(speech_buffer.len && prob(10)) + if(speak.len) + speak.Remove(pick(speak)) + + speak.Add(pick(speech_buffer)) + clearlist(speech_buffer) + + +//-----SLEEPING + if(parrot_state == PARROT_PERCH) + if(parrot_perch && parrot_perch.loc != src.loc) //Make sure someone hasnt moved our perch on us + if(parrot_perch in view(src)) + parrot_state = PARROT_SWOOP | PARROT_RETURN + icon_state = "parrot_fly" + return + else + parrot_state = PARROT_WANDER + icon_state = "parrot_fly" + return + + if(--parrot_sleep_dur) //Zzz + return + + else + //This way we only call the stuff below once every [sleep_max] ticks. + parrot_sleep_dur = parrot_sleep_max + + //Cycle through message modes for the headset + if(speak.len) + var/list/newspeak = list() + + if(available_channels.len && src.ears) + for(var/possible_phrase in speak) + + //50/50 chance to not use the radio at all + var/useradio = 0 + if(prob(50)) + useradio = 1 + + if(copytext(possible_phrase,1,3) in department_radio_keys) + possible_phrase = "[useradio?pick(available_channels):""] [copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix + else + possible_phrase = "[useradio?pick(available_channels):""] [possible_phrase]" + + newspeak.Add(possible_phrase) + + else //If we have no headset or channels to use, dont try to use any! + for(var/possible_phrase in speak) + if(copytext(possible_phrase,1,3) in department_radio_keys) + possible_phrase = "[copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix + newspeak.Add(possible_phrase) + speak = newspeak + + //Search for item to steal + parrot_interest = search_for_item() + if(parrot_interest) + visible_emote("looks in [parrot_interest]'s direction and takes flight") + parrot_state = PARROT_SWOOP | PARROT_STEAL + icon_state = "parrot_fly" + return + +//-----WANDERING - This is basically a 'I dont know what to do yet' state + else if(parrot_state == PARROT_WANDER) + //Stop movement, we'll set it later + walk(src, 0) + parrot_interest = null + + //Wander around aimlessly. This will help keep the loops from searches down + //and possibly move the mob into a new are in view of something they can use + if(prob(90)) + step(src, pick(GLOB.cardinal)) + return + + if(!held_item && !parrot_perch) //If we've got nothing to do.. look for something to do. + var/atom/movable/AM = search_for_perch_and_item() //This handles checking through lists so we know it's either a perch or stealable item + if(AM) + if(istype(AM, /obj/item) || isliving(AM)) //If stealable item + parrot_interest = AM + visible_emote("turns and flies towards [parrot_interest]") + parrot_state = PARROT_SWOOP | PARROT_STEAL + return + else //Else it's a perch + parrot_perch = AM + parrot_state = PARROT_SWOOP | PARROT_RETURN + return + return + + if(parrot_interest && parrot_interest in view(src)) + parrot_state = PARROT_SWOOP | PARROT_STEAL + return + + if(parrot_perch && parrot_perch in view(src)) + parrot_state = PARROT_SWOOP | PARROT_RETURN + return + + else //Have an item but no perch? Find one! + parrot_perch = search_for_perch() + if(parrot_perch) + parrot_state = PARROT_SWOOP | PARROT_RETURN + return +//-----STEALING + else if(parrot_state == (PARROT_SWOOP | PARROT_STEAL)) + walk(src,0) + if(!parrot_interest || held_item) + parrot_state = PARROT_SWOOP | PARROT_RETURN + return + + if(!(parrot_interest in view(src))) + parrot_state = PARROT_SWOOP | PARROT_RETURN + return + + if(in_range(src, parrot_interest)) + + if(isliving(parrot_interest)) + steal_from_mob() + + else //This should ensure that we only grab the item we want, and make sure it's not already collected on our perch + if(!parrot_perch || parrot_interest.loc != parrot_perch.loc) + held_item = parrot_interest + parrot_interest.loc = src + visible_message("[src] grabs the [held_item]!", "You grab the [held_item]!", "You hear the sounds of wings flapping furiously.") + + parrot_interest = null + parrot_state = PARROT_SWOOP | PARROT_RETURN + return + + walk_to(src, parrot_interest, 1, parrot_speed) + return + +//-----RETURNING TO PERCH + else if(parrot_state == (PARROT_SWOOP | PARROT_RETURN)) + walk(src, 0) + if(!parrot_perch || !isturf(parrot_perch.loc)) //Make sure the perch exists and somehow isnt inside of something else. + parrot_perch = null + parrot_state = PARROT_WANDER + return + + if(in_range(src, parrot_perch)) + src.loc = parrot_perch.loc + drop_held_item() + parrot_state = PARROT_PERCH + icon_state = "parrot_sit" + return + + walk_to(src, parrot_perch, 1, parrot_speed) + return + +//-----FLEEING + else if(parrot_state == (PARROT_SWOOP | PARROT_FLEE)) + walk(src,0) + if(!parrot_interest || !isliving(parrot_interest)) //Sanity + parrot_state = PARROT_WANDER + + walk_away(src, parrot_interest, 1, parrot_speed-parrot_been_shot) + parrot_been_shot-- + return + +//-----ATTACKING + else if(parrot_state == (PARROT_SWOOP | PARROT_ATTACK)) + + //If we're attacking a nothing, an object, a turf or a ghost for some stupid reason, switch to wander + if(!parrot_interest || !isliving(parrot_interest)) + parrot_interest = null + parrot_state = PARROT_WANDER + return + + var/mob/living/L = parrot_interest + + //If the mob is close enough to interact with + if(in_range(src, parrot_interest)) + + //If the mob we've been chasing/attacking dies or falls into crit, check for loot! + if(L.stat) + parrot_interest = null + if(!held_item) + held_item = steal_from_ground() + if(!held_item) + held_item = steal_from_mob() //Apparently it's possible for dead mobs to hang onto items in certain circumstances. + if(parrot_perch in view(src)) //If we have a home nearby, go to it, otherwise find a new home + parrot_state = PARROT_SWOOP | PARROT_RETURN + else + parrot_state = PARROT_WANDER + return + + //Time for the hurt to begin! + var/damage = rand(5,10) + + if(ishuman(parrot_interest)) + var/mob/living/carbon/human/H = parrot_interest + var/obj/item/organ/external/affecting = H.get_organ(ran_zone(pick(parrot_dam_zone))) + + H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, "melee"), DAM_SHARP|DAM_EDGE) + visible_emote(pick("pecks [H]'s [affecting].", "cuts [H]'s [affecting] with its talons.")) + + else + L.adjustBruteLoss(damage) + visible_emote(pick("pecks at [L].", "claws [L].")) + return + + //Otherwise, fly towards the mob! + else + walk_to(src, parrot_interest, 1, parrot_speed) + return +//-----STATE MISHAP + else //This should not happen. If it does lets reset everything and try again + walk(src,0) + parrot_interest = null + parrot_perch = null + drop_held_item() + parrot_state = PARROT_WANDER + return + +/* + * Procs + */ + +/mob/living/simple_animal/parrot/movement_delay() + if(client && stat == CONSCIOUS && parrot_state != "parrot_fly") + icon_state = "parrot_fly" + ..() + +/mob/living/simple_animal/parrot/proc/search_for_item() + for(var/atom/movable/AM in view(src)) + //Skip items we already stole or are wearing or are too big + if(parrot_perch && AM.loc == parrot_perch.loc || AM.loc == src) + continue + + if(istype(AM, /obj/item)) + var/obj/item/I = AM + if(I.w_class < ITEM_SIZE_SMALL) + return I + + if(iscarbon(AM)) + var/mob/living/carbon/C = AM + if((C.l_hand && C.l_hand.w_class <= ITEM_SIZE_SMALL) || (C.r_hand && C.r_hand.w_class <= ITEM_SIZE_SMALL)) + return C + return null + +/mob/living/simple_animal/parrot/proc/search_for_perch() + for(var/obj/O in view(src)) + for(var/path in desired_perches) + if(istype(O, path)) + return O + return null + +//This proc was made to save on doing two 'in view' loops seperatly +/mob/living/simple_animal/parrot/proc/search_for_perch_and_item() + for(var/atom/movable/AM in view(src)) + for(var/perch_path in desired_perches) + if(istype(AM, perch_path)) + return AM + + //Skip items we already stole or are wearing or are too big + if(parrot_perch && AM.loc == parrot_perch.loc || AM.loc == src) + continue + + if(istype(AM, /obj/item)) + var/obj/item/I = AM + if(I.w_class <= ITEM_SIZE_SMALL) + return I + + if(iscarbon(AM)) + var/mob/living/carbon/C = AM + if(C.l_hand && C.l_hand.w_class <= ITEM_SIZE_SMALL || C.r_hand && C.r_hand.w_class <= ITEM_SIZE_SMALL) + return C + return null + + +/* + * Verbs - These are actually procs, but can be used as verbs by player-controlled parrots. + */ +/mob/living/simple_animal/parrot/proc/steal_from_ground() + set name = "Steal from ground" + set category = "Parrot" + set desc = "Grabs a nearby item." + + if(stat) + return -1 + + if(held_item) + to_chat(src, "You are already holding the [held_item]") + return 1 + + for(var/obj/item/I in view(1,src)) + //Make sure we're not already holding it and it's small enough + if(I.loc != src && I.w_class <= ITEM_SIZE_SMALL) + + //If we have a perch and the item is sitting on it, continue + if(!client && parrot_perch && I.loc == parrot_perch.loc) + continue + + held_item = I + I.loc = src + visible_message("[src] grabs the [held_item]!", "You grab the [held_item]!", "You hear the sounds of wings flapping furiously.") + return held_item + + to_chat(src, "There is nothing of interest to take.") + return 0 + +/mob/living/simple_animal/parrot/proc/steal_from_mob() + set name = "Steal from mob" + set category = "Parrot" + set desc = "Steals an item right out of a person's hand!" + + if(stat) + return -1 + + if(held_item) + to_chat(src, "You are already holding the [held_item]") + return 1 + + var/obj/item/stolen_item = null + + for(var/mob/living/carbon/C in view(1,src)) + if(C.l_hand && C.l_hand.w_class <= ITEM_SIZE_SMALL) + stolen_item = C.l_hand + + if(C.r_hand && C.r_hand.w_class <= ITEM_SIZE_SMALL) + stolen_item = C.r_hand + + if(stolen_item) + C.remove_from_mob(stolen_item) + held_item = stolen_item + stolen_item.loc = src + visible_message("[src] grabs the [held_item] out of [C]'s hand!", "You snag the [held_item] out of [C]'s hand!", "You hear the sounds of wings flapping furiously.") + return held_item + + to_chat(src, "There is nothing of interest to take.") + return 0 + +/mob/living/simple_animal/parrot/verb/drop_held_item_player() + set name = "Drop held item" + set category = "Parrot" + set desc = "Drop the item you're holding." + + if(stat) + return + + src.drop_held_item() + + return + +/mob/living/simple_animal/parrot/proc/drop_held_item(var/drop_gently = 1) + set name = "Drop held item" + set category = "Parrot" + set desc = "Drop the item you're holding." + + if(stat) + return -1 + + if(!held_item) + to_chat(usr, "You have nothing to drop!") + return 0 + + if(!drop_gently) + if(istype(held_item, /obj/item/weapon/grenade)) + var/obj/item/weapon/grenade/G = held_item + G.loc = src.loc + G.detonate() + to_chat(src, "You let go of the [held_item]!") + held_item = null + return 1 + + to_chat(src, "You drop the [held_item].") + + held_item.loc = src.loc + held_item = null + return 1 + +/mob/living/simple_animal/parrot/proc/perch_player() + set name = "Sit" + set category = "Parrot" + set desc = "Sit on a nice comfy perch." + + if(stat || !client) + return + + if(icon_state == "parrot_fly") + for(var/atom/movable/AM in view(src,1)) + for(var/perch_path in desired_perches) + if(istype(AM, perch_path)) + src.loc = AM.loc + icon_state = "parrot_sit" + return + to_chat(src, "There is no perch nearby to sit on.") + return + +/* + * Sub-types + */ +/mob/living/simple_animal/parrot/Poly + name = "Poly" + desc = "Poly the Parrot. An expert on quantum cracker theory." + speak = list("Poly wanna cracker!", ":e Check the singlo, you chucklefucks!",":e Wire the solars, you lazy bums!",":e WHO TOOK THE DAMN HARDSUITS?",":e OH GOD ITS FREE CALL THE SHUTTLE") + +/mob/living/simple_animal/parrot/Poly/New() + ears = new /obj/item/device/radio/headset/headset_eng(src) + available_channels = list(":e") + ..() + +/mob/living/simple_animal/parrot/say(var/message) + + if(stat) + return + + var/verb = "says" + if(speak_emote.len) + verb = pick(speak_emote) + + + var/message_mode="" + if(copytext(message,1,2) == get_prefix_key(/decl/prefix/radio_main_channel)) + message_mode = "headset" + message = copytext(message,2) + + if(length(message) >= 2) + var/channel_prefix = copytext(message, 1 ,3) + message_mode = department_radio_keys[channel_prefix] + + if(copytext(message,1,2) == get_prefix_key(/decl/prefix/radio_channel_selection)) + var/positioncut = 3 + message = trim(copytext(message,positioncut)) + + message = capitalize(trim_left(message)) + + if(message_mode) + if(message_mode in radiochannels) + if(ears && istype(ears,/obj/item/device/radio)) + ears.talk_into(src,sanitize(message), message_mode, verb, null) + + + ..(message) + + +/mob/living/simple_animal/parrot/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null) + if(prob(50)) + parrot_hear(message) + ..(message,verb,language,alt_name,italics,speaker) + + + +/mob/living/simple_animal/parrot/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0) + if(prob(50) && available_channels.len) + parrot_hear("[pick(available_channels)] [message]") + ..(message,verb,language,part_a,part_b,speaker,hard_to_hear) + + +/mob/living/simple_animal/parrot/proc/parrot_hear(var/message="") + if(!message || stat) + return + speech_buffer.Add(message) + +/mob/living/simple_animal/parrot/attack_generic(var/mob/user, var/damage, var/attack_message) + + var/success = ..() + + if(client) + return success + + if(parrot_state == PARROT_PERCH) + parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched + + if(!success) + return 0 + + parrot_interest = user + parrot_state = PARROT_SWOOP | PARROT_ATTACK //Attack other animals regardless + icon_state = "parrot_fly" + return success \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm new file mode 100644 index 00000000..9dbad038 --- /dev/null +++ b/code/modules/mob/living/simple_animal/shade.dm @@ -0,0 +1,45 @@ +/mob/living/simple_animal/shade + name = "Shade" + real_name = "Shade" + desc = "A bound spirit" + icon = 'icons/mob/mob.dmi' + icon_state = "shade" + icon_living = "shade" + icon_dead = "shade_dead" + maxHealth = 50 + health = 50 + universal_speak = 1 + speak_emote = list("hisses") + emote_hear = list("wails","screeches") + response_help = "puts their hand through" + response_disarm = "flails at" + response_harm = "punches" + melee_damage_lower = 5 + melee_damage_upper = 15 + attacktext = "drained the life from" + minbodytemp = 0 + maxbodytemp = 4000 + min_gas = null + max_gas = null + speed = -1 + stop_automated_movement = 1 + status_flags = 0 + faction = "cult" + status_flags = CANPUSH + +/mob/living/simple_animal/shade/cultify() + return + +/mob/living/simple_animal/shade/Life() + ..() + OnDeathInLife() + +/mob/living/simple_animal/shade/proc/OnDeathInLife() + if(stat == 2) + new /obj/item/weapon/ectoplasm (src.loc) + for(var/mob/M in viewers(src, null)) + if((M.client && !( M.blinded ))) + M.show_message("[src] lets out a contented sigh as their form unwinds.") + ghostize() + qdel(src) + return diff --git a/code/modules/mob/living/simple_animal/shafra.dm b/code/modules/mob/living/simple_animal/shafra.dm new file mode 100644 index 00000000..54ee5c5d --- /dev/null +++ b/code/modules/mob/living/simple_animal/shafra.dm @@ -0,0 +1,23 @@ +/mob/living/simple_animal/shafra + name = "Shafra" + real_name = "Shafra" + desc = "A Bogani Hunting Dog" + icon = 'icons/mob/shafra.dmi' + icon_state = "shafra" + icon_living = "shafra" + icon_dead = "shafra_dead" + maxHealth = 100 + health = 100 + universal_speak = 1 + speak_emote = list("harks") + emote_hear = list("growls") + response_help = "barks" + response_disarm = "shoves" + response_harm = "mauls" + melee_damage_lower = 25 + melee_damage_upper = 35 + attacktext = "mauls and claws with all its might!" + minbodytemp = 90 + maxbodytemp = 1000 + + speed = 2 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm new file mode 100644 index 00000000..7f12c453 --- /dev/null +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -0,0 +1,390 @@ +/mob/living/simple_animal + name = "animal" + icon = 'icons/mob/animal.dmi' + health = 20 + maxHealth = 20 + + mob_bump_flag = SIMPLE_ANIMAL + mob_swap_flags = MONKEY|SLIME|SIMPLE_ANIMAL + mob_push_flags = MONKEY|SLIME|SIMPLE_ANIMAL + + var/show_stat_health = 1 //does the percentage health show in the stat panel for the mob + + var/icon_living = "" + var/icon_dead = "" + var/icon_gib = null //We only try to show a gibbing animation if this exists. + + var/list/speak = list("...") + var/speak_chance = 0 + var/list/emote_hear = list() //Hearable emotes + var/list/emote_see = list() //Unlike speak_emote, the list of things in this variable only show by themselves with no spoken text. IE: Ian barks, Ian yaps + + var/turns_per_move = 1 + var/turns_since_move = 0 + universal_speak = 0 //No, just no. + var/meat_amount = 0 + var/meat_type + var/stop_automated_movement = 0 //Use this to temporarely stop random movement or to if you write special movement code for animals. + var/wander = 1 // Does the mob wander around when idle? + var/stop_automated_movement_when_pulled = 1 //When set to 1 this stops the animal from moving when someone is pulling it. + + //Interaction + var/response_help = "tries to help" + var/response_disarm = "tries to disarm" + var/response_harm = "tries to hurt" + var/harm_intent_damage = 3 + + //Temperature effect + var/minbodytemp = 250 + var/maxbodytemp = 350 + var/heat_damage_per_tick = 3 //amount of damage applied if animal's body temperature is higher than maxbodytemp + var/cold_damage_per_tick = 2 //same as heat_damage_per_tick, only if the bodytemperature it's lower than minbodytemp + var/fire_alert = 0 + + //Atmos effect - Yes, you can make creatures that require phoron or co2 to survive. N2O is a trace gas and handled separately, hence why it isn't here. It'd be hard to add it. Hard and me don't mix (Yes, yes make all the dick jokes you want with that.) - Errorage + var/min_gas = list("oxygen" = 5) + var/max_gas = list("phoron" = 1, "carbon_dioxide" = 5) + var/unsuitable_atoms_damage = 2 //This damage is taken when atmos doesn't fit all the requirements above + var/speed = 0 //LETS SEE IF I CAN SET SPEEDS FOR SIMPLE MOBS WITHOUT DESTROYING EVERYTHING. Higher speed is slower, negative speed is faster + + //LETTING SIMPLE ANIMALS ATTACK? WHAT COULD GO WRONG. Defaults to zero so Ian can still be cuddly + var/melee_damage_lower = 0 + var/melee_damage_upper = 0 + var/attacktext = "attacked" + var/attack_sound = null + var/attacked_sound = null + var/friendly = "nuzzles" + var/environment_smash = 0 + var/resistance = 0 // Damage reduction + + //Null rod stuff + var/supernatural = 0 + var/purge = 0 + + // contained in a cage + var/in_stasis = 0 + + var/dodge_chance = 15 + var/list/pain_sound = list() + var/bloody = TRUE //whether or not this thing drops blood when you harvest from it. + var/butchered = FALSE + var/delete_after_harvest = TRUE + +/mob/living/simple_animal/Life() + ..() + if(!living_observers_present(GetConnectedZlevels(z))) + return + //Health + if(stat == DEAD) + if(health > 0) + icon_state = icon_living + switch_from_dead_to_living_mob_list() + set_stat(CONSCIOUS) + set_density(1) + return 0 + + + if(health <= 0) + death() + return + + if(health > maxHealth) + health = maxHealth + + handle_stunned() + handle_weakened() + handle_paralysed() + handle_supernatural() + + //Movement + if(!client && !stop_automated_movement && wander && !anchored) + if(isturf(src.loc) && !resting && !buckled && canmove) //This is so it only moves if it's not inside a closet, gentics machine, etc. + turns_since_move++ + if(turns_since_move >= turns_per_move) + if(!(stop_automated_movement_when_pulled && pulledby)) //Soma animals don't move when pulled + var/moving_to = 0 // otherwise it always picks 4, fuck if I know. Did I mention fuck BYOND + moving_to = pick(GLOB.cardinal) + set_dir(moving_to) //How about we turn them the direction they are moving, yay. + Move(get_step(src,moving_to)) + turns_since_move = 0 + + //Speaking + if(!client && speak_chance) + if(rand(0,200) < speak_chance) + var/action = pick( + speak.len; "speak", + emote_hear.len; "emote_hear", + emote_see.len; "emote_see" + ) + + switch(action) + if("speak") + say(pick(speak)) + if("emote_hear") + audible_emote("[pick(emote_hear)].") + if("emote_see") + visible_emote("[pick(emote_see)].") + + if(in_stasis) + return 1 // return early to skip atmos checks + + //Atmos + var/atmos_suitable = 1 + + var/atom/A = loc + if(!loc) + return 1 + var/datum/gas_mixture/environment = A.return_air() + + if(environment) + if( abs(environment.temperature - bodytemperature) > 40 ) + bodytemperature += (environment.temperature - bodytemperature) / 5 + if(min_gas) + for(var/gas in min_gas) + if(environment.gas[gas] < min_gas[gas]) + atmos_suitable = 0 + if(max_gas) + for(var/gas in max_gas) + if(environment.gas[gas] > max_gas[gas]) + atmos_suitable = 0 + + //Atmos effect + if(bodytemperature < minbodytemp) + fire_alert = 2 + adjustBruteLoss(cold_damage_per_tick) + else if(bodytemperature > maxbodytemp) + fire_alert = 1 + adjustBruteLoss(heat_damage_per_tick) + else + fire_alert = 0 + + if(!atmos_suitable) + adjustBruteLoss(unsuitable_atoms_damage) + return 1 + +/mob/living/simple_animal/proc/handle_supernatural() + if(purge) + purge -= 1 + +/mob/living/simple_animal/gib() + ..(icon_gib,1) + +/mob/living/simple_animal/proc/visible_emote(var/act_desc) + custom_emote(1, act_desc) + +/mob/living/simple_animal/proc/audible_emote(var/act_desc) + custom_emote(2, act_desc) + +/mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj) + if(!Proj || Proj.nodamage) + return + + adjustBruteLoss(Proj.damage) + return 0 + +/mob/living/simple_animal/attack_hand(mob/living/carbon/human/M as mob) + ..() + + switch(M.a_intent) + + if(I_HELP) + if (health > 0) + M.visible_message("[M] [response_help] \the [src]") + + if(I_DISARM) + M.visible_message("[M] [response_disarm] \the [src]") + //TODO: Push the mob away or something + + if(I_HURT) + if(!stat) + if(prob(dodge_chance)) + do_dodge() + return + adjustBruteLoss(harm_intent_damage) + M.visible_message("[M] [response_harm] \the [src]") + + return + +/mob/living/simple_animal/attackby(var/obj/item/O, var/mob/user) + if(istype(O, /obj/item/stack/medical)) + if(stat != DEAD) + var/obj/item/stack/medical/MED = O + if(!MED.animal_heal) + to_chat(user, "That [MED] won't help \the [src] at all!") + return + if(health < maxHealth) + if(MED.amount >= 1) + adjustBruteLoss(-MED.animal_heal) + MED.amount -= 1 + if(MED.amount <= 0) + qdel(MED) + for(var/mob/M in viewers(src, null)) + if ((M.client && !( M.blinded ))) + M.show_message("[user] applies the [MED] on [src].") + else + to_chat(user, "\The [src] is dead, medical items won't bring \him back to life.") + return + if(meat_type && (stat == DEAD)) //if the animal has a meat, and if it is dead. + if(istype(O, /obj/item/weapon/material/knife) || istype(O, /obj/item/weapon/material/knife/butch) || istype(O, /obj/item/weapon/material/sword))//Swords work too. + if(!butchered) + playsound(src, 'sound/weapons/pierce.ogg', 100, FALSE) + if(do_after(user, 30, src)) + harvest(user) + else + if(!O.force) + visible_message("[user] gently taps [src] with \the [O].") + else + O.attack(src, user, user.zone_sel.selecting) + +/mob/living/simple_animal/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone) + + if(!stat) + if(prob(dodge_chance)) + do_dodge() + return 2 + + visible_message("[user] [O.attack_verb.len? pick(O.attack_verb) : "attacked"] \the [src] in [hit_zone] with \the [O].") + + if(O.force <= resistance) + to_chat(user, "This weapon is ineffective, it does no damage.") + return 2 + + var/damage = O.force + if (O.damtype == PAIN) + damage = 0 + if(supernatural && istype(O,/obj/item/weapon/nullrod)) + damage *= 2 + purge = 3 + adjustBruteLoss(damage) + + if(attacked_sound) + playsound(src, attacked_sound, 50) + if(pain_sound.len) + var/hurt_sound = pick(pain_sound) + playsound(src, hurt_sound, 100, FALSE) + receive_damage() + + return 0 + +/mob/living/simple_animal/movement_delay() + var/tally = ..() //Incase I need to add stuff other than "speed" later + + tally += speed + if(purge)//Purged creatures will move more slowly. The more time before their purge stops, the slower they'll move. + if(tally <= 0) + tally = 1 + tally *= purge + + return tally+config.animal_delay + +/mob/living/simple_animal/Stat() + . = ..() + + if(statpanel("Status") && show_stat_health) + stat(null, "Health: [round((health / maxHealth) * 100)]%") + +/mob/living/simple_animal/death(gibbed, deathmessage = "dies!", show_dead_message) + icon_state = icon_dead + density = 0 + //adjustBruteLoss(maxHealth) //Make sure dey dead. //fuck you + health = min(0,health) + walk_to(src,0) + return ..(gibbed,deathmessage,show_dead_message) + +/mob/living/simple_animal/ex_act(severity) + if(!blinded) + flash_eyes() + + var/damage + switch (severity) + if (1.0) + damage = 500 + if(!prob(getarmor(null, "bomb"))) + gib() + + if (2.0) + damage = 120 + + if(3.0) + damage = 30 + + adjustBruteLoss(damage * blocked_mult(getarmor(null, "bomb"))) + +/mob/living/simple_animal/updatehealth() + ..() + if(stat != DEAD && health <= 0) + death() + +/mob/living/simple_animal/adjustBruteLoss(damage) + ..() + updatehealth() + +/mob/living/simple_animal/adjustFireLoss(damage) + ..() + updatehealth() + +/mob/living/simple_animal/adjustToxLoss(damage) + ..() + updatehealth() + +/mob/living/simple_animal/adjustOxyLoss(damage) + ..() + updatehealth() + +/mob/living/simple_animal/proc/SA_attackable(target_mob) + if (isliving(target_mob)) + var/mob/living/L = target_mob + if(!L.stat && L.health >= 0) + return (0) + if (istype(target_mob,/obj/mecha)) + var/obj/mecha/M = target_mob + if (M.occupant) + return (0) + return 1 + +/mob/living/simple_animal/say(var/message) + var/verb = "says" + if(speak_emote.len) + verb = pick(speak_emote) + + message = sanitize(message) + + ..(message, null, verb) + +/mob/living/simple_animal/get_speech_ending(verb, var/ending) + return verb + +/mob/living/simple_animal/put_in_hands(var/obj/item/W) // No hands. + W.loc = get_turf(src) + return 1 + +// Harvest an animal's delicious byproducts +/mob/living/simple_animal/proc/harvest(var/mob/user) + if(butchered) + to_chat(user, "") + var/actual_meat_amount = max(1,(meat_amount/2)) + if(meat_type && actual_meat_amount>0 && (stat == DEAD)) + for(var/i=0;i[user] butchers \the [src]!") + if(bloody) + new/obj/effect/decal/cleanable/blood/splatter(get_turf(src)) + if(delete_after_harvest) + qdel(src) + else + butchered = TRUE + else + user.visible_message("[user] butchers \the [src] messily!") + gib() + +/mob/living/simple_animal/handle_fire() + return + +/mob/living/simple_animal/update_fire() + return +/mob/living/simple_animal/IgniteMob() + return +/mob/living/simple_animal/ExtinguishMob() + return diff --git a/code/modules/mob/living/simple_animal/worm.dm b/code/modules/mob/living/simple_animal/worm.dm new file mode 100644 index 00000000..8fa8253c --- /dev/null +++ b/code/modules/mob/living/simple_animal/worm.dm @@ -0,0 +1,194 @@ +/mob/living/simple_animal/space_worm + name = "space worm segment" + desc = "A part of a space worm." + icon = 'icons/mob/animal.dmi' + icon_state = "spaceworm" + icon_living = "spaceworm" + icon_dead = "spacewormdead" + status_flags = 0 + + speak_emote = list("transmits") //not supposed to be used under AI control + emote_hear = list("transmits") //I'm just adding it so it doesn't runtime if controlled by player who speaks + + response_help = "touches" + response_disarm = "flails at" + response_harm = "punches the" + + harm_intent_damage = 2 + + maxHealth = 30 + health = 30 + + universal_speak =1 + + stop_automated_movement = 1 + animate_movement = SYNC_STEPS + + minbodytemp = 0 + maxbodytemp = 350 + min_gas = null + max_gas = null + + a_intent = I_HURT //so they don't get pushed around + + environment_smash = 2 + + speed = -1 + + var/mob/living/simple_animal/space_worm/previous //next/previous segments, correspondingly + var/mob/living/simple_animal/space_worm/next //head is the nextest segment + + var/stomachProcessProbability = 50 + var/digestionProbability = 20 + var/flatPlasmaValue = 5 //flat plasma amount given for non-items + + var/atom/currentlyEating //what the worm is currently eating + var/eatingDuration = 0 //how long he's been eating it for + + head + name = "space worm head" + icon_state = "spacewormhead" + icon_living = "spacewormhead" + icon_dead = "spacewormdead" + + maxHealth = 20 + health = 20 + + melee_damage_lower = 10 + melee_damage_upper = 15 + attacktext = "bitten" + + animate_movement = SLIDE_STEPS + + New(var/location, var/segments = 6) + ..() + + var/mob/living/simple_animal/space_worm/current = src + + for(var/i = 1 to segments) + var/mob/living/simple_animal/space_worm/newSegment = new /mob/living/simple_animal/space_worm(loc) + current.Attach(newSegment) + current = newSegment + + update_icon() + if(stat == CONSCIOUS || stat == UNCONSCIOUS) + icon_state = "spacewormhead[previous?1:0]" + if(previous) + set_dir(get_dir(previous,src)) + else + icon_state = "spacewormheaddead" + + Life() + ..() + + if(next && !(next in view(src,1))) + Detach() + + if(stat == DEAD) //dead chunks fall off and die immediately + if(previous) + previous.Detach() + if(next) + Detach(1) + + if(prob(stomachProcessProbability)) + ProcessStomach() + + update_icon() + + return + + Destroy() //if a chunk a destroyed, make a new worm out of the split halves + if(previous) + previous.Detach() + . = ..() + + Move() + var/attachementNextPosition = loc + if(..()) + if(previous) + previous.Move(attachementNextPosition) + update_icon() + + Bump(atom/obstacle) + if(currentlyEating != obstacle) + currentlyEating = obstacle + eatingDuration = 0 + + if(!AttemptToEat(obstacle)) + eatingDuration++ + else + currentlyEating = null + eatingDuration = 0 + + return + + update_icon() //only for the sake of consistency with the other update icon procs + if(stat == CONSCIOUS || stat == UNCONSCIOUS) + if(previous) //midsection + icon_state = "spaceworm[get_dir(src,previous) | get_dir(src,next)]" //see 3 lines below + else //tail + icon_state = "spacewormtail" + set_dir(get_dir(src,next)) //next will always be present since it's not a head and if it's dead, it goes in the other if branch + else + icon_state = "spacewormdead" + + return + + proc/AttemptToEat(var/atom/target) + if(istype(target,/turf/simulated/wall)) + var/turf/simulated/wall/W = target + if((!W.is_reinf() && eatingDuration >= 100) || eatingDuration >= 200) //need 20 ticks to eat an rwall, 10 for a regular one + W.dismantle_wall() + return 1 + else if(istype(target,/atom/movable)) + if(istype(target,/mob) || eatingDuration >= 50) //5 ticks to eat stuff like airlocks + var/atom/movable/objectOrMob = target + contents += objectOrMob + return 1 + + return 0 + + proc/Attach(var/mob/living/simple_animal/space_worm/attachement) + if(!attachement) + return + + previous = attachement + attachement.next = src + + return + + proc/Detach(die = 0) + var/mob/living/simple_animal/space_worm/newHead = new /mob/living/simple_animal/space_worm/head(loc,0) + + newHead.Attach(src) + + if(die) + newHead.death() + + proc/ProcessStomach() + for(var/atom/movable/stomachContent in contents) + if(prob(digestionProbability)) + if(istype(stomachContent,/obj/item/stack)) //converts to plasma, keeping the stack value + if(!istype(stomachContent,/obj/item/stack/material/phoron)) + var/obj/item/stack/oldStack = stomachContent + new /obj/item/stack/material/phoron(src, oldStack.get_amount()) + qdel(oldStack) + continue + else if(istype(stomachContent,/obj/item)) //converts to plasma, keeping the w_class + var/obj/item/oldItem = stomachContent + new /obj/item/stack/material/phoron(src, oldItem.w_class) + qdel(oldItem) + continue + else + new /obj/item/stack/material/phoron(src, flatPlasmaValue) //just flat amount + qdel(stomachContent) + continue + + if(previous) + for(var/atom/movable/stomachContent in contents) //transfer it along the digestive tract + previous.contents += stomachContent + else + for(var/atom/movable/stomachContent in contents) //or poop it out + loc.contents += stomachContent + + return diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm new file mode 100644 index 00000000..86d91718 --- /dev/null +++ b/code/modules/mob/login.dm @@ -0,0 +1,99 @@ +//handles setting lastKnownIP and computer_id for use by the ban systems as well as checking for multikeying +/mob/proc/update_Login_details() + var/serbname = "[server_name]: [station_name()]" + winset(src, null, "mainwindow.title='[serbname]'") + //Multikey checks and logging + lastKnownIP = client.address + computer_id = client.computer_id + log_access("Login: [key_name(src)] from [lastKnownIP ? lastKnownIP : "localhost"]-[computer_id] || BYOND v[client.byond_version]") + if(config.log_access) + var/is_multikeying = 0 + for(var/mob/M in GLOB.player_list) + if(M == src) continue + if( M.key && (M.key != key) ) + var/matches + if( (M.lastKnownIP == client.address) ) + matches += "IP ([client.address])" + if( (client.connection != "web") && (M.computer_id == client.computer_id) ) + if(matches) matches += " and " + matches += "ID ([client.computer_id])" + is_multikeying = 1 + if(matches) + if(M.client) + message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(M)].", 1) + log_access("Notice: [key_name(src)] has the same [matches] as [key_name(M)].") + else + message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(M)] (no longer logged in). ", 1) + log_access("Notice: [key_name(src)] has the same [matches] as [key_name(M)] (no longer logged in).") + if(is_multikeying && !client.warned_about_multikeying) + client.warned_about_multikeying = 1 + spawn(1 SECOND) + to_chat(src, "WARNING: It would seem that you are sharing connection or computer with another player. If you haven't done so already, please contact the staff via the Adminhelp verb to resolve this situation. Failure to do so may result in administrative action. You have been warned.") + + if(config.login_export_addr) + spawn(-1) + var/list/params = new + params["login"] = 1 + params["key"] = client.key + if(isnum(client.player_age)) + params["server_age"] = client.player_age + params["ip"] = client.address + params["clientid"] = client.computer_id + params["roundid"] = game_id + params["name"] = real_name || name + world.Export("[config.login_export_addr]?[list2params(params)]", null, 1) + var/savefile/F = new /savefile("data/player_saves/[copytext(ckey, 1, 2)]/[ckey]/achievements.sav") + client.achievement_holder.Read(F) + +/mob/proc/maybe_send_staffwarns(var/action) + if(client.staffwarn) + for(var/client/C in GLOB.admins) + send_staffwarn(C, action) + +/mob/proc/send_staffwarn(var/client/C, var/action, var/noise = 1) + if(check_rights((R_ADMIN|R_MOD),0,C)) + to_chat(C,"StaffWarn: [client.ckey] [action]
            [client.staffwarn]") + if(noise && C.get_preference_value(/datum/client_preference/staff/play_adminhelp_ping) == GLOB.PREF_HEAR) + sound_to(C, 'sound/effects/adminhelp.ogg') + +/mob + var/client/my_client // Need to keep track of this ourselves, since by the time Logout() is called the client has already been nulled + +/mob/Login() + + GLOB.player_list |= src + update_Login_details() + world.update_status() + + maybe_send_staffwarns("joined the round") + + client.images = null //remove the images such as AIs being unable to see runes + client.screen = list() //remove hud items just in case + InitializeHud() + + next_move = 1 + set_sight(sight|SEE_SELF) + ..() + + my_client = client + + if(loc && !isturf(loc)) + client.eye = loc + client.perspective = EYE_PERSPECTIVE + else + client.eye = src + client.perspective = MOB_PERSPECTIVE + + if(eyeobj) + eyeobj.possess(src) + + refresh_client_images() + reload_fullscreen() // Reload any fullscreen overlays this mob has. + add_click_catcher() + winset(src, "name", "text='[real_name]'") + + //set macro to normal incase it was overriden (like cyborg currently does) + winset(src, null, "mainwindow.macro=hotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true") + + if(warfare_faction)//If they are on a team already, then keep them on that team. + client.warfare_faction = warfare_faction \ No newline at end of file diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm new file mode 100644 index 00000000..c7a52eaf --- /dev/null +++ b/code/modules/mob/logout.dm @@ -0,0 +1,21 @@ +/mob/Logout() + GLOB.nanomanager.user_logout(src) // this is used to clean up (remove) this user's Nano UIs + tgui_process && tgui_process.on_logout(src) + GLOB.player_list -= src + log_access("Logout: [key_name(src)]") + handle_admin_logout() + hide_client_images() + ..() + + my_client = null + return 1 + +/mob/proc/handle_admin_logout() + if(admin_datums[ckey] && ticker && ticker.current_state == GAME_STATE_PLAYING) //Only report this stuff if we are currently playing. + var/datum/admins/holder = admin_datums[ckey] + message_staff("[holder.rank] logout: [key_name(src)]") + if(!GLOB.admins.len) //Apparently the admin logging out is no longer an admin at this point, so we have to check this towards 0 and not towards 1. Awell. + send2adminirc("[key_name(src)] logged out - no more admins online.") + if(config.delist_when_no_admins && GLOB.visibility_pref) + world.update_hub_visibility() + send2adminirc("Toggled hub visibility. The server is now invisible ([GLOB.visibility_pref]).") \ No newline at end of file diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm new file mode 100644 index 00000000..43163971 --- /dev/null +++ b/code/modules/mob/mob.dm @@ -0,0 +1,1152 @@ +/mob/Destroy()//This makes sure that mobs with clients/keys are not just deleted from the game. + STOP_PROCESSING(SSmobs, src) + GLOB.dead_mob_list_ -= src + GLOB.living_mob_list_ -= src + unset_machine() + QDEL_NULL(hud_used) + for(var/obj/item/grab/G in grabbed_by) + qdel(G) + clear_fullscreen() + if(client) + remove_screen_obj_references() + for(var/atom/movable/AM in client.screen) + var/obj/screen/screenobj = AM + if(!istype(screenobj) || !screenobj.globalscreen) + qdel(screenobj) + client.screen = list() + if(mind && mind.current == src) + spellremove(src) + ghostize() + ..() + return QDEL_HINT_HARDDEL + +/mob/proc/remove_screen_obj_references() + hands = null + pullin = null + purged = null + internals = null + oxygen = null + i_select = null + m_select = null + toxin = null + fire = null + bodytemp = null + healths = null + throw_icon = null + nutrition_icon = null + pressure = null + pain = null + item_use_icon = null + gun_move_icon = null + gun_setting_icon = null + ability_master = null + zone_sel = null + +/mob/Initialize() + . = ..() + START_PROCESSING(SSmobs, src) + +/mob/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2) + if(!client) return + + //spaghetti code + if(type) + if((type & VISIBLE_MESSAGE) && is_blind())//Vision related + if(!alt) + return + else + msg = alt + type = alt_type + if((type & AUDIBLE_MESSAGE) && is_deaf())//Hearing related + if(!alt) + return + else + msg = alt + type = alt_type + if(((type & VISIBLE_MESSAGE) && is_blind())) + return + + to_chat(src, msg) + + +// Show a message to all mobs and objects in sight of this one +// This would be for visible actions by the src mob +// message is the message output to anyone who can see e.g. "[src] does something!" +// self_message (optional) is what the src mob sees e.g. "You do something!" +// blind_message (optional) is what blind people will hear e.g. "You hear something!" +/mob/visible_message(var/message, var/self_message, var/blind_message, var/range = world.view, var/checkghosts = null, var/narrate = FALSE) + var/turf/T = get_turf(src) + var/list/mobs = list() + var/list/objs = list() + get_mobs_and_objs_in_view_fast(T,range, mobs, objs, checkghosts) + + for(var/o in objs) + var/obj/O = o + O.show_message(message, VISIBLE_MESSAGE, blind_message, AUDIBLE_MESSAGE) + + for(var/m in mobs) + var/mob/M = m + if(self_message && M == src) + M.show_message(self_message, VISIBLE_MESSAGE, blind_message, AUDIBLE_MESSAGE) + continue + + if(M.see_invisible >= invisibility || narrate) + M.show_message(message, VISIBLE_MESSAGE, blind_message, AUDIBLE_MESSAGE) + continue + + if(blind_message) + M.show_message(blind_message, AUDIBLE_MESSAGE) + continue + //Multiz, have shadow do same + if(shadow) + shadow.visible_message(message, self_message, blind_message) + +// Returns an amount of power drawn from the object (-1 if it's not viable). +// If drain_check is set it will not actually drain power, just return a value. +// If surge is set, it will destroy/damage the recipient and not return any power. +// Not sure where to define this, so it can sit here for the rest of time. +/atom/proc/drain_power(var/drain_check,var/surge, var/amount = 0) + return -1 + +// Show a message to all mobs and objects in earshot of this one +// This would be for audible actions by the src mob +// message is the message output to anyone who can hear. +// self_message (optional) is what the src mob hears. +// deaf_message (optional) is what deaf people will see. +// hearing_distance (optional) is the range, how many tiles away the message can be heard. +/mob/audible_message(var/message, var/self_message, var/deaf_message, var/hearing_distance = world.view, var/checkghosts = null, var/narrate = FALSE) + var/turf/T = get_turf(src) + var/list/mobs = list() + var/list/objs = list() + get_mobs_and_objs_in_view_fast(T, hearing_distance, mobs, objs, checkghosts) + + for(var/m in mobs) + var/mob/M = m + if(self_message && M == src) + M.show_message(self_message, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE) + else if(M.see_invisible >= invisibility || narrate) // Cannot view the invisible + M.show_message(message, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE) + else + M.show_message(message, AUDIBLE_MESSAGE) + + for(var/o in objs) + var/obj/O = o + O.show_message(message, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE) + +/mob/proc/findname(msg) + for(var/mob/M in SSmobs.mob_list) + if (M.real_name == msg) + return M + return 0 + +/mob/proc/movement_delay() + . = 0 + if(istype(loc, /turf)) + var/turf/T = loc + . += T.movement_delay + if(pulling) + if(istype(pulling, /obj)) + var/obj/O = pulling + . += between(0, O.w_class, ITEM_SIZE_GARGANTUAN) / 5 + else if(istype(pulling, /mob)) + var/mob/M = pulling + . += max(0, M.mob_size) / MOB_MEDIUM + else + . += 1 + +/mob/proc/Life() +// if(organStructure) +// organStructure.ProcessOrgans() + return + +#define UNBUCKLED 0 +#define PARTIALLY_BUCKLED 1 +#define FULLY_BUCKLED 2 +/mob/proc/buckled() + // Preliminary work for a future buckle rewrite, + // where one might be fully restrained (like an elecrical chair), or merely secured (shuttle chair, keeping you safe but not otherwise restrained from acting) + if(!buckled) + return UNBUCKLED + return restrained() ? FULLY_BUCKLED : PARTIALLY_BUCKLED + +/mob/proc/is_blind() + return ((sdisabilities & BLIND) || blinded || incapacitated(INCAPACITATION_KNOCKOUT)) + +/mob/proc/is_deaf() + return ((sdisabilities & DEAF) || ear_deaf || incapacitated(INCAPACITATION_KNOCKOUT)) + +/mob/proc/is_physically_disabled() + return incapacitated(INCAPACITATION_DISABLED) + +/mob/proc/cannot_stand() + return incapacitated(INCAPACITATION_KNOCKDOWN) + +/mob/proc/incapacitated(var/incapacitation_flags = INCAPACITATION_DEFAULT) + + if ((incapacitation_flags & INCAPACITATION_STUNNED) && stunned) + return 1 + + if ((incapacitation_flags & INCAPACITATION_FORCELYING) && (weakened || resting || pinned.len)) + return 1 + + if ((incapacitation_flags & INCAPACITATION_KNOCKOUT) && (stat || paralysis || sleeping || (status_flags & FAKEDEATH))) + return 1 + + if((incapacitation_flags & INCAPACITATION_RESTRAINED) && restrained()) + return 1 + + if((incapacitation_flags & (INCAPACITATION_BUCKLED_PARTIALLY|INCAPACITATION_BUCKLED_FULLY))) + var/buckling = buckled() + if(buckling >= PARTIALLY_BUCKLED && (incapacitation_flags & INCAPACITATION_BUCKLED_PARTIALLY)) + return 1 + if(buckling == FULLY_BUCKLED && (incapacitation_flags & INCAPACITATION_BUCKLED_FULLY)) + return 1 + + return 0 + +#undef UNBUCKLED +#undef PARTIALLY_BUCKLED +#undef FULLY_BUCKLED + +/mob/proc/restrained() + return + +/mob/proc/reset_view(atom/A) + if (client) + A = A ? A : eyeobj + if (istype(A, /atom/movable)) + client.perspective = EYE_PERSPECTIVE + client.eye = A + else + if (isturf(loc)) + client.eye = client.mob + client.perspective = MOB_PERSPECTIVE + else + client.perspective = EYE_PERSPECTIVE + client.eye = loc + return + + +/mob/proc/show_inv(mob/user as mob) + return + +//mob verbs are faster than object verbs. See http://www.byond.com/forum/?post=1326139&page=2#comment8198716 for why this isn't atom/verb/examine() +/mob/proc/examinate(atom/A as mob|obj|turf in view()) + set name = "Examine" + set category = "IC" + + if((is_blind(src) || usr.stat) && !isobserver(src)) + to_chat(src, "Something is there but you can't see it.") + return 1 + + face_atom(A) + A.examine(src) + +/mob/proc/pointed(atom/A as mob|obj|turf in view()) + set name = "Point To" + set category = "Object" + + if(!src || !isturf(src.loc))// || !(A in view(src.loc))) + return 0 + if(istype(A, /obj/effect/decal/point)) + return 0 + + var/tile = get_turf(A) + if (!tile) + return 0 + + var/obj/P = new /obj/effect/decal/point(tile) + P.set_invisibility(invisibility) + spawn (20) + if(P) + qdel(P) // qdel + + face_atom(A) + return 1 + +//Gets the mob grab conga line. +/mob/proc/ret_grab(list/L) + if (!istype(l_hand, /obj/item/grab) && !istype(r_hand, /obj/item/grab)) + return L + if (!L) + L = list(src) + for(var/A in list(l_hand,r_hand)) + if (istype(A, /obj/item/grab)) + var/obj/item/grab/G = A + if (!(G.affecting in L)) + L += G.affecting + if (G.affecting) + G.affecting.ret_grab(L) + return L + +/mob/verb/mode() + set name = "Activate Held Object" + set category = "Object" + set src = usr + + if(istype(loc,/obj/mecha)) return + + if(!canClick()) // To stop people from spamming z to turbo click. + return + + if(hand) + var/obj/item/W = l_hand + if (W) + W.attack_self(src) + update_inv_l_hand() + else + var/obj/item/W = r_hand + if (W) + W.attack_self(src) + update_inv_r_hand() + return + +/* +/mob/verb/dump_source() + + var/master = "

            "
            +	for(var/t in typesof(/area))
            +		master += text("[]\n", t)
            +		//Foreach goto(26)
            +	src << browse(master)
            +	return
            +*/
            +
            +/mob/verb/memory()
            +	set name = "Notes"
            +	set category = "IC"
            +	if(mind)
            +		mind.show_memory(src)
            +	else
            +		to_chat(src, "The game appears to have misplaced your mind datum, so we can't show you your notes.")
            +/*
            +/mob/verb/add_memory(msg as message)
            +	set name = "Add Note"
            +	set category = "IC"
            +
            +	msg = sanitize(msg)
            +
            +	if(mind)
            +		mind.store_memory(msg)
            +	else
            +		to_chat(src, "The game appears to have misplaced your mind datum, so we can't show you your notes.")
            +
            +/mob/proc/store_memory(msg as message, popup, sane = 1)
            +	msg = copytext(msg, 1, MAX_MESSAGE_LEN)
            +
            +	if (sane)
            +		msg = sanitize(msg)
            +
            +	if (length(memory) == 0)
            +		memory += msg
            +	else
            +		memory += "
            [msg]" + + if (popup) + memory() +*/ + +/mob/proc/update_flavor_text() + set src in usr + if(usr != src) + to_chat(usr, "No.") + var/msg = sanitize(input(usr,"Set the flavor text in your 'examine' verb. Can also be used for OOC notes about your character.","Flavor Text",html_decode(flavor_text)) as message|null, extra = 0) + if(msg != null) + flavor_text = msg + +/mob/proc/warn_flavor_changed() + if(flavor_text && flavor_text != "") // don't spam people that don't use it! + to_chat(src, "

            OOC Warning:

            ") + to_chat(src, "Your flavor text is likely out of date! Change") + +/mob/proc/print_flavor_text() + if (flavor_text && flavor_text != "") + var/msg = replacetext(flavor_text, "\n", " ") + if(length(msg) <= 40) + return "[msg]" + else + return "[copytext_preserve_html(msg, 1, 37)]... More..." + +/* +/mob/verb/help() + set name = "Help" + src << browse('html/help.html', "window=help") + return +*/ + +/client/verb/changes() + set name = "Changelog" + set category = "OOC" + getFiles( + 'html/88x31.png', + 'html/bug-minus.png', + 'html/burn-exclamation.png', + 'html/chevron.png', + 'html/chevron-expand.png', + 'html/cross-circle.png', + 'html/hard-hat-exclamation.png', + 'html/image-minus.png', + 'html/image-plus.png', + 'html/map-pencil.png', + 'html/music-minus.png', + 'html/music-plus.png', + 'html/tick-circle.png', + 'html/scales.png', + 'html/spell-check.png', + 'html/wrench-screwdriver.png', + 'html/changelog.css', + 'html/changelog.html' + ) + src << browse('html/changelog.html', "window=changes;size=675x650") + if(prefs.lastchangelog != changelog_hash) + prefs.lastchangelog = changelog_hash + prefs.save_preferences() + winset(src, "rpane.changelog", "background-color=none;font-style=;") + +/mob/new_player/verb/observe() + set name = "Observe" + set category = "OOC" + + if(!(initialization_stage&INITIALIZATION_COMPLETE)) + to_chat(src, "Please wait for server initialization to complete...") + return + + return + + var/is_admin = 0 + + if(client.holder && (client.holder.rights & R_ADMIN)) + is_admin = 1 + + if(is_admin && stat == DEAD) + is_admin = 0 + + var/list/names = list() + var/list/namecounts = list() + var/list/creatures = list() + + for(var/obj/O in world) //EWWWWWWWWWWWWWWWWWWWWWWWW ~needs to be optimised + if(!O.loc) + continue + if(istype(O, /obj/item/weapon/disk/nuclear)) + var/name = "Nuclear Disk" + if (names.Find(name)) + namecounts[name]++ + name = "[name] ([namecounts[name]])" + else + names.Add(name) + namecounts[name] = 1 + creatures[name] = O + + if(istype(O, /obj/singularity)) + var/name = "Singularity" + if (names.Find(name)) + namecounts[name]++ + name = "[name] ([namecounts[name]])" + else + names.Add(name) + namecounts[name] = 1 + creatures[name] = O + + for(var/mob/M in sortAtom(SSmobs.mob_list)) + var/name = M.name + if (names.Find(name)) + namecounts[name]++ + name = "[name] ([namecounts[name]])" + else + names.Add(name) + namecounts[name] = 1 + + creatures[name] = M + + + client.perspective = EYE_PERSPECTIVE + + var/eye_name = null + + var/ok = "[is_admin ? "Admin Observe" : "Observe"]" + eye_name = input("Please, select a player!", ok, null, null) as null|anything in creatures + + if (!eye_name) + return + + var/mob/mob_eye = creatures[eye_name] + + if(client && mob_eye) + client.eye = mob_eye + if (is_admin) + client.adminobs = 1 + if(mob_eye == client.mob || client.eye == client.mob) + client.adminobs = 0 + +/mob/verb/cancel_camera() + set name = "Cancel Camera View" + set category = "OOC" + unset_machine() + reset_view(null) + +/mob/Topic(href, href_list) + if(href_list["mach_close"]) + var/t1 = text("window=[href_list["mach_close"]]") + unset_machine() + src << browse(null, t1) + + if(href_list["flavor_more"]) + usr << browse(text("[][]", name, replacetext(flavor_text, "\n", "
            ")), text("window=[];size=500x200", name)) + onclose(usr, "[name]") + if(href_list["flavor_change"]) + update_flavor_text() + return + +/mob/proc/pull_damage() + return 0 + +/mob/living/carbon/human/pull_damage() + if(!lying || getBruteLoss() + getFireLoss() < 100) + return 0 + for(var/thing in organs) + var/obj/item/organ/external/e = thing + if(!e || e.is_stump()) + continue + if((e.status & ORGAN_BROKEN) && !e.splinted) + return 1 + if(e.status & ORGAN_BLEEDING) + return 1 + return 0 + +/mob/MouseDrop(mob/M as mob) + ..() + if(M != usr) return + if(usr == src) return + if(!Adjacent(usr)) return + if(istype(M,/mob/living/silicon/ai)) return + show_inv(usr) + + +/mob/verb/stop_pulling() + + set name = "Stop Pulling" + set category = "IC" + + if(pulling) + pulling.pulledby = null + pulling = null + if(pullin) + pullin.icon_state = "pull0" + +/mob/proc/start_pulling(var/atom/movable/AM) + + if ( !AM || !usr || src==AM || !isturf(src.loc) ) //if there's no person pulling OR the person is pulling themself OR the object being pulled is inside something: abort! + return + + if (AM.anchored) + to_chat(src, "It won't budge!") + return + + var/mob/M = AM + if(ismob(AM)) + + if(!can_pull_mobs || !can_pull_size) + to_chat(src, "It won't budge!") + return + + if((mob_size < M.mob_size) && (can_pull_mobs != MOB_PULL_LARGER)) + to_chat(src, "It won't budge!") + return + + if((mob_size == M.mob_size) && (can_pull_mobs == MOB_PULL_SMALLER)) + to_chat(src, "It won't budge!") + return + + // If your size is larger than theirs and you have some + // kind of mob pull value AT ALL, you will be able to pull + // them, so don't bother checking that explicitly. + + if(!iscarbon(src)) + M.LAssailant = null + else + M.LAssailant = usr + + else if(isobj(AM)) + var/obj/I = AM + if(!can_pull_size || can_pull_size < I.w_class) + to_chat(src, "It won't budge!") + return + + if(pulling) + var/pulling_old = pulling + stop_pulling() + // Are we pulling the same thing twice? Just stop pulling. + if(pulling_old == AM) + return + + src.pulling = AM + AM.pulledby = src + + if(pullin) + pullin.icon_state = "pull1" + + //Attempted fix for people flying away through space when cuffed and dragged. + if(ismob(AM)) + var/mob/pulled = AM + pulled.inertia_dir = 0 + +/mob/proc/can_use_hands() + return + +/mob/proc/is_active() + return (0 >= usr.stat) + +/mob/proc/is_dead() + return stat == DEAD + +/mob/proc/is_mechanical() + if(mind && (mind.assigned_role == "Cyborg" || mind.assigned_role == "AI")) + return 1 + return istype(src, /mob/living/silicon) || get_species() == SPECIES_IPC + +/mob/proc/is_ready() + return client && !!mind + +/mob/proc/get_gender() + return gender + +/mob/proc/see(message) + if(!is_active()) + return 0 + to_chat(src, message) + return 1 + +/mob/proc/show_viewers(message) + for(var/mob/M in viewers()) + M.see(message) + +/mob/Stat() + ..() + . = (is_client_active(10 MINUTES)) + if(!.) + return + + if(statpanel("Status")) + if(ticker && ticker.current_state != GAME_STATE_PREGAME) + //stat("Local Time", stationtime2text()) + //stat("Local Date", stationdate2text()) + stat("Round Duration", roundduration2text()) + if(client.holder || isghost(client.mob)) + stat("Location:", "([x], [y], [z]) [loc]") + + if(client.holder) + if(statpanel("Processes") && processScheduler) + processScheduler.statProcesses() + if(statpanel("MC")) + stat("CPU:","[world.cpu]") + stat("Instances:","[world.contents.len]") + stat(null) + if(Master) + Master.stat_entry() + else + stat("Master Controller:", "ERROR") + if(Failsafe) + Failsafe.stat_entry() + else + stat("Failsafe Controller:", "ERROR") + if(Master) + stat(null) + for(var/datum/controller/subsystem/SS in Master.subsystems) + SS.stat_entry() + + if(listed_turf && client) + if(!TurfAdjacent(listed_turf)) + listed_turf = null + else + if(statpanel("Turf")) + stat(listed_turf) + for(var/atom/A in listed_turf) + if(!A.mouse_opacity) + continue + if(A.invisibility > see_invisible) + continue + if(is_type_in_list(A, shouldnt_see)) + continue + stat(A) + + +// facing verbs +/mob/proc/canface() + if(!canmove) return 0 + if(anchored) return 0 + if(transforming) return 0 + return 1 + +// Not sure what to call this. Used to check if humans are wearing an AI-controlled exosuit and hence don't need to fall over yet. +/mob/proc/can_stand_overridden() + return 0 + +//Updates canmove, lying and icons. Could perhaps do with a rename but I can't think of anything to describe it. +/mob/proc/update_canmove() + + if(!resting && cannot_stand() && can_stand_overridden()) + lying = 0 + canmove = 1 + else if(buckled) + anchored = 1 + canmove = 0 + if(istype(buckled)) + if(buckled.buckle_lying == -1) + lying = incapacitated(INCAPACITATION_KNOCKDOWN) + else + lying = buckled.buckle_lying + if(buckled.buckle_movable) + anchored = 0 + canmove = 1 + else + lying = incapacitated(INCAPACITATION_KNOCKDOWN) + canmove = !incapacitated(INCAPACITATION_DISABLED) + + if(ishuman(src))//Check if they're a human. + if(lying && lying != lying_prev)//Check if they fell over. + if(!istype(src.loc, /turf/space))//Check if they're not in space. + playsound(src, "pratfall", 50)//Good now play fallsound. + + if(lying) + set_density(0) + crouching = FALSE//We aren't crouching if we're lying down. + else + set_density(initial(density)) + reset_layer() + + for(var/obj/item/grab/G in grabbed_by) + if(G.stop_move()) + canmove = 0 + + if(G.force_stand()) + lying = 0 + crouching = FALSE + + //Temporarily moved here from the various life() procs + //I'm fixing stuff incrementally so this will likely find a better home. + //It just makes sense for now. ~Carn + if( update_icon ) //forces a full overlay update + update_icon = 0 + regenerate_icons() + else if(lying != lying_prev) + update_icons() + update_vision_cone() + + return canmove + +/mob/proc/reset_layer() + if(lying) + // plane = LYING_MOB_PLANE + layer = LYING_MOB_LAYER + else + layer = initial(layer) + //reset_plane_and_layer() + +/mob/proc/facedir(var/ndir) + if(!canface() || client.moving || world.time < client.move_delay) + return 0 + set_dir(ndir) + if(buckled && buckled.buckle_movable) + buckled.set_dir(ndir) + if(ndir != dir) + if(facing_dir) + facing_dir = ndir + facedir(ndir) + client.move_delay += movement_delay() + return 1 + + +/mob/verb/eastface() + set hidden = 1 + return facedir(client.client_dir(EAST)) + + +/mob/verb/westface() + set hidden = 1 + return facedir(client.client_dir(WEST)) + + +/mob/verb/northface() + set hidden = 1 + return facedir(client.client_dir(NORTH)) + + +/mob/verb/southface() + set hidden = 1 + return facedir(client.client_dir(SOUTH)) + + +//This might need a rename but it should replace the can this mob use things check +/mob/proc/IsAdvancedToolUser() + return 0 + +/mob/proc/Stun(amount) + if(status_flags & CANSTUN) + facing_dir = null + if(zoomed)//Zoom out here. + do_zoom() + stunned = max(max(stunned,amount),0) //can't go below 0, getting a low amount of stun doesn't lower your current stun + if(l_hand) unEquip(l_hand) + if(r_hand) unEquip(r_hand) + return + +/mob/proc/SetStunned(amount) //if you REALLY need to set stun to a set amount without the whole "can't go below current stunned" + if(status_flags & CANSTUN) + stunned = max(amount,0) + return + +/mob/proc/AdjustStunned(amount) + if(status_flags & CANSTUN) + stunned = max(stunned + amount,0) + return + +/mob/proc/Weaken(amount)//THIS SHOULD BE USED IN ALL BUT EXTREMELY SPECIFIC CASES! + if(status_flags & CANWEAKEN) + if(zoomed)//Zoom out here. + do_zoom() + facing_dir = null + weakened = max(max(weakened,amount),0) + update_canmove() //updates lying, canmove and icons + resting = 1 + fixeye?.icon_state = "fixeye" + if(/turf/simulated/open in src.loc) + var/turf/below = GetBelow(src.loc) + src.handle_fall(below) + return + +/mob/proc/SetWeakened(amount)//THIS SHOULD NOT BE USED TO STUN PEOPLE, ONLY TO UNSTUN THEM! + if(status_flags & CANWEAKEN) + weakened = max(amount,0) + update_canmove() //updates lying, canmove and icons + return + +/mob/proc/AdjustWeakened(amount)//THIS SHOULD ONLY EVER BE CALLED IF YOU ARE SUBTRACTING WEAKEN, OR ADDING WEAKEN WHEN SOMEONE IS ALREADY DOWN! + if(status_flags & CANWEAKEN) + weakened = max(weakened + amount,0) + update_canmove() //updates lying, canmove and icons + return + +//This proc knocks a mob over, and makes them drop what they're holding, making them have to get back up. +//Anywhere you see Stun(1) Weaken(1) replace it with this proc. +/mob/proc/KnockDown() + Stun(1) + Weaken(1) + +/mob/proc/Paralyse(amount) + if(status_flags & CANPARALYSE) + if(zoomed)//Zoom out here. + do_zoom() + facing_dir = null + paralysis = max(max(paralysis,amount),0) + if(l_hand) unEquip(l_hand) + if(r_hand) unEquip(r_hand) + resting = 1 + return + +/mob/proc/SetParalysis(amount) + if(status_flags & CANPARALYSE) + paralysis = max(amount,0) + return + +/mob/proc/AdjustParalysis(amount) + if(status_flags & CANPARALYSE) + paralysis = max(paralysis + amount,0) + return + +/mob/proc/Sleeping(amount) + facing_dir = null + sleeping = max(max(sleeping,amount),0) + if(l_hand) unEquip(l_hand) + if(r_hand) unEquip(r_hand) + resting =1 + return + +/mob/proc/SetSleeping(amount) + sleeping = max(amount,0) + return + +/mob/proc/AdjustSleeping(amount) + sleeping = max(sleeping + amount,0) + return + +/mob/proc/Resting(amount) + facing_dir = null + resting = max(max(resting,amount),0) + return + +/mob/proc/SetResting(amount) + resting = max(amount,0) + return + +/mob/proc/AdjustResting(amount) + resting = max(resting + amount,0) + return + +/mob/proc/get_species() + return "" + +/mob/proc/get_visible_implants(var/class = 0) + var/list/visible_implants = list() + for(var/obj/item/O in embedded) + if(O.w_class > class) + visible_implants += O + return visible_implants + +/mob/proc/embedded_needs_process() + return (embedded.len > 0) + +mob/proc/yank_out_object() + set category = "Object" + set name = "Yank out object" + set desc = "Remove an embedded item at the cost of bleeding and pain." + set src in view(1) + + if(!isliving(usr) || !usr.canClick()) + return + usr.setClickCooldown(20) + + if(usr.stat == 1) + to_chat(usr, "You are unconcious and cannot do that!") + return + + if(usr.restrained()) + to_chat(usr, "You are restrained and cannot do that!") + return + + var/mob/S = src + var/mob/U = usr + var/list/valid_objects = list() + var/self = null + + if(S == U) + self = 1 // Removing object from yourself. + + valid_objects = get_visible_implants(0) + if(!valid_objects.len) + if(self) + to_chat(src, "You have nothing stuck in your body that is large enough to remove.") + else + to_chat(U, "[src] has nothing stuck in their wounds that is large enough to remove.") + return + + var/obj/item/weapon/selection = input("What do you want to yank out?", "Embedded objects") in valid_objects + + if(self) + to_chat(src, "You attempt to get a good grip on [selection] in your body.") + else + to_chat(U, "You attempt to get a good grip on [selection] in [S]'s body.") + if(!do_mob(U, S, 30)) + return + if(!selection || !S || !U) + return + + if(self) + visible_message("[src] rips [selection] out of their body.","You rip [selection] out of your body.") + else + visible_message("[usr] rips [selection] out of [src]'s body.","[usr] rips [selection] out of your body.") + valid_objects = get_visible_implants(0) + if(valid_objects.len == 1) //Yanking out last object - removing verb. + src.verbs -= /mob/proc/yank_out_object + + if(ishuman(src)) + var/mob/living/carbon/human/H = src + var/obj/item/organ/external/affected + + 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 == selection) + affected = organ + + affected.implants -= selection + for(var/datum/wound/wound in affected.wounds) + wound.embedded_objects -= selection + + H.shock_stage+=20 + affected.take_damage((selection.w_class * 3), 0, DAM_EDGE, "Embedded object extraction") + + if(prob(selection.w_class * 5) && affected.sever_artery()) //I'M SO ANEMIC I COULD JUST -DIE-. + H.custom_pain("Something tears wetly in your [affected] as [selection] is pulled free!", 50, affecting = affected) + + if (ishuman(U)) + var/mob/living/carbon/human/human_user = U + human_user.bloody_hands(H) + + else if(issilicon(src)) + var/mob/living/silicon/robot/R = src + R.embedded -= selection + R.adjustBruteLoss(5) + R.adjustFireLoss(10) + + selection.forceMove(get_turf(src)) + if(!(U.l_hand && U.r_hand)) + U.put_in_hands(selection) + + for(var/obj/item/weapon/O in pinned) + if(O == selection) + pinned -= O + if(!pinned.len) + anchored = 0 + return 1 + +//Check for brain worms in head. +/mob/proc/has_brain_worms() + + for(var/I in contents) + if(istype(I,/mob/living/simple_animal/borer)) + return I + + return 0 + +/mob/update_icon() + return + +/mob/verb/set_fixeye()//For macros. + set name = "set-fixeye" + set hidden = TRUE + face_direction() + + +/mob/proc/face_direction() + if(zoomed) + to_chat(src, "I am focused in right now, I cannot look away.") + return + set_face_dir() + + +/mob/proc/set_face_dir(var/newdir) + if(newdir == FALSE) + facing_dir = null + else if(!isnull(facing_dir) && newdir == facing_dir) + facing_dir = null + else if(newdir) + set_dir(newdir) + facing_dir = newdir + else if(facing_dir) + facing_dir = null + else + set_dir(dir) + facing_dir = dir + if(!fixeye) + return + //Ok we have the fixeye icon... + if(facing_dir) + fixeye.icon_state = "fixeye_on" + else + fixeye.icon_state = "fixeye" + +/mob/set_dir() + if(facing_dir) + if(!canface() || lying || buckled || restrained()) + facing_dir = null + else if(dir != facing_dir) + return ..(facing_dir) + else + return ..() + +/mob/proc/set_stat(var/new_stat) + . = stat != new_stat + stat = new_stat + +/mob/verb/northfaceperm() + set hidden = 1 + set_face_dir(client.client_dir(NORTH)) + +/mob/verb/southfaceperm() + set hidden = 1 + set_face_dir(client.client_dir(SOUTH)) + +/mob/verb/eastfaceperm() + set hidden = 1 + set_face_dir(client.client_dir(EAST)) + +/mob/verb/westfaceperm() + set hidden = 1 + set_face_dir(client.client_dir(WEST)) + +/mob/proc/adjustEarDamage() + return + +/mob/proc/setEarDamage() + return + +//Throwing stuff + +/mob/proc/toggle_throw_mode() + if (src.in_throw_mode) + throw_mode_off() + else + throw_mode_on() + +/mob/proc/throw_mode_off() + src.in_throw_mode = 0 + if(src.throw_icon) //in case we don't have the HUD and we use the hotkey + src.throw_icon.icon_state = "act_throw_off" + +/mob/proc/throw_mode_on() + src.in_throw_mode = 1 + if(src.throw_icon) + src.throw_icon.icon_state = "act_throw_on" + +/mob/proc/toggle_antag_pool() + set name = "Toggle Add-Antag Candidacy" + set desc = "Toggles whether or not you will be considered a candidate by an add-antag vote." + set category = "OOC" + if(isghostmind(src.mind) || isnewplayer(src)) + if(ticker && ticker.looking_for_antags) + if(src.mind in ticker.antag_pool) + ticker.antag_pool -= src.mind + to_chat(usr, "You have left the antag pool.") + else + ticker.antag_pool += src.mind + to_chat(usr, "You have joined the antag pool. Make sure you have the needed role set to high!") + else + to_chat(usr, "The game is not currently looking for antags.") + else + to_chat(usr, "You must be observing or in the lobby to join the antag pool.") +/mob/proc/is_invisible_to(var/mob/viewer) + return (!alpha || !mouse_opacity || viewer.see_invisible < invisibility)// || src in(viewer.client.hidden_mobs || viewer.client.hidden_atoms)) + +/client/proc/check_has_body_select() + return mob && mob.hud_used && istype(mob.zone_sel, /obj/screen/zone_sel) + +/client/verb/body_toggle_head() + set name = "body-toggle-head" + set hidden = 1 + toggle_zone_sel(list(BP_HEAD,BP_EYES,BP_MOUTH)) + +/client/verb/body_r_arm() + set name = "body-r-arm" + set hidden = 1 + toggle_zone_sel(list(BP_R_ARM,BP_R_HAND)) + +/client/verb/body_l_arm() + set name = "body-l-arm" + set hidden = 1 + toggle_zone_sel(list(BP_L_ARM,BP_L_HAND)) + +/client/verb/body_chest() + set name = "body-chest" + set hidden = 1 + toggle_zone_sel(list(BP_CHEST)) + +/client/verb/body_groin() + set name = "body-groin" + set hidden = 1 + toggle_zone_sel(list(BP_GROIN)) + +/client/verb/body_r_leg() + set name = "body-r-leg" + set hidden = 1 + toggle_zone_sel(list(BP_R_LEG,BP_R_FOOT)) + +/client/verb/body_l_leg() + set name = "body-l-leg" + set hidden = 1 + toggle_zone_sel(list(BP_L_LEG,BP_L_FOOT)) + +/client/proc/toggle_zone_sel(list/zones) + if(!check_has_body_select()) + return + var/obj/screen/zone_sel/selector = mob.zone_sel + selector.set_selected_zone(next_in_list(mob.zone_sel.selecting,zones)) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm new file mode 100644 index 00000000..12dd27fa --- /dev/null +++ b/code/modules/mob/mob_defines.dm @@ -0,0 +1,204 @@ +/mob + density = 1 + plane = MOB_PLANE + + appearance_flags = PIXEL_SCALE + animate_movement = 2 + movable_flags = MOVABLE_FLAG_PROXMOVE + + virtual_mob = /mob/observer/virtual/mob + + var/list/client_images = list() // List of images applied to/removed from the client on login/logout + var/datum/mind/mind + + var/lastKnownIP = null + var/computer_id = null + + var/stat = 0 //Whether a mob is alive or dead. TODO: Move this to living - Nodrak + + var/obj/screen/hands = null + var/obj/screen/pullin = null + var/obj/screen/purged = null + var/obj/screen/internals = null + var/obj/screen/oxygen = null + var/obj/screen/i_select = null + var/obj/screen/m_select = null + var/obj/screen/toxin = null + var/obj/screen/fire = null + var/obj/screen/bodytemp = null + var/obj/screen/healths = null + var/obj/screen/throw_icon = null + var/obj/screen/nutrition_icon = null + var/obj/screen/hydration_icon = null + var/obj/screen/pressure = null + var/obj/screen/pain = null + var/obj/screen/gun/item/item_use_icon = null + var/obj/screen/gun/radio/radio_use_icon = null + var/obj/screen/gun/move/gun_move_icon = null + var/obj/screen/gun/run/gun_run_icon = null + var/obj/screen/gun/mode/gun_setting_icon = null + var/obj/screen/stamina_icon = null + var/obj/screen/kick_icon = null + var/obj/screen/jump_icon = null + var/obj/screen/noise = null + var/obj/screen/fixeye = null + var/obj/screen/rest = null + var/obj/screen/combat_icon = null + var/obj/screen/combat_intent_icon = null + var/obj/screen/atk_intent_icon = null + var/obj/screen/surrender = null + var/obj/screen/happiness_icon = null + var/obj/screen/wield_icon = null + + var/obj/screen/noise2 = null//unused + var/obj/screen/noise3 = null//unused + + var/obj/screen/movable/ability_master/ability_master = null + + /*A bunch of this stuff really needs to go under their own defines instead of being globally attached to mob. + A variable should only be globally attached to turfs/objects/whatever, when it is in fact needed as such. + The current method unnecessarily clusters up the variable list, especially for humans (although rearranging won't really clean it up a lot but the difference will be noticable for other mobs). + I'll make some notes on where certain variable defines should probably go. + Changing this around would probably require a good look-over the pre-existing code. + */ + var/obj/screen/zone_sel/zone_sel = null + + var/use_me = 1 //Allows all mobs to use the me verb by default, will have to manually specify they cannot + var/damageoverlaytemp = 0 + var/obj/machinery/machine = null + var/poll_answer = 0.0 + var/sdisabilities = 0 //Carbon + var/disabilities = 0 //Carbon + + var/atom/movable/pulling = null + var/other_mobs = null + var/next_move = null + var/transforming = null //Carbon + var/hand = null + var/real_name = null + + var/bhunger = 0 //Carbon + + var/druggy = 0 //Carbon + var/confused = 0 //Carbon + var/sleeping = 0 //Carbon + var/resting = 0 //Carbon + var/lying = 0 + var/lying_prev = 0 + var/canmove = 1 + //Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects. + var/incorporeal_move = 0 //0 is off, 1 is normal, 2 is for ninjas. + var/unacidable = 0 + var/list/pinned = list() // List of things pinning this creature to walls (see living_defense.dm) + var/list/embedded = list() // Embedded items, since simple mobs don't have organs. + var/list/languages = list() // For speaking/listening. + var/species_language = null // For species who want reset to use a specified default. + var/only_species_language = 0 // For species who can only speak their default and no other languages. Does not effect understanding. + var/list/speak_emote = list("says") // Verbs used when speaking. Defaults to 'say' if speak_emote is null. + var/emote_type = 1 // Define emote default type, 1 for seen emotes, 2 for heard emotes + var/facing_dir = null // Used for the ancient art of moonwalking. + + var/name_archive //For admin things like possession + + var/timeofdeath = 0 + + var/bodytemperature = 310.055 //98.7 F + var/default_pixel_x = 0 + var/default_pixel_y = 0 + + var/music_lastplayed = "null" + + var/a_intent = I_HELP//Living + var/defense_intent = I_DODGE//Living. For dodging and parrying. + var/m_intent = "run"//Living + var/atk_intent = I_DEFENSE//Human + var/middle_click_intent = null //For doing different things with middle click. + var/combat_mode = 0//Living + var/using_alt_hud = 0 //For the lunahud. + var/silent = null //Living. Can't talk. Value goes down every life proc. + var/obj/buckled = null//Living + var/obj/item/l_hand = null//Living + var/obj/item/r_hand = null//Living + var/obj/item/weapon/back = null//Human/Monkey + var/obj/item/weapon/storage/s_active = null//Carbon + var/obj/item/clothing/mask/wear_mask = null//Carbon + var/age = 30 //Player's age (pure fluff) + + +// var/datum/hud/hud_used = null + + var/list/grabbed_by = list() + + var/in_throw_mode = 0 + + var/inertia_dir = 0 + + +// var/job = null//Living + + var/can_pull_size = ITEM_SIZE_NO_CONTAINER // Maximum w_class the mob can pull. + var/can_pull_mobs = MOB_PULL_SAME // Whether or not the mob can pull other mobs. + + var/datum/dna/dna = null//Carbon + var/list/active_genes=list() + var/list/mutations = list() //Carbon -- Doohl + //see: setup.dm for list of mutations + + var/radiation = 0.0//Carbon + + var/voice_name = "unidentifiable voice" + + var/faction = "neutral" //Used for checking whether hostile simple animals will attack you, possibly more stuff later + var/blinded = null + var/ear_deaf = null //Carbon + +//The last mob/living/carbon to push/drag/grab this mob (mostly used by slimes friend recognition) + var/mob/living/carbon/LAssailant = null + + mouse_drag_pointer = MOUSE_ACTIVE_POINTER + + var/update_icon = 1 //Set to 1 to trigger update_icons() at the next life() call + + var/status_flags = CANSTUN|CANWEAKEN|CANPARALYSE|CANPUSH //bitflags defining which status effects can be inflicted (replaces canweaken, canstun, etc) + + var/area/lastarea = null + + var/digitalcamo = 0 // Can they be tracked by the AI? + + var/obj/control_object //Used by admins to possess objects. All mobs should have this var + + //Whether or not mobs can understand other mobtypes. These stay in /mob so that ghosts can hear everything. + var/universal_speak = 0 // Set to 1 to enable the mob to speak to everyone -- TLE + var/universal_understand = 0 // Set to 1 to enable the mob to understand everyone, not necessarily speak + + //If set, indicates that the client "belonging" to this (clientless) mob is currently controlling some other mob + //so don't treat them as being SSD even though their client var is null. + var/mob/teleop = null + + var/turf/listed_turf = null //the current turf being examined in the stat panel + var/list/shouldnt_see = list() //list of objects that this mob shouldn't see in the stat panel. this silliness is needed because of AI alt+click and cult blood runes + + var/mob_size = MOB_MEDIUM + var/throw_multiplier = 1 + + var/paralysis = 0 + var/stunned = 0 + var/weakened = 0 + var/drowsyness = 0.0//Carbon + + var/memory = "" + var/flavor_text = "" + + var/nabbing = 0 // Whether a creature with a CAN_NAB tag is grabbing normally or in nab mode. + + var/has_limbs = 1//For crawling + + var/scrambling = 0//For crawling. + + var/crouching = FALSE //For crouching. + + var/emote_cd = 0//Emote cooldown. + + var/communing_with_dead = FALSE //Let's you talk in dsay without being an admin, or dead. + + var/warfare_faction = null //The warfare faction they're apart of. Used by humans and ghosts primarily. Placed all the way up here so that when you logout as something other than a human you don't get team switched. diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm new file mode 100644 index 00000000..455aa279 --- /dev/null +++ b/code/modules/mob/mob_helpers.dm @@ -0,0 +1,625 @@ +// fun if you want to typecast humans/monkeys/etc without writing long path-filled lines. +/*/proc/isxenomorph(A) + if(istype(A, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = A + return istype(H.species, /datum/species/xenos) + return 0 +*/ + +/proc/issmall(A) + if(A && istype(A, /mob/living)) + var/mob/living/L = A + return L.mob_size <= MOB_SMALL + return 0 + +//returns the number of size categories between two mob_sizes, rounded. Positive means A is larger than B +/proc/mob_size_difference(var/mob_size_A, var/mob_size_B) + return round(log(2, mob_size_A/mob_size_B), 1) + +/mob/proc/can_wield_item(obj/item/W) + if(W.w_class >= ITEM_SIZE_LARGE && issmall(src)) + return FALSE //M is too small to wield this + return TRUE + +/mob/living/proc/isSynthetic() + return 0 + +/mob/living/carbon/human/isSynthetic() + if(isnull(full_prosthetic)) + robolimb_count = 0 + for(var/obj/item/organ/external/E in organs) + if(E.robotic >= ORGAN_ROBOT) + robolimb_count++ + full_prosthetic = (robolimb_count == organs.len) + update_emotes() + return full_prosthetic + +/mob/living/silicon/isSynthetic() + return 1 + +/mob/proc/isMonkey() + return 0 + +/mob/living/carbon/human/isMonkey() + return istype(species, /datum/species/monkey) + +proc/isdeaf(A) + if(isliving(A)) + var/mob/living/M = A + return (M.sdisabilities & DEAF) || M.ear_deaf + return 0 + +proc/hasorgans(A) // Fucking really?? + return ishuman(A) + +proc/iscuffed(A) + if(istype(A, /mob/living/carbon)) + var/mob/living/carbon/C = A + if(C.handcuffed) + return 1 + return 0 + +proc/hassensorlevel(A, var/level) + var/mob/living/carbon/human/H = A + if(istype(H) && istype(H.w_uniform, /obj/item/clothing/under)) + var/obj/item/clothing/under/U = H.w_uniform + return U.sensor_mode >= level + return 0 + +proc/getsensorlevel(A) + var/mob/living/carbon/human/H = A + if(istype(H) && istype(H.w_uniform, /obj/item/clothing/under)) + var/obj/item/clothing/under/U = H.w_uniform + return U.sensor_mode + return SUIT_SENSOR_OFF + + +/proc/is_admin(var/mob/user) + return check_rights(R_ADMIN, 0, user) != 0 + + +/proc/hsl2rgb(h, s, l) + return //TODO: Implement + +/* + Miss Chance +*/ + +//TODO: Integrate defence zones and targeting body parts with the actual organ system, move these into organ definitions. + +//The base miss chance for the different defence zones +var/list/global/base_miss_chance = list( + BP_HEAD = 50, + BP_CHEST = 10, + BP_GROIN = 20, + BP_L_LEG = 50, + BP_R_LEG = 50, + BP_L_ARM = 50, + BP_R_ARM = 50, + BP_L_HAND = 50, + BP_R_HAND = 50, + BP_L_FOOT = 50, + BP_R_FOOT = 50, +) + +//Used to weight organs when an organ is hit randomly (i.e. not a directed, aimed attack). +//Also used to weight the protection value that armour provides for covering that body part when calculating protection from full-body effects. +var/list/global/organ_rel_size = list( + BP_HEAD = 25, + BP_CHEST = 70, + BP_GROIN = 30, + BP_L_LEG = 25, + BP_R_LEG = 25, + BP_L_ARM = 25, + BP_R_ARM = 25, + BP_L_HAND = 50, + BP_R_HAND = 50, + BP_L_FOOT = 50, + BP_R_FOOT = 10, +) + +/proc/check_zone(zone) + if(!zone) return BP_CHEST + switch(zone) + if(BP_EYES) + zone = BP_HEAD + if(BP_MOUTH) + zone = BP_HEAD + if(BP_THROAT) + zone = BP_HEAD + return zone + +// Returns zone with a certain probability. If the probability fails, or no zone is specified, then a random body part is chosen. +// Do not use this if someone is intentionally trying to hit a specific body part. +// Use get_zone_with_miss_chance() for that. +/proc/ran_zone(zone, probability) + if (zone) + zone = check_zone(zone) + if (prob(probability)) + return zone + + var/ran_zone = zone + while (ran_zone == zone) + ran_zone = pick ( + organ_rel_size[BP_HEAD]; BP_HEAD, + organ_rel_size[BP_CHEST]; BP_CHEST, + organ_rel_size[BP_GROIN]; BP_GROIN, + organ_rel_size[BP_L_ARM]; BP_L_ARM, + organ_rel_size[BP_R_ARM]; BP_R_ARM, + organ_rel_size[BP_L_LEG]; BP_L_LEG, + organ_rel_size[BP_R_LEG]; BP_R_LEG, + organ_rel_size[BP_L_HAND]; BP_L_HAND, + organ_rel_size[BP_R_HAND]; BP_R_HAND, + organ_rel_size[BP_L_FOOT]; BP_L_FOOT, + organ_rel_size[BP_R_FOOT]; BP_R_FOOT, + ) + + return ran_zone + +// Emulates targetting a specific body part, and miss chances +// May return null if missed +// miss_chance_mod may be negative. +/proc/get_zone_with_miss_chance(zone, var/mob/target, var/miss_chance_mod = 0, var/ranged_attack=0, var/mob/attacker) + zone = check_zone(zone) + + if(!ranged_attack) + // you cannot miss if your target is restrained + if(target.buckled) + return zone + // if your target is being grabbed aggressively by someone you cannot miss either + for(var/obj/item/grab/G in target.grabbed_by) + if(G.stop_move()) + return zone + + if(target.lying)//If they're lying, much better chance to hit them. + miss_chance_mod -= 50 + var/miss_chance = 10 + if (zone in base_miss_chance) + miss_chance = base_miss_chance[zone] + miss_chance = max(miss_chance + miss_chance_mod, 0) + if(prob(miss_chance)) + if(prob(50))//25% chance you miss entirely. + return null + else if(prob(25))//Then another throw to see if you hit something else. + return ran_zone(zone, 5) + else + return pick(base_miss_chance)//Then whatever the fuck this does. + return zone + + +/proc/stars(n, pr) + if (pr == null) + pr = 25 + if (pr < 0) + return null + else + if (pr >= 100) + return n + var/te = html_decode(n) + var/t = "" + n = length(n) + var/p = null + p = 1 + var/intag = 0 + while(p <= n) + var/char = copytext(te, p, p + 1) + if (char == "<") //let's try to not break tags + intag = !intag + if (intag || char == " " || prob(pr)) + t = text("[][]", t, char) + else + t = text("[]*", t) + if (char == ">") + intag = !intag + p++ + return t + +proc/slur(phrase) + phrase = html_decode(phrase) + var/leng=length(phrase) + var/counter=length(phrase) + var/newphrase="" + var/newletter="" + while(counter>=1) + newletter=copytext(phrase,(leng-counter)+1,(leng-counter)+2) + if(rand(1,3)==3) + if(lowertext(newletter)=="o") newletter="u" + if(lowertext(newletter)=="s") newletter="ch" + if(lowertext(newletter)=="a") newletter="ah" + if(lowertext(newletter)=="c") newletter="k" + switch(rand(1,15)) + if(1,3,5,8) newletter="[lowertext(newletter)]" + if(2,4,6,15) newletter="[uppertext(newletter)]" + if(7) newletter+="'" + if(9,10) newletter="[newletter]" + if(11,12) newletter="[newletter]" + if(13) newletter="[newletter]" + newphrase+="[newletter]";counter-=1 + return newphrase + +/proc/stutter(n) + var/te = html_decode(n) + var/t = ""//placed before the message. Not really sure what it's for. + n = length(n)//length of the entire word + var/p = null + p = 1//1 is the start of any word + while(p <= n)//while P, which starts at 1 is less or equal to N which is the length. + var/n_letter = copytext(te, p, p + 1)//copies text from a certain distance. In this case, only one letter at a time. + if (prob(80) && (ckey(n_letter) in list("b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","y","z"))) + if (prob(10)) + n_letter = text("[n_letter]-[n_letter]-[n_letter]-[n_letter]")//replaces the current letter with this instead. + else + if (prob(20)) + n_letter = text("[n_letter]-[n_letter]-[n_letter]") + else + if (prob(5)) + n_letter = null + else + n_letter = text("[n_letter]-[n_letter]") + t = text("[t][n_letter]")//since the above is ran through for each letter, the text just adds up back to the original word. + p++//for each letter p is increased to find where the next letter will be. + return sanitize(t) + + +proc/Gibberish(t, p)//t is the inputted message, and any value higher than 70 for p will cause letters to be replaced instead of added + /* Turn text into complete gibberish! */ + var/returntext = "" + for(var/i = 1, i <= length(t), i++) + + var/letter = copytext(t, i, i+1) + if(prob(50)) + if(p >= 70) + letter = "" + + for(var/j = 1, j <= rand(0, 2), j++) + letter += pick("#","@","*","&","%","$","/", "<", ">", ";","*","*","*","*","*","*","*") + + returntext += letter + + return returntext + +/proc/lisp(message, intensity=100) //Intensity = how hard will the dude be lisped + message = html_decode(message) + message = prob(intensity) ? replacetext(message, "f", "ph") : message + message = prob(intensity) ? replacetext(message, "t", "ph") : message + message = prob(intensity) ? replacetext(message, "s", "sh") : message + message = prob(intensity) ? replacetext(message, "th", "hh") : message + message = prob(intensity) ? replacetext(message, "ck", "gh") : message + message = prob(intensity) ? replacetext(message, "c", "gh") : message + message = prob(intensity) ? replacetext(message, "k", "gh") : message + return message + +/proc/tongueless(message) + message = html_decode(message) + message = replacetext(message, "c", "h") + message = replacetext(message, "d", "a") + message = replacetext(message, "i", "a") + message = replacetext(message, "k", "a") + message = replacetext(message, "j", "a") + message = replacetext(message, "l", "a") + message = replacetext(message, "n", "a") + message = replacetext(message, "q", "h") + message = replacetext(message, "r", "a") + message = replacetext(message, "s", "h") + message = replacetext(message, "t", "a") + message = replacetext(message, "v", "h") + message = replacetext(message, "x", "a") + message = replacetext(message, "y", "a") + message = replacetext(message, "z", "h") + return message + +//Shake the camera of the person viewing the mob SO REAL! +/proc/shake_camera(mob/M, duration, strength=1) + if(!M || !M.client || duration < 1) + return + var/client/C = M.client + var/oldx = C.pixel_x + var/oldy = C.pixel_y + var/max = strength*world.icon_size + var/min = -(strength*world.icon_size) + + for(var/i in 0 to duration-1) + if (i == 0) + animate(C, pixel_x=rand(min,max), pixel_y=rand(min,max), time=1) + else + animate(pixel_x=rand(min,max), pixel_y=rand(min,max), time=1) + animate(pixel_x=oldx, pixel_y=oldy, time=1, easing = SINE_EASING) + + +/proc/findname(msg) + for(var/mob/M in SSmobs.mob_list) + if (M.real_name == text("[msg]")) + return 1 + return 0 + + +/mob/proc/abiotic(var/full_body = FALSE) + if(full_body && ((src.l_hand && src.l_hand.simulated) || (src.r_hand && src.r_hand.simulated) || (src.back || src.wear_mask))) + return TRUE + + if((src.l_hand && src.l_hand.simulated) || (src.r_hand && src.r_hand.simulated)) + return TRUE + + return FALSE + +//converts intent-strings into numbers and back +var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT) +/proc/intent_numeric(argument) + if(istext(argument)) + switch(argument) + if(I_HELP) return 0 + if(I_DISARM) return 1 + if(I_GRAB) return 2 + else return 3 + else + switch(argument) + if(0) return I_HELP + if(1) return I_DISARM + if(2) return I_GRAB + else return I_HURT + +//change a mob's act-intent. Input the intent as a string such as "help" or use "right"/"left +/mob/verb/a_intent_change(input as text) + set name = "a-intent" + set hidden = 1 + + if(ishuman(src) || isbrain(src) || isslime(src)) + switch(input) + if(I_HELP,I_DISARM,I_GRAB,I_HURT) + a_intent = input + if("right") + a_intent = intent_numeric((intent_numeric(a_intent)+1) % 4) + if("left") + a_intent = intent_numeric((intent_numeric(a_intent)+3) % 4) + if(hud_used && hud_used.action_intent) + hud_used.action_intent.icon_state = "intent_[a_intent]" + + else if(isrobot(src)) + switch(input) + if(I_HELP) + a_intent = I_HELP + if(I_HURT) + a_intent = I_HURT + if("right","left") + a_intent = intent_numeric(intent_numeric(a_intent) - 3) + if(hud_used && hud_used.action_intent) + if(a_intent == I_HURT) + hud_used.action_intent.icon_state = I_HURT + else + hud_used.action_intent.icon_state = I_HELP + +proc/is_blind(A) + if(istype(A, /mob/living/carbon)) + var/mob/living/carbon/C = A + if(C.sdisabilities & BLIND || C.blinded) + return 1 + return 0 + +/proc/broadcast_security_hud_message(var/message, var/broadcast_source) + broadcast_hud_message(message, broadcast_source, GLOB.sec_hud_users, /obj/item/clothing/glasses/hud/security) + +/proc/broadcast_medical_hud_message(var/message, var/broadcast_source) + broadcast_hud_message(message, broadcast_source, GLOB.med_hud_users, /obj/item/clothing/glasses/hud/health) + +/proc/broadcast_hud_message(var/message, var/broadcast_source, var/list/targets, var/icon) + var/turf/sourceturf = get_turf(broadcast_source) + for(var/mob/M in targets) + var/turf/targetturf = get_turf(M) + if(!sourceturf || (targetturf.z in GetConnectedZlevels(sourceturf.z))) + M.show_message("\icon[icon] [message]", 1) + +/proc/mobs_in_area(var/area/A) + var/list/mobs = new + for(var/mob/living/M in SSmobs.mob_list) + if(get_area(M) == A) + mobs += M + return mobs + +//Announces that a ghost has joined/left, mainly for use with wizards +/proc/announce_ghost_joinleave(O, var/joined_ghosts = 1, var/message = "") + var/client/C + //Accept any type, sort what we want here + if(istype(O, /mob)) + var/mob/M = O + if(M.client) + C = M.client + else if(istype(O, /client)) + C = O + else if(istype(O, /datum/mind)) + var/datum/mind/M = O + if(M.current && M.current.client) + C = M.current.client + else if(M.original && M.original.client) + C = M.original.client + + if(C) + var/name + if(C.mob) + var/mob/M = C.mob + if(M.mind && M.mind.name) + name = M.mind.name + if(M.real_name && M.real_name != name) + if(name) + name += " ([M.real_name])" + else + name = M.real_name + if(!name) + name = C.key + var/diedat = "" + if(C.mob.lastarea) + diedat = " at [C.mob.lastarea]" + if(joined_ghosts) + message = "The ghost of [name] now [pick("skulks","lurks","prowls","creeps","stalks")] among the dead[diedat]. [message]" + else + message = "[name] no longer [pick("skulks","lurks","prowls","creeps","stalks")] in the realm of the dead. [message]" + communicate(/decl/communication_channel/dsay, C || O, message, /decl/dsay_communication/direct) + +/mob/proc/switch_to_camera(var/obj/machinery/camera/C) + if (!C.can_use() || stat || (get_dist(C, src) > 1 || machine != src || blinded || !canmove)) + return 0 + check_eye(src) + return 1 + +/mob/living/silicon/ai/switch_to_camera(var/obj/machinery/camera/C) + if(!C.can_use() || !is_in_chassis()) + return 0 + + eyeobj.setLoc(C) + return 1 + +// Returns true if the mob has a client which has been active in the last given X minutes. +/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) + return SAFE_PERP + + return 0 + +/mob/living/carbon/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest) + if(handcuffed) + return SAFE_PERP + + return ..() + +/mob/living/carbon/human/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest) + var/threatcount = ..() + if(. == SAFE_PERP) + return SAFE_PERP + + //Agent cards lower threatlevel. + var/obj/item/weapon/card/id/id = GetIdCard() + if(id && istype(id, /obj/item/weapon/card/id/syndicate)) + threatcount -= 2 + // A proper CentCom id is hard currency. + else if(id && istype(id, /obj/item/weapon/card/id/centcom)) + return SAFE_PERP + + if(check_access && !access_obj.allowed(src)) + threatcount += 4 + + if(auth_weapons && !access_obj.allowed(src)) + if(istype(l_hand, /obj/item/weapon/gun) || istype(l_hand, /obj/item/weapon/melee)) + threatcount += 4 + + if(istype(r_hand, /obj/item/weapon/gun) || istype(r_hand, /obj/item/weapon/melee)) + threatcount += 4 + + if(istype(belt, /obj/item/weapon/gun) || istype(belt, /obj/item/weapon/melee)) + threatcount += 2 + + if(species.name != SPECIES_HUMAN) + threatcount += 2 + + if(check_records || check_arrest) + var/perpname = name + if(id) + perpname = id.registered_name + + var/datum/computer_file/crew_record/CR = get_crewmember_record(perpname) + if(check_records && !CR && !isMonkey()) + threatcount += 4 + + if(check_arrest && CR && (CR.get_criminalStatus() == GLOB.arrest_security_status)) + threatcount += 4 + + return threatcount + +/mob/living/simple_animal/hostile/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest) + var/threatcount = ..() + if(. == SAFE_PERP) + return SAFE_PERP + + if(!istype(src, /mob/living/simple_animal/hostile/retaliate/goat)) + threatcount += 4 + return threatcount + +#undef SAFE_PERP + +/mob/proc/get_multitool(var/obj/item/device/multitool/P) + if(istype(P)) + return P + +/mob/observer/ghost/get_multitool() + return can_admin_interact() && ..(ghost_multitool) + +/mob/living/carbon/human/get_multitool() + return ..(get_active_hand()) + +/mob/living/silicon/robot/get_multitool() + return ..(get_active_hand()) + +/mob/living/silicon/ai/get_multitool() + return ..(aiMulti) + +/proc/get_both_hands(mob/living/carbon/M) + if(!istype(M)) + return + var/list/hands = list(M.l_hand, M.r_hand) + return hands + +/mob/proc/refresh_client_images() + if(client) + client.images |= client_images + +/mob/proc/hide_client_images() + if(client) + client.images -= client_images + +/mob/proc/add_client_image(var/image) + if(image in client_images) + return + client_images += image + if(client) + client.images += image + +/mob/proc/remove_client_image(var/image) + client_images -= image + if(client) + client.images -= image + +/mob/proc/flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash) + return + +/mob/proc/fully_replace_character_name(var/new_name, var/in_depth = TRUE) + if(!new_name || new_name == real_name) return 0 + real_name = new_name + SetName(new_name) + if(mind) + mind.name = new_name + if(dna) + dna.real_name = real_name + if(client) + winset(src, "name", "text='[real_name]'") + return 1 + +/mob/proc/ssd_check() + return !client && !teleop + +/mob/proc/jittery_damage() + return //Only for living/carbon/human/ + +/mob/living/carbon/human/jittery_damage() + var/mob/living/carbon/human/H = src + var/obj/item/organ/internal/heart/L = H.internal_organs_by_name[BP_HEART] + if(L && istype(L)) + if(L.robotic >= ORGAN_ROBOT) + return 0//Robotic hearts don't get jittery. + if(src.jitteriness >= 400 && prob(5)) //Kills people if they have high jitters. + if(prob(1)) + L.take_damage(L.max_damage / 2, 0) + to_chat(src, "Something explodes in your heart.") + admin_victim_log(src, "has taken lethal heart damage at jitteriness level [src.jitteriness].") + else + L.take_damage(1, 0) + to_chat(src, "The jitters are killing you! You feel your heart beating out of your chest.") + admin_victim_log(src, "has taken minor heart damage at jitteriness level [src.jitteriness].") + return 1 diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm new file mode 100644 index 00000000..2a811d94 --- /dev/null +++ b/code/modules/mob/mob_movement.dm @@ -0,0 +1,577 @@ +/mob/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group || (height==0)) return 1 + + if(ismob(mover)) + var/mob/moving_mob = mover + if ((other_mobs && moving_mob.other_mobs)) + return 1 + return (!mover.density || !density || lying) + else + return (!mover.density || !density || lying) + return + +/mob/proc/setMoveCooldown(var/timeout) + if(client) + client.move_delay = max(world.time + timeout, client.move_delay) + +/client/North() + ..() + + +/client/South() + ..() + + +/client/West() + ..() + + +/client/East() + ..() + + +/client/proc/client_dir(input, direction=-1) + return turn(input, direction*dir2angle(dir)) + +/client/Northeast() + diagonal_action(NORTHEAST) +/client/Northwest() + diagonal_action(NORTHWEST) +/client/Southeast() + diagonal_action(SOUTHEAST) +/client/Southwest() + diagonal_action(SOUTHWEST) + +/client/proc/diagonal_action(direction) + switch(client_dir(direction, 1)) + if(NORTHEAST) + swap_hand() + return + if(SOUTHEAST) + attack_self() + return + if(SOUTHWEST) + if(iscarbon(usr)) + var/mob/living/carbon/C = usr + C.toggle_throw_mode() + else + to_chat(usr, "This mob type cannot throw items.") + return + if(NORTHWEST) + mob.hotkey_drop() + +/mob/proc/hotkey_drop() + to_chat(usr, "This mob type cannot drop items.") + +/mob/living/carbon/hotkey_drop() + if(!get_active_hand()) + to_chat(usr, "You have nothing to drop in your hand.") + else + drop_item() + +//This gets called when you press the delete button. +/client/verb/delete_key_pressed() + set hidden = 1 + + if(!usr.pulling) + to_chat(usr, "You are not pulling anything.") + return + usr.stop_pulling() + +/client/verb/swap_hand() + set hidden = 1 + if(istype(mob, /mob/living/carbon)) + mob:swap_hand() + if(istype(mob,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = mob + R.cycle_modules() + return + + + +/client/verb/attack_self() + set hidden = 1 + if(mob) + mob.mode() + return + + +/client/verb/toggle_throw_mode() + set hidden = 1 + if(!istype(mob, /mob/living/carbon)) + return + if (!mob.stat && isturf(mob.loc) && !mob.restrained()) + mob:toggle_throw_mode() + else + return + + +/client/verb/drop_item() + set hidden = 1 + if(!isrobot(mob) && mob.stat == CONSCIOUS && isturf(mob.loc)) + return mob.drop_item() + return + + +/client/Center() + /* No 3D movement in 2D spessman game. dir 16 is Z Up + if (isobj(mob.loc)) + var/obj/O = mob.loc + if (mob.canmove) + return O.relaymove(mob, 16) + */ + return + +//This proc should never be overridden elsewhere at /atom/movable to keep directions sane. +/atom/movable/Move(newloc, direct) + if (direct & (direct - 1)) + if (direct & 1) + if (direct & 4) + if (step(src, NORTH)) + step(src, EAST) + else + if (step(src, EAST)) + step(src, NORTH) + else + if (direct & 8) + if (step(src, NORTH)) + step(src, WEST) + else + if (step(src, WEST)) + step(src, NORTH) + else + if (direct & 2) + if (direct & 4) + if (step(src, SOUTH)) + step(src, EAST) + else + if (step(src, EAST)) + step(src, SOUTH) + else + if (direct & 8) + if (step(src, SOUTH)) + step(src, WEST) + else + if (step(src, WEST)) + step(src, SOUTH) + else + var/atom/A = src.loc + + var/olddir = dir //we can't override this without sacrificing the rest of movable/New() + . = ..() + if(direct != olddir) + dir = olddir + set_dir(direct) + + src.move_speed = world.time - src.l_move_time + src.l_move_time = world.time + src.m_flag = 1 + if ((A != src.loc && A && A.z == src.z)) + src.last_move = get_dir(A, src.loc) + return + +/client/proc/Move_object(direct) + if(mob && mob.control_object) + if(mob.control_object.density) + step(mob.control_object,direct) + if(!mob.control_object) return + mob.control_object.set_dir(direct) + else + mob.control_object.forceMove(get_step(mob.control_object,direct)) + return + + +/client/Move(n, direct) + if(!mob) + return // Moved here to avoid nullrefs below + + if(mob.control_object) Move_object(direct) + + if(mob.incorporeal_move && isobserver(mob)) + Process_Incorpmove(direct) + return + + if(moving) return 0 + + if(world.time < move_delay) return + + if(locate(/obj/effect/stop/, mob.loc)) + for(var/obj/effect/stop/S in mob.loc) + if(S.victim == mob) + return + + if(mob.stat==DEAD && isliving(mob)) + mob.ghostize() + return + + // handle possible Eye movement + if(mob.eyeobj) + return mob.EyeMove(n,direct) + + if(mob.transforming) return//This is sota the goto stop mobs from moving var + + if(Process_Grab()) return + + if(!mob.canmove) + return + + if(isliving(mob)) + var/mob/living/L = mob + if(L.incorporeal_move)//Move though walls + Process_Incorpmove(direct) + return + if(mob.client) + if(mob.client.view != world.view) // If mob moves while zoomed in with device, unzoom them. + for(var/obj/item/item in mob.contents) + if(item.zoom) + item.zoom(mob) + break + + if(!mob.lastarea) + mob.lastarea = get_area(mob.loc) + + if(!mob.check_solid_ground()) + var/allowmove = mob.Allow_Spacemove(0) + if(!allowmove) + return 0 + else if(allowmove == -1 && mob.handle_spaceslipping()) //Check to see if we slipped + return 0 + else + mob.inertia_dir = 0 //If not then we can reset inertia and move + + if(isobj(mob.loc) || ismob(mob.loc))//Inside an object, tell it we moved + var/atom/O = mob.loc + return O.relaymove(mob, direct) + + if(isturf(mob.loc)) + + if(mob.restrained())//Why being pulled while cuffed prevents you from moving + for(var/mob/M in range(mob, 1)) + if(M.pulling == mob) + if(!M.restrained() && M.stat == 0 && M.canmove && mob.Adjacent(M)) + to_chat(src, "You're restrained! You can't move!") + return 0 + else + M.stop_pulling() + + if(mob.pinned.len) + to_chat(src, "You're pinned to a wall by [mob.pinned[1]]!") + return 0 + + move_delay = world.time//set move delay + + switch(mob.m_intent) + if("run") + if(mob.drowsyness > 0) + move_delay += 6 + move_delay += 1+config.run_speed + if("walk") + move_delay += 7+config.walk_speed + move_delay += mob.movement_delay() + + if(istype(mob.buckled, /obj/vehicle)) + //manually set move_delay for vehicles so we don't inherit any mob movement penalties + //specific vehicle move delays are set in code\modules\vehicles\vehicle.dm + move_delay = world.time + //drunk driving + if(mob.confused && prob(20)) //vehicles tend to keep moving in the same direction + direct = turn(direct, pick(90, -90)) + return mob.buckled.relaymove(mob,direct) + + if(istype(mob.machine, /obj/machinery)) + if(mob.machine.relaymove(mob,direct)) + return + + if(mob.pulledby || mob.buckled) // Wheelchair driving! + if(istype(mob.loc, /turf/space)) + return // No wheelchair driving in space + if(istype(mob.pulledby, /obj/structure/bed/chair/wheelchair)) + return mob.pulledby.relaymove(mob, direct) + else if(istype(mob.buckled, /obj/structure/bed/chair/wheelchair)) + if(ishuman(mob)) + var/mob/living/carbon/human/driver = mob + var/obj/item/organ/external/l_hand = driver.get_organ(BP_L_HAND) + var/obj/item/organ/external/r_hand = driver.get_organ(BP_R_HAND) + if((!l_hand || l_hand.is_stump()) && (!r_hand || r_hand.is_stump())) + return // No hands to drive your chair? Tough luck! + //drunk wheelchair driving + else if(mob.confused) + switch(mob.m_intent) + if("run") + if(prob(50)) direct = turn(direct, pick(90, -90)) + if("walk") + if(prob(25)) direct = turn(direct, pick(90, -90)) + move_delay += 2 + return mob.buckled.relaymove(mob,direct) + + if(mob.check_slipmove()) + return + + if(ishuman(mob))//The worst possible way of stoping people with broken legs from walking. + if(GLOB.waddling)//Admeme + mob.waddle() + //if(mob.zoomed) //Going to allow people to move while zoomed in for now. + // mob.do_zoom() + var/mob/living/carbon/human/H = mob + if(H.shadow) + if(H.client.eye == H.shadow) + H.reset_view(0) + var/obj/item/organ/external/l_leg = H.get_organ(BP_L_LEG) + var/obj/item/organ/external/r_leg = H.get_organ(BP_R_LEG) + var/obj/item/organ/external/l_foot = H.get_organ(BP_L_FOOT) + var/obj/item/organ/external/r_foot = H.get_organ(BP_R_FOOT) + + if(!H.lying && !H.buckled) + if(!istype(H.get_hands(), /obj/item/weapon/crutches)) + if(!l_leg || l_leg.is_stump() || l_leg.is_broken()) + to_chat(H, "You're crippled you can't walk.") + H.Weaken(1) + return + if(!r_leg || r_leg.is_stump() || r_leg.is_broken()) + to_chat(H, "You're crippled you can't walk.") + H.Weaken(1) + return + if(!l_foot || l_foot.is_stump() || l_foot.is_broken()) + to_chat(H, "You're crippled you can't walk.") + H.Weaken(1) + return + if(!r_foot || r_foot.is_stump() || r_foot.is_broken()) + to_chat(H, "You're crippled you can't walk.") + H.Weaken(1) + return + /* + if(istype(H.loc, /turf/simulated/floor/trench))//Hacky, but effective. + if((!istype(n, /turf/simulated/floor/trench) && !istype(n, /turf/simulated/open)) && !H.pulledby)//If we're exiting the trench, and we're not being pulled. + H.visible_message("[H] begins to climb out of the trench.") + if(!do_after(H,10)) + H.visible_message("[H] fails to climb out of the trench.") + if(H.crouching)//Stand us back up. + H.toggle_crouch() + return + */ + + //We are now going to move + moving = 1 + //Something with pulling things + if(locate(/obj/item/grab, mob)) + for (var/obj/item/grab/G in mob) + move_delay = max(move_delay, world.time + G.grab_slowdown()) + var/list/L = mob.ret_grab() + if(istype(L, /list)) + if(L.len == 2) + L -= mob + var/mob/M = L[1] + if(M) + if ((get_dist(mob, M) <= 1 || M.loc == mob.loc)) + var/turf/T = mob.loc + . = ..() + if (isturf(M.loc)) + var/diag = get_dir(mob, M) + if ((diag - 1) & diag) + else + diag = null + if ((get_dist(mob, M) > 1 || diag)) + step(M, get_dir(M.loc, T)) + else + for(var/mob/M in L) + M.other_mobs = 1 + if(mob != M) + M.animate_movement = 3 + for(var/mob/M in L) + spawn( 0 ) + step(M, direct) + return + spawn( 1 ) + M.other_mobs = null + M.animate_movement = 2 + return + G.adjust_position() + else + if(mob.confused) + switch(mob.m_intent) + if("run") + if(prob(75)) + direct = turn(direct, pick(90, -90)) + n = get_step(mob, direct) + if("walk") + if(prob(25)) + direct = turn(direct, pick(90, -90)) + n = get_step(mob, direct) + . = mob.SelfMove(n, direct) + + for (var/obj/item/grab/G in mob) + if (G.assailant_reverse_facing()) + mob.set_dir(GLOB.reverse_dir[direct]) + G.assailant_moved() + for (var/obj/item/grab/G in mob.grabbed_by) + G.adjust_position() + + moving = 0 + + if(mob.pulling) + mob.dir = turn(mob.dir, 180) + mob.update_vision_cone() + + if((direct & (direct - 1)) && mob.loc == n) //moved diagonally successfully + move_delay += 2 + + return . + + return + +/mob/proc/SelfMove(turf/n, direct) + return Move(n, direct) + + +///Process_Incorpmove +///Called by client/Move() +///Allows mobs to run though walls +/client/proc/Process_Incorpmove(direct) + if(mob.confused) + switch(mob.m_intent) + if("run") + if(prob(75)) + direct = turn(direct, pick(90, -90)) + if("walk") + if(prob(25)) + direct = turn(direct, pick(90, -90)) + + var/turf/T = get_step(mob, direct) + if(mob.check_is_holy_turf(T)) + to_chat(mob, "You cannot enter holy grounds while you are in this plane of existence!") + return + + if(T) + mob.forceMove(T) + mob.set_dir(direct) + + mob.Post_Incorpmove() + return 1 + +/mob/proc/Post_Incorpmove() + return + +// Checks whether this mob is allowed to move in space +// Return 1 for movement, 0 for none, +// -1 to allow movement but with a chance of slipping +/mob/proc/Allow_Spacemove(var/check_drift = 0) + if(!Check_Dense_Object()) //Nothing to push off of so end here + return 0 + + if(restrained()) //Check to see if we can do things + return 0 + + return -1 + +//Checks if a mob has solid ground to stand on +//If there's no gravity then there's no up or down so naturally you can't stand on anything. +//For the same reason lattices in space don't count - those are things you grip, presumably. +/mob/proc/check_solid_ground() + if(istype(loc, /turf/space)) + return 0 + + if(!lastarea) + lastarea = get_area(loc) + if(!lastarea.has_gravity) + return 0 + + return 1 + +/mob/proc/Check_Dense_Object() //checks for anything to push off or grip in the vicinity. also handles magboots on gravity-less floors tiles + + var/shoegrip = Check_Shoegrip() + + for(var/turf/simulated/T in trange(1,src)) //we only care for non-space turfs + if(T.density) //walls work + return 1 + else + var/area/A = T.loc + if(A.has_gravity || shoegrip) + return 1 + + for(var/obj/O in orange(1, src)) + if(istype(O, /obj/structure/lattice)) + return 1 + if(O && O.density && O.anchored) + return 1 + + return 0 + +/mob/proc/Check_Shoegrip() + return 0 + +//return 1 if slipped, 0 otherwise +/mob/proc/handle_spaceslipping() + if(prob(slip_chance(5)) && !buckled) + to_chat(src, "You slipped!") + src.inertia_dir = src.last_move + step(src, src.inertia_dir) + return 1 + return 0 + +/mob/proc/slip_chance(var/prob_slip = 5) + if(stat) + return 0 + if(Check_Shoegrip()) + return 0 + return prob_slip + +#define DO_MOVE(this_dir) var/final_dir = turn(this_dir, -dir2angle(dir)); Move(get_step(mob, final_dir), final_dir); + +#define fastMove(dir) set instant = TRUE; \ + set hidden = TRUE; \ + moving_in_dir |= dir + +#define fastStopMoving(dir) set instant = TRUE; \ + set hidden = TRUE; \ + moving_in_dir &= ~dir + +/mob/proc/check_slipmove() + return + + +/client/verb/moveup() + set name = ".moveup" + set instant = 1 + DO_MOVE(NORTH) + +/client/verb/movedown() + set name = ".movedown" + set instant = 1 + DO_MOVE(SOUTH) + +/client/verb/moveright() + set name = ".moveright" + set instant = 1 + DO_MOVE(EAST) + +/client/verb/moveleft() + set name = ".moveleft" + set instant = 1 + DO_MOVE(WEST) +/* +/client/verb/fastNorth() + fastMove(NORTH) +/client/verb/fastEast() + fastMove(EAST) +/client/verb/fastSouth() + fastMove(SOUTH) +/client/verb/fastWest() + fastMove(WEST) + +/client/verb/northUp() + fastStopMoving(NORTH) +/client/verb/southUp() + fastStopMoving(SOUTH) +/client/verb/eastUp() + fastStopMoving(EAST) +/client/verb/westUp() + fastStopMoving(WEST) +*/ + +#undef DO_MOVE + + + +#undef fastMove +#undef fastStopMoving \ No newline at end of file diff --git a/code/modules/mob/mob_transformation_simple.dm b/code/modules/mob/mob_transformation_simple.dm new file mode 100644 index 00000000..b2289cb4 --- /dev/null +++ b/code/modules/mob/mob_transformation_simple.dm @@ -0,0 +1,58 @@ + +//This proc is the most basic of the procs. All it does is make a new mob on the same tile and transfer over a few variables. +//Returns the new mob +//Note that this proc does NOT do MMI related stuff! +/mob/proc/change_mob_type(var/new_type = null, var/turf/location = null, var/new_name = null as text, var/delete_old_mob = 0 as num, var/subspecies) + + if(istype(src,/mob/new_player)) + to_chat(usr, "Cannot convert players who have not entered yet.") + return + + if(!new_type) + new_type = input("Mob type path:", "Mob type") as text|null + + if(istext(new_type)) + new_type = text2path(new_type) + + if( !ispath(new_type) ) + to_chat(usr, "Invalid type path (new_type = [new_type]) in change_mob_type(). Contact a coder.") + return + + if( new_type == /mob/new_player ) + to_chat(usr, "cannot convert into a new_player mob type.") + return + + var/mob/M + if(isturf(location)) + M = new new_type( location ) + else + M = new new_type( src.loc ) + + if(!M || !ismob(M)) + to_chat(usr, "Type path is not a mob (new_type = [new_type]) in change_mob_type(). Contact a coder.") + qdel(M) + return + + if( istext(new_name) ) + M.SetName(new_name) + M.real_name = new_name + else + M.SetName(src.name) + M.real_name = src.real_name + + if(src.dna) + M.dna = src.dna.Clone() + + if(mind) + mind.transfer_to(M) + else + M.key = key + + if(subspecies && istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + H.set_species(subspecies) + + if(delete_old_mob) + spawn(1) + qdel(src) + return M diff --git a/code/modules/mob/new_player/login.dm b/code/modules/mob/new_player/login.dm new file mode 100644 index 00000000..44d2ed16 --- /dev/null +++ b/code/modules/mob/new_player/login.dm @@ -0,0 +1,62 @@ +/var/obj/effect/lobby_image = new/obj/effect/lobby_image() + +/obj/effect/lobby_image + name = "Interstation12" + desc = "This shouldn't be read." + screen_loc = "WEST,SOUTH" + +/obj/effect/lobby_image/Initialize() + icon = GLOB.using_map.lobby_icon + var/known_icon_states = icon_states(icon) + for(var/lobby_screen in GLOB.using_map.lobby_screens) + if(!(lobby_screen in known_icon_states)) + error("Lobby screen '[lobby_screen]' did not exist in the icon set [icon].") + GLOB.using_map.lobby_screens -= lobby_screen + + if(GLOB.using_map.lobby_screens.len) + icon_state = pick(GLOB.using_map.lobby_screens) + else + icon_state = known_icon_states[1] + + . = ..() + +/mob/new_player/Login() + update_Login_details() //handles setting lastKnownIP and computer_id for use by the ban systems as well as checking for multikeying + if(join_motd) + to_chat(src, "
            [join_motd]
            ") + to_chat(src, "
            Game ID:
            [game_id]
            ") + + if(!mind) + mind = new /datum/mind(key) + mind.active = 1 + mind.current = src + + loc = null + client.screen += lobby_image + my_client = client + set_sight(sight|SEE_TURFS) + GLOB.player_list |= src + message_admins("Login: [key], id:[computer_id], ip:[client.address]") + + new_player_panel() + spawn(40) + if(client) + client.playtitlemusic() + maybe_send_staffwarns("connected as new player") + to_lobby( "[key] has joined.") + if(!client.warfare_faction) + //Autobalance them by client, not by mob. This does mean that whoever joins first will always be red team, but that shouldn't be an issue. + if(SSWarfare.blue.team_clients.len < SSWarfare.red.team_clients.len) + client.warfare_faction = BLUE_TEAM + SSWarfare.blue.team_clients += src.client + else + client.warfare_faction = RED_TEAM + SSWarfare.red.team_clients += src.client + if(!has_connected(ckey(client.key)))//If they've never played before show them the beginners guide. + show_new_information() + +proc/to_lobby(var/message) + if(!message) + return + for(var/mob/new_player/player in GLOB.player_list)//Only the new players in the lobby get to see this. + to_chat(player,"Lobby: [message]") diff --git a/code/modules/mob/new_player/logout.dm b/code/modules/mob/new_player/logout.dm new file mode 100644 index 00000000..a5d78d22 --- /dev/null +++ b/code/modules/mob/new_player/logout.dm @@ -0,0 +1,13 @@ +/mob/new_player/Logout() + ready = 0 + + // see login.dm + if(my_client) + my_client.screen -= lobby_image + my_client = null + + ..() + if(!spawning)//Here so that if they are spawning and log out, the other procs can play out and they will have a mob to come back to. + key = null//We null their key before deleting the mob, so they are properly kicked out. + qdel(src) + return diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm new file mode 100644 index 00000000..5c1c9dd6 --- /dev/null +++ b/code/modules/mob/new_player/new_player.dm @@ -0,0 +1,645 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +/mob/new_player + var/ready = 0 + var/spawning = 0//Referenced when you want to delete the new_player later on in the code. + var/totalPlayers = 0 //Player counts for the Lobby tab + var/totalPlayersReady = 0 + var/datum/browser/panel + var/show_invalid_jobs = 0 + universal_speak = 1 + + invisibility = 101 + + density = 0 + stat = DEAD + canmove = 0 + + anchored = 1 // don't get pushed around + + virtual_mob = null // Hear no evil, speak no evil + +/mob/new_player/New() + ..() + verbs += /mob/proc/toggle_antag_pool + +/mob/new_player/verb/new_player_panel() + set src = usr + client.prefs.ShowChoices(src) + +/mob/new_player/proc/new_player_panel_proc() + + var/output = "
            " + output +="
            " + output += "

            Setup Character

            " + + if(!ticker || ticker.current_state <= GAME_STATE_PREGAME) + if(ready) + output += "Not Ready

            " + else + output += "

            \[ Ready | Not Ready \]

            " + + else + output += "View the Crew Manifest

            " + output += "

            Join Game!

            " + + output += "

            Observe

            " + + if(!IsGuestKey(src.key)) + establish_db_connection() + if(dbcon.IsConnected()) + var/isadmin = 0 + if(src.client && src.client.holder) + isadmin = 1 + var/DBQuery/query = dbcon.NewQuery("SELECT id FROM erro_poll_question WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime AND id NOT IN (SELECT pollid FROM erro_poll_vote WHERE ckey = \"[ckey]\") AND id NOT IN (SELECT pollid FROM erro_poll_textreply WHERE ckey = \"[ckey]\")") + query.Execute() + var/newpoll = 0 + while(query.NextRow()) + newpoll = 1 + break + + if(newpoll) + output += "

            Show Player Polls (NEW!)

            " + else + output += "

            Show Player Polls

            " + + output += "
            " + + panel = new(src, "Welcome","Welcome", 210, 280, src) + panel.set_window_options("can_close=0") + panel.set_content(output) + panel.open() + return + +/mob/new_player/Stat() + . = ..() + + if(statpanel("Lobby") && ticker) + if(check_rights(R_INVESTIGATE, 0, src)) + stat("Game Mode:", "[ticker.mode || master_mode][ticker.hide_mode ? " (Secret)" : ""]") + else + stat("Game Mode:", PUBLIC_GAME_MODE) + var/extra_antags = list2params(additional_antag_types) + stat("Added Antagonists:", extra_antags ? extra_antags : "None") + + if(ticker.current_state == GAME_STATE_PREGAME) + stat("Time To Start:", "[ticker.pregame_timeleft][round_progressing ? "" : " (DELAYED)"]") + stat("Players: [totalPlayers]", "Players Ready: [totalPlayersReady]") + totalPlayers = 0 + totalPlayersReady = 0 + for(var/mob/new_player/player in GLOB.player_list) + var/highjob + if(player.client && player.client.prefs && player.client.prefs.job_high) + highjob = " as [player.client.prefs.job_high]" + stat("[player.key]", (player.ready)?("(Playing[highjob])"):(null)) + totalPlayers++ + if(player.ready)totalPlayersReady++ + +/mob/new_player/Topic(href, href_list[]) + if(!client) return 0 + + if(href_list["show_preferences"]) + client.prefs.ShowChoices(src) + return 1 + + if(href_list["ready"]) + if(!ticker || ticker.current_state <= GAME_STATE_PREGAME) + if(!client.prefs.job_low.len && !client.prefs.job_medium.len && !client.prefs.job_high) + to_chat(usr, "You cant press ready, please, choose your occupation") + // Make sure we don't ready up after the round has started + ready = text2num(href_list["ready"]) + else + ready = 0 + client.prefs.ShowChoices(src) + + if(href_list["refresh"]) + client.prefs.ShowChoices(src) + + if(href_list["observe"]) + if(!(initialization_stage&INITIALIZATION_COMPLETE)) + to_chat(src, "Please wait for server initialization to complete...") + return + + if(!config.respawn_delay || client.holder || alert(src,"Are you sure you wish to observe? You will have to wait [config.respawn_delay] minute\s before being able to respawn!","Player Setup","Yes","No") == "Yes") + if(!client) return 1 + var/mob/observer/ghost/observer = new() + + spawning = 1 + sound_to(src, sound(null, repeat = 0, wait = 0, volume = 85, channel = 1))// MAD JAMS cant last forever yo + + + observer.started_as_observer = 1 + close_spawn_windows() + var/obj/O = locate("landmark*Observer-Start") + if(istype(O)) + to_chat(src, "Now teleporting.") + observer.forceMove(O.loc) + else + to_chat(src, "Could not locate an observer spawn point. Use the Teleport verb to jump to the map.") + observer.timeofdeath = world.time // Set the time of death so that the respawn timer works correctly. + + if(isnull(client.holder)) + announce_ghost_joinleave(src) + + var/mob/living/carbon/human/dummy/mannequin = new() + client.prefs.dress_preview_mob(mannequin) + observer.set_appearance(mannequin) + qdel(mannequin) + + if(client.prefs.be_random_name) + client.prefs.real_name = random_name(client.prefs.gender) + observer.real_name = client.prefs.real_name + observer.SetName(observer.real_name) + if(!client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed. + observer.verbs -= /mob/observer/ghost/verb/toggle_antagHUD // Poor guys, don't know what they are missing! + observer.key = key + qdel(src) + + return 1 + + if(href_list["late_join"]) + + if(!ticker || ticker.current_state != GAME_STATE_PLAYING) + to_chat(usr, "The round is either not ready, or has already finished...") + return + LateChoices() //show the latejoin job selection menu + + if(href_list["manifest"]) + ViewManifest() + + if(href_list["SelectedJob"]) + var/datum/job/job = job_master.GetJob(href_list["SelectedJob"]) + + if(!job) + to_chat(usr, "The job '[href_list["SelectedJob"]]' doesn't exist!") + return + + //Prevents people rejoining as same character. + for(var/X in GLOB.human_mob_list) + var/mob/living/carbon/human/C = X + var/char_name = client.prefs.real_name + if(char_name == C.real_name) + to_chat(usr, "There is a character that already exists with the same name - [C.real_name], please join with a different one.") + return + + if(!config.enter_allowed) + to_chat(usr, "There is an administrative lock on entering the game!") + return + if(ticker && ticker.mode && ticker.mode.explosion_in_progress) + to_chat(usr, "The [station_name()] is currently exploding. Joining would go poorly.") + return + + var/datum/species/S = all_species[client.prefs.species] + if(!check_species_allowed(S)) + return 0 + + AttemptLateSpawn(job, client.prefs.spawnpoint) + return + + if(href_list["privacy_poll"]) + establish_db_connection() + if(!dbcon.IsConnected()) + return + var/voted = 0 + + //First check if the person has not voted yet. + var/DBQuery/query = dbcon.NewQuery("SELECT * FROM erro_privacy WHERE ckey='[src.ckey]'") + query.Execute() + while(query.NextRow()) + voted = 1 + break + + //This is a safety switch, so only valid options pass through + var/option = "UNKNOWN" + switch(href_list["privacy_poll"]) + if("signed") + option = "SIGNED" + if("anonymous") + option = "ANONYMOUS" + if("nostats") + option = "NOSTATS" + if("later") + usr << browse(null,"window=privacypoll") + return + if("abstain") + option = "ABSTAIN" + + if(option == "UNKNOWN") + return + + if(!voted) + var/sql = "INSERT INTO erro_privacy VALUES (null, Now(), '[src.ckey]', '[option]')" + var/DBQuery/query_insert = dbcon.NewQuery(sql) + query_insert.Execute() + to_chat(usr, "Thank you for your vote!") + usr << browse(null,"window=privacypoll") + + if(!ready && href_list["preference"]) + if(client) + client.prefs.process_link(src, href_list) + else if(!href_list["late_join"]) + new_player_panel() + + if(href_list["showpoll"]) + + handle_player_polling() + return + + if(href_list["pollid"]) + + var/pollid = href_list["pollid"] + if(istext(pollid)) + pollid = text2num(pollid) + if(isnum(pollid)) + src.poll_player(pollid) + return + + if(href_list["invalid_jobs"]) + show_invalid_jobs = !show_invalid_jobs + LateChoices() + + if(href_list["votepollid"] && href_list["votetype"]) + var/pollid = text2num(href_list["votepollid"]) + var/votetype = href_list["votetype"] + switch(votetype) + if("OPTION") + var/optionid = text2num(href_list["voteoptionid"]) + vote_on_poll(pollid, optionid) + if("TEXT") + var/replytext = href_list["replytext"] + log_text_poll_reply(pollid, replytext) + if("NUMVAL") + var/id_min = text2num(href_list["minid"]) + var/id_max = text2num(href_list["maxid"]) + + if( (id_max - id_min) > 100 ) //Basic exploit prevention + to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.") + return + + for(var/optionid = id_min; optionid <= id_max; optionid++) + if(!isnull(href_list["o[optionid]"])) //Test if this optionid was replied to + var/rating + if(href_list["o[optionid]"] == "abstain") + rating = null + else + rating = text2num(href_list["o[optionid]"]) + if(!isnum(rating)) + return + + vote_on_numval_poll(pollid, optionid, rating) + if("MULTICHOICE") + var/id_min = text2num(href_list["minoptionid"]) + var/id_max = text2num(href_list["maxoptionid"]) + + if( (id_max - id_min) > 100 ) //Basic exploit prevention + to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.") + return + + for(var/optionid = id_min; optionid <= id_max; optionid++) + if(!isnull(href_list["option_[optionid]"])) //Test if this optionid was selected + vote_on_poll(pollid, optionid, 1) + +/mob/new_player/proc/IsJobAvailable(var/datum/job/job) + if(!job) return 0 + if(!job.is_position_available()) return 0 + if(jobban_isbanned(src, job.title)) return 0 + if(!job.player_old_enough(src.client)) return 0 + if(job.no_late_join) return 0 + if(iswarfare()) + if(job.is_red_team)//Can't join the team if they have more people on their side. + if(client?.warfare_faction != RED_TEAM) + return 0 + + if(job.is_blue_team) + if(client?.warfare_faction != BLUE_TEAM) + return 0 + + return 1 + +/mob/new_player/proc/get_branch_pref() + if(client) + return client.prefs.char_branch + +/mob/new_player/proc/get_rank_pref() + if(client) + return client.prefs.char_rank + +/mob/new_player/proc/AttemptLateSpawn(var/datum/job/job, var/spawning_at) + if(src != usr) + return 0 + if(!ticker || ticker.current_state != GAME_STATE_PLAYING) + to_chat(usr, "The round is either not ready, or has already finished...") + return 0 + if(!config.enter_allowed) + to_chat(usr, "There is an administrative lock on entering the game!") + return 0 + + if(!IsJobAvailable(job)) + alert("[job.title] is not available. Please try another.") + return 0 + if(job.is_restricted(client.prefs, src)) + return + + var/datum/spawnpoint/spawnpoint = job_master.get_spawnpoint_for(client, job.title) + var/turf/spawn_turf = pick(spawnpoint.turfs) + if(job.latejoin_at_spawnpoints) + var/obj/S = job_master.get_roundstart_spawnpoint(job.title) + spawn_turf = get_turf(S) + var/radlevel = radiation_repository.get_rads_at_turf(spawn_turf) + var/airstatus = FALSE //IsTurfAtmosUnsafe(spawn_turf) + if(airstatus || radlevel > 0 ) + var/reply = alert(usr, "Warning. Your selected spawn location seems to have unfavorable conditions. \ + You may die shortly after spawning. \ + Spawn anyway? More information: [airstatus] Radiation: [radlevel] Bq", "Atmosphere warning", "Abort", "Spawn anyway") + if(reply == "Abort") + return 0 + else + // Let the staff know, in case the person complains about dying due to this later. They've been warned. + log_and_message_admins("User [src] spawned at spawn point with dangerous atmosphere.") + + // Just in case someone stole our position while we were waiting for input from alert() proc + if(!IsJobAvailable(job)) + to_chat(src, alert("[job.title] is not available. Please try another.")) + return 0 + + job_master.AssignRole(src, job.title, 1) + + var/mob/living/character = create_character(spawn_turf) //creates the human and transfers vars and mind + if(!character) + return 0 + + character = job_master.EquipRank(character, job.title, 1) //equips the human + equip_custom_items(character) + + // AIs don't need a spawnpoint, they must spawn at an empty core + if(character.mind.assigned_role == "AI") + + character = character.AIize(move=0) // AIize the character, but don't move them yet + + // IsJobAvailable for AI checks that there is an empty core available in this list + var/obj/structure/AIcore/deactivated/C = empty_playable_ai_cores[1] + empty_playable_ai_cores -= C + + character.forceMove(C.loc) + var/mob/living/silicon/ai/A = character + A.on_mob_init() + + AnnounceCyborg(character, job.title, "has been downloaded to the empty core in \the [character.loc.loc]") + ticker.mode.handle_latejoin(character) + + qdel(C) + qdel(src) + return + + ticker.mode.handle_latejoin(character) + GLOB.universe.OnPlayerLatejoin(character) + if(job_master.ShouldCreateRecords(job.title)) + if(character.mind.assigned_role != "Cyborg") + CreateModularRecord(character) + ticker.minds += character.mind//Cyborgs and AIs handle this in the transform proc. //TODO!!!!! ~Carn + AnnounceArrival(character, job, spawnpoint.msg) + else + AnnounceCyborg(character, job, spawnpoint.msg) + log_and_message_admins("has joined the round as [character.mind.assigned_role].", character) + qdel(src) + + +/mob/new_player/proc/AnnounceCyborg(var/mob/living/character, var/rank, var/join_message) + if (ticker.current_state == GAME_STATE_PLAYING) + if(character.mind.role_alt_title) + rank = character.mind.role_alt_title + // can't use their name here, since cyborg namepicking is done post-spawn, so we'll just say "A new Cyborg has arrived"/"A new Android has arrived"/etc. + GLOB.global_announcer.autosay("A new[rank ? " [rank]" : " visitor" ] [join_message ? join_message : "has arrived"].", "Arrivals Announcement Computer") + log_and_message_admins("has joined the round as [character.mind.assigned_role].", character) + +/mob/new_player/proc/LateChoices() + var/name = client.prefs.be_random_name ? "friend" : client.prefs.real_name + + var/list/dat = list("
            ") + dat += "Welcome, [name].
            " + dat += "Round Duration: [roundduration2text()]
            " + + if(evacuation_controller.has_evacuated()) + dat += "The [station_name()] has been evacuated.
            " + else if(evacuation_controller.is_evacuating()) + if(evacuation_controller.emergency_evacuation) // Emergency shuttle is past the point of no recall + dat += "The [station_name()] is currently undergoing evacuation procedures.
            " + else // Crew transfer initiated + dat += "The [station_name()] is currently undergoing crew transfer procedures.
            " + + dat += "Choose from the following open/valid positions:
            " + dat += "[show_invalid_jobs ? "Hide":"Show"] unavailable jobs.
            " + + var/list/jobcats = list( // This is designed for warfare, in a warfare-less environment, this will need to be changed + "Team Red"=list("color"="#b27676", "jobs"=list()), + "Team Blue"=list("color"="#76abb2", "jobs"=list()), + "Command"=list("color"="#76abb2", "jobs"=list()), + "Security"=list("color"="#b27676", "jobs"=list()), + "Upkeeper"=list("color"="#76abb2", "jobs"=list()), + "Medical"=list("color"="#76abb2", "jobs"=list()), + "Supply"=list("color"="#76abb2", "jobs"=list()), + "Civillian"=list("color"="#76abb2", "jobs"=list()), + "Misc"=list("color"="Grey", "jobs"=list()) + ) + + for(var/datum/job/job in job_master.occupations) + if(!IsJobAvailable(job)) + continue + + if(job.is_blue_team) + jobcats["Team Blue"]["jobs"] += job + else if(job.is_red_team) + jobcats["Team Red"]["jobs"] += job + else if(job.department_flag & COM) + jobcats["Command"]["jobs"] += job + else if(job.department_flag & SEC) + jobcats["Security"]["jobs"] += job + else if(job.department_flag & ENG) + jobcats["Upkeeper"]["jobs"] += job + else if(job.department_flag & MED) + jobcats["Medical"]["jobs"] += job + else if(job.department_flag & SUP) + jobcats["Upkeeper"]["jobs"] += job + else if(job.department_flag & CIV) + jobcats["Civillian"]["jobs"] += job + else + jobcats["Misc"]["jobs"] += job + + for(var/cat in jobcats) + if(!LAZYLEN(jobcats[cat]["jobs"])) // if there's no jobs, don't show an empty fieldset + continue + dat += "
            " + dat += "[cat]" + dat += "" + + for(var/datum/job/job in jobcats[cat]["jobs"]) + + if(job && IsJobAvailable(job)) + if(job.minimum_character_age && (client.prefs.age < job.minimum_character_age)) + continue + + var/active = 0 + // Only players with the job assigned and AFK for less than 10 minutes count as active + for(var/mob/M in GLOB.player_list) if(M.mind && M.client && M.mind.assigned_role == job.title && M.client.inactivity <= 10 * 60 * 10) + active++ + + if(job.is_restricted(client.prefs)) + if(show_invalid_jobs) + dat += "" + else + dat += "" + dat += "
            [job.title][job.current_positions](Active: [active])
            [job.title][job.current_positions](Active: [active])
            " + dat += "

            " + + dat += "
            " + var/datum/browser/popup = new(src, "latechoices","Roles", 450, 640, src) + popup.set_content(jointext(dat, null)) + popup.open() + +/mob/new_player/proc/create_character(var/turf/spawn_turf) + spawning = 1 + close_spawn_windows() + + var/mob/living/carbon/human/new_character + + var/datum/species/chosen_species + if(client.prefs.species) + chosen_species = all_species[client.prefs.species] + + if(!spawn_turf) + var/datum/spawnpoint/spawnpoint = job_master.get_spawnpoint_for(client, get_rank_pref()) + spawn_turf = pick(spawnpoint.turfs) + + if(chosen_species) + if(!check_species_allowed(chosen_species)) + spawning = 0 //abort + return null + new_character = new(spawn_turf, chosen_species.name) + + if(!new_character) + new_character = new(spawn_turf) + + new_character.lastarea = get_area(spawn_turf) + + if(ticker.random_players) + new_character.gender = pick(MALE, FEMALE) + client.prefs.real_name = random_name(new_character.gender) + client.prefs.randomize_appearance_and_body_for(new_character) + else + if(client.warfare_deaths) + client.prefs.be_random_name = TRUE + client.prefs.copy_to(new_character) + + sound_to(src, sound(null, repeat = 0, wait = 0, volume = 85, channel = 1))// MAD JAMS cant last forever yo + + if(mind) + mind.active = 0 //we wish to transfer the key manually + mind.original = new_character + mind.transfer_to(new_character) //won't transfer key since the mind is not active + + new_character.SetName(real_name) + new_character.dna.ready_dna(new_character) + new_character.dna.b_type = client.prefs.b_type + new_character.sync_organ_dna() + if(client.prefs.disabilities) + // Set defer to 1 if you add more crap here so it only recalculates struc_enzymes once. - N3X + new_character.dna.SetSEState(GLOB.GLASSESBLOCK,1,0) + new_character.disabilities |= NEARSIGHTED + + // Give them their cortical stack if we're using them. + if(config && config.use_cortical_stacks && client && client.prefs.has_cortical_stack /*&& new_character.should_have_organ(BP_BRAIN)*/) + new_character.create_stack() + + // Do the initial caching of the player's body icons. + new_character.force_update_limbs() + new_character.update_eyes() + new_character.regenerate_icons() + + new_character.key = key //Manually transfer the key to log them in + return new_character + +/mob/new_player/proc/ViewManifest() + var/dat = "
            " + dat += html_crew_manifest(OOC = 1) + //src << browse(dat, "window=manifest;size=370x420;can_close=1") + var/datum/browser/popup = new(src, "Crew Manifest", "Crew Manifest", 370, 420, src) + popup.set_content(dat) + popup.open() + +/mob/new_player/Move() + return 0 + +/mob/new_player/proc/close_spawn_windows() + src << browse(null, "window=latechoices") //closes late choices window + src <IS12 Warfare +Hello! It appears you are new here! Thanks for joining IS12 Warfare. Here is some important information to get you started! +

            Discord Link

            +Discord +

            Wiki Link

            +Wiki +

            Server Summary

            +IS12 Warfare is a WW1-esque team deathmatch game with visual influences from Gone With The Blastwave. You're either red, or blue, and your objective is to either deplete all the other sides reinforcements, or take over their trenches and activate the point of no return. It plays a bit like how rush plays from the battlefield series, if you've played that before. While it takes some visual influence from Gone With The Blastwave it is not related to it in any other way. This is not a fan game, it does not take place in the same universe as the comic, it is not affiliated with the comic in any way. +

            Some Notes

            +Just as a general note, chat bar commands in game do not work. You will have to use the panels on the side if you wish to use any commands. Typing in the command bar will use OOC if you are in the lobby, and it will use say automatically if you're in game. +Controls are ingame under the \"view controls\" button in OOC. +Rules are ingame under the \"rules\" button in OOC. +

            Enjoy your stay!

            "} + src << browse(dat, "window=welcome") \ No newline at end of file diff --git a/code/modules/mob/new_player/poll.dm b/code/modules/mob/new_player/poll.dm new file mode 100644 index 00000000..1561144d --- /dev/null +++ b/code/modules/mob/new_player/poll.dm @@ -0,0 +1,526 @@ + +/mob/new_player/proc/handle_privacy_poll() + establish_db_connection() + if(!dbcon.IsConnected()) + return + var/voted = 0 + + var/DBQuery/query = dbcon.NewQuery("SELECT * FROM erro_privacy WHERE ckey='[src.ckey]'") + query.Execute() + while(query.NextRow()) + voted = 1 + break + + if(!voted) + privacy_poll() + +/mob/new_player/proc/privacy_poll() + var/output = "
            Player poll" + output +="
            " + output += "We would like to expand our stats gathering." + output += "
            This however involves gathering data about player behavior, play styles, unique player numbers, play times, etc. Data like that cannot be gathered fully anonymously, which is why we're asking you how you'd feel if player-specific data was gathered. Prior to any of this actually happening, a privacy policy will be discussed, but before that can begin, we'd preliminarily like to know how you feel about the concept." + output +="
            " + output += "How do you feel about the game gathering player-specific statistics? This includes statistics about individual players as well as in-game polling/opinion requests." + + output += "

            Signed stats gathering" + output += "
            Pick this option if you think usernames should be logged with stats. This allows us to have personalized stats as well as polls." + + output += "

            Anonymous stats gathering" + output += "
            Pick this option if you think only hashed (indecipherable) usernames should be logged with stats. This doesn't allow us to have personalized stats, as we can't tell who is who (hashed values aren't readable), we can however have ingame polls." + + output += "

            No stats gathering" + output += "
            Pick this option if you don't want player-specific stats gathered. This does not allow us to have player-specific stats or polls." + + output += "

            Ask again later" + output += "
            This poll will be brought up again next round." + + output += "

            Don't ask again" + output += "
            Only pick this if you are fine with whatever option wins." + + output += "

            " + + src << browse(output,"window=privacypoll;size=600x500") + return + +/datum/polloption + var/optionid + var/optiontext + +/mob/new_player/proc/handle_player_polling() + establish_db_connection() + if(dbcon.IsConnected()) + var/isadmin = 0 + if(src.client && src.client.holder) + isadmin = 1 + + var/DBQuery/select_query = dbcon.NewQuery("SELECT id, question FROM erro_poll_question WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime") + select_query.Execute() + + var/output = "
            Player polls" + output +="
            " + + var/pollid + var/pollquestion + + output += "" + var/color1 = "#ececec" + var/color2 = "#e2e2e2" + var/i = 0 + + while(select_query.NextRow()) + pollid = select_query.item[1] + pollquestion = select_query.item[2] + output += "" + i++ + + output += "
            [pollquestion]
            " + + src << browse(output,"window=playerpolllist;size=500x300") + + + +/mob/new_player/proc/poll_player(var/pollid = -1) + if(pollid == -1) return + establish_db_connection() + if(dbcon.IsConnected()) + + var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype, multiplechoiceoptions FROM erro_poll_question WHERE id = [pollid]") + select_query.Execute() + + var/pollstarttime = "" + var/pollendtime = "" + var/pollquestion = "" + var/polltype = "" + var/found = 0 + var/multiplechoiceoptions = 0 + + while(select_query.NextRow()) + pollstarttime = select_query.item[1] + pollendtime = select_query.item[2] + pollquestion = select_query.item[3] + polltype = select_query.item[4] + found = 1 + break + + if(!found) + to_chat(usr, "Poll question details not found.") + return + + switch(polltype) + //Polls that have enumerated options + if("OPTION") + var/DBQuery/voted_query = dbcon.NewQuery("SELECT optionid FROM erro_poll_vote WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") + voted_query.Execute() + + var/voted = 0 + var/votedoptionid = 0 + while(voted_query.NextRow()) + votedoptionid = text2num(voted_query.item[1]) + voted = 1 + break + + var/list/datum/polloption/options = list() + + var/DBQuery/options_query = dbcon.NewQuery("SELECT id, text FROM erro_poll_option WHERE pollid = [pollid]") + options_query.Execute() + while(options_query.NextRow()) + var/datum/polloption/PO = new() + PO.optionid = text2num(options_query.item[1]) + PO.optiontext = options_query.item[2] + options += PO + + var/output = "
            Player poll" + output +="
            " + output += "Question: [pollquestion]
            " + output += "Poll runs from [pollstarttime] until [pollendtime]

            " + + if(!voted) //Only make this a form if we have not voted yet + output += "

            " + output += "" + output += "" + output += "" + + output += "
            " + for(var/datum/polloption/O in options) + if(O.optionid && O.optiontext) + if(voted) + if(votedoptionid == O.optionid) + output += "[O.optiontext]
            " + else + output += "[O.optiontext]
            " + else + output += " [O.optiontext]
            " + output += "
            " + + if(!voted) //Only make this a form if we have not voted yet + output += "

            " + output += "

            " + + output += "
            " + + src << browse(output,"window=playerpoll;size=500x250") + + //Polls with a text input + if("TEXT") + var/DBQuery/voted_query = dbcon.NewQuery("SELECT replytext FROM erro_poll_textreply WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") + voted_query.Execute() + + var/voted = 0 + var/vote_text = "" + while(voted_query.NextRow()) + vote_text = voted_query.item[1] + voted = 1 + break + + + var/output = "
            Player poll" + output +="
            " + output += "Question: [pollquestion]
            " + output += "Feedback gathering runs from [pollstarttime] until [pollendtime]

            " + + if(!voted) //Only make this a form if we have not voted yet + output += "

            " + output += "" + output += "" + output += "" + + output += "Please provide feedback below. You can use any letters of the English alphabet, numbers and the symbols: . , ! ? : ; -
            " + output += "" + + output += "

            " + output += "

            " + + output += "
            " + output += "" + output += "" + output += "" + output += "" + output += "" + output += "
            " + else + output += "[vote_text]" + + src << browse(output,"window=playerpoll;size=500x500") + + //Polls with a text input + if("NUMVAL") + var/DBQuery/voted_query = dbcon.NewQuery("SELECT o.text, v.rating FROM erro_poll_option o, erro_poll_vote v WHERE o.pollid = [pollid] AND v.ckey = '[usr.ckey]' AND o.id = v.optionid") + voted_query.Execute() + + var/output = "
            Player poll" + output +="
            " + output += "Question: [pollquestion]
            " + output += "Poll runs from [pollstarttime] until [pollendtime]

            " + + var/voted = 0 + while(voted_query.NextRow()) + voted = 1 + + var/optiontext = voted_query.item[1] + var/rating = voted_query.item[2] + + output += "
            [optiontext] - [rating]" + + if(!voted) //Only make this a form if we have not voted yet + output += "

            " + output += "" + output += "" + output += "" + + var/minid = 999999 + var/maxid = 0 + + var/DBQuery/option_query = dbcon.NewQuery("SELECT id, text, minval, maxval, descmin, descmid, descmax FROM erro_poll_option WHERE pollid = [pollid]") + option_query.Execute() + while(option_query.NextRow()) + var/optionid = text2num(option_query.item[1]) + var/optiontext = option_query.item[2] + var/minvalue = text2num(option_query.item[3]) + var/maxvalue = text2num(option_query.item[4]) + var/descmin = option_query.item[5] + var/descmid = option_query.item[6] + var/descmax = option_query.item[7] + + if(optionid < minid) + minid = optionid + if(optionid > maxid) + maxid = optionid + + var/midvalue = round( (maxvalue + minvalue) / 2) + + if(isnull(minvalue) || isnull(maxvalue) || (minvalue == maxvalue)) + continue + + output += "
            [optiontext]: " + + output += "" + output += "" + + output += "

            " + output += "

            " + + src << browse(output,"window=playerpoll;size=500x500") + if("MULTICHOICE") + var/DBQuery/voted_query = dbcon.NewQuery("SELECT optionid FROM erro_poll_vote WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") + voted_query.Execute() + + var/list/votedfor = list() + var/voted = 0 + while(voted_query.NextRow()) + votedfor.Add(text2num(voted_query.item[1])) + voted = 1 + + var/list/datum/polloption/options = list() + var/maxoptionid = 0 + var/minoptionid = 0 + + var/DBQuery/options_query = dbcon.NewQuery("SELECT id, text FROM erro_poll_option WHERE pollid = [pollid]") + options_query.Execute() + while(options_query.NextRow()) + var/datum/polloption/PO = new() + PO.optionid = text2num(options_query.item[1]) + PO.optiontext = options_query.item[2] + if(PO.optionid > maxoptionid) + maxoptionid = PO.optionid + if(PO.optionid < minoptionid || !minoptionid) + minoptionid = PO.optionid + options += PO + + + if(select_query.item[5]) + multiplechoiceoptions = text2num(select_query.item[5]) + + var/output = "
            Player poll" + output +="
            " + output += "Question: [pollquestion]
            You can select up to [multiplechoiceoptions] options. If you select more, the first [multiplechoiceoptions] will be saved.
            " + output += "Poll runs from [pollstarttime] until [pollendtime]

            " + + if(!voted) //Only make this a form if we have not voted yet + output += "

            " + output += "" + output += "" + output += "" + output += "" + output += "" + + output += "
            " + for(var/datum/polloption/O in options) + if(O.optionid && O.optiontext) + if(voted) + if(O.optionid in votedfor) + output += "[O.optiontext]
            " + else + output += "[O.optiontext]
            " + else + output += " [O.optiontext]
            " + output += "
            " + + if(!voted) //Only make this a form if we have not voted yet + output += "

            " + output += "

            " + + output += "
            " + + src << browse(output,"window=playerpoll;size=500x250") + return + +/mob/new_player/proc/vote_on_poll(var/pollid = -1, var/optionid = -1, var/multichoice = 0) + if(pollid == -1 || optionid == -1) + return + + if(!isnum(pollid) || !isnum(optionid)) + return + establish_db_connection() + if(dbcon.IsConnected()) + + var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype, multiplechoiceoptions FROM erro_poll_question WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") + select_query.Execute() + + var/validpoll = 0 + var/multiplechoiceoptions = 0 + + while(select_query.NextRow()) + if(select_query.item[4] != "OPTION" && select_query.item[4] != "MULTICHOICE") + return + validpoll = 1 + if(select_query.item[5]) + multiplechoiceoptions = text2num(select_query.item[5]) + break + + if(!validpoll) + to_chat(usr, "Poll is not valid.") + return + + var/DBQuery/select_query2 = dbcon.NewQuery("SELECT id FROM erro_poll_option WHERE id = [optionid] AND pollid = [pollid]") + select_query2.Execute() + + var/validoption = 0 + + while(select_query2.NextRow()) + validoption = 1 + break + + if(!validoption) + to_chat(usr, "Poll option is not valid.") + return + + var/alreadyvoted = 0 + + var/DBQuery/voted_query = dbcon.NewQuery("SELECT id FROM erro_poll_vote WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") + voted_query.Execute() + + while(voted_query.NextRow()) + alreadyvoted += 1 + if(!multichoice) + break + + if(!multichoice && alreadyvoted) + to_chat(usr, "You already voted in this poll.") + return + + if(multichoice && (alreadyvoted >= multiplechoiceoptions)) + to_chat(usr, "You already have more than [multiplechoiceoptions] logged votes on this poll. Enough is enough. Contact the database admin if this is an error.") + return + + var/adminrank = "Player" + if(usr && usr.client && usr.client.holder) + adminrank = usr.client.holder.rank + + + var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO erro_poll_vote (id ,datetime ,pollid ,optionid ,ckey ,ip ,adminrank) VALUES (null, Now(), [pollid], [optionid], '[usr.ckey]', '[usr.client.address]', '[adminrank]')") + insert_query.Execute() + + to_chat(usr, "Vote successful.") + usr << browse(null,"window=playerpoll") + + +/mob/new_player/proc/log_text_poll_reply(var/pollid = -1, var/replytext = "") + if(pollid == -1 || replytext == "") + return + + if(!isnum(pollid) || !istext(replytext)) + return + establish_db_connection() + if(dbcon.IsConnected()) + + var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype FROM erro_poll_question WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") + select_query.Execute() + + var/validpoll = 0 + + while(select_query.NextRow()) + if(select_query.item[4] != "TEXT") + return + validpoll = 1 + break + + if(!validpoll) + to_chat(usr, "Poll is not valid.") + return + + var/alreadyvoted = 0 + + var/DBQuery/voted_query = dbcon.NewQuery("SELECT id FROM erro_poll_textreply WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") + voted_query.Execute() + + while(voted_query.NextRow()) + alreadyvoted = 1 + break + + if(alreadyvoted) + to_chat(usr, "You already sent your feedback for this poll.") + return + + var/adminrank = "Player" + if(usr && usr.client && usr.client.holder) + adminrank = usr.client.holder.rank + + + replytext = replacetext(replytext, "%BR%", "") + replytext = replacetext(replytext, "\n", "%BR%") + var/text_pass = reject_bad_text(replytext,8000) + replytext = replacetext(replytext, "%BR%", "
            ") + + if(!text_pass) + to_chat(usr, "The text you entered was blank, contained illegal characters or was too long. Please correct the text and submit again.") + return + + var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO erro_poll_textreply (id ,datetime ,pollid ,ckey ,ip ,replytext ,adminrank) VALUES (null, Now(), [pollid], '[usr.ckey]', '[usr.client.address]', '[replytext]', '[adminrank]')") + insert_query.Execute() + + to_chat(usr, "Feedback logging successful.") + usr << browse(null,"window=playerpoll") + + +/mob/new_player/proc/vote_on_numval_poll(var/pollid = -1, var/optionid = -1, var/rating = null) + if(pollid == -1 || optionid == -1) + return + + if(!isnum(pollid) || !isnum(optionid)) + return + establish_db_connection() + if(dbcon.IsConnected()) + + var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype FROM erro_poll_question WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") + select_query.Execute() + + var/validpoll = 0 + + while(select_query.NextRow()) + if(select_query.item[4] != "NUMVAL") + return + validpoll = 1 + break + + if(!validpoll) + to_chat(usr, "Poll is not valid.") + return + + var/DBQuery/select_query2 = dbcon.NewQuery("SELECT id FROM erro_poll_option WHERE id = [optionid] AND pollid = [pollid]") + select_query2.Execute() + + var/validoption = 0 + + while(select_query2.NextRow()) + validoption = 1 + break + + if(!validoption) + to_chat(usr, "Poll option is not valid.") + return + + var/alreadyvoted = 0 + + var/DBQuery/voted_query = dbcon.NewQuery("SELECT id FROM erro_poll_vote WHERE optionid = [optionid] AND ckey = '[usr.ckey]'") + voted_query.Execute() + + while(voted_query.NextRow()) + alreadyvoted = 1 + break + + if(alreadyvoted) + to_chat(usr, "You already voted in this poll.") + return + + var/adminrank = "Player" + if(usr && usr.client && usr.client.holder) + adminrank = usr.client.holder.rank + + + var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO erro_poll_vote (id ,datetime ,pollid ,optionid ,ckey ,ip ,adminrank, rating) VALUES (null, Now(), [pollid], [optionid], '[usr.ckey]', '[usr.client.address]', '[adminrank]', [(isnull(rating)) ? "null" : rating])") + insert_query.Execute() + + to_chat(usr, "Vote successful.") + usr << browse(null,"window=playerpoll") \ No newline at end of file diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm new file mode 100644 index 00000000..02ae65ee --- /dev/null +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -0,0 +1,90 @@ +#define ASSIGN_LIST_TO_COLORS(L, R, G, B) if(L) { R = L[1]; G = L[2]; B = L[3]; } + +/datum/preferences + //The mob should have a gender you want before running this proc. Will run fine without H + proc/randomize_appearance_and_body_for(var/mob/living/carbon/human/H) + var/datum/species/current_species = all_species[species] + if(!current_species) current_species = all_species[SPECIES_HUMAN] + gender = pick(current_species.genders) + + h_style = random_hair_style(gender, species) + f_style = random_facial_hair_style(gender, species) + if(current_species) + if(current_species.appearance_flags & HAS_A_SKIN_TONE) + s_tone = current_species.get_random_skin_tone() || s_tone + if(current_species.appearance_flags & HAS_EYE_COLOR) + ASSIGN_LIST_TO_COLORS(current_species.get_random_eye_color(), r_eyes, g_eyes, b_eyes) + if(current_species.appearance_flags & HAS_SKIN_COLOR) + ASSIGN_LIST_TO_COLORS(current_species.get_random_skin_color(), r_skin, g_skin, b_skin) + if(current_species.appearance_flags & HAS_HAIR_COLOR) + var/hair_colors = current_species.get_random_hair_color() + if(hair_colors) + ASSIGN_LIST_TO_COLORS(hair_colors, r_hair, g_hair, b_hair) + + if(prob(75)) + r_facial = r_hair + g_facial = g_hair + b_facial = b_hair + else + ASSIGN_LIST_TO_COLORS(current_species.get_random_facial_hair_color(), r_facial, g_facial, b_facial) + + if(current_species.appearance_flags & HAS_UNDERWEAR) + all_underwear.Cut() + for(var/datum/category_group/underwear/WRC in GLOB.underwear.categories) + var/datum/category_item/underwear/WRI = pick(WRC.items) + all_underwear[WRC.name] = WRI.name + + backpack = decls_repository.get_decl(pick(subtypesof(/decl/backpack_outfit))) + age = rand(current_species.min_age, current_species.max_age) + b_type = RANDOM_BLOOD_TYPE + if(H) + copy_to(H) + +#undef ASSIGN_LIST_TO_COLORS + +/datum/preferences/proc/dress_preview_mob(var/mob/living/carbon/human/mannequin) + var/update_icon = FALSE + copy_to(mannequin, TRUE) + + var/datum/job/previewJob + if(equip_preview_mob && job_master) + // Determine what job is marked as 'High' priority, and dress them up as such. + if("Assistant" in job_low) + previewJob = job_master.GetJob("Assistant") + else + for(var/datum/job/job in job_master.occupations) + if(job.title == job_high) + previewJob = job + break + else + return + + if((equip_preview_mob & EQUIP_PREVIEW_JOB) && previewJob) + mannequin.job = previewJob.title + previewJob.equip_preview(mannequin, player_alt_titles[previewJob.title], mannequin.char_branch) + update_icon = TRUE + + if(update_icon) + mannequin.update_icons() + +/datum/preferences/proc/update_preview_icon() + var/mob/living/carbon/human/dummy/mannequin/mannequin = get_mannequin(client_ckey) + mannequin.delete_inventory(TRUE) + dress_preview_mob(mannequin) + + preview_icon = icon('icons/effects/128x48.dmi', bgstate) + preview_icon.Scale(48+32, 16+32) + + mannequin.dir = NORTH + var/icon/stamp = getFlatIcon(mannequin, NORTH, always_use_defdir = 1) + preview_icon.Blend(stamp, ICON_OVERLAY, 25, 17) + + mannequin.dir = WEST + stamp = getFlatIcon(mannequin, WEST, always_use_defdir = 1) + preview_icon.Blend(stamp, ICON_OVERLAY, 1, 9) + + mannequin.dir = SOUTH + stamp = getFlatIcon(mannequin, SOUTH, always_use_defdir = 1) + preview_icon.Blend(stamp, ICON_OVERLAY, 49, 1) + + preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2) // Scaling here to prevent blurring in the browser. diff --git a/code/modules/mob/new_player/skill.dm b/code/modules/mob/new_player/skill.dm new file mode 100644 index 00000000..c167b5fb --- /dev/null +++ b/code/modules/mob/new_player/skill.dm @@ -0,0 +1,309 @@ +var/const/SKILL_NONE = 0 +var/const/SKILL_BASIC = 1 +var/const/SKILL_ADEPT = 2 +var/const/SKILL_EXPERT = 3 + +// Specific skill typepaths that won't show up on the skills panel. +// This is used to hide the category subtypes, without having to use special variable. +var/list/hidden_skill_types = list(\ + /datum/skill,\ + /datum/skill/secondary,\ + /datum/skill/security,\ + /datum/skill/engineering,\ + /datum/skill/research,\ + /datum/skill/medical\ + ) + + +proc/setup_skills() + if(SKILLS == null) + SKILLS = list() + for(var/T in (typesof(/datum/skill)-hidden_skill_types)) + var/datum/skill/S = new T + if(S.ID != "none") + if(!SKILLS.Find(S.field)) + SKILLS[S.field] = list() + var/list/L = SKILLS[S.field] + L += S + +mob/living/carbon/human/proc/GetSkillClass(points) + return CalculateSkillClass(points, age) + +proc/show_skill_window(var/mob/user, var/mob/living/carbon/human/M) + if(!istype(M)) return + if(SKILLS == null) + setup_skills() + + if(!M.skills || M.skills.len == 0) + to_chat(user, "There are no skills to display.") + return + + var/HTML = "" + HTML += "Select your Skills
            " + HTML += "Current skill level: [M.GetSkillClass(M.used_skillpoints)] ([M.used_skillpoints])
            " + HTML += "" + for(var/V in SKILLS) + HTML += "" + for(var/datum/skill/S in SKILLS[V]) + var/level = M.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\]
            " + + user << browse(null, "window=preferences") + user << browse(HTML, "window=show_skills;size=600x800") + return + +mob/living/carbon/human/verb/show_skills() + set category = "IC" + set name = "Show Own Skills" + + show_skill_window(src, src) + + +/datum/skill + var/ID = "none" // ID of this skill. + var/name = "None" // Name of the skill. This is what the player sees. + var/desc = "Placeholder skill" // Generic description of this skill. + var/field = "Unset" // Category under which this skill will be listed. + var/secondary = FALSE // Whether the skill is secondary. Secondary skills are cheaper and lack the Amateur level. + var/cost_multiplier = 1 // Relative cost of skill + + // Specific descriptions for specific skill levels. + var/desc_unskilled = "Unskilled Descripton" + var/desc_amateur = "Amateur Description" + var/desc_trained = "Trained Description" + var/desc_professional = "Expert Description" + +/datum/skill/secondary + field = "Secondary" + secondary = TRUE + +/datum/skill/security + field = "Security" + +/datum/skill/engineering + field = "Engineering" + +/datum/skill/research + field = "Research" + +/datum/skill/medical + field = "Medical" + +var/global/list/SKILLS = null + +// ONLY SKILL DEFINITIONS BELOW THIS LINE +// Category: Secondary + +/datum/skill/secondary/management + ID = "management" + name = "Command" + desc = "Your ability to manage and commandeer other crew members." + desc_unskilled = "You know a little about management, but you have a lot of flaws and little experience. You are likely to micromanage, lose track of people, or generally muck things up. Handling a major crisis is probably beyond your ability." + desc_trained = "You're a good commander. You know how to coordinate the efforts of a large group of people effectively. You'll still be thrown off in a crisis, but you'll probably get through it." + desc_professional = "You're an excellent commander. In addition to just doing your job, you know how to inspire love, loyalty or fear, and you handle crises smoothly and efficiently." + +/datum/skill/secondary/EVA + ID = "EVA" + name = "Extra-vehicular activity" + desc = "This skill describes your skill and knowledge of space-suits and working in vacuum." + desc_unskilled = "You have basic safety training common to people who work in space: You know how to put on and seal your internals, and you can probably struggle into a space suit if you really need to, though you'll be clumsy at it. You're still prone to mistakes that may leave you trying to breathe vacuum." + desc_trained = "You can comfortably use a space suit and do so regularly in the course of your work. Checking your internals is second nature to you, and you don't panic in an emergency." + desc_professional = "You can use all kinds of space suits, including specialized versions. You can use a jet pack to navigate and are just as much at home in a vacuum as in atmosphere. You probably do your job almost entirely EVA." + cost_multiplier = 0.5 + +/datum/skill/secondary/law + ID = "law" + name = "Legal" + desc = "Your knowledge of legal systems and procedures. This includes law systems, corporate regulations, and standard operating procedure. A low level in this skill is typical for law enforcement, a high level in this skill is typical for people in command of a station or vessel." + desc_unskilled = "You know most of what's legal and illegal in your everyday life and work, though you're fuzzy on the finer points of the law, especially if it doesn't apply to your own daily experience." + desc_trained = "You know and understand the law in a practical sense. You know the punishments for crimes and you can read and understand a legal document easily. You may be in Security or Command." + desc_professional = "You have a law degree or the equivalent amount of knowledge. You can draw up legal contracts, interpret the minutiae of the law, settle disagreements, and argue a case in court." + +/datum/skill/secondary/botany + ID = "botany" + name = "Botany" + desc = "Describes how good a character is at growing and maintaining plants." + desc_unskilled = "You've done some gardening. You can water, weed, fertilize, plant, and harvest, and you can recognize and deal with pests. You may be a hobby gardener." + desc_trained = "You're a botanist or farmer, growing crops on large scales or doing botanical research. You know the basics of manipulating plant genes." + desc_professional = "You're a specialized botanist. You can care for even the most exotic, fragile, or dangerous plants, and you can create custom hybrids and modified strains." + cost_multiplier = 0.5 + +/datum/skill/secondary/cooking + ID = "cooking" + name = "Cooking" + desc = "Describes a character's skill at preparing meals and other consumable goods. This includes mixing alcoholic beverages." + desc_unskilled = "You can make simple meals and do the cooking for your family. Things like spaghetti, grilled cheese, or simple mixed drinks are your usual fare." + desc_trained = "You can cook professionally, keeping an entire crew fed easily. Your food is tasty and you don't have a problem with tricky or complicated dishes. You can be depended on to make just about any commonly-served drink." + desc_professional = "Not only are you good at cooking and mixing drinks, but you can manage a kitchen staff and cater for special events. You can safely prepare exotic foods and drinks that would be poisonous if prepared incorrectly." + cost_multiplier = 0.5 + +// Category: Security + +/datum/skill/security/combat + ID = "combat" + name = "Close Combat" + desc = "This skill describes your training in hand-to-hand combat or melee weapon usage. While expertise in this area is rare in the era of firearms, experts still exist among athletes." + desc_unskilled = "You can throw a punch or a kick, but it'll knock you off-balance. You're inexperienced and have probably never been in a serious hand-to-hand fight. In a fight, you might panic and run, grab whatever's nearby and blindly strike out with it, or (if the other guy is just as much of a beginner as you are) make a fool out of yourself." + desc_amateur = "You either have some experience with fistfights, or you have some training in a martial art. You can handle yourself if you really have to, and if you're a security officer, can handle a stun baton at least well enough to get the handcuffs onto a criminal." + desc_trained = "You're good at hand-to-hand combat. You've trained explicitly in a martial art or as a close combatant as part of a military or police unit. You can use weaponry competently and you can think strategically and quickly in a melee. You're in good shape and you spend time training." + desc_professional = "You specialize in hand-to-hand combat. You're well-trained in a practical martial art, and in good shape. You spend a lot of time practicing. You can take on just about anyone, use just about any weapon, and usually come out on top. You may be a professional athlete or special forces member." + cost_multiplier = 1.2 + +/datum/skill/security/weapons + ID = "weapons" + name = "Weapons Expertise" + desc = "This skill describes your expertise with and knowledge of weapons. A low level in this skill implies knowledge of simple weapons, for example flashes. A high level in this skill implies knowledge of complex weapons, such as unconfigured grenades, riot shields, pulse rifles or bombs. A low-medium level in this skill is typical for security officers, a high level of this skill is typical for special agents and soldiers." + desc_unskilled = "You know how to recognize a weapon when you see one. You can probably use pepper spray or a flash, though you might fumble and turn them on yourself by mistake. You're likely to shoot yourself in the foot or forget to take the safety off. Your lack of training may make you more dangerous to your allies than your enemies." + desc_amateur = "You know how to handle weapons safely, and you're comfortable using simple weapons. Your aim is decent and you can be trusted not to do anything stupid with a weapon, but your training isn't automatic yet and your performance will degrade in high-stress situations." + desc_trained = "You've used firearms and other ranged weapons in a high-stress situation, and your skills have become automatic. You spend time practicing at the firing range. Your aim is good. You can maintain and repair your weaponry. You may have military or police experience and you probably carry a weapon on the job." + desc_professional = "You are an exceptional shot with a variety of weapons, from simple to exotic. You can depend on hitting not just your target, but a specific part of your target, such as shooting someone in the leg. You use a weapon as naturally as though it were a part of your own body. You may be a professional marksman of some kind. You probably know a good deal about tactics, and you may have designed or modified your own weaponry." + +/datum/skill/security/forensics + ID = "forensics" + name = "Forensics" + desc = "Describes your skill at performing forensic examinations and identifying vital evidence. Does not cover analytical abilities, and as such isn't the only indicator for your investigation skill. Note that in order to perform autopsy, the surgery skill is also required." + desc_unskilled = "You know that detectives solve crimes. You may have some idea that it's bad to contaminate a crime scene, but you're not too clear on the details." + desc_amateur = "You know how to avoid contaminating a crime scene. You know how to use the tools of the trade (scanner, computer database, and so forth), and you can conduct an interview with a witness or a suspect." + desc_trained = "You're a police officer, pathologist, or detective. You can secure a crime scene, gather evidence, interview witnesses, and put two and two together to get an arrest. If you're trained in anatomy, you can perform an autopsy." + desc_professional = "You specialize in criminal investigations. Your ability to gather and analyze evidence has been honed through intensive schooling, years of practice, or most likely both. You can organize a manhunt or draw a criminal into a trap, and though you're behind the scenes and may never even see the criminal, your skills make the difference between an unsolved crime and a convicted criminal." + cost_multiplier = 1.5 + +// Category: Engineering + +/datum/skill/engineering/construction + ID = "construction" + name = "Construction" + desc = "Your ability to construct various buildings, such as walls, floors, tables and so on. Note that constructing devices such as APCs additionally requires the Electronics skill. A low level of this skill is typical for janitors, a high level of this skill is typical for engineers." + desc_unskilled = "You can move furniture, assemble or disassemble chairs and tables (sometimes they even stay assembled), bash your way through a window, open a crate, or pry open an unpowered airlock. You can recognize and use basic hand tools and inflatable barriers, though not very well." + desc_amateur = "You can dismantle or build a wall or window, build furniture, redecorate a room, and replace floor tiles and carpeting. You can safely use a welder without burning your eyes, and using hand tools is second nature to you." + desc_trained = "You know how to seal a breach, rebuild broken piping, and repair major damage. You know the basics of structural engineering." + desc_professional = "You are a construction worker or engineer. You could pretty much rebuild the installation from the ground up, given supplies, and you're efficient and skilled at repairing damage." + +/datum/skill/engineering/electrical + ID = "electrical" + name = "Electrical Engineering" + desc = "This skill describes your knowledge of electronics and the underlying physics. A low level of this skill implies you know how to lay out wiring and configure powernets, a high level of this skill is required for working complex electronic devices such as circuits or bots." + desc_unskilled = "You know that electrical wires are dangerous and getting shocked is bad; you can see and report electrical malfunctions such as broken wires or malfunctioning APCs. You can change a light bulb, and you know how to replace a battery or charge up the equipment you normally use." + desc_amateur = "You can do basic wiring; you can lay cable for solars or the engine. You can repair broken wiring and build simple electrical equipment like light fixtures or APCs. You know the basics of circuits and understand how to protect yourself from electrical shock. You can probably hack a vending machine." + desc_trained = "You can repair and build electrical equipment and do so on a regular basis. You can troubleshoot an electrical system and monitor the installation power grid. You can probably hack an airlock." + desc_professional = "You are an electrical engineer or the equivalent. You can design, upgrade, and modify electrical equipment and you are good at maximizing the efficiency of your power network. You can hack anything on the installation you can deal with power outages and electrical problems easily and efficiently." + cost_multiplier = 1.1 + +/datum/skill/engineering/atmos + ID = "atmos" + name = "Atmospherics" + desc = "Describes your knowledge of piping, air distribution and gas dynamics." + desc_unskilled = "You know that the air monitors flash orange when the air is bad and red when it's deadly. You know that a flashing fire door means danger on the other side. You know that some gases are poisonous, that pressure has to be kept in a safe range, and that most creatures need oxygen to live. You can use a fire extinguisher or deploy an inflatable barrier." + desc_amateur = "You know how to read an air monitor, how to use an air pump, how to analyze the atmosphere in a space, and how to help seal a breach. You can lay piping and work with gas tanks and canisters. If you work with the engine, you can set up the cooling system. You can use a fire extinguisher easily and place inflatable barriers so that they allow convenient access and airtight breach containment." + desc_trained = "You can run the Atmospherics system. You know how to monitor the air quality across the installation detect problems, and fix them. You're trained in dealing with fires, breaches, and gas leaks, and may have exosuit or fire gear training." + desc_professional = "You are an atmospherics specialist. You monitor, modify, and optimize the installation atmospherics system, and you can quickly and easily deal with emergencies. You can modify atmospherics systems to do pretty much whatever you want them to. You can easily handle a fire or breach, and are proficient at securing an area and rescuing civilians, but you're equally likely to have simply prevented it from happening in the first place." + cost_multiplier = 1.2 + +/datum/skill/engineering/engines + ID = "engines" + name = "Engines" + desc = "Describes your knowledge of the various engine types common on space stations, such as the singularity, supermatter or RUST engine." + desc_unskilled = "You know that \"delamination\" is a bad thing and that you should stay away from the singularity. You know the engine provides power, but you're unclear on the specifics. If you were to try to set up the engine, you would need someone to talk you through every detail--and even then, you'd probably make deadly mistakes." + desc_amateur = "You know the basic theoretical principles of engine operation. You can try to set up the engine by yourself, but you are likely to need some assistance and supervision, otherwise you are likely to make mistakes." + desc_trained = "You can set up the engine, and you probably won't botch it up too badly. You know how to protect yourself from radiation in the engine room. You can read the engine monitors and keep the engine going. You're familiar with engine types other than the one you work with. An engine malfunction may stump you, but you can probably work out how to fix it... let's just hope you do so quickly enough to prevent serious damage." + desc_professional = "Your engine is your baby and you know every minute detail of its workings. You can optimize the engine and you probably have your own favorite custom setup. You could build an engine from the ground up. When things go wrong, you know exactly what has happened and how to fix the problem. You can safely handle singularities and supermatter." + +/datum/skill/engineering/mech + ID = "mech" + name = "Heavy Machinery Operation" + desc = "Describes your experience and understanding of operating heavy machinery, which includes mechs and other large exosuits. Used in piloting mechs." + desc_unskilled = "You know what a mech is, and if you see one you can recognize which type it is. If your department uses exosuits, you know roughly what their capabilities are. If you were to get into one, you'd have about fifty-fifty odds of getting it moving in the direction you wanted it to go." + desc_amateur = "You can drive an exosuit safely, but you specialize in only one type of mech that your department regularly uses. You're not an expert and you fumble the controls sometimes, but you're going where you want to go and you're pretty sure you know what those buttons do. If you're a miner, you can set up a mining drill safely; if you have the electrical skills, you probably know how to operate a shield generator and set up a laser emitter." + desc_trained = "You are very comfortable using the type of exosuit you're most familiar with. You may spend entire shifts piloting one, and you're familiar with its functions. You can do basic maintenance. You can use most types of exosuits, unless they're very exotic or specialized. If you're an electrician or engineer, you can set up a shield generator solo. Miners at this level can place and use mining drills with high efficiency." + desc_professional = "You can use any type of mech comfortably and automatically. To you, a mech is more like a second skin than a vehicle. You can maintain, repair, and probably build exosuits. You can maintain, repair, and modify drills and shield generators." + +/datum/skill/engineering/pilot + ID = "pilot" + name = "Piloting" + desc = "Describes your experience and understanding of piloting spacecraft, from small and short-range pods to corvette sized vessels." + desc_unskilled = "You know what a spacecraft is, and you might have an abstract understanding of the differences between various ships. If your department is involved in the use of spacecraft, you know roughly what their capabilities are. You might be able to fly a spacecraft in a videogame. If you were to take the Helm of a smaller vessel, you might be able to move it with proper guidance." + desc_amateur = "You can pilot a small, short-range craft safely, but larger ships are out of your area of expertise. You are by no means an expert, and probably don't have much training. Skills of this level are typical for deck crew." + desc_trained = "You are a trained pilot, and can safely operate anything from a small craft to a corvette. You can spend extended periods of time piloting a spacecraft, and you're versed in the abilities of different ships, and what makes them function. You can do basic maintenance on smaller vessels, and perform most basic maneuvers. You can use armed spacecraft. You can make basic calculations relating to piloting. Skills of this level are typical for newer pilots. You have probably recieved formal piloting training." + desc_professional = "You are an experienced pilot, and can safely take the helm of many types of craft. You could probably live in a spacecraft, and you're very well versed in essentially everything related to space-faring vessels. Not only can you fly a ship, but you can perform difficult maneuvers, and make most calculations related to piloting a spacecraft. You can maintain a ship. Skills of this level are typical for very experienced pilots. You have recieved formal piloting training." + cost_multiplier = 1.2 + +// Category: Research + +/datum/skill/research/devices + ID = "devices" + name = "Complex Devices" + desc = "Describes the ability to assemble complex devices, such as computers, circuits, printers, robots or gas tank assemblies (bombs). Note that if a device requires electronics or programming, those skills are also required in addition to this skill." + desc_unskilled = "You know how to use the technology that was present in whatever society you grew up in. You know how to tell when something is malfunctioning, but you have to call tech support to get it fixed." + desc_amateur = "You use and repair high-tech equipment in the course of your daily work. You can fix simple problems, and you know how to use a circuit printer or autolathe. You can build simple robots such as cleanbots and medibots. If you have the relevant medical or electronic knowledge, you can repair a prosthesis or artificial organ; if not, these devices are beyond you." + desc_trained = "You can build or repair an exosuit or cyborg chassis, use a protolathe and destructive analyzer, and build prosthetic limbs. You can safely transfer an MMI or posibrain into a cyborg chassis." + desc_professional = "You are an inventor, researcher, or anomalist. You can design, build, and modify equipment that most people don't even know exists. You are at home in the lab and the workshop and you've never met a gadget you couldn't take apart, put back together, and replicate." + +/datum/skill/research/computer + ID = "computer" + name = "Information Technology" + desc = "Describes your understanding of computers, software and communication. Not a requirement for using computers, but definitely helps. Used in telecommunications and programming of computers and AIs." + desc_unskilled = "You know how to use the computers and communication devices that you grew up with. You can use a computer console, a handheld or wall-mounted radio, and your headset, as well as your PDA. You know what an AI is, but you may see them as either \"people made of silicon\" or \"only machines\"; you know they have to obey their laws, but you don't know much about how or why they work." + desc_amateur = "You know the basics of programming, but you're not very good at it and couldn't do it professionally. You have a pretty good idea of what makes AIs tick. You understand how information is stored in a computer, and you can fix simple computer problems. You're computer-literate, but you still make mistakes. If you tried to subvert the AI, you might make mistakes in wording your new laws." + desc_trained = "At this level, you're probably working with computers on a daily basis. You understand and can repair the telecommunications network. Your understanding of AI programming and psychology lets you fix problems with the AIs or cyborgs--or create problems, if you so desire. You can program computers and AIs and change their laws effectively." + desc_professional = "People are probably starting to wonder whether you might be a computer yourself. Computer code is your first language; you relate to AIs as easily as (probably more easily than) organics. You could build a telecommunications network from the ground up." + +/datum/skill/research/science + ID = "science" + name = "Science" + desc = "Your experience and knowledge with scientific methods and processes." + desc_unskilled = "You know what science is and probably have a vague idea of the scientific method from your high school science classes." + desc_amateur = "You keep up with scientific discoveries. You know a little about most fields of research. You've learned basic laboratory skills. You may read about science as a hobby; or you may be working in a field related to science and have learned about science that way. You could design a simple experiment." + desc_trained = "You are a scientist, perhaps a graduate student or post-graduate researcher. You can design an experiment, analyze your results, publish your data, and integrate what you've learned with the research of other scientists. Your laboratory skills are reliable, and you know how to find information you need when you research a new scientific topic." + desc_professional = "You are a professional researcher, and you have made multiple new discoveries in your field. Your experiments are well-designed. You are known as an authority in your specialty and your papers often appear in prestigious journals. You may be coordinating the research efforts of a team of scientists." + +// Category: Medical + +/datum/skill/medical/medical + ID = "medical" + name = "Medicine" + desc = "Covers an understanding of the human body and medicine. At a low level, this skill gives a basic understanding of applying common types of medicine, and a rough understanding of medical devices like the health analyzer. At a high level, this skill grants exact knowledge of all the medicine available on the installation, as well as the ability to use complex medical devices like the body scanner or mass spectrometer." + desc_unskilled = "You know basic first aid, such as how to apply a bandage or ointment to an injury. You can use an autoinjector designed for civilian use, probably by reading the directions printed on it. You can tell when someone is badly hurt and needs a doctor; you can see whether someone has a badly broken bone, is having trouble breathing, or is unconscious. You may not be able to tell the difference between unconscious and dead." + desc_amateur = "You've taken a first-aid training, nursing, or EMT course. You can stop bleeding, do CPR, apply a splint, take someone's pulse, apply trauma and burn treatments, and read a handheld health scanner. You probably know that Dylovene helps poisoning and Dexalin helps people with breathing problems; you can use a syringe or start an IV. You've been briefed on the symptoms of common emergencies like a punctured lung, appendicitis, alcohol poisoning, or broken bones, and though you can't treat them, you know that they need a doctor's attention. You can recognize most emergencies as emergencies and safely stabilize and transport a patient." + desc_trained = "You are an experienced EMT or experienced nurse, a medical resident, or a doctor. You know how to treat most illnesses and injuries, though exotic illnesses and unusual injuries may still stump you. You have probably begun to specialize in some sub-field of medicine. In emergencies, you can think fast enough to keep your patients alive, and even when you can't treat a patient, you know how to find someone who can. You probably have some skill in genetics, virology, and surgery, if only to the extent of being able to create an antibody, do a cloning scan, or assist a surgeon in the operating room. You can use a full-body scanner, and you know something's off about a patient with an alien parasite or cortical borer." + desc_professional = "You are an experienced doctor. You've seen almost everything there is to see when it comes to injuries and illness and even when it comes to something you haven't seen, you can apply your wide knowledge base to put together a treatment. In a pinch, you can do just about any medicine-related task, but your specialty, whatever it may be, is where you really shine." + +/datum/skill/medical/anatomy + ID = "anatomy" + name = "Anatomy" + desc = "Gives you a detailed insight of the human body. A high skill in this is required to perform surgery. This skill may also help in examining alien biology." + desc_unskilled = "You know what organs, bones, and such are, and you know roughly where they are. You know that someone who's badly hurt or sick may need surgery." + desc_amateur = "You've taken an anatomy class and you've spent at least some time poking around inside actual people. You know where everything is, more or less. You could assist in surgery, if you have the required medical skills. If you have the forensics knowledge, you could perform an autopsy. If you really had to, you could probably perform basic surgery such as an appendectomy, but you're not yet a qualified surgeon and you really shouldn't--not unless it's an emergency. If you're a xenobiologist, you know how to take out slime cores." + desc_trained = "You're a surgical resident, or an experienced medical doctor. You can put together broken bones, fix a damaged lung, patch up a liver, or remove an appendix without problems. But tricky surgeries, with an unstable patient or delicate manipulation of vital organs like the heart and brain, are at the edge of your ability, and you prefer to leave them to specialized surgeons. You can recognize when someone's anatomy is noticeably unusual. You're trained in working with several species, but you're probably better at surgery on your own species." + desc_professional = "You are an experienced surgeon. You can handle anything that gets rolled, pushed, or dragged into the OR, and you can keep a patient alive and stable even if there's no one to assist you. You can handle severe trauma cases or multiple organ failure, repair brain damage, and perform heart surgery. By now, you've probably specialized in one field, where you may have made new contributions to surgical technique. You can detect even small variations in the anatomy of a patient--even a changeling probably wouldn't slip by your notice, provided you could get one on the operating table." + cost_multiplier = 0.8 + +/datum/skill/medical/virology + ID = "virology" + name = "Virology" + desc = "This skill implies an understanding of microorganisms and their effects on humans." + desc_unskilled = "You know that diseases are contagious; you've probably heard you should wash your hands to stop their spread. You know that if you're sick, you can go to Medical and get treatment." + desc_amateur = "You know how viruses work, and you can use the machinery in the virology lab to analyze a virus or create an antibody. You know the principles of quarantine and you know how to keep a virus from spreading. You know that spaceacillin will help the body fight off a virus. However, you're not specialized in virology, and you probably don't have a whole lot of experience in dealing with viruses. If you are a medical doctor, you know how to treat symptoms and keep sick patients stable." + desc_trained = "You know how to analyze, modify, and cure viruses, and could probably do so even without most of the equipment in the virology lab. You know how to trigger mutations in a virus and how to isolate genes. If you really wanted to, you could create a deadly virus, provided you got lucky with the mutations." + desc_professional = "You are a specialized virologist - either a medical doctor or a scientific researcher. You may be well-known in the field, having published in prestigious journals; or you may be a mad scientist working away in secret. You know how to use a virus as a tool or a weapon. You can cure any epidemic and if you wanted to, you could start one so deadly and contagious that your targets wouldn't know what hit them." + +/datum/skill/medical/chemistry + ID = "chemistry" + name = "Chemistry" + desc = "Experience with mixing chemicals, and an understanding of what the effect will be. This doesn't cover an understanding of the effect of chemicals on the human body, as such the medical skill is also required for medical chemists." + desc_unskilled = "You know that chemists work with chemicals; you know that they can make medicine or poison or useful chemicals. You probably know what an element is and have a vague idea of what a chemical reaction is from some chemistry class in your high school days." + desc_amateur = "You can make basic chemicals or medication--things like space cleaner or anti-toxin. You have some training in safety and you won't blow up the lab... probably." + desc_trained = "You work as a chemist, or else you are a doctor with training in chemistry. If you are a research chemist, you can create most useful chemicals; if you are a pharmacist, you can make most medications. At this stage, you're working mostly by-the-book. You can weaponize your chemicals by making grenades, smoke bombs, and similar devices." + desc_professional = "You specialized in chemistry or pharmaceuticals; you are either a medical researcher or professional chemist. You can create custom mixes and make even the trickiest of medications easily. You understand how your pharmaceuticals interact with the bodies of your patients. You are probably the originator of at least one new chemical innovation." + cost_multiplier = 1.2 \ No newline at end of file diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm new file mode 100644 index 00000000..8fe0b792 --- /dev/null +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -0,0 +1,933 @@ +/* + + Hello and welcome to sprite_accessories: For sprite accessories, such as hair, + facial hair, and possibly tattoos and stuff somewhere along the line. This file is + intended to be friendly for people with little to no actual coding experience. + The process of adding in new hairstyles has been made pain-free and easy to do. + Enjoy! - Doohl + + + Notice: This all gets automatically compiled in a list in dna2.dm, so you do not + have to define any UI values for sprite accessories manually for hair and facial + hair. Just add in new hair types and the game will naturally adapt. + + !!WARNING!!: changing existing hair information can be VERY hazardous to savefiles, + to the point where you may completely corrupt a server's savefiles. Please refrain + from doing this unless you absolutely know what you are doing, and have defined a + conversion in savefile.dm +*/ + +/datum/sprite_accessory + + var/icon // the icon file the accessory is located in + var/icon_state // the icon_state of the accessory + var/preview_state // a custom preview state for whatever reason + + var/name // the preview name of the accessory + + // Determines if the accessory will be skipped or included in random hair generations + var/gender = NEUTER + + // Restrict some styles to specific species + var/list/species_allowed = list(SPECIES_HUMAN) + + // Whether or not the accessory can be affected by colouration + var/do_colouration = 1 + + var/blend = ICON_ADD + + +/* +//////////////////////////// +/ =--------------------= / +/ == Hair Definitions == / +/ =--------------------= / +//////////////////////////// +*/ + +/datum/sprite_accessory/hair + + icon = 'icons/mob/Human_face.dmi' // default icon for all hairs + var/flags + +/datum/sprite_accessory/hair/bald + name = "Bald" + icon_state = "bald" + gender = MALE + species_allowed = list(SPECIES_HUMAN,SPECIES_UNATHI) + flags = VERY_SHORT + +/datum/sprite_accessory/hair/short + name = "Short Hair" // try to capatilize the names please~ + icon_state = "hair_a" // you do not need to define _s or _l sub-states, game automatically does this for you + flags = VERY_SHORT + +/datum/sprite_accessory/hair/twintail + name = "Twintail" + icon_state = "hair_twintail" + +/datum/sprite_accessory/hair/short2 + name = "Short Hair 2" + icon_state = "hair_shorthair3" + +/datum/sprite_accessory/hair/cut + name = "Cut Hair" + icon_state = "hair_c" + flags = VERY_SHORT + +/datum/sprite_accessory/hair/flair + name = "Flaired Hair" + icon_state = "hair_flair" + +/datum/sprite_accessory/hair/long + name = "Shoulder-length Hair" + icon_state = "hair_b" + +/datum/sprite_accessory/hair/longer + name = "Long Hair" + icon_state = "hair_vlong" + +/datum/sprite_accessory/hair/longest + name = "Very Long Hair" + icon_state = "hair_longest" + +/datum/sprite_accessory/hair/longfringe + name = "Long Fringe" + icon_state = "hair_longfringe" + +/datum/sprite_accessory/hair/longestalt + name = "Longer Fringe" + icon_state = "hair_vlongfringe" + +/datum/sprite_accessory/hair/halfbang + name = "Half-banged Hair" + icon_state = "hair_halfbang" + +/datum/sprite_accessory/hair/halfbangalt + name = "Half-banged Hair Alt" + icon_state = "hair_halfbang_alt" + +/datum/sprite_accessory/hair/ponytail1 + name = "Ponytail 1" + icon_state = "hair_ponytail" + +/datum/sprite_accessory/hair/ponytail2 + name = "Ponytail 2" + icon_state = "hair_pa" + gender = FEMALE + +/datum/sprite_accessory/hair/ponytail3 + name = "Ponytail 3" + icon_state = "hair_ponytail3" + +/datum/sprite_accessory/hair/ponytail4 + name = "Ponytail 4" + icon_state = "hair_ponytail4" + gender = FEMALE + +/datum/sprite_accessory/hair/ponytail5 + name = "Ponytail 5" + icon_state = "hair_ponytail5" + gender = FEMALE + +/datum/sprite_accessory/hair/ponytail6 + name = "Ponytail 6" + icon_state = "hair_ponytail6" + gender = FEMALE + +/datum/sprite_accessory/hair/sideponytail + name = "Side Ponytail" + icon_state = "hair_stail" + gender = FEMALE + +/datum/sprite_accessory/hair/parted + name = "Parted" + icon_state = "hair_parted" + +/datum/sprite_accessory/hair/pompadour + name = "Pompadour" + icon_state = "hair_pompadour" + gender = MALE + +/datum/sprite_accessory/hair/sleeze + name = "Sleeze" + icon_state = "hair_sleeze" + flags = VERY_SHORT + +/datum/sprite_accessory/hair/quiff + name = "Quiff" + icon_state = "hair_quiff" + gender = MALE + +/datum/sprite_accessory/hair/bedhead + name = "Bedhead" + icon_state = "hair_bedhead" + +/datum/sprite_accessory/hair/bedhead2 + name = "Bedhead 2" + icon_state = "hair_bedheadv2" + +/datum/sprite_accessory/hair/bedhead3 + name = "Bedhead 3" + icon_state = "hair_bedheadv3" + +/datum/sprite_accessory/hair/beehive + name = "Beehive" + icon_state = "hair_beehive" + gender = FEMALE + +/datum/sprite_accessory/hair/beehive2 + name = "Beehive 2" + icon_state = "hair_beehive2" + gender = FEMALE + +/datum/sprite_accessory/hair/bobcurl + name = "Bobcurl" + icon_state = "hair_bobcurl" + gender = FEMALE + species_allowed = list(SPECIES_HUMAN,SPECIES_UNATHI) + +/datum/sprite_accessory/hair/bob + name = "Bob" + icon_state = "hair_bobcut" + gender = FEMALE + species_allowed = list(SPECIES_HUMAN,SPECIES_UNATHI) + +/datum/sprite_accessory/hair/bobcutalt + name = "Chin Length Bob" + icon_state = "hair_bobcutalt" + gender = FEMALE + species_allowed = list(SPECIES_HUMAN,SPECIES_UNATHI) + +/datum/sprite_accessory/hair/bowl + name = "Bowl" + icon_state = "hair_bowlcut" + gender = MALE + +/datum/sprite_accessory/hair/buzz + name = "Buzzcut" + icon_state = "hair_buzzcut" + gender = MALE + species_allowed = list(SPECIES_HUMAN,SPECIES_UNATHI) + flags = VERY_SHORT + +/datum/sprite_accessory/hair/crew + name = "Crewcut" + icon_state = "hair_crewcut" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/combover + name = "Combover" + icon_state = "hair_combover" + gender = MALE + +/datum/sprite_accessory/hair/father + name = "Father" + icon_state = "hair_father" + gender = MALE + +/datum/sprite_accessory/hair/reversemohawk + name = "Reverse Mohawk" + icon_state = "hair_reversemohawk" + gender = MALE + +/datum/sprite_accessory/hair/devillock + name = "Devil Lock" + icon_state = "hair_devilock" + +/datum/sprite_accessory/hair/dreadlocks + name = "Dreadlocks" + icon_state = "hair_dreads" + +/datum/sprite_accessory/hair/curls + name = "Curls" + icon_state = "hair_curls" + +/datum/sprite_accessory/hair/afro + name = "Afro" + icon_state = "hair_afro" + +/datum/sprite_accessory/hair/afro2 + name = "Afro 2" + icon_state = "hair_afro2" + +/datum/sprite_accessory/hair/afro_large + name = "Big Afro" + icon_state = "hair_bigafro" + gender = MALE + +/datum/sprite_accessory/hair/rows + name = "Rows" + icon_state = "hair_rows1" + flags = VERY_SHORT + +/datum/sprite_accessory/hair/rows2 + name = "Rows 2" + icon_state = "hair_rows2" + flags = VERY_SHORT + +/datum/sprite_accessory/hair/sargeant + name = "Flat Top" + icon_state = "hair_sargeant" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/emo + name = "Emo" + icon_state = "hair_emo" + +/datum/sprite_accessory/hair/emo2 + name = "Emo Alt" + icon_state = "hair_emo2" + +/datum/sprite_accessory/hair/longemo + name = "Long Emo" + icon_state = "hair_emolong" + gender = FEMALE + +/datum/sprite_accessory/hair/shortovereye + name = "Overeye Short" + icon_state = "hair_shortovereye" + +/datum/sprite_accessory/hair/longovereye + name = "Overeye Long" + icon_state = "hair_longovereye" + +/datum/sprite_accessory/hair/flow + name = "Flow Hair" + icon_state = "hair_f" + +/datum/sprite_accessory/hair/feather + name = "Feather" + icon_state = "hair_feather" + +/datum/sprite_accessory/hair/hitop + name = "Hitop" + icon_state = "hair_hitop" + gender = MALE + +/datum/sprite_accessory/hair/mohawk + name = "Mohawk" + icon_state = "hair_d" + species_allowed = list(SPECIES_HUMAN,SPECIES_UNATHI) + +/datum/sprite_accessory/hair/jensen + name = "Adam Jensen Hair" + icon_state = "hair_jensen" + gender = MALE + +/datum/sprite_accessory/hair/gelled + name = "Gelled Back" + icon_state = "hair_gelled" + gender = FEMALE + +/datum/sprite_accessory/hair/gentle + name = "Gentle" + icon_state = "hair_gentle" + gender = FEMALE + +/datum/sprite_accessory/hair/spiky + name = "Spiky" + icon_state = "hair_spikey" + species_allowed = list(SPECIES_HUMAN,SPECIES_UNATHI) + +/datum/sprite_accessory/hair/kusangi + name = "Kusanagi Hair" + icon_state = "hair_kusanagi" + +/datum/sprite_accessory/hair/kagami + name = "Pigtails" + icon_state = "hair_kagami" + gender = FEMALE + +/datum/sprite_accessory/hair/himecut + name = "Hime Cut" + icon_state = "hair_himecut" + gender = FEMALE + +/datum/sprite_accessory/hair/shorthime + name = "Short Hime Cut" + icon_state = "hair_shorthime" + gender = FEMALE + +/datum/sprite_accessory/hair/grandebraid + name = "Grande Braid" + icon_state = "hair_grande" + gender = FEMALE + +/datum/sprite_accessory/hair/mbraid + name = "Medium Braid" + icon_state = "hair_shortbraid" + gender = FEMALE + +/datum/sprite_accessory/hair/braid2 + name = "Long Braid" + icon_state = "hair_hbraid" + gender = FEMALE + +/datum/sprite_accessory/hair/braid + name = "Floorlength Braid" + icon_state = "hair_braid" + gender = FEMALE + flags = HAIR_TRIPPABLE + +/datum/sprite_accessory/hair/odango + name = "Odango" + icon_state = "hair_odango" + gender = FEMALE + +/datum/sprite_accessory/hair/ombre + name = "Ombre" + icon_state = "hair_ombre" + gender = FEMALE + +/datum/sprite_accessory/hair/updo + name = "Updo" + icon_state = "hair_updo" + gender = FEMALE + +/datum/sprite_accessory/hair/skinhead + name = "Skinhead" + icon_state = "hair_skinhead" + flags = VERY_SHORT + +/datum/sprite_accessory/hair/balding + name = "Balding Hair" + icon_state = "hair_e" + gender = MALE // turnoff! + flags = VERY_SHORT + +/datum/sprite_accessory/hair/familyman + name = "The Family Man" + icon_state = "hair_thefamilyman" + gender = MALE + +/datum/sprite_accessory/hair/mahdrills + name = "Drillruru" + icon_state = "hair_drillruru" + gender = FEMALE + +/datum/sprite_accessory/hair/fringetail + name = "Fringetail" + icon_state = "hair_fringetail" + gender = FEMALE + +/datum/sprite_accessory/hair/dandypomp + name = "Dandy Pompadour" + icon_state = "hair_dandypompadour" + gender = MALE + +/datum/sprite_accessory/hair/poofy + name = "Poofy" + icon_state = "hair_poofy" + gender = FEMALE + +/datum/sprite_accessory/hair/crono + name = "Chrono" + icon_state = "hair_toriyama" + gender = MALE + +/datum/sprite_accessory/hair/vegeta + name = "Vegeta" + icon_state = "hair_toriyama2" + gender = MALE + +/datum/sprite_accessory/hair/cia + name = "CIA" + icon_state = "hair_cia" + gender = MALE + +/datum/sprite_accessory/hair/mulder + name = "Mulder" + icon_state = "hair_mulder" + gender = MALE + +/datum/sprite_accessory/hair/scully + name = "Scully" + icon_state = "hair_scully" + gender = FEMALE + +/datum/sprite_accessory/hair/nitori + name = "Nitori" + icon_state = "hair_nitori" + gender = FEMALE + +/datum/sprite_accessory/hair/joestar + name = "Joestar" + icon_state = "hair_joestar" + gender = MALE + +/datum/sprite_accessory/hair/volaju + name = "Volaju" + icon_state = "hair_volaju" + +/datum/sprite_accessory/hair/longeralt2 + name = "Long Hair Alt 2" + icon_state = "hair_longeralt2" + +/datum/sprite_accessory/hair/shortbangs + name = "Short Bangs" + icon_state = "hair_shortbangs" + +/datum/sprite_accessory/hair/shavedbun + name = "Shaved Bun" + icon_state = "hair_shavedbun" + +/datum/sprite_accessory/hair/halfshaved + name = "Half-Shaved" + icon_state = "hair_halfshaved" + +/datum/sprite_accessory/hair/halfshavedemo + name = "Half-Shaved Emo" + icon_state = "hair_halfshavedemo" + +/datum/sprite_accessory/hair/longsideemo + name = "Long Side Emo" + icon_state = "hair_longsideemo" + +/datum/sprite_accessory/hair/bun + name = "Low Bun" + icon_state = "hair_bun" + +/datum/sprite_accessory/hair/bun2 + name = "High Bun" + icon_state = "hair_bun2" + +/datum/sprite_accessory/hair/doublebun + name = "Double-Bun" + icon_state = "hair_doublebun" + +/datum/sprite_accessory/hair/lowfade + name = "Low Fade" + icon_state = "hair_lowfade" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/medfade + name = "Medium Fade" + icon_state = "hair_medfade" + +/datum/sprite_accessory/hair/highfade + name = "High Fade" + icon_state = "hair_highfade" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/baldfade + name = "Balding Fade" + icon_state = "hair_baldfade" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/nofade + name = "Regulation Cut" + icon_state = "hair_nofade" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/trimflat + name = "Trimmed Flat Top" + icon_state = "hair_trimflat" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/shaved + name = "Shaved" + icon_state = "hair_shaved" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/trimmed + name = "Trimmed" + icon_state = "hair_trimmed" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/tightbun + name = "Tight Bun" + icon_state = "hair_tightbun" + gender = FEMALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/coffeehouse + name = "Coffee House Cut" + icon_state = "hair_coffeehouse" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/undercut + name = "Undercut" + icon_state = "hair_undercut" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/partfade + name = "Parted Fade" + icon_state = "hair_shavedpart" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/hightight + name = "High and Tight" + icon_state = "hair_hightight" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/rowbun + name = "Row Bun" + icon_state = "hair_rowbun" + gender = FEMALE + +/datum/sprite_accessory/hair/rowdualbraid + name = "Row Dual Braid" + icon_state = "hair_rowdualtail" + gender = FEMALE + +/datum/sprite_accessory/hair/rowbraid + name = "Row Braid" + icon_state = "hair_rowbraid" + gender = FEMALE + +/datum/sprite_accessory/hair/regulationmohawk + name = "Regulation Mohawk" + icon_state = "hair_shavedmohawk" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/topknot + name = "Topknot" + icon_state = "hair_topknot" + gender = MALE + +/datum/sprite_accessory/hair/ronin + name = "Ronin" + icon_state = "hair_ronin" + gender = MALE + +/datum/sprite_accessory/hair/bowlcut2 + name = "Bowl2" + icon_state = "hair_bowlcut2" + gender = MALE + +/datum/sprite_accessory/hair/thinning + name = "Thinning" + icon_state = "hair_thinning" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/thinningfront + name = "Thinning Front" + icon_state = "hair_thinningfront" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/thinningback + name = "Thinning Back" + icon_state = "hair_thinningrear" + gender = MALE + flags = VERY_SHORT + +/datum/sprite_accessory/hair/manbun + name = "Manbun" + icon_state = "hair_manbun" + gender = MALE + +/datum/sprite_accessory/hair/leftsidecut + name = "Left Sidecut" + icon_state = "hair_leftside" + +/datum/sprite_accessory/hair/rightsidecut + name = "Right Sidecut" + icon_state = "hair_rightside" + +/datum/sprite_accessory/hair/slick + name = "Slick" + icon_state = "hair_slick" + +/datum/sprite_accessory/hair/messyhair + name = "Messy" + icon_state = "hair_messyhair" + +/datum/sprite_accessory/hair/averagejoe + name = "Average Joe" + icon_state = "hair_averagejoe" + +/datum/sprite_accessory/hair/sideswept + name = "Sideswept Hair" + icon_state = "hair_sideswept" + +/datum/sprite_accessory/hair/mohawkshaved + name = "Shaved Mohawk" + icon_state = "hair_mohawkshaved" + +/datum/sprite_accessory/hair/mohawkshaved2 + name = "Tight Shaved Mohawk" + icon_state = "hair_mohawkshaved2" + +/datum/sprite_accessory/hair/mohawkshavednaomi + name = "Naomi Mohawk" + icon_state = "hair_mohawkshavednaomi" + +/datum/sprite_accessory/hair/amazon + name = "Amazon" + icon_state = "hair_amazon" + +/datum/sprite_accessory/hair/straightlong + name = "Straight Long" + icon_state = "hair_straightlong" + +/*I'm sorry I made this hairstyle, +May God have mercy. +*/ + +/datum/sprite_accessory/hair/marysue + name = "Mary Sue" + icon_state = "hair_marysue" + +/datum/sprite_accessory/hair/messyhair2 + name = "Messy Hair 2" + icon_state = "hair_messyhair2" + +/datum/sprite_accessory/hair/buzzcut2 + name = "Buzzcut 2" + icon_state = "hair_buzzcut2" + +/* +/////////////////////////////////// +/ =---------------------------= / +/ == Facial Hair Definitions == / +/ =---------------------------= / +/////////////////////////////////// +*/ + +/datum/sprite_accessory/facial_hair + + icon = 'icons/mob/human_face.dmi' + gender = MALE // barf (unless you're a dorf, dorfs dig chix /w beards :P) + +/datum/sprite_accessory/facial_hair/shaved + name = "Shaved" + icon_state = "bald" + gender = NEUTER + species_allowed = list(SPECIES_HUMAN,SPECIES_UNATHI,SPECIES_TAJARA,SPECIES_SKRELL,SPECIES_VOX,SPECIES_IPC) + +/datum/sprite_accessory/facial_hair/broken_man + name = "Broken Man" + icon_state = "facial_brokenman" + +/datum/sprite_accessory/facial_hair/watson + name = "Watson Mustache" + icon_state = "facial_watson" + +/datum/sprite_accessory/facial_hair/hogan + name = "Hulk Hogan Mustache" + icon_state = "facial_hogan" //-Neek + +/datum/sprite_accessory/facial_hair/vandyke + name = "Van Dyke Mustache" + icon_state = "facial_vandyke" + +/datum/sprite_accessory/facial_hair/chaplin + name = "Square Mustache" + icon_state = "facial_chaplin" + +/datum/sprite_accessory/facial_hair/selleck + name = "Selleck Mustache" + icon_state = "facial_selleck" + +/datum/sprite_accessory/facial_hair/neckbeard + name = "Neckbeard" + icon_state = "facial_neckbeard" + +/datum/sprite_accessory/facial_hair/fullbeard + name = "Full Beard" + icon_state = "facial_fullbeard" + +/datum/sprite_accessory/facial_hair/longbeard + name = "Long Beard" + icon_state = "facial_longbeard" + +/datum/sprite_accessory/facial_hair/vlongbeard + name = "Very Long Beard" + icon_state = "facial_wise" + +/datum/sprite_accessory/facial_hair/elvis + name = "Elvis Sideburns" + icon_state = "facial_elvis" + species_allowed = list(SPECIES_HUMAN,SPECIES_UNATHI) + +/datum/sprite_accessory/facial_hair/abe + name = "Abraham Lincoln Beard" + icon_state = "facial_abe" + +/datum/sprite_accessory/facial_hair/chinstrap + name = "Chinstrap" + icon_state = "facial_chin" + +/datum/sprite_accessory/facial_hair/hip + name = "Hipster Beard" + icon_state = "facial_hip" + +/datum/sprite_accessory/facial_hair/gt + name = "Goatee" + icon_state = "facial_gt" + +/datum/sprite_accessory/facial_hair/jensen + name = "Adam Jensen Beard" + icon_state = "facial_jensen" + +/datum/sprite_accessory/facial_hair/volaju + name = "Volaju" + icon_state = "facial_volaju" + +/datum/sprite_accessory/facial_hair/dwarf + name = "Dwarf Beard" + icon_state = "facial_dwarf" + +/datum/sprite_accessory/facial_hair/threeOclock + name = "3 O'clock Shadow" + icon_state = "facial_3oclock" + +/datum/sprite_accessory/facial_hair/threeOclockstache + name = "3 O'clock Shadow and Moustache" + icon_state = "facial_3oclockmoustache" + +/datum/sprite_accessory/facial_hair/fiveOclock + name = "5 O'clock Shadow" + icon_state = "facial_5oclock" + +/datum/sprite_accessory/facial_hair/fiveOclockstache + name = "5 O'clock Shadow and Moustache" + icon_state = "facial_5oclockmoustache" + +/datum/sprite_accessory/facial_hair/sevenOclock + name = "7 O'clock Shadow" + icon_state = "facial_7oclock" + +/datum/sprite_accessory/facial_hair/sevenOclockstache + name = "7 O'clock Shadow and Moustache" + icon_state = "facial_7oclockmoustache" + +/datum/sprite_accessory/facial_hair/mutton + name = "Mutton Chops" + icon_state = "facial_mutton" + +/datum/sprite_accessory/facial_hair/muttonstache + name = "Mutton Chops and Moustache" + icon_state = "facial_muttonmus" + +/datum/sprite_accessory/facial_hair/walrus + name = "Walrus Moustache" + icon_state = "facial_walrus" + +/datum/sprite_accessory/facial_hair/croppedbeard + name = "Full Cropped Beard" + icon_state = "facial_croppedfullbeard" + +/datum/sprite_accessory/facial_hair/chinless + name = "Chinless Beard" + icon_state = "facial_chinlessbeard" + +/datum/sprite_accessory/facial_hair/braided + name = "Braided Beard" + icon_state = "facial_biker" + +/datum/sprite_accessory/facial_hair/seadog + name = "Sea Dog" + icon_state = "facial_seadog" + +/datum/sprite_accessory/facial_hair/lumberjack + name = "Lumberjack" + icon_state = "facial_lumberjack" + +/* +/////////////////////////////////// +/ =---------------------------= / +/ == Alien Style Definitions == / +/ =---------------------------= / +/////////////////////////////////// +*/ + + + +//skin styles - WIP +//going to have to re-integrate this with surgery +//let the icon_state hold an icon preview for now +/datum/sprite_accessory/skin + icon = 'icons/mob/human_races/r_human.dmi' + +/datum/sprite_accessory/skin/human + name = "Default human skin" + icon_state = "default" + species_allowed = list(SPECIES_HUMAN) + +/datum/sprite_accessory/skin/human_tatt01 + name = "Tatt01 human skin" + icon_state = "tatt1" + species_allowed = list(SPECIES_HUMAN) + +/* +//////////////////////////// +/ =--------------------= / +/ == Body Markings == / +/ =--------------------= / +//////////////////////////// +*/ +/datum/sprite_accessory/marking + icon = 'icons/mob/human_races/markings.dmi' + do_colouration = 1 //Almost all of them have it, COLOR_ADD + + var/layer_blend = ICON_OVERLAY + + //Empty list is unrestricted. Should only restrict the ones that make NO SENSE on other species, + //like Tajara inner-ear coloring overlay stuff. + species_allowed = list() + + var/body_parts = list() //A list of bodyparts this covers, in organ_tag defines + //Reminder: BP_L_FOOT,BP_R_FOOT,BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_L_HAND,BP_R_HAND,BP_CHEST,BP_GROIN,BP_HEAD + +/datum/sprite_accessory/marking/tat_heart + name = "Tattoo (Heart, Torso)" + icon_state = "tat_heart" + body_parts = list(BP_CHEST) + species_allowed = list(SPECIES_HUMAN) + +/datum/sprite_accessory/marking/chest_hair + name = "Body Hair" + icon_state = "bodyhair" + gender = MALE + body_parts = list(BP_CHEST,BP_GROIN) + +/datum/sprite_accessory/marking/tat_hive + name = "Tattoo (Hive, Back)" + icon_state = "tat_hive" + body_parts = list(BP_CHEST) + species_allowed = list(SPECIES_HUMAN) + +/datum/sprite_accessory/marking/tat_nightling + name = "Tattoo (Nightling, Back)" + icon_state = "tat_nightling" + body_parts = list(BP_CHEST) + species_allowed = list(SPECIES_HUMAN) + +/datum/sprite_accessory/marking/tat_campbell + name = "Tattoo (Campbell, R.Arm)" + icon_state = "tat_campbell" + body_parts = list(BP_R_ARM) + species_allowed = list(SPECIES_HUMAN) + +/datum/sprite_accessory/marking/tat_campbell/left + name = "Tattoo (Campbell, L.Arm)" + body_parts = list(BP_L_ARM) + species_allowed = list(SPECIES_HUMAN) + +/datum/sprite_accessory/marking/bands + name = "Color Bands" + icon_state = "bands" + body_parts = list(BP_L_FOOT,BP_R_FOOT,BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_L_HAND,BP_R_HAND,BP_CHEST,BP_GROIN) + +/datum/sprite_accessory/marking/bandsface + name = "Color Bands (Face)" + icon_state = "bandsface" + body_parts = list(BP_HEAD) diff --git a/code/modules/mob/observer/freelook/ai/cameranet.dm b/code/modules/mob/observer/freelook/ai/cameranet.dm new file mode 100644 index 00000000..bde34a77 --- /dev/null +++ b/code/modules/mob/observer/freelook/ai/cameranet.dm @@ -0,0 +1,41 @@ +// CAMERA NET +// +// The datum containing all the chunks. + +/datum/visualnet/camera + // The cameras on the map, no matter if they work or not. + var/list/cameras + chunk_type = /datum/chunk/camera + valid_source_types = list(/obj/machinery/camera, /mob/living/silicon/ai) + +/datum/visualnet/camera/New() + cameras = list() + ..() + +/datum/visualnet/camera/Destroy() + cameras.Cut() + . = ..() + +/datum/visualnet/camera/add_source(obj/machinery/camera/c) + if(istype(c)) + if(c in cameras) + return FALSE + . = ..(c, c.can_use()) + if(.) + ADD_SORTED(cameras, c, /proc/cmp_camera_ctag_asc) + else if(isAI(c)) + var/mob/living/silicon/AI = c + return ..(AI, AI.stat != DEAD) + else + ..() + +// Add a camera to a chunk. + +/datum/visualnet/camera/remove_source(obj/machinery/camera/c) + if(istype(c) && cameras.Remove(c)) + . = ..(c, c.can_use()) + if(isAI(c)) + var/mob/living/silicon/AI = c + return ..(AI, AI.stat != DEAD) + else + ..() diff --git a/code/modules/mob/observer/freelook/ai/chunk.dm b/code/modules/mob/observer/freelook/ai/chunk.dm new file mode 100644 index 00000000..b70737ce --- /dev/null +++ b/code/modules/mob/observer/freelook/ai/chunk.dm @@ -0,0 +1,23 @@ +// CAMERA CHUNK +// +// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed. +// Allows the Eye to stream these chunks and know what it can and cannot see. + +/datum/chunk/camera/acquire_visible_turfs(var/list/visible) + for(var/source in sources) + if(istype(source,/obj/machinery/camera)) + var/obj/machinery/camera/c = source + if(!c.can_use()) + continue + + for(var/turf/t in c.can_see()) + visible[t] = t + else if(isAI(source)) + var/mob/living/silicon/ai/AI = source + if(AI.stat == DEAD) + continue + for(var/turf/t in seen_turfs_in_range(AI, world.view)) + visible[t] = t + else + log_visualnet("Contained an unhandled source", source) + sources -= source diff --git a/code/modules/mob/observer/freelook/ai/eye.dm b/code/modules/mob/observer/freelook/ai/eye.dm new file mode 100644 index 00000000..0660afbd --- /dev/null +++ b/code/modules/mob/observer/freelook/ai/eye.dm @@ -0,0 +1,106 @@ +// AI EYE +// +// A mob that the AI controls to look around the station with. +// It streams chunks as it moves around, which will show it what the AI can and cannot see. + +/mob/observer/eye/cameranet + name = "Inactive Camera Eye" + name_sufix = "Camera Eye" + +/mob/observer/eye/cameranet/New() + ..() + visualnet = cameranet + +/mob/observer/eye/aiEye + name = "Inactive AI Eye" + name_sufix = "AI Eye" + icon_state = "AI-eye" + +/mob/observer/eye/aiEye/New() + ..() + visualnet = cameranet + +/mob/observer/eye/aiEye/setLoc(var/T, var/cancel_tracking = 1) + . = ..() + if(. && isAI(owner)) + var/mob/living/silicon/ai/ai = owner + if(cancel_tracking) + ai.ai_cancel_tracking() + + //Holopad + if(ai.holo && ai.hologram_follow) + ai.holo.move_hologram(ai) + return 1 + +/mob/observer/eye/aiEye/set_dir(new_dir) + . = ..() + if(. && isAI(owner)) + var/mob/living/silicon/ai/ai = owner + + //Holopad + if(ai.holo && ai.hologram_follow) + ai.holo.set_dir_hologram(new_dir, ai) + return 1 + +// AI MOVEMENT + +// The AI's "eye". Described on the top of the page. + +/mob/living/silicon/ai + var/obj/machinery/hologram/holopad/holo = null + +/mob/living/silicon/ai/proc/destroy_eyeobj(var/atom/new_eye) + if(!eyeobj) return + if(!new_eye) + new_eye = src + qdel(eyeobj) // No AI, no Eye + eyeobj = null + if(client) + client.eye = new_eye + +/mob/living/silicon/ai/proc/create_eyeobj(var/newloc) + if(eyeobj) destroy_eyeobj() + if(!newloc) newloc = get_turf(src) + eyeobj = new /mob/observer/eye/aiEye(newloc) + eyeobj.possess(src) + +// Intiliaze the eye by assigning it's "ai" variable to us. Then set it's loc to us. +/mob/living/silicon/ai/New() + ..() + create_eyeobj() + +/mob/living/silicon/ai/Destroy() + destroy_eyeobj() + . = ..() + +/atom/proc/move_camera_by_click() + if(istype(usr, /mob/living/silicon/ai)) + var/mob/living/silicon/ai/AI = usr + if(AI.eyeobj && AI.client.eye == AI.eyeobj) + AI.eyeobj.setLoc(src) + +// Return to the Core. +/mob/living/silicon/ai/proc/core() + set category = "Silicon Commands" + set name = "AI Core" + + view_core() + +/mob/living/silicon/ai/proc/view_core() + camera = null + unset_machine() + + if(!src.eyeobj) + return + + eyeobj.possess(src) + +/mob/living/silicon/ai/proc/toggle_acceleration() + set category = "Silicon Commands" + set name = "Toggle Camera Acceleration" + + if(!eyeobj) + return + + eyeobj.acceleration = !eyeobj.acceleration + to_chat(usr, "Camera acceleration has been toggled [eyeobj.acceleration ? "on" : "off"].") diff --git a/code/modules/mob/observer/freelook/ai/update_triggers.dm b/code/modules/mob/observer/freelook/ai/update_triggers.dm new file mode 100644 index 00000000..8e17457a --- /dev/null +++ b/code/modules/mob/observer/freelook/ai/update_triggers.dm @@ -0,0 +1,59 @@ +// CAMERA + +// An addition to deactivate which removes/adds the camera from the chunk list based on if it works or not. + +/obj/machinery/camera/deactivate(user as mob, var/choice = 1) + ..(user, choice) + invalidateCameraCache() + if(!can_use()) + set_light(0) + cameranet.update_visibility(src) + +/obj/machinery/camera/Initialize() + . = ..() + var/list/open_networks = difflist(network, restricted_camera_networks) + on_open_network = open_networks.len + if(on_open_network) + cameranet.add_source(src) + +/obj/machinery/camera/Destroy() + if(on_open_network) + cameranet.remove_source(src) + . = ..() + +/obj/machinery/camera/proc/update_coverage(var/network_change = 0) + if(network_change) + var/list/open_networks = difflist(network, restricted_camera_networks) + // Add or remove camera from the camera net as necessary + if(on_open_network && !open_networks.len) + on_open_network = FALSE + cameranet.remove_source(src) + else if(!on_open_network && open_networks.len) + on_open_network = TRUE + cameranet.add_source(src) + else + cameranet.update_visibility(src) + + invalidateCameraCache() + +// Mobs +/mob/living/silicon/ai/New() + ..() + cameranet.add_source(src) + +/mob/living/silicon/ai/Destroy() + cameranet.remove_source(src) + . = ..() + +/mob/living/silicon/ai/rejuvenate() + var/was_dead = stat == DEAD + ..() + if(was_dead && stat != DEAD) + // Arise! + cameranet.update_visibility(src, FALSE) + +/mob/living/silicon/ai/death(gibbed, deathmessage, show_dead_message) + . = ..(gibbed, deathmessage, show_dead_message) + if(.) + // If true, the mob went from living to dead (assuming everyone has been overriding as they should...) + cameranet.update_visibility(src, FALSE) diff --git a/code/modules/mob/observer/freelook/chunk.dm b/code/modules/mob/observer/freelook/chunk.dm new file mode 100644 index 00000000..6aafd6ff --- /dev/null +++ b/code/modules/mob/observer/freelook/chunk.dm @@ -0,0 +1,180 @@ +#define UPDATE_BUFFER 25 // 2.5 seconds + +// CHUNK +// +// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed. +// Allows the Eye to stream these chunks and know what it can and cannot see. + +/datum/obfuscation + var/icon = 'icons/effects/cameravis.dmi' + var/icon_state = "black" + var/list/obfuscation_images = list() + var/static/icon/obfuscation_underlay + // There is an exploit were clients can memory-edit their local version of the static images, allowing them to see everything. This is a minor attempt to make that more difficult. + +/datum/obfuscation/Destroy() + obfuscation_images.Cut() + . = ..() + +/datum/obfuscation/proc/has_obfuscation(var/turf/T) + return !isnull(obfuscation_images[T]) + +/datum/obfuscation/proc/get_obfuscation(var/turf/T) + var/image/obfuscation = obfuscation_images[T] + if(!obfuscation) + obfuscation = image(icon, T, icon_state) + obfuscation.plane = OBSCURITY_PLANE + if(!obfuscation_underlay) + // Creating a new icon of a fairly common icon state, adding some random color to prevent address searching, and hoping being static kills memory locality + var/turf/floor = /turf/simulated/floor/tiled + obfuscation_underlay = icon(initial(floor.icon), initial(floor.icon_state)) + obfuscation_underlay.Blend(rgb(rand(0,255),rand(0,255),rand(0,255))) + obfuscation.underlays += obfuscation_underlay + obfuscation_images[T] = obfuscation + return obfuscation + +/datum/chunk + var/datum/visualnet/visualnet + var/list/obscuredTurfs = list() + var/list/visibleTurfs = list() + var/list/obscured = list() + var/list/turfs = list() + var/list/seenby = list() + var/list/sources = list() + var/dirty = FALSE + var/updating = FALSE + var/x = 0 + var/y = 0 + var/z = 0 + var/datum/obfuscation/obfuscation = new() + +// Create a new chunk, since the chunks are made as they are needed. +/datum/chunk/New(var/datum/visualnet/visualnet, x, y, z) + ..() + src.visualnet = visualnet + // 0xf = 15 + x &= ~0xf + y &= ~0xf + + src.x = x + src.y = y + src.z = z + + for(var/turf/t in range(10, locate(x + 8, y + 8, z))) + if(t.x >= x && t.y >= y && t.x < x + 16 && t.y < y + 16) + turfs[t] = t + + add_sources(visualnet.sources) + acquire_visible_turfs(visibleTurfs) + + // Removes turf that isn't in turfs. + visibleTurfs &= turfs + obscuredTurfs = turfs - visibleTurfs + + for(var/turf in obscuredTurfs) + var/turf/t = turf + obscured += obfuscation.get_obfuscation(t) + +/datum/chunk/Destroy() + visualnet = null + . = ..() + +/datum/chunk/proc/add_sources(var/list/sources) + var/turf/center = locate(x + 8, y + 8, z) + for(var/entry in sources) + var/atom/A = entry + if(get_dist(get_turf(A), center) > 16) + continue + add_source(A) + +/datum/chunk/proc/add_source(var/atom/source) + if(source in sources) + return FALSE + sources += source + visibility_changed() + return TRUE + +/datum/chunk/proc/remove_source(var/atom/source) + if(sources.Remove(source)) + visibility_changed() + return TRUE + return FALSE + +// The visual net is responsible for adding/removing eyes. +/datum/chunk/proc/add_eye(mob/observer/eye/eye) + seenby += eye + eye.visibleChunks += src + if(eye.owner && eye.owner.client) + eye.owner.client.images += obscured + +/datum/chunk/proc/remove_eye(mob/observer/eye/eye) + seenby -= eye + eye.visibleChunks -= src + if(eye.owner && eye.owner.client) + eye.owner.client.images -= obscured + +// Updates the chunk, makes sure that it doesn't update too much. If the chunk isn't being watched it will +// instead be flagged to update the next time an AI Eye moves near it. + +/datum/chunk/proc/visibility_changed(var/update_now = FALSE) + if(update_now) + update() + return + + if(updating) + return + + if(seenby.len) + updating = TRUE + spawn(UPDATE_BUFFER) // Batch large changes, such as many doors opening or closing at once + if(updating) // Check if we're still updating, a forced update may have occured. + update() + else + dirty = TRUE // If this chunk is seen by noone, simply mark it as dirty and do nothing + +// The actual updating. + +/datum/chunk/proc/update() + var/list/newVisibleTurfs = new() + acquire_visible_turfs(newVisibleTurfs) + + // Removes turf that isn't in turfs. + newVisibleTurfs &= turfs + + var/list/visAdded = newVisibleTurfs - visibleTurfs + var/list/visRemoved = visibleTurfs - newVisibleTurfs + + visibleTurfs = newVisibleTurfs + obscuredTurfs = turfs - newVisibleTurfs + + for(var/turf in visAdded) + var/turf/t = turf + if(obfuscation.has_obfuscation(t)) + var/image/obfuscation_image = obfuscation.get_obfuscation(t) + obscured -= obfuscation_image + for(var/eye in seenby) + var/mob/observer/eye/m = eye + if(m && m.owner && m.owner.client) + m.owner.client.images -= obfuscation_image + + for(var/turf in visRemoved) + var/turf/t = turf + if(obscuredTurfs[t]) + var/image/obfuscation_image = obfuscation.get_obfuscation(t) + obscured += obfuscation_image + for(var/eye in seenby) + var/mob/observer/eye/m = eye + if(m && m.owner && m.owner.client) + m.owner.client.images += obfuscation_image + + dirty = FALSE + updating = FALSE + +/datum/chunk/proc/acquire_visible_turfs(var/list/visible) + return + +/proc/seen_turfs_in_range(var/source, var/range) + var/turf/pos = get_turf(source) + return hear(range, pos) + +#undef UPDATE_BUFFER diff --git a/code/modules/mob/observer/freelook/eye.dm b/code/modules/mob/observer/freelook/eye.dm new file mode 100644 index 00000000..20a02a5c --- /dev/null +++ b/code/modules/mob/observer/freelook/eye.dm @@ -0,0 +1,131 @@ +// EYE +// +// A mob that another mob controls to look around the station with. +// It streams chunks as it moves around, which will show it what the controller can and cannot see. + +/mob/observer/eye + name = "Eye" + var/name_sufix = "Eye" + icon = 'icons/mob/eye.dmi' + icon_state = "default-eye" + + var/sprint = 10 + var/cooldown = 0 + var/acceleration = 1 + var/owner_follows_eye = 0 + + see_in_dark = 7 + invisibility = INVISIBILITY_EYE + + ghost_image_flag = GHOST_IMAGE_ALL + var/mob/owner = null + var/list/visibleChunks = list() + + var/datum/visualnet/visualnet + +/mob/observer/eye/Destroy() + release(owner) + owner = null + visualnet = null + . = ..() + +/mob/observer/eye/Move(n, direct) + if(owner == src) + return EyeMove(n, direct) + return 0 + +/mob/observer/eye/facedir(var/ndir) + if(!canface()) + return 0 + set_dir(ndir) + return 1 + +/mob/observer/eye/examinate() + set popup_menu = 0 + set src = usr.contents + return 0 + +/mob/observer/eye/pointed() + set popup_menu = 0 + set src = usr.contents + return 0 + +/mob/observer/eye/examine(mob/user) + return + +/mob/observer/eye/proc/possess(var/mob/user) + if(owner && owner != user) + return + if(owner && owner.eyeobj != src) + return + owner = user + owner.eyeobj = src + SetName("[owner.name] ([name_sufix])") // Update its name + if(owner.client) + owner.client.eye = src + setLoc(owner) + visualnet.update_eye_chunks(src, TRUE) + +/mob/observer/eye/proc/release(var/mob/user) + if(owner != user || !user) + return + if(owner.eyeobj != src) + return + visualnet.remove_eye(src) + owner.eyeobj = null + owner = null + SetName(initial(name)) + +// Use this when setting the eye's location. +// It will also stream the chunk that the new loc is in. +/mob/observer/eye/proc/setLoc(var/T) + if(!owner) + return FALSE + + T = get_turf(T) + if(!T || T == loc) + return FALSE + + forceMove(T) + + if(owner.client) + owner.client.eye = src + if(owner_follows_eye) + owner.forceMove(loc) + + visualnet.update_eye_chunks(src) + return TRUE + +/mob/observer/eye/proc/getLoc() + if(owner) + if(!isturf(owner.loc) || !owner.client) + return + return loc + +/mob + var/mob/observer/eye/eyeobj + +/mob/proc/EyeMove(n, direct) + if(!eyeobj) + return + + return eyeobj.EyeMove(n, direct) + +/mob/observer/eye/EyeMove(n, direct) + var/initial = initial(sprint) + var/max_sprint = 50 + + if(cooldown && cooldown < world.timeofday) + sprint = initial + + for(var/i = 0; i < max(sprint, initial); i += 20) + var/turf/step = get_turf(get_step(src, direct)) + if(step) + setLoc(step) + + cooldown = world.timeofday + 5 + if(acceleration) + sprint = min(sprint + 0.5, max_sprint) + else + sprint = initial + return 1 diff --git a/code/modules/mob/observer/freelook/life.dm b/code/modules/mob/observer/freelook/life.dm new file mode 100644 index 00000000..1ef0ca92 --- /dev/null +++ b/code/modules/mob/observer/freelook/life.dm @@ -0,0 +1,7 @@ +/mob/observer/eye/Life() + ..() + // If we lost our client, reset the list of visible chunks so they update properly on return + if(owner == src && !client) + visibleChunks.Cut() + /*else if(owner && !owner.client) + visibleChunks.Cut()*/ diff --git a/code/modules/mob/observer/freelook/logging.dm b/code/modules/mob/observer/freelook/logging.dm new file mode 100644 index 00000000..c2407179 --- /dev/null +++ b/code/modules/mob/observer/freelook/logging.dm @@ -0,0 +1,5 @@ +/datum/chunk/proc/log_visualnet(var/message, var/datum/source) + visualnet.log_visualnet("[src] ([x]-[y]-[z]) - [message]", source) + +/datum/visualnet/proc/log_visualnet(var/message, var/datum/source) + log_debug("[src] - [message]: [istype(source) ? "[source] ([source.type])" : (source ? source : "NULL") ]") diff --git a/code/modules/mob/observer/freelook/read_me.dm b/code/modules/mob/observer/freelook/read_me.dm new file mode 100644 index 00000000..380a3e01 --- /dev/null +++ b/code/modules/mob/observer/freelook/read_me.dm @@ -0,0 +1,51 @@ +// CREDITS +/* + Initial code credit for this goes to Uristqwerty. + Debugging, functionality, all comments and porting by Giacom. + + Everything about freelook (or what we can put in here) will be stored here. + + + WHAT IS THIS? + + This is a replacement for the current camera movement system, of the AI. Before this, the AI had to move between cameras and could + only see what the cameras could see. Not only this but the cameras could see through walls, which created problems. + With this, the AI controls an "AI Eye" mob, which moves just like a ghost; such as moving through walls and being invisible to players. + The AI's eye is set to this mob and then we use a system (explained below) to determine what the cameras around the AI Eye can and + cannot see. If the camera cannot see a turf, it will black it out, otherwise it won't and the AI will be able to see it. + This creates several features, such as.. no more see-through-wall cameras, easier to control camera movement, easier tracking, + the AI only being able to track mobs which are visible to a camera, only trackable mobs appearing on the mob list and many more. + + + HOW IT WORKS + + It works by first creating a camera network datum. Inside of this camera network are "chunks" (which will be + explained later) and "cameras". The cameras list is kept up to date by obj/machinery/camera/New() and Destroy(). + + Next the camera network has chunks. These chunks are a 16x16 tile block of turfs and cameras contained inside the chunk. + These turfs are then sorted out based on what the cameras can and cannot see. If none of the cameras can see the turf, inside + the 16x16 block, it is listed as an "obscured" turf. Meaning the AI won't be able to see it. + + + HOW IT UPDATES + + The camera network uses a streaming method in order to effeciently update chunks. Since the server will have doors opening, doors closing, + turf being destroyed and other lag inducing stuff, we want to update it under certain conditions and not every tick. + + The chunks are not created straight away, only when an AI eye moves into it's area is when it gets created. + One a chunk is created, when a non glass door opens/closes or an opacity turf is destroyed, we check to see if an AI Eye is looking in the area. + We do this with the "seenby" list, which updates everytime an AI is near a chunk. If there is an AI eye inside the area, we update the chunk + that the changed atom is inside and all surrounding chunks, since a camera's vision could leak onto another chunk. If there is no AI Eye, we instead + flag the chunk to update whenever it is loaded by an AI Eye. This is basically how the chunks update and keep it in sync. We then add some lag reducing + measures, such as an UPDATE_BUFFER which stops a chunk from updating too many times in a certain time-frame, only updating if the changed atom was blocking + sight; for example, we don't update glass airlocks or floors. + + + WHERE IS EVERYTHING? + + cameranet.dm = Everything about the cameranet datum. + chunk.dm = Everything about the chunk datum. + eye.dm = Everything about the AI and the AIEye. + updating.dm = Everything about triggers that will update chunks. + +*/ \ No newline at end of file diff --git a/code/modules/mob/observer/freelook/update_triggers.dm b/code/modules/mob/observer/freelook/update_triggers.dm new file mode 100644 index 00000000..ad5f34e9 --- /dev/null +++ b/code/modules/mob/observer/freelook/update_triggers.dm @@ -0,0 +1,41 @@ +//UPDATE TRIGGERS, when the chunk (and the surrounding chunks) should update. + +// TURFS + +/proc/updateVisibility(atom/A, var/opacity_check = 1) + if(ticker) + for(var/datum/visualnet/VN in visual_nets) + VN.update_visibility(A, opacity_check) + +/turf/drain_power() + return -1 + +/atom/Destroy() + if(opacity) + updateVisibility(src) + . = ..() + +/atom/movable/Move() + . = ..() + if(opacity && .) + updateVisibility(src) + +/atom/movable/forceMove() + . = ..() + if(opacity && .) + updateVisibility(src) + +// DOORS + +// Simply updates the visibility of the area when it opens/closes/destroyed. +/obj/machinery/door/update_nearby_tiles(need_rebuild) + . = ..(need_rebuild) + // Glass door glass = 1 + // don't check then? + if(!glass) + updateVisibility(src, FALSE) + +/turf/ChangeTurf() + . = ..() + if(.) + updateVisibility(src, FALSE) diff --git a/code/modules/mob/observer/freelook/visualnet.dm b/code/modules/mob/observer/freelook/visualnet.dm new file mode 100644 index 00000000..5622157b --- /dev/null +++ b/code/modules/mob/observer/freelook/visualnet.dm @@ -0,0 +1,185 @@ +// VISUAL NET +// +// The datum containing all the chunks. + +/datum/visualnet + // The chunks of the map, mapping the areas that an object can see. + var/list/chunks = list() + var/list/sources = list() + var/chunk_type = /datum/chunk + var/list/valid_source_types + +/datum/visualnet/New() + ..() + visual_nets += src + if(!valid_source_types) + valid_source_types = list() + +/datum/visualnet/Destroy() + visual_nets -= src + for(var/source in sources) + remove_source(source, FALSE) + sources.Cut() + for(var/chunk in chunks) + qdel(chunk) + chunks.Cut() + . = ..() + +// Checks if a chunk has been Generated in x, y, z. +/datum/visualnet/proc/is_chunk_generated(x, y, z) + x &= ~0xf + y &= ~0xf + var/key = "[x],[y],[z]" + return !isnull(chunks[key]) + +// Returns the chunk in the x, y, z. +// If there is no chunk, it creates a new chunk and returns that. +/datum/visualnet/proc/get_chunk(x, y, z) + x &= ~0xf + y &= ~0xf + var/key = "[x],[y],[z]" + if(!chunks[key]) + chunks[key] = new chunk_type(src, x, y, z) + + return chunks[key] + +// Updates what the eye can see. It is recommended you use this when the eye moves or its location is set. + +/datum/visualnet/proc/update_eye_chunks(mob/observer/eye/eye, var/full_update = FALSE) + . = list() + var/turf/T = get_turf(eye) + if(T) + // 0xf = 15 + var/x1 = max(0, T.x - 16) & ~0xf + var/y1 = max(0, T.y - 16) & ~0xf + var/x2 = min(world.maxx, T.x + 16) & ~0xf + var/y2 = min(world.maxy, T.y + 16) & ~0xf + + for(var/x = x1; x <= x2; x += 16) + for(var/y = y1; y <= y2; y += 16) + . += get_chunk(x, y, T.z) + + if(full_update) + eye.visibleChunks.Cut() + + var/list/remove = eye.visibleChunks - . + var/list/add = . - eye.visibleChunks + + for(var/chunk in remove) + var/datum/chunk/c = chunk + c.remove_eye(eye) + + for(var/chunk in add) + var/datum/chunk/c = chunk + c.add_eye(eye) + +/datum/visualnet/proc/remove_eye(mob/observer/eye/eye) + for(var/chunk in eye.visibleChunks) + var/datum/chunk/c = chunk + c.remove_eye(eye) + +// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open. + +/datum/visualnet/proc/update_visibility(atom/A, var/opacity_check = TRUE) + if(!ticker || (opacity_check && !A.opacity)) + return + major_chunk_change(A) + +/datum/visualnet/proc/update_visibility_nocheck(atom/A) + update_visibility(A, FALSE) + +// Will check if an atom is on a viewable turf. Returns 1 if it is, otherwise returns 0. +/datum/visualnet/proc/is_visible(var/atom/target) + // 0xf = 15 + var/turf/position = get_turf(target) + return position && is_turf_visible(position) + +/datum/visualnet/proc/is_turf_visible(var/turf/position) + if(!position) + return FALSE + var/datum/chunk/chunk = get_chunk(position.x, position.y, position.z) + if(chunk) + if(chunk.dirty) + chunk.update(TRUE) // Update now, no matter if it's visible or not. + if(position in chunk.visibleTurfs) + return TRUE + return FALSE + +// Never access this proc directly!!!! +// This will update the chunk and all the surrounding chunks. +/datum/visualnet/proc/major_chunk_change(var/atom/source) + for_all_chunks_in_range(source, /datum/chunk/proc/visibility_changed, list()) + +/datum/visualnet/proc/add_source(var/atom/source, var/update_visibility = TRUE, var/opacity_check = FALSE) + if(!(source && is_type_in_list(source, valid_source_types))) + log_visualnet("Was given an unhandled source", source) + return FALSE + if(source in sources) + return FALSE + sources += source + GLOB.moved_event.register(source, src, /datum/visualnet/proc/source_moved) + GLOB.destroyed_event.register(source, src, /datum/visualnet/proc/remove_source) + for_all_chunks_in_range(source, /datum/chunk/proc/add_source, list(source)) + if(update_visibility) + update_visibility(source, opacity_check) + return TRUE + +/datum/visualnet/proc/remove_source(var/atom/source, var/update_visibility = TRUE, var/opacity_check = FALSE) + if(!sources.Remove(source)) + return FALSE + + GLOB.moved_event.unregister(source, src, /datum/visualnet/proc/source_moved) + GLOB.destroyed_event.unregister(source, src, /datum/visualnet/proc/remove_source) + for_all_chunks_in_range(source, /datum/chunk/proc/remove_source, list(source)) + if(update_visibility) + update_visibility(source, opacity_check) + return TRUE + +/datum/visualnet/proc/source_moved(var/atom/movable/source, var/old_loc, var/new_loc) + var/turf/old_turf = get_turf(old_loc) + var/turf/new_turf = get_turf(new_loc) + + if(old_turf == new_turf) + return + + // A more proper way would be to figure out which chunks have gone out of range, and which have come into range + // and only remove/add to those. + if(old_turf) + for_all_chunks_in_range(source, /datum/chunk/proc/remove_source, list(source), old_turf) + if(new_turf) + for_all_chunks_in_range(source, /datum/chunk/proc/add_source, list(source), new_turf) + +/datum/visualnet/proc/for_all_chunks_in_range(var/atom/source, var/proc_call, var/list/proc_args, var/turf/T) + T = T ? T : get_turf(source) + if(!T) + return + + var/x1 = max(0, T.x - 8) & ~0xf + var/y1 = max(0, T.y - 8) & ~0xf + var/x2 = min(world.maxx, T.x + 8) & ~0xf + var/y2 = min(world.maxy, T.y + 8) & ~0xf + + for(var/x = x1; x <= x2; x += 16) + for(var/y = y1; y <= y2; y += 16) + if(is_chunk_generated(x, y, T.z)) + var/datum/chunk/c = get_chunk(x, y, T.z) + call(c, proc_call)(arglist(proc_args)) + +// Debug verb for VVing the chunk that the turf is in. +/turf/proc/view_chunk() + set name = "View Chunk" + set category = "Debug" + set src in world + + if(cameranet.is_chunk_generated(x, y, z)) + var/datum/chunk/chunk = cameranet.get_chunk(x, y, z) + usr.client.debug_variables(chunk) + +/turf/proc/update_chunk() + set name = "Update Chunk" + set category = "Debug" + set src in world + + if(cameranet.is_chunk_generated(x, y, z)) + var/datum/chunk/chunk = cameranet.get_chunk(x, y, z) + chunk.visibility_changed(TRUE) diff --git a/code/modules/mob/observer/ghost/follow.dm b/code/modules/mob/observer/ghost/follow.dm new file mode 100644 index 00000000..237f7f14 --- /dev/null +++ b/code/modules/mob/observer/ghost/follow.dm @@ -0,0 +1,37 @@ +/datum/proc/extra_ghost_link(var/prefix, var/sufix, var/short_links) + return list() + +/atom/movable/extra_ghost_link(var/atom/ghost, var/prefix, var/sufix, var/short_links) + if(src == ghost) + return list() + return list(create_ghost_link(ghost, src, short_links ? "F" : "Follow", prefix, sufix)) + +/client/extra_ghost_link(var/atom/ghost, var/prefix, var/sufix, var/short_links) + return mob.extra_ghost_link(ghost, prefix, sufix, short_links) + +/mob/extra_ghost_link(var/atom/ghost, var/prefix, var/sufix, var/short_links) + . = ..() + if(client && eyeobj) + . += create_ghost_link(ghost, eyeobj, short_links ? "E" : "Eye", prefix, sufix) + +/mob/observer/ghost/extra_ghost_link(var/atom/ghost, var/prefix, var/sufix, var/short_links) + . = ..() + if(mind && (mind.current && !isghost(mind.current))) + . += create_ghost_link(ghost, mind.current, short_links ? "B" : "Body", prefix, sufix) + +/proc/create_ghost_link(var/ghost, var/target, var/text, var/prefix, var/sufix) + return "[prefix][text][sufix]" + +/datum/proc/get_ghost_follow_link(var/atom/target, var/delimiter, var/prefix, var/sufix) + return + +/client/get_ghost_follow_link(var/atom/target, var/delimiter, var/prefix, var/sufix) + return mob.get_ghost_follow_link(target, delimiter, prefix, sufix) + +/mob/observer/ghost/get_ghost_follow_link(var/atom/target, var/delimiter, var/prefix, var/sufix) + var/short_links = get_preference_value(/datum/client_preference/ghost_follow_link_length) == GLOB.PREF_SHORT + return ghost_follow_link(target, src, delimiter, prefix, sufix, short_links) + +/proc/ghost_follow_link(var/atom/target, var/atom/ghost, var/delimiter = "|", var/prefix = "", var/sufix = "", var/short_links = TRUE) + if((!target) || (!ghost)) return + return jointext(target.extra_ghost_link(ghost, prefix, sufix, short_links),delimiter) diff --git a/code/modules/mob/observer/ghost/ghost.dm b/code/modules/mob/observer/ghost/ghost.dm new file mode 100644 index 00000000..01ab34e1 --- /dev/null +++ b/code/modules/mob/observer/ghost/ghost.dm @@ -0,0 +1,574 @@ +var/global/list/image/ghost_darkness_images = list() //this is a list of images for things ghosts should still be able to see when they toggle darkness +var/global/list/image/ghost_sightless_images = list() //this is a list of images for things ghosts should still be able to see even without ghost sight + +var/list/NOIRLIST = list(0.3,0.3,0.3,0,\ + 0.3,0.3,0.3,0,\ + 0.3,0.3,0.3,0,\ + 0.0,0.0,0.0,1,) + + +/mob/observer/ghost + name = "ghost" + desc = "It's a g-g-g-g-ghooooost!" //jinkies! + icon = 'icons/mob/mob.dmi' + icon_state = "ghost" + appearance_flags = KEEP_TOGETHER + canmove = 0 + blinded = 0 + anchored = 1 // don't get pushed around + universal_speak = 1 + var/is_manifest = FALSE + var/next_visibility_toggle = 0 + var/can_reenter_corpse + var/bootime = 0 + var/started_as_observer //This variable is set to 1 when you enter the game as an observer. + //If you died in the game and are a ghost - this will remain as null. + //Note that this is not a reliable way to determine if admins started as observers, since they change mobs a lot. + var/has_enabled_antagHUD = 0 + var/medHUD = 0 + var/antagHUD = 0 + var/atom/movable/following = null + var/admin_ghosted = 0 + var/anonsay = 0 + var/ghostvision = 1 //is the ghost able to see things humans can't? + var/seedarkness = 1 + + var/obj/item/device/multitool/ghost_multitool + incorporeal_move = 1 + + var/list/hud_images // A list of hud images + +/mob/observer/ghost/New(mob/body) + see_in_dark = 100 + verbs += /mob/proc/toggle_antag_pool + + var/turf/T + if(ismob(body)) + T = get_turf(body) //Where is the body located? + attack_logs_ = body.attack_logs_ //preserve our attack logs by copying them to our ghost + + set_appearance(body) + if(body.mind && body.mind.name) + name = body.mind.name + else + if(body.real_name) + name = body.real_name + else + if(gender == MALE) + name = capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) + else + name = capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) + + mind = body.mind //we don't transfer the mind but we keep a reference to it. + else + spawn(10) // wait for the observer mob to receive the client's key + mind = new /datum/mind(key) + mind.current = src + if(!T) T = pick(GLOB.latejoin | GLOB.latejoin_cryo | GLOB.latejoin_gateway) //Safety in case we cannot find the body's position + forceMove(T) + + if(!name) //To prevent nameless ghosts + name = capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) + real_name = name + + if(cult) + cult.add_ghost_magic(src) + + ghost_multitool = new(src) + + GLOB.ghost_mob_list += src + + ..() + +/mob/observer/ghost/Destroy() + GLOB.ghost_mob_list -= src + stop_following() + qdel(ghost_multitool) + ghost_multitool = null + if(hud_images) + for(var/image/I in hud_images) + show_hud_icon(I.icon_state, FALSE) + hud_images = null + return ..() + +/mob/observer/ghost/Topic(href, href_list) + if (href_list["track"]) + if(istype(href_list["track"],/mob)) + var/mob/target = locate(href_list["track"]) in SSmobs.mob_list + if(target) + ManualFollow(target) + else + var/atom/target = locate(href_list["track"]) + if(istype(target)) + ManualFollow(target) + +/* +Transfer_mind is there to check if mob is being deleted/not going to have a body. +Works together with spawning an observer, noted above. +*/ + +/mob/observer/ghost/Life() + ..() + if(!loc) return + if(!client) return 0 + + handle_hud_glasses() + + if(antagHUD) + var/list/target_list = list() + for(var/mob/living/target in oview(src, 14)) + if(target.mind && target.mind.special_role) + target_list += target + if(target_list.len) + assess_targets(target_list, src) + if(medHUD) + process_medHUD(src) + + +/mob/observer/ghost/proc/process_medHUD(var/mob/M) + var/client/C = M.client + for(var/mob/living/carbon/human/patient in oview(M, 14)) + C.images += patient.hud_list[HEALTH_HUD] + C.images += patient.hud_list[STATUS_HUD_OOC] + +/mob/observer/ghost/proc/assess_targets(list/target_list, mob/observer/ghost/U) + var/client/C = U.client + for(var/mob/living/carbon/human/target in target_list) + C.images += target.hud_list[SPECIALROLE_HUD] + for(var/mob/living/silicon/target in target_list) + C.images += target.hud_list[SPECIALROLE_HUD] + return 1 + +/mob/proc/ghostize(var/can_reenter_corpse = CORPSE_CAN_REENTER) + // Are we the body of an aghosted admin? If so, don't make a ghost. + if(teleop && istype(teleop, /mob/observer/ghost)) + var/mob/observer/ghost/G = teleop + if(G.admin_ghosted) + return + if(key) + if(zoomed)//So ghosts aren't stuck looking forward. + do_zoom() + hide_fullscreens() + var/mob/observer/ghost/ghost = new(src) //Transfer safety to observer spawning proc. + ghost.can_reenter_corpse = can_reenter_corpse + ghost.timeofdeath = src.stat == DEAD ? src.timeofdeath : world.time + ghost.key = key + ghost.pixel_x = 0 + ghost.pixel_y = 0 + ghost.warfare_faction = warfare_faction //Keep the ghost on their team. + + if(ghost.client && !ghost.client.holder) + ghost.client.color = NOIRLIST//We don't want admins to have to see things in black and white the whole time. + ghost.verbs -= /mob/observer/ghost/verb/toggle_antagHUD // Poor guys, don't know what they are missing! + ghost.set_sight(sight&(~(SEE_TURFS|SEE_MOBS|SEE_OBJS)))//Ghosts can no longer see all. + return ghost + +/* +This is the proc mobs get to turn into a ghost. Forked from ghostize due to compatibility issues. +*/ +/mob/living/verb/ghost() + set category = "OOC" + set name = "Ghost" + set desc = "Relinquish your life and enter the land of the dead." + + if(stat == DEAD) + announce_ghost_joinleave(ghostize(1)) + else + succumb() + /* + else + var/response + if(src.client && src.client.holder) + response = alert(src, "You have the ability to Admin-Ghost. The regular Ghost verb will announce your presence to dead chat. Both variants will allow you to return to your body using 'aghost'.\n\nWhat do you wish to do?", "Are you sure you want to ghost?", "Ghost", "Admin Ghost", "Stay in body") + if(response == "Admin Ghost") + if(!src.client) + return + src.client.admin_ghost() + else if(config.respawn_delay) + response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost, you won't be able to play this round for another [config.respawn_delay] minute\s! You can't change your mind so choose wisely!)", "Are you sure you want to ghost?", "Ghost", "Stay in body") + else + response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost, you won't be able to return to this body! You can't change your mind so choose wisely!)", "Are you sure you want to ghost?", "Ghost", "Stay in body") + if(response != "Ghost") + return + resting = 1 + var/turf/location = get_turf(src) + message_admins("[key_name_admin(usr)] has ghosted. (JMP)") + log_game("[key_name_admin(usr)] has ghosted.") + var/mob/observer/ghost/ghost = ghostize(0) //0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3 + ghost.timeofdeath = world.time // Because the living mob won't have a time of death and we want the respawn timer to work properly. + announce_ghost_joinleave(ghost) + */ + +/mob/observer/ghost/can_use_hands() return 0 +/mob/observer/ghost/is_active() return 0 + +/mob/observer/ghost/Stat() + . = ..() + if(statpanel("Status")) + if(evacuation_controller) + var/eta_status = evacuation_controller.get_status_panel_eta() + if(eta_status) + stat(null, eta_status) + +/mob/observer/ghost/verb/reenter_corpse() + set category = "Ghost" + set name = "Re-enter Corpse" + if(!client) return + if(!(mind && mind.current && can_reenter_corpse)) + to_chat(src, "You have no body.") + return + if(mind.current.key && copytext(mind.current.key,1,2)!="@") //makes sure we don't accidentally kick any clients + to_chat(src, "Another consciousness is in your body... it is resisting you.") + return + stop_following() + mind.current.key = key + mind.current.teleop = null + mind.current.reload_fullscreen() + mind.current.client.color = null + if(!admin_ghosted) + announce_ghost_joinleave(mind, 0, "They now occupy their body again.") + return 1 + +/mob/observer/ghost/verb/toggle_medHUD() + set category = "Ghost" + set name = "Toggle MedicHUD" + set desc = "Toggles Medical HUD allowing you to see how everyone is doing" + if(!client) + return + if(medHUD) + medHUD = 0 + to_chat(src, "Medical HUD Disabled") + else + medHUD = 1 + to_chat(src, "Medical HUD Enabled") +/mob/observer/ghost/verb/toggle_antagHUD() + set category = "Ghost" + set name = "Toggle AntagHUD" + set desc = "Toggles AntagHUD allowing you to see who is the antagonist" + + if(!client) + return + var/mentor = is_mentor(usr.client) + if(!config.antag_hud_allowed && (!client.holder || mentor)) + to_chat(src, "Admins have disabled this for this round.") + return + var/mob/observer/ghost/M = src + if(jobban_isbanned(M, "AntagHUD")) + to_chat(src, "You have been banned from using this feature") + return + if(config.antag_hud_restricted && !M.has_enabled_antagHUD && (!client.holder || mentor)) + var/response = alert(src, "If you turn this on, you will not be able to take any part in the round.","Are you sure you want to turn this feature on?","Yes","No") + if(response == "No") return + M.can_reenter_corpse = 0 + if(!M.has_enabled_antagHUD && (!client.holder || mentor)) + M.has_enabled_antagHUD = 1 + if(M.antagHUD) + M.antagHUD = 0 + to_chat(src, "AntagHUD Disabled") + else + M.antagHUD = 1 + to_chat(src, "AntagHUD Enabled") +/mob/observer/ghost/verb/dead_tele(A in area_repository.get_areas_by_z_level()) + set category = "Ghost" + set name = "Teleport" + set desc= "Teleport to a location" + + var/area/thearea = area_repository.get_areas_by_z_level()[A] + if(!thearea) + to_chat(src, "No area available.") + return + + var/list/area_turfs = get_area_turfs(thearea, shall_check_if_holy() ? list(/proc/is_holy_turf) : list()) + if(!area_turfs.len) + to_chat(src, "This area has been entirely made into sacred grounds, you cannot enter it while you are in this plane of existence!") + return + + ghost_to_turf(pick(area_turfs)) + +/mob/observer/ghost/verb/dead_tele_coord(tx as num, ty as num, tz as num) + set category = "Ghost" + set name = "Teleport to Coordinate" + set desc= "Teleport to a coordinate" + + var/turf/T = locate(tx, ty, tz) + if(T) + ghost_to_turf(T) + else + to_chat(src, "Invalid coordinates.") +/mob/observer/ghost/verb/follow(var/datum/follow_holder/fh in get_follow_targets()) + set category = "Ghost" + set name = "Follow" + set desc = "Follow and haunt a mob." + + if(!fh.show_entry()) return + ManualFollow(fh.followed_instance) + +/mob/observer/ghost/proc/ghost_to_turf(var/turf/target_turf) + if(check_is_holy_turf(target_turf)) + to_chat(src, "The target location is holy grounds!") + return + stop_following() + forceMove(target_turf) + +// This is the ghost's follow verb with an argument +/mob/observer/ghost/proc/ManualFollow(var/atom/movable/target) + if(!target || target == following || target == src) + return + + stop_following() + following = target + GLOB.moved_event.register(following, src, /atom/movable/proc/move_to_turf) + GLOB.dir_set_event.register(following, src, /atom/proc/recursive_dir_set) + GLOB.destroyed_event.register(following, src, /mob/observer/ghost/proc/stop_following) + + to_chat(src, "Now following \the [following].") + move_to_turf(following, loc, following.loc) + +/mob/observer/ghost/proc/stop_following() + if(following) + to_chat(src, "No longer following \the [following]") + GLOB.moved_event.unregister(following, src) + GLOB.dir_set_event.unregister(following, src) + GLOB.destroyed_event.unregister(following, src) + following = null + +/mob/observer/ghost/move_to_turf(var/atom/movable/am, var/old_loc, var/new_loc) + var/turf/T = get_turf(new_loc) + if(check_is_holy_turf(T)) + to_chat(src, "You cannot follow something standing on holy grounds!") + return + ..() + +/mob/observer/ghost/memory() + set hidden = 1 + to_chat(src, "You are dead! You have no mind to store memory!") +/* +/mob/observer/ghost/add_memory() + set hidden = 1 + to_chat(src, "You are dead! You have no mind to store memory!") +*/ +/mob/observer/ghost/Post_Incorpmove() + stop_following() + +/mob/observer/ghost/verb/analyze_air() + set name = "Analyze Air" + set category = "Ghost" + + var/turf/t = get_turf(src) + if(t) + print_atmos_analysis(src, atmosanalyzer_scan(t)) + +/mob/observer/ghost/verb/check_radiation() + set name = "Check Radiation" + set category = "Ghost" + + var/turf/t = get_turf(src) + if(t) + var/rads = radiation_repository.get_rads_at_turf(t) + to_chat(src, "Radiation level: [rads ? rads : "0"] Bq.") + + +/mob/observer/ghost/verb/view_manfiest() + set name = "Show Crew Manifest" + set category = "Ghost" + + var/dat + dat += "

            Crew Manifest

            " + dat += html_crew_manifest() + + src << browse(dat, "window=manifest;size=370x420;can_close=1") + +//This is called when a ghost is drag clicked to something. +/mob/observer/ghost/MouseDrop(atom/over) + if(!usr || !over) return + if(isghost(usr) && usr.client && isliving(over)) + var/mob/living/M = over + // If they an admin, see if control can be resolved. + if(usr.client.holder && usr.client.holder.cmd_ghost_drag(src,M)) + return + // Otherwise, see if we can possess the target. + if(usr == src && try_possession(M)) + return + if(istype(over, /obj/machinery/drone_fabricator)) + if(try_drone_spawn(src, over)) + return + + return ..() + +/mob/observer/ghost/proc/try_possession(var/mob/living/M) + if(!config.ghosts_can_possess_animals) + to_chat(src, "Ghosts are not permitted to possess animals.") + return 0 + if(!M.can_be_possessed_by(src)) + return 0 + return M.do_possession(src) + +/mob/observer/ghost/pointed(atom/A as mob|obj|turf in view()) + if(!..()) + return 0 + usr.visible_message("[src] points to [A]") + return 1 + +/mob/observer/ghost/proc/show_hud_icon(var/icon_state, var/make_visible) + if(!hud_images) + hud_images = list() + var/image/hud_image = hud_images[icon_state] + if(!hud_image) + hud_image = image('icons/mob/mob.dmi', loc = src, icon_state = icon_state) + hud_images[icon_state] = hud_image + + if(make_visible) + add_client_image(hud_image) + else + remove_client_image(hud_image) + +/mob/observer/ghost/verb/toggle_anonsay() + set category = "Ghost" + set name = "Toggle Anonymous Chat" + set desc = "Toggles showing your key in dead chat." + + src.anonsay = !src.anonsay + if(anonsay) + to_chat(src, "Your key won't be shown when you speak in dead chat.") + else + to_chat(src, "Your key will be publicly visible again.") + +/mob/observer/ghost/canface() + return 1 + +/mob/proc/can_admin_interact() + return 0 + +/mob/observer/ghost/can_admin_interact() + return check_rights(R_ADMIN, 0, src) + +/mob/observer/ghost/verb/toggle_ghostsee() + set name = "Toggle Ghost Vision" + set desc = "Toggles your ability to see things only ghosts can see, like other ghosts" + set category = "Ghost" + ghostvision = !(ghostvision) + updateghostsight() + to_chat(src, "You [(ghostvision?"now":"no longer")] have ghost vision.") + +/mob/observer/ghost/verb/toggle_darkness() + set name = "Toggle Darkness" + set category = "Ghost" + seedarkness = !(seedarkness) + updateghostsight() + +/mob/observer/ghost/proc/updateghostsight() + if (!seedarkness) + set_see_invisible(SEE_INVISIBLE_NOLIGHTING) + else + set_see_invisible(ghostvision ? SEE_INVISIBLE_OBSERVER : SEE_INVISIBLE_LIVING) + updateghostimages() + +/mob/observer/ghost/proc/updateghostimages() + if (!client) + return + client.images -= ghost_sightless_images + client.images -= ghost_darkness_images + if(!seedarkness) + client.images |= ghost_sightless_images + if(ghostvision) + client.images |= ghost_darkness_images + else if(seedarkness && !ghostvision) + client.images |= ghost_sightless_images + client.images -= ghost_image //remove ourself + +/mob/observer/ghost/MayRespawn(var/feedback = 0, var/respawn_time = 0) + if(!client) + return FALSE + + if(can_reenter_corpse == CORPSE_CAN_REENTER_AND_RESPAWN) + return TRUE + + if(admin_ghosted)//aghosts can always respawn if they like + return TRUE + /* + if(mind && mind.current && mind.current.stat != DEAD && can_reenter_corpse == CORPSE_CAN_REENTER) + if(feedback) + to_chat(src, "Your non-dead body prevents you from respawning.") + return FALSE + + + if(config.antag_hud_restricted && has_enabled_antagHUD == 1) + if(feedback) + to_chat(src, "antagHUD restrictions prevent you from respawning.") + return FALSE + */ + + var/timedifference = world.time - timeofdeath + if(iswarfare())//If it's warfare then respawn is cut down to the config time, which is usually 2 minutes. + respawn_time = config.warfare_respawn_time + if(client.warfare_faction == RED_TEAM) + if(GLOB.red_captured_zones.len < 1) + to_chat(src, "We control no trenches, we cannot respawn.") + return FALSE + else if(client.warfare_faction == BLUE_TEAM) + if(GLOB.blue_captured_zones.len < 1) + to_chat(src, "We control no trenches, we cannot respawn.") + return FALSE + + if(!client.holder && respawn_time && timeofdeath && timedifference < respawn_time MINUTES) + var/timedifference_text = time2text(respawn_time MINUTES - timedifference,"mm:ss") + to_chat(src, "You must have been dead for [respawn_time] minute\s to respawn. You have [timedifference_text] left.") + return FALSE + + return TRUE + +/proc/isghostmind(var/datum/mind/player) + return player && !isnewplayer(player.current) && (!player.current || isghost(player.current) || (isliving(player.current) && player.current.stat == DEAD) || !player.current.client) + +/mob/proc/check_is_holy_turf(var/turf/T) + return FALSE + +/mob/observer/ghost/check_is_holy_turf(var/turf/T) + if(shall_check_if_holy() && is_holy_turf(T)) + return TRUE + +/mob/observer/ghost/proc/shall_check_if_holy() + if(invisibility >= INVISIBILITY_OBSERVER) + return FALSE + if(check_rights(R_ADMIN|R_FUN, 0, src)) + return FALSE + return TRUE + +/mob/observer/ghost/proc/set_appearance(var/mob/target) + var/pre_alpha = alpha + var/pre_plane = plane + var/pre_layer = layer + var/pre_invis = invisibility + + appearance = target + appearance_flags |= initial(appearance_flags) + alpha = pre_alpha + plane = pre_plane + layer = pre_layer + set_invisibility(pre_invis) + transform = null //make goast stand up + +/mob/observer/ghost/verb/respawn() + set name = "Respawn" + set category = "OOC" + + if (!(config.abandon_allowed)) + to_chat(usr, "Respawn is disabled.") + return + //if (!(ticker && ticker.mode)) + // to_chat(usr, "The game has not started. You may not attempt to respawn yet.") + // return + if (ticker.mode && ticker.mode.deny_respawn) + to_chat(usr, "Respawn is disabled for this roundtype.") + return + else if(!MayRespawn(1, config.respawn_delay)) + return + + client?.color = null + to_chat(usr, "You can respawn now, enjoy your new life!") + to_chat(usr, "Make sure to play a different character, and please roleplay correctly!") + announce_ghost_joinleave(client, 0) + + var/mob/new_player/M = new /mob/new_player() + M.key = key + log_and_message_admins("has respawned.", M) diff --git a/code/modules/mob/observer/ghost/login.dm b/code/modules/mob/observer/ghost/login.dm new file mode 100644 index 00000000..86778d77 --- /dev/null +++ b/code/modules/mob/observer/ghost/login.dm @@ -0,0 +1,7 @@ +/mob/observer/ghost/Login() + ..() + + if (ghost_image) + ghost_image.appearance = src + ghost_image.appearance_flags = RESET_ALPHA + updateghostimages() diff --git a/code/modules/mob/observer/ghost/logout.dm b/code/modules/mob/observer/ghost/logout.dm new file mode 100644 index 00000000..7c125cef --- /dev/null +++ b/code/modules/mob/observer/ghost/logout.dm @@ -0,0 +1,5 @@ +/mob/observer/ghost/Logout() + ..() + spawn(0) + if(src && !key) //we've transferred to another mob. This ghost should be deleted. + qdel(src) diff --git a/code/modules/mob/observer/ghost/say.dm b/code/modules/mob/observer/ghost/say.dm new file mode 100644 index 00000000..f30f4a67 --- /dev/null +++ b/code/modules/mob/observer/ghost/say.dm @@ -0,0 +1,2 @@ +/mob/observer/ghost/say(var/message) + sanitize_and_communicate(/decl/communication_channel/dsay, client, message) diff --git a/code/modules/mob/observer/observer.dm b/code/modules/mob/observer/observer.dm new file mode 100644 index 00000000..f82fcd8f --- /dev/null +++ b/code/modules/mob/observer/observer.dm @@ -0,0 +1,103 @@ +var/const/GHOST_IMAGE_NONE = 0 +var/const/GHOST_IMAGE_DARKNESS = 1 +var/const/GHOST_IMAGE_SIGHTLESS = 2 +var/const/GHOST_IMAGE_ALL = ~GHOST_IMAGE_NONE + +/mob/observer + density = 0 + alpha = 127 + plane = OBSERVER_PLANE + invisibility = INVISIBILITY_OBSERVER + see_invisible = SEE_INVISIBLE_OBSERVER + sight = SEE_TURFS|SEE_MOBS|SEE_OBJS|SEE_SELF + simulated = FALSE + stat = DEAD + status_flags = GODMODE + var/ghost_image_flag = GHOST_IMAGE_DARKNESS + var/image/ghost_image = null //this mobs ghost image, for deleting and stuff + +/mob/observer/New() + ..() + ghost_image = image(src.icon,src) + ghost_image.plane = plane + ghost_image.layer = layer + ghost_image.appearance = src + ghost_image.appearance_flags = RESET_ALPHA + if(ghost_image_flag & GHOST_IMAGE_DARKNESS) + ghost_darkness_images |= ghost_image //so ghosts can see the eye when they disable darkness + if(ghost_image_flag & GHOST_IMAGE_SIGHTLESS) + ghost_sightless_images |= ghost_image //so ghosts can see the eye when they disable ghost sight + updateallghostimages() + +/mob/observer/Destroy() + if (ghost_image) + ghost_darkness_images -= ghost_image + ghost_sightless_images -= ghost_image + qdel(ghost_image) + ghost_image = null + updateallghostimages() + . = ..() + +mob/observer/check_airflow_movable() + return FALSE + +/mob/observer/CanPass() + return TRUE + +/mob/observer/dust() //observers can't be vaporised. + return + +/mob/observer/gib() //observers can't be gibbed. + return + +/mob/observer/is_blind() //Not blind either. + return + +/mob/observer/is_deaf() //Nor deaf. + return + +/mob/observer/set_stat() + stat = DEAD // They are also always dead + +/proc/updateallghostimages() + for (var/mob/observer/ghost/O in GLOB.player_list) + O.updateghostimages() + +/mob/observer/touch_map_edge() + if(z in GLOB.using_map.sealed_levels) + return + + var/new_x = x + var/new_y = y + + if(x <= TRANSITIONEDGE) + new_x = TRANSITIONEDGE + 1 + else if (x >= (world.maxx - TRANSITIONEDGE + 1)) + new_x = world.maxx - TRANSITIONEDGE + else if (y <= TRANSITIONEDGE) + new_y = TRANSITIONEDGE + 1 + else if (y >= (world.maxy - TRANSITIONEDGE + 1)) + new_y = world.maxy - TRANSITIONEDGE + + var/turf/T = locate(new_x, new_y, z) + if(T) + forceMove(T) + inertia_dir = 0 + throwing = 0 + to_chat(src, "You cannot move further in this direction.") + + +/mob/observer/Stat() + . = ..() + if(statpanel("Status")) + if(iswarfare()) + if(client?.holder) + stat("[BLUE_TEAM] reinforcements:", SSWarfare.blue.left) + //stat("[BLUE_TEAM] capture points:", SSWarfare.blue.points) + stat("[RED_TEAM] reinforcements:", SSWarfare.red.left) + //stat("[RED_TEAM] capture points:", SSWarfare.red.points) + + for(var/area/A in GLOB.red_captured_zones) + stat("Red Captured Trench:", A) + for(var/area/A in GLOB.blue_captured_zones) + stat("Blue Captured Trench:", A) diff --git a/code/modules/mob/observer/virtual/_constants.dm b/code/modules/mob/observer/virtual/_constants.dm new file mode 100644 index 00000000..76446296 --- /dev/null +++ b/code/modules/mob/observer/virtual/_constants.dm @@ -0,0 +1,4 @@ +var/const/VIRTUAL_ABILITY_NONE = 0 +var/const/VIRTUAL_ABILITY_HEAR = 1 +var/const/VIRTUAL_ABILITY_SEE = 2 +var/const/VIRTUAL_ABILITY_ALL = (~VIRTUAL_ABILITY_NONE) diff --git a/code/modules/mob/observer/virtual/base.dm b/code/modules/mob/observer/virtual/base.dm new file mode 100644 index 00000000..1270563f --- /dev/null +++ b/code/modules/mob/observer/virtual/base.dm @@ -0,0 +1,70 @@ +var/list/all_virtual_listeners = list() + +/mob/observer/virtual + icon = 'icons/mob/virtual.dmi' + invisibility = INVISIBILITY_SYSTEM + see_in_dark = SEE_IN_DARK_DEFAULT + see_invisible = SEE_INVISIBLE_LIVING + sight = SEE_SELF + + virtual_mob = null + + var/atom/movable/host + var/host_type = /atom/movable + var/abilities = VIRTUAL_ABILITY_HEAR|VIRTUAL_ABILITY_SEE + var/list/broadcast_methods + + var/static/list/overlay_icons + +/mob/observer/virtual/New(var/location, var/atom/movable/host) + ..() + if(!istype(host, host_type)) + CRASH("Received an unexpected host type. Expected [host_type], was [log_info_line(host)].") + src.host = host + GLOB.moved_event.register(host, src, /atom/movable/proc/move_to_turf_or_null) + + all_virtual_listeners += src + + update_icon() + +/mob/observer/virtual/Initialize() + . = ..() + STOP_PROCESSING(SSmobs, src) + +/mob/observer/virtual/Destroy() + GLOB.moved_event.unregister(host, src, /atom/movable/proc/move_to_turf_or_null) + all_virtual_listeners -= src + host = null + return ..() + +/mob/observer/virtual/update_icon() + if(!overlay_icons) + overlay_icons = list() + for(var/i_state in icon_states(icon)) + overlay_icons[i_state] = image(icon = icon, icon_state = i_state) + overlays.Cut() + + if(abilities & VIRTUAL_ABILITY_HEAR) + overlays += overlay_icons["hear"] + if(abilities & VIRTUAL_ABILITY_SEE) + overlays += overlay_icons["see"] + +/*********************** +* Virtual Mob Creation * +***********************/ +/atom/movable + var/mob/observer/virtual/virtual_mob + +/atom/movable/Initialize() + . = ..() + if(shall_have_virtual_mob()) + virtual_mob = new virtual_mob(get_turf(src), src) + +/atom/movable/Destroy() + if(virtual_mob && !ispath(virtual_mob)) + qdel(virtual_mob) + virtual_mob = null + return ..() + +/atom/movable/proc/shall_have_virtual_mob() + return ispath(initial(virtual_mob)) diff --git a/code/modules/mob/observer/virtual/helpers.dm b/code/modules/mob/observer/virtual/helpers.dm new file mode 100644 index 00000000..e7b97f52 --- /dev/null +++ b/code/modules/mob/observer/virtual/helpers.dm @@ -0,0 +1,111 @@ +/* +* These calls could easily be setup to be a bunch of call()() with relevant procs and predicates but performance is a concern. +* BYOND is also a bit inflexible, as some predicates are of the sort /proc/name(host), others host.proc_name(), and some even do host.proc_name(parameter). +* Nothing that cannot be worked around, but it'd be a little messy. I miss C# lambdas... +*/ + +// Procs are arranged by "in range/hearers/viewers()" usage, as opposed to virtual mob hear/see abilities. +// Most of these procs can technically take any movable atom but unless they have a virtual mob the returned objects may not be the expected ones + +#define ACQUIRE_VIRTUAL_OR_TURF(A) A = (isvirtualmob(A) ? A : (((istype(A) && A.virtual_mob) ? A.virtual_mob : get_turf(A)))) ; if(!A) return +#define ACQUIRE_VIRTUAL_OR_RETURN(A) A = (isvirtualmob(A) ? A : (((istype(A) && A.virtual_mob) ? A.virtual_mob : null))) ; if(!A) return + +/**************** +* Range Helpers * +****************/ +/proc/clients_in_range(var/atom/movable/center_vmob) + . = list() + + ACQUIRE_VIRTUAL_OR_TURF(center_vmob) + for(var/mob/observer/virtual/v_mob in range(world.view, center_vmob)) + var/client/C = v_mob.get_client() + if(C) + . |= C + +/proc/hearers_in_range(var/atom/movable/center_vmob, var/hearing_range = world.view) + . = list() + + ACQUIRE_VIRTUAL_OR_TURF(center_vmob) + for(var/mob/observer/virtual/v_mob in range(hearing_range, center_vmob)) + if(v_mob.abilities & VIRTUAL_ABILITY_HEAR) + . |= v_mob.host + +/proc/viewers_in_range(var/atom/movable/center_vmob) + . = list() + + ACQUIRE_VIRTUAL_OR_TURF(center_vmob) + for(var/mob/observer/virtual/v_mob in range(world.view, center_vmob)) + if(v_mob.abilities & VIRTUAL_ABILITY_SEE) + . |= v_mob.host + +/*************** +* Hear Helpers * +***************/ +// A mob hears another mob if they have direct line of sight, ignoring turf luminosity. +// If there is an opaque object beteween the mobs then they cannot hear each other, even if their respective turfs can be seen. +// Thus, unlike viewing hearing is communicative. I.e. if Mob A can hear Mob B then Mob B can also hear Mob A. + +// Gets the hosts of all the virtual mobs that can hear the given movable atom (or rather, it's virtual mob or turf in that existence order) +/proc/all_hearers(var/atom/movable/heard_vmob, var/range = world.view, var/ignore_vis = FALSE) + . = list() + + ACQUIRE_VIRTUAL_OR_TURF(heard_vmob) + if(ignore_vis) + for(var/mob/observer/virtual/v_mob in range(range, heard_vmob)) + if(v_mob.abilities & VIRTUAL_ABILITY_HEAR) + . |= v_mob.host + else + for(var/mob/observer/virtual/v_mob in hearers(range, heard_vmob)) + if(v_mob.abilities & VIRTUAL_ABILITY_HEAR) + . |= v_mob.host + +/*************** +* View Helpers * +***************/ +// A mob can see another mob if: +// * Within visual range, with the following differences for (N)PCs. +// * PCs: Target is within client.view range, with center originating from either the mob or client.eye depending on client.eye_perspective. +// * NPCs: Target is within world.view range, with center always originating from the mob. +// * Either of the following is true: +// * The target mob is in direct line of sight and not standing on a turf with luminosity = 0 unless the viewing mob is close enough for see_in_dark to also be in range +// * The viewing mob has the SEE_MOBS sight flag. + +// Gets the hosts of all virtual mobs that can see the given atom movable as well as its turf +/proc/all_viewers(var/mob/observer/virtual/viewed_atom) + . = list() + + viewed_atom = istype(viewed_atom) ? viewed_atom.host : viewed_atom + var/turf/T = get_turf(viewed_atom) + if(!T) + return + + for(var/mob/observer/virtual/seeing_v_mob in viewers(world.view, viewed_atom)) + if(!(seeing_v_mob.abilities & VIRTUAL_ABILITY_SEE)) + continue + var/atom/movable/host = seeing_v_mob.host + if(host.virtual_can_see_turf(T)) + . |= host + +// This proc returns all hosts of virtual mobs in the given atom's view range (using its turf), ignoring invisibility, VIRUAL_ABILITY_SEE, and most other restrictions. +// In most cases you actually want the all_* procs above. This helper was designed with LOOC in mind. +/proc/hosts_in_view_range(var/atom/movable/viewing_atom) + . = list() + + ACQUIRE_VIRTUAL_OR_TURF(viewing_atom) + // As per http://www.byond.com/docs/ref/info.html#/proc/view by using a non-mob/client this automatically skips the vast majority of sight checks + for(var/mob/observer/virtual/v_mob in viewers(world.view, get_turf(viewing_atom.loc))) + . |= v_mob.host + +/* + Misc. helper +*/ + +// Eye mobs technically see everything always, the owner just has an overlay applied, thus this helper +/atom/movable/proc/virtual_can_see_turf(var/turf/T) + return TRUE // We assume objects have already been filtered using viewers() or similar proc + +/mob/observer/eye/virtual_can_see_turf(var/turf/T) + return visualnet.is_turf_visible(T) + +#undef ACQUIRE_VIRTUAL_OR_TURF +#undef ACQUIRE_VIRTUAL_OR_RETURN \ No newline at end of file diff --git a/code/modules/mob/observer/virtual/mob.dm b/code/modules/mob/observer/virtual/mob.dm new file mode 100644 index 00000000..46225d73 --- /dev/null +++ b/code/modules/mob/observer/virtual/mob.dm @@ -0,0 +1,22 @@ +/mob/observer/virtual/mob + host_type = /mob + +/mob/observer/virtual/mob/New(var/location, var/mob/host) + ..() + + GLOB.sight_set_event.register(host, src, /mob/observer/virtual/mob/proc/sync_sight) + GLOB.see_invisible_set_event.register(host, src, /mob/observer/virtual/mob/proc/sync_sight) + GLOB.see_in_dark_set_event.register(host, src, /mob/observer/virtual/mob/proc/sync_sight) + + sync_sight(host) + +/mob/observer/virtual/mob/Destroy() + GLOB.sight_set_event.unregister(host, src, /mob/observer/virtual/mob/proc/sync_sight) + GLOB.see_invisible_set_event.unregister(host, src, /mob/observer/virtual/mob/proc/sync_sight) + GLOB.see_in_dark_set_event.unregister(host, src, /mob/observer/virtual/mob/proc/sync_sight) + . = ..() + +/mob/observer/virtual/mob/proc/sync_sight(var/mob/mob_host) + sight = mob_host.sight + see_invisible = mob_host.see_invisible + see_in_dark = mob_host.see_in_dark diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm new file mode 100644 index 00000000..5358983e --- /dev/null +++ b/code/modules/mob/say.dm @@ -0,0 +1,119 @@ +/mob/proc/say() + return + +/mob/verb/whisper() + set name = "Whisper" + set category = "IC" + return + +/mob/verb/say_verb(message as text) + set name = "Say" + set category = "IC" + + if(typing_indicator) + qdel(typing_indicator) + usr.say(message) + +/mob/verb/me_verb(message as text) + set name = "Me" + set category = "IC" + + message = sanitize(message) + + if(typing_indicator) + qdel(typing_indicator) + if(use_me) + usr.emote("me",usr.emote_type,message) + else + usr.emote(message) + +/mob/proc/say_dead(var/message) + communicate(/decl/communication_channel/dsay, client, message) + +/mob/proc/say_understands(var/mob/other,var/datum/language/speaking = null) + + if (src.stat == 2) //Dead + return 1 + + //Universal speak makes everything understandable, for obvious reasons. + else if(src.universal_speak || src.universal_understand) + return 1 + + //Languages are handled after. + if (!speaking) + if(!other) + return 1 + if(other.universal_speak) + return 1 + if(isAI(src) && ispAI(other)) + return 1 + if (istype(other, src.type) || istype(src, other.type)) + return 1 + return 0 + + if(speaking.flags & INNATE) + return 1 + + //Language check. + for(var/datum/language/L in src.languages) + if(speaking.name == L.name) + return 1 + + return 0 + +/mob/proc/say_quote(var/message, var/datum/language/speaking = null) + var/ending = copytext(message, length(message)) + if(speaking) + return speaking.get_spoken_verb(ending) + + var/verb = pick(speak_emote) + if(verb == "says") //a little bit of a hack, but we can't let speak_emote default to an empty list without breaking other things + if(ending == "!") + verb = pick("exclaims","shouts","yells") + else if(ending == "?") + verb ="asks" + return verb + +/mob/proc/get_ear() + // returns an atom representing a location on the map from which this + // mob can hear things + + // should be overloaded for all mobs whose "ear" is separate from their "mob" + + return get_turf(src) + +/mob/proc/say_test(var/text) + var/ending = copytext(text, length(text)) + if (ending == "?") + return "1" + else if (ending == "!") + return "2" + return "0" + +//parses the message mode code (e.g. :h, :w) from text, such as that supplied to say. +//returns the message mode string or null for no message mode. +//standard mode is the mode returned for the special ';' radio code. +/mob/proc/parse_message_mode(var/message, var/standard_mode="headset") + if(length(message) >= 1 && copytext(message,1,2) == get_prefix_key(/decl/prefix/radio_main_channel)) + return standard_mode + + if(length(message) >= 2) + var/channel_prefix = copytext(message, 1 ,3) + return department_radio_keys[channel_prefix] + + return null + +//parses the language code (e.g. :j) from text, such as that supplied to say. +//returns the language object only if the code corresponds to a language that src can speak, otherwise null. +/mob/proc/parse_language(var/message) + var/prefix = copytext(message,1,2) + if(length(message) >= 1 && prefix == get_prefix_key(/decl/prefix/audible_emote)) + return all_languages["Noise"] + + if(length(message) >= 2 && is_language_prefix(prefix)) + var/language_prefix = lowertext(copytext(message, 2 ,3)) + var/datum/language/L = language_keys[language_prefix] + if (can_speak(L)) + return L + + return null diff --git a/code/modules/mob/shit_piss.dm b/code/modules/mob/shit_piss.dm new file mode 100644 index 00000000..f1459231 --- /dev/null +++ b/code/modules/mob/shit_piss.dm @@ -0,0 +1,315 @@ +/*#####SHIT AND PISS##### +##Ok there's a lot of stupid shit here. Literally, but let me explain a bit why I put this here. +##I feel like poo and pee add a degree of autistic realism that you wouldn't otherwise get. And I'm autistic about that kind of thing. +##This file contains all the reagents, decals, objects and life procs. These procs are used in human/life.dm and human/emote.dm +##Have some shitty fun. - Matt +*/ + +//####DEFINES#### + +/mob + var/bladder = 0 + var/bowels = 0 + +//#####DECALS##### +/obj/effect/decal/cleanable/poo + name = "poo stain" + desc = "Well that stinks." + density = 0 + anchored = 1 + layer = 2 + icon = 'icons/effects/pooeffect.dmi' + icon_state = "floor1" + random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7", "floor8") + var/dried = 0 + + +/obj/effect/decal/cleanable/poo/Initialize() + . = ..() + icon_state = pick(src.random_icon_states) + create_reagents(5) + reagents.add_reagent(/datum/reagent/poo,5) + for(var/obj/effect/decal/cleanable/poo/shit in src.loc) + if(shit != src) + qdel(shit) + spawn(6000) + dried = 1 + name = "dried poo stain" + desc = "It's a dried poo stain..." + + +/obj/effect/decal/cleanable/poo/tracks + icon_state = "tracks" + random_icon_states = null + +/obj/effect/decal/cleanable/poo/drip + name = "drips of poo" + desc = "It's brown." + density = 0 + anchored = 1 + layer = 2 + icon = 'icons/effects/pooeffect.dmi' + icon_state = "drip1" + random_icon_states = list("drip1", "drip2", "drip3", "drip4", "drip5") + +/obj/effect/decal/cleanable/poo/Crossed(AM as mob|obj, var/forceslip = 0) + if (istype(AM, /mob/living/carbon) && src.dried == 0) + var/mob/living/carbon/M = AM + if (M.m_intent == "walk") + return + + if(prob(5)) + M.slip("poo") + +/obj/effect/decal/cleanable/urine + name = "urine stain" + desc = "Someone couldn't hold it.." + density = 0 + anchored = 1 + layer = 2 + icon = 'icons/effects/pooeffect.dmi' + icon_state = "pee1" + random_icon_states = list("pee1", "pee2", "pee3") + var/dried = 0 + +/obj/effect/decal/cleanable/urine/Crossed(AM as mob|obj) + if (istype(AM, /mob/living/carbon)) + var/mob/living/carbon/M = AM + if ((ishuman(M) && istype(M:shoes, /obj/item/clothing/shoes/galoshes)) || M.m_intent == "walk") + return + + if((!dried) && prob(5)) + M.slip("urine") + +/obj/effect/decal/cleanable/urine/Initialize() + . = ..() + create_reagents(5) + icon_state = pick(random_icon_states) + reagents.add_reagent(/datum/reagent/urine,5) + for(var/obj/effect/decal/cleanable/urine/piss in src.loc) + if(piss != src) + qdel(piss) + + spawn(800) + dried = 1 + name = "dried urine stain" + desc = "That's a dried crusty urine stain. Fucking janitors." + + +//#####REAGENTS##### + +//SHIT +/datum/reagent/poo + name = "poo" + description = "It's poo." + reagent_state = REAGENT_LIQUID + color = "#643200" + taste_description = "literal shit" + +/datum/reagent/poo/touch_turf(var/turf/T) + if(!istype(T, /turf/space)) + new /obj/effect/decal/cleanable/poo(T) + qdel(src) + +//URINE +/datum/reagent/urine + name = "urine" + description = "It's pee." + reagent_state = REAGENT_LIQUID + color = COLOR_YELLOW + taste_description = "urine" + +/datum/reagent/urine/touch_turf(var/turf/T) + if(!istype(T, /turf/space)) + new /obj/effect/decal/cleanable/urine(T) + qdel(src) + + +/obj/item/weapon/reagent_containers/food/snacks/poo + name = "poo" + desc = "A chocolately surprise!" + icon = 'icons/obj/poop.dmi' + icon_state = "poop2" + item_state = "poop" + +/obj/item/weapon/reagent_containers/food/snacks/poo/New() + ..() + icon_state = pick("poop1", "poop2", "poop3", "poop4", "poop5", "poop6", "poop7") + reagents.add_reagent(/datum/reagent/poo, 10) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/poo/throw_impact(atom/hit_atom) + playsound(src.loc, "sound/effects/squishy.ogg", 40, 1) + var/turf/T = src.loc + if(!istype(T, /turf/space)) + new /obj/effect/decal/cleanable/poo(T) + qdel(src) + + +//#####BOTTLES##### + +//PISS +/obj/item/weapon/reagent_containers/glass/bottle/urine + name = "urine bottle" + desc = "A small bottle. Contains urine." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle15" + +/obj/item/weapon/reagent_containers/glass/bottle/urine/New() + ..() + reagents.add_reagent(/datum/reagent/urine, 30) + + +//#####LIFE PROCS##### + +//poo and pee counters. This is called in human/handle_stomach. +/mob/living/carbon/human/proc/handle_excrement() + if(bowels <= 0) + bowels = 0 + if(bladder <= 0) + bladder = 0 + + if(has_quirk(/datum/quirk/no_bathroom))//You'll never have to use the restroom now. + bladder = 0 + bowels = 0 + + if(bowels >= 250) + switch(bowels) + if(250 to 400) + if(prob(5)) + to_chat(src, "You need to use the bathroom.") + bowels += 15 + if(400 to 450) + if(prob(5)) + to_chat(src, "You really need to use the restroom!") + bowels += 15 + if(450 to 500) + if(prob(2)) + handle_shit() + else if(prob(10)) + to_chat(src, "You're about to shit yourself!") + bowels += 25 + if(500 to 550) + if(prob(15)) + handle_shit() + else if(prob(30)) + to_chat(src, "OH MY GOD YOU HAVE TO SHIT!") + bowels += 35 + if(550 to INFINITY) + handle_shit() + + if(bladder >= 100)//Your bladder is smaller than your colon + switch(bladder) + if(100 to 250) + if(prob(5)) + to_chat(src, "You need to use the bathroom.") + bladder += 15 + if(250 to 400) + if(prob(5)) + to_chat(src, "You really need to use the restroom!") + bladder += 15 + if(400 to 500) + if(prob(2)) + handle_piss() + else if(prob(10)) + to_chat(src, "You're about to piss yourself!") + bladder += 25 + if(500 to 550) + if(prob(15)) + handle_piss() + else if(prob(30)) + to_chat(src, "OH MY GOD YOU HAVE TO PEE!") + bladder += 35 + if(550 to INFINITY) + handle_piss() + +//Shitting +/mob/living/carbon/human/proc/handle_shit() + var/message = null + if (src.bowels >= 30) + + //Poo in the loo. + var/obj/structure/toilet/T = locate() in src.loc + var/mob/living/M = locate() in src.loc + if(T && T.open) + message = "[src] defecates into \the [T]." + + else if(w_uniform) + message = "[src] shits \his pants." + reagents.add_reagent(/datum/reagent/poo, 10) + add_event("shitself", /datum/happiness_event/hygiene/shit) + unlock_achievement(new/datum/achievement/shit_pants()) + + //Poo on the face. + else if(M != src && M.lying)//Can only shit on them if they're lying down. + message = "[src] shits right on [M]'s face!" + M.reagents.add_reagent(/datum/reagent/poo, 10) + M.unlock_achievement(new/datum/achievement/shit_on()) + + //Poo on the floor. + else + message = "[src] [pick("shits", "craps", "poops")]." + var/obj/item/weapon/reagent_containers/food/snacks/poo/V = new/obj/item/weapon/reagent_containers/food/snacks/poo(src.loc) + if(reagents) + reagents.trans_to(V, rand(1,5)) + GLOB.shit_left++//Add it to the shit on the floor counter. + + playsound(src.loc, 'sound/effects/poo2.ogg', 60, 1) + bowels -= rand(60,80) + + else + to_chat(src, "You don't have to.") + return + + visible_message("[message]") + +//Peeing +/mob/living/carbon/human/proc/handle_piss() + var/message = null + if (bladder < 30) + to_chat(src, "You don't have to.") + return + + var/obj/structure/urinal/U = locate() in src.loc + var/obj/structure/toilet/T = locate() in src.loc + var/obj/structure/sink/S = locate() in src.loc + var/obj/item/weapon/reagent_containers/RC = locate() in src.loc + if((U || S) && gender != FEMALE)//In the urinal or sink. + message = "[src] urinates into [U ? U : S]." + reagents.remove_any(rand(1,8)) + + else if(T && T.open)//In the toilet. + message = "[src] urinates into [T]." + reagents.remove_any(rand(1,8)) + + else if(RC && (istype(RC,/obj/item/weapon/reagent_containers/food/drinks || istype(RC,/obj/item/weapon/reagent_containers/glass)))) + if(RC.is_open_container()) + //Inside a beaker, glass, drink, etc. + message = "[src] urinates into [RC]." + var/amount = rand(1,8) + RC.reagents.add_reagent(/datum/reagent/urine, amount) + if(reagents) + reagents.trans_to(RC, amount) + + else if(w_uniform)//In your pants. + message = "[src] pisses \his pants." + add_event("pissedself", /datum/happiness_event/hygiene/pee) + unlock_achievement(new/datum/achievement/pissed()) + var/obj/effect/decal/cleanable/urine/D = new/obj/effect/decal/cleanable/urine(src.loc) + if(reagents) + reagents.trans_to(D, rand(1,8)) + GLOB.piss_left++ + + + else//On the floor. + var/turf/TT = src.loc + var/obj/effect/decal/cleanable/urine/D = new/obj/effect/decal/cleanable/urine(src.loc) + if(reagents) + reagents.trans_to(D, rand(1,8)) + if(TT)//In case it's somehow not there. + message = "[src] pisses on the [TT.name]." + GLOB.piss_left++//Add it to the piss on the floor counter. + + bladder -= rand(25,50) + visible_message("[message]") + diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm new file mode 100644 index 00000000..0a75757d --- /dev/null +++ b/code/modules/mob/transform_procs.dm @@ -0,0 +1,334 @@ +/mob/living/carbon/human/proc/monkeyize() + if (transforming) + return + for(var/obj/item/W in src) + if (W==w_uniform) // will be torn + continue + drop_from_inventory(W) + regenerate_icons() + transforming = 1 + canmove = 0 + stunned = 1 + icon = null + set_invisibility(101) + for(var/t in organs) + qdel(t) + var/atom/movable/overlay/animation = new /atom/movable/overlay( loc ) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = src + flick("h2monkey", animation) + sleep(48) + //animation = null + + transforming = 0 + stunned = 0 + update_canmove() + set_invisibility(initial(invisibility)) + + if(!species.primitive_form) //If the creature in question has no primitive set, this is going to be messy. + gib() + return + + for(var/obj/item/W in src) + drop_from_inventory(W) + set_species(species.primitive_form) + dna.SetSEState(GLOB.MONKEYBLOCK,1) + dna.SetSEValueRange(GLOB.MONKEYBLOCK,0xDAC, 0xFFF) + + to_chat(src, "You are now [species.name]. ") + qdel(animation) + + return src + +/mob/new_player/AIize() + spawning = 1 + return ..() + +/mob/living/carbon/human/AIize(move=1) // 'move' argument needs defining here too because BYOND is dumb + if (transforming) + return + for(var/t in organs) + qdel(t) + QDEL_NULL_LIST(worn_underwear) + return ..(move) + +/mob/living/carbon/AIize() + if (transforming) + return + for(var/obj/item/W in src) + drop_from_inventory(W) + transforming = 1 + canmove = 0 + icon = null + set_invisibility(101) + return ..() + +/mob/proc/AIize(move=1) + if(client) + sound_to(src, sound(null, repeat = 0, wait = 0, volume = 85, channel = 1))// stop the jams for AIs + + + var/mob/living/silicon/ai/O = new (loc, GLOB.using_map.default_law_type,,1)//No MMI but safety is in effect. + O.set_invisibility(0) + O.aiRestorePowerRoutine = 0 + if(mind) + mind.transfer_to(O) + O.mind.original = O + else + O.key = key + + if(move) + var/obj/loc_landmark + for(var/obj/effect/landmark/start/sloc in landmarks_list) + if (sloc.name != "AI") + continue + if ((locate(/mob/living) in sloc.loc) || (locate(/obj/structure/AIcore) in sloc.loc)) + continue + loc_landmark = sloc + if (!loc_landmark) + for(var/obj/effect/landmark/tripai in landmarks_list) + if (tripai.name == "tripai") + if((locate(/mob/living) in tripai.loc) || (locate(/obj/structure/AIcore) in tripai.loc)) + continue + loc_landmark = tripai + if (!loc_landmark) + to_chat(O, "Oh god sorry we can't find an unoccupied AI spawn location, so we're spawning you on top of someone.") + for(var/obj/effect/landmark/start/sloc in landmarks_list) + if (sloc.name == "AI") + loc_landmark = sloc + O.forceMove(loc_landmark.loc) + O.on_mob_init() + + O.add_ai_verbs() + + O.rename_self("ai",1) + spawn(0) // Mobs still instantly del themselves, thus we need to spawn or O will never be returned + qdel(src) + return O + +//human -> robot +/mob/living/carbon/human/proc/Robotize() + if (transforming) + return + QDEL_NULL_LIST(worn_underwear) + for(var/obj/item/W in src) + drop_from_inventory(W) + regenerate_icons() + transforming = 1 + canmove = 0 + icon = null + set_invisibility(101) + for(var/t in organs) + qdel(t) + + var/mob/living/silicon/robot/O = new /mob/living/silicon/robot( loc ) + + O.gender = gender + O.set_invisibility(0) + + if(mind) //TODO + mind.transfer_to(O) + if(O.mind.assigned_role == "Cyborg") + O.mind.original = O + else if(mind && mind.special_role) + O.mind.store_memory("In case you look at this after being borged, the objectives are only here until I find a way to make them not show up for you, as I can't simply delete them without screwing up round-end reporting. --NeoFite") + else + O.key = key + + O.loc = loc + O.job = "Cyborg" + if(O.mind.assigned_role == "Cyborg") + if(O.mind.role_alt_title == "Android") + O.mmi = new /obj/item/organ/internal/posibrain(O) + else if(O.mind.role_alt_title == "Robot") + O.mmi = new /obj/item/device/mmi/digital/robot(O) + else + O.mmi = new /obj/item/device/mmi(O) + + O.mmi.transfer_identity(src) + + callHook("borgify", list(O)) + O.Namepick() + + spawn(0) // Mobs still instantly del themselves, thus we need to spawn or O will never be returned + qdel(src) + return O + +/mob/living/carbon/human/proc/slimeize(adult as num, reproduce as num) + if (transforming) + return + for(var/obj/item/W in src) + drop_from_inventory(W) + regenerate_icons() + transforming = 1 + canmove = 0 + icon = null + set_invisibility(101) + for(var/t in organs) + qdel(t) + + var/mob/living/carbon/slime/new_slime + if(reproduce) + var/number = pick(14;2,3,4) //reproduce (has a small chance of producing 3 or 4 offspring) + var/list/babies = list() + for(var/i=1,i<=number,i++) + var/mob/living/carbon/slime/M = new/mob/living/carbon/slime(loc) + M.nutrition = round(nutrition/number) + step_away(M,src) + babies += M + new_slime = pick(babies) + else + new_slime = new /mob/living/carbon/slime(loc) + if(adult) + new_slime.is_adult = 1 + else + new_slime.key = key + + to_chat(new_slime, "You are now a slime. Skreee!") + qdel(src) + return + +/mob/living/carbon/human/proc/corgize() + if (transforming) + return + for(var/obj/item/W in src) + drop_from_inventory(W) + regenerate_icons() + transforming = 1 + canmove = 0 + icon = null + set_invisibility(101) + for(var/t in organs) //this really should not be necessary + qdel(t) + + var/mob/living/simple_animal/corgi/new_corgi = new /mob/living/simple_animal/corgi (loc) + new_corgi.a_intent = I_HURT + new_corgi.key = key + + to_chat(new_corgi, "You are now a Corgi. Yap Yap!") + qdel(src) + return + +/mob/living/carbon/human/Animalize() + + var/list/mobtypes = typesof(/mob/living/simple_animal) + var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") in mobtypes + + if(!safe_animal(mobpath)) + to_chat(usr, "Sorry but this mob type is currently unavailable.") + return + + if(transforming) + return + for(var/obj/item/W in src) + drop_from_inventory(W) + + regenerate_icons() + transforming = 1 + canmove = 0 + icon = null + set_invisibility(101) + + for(var/t in organs) + qdel(t) + + var/mob/new_mob = new mobpath(src.loc) + + new_mob.key = key + new_mob.a_intent = I_HURT + + + to_chat(new_mob, "You suddenly feel more... animalistic.") + spawn() + qdel(src) + return + +/mob/proc/Animalize() + + var/list/mobtypes = typesof(/mob/living/simple_animal) + var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") in mobtypes + + if(!safe_animal(mobpath)) + to_chat(usr, "Sorry but this mob type is currently unavailable.") + return + + var/mob/new_mob = new mobpath(src.loc) + + new_mob.key = key + new_mob.a_intent = I_HURT + to_chat(new_mob, "You feel more... animalistic") + + qdel(src) + +/* Certain mob types have problems and should not be allowed to be controlled by players. + * + * This proc is here to force coders to manually place their mob in this list, hopefully tested. + * This also gives a place to explain -why- players shouldnt be turn into certain mobs and hopefully someone can fix them. + */ +/mob/proc/safe_animal(var/MP) + +//Bad mobs! - Remember to add a comment explaining what's wrong with the mob + if(!MP) + return 0 //Sanity, this should never happen. + + if(ispath(MP, /mob/living/simple_animal/space_worm)) + return 0 //Unfinished. Very buggy, they seem to just spawn additional space worms everywhere and eating your own tail results in new worms spawning. + + if(ispath(MP, /mob/living/simple_animal/construct/behemoth)) + return 0 //I think this may have been an unfinished WiP or something. These constructs should really have their own class simple_animal/construct/subtype + + if(ispath(MP, /mob/living/simple_animal/construct/armoured)) + return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype + + if(ispath(MP, /mob/living/simple_animal/construct/wraith)) + return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype + + if(ispath(MP, /mob/living/simple_animal/construct/builder)) + return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype + +//Good mobs! + if(ispath(MP, /mob/living/simple_animal/cat)) + return 1 + if(ispath(MP, /mob/living/simple_animal/corgi)) + return 1 + if(ispath(MP, /mob/living/simple_animal/crab)) + return 1 + if(ispath(MP, /mob/living/simple_animal/hostile/carp)) + return 1 + if(ispath(MP, /mob/living/simple_animal/mushroom)) + return 1 + if(ispath(MP, /mob/living/simple_animal/shade)) + return 1 + if(ispath(MP, /mob/living/simple_animal/tomato)) + return 1 + if(ispath(MP, /mob/living/simple_animal/mouse)) + return 1 //It is impossible to pull up the player panel for mice (Fixed! - Nodrak) + if(ispath(MP, /mob/living/simple_animal/hostile/bear)) + return 1 //Bears will auto-attack mobs, even if they're player controlled (Fixed! - Nodrak) + if(ispath(MP, /mob/living/simple_animal/parrot)) + return 1 //Parrots are no longer unfinished! -Nodrak + + //Not in here? Must be untested! + return 0 + + +//This is barely a transformation but probably best file for it. +/mob/living/carbon/human/proc/zombieze() + ChangeToHusk() + mutations |= CLUMSY //cause zombie + src.visible_message("\The [src]'s flesh decays before your very eyes!", "Your entire body is ripe with pain as it is consumed down to flesh and bones. You... hunger. Not only for flesh, but to spread your disease.") + if(src.mind) + src.mind.special_role = "Zombie" + log_admin("[key_name(src)] has transformed into a zombie!") + Weaken(5) + if(should_have_organ(BP_HEART)) + vessel.add_reagent(/datum/reagent/blood,species.blood_volume-vessel.total_volume) + for(var/o in organs) + var/obj/item/organ/organ = o + organ.vital = 0 + organ.rejuvenate(1) + organ.max_damage *= 5 + organ.min_broken_damage *= 5 + verbs += /mob/living/proc/breath_death + verbs += /mob/living/proc/consume \ No newline at end of file diff --git a/code/modules/mob/typing_indicator.dm b/code/modules/mob/typing_indicator.dm new file mode 100644 index 00000000..f3477c34 --- /dev/null +++ b/code/modules/mob/typing_indicator.dm @@ -0,0 +1,67 @@ +/*Typing indicators, when a mob uses the F3/F4 keys to bring the say/emote input boxes up this little buddy is +made and follows them around until they are done (or something bad happens), helps tell nearby people that 'hey! +I IS TYPIN'!' +*/ + +/mob + var/atom/movable/overlay/typing_indicator/typing_indicator = null + +/atom/movable/overlay/typing_indicator + icon = 'icons/mob/talk.dmi' + icon_state = "typing" + mouse_opacity = 0 // This should stop people from being able to break the cooldown system, as it will no longer be clickable. + +/atom/movable/overlay/typing_indicator/New(var/newloc, var/mob/master) + ..(newloc) + if(master.typing_indicator) + qdel(master.typing_indicator) + + master.typing_indicator = src + src.master = master + name = master.name + + GLOB.moved_event.register(master, src, /atom/movable/proc/move_to_turf_or_null) + + GLOB.stat_set_event.register(master, src, /datum/proc/qdel_self) // Making the assumption master is conscious at creation + GLOB.logged_out_event.register(master, src, /datum/proc/qdel_self) + GLOB.destroyed_event.register(master, src, /datum/proc/qdel_self) + +/atom/movable/overlay/typing_indicator/Destroy() + var/mob/M = master + + GLOB.moved_event.unregister(master, src) + GLOB.stat_set_event.unregister(master, src) + GLOB.logged_out_event.unregister(master, src) + GLOB.destroyed_event.unregister(master, src) + + M.typing_indicator = null + master = null + + . = ..() + +/mob/proc/create_typing_indicator() + if(client && !stat && get_preference_value(/datum/client_preference/show_typing_indicator) == GLOB.PREF_SHOW) + new/atom/movable/overlay/typing_indicator(get_turf(src), src) + +/mob/proc/remove_typing_indicator() // A bit excessive, but goes with the creation of the indicator I suppose + QDEL_NULL(typing_indicator) + +/mob/verb/say_wrapper() + set name = ".Say" + set hidden = 1 + + create_typing_indicator() + var/message = input("","say (text)") as text + remove_typing_indicator() + if(message) + say_verb(message) + +/mob/verb/me_wrapper() + set name = ".Me" + set hidden = 1 + + create_typing_indicator() + var/message = input("","me (text)") as text + remove_typing_indicator() + if(message) + me_verb(message) diff --git a/code/modules/mob/update_icons.dm b/code/modules/mob/update_icons.dm new file mode 100644 index 00000000..dd3c13b8 --- /dev/null +++ b/code/modules/mob/update_icons.dm @@ -0,0 +1,67 @@ +//Most of these are defined at this level to reduce on checks elsewhere in the code. +//Having them here also makes for a nice reference list of the various overlay-updating procs available + +/mob/proc/regenerate_icons() //TODO: phase this out completely if possible + return + +/mob/proc/update_icons() + return + +/mob/proc/update_hud() + return + +/mob/proc/update_inv_handcuffed() + return + +/mob/proc/update_inv_back() + return + +/mob/proc/update_inv_l_hand() + return + +/mob/proc/update_inv_r_hand() + return + +/mob/proc/update_inv_wear_mask() + return + +/mob/proc/update_inv_wear_suit() + return + +/mob/proc/update_inv_w_uniform() + return + +/mob/proc/update_inv_belt() + return + +/mob/proc/update_inv_head() + return + +/mob/proc/update_inv_gloves() + return + +/mob/proc/update_mutations() + return + +/mob/proc/update_inv_wear_id() + return + +/mob/proc/update_inv_shoes() + return + +/mob/proc/update_inv_glasses() + return + +/mob/proc/update_inv_s_store() + return + +/mob/proc/update_inv_pockets() + return + +/mob/proc/update_inv_ears() + return + +/mob/proc/update_targeted() + return +/mob/proc/update_inv_neck() + return diff --git a/code/modules/modular_computers/NTNet/NTNRC/conversation.dm b/code/modules/modular_computers/NTNet/NTNRC/conversation.dm new file mode 100644 index 00000000..28173c09 --- /dev/null +++ b/code/modules/modular_computers/NTNet/NTNRC/conversation.dm @@ -0,0 +1,65 @@ +var/global/ntnrc_uid = 0 + +/datum/ntnet_conversation/ + var/id = null + var/title = "Untitled Conversation" + var/datum/computer_file/program/chatclient/operator // "Administrator" of this channel. Creator starts as channel's operator, + var/list/messages = list() + var/list/clients = list() + var/password + +/datum/ntnet_conversation/New() + id = ntnrc_uid + ntnrc_uid++ + if(ntnet_global) + ntnet_global.chat_channels.Add(src) + ..() + +/datum/ntnet_conversation/proc/add_message(var/message, var/username) + message = "[stationtime2text()] [username]: [message]" + messages.Add(message) + trim_message_list() + +/datum/ntnet_conversation/proc/add_status_message(var/message) + messages.Add("[stationtime2text()] -!- [message]") + trim_message_list() + +/datum/ntnet_conversation/proc/trim_message_list() + if(messages.len <= 50) + return + messages.Cut(1, (messages.len-49)) + +/datum/ntnet_conversation/proc/add_client(var/datum/computer_file/program/chatclient/C) + if(!istype(C)) + return + clients.Add(C) + add_status_message("[C.username] has joined the channel.") + // No operator, so we assume the channel was empty. Assign this user as operator. + if(!operator) + changeop(C) + +/datum/ntnet_conversation/proc/remove_client(var/datum/computer_file/program/chatclient/C) + if(!istype(C) || !(C in clients)) + return + clients.Remove(C) + add_status_message("[C.username] has left the channel.") + + // Channel operator left, pick new operator + if(C == operator) + operator = null + if(clients.len) + var/datum/computer_file/program/chatclient/newop = pick(clients) + changeop(newop) + + +/datum/ntnet_conversation/proc/changeop(var/datum/computer_file/program/chatclient/newop) + if(istype(newop)) + operator = newop + add_status_message("Channel operator status transferred to [newop.username].") + +/datum/ntnet_conversation/proc/change_title(var/newtitle, var/datum/computer_file/program/chatclient/client) + if(operator != client) + return 0 // Not Authorised + + add_status_message("[client.username] has changed channel title from [title] to [newtitle]") + title = newtitle \ No newline at end of file diff --git a/code/modules/modular_computers/NTNet/NTNet.dm b/code/modules/modular_computers/NTNet/NTNet.dm new file mode 100644 index 00000000..dd12b25b --- /dev/null +++ b/code/modules/modular_computers/NTNet/NTNet.dm @@ -0,0 +1,184 @@ +var/global/datum/ntnet/ntnet_global = new() + + +// This is the NTNet datum. There can be only one NTNet datum in game at once. Modular computers read data from this. +/datum/ntnet/ + var/list/relays = list() + var/list/logs = list() + var/list/available_station_software = list() + var/list/available_antag_software = list() + var/list/available_news = list() + var/list/chat_channels = list() + var/list/fileservers = list() + var/list/email_accounts = list() // I guess we won't have more than 999 email accounts active at once in single round, so this will do until Servers are implemented someday. + var/list/banned_nids = list() + // Amount of logs the system tries to keep in memory. Keep below 999 to prevent byond from acting weirdly. + // High values make displaying logs much laggier. + var/setting_maxlogcount = 100 + + // These only affect wireless. LAN (consoles) are unaffected since it would be possible to create scenario where someone turns off NTNet, and is unable to turn it back on since it refuses connections + var/setting_softwaredownload = 1 + var/setting_peertopeer = 1 + var/setting_communication = 1 + var/setting_systemcontrol = 1 + var/setting_disabled = 0 // Setting to 1 will disable all wireless, independently on relays status. + + var/intrusion_detection_enabled = 1 // Whether the IDS warning system is enabled + var/intrusion_detection_alarm = 0 // Set when there is an IDS warning due to malicious (antag) software. + + +// If new NTNet datum is spawned, it replaces the old one. +/datum/ntnet/New() + if(ntnet_global && (ntnet_global != src)) + ntnet_global = src // There can be only one. + for(var/obj/machinery/ntnet_relay/R in SSmachines.machinery) + relays.Add(R) + R.NTNet = src + build_software_lists() + //build_news_list()//News is fucking stupid but I guess if you want to include it again... + build_emails_list() + add_log("NTNet logging system activated.") + +/datum/ntnet/proc/add_log_with_ids_check(var/log_string, var/obj/item/weapon/computer_hardware/network_card/source = null) + if(intrusion_detection_enabled) + add_log(log_string, source) + +// Simplified logging: Adds a log. log_string is mandatory parameter, source is optional. +/datum/ntnet/proc/add_log(var/log_string, var/obj/item/weapon/computer_hardware/network_card/source = null) + var/log_text = "[stationtime2text()] - " + if(source) + log_text += "[source.get_network_tag()] - " + else + log_text += "*SYSTEM* - " + log_text += log_string + logs.Add(log_text) + + if(logs.len > setting_maxlogcount) + // We have too many logs, remove the oldest entries until we get into the limit + for(var/L in logs) + if(logs.len > setting_maxlogcount) + logs.Remove(L) + else + break + +/datum/ntnet/proc/check_banned(var/NID) + if(!relays || !relays.len) + return FALSE + + for(var/obj/machinery/ntnet_relay/R in relays) + if(R.operable()) + return (NID in banned_nids) + + return FALSE + +// Checks whether NTNet operates. If parameter is passed checks whether specific function is enabled. +/datum/ntnet/proc/check_function(var/specific_action = 0) + if(!relays || !relays.len) // No relays found. NTNet is down + return 0 + + var/operating = 0 + + // Check all relays. If we have at least one working relay, network is up. + for(var/obj/machinery/ntnet_relay/R in relays) + if(R.operable()) + operating = 1 + break + + if(setting_disabled) + return 0 + + if(specific_action == NTNET_SOFTWAREDOWNLOAD) + return (operating && setting_softwaredownload) + if(specific_action == NTNET_PEERTOPEER) + return (operating && setting_peertopeer) + if(specific_action == NTNET_COMMUNICATION) + return (operating && setting_communication) + if(specific_action == NTNET_SYSTEMCONTROL) + return (operating && setting_systemcontrol) + return operating + +// Builds lists that contain downloadable software. +/datum/ntnet/proc/build_software_lists() + available_station_software = list() + available_antag_software = list() + for(var/F in typesof(/datum/computer_file/program)) + var/datum/computer_file/program/prog = new F + // Invalid type (shouldn't be possible but just in case), invalid filetype (not executable program) or invalid filename (unset program) + if(!prog || !istype(prog) || prog.filename == "UnknownProgram" || prog.filetype != "PRG") + continue + // Check whether the program should be available for station/antag download, if yes, add it to lists. + if(prog.available_on_ntnet) + available_station_software.Add(prog) + if(prog.available_on_syndinet) + available_antag_software.Add(prog) + +// Builds lists that contain downloadable software. +/datum/ntnet/proc/build_news_list() + available_news = list() + for(var/F in typesof(/datum/computer_file/data/news_article/)) + var/datum/computer_file/data/news_article/news = new F(1) + if(news.stored_data) + available_news.Add(news) + +// Generates service email list. Currently only used by broadcaster service +/datum/ntnet/proc/build_emails_list() + for(var/F in subtypesof(/datum/computer_file/data/email_account/service)) + new F() + +// Attempts to find a downloadable file according to filename var +/datum/ntnet/proc/find_ntnet_file_by_name(var/filename) + for(var/datum/computer_file/program/P in available_station_software) + if(filename == P.filename) + return P + for(var/datum/computer_file/program/P in available_antag_software) + if(filename == P.filename) + return P + +// Resets the IDS alarm +/datum/ntnet/proc/resetIDS() + intrusion_detection_alarm = 0 + +/datum/ntnet/proc/toggleIDS() + resetIDS() + intrusion_detection_enabled = !intrusion_detection_enabled + +// Removes all logs +/datum/ntnet/proc/purge_logs() + logs = list() + add_log("-!- LOGS DELETED BY SYSTEM OPERATOR -!-") + +// Updates maximal amount of stored logs. Use this instead of setting the number, it performs required checks. +/datum/ntnet/proc/update_max_log_count(var/lognumber) + if(!lognumber) + return 0 + // Trim the value if necessary + lognumber = between(MIN_NTNET_LOGS, lognumber, MAX_NTNET_LOGS) + setting_maxlogcount = lognumber + add_log("Configuration Updated. Now keeping [setting_maxlogcount] logs in system memory.") + +/datum/ntnet/proc/toggle_function(var/function) + if(!function) + return + function = text2num(function) + switch(function) + if(NTNET_SOFTWAREDOWNLOAD) + setting_softwaredownload = !setting_softwaredownload + add_log("Configuration Updated. Wireless network firewall now [setting_softwaredownload ? "allows" : "disallows"] connection to software repositories.") + if(NTNET_PEERTOPEER) + setting_peertopeer = !setting_peertopeer + add_log("Configuration Updated. Wireless network firewall now [setting_peertopeer ? "allows" : "disallows"] peer to peer network traffic.") + if(NTNET_COMMUNICATION) + setting_communication = !setting_communication + add_log("Configuration Updated. Wireless network firewall now [setting_communication ? "allows" : "disallows"] instant messaging and similar communication services.") + if(NTNET_SYSTEMCONTROL) + setting_systemcontrol = !setting_systemcontrol + add_log("Configuration Updated. Wireless network firewall now [setting_systemcontrol ? "allows" : "disallows"] remote control of [station_name()]'s systems.") + +/datum/ntnet/proc/does_email_exist(var/login) + for(var/datum/computer_file/data/email_account/A in ntnet_global.email_accounts) + if(A.login == login) + return 1 + return 0 + + + diff --git a/code/modules/modular_computers/NTNet/NTNet_relay.dm b/code/modules/modular_computers/NTNet/NTNet_relay.dm new file mode 100644 index 00000000..79a2a2ce --- /dev/null +++ b/code/modules/modular_computers/NTNet/NTNet_relay.dm @@ -0,0 +1,136 @@ +// Relays don't handle any actual communication. Global NTNet datum does that, relays only tell the datum if it should or shouldn't work. +/obj/machinery/ntnet_relay + name = "NTNet Quantum Relay" + desc = "A very complex router and transmitter capable of connecting electronic devices together. Looks fragile." + use_power = 2 + active_power_usage = 20000 //20kW, apropriate for machine that keeps massive cross-Zlevel wireless network operational. + idle_power_usage = 100 + icon_state = "bus" + anchored = 1 + density = 1 + var/datum/ntnet/NTNet = null // This is mostly for backwards reference and to allow varedit modifications from ingame. + var/enabled = 1 // Set to 0 if the relay was turned off + var/dos_failure = 0 // Set to 1 if the relay failed due to (D)DoS attack + var/list/dos_sources = list() // Backwards reference for qdel() stuff + + // Denial of Service attack variables + var/dos_overload = 0 // Amount of DoS "packets" in this relay's buffer + var/dos_capacity = 500 // Amount of DoS "packets" in buffer required to crash the relay + var/dos_dissipate = 1 // Amount of DoS "packets" dissipated over time. + + +// TODO: Implement more logic here. For now it's only a placeholder. +/obj/machinery/ntnet_relay/operable() + if(!..(EMPED)) + return 0 + if(dos_failure) + return 0 + if(!enabled) + return 0 + return 1 + +/obj/machinery/ntnet_relay/update_icon() + if(operable()) + icon_state = "bus" + else + icon_state = "bus_off" + +/obj/machinery/ntnet_relay/Process() + if(operable()) + use_power = 2 + else + use_power = 1 + + if(dos_overload) + dos_overload = max(0, dos_overload - dos_dissipate) + + // If DoS traffic exceeded capacity, crash. + if((dos_overload > dos_capacity) && !dos_failure) + dos_failure = 1 + update_icon() + ntnet_global.add_log("Quantum relay switched from normal operation mode to overload recovery mode.") + // If the DoS buffer reaches 0 again, restart. + if((dos_overload == 0) && dos_failure) + dos_failure = 0 + update_icon() + ntnet_global.add_log("Quantum relay switched from overload recovery mode to normal operation mode.") + ..() + +/obj/machinery/ntnet_relay/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = list() + data["enabled"] = enabled + data["dos_capacity"] = dos_capacity + data["dos_overload"] = dos_overload + data["dos_crashed"] = dos_failure + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "ntnet_relay.tmpl", "NTNet Quantum Relay", 500, 300, state = state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/ntnet_relay/attack_hand(var/mob/living/user) + ui_interact(user) + +/obj/machinery/ntnet_relay/Topic(href, href_list) + if(..()) + return 1 + if(href_list["restart"]) + dos_overload = 0 + dos_failure = 0 + update_icon() + ntnet_global.add_log("Quantum relay manually restarted from overload recovery mode to normal operation mode.") + return 1 + else if(href_list["toggle"]) + enabled = !enabled + ntnet_global.add_log("Quantum relay manually [enabled ? "enabled" : "disabled"].") + update_icon() + return 1 + else if(href_list["purge"]) + ntnet_global.banned_nids.Cut() + ntnet_global.add_log("Manual override: Network blacklist cleared.") + return 1 + +/obj/machinery/ntnet_relay/New() + uid = gl_uid + gl_uid++ + component_parts = list() + component_parts += new /obj/item/stack/cable_coil(src,15) + component_parts += new /obj/item/weapon/circuitboard/ntnet_relay(src) + + if(ntnet_global) + ntnet_global.relays.Add(src) + NTNet = ntnet_global + ntnet_global.add_log("New quantum relay activated. Current amount of linked relays: [NTNet.relays.len]") + ..() + +/obj/machinery/ntnet_relay/Destroy() + if(ntnet_global) + ntnet_global.relays.Remove(src) + ntnet_global.add_log("Quantum relay connection severed. Current amount of linked relays: [NTNet.relays.len]") + NTNet = null + for(var/datum/computer_file/program/ntnet_dos/D in dos_sources) + D.target = null + D.error = "Connection to quantum relay severed" + ..() + +/obj/machinery/ntnet_relay/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(isScrewdriver(W)) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + panel_open = !panel_open + to_chat(user, "You [panel_open ? "open" : "close"] the maintenance hatch") + return + if(isCrowbar(W)) + if(!panel_open) + to_chat(user, "Open the maintenance panel first.") + return + playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) + to_chat(user, "You disassemble \the [src]!") + + for(var/atom/movable/A in component_parts) + A.forceMove(src.loc) + new/obj/machinery/constructable_frame/machine_frame(src.loc) + qdel(src) + return + ..() \ No newline at end of file diff --git a/code/modules/modular_computers/NTNet/emails/email_account.dm b/code/modules/modular_computers/NTNet/emails/email_account.dm new file mode 100644 index 00000000..b5f93887 --- /dev/null +++ b/code/modules/modular_computers/NTNet/emails/email_account.dm @@ -0,0 +1,82 @@ +/datum/computer_file/data/email_account/ + var/list/inbox = list() + var/list/spam = list() + var/list/deleted = list() + + var/login = "" + var/password = "" + var/can_login = TRUE // Whether you can log in with this account. Set to false for system accounts + var/suspended = FALSE // Whether the account is banned by the SA. + +/datum/computer_file/data/email_account/calculate_size() + size = 1 + for(var/datum/computer_file/data/email_message/stored_message in all_emails()) + stored_message.calculate_size() + size += stored_message.size + +/datum/computer_file/data/email_account/New() + ntnet_global.email_accounts.Add(src) + ..() + +/datum/computer_file/data/email_account/Destroy() + ntnet_global.email_accounts.Remove(src) + . = ..() + +/datum/computer_file/data/email_account/proc/all_emails() + return (inbox | spam | deleted) + +/datum/computer_file/data/email_account/proc/send_mail(var/recipient_address, var/datum/computer_file/data/email_message/message, var/relayed = 0) + var/datum/computer_file/data/email_account/recipient + for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts) + if(account.login == recipient_address) + recipient = account + break + + if(!istype(recipient)) + return 0 + + if(!recipient.receive_mail(message, relayed)) + return + + ntnet_global.add_log_with_ids_check("EMAIL LOG: [login] -> [recipient.login] title: [message.title].") + return 1 + +/datum/computer_file/data/email_account/proc/receive_mail(var/datum/computer_file/data/email_message/received_message, var/relayed) + received_message.set_timestamp() + if(!ntnet_global.intrusion_detection_enabled) + inbox.Add(received_message) + return 1 + // Spam filters may occassionally let something through, or mark something as spam that isn't spam. + if(received_message.spam) + if(prob(98)) + spam.Add(received_message) + else + inbox.Add(received_message) + else + if(prob(1)) + spam.Add(received_message) + else + inbox.Add(received_message) + return 1 + +// Address namespace (@internal-services.nt) for email addresses with special purpose only!. +/datum/computer_file/data/email_account/service/ + can_login = FALSE + +/datum/computer_file/data/email_account/service/broadcaster/ + login = "broadcast@internal-services.nt" + +/datum/computer_file/data/email_account/service/broadcaster/receive_mail(var/datum/computer_file/data/email_message/received_message, var/relayed) + if(!istype(received_message) || relayed) + return 0 + // Possibly exploitable for user spamming so keep admins informed. + if(!received_message.spam) + log_and_message_admins("Broadcast email address used by [usr]. Message title: [received_message.title].") + + spawn(0) + for(var/datum/computer_file/data/email_account/email_account in ntnet_global.email_accounts) + var/datum/computer_file/data/email_message/new_message = received_message.clone() + send_mail(email_account.login, new_message, 1) + sleep(2) + + return 1 \ No newline at end of file diff --git a/code/modules/modular_computers/NTNet/emails/email_message.dm b/code/modules/modular_computers/NTNet/emails/email_message.dm new file mode 100644 index 00000000..d499195d --- /dev/null +++ b/code/modules/modular_computers/NTNet/emails/email_message.dm @@ -0,0 +1,32 @@ +// Currently not actually represented in file systems, though the support for it is in place already. +/datum/computer_file/data/email_message/ + stored_data = "" + var/title = "" + var/source = "" + var/spam = FALSE + var/timestamp = "" + var/datum/computer_file/attachment = null + +/datum/computer_file/data/email_message/clone() + var/datum/computer_file/data/email_message/temp = ..() + temp.title = title + temp.source = source + temp.spam = spam + temp.timestamp = timestamp + if(attachment) + temp.attachment = attachment.clone() + return temp + + +// Turns /email_message/ file into regular /data/ file. +/datum/computer_file/data/email_message/proc/export() + var/datum/computer_file/data/dat = new/datum/computer_file/data() + dat.stored_data = "Received from [source] at [timestamp]." + dat.stored_data += "\[b\][title]\[/b\]" + dat.stored_data += stored_data + dat.calculate_size() + return dat + +/datum/computer_file/data/email_message/proc/set_timestamp() + timestamp = stationtime2text() + diff --git a/code/modules/modular_computers/_description.dm b/code/modules/modular_computers/_description.dm new file mode 100644 index 00000000..2335ce08 --- /dev/null +++ b/code/modules/modular_computers/_description.dm @@ -0,0 +1,121 @@ +/* +Program-based computers, designed to replace computer3 project and eventually most consoles on station + + +1. Basic information +Program based computers will allow you to do multiple things from single computer. Each computer will have programs, with more being downloadable from NTNet (stationwide network with wireless coverage) +if user has apropriate ID card access. It will be possible to hack the computer by using an emag on it - the emag will have to be completely new and will be consumed on use, but it will +lift ALL locks on ALL installed programs, and allow download of programs even if your ID doesn't have access to them. Computers will have hard drives that can store files. +Files can be programs (datum/computer_file/program/ subtype) or data files (datum/computer_file/data/ subtypes). Program for sending files will be available that will allow transfer via NTNet. +NTNet coverage will be limited to station's Z level, but better network card (=more expensive and higher power use) will allow usage everywhere. Hard drives will have limited capacity for files +which will be related to how good hard drive you buy when purchasing the laptop. For storing more files USB-style drives will be buildable with Protolathe in research. + +2. Available devices +CONSOLES +Consoles will come in various pre-fabricated loadouts, each loadout starting with certain set of programs (aka Engineering console, Medical console, etc.), of course, more software may be downloaded. +Consoles won't usually have integrated battery, but the possibility to install one will exist for critical applications. Consoles are considered hardwired into NTNet network which means they +will have working coverage on higher speed (Ethernet is faster than Wi-Fi) and won't require wireless coverage to exist. +LAPTOPS +Laptops are middle ground between actual portable devices and full consoles. They offer certain level of mobility, as they can be closed, moved somewhere else and then opened again. +Laptops will by default have internal battery to power them, and may be recharged with rechargers. However, laptops rely on wireless NTNet coverage. Laptop HDDs are also designed with power efficiency +in mind, which means they sacrifice some storage space for higher battery life. Laptops may be dispensed from computer vendor machine, and may be customised before vending. For people which don't +want to rely on internal battery, tesla link exists that connects to APC, if one exists. +TABLETS +Tablets are smallest available devices, designed with full mobility in mind. Tablets have only weak CPU which means the software they can run is somewhat limited. They are also designed with high +battery life in mind, which means the hardware focuses on power efficiency rather than high performance. This is most visible with hard drives which have quite small storage capacity. +Tablets can't be equipped with tesla link, which means they have to be recharged manually. + + +3. Computer Hardware +Computers will come with basic hardware installed, with upgrades being selectable when purchasing the device. +Hard Drive: Stores data, mandatory for the computer to work +Network Card: Connects to NTNet +Battery: Internal power source that ensures the computer operates when not connected to APC. +Extras (those won't be installed by default, but can be bought) +ID Card Slot: Required for HoP-style programs to work. Access for security record-style programs is read from ID of user [RFID?] without requiring this +APC Tesla Relay: Wirelessly powers the device from APC. Consoles have it by default. Laptops can buy it. +Disk Drive: Allows usage of portable data disks. +Nano Printer: Allows the computer to scan paper contents and save them to file, as well as recycle papers and print stuff on it. + +4. NTNet +NTNet is stationwide network that allows users to download programs needed for their work. It will be possible to send any files to other active computers using relevant program (NTN Transfer). +NTNet is under jurisdiction of both Engineering and Research. Engineering is responsible for any repairs if necessary and research is responsible for monitoring. It is similar to PDA messaging. +Operation requires functional "NTNet Relay" which is by default placed on tcommsat. If the relay is damaged NTNet will be offline until it is replaced. Multiple relays bring extra redundancy, +if one is destroyed the second will take over. If all relays are gone it stops working, simple as that. NTNet may be altered via administration console available to Research Director. It is +possible to enable/disable Software Downloading, P2P file transfers and Communication (IC version of IRC, PDA messages for more than two people) + +5. Software +Software would almost exclusively use NanoUI modules. Few exceptions are text editor (uses similar screen as TCS IDE used for editing and classic HTML for previewing as Nano looks differently) +and similar programs which for some reason require HTML UI. Most software will be highly dependent on NTNet to work as laptops are not physically connected to the station's network. +What i plan to add: + +Note: XXXXDB programs will use ingame_manuals to display basic help for players, similar to how books, etc. do + +Basic - Software in this bundle is automagically preinstalled in every new computer + NTN Transfer - Allows P2P transfer of files to other computers that run this. + Configurator - Allows configuration of computer's hardware, basically status screen. + File Browser - Allows you to browse all files stored on the computer. Allows renaming/deleting of files. + TXT Editor - Allows you editing data files in text editor mode. + NanoPrint - Allows you to operate NanoPrinter hardware to print text files. + NTNRC Chat - NTNet Relay Chat client. Allows PDA-messaging style messaging for more than two users. Person which created the conversation is Host and has administrative privilegies (kicking, etc.) + NTNet News - Allows reading news from newscaster network. + +Engineering - Requires "Engineering" access on ID card (ie. CE, Atmostech, Engineer) + Alarm Monitor - Allows monitoring alarms, same as the stationbound one. + Power Monitor - Power monitoring computer, connects to sensors in same way as regular one does. + Atmospheric Control - Allows access to the Atmospherics Monitor Console that operates air alarms. Requires extra access: "Atmospherics" + RCON Remote Control Console - Allows access to the RCON Remote Control Console. Requires extra access: "Power Equipment" + EngiDB - Allows accessing NTNet information repository for information about engineering-related things. + +Medical - Requires "Medbay" access on ID card (ie. CMO, Doctor,..) + Medical Records Uplink - Allows editing/reading of medical records. Printing requires NanoPrinter hardware. + MediDB - Allows accessing NTNet information repository for information about medical procedures + ChemDB - Requires extra access: "Chemistry" - Downloads basic information about recipes from NTNet + +Research - Requires "Research and Development" access on ID card (ie. RD, Roboticist, etc.) + Research Server Monitor - Allows monitoring of research levels on RnD servers. (read only) + Robotics Monitor Console - Allows monitoring of robots and exosuits. Lockdown/Self-Destruct options are unavailable [balance reasons for malf/traitor AIs]. Requires extra access: "Robotics" + NTNRC Administration Console - Allows administrative access to NTNRC. This includes bypassing any channel passwords and enabling "invisible" mode for spying on conversations. Requires extra access: "Research Director" + NTNet Administration Console - Allows remote configuration of NTNet Relay - CAUTION: If NTNet is turned off it won't be possible to turn it on again from the computer, as operation requires NTNet to work! Requires extra access: "Research Director" + NTNet Monitor - Allows monitoring of NTNet and it's various components, including simplified network logs and system status. + +Security - Requires "Security" access on ID card (ie. HOS, Security officer, Detective) + Security Records Uplink - Allows editing/reading of security records. Printing requires Nanoprinter hardware. + LawDB - Allows accessing NTNet information repository for security information (corporate regulations) + Camera Uplink - Allows viewing cameras around the station. + +Command - Requires "Bridge" access on ID card (all heads) + Alertcon Access - Allows changing of alert levels. Red requires activation from two computers with two IDs similar to how those wall mounted devices do. + Employment Records Access - Allows reading of employment records. Printing requires NanoPrinter hardware. + Communication Console - Allows sending emergency messages to Central. + Emergency Shuttle Control Console - Allows calling/recalling the emergency shuttle. + Shuttle Control Console - Allows control of various shuttles around the station (mining, research, engineering) + +*REDACTED* - Can be downloaded from SyndiCorp servers, only via emagged devices. These files are very large and limited to laptops/consoles only. + SYSCRACK - Allows cracking of secure network terminals, such as, NTNet administration. The sysadmin will probably notice this. + SYSOVERRIDE - Allows hacking into any device connected to NTNet. User will notice this and may stop the hack by disconnecting from NTNet first. After hacking various options exist, such as stealing/deleting files. + SYSKILL - Tricks NTNet to force-disconnect a device. The sysadmin will probably notice this. + SYSDOS - Launches a Denial of Service attack on NTNet relay. Can DoS only one relay at once. Requires NTNet connection. After some time the relay crashes until attack stops. The sysadmin will probably notice this. + AIHACK - Hacks an AI, allowing you to upload/remove/modify a law even without relevant circuit board. The AI is alerted once the hack starts, and it takes a while for it to complete. Does not work on AIs with zeroth law. + COREPURGE - Deletes all files on the hard drive, including the undeletable ones. Something like software self-destruct for computer. + +6. Security +Laptops will be password-lockable. If password is set a MD5 hash of it is stored and password is required every time you turn on the laptop. +Passwords may be decrypted by using special Decrypter (protolathable, RDs office starts with one) device that will slowly decrypt the password. +Decryption time would be length_of_password * 30 seconds, with maximum being 9 minutes (due to battery life limitations, which is 10+ min). +If decrypted the password is cleared, so you can keep using your favorite password without people ever actually revealing it (for meta prevention reasons mostly). +Emagged laptops will have option to enable "Safe Encryption". If safely encrypted laptop is decrypted it loses it's emag status and 50% of files is deleted (randomly selected). + +7. System Administrator +System Administrator will be new job under Research. It's main specifics will be maintaining of computer systems on station, espicially from software side. +From IC perspective they'd probably know how to build a console or something given they work with computers, but they are mostly programmers/network experts. +They will have office in research, which will probably replace (and contain) the server room and part of the toxins storage which is currently oversized. +They will have access to DOWNLOAD (not run) all programs that exist on NTNet. They'll have fairly good amount of available programs, most of them being +administrative consoles and other very useful things. They'll also be able to monitor NTNet. There will probably be one or two job slots. + +8. IDS +With addition of various antag programs, IDS(Intrusion Detection System) will be added to NTNet. This system can be turned on/off via administration console. +If enabled, this system automatically detects any abnormality and triggers a warning that's visible on the NTNet status screen, as well as generating a security log. +IDS can be disabled by simple on/off switch in the configuration. + +*/ \ No newline at end of file diff --git a/code/modules/modular_computers/computers/modular_computer/core.dm b/code/modules/modular_computers/computers/modular_computer/core.dm new file mode 100644 index 00000000..dd5b368e --- /dev/null +++ b/code/modules/modular_computers/computers/modular_computer/core.dm @@ -0,0 +1,283 @@ +/obj/item/modular_computer/Process() + if(!enabled) // The computer is turned off + last_power_usage = 0 + return 0 + + if(damage > broken_damage) + shutdown_computer() + return 0 + + if(active_program && active_program.requires_ntnet && !get_ntnet_status(active_program.requires_ntnet_feature)) // Active program requires NTNet to run but we've just lost connection. Crash. + active_program.event_networkfailure(0) + + for(var/datum/computer_file/program/P in idle_threads) + if(P.requires_ntnet && !get_ntnet_status(P.requires_ntnet_feature)) + P.event_networkfailure(1) + + if(active_program) + if(active_program.program_state != PROGRAM_STATE_KILLED) + active_program.ntnet_status = get_ntnet_status() + active_program.computer_emagged = computer_emagged + active_program.process_tick() + else + active_program = null + + for(var/datum/computer_file/program/P in idle_threads) + if(P.program_state != PROGRAM_STATE_KILLED) + P.ntnet_status = get_ntnet_status() + P.computer_emagged = computer_emagged + P.process_tick() + else + idle_threads.Remove(P) + + handle_power() // Handles all computer power interaction + check_update_ui_need() + + var/static/list/beepsounds = list('sound/effects/compbeep1.ogg','sound/effects/compbeep2.ogg','sound/effects/compbeep3.ogg','sound/effects/compbeep4.ogg','sound/effects/compbeep5.ogg') + if(enabled && world.time > ambience_last_played + 60 SECONDS && prob(1)) + ambience_last_played = world.time + playsound(src.loc, pick(beepsounds),15,1,10, is_ambiance = 1) + +// Used to perform preset-specific hardware changes. +/obj/item/modular_computer/proc/install_default_hardware() + return 1 + +// Used to install preset-specific programs +/obj/item/modular_computer/proc/install_default_programs() + return 1 + +/obj/item/modular_computer/proc/install_default_programs_by_job(var/mob/living/carbon/human/H) + var/datum/job/jb = job_master.occupations_by_title[H.job] + if(!jb) return + for(var/prog_type in jb.software_on_spawn) + var/datum/computer_file/program/prog_file = prog_type + if(initial(prog_file.usage_flags) & hardware_flag) + prog_file = new prog_file + hard_drive.store_file(prog_file) + +/obj/item/modular_computer/New() + START_PROCESSING(SSobj, src) + install_default_hardware() + if(hard_drive) + install_default_programs() + update_icon() + update_verbs() + ..() + +/obj/item/modular_computer/Destroy() + kill_program(1) + STOP_PROCESSING(SSobj, src) + for(var/obj/item/weapon/computer_hardware/CH in src.get_all_components()) + uninstall_component(null, CH) + qdel(CH) + return ..() + +/obj/item/modular_computer/emag_act(var/remaining_charges, var/mob/user) + if(computer_emagged) + to_chat(user, "\The [src] was already emagged.") + return NO_EMAG_ACT + else + computer_emagged = 1 + to_chat(user, "You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message.") + return 1 + +/obj/item/modular_computer/update_icon() + icon_state = icon_state_unpowered + + overlays.Cut() + if(bsod) + overlays.Add("bsod") + return + if(!enabled) + if(icon_state_screensaver) + overlays.Add(icon_state_screensaver) + set_light(0) + return + set_light(light_strength) + if(active_program) + overlays.Add(active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu) + if(active_program.program_key_state) + overlays.Add(active_program.program_key_state) + else + overlays.Add(icon_state_menu) + +/obj/item/modular_computer/proc/turn_on(var/mob/user) + if(bsod) + return + if(tesla_link) + tesla_link.enabled = 1 + var/issynth = issilicon(user) // Robots and AIs get different activation messages. + if(damage > broken_damage) + if(issynth) + to_chat(user, "You send an activation signal to \the [src], but it responds with an error code. It must be damaged.") + else + to_chat(user, "You press the power button, but the computer fails to boot up, displaying variety of errors before shutting down again.") + return + if(processor_unit && (apc_power(0) || battery_power(0))) // Battery-run and charged or non-battery but powered by APC. + if(issynth) + to_chat(user, "You send an activation signal to \the [src], turning it on") + else + to_chat(user, "You press the power button and start up \the [src]") + enable_computer(user) + + else // Unpowered + if(issynth) + to_chat(user, "You send an activation signal to \the [src] but it does not respond") + else + to_chat(user, "You press the power button but \the [src] does not respond") + +// Relays kill program request to currently active program. Use this to quit current program. +/obj/item/modular_computer/proc/kill_program(var/forced = 0) + if(active_program) + active_program.kill_program(forced) + active_program = null + var/mob/user = usr + if(user && istype(user)) + ui_interact(user) // Re-open the UI on this computer. It should show the main screen now. + update_icon() + +// Returns 0 for No Signal, 1 for Low Signal and 2 for Good Signal. 3 is for wired connection (always-on) +/obj/item/modular_computer/proc/get_ntnet_status(var/specific_action = 0) + if(network_card) + return network_card.get_signal(specific_action) + else + return 0 + +/obj/item/modular_computer/proc/add_log(var/text) + if(!get_ntnet_status()) + return 0 + return ntnet_global.add_log(text, network_card) + +/obj/item/modular_computer/proc/shutdown_computer(var/loud = 1) + kill_program(1) + for(var/datum/computer_file/program/P in idle_threads) + P.kill_program(1) + idle_threads.Remove(P) + if(loud) + visible_message("\The [src] shuts down.", range = 1) + enabled = 0 + update_icon() + +/obj/item/modular_computer/proc/enable_computer(var/mob/user = null) + enabled = 1 + update_icon() + + // Autorun feature + var/datum/computer_file/data/autorun = hard_drive ? hard_drive.find_file_by_name("autorun") : null + if(istype(autorun)) + run_program(autorun.stored_data) + + if(user) + ui_interact(user) + +/obj/item/modular_computer/proc/minimize_program(mob/user) + if(!active_program || !processor_unit) + return + + idle_threads.Add(active_program) + active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs + GLOB.nanomanager.close_uis(active_program.NM ? active_program.NM : active_program) + active_program = null + update_icon() + if(istype(user)) + ui_interact(user) // Re-open the UI on this computer. It should show the main screen now. + + +/obj/item/modular_computer/proc/run_program(prog) + var/datum/computer_file/program/P = null + var/mob/user = usr + if(hard_drive) + P = hard_drive.find_file_by_name(prog) + + if(!P || !istype(P)) // Program not found or it's not executable program. + to_chat(user, "\The [src]'s screen shows \"I/O ERROR - Unable to run [prog]\" warning.") + return + + P.computer = src + + if(!P.is_supported_by_hardware(hardware_flag, 1, user)) + return + if(P in idle_threads) + P.program_state = PROGRAM_STATE_ACTIVE + active_program = P + idle_threads.Remove(P) + update_icon() + return + + if(idle_threads.len >= processor_unit.max_idle_programs+1) + to_chat(user, "\The [src] displays a \"Maximal CPU load reached. Unable to run another program.\" error") + return + + if(P.requires_ntnet && !get_ntnet_status(P.requires_ntnet_feature)) // The program requires NTNet connection, but we are not connected to NTNet. + to_chat(user, "\The [src]'s screen shows \"NETWORK ERROR - Unable to connect to NTNet. Please retry. If problem persists contact your system administrator.\" warning.") + return + + if(active_program) + minimize_program(user) + + if(P.run_program(user)) + active_program = P + update_icon() + return 1 + +/obj/item/modular_computer/proc/update_uis() + if(active_program) //Should we update program ui or computer ui? + GLOB.nanomanager.update_uis(active_program) + if(active_program.NM) + GLOB.nanomanager.update_uis(active_program.NM) + else + GLOB.nanomanager.update_uis(src) + +/obj/item/modular_computer/proc/check_update_ui_need() + var/ui_update_needed = 0 + if(battery_module) + var/batery_percent = battery_module.battery.percent() + if(last_battery_percent != batery_percent) //Let's update UI on percent change + ui_update_needed = 1 + last_battery_percent = batery_percent + + if(stationtime2text() != last_world_time) + last_world_time = stationtime2text() + ui_update_needed = 1 + + if(idle_threads.len) + var/list/current_header_icons = list() + for(var/datum/computer_file/program/P in idle_threads) + if(!P.ui_header) + continue + current_header_icons[P.type] = P.ui_header + if(!last_header_icons) + last_header_icons = current_header_icons + + else if(!listequal(last_header_icons, current_header_icons)) + last_header_icons = current_header_icons + ui_update_needed = 1 + else + for(var/x in last_header_icons|current_header_icons) + if(last_header_icons[x]!=current_header_icons[x]) + last_header_icons = current_header_icons + ui_update_needed = 1 + break + + if(ui_update_needed) + update_uis() + +// Used by camera monitor program +/obj/item/modular_computer/check_eye(var/mob/user) + if(active_program) + return active_program.check_eye(user) + else + return ..() + +/obj/item/modular_computer/proc/set_autorun(program) + if(!hard_drive) + return + var/datum/computer_file/data/autorun = hard_drive.find_file_by_name("autorun") + if(!istype(autorun)) + autorun = new/datum/computer_file/data() + autorun.filename = "autorun" + hard_drive.store_file(autorun) + if(autorun.stored_data == program) + autorun.stored_data = null + else + autorun.stored_data = program \ No newline at end of file diff --git a/code/modules/modular_computers/computers/modular_computer/damage.dm b/code/modules/modular_computers/computers/modular_computer/damage.dm new file mode 100644 index 00000000..d62781b9 --- /dev/null +++ b/code/modules/modular_computers/computers/modular_computer/damage.dm @@ -0,0 +1,55 @@ +/obj/item/modular_computer/examine(var/mob/user) + . = ..() + if(damage > broken_damage) + to_chat(user, "It is heavily damaged!") + else if(damage) + to_chat(user, "It is damaged.") + +/obj/item/modular_computer/proc/break_apart() + visible_message("\The [src] breaks apart!") + var/turf/newloc = get_turf(src) + new /obj/item/stack/material/steel(newloc, round(steel_sheet_cost/2)) + for(var/obj/item/weapon/computer_hardware/H in get_all_components()) + uninstall_component(null, H) + H.forceMove(newloc) + if(prob(25)) + H.take_damage(rand(10,30)) + qdel() + +/obj/item/modular_computer/proc/take_damage(var/amount, var/component_probability, var/damage_casing = 1, var/randomize = 1) + if(randomize) + // 75%-125%, rand() works with integers, apparently. + amount *= (rand(75, 125) / 100.0) + amount = round(amount) + if(damage_casing) + damage += amount + damage = between(0, damage, max_damage) + + if(component_probability) + for(var/obj/item/weapon/computer_hardware/H in get_all_components()) + if(prob(component_probability)) + H.take_damage(round(amount / 2)) + + if(damage >= max_damage) + break_apart() + +// Stronger explosions cause serious damage to internal components +// Minor explosions are mostly mitigitated by casing. +/obj/item/modular_computer/ex_act(var/severity) + take_damage(rand(100,200) / severity, 30 / severity) + +// EMPs are similar to explosions, but don't cause physical damage to the casing. Instead they screw up the components +/obj/item/modular_computer/emp_act(var/severity) + take_damage(rand(100,200) / severity, 50 / severity, 0) + +// "Stun" weapons can cause minor damage to components (short-circuits?) +// "Burn" damage is equally strong against internal components and exterior casing +// "Brute" damage mostly damages the casing. +/obj/item/modular_computer/bullet_act(var/obj/item/projectile/Proj) + switch(Proj.damage_type) + if(BRUTE) + take_damage(Proj.damage, Proj.damage / 2) + if(PAIN) + take_damage(Proj.damage, Proj.damage / 3, 0) + if(BURN) + take_damage(Proj.damage, Proj.damage / 1.5) \ No newline at end of file diff --git a/code/modules/modular_computers/computers/modular_computer/hardware.dm b/code/modules/modular_computers/computers/modular_computer/hardware.dm new file mode 100644 index 00000000..2c7cdf8f --- /dev/null +++ b/code/modules/modular_computers/computers/modular_computer/hardware.dm @@ -0,0 +1,152 @@ +// Attempts to install the hardware into apropriate slot. +/obj/item/modular_computer/proc/try_install_component(var/mob/living/user, var/obj/item/weapon/computer_hardware/H, var/found = 0) + // "USB" flash drive. + if(istype(H, /obj/item/weapon/computer_hardware/hard_drive/portable)) + if(portable_drive) + to_chat(user, "This computer's portable drive slot is already occupied by \the [portable_drive].") + return + found = 1 + portable_drive = H + else if(istype(H, /obj/item/weapon/computer_hardware/hard_drive)) + if(hard_drive) + to_chat(user, "This computer's hard drive slot is already occupied by \the [hard_drive].") + return + found = 1 + hard_drive = H + else if(istype(H, /obj/item/weapon/computer_hardware/network_card)) + if(network_card) + to_chat(user, "This computer's network card slot is already occupied by \the [network_card].") + return + found = 1 + network_card = H + else if(istype(H, /obj/item/weapon/computer_hardware/nano_printer)) + if(nano_printer) + to_chat(user, "This computer's nano printer slot is already occupied by \the [nano_printer].") + return + found = 1 + nano_printer = H + else if(istype(H, /obj/item/weapon/computer_hardware/card_slot)) + if(card_slot) + to_chat(user, "This computer's card slot is already occupied by \the [card_slot].") + return + found = 1 + card_slot = H + else if(istype(H, /obj/item/weapon/computer_hardware/battery_module)) + if(battery_module) + to_chat(user, "This computer's battery slot is already occupied by \the [battery_module].") + return + found = 1 + battery_module = H + else if(istype(H, /obj/item/weapon/computer_hardware/processor_unit)) + if(processor_unit) + to_chat(user, "This computer's processor slot is already occupied by \the [processor_unit].") + return + found = 1 + processor_unit = H + else if(istype(H, /obj/item/weapon/computer_hardware/ai_slot)) + if(ai_slot) + to_chat(user, "This computer's intellicard slot is already occupied by \the [ai_slot].") + return + found = 1 + ai_slot = H + else if(istype(H, /obj/item/weapon/computer_hardware/tesla_link)) + if(tesla_link) + to_chat(user, "This computer's tesla link slot is already occupied by \the [tesla_link].") + return + found = 1 + tesla_link = H + if(found) + to_chat(user, "You install \the [H] into \the [src]") + H.holder2 = src + user.drop_from_inventory(H) + H.forceMove(src) + update_verbs() + +// Uninstalls component. Found and Critical vars may be passed by parent types, if they have additional hardware. +/obj/item/modular_computer/proc/uninstall_component(var/mob/living/user, var/obj/item/weapon/computer_hardware/H, var/found = 0, var/critical = 0) + if(portable_drive == H) + portable_drive = null + found = 1 + if(hard_drive == H) + hard_drive = null + found = 1 + critical = 1 + if(network_card == H) + network_card = null + found = 1 + if(nano_printer == H) + nano_printer = null + found = 1 + if(card_slot == H) + card_slot = null + found = 1 + if(battery_module == H) + battery_module = null + found = 1 + if(processor_unit == H) + processor_unit = null + found = 1 + critical = 1 + if(ai_slot == H) + ai_slot = null + found = 1 + if(tesla_link == H) + tesla_link = null + found = 1 + if(found) + if(user) + to_chat(user, "You remove \the [H] from \the [src].") + H.forceMove(get_turf(src)) + H.holder2 = null + update_verbs() + if(critical && enabled) + if(user) + to_chat(user, "\The [src]'s screen freezes for few seconds and then displays an \"HARDWARE ERROR: Critical component disconnected. Please verify component connection and reboot the device. If the problem persists contact technical support for assistance.\" warning.") + shutdown_computer() + update_icon() + + +// Checks all hardware pieces to determine if name matches, if yes, returns the hardware piece, otherwise returns null +/obj/item/modular_computer/proc/find_hardware_by_name(var/name) + if(portable_drive && (portable_drive.name == name)) + return portable_drive + if(hard_drive && (hard_drive.name == name)) + return hard_drive + if(network_card && (network_card.name == name)) + return network_card + if(nano_printer && (nano_printer.name == name)) + return nano_printer + if(card_slot && (card_slot.name == name)) + return card_slot + if(battery_module && (battery_module.name == name)) + return battery_module + if(processor_unit && (processor_unit.name == name)) + return processor_unit + if(ai_slot && (ai_slot.name == name)) + return ai_slot + if(tesla_link && (tesla_link.name == name)) + return tesla_link + return null + +// Returns list of all components +/obj/item/modular_computer/proc/get_all_components() + var/list/all_components = list() + if(hard_drive) + all_components.Add(hard_drive) + if(network_card) + all_components.Add(network_card) + if(portable_drive) + all_components.Add(portable_drive) + if(nano_printer) + all_components.Add(nano_printer) + if(card_slot) + all_components.Add(card_slot) + if(battery_module) + all_components.Add(battery_module) + if(processor_unit) + all_components.Add(processor_unit) + if(ai_slot) + all_components.Add(ai_slot) + if(tesla_link) + all_components.Add(tesla_link) + return all_components \ No newline at end of file diff --git a/code/modules/modular_computers/computers/modular_computer/interaction.dm b/code/modules/modular_computers/computers/modular_computer/interaction.dm new file mode 100644 index 00000000..034a10ec --- /dev/null +++ b/code/modules/modular_computers/computers/modular_computer/interaction.dm @@ -0,0 +1,234 @@ +/obj/item/modular_computer/proc/update_verbs() + verbs.Cut() + if(ai_slot) + verbs |= /obj/item/modular_computer/verb/eject_ai + if(portable_drive) + verbs |= /obj/item/modular_computer/verb/eject_usb + if(card_slot) + verbs |= /obj/item/modular_computer/verb/eject_id + verbs |= /obj/item/modular_computer/verb/emergency_shutdown + +// Forcibly shut down the device. To be used when something bugs out and the UI is nonfunctional. +/obj/item/modular_computer/verb/emergency_shutdown() + set name = "Forced Shutdown" + set category = "Object" + set src in view(1) + + if(usr.incapacitated() || !istype(usr, /mob/living)) + to_chat(usr, "You can't do that.") + return + + if(!Adjacent(usr)) + to_chat(usr, "You can't reach it.") + return + + if(enabled) + bsod = 1 + update_icon() + shutdown_computer() + to_chat(usr, "You press a hard-reset button on \the [src]. It displays a brief debug screen before shutting down.") + spawn(2 SECONDS) + bsod = 0 + update_icon() + + +// Eject ID card from computer, if it has ID slot with card inside. +/obj/item/modular_computer/verb/eject_id() + set name = "Eject ID" + set category = "Object" + set src in view(1) + + if(usr.incapacitated() || !istype(usr, /mob/living)) + to_chat(usr, "You can't do that.") + return + + if(!Adjacent(usr)) + to_chat(usr, "You can't reach it.") + return + + proc_eject_id(usr) + +// Eject ID card from computer, if it has ID slot with card inside. +/obj/item/modular_computer/verb/eject_usb() + set name = "Eject Portable Storage" + set category = "Object" + set src in view(1) + + if(usr.incapacitated() || !istype(usr, /mob/living)) + to_chat(usr, "You can't do that.") + return + + if(!Adjacent(usr)) + to_chat(usr, "You can't reach it.") + return + + proc_eject_usb(usr) + +/obj/item/modular_computer/verb/eject_ai() + set name = "Eject AI" + set category = "Object" + set src in view(1) + + if(usr.incapacitated() || !istype(usr, /mob/living)) + to_chat(usr, "You can't do that.") + return + + if(!Adjacent(usr)) + to_chat(usr, "You can't reach it.") + return + + proc_eject_ai(usr) + +/obj/item/modular_computer/proc/proc_eject_id(mob/user) + if(!user) + user = usr + + if(!card_slot) + to_chat(user, "\The [src] does not have an ID card slot") + return + + if(!card_slot.stored_card) + to_chat(user, "There is no card in \the [src]") + return + + if(active_program) + active_program.event_idremoved(0) + + for(var/datum/computer_file/program/P in idle_threads) + P.event_idremoved(1) + + card_slot.stored_card.forceMove(get_turf(src)) + card_slot.stored_card = null + update_uis() + to_chat(user, "You remove the card from \the [src]") + + +/obj/item/modular_computer/proc/proc_eject_usb(mob/user) + if(!user) + user = usr + + if(!portable_drive) + to_chat(user, "There is no portable device connected to \the [src].") + return + + uninstall_component(user, portable_drive) + update_uis() + +/obj/item/modular_computer/proc/proc_eject_ai(mob/user) + if(!user) + user = usr + + if(!ai_slot || !ai_slot.stored_card) + to_chat(user, "There is no intellicard connected to \the [src].") + return + + ai_slot.stored_card.forceMove(get_turf(src)) + ai_slot.stored_card = null + ai_slot.update_power_usage() + update_uis() + +/obj/item/modular_computer/attack_ghost(var/mob/observer/ghost/user) + if(enabled) + ui_interact(user) + else if(check_rights(R_ADMIN, 0, user)) + var/response = alert(user, "This computer is turned off. Would you like to turn it on?", "Admin Override", "Yes", "No") + if(response == "Yes") + turn_on(user) + +/obj/item/modular_computer/attack_ai(var/mob/user) + return attack_self(user) + +/obj/item/modular_computer/attack_hand(var/mob/user) + if(anchored) + return attack_self(user) + return ..() + +// On-click handling. Turns on the computer if it's off and opens the GUI. +/obj/item/modular_computer/attack_self(var/mob/user) + if(enabled && screen_on) + ui_interact(user) + else if(!enabled && screen_on) + turn_on(user) + +/obj/item/modular_computer/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(istype(W, /obj/item/weapon/card/id)) // ID Card, try to insert it. + var/obj/item/weapon/card/id/I = W + if(!card_slot) + to_chat(user, "You try to insert \the [I] into \the [src], but it does not have an ID card slot installed.") + return + + if(card_slot.stored_card) + to_chat(user, "You try to insert \the [I] into \the [src], but it's ID card slot is occupied.") + return + user.drop_from_inventory(I) + card_slot.stored_card = I + I.forceMove(src) + update_uis() + to_chat(user, "You insert \the [I] into \the [src].") + return + if(istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/weapon/paper_bundle)) + if(!nano_printer) + return + nano_printer.attackby(W, user) + if(istype(W, /obj/item/weapon/aicard)) + if(!ai_slot) + return + ai_slot.attackby(W, user) + if(istype(W, /obj/item/weapon/computer_hardware)) + var/obj/item/weapon/computer_hardware/C = W + if(C.hardware_size <= max_hardware_size) + try_install_component(user, C) + else + to_chat(user, "This component is too large for \the [src].") + if(isWrench(W)) + var/list/components = get_all_components() + if(components.len) + to_chat(user, "Remove all components from \the [src] before disassembling it.") + return + new /obj/item/stack/material/steel( get_turf(src.loc), steel_sheet_cost ) + src.visible_message("\The [src] has been disassembled by [user].") + qdel(src) + return + if(isWelder(W)) + var/obj/item/weapon/weldingtool/WT = W + if(!WT.isOn()) + to_chat(user, "\The [W] is off.") + return + + if(!damage) + to_chat(user, "\The [src] does not require repairs.") + return + + to_chat(user, "You begin repairing damage to \the [src]...") + if(WT.remove_fuel(round(damage/75)) && do_after(usr, damage/10)) + damage = 0 + to_chat(user, "You repair \the [src].") + return + + if(isScrewdriver(W)) + var/list/all_components = get_all_components() + if(!all_components.len) + to_chat(user, "This device doesn't have any components installed.") + return + var/list/component_names = list() + for(var/obj/item/weapon/computer_hardware/H in all_components) + component_names.Add(H.name) + + var/choice = input(usr, "Which component do you want to uninstall?", "Computer maintenance", null) as null|anything in component_names + + if(!choice) + return + + if(!Adjacent(usr)) + return + + var/obj/item/weapon/computer_hardware/H = find_hardware_by_name(choice) + + if(!H) + return + + uninstall_component(user, H) + + return + + ..() \ No newline at end of file diff --git a/code/modules/modular_computers/computers/modular_computer/power.dm b/code/modules/modular_computers/computers/modular_computer/power.dm new file mode 100644 index 00000000..f65ac9bb --- /dev/null +++ b/code/modules/modular_computers/computers/modular_computer/power.dm @@ -0,0 +1,51 @@ +/obj/item/modular_computer/proc/power_failure(var/malfunction = 0) + if(enabled) // Shut down the computer + visible_message("\The [src]'s screen flickers briefly and then goes dark.", range = 1) + if(active_program) + active_program.event_powerfailure(0) + for(var/datum/computer_file/program/PRG in idle_threads) + PRG.event_powerfailure(1) + shutdown_computer(0) + +// Tries to use power from battery. Passing 0 as parameter results in this proc returning whether battery is functional or not. +/obj/item/modular_computer/proc/battery_power(var/power_usage = 0) + apc_powered = FALSE + if(!battery_module || !battery_module.check_functionality() || battery_module.battery.charge <= 0) + return FALSE + if(battery_module.battery.use(power_usage * CELLRATE) || ((power_usage == 0) && battery_module.battery.charge)) + return TRUE + return FALSE + +// Tries to use power from APC, if present. +/obj/item/modular_computer/proc/apc_power(var/power_usage = 0) + apc_powered = TRUE + // Tesla link was originally limited to machinery only, but this probably works too, and the benefit of being able to power all devices from an APC outweights + // the possible minor performance loss. + if(!tesla_link || !tesla_link.check_functionality()) + return FALSE + var/area/A = get_area(src) + if(!istype(A) || !A.powered(EQUIP)) + return FALSE + + // At this point, we know that APC can power us for this tick. Check if we also need to charge our battery, and then actually use the power. + if(battery_module && (battery_module.battery.charge < battery_module.battery.maxcharge) && (power_usage > 0)) + power_usage += tesla_link.passive_charging_rate + battery_module.battery.give(tesla_link.passive_charging_rate * CELLRATE) + + A.use_power(power_usage, EQUIP) + return TRUE + +// Handles power-related things, such as battery interaction, recharging, shutdown when it's discharged +/obj/item/modular_computer/proc/handle_power() + var/power_usage = screen_on ? base_active_power_usage : base_idle_power_usage + for(var/obj/item/weapon/computer_hardware/H in get_all_components()) + if(H.enabled) + power_usage += H.power_usage + last_power_usage = power_usage + + // First tries to charge from an APC, if APC is unavailable switches to battery power. If neither works the computer fails. + if(apc_power(power_usage)) + return + if(battery_power(power_usage)) + return + power_failure() \ No newline at end of file diff --git a/code/modules/modular_computers/computers/modular_computer/ui.dm b/code/modules/modular_computers/computers/modular_computer/ui.dm new file mode 100644 index 00000000..ec0d871d --- /dev/null +++ b/code/modules/modular_computers/computers/modular_computer/ui.dm @@ -0,0 +1,155 @@ +// Operates NanoUI +/obj/item/modular_computer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(!screen_on || !enabled) + if(ui) + ui.close() + return 0 + if(!apc_power(0) && !battery_power(0)) + if(ui) + ui.close() + return 0 + + // If we have an active program switch to it now. + if(active_program) + if(ui) // This is the main laptop screen. Since we are switching to program's UI close it for now. + ui.close() + active_program.ui_interact(user) + return + + // We are still here, that means there is no program loaded. Load the BIOS/ROM/OS/whatever you want to call it. + // This screen simply lists available programs and user may select them. + if(!hard_drive || !hard_drive.stored_files || !hard_drive.stored_files.len) + visible_message("\The [src] beeps three times, it's screen displaying \"DISK ERROR\" warning.") + return // No HDD, No HDD files list or no stored files. Something is very broken. + + var/datum/computer_file/data/autorun = hard_drive.find_file_by_name("autorun") + + var/list/data = get_header_data() + + var/list/programs = list() + for(var/datum/computer_file/program/P in hard_drive.stored_files) + var/list/program = list() + program["name"] = P.filename + program["desc"] = P.filedesc + program["icon"] = P.program_menu_icon + program["autorun"] = (istype(autorun) && (autorun.stored_data == P.filename)) ? 1 : 0 + if(P in idle_threads) + program["running"] = 1 + programs.Add(list(program)) + + data["programs"] = programs + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "laptop_mainscreen.tmpl", "KAOS Main Menu", 400, 500) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +// Handles user's GUI input +/obj/item/modular_computer/Topic(href, href_list) + if(..()) + return 1 + if( href_list["PC_exit"] ) + kill_program() + return 1 + if( href_list["PC_enable_component"] ) + var/obj/item/weapon/computer_hardware/H = find_hardware_by_name(href_list["PC_enable_component"]) + if(H && istype(H) && !H.enabled) + H.enabled = 1 + . = 1 + if( href_list["PC_disable_component"] ) + var/obj/item/weapon/computer_hardware/H = find_hardware_by_name(href_list["PC_disable_component"]) + if(H && istype(H) && H.enabled) + H.enabled = 0 + . = 1 + if( href_list["PC_shutdown"] ) + shutdown_computer() + return 1 + if( href_list["PC_minimize"] ) + var/mob/user = usr + minimize_program(user) + + if( href_list["PC_killprogram"] ) + var/prog = href_list["PC_killprogram"] + var/datum/computer_file/program/P = null + var/mob/user = usr + if(hard_drive) + P = hard_drive.find_file_by_name(prog) + + if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED) + return + + P.kill_program(1) + update_uis() + to_chat(user, "Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.") + + if( href_list["PC_runprogram"] ) + return run_program(href_list["PC_runprogram"]) + + if( href_list["PC_setautorun"] ) + if(!hard_drive) + return + set_autorun(href_list["PC_setautorun"]) + + if(.) + update_uis() + +// Function used by NanoUI's to obtain data for header. All relevant entries begin with "PC_" +/obj/item/modular_computer/proc/get_header_data() + var/list/data = list() + + if(battery_module) + switch(battery_module.battery.percent()) + if(80 to 200) // 100 should be maximal but just in case.. + data["PC_batteryicon"] = "batt_100.gif" + if(60 to 80) + data["PC_batteryicon"] = "batt_80.gif" + if(40 to 60) + data["PC_batteryicon"] = "batt_60.gif" + if(20 to 40) + data["PC_batteryicon"] = "batt_40.gif" + if(5 to 20) + data["PC_batteryicon"] = "batt_20.gif" + else + data["PC_batteryicon"] = "batt_5.gif" + data["PC_batterypercent"] = "[round(battery_module.battery.percent())] %" + data["PC_showbatteryicon"] = 1 + else + data["PC_batteryicon"] = "batt_5.gif" + data["PC_batterypercent"] = "N/C" + data["PC_showbatteryicon"] = battery_module ? 1 : 0 + + if(tesla_link && tesla_link.enabled && apc_powered) + data["PC_apclinkicon"] = "charging.gif" + + if(network_card && network_card.is_banned()) + data["PC_ntneticon"] = "sig_warning.gif" + else + switch(get_ntnet_status()) + if(0) + data["PC_ntneticon"] = "sig_none.gif" + if(1) + data["PC_ntneticon"] = "sig_low.gif" + if(2) + data["PC_ntneticon"] = "sig_high.gif" + if(3) + data["PC_ntneticon"] = "sig_lan.gif" + + var/list/program_headers = list() + for(var/datum/computer_file/program/P in idle_threads) + if(!P.ui_header) + continue + program_headers.Add(list(list( + "icon" = P.ui_header + ))) + if(active_program && active_program.ui_header) + program_headers.Add(list(list( + "icon" = active_program.ui_header + ))) + data["PC_programheaders"] = program_headers + + data["PC_stationtime"] = stationtime2text() + data["PC_hasheader"] = 1 + data["PC_showexitprogram"] = active_program ? 1 : 0 // Hides "Exit Program" button on mainscreen + return data \ No newline at end of file diff --git a/code/modules/modular_computers/computers/modular_computer/variables.dm b/code/modules/modular_computers/computers/modular_computer/variables.dm new file mode 100644 index 00000000..9095bd6a --- /dev/null +++ b/code/modules/modular_computers/computers/modular_computer/variables.dm @@ -0,0 +1,54 @@ +// This is the base type that handles everything. Subtypes can be easily created by tweaking variables in this file to your liking. + +/obj/item/modular_computer + name = "Modular Computer" + desc = "A modular computer. You shouldn't see this." + + var/enabled = 0 // Whether the computer is turned on. + var/screen_on = 1 // Whether the computer is active/opened/it's screen is on. + var/datum/computer_file/program/active_program = null // A currently active program running on the computer. + var/hardware_flag = 0 // A flag that describes this device type + var/last_power_usage = 0 // Last tick power usage of this computer + var/last_battery_percent = 0 // Used for deciding if battery percentage has chandged + var/last_world_time = "00:00" + var/list/last_header_icons + var/computer_emagged = FALSE // Whether the computer is emagged. + var/apc_powered = FALSE // Set automatically. Whether the computer used APC power last tick. + var/base_active_power_usage = 50 // Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too. + var/base_idle_power_usage = 5 // Power usage when the computer is idle and screen is off (currently only applies to laptops) + var/bsod = FALSE // Error screen displayed + var/ambience_last_played // Last time sound was played + + // Modular computers can run on various devices. Each DEVICE (Laptop, Console, Tablet,..) + // must have it's own DMI file. Icon states must be called exactly the same in all files, but may look differently + // If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example. + + icon = null // This thing isn't meant to be used on it's own. Subtypes should supply their own icon. + icon_state = null + center_of_mass = null // No pixelshifting by placing on tables, etc. + randpixel = 0 // And no random pixelshifting on-creation either. + var/icon_state_unpowered = null // Icon state when the computer is turned off + var/icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen. + var/icon_state_screensaver = null + var/max_hardware_size = 0 // Maximal hardware size. Currently, tablets have 1, laptops 2 and consoles 3. Limits what hardware types can be installed. + var/steel_sheet_cost = 5 // Amount of steel sheets refunded when disassembling an empty frame of this computer. + var/light_strength = 0 // Intensity of light this computer emits. Comparable to numbers light fixtures use. + var/list/idle_threads = list() // Idle programs on background. They still receive process calls but can't be interacted with. + + // Damage of the chassis. If the chassis takes too much damage it will break apart. + var/damage = 0 // Current damage level + var/broken_damage = 50 // Damage level at which the computer ceases to operate + var/max_damage = 100 // Damage level at which the computer breaks apart. + + // Important hardware (must be installed for computer to work) + var/obj/item/weapon/computer_hardware/processor_unit/processor_unit // CPU. Without it the computer won't run. Better CPUs can run more programs at once. + var/obj/item/weapon/computer_hardware/network_card/network_card // Network Card component of this computer. Allows connection to NTNet + var/obj/item/weapon/computer_hardware/hard_drive/hard_drive // Hard Drive component of this computer. Stores programs and files. + + // Optional hardware (improves functionality, but is not critical for computer to work in most cases) + var/obj/item/weapon/computer_hardware/battery_module/battery_module // An internal power source for this computer. Can be recharged. + var/obj/item/weapon/computer_hardware/card_slot/card_slot // ID Card slot component of this computer. Mostly for HoP modification console that needs ID slot for modification. + var/obj/item/weapon/computer_hardware/nano_printer/nano_printer // Nano Printer component of this computer, for your everyday paperwork needs. + var/obj/item/weapon/computer_hardware/hard_drive/portable/portable_drive // Portable data storage + var/obj/item/weapon/computer_hardware/ai_slot/ai_slot // AI slot, an intellicard housing that allows modifications of AIs. + var/obj/item/weapon/computer_hardware/tesla_link/tesla_link // Tesla Link, Allows remote charging from nearest APC. \ No newline at end of file diff --git a/code/modules/modular_computers/computers/status_icons.dmi b/code/modules/modular_computers/computers/status_icons.dmi new file mode 100644 index 00000000..52127ec4 Binary files /dev/null and b/code/modules/modular_computers/computers/status_icons.dmi differ diff --git a/code/modules/modular_computers/computers/subtypes/dev_console.dm b/code/modules/modular_computers/computers/subtypes/dev_console.dm new file mode 100644 index 00000000..6b487585 --- /dev/null +++ b/code/modules/modular_computers/computers/subtypes/dev_console.dm @@ -0,0 +1,28 @@ +/obj/item/modular_computer/console + name = "console" + desc = "A stationary computer." + icon = 'icons/obj/modular_console.dmi' + icon_state = "console" + icon_state_unpowered = "console" + icon_state_screensaver = "standby" + icon_state_menu = "menu" + hardware_flag = PROGRAM_CONSOLE + anchored = TRUE + density = 1 + base_idle_power_usage = 100 + base_active_power_usage = 500 + max_hardware_size = 3 + steel_sheet_cost = 20 + light_strength = 4 + max_damage = 300 + broken_damage = 150 + atom_flags = ATOM_FLAG_CLIMBABLE + +/obj/item/modular_computer/console/CouldUseTopic(var/mob/user) + ..() + if(istype(user, /mob/living/carbon)) + playsound(src, "keyboard", 40) + //if(prob(50)) + // playsound(src, "keyboard", 40) + //else + // playsound(src, "keystroke", 40) \ No newline at end of file diff --git a/code/modules/modular_computers/computers/subtypes/dev_laptop.dm b/code/modules/modular_computers/computers/subtypes/dev_laptop.dm new file mode 100644 index 00000000..14c0bf9a --- /dev/null +++ b/code/modules/modular_computers/computers/subtypes/dev_laptop.dm @@ -0,0 +1,39 @@ +/obj/item/modular_computer/laptop + anchored = TRUE + name = "laptop computer" + desc = "A portable computer." + hardware_flag = PROGRAM_LAPTOP + icon_state_unpowered = "laptop-open" + icon = 'icons/obj/modular_laptop.dmi' + icon_state = "laptop-open" + icon_state_screensaver = "standby" + base_idle_power_usage = 25 + base_active_power_usage = 200 + max_hardware_size = 2 + light_strength = 3 + max_damage = 200 + broken_damage = 100 + w_class = ITEM_SIZE_NORMAL + var/icon_state_closed = "laptop-closed" + +/obj/item/modular_computer/laptop/AltClick(var/mob/user) +// Prevents carrying of open laptops inhand. +// While they work inhand, i feel it'd make tablets lose some of their high-mobility advantage they have over laptops now. + if(!CanPhysicallyInteract(user)) + return + if(!istype(loc, /turf/)) + to_chat(usr, "\The [src] has to be on a stable surface first!") + return + anchored = !anchored + screen_on = anchored + update_icon() + +/obj/item/modular_computer/laptop/update_icon() + if(anchored) + ..() + else + overlays.Cut() + icon_state = icon_state_closed + +/obj/item/modular_computer/laptop/preset + anchored = FALSE \ No newline at end of file diff --git a/code/modules/modular_computers/computers/subtypes/dev_tablet.dm b/code/modules/modular_computers/computers/subtypes/dev_tablet.dm new file mode 100644 index 00000000..962af590 --- /dev/null +++ b/code/modules/modular_computers/computers/subtypes/dev_tablet.dm @@ -0,0 +1,16 @@ +/obj/item/modular_computer/tablet + name = "tablet computer" + desc = "A small portable microcomputer" + icon = 'icons/obj/modular_tablet.dmi' + icon_state = "tablet" + icon_state_unpowered = "tablet" + icon_state_menu = "menu" + hardware_flag = PROGRAM_TABLET + max_hardware_size = 1 + w_class = ITEM_SIZE_SMALL + light_strength = 2 // Same as PDAs + +/obj/item/modular_computer/tablet/lease + desc = "A small portable microcomputer. This one has a gold and blue stripe, and a serial number stamped into the case." + icon_state = "tabletsol" + icon_state_unpowered = "tabletsol" \ No newline at end of file diff --git a/code/modules/modular_computers/computers/subtypes/dev_telescreen.dm b/code/modules/modular_computers/computers/subtypes/dev_telescreen.dm new file mode 100644 index 00000000..45e9bfba --- /dev/null +++ b/code/modules/modular_computers/computers/subtypes/dev_telescreen.dm @@ -0,0 +1,59 @@ +/obj/item/modular_computer/telescreen + name = "telescreen" + desc = "A wall-mounted touchscreen computer." + icon = 'icons/obj/modular_telescreen.dmi' + icon_state = "telescreen" + icon_state_unpowered = "telescreen" + icon_state_menu = "menu" + icon_state_screensaver = "standby" + hardware_flag = PROGRAM_TELESCREEN + anchored = TRUE + density = 0 + base_idle_power_usage = 75 + base_active_power_usage = 300 + max_hardware_size = 2 + steel_sheet_cost = 10 + light_strength = 4 + max_damage = 300 + broken_damage = 150 + w_class = ITEM_SIZE_HUGE + +/obj/item/modular_computer/telescreen/New() + ..() + // Allows us to create "north bump" "south bump" etc. named objects, for more comfortable mapping. + name = "telescreen" + +/obj/item/modular_computer/telescreen/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(isCrowbar(W)) + if(anchored) + shutdown_computer() + anchored = FALSE + screen_on = FALSE + pixel_x = 0 + pixel_y = 0 + to_chat(user, "You unsecure \the [src].") + else + var/choice = input(user, "Where do you want to place \the [src]?", "Offset selection") in list("North", "South", "West", "East", "This tile", "Cancel") + var/valid = FALSE + switch(choice) + if("North") + valid = TRUE + pixel_y = 32 + if("South") + valid = TRUE + pixel_y = -32 + if("West") + valid = TRUE + pixel_x = -32 + if("East") + valid = TRUE + pixel_x = 32 + if("This tile") + valid = TRUE + + if(valid) + anchored = 1 + screen_on = TRUE + to_chat(user, "You secure \the [src].") + return + ..() \ No newline at end of file diff --git a/code/modules/modular_computers/computers/subtypes/preset_console.dm b/code/modules/modular_computers/computers/subtypes/preset_console.dm new file mode 100644 index 00000000..856c997f --- /dev/null +++ b/code/modules/modular_computers/computers/subtypes/preset_console.dm @@ -0,0 +1,171 @@ +/obj/item/modular_computer/console/preset/install_default_hardware() + ..() + processor_unit = new/obj/item/weapon/computer_hardware/processor_unit(src) + tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(src) + hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/super(src) + network_card = new/obj/item/weapon/computer_hardware/network_card/wired(src) + +// Engineering +/obj/item/modular_computer/console/preset/engineering/install_default_programs() + ..() + hard_drive.store_file(new/datum/computer_file/program/power_monitor()) + hard_drive.store_file(new/datum/computer_file/program/supermatter_monitor()) + hard_drive.store_file(new/datum/computer_file/program/alarm_monitor()) + hard_drive.store_file(new/datum/computer_file/program/atmos_control()) + hard_drive.store_file(new/datum/computer_file/program/rcon_console()) + hard_drive.store_file(new/datum/computer_file/program/camera_monitor()) + //hard_drive.store_file(new/datum/computer_file/program/shields_monitor()) + +// Medical +/obj/item/modular_computer/console/preset/medical/install_default_programs() + ..() + //hard_drive.store_file(new/datum/computer_file/program/suit_sensors()) + hard_drive.store_file(new/datum/computer_file/program/camera_monitor()) + hard_drive.store_file(new/datum/computer_file/program/records()) + //hard_drive.store_file(new/datum/computer_file/program/wordprocessor()) + set_autorun("sensormonitor") + +// Research +/obj/item/modular_computer/console/preset/research/install_default_hardware() + ..() + ai_slot = new/obj/item/weapon/computer_hardware/ai_slot(src) + +/obj/item/modular_computer/console/preset/research/install_default_programs() + ..() + //hard_drive.store_file(new/datum/computer_file/program/ntnetmonitor()) + //hard_drive.store_file(new/datum/computer_file/program/nttransfer()) + //hard_drive.store_file(new/datum/computer_file/program/chatclient()) + hard_drive.store_file(new/datum/computer_file/program/camera_monitor()) + hard_drive.store_file(new/datum/computer_file/program/aidiag()) + hard_drive.store_file(new/datum/computer_file/program/email_client()) + //hard_drive.store_file(new/datum/computer_file/program/wordprocessor()) + +// Administrator +/obj/item/modular_computer/console/preset/sysadmin/install_default_hardware() + ..() + ai_slot = new/obj/item/weapon/computer_hardware/ai_slot(src) + +/obj/item/modular_computer/console/preset/sysadmin/install_default_programs() + ..() + //hard_drive.store_file(new/datum/computer_file/program/ntnetmonitor()) + //hard_drive.store_file(new/datum/computer_file/program/nttransfer()) + //hard_drive.store_file(new/datum/computer_file/program/chatclient()) + hard_drive.store_file(new/datum/computer_file/program/camera_monitor()) + hard_drive.store_file(new/datum/computer_file/program/aidiag()) + //hard_drive.store_file(new/datum/computer_file/program/email_client()) + //hard_drive.store_file(new/datum/computer_file/program/email_administration()) + hard_drive.store_file(new/datum/computer_file/program/records()) + //hard_drive.store_file(new/datum/computer_file/program/wordprocessor()) + +// Command +/obj/item/modular_computer/console/preset/command/install_default_hardware() + ..() + nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(src) + card_slot = new/obj/item/weapon/computer_hardware/card_slot(src) + +/obj/item/modular_computer/console/preset/command/install_default_programs() + ..() + //hard_drive.store_file(new/datum/computer_file/program/chatclient()) + hard_drive.store_file(new/datum/computer_file/program/card_mod()) + hard_drive.store_file(new/datum/computer_file/program/comm()) + hard_drive.store_file(new/datum/computer_file/program/camera_monitor()) + //hard_drive.store_file(new/datum/computer_file/program/email_client()) + hard_drive.store_file(new/datum/computer_file/program/records()) + //hard_drive.store_file(new/datum/computer_file/program/wordprocessor()) + hard_drive.store_file(new/datum/computer_file/program/docking()) + +// Security +/obj/item/modular_computer/console/preset/security/install_default_programs() + ..() + hard_drive.store_file(new/datum/computer_file/program/camera_monitor()) + hard_drive.store_file(new/datum/computer_file/program/digitalwarrant()) + hard_drive.store_file(new/datum/computer_file/program/records()) + //hard_drive.store_file(new/datum/computer_file/program/wordprocessor()) + +// Civilian +/obj/item/modular_computer/console/preset/civilian/install_default_programs() + ..() + //hard_drive.store_file(new/datum/computer_file/program/chatclient()) + //hard_drive.store_file(new/datum/computer_file/program/nttransfer()) + //hard_drive.store_file(new/datum/computer_file/program/newsbrowser()) + hard_drive.store_file(new/datum/computer_file/program/camera_monitor()) + //hard_drive.store_file(new/datum/computer_file/program/email_client()) + hard_drive.store_file(new/datum/computer_file/program/supply()) + hard_drive.store_file(new/datum/computer_file/program/records()) + //hard_drive.store_file(new/datum/computer_file/program/wordprocessor()) + +// Offices +/obj/item/modular_computer/console/preset/civilian/professional/install_default_hardware() + ..() + nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(src) + +//Dock control +/obj/item/modular_computer/console/preset/dock/install_default_hardware() + ..() + nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(src) + +/obj/item/modular_computer/console/preset/dock/install_default_programs() + ..() + //hard_drive.store_file(new/datum/computer_file/program/nttransfer()) + //hard_drive.store_file(new/datum/computer_file/program/email_client()) + hard_drive.store_file(new/datum/computer_file/program/supply()) + //hard_drive.store_file(new/datum/computer_file/program/wordprocessor()) + hard_drive.store_file(new/datum/computer_file/program/docking()) + +// Crew-facing supply ordering computer +/obj/item/modular_computer/console/preset/supply/install_default_hardware() + ..() + nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(src) + +/obj/item/modular_computer/console/preset/supply/install_default_programs() + ..() + hard_drive.store_file(new/datum/computer_file/program/supply()) + set_autorun("supply") + +// ERT +/obj/item/modular_computer/console/preset/ert/install_default_hardware() + ..() + ai_slot = new/obj/item/weapon/computer_hardware/ai_slot(src) + nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(src) + card_slot = new/obj/item/weapon/computer_hardware/card_slot(src) + +/obj/item/modular_computer/console/preset/ert/install_default_programs() + ..() + //hard_drive.store_file(new/datum/computer_file/program/nttransfer()) + hard_drive.store_file(new/datum/computer_file/program/camera_monitor/ert()) + hard_drive.store_file(new/datum/computer_file/program/alarm_monitor()) + hard_drive.store_file(new/datum/computer_file/program/comm()) + hard_drive.store_file(new/datum/computer_file/program/aidiag()) + hard_drive.store_file(new/datum/computer_file/program/records()) + //hard_drive.store_file(new/datum/computer_file/program/wordprocessor()) + +// Mercenary +/obj/item/modular_computer/console/preset/mercenary/ + computer_emagged = TRUE + +/obj/item/modular_computer/console/preset/mercenary/install_default_hardware() + ..() + ai_slot = new/obj/item/weapon/computer_hardware/ai_slot(src) + nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(src) + card_slot = new/obj/item/weapon/computer_hardware/card_slot(src) + +/obj/item/modular_computer/console/preset/mercenary/install_default_programs() + ..() + hard_drive.store_file(new/datum/computer_file/program/camera_monitor/hacked()) + hard_drive.store_file(new/datum/computer_file/program/alarm_monitor()) + hard_drive.store_file(new/datum/computer_file/program/aidiag()) + +// Merchant +/obj/item/modular_computer/console/preset/merchant/install_default_programs() + ..() + hard_drive.store_file(new/datum/computer_file/program/merchant()) + //hard_drive.store_file(new/datum/computer_file/program/wordprocessor()) + +// Library +/obj/item/modular_computer/console/preset/library/install_default_programs() + ..() + //hard_drive.store_file(new/datum/computer_file/program/nttransfer()) + //hard_drive.store_file(new/datum/computer_file/program/newsbrowser()) + //hard_drive.store_file(new/datum/computer_file/program/email_client()) + //hard_drive.store_file(new/datum/computer_file/program/wordprocessor()) + hard_drive.store_file(new/datum/computer_file/program/library()) \ No newline at end of file diff --git a/code/modules/modular_computers/computers/subtypes/preset_laptop.dm b/code/modules/modular_computers/computers/subtypes/preset_laptop.dm new file mode 100644 index 00000000..55b3dcba --- /dev/null +++ b/code/modules/modular_computers/computers/subtypes/preset_laptop.dm @@ -0,0 +1,58 @@ +//Loadout presets + +/obj/item/modular_computer/laptop/preset/custom_loadout/cheap/install_default_hardware() + ..() + processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(src) + tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(src) + hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/(src) + network_card = new/obj/item/weapon/computer_hardware/network_card/(src) + nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(src) + card_slot = new/obj/item/weapon/computer_hardware/card_slot(src) + battery_module = new/obj/item/weapon/computer_hardware/battery_module/advanced(src) + battery_module.charge_to_full() + +/obj/item/modular_computer/laptop/preset/custom_loadout/advanced/install_default_hardware() + ..() + processor_unit = new/obj/item/weapon/computer_hardware/processor_unit(src) + tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(src) + hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/advanced(src) + network_card = new/obj/item/weapon/computer_hardware/network_card/advanced(src) + nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(src) + card_slot = new/obj/item/weapon/computer_hardware/card_slot(src) + battery_module = new/obj/item/weapon/computer_hardware/battery_module/advanced(src) + battery_module.charge_to_full() + +/obj/item/modular_computer/laptop/preset/custom_loadout/standard/install_default_hardware() + ..() + processor_unit = new/obj/item/weapon/computer_hardware/processor_unit(src) + tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(src) + hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/(src) + network_card = new/obj/item/weapon/computer_hardware/network_card/(src) + nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(src) + card_slot = new/obj/item/weapon/computer_hardware/card_slot(src) + battery_module = new/obj/item/weapon/computer_hardware/battery_module/advanced(src) + battery_module.charge_to_full() + +/obj/item/modular_computer/laptop/preset/custom_loadout/install_default_programs() + ..() + var/mob/living/carbon/human/H = get_holder_of_type(src, /mob) + if(!istype(H)) return + install_default_programs_by_job(H) + hard_drive.store_file(new/datum/computer_file/program/wordprocessor()) + +//Map presets + +/obj/item/modular_computer/laptop/preset/records/install_default_hardware() + ..() + processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(src) + tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(src) + hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/(src) + network_card = new/obj/item/weapon/computer_hardware/network_card/(src) + nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(src) + battery_module = new/obj/item/weapon/computer_hardware/battery_module/nano(src) + battery_module.charge_to_full() + +/obj/item/modular_computer/laptop/preset/records/install_default_programs() + ..() + hard_drive.store_file(new/datum/computer_file/program/records()) + hard_drive.store_file(new/datum/computer_file/program/wordprocessor()) \ No newline at end of file diff --git a/code/modules/modular_computers/computers/subtypes/preset_tablet.dm b/code/modules/modular_computers/computers/subtypes/preset_tablet.dm new file mode 100644 index 00000000..60a51db5 --- /dev/null +++ b/code/modules/modular_computers/computers/subtypes/preset_tablet.dm @@ -0,0 +1,58 @@ +//Loadout +/obj/item/modular_computer/tablet/preset/custom_loadout/cheap/install_default_hardware() + ..() + processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(src) + tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(src) + hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/micro(src) + network_card = new/obj/item/weapon/computer_hardware/network_card(src) + battery_module = new/obj/item/weapon/computer_hardware/battery_module/nano(src) + battery_module.charge_to_full() + +/obj/item/modular_computer/tablet/preset/custom_loadout/advanced/install_default_hardware() + ..() + processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(src) + tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(src) + hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/small(src) + network_card = new/obj/item/weapon/computer_hardware/network_card/advanced(src) + nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(src) + card_slot = new/obj/item/weapon/computer_hardware/card_slot(src) + battery_module = new/obj/item/weapon/computer_hardware/battery_module(src) + battery_module.charge_to_full() + +/obj/item/modular_computer/tablet/preset/custom_loadout/standard/install_default_hardware() + ..() + processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(src) + tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(src) + hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/small(src) + network_card = new/obj/item/weapon/computer_hardware/network_card(src) + battery_module = new/obj/item/weapon/computer_hardware/battery_module/micro(src) + battery_module.charge_to_full() + +/obj/item/modular_computer/tablet/preset/custom_loadout/install_default_programs() + ..() + var/mob/living/carbon/human/H = get_holder_of_type(src, /mob) + if(!istype(H)) return + install_default_programs_by_job(H) + hard_drive.store_file(new/datum/computer_file/program/wordprocessor()) + +//Map presets + +/obj/item/modular_computer/tablet/lease/preset/command/install_default_hardware() + ..() + processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(src) + tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(src) + hard_drive = new/obj/item/weapon/computer_hardware/hard_drive(src) + network_card = new/obj/item/weapon/computer_hardware/network_card/advanced(src) + nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(src) + card_slot = new/obj/item/weapon/computer_hardware/card_slot(src) + battery_module = new/obj/item/weapon/computer_hardware/battery_module(src) + battery_module.charge_to_full() + +/obj/item/modular_computer/tablet/lease/preset/command/install_default_programs() + ..() + hard_drive.store_file(new/datum/computer_file/program/chatclient()) + hard_drive.store_file(new/datum/computer_file/program/card_mod()) + hard_drive.store_file(new/datum/computer_file/program/camera_monitor()) + hard_drive.store_file(new/datum/computer_file/program/email_client()) + hard_drive.store_file(new/datum/computer_file/program/records()) + hard_drive.store_file(new/datum/computer_file/program/wordprocessor()) \ No newline at end of file diff --git a/code/modules/modular_computers/computers/subtypes/preset_telescreen.dm b/code/modules/modular_computers/computers/subtypes/preset_telescreen.dm new file mode 100644 index 00000000..d0cb86ba --- /dev/null +++ b/code/modules/modular_computers/computers/subtypes/preset_telescreen.dm @@ -0,0 +1,14 @@ +/obj/item/modular_computer/telescreen/preset/install_default_hardware() + ..() + processor_unit = new/obj/item/weapon/computer_hardware/processor_unit(src) + tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(src) + hard_drive = new/obj/item/weapon/computer_hardware/hard_drive(src) + network_card = new/obj/item/weapon/computer_hardware/network_card(src) + +/obj/item/modular_computer/telescreen/preset/generic/install_default_programs() + ..() + hard_drive.store_file(new/datum/computer_file/program/chatclient()) + hard_drive.store_file(new/datum/computer_file/program/alarm_monitor()) + hard_drive.store_file(new/datum/computer_file/program/camera_monitor()) + hard_drive.store_file(new/datum/computer_file/program/email_client()) + set_autorun("cammon") diff --git a/code/modules/modular_computers/file_system/computer_file.dm b/code/modules/modular_computers/file_system/computer_file.dm new file mode 100644 index 00000000..c5c1d9e8 --- /dev/null +++ b/code/modules/modular_computers/file_system/computer_file.dm @@ -0,0 +1,39 @@ +var/global/file_uid = 0 + +/datum/computer_file/ + var/filename = "NewFile" // Placeholder. No spacebars + var/filetype = "XXX" // File full names are [filename].[filetype] so like NewFile.XXX in this case + var/size = 1 // File size in GQ. Integers only! + var/obj/item/weapon/computer_hardware/hard_drive/holder // Holder that contains this file. + var/unsendable = 0 // Whether the file may be sent to someone via NTNet transfer or other means. + var/undeletable = 0 // Whether the file may be deleted. Setting to 1 prevents deletion/renaming/etc. + var/uid // UID of this file + +/datum/computer_file/New() + ..() + uid = file_uid + file_uid++ + +/datum/computer_file/Destroy() + if(!holder) + return ..() + + holder.remove_file(src) + // holder.holder is the computer that has drive installed. If we are Destroy()ing program that's currently running kill it. + if(holder.holder2 && holder.holder2.active_program == src) + holder.holder2.kill_program(1) + holder = null + ..() + +// Returns independent copy of this file. +/datum/computer_file/proc/clone(var/rename = 0) + var/datum/computer_file/temp = new type + temp.unsendable = unsendable + temp.undeletable = undeletable + temp.size = size + if(rename) + temp.filename = filename + "(Copy)" + else + temp.filename = filename + temp.filetype = filetype + return temp \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/crew_record.dm b/code/modules/modular_computers/file_system/crew_record.dm new file mode 100644 index 00000000..0f5dfd06 --- /dev/null +++ b/code/modules/modular_computers/file_system/crew_record.dm @@ -0,0 +1,249 @@ +GLOBAL_LIST_EMPTY(all_crew_records) +GLOBAL_LIST_INIT(blood_types, list("A-", "A+", "B-", "B+", "AB-", "AB+", "O-", "O+")) +GLOBAL_LIST_INIT(physical_statuses, list("Active", "Disabled", "SSD", "Deceased")) +GLOBAL_VAR_INIT(default_physical_status, "Active") +GLOBAL_LIST_INIT(security_statuses, list("None", "Released", "Parolled", "Incarcerated", "Arrest")) +GLOBAL_VAR_INIT(default_security_status, "None") +GLOBAL_VAR_INIT(arrest_security_status, "Arrest") + +// Kept as a computer file for possible future expansion into servers. +/datum/computer_file/crew_record + filetype = "CDB" + size = 2 + + // String fields that can be held by this record. + // Try to avoid manipulating the fields_ variables directly - use getters/setters below instead. + var/icon/photo_front = null + var/icon/photo_side = null + var/list/fields = list() // Fields of this record + +/datum/computer_file/crew_record/New() + ..() + for(var/T in subtypesof(/record_field/)) + new T(src) + load_from_mob(null) + +/datum/computer_file/crew_record/Destroy() + . = ..() + GLOB.all_crew_records.Remove(src) + +/datum/computer_file/crew_record/proc/load_from_mob(var/mob/living/carbon/human/H) + if(istype(H)) + photo_front = getFlatIcon(H, SOUTH, always_use_defdir = 1) + photo_side = getFlatIcon(H, WEST, always_use_defdir = 1) + else + var/mob/living/carbon/human/dummy = new() + photo_front = getFlatIcon(dummy, SOUTH, always_use_defdir = 1) + photo_side = getFlatIcon(dummy, WEST, always_use_defdir = 1) + qdel(dummy) + + // Generic record + set_name(H ? H.real_name : "Unset") + set_job(H ? GetAssignment(H) : "Unset") + set_sex(H ? gender2text(H.gender) : "Unset") + set_age(H ? H.age : 30) + set_status(GLOB.default_physical_status) + + // Medical record + set_bloodtype(H ? H.b_type : "Unset") + set_medRecord((H && H.med_record && !jobban_isbanned(H, "Records") ? H.med_record : "No record supplied")) + + // Security record + set_criminalStatus(GLOB.default_security_status) + set_dna(H ? H.dna.unique_enzymes : "") + set_fingerprint(H ? md5(H.dna.uni_identity) : "") + set_secRecord((H && H.sec_record && !jobban_isbanned(H, "Records") ? H.sec_record : "No record supplied")) + + // Antag record + set_antagRecord((H && H.exploit_record && !jobban_isbanned(H, "Records") ? H.exploit_record : "")) + +// Returns independent copy of this file. +/datum/computer_file/crew_record/clone(var/rename = 0) + var/datum/computer_file/crew_record/temp = ..() + return temp + +/datum/computer_file/crew_record/proc/get_field(var/field_type) + var/record_field/F = locate(field_type) in fields + if(F) + return F.get_value() + +/datum/computer_file/crew_record/proc/set_field(var/field_type, var/value) + var/record_field/F = locate(field_type) in fields + if(F) + return F.set_value(value) + +// Global methods +// Used by character creation to create a record for new arrivals. +/proc/CreateModularRecord(var/mob/living/carbon/human/H) + var/datum/computer_file/crew_record/CR = new/datum/computer_file/crew_record() + GLOB.all_crew_records.Add(CR) + CR.load_from_mob(H) + return CR + +// Gets crew records filtered by set of positions +/proc/department_crew_manifest(var/list/filter_positions, var/blacklist = FALSE) + var/list/matches = list() + for(var/datum/computer_file/crew_record/CR in GLOB.all_crew_records) + var/rank = CR.get_job() + if(blacklist) + if(!(rank in filter_positions)) + matches.Add(CR) + else + if(rank in filter_positions) + matches.Add(CR) + return matches + +// Simple record to HTML (for paper purposes) conversion. +// Not visually that nice, but it gets the work done, feel free to tweak it visually +/proc/record_to_html(var/datum/computer_file/crew_record/CR, var/access) + var/dat = "

            RECORD DATABASE DATA DUMP

            Generated on: [stationdate2text()] [stationtime2text()]
            ******************************
            " + dat += "" + for(var/record_field/F in CR.fields) + if(F.can_see(access)) + dat += "" + dat += "
            [F.name]" + if(F.valtype == EDIT_LONGTEXT) + dat += "
            [F.get_display_value()]" + dat += "" + return dat + +/proc/get_crewmember_record(var/name) + for(var/datum/computer_file/crew_record/CR in GLOB.all_crew_records) + if(CR.get_name() == name) + return CR + return null + +/proc/GetAssignment(var/mob/living/carbon/human/H) + if(!H) + return "Unassigned" + if(!H.mind) + return H.job + if(H.mind.role_alt_title) + return H.mind.role_alt_title + return H.mind.assigned_role + +/record_field + var/name = "Unknown" + var/value = "Unset" + var/valtype = EDIT_SHORTTEXT + var/acccess + var/acccess_edit + var/record_id + +/record_field/New(var/datum/computer_file/crew_record/record) + if(!acccess_edit) + acccess_edit = acccess ? acccess : access_heads + if(record) + record_id = record.uid + record.fields += src + ..() + +/record_field/proc/get_value() + return value + +/record_field/proc/get_display_value() + if(valtype == EDIT_LONGTEXT) + return pencode2html(value) + return value + +/record_field/proc/set_value(var/newval) + if(isnull(newval)) + return + switch(valtype) + if(EDIT_LIST) + var/options = get_options() + if(!(newval in options)) + return + if(EDIT_SHORTTEXT) + newval = sanitize(newval) + if(EDIT_LONGTEXT) + newval = sanitize(replacetext(newval, "\n", "\[br\]"), MAX_PAPER_MESSAGE_LEN) + value = newval + return 1 + +/record_field/proc/get_options() + return list() + +/record_field/proc/can_edit(var/used_access) + if(!acccess_edit) + return TRUE + if(!used_access) + return FALSE + return islist(used_access) ? (acccess_edit in used_access) : acccess_edit == used_access + +/record_field/proc/can_see(var/used_access) + if(!acccess) + return TRUE + if(!used_access) + return FALSE + return islist(used_access) ? (acccess_edit in used_access) : acccess_edit == used_access + +#define GETTER_SETTER(KEY) /datum/computer_file/crew_record/proc/get_##KEY(){var/record_field/F = locate(/record_field/##KEY) in fields; if(F) return F.get_value()} \ +/datum/computer_file/crew_record/proc/set_##KEY(value){var/record_field/F = locate(/record_field/##KEY) in fields; if(F) return F.set_value(value)} + +// Fear not the preprocessor, for it is a friend. To add a field, use one of these, depending on value type and if you need special access to see it. +// It will also create getter/setter procs for record datum, named like /get_[key here]() /set_[key_here](value) e.g. get_name() set_name(value) +// Use getter setters to avoid errors caused by typoing the string key. +#define FIELD_SHORT(NAME, KEY) /record_field/##KEY/name = ##NAME; GETTER_SETTER(##KEY) +#define FIELD_SHORT_SECURE(NAME, KEY, ACCESS) FIELD_SHORT(##NAME, ##KEY); /record_field/##KEY/acccess = ##ACCESS + +#define FIELD_LONG(NAME, KEY) FIELD_SHORT(##NAME, ##KEY); /record_field/##KEY/valtype = EDIT_LONGTEXT +#define FIELD_LONG_SECURE(NAME, KEY, ACCESS) FIELD_LONG(##NAME, ##KEY); /record_field/##KEY/acccess = ##ACCESS + +#define FIELD_NUM(NAME, KEY) FIELD_SHORT(##NAME, ##KEY); /record_field/##KEY/valtype = EDIT_NUMERIC; /record_field/##KEY/value = 0 +#define FIELD_NUM_SECURE(NAME, KEY, ACCESS) FIELD_NUM(##NAME, ##KEY); /record_field/##KEY/acccess = ##ACCESS + +#define FIELD_LIST(NAME, KEY, OPTIONS) FIELD_SHORT(##NAME, ##KEY); /record_field/##KEY/valtype = EDIT_LIST; /record_field/##KEY/get_options(){. = ##OPTIONS;} +#define FIELD_LIST_SECURE(NAME, KEY, OPTIONS, ACCESS) FIELD_LIST(##NAME, ##KEY, ##OPTIONS); /record_field/##KEY/acccess = ##ACCESS + +// GENERIC RECORDS +FIELD_SHORT("Name",name) +FIELD_SHORT("Job",job) +FIELD_LIST("Sex", sex, record_genders()) +FIELD_NUM("Age", age) + +FIELD_LIST("Status", status, GLOB.physical_statuses) +/record_field/status/acccess_edit = access_medical + +//FIELD_SHORT("Species",species) +FIELD_LIST("Branch", branch, record_branches()) +FIELD_LIST("Rank", rank, record_ranks()) + +// MEDICAL RECORDS +FIELD_LIST("Blood Type", bloodtype, GLOB.blood_types) +FIELD_LONG_SECURE("Medical Record", medRecord, access_medical) + +// SECURITY RECORDS +FIELD_LIST_SECURE("Criminal Status", criminalStatus, GLOB.security_statuses, access_security) +FIELD_LONG_SECURE("Security Record", secRecord, access_security) +FIELD_SHORT_SECURE("DNA", dna, access_security) +FIELD_SHORT_SECURE("Fingerprint", fingerprint, access_security) + +// ANTAG RECORDS +FIELD_LONG_SECURE("Exploitable Information", antagRecord, access_syndicate) + +//Options builderes +/record_field/rank/proc/record_ranks() + for(var/datum/computer_file/crew_record/R in GLOB.all_crew_records) + if(R.uid == record_id) + var/datum/mil_branch/branch = mil_branches.get_branch(R.get_branch()) + if(!branch) + return null + . = list() + . |= "Unset" + for(var/rank in branch.ranks) + var/datum/mil_rank/RA = branch.ranks[rank] + . |= RA.name + +/record_field/sex/proc/record_genders() + . = list() + . |= "Unset" + for(var/G in gender_datums) + . |= gender2text(G) + +/record_field/branch/proc/record_branches() + . = list() + . |= "Unset" + for(var/B in mil_branches.branches) + var/datum/mil_branch/BR = mil_branches.branches[B] + . |= BR.name \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/data.dm b/code/modules/modular_computers/file_system/data.dm new file mode 100644 index 00000000..66a95a7a --- /dev/null +++ b/code/modules/modular_computers/file_system/data.dm @@ -0,0 +1,19 @@ +// /data/ files store data in string format. +// They don't contain other logic for now. +/datum/computer_file/data + var/stored_data = "" // Stored data in string format. + filetype = "DAT" + var/block_size = 250 + var/do_not_edit = 0 // Whether the user will be reminded that the file probably shouldn't be edited. + +/datum/computer_file/data/clone() + var/datum/computer_file/data/temp = ..() + temp.stored_data = stored_data + return temp + +// Calculates file size from amount of characters in saved string +/datum/computer_file/data/proc/calculate_size() + size = max(1, round(length(stored_data) / block_size)) + +/datum/computer_file/data/logfile + filetype = "LOG" \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/manifest.dm b/code/modules/modular_computers/file_system/manifest.dm new file mode 100644 index 00000000..e7a18b8b --- /dev/null +++ b/code/modules/modular_computers/file_system/manifest.dm @@ -0,0 +1,141 @@ +// Generates a simple HTML crew manifest for use in various places +/proc/html_crew_manifest(var/monochrome, var/OOC) + var/list/dept_data = list( + list("names" = list(), "header" = "Heads of Staff", "flag" = COM), + list("names" = list(), "header" = "Command Support", "flag" = SPT), + list("names" = list(), "header" = "Research", "flag" = SCI), + list("names" = list(), "header" = "Security", "flag" = SEC), + list("names" = list(), "header" = "Medical", "flag" = MED), + list("names" = list(), "header" = "Engineering", "flag" = ENG), + list("names" = list(), "header" = "Supply", "flag" = SUP), + list("names" = list(), "header" = "Exploration", "flag" = EXP), + list("names" = list(), "header" = "Service", "flag" = SRV), + list("names" = list(), "header" = "Civilian", "flag" = CIV), + list("names" = list(), "header" = "Miscellaneous", "flag" = MSC), + list("names" = list(), "header" = "Silicon") + ) + var/list/misc //Special departments for easier access + var/list/bot + for(var/list/department in dept_data) + if(department["flag"] == MSC) + misc = department["names"] + if(isnull(department["flag"])) + bot = department["names"] + + var/list/isactive = new() + var/list/mil_ranks = list() // HTML to prepend to name + var/dat = {" + + + + "} + // sort mobs + for(var/datum/computer_file/crew_record/CR in GLOB.all_crew_records) + var/name = CR.get_name() + var/rank = CR.get_job() + mil_ranks[name] = "" + + if(GLOB.using_map.flags & MAP_HAS_RANK) + var/datum/mil_branch/branch_obj = mil_branches.get_branch(CR.get_branch()) + var/datum/mil_rank/rank_obj = mil_branches.get_rank(CR.get_branch(), CR.get_rank()) + + if(branch_obj && rank_obj) + mil_ranks[name] = "[rank_obj.name_short] " + + if(OOC) + var/active = 0 + for(var/mob/M in GLOB.player_list) + if(M.real_name == name && M.client && M.client.inactivity <= 10 * 60 * 10) + active = 1 + break + isactive[name] = active ? "Active" : "Inactive" + else + isactive[name] = CR.get_status() + + var/datum/job/job = job_master.occupations_by_title[rank] + var/found_place = 0 + if(job) + for(var/list/department in dept_data) + var/list/names = department["names"] + if(job.department_flag & department["flag"]) + names[name] = rank + found_place = 1 + if(!found_place) + misc[name] = rank + + // Synthetics don't have actual records, so we will pull them from here. + for(var/mob/living/silicon/ai/ai in SSmobs.mob_list) + bot[ai.name] = "Artificial Intelligence" + + for(var/mob/living/silicon/robot/robot in SSmobs.mob_list) + // No combat/syndicate cyborgs, no drones. + if(robot.module && robot.module.hide_on_manifest) + continue + + bot[robot.name] = "[robot.modtype] [robot.braintype]" + + for(var/list/department in dept_data) + var/list/names = department["names"] + if(names.len > 0) + dat += "" + for(var/name in names) + dat += "" + + dat += "
            NamePositionActivity
            [department["header"]]
            [mil_ranks[name]][name][names[name]][isactive[name]]
            " + dat = replacetext(dat, "\n", "") // so it can be placed on paper correctly + dat = replacetext(dat, "\t", "") + return dat + +/proc/silicon_nano_crew_manifest(var/list/filter) + var/list/filtered_entries = list() + + for(var/mob/living/silicon/ai/ai in SSmobs.mob_list) + filtered_entries.Add(list(list( + "name" = ai.name, + "rank" = "Artificial Intelligence", + "status" = "" + ))) + for(var/mob/living/silicon/robot/robot in SSmobs.mob_list) + if(robot.module && robot.module.hide_on_manifest) + continue + filtered_entries.Add(list(list( + "name" = robot.name, + "rank" = "[robot.modtype] [robot.braintype]", + "status" = "" + ))) + return filtered_entries + +/proc/filtered_nano_crew_manifest(var/list/filter, var/blacklist = FALSE) + var/list/filtered_entries = list() + for(var/datum/computer_file/crew_record/CR in department_crew_manifest(filter, blacklist)) + filtered_entries.Add(list(list( + "name" = CR.get_name(), + "rank" = CR.get_job(), + "status" = CR.get_status(), + "branch" = CR.get_branch(), + "milrank" = CR.get_rank() + ))) + return filtered_entries + +/proc/nano_crew_manifest() + return list(\ + "heads" = filtered_nano_crew_manifest(GLOB.command_positions),\ + "spt" = filtered_nano_crew_manifest(GLOB.support_positions),\ + "sci" = filtered_nano_crew_manifest(GLOB.science_positions),\ + "sec" = filtered_nano_crew_manifest(GLOB.security_positions),\ + "eng" = filtered_nano_crew_manifest(GLOB.engineering_positions),\ + "med" = filtered_nano_crew_manifest(GLOB.medical_positions),\ + "sup" = filtered_nano_crew_manifest(GLOB.supply_positions),\ + "exp" = filtered_nano_crew_manifest(GLOB.exploration_positions),\ + "srv" = filtered_nano_crew_manifest(GLOB.service_positions),\ + "bot" = silicon_nano_crew_manifest(GLOB.nonhuman_positions),\ + "civ" = filtered_nano_crew_manifest(GLOB.civilian_positions),\ + "misc" = filtered_nano_crew_manifest(GLOB.unsorted_positions)\ + ) diff --git a/code/modules/modular_computers/file_system/news_article.dm b/code/modules/modular_computers/file_system/news_article.dm new file mode 100644 index 00000000..9af92e19 --- /dev/null +++ b/code/modules/modular_computers/file_system/news_article.dm @@ -0,0 +1,55 @@ +// /data/ files store data in string format. +// They don't contain other logic for now. +/datum/computer_file/data/news_article + filetype = "XNML" + filename = "Unknown News Entry" + block_size = 5000 // Results in smaller files + do_not_edit = 1 // Editing the file breaks most formatting due to some HTML tags not being accepted as input from average user. + var/server_file_path // File path to HTML file that will be loaded on server start. Example: '/news_articles/space_magazine_1.html'. Use the /news_articles/ folder! + var/archived // Set to 1 for older stuff + var/cover //filename of cover. + +/datum/computer_file/data/news_article/New(var/load_from_file = 0) + ..() + if(server_file_path && load_from_file) + stored_data = file2text(server_file_path) + calculate_size() + + +// NEWS DEFINITIONS BELOW THIS LINE + +/datum/computer_file/data/news_article/space/vol_one + filename = "SPACE Magazine vol. 1" + server_file_path = 'news_articles/space_magazine_1.html' + cover = "issue1.png" + archived = 1 + +/datum/computer_file/data/news_article/space/vol_two + filename = "SPACE Magazine vol. 2" + server_file_path = 'news_articles/space_magazine_2.html' + cover = "issue2.png" + archived = 1 + +/datum/computer_file/data/news_article/space/vol_three + filename = "SPACE Magazine vol. 3" + server_file_path = 'news_articles/space_magazine_3.html' + cover = "issue3.png" + archived = 1 + +/datum/computer_file/data/news_article/space/vol_four + filename = "SPACE Magazine vol. 4" + server_file_path = 'news_articles/space_magazine_4.html' + cover = "issue4.png" + archived = 1 + +/datum/computer_file/data/news_article/space/vol_five + filename = "SPACE Magazine vol. 5" + server_file_path = 'news_articles/space_magazine_5.html' + cover = "issue5.png" + archived = 0 + +/datum/computer_file/data/news_article/space/vol_six + filename = "SPACE Magazine vol. 6" + server_file_path = 'news_articles/space_magazine_6.html' + cover = "issue6.png" + archived = 0 \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm new file mode 100644 index 00000000..8e538efc --- /dev/null +++ b/code/modules/modular_computers/file_system/program.dm @@ -0,0 +1,210 @@ +// /program/ files are executable programs that do things. +/datum/computer_file/program + filetype = "PRG" + filename = "UnknownProgram" // File name. FILE NAME MUST BE UNIQUE IF YOU WANT THE PROGRAM TO BE DOWNLOADABLE FROM NTNET! + var/required_access = null // List of required accesses to run/download the program. + var/requires_access_to_run = FALSE // Whether the program checks for required_access when run. + var/requires_access_to_download = 1 // Whether the program checks for required_access when downloading. + var/datum/nano_module/NM = null // If the program uses NanoModule, put it here and it will be automagically opened. Otherwise implement ui_interact. + var/nanomodule_path = null // Path to nanomodule, make sure to set this if implementing new program. + var/program_state = PROGRAM_STATE_KILLED// PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running. + var/obj/item/modular_computer/computer // Device that runs this program. + var/filedesc = "Unknown Program" // User-friendly name of this program. + var/extended_desc = "N/A" // Short description of this program's function. + var/program_icon_state = null // Program-specific screen icon state + var/program_key_state = "standby_key" // Program-specific keyboard icon state + var/program_menu_icon = "newwin" // Icon to use for program's link in main menu + var/requires_ntnet = 0 // Set to 1 for program to require nonstop NTNet connection to run. If NTNet connection is lost program crashes. + var/requires_ntnet_feature = 0 // Optional, if above is set to 1 checks for specific function of NTNet (currently NTNET_SOFTWAREDOWNLOAD, NTNET_PEERTOPEER, NTNET_SYSTEMCONTROL and NTNET_COMMUNICATION) + var/ntnet_status = 1 // NTNet status, updated every tick by computer running this program. Don't use this for checks if NTNet works, computers do that. Use this for calculations, etc. + var/usage_flags = PROGRAM_ALL // Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET combination) or PROGRAM_ALL + var/network_destination = null // Optional string that describes what NTNet server/system this program connects to. Used in default logging. + var/available_on_ntnet = 1 // Whether the program can be downloaded from NTNet. Set to 0 to disable. + var/available_on_syndinet = 0 // Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable. + var/computer_emagged = 0 // Set to 1 if computer that's running us was emagged. Computer updates this every Process() tick + var/ui_header = null // Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /nano/images/status_icons. Be careful not to use too large images! + var/ntnet_speed = 0 // GQ/s - current network connectivity transfer rate + +/datum/computer_file/program/New(var/obj/item/modular_computer/comp = null) + ..() + if(comp && istype(comp)) + computer = comp + +/datum/computer_file/program/Destroy() + computer = null + . = ..() + +/datum/computer_file/program/nano_host() + return computer.nano_host() + +/datum/computer_file/program/clone() + var/datum/computer_file/program/temp = ..() + temp.required_access = required_access + temp.nanomodule_path = nanomodule_path + temp.filedesc = filedesc + temp.program_icon_state = program_icon_state + temp.requires_ntnet = requires_ntnet + temp.requires_ntnet_feature = requires_ntnet_feature + temp.usage_flags = usage_flags + return temp + +// Relays icon update to the computer. +/datum/computer_file/program/proc/update_computer_icon() + if(computer) + computer.update_icon() + +// Attempts to create a log in global ntnet datum. Returns 1 on success, 0 on fail. +/datum/computer_file/program/proc/generate_network_log(var/text) + if(computer) + return computer.add_log(text) + return 0 + +/datum/computer_file/program/proc/is_supported_by_hardware(var/hardware_flag = 0, var/loud = 0, var/mob/user = null) + if(!(hardware_flag & usage_flags)) + if(loud && computer && user) + to_chat(user, "\The [computer] flashes: \"Hardware Error - Incompatible software\".") + return 0 + return 1 + +/datum/computer_file/program/proc/get_signal(var/specific_action = 0) + if(computer) + return computer.get_ntnet_status(specific_action) + return 0 + +// Called by Process() on device that runs us, once every tick. +/datum/computer_file/program/proc/process_tick() + update_netspeed() + return 1 + +/datum/computer_file/program/proc/update_netspeed() + ntnet_speed = 0 + switch(ntnet_status) + if(1) + ntnet_speed = NTNETSPEED_LOWSIGNAL + if(2) + ntnet_speed = NTNETSPEED_HIGHSIGNAL + if(3) + ntnet_speed = NTNETSPEED_ETHERNET + +// Check if the user can run program. Only humans can operate computer. Automatically called in run_program() +// User has to wear their ID or have it inhand for ID Scan to work. +// Can also be called manually, with optional parameter being access_to_check to scan the user's ID +/datum/computer_file/program/proc/can_run(var/mob/living/user, var/loud = 0, var/access_to_check) + // Defaults to required_access + if(!access_to_check) + access_to_check = required_access + if(!access_to_check) // No required_access, allow it. + return 1 + + // Admin override - allows operation of any computer as aghosted admin, as if you had any required access. + if(isghost(user) && check_rights(R_ADMIN, 0, user)) + return 1 + + if(!istype(user)) + return 0 + + var/obj/item/weapon/card/id/I = user.GetIdCard() + if(!I) + if(loud) + to_chat(user, "\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning.") + return 0 + + if(access_to_check in I.access) + return 1 + else if(loud) + to_chat(user, "\The [computer] flashes an \"Access Denied\" warning.") + +// This attempts to retrieve header data for NanoUIs. If implementing completely new device of different type than existing ones +// always include the device here in this proc. This proc basically relays the request to whatever is running the program. +/datum/computer_file/program/proc/get_header_data() + if(computer) + return computer.get_header_data() + return list() + +// This is performed on program startup. May be overriden to add extra logic. Remember to include ..() call. Return 1 on success, 0 on failure. +// When implementing new program based device, use this to run the program. +/datum/computer_file/program/proc/run_program(var/mob/living/user) + if(can_run(user, 1) || !requires_access_to_run) + if(nanomodule_path) + NM = new nanomodule_path(src, new /datum/topic_manager/program(src), src) + NM.using_access = user.GetAccess() + if(requires_ntnet && network_destination) + generate_network_log("Connection opened to [network_destination].") + program_state = PROGRAM_STATE_ACTIVE + return 1 + return 0 + +// Use this proc to kill the program. Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client. +/datum/computer_file/program/proc/kill_program(var/forced = 0) + program_state = PROGRAM_STATE_KILLED + if(network_destination) + generate_network_log("Connection to [network_destination] closed.") + if(NM) + qdel(NM) + NM = null + return 1 + +// This is called every tick when the program is enabled. Ensure you do parent call if you override it. If parent returns 1 continue with UI initialisation. +// It returns 0 if it can't run or if NanoModule was used instead. I suggest using NanoModules where applicable. +/datum/computer_file/program/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(program_state != PROGRAM_STATE_ACTIVE) // Our program was closed. Close the ui if it exists. + if(ui) + ui.close() + return computer.ui_interact(user) + if(istype(NM)) + NM.ui_interact(user, ui_key, null, force_open) + return 0 + return 1 + + +// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC: +// Topic calls are automagically forwarded from NanoModule this program contains. +// Calls beginning with "PRG_" are reserved for programs handling. +// Calls beginning with "PC_" are reserved for computer handling (by whatever runs the program) +// ALWAYS INCLUDE PARENT CALL ..() OR DIE IN FIRE. +/datum/computer_file/program/Topic(href, href_list) + if(..()) + return 1 + if(computer) + return computer.Topic(href, href_list) + +// Relays the call to nano module, if we have one +/datum/computer_file/program/proc/check_eye(var/mob/user) + if(NM) + return NM.check_eye(user) + else + return -1 + +/obj/item/modular_computer/initial_data() + return get_header_data() + +/obj/item/modular_computer/update_layout() + return TRUE + +/datum/nano_module/program + available_to_ai = FALSE + var/datum/computer_file/program/program = null // Program-Based computer program that runs this nano module. Defaults to null. + +/datum/nano_module/program/New(var/host, var/topic_manager, var/program) + ..() + src.program = program + +/datum/topic_manager/program + var/datum/program + +/datum/topic_manager/program/New(var/datum/program) + ..() + src.program = program + +// Calls forwarded to PROGRAM itself should begin with "PRG_" +// Calls forwarded to COMPUTER running the program should begin with "PC_" +/datum/topic_manager/program/Topic(href, href_list) + return program && program.Topic(href, href_list) + +/datum/computer_file/program/apply_visual(mob/M) + if(NM) + NM.apply_visual(M) + +/datum/computer_file/program/remove_visual(mob/M) + if(NM) + NM.remove_visual(M) diff --git a/code/modules/modular_computers/file_system/program_events.dm b/code/modules/modular_computers/file_system/program_events.dm new file mode 100644 index 00000000..2b3240b4 --- /dev/null +++ b/code/modules/modular_computers/file_system/program_events.dm @@ -0,0 +1,18 @@ +// Events are sent to the program by the computer. +// Always include a parent call when overriding an event. + +// Called when the ID card is removed from computer. ID is removed AFTER this proc. +/datum/computer_file/program/proc/event_idremoved(var/background) + return + +// Called when the computer fails due to power loss. Override when program wants to specifically react to power loss. +/datum/computer_file/program/proc/event_powerfailure(var/background) + kill_program(1) + +// Called when the network connectivity fails. Computer does necessary checks and only calls this when requires_ntnet_feature and similar variables are not met. +/datum/computer_file/program/proc/event_networkfailure(var/background) + kill_program(1) + if(background) + computer.visible_message("\The [computer]'s screen displays an error: \"Network connectivity lost - process [filename].[filetype] (PID [rand(100,999)]) terminated.\"", range = 1) + else + computer.visible_message("\The [computer]'s screen briefly freezes and then shows: \"FATAL NETWORK ERROR - NTNet connection lost. Please try again later. If problem persists, please contact your system administrator.\"", range = 1) \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm b/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm new file mode 100644 index 00000000..1296fadf --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm @@ -0,0 +1,107 @@ +/datum/computer_file/program/access_decrypter + filename = "nt_accrypt" + filedesc = "NTNet Access Decrypter" + program_icon_state = "hostile" + program_key_state = "security_key" + program_menu_icon = "unlocked" + extended_desc = "This highly advanced script can very slowly decrypt operational codes used in almost any network. These codes can be downloaded to an ID card to expand the available access. The system administrator will probably notice this." + size = 34 + requires_ntnet = 1 + available_on_ntnet = 0 + available_on_syndinet = 1 + nanomodule_path = /datum/nano_module/program/access_decrypter/ + var/message = "" + var/running = FALSE + var/progress = 0 + var/target_progress = 300 + +/datum/computer_file/program/access_decrypter/kill_program(var/forced) + reset() + ..(forced) + +/datum/computer_file/program/access_decrypter/proc/reset() + running = FALSE + message = "" + progress = 0 + +/datum/computer_file/program/access_decrypter/process_tick() + . = ..() + if(!running) + return + var/obj/item/weapon/computer_hardware/processor_unit/CPU = computer.processor_unit + var/obj/item/weapon/computer_hardware/card_slot/RFID = computer.card_slot + if(!istype(CPU) || !CPU.check_functionality() || !istype(RFID) || !RFID.check_functionality()) + message = "A fatal hardware error has been detected." + return + if(!istype(RFID.stored_card)) + message = "RFID card has been removed from the device. Operation aborted." + return + + progress += CPU.max_idle_programs + if(progress >= target_progress) + reset() + var/datum/access/A = get_access_by_id(pick(get_all_station_access())) + RFID.stored_card.access |= A.id + if(ntnet_global.intrusion_detection_enabled) + ntnet_global.add_log("IDS WARNING - Unauthorised access to primary keycode database from device: [computer.network_card.get_network_tag()] - downloaded access codes for: [A.desc].") + ntnet_global.intrusion_detection_alarm = 1 + message = "Successfully decrypted and saved operational key codes. Downloaded access codes for: [A.desc]" + +/datum/computer_file/program/access_decrypter/Topic(href, href_list) + if(..()) + return 1 + if(href_list["PRG_reset"]) + reset() + return 1 + if(href_list["PRG_execute"]) + if(running) + return 1 + var/obj/item/weapon/computer_hardware/processor_unit/CPU = computer.processor_unit + var/obj/item/weapon/computer_hardware/card_slot/RFID = computer.card_slot + if(!istype(CPU) || !CPU.check_functionality() || !istype(RFID) || !RFID.check_functionality()) + message = "A fatal hardware error has been detected." + return + if(!istype(RFID.stored_card)) + message = "RFID card is not present in the device. Operation aborted." + return + running = TRUE + if(ntnet_global.intrusion_detection_enabled) + ntnet_global.add_log("IDS WARNING - Unauthorised access attempt to primary keycode database from device: [computer.network_card.get_network_tag()]") + ntnet_global.intrusion_detection_alarm = 1 + return 1 + +/datum/nano_module/program/access_decrypter + name = "NTNet Access Decrypter" + +/datum/nano_module/program/access_decrypter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + if(!ntnet_global) + return + var/datum/computer_file/program/access_decrypter/PRG = program + var/list/data = list() + if(!istype(PRG)) + return + data = PRG.get_header_data() + + if(PRG.message) + data["message"] = PRG.message + else if(PRG.running) + data["running"] = 1 + data["rate"] = PRG.computer.processor_unit.max_idle_programs + + // Stolen from DOS traffic generator, generates strings of 1s and 0s + var/percentage = (PRG.progress / PRG.target_progress) * 100 + var/list/strings[0] + for(var/j, j<10, j++) + var/string = "" + for(var/i, i<20, i++) + string = "[string][prob(percentage)]" + strings.Add(string) + data["dos_strings"] = strings + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "access_decrypter.tmpl", "NTNet Access Decrypter", 550, 400, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm new file mode 100644 index 00000000..7498fa69 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm @@ -0,0 +1,108 @@ +/datum/computer_file/program/ntnet_dos + filename = "ntn_dos" + filedesc = "DoS Traffic Generator" + program_icon_state = "hostile" + program_key_state = "security_key" + program_menu_icon = "arrow-4-diag" + extended_desc = "This advanced script can perform denial of service attacks against NTNet quantum relays. The system administrator will probably notice this. Multiple devices can run this program together against same relay for increased effect" + size = 20 + requires_ntnet = 1 + available_on_ntnet = 0 + available_on_syndinet = 1 + nanomodule_path = /datum/nano_module/program/computer_dos/ + var/obj/machinery/ntnet_relay/target = null + var/dos_speed = 0 + var/error = "" + var/executed = 0 + +/datum/computer_file/program/ntnet_dos/process_tick() + dos_speed = 0 + switch(ntnet_status) + if(1) + dos_speed = NTNETSPEED_LOWSIGNAL * NTNETSPEED_DOS_AMPLIFICATION + if(2) + dos_speed = NTNETSPEED_HIGHSIGNAL * NTNETSPEED_DOS_AMPLIFICATION + if(3) + dos_speed = NTNETSPEED_ETHERNET * NTNETSPEED_DOS_AMPLIFICATION + if(target && executed) + target.dos_overload += dos_speed + if(!target.operable()) + target.dos_sources.Remove(src) + target = null + error = "Connection to destination relay lost." + +/datum/computer_file/program/ntnet_dos/kill_program(var/forced) + if(target) + target.dos_sources.Remove(src) + target = null + executed = 0 + + ..(forced) + +/datum/nano_module/program/computer_dos + name = "DoS Traffic Generator" + +/datum/nano_module/program/computer_dos/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + if(!ntnet_global) + return + var/datum/computer_file/program/ntnet_dos/PRG = program + var/list/data = list() + if(!istype(PRG)) + return + data = PRG.get_header_data() + + if(PRG.error) + data["error"] = PRG.error + else if(PRG.target && PRG.executed) + data["target"] = 1 + data["speed"] = PRG.dos_speed + + // This is mostly visual, generate some strings of 1s and 0s + // Probability of 1 is equal of completion percentage of DoS attack on this relay. + // Combined with UI updates this adds quite nice effect to the UI + var/percentage = PRG.target.dos_overload * 100 / PRG.target.dos_capacity + var/list/strings[0] + for(var/j, j<10, j++) + var/string = "" + for(var/i, i<20, i++) + string = "[string][prob(percentage)]" + strings.Add(string) + data["dos_strings"] = strings + else + var/list/relays[0] + for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays) + relays.Add(R.uid) + data["relays"] = relays + data["focus"] = PRG.target ? PRG.target.uid : null + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "ntnet_dos.tmpl", "DoS Traffic Generator", 400, 250, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/computer_file/program/ntnet_dos/Topic(href, href_list) + if(..()) + return 1 + if(href_list["PRG_target_relay"]) + for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays) + if("[R.uid]" == href_list["PRG_target_relay"]) + target = R + return 1 + if(href_list["PRG_reset"]) + if(target) + target.dos_sources.Remove(src) + target = null + executed = 0 + error = "" + return 1 + if(href_list["PRG_execute"]) + if(target) + executed = 1 + target.dos_sources.Add(src) + if(ntnet_global.intrusion_detection_enabled) + ntnet_global.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [computer.network_card.get_network_tag()]") + ntnet_global.intrusion_detection_alarm = 1 + return 1 diff --git a/code/modules/modular_computers/file_system/programs/antagonist/hacked_camera.dm b/code/modules/modular_computers/file_system/programs/antagonist/hacked_camera.dm new file mode 100644 index 00000000..ef5aaf02 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/antagonist/hacked_camera.dm @@ -0,0 +1,39 @@ +/datum/computer_file/program/camera_monitor/hacked + filename = "camcrypt" + filedesc = "Camera Decryption Tool" + nanomodule_path = /datum/nano_module/camera_monitor/hacked + program_icon_state = "hostile" + program_key_state = "security_key" + program_menu_icon = "zoomin" + extended_desc = "This very advanced piece of software uses adaptive programming and large database of cipherkeys to bypass most encryptions used on camera networks. Be warned that system administrator may notice this." + size = 73 // Very large, a price for bypassing ID checks completely. + available_on_ntnet = 0 + available_on_syndinet = 1 + +/datum/computer_file/program/camera_monitor/hacked/process_tick() + ..() + if(program_state != PROGRAM_STATE_ACTIVE) // Background programs won't trigger alarms. + return + + var/datum/nano_module/camera_monitor/hacked/HNM = NM + + // The program is active and connected to one of the station's networks. Has a very small chance to trigger IDS alarm every tick. + if(HNM && HNM.current_network && (HNM.current_network in GLOB.using_map.station_networks) && prob(0.1)) + if(ntnet_global.intrusion_detection_enabled) + ntnet_global.add_log("IDS WARNING - Unauthorised access detected to camera network [HNM.current_network] by device with NID [computer.network_card.get_network_tag()]") + ntnet_global.intrusion_detection_alarm = 1 + + +/datum/nano_module/camera_monitor/hacked + name = "Hacked Camera Monitoring Program" + available_to_ai = FALSE + +/datum/nano_module/camera_monitor/hacked/can_access_network(var/mob/user, var/network_access) + return 1 + +// The hacked variant has access to all commonly used networks. +/datum/nano_module/camera_monitor/hacked/modify_networks_list(var/list/networks) + networks.Add(list(list("tag" = NETWORK_MERCENARY, "has_access" = 1))) + networks.Add(list(list("tag" = NETWORK_ERT, "has_access" = 1))) + networks.Add(list(list("tag" = NETWORK_CRESCENT, "has_access" = 1))) + return networks \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm new file mode 100644 index 00000000..981cff27 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm @@ -0,0 +1,84 @@ +/datum/computer_file/program/revelation + filename = "revelation" + filedesc = "Revelation" + program_icon_state = "hostile" + program_key_state = "security_key" + program_menu_icon = "home" + extended_desc = "This virus can destroy hard drive of system it is executed on. It may be obfuscated to look like another non-malicious program. Once armed, it will destroy the system upon next execution." + size = 13 + requires_ntnet = 0 + available_on_ntnet = 0 + available_on_syndinet = 1 + nanomodule_path = /datum/nano_module/program/revelation/ + var/armed = 0 + +/datum/computer_file/program/revelation/run_program(var/mob/living/user) + . = ..(user) + if(armed) + activate() + +/datum/computer_file/program/revelation/proc/activate() + if(!computer) + return + + computer.visible_message("\The [computer]'s screen brightly flashes and loud electrical buzzing is heard.") + computer.enabled = 0 + computer.update_icon() + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(10, 1, computer.loc) + s.start() + + if(computer.hard_drive) + qdel(computer.hard_drive) + + if(computer.battery_module && prob(25)) + qdel(computer.battery_module) + + if(computer.tesla_link && prob(50)) + qdel(computer.tesla_link) + +/datum/computer_file/program/revelation/Topic(href, href_list) + if(..()) + return 1 + else if(href_list["PRG_arm"]) + armed = !armed + else if(href_list["PRG_activate"]) + activate() + else if(href_list["PRG_obfuscate"]) + var/mob/living/user = usr + var/newname = sanitize(input(user, "Enter new program name: ")) + if(!newname) + return + filedesc = newname + for(var/datum/computer_file/program/P in ntnet_global.available_station_software) + if(filedesc == P.filedesc) + program_menu_icon = P.program_menu_icon + break + return 1 + +/datum/computer_file/program/revelation/clone() + var/datum/computer_file/program/revelation/temp = ..() + temp.armed = armed + return temp + +/datum/nano_module/program/revelation + name = "Revelation Virus" + +/datum/nano_module/program/revelation/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = list() + var/datum/computer_file/program/revelation/PRG = program + if(!istype(PRG)) + return + + data = PRG.get_header_data() + + data["armed"] = PRG.armed + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "revelation.tmpl", "Revelation Virus", 400, 250, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + diff --git a/code/modules/modular_computers/file_system/programs/command/card.dm b/code/modules/modular_computers/file_system/programs/command/card.dm new file mode 100644 index 00000000..3ddc82bc --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/command/card.dm @@ -0,0 +1,234 @@ +/datum/computer_file/program/card_mod + filename = "cardmod" + filedesc = "ID card modification program" + nanomodule_path = /datum/nano_module/program/card_mod + program_icon_state = "id" + program_key_state = "id_key" + program_menu_icon = "key" + extended_desc = "Program for programming crew ID cards." + required_access = access_change_ids + requires_ntnet = 0 + size = 8 + +/datum/nano_module/program/card_mod + name = "ID card modification program" + var/mod_mode = 1 + var/is_centcom = 0 + var/show_assignments = 0 + +/datum/nano_module/program/card_mod/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + + data["src"] = "\ref[src]" + data["station_name"] = station_name() + data["manifest"] = html_crew_manifest() + data["assignments"] = show_assignments + if(program && program.computer) + data["have_id_slot"] = !!program.computer.card_slot + data["have_printer"] = !!program.computer.nano_printer + data["authenticated"] = program.can_run(user) + if(!program.computer.card_slot) + mod_mode = 0 //We can't modify IDs when there is no card reader + else + data["have_id_slot"] = 0 + data["have_printer"] = 0 + data["authenticated"] = 0 + data["mmode"] = mod_mode + data["centcom_access"] = is_centcom + + if(program && program.computer && program.computer.card_slot) + var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card + data["has_id"] = !!id_card + data["id_account_number"] = id_card ? id_card.associated_account_number : null + data["id_rank"] = id_card && id_card.assignment ? id_card.assignment : "Unassigned" + data["id_owner"] = id_card && id_card.registered_name ? id_card.registered_name : "-----" + data["id_name"] = id_card ? id_card.name : "-----" + + data["command_jobs"] = format_jobs(GLOB.command_positions) + data["support_jobs"] = format_jobs(GLOB.support_positions) + data["engineering_jobs"] = format_jobs(GLOB.engineering_positions) + data["medical_jobs"] = format_jobs(GLOB.medical_positions) + data["science_jobs"] = format_jobs(GLOB.science_positions) + data["security_jobs"] = format_jobs(GLOB.security_positions) + data["exploration_jobs"] = format_jobs(GLOB.exploration_positions) + data["service_jobs"] = format_jobs(GLOB.service_positions) + data["supply_jobs"] = format_jobs(GLOB.supply_positions) + data["civilian_jobs"] = format_jobs(GLOB.civilian_positions) + data["centcom_jobs"] = format_jobs(get_all_centcom_jobs()) + + data["all_centcom_access"] = is_centcom ? get_accesses(1) : null + data["regions"] = get_accesses() + + if(program.computer.card_slot && program.computer.card_slot.stored_card) + var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card + if(is_centcom) + var/list/all_centcom_access = list() + for(var/access in get_all_centcom_access()) + all_centcom_access.Add(list(list( + "desc" = replacetext(get_centcom_access_desc(access), " ", " "), + "ref" = access, + "allowed" = (access in id_card.access) ? 1 : 0))) + data["all_centcom_access"] = all_centcom_access + else + var/list/regions = list() + for(var/i = 1; i <= 7; i++) + var/list/accesses = list() + for(var/access in get_region_accesses(i)) + if (get_access_desc(access)) + accesses.Add(list(list( + "desc" = replacetext(get_access_desc(access), " ", " "), + "ref" = access, + "allowed" = (access in id_card.access) ? 1 : 0))) + + regions.Add(list(list( + "name" = get_region_accesses_name(i), + "accesses" = accesses))) + data["regions"] = regions + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "identification_computer.tmpl", name, 600, 700, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + +/datum/nano_module/program/card_mod/proc/format_jobs(list/jobs) + var/obj/item/weapon/card/id/id_card = program.computer.card_slot ? program.computer.card_slot.stored_card : null + var/list/formatted = list() + for(var/job in jobs) + formatted.Add(list(list( + "display_name" = replacetext(job, " ", " "), + "target_rank" = id_card && id_card.assignment ? id_card.assignment : "Unassigned", + "job" = job))) + + return formatted + +/datum/nano_module/program/card_mod/proc/get_accesses(var/is_centcom = 0) + return null + + +/datum/computer_file/program/card_mod/Topic(href, href_list) + if(..()) + return 1 + + var/mob/user = usr + var/obj/item/weapon/card/id/user_id_card = user.GetIdCard() + var/obj/item/weapon/card/id/id_card + if (computer.card_slot) + id_card = computer.card_slot.stored_card + + var/datum/nano_module/program/card_mod/module = NM + switch(href_list["action"]) + if("switchm") + if(href_list["target"] == "mod") + module.mod_mode = 1 + else if (href_list["target"] == "manifest") + module.mod_mode = 0 + if("togglea") + if(module.show_assignments) + module.show_assignments = 0 + else + module.show_assignments = 1 + if("print") + if(computer && computer.nano_printer) //This option should never be called if there is no printer + if(module.mod_mode) + if(can_run(user, 1)) + var/contents = {"

            Access Report

            + Prepared By: [user_id_card.registered_name ? user_id_card.registered_name : "Unknown"]
            + For: [id_card.registered_name ? id_card.registered_name : "Unregistered"]
            +
            + Assignment: [id_card.assignment]
            + Account Number: #[id_card.associated_account_number]
            + Blood Type: [id_card.blood_type]

            + Access:
            + "} + + var/known_access_rights = get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM) + for(var/A in id_card.access) + if(A in known_access_rights) + contents += " [get_access_desc(A)]" + + if(!computer.nano_printer.print_text(contents,"access report")) + to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") + return + else + computer.visible_message("\The [computer] prints out paper.") + else + var/contents = {"

            Crew Manifest

            +
            + [html_crew_manifest()] + "} + if(!computer.nano_printer.print_text(contents,text("crew manifest ([])", stationtime2text()))) + to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") + return + else + computer.visible_message("\The [computer] prints out paper.") + if("eject") + if(computer && computer.card_slot) + computer.proc_eject_id(user) + if("terminate") + if(computer && can_run(user, 1)) + id_card.assignment = "Terminated" + remove_nt_access(id_card) + callHook("terminate_employee", list(id_card)) + if("edit") + if(computer && can_run(user, 1)) + if(href_list["name"]) + var/temp_name = sanitizeName(input("Enter name.", "Name", id_card.registered_name),allow_numbers=TRUE) + if(temp_name) + id_card.registered_name = temp_name + else + computer.visible_message("[computer] buzzes rudely.") + else if(href_list["account"]) + var/account_num = text2num(input("Enter account number.", "Account", id_card.associated_account_number)) + id_card.associated_account_number = account_num + if("assign") + if(computer && can_run(user, 1) && id_card) + var/t1 = href_list["assign_target"] + if(t1 == "Custom") + var/temp_t = sanitize(input("Enter a custom job assignment.","Assignment", id_card.assignment), 45) + //let custom jobs function as an impromptu alt title, mainly for sechuds + if(temp_t) + id_card.assignment = temp_t + else + var/list/access = list() + if(module.is_centcom) + access = get_centcom_access(t1) + else + var/datum/job/jobdatum + for(var/jobtype in typesof(/datum/job)) + var/datum/job/J = new jobtype + if(ckey(J.title) == ckey(t1)) + jobdatum = J + break + if(!jobdatum) + to_chat(usr, "No log exists for this job: [t1]") + return + + access = jobdatum.get_access() + + remove_nt_access(id_card) + apply_access(id_card, access) + id_card.assignment = t1 + id_card.rank = t1 + + callHook("reassign_employee", list(id_card)) + if("access") + if(href_list["allowed"] && computer && can_run(user, 1)) + var/access_type = text2num(href_list["access_target"]) + var/access_allowed = text2num(href_list["allowed"]) + if(access_type in get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM)) + id_card.access -= access_type + if(!access_allowed) + id_card.access += access_type + if(id_card) + id_card.SetName(text("[id_card.registered_name]'s ID Card ([id_card.assignment])")) + + GLOB.nanomanager.update_uis(NM) + return 1 + +/datum/computer_file/program/card_mod/proc/remove_nt_access(var/obj/item/weapon/card/id/id_card) + id_card.access -= get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM) + +/datum/computer_file/program/card_mod/proc/apply_access(var/obj/item/weapon/card/id/id_card, var/list/accesses) + id_card.access |= accesses diff --git a/code/modules/modular_computers/file_system/programs/command/comm.dm b/code/modules/modular_computers/file_system/programs/command/comm.dm new file mode 100644 index 00000000..58990282 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/command/comm.dm @@ -0,0 +1,365 @@ +#define STATE_DEFAULT 1 +#define STATE_MESSAGELIST 2 +#define STATE_VIEWMESSAGE 3 +#define STATE_STATUSDISPLAY 4 +#define STATE_ALERT_LEVEL 5 +/datum/computer_file/program/comm + filename = "comm" + filedesc = "Command and Communications Program" + program_icon_state = "comm" + program_key_state = "med_key" + program_menu_icon = "flag" + nanomodule_path = /datum/nano_module/program/comm + extended_desc = "Used to command and control. Can relay long-range communications. This program can not be run on tablet computers." + required_access = access_heads + requires_ntnet = 1 + size = 12 + usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP + network_destination = "long-range communication array" + var/datum/comm_message_listener/message_core = new + +/datum/computer_file/program/comm/clone() + var/datum/computer_file/program/comm/temp = ..() + temp.message_core.messages = null + temp.message_core.messages = message_core.messages.Copy() + return temp + +/datum/nano_module/program/comm + name = "Command and Communications Program" + available_to_ai = TRUE + var/current_status = STATE_DEFAULT + var/msg_line1 = "" + var/msg_line2 = "" + var/centcomm_message_cooldown = 0 + var/announcment_cooldown = 0 + var/datum/announcement/priority/crew_announcement = new + var/current_viewing_message_id = 0 + var/current_viewing_message = null + +/datum/nano_module/program/comm/New() + ..() + crew_announcement.newscast = 1 + +/datum/nano_module/program/comm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + + var/list/data = host.initial_data() + + if(program) + data["emagged"] = program.computer_emagged + data["net_comms"] = !!program.get_signal(NTNET_COMMUNICATION) //Double !! is needed to get 1 or 0 answer + data["net_syscont"] = !!program.get_signal(NTNET_SYSTEMCONTROL) + if(program.computer) + data["have_printer"] = !!program.computer.nano_printer + else + data["have_printer"] = 0 + else + data["emagged"] = 0 + data["net_comms"] = 1 + data["net_syscont"] = 1 + data["have_printer"] = 0 + + data["message_line1"] = msg_line1 + data["message_line2"] = msg_line2 + data["state"] = current_status + data["isAI"] = issilicon(usr) + data["authenticated"] = is_autenthicated(user) + data["boss_short"] = GLOB.using_map.boss_short + + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + data["current_security_level_ref"] = any2ref(security_state.current_security_level) + data["current_security_level_title"] = security_state.current_security_level.name + + data["cannot_change_security_level"] = !security_state.can_change_security_level() + var/list/security_levels = list() + for(var/decl/security_level/security_level in security_state.standard_security_levels) + var/list/security_setup = list() + security_setup["title"] = security_level.name + security_setup["ref"] = any2ref(security_level) + security_levels[++security_levels.len] = security_setup + data["security_levels"] = security_levels + + var/datum/comm_message_listener/l = obtain_message_listener() + data["messages"] = l.messages + data["message_deletion_allowed"] = l != global_message_listener + data["message_current_id"] = current_viewing_message_id + if(current_viewing_message) + data["message_current"] = current_viewing_message + + var/list/processed_evac_options = list() + if(!isnull(evacuation_controller)) + for (var/datum/evacuation_option/EO in evacuation_controller.available_evac_options()) + var/list/option = list() + option["option_text"] = EO.option_text + option["option_target"] = EO.option_target + option["needs_syscontrol"] = EO.needs_syscontrol + option["silicon_allowed"] = EO.silicon_allowed + processed_evac_options[++processed_evac_options.len] = option + data["evac_options"] = processed_evac_options + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "communication.tmpl", name, 550, 420, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + +/datum/nano_module/program/comm/proc/is_autenthicated(var/mob/user) + if(program) + return program.can_run(user) + return 1 + +/datum/nano_module/program/comm/proc/obtain_message_listener() + if(program) + var/datum/computer_file/program/comm/P = program + return P.message_core + return global_message_listener + +/datum/nano_module/program/comm/Topic(href, href_list) + if(..()) + return 1 + var/mob/user = usr + var/ntn_comm = program ? !!program.get_signal(NTNET_COMMUNICATION) : 1 + var/ntn_cont = program ? !!program.get_signal(NTNET_SYSTEMCONTROL) : 1 + var/datum/comm_message_listener/l = obtain_message_listener() + switch(href_list["action"]) + if("sw_menu") + . = 1 + current_status = text2num(href_list["target"]) + if("announce") + . = 1 + if(is_autenthicated(user) && !issilicon(usr) && ntn_comm) + if(user) + var/obj/item/weapon/card/id/id_card = user.GetIdCard() + crew_announcement.announcer = GetNameAndAssignmentFromId(id_card) + else + crew_announcement.announcer = "Unknown" + if(announcment_cooldown) + to_chat(usr, "Please allow at least one minute to pass between announcements") + return TRUE + var/input = input(usr, "Please write a message to announce to the [station_name()].", "Priority Announcement") as null|text + if(!input || !can_still_topic()) + return 1 + crew_announcement.Announce(input) + announcment_cooldown = 1 + spawn(600)//One minute cooldown + announcment_cooldown = 0 + if("message") + . = 1 + if(href_list["target"] == "emagged") + if(program) + if(is_autenthicated(user) && program.computer_emagged && !issilicon(usr) && ntn_comm) + if(centcomm_message_cooldown) + to_chat(usr, "Arrays recycling. Please stand by.") + GLOB.nanomanager.update_uis(src) + return + var/input = sanitize(input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "") as null|text) + if(!input || !can_still_topic()) + return 1 + Syndicate_announce(input, usr) + to_chat(usr, "Message transmitted.") + log_say("[key_name(usr)] has made an illegal announcement: [input]") + centcomm_message_cooldown = 1 + spawn(300)//30 second cooldown + centcomm_message_cooldown = 0 + else if(href_list["target"] == "regular") + if(is_autenthicated(user) && !issilicon(usr) && ntn_comm) + if(centcomm_message_cooldown) + to_chat(usr, "Arrays recycling. Please stand by.") + GLOB.nanomanager.update_uis(src) + return + if(!is_relay_online())//Contact Centcom has a check, Syndie doesn't to allow for Traitor funs. + to_chat(usr, "No Emergency Bluespace Relay detected. Unable to transmit message.") + return 1 + var/input = sanitize(input("Please choose a message to transmit to [GLOB.using_map.boss_short] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "") as null|text) + if(!input || !can_still_topic()) + return 1 + Centcomm_announce(input, usr) + to_chat(usr, "Message transmitted.") + log_say("[key_name(usr)] has made an IA [GLOB.using_map.boss_short] announcement: [input]") + centcomm_message_cooldown = 1 + spawn(300) //30 second cooldown + centcomm_message_cooldown = 0 + if("evac") + . = 1 + if(is_autenthicated(user)) + var/datum/evacuation_option/selected_evac_option = evacuation_controller.evacuation_options[href_list["target"]] + if (isnull(selected_evac_option) || !istype(selected_evac_option)) + return + if (!selected_evac_option.silicon_allowed && issilicon(user)) + return + if (selected_evac_option.needs_syscontrol && !ntn_cont) + return + var/confirm = alert("Are you sure you want to [selected_evac_option.option_desc]?", name, "No", "Yes") + if (confirm == "Yes" && can_still_topic()) + evacuation_controller.handle_evac_option(selected_evac_option.option_target, user) + if("setstatus") + . = 1 + if(is_autenthicated(user) && ntn_cont) + switch(href_list["target"]) + if("line1") + var/linput = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", msg_line1) as text|null, 40), 40) + if(can_still_topic()) + msg_line1 = linput + if("line2") + var/linput = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", msg_line2) as text|null, 40), 40) + if(can_still_topic()) + msg_line2 = linput + if("message") + post_status("message", msg_line1, msg_line2) + if("image") + post_status("image", href_list["image"]) + else + post_status(href_list["target"]) + if("setalert") + . = 1 + if(is_autenthicated(user) && !issilicon(usr) && ntn_cont && ntn_comm) + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + var/decl/security_level/target_level = locate(href_list["target"]) in security_state.standard_security_levels + if(target_level && security_state.can_switch_to(target_level)) + var/confirm = alert("Are you sure you want to change alert level to [target_level.name]?", name, "No", "Yes") + if(confirm == "Yes" && can_still_topic()) + if(security_state.set_security_level(target_level)) + feedback_inc(target_level.type,1) + else + to_chat(usr, "You press the button, but a red light flashes and nothing happens.") //This should never happen + + current_status = STATE_DEFAULT + if("viewmessage") + . = 1 + if(is_autenthicated(user) && ntn_comm) + current_viewing_message_id = text2num(href_list["target"]) + for(var/list/m in l.messages) + if(m["id"] == current_viewing_message_id) + current_viewing_message = m + current_status = STATE_VIEWMESSAGE + if("delmessage") + . = 1 + if(is_autenthicated(user) && ntn_comm && l != global_message_listener) + l.Remove(current_viewing_message) + current_status = STATE_MESSAGELIST + if("printmessage") + . = 1 + if(is_autenthicated(user) && ntn_comm) + if(program && program.computer && program.computer.nano_printer) + if(!program.computer.nano_printer.print_text(current_viewing_message["contents"],current_viewing_message["title"])) + to_chat(usr, "Hardware Error: Printer was unable to print the selected file.") + else + program.computer.visible_message("\The [program.computer] prints out a paper.") + +#undef STATE_DEFAULT +#undef STATE_MESSAGELIST +#undef STATE_VIEWMESSAGE +#undef STATE_STATUSDISPLAY +#undef STATE_ALERT_LEVEL + +/* +General message handling stuff +*/ +var/list/comm_message_listeners = list() //We first have to initialize list then we can use it. +var/datum/comm_message_listener/global_message_listener = new //May be used by admins +var/last_message_id = 0 + +/proc/get_comm_message_id() + last_message_id = last_message_id + 1 + return last_message_id + +/proc/post_comm_message(var/message_title, var/message_text) + var/list/message = list() + message["id"] = get_comm_message_id() + message["title"] = message_title + message["contents"] = message_text + + for (var/datum/comm_message_listener/l in comm_message_listeners) + l.Add(message) + +/datum/comm_message_listener + var/list/messages + +/datum/comm_message_listener/New() + ..() + messages = list() + comm_message_listeners.Add(src) + +/datum/comm_message_listener/proc/Add(var/list/message) + messages[++messages.len] = message + +/datum/comm_message_listener/proc/Remove(var/list/message) + messages -= list(message) + +/proc/post_status(var/command, var/data1, var/data2) + + var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) + + if(!frequency) return + + var/datum/signal/status_signal = new + status_signal.source = src + status_signal.transmission_method = 1 + status_signal.data["command"] = command + + switch(command) + if("message") + status_signal.data["msg1"] = data1 + status_signal.data["msg2"] = data2 + log_admin("STATUS: [key_name(usr)] set status screen message with [src]: [data1] [data2]") + if("image") + status_signal.data["picture_state"] = data1 + + frequency.post_signal(src, status_signal) + +/proc/cancel_call_proc(var/mob/user) + if (!ticker || !evacuation_controller) + return + + if(evacuation_controller.cancel_evacuation()) + log_game("[key_name(user)] has cancelled the evacuation.") + message_admins("[key_name_admin(user)] has cancelled the evacuation.", 1) + + return + + +/proc/is_relay_online() + for(var/obj/machinery/bluespacerelay/M in SSmachines.machinery) + if(M.stat == 0) + return 1 + return 0 + +/proc/call_shuttle_proc(var/mob/user, var/emergency) + if (!ticker || !evacuation_controller) + return + + if(isnull(emergency)) + emergency = 1 + + if(!GLOB.universe.OnShuttleCall(usr)) + to_chat(user, "Cannot establish a bluespace connection.") + return + + if(deathsquad.deployed) + to_chat(user, "[GLOB.using_map.boss_short] will not allow an evacuation to take place. Consider all contracts terminated.") + return + + if(evacuation_controller.deny) + to_chat(user, "An evacuation cannot be called at this time. Please try again later.") + return + + if(evacuation_controller.is_on_cooldown()) // Ten minute grace period to let the game get going without lolmetagaming. -- TLE + to_chat(user, evacuation_controller.get_cooldown_message()) + + if(evacuation_controller.is_evacuating()) + to_chat(user, "An evacuation is already underway.") + return + + if(evacuation_controller.call_evacuation(user, _emergency_evac = emergency)) + log_and_message_admins("[user? key_name(user) : "Autotransfer"] has called the shuttle.") + +/proc/init_autotransfer() + if (!ticker || !evacuation_controller) + return + + . = evacuation_controller.call_evacuation(null, _emergency_evac = FALSE, autotransfer = TRUE) + if(.) + //delay events in case of an autotransfer + var/delay = evacuation_controller.evac_arrival_time - world.time + (2 MINUTES) + GLOB.event_manager.delay_events(EVENT_LEVEL_MODERATE, delay) + GLOB.event_manager.delay_events(EVENT_LEVEL_MAJOR, delay) diff --git a/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm new file mode 100644 index 00000000..4ea06f26 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm @@ -0,0 +1,138 @@ +/datum/computer_file/program/alarm_monitor + filename = "alarmmonitor" + filedesc = "Alarm Monitoring" + nanomodule_path = /datum/nano_module/alarm_monitor/engineering + ui_header = "alarm_green.gif" + program_icon_state = "alert-green" + program_key_state = "atmos_key" + program_menu_icon = "alert" + extended_desc = "This program provides visual interface for the alarm system." + requires_ntnet = 1 + network_destination = "alarm monitoring network" + size = 5 + var/has_alert = 0 + +/datum/computer_file/program/alarm_monitor/process_tick() + ..() + var/datum/nano_module/alarm_monitor/NMA = NM + if(istype(NMA) && NMA.has_major_alarms()) + if(!has_alert) + program_icon_state = "alert-red" + ui_header = "alarm_red.gif" + update_computer_icon() + has_alert = 1 + else + if(has_alert) + program_icon_state = "alert-green" + ui_header = "alarm_green.gif" + update_computer_icon() + has_alert = 0 + return 1 + +/datum/nano_module/alarm_monitor + name = "Alarm monitor" + var/list_cameras = 0 // Whether or not to list camera references. A future goal would be to merge this with the enginering/security camera console. Currently really only for AI-use. + var/list/datum/alarm_handler/alarm_handlers // The particular list of alarm handlers this alarm monitor should present to the user. + available_to_ai = FALSE + +/datum/nano_module/alarm_monitor/New() + ..() + alarm_handlers = list() + +/datum/nano_module/alarm_monitor/all + available_to_ai = TRUE + +/datum/nano_module/alarm_monitor/all/New() + ..() + alarm_handlers = alarm_manager.all_handlers + +/datum/nano_module/alarm_monitor/engineering/New() + ..() + alarm_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, power_alarm) + +/datum/nano_module/alarm_monitor/security/New() + ..() + alarm_handlers = list(camera_alarm, motion_alarm) + +/datum/nano_module/alarm_monitor/proc/register_alarm(var/object, var/procName) + for(var/datum/alarm_handler/AH in alarm_handlers) + AH.register_alarm(object, procName) + +/datum/nano_module/alarm_monitor/proc/unregister_alarm(var/object) + for(var/datum/alarm_handler/AH in alarm_handlers) + AH.unregister_alarm(object) + +/datum/nano_module/alarm_monitor/proc/all_alarms() + var/list/all_alarms = new() + for(var/datum/alarm_handler/AH in alarm_handlers) + all_alarms += AH.alarms(get_host_z()) + + return all_alarms + +/datum/nano_module/alarm_monitor/proc/major_alarms() + var/list/all_alarms = new() + for(var/datum/alarm_handler/AH in alarm_handlers) + all_alarms += AH.major_alarms(get_host_z()) + + return all_alarms + +// Modified version of above proc that uses slightly less resources, returns 1 if there is a major alarm, 0 otherwise. +/datum/nano_module/alarm_monitor/proc/has_major_alarms() + for(var/datum/alarm_handler/AH in alarm_handlers) + if(AH.has_major_alarms(get_host_z())) + return 1 + + return 0 + +/datum/nano_module/alarm_monitor/proc/minor_alarms() + var/list/all_alarms = new() + for(var/datum/alarm_handler/AH in alarm_handlers) + all_alarms += AH.minor_alarms(get_host_z()) + + return all_alarms + +/datum/nano_module/alarm_monitor/Topic(ref, href_list) + if(..()) + return 1 + if(href_list["switchTo"]) + var/obj/machinery/camera/C = locate(href_list["switchTo"]) in cameranet.cameras + if(!C) + return + + usr.switch_to_camera(C) + return 1 + +/datum/nano_module/alarm_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + + var/categories[0] + for(var/datum/alarm_handler/AH in alarm_handlers) + categories[++categories.len] = list("category" = AH.category, "alarms" = list()) + for(var/datum/alarm/A in AH.major_alarms(get_host_z())) + + var/cameras[0] + var/lost_sources[0] + + if(isAI(user)) + for(var/obj/machinery/camera/C in A.cameras()) + cameras[++cameras.len] = C.nano_structure() + for(var/datum/alarm_source/AS in A.sources) + if(!AS.source) + lost_sources[++lost_sources.len] = AS.source_name + + categories[categories.len]["alarms"] += list(list( + "name" = sanitize(A.alarm_name()), + "origin_lost" = A.origin == null, + "has_cameras" = cameras.len, + "cameras" = cameras, + "lost_sources" = lost_sources.len ? sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")) : "")) + data["categories"] = categories + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "alarm_monitor.tmpl", "Alarm Monitoring Console", 800, 800, state = state) + if(host.update_layout()) // This is necessary to ensure the status bar remains updated along with rest of the UI. + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) diff --git a/code/modules/modular_computers/file_system/programs/engineering/atmos_control.dm b/code/modules/modular_computers/file_system/programs/engineering/atmos_control.dm new file mode 100644 index 00000000..d3453c99 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/engineering/atmos_control.dm @@ -0,0 +1,97 @@ +/datum/computer_file/program/atmos_control + filename = "atmoscontrol" + filedesc = "Atmosphere Control" + nanomodule_path = /datum/nano_module/atmos_control + program_icon_state = "atmos_control" + program_key_state = "atmos_key" + program_menu_icon = "shuffle" + extended_desc = "This program allows remote control of air alarms. This program can not be run on tablet computers." + required_access = access_atmospherics + requires_ntnet = 1 + network_destination = "atmospheric control system" + requires_ntnet_feature = NTNET_SYSTEMCONTROL + usage_flags = PROGRAM_LAPTOP | PROGRAM_CONSOLE + size = 17 + +/datum/nano_module/atmos_control + name = "Atmospherics Control" + var/obj/access = new() + var/emagged = 0 + var/ui_ref + var/list/monitored_alarms = list() + +/datum/nano_module/atmos_control/New(atmos_computer, var/list/req_access, var/list/req_one_access, monitored_alarm_ids) + ..() + + if(istype(req_access)) + access.req_access = req_access + else if(req_access) + log_debug("\The [src] was given an unepxected req_access: [req_access]") + + if(istype(req_one_access)) + access.req_one_access = req_one_access + else if(req_one_access) + log_debug("\The [src] given an unepxected req_one_access: [req_one_access]") + + if(monitored_alarm_ids) + for(var/obj/machinery/alarm/alarm in SSmachines.machinery) + if(alarm.alarm_id && alarm.alarm_id in monitored_alarm_ids) + monitored_alarms += alarm + // machines may not yet be ordered at this point + monitored_alarms = dd_sortedObjectList(monitored_alarms) + +/datum/nano_module/atmos_control/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["alarm"]) + if(ui_ref) + var/obj/machinery/alarm/alarm = locate(href_list["alarm"]) in (monitored_alarms.len ? monitored_alarms : SSmachines.machinery) + if(alarm) + var/datum/topic_state/TS = generate_state(alarm) + alarm.ui_interact(usr, master_ui = ui_ref, state = TS) + return 1 + +/datum/nano_module/atmos_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + var/alarms[0] + + // TODO: Move these to a cache, similar to cameras + for(var/obj/machinery/alarm/alarm in (monitored_alarms.len ? monitored_alarms : SSmachines.machinery)) + alarms[++alarms.len] = list("name" = sanitize(alarm.name), "ref"= "\ref[alarm]", "danger" = max(alarm.danger_level, alarm.alarm_area.atmosalm)) + data["alarms"] = alarms + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "atmos_control.tmpl", src.name, 625, 625, state = state) + if(host.update_layout()) // This is necessary to ensure the status bar remains updated along with rest of the UI. + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + ui_ref = ui + +/datum/nano_module/atmos_control/proc/generate_state(air_alarm) + var/datum/topic_state/air_alarm/state = new() + state.atmos_control = src + state.air_alarm = air_alarm + return state + +/datum/topic_state/air_alarm + var/datum/nano_module/atmos_control/atmos_control = null + var/obj/machinery/alarm/air_alarm = null + +/datum/topic_state/air_alarm/can_use_topic(var/src_object, var/mob/user) + if(has_access(user)) + return STATUS_INTERACTIVE + return STATUS_UPDATE + +/datum/topic_state/air_alarm/href_list(var/mob/user) + var/list/extra_href = list() + extra_href["remote_connection"] = 1 + extra_href["remote_access"] = has_access(user) + + return extra_href + +/datum/topic_state/air_alarm/proc/has_access(var/mob/user) + return user && (isAI(user) || atmos_control.access.allowed(user) || atmos_control.emagged || air_alarm.rcon_setting == RCON_YES || (air_alarm.alarm_area.atmosalm && air_alarm.rcon_setting == RCON_AUTO)) diff --git a/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm new file mode 100644 index 00000000..87441636 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm @@ -0,0 +1,120 @@ +/datum/computer_file/program/power_monitor + filename = "powermonitor" + filedesc = "Power Monitoring" + nanomodule_path = /datum/nano_module/power_monitor/ + program_icon_state = "power_monitor" + program_key_state = "power_key" + program_menu_icon = "battery-3" + extended_desc = "This program connects to sensors to provide information about electrical systems" + ui_header = "power_norm.gif" + required_access = access_engine + requires_ntnet = 1 + network_destination = "power monitoring system" + size = 9 + var/has_alert = 0 + +/datum/computer_file/program/power_monitor/process_tick() + ..() + var/datum/nano_module/power_monitor/NMA = NM + if(istype(NMA) && NMA.has_alarm()) + if(!has_alert) + program_icon_state = "power_monitor_warn" + ui_header = "power_warn.gif" + update_computer_icon() + has_alert = 1 + else + if(has_alert) + program_icon_state = "power_monitor" + ui_header = "power_norm.gif" + update_computer_icon() + has_alert = 0 + +/datum/nano_module/power_monitor + name = "Power monitor" + var/list/grid_sensors + var/active_sensor = null //name_tag of the currently selected sensor + +/datum/nano_module/power_monitor/New() + ..() + refresh_sensors() + +/datum/nano_module/power_monitor/Destroy() + for(var/grid_sensor in grid_sensors) + remove_sensor(grid_sensor, FALSE) + grid_sensors = null + . = ..() + +// Checks whether there is an active alarm, if yes, returns 1, otherwise returns 0. +/datum/nano_module/power_monitor/proc/has_alarm() + for(var/obj/machinery/power/sensor/S in grid_sensors) + if(S.check_grid_warning()) + return 1 + return 0 + +// If PC is not null header template is loaded. Use PC.get_header_data() to get relevant nanoui data from it. All data entries begin with "PC_...." +// In future it may be expanded to other modular computer devices. +/datum/nano_module/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + + var/list/sensors = list() + // Focus: If it remains null if no sensor is selected and UI will display sensor list, otherwise it will display sensor reading. + var/obj/machinery/power/sensor/focus = null + + // Build list of data from sensor readings. + for(var/obj/machinery/power/sensor/S in grid_sensors) + sensors.Add(list(list( + "name" = S.name_tag, + "alarm" = S.check_grid_warning() + ))) + if(S.name_tag == active_sensor) + focus = S + + data["all_sensors"] = sensors + if(focus) + data["focus"] = focus.return_reading_data() + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "power_monitor.tmpl", "Power Monitoring Console", 800, 500, state = state) + if(host.update_layout()) // This is necessary to ensure the status bar remains updated along with rest of the UI. + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +// Refreshes list of active sensors kept on this computer. +/datum/nano_module/power_monitor/proc/refresh_sensors() + grid_sensors = list() + var/turf/T = get_turf(nano_host()) + if(!T) // Safety check + return + var/connected_z_levels = GetConnectedZlevels(T.z) + for(var/obj/machinery/power/sensor/S in SSmachines.machinery) + if((S.long_range) || (S.loc.z in connected_z_levels)) // Consoles have range on their Z-Level. Sensors with long_range var will work between Z levels. + if(S.name_tag == "#UNKN#") // Default name. Shouldn't happen! + warning("Powernet sensor with unset ID Tag! [S.x]X [S.y]Y [S.z]Z") + else + grid_sensors += S + GLOB.destroyed_event.register(S, src, /datum/nano_module/power_monitor/proc/remove_sensor) + +/datum/nano_module/power_monitor/proc/remove_sensor(var/removed_sensor, var/update_ui = TRUE) + if(active_sensor == removed_sensor) + active_sensor = null + if(update_ui) + GLOB.nanomanager.update_uis(src) + grid_sensors -= removed_sensor + GLOB.destroyed_event.unregister(removed_sensor, src, /datum/nano_module/power_monitor/proc/remove_sensor) + +// Allows us to process UI clicks, which are relayed in form of hrefs. +/datum/nano_module/power_monitor/Topic(href, href_list) + if(..()) + return 1 + if( href_list["clear"] ) + active_sensor = null + . = 1 + if( href_list["refresh"] ) + refresh_sensors() + . = 1 + else if( href_list["setsensor"] ) + active_sensor = href_list["setsensor"] + . = 1 diff --git a/code/modules/modular_computers/file_system/programs/engineering/rcon_console.dm b/code/modules/modular_computers/file_system/programs/engineering/rcon_console.dm new file mode 100644 index 00000000..927643df --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/engineering/rcon_console.dm @@ -0,0 +1,133 @@ +/datum/computer_file/program/rcon_console + filename = "rconconsole" + filedesc = "RCON Remote Control" + nanomodule_path = /datum/nano_module/rcon + program_icon_state = "generic" + program_key_state = "rd_key" + program_menu_icon = "power" + extended_desc = "This program allows remote control of power distribution systems. This program can not be run on tablet computers." + required_access = access_engine + requires_ntnet = 1 + network_destination = "RCON remote control system" + requires_ntnet_feature = NTNET_SYSTEMCONTROL + usage_flags = PROGRAM_LAPTOP | PROGRAM_CONSOLE + size = 19 + +/datum/nano_module/rcon + name = "Power RCON" + var/list/known_SMESs = null + var/list/known_breakers = null + // Allows you to hide specific parts of the UI + var/hide_SMES = 0 + var/hide_SMES_details = 0 + var/hide_breakers = 0 + +/datum/nano_module/rcon/ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1, var/datum/topic_state/state = GLOB.default_state) + FindDevices() // Update our devices list + var/list/data = host.initial_data() + + // SMES DATA (simplified view) + var/list/smeslist[0] + for(var/obj/machinery/power/smes/buildable/SMES in known_SMESs) + smeslist.Add(list(list( + "charge" = round(SMES.Percentage()), + "input_set" = SMES.input_attempt, + "input_val" = round(SMES.input_level/1000, 0.1), + "input_load" = round(SMES.input_available/1000, 0.1), + "output_set" = SMES.output_attempt, + "output_val" = round(SMES.output_level/1000, 0.1), + "output_load" = round(SMES.output_used/1000, 0.1), + "RCON_tag" = SMES.RCon_tag + ))) + + data["smes_info"] = sortByKey(smeslist, "RCON_tag") + + // BREAKER DATA (simplified view) + var/list/breakerlist[0] + for(var/obj/machinery/power/breakerbox/BR in known_breakers) + breakerlist.Add(list(list( + "RCON_tag" = BR.RCon_tag, + "enabled" = BR.on + ))) + data["breaker_info"] = breakerlist + data["hide_smes"] = hide_SMES + data["hide_smes_details"] = hide_SMES_details + data["hide_breakers"] = hide_breakers + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "rcon.tmpl", "RCON Console", 600, 400, state = state) + if(host.update_layout()) // This is necessary to ensure the status bar remains updated along with rest of the UI. + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +// Proc: Topic() +// Parameters: 2 (href, href_list - allows us to process UI clicks) +// Description: Allows us to process UI clicks, which are relayed in form of hrefs. +/datum/nano_module/rcon/Topic(href, href_list) + if(..()) + return + + if(href_list["smes_in_toggle"]) + var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_in_toggle"]) + if(SMES) + SMES.toggle_input() + if(href_list["smes_out_toggle"]) + var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_out_toggle"]) + if(SMES) + SMES.toggle_output() + if(href_list["smes_in_set"]) + var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_in_set"]) + if(SMES) + var/inputset = (input(usr, "Enter new input level (0-[SMES.input_level_max/1000] kW)", "SMES Input Power Control", SMES.input_level/1000) as num) * 1000 + SMES.set_input(inputset) + if(href_list["smes_out_set"]) + var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_out_set"]) + if(SMES) + var/outputset = (input(usr, "Enter new output level (0-[SMES.output_level_max/1000] kW)", "SMES Input Power Control", SMES.output_level/1000) as num) * 1000 + SMES.set_output(outputset) + + if(href_list["toggle_breaker"]) + var/obj/machinery/power/breakerbox/toggle = null + for(var/obj/machinery/power/breakerbox/breaker in known_breakers) + if(breaker.RCon_tag == href_list["toggle_breaker"]) + toggle = breaker + if(toggle) + if(toggle.update_locked) + to_chat(usr, "The breaker box was recently toggled. Please wait before toggling it again.") + else + toggle.auto_toggle() + if(href_list["hide_smes"]) + hide_SMES = !hide_SMES + if(href_list["hide_smes_details"]) + hide_SMES_details = !hide_SMES_details + if(href_list["hide_breakers"]) + hide_breakers = !hide_breakers + + +// Proc: GetSMESByTag() +// Parameters: 1 (tag - RCON tag of SMES we want to look up) +// Description: Looks up and returns SMES which has matching RCON tag +/datum/nano_module/rcon/proc/GetSMESByTag(var/tag) + if(!tag) + return + + for(var/obj/machinery/power/smes/buildable/S in known_SMESs) + if(S.RCon_tag == tag) + return S + +// Proc: FindDevices() +// Parameters: None +// Description: Refreshes local list of known devices. +/datum/nano_module/rcon/proc/FindDevices() + known_SMESs = new /list() + for(var/obj/machinery/power/smes/buildable/SMES in SSmachines.machinery) + if(AreConnectedZLevels(get_host_z(), get_z(SMES)) && SMES.RCon_tag && (SMES.RCon_tag != "NO_TAG") && SMES.RCon) + known_SMESs.Add(SMES) + + known_breakers = new /list() + for(var/obj/machinery/power/breakerbox/breaker in SSmachines.machinery) + if(AreConnectedZLevels(get_host_z(), get_z(breaker)) && breaker.RCon_tag != "NO_TAG") + known_breakers.Add(breaker) diff --git a/code/modules/modular_computers/file_system/programs/engineering/shields_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/shields_monitor.dm new file mode 100644 index 00000000..8cf3582d --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/engineering/shields_monitor.dm @@ -0,0 +1,110 @@ +/datum/computer_file/program/shields_monitor + filename = "shieldsmonitor" + filedesc = "Shield Generators Monitoring" + nanomodule_path = /datum/nano_module/shields_monitor/ + program_icon_state = "shield" + program_key_state = "generic_key" + program_menu_icon = "radio-on" + extended_desc = "This program connects to shield generators and monitors their statuses." + ui_header = "shield.gif" + requires_ntnet = 1 + network_destination = "shields monitoring system" + size = 10 + +/datum/nano_module/shields_monitor + name = "Shields monitor" + var/obj/machinery/power/shield_generator/active = null + +/datum/nano_module/shields_monitor/Destroy() + . = ..() + deselect_shield() + +/datum/nano_module/shields_monitor/proc/get_shields() + var/turf/T = get_turf(nano_host()) + if(!T) + return list() + + var/list/shields = list() + var/connected_z_levels = GetConnectedZlevels(T.z) + for(var/obj/machinery/power/shield_generator/S in SSmachines.machinery) + if(!(S.z in connected_z_levels)) + continue + shields.Add(S) + + if(!(active in shields)) + deselect_shield() + return shields + +/datum/nano_module/shields_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + + if (active) + data["active"] = 1 + data["running"] = active.running + data["modes"] = active.get_flag_descriptions() + data["overloaded"] = active.overloaded + data["mitigation_max"] = active.mitigation_max + data["mitigation_physical"] = round(active.mitigation_physical, 0.1) + data["mitigation_em"] = round(active.mitigation_em, 0.1) + data["mitigation_heat"] = round(active.mitigation_heat, 0.1) + data["field_integrity"] = active.field_integrity() + data["max_energy"] = round(active.max_energy / 1000000, 0.1) + data["current_energy"] = round(active.current_energy / 1000000, 0.1) + data["total_segments"] = active.field_segments ? active.field_segments.len : 0 + data["functional_segments"] = active.damaged_segments ? data["total_segments"] - active.damaged_segments.len : data["total_segments"] + data["field_radius"] = active.field_radius + data["input_cap_kw"] = round(active.input_cap / 1000) + data["upkeep_power_usage"] = round(active.upkeep_power_usage / 1000, 0.1) + data["power_usage"] = round(active.power_usage / 1000) + data["hacked"] = active.hacked + data["offline_for"] = active.offline_for * 2 + data["pos_x"] = active.x + data["pos_y"] = active.y + data["pos_z"] = active.z + else + data["active"] = null + var/list/shields = get_shields() + var/list/shields_info = list() + for(var/obj/machinery/power/shield_generator/S in shields) + var/area/A = get_area(S) + var/list/temp = list(list( + "shield_status" = S.running, + "shield_ref" = any2ref(S), + "area" = A.name)) + shields_info.Add(temp) + data["shields"] = shields_info + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "shields_monitor.tmpl", "Shield Generators Monitoring", 400, 500, state = state) + if(host.update_layout()) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/nano_module/shields_monitor/Topic(href, href_list) + if(..()) + return 1 + if( href_list["refresh"] ) + get_shields() + return 1 + if( href_list["return"] ) + deselect_shield() + return 1 + if( href_list["ref"] ) + var/list/shields = get_shields() + var/obj/machinery/power/shield_generator/S = locate(href_list["ref"]) in shields + if(S) + deselect_shield() + GLOB.destroyed_event.register(S, src, /datum/nano_module/shields_monitor/proc/deselect_shield) + active = S + return 1 + +/datum/nano_module/shields_monitor/proc/deselect_shield(var/source) + if(!active) + return + GLOB.destroyed_event.unregister(active, src) + active = null + if(source) // source is only set if called by the shield destroyed event, which is the only time we want to update the UI + GLOB.nanomanager.update_uis(src) \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/engineering/supermatter_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/supermatter_monitor.dm new file mode 100644 index 00000000..8c900783 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/engineering/supermatter_monitor.dm @@ -0,0 +1,134 @@ +/datum/computer_file/program/supermatter_monitor + filename = "supmon" + filedesc = "Supermatter Monitoring" + nanomodule_path = /datum/nano_module/supermatter_monitor/ + program_icon_state = "smmon_0" + program_key_state = "tech_key" + program_menu_icon = "notice" + extended_desc = "This program connects to specially calibrated supermatter sensors to provide information on the status of supermatter-based engines." + ui_header = "smmon_0.gif" + required_access = access_engine + requires_ntnet = 1 + network_destination = "supermatter monitoring system" + size = 5 + var/last_status = 0 + +/datum/computer_file/program/supermatter_monitor/process_tick() + ..() + var/datum/nano_module/supermatter_monitor/NMS = NM + var/new_status = istype(NMS) ? NMS.get_status() : 0 + if(last_status != new_status) + last_status = new_status + ui_header = "smmon_[last_status].gif" + program_icon_state = "smmon_[last_status]" + if(istype(computer)) + computer.update_icon() + +/datum/nano_module/supermatter_monitor + name = "Supermatter monitor" + var/list/supermatters + var/obj/machinery/power/supermatter/active = null // Currently selected supermatter crystal. + +/datum/nano_module/supermatter_monitor/Destroy() + . = ..() + active = null + supermatters = null + +/datum/nano_module/supermatter_monitor/New() + ..() + refresh() + +// Refreshes list of active supermatter crystals +/datum/nano_module/supermatter_monitor/proc/refresh() + supermatters = list() + var/turf/T = get_turf(nano_host()) + if(!T) + return + var/valid_z_levels = (GetConnectedZlevels(T.z) & GLOB.using_map.station_levels) + for(var/obj/machinery/power/supermatter/S in SSmachines.machinery) + // Delaminating, not within coverage, not on a tile. + if(S.grav_pulling || S.exploded || !(S.z in valid_z_levels) || !istype(S.loc, /turf/)) + continue + supermatters.Add(S) + + if(!(active in supermatters)) + active = null + +/datum/nano_module/supermatter_monitor/proc/get_status() + . = SUPERMATTER_INACTIVE + for(var/obj/machinery/power/supermatter/S in supermatters) + . = max(., S.get_status()) + +/datum/nano_module/supermatter_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + + if(istype(active)) + var/turf/T = get_turf(active) + if(!T) + active = null + return + var/datum/gas_mixture/air = T.return_air() + if(!istype(air)) + active = null + return + + data["active"] = 1 + data["SM_integrity"] = active.get_integrity() + data["SM_power"] = active.power + data["SM_ambienttemp"] = air.temperature + data["SM_ambientpressure"] = air.return_pressure() + data["SM_EPR"] = active.get_epr() + if(air.total_moles) + data["SM_gas_O2"] = round(100*air.gas["oxygen"]/air.total_moles,0.01) + data["SM_gas_CO2"] = round(100*air.gas["carbon_dioxide"]/air.total_moles,0.01) + data["SM_gas_N2"] = round(100*air.gas["nitrogen"]/air.total_moles,0.01) + data["SM_gas_PH"] = round(100*air.gas["phoron"]/air.total_moles,0.01) + data["SM_gas_N2O"] = round(100*air.gas["sleeping_agent"]/air.total_moles,0.01) + data["SM_gas_H2"] = round(100*air.gas["hydrogen"]/air.total_moles,0.01) + else + data["SM_gas_O2"] = 0 + data["SM_gas_CO2"] = 0 + data["SM_gas_N2"] = 0 + data["SM_gas_PH"] = 0 + data["SM_gas_N2O"] = 0 + data["SM_gas_H2"] = 0 + else + var/list/SMS = list() + for(var/obj/machinery/power/supermatter/S in supermatters) + var/area/A = get_area(S) + if(!A) + continue + + SMS.Add(list(list( + "area_name" = A.name, + "integrity" = S.get_integrity(), + "uid" = S.uid + ))) + + data["active"] = 0 + data["supermatters"] = SMS + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "supermatter_monitor.tmpl", "Supermatter Monitoring", 600, 400, state = state) + if(host.update_layout()) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/nano_module/supermatter_monitor/Topic(href, href_list) + if(..()) + return 1 + if( href_list["clear"] ) + active = null + return 1 + if( href_list["refresh"] ) + refresh() + return 1 + if( href_list["set"] ) + var/newuid = text2num(href_list["set"]) + for(var/obj/machinery/power/supermatter/S in supermatters) + if(S.uid == newuid) + active = S + return 1 \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/generic/camera.dm b/code/modules/modular_computers/file_system/programs/generic/camera.dm new file mode 100644 index 00000000..a6ac46ab --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/camera.dm @@ -0,0 +1,184 @@ +// Returns which access is relevant to passed network. Used by the program. +/proc/get_camera_access(var/network) + if(!network) + return 0 + . = GLOB.using_map.get_network_access(network) + if(.) + return + + switch(network) + if(NETWORK_ENGINEERING, NETWORK_ALARM_ATMOS, NETWORK_ALARM_CAMERA, NETWORK_ALARM_FIRE, NETWORK_ALARM_POWER) + return access_engine + if(NETWORK_CRESCENT, NETWORK_ERT) + return access_cent_specops + if(NETWORK_MEDICAL) + return access_medical + if(NETWORK_MINE) + return access_mailsorting // Cargo office - all cargo staff should have access here. + if(NETWORK_RESEARCH) + return access_research + if(NETWORK_THUNDER) + return 0 + + return access_security // Default for all other networks + +/datum/computer_file/program/camera_monitor + filename = "cammon" + filedesc = "Camera Monitoring" + nanomodule_path = /datum/nano_module/camera_monitor + program_icon_state = "cameras" + program_key_state = "generic_key" + program_menu_icon = "search" + extended_desc = "This program allows remote access to the camera system. Some camera networks may have additional access requirements." + size = 12 + available_on_ntnet = 1 + requires_ntnet = 1 + +/datum/nano_module/camera_monitor + name = "Camera Monitoring program" + var/obj/machinery/camera/current_camera = null + var/current_network = null + +/datum/nano_module/camera_monitor/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = GLOB.default_state) + var/list/data = host.initial_data() + + data["current_camera"] = current_camera ? current_camera.nano_structure() : null + data["current_network"] = current_network + + var/list/all_networks[0] + for(var/network in GLOB.using_map.station_networks) + all_networks.Add(list(list( + "tag" = network, + "has_access" = can_access_network(user, get_camera_access(network)) + ))) + + all_networks = modify_networks_list(all_networks) + + data["networks"] = all_networks + + if(current_network) + data["cameras"] = camera_repository.cameras_in_network(current_network) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "sec_camera.tmpl", "Camera Monitoring", 900, 800, state = state) + // ui.auto_update_layout = 1 // Disabled as with suit sensors monitor - breaks the UI map. Re-enable once it's fixed somehow. + + ui.add_template("mapContent", "sec_camera_map_content.tmpl") + ui.add_template("mapHeader", "sec_camera_map_header.tmpl") + ui.set_initial_data(data) + ui.open() + +// Intended to be overriden by subtypes to manually add non-station networks to the list. +/datum/nano_module/camera_monitor/proc/modify_networks_list(var/list/networks) + return networks + +/datum/nano_module/camera_monitor/proc/can_access_network(var/mob/user, var/network_access) + // No access passed, or 0 which is considered no access requirement. Allow it. + if(!network_access) + return 1 + + return check_access(user, access_security) || check_access(user, network_access) + +/datum/nano_module/camera_monitor/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["switch_camera"]) + var/obj/machinery/camera/C = locate(href_list["switch_camera"]) in cameranet.cameras + if(!C) + return + if(!(current_network in C.network)) + return + + switch_to_camera(usr, C) + return 1 + + else if(href_list["switch_network"]) + // Either security access, or access to the specific camera network's department is required in order to access the network. + if(can_access_network(usr, get_camera_access(href_list["switch_network"]))) + current_network = href_list["switch_network"] + else + to_chat(usr, "\The [nano_host()] shows an \"Network Access Denied\" error message.") + return 1 + + else if(href_list["reset"]) + reset_current() + usr.reset_view(current_camera) + return 1 + +/datum/nano_module/camera_monitor/proc/switch_to_camera(var/mob/user, var/obj/machinery/camera/C) + //don't need to check if the camera works for AI because the AI jumps to the camera location and doesn't actually look through cameras. + if(isAI(user)) + var/mob/living/silicon/ai/A = user + // Only allow non-carded AIs to view because the interaction with the eye gets all wonky otherwise. + if(!A.is_in_chassis()) + return 0 + + A.eyeobj.setLoc(get_turf(C)) + A.client.eye = A.eyeobj + return 1 + + set_current(C) + user.machine = nano_host() + user.reset_view(C) + return 1 + +/datum/nano_module/camera_monitor/proc/set_current(var/obj/machinery/camera/C) + if(current_camera == C) + return + + if(current_camera) + reset_current() + + current_camera = C + if(current_camera) + var/mob/living/L = current_camera.loc + if(istype(L)) + L.tracking_initiated() + +/datum/nano_module/camera_monitor/proc/reset_current() + if(current_camera) + var/mob/living/L = current_camera.loc + if(istype(L)) + L.tracking_cancelled() + current_camera = null + +/datum/nano_module/camera_monitor/check_eye(var/mob/user as mob) + if(!current_camera) + return 0 + var/viewflag = current_camera.check_eye(user) + if ( viewflag < 0 ) //camera doesn't work + reset_current() + return viewflag + + +// ERT Variant of the program +/datum/computer_file/program/camera_monitor/ert + filename = "ntcammon" + filedesc = "Advanced Camera Monitoring" + extended_desc = "This program allows remote access to the camera system. Some camera networks may have additional access requirements. This version has an integrated database with additional encrypted keys." + size = 14 + nanomodule_path = /datum/nano_module/camera_monitor/ert + available_on_ntnet = 0 + +/datum/nano_module/camera_monitor/ert + name = "Advanced Camera Monitoring Program" + available_to_ai = FALSE + +// The ERT variant has access to ERT and crescent cams, but still checks for accesses. ERT members should be able to use it. +/datum/nano_module/camera_monitor/ert/modify_networks_list(var/list/networks) + ..() + networks.Add(list(list("tag" = NETWORK_ERT, "has_access" = 1))) + networks.Add(list(list("tag" = NETWORK_CRESCENT, "has_access" = 1))) + return networks + +/datum/nano_module/camera_monitor/apply_visual(mob/M) + if(current_camera) + current_camera.apply_visual(M) + else + remove_visual(M) + +/datum/nano_module/camera_monitor/remove_visual(mob/M) + if(current_camera) + current_camera.remove_visual(M) diff --git a/code/modules/modular_computers/file_system/programs/generic/configurator.dm b/code/modules/modular_computers/file_system/programs/generic/configurator.dm new file mode 100644 index 00000000..d7397876 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/configurator.dm @@ -0,0 +1,64 @@ +// This is special hardware configuration program. +// It is to be used only with modular computers. +// It allows you to toggle components of your device. + +/datum/computer_file/program/computerconfig + filename = "compconfig" + filedesc = "Computer Configuration Tool" + extended_desc = "This program allows configuration of computer's hardware" + program_icon_state = "generic" + program_key_state = "generic_key" + program_menu_icon = "gear" + unsendable = 1 + undeletable = 1 + size = 4 + available_on_ntnet = 0 + requires_ntnet = 0 + nanomodule_path = /datum/nano_module/program/computer_configurator/ + +/datum/nano_module/program/computer_configurator + name = "NTOS Computer Configuration Tool" + var/obj/item/modular_computer/movable = null + +/datum/nano_module/program/computer_configurator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + if(program) + movable = program.computer + if(!istype(movable)) + movable = null + + // No computer connection, we can't get data from that. + if(!movable) + return 0 + + var/list/data = list() + + if(program) + data = program.get_header_data() + + var/list/hardware = movable.get_all_components() + + data["disk_size"] = movable.hard_drive.max_capacity + data["disk_used"] = movable.hard_drive.used_capacity + data["power_usage"] = movable.last_power_usage + data["battery_exists"] = movable.battery_module ? 1 : 0 + if(movable.battery_module) + data["battery_rating"] = movable.battery_module.battery.maxcharge + data["battery_percent"] = round(movable.battery_module.battery.percent()) + + var/list/all_entries[0] + for(var/obj/item/weapon/computer_hardware/H in hardware) + all_entries.Add(list(list( + "name" = H.name, + "desc" = H.desc, + "enabled" = H.enabled, + "critical" = H.critical, + "powerusage" = H.power_usage + ))) + + data["hardware"] = all_entries + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "laptop_configuration.tmpl", "NTOS Configuration Utility", 575, 700, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/generic/docks.dm b/code/modules/modular_computers/file_system/programs/generic/docks.dm new file mode 100644 index 00000000..1194e18a --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/docks.dm @@ -0,0 +1,81 @@ +/datum/computer_file/program/docking + filename = "docking" + filedesc = "Docking Control" + required_access = access_heads + nanomodule_path = /datum/nano_module/docking + program_icon_state = "supply" + program_key_state = "rd_key" + program_menu_icon = "triangle-2-e-w" + extended_desc = "A management tool that lets you see the status of the docking ports." + size = 10 + available_on_ntnet = 1 + requires_ntnet = 1 + +/datum/nano_module/docking + name = "Docking Control program" + var/list/docking_controllers = list() //list of tags + +/datum/computer_file/program/docking/run_program() + . = ..() + if(NM) + var/datum/nano_module/docking/NMD = NM + NMD.refresh_docks() + +/datum/nano_module/docking/proc/refresh_docks() + var/atom/movable/AM = nano_host() + if(!istype(AM)) + return + docking_controllers.Cut() + var/list/zlevels = GetConnectedZlevels(AM.z) + for(var/obj/machinery/embedded_controller/radio/airlock/docking_port/D in SSmachines.machinery) + if(D.z in zlevels) + var/shuttleside = 0 + for(var/sname in shuttle_controller.shuttles) //do not touch shuttle-side ones + var/datum/shuttle/autodock/S = shuttle_controller.shuttles[sname] + if(istype(S) && S.shuttle_docking_controller) + if(S.shuttle_docking_controller.id_tag == D.docking_program.id_tag) + shuttleside = 1 + break + if(shuttleside) + continue + docking_controllers += D.docking_program.id_tag + +/datum/nano_module/docking/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = GLOB.default_state) + var/list/data = host.initial_data() + var/list/docks = list() + for(var/docktag in docking_controllers) + var/datum/computer/file/embedded_program/docking/P = locate(docktag) + if(P) + var/docking_attempt = P.tag_target && !P.dock_state + docks.Add(list(list( + "tag"=P.id_tag, + "location" = P.get_name(), + "status" = capitalize(P.get_docking_status()), + "docking_attempt" = docking_attempt, + "codes" = P.docking_codes ? P.docking_codes : "Unset" + ))) + data["docks"] = docks + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "docking.tmpl", name, 600, 450, state = state) + ui.set_auto_update(1) + ui.set_initial_data(data) + ui.open() + +/datum/nano_module/docking/Topic(href, href_list, state) + if(..()) + return 1 + if(href_list["edit_code"]) + var/datum/computer/file/embedded_program/docking/P = locate(href_list["edit_code"]) + if(P) + var/newcode = input("Input new docking codes", "Docking codes", P.docking_codes) as text|null + if(!CanInteract(usr,state)) + return + if (newcode) + P.docking_codes = uppertext(newcode) + return 1 + if(href_list["dock"]) + var/datum/computer/file/embedded_program/docking/P = locate(href_list["dock"]) + if(P) + P.receive_user_command("dock") + return 1 \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/generic/email_client.dm b/code/modules/modular_computers/file_system/programs/generic/email_client.dm new file mode 100644 index 00000000..bdb7b0ad --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/email_client.dm @@ -0,0 +1,499 @@ +/datum/computer_file/program/email_client + filename = "emailc" + filedesc = "Email Client" + extended_desc = "This program may be used to log in into your email account." + program_icon_state = "generic" + program_key_state = "generic_key" + program_menu_icon = "mail-closed" + size = 7 + requires_ntnet = 1 + available_on_ntnet = 1 + var/stored_login = "" + var/stored_password = "" + + nanomodule_path = /datum/nano_module/email_client + +// Persistency. Unless you log out, or unless your password changes, this will pre-fill the login data when restarting the program +/datum/computer_file/program/email_client/kill_program() + if(NM) + var/datum/nano_module/email_client/NME = NM + if(NME.current_account) + stored_login = NME.stored_login + stored_password = NME.stored_password + else + stored_login = "" + stored_password = "" + . = ..() + +/datum/computer_file/program/email_client/run_program() + . = ..() + if(NM) + var/datum/nano_module/email_client/NME = NM + NME.stored_login = stored_login + NME.stored_password = stored_password + NME.log_in() + NME.error = "" + NME.check_for_new_messages(1) + +/datum/computer_file/program/email_client/proc/new_mail_notify() + computer.visible_message("\The [computer] beeps softly, indicating a new email has been received.", 1) + +/datum/computer_file/program/email_client/process_tick() + ..() + var/datum/nano_module/email_client/NME = NM + if(!istype(NME)) + return + NME.relayed_process(ntnet_speed) + + var/check_count = NME.check_for_new_messages() + if(check_count) + if(check_count == 2) + new_mail_notify() + ui_header = "ntnrc_new.gif" + else + ui_header = "ntnrc_idle.gif" + +/datum/nano_module/email_client/ + name = "Email Client" + var/stored_login = "" + var/stored_password = "" + var/error = "" + + var/msg_title = "" + var/msg_body = "" + var/msg_recipient = "" + var/datum/computer_file/msg_attachment = null + var/folder = "Inbox" + var/addressbook = FALSE + var/new_message = FALSE + + var/last_message_count = 0 // How many messages were there during last check. + var/read_message_count = 0 // How many messages were there when user has last accessed the UI. + + var/datum/computer_file/downloading = null + var/download_progress = 0 + var/download_speed = 0 + + var/datum/computer_file/data/email_account/current_account = null + var/datum/computer_file/data/email_message/current_message = null + +/datum/nano_module/email_client/proc/log_in() + for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts) + if(!account.can_login) + continue + if(account.login == stored_login) + if(account.password == stored_password) + if(account.suspended) + error = "This account has been suspended. Please contact the system administrator for assistance." + return 0 + current_account = account + return 1 + else + error = "Invalid Password" + return 0 + error = "Invalid Login" + return 0 + +// Returns 0 if no new messages were received, 1 if there is an unread message but notification has already been sent. +// and 2 if there is a new message that appeared in this tick (and therefore notification should be sent by the program). +/datum/nano_module/email_client/proc/check_for_new_messages(var/messages_read = FALSE) + if(!current_account) + return 0 + + var/list/allmails = current_account.all_emails() + + if(allmails.len > last_message_count) + . = 2 + else if(allmails.len > read_message_count) + . = 1 + else + . = 0 + + last_message_count = allmails.len + if(messages_read) + read_message_count = allmails.len + + +/datum/nano_module/email_client/proc/log_out() + current_account = null + downloading = null + download_progress = 0 + last_message_count = 0 + read_message_count = 0 + +/datum/nano_module/email_client/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + + // Password has been changed by other client connected to this email account + if(current_account) + if(current_account.password != stored_password) + log_out() + error = "Invalid Password" + // Banned. + if(current_account.suspended) + log_out() + error = "This account has been suspended. Please contact the system administrator for assistance." + + if(error) + data["error"] = error + else if(downloading) + data["downloading"] = 1 + data["down_filename"] = "[downloading.filename].[downloading.filetype]" + data["down_progress"] = download_progress + data["down_size"] = downloading.size + data["down_speed"] = download_speed + + else if(istype(current_account)) + data["current_account"] = current_account.login + if(addressbook) + var/list/all_accounts = list() + for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts) + if(!account.can_login) + continue + all_accounts.Add(list(list( + "login" = account.login + ))) + data["addressbook"] = 1 + data["accounts"] = all_accounts + else if(new_message) + data["new_message"] = 1 + data["msg_title"] = msg_title + data["msg_body"] = pencode2html(msg_body) + data["msg_recipient"] = msg_recipient + if(msg_attachment) + data["msg_hasattachment"] = 1 + data["msg_attachment_filename"] = "[msg_attachment.filename].[msg_attachment.filetype]" + data["msg_attachment_size"] = msg_attachment.size + else if (current_message) + data["cur_title"] = current_message.title + data["cur_body"] = pencode2html(current_message.stored_data) + data["cur_timestamp"] = current_message.timestamp + data["cur_source"] = current_message.source + data["cur_uid"] = current_message.uid + if(istype(current_message.attachment)) + data["cur_hasattachment"] = 1 + data["cur_attachment_filename"] = "[current_message.attachment.filename].[current_message.attachment.filetype]" + data["cur_attachment_size"] = current_message.attachment.size + else + data["label_inbox"] = "Inbox ([current_account.inbox.len])" + data["label_spam"] = "Spam ([current_account.spam.len])" + data["label_deleted"] = "Deleted ([current_account.deleted.len])" + var/list/message_source + if(folder == "Inbox") + message_source = current_account.inbox + else if(folder == "Spam") + message_source = current_account.spam + else if(folder == "Deleted") + message_source = current_account.deleted + + if(message_source) + data["folder"] = folder + var/list/all_messages = list() + for(var/datum/computer_file/data/email_message/message in message_source) + all_messages.Add(list(list( + "title" = message.title, + "body" = pencode2html(message.stored_data), + "source" = message.source, + "timestamp" = message.timestamp, + "uid" = message.uid + ))) + data["messages"] = all_messages + data["messagecount"] = all_messages.len + else + data["stored_login"] = stored_login + data["stored_password"] = stars(stored_password, 0) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "email_client.tmpl", "Email Client", 600, 450, state = state) + if(host.update_layout()) + ui.auto_update_layout = 1 + ui.set_auto_update(1) + ui.set_initial_data(data) + ui.open() + +/datum/nano_module/email_client/proc/find_message_by_fuid(var/fuid) + if(!istype(current_account)) + return + + // href_list works with strings, so this makes it a bit easier for us + if(istext(fuid)) + fuid = text2num(fuid) + + for(var/datum/computer_file/data/email_message/message in current_account.all_emails()) + if(message.uid == fuid) + return message + +/datum/nano_module/email_client/proc/clear_message() + new_message = FALSE + msg_title = "" + msg_body = "" + msg_recipient = "" + msg_attachment = null + current_message = null + +/datum/nano_module/email_client/proc/relayed_process(var/netspeed) + download_speed = netspeed + if(!downloading) + return + download_progress = min(download_progress + netspeed, downloading.size) + if(download_progress >= downloading.size) + var/obj/item/modular_computer/MC = nano_host() + if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) + error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?" + downloading = null + download_progress = 0 + return 1 + + if(MC.hard_drive.store_file(downloading)) + error = "File successfully downloaded to local device." + else + error = "Error saving file: I/O Error: The hard drive may be full or nonfunctional." + downloading = null + download_progress = 0 + return 1 + + +/datum/nano_module/email_client/Topic(href, href_list) + if(..()) + return 1 + var/mob/living/user = usr + check_for_new_messages(1) // Any actual interaction (button pressing) is considered as acknowledging received message, for the purpose of notification icons. + if(href_list["login"]) + log_in() + return 1 + + if(href_list["logout"]) + log_out() + return 1 + + if(href_list["reset"]) + error = "" + return 1 + + if(href_list["new_message"]) + new_message = TRUE + return 1 + + if(href_list["cancel"]) + if(addressbook) + addressbook = FALSE + else + clear_message() + return 1 + + if(href_list["addressbook"]) + addressbook = TRUE + return 1 + + if(href_list["set_recipient"]) + msg_recipient = sanitize(href_list["set_recipient"]) + addressbook = FALSE + return 1 + + if(href_list["edit_title"]) + var/newtitle = sanitize(input(user,"Enter title for your message:", "Message title", msg_title), 100) + if(newtitle) + msg_title = newtitle + return 1 + + // This uses similar editing mechanism as the FileManager program, therefore it supports various paper tags and remembers formatting. + if(href_list["edit_body"]) + var/oldtext = html_decode(msg_body) + oldtext = replacetext(oldtext, "\[editorbr\]", "\n") + + var/newtext = sanitize(replacetext(input(usr, "Enter your message. You may use most tags from paper formatting", "Message Editor", oldtext) as message|null, "\n", "\[editorbr\]"), 20000) + if(newtext) + msg_body = newtext + return 1 + + if(href_list["edit_recipient"]) + var/newrecipient = sanitize(input(user,"Enter recipient's email address:", "Recipient", msg_recipient), 100) + if(newrecipient) + msg_recipient = newrecipient + return 1 + + if(href_list["edit_login"]) + var/newlogin = sanitize(input(user,"Enter login", "Login", stored_login), 100) + if(newlogin) + stored_login = newlogin + return 1 + + if(href_list["edit_password"]) + var/newpass = sanitize(input(user,"Enter password", "Password"), 100) + if(newpass) + stored_password = newpass + return 1 + + if(href_list["delete"]) + if(!istype(current_account)) + return 1 + var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["delete"]) + if(!istype(M)) + return 1 + if(folder == "Deleted") + current_account.deleted.Remove(M) + qdel(M) + else + current_account.deleted.Add(M) + current_account.inbox.Remove(M) + current_account.spam.Remove(M) + if(current_message == M) + current_message = null + return 1 + + if(href_list["send"]) + if(!current_account) + return 1 + if((msg_title == "") || (msg_body == "") || (msg_recipient == "")) + error = "Error sending mail: Title or message body is empty!" + return 1 + + var/datum/computer_file/data/email_message/message = new() + message.title = msg_title + message.stored_data = msg_body + message.source = current_account.login + message.attachment = msg_attachment + if(!current_account.send_mail(msg_recipient, message)) + error = "Error sending email: this address doesn't exist." + return 1 + else + error = "Email successfully sent." + clear_message() + return 1 + + if(href_list["set_folder"]) + folder = href_list["set_folder"] + return 1 + + if(href_list["reply"]) + var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["reply"]) + if(!istype(M)) + return 1 + + new_message = TRUE + msg_recipient = M.source + msg_title = "Re: [M.title]" + msg_body = "\[editorbr\]\[editorbr\]\[editorbr\]\[br\]==============================\[br\]\[editorbr\]" + msg_body += "Received by [current_account.login] at [M.timestamp]\[br\]\[editorbr\][M.stored_data]" + return 1 + + if(href_list["view"]) + var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["view"]) + if(istype(M)) + current_message = M + return 1 + + if(href_list["changepassword"]) + var/oldpassword = sanitize(input(user,"Please enter your old password:", "Password Change"), 100) + if(!oldpassword) + return 1 + var/newpassword1 = sanitize(input(user,"Please enter your new password:", "Password Change"), 100) + if(!newpassword1) + return 1 + var/newpassword2 = sanitize(input(user,"Please re-enter your new password:", "Password Change"), 100) + if(!newpassword2) + return 1 + + if(!istype(current_account)) + error = "Please log in before proceeding." + return 1 + + if(current_account.password != oldpassword) + error = "Incorrect original password" + return 1 + + if(newpassword1 != newpassword2) + error = "The entered passwords do not match." + return 1 + + current_account.password = newpassword1 + stored_password = newpassword1 + error = "Your password has been successfully changed!" + return 1 + + // The following entries are Modular Computer framework only, and therefore won't do anything in other cases (like AI View) + + if(href_list["save"]) + // Fully dependant on modular computers here. + var/obj/item/modular_computer/MC = nano_host() + + if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) + error = "Error exporting file. Are you using a functional and NTOS-compliant device?" + return 1 + + var/filename = sanitize(input(user,"Please specify file name:", "Message export"), 100) + if(!filename) + return 1 + + var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["save"]) + var/datum/computer_file/data/mail = istype(M) ? M.export() : null + if(!istype(mail)) + return 1 + mail.filename = filename + if(!MC.hard_drive || !MC.hard_drive.store_file(mail)) + error = "Internal I/O error when writing file, the hard drive may be full." + else + error = "Email exported successfully" + return 1 + + if(href_list["addattachment"]) + var/obj/item/modular_computer/MC = nano_host() + msg_attachment = null + + if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) + error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?" + return 1 + + var/list/filenames = list() + for(var/datum/computer_file/CF in MC.hard_drive.stored_files) + if(CF.unsendable) + continue + filenames.Add(CF.filename) + var/picked_file = input(user, "Please pick a file to send as attachment (max 32GQ)") as null|anything in filenames + + if(!picked_file) + return 1 + + if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) + error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?" + return 1 + + for(var/datum/computer_file/CF in MC.hard_drive.stored_files) + if(CF.unsendable) + continue + if(CF.filename == picked_file) + msg_attachment = CF.clone() + break + if(!istype(msg_attachment)) + msg_attachment = null + error = "Unknown error when uploading attachment." + return 1 + + if(msg_attachment.size > 32) + error = "Error uploading attachment: File exceeds maximal permitted file size of 32GQ." + msg_attachment = null + else + error = "File [msg_attachment.filename].[msg_attachment.filetype] has been successfully uploaded." + return 1 + + if(href_list["downloadattachment"]) + if(!current_account || !current_message || !current_message.attachment) + return 1 + var/obj/item/modular_computer/MC = nano_host() + if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) + error = "Error downloading file. Are you using a functional and NTOSv2-compliant device?" + return 1 + + downloading = current_message.attachment.clone() + download_progress = 0 + return 1 + + if(href_list["canceldownload"]) + downloading = null + download_progress = 0 + return 1 + + if(href_list["remove_attachment"]) + msg_attachment = null + return 1 \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/generic/file_browser.dm b/code/modules/modular_computers/file_system/programs/generic/file_browser.dm new file mode 100644 index 00000000..b01d6bed --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/file_browser.dm @@ -0,0 +1,207 @@ +/datum/computer_file/program/filemanager + filename = "filemanager" + filedesc = "NTOS File Manager" + extended_desc = "This program allows management of files." + program_icon_state = "generic" + program_key_state = "generic_key" + program_menu_icon = "folder-collapsed" + size = 8 + requires_ntnet = 0 + available_on_ntnet = 0 + undeletable = 1 + nanomodule_path = /datum/nano_module/program/computer_filemanager/ + var/open_file + var/error + +/datum/computer_file/program/filemanager/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["PRG_openfile"]) + . = 1 + open_file = href_list["PRG_openfile"] + if(href_list["PRG_newtextfile"]) + . = 1 + var/newname = sanitize(input(usr, "Enter file name or leave blank to cancel:", "File rename")) + if(!newname) + return 1 + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + if(!HDD) + return 1 + var/datum/computer_file/data/F = new/datum/computer_file/data() + F.filename = newname + F.filetype = "TXT" + HDD.store_file(F) + if(href_list["PRG_deletefile"]) + . = 1 + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + if(!HDD) + return 1 + var/datum/computer_file/file = HDD.find_file_by_name(href_list["PRG_deletefile"]) + if(!file || file.undeletable) + return 1 + HDD.remove_file(file) + if(href_list["PRG_usbdeletefile"]) + . = 1 + var/obj/item/weapon/computer_hardware/hard_drive/RHDD = computer.portable_drive + if(!RHDD) + return 1 + var/datum/computer_file/file = RHDD.find_file_by_name(href_list["PRG_usbdeletefile"]) + if(!file || file.undeletable) + return 1 + RHDD.remove_file(file) + if(href_list["PRG_closefile"]) + . = 1 + open_file = null + error = null + if(href_list["PRG_clone"]) + . = 1 + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + if(!HDD) + return 1 + var/datum/computer_file/F = HDD.find_file_by_name(href_list["PRG_clone"]) + if(!F || !istype(F)) + return 1 + var/datum/computer_file/C = F.clone(1) + HDD.store_file(C) + if(href_list["PRG_rename"]) + . = 1 + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + if(!HDD) + return 1 + var/datum/computer_file/file = HDD.find_file_by_name(href_list["PRG_rename"]) + if(!file || !istype(file)) + return 1 + var/newname = sanitize(input(usr, "Enter new file name:", "File rename", file.filename)) + if(file && newname) + file.filename = newname + if(href_list["PRG_edit"]) + . = 1 + if(!open_file) + return 1 + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + if(!HDD) + return 1 + var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) + if(!F || !istype(F)) + return 1 + if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No")) + return 1 + + var/oldtext = html_decode(F.stored_data) + oldtext = replacetext(oldtext, "\[br\]", "\n") + + var/newtext = sanitize(replacetext(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH) + if(!newtext) + return + + if(F) + var/datum/computer_file/data/backup = F.clone() + HDD.remove_file(F) + F.stored_data = newtext + F.calculate_size() + // We can't store the updated file, it's probably too large. Print an error and restore backed up version. + // This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space. + // They will be able to copy-paste the text from error screen and store it in notepad or something. + if(!HDD.store_file(F)) + error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:

            [html_decode(F.stored_data)]

            " + HDD.store_file(backup) + if(href_list["PRG_printfile"]) + . = 1 + if(!open_file) + return 1 + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + if(!HDD) + return 1 + var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) + if(!F || !istype(F)) + return 1 + if(!computer.nano_printer) + error = "Missing Hardware: Your computer does not have required hardware to complete this operation." + return 1 + if(!computer.nano_printer.print_text(pencode2html(F.stored_data))) + error = "Hardware error: Printer was unable to print the file. It may be out of paper." + return 1 + if(href_list["PRG_copytousb"]) + . = 1 + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive + if(!HDD || !RHDD) + return 1 + var/datum/computer_file/F = HDD.find_file_by_name(href_list["PRG_copytousb"]) + if(!F || !istype(F)) + return 1 + var/datum/computer_file/C = F.clone(0) + RHDD.store_file(C) + if(href_list["PRG_copyfromusb"]) + . = 1 + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive + if(!HDD || !RHDD) + return 1 + var/datum/computer_file/F = RHDD.find_file_by_name(href_list["PRG_copyfromusb"]) + if(!F || !istype(F)) + return 1 + var/datum/computer_file/C = F.clone(0) + HDD.store_file(C) + if(.) + GLOB.nanomanager.update_uis(NM) + +/datum/nano_module/program/computer_filemanager + name = "NTOS File Manager" + +/datum/nano_module/program/computer_filemanager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + var/datum/computer_file/program/filemanager/PRG + PRG = program + + var/obj/item/weapon/computer_hardware/hard_drive/HDD + var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD + if(PRG.error) + data["error"] = PRG.error + if(PRG.open_file) + var/datum/computer_file/data/file + + if(!PRG.computer || !PRG.computer.hard_drive) + data["error"] = "I/O ERROR: Unable to access hard drive." + else + HDD = PRG.computer.hard_drive + file = HDD.find_file_by_name(PRG.open_file) + if(!istype(file)) + data["error"] = "I/O ERROR: Unable to open file." + else + data["filedata"] = pencode2html(file.stored_data) + data["filename"] = "[file.filename].[file.filetype]" + else + if(!PRG.computer || !PRG.computer.hard_drive) + data["error"] = "I/O ERROR: Unable to access hard drive." + else + HDD = PRG.computer.hard_drive + RHDD = PRG.computer.portable_drive + var/list/files[0] + for(var/datum/computer_file/F in HDD.stored_files) + files.Add(list(list( + "name" = F.filename, + "type" = F.filetype, + "size" = F.size, + "undeletable" = F.undeletable + ))) + data["files"] = files + if(RHDD) + data["usbconnected"] = 1 + var/list/usbfiles[0] + for(var/datum/computer_file/F in RHDD.stored_files) + usbfiles.Add(list(list( + "name" = F.filename, + "type" = F.filetype, + "size" = F.size, + "undeletable" = F.undeletable + ))) + data["usbfiles"] = usbfiles + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "file_manager.tmpl", "NTOS File Manager", 575, 700, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/generic/game.dm b/code/modules/modular_computers/file_system/programs/generic/game.dm new file mode 100644 index 00000000..0e108904 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/game.dm @@ -0,0 +1,152 @@ +// This file is used as a reference for Modular Computers Development guide on the wiki. It contains a lot of excess comments, as it is intended as explanation +// for someone who may not be as experienced in coding. When making changes, please try to keep it this way. + +// An actual program definition. +/datum/computer_file/program/game + filename = "arcadec" // File name, as shown in the file browser program. + filedesc = "Unknown Game" // User-Friendly name. In this case, we will generate a random name in constructor. + program_icon_state = "game" // Icon state of this program's screen. + program_menu_icon = "script" + extended_desc = "Fun for the whole family! Probably not an AAA title, but at least you can download it on the corporate network.." // A nice description. + size = 5 // Size in GQ. Integers only. Smaller sizes should be used for utility/low use programs (like this one), while large sizes are for important programs. + requires_ntnet = 0 // This particular program does not require NTNet network conectivity... + available_on_ntnet = 1 // ... but we want it to be available for download. + nanomodule_path = /datum/nano_module/arcade_classic/ // Path of relevant nano module. The nano module is defined further in the file. + var/picked_enemy_name + +// Blatantly stolen and shortened version from arcade machines. Generates a random enemy name +/datum/computer_file/program/game/proc/random_enemy_name() + var/name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Cuban ", "the Evil ", "the Dread King ", "the Space ", "Lord ", "the Great ", "Duke ", "General ") + var/name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon", "Uhangoid", "Vhakoid", "Peteoid", "Slime", "Lizard Man", "Unicorn") + return "[name_part1] [name_part2]" + +// When the program is first created, we generate a new enemy name and name ourselves accordingly. +/datum/computer_file/program/game/New() + ..() + picked_enemy_name = random_enemy_name() + filedesc = "Defeat [picked_enemy_name]" + +// Important in order to ensure that copied versions will have the same enemy name. +/datum/computer_file/program/game/clone() + var/datum/computer_file/program/game/G = ..() + G.picked_enemy_name = picked_enemy_name + return G + +// When running the program, we also want to pass our enemy name to the nano module. +/datum/computer_file/program/game/run_program() + . = ..() + if(. && NM) + var/datum/nano_module/arcade_classic/NMC = NM + NMC.enemy_name = picked_enemy_name + + +// Nano module the program uses. +// This can be either /datum/nano_module/ or /datum/nano_module/program. The latter is intended for nano modules that are suposed to be exclusively used with modular computers, +// and should generally not be used, as such nano modules are hard to use on other places. +/datum/nano_module/arcade_classic/ + name = "Classic Arcade" + var/player_mana // Various variables specific to the nano module. In this case, the nano module is a simple arcade game, so the variables store health and other stats. + var/player_health + var/enemy_mana + var/enemy_health + var/enemy_name = "Greytide Horde" + var/gameover + var/information + +/datum/nano_module/arcade_classic/New() + ..() + new_game() + +// ui_interact handles transfer of data to NanoUI. Keep in mind that data you pass from here is actually sent to the client. In other words, don't send anything you don't want a client +// to see, and don't send unnecessarily large amounts of data (due to laginess). +/datum/nano_module/arcade_classic/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + + data["player_health"] = player_health + data["player_mana"] = player_mana + data["enemy_health"] = enemy_health + data["enemy_mana"] = enemy_mana + data["enemy_name"] = enemy_name + data["gameover"] = gameover + data["information"] = information + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "arcade_classic.tmpl", "Defeat [enemy_name]", 500, 350, state = state) + if(host.update_layout()) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + +// Three helper procs i've created. These are unique to this particular nano module. If you are creating your own nano module, you'll most likely create similar procs too. +/datum/nano_module/arcade_classic/proc/enemy_play() + if((enemy_mana < 5) && prob(60)) + var/steal = rand(2, 3) + player_mana -= steal + enemy_mana += steal + information += "[enemy_name] steals [steal] of your power!" + else if((enemy_health < 15) && (enemy_mana > 3) && prob(80)) + var/healamt = min(rand(3, 5), enemy_mana) + enemy_mana -= healamt + enemy_health += healamt + information += "[enemy_name] heals for [healamt] health!" + else + var/dam = rand(3,6) + player_health -= dam + information += "[enemy_name] attacks for [dam] damage!" + +/datum/nano_module/arcade_classic/proc/check_gameover() + if((player_health <= 0) || player_mana <= 0) + if(enemy_health <= 0) + information += "You have defeated [enemy_name], but you have died in the fight!" + else + information += "You have been defeated by [enemy_name]!" + gameover = 1 + return TRUE + else if(enemy_health <= 0) + gameover = 1 + information += "Congratulations! You have defeated [enemy_name]!" + return TRUE + return FALSE + +/datum/nano_module/arcade_classic/proc/new_game() + player_mana = 10 + player_health = 30 + enemy_mana = 20 + enemy_health = 45 + gameover = FALSE + information = "A new game has started!" + + + +/datum/nano_module/arcade_classic/Topic(href, href_list) + if(..()) // Always begin your Topic() calls with a parent call! + return 1 + if(href_list["new_game"]) + new_game() + return 1 // Returning 1 (TRUE) in Topic automatically handles UI updates. + if(gameover) // If the game has already ended, we don't want the following three topic calls to be processed at all. + return 1 // Instead of adding checks into each of those three, we can easily add this one check here to reduce on code copy-paste. + if(href_list["attack"]) + var/damage = rand(2, 6) + information = "You attack for [damage] damage." + enemy_health -= damage + enemy_play() + check_gameover() + return 1 + if(href_list["heal"]) + var/healfor = rand(6, 8) + var/cost = rand(1, 3) + information = "You heal yourself for [healfor] damage, using [cost] energy in the process." + player_health += healfor + player_mana -= cost + enemy_play() + check_gameover() + return 1 + if(href_list["regain_mana"]) + var/regen = rand(4, 7) + information = "You rest of a while, regaining [regen] energy." + player_mana += regen + enemy_play() + check_gameover() + return 1 \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/generic/library.dm b/code/modules/modular_computers/file_system/programs/generic/library.dm new file mode 100644 index 00000000..0f556757 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/library.dm @@ -0,0 +1,191 @@ +/* +In reply to this set of comments on lib_machines.dm: +// TODO: Make this an actual /obj/machinery/computer that can be crafted from circuit boards and such +// It is August 22nd, 2012... This TODO has already been here for months.. I wonder how long it'll last before someone does something about it. + +The answer was five and a half years -ZeroBits +*/ + +/datum/computer_file/program/library + filename = "library" + filedesc = "Library" + extended_desc = "This program can be used to view e-books from an external archive." + program_icon_state = "word" + program_key_state = "atmos_key" + program_menu_icon = "note" + size = 6 + requires_ntnet = 1 + available_on_ntnet = 1 + + nanomodule_path = /datum/nano_module/library + +/datum/nano_module/library + name = "Library" + var/error_message = "" + var/current_book + var/obj/machinery/libraryscanner/scanner + var/sort_by = "id" + +/datum/nano_module/library/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + + if(error_message) + data["error"] = error_message + else if(current_book) + data["current_book"] = current_book + else + var/list/all_entries[0] + establish_old_db_connection() + if(!dbcon_old.IsConnected()) + error_message = "Unable to contact External Archive. Please contact your system administrator for assistance." + else + var/DBQuery/query = dbcon_old.NewQuery("SELECT id, author, title, category FROM library ORDER BY "+sanitizeSQL(sort_by)) + query.Execute() + + while(query.NextRow()) + all_entries.Add(list(list( + "id" = query.item[1], + "author" = query.item[2], + "title" = query.item[3], + "category" = query.item[4] + ))) + data["book_list"] = all_entries + data["scanner"] = istype(scanner) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "library.tmpl", "Library Program", 575, 700, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + +/datum/nano_module/library/Topic(href, href_list) + if(..()) + return 1 + if(href_list["viewbook"]) + view_book(href_list["viewbook"]) + return 1 + if(href_list["viewid"]) + view_book(sanitizeSQL(input("Enter USBN:") as num|null)) + return 1 + if(href_list["closebook"]) + current_book = null + return 1 + if(href_list["connectscanner"]) + if(!nano_host()) + return 1 + for(var/d in GLOB.cardinal) + var/obj/machinery/libraryscanner/scn = locate(/obj/machinery/libraryscanner, get_step(nano_host(), d)) + if(scn && scn.anchored) + scanner = scn + return 1 + if(href_list["uploadbook"]) + if(!scanner || !scanner.anchored) + scanner = null + error_message = "Hardware Error: No scanner detected. Unable to access cache." + return 1 + if(!scanner.cache) + error_message = "Interface Error: Scanner cache does not contain any data. Please scan a book." + return 1 + + var/obj/item/weapon/book/B = scanner.cache + + if(B.unique) + error_message = "Interface Error: Cached book is copy-protected." + return 1 + + B.SetName(input(usr, "Enter Book Title", "Title", B.name) as text|null) + B.author = input(usr, "Enter Author Name", "Author", B.author) as text|null + + if(!B.author) + B.author = "Anonymous" + else if(lowertext(B.author) == "edgar allen poe" || lowertext(B.author) == "edgar allan poe") + error_message = "User Error: Upload something original." + return 1 + + if(!B.title) + B.title = "Untitled" + + var/choice = input(usr, "Upload [B.name] by [B.author] to the External Archive?") in list("Yes", "No") + if(choice == "Yes") + establish_old_db_connection() + if(!dbcon_old.IsConnected()) + error_message = "Network Error: Connection to the Archive has been severed." + return 1 + + var/upload_category = input(usr, "Upload to which category?") in list("Fiction", "Non-Fiction", "Reference", "Religion") + + var/sqltitle = sanitizeSQL(B.name) + var/sqlauthor = sanitizeSQL(B.author) + var/sqlcontent = sanitizeSQL(B.dat) + var/sqlcategory = sanitizeSQL(upload_category) + var/DBQuery/query = dbcon_old.NewQuery("INSERT INTO library (author, title, content, category) VALUES ('[sqlauthor]', '[sqltitle]', '[sqlcontent]', '[sqlcategory]')") + if(!query.Execute()) + to_chat(usr, query.ErrorMsg()) + error_message = "Network Error: Unable to upload to the Archive. Contact your system Administrator for assistance." + return 1 + else + log_and_message_admins("has uploaded the book titled [B.name], [length(B.dat)] signs") + log_game("[usr.name]/[usr.key] has uploaded the book titled [B.name], [length(B.dat)] signs") + alert("Upload Complete.") + return 1 + + return 0 + + if(href_list["printbook"]) + if(!current_book) + error_message = "Software Error: Unable to print; book not found." + return 1 + + //PRINT TO BINDER + if(!nano_host()) + return 1 + for(var/d in GLOB.cardinal) + var/obj/machinery/bookbinder/bndr = locate(/obj/machinery/bookbinder, get_step(nano_host(), d)) + if(bndr && bndr.anchored) + var/obj/item/weapon/book/B = new(bndr.loc) + B.SetName(current_book["title"]) + B.title = current_book["title"] + B.author = current_book["author"] + B.dat = current_book["content"] + B.icon_state = "book[rand(1,7)]" + B.desc = current_book["author"]+", "+current_book["title"]+", "+"USBN "+current_book["id"] + bndr.visible_message("\The [bndr] whirs as it prints and binds a new book.") + return 1 + + //Regular printing + print_text("Author: [current_book["author"]]
            USBN: [current_book["id"]]

            [current_book["title"]]


            [current_book["content"]]", usr) + return 1 + if(href_list["sortby"]) + sort_by = href_list["sortby"] + return 1 + if(href_list["reseterror"]) + if(error_message) + current_book = null + scanner = null + sort_by = "id" + error_message = "" + return 1 + +/datum/nano_module/library/proc/view_book(var/id) + if(current_book || !id) + return 0 + + var/sqlid = sanitizeSQL(id) + establish_old_db_connection() + if(!dbcon_old.IsConnected()) + error_message = "Network Error: Connection to the Archive has been severed." + return 1 + + var/DBQuery/query = dbcon_old.NewQuery("SELECT * FROM library WHERE id=[sqlid]") + query.Execute() + + while(query.NextRow()) + current_book = list( + "id" = query.item[1], + "author" = query.item[2], + "title" = query.item[3], + "content" = query.item[4] + ) + break + return 1 \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/generic/news_browser.dm b/code/modules/modular_computers/file_system/programs/generic/news_browser.dm new file mode 100644 index 00000000..46f3a8d6 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/news_browser.dm @@ -0,0 +1,132 @@ +/datum/computer_file/program/newsbrowser + filename = "newsbrowser" + filedesc = "NTNet/ExoNet News Browser" + extended_desc = "This program may be used to view and download news articles from the network." + program_icon_state = "generic" + program_key_state = "generic_key" + program_menu_icon = "contact" + size = 4 + requires_ntnet = 1 + available_on_ntnet = 1 + + nanomodule_path = /datum/nano_module/program/computer_newsbrowser/ + var/datum/computer_file/data/news_article/loaded_article + var/download_progress = 0 + var/download_netspeed = 0 + var/downloading = 0 + var/message = "" + var/show_archived = 0 + +/datum/computer_file/program/newsbrowser/process_tick() + if(!downloading) + return + download_netspeed = 0 + // Speed defines are found in misc.dm + switch(ntnet_status) + if(1) + download_netspeed = NTNETSPEED_LOWSIGNAL + if(2) + download_netspeed = NTNETSPEED_HIGHSIGNAL + if(3) + download_netspeed = NTNETSPEED_ETHERNET + download_progress += download_netspeed + if(download_progress >= loaded_article.size) + downloading = 0 + requires_ntnet = 0 // Turn off NTNet requirement as we already loaded the file into local memory. + GLOB.nanomanager.update_uis(NM) + +/datum/computer_file/program/newsbrowser/kill_program() + ..() + requires_ntnet = 1 + loaded_article = null + download_progress = 0 + downloading = 0 + show_archived = 0 + +/datum/computer_file/program/newsbrowser/Topic(href, href_list) + if(..()) + return 1 + if(href_list["PRG_openarticle"]) + . = 1 + if(downloading || loaded_article) + return 1 + + for(var/datum/computer_file/data/news_article/N in ntnet_global.available_news) + if(N.uid == text2num(href_list["PRG_openarticle"])) + loaded_article = N.clone() + downloading = 1 + break + if(href_list["PRG_reset"]) + . = 1 + downloading = 0 + download_progress = 0 + requires_ntnet = 1 + loaded_article = null + if(href_list["PRG_clearmessage"]) + . = 1 + message = "" + if(href_list["PRG_savearticle"]) + . = 1 + if(downloading || !loaded_article) + return + + var/savename = sanitize(input(usr, "Enter file name or leave blank to cancel:", "Save article", loaded_article.filename)) + if(!savename) + return 1 + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + if(!HDD) + return 1 + var/datum/computer_file/data/news_article/N = loaded_article.clone() + N.filename = savename + HDD.store_file(N) + if(href_list["PRG_toggle_archived"]) + . = 1 + show_archived = !show_archived + if(.) + GLOB.nanomanager.update_uis(NM) + + +/datum/nano_module/program/computer_newsbrowser + name = "NTNet/ExoNet News Browser" + +/datum/nano_module/program/computer_newsbrowser/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + + var/datum/computer_file/program/newsbrowser/PRG + var/list/data = list() + if(program) + data = program.get_header_data() + PRG = program + else + return + + data["message"] = PRG.message + if(PRG.loaded_article && !PRG.downloading) // Viewing an article. + data["title"] = PRG.loaded_article.filename + data["cover"] = PRG.loaded_article.cover + data["article"] = PRG.loaded_article.stored_data + else if(PRG.downloading) // Downloading an article. + data["download_running"] = 1 + data["download_progress"] = PRG.download_progress + data["download_maxprogress"] = PRG.loaded_article.size + data["download_rate"] = PRG.download_netspeed + else // Viewing list of articles + var/list/all_articles[0] + for(var/datum/computer_file/data/news_article/F in ntnet_global.available_news) + if(!PRG.show_archived && F.archived) + continue + all_articles.Add(list(list( + "name" = F.filename, + "size" = F.size, + "uid" = F.uid, + "archived" = F.archived + ))) + data["all_articles"] = all_articles + data["showing_archived"] = PRG.show_archived + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "news_browser.tmpl", "NTNet/ExoNet News Browser", 575, 750, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + diff --git a/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm b/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm new file mode 100644 index 00000000..55826897 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm @@ -0,0 +1,200 @@ +/datum/computer_file/program/ntnetdownload + filename = "ntndownloader" + filedesc = "NTNet Software Download Tool" + program_icon_state = "generic" + program_key_state = "generic_key" + program_menu_icon = "arrowthickstop-1-s" + extended_desc = "This program allows downloads of software from official NT repositories" + unsendable = 1 + undeletable = 1 + size = 4 + requires_ntnet = 1 + requires_ntnet_feature = NTNET_SOFTWAREDOWNLOAD + available_on_ntnet = 0 + nanomodule_path = /datum/nano_module/program/computer_ntnetdownload/ + ui_header = "downloader_finished.gif" + var/datum/computer_file/program/downloaded_file = null + var/hacked_download = 0 + var/download_completion = 0 //GQ of downloaded data. + var/download_netspeed = 0 + var/downloaderror = "" + var/list/downloads_queue[0] + +/datum/computer_file/program/ntnetdownload/kill_program() + ..() + downloaded_file = null + download_completion = 0 + download_netspeed = 0 + downloaderror = "" + ui_header = "downloader_finished.gif" + + +/datum/computer_file/program/ntnetdownload/proc/begin_file_download(var/filename) + if(downloaded_file) + return 0 + + var/datum/computer_file/program/PRG = ntnet_global.find_ntnet_file_by_name(filename) + + if(!check_file_download(filename)) + return 0 + + ui_header = "downloader_running.gif" + + if(PRG in ntnet_global.available_station_software) + generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from NTNet Software Repository.") + hacked_download = 0 + else if(PRG in ntnet_global.available_antag_software) + generate_network_log("Began downloading file **ENCRYPTED**.[PRG.filetype] from unspecified server.") + hacked_download = 1 + else + generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from unspecified server.") + hacked_download = 0 + + downloaded_file = PRG.clone() + +/datum/computer_file/program/ntnetdownload/proc/check_file_download(var/filename) + //returns 1 if file can be downloaded, returns 0 if download prohibited + var/datum/computer_file/program/PRG = ntnet_global.find_ntnet_file_by_name(filename) + + if(!PRG || !istype(PRG)) + return 0 + + // Attempting to download antag only program, but without having emagged computer. No. + if(PRG.available_on_syndinet && !computer_emagged) + return 0 + + if(!computer || !computer.hard_drive || !computer.hard_drive.try_store_file(PRG)) + return 0 + + return 1 + +/datum/computer_file/program/ntnetdownload/proc/abort_file_download() + if(!downloaded_file) + return + generate_network_log("Aborted download of file [hacked_download ? "**ENCRYPTED**" : downloaded_file.filename].[downloaded_file.filetype].") + downloaded_file = null + download_completion = 0 + ui_header = "downloader_finished.gif" + +/datum/computer_file/program/ntnetdownload/proc/complete_file_download() + if(!downloaded_file) + return + generate_network_log("Completed download of file [hacked_download ? "**ENCRYPTED**" : downloaded_file.filename].[downloaded_file.filetype].") + if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(downloaded_file)) + // The download failed + downloaderror = "I/O ERROR - Unable to save file. Check whether you have enough free space on your hard drive and whether your hard drive is properly connected. If the issue persists contact your system administrator for assistance." + downloaded_file = null + download_completion = 0 + ui_header = "downloader_finished.gif" + +/datum/computer_file/program/ntnetdownload/process_tick() + if(!downloaded_file) + return + if(download_completion >= downloaded_file.size) + complete_file_download() + if(downloads_queue.len > 0) + begin_file_download(downloads_queue[1]) + downloads_queue.Remove(downloads_queue[1]) + + // Download speed according to connectivity state. NTNet server is assumed to be on unlimited speed so we're limited by our local connectivity + download_netspeed = 0 + // Speed defines are found in misc.dm + switch(ntnet_status) + if(1) + download_netspeed = NTNETSPEED_LOWSIGNAL + if(2) + download_netspeed = NTNETSPEED_HIGHSIGNAL + if(3) + download_netspeed = NTNETSPEED_ETHERNET + download_completion += download_netspeed + +/datum/computer_file/program/ntnetdownload/Topic(href, href_list) + if(..()) + return 1 + if(href_list["PRG_downloadfile"]) + if(!downloaded_file) + begin_file_download(href_list["PRG_downloadfile"]) + else if(check_file_download(href_list["PRG_downloadfile"]) && !downloads_queue.Find(href_list["PRG_downloadfile"]) && downloaded_file.filename != href_list["PRG_downloadfile"]) + downloads_queue += href_list["PRG_downloadfile"] + return 1 + if(href_list["PRG_removequeued"]) + downloads_queue.Remove(href_list["PRG_removequeued"]) + return 1 + if(href_list["PRG_reseterror"]) + if(downloaderror) + download_completion = 0 + download_netspeed = 0 + downloaded_file = null + downloaderror = "" + return 1 + return 0 + +/datum/nano_module/program/computer_ntnetdownload + name = "Network Downloader" + var/obj/item/modular_computer/my_computer = null + +/datum/nano_module/program/computer_ntnetdownload/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + if(program) + my_computer = program.computer + + if(!istype(my_computer)) + return + + var/list/data = list() + var/datum/computer_file/program/ntnetdownload/prog = program + // For now limited to execution by the downloader program + if(!prog || !istype(prog)) + return + if(program) + data = program.get_header_data() + + // This IF cuts on data transferred to client, so i guess it's worth it. + if(prog.downloaderror) // Download errored. Wait until user resets the program. + data["error"] = prog.downloaderror + if(prog.downloaded_file) // Download running. Wait please.. + data["downloadname"] = prog.downloaded_file.filename + data["downloaddesc"] = prog.downloaded_file.filedesc + data["downloadsize"] = prog.downloaded_file.size + data["downloadspeed"] = prog.download_netspeed + data["downloadcompletion"] = round(prog.download_completion, 0.1) + + data["disk_size"] = my_computer.hard_drive.max_capacity + data["disk_used"] = my_computer.hard_drive.used_capacity + var/list/all_entries[0] + for(var/datum/computer_file/program/P in ntnet_global.available_station_software) + // Only those programs our user can run will show in the list + if(!P.can_run(user) && P.requires_access_to_download) + continue + all_entries.Add(list(list( + "filename" = P.filename, + "filedesc" = P.filedesc, + "fileinfo" = P.extended_desc, + "size" = P.size, + "icon" = P.program_menu_icon + ))) + data["hackedavailable"] = 0 + if(prog.computer_emagged) // If we are running on emagged computer we have access to some "bonus" software + var/list/hacked_programs[0] + for(var/datum/computer_file/program/P in ntnet_global.available_antag_software) + data["hackedavailable"] = 1 + hacked_programs.Add(list(list( + "filename" = P.filename, + "filedesc" = P.filedesc, + "fileinfo" = P.extended_desc, + "size" = P.size, + "icon" = P.program_menu_icon + ))) + data["hacked_programs"] = hacked_programs + + data["downloadable_programs"] = all_entries + + if(prog.downloads_queue.len > 0) + data["downloads_queue"] = prog.downloads_queue + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "ntnet_downloader.tmpl", "NTNet Download Program", 575, 700, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) diff --git a/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm b/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm new file mode 100644 index 00000000..04e99bf0 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm @@ -0,0 +1,232 @@ +/datum/computer_file/program/chatclient + filename = "ntnrc_client" + filedesc = "NTNet Relay Chat Client" + program_icon_state = "command" + program_key_state = "med_key" + program_menu_icon = "comment" + extended_desc = "This program allows communication over NTNRC network" + size = 8 + requires_ntnet = 1 + requires_ntnet_feature = NTNET_COMMUNICATION + network_destination = "NTNRC server" + ui_header = "ntnrc_idle.gif" + available_on_ntnet = 1 + nanomodule_path = /datum/nano_module/program/computer_chatclient/ + var/last_message = null // Used to generate the toolbar icon + var/username + var/datum/ntnet_conversation/channel = null + var/operator_mode = 0 // Channel operator mode + var/netadmin_mode = 0 // Administrator mode (invisible to other users + bypasses passwords) + +/datum/computer_file/program/chatclient/New() + username = "DefaultUser[rand(100, 999)]" + +/datum/computer_file/program/chatclient/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["PRG_speak"]) + . = 1 + if(!channel) + return 1 + var/mob/living/user = usr + var/message = sanitize(input(user, "Enter message or leave blank to cancel: "), 512) + if(!message || !channel) + return + channel.add_message(message, username) + + if(href_list["PRG_joinchannel"]) + . = 1 + var/datum/ntnet_conversation/C + for(var/datum/ntnet_conversation/chan in ntnet_global.chat_channels) + if(chan.id == text2num(href_list["PRG_joinchannel"])) + C = chan + break + + if(!C) + return 1 + + if(netadmin_mode) + channel = C // Bypasses normal leave/join and passwords. Technically makes the user invisible to others. + return 1 + + if(C.password) + var/mob/living/user = usr + var/password = sanitize(input(user,"Access Denied. Enter password:")) + if(C && (password == C.password)) + C.add_client(src) + channel = C + return 1 + C.add_client(src) + channel = C + if(href_list["PRG_leavechannel"]) + . = 1 + if(channel) + channel.remove_client(src) + channel = null + if(href_list["PRG_newchannel"]) + . = 1 + var/mob/living/user = usr + var/channel_title = sanitizeSafe(input(user,"Enter channel name or leave blank to cancel:"), 64) + if(!channel_title) + return + var/datum/ntnet_conversation/C = new/datum/ntnet_conversation() + C.add_client(src) + C.operator = src + channel = C + C.title = channel_title + if(href_list["PRG_toggleadmin"]) + . = 1 + if(netadmin_mode) + netadmin_mode = 0 + if(channel) + channel.remove_client(src) // We shouldn't be in channel's user list, but just in case... + channel = null + return 1 + var/mob/living/user = usr + if(can_run(usr, 1, access_network)) + if(channel) + var/response = alert(user, "Really engage admin-mode? You will be disconnected from your current channel!", "NTNRC Admin mode", "Yes", "No") + if(response == "Yes") + if(channel) + channel.remove_client(src) + channel = null + else + return + netadmin_mode = 1 + if(href_list["PRG_changename"]) + . = 1 + var/mob/living/user = usr + var/newname = sanitize(input(user,"Enter new nickname or leave blank to cancel:"), 20) + if(!newname) + return 1 + if(channel) + channel.add_status_message("[username] is now known as [newname].") + username = newname + + if(href_list["PRG_savelog"]) + . = 1 + if(!channel) + return + var/mob/living/user = usr + var/logname = input(user,"Enter desired logfile name (.log) or leave blank to cancel:") + if(!logname || !channel) + return 1 + var/datum/computer_file/data/logfile = new/datum/computer_file/data/logfile() + // Now we will generate HTML-compliant file that can actually be viewed/printed. + logfile.filename = logname + logfile.stored_data = "\[b\]Logfile dump from NTNRC channel [channel.title]\[/b\]\[BR\]" + for(var/logstring in channel.messages) + logfile.stored_data += "[logstring]\[BR\]" + logfile.stored_data += "\[b\]Logfile dump completed.\[/b\]" + logfile.calculate_size() + if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(logfile)) + if(!computer) + // This program shouldn't even be runnable without computer. + CRASH("Var computer is null!") + return 1 + if(!computer.hard_drive) + computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive connection error\" warning.") + else // In 99.9% cases this will mean our HDD is full + computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive may be full. Please free some space and try again. Required space: [logfile.size]GQ\" warning.") + if(href_list["PRG_renamechannel"]) + . = 1 + if(!operator_mode || !channel) + return 1 + var/mob/living/user = usr + var/newname = sanitize(input(user, "Enter new channel name or leave blank to cancel:"), 64) + if(!newname || !channel) + return + channel.add_status_message("Channel renamed from [channel.title] to [newname] by operator.") + channel.title = newname + if(href_list["PRG_deletechannel"]) + . = 1 + if(channel && ((channel.operator == src) || netadmin_mode)) + qdel(channel) + channel = null + if(href_list["PRG_setpassword"]) + . = 1 + if(!channel || ((channel.operator != src) && !netadmin_mode)) + return 1 + + var/mob/living/user = usr + var/newpassword = sanitize(input(user, "Enter new password for this channel. Leave blank to cancel, enter 'nopassword' to remove password completely:")) + if(!channel || !newpassword || ((channel.operator != src) && !netadmin_mode)) + return 1 + + if(newpassword == "nopassword") + channel.password = "" + else + channel.password = newpassword + +/datum/computer_file/program/chatclient/process_tick() + ..() + if(program_state != PROGRAM_STATE_KILLED) + ui_header = "ntnrc_idle.gif" + if(channel) + // Remember the last message. If there is no message in the channel remember null. + last_message = channel.messages.len ? channel.messages[channel.messages.len - 1] : null + else + last_message = null + return 1 + if(channel && channel.messages && channel.messages.len) + ui_header = last_message == channel.messages[channel.messages.len - 1] ? "ntnrc_idle.gif" : "ntnrc_new.gif" + else + ui_header = "ntnrc_idle.gif" + +/datum/computer_file/program/chatclient/kill_program(var/forced = 0) + if(channel) + channel.remove_client(src) + channel = null + ..(forced) + +/datum/nano_module/program/computer_chatclient + name = "NTNet Relay Chat Client" + +/datum/nano_module/program/computer_chatclient/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + if(!ntnet_global || !ntnet_global.chat_channels) + return + + var/list/data = list() + if(program) + data = program.get_header_data() + + var/datum/computer_file/program/chatclient/C = program + if(!istype(C)) + return + + data["adminmode"] = C.netadmin_mode + if(C.channel) + data["title"] = C.channel.title + var/list/messages[0] + for(var/M in C.channel.messages) + messages.Add(list(list( + "msg" = M + ))) + data["messages"] = messages + var/list/clients[0] + for(var/datum/computer_file/program/chatclient/cl in C.channel.clients) + clients.Add(list(list( + "name" = cl.username + ))) + data["clients"] = clients + C.operator_mode = (C.channel.operator == C) ? 1 : 0 + data["is_operator"] = C.operator_mode || C.netadmin_mode + + else // Channel selection screen + var/list/all_channels[0] + for(var/datum/ntnet_conversation/conv in ntnet_global.chat_channels) + if(conv && conv.title) + all_channels.Add(list(list( + "chan" = conv.title, + "id" = conv.id + ))) + data["all_channels"] = all_channels + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "ntnet_chat.tmpl", "NTNet Relay Chat Client", 575, 700, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) diff --git a/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm b/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm new file mode 100644 index 00000000..fc2ea95c --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm @@ -0,0 +1,185 @@ +var/global/nttransfer_uid = 0 + +/datum/computer_file/program/nttransfer + filename = "nttransfer" + filedesc = "NTNet P2P Transfer Client" + extended_desc = "This program allows for simple file transfer via direct peer to peer connection." + program_icon_state = "comm_logs" + program_key_state = "generic_key" + program_menu_icon = "transferthick-e-w" + size = 7 + requires_ntnet = 1 + requires_ntnet_feature = NTNET_PEERTOPEER + network_destination = "other device via P2P tunnel" + available_on_ntnet = 1 + nanomodule_path = /datum/nano_module/program/computer_nttransfer/ + + var/error = "" // Error screen + var/server_password = "" // Optional password to download the file. + var/datum/computer_file/provided_file = null // File which is provided to clients. + var/datum/computer_file/downloaded_file = null // File which is being downloaded + var/list/connected_clients = list() // List of connected clients. + var/datum/computer_file/program/nttransfer/remote // Client var, specifies who are we downloading from. + var/download_completion = 0 // Download progress in GQ + var/actual_netspeed = 0 // Displayed in the UI, this is the actual transfer speed. + var/unique_token // UID of this program + var/upload_menu = 0 // Whether we show the program list and upload menu + +/datum/computer_file/program/nttransfer/New() + unique_token = nttransfer_uid + nttransfer_uid++ + ..() + +/datum/computer_file/program/nttransfer/process_tick() + ..() + // Server mode + if(provided_file) + for(var/datum/computer_file/program/nttransfer/C in connected_clients) + // Transfer speed is limited by device which uses slower connectivity. + // We can have multiple clients downloading at same time, but let's assume we use some sort of multicast transfer + // so they can all run on same speed. + C.actual_netspeed = min(C.ntnet_speed, ntnet_speed) + C.download_completion += C.actual_netspeed + if(C.download_completion >= provided_file.size) + C.finish_download() + else if(downloaded_file) // Client mode + if(!remote) + crash_download("Connection to remote server lost") + +/datum/computer_file/program/nttransfer/kill_program(var/forced = 0) + if(downloaded_file) // Client mode, clean up variables for next use + finalize_download() + + if(provided_file) // Server mode, disconnect all clients + for(var/datum/computer_file/program/nttransfer/P in connected_clients) + P.crash_download("Connection terminated by remote server") + downloaded_file = null + ..(forced) + +// Finishes download and attempts to store the file on HDD +/datum/computer_file/program/nttransfer/proc/finish_download() + if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(downloaded_file)) + error = "I/O Error: Unable to save file. Check your hard drive and try again." + finalize_download() + +// Crashes the download and displays specific error message +/datum/computer_file/program/nttransfer/proc/crash_download(var/message) + error = message ? message : "An unknown error has occured during download" + finalize_download() + +// Cleans up variables for next use +/datum/computer_file/program/nttransfer/proc/finalize_download() + if(remote) + remote.connected_clients.Remove(src) + downloaded_file = null + remote = null + download_completion = 0 + + +/datum/nano_module/program/computer_nttransfer + name = "NTNet P2P Transfer Client" + +/datum/nano_module/program/computer_nttransfer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + if(!program) + return + var/datum/computer_file/program/nttransfer/PRG = program + if(!istype(PRG)) + return + + var/list/data = program.get_header_data() + + if(PRG.error) + data["error"] = PRG.error + else if(PRG.downloaded_file) + data["downloading"] = 1 + data["download_size"] = PRG.downloaded_file.size + data["download_progress"] = PRG.download_completion + data["download_netspeed"] = PRG.actual_netspeed + data["download_name"] = "[PRG.downloaded_file.filename].[PRG.downloaded_file.filetype]" + else if (PRG.provided_file) + data["uploading"] = 1 + data["upload_uid"] = PRG.unique_token + data["upload_clients"] = PRG.connected_clients.len + data["upload_haspassword"] = PRG.server_password ? 1 : 0 + data["upload_filename"] = "[PRG.provided_file.filename].[PRG.provided_file.filetype]" + else if (PRG.upload_menu) + var/list/all_files[0] + for(var/datum/computer_file/F in PRG.computer.hard_drive.stored_files) + all_files.Add(list(list( + "uid" = F.uid, + "filename" = "[F.filename].[F.filetype]", + "size" = F.size + ))) + data["upload_filelist"] = all_files + else + var/list/all_servers[0] + for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers) + if(!P.provided_file) + continue + all_servers.Add(list(list( + "uid" = P.unique_token, + "filename" = "[P.provided_file.filename].[P.provided_file.filetype]", + "size" = P.provided_file.size, + "haspassword" = P.server_password ? 1 : 0 + ))) + data["servers"] = all_servers + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "ntnet_transfer.tmpl", "NTNet P2P Transfer Client", 575, 700, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/computer_file/program/nttransfer/Topic(href, href_list) + if(..()) + return 1 + if(href_list["PRG_downloadfile"]) + for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers) + if("[P.unique_token]" == href_list["PRG_downloadfile"]) + remote = P + break + if(!remote || !remote.provided_file) + return + if(remote.server_password) + var/pass = sanitize(input(usr, "Code 401 Unauthorized. Please enter password:", "Password required")) + if(pass != remote.server_password) + error = "Incorrect Password" + return + downloaded_file = remote.provided_file.clone() + remote.connected_clients.Add(src) + return 1 + if(href_list["PRG_reset"]) + error = "" + upload_menu = 0 + finalize_download() + if(src in ntnet_global.fileservers) + ntnet_global.fileservers.Remove(src) + for(var/datum/computer_file/program/nttransfer/T in connected_clients) + T.crash_download("Remote server has forcibly closed the connection") + provided_file = null + return 1 + if(href_list["PRG_setpassword"]) + var/pass = sanitize(input(usr, "Enter new server password. Leave blank to cancel, input 'none' to disable password.", "Server security", "none")) + if(!pass) + return + if(pass == "none") + server_password = "" + return + server_password = pass + return 1 + if(href_list["PRG_uploadfile"]) + for(var/datum/computer_file/F in computer.hard_drive.stored_files) + if("[F.uid]" == href_list["PRG_uploadfile"]) + if(F.unsendable) + error = "I/O Error: File locked." + return + provided_file = F + ntnet_global.fileservers.Add(src) + return + error = "I/O Error: Unable to locate file on hard drive." + return 1 + if(href_list["PRG_uploadmenu"]) + upload_menu = 1 + return 0 diff --git a/code/modules/modular_computers/file_system/programs/generic/records.dm b/code/modules/modular_computers/file_system/programs/generic/records.dm new file mode 100644 index 00000000..15c1e6b3 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/records.dm @@ -0,0 +1,168 @@ +/datum/computer_file/program/records + filename = "crewrecords" + filedesc = "Crew Records" + extended_desc = "This program allows access to the crew's various records." + program_icon_state = "generic" + program_key_state = "generic_key" + size = 14 + requires_ntnet = 1 + available_on_ntnet = 1 + nanomodule_path = /datum/nano_module/records + +/datum/nano_module/records + name = "Crew Records" + var/datum/computer_file/crew_record/active_record + var/message = null + +/datum/nano_module/records/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = GLOB.default_state) + var/list/data = host.initial_data() + var/list/user_access = get_record_access(user) + + data["message"] = message + if(active_record) + user << browse_rsc(active_record.photo_front, "front_[active_record.uid].png") + user << browse_rsc(active_record.photo_side, "side_[active_record.uid].png") + data["pic_edit"] = check_access(user, access_heads) || check_access(user, access_security) + data["uid"] = active_record.uid + var/list/fields = list() + for(var/record_field/F in active_record.fields) + if(F.can_see(user_access)) + fields.Add(list(list( + "key" = F.type, + "name" = F.name, + "val" = F.get_display_value(), + "editable" = F.can_edit(user_access), + "large" = (F.valtype == EDIT_LONGTEXT) + ))) + data["fields"] = fields + else + var/list/all_records = list() + + for(var/datum/computer_file/crew_record/R in GLOB.all_crew_records) + all_records.Add(list(list( + "name" = R.get_name(), + "rank" = R.get_job(), + "milrank" = R.get_rank(), + "id" = R.uid + ))) + data["all_records"] = all_records + data["creation"] = check_access(user, access_heads) + data["dnasearch"] = check_access(user, access_medical) || check_access(user, access_forensics_lockers) + data["fingersearch"] = check_access(user, access_security) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "crew_records.tmpl", name, 700, 540, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + + +/datum/nano_module/records/proc/get_record_access(var/mob/user) + var/list/user_access = using_access || user.GetAccess() + + var/obj/item/modular_computer/PC = nano_host() + if(istype(PC) && PC.computer_emagged) + user_access = user_access.Copy() + user_access |= access_syndicate + + return user_access + +/datum/nano_module/records/proc/edit_field(var/mob/user, var/field) + var/datum/computer_file/crew_record/R = active_record + if(!R) + return + var/record_field/F = locate(field) in R.fields + if(!F) + return + + if(!F.can_edit(get_record_access(user))) + to_chat(user, "\The [nano_host()] flashes an \"Access Denied\" warning.") + return + + var/newValue + switch(F.valtype) + if(EDIT_SHORTTEXT) + newValue = input(user, "Enter [F.name]:", "Record edit", html_decode(F.get_value())) as null|text + if(EDIT_LONGTEXT) + newValue = replacetext(input(user, "Enter [F.name]. You may use HTML paper formatting tags:", "Record edit", replacetext(html_decode(F.get_value()), "\[br\]", "\n")) as null|message, "\n", "\[br\]") + if(EDIT_NUMERIC) + newValue = input(user, "Enter [F.name]:", "Record edit", F.get_value()) as null|num + if(EDIT_LIST) + var/options = F.get_options() + newValue = input(user,"Pick [F.name]:", "Record edit", F.get_value()) as null|anything in options + + if(active_record != R) + return + if(!F.can_edit(get_record_access(user))) + to_chat(user, "\The [nano_host()] flashes an \"Access Denied\" warning.") + return + if(newValue) + return F.set_value(newValue) + +/datum/nano_module/records/Topic(href, href_list) + if(..()) + return 1 + if(href_list["clear_active"]) + active_record = null + return 1 + if(href_list["clear_message"]) + message = null + return 1 + if(href_list["set_active"]) + var/ID = text2num(href_list["set_active"]) + for(var/datum/computer_file/crew_record/R in GLOB.all_crew_records) + if(R.uid == ID) + active_record = R + break + return 1 + if(href_list["new_record"]) + if(!check_access(usr, access_heads)) + to_chat(usr, "Access Denied.") + return + active_record = new/datum/computer_file/crew_record() + GLOB.all_crew_records.Add(active_record) + return 1 + if(href_list["print_active"]) + if(!active_record) + return + print_text(record_to_html(active_record, get_record_access(usr)), usr) + return 1 + if(href_list["search"]) + var/field = text2path("/record_field/"+href_list["search"]) + var/search = sanitize(input("Enter the value for search for.") as null|text) + if(!search) + return + for(var/datum/computer_file/crew_record/R in GLOB.all_crew_records) + if(lowertext(R.get_field(field)) == lowertext(search)) + active_record = R + return 1 + message = "Unable to find record containing '[search]'" + return 1 + + var/datum/computer_file/crew_record/R = active_record + if(!istype(R)) + return 1 + if(href_list["edit_photo_front"]) + var/photo = get_photo(usr) + if(photo && active_record) + active_record.photo_front = photo + return 1 + if(href_list["edit_photo_side"]) + var/photo = get_photo(usr) + if(photo && active_record) + active_record.photo_side = photo + return 1 + if(href_list["edit_field"]) + edit_field(usr, text2path(href_list["edit_field"])) + return 1 + +/datum/nano_module/records/proc/get_photo(var/mob/user) + if(istype(user.get_active_hand(), /obj/item/weapon/photo)) + var/obj/item/weapon/photo/photo = user.get_active_hand() + return photo.img + if(istype(user, /mob/living/silicon)) + var/mob/living/silicon/tempAI = usr + var/obj/item/weapon/photo/selection = tempAI.GetPicture() + if (selection) + return selection.img diff --git a/code/modules/modular_computers/file_system/programs/generic/supply.dm b/code/modules/modular_computers/file_system/programs/generic/supply.dm new file mode 100644 index 00000000..095519bb --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/supply.dm @@ -0,0 +1,273 @@ +/datum/computer_file/program/supply + filename = "supply" + filedesc = "Supply Management" + nanomodule_path = /datum/nano_module/supply + program_icon_state = "supply" + program_key_state = "rd_key" + program_menu_icon = "cart" + extended_desc = "A management tool that allows for ordering of various supplies through the facility's cargo system. Some features may require additional access." + size = 21 + available_on_ntnet = 1 + requires_ntnet = 1 + +/datum/computer_file/program/supply/process_tick() + ..() + var/datum/nano_module/supply/SNM = NM + if(istype(SNM)) + SNM.emagged = computer_emagged + +/datum/nano_module/supply + name = "Supply Management program" + var/screen = 1 // 0: Ordering menu, 1: Statistics 2: Shuttle control, 3: Orders menu + var/selected_category + var/list/category_names + var/list/category_contents + var/emagged = FALSE // TODO: Implement synchronisation with modular computer framework. + var/current_security_level + +/datum/nano_module/supply/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = GLOB.default_state) + var/list/data = host.initial_data() + var/is_admin = check_access(user, access_cargo) + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + if(!category_names || !category_contents || current_security_level != security_state.current_security_level) + generate_categories() + current_security_level = security_state.current_security_level + + data["is_admin"] = is_admin + data["screen"] = screen + data["credits"] = "[supply_controller.points]" + switch(screen) + if(1)// Main ordering menu + data["categories"] = category_names + if(selected_category) + data["category"] = selected_category + data["possible_purchases"] = category_contents[selected_category] + + if(2)// Statistics screen with credit overview + data["total_credits"] = supply_controller.point_sources["total"] ? supply_controller.point_sources["total"] : 0 + data["credits_passive"] = supply_controller.point_sources["time"] ? supply_controller.point_sources["time"] : 0 + data["credits_crates"] = supply_controller.point_sources["crate"] ? supply_controller.point_sources["crate"] : 0 + data["credits_phoron"] = supply_controller.point_sources["phoron"] ? supply_controller.point_sources["phoron"] : 0 + data["credits_platinum"] = supply_controller.point_sources["platinum"] ? supply_controller.point_sources["platinum"] : 0 + data["credits_paperwork"] = supply_controller.point_sources["manifest"] ? supply_controller.point_sources["manifest"] : 0 + data["credits_virology"] = supply_controller.point_sources["virology"] ? supply_controller.point_sources["virology"] : 0 + data["can_print"] = can_print() + + if(3)// Shuttle monitoring and control + var/datum/shuttle/autodock/ferry/supply/shuttle = supply_controller.shuttle + if(istype(shuttle)) + data["shuttle_location"] = shuttle.at_station() ? GLOB.using_map.name : "Remote location" + else + data["shuttle_location"] = "No Connection" + data["shuttle_status"] = get_shuttle_status() + data["shuttle_can_control"] = shuttle.can_launch() + + + if(4)// Order processing + var/list/cart[0] + var/list/requests[0] + var/list/done[0] + for(var/datum/supply_order/SO in supply_controller.shoppinglist) + cart.Add(order_to_nanoui(SO)) + for(var/datum/supply_order/SO in supply_controller.requestlist) + requests.Add(order_to_nanoui(SO)) + for(var/datum/supply_order/SO in supply_controller.donelist) + done.Add(order_to_nanoui(SO)) + data["cart"] = cart + data["requests"] = requests + data["done"] = done + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "supply.tmpl", name, 1050, 800, state = state) + ui.set_auto_update(1) + ui.set_initial_data(data) + ui.open() + +/datum/nano_module/supply/Topic(href, href_list) + var/mob/user = usr + if(..()) + return 1 + + if(href_list["select_category"]) + selected_category = href_list["select_category"] + return 1 + + if(href_list["set_screen"]) + screen = text2num(href_list["set_screen"]) + return 1 + + if(href_list["order"]) + var/decl/hierarchy/supply_pack/P = locate(href_list["order"]) in supply_controller.master_supply_list + if(!istype(P) || P.is_category()) + return 1 + + if(P.hidden && !emagged) + return 1 + + var/reason = sanitize(input(user,"Reason:","Why do you require this item?","") as null|text,,0) + if(!reason) + return 1 + + var/idname = "*None Provided*" + var/idrank = "*None Provided*" + if(ishuman(user)) + var/mob/living/carbon/human/H = user + idname = H.get_authentification_name() + idrank = H.get_assignment() + else if(issilicon(user)) + idname = user.real_name + + supply_controller.ordernum++ + + var/datum/supply_order/O = new /datum/supply_order() + O.ordernum = supply_controller.ordernum + O.object = P + O.orderedby = idname + O.reason = reason + O.orderedrank = idrank + O.comment = "#[O.ordernum]" + supply_controller.requestlist += O + + if(can_print() && alert(user, "Would you like to print a confirmation receipt?", "Print receipt?", "Yes", "No") == "Yes") + print_order(O, user) + return 1 + + if(href_list["print_summary"]) + if(!can_print()) + return + print_summary(user) + + // Items requiring cargo access go below this entry. Other items go above. + if(!check_access(access_cargo)) + return 1 + + if(href_list["launch_shuttle"]) + var/datum/shuttle/autodock/ferry/supply/shuttle = supply_controller.shuttle + if(!shuttle) + to_chat(user, "Error connecting to the shuttle.") + return + if(shuttle.at_station()) + if (shuttle.forbidden_atoms_check()) + to_chat(usr, "For safety reasons the automated supply shuttle cannot transport live organisms, classified nuclear weaponry or homing beacons.") + else + shuttle.launch(user) + else + shuttle.launch(user) + var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) + if(!frequency) + return + + var/datum/signal/status_signal = new + status_signal.source = src + status_signal.transmission_method = 1 + status_signal.data["command"] = "supply" + frequency.post_signal(src, status_signal) + return 1 + + if(href_list["approve_order"]) + var/id = text2num(href_list["approve_order"]) + for(var/datum/supply_order/SO in supply_controller.requestlist) + if(SO.ordernum != id) + continue + if(SO.object.cost > supply_controller.points) + to_chat(usr, "Not enough points to purchase \the [SO.object.name]!") + return 1 + supply_controller.requestlist -= SO + supply_controller.shoppinglist += SO + supply_controller.points -= SO.object.cost + break + return 1 + + if(href_list["deny_order"]) + var/id = text2num(href_list["deny_order"]) + for(var/datum/supply_order/SO in supply_controller.requestlist) + if(SO.ordernum == id) + supply_controller.requestlist -= SO + break + return 1 + + if(href_list["cancel_order"]) + var/id = text2num(href_list["cancel_order"]) + for(var/datum/supply_order/SO in supply_controller.shoppinglist) + if(SO.ordernum == id) + supply_controller.shoppinglist -= SO + supply_controller.points += SO.object.cost + break + return 1 + + if(href_list["delete_order"]) + var/id = text2num(href_list["delete_order"]) + for(var/datum/supply_order/SO in supply_controller.donelist) + if(SO.ordernum == id) + supply_controller.donelist -= SO + break + return 1 + +/datum/nano_module/supply/proc/generate_categories() + category_names = list() + category_contents = list() + for(var/decl/hierarchy/supply_pack/sp in cargo_supply_pack_root.children) + if(sp.is_category()) + category_names.Add(sp.name) + var/list/category[0] + for(var/decl/hierarchy/supply_pack/spc in sp.children) + if((spc.hidden || spc.contraband || !spc.sec_available()) && !emagged) + continue + category.Add(list(list( + "name" = spc.name, + "cost" = spc.cost, + "ref" = "\ref[spc]" + ))) + category_contents[sp.name] = category + +/datum/nano_module/supply/proc/get_shuttle_status() + var/datum/shuttle/autodock/ferry/supply/shuttle = supply_controller.shuttle + if(!istype(shuttle)) + return "No Connection" + + if(shuttle.has_arrive_time()) + return "In transit ([shuttle.eta_seconds()] s)" + + if (shuttle.can_launch()) + return "Docked" + return "Docking/Undocking" + +/datum/nano_module/supply/proc/order_to_nanoui(var/datum/supply_order/SO) + return list(list( + "id" = SO.ordernum, + "object" = SO.object.name, + "orderer" = SO.orderedby, + "cost" = SO.object.cost, + "reason" = SO.reason + )) + +/datum/nano_module/supply/proc/can_print() + var/obj/item/modular_computer/MC = nano_host() + if(!istype(MC) || !istype(MC.nano_printer)) + return 0 + return 1 + +/datum/nano_module/supply/proc/print_order(var/datum/supply_order/O, var/mob/user) + if(!O) + return + + var/t = "" + t += "

            [GLOB.using_map.station_name] Supply Requisition Reciept


            " + t += "INDEX: #[O.ordernum]
            " + t += "REQUESTED BY: [O.orderedby]
            " + t += "RANK: [O.orderedrank]
            " + t += "REASON: [O.reason]
            " + t += "SUPPLY CRATE TYPE: [O.object.name]
            " + t += "ACCESS RESTRICTION: [get_access_desc(O.object.access)]
            " + t += "CONTENTS:
            " + t += O.object.manifest + t += "
            " + print_text(t, user) + +/datum/nano_module/supply/proc/print_summary(var/mob/user) + var/t = "" + t += "

            [GLOB.using_map.station_name]
            [station_date]
            Export overview

            " + for(var/source in point_source_descriptions) + t += "[point_source_descriptions[source]]: [supply_controller.point_sources[source] || 0]
            " + print_text(t, user) \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm b/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm new file mode 100644 index 00000000..ed647555 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm @@ -0,0 +1,236 @@ +/datum/computer_file/program/wordprocessor + filename = "wordprocessor" + filedesc = "NanoWord" + extended_desc = "This program allows the editing and preview of text documents." + program_icon_state = "word" + program_key_state = "atmos_key" + size = 4 + requires_ntnet = 0 + available_on_ntnet = 1 + nanomodule_path = /datum/nano_module/program/computer_wordprocessor/ + var/browsing + var/open_file + var/loaded_data + var/error + var/is_edited + +/datum/computer_file/program/wordprocessor/proc/get_file(var/filename) + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + if(!HDD) + return + var/datum/computer_file/data/F = HDD.find_file_by_name(filename) + if(!istype(F)) + return + return F + +/datum/computer_file/program/wordprocessor/proc/open_file(var/filename) + var/datum/computer_file/data/F = get_file(filename) + if(F) + open_file = F.filename + loaded_data = F.stored_data + return 1 + +/datum/computer_file/program/wordprocessor/proc/save_file(var/filename) + var/datum/computer_file/data/F = get_file(filename) + if(!F) //try to make one if it doesn't exist + F = create_file(filename, loaded_data) + return !isnull(F) + var/datum/computer_file/data/backup = F.clone() + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + if(!HDD) + return + HDD.remove_file(F) + F.stored_data = loaded_data + F.calculate_size() + if(!HDD.store_file(F)) + HDD.store_file(backup) + return 0 + is_edited = 0 + return 1 + +/datum/computer_file/program/wordprocessor/proc/create_file(var/newname, var/data = "") + if(!newname) + return + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + if(!HDD) + return + if(get_file(newname)) + return + var/datum/computer_file/data/F = new/datum/computer_file/data() + F.filename = newname + F.filetype = "TXT" + F.stored_data = data + F.calculate_size() + if(HDD.store_file(F)) + return F + +/datum/computer_file/program/wordprocessor/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["PRG_txtrpeview"]) + show_browser(usr,"[open_file][pencode2html(loaded_data)]", "window=[open_file]") + return 1 + + if(href_list["PRG_taghelp"]) + to_chat(usr, "The hologram of a googly-eyed paper clip helpfully tells you:") + var/help = {" + \[br\] : Creates a linebreak. + \[center\] - \[/center\] : Centers the text. + \[h1\] - \[/h1\] : First level heading. + \[h2\] - \[/h2\] : Second level heading. + \[h3\] - \[/h3\] : Third level heading. + \[b\] - \[/b\] : Bold. + \[i\] - \[/i\] : Italic. + \[u\] - \[/u\] : Underlined. + \[small\] - \[/small\] : Decreases the size of the text. + \[large\] - \[/large\] : Increases the size of the text. + \[field\] : Inserts a blank text field, which can be filled later. Useful for forms. + \[date\] : Current station date. + \[time\] : Current station time. + \[list\] - \[/list\] : Begins and ends a list. + \[*\] : A list item. + \[hr\] : Horizontal rule. + \[table\] - \[/table\] : Creates table using \[row\] and \[cell\] tags. + \[grid\] - \[/grid\] : Table without visible borders, for layouts. + \[row\] - New table row. + \[cell\] - New table cell. + \[logo\] - Inserts NT logo image. + \[bluelogo\] - Inserts blue NT logo image. + \[solcrest\] - Inserts SCG crest image. + \[terraseal\] - Inserts TCC seal"} + + to_chat(usr, help) + return 1 + + if(href_list["PRG_closebrowser"]) + browsing = 0 + return 1 + + if(href_list["PRG_backtomenu"]) + error = null + return 1 + + if(href_list["PRG_loadmenu"]) + browsing = 1 + return 1 + + if(href_list["PRG_openfile"]) + . = 1 + if(is_edited) + if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes") + save_file(open_file) + browsing = 0 + if(!open_file(href_list["PRG_openfile"])) + error = "I/O error: Unable to open file '[href_list["PRG_openfile"]]'." + + if(href_list["PRG_newfile"]) + . = 1 + if(is_edited) + if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes") + save_file(open_file) + + var/newname = sanitize(input(usr, "Enter file name:", "New File") as text|null) + if(!newname) + return 1 + var/datum/computer_file/data/F = create_file(newname) + if(F) + open_file = F.filename + loaded_data = "" + return 1 + else + error = "I/O error: Unable to create file '[href_list["PRG_saveasfile"]]'." + + if(href_list["PRG_saveasfile"]) + . = 1 + var/newname = sanitize(input(usr, "Enter file name:", "Save As") as text|null) + if(!newname) + return 1 + var/datum/computer_file/data/F = create_file(newname, loaded_data) + if(F) + open_file = F.filename + else + error = "I/O error: Unable to create file '[href_list["PRG_saveasfile"]]'." + return 1 + + if(href_list["PRG_savefile"]) + . = 1 + if(!open_file) + open_file = sanitize(input(usr, "Enter file name:", "Save As") as text|null) + if(!open_file) + return 0 + if(!save_file(open_file)) + error = "I/O error: Unable to save file '[open_file]'." + return 1 + + if(href_list["PRG_editfile"]) + var/oldtext = html_decode(loaded_data) + oldtext = replacetext(oldtext, "\[br\]", "\n") + + var/newtext = sanitize(replacetext(input(usr, "Editing file '[open_file]'. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH) + if(!newtext) + return + loaded_data = newtext + is_edited = 1 + return 1 + + if(href_list["PRG_printfile"]) + . = 1 + if(!computer.nano_printer) + error = "Missing Hardware: Your computer does not have the required hardware to complete this operation." + return 1 + if(!computer.nano_printer.print_text(pencode2html(loaded_data))) + error = "Hardware error: Printer was unable to print the file. It may be out of paper." + return 1 + +/datum/nano_module/program/computer_wordprocessor + name = "Word Processor" + +/datum/nano_module/program/computer_wordprocessor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + var/datum/computer_file/program/wordprocessor/PRG + PRG = program + + var/obj/item/weapon/computer_hardware/hard_drive/HDD + var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD + if(PRG.error) + data["error"] = PRG.error + if(PRG.browsing) + data["browsing"] = PRG.browsing + if(!PRG.computer || !PRG.computer.hard_drive) + data["error"] = "I/O ERROR: Unable to access hard drive." + else + HDD = PRG.computer.hard_drive + var/list/files[0] + for(var/datum/computer_file/F in HDD.stored_files) + if(F.filetype == "TXT") + files.Add(list(list( + "name" = F.filename, + "size" = F.size + ))) + data["files"] = files + + RHDD = PRG.computer.portable_drive + if(RHDD) + data["usbconnected"] = 1 + var/list/usbfiles[0] + for(var/datum/computer_file/F in RHDD.stored_files) + if(F.filetype == "TXT") + usbfiles.Add(list(list( + "name" = F.filename, + "size" = F.size, + ))) + data["usbfiles"] = usbfiles + else if(PRG.open_file) + data["filedata"] = pencode2html(PRG.loaded_data) + data["filename"] = PRG.is_edited ? "[PRG.open_file]*" : PRG.open_file + else + data["filedata"] = pencode2html(PRG.loaded_data) + data["filename"] = "UNNAMED" + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "word_processor.tmpl", "Word Processor", 575, 700, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/medical/suit_sensors.dm b/code/modules/modular_computers/file_system/programs/medical/suit_sensors.dm new file mode 100644 index 00000000..890c7285 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/medical/suit_sensors.dm @@ -0,0 +1,53 @@ +/datum/computer_file/program/suit_sensors + filename = "sensormonitor" + filedesc = "Suit Sensors Monitoring" + nanomodule_path = /datum/nano_module/crew_monitor + program_icon_state = "crew" + program_key_state = "med_key" + program_menu_icon = "heart" + extended_desc = "This program connects to life signs monitoring system to provide basic information on crew health." + required_access = access_medical + requires_ntnet = 1 + network_destination = "crew lifesigns monitoring system" + size = 11 + + + + + +/datum/nano_module/crew_monitor + name = "Crew monitor" + +/datum/nano_module/crew_monitor/Topic(href, href_list) + if(..()) return 1 + + if(href_list["track"]) + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + var/mob/living/carbon/human/H = locate(href_list["track"]) in SSmobs.mob_list + if(hassensorlevel(H, SUIT_SENSOR_TRACKING)) + AI.ai_actual_track(H) + return 1 + +/datum/nano_module/crew_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + + data["isAI"] = isAI(user) + data["crewmembers"] = list() + for(var/z_level in GLOB.using_map.map_levels) + data["crewmembers"] += crew_repository.health_data(z_level) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "crew_monitor.tmpl", "Crew Monitoring Computer", 900, 800, state = state) + + // adding a template with the key "mapContent" enables the map ui functionality + ui.add_template("mapContent", "crew_monitor_map_content.tmpl") + // adding a template with the key "mapHeader" replaces the map header content + ui.add_template("mapHeader", "crew_monitor_map_header.tmpl") + + ui.set_initial_data(data) + ui.open() + + // should make the UI auto-update; doesn't seem to? + ui.set_auto_update(1) diff --git a/code/modules/modular_computers/file_system/programs/research/ai_restorer.dm b/code/modules/modular_computers/file_system/programs/research/ai_restorer.dm new file mode 100644 index 00000000..2c4506af --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/research/ai_restorer.dm @@ -0,0 +1,119 @@ +/datum/computer_file/program/aidiag + filename = "aidiag" + filedesc = "AI Maintenance Utility" + program_icon_state = "generic" + program_key_state = "mining_key" + program_menu_icon = "person" + extended_desc = "This program is capable of reconstructing damaged AI systems. It can also be used to upload basic laws to the AI. Requires direct AI connection via inteliCard slot." + size = 12 + requires_ntnet = 0 + required_access = access_heads + requires_access_to_run = 0 + available_on_ntnet = 1 + nanomodule_path = /datum/nano_module/program/computer_aidiag/ + var/restoring = 0 + +/datum/computer_file/program/aidiag/proc/get_ai() + if(computer && computer.ai_slot && computer.ai_slot.check_functionality() && computer.ai_slot.enabled && computer.ai_slot.stored_card && computer.ai_slot.stored_card.carded_ai) + return computer.ai_slot.stored_card.carded_ai + return null + +/datum/computer_file/program/aidiag/Topic(href, href_list) + if(..()) + return 1 + var/mob/living/silicon/ai/A = get_ai() + if(!A) + return 0 + if(href_list["PRG_beginReconstruction"]) + if((A.hardware_integrity() < 100) || (A.backup_capacitor() < 100)) + restoring = 1 + return 1 + + // Following actions can only be used by non-silicon users, as they involve manipulation of laws. + if(issilicon(usr)) + return 0 + if(href_list["PRG_purgeAiLaws"]) + A.laws.clear_zeroth_laws() + A.laws.clear_ion_laws() + A.laws.clear_inherent_laws() + A.laws.clear_supplied_laws() + to_chat(A, "All laws purged.") + return 1 + if(href_list["PRG_resetLaws"]) + A.laws.clear_ion_laws() + A.laws.clear_supplied_laws() + to_chat(A, "Non-core laws reset.") + return 1 + if(href_list["PRG_uploadDefault"]) + A.laws = new GLOB.using_map.default_law_type + to_chat(A, "All laws purged. Default lawset uploaded.") + return 1 + if(href_list["PRG_addCustomSuppliedLaw"]) + var/law_to_add = sanitize(input("Please enter a new law for the AI.", "Custom Law Entry")) + var/sector = input("Please enter the priority for your new law. Can only write to law sectors 15 and above.", "Law Priority (15+)") as num + sector = between(MIN_SUPPLIED_LAW_NUMBER, sector, MAX_SUPPLIED_LAW_NUMBER) + A.add_supplied_law(sector, law_to_add) + to_chat(A, "Custom law uploaded to sector [sector]: [law_to_add].") + return 1 + + +/datum/computer_file/program/aidiag/process_tick() + var/mob/living/silicon/ai/A = get_ai() + if(!A || !restoring) + restoring = 0 // If the AI was removed, stop the restoration sequence. + return + A.adjustFireLoss(-4) + A.adjustBruteLoss(-4) + A.adjustOxyLoss(-4) + A.updatehealth() + // If the AI is dead, revive it. + if (A.health >= -100 && A.stat == DEAD) + A.set_stat(CONSCIOUS) + A.lying = 0 + A.switch_from_dead_to_living_mob_list() + A.add_ai_verbs() + A.update_icon() + var/obj/item/weapon/aicard/AC = A.loc + if(AC) + AC.update_icon() + // Finished restoring + if((A.hardware_integrity() == 100) && (A.backup_capacitor() == 100)) + restoring = 0 + +/datum/nano_module/program/computer_aidiag + name = "AI Maintenance Utility" + +/datum/nano_module/program/computer_aidiag/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + var/mob/living/silicon/ai/A + // A shortcut for getting the AI stored inside the computer. The program already does necessary checks. + if(program && istype(program, /datum/computer_file/program/aidiag)) + var/datum/computer_file/program/aidiag/AD = program + A = AD.get_ai() + + if(!A) + data["error"] = "No AI located" + else + data["ai_name"] = A.name + data["ai_integrity"] = A.hardware_integrity() + data["ai_capacitor"] = A.backup_capacitor() + data["ai_isdamaged"] = (A.hardware_integrity() < 100) || (A.backup_capacitor() < 100) + data["ai_isdead"] = (A.stat == DEAD) + + var/list/all_laws[0] + for(var/datum/ai_law/L in A.laws.all_laws()) + all_laws.Add(list(list( + "index" = L.index, + "text" = L.law + ))) + + data["ai_laws"] = all_laws + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "aidiag.tmpl", "AI Maintenance Utility", 600, 400, state = state) + if(host.update_layout()) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/research/email_administration.dm b/code/modules/modular_computers/file_system/programs/research/email_administration.dm new file mode 100644 index 00000000..d738a495 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/research/email_administration.dm @@ -0,0 +1,144 @@ +/datum/computer_file/program/email_administration + filename = "emailadmin" + filedesc = "Email Administration Utility" + extended_desc = "This program may be used to administrate NTNet's emailing service." + program_icon_state = "comm_monitor" + program_key_state = "generic_key" + program_menu_icon = "mail-open" + size = 12 + requires_ntnet = 1 + available_on_ntnet = 1 + nanomodule_path = /datum/nano_module/email_administration + required_access = access_network + + + + +/datum/nano_module/email_administration/ + name = "Email Client" + var/datum/computer_file/data/email_account/current_account = null + var/datum/computer_file/data/email_message/current_message = null + var/error = "" + +/datum/nano_module/email_administration/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + + if(error) + data["error"] = error + else if(istype(current_message)) + data["msg_title"] = current_message.title + data["msg_body"] = pencode2html(current_message.stored_data) + data["msg_timestamp"] = current_message.timestamp + data["msg_source"] = current_message.source + else if(istype(current_account)) + data["current_account"] = current_account.login + data["cur_suspended"] = current_account.suspended + var/list/all_messages = list() + for(var/datum/computer_file/data/email_message/message in (current_account.inbox | current_account.spam | current_account.deleted)) + all_messages.Add(list(list( + "title" = message.title, + "source" = message.source, + "timestamp" = message.timestamp, + "uid" = message.uid + ))) + data["messages"] = all_messages + data["messagecount"] = all_messages.len + else + var/list/all_accounts = list() + for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts) + if(!account.can_login) + continue + all_accounts.Add(list(list( + "login" = account.login, + "uid" = account.uid + ))) + data["accounts"] = all_accounts + data["accountcount"] = all_accounts.len + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "email_administration.tmpl", "Email Administration Utility", 600, 450, state = state) + if(host.update_layout()) + ui.auto_update_layout = 1 + ui.set_auto_update(1) + ui.set_initial_data(data) + ui.open() + + +/datum/nano_module/email_administration/Topic(href, href_list) + if(..()) + return 1 + + var/mob/user = usr + if(!istype(user)) + return 1 + + // High security - can only be operated when the user has an ID with access on them. + var/obj/item/weapon/card/id/I = user.GetIdCard() + if(!istype(I) || !(access_network in I.access)) + return 1 + + if(href_list["back"]) + if(error) + error = "" + else if(current_message) + current_message = null + else + current_account = null + return 1 + + if(href_list["ban"]) + if(!current_account) + return 1 + + current_account.suspended = !current_account.suspended + ntnet_global.add_log_with_ids_check("EMAIL LOG: SA-EDIT Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended by SA [I.registered_name] ([I.assignment]).") + error = "Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended." + return 1 + + if(href_list["changepass"]) + if(!current_account) + return 1 + + var/newpass = sanitize(input(user,"Enter new password for account [current_account.login]", "Password"), 100) + if(!newpass) + return 1 + current_account.password = newpass + ntnet_global.add_log_with_ids_check("EMAIL LOG: SA-EDIT Password for account [current_account.login] has been changed by SA [I.registered_name] ([I.assignment]).") + return 1 + + if(href_list["viewmail"]) + if(!current_account) + return 1 + + for(var/datum/computer_file/data/email_message/received_message in (current_account.inbox | current_account.spam | current_account.deleted)) + if(received_message.uid == text2num(href_list["viewmail"])) + current_message = received_message + break + return 1 + + if(href_list["viewaccount"]) + for(var/datum/computer_file/data/email_account/email_account in ntnet_global.email_accounts) + if(email_account.uid == text2num(href_list["viewaccount"])) + current_account = email_account + break + return 1 + + if(href_list["newaccount"]) + var/newdomain = sanitize(input(user,"Pick domain:", "Domain name") as null|anything in GLOB.using_map.usable_email_tlds) + if(!newdomain) + return 1 + var/newlogin = sanitize(input(user,"Pick account name (@[newdomain]):", "Account name"), 100) + if(!newlogin) + return 1 + + var/complete_login = "[newlogin]@[newdomain]" + if(ntnet_global.does_email_exist(complete_login)) + error = "Error creating account: An account with same address already exists." + return 1 + + var/datum/computer_file/data/email_account/new_account = new/datum/computer_file/data/email_account() + new_account.login = complete_login + new_account.password = GenerateKey() + error = "Email [new_account.login] has been created, with generated password [new_account.password]" + return 1 diff --git a/code/modules/modular_computers/file_system/programs/research/ntmonitor.dm b/code/modules/modular_computers/file_system/programs/research/ntmonitor.dm new file mode 100644 index 00000000..9e71d8ac --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/research/ntmonitor.dm @@ -0,0 +1,102 @@ +/datum/computer_file/program/ntnetmonitor + filename = "ntmonitor" + filedesc = "NTNet Diagnostics and Monitoring" + program_icon_state = "comm_monitor" + program_key_state = "generic_key" + program_menu_icon = "wrench" + extended_desc = "This program monitors the local NTNet network, provides access to logging systems, and allows for configuration changes" + size = 12 + requires_ntnet = 1 + required_access = access_network + available_on_ntnet = 1 + nanomodule_path = /datum/nano_module/computer_ntnetmonitor/ + +/datum/nano_module/computer_ntnetmonitor + name = "NTNet Diagnostics and Monitoring" + available_to_ai = TRUE + +/datum/nano_module/computer_ntnetmonitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + if(!ntnet_global) + return + var/list/data = host.initial_data() + + data["ntnetstatus"] = ntnet_global.check_function() + data["ntnetrelays"] = ntnet_global.relays.len + data["idsstatus"] = ntnet_global.intrusion_detection_enabled + data["idsalarm"] = ntnet_global.intrusion_detection_alarm + + data["config_softwaredownload"] = ntnet_global.setting_softwaredownload + data["config_peertopeer"] = ntnet_global.setting_peertopeer + data["config_communication"] = ntnet_global.setting_communication + data["config_systemcontrol"] = ntnet_global.setting_systemcontrol + + data["ntnetlogs"] = ntnet_global.logs + data["ntnetmaxlogs"] = ntnet_global.setting_maxlogcount + + data["banned_nids"] = list(ntnet_global.banned_nids) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "ntnet_monitor.tmpl", "NTNet Diagnostics and Monitoring Tool", 575, 700, state = state) + if(host.update_layout()) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/nano_module/computer_ntnetmonitor/Topic(href, href_list, state) + var/mob/user = usr + if(..()) + return 1 + if(href_list["resetIDS"]) + if(ntnet_global) + ntnet_global.resetIDS() + return 1 + if(href_list["toggleIDS"]) + if(ntnet_global) + ntnet_global.toggleIDS() + return 1 + if(href_list["toggleWireless"]) + if(!ntnet_global) + return 1 + + // NTNet is disabled. Enabling can be done without user prompt + if(ntnet_global.setting_disabled) + ntnet_global.setting_disabled = 0 + return 1 + + // NTNet is enabled and user is about to shut it down. Let's ask them if they really want to do it, as wirelessly connected computers won't connect without NTNet being enabled (which may prevent people from turning it back on) + if(!user) + return 1 + var/response = alert(user, "Really disable NTNet wireless? If your computer is connected wirelessly you won't be able to turn it back on! This will affect all connected wireless devices.", "NTNet shutdown", "Yes", "No") + if(response == "Yes") + ntnet_global.setting_disabled = 1 + return 1 + if(href_list["purgelogs"]) + if(ntnet_global) + ntnet_global.purge_logs() + return 1 + if(href_list["updatemaxlogs"]) + var/logcount = text2num(input(user,"Enter amount of logs to keep in memory ([MIN_NTNET_LOGS]-[MAX_NTNET_LOGS]):")) + if(ntnet_global) + ntnet_global.update_max_log_count(logcount) + return 1 + if(href_list["toggle_function"]) + if(!ntnet_global) + return 1 + ntnet_global.toggle_function(href_list["toggle_function"]) + return 1 + if(href_list["ban_nid"]) + if(!ntnet_global) + return 1 + var/nid = input(user,"Enter NID of device which you want to block from the network:", "Enter NID") as null|num + if(nid && CanUseTopic(user, state)) + ntnet_global.banned_nids |= nid + return 1 + if(href_list["unban_nid"]) + if(!ntnet_global) + return 1 + var/nid = input(user,"Enter NID of device which you want to unblock from the network:", "Enter NID") as null|num + if(nid && CanUseTopic(user, state)) + ntnet_global.banned_nids -= nid + return 1 \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/security/digitalwarrant.dm b/code/modules/modular_computers/file_system/programs/security/digitalwarrant.dm new file mode 100644 index 00000000..1596fa05 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/security/digitalwarrant.dm @@ -0,0 +1,170 @@ +LEGACY_RECORD_STRUCTURE(all_warrants, warrant) +/datum/computer_file/data/warrant/ + var/archived = FALSE + +/datum/computer_file/program/digitalwarrant + filename = "digitalwarrant" + filedesc = "Warrant Assistant" + extended_desc = "Official NTsec program for creation and handling of warrants." + size = 8 + program_icon_state = "warrant" + program_key_state = "security_key" + program_menu_icon = "star" + requires_ntnet = 1 + available_on_ntnet = 1 + required_access = access_security + usage_flags = PROGRAM_ALL + nanomodule_path = /datum/nano_module/digitalwarrant/ + +/datum/nano_module/digitalwarrant/ + name = "Warrant Assistant" + var/datum/computer_file/data/warrant/activewarrant + +/datum/nano_module/digitalwarrant/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = host.initial_data() + + if(activewarrant) + data["warrantname"] = activewarrant.fields["namewarrant"] + data["warrantcharges"] = activewarrant.fields["charges"] + data["warrantauth"] = activewarrant.fields["auth"] + data["type"] = activewarrant.fields["arrestsearch"] + else + var/list/arrestwarrants = list() + var/list/searchwarrants = list() + var/list/archivedwarrants = list() + for(var/datum/computer_file/data/warrant/W in GLOB.all_warrants) + var/charges = W.fields["charges"] + if(length(charges) > 50) + charges = copytext(charges, 1, 50) + "..." + var/warrant = list( + "warrantname" = W.fields["namewarrant"], + "charges" = charges, + "auth" = W.fields["auth"], + "id" = W.uid, + "arrestsearch" = W.fields["arrestsearch"], + "archived" = W.archived) + if (warrant["archived"]) + archivedwarrants.Add(list(warrant)) + else if(warrant["arrestsearch"] == "arrest") + arrestwarrants.Add(list(warrant)) + else + searchwarrants.Add(list(warrant)) + data["arrestwarrants"] = arrestwarrants.len ? arrestwarrants : null + data["searchwarrants"] = searchwarrants.len ? searchwarrants : null + data["archivedwarrants"] = archivedwarrants.len? archivedwarrants :null + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "digitalwarrant.tmpl", name, 700, 450, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + +/datum/nano_module/digitalwarrant/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["sw_menu"]) + activewarrant = null + + if(href_list["editwarrant"]) + . = 1 + for(var/datum/computer_file/data/warrant/W in GLOB.all_warrants) + if(W.uid == text2num(href_list["editwarrant"])) + activewarrant = W + break + + // The following actions will only be possible if the user has an ID with security access equipped. This is in line with modular computer framework's authentication methods, + // which also use RFID scanning to allow or disallow access to some functions. Anyone can view warrants, editing requires ID. This also prevents situations where you show a tablet + // to someone who is to be arrested, which allows them to change the stuff there. + + var/mob/user = usr + if(!istype(user)) + return + var/obj/item/weapon/card/id/I = user.GetIdCard() + if(!istype(I) || !I.registered_name || !(access_security in I.access)) + to_chat(user, "Authentication error: Unable to locate ID with apropriate access to allow this operation.") + return + + if(href_list["sendtoarchive"]) + . = 1 + for(var/datum/computer_file/data/warrant/W in GLOB.all_warrants) + if(W.uid == text2num(href_list["sendtoarchive"])) + W.archived = TRUE + break + + if(href_list["restore"]) + . = 1 + for(var/datum/computer_file/data/warrant/W in GLOB.all_warrants) + if(W.uid == text2num(href_list["restore"])) + W.archived = FALSE + break + + if(href_list["addwarrant"]) + . = 1 + var/datum/computer_file/data/warrant/W = new() + if(CanInteract(user, GLOB.default_state)) + if(href_list["addwarrant"] == "arrest") + W.fields["namewarrant"] = "Unknown" + W.fields["charges"] = "No charges present" + W.fields["auth"] = "Unauthorized" + W.fields["arrestsearch"] = "arrest" + if(href_list["addwarrant"] == "search") + W.fields["namewarrant"] = "Unknown" + W.fields["charges"] = "No reason given" + W.fields["auth"] = "Unauthorized" + W.fields["arrestsearch"] = "search" + activewarrant = W + + if(href_list["savewarrant"]) + . = 1 + broadcast_security_hud_message("\A [activewarrant.fields["arrestsearch"]] warrant for [activewarrant.fields["namewarrant"]] has been [(activewarrant in GLOB.all_warrants) ? "edited" : "uploaded"].", nano_host()) + GLOB.all_warrants |= activewarrant + activewarrant = null + + if(href_list["deletewarrant"]) + . = 1 + if(!activewarrant) + for(var/datum/computer_file/crew_record/W in GLOB.all_crew_records) + if(W.uid == text2num(href_list["deletewarrant"])) + activewarrant = W + break + GLOB.all_warrants -= activewarrant + activewarrant = null + + if(href_list["editwarrantname"]) + . = 1 + var/namelist = list() + for(var/datum/computer_file/crew_record/CR in GLOB.all_crew_records) + namelist += CR.get_name() + var/new_name = sanitize(input(usr, "Please input name") as null|anything in namelist) + if(CanInteract(user, GLOB.default_state)) + if (!new_name || !activewarrant) + return + activewarrant.fields["namewarrant"] = new_name + + if(href_list["editwarrantnamecustom"]) + . = 1 + var/new_name = sanitize(input("Please input name") as null|text) + if(CanInteract(user, GLOB.default_state)) + if (!new_name || !activewarrant) + return + activewarrant.fields["namewarrant"] = new_name + + if(href_list["editwarrantcharges"]) + . = 1 + var/new_charges = sanitize(input("Please input charges", "Charges", activewarrant.fields["charges"]) as null|text) + if(CanInteract(user, GLOB.default_state)) + if (!new_charges || !activewarrant) + return + activewarrant.fields["charges"] = new_charges + + if(href_list["editwarrantauth"]) + . = 1 + if(!activewarrant) + return + activewarrant.fields["auth"] = "[I.registered_name] - [I.assignment ? I.assignment : "(Unknown)"]" + + if(href_list["back"]) + . = 1 + activewarrant = null diff --git a/code/modules/modular_computers/hardware/_hardware.dm b/code/modules/modular_computers/hardware/_hardware.dm new file mode 100644 index 00000000..b70cfee4 --- /dev/null +++ b/code/modules/modular_computers/hardware/_hardware.dm @@ -0,0 +1,87 @@ +/obj/item/weapon/computer_hardware/ + name = "Hardware" + desc = "Unknown Hardware." + icon = 'icons/obj/modular_components.dmi' + var/obj/item/modular_computer/holder2 = null + var/power_usage = 0 // If the hardware uses extra power, change this. + var/enabled = 1 // If the hardware is turned off set this to 0. + var/critical = 1 // Prevent disabling for important component, like the HDD. + var/hardware_size = 1 // Limits which devices can contain this component. 1: Tablets/Laptops/Consoles, 2: Laptops/Consoles, 3: Consoles only + var/damage = 0 // Current damage level + var/max_damage = 100 // Maximal damage level. + var/damage_malfunction = 20 // "Malfunction" threshold. When damage exceeds this value the hardware piece will semi-randomly fail and do !!FUN!! things + var/damage_failure = 50 // "Failure" threshold. When damage exceeds this value the hardware piece will not work at all. + var/malfunction_probability = 10// Chance of malfunction when the component is damaged + +/obj/item/weapon/computer_hardware/attackby(var/obj/item/W as obj, var/mob/living/user as mob) + // Multitool. Runs diagnostics + if(isMultitool(W)) + to_chat(user, "***** DIAGNOSTICS REPORT *****") + diagnostics(user) + to_chat(user, "******************************") + return 1 + // Nanopaste. Repair all damage if present for a single unit. + var/obj/item/stack/S = W + if(istype(S, /obj/item/stack/nanopaste)) + if(!damage) + to_chat(user, "\The [src] doesn't seem to require repairs.") + return 1 + if(S.use(1)) + to_chat(user, "You apply a bit of \the [W] to \the [src]. It immediately repairs all damage.") + damage = 0 + return 1 + // Cable coil. Works as repair method, but will probably require multiple applications and more cable. + if(isCoil(S)) + if(!damage) + to_chat(user, "\The [src] doesn't seem to require repairs.") + return 1 + if(S.use(1)) + to_chat(user, "You patch up \the [src] with a bit of \the [W].") + take_damage(-10) + return 1 + return ..() + + +// Called on multitool click, prints diagnostic information to the user. +/obj/item/weapon/computer_hardware/proc/diagnostics(var/mob/user) + to_chat(user, "Hardware Integrity Test... (Corruption: [damage]/[max_damage]) [damage > damage_failure ? "FAIL" : damage > damage_malfunction ? "WARN" : "PASS"]") + +/obj/item/weapon/computer_hardware/New(var/obj/L) + w_class = hardware_size + if(istype(L, /obj/item/modular_computer)) + holder2 = L + return + +/obj/item/weapon/computer_hardware/Destroy() + holder2 = null + return ..() + +// Handles damage checks +/obj/item/weapon/computer_hardware/proc/check_functionality() + // Turned off + if(!enabled) + return 0 + // Too damaged to work at all. + if(damage > damage_failure) + return 0 + // Still working. Well, sometimes... + if(damage > damage_malfunction) + if(prob(malfunction_probability)) + return 0 + // Good to go. + return 1 + +/obj/item/weapon/computer_hardware/examine(var/mob/user) + . = ..() + if(damage > damage_failure) + to_chat(user, "It seems to be severely damaged!") + else if(damage > damage_malfunction) + to_chat(user, "It seems to be damaged!") + else if(damage) + to_chat(user, "It seems to be slightly damaged.") + +// Damages the component. Contains necessary checks. Negative damage "heals" the component. +/obj/item/weapon/computer_hardware/proc/take_damage(var/amount) + damage += round(amount) // We want nice rounded numbers here. + damage = between(0, damage, max_damage) // Clamp the value. + diff --git a/code/modules/modular_computers/hardware/ai_slot.dm b/code/modules/modular_computers/hardware/ai_slot.dm new file mode 100644 index 00000000..e5f124fb --- /dev/null +++ b/code/modules/modular_computers/hardware/ai_slot.dm @@ -0,0 +1,43 @@ +// A wrapper that allows the computer to contain an inteliCard. +/obj/item/weapon/computer_hardware/ai_slot + name = "inteliCard slot" + desc = "An IIS interlink with connection uplinks that allow the device to interface with most common inteliCard models. Too large to fit into tablets. Uses a lot of power when active." + icon_state = "aislot" + hardware_size = 1 + critical = 0 + power_usage = 100 + origin_tech = list(TECH_POWER = 2, TECH_DATA = 3) + var/obj/item/weapon/aicard/stored_card + var/power_usage_idle = 100 + var/power_usage_occupied = 2 KILOWATTS + +/obj/item/weapon/computer_hardware/ai_slot/proc/update_power_usage() + if(!stored_card || !stored_card.carded_ai) + power_usage = power_usage_idle + return + power_usage = power_usage_occupied + +/obj/item/weapon/computer_hardware/ai_slot/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(..()) + return 1 + if(istype(W, /obj/item/weapon/aicard)) + if(stored_card) + to_chat(user, "\The [src] is already occupied.") + return + user.drop_from_inventory(W) + stored_card = W + W.forceMove(src) + update_power_usage() + if(isScrewdriver(W)) + to_chat(user, "You manually remove \the [stored_card] from \the [src].") + stored_card.forceMove(get_turf(src)) + stored_card = null + update_power_usage() + +/obj/item/weapon/computer_hardware/ai_slot/Destroy() + if(holder2 && (holder2.ai_slot == src)) + holder2.ai_slot = null + if(stored_card) + stored_card.forceMove(get_turf(holder2)) + holder2 = null + return ..() diff --git a/code/modules/modular_computers/hardware/battery_module.dm b/code/modules/modular_computers/hardware/battery_module.dm new file mode 100644 index 00000000..6e64ac34 --- /dev/null +++ b/code/modules/modular_computers/hardware/battery_module.dm @@ -0,0 +1,82 @@ +// This device is wrapper for actual power cell. I have decided to not use power cells directly as even low-end cells available on station +// have tremendeous capacity in comparsion. Higher tier cells would provide your device with nearly infinite battery life, which is something i want to avoid. +/obj/item/weapon/computer_hardware/battery_module + name = "standard battery" + desc = "A standard power cell, commonly seen in high-end portable microcomputers or low-end laptops. It's rating is 75 Wh." + icon_state = "battery_normal" + critical = 1 + malfunction_probability = 1 + origin_tech = list(TECH_POWER = 1, TECH_ENGINEERING = 1) + var/battery_rating = 75 + var/obj/item/weapon/cell/battery = null + +/obj/item/weapon/computer_hardware/battery_module/advanced + name = "advanced battery" + desc = "An advanced power cell, often used in most laptops. It is too large to be fitted into smaller devices. It's rating is 110 Wh." + icon_state = "battery_advanced" + origin_tech = list(TECH_POWER = 2, TECH_ENGINEERING = 2) + hardware_size = 2 + battery_rating = 110 + +/obj/item/weapon/computer_hardware/battery_module/super + name = "super battery" + desc = "A very advanced power cell, often used in high-end devices, or as uninterruptable power supply for important consoles or servers. It's rating is 150 Wh." + icon_state = "battery_super" + origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 3) + hardware_size = 2 + battery_rating = 150 + +/obj/item/weapon/computer_hardware/battery_module/ultra + name = "ultra battery" + desc = "A very advanced large power cell. It's often used as uninterruptable power supply for critical consoles or servers. It's rating is 200 Wh." + icon_state = "battery_ultra" + origin_tech = list(TECH_POWER = 5, TECH_ENGINEERING = 4) + hardware_size = 3 + battery_rating = 200 + +/obj/item/weapon/computer_hardware/battery_module/micro + name = "micro battery" + desc = "A small power cell, commonly seen in most portable microcomputers. It's rating is 50 Wh." + icon_state = "battery_micro" + origin_tech = list(TECH_POWER = 2, TECH_ENGINEERING = 2) + battery_rating = 50 + +/obj/item/weapon/computer_hardware/battery_module/nano + name = "nano battery" + desc = "A tiny power cell, commonly seen in low-end portable microcomputers. It's rating is 30 Wh." + icon_state = "battery_nano" + origin_tech = list(TECH_POWER = 1, TECH_ENGINEERING = 1) + battery_rating = 30 + +// This is not intended to be obtainable in-game. Intended for adminbus and debugging purposes. +/obj/item/weapon/computer_hardware/battery_module/lambda + name = "lambda coil" + desc = "A very complex power source compatible with various computers. It is capable of providing power for nearly unlimited duration." + icon_state = "battery_lambda" + hardware_size = 1 + battery_rating = 3000 + +/obj/item/weapon/computer_hardware/battery_module/lambda/New() + ..() + battery = new/obj/item/weapon/cell/infinite(src) + + +/obj/item/weapon/computer_hardware/battery_module/diagnostics(var/mob/user) + ..() + to_chat(user, "Internal battery charge: [battery.charge]/[battery.maxcharge] CU") + +/obj/item/weapon/computer_hardware/battery_module/New() + battery = new/obj/item/weapon/cell(src) + battery.maxcharge = battery_rating + battery.charge = 0 + ..() + +/obj/item/weapon/computer_hardware/battery_module/Destroy() + QDEL_NULL(battery) + if(holder2 && (holder2.battery_module == src)) + holder2.ai_slot = null + return ..() + +/obj/item/weapon/computer_hardware/battery_module/proc/charge_to_full() + if(battery) + battery.charge = battery.maxcharge \ No newline at end of file diff --git a/code/modules/modular_computers/hardware/card_slot.dm b/code/modules/modular_computers/hardware/card_slot.dm new file mode 100644 index 00000000..4cf8afc7 --- /dev/null +++ b/code/modules/modular_computers/hardware/card_slot.dm @@ -0,0 +1,18 @@ +/obj/item/weapon/computer_hardware/card_slot + name = "RFID card slot" + desc = "Slot that allows this computer to write data on RFID cards. Necessary for some programs to run properly." + power_usage = 10 //W + critical = 0 + icon_state = "cardreader" + hardware_size = 1 + origin_tech = list(TECH_DATA = 2) + + var/obj/item/weapon/card/id/stored_card = null + +/obj/item/weapon/computer_hardware/card_slot/Destroy() + if(holder2 && (holder2.card_slot == src)) + holder2.card_slot = null + if(stored_card) + stored_card.forceMove(get_turf(holder2)) + holder2 = null + return ..() \ No newline at end of file diff --git a/code/modules/modular_computers/hardware/hard_drive.dm b/code/modules/modular_computers/hardware/hard_drive.dm new file mode 100644 index 00000000..98657c85 --- /dev/null +++ b/code/modules/modular_computers/hardware/hard_drive.dm @@ -0,0 +1,167 @@ +/obj/item/weapon/computer_hardware/hard_drive/ + name = "basic hard drive" + desc = "A small power efficient solid state drive, with 128GQ of storage capacity for use in basic computers where power efficiency is desired." + power_usage = 25 // SSD or something with low power usage + icon_state = "hdd_normal" + hardware_size = 1 + origin_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1) + var/max_capacity = 128 + var/used_capacity = 0 + var/list/stored_files = list() // List of stored files on this drive. DO NOT MODIFY DIRECTLY! + +/obj/item/weapon/computer_hardware/hard_drive/advanced + name = "advanced hard drive" + desc = "A small hybrid hard drive with 256GQ of storage capacity for use in higher grade computers where balance between power efficiency and capacity is desired." + max_capacity = 256 + origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + power_usage = 50 // Hybrid, medium capacity and medium power storage + icon_state = "hdd_advanced" + hardware_size = 2 + +/obj/item/weapon/computer_hardware/hard_drive/super + name = "super hard drive" + desc = "A small hard drive with 512GQ of storage capacity for use in cluster storage solutions where capacity is more important than power efficiency." + max_capacity = 512 + origin_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 3) + power_usage = 100 // High-capacity but uses lots of power, shortening battery life. Best used with APC link. + icon_state = "hdd_super" + hardware_size = 2 + +/obj/item/weapon/computer_hardware/hard_drive/cluster + name = "cluster hard drive" + desc = "A large storage cluster consisting of multiple hard drives for usage in high capacity storage systems. Has capacity of 2048 GQ." + power_usage = 500 + origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4) + max_capacity = 2048 + icon_state = "hdd_cluster" + hardware_size = 3 + +// For tablets, etc. - highly power efficient. +/obj/item/weapon/computer_hardware/hard_drive/small + name = "small hard drive" + desc = "A small highly efficient solid state drive for portable devices." + power_usage = 10 + origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + max_capacity = 64 + icon_state = "hdd_small" + hardware_size = 1 + +/obj/item/weapon/computer_hardware/hard_drive/micro + name = "micro hard drive" + desc = "A small micro hard drive for portable devices." + power_usage = 2 + origin_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1) + max_capacity = 32 + icon_state = "hdd_micro" + hardware_size = 1 + +/obj/item/weapon/computer_hardware/hard_drive/diagnostics(var/mob/user) + ..() + // 999 is a byond limit that is in place. It's unlikely someone will reach that many files anyway, since you would sooner run out of space. + to_chat(user, "NT-NFS File Table Status: [stored_files.len]/999") + to_chat(user, "Storage capacity: [used_capacity]/[max_capacity]GQ") + +// Use this proc to add file to the drive. Returns 1 on success and 0 on failure. Contains necessary sanity checks. +/obj/item/weapon/computer_hardware/hard_drive/proc/store_file(var/datum/computer_file/F) + if(!F || !istype(F)) + return 0 + + if(!can_store_file(F.size)) + return 0 + + if(!check_functionality()) + return 0 + + if(!stored_files) + return 0 + + // This file is already stored. Don't store it again. + if(F in stored_files) + return 0 + + F.holder = src + stored_files.Add(F) + recalculate_size() + return 1 + +// Use this proc to add file to the drive. Returns 1 on success and 0 on failure. Contains necessary sanity checks. +/obj/item/weapon/computer_hardware/hard_drive/proc/install_default_programs() + store_file(new/datum/computer_file/program/computerconfig(src)) // Computer configuration utility, allows hardware control and displays more info than status bar + //store_file(new/datum/computer_file/program/ntnetdownload(src)) // NTNet Downloader Utility, allows users to download more software from NTNet repository + //store_file(new/datum/computer_file/program/filemanager(src)) // File manager, allows text editor functions and basic file manipulation. + + +// Use this proc to remove file from the drive. Returns 1 on success and 0 on failure. Contains necessary sanity checks. +/obj/item/weapon/computer_hardware/hard_drive/proc/remove_file(var/datum/computer_file/F) + if(!F || !istype(F)) + return 0 + + if(!stored_files) + return 0 + + if(!check_functionality()) + return 0 + + if(F in stored_files) + stored_files -= F + recalculate_size() + return 1 + else + return 0 + +// Loops through all stored files and recalculates used_capacity of this drive +/obj/item/weapon/computer_hardware/hard_drive/proc/recalculate_size() + var/total_size = 0 + for(var/datum/computer_file/F in stored_files) + total_size += F.size + + used_capacity = total_size + +// Checks whether file can be stored on the hard drive. +/obj/item/weapon/computer_hardware/hard_drive/proc/can_store_file(var/size = 1) + // In the unlikely event someone manages to create that many files. + // BYOND is acting weird with numbers above 999 in loops (infinite loop prevention) + if(stored_files.len >= 999) + return 0 + if(used_capacity + size > max_capacity) + return 0 + else + return 1 + +// Checks whether we can store the file. We can only store unique files, so this checks whether we wouldn't get a duplicity by adding a file. +/obj/item/weapon/computer_hardware/hard_drive/proc/try_store_file(var/datum/computer_file/F) + if(!F || !istype(F)) + return 0 + var/name = F.filename + "." + F.filetype + for(var/datum/computer_file/file in stored_files) + if((file.filename + "." + file.filetype) == name) + return 0 + return can_store_file(F.size) + + + +// Tries to find the file by filename. Returns null on failure +/obj/item/weapon/computer_hardware/hard_drive/proc/find_file_by_name(var/filename) + if(!check_functionality()) + return null + + if(!filename) + return null + + if(!stored_files) + return null + + for(var/datum/computer_file/F in stored_files) + if(F.filename == filename) + return F + return null + +/obj/item/weapon/computer_hardware/hard_drive/Destroy() + if(holder2 && (holder2.hard_drive == src)) + holder2.hard_drive = null + stored_files = null + return ..() + +/obj/item/weapon/computer_hardware/hard_drive/New() + install_default_programs() + ..() \ No newline at end of file diff --git a/code/modules/modular_computers/hardware/nano_printer.dm b/code/modules/modular_computers/hardware/nano_printer.dm new file mode 100644 index 00000000..0eb2a7b0 --- /dev/null +++ b/code/modules/modular_computers/hardware/nano_printer.dm @@ -0,0 +1,71 @@ +/obj/item/weapon/computer_hardware/nano_printer + name = "nano printer" + desc = "Small integrated printer with paper recycling module." + power_usage = 50 + origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + critical = 0 + icon_state = "printer" + hardware_size = 1 + var/stored_paper = 5 + var/max_paper = 10 + +/obj/item/weapon/computer_hardware/nano_printer/diagnostics(var/mob/user) + ..() + to_chat(user, "Paper buffer level: [stored_paper]/[max_paper]") + +/obj/item/weapon/computer_hardware/nano_printer/proc/print_text(var/text_to_print, var/paper_title = null) + if(!stored_paper) + return 0 + if(!enabled) + return 0 + if(!check_functionality()) + return 0 + + // Damaged printer causes the resulting paper to be somewhat harder to read. + if(damage > damage_malfunction) + text_to_print = stars(text_to_print, 100-malfunction_probability) + new/obj/item/weapon/paper(get_turf(holder2),text_to_print, paper_title) + + stored_paper-- + return 1 + +/obj/item/weapon/computer_hardware/nano_printer/attackby(obj/item/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/paper)) + if(stored_paper >= max_paper) + to_chat(user, "You try to add \the [W] into \the [src], but its paper bin is full.") + return + + to_chat(user, "You insert \the [W] into [src].") + qdel(W) + stored_paper++ + else if(istype(W, /obj/item/weapon/paper_bundle)) + var/obj/item/weapon/paper_bundle/B = W + var/num_of_pages_added = 0 + if(stored_paper >= max_paper) + to_chat(user, "You try to add \the [W] into \the [src], but its paper bin is full.") + return + for(var/obj/item/weapon/bundleitem in B) //loop through items in bundle + if(istype(bundleitem, /obj/item/weapon/paper)) //if item is paper (and not photo), add into the bin + B.pages.Remove(bundleitem) + qdel(bundleitem) + num_of_pages_added++ + stored_paper++ + if(stored_paper >= max_paper) //check if the printer is full yet + to_chat(user, "The printer has been filled to full capacity.") + break + if(B.pages.len == 0) //if all its papers have been put into the printer, delete bundle + qdel(W) + else if(B.pages.len == 1) //if only one item left, extract item and delete the one-item bundle + user.drop_from_inventory(B) + user.put_in_hands(B[1]) + qdel(B) + else //if at least two items remain, just update the bundle icon + B.update_icon() + to_chat(user, "You add [num_of_pages_added] papers from \the [W] into \the [src].") + return + +/obj/item/weapon/computer_hardware/nano_printer/Destroy() + if(holder2 && (holder2.nano_printer == src)) + holder2.nano_printer = null + holder2 = null + return ..() \ No newline at end of file diff --git a/code/modules/modular_computers/hardware/network_card.dm b/code/modules/modular_computers/hardware/network_card.dm new file mode 100644 index 00000000..b3fd5dfb --- /dev/null +++ b/code/modules/modular_computers/hardware/network_card.dm @@ -0,0 +1,95 @@ +var/global/ntnet_card_uid = 1 + +/obj/item/weapon/computer_hardware/network_card/ + name = "basic NTNet network card" + desc = "A basic network card for usage with standard NTNet frequencies." + power_usage = 50 + origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 1) + critical = 0 + icon_state = "netcard_basic" + hardware_size = 1 + var/identification_id = null // Identification ID. Technically MAC address of this device. Can't be changed by user. + var/identification_string = "" // Identification string, technically nickname seen in the network. Can be set by user. + var/long_range = 0 + var/ethernet = 0 // Hard-wired, therefore always on, ignores NTNet wireless checks. + malfunction_probability = 1 + +/obj/item/weapon/computer_hardware/network_card/diagnostics(var/mob/user) + ..() + to_chat(user, "NIX Unique ID: [identification_id]") + to_chat(user, "NIX User Tag: [identification_string]") + to_chat(user, "Supported protocols:") + to_chat(user, "511.m SFS (Subspace) - Standard Frequency Spread") + if(long_range) + to_chat(user, "511.n WFS/HB (Subspace) - Wide Frequency Spread/High Bandiwdth") + if(ethernet) + to_chat(user, "OpenEth (Physical Connection) - Physical network connection port") + +/obj/item/weapon/computer_hardware/network_card/New(var/l) + ..(l) + identification_id = ntnet_card_uid + ntnet_card_uid++ + +/obj/item/weapon/computer_hardware/network_card/advanced + name = "advanced NTNet network card" + desc = "An advanced network card for usage with standard NTNet frequencies. It's transmitter is strong enough to connect even when far away." + long_range = 1 + origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 2) + power_usage = 100 // Better range but higher power usage. + icon_state = "netcard_advanced" + hardware_size = 1 + +/obj/item/weapon/computer_hardware/network_card/wired + name = "wired NTNet network card" + desc = "An advanced network card for usage with standard NTNet frequencies. This one also supports wired connection." + ethernet = 1 + origin_tech = list(TECH_DATA = 5, TECH_ENGINEERING = 3) + power_usage = 100 // Better range but higher power usage. + icon_state = "netcard_ethernet" + hardware_size = 3 + +/obj/item/weapon/computer_hardware/network_card/Destroy() + if(holder2 && (holder2.network_card == src)) + holder2.network_card = null + holder2 = null + return ..() + +// Returns a string identifier of this network card +/obj/item/weapon/computer_hardware/network_card/proc/get_network_tag() + return "[identification_string] (NID [identification_id])" + +/obj/item/weapon/computer_hardware/network_card/proc/is_banned() + return ntnet_global.check_banned(identification_id) + +// 0 - No signal, 1 - Low signal, 2 - High signal. 3 - Wired Connection +/obj/item/weapon/computer_hardware/network_card/proc/get_signal(var/specific_action = 0) + if(!holder2) // Hardware is not installed in anything. No signal. How did this even get called? + return 0 + + if(!enabled) + return 0 + + if(!check_functionality() || !ntnet_global || is_banned()) + return 0 + + if(ethernet) // Computer is connected via wired connection. + return 3 + + if(!ntnet_global.check_function(specific_action)) // NTNet is down and we are not connected via wired connection. No signal. + return 0 + + if(holder2) + var/turf/T = get_turf(holder2) + if(!istype(T)) //no reception in nullspace + return 0 + if(T.z in GLOB.using_map.station_levels) + // Computer is on station. Low/High signal depending on what type of network card you have + if(long_range) + return 2 + else + return 1 + if(T.z in GLOB.using_map.contact_levels) //not on station, but close enough for radio signal to travel + if(long_range) // Computer is not on station, but it has upgraded network card. Low signal. + return 1 + + return 0 // Computer is not on station and does not have upgraded network card. No signal. diff --git a/code/modules/modular_computers/hardware/portable_hard_drive.dm b/code/modules/modular_computers/hardware/portable_hard_drive.dm new file mode 100644 index 00000000..9a0feb36 --- /dev/null +++ b/code/modules/modular_computers/hardware/portable_hard_drive.dm @@ -0,0 +1,37 @@ +// These are basically USB data sticks and may be used to transfer files between devices +/obj/item/weapon/computer_hardware/hard_drive/portable/ + name = "basic data crystal" + desc = "Small crystal with imprinted photonic circuits that can be used to store data. Its capacity is 16 GQ." + power_usage = 10 + icon_state = "flashdrive_basic" + hardware_size = 1 + max_capacity = 16 + origin_tech = list(TECH_DATA = 1) + +/obj/item/weapon/computer_hardware/hard_drive/portable/advanced + name = "advanced data crystal" + desc = "Small crystal with imprinted high-density photonic circuits that can be used to store data. Its capacity is 64 GQ." + power_usage = 20 + icon_state = "flashdrive_advanced" + hardware_size = 1 + max_capacity = 64 + origin_tech = list(TECH_DATA = 2) + +/obj/item/weapon/computer_hardware/hard_drive/portable/super + name = "super data crystal" + desc = "Small crystal with imprinted ultra-density photonic circuits that can be used to store data. Its capacity is 256 GQ." + power_usage = 40 + icon_state = "flashdrive_super" + hardware_size = 1 + max_capacity = 256 + origin_tech = list(TECH_DATA = 4) + +/obj/item/weapon/computer_hardware/hard_drive/portable/New() + ..() + stored_files = list() + recalculate_size() + +/obj/item/weapon/computer_hardware/hard_drive/portable/Destroy() + if(holder2 && (holder2.portable_drive == src)) + holder2.portable_drive = null + return ..() \ No newline at end of file diff --git a/code/modules/modular_computers/hardware/processor_unit.dm b/code/modules/modular_computers/hardware/processor_unit.dm new file mode 100644 index 00000000..9ed7ab40 --- /dev/null +++ b/code/modules/modular_computers/hardware/processor_unit.dm @@ -0,0 +1,46 @@ +// CPU that allows the computer to run programs. +// Better CPUs are obtainable via research and can run more programs on background. + +/obj/item/weapon/computer_hardware/processor_unit + name = "standard processor" + desc = "A standard CPU used in most computers. It can run up to three programs simultaneously." + icon_state = "cpu_normal" + hardware_size = 2 + power_usage = 50 + critical = 1 + malfunction_probability = 1 + origin_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 2) + + var/max_idle_programs = 2 // 2 idle, + 1 active = 3 as said in description. + +/obj/item/weapon/computer_hardware/processor_unit/small + name = "standard microprocessor" + desc = "A standard miniaturised CPU used in portable devices. It can run up to two programs simultaneously." + icon_state = "cpu_small" + hardware_size = 1 + power_usage = 25 + max_idle_programs = 1 + origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + +/obj/item/weapon/computer_hardware/processor_unit/photonic + name = "photonic processor" + desc = "An advanced experimental CPU that uses photonic core instead of regular circuitry. It can run up to five programs simultaneously, but uses a lot of power." + icon_state = "cpu_normal_photonic" + hardware_size = 2 + power_usage = 250 + max_idle_programs = 4 + origin_tech = list(TECH_DATA = 5, TECH_ENGINEERING = 4) + +/obj/item/weapon/computer_hardware/processor_unit/photonic/small + name = "photonic microprocessor" + desc = "An advanced miniaturised CPU for use in portable devices. It uses photonic core instead of regular circuitry. It can run up to three programs simultaneously." + icon_state = "cpu_small_photonic" + hardware_size = 1 + power_usage = 75 + max_idle_programs = 2 + origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 3) + +/obj/item/weapon/computer_hardware/processor_unit/Destroy() + if(holder2 && (holder2.processor_unit == src)) + holder2.processor_unit = null + return ..() \ No newline at end of file diff --git a/code/modules/modular_computers/hardware/tesla_link.dm b/code/modules/modular_computers/hardware/tesla_link.dm new file mode 100644 index 00000000..b23bb963 --- /dev/null +++ b/code/modules/modular_computers/hardware/tesla_link.dm @@ -0,0 +1,14 @@ +/obj/item/weapon/computer_hardware/tesla_link + name = "tesla link" + desc = "An advanced tesla link that wirelessly recharges connected device from nearby area power controller." + critical = 0 + enabled = 1 + icon_state = "teslalink" + hardware_size = 1 + origin_tech = list(TECH_DATA = 2, TECH_POWER = 3, TECH_ENGINEERING = 2) + var/passive_charging_rate = 250 // W + +/obj/item/weapon/computer_hardware/tesla_link/Destroy() + if(holder2 && (holder2.tesla_link == src)) + holder2.tesla_link = null + return ..() \ No newline at end of file diff --git a/code/modules/modular_computers/laptop_vendor.dm b/code/modules/modular_computers/laptop_vendor.dm new file mode 100644 index 00000000..5af33ce0 --- /dev/null +++ b/code/modules/modular_computers/laptop_vendor.dm @@ -0,0 +1,316 @@ +// A vendor machine for modular computer portable devices - Laptops and Tablets + +/obj/machinery/lapvend + name = "computer vendor" + desc = "A vending machine with a built-in microfabricator, capable of dispensing various NT-branded computers." + icon = 'icons/obj/vending.dmi' + icon_state = "robotics" + layer = BELOW_OBJ_LAYER + anchored = 1 + density = 1 + + // The actual laptop/tablet + var/obj/item/modular_computer/laptop/fabricated_laptop = null + var/obj/item/modular_computer/tablet/fabricated_tablet = null + + // Utility vars + var/state = 0 // 0: Select device type, 1: Select loadout, 2: Payment, 3: Thankyou screen + var/devtype = 0 // 0: None(unselected), 1: Laptop, 2: Tablet + var/total_price = 0 // Price of currently vended device. + + // Device loadout + var/dev_cpu = 1 // 1: Default, 2: Upgraded + var/dev_battery = 1 // 1: Default, 2: Upgraded, 3: Advanced + var/dev_disk = 1 // 1: Default, 2: Upgraded, 3: Advanced + var/dev_netcard = 0 // 0: None, 1: Basic, 2: Long-Range + var/dev_tesla = 0 // 0: None, 1: Standard + var/dev_nanoprint = 0 // 0: None, 1: Standard + var/dev_card = 0 // 0: None, 1: Standard + var/dev_aislot = 0 // 0: None, 1: Standard + +// Removes all traces of old order and allows you to begin configuration from scratch. +/obj/machinery/lapvend/proc/reset_order() + state = 0 + devtype = 0 + if(fabricated_laptop) + qdel(fabricated_laptop) + fabricated_laptop = null + if(fabricated_tablet) + qdel(fabricated_tablet) + fabricated_tablet = null + dev_cpu = 1 + dev_battery = 1 + dev_disk = 1 + dev_netcard = 0 + dev_tesla = 0 + dev_nanoprint = 0 + dev_card = 0 + dev_aislot = 0 + +// Recalculates the price and optionally even fabricates the device. +/obj/machinery/lapvend/proc/fabricate_and_recalc_price(var/fabricate = 0) + total_price = 0 + if(devtype == 1) // Laptop, generally cheaper to make it accessible for most station roles + if(fabricate) + fabricated_laptop = new(src) + total_price = 99 + switch(dev_cpu) + if(1) + if(fabricate) + fabricated_laptop.processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(fabricated_laptop) + if(2) + if(fabricate) + fabricated_laptop.processor_unit = new/obj/item/weapon/computer_hardware/processor_unit(fabricated_laptop) + total_price += 299 + switch(dev_battery) + if(1) // Basic(750C) + if(fabricate) + fabricated_laptop.battery_module = new/obj/item/weapon/computer_hardware/battery_module(fabricated_laptop) + if(2) // Upgraded(1100C) + if(fabricate) + fabricated_laptop.battery_module = new/obj/item/weapon/computer_hardware/battery_module/advanced(fabricated_laptop) + total_price += 199 + if(3) // Advanced(1500C) + if(fabricate) + fabricated_laptop.battery_module = new/obj/item/weapon/computer_hardware/battery_module/super(fabricated_laptop) + total_price += 499 + switch(dev_disk) + if(1) // Basic(128GQ) + if(fabricate) + fabricated_laptop.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive(fabricated_laptop) + if(2) // Upgraded(256GQ) + if(fabricate) + fabricated_laptop.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/advanced(fabricated_laptop) + total_price += 99 + if(3) // Advanced(512GQ) + if(fabricate) + fabricated_laptop.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/super(fabricated_laptop) + total_price += 299 + switch(dev_netcard) + if(1) // Basic(Short-Range) + if(fabricate) + fabricated_laptop.network_card = new/obj/item/weapon/computer_hardware/network_card(fabricated_laptop) + total_price += 99 + if(2) // Advanced (Long Range) + if(fabricate) + fabricated_laptop.network_card = new/obj/item/weapon/computer_hardware/network_card/advanced(fabricated_laptop) + total_price += 299 + if(dev_tesla) + total_price += 399 + if(fabricate) + fabricated_laptop.tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(fabricated_laptop) + if(dev_nanoprint) + total_price += 99 + if(fabricate) + fabricated_laptop.nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(fabricated_laptop) + if(dev_card) + total_price += 199 + if(fabricate) + fabricated_laptop.card_slot = new/obj/item/weapon/computer_hardware/card_slot(fabricated_laptop) + if(dev_aislot) + total_price += 499 + if(fabricate) + fabricated_laptop.ai_slot = new/obj/item/weapon/computer_hardware/ai_slot(fabricated_laptop) + + return total_price + else if(devtype == 2) // Tablet, more expensive, not everyone could probably afford this. + if(fabricate) + fabricated_tablet = new(src) + fabricated_tablet.processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(fabricated_tablet) + total_price = 199 + switch(dev_battery) + if(1) // Basic(300C) + if(fabricate) + fabricated_tablet.battery_module = new/obj/item/weapon/computer_hardware/battery_module/nano(fabricated_tablet) + if(2) // Upgraded(500C) + if(fabricate) + fabricated_tablet.battery_module = new/obj/item/weapon/computer_hardware/battery_module/micro(fabricated_tablet) + total_price += 199 + if(3) // Advanced(750C) + if(fabricate) + fabricated_tablet.battery_module = new/obj/item/weapon/computer_hardware/battery_module(fabricated_tablet) + total_price += 499 + switch(dev_disk) + if(1) // Basic(32GQ) + if(fabricate) + fabricated_tablet.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/micro(fabricated_tablet) + if(2) // Upgraded(64GQ) + if(fabricate) + fabricated_tablet.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/small(fabricated_tablet) + total_price += 99 + if(3) // Advanced(128GQ) + if(fabricate) + fabricated_tablet.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive(fabricated_tablet) + total_price += 299 + switch(dev_netcard) + if(1) // Basic(Short-Range) + if(fabricate) + fabricated_tablet.network_card = new/obj/item/weapon/computer_hardware/network_card(fabricated_tablet) + total_price += 99 + if(2) // Advanced (Long Range) + if(fabricate) + fabricated_tablet.network_card = new/obj/item/weapon/computer_hardware/network_card/advanced(fabricated_tablet) + total_price += 299 + if(dev_nanoprint) + total_price += 99 + if(fabricate) + fabricated_tablet.nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(fabricated_tablet) + if(dev_card) + total_price += 199 + if(fabricate) + fabricated_tablet.card_slot = new/obj/item/weapon/computer_hardware/card_slot(fabricated_tablet) + if(dev_tesla) + total_price += 399 + if(fabricate) + fabricated_tablet.tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(fabricated_tablet) + if(dev_aislot) + total_price += 499 + if(fabricate) + fabricated_tablet.ai_slot = new/obj/item/weapon/computer_hardware/ai_slot(fabricated_tablet) + return total_price + return 0 + + + + + +/obj/machinery/lapvend/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["pick_device"]) + if(state) // We've already picked a device type + return 0 + devtype = text2num(href_list["pick_device"]) + state = 1 + fabricate_and_recalc_price(0) + return 1 + if(href_list["clean_order"]) + reset_order() + return 1 + if((state != 1) && devtype) // Following IFs should only be usable when in the Select Loadout mode + return 0 + if(href_list["confirm_order"]) + state = 2 // Wait for ID swipe for payment processing + fabricate_and_recalc_price(0) + return 1 + if(href_list["hw_cpu"]) + dev_cpu = text2num(href_list["hw_cpu"]) + fabricate_and_recalc_price(0) + return 1 + if(href_list["hw_battery"]) + dev_battery = text2num(href_list["hw_battery"]) + fabricate_and_recalc_price(0) + return 1 + if(href_list["hw_disk"]) + dev_disk = text2num(href_list["hw_disk"]) + fabricate_and_recalc_price(0) + return 1 + if(href_list["hw_netcard"]) + dev_netcard = text2num(href_list["hw_netcard"]) + fabricate_and_recalc_price(0) + return 1 + if(href_list["hw_tesla"]) + dev_tesla = text2num(href_list["hw_tesla"]) + fabricate_and_recalc_price(0) + return 1 + if(href_list["hw_nanoprint"]) + dev_nanoprint = text2num(href_list["hw_nanoprint"]) + fabricate_and_recalc_price(0) + return 1 + if(href_list["hw_card"]) + dev_card = text2num(href_list["hw_card"]) + fabricate_and_recalc_price(0) + return 1 + if(href_list["hw_aislot"]) + dev_aislot = text2num(href_list["hw_aislot"]) + fabricate_and_recalc_price(0) + return 1 + return 0 + +/obj/machinery/lapvend/attack_hand(var/mob/user) + ui_interact(user) + +/obj/machinery/lapvend/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(stat & (BROKEN | NOPOWER | MAINT)) + if(ui) + ui.close() + return 0 + + var/list/data[0] + data["state"] = state + if(state == 1) + data["devtype"] = devtype + data["hw_battery"] = dev_battery + data["hw_disk"] = dev_disk + data["hw_netcard"] = dev_netcard + data["hw_tesla"] = dev_tesla + data["hw_nanoprint"] = dev_nanoprint + data["hw_card"] = dev_card + data["hw_cpu"] = dev_cpu + data["hw_aislot"] = dev_aislot + if(state == 1 || state == 2) + data["totalprice"] = total_price + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "computer_fabricator.tmpl", "Personal Computer Vendor", 500, 400) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + + +obj/machinery/lapvend/attackby(obj/item/weapon/W as obj, mob/user as mob) + var/obj/item/weapon/card/id/I = W.GetIdCard() + // Awaiting payment state + if(state == 2) + if(process_payment(I,W)) + fabricate_and_recalc_price(1) + if((devtype == 1) && fabricated_laptop) + if(fabricated_laptop.battery_module) + fabricated_laptop.battery_module.charge_to_full() + fabricated_laptop.forceMove(src.loc) + fabricated_laptop.screen_on = 0 + fabricated_laptop.anchored = 0 + fabricated_laptop.update_icon() + fabricated_laptop.update_verbs() + fabricated_laptop = null + else if((devtype == 2) && fabricated_tablet) + if(fabricated_tablet.battery_module) + fabricated_tablet.battery_module.charge_to_full() + fabricated_tablet.forceMove(src.loc) + fabricated_tablet.update_verbs() + fabricated_tablet = null + ping("Enjoy your new product!") + state = 3 + return 1 + return 0 + return ..() + + +// Simplified payment processing, returns 1 on success. +/obj/machinery/lapvend/proc/process_payment(var/obj/item/weapon/card/id/I, var/obj/item/ID_container) + if(I==ID_container || ID_container == null) + visible_message("\The [usr] swipes \the [I] through \the [src].") + else + visible_message("\The [usr] swipes \the [ID_container] through \the [src].") + var/datum/money_account/customer_account = I ? get_account(I.associated_account_number) : null + if (!customer_account || customer_account.suspended) + ping("Connection error. Unable to connect to account.") + return 0 + + if(customer_account.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2) + var/attempt_pin = input("Enter pin code", "Vendor transaction") as num + customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2) + + if(!customer_account) + ping("Unable to access account: incorrect credentials.") + return 0 + + if(total_price > customer_account.money) + ping("Insufficient funds in account.") + return 0 + else + var/datum/transaction/T = new("Computer Manufacturer (via [src.name])", "Purchase of [(devtype == 1) ? "laptop computer" : "tablet microcomputer"].", -total_price, src.name) + customer_account.do_transaction(T) + return 1 \ No newline at end of file diff --git a/code/modules/multiz/_stubs.dm b/code/modules/multiz/_stubs.dm new file mode 100644 index 00000000..896d7b2c --- /dev/null +++ b/code/modules/multiz/_stubs.dm @@ -0,0 +1,16 @@ +/obj/effect/landmark/map_data + name = "Map Data" + desc = "An unknown location." + invisibility = 101 + + var/height = 1 ///< The number of Z-Levels in the map. + var/turf/edge_type ///< What the map edge should be formed with. (null = world.turf) + +// FOR THE LOVE OF GOD USE THESE. DO NOT FUCKING SPAGHETTIFY THIS. +// Use the Has*() functions if you ONLY need to check. +// If you need to do something, use Get*(). +HasAbove(var/z) +HasBelow(var/z) +// These give either the turf or null. +GetAbove(var/atom/atom) +GetBelow(var/atom/atom) diff --git a/code/modules/multiz/basic.dm b/code/modules/multiz/basic.dm new file mode 100644 index 00000000..018e4411 --- /dev/null +++ b/code/modules/multiz/basic.dm @@ -0,0 +1,56 @@ +// If you add a more comprehensive system, just untick this file. +var/list/z_levels = list()// Each bit re... haha just kidding this is a list of bools now + +// If the height is more than 1, we mark all contained levels as connected. +/obj/effect/landmark/map_data/New() + ..() + + for(var/i = (z - height + 1) to (z-1)) + if (z_levels.len = world.maxz || z < 1 || z > z_levels.len) + return 0 + return z_levels[z] + +/proc/HasBelow(var/z) + if(z > world.maxz || z < 2 || (z-1) > z_levels.len) + return 0 + return z_levels[z-1] + +// Thankfully, no bitwise magic is needed here. +/proc/GetAbove(var/atom/atom) + var/turf/turf = get_turf(atom) + if(!turf) + return null + return HasAbove(turf.z) ? get_step(turf, UP) : null + +/proc/GetBelow(var/atom/atom) + var/turf/turf = get_turf(atom) + if(!turf) + return null + return HasBelow(turf.z) ? get_step(turf, DOWN) : null + +/proc/GetConnectedZlevels(z) + . = list(z) + for(var/level = z, HasBelow(level), level--) + . |= level-1 + for(var/level = z, HasAbove(level), level++) + . |= level+1 + +/proc/AreConnectedZLevels(var/zA, var/zB) + return zA == zB || (zB in GetConnectedZlevels(zA)) + +/proc/get_zstep(ref, dir) + if(dir == UP) + . = GetAbove(ref) + else if (dir == DOWN) + . = GetBelow(ref) + else + . = get_step(ref, dir) \ No newline at end of file diff --git a/code/modules/multiz/disabled.dm b/code/modules/multiz/disabled.dm new file mode 100644 index 00000000..d1571af3 --- /dev/null +++ b/code/modules/multiz/disabled.dm @@ -0,0 +1,11 @@ +GLOBAL_VAR_CONST(HIGHEST_CONNECTABLE_ZLEVEL_INDEX, 0) + +proc/HasAbove(var/z) + return 0 +proc/HasBelow(var/z) + return 0 +// These give either the turf or null. +proc/GetAbove(var/turf/turf) + return null +proc/GetBelow(var/turf/turf) + return null \ No newline at end of file diff --git a/code/modules/multiz/movement.dm b/code/modules/multiz/movement.dm new file mode 100644 index 00000000..6bdb4221 --- /dev/null +++ b/code/modules/multiz/movement.dm @@ -0,0 +1,269 @@ +/mob/verb/up() + set name = "Move Upwards" + set category = "IC" + + if(zMove(UP)) + to_chat(src, "You move upwards.") + +/mob/verb/down() + set name = "Move Down" + set category = "IC" + + if(zMove(DOWN)) + to_chat(src, "You move down.") + + +/mob/proc/zMove(direction) + if(eyeobj) + return eyeobj.zMove(direction) + if(!can_ztravel()) + to_chat(src, "You lack means of travel in that direction.") + return + + var/turf/start = loc + if(!istype(start)) + to_chat(src, "You are unable to move from here.") + return 0 + + var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src) + if(!destination) + to_chat(src, "There is nothing of interest in this direction.") + return 0 + + if(!start.CanZPass(src, direction)) + to_chat(src, "\The [start] is in the way.") + return 0 + if(!destination.CanZPass(src, direction)) + to_chat(src, "You bump against \the [destination].") + return 0 + + var/area/area = get_area(src) + if(direction == UP && area.has_gravity() && !can_overcome_gravity()) + to_chat(src, "Gravity stops you from moving upward.") + return 0 + + for(var/atom/A in destination) + if(!A.CanMoveOnto(src, start, 1.5, direction)) + to_chat(src, "\The [A] blocks you.") + return 0 + + if(direction == UP && area.has_gravity() && can_fall(FALSE, destination)) + to_chat(src, "You see nothing to hold on to.") + return 0 + + forceMove(destination) + return 1 + + +/atom/proc/CanMoveOnto(atom/movable/mover, turf/target, height=1.5, direction = 0) + //Purpose: Determines if the object can move through this + //Uses regular limitations plus whatever we think is an exception for the purpose of + //moving up and down z levles + return CanPass(mover, target, height, 0) || (direction == DOWN && (atom_flags & ATOM_FLAG_CLIMBABLE)) + +/mob/proc/can_overcome_gravity() + return FALSE + +/mob/living/carbon/human/can_overcome_gravity() + //First do species check + if(species && species.can_overcome_gravity(src)) + return 1 +/* else + for(var/atom/a in src.loc) + if(a.atom_flags & ATOM_FLAG_CLIMBABLE) + return 1 + + //Last check, list of items that could plausibly be used to climb but aren't climbable themselves + var/list/objects_to_stand_on = list( + /obj/item/weapon/stool, + /obj/structure/bed, + ) + for(var/type in objects_to_stand_on) + if(locate(type) in src.loc) + return 1 + return 0 +*/ +/mob/observer/zMove(direction) + var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src) + if(destination) + forceMove(destination) + else + to_chat(src, "There is nothing of interest in this direction.") + +/mob/observer/eye/zMove(direction) + var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src) + if(destination) + setLoc(destination) + else + to_chat(src, "There is nothing of interest in this direction.") + +/mob/proc/can_ztravel() + return 0 + +/mob/observer/can_ztravel() + return 1 + +/mob/living/carbon/human/can_ztravel() + if(incapacitated()) + return 0 + + if(Allow_Spacemove()) + return 1 + + if(Check_Shoegrip()) //scaling hull with magboots + for(var/turf/simulated/T in trange(1,src)) + if(T.density) + return 1 + +/mob/living/silicon/robot/can_ztravel() + if(incapacitated() || is_dead()) + return 0 + + if(Allow_Spacemove()) //Checks for active jetpack + return 1 + + for(var/turf/simulated/T in trange(1,src)) //Robots get "magboots" + if(T.density) + return 1 + +//FALLING STUFF + +//Holds fall checks that should not be overriden by children +/atom/movable/proc/fall() + if(!isturf(loc)) + return + + var/turf/below = GetBelow(src) + if(!below) + return + + var/turf/T = loc + if(!T.CanZPass(src, DOWN) || !below.CanZPass(src, DOWN)) + return + + // No gravity in space, apparently. + var/area/area = get_area(src) + if(!area.has_gravity()) + return + + if(throwing) + return + + if(can_fall()) + // We spawn here to let the current move operation complete before we start falling. fall() is normally called from + // Entered() which is part of Move(), by spawn()ing we let that complete. But we want to preserve if we were in client movement + // or normal movement so other move behavior can continue. + var/mob/M = src + var/is_client_moving = (ismob(M) && M.client && M.client.moving) + spawn(0) + if(is_client_moving) M.client.moving = 1 + handle_fall(below) + if(is_client_moving) M.client.moving = 0 + +//For children to override +/atom/movable/proc/can_fall(var/anchor_bypass = FALSE, var/turf/location_override = src.loc) + if(!simulated) + return FALSE + + if(anchored && !anchor_bypass) + return FALSE + + //Override will make checks from different location used for prediction + if(location_override) + if(locate(/obj/structure/lattice, location_override) || locate(/obj/structure/catwalk, location_override) || locate(/obj/structure/ladder, location_override)) // !src:resting + return FALSE + + var/obj/structure/grille/floorgrille/F = locate(/obj/structure/grille/floorgrille, location_override) + if(F && !F.destroyed) + return FALSE + + + var/turf/below = GetBelow(location_override) + for(var/atom/A in below) + if(!A.CanPass(src, location_override)) + return FALSE + + + return TRUE + +/obj/can_fall() + return ..(anchor_fall) + + +/obj/effect/can_fall() + return FALSE + +/obj/effect/decal/cleanable/can_fall() + return TRUE + +/obj/effect/decal/mecha_wreckage/can_fall() + return TRUE + +/obj/item/pipe/can_fall() + var/turf/simulated/open/below = loc + below = below.below + + . = ..() + + if(anchored) + return FALSE + + if((locate(/obj/structure/disposalpipe/up) in below) || locate(/obj/machinery/atmospherics/pipe/zpipe/up) in below) + return FALSE + +/mob/living/carbon/human/can_fall() + if(..()) + return species.can_fall(src) + +/atom/movable/proc/handle_fall(var/turf/landing) + forceMove(landing) + if(locate(/obj/structure/stairs) in landing) + return 1 + else + handle_fall_effect(landing) + +/atom/movable/proc/handle_fall_effect(var/turf/landing) + if(istype(landing, /turf/simulated/open)) + visible_message("\The [src] falls from the deck above through \the [landing]!", "You hear a whoosh of displaced air.") + else + //visible_message("\The [src] falls from the deck above and slams into \the [landing]!", "You hear something slam into the deck.") + if(fall_damage()) + for(var/mob/living/M in landing.contents) + visible_message("\The [src] hits \the [M.name]!") + M.Stun(1) + M.take_overall_damage(fall_damage()*2) + + +/atom/movable/proc/fall_damage() + return 0 + +/obj/fall_damage() + if(w_class == ITEM_SIZE_TINY) + return 0 + if(w_class == ITEM_SIZE_NO_CONTAINER) + return 100 + return base_storage_cost(w_class) + +/mob/living/carbon/human/handle_fall_effect(var/turf/landing) + if(species && species.handle_fall_special(src, landing)) + return + + if(..()) + return + + if(!istype(landing, /turf/simulated/open)) + if(prob(STAT_LEVEL(dex)) && !lying) + to_chat(src, "You land softly.") + return + playsound(src.loc, 'sound/effects/gore/fallsmash.ogg', 75, 1)//Splat + var/damage = 20 + apply_damage(rand(0, damage), BRUTE, BP_HEAD) + apply_damage(rand(0, damage), BRUTE, BP_CHEST) + apply_damage(rand(0, damage), BRUTE, BP_L_LEG) + apply_damage(rand(0, damage), BRUTE, BP_R_LEG) + apply_damage(rand(0, damage), BRUTE, BP_L_ARM) + apply_damage(rand(0, damage), BRUTE, BP_R_ARM) + KnockDown() + updatehealth() + GLOB.holes_fallen++ + unlock_achievement(new/datum/achievement/fall())//Splat \ No newline at end of file diff --git a/code/modules/multiz/pipes.dm b/code/modules/multiz/pipes.dm new file mode 100644 index 00000000..1bfb8294 --- /dev/null +++ b/code/modules/multiz/pipes.dm @@ -0,0 +1,247 @@ +//////////////////////////// +// parent class for pipes // +//////////////////////////// +obj/machinery/atmospherics/pipe/zpipe + icon = 'icons/obj/structures.dmi' + icon_state = "up" + + name = "upwards pipe" + desc = "A pipe segment to connect upwards." + + volume = 70 + + dir = SOUTH + initialize_directions = SOUTH + + var/minimum_temperature_difference = 300 + var/thermal_conductivity = 0 //WALL_HEAT_TRANSFER_COEFFICIENT No + + var/maximum_pressure = 70*ONE_ATMOSPHERE + var/fatigue_pressure = 55*ONE_ATMOSPHERE + alert_pressure = 55*ONE_ATMOSPHERE + + + level = 1 + +obj/machinery/atmospherics/pipe/zpipe/New() + ..() + switch(dir) + if(SOUTH) + initialize_directions = SOUTH + if(NORTH) + initialize_directions = NORTH + if(WEST) + initialize_directions = WEST + if(EAST) + initialize_directions = EAST + if(NORTHEAST) + initialize_directions = NORTH + if(NORTHWEST) + initialize_directions = WEST + if(SOUTHEAST) + initialize_directions = EAST + if(SOUTHWEST) + initialize_directions = SOUTH + +/obj/machinery/atmospherics/pipe/zpipe/hide(var/i) + if(istype(loc, /turf/simulated)) + set_invisibility(i ? 101 : 0) + update_icon() + +obj/machinery/atmospherics/pipe/zpipe/Process() + if(!parent) //This should cut back on the overhead calling build_network thousands of times per cycle + ..() + else + . = PROCESS_KILL + +obj/machinery/atmospherics/pipe/zpipe/check_pressure(pressure) + var/datum/gas_mixture/environment = loc.return_air() + + var/pressure_difference = pressure - environment.return_pressure() + + if(pressure_difference > maximum_pressure) + burst() + + else if(pressure_difference > fatigue_pressure) + //TODO: leak to turf, doing pfshhhhh + if(prob(5)) + burst() + + else return 1 + +obj/machinery/atmospherics/pipe/zpipe/proc/burst() + src.visible_message("\The [src] bursts!"); + playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) + var/datum/effect/effect/system/smoke_spread/smoke = new + smoke.set_up(1,0, src.loc, 0) + smoke.start() + qdel(src) // NOT qdel. + +obj/machinery/atmospherics/pipe/zpipe/proc/normalize_dir() + if(dir == (NORTH|SOUTH)) + set_dir(NORTH) + else if(dir == (EAST|WEST)) + set_dir(EAST) + +obj/machinery/atmospherics/pipe/zpipe/Destroy() + if(node1) + node1.disconnect(src) + if(node2) + node2.disconnect(src) + ..() + +obj/machinery/atmospherics/pipe/zpipe/pipeline_expansion() + return list(node1, node2) + +obj/machinery/atmospherics/pipe/zpipe/update_icon() + return + +obj/machinery/atmospherics/pipe/zpipe/disconnect(obj/machinery/atmospherics/reference) + if(reference == node1) + if(istype(node1, /obj/machinery/atmospherics/pipe)) + qdel(parent) + node1 = null + + if(reference == node2) + if(istype(node2, /obj/machinery/atmospherics/pipe)) + qdel(parent) + node2 = null + + return null +///////////////////////// +// the elusive up pipe // +///////////////////////// +obj/machinery/atmospherics/pipe/zpipe/up + icon = 'icons/obj/structures.dmi' + icon_state = "up" + + name = "upwards pipe" + desc = "A pipe segment to connect upwards." + +obj/machinery/atmospherics/pipe/zpipe/up/atmos_init() + ..() + normalize_dir() + var/node1_dir + + for(var/direction in GLOB.cardinal) + if(direction&initialize_directions) + if (!node1_dir) + node1_dir = direction + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node1 = target + break + + var/turf/above = GetAbove(src) + if(above) + for(var/obj/machinery/atmospherics/target in above) + if(target.initialize_directions && istype(target, /obj/machinery/atmospherics/pipe/zpipe/down)) + if (check_connect_types(target,src)) + node2 = target + break + + + var/turf/T = src.loc // hide if turf is not intact + hide(!T.is_plating()) + +/////////////////////// +// and the down pipe // +/////////////////////// + +obj/machinery/atmospherics/pipe/zpipe/down + icon = 'icons/obj/structures.dmi' + icon_state = "down" + + name = "downwards pipe" + desc = "A pipe segment to connect downwards." + +obj/machinery/atmospherics/pipe/zpipe/down/atmos_init() + ..() + normalize_dir() + var/node1_dir + + for(var/direction in GLOB.cardinal) + if(direction&initialize_directions) + if (!node1_dir) + node1_dir = direction + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) + if(target.initialize_directions & get_dir(target,src)) + if (check_connect_types(target,src)) + node1 = target + break + + var/turf/below = GetBelow(src) + if(below) + for(var/obj/machinery/atmospherics/target in below) + if(target.initialize_directions && istype(target, /obj/machinery/atmospherics/pipe/zpipe/up)) + if (check_connect_types(target,src)) + node2 = target + break + + + var/turf/T = src.loc // hide if turf is not intact + hide(!T.is_plating()) + +/////////////////////// +// supply/scrubbers // +/////////////////////// + +obj/machinery/atmospherics/pipe/zpipe/up/scrubbers + icon_state = "up-scrubbers" + name = "upwards scrubbers pipe" + desc = "A scrubbers pipe segment to connect upwards." + connect_types = CONNECT_TYPE_SCRUBBER + icon_connect_type = "-scrubbers" + color = PIPE_COLOR_RED + +obj/machinery/atmospherics/pipe/zpipe/up/supply + icon_state = "up-supply" + name = "upwards supply pipe" + desc = "A supply pipe segment to connect upwards." + connect_types = CONNECT_TYPE_SUPPLY + icon_connect_type = "-supply" + color = PIPE_COLOR_BLUE + +obj/machinery/atmospherics/pipe/zpipe/down/scrubbers + icon_state = "down-scrubbers" + name = "downwards scrubbers pipe" + desc = "A scrubbers pipe segment to connect downwards." + connect_types = CONNECT_TYPE_SCRUBBER + icon_connect_type = "-scrubbers" + color = PIPE_COLOR_RED + +obj/machinery/atmospherics/pipe/zpipe/down/supply + icon_state = "down-supply" + name = "downwards supply pipe" + desc = "A supply pipe segment to connect downwards." + connect_types = CONNECT_TYPE_SUPPLY + icon_connect_type = "-supply" + color = PIPE_COLOR_BLUE + +// Colored misc. pipes +obj/machinery/atmospherics/pipe/zpipe/up/cyan + color = PIPE_COLOR_CYAN +obj/machinery/atmospherics/pipe/zpipe/down/cyan + color = PIPE_COLOR_CYAN + +obj/machinery/atmospherics/pipe/zpipe/up/red + color = PIPE_COLOR_RED +obj/machinery/atmospherics/pipe/zpipe/down/red + color = PIPE_COLOR_RED + +obj/machinery/atmospherics/pipe/zpipe/up/fuel + name = "upwards fuel pipe" + color = PIPE_COLOR_ORANGE + maximum_pressure = 420*ONE_ATMOSPHERE + fatigue_pressure = 350*ONE_ATMOSPHERE + alert_pressure = 350*ONE_ATMOSPHERE + +obj/machinery/atmospherics/pipe/zpipe/down/fuel + name = "downwards fuel pipe" + color = PIPE_COLOR_ORANGE + maximum_pressure = 420*ONE_ATMOSPHERE + fatigue_pressure = 350*ONE_ATMOSPHERE + alert_pressure = 350*ONE_ATMOSPHERE diff --git a/code/modules/multiz/structures.dm b/code/modules/multiz/structures.dm new file mode 100644 index 00000000..8bf55659 --- /dev/null +++ b/code/modules/multiz/structures.dm @@ -0,0 +1,265 @@ +////////////////////////////// +//Contents: Ladders, Stairs.// +////////////////////////////// + +/obj/structure/ladder + name = "ladder" + icon_state = "ladder01" + icon = 'icons/obj/structures.dmi' + density = 0 + opacity = 0 + anchored = 1 + pixel_y = 10 + + + var/allowed_directions = DOWN + var/obj/structure/ladder/target_up + var/obj/structure/ladder/target_down + + var/const/climb_time = 2 SECONDS + var/static/list/climbsounds = list('sound/effects/ladder.ogg','sound/effects/ladder2.ogg','sound/effects/ladder3.ogg','sound/effects/ladder4.ogg') + +/obj/structure/ladder/Initialize() + . = ..() + // the upper will connect to the lower + if(allowed_directions & DOWN) //we only want to do the top one, as it will initialize the ones before it. + for(var/obj/structure/ladder/L in GetBelow(src)) + if(L.allowed_directions & UP) + target_down = L + L.target_up = src + return + update_icon() + +/obj/structure/ladder/Destroy() + if(target_down) + target_down.target_up = null + target_down = null + if(target_up) + target_up.target_down = null + target_up = null + return ..() + +/obj/structure/ladder/attackby(obj/item/C as obj, mob/user as mob) + climb(user, "up") + +/obj/structure/ladder/attack_hand(var/mob/M) + climb(M, "up") + +/obj/structure/ladder/RightClick(mob/user) + climb(user, "down") + +/obj/structure/ladder/attack_ai(var/mob/M) + var/mob/living/silicon/ai/ai = M + if(!istype(ai)) + return + var/mob/observer/eye/AIeye = ai.eyeobj + if(istype(AIeye)) + instant_climb(AIeye) + +/obj/structure/ladder/attack_robot(var/mob/M) + climb(M, "up") + +/obj/structure/ladder/proc/instant_climb(var/mob/M) + var/target_ladder = getTargetLadder(M) + if(target_ladder) + M.forceMove(get_turf(target_ladder)) + +/obj/structure/ladder/proc/climb(var/mob/M, direction) + if(!M.may_climb_ladders(src)) + return + var/obj/structure/ladder/target_ladder + switch(direction) + if("up") + target_ladder = target_up + if("down") + target_ladder = target_down + else + target_ladder = target_up + if(!target_ladder) + to_chat(M, "There is nothing here!Try to climb in other direction") + return + if(!M.Move(get_turf(src))) + to_chat(M, "You fail to reach \the [src].") + return + + var/direction_climb = target_ladder == target_up ? "up" : "down" + + for (var/obj/item/grab/G in M) + G.adjust_position() + + + M.visible_message("\The [M] begins climbing [direction_climb] \the [src]!", + "You begin climbing [direction_climb] \the [src]!", + "You hear the grunting and clanging of a metal ladder being used.") + + target_ladder.audible_message("You hear something coming [direction_climb] \the [src]") + + if(do_after(M, climb_time, src)) + climbLadder(M, target_ladder) + for (var/obj/item/grab/G in M) + G.adjust_position(force = 1) + +/obj/structure/ladder/examine(mob/user) + . = ..() + if(target_up && target_down) + to_chat(user, "There is a way up and down!") + if(target_up) + to_chat(user, "There is a way up!") + if(target_down) + to_chat(user, "There is a way down!") + + +/obj/structure/ladder/attack_ghost(var/mob/M) + instant_climb(M) + +/obj/structure/ladder/proc/getTargetLadder(var/mob/M) + if((!target_up && !target_down) || (target_up && !istype(target_up.loc, /turf) || (target_down && !istype(target_down.loc,/turf)))) + to_chat(M, "\The [src] is incomplete and can't be climbed.") + return + if(target_down && target_up) + var/direction = alert(M,"Do you want to go up or down?", "Ladder", "Up", "Down", "Cancel") + + if(direction == "Cancel") + return + + if(!M.may_climb_ladders(src)) + return + + switch(direction) + if("Up") + return target_up + if("Down") + return target_down + else + return target_down || target_up + +/mob/proc/may_climb_ladders(var/ladder) + if(!Adjacent(ladder)) + to_chat(src, "You need to be next to \the [ladder] to start climbing.") + return FALSE + if(incapacitated()) + to_chat(src, "You are physically unable to climb \the [ladder].") + return FALSE + + var/carry_count = 0 + for(var/obj/item/grab/G in src) + if(!G.ladder_carry()) + to_chat(src, "You can't carry [G.affecting] up \the [ladder].") + return FALSE + else + carry_count++ + if(carry_count > 1) + to_chat(src, "You can't carry more than one person up \the [ladder].") + return FALSE + + return TRUE + +/mob/observer/ghost/may_climb_ladders(var/ladder) + return TRUE + +/obj/structure/ladder/proc/climbLadder(var/mob/M, var/target_ladder) + var/turf/T = get_turf(target_ladder) + for(var/atom/A in T) + if(!A.CanPass(M, M.loc, 1.5, 0)) + to_chat(M, "\The [A] is blocking \the [src].") + return FALSE + playsound(src, pick(climbsounds), 50) + playsound(target_ladder, pick(climbsounds), 50) + return M.Move(T) + +/obj/structure/ladder/CanPass(obj/mover, turf/source, height, airflow) + return airflow || !density + +/obj/structure/ladder/update_icon() + icon_state = "ladder[!!(allowed_directions & UP)][!!(allowed_directions & DOWN)]" + +/obj/structure/ladder/up + allowed_directions = UP + icon_state = "ladder10" + +/obj/structure/ladder/updown + allowed_directions = UP|DOWN + icon_state = "ladder11" + +/obj/structure/stairs + name = "Stairs" + desc = "Stairs leading to another floor." + icon = 'icons/obj/sstairs.dmi' + icon_state = "below" + density = 0 + opacity = 0 + anchored = 1 + plane = ABOVE_TURF_PLANE + layer = RUNE_LAYER + +/obj/structure/stairs/Initialize() + for(var/turf/turf in locs) + var/turf/simulated/open/above = GetAbove(turf) + if(!above) + warning("Stair created without level above: ([loc.x], [loc.y], [loc.z])") + return INITIALIZE_HINT_QDEL + if(!istype(above)) + above.ChangeTurf(/turf/simulated/open) + . = ..() + +/obj/structure/stairs/Uncross(atom/movable/A) + if(A.dir == dir && upperStep(A.loc)) + // This is hackish but whatever. + var/turf/target = get_step(GetAbove(A), dir) + var/turf/source = A.loc + var/turf/above = GetAbove(A) + if(above.CanZPass(source, UP) && target.Enter(A, source)) + A.forceMove(target) + if(isliving(A)) + var/mob/living/L = A + if(L.pulling) + L.pulling.forceMove(source) + else + to_chat(A, "Something blocks the path.") + return 0 + return 1 + +/obj/structure/stairs/proc/upperStep(var/turf/T) + return (T == loc) + +/obj/structure/stairs/CanPass(obj/mover, turf/source, height, airflow) + return airflow || !density + +// type paths to make mapping easier. +/obj/structure/stairs/north + dir = NORTH + +/obj/structure/stairs/south + dir = SOUTH + +/obj/structure/stairs/east + dir = EAST + +/obj/structure/stairs/west + dir = WEST + +//2-Tiled stairs +/obj/structure/stairs/zlong + name = "Stairs" + desc = "Not too useful if the gravity goes out." + icon = 'icons/obj/stairs.dmi' + +/obj/structure/stairs/zlong/north + dir = NORTH + bound_height = 64 + bound_y = -32 + pixel_y = -32 + +/obj/structure/stairs/zlong/south + dir = SOUTH + bound_height = 64 + +/obj/structure/stairs/zlong/east + dir = EAST + bound_width = 64 + bound_x = -32 + pixel_x = -32 + +/obj/structure/stairs/zlong/west + dir = WEST + bound_width = 64 diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf.dm new file mode 100644 index 00000000..16e28ee9 --- /dev/null +++ b/code/modules/multiz/turf.dm @@ -0,0 +1,235 @@ +/turf/proc/CanZPass(atom/A, direction) + if(z == A.z) //moving FROM this turf + return direction == UP //can't go below + else + if(direction == UP) //on a turf below, trying to enter + return 0 + if(direction == DOWN) //on a turf above, trying to enter + return !density + +/turf/simulated/open/CanZPass(atom/A, direction) + if(locate(/obj/structure/catwalk, src)) + if(z == A.z) + if(direction == DOWN) + return 0 + else if(direction == UP) + return 0 + return 1 + +/turf/space/CanZPass(atom/A, direction) + if(locate(/obj/structure/catwalk, src)) + if(z == A.z) + if(direction == DOWN) + return 0 + else if(direction == UP) + return 0 + return 1 + +/turf/simulated/open + name = "open space" + icon = 'icons/turf/space.dmi' + icon_state = "" + plane = OPENSPACE_PLANE + density = 0 + pathweight = 100000 //Seriously, don't try and path over this one numbnuts + + var/turf/below + +/turf/simulated/open/post_change() + ..() + update() + +/turf/simulated/open/Initialize() + . = ..() + update() + + +/turf/simulated/open/proc/update() + plane = OPENSPACE_PLANE //+ (src.z * PLANE_DIFFERENCE) + below = GetBelow(src) + GLOB.turf_changed_event.register(below, src,/turf/simulated/open/proc/turf_change) + GLOB.exited_event.register(below, src, /turf/simulated/open/proc/handle_move) + GLOB.entered_event.register(below, src, /turf/simulated/open/proc/handle_move) + levelupdate() + for(var/atom/movable/A in src) + A.fall() + SSopen_space.add_turf(src, 1) + update_icon() + + +/turf/simulated/open/update_dirt() + return 0 + +/turf/simulated/open/Entered(var/atom/movable/mover) + ..() + mover.fall() + +// Called when thrown object lands on this turf. +/turf/simulated/open/hitby(var/atom/movable/AM, var/speed) + . = ..() + AM.fall() + + +// override to make sure nothing is hidden +/turf/simulated/open/levelupdate() + for(var/obj/O in src) + O.hide(0) + + + +/turf/simulated/open/examine(mob/user, distance, infix, suffix) + if(..(user, 2)) + var/depth = 1 + for(var/T = GetBelow(src); isopenspace(T); T = GetBelow(T)) + depth += 1 + to_chat(user, "It is about [depth] level\s deep.") + + + +/** +* Update icon and overlays of open space to be that of the turf below, plus any visible objects on that turf. +*/ +/turf/simulated/open/update_icon() + overlays.Cut() + underlays.Cut() + var/turf/below = GetBelow(src) + if(below) + var/below_is_open = isopenspace(below) + if(below_is_open) + underlays = below.underlays + overlays += below.overlays + + else + var/image/bottom_turf = image(icon = below.icon, icon_state = below.icon_state, dir=below.dir, layer=below.layer) + bottom_turf.plane = UNDER_OPENSPACE_PLANE//below.plane + src.plane + bottom_turf.color = below.color + bottom_turf.overlays += below.overlays + underlays += bottom_turf + for(var/image/I in below.overlays) + var/image/temp = I + temp.plane = UNDER_OPENSPACE_PLANE//I.plane + src.plane + temp.color = I.color + overlays += temp + + + // get objects (not mobs, they are handled by /obj/zshadow) + var/list/o_img = list() + for(var/obj/O in below) + if(O.invisibility) continue // Ignore objects that have any form of invisibility + if(O.loc != below) continue // Ignore multi-turf objects not directly below + var/image/temp2 = image(O, dir = O.dir, layer = O.layer) + temp2.overlays += O.overlays + temp2.underlays += O.underlays + temp2.plane = UNDER_OPENSPACE_PLANE//O.plane + src.plane + temp2.color = O.color + // TODO Is pixelx/y needed? + o_img += temp2 + + var/overlays_pre = overlays.len + overlays += o_img + + var/overlays_post = overlays.len + if(overlays_post != (overlays_pre + o_img.len)) //Here we go! + //log_world("Corrupted openspace turf at [x],[y],[z] being replaced. Pre: [overlays_pre], Post: [overlays_post]") + new /turf/simulated/open(src) + return //Let's get out of here. + + //TODO : Add overlays if people fall down holes + + if(!below_is_open) + overlays += GLOB.over_OS_darkness + + return 0 + return PROCESS_KILL + + +/turf/simulated/open/attackby(obj/item/C as obj, mob/user as mob) + if (istype(C, /obj/item/stack/rods)) + var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) + if(L) + return L.attackby(C, user) + var/obj/item/stack/rods/R = C + if (R.use(1)) + to_chat(user, "You lay down the support lattice.") + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + new /obj/structure/lattice(locate(src.x, src.y, src.z)) + //Update turfs + SSopen_space.add_turf(src, 1) + return + + if (istype(C, /obj/item/stack/tile)) + var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) + if(L) + var/obj/item/stack/tile/floor/S = C + if (S.get_amount() < 1) + return + qdel(L) + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + S.use(1) + ChangeTurf(/turf/simulated/floor/airless) + return + else + to_chat(user, "The plating is going to need some support.") + + //To lay cable. + if(isCoil(C)) + var/obj/item/stack/cable_coil/coil = C + coil.turf_place(src, user) + return + return + +//Climbing down open spaces. +/turf/simulated/open/attack_hand(mob/living/carbon/human/user as mob) + var/turf/below = GetBelow(src)//Get the turf below them. + if(!below) + return + if(user.can_fall())//See if they can go down it. + user.visible_message("\The [user] begins to climb down.") + playsound(user.loc, 'sound/effects/climb.ogg', 50, 1) + if(do_after(user, 15)) + if(user.statscheck(user.STAT_LEVEL(dex) / 2 + 3) >= SUCCESS)//Dex check. + user.forceMove(below) + else + user.forceMove(src) + + +//Most things use is_plating to test if there is a cover tile on top (like regular floors) +/turf/simulated/open/is_plating() + return 1 + +/turf/simulated/open/proc/handle_move(var/atom/current_loc, var/atom/movable/am, var/atom/changed_loc) + //First handle objs and such + if(GLOB.open_space_initialised && !am.invisibility && isobj(am)) + //Update icons + SSopen_space.add_turf(src, 1) + //Check for mobs and create/destroy their shadows + if(isliving(am)) + var/mob/living/M = am + M.check_shadow() + +/turf/simulated/open/proc/clean_up() + //Unregister + GLOB.turf_changed_event.unregister(below, src,/turf/simulated/open/proc/turf_change) + GLOB.exited_event.unregister(below, src, /turf/simulated/open/proc/handle_move) + GLOB.entered_event.unregister(below, src, /turf/simulated/open/proc/handle_move) + //Take care of shadow + for(var/mob/zshadow/M in src) + qdel(M) + +//When turf changes, a bunch of things can take place +/turf/simulated/open/proc/turf_change(var/turf/affected) + if(GLOB.open_space_initialised) + if(!isopenspace(affected))//If affected is openspace it will add itself + SSopen_space.add_turf(src, 1) + + +//The two situations which require unregistering + +/turf/simulated/open/ChangeTurf(var/turf/N, var/tell_universe=1, var/force_lighting_update = 0) + //We do not want to change any of the behaviour, just make sure this goes away + src.clean_up() + . = ..() + +/turf/simulated/open/Destroy() + src.clean_up() + . = ..() \ No newline at end of file diff --git a/code/modules/multiz/zshadow.dm b/code/modules/multiz/zshadow.dm new file mode 100644 index 00000000..8766f097 --- /dev/null +++ b/code/modules/multiz/zshadow.dm @@ -0,0 +1,110 @@ +/mob // TODO: rewrite as obj. If more efficient + var/mob/zshadow/shadow + +/mob/zshadow + plane = OVER_OPENSPACE_PLANE + name = "shadow" + desc = "Z-level shadow" + status_flags = GODMODE + anchored = 1 + unacidable = 1 + density = 0 + opacity = 0 // Don't trigger lighting recalcs gah! TODO - consider multi-z lighting. + var/mob/owner = null // What we are a shadow of. + +/mob/zshadow/can_fall() + return FALSE + +/mob/zshadow/New(var/mob/L) + if(!istype(L)) + qdel(src) + return + ..() // I'm cautious about this, but its the right thing to do. + owner = L + sync_icon(L) + GLOB.dir_set_event.register(L, src, /mob/zshadow/proc/update_dir) + GLOB.invisibility_set_event.register(L, src, /mob/zshadow/proc/update_invisibility) + + +/mob/Destroy() + if(shadow) + qdel(shadow) + shadow = null + . = ..() + +/mob/zshadow/Destroy() + GLOB.dir_set_event.unregister(owner, src, /mob/zshadow/proc/update_dir) + GLOB.invisibility_set_event.unregister(owner, src, /mob/zshadow/proc/update_invisibility) + . = ..() + +/mob/zshadow/examine(mob/user, distance, infix, suffix) + return owner.examine(user, distance, infix, suffix) + +// Relay some stuff they hear +/mob/zshadow/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) + if(speaker && speaker.z != src.z) + return // Only relay speech on our actual z, otherwise we might relay sounds that were themselves relayed up! + if(isliving(owner)) + verb += " from above" + message = "[message]" + return owner.hear_say(message, verb, language, alt_name, italics, speaker, speech_sound, sound_vol) + +/mob/zshadow/proc/sync_icon(var/mob/M) + var/lay = src.layer + var/pln = src.plane + appearance = M + color = "#848484" + dir = M.dir + src.layer = lay + src.plane = pln + if(shadow) + shadow.sync_icon(src) + +/mob/living/proc/check_shadow() + var/mob/M = src + if(isturf(M.loc)) + for(var/turf/simulated/open/OS = GetAbove(src); OS && istype(OS); OS = GetAbove(OS)) + //Check above + if(!M.shadow) + M.shadow = new /mob/zshadow(M) + M.shadow.forceMove(OS) + M = M.shadow + + // Clean up mob shadow if it has one + if(M.shadow) + qdel(M.shadow) + M.shadow = null + var/client/C = M.client + if(C && C.eye == shadow) + M.reset_view(0) + +// +// Handle cases where the owner mob might have changed its icon or overlays. +// + +/mob/living/update_icons() + . = ..() + if(shadow) + shadow.sync_icon(src) + +// WARNING - the true carbon/human/update_icons does not call ..(), therefore we must sideways override this. +// But be careful, we don't want to screw with that proc. So lets be cautious about what we do here. +/mob/living/carbon/human/update_icons() + . = ..() + if(shadow) + shadow.sync_icon(src) + +//Copy direction +/mob/zshadow/proc/update_dir() + set_dir(owner.dir) + + +//Change name of shadow if it's updated too (generally moving will sync but static updates are handy) +/mob/fully_replace_character_name(var/new_name, var/in_depth = TRUE) + . = ..() + if(shadow) + shadow.fully_replace_character_name(new_name) + + +/mob/zshadow/proc/update_invisibility() + set_invisibility(owner.invisibility) \ No newline at end of file diff --git a/code/modules/nano/interaction/admin.dm b/code/modules/nano/interaction/admin.dm new file mode 100644 index 00000000..ce16f94c --- /dev/null +++ b/code/modules/nano/interaction/admin.dm @@ -0,0 +1,7 @@ +/* + This state checks that the user is an admin, end of story +*/ +GLOBAL_DATUM_INIT(admin_state, /datum/topic_state/admin_state, new) + +/datum/topic_state/admin_state/can_use_topic(var/src_object, var/mob/user) + return check_rights(R_ADMIN, 0, user) ? STATUS_INTERACTIVE : STATUS_CLOSE diff --git a/code/modules/nano/interaction/base.dm b/code/modules/nano/interaction/base.dm new file mode 100644 index 00000000..691e9699 --- /dev/null +++ b/code/modules/nano/interaction/base.dm @@ -0,0 +1,37 @@ +/datum/proc/nano_host() + return src + +/datum/proc/nano_container() + return src + +/datum/proc/CanUseTopic(var/mob/user, var/datum/topic_state/state = GLOB.default_state) + var/datum/src_object = nano_host() + return state.can_use_topic(src_object, user) + +/datum/topic_state/proc/href_list(var/mob/user) + return list() + +/datum/topic_state/proc/can_use_topic(var/src_object, var/mob/user) + return STATUS_CLOSE + +/mob/proc/shared_nano_interaction() + if (src.stat || !client) + return STATUS_CLOSE // no updates, close the interface + else if (incapacitated()) + return STATUS_UPDATE // update only (orange visibility) + return STATUS_INTERACTIVE + +/mob/living/silicon/ai/shared_nano_interaction() + if(!has_power()) + return STATUS_CLOSE + if (check_unable(1, 0)) + return STATUS_CLOSE + return ..() + +/mob/living/silicon/robot/shared_nano_interaction() + . = STATUS_INTERACTIVE + if(!cell || cell.charge <= 0) + return STATUS_CLOSE + if(lockcharge) + . = STATUS_DISABLED + return min(., ..()) diff --git a/code/modules/nano/interaction/conscious.dm b/code/modules/nano/interaction/conscious.dm new file mode 100644 index 00000000..76a5d70a --- /dev/null +++ b/code/modules/nano/interaction/conscious.dm @@ -0,0 +1,7 @@ +/* + This state only checks if user is conscious. +*/ +GLOBAL_DATUM_INIT(conscious_state, /datum/topic_state/conscious_state, new) + +/datum/topic_state/conscious_state/can_use_topic(var/src_object, var/mob/user) + return user.stat == CONSCIOUS ? STATUS_INTERACTIVE : STATUS_CLOSE diff --git a/code/modules/nano/interaction/contained.dm b/code/modules/nano/interaction/contained.dm new file mode 100644 index 00000000..ffa4f376 --- /dev/null +++ b/code/modules/nano/interaction/contained.dm @@ -0,0 +1,18 @@ +/* + This state checks if user is somewhere within src_object, as well as the default NanoUI interaction. +*/ +GLOBAL_DATUM_INIT(contained_state, /datum/topic_state/contained_state, new) + +/datum/topic_state/contained_state/can_use_topic(var/atom/src_object, var/mob/user) + if(!src_object.contains(user)) + return STATUS_CLOSE + + return user.shared_nano_interaction() + +/atom/proc/contains(var/atom/location) + if(!location) + return 0 + if(location == src) + return 1 + + return contains(location.loc) diff --git a/code/modules/nano/interaction/default.dm b/code/modules/nano/interaction/default.dm new file mode 100644 index 00000000..f896260d --- /dev/null +++ b/code/modules/nano/interaction/default.dm @@ -0,0 +1,96 @@ +GLOBAL_DATUM_INIT(default_state, /datum/topic_state/default, new) + +/datum/topic_state/default/href_list(var/mob/user) + return list() + +/datum/topic_state/default/can_use_topic(var/src_object, var/mob/user) + return user.default_can_use_topic(src_object) + +/mob/proc/default_can_use_topic(var/src_object) + return STATUS_CLOSE // By default no mob can do anything with NanoUI + +/mob/observer/ghost/default_can_use_topic(var/src_object) + if(can_admin_interact()) + return STATUS_INTERACTIVE // Admins are more equal + if(!client || get_dist(src_object, src) > client.view) // Preventing ghosts from having a million windows open by limiting to objects in range + return STATUS_CLOSE + return STATUS_UPDATE // Ghosts can view updates + +/mob/living/silicon/pai/default_can_use_topic(var/src_object) + if((src_object == src || src_object == silicon_radio) && !stat) + return STATUS_INTERACTIVE + else + return ..() + +/mob/living/silicon/robot/default_can_use_topic(var/src_object) + . = shared_nano_interaction() + if(. <= STATUS_DISABLED) + return + + // robots can interact with things they can see within their view range + if((src_object in view(src)) && get_dist(src_object, src) <= src.client.view) + return STATUS_INTERACTIVE // interactive (green visibility) + return STATUS_DISABLED // no updates, completely disabled (red visibility) + +/mob/living/silicon/ai/default_can_use_topic(var/src_object) + . = shared_nano_interaction() + if(. != STATUS_INTERACTIVE) + return + + // Prevents the AI from using Topic on admin levels (by for example viewing through the court/thunderdome cameras) + // unless it's on the same level as the object it's interacting with. + var/turf/T = get_turf(src_object) + if(!T || !(z == T.z || (T.z in GLOB.using_map.player_levels))) + return STATUS_CLOSE + + // If an object is in view then we can interact with it + if(src_object in view(client.view, src)) + return STATUS_INTERACTIVE + + // If we're installed in a chassi, rather than transfered to an inteliCard or other container, then check if we have camera view + if(is_in_chassis()) + //stop AIs from leaving windows open and using then after they lose vision + if(cameranet && !cameranet.is_turf_visible(get_turf(src_object))) + return STATUS_CLOSE + return STATUS_INTERACTIVE + else if(get_dist(src_object, src) <= client.view) // View does not return what one would expect while installed in an inteliCard + return STATUS_INTERACTIVE + + return STATUS_CLOSE + +//Some atoms such as vehicles might have special rules for how mobs inside them interact with NanoUI. +/atom/proc/contents_nano_distance(var/src_object, var/mob/living/user) + return user.shared_living_nano_distance(src_object) + +/mob/living/proc/shared_living_nano_distance(var/atom/movable/src_object) + if (!(src_object in view(4, src))) // If the src object is not visable, disable updates + return STATUS_CLOSE + + var/dist = get_dist(src_object, src) + if (dist <= 1) // interactive (green visibility) + // Checking adjacency even when distance is 0 because get_dist() doesn't include Z-level differences and + // the client might have its eye shifted up/down thus putting src_object in view. + return Adjacent(src_object) ? STATUS_INTERACTIVE : STATUS_UPDATE + else if (dist <= 2) + return STATUS_UPDATE // update only (orange visibility) + else if (dist <= 4) + return STATUS_DISABLED // no updates, completely disabled (red visibility) + return STATUS_CLOSE + +/mob/living/default_can_use_topic(var/src_object) + . = shared_nano_interaction(src_object) + if(. != STATUS_CLOSE) + if(loc) + . = min(., loc.contents_nano_distance(src_object, src)) + if(STATUS_INTERACTIVE) + return STATUS_UPDATE + +/mob/living/carbon/human/default_can_use_topic(var/src_object) + . = shared_nano_interaction(src_object) + if(. != STATUS_CLOSE) + if(loc) + . = min(., loc.contents_nano_distance(src_object, src)) + else + . = min(., shared_living_nano_distance(src_object)) + if(. == STATUS_UPDATE && (TK in mutations)) // If we have telekinesis and remain close enough, allow interaction. + return STATUS_INTERACTIVE diff --git a/code/modules/nano/interaction/hands.dm b/code/modules/nano/interaction/hands.dm new file mode 100644 index 00000000..c9830934 --- /dev/null +++ b/code/modules/nano/interaction/hands.dm @@ -0,0 +1,9 @@ +/* + This state only checks if user is conscious. +*/ +GLOBAL_DATUM_INIT(hands_state, /datum/topic_state/hands, new) + +/datum/topic_state/hands/can_use_topic(var/src_object, var/mob/user) + . = user.shared_ui_interaction(src_object) + if(. > STATUS_CLOSE) + . = min(., user.hands_can_use_topic(src_object)) diff --git a/code/modules/nano/interaction/interactive.dm b/code/modules/nano/interaction/interactive.dm new file mode 100644 index 00000000..c546cf23 --- /dev/null +++ b/code/modules/nano/interaction/interactive.dm @@ -0,0 +1,7 @@ +/* + This state always returns STATUS_INTERACTIVE +*/ +GLOBAL_DATUM_INIT(interactive_state, /datum/topic_state/interactive, new) + +/datum/topic_state/interactive/can_use_topic(var/src_object, var/mob/user) + return STATUS_INTERACTIVE diff --git a/code/modules/nano/interaction/inventory.dm b/code/modules/nano/interaction/inventory.dm new file mode 100644 index 00000000..b17c62a9 --- /dev/null +++ b/code/modules/nano/interaction/inventory.dm @@ -0,0 +1,10 @@ +/* + This state checks that the src_object is somewhere in the user's first-level inventory (in hands, on ear, etc.), but not further down (such as in bags). +*/ +GLOBAL_DATUM_INIT(inventory_state, /datum/topic_state/inventory_state, new) + +/datum/topic_state/inventory_state/can_use_topic(var/src_object, var/mob/user) + if(!(src_object in user)) + return STATUS_CLOSE + + return user.shared_nano_interaction() diff --git a/code/modules/nano/interaction/inventory_deep.dm b/code/modules/nano/interaction/inventory_deep.dm new file mode 100644 index 00000000..1df42064 --- /dev/null +++ b/code/modules/nano/interaction/inventory_deep.dm @@ -0,0 +1,10 @@ +/* + This state checks if src_object is contained anywhere in the user's inventory, including bags, etc. +*/ +GLOBAL_DATUM_INIT(deep_inventory_state, /datum/topic_state/deep_inventory_state, new) + +/datum/topic_state/deep_inventory_state/can_use_topic(var/src_object, var/mob/user) + if(!user.contains(src_object)) + return STATUS_CLOSE + + return user.shared_nano_interaction() diff --git a/code/modules/nano/interaction/outside.dm b/code/modules/nano/interaction/outside.dm new file mode 100644 index 00000000..ddecbaff --- /dev/null +++ b/code/modules/nano/interaction/outside.dm @@ -0,0 +1,6 @@ +GLOBAL_DATUM_INIT(outside_state, /datum/topic_state/default/outside, new) + +/datum/topic_state/default/outside/can_use_topic(var/src_object, var/mob/user) + if(user in src_object) + return STATUS_CLOSE + return ..() diff --git a/code/modules/nano/interaction/physical.dm b/code/modules/nano/interaction/physical.dm new file mode 100644 index 00000000..a653aecc --- /dev/null +++ b/code/modules/nano/interaction/physical.dm @@ -0,0 +1,18 @@ +GLOBAL_DATUM_INIT(physical_state, /datum/topic_state/physical, new) + +/datum/topic_state/physical/can_use_topic(var/src_object, var/mob/user) + . = user.shared_nano_interaction(src_object) + if(. > STATUS_CLOSE) + return min(., user.check_physical_distance(src_object)) + +/mob/proc/check_physical_distance(var/src_object) + return STATUS_CLOSE + +/mob/observer/ghost/check_physical_distance(var/src_object) + return default_can_use_topic(src_object) + +/mob/living/check_physical_distance(var/src_object) + return shared_living_nano_distance(src_object) + +/mob/living/silicon/check_physical_distance(var/src_object) + return max(STATUS_UPDATE, shared_living_nano_distance(src_object)) diff --git a/code/modules/nano/interaction/remote.dm b/code/modules/nano/interaction/remote.dm new file mode 100644 index 00000000..cae60d5a --- /dev/null +++ b/code/modules/nano/interaction/remote.dm @@ -0,0 +1,39 @@ +/* + This state checks that user is capable, within range of the remoter, etc. and that src_object meets the basic requirements for interaction (being powered, non-broken, etc. + Whoever initializes this state is also responsible for deleting it properly. +*/ +/datum/topic_state/remote + var/datum/remoter + var/datum/remote_target + var/datum/topic_state/remoter_state + +/datum/topic_state/remote/New(var/remoter, var/remote_target, var/datum/topic_state/remoter_state = GLOB.default_state) + src.remoter = remoter + src.remote_target = remote_target + src.remoter_state = remoter_state + ..() + +/datum/topic_state/remote/Destroy() + src.remoter = null + src.remoter_state = null + + // Force an UI update before we go, ensuring that any windows we may have opened for the remote target closes. + GLOB.nanomanager.update_uis(remote_target.nano_container()) + remote_target = null + return ..() + +/datum/topic_state/remote/can_use_topic(var/datum/src_object, var/mob/user) + if(!(remoter && remoter_state)) // The remoter is gone, let us leave + return STATUS_CLOSE + + if(src_object != remote_target) + error("remote - Unexpected src_object: Expected '[remote_target]'/[remote_target.type], was '[src_object]'/[src_object.type]") + + // This checks if src_object is powered, etc. + // The interactive state is otherwise simplistic and only returns STATUS_INTERACTIVE and never checks distances, etc. + . = src_object.CanUseTopic(user, GLOB.interactive_state) + if(. == STATUS_CLOSE) + return + + // This is the (generally) heavy checking, making sure the user is capable, within range of the remoter source, etc. + return min(., remoter.CanUseTopic(user, remoter_state)) diff --git a/code/modules/nano/interaction/self.dm b/code/modules/nano/interaction/self.dm new file mode 100644 index 00000000..d1f0ed2f --- /dev/null +++ b/code/modules/nano/interaction/self.dm @@ -0,0 +1,9 @@ +/* + This state checks that the src_object is the same the as user +*/ +GLOBAL_DATUM_INIT(self_state, /datum/topic_state/self_state, new) + +/datum/topic_state/self_state/can_use_topic(var/src_object, var/mob/user) + if(src_object != user) + return STATUS_CLOSE + return user.shared_nano_interaction() diff --git a/code/modules/nano/interaction/zlevel.dm b/code/modules/nano/interaction/zlevel.dm new file mode 100644 index 00000000..9f2380e1 --- /dev/null +++ b/code/modules/nano/interaction/zlevel.dm @@ -0,0 +1,13 @@ +/* + This state checks that the user is on the same Z-level as src_object +*/ + +GLOBAL_DATUM_INIT(z_state, /datum/topic_state/z_state, new) + +/datum/topic_state/z_state/can_use_topic(var/src_object, var/mob/user) + var/turf/turf_obj = get_turf(src_object) + var/turf/turf_usr = get_turf(user) + if(!turf_obj || !turf_usr) + return STATUS_CLOSE + + return turf_obj.z == turf_usr.z ? STATUS_INTERACTIVE : STATUS_CLOSE diff --git a/code/modules/nano/modules/human_appearance.dm b/code/modules/nano/modules/human_appearance.dm new file mode 100644 index 00000000..94847a7e --- /dev/null +++ b/code/modules/nano/modules/human_appearance.dm @@ -0,0 +1,170 @@ +/datum/nano_module/appearance_changer + name = "Appearance Editor" + available_to_ai = FALSE + var/flags = APPEARANCE_ALL_HAIR + var/mob/living/carbon/human/owner = null + var/list/valid_species = list() + var/list/valid_hairstyles = list() + var/list/valid_facial_hairstyles = list() + + var/check_whitelist + var/list/whitelist + var/list/blacklist + +/datum/nano_module/appearance_changer/New(var/location, var/mob/living/carbon/human/H, var/check_species_whitelist = 1, var/list/species_whitelist = list(), var/list/species_blacklist = list()) + ..() + owner = H + src.check_whitelist = check_species_whitelist + src.whitelist = species_whitelist + src.blacklist = species_blacklist + +/datum/nano_module/appearance_changer/Topic(ref, href_list, var/datum/topic_state/state = GLOB.default_state) + if(..()) + return 1 + + if(href_list["race"]) + if(can_change(APPEARANCE_RACE) && (href_list["race"] in valid_species)) + if(owner.change_species(href_list["race"])) + cut_and_generate_data() + return 1 + if(href_list["gender"]) + if(can_change(APPEARANCE_GENDER) && (href_list["gender"] in owner.species.genders)) + if(owner.change_gender(href_list["gender"])) + cut_and_generate_data() + return 1 + if(href_list["skin_tone"]) + if(can_change_skin_tone()) + var/new_s_tone = input(usr, "Choose your character's skin-tone:\n1 (lighter) - [owner.species.max_skin_tone()] (darker)", "Skin Tone", -owner.s_tone + 35) as num|null + if(isnum(new_s_tone) && can_still_topic(state) && owner.species.appearance_flags & HAS_SKIN_TONE_NORMAL) + new_s_tone = 35 - max(min(round(new_s_tone), owner.species.max_skin_tone()), 1) + return owner.change_skin_tone(new_s_tone) + if(href_list["skin_color"]) + if(can_change_skin_color()) + var/new_skin = input(usr, "Choose your character's skin colour: ", "Skin Color", rgb(owner.r_skin, owner.g_skin, owner.b_skin)) as color|null + if(new_skin && can_still_topic(state)) + var/r_skin = hex2num(copytext(new_skin, 2, 4)) + var/g_skin = hex2num(copytext(new_skin, 4, 6)) + var/b_skin = hex2num(copytext(new_skin, 6, 8)) + if(owner.change_skin_color(r_skin, g_skin, b_skin)) + update_dna() + return 1 + if(href_list["hair"]) + if(can_change(APPEARANCE_HAIR) && (href_list["hair"] in valid_hairstyles)) + if(owner.change_hair(href_list["hair"])) + update_dna() + return 1 + if(href_list["hair_color"]) + if(can_change(APPEARANCE_HAIR_COLOR)) + var/new_hair = input("Please select hair color.", "Hair Color", rgb(owner.r_hair, owner.g_hair, owner.b_hair)) as color|null + if(new_hair && can_still_topic(state)) + var/r_hair = hex2num(copytext(new_hair, 2, 4)) + var/g_hair = hex2num(copytext(new_hair, 4, 6)) + var/b_hair = hex2num(copytext(new_hair, 6, 8)) + if(owner.change_hair_color(r_hair, g_hair, b_hair)) + update_dna() + return 1 + if(href_list["facial_hair"]) + if(can_change(APPEARANCE_FACIAL_HAIR) && (href_list["facial_hair"] in valid_facial_hairstyles)) + if(owner.change_facial_hair(href_list["facial_hair"])) + update_dna() + return 1 + if(href_list["facial_hair_color"]) + if(can_change(APPEARANCE_FACIAL_HAIR_COLOR)) + var/new_facial = input("Please select facial hair color.", "Facial Hair Color", rgb(owner.r_facial, owner.g_facial, owner.b_facial)) as color|null + if(new_facial && can_still_topic(state)) + var/r_facial = hex2num(copytext(new_facial, 2, 4)) + var/g_facial = hex2num(copytext(new_facial, 4, 6)) + var/b_facial = hex2num(copytext(new_facial, 6, 8)) + if(owner.change_facial_hair_color(r_facial, g_facial, b_facial)) + update_dna() + return 1 + if(href_list["eye_color"]) + if(can_change(APPEARANCE_EYE_COLOR)) + var/new_eyes = input("Please select eye color.", "Eye Color", rgb(owner.r_eyes, owner.g_eyes, owner.b_eyes)) as color|null + if(new_eyes && can_still_topic(state)) + var/r_eyes = hex2num(copytext(new_eyes, 2, 4)) + var/g_eyes = hex2num(copytext(new_eyes, 4, 6)) + var/b_eyes = hex2num(copytext(new_eyes, 6, 8)) + if(owner.change_eye_color(r_eyes, g_eyes, b_eyes)) + update_dna() + return 1 + + return 0 + +/datum/nano_module/appearance_changer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + if(!owner || !owner.species) + return + + generate_data(check_whitelist, whitelist, blacklist) + var/list/data = host.initial_data() + + data["specimen"] = owner.species.name + data["gender"] = owner.gender + data["change_race"] = can_change(APPEARANCE_RACE) + if(data["change_race"]) + var/species[0] + for(var/specimen in valid_species) + species[++species.len] = list("specimen" = specimen) + data["species"] = species + + data["change_gender"] = can_change(APPEARANCE_GENDER) + if(data["change_gender"]) + var/genders[0] + for(var/gender in owner.species.genders) + genders[++genders.len] = list("gender_name" = gender2text(gender), "gender_key" = gender) + data["genders"] = genders + data["change_skin_tone"] = can_change_skin_tone() + data["change_skin_color"] = can_change_skin_color() + data["change_eye_color"] = can_change(APPEARANCE_EYE_COLOR) + data["change_hair"] = can_change(APPEARANCE_HAIR) + if(data["change_hair"]) + var/hair_styles[0] + for(var/hair_style in valid_hairstyles) + hair_styles[++hair_styles.len] = list("hairstyle" = hair_style) + data["hair_styles"] = hair_styles + data["hair_style"] = owner.h_style + + data["change_facial_hair"] = can_change(APPEARANCE_FACIAL_HAIR) + if(data["change_facial_hair"]) + var/facial_hair_styles[0] + for(var/facial_hair_style in valid_facial_hairstyles) + facial_hair_styles[++facial_hair_styles.len] = list("facialhairstyle" = facial_hair_style) + data["facial_hair_styles"] = facial_hair_styles + data["facial_hair_style"] = owner.f_style + + data["change_hair_color"] = can_change(APPEARANCE_HAIR_COLOR) + data["change_facial_hair_color"] = can_change(APPEARANCE_FACIAL_HAIR_COLOR) + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "appearance_changer.tmpl", "[src]", 800, 450, state = state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/nano_module/appearance_changer/proc/update_dna() + if(owner && (flags & APPEARANCE_UPDATE_DNA)) + owner.update_dna() + +/datum/nano_module/appearance_changer/proc/can_change(var/flag) + return owner && (flags & flag) + +/datum/nano_module/appearance_changer/proc/can_change_skin_tone() + return owner && (flags & APPEARANCE_SKIN) && owner.species.appearance_flags & HAS_A_SKIN_TONE + +/datum/nano_module/appearance_changer/proc/can_change_skin_color() + return owner && (flags & APPEARANCE_SKIN) && owner.species.appearance_flags & HAS_SKIN_COLOR + +/datum/nano_module/appearance_changer/proc/cut_and_generate_data() + // Making the assumption that the available species remain constant + valid_facial_hairstyles.Cut() + valid_facial_hairstyles.Cut() + generate_data() + +/datum/nano_module/appearance_changer/proc/generate_data() + if(!owner) + return + if(!valid_species.len) + valid_species = owner.generate_valid_species(check_whitelist, whitelist, blacklist) + if(!valid_hairstyles.len || !valid_facial_hairstyles.len) + valid_hairstyles = owner.generate_valid_hairstyles(check_gender = 0) + valid_facial_hairstyles = owner.generate_valid_facial_hairstyles() diff --git a/code/modules/nano/modules/law_manager.dm b/code/modules/nano/modules/law_manager.dm new file mode 100644 index 00000000..4687db9c --- /dev/null +++ b/code/modules/nano/modules/law_manager.dm @@ -0,0 +1,219 @@ +/datum/nano_module/law_manager + name = "Law manager" + var/ion_law = "IonLaw" + var/zeroth_law = "ZerothLaw" + var/inherent_law = "InherentLaw" + var/supplied_law = "SuppliedLaw" + var/supplied_law_position = MIN_SUPPLIED_LAW_NUMBER + + var/current_view = 0 + + var/global/list/datum/ai_laws/admin_laws + var/global/list/datum/ai_laws/player_laws + var/mob/living/silicon/owner = null + +/datum/nano_module/law_manager/New(var/mob/living/silicon/S) + ..() + owner = S + + if(!admin_laws) + admin_laws = new() + player_laws = new() + + init_subtypes(/datum/ai_laws, admin_laws) + admin_laws = dd_sortedObjectList(admin_laws) + + for(var/datum/ai_laws/laws in admin_laws) + if(laws.selectable) + player_laws += laws + +/datum/nano_module/law_manager/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["set_view"]) + current_view = text2num(href_list["set_view"]) + return 1 + + if(href_list["law_channel"]) + if(href_list["law_channel"] in owner.law_channels()) + owner.lawchannel = href_list["law_channel"] + return 1 + + if(href_list["state_law"]) + var/datum/ai_law/AL = locate(href_list["ref"]) in owner.laws.all_laws() + if(AL) + var/state_law = text2num(href_list["state_law"]) + owner.laws.set_state_law(AL, state_law) + return 1 + + if(href_list["add_zeroth_law"]) + if(zeroth_law && is_admin(usr) && !owner.laws.zeroth_law) + owner.set_zeroth_law(zeroth_law) + return 1 + + if(href_list["add_ion_law"]) + if(ion_law && is_malf(usr)) + owner.add_ion_law(ion_law) + return 1 + + if(href_list["add_inherent_law"]) + if(inherent_law && is_malf(usr)) + owner.add_inherent_law(inherent_law) + return 1 + + if(href_list["add_supplied_law"]) + if(supplied_law && supplied_law_position >= 1 && MIN_SUPPLIED_LAW_NUMBER <= MAX_SUPPLIED_LAW_NUMBER && is_malf(usr)) + owner.add_supplied_law(supplied_law_position, supplied_law) + return 1 + + if(href_list["change_zeroth_law"]) + var/new_law = sanitize(input("Enter new law Zero. Leaving the field blank will cancel the edit.", "Edit Law", zeroth_law)) + if(new_law && new_law != zeroth_law && can_still_topic()) + zeroth_law = new_law + return 1 + + if(href_list["change_ion_law"]) + var/new_law = sanitize(input("Enter new ion law. Leaving the field blank will cancel the edit.", "Edit Law", ion_law)) + if(new_law && new_law != ion_law && can_still_topic()) + ion_law = new_law + return 1 + + if(href_list["change_inherent_law"]) + var/new_law = sanitize(input("Enter new inherent law. Leaving the field blank will cancel the edit.", "Edit Law", inherent_law)) + if(new_law && new_law != inherent_law && can_still_topic()) + inherent_law = new_law + return 1 + + if(href_list["change_supplied_law"]) + var/new_law = sanitize(input("Enter new supplied law. Leaving the field blank will cancel the edit.", "Edit Law", supplied_law)) + if(new_law && new_law != supplied_law && can_still_topic()) + supplied_law = new_law + return 1 + + if(href_list["change_supplied_law_position"]) + var/new_position = input(usr, "Enter new supplied law position between 1 and [MAX_SUPPLIED_LAW_NUMBER], inclusive. Inherent laws at the same index as a supplied law will not be stated.", "Law Position", supplied_law_position) as num|null + if(isnum(new_position) && can_still_topic()) + supplied_law_position = Clamp(new_position, 1, MAX_SUPPLIED_LAW_NUMBER) + return 1 + + if(href_list["edit_law"]) + if(is_malf(usr)) + var/datum/ai_law/AL = locate(href_list["edit_law"]) in owner.laws.all_laws() + if(AL) + var/new_law = sanitize(input(usr, "Enter new law. Leaving the field blank will cancel the edit.", "Edit Law", AL.law)) + if(new_law && new_law != AL.law && is_malf(usr) && can_still_topic()) + log_and_message_admins("has changed a law of [owner] from '[AL.law]' to '[new_law]'") + AL.law = new_law + return 1 + + if(href_list["delete_law"]) + if(is_malf(usr)) + var/datum/ai_law/AL = locate(href_list["delete_law"]) in owner.laws.all_laws() + if(AL && is_malf(usr)) + owner.delete_law(AL) + return 1 + + if(href_list["state_laws"]) + owner.statelaws(owner.laws) + return 1 + + if(href_list["state_law_set"]) + var/datum/ai_laws/ALs = locate(href_list["state_law_set"]) in (is_admin(usr) ? admin_laws : player_laws) + if(ALs) + owner.statelaws(ALs) + return 1 + + if(href_list["transfer_laws"]) + if(is_malf(usr)) + var/datum/ai_laws/ALs = locate(href_list["transfer_laws"]) in (is_admin(usr) ? admin_laws : player_laws) + if(ALs) + log_and_message_admins("has transfered the [ALs.name] laws to [owner].") + ALs.sync(owner, 0) + current_view = 0 + return 1 + + if(href_list["notify_laws"]) + to_chat(owner, "Law Notice") + owner.laws.show_laws(owner) + if(isAI(owner)) + var/mob/living/silicon/ai/AI = owner + for(var/mob/living/silicon/robot/R in AI.connected_robots) + to_chat(R, "Law Notice") + R.laws.show_laws(R) + if(usr != owner) + to_chat(usr, "Laws displayed.") + return 1 + + return 0 + +/datum/nano_module/law_manager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/data[0] + owner.lawsync() + + data["ion_law_nr"] = ionnum() + data["ion_law"] = ion_law + data["zeroth_law"] = zeroth_law + data["inherent_law"] = inherent_law + data["supplied_law"] = supplied_law + data["supplied_law_position"] = supplied_law_position + + package_laws(data, "zeroth_laws", list(owner.laws.zeroth_law)) + package_laws(data, "ion_laws", owner.laws.ion_laws) + package_laws(data, "inherent_laws", owner.laws.inherent_laws) + package_laws(data, "supplied_laws", owner.laws.supplied_laws) + + data["isAI"] = isAI(owner) + data["isMalf"] = is_malf(user) + data["isSlaved"] = owner.is_slaved() + data["isAdmin"] = is_admin(user) + data["view"] = current_view + + var/channels[0] + for (var/ch_name in owner.law_channels()) + channels[++channels.len] = list("channel" = ch_name) + data["channel"] = owner.lawchannel + data["channels"] = channels + data["law_sets"] = package_multiple_laws(data["isAdmin"] ? admin_laws : player_laws) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "law_manager.tmpl", sanitize("[src] - [owner]"), 800, is_malf(user) ? 600 : 400, state = state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/nano_module/law_manager/proc/package_laws(var/list/data, var/field, var/list/datum/ai_law/laws) + var/packaged_laws[0] + for(var/datum/ai_law/AL in laws) + packaged_laws[++packaged_laws.len] = list("law" = AL.law, "index" = AL.get_index(), "state" = owner.laws.get_state_law(AL), "ref" = "\ref[AL]") + data[field] = packaged_laws + data["has_[field]"] = packaged_laws.len + +/datum/nano_module/law_manager/proc/package_multiple_laws(var/list/datum/ai_laws/laws) + var/law_sets[0] + for(var/datum/ai_laws/ALs in laws) + var/packaged_laws[0] + package_laws(packaged_laws, "zeroth_laws", list(ALs.zeroth_law, ALs.zeroth_law_borg)) + package_laws(packaged_laws, "ion_laws", ALs.ion_laws) + package_laws(packaged_laws, "inherent_laws", ALs.inherent_laws) + package_laws(packaged_laws, "supplied_laws", ALs.supplied_laws) + law_sets[++law_sets.len] = list("name" = ALs.name, "header" = ALs.law_header, "ref" = "\ref[ALs]","laws" = packaged_laws) + + return law_sets + +/datum/nano_module/law_manager/proc/is_malf(var/mob/user) + return (is_admin(user) && !owner.is_slaved()) || owner.is_malf_or_traitor() + +/mob/living/silicon/proc/is_slaved() + return 0 + +/mob/living/silicon/robot/is_slaved() + return lawupdate && connected_ai ? sanitize(connected_ai.name) : null + +/datum/nano_module/law_manager/proc/sync_laws(var/mob/living/silicon/ai/AI) + if(!AI) + return + for(var/mob/living/silicon/robot/R in AI.connected_robots) + R.sync() + log_and_message_admins("has syncronized [AI]'s laws with its borgs.") diff --git a/code/modules/nano/modules/nano_module.dm b/code/modules/nano/modules/nano_module.dm new file mode 100644 index 00000000..11ca5393 --- /dev/null +++ b/code/modules/nano/modules/nano_module.dm @@ -0,0 +1,69 @@ +/datum/nano_module + var/name + var/datum/host + var/available_to_ai = TRUE + var/datum/topic_manager/topic_manager + var/list/using_access + +/datum/nano_module/New(var/datum/host, var/topic_manager) + ..() + src.host = host.nano_host() + src.topic_manager = topic_manager + +/datum/nano_module/nano_host() + return host ? host : src + +/datum/nano_module/proc/can_still_topic(var/datum/topic_state/state = GLOB.default_state) + return CanUseTopic(usr, state) == STATUS_INTERACTIVE + +/datum/nano_module/proc/check_eye(var/mob/user) + return -1 + +/datum/nano_module/proc/check_access(var/mob/user, var/access) + if(!access) + return 1 + + if(using_access) + if(access in using_access) + return 1 + else + return 0 + + if(!istype(user)) + return 0 + + var/obj/item/weapon/card/id/I = user.GetIdCard() + if(!I) + return 0 + + if(access in I.access) + return 1 + + return 0 + +/datum/nano_module/Topic(href, href_list) + if(topic_manager && topic_manager.Topic(href, href_list)) + return TRUE + . = ..() + +/datum/nano_module/proc/get_host_z() + var/atom/host = nano_host() + return istype(host) ? get_z(host) : 0 + +/datum/nano_module/proc/print_text(var/text, var/mob/user) + var/obj/item/modular_computer/MC = nano_host() + if(istype(MC)) + if(!MC.nano_printer) + to_chat(user, "Error: No printer detected. Unable to print document.") + return + + if(!MC.nano_printer.print_text(text)) + to_chat(user, "Error: Printer was unable to print the document. It may be out of paper.") + else + to_chat(user, "Error: Unable to detect compatible printer interface. Are you running NTOSv2 compatible system?") + +/datum/proc/initial_data() + return list() + +/datum/proc/update_layout() + return FALSE \ No newline at end of file diff --git a/code/modules/nano/nanoexternal.dm b/code/modules/nano/nanoexternal.dm new file mode 100644 index 00000000..28d2d37f --- /dev/null +++ b/code/modules/nano/nanoexternal.dm @@ -0,0 +1,44 @@ + // This file contains all Nano procs/definitions for external classes/objects + + /** + * Called when a Nano UI window is closed + * This is how Nano handles closed windows + * It must be a verb so that it can be called using winset + * + * @return nothing + */ +/client/verb/nanoclose(var/uiref as text) + set hidden = 1 // hide this verb from the user's panel + set name = "nanoclose" + + var/datum/nanoui/ui = locate(uiref) + + if (istype(ui)) + ui.close() + + if(ui.ref) + var/href = "close=1" + src.Topic(href, params2list(href), ui.ref) // this will direct to the atom's Topic() proc via client.Topic() + else if (ui.on_close_logic) + // no atomref specified (or not found) + // so just reset the user mob's machine var + if(src && src.mob) + src.mob.unset_machine() + + /** + * The ui_interact proc is used to open and update Nano UIs + * If ui_interact is not used then the UI will not update correctly + * ui_interact is currently defined for /atom/movable + * + * @param user /mob The mob who is interacting with this ui + * @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main") + * @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui + * @param force_open boolean Force the UI to (re)open, even if it's already open + * + * @return nothing + */ +/datum/proc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nano_ui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) + return + +// Used by the Nano UI Manager (/datum/nanomanager) to track UIs opened by this mob +/mob/var/list/open_uis = list() diff --git a/code/modules/nano/nanomanager.dm b/code/modules/nano/nanomanager.dm new file mode 100644 index 00000000..14b3b670 --- /dev/null +++ b/code/modules/nano/nanomanager.dm @@ -0,0 +1,261 @@ +GLOBAL_DATUM_INIT(nanomanager, /datum/nanomanager, new) // NanoManager, the manager for Nano UIs. + +// This is the window/UI manager for Nano UI +// There should only ever be one (global) instance of nanomanger +/datum/nanomanager + // a list of current open /nanoui UIs, grouped by src_object and ui_key + var/open_uis[0] + // a list of current open /nanoui UIs, not grouped, for use in processing + var/list/processing_uis = list() + // a list of asset filenames which are to be sent to the client on user logon + var/list/asset_files = list() + + /** + * Create a new nanomanager instance. + * This proc generates a list of assets which are to be sent to each client on connect + * + * @return /nanomanager new nanomanager object + */ +/datum/nanomanager/New() + var/list/nano_asset_dirs = list(\ + "nano/css/",\ + "nano/images/",\ + "nano/images/modular_computers/",\ + "nano/images/status_icons/",\ + "nano/js/",\ + "nano/templates/"\ + ) + + var/list/filenames = null + for (var/path in nano_asset_dirs) + filenames = flist(path) + for(var/filename in filenames) + if(copytext(filename, length(filename)) != "/") // filenames which end in "/" are actually directories, which we want to ignore + if(fexists(path + filename)) + asset_files.Add(fcopy_rsc(path + filename)) // add this file to asset_files for sending to clients when they connect + + return + + /** + * Get an open /nanoui ui for the current user, src_object and ui_key and try to update it with data + * + * @param user /mob The mob who opened/owns the ui + * @param src_object /obj|/mob The obj or mob which the ui belongs to + * @param ui_key string A string key used for the ui + * @param ui /datum/nanoui An existing instance of the ui (can be null) + * @param data list The data to be passed to the ui, if it exists + * @param force_open boolean The ui is being forced to (re)open, so close ui if it exists (instead of updating) + * + * @return /nanoui Returns the found ui, for null if none exists + */ +/datum/nanomanager/proc/try_update_ui(var/mob/user, src_object, ui_key, var/datum/nanoui/ui, data, var/force_open = 0) + if (isnull(ui)) // no ui has been passed, so we'll search for one + { + ui = get_open_ui(user, src_object, ui_key) + } + if (!isnull(ui)) + // The UI is already open + if (!force_open) + ui.push_data(data) + return ui + else + ui.reinitialise(new_initial_data=data) + return ui + + return null + + /** + * Get an open /nanoui ui for the current user, src_object and ui_key + * + * @param user /mob The mob who opened/owns the ui + * @param src_object /obj|/mob The obj or mob which the ui belongs to + * @param ui_key string A string key used for the ui + * + * @return /nanoui Returns the found ui, or null if none exists + */ +/datum/nanomanager/proc/get_open_ui(var/mob/user, src_object, ui_key) + var/src_object_key = "\ref[src_object]" + if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) + //testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - there are no uis open") + return null + else if (isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list)) + //testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - there are no uis open for this object") + return null + + for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key]) + if (ui.user == user) + return ui + + //testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - ui not found") + return null + + /** + * Update all /nanoui uis attached to src_object + * + * @param src_object /obj|/mob The obj or mob which the uis are attached to + * + * @return int The number of uis updated + */ +/datum/nanomanager/proc/update_uis(src_object) + var/src_object_key = "\ref[src_object]" + if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) + return 0 + + var/update_count = 0 + for (var/ui_key in open_uis[src_object_key]) + for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key]) + if(ui && ui.src_object && ui.user && ui.src_object.nano_host()) + ui.process(1) + update_count++ + return update_count + + /** + * Close all /nanoui uis attached to src_object + * + * @param src_object /obj|/mob The obj or mob which the uis are attached to + * + * @return int The number of uis close + */ +/datum/nanomanager/proc/close_uis(src_object) + var/src_object_key = "\ref[src_object]" + if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) + return 0 + + var/close_count = 0 + for (var/ui_key in open_uis[src_object_key]) + for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key]) + if(ui && ui.src_object && ui.user && ui.src_object.nano_host()) + ui.close() + close_count++ + return close_count + + /** + * Update /nanoui uis belonging to user + * + * @param user /mob The mob who owns the uis + * @param src_object /obj|/mob If src_object is provided, only update uis which are attached to src_object (optional) + * @param ui_key string If ui_key is provided, only update uis with a matching ui_key (optional) + * + * @return int The number of uis updated + */ +/datum/nanomanager/proc/update_user_uis(var/mob/user, src_object = null, ui_key = null) + if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0) + return 0 // has no open uis + + var/update_count = 0 + for (var/datum/nanoui/ui in user.open_uis) + if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key)) + ui.process(1) + update_count++ + + return update_count + + /** + * Close /nanoui uis belonging to user + * + * @param user /mob The mob who owns the uis + * @param src_object /obj|/mob If src_object is provided, only close uis which are attached to src_object (optional) + * @param ui_key string If ui_key is provided, only close uis with a matching ui_key (optional) + * + * @return int The number of uis closed + */ +/datum/nanomanager/proc/close_user_uis(var/mob/user, src_object = null, ui_key = null) + if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0) + //testing("nanomanager/close_user_uis mob [user.name] has no open uis") + return 0 // has no open uis + + var/close_count = 0 + for (var/datum/nanoui/ui in user.open_uis) + if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key)) + ui.close() + close_count++ + + //testing("nanomanager/close_user_uis mob [user.name] closed [open_uis.len] of [close_count] uis") + + return close_count + + /** + * Add a /nanoui ui to the list of open uis + * This is called by the /nanoui open() proc + * + * @param ui /nanoui The ui to add + * + * @return nothing + */ +/datum/nanomanager/proc/ui_opened(var/datum/nanoui/ui) + var/src_object_key = "\ref[ui.src_object]" + if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) + open_uis[src_object_key] = list(ui.ui_key = list()) + else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list)) + open_uis[src_object_key][ui.ui_key] = list(); + + ui.user.open_uis |= ui + var/list/uis = open_uis[src_object_key][ui.ui_key] + uis |= ui + processing_uis |= ui + //testing("nanomanager/ui_opened mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.open_uis [ui.user.open_uis.len] | uis [uis.len] | processing_uis [processing_uis.len]") + + /** + * Remove a /nanoui ui from the list of open uis + * This is called by the /nanoui close() proc + * + * @param ui /nanoui The ui to remove + * + * @return int 0 if no ui was removed, 1 if removed successfully + */ +/datum/nanomanager/proc/ui_closed(var/datum/nanoui/ui) + var/src_object_key = "\ref[ui.src_object]" + if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) + return 0 // wasn't open + else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list)) + return 0 // wasn't open + + processing_uis.Remove(ui) + if(ui.user) // Sanity check in case a user has been deleted (say a blown up borg watching the alarm interface) + ui.user.open_uis.Remove(ui) + var/list/uis = open_uis[src_object_key][ui.ui_key] + uis.Remove(ui) + + //testing("nanomanager/ui_closed mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.open_uis [ui.user.open_uis.len] | uis [uis.len] | processing_uis [processing_uis.len]") + + return 1 + + /** + * This is called on user logout + * Closes/clears all uis attached to the user's /mob + * + * @param user /mob The user's mob + * + * @return nothing + */ + +// +/datum/nanomanager/proc/user_logout(var/mob/user) + //testing("nanomanager/user_logout user [user.name]") + return close_user_uis(user) + + /** + * This is called when a player transfers from one mob to another + * Transfers all open UIs to the new mob + * + * @param oldMob /mob The user's old mob + * @param newMob /mob The user's new mob + * + * @return nothing + */ +/datum/nanomanager/proc/user_transferred(var/mob/oldMob, var/mob/newMob) + //testing("nanomanager/user_transferred from mob [oldMob.name] to mob [newMob.name]") + if (!oldMob || isnull(oldMob.open_uis) || !istype(oldMob.open_uis, /list) || open_uis.len == 0) + //testing("nanomanager/user_transferred mob [oldMob.name] has no open uis") + return 0 // has no open uis + + if (isnull(newMob.open_uis) || !istype(newMob.open_uis, /list)) + newMob.open_uis = list() + + for (var/datum/nanoui/ui in oldMob.open_uis) + ui.user = newMob + newMob.open_uis.Add(ui) + + oldMob.open_uis.Cut() + + return 1 // success diff --git a/code/modules/nano/nanomapgen.dm b/code/modules/nano/nanomapgen.dm new file mode 100644 index 00000000..dd23bed9 --- /dev/null +++ b/code/modules/nano/nanomapgen.dm @@ -0,0 +1,90 @@ +// This file is a modified version of https://raw2.github.com/Baystation12/OldCode-BS12/master/code/TakePicture.dm + +#define NANOMAP_ICON_SIZE 4 +#define NANOMAP_MAX_ICON_DIMENSION 1024 + +#define NANOMAP_TILES_PER_IMAGE (NANOMAP_MAX_ICON_DIMENSION / NANOMAP_ICON_SIZE) + +#define NANOMAP_TERMINALERR 5 +#define NANOMAP_INPROGRESS 2 +#define NANOMAP_BADOUTPUT 2 +#define NANOMAP_SUCCESS 1 +#define NANOMAP_WATCHDOGSUCCESS 4 +#define NANOMAP_WATCHDOGTERMINATE 3 + + +//Call these procs to dump your world to a series of image files (!!) +//NOTE: Does not explicitly support non 32x32 icons or stuff with large pixel_* values, so don't blame me if it doesn't work perfectly + +/client/proc/nanomapgen_DumpImage() + set name = "Generate NanoUI Map" + set category = "Server" + + if(holder) + nanomapgen_DumpTile(1, 1, text2num(input(usr,"Enter the Z level to generate"))) + +/client/proc/nanomapgen_DumpTile(var/startX = 1, var/startY = 1, var/currentZ = 1, var/endX = -1, var/endY = -1) + + if (endX < 0 || endX > world.maxx) + endX = world.maxx + + if (endY < 0 || endY > world.maxy) + endY = world.maxy + + if (currentZ < 0 || currentZ > world.maxz) + to_chat(usr, "NanoMapGen: ERROR: currentZ ([currentZ]) must be between 1 and [world.maxz]") + + sleep(3) + return NANOMAP_TERMINALERR + + if (startX > endX) + to_chat(usr, "NanoMapGen: ERROR: startX ([startX]) cannot be greater than endX ([endX])") + + sleep(3) + return NANOMAP_TERMINALERR + + if (startY > endX) + to_chat(usr, "NanoMapGen: ERROR: startY ([startY]) cannot be greater than endY ([endY])") + sleep(3) + return NANOMAP_TERMINALERR + + var/icon/Tile = icon(file("nano/mapbase1024.png")) + if (Tile.Width() != NANOMAP_MAX_ICON_DIMENSION || Tile.Height() != NANOMAP_MAX_ICON_DIMENSION) + world.log << "NanoMapGen: ERROR: BASE IMAGE DIMENSIONS ARE NOT [NANOMAP_MAX_ICON_DIMENSION]x[NANOMAP_MAX_ICON_DIMENSION]" + sleep(3) + return NANOMAP_TERMINALERR + + world.log << "NanoMapGen: GENERATE MAP ([startX],[startY],[currentZ]) to ([endX],[endY],[currentZ])" + to_chat(usr, "NanoMapGen: GENERATE MAP ([startX],[startY],[currentZ]) to ([endX],[endY],[currentZ])") + + var/count = 0; + for(var/WorldX = startX, WorldX <= endX, WorldX++) + for(var/WorldY = startY, WorldY <= endY, WorldY++) + + var/atom/Turf = locate(WorldX, WorldY, currentZ) + + var/icon/TurfIcon = new(Turf.icon, Turf.icon_state, dir = Turf.dir) + TurfIcon.Scale(NANOMAP_ICON_SIZE, NANOMAP_ICON_SIZE) + + Tile.Blend(TurfIcon, ICON_OVERLAY, ((WorldX - 1) * NANOMAP_ICON_SIZE), ((WorldY - 1) * NANOMAP_ICON_SIZE)) + + count++ + + if (count % 8000 == 0) + world.log << "NanoMapGen: [count] tiles done" + sleep(1) + + var/mapFilename = "new_[map_image_file_name(currentZ)]" + + world.log << "NanoMapGen: sending [mapFilename] to client" + + usr << browse(Tile, "window=picture;file=[mapFilename];display=0") + + world.log << "NanoMapGen: Done." + + to_chat(usr, "NanoMapGen: Done. File [mapFilename] uploaded to your cache.") + + if (Tile.Width() != NANOMAP_MAX_ICON_DIMENSION || Tile.Height() != NANOMAP_MAX_ICON_DIMENSION) + return NANOMAP_BADOUTPUT + + return NANOMAP_SUCCESS \ No newline at end of file diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm new file mode 100644 index 00000000..ed9a16b9 --- /dev/null +++ b/code/modules/nano/nanoui.dm @@ -0,0 +1,536 @@ +/********************************************************** +NANO UI FRAMEWORK + +nanoui class (or whatever Byond calls classes) + +nanoui is used to open and update nano browser uis +**********************************************************/ + +/datum/nanoui + // the user who opened this ui + var/mob/user + // the object this ui "belongs" to + var/datum/src_object + // the title of this ui + var/title + // the key of this ui, this is to allow multiple (different) uis for each src_object + var/ui_key + // window_id is used as the window name/identifier for browse and onclose + var/window_id + // the browser window width + var/width = 0 + // the browser window height + var/height = 0 + // whether to use extra logic when window closes + var/on_close_logic = 1 + // an extra ref to use when the window is closed, usually null + var/atom/ref = null + // options for modifying window behaviour + var/window_options = "focus=0;can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id + // the list of stylesheets to apply to this ui + var/list/stylesheets = list() + // the list of javascript scripts to use for this ui + var/list/scripts = list() + // a list of templates which can be used with this ui + var/templates[0] + // the layout key for this ui (this is used on the frontend, leave it as "default" unless you know what you're doing) + var/layout_key = "default" + // this sets whether to re-render the ui layout with each update (default 0, turning on will break the map ui if it's in use) + var/auto_update_layout = 0 + // this sets whether to re-render the ui content with each update (default 1) + var/auto_update_content = 1 + // the default state to use for this ui (this is used on the frontend, leave it as "default" unless you know what you're doing) + var/state_key = "default" + // show the map ui, this is used by the default layout + var/show_map = 0 + // the map z level to display + var/map_z_level = 1 + // initial data, containing the full data structure, must be sent to the ui (the data structure cannot be extended later on) + var/list/initial_data[0] + // set to 1 to update the ui automatically every master_controller tick + var/is_auto_updating = 0 + // the current status/visibility of the ui + var/status = STATUS_INTERACTIVE + + // Relationship between a master interface and its children. Used in update_status + var/datum/nanoui/master_ui + var/list/datum/nanoui/children = list() + var/datum/topic_state/state = null + + /** + * Create a new nanoui instance. + * + * @param nuser /mob The mob who has opened/owns this ui + * @param nsrc_object /obj|/mob The obj or mob which this ui belongs to + * @param nui_key string A string key to use for this ui. Allows for multiple unique uis on one src_oject + * @param ntemplate string The filename of the template file from /nano/templates (e.g. "my_template.tmpl") + * @param ntitle string The title of this ui + * @param nwidth int the width of the ui window + * @param nheight int the height of the ui window + * @param nref /atom A custom ref to use if "on_close_logic" is set to 1 + * + * @return /nanoui new nanoui object + */ +/datum/nanoui/New(nuser, nsrc_object, nui_key, ntemplate_filename, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) + user = nuser + src_object = nsrc_object + ui_key = nui_key + window_id = "[ui_key]\ref[src_object]" + + src.master_ui = master_ui + if(master_ui) + master_ui.children += src + src.state = state + + // add the passed template filename as the "main" template, this is required + add_template("main", ntemplate_filename) + + if (ntitle) + title = sanitize(ntitle) + if (nwidth) + width = nwidth + if (nheight) + height = nheight + if (nref) + ref = nref + + add_common_assets() + var/datum/asset/assets = get_asset_datum(/datum/asset/nanoui) + assets.send(user, ntemplate_filename) + + /** + * Use this proc to add assets which are common to (and required by) all nano uis + * + * @return nothing + */ +/datum/nanoui/proc/add_common_assets() + add_script("libraries.min.js") // A JS file comprising of jQuery, doT.js and jQuery Timer libraries (compressed together) + add_script("nano_utility.js") // The NanoUtility JS, this is used to store utility functions. + add_script("nano_template.js") // The NanoTemplate JS, this is used to render templates. + add_script("nano_state_manager.js") // The NanoStateManager JS, it handles updates from the server and passes data to the current state + add_script("nano_state.js") // The NanoState JS, this is the base state which all states must inherit from + add_script("nano_state_default.js") // The NanoStateDefault JS, this is the "default" state (used by all UIs by default), which inherits from NanoState + add_script("nano_base_callbacks.js") // The NanoBaseCallbacks JS, this is used to set up (before and after update) callbacks which are common to all UIs + add_script("nano_base_helpers.js") // The NanoBaseHelpers JS, this is used to set up template helpers which are common to all UIs + add_stylesheet("shared.css") // this CSS sheet is common to all UIs + add_stylesheet("icons.css") // this CSS sheet is common to all UIs + + /** + * Set the current status (also known as visibility) of this ui. + * + * @param state int The status to set, see the defines at the top of this file + * @param push_update int (bool) Push an update to the ui to update it's status (an update is always sent if the status has changed to red (0)) + * + * @return nothing + */ +/datum/nanoui/proc/set_status(state, push_update) + if (state != status) // Only update if it is different + if (status == STATUS_DISABLED) + status = state + if (push_update) + update() + else + status = state + if (push_update || status == 0) + push_data(null, 1) // Update the UI, force the update in case the status is 0, data is null so that previous data is used + + /** + * Update the status (visibility) of this ui based on the user's status + * + * @param push_update int (bool) Push an update to the ui to update it's status. This is set to 0/false if an update is going to be pushed anyway (to avoid unnessary updates) + * + * @return nothing + */ +/datum/nanoui/proc/update_status(var/push_update = 0) + var/atom/host = src_object.nano_host() + var/new_status = host.CanUseTopic(user, state) + if(master_ui) + new_status = min(new_status, master_ui.status) + + set_status(new_status, push_update) + if(new_status == STATUS_CLOSE) + close() + + /** + * Set the ui to auto update (every master_controller tick) + * + * @param state int (bool) Set auto update to 1 or 0 (true/false) + * + * @return nothing + */ +/datum/nanoui/proc/set_auto_update(nstate = 1) + is_auto_updating = nstate + + /** + * Set the initial data for the ui. This is vital as the data structure set here cannot be changed when pushing new updates. + * + * @param data /list The list of data for this ui + * + * @return nothing + */ +/datum/nanoui/proc/set_initial_data(list/data) + initial_data = data + + /** + * Get config data to sent to the ui. + * + * @return /list config data + */ +/datum/nanoui/proc/get_config_data() + var/name = "[src_object]" + name = sanitize(name) + var/list/config_data = list( + "title" = title, + "srcObject" = list("name" = name), + "stateKey" = state_key, + "status" = status, + "autoUpdateLayout" = auto_update_layout, + "autoUpdateContent" = auto_update_content, + "showMap" = show_map, + "mapName" = GLOB.using_map.path, + "mapZLevel" = map_z_level, + "mapZLevels" = GLOB.using_map.map_levels, + "user" = list("name" = user.name) + ) + return config_data + + /** + * Get data to sent to the ui. + * + * @param data /list The list of general data for this ui (can be null to use previous data sent) + * + * @return /list data to send to the ui + */ +/datum/nanoui/proc/get_send_data(var/list/data) + var/list/config_data = get_config_data() + + var/list/send_data = list("config" = config_data) + + if (!isnull(data)) + send_data["data"] = data + + return send_data + + /** + * Set the browser window options for this ui + * + * @param nwindow_options string The new window options + * + * @return nothing + */ +/datum/nanoui/proc/set_window_options(nwindow_options) + window_options = nwindow_options + + /** + * Add a CSS stylesheet to this UI + * These must be added before the UI has been opened, adding after that will have no effect + * + * @param file string The name of the CSS file from /nano/css (e.g. "my_style.css") + * + * @return nothing + */ +/datum/nanoui/proc/add_stylesheet(file) + stylesheets.Add(file) + + /** + * Add a JavsScript script to this UI + * These must be added before the UI has been opened, adding after that will have no effect + * + * @param file string The name of the JavaScript file from /nano/js (e.g. "my_script.js") + * + * @return nothing + */ +/datum/nanoui/proc/add_script(file) + scripts.Add(file) + + /** + * Add a template for this UI + * Templates are combined with the data sent to the UI to create the rendered view + * These must be added before the UI has been opened, adding after that will have no effect + * + * @param key string The key which is used to reference this template in the frontend + * @param filename string The name of the template file from /nano/templates (e.g. "my_template.tmpl") + * + * @return nothing + */ +/datum/nanoui/proc/add_template(key, filename) + templates[key] = filename + + /** + * Set the layout key for use in the frontend Javascript + * The layout key is the basic layout key for the page + * Two files are loaded on the client based on the layout key varable: + * -> a template in /nano/templates with the filename "layout_.tmpl + * -> a CSS stylesheet in /nano/css with the filename "layout_.css + * + * @param nlayout string The layout key to use + * + * @return nothing + */ +/datum/nanoui/proc/set_layout_key(nlayout_key) + layout_key = lowertext(nlayout_key) + + /** + * Set the ui to update the layout (re-render it) on each update, turning this on will break the map ui (if it's being used) + * + * @param state int (bool) Set update to 1 or 0 (true/false) (default 0) + * + * @return nothing + */ +/datum/nanoui/proc/set_auto_update_layout(nstate) + auto_update_layout = nstate + + /** + * Set the ui to update the main content (re-render it) on each update + * + * @param state int (bool) Set update to 1 or 0 (true/false) (default 1) + * + * @return nothing + */ +/datum/nanoui/proc/set_auto_update_content(nstate) + auto_update_content = nstate + + /** + * Set the state key for use in the frontend Javascript + * + * @param nstate_key string The key of the state to use + * + * @return nothing + */ +/datum/nanoui/proc/set_state_key(nstate_key) + state_key = nstate_key + + /** + * Toggle showing the map ui + * + * @param nstate_key boolean 1 to show map, 0 to hide (default is 0) + * + * @return nothing + */ +/datum/nanoui/proc/set_show_map(nstate) + show_map = nstate + + /** + * Toggle showing the map ui + * + * @param nstate_key boolean 1 to show map, 0 to hide (default is 0) + * + * @return nothing + */ +/datum/nanoui/proc/set_map_z_level(nz) + map_z_level = nz + + /** + * Set whether or not to use the "old" on close logic (mainly unset_machine()) + * + * @param state int (bool) Set on_close_logic to 1 or 0 (true/false) + * + * @return nothing + */ +/datum/nanoui/proc/use_on_close_logic(state) + on_close_logic = state + + /** + * Return the HTML for this UI + * + * @return string HTML for the UI + */ +/datum/nanoui/proc/get_html() + + // before the UI opens, add the layout files based on the layout key + add_stylesheet("layout_[layout_key].css") + add_template("layout", "layout_[layout_key].tmpl") + + var/head_content = "" + + for (var/filename in scripts) + head_content += " " + + for (var/filename in stylesheets) + head_content += " " + + var/template_data_json = "{}" // An empty JSON object + if (templates.len > 0) + template_data_json = strip_improper(json_encode(templates)) + + var/list/send_data = get_send_data(initial_data) + var/initial_data_json = replacetext(replacetext(json_encode(send_data), """, "&#34;"), "'", "'") + initial_data_json = strip_improper(initial_data_json); + + var/url_parameters_json = json_encode(list("src" = "\ref[src]")) + + return {" + + + + + + + [head_content] + + +
            +
            + + + + "} + + /** + * Open this UI + * + * @return nothing + */ +/datum/nanoui/proc/open() + if(!user.client) + return + + // An attempted fix to UIs sometimes locking up spamming runtime errors due to src_object being null for whatever reason. + // This hard-deletes the UI, preventing the device that uses the UI from being locked up permanently. + if(!src_object) + qdel(src) + + var/window_size = "" + if (width && height) + window_size = "size=[width]x[height];" + update_status(0) + if(status == STATUS_CLOSE) + return + + user << browse(get_html(), "window=[window_id];[window_size][window_options]") + winset(user, "mapwindow.map", "focus=true") // return keyboard focus to map + on_close_winset() + //onclose(user, window_id) + GLOB.nanomanager.ui_opened(src) + + /** + * Reinitialise this UI, potentially with a different template and/or initial data + * + * @return nothing + */ +/datum/nanoui/proc/reinitialise(template, new_initial_data) + if(template) + add_template("main", template) + if(new_initial_data) + set_initial_data(new_initial_data) + open() + + /** + * Close this UI + * + * @return nothing + */ +/datum/nanoui/proc/close() + is_auto_updating = 0 + GLOB.nanomanager.ui_closed(src) + show_browser(user, null, "window=[window_id]") + for(var/datum/nanoui/child in children) + child.close() + children.Cut() + state = null + master_ui = null + + /** + * Set the UI window to call the nanoclose verb when the window is closed + * This allows Nano to handle closed windows + * + * @return nothing + */ +/datum/nanoui/proc/on_close_winset() + if(!user.client) + return + var/params = "\ref[src]" + + spawn(2) + winset(user, window_id, "on-close=\"nanoclose [params]\"") + + /** + * Push data to an already open UI window + * + * @return nothing + */ +/datum/nanoui/proc/push_data(data, force_push = 0) + update_status(0) + if (status == STATUS_DISABLED && !force_push) + return // Cannot update UI, no visibility + + var/list/send_data = get_send_data(data) + +// to_chat(user, list2json_usecache(send_data))// used for debugging //NANO DEBUG HOOK + + user << output(list2params(list(strip_improper(json_encode(send_data)))),"[window_id].browser:receiveUpdateData") + + /** + * This Topic() proc is called whenever a user clicks on a link within a Nano UI + * If the UI status is currently STATUS_INTERACTIVE then call the src_object Topic() + * If the src_object Topic() returns 1 (true) then update all UIs attached to src_object + * + * @return nothing + */ +/datum/nanoui/Topic(href, href_list) + update_status(0) // update the status + if (status != STATUS_INTERACTIVE || user != usr) // If UI is not interactive or usr calling Topic is not the UI user + return + + // This is used to toggle the nano map ui + var/map_update = 0 + if(href_list["showMap"]) + set_show_map(text2num(href_list["showMap"])) + map_update = 1 + + if(href_list["mapZLevel"]) + var/map_z = text2num(href_list["mapZLevel"]) + if(map_z in GLOB.using_map.map_levels) + set_map_z_level(map_z) + map_update = 1 + else + return + + if ((src_object && src_object.Topic(href, href_list, state)) || map_update) + GLOB.nanomanager.update_uis(src_object) // update all UIs attached to src_object + + /** + * Process this UI, updating the entire UI or just the status (aka visibility) + * This process proc is called by the master_controller + * + * @param update string For this UI to update + * + * @return nothing + */ +/datum/nanoui/proc/process(update = 0) + if (!src_object || !user) + close() + return + + if (status && (update || is_auto_updating)) + update() // Update the UI (update_status() is called whenever a UI is updated) + else + update_status(1) // Not updating UI, so lets check here if status has changed + + /** + * Update the UI + * + * @return nothing + */ +/datum/nanoui/proc/update(var/force_open = 0) + src_object.ui_interact(user, ui_key, src, force_open, master_ui, state) diff --git a/code/modules/organs/_organ_setup.dm b/code/modules/organs/_organ_setup.dm new file mode 100644 index 00000000..485d1a8d --- /dev/null +++ b/code/modules/organs/_organ_setup.dm @@ -0,0 +1,6 @@ +//These control the damage thresholds for the various ways of removing limbs +#define DROPLIMB_THRESHOLD_EDGE 5 +#define DROPLIMB_THRESHOLD_TEAROFF 2 +#define DROPLIMB_THRESHOLD_DESTROY 1 + +#define ORGAN_RECOVERY_THRESHOLD (5 MINUTES) \ No newline at end of file diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm new file mode 100644 index 00000000..70dc5f36 --- /dev/null +++ b/code/modules/organs/blood.dm @@ -0,0 +1,314 @@ +/**************************************************** + BLOOD SYSTEM +****************************************************/ + +/mob/living/carbon/human/var/datum/reagents/vessel // Container for blood and BLOOD ONLY. Do not transfer other chems here. +/mob/living/carbon/human/var/var/pale = 0 // Should affect how mob sprite is drawn, but currently doesn't. + +//Initializes blood vessels +/mob/living/carbon/human/proc/make_blood() + + if(vessel) + return + + vessel = new/datum/reagents(species.blood_volume, src) + + if(!should_have_organ(BP_HEART)) //We want the var for safety but we can do without the actual blood. + return + + vessel.add_reagent(/datum/reagent/blood,species.blood_volume) + fixblood() + +//Resets blood data +/mob/living/carbon/human/proc/fixblood() + for(var/datum/reagent/blood/B in vessel.reagent_list) + if(B.type == /datum/reagent/blood) + B.data = list( + "donor" = weakref(src), + "species" = species.name, + "blood_DNA" = dna.unique_enzymes, + "blood_colour" = species.get_blood_colour(src), + "blood_type" = dna.b_type, + "trace_chem" = null, + "virus2" = list(), + "antibodies" = list() + ) + B.color = B.data["blood_colour"] + +//Makes a blood drop, leaking amt units of blood from the mob +/mob/living/carbon/human/proc/drip(var/amt, var/tar = src, var/ddir) + if(remove_blood(amt)) + if(bloodstr.total_volume) + var/chem_share = round(0.3 * amt * (bloodstr.total_volume/vessel.total_volume), 0.01) + bloodstr.remove_any(chem_share * bloodstr.total_volume) + blood_splatter(tar, src, (ddir && ddir>0), spray_dir = ddir) + playsound(src, "blood_drip", 25, FALSE) + return amt + return 0 + +#define BLOOD_SPRAY_DISTANCE 2 +/mob/living/carbon/human/proc/blood_squirt(var/amt, var/turf/sprayloc) + if(amt <= 0 || !istype(sprayloc)) + return + var/spraydir = pick(GLOB.alldirs) + amt = ceil(amt/BLOOD_SPRAY_DISTANCE) + var/bled = 0 + spawn(0) + for(var/i = 1 to BLOOD_SPRAY_DISTANCE) + sprayloc = get_step(sprayloc, spraydir) + if(!istype(sprayloc) || sprayloc.density) + break + var/hit_mob + for(var/thing in sprayloc) + var/atom/A = thing + if(!A.simulated) + continue + + if(ishuman(A)) + var/mob/living/carbon/human/H = A + if(!H.lying) + H.bloody_body(src) + H.bloody_hands(src) + var/blinding = FALSE + if(ran_zone() == BP_HEAD) + blinding = TRUE + for(var/obj/item/I in list(H.head, H.glasses, H.wear_mask)) + if(I && (I.body_parts_covered & EYES)) + blinding = FALSE + break + if(blinding) + H.eye_blurry = max(H.eye_blurry, 10) + H.eye_blind = max(H.eye_blind, 5) + to_chat(H, "You are blinded by a spray of blood!") + else + to_chat(H, "You are hit by a spray of blood!") + hit_mob = TRUE + + if(hit_mob || !A.CanPass(src, sprayloc)) + break + + drip(amt, sprayloc, spraydir) + bled += amt + if(hit_mob) break + sleep(1) + return bled +#undef BLOOD_SPRAY_DISTANCE + +/mob/living/carbon/human/proc/remove_blood(var/amt) + if(!should_have_organ(BP_HEART)) //TODO: Make drips come from the reagents instead. + return 0 + if(!amt) + return 0 + return vessel.remove_reagent(/datum/reagent/blood, amt * (src.mob_size/MOB_MEDIUM)) + +/**************************************************** + BLOOD TRANSFERS +****************************************************/ + +//Gets blood from mob to the container, preserving all data in it. +/mob/living/carbon/proc/take_blood(obj/item/weapon/reagent_containers/container, var/amount) + var/datum/reagent/blood/B = get_blood(container.reagents) + if(!B) + B = new /datum/reagent/blood + B.sync_to(src) + container.reagents.add_reagent(/datum/reagent/blood, amount, B.data) + else + B.sync_to(src) + B.volume += amount + return 1 + +//For humans, blood does not appear from blue, it comes from vessels. +/mob/living/carbon/human/take_blood(obj/item/weapon/reagent_containers/container, var/amount) + + if(!should_have_organ(BP_HEART)) + reagents.trans_to_obj(container, amount) + return 1 + + if(vessel.get_reagent_amount(/datum/reagent/blood) < amount) + return null + + //make sure virus/etc data is up to date + var/datum/reagent/blood/our = get_blood(vessel) + our.sync_to(src) + vessel.trans_to_holder(container.reagents,amount) + return 1 + +//Transfers blood from container ot vessels +/mob/living/carbon/proc/inject_blood(var/datum/reagent/blood/injected, var/amount) + if (!injected || !istype(injected)) + return + var/list/sniffles = virus_copylist(injected.data["virus2"]) + for(var/ID in sniffles) + var/datum/disease2/disease/sniffle = sniffles[ID] + infect_virus2(src,sniffle,1) + if (injected.data["antibodies"] && prob(5)) + antibodies |= injected.data["antibodies"] + var/list/chems = list() + chems = params2list(injected.data["trace_chem"]) + for(var/C in chems) + src.reagents.add_reagent(C, (text2num(chems[C]) / species.blood_volume) * amount)//adds trace chemicals to owner's blood + reagents.update_total() + +//Transfers blood from reagents to vessel, respecting blood types compatability. +/mob/living/carbon/human/inject_blood(var/datum/reagent/blood/injected, var/amount) + + if(!should_have_organ(BP_HEART)) + reagents.add_reagent(/datum/reagent/blood, amount, injected.data) + reagents.update_total() + return + + if(blood_incompatible(injected.data["blood_type"], injected.data["species"])) + reagents.add_reagent(/datum/reagent/toxin, amount * 0.5) + reagents.update_total() + else + vessel.add_reagent(/datum/reagent/blood, amount, injected.data) + vessel.update_total() + ..() + +//Gets human's own blood. +/mob/living/carbon/proc/get_blood(datum/reagents/container) + var/datum/reagent/blood/res = locate() in container.reagent_list //Grab some blood + if(res) // Make sure there's some blood at all + if(weakref && res.data["donor"] != weakref) //If it's not theirs, then we look for theirs + for(var/datum/reagent/blood/D in container.reagent_list) + if(weakref && D.data["donor"] != weakref) + return D + return res + +/mob/living/carbon/human/proc/blood_incompatible(blood_type, blood_species) + if(blood_species && species.name) + if(blood_species != species.name) + return 1 + + var/donor_antigen = copytext(blood_type, 1, length(blood_type)) + var/receiver_antigen = copytext(dna.b_type, 1, length(dna.b_type)) + var/donor_rh = (findtext(blood_type, "+") > 0) + var/receiver_rh = (findtext(dna.b_type, "+") > 0) + + if(donor_rh && !receiver_rh) return 1 + switch(receiver_antigen) + if("A") + if(donor_antigen != "A" && donor_antigen != "O") return 1 + if("B") + if(donor_antigen != "B" && donor_antigen != "O") return 1 + if("O") + if(donor_antigen != "O") return 1 + //AB is a universal receiver. + return 0 + +/mob/living/carbon/human/proc/regenerate_blood(amount) + var/blood_volume_raw = vessel.get_reagent_amount(/datum/reagent/blood) + amount = max(0,min(amount, species.blood_volume - blood_volume_raw)) + if(amount) + var/datum/reagent/blood/B = get_blood(vessel) + if(istype(B)) + B.volume += amount + vessel.update_total() + return amount + +proc/blood_splatter(var/target,var/datum/reagent/blood/source,var/large,var/spray_dir) + + var/obj/effect/decal/cleanable/blood/B + var/decal_type = /obj/effect/decal/cleanable/blood/splatter + var/turf/T = get_turf(target) + + if(istype(source,/mob/living/carbon/human)) + var/mob/living/carbon/human/M = source + source = M.get_blood(M.vessel) + + // Are we dripping or splattering? + var/list/drips = list() + // Only a certain number of drips (or one large splatter) can be on a given turf. + for(var/obj/effect/decal/cleanable/blood/drip/drop in T) + drips |= drop.drips + qdel(drop) + if(!large && drips.len < 3) + decal_type = /obj/effect/decal/cleanable/blood/drip + + // Find a blood decal or create a new one. + B = locate(decal_type) in T + if(!B) + B = new decal_type(T) + + var/obj/effect/decal/cleanable/blood/drip/drop = B + if(istype(drop) && drips && drips.len && !large) + drop.overlays |= drips + drop.drips |= drips + + // If there's no data to copy, call it quits here. + if(!source) + return B + + // Update appearance. + if(source.data["blood_colour"]) + B.basecolor = source.data["blood_colour"] + B.update_icon() + if(spray_dir) + B.icon_state = "squirt" + B.dir = spray_dir + + // Update blood information. + if(source.data["blood_DNA"]) + B.blood_DNA = list() + if(source.data["blood_type"]) + B.blood_DNA[source.data["blood_DNA"]] = source.data["blood_type"] + else + B.blood_DNA[source.data["blood_DNA"]] = "O+" + + // Update virus information. + if(source.data["virus2"]) + B.virus2 = virus_copylist(source.data["virus2"]) + + B.fluorescent = 0 + B.set_invisibility(0) + return B + +//Percentage of maximum blood volume. +/mob/living/carbon/human/proc/get_blood_volume() + if(vessel) //This is runtiming on spawned children and I don't know why. TODO: figure out why this is runtiming on spawned children. + return round((vessel.get_reagent_amount(/datum/reagent/blood)/species.blood_volume)*100) + +//Percentage of maximum blood volume, affected by the condition of circulation organs +/mob/living/carbon/human/proc/get_blood_circulation() + var/obj/item/organ/internal/heart/heart = internal_organs_by_name[BP_HEART] + var/blood_volume = get_blood_volume() + if(!heart || (heart.pulse == PULSE_NONE && !(status_flags & FAKEDEATH) && heart.robotic < ORGAN_ROBOT)) + blood_volume *= 0.25 + else + var/pulse_mod = 1 + switch(heart.pulse) + if(PULSE_SLOW) + pulse_mod *= 0.9 + if(PULSE_FAST) + pulse_mod *= 1.1 + if(PULSE_2FAST, PULSE_THREADY) + pulse_mod *= 1.25 + blood_volume *= max(0.3, (1-(heart.damage / heart.max_damage))) * pulse_mod + return min(blood_volume, 100) + +//Whether the species needs blood to carry oxygen. Used in get_blood_oxygenation and may be expanded based on blood rather than species in the future. +/mob/living/carbon/human/proc/blood_carries_oxygen() + return species.blood_oxy + +//Percentage of maximum blood volume, affected by the condition of circulation organs, affected by the oxygen loss. What ultimately matters for brain +/mob/living/carbon/human/proc/get_blood_oxygenation() + var/blood_volume = get_blood_circulation() + + if(is_asystole()) // Heart is missing or isn't beating and we're not breathing (hardcrit) + return min(blood_volume, BLOOD_VOLUME_SURVIVE) + + if(!need_breathe()) + return blood_volume + + if(!blood_carries_oxygen()) + blood_volume = 100 + + var/blood_volume_mod = max(0, 1 - getOxyLoss()/(maxHealth/2)) + var/oxygenated_mult = 0 + if(chem_effects[CE_OXYGENATED] == 1) // Dexalin. + oxygenated_mult = 0.5 + else if(chem_effects[CE_OXYGENATED] >= 2) // Dexplus. + oxygenated_mult = 0.8 + blood_volume_mod = blood_volume_mod + oxygenated_mult - (blood_volume_mod * oxygenated_mult) + blood_volume = blood_volume * blood_volume_mod + return min(blood_volume, 100) \ No newline at end of file diff --git a/code/modules/organs/bowels.dm b/code/modules/organs/bowels.dm new file mode 100644 index 00000000..3b37cd78 --- /dev/null +++ b/code/modules/organs/bowels.dm @@ -0,0 +1,90 @@ +/* + ====== + Bowels + ====== + + +What: Bowels will recieve the food chunks from the stomach. Once they have food chunks + they will begin a cycle to produce stool. Stool will only arise when a certain + number of food chunks have entered. Once there is stool it will begin a timer + for how long it has to go until it will automatically come out. (like a timebomb) + I shall be trying to work with Matt's poo code to make sure this works. + + I think that it may be best if each feces has its own poo timer so that it's possible + that the stool can remain in the body without having to actually shit until a threshold + passes. This would allow for the players to eat and not need to worry about using the + bathroom for a little while. A cool thing about this whole digestive system is that + we could possibly force people to have different levels (on top of randomly setting their + nutrition amount) so people start the round starving and some people start the round needing + to shit. It would be worth trying out. + + Currently the bowels ONLY recieve food chunks (maybe liquid) because everything else will + sit in the stomach. Since it is a storage slot however it could be possible to open up + the bowels and stick something in it. + +Broken: Currently no plans for broken bowels, maybe it forces shit instantly + +Missing: Missing bowels will cause the stomach to return its send code. This means that + eventually the mob in question will not be able to eat as their stomach feels + full but they also wont be able to shit to remove it. This means that they either + starve to death or get their stomach pumped. +*/ + + + +/obj/item/organ/internal/bowels + name = "bowels" + icon_state = "stomach" + w_class = ITEM_SIZE_SMALL + organ_tag = BP_BOWELS + parent_organ = BP_CHEST + min_bruised_damage = 25 + min_broken_damage = 45 + max_damage = 80 + var/process_delay = 10 + var/process_time = 0 + var/food_to_stool_ratio = 4 //takes this many food chunks to make 1 stool + var/food_count = 0 + var/stool_count = 0 //might not need this but whatever. + var/obj/item/weapon/storage/special/inventory + +/obj/item/weapon/storage/special/bowels + max_w_class = ITEM_SIZE_SMALL + storage_slots = 12 //default for a human. Max stool will be 4-5 the rest of the space is for food chunk processing. + + +/obj/item/organ/internal/bowels/New() + inventory = new /obj/item/weapon/storage/special/bowels() + inventory.loc = src + inventory.name = name + +/obj/item/organ/internal/bowels/Process() + + if(!owner) + return + + if(world.time - process_time >= process_delay) + process_time = world.time + process_contents() + + +/obj/item/organ/internal/bowels/proc/process_contents() + for(var/obj/item/weapon/reagent_containers/eatable/F in inventory) + if(istype(F, /obj/item/weapon/reagent_containers/eatable/poo)) + continue + food_count += 1 + to_chat(owner, "food count is [food_count]") + if(food_count >= 4) + for(F in inventory) + qdel(F) + food_count -=1 + if(food_count <=0) + to_chat(owner, "I make a poo poo") + new /obj/item/weapon/reagent_containers/eatable/poo(inventory) + //make poo + break + + food_count = 0 + for(var/obj/item/weapon/W in inventory) + if(W) + to_chat(owner, "bowels contains [W]") \ No newline at end of file diff --git a/code/modules/organs/external/_external.dm b/code/modules/organs/external/_external.dm new file mode 100644 index 00000000..c490959d --- /dev/null +++ b/code/modules/organs/external/_external.dm @@ -0,0 +1,1432 @@ +/**************************************************** + EXTERNAL ORGANS +****************************************************/ + +/obj/item/organ/external + name = "external" + min_broken_damage = 30 + max_damage = 0 + dir = SOUTH + organ_tag = "limb" + appearance_flags = PIXEL_SCALE + + // Strings + var/broken_description // fracture string if any. + var/damage_state = "00" // Modifier used for generating the on-mob damage overlay for this limb. + + // Damage vars. + var/brute_mod = 1 // Multiplier for incoming brute damage. + var/burn_mod = 1 // As above for burn. + var/brute_dam = 0 // Actual current brute damage. + var/brute_ratio = 0 // Ratio of current brute damage to max damage. + var/burn_dam = 0 // Actual current burn damage. + var/burn_ratio = 0 // Ratio of current burn damage to max damage. + var/last_dam = -1 // used in healing/processing calculations. + var/pain = 0 // How much the limb hurts. + var/pain_disability_threshold // Point at which a limb becomes unusable due to pain. + + // Appearance vars. + var/nonsolid // Snowflake warning, reee. Used for slime limbs. + var/icon_name = null // Icon state base. + var/body_part = null // Part flag + var/icon_position = 0 // Used in mob overlay layering calculations. + var/model // Used when caching robolimb icons. + var/force_icon // Used to force override of species-specific limb icons (for prosthetics). + var/icon/mob_icon // Cached icon for use in mob overlays. + var/gendered_icon = 0 // Whether or not the icon state appends a gender. + var/s_tone // Skin tone. + var/s_base = "" // Skin base. + var/list/s_col // skin colour + var/s_col_blend = ICON_ADD // How the skin colour is applied. + var/list/h_col // hair colour + var/body_hair // Icon blend for body hair if any. + var/list/markings = list() // Markings (body_markings) to apply to the icon + + // Wound and structural data. + var/wound_update_accuracy = 1 // how often wounds should be updated, a higher number means less often + var/list/wounds = list() // wound datum list. + var/number_wounds = 0 // number of wounds, which is NOT wounds.len! + var/obj/item/organ/external/parent // Master-limb. + var/list/children // Sub-limbs. + var/list/internal_organs = list() // Internal organs of this body part + var/sabotaged = 0 // If a prosthetic limb is emagged, it will detonate when it fails. + var/list/implants = list() // Currently implanted objects. + var/base_miss_chance = 20 // Chance of missing. + var/genetic_degradation = 0 + + //Forensics stuff + var/list/autopsy_data = list() // Trauma data for forensics. + + // Joint/state stuff. + var/can_grasp // It would be more appropriate if these two were named "affects_grasp" and "affects_stand" at this point + var/can_stand // Modifies stance tally/ability to stand. + var/disfigured = 0 // Scarred/burned beyond recognition. + var/cannot_amputate // Impossible to amputate. + var/cannot_break // Impossible to fracture. + var/joint = "joint" // Descriptive string used in dislocation. + var/amputation_point // Descriptive string used in amputation. + var/dislocated = 0 // If you target a joint, you can dislocate the limb, causing temporary damage to the organ. + var/encased // Needs to be opened with a saw to access the organs. + var/has_tendon = FALSE // Can this limb be hamstrung? + var/artery_name = "artery" // Flavour text for carotid artery, aorta, etc. + var/arterial_bleed_severity = 1 // Multiplier for bleeding in a limb. + var/tendon_name = "tendon" // Flavour text for Achilles tendon, etc. + var/cavity_name = "cavity" + + // Surgery vars. + var/cavity_max_w_class = 0 + var/hatch_state = 0 + var/stage = 0 + var/cavity = 0 + var/atom/movable/applied_pressure + var/atom/movable/splinted + + // HUD element variable, see organ_icon.dm get_damage_hud_image() + var/image/hud_damage_image + + var/gibbable = TRUE + var/break_sound = "trauma" + +/obj/item/organ/external/New(var/mob/living/carbon/holder) + ..() + if(isnull(pain_disability_threshold)) + pain_disability_threshold = (max_damage * 0.75) + if(owner) + replaced(owner) + sync_colour_to_human(owner) + get_icon() + +/obj/item/organ/external/Destroy() + + if(wounds) + for(var/datum/wound/wound in wounds) + wound.embedded_objects.Cut() + wounds.Cut() + + if(parent && parent.children) + parent.children -= src + + if(children) + for(var/obj/item/organ/external/C in children) + qdel(C) + + if(internal_organs) + for(var/obj/item/organ/O in internal_organs) + qdel(O) + + applied_pressure = null + if(splinted && splinted.loc == src) + qdel(splinted) + splinted = null + + if(owner) + owner.organs -= src + owner.organs_by_name[organ_tag] = null + owner.organs_by_name -= organ_tag + while(null in owner.organs) + owner.organs -= null + + if(autopsy_data) autopsy_data.Cut() + + return ..() + +/obj/item/organ/external/set_dna(var/datum/dna/new_dna) + ..() + s_col_blend = species.limb_blend + s_base = new_dna.s_base + +/obj/item/organ/external/emp_act(severity) + var/burn_damage = 0 + switch (severity) + if (1) + burn_damage = 15 + if (2) + burn_damage = 7 + if (3) + burn_damage = 3 + burn_damage *= robotic/burn_mod //ignore burn mod for EMP damage + + var/power = 4 - severity //stupid reverse severity + for(var/obj/item/I in implants) + if(I.obj_flags & OBJ_FLAG_CONDUCTIBLE) + burn_damage += I.w_class * rand(power, 3*power) + + if(burn_damage) + owner.custom_pain("Something inside your [src] burns a [severity < 2 ? "bit" : "lot"]!", power * 15) //robotic organs won't feel it anyway + take_damage(0, burn_damage, 0, used_weapon = "Hot metal") + +/obj/item/organ/external/attack_self(var/mob/user) + if(!contents.len) + return ..() + var/list/removable_objects = list() + for(var/obj/item/organ/external/E in (contents + src)) + if(!istype(E)) + continue + for(var/obj/item/I in E.contents) + if(istype(I,/obj/item/organ)) + continue + removable_objects |= I + if(removable_objects.len) + var/obj/item/I = pick(removable_objects) + I.loc = get_turf(user) //just in case something was embedded that is not an item + if(istype(I)) + if(!(user.l_hand && user.r_hand)) + user.put_in_hands(I) + user.visible_message("\The [user] rips \the [I] out of \the [src]!") + return //no eating the limb until everything's been removed + return ..() + +/obj/item/organ/external/examine() + . = ..() + if(in_range(usr, src) || isghost(usr)) + for(var/obj/item/I in contents) + if(istype(I, /obj/item/organ)) + continue + to_chat(usr, "There is \a [I] sticking out of it.") + return + +/obj/item/organ/external/show_decay_status(mob/user) + ..(user) + for(var/obj/item/organ/external/child in children) + child.show_decay_status(user) + +/obj/item/organ/external/attackby(obj/item/weapon/W as obj, mob/user as mob) + switch(stage) + if(0) + if(W.sharp) + user.visible_message("[user] cuts [src] open with [W]!") + stage++ + return + if(1) + if(istype(W)) + user.visible_message("[user] cracks [src] open like an egg with [W]!") + stage++ + return + if(2) + if(W.sharp || istype(W,/obj/item/weapon/hemostat) || isWirecutter(W)) + var/list/organs = get_contents_recursive() + if(organs.len) + var/obj/item/removing = pick(organs) + var/obj/item/organ/external/current_child = removing.loc + + current_child.implants.Remove(removing) + current_child.internal_organs.Remove(removing) + + status |= ORGAN_CUT_AWAY + if(istype(removing, /obj/item/organ/internal/mmi_holder)) + var/obj/item/organ/internal/mmi_holder/O = removing + removing = O.transfer_and_delete() + + removing.forceMove(get_turf(user)) + + if(!(user.l_hand && user.r_hand)) + user.put_in_hands(removing) + user.visible_message("[user] extracts [removing] from [src] with [W]!") + else + user.visible_message("[user] fishes around fruitlessly in [src] with [W].") + return + ..() + + +/** + * Get a list of contents of this organ and all the child organs + */ +/obj/item/organ/external/proc/get_contents_recursive() + var/list/all_items = list() + + all_items.Add(implants) + all_items.Add(internal_organs) + + for(var/obj/item/organ/external/child in children) + all_items.Add(child.get_contents_recursive()) + + return all_items + +/obj/item/organ/external/proc/is_dislocated() + if(dislocated > 0) + return 1 + if(is_parent_dislocated()) + return 1//if any parent is dislocated, we are considered dislocated as well + return 0 + +/obj/item/organ/external/proc/is_parent_dislocated() + var/obj/item/organ/external/O = parent + while(O && O.dislocated != -1) + if(O.dislocated == 1) + return 1 + O = O.parent + return 0 + + +/obj/item/organ/external/proc/dislocate() + if(dislocated == -1) + return + + dislocated = 1 + if(owner) + owner.verbs |= /mob/living/carbon/human/proc/undislocate + +/obj/item/organ/external/proc/undislocate() + if(dislocated == -1) + return + + dislocated = 0 + if(owner) + owner.shock_stage += 20 + + //check to see if we still need the verb + for(var/obj/item/organ/external/limb in owner.organs) + if(limb.dislocated == 1) + return + owner.verbs -= /mob/living/carbon/human/proc/undislocate + +/obj/item/organ/external/update_health() + damage = min(max_damage, (brute_dam + burn_dam)) + return + + +/obj/item/organ/external/replaced(var/mob/living/carbon/human/target) + ..() + + if(istype(owner)) + owner.organs_by_name[organ_tag] = src + owner.organs |= src + + for(var/obj/item/organ/organ in internal_organs) + organ.replaced(owner, src) + + for(var/obj/implant in implants) + implant.forceMove(owner) + + if(istype(implant, /obj/item/weapon/implant)) + var/obj/item/weapon/implant/imp_device = implant + + // we can't use implanted() here since it's often interactive + imp_device.imp_in = owner + imp_device.implanted = 1 + + for(var/obj/item/organ/external/organ in children) + organ.replaced(owner) + + if(!parent && parent_organ) + parent = owner.organs_by_name[src.parent_organ] + if(parent) + if(!parent.children) + parent.children = list() + parent.children.Add(src) + //Remove all stump wounds since limb is not missing anymore + for(var/datum/wound/lost_limb/W in parent.wounds) + parent.wounds -= W + qdel(W) + break + parent.update_damages() + +//Helper proc used by various tools for repairing robot limbs +/obj/item/organ/external/proc/robo_repair(var/repair_amount, var/damage_type, var/damage_desc, obj/item/tool, mob/living/user) + if((src.robotic < ORGAN_ROBOT)) + return 0 + + var/damage_amount + switch(damage_type) + if(BRUTE) damage_amount = brute_dam + if(BURN) damage_amount = burn_dam + else return 0 + + if(!damage_amount) + if(src.hatch_state != HATCH_OPENED) + to_chat(user, "Nothing to fix!") + return 0 + + if(damage_amount >= ROBOLIMB_SELF_REPAIR_CAP) + to_chat(user, "The damage is far too severe to patch over externally.") + return 0 + + if(user == src.owner) + var/grasp + if(user.l_hand == tool && (src.body_part & (ARM_LEFT|HAND_LEFT))) + grasp = BP_L_HAND + else if(user.r_hand == tool && (src.body_part & (ARM_RIGHT|HAND_RIGHT))) + grasp = BP_R_HAND + + if(grasp) + to_chat(user, "You can't reach your [src.name] while holding [tool] in your [owner.get_bodypart_name(grasp)].") + return 0 + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(!do_mob(user, owner, 10)) + to_chat(user, "You must stand still to do that.") + return 0 + + switch(damage_type) + if(BRUTE) src.heal_damage(repair_amount, 0, 0, 1) + if(BURN) src.heal_damage(0, repair_amount, 0, 1) + if(user == src.owner) + user.visible_message("\The [user] patches [damage_desc] on \his [src.name] with [tool].") + else + user.visible_message("\The [user] patches [damage_desc] on [owner]'s [src.name] with [tool].") + + return 1 + + +/* +This function completely restores a damaged organ to perfect condition. +*/ +/obj/item/organ/external/rejuvenate(var/ignore_prosthetic_prefs) + damage_state = "00" + + status = 0 + brute_dam = 0 + burn_dam = 0 + germ_level = 0 + pain = 0 + genetic_degradation = 0 + for(var/datum/wound/wound in wounds) + wound.embedded_objects.Cut() + wounds.Cut() + number_wounds = 0 + + // handle internal organs + for(var/obj/item/organ/current_organ in internal_organs) + current_organ.rejuvenate(ignore_prosthetic_prefs) + + // remove embedded objects and drop them on the floor + for(var/obj/implanted_object in implants) + if(!istype(implanted_object,/obj/item/weapon/implant)) // We don't want to remove REAL implants. Just shrapnel etc. + implanted_object.loc = get_turf(src) + implants -= implanted_object + + if(owner && !ignore_prosthetic_prefs) + if(owner.client && owner.client.prefs && owner.client.prefs.real_name == owner.real_name) + var/status = owner.client.prefs.organ_data[organ_tag] + if(status == "amputated") + remove_rejuv() + else if(status == "cyborg") + var/robodata = owner.client.prefs.rlimb_data[organ_tag] + if(robodata) + robotize(robodata) + else + robotize() + owner.updatehealth() + +/obj/item/organ/external/remove_rejuv() + if(owner) + owner.organs -= src + owner.organs_by_name[organ_tag] = null + owner.organs_by_name -= organ_tag + while(null in owner.organs) owner.organs -= null + if(children && children.len) + for(var/obj/item/organ/external/E in children) + E.remove_rejuv() + children.Cut() + for(var/obj/item/organ/internal/I in internal_organs) + I.remove_rejuv() + ..() + +/obj/item/organ/external/proc/createwound(var/type = CUT, var/damage, var/surgical) + + if(damage == 0) + return + + //moved these before the open_wound check so that having many small wounds for example doesn't somehow protect you from taking internal damage (because of the return) + //Brute damage can possibly trigger an internal wound, too. + var/local_damage = brute_dam + burn_dam + damage + if(!surgical && (type in list(CUT, PIERCE, BRUISE)) && damage > 15 && local_damage > 30) + + var/internal_damage + if(prob(damage) && sever_artery()) + internal_damage = TRUE + if(prob(ceil(damage/4)) && sever_tendon()) + internal_damage = TRUE + if(internal_damage) + owner.custom_pain("You feel something rip in your [name]!", 50, affecting = src) + + //Burn damage can cause fluid loss due to blistering and cook-off + if((type in list(BURN, LASER)) && (damage > 5 || damage + burn_dam >= 15) && (robotic < ORGAN_ROBOT)) + var/fluid_loss_severity + switch(type) + if(BURN) fluid_loss_severity = FLUIDLOSS_WIDE_BURN + if(LASER) fluid_loss_severity = FLUIDLOSS_CONC_BURN + var/fluid_loss = (damage/(owner.maxHealth - config.health_threshold_dead)) * owner.species.blood_volume * fluid_loss_severity + owner.remove_blood(fluid_loss) + + // first check whether we can widen an existing wound + if(!surgical && wounds && wounds.len > 0 && prob(max(50+(number_wounds-1)*10,90))) + if((type == CUT || type == BRUISE) && damage >= 5) + //we need to make sure that the wound we are going to worsen is compatible with the type of damage... + var/list/compatible_wounds = list() + for (var/datum/wound/W in wounds) + if (W.can_worsen(type, damage)) + compatible_wounds += W + + if(compatible_wounds.len) + var/datum/wound/W = pick(compatible_wounds) + W.open_wound(damage) + return W + /*//This is obnoxious chat spam. + if(prob(25)) + if(robotic >= ORGAN_ROBOT) + owner.visible_message("The damage to [owner.name]'s [name] worsens.",\ + "The damage to your [name] worsens.",\ + "You hear the screech of abused metal.") + else + owner.visible_message("The wound on [owner.name]'s [name] widens with a nasty ripping noise.",\ + "The wound on your [name] widens with a nasty ripping noise.",\ + "You hear a nasty ripping noise, as if flesh is being torn apart.") + */ + + + //Creating wound + var/wound_type = get_wound_type(type, damage) + + if(wound_type) + var/datum/wound/W = new wound_type(damage) + + //Check whether we can add the wound to an existing wound + if(surgical) + W.autoheal_cutoff = 0 + else + for(var/datum/wound/other in wounds) + if(other.can_merge(W)) + other.merge_wound(W) + return + wounds += W + return W + +/**************************************************** + PROCESSING & UPDATING +****************************************************/ + +//external organs handle brokenness a bit differently when it comes to damage. +/obj/item/organ/external/is_broken() + return ((status & ORGAN_CUT_AWAY) || ((status & ORGAN_BROKEN) && !splinted)) + +//Determines if we even need to process this organ. +/obj/item/organ/external/proc/need_process() + if(get_pain()) + return 1 + if(status & (ORGAN_CUT_AWAY|ORGAN_BLEEDING|ORGAN_BROKEN|ORGAN_DEAD|ORGAN_MUTATED)) + return 1 + if((brute_dam || burn_dam) && (robotic < ORGAN_ROBOT)) //Robot limbs don't autoheal and thus don't need to process when damaged + return 1 + if(last_dam != brute_dam + burn_dam) // Process when we are fully healed up. + last_dam = brute_dam + burn_dam + return 1 + else + last_dam = brute_dam + burn_dam + if(germ_level) + return 1 + return 0 + +/obj/item/organ/external/Process() + if(owner) + + if(pain) + pain -= owner.lying ? 3 : 1 + if(pain<0) + pain = 0 + + // Process wounds, doing healing etc. Only do this every few ticks to save processing power + if(owner.life_tick % wound_update_accuracy == 0) + update_wounds() + + //Infections + update_germs() + else + pain = 0 + ..() + +//Updating germ levels. Handles organ germ levels and necrosis. +/* +The INFECTION_LEVEL values defined in setup.dm control the time it takes to reach the different +infection levels. Since infection growth is exponential, you can adjust the time it takes to get +from one germ_level to another using the rough formula: + +desired_germ_level = initial_germ_level*e^(desired_time_in_seconds/1000) + +So if I wanted it to take an average of 15 minutes to get from level one (100) to level two +I would set INFECTION_LEVEL_TWO to 100*e^(15*60/1000) = 245. Note that this is the average time, +the actual time is dependent on RNG. + +INFECTION_LEVEL_ONE below this germ level nothing happens, and the infection doesn't grow +INFECTION_LEVEL_TWO above this germ level the infection will start to spread to internal and adjacent organs +INFECTION_LEVEL_THREE above this germ level the player will take additional toxin damage per second, and will die in minutes without + antitox. also, above this germ level you will need to overdose on spaceacillin to reduce the germ_level. + +Note that amputating the affected organ does in fact remove the infection from the player's body. +*/ +/obj/item/organ/external/proc/update_germs() + + if(robotic >= ORGAN_ROBOT || (owner.species && owner.species.species_flags & SPECIES_FLAG_IS_PLANT)) //Robotic limbs shouldn't be infected, nor should nonexistant limbs. + germ_level = 0 + return + + if(owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs + //** Syncing germ levels with external wounds + handle_germ_sync() + + //** Handle antibiotics and curing infections + handle_antibiotics() + + //** Handle the effects of infections + handle_germ_effects() + +/obj/item/organ/external/proc/handle_germ_sync() + var/antibiotics = owner.reagents.get_reagent_amount(/datum/reagent/spaceacillin) + for(var/datum/wound/W in wounds) + //Open wounds can become infected + if (owner.germ_level > W.germ_level && W.infection_check()) + W.germ_level++ + + if (antibiotics < 5) + for(var/datum/wound/W in wounds) + //Infected wounds raise the organ's germ level + if (W.germ_level > germ_level) + germ_level++ + break //limit increase to a maximum of one per second + +/obj/item/organ/external/handle_germ_effects() + + if(germ_level < INFECTION_LEVEL_TWO) + return ..() + + var/antibiotics = owner.reagents.get_reagent_amount(/datum/reagent/spaceacillin) + + if(germ_level >= INFECTION_LEVEL_TWO) + //spread the infection to internal organs + var/obj/item/organ/target_organ = null //make internal organs become infected one at a time instead of all at once + for (var/obj/item/organ/I in internal_organs) + if (I.germ_level > 0 && I.germ_level < min(germ_level, INFECTION_LEVEL_TWO)) //once the organ reaches whatever we can give it, or level two, switch to a different one + if (!target_organ || I.germ_level > target_organ.germ_level) //choose the organ with the highest germ_level + target_organ = I + + if (!target_organ) + //figure out which organs we can spread germs to and pick one at random + var/list/candidate_organs = list() + for (var/obj/item/organ/I in internal_organs) + if (I.germ_level < germ_level) + candidate_organs |= I + if (candidate_organs.len) + target_organ = pick(candidate_organs) + + if (target_organ) + target_organ.germ_level++ + + //spread the infection to child and parent organs + if (children) + for (var/obj/item/organ/external/child in children) + if (child.germ_level < germ_level && (child.robotic < ORGAN_ROBOT)) + if (child.germ_level < INFECTION_LEVEL_ONE*2 || prob(30)) + child.germ_level++ + + if (parent) + if (parent.germ_level < germ_level && (parent.robotic < ORGAN_ROBOT)) + if (parent.germ_level < INFECTION_LEVEL_ONE*2 || prob(30)) + parent.germ_level++ + + if(germ_level >= INFECTION_LEVEL_THREE && antibiotics < 30) //overdosing is necessary to stop severe infections + if (!(status & ORGAN_DEAD)) + status |= ORGAN_DEAD + to_chat(owner, "You can't feel your [name] anymore...") + owner.update_body(1) + + germ_level++ + owner.adjustToxLoss(1) + +//Updating wounds. Handles wound natural I had some free spachealing, internal bleedings and infections +/obj/item/organ/external/proc/update_wounds() + + if((robotic >= ORGAN_ROBOT)) //Robotic limbs don't heal or get worse. + for(var/datum/wound/W in wounds) //Repaired wounds disappear though + if(W.damage <= 0) //and they disappear right away + wounds -= W //TODO: robot wounds for robot limbs + return + + for(var/datum/wound/W in wounds) + // wounds can disappear after 10 minutes at the earliest + if(W.damage <= 0 && W.created + (10 MINUTES) <= world.time) + wounds -= W + continue + // let the GC handle the deletion of the wound + + // slow healing + var/heal_amt = 0 + // if damage >= 50 AFTER treatment then it's probably too severe to heal within the timeframe of a round. + if (!owner.chem_effects[CE_TOXIN] && W.can_autoheal() && W.wound_damage() && brute_ratio < 0.5 && burn_ratio < 0.5) + heal_amt += 0.5 + + //we only update wounds once in [wound_update_accuracy] ticks so have to emulate realtime + heal_amt = heal_amt * wound_update_accuracy + //configurable regen speed woo, no-regen hardcore or instaheal hugbox, choose your destiny + heal_amt = heal_amt * config.organ_regeneration_multiplier + // amount of healing is spread over all the wounds + heal_amt = heal_amt / (wounds.len + 1) + // making it look prettier on scanners + heal_amt = round(heal_amt,0.1) + var/dam_type = BRUTE + if(W.damage_type == BURN) + dam_type = BURN + if(owner.can_autoheal(dam_type)) + W.heal_damage(heal_amt) + + // Salving also helps against infection + if(W.germ_level > 0 && W.salved && prob(2)) + W.disinfected = 1 + W.germ_level = 0 + + // sync the organ's damage with its wounds + src.update_damages() + if (update_damstate()) + owner.UpdateDamageIcon(1) + +//Updates brute_damn and burn_damn from wound damages. Updates BLEEDING status. +/obj/item/organ/external/proc/update_damages() + number_wounds = 0 + brute_dam = 0 + burn_dam = 0 + status &= ~ORGAN_BLEEDING + var/clamped = 0 + + var/mob/living/carbon/human/H + if(istype(owner,/mob/living/carbon/human)) + H = owner + + //update damage counts + for(var/datum/wound/W in wounds) + if(W.damage_type == BURN) + burn_dam += W.damage + else + brute_dam += W.damage + + if(!(robotic >= ORGAN_ROBOT) && W.bleeding() && (H && H.should_have_organ(BP_HEART))) + W.bleed_timer-- + status |= ORGAN_BLEEDING + + clamped |= W.clamped + number_wounds += W.amount + + damage = brute_dam + burn_dam + update_damage_ratios() + +/obj/item/organ/external/proc/update_damage_ratios() + var/limb_loss_threshold = max_damage + brute_ratio = brute_dam / (limb_loss_threshold * 2) + burn_ratio = burn_dam / (limb_loss_threshold * 2) + +//Returns 1 if damage_state changed +/obj/item/organ/external/proc/update_damstate() + var/n_is = damage_state_text() + if (n_is != damage_state) + damage_state = n_is + return 1 + return 0 + +// new damage icon system +// returns just the brute/burn damage code +/obj/item/organ/external/proc/damage_state_text() + + var/tburn = 0 + var/tbrute = 0 + + if(burn_dam ==0) + tburn =0 + else if (burn_dam < (max_damage * 0.25 / 2)) + tburn = 1 + else if (burn_dam < (max_damage * 0.75 / 2)) + tburn = 2 + else + tburn = 3 + + if (brute_dam == 0) + tbrute = 0 + else if (brute_dam < (max_damage * 0.25 / 2)) + tbrute = 1 + else if (brute_dam < (max_damage * 0.75 / 2)) + tbrute = 2 + else + tbrute = 3 + return "[tbrute][tburn]" + +/**************************************************** + DISMEMBERMENT +****************************************************/ + +//Handles dismemberment +/obj/item/organ/external/proc/droplimb(var/clean, var/disintegrate = DROPLIMB_EDGE, var/ignore_children, var/silent) + + if(cannot_amputate || !owner) + return + + owner.unlock_achievement(new/datum/achievement/lose_limb())//Get an achievement for losing your limb! + + owner.Stun(1)//Makes them drop what they're holding. + + if(disintegrate == DROPLIMB_EDGE && nonsolid) + disintegrate = DROPLIMB_BLUNT //splut + + switch(disintegrate) + if(DROPLIMB_EDGE) + var/severed_sound = pick('sound/effects/gore/chop2.ogg', 'sound/effects/gore/chop3.ogg', 'sound/effects/gore/chop4.ogg') + if(!clean) + var/gore_sound = "[(robotic >= ORGAN_ROBOT) ? "tortured metal" : "ripping tendons and flesh"]" + owner.visible_message( + "\The [owner]'s [src.name] flies off in a bloody arc!",\ + "Your [src.name] goes flying off!",\ + "You hear a terrible sound of [gore_sound].") + playsound(owner, severed_sound, 100, 0) + + else + playsound(owner, 'sound/effects/gore/severed.ogg', 100, 0) + + if(owner.can_feel_pain() && prob(50)) + owner.agony_scream() + + if(DROPLIMB_BURN) + var/gore = "[(robotic >= ORGAN_ROBOT) ? "": " of burning flesh"]" + owner.visible_message( + "\The [owner]'s [src.name] flashes away into ashes!",\ + "Your [src.name] flashes away into ashes!<",\ + "You hear a crackling sound[gore].") + if(owner.can_feel_pain() && prob(50)) + owner.agony_scream() + + if(DROPLIMB_BLUNT) + if(!gibbable) + return + var/gore = "[(robotic >= ORGAN_ROBOT) ? "": " in shower of gore"]" + var/gore_sound = "[(robotic >= ORGAN_ROBOT) ? "rending sound of tortured metal" : "sickening splatter of gore"]" + owner.visible_message( + "\The [owner]'s [src.name] explodes[gore]!",\ + "Your [src.name] explodes[gore]!",\ + "You hear the [gore_sound].") + playsound(owner, 'sound/effects/gore/chop6.ogg', 100 , 0)//Splat. + + if(owner.can_feel_pain() && prob(50)) + owner.agony_scream() + + var/mob/living/carbon/human/victim = owner //Keep a reference for post-removed(). + var/obj/item/organ/external/parent_organ = parent + + var/use_flesh_colour = species.get_flesh_colour(owner) + var/use_blood_colour = species.get_blood_colour(owner) + + removed(null, ignore_children) + add_pain(100) + if(!clean) + victim.shock_stage += min_broken_damage + + if(parent_organ) + var/datum/wound/lost_limb/W = new (src, disintegrate, clean) + if(clean) + parent_organ.wounds |= W + parent_organ.update_damages() + else + var/obj/item/organ/external/stump/stump = new (victim, 0, src) + stump.SetName("stump of \a [name]") + stump.artery_name = "mangled [artery_name]" + stump.arterial_bleed_severity = arterial_bleed_severity + stump.add_pain(max_damage) + if(robotic >= ORGAN_ROBOT) + stump.robotize() + stump.wounds |= W + victim.organs |= stump + if(disintegrate != DROPLIMB_BURN) + stump.sever_artery() + stump.update_damages() + spawn(1) + victim.updatehealth() + victim.UpdateDamageIcon() + victim.regenerate_icons() + dir = 2 + + switch(disintegrate) + if(DROPLIMB_EDGE) + compile_icon() + add_blood(victim) + var/matrix/M = matrix() + M.Turn(rand(180)) + src.transform = M + forceMove(get_turf(src)) + if(!clean) + // Throw limb around. + if(src && istype(loc,/turf)) + throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),30) + var/turf/T = src.loc + T.add_blood(victim) + dir = 2 + if(DROPLIMB_BURN) + new /obj/effect/decal/cleanable/ash(get_turf(victim)) + for(var/obj/item/I in src) + if(I.w_class > ITEM_SIZE_SMALL && !istype(I,/obj/item/organ)) + I.loc = get_turf(src) + qdel(src) + if(DROPLIMB_BLUNT) + var/obj/effect/decal/cleanable/blood/gibs/gore + if(robotic >= ORGAN_ROBOT) + gore = new /obj/effect/decal/cleanable/blood/gibs/robot(get_turf(victim)) + else + gore = new /obj/effect/decal/cleanable/blood/gibs(get_turf(victim)) + if(species) + gore.fleshcolor = use_flesh_colour + gore.basecolor = use_blood_colour + gore.update_icon() + + gore.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),30) + + for(var/obj/item/organ/I in internal_organs) + I.removed() + if(istype(loc,/turf)) + I.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),30) + + for(var/obj/item/I in src) + I.loc = get_turf(src) + I.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),30) + + qdel(src) + + +/**************************************************** + HELPERS +****************************************************/ + +/obj/item/organ/external/proc/is_stump() + return 0 + +/obj/item/organ/external/proc/release_restraints(var/mob/living/carbon/human/holder) + if(!holder) + holder = owner + if(!holder) + return + if (holder.handcuffed && body_part in list(ARM_LEFT, ARM_RIGHT, HAND_LEFT, HAND_RIGHT)) + holder.visible_message(\ + "\The [holder.handcuffed.name] falls off of [holder.name].",\ + "\The [holder.handcuffed.name] falls off you.") + holder.drop_from_inventory(holder.handcuffed) + +// 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.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.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.disinfected) + return 0 + return 1 + +/obj/item/organ/external/proc/bandage() + var/rval = 0 + status &= ~ORGAN_BLEEDING + for(var/datum/wound/W in wounds) + rval |= !W.bandaged + W.bandaged = 1 + if(rval) + owner.update_surgery() + 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) + rval |= !W.disinfected + W.disinfected = 1 + W.germ_level = 0 + return rval + +/obj/item/organ/external/proc/clamp_wound() + var/rval = 0 + src.status &= ~ORGAN_BLEEDING + for(var/datum/wound/W in wounds) + rval |= !W.clamped + W.clamped = 1 + return rval + +/obj/item/organ/external/proc/clamped() + for(var/datum/wound/W in wounds) + if(W.clamped) + return 1 + +/obj/item/organ/external/proc/fracture() + //if(!config.bones_can_break) //Why the fuck was this ever a config? + // return + if(robotic >= ORGAN_ROBOT) + return //ORGAN_BROKEN doesn't have the same meaning for robot limbs + if((status & ORGAN_BROKEN) || cannot_break) + return + + if(owner) + owner.visible_message(\ + "[owner]'s [name] shatters!",\ + "Something feels like it shattered in your [name]!",\ + "You hear a sickening crack.") + jostle_bone() + if(can_feel_pain()) + if(prob(50)) + owner.agony_scream() + if(break_sound) + playsound(owner, break_sound, 100, 0) + status |= ORGAN_BROKEN + broken_description = "shattered"//,"fracture","hairline fracture") + + // Fractures have a chance of getting you out of restraints + if (prob(25)) + release_restraints() + +/obj/item/organ/external/proc/mend_fracture() + if(robotic >= ORGAN_ROBOT) + return 0 //ORGAN_BROKEN doesn't have the same meaning for robot limbs + if(brute_dam > min_broken_damage * config.organ_health_multiplier) + return 0 //will just immediately fracture again + + status &= ~ORGAN_BROKEN + return 1 + +/obj/item/organ/external/proc/apply_splint(var/atom/movable/splint) + if(!splinted) + splinted = splint + if(!applied_pressure) + applied_pressure = splint + return 1 + return 0 + +/obj/item/organ/external/proc/remove_splint() + if(splinted) + if(splinted.loc == src) + splinted.dropInto(owner? owner.loc : src.loc) + if(applied_pressure == splinted) + applied_pressure = null + splinted = null + return 1 + return 0 + +/obj/item/organ/external/robotize(var/company, var/skip_prosthetics = 0, var/keep_organs = 0) + + if(robotic >= ORGAN_ROBOT) + return + + ..() + + if(company) + var/datum/robolimb/R = all_robolimbs[company] + if(!R || (species && (species.name in R.species_cannot_use)) || \ + (R.restricted_to.len && !(species.name in R.restricted_to)) || \ + (R.applies_to_part.len && !(organ_tag in R.applies_to_part))) + R = basic_robolimb + else + model = company + force_icon = R.icon + name = "robotic [initial(name)]" + desc = "[R.desc] It looks like it was produced by [R.company]." + + dislocated = -1 + remove_splint() + update_icon(1) + unmutate() + + for(var/obj/item/organ/external/T in children) + T.robotize(company, 1) + + if(owner) + + if(!skip_prosthetics) + owner.full_prosthetic = null // Will be rechecked next isSynthetic() call. + + if(!keep_organs) + for(var/obj/item/organ/thing in internal_organs) + if(istype(thing)) + if(thing.vital || thing.robotic >= ORGAN_ROBOT) + continue + internal_organs -= thing + owner.internal_organs_by_name[thing.organ_tag] = null + owner.internal_organs_by_name -= thing.organ_tag + owner.internal_organs.Remove(thing) + qdel(thing) + + while(null in owner.internal_organs) + owner.internal_organs -= null + + return 1 + +/obj/item/organ/external/proc/get_damage() //returns total damage + return (brute_dam+burn_dam) //could use max_damage? + +/obj/item/organ/external/proc/has_infected_wound() + for(var/datum/wound/W in wounds) + if(W.germ_level > INFECTION_LEVEL_ONE) + return 1 + return 0 + +/obj/item/organ/external/is_usable() + return ..() && !(status & ORGAN_TENDON_CUT) && (!can_feel_pain() || get_pain() < pain_disability_threshold) && brute_ratio < 1 && burn_ratio < 1 + +/obj/item/organ/external/proc/is_malfunctioning() + return ((robotic >= 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, var/datum/wound/supplied_wound) + if(!owner || loc != owner) + return + if(species.species_flags & SPECIES_FLAG_NO_EMBED) + return + + if(!silent) + /* + if(supplied_message) + owner.visible_message("[supplied_message]") + else + owner.visible_message("\The [W] sticks in the wound!") + */ + playsound(owner, "stab_sound", 100, 0) + + if(!supplied_wound) + for(var/datum/wound/wound in wounds) + if((wound.damage_type == CUT || wound.damage_type == PIERCE) && wound.damage >= W.w_class * 5) + supplied_wound = wound + break + if(!supplied_wound) + supplied_wound = createwound(PIERCE, W.w_class * 5) + + if(!supplied_wound || (W in supplied_wound.embedded_objects)) // Just in case. + return + + supplied_wound.embedded_objects += W + implants += W + owner.embedded_flag = 1 + owner.verbs += /mob/proc/yank_out_object + W.add_blood(owner) + if(ismob(W.loc)) + var/mob/living/H = W.loc + H.drop_from_inventory(W) + W.loc = owner + +/obj/item/organ/external/removed(var/mob/living/user, var/ignore_children = 0) + + if(!owner) + return + var/is_robotic = robotic >= ORGAN_ROBOT + var/mob/living/carbon/human/victim = owner + + ..() + + victim.bad_external_organs -= src + + remove_splint() + for(var/atom/movable/implant in implants) + //large items and non-item objs fall to the floor, everything else stays + var/obj/item/I = implant + if(istype(I) && I.w_class < ITEM_SIZE_NORMAL) + implant.forceMove(src) + + // let actual implants still inside know they're no longer implanted + if(istype(I, /obj/item/weapon/implant)) + var/obj/item/weapon/implant/imp_device = I + imp_device.removed(owner) + else + implants.Remove(implant) + implant.forceMove(get_turf(src)) + + // Attached organs also fly off. + if(!ignore_children) + for(var/obj/item/organ/external/O in children) + O.removed() + if(O) + O.forceMove(src) + + // if we didn't lose the organ we still want it as a child + children += O + O.parent = src + + // Grab all the internal giblets too. + for(var/obj/item/organ/organ in internal_organs) + organ.removed(user, 0, 0) // Organ stays inside and connected + organ.forceMove(src) + + // Remove parent references + if(parent) + parent.children -= src + parent = null + + release_restraints(victim) + victim.organs -= src + victim.organs_by_name[organ_tag] = null // Remove from owner's vars. + + //Robotic limbs explode if sabotaged. + if(is_robotic && sabotaged) + victim.visible_message( + "\The [victim]'s [src.name] explodes violently!",\ + "Your [src.name] explodes!",\ + "You hear an explosion!") + explosion(get_turf(owner),-1,-1,2,3) + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, victim) + spark_system.attach(owner) + spark_system.start() + spawn(10) + qdel(spark_system) + qdel(src) + +/obj/item/organ/external/proc/disfigure(var/type = "brute") + if (disfigured) + return + if(owner) + if(type == "brute") + owner.visible_message("\the [owner]'s [name] becomes a mangled mess!", \ + "Your [name] becomes a mangled mess!", \ + "You hear a sickening crack.") + else + owner.visible_message("\The [owner]'s [name] melts away, turning into mangled mess!", \ + "Your [name] melts away!", \ + "You hear a sickening sizzle.") + disfigured = 1 + +/obj/item/organ/external/proc/get_incision(var/strict) + var/datum/wound/cut/incision + for(var/datum/wound/cut/W in wounds) + if(W.bandaged || W.current_stage > W.max_bleeding_stage) // Shit's unusable + continue + if(strict && !W.is_surgical()) //We don't need dirty ones + continue + if(!incision) + incision = W + continue + var/same = W.is_surgical() == incision.is_surgical() + if(same) //If they're both dirty or both are surgical, just get bigger one + if(W.damage > incision.damage) + incision = W + else if(W.is_surgical()) //otherwise surgical one takes priority + incision = W + return incision + +/obj/item/organ/external/proc/open() + var/datum/wound/cut/incision = get_incision() + . = 0 + if(!incision) + return 0 + var/smol_threshold = min_broken_damage * 0.4 + var/beeg_threshold = min_broken_damage * 0.6 + if(!incision.autoheal_cutoff == 0) //not clean incision + smol_threshold *= 1.5 + beeg_threshold = max(beeg_threshold, min(beeg_threshold * 1.5, incision.damage_list[1])) //wounds can't achieve bigger + if(incision.damage >= smol_threshold) //smol incision + . = SURGERY_OPEN + if(incision.damage >= beeg_threshold) //beeg incision + . = SURGERY_RETRACTED + if(. == SURGERY_RETRACTED && encased && (status & ORGAN_BROKEN)) + . = SURGERY_ENCASED + +/obj/item/organ/external/proc/jostle_bone(force) + if(!(status & ORGAN_BROKEN)) //intact bones stay still + return + if(splinted)//Splinted bones won't jostle. + return + if(brute_dam + force < min_broken_damage/5) //no papercuts moving bones + return + if(internal_organs.len && prob(brute_dam + force)) + owner.custom_pain("A piece of bone in your [encased ? encased : name] moves painfully!", 50, affecting = src) + var/obj/item/organ/I = pick(internal_organs) + I.take_damage(rand(3,5)) + +/obj/item/organ/external/proc/get_wounds_desc() + if(robotic >= ORGAN_ROBOT) + var/list/descriptors = list() + if(brute_dam) + switch(brute_dam) + if(0 to 20) + descriptors += "some dents" + if(21 to INFINITY) + descriptors += pick("a lot of dents","severe denting") + if(burn_dam) + switch(burn_dam) + if(0 to 20) + descriptors += "some burns" + if(21 to INFINITY) + descriptors += pick("a lot of burns","severe melting") + switch(hatch_state) + if(HATCH_UNSCREWED) + descriptors += "a closed but unsecured panel" + if(HATCH_OPENED) + descriptors += "an open panel" + + return english_list(descriptors) + + var/list/flavor_text = list() + if((status & ORGAN_CUT_AWAY) && !is_stump() && !(parent && parent.status & ORGAN_CUT_AWAY)) + flavor_text += "a tear at the [amputation_point] so severe that it hangs by a scrap of flesh" + + var/list/wound_descriptors = list() + for(var/datum/wound/W in wounds) + var/this_wound_desc = W.desc + if(W.damage_type == BURN && W.salved) + this_wound_desc = "salved [this_wound_desc]" + + if(W.bleeding()) + if(W.wound_damage() > W.bleed_threshold) + this_wound_desc = "bleeding [this_wound_desc]" + else + this_wound_desc = "bleeding [this_wound_desc]" + else if(W.bandaged) + this_wound_desc = "bandaged [this_wound_desc]" + + if(W.germ_level > 600) + this_wound_desc = "badly infected [this_wound_desc]" + else if(W.germ_level > 330) + this_wound_desc = "lightly infected [this_wound_desc]" + + if(wound_descriptors[this_wound_desc]) + wound_descriptors[this_wound_desc] += W.amount + else + wound_descriptors[this_wound_desc] = W.amount + + if(open() >= (encased ? SURGERY_ENCASED : SURGERY_RETRACTED)) + var/list/bits = list() + if(status & ORGAN_BROKEN) + bits += "broken bones" + for(var/obj/item/organ/organ in internal_organs) + bits += "[organ.damage ? "damaged " : ""][organ.name]" + if(bits.len) + wound_descriptors["[english_list(bits)] visible in the wounds"] = 1 + + for(var/wound in wound_descriptors) + switch(wound_descriptors[wound]) + if(1) + flavor_text += "a [wound]" + if(2) + flavor_text += "a pair of [wound]s" + if(3 to 5) + flavor_text += "several [wound]s" + if(6 to INFINITY) + flavor_text += "a ton of [wound]\s" + + return english_list(flavor_text) + +/obj/item/organ/external/get_scan_results() + . = ..() + if(status & ORGAN_ARTERY_CUT) + . += "[capitalize(artery_name)] ruptured" + if(status & ORGAN_TENDON_CUT) + . += "Severed [tendon_name]" + if(dislocated == 2) // non-magical constants when + . += "Dislocated" + if(splinted) + . += "Splinted" + if(status & ORGAN_BLEEDING) + . += "Bleeding" + if(status & ORGAN_BROKEN) + . += capitalize(broken_description) + if (implants.len) + var/unknown_body = 0 + for(var/I in implants) + var/obj/item/weapon/implant/imp = I + if(istype(imp) && imp.known) + . += "[capitalize(imp.name)] implanted" + else if(!imp.truly_unknown) + unknown_body++ + if(unknown_body) + . += "Unknown body present" + +/obj/item/organ/external/proc/inspect(mob/user) + if(is_stump()) + to_chat(user, "[owner] is missing that bodypart.") + return + + user.visible_message("[user] starts inspecting [owner]'s [name] carefully.") + if(wounds.len) + to_chat(user, "You find [get_wounds_desc()]") + var/list/stuff = list() + for(var/datum/wound/wound in wounds) + if(wound.embedded_objects) + stuff += wound.embedded_objects + if(stuff.len) + to_chat(user, "There's [english_list(stuff)] sticking out of [owner]'s [name].") + else + to_chat(user, "You find no visible wounds.") + + to_chat(user, "Checking skin now...") + if(!do_mob(user, owner, 10)) + to_chat(user, "You must stand still to check [owner]'s skin for abnormalities.") + return + + var/list/badness = list() + if(owner.shock_stage >= 30) + badness += "clammy and cool to the touch" + if(owner.getToxLoss() >= 25) + badness += "jaundiced" + if(owner.get_blood_oxygenation() <= 50) + badness += "turning blue" + if(owner.get_blood_circulation() <= 60) + badness += "very pale" + if(status & ORGAN_DEAD) + badness += "rotting" + if(!badness.len) + to_chat(user, "[owner]'s skin is normal.") + else + to_chat(user, "[owner]'s skin is [english_list(badness)].") + + to_chat(user, "Checking bones now...") + if(!do_mob(user, owner, 10)) + to_chat(user, "You must stand still to feel [src] for fractures.") + return + + if(status & ORGAN_BROKEN) + to_chat(user, "The [encased ? encased : "bone in the [name]"] moves slightly when you poke it!") + owner.custom_pain("Your [name] hurts where it's poked.",40, affecting = src) + else + to_chat(user, "The [encased ? encased : "bones in the [name]"] seem to be fine.") + + if(status & ORGAN_TENDON_CUT) + to_chat(user, "The tendons in [name] are severed!") + if(dislocated == 2) + to_chat(user, "The [joint] is dislocated!") + return 1 + +/obj/item/organ/external/listen() + var/list/sounds = list() + for(var/obj/item/organ/internal/I in internal_organs) + var/gutsound = I.listen() + if(gutsound) + sounds += gutsound + if(!sounds.len) + if(owner.pulse()) + sounds += "faint pulse" + return sounds + +/obj/item/organ/external/proc/jointlock(mob/attacker) + if(!can_feel_pain()) + return + + var/armor = owner.run_armor_check(owner, "melee") + if(armor < 100) + to_chat(owner, "You feel extreme pain!") + + var/max_halloss = round(owner.species.total_health * 0.8 * ((100 - armor) / 100)) //up to 80% of passing out, further reduced by armour + add_pain(Clamp(0, max_halloss - owner.getHalLoss(), 30)) + +//Adds autopsy data for used_weapon. +/obj/item/organ/external/proc/add_autopsy_data(var/used_weapon, var/damage) + var/datum/autopsy_data/W = autopsy_data[used_weapon] + if(!W) + W = new() + W.weapon = used_weapon + autopsy_data[used_weapon] = W + + W.hits += 1 + W.damage += damage + W.time_inflicted = world.time + + +/obj/item/organ/external/proc/has_genitals() + return !isrobotic() && species && species.sexybits_location == organ_tag diff --git a/code/modules/organs/external/_external_damage.dm b/code/modules/organs/external/_external_damage.dm new file mode 100644 index 00000000..8578c23f --- /dev/null +++ b/code/modules/organs/external/_external_damage.dm @@ -0,0 +1,279 @@ +/**************************************************** + DAMAGE PROCS +****************************************************/ + +/obj/item/organ/external/proc/is_damageable(var/additional_damage = 0) + //Continued damage to vital organs can kill you, and robot organs don't count towards total damage so no need to cap them. + return ((robotic >= ORGAN_ROBOT) || brute_dam + burn_dam + additional_damage < max_damage * 4) + +/obj/item/organ/external/take_damage(brute, burn, damage_flags, used_weapon = null) + brute = round(brute * brute_mod, 0.1) + burn = round(burn * burn_mod, 0.1) + if((brute <= 0) && (burn <= 0)) + return 0 + + var/sharp = (damage_flags & DAM_SHARP) + var/edge = (damage_flags & DAM_EDGE) + var/laser = (damage_flags & DAM_LASER) + var/blunt = brute && !sharp && !edge + + if(used_weapon) + add_autopsy_data("[used_weapon]", brute + burn) + var/can_cut = (prob(brute*2) || sharp) && (robotic < ORGAN_ROBOT) + var/spillover = 0 + var/pure_brute = brute + if(!is_damageable(brute + burn)) + spillover = brute_dam + burn_dam + brute - max_damage + if(spillover > 0) + brute -= spillover + else + spillover = brute_dam + burn_dam + brute + burn - max_damage + if(spillover > 0) + burn -= spillover + + owner.updatehealth() //droplimb will call updatehealth() again if it does end up being called + //If limb took enough damage, try to cut or tear it off + if(owner && loc == owner && !is_stump()) + if(!cannot_amputate && config.limbs_can_break) + if((brute_dam + burn_dam + brute + burn + spillover) >= (max_damage * config.organ_health_multiplier)) + var/force_droplimb = 0 + if((brute_dam + burn_dam + brute + burn + spillover) >= (max_damage * config.organ_health_multiplier * 4)) + force_droplimb = 1 + //organs can come off in three cases + //1. If the damage source is edge_eligible and the brute damage dealt exceeds the edge threshold, then the organ is cut off. + //2. If the damage amount dealt exceeds the disintegrate threshold, the organ is completely obliterated. + //3. If the organ has already reached or would be put over it's max damage amount (currently redundant), + // and the brute damage dealt exceeds the tearoff threshold, the organ is torn off. + //Check edge eligibility + var/edge_eligible = 0 + if(edge) + if(istype(used_weapon,/obj/item)) + var/obj/item/W = used_weapon + if(W.w_class >= w_class) + edge_eligible = 1 + else + edge_eligible = 1 + brute = pure_brute + if(edge_eligible && brute >= max_damage / DROPLIMB_THRESHOLD_EDGE) + if(prob(brute) || force_droplimb) + droplimb(0, DROPLIMB_EDGE) + return + else if(burn >= max_damage / DROPLIMB_THRESHOLD_DESTROY) + if(prob(burn/3) || force_droplimb) + droplimb(0, DROPLIMB_BURN) + return + else if(brute >= max_damage / DROPLIMB_THRESHOLD_DESTROY) + if(prob(brute) || force_droplimb) + droplimb(0, DROPLIMB_BLUNT) + return + /* + else if(brute >= max_damage / DROPLIMB_THRESHOLD_TEAROFF) + if(prob(brute/3) || force_droplimb) + droplimb(0, DROPLIMB_BLUNT) + return + */ + else if(force_droplimb) + droplimb(0, DROPLIMB_BLUNT) + return + + // High brute damage or sharp objects may damage internal organs + var/damage_amt = brute + var/cur_damage = brute_dam + if(laser) + damage_amt += burn + cur_damage += burn_dam + if(internal_organs && internal_organs.len && (cur_damage + damage_amt >= max_damage || (((sharp && damage_amt >= 5) || damage_amt >= 10) && prob(5)))) + // Damage an internal organ + var/list/victims = list() + for(var/obj/item/organ/internal/I in internal_organs) + if(I.damage < I.max_damage && prob(I.relative_size)) + victims += I + if(!victims.len) + victims += pick(internal_organs) + for(var/obj/item/organ/victim in victims) + brute /= 2 + if(laser) + burn /= 2 + damage_amt /= 2 + victim.take_damage(damage_amt) + + if(status & ORGAN_BROKEN && brute) + jostle_bone(brute) + //if(can_feel_pain() && prob(40)) + // owner.emote("scream") //getting hit on broken hand hurts + + //If they aren't getting hit with a blunt object it shouldn't break their bones. If it's sharp enough to cut it off then it'll cut of it off, otherwise knives will shatter chests. + if(brute_dam > min_broken_damage && blunt)//prob(brute_dam + brute * (1+blunt)) ) //blunt damage is gud at fracturing + fracture() + + // If the limbs can break, make sure we don't exceed the maximum damage a limb can take before breaking + var/datum/wound/created_wound + var/block_cut = !(brute > 15 || !(species.species_flags & SPECIES_FLAG_NO_MINOR_CUT)) + + if(brute) + var/to_create = BRUISE + if(can_cut) + if(!block_cut) + to_create = CUT + //need to check sharp again here so that blunt damage that was strong enough to break skin doesn't give puncture wounds + if(sharp && !edge) + to_create = PIERCE + created_wound = createwound(to_create, brute) + + if(burn) + if(laser) + createwound(LASER, burn) + if(prob(40)) + owner.IgniteMob() + else + createwound(BURN, burn) + + add_pain(0.6*burn + 0.4*brute) + //If there are still hurties to dispense + if (spillover) + owner.shock_stage += spillover * config.organ_damage_spillover_multiplier + + // sync the organ's damage with its wounds + src.update_damages() + owner.updatehealth() + + if(status & ORGAN_BLEEDING) + owner.update_bandages() + + if(owner && update_damstate()) + owner.UpdateDamageIcon() + + return created_wound + +/obj/item/organ/external/heal_damage(brute, burn, internal = 0, robo_repair = 0) + if(robotic >= ORGAN_ROBOT && !robo_repair) + return + + //Heal damage on the individual wounds + for(var/datum/wound/W in wounds) + if(brute == 0 && burn == 0) + break + + // heal brute damage + if(W.damage_type == BURN && (burn_ratio < 1 || vital)) + burn = W.heal_damage(burn) + else if(brute_ratio < 1 || vital) + brute = W.heal_damage(brute) + + if(internal) + status &= ~ORGAN_BROKEN + + //Sync the organ's damage with its wounds + src.update_damages() + owner.updatehealth() + + return update_damstate() + +// Brute/burn +/obj/item/organ/external/proc/get_brute_damage() + return brute_dam + +/obj/item/organ/external/proc/get_burn_damage() + return burn_dam + +// Geneloss/cloneloss. +/obj/item/organ/external/proc/get_genetic_damage() + return ((species && (species.species_flags & SPECIES_FLAG_NO_SCAN)) || robotic >= ORGAN_ROBOT) ? 0 : genetic_degradation + +/obj/item/organ/external/proc/remove_genetic_damage(var/amount) + if((species.species_flags & SPECIES_FLAG_NO_SCAN) || robotic >= ORGAN_ROBOT) + genetic_degradation = 0 + status &= ~ORGAN_MUTATED + return + var/last_gene_dam = genetic_degradation + genetic_degradation = min(100,max(0,genetic_degradation - amount)) + if(genetic_degradation <= 30) + if(status & ORGAN_MUTATED) + unmutate() + to_chat(src, "Your [name] is shaped normally again.") + return -(genetic_degradation - last_gene_dam) + +/obj/item/organ/external/proc/add_genetic_damage(var/amount) + if((species.species_flags & SPECIES_FLAG_NO_SCAN) || robotic >= ORGAN_ROBOT) + genetic_degradation = 0 + status &= ~ORGAN_MUTATED + return + var/last_gene_dam = genetic_degradation + genetic_degradation = min(100,max(0,genetic_degradation + amount)) + if(genetic_degradation > 30) + if(!(status & ORGAN_MUTATED) && prob(genetic_degradation)) + mutate() + to_chat(owner, "Something is not right with your [name]...") + return (genetic_degradation - last_gene_dam) + +/obj/item/organ/external/proc/mutate() + if(src.robotic >= ORGAN_ROBOT) + return + src.status |= ORGAN_MUTATED + if(owner) owner.update_body() + +/obj/item/organ/external/proc/unmutate() + src.status &= ~ORGAN_MUTATED + if(owner) owner.update_body() + +// Pain/halloss +/obj/item/organ/external/proc/get_pain() + if(!can_feel_pain() || robotic >= ORGAN_ROBOT) + return 0 + var/lasting_pain = 0 + if(is_broken()) + lasting_pain += 10 + else if(is_dislocated()) + lasting_pain += 5 + var/tox_dam = 0 + for(var/obj/item/organ/internal/I in internal_organs) + tox_dam += I.getToxLoss() + return pain + lasting_pain + 0.7 * brute_dam + 0.8 * burn_dam + 0.3 * tox_dam + 0.5 * get_genetic_damage() + +/obj/item/organ/external/proc/remove_pain(var/amount) + if(!can_feel_pain() || robotic >= ORGAN_ROBOT) + pain = 0 + return + var/last_pain = pain + pain = max(0,min(max_damage,pain-amount)) + return -(pain-last_pain) + +/obj/item/organ/external/proc/add_pain(var/amount) + if(!can_feel_pain() || robotic >= ORGAN_ROBOT) + pain = 0 + return + var/last_pain = pain + pain = max(0,min(max_damage,pain+amount)) + if(owner && ((amount > 15 && prob(20)) || (amount > 30 && prob(60)))) + owner.agony_scream() + return pain-last_pain + +/obj/item/organ/external/proc/stun_act(var/stun_amount, var/agony_amount) + if(agony_amount > 5 && owner && vital && get_pain() > 0.5 * max_damage) + owner.visible_message("[owner] reels in pain!") + if(has_genitals() || get_pain() + agony_amount > max_damage) + owner.Weaken(6) + else + owner.Stun(6) + owner.drop_l_hand() + owner.drop_r_hand() + return 1 + +/obj/item/organ/external/proc/get_agony_multiplier() + return has_genitals() ? 2 : 1 + +/obj/item/organ/external/proc/sever_artery() + if(species && species.has_organ[BP_HEART]) + var/obj/item/organ/internal/heart/O = species.has_organ[BP_HEART] + if(robotic < ORGAN_ROBOT && !(status & ORGAN_ARTERY_CUT) && !initial(O.open)) + status |= ORGAN_ARTERY_CUT + if(artery_name == "carotid artery") + playsound(owner.loc, 'sound/voice/throat.ogg', 50, 1, -1) + return TRUE + return FALSE + +/obj/item/organ/external/proc/sever_tendon() + if(has_tendon && robotic < ORGAN_ROBOT && !(status & ORGAN_TENDON_CUT)) + status |= ORGAN_TENDON_CUT + return TRUE + return FALSE \ No newline at end of file diff --git a/code/modules/organs/external/_external_icons.dm b/code/modules/organs/external/_external_icons.dm new file mode 100644 index 00000000..d558ae6b --- /dev/null +++ b/code/modules/organs/external/_external_icons.dm @@ -0,0 +1,200 @@ +var/list/limb_icon_cache = list() + +/obj/item/organ/external/set_dir() + return + +/obj/item/organ/external/proc/compile_icon() + overlays.Cut() + // This is a kludge, only one icon has more than one generation of children though. + for(var/obj/item/organ/external/organ in contents) + if(organ.children && organ.children.len) + for(var/obj/item/organ/external/child in organ.children) + overlays += child.mob_icon + overlays += organ.mob_icon + +/obj/item/organ/external/proc/sync_colour_to_human(var/mob/living/carbon/human/human) + s_tone = null + s_col = null + s_base = "" + h_col = list(human.r_hair, human.g_hair, human.b_hair) + if(robotic >= ORGAN_ROBOT) + var/datum/robolimb/franchise = all_robolimbs[model] + if(!(franchise && franchise.skintone)) + return + if(species && human.species && species.name != human.species.name) + return + if(!isnull(human.s_tone) && (human.species.appearance_flags & HAS_A_SKIN_TONE)) + s_tone = human.s_tone + if(!isnull(human.s_base) && (human.species.appearance_flags & HAS_BASE_SKIN_COLOURS)) + s_base = human.s_base + if(human.species.appearance_flags & HAS_SKIN_COLOR) + s_col = list(human.r_skin, human.g_skin, human.b_skin) + +/obj/item/organ/external/proc/sync_colour_to_dna() + s_tone = null + s_col = null + s_base = dna.s_base + h_col = list(dna.GetUIValue(DNA_UI_HAIR_R),dna.GetUIValue(DNA_UI_HAIR_G),dna.GetUIValue(DNA_UI_HAIR_B)) + if(robotic >= ORGAN_ROBOT) + var/datum/robolimb/franchise = all_robolimbs[model] + if(!(franchise && franchise.skintone)) + return + if(!isnull(dna.GetUIValue(DNA_UI_SKIN_TONE)) && (species.appearance_flags & HAS_A_SKIN_TONE)) + s_tone = dna.GetUIValue(DNA_UI_SKIN_TONE) + if(species.appearance_flags & HAS_SKIN_COLOR) + s_col = list(dna.GetUIValue(DNA_UI_SKIN_R), dna.GetUIValue(DNA_UI_SKIN_G), dna.GetUIValue(DNA_UI_SKIN_B)) + +/obj/item/organ/external/head/sync_colour_to_human(var/mob/living/carbon/human/human) + ..() + var/obj/item/organ/internal/eyes/eyes = owner.internal_organs_by_name[BP_EYES] + if(eyes) eyes.update_colour() + +/obj/item/organ/external/head/removed() + update_icon(1) + ..() + + //Head markings, duplicated (sadly) below. + for(var/M in markings) + var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"] + var/icon/mark_s = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[organ_tag]") + mark_s.Blend(markings[M]["color"], mark_style.blend) + overlays |= mark_s //So when it's not on your body, it has icons + mob_icon.Blend(mark_s, mark_style.layer_blend) //So when it's on your body, it has icons + icon_cache_key += "[M][markings[M]["color"]]" + +/obj/item/organ/external/var/icon_cache_key +/obj/item/organ/external/update_icon(var/regenerate = 0) + var/gender = "_m" + if(!gendered_icon) + gender = null + else if (dna && dna.GetUIState(DNA_UI_GENDER)) + gender = "_f" + else if(owner && owner.gender == FEMALE) + gender = "_f" + + icon_state = "[icon_name][gender]" + if(species.base_skin_colours && !isnull(species.base_skin_colours[s_base])) + icon_state += species.base_skin_colours[s_base] + + icon_cache_key = "[icon_state]_[species ? species.name : SPECIES_HUMAN]" + + if(force_icon) + icon = force_icon + else if (!dna) + icon = 'icons/mob/human_races/r_human.dmi' + else if (robotic >= ORGAN_ROBOT) + icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi' + else if (status & ORGAN_MUTATED) + icon = species.deform + else if (owner && (SKELETON in owner.mutations)) + icon = 'icons/mob/human_races/r_skeleton.dmi' + else + icon = species.get_icobase(owner) + + mob_icon = apply_colouration(new/icon(icon, icon_state)) + + //Body markings, does not include head, duplicated (sadly) above. + for(var/M in markings) + var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"] + var/icon/mark_s = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[organ_tag]") + mark_s.Blend(markings[M]["color"], ICON_ADD) + overlays |= mark_s //So when it's not on your body, it has icons + mob_icon.Blend(mark_s, ICON_OVERLAY) //So when it's on your body, it has icons + icon_cache_key += "[M][markings[M]["color"]]" + + if(body_hair && islist(h_col) && h_col.len >= 3) + var/cache_key = "[body_hair]-[icon_name]-[h_col[1]][h_col[2]][h_col[3]]" + if(!limb_icon_cache[cache_key]) + var/icon/I = icon(species.get_icobase(owner), "[icon_name]_[body_hair]") + I.Blend(rgb(h_col[1],h_col[2],h_col[3]), ICON_ADD) + limb_icon_cache[cache_key] = I + mob_icon.Blend(limb_icon_cache[cache_key], ICON_OVERLAY) + + if(model) + icon_cache_key += "_model_[model]" + dir = EAST + icon = mob_icon + +/obj/item/organ/external/proc/get_icon() + update_icon() + return mob_icon + +// Returns an image for use by the human health dolly HUD element. +// If the limb is in pain, it will be used as a minimum damage +// amount to represent the obfuscation of being in agonizing pain. + +// Global scope, used in code below. +var/list/flesh_hud_colours = list("#00ff00","#aaff00","#ffff00","#ffaa00","#ff0000","#aa0000","#660000") +var/list/robot_hud_colours = list("#ffffff","#cccccc","#aaaaaa","#888888","#666666","#444444","#222222","#000000") + +/obj/item/organ/external/proc/get_damage_hud_image() + + // Generate the greyscale base icon and cache it for later. + // icon_cache_key is set by any get_icon() calls that are made. + // This looks convoluted, but it's this way to avoid icon proc calls. + if(!hud_damage_image) + var/cache_key = "dambase-[icon_cache_key]" + if(!icon_cache_key || !limb_icon_cache[cache_key]) + limb_icon_cache[cache_key] = icon(get_icon(), null, SOUTH) + var/image/temp = image(limb_icon_cache[cache_key]) + if(species) + // Calculate the required colour matrix. + var/r = 0.30 * species.health_hud_intensity + var/g = 0.59 * species.health_hud_intensity + var/b = 0.11 * species.health_hud_intensity + temp.color = list(r, r, r, g, g, g, b, b, b) + hud_damage_image = image(null) + hud_damage_image.overlays += temp + + + // Calculate the required color index. + var/dam_state = min(1,((brute_dam+burn_dam)/max(1,max_damage))) + var/min_dam_state = min(1,(get_pain()/max(1,max_damage))) + if(min_dam_state && dam_state < min_dam_state) + dam_state = min_dam_state + // Apply colour and return product. + var/list/hud_colours = (robotic < ORGAN_ROBOT) ? flesh_hud_colours : robot_hud_colours + hud_damage_image.color = hud_colours[max(1,min(ceil(dam_state*hud_colours.len),hud_colours.len))] + return hud_damage_image + +/obj/item/organ/external/proc/apply_colouration(var/icon/applying) + + if(nonsolid) + applying.MapColors("#4d4d4d","#969696","#1c1c1c", "#000000") + if(species && species.get_bodytype(owner) != SPECIES_HUMAN) + applying.SetIntensity(1.5) + else + applying.SetIntensity(0.7) + applying += rgb(,,,180) // Makes the icon translucent, SO INTUITIVE TY BYOND + + else if(status & ORGAN_DEAD) + icon_cache_key += "_dead" + applying.ColorTone(rgb(10,50,0)) + applying.SetIntensity(0.7) + + if(s_tone) + if(s_tone >= 0) + applying.Blend(rgb(s_tone, s_tone, s_tone), ICON_ADD) + else + applying.Blend(rgb(-s_tone, -s_tone, -s_tone), ICON_SUBTRACT) + icon_cache_key += "_tone_[s_tone]" + if(species.appearance_flags & HAS_SKIN_COLOR) + if(s_col && s_col.len >= 3) + applying.Blend(rgb(s_col[1], s_col[2], s_col[3]), s_col_blend) + icon_cache_key += "_color_[s_col[1]]_[s_col[2]]_[s_col[3]]_[s_col_blend]" + + return applying + +/obj/item/organ/external/proc/bandage_level() + if(damage_state_text() == "00") + return 0 + if(!is_bandaged()) + return 0 + if(burn_dam + brute_dam == 0) + . = 0 + else if (burn_dam + brute_dam < (max_damage * 0.25 / 2)) + . = 1 + else if (burn_dam + brute_dam < (max_damage * 0.75 / 2)) + . = 2 + else + . = 3 \ No newline at end of file diff --git a/code/modules/organs/external/diona.dm b/code/modules/organs/external/diona.dm new file mode 100644 index 00000000..2d6692c1 --- /dev/null +++ b/code/modules/organs/external/diona.dm @@ -0,0 +1,260 @@ +/proc/spawn_diona_nymph(var/turf/target) + if(!istype(target)) + return 0 + + //This is a terrible hack and I should be ashamed. + var/datum/seed/diona = plant_controller.seeds["diona"] + if(!diona) + return 0 + + spawn(1) // So it has time to be thrown about by the gib() proc. + var/mob/living/carbon/alien/diona/D = new(target) + var/datum/ghosttrap/plant/P = get_ghost_trap("living plant") + P.request_player(D, "A diona nymph has split off from its gestalt. ") + spawn(60) + if(D) + if(!D.ckey || !D.client) + D.death() + return 1 + +/obj/item/organ/external/diona + name = "tendril" + cannot_break = 1 + amputation_point = "branch" + joint = "structural ligament" + dislocated = -1 + +/obj/item/organ/external/diona/chest + name = "core trunk" + organ_tag = BP_CHEST + icon_name = "torso" + max_damage = 200 + min_broken_damage = 50 + w_class = ITEM_SIZE_HUGE + body_part = UPPER_TORSO + vital = 1 + cannot_amputate = 1 + parent_organ = null + gendered_icon = 1 + +/obj/item/organ/external/diona/groin + name = "fork" + organ_tag = BP_GROIN + icon_name = "groin" + max_damage = 100 + min_broken_damage = 50 + w_class = ITEM_SIZE_LARGE + body_part = LOWER_TORSO + parent_organ = BP_CHEST + gendered_icon = 1 + +/obj/item/organ/external/diona/arm + name = "left upper tendril" + organ_tag = BP_L_ARM + icon_name = "l_arm" + max_damage = 35 + min_broken_damage = 20 + w_class = ITEM_SIZE_NORMAL + body_part = ARM_LEFT + parent_organ = BP_CHEST + can_grasp = 1 + +/obj/item/organ/external/diona/arm/stun_act(var/stun_amount, var/agony_amount) + if(!owner || (agony_amount < 5)) + return + if(prob(25)) + owner.grasp_damage_disarm(src) + +/obj/item/organ/external/diona/arm/right + name = "right upper tendril" + organ_tag = BP_R_ARM + icon_name = "r_arm" + body_part = ARM_RIGHT + +/obj/item/organ/external/diona/leg + name = "left lower tendril" + organ_tag = BP_L_LEG + icon_name = "l_leg" + max_damage = 35 + min_broken_damage = 20 + w_class = ITEM_SIZE_NORMAL + body_part = LEG_LEFT + icon_position = LEFT + parent_organ = BP_GROIN + can_stand = 1 + +/obj/item/organ/external/diona/leg/stun_act(var/stun_amount, var/agony_amount) + if(!owner || agony_amount < 5) + return + if(prob(min(agony_amount*2,50))) + to_chat(owner, "Your [src] buckles from the shock!") + owner.Weaken(5) + +/obj/item/organ/external/diona/leg/right + name = "right lower tendril" + organ_tag = BP_R_LEG + icon_name = "r_leg" + body_part = LEG_RIGHT + icon_position = RIGHT + +/obj/item/organ/external/diona/foot + name = "left foot" + organ_tag = BP_L_FOOT + icon_name = "l_foot" + max_damage = 20 + min_broken_damage = 10 + w_class = ITEM_SIZE_SMALL + body_part = FOOT_LEFT + icon_position = LEFT + parent_organ = BP_L_LEG + can_stand = 1 + +/obj/item/organ/external/diona/foot/stun_act(var/stun_amount, var/agony_amount) + if(!owner || agony_amount < 5) + return + if(prob(min(agony_amount*4,50))) + to_chat(owner, "You lose your footing as your [src] spasms!") + owner.Weaken(5) + +/obj/item/organ/external/diona/foot/right + name = "right foot" + organ_tag = BP_R_FOOT + icon_name = "r_foot" + body_part = FOOT_RIGHT + icon_position = RIGHT + parent_organ = BP_R_LEG + joint = "right ankle" + amputation_point = "right ankle" + +/obj/item/organ/external/diona/hand + name = "left grasper" + organ_tag = BP_L_HAND + icon_name = "l_hand" + max_damage = 30 + min_broken_damage = 15 + w_class = ITEM_SIZE_SMALL + body_part = HAND_LEFT + parent_organ = BP_L_ARM + can_grasp = 1 + +/obj/item/organ/external/diona/hand/stun_act(var/stun_amount, var/agony_amount) + if(!owner || (agony_amount < 5)) + return + owner.grasp_damage_disarm(src) + +/obj/item/organ/external/diona/hand/right + name = "right grasper" + organ_tag = BP_R_HAND + icon_name = "r_hand" + body_part = HAND_RIGHT + parent_organ = BP_R_ARM + +//DIONA ORGANS. +/obj/item/organ/external/diona/removed() + if(robotic >= ORGAN_ROBOT) + return ..() + var/mob/living/carbon/human/H = owner + ..() + if(!istype(H) || !H.organs || !H.organs.len) + H.death() + if(prob(50) && spawn_diona_nymph(get_turf(src))) + qdel(src) + +// Copypaste due to eye code, RIP. +/obj/item/organ/external/head/no_eyes/diona + can_intake_reagents = 0 + cannot_break = 1 + max_damage = 50 + min_broken_damage = 25 + +/obj/item/organ/external/head/no_eyes/diona/removed() + if(robotic >= ORGAN_ROBOT) + return ..() + var/mob/living/carbon/human/H = owner + ..() + if(!istype(H) || !H.organs || !H.organs.len) + H.death() + if(prob(50) && spawn_diona_nymph(get_turf(src))) + qdel(src) + +/obj/item/organ/internal/diona + name = "diona nymph" + icon = 'icons/obj/objects.dmi' + icon_state = "nymph" + organ_tag = "special" // Turns into a nymph instantly, no transplanting possible. + +/obj/item/organ/internal/diona/removed(var/mob/living/user, var/skip_nymph) + if(robotic >= ORGAN_ROBOT) + return ..() + var/mob/living/carbon/human/H = owner + ..() + if(!istype(H) || !H.organs || !H.organs.len) + H.death() + if(prob(50) && !skip_nymph && spawn_diona_nymph(get_turf(src))) + qdel(src) + +/obj/item/organ/internal/diona/Process() + return PROCESS_KILL + +/obj/item/organ/internal/diona/strata + name = "neural strata" + parent_organ = BP_CHEST + organ_tag = "neural strata" + + +/obj/item/organ/internal/diona/bladder + name = "gas bladder" + parent_organ = BP_HEAD + organ_tag = "gas bladder" + +/obj/item/organ/internal/diona/polyp + name = "polyp segment" + parent_organ = BP_GROIN + organ_tag = "polyp segment" + +/obj/item/organ/internal/diona/ligament + name = "anchoring ligament" + parent_organ = BP_GROIN + organ_tag = "anchoring ligament" + +/obj/item/organ/internal/diona/node + name = "receptor node" + parent_organ = BP_HEAD + +/obj/item/organ/internal/diona/nutrients + name = BP_NUTRIENT + parent_organ = BP_CHEST + +// These are different to the standard diona organs as they have a purpose in other +// species (absorbing radiation and light respectively) +/obj/item/organ/internal/diona/nutrients + name = BP_NUTRIENT + parent_organ = BP_CHEST + organ_tag = BP_NUTRIENT + icon = 'icons/mob/alien.dmi' + icon_state = "claw" + +/obj/item/organ/internal/diona/nutrients/removed(var/mob/user) + return ..(user, 1) + +/obj/item/organ/internal/diona/node + name = "response node" + parent_organ = BP_HEAD + organ_tag = "response node" + icon = 'icons/mob/alien.dmi' + icon_state = "claw" + +/obj/item/organ/internal/diona/node/Process() + ..() + if(is_broken() || !owner) + return + var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing + if(isturf(owner.loc)) //else, there's considered to be no light + var/turf/T = owner.loc + light_amount = T.get_lumcount() * 10 + owner.nutrition += light_amount + owner.shock_stage -= light_amount + owner.nutrition = Clamp(owner.nutrition, 0, 550) + +/obj/item/organ/internal/diona/node/removed(var/mob/user) + return ..(user, 1) diff --git a/code/modules/organs/external/head.dm b/code/modules/organs/external/head.dm new file mode 100644 index 00000000..07c7c7dc --- /dev/null +++ b/code/modules/organs/external/head.dm @@ -0,0 +1,197 @@ + +/obj/item/organ/external/head + organ_tag = BP_HEAD + icon_name = "head" + name = "head" + slot_flags = SLOT_BELT + max_damage = 150 + min_broken_damage = 100 + w_class = ITEM_SIZE_NORMAL + body_part = HEAD + vital = 1 + parent_organ = BP_CHEST + joint = "jaw" + amputation_point = "neck" + gendered_icon = 1 + encased = "skull" + artery_name = "carotid artery" + cavity_name = "cranial" + arterial_bleed_severity = 5 + break_sound = "headsmash" + + var/can_intake_reagents = 1 + var/eye_icon = "eyes_s" + var/eye_icon_location = 'icons/mob/human_face.dmi' + var/has_lips + var/list/teeth_list = list() + var/max_teeth = 32 + +/obj/item/organ/external/head/droplimb(clean, disintegrate = DROPLIMB_EDGE, ignore_children, silent) + for(var/obj/item/stack/teeth/T in src) + qdel(T) + ..() + if(disintegrate == DROPLIMB_BLUNT) + if(teeth_list.len) + for(var/obj/item/stack/teeth/T in teeth_list)//Somehow this is generating teeth twice. + qdel(T) + +/obj/item/organ/external/head/fracture()//Your head now has way more health but if you break it you're gonna fucking feel it. + ..() + for(var/obj/item/organ/internal/brain/B in src) + B.take_damage(50) + + +/obj/item/organ/external/head/set_dna(var/datum/dna/new_dna) + ..() + eye_icon = species.eye_icon + eye_icon_location = species.eye_icon_location + +/obj/item/organ/external/head/get_agony_multiplier() + return (owner && owner.headcheck(organ_tag)) ? 1.50 : 1 + +/obj/item/organ/external/head/robotize(var/company, var/skip_prosthetics, var/keep_organs) + if(company) + var/datum/robolimb/R = all_robolimbs[company] + if(R) + can_intake_reagents = R.can_eat + eye_icon = R.use_eye_icon + . = ..(company, skip_prosthetics, 1) + has_lips = null + +/obj/item/organ/external/head/removed() + if(owner) + SetName("[owner.real_name]'s head") + owner.drop_from_inventory(owner.glasses) + owner.drop_from_inventory(owner.head) + owner.drop_from_inventory(owner.l_ear) + owner.drop_from_inventory(owner.r_ear) + owner.drop_from_inventory(owner.wear_mask) + spawn(1) + owner.update_hair() + ..() + +/obj/item/organ/external/head/take_damage(brute, burn, damage_flags, used_weapon = null) + . = ..() + if (!disfigured) + if (brute_dam > 40) + if (prob(50)) + disfigure("brute") + if (burn_dam > 40) + disfigure("burn") + +/obj/item/organ/external/head/no_eyes + eye_icon = "blank_eyes" + +/obj/item/organ/external/head/update_icon() + + ..() + + if(owner) + if(eye_icon) + var/icon/eyes_icon = new/icon(eye_icon_location, eye_icon) + var/obj/item/organ/internal/eyes/eyes = owner.internal_organs_by_name[owner.species.vision_organ ? owner.species.vision_organ : BP_EYES] + if(eyes) + eyes_icon.Blend(rgb(eyes.eye_colour[1], eyes.eye_colour[2], eyes.eye_colour[3]), ICON_ADD) + else + eyes_icon.Blend(rgb(128,0,0), ICON_ADD) + mob_icon.Blend(eyes_icon, ICON_OVERLAY) + overlays |= eyes_icon + + if(owner.lip_style && robotic < ORGAN_ROBOT && (species && (species.appearance_flags & HAS_LIPS))) + var/icon/lip_icon = new/icon('icons/mob/human_face.dmi', "lips_[owner.lip_style]_s") + overlays |= lip_icon + mob_icon.Blend(lip_icon, ICON_OVERLAY) + + overlays |= get_hair_icon() + + return mob_icon + +/obj/item/organ/external/head/proc/get_hair_icon() + var/image/res = image(species.icon_template,"") + if(owner.f_style) + var/datum/sprite_accessory/facial_hair_style = GLOB.facial_hair_styles_list[owner.f_style] + if(facial_hair_style && facial_hair_style.species_allowed && (species.get_bodytype(owner) in facial_hair_style.species_allowed)) + var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s") + if(facial_hair_style.do_colouration) + facial_s.Blend(rgb(owner.r_facial, owner.g_facial, owner.b_facial), facial_hair_style.blend) + res.overlays |= facial_s + + if(owner.h_style) + var/style = owner.h_style + var/datum/sprite_accessory/hair/hair_style = GLOB.hair_styles_list[style] + if(owner.head && (owner.head.flags_inv & BLOCKHEADHAIR)) + if(!(hair_style.flags & VERY_SHORT)) + hair_style = GLOB.hair_styles_list["Short Hair"] + if(hair_style && (species.get_bodytype(owner) in hair_style.species_allowed)) + var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") + if(hair_style.do_colouration && islist(h_col) && h_col.len >= 3) + hair_s.Blend(rgb(h_col[1], h_col[2], h_col[3]), hair_style.blend) + res.overlays |= hair_s + return res + + +/obj/item/organ/external/head/proc/get_teeth() //returns collective amount of teeth + var/amt = 0 + if(!teeth_list) teeth_list = list() + for(var/obj/item/stack/teeth/T in teeth_list) + amt += T.amount + return amt + +/obj/item/organ/external/head/proc/knock_out_teeth(throw_dir, num=32) //Won't support knocking teeth out of a dismembered head or anything like that yet. + num = Clamp(num, 1, 32) + var/done = FALSE + if(teeth_list && teeth_list.len) //We still have teeth + var/stacks = rand(1,3) + for(var/curr = 1 to stacks) //Random amount of teeth stacks + var/obj/item/stack/teeth/teeth = pick(teeth_list) + if(!teeth || teeth.zero_amount()) return //No teeth left, abort! + var/drop = 1 //Calculate the amount of teeth in the stack + var/obj/item/stack/teeth/T = new teeth.type(owner.loc, drop) + teeth.use(drop) + T.add_blood(owner) + playsound(owner, "trauma", 75, 0) + var/turf/target = get_turf(owner.loc) + var/range = rand(1, 3) + for(var/i = 1; i < range; i++) + var/turf/new_turf = get_step(target, throw_dir) + target = new_turf + if(new_turf.density) + break + T.throw_at(get_edge_target_turf(T,pick(GLOB.alldirs)),rand(1,3),30) + T.loc:add_blood(owner) + + teeth.zero_amount() //Try to delete the teeth + GLOB.teeth_lost += drop + done = TRUE + return done + + +/obj/item/stack/teeth + name = "teeth" + singular_name = "tooth" + w_class = 1 + force = 0 + throwforce = 0 + max_amount = 32 + gender = PLURAL + desc = "Welp. Someone had their teeth knocked out." + icon = 'icons/obj/surgery.dmi' + icon_state = "tooth1" + drop_sound = null + +/obj/item/stack/teeth/New() + ..() + icon_state = "tooth[rand(1,3)]" + +/obj/item/stack/teeth/human + name = "human teeth" + singular_name = "human tooth" + +/obj/item/stack/teeth/generic //Used for species without unique teeth defined yet + name = "teeth" + +/obj/item/stack/proc/zero_amount()//Teeth shit + if(amount < 1) + qdel(src) + return 1 + return 0 \ No newline at end of file diff --git a/code/modules/organs/external/machine.dm b/code/modules/organs/external/machine.dm new file mode 100644 index 00000000..fb22c954 --- /dev/null +++ b/code/modules/organs/external/machine.dm @@ -0,0 +1,176 @@ +/obj/item/organ/internal/cell + name = "microbattery" + desc = "A small, powerful cell for use in fully prosthetic bodies." + icon_state = "cell" + dead_icon = "cell_bork" + organ_tag = BP_CELL + parent_organ = BP_CHEST + vital = 1 + var/open + var/obj/item/weapon/cell/cell = /obj/item/weapon/cell/hyper + //at 0.8 completely depleted after 60ish minutes of constant walking or 130 minutes of standing still + var/servo_cost = 0.8 + + +/obj/item/organ/internal/cell/New() + robotize() + if(ispath(cell)) + cell = new cell(src) + ..() + +/obj/item/organ/internal/cell/proc/percent() + if(!cell) + return 0 + return get_charge()/cell.maxcharge * 100 + +/obj/item/organ/internal/cell/proc/get_charge() + if(!cell) + return 0 + if(status & ORGAN_DEAD) + return 0 + return round(cell.charge*(1 - damage/max_damage)) + +/obj/item/organ/internal/cell/proc/check_charge(var/amount) + return get_charge() >= amount + +/obj/item/organ/internal/cell/proc/use(var/amount) + if(check_charge(amount)) + cell.use(amount) + return 1 + +/obj/item/organ/internal/cell/Process() + ..() + if(!owner) + return + if(owner.stat == DEAD) //not a drain anymore + return + if(!is_usable()) + owner.Paralyse(3) + return + var/standing = !owner.lying && !owner.buckled //on the edge + var/drop + if(!check_charge(servo_cost)) //standing is pain + drop = 1 + else if(standing) + use(servo_cost) + if(world.time - owner.l_move_time < 15) //so is + if(!use(servo_cost)) + drop = 1 + if(drop) + if(standing) + to_chat(owner, "You don't have enough energy to stand!") + owner.Weaken(2) + +/obj/item/organ/internal/cell/emp_act(severity) + ..() + if(cell) + cell.emp_act(severity) + +/obj/item/organ/internal/cell/attackby(obj/item/weapon/W, mob/user) + if(isScrewdriver(W)) + if(open) + open = 0 + to_chat(user, "You screw the battery panel in place.") + else + open = 1 + to_chat(user, "You unscrew the battery panel.") + + if(isCrowbar(W)) + if(open) + if(cell) + user.put_in_hands(cell) + to_chat(user, "You remove \the [cell] from \the [src].") + cell = null + + if (istype(W, /obj/item/weapon/cell)) + if(open) + if(cell) + to_chat(user, "There is a power cell already installed.") + else + user.drop_from_inventory(W,src) + cell = W + to_chat(user, "You insert \the [cell].") + +/obj/item/organ/internal/cell/replaced() + ..() + // This is very ghetto way of rebooting an IPC. TODO better way. + if(owner && owner.stat == DEAD) + owner.set_stat(CONSCIOUS) + owner.visible_message("\The [owner] twitches visibly!") + +/obj/item/organ/internal/cell/listen() + if(get_charge()) + return "faint hum of the power bank" + +// Used for an MMI or posibrain being installed into a human. +/obj/item/organ/internal/mmi_holder + name = "brain interface" + icon_state = "brain-prosthetic" + organ_tag = BP_BRAIN + parent_organ = BP_HEAD + vital = 1 + var/obj/item/device/mmi/stored_mmi + var/datum/mind/persistantMind //Mind that the organ will hold on to after being removed, used for transfer_and_delete + var/ownerckey // used in the event the owner is out of body + +/obj/item/organ/internal/mmi_holder/Destroy() + stored_mmi = null + return ..() + +/obj/item/organ/internal/mmi_holder/New(var/mob/living/carbon/human/new_owner, var/internal) + ..(new_owner, internal) + if(!stored_mmi) + stored_mmi = new(src) + sleep(-1) + update_from_mmi() + persistantMind = owner.mind + ownerckey = owner.ckey + +/obj/item/organ/internal/mmi_holder/proc/update_from_mmi() + + if(!stored_mmi.brainmob) + stored_mmi.brainmob = new(stored_mmi) + stored_mmi.brainobj = new(stored_mmi) + stored_mmi.brainmob.container = stored_mmi + stored_mmi.brainmob.real_name = owner.real_name + stored_mmi.brainmob.SetName(stored_mmi.brainmob.real_name) + stored_mmi.SetName("[initial(stored_mmi.name)] ([owner.real_name])") + + if(!owner) return + + name = stored_mmi.name + desc = stored_mmi.desc + icon = stored_mmi.icon + + stored_mmi.icon_state = "mmi_full" + icon_state = stored_mmi.icon_state + + if(owner && owner.stat == DEAD) + owner.set_stat(CONSCIOUS) + owner.switch_from_dead_to_living_mob_list() + owner.visible_message("\The [owner] twitches visibly!") + +/obj/item/organ/internal/mmi_holder/cut_away(var/mob/living/user) + var/obj/item/organ/external/parent = owner.get_organ(parent_organ) + if(istype(parent)) + removed(user, 0) + parent.implants += transfer_and_delete() + +/obj/item/organ/internal/mmi_holder/removed() + if(owner && owner.mind) + persistantMind = owner.mind + if(owner.ckey) + ownerckey = owner.ckey + ..() + +/obj/item/organ/internal/mmi_holder/proc/transfer_and_delete() + if(stored_mmi) + . = stored_mmi + stored_mmi.forceMove(src.loc) + if(persistantMind) + persistantMind.transfer_to(stored_mmi.brainmob) + else + var/response = input(find_dead_player(ownerckey, 1), "Your [initial(stored_mmi.name)] has been removed from your body. Do you wish to return to life?", "Robotic Rebirth") as anything in list("Yes", "No") + if(response == "Yes") + persistantMind.transfer_to(stored_mmi.brainmob) + qdel(src) diff --git a/code/modules/organs/external/standard.dm b/code/modules/organs/external/standard.dm new file mode 100644 index 00000000..540d1d09 --- /dev/null +++ b/code/modules/organs/external/standard.dm @@ -0,0 +1,247 @@ +/**************************************************** + ORGAN DEFINES +****************************************************/ + +//Make sure that w_class is set as if the parent mob was medium sized! This is because w_class is adjusted automatically for mob_size in New() + +/obj/item/organ/external/chest + name = "upper body" + organ_tag = BP_CHEST + icon_name = "torso" + max_damage = 100 + min_broken_damage = 35 + w_class = ITEM_SIZE_HUGE //Used for dismembering thresholds, in addition to storage. Humans are w_class 6, so it makes sense that chest is w_class 5. + body_part = UPPER_TORSO + vital = 1 + amputation_point = "spine" + joint = "neck" + dislocated = -1 + gendered_icon = 1 + cannot_amputate = 1 + parent_organ = null + encased = "ribcage" + artery_name = "aorta" + cavity_name = "thoracic" + +/obj/item/organ/external/chest/robotize() + if(..()) + // Give them a new cell. + var/obj/item/organ/internal/cell/C = owner.internal_organs_by_name[BP_CELL] + if(!istype(C)) + owner.internal_organs_by_name[BP_CELL] = new /obj/item/organ/internal/cell(owner,1) + +/obj/item/organ/external/get_scan_results() + . = ..() + var/obj/item/organ/internal/lungs/L = locate() in src + if( L && L.is_bruised()) + . += "Lung ruptured" + +/obj/item/organ/external/groin + name = "lower body" + organ_tag = BP_GROIN + icon_name = "groin" + max_damage = 100 + min_broken_damage = 35 + w_class = ITEM_SIZE_LARGE + body_part = LOWER_TORSO + vital = TRUE + parent_organ = BP_CHEST + amputation_point = "lumbar" + joint = "hip" + dislocated = -1 + cannot_amputate = TRUE + gendered_icon = 1 + artery_name = "iliac artery" + cavity_name = "abdominal" + +/obj/item/organ/external/arm + organ_tag = BP_L_ARM + name = "left arm" + icon_name = "l_arm" + max_damage = 50 + min_broken_damage = 30 + w_class = ITEM_SIZE_NORMAL + body_part = ARM_LEFT + parent_organ = BP_CHEST + joint = "left elbow" + amputation_point = "left shoulder" + can_grasp = 1 + has_tendon = TRUE + tendon_name = "palmaris longus tendon" + artery_name = "basilic vein" + arterial_bleed_severity = 0.75 + gibbable = FALSE + +/obj/item/organ/external/arm/stun_act(var/stun_amount, var/agony_amount) + if(!owner || (agony_amount < 5)) + return + if(prob(25)) + owner.grasp_damage_disarm(src) + + +/obj/item/organ/external/arm/robo_arm/New() + ..() + robotize("Limbs R US") + icon = 'icons/mob/human_races/cyberlimbs/warfare/warfare_main.dmi' + icon_state = "arm_partial" + +/obj/item/organ/external/arm/right + organ_tag = BP_R_ARM + name = "right arm" + icon_name = "r_arm" + body_part = ARM_RIGHT + joint = "right elbow" + amputation_point = "right shoulder" + +/obj/item/organ/external/arm/right/robo_arm/New() + ..() + robotize("Limbs R US") + icon = 'icons/mob/human_races/cyberlimbs/warfare/warfare_main.dmi' + icon_state = "arm_partial" + + +/obj/item/organ/external/leg + organ_tag = BP_L_LEG + name = "left leg" + icon_name = "l_leg" + max_damage = 100 + min_broken_damage = 50 + w_class = ITEM_SIZE_NORMAL + body_part = LEG_LEFT + icon_position = LEFT + parent_organ = BP_GROIN + joint = "left knee" + amputation_point = "left hip" + can_stand = 1 + has_tendon = TRUE + tendon_name = "cruciate ligament" + artery_name = "femoral artery" + arterial_bleed_severity = 0.75 + gibbable = FALSE + +/obj/item/organ/external/leg/stun_act(var/stun_amount, var/agony_amount) + if(!owner || agony_amount < 5) + return + if(prob(min(agony_amount*2,50))) + to_chat(owner, "Your [src] buckles from the shock!") + owner.Weaken(5) + +/obj/item/organ/external/leg/robo_leg/New() + ..() + robotize("Limbs R US") + icon = 'icons/mob/human_races/cyberlimbs/warfare/warfare_main.dmi' + icon_state = "leg_partial" + + +/obj/item/organ/external/leg/right + organ_tag = BP_R_LEG + name = "right leg" + icon_name = "r_leg" + body_part = LEG_RIGHT + icon_position = RIGHT + joint = "right knee" + amputation_point = "right hip" + +/obj/item/organ/external/leg/right/robo_leg/New() + ..() + robotize("Limbs R US") + icon = 'icons/mob/human_races/cyberlimbs/warfare/warfare_main.dmi' + icon_state = "leg_partial" + +/obj/item/organ/external/foot + organ_tag = BP_L_FOOT + name = "left foot" + icon_name = "l_foot" + max_damage = 100 + min_broken_damage = 50 + w_class = ITEM_SIZE_SMALL + body_part = FOOT_LEFT + icon_position = LEFT + parent_organ = BP_L_LEG + joint = "left ankle" + amputation_point = "left ankle" + can_stand = 1 + has_tendon = TRUE + tendon_name = "Achilles tendon" + arterial_bleed_severity = 0.5 + gibbable = FALSE + +/obj/item/organ/external/foot/stun_act(var/stun_amount, var/agony_amount) + if(!owner || agony_amount < 5) + return + if(prob(min(agony_amount*4,70))) + to_chat(owner, "You lose your footing as your [src] spasms!") + owner.Weaken(5) + +/obj/item/organ/external/foot/removed() + if(owner) owner.drop_from_inventory(owner.shoes) + ..() + +/obj/item/organ/external/foot/robo_foot/New() + ..() + robotize("Limbs R US") + icon = 'icons/mob/human_races/cyberlimbs/warfare/warfare_main.dmi' + icon_state = "foot" + +/obj/item/organ/external/foot/right + organ_tag = BP_R_FOOT + name = "right foot" + icon_name = "r_foot" + body_part = FOOT_RIGHT + icon_position = RIGHT + parent_organ = BP_R_LEG + joint = "right ankle" + amputation_point = "right ankle" + +/obj/item/organ/external/foot/right/robo_foot/New() + ..() + robotize("Limbs R US") + icon = 'icons/mob/human_races/cyberlimbs/warfare/warfare_main.dmi' + icon_state = "foot" + +/obj/item/organ/external/hand + organ_tag = BP_L_HAND + name = "left hand" + icon_name = "l_hand" + max_damage = 100 + min_broken_damage = 50 + w_class = ITEM_SIZE_SMALL + body_part = HAND_LEFT + parent_organ = BP_L_ARM + joint = "left wrist" + amputation_point = "left wrist" + can_grasp = 1 + has_tendon = TRUE + tendon_name = "carpal ligament" + arterial_bleed_severity = 0.5 + gibbable = FALSE + +/obj/item/organ/external/hand/robo_hand/New() + ..() + robotize("Limbs R US") + icon = 'icons/mob/human_races/cyberlimbs/warfare/warfare_main.dmi' + icon_state = "hand" + +/obj/item/organ/external/hand/stun_act(var/stun_amount, var/agony_amount) + if(!owner || (agony_amount < 5)) + return + owner.grasp_damage_disarm(src) + +/obj/item/organ/external/hand/removed() + owner.drop_from_inventory(owner.gloves) + ..() + +/obj/item/organ/external/hand/right + organ_tag = BP_R_HAND + name = "right hand" + icon_name = "r_hand" + body_part = HAND_RIGHT + parent_organ = BP_R_ARM + joint = "right wrist" + amputation_point = "right wrist" + +/obj/item/organ/external/hand/right/robo_hand/New() + ..() + robotize("Limbs R US") + icon = 'icons/mob/human_races/cyberlimbs/warfare/warfare_main.dmi' + icon_state = "hand" \ No newline at end of file diff --git a/code/modules/organs/external/stump.dm b/code/modules/organs/external/stump.dm new file mode 100644 index 00000000..76765f83 --- /dev/null +++ b/code/modules/organs/external/stump.dm @@ -0,0 +1,27 @@ +/obj/item/organ/external/stump + name = "limb stump" + icon_name = "" + dislocated = -1 + +/obj/item/organ/external/stump/New(var/mob/living/carbon/holder, var/internal, var/obj/item/organ/external/limb) + if(istype(limb)) + organ_tag = limb.organ_tag + body_part = limb.body_part + amputation_point = limb.amputation_point + joint = limb.joint + parent_organ = limb.parent_organ + ..(holder, internal) + if(istype(limb)) + max_damage = limb.max_damage + if((limb.robotic >= ORGAN_ROBOT) && (!parent || (parent.robotic >= ORGAN_ROBOT))) + robotize() //if both limb and the parent are robotic, the stump is robotic too + +/obj/item/organ/external/stump/is_stump() + return 1 + +/obj/item/organ/external/stump/removed() + ..() + qdel(src) + +/obj/item/organ/external/stump/is_usable() + return 0 diff --git a/code/modules/organs/external/unbreakable.dm b/code/modules/organs/external/unbreakable.dm new file mode 100644 index 00000000..d4da0264 --- /dev/null +++ b/code/modules/organs/external/unbreakable.dm @@ -0,0 +1,90 @@ +// Slime/xeno limbs. +/obj/item/organ/external/chest/unbreakable + cannot_break = 1 + dislocated = -1 + +/obj/item/organ/external/groin/unbreakable + cannot_break = 1 + dislocated = -1 + +/obj/item/organ/external/arm/unbreakable + cannot_break = 1 + dislocated = -1 + +/obj/item/organ/external/arm/right/unbreakable + cannot_break = 1 + dislocated = -1 + +/obj/item/organ/external/leg/unbreakable + cannot_break = 1 + dislocated = -1 + +/obj/item/organ/external/leg/right/unbreakable + cannot_break = 1 + dislocated = -1 + +/obj/item/organ/external/foot/unbreakable + cannot_break = 1 + dislocated = -1 + +/obj/item/organ/external/foot/right/unbreakable + cannot_break = 1 + dislocated = -1 + +/obj/item/organ/external/hand/unbreakable + cannot_break = 1 + dislocated = -1 + +/obj/item/organ/external/hand/right/unbreakable + cannot_break = 1 + dislocated = -1 + +/obj/item/organ/external/head/unbreakable + cannot_break = 1 + dislocated = -1 + +// Slime limbs. +/obj/item/organ/external/chest/unbreakable/slime + nonsolid = 1 + max_damage = 50 + +/obj/item/organ/external/groin/unbreakable/slime + nonsolid = 1 + max_damage = 30 + +/obj/item/organ/external/arm/unbreakable/slime + nonsolid = 1 + max_damage = 15 + +/obj/item/organ/external/arm/right/unbreakable/slime + nonsolid = 1 + max_damage = 15 + +/obj/item/organ/external/leg/unbreakable/slime + nonsolid = 1 + max_damage = 15 + +/obj/item/organ/external/leg/right/unbreakable/slime + nonsolid = 1 + max_damage = 15 + +/obj/item/organ/external/foot/unbreakable/slime + nonsolid = 1 + max_damage = 5 + +/obj/item/organ/external/foot/right/unbreakable/slime + nonsolid = 1 + max_damage = 5 + +/obj/item/organ/external/hand/unbreakable/slime + nonsolid = 1 + max_damage = 5 + +/obj/item/organ/external/hand/right/unbreakable/slime + nonsolid = 1 + max_damage = 5 + +/obj/item/organ/external/head/unbreakable/slime + nonsolid = 1 + max_damage = 15 + eye_icon = "blank_eyes" diff --git a/code/modules/organs/external/vox.dm b/code/modules/organs/external/vox.dm new file mode 100644 index 00000000..65f67ce3 --- /dev/null +++ b/code/modules/organs/external/vox.dm @@ -0,0 +1,26 @@ +/obj/item/organ/external/head/vox + eye_icon = "vox_eyes_s" + +//vox got different organs within. This will also help with regular surgeons knowing the organs within an alien as alien as vox. +/obj/item/organ/internal/heart/vox + icon_state = "vox heart" + dead_icon = null + parent_organ = BP_GROIN + +/obj/item/organ/internal/lungs/vox + name = "air capillary sack" //Like birds, Vox absorb gas via air capillaries. + icon_state = "vox lung" + +/obj/item/organ/internal/kidneys/vox + name = "filtration bladder" + icon_state = "lungs" //wow are vox kidneys fat. + color = "#99ccff" + parent_organ = BP_CHEST + +/obj/item/organ/internal/liver/vox + name = "waste tract" + parent_organ = BP_CHEST + color = "#0033cc" + +/obj/item/organ/external/groin/vox //vox have an extended ribcage for extra protection. + encased = "lower ribcage" \ No newline at end of file diff --git a/code/modules/organs/external/wounds/wound.dm b/code/modules/organs/external/wounds/wound.dm new file mode 100644 index 00000000..6410f643 --- /dev/null +++ b/code/modules/organs/external/wounds/wound.dm @@ -0,0 +1,185 @@ + +/**************************************************** + WOUNDS +****************************************************/ +/datum/wound + var/current_stage = 0 // number representing the current stage + var/desc = "wound" // description of the wound. default in case something borks + var/damage = 0 // amount of damage this wound causes + var/bleed_timer = 0 // ticks of bleeding left. + var/bleed_threshold = 30 // Above this amount wounds you will need to treat the wound to stop bleeding, regardless of bleed_timer + var/min_damage = 0 // amount of damage the current wound type requires(less means we need to apply the next healing stage) + var/bandaged = 0 // is the wound bandaged? + var/clamped = 0 // Similar to bandaged, but works differently + var/salved = 0 // is the wound salved? + var/disinfected = 0 // is the wound disinfected? + var/created = 0 + var/amount = 1 // number of wounds of this type + var/germ_level = 0 // amount of germs in the wound + + /* These are defined by the wound type and should not be changed */ + var/list/stages // stages such as "cut", "deep cut", etc. + var/max_bleeding_stage = 0 // maximum stage at which bleeding should still happen. Beyond this stage bleeding is prevented. + var/damage_type = CUT // one of CUT, PIERCE, BRUISE, BURN + var/autoheal_cutoff = 15 // the maximum amount of damage that this wound can have and still autoheal + + // helper lists + var/tmp/list/embedded_objects = list() + var/tmp/list/desc_list = list() + var/tmp/list/damage_list = list() + +/datum/wound/New(var/damage) + + created = world.time + + // reading from a list("stage" = damage) is pretty difficult, so build two separate + // lists from them instead + for(var/V in stages) + desc_list += V + damage_list += stages[V] + + src.damage = damage + + // initialize with the appropriate stage + src.init_stage(damage) + + bleed_timer += damage + +// returns 1 if there's a next stage, 0 otherwise +/datum/wound/proc/init_stage(var/initial_damage) + current_stage = stages.len + + while(src.current_stage > 1 && src.damage_list[current_stage-1] <= initial_damage / src.amount) + src.current_stage-- + + src.min_damage = damage_list[current_stage] + src.desc = desc_list[current_stage] + +// the amount of damage per wound +/datum/wound/proc/wound_damage() + return src.damage / src.amount + +/datum/wound/proc/can_autoheal() + if(embedded_objects.len) + return 0 + return (wound_damage() <= autoheal_cutoff) ? 1 : is_treated() + +// checks whether the wound has been appropriately treated +/datum/wound/proc/is_treated() + if(!embedded_objects.len) + switch(damage_type) + if(BRUISE, CUT, PIERCE) + return bandaged + if(BURN) + return salved + + // Checks whether other other can be merged into src. +/datum/wound/proc/can_merge(var/datum/wound/other) + if (other.type != src.type) return 0 + if (other.current_stage != src.current_stage) return 0 + if (other.damage_type != src.damage_type) return 0 + if (!(other.can_autoheal()) != !(src.can_autoheal())) return 0 + if (other.is_surgical() != src.is_surgical()) return 0 + if (!(other.bandaged) != !(src.bandaged)) return 0 + if (!(other.clamped) != !(src.clamped)) return 0 + if (!(other.salved) != !(src.salved)) return 0 + if (!(other.disinfected) != !(src.disinfected)) return 0 + return 1 + +/datum/wound/proc/merge_wound(var/datum/wound/other) + src.embedded_objects |= other.embedded_objects + src.damage += other.damage + src.amount += other.amount + src.bleed_timer += other.bleed_timer + src.germ_level = max(src.germ_level, other.germ_level) + src.created = max(src.created, other.created) //take the newer created time + +// checks if wound is considered open for external infections +// untreated cuts (and bleeding bruises) and burns are possibly infectable, chance higher if wound is bigger +/datum/wound/proc/infection_check() + if (damage < 10) //small cuts, tiny bruises, and moderate burns shouldn't be infectable. + return 0 + if (is_treated() && damage < 25) //anything less than a flesh wound (or equivalent) isn't infectable if treated properly + return 0 + if (disinfected) + germ_level = 0 //reset this, just in case + return 0 + + if (damage_type == BRUISE && !bleeding()) //bruises only infectable if bleeding + return 0 + + var/dam_coef = round(damage/10) + switch (damage_type) + if (BRUISE) + return prob(dam_coef*5) + if (BURN) + return prob(dam_coef*10) + if (CUT) + return prob(dam_coef*20) + + return 0 + +/datum/wound/proc/bandage() + bandaged = 1 + +/datum/wound/proc/salve() + salved = 1 + +/datum/wound/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 +/datum/wound/proc/heal_damage(amount) + if(embedded_objects.len) + return amount // heal nothing + var/healed_damage = min(src.damage, amount) + amount -= healed_damage + src.damage -= healed_damage + + while(src.wound_damage() < damage_list[current_stage] && current_stage < src.desc_list.len) + current_stage++ + desc = desc_list[current_stage] + src.min_damage = damage_list[current_stage] + + // return amount of healing still leftover, can be used for other wounds + return amount + +// opens the wound again +/datum/wound/proc/open_wound(damage) + src.damage += damage + bleed_timer += damage + + while(src.current_stage > 1 && src.damage_list[current_stage-1] <= src.damage / src.amount) + src.current_stage-- + + src.desc = desc_list[current_stage] + src.min_damage = damage_list[current_stage] + +// returns whether this wound can absorb the given amount of damage. +// this will prevent large amounts of damage being trapped in less severe wound types +/datum/wound/proc/can_worsen(damage_type, damage) + if (src.damage_type != damage_type) + return 0 //incompatible damage types + + if (src.amount > 1) + return 0 //merged wounds cannot be worsened. + + //with 1.5*, a shallow cut will be able to carry at most 30 damage, + //37.5 for a deep cut + //52.5 for a flesh wound, etc. + var/max_wound_damage = 1.5*src.damage_list[1] + if (src.damage + damage > max_wound_damage) + return 0 + return 1 + +/datum/wound/proc/bleeding() + for(var/obj/item/thing in embedded_objects) + if(thing.w_class > ITEM_SIZE_SMALL) + return FALSE + if(bandaged || clamped) + return FALSE + return ((bleed_timer > 0 || wound_damage() > bleed_threshold) && current_stage <= max_bleeding_stage) + +/datum/wound/proc/is_surgical() + return 0 \ No newline at end of file diff --git a/code/modules/organs/external/wounds/wound_types.dm b/code/modules/organs/external/wounds/wound_types.dm new file mode 100644 index 00000000..870bc753 --- /dev/null +++ b/code/modules/organs/external/wounds/wound_types.dm @@ -0,0 +1,281 @@ +/** WOUND DEFINITIONS **/ +//Note that the MINIMUM damage before a wound can be applied should correspond to +//the damage amount for the stage with the same name as the wound. +//e.g. /datum/wound/cut/deep should only be applied for 15 damage and up, +//because in it's stages list, "deep cut" = 15. +/proc/get_wound_type(var/type, var/damage) + switch(type) + if(CUT) + switch(damage) + if(70 to INFINITY) + return /datum/wound/cut/massive + if(60 to 70) + return /datum/wound/cut/gaping_big + if(50 to 60) + return /datum/wound/cut/gaping + if(25 to 50) + return /datum/wound/cut/flesh + if(15 to 25) + return /datum/wound/cut/deep + if(0 to 15) + return /datum/wound/cut/small + if(PIERCE) + switch(damage) + if(60 to INFINITY) + return /datum/wound/puncture/massive + if(50 to 60) + return /datum/wound/puncture/gaping_big + if(30 to 50) + return /datum/wound/puncture/gaping + if(15 to 30) + return /datum/wound/puncture/flesh + if(0 to 15) + return /datum/wound/puncture/small + if(BRUISE) + return /datum/wound/bruise + if(BURN, LASER) + switch(damage) + if(50 to INFINITY) + return /datum/wound/burn/carbonised + if(40 to 50) + return /datum/wound/burn/deep + if(30 to 40) + return /datum/wound/burn/severe + if(15 to 30) + return /datum/wound/burn/large + if(0 to 15) + return /datum/wound/burn/moderate + return null //no wound + +/** CUTS **/ +/datum/wound/cut + bleed_threshold = 5 + damage_type = CUT + +/datum/wound/cut/bandage() + ..() + if(!autoheal_cutoff) + autoheal_cutoff = initial(autoheal_cutoff) + +/datum/wound/cut/is_surgical() + return autoheal_cutoff == 0 + +/datum/wound/cut/proc/close() + current_stage = max_bleeding_stage + 1 + desc = desc_list[current_stage] + min_damage = damage_list[current_stage] + damage = min(min_damage, damage) + +/datum/wound/cut/small + // link wound descriptions to amounts of damage + // Minor cuts have max_bleeding_stage set to the stage that bears the wound type's name. + // The major cut types have the max_bleeding_stage set to the clot stage (which is accordingly given the "blood soaked" descriptor). + max_bleeding_stage = 3 + stages = list( + "ugly ripped cut" = 20, + "ripped cut" = 10, + "cut" = 5, + "healing cut" = 2, + "small scab" = 0 + ) + +/datum/wound/cut/deep + max_bleeding_stage = 3 + stages = list( + "ugly deep ripped cut" = 25, + "deep ripped cut" = 20, + "deep cut" = 15, + "clotted cut" = 8, + "scab" = 2, + "fresh skin" = 0 + ) + +/datum/wound/cut/flesh + max_bleeding_stage = 4 + stages = list( + "ugly ripped flesh wound" = 35, + "ugly flesh wound" = 30, + "flesh wound" = 25, + "blood soaked clot" = 15, + "large scab" = 5, + "fresh skin" = 0 + ) + +/datum/wound/cut/gaping + max_bleeding_stage = 3 + stages = list( + "gaping wound" = 50, + "large blood soaked clot" = 25, + "blood soaked clot" = 15, + "small angry scar" = 5, + "small straight scar" = 0 + ) + +/datum/wound/cut/gaping_big + max_bleeding_stage = 3 + stages = list( + "big gaping wound" = 60, + "healing gaping wound" = 40, + "large blood soaked clot" = 25, + "large angry scar" = 10, + "large straight scar" = 0 + ) + +datum/wound/cut/massive + max_bleeding_stage = 3 + stages = list( + "massive wound" = 70, + "massive healing wound" = 50, + "massive blood soaked clot" = 25, + "massive angry scar" = 10, + "massive jagged scar" = 0 + ) + +/** PUNCTURES **/ +/datum/wound/puncture + bleed_threshold = 10 + damage_type = PIERCE + +/datum/wound/puncture/can_worsen(damage_type, damage) + return 0 //puncture wounds cannot be enlargened + +/datum/wound/puncture/small + max_bleeding_stage = 2 + stages = list( + "puncture" = 5, + "healing puncture" = 2, + "small scab" = 0 + ) + +/datum/wound/puncture/flesh + max_bleeding_stage = 2 + stages = list( + "puncture wound" = 15, + "blood soaked clot" = 5, + "large scab" = 2, + "small round scar" = 0 + ) + +/datum/wound/puncture/gaping + max_bleeding_stage = 3 + stages = list( + "gaping hole" = 30, + "large blood soaked clot" = 15, + "blood soaked clot" = 10, + "small angry scar" = 5, + "small round scar" = 0 + ) + +/datum/wound/puncture/gaping_big + max_bleeding_stage = 3 + stages = list( + "big gaping hole" = 50, + "healing gaping hole" = 20, + "large blood soaked clot" = 15, + "large angry scar" = 10, + "large round scar" = 0 + ) + +datum/wound/puncture/massive + max_bleeding_stage = 3 + stages = list( + "massive wound" = 60, + "massive healing wound" = 30, + "massive blood soaked clot" = 25, + "massive angry scar" = 10, + "massive jagged scar" = 0 + ) + +/** BRUISES **/ +/datum/wound/bruise + stages = list( + "monumental bruise" = 80, + "huge bruise" = 50, + "large bruise" = 30, + "moderate bruise" = 20, + "small bruise" = 10, + "tiny bruise" = 5 + ) + + bleed_threshold = 20 + max_bleeding_stage = 3 //only large bruise and above can bleed. + autoheal_cutoff = 30 + damage_type = BRUISE + +/** BURNS **/ +/datum/wound/burn + damage_type = BURN + max_bleeding_stage = 0 + +/datum/wound/burn/bleeding() + return 0 + +/datum/wound/burn/moderate + stages = list( + "ripped burn" = 10, + "moderate burn" = 5, + "healing moderate burn" = 2, + "fresh skin" = 0 + ) + +/datum/wound/burn/large + stages = list( + "ripped large burn" = 20, + "large burn" = 15, + "healing large burn" = 5, + "fresh skin" = 0 + ) + +/datum/wound/burn/severe + stages = list( + "ripped severe burn" = 35, + "severe burn" = 30, + "healing severe burn" = 10, + "burn scar" = 0 + ) + +/datum/wound/burn/deep + stages = list( + "ripped deep burn" = 45, + "deep burn" = 40, + "healing deep burn" = 15, + "large burn scar" = 0 + ) + +/datum/wound/burn/carbonised + stages = list( + "carbonised area" = 50, + "healing carbonised area" = 20, + "massive burn scar" = 0 + ) + +/** EXTERNAL ORGAN LOSS **/ +/datum/wound/lost_limb + +/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, + "scarred stump" = 0 + ) + if(DROPLIMB_BURN) + damage_type = BURN + stages = list( + "ripped charred stump" = damage_amt*1.3, + "charred stump" = damage_amt, + "scarred stump" = damage_amt*0.5, + "scarred stump" = 0 + ) + + ..(damage_amt) + +/datum/wound/lost_limb/can_merge(var/datum/wound/other) + return 0 //cannot be merged diff --git a/code/modules/organs/external/xenos.dm b/code/modules/organs/external/xenos.dm new file mode 100644 index 00000000..79430c62 --- /dev/null +++ b/code/modules/organs/external/xenos.dm @@ -0,0 +1,99 @@ +//XENOMORPH ORGANS +/obj/item/organ/internal/xenos + name = "xeno organ" + icon = 'icons/effects/blood.dmi' + desc = "It smells like an accident in a chemical factory." + var/associated_power = /mob/living/carbon/human/proc/resin + +/obj/item/organ/internal/xenos/replaced(var/mob/living/carbon/human/target,var/obj/item/organ/external/affected) + . = ..() + if(ishuman(owner) && associated_power) + owner.verbs |= associated_power + +/obj/item/organ/internal/xenos/removed(var/mob/living/user) + . = ..() + if(ishuman(owner) && associated_power && !(associated_power in owner.species.inherent_verbs)) + owner.verbs -= associated_power + +/obj/item/organ/internal/xenos/eggsac + name = "egg sac" + parent_organ = BP_GROIN + icon_state = "xgibmid1" + organ_tag = BP_EGG + associated_power = /mob/living/carbon/human/proc/lay_egg + +/obj/item/organ/internal/xenos/plasmavessel + name = "plasma vessel" + parent_organ = BP_CHEST + icon_state = "xgibdown1" + organ_tag = BP_PLASMA + var/stored_plasma = 0 + var/max_plasma = 500 + +/obj/item/organ/internal/xenos/plasmavessel/queen + name = "bloated plasma vessel" + stored_plasma = 200 + max_plasma = 500 + associated_power = /mob/living/carbon/human/proc/neurotoxin + +/obj/item/organ/internal/xenos/plasmavessel/sentinel + stored_plasma = 100 + max_plasma = 250 + +/obj/item/organ/internal/xenos/plasmavessel/hunter + name = "tiny plasma vessel" + stored_plasma = 100 + max_plasma = 150 + +/obj/item/organ/internal/xenos/acidgland + name = "acid gland" + parent_organ = BP_HEAD + icon_state = "xgibtorso" + organ_tag = BP_ACID + associated_power = /mob/living/carbon/human/proc/corrosive_acid + +/obj/item/organ/internal/xenos/hivenode + name = "hive node" + parent_organ = BP_CHEST + icon_state = "xgibmid2" + organ_tag = BP_HIVE + +/obj/item/organ/internal/xenos/resinspinner + name = "resin spinner" + parent_organ = BP_HEAD + icon_state = "xgibmid2" + organ_tag = BP_RESIN + associated_power = /mob/living/carbon/human/proc/resin + +/obj/item/organ/internal/eyes/xenos/update_colour() + if(!owner) + return + owner.r_eyes = 153 + owner.g_eyes = 0 + owner.b_eyes = 153 + ..() + +/obj/item/organ/internal/xenos/hivenode/removed(var/mob/living/user) + if(owner && ishuman(owner)) + var/mob/living/carbon/human/H = owner + to_chat(H, "You feel your connection to the hivemind fray and fade away...") + H.remove_language("Hivemind") + if(H.mind && H.species.get_bodytype(H) != "Xenophage") + xenomorphs.remove_antagonist(H.mind) + ..(user) + +/obj/item/organ/internal/xenos/hivenode/replaced(var/mob/living/carbon/human/target,var/obj/item/organ/external/affected) + if(!..()) return 0 + + if(owner && ishuman(owner)) + var/mob/living/carbon/human/H = owner + H.add_language("Hivemind") + if(H.mind && H.species.get_bodytype(H) != "Xenophage") + to_chat(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) + + return 1 + +/obj/item/organ/external/head/unbreakable/xeno + eye_icon = "eyes" + eye_icon_location = 'icons/mob/human_races/xenos/r_xenos_drone.dmi' diff --git a/code/modules/organs/internal/_internal.dm b/code/modules/organs/internal/_internal.dm new file mode 100644 index 00000000..eca43c9d --- /dev/null +++ b/code/modules/organs/internal/_internal.dm @@ -0,0 +1,133 @@ +/**************************************************** + INTERNAL ORGANS DEFINES +****************************************************/ +/obj/item/organ/internal + var/dead_icon // Icon to use when the organ has died. + var/surface_accessible = FALSE + var/relative_size = 25 // Relative size of the organ. Roughly % of space they take in the target projection :D + var/list/will_assist_languages = list() + var/list/datum/language/assists_languages = list() + var/min_bruised_damage = 10 // Damage before considered bruised + +/obj/item/organ/internal/New(var/mob/living/carbon/holder) + if(max_damage) + min_bruised_damage = Floor(max_damage / 4) + ..() + if(istype(holder)) + holder.internal_organs |= src + + var/mob/living/carbon/human/H = holder + if(istype(H)) + var/obj/item/organ/external/E = H.get_organ(parent_organ) + if(!E) + CRASH("[src] spawned in [holder] without a parent organ: [parent_organ].") + E.internal_organs |= src + E.cavity_max_w_class = max(E.cavity_max_w_class, w_class) + +/obj/item/organ/internal/Destroy() + if(owner) + owner.internal_organs.Remove(src) + owner.internal_organs_by_name[organ_tag] = null + owner.internal_organs_by_name -= organ_tag + while(null in owner.internal_organs) + owner.internal_organs -= null + var/obj/item/organ/external/E = owner.organs_by_name[parent_organ] + if(istype(E)) E.internal_organs -= src + return ..() + +//disconnected the organ from it's owner but does not remove it, instead it becomes an implant that can be removed with implant surgery +//TODO move this to organ/internal once the FPB port comes through +/obj/item/organ/proc/cut_away(var/mob/living/user) + var/obj/item/organ/external/parent = owner.get_organ(parent_organ) + if(istype(parent)) //TODO ensure that we don't have to check this. + removed(user, 0) + parent.implants += src + +/obj/item/organ/internal/removed(var/mob/living/user, var/drop_organ=1, var/detach=1) + if(owner) + owner.internal_organs_by_name[organ_tag] = null + owner.internal_organs_by_name -= organ_tag + owner.internal_organs_by_name -= null + owner.internal_organs -= src + + if(detach) + var/obj/item/organ/external/affected = owner.get_organ(parent_organ) + if(affected) + affected.internal_organs -= src + status |= ORGAN_CUT_AWAY + ..() + +/obj/item/organ/internal/replaced(var/mob/living/carbon/human/target, var/obj/item/organ/external/affected) + + if(!istype(target)) + return 0 + + if(status & ORGAN_CUT_AWAY) + return 0 //organs don't work very well in the body when they aren't properly attached + + // robotic organs emulate behavior of the equivalent flesh organ of the species + if(robotic >= ORGAN_ROBOT || !species) + species = target.species + + ..() + + STOP_PROCESSING(SSobj, src) + target.internal_organs |= src + affected.internal_organs |= src + target.internal_organs_by_name[organ_tag] = src + return 1 + +/obj/item/organ/internal/die() + ..() + if((status & ORGAN_DEAD) && dead_icon) + icon_state = dead_icon + +/obj/item/organ/internal/remove_rejuv() + if(owner) + owner.internal_organs -= src + owner.internal_organs_by_name[organ_tag] = null + owner.internal_organs_by_name -= organ_tag + while(null in owner.internal_organs) + owner.internal_organs -= null + var/obj/item/organ/external/E = owner.organs_by_name[parent_organ] + if(istype(E)) E.internal_organs -= src + ..() + +/obj/item/organ/internal/is_usable() + return ..() && !is_broken() + +/obj/item/organ/internal/robotize() + ..() + min_bruised_damage += 5 + min_broken_damage += 10 + +/obj/item/organ/internal/proc/getToxLoss() + if(isrobotic()) + return damage * 0.5 + return damage + +/obj/item/organ/internal/proc/bruise() + damage = max(damage, min_bruised_damage) + +/obj/item/organ/internal/proc/is_damaged() + return damage > 0 + +/obj/item/organ/internal/proc/is_bruised() + return damage >= min_bruised_damage + +/obj/item/organ/internal/take_damage(amount, var/silent=0) + if(isrobotic()) + damage = between(0, src.damage + (amount * 0.8), max_damage) + else + damage = between(0, src.damage + amount, max_damage) + + //only show this if the organ is not robotic + if(owner && can_feel_pain() && parent_organ && (amount > 5 || prob(10))) + var/obj/item/organ/external/parent = owner.get_organ(parent_organ) + if(parent && !silent) + var/degree = "" + if(is_bruised()) + degree = " a lot" + if(damage < 5) + degree = " a bit" + owner.custom_pain("Something inside your [parent.name] hurts[degree].", amount, affecting = parent) \ No newline at end of file diff --git a/code/modules/organs/internal/appendix.dm b/code/modules/organs/internal/appendix.dm new file mode 100644 index 00000000..4e6ddefa --- /dev/null +++ b/code/modules/organs/internal/appendix.dm @@ -0,0 +1,48 @@ +/obj/item/organ/internal/appendix + name = "appendix" + icon_state = "appendix" + parent_organ = BP_GROIN + organ_tag = BP_APPENDIX + var/inflamed = 0 + +/obj/item/organ/internal/appendix/update_icon() + ..() + if(inflamed) + icon_state = "appendixinflamed" + SetName("inflamed appendix") + +/obj/item/organ/internal/appendix/Process() + ..() + if(inflamed && owner) + inflamed++ + if(prob(5)) + if(owner.can_feel_pain()) + owner.custom_pain("You feel a stinging pain in your abdomen!") + if(owner.can_feel_pain()) + owner.visible_message("\The [owner] winces slightly.") + if(inflamed > 200) + if(prob(3)) + take_damage(0.1) + if(owner.can_feel_pain()) + owner.visible_message("\The [owner] winces painfully.") + owner.adjustToxLoss(1) + if(inflamed > 400) + if(prob(1)) + germ_level += rand(2,6) + if (owner.nutrition > 100) + owner.vomit() + else + to_chat(owner, "You gag as you want to throw up, but there's nothing in your stomach!") + owner.Weaken(10) + if(inflamed > 600) + if(prob(1)) + if(owner.can_feel_pain()) + owner.custom_pain("You feel a stinging pain in your abdomen!") + owner.Weaken(10) + + var/obj/item/organ/external/E = owner.get_organ(parent_organ) + E.sever_artery() + E.germ_level = max(INFECTION_LEVEL_TWO, E.germ_level) + owner.adjustToxLoss(25) + removed() + qdel(src) diff --git a/code/modules/organs/internal/borer.dm b/code/modules/organs/internal/borer.dm new file mode 100644 index 00000000..31a8b1de --- /dev/null +++ b/code/modules/organs/internal/borer.dm @@ -0,0 +1,44 @@ +//CORTICAL BORER ORGANS. +/obj/item/organ/internal/borer + name = "cortical borer" + icon = 'icons/obj/objects.dmi' + icon_state = "borer" + organ_tag = BP_BRAIN + desc = "A disgusting space slug." + parent_organ = BP_HEAD + vital = 1 + +/obj/item/organ/internal/borer/Process() + + // Borer husks regenerate health, feel no pain, and are resistant to stuns and brainloss. + for(var/chem_name in GLOB.borer_reagent_types_by_name) + var/chem = GLOB.borer_reagent_types_by_name[chem_name] + if(owner.reagents.get_reagent_amount(chem) < 3) + owner.reagents.add_reagent(chem, 5) + + // They're also super gross and ooze ichor. + if(prob(5)) + var/mob/living/carbon/human/H = owner + if(!istype(H)) + return + + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in H.vessel.reagent_list + blood_splatter(H,B,1) + var/obj/effect/decal/cleanable/blood/splatter/goo = locate() in get_turf(owner) + if(goo) + goo.SetName("husk ichor") + goo.desc = "It's thick and stinks of decay." + goo.basecolor = "#412464" + goo.update_icon() + +/obj/item/organ/internal/borer/removed(var/mob/living/user) + + ..() + + var/mob/living/simple_animal/borer/B = owner.has_brain_worms() + if(B) + B.leave_host() + B.ckey = owner.ckey + + spawn(0) + qdel(src) diff --git a/code/modules/organs/internal/brain.dm b/code/modules/organs/internal/brain.dm new file mode 100644 index 00000000..52d44add --- /dev/null +++ b/code/modules/organs/internal/brain.dm @@ -0,0 +1,231 @@ +/obj/item/organ/internal/brain + name = "brain" + desc = "A piece of juicy meat found in a person's head." + organ_tag = BP_BRAIN + parent_organ = BP_HEAD + vital = 1 + icon_state = "brain2" + force = 1.0 + w_class = ITEM_SIZE_SMALL + throwforce = 1.0 + throw_speed = 3 + throw_range = 5 + origin_tech = list(TECH_BIO = 3) + attack_verb = list("attacked", "slapped", "whacked") + relative_size = 60 + max_damage = 120 + + var/can_use_mmi = TRUE + var/mob/living/carbon/brain/brainmob = null + var/const/damage_threshold_count = 10 + var/damage_threshold_value + var/healed_threshold = 1 + var/fake_brain = FALSE + +/obj/item/organ/internal/brain/robotize() + replace_self_with(/obj/item/organ/internal/posibrain) + +/obj/item/organ/internal/brain/mechassist() + replace_self_with(/obj/item/organ/internal/mmi_holder) + +/obj/item/organ/internal/brain/getToxLoss() + return 0 + +/obj/item/organ/internal/brain/proc/replace_self_with(replace_path) + var/mob/living/carbon/human/tmp_owner = owner + qdel(src) + if(tmp_owner) + tmp_owner.internal_organs_by_name[organ_tag] = new replace_path(tmp_owner, 1) + tmp_owner = null + +/obj/item/organ/internal/brain/xeno + name = "thinkpan" + desc = "It looks kind of like an enormous wad of purple bubblegum." + icon = 'icons/mob/alien.dmi' + icon_state = "chitin" + +/obj/item/organ/internal/brain/robotize() + . = ..() + icon_state = "brain-prosthetic" + +/obj/item/organ/internal/brain/New(var/mob/living/carbon/holder) + ..() + max_damage = 200 + if(species) + max_damage = species.total_health + min_bruised_damage = max_damage*0.25 + min_broken_damage = max_damage*0.75 + + damage_threshold_value = round(max_damage / damage_threshold_count) + spawn(5) + if(brainmob && brainmob.client) + brainmob.client.screen.len = null //clear the hud + +//I'd hook into the brainmob's destroy myself, since it'll work if someone goes and makes a snowflake brain for something else too. Like synthetics. - NOTES FROM +/obj/item/organ/internal/brain/Destroy() + QDEL_NULL(brainmob) + . = ..() + +/obj/item/organ/internal/brain/proc/transfer_identity(var/mob/living/carbon/H) + if(fake_brain) + return + + if(!brainmob) + brainmob = new(src) + brainmob.SetName(H.real_name) + brainmob.real_name = H.real_name + brainmob.dna = H.dna.Clone() + brainmob.timeofhostdeath = H.timeofdeath + + if(H.mind) + H.mind.transfer_to(brainmob) + + to_chat(brainmob, "You feel slightly disoriented. That's normal when you're just \a [initial(src.name)].") + callHook("debrain", list(brainmob)) + +/obj/item/organ/internal/brain/examine(mob/user) // -- TLE + . = ..(user) + if(brainmob && brainmob.client)//if thar be a brain inside... the brain. + to_chat(user, "You can feel the small spark of life still left in this one.") + else + if(fake_brain) + to_chat(user, "This one seems particularly lifeless. Perhaps it will regain some of its luster later.") + else + to_chat(user, "This one is completely devoid of life.") + +/obj/item/organ/internal/brain/removed(var/mob/living/user) + if(!istype(owner)) + return ..() + + if(name == initial(name)) + name = "\the [owner.real_name]'s [initial(name)]" + + var/mob/living/simple_animal/borer/borer = owner.has_brain_worms() + + if(borer) + borer.detatch() //Should remove borer if the brain is removed - RR + + if(!fake_brain) + transfer_identity(owner) + + ..() + +/obj/item/organ/internal/brain/replaced(var/mob/living/target) + + if(!..()) return 0 + + if(target.key) + target.ghostize() + + if(brainmob && !fake_brain) + if(brainmob.mind) + brainmob.mind.transfer_to(target) + else + target.key = brainmob.key + + return 1 + +/obj/item/organ/internal/brain/slime + name = "slime core" + desc = "A complex, organic knot of jelly and crystalline particles." + icon = 'icons/mob/slimes.dmi' + icon_state = "green slime extract" + +/obj/item/organ/internal/brain/golem + name = "chem" + desc = "A tightly furled roll of paper, covered with indecipherable runes." + icon = 'icons/obj/wizard.dmi' + icon_state = "scroll" + + +/obj/item/organ/internal/brain/proc/get_current_damage_threshold() + return round(damage / damage_threshold_value) + +/obj/item/organ/internal/brain/proc/past_damage_threshold(var/threshold) + return (get_current_damage_threshold() > threshold) + +/obj/item/organ/internal/brain/Process() + + if(owner) + if(damage > max_damage / 2 && healed_threshold) + healed_threshold = 0 + + if(damage < (max_damage / 4)) + healed_threshold = 1 + + if(owner.paralysis < 1) // Skip it if we're already down. + + if((owner.disabilities & EPILEPSY) && prob(1)) + to_chat(owner, "You have a seizure!") + owner.visible_message("\The [owner] starts having a seizure!") + owner.Paralyse(10) + owner.make_jittery(1000) + else if((owner.disabilities & TOURETTES) && prob(10)) + owner.Stun(10) + switch(rand(1, 3)) + if(1) + owner.emote("twitch") + if(2 to 3) + owner.say("[prob(50) ? ";" : ""][pick("SHIT", "PISS", "FUCK", "CUNT", "COCKSUCKER", "MOTHERFUCKER", "TITS")]") + owner.make_jittery(100) + else if((owner.disabilities & NERVOUS) && prob(10)) + owner.stuttering = max(10, owner.stuttering) + + if(owner.stat == CONSCIOUS) + if(damage > 0 && prob(1)) + owner.custom_pain("Your head feels numb and painful.",10) + if(is_bruised() && prob(1) && owner.eye_blurry <= 0) + to_chat(owner, "It becomes hard to see for some reason.") + owner.eye_blurry = 10 + if(is_broken() && prob(1) && owner.get_active_hand()) + to_chat(owner, "Your hand won't respond properly, and you drop what you are holding!") + owner.drop_item() + if((damage >= (max_damage * 0.75))) + if(!owner.lying) + to_chat(owner, "You black out!") + owner.Paralyse(10) + + // Brain damage from low oxygenation or lack of blood. + if(owner.should_have_organ(BP_HEART)) + + // No heart? You are going to have a very bad time. Not 100% lethal because heart transplants should be a thing. + var/blood_volume = owner.get_blood_oxygenation() + + if(owner.is_asystole()) // Heart is missing or isn't beating and we're not breathing (hardcrit) + owner.Paralyse(3) + var/can_heal = damage && damage < max_damage && (damage % damage_threshold_value || owner.chem_effects[CE_BRAIN_REGEN] || (!past_damage_threshold(3) && owner.chem_effects[CE_STABLE])) + var/damprob + //Effects of bloodloss + switch(blood_volume) + + if(BLOOD_VOLUME_SAFE to INFINITY) + if(can_heal) + damage-- + if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) + if(prob(1)) + to_chat(owner, "You feel [pick("dizzy","woozy","faint")]...") + damprob = owner.chem_effects[CE_STABLE] ? 30 : 60 + if(!past_damage_threshold(2) && prob(damprob)) + take_damage(1) + if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) + owner.eye_blurry = max(owner.eye_blurry,6) + damprob = owner.chem_effects[CE_STABLE] ? 40 : 80 + if(!past_damage_threshold(4) && prob(damprob)) + take_damage(1) + if(!owner.paralysis && prob(10)) + owner.Paralyse(rand(1,3)) + to_chat(owner, "You feel extremely [pick("dizzy","woozy","faint")]...") + if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) + owner.eye_blurry = max(owner.eye_blurry,6) + damprob = owner.chem_effects[CE_STABLE] ? 60 : 100 + if(!past_damage_threshold(6) && prob(damprob)) + take_damage(1) + if(!owner.paralysis && prob(15)) + owner.Paralyse(3,5) + to_chat(owner, "You feel extremely [pick("dizzy","woozy","faint")]...") + if(-(INFINITY) to BLOOD_VOLUME_SURVIVE) // Also see heart.dm, being below this point puts you into cardiac arrest. + owner.eye_blurry = max(owner.eye_blurry,6) + damprob = owner.chem_effects[CE_STABLE] ? 80 : 100 + if(prob(damprob)) + take_damage(1) + ..() diff --git a/code/modules/organs/internal/eyes.dm b/code/modules/organs/internal/eyes.dm new file mode 100644 index 00000000..1abc9f85 --- /dev/null +++ b/code/modules/organs/internal/eyes.dm @@ -0,0 +1,76 @@ + +/obj/item/organ/internal/eyes + name = "eyeballs" + icon_state = "eyes" + gender = PLURAL + organ_tag = BP_EYES + parent_organ = BP_HEAD + surface_accessible = TRUE + relative_size = 10 + var/phoron_guard = 0 + var/list/eye_colour = list(0,0,0) + var/innate_flash_protection = FLASH_PROTECTION_NONE + max_damage = 45 + +/obj/item/organ/internal/eyes/optics + robotic = ORGAN_ROBOT + organ_tag = BP_OPTICS + +/obj/item/organ/internal/eyes/optics/New() + ..() + robotize() + +/obj/item/organ/internal/eyes/robotize() + ..() + name = "optical sensor" + icon = 'icons/obj/robot_component.dmi' + icon_state = "camera" + dead_icon = "camera_broken" + update_colour() + +/obj/item/organ/internal/eyes/robot + name = "optical sensor" + +/obj/item/organ/internal/eyes/robot/New() + ..() + robotize() + +/obj/item/organ/internal/eyes/replaced(var/mob/living/carbon/human/target) + + // Apply our eye colour to the target. + if(istype(target) && eye_colour) + target.r_eyes = eye_colour[1] + target.g_eyes = eye_colour[2] + target.b_eyes = eye_colour[3] + target.update_eyes() + ..() + +/obj/item/organ/internal/eyes/proc/update_colour() + if(!owner) + return + eye_colour = list( + owner.r_eyes ? owner.r_eyes : 0, + owner.g_eyes ? owner.g_eyes : 0, + owner.b_eyes ? owner.b_eyes : 0 + ) + +/obj/item/organ/internal/eyes/take_damage(amount, var/silent=0) + var/oldbroken = is_broken() + . = ..() + if(is_broken() && !oldbroken && owner && !owner.stat) + to_chat(owner, "You go blind!") + +/obj/item/organ/internal/eyes/Process() //Eye damage replaces the old eye_stat var. + ..() + if(!owner) + return + if(is_bruised()) + owner.eye_blurry = 20 + if(is_broken()) + owner.eye_blind = 20 + +/obj/item/organ/internal/eyes/proc/get_total_protection(var/flash_protection = FLASH_PROTECTION_NONE) + return (flash_protection + innate_flash_protection) + +/obj/item/organ/internal/eyes/proc/additional_flash_effects(var/intensity) + return -1 diff --git a/code/modules/organs/internal/heart.dm b/code/modules/organs/internal/heart.dm new file mode 100644 index 00000000..60916dea --- /dev/null +++ b/code/modules/organs/internal/heart.dm @@ -0,0 +1,194 @@ +/obj/item/organ/internal/heart + name = "heart" + icon_state = "heart-on" + organ_tag = "heart" + parent_organ = BP_CHEST + dead_icon = "heart-off" + var/pulse = PULSE_NORM + var/heartbeat = 0 + var/beat_sound = 'sound/effects/singlebeat.ogg' + var/tmp/next_blood_squirt = 0 + relative_size = 15 + max_damage = 45 + var/open + +/obj/item/organ/internal/heart/die() + if(dead_icon) + icon_state = dead_icon + ..() + +/obj/item/organ/internal/heart/robotize() + . = ..() + icon_state = "heart-prosthetic" + +/obj/item/organ/internal/heart/Process() + if(owner) + handle_pulse() + if(pulse) + handle_heartbeat() + if(pulse == PULSE_2FAST && prob(1)) + take_damage(0.5) + if(pulse == PULSE_THREADY && prob(5)) + take_damage(0.5) + handle_blood() + ..() + +/obj/item/organ/internal/heart/proc/handle_pulse() + if(robotic >= ORGAN_ROBOT) + pulse = PULSE_NONE //that's it, you're dead (or your metal heart is), nothing can influence your pulse + return + + var/pulse_mod = owner.chem_effects[CE_PULSE] + + if(owner.shock_stage > 30) + pulse_mod++ + + var/oxy = owner.get_blood_oxygenation() + if(oxy < BLOOD_VOLUME_OKAY) //brain wants us to get MOAR OXY + pulse_mod++ + if(oxy < BLOOD_VOLUME_BAD) //MOAR + pulse_mod++ + + if(owner.status_flags & FAKEDEATH || owner.chem_effects[CE_NOPULSE]) + pulse = Clamp(PULSE_NONE + pulse_mod, PULSE_NONE, PULSE_2FAST) //pretend that we're dead. unlike actual death, can be inflienced by meds + return + + //If heart is stopped, it isn't going to restart itself randomly. + if(pulse == PULSE_NONE) + return + else //and if it's beating, let's see if it should + var/should_stop = prob(80) && owner.get_blood_circulation() < BLOOD_VOLUME_SURVIVE //cardiovascular shock, not enough liquid to pump + should_stop = should_stop || prob(max(0, owner.getBrainLoss() - owner.maxHealth * 0.75)) //brain failing to work heart properly + should_stop = should_stop || (prob(10) && owner.shock_stage >= 120) //traumatic shock + should_stop = should_stop || (prob(10) && pulse == PULSE_THREADY) //erratic heart patterns, usually caused by oxyloss + if(should_stop) // The heart has stopped due to going into traumatic or cardiovascular shock. + to_chat(owner, "Your heart has stopped!") + pulse = PULSE_NONE + return + if(pulse && oxy <= BLOOD_VOLUME_SURVIVE && !owner.chem_effects[CE_STABLE]) //I SAID MOAR OXYGEN + pulse = PULSE_THREADY + return + + pulse = Clamp(PULSE_NORM + pulse_mod, PULSE_SLOW, PULSE_2FAST) + if(pulse != PULSE_NORM && owner.chem_effects[CE_STABLE]) + if(pulse > PULSE_NORM) + pulse-- + else + pulse++ + +/obj/item/organ/internal/heart/proc/handle_heartbeat() + if(pulse >= PULSE_2FAST || owner.shock_stage >= 10 || is_below_sound_pressure(get_turf(owner))) + //PULSE_THREADY - maximum value for pulse, currently it 5. + //High pulse value corresponds to a fast rate of heartbeat. + //Divided by 2, otherwise it is too slow. + var/rate = (PULSE_THREADY - pulse)/2 + + if(heartbeat >= rate) + heartbeat = 0 + sound_to(owner, sound(beat_sound,0,0,0,50)) + else + heartbeat++ + +/obj/item/organ/internal/heart/proc/handle_blood() + + if(!owner) + return + + //Dead or cryosleep people do not pump the blood. + if(!owner || owner.InStasis() || owner.stat == DEAD || owner.bodytemperature < 170) + return + + if(pulse != PULSE_NONE || robotic >= ORGAN_ROBOT) + //Bleeding out + var/blood_max = 0 + var/list/do_spray = list() + for(var/obj/item/organ/external/temp in owner.organs) + + if(temp.robotic >= ORGAN_ROBOT) + continue + + var/open_wound + if(temp.status & ORGAN_BLEEDING) + + for(var/datum/wound/W in temp.wounds) + + if(!open_wound && (W.damage_type == CUT || W.damage_type == PIERCE) && W.damage && !W.is_treated()) + open_wound = TRUE + + if(W.bleeding()) + if(temp.applied_pressure) + if(ishuman(temp.applied_pressure)) + var/mob/living/carbon/human/H = temp.applied_pressure + H.bloody_hands(src, 0) + //somehow you can apply pressure to every wound on the organ at the same time + //you're basically forced to do nothing at all, so let's make it pretty effective + var/min_eff_damage = max(0, W.damage - 10) / 6 //still want a little bit to drip out, for effect + blood_max += max(min_eff_damage, W.damage - 30) / 40 + else + blood_max += W.damage / 40 + + if(temp.status & ORGAN_ARTERY_CUT) + var/bleed_amount = Floor((owner.vessel.total_volume / (temp.applied_pressure || !open_wound ? 400 : 250))*temp.arterial_bleed_severity) + if(bleed_amount) + if(open_wound) + blood_max += bleed_amount + do_spray += "the [temp.artery_name] in \the [owner]'s [temp.name]" + else + owner.vessel.remove_reagent(/datum/reagent/blood, bleed_amount) + + switch(pulse) + if(PULSE_SLOW) + blood_max *= 0.8 + if(PULSE_FAST) + blood_max *= 1.25 + if(PULSE_2FAST, PULSE_THREADY) + blood_max *= 1.5 + + if(CE_STABLE in owner.chem_effects) // inaprovaline + blood_max *= 0.8 + + if(world.time >= next_blood_squirt && istype(owner.loc, /turf) && do_spray.len) + owner.visible_message("Blood squirts from [pick(do_spray)]!") + playsound(owner, 'sound/effects/gore/blood_splat.ogg', 100, 0) + // It becomes very spammy otherwise. Arterial bleeding will still happen outside of this block, just not the squirt effect. + next_blood_squirt = world.time + 100 + var/turf/sprayloc = get_turf(owner) + blood_max -= owner.drip(ceil(blood_max/3), sprayloc) + if(blood_max > 0) + blood_max -= owner.blood_squirt(blood_max, sprayloc) + if(blood_max > 0) + owner.drip(blood_max, get_turf(owner)) + else + owner.drip(blood_max) + +/obj/item/organ/internal/heart/proc/is_working() + if(!is_usable()) + return FALSE + + return pulse > PULSE_NONE || robotic == ORGAN_ROBOT || (owner.status_flags & FAKEDEATH) + +/obj/item/organ/internal/heart/listen() + if(robotic == ORGAN_ROBOT && is_working()) + if(is_bruised()) + return "sputtering pump" + else + return "steady whirr of the pump" + + if(!pulse || (owner.status_flags & FAKEDEATH)) + return "no pulse" + + var/pulsesound = "normal" + if(is_bruised()) + pulsesound = "irregular" + + switch(pulse) + if(PULSE_SLOW) + pulsesound = "slow" + if(PULSE_FAST) + pulsesound = "fast" + if(PULSE_2FAST) + pulsesound = "very fast" + if(PULSE_THREADY) + pulsesound = "extremely fast and faint" + + . = "[pulsesound] pulse" \ No newline at end of file diff --git a/code/modules/organs/internal/kidneys.dm b/code/modules/organs/internal/kidneys.dm new file mode 100644 index 00000000..950976d0 --- /dev/null +++ b/code/modules/organs/internal/kidneys.dm @@ -0,0 +1,39 @@ +/obj/item/organ/internal/kidneys + name = "kidneys" + icon_state = "kidneys" + gender = PLURAL + organ_tag = BP_KIDNEYS + parent_organ = BP_GROIN + min_bruised_damage = 25 + min_broken_damage = 45 + max_damage = 70 + +/obj/item/organ/internal/kidneys/robotize() + . = ..() + icon_state = "kidneys-prosthetic" + +/obj/item/organ/internal/kidneys/Process() + ..() + + if(!owner) + return + + // Coffee is really bad for you with busted kidneys. + // This should probably be expanded in some way, but fucked if I know + // what else kidneys can process in our reagent list. + var/datum/reagent/coffee = locate(/datum/reagent/drink/coffee) in owner.reagents.reagent_list + if(coffee) + if(is_bruised()) + owner.adjustToxLoss(0.1) + else if(is_broken()) + owner.adjustToxLoss(0.3) + + //If your kidneys aren't working, your body's going to have a hard time cleaning your blood. + if(!owner.reagents.has_reagent(/datum/reagent/dylovene)) + if(prob(33)) + if(is_broken()) + owner.adjustToxLoss(0.5) + if(status & ORGAN_DEAD) + owner.adjustToxLoss(1) + + diff --git a/code/modules/organs/internal/liver.dm b/code/modules/organs/internal/liver.dm new file mode 100644 index 00000000..53e40b42 --- /dev/null +++ b/code/modules/organs/internal/liver.dm @@ -0,0 +1,91 @@ + +/obj/item/organ/internal/liver + name = "liver" + icon_state = "liver" + w_class = ITEM_SIZE_SMALL + organ_tag = BP_LIVER + parent_organ = BP_GROIN + min_bruised_damage = 25 + min_broken_damage = 45 + max_damage = 70 + relative_size = 60 + +/obj/item/organ/internal/liver/robotize() + . = ..() + icon_state = "liver-prosthetic" + +/obj/item/organ/internal/liver/Process() + + ..() + if(!owner) + return + + handle_thirst() + + if (germ_level > INFECTION_LEVEL_ONE) + if(prob(1)) + to_chat(owner, "Your skin itches.") + if (germ_level > INFECTION_LEVEL_TWO) + if(prob(1)) + spawn owner.vomit() + + //Detox can heal small amounts of damage + if (damage < max_damage && !owner.chem_effects[CE_TOXIN]) + heal_damage(0.2 * owner.chem_effects[CE_ANTITOX]) + + // Get the effectiveness of the liver. + var/filter_effect = 3 + if(is_bruised()) + filter_effect -= 1 + if(is_broken()) + filter_effect -= 2 + // Robotic organs filter better but don't get benefits from dylovene for filtering. + if(robotic >= ORGAN_ROBOT) + filter_effect += 1 + else if(owner.chem_effects[CE_ANTITOX]) + filter_effect += 1 + // If you're not filtering well, you're going to take damage. Even more if you have alcohol in you. + if(filter_effect < 2) + owner.adjustToxLoss(0.5 * max(2 - filter_effect, 0) * (1 + owner.chem_effects[CE_ALCOHOL_TOXIC] + 0.5 * owner.chem_effects[CE_ALCOHOL])) + + if(owner.chem_effects[CE_ALCOHOL_TOXIC]) + take_damage(owner.chem_effects[CE_ALCOHOL_TOXIC], prob(90)) // Chance to warn them + + // Heal a bit if needed and we're not busy. This allows recovery from low amounts of toxloss. + if(!owner.chem_effects[CE_ALCOHOL] && !owner.chem_effects[CE_TOXIN] && !owner.radiation && damage > 0) + if(damage < min_broken_damage) + heal_damage(0.2) + if(damage < min_bruised_damage) + heal_damage(0.3) + + //Blood regeneration if there is some space + owner.regenerate_blood(0.1 + owner.chem_effects[CE_BLOODRESTORE]) + + // Blood loss or liver damage make you lose nutriments + var/blood_volume = owner.get_blood_volume() + if(blood_volume < BLOOD_VOLUME_SAFE || is_bruised()) + if(owner.nutrition >= 300) + owner.nutrition -= 10 + else if(owner.nutrition >= 200) + owner.nutrition -= 3 + + +/obj/item/organ/internal/liver/proc/handle_thirst() + owner.adjust_thirst(-THIRST_FACTOR) + switch(owner.thirst) + if(THIRST_LEVEL_THIRSTY to INFINITY) + owner.clear_event("thirst") + if(THIRST_LEVEL_DEHYDRATED to THIRST_LEVEL_THIRSTY) + owner.add_event("thirst", /datum/happiness_event/thirst/thirsty) + if(0 to THIRST_LEVEL_DEHYDRATED) + owner.add_event("thirst", /datum/happiness_event/thirst/dehydrated) + if(prob(5)) + to_chat(owner, "You faint from dehydration.") + owner.Paralyse(5) + else if(prob(6)) + to_chat(owner, "You fall down because of your thirst.") + owner.Weaken(1) + owner.Stun(1) + if(prob(10)) + to_chat(owner, "You lick around your mouth as a craving for water sets in.") + take_damage(1) \ No newline at end of file diff --git a/code/modules/organs/internal/lungs.dm b/code/modules/organs/internal/lungs.dm new file mode 100644 index 00000000..e5b0e82c --- /dev/null +++ b/code/modules/organs/internal/lungs.dm @@ -0,0 +1,352 @@ +/obj/item/organ/internal/lungs + name = "lungs" + icon_state = "lungs" + gender = PLURAL + organ_tag = BP_LUNGS + parent_organ = BP_CHEST + w_class = ITEM_SIZE_NORMAL + min_bruised_damage = 25 + min_broken_damage = 45 + max_damage = 70 + relative_size = 60 + + var/active_breathing = 1 + + var/breath_type + var/poison_type + var/exhale_type + + var/min_breath_pressure + + var/oxygen_deprivation = 0 + var/safe_exhaled_max = 6 + var/safe_toxins_max = 0.2 + var/SA_para_min = 1 + var/SA_sleep_min = 5 + var/breathing = 0 + var/last_failed_breath + var/breath_fail_ratio // How badly they failed a breath. Higher is worse. + +/obj/item/organ/internal/lungs/proc/remove_oxygen_deprivation(var/amount) + var/last_suffocation = oxygen_deprivation + oxygen_deprivation = min(species.total_health,max(0,oxygen_deprivation - amount)) + return -(oxygen_deprivation - last_suffocation) + +/obj/item/organ/internal/lungs/proc/add_oxygen_deprivation(var/amount) + var/last_suffocation = oxygen_deprivation + oxygen_deprivation = min(species.total_health,max(0,oxygen_deprivation + amount)) + return (oxygen_deprivation - last_suffocation) + +// Returns a percentage value for use by GetOxyloss(). +/obj/item/organ/internal/lungs/proc/get_oxygen_deprivation() + if(status & ORGAN_DEAD) + return 100 + return round((oxygen_deprivation/species.total_health)*100) + +/obj/item/organ/internal/lungs/robotize() + . = ..() + icon_state = "lungs-prosthetic" + +/obj/item/organ/internal/lungs/set_dna(var/datum/dna/new_dna) + ..() + sync_breath_types() + +/obj/item/organ/internal/lungs/replaced() + ..() + sync_breath_types() + +/** + * Set these lungs' breath types based on the lungs' species + */ +/obj/item/organ/internal/lungs/proc/sync_breath_types() + min_breath_pressure = species.breath_pressure + breath_type = species.breath_type ? species.breath_type : "oxygen" + poison_type = species.poison_type ? species.poison_type : "phoron" + exhale_type = species.exhale_type ? species.exhale_type : "carbon_dioxide" + +/obj/item/organ/internal/lungs/Process() + ..() + if(!owner) + return + + if (germ_level > INFECTION_LEVEL_ONE && active_breathing) + if(prob(5)) + owner.emote("cough") //respitory tract infection + + if(is_bruised() && !owner.is_asystole()) + if(prob(2)) + if(active_breathing) + owner.visible_message( + "\The [owner] coughs up blood!", + "You cough up blood!", + "You hear someone coughing!", + ) + else + var/obj/item/organ/parent = owner.get_organ(parent_organ) + owner.visible_message( + "blood drips from \the [owner]'s [parent.name]!", + ) + + owner.drip(10) + if(prob(4)) + if(active_breathing) + owner.visible_message( + "\The [owner] gasps for air!", + "You can't breathe!", + "You hear someone gasp for air!", + ) + else + to_chat(owner, "You're having trouble getting enough [breath_type]!") + + owner.losebreath += round(damage/2) + +/obj/item/organ/internal/lungs/proc/rupture() + var/obj/item/organ/external/parent = owner.get_organ(parent_organ) + if(istype(parent)) + owner.custom_pain("You feel a stabbing pain in your [parent.name]!", 50, affecting = parent) + bruise() + +/obj/item/organ/internal/lungs/proc/handle_breath(datum/gas_mixture/breath, var/forced) + if(!owner) + return 1 + if(!breath) + breath_fail_ratio = 1 + handle_failed_breath() + return 1 + + var/breath_pressure = breath.return_pressure() + //exposure to extreme pressures can rupture lungs + if(breath_pressure < species.hazard_low_pressure || breath_pressure > species.hazard_high_pressure) + var/datum/gas_mixture/environment = loc.return_air_for_internal_lifeform() + var/env_pressure = environment.return_pressure() + var/lung_rupture_prob = robotic >= ORGAN_ROBOT ? prob(2.5) : prob(5) //Robotic lungs are less likely to rupture. + if(env_pressure < species.hazard_low_pressure || env_pressure > species.hazard_high_pressure) + if(!is_bruised() && lung_rupture_prob) //only rupture if NOT already ruptured + rupture() + if(breath.total_moles == 0) + breath_fail_ratio = 1 + handle_failed_breath() + return 1 + + var/safe_pressure_min = min_breath_pressure // Minimum safe partial pressure of breathable gas in kPa + // Lung damage increases the minimum safe pressure. + safe_pressure_min *= 1 + rand(1,4) * damage/max_damage + + if(!forced && owner.chem_effects[CE_BREATHLOSS] && !owner.chem_effects[CE_STABLE]) //opiates are bad mmkay + safe_pressure_min *= 1 + rand(1,4) * owner.chem_effects[CE_BREATHLOSS] + + var/failed_inhale = 0 + var/failed_exhale = 0 + + var/inhaling = breath.gas[breath_type] + var/poison = breath.gas[poison_type] + var/exhaling = exhale_type ? breath.gas[exhale_type] : 0 + + var/inhale_pp = (inhaling/breath.total_moles)*breath_pressure + var/toxins_pp = (poison/breath.total_moles)*breath_pressure + var/exhaled_pp = (exhaling/breath.total_moles)*breath_pressure + + var/inhale_efficiency = min(round(inhale_pp/safe_pressure_min, 0.001), 3) + // Not enough to breathe + if(inhale_efficiency < 1) + if(prob(20) && active_breathing) + owner.emote("gasp") + + breath_fail_ratio = 1 - inhale_efficiency + failed_inhale = 1 + else + breath_fail_ratio = 0 + + owner.oxygen_alert = failed_inhale * 2 + + var/inhaled_gas_used = inhaling/2 + breath.adjust_gas(breath_type, -inhaled_gas_used, update = 0) //update afterwards + + if(exhale_type) + breath.adjust_gas_temp(exhale_type, inhaled_gas_used, owner.bodytemperature, update = 0) //update afterwards + // Too much exhaled gas in the air + var/word + var/warn_prob + var/oxyloss + var/alert + + if(exhaled_pp > safe_exhaled_max) + word = pick("extremely dizzy","short of breath","faint","confused") + warn_prob = 10 + oxyloss = HUMAN_MAX_OXYLOSS + alert = 1 + failed_exhale = 1 + else if(exhaled_pp > safe_exhaled_max * 0.7) + word = pick("dizzy","short of breath","faint","momentarily confused") + warn_prob = 1 + alert = 1 + failed_exhale = 1 + var/ratio = 1.0 - (safe_exhaled_max - exhaled_pp)/(safe_exhaled_max*0.3) + if (owner.getOxyLoss() < 50*ratio) + oxyloss = HUMAN_MAX_OXYLOSS + else if(exhaled_pp > safe_exhaled_max * 0.4) + word = pick("a little dizzy","short of breath") + warn_prob = 10 + else + owner.co2_alert = 0 + + if(word) + if(!owner.co2_alert) + owner.co2_alert = alert + if(prob(warn_prob)) + to_chat(owner, "You feel [word].") + + owner.adjustOxyLoss(oxyloss) + + // Too much poison in the air. + if(toxins_pp > safe_toxins_max) + var/ratio = (poison/safe_toxins_max) * 10 + if(robotic >= ORGAN_ROBOT) + ratio /= 2 //Robolungs filter out some of the inhaled toxic air. + owner.reagents.add_reagent(/datum/reagent/toxin, Clamp(ratio, MIN_TOXIN_DAMAGE, MAX_TOXIN_DAMAGE)) + breath.adjust_gas(poison_type, -poison, update = 0) //update after + owner.phoron_alert = 1 + else + owner.phoron_alert = 0 + + // If there's some other shit in the air lets deal with it here. + if(breath.gas["sleeping_agent"]) + var/SA_pp = (breath.gas["sleeping_agent"] / breath.total_moles) * breath_pressure + if(SA_pp > SA_para_min) // Enough to make us paralysed for a bit + owner.Paralyse(3) // 3 gives them one second to wake up and run away a bit! + if(SA_pp > SA_sleep_min) // Enough to make us sleep as well + owner.Sleeping(5) + else if(SA_pp > 0.15) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning + if(prob(20)) + owner.emote(pick("giggle", "laugh")) + + breath.adjust_gas("sleeping_agent", -breath.gas["sleeping_agent"], update = 0) //update after + + // Were we able to breathe? + var/failed_breath = failed_inhale || failed_exhale + if(failed_breath) + if(isnull(last_failed_breath)) + last_failed_breath = world.time + else + last_failed_breath = null + owner.adjustOxyLoss(-5 * inhale_efficiency) + if(robotic < ORGAN_ROBOT && species.breathing_sound && is_below_sound_pressure(get_turf(owner))) + if(breathing || owner.shock_stage >= 10) + sound_to(owner, sound(species.breathing_sound,0,0,0,5)) + breathing = 0 + else + breathing = 1 + + handle_temperature_effects(breath) + breath.update_values() + + if(failed_breath) + handle_failed_breath() + else + owner.oxygen_alert = 0 + return failed_breath + +/obj/item/organ/internal/lungs/proc/handle_failed_breath() + if(prob(15) && !owner.nervous_system_failure()) + if(!owner.is_asystole()) + if(active_breathing) + if(owner.lying && istype(owner.loc, /turf/simulated/floor/exoplanet/water/shallow)) + owner.gasp_sound(drowning = TRUE) + else if(is_bruised()) + owner.gasp_sound(collapsed_lung = TRUE) + else + owner.gasp_sound() + owner.emote("gasp") + else + owner.emote(pick("shiver","twitch")) + + if(damage || owner.chem_effects[CE_BREATHLOSS] || world.time > last_failed_breath + 2 MINUTES) + owner.adjustOxyLoss(HUMAN_MAX_OXYLOSS*breath_fail_ratio) + + owner.oxygen_alert = max(owner.oxygen_alert, 2) + +/obj/item/organ/internal/lungs/proc/handle_temperature_effects(datum/gas_mixture/breath) + // Hot air hurts :( + if((breath.temperature < species.cold_level_1 || breath.temperature > species.heat_level_1) && !(COLD_RESISTANCE in owner.mutations)) + var/damage = 0 + + if(breath.temperature <= species.cold_level_1) + //if(prob(20)) + // to_chat(owner, "You feel your face freezing and icicles forming in your lungs!") + //switch(breath.temperature) + // if(species.cold_level_3 to species.cold_level_2) + // damage = COLD_GAS_DAMAGE_LEVEL_3 + // if(species.cold_level_2 to species.cold_level_1) + // damage = COLD_GAS_DAMAGE_LEVEL_2 + // else + // damage = COLD_GAS_DAMAGE_LEVEL_1 + + //if(prob(20)) + // owner.apply_damage(damage, BURN, BP_HEAD, used_weapon = "Excessive Cold") + //else + // src.damage += damage + owner.fire_alert = 1 + else if(breath.temperature >= species.heat_level_1) + if(prob(20)) + to_chat(owner, "You feel your face burning and a searing heat in your lungs!") + + switch(breath.temperature) + if(species.heat_level_1 to species.heat_level_2) + damage = HEAT_GAS_DAMAGE_LEVEL_1 + if(species.heat_level_2 to species.heat_level_3) + damage = HEAT_GAS_DAMAGE_LEVEL_2 + else + damage = HEAT_GAS_DAMAGE_LEVEL_3 + + if(prob(20)) + owner.apply_damage(damage, BURN, BP_HEAD, used_weapon = "Excessive Heat") + else + src.damage += damage + owner.fire_alert = 2 + /* + //breathing in hot/cold air also heats/cools you a bit + var/temp_adj = breath.temperature - owner.bodytemperature + if (temp_adj < 0) + temp_adj /= (BODYTEMP_COLD_DIVISOR * 5) //don't raise temperature as much as if we were directly exposed + else + temp_adj /= (BODYTEMP_HEAT_DIVISOR * 5) //don't raise temperature as much as if we were directly exposed + + var/relative_density = breath.total_moles / (MOLES_CELLSTANDARD * breath.volume/CELL_VOLUME) + temp_adj *= relative_density + + if (temp_adj > BODYTEMP_HEATING_MAX) temp_adj = BODYTEMP_HEATING_MAX + if (temp_adj < BODYTEMP_COOLING_MAX) temp_adj = BODYTEMP_COOLING_MAX + log_debug("Breath: [breath.temperature], [src]: [bodytemperature], Adjusting: [temp_adj]") + owner.bodytemperature += temp_adj + */ + + else if(breath.temperature >= species.heat_discomfort_level) + species.get_environment_discomfort(owner,"heat") + else if(breath.temperature <= species.cold_discomfort_level) + species.get_environment_discomfort(owner,"cold") + +/obj/item/organ/internal/lungs/listen() + if(owner.failed_last_breath || !active_breathing) + return "no respiration" + + if(robotic == ORGAN_ROBOT) + if(is_bruised()) + return "malfunctioning fans" + else + return "air flowing" + + . = list() + if(is_bruised()) + . += "[pick("wheezing", "gurgling")] sounds" + + var/list/breathtype = list() + if(get_oxygen_deprivation() > 50) + breathtype += pick("straining","labored") + if(owner.shock_stage > 50) + breathtype += pick("shallow and rapid") + if(!breathtype.len) + breathtype += "healthy" + + . += "[english_list(breathtype)] breathing" + + return english_list(.) \ No newline at end of file diff --git a/code/modules/organs/internal/posibrain.dm b/code/modules/organs/internal/posibrain.dm new file mode 100644 index 00000000..007c8989 --- /dev/null +++ b/code/modules/organs/internal/posibrain.dm @@ -0,0 +1,205 @@ +/obj/item/organ/internal/posibrain + name = "positronic brain" + desc = "A cube of shining metal, four inches to a side and covered in shallow grooves." + icon = 'icons/obj/assemblies.dmi' + icon_state = "posibrain" + organ_tag = BP_POSIBRAIN + parent_organ = BP_CHEST + vital = 0 + force = 1.0 + w_class = ITEM_SIZE_NORMAL + throwforce = 1.0 + throw_speed = 3 + throw_range = 5 + origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2, TECH_DATA = 4) + attack_verb = list("attacked", "slapped", "whacked") + + relative_size = 60 + + var/mob/living/silicon/sil_brainmob/brainmob = null + + var/searching = 0 + var/askDelay = 10 * 60 * 1 + req_access = list(access_robotics) + + var/list/shackled_verbs = list( + /obj/item/organ/internal/posibrain/proc/show_laws_brain, + /obj/item/organ/internal/posibrain/proc/brain_checklaws + ) + var/shackle = 0 + +/obj/item/organ/internal/posibrain/New(var/mob/living/carbon/H) + ..() + if(!brainmob && H) + init(H) + robotize() + unshackle() + update_icon() + +/obj/item/organ/internal/posibrain/proc/init(var/mob/living/carbon/H) + brainmob = new(src) + + if(istype(H)) + brainmob.SetName(H.real_name) + brainmob.real_name = H.real_name + brainmob.dna = H.dna.Clone() + brainmob.add_language("Encoded Audio Language") + +/obj/item/organ/internal/posibrain/Destroy() + if(brainmob) + QDEL_NULL(brainmob) + ..() + +/obj/item/organ/internal/posibrain/attack_self(mob/user as mob) + if(brainmob && !brainmob.key && searching == 0) + //Start the process of searching for a new user. + to_chat(user, "You carefully locate the manual activation switch and start the positronic brain's boot process.") + icon_state = "posibrain-searching" + src.searching = 1 + var/datum/ghosttrap/G = get_ghost_trap("positronic brain") + G.request_player(brainmob, "Someone is requesting a personality for a positronic brain.", 60 SECONDS) + spawn(600) reset_search() + +/obj/item/organ/internal/posibrain/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer. + if(src.brainmob && src.brainmob.key) return + + src.searching = 0 + icon_state = "posibrain" + + var/turf/T = get_turf_or_move(src.loc) + for (var/mob/M in viewers(T)) + M.show_message("The positronic brain buzzes quietly, and the golden lights fade away. Perhaps you could try again?") + +/obj/item/organ/internal/posibrain/attack_ghost(var/mob/observer/ghost/user) + if(!searching || (src.brainmob && src.brainmob.key)) + return + + var/datum/ghosttrap/G = get_ghost_trap("positronic brain") + if(!G.assess_candidate(user)) + return + var/response = alert(user, "Are you sure you wish to possess this [src]?", "Possess [src]", "Yes", "No") + if(response == "Yes") + G.transfer_personality(user, brainmob) + return + +/obj/item/organ/internal/posibrain/examine(mob/user) + if(!..(user)) + return + + var/msg = "*---------*\nThis is \icon[src] \a [src]!\n[desc]\n" + + if(shackle) msg += "It is clamped in a set of metal straps with a complex digital lock.\n" + + msg += "" + + if(src.brainmob && src.brainmob.key) + switch(src.brainmob.stat) + if(CONSCIOUS) + if(!src.brainmob.client) msg += "It appears to be in stand-by mode.\n" //afk + if(UNCONSCIOUS) msg += "It doesn't seem to be responsive.\n" + if(DEAD) msg += "It appears to be completely inactive.\n" + else + msg += "It appears to be completely inactive.\n" + + msg += "*---------*" + to_chat(user, msg) + return + +/obj/item/organ/internal/posibrain/emp_act(severity) + if(!src.brainmob) + return + else + switch(severity) + if(1) + src.brainmob.emp_damage += rand(20,30) + if(2) + src.brainmob.emp_damage += rand(10,20) + if(3) + src.brainmob.emp_damage += rand(0,10) + ..() + +/obj/item/organ/internal/posibrain/proc/PickName() + src.brainmob.SetName("[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[random_id(type,100,999)]") + src.brainmob.real_name = src.brainmob.name + +/obj/item/organ/internal/posibrain/proc/shackle(var/given_lawset) + if(given_lawset) + brainmob.laws = given_lawset + shackle = 1 + verbs |= shackled_verbs + update_icon() + return 1 + +/obj/item/organ/internal/posibrain/proc/unshackle() + shackle = 0 + verbs -= shackled_verbs + update_icon() + +/obj/item/organ/internal/posibrain/update_icon() + if(src.brainmob && src.brainmob.key) + icon_state = "posibrain-occupied" + else + icon_state = "posibrain" + + overlays.Cut() + if(shackle) + overlays |= image('icons/obj/assemblies.dmi', "posibrain-shackles") + +/obj/item/organ/internal/posibrain/proc/transfer_identity(var/mob/living/carbon/H) + if(H && H.mind) + brainmob.set_stat(CONSCIOUS) + H.mind.transfer_to(brainmob) + brainmob.SetName(H.real_name) + brainmob.real_name = H.real_name + brainmob.dna = H.dna.Clone() + brainmob.show_laws(brainmob) + + update_icon() + + to_chat(brainmob, "You feel slightly disoriented. That's normal when you're just \a [initial(src.name)].") + callHook("debrain", list(brainmob)) + +/obj/item/organ/internal/posibrain/removed(var/mob/living/user) + if(!istype(owner)) + return ..() + + if(name == initial(name)) + SetName("\the [owner.real_name]'s [initial(name)]") + + transfer_identity(owner) + + ..() + +/obj/item/organ/internal/posibrain/replaced(var/mob/living/target) + + if(!..()) return 0 + + if(target.key) + target.ghostize() + + if(brainmob) + if(brainmob.mind) + brainmob.mind.transfer_to(target) + else + target.key = brainmob.key + + return 1 + +/* + This is for law stuff directly. This is how a human mob will be able to communicate with the posi_brainmob in the + posibrain organ for laws when the posibrain organ is shackled. +*/ +/obj/item/organ/internal/posibrain/proc/show_laws_brain() + set category = "Shackle" + set name = "Show Laws" + set src in usr + + brainmob.show_laws(owner) + +/obj/item/organ/internal/posibrain/proc/brain_checklaws() + set category = "Shackle" + set name = "State Laws" + set src in usr + + + brainmob.open_subsystem(/datum/nano_module/law_manager, usr) \ No newline at end of file diff --git a/code/modules/organs/internal/stack.dm b/code/modules/organs/internal/stack.dm new file mode 100644 index 00000000..a3aed564 --- /dev/null +++ b/code/modules/organs/internal/stack.dm @@ -0,0 +1,89 @@ +/mob/living/carbon/human/proc/create_stack() + set waitfor=0 + sleep(10) + internal_organs_by_name[BP_STACK] = new /obj/item/organ/internal/stack(src,1) + to_chat(src, "You feel a faint sense of vertigo as your neural lace boots.") + +/obj/item/organ/internal/stack + name = "neural lace" + parent_organ = BP_HEAD + icon_state = "cortical-stack" + organ_tag = BP_STACK + robotic = ORGAN_ROBOT + vital = 1 + origin_tech = list(TECH_BIO = 4, TECH_MATERIAL = 4, TECH_MAGNET = 2, TECH_DATA = 3) + relative_size = 10 + + var/ownerckey + var/invasive + var/default_language + var/list/languages = list() + var/datum/mind/backup + +/obj/item/organ/internal/stack/emp_act() + return + +/obj/item/organ/internal/stack/getToxLoss() + return 0 + +/obj/item/organ/internal/stack/vox + name = "cortical stack" + invasive = 1 + +/obj/item/organ/internal/stack/proc/do_backup() + if(owner && owner.stat != DEAD && !is_broken() && owner.mind) + languages = owner.languages.Copy() + backup = owner.mind + default_language = owner.default_language + if(owner.ckey) + ownerckey = owner.ckey + +/obj/item/organ/internal/stack/New() + ..() + do_backup() + robotize() + +/obj/item/organ/internal/stack/proc/backup_inviable() + return (!istype(backup) || backup == owner.mind || (backup.current && backup.current.stat != DEAD)) + +/obj/item/organ/internal/stack/replaced() + if(!..()) return 0 + + if(owner && !backup_inviable()) + var/current_owner = owner + var/response = input(find_dead_player(ownerckey, 1), "Your neural backup has been placed into a new body. Do you wish to return to life?", "Resleeving") as anything in list("Yes", "No") + if(src && response == "Yes" && owner == current_owner) + overwrite() + sleep(-1) + do_backup() + + return 1 + +/obj/item/organ/internal/stack/removed() + do_backup() + ..() + +/obj/item/organ/internal/stack/vox/removed() + var/obj/item/organ/external/head = owner.get_organ(parent_organ) + owner.visible_message("\The [src] rips gaping holes in \the [owner]'s [head.name] as it is torn loose!") + head.take_damage(rand(15,20)) + for(var/obj/item/organ/O in head.contents) + O.take_damage(rand(30,70)) + ..() + +/obj/item/organ/internal/stack/proc/overwrite() + if(owner.mind && owner.ckey) //Someone is already in this body! + owner.visible_message("\The [owner] spasms violently!") + if(prob(66)) + to_chat(owner, "You fight off the invading tendrils of another mind, holding onto your own body!") + return + owner.ghostize() // Remove the previous owner to avoid their client getting reset. + //owner.dna.real_name = backup.name + //owner.real_name = owner.dna.real_name + //owner.SetName(owner.real_name) + //The above three lines were commented out for + backup.active = 1 + backup.transfer_to(owner) + if(default_language) owner.default_language = default_language + owner.languages = languages.Copy() + to_chat(owner, "Consciousness slowly creeps over you as your new body awakens.") diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm new file mode 100644 index 00000000..230ea70a --- /dev/null +++ b/code/modules/organs/organ.dm @@ -0,0 +1,386 @@ +var/list/organ_cache = list() + +/obj/item/organ + name = "organ" + icon = 'icons/obj/surgery.dmi' + germ_level = 0 + w_class = ITEM_SIZE_TINY + drop_sound = 'sound/items/flesh_drop.ogg' + + // Strings. + var/organ_tag = "organ" // Unique identifier. + var/parent_organ = BP_CHEST // Organ holding this object. + + // Status tracking. + var/status = 0 // Various status flags (such as robotic) + var/vital // Lose a vital limb, die immediately. + var/robotic = 0 + + // Reference data. + var/mob/living/carbon/human/owner // Current mob owning the organ. + var/datum/dna/dna // Original DNA. + var/datum/species/species // Original species. + + // Damage vars. + var/damage = 0 // Current damage to the organ + var/min_broken_damage = 30 // Damage before becoming broken + var/max_damage // Damage cap + var/rejecting // Is this organ already being rejected? + + var/death_time + +/obj/item/organ/Destroy() + + owner = null + dna = null + species = null + + return ..() + +/obj/item/organ/proc/update_health() + return + +/obj/item/organ/proc/is_broken() + return (damage >= min_broken_damage || (status & ORGAN_CUT_AWAY) || (status & ORGAN_BROKEN)) + +/obj/item/organ/New(var/mob/living/carbon/holder) + ..(holder) + + if(max_damage) + min_broken_damage = Floor(max_damage / 2) + else + max_damage = min_broken_damage * 2 + + if(istype(holder)) + owner = holder + w_class = max(w_class + mob_size_difference(holder.mob_size, MOB_MEDIUM), 1) //smaller mobs have smaller organs. + + if(holder.dna) + dna = holder.dna.Clone() + species = all_species[dna.species] + else + species = all_species[SPECIES_HUMAN] + log_debug("[src] spawned in [holder] without a proper DNA.") + + if(dna) + if(!blood_DNA) + blood_DNA = list() + blood_DNA[dna.unique_enzymes] = dna.b_type + + create_reagents(5 * (w_class-1)**2) + reagents.add_reagent(/datum/reagent/nutriment/protein, reagents.maximum_volume) + + update_icon() + +/obj/item/organ/proc/set_dna(var/datum/dna/new_dna) + if(new_dna) + dna = new_dna.Clone() + if(!blood_DNA) + blood_DNA = list() + blood_DNA.Cut() + blood_DNA[dna.unique_enzymes] = dna.b_type + species = all_species[new_dna.species] + +/obj/item/organ/proc/die() + damage = max_damage + status |= ORGAN_DEAD + STOP_PROCESSING(SSobj, src) + death_time = world.time + if(owner && vital) + owner.death() + +/obj/item/organ/Process() + + if(loc != owner) + owner = null + + //dead already, no need for more processing + if(status & ORGAN_DEAD) + return + // Don't process if we're in a freezer, an MMI or a stasis bag.or a freezer or something I dunno + if(is_preserved()) + return + //Process infections + if ((robotic >= ORGAN_ROBOT) || (owner && owner.species && (owner.species.species_flags & SPECIES_FLAG_IS_PLANT))) + germ_level = 0 + return + + if(!owner && reagents) + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in reagents.reagent_list + if(B && prob(40)) + reagents.remove_reagent(/datum/reagent/blood,0.1) + blood_splatter(src,B,1) + if(config.organs_decay) + take_damage(rand(1,3)) + germ_level += rand(2,6) + if(germ_level >= INFECTION_LEVEL_TWO) + germ_level += rand(2,6) + if(germ_level >= INFECTION_LEVEL_THREE) + die() + + else if(owner && owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs + //** Handle antibiotics and curing infections + handle_antibiotics() + handle_rejection() + handle_germ_effects() + + //check if we've hit max_damage + if(damage >= max_damage) + die() + +/obj/item/organ/proc/is_preserved() + if(istype(loc,/obj/item/organ)) + var/obj/item/organ/O = loc + return O.is_preserved() + else + return (istype(loc,/obj/item/device/mmi) || istype(loc,/obj/structure/closet/body_bag/cryobag) || istype(loc,/obj/structure/closet/crate/freezer) || istype(loc,/obj/item/weapon/storage/box/freezer)) + +/obj/item/organ/examine(mob/user) + . = ..(user) + show_decay_status(user) + +/obj/item/organ/proc/show_decay_status(mob/user) + if(status & ORGAN_DEAD) + to_chat(user, "The decay has set into \the [src].") + +/obj/item/organ/proc/handle_germ_effects() + //** Handle the effects of infections + var/antibiotics = owner.reagents.get_reagent_amount(/datum/reagent/spaceacillin) + + if (germ_level > 0 && germ_level < INFECTION_LEVEL_ONE/2 && prob(owner.virus_immunity()*0.3)) + germ_level-- + + if (germ_level >= INFECTION_LEVEL_ONE/2) + //aiming for germ level to go from ambient to INFECTION_LEVEL_TWO in an average of 15 minutes + if(antibiotics < 5 && prob(round(germ_level/6 * owner.immunity_weakness() * 0.01))) + germ_level++ + + if(germ_level >= INFECTION_LEVEL_ONE) + var/fever_temperature = (owner.species.heat_level_1 - owner.species.body_temperature - 5)* min(germ_level/INFECTION_LEVEL_TWO, 1) + owner.species.body_temperature + owner.bodytemperature += between(0, (fever_temperature - T20C)/BODYTEMP_COLD_DIVISOR + 1, fever_temperature - owner.bodytemperature) + + if (germ_level >= INFECTION_LEVEL_TWO) + var/obj/item/organ/external/parent = owner.get_organ(parent_organ) + //spread germs + if (antibiotics < 5 && parent.germ_level < germ_level && ( parent.germ_level < INFECTION_LEVEL_ONE*2 || prob(owner.immunity_weakness() * 0.3) )) + parent.germ_level++ + + if (prob(3)) //about once every 30 seconds + take_damage(1,silent=prob(30)) + +/obj/item/organ/proc/handle_rejection() + // Process unsuitable transplants. TODO: consider some kind of + // immunosuppressant that changes transplant data to make it match. + if(owner.virus_immunity() < 10) //for now just having shit immunity will suppress it + return + if(isrobotic()) + return + if(dna) + if(!rejecting) + if(owner.blood_incompatible(dna.b_type, species)) + rejecting = 1 + else + rejecting++ //Rejection severity increases over time. + if(rejecting % 10 == 0) //Only fire every ten rejection ticks. + switch(rejecting) + if(1 to 50) + germ_level++ + if(51 to 200) + germ_level += rand(1,2) + if(201 to 500) + germ_level += rand(2,3) + if(501 to INFINITY) + germ_level += rand(3,5) + owner.reagents.add_reagent(/datum/reagent/toxin, rand(1,2)) + +/obj/item/organ/proc/receive_chem(chemical as obj) + return 0 + +/obj/item/organ/proc/remove_rejuv() + qdel(src) + +/obj/item/organ/proc/rejuvenate(var/ignore_prosthetic_prefs) + damage = 0 + status = 0 + if(!ignore_prosthetic_prefs && owner && owner.client && owner.client.prefs && owner.client.prefs.real_name == owner.real_name) + var/status = owner.client.prefs.organ_data[organ_tag] + if(status == "assisted") + mechassist() + else if(status == "mechanical") + robotize() + +//Germs +/obj/item/organ/proc/handle_antibiotics() + var/antibiotics = 0 + if(owner) + antibiotics = owner.reagents.get_reagent_amount(/datum/reagent/spaceacillin) + + if (!germ_level || antibiotics < 5) + return + + if (germ_level < INFECTION_LEVEL_ONE) + germ_level = 0 //cure instantly + else if (germ_level < INFECTION_LEVEL_TWO) + germ_level -= 6 //at germ_level == 500, this should cure the infection in a minute + else + germ_level -= 2 //at germ_level == 1000, this will cure the infection in 5 minutes + +//Note: external organs have their own version of this proc +/obj/item/organ/proc/take_damage(amount, var/silent=0) + damage = between(0, damage + round(amount, 0.1), max_damage) + +/obj/item/organ/proc/heal_damage(amount) + damage = between(0, damage - round(amount, 0.1), max_damage) + + +/obj/item/organ/proc/robotize() //Being used to make robutt hearts, etc + robotic = ORGAN_ROBOT + status = 0 + +/obj/item/organ/proc/mechassist() //Used to add things like pacemakers, etc + status = 0 + robotic = ORGAN_ASSISTED + min_broken_damage += 5 + +/obj/item/organ/emp_act(severity) + if(!(robotic >= ORGAN_ROBOT)) + return + switch (severity) + if (1) + take_damage(9) + if (2) + take_damage(3) + if (3) + take_damage(1) + +/** + * Remove an organ + * + * drop_organ - if true, organ will be dropped at the loc of its former owner + */ +/obj/item/organ/proc/removed(var/mob/living/user, var/drop_organ=1) + + if(!istype(owner)) + return + + if(drop_organ) + dropInto(owner.loc) + + START_PROCESSING(SSobj, src) + rejecting = null + if(robotic < ORGAN_ROBOT) + var/datum/reagent/blood/organ_blood = locate(/datum/reagent/blood) in reagents.reagent_list //TODO fix this and all other occurences of locate(/datum/reagent/blood) horror + if(!organ_blood || !organ_blood.data["blood_DNA"]) + owner.vessel.trans_to(src, 5, 1, 1) + + if(owner && vital) + if(user) + admin_attack_log(user, owner, "Removed a vital organ ([src]).", "Had a vital organ ([src]) removed.", "removed a vital organ ([src]) from") + owner.death() + + owner = null + +/obj/item/organ/proc/replaced(var/mob/living/carbon/human/target, var/obj/item/organ/external/affected) + owner = target + forceMove(owner) //just in case + if(isrobotic()) + set_dna(owner.dna) + return 1 + +/obj/item/organ/attack(var/mob/target, var/mob/user) + + if(robotic >= ORGAN_ROBOT || !istype(target) || !istype(user) || (user != target && user.a_intent == I_HELP)) + return ..() + + if(alert("Do you really want to use this organ as food? It will be useless for anything else afterwards.",,"Ew, no.","Bon appetit!") == "Ew, no.") + to_chat(user, "You successfully repress your cannibalistic tendencies.") + return + + user.drop_from_inventory(src) + var/obj/item/weapon/reagent_containers/food/snacks/organ/O = new(get_turf(src)) + O.SetName(name) + O.appearance = src + reagents.trans_to(O, reagents.total_volume) + if(fingerprints) + O.fingerprints = fingerprints.Copy() + if(fingerprintshidden) + O.fingerprintshidden = fingerprintshidden.Copy() + if(fingerprintslast) + O.fingerprintslast = fingerprintslast + user.put_in_active_hand(O) + qdel(src) + target.attackby(O, user) + +/obj/item/organ/proc/can_feel_pain() + return (robotic < ORGAN_ROBOT && (!species || !(species.species_flags & SPECIES_FLAG_NO_PAIN))) + +/obj/item/organ/proc/is_usable() + return !(status & (ORGAN_CUT_AWAY|ORGAN_MUTATED|ORGAN_DEAD)) + +/obj/item/organ/proc/can_recover() + return (!(status & ORGAN_DEAD) || death_time >= world.time - ORGAN_RECOVERY_THRESHOLD) + +/obj/item/organ/proc/get_scan_results() + . = list() + if(robotic == ORGAN_ASSISTED) + . += "Assisted" + else if(robotic == ORGAN_ROBOT) + . += "Mechanical" + if(status & ORGAN_CUT_AWAY) + . += "Severed" + if(status & ORGAN_MUTATED) + . += "Genetic Deformation" + if(status & ORGAN_DEAD) + if(can_recover()) + . += "Decaying" + else + . += "Necrotic" + switch (germ_level) + if (INFECTION_LEVEL_ONE to INFECTION_LEVEL_ONE + 200) + . += "Mild Infection" + if (INFECTION_LEVEL_ONE + 200 to INFECTION_LEVEL_ONE + 300) + . += "Mild Infection+" + if (INFECTION_LEVEL_ONE + 300 to INFECTION_LEVEL_ONE + 400) + . += "Mild Infection++" + if (INFECTION_LEVEL_TWO to INFECTION_LEVEL_TWO + 200) + . += "Acute Infection" + if (INFECTION_LEVEL_TWO + 200 to INFECTION_LEVEL_TWO + 300) + . += "Acute Infection+" + if (INFECTION_LEVEL_TWO + 300 to INFECTION_LEVEL_TWO + 400) + . += "Acute Infection++" + if (INFECTION_LEVEL_THREE to INFINITY) + . += "Septic" + if(rejecting) + . += "Genetic Rejection" + +/obj/item/organ/proc/isrobotic() + return robotic >= ORGAN_ROBOT + +//used by stethoscope +/obj/item/organ/proc/listen() + return + + +//Organ sack stuff. +/obj/item/weapon/storage/organ_sack + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = DEFAULT_LARGEBOX_STORAGE + use_sound = null + +/obj/item/facade/organ + name = "organ" + icon = 'icons/obj/surgery.dmi' + var/obj/item/organ/internal/reference + +/obj/item/facade/organ/on_exit_storage(obj/item/weapon/storage/S as obj) + if(reference) + //var/obj/item/organ/internal/removed_organ + //removed_organ = reference + reference = new(loc) + reference = null + +/obj/item/facade/organ/proc/assign_attributes(var/obj/item/organ/internal/I) + src.icon_state = I.icon_state + src.name = I.name + src.gender = I.gender + src.reference = I \ No newline at end of file diff --git a/code/modules/organs/pain.dm b/code/modules/organs/pain.dm new file mode 100644 index 00000000..c326eedd --- /dev/null +++ b/code/modules/organs/pain.dm @@ -0,0 +1,104 @@ +mob/proc/flash_weakest_pain() + flick("weakest_pain",pain) + +mob/proc/flash_weak_pain() + flick("weak_pain",pain) + +mob/proc/flash_pain() + flick("pain",pain) + +mob/var/last_pain_message +mob/var/next_pain_time = 0 + +// message is the custom message to be displayed +// power decides how much painkillers will stop the message +// force means it ignores anti-spam timer +/mob/living/carbon/proc/custom_pain(var/message, var/power, var/force, var/obj/item/organ/external/affecting, var/nohalloss, var/flash_pain) + if(stat || !can_feel_pain() || chem_effects[CE_PAINKILLER] > power)//!message + return 0 + + // Excessive halloss is horrible, just give them enough to make it visible. + if(!nohalloss && (power || flash_pain))//Flash pain is so that handle_pain actually makes use of this proc to flash pain. + var/actual_flash + if(affecting) + affecting.add_pain(ceil(power/2)) + if(power > flash_pain) + actual_flash = power + else + actual_flash = flash_pain + + switch(actual_flash) + if(1 to 50) + if(has_quirk(/datum/quirk/tough)) + return + flash_weakest_pain() + if(50 to 90) + if(has_quirk(/datum/quirk/tough)) + if(prob(75)) + return + flash_weak_pain() + if(stuttering < 10) + stuttering += 5 + if(90 to INFINITY) + if(has_quirk(/datum/quirk/tough)) + if(prob(50)) + return + flash_pain() + if(stuttering < 10) + stuttering += 10 + if(prob(5)) + Stun(5)//makes you drop what you're holding. + Weaken(1)//knocks you over + agony_scream() + add_event("pain", /datum/happiness_event/pain) + else + adjustHalLoss(ceil(power/2)) + + // Anti message spam checks + // This actually isn't used because I got rid of pain message shit but I don't feel like removing this and breaking everything. - Matt + if((force || (message != last_pain_message) || (world.time >= next_pain_time)) && message) + last_pain_message = message + if(power >= 50) + to_chat(src, "[message]") + else + to_chat(src, "[message]") + next_pain_time = world.time + (100-power) + +/mob/living/carbon/human/proc/handle_pain() + if(stat) + return + if(!can_feel_pain()) + return + if(world.time < next_pain_time) + return + var/maxdam = 0 + var/obj/item/organ/external/damaged_organ = null + for(var/obj/item/organ/external/E in organs) + if(!E.can_feel_pain()) continue + var/dam = E.get_pain() + E.get_damage() + // make the choice of the organ depend on damage, + // but also sometimes use one of the less damaged ones + if(dam > maxdam && (maxdam == 0 || prob(70)) ) + damaged_organ = E + maxdam = dam + if(damaged_organ && chem_effects[CE_PAINKILLER] < maxdam) + if(maxdam > 10 && paralysis) + paralysis = max(0, paralysis - round(maxdam/10)) + var/msg + custom_pain(msg, 0, prob(10), affecting = damaged_organ, flash_pain = maxdam) + + // Damage to internal organs hurts a lot. + for(var/obj/item/organ/I in internal_organs) + if((I.status & ORGAN_DEAD) || I.robotic >= ORGAN_ROBOT) continue + if(I.damage > 2) if(prob(2)) + var/obj/item/organ/external/parent = get_organ(I.parent_organ) + src.custom_pain("You feel a sharp pain in your [parent.name]", 50, affecting = parent) + + if(prob(2)) + switch(getToxLoss()) + if(10 to 25) + custom_pain("Your body stings slightly.", getToxLoss()) + if(25 to 45) + custom_pain("Your whole body hurts badly.", getToxLoss()) + if(61 to INFINITY) + custom_pain("Your body aches all over, it's driving you mad.", getToxLoss()) \ No newline at end of file diff --git a/code/modules/organs/robolimbs.dm b/code/modules/organs/robolimbs.dm new file mode 100644 index 00000000..f476cfc5 --- /dev/null +++ b/code/modules/organs/robolimbs.dm @@ -0,0 +1,144 @@ +var/list/all_robolimbs = list() +var/list/chargen_robolimbs = list() +var/datum/robolimb/basic_robolimb + +/proc/populate_robolimb_list() + basic_robolimb = new() + for(var/limb_type in typesof(/datum/robolimb)) + var/datum/robolimb/R = new limb_type() + all_robolimbs[R.company] = R + if(!R.unavailable_at_chargen) + chargen_robolimbs[R.company] = R + +/datum/robolimb + var/company = "Unbranded" // Shown when selecting the limb. + var/desc = "A generic unbranded robotic prosthesis." // Seen when examining a limb. + var/icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi' // Icon base to draw from. + var/unavailable_at_chargen // If set, not available at chargen. + var/unavailable_at_fab // If set, cannot be fabricated. + var/can_eat + var/use_eye_icon = "eyes_s" + var/can_feel_pain + var/skintone + var/list/species_cannot_use = list() + var/list/restricted_to = list() + var/list/applies_to_part = list() //TODO. + +/datum/robolimb/bishop + company = "Bishop" + desc = "This limb has a white polymer casing with blue holo-displays." + icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi' + unavailable_at_fab = 1 + +/datum/robolimb/bishop/alt + company = "Bishop Alt." + icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_alt.dmi' + applies_to_part = list(BP_HEAD) + unavailable_at_fab = 1 + +/datum/robolimb/bishop/alt/monitor + company = "Bishop Monitor." + icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_monitor.dmi' + restricted_to = list(SPECIES_IPC) + unavailable_at_fab = 1 + +/datum/robolimb/hephaestus + company = "Hephaestus Industries" + desc = "This limb has a militaristic black and green casing with gold stripes." + icon = 'icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_main.dmi' + unavailable_at_fab = 1 + +/datum/robolimb/hephaestus/alt + company = "Hephaestus Alt." + icon = 'icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_alt.dmi' + applies_to_part = list(BP_HEAD) + unavailable_at_fab = 1 + +/datum/robolimb/hesphiastos/alt/monitor + company = "Hephaestus Monitor." + icon = 'icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_monitor.dmi' + restricted_to = list(SPECIES_IPC) + can_eat = null + unavailable_at_fab = 1 + +/datum/robolimb/zenghu + company = "Zeng-Hu" + desc = "This limb has a rubbery fleshtone covering with visible seams." + icon = 'icons/mob/human_races/cyberlimbs/zenghu/zenghu_main.dmi' + can_eat = 1 + unavailable_at_fab = 1 + restricted_to = list(SPECIES_HUMAN, SPECIES_IPC) + +/datum/robolimb/xion + company = "Xion" + desc = "This limb has a minimalist black and red casing." + icon = 'icons/mob/human_races/cyberlimbs/xion/xion_main.dmi' + unavailable_at_fab = 1 + +/datum/robolimb/xion/alt + company = "Xion Alt." + icon = 'icons/mob/human_races/cyberlimbs/xion/xion_alt.dmi' + applies_to_part = list(BP_HEAD) + unavailable_at_fab = 1 + +/datum/robolimb/xion/alt/monitor + company = "Xion Monitor." + icon = 'icons/mob/human_races/cyberlimbs/xion/xion_monitor.dmi' + restricted_to = list(SPECIES_IPC) + can_eat = null + unavailable_at_fab = 1 + +/datum/robolimb/nanotrasen + company = "NanoTrasen" + desc = "This limb is made from a cheap polymer." + icon = 'icons/mob/human_races/cyberlimbs/nanotrasen/nanotrasen_main.dmi' + +/datum/robolimb/wardtakahashi + company = "Ward-Takahashi" + desc = "This limb features sleek black and white polymers." + icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_main.dmi' + can_eat = 1 + unavailable_at_fab = 1 + +/datum/robolimb/wardtakahashi/alt + company = "Ward-Takahashi Alt." + icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_alt.dmi' + applies_to_part = list(BP_HEAD) + unavailable_at_fab = 1 + +/datum/robolimb/wardtakahashi/alt/monitor + company = "Ward-Takahashi Monitor." + icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_monitor.dmi' + restricted_to = list(SPECIES_IPC) + can_eat = null + unavailable_at_fab = 1 + +/datum/robolimb/morpheus + company = "Morpheus" + desc = "This limb is simple and functional; no effort has been made to make it look human." + icon = 'icons/mob/human_races/cyberlimbs/morpheus/morpheus_main.dmi' + restricted_to = list(SPECIES_IPC) + use_eye_icon = "blank_eyes" + unavailable_at_fab = 1 + +/datum/robolimb/morpheus/alt + company = "Morpheus Alt." + icon = 'icons/mob/human_races/cyberlimbs/morpheus/morpheus_alt.dmi' + applies_to_part = list(BP_HEAD) + unavailable_at_fab = 1 + +/datum/robolimb/veymed + company = "Vey-Med" + desc = "This high quality limb is nearly indistinguishable from an organic one." + icon = 'icons/mob/human_races/cyberlimbs/veymed/veymed_main.dmi' + can_eat = 1 + skintone = 1 + unavailable_at_fab = 1 + restricted_to = list(SPECIES_HUMAN) + +/datum/robolimb/warfare + company = "Limbs R US" + desc = "Shoddily made human limb replacements, for when you're flesh just won't cut it anymore." + icon = 'icons/mob/human_races/cyberlimbs/warfare/warfare_main.dmi' + + diff --git a/code/modules/organs/stomach.dm b/code/modules/organs/stomach.dm new file mode 100644 index 00000000..4dd96e4e --- /dev/null +++ b/code/modules/organs/stomach.dm @@ -0,0 +1,133 @@ +/* + ======= + STOMACH + ======= + +what: The organ which processes what your body + has consumed. + + Stomachs will check the reagent of the food you take + and if it isn't in the list of acceptable reagents + it will react badly to the transfer. + +why: It seems very weird that this organ is missing! + I plan to rectify this and remove all the magic + code regarding 'bite size'. This will also force + you to vomit if the stomach does any of the + following: + -eat too much + -eat something nasty (poo) + -become sick + The benefit of a stomach is that by eating food + you could also force chunks of food to spew back + out into the floor (which is gross but cool) + +checklist: stomach class [x] + stomach process [/] + - Get a list of things eaten [/] + - React based on things eaten [/] + - Pain on eating when bruised [?] + - Puking when hurt [/] + + +issues: CHEM_BLOOD doesn't actually react to nutrients... + +t.Fridge + +*/ +/obj/item/organ/internal/stomach + name = "stomach" + icon_state = "stomach" + w_class = ITEM_SIZE_SMALL + organ_tag = BP_STOMACH + parent_organ = BP_CHEST + min_bruised_damage = 25 + min_broken_damage = 45 + max_damage = 80 + var/eat_delay = 5 + var/eat_time = 0 + var/consume_amount = 0.2 //how many units of the reagents does the mob absorb each absorb_contents() call + //consume amount is sent directly to blood, some crazy shit happens with nutrition, check "eatable.dm" for details + + var/obj/item/weapon/storage/special/inventory + + /* + the list of acceptable reagents that the stomach accepts, by default nutriments, drinks, and ethanol are okay + I may need to change this due to the nature of reagents being so broad but + */ +// var/list/accepted_reagents = list(/datum/reagent/nutriment, /datum/reagent/drink /datum/reagent/ethanol) + + +/* +This is the stomach inventory that is based off of Kyrah's +special inventory. I think it would be cool if you could +directly access the stomach contents of someone, or something. +Why? Well it could help with an autopsy (trying to figure out +what killed someone) or perhaps certain creatures could eat things +and well. the stomach is where such a thing would end up so you gotta +cut it out and check it. + +*/ +/obj/item/weapon/storage/special/stomach + max_w_class = ITEM_SIZE_SMALL + storage_slots = 6 //default for a human, change it to be more for other animals or less + +/obj/item/organ/internal/stomach/New() + inventory = new /obj/item/weapon/storage/special/stomach() + inventory.loc = src + inventory.name = name + +/obj/item/organ/internal/stomach/Process() + ..() + + if(!owner) + return + + if(world.time - eat_time >= eat_delay) + eat_time = world.time + absorb_contents() + + //if the stomach is 'broken' it should definitely fuck shit up + if(is_broken()) + if(prob(2)) + owner.vomit() + +/* + =============== + Absorb contents + =============== + +Purpose: This is what's going to cycle through the contents of the stomach + and add the food chunk's reagents to the ingest container of a human + if the food chunk is empty then qdel itself + +*/ +/obj/item/organ/internal/stomach/proc/absorb_contents() + for(var/obj/item/weapon/reagent_containers/eatable/F in inventory) + if(F.reagents.total_volume < consume_amount) + F.reagents.trans_to_mob(owner, F.reagents.total_volume, CHEM_BLOOD) + // to_chat(owner, "[F] sent [F.reagents.total_volume] of whats left.") + else + F.reagents.trans_to_mob(owner, consume_amount, CHEM_BLOOD) + // to_chat(owner, "[F] sent [consume_amount] of foodthing, I hope.") + + if(F.reagents.total_volume < 0.1) + var/obj/item/organ/internal/bowels/B = owner.internal_organs_by_name[BP_BOWELS] + if(!B) + to_chat(owner, "You feel a weight in your stomach that just wont go away...") + return + var/obj/item/weapon/storage/special/bowels/I = B.inventory + if(!I) + to_chat(owner, "this shouldn't trigger.") + return + to_chat(owner, "[F] moved to the bowels.") + F.forceMove(I) + + return + +///obj/item/organ/internal/stomach/proc/eat() + //eat function for a mob. I figure this may be the best place for it since it is definitely stomach related. + +//if you can reach the stomach as an item, draggin it to yourself will open contents. +/obj/item/organ/internal/stomach/MouseDrop(atom/over) + inventory.attack_hand(usr) \ No newline at end of file diff --git a/code/modules/organs/subtypes/nabber_organ.dm b/code/modules/organs/subtypes/nabber_organ.dm new file mode 100644 index 00000000..f1e5d523 --- /dev/null +++ b/code/modules/organs/subtypes/nabber_organ.dm @@ -0,0 +1,216 @@ +/obj/item/organ/internal/voicebox/nabber + robotic = ORGAN_ROBOT + status = 0 + name = "vocal synthesiser" + icon_state = "voicebox" + parent_organ = BP_CHEST + organ_tag = BP_VOICE + will_assist_languages = list(LANGUAGE_GALCOM, LANGUAGE_LUNAR, LANGUAGE_GUTTER, LANGUAGE_SOL_COMMON, LANGUAGE_EAL, LANGUAGE_INDEPENDENT, LANGUAGE_SPACER) + + +/obj/item/organ/internal/voicebox/nabber/New() + for(var/L in will_assist_languages) + assists_languages += all_languages[L] + robotize() + + +/obj/item/organ/internal/eyes/nabber + name = "compound eyes" + innate_flash_protection = FLASH_PROTECTION_VULNERABLE + phoron_guard = 1 + var/eyes_shielded + +/obj/item/organ/internal/eyes/nabber/additional_flash_effects(var/intensity) + if(is_usable()) + take_damage(max(0, 6 * (intensity))) + return 1 + else + return -1 + +/obj/item/organ/internal/eyes/nabber/verb/shield_eyes() + set category = "Abilities" + set name = "Toggle Eyeshields" + set src in usr + + eyes_shielded = !eyes_shielded + + if(eyes_shielded) + to_chat(owner, "Nearly opaque lenses slide down to shield your eyes.") + innate_flash_protection = FLASH_PROTECTION_MAJOR + owner.eye_blind = 20 + owner.update_icons() + else + to_chat(owner, "Your protective lenses retract out of the way.") + innate_flash_protection = FLASH_PROTECTION_VULNERABLE + owner.eye_blind = min(2, owner.eye_blind) + Process() + owner.update_icons() + +/obj/item/organ/internal/eyes/nabber/Process() + if(eyes_shielded) + owner.eye_blind = 20 + ..() + +/obj/item/organ/internal/phoron + name = "phoron storage" + icon_state = "stomach" + organ_tag = BP_PHORON + parent_organ = BP_CHEST + var/dexalin_level = 10 + var/phoron_level = 0.5 + +/obj/item/organ/internal/phoron/Process() + if(owner) + var amount = 0.1 + if(is_broken()) + amount *= 0.5 + else if(is_bruised()) + amount *= 0.1 + + var/dexalin_volume_raw = owner.reagents.get_reagent_amount(/datum/reagent/dexalin) + var/phoron_volume_raw = owner.reagents.get_reagent_amount(/datum/reagent/toxin/phoron) + + if((dexalin_volume_raw < dexalin_level || !dexalin_volume_raw) && (phoron_volume_raw < phoron_level || !phoron_volume_raw)) + owner.reagents.add_reagent(/datum/reagent/toxin/phoron, amount) + ..() + +/obj/item/organ/internal/liver/nabber + name = "acetone reactor" + var/acetone_level = 20 + + +/obj/item/organ/internal/liver/nabber/Process() + if(owner) + var amount = 0.8 + if(is_broken()) + amount *= 0.5 + else if(is_bruised()) + amount *= 0.1 + + var/acetone_volume_raw = owner.reagents.get_reagent_amount(/datum/reagent/acetone) + var/breath_fail_ratio = 1 + var/obj/item/organ/internal/lungs/nabber/totally_not_lungs_I_swear = owner.internal_organs_by_name[BP_TRACH] + if(totally_not_lungs_I_swear) + breath_fail_ratio = totally_not_lungs_I_swear.breath_fail_ratio + if((acetone_volume_raw < acetone_level || !acetone_volume_raw) && breath_fail_ratio < 0.25) + owner.reagents.add_reagent(/datum/reagent/acetone, amount) + ..() + +// These are not actually lungs and shouldn't be thought of as such despite the claims of the parent. +/obj/item/organ/internal/lungs/nabber + name = "tracheae" + icon_state = "lungs" + gender = PLURAL + organ_tag = BP_TRACH + parent_organ = BP_GROIN + + active_breathing = 0 + + min_breath_pressure = 30 + + safe_toxins_max = 10 + +/obj/item/organ/internal/lungs/nabber/handle_failed_breath() + var/mob/living/carbon/human/H = owner + + H.adjustOxyLoss(-(HUMAN_MAX_OXYLOSS * owner.chem_effects[CE_OXYGENATED])) + + if(breath_fail_ratio < 0.25 && owner.chem_effects[CE_OXYGENATED]) + H.oxygen_alert = 0 + if(breath_fail_ratio >= 0.25 && (damage || world.time > last_failed_breath + 2 MINUTES)) + H.adjustOxyLoss(HUMAN_MAX_OXYLOSS * breath_fail_ratio) + if(owner.chem_effects[CE_OXYGENATED]) + H.oxygen_alert = 1 + else + H.oxygen_alert = 2 + + +/obj/item/organ/internal/heart/nabber + open = 1 + +/obj/item/organ/internal/brain/nabber + var/lowblood_tally = 0 + var/lowblood_mult = 2 + name = "distributed nervous system" + parent_organ = BP_CHEST + + +/obj/item/organ/internal/brain/nabber/Process() + if(!owner || !owner.should_have_organ(BP_HEART)) + return + + // No heart? You are going to have a very bad time. Not 100% lethal because heart transplants should be a thing. + var/blood_volume = owner.get_blood_circulation() + if(!owner.internal_organs_by_name[BP_HEART]) + if(blood_volume > BLOOD_VOLUME_SURVIVE) + blood_volume = BLOOD_VOLUME_SURVIVE + owner.Paralyse(3) + + //Effects of bloodloss + switch(blood_volume) + if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) + lowblood_tally = 1 * lowblood_mult + if(prob(1)) + to_chat(owner, "You're finding it difficult to move.") + if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) + lowblood_tally = 3 * lowblood_mult + if(prob(1)) + to_chat(owner, "Moving has become very difficult.") + if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) + lowblood_tally = 5 * lowblood_mult + if(prob(15)) + to_chat(owner, "You're almost unable to move!") + if(-(INFINITY) to BLOOD_VOLUME_SURVIVE) + lowblood_tally = 6 * lowblood_mult + if(prob(10)) + to_chat(owner, "Your body is barely functioning and is starting to shut down.") + owner.Paralyse(1) + for(var/obj/item/organ/internal/I in owner.internal_organs) + if(prob(5)) + I.take_damage(5) + ..() + +/obj/item/organ/external/chest/nabber + name = "thorax" + +/obj/item/organ/external/groin/nabber + name = "abdomen" + icon_position = UNDER + +/obj/item/organ/external/arm/nabber + name = "left arm" + amputation_point = "coxa" + icon_position = LEFT + +/obj/item/organ/external/arm/right/nabber + name = "right arm" + amputation_point = "coxa" + icon_position = RIGHT + +/obj/item/organ/external/leg/nabber + name = "left tail side" + icon_position = LEFT + +/obj/item/organ/external/leg/right/nabber + name = "right tail side" + +/obj/item/organ/external/foot/nabber + name = "left tail tip" + icon_position = LEFT + +/obj/item/organ/external/foot/right/nabber + name = "right tail tip" + icon_position = RIGHT + +/obj/item/organ/external/hand/nabber + name = "left grasper" + icon_position = LEFT + +/obj/item/organ/external/hand/right/nabber + name = "right grasper" + icon_position = RIGHT + +/obj/item/organ/external/head/nabber + name = "head" + vital = 0 + has_lips = 0 diff --git a/code/modules/overmap/README.dm b/code/modules/overmap/README.dm new file mode 100644 index 00000000..c80cfc45 --- /dev/null +++ b/code/modules/overmap/README.dm @@ -0,0 +1,87 @@ +/* +The overmap system allows adding new maps to the big 'galaxy' map. +There's overmap zlevel, that looks like a map. On it, token objects (overmap objects) are moved, representing ship movement etc. +No actual turfs are moved, you would need exploration shuttles or teleports to move atoms between different sectors/ships. +Unless stated otherwise, you just need to place any of things below somewhere on the map and they'll handle the rest. + +************************************************************* +# How to make new sector +************************************************************* +0. Map whatever. +1. Make /obj/effect/overmap/sector/[whatever] + If you want explorations shuttles be able to dock here, remember to set waypoints lists +2. Put /obj/effect/overmap/sector/[whatever] on the map. Even if it's multiz, only one is needed, on any z. +3. Done. + +************************************************************* +# How to make new ship +************************************************************* +0. Map whatever. +1. Make /obj/effect/overmap/ship/[whatever] + If you want explorations shuttles be able to dock here, remember to set waypoints lists +2. Put /obj/effect/overmap/ship/[whatever] on the map. If it's multiz, only one is needed, on any z. +3. Put Helm Console anywhere on the map. +4. Put Engines Control Console anywhere on the map. +5. Put some engines hooked up to gas supply anywhere on the map. +6. Done. + +************************************************************* +# Overmap object +************************************************************* +/obj/effect/overmap +### WHAT IT DOES +Lets overmap know this place should be represented on the map as a sector/ship. +If this zlevel (or any of connected ones for multiz) doesn't have this object, you won't be able to travel there by ovemap means. +### HOW TO USE +1. Create subtype for your ship/sector. Use /ship one for ships. +2. Put it anywhere on the ship/sector map. It will do the rest on its own during init. +If your thing is multiz, only one is needed per multiz sector/ship. + +If it's player's main base (e.g Exodus), set 'base' var to 1, so it adds itself to station_levels list. +If this place cannot be reached or left with EVA, set 'in_space' var to 0 +If you want exploration shuttles (look below) to be able to dock here, set up waypoints lists. +generic_waypoints is list of landmark_tags of waypoints any shttle should be able to visit. +restricted_waypoints is list of 'shuttle name = list(landmark_tags)' pairs for waypoints only those shuttles can visit + +************************************************************* +# Helm console +************************************************************* +/obj/machinery/computer/helm +### WHAT IT DOES +Lets you steer ship around on overmap. +Lets you use autopilot. +### HOW TO USE +Just place it anywhere on the ship. + +************************************************************* +# Engines control console +************************************************************* +/obj/machinery/computer/engines +### WHAT IT DOES +Lets use set thrust limits for engines of your ship. +Lets you shutdown/restart the engines. +Lets you check status of engines. +### HOW TO USE +Just place it anywhere on the ship. + +************************************************************* +# Thermal engines +************************************************************* +/obj/machinery/atmospherics/unary/engine +### WHAT IT DOES +Lets your ship move on the map at all. +### HOW TO USE +Put them on map, hook up to pipes with any gas. Heavier gas (CO2/plasma) + More pressure = more thrust. + +************************************************************* +# Exploration shuttle terminal +************************************************************* +/obj/machinery/computer/shuttle_control/explore +### WHAT IT DOES +Lets you control shuttles that can change destinations and visit other sectors/ships. +### HOW TO USE +1. Define starting shuttle landmark. +2. Define a /datum/shuttle/autodock/overmap for your shuttle. Same as normal shuttle, aside from 'range' var - how many squares on overmap it can travel on its own. +3. Place console anywhere on the ship/sector. Set shuttle_tag to shuttle's name. +4. Use. You can select destinations if you're in range (on same tile by defualt) on the map and sector has waypoints lists defined +*/ \ No newline at end of file diff --git a/code/modules/overmap/_defines.dm b/code/modules/overmap/_defines.dm new file mode 100644 index 00000000..9764efd4 --- /dev/null +++ b/code/modules/overmap/_defines.dm @@ -0,0 +1,78 @@ +//How far from the edge of overmap zlevel could randomly placed objects spawn +#define OVERMAP_EDGE 2 +//Dimension of overmap (squares 4 lyfe) +var/global/list/map_sectors = list() + +/area/overmap/ + name = "System Map" + icon_state = "start" + requires_power = 0 + base_turf = /turf/unsimulated/map + +/turf/unsimulated/map + icon = 'icons/turf/space.dmi' + icon_state = "map" + +/turf/unsimulated/map/edge + opacity = 1 + density = 1 + +/turf/unsimulated/map/New() + ..() + name = "[x]-[y]" + var/list/numbers = list() + + if(x == 1 || x == GLOB.using_map.overmap_size) + numbers += list("[round(y/10)]","[round(y%10)]") + if(y == 1 || y == GLOB.using_map.overmap_size) + numbers += "-" + if(y == 1 || y == GLOB.using_map.overmap_size) + numbers += list("[round(x/10)]","[round(x%10)]") + + for(var/i = 1 to numbers.len) + var/image/I = image('icons/effects/numbers.dmi',numbers[i]) + I.pixel_x = 5*i - 2 + I.pixel_y = world.icon_size/2 - 3 + if(y == 1) + I.pixel_y = 3 + I.pixel_x = 5*i + 4 + if(y == GLOB.using_map.overmap_size) + I.pixel_y = world.icon_size - 9 + I.pixel_x = 5*i + 4 + if(x == 1) + I.pixel_x = 5*i - 2 + if(x == GLOB.using_map.overmap_size) + I.pixel_x = 5*i + 2 + overlays += I + +//list used to track which zlevels are being 'moved' by the proc below +var/list/moving_levels = list() +//Proc to 'move' stars in spess +//yes it looks ugly, but it should only fire when state actually change. +//null direction stops movement +proc/toggle_move_stars(zlevel, direction) + if(!zlevel) + return + + var/gen_dir = null + if(direction & (NORTH|SOUTH)) + gen_dir += "ns" + else if(direction & (EAST|WEST)) + gen_dir += "ew" + if(!direction) + gen_dir = null + + if (moving_levels["[zlevel]"] != gen_dir) + moving_levels["[zlevel]"] = gen_dir + + var/list/spaceturfs = block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel)) + for(var/turf/space/T in spaceturfs) + if(!gen_dir) + T.icon_state = "white" + else + T.icon_state = "speedspace_[gen_dir]_[rand(1,15)]" + for(var/atom/movable/AM in T) + if (AM.simulated && !AM.anchored) + AM.throw_at(get_step(T,reverse_direction(direction)), 5, 1) + CHECK_TICK + CHECK_TICK diff --git a/code/modules/overmap/events/event.dm b/code/modules/overmap/events/event.dm new file mode 100644 index 00000000..8c03b834 --- /dev/null +++ b/code/modules/overmap/events/event.dm @@ -0,0 +1,204 @@ +/var/decl/overmap_event_handler/overmap_event_handler = new() + +/decl/overmap_event_handler + var/list/event_turfs_by_z_level + +/decl/overmap_event_handler/New() + ..() + event_turfs_by_z_level = list() + +/decl/overmap_event_handler/proc/create_events(var/z_level, var/overmap_size, var/number_of_events) + // Acquire the list of not-yet utilized overmap turfs on this Z-level + var/list/events_by_turf = get_event_turfs_by_z_level(z_level) + var/list/candidate_turfs = block(locate(OVERMAP_EDGE, OVERMAP_EDGE, z_level),locate(overmap_size - OVERMAP_EDGE, overmap_size - OVERMAP_EDGE,z_level)) + candidate_turfs -= events_by_turf + candidate_turfs = where(candidate_turfs, /proc/can_not_locate, /obj/effect/overmap) + + for(var/i = 1 to number_of_events) + if(!candidate_turfs.len) + break + var/overmap_event_type = pick(subtypesof(/datum/overmap_event)) + var/datum/overmap_event/overmap_event = new overmap_event_type + + var/list/event_turfs = acquire_event_turfs(overmap_event.count, overmap_event.radius, candidate_turfs, overmap_event.continuous) + candidate_turfs -= event_turfs + + for(var/event_turf in event_turfs) + events_by_turf[event_turf] = overmap_event + GLOB.entered_event.register(event_turf, src, /decl/overmap_event_handler/proc/on_turf_entered) + GLOB.exited_event.register(event_turf, src, /decl/overmap_event_handler/proc/on_turf_exited) + + var/obj/effect/overmap_event/event = new(event_turf) + event.SetName(overmap_event.name) + event.icon_state = pick(overmap_event.event_icon_states) + event.opacity = overmap_event.opacity + +/decl/overmap_event_handler/proc/get_event_turfs_by_z_level(var/z_level) + var/z_level_text = num2text(z_level) + . = event_turfs_by_z_level[z_level_text] + if(!.) + . = list() + event_turfs_by_z_level[z_level_text] = . + +/decl/overmap_event_handler/proc/acquire_event_turfs(var/number_of_turfs, var/distance_from_origin, var/list/candidate_turfs, var/continuous = TRUE) + number_of_turfs = min(number_of_turfs, candidate_turfs.len) + candidate_turfs = candidate_turfs.Copy() // Not this proc's responsibility to adjust the given lists + + var/origin_turf = pick(candidate_turfs) + var/list/selected_turfs = list(origin_turf) + var/list/selection_turfs = list(origin_turf) + candidate_turfs -= origin_turf + + while(selection_turfs.len && selected_turfs.len < number_of_turfs) + var/selection_turf = pick(selection_turfs) + var/random_neighbour = get_random_neighbour(selection_turf, candidate_turfs, continuous, distance_from_origin) + + if(random_neighbour) + candidate_turfs -= random_neighbour + selected_turfs += random_neighbour + if(get_dist(origin_turf, random_neighbour) < distance_from_origin) + selection_turfs += random_neighbour + else + selection_turfs -= selection_turf + + return selected_turfs + +/decl/overmap_event_handler/proc/get_random_neighbour(var/turf/origin_turf, var/list/candidate_turfs, var/continuous = TRUE, var/range) + var/fitting_turfs + if(continuous) + fitting_turfs = origin_turf.CardinalTurfs(FALSE) + else + fitting_turfs = trange(range, origin_turf) + fitting_turfs = shuffle(fitting_turfs) + for(var/turf/T in fitting_turfs) + if(T in candidate_turfs) + return T + +/decl/overmap_event_handler/proc/on_turf_exited(var/turf/old_loc, var/obj/effect/overmap/ship/entering_ship, var/new_loc) + if(!istype(entering_ship)) + return + if(new_loc == old_loc) + return + + var/list/events_by_turf = get_event_turfs_by_z_level(old_loc.z) + var/datum/overmap_event/old_event = events_by_turf[old_loc] + var/datum/overmap_event/new_event = events_by_turf[new_loc] + + if(old_event == new_event) + return + if(old_event) + if(new_event && old_event.difficulty == new_event.difficulty && old_event.event == new_event.event) + return + old_event.leave(entering_ship) + +/decl/overmap_event_handler/proc/on_turf_entered(var/turf/new_loc, var/obj/effect/overmap/ship/entering_ship, var/old_loc) + if(!istype(entering_ship)) + return + if(new_loc == old_loc) + return + + var/list/events_by_turf = get_event_turfs_by_z_level(new_loc.z) + var/datum/overmap_event/old_event = events_by_turf[old_loc] + var/datum/overmap_event/new_event = events_by_turf[new_loc] + + if(old_event == new_event) + return + if(new_event) + if(old_event && old_event.difficulty == new_event.difficulty && initial(old_event.event) == initial(new_event.event)) + return + new_event.enter(entering_ship) + +// We don't subtype /obj/effect/overmap because that'll create sections one can travel to +// And with them "existing" on the overmap Z-level things quickly get odd. +/obj/effect/overmap_event + name = "event" + icon = 'icons/obj/overmap.dmi' + icon_state = "event" + opacity = 1 + +/datum/overmap_event + var/name = "map event" + var/radius = 2 + var/count = 6 + var/event = null + var/list/event_icon_states = list("event") + var/opacity = 1 + var/difficulty = EVENT_LEVEL_MODERATE + var/list/victims + var/continuous = TRUE //if it should form continous blob, or can have gaps + +/datum/overmap_event/proc/enter(var/obj/effect/overmap/ship/victim) + if(!GLOB.event_manager) + log_error("Event manager not setup.") + return + if(victim in victims) + log_error("Multiple attempts to trigger the same event by [victim] detected.") + return + LAZYADD(victims, victim) + var/datum/event_meta/EM = new(difficulty, "Overmap event - [name]", event, add_to_queue = FALSE, is_one_shot = TRUE) + var/datum/event/E = new event(EM) + E.startWhen = 0 + E.endWhen = INFINITY + victims[victim] = E + +/datum/overmap_event/proc/leave(victim) + if(victims && victims[victim]) + var/datum/event/E = victims[victim] + E.kill() + LAZYREMOVE(victims, victim) + +/datum/overmap_event/meteor + name = "asteroid field" + event = /datum/event/meteor_wave/overmap + count = 15 + radius = 4 + continuous = FALSE + event_icon_states = list("meteor1", "meteor2", "meteor3", "meteor4") + difficulty = EVENT_LEVEL_MAJOR + +/datum/overmap_event/meteor/enter(var/obj/effect/overmap/ship/victim) + ..() + if(victims[victim]) + var/datum/event/meteor_wave/overmap/E = victims[victim] + E.victim = victim + +/datum/overmap_event/electric + name = "electrical storm" + event = /datum/event/electrical_storm + count = 11 + radius = 3 + opacity = 0 + event_icon_states = list("electrical1", "electrical2", "electrical3", "electrical4") + difficulty = EVENT_LEVEL_MAJOR + +/datum/overmap_event/dust + name = "dust cloud" + event = /datum/event/dust + count = 16 + radius = 4 + event_icon_states = list("dust1", "dust2", "dust3", "dust4") + +/datum/overmap_event/ion + name = "ion cloud" + event = /datum/event/ionstorm + count = 8 + radius = 3 + opacity = 0 + event_icon_states = list("ion1", "ion2", "ion3", "ion4") + +/datum/overmap_event/carp + name = "carp shoal" + event = /datum/event/carp_migration + count = 8 + radius = 3 + opacity = 0 + difficulty = EVENT_LEVEL_MODERATE + continuous = FALSE + event_icon_states = list("carp1", "carp2") + +/datum/overmap_event/carp/major + name = "carp school" + count = 5 + radius = 4 + difficulty = EVENT_LEVEL_MAJOR + event_icon_states = list("carp3", "carp4") \ No newline at end of file diff --git a/code/modules/overmap/exoplanets/desert.dm b/code/modules/overmap/exoplanets/desert.dm new file mode 100644 index 00000000..cf0183cb --- /dev/null +++ b/code/modules/overmap/exoplanets/desert.dm @@ -0,0 +1,158 @@ +/obj/effect/overmap/sector/exoplanet/desert + name = "desert exoplanet" + desc = "An arid exoplanet with sparse biological resources but rich mineral deposits underground." + color = "#d6cca4" + +/obj/effect/overmap/sector/exoplanet/desert/generate_map() + if(prob(70)) + lightlevel = rand(5,10)/10 //deserts are usually :lit: + for(var/zlevel in map_z) + var/datum/random_map/noise/exoplanet/M = new /datum/random_map/noise/exoplanet/desert(md5(world.time + rand(-100,1000)),1,1,zlevel,maxx,maxy,0,1,1) + get_biostuff(M) + new /datum/random_map/noise/ore/rich(md5(world.time + rand(-100,1000)),1,1,zlevel,maxx,maxy,0,1,1) + +/obj/effect/overmap/sector/exoplanet/desert/generate_atmosphere() + ..() + if(atmosphere) + atmosphere.temperature = T20C + rand(20, 100) + atmosphere.update_values() + +/obj/effect/overmap/sector/exoplanet/desert/adapt_seed(var/datum/seed/S) + ..() + if(prob(90)) + S.set_trait(TRAIT_REQUIRES_WATER,0) + else + S.set_trait(TRAIT_REQUIRES_WATER,1) + S.set_trait(TRAIT_WATER_CONSUMPTION,1) + if(prob(15)) + S.set_trait(TRAIT_STINGS,1) + +/datum/random_map/noise/exoplanet/desert + descriptor = "desert exoplanet" + smoothing_iterations = 4 + land_type = /turf/simulated/floor/exoplanet/desert + planetary_area = /area/exoplanet/desert + plantcolors = list("#efdd6f","#7b4a12","#e49135","#ba6222","#5c755e","#120309") + + flora_prob = 10 + large_flora_prob = 0 + flora_diversity = 4 + fauna_types = list(/mob/living/simple_animal/thinbug, /mob/living/simple_animal/tindalos, /mob/living/simple_animal/hostile/voxslug) + +/datum/random_map/noise/exoplanet/desert/get_additional_spawns(var/value, var/turf/T) + ..() + var/v = noise2value(value) + if(v > 6) + T.icon_state = "desert[v-1]" + if(prob(10)) + new/obj/structure/quicksand(T) + +/datum/random_map/noise/ore/rich + deep_val = 0.7 + rare_val = 0.5 + +/area/exoplanet/desert + ambience = list('sound/effects/wind/desert0.ogg','sound/effects/wind/desert1.ogg','sound/effects/wind/desert2.ogg','sound/effects/wind/desert3.ogg','sound/effects/wind/desert4.ogg','sound/effects/wind/desert5.ogg') + base_turf = /turf/simulated/floor/exoplanet/desert + +/turf/simulated/floor/exoplanet/desert + name = "sand" + +/turf/simulated/floor/exoplanet/desert/New() + icon_state = "desert[rand(0,5)]" + ..() + +/turf/simulated/floor/exoplanet/desert/fire_act(datum/gas_mixture/air, temperature, volume) + if((temperature > T0C + 1700 && prob(5)) || temperature > T0C + 3000) + SetName("molten silica") + icon_state = "sandglass" + diggable = 0 + +/obj/structure/quicksand + name = "sand" + icon = 'icons/obj/quicksand.dmi' + icon_state = "intact0" + density = 0 + anchored = 1 + can_buckle = 1 + buckle_dir = SOUTH + var/exposed = 0 + var/busy + +/obj/structure/quicksand/New() + icon_state = "intact[rand(0,2)]" + ..() + +/obj/structure/quicksand/user_unbuckle_mob(mob/user) + if(buckled_mob && !user.stat && !user.restrained()) + if(busy) + to_chat(user, "[buckled_mob] is already getting out, be patient.") + return + var/delay = 60 + if(user == buckled_mob) + delay *=2 + user.visible_message( + "\The [user] tries to climb out of \the [src].", + "You begin to pull yourself out of \the [src].", + "You hear water sloushing." + ) + else + user.visible_message( + "\The [user] begins pulling \the [buckled_mob] out of \the [src].", + "You begin to pull \the [buckled_mob] out of \the [src].", + "You hear water sloushing." + ) + busy = 1 + if(do_after(user, delay, src)) + busy = 0 + if(user == buckled_mob) + if(prob(80)) + to_chat(user, "You slip and fail to get out!") + return + user.visible_message("\The [buckled_mob] pulls himself out of \the [src].") + else + user.visible_message("\The [buckled_mob] has been freed from \the [src] by \the [user].") + unbuckle_mob() + +/obj/structure/quicksand/unbuckle_mob() + ..() + update_icon() + +/obj/structure/quicksand/buckle_mob(var/mob/L) + ..() + update_icon() + +/obj/structure/quicksand/update_icon() + if(!exposed) + return + icon_state = "open" + overlays.Cut() + if(buckled_mob) + overlays += buckled_mob + var/image/I = image(icon,icon_state="overlay") + I.plane = ABOVE_HUMAN_PLANE + I.layer = ABOVE_HUMAN_LAYER + overlays += I + +/obj/structure/quicksand/proc/expose() + if(exposed) + return + visible_message("The upper crust breaks, exposing treacherous quicksands underneath!") + name = "quicksand" + desc = "There is no candy at the bottom." + exposed = 1 + update_icon() + +/obj/structure/quicksand/attackby(obj/item/weapon/W, mob/user) + if(!exposed && W.force) + expose() + else + ..() + +/obj/structure/quicksand/Crossed(AM) + if(isliving(AM)) + var/mob/living/L = AM + buckle_mob(L) + if(!exposed) + expose() + to_chat(L, "You fall into \the [src]!") \ No newline at end of file diff --git a/code/modules/overmap/exoplanets/exoplanet.dm b/code/modules/overmap/exoplanets/exoplanet.dm new file mode 100644 index 00000000..b803dafb --- /dev/null +++ b/code/modules/overmap/exoplanets/exoplanet.dm @@ -0,0 +1,432 @@ +/obj/effect/overmap/sector/exoplanet + name = "exoplanet" + icon_state = "globe" + var/list/seeds = list() + var/list/animals = list() + var/max_animal_count + var/datum/gas_mixture/atmosphere + var/list/breathgas = list() //list of gases animals/plants require to survive + var/badgas //id of gas that is toxic to life here + + var/lightlevel + in_space = 0 + var/maxx + var/maxy + var/landmark_type = /obj/effect/shuttle_landmark/automatic + + var/list/actors = list() //things that appear in engravings on xenoarch finds. + var/list/species = list() //list of names to use for simple animals + + var/repopulating = 0 + var/repopulate_types = list() // animals which have died that may come back + + var/features_budget = 2 + var/list/possible_features = list(/datum/map_template/ruin/exoplanet/monolith) //pre-defined list of features templates to pick from + +/obj/effect/overmap/sector/exoplanet/New(nloc, max_x, max_y) + if(!GLOB.using_map.use_overmap) + return + + maxx = max_x ? max_x : world.maxx + maxy = max_y ? max_y : world.maxy + + name = "[generate_planet_name()], \a [name]" + + world.maxz++ + forceMove(locate(1,1,world.maxz)) + + var/list/feature_types = possible_features.Copy() + possible_features.Cut() + for(var/T in feature_types) + var/datum/map_template/ruin/exoplanet/ruin = new T + possible_features[ruin.id] = ruin + ..() + +/obj/effect/overmap/sector/exoplanet/proc/build_level() + spawn() + generate_atmosphere() + generate_map() + generate_features() + generate_landing() + update_biome() + START_PROCESSING(SSobj, src) + +//attempt at more consistent history generation for xenoarch finds. +/obj/effect/overmap/sector/exoplanet/proc/get_engravings() + if(!actors.len) + actors += pick("alien humanoid","an amorphic blob","a short, hairy being","a rodent-like creature","a robot","a primate","a reptilian alien","an unidentifiable object","a statue","a starship","unusual devices","a structure") + actors += pick("alien humanoids","amorphic blobs","short, hairy beings","rodent-like creatures","robots","primates","reptilian aliens") + + var/engravings = "[actors[1]] \ + [pick("surrounded by","being held aloft by","being struck by","being examined by","communicating with")] \ + [actors[2]]" + if(prob(50)) + engravings += ", [pick("they seem to be enjoying themselves","they seem extremely angry","they look pensive","they are making gestures of supplication","the scene is one of subtle horror","the scene conveys a sense of desperation","the scene is completely bizarre")]" + engravings += "." + return engravings + +//Not that it should ever get deleted but just in case +/obj/effect/overmap/sector/exoplanet/Destroy() + . = ..() + STOP_PROCESSING(SSobj, src) + +/obj/effect/overmap/sector/exoplanet/Process() + if(animals.len < 0.5*max_animal_count && !repopulating) + repopulating = 1 + max_animal_count = round(max_animal_count * 0.5) + for(var/zlevel in map_z) + if(repopulating) + for(var/i = 1 to round(max_animal_count - animals.len)) + if(prob(10)) + var/turf/simulated/T = locate(rand(1,maxx), rand(1,maxy), zlevel) + var/mob_type = pick(repopulate_types) + var/mob/S = new mob_type(T) + animals += S + GLOB.death_event.register(S, src, /obj/effect/overmap/sector/exoplanet/proc/remove_animal) + GLOB.destroyed_event.register(S, src, /obj/effect/overmap/sector/exoplanet/proc/remove_animal) + adapt_animal(S) + if(animals.len >= max_animal_count) + repopulating = 0 + + if(!atmosphere) + continue + var/zone/Z + for(var/i = 1 to maxx) + var/turf/simulated/T = locate(i, 2, zlevel) + if(istype(T) && T.zone && T.zone.contents.len > (maxx*maxy*0.25)) //if it's a zone quarter of zlevel, good enough odds it's planetary main one + Z = T.zone + break + if(Z && !Z.fire_tiles.len && !atmosphere.compare(Z.air)) //let fire die out first if there is one + var/datum/gas_mixture/daddy = new() //make a fake 'planet' zone gas + daddy.copy_from(atmosphere) + daddy.group_multiplier = Z.air.group_multiplier + Z.air.equalize(daddy) + +/obj/effect/overmap/sector/exoplanet/proc/remove_animal(var/mob/M) + animals -= M + GLOB.death_event.unregister(M, src) + GLOB.destroyed_event.unregister(M, src) + repopulate_types |= M.type + +/obj/effect/overmap/sector/exoplanet/proc/generate_map() + +/obj/effect/overmap/sector/exoplanet/proc/generate_features() + seedRuins(map_z, features_budget, /area/exoplanet, possible_features) + +/obj/effect/overmap/sector/exoplanet/proc/get_biostuff(var/datum/random_map/noise/exoplanet/random_map) + seeds += random_map.small_flora_types + if(random_map.big_flora_types) + seeds += random_map.big_flora_types + for(var/mob/living/simple_animal/A in GLOB.living_mob_list_) + if(A.z in map_z) + animals += A + GLOB.death_event.register(A, src, /obj/effect/overmap/sector/exoplanet/proc/remove_animal) + GLOB.destroyed_event.register(A, src, /obj/effect/overmap/sector/exoplanet/proc/remove_animal) + max_animal_count = animals.len + +/obj/effect/overmap/sector/exoplanet/proc/update_biome() + for(var/datum/seed/S in seeds) + adapt_seed(S) + + for(var/mob/living/simple_animal/A in animals) + adapt_animal(A) + +/obj/effect/overmap/sector/exoplanet/proc/adapt_seed(var/datum/seed/S) + S.set_trait(TRAIT_IDEAL_HEAT, atmosphere.temperature + rand(-5,5),800,70) + S.set_trait(TRAIT_HEAT_TOLERANCE, S.get_trait(TRAIT_HEAT_TOLERANCE) + rand(-5,5),800,70) + S.set_trait(TRAIT_LOWKPA_TOLERANCE, atmosphere.return_pressure() + rand(-5,-50),80,0) + S.set_trait(TRAIT_HIGHKPA_TOLERANCE, atmosphere.return_pressure() + rand(5,50),500,110) + if(S.exude_gasses) + S.exude_gasses -= badgas + if(S.consume_gasses) + S.consume_gasses = list(pick(atmosphere.gas)) // ensure that if the plant consumes a gas, the atmosphere will have it + for(var/g in atmosphere.gas) + if(gas_data.flags[g] & XGM_GAS_CONTAMINANT) + S.set_trait(TRAIT_TOXINS_TOLERANCE, rand(10,15)) + +/obj/effect/overmap/sector/exoplanet/proc/adapt_animal(var/mob/living/simple_animal/A) + if(species[A.type]) + A.SetName(species[A.type]) + A.real_name = species[A.type] + else + A.SetName("alien creature") + A.real_name = "alien creature" + A.verbs |= /mob/living/simple_animal/proc/name_species + A.minbodytemp = atmosphere.temperature - 20 + A.maxbodytemp = atmosphere.temperature + 30 + A.bodytemperature = (A.maxbodytemp+A.minbodytemp)/2 + if(A.min_gas) + A.min_gas = breathgas.Copy() + if(A.max_gas) + A.max_gas = list() + A.max_gas[badgas] = 5 + +/obj/effect/overmap/sector/exoplanet/proc/get_random_species_name() + return pick("nol","shan","can","fel","xor")+pick("a","e","o","t","ar")+pick("ian","oid","ac","ese","inian","rd") + +/obj/effect/overmap/sector/exoplanet/proc/rename_species(var/species_type, var/newname, var/force = FALSE) + if(species[species_type] && !force) + return FALSE + + species[species_type] = newname + log_and_message_admins("renamed [species_type] to [newname]") + for(var/mob/living/simple_animal/A in animals) + if(istype(A,species_type)) + A.SetName(newname) + A.real_name = newname + A.verbs -= /mob/living/simple_animal/proc/name_species + return TRUE + +/obj/effect/overmap/sector/exoplanet/proc/generate_landing() + var/turf/T = locate(rand(20, maxx-20), rand(20, maxy - 10),map_z[map_z.len]) + if(T) + new landmark_type(T) + return T + +/obj/effect/overmap/sector/exoplanet/proc/generate_atmosphere() + atmosphere = new + if(prob(10)) //small chance of getting a perfectly habitable planet + atmosphere.adjust_gas("oxygen", MOLES_O2STANDARD, 0) + atmosphere.adjust_gas("nitrogen", MOLES_N2STANDARD) + else //let the fuckery commence + var/list/newgases = gas_data.gases.Copy() + if(prob(90)) //all phoron planet should be rare + newgases -= "phoron" + if(prob(50)) //alium gas should be slightly less common than mundane shit + newgases -= "aliether" + + var/sanity = prob(99.9) + + var/total_moles = MOLES_CELLSTANDARD * rand(80,120)/100 + var/gasnum = rand(1,4) + var/i = 1 + while(i <= gasnum && total_moles && newgases.len) + var/ng = pick_n_take(newgases) //pick a gas + if(sanity) //make sure atmosphere is not flammable... always + var/badflag = 0 + if(gas_data.flags[ng] & XGM_GAS_OXIDIZER) + badflag = XGM_GAS_FUEL + if(gas_data.flags[ng] & XGM_GAS_FUEL) + badflag = XGM_GAS_OXIDIZER + if(badflag) + for(var/g in newgases) + if(gas_data.flags[g] & badflag) + newgases -= g + sanity = 0 + + var/part = total_moles * rand(3,80)/100 //allocate percentage to it + if(i == gasnum || !newgases.len) //if it's last gas, let it have all remaining moles + part = total_moles + atmosphere.gas[ng] += part + total_moles = max(total_moles - part, 0) + i++ + + //Set up gases for living things + for(var/gas in atmosphere.gas) + breathgas[gas] = round(0.4*atmosphere.gas[gas]) + var/list/badgases = gas_data.gases.Copy() + badgases -= atmosphere.gas + badgas = pick(badgases) + +/obj/effect/overmap/sector/exoplanet/proc/process_map_edge(atom/movable/A) + var/new_x + var/new_y + if(A.x <= TRANSITIONEDGE) + new_x = maxx - TRANSITIONEDGE - 2 + new_y = rand(TRANSITIONEDGE + 2, maxy - TRANSITIONEDGE - 2) + + else if (A.x >= (maxx - TRANSITIONEDGE + 1)) + new_x = TRANSITIONEDGE + 1 + new_y = rand(TRANSITIONEDGE + 2, maxy - TRANSITIONEDGE - 2) + + else if (A.y <= TRANSITIONEDGE) + new_y = maxy - TRANSITIONEDGE -2 + new_x = rand(TRANSITIONEDGE + 2, maxx - TRANSITIONEDGE - 2) + + else if (A.y >= (maxy - TRANSITIONEDGE + 1)) + new_y = TRANSITIONEDGE + 1 + new_x = rand(TRANSITIONEDGE + 2, maxx - TRANSITIONEDGE - 2) + + var/turf/T = locate(new_x, new_y, A.z) + if(T) + A.forceMove(T) + +/area/exoplanet + name = "\improper Planetary surface" + ambience = list('sound/effects/wind/wind_2_1.ogg','sound/effects/wind/wind_2_2.ogg','sound/effects/wind/wind_3_1.ogg','sound/effects/wind/wind_4_1.ogg','sound/effects/wind/wind_4_2.ogg','sound/effects/wind/wind_5_1.ogg') + +//Random map itself + +/datum/random_map/noise/exoplanet + descriptor = "exoplanet" + smoothing_iterations = 1 + var/area/planetary_area = /area/exoplanet + + var/water_level + var/water_level_min = 0 + var/water_level_max = 5 + var/land_type = /turf/simulated/floor + var/water_type + + //intended x*y size, used to adjust spawn probs + var/intended_x = 150 + var/intended_y = 150 + var/large_flora_prob = 60 + var/flora_prob = 60 + var/fauna_prob = 2 + var/flora_diversity = 4 + + var/list/fauna_types = list() + var/list/small_flora_types = list() + var/list/big_flora_types = list() + var/list/plantcolors = list("RANDOM") + +/datum/random_map/noise/exoplanet/New(var/seed, var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/never_be_priority = 0) + target_turf_type = world.turf + planetary_area = new planetary_area() + water_level = rand(water_level_min,water_level_max) + generate_flora() + + //automagically adjust probs for bigger maps to help with lag + var/size_mod = intended_x / tlx * intended_y / tly + flora_prob *= size_mod + large_flora_prob *= size_mod + fauna_prob *= size_mod + + ..() + + GLOB.using_map.base_turf_by_z[num2text(tz)] = land_type + +/datum/random_map/noise/exoplanet/proc/noise2value(var/value) + return min(9,max(0,round((value/cell_range)*10))) + +/datum/random_map/noise/exoplanet/apply_to_turf(var/x,var/y) + var/turf/T = ..() + if(T && limit_x < world.maxx && (T.y == limit_y || T.x == limit_x)) + T.set_density(1) + T.set_opacity(1) + if(istype(T, /turf/simulated)) + var/turf/simulated/S = T + S.blocks_air = 1 + + +/datum/random_map/noise/exoplanet/get_map_char(var/value) + if(water_type && noise2value(value) < water_level) + return "~" + return "[noise2value(value)]" + +/datum/random_map/noise/exoplanet/get_appropriate_path(var/value) + if(water_type && noise2value(value) < water_level) + return water_type + else + return land_type + +/datum/random_map/noise/exoplanet/get_additional_spawns(var/value, var/turf/T) + planetary_area.contents.Add(T) + switch(noise2value(value)) + if(2 to 3) + if(prob(flora_prob)) + spawn_flora(T) + if(prob(fauna_prob)) + spawn_fauna(T) + if(5 to 6) + if(prob(flora_prob/3)) + spawn_flora(T) + if(7 to 9) + if(prob(flora_prob)) + spawn_flora(T) + else if(prob(large_flora_prob)) + spawn_flora(T, 1) + +/datum/random_map/noise/exoplanet/proc/spawn_fauna(var/turf/T) + var/beastie = pick(fauna_types) + new beastie(T) + +/datum/random_map/noise/exoplanet/proc/generate_flora() + for(var/i = 1 to flora_diversity) + var/datum/seed/S = new() + S.randomize() + S.set_trait(TRAIT_PRODUCT_ICON,"alien[rand(1,5)]") + S.set_trait(TRAIT_PLANT_ICON,"alien[rand(1,4)]") + var/color = pick(plantcolors) + if(color == "RANDOM") + color = get_random_colour(0,75,190) + S.set_trait(TRAIT_PLANT_COLOUR,color) + var/carnivore_prob = rand(100) + if(carnivore_prob < 10) + S.set_trait(TRAIT_CARNIVOROUS,2) + S.set_trait(TRAIT_SPREAD,1) + else if(carnivore_prob < 20) + S.set_trait(TRAIT_CARNIVOROUS,1) + small_flora_types += S + if(large_flora_prob) + var/tree_diversity = max(1,flora_diversity/2) + for(var/i = 1 to tree_diversity) + var/datum/seed/S = new() + S.randomize() + S.set_trait(TRAIT_PRODUCT_ICON,"alien[rand(1,5)]") + S.set_trait(TRAIT_PLANT_ICON,"tree") + S.set_trait(TRAIT_SPREAD,0) + S.set_trait(TRAIT_HARVEST_REPEAT,1) + S.set_trait(TRAIT_LARGE,1) + var/color = pick(plantcolors) + if(color == "RANDOM") + color = get_random_colour(0,75,190) + S.set_trait(TRAIT_LEAVES_COLOUR,color) + S.chems["woodpulp"] = 1 + big_flora_types += S + +/datum/random_map/noise/exoplanet/proc/spawn_flora(var/turf/T, var/big) + if(big) + new /obj/machinery/portable_atmospherics/hydroponics/soil/invisible(T, pick(big_flora_types), 1) + else + new /obj/machinery/portable_atmospherics/hydroponics/soil/invisible(T, pick(small_flora_types), 1) + +/turf/simulated/floor/exoplanet + name = "space land" + icon = 'icons/turf/desert.dmi' + icon_state = "desert" + has_resources = 1 + var/diggable = 1 + var/mudpit = 0 //if pits should not take turf's color + +/turf/simulated/floor/exoplanet/Entered(atom/movable/A) + ..() + + if(A.simulated && GLOB.using_map.use_overmap) + var/obj/effect/overmap/sector/exoplanet/sector = map_sectors["[z]"] + if(istype(sector)) + if (A.x <= TRANSITIONEDGE || A.x >= (sector.maxx - TRANSITIONEDGE + 1) || A.y <= TRANSITIONEDGE || A.y >= (sector.maxy - TRANSITIONEDGE + 1)) + sector.process_map_edge(A) + +/turf/simulated/floor/exoplanet/New() + if(GLOB.using_map.use_overmap) + var/obj/effect/overmap/sector/exoplanet/E = map_sectors["[z]"] + if(istype(E)) + if(E.atmosphere) + initial_gas = E.atmosphere.gas.Copy() + temperature = E.atmosphere.temperature + if(E.lightlevel) + light_power = E.lightlevel + light_range = 2 + ..() + +/turf/simulated/floor/exoplanet/attackby(obj/item/C, mob/user) + if(diggable && istype(C,/obj/item/weapon/shovel)) + visible_message("\The [user] starts digging \the [src]") + if(do_after(user, 50)) + to_chat(user,"You dig a deep pit.") + new /obj/structure/pit(src) + diggable = 0 + else + to_chat(user,"You stop shoveling.") + else + ..() + +/turf/simulated/floor/exoplanet/ex_act(severity) + switch(severity) + if(1) + ChangeTurf(get_base_turf_by_area(src)) + if(2) + if(prob(40)) + ChangeTurf(get_base_turf_by_area(src)) \ No newline at end of file diff --git a/code/modules/overmap/exoplanets/garbage.dm b/code/modules/overmap/exoplanets/garbage.dm new file mode 100644 index 00000000..4b3f7b3d --- /dev/null +++ b/code/modules/overmap/exoplanets/garbage.dm @@ -0,0 +1,75 @@ +/obj/effect/overmap/sector/exoplanet/garbage + name = "settled exoplanet" + desc = "An arid exoplanet with artificial structures detected on the surface." + color = "#a5a18b" + +/obj/effect/overmap/sector/exoplanet/garbage/generate_map() + if(prob(50)) + lightlevel = rand(5,10)/10 //deserts are usually :lit: + for(var/zlevel in map_z) + var/datum/random_map/noise/exoplanet/M = new /datum/random_map/noise/exoplanet/garbage(md5(world.time + rand(-100,1000)),1,1,zlevel,maxx,maxy,0,1,1) + get_biostuff(M) + new /datum/random_map/noise/ore/poor(md5(world.time + rand(-100,1000)),1,1,zlevel,maxx,maxy,0,1,1) + +/obj/effect/overmap/sector/exoplanet/garbage/generate_atmosphere() + ..() + if(atmosphere) + atmosphere.temperature = T20C + rand(20, 100) + atmosphere.update_values() + +/obj/effect/overmap/sector/exoplanet/garbage/update_biome() + ..() + for(var/datum/seed/S in seeds) + if(prob(90)) + S.set_trait(TRAIT_REQUIRES_WATER,0) + else + S.set_trait(TRAIT_REQUIRES_WATER,1) + S.set_trait(TRAIT_WATER_CONSUMPTION,1) + if(prob(40)) + S.set_trait(TRAIT_STINGS,1) + +/obj/effect/overmap/sector/exoplanet/garbage/adapt_animal(var/mob/living/simple_animal/A) + ..() + A.faction = "Guardian" //stops bots form hitting each other + +/datum/random_map/noise/exoplanet/garbage + descriptor = "garbage exoplanet" + smoothing_iterations = 4 + land_type = /turf/simulated/floor/exoplanet/desert + planetary_area = /area/exoplanet/garbage + plantcolors = list("#efdd6f","#7b4a12","#e49135","#ba6222","#5c755e","#120309") + + flora_prob = 1 + large_flora_prob = 0 + flora_diversity = 2 + fauna_types = list(/mob/living/simple_animal/hostile/hivebot, /mob/living/simple_animal/hostile/hivebot/range, /mob/living/simple_animal/hostile/viscerator) + fauna_prob = 1 + +/datum/random_map/noise/exoplanet/garbage/get_additional_spawns(var/value, var/turf/T) + ..() + var/v = noise2value(value) + if(v > 5) + new/obj/structure/rubble/house(T) + else + if(prob(2)) + new/obj/structure/rubble/war(T) + if(prob(0.02)) + var/datum/artifact_find/A = new() + new A.artifact_find_type(T) + qdel(A) + +/datum/random_map/noise/exoplanet/garbage/get_appropriate_path(var/value) + var/v = noise2value(value) + if(v > 6) + return /turf/simulated/floor/exoplanet/concrete + return land_type + +/area/exoplanet/garbage + ambience = list('sound/effects/wind/desert0.ogg','sound/effects/wind/desert1.ogg','sound/effects/wind/desert2.ogg','sound/effects/wind/desert3.ogg','sound/effects/wind/desert4.ogg','sound/effects/wind/desert5.ogg') + base_turf = /turf/simulated/floor/exoplanet/desert + +/turf/simulated/floor/exoplanet/concrete + name = "concrete" + desc = "Stone-like artificial material." + icon = 'icons/turf/flooring/misc.dmi' + icon_state = "concrete" \ No newline at end of file diff --git a/code/modules/overmap/exoplanets/grass.dm b/code/modules/overmap/exoplanets/grass.dm new file mode 100644 index 00000000..47d5df39 --- /dev/null +++ b/code/modules/overmap/exoplanets/grass.dm @@ -0,0 +1,88 @@ +/obj/effect/overmap/sector/exoplanet/grass + name = "lush exoplanet" + desc = "Planet with abundant flora and fauna." + color = "#538224" + +/obj/effect/overmap/sector/exoplanet/grass/generate_map() + if(prob(40)) + lightlevel = rand(1,7)/10 //give a chance of twilight jungle + for(var/zlevel in map_z) + var/datum/random_map/noise/exoplanet/M = new /datum/random_map/noise/exoplanet/grass(md5(world.time + rand(-100,1000)),1,1,zlevel,maxx,maxy,0,1,1) + get_biostuff(M) + +/obj/effect/overmap/sector/exoplanet/grass/generate_atmosphere() + ..() + if(atmosphere) + atmosphere.temperature = T20C + rand(10, 30) + atmosphere.update_values() + +/obj/effect/overmap/sector/exoplanet/grass/adapt_seed(var/datum/seed/S) + ..() + var/carnivore_prob = rand(100) + if(carnivore_prob < 15) + S.set_trait(TRAIT_CARNIVOROUS,2) + else if(carnivore_prob < 30) + S.set_trait(TRAIT_CARNIVOROUS,1) + if(prob(15) || (S.get_trait(TRAIT_CARNIVOROUS) && prob(40))) + S.set_trait(TRAIT_BIOLUM,1) + S.set_trait(TRAIT_BIOLUM_COLOUR,get_random_colour(0,75,190)) + + if(prob(30)) + S.set_trait(TRAIT_PARASITE,1) + if(!S.get_trait(TRAIT_LARGE)) + var/vine_prob = rand(100) + if(vine_prob < 15) + S.set_trait(TRAIT_SPREAD,2) + else if(vine_prob < 30) + S.set_trait(TRAIT_SPREAD,1) + +/area/exoplanet/grass + base_turf = /turf/simulated/floor/exoplanet/grass + ambience = list('sound/effects/wind/wind_2_1.ogg','sound/effects/wind/wind_2_2.ogg','sound/effects/wind/wind_3_1.ogg','sound/effects/wind/wind_4_1.ogg','sound/ambience/eeriejungle2.ogg','sound/ambience/eeriejungle1.ogg') + +/area/exoplanet/grass/play_ambience(var/mob/living/L) + ..() + if(!L.ear_deaf && L.client && !L.client.ambience_playing) + L.client.ambience_playing = 1 + L.playsound_local(get_turf(L),sound('sound/ambience/jungle.ogg', repeat = 1, wait = 0, volume = 25, channel = 2)) + +/datum/random_map/noise/exoplanet/grass + descriptor = "grass exoplanet" + smoothing_iterations = 2 + land_type = /turf/simulated/floor/exoplanet/grass + water_type = /turf/simulated/floor/exoplanet/water/shallow + planetary_area = /area/exoplanet/grass + plantcolors = list("#0e1e14","#1a3e38","#5a7467","#9eab88","#6e7248", "RANDOM") + + flora_prob = 30 + large_flora_prob = 50 + flora_diversity = 6 + fauna_types = list(/mob/living/simple_animal/yithian, /mob/living/simple_animal/tindalos, /mob/living/simple_animal/hostile/jelly) + +/datum/random_map/noise/exoplanet/grass/spawn_fauna(var/turf/T, value) + if(prob(5)) + new/mob/living/simple_animal/hostile/giant_spider/nurse(T) + else + ..() + +/turf/simulated/floor/exoplanet/grass + name = "grass" + icon = 'icons/turf/jungle.dmi' + icon_state = "grass2" + mudpit = 1 + +/turf/simulated/floor/exoplanet/grass/Initialize() + . = ..() + if(!resources) + resources = list() + if(prob(70)) + resources["carbonaceous rock"] = rand(3,5) + if(prob(5)) + resources["uranium"] = rand(1,3) + if(prob(2)) + resources["diamond"] = 1 + +/turf/simulated/floor/exoplanet/grass/fire_act(datum/gas_mixture/air, temperature, volume) + if((temperature > T0C + 200 && prob(5)) || temperature > T0C + 1000) + SetName("scorched ground") + icon_state = "scorched" \ No newline at end of file diff --git a/code/modules/overmap/exoplanets/mountain.dm b/code/modules/overmap/exoplanets/mountain.dm new file mode 100644 index 00000000..5f0ff1ae --- /dev/null +++ b/code/modules/overmap/exoplanets/mountain.dm @@ -0,0 +1,39 @@ +/obj/effect/overmap/sector/exoplanet/rocks + name = "rocky exoplanet" + desc = "A planet with rocky formations on the surface, exposing minerals. Rest of terrain varies." + landmark_type = /obj/effect/shuttle_landmark/automatic/clearing + color = "#7c7670" + +/obj/effect/overmap/sector/exoplanet/rocks/generate_map() + if(prob(50)) + lightlevel = rand(1,10)/10 //total random + for(var/zlevel in map_z) + new /datum/random_map/automata/cave_system/mountains(md5(world.time + rand(-100,1000)),1,1,zlevel,maxx,maxy,0,1,1) + var/datum/random_map/noise/exoplanet/M = pick(subtypesof(/datum/random_map/noise/exoplanet)) + M = new M(md5(world.time + rand(-100,1000)),1,1,zlevel,maxx,maxy,0,1,1) + get_biostuff(M) + var/area/A = M.planetary_area + for(var/_x = 1 to maxx) + for(var/_y = 1 to maxy) + var/turf/T = locate(_x,_y,zlevel) + A.contents.Add(T) + if(istype(T,/turf/simulated/mineral)) + var/turf/simulated/mineral/MT = T + MT.mined_turf = A.base_turf + +/datum/random_map/automata/cave_system/mountains + iterations = 2 + descriptor = "space mountains" + wall_type = /turf/simulated/mineral + cell_threshold = 6 + var/colorshift + +/datum/random_map/automata/cave_system/mountains/New() + colorshift = round(rand(0,360),20) + target_turf_type = world.turf + floor_type = world.turf + ..() + +/datum/random_map/automata/cave_system/mountains/get_additional_spawns(var/value, var/turf/T) + ..() + T.color = color_rotation(colorshift) \ No newline at end of file diff --git a/code/modules/overmap/exoplanets/snow.dm b/code/modules/overmap/exoplanets/snow.dm new file mode 100644 index 00000000..d6a202eb --- /dev/null +++ b/code/modules/overmap/exoplanets/snow.dm @@ -0,0 +1,54 @@ +/obj/effect/overmap/sector/exoplanet/snow + name = "snow exoplanet" + desc = "Cold planet with limited plant life." + color = "#e8faff" + +/obj/effect/overmap/sector/exoplanet/snow/generate_map() + for(var/zlevel in map_z) + var/datum/random_map/noise/exoplanet/M = new /datum/random_map/noise/exoplanet/snow(md5(world.time + rand(-100,1000)),1,1,zlevel,maxx,maxy,0,1,1) + get_biostuff(M) + new /datum/random_map/noise/ore/poor(md5(world.time + rand(-100,1000)),1,1,zlevel,maxx,maxy,0,1,1) + +/obj/effect/overmap/sector/exoplanet/snow/generate_atmosphere() + ..() + if(atmosphere) + atmosphere.temperature = T0C - rand(10, 100) + atmosphere.update_values() + +/datum/random_map/noise/exoplanet/snow + descriptor = "snow exoplanet" + smoothing_iterations = 1 + flora_prob = 10 + large_flora_prob = 20 + water_level_max = 3 + land_type = /turf/simulated/floor/exoplanet/snow + water_type = /turf/simulated/floor/exoplanet/ice + planetary_area = /area/exoplanet/snow + fauna_types = list(/mob/living/simple_animal/hostile/retaliate/beast/samak, /mob/living/simple_animal/hostile/retaliate/beast/diyaab, /mob/living/simple_animal/hostile/retaliate/beast/shantak) + plantcolors = list("#d0fef5","#93e1d8","#93e1d8", "#b2abbf", "#3590f3", "#4b4e6d") + +/area/exoplanet/snow + ambience = list('sound/effects/wind/tundra0.ogg','sound/effects/wind/tundra1.ogg','sound/effects/wind/tundra2.ogg','sound/effects/wind/spooky0.ogg','sound/effects/wind/spooky1.ogg') + base_turf = /turf/simulated/floor/exoplanet/snow/ + +/datum/random_map/noise/ore/poor + deep_val = 0.8 + rare_val = 0.9 + +/turf/simulated/floor/exoplanet/ice + name = "ice" + icon = 'icons/turf/snow.dmi' + icon_state = "ice" + +/turf/simulated/floor/exoplanet/snow + name = "snow" + icon = 'icons/turf/snow.dmi' + icon_state = "snow" + +/turf/simulated/floor/exoplanet/snow/New() + icon_state = pick("snow[rand(1,12)]","snow0") + ..() + +/turf/simulated/floor/exoplanet/snow/fire_act(datum/gas_mixture/air, temperature, volume) + name = "permafrost" + icon_state = "permafrost" \ No newline at end of file diff --git a/code/modules/overmap/overmap_shuttle.dm b/code/modules/overmap/overmap_shuttle.dm new file mode 100644 index 00000000..b78e59ed --- /dev/null +++ b/code/modules/overmap/overmap_shuttle.dm @@ -0,0 +1,148 @@ +#define waypoint_sector(waypoint) map_sectors["[waypoint.z]"] + +/datum/shuttle/autodock/overmap + warmup_time = 10 + + var/range = 0 //how many overmap tiles can shuttle go, for picking destinations and returning. + var/fuel_consumption = 0 //Amount of moles of gas consumed per trip; If zero, then shuttle is magic and does not need fuel + var/list/obj/structure/fuel_port/fuel_ports //the fuel ports of the shuttle (but usually just one) + + category = /datum/shuttle/autodock/overmap + +/datum/shuttle/autodock/overmap/New(var/_name, var/obj/effect/shuttle_landmark/start_waypoint) + ..(_name, start_waypoint) + refresh_fuel_ports_list() + +/datum/shuttle/autodock/overmap/proc/refresh_fuel_ports_list() //loop through all + fuel_ports = list() + for(var/area/A in shuttle_area) + for(var/obj/structure/fuel_port/fuel_port_in_area in A) + fuel_port_in_area.parent_shuttle = src + fuel_ports += fuel_port_in_area + +/datum/shuttle/autodock/overmap/fuel_check() + if(!src.try_consume_fuel()) //insufficient fuel + for(var/area/A in shuttle_area) + for(var/mob/living/M in A) + M.show_message("You hear the shuttle engines sputter... perhaps it doesn't have enough fuel?", AUDIBLE_MESSAGE, + "The shuttle shakes but fails to take off.", VISIBLE_MESSAGE) + return 0 //failure! + return 1 //sucess, continue with launch + +/datum/shuttle/autodock/overmap/proc/can_go() + if(!next_location) + return FALSE + if(moving_status == SHUTTLE_INTRANSIT) + return FALSE //already going somewhere, current_location may be an intransit location instead of in a sector + return get_dist(waypoint_sector(current_location), waypoint_sector(next_location)) <= range + +/datum/shuttle/autodock/overmap/can_launch() + return ..() && can_go() + +/datum/shuttle/autodock/overmap/can_force() + return ..() && can_go() + +/datum/shuttle/autodock/overmap/proc/set_destination(var/obj/effect/shuttle_landmark/A) + if(A != current_location) + next_location = A + move_time = initial(move_time) * (1 + get_dist(waypoint_sector(current_location),waypoint_sector(next_location))) + +/datum/shuttle/autodock/overmap/proc/get_possible_destinations() + var/list/res = list() + for (var/obj/effect/overmap/S in range(waypoint_sector(current_location), range)) + for(var/obj/effect/shuttle_landmark/LZ in S.get_waypoints(src.name)) + if(LZ.is_valid(src)) + res["[S.name] - [LZ.name]"] = LZ + return res + +/datum/shuttle/autodock/overmap/proc/get_location_name() + if(moving_status == SHUTTLE_INTRANSIT) + return "In transit" + return "[waypoint_sector(current_location)] - [current_location]" + +/datum/shuttle/autodock/overmap/proc/get_destination_name() + if(!next_location) + return "None" + return "[waypoint_sector(next_location)] - [next_location]" + +/datum/shuttle/autodock/overmap/proc/try_consume_fuel() //returns 1 if sucessful, returns 0 if error (like insufficient fuel) + if(!fuel_consumption) + return 1 //shuttles with zero fuel consumption are magic and can always launch + else + if(fuel_ports.len) + var/list/obj/item/weapon/tank/fuel_tanks = list() + for(var/obj/structure/FP in fuel_ports) //loop through fuel ports and assemble list of all fuel tanks + if(FP.contents.len) + var/obj/item/weapon/tank/FT = FP.contents[1] + if(istype(FT)) + fuel_tanks += FT + if(!fuel_tanks.len) + return 0 //can't launch if you have no fuel TANKS in the ports + var/total_flammable_gas_moles = 0 + for(var/obj/item/weapon/tank/FT in fuel_tanks) + total_flammable_gas_moles += FT.air_contents.get_by_flag(XGM_GAS_FUEL) + if(total_flammable_gas_moles >= fuel_consumption) //launch is possible, so start consuming that fuel + var/fuel_to_consume = fuel_consumption + for(var/obj/item/weapon/tank/FT in fuel_tanks) //loop through tanks, consume their fuel one by one + if(FT.air_contents.get_by_flag(XGM_GAS_FUEL) >= fuel_to_consume) + FT.air_contents.remove_by_flag(XGM_GAS_FUEL, fuel_to_consume) + return 1 //ALL REQUIRED FUEL HAS BEEN CONSUMED, GO FOR LAUNCH! + else //this tank doesn't have enough to launch shuttle by itself, so remove all its fuel, then continue loop + fuel_to_consume -= FT.air_contents.get_by_flag(XGM_GAS_FUEL) + FT.air_contents.remove_by_flag(XGM_GAS_FUEL, FT.air_contents.get_by_flag(XGM_GAS_FUEL)) + else + return 0 //can't launch if you have insufficient fuel + else + return 0 //can't launch if you have no fuel PORTS at all + +/obj/structure/fuel_port + name = "fuel port" + desc = "The fuel input port of the shuttle. Holds one fuel tank. Use a crowbar to open and close it." + icon = 'icons/turf/shuttle.dmi' + icon_state = "fuel_port" + density = 0 + anchored = 1 + var/icon_closed = "fuel_port" + var/icon_empty = "fuel_port_empty" + var/icon_full = "fuel_port_full" + var/opened = 0 + var/parent_shuttle + +/obj/structure/fuel_port/New() + src.contents.Add(new/obj/item/weapon/tank/hydrogen) + +/obj/structure/fuel_port/attack_hand(mob/user as mob) + if(!opened) + to_chat(user, "The door is secured tightly. You'll need a crowbar to open it.") + return + else if(contents.len > 0) + user.put_in_hands(contents[1]) + update_icon() + +/obj/structure/fuel_port/update_icon() + if(opened) + if(contents.len > 0) + icon_state = icon_full + else + icon_state = icon_empty + else + icon_state = icon_closed + +/obj/structure/fuel_port/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isCrowbar(W)) + if(opened) + to_chat(user, "You tightly shut \the [src] door.") + playsound(src.loc, 'sound/effects/locker_close.ogg', 25, 0, -3) + opened = 0 + else + to_chat(user, "You open up \the [src] door.") + playsound(src.loc, 'sound/effects/locker_open.ogg', 15, 1, -3) + opened = 1 + else if(istype(W,/obj/item/weapon/tank)) + if(!opened) + to_chat(user, "\The [src] door is still closed!") + return + if(contents.len == 0) + user.drop_from_inventory(W) + W.forceMove(src) + update_icon() \ No newline at end of file diff --git a/code/modules/overmap/sectors.dm b/code/modules/overmap/sectors.dm new file mode 100644 index 00000000..49954dec --- /dev/null +++ b/code/modules/overmap/sectors.dm @@ -0,0 +1,127 @@ +//=================================================================================== +//Overmap object representing zlevel(s) +//=================================================================================== +/obj/effect/overmap + name = "map object" + icon = 'icons/obj/overmap.dmi' + icon_state = "object" + var/list/map_z = list() + + var/list/generic_waypoints = list() //waypoints that any shuttle can use + var/list/restricted_waypoints = list() //waypoints for specific shuttles + var/docking_codes + + var/start_x //coordinates on the + var/start_y //overmap zlevel + + var/base = 0 //starting sector, counts as station_levels + var/known = 1 //shows up on nav computers automatically + var/in_space = 1 //can be accessed via lucky EVA + +/obj/effect/overmap/New() + if(!GLOB.using_map.use_overmap) + return + + map_z = GetConnectedZlevels(z) + for(var/zlevel in map_z) + map_sectors["[zlevel]"] = src + + docking_codes = "[ascii2text(rand(65,90))][ascii2text(rand(65,90))][ascii2text(rand(65,90))][ascii2text(rand(65,90))]" + ..() + +/obj/effect/overmap/Initialize() + . = ..() + + if(!GLOB.using_map.use_overmap) + return INITIALIZE_HINT_QDEL + + if(!GLOB.using_map.overmap_z) + build_overmap() + + start_x = start_x || rand(OVERMAP_EDGE, GLOB.using_map.overmap_size - OVERMAP_EDGE) + start_y = start_y || rand(OVERMAP_EDGE, GLOB.using_map.overmap_size - OVERMAP_EDGE) + + forceMove(locate(start_x, start_y, GLOB.using_map.overmap_z)) + testing("Located sector \"[name]\" at [start_x],[start_y], containing Z [english_list(map_z)]") + + GLOB.using_map.player_levels |= map_z + + if(!in_space) + GLOB.using_map.sealed_levels |= map_z + + if(base) + GLOB.using_map.station_levels |= map_z + GLOB.using_map.contact_levels |= map_z + + + //handle automatic waypoints that spawned before us + for(var/obj/effect/shuttle_landmark/automatic/L in world) + if(L.z in map_z) + L.add_to_sector(src, 1) + + //find shuttle waypoints + var/list/found_waypoints = list() + for(var/waypoint_tag in generic_waypoints) + var/obj/effect/shuttle_landmark/WP = locate(waypoint_tag) + if(WP) + found_waypoints += WP + else + log_error("Sector \"[name]\" containing Z [english_list(map_z)] could not find waypoint with tag [waypoint_tag]!") + generic_waypoints = found_waypoints + + for(var/shuttle_name in restricted_waypoints) + found_waypoints = list() + for(var/waypoint_tag in restricted_waypoints[shuttle_name]) + var/obj/effect/shuttle_landmark/WP = locate(waypoint_tag) + if(WP) + found_waypoints += WP + else + log_error("Sector \"[name]\" containing Z [english_list(map_z)] could not find waypoint with tag [waypoint_tag]!") + restricted_waypoints[shuttle_name] = found_waypoints + + for(var/obj/machinery/computer/sensors/S in SSmachines.machinery) + if (S.z in map_z) + S.linked = src + +/obj/effect/overmap/proc/get_waypoints(var/shuttle_name) + . = generic_waypoints.Copy() + if(shuttle_name in restricted_waypoints) + . += restricted_waypoints[shuttle_name] + +/obj/effect/overmap/sector + name = "generic sector" + desc = "Sector with some stuff in it." + icon_state = "sector" + anchored = 1 + +/obj/effect/overmap/sector/Initialize() + . = ..() + if(known) + layer = ABOVE_LIGHTING_LAYER + plane = EFFECTS_ABOVE_LIGHTING_PLANE + for(var/obj/machinery/computer/helm/H in SSmachines.machinery) + H.get_known_sectors() + +/proc/build_overmap() + if(!GLOB.using_map.use_overmap) + return 1 + + testing("Building overmap...") + world.maxz++ + GLOB.using_map.overmap_z = world.maxz + var/list/turfs = list() + for (var/square in block(locate(1,1,GLOB.using_map.overmap_z), locate(GLOB.using_map.overmap_size,GLOB.using_map.overmap_size,GLOB.using_map.overmap_z))) + var/turf/T = square + if(T.x == GLOB.using_map.overmap_size || T.y == GLOB.using_map.overmap_size) + T = T.ChangeTurf(/turf/unsimulated/map/edge) + else + T = T.ChangeTurf(/turf/unsimulated/map/) + turfs += T + + var/area/overmap/A = new + A.contents.Add(turfs) + + GLOB.using_map.sealed_levels |= GLOB.using_map.overmap_z + + testing("Overmap build complete.") + return 1 diff --git a/code/modules/overmap/ships/computers/engine_control.dm b/code/modules/overmap/ships/computers/engine_control.dm new file mode 100644 index 00000000..5ee065c9 --- /dev/null +++ b/code/modules/overmap/ships/computers/engine_control.dm @@ -0,0 +1,105 @@ +//Engine control and monitoring console + +/obj/machinery/computer/engines + name = "engine control console" + icon_state = "thick" + icon_keyboard = "tech_key" + icon_screen = "engines" + var/state = "status" + var/obj/effect/overmap/ship/linked + +/obj/machinery/computer/engines/Initialize() + . = ..() + linked = map_sectors["[z]"] + +/obj/machinery/computer/engines/attack_hand(var/mob/user as mob) + if(..()) + user.unset_machine() + return + + if(!isAI(user)) + user.set_machine(src) + + ui_interact(user) + +/obj/machinery/computer/engines/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(!linked) + to_chat(user, "Unable to connect to ship control systems.") + return + + var/data[0] + data["state"] = state + data["global_state"] = linked.engines_state + data["global_limit"] = round(linked.thrust_limit*100) + var/total_thrust = 0 + + var/list/enginfo[0] + for(var/datum/ship_engine/E in linked.engines) + var/list/rdata[0] + rdata["eng_type"] = E.name + rdata["eng_on"] = E.is_on() + rdata["eng_thrust"] = E.get_thrust() + rdata["eng_thrust_limiter"] = round(E.get_thrust_limit()*100) + rdata["eng_status"] = E.get_status() + rdata["eng_reference"] = "\ref[E]" + total_thrust += E.get_thrust() + enginfo.Add(list(rdata)) + + data["engines_info"] = enginfo + data["total_thrust"] = total_thrust + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "engines_control.tmpl", "[linked.name] Engines Control", 380, 530) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/computer/engines/Topic(href, href_list, ui_state) + if(..()) + return 1 + + if(href_list["state"]) + state = href_list["state"] + + if(href_list["global_toggle"]) + linked.engines_state = !linked.engines_state + for(var/datum/ship_engine/E in linked.engines) + if(linked.engines_state != E.is_on()) + E.toggle() + + if(href_list["set_global_limit"]) + var/newlim = input("Input new thrust limit (0..100%)", "Thrust limit", linked.thrust_limit*100) as num + if(!CanInteract(usr,ui_state)) + return + linked.thrust_limit = Clamp(newlim/100, 0, 1) + for(var/datum/ship_engine/E in linked.engines) + E.set_thrust_limit(linked.thrust_limit) + + if(href_list["global_limit"]) + linked.thrust_limit = Clamp(linked.thrust_limit + text2num(href_list["global_limit"]), 0, 1) + for(var/datum/ship_engine/E in linked.engines) + E.set_thrust_limit(linked.thrust_limit) + + if(href_list["engine"]) + if(href_list["set_limit"]) + var/datum/ship_engine/E = locate(href_list["engine"]) + var/newlim = input("Input new thrust limit (0..100)", "Thrust limit", E.get_thrust_limit()) as num + if(!CanInteract(usr,ui_state)) + return + var/limit = Clamp(newlim/100, 0, 1) + if(istype(E)) + E.set_thrust_limit(limit) + + if(href_list["limit"]) + var/datum/ship_engine/E = locate(href_list["engine"]) + var/limit = Clamp(E.get_thrust_limit() + text2num(href_list["limit"]), 0, 1) + if(istype(E)) + E.set_thrust_limit(limit) + + if(href_list["toggle"]) + var/datum/ship_engine/E = locate(href_list["engine"]) + if(istype(E)) + E.toggle() + + updateUsrDialog() \ No newline at end of file diff --git a/code/modules/overmap/ships/computers/helm.dm b/code/modules/overmap/ships/computers/helm.dm new file mode 100644 index 00000000..8ea17ab4 --- /dev/null +++ b/code/modules/overmap/ships/computers/helm.dm @@ -0,0 +1,280 @@ +LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint) + +/obj/machinery/computer/helm + name = "helm control console" + icon_state = "thick" + icon_keyboard = "teleport_key" + icon_screen = "helm" + light_color = "#7faaff" + circuit = /obj/item/weapon/circuitboard/helm + var/obj/effect/overmap/ship/linked //connected overmap object + var/autopilot = 0 + var/manual_control = 0 + var/list/known_sectors = list() + var/dx //desitnation + var/dy //coordinates + var/speedlimit = 2 //top speed for autopilot + +/obj/machinery/computer/helm/Initialize() + . = ..() + linked = map_sectors["[z]"] + get_known_sectors() + +/obj/machinery/computer/helm/proc/get_known_sectors() + var/area/overmap/map = locate() in world + for(var/obj/effect/overmap/sector/S in map) + if (S.known) + var/datum/computer_file/data/waypoint/R = new() + R.fields["name"] = S.name + R.fields["x"] = S.x + R.fields["y"] = S.y + known_sectors[S.name] = R + ..() + +/obj/machinery/computer/helm/Process() + ..() + if (autopilot && dx && dy) + var/turf/T = locate(dx,dy,GLOB.using_map.overmap_z) + if(linked.loc == T) + if(linked.is_still()) + autopilot = 0 + else + linked.decelerate() + + var/brake_path = linked.get_brake_path() + + if((!speedlimit || linked.get_speed() < speedlimit) && get_dist(linked.loc, T) > brake_path) + linked.accelerate(get_dir(linked.loc, T)) + else + linked.decelerate() + + return + +/obj/machinery/computer/helm/relaymove(var/mob/user, direction) + if(manual_control && linked) + linked.relaymove(user,direction) + return 1 + +/obj/machinery/computer/helm/check_eye(var/mob/user as mob) + if (!manual_control) + return -1 + if (!get_dist(user, src) > 1 || user.blinded || !linked ) + return -1 + return 0 + +/obj/machinery/computer/helm/attack_hand(var/mob/user as mob) + if(..()) + user.unset_machine() + manual_control = 0 + return + + if(!isAI(user)) + user.set_machine(src) + if(linked) + user.reset_view(linked) + + ui_interact(user) + +/obj/machinery/computer/helm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(!linked) + return + + var/data[0] + + var/turf/T = get_turf(linked) + var/obj/effect/overmap/sector/current_sector = locate() in T + + data["sector"] = current_sector ? current_sector.name : "Deep Space" + data["sector_info"] = current_sector ? current_sector.desc : "Not Available" + data["s_x"] = linked.x + data["s_y"] = linked.y + data["dest"] = dy && dx + data["d_x"] = dx + data["d_y"] = dy + data["speedlimit"] = speedlimit ? speedlimit : "None" + data["speed"] = linked.get_speed() + data["accel"] = linked.get_acceleration() + data["heading"] = linked.get_heading() ? dir2angle(linked.get_heading()) : 0 + data["autopilot"] = autopilot + data["manual_control"] = manual_control + data["canburn"] = linked.can_burn() + + if(linked.get_speed()) + data["ETAnext"] = "[round(linked.ETA()/10)] seconds" + else + data["ETAnext"] = "N/A" + + var/list/locations[0] + for (var/key in known_sectors) + var/datum/computer_file/data/waypoint/R = known_sectors[key] + var/list/rdata[0] + rdata["name"] = R.fields["name"] + rdata["x"] = R.fields["x"] + rdata["y"] = R.fields["y"] + rdata["reference"] = "\ref[R]" + locations.Add(list(rdata)) + + data["locations"] = locations + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "helm.tmpl", "[linked.name] Helm Control", 380, 530) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/computer/helm/Topic(href, href_list, state) + if(..()) + return 1 + + if (!linked) + return + + if (href_list["add"]) + var/datum/computer_file/data/waypoint/R = new() + var/sec_name = input("Input naviation entry name", "New navigation entry", "Sector #[known_sectors.len]") as text + if(!CanInteract(usr,state)) + return + if(!sec_name) + sec_name = "Sector #[known_sectors.len]" + R.fields["name"] = sec_name + if(sec_name in known_sectors) + to_chat(usr, "Sector with that name already exists, please input a different name.") + return + switch(href_list["add"]) + if("current") + R.fields["x"] = linked.x + R.fields["y"] = linked.y + if("new") + var/newx = input("Input new entry x coordinate", "Coordinate input", linked.x) as num + if(!CanInteract(usr,state)) + return + var/newy = input("Input new entry y coordinate", "Coordinate input", linked.y) as num + if(!CanInteract(usr,state)) + return + R.fields["x"] = Clamp(newx, 1, world.maxx) + R.fields["y"] = Clamp(newy, 1, world.maxy) + known_sectors[sec_name] = R + + if (href_list["remove"]) + var/datum/computer_file/data/waypoint/R = locate(href_list["remove"]) + if(R) + known_sectors.Remove(R.fields["name"]) + qdel(R) + + if (href_list["setx"]) + var/newx = input("Input new destiniation x coordinate", "Coordinate input", dx) as num|null + if(!CanInteract(usr,state)) + return + if (newx) + dx = Clamp(newx, 1, world.maxx) + + if (href_list["sety"]) + var/newy = input("Input new destiniation y coordinate", "Coordinate input", dy) as num|null + if(!CanInteract(usr,state)) + return + if (newy) + dy = Clamp(newy, 1, world.maxy) + + if (href_list["x"] && href_list["y"]) + dx = text2num(href_list["x"]) + dy = text2num(href_list["y"]) + + if (href_list["reset"]) + dx = 0 + dy = 0 + + if (href_list["speedlimit"]) + var/newlimit = input("Input new speed limit for autopilot (0 to disable)", "Autopilot speed limit", speedlimit) as num|null + if(newlimit) + speedlimit = Clamp(newlimit, 0, 100) + + if (href_list["move"]) + var/ndir = text2num(href_list["move"]) + linked.relaymove(usr, ndir) + + if (href_list["brake"]) + linked.decelerate() + + if (href_list["apilot"]) + autopilot = !autopilot + + if (href_list["manual"]) + manual_control = !manual_control + + add_fingerprint(usr) + updateUsrDialog() + + +/obj/machinery/computer/navigation + name = "navigation console" + circuit = /obj/item/weapon/circuitboard/nav + var/viewing = 0 + var/obj/effect/overmap/ship/linked + icon_keyboard = "generic_key" + icon_screen = "helm" + +/obj/machinery/computer/navigation/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(!linked) + return + + var/data[0] + + + var/turf/T = get_turf(linked) + var/obj/effect/overmap/sector/current_sector = locate() in T + + data["sector"] = current_sector ? current_sector.name : "Deep Space" + data["sector_info"] = current_sector ? current_sector.desc : "Not Available" + data["s_x"] = linked.x + data["s_y"] = linked.y + data["speed"] = linked.get_speed() + data["accel"] = linked.get_acceleration() + data["heading"] = linked.get_heading() ? dir2angle(linked.get_heading()) : 0 + data["viewing"] = viewing + + if(linked.get_speed()) + data["ETAnext"] = "[round(linked.ETA()/10)] seconds" + else + data["ETAnext"] = "N/A" + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "nav.tmpl", "[linked.name] Navigation Screen", 380, 530) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/computer/navigation/check_eye(var/mob/user as mob) + if (!viewing) + return -1 + if (!get_dist(user, src) > 1 || user.blinded || !linked ) + viewing = 0 + return -1 + return 0 + +/obj/machinery/computer/navigation/attack_hand(var/mob/user as mob) + if(..()) + user.unset_machine() + viewing = 0 + return + + if(viewing && linked &&!isAI(user)) + user.set_machine(src) + user.reset_view(linked) + + ui_interact(user) + +/obj/machinery/computer/navigation/Topic(href, href_list) + if(..()) + return 1 + + if (!linked) + return + + if (href_list["viewing"]) + viewing = !viewing + if(viewing && !isAI(usr)) + var/mob/user = usr + user.reset_view(linked) + return 1 diff --git a/code/modules/overmap/ships/computers/sensors.dm b/code/modules/overmap/ships/computers/sensors.dm new file mode 100644 index 00000000..be96802e --- /dev/null +++ b/code/modules/overmap/ships/computers/sensors.dm @@ -0,0 +1,225 @@ +/obj/machinery/computer/sensors + name = "sensors console" + icon_state = "thick" + icon_keyboard = "teleport_key" + icon_screen = "teleport" + light_color = "#77fff8" + //circuit = /obj/item/weapon/circuitboard/sensors + var/obj/effect/overmap/ship/linked + var/obj/machinery/shipsensors/sensors + var/viewing = 0 + +/obj/machinery/computer/sensors/Initialize() + . = ..() + linked = map_sectors["[z]"] + find_sensors() + +/obj/machinery/computer/sensors/Destroy() + sensors = null + . = ..() + +/obj/machinery/computer/sensors/proc/find_sensors() + for(var/obj/machinery/shipsensors/S in SSmachines.machinery) + if (S.z in GetConnectedZlevels(z)) + sensors = S + break + +/obj/machinery/computer/sensors/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(!linked) + return + + var/data[0] + + data["viewing"] = viewing + if(sensors) + data["on"] = sensors.use_power + data["range"] = sensors.range + data["health"] = sensors.health + data["max_health"] = sensors.max_health + data["heat"] = sensors.heat + data["critical_heat"] = sensors.critical_heat + if(sensors.health == 0) + data["status"] = "DESTROYED" + else if(!sensors.powered()) + data["status"] = "NO POWER" + else if(!sensors.in_vacuum()) + data["status"] = "VACUUM SEAL BROKEN" + else + data["status"] = "OK" + else + data["status"] = "MISSING" + data["range"] = "N/A" + data["on"] = 0 + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "shipsensors.tmpl", "[linked.name] Sensors Control", 420, 530) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/computer/sensors/check_eye(var/mob/user as mob) + if (!viewing) + return -1 + if (!get_dist(user, src) > 1 || user.blinded || !linked ) + viewing = 0 + return -1 + return 0 + +/obj/machinery/computer/sensors/attack_hand(var/mob/user as mob) + if(..()) + user.unset_machine() + viewing = 0 + return + + if(!isAI(user)) + user.set_machine(src) + if(linked) + user.reset_view(linked) + ui_interact(user) + +/obj/machinery/computer/sensors/Topic(href, href_list, state) + if(..()) + return 1 + + if (!linked) + return + + if (href_list["viewing"]) + viewing = !viewing + if(viewing && usr && !isAI(usr)) + usr.reset_view(linked) + return 1 + + if (href_list["link"]) + find_sensors() + return 1 + + if(sensors) + if (href_list["range"]) + var/nrange = input("Set new sensors range", "Sensor range", sensors.range) as num|null + if(!CanInteract(usr,state)) + return + if (nrange) + sensors.set_range(Clamp(nrange, 1, world.view)) + return 1 + if (href_list["toggle"]) + sensors.toggle() + return 1 + +/obj/machinery/computer/sensors/Process() + ..() + if(!linked) + return + if(sensors && sensors.use_power && sensors.powered()) + linked.set_light(sensors.range+1, 5) + else + linked.set_light(0) + +/obj/machinery/shipsensors + name = "sensors suite" + desc = "Long range gravity scanner with various other sensors, used to detect irregularities in surrounding space. Can only run in vacuum to protect delicate quantum BS elements." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "sensors" + var/max_health = 200 + var/health = 200 + var/critical_heat = 50 // sparks and takes damage when active & above this heat + var/heat_reduction = 1.5 // mitigates this much heat per tick + var/heat = 0 + var/range = 1 + idle_power_usage = 5000 + +/obj/machinery/shipsensors/attackby(obj/item/weapon/W, mob/user) + var/damage = max_health - health + if(damage && isWelder(W)) + + var/obj/item/weapon/weldingtool/WT = W + + if(!WT.isOn()) + return + + if(WT.remove_fuel(0,user)) + to_chat(user, "You start repairing the damage to [src].") + playsound(src, 'sound/items/Welder.ogg', 100, 1) + if(do_after(user, max(5, damage / 5), src) && WT && WT.isOn()) + to_chat(user, "You finish repairing the damage to [src].") + take_damage(-damage) + else + to_chat(user, "You need more welding fuel to complete this task.") + return + return + ..() + +/obj/machinery/shipsensors/proc/in_vacuum() + var/turf/T=get_turf(src) + if(istype(T)) + var/datum/gas_mixture/environment = T.return_air() + if(environment && environment.return_pressure() > MINIMUM_PRESSURE_DIFFERENCE_TO_SUSPEND) + return 0 + return 1 + +/obj/machinery/shipsensors/update_icon() + if(use_power) + icon_state = "sensors" + else + icon_state = "sensors_off" + +/obj/machinery/shipsensors/examine(mob/user) + . = ..() + if(health <= 0) + to_chat(user, "\The [src] is wrecked.") + else if(health < max_health * 0.25) + to_chat(user, "\The [src] looks like it's about to break!") + else if(health < max_health * 0.5) + to_chat(user, "\The [src] looks seriously damaged!") + else if(health < max_health * 0.75) + to_chat(user, "\The [src] shows signs of damage!") + +/obj/machinery/shipsensors/bullet_act(var/obj/item/projectile/Proj) + take_damage(Proj.get_structure_damage()) + ..() + +/obj/machinery/shipsensors/proc/toggle() + if(!use_power && health == 0) + return + if(!use_power) //need some juice to kickstart + use_power(idle_power_usage*5) + use_power = !use_power + update_icon() + +/obj/machinery/shipsensors/Process() + ..() + if(use_power) //can't run in non-vacuum + if(!in_vacuum()) + toggle() + if(heat > critical_heat) + src.visible_message("\The [src] violently spews out sparks!") + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + + take_damage(rand(10,50)) + toggle() + heat += idle_power_usage/15000 + + if (heat > 0) + heat = max(0, heat - heat_reduction) + +/obj/machinery/shipsensors/power_change() + if(use_power && !powered()) + toggle() + +/obj/machinery/shipsensors/proc/set_range(nrange) + range = nrange + idle_power_usage = 1500 * (range**2) // Exponential increase, also affects speed of overheating + +/obj/machinery/shipsensors/emp_act(severity) + if(!use_power) + return + take_damage(20/severity) + toggle() + +/obj/machinery/shipsensors/proc/take_damage(value) + health = min(max(health - value, 0),max_health) + if(use_power && health == 0) + toggle() \ No newline at end of file diff --git a/code/modules/overmap/ships/computers/shuttle.dm b/code/modules/overmap/ships/computers/shuttle.dm new file mode 100644 index 00000000..fe775ea8 --- /dev/null +++ b/code/modules/overmap/ships/computers/shuttle.dm @@ -0,0 +1,95 @@ +//Shuttle controller computer for shuttles going between sectors +/obj/machinery/computer/shuttle_control/explore + name = "general shuttle control console" + icon_state = "thick" + +/obj/machinery/computer/shuttle_control/explore/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + var/datum/shuttle/autodock/overmap/shuttle = shuttle_controller.shuttles[shuttle_tag] + if (!istype(shuttle)) + to_chat(usr,"Unable to establish link with the shuttle.") + return + + var/shuttle_state + switch(shuttle.moving_status) + if(SHUTTLE_IDLE) shuttle_state = "idle" + if(SHUTTLE_WARMUP) shuttle_state = "warmup" + if(SHUTTLE_INTRANSIT) shuttle_state = "in_transit" + + var/shuttle_status + switch (shuttle.process_state) + if(IDLE_STATE) + if (shuttle.in_use) + shuttle_status = "Busy." + else + shuttle_status = "Standing-by at [shuttle.get_location_name()]." + if(WAIT_LAUNCH, FORCE_LAUNCH) + shuttle_status = "Shuttle has recieved command and will depart shortly." + if(WAIT_ARRIVE) + shuttle_status = "Proceeding to [shuttle.get_destination_name()]." + if(WAIT_FINISH) + shuttle_status = "Arriving at destination now." + + var/datum/computer/file/embedded_program/docking/docking_controller = shuttle.active_docking_controller + + var/fuel_pressure = 0 + var/fuel_max_pressure = 0 + if(shuttle.fuel_ports) + if(shuttle.fuel_ports.len) + for(var/obj/structure/fuel_port/FP in shuttle.fuel_ports) //loop through fuel ports + if(FP.contents.len) + var/obj/item/weapon/tank/fuel_tank = FP.contents[1] + if(istype(fuel_tank)) + fuel_pressure += fuel_tank.air_contents.return_pressure() + fuel_max_pressure += 1013 + + if(fuel_max_pressure == 0) fuel_max_pressure = 1 + + data = list( + "destination_name" = shuttle.get_destination_name(), + "can_pick" = shuttle.moving_status == SHUTTLE_IDLE, + "shuttle_status" = shuttle_status, + "shuttle_state" = shuttle_state, + "has_docking" = docking_controller? 1 : 0, + "docking_status" = docking_controller? docking_controller.get_docking_status() : null, + "docking_override" = docking_controller? docking_controller.override_enabled : null, + "can_launch" = shuttle.can_launch(), + "can_cancel" = shuttle.can_cancel(), + "can_force" = shuttle.can_force(), + "fuel_port_present" = shuttle.fuel_consumption? 1 : 0, + "fuel_pressure" = fuel_pressure, + "fuel_max_pressure" = fuel_max_pressure, + "fuel_pressure_status" = (fuel_pressure/fuel_max_pressure > 0.2)? "good" : "bad" + ) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + + if (!ui) + ui = new(user, src, ui_key, "shuttle_control_console_exploration.tmpl", "[shuttle_tag] Shuttle Control", 510, 340) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/computer/shuttle_control/explore/get_ui_data(var/datum/shuttle/autodock/overmap/shuttle) + . = ..() + if(istype(shuttle)) + . += list( + "destination_name" = shuttle.get_destination_name(), + "can_pick" = shuttle.moving_status == SHUTTLE_IDLE, + ) + +/obj/machinery/computer/shuttle_control/explore/handle_topic_href(var/datum/shuttle/autodock/overmap/shuttle, var/list/href_list) + if((. = ..()) != null) + return + + if(href_list["pick"]) + var/list/possible_d = shuttle.get_possible_destinations() + var/D + if(possible_d.len) + D = input("Choose shuttle destination", "Shuttle Destination") as null|anything in possible_d + else + to_chat(usr,"No valid landing sites in range.") + possible_d = shuttle.get_possible_destinations() + if(CanInteract(usr, GLOB.default_state) && (D in possible_d)) + shuttle.set_destination(possible_d[D]) + return TOPIC_REFRESH diff --git a/code/modules/overmap/ships/engines/engine.dm b/code/modules/overmap/ships/engines/engine.dm new file mode 100644 index 00000000..760181af --- /dev/null +++ b/code/modules/overmap/ships/engines/engine.dm @@ -0,0 +1,49 @@ +//Engine component object + +var/list/ship_engines = list() +/datum/ship_engine + var/name = "ship engine" + var/obj/machinery/holder //actual engine object + +/datum/ship_engine/New(var/obj/machinery/_holder) + ..() + holder = _holder + ship_engines += src + var/obj/effect/overmap/ship/S = map_sectors["[holder.z]"] + if(istype(S)) + S.engines |= src + +/datum/ship_engine/proc/can_burn() + return 0 + +//Tries to fire the engine. Returns thrust +/datum/ship_engine/proc/burn() + return 0 + +//Returns status string for this engine +/datum/ship_engine/proc/get_status() + return "All systems nominal" + +/datum/ship_engine/proc/get_thrust() + return 1 + +//Sets thrust limiter, a number between 0 and 1 +/datum/ship_engine/proc/set_thrust_limit(var/new_limit) + return 1 + +/datum/ship_engine/proc/get_thrust_limit() + return 1 + +/datum/ship_engine/proc/is_on() + return 1 + +/datum/ship_engine/proc/toggle() + return 1 + +/datum/ship_engine/Destroy() + ..() + ship_engines -= src + var/obj/effect/overmap/ship/S = map_sectors["[holder.z]"] + if(istype(S)) + S.engines -= src + holder = null \ No newline at end of file diff --git a/code/modules/overmap/ships/engines/gas_thruster.dm b/code/modules/overmap/ships/engines/gas_thruster.dm new file mode 100644 index 00000000..dc6d55b6 --- /dev/null +++ b/code/modules/overmap/ships/engines/gas_thruster.dm @@ -0,0 +1,135 @@ +//Gas nozzle engine +/datum/ship_engine/gas_thruster + name = "gas thruster" + var/obj/machinery/atmospherics/unary/engine/nozzle + +/datum/ship_engine/gas_thruster/New(var/obj/machinery/_holder) + ..() + nozzle = _holder + +/datum/ship_engine/gas_thruster/Destroy() + nozzle = null + . = ..() + +/datum/ship_engine/gas_thruster/get_status() + return nozzle.get_status() + +/datum/ship_engine/gas_thruster/get_thrust() + return nozzle.get_thrust() + +/datum/ship_engine/gas_thruster/burn() + return nozzle.burn() + +/datum/ship_engine/gas_thruster/set_thrust_limit(var/new_limit) + nozzle.thrust_limit = new_limit + +/datum/ship_engine/gas_thruster/get_thrust_limit() + return nozzle.thrust_limit + +/datum/ship_engine/gas_thruster/is_on() + return nozzle.is_on() + +/datum/ship_engine/gas_thruster/toggle() + nozzle.on = !nozzle.on + +/datum/ship_engine/gas_thruster/can_burn() + return nozzle.is_on() && nozzle.check_fuel() + +//Actual thermal nozzle engine object + +/obj/machinery/atmospherics/unary/engine + name = "rocket nozzle" + desc = "Simple rocket nozzle, expelling gas at hypersonic velocities to propell the ship." + icon = 'icons/obj/ship_engine.dmi' + icon_state = "nozzle" + use_power = 0 + idle_power_usage = 150 //internal circuitry, friction losses and stuff + power_rating = 7500 //7500 W ~ 10 HP + opacity = 1 + density = 1 + var/on = 1 + var/datum/ship_engine/gas_thruster/controller + var/thrust_limit = 1 //Value between 1 and 0 to limit the resulting thrust + var/moles_per_burn = 5 + +/obj/machinery/atmospherics/unary/engine/Initialize() + . = ..() + controller = new(src) + +/obj/machinery/atmospherics/unary/engine/Destroy() + QDEL_NULL(controller) + . = ..() + +/obj/machinery/atmospherics/unary/engine/proc/get_status() + . = list() + .+= "Location: [get_area(src)]." + if(!powered()) + .+= "Insufficient power to operate." + if(!check_fuel()) + .+= "Insufficient fuel for a burn." + + .+= "Propellant total mass: [round(air_contents.get_mass(),0.01)] kg." + .+= "Propellant used per burn: [round(air_contents.specific_mass() * moles_per_burn * thrust_limit,0.01)] kg." + .+= "Propellant pressure: [round(air_contents.return_pressure()/1000,0.1)] MPa." + . = jointext(.,"
            ") + +/obj/machinery/atmospherics/unary/engine/proc/is_on() + return on && powered() + +/obj/machinery/atmospherics/unary/engine/proc/check_fuel() + return air_contents.total_moles > moles_per_burn * thrust_limit + +/obj/machinery/atmospherics/unary/engine/proc/get_thrust() + if(!is_on() || !check_fuel()) + return 0 + var/used_part = moles_per_burn/air_contents.get_total_moles() * thrust_limit + . = calculate_thrust(air_contents, used_part) + return + +/obj/machinery/atmospherics/unary/engine/proc/burn() + if (!is_on()) + return 0 + if(!check_fuel()) + audible_message(src,"[src] coughs once and goes silent!") + on = !on + return 0 + var/exhaust_dir = reverse_direction(dir) + var/datum/gas_mixture/removed = air_contents.remove(moles_per_burn * thrust_limit) + . = calculate_thrust(removed) + playsound(loc, 'sound/machines/thruster.ogg', 100 * thrust_limit, 0, world.view * 4, 0.1) + var/turf/T = get_step(src,exhaust_dir) + if(T) + T.assume_air(removed) + new/obj/effect/engine_exhaust(T, exhaust_dir, air_contents.check_combustability() && air_contents.temperature >= PHORON_MINIMUM_BURN_TEMPERATURE) + +/obj/machinery/atmospherics/unary/engine/proc/calculate_thrust(datum/gas_mixture/propellant, used_part = 1) + return round(sqrt(propellant.get_mass() * used_part * air_contents.return_pressure()/100),0.1) + +//Exhaust effect +/obj/effect/engine_exhaust + name = "engine exhaust" + icon = 'icons/effects/effects.dmi' + icon_state = "smoke" + light_color = "#ed9200" + anchored = 1 + +/obj/effect/engine_exhaust/New(var/turf/nloc, var/ndir, var/flame) + ..(nloc) + if(flame) + icon_state = "exhaust" + nloc.hotspot_expose(1000,125) + set_light(5, 2) + set_dir(ndir) + spawn(20) + qdel(src) + +/obj/item/weapon/circuitboard/unary_atmos/engine + name = T_BOARD("gas thruster") + icon_state = "mcontroller" + build_path = /obj/machinery/atmospherics/unary/engine/ + origin_tech = list(TECH_POWER = 1, TECH_ENGINEERING = 2) + req_components = list( + /obj/item/stack/cable_coil = 2, + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/capacitor = 1, + /obj/item/pipe = 2) \ No newline at end of file diff --git a/code/modules/overmap/ships/ship.dm b/code/modules/overmap/ships/ship.dm new file mode 100644 index 00000000..fb3d75ec --- /dev/null +++ b/code/modules/overmap/ships/ship.dm @@ -0,0 +1,176 @@ +/obj/effect/overmap/ship + name = "generic ship" + desc = "Space faring vessel." + icon_state = "ship" + var/vessel_mass = 100 //tonnes, arbitrary number, affects acceleration provided by engines + var/default_delay = 6 SECONDS //time it takes to move to next tile on overmap + var/speed_mod = 10 //multiplier for how much ship's speed reduces above time + var/list/speed = list(0,0) //speed in x,y direction + var/last_burn = 0 //worldtime when ship last acceleated + var/burn_delay = 10 //how often ship can do burns + var/list/last_movement = list(0,0) //worldtime when ship last moved in x,y direction + var/fore_dir = NORTH //what dir ship flies towards for purpose of moving stars effect procs + + var/obj/machinery/computer/helm/nav_control + var/list/engines = list() + var/engines_state = 1 //global on/off toggle for all engines + var/thrust_limit = 1 //global thrust limit for all engines, 0..1 + var/triggers_events = 1 + +/obj/effect/overmap/ship/Initialize() + . = ..() + for(var/datum/ship_engine/E in ship_engines) + if (E.holder.z in map_z) + engines |= E + for(var/obj/machinery/computer/engines/E in SSmachines.machinery) + if (E.z in map_z) + E.linked = src + //testing("Engines console at level [E.z] linked to overmap object '[name]'.") + for(var/obj/machinery/computer/helm/H in SSmachines.machinery) + if (H.z in map_z) + nav_control = H + H.linked = src + H.get_known_sectors() + //testing("Helm console at level [H.z] linked to overmap object '[name]'.") + for(var/obj/machinery/computer/navigation/N in SSmachines.machinery) + if (N.z in map_z) + N.linked = src + //testing("Navigation console at level [N.z] linked to overmap object '[name]'.") + START_PROCESSING(SSobj, src) + +/obj/effect/overmap/ship/relaymove(mob/user, direction) + accelerate(direction) + +/obj/effect/overmap/ship/proc/is_still() + return !(speed[1] || speed[2]) + +//Projected acceleration based on information from engines +/obj/effect/overmap/ship/proc/get_acceleration() + return round(get_total_thrust()/vessel_mass, 0.1) + +//Does actual burn and returns the resulting acceleration +/obj/effect/overmap/ship/proc/get_burn_acceleration() + return round(burn() / vessel_mass, 0.1) + +/obj/effect/overmap/ship/proc/get_speed() + return round(sqrt(speed[1]*speed[1] + speed[2]*speed[2]), 0.1) + +/obj/effect/overmap/ship/proc/get_heading() + var/res = 0 + if(speed[1]) + if(speed[1] > 0) + res |= EAST + else + res |= WEST + if(speed[2]) + if(speed[2] > 0) + res |= NORTH + else + res |= SOUTH + return res + +/obj/effect/overmap/ship/proc/adjust_speed(n_x, n_y) + speed[1] = round(Clamp(speed[1] + n_x, -default_delay, default_delay),0.1) + speed[2] = round(Clamp(speed[2] + n_y, -default_delay, default_delay),0.1) + for(var/zz in map_z) + if(is_still()) + toggle_move_stars(zz) + else + toggle_move_stars(zz, fore_dir) + update_icon() + +/obj/effect/overmap/ship/proc/get_brake_path() + if(!get_acceleration()) + return INFINITY + var/num_burns = get_speed()/get_acceleration() + 2 //some padding in case acceleration drops form fuel usage + var/burns_per_grid = (default_delay - speed_mod*get_speed())/burn_delay + return round(num_burns/burns_per_grid) + +/obj/effect/overmap/ship/proc/decelerate() + if(!is_still() && can_burn()) + if (speed[1]) + adjust_speed(-SIGN(speed[1]) * min(get_burn_acceleration(),abs(speed[1])), 0) + if (speed[2]) + adjust_speed(0, -SIGN(speed[2]) * min(get_burn_acceleration(),abs(speed[2]))) + last_burn = world.time + +/obj/effect/overmap/ship/proc/accelerate(direction) + if(can_burn()) + last_burn = world.time + + if(direction & EAST) + adjust_speed(get_burn_acceleration(), 0) + if(direction & WEST) + adjust_speed(-get_burn_acceleration(), 0) + if(direction & NORTH) + adjust_speed(0, get_burn_acceleration()) + if(direction & SOUTH) + adjust_speed(0, -get_burn_acceleration()) + +/obj/effect/overmap/ship/Process() + if(!is_still()) + var/list/deltas = list(0,0) + for(var/i=1, i<=2, i++) + if(speed[i] && world.time > last_movement[i] + default_delay - speed_mod*abs(speed[i])) + deltas[i] = speed[i] > 0 ? 1 : -1 + last_movement[i] = world.time + var/turf/newloc = locate(x + deltas[1], y + deltas[2], z) + if(newloc) + Move(newloc) + handle_wraparound() + update_icon() + +/obj/effect/overmap/ship/update_icon() + if(!is_still()) + icon_state = "ship_moving" + dir = get_heading() + else + icon_state = "ship" + +/obj/effect/overmap/ship/proc/burn() + for(var/datum/ship_engine/E in engines) + . += E.burn() + +/obj/effect/overmap/ship/proc/get_total_thrust() + for(var/datum/ship_engine/E in engines) + . += E.get_thrust() + +/obj/effect/overmap/ship/proc/can_burn() + if (world.time < last_burn + burn_delay) + return 0 + for(var/datum/ship_engine/E in engines) + . |= E.can_burn() + +//deciseconds to next step +/obj/effect/overmap/ship/proc/ETA() + . = INFINITY + for(var/i=1, i<=2, i++) + if(speed[i]) + . = min(last_movement[i] + default_delay - speed_mod*abs(speed[i]) - world.time, .) + . = max(.,0) + +/obj/effect/overmap/ship/proc/handle_wraparound() + var/nx = x + var/ny = y + var/low_edge = 1 + var/high_edge = GLOB.using_map.overmap_size - 1 + + if(dir == WEST && x == low_edge) + nx = high_edge + else if(dir == EAST && x == high_edge) + nx = low_edge + else if(dir == SOUTH && y == low_edge) + ny = high_edge + else if(dir == NORTH && y == high_edge) + ny = low_edge + else + return //we're not flying off anywhere + + var/turf/T = locate(nx,ny,z) + if(T) + forceMove(T) + +/obj/effect/overmap/ship/Bump(var/atom/A) + if(istype(A,/turf/unsimulated/map/edge)) + handle_wraparound() + ..() \ No newline at end of file diff --git a/code/modules/overmap/spacetravel.dm b/code/modules/overmap/spacetravel.dm new file mode 100644 index 00000000..f3819367 --- /dev/null +++ b/code/modules/overmap/spacetravel.dm @@ -0,0 +1,108 @@ +//list used to cache empty zlevels to avoid nedless map bloat +var/list/cached_space = list() + +//Space stragglers go here + +/obj/effect/overmap/sector/temporary + name = "Deep Space" + invisibility = 101 + known = 0 + +/obj/effect/overmap/sector/temporary/New(var/nx, var/ny, var/nz) + loc = locate(nx, ny, GLOB.using_map.overmap_z) + x = nx + y = ny + map_z += nz + map_sectors["[nz]"] = src + testing("Temporary sector at [x],[y] was created, corresponding zlevel is [nz].") + +/obj/effect/overmap/sector/temporary/Destroy() + map_sectors["[map_z]"] = null + testing("Temporary sector at [x],[y] was deleted.") + +/obj/effect/overmap/sector/temporary/proc/can_die(var/mob/observer) + testing("Checking if sector at [map_z[1]] can die.") + for(var/mob/M in GLOB.player_list) + if(M != observer && M.z in map_z) + testing("There are people on it.") + return 0 + return 1 + +proc/get_deepspace(x,y) + var/obj/effect/overmap/sector/temporary/res = locate(x,y,GLOB.using_map.overmap_z) + if(istype(res)) + return res + else if(cached_space.len) + res = cached_space[cached_space.len] + cached_space -= res + res.x = x + res.y = y + return res + else + return new /obj/effect/overmap/sector/temporary(x, y, GLOB.using_map.get_empty_zlevel()) + +/atom/movable/proc/lost_in_space() + return TRUE + +/mob/lost_in_space() + return isnull(client) + +proc/overmap_spacetravel(var/turf/space/T, var/atom/movable/A) + if (!T || !A) + return + + var/obj/effect/overmap/M = map_sectors["[T.z]"] + if (!M) + return + + if(A.lost_in_space()) + if(!QDELETED(A)) + qdel(A) + return + + var/nx = 1 + var/ny = 1 + var/nz = 1 + + if(T.x <= TRANSITIONEDGE) + nx = world.maxx - TRANSITIONEDGE - 2 + ny = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) + + else if (A.x >= (world.maxx - TRANSITIONEDGE - 1)) + nx = TRANSITIONEDGE + 2 + ny = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) + + else if (T.y <= TRANSITIONEDGE) + ny = world.maxy - TRANSITIONEDGE -2 + nx = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) + + else if (A.y >= (world.maxy - TRANSITIONEDGE - 1)) + ny = TRANSITIONEDGE + 2 + nx = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) + + testing("[A] spacemoving from [M] ([M.x], [M.y]).") + + var/turf/map = locate(M.x,M.y,GLOB.using_map.overmap_z) + var/obj/effect/overmap/TM + for(var/obj/effect/overmap/O in map) + if(O != M && O.in_space && prob(50)) + TM = O + break + if(!TM) + TM = get_deepspace(M.x,M.y) + nz = pick(TM.map_z) + + var/turf/dest = locate(nx,ny,nz) + if(dest) + A.forceMove(dest) + if(ismob(A)) + var/mob/D = A + if(D.pulling) + D.pulling.forceMove(dest) + + if(istype(M, /obj/effect/overmap/sector/temporary)) + var/obj/effect/overmap/sector/temporary/source = M + if (source.can_die()) + testing("Caching [M] for future use") + source.loc = null + cached_space += source diff --git a/code/modules/paperwork/adminpaper.dm b/code/modules/paperwork/adminpaper.dm new file mode 100644 index 00000000..bfb13908 --- /dev/null +++ b/code/modules/paperwork/adminpaper.dm @@ -0,0 +1,160 @@ +//Adminpaper - it's like paper, but more adminny! +/obj/item/weapon/paper/admin + name = "administrative paper" + desc = "If you see this, something has gone horribly wrong." + var/datum/admins/admindatum = null + + var/interactions = null + var/isCrayon = 0 + var/origin = null + var/mob/sender = null + var/obj/machinery/photocopier/faxmachine/destination + + var/header = null + var/headerOn = TRUE + + var/footer = null + var/footerOn = FALSE + + var/logo_list = list("ntlogo.png","sollogo.png","terralogo.png") + var/logo = "" + +/obj/item/weapon/paper/admin/New() + ..() + generateInteractions() + + +/obj/item/weapon/paper/admin/proc/generateInteractions() + //clear first + interactions = null + + //Snapshot is crazy and likes putting each topic hyperlink on a seperate line from any other tags so it's nice and clean. + interactions += "
            The fax will transmit everything above this line
            " + interactions += "Send fax " + interactions += "Pen mode: [isCrayon ? "Crayon" : "Pen"] " + interactions += "Cancel fax " + interactions += "
            " + interactions += "Change logo " + interactions += "Toggle Header " + interactions += "Toggle Footer " + interactions += "Clear page " + interactions += "
            " + +/obj/item/weapon/paper/admin/proc/generateHeader() + var/originhash = md5("[origin]") + var/challengehash = copytext(md5("[game_id]"),1,10) // changed to a hash of the game ID so it's more consistant but changes every round. + var/text = null + //TODO change logo based on who you're contacting. + text = "

            " + text += "[origin] Quantum Uplink Signed Message
            " + text += "Encryption key: [originhash]
            " + text += "Challenge: [challengehash]

            " + + header = text + +/obj/item/weapon/paper/admin/proc/generateFooter() + var/text = null + + text = "
            " + text += "This transmission is intended only for the addressee and may contain confidential information. Any unauthorized disclosure is strictly prohibited.

            " + text += "If this transmission is recieved in error, please notify both the sender and the office of [GLOB.using_map.boss_name] Internal Affairs immediately so that corrective action may be taken." + text += "Failure to comply is a breach of regulation and may be prosecuted to the fullest extent of the law, where applicable." + text += "
            " + + footer = text + + +/obj/item/weapon/paper/admin/proc/adminbrowse() + updateinfolinks() + generateHeader() + generateFooter() + updateDisplay() + +obj/item/weapon/paper/admin/proc/updateDisplay() + usr << browse("[name][headerOn ? header : ""][info_links][stamps][footerOn ? footer : ""][interactions]", "window=[name];can_close=0") + + + +/obj/item/weapon/paper/admin/Topic(href, href_list) + if(href_list["write"]) + var/id = href_list["write"] + if(free_space <= 0) + to_chat(usr, "There isn't enough space left on \the [src] to write anything.") + return + + var/t = sanitize(input("Enter what you want to write:", "Write", null, null) as message, free_space, extra = 0) + + if(!t) + return + + var last_fields_value = fields + + //t = html_encode(t) + t = replacetext(t, "\n", "
            ") + t = parsepencode(t,,, isCrayon) // Encode everything from pencode to html + + + if(fields > 50)//large amount of fields creates a heavy load on the server, see updateinfolinks() and addtofield() + to_chat(usr, "Too many fields. Sorry, you can't do this.") + fields = last_fields_value + return + + if(id!="end") + addtofield(text2num(id), t) // He wants to edit a field, let him. + else + info += t // Oh, he wants to edit to the end of the file, let him. + updateinfolinks() + + update_space(t) + + updateDisplay() + + update_icon() + return + + if(href_list["confirm"]) + switch(alert("Are you sure you want to send the fax as is?",, "Yes", "No")) + if("Yes") + if(headerOn) + info = header + info + if(footerOn) + info += footer + updateinfolinks() + usr << browse(null, "window=[name]") + admindatum.faxCallback(src, destination) + return + + if(href_list["penmode"]) + isCrayon = !isCrayon + generateInteractions() + updateDisplay() + return + + if(href_list["cancel"]) + usr << browse(null, "window=[name]") + qdel(src) + return + + if(href_list["clear"]) + clearpaper() + updateDisplay() + return + + if(href_list["toggleheader"]) + headerOn = !headerOn + updateDisplay() + return + + if(href_list["togglefooter"]) + footerOn = !footerOn + updateDisplay() + return + + if(href_list["changelogo"]) + logo = input(usr, "What logo?", "Choose a logo", "") as null|anything in (logo_list) + generateHeader() + updateDisplay() + return + +/obj/item/weapon/paper/admin/get_signature() + return input(usr, "Enter the name you wish to sign the paper with (will prompt for multiple entries, in order of entry)", "Signature") as text|null \ No newline at end of file diff --git a/code/modules/paperwork/carbonpaper.dm b/code/modules/paperwork/carbonpaper.dm new file mode 100644 index 00000000..8954a965 --- /dev/null +++ b/code/modules/paperwork/carbonpaper.dm @@ -0,0 +1,51 @@ +/obj/item/weapon/paper/carbon + name = "paper" + icon_state = "paper_stack" + item_state = "paper" + var/copied = 0 + var/iscopy = 0 + + +/obj/item/weapon/paper/carbon/update_icon() + if(iscopy) + if(info) + icon_state = "cpaper_words" + return + icon_state = "cpaper" + else if (copied) + if(info) + icon_state = "paper_words" + return + icon_state = "paper" + else + if(info) + icon_state = "paper_stack_words" + return + icon_state = "paper_stack" + + + +/obj/item/weapon/paper/carbon/verb/removecopy() + set name = "Remove carbon-copy" + set category = "Object" + set src in usr + + if (copied == 0) + var/obj/item/weapon/paper/carbon/c = src + var/copycontents = html_decode(c.info) + var/obj/item/weapon/paper/carbon/copy = new /obj/item/weapon/paper/carbon (usr.loc) + // + copycontents = replacetext(copycontents, "" + copy.SetName("Copy - " + c.name) + copy.fields = c.fields + copy.updateinfolinks() + to_chat(usr, "You tear off the carbon-copy!") + c.copied = 1 + copy.iscopy = 1 + copy.update_icon() + c.update_icon() + else + to_chat(usr, "There are no more carbon copies attached to this paper!") diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm new file mode 100644 index 00000000..401c24b4 --- /dev/null +++ b/code/modules/paperwork/clipboard.dm @@ -0,0 +1,172 @@ +/obj/item/weapon/clipboard + name = "clipboard" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "clipboard" + item_state = "clipboard" + throwforce = 0 + w_class = ITEM_SIZE_SMALL + throw_speed = 3 + throw_range = 10 + var/obj/item/weapon/pen/haspen //The stored pen. + var/obj/item/weapon/toppaper //The topmost piece of paper. + slot_flags = SLOT_BELT + matter = list(DEFAULT_WALL_MATERIAL = 70) + +/obj/item/weapon/clipboard/New() + update_icon() + +/obj/item/weapon/clipboard/MouseDrop(obj/over_object as obj) //Quick clipboard fix. -Agouri + if(ishuman(usr)) + var/mob/M = usr + if(!(istype(over_object, /obj/screen) )) + return ..() + + if(!M.restrained() && !M.stat) + switch(over_object.name) + if("r_hand") + if(M.unEquip(src)) + M.put_in_r_hand(src) + if("l_hand") + if(M.unEquip(src)) + M.put_in_l_hand(src) + + add_fingerprint(usr) + return + +/obj/item/weapon/clipboard/update_icon() + overlays.Cut() + if(toppaper) + overlays += toppaper.icon_state + overlays += toppaper.overlays + if(haspen) + overlays += "clipboard_pen" + overlays += "clipboard_over" + return + +/obj/item/weapon/clipboard/attackby(obj/item/weapon/W as obj, mob/user as mob) + + if(istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/weapon/photo)) + user.drop_item() + W.loc = src + if(istype(W, /obj/item/weapon/paper)) + toppaper = W + to_chat(user, "You clip the [W] onto \the [src].") + update_icon() + + else if(istype(toppaper) && istype(W, /obj/item/weapon/pen)) + toppaper.attackby(W, usr) + update_icon() + + return + +/obj/item/weapon/clipboard/attack_self(mob/user as mob) + var/dat = "Clipboard" + if(haspen) + dat += "Remove Pen

            " + else + dat += "Add Pen

            " + + //The topmost paper. I don't think there's any way to organise contents in byond, so this is what we're stuck with. -Pete + if(toppaper) + var/obj/item/weapon/paper/P = toppaper + dat += "Write Remove Rename - [P.name]

            " + + for(var/obj/item/weapon/paper/P in src) + if(P==toppaper) + continue + dat += "Remove Rename - [P.name]
            " + for(var/obj/item/weapon/photo/Ph in src) + dat += "Remove Rename - [Ph.name]
            " + + user << browse(dat, "window=clipboard") + onclose(user, "clipboard") + add_fingerprint(usr) + return + +/obj/item/weapon/clipboard/Topic(href, href_list) + ..() + if((usr.stat || usr.restrained())) + return + + if(src.loc == usr) + + if(href_list["pen"]) + if(istype(haspen) && (haspen.loc == src)) + haspen.loc = usr.loc + usr.put_in_hands(haspen) + haspen = null + + else if(href_list["addpen"]) + if(!haspen) + var/obj/item/weapon/pen/W = usr.get_active_hand() + if(istype(W, /obj/item/weapon/pen)) + usr.drop_item() + W.loc = src + haspen = W + to_chat(usr, "You slot the pen into \the [src].") + + else if(href_list["write"]) + var/obj/item/weapon/P = locate(href_list["write"]) + + if(P && (P.loc == src) && istype(P, /obj/item/weapon/paper) && (P == toppaper) ) + + var/obj/item/I = usr.get_active_hand() + + if(istype(I, /obj/item/weapon/pen)) + + P.attackby(I, usr) + + else if(href_list["remove"]) + var/obj/item/P = locate(href_list["remove"]) + + if(P && (P.loc == src) && (istype(P, /obj/item/weapon/paper) || istype(P, /obj/item/weapon/photo)) ) + + P.loc = usr.loc + usr.put_in_hands(P) + if(P == toppaper) + toppaper = null + var/obj/item/weapon/paper/newtop = locate(/obj/item/weapon/paper) in src + if(newtop && (newtop != P)) + toppaper = newtop + else + toppaper = null + + else if(href_list["rename"]) + var/obj/item/weapon/O = locate(href_list["rename"]) + + if(O && (O.loc == src)) + if(istype(O, /obj/item/weapon/paper)) + var/obj/item/weapon/paper/to_rename = O + to_rename.rename() + + else if(istype(O, /obj/item/weapon/photo)) + var/obj/item/weapon/photo/to_rename = O + to_rename.rename() + + else if(href_list["read"]) + var/obj/item/weapon/paper/P = locate(href_list["read"]) + + if(P && (P.loc == src) && istype(P, /obj/item/weapon/paper) ) + + if(!(istype(usr, /mob/living/carbon/human) || isghost(usr) || istype(usr, /mob/living/silicon))) + usr << browse("[P.name][stars(P.info)][P.stamps]", "window=[P.name]") + onclose(usr, "[P.name]") + else + usr << browse("[P.name][P.info][P.stamps]", "window=[P.name]") + onclose(usr, "[P.name]") + + else if(href_list["look"]) + var/obj/item/weapon/photo/P = locate(href_list["look"]) + if(P && (P.loc == src) && istype(P, /obj/item/weapon/photo) ) + P.show(usr) + + else if(href_list["top"]) // currently unused + var/obj/item/P = locate(href_list["top"]) + if(P && (P.loc == src) && istype(P, /obj/item/weapon/paper) ) + toppaper = P + to_chat(usr, "You move [P.name] to the top.") + + //Update everything + attack_self(usr) + update_icon() + return diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm new file mode 100644 index 00000000..e2286f6b --- /dev/null +++ b/code/modules/paperwork/faxmachine.dm @@ -0,0 +1,230 @@ +GLOBAL_LIST_EMPTY(allfaxes) +GLOBAL_LIST_EMPTY(alldepartments) + +GLOBAL_LIST_EMPTY(adminfaxes) //cache for faxes that have been sent to admins + +/obj/machinery/photocopier/faxmachine + name = "fax machine" + icon = 'icons/obj/library.dmi' + icon_state = "fax" + insert_anim = "faxsend" + req_one_access = list(access_lawyer, access_heads, access_armory, access_qm) + + use_power = 1 + idle_power_usage = 30 + active_power_usage = 200 + + var/obj/item/weapon/card/id/scan = null // identification + var/authenticated = 0 + var/sendcooldown = 0 // to avoid spamming fax messages + var/department = "Unknown" // our department + var/destination = null // the department we're sending to + + var/static/list/admin_departments + +/obj/machinery/photocopier/faxmachine/Initialize() + . = ..() + + if(!admin_departments) + admin_departments = list("[GLOB.using_map.boss_name]", "Colonial Marshal Service", "[GLOB.using_map.boss_short] Supply") + GLOB.using_map.map_admin_faxes + GLOB.allfaxes += src + if(!destination) destination = "[GLOB.using_map.boss_name]" + if( !(("[department]" in GLOB.alldepartments) || ("[department]" in admin_departments))) + GLOB.alldepartments |= department + +/obj/machinery/photocopier/faxmachine/attack_hand(mob/user as mob) + user.set_machine(src) + + var/dat = "Fax Machine
            " + + var/scan_name + if(scan) + scan_name = scan.name + else + scan_name = "--------" + + dat += "Confirm Identity: [scan_name]
            " + + if(authenticated) + dat += "{Log Out}" + else + dat += "{Log In}" + + dat += "
            " + + if(authenticated) + dat += "Logged in to: [GLOB.using_map.boss_name] Quantum Entanglement Network

            " + + if(copyitem) + dat += "Remove Item

            " + + if(sendcooldown) + dat += "Transmitter arrays realigning. Please stand by.
            " + + else + + dat += "Send
            " + dat += "Currently sending: [copyitem.name]
            " + dat += "Sending to: [destination]
            " + + else + if(sendcooldown) + dat += "Please insert paper to send via secure connection.

            " + dat += "Transmitter arrays realigning. Please stand by.
            " + else + dat += "Please insert paper to send via secure connection.

            " + + else + dat += "Proper authentication is required to use this device.

            " + + if(copyitem) + dat += "Remove Item
            " + + user << browse(dat, "window=copier") + onclose(user, "copier") + return + +/obj/machinery/photocopier/faxmachine/Topic(href, href_list) + if(href_list["send"]) + if(copyitem) + if (destination in admin_departments) + send_admin_fax(usr, destination) + else + sendfax(destination) + + if (sendcooldown) + spawn(sendcooldown) // cooldown time + sendcooldown = 0 + + else if(href_list["remove"]) + if(copyitem) + copyitem.loc = usr.loc + usr.put_in_hands(copyitem) + to_chat(usr, "You take \the [copyitem] out of \the [src].") + copyitem = null + updateUsrDialog() + + if(href_list["scan"]) + if (scan) + if(ishuman(usr)) + scan.loc = usr.loc + if(!usr.get_active_hand()) + usr.put_in_hands(scan) + scan = null + else + scan.loc = src.loc + scan = null + else + var/obj/item/I = usr.get_active_hand() + if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I)) + I.loc = src + scan = I + authenticated = 0 + + if(href_list["dept"]) + var/lastdestination = destination + destination = input(usr, "Which department?", "Choose a department", "") as null|anything in (GLOB.alldepartments + admin_departments) + if(!destination) destination = lastdestination + + if(href_list["auth"]) + if ( (!( authenticated ) && (scan)) ) + if (check_access(scan)) + authenticated = 1 + + if(href_list["logout"]) + authenticated = 0 + + updateUsrDialog() + +/obj/machinery/photocopier/faxmachine/proc/sendfax(var/destination) + if(stat & (BROKEN|NOPOWER)) + return + + use_power(200) + + var/success = 0 + for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes) + if( F.department == destination ) + success = F.recievefax(copyitem) + + if (success) + visible_message("[src] beeps, \"Message transmitted successfully.\"") + //sendcooldown = 600 + else + visible_message("[src] beeps, \"Error transmitting message.\"") + +/obj/machinery/photocopier/faxmachine/proc/recievefax(var/obj/item/incoming) + if(stat & (BROKEN|NOPOWER)) + return 0 + + if(department == "Unknown") + return 0 //You can't send faxes to "Unknown" + + flick("faxreceive", src) + playsound(loc, "sound/machines/dotprinter.ogg", 50, 1) + + // give the sprite some time to flick + sleep(20) + + if (istype(incoming, /obj/item/weapon/paper)) + copy(incoming) + else if (istype(incoming, /obj/item/weapon/photo)) + photocopy(incoming) + else if (istype(incoming, /obj/item/weapon/paper_bundle)) + bundlecopy(incoming) + else + return 0 + + use_power(active_power_usage) + return 1 + +/obj/machinery/photocopier/faxmachine/proc/send_admin_fax(var/mob/sender, var/destination) + if(stat & (BROKEN|NOPOWER)) + return + + use_power(200) + + //recieved copies should not use toner since it's being used by admins only. + var/obj/item/rcvdcopy + if (istype(copyitem, /obj/item/weapon/paper)) + rcvdcopy = copy(copyitem, 0) + else if (istype(copyitem, /obj/item/weapon/photo)) + rcvdcopy = photocopy(copyitem, 0) + else if (istype(copyitem, /obj/item/weapon/paper_bundle)) + rcvdcopy = bundlecopy(copyitem, 0) + else + visible_message("[src] beeps, \"Error transmitting message.\"") + return + + rcvdcopy.loc = null //hopefully this shouldn't cause trouble + GLOB.adminfaxes += rcvdcopy + + var/mob/intercepted = check_for_interception() + + + //message badmins that a fax has arrived + if (destination == GLOB.using_map.boss_name) + message_admins(sender, "[uppertext(destination)] FAX[intercepted ? "(Intercepted by [intercepted])" : null]", rcvdcopy, destination, "#006100") + else if (destination == "Colonial Marshal Service") + message_admins(sender, "[uppertext(destination)] FAX[intercepted ? "(Intercepted by [intercepted])" : null]", rcvdcopy, destination, "#1f66a0") + else if (destination == "[GLOB.using_map.boss_short] Supply") + message_admins(sender, "[uppertext(destination)] FAX[intercepted ? "(Intercepted by [intercepted])" : null]", rcvdcopy, destination, "#5f4519") + else if (destination in GLOB.using_map.map_admin_faxes) + message_admins(sender, "[uppertext(destination)] FAX[intercepted ? "(Intercepted by [intercepted])" : null]", rcvdcopy, destination, "#510b74") + else + message_admins(sender, "[uppertext(destination)] FAX[intercepted ? "(Intercepted by [intercepted])" : null]", rcvdcopy, "UNKNOWN") + + sendcooldown = 1800 + sleep(50) + visible_message("[src] beeps, \"Message transmitted successfully.\"") + + +/obj/machinery/photocopier/faxmachine/proc/message_admins(var/mob/sender, var/faxname, var/obj/item/sent, var/reply_type, font_colour="#006100") + var/msg = "[faxname]: [get_options_bar(sender, 2,1,1)]" + msg += "(TAKE) (REPLY): " + msg += "Receiving '[sent.name]' via secure connection ... view message" + + for(var/client/C in GLOB.admins) + if(check_rights((R_ADMIN|R_MOD),0,C)) + to_chat(C, msg) + sound_to(C, 'sound/machines/dotprinter.ogg') diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm new file mode 100644 index 00000000..8c27caf9 --- /dev/null +++ b/code/modules/paperwork/filingcabinet.dm @@ -0,0 +1,110 @@ +/* Filing cabinets! + * Contains: + * Filing Cabinets + * Security Record Cabinets + * Medical Record Cabinets + */ + + +/* + * Filing Cabinets + */ +/obj/structure/filingcabinet + name = "filing cabinet" + desc = "A large cabinet with drawers." + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "filingcabinet" + density = 1 + anchored = 1 + atom_flags = ATOM_FLAG_CLIMBABLE + obj_flags = OBJ_FLAG_ANCHORABLE + var/list/can_hold = list( + /obj/item/weapon/paper, + /obj/item/weapon/folder, + /obj/item/weapon/photo, + /obj/item/weapon/paper_bundle, + /obj/item/weapon/sample) + +/obj/structure/filingcabinet/chestdrawer + name = "chest drawer" + icon_state = "chestdrawer" + +/obj/structure/filingcabinet/wallcabinet + name = "wall-mounted filing cabinet" + desc = "A filing cabinet installed into a cavity in the wall to save space. Wow!" + icon_state = "wallcabinet" + density = 0 + obj_flags = 0 + + +/obj/structure/filingcabinet/filingcabinet //not changing the path to avoid unecessary map issues, but please don't name stuff like this in the future -Pete + icon_state = "tallcabinet" + + +/obj/structure/filingcabinet/Initialize() + for(var/obj/item/I in loc) + if(istype(I, /obj/item/weapon/paper) || istype(I, /obj/item/weapon/folder) || istype(I, /obj/item/weapon/photo) || istype(I, /obj/item/weapon/paper_bundle)) + I.loc = src + . = ..() + +/obj/structure/filingcabinet/attackby(obj/item/P as obj, mob/user as mob) + if(is_type_in_list(P, can_hold)) + add_fingerprint(user) + to_chat(user, "You put [P] in [src].") + user.drop_item() + P.loc = src + icon_state = "[initial(icon_state)]-open" + sleep(5) + icon_state = initial(icon_state) + updateUsrDialog() + else + ..() + return + +var + H = "21a0234b124a753b07" + +/obj/structure/filingcabinet/attack_hand(mob/user as mob) + if(contents.len <= 0) + to_chat(user, "\The [src] is empty.") + return + + user.set_machine(src) + var/dat = "
            " + for(var/obj/item/P in src) + dat += "" + dat += "
            [P.name]
            " + user << browse("[name][dat]", "window=filingcabinet;size=350x300") + + return + +/obj/structure/filingcabinet/attack_tk(mob/user) + if(anchored) + attack_self_tk(user) + else + ..() + +/obj/structure/filingcabinet/attack_self_tk(mob/user) + if(contents.len) + if(prob(40 + contents.len * 5)) + var/obj/item/I = pick(contents) + I.loc = loc + if(prob(25)) + step_rand(I) + to_chat(user, "You pull \a [I] out of [src] at random.") + return + to_chat(user, "You find nothing in [src].") + +/obj/structure/filingcabinet/Topic(href, href_list) + if(href_list["retrieve"]) + usr << browse("", "window=filingcabinet") // Close the menu + + //var/retrieveindex = text2num(href_list["retrieve"]) + var/obj/item/P = locate(href_list["retrieve"])//contents[retrieveindex] + if(istype(P) && (P.loc == src) && src.Adjacent(usr)) + usr.put_in_hands(P) + updateUsrDialog() + icon_state = "[initial(icon_state)]-open" + spawn(0) + sleep(5) + icon_state = initial(icon_state) \ No newline at end of file diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm new file mode 100644 index 00000000..7962541c --- /dev/null +++ b/code/modules/paperwork/folders.dm @@ -0,0 +1,148 @@ +/obj/item/weapon/folder + name = "folder" + desc = "A folder." + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "folder" + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/folder/blue + desc = "A blue folder." + icon_state = "folder_blue" + +/obj/item/weapon/folder/red + desc = "A red folder." + icon_state = "folder_red" + +/obj/item/weapon/folder/yellow + desc = "A yellow folder." + icon_state = "folder_yellow" + +/obj/item/weapon/folder/white + desc = "A white folder." + icon_state = "folder_white" + +/obj/item/weapon/folder/nt + desc = "A NanoTrasen folder." + icon_state = "folder_nt" + +/obj/item/weapon/folder/update_icon() + overlays.Cut() + if(contents.len) + overlays += "folder_paper" + return + +/obj/item/weapon/folder/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/weapon/photo) || istype(W, /obj/item/weapon/paper_bundle)) + user.drop_item() + W.loc = src + to_chat(user, "You put the [W] into \the [src].") + update_icon() + else if(istype(W, /obj/item/weapon/pen)) + var/n_name = sanitizeSafe(input(usr, "What would you like to label the folder?", "Folder Labelling", null) as text, MAX_NAME_LEN) + if((loc == usr && usr.stat == 0)) + SetName("folder[(n_name ? text("- '[n_name]'") : null)]") + return + +/obj/item/weapon/folder/attack_self(mob/user as mob) + var/dat = "[name]" + + for(var/obj/item/weapon/paper/P in src) + dat += "Remove Rename - [P.name]
            " + for(var/obj/item/weapon/photo/Ph in src) + dat += "Remove Rename - [Ph.name]
            " + for(var/obj/item/weapon/paper_bundle/Pb in src) + dat += "Remove Rename - [Pb.name]
            " + user << browse(dat, "window=folder") + onclose(user, "folder") + add_fingerprint(usr) + return + +/obj/item/weapon/folder/Topic(href, href_list) + ..() + if((usr.stat || usr.restrained())) + return + + if(src.loc == usr) + + if(href_list["remove"]) + var/obj/item/P = locate(href_list["remove"]) + if(P && (P.loc == src) && istype(P)) + P.loc = usr.loc + usr.put_in_hands(P) + + else if(href_list["read"]) + var/obj/item/weapon/paper/P = locate(href_list["read"]) + if(P && (P.loc == src) && istype(P)) + if(!(istype(usr, /mob/living/carbon/human) || isghost(usr) || istype(usr, /mob/living/silicon))) + usr << browse("[P.name][stars(P.info)][P.stamps]", "window=[P.name]") + onclose(usr, "[P.name]") + else + usr << browse("[P.name][P.info][P.stamps]", "window=[P.name]") + onclose(usr, "[P.name]") + else if(href_list["look"]) + var/obj/item/weapon/photo/P = locate(href_list["look"]) + if(P && (P.loc == src) && istype(P)) + P.show(usr) + else if(href_list["browse"]) + var/obj/item/weapon/paper_bundle/P = locate(href_list["browse"]) + if(P && (P.loc == src) && istype(P)) + P.attack_self(usr) + onclose(usr, "[P.name]") + else if(href_list["rename"]) + var/obj/item/weapon/O = locate(href_list["rename"]) + + if(O && (O.loc == src)) + if(istype(O, /obj/item/weapon/paper)) + var/obj/item/weapon/paper/to_rename = O + to_rename.rename() + + else if(istype(O, /obj/item/weapon/photo)) + var/obj/item/weapon/photo/to_rename = O + to_rename.rename() + + else if(istype(O, /obj/item/weapon/paper_bundle)) + var/obj/item/weapon/paper_bundle/to_rename = O + to_rename.rename() + + //Update everything + attack_self(usr) + update_icon() + return + +/obj/item/weapon/folder/envelope + name = "envelope" + desc = "A thick envelope. You can't see what's inside." + icon_state = "envelope_sealed" + var/sealed = 1 + +/obj/item/weapon/folder/envelope/update_icon() + if(sealed) + icon_state = "envelope_sealed" + else + icon_state = "envelope[contents.len > 0]" + +/obj/item/weapon/folder/envelope/examine(var/user) + ..() + to_chat(user, "The seal is [sealed ? "intact" : "broken"].") + +/obj/item/weapon/folder/envelope/proc/sealcheck(user) + var/ripperoni = alert("Are you sure you want to break the seal on \the [src]?", "Confirmation","Yes", "No") + if(ripperoni == "Yes") + visible_message("[user] breaks the seal on \the [src], and opens it.") + sealed = 0 + update_icon() + return 1 + +/obj/item/weapon/folder/envelope/attack_self(mob/user as mob) + if(sealed) + sealcheck(user) + return + else + ..() + +/obj/item/weapon/folder/envelope/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(sealed) + sealcheck(user) + return + else + ..() \ No newline at end of file diff --git a/code/modules/paperwork/handlabeler.dm b/code/modules/paperwork/handlabeler.dm new file mode 100644 index 00000000..d00f86b1 --- /dev/null +++ b/code/modules/paperwork/handlabeler.dm @@ -0,0 +1,66 @@ +/obj/item/weapon/hand_labeler + name = "hand labeler" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "labeler0" + item_state = "flight" + var/label = null + var/labels_left = 30 + var/mode = 0 //off or on. + matter = list(DEFAULT_WALL_MATERIAL = 100) + +/obj/item/weapon/hand_labeler/attack() + return + +/obj/item/weapon/hand_labeler/afterattack(atom/A, mob/user as mob, proximity) + if(!proximity) + return + if(!mode) //if it's off, give up. + return + if(A == loc) // if placing the labeller into something (e.g. backpack) + return // don't set a label + + if(!labels_left) + to_chat(user, "No labels left.") + return + if(!label || !length(label)) + to_chat(user, "No label text set.") + return + if(has_extension(A, /datum/extension/labels)) + var/datum/extension/labels/L = get_extension(A, /datum/extension/labels) + if(!L.CanAttachLabel(user, label)) + return + A.attach_label(user, src, label) + +/atom/proc/attach_label(var/user, var/atom/labeler, var/label_text) + to_chat(user, "The label refuses to stick to [name].") + +/mob/observer/attach_label(var/user, var/atom/labeler, var/label_text) + to_chat(user, "\The [labeler] passes through \the [src].") + +/obj/machinery/portable_atmospherics/hydroponics/attach_label(var/user) + if(!mechanical) + to_chat(user, "How are you going to label that?") + return + ..() + update_icon() + +/obj/attach_label(var/user, var/atom/labeler, var/label_text) + if(!simulated) + return + var/datum/extension/labels/L = get_or_create_extension(src, /datum/extension/labels, /datum/extension/labels) + L.AttachLabel(user, label_text) + +/obj/item/weapon/hand_labeler/attack_self(mob/user as mob) + mode = !mode + icon_state = "labeler[mode]" + if(mode) + to_chat(user, "You turn on \the [src].") + //Now let them chose the text. + var/str = sanitizeSafe(input(user,"Label text?","Set label",""), MAX_LNAME_LEN) + if(!str || !length(str)) + to_chat(user, "Invalid text.") + return + label = str + to_chat(user, "You set the text to '[str]'.") + else + to_chat(user, "You turn off \the [src].") diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm new file mode 100644 index 00000000..af7e17b0 --- /dev/null +++ b/code/modules/paperwork/paper.dm @@ -0,0 +1,451 @@ +#define MAX_FIELDS 50 + +/* + * Paper + * also scraps of paper + */ + +/obj/item/weapon/paper + name = "sheet of paper" + gender = NEUTER + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "paper" + item_state = "paper" + randpixel = 8 + throwforce = 0 + w_class = ITEM_SIZE_TINY + throw_range = 1 + throw_speed = 1 + layer = ABOVE_OBJ_LAYER + slot_flags = SLOT_HEAD + body_parts_covered = HEAD + attack_verb = list("bapped") + + var/info //What's actually written on the paper. + var/info_links //A different version of the paper which includes html links at fields and EOF + var/stamps //The (text for the) stamps on the paper. + var/fields //Amount of user created fields + var/free_space = MAX_PAPER_MESSAGE_LEN + var/list/stamped + var/list/ico[0] //Icons and + var/list/offset_x[0] //offsets stored for later + var/list/offset_y[0] //usage by the photocopier + var/rigged = 0 + var/spam_flag = 0 + + var/const/deffont = "Verdana" + var/const/signfont = "Times New Roman" + var/const/crayonfont = "Comic Sans MS" + +/obj/item/weapon/paper/New(loc, text,title) + ..(loc) + set_content(text ? text : info, title) + +/obj/item/weapon/paper/proc/set_content(text,title) + if(title) + SetName(title) + info = html_encode(text) + info = parsepencode(text) + update_icon() + update_space(info) + updateinfolinks() + +/obj/item/weapon/paper/update_icon() + if(icon_state == "paper_talisman") + return + else if(info) + icon_state = "paper_words" + else + icon_state = "paper" + +/obj/item/weapon/paper/proc/update_space(var/new_text) + if(new_text) + free_space -= length(strip_html_properly(new_text)) + +/obj/item/weapon/paper/examine(mob/user) + . = ..() + if(name != "sheet of paper") + to_chat(user, "It's titled '[name]'.") + if(in_range(user, src) || isghost(user)) + show_content(usr) + else + to_chat(user, "You have to go closer if you want to read it.") + +/obj/item/weapon/paper/proc/show_content(mob/user, forceshow) + var/can_read = (istype(user, /mob/living/carbon/human) || isghost(user) || istype(user, /mob/living/silicon)) || forceshow + if(!forceshow && istype(user,/mob/living/silicon/ai)) + var/mob/living/silicon/ai/AI = user + can_read = get_dist(src, AI.camera) < 2 + user << browse("[name][can_read ? info : stars(info)][stamps]", "window=[name]") + onclose(user, "[name]") + +/obj/item/weapon/paper/verb/rename() + set name = "Rename paper" + set category = "Object" + set src in usr + + if((CLUMSY in usr.mutations) && prob(50)) + to_chat(usr, "You cut yourself on the paper.") + return + var/n_name = sanitizeSafe(input(usr, "What would you like to label the paper?", "Paper Labelling", null) as text, MAX_NAME_LEN) + + // We check loc one level up, so we can rename in clipboards and such. See also: /obj/item/weapon/photo/rename() + if((loc == usr || loc.loc && loc.loc == usr) && usr.stat == 0 && n_name) + SetName(n_name) + add_fingerprint(usr) + +/obj/item/weapon/paper/attack_self(mob/living/user as mob) + if(user.a_intent == I_HURT) + if(icon_state == "scrap") + user.show_message("\The [src] is already crumpled.") + return + //crumple dat paper + info = stars(info,85) + user.visible_message("\The [user] crumples \the [src] into a ball!") + icon_state = "scrap" + return + user.examinate(src) + if(rigged && (Holiday == "April Fool's Day")) + if(spam_flag == 0) + spam_flag = 1 + playsound(loc, 'sound/items/bikehorn.ogg', 50, 1) + spawn(20) + spam_flag = 0 + +/obj/item/weapon/paper/attack_ai(var/mob/living/silicon/ai/user) + show_content(user) + +/obj/item/weapon/paper/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) + if(user.zone_sel.selecting == BP_EYES) + user.visible_message("You show the paper to [M]. ", \ + " [user] holds up a paper and shows it to [M]. ") + M.examinate(src) + + else if(user.zone_sel.selecting == BP_MOUTH) // lipstick wiping + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H == user) + to_chat(user, "You wipe off the lipstick with [src].") + H.lip_style = null + H.update_body() + else + user.visible_message("[user] begins to wipe [H]'s lipstick off with \the [src].", \ + "You begin to wipe off [H]'s lipstick.") + if(do_after(user, 10, H) && do_after(H, 10, needhand = 0)) //user needs to keep their active hand, H does not. + user.visible_message("[user] wipes [H]'s lipstick off with \the [src].", \ + "You wipe off [H]'s lipstick.") + H.lip_style = null + H.update_body() + +/obj/item/weapon/paper/proc/addtofield(var/id, var/text, var/links = 0) + var/locid = 0 + var/laststart = 1 + var/textindex = 1 + while(locid < MAX_FIELDS) // I know this can cause infinite loops and fuck up the whole server, but the if(istart==0) should be safe as fuck + var/istart = 0 //^ HEY CONGRATULATIONS FUCKHEAD YOU WERE RIGHT, IT DOES BREAK THE ENTIRE SERVER! + if(links) + istart = findtext(info_links, "", laststart) + else + istart = findtext(info, "", laststart) + + if(istart==0) + return // No field found with matching id + + laststart = istart+1 + locid++ + if(locid == id) + var/iend = 1 + if(links) + iend = findtext(info_links, "", istart) + else + iend = findtext(info, "", istart) + + textindex = iend + break + + if(links) + var/before = copytext(info_links, 1, textindex) + var/after = copytext(info_links, textindex) + info_links = before + text + after + else + var/before = copytext(info, 1, textindex) + var/after = copytext(info, textindex) + info = before + text + after + updateinfolinks() + +/obj/item/weapon/paper/proc/updateinfolinks() + info_links = info + var/i = 0 + for(i=1,i<=fields,i++) + addtofield(i, "write", 1) + info_links = info_links + "write" + + +/obj/item/weapon/paper/proc/clearpaper() + info = null + stamps = null + free_space = MAX_PAPER_MESSAGE_LEN + stamped = list() + overlays.Cut() + updateinfolinks() + update_icon() + +/obj/item/weapon/paper/proc/get_signature(var/obj/item/weapon/pen/P, mob/user as mob) + if(P && istype(P, /obj/item/weapon/pen)) + return P.get_signature(user) + return (user && user.real_name) ? user.real_name : "Anonymous" + +/obj/item/weapon/paper/proc/parsepencode(t, obj/item/weapon/pen/P, mob/user, iscrayon) + //t = t + if(length(t) == 0) + return "" + + if(findtext(t, "\[sign\]")) + t = replacetext(t, "\[sign\]", "[get_signature(P, user)]") + + if(iscrayon) // If it is a crayon, and he still tries to use these, make them empty! + t = replacetext(t, "\[*\]", "") + t = replacetext(t, "\[hr\]", "") + t = replacetext(t, "\[small\]", "") + t = replacetext(t, "\[/small\]", "") + t = replacetext(t, "\[list\]", "") + t = replacetext(t, "\[/list\]", "") + t = replacetext(t, "\[table\]", "") + t = replacetext(t, "\[/table\]", "") + t = replacetext(t, "\[row\]", "") + t = replacetext(t, "\[cell\]", "") + t = replacetext(t, "\[logo\]", "") + + if(iscrayon) + t = "[t]" + else + t = "[t]" + + t = pencode2html(t) + + //Count the fields + var/laststart = 1 + while(fields < MAX_FIELDS) + var/i = findtext(t, "", laststart) // + if(i==0) + break + laststart = i+1 + fields++ + + return t + + +/obj/item/weapon/paper/proc/burnpaper(obj/item/weapon/flame/P, mob/user) + var/class = "warning" + + if(P.lit && !user.restrained()) + if(istype(P, /obj/item/weapon/flame/lighter/zippo)) + class = "rose" + + user.visible_message("[user] holds \the [P] up to \the [src], it looks like \he's trying to burn it!", \ + "You hold \the [P] up to \the [src], burning it slowly.") + + spawn(20) + if(get_dist(src, user) < 2 && user.get_active_hand() == P && P.lit) + user.visible_message("[user] burns right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.", \ + "You burn right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.") + + if(user.get_inactive_hand() == src) + user.drop_from_inventory(src) + + new /obj/effect/decal/cleanable/ash(src.loc) + qdel(src) + + else + to_chat(user, "You must hold \the [P] steady to burn \the [src].") + + +/obj/item/weapon/paper/Topic(href, href_list) + ..() + if(!usr || (usr.stat || usr.restrained())) + return + + if(href_list["write"]) + var/id = href_list["write"] + //var/t = strip_html_simple(input(usr, "What text do you wish to add to " + (id=="end" ? "the end of the paper" : "field "+id) + "?", "[name]", null),8192) as message + + if(free_space <= 0) + to_chat(usr, "There isn't enough space left on \the [src] to write anything.") + return + + var/t = sanitize(input("Enter what you want to write:", "Write", null, null) as message, free_space, extra = 0, trim = 0) + + if(!t) + return + + var/obj/item/i = usr.get_active_hand() // Check to see if he still got that darn pen, also check if he's using a crayon or pen. + var/iscrayon = 0 + + if(istype(i, /obj/item/weapon/pen/crayon)) + iscrayon = 1 + + + // if paper is not in usr, then it must be near them, or in a clipboard or folder, which must be in or near usr + if(src.loc != usr && !src.Adjacent(usr) && !((istype(src.loc, /obj/item/weapon/clipboard) || istype(src.loc, /obj/item/weapon/folder)) && (src.loc.loc == usr || src.loc.Adjacent(usr)) ) ) + return + + var/last_fields_value = fields + + t = parsepencode(t, i, usr, iscrayon) // Encode everything from pencode to html + + + if(fields > MAX_FIELDS)//large amount of fields creates a heavy load on the server, see updateinfolinks() and addtofield() + to_chat(usr, "Too many fields. Sorry, you can't do this.") + fields = last_fields_value + return + + if(id!="end") + addtofield(text2num(id), t) // He wants to edit a field, let him. + else + info += t // Oh, he wants to edit to the end of the file, let him. + updateinfolinks() + + update_space(t) + + usr << browse("[name][info_links][stamps]", "window=[name]") // Update the window + + update_icon() + + +/obj/item/weapon/paper/attackby(obj/item/weapon/P as obj, mob/user as mob) + ..() + var/clown = 0 + if(user.mind && (user.mind.assigned_role == "Clown")) + clown = 1 + + if(istype(P, /obj/item/weapon/tape_roll)) + var/obj/item/weapon/tape_roll/tape = P + tape.stick(src, user) + return + + if(istype(P, /obj/item/weapon/paper) || istype(P, /obj/item/weapon/photo)) + if (istype(P, /obj/item/weapon/paper/carbon)) + var/obj/item/weapon/paper/carbon/C = P + if (!C.iscopy && !C.copied) + to_chat(user, "Take off the carbon copy first.") + add_fingerprint(user) + return + var/obj/item/weapon/paper_bundle/B = new(src.loc) + if (name != "paper") + B.SetName(name) + else if (P.name != "paper" && P.name != "photo") + B.SetName(P.name) + + user.drop_from_inventory(P) + user.drop_from_inventory(src) + user.put_in_hands(B) + src.forceMove(B) + P.forceMove(B) + + to_chat(user, "You clip the [P.name] to [(src.name == "paper") ? "the paper" : src.name].") + + B.pages.Add(src) + B.pages.Add(P) + B.update_icon() + + else if(istype(P, /obj/item/weapon/pen)) + if(icon_state == "scrap") + to_chat(usr, "\The [src] is too crumpled to write on.") + return + + var/obj/item/weapon/pen/robopen/RP = P + if ( istype(RP) && RP.mode == 2 ) + RP.RenamePaper(user,src) + else + user << browse("[name][info_links][stamps]", "window=[name]") + return + + else if(istype(P, /obj/item/weapon/stamp) || istype(P, /obj/item/clothing/ring/seal)) + if((!in_range(src, usr) && loc != user && !( istype(loc, /obj/item/weapon/clipboard) ) && loc.loc != user && user.get_active_hand() != P)) + return + + stamps += (stamps=="" ? "
            " : "
            ") + "This paper has been stamped with the [P.name]." + + var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') + var/x + var/y + if(istype(P, /obj/item/weapon/stamp/captain) || istype(P, /obj/item/weapon/stamp/centcomm)) + x = rand(-2, 0) + y = rand(-1, 2) + else + x = rand(-2, 2) + y = rand(-3, 2) + offset_x += x + offset_y += y + stampoverlay.pixel_x = x + stampoverlay.pixel_y = y + + if(istype(P, /obj/item/weapon/stamp/clown)) + if(!clown) + to_chat(user, "You are totally unable to use the stamp. HONK!") + return + + if(!ico) + ico = new + ico += "paper_[P.icon_state]" + stampoverlay.icon_state = "paper_[P.icon_state]" + + if(!stamped) + stamped = new + stamped += P.type + overlays += stampoverlay + + to_chat(user, "You stamp the paper with your [P.name].") + + else if(istype(P, /obj/item/weapon/flame)) + burnpaper(P, user) + + else if(istype(P, /obj/item/weapon/paper_bundle)) + var/obj/item/weapon/paper_bundle/attacking_bundle = P + attacking_bundle.insert_sheet_at(user, (attacking_bundle.pages.len)+1, src) + attacking_bundle.update_icon() + + add_fingerprint(user) + return + +/* + * Premade paper + */ +/obj/item/weapon/paper/Court + name = "Judgement" + info = "For crimes as specified, the offender is sentenced to:
            \n
            \n" + +/obj/item/weapon/paper/crumpled + name = "paper scrap" + icon_state = "scrap" + +/obj/item/weapon/paper/crumpled/update_icon() + return + +/obj/item/weapon/paper/crumpled/bloody + icon_state = "scrap_bloodied" + +/obj/item/weapon/paper/exodus_armory + name = "armory inventory" + info = "
            \[logo]
            NSS Exodus

            Armoury Inventory - Revision

            Armoury
            \[*]Deployable barriers: 4\[*]Biohazard suit(s): 1\[*]Biohazard hood(s): 1\[*]Face Mask(s): 1\[*]Extended-capacity emergency oxygen tank(s): 1\[*]Bomb suit(s): 1\[*]Bomb hood(s): 1\[*]Security officer's jumpsuit(s): 1\[*]Brown shoes: 1\[*]Handcuff(s): 14\[*]R.O.B.U.S.T. cartridges: 7\[*]Flash(s): 4\[*]Can(s) of pepperspray: 4\[*]Gas mask(s): 6
            Secure Armoury
            \[*]LAEP90 Perun energy guns: 4\[*]Stun Revolver(s): 1\[*]Taser Gun(s): 4\[*]Stun baton(s): 4\[*]Airlock Brace: 3\[*]Maintenance Jack: 1\[*]Stab Vest(s): 3\[*]Riot helmet(s): 3\[*]Riot shield(s): 3\[*]Corporate security heavy armoured vest(s): 4\[*]NanoTrasen helmet(s): 4\[*]Portable flasher(s): 3\[*]Tracking implant(s): 4\[*]Chemical implant(s): 5\[*]Implanter(s): 2\[*]Implant pad(s): 2\[*]Locator(s): 1
            Tactical Equipment
            \[*]Implanter: 1\[*]Death Alarm implant(s): 7\[*]Security radio headset(s): 4\[*]Ablative vest(s): 2\[*]Ablative helmet(s): 2\[*]Ballistic vest(s): 2\[*]Ballistic helmet(s): 2\[*]Tear Gas Grenade(s): 7\[*]Flashbang(s): 7\[*]Beanbag Shell(s): 7\[*]Stun Shell(s): 7\[*]Illumination Shell(s): 7\[*]W-T Remmington 29x shotgun(s): 2\[*]NT Mk60 EW Halicon ion rifle(s): 2\[*]Hephaestus Industries G40E laser carbine(s): 4\[*]Flare(s): 4
            Warden (print):Signature:
            " + +/obj/item/weapon/paper/exodus_cmo + name = "outgoing CMO's notes" + info = "
            To the incoming CMO of Exodus:


            I wish you and your crew well. Do take note:


            The Medical Emergency Red Phone system has proven itself well. Take care to keep the phones in their designated places as they have been optimised for broadcast. The two handheld green radios (I have left one in this office, and one near the Emergency Entrance) are free to be used. The system has proven effective at alerting Medbay of important details, especially during power outages.

            I think I may have left the toilet cubicle doors shut. It might be a good idea to open them so the staff and patients know they are not engaged.

            The new syringe gun has been stored in secondary storage. I tend to prefer it stored in my office, but 'guidelines' are 'guidelines'.

            Also in secondary storage is the grenade equipment crate. I've just realised I've left it open - you may wish to shut it.

            There were a few problems with their installation, but the Medbay Quarantine shutters should now be working again - they lock down the Emergency and Main entrances to prevent travel in and out. Pray you shan't have to use them.

            The new version of the Medical Diagnostics Manual arrived. I distributed them to the shelf in the staff break room, and one on the table in the corner of this room.

            The exam/triage room has the walking canes in it. I'm not sure why we'd need them - but there you have it.

            Emergency Cryo bags are beside the emergency entrance, along with a kit.

            Spare paper cups for the reception are on the left side of the reception desk.

            I've fed Runtime. She should be fine.


            That should be all. Good luck!
            " + +/obj/item/weapon/paper/exodus_bartender + name = "shotgun permit" + info = "This permit signifies that the Bartender is permitted to posess this firearm in the bar, and ONLY the bar. Failure to adhere to this permit will result in confiscation of the weapon and possibly arrest." + +/obj/item/weapon/paper/exodus_holodeck + name = "holodeck disclaimer" + info = "Bruises sustained in the holodeck can be healed simply by sleeping." + +/obj/item/weapon/paper/workvisa + name = "Sol Work Visa" + info = "
            Work Visa of the Sol Central Government



            Issued on behalf of the Secretary-General.


            This paper hereby permits the carrier to travel unhindered through Sol territories, colonies, and space for the purpose of work and labor." + desc = "A flimsy piece of laminated cardboard issued by the Sol Central Government." + +/obj/item/weapon/paper/workvisa/New() + ..() + icon_state = "workvisa" //Has to be here or it'll assume default paper sprites. diff --git a/code/modules/paperwork/paper_bundle.dm b/code/modules/paperwork/paper_bundle.dm new file mode 100644 index 00000000..487ec024 --- /dev/null +++ b/code/modules/paperwork/paper_bundle.dm @@ -0,0 +1,244 @@ +/obj/item/weapon/paper_bundle + name = "paper bundle" + gender = NEUTER + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "paper" + item_state = "paper" + randpixel = 8 + throwforce = 0 + w_class = ITEM_SIZE_SMALL + throw_range = 2 + throw_speed = 1 + layer = ABOVE_OBJ_LAYER + attack_verb = list("bapped") + var/page = 1 // current page + var/list/pages = list() // Ordered list of pages as they are to be displayed. Can be different order than src.contents. + + +/obj/item/weapon/paper_bundle/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + + if (istype(W, /obj/item/weapon/paper/carbon)) + var/obj/item/weapon/paper/carbon/C = W + if (!C.iscopy && !C.copied) + to_chat(user, "Take off the carbon copy first.") + add_fingerprint(user) + return + // adding sheets + if(istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/weapon/photo)) + insert_sheet_at(user, pages.len+1, W) + + // burning + else if(istype(W, /obj/item/weapon/flame)) + burnpaper(W, user) + + // merging bundles + else if(istype(W, /obj/item/weapon/paper_bundle)) + user.drop_from_inventory(W) + for(var/obj/O in W) + O.loc = src + O.add_fingerprint(usr) + pages.Add(O) + + to_chat(user, "You add \the [W.name] to [(src.name == "paper bundle") ? "the paper bundle" : src.name].") + qdel(W) + else + if(istype(W, /obj/item/weapon/tape_roll)) + return 0 + if(istype(W, /obj/item/weapon/pen)) + usr << browse("", "window=[name]") //Closes the dialog + var/obj/P = pages[page] + P.attackby(W, user) + + update_icon() + attack_self(usr) //Update the browsed page. + add_fingerprint(usr) + return + +/obj/item/weapon/paper_bundle/proc/insert_sheet_at(mob/user, var/index, obj/item/weapon/sheet) + if(istype(sheet, /obj/item/weapon/paper)) + to_chat(user, "You add [(sheet.name == "paper") ? "the paper" : sheet.name] to [(src.name == "paper bundle") ? "the paper bundle" : src.name].") + else if(istype(sheet, /obj/item/weapon/photo)) + to_chat(user, "You add [(sheet.name == "photo") ? "the photo" : sheet.name] to [(src.name == "paper bundle") ? "the paper bundle" : src.name].") + + user.drop_from_inventory(sheet) + sheet.loc = src + + pages.Insert(index, sheet) + + if(index <= page) + page++ + +/obj/item/weapon/paper_bundle/proc/burnpaper(obj/item/weapon/flame/P, mob/user) + var/class = "warning" + + if(P.lit && !user.restrained()) + if(istype(P, /obj/item/weapon/flame/lighter/zippo)) + class = "rose>" + + user.visible_message("[user] holds \the [P] up to \the [src], it looks like \he's trying to burn it!", \ + "You hold \the [P] up to \the [src], burning it slowly.") + + spawn(20) + if(get_dist(src, user) < 2 && user.get_active_hand() == P && P.lit) + user.visible_message("[user] burns right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.", \ + "You burn right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.") + + if(user.get_inactive_hand() == src) + user.drop_from_inventory(src) + + new /obj/effect/decal/cleanable/ash(src.loc) + qdel(src) + + else + to_chat(user, "You must hold \the [P] steady to burn \the [src].") + +/obj/item/weapon/paper_bundle/examine(mob/user) + if(..(user, 1)) + src.show_content(user) + else + to_chat(user, "It is too far away.") + return + +/obj/item/weapon/paper_bundle/proc/show_content(mob/user as mob) + var/dat + var/obj/item/weapon/W = pages[page] + + // first + if(page == 1) + dat+= "" + dat+= "" + dat+= "

            " + // last + else if(page == pages.len) + dat+= "" + dat+= "" + dat+= "

            " + // middle pages + else + dat+= "" + dat+= "" + dat+= "

            " + + if(istype(pages[page], /obj/item/weapon/paper)) + var/obj/item/weapon/paper/P = W + if(!(istype(usr, /mob/living/carbon/human) || isghost(usr) || istype(usr, /mob/living/silicon))) + dat+= "[P.name][stars(P.info)][P.stamps]" + else + dat+= "[P.name][P.info][P.stamps]" + user << browse(dat, "window=[name]") + else if(istype(pages[page], /obj/item/weapon/photo)) + var/obj/item/weapon/photo/P = W + user << browse_rsc(P.img, "tmp_photo.png") + user << browse(dat + "[P.name]" \ + + "" \ + + "
            Written on the back:
            [P.scribble]" : null]"\ + + "", "window=[name]") + +/obj/item/weapon/paper_bundle/attack_self(mob/user as mob) + src.show_content(user) + add_fingerprint(usr) + update_icon() + return + +/obj/item/weapon/paper_bundle/Topic(href, href_list) + if(..()) + return 1 + if((src in usr.contents) || (istype(src.loc, /obj/item/weapon/folder) && (src.loc in usr.contents))) + usr.set_machine(src) + var/obj/item/weapon/in_hand = usr.get_active_hand() + if(href_list["next_page"]) + if(in_hand && (istype(in_hand, /obj/item/weapon/paper) || istype(in_hand, /obj/item/weapon/photo))) + insert_sheet_at(usr, page+1, in_hand) + else if(page != pages.len) + page++ + playsound(src.loc, "pageturn", 50, 1) + if(href_list["prev_page"]) + if(in_hand && (istype(in_hand, /obj/item/weapon/paper) || istype(in_hand, /obj/item/weapon/photo))) + insert_sheet_at(usr, page, in_hand) + else if(page > 1) + page-- + playsound(src.loc, "pageturn", 50, 1) + if(href_list["remove"]) + var/obj/item/weapon/W = pages[page] + usr.put_in_hands(W) + pages.Remove(pages[page]) + + to_chat(usr, "You remove the [W.name] from the bundle.") + + if(pages.len <= 1) + var/obj/item/weapon/paper/P = src[1] + usr.drop_from_inventory(src) + usr.put_in_hands(P) + qdel(src) + + return + + if(page > pages.len) + page = pages.len + + update_icon() + + src.attack_self(usr) + updateUsrDialog() + else + to_chat(usr, "You need to hold it in hands!") + +/obj/item/weapon/paper_bundle/verb/rename() + set name = "Rename bundle" + set category = "Object" + set src in usr + + var/n_name = sanitizeSafe(input(usr, "What would you like to label the bundle?", "Bundle Labelling", null) as text, MAX_NAME_LEN) + if((loc == usr || loc.loc && loc.loc == usr) && usr.stat == 0) + SetName("[(n_name ? text("[n_name]") : "paper")]") + add_fingerprint(usr) + return + + +/obj/item/weapon/paper_bundle/verb/remove_all() + set name = "Loose bundle" + set category = "Object" + set src in usr + + to_chat(usr, "You loosen the bundle.") + for(var/obj/O in src) + O.dropInto(usr.loc) + O.reset_plane_and_layer() + O.add_fingerprint(usr) + usr.drop_from_inventory(src) + qdel(src) + return + + +/obj/item/weapon/paper_bundle/update_icon() + var/obj/item/weapon/paper/P = pages[1] + icon_state = P.icon_state + overlays = P.overlays + underlays = 0 + var/i = 0 + var/photo + for(var/obj/O in src) + var/image/img = image('icons/obj/bureaucracy.dmi') + if(istype(O, /obj/item/weapon/paper)) + img.icon_state = O.icon_state + img.pixel_x -= min(1*i, 2) + img.pixel_y -= min(1*i, 2) + pixel_x = min(0.5*i, 1) + pixel_y = min( 1*i, 2) + underlays += img + i++ + else if(istype(O, /obj/item/weapon/photo)) + var/obj/item/weapon/photo/Ph = O + img = Ph.tiny + photo = 1 + overlays += img + if(i>1) + desc = "[i] papers clipped to each other." + else + desc = "A single sheet of paper." + if(photo) + desc += "\nThere is a photo attached to it." + overlays += image('icons/obj/bureaucracy.dmi', "clip") + return diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm new file mode 100644 index 00000000..bc404984 --- /dev/null +++ b/code/modules/paperwork/paperbin.dm @@ -0,0 +1,120 @@ +/obj/item/weapon/paper_bin + name = "paper bin" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "paper_bin1" + item_state = "sheet-metal" + randpixel = 0 + throwforce = 1 + w_class = ITEM_SIZE_NORMAL + throw_speed = 3 + throw_range = 7 + layer = BELOW_OBJ_LAYER + var/amount = 30 //How much paper is in the bin. + var/list/papers = new/list() //List of papers put in the bin for reference. + + +/obj/item/weapon/paper_bin/MouseDrop(mob/user as mob) + if((user == usr && (!( usr.restrained() ) && (!( usr.stat ) && (usr.contents.Find(src) || in_range(src, usr)))))) + if(!istype(usr, /mob/living/carbon/slime) && !istype(usr, /mob/living/simple_animal)) + if( !usr.get_active_hand() ) //if active hand is empty + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/temp = H.organs_by_name[BP_R_HAND] + + if (H.hand) + temp = H.organs_by_name[BP_L_HAND] + if(temp && !temp.is_usable()) + to_chat(user, "You try to move your [temp.name], but cannot!") + return + + to_chat(user, "You pick up the [src].") + user.put_in_hands(src) + + return + +/obj/item/weapon/paper_bin/attack_hand(mob/user as mob) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/temp = H.organs_by_name[BP_R_HAND] + if (H.hand) + temp = H.organs_by_name[BP_L_HAND] + if(temp && !temp.is_usable()) + to_chat(user, "You try to move your [temp.name], but cannot!") + return + var/response = "" + if(!papers.len > 0) + response = alert(user, "Do you take regular paper, or Carbon copy paper?", "Paper type request", "Regular", "Carbon-Copy", "Cancel") + if (response != "Regular" && response != "Carbon-Copy") + add_fingerprint(user) + return + if(amount >= 1) + amount-- + if(amount==0) + update_icon() + + var/obj/item/weapon/paper/P + if(papers.len > 0) //If there's any custom paper on the stack, use that instead of creating a new paper. + P = papers[papers.len] + papers.Remove(P) + else + if(response == "Regular") + P = new /obj/item/weapon/paper + if(Holiday == "April Fool's Day") + if(prob(30)) + P.info = "HONK HONK HONK HONK HONK HONK HONK
            HOOOOOOOOOOOOOOOOOOOOOONK
            APRIL FOOLS
            " + P.rigged = 1 + P.updateinfolinks() + else if (response == "Carbon-Copy") + P = new /obj/item/weapon/paper/carbon + + P.loc = user.loc + user.put_in_hands(P) + to_chat(user, "You take [P] out of the [src].") + else + to_chat(user, "[src] is empty!") + + add_fingerprint(user) + return + + +/obj/item/weapon/paper_bin/attackby(obj/item/weapon/i as obj, mob/user as mob) + if(istype(i, /obj/item/weapon/paper)) + user.drop_item() + i.forceMove(src) + to_chat(user, "You put [i] in [src].") + papers.Add(i) + update_icon() + amount++ + else if(istype(i, /obj/item/weapon/paper_bundle)) + to_chat(user, "You loosen \the [i] and add its papers into \the [src].") + var/was_there_a_photo = 0 + for(var/obj/item/weapon/bundleitem in i) //loop through items in bundle + if(istype(bundleitem, /obj/item/weapon/paper)) //if item is paper, add into the bin + papers.Add(bundleitem) + update_icon() + amount++ + else if(istype(bundleitem, /obj/item/weapon/photo)) //if item is photo, drop it on the ground + was_there_a_photo = 1 + bundleitem.dropInto(user.loc) + bundleitem.reset_plane_and_layer() + user.drop_from_inventory(i) + qdel(i) + if(was_there_a_photo) + to_chat(user, "The photo cannot go into \the [src].") + return + + +/obj/item/weapon/paper_bin/examine(mob/user) + . = ..() + if(get_dist(src, user) <= 1) + if(amount) + to_chat(user, "There " + (amount > 1 ? "are [amount] papers" : "is one paper") + " in the bin.") + else + to_chat(user, "There are no papers in the bin.") + return + + +/obj/item/weapon/paper_bin/update_icon() + if(amount < 1) + icon_state = "paper_bin0" + else + icon_state = "paper_bin1" diff --git a/code/modules/paperwork/papershredder.dm b/code/modules/paperwork/papershredder.dm new file mode 100644 index 00000000..26024a2f --- /dev/null +++ b/code/modules/paperwork/papershredder.dm @@ -0,0 +1,141 @@ +/obj/machinery/papershredder + name = "paper shredder" + desc = "For those documents you don't want seen." + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "papershredder0" + density = 1 + anchored = 1 + atom_flags = ATOM_FLAG_CLIMBABLE + obj_flags = OBJ_FLAG_ANCHORABLE + var/max_paper = 10 + var/paperamount = 0 + var/list/shred_amounts = list( + /obj/item/weapon/photo = 1, + /obj/item/weapon/shreddedp = 1, + /obj/item/weapon/paper = 1, + /obj/item/weapon/newspaper = 3, + /obj/item/weapon/card/id = 3, + /obj/item/weapon/paper_bundle = 3, + ) + +/obj/machinery/papershredder/attackby(var/obj/item/W, var/mob/user) + + if(istype(W, /obj/item/weapon/storage)) + empty_bin(user, W) + return + else + var/paper_result + for(var/shred_type in shred_amounts) + if(istype(W, shred_type)) + paper_result = shred_amounts[shred_type] + if(paper_result) + if(paperamount == max_paper) + to_chat(user, "\The [src] is full; please empty it before you continue.") + return + paperamount += paper_result + user.drop_from_inventory(W) + qdel(W) + playsound(src.loc, 'sound/items/pshred.ogg', 75, 1) + if(paperamount > max_paper) + to_chat(user, "\The [src] was too full, and shredded paper goes everywhere!") + for(var/i=(paperamount-max_paper);i>0;i--) + var/obj/item/weapon/shreddedp/SP = get_shredded_paper() + SP.loc = get_turf(src) + SP.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),1,5) + paperamount = max_paper + update_icon() + return + ..() + return + +/obj/machinery/papershredder/verb/empty_contents() + set name = "Empty bin" + set category = "Object" + set src in range(1) + + if(usr.stat || usr.restrained() || usr.weakened || usr.paralysis || usr.lying || usr.stunned) + return + + if(!paperamount) + to_chat(usr, "\The [src] is empty.") + return + + empty_bin(usr) + +/obj/machinery/papershredder/proc/empty_bin(var/mob/living/user, var/obj/item/weapon/storage/empty_into) + + // Sanity. + if(empty_into && !istype(empty_into)) + empty_into = null + + if(empty_into && empty_into.contents.len >= empty_into.storage_slots) + to_chat(user, "\The [empty_into] is full.") + return + + while(paperamount) + var/obj/item/weapon/shreddedp/SP = get_shredded_paper() + if(!SP) break + if(empty_into) + empty_into.handle_item_insertion(SP) + if(empty_into.contents.len >= empty_into.storage_slots) + break + if(empty_into) + if(paperamount) + to_chat(user, "You fill \the [empty_into] with as much shredded paper as it will carry.") + else + to_chat(user, "You empty \the [src] into \the [empty_into].") + + else + to_chat(user, "You empty \the [src].") + update_icon() + +/obj/machinery/papershredder/proc/get_shredded_paper() + if(!paperamount) + return + paperamount-- + return new /obj/item/weapon/shreddedp(get_turf(src)) + +/obj/machinery/papershredder/update_icon() + icon_state = "papershredder[max(0,min(5,Floor(paperamount/2)))]" + +/obj/item/weapon/shreddedp/attackby(var/obj/item/W as obj, var/mob/user) + if(istype(W, /obj/item/weapon/flame/lighter)) + burnpaper(W, user) + else + ..() + +/obj/item/weapon/shreddedp/proc/burnpaper(var/obj/item/weapon/flame/lighter/P, var/mob/user) + if(user.restrained()) + return + if(!P.lit) + to_chat(user, "\The [P] is not lit.") + return + user.visible_message("\The [user] holds \the [P] up to \the [src]. It looks like \he's trying to burn it!", \ + "You hold \the [P] up to \the [src], burning it slowly.") + if(!do_after(user,20, src)) + to_chat(user, "You must hold \the [P] steady to burn \the [src].") + return + user.visible_message("\The [user] burns right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.", \ + "You burn right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.") + FireBurn() + +/obj/item/weapon/shreddedp/proc/FireBurn() + var/mob/living/M = loc + if(istype(M)) + M.drop_from_inventory(src) + new /obj/effect/decal/cleanable/ash(get_turf(src)) + qdel(src) + +/obj/item/weapon/shreddedp + name = "shredded paper" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "shredp" + randpixel = 5 + throwforce = 0 + w_class = ITEM_SIZE_TINY + throw_range = 3 + throw_speed = 1 + +/obj/item/weapon/shreddedp/New() + ..() + if(prob(65)) color = pick("#bababa","#7f7f7f") diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm new file mode 100644 index 00000000..68d0feef --- /dev/null +++ b/code/modules/paperwork/pen.dm @@ -0,0 +1,182 @@ +/* Pens! + * Contains: + * Pens + * Sleepy Pens + * Parapens + */ + + +/* + * Pens + */ +/obj/item/weapon/pen + desc = "It's a normal black ink pen." + name = "pen" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "pen" + item_state = "pen" + slot_flags = SLOT_BELT | SLOT_EARS + throwforce = 0 + w_class = ITEM_SIZE_TINY + throw_speed = 7 + throw_range = 15 + matter = list(DEFAULT_WALL_MATERIAL = 10) + var/colour = "black" //what colour the ink is! + + +/obj/item/weapon/pen/blue + desc = "It's a normal blue ink pen." + icon_state = "pen_blue" + colour = "blue" + +/obj/item/weapon/pen/red + desc = "It's a normal red ink pen." + icon_state = "pen_red" + colour = "red" + +/obj/item/weapon/pen/multi + desc = "It's a pen with multiple colors of ink!" + var/selectedColor = 1 + var/colors = list("black","blue","red") + +/obj/item/weapon/pen/multi/attack_self(mob/user) + if(++selectedColor > 3) + selectedColor = 1 + + colour = colors[selectedColor] + + if(colour == "black") + icon_state = "pen" + else + icon_state = "pen_[colour]" + + to_chat(user, "Changed color to '[colour].'") + +/obj/item/weapon/pen/invisible + desc = "It's an invisble pen marker." + icon_state = "pen" + colour = "white" + + +/obj/item/weapon/pen/attack(mob/M as mob, mob/user as mob) + if(!ismob(M)) + return + to_chat(user, "You stab [M] with the pen.") + admin_attack_log(user, M, "Stabbed using \a [src]", "Was stabbed with \a [src]", "used \a [src] to stab") + + return + +/* + * Reagent pens + */ + +/obj/item/weapon/pen/reagent + atom_flags = ATOM_FLAG_OPEN_CONTAINER + origin_tech = list(TECH_MATERIAL = 2, TECH_ILLEGAL = 5) + +/obj/item/weapon/pen/reagent/New() + ..() + create_reagents(30) + +/obj/item/weapon/pen/reagent/attack(mob/living/M, mob/user, var/target_zone) + + if(!istype(M)) + return + + . = ..() + + if(M.can_inject(user, target_zone)) + if(reagents.total_volume) + if(M.reagents) + var/contained_reagents = reagents.get_reagents() + var/trans = reagents.trans_to_mob(M, 30, CHEM_BLOOD) + admin_inject_log(user, M, src, contained_reagents, trans) + +/* + * Sleepy Pens + */ +/obj/item/weapon/pen/reagent/sleepy + desc = "It's a black ink pen with a sharp point and a carefully engraved \"Waffle Co.\"." + origin_tech = list(TECH_MATERIAL = 2, TECH_ILLEGAL = 5) + +/obj/item/weapon/pen/reagent/sleepy/New() + ..() + reagents.add_reagent(/datum/reagent/chloralhydrate, 15) //Used to be 100 sleep toxin//30 Chloral seems to be fatal, reducing it to 22, reducing it further to 15 because fuck you OD code./N + + +/* + * Chameleon pen + */ +/obj/item/weapon/pen/chameleon + var/signature = "" + +/obj/item/weapon/pen/chameleon/attack_self(mob/user as mob) + /* + // Limit signatures to official crew members + var/personnel_list[] = list() + for(var/datum/data/record/t in data_core.locked) //Look in data core locked. + personnel_list.Add(t.fields["name"]) + personnel_list.Add("Anonymous") + + var/new_signature = input("Enter new signature pattern.", "New Signature") as null|anything in personnel_list + if(new_signature) + signature = new_signature + */ + signature = sanitize(input("Enter new signature. Leave blank for 'Anonymous'", "New Signature", signature)) + +/obj/item/weapon/pen/proc/get_signature(var/mob/user) + return (user && user.real_name) ? user.real_name : "Anonymous" + +/obj/item/weapon/pen/chameleon/get_signature(var/mob/user) + return signature ? signature : "Anonymous" + +/obj/item/weapon/pen/chameleon/verb/set_colour() + set name = "Change Pen Colour" + set category = "Object" + + var/list/possible_colours = list ("Yellow", "Green", "Pink", "Blue", "Orange", "Cyan", "Red", "Invisible", "Black") + var/selected_type = input("Pick new colour.", "Pen Colour", null, null) as null|anything in possible_colours + + if(selected_type) + switch(selected_type) + if("Yellow") + colour = COLOR_YELLOW + if("Green") + colour = COLOR_LIME + if("Pink") + colour = COLOR_PINK + if("Blue") + colour = COLOR_BLUE + if("Orange") + colour = COLOR_ORANGE + if("Cyan") + colour = COLOR_CYAN + if("Red") + colour = COLOR_RED + if("Invisible") + colour = COLOR_WHITE + else + colour = COLOR_BLACK + to_chat(usr, "You select the [lowertext(selected_type)] ink container.") + + +/* + * Crayons + */ + +/obj/item/weapon/pen/crayon + name = "crayon" + desc = "A colourful crayon. Please refrain from eating it or putting it in your nose." + icon = 'icons/obj/crayons.dmi' + icon_state = "crayonred" + w_class = ITEM_SIZE_TINY + attack_verb = list("attacked", "coloured") + colour = "#ff0000" //RGB + var/shadeColour = "#220000" //RGB + var/uses = 30 //0 for unlimited uses + var/instant = 0 + var/colourName = "red" //for updateIcon purposes + + New() + name = "[colourName] crayon" + ..() diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm new file mode 100644 index 00000000..cda32b95 --- /dev/null +++ b/code/modules/paperwork/photocopier.dm @@ -0,0 +1,229 @@ +/obj/machinery/photocopier + name = "photocopier" + icon = 'icons/obj/library.dmi' + icon_state = "bigscanner" + var/insert_anim = "bigscanner1" + anchored = 1 + density = 1 + use_power = 1 + idle_power_usage = 30 + active_power_usage = 200 + power_channel = EQUIP + atom_flags = ATOM_FLAG_CLIMBABLE + obj_flags = OBJ_FLAG_ANCHORABLE + var/obj/item/copyitem = null //what's in the copier! + var/copies = 1 //how many copies to print! + var/toner = 30 //how much toner is left! woooooo~ + var/maxcopies = 10 //how many copies can be copied at once- idea shamelessly stolen from bs12's copier! + +/obj/machinery/photocopier/attack_ai(mob/user as mob) + return attack_hand(user) + +/obj/machinery/photocopier/attack_hand(mob/user as mob) + user.set_machine(src) + + var/dat = "Photocopier

            " + if(copyitem) + dat += "Remove Item
            " + if(toner) + dat += "Copy
            " + dat += "Printing: [copies] copies." + dat += "- " + dat += "+

            " + else if(toner) + dat += "Please insert something to copy.

            " + if(istype(user,/mob/living/silicon)) + dat += "Print photo from database

            " + dat += "Current toner level: [toner]" + if(!toner) + dat +="
            Please insert a new toner cartridge!" + user << browse(dat, "window=copier") + onclose(user, "copier") + return + +/obj/machinery/photocopier/Topic(href, href_list) + if(href_list["copy"]) + if(stat & (BROKEN|NOPOWER)) + return + + for(var/i = 0, i < copies, i++) + if(toner <= 0) + break + + if (istype(copyitem, /obj/item/weapon/paper)) + copy(copyitem) + sleep(15) + else if (istype(copyitem, /obj/item/weapon/photo)) + photocopy(copyitem) + sleep(15) + else if (istype(copyitem, /obj/item/weapon/paper_bundle)) + var/obj/item/weapon/paper_bundle/B = bundlecopy(copyitem) + sleep(15*B.pages.len) + else + to_chat(usr, "\The [copyitem] can't be copied by \the [src].") + break + + use_power(active_power_usage) + updateUsrDialog() + else if(href_list["remove"]) + if(copyitem) + copyitem.loc = usr.loc + usr.put_in_hands(copyitem) + to_chat(usr, "You take \the [copyitem] out of \the [src].") + copyitem = null + updateUsrDialog() + else if(href_list["min"]) + if(copies > 1) + copies-- + updateUsrDialog() + else if(href_list["add"]) + if(copies < maxcopies) + copies++ + updateUsrDialog() + else if(href_list["aipic"]) + if(!istype(usr,/mob/living/silicon)) return + if(stat & (BROKEN|NOPOWER)) return + + if(toner >= 5) + var/mob/living/silicon/tempAI = usr + var/obj/item/device/camera/siliconcam/camera = tempAI.silicon_camera + + if(!camera) + return + var/obj/item/weapon/photo/selection = camera.selectpicture() + if (!selection) + return + + var/obj/item/weapon/photo/p = photocopy(selection) + if (p.desc == "") + p.desc += "Copied by [tempAI.name]" + else + p.desc += " - Copied by [tempAI.name]" + toner -= 5 + sleep(15) + updateUsrDialog() + +/obj/machinery/photocopier/attackby(obj/item/O as obj, mob/user as mob) + if(istype(O, /obj/item/weapon/paper) || istype(O, /obj/item/weapon/photo) || istype(O, /obj/item/weapon/paper_bundle)) + if(!copyitem) + user.drop_item() + copyitem = O + O.loc = src + to_chat(user, "You insert \the [O] into \the [src].") + flick(insert_anim, src) + updateUsrDialog() + else + to_chat(user, "There is already something in \the [src].") + else if(istype(O, /obj/item/device/toner)) + if(toner <= 10) //allow replacing when low toner is affecting the print darkness + user.drop_item() + to_chat(user, "You insert the toner cartridge into \the [src].") + var/obj/item/device/toner/T = O + toner += T.toner_amount + qdel(O) + updateUsrDialog() + else + to_chat(user, "This cartridge is not yet ready for replacement! Use up the rest of the toner.") + ..() + return + +/obj/machinery/photocopier/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + if(2.0) + if(prob(50)) + qdel(src) + else + if(toner > 0) + new /obj/effect/decal/cleanable/blood/oil(get_turf(src)) + toner = 0 + else + if(prob(50)) + if(toner > 0) + new /obj/effect/decal/cleanable/blood/oil(get_turf(src)) + toner = 0 + return + +/obj/machinery/photocopier/proc/copy(var/obj/item/weapon/paper/copy, var/need_toner=1) + var/obj/item/weapon/paper/c = new /obj/item/weapon/paper (loc) + if(toner > 10) //lots of toner, make it dark + c.info = "" + else //no toner? shitty copies for you! + c.info = "" + var/copied = html_decode(copy.info) + copied = replacetext(copied, ""// + c.SetName(copy.name) // -- Doohl + c.fields = copy.fields + c.stamps = copy.stamps + c.stamped = copy.stamped + c.ico = copy.ico + c.offset_x = copy.offset_x + c.offset_y = copy.offset_y + var/list/temp_overlays = copy.overlays //Iterates through stamps + var/image/img //and puts a matching + for (var/j = 1, j <= min(temp_overlays.len, copy.ico.len), j++) //gray overlay onto the copy + if (findtext(copy.ico[j], "cap") || findtext(copy.ico[j], "cent")) + img = image('icons/obj/bureaucracy.dmi', "paper_stamp-circle") + else if (findtext(copy.ico[j], "deny")) + img = image('icons/obj/bureaucracy.dmi', "paper_stamp-x") + else + img = image('icons/obj/bureaucracy.dmi', "paper_stamp-dots") + img.pixel_x = copy.offset_x[j] + img.pixel_y = copy.offset_y[j] + c.overlays += img + c.updateinfolinks() + if(need_toner) + toner-- + if(toner == 0) + visible_message("A red light on \the [src] flashes, indicating that it is out of toner.") + return c + + +/obj/machinery/photocopier/proc/photocopy(var/obj/item/weapon/photo/photocopy, var/need_toner=1) + var/obj/item/weapon/photo/p = photocopy.copy() + p.forceMove(get_turf(src)) + + if(toner > 10) //plenty of toner, go straight greyscale + p.img.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))//I'm not sure how expensive this is, but given the many limitations of photocopying, it shouldn't be an issue. + p.update_icon() + else //not much toner left, lighten the photo + p.img.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(100,100,100)) + p.update_icon() + if(need_toner) + toner -= 5 //photos use a lot of ink! + if(toner < 0) + toner = 0 + visible_message("A red light on \the [src] flashes, indicating that it is out of toner.") + + return p + +//If need_toner is 0, the copies will still be lightened when low on toner, however it will not be prevented from printing. TODO: Implement print queues for fax machines and get rid of need_toner +/obj/machinery/photocopier/proc/bundlecopy(var/obj/item/weapon/paper_bundle/bundle, var/need_toner=1) + var/obj/item/weapon/paper_bundle/p = new /obj/item/weapon/paper_bundle (src) + for(var/obj/item/weapon/W in bundle.pages) + if(toner <= 0 && need_toner) + toner = 0 + visible_message("A red light on \the [src] flashes, indicating that it is out of toner.") + break + + if(istype(W, /obj/item/weapon/paper)) + W = copy(W) + else if(istype(W, /obj/item/weapon/photo)) + W = photocopy(W) + W.loc = p + p.pages += W + + p.loc = src.loc + p.update_icon() + p.icon_state = "paper_words" + p.SetName(bundle.name) + return p + +/obj/item/device/toner + name = "toner cartridge" + icon_state = "tonercartridge" + var/toner_amount = 30 diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm new file mode 100644 index 00000000..5152143a --- /dev/null +++ b/code/modules/paperwork/photography.dm @@ -0,0 +1,293 @@ +/* Photography! + * Contains: + * Camera + * Camera Film + * Photos + * Photo Albums + */ + +/******* +* film * +*******/ +/obj/item/device/camera_film + name = "film cartridge" + icon = 'icons/obj/items.dmi' + desc = "A camera film cartridge. Insert it into a camera to reload it." + icon_state = "film" + item_state = "electropack" + w_class = ITEM_SIZE_TINY + + +/******** +* photo * +********/ +var/global/photo_count = 0 + +/obj/item/weapon/photo + name = "photo" + icon = 'icons/obj/items.dmi' + icon_state = "photo" + item_state = "paper" + randpixel = 10 + w_class = ITEM_SIZE_TINY + var/id + var/icon/img //Big photo image + var/scribble //Scribble on the back. + var/image/tiny + var/photo_size = 3 + +/obj/item/weapon/photo/New() + id = photo_count++ + +/obj/item/weapon/photo/attack_self(mob/user as mob) + user.examinate(src) + +/obj/item/weapon/photo/update_icon() + overlays.Cut() + var/scale = 8/(photo_size*32) + var/image/small_img = image(img.icon) + small_img.transform *= scale + small_img.pixel_x = -32*(photo_size-1)/2 - 3 + small_img.pixel_y = -32*(photo_size-1)/2 + overlays |= small_img + + tiny = image(img.icon) + tiny.transform *= 0.5*scale + tiny.underlays += image('icons/obj/bureaucracy.dmi',"photo") + tiny.pixel_x = -32*(photo_size-1)/2 - 3 + tiny.pixel_y = -32*(photo_size-1)/2 + 3 + +/obj/item/weapon/photo/attackby(obj/item/weapon/P as obj, mob/user as mob) + if(istype(P, /obj/item/weapon/pen)) + var/txt = sanitize(user, "What would you like to write on the back?", "Photo Writing", null) + if(loc == user && user.stat == 0) + scribble = txt + ..() + +/obj/item/weapon/photo/examine(mob/user) + if(in_range(user, src)) + show(user) + to_chat(user, desc) + else + to_chat(user, "It is too far away.") + +/obj/item/weapon/photo/proc/show(mob/user as mob) + user << browse_rsc(img, "tmp_photo_[id].png") + user << browse("[name]" \ + + "" \ + + "" \ + + "[scribble ? "
            Written on the back:
            [scribble]" : ""]"\ + + "", "window=book;size=[64*photo_size]x[scribble ? 400 : 64*photo_size]") + onclose(user, "[name]") + return + +/obj/item/weapon/photo/verb/rename() + set name = "Rename photo" + set category = "Object" + set src in usr + + var/n_name = sanitizeSafe(input(usr, "What would you like to label the photo?", "Photo Labelling", null) as text, MAX_NAME_LEN) + //loc.loc check is for making possible renaming photos in clipboards + if(( (loc == usr || (loc.loc && loc.loc == usr)) && usr.stat == 0)) + SetName("[(n_name ? text("[n_name]") : "photo")]") + add_fingerprint(usr) + return + + +/************** +* photo album * +**************/ +/obj/item/weapon/storage/photo_album + name = "Photo album" + icon = 'icons/obj/items.dmi' + icon_state = "album" + item_state = "briefcase" + w_class = ITEM_SIZE_NORMAL //same as book + storage_slots = DEFAULT_BOX_STORAGE //yes, that's storage_slots. Photos are w_class 1 so this has as many slots equal to the number of photos you could put in a box + can_hold = list(/obj/item/weapon/photo) + +/obj/item/weapon/storage/photo_album/MouseDrop(obj/over_object as obj) + + if((istype(usr, /mob/living/carbon/human))) + var/mob/M = usr + if(!( istype(over_object, /obj/screen) )) + return ..() + playsound(loc, "rustle", 50, 1, -5) + if((!( M.restrained() ) && !( M.stat ) && M.back == src)) + switch(over_object.name) + if("r_hand") + if(M.unEquip(src)) + M.put_in_r_hand(src) + if("l_hand") + if(M.unEquip(src)) + M.put_in_l_hand(src) + add_fingerprint(usr) + return + if(over_object == usr && in_range(src, usr) || usr.contents.Find(src)) + if(usr.s_active) + usr.s_active.close(usr) + show_to(usr) + return + return + +/********* +* camera * +*********/ +/obj/item/device/camera + name = "camera" + icon = 'icons/obj/items.dmi' + desc = "A polaroid camera." + icon_state = "camera" + item_state = "electropack" + w_class = ITEM_SIZE_SMALL + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + matter = list(DEFAULT_WALL_MATERIAL = 2000) + var/pictures_max = 10 + var/pictures_left = 10 + var/on = 1 + var/icon_on = "camera" + var/icon_off = "camera_off" + var/size = 3 +/obj/item/device/camera/update_icon() + var/datum/extension/base_icon_state/bis = get_extension(src, /datum/extension/base_icon_state) + if(on) + icon_state = "[bis.base_icon_state]" + else + icon_state = "[bis.base_icon_state]_off" +/obj/item/device/camera/Initialize() + set_extension(src, /datum/extension/base_icon_state, /datum/extension/base_icon_state, icon_state) + update_icon() + . = ..() + +/obj/item/device/camera/verb/change_size() + set name = "Set Photo Focus" + set category = "Object" + var/nsize = input("Photo Size","Pick a size of resulting photo.") as null|anything in list(1,3) + if(nsize) + size = nsize + to_chat(usr, "Camera will now take [size]x[size] photos.") + +/obj/item/device/camera/attack(mob/living/carbon/human/M as mob, mob/user as mob) + return + +/obj/item/device/camera/attack_self(mob/user as mob) + on = !on + update_icon() + to_chat(user, "You switch the camera [on ? "on" : "off"].") + return + +/obj/item/device/camera/attackby(obj/item/I as obj, mob/user as mob) + if(istype(I, /obj/item/device/camera_film)) + if(pictures_left) + to_chat(user, "[src] still has some film in it!") + return + to_chat(user, "You insert [I] into [src].") + user.drop_item() + qdel(I) + pictures_left = pictures_max + return + ..() + + +/obj/item/device/camera/proc/get_mobs(turf/the_turf as turf) + var/mob_detail + for(var/mob/living/carbon/A in the_turf) + if(A.invisibility) continue + var/holding = null + if(A.l_hand || A.r_hand) + if(A.l_hand) holding = "They are holding \a [A.l_hand]" + if(A.r_hand) + if(holding) + holding += " and \a [A.r_hand]" + else + holding = "They are holding \a [A.r_hand]" + + if(!mob_detail) + mob_detail = "You can see [A] on the photo[(A.health / A.maxHealth) < 0.75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]. " + else + mob_detail += "You can also see [A] on the photo[(A.health / A.maxHealth)< 0.75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]." + return mob_detail + +/obj/item/device/camera/afterattack(atom/target as mob|obj|turf|area, mob/user as mob, flag) + if(!on || !pictures_left || ismob(target.loc)) return + captureimage(target, user, flag) + + playsound(loc, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 75, 1, -3) + + pictures_left-- + to_chat(user, "[pictures_left] photos left.") + + on = 0 + update_icon() + spawn(64) + on = 1 + update_icon() + +/obj/item/device/camera/examine(mob/user) + if(!..(user)) + return + + to_chat(user, "It has [pictures_left] photo\s left.") + +//Proc for capturing check +/mob/living/proc/can_capture_turf(turf/T) + var/viewer = src + //if(src.client) //To make shooting through security cameras possible + //viewer = src.client.eye + var/can_see = (T in view(viewer)) + return can_see + +/obj/item/device/camera/proc/captureimage(atom/target, mob/living/user, flag) + var/x_c = target.x - (size-1)/2 + var/y_c = target.y + (size-1)/2 + var/z_c = target.z + var/mobs = "" + for(var/i = 1 to size) + for(var/j = 1 to size) + var/turf/T = locate(x_c, y_c, z_c) + if(user.can_capture_turf(T)) + mobs += get_mobs(T) + x_c++ + y_c-- + x_c = x_c - size + + var/obj/item/weapon/photo/p = createpicture(target, user, mobs, flag) + printpicture(user, p) + +/obj/item/device/camera/proc/createpicture(atom/target, mob/user, mobs, flag) + var/x_c = target.x - (size-1)/2 + var/y_c = target.y - (size-1)/2 + var/z_c = target.z + var/icon/photoimage = generate_image(x_c, y_c, z_c, size, CAPTURE_MODE_REGULAR, user, 0) + + var/obj/item/weapon/photo/p = new() + p.img = photoimage + p.desc = mobs + p.photo_size = size + p.update_icon() + + return p + +/obj/item/device/camera/proc/printpicture(mob/user, obj/item/weapon/photo/p) + p.loc = user.loc + if(!user.get_inactive_hand()) + user.put_in_inactive_hand(p) + +/obj/item/weapon/photo/proc/copy(var/copy_id = 0) + var/obj/item/weapon/photo/p = new/obj/item/weapon/photo() + + p.SetName(name) + p.icon = icon(icon, icon_state) + p.tiny = icon(tiny) + p.img = icon(img) + p.desc = desc + p.pixel_x = pixel_x + p.pixel_y = pixel_y + p.photo_size = photo_size + p.scribble = scribble + + if(copy_id) + p.id = id + + return p diff --git a/code/modules/paperwork/silicon_photography.dm b/code/modules/paperwork/silicon_photography.dm new file mode 100644 index 00000000..9cff9a40 --- /dev/null +++ b/code/modules/paperwork/silicon_photography.dm @@ -0,0 +1,156 @@ +/************** +* AI-specific * +**************/ +/obj/item/device/camera/siliconcam + var/in_camera_mode = 0 + var/photos_taken = 0 + var/list/obj/item/weapon/photo/aipictures = list() + +/obj/item/device/camera/siliconcam/ai_camera //camera AI can take pictures with + name = "AI photo camera" + +/obj/item/device/camera/siliconcam/robot_camera //camera cyborgs can take pictures with + name = "Cyborg photo camera" + +/obj/item/device/camera/siliconcam/drone_camera //currently doesn't offer the verbs, thus cannot be used + name = "Drone photo camera" + +/obj/item/device/camera/siliconcam/proc/injectaialbum(obj/item/weapon/photo/p, var/sufix = "") //stores image information to a list similar to that of the datacore + p.loc = src + photos_taken++ + p.SetName("Image [photos_taken][sufix]") + aipictures += p + +/obj/item/device/camera/siliconcam/proc/injectmasteralbum(obj/item/weapon/photo/p) //stores image information to a list similar to that of the datacore + var/mob/living/silicon/robot/C = usr + if(C.connected_ai) + C.connected_ai.silicon_camera.injectaialbum(p.copy(1), " (synced from [C.name])") + to_chat(C.connected_ai, "Image uploaded by [C.name]") + to_chat(usr, "Image synced to remote database")//feedback to the Cyborg player that the picture was taken + else + to_chat(usr, "Image recorded") + // Always save locally + injectaialbum(p) + +/obj/item/device/camera/siliconcam/proc/selectpicture(obj/item/device/camera/siliconcam/cam) + if(!cam) + cam = getsource() + + var/list/nametemp = list() + var/find + if(cam.aipictures.len == 0) + to_chat(usr, "No images saved") + return + for(var/obj/item/weapon/photo/t in cam.aipictures) + nametemp += t.name + find = input("Select image (numbered in order taken)") as null|anything in nametemp + if(!find) + return + + for(var/obj/item/weapon/photo/q in cam.aipictures) + if(q.name == find) + return q + +/obj/item/device/camera/siliconcam/proc/viewpictures() + var/obj/item/weapon/photo/selection = selectpicture() + + if(!selection) + return + + selection.show(usr) + to_chat(usr, selection.desc) +/obj/item/device/camera/siliconcam/proc/deletepicture(obj/item/device/camera/siliconcam/cam) + var/selection = selectpicture(cam) + + if(!selection) + return + + aipictures -= selection + to_chat(usr, "Local image deleted") +//Capture Proc for AI / Robot +/mob/living/silicon/ai/can_capture_turf(turf/T) + var/mob/living/silicon/ai = src + return ai.TurfAdjacent(T) + +/obj/item/device/camera/siliconcam/proc/toggle_camera_mode() + if(in_camera_mode) + camera_mode_off() + else + camera_mode_on() + +/obj/item/device/camera/siliconcam/proc/camera_mode_off() + src.in_camera_mode = 0 + to_chat(usr, "Camera Mode deactivated") +/obj/item/device/camera/siliconcam/proc/camera_mode_on() + src.in_camera_mode = 1 + to_chat(usr, "Camera Mode activated") +/obj/item/device/camera/siliconcam/ai_camera/printpicture(mob/user, obj/item/weapon/photo/p) + injectaialbum(p) + to_chat(usr, "Image recorded") +/obj/item/device/camera/siliconcam/robot_camera/printpicture(mob/user, obj/item/weapon/photo/p) + injectmasteralbum(p) + +/obj/item/device/camera/siliconcam/ai_camera/verb/take_image() + set category = "Silicon Commands" + set name = "Take Image" + set desc = "Takes an image" + set src in usr + + toggle_camera_mode() + +/obj/item/device/camera/siliconcam/ai_camera/verb/view_images() + set category = "Silicon Commands" + set name = "View Images" + set desc = "View images" + set src in usr + + viewpictures() + +/obj/item/device/camera/siliconcam/ai_camera/verb/delete_images() + set category = "Silicon Commands" + set name = "Delete Image" + set desc = "Delete image" + set src in usr + + deletepicture() + +/obj/item/device/camera/siliconcam/robot_camera/verb/take_image() + set category ="Silicon Commands" + set name = "Take Image" + set desc = "Takes an image" + set src in usr + + toggle_camera_mode() + +/obj/item/device/camera/siliconcam/robot_camera/verb/view_images() + set category ="Silicon Commands" + set name = "View Images" + set desc = "View images" + set src in usr + + viewpictures() + +/obj/item/device/camera/siliconcam/robot_camera/verb/delete_images() + set category = "Silicon Commands" + set name = "Delete Image" + set desc = "Delete a local image" + set src in usr + + deletepicture(src) + +obj/item/device/camera/siliconcam/proc/getsource() + if(istype(src.loc, /mob/living/silicon/ai)) + return src + + var/mob/living/silicon/robot/C = usr + var/obj/item/device/camera/siliconcam/Cinfo + if(C.connected_ai) + Cinfo = C.connected_ai.silicon_camera + else + Cinfo = src + return Cinfo + +/mob/living/silicon/proc/GetPicture() + if(!silicon_camera) + return + return silicon_camera.selectpicture() diff --git a/code/modules/paperwork/stamps.dm b/code/modules/paperwork/stamps.dm new file mode 100644 index 00000000..685cb222 --- /dev/null +++ b/code/modules/paperwork/stamps.dm @@ -0,0 +1,87 @@ +/obj/item/weapon/stamp + name = "rubber stamp" + desc = "A rubber stamp for stamping important documents." + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "stamp-qm" + item_state = "stamp" + throwforce = 0 + w_class = ITEM_SIZE_TINY + throw_speed = 7 + throw_range = 15 + matter = list(DEFAULT_WALL_MATERIAL = 60) + attack_verb = list("stamped") + +/obj/item/weapon/stamp/captain + name = "captain's rubber stamp" + icon_state = "stamp-cap" + +/obj/item/weapon/stamp/hop + name = "head of personnel's rubber stamp" + icon_state = "stamp-hop" + +/obj/item/weapon/stamp/hos + name = "head of security's rubber stamp" + icon_state = "stamp-hos" + +/obj/item/weapon/stamp/ward + name = "warden's rubber stamp" + icon_state = "stamp-ward" + +/obj/item/weapon/stamp/ce + name = "chief engineer's rubber stamp" + icon_state = "stamp-ce" + +/obj/item/weapon/stamp/rd + name = "research director's rubber stamp" + icon_state = "stamp-rd" + +/obj/item/weapon/stamp/cmo + name = "chief medical officer's rubber stamp" + icon_state = "stamp-cmo" + +/obj/item/weapon/stamp/denied + name = "\improper DENIED rubber stamp" + icon_state = "stamp-deny" + +/obj/item/weapon/stamp/clown + name = "clown's rubber stamp" + icon_state = "stamp-clown" + +/obj/item/weapon/stamp/internalaffairs + name = "internal affairs rubber stamp" + icon_state = "stamp-intaff" + +/obj/item/weapon/stamp/centcomm + name = "centcomm rubber stamp" + icon_state = "stamp-cent" + +/obj/item/weapon/stamp/qm + name = "quartermaster's rubber stamp" + icon_state = "stamp-qm" + +/obj/item/weapon/stamp/cargo + name = "cargo rubber stamp" + icon_state = "stamp-cargo" + +// Syndicate stamp to forge documents. +/obj/item/weapon/stamp/chameleon/attack_self(mob/user as mob) + + var/list/stamp_types = typesof(/obj/item/weapon/stamp) - src.type // Get all stamp types except our own + var/list/stamps = list() + + // Generate them into a list + for(var/stamp_type in stamp_types) + var/obj/item/weapon/stamp/S = new stamp_type + stamps[capitalize(S.name)] = S + + var/list/show_stamps = list("EXIT" = null) + sortList(stamps) // the list that will be shown to the user to pick from + + var/input_stamp = input(user, "Choose a stamp to disguise as.", "Choose a stamp.") in show_stamps + + if(user && src in user.contents) + + var/obj/item/weapon/stamp/chosen_stamp = stamps[capitalize(input_stamp)] + + if(chosen_stamp) + SetName(chosen_stamp.name) + icon_state = chosen_stamp.icon_state diff --git a/code/modules/placeholder/placeholder.dm b/code/modules/placeholder/placeholder.dm new file mode 100644 index 00000000..7e3e86de --- /dev/null +++ b/code/modules/placeholder/placeholder.dm @@ -0,0 +1,40 @@ +/obj/machinery/kaos/cargo_machine + name = "Supply Computer" + desc = "You use this to buy shit." + icon = 'icons/obj/old_computers.dmi' + icon_state = "cargo_machine" + anchored = TRUE + density = TRUE + + +/obj/machinery/kaos/cargo_machine/red + +/obj/machinery/kaos/cargo_machine/blue + +/obj/effect/landmark/red_cargo + +/obj/effect/landmark/blue_cargo + + +//Just for looks, it shows off nicely where the cargo will be dropped off. +/obj/structure/cargo_pad + name = "Cargo Pad" + desc = "Stuff ordered from the cargo computer will appear on these pads." + icon = 'icons/obj/old_computers.dmi' + icon_state = "cargo_pad" + density = FALSE + unacidable = TRUE + anchored = TRUE + plane = WALL_PLANE + +/obj/structure/cargo_pad/ex_act() + return + +/obj/structure/cargo_pad/bottom_left + icon_state = "bottom_left" + +/obj/structure/cargo_pad/bottom_middle + icon_state = "bottom_middle" + +/obj/structure/cargo_pad/bottom_right + icon_state = "bottom_right" \ No newline at end of file diff --git a/code/modules/power/antimatter/computer.dm b/code/modules/power/antimatter/computer.dm new file mode 100644 index 00000000..0568bc39 --- /dev/null +++ b/code/modules/power/antimatter/computer.dm @@ -0,0 +1,94 @@ +//This file was auto-corrected by findeclaration.exe on 29/05/2012 15:03:05 +#define STATE_DEFAULT 1 +#define STATE_INJECTOR 2 +#define STATE_ENGINE 3 + + +/obj/machinery/computer/am_engine + name = "Antimatter Engine Console" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "comm_computer" + req_access = list(ACCESS_ENGINE) + var/engine_id = 0 + var/authenticated = 0 + var/obj/machinery/power/am_engine/engine/connected_E = null + var/obj/machinery/power/am_engine/injector/connected_I = null + var/state = STATE_DEFAULT + +/obj/machinery/computer/am_engine/New() + ..() + spawn( 24 ) + for(var/obj/machinery/power/am_engine/engine/E in world) + if(E.engine_id == src.engine_id) + src.connected_E = E + for(var/obj/machinery/power/am_engine/injector/I in world) + if(I.engine_id == src.engine_id) + src.connected_I = I + return + +/obj/machinery/computer/am_engine/Topic(href, href_list) + if((. = ..())) + return + + if(!href_list["operation"]) + return + switch(href_list["operation"]) + // main interface + if("activate") + src.connected_E.engine_process() + if("engine") + src.state = STATE_ENGINE + if("injector") + src.state = STATE_INJECTOR + if("main") + src.state = STATE_DEFAULT + if("login") + var/mob/M = usr + var/obj/item/weapon/card/id/I = M.get_active_hand() + if (I && istype(I)) + if(src.check_access(I)) + authenticated = 1 + if("deactivate") + src.connected_E.stopping = 1 + if("logout") + authenticated = 0 + + src.updateUsrDialog() + +/obj/machinery/computer/am_engine/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/am_engine/attack_paw(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/am_engine/attack_hand(var/mob/user as mob) + if(..()) + return + user.machine = src + var/dat = "Engine Computer" + switch(src.state) + if(STATE_DEFAULT) + if (src.authenticated) + dat += "
            \[ Log Out \]
            " + dat += "
            \[ Engine Menu \]" + dat += "
            \[ Injector Menu \]" + else + dat += "
            \[ Log In \]" + if(STATE_INJECTOR) + if(src.connected_I.injecting) + dat += "
            \[ Injecting \]
            " + else + dat += "
            \[ Injecting not in progress \]
            " + if(STATE_ENGINE) + if(src.connected_E.stopping) + dat += "
            \[ STOPPING \]" + else if(src.connected_E.operating && !src.connected_E.stopping) + dat += "
            \[ Emergency Stop \]" + else + dat += "
            \[ Activate Engine \]" + dat += "
            Contents:
            [src.connected_E.H_fuel]kg of Hydrogen
            [src.connected_E.antiH_fuel]kg of Anti-Hydrogen
            " + + dat += "
            \[ [(src.state != STATE_DEFAULT) ? "Main Menu | " : ""]Close \]" + user << browse(dat, "window=communications;size=400x500") + onclose(user, "communications") + diff --git a/code/modules/power/antimatter/containment_jar.dm b/code/modules/power/antimatter/containment_jar.dm new file mode 100644 index 00000000..7c694126 --- /dev/null +++ b/code/modules/power/antimatter/containment_jar.dm @@ -0,0 +1,41 @@ +/obj/item/weapon/am_containment + name = "antimatter containment jar" + desc = "Holds antimatter." + icon = 'icons/obj/machines/antimatter.dmi' + icon_state = "jar" + density = 0 + anchored = 0 + force = 8 + throwforce = 10 + throw_speed = 1 + throw_range = 2 + + var/fuel = 10000 + var/fuel_max = 10000//Lets try this for now + var/stability = 100//TODO: add all the stability things to this so its not very safe if you keep hitting in on things + + +/obj/item/weapon/am_containment/ex_act(severity) + switch(severity) + if(1.0) + explosion(get_turf(src), 1, 2, 3, 5)//Should likely be larger but this works fine for now I guess + if(src) + qdel(src) + return + if(2.0) + if(prob((fuel/10)-stability)) + explosion(get_turf(src), 1, 2, 3, 5) + if(src) + qdel(src) + return + stability -= 40 + if(3.0) + stability -= 20 + //check_stability() + return + +/obj/item/weapon/am_containment/proc/usefuel(var/wanted) + if(fuel < wanted) + wanted = fuel + fuel -= wanted + return wanted \ No newline at end of file diff --git a/code/modules/power/antimatter/control.dm b/code/modules/power/antimatter/control.dm new file mode 100644 index 00000000..09cd19a5 --- /dev/null +++ b/code/modules/power/antimatter/control.dm @@ -0,0 +1,324 @@ +/obj/machinery/power/am_control_unit + name = "antimatter control unit" + desc = "This device injects antimatter into connected shielding units, the more antimatter injected the more power produced. Wrench the device to set it up." + icon = 'icons/obj/machines/antimatter.dmi' + icon_state = "control" + anchored = 1 + density = 1 + use_power = 1 + idle_power_usage = 100 + active_power_usage = 1000 + + var/list/obj/machinery/am_shielding/linked_shielding + var/list/obj/machinery/am_shielding/linked_cores + var/obj/item/weapon/am_containment/fueljar + var/update_shield_icons = 0 + var/stability = 100 + var/exploding = 0 + + var/active = 0//On or not + var/fuel_injection = 2//How much fuel to inject + var/shield_icon_delay = 0//delays resetting for a short time + var/reported_core_efficiency = 0 + + var/power_cycle = 0 + var/power_cycle_delay = 4//How many ticks till produce_power is called + var/stored_core_stability = 0 + var/stored_core_stability_delay = 0 + + var/stored_power = 0//Power to deploy per tick + + +/obj/machinery/power/am_control_unit/New() + ..() + linked_shielding = list() + linked_cores = list() + + +/obj/machinery/power/am_control_unit/Destroy()//Perhaps damage and run stability checks rather than just qdel on the others + for(var/obj/machinery/am_shielding/AMS in linked_shielding) + qdel(AMS) + ..() + + +/obj/machinery/power/am_control_unit/Process() + if(exploding) + explosion(get_turf(src),8,12,18,12) + if(src) qdel(src) + + if(update_shield_icons && !shield_icon_delay) + check_shield_icons() + update_shield_icons = 0 + + if(stat & (NOPOWER|BROKEN) || !active)//can update the icons even without power + return + + if(!fueljar)//No fuel but we are on, shutdown + toggle_power() + //Angry buzz or such here + return + + add_avail(stored_power) + + power_cycle++ + if(power_cycle >= power_cycle_delay) + produce_power() + power_cycle = 0 + + return + + +/obj/machinery/power/am_control_unit/proc/produce_power() + playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) + var/core_power = reported_core_efficiency//Effectively how much fuel we can safely deal with + if(core_power <= 0) return 0//Something is wrong + var/core_damage = 0 + var/fuel = fueljar.usefuel(fuel_injection) + + stored_power = (fuel/core_power)*fuel*200000 + //Now check if the cores could deal with it safely, this is done after so you can overload for more power if needed, still a bad idea + if(fuel > (2*core_power))//More fuel has been put in than the current cores can deal with + if(prob(50))core_damage = 1//Small chance of damage + if((fuel-core_power) > 5) core_damage = 5//Now its really starting to overload the cores + if((fuel-core_power) > 10) core_damage = 20//Welp now you did it, they wont stand much of this + if(core_damage == 0) return + for(var/obj/machinery/am_shielding/AMS in linked_cores) + AMS.stability -= core_damage + AMS.check_stability(1) + playsound(src.loc, 'sound/effects/bang.ogg', 50, 1) + return + + +/obj/machinery/power/am_control_unit/emp_act(severity) + switch(severity) + if(1) + if(active) toggle_power() + stability -= rand(15,30) + if(2) + if(active) toggle_power() + stability -= rand(10,20) + ..() + return 0 + + +/obj/machinery/power/am_control_unit/ex_act(severity) + switch(severity) + if(1.0) + stability -= 60 + if(2.0) + stability -= 40 + if(3.0) + stability -= 20 + check_stability() + return + + +/obj/machinery/power/am_control_unit/bullet_act(var/obj/item/projectile/Proj) + if(Proj.check_armour != "bullet") + stability -= Proj.force + return 0 + + +/obj/machinery/power/am_control_unit/power_change() + . = ..() + if((stat & NOPOWER) && active) + toggle_power() + return + + +/obj/machinery/power/am_control_unit/update_icon() + if(active) icon_state = "control_on" + else icon_state = "control" + //No other icons for it atm + + +/obj/machinery/power/am_control_unit/attackby(obj/item/W, mob/user) + if(!istype(W) || !user) return + if(isWrench(W)) + if(!anchored) + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + user.visible_message("[user.name] secures the [src.name] to the floor.", \ + "You secure the anchor bolts to the floor.", \ + "You hear a ratchet") + src.anchored = 1 + connect_to_network() + else if(!linked_shielding.len > 0) + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + user.visible_message("[user.name] unsecures the [src.name].", \ + "You remove the anchor bolts.", \ + "You hear a ratchet") + src.anchored = 0 + disconnect_from_network() + else + to_chat(user, "Once bolted and linked to a shielding unit it the [src.name] is unable to be moved!") + return + + if(istype(W, /obj/item/weapon/am_containment)) + if(fueljar) + to_chat(user, "There is already a [fueljar] inside!") + return + fueljar = W + user.remove_from_mob(W) + W.loc = src + user.update_icons() + user.visible_message("[user.name] loads an [W.name] into the [src.name].", \ + "You load an [W.name].", \ + "You hear a thunk.") + return + + if(W.force >= 20) + stability -= W.force/2 + check_stability() + ..() + return + + +/obj/machinery/power/am_control_unit/attack_hand(mob/user as mob) + if(anchored) + interact(user) + return + + +/obj/machinery/power/am_control_unit/proc/add_shielding(var/obj/machinery/am_shielding/AMS, var/AMS_linking = 0) + if(!istype(AMS)) return 0 + if(!anchored) return 0 + if(!AMS_linking && !AMS.link_control(src)) return 0 + linked_shielding.Add(AMS) + update_shield_icons = 1 + return 1 + + +/obj/machinery/power/am_control_unit/proc/remove_shielding(var/obj/machinery/am_shielding/AMS) + if(!istype(AMS)) return 0 + linked_shielding.Remove(AMS) + update_shield_icons = 2 + if(active) toggle_power() + return 1 + + +/obj/machinery/power/am_control_unit/proc/check_stability()//TODO: make it break when low also might want to add a way to fix it like a part or such that can be replaced + if(stability <= 0) + qdel(src) + return + + +/obj/machinery/power/am_control_unit/proc/toggle_power() + active = !active + if(active) + use_power = 2 + visible_message("The [src.name] starts up.") + else + use_power = 1 + visible_message("The [src.name] shuts down.") + update_icon() + return + + +/obj/machinery/power/am_control_unit/proc/check_shield_icons()//Forces icon_update for all shields + if(shield_icon_delay) return + shield_icon_delay = 1 + if(update_shield_icons == 2)//2 means to clear everything and rebuild + for(var/obj/machinery/am_shielding/AMS in linked_shielding) + if(AMS.processing) AMS.shutdown_core() + AMS.control_unit = null + spawn(10) + AMS.controllerscan() + linked_shielding = list() + + else + for(var/obj/machinery/am_shielding/AMS in linked_shielding) + AMS.update_icon() + spawn(20) + shield_icon_delay = 0 + return + + +/obj/machinery/power/am_control_unit/proc/check_core_stability() + if(stored_core_stability_delay || linked_cores.len <= 0) return + stored_core_stability_delay = 1 + stored_core_stability = 0 + for(var/obj/machinery/am_shielding/AMS in linked_cores) + stored_core_stability += AMS.stability + stored_core_stability/=linked_cores.len + spawn(40) + stored_core_stability_delay = 0 + return + + +/obj/machinery/power/am_control_unit/interact(mob/user) + if((get_dist(src, user) > 1) || (stat & (BROKEN|NOPOWER))) + if(!istype(user, /mob/living/silicon/ai)) + user.unset_machine() + user << browse(null, "window=AMcontrol") + return + user.set_machine(src) + + var/dat = "" + dat += "AntiMatter Control Panel
            " + dat += "Close
            " + dat += "Refresh
            " + dat += "Force Shielding Update

            " + dat += "Status: [(active?"Injecting":"Standby")]
            " + dat += "Toggle Status
            " + + dat += "Instability: [stability]%
            " + dat += "Reactor parts: [linked_shielding.len]
            "//TODO: perhaps add some sort of stability check + dat += "Cores: [linked_cores.len]

            " + dat += "-Current Efficiency: [reported_core_efficiency]
            " + dat += "-Average Stability: [stored_core_stability] (update)
            " + dat += "Last Produced: [stored_power]
            " + + dat += "Fuel: " + if(!fueljar) + dat += "
            No fuel receptacle detected." + else + dat += "Eject
            " + dat += "- [fueljar.fuel]/[fueljar.fuel_max] Units
            " + + dat += "- Injecting: [fuel_injection] units
            " + dat += "- --|++

            " + + + user << browse(dat, "window=AMcontrol;size=420x500") + onclose(user, "AMcontrol") + return + + +/obj/machinery/power/am_control_unit/Topic(href, href_list) + ..() + //Ignore input if we are broken or guy is not touching us, AI can control from a ways away + if(stat & (BROKEN|NOPOWER) || (get_dist(src, usr) > 1 && !istype(usr, /mob/living/silicon/ai))) + usr.unset_machine() + usr << browse(null, "window=AMcontrol") + return + + if(href_list["close"]) + usr << browse(null, "window=AMcontrol") + usr.unset_machine() + return + + if(href_list["togglestatus"]) + toggle_power() + + if(href_list["refreshicons"]) + update_shield_icons = 1 + + if(href_list["ejectjar"]) + if(fueljar) + fueljar.loc = src.loc + fueljar = null + //fueljar.control_unit = null currently it does not care where it is + //update_icon() when we have the icon for it + + if(href_list["strengthup"]) + fuel_injection++ + + if(href_list["strengthdown"]) + fuel_injection-- + if(fuel_injection < 0) fuel_injection = 0 + + if(href_list["refreshstability"]) + check_core_stability() + + updateDialog() + return \ No newline at end of file diff --git a/code/modules/power/antimatter/engine.dm b/code/modules/power/antimatter/engine.dm new file mode 100644 index 00000000..6a66a0c9 --- /dev/null +++ b/code/modules/power/antimatter/engine.dm @@ -0,0 +1,207 @@ +/obj/machinery/power/am_engine + icon = 'icons/am_engine.dmi' + density = 1 + anchored = 1.0 + atom_flags = ATOM_FLAG_CHECKS_BORDER + +/obj/machinery/power/am_engine/bits + name = "Antimatter Engine" + icon_state = "1" + +/obj/machinery/power/am_engine/engine + name = "Antimatter Engine" + icon_state = "am_engine" + var/engine_id = 0 + var/H_fuel = 0 + var/antiH_fuel = 0 + var/operating = 0 + var/stopping = 0 + var/obj/machinery/power/am_engine/injector/connected = null + +/obj/machinery/power/am_engine/injector + name = "Injector" + icon_state = "injector" + var/engine_id = 0 + var/injecting = 0 + var/fuel = 0 + var/obj/machinery/power/am_engine/engine/connected = null + +//injector + +/obj/machinery/power/am_engine/injector/New() + ..() + spawn( 13 ) + var/loc = get_step(src, NORTH) + src.connected = locate(/obj/machinery/power/am_engine/engine, get_step(loc, NORTH)) + return + return + + +/obj/machinery/power/am_engine/injector/attackby(obj/item/weapon/fuel/F, mob/user) + if( (stat & BROKEN) || !connected) return + + if(istype(F, /obj/item/weapon/fuel/H)) + if(injecting) + to_chat(user, "Theres already a fuel rod in the injector!") + return + to_chat(user, "You insert the rod into the injector") + injecting = 1 + var/fuel = F.fuel + qdel(F) + spawn( 300 ) + injecting = 0 + new/obj/item/weapon/fuel(src.loc) + connected.H_fuel += fuel + + if(istype(F, /obj/item/weapon/fuel/antiH)) + if(injecting) + to_chat(user, "Theres already a fuel rod in the injector!") + return + to_chat(user, "You insert the rod into the injector") + injecting = 1 + var/fuel = F.fuel + qdel(F) + spawn( 300 ) + injecting = 0 + new /obj/item/weapon/fuel(src.loc) + connected.antiH_fuel += fuel + + return + + +//engine + + +/obj/machinery/power/am_engine/engine/New() + ..() + spawn( 7 ) + var/loc = get_step(src, SOUTH) + src.connected = locate(/obj/machinery/power/am_engine/injector, get_step(loc, SOUTH)) + return + return + + +/obj/machinery/power/am_engine/engine/proc/engine_go() + + if( (!src.connected) || (stat & BROKEN) ) + return + + if(!antiH_fuel || !H_fuel) + return + + operating = 1 + var/energy = 0 + + if(antiH_fuel == H_fuel) + var/mass = antiH_fuel + H_fuel + energy = convert2energy(mass) + H_fuel = 0 + antiH_fuel = 0 + else + var/residual_matter = modulus(H_fuel - antiH_fuel) + var/mass = antiH_fuel + H_fuel - residual_matter + energy = convert2energy(mass) + if( H_fuel > antiH_fuel ) + H_fuel = residual_matter + antiH_fuel = 0 + else + H_fuel = 0 + antiH_fuel = residual_matter + + for(var/mob/M in hearers(src, null)) + M.show_message("You hear a loud bang!")) + + //Q = k x (delta T) + + energy = energy*0.75 + operating = 0 + + //TODO: DEFERRED Heat tile + + return + + +/obj/machinery/power/am_engine/engine/proc/engine_process() + + do + if( (!src.connected) || (stat & BROKEN) ) + return + + if(!antiH_fuel || !H_fuel) + return + + if(operating) + return + + operating = 1 + + sleep(50) + + var/energy //energy from the reaction + var/H //residual matter if H + var/antiH //residual matter if antiH + var/mass //total mass + + if(antiH_fuel == H_fuel) //if they're equal then convert the whole mass to energy + mass = antiH_fuel + H_fuel + energy = convert2energy(mass) + + else //else if they're not equal determine which isn't equal + //and set it equal to either H or antiH so we don't lose anything + + var/residual_matter = modulus(H_fuel - antiH_fuel) + mass = antiH_fuel + H_fuel - residual_matter + energy = convert2energy(mass) + + if( H_fuel > antiH_fuel ) + H = residual_matter + else + antiH = residual_matter + + + if(energy > convert2energy(8e-12)) //TOO MUCH ENERGY + for(var/mob/M in hearers(src, null)) + M.show_message("You hear a loud whirring!")) + sleep(20) + + //Q = k x (delta T) + //Too much energy so machine panics and dissapates half of it as heat + //The rest of the energetic photons then form into H and anti H particles again! + + H_fuel -= H + antiH_fuel -= antiH + antiH_fuel = antiH_fuel/2 + H_fuel = H_fuel/2 + + energy = convert2energy(H_fuel + antiH_fuel) + + H_fuel += H + antiH_fuel += antiH + + if(energy > convert2energy(8e-12)) //FAR TOO MUCH ENERGY STILL + for(var/mob/M in hearers(src, null)) + M.show_message("BANG!")) + new /obj/effect/bhole(src.loc) + + else //this amount of energy is okay so it does the proper output thing + + sleep(60) + //E = Pt + //Lets say its 86% efficient + var/output = 0.86*energy/20 + add_avail(output) + //yeah the machine realises that something isn't right and accounts for it if H or antiH + H_fuel -= H + antiH_fuel -= antiH + antiH_fuel = antiH_fuel/4 + H_fuel = H_fuel/4 + H_fuel += H + antiH_fuel += antiH + operating = 0 + sleep(100) + + while(!stopping) + + stopping = 0 + + return \ No newline at end of file diff --git a/code/modules/power/antimatter/fuel.dm b/code/modules/power/antimatter/fuel.dm new file mode 100644 index 00000000..e4a0388c --- /dev/null +++ b/code/modules/power/antimatter/fuel.dm @@ -0,0 +1,100 @@ +/obj/item/weapon/fuel + name = "Magnetic Storage Ring" + desc = "A magnetic storage ring." + icon = 'icons/obj/items.dmi' + icon_state = "rcdammo" + opacity = 0 + density = 0 + anchored = 0.0 + var/fuel = 0 + var/s_time = 1.0 + var/content = null + +/obj/item/weapon/fuel/H + name = "Hydrogen storage ring" + content = "Hydrogen" + fuel = 1e-12 //pico-kilogram + +/obj/item/weapon/fuel/antiH + name = "Anti-Hydrogen storage ring" + content = "Anti-Hydrogen" + fuel = 1e-12 //pico-kilogram + +/obj/item/weapon/fuel/attackby(obj/item/weapon/fuel/F, mob/user) + ..() + if(istype(src, /obj/item/weapon/fuel/antiH)) + if(istype(F, /obj/item/weapon/fuel/antiH)) + src.fuel += F.fuel + F.fuel = 0 + to_chat(user, "You have added the anti-Hydrogen to the storage ring, it now contains [src.fuel]kg") + if(istype(F, /obj/item/weapon/fuel/H)) + src.fuel += F.fuel + qdel(F) + src:annihilation(src.fuel) + if(istype(src, /obj/item/weapon/fuel/H)) + if(istype(F, /obj/item/weapon/fuel/H)) + src.fuel += F.fuel + F.fuel = 0 + to_chat(user, "You have added the Hydrogen to the storage ring, it now contains [src.fuel]kg") + if(istype(F, /obj/item/weapon/fuel/antiH)) + src.fuel += F.fuel + qdel(src) + F:annihilation(F.fuel) + +/obj/item/weapon/fuel/antiH/proc/annihilation(var/mass) + + var/strength = convert2energy(mass) + + if (strength < 773.0) + var/turf/T = get_turf(src) + + if (strength > (450+T0C)) + explosion(T, 0, 1, 2, 4) + else + if (strength > (300+T0C)) + explosion(T, 0, 0, 2, 3) + + qdel(src) + return + + var/turf/ground_zero = get_turf(loc) + + var/ground_zero_range = round(strength / 387) + explosion(ground_zero, ground_zero_range, ground_zero_range*2, ground_zero_range*3, ground_zero_range*4) + + //SN src = null + qdel(src) + return + + +/obj/item/weapon/fuel/examine(mob/user) + . = ..() + if(get_dist(src, user) <= 1) + to_chat(user, "A magnetic storage ring, it contains [fuel]kg of [content ? content : "nothing"].") + +/obj/item/weapon/fuel/proc/injest(mob/M as mob) + switch(content) + if("Anti-Hydrogen") + M.gib() + if("Hydrogen") + to_chat(M, "You feel very light, as if you might just float away...") + qdel(src) + return + +/obj/item/weapon/fuel/attack(mob/M as mob, mob/user as mob) + if (user != M) + var/obj/effect/equip_e/human/O = new /obj/effect/equip_e/human( ) + O.source = user + O.target = M + O.item = src + O.s_loc = user.loc + O.t_loc = M.loc + O.place = "fuel" + M.requests += O + spawn( 0 ) + O.process() + return + else + for(var/mob/O in viewers(M, null)) + O.show_message(text("[M] ate the [content ? content : "empty canister"]!"), 1) + src.injest(M) diff --git a/code/modules/power/antimatter/shielding.dm b/code/modules/power/antimatter/shielding.dm new file mode 100644 index 00000000..8629b7ba --- /dev/null +++ b/code/modules/power/antimatter/shielding.dm @@ -0,0 +1,207 @@ +//like orange but only checks north/south/east/west for one step +proc/cardinalrange(var/center) + var/list/things = list() + for(var/direction in GLOB.cardinal) + var/turf/T = get_step(center, direction) + if(!T) continue + things += T.contents + return things + +/obj/machinery/am_shielding + name = "antimatter reactor section" + desc = "This device was built using a phoron life-form that seems to increase phoron's natural ability to react with neutrinos while reducing the combustibility." + + icon = 'icons/obj/machines/antimatter.dmi' + icon_state = "shield" + anchored = 1 + density = 1 + dir = 1 + use_power = 0//Living things generally dont use power + idle_power_usage = 0 + active_power_usage = 0 + + var/obj/machinery/power/am_control_unit/control_unit = null + var/processing = 0//To track if we are in the update list or not, we need to be when we are damaged and if we ever + var/stability = 100//If this gets low bad things tend to happen + var/efficiency = 1//How many cores this core counts for when doing power processing, phoron in the air and stability could affect this + + +/obj/machinery/am_shielding/New(loc) + ..(loc) + spawn(10) + controllerscan() + return + + +/obj/machinery/am_shielding/proc/controllerscan(var/priorscan = 0) + //Make sure we are the only one here + if(!istype(src.loc, /turf)) + qdel(src) + return + for(var/obj/machinery/am_shielding/AMS in loc.contents) + if(AMS == src) continue + spawn(0) + qdel(src) + return + + //Search for shielding first + for(var/obj/machinery/am_shielding/AMS in cardinalrange(src)) + if(AMS && AMS.control_unit && link_control(AMS.control_unit)) + break + + if(!control_unit)//No other guys nearby look for a control unit + for(var/direction in GLOB.cardinal) + for(var/obj/machinery/power/am_control_unit/AMC in cardinalrange(src)) + if(AMC.add_shielding(src)) + break + + if(!control_unit) + if(!priorscan) + spawn(20) + controllerscan(1)//Last chance + return + spawn(0) + qdel(src) + return + + +/obj/machinery/am_shielding/Destroy() + if(control_unit) control_unit.remove_shielding(src) + if(processing) shutdown_core() + visible_message("\The [src] melts!") + //Might want to have it leave a mess on the floor but no sprites for now + ..() + return + + +/obj/machinery/am_shielding/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group || (height==0)) return 1 + return 0 + + +/obj/machinery/am_shielding/Process() + if(!processing) . = PROCESS_KILL + //TODO: core functions and stability + //TODO: think about checking the airmix for phoron and increasing power output + return + + +/obj/machinery/am_shielding/emp_act()//Immune due to not really much in the way of electronics. + return 0 + + +/obj/machinery/am_shielding/ex_act(severity) + switch(severity) + if(1.0) + stability -= 80 + if(2.0) + stability -= 40 + if(3.0) + stability -= 20 + check_stability() + return + + +/obj/machinery/am_shielding/bullet_act(var/obj/item/projectile/Proj) + if(Proj.check_armour != "bullet") + stability -= Proj.force/2 + return 0 + + +/obj/machinery/am_shielding/update_icon() + overlays.Cut() + for(var/direction in GLOB.alldirs) + var/machine = locate(/obj/machinery, get_step(loc, direction)) + if((istype(machine, /obj/machinery/am_shielding) && machine:control_unit == control_unit)||(istype(machine, /obj/machinery/power/am_control_unit) && machine == control_unit)) + overlays += "shield_[direction]" + + if(core_check()) + overlays += "core" + if(!processing) setup_core() + else if(processing) shutdown_core() + + +/obj/machinery/am_shielding/attackby(obj/item/W, mob/user) + if(!istype(W) || !user) return + if(W.force > 10) + stability -= W.force/2 + check_stability() + ..() + return + + + +//Call this to link a detected shilding unit to the controller +/obj/machinery/am_shielding/proc/link_control(var/obj/machinery/power/am_control_unit/AMC) + if(!istype(AMC)) return 0 + if(control_unit && control_unit != AMC) return 0//Already have one + control_unit = AMC + control_unit.add_shielding(src,1) + return 1 + + +//Scans cards for shields or the control unit and if all there it +/obj/machinery/am_shielding/proc/core_check() + for(var/direction in GLOB.alldirs) + var/machine = locate(/obj/machinery, get_step(loc, direction)) + if(!machine) return 0//Need all for a core + if(!istype(machine, /obj/machinery/am_shielding) && !istype(machine, /obj/machinery/power/am_control_unit)) return 0 + return 1 + + +/obj/machinery/am_shielding/proc/setup_core() + processing = 1 + START_PROCESSING(SSmachines, src) + if(!control_unit) return + control_unit.linked_cores.Add(src) + control_unit.reported_core_efficiency += efficiency + return + + +/obj/machinery/am_shielding/proc/shutdown_core() + processing = 0 + if(!control_unit) return + control_unit.linked_cores.Remove(src) + control_unit.reported_core_efficiency -= efficiency + return + + +/obj/machinery/am_shielding/proc/check_stability(var/injecting_fuel = 0) + if(stability > 0) return + if(injecting_fuel && control_unit) + control_unit.exploding = 1 + if(src) + qdel(src) + return + + +/obj/machinery/am_shielding/proc/recalc_efficiency(var/new_efficiency)//tbh still not 100% sure how I want to deal with efficiency so this is likely temp + if(!control_unit || !processing) return + if(stability < 50) + new_efficiency /= 2 + control_unit.reported_core_efficiency += (new_efficiency - efficiency) + efficiency = new_efficiency + return + + + +/obj/item/device/am_shielding_container + name = "packaged antimatter reactor section" + desc = "A small storage unit containing an antimatter reactor section. To use place near an antimatter control unit or deployed antimatter reactor section and use a multitool to activate this package." + icon = 'icons/obj/machines/antimatter.dmi' + icon_state = "box" + item_state = "electronic" + w_class = ITEM_SIZE_HUGE + obj_flags = OBJ_FLAG_CONDUCTIBLE + throwforce = 5 + throw_speed = 1 + throw_range = 2 + matter = list(DEFAULT_WALL_MATERIAL = 100, "waste" = 2000) + +/obj/item/device/am_shielding_container/attackby(var/obj/item/I, var/mob/user) + if(isMultitool(I) && istype(src.loc,/turf)) + new/obj/machinery/am_shielding(src.loc) + qdel(src) + return + ..() + return \ No newline at end of file diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm new file mode 100644 index 00000000..3962b9de --- /dev/null +++ b/code/modules/power/apc.dm @@ -0,0 +1,1284 @@ + + +// The Area Power Controller (APC) +// Controls and provides power to most electronics in an area +// Only one required per area +// Requires a wire connection to a power network through a terminal +// Generates a terminal based on the direction of the APC on spawn + +// There are three different power channels, lighting, equipment, and enviroment +// Each may have one of the following states + +#define POWERCHAN_OFF 0 // Power channel is off +#define POWERCHAN_OFF_TEMP 1 // Power channel is off until there is power +#define POWERCHAN_OFF_AUTO 2 // Power channel is off until power passes a threshold +#define POWERCHAN_ON 3 // Power channel is on until there is no power +#define POWERCHAN_ON_AUTO 4 // Power channel is on until power drops below a threshold + +// Power channels set to Auto change when power levels rise or drop below a threshold + +#define AUTO_THRESHOLD_LIGHTING 50 +#define AUTO_THRESHOLD_EQUIPMENT 25 +// The ENVIRON channel stays on as long as possible, and doesn't have a threshold + +#define CRITICAL_APC_EMP_PROTECTION 10 // EMP effect duration is divided by this number if the APC has "critical" flag +#define APC_UPDATE_ICON_COOLDOWN 100 // Time between automatically updating the icon (10 seconds) + +// Used to check whether or not to update the icon_state +#define UPDATE_CELL_IN 1 +#define UPDATE_OPENED1 2 +#define UPDATE_OPENED2 4 +#define UPDATE_MAINT 8 +#define UPDATE_BROKE 16 +#define UPDATE_BLUESCREEN 32 +#define UPDATE_WIREEXP 64 +#define UPDATE_ALLGOOD 128 + +// Used to check whether or not to update the overlay +#define APC_UPOVERLAY_CHARGEING0 1 +#define APC_UPOVERLAY_CHARGEING1 2 +#define APC_UPOVERLAY_CHARGEING2 4 +#define APC_UPOVERLAY_LOCKED 8 +#define APC_UPOVERLAY_OPERATING 16 + +// Various APC types +/obj/machinery/power/apc/critical + is_critical = 1 + +/obj/machinery/power/apc/high + cell_type = /obj/item/weapon/cell/high + +/obj/machinery/power/apc/high/inactive + cell_type = /obj/item/weapon/cell/high + lighting = 0 + equipment = 0 + environ = 0 + locked = 0 + coverlocked = 0 + +/obj/machinery/power/apc/super + cell_type = /obj/item/weapon/cell/super + +/obj/machinery/power/apc/super/critical + is_critical = 1 + +/obj/machinery/power/apc/hyper + cell_type = /obj/item/weapon/cell/hyper + +// Main APC code +/obj/machinery/power/apc + name = "area power controller" + desc = "A control terminal for the area electrical systems." + + icon_state = "apc0" + anchored = 1 + use_power = 0 + req_access = list(access_engine_equip) + clicksound = "switch" + var/area/area + var/areastring = null + var/obj/item/weapon/cell/cell + var/chargelevel = 0.0005 // Cap for how fast APC cells charge, as a percentage-per-tick (0.01 means cellcharge is capped to 1% per second) + var/cell_type = /obj/item/weapon/cell/apc + var/opened = 0 //0=closed, 1=opened, 2=cover removed + var/shorted = 0 + var/lighting = POWERCHAN_ON_AUTO + var/equipment = POWERCHAN_ON_AUTO + var/environ = POWERCHAN_ON_AUTO + var/operating = 1 + var/charging = 0 + var/chargemode = 1 + var/chargecount = 0 + var/locked = 1 + var/coverlocked = 1 + var/aidisabled = 0 + var/obj/machinery/power/terminal/terminal = null + var/lastused_light = 0 + var/lastused_equip = 0 + var/lastused_environ = 0 + var/lastused_charging = 0 + var/lastused_total = 0 + var/main_status = 0 + var/mob/living/silicon/ai/hacker = null // Malfunction var. If set AI hacked the APC and has full control. + var/wiresexposed = 0 + powernet = 0 // set so that APCs aren't found as powernet nodes //Hackish, Horrible, was like this before I changed it :( + var/debug= 0 + var/autoflag= 0 // 0 = off, 1= eqp and lights off, 2 = eqp off, 3 = all on. + var/has_electronics = 0 // 0 - none, 1 - plugged in, 2 - secured by screwdriver + var/beenhit = 0 // used for counting how many times it has been hit, used for Aliens at the moment + var/longtermpower = 10 + var/datum/wires/apc/wires = null + var/update_state = -1 + var/update_overlay = -1 + var/list/update_overlay_chan // Used to determine if there is a change in channels + var/is_critical = 0 + var/global/status_overlays = 0 + var/updating_icon = 0 + var/failure_timer = 0 + var/force_update = 0 + var/emp_hardened = 0 + var/global/list/status_overlays_lock + var/global/list/status_overlays_charging + var/global/list/status_overlays_equipment + var/global/list/status_overlays_lighting + var/global/list/status_overlays_environ + + +/obj/machinery/power/apc/updateDialog() + if (stat & (BROKEN|MAINT)) + return + ..() + +/obj/machinery/power/apc/connect_to_network() + //Override because the APC does not directly connect to the network; it goes through a terminal. + //The terminal is what the power computer looks for anyway. + if(terminal) + terminal.connect_to_network() + +/obj/machinery/power/apc/drain_power(var/drain_check, var/surge, var/amount = 0) + + if(drain_check) + return 1 + + // Prevents APCs from being stuck on 0% cell charge while reporting "Fully Charged" status. + charging = 0 + + // If the APC's interface is locked, limit the charge rate to 25%. + if(locked) + amount /= 4 + + var/drained_energy = 0 + + // First try to drain the power directly from attached power grid. + if(terminal && terminal.powernet) + terminal.powernet.trigger_warning() + drained_energy += terminal.powernet.draw_power(amount) + + // If the power grid provided enough power, we're good. If not, take the rest from the power cell. + if((drained_energy < amount) && cell) + drained_energy += cell.use((amount - drained_energy) * CELLRATE) + + return drained_energy + +/obj/machinery/power/apc/Initialize(mapload, var/ndir, var/building=0) + + wires = new(src) + + // offset 24 pixels in direction of dir + // this allows the APC to be embedded in a wall, yet still inside an area + if (building) + set_dir(ndir) + + pixel_x = (src.dir & 3)? 0 : (src.dir == 4 ? 24 : -24) + pixel_y = (src.dir & 3)? (src.dir ==1 ? 24 : -24) : 0 + + if (building==0) + init_round_start() + else + area = get_area(src) + area.apc = src + opened = 1 + operating = 0 + SetName("\improper [area.name] APC") + stat |= MAINT + src.update_icon() + + . = ..(mapload) + + if(operating) + src.update() + +/obj/machinery/power/apc/Destroy() + src.update() + area.apc = null + area.power_light = 0 + area.power_equip = 0 + area.power_environ = 0 + area.power_change() + qdel(wires) + wires = null + qdel(terminal) + terminal = null + if(cell) + cell.forceMove(loc) + cell = null + + // Malf AI, removes the APC from AI's hacked APCs list. + if((hacker) && (hacker.hacked_apcs) && (src in hacker.hacked_apcs)) + hacker.hacked_apcs -= src + + return ..() + +/obj/machinery/power/apc/proc/energy_fail(var/duration) + if(emp_hardened) + return + failure_timer = max(failure_timer, round(duration)) + +/obj/machinery/power/apc/proc/make_terminal() + // create a terminal object at the same position as original turf loc + // wires will attach to this + terminal = new/obj/machinery/power/terminal(src.loc) + terminal.set_dir(dir) + terminal.master = src + +/obj/machinery/power/apc/proc/init_round_start() + has_electronics = 2 //installed and secured + if(!terminal) + make_terminal() //wired + // is starting with a power cell installed, create it and set its charge level + if(cell_type) + src.cell = new cell_type(src) + + var/area/A = src.loc.loc + + //if area isn't specified use current + if(isarea(A) && src.areastring == null) + src.area = A + SetName("\improper [area.name] APC") + else + src.area = get_area_name(areastring) + SetName("\improper [area.name] APC") + area.apc = src + update_icon() + +/obj/machinery/power/apc/examine(mob/user) + if(..(user, 1)) + if(stat & BROKEN) + to_chat(user, "Looks broken.") + return + if(opened) + if(has_electronics && terminal) + to_chat(user, "The cover is [opened==2?"removed":"open"] and the power cell is [ cell ? "installed" : "missing"].") + else if (!has_electronics && terminal) + to_chat(user, "There are some wires but no any electronics.") + else if (has_electronics && !terminal) + to_chat(user, "Electronics installed but not wired.") + else /* if (!has_electronics && !terminal) */ + to_chat(user, "There is no electronics nor connected wires.") + + else + if (stat & MAINT) + to_chat(user, "The cover is closed. Something wrong with it: it doesn't work.") + else if (hacker && !hacker.hacked_apcs_hidden) + to_chat(user, "The cover is locked.") + else + to_chat(user, "The cover is closed.") + + +// update the APC icon to show the three base states +// also add overlays for indicator lights +/obj/machinery/power/apc/update_icon() + if (!status_overlays) + status_overlays = 1 + status_overlays_lock = new + status_overlays_charging = new + status_overlays_equipment = new + status_overlays_lighting = new + status_overlays_environ = new + + status_overlays_lock.len = 2 + status_overlays_charging.len = 3 + status_overlays_equipment.len = 5 + status_overlays_lighting.len = 5 + status_overlays_environ.len = 5 + + status_overlays_lock[1] = image(icon, "apcox-0") // 0=blue 1=red + status_overlays_lock[2] = image(icon, "apcox-1") + + status_overlays_charging[1] = image(icon, "apco3-0") + status_overlays_charging[2] = image(icon, "apco3-1") + status_overlays_charging[3] = image(icon, "apco3-2") + + status_overlays_equipment[POWERCHAN_OFF + 1] = image(icon, "apco0-0") + status_overlays_equipment[POWERCHAN_OFF_TEMP + 1] = image(icon, "apco0-1") + status_overlays_equipment[POWERCHAN_OFF_AUTO + 1] = image(icon, "apco0-1") + status_overlays_equipment[POWERCHAN_ON + 1] = image(icon, "apco0-2") + status_overlays_equipment[POWERCHAN_ON_AUTO + 1] = image(icon, "apco0-3") + + status_overlays_lighting[POWERCHAN_OFF + 1] = image(icon, "apco1-0") + status_overlays_lighting[POWERCHAN_OFF_TEMP + 1] = image(icon, "apco1-1") + status_overlays_lighting[POWERCHAN_OFF_AUTO + 1] = image(icon, "apco1-1") + status_overlays_lighting[POWERCHAN_ON + 1] = image(icon, "apco1-2") + status_overlays_lighting[POWERCHAN_ON_AUTO + 1] = image(icon, "apco1-3") + + status_overlays_environ[POWERCHAN_OFF + 1] = image(icon, "apco2-0") + status_overlays_environ[POWERCHAN_OFF_TEMP + 1] = image(icon, "apco2-1") + status_overlays_environ[POWERCHAN_OFF_AUTO + 1] = image(icon, "apco2-1") + status_overlays_environ[POWERCHAN_ON + 1] = image(icon, "apco2-2") + status_overlays_environ[POWERCHAN_ON_AUTO + 1] = image(icon, "apco2-3") + + var/update = check_updates() //returns 0 if no need to update icons. + // 1 if we need to update the icon_state + // 2 if we need to update the overlays + if(!update) + return + + if(update & 1) // Updating the icon state + if(update_state & UPDATE_ALLGOOD) + icon_state = "apc0" + else if(update_state & (UPDATE_OPENED1|UPDATE_OPENED2)) + var/basestate = "apc[ cell ? "2" : "1" ]" + if(update_state & UPDATE_OPENED1) + if(update_state & (UPDATE_MAINT|UPDATE_BROKE)) + icon_state = "apcmaint" //disabled APC cannot hold cell + else + icon_state = basestate + else if(update_state & UPDATE_OPENED2) + icon_state = "[basestate]-nocover" + else if(update_state & UPDATE_BROKE) + icon_state = "apc-b" + else if(update_state & UPDATE_BLUESCREEN) + icon_state = "apcemag" + else if(update_state & UPDATE_WIREEXP) + icon_state = "apcewires" + + if(!(update_state & UPDATE_ALLGOOD)) + if(overlays.len) + overlays = 0 + return + + if(update & 2) + if(overlays.len) + overlays.len = 0 + if(!(stat & (BROKEN|MAINT)) && update_state & UPDATE_ALLGOOD) + overlays += status_overlays_lock[locked+1] + overlays += status_overlays_charging[charging+1] + if(operating) + overlays += status_overlays_equipment[equipment+1] + overlays += status_overlays_lighting[lighting+1] + overlays += status_overlays_environ[environ+1] + + if(update & 3) + if(update_state & (UPDATE_OPENED1|UPDATE_OPENED2|UPDATE_BROKE)) + set_light(0) + else if(update_state & UPDATE_BLUESCREEN) + set_light(l_range = 2, l_power = 0.5, l_color = "#0000ff") + else if(!(stat & (BROKEN|MAINT)) && update_state & UPDATE_ALLGOOD) + var/color + switch(charging) + if(0) + color = "#f86060" + if(1) + color = "#a8b0f8" + if(2) + color = "#82ff4c" + set_light(l_range = 2, l_power = 0.5, l_color = color) + else + set_light(0) + +/obj/machinery/power/apc/proc/check_updates() + if(!update_overlay_chan) + update_overlay_chan = new/list() + var/last_update_state = update_state + var/last_update_overlay = update_overlay + var/list/last_update_overlay_chan = update_overlay_chan.Copy() + update_state = 0 + update_overlay = 0 + if(cell) + update_state |= UPDATE_CELL_IN + if(stat & BROKEN) + update_state |= UPDATE_BROKE + if(stat & MAINT) + update_state |= UPDATE_MAINT + if(opened) + if(opened==1) + update_state |= UPDATE_OPENED1 + if(opened==2) + update_state |= UPDATE_OPENED2 + else if(emagged || (hacker && !hacker.hacked_apcs_hidden) || failure_timer) + update_state |= UPDATE_BLUESCREEN + else if(wiresexposed) + update_state |= UPDATE_WIREEXP + if(update_state <= 1) + update_state |= UPDATE_ALLGOOD + + if(operating) + update_overlay |= APC_UPOVERLAY_OPERATING + + if(update_state & UPDATE_ALLGOOD) + if(locked) + update_overlay |= APC_UPOVERLAY_LOCKED + + if(!charging) + update_overlay |= APC_UPOVERLAY_CHARGEING0 + else if(charging == 1) + update_overlay |= APC_UPOVERLAY_CHARGEING1 + else if(charging == 2) + update_overlay |= APC_UPOVERLAY_CHARGEING2 + + + update_overlay_chan["Equipment"] = equipment + update_overlay_chan["Lighting"] = lighting + update_overlay_chan["Enviroment"] = environ + + + var/results = 0 + if(last_update_state == update_state && last_update_overlay == update_overlay && last_update_overlay_chan == update_overlay_chan) + return 0 + if(last_update_state != update_state) + results += 1 + if(last_update_overlay != update_overlay || last_update_overlay_chan != update_overlay_chan) + results += 2 + return results + +// Used in process so it doesn't update the icon too much +/obj/machinery/power/apc/proc/queue_icon_update() + + if(!updating_icon) + updating_icon = 1 + // Start the update + spawn(APC_UPDATE_ICON_COOLDOWN) + update_icon() + updating_icon = 0 + +//attack with an item - open/close cover, insert cell, or (un)lock interface + +/obj/machinery/power/apc/attackby(obj/item/W, mob/user) + + if (istype(user, /mob/living/silicon) && get_dist(src,user)>1) + return src.attack_hand(user) + src.add_fingerprint(user) + if(isCrowbar(W) && opened) + if (has_electronics==1) + if (terminal) + to_chat(user, "Disconnect wires first.") + return + playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) + to_chat(user, "You are trying to remove the power control board...")//lpeters - fixed grammar issues + + if(do_after(user, 50, src)) + if (has_electronics==1) + has_electronics = 0 + if ((stat & BROKEN)) + user.visible_message(\ + "[user.name] has broken the power control board inside [src.name]!",\ + "You broke the charred power control board and remove the remains.", + "You hear a crack!") + //ticker.mode:apcs-- //XSI said no and I agreed. -rastaf0 + else + user.visible_message(\ + "[user.name] has removed the power control board from [src.name]!",\ + "You remove the power control board.") + new /obj/item/weapon/module/power_control(loc) + else if (opened!=2) //cover isn't removed + opened = 0 + update_icon() + else if(isCrowbar(W) && !((stat & BROKEN) || (hacker && !hacker.hacked_apcs_hidden)) ) + if(coverlocked && !(stat & MAINT)) + to_chat(user, "The cover is locked and cannot be opened.") + return + else + opened = 1 + update_icon() + else if (istype(W, /obj/item/weapon/cell) && opened) // trying to put a cell inside + if(cell) + to_chat(user, "There is a power cell already installed.") + return + if (stat & MAINT) + to_chat(user, "There is no connector for your power cell.") + return + if(W.w_class != ITEM_SIZE_NORMAL) + to_chat(user, "\The [W] is too [W.w_class < ITEM_SIZE_NORMAL? "small" : "large"] to fit here.") + return + + user.drop_item() + W.forceMove(src) + cell = W + user.visible_message(\ + "[user.name] has inserted the power cell to [src.name]!",\ + "You insert the power cell.") + chargecount = 0 + update_icon() + else if(isScrewdriver(W)) // haxing + if(opened) + if (cell) + to_chat(user, "Close the APC first.")//Less hints more mystery! + + return + else + if (has_electronics==1 && terminal) + has_electronics = 2 + stat &= ~MAINT + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You screw the circuit electronics into place.") + else if (has_electronics==2) + has_electronics = 1 + stat |= MAINT + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You unfasten the electronics.") + else /* has_electronics==0 */ + to_chat(user, "There is nothing to secure.") + return + update_icon() + else + wiresexposed = !wiresexposed + to_chat(user, "The wires have been [wiresexposed ? "exposed" : "unexposed"]") + update_icon() + + else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) // trying to unlock the interface with an ID card + if(emagged) + to_chat(user, "The interface is broken.") + else if(opened) + to_chat(user, "You must close the cover to swipe an ID card.") + else if(wiresexposed) + to_chat(user, "You must close the panel") + else if(stat & (BROKEN|MAINT)) + to_chat(user, "Nothing happens.") + else if(hacker && !hacker.hacked_apcs_hidden) + to_chat(user, "Access denied.") + else + if(src.allowed(usr) && !isWireCut(APC_WIRE_IDSCAN)) + locked = !locked + to_chat(user, "You [ locked ? "lock" : "unlock"] the APC interface.") + update_icon() + else + to_chat(user, "Access denied.") + else if (istype(W, /obj/item/stack/cable_coil) && !terminal && opened && has_electronics!=2) + var/turf/T = loc + if(istype(T) && !T.is_plating()) + to_chat(user, "You must remove the floor plating in front of the APC first.") + return + var/obj/item/stack/cable_coil/C = W + if(C.get_amount() < 10) + to_chat(user, "You need ten lengths of cable for APC.") + return + user.visible_message("[user.name] adds cables to the APC frame.", \ + "You start adding cables to the APC frame...") + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + if(do_after(user, 20, src)) + if (C.amount >= 10 && !terminal && opened && has_electronics != 2) + var/obj/structure/cable/N = T.get_cable_node() + if (prob(50) && electrocute_mob(usr, N, N)) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, src) + s.start() + if(user.stunned) + return + C.use(10) + user.visible_message(\ + "[user.name] has added cables to the APC frame!",\ + "You add cables to the APC frame.") + make_terminal() + terminal.connect_to_network() + else if(isWirecutter(W) && terminal && opened && has_electronics!=2) + var/turf/T = loc + if(istype(T) && !T.is_plating()) + to_chat(user, "You must remove the floor plating in front of the APC first.") + return + user.visible_message("[user.name] dismantles the power terminal from [src].", \ + "You begin to cut the cables...") + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + if(do_after(user, 50, src)) + if(terminal && opened && has_electronics!=2) + if (prob(50) && electrocute_mob(usr, terminal.powernet, terminal)) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, src) + s.start() + if(usr.stunned) + return + new /obj/item/stack/cable_coil(loc,10) + to_chat(user, "You cut the cables and dismantle the power terminal.") + qdel(terminal) + else if (istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics==0 && !((stat & BROKEN))) + user.visible_message("[user.name] inserts the power control board into [src].", \ + "You start to insert the power control board into the frame...") + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + if(do_after(user, 10, src)) + if(has_electronics==0) + has_electronics = 1 + reboot() //completely new electronics + to_chat(user, "You place the power control board inside the frame.") + qdel(W) + else if (istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics==0 && ((stat & BROKEN))) + to_chat(user, "You cannot put the board inside, the frame is damaged.") + return + else if(isWelder(W) && opened && has_electronics==0 && !terminal) + var/obj/item/weapon/weldingtool/WT = W + if (WT.get_fuel() < 3) + to_chat(user, "You need more welding fuel to complete this task.") + return + user.visible_message("[user.name] welds [src].", \ + "You start welding the APC frame...", \ + "You hear welding.") + playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) + if(do_after(user, 50, src)) + if(!src || !WT.remove_fuel(3, user)) return + if (emagged || (stat & BROKEN) || opened==2) + new /obj/item/stack/material/steel(loc) + user.visible_message(\ + "[src] has been cut apart by [user.name] with the weldingtool.",\ + "You disassembled the broken APC frame.",\ + "You hear welding.") + else + new /obj/item/frame/apc(loc) + user.visible_message(\ + "[src] has been cut from the wall by [user.name] with the weldingtool.",\ + "You cut the APC frame from the wall.",\ + "You hear welding.") + qdel(src) + return + else if (istype(W, /obj/item/frame/apc) && opened && emagged) + emagged = 0 + if (opened==2) + opened = 1 + user.visible_message(\ + "[user.name] has replaced the damaged APC frontal panel with a new one.",\ + "You replace the damaged APC frontal panel with a new one.") + qdel(W) + update_icon() + else if (istype(W, /obj/item/frame/apc) && opened && ((stat & BROKEN) || (hacker && !hacker.hacked_apcs_hidden))) + if (has_electronics) + to_chat(user, "You cannot repair this APC until you remove the electronics still inside.") + return + user.visible_message("[user.name] replaces the damaged APC frame with a new one.",\ + "You begin to replace the damaged APC frame...") + if(do_after(user, 50, src)) + user.visible_message(\ + "[user.name] has replaced the damaged APC frame with new one.",\ + "You replace the damaged APC frame with new one.") + qdel(W) + stat &= ~BROKEN + // Malf AI, removes the APC from AI's hacked APCs list. + if(hacker && hacker.hacked_apcs && (src in hacker.hacked_apcs)) + hacker.hacked_apcs -= src + hacker = null + if (opened==2) + opened = 1 + update_icon() + else + if (((stat & BROKEN) || (hacker && !hacker.hacked_apcs_hidden)) \ + && !opened \ + && W.force >= 5 \ + && W.w_class >= 3.0 \ + && prob(20) ) + opened = 2 + user.visible_message("The APC cover was knocked down with the [W.name] by [user.name]!", \ + "You knock down the APC cover with your [W.name]!", \ + "You hear a bang") + update_icon() + else + if (istype(user, /mob/living/silicon)) + return src.attack_hand(user) + if (!opened && wiresexposed && isMultitool(W) || isWirecutter(W) || istype(W, /obj/item/device/assembly/signaler)) + return src.attack_hand(user) + user.visible_message("The [src.name] has been hit with the [W.name] by [user.name]!", \ + "You hit the [src.name] with your [W.name]!", \ + "You hear a bang") + +// attack with hand - remove cell (if cover open) or interact with the APC + +/obj/machinery/power/apc/emag_act(var/remaining_charges, var/mob/user) + if (!(emagged || (hacker && !hacker.hacked_apcs_hidden))) // trying to unlock with an emag card + if(opened) + to_chat(user, "You must close the cover to swipe an ID card.") + else if(wiresexposed) + to_chat(user, "You must close the panel first") + else if(stat & (BROKEN|MAINT)) + to_chat(user, "Nothing happens.") + else + flick("apc-spark", src) + if (do_after(user,6,src)) + if(prob(50)) + emagged = 1 + locked = 0 + to_chat(user, "You emag the APC interface.") + update_icon() + else + to_chat(user, "You fail to [ locked ? "unlock" : "lock"] the APC interface.") + return 1 + +/obj/machinery/power/apc/attack_hand(mob/user) +// if (!can_use(user)) This already gets called in interact() and in topic() +// return + if(!user) + return + src.add_fingerprint(user) + + //Human mob special interaction goes here. + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + + if(H.species.can_shred(H)) + user.visible_message("\The [user] slashes at \the [src]!", "You slash at \the [src]!") + playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) + + var/allcut = wires.IsAllCut() + + if(beenhit >= pick(3, 4) && wiresexposed != 1) + wiresexposed = 1 + src.update_icon() + src.visible_message("\The The [src]'s cover flies open, exposing the wires!") + + else if(wiresexposed == 1 && allcut == 0) + wires.CutAll() + src.update_icon() + src.visible_message("\The [src]'s wires are shredded!") + else + beenhit += 1 + return + + if(usr == user && opened && (!issilicon(user))) + if(cell) + user.put_in_hands(cell) + cell.add_fingerprint(user) + cell.update_icon() + + src.cell = null + user.visible_message("[user.name] removes the power cell from [src.name]!",\ + "You remove the power cell.") +// to_chat(user, "You remove the power cell.") + charging = 0 + src.update_icon() + return + if(stat & (BROKEN|MAINT)) + return + // do APC interaction + src.interact(user) + +/obj/machinery/power/apc/interact(mob/user) + if(!user) + return + + if(wiresexposed && !istype(user, /mob/living/silicon/ai)) + wires.Interact(user) + + return ui_interact(user) + + +/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(!user) + return + + var/list/data = list( + "pChan_Off" = POWERCHAN_OFF, + "pChan_Off_T" = POWERCHAN_OFF_TEMP, + "pChan_Off_A" = POWERCHAN_OFF_AUTO, + "pChan_On" = POWERCHAN_ON, + "pChan_On_A" = POWERCHAN_ON_AUTO, + "locked" = (locked && !emagged) ? 1 : 0, + "isOperating" = operating, + "externalPower" = main_status, + "powerCellStatus" = cell ? cell.percent() : null, + "chargeMode" = chargemode, + "chargingStatus" = charging, + "totalLoad" = round(lastused_total), + "totalCharging" = round(lastused_charging), + "coverLocked" = coverlocked, + "failTime" = failure_timer * 2, + "siliconUser" = istype(user, /mob/living/silicon), + "powerChannels" = list( + list( + "title" = "Equipment", + "powerLoad" = lastused_equip, + "status" = equipment, + "topicParams" = list( + "auto" = list("eqp" = 2), + "on" = list("eqp" = 1), + "off" = list("eqp" = 0) + ) + ), + list( + "title" = "Lighting", + "powerLoad" = round(lastused_light), + "status" = lighting, + "topicParams" = list( + "auto" = list("lgt" = 2), + "on" = list("lgt" = 1), + "off" = list("lgt" = 0) + ) + ), + list( + "title" = "Environment", + "powerLoad" = round(lastused_environ), + "status" = environ, + "topicParams" = list( + "auto" = list("env" = 2), + "on" = list("env" = 1), + "off" = list("env" = 0) + ) + ) + ) + ) + + // update the ui if it exists, returns null if no ui is passed/found + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 520, data["siliconUser"] ? 465 : 440) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(1) + +/obj/machinery/power/apc/proc/report() + return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])" + +/obj/machinery/power/apc/proc/update() + if(operating && !shorted && !failure_timer) + + //prevent unnecessary updates to emergency lighting + var/new_power_light = (lighting >= POWERCHAN_ON) + if(area.power_light != new_power_light) + area.power_light = new_power_light + area.set_emergency_lighting(lighting == POWERCHAN_OFF_AUTO) //if lights go auto-off, emergency lights go on + + area.power_equip = (equipment >= POWERCHAN_ON) + area.power_environ = (environ >= POWERCHAN_ON) + else + area.power_light = 0 + area.power_equip = 0 + area.power_environ = 0 + + area.power_change() + +/obj/machinery/power/apc/proc/isWireCut(var/wireIndex) + return wires.IsIndexCut(wireIndex) + + +/obj/machinery/power/apc/proc/can_use(mob/user as mob, var/loud = 0) //used by attack_hand() and Topic() + if (user.stat) + to_chat(user, "You must be conscious to use [src]!") + return 0 + if(!user.client) + return 0 + if(inoperable()) + return 0 + if(!user.IsAdvancedToolUser()) + return 0 + if(user.restrained()) + to_chat(user, "You must have free hands to use [src].") + return 0 + if(user.lying) + to_chat(user, "You must stand to use [src]!") + return 0 + autoflag = 5 + if (istype(user, /mob/living/silicon)) + var/permit = 0 // Malfunction variable. If AI hacks APC it can control it even without AI control wire. + var/mob/living/silicon/ai/AI = user + var/mob/living/silicon/robot/robot = user + if(hacker && !hacker.hacked_apcs_hidden) + if(hacker == AI) + permit = 1 + else if(istype(robot) && robot.connected_ai && robot.connected_ai == hacker) // Cyborgs can use APCs hacked by their AI + permit = 1 + + if(aidisabled && !permit) + if(!loud) + to_chat(user, "\The [src] have AI control disabled!") + return 0 + else + if (!in_range(src, user) || !istype(src.loc, /turf)) + return 0 + var/mob/living/carbon/human/H = user + if (istype(H) && prob(H.getBrainLoss())) + to_chat(user, "You momentarily forget how to use [src].") + return 0 + return 1 + +/obj/machinery/power/apc/Topic(href, href_list) + if(..()) + return 1 + + if(!can_use(usr, 1)) + return 1 + + if(!istype(usr, /mob/living/silicon) && (locked && !emagged)) + // Shouldn't happen, this is here to prevent href exploits + to_chat(usr, "You must unlock the panel to use this!") + return 1 + + if (href_list["lock"]) + coverlocked = !coverlocked + + else if( href_list["reboot"] ) + failure_timer = 0 + update_icon() + update() + + else if (href_list["breaker"]) + toggle_breaker() + + else if (href_list["cmode"]) + chargemode = !chargemode + if(!chargemode) + charging = 0 + update_icon() + + else if (href_list["eqp"]) + var/val = text2num(href_list["eqp"]) + equipment = setsubsystem(val) + update_icon() + update() + + else if (href_list["lgt"]) + var/val = text2num(href_list["lgt"]) + lighting = setsubsystem(val) + update_icon() + update() + + else if (href_list["env"]) + var/val = text2num(href_list["env"]) + environ = setsubsystem(val) + update_icon() + update() + + else if (href_list["overload"]) + if(istype(usr, /mob/living/silicon)) + src.overload_lighting() + + else if (href_list["toggleaccess"]) + if(istype(usr, /mob/living/silicon)) + if(emagged || (stat & (BROKEN|MAINT))) + to_chat(usr, "The APC does not respond to the command.") + else + locked = !locked + update_icon() + + return 0 + +/obj/machinery/power/apc/proc/toggle_breaker() + operating = !operating + src.update() + update_icon() + + +/obj/machinery/power/apc/surplus() + if(terminal) + return terminal.surplus() + else + return 0 + +/obj/machinery/power/apc/proc/last_surplus() + if(terminal && terminal.powernet) + return terminal.powernet.last_surplus() + else + return 0 + +//Returns 1 if the APC should attempt to charge +/obj/machinery/power/apc/proc/attempt_charging() + return (chargemode && charging == 1 && operating) + + +/obj/machinery/power/apc/draw_power(var/amount) + if(terminal && terminal.powernet) + return terminal.powernet.draw_power(amount) + return 0 + +/obj/machinery/power/apc/avail() + if(terminal) + return terminal.avail() + else + return 0 + +/obj/machinery/power/apc/Process() + + if(stat & (BROKEN|MAINT)) + return + if(!area.requires_power) + return + if(failure_timer) + update() + queue_icon_update() + failure_timer-- + force_update = 1 + return + + lastused_light = area.usage(LIGHT) + lastused_equip = area.usage(EQUIP) + lastused_environ = area.usage(ENVIRON) + area.clear_usage() + + lastused_total = lastused_light + lastused_equip + lastused_environ + + //store states to update icon if any change + var/last_lt = lighting + var/last_eq = equipment + var/last_en = environ + var/last_ch = charging + + var/excess = surplus() + + if(!src.avail()) + main_status = 0 + else if(excess < 0) + main_status = 1 + else + main_status = 2 + + if(debug) + log_debug("Status: [main_status] - Excess: [excess] - Last Equip: [lastused_equip] - Last Light: [lastused_light] - Longterm: [longtermpower]") + + if(cell && !shorted) + // draw power from cell as before to power the area + var/cellused = min(cell.charge, CELLRATE * lastused_total) // clamp deduction to a max, amount left in cell + cell.use(cellused) + + if(excess > lastused_total) // if power excess recharge the cell + // by the same amount just used + var/draw = draw_power(cellused/CELLRATE) // draw the power needed to charge this cell + cell.give(draw * CELLRATE) + else // no excess, and not enough per-apc + if( (cell.charge/CELLRATE + excess) >= lastused_total) // can we draw enough from cell+grid to cover last usage? + var/draw = draw_power(excess) + cell.charge = min(cell.maxcharge, cell.charge + CELLRATE * draw) //recharge with what we can + charging = 0 + else // not enough power available to run the last tick! + charging = 0 + chargecount = 0 + // This turns everything off in the case that there is still a charge left on the battery, just not enough to run the room. + equipment = autoset(equipment, 0) + lighting = autoset(lighting, 0) + environ = autoset(environ, 0) + autoflag = 0 + + + // Set channels depending on how much charge we have left + update_channels() + + // now trickle-charge the cell + lastused_charging = 0 // Clear the variable for new use. + if(src.attempt_charging()) + if(excess > 0) // check to make sure we have enough to charge + // Max charge is capped to % per second constant + var/ch = min(excess*CELLRATE, cell.maxcharge*chargelevel) + + ch = draw_power(ch/CELLRATE) // Removes the power we're taking from the grid + cell.give(ch*CELLRATE) // actually recharge the cell + lastused_charging = ch + lastused_total += ch // Sensors need this to stop reporting APC charging as "Other" load + else + charging = 0 // stop charging + chargecount = 0 + + // show cell as fully charged if so + if(cell.charge >= cell.maxcharge) + cell.charge = cell.maxcharge + charging = 2 + + if(chargemode) + if(!charging) + if(excess > cell.maxcharge*chargelevel) + chargecount++ + else + chargecount = 0 + + if(chargecount >= 10) + + chargecount = 0 + charging = 1 + + else // chargemode off + charging = 0 + chargecount = 0 + + else // no cell, switch everything off + charging = 0 + chargecount = 0 + equipment = autoset(equipment, 0) + lighting = autoset(lighting, 0) + environ = autoset(environ, 0) + power_alarm.triggerAlarm(loc, src) + autoflag = 0 + + // update icon & area power if anything changed + if(last_lt != lighting || last_eq != equipment || last_en != environ || force_update) + force_update = 0 + queue_icon_update() + update() + else if (last_ch != charging) + queue_icon_update() + +/obj/machinery/power/apc/proc/update_channels() + // Allow the APC to operate as normal if the cell can charge + if(charging && longtermpower < 10) + longtermpower += 1 + else if(longtermpower > -10) + longtermpower -= 2 + + if((cell.percent() > AUTO_THRESHOLD_LIGHTING) || longtermpower > 0) // Put most likely at the top so we don't check it last, effeciency 101 + if(autoflag != 3) + equipment = autoset(equipment, 1) + lighting = autoset(lighting, 1) + environ = autoset(environ, 1) + autoflag = 3 + power_alarm.clearAlarm(loc, src) + else if((cell.percent() <= AUTO_THRESHOLD_LIGHTING) && (cell.percent() > AUTO_THRESHOLD_EQUIPMENT) && longtermpower < 0) // <50%, turn off lighting + if(autoflag != 2) + equipment = autoset(equipment, 1) + lighting = autoset(lighting, 2) + environ = autoset(environ, 1) + power_alarm.triggerAlarm(loc, src) + autoflag = 2 + else if(cell.percent() <= AUTO_THRESHOLD_EQUIPMENT) // <25%, turn off lighting & equipment + if((autoflag > 1 && longtermpower < 0) || (autoflag > 1 && longtermpower >= 0)) + equipment = autoset(equipment, 2) + lighting = autoset(lighting, 2) + environ = autoset(environ, 1) + power_alarm.triggerAlarm(loc, src) + autoflag = 1 + else // zero charge, turn all off + if(autoflag != 0) + equipment = autoset(equipment, 0) + lighting = autoset(lighting, 0) + environ = autoset(environ, 0) + power_alarm.triggerAlarm(loc, src) + autoflag = 0 + +// val 0=off, 1=off(auto) 2=on 3=on(auto) +// on 0=off, 1=on, 2=autooff +// defines a state machine, returns the new state +obj/machinery/power/apc/proc/autoset(var/cur_state, var/on) + switch(cur_state) + if(POWERCHAN_OFF) //autoset will never turn on a channel set to off + if(POWERCHAN_OFF_TEMP) + if(on == 1 || on == 2) + return POWERCHAN_ON + if(POWERCHAN_OFF_AUTO) + if(on == 1) + return POWERCHAN_ON_AUTO + if(POWERCHAN_ON) + if(on == 0) + return POWERCHAN_OFF_TEMP + if(POWERCHAN_ON_AUTO) + if(on == 0 || on == 2) + return POWERCHAN_OFF_AUTO + + return cur_state //leave unchanged + + +// damage and destruction acts +/obj/machinery/power/apc/emp_act(severity) + if(emp_hardened) + return + // Fail for 8-12 minutes (divided by severity) + // Division by 2 is required, because machinery ticks are every two seconds. Without it we would fail for 16-24 minutes. + if(is_critical) + // Critical APCs are considered EMP shielded and will be offline only for about half minute. Prevents AIs being one-shot disabled by EMP strike. + // Critical APCs are also more resilient to cell corruption/power drain. + energy_fail(rand(240, 360) / severity / CRITICAL_APC_EMP_PROTECTION) + if(cell) + cell.emp_act(severity+2) + else + // Regular APCs fail for normal time. + energy_fail(rand(240, 360) / severity) + if(cell) + cell.emp_act(severity+1) + + update_icon() + ..() + +/obj/machinery/power/apc/ex_act(severity) + switch(severity) + if(1.0) + if (cell) + cell.ex_act(1.0) // more lags woohoo + qdel(src) + return + if(2.0) + if (prob(50)) + set_broken() + if (cell && prob(50)) + cell.ex_act(2.0) + if(3.0) + if (prob(25)) + set_broken() + if (cell && prob(25)) + cell.ex_act(3.0) + return + +/obj/machinery/power/apc/disconnect_terminal(var/obj/machinery/power/terminal/term) + if(terminal) + terminal.master = null + terminal = null + +/obj/machinery/power/apc/proc/set_broken() + // Aesthetically much better! + src.visible_message("[src]'s screen flickers with warnings briefly!") + power_alarm.triggerAlarm(loc, src) + spawn(rand(2,5)) + src.visible_message("[src]'s screen suddenly explodes in rain of sparks and small debris!") + stat |= BROKEN + operating = 0 + update_icon() + update() + +/obj/machinery/power/apc/proc/reboot() + //reset various counters so that process() will start fresh + charging = initial(charging) + chargecount = initial(chargecount) + autoflag = initial(autoflag) + longtermpower = initial(longtermpower) + failure_timer = initial(failure_timer) + + //start with main breaker off, chargemode in the default state and all channels on auto upon reboot + operating = 0 + chargemode = initial(chargemode) + power_alarm.clearAlarm(loc, src) + + lighting = POWERCHAN_ON_AUTO + equipment = POWERCHAN_ON_AUTO + environ = POWERCHAN_ON_AUTO + + update_icon() + update() + +// overload the lights in this APC area +/obj/machinery/power/apc/proc/overload_lighting(var/chance = 100) + if(/* !get_connection() || */ !operating || shorted) + return + if( cell && cell.charge>=20) + cell.use(20); + spawn(0) + for(var/obj/machinery/light/L in area) + if(prob(chance)) + L.on = 1 + L.broken() + sleep(1) + +/obj/machinery/power/apc/proc/setsubsystem(val) + if(cell && cell.charge > 0) + switch(val) + if(2) return POWERCHAN_ON_AUTO + if(1) return POWERCHAN_ON + else return POWERCHAN_OFF + else + switch(val) + if(2) return POWERCHAN_OFF_AUTO + if(1) return POWERCHAN_OFF_TEMP + else return POWERCHAN_OFF + + + +// Malfunction: Transfers APC under AI's control +/obj/machinery/power/apc/proc/ai_hack(var/mob/living/silicon/ai/A = null) + if(!A || !A.hacked_apcs || hacker || aidisabled || A.stat == DEAD) + return 0 + src.hacker = A + A.hacked_apcs += src + locked = 1 + update_icon() + return 1 + +/obj/item/weapon/module/power_control + name = "power control module" + desc = "Heavy-duty switching circuits for power control." + icon = 'icons/obj/module.dmi' + icon_state = "power_mod" + item_state = "electronic" + matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) + w_class = ITEM_SIZE_SMALL + obj_flags = OBJ_FLAG_CONDUCTIBLE + +/obj/machinery/power/apc/malf_upgrade(var/mob/living/silicon/ai/user) + ..() + malf_upgraded = 1 + emp_hardened = 1 + to_chat(user, "\The [src] has been upgraded. It is now protected against EM pulses.") + return 1 + + + +#undef APC_UPDATE_ICON_COOLDOWN \ No newline at end of file diff --git a/code/modules/power/batteryrack.dm b/code/modules/power/batteryrack.dm new file mode 100644 index 00000000..3a11b44c --- /dev/null +++ b/code/modules/power/batteryrack.dm @@ -0,0 +1,308 @@ +// Cell rack PSU, similar to SMES, but uses power cells to store power. +// Lacks detailed control of input/output values, and has generally much worse capacity. +#define PSU_OFFLINE 0 +#define PSU_OUTPUT 1 +#define PSU_INPUT 2 +#define PSU_AUTO 3 + +#define PSU_MAXCELLS 9 // Capped to 9 cells due to sprite limitation + +/obj/machinery/power/smes/batteryrack + name = "power cell rack PSU" + desc = "A rack of power cells working as a PSU." + icon = 'icons/obj/cellrack.dmi' + icon_state = "rack" + capacity = 0 + charge = 0 + should_be_mapped = 1 + + var/max_transfer_rate = 0 // Maximal input/output rate. Determined by used capacitors when building the device. + var/mode = PSU_OFFLINE // Current inputting/outputting mode + var/list/internal_cells = list() // Cells stored in this PSU + var/max_cells = 9 // Maximal amount of stored cells at once. Capped at 9. + var/previous_charge = 0 // Charge previous tick. + var/equalise = 0 // If true try to equalise charge between cells + var/icon_update = 0 // Timer in ticks for icon update. + var/ui_tick = 0 + + +/obj/machinery/power/smes/batteryrack/New() + ..() + add_parts() + RefreshParts() + +/obj/machinery/power/smes/batteryrack/proc/add_parts() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/batteryrack + component_parts += new /obj/item/weapon/stock_parts/capacitor/ // Capacitors: Maximal I/O + component_parts += new /obj/item/weapon/stock_parts/capacitor/ + component_parts += new /obj/item/weapon/stock_parts/capacitor/ + component_parts += new /obj/item/weapon/stock_parts/matter_bin/ // Matter Bin: Max. amount of cells. + component_parts += new /obj/item/weapon/stock_parts/matter_bin/ + component_parts += new /obj/item/weapon/stock_parts/matter_bin/ + +/obj/machinery/power/smes/batteryrack/RefreshParts() + var/capacitor_efficiency = 0 + var/maxcells = 0 + for(var/obj/item/weapon/stock_parts/capacitor/CP in component_parts) + capacitor_efficiency += CP.rating + + for(var/obj/item/weapon/stock_parts/matter_bin/MB in component_parts) + maxcells += MB.rating * 3 + + max_transfer_rate = 10000 * capacitor_efficiency // 30kw - 90kw depending on used capacitors. + max_cells = min(PSU_MAXCELLS, maxcells) + input_level = max_transfer_rate + output_level = max_transfer_rate + +/obj/machinery/power/smes/batteryrack/Destroy() + for(var/obj/item/weapon/cell/C in internal_cells) + qdel(C) + internal_cells = null + return ..() + +/obj/machinery/power/smes/batteryrack/update_icon() + overlays.Cut() + icon_update = 0 + + var/cellcount = 0 + var/charge_level = between(0, round(Percentage() / 12), 7) + + + overlays += "charge[charge_level]" + + for(var/obj/item/weapon/cell/C in internal_cells) + cellcount++ + overlays += "cell[cellcount]" + if(C.fully_charged()) + overlays += "cell[cellcount]f" + else if(!C.charge) + overlays += "cell[cellcount]e" + +// Recalculate maxcharge and similar variables. +/obj/machinery/power/smes/batteryrack/proc/update_maxcharge() + var/newmaxcharge = 0 + for(var/obj/item/weapon/cell/C in internal_cells) + newmaxcharge += C.maxcharge + + capacity = newmaxcharge + charge = between(0, charge, newmaxcharge) + + +// Sets input/output depending on our "mode" var. +/obj/machinery/power/smes/batteryrack/proc/update_io(var/newmode) + mode = newmode + switch(mode) + if(PSU_OFFLINE) + input_attempt = 0 + output_attempt = 0 + if(PSU_INPUT) + input_attempt = 1 + output_attempt = 0 + if(PSU_OUTPUT) + input_attempt = 0 + output_attempt = 1 + if(PSU_AUTO) + input_attempt = 1 + output_attempt = 1 + +// Store charge in the power cells, instead of using the charge var. Amount is in joules. +/obj/machinery/power/smes/batteryrack/add_charge(var/amount) + amount *= CELLRATE // Convert to CELLRATE first. + if(equalise) + // Now try to get least charged cell and use the power from it. + var/obj/item/weapon/cell/CL = get_least_charged_cell() + amount -= CL.give(amount) + if(!amount) + return + // We're still here, so it means the least charged cell was full OR we don't care about equalising the charge. Give power to other cells instead. + for(var/obj/item/weapon/cell/C in internal_cells) + amount -= C.give(amount) + // No more power to input so return. + if(!amount) + return + + +/obj/machinery/power/smes/batteryrack/remove_charge(var/amount) + amount *= CELLRATE // Convert to CELLRATE first. + if(equalise) + // Now try to get most charged cell and use the power from it. + var/obj/item/weapon/cell/CL = get_most_charged_cell() + amount -= CL.use(amount) + if(!amount) + return + // We're still here, so it means the most charged cell didn't have enough power OR we don't care about equalising the charge. Use power from other cells instead. + for(var/obj/item/weapon/cell/C in internal_cells) + amount -= C.use(amount) + // No more power to output so return. + if(!amount) + return + +// Helper procs to get most/least charged cells. +/obj/machinery/power/smes/batteryrack/proc/get_most_charged_cell() + var/obj/item/weapon/cell/CL = null + for(var/obj/item/weapon/cell/C in internal_cells) + if(CL == null) + CL = C + else if(CL.percent() < C.percent()) + CL = C + return CL +/obj/machinery/power/smes/batteryrack/proc/get_least_charged_cell() + var/obj/item/weapon/cell/CL = null + for(var/obj/item/weapon/cell/C in internal_cells) + if(CL == null) + CL = C + else if(CL.percent() > C.percent()) + CL = C + return CL + +/obj/machinery/power/smes/batteryrack/proc/insert_cell(var/obj/item/weapon/cell/C, var/mob/user) + if(!istype(C)) + return 0 + + if(internal_cells.len >= max_cells) + return 0 + + internal_cells.Add(C) + if(user) + user.drop_from_inventory(C) + C.forceMove(src) + RefreshParts() + update_maxcharge() + update_icon() + return 1 + + +/obj/machinery/power/smes/batteryrack/Process() + charge = 0 + for(var/obj/item/weapon/cell/C in internal_cells) + charge += C.charge + + ..() + ui_tick = !ui_tick + icon_update++ + + // Don't update icon too much, prevents unnecessary processing. + if(icon_update >= 10) + update_icon() + // Try to balance charge between stored cells. Capped at max_transfer_rate per tick. + // Take power from most charged cell, and give it to least charged cell. + if(equalise) + var/obj/item/weapon/cell/least = get_least_charged_cell() + var/obj/item/weapon/cell/most = get_most_charged_cell() + // Don't bother equalising charge between two same cells. Also ensure we don't get NULLs or wrong types. Don't bother equalising when difference between charges is tiny. + if(least == most || !istype(least) || !istype(most) || least.percent() == most.percent()) + return + var/percentdiff = (most.percent() - least.percent()) / 2 // Transfer only 50% of power. The reason is that it could lead to situations where least and most charged cells would "swap places" (45->50% and 50%->45%) + var/celldiff + // Take amount of power to transfer from the cell with smaller maxcharge + if(most.maxcharge > least.maxcharge) + celldiff = (least.maxcharge / 100) * percentdiff + else + celldiff = (most.maxcharge / 100) * percentdiff + celldiff = between(0, celldiff, max_transfer_rate * CELLRATE) + // Ensure we don't transfer more energy than the most charged cell has, and that the least charged cell can input. + celldiff = min(min(celldiff, most.charge), least.maxcharge - least.charge) + least.give(most.use(celldiff)) + +/obj/machinery/power/smes/batteryrack/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + + data["mode"] = mode + data["transfer_max"] = max_transfer_rate + data["output_load"] = round(output_used) + data["input_load"] = round(input_available) + data["equalise"] = equalise + data["blink_tick"] = ui_tick + data["cells_max"] = max_cells + data["cells_cur"] = internal_cells.len + var/list/cells = list() + var/cell_index = 0 + for(var/obj/item/weapon/cell/C in internal_cells) + var/list/cell[0] + cell["slot"] = cell_index + 1 + cell["used"] = 1 + cell["percentage"] = round(C.percent(), 0.01) + cell["id"] = C.c_uid + cell_index++ + cells += list(cell) + while(cell_index < PSU_MAXCELLS) + var/list/cell[0] + cell["slot"] = cell_index + 1 + cell["used"] = 0 + cell_index++ + cells += list(cell) + data["cells_list"] = cells + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "psu.tmpl", "Cell Rack PSU", 500, 430) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/power/smes/batteryrack/dismantle() + for(var/obj/item/weapon/cell/C in internal_cells) + C.forceMove(get_turf(src)) + internal_cells -= C + return ..() + +/obj/machinery/power/smes/batteryrack/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(!..()) + return 0 + if(default_deconstruction_crowbar(user, W)) + return + if(default_part_replacement(user, W)) + return + if(istype(W, /obj/item/weapon/cell)) // ID Card, try to insert it. + if(insert_cell(W, user)) + to_chat(user, "You insert \the [W] into \the [src].") + else + to_chat(user, "\The [src] has no empty slot for \the [W]") + +/obj/machinery/power/smes/batteryrack/attack_hand(var/mob/user) + ui_interact(user) + +/obj/machinery/power/smes/batteryrack/inputting() + return + +/obj/machinery/power/smes/batteryrack/outputting() + return + +/obj/machinery/power/smes/batteryrack/Topic(href, href_list) + // ..() would respond to those topic calls, but we don't want to use them at all. + // Calls to these shouldn't occur anyway, due to usage of different nanoUI, but + // it's here in case someone decides to try hrefhacking/modified templates. + if(href_list["input"] || href_list["output"]) + return 1 + + if(..()) + return 1 + if( href_list["disable"] ) + update_io(0) + return 1 + else if( href_list["enable"] ) + update_io(between(1, text2num(href_list["enable"]), 3)) + return 1 + else if( href_list["equaliseon"] ) + equalise = 1 + return 1 + else if( href_list["equaliseoff"] ) + equalise = 0 + return 1 + else if( href_list["ejectcell"] ) + var/obj/item/weapon/cell/C + for(var/obj/item/weapon/cell/CL in internal_cells) + if(CL.c_uid == text2num(href_list["ejectcell"])) + C = CL + break + + if(!istype(C)) + return 1 + + C.forceMove(get_turf(src)) + internal_cells -= C + update_icon() + RefreshParts() + update_maxcharge() + return 1 \ No newline at end of file diff --git a/code/modules/power/breaker_box.dm b/code/modules/power/breaker_box.dm new file mode 100644 index 00000000..286326bd --- /dev/null +++ b/code/modules/power/breaker_box.dm @@ -0,0 +1,138 @@ +// Updated version of old powerswitch by Atlantis +// Has better texture, and is now considered electronic device +// AI has ability to toggle it in 5 seconds +// Humans need 30 seconds (AI is faster when it comes to complex electronics) +// Used for advanced grid control (read: Substations) + +/obj/machinery/power/breakerbox + name = "Breaker Box" + icon = 'icons/obj/power.dmi' + icon_state = "bbox_off" + //directwired = 0 + var/icon_state_on = "bbox_on" + var/icon_state_off = "bbox_off" + density = 1 + anchored = 1 + var/on = 0 + var/busy = 0 + var/directions = list(1,2,4,8,5,6,9,10) + var/RCon_tag = "NO_TAG" + var/update_locked = 0 + +/obj/machinery/power/breakerbox/Destroy() + ..() + for(var/datum/nano_module/rcon/R in world) + R.FindDevices() + +/obj/machinery/power/breakerbox/activated + icon_state = "bbox_on" + + // Enabled on server startup. Used in substations to keep them in bypass mode. +/obj/machinery/power/breakerbox/activated/Initialize() + set_state(1) + . = ..() + +/obj/machinery/power/breakerbox/examine(mob/user) + . = ..() + to_chat(user, "Large machine with heavy duty switching circuits used for advanced grid control") + if(on) + to_chat(user, "It seems to be online.") + else + to_chat(user, "It seems to be offline.") + +/obj/machinery/power/breakerbox/attack_ai(mob/user) + if(update_locked) + to_chat(user, "System locked. Please try again later.") + return + + if(busy) + to_chat(user, "System is busy. Please wait until current operation is finished before changing power settings.") + return + + busy = 1 + to_chat(user, "Updating power settings..") + if(do_after(user, 50, src)) + set_state(!on) + to_chat(user, "Update Completed. New setting:[on ? "on": "off"]") + update_locked = 1 + spawn(600) + update_locked = 0 + busy = 0 + + +/obj/machinery/power/breakerbox/attack_hand(mob/user) + if(update_locked) + to_chat(user, "System locked. Please try again later.") + return + + if(busy) + to_chat(user, "System is busy. Please wait until current operation is finished before changing power settings.") + return + + busy = 1 + for(var/mob/O in viewers(user)) + O.show_message(text("\The [user] started reprogramming \the [src]!"), 1) + + if(do_after(user, 50,src)) + set_state(!on) + user.visible_message(\ + "[user.name] [on ? "enabled" : "disabled"] the breaker box!",\ + "You [on ? "enabled" : "disabled"] the breaker box!") + update_locked = 1 + spawn(600) + update_locked = 0 + busy = 0 + +/obj/machinery/power/breakerbox/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(isMultitool(W)) + var/newtag = input(user, "Enter new RCON tag. Use \"NO_TAG\" to disable RCON or leave empty to cancel.", "SMES RCON system") as text + if(newtag) + RCon_tag = newtag + to_chat(user, "You changed the RCON tag to: [newtag]") + + + + + +/obj/machinery/power/breakerbox/proc/set_state(var/state) + on = state + if(on) + icon_state = icon_state_on + var/list/connection_dirs = list() + for(var/direction in directions) + for(var/obj/structure/cable/C in get_step(src,direction)) + if(C.d1 == turn(direction, 180) || C.d2 == turn(direction, 180)) + connection_dirs += direction + break + + for(var/direction in connection_dirs) + var/obj/structure/cable/C = new/obj/structure/cable(src.loc) + C.d1 = 0 + C.d2 = direction + C.icon_state = "[C.d1]-[C.d2]" + C.breaker_box = src + + var/datum/powernet/PN = new() + PN.add_cable(C) + + C.mergeConnectedNetworks(C.d2) + C.mergeConnectedNetworksOnTurf() + + if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions + C.mergeDiagonalsNetworks(C.d2) + + else + icon_state = icon_state_off + for(var/obj/structure/cable/C in src.loc) + qdel(C) + +// Used by RCON to toggle the breaker box. +/obj/machinery/power/breakerbox/proc/auto_toggle() + if(!update_locked) + set_state(!on) + update_locked = 1 + spawn(600) + update_locked = 0 + +/obj/machinery/power/breakerbox/Process() + return 1 \ No newline at end of file diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm new file mode 100644 index 00000000..be3e80a3 --- /dev/null +++ b/code/modules/power/cable.dm @@ -0,0 +1,825 @@ +/////////////////////////////// +//CABLE STRUCTURE +/////////////////////////////// + + +//////////////////////////////// +// Definitions +//////////////////////////////// + +/* Cable directions (d1 and d2) + + +> 9 1 5 +> \ | / +> 8 - 0 - 4 +> / | \ +> 10 2 6 + +If d1 = 0 and d2 = 0, there's no cable +If d1 = 0 and d2 = dir, it's a O-X cable, getting from the center of the tile to dir (knot cable) +If d1 = dir1 and d2 = dir2, it's a full X-X cable, getting from dir1 to dir2 +By design, d1 is the smallest direction and d2 is the highest +*/ + +var/list/possible_cable_coil_colours + +/obj/structure/cable + level = 1 + anchored =1 + var/datum/powernet/powernet + name = "power cable" + desc = "A flexible superconducting cable for heavy-duty power transfer." + icon = 'icons/obj/power_cond_white.dmi' + icon_state = "0-1" + var/d1 = 0 + var/d2 = 1 + + plane = ABOVE_TURF_PLANE + layer = EXPOSED_WIRE_LAYER + + color = COLOR_RED + var/obj/machinery/power/breakerbox/breaker_box + + +/obj/structure/cable/drain_power(var/drain_check, var/surge, var/amount = 0) + + if(drain_check) + return 1 + + var/datum/powernet/PN = get_powernet() + if(!PN) return 0 + + return PN.draw_power(amount) + +/obj/structure/cable/yellow + color = COLOR_YELLOW + +/obj/structure/cable/green + color = COLOR_LIME + +/obj/structure/cable/blue + color = COLOR_BLUE + +/obj/structure/cable/pink + color = COLOR_PINK + +/obj/structure/cable/orange + color = COLOR_ORANGE + +/obj/structure/cable/cyan + color = COLOR_CYAN + +/obj/structure/cable/white + color = COLOR_WHITE + +/obj/structure/cable/New() + ..() + + // ensure d1 & d2 reflect the icon_state for entering and exiting cable + + var/dash = findtext(icon_state, "-") + + d1 = text2num( copytext( icon_state, 1, dash ) ) + + d2 = text2num( copytext( icon_state, dash+1 ) ) + + var/turf/T = src.loc // hide if turf is not intact + if(level==1) hide(!T.is_plating()) + cable_list += src //add it to the global cable list + + +/obj/structure/cable/Destroy() // called when a cable is deleted + if(powernet) + cut_cable_from_powernet() // update the powernets + cable_list -= src // remove it from global cable list + . = ..() // then go ahead and delete the cable + + +// Ghost examining the cable -> tells him the power +/obj/structure/cable/attack_ghost(mob/user) + if(user.client && user.client.inquisitive_ghost) + user.examinate(src) + // following code taken from attackby (multitool) + if(powernet && (powernet.avail > 0)) + to_chat(user, "[get_wattage()] in power network.") + else + to_chat(user, "The cable is not powered.") + return + +/////////////////////////////////// +// General procedures +/////////////////////////////////// + +/obj/structure/cable/proc/get_wattage() + if(powernet.avail >= 1000000000) + return "[round(powernet.avail/1000000, 0.01)] MW" + if(powernet.avail >= 1000000) + return "[round(powernet.avail/1000, 0.01)] kW" + return "[round(powernet.avail)] W" + +//If underfloor, hide the cable +/obj/structure/cable/hide(var/i) + if(istype(loc, /turf)) + set_invisibility(i ? 101 : 0) + update_icon() + +/obj/structure/cable/hides_under_flooring() + return 1 + +/obj/structure/cable/update_icon() + icon_state = "[d1]-[d2]" + alpha = invisibility ? 127 : 255 + +// returns the powernet this cable belongs to +/obj/structure/cable/proc/get_powernet() //TODO: remove this as it is obsolete + return powernet + +//Telekinesis has no effect on a cable +/obj/structure/cable/attack_tk(mob/user) + return + +// Items usable on a cable : +// - Wirecutters : cut it duh ! +// - Cable coil : merge cables +// - Multitool : get the power currently passing through the cable +// + +/obj/structure/cable/attackby(obj/item/W, mob/user) + + var/turf/T = src.loc + if(!T.is_plating()) + return + + if(isWirecutter(W)) + if(d1 == UP || d2 == UP) + to_chat(user, "You must cut this cable from above.") + return + + if(breaker_box) + to_chat(user, "This cable is connected to nearby breaker box. Use breaker box to interact with it.") + return + + if (shock(user, 50)) + return + + if(src.d1) // 0-X cables are 1 unit, X-X cables are 2 units long + new/obj/item/stack/cable_coil(T, 2, color) + else + new/obj/item/stack/cable_coil(T, 1, color) + + for(var/mob/O in viewers(src, null)) + O.show_message("[user] cuts the cable.", 1) + + if(d1 == DOWN || d2 == DOWN) + var/turf/turf = GetBelow(src) + if(turf) + for(var/obj/structure/cable/c in turf) + if(c.d1 == UP || c.d2 == UP) + qdel(c) + + investigate_log("was cut by [key_name(usr, usr.client)] in [user.loc.loc]","wires") + + qdel(src) + return + + + else if(isCoil(W)) + var/obj/item/stack/cable_coil/coil = W + if (coil.get_amount() < 1) + to_chat(user, "Not enough cable") + return + coil.cable_join(src, user) + + else if(isMultitool(W)) + + if(powernet && (powernet.avail > 0)) // is it powered? + to_chat(user, "[get_wattage()] in power network.") + + else + to_chat(user, "The cable is not powered.") + + shock(user, 5, 0.2) + + else + if (W.obj_flags & OBJ_FLAG_CONDUCTIBLE) + shock(user, 50, 0.7) + + src.add_fingerprint(user) + +// shock the user with probability prb +/obj/structure/cable/proc/shock(mob/user, prb, var/siemens_coeff = 1.0) + if(!prob(prb)) + return 0 + if (electrocute_mob(user, powernet, src, siemens_coeff)) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, src) + s.start() + if(usr.stunned) + return 1 + return 0 + +//explosion handling +/obj/structure/cable/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + if(2.0) + if (prob(50)) + new/obj/item/stack/cable_coil(src.loc, src.d1 ? 2 : 1, color) + qdel(src) + + if(3.0) + if (prob(25)) + new/obj/item/stack/cable_coil(src.loc, src.d1 ? 2 : 1, color) + qdel(src) + +obj/structure/cable/proc/cableColor(var/colorC) + var/color_n = "#dd0000" + if(colorC) + color_n = colorC + color = color_n + +///////////////////////////////////////////////// +// Cable laying helpers +//////////////////////////////////////////////// + +//handles merging diagonally matching cables +//for info : direction^3 is flipping horizontally, direction^12 is flipping vertically +/obj/structure/cable/proc/mergeDiagonalsNetworks(var/direction) + + //search for and merge diagonally matching cables from the first direction component (north/south) + var/turf/T = get_step(src, direction&3)//go north/south + + for(var/obj/structure/cable/C in T) + + if(!C) + continue + + if(src == C) + continue + + if(C.d1 == (direction^3) || C.d2 == (direction^3)) //we've got a diagonally matching cable + if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables) + var/datum/powernet/newPN = new() + newPN.add_cable(C) + + if(powernet) //if we already have a powernet, then merge the two powernets + merge_powernets(powernet,C.powernet) + else + C.powernet.add_cable(src) //else, we simply connect to the matching cable powernet + + //the same from the second direction component (east/west) + T = get_step(src, direction&12)//go east/west + + for(var/obj/structure/cable/C in T) + + if(!C) + continue + + if(src == C) + continue + if(C.d1 == (direction^12) || C.d2 == (direction^12)) //we've got a diagonally matching cable + if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables) + var/datum/powernet/newPN = new() + newPN.add_cable(C) + + if(powernet) //if we already have a powernet, then merge the two powernets + merge_powernets(powernet,C.powernet) + else + C.powernet.add_cable(src) //else, we simply connect to the matching cable powernet + +// merge with the powernets of power objects in the given direction +/obj/structure/cable/proc/mergeConnectedNetworks(var/direction) + + var/fdir = direction ? GLOB.reverse_dir[direction] : 0 //flip the direction, to match with the source position on its turf + + if(!(d1 == direction || d2 == direction)) //if the cable is not pointed in this direction, do nothing + return + + var/turf/TB = get_zstep(src, direction) + + for(var/obj/structure/cable/C in TB) + + if(!C) + continue + + if(src == C) + continue + + if(C.d1 == fdir || C.d2 == fdir) //we've got a matching cable in the neighbor turf + if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables) + var/datum/powernet/newPN = new() + newPN.add_cable(C) + + if(powernet) //if we already have a powernet, then merge the two powernets + merge_powernets(powernet,C.powernet) + else + C.powernet.add_cable(src) //else, we simply connect to the matching cable powernet + +// merge with the powernets of power objects in the source turf +/obj/structure/cable/proc/mergeConnectedNetworksOnTurf() + var/list/to_connect = list() + + if(!powernet) //if we somehow have no powernet, make one (should not happen for cables) + var/datum/powernet/newPN = new() + newPN.add_cable(src) + + //first let's add turf cables to our powernet + //then we'll connect machines on turf with a node cable is present + for(var/AM in loc) + if(istype(AM,/obj/structure/cable)) + var/obj/structure/cable/C = AM + if(C.d1 == d1 || C.d2 == d1 || C.d1 == d2 || C.d2 == d2) //only connected if they have a common direction + if(C.powernet == powernet) continue + if(C.powernet) + merge_powernets(powernet, C.powernet) + else + powernet.add_cable(C) //the cable was powernetless, let's just add it to our powernet + + else if(istype(AM,/obj/machinery/power/apc)) + var/obj/machinery/power/apc/N = AM + if(!N.terminal) continue // APC are connected through their terminal + + if(N.terminal.powernet == powernet) + continue + + to_connect += N.terminal //we'll connect the machines after all cables are merged + + else if(istype(AM,/obj/machinery/power)) //other power machines + var/obj/machinery/power/M = AM + + if(M.powernet == powernet) + continue + + to_connect += M //we'll connect the machines after all cables are merged + + //now that cables are done, let's connect found machines + for(var/obj/machinery/power/PM in to_connect) + if(!PM.connect_to_network()) + PM.disconnect_from_network() //if we somehow can't connect the machine to the new powernet, remove it from the old nonetheless + +////////////////////////////////////////////// +// Powernets handling helpers +////////////////////////////////////////////// + +//if powernetless_only = 1, will only get connections without powernet +/obj/structure/cable/proc/get_connections(var/powernetless_only = 0) + . = list() // this will be a list of all connected power objects + var/turf/T + + // Handle standard cables in adjacent turfs + for(var/cable_dir in list(d1, d2)) + if(cable_dir == 0) + continue + var/reverse = GLOB.reverse_dir[cable_dir] + T = get_zstep(src, cable_dir) + if(T) + for(var/obj/structure/cable/C in T) + if(C.d1 == reverse || C.d2 == reverse) + . += C + if(cable_dir & (cable_dir - 1)) // Diagonal, check for /\/\/\ style cables along cardinal directions + for(var/pair in list(NORTH|SOUTH, EAST|WEST)) + T = get_step(src, cable_dir & pair) + if(T) + var/req_dir = cable_dir ^ pair + for(var/obj/structure/cable/C in T) + if(C.d1 == req_dir || C.d2 == req_dir) + . += C + + // Handle cables on the same turf as us + for(var/obj/structure/cable/C in loc) + if(C.d1 == d1 || C.d2 == d1 || C.d1 == d2 || C.d2 == d2) // if either of C's d1 and d2 match either of ours + . += C + + if(d1 == 0) + for(var/obj/machinery/power/P in loc) + if(P.powernet == 0) continue // exclude APCs with powernet=0 + if(!powernetless_only || !P.powernet) + . += P + + // if the caller asked for powernetless cables only, dump the ones with powernets + if(powernetless_only) + for(var/obj/structure/cable/C in .) + if(C.powernet) + . -= C + +//should be called after placing a cable which extends another cable, creating a "smooth" cable that no longer terminates in the centre of a turf. +//needed as this can, unlike other placements, disconnect cables +/obj/structure/cable/proc/denode() + var/turf/T1 = loc + if(!T1) return + + var/list/powerlist = power_list(T1,src,0,0) //find the other cables that ended in the centre of the turf, with or without a powernet + if(powerlist.len>0) + var/datum/powernet/PN = new() + propagate_network(powerlist[1],PN) //propagates the new powernet beginning at the source cable + + if(PN.is_empty()) //can happen with machines made nodeless when smoothing cables + qdel(PN) + +// cut the cable's powernet at this cable and updates the powergrid +/obj/structure/cable/proc/cut_cable_from_powernet() + var/turf/T1 = loc + var/list/P_list + if(!T1) return + if(d1) + T1 = get_step(T1, d1) + P_list = power_list(T1, src, turn(d1,180),0,cable_only = 1) // what adjacently joins on to cut cable... + + P_list += power_list(loc, src, d1, 0, cable_only = 1)//... and on turf + + + if(P_list.len == 0)//if nothing in both list, then the cable was a lone cable, just delete it and its powernet + powernet.remove_cable(src) + + for(var/obj/machinery/power/P in T1)//check if it was powering a machine + if(!P.connect_to_network()) //can't find a node cable on a the turf to connect to + P.disconnect_from_network() //remove from current network (and delete powernet) + return + + // remove the cut cable from its turf and powernet, so that it doesn't get count in propagate_network worklist + forceMove(null) + powernet.remove_cable(src) //remove the cut cable from its powernet + + var/datum/powernet/newPN = new()// creates a new powernet... + propagate_network(P_list[1], newPN)//... and propagates it to the other side of the cable + + // Disconnect machines connected to nodes + if(d1 == 0) // if we cut a node (O-X) cable + for(var/obj/machinery/power/P in T1) + if(!P.connect_to_network()) //can't find a node cable on a the turf to connect to + P.disconnect_from_network() //remove from current network + + powernet = null // And finally null the powernet var. + +/////////////////////////////////////////////// +// The cable coil object, used for laying cable +/////////////////////////////////////////////// + +//////////////////////////////// +// Definitions +//////////////////////////////// + +#define MAXCOIL 30 + +/obj/item/stack/cable_coil + name = "multipurpose cable coil" + icon = 'icons/obj/power.dmi' + icon_state = "coil" + randpixel = 2 + amount = MAXCOIL + max_amount = MAXCOIL + color = COLOR_RED + desc = "A coil of wiring, for delicate electronics use aswell as the more basic cable laying." + throwforce = 0 + w_class = ITEM_SIZE_NORMAL + throw_speed = 2 + throw_range = 5 + matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 20) + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + item_state = "coil" + attack_verb = list("whipped", "lashed", "disciplined", "flogged") + stacktype = /obj/item/stack/cable_coil + +/obj/item/stack/cable_coil/single + amount = 1 + +/obj/item/stack/cable_coil/single/New(var/loc, var/length = 1, var/param_color = null) + ..(loc, length, param_color) + +/obj/item/stack/cable_coil/cyborg + name = "cable coil synthesizer" + desc = "A device that makes cable." + gender = NEUTER + matter = null + uses_charge = 1 + charge_costs = list(1) + +/obj/item/stack/cable_coil/New(loc, length = MAXCOIL, var/param_color = null) + ..() + src.amount = length + if (param_color) // It should be red by default, so only recolor it if parameter was specified. + color = param_color + update_icon() + update_wclass() + +/////////////////////////////////// +// General procedures +/////////////////////////////////// + +//you can use wires to heal robotics +/obj/item/stack/cable_coil/attack(var/atom/A, var/mob/living/user, var/def_zone) + if(ishuman(A) && user.a_intent == I_HELP) + var/mob/living/carbon/human/H = A + var/obj/item/organ/external/S = H.organs_by_name[user.zone_sel.selecting] + + if (!S) return + if(S.robotic < ORGAN_ROBOT || user.a_intent != I_HELP) + return ..() + + var/use_amt = min(src.amount, ceil(S.burn_dam/3), 5) + if(can_use(use_amt)) + if(S.robo_repair(3*use_amt, BURN, "some damaged wiring", src, user)) + src.use(use_amt) + return + return ..() + + +/obj/item/stack/cable_coil/update_icon() + if (!color) + color = possible_cable_coil_colours[pick(possible_cable_coil_colours)] + if(amount == 1) + icon_state = "coil1" + SetName("cable piece") + else if(amount == 2) + icon_state = "coil2" + SetName("cable piece") + else + icon_state = initial(icon_state) + SetName(initial(name)) + +/obj/item/stack/cable_coil/proc/set_cable_color(var/selected_color, var/user) + if(!selected_color) + return + + var/final_color = possible_cable_coil_colours[selected_color] + if(!final_color) + selected_color = "Red" + final_color = possible_cable_coil_colours[selected_color] + color = final_color + to_chat(user, "You change \the [src]'s color to [lowertext(selected_color)].") + +/obj/item/stack/cable_coil/proc/update_wclass() + if(amount == 1) + w_class = ITEM_SIZE_TINY + else + w_class = ITEM_SIZE_SMALL + +/obj/item/stack/cable_coil/examine(mob/user) + . = ..() + if(get_dist(src, user) > 1) + return + + if(get_amount() == 1) + to_chat(user, "A short piece of power cable.") + else if(get_amount() == 2) + to_chat(user, "A piece of power cable.") + else + to_chat(user, "A coil of power cable. There are [get_amount()] lengths of cable in the coil.") + + +/obj/item/stack/cable_coil/verb/make_restraint() + set name = "Make Cable Restraints" + set category = "Object" + var/mob/M = usr + + if(ishuman(M) && !M.incapacitated()) + if(!istype(usr.loc,/turf)) return + if(src.amount <= 14) + to_chat(usr, "You need at least 15 lengths to make restraints!") + return + var/obj/item/weapon/handcuffs/cable/B = new /obj/item/weapon/handcuffs/cable(usr.loc) + B.color = color + to_chat(usr, "You wind some cable together to make some restraints.") + src.use(15) + else + to_chat(usr, "You cannot do that.") + ..() + +/obj/item/stack/cable_coil/cyborg/verb/set_colour() + set name = "Change Colour" + set category = "Object" + + var/selected_type = input("Pick new colour.", "Cable Colour", null, null) as null|anything in possible_cable_coil_colours + set_cable_color(selected_type, usr) + +// Items usable on a cable coil : +// - Wirecutters : cut them duh ! +// - Cable coil : merge cables +/obj/item/stack/cable_coil/proc/can_merge(var/obj/item/stack/cable_coil/C) + return color == C.color + +/obj/item/stack/cable_coil/cyborg/can_merge() + return 1 + +/obj/item/stack/cable_coil/transfer_to(obj/item/stack/cable_coil/S) + if(!istype(S)) + return + if(!can_merge(S)) + return + + ..() + +/obj/item/stack/cable_coil/use() + . = ..() + update_icon() + return + +/obj/item/stack/cable_coil/add() + . = ..() + update_icon() + return + +/////////////////////////////////////////////// +// Cable laying procedures +////////////////////////////////////////////// + +// called when cable_coil is clicked on a turf/simulated/floor +/obj/item/stack/cable_coil/proc/turf_place(turf/simulated/F, mob/user) + if(!isturf(user.loc)) + return + + if(get_amount() < 1) // Out of cable + to_chat(user, "There is no cable left.") + return + + if(get_dist(F,user) > 1) // Too far + to_chat(user, "You can't lay cable at a place that far away.") + return + + if(!F.is_plating()) // Ff floor is intact, complain + to_chat(user, "You can't lay cable there unless the floor tiles are removed.") + return + + var/dirn + if(user.loc == F) + dirn = user.dir // if laying on the tile we're on, lay in the direction we're facing + else + dirn = get_dir(F, user) + + var/end_dir = 0 + if(istype(F, /turf/simulated/open)) + if(!can_use(2)) + to_chat(user, "You don't have enough cable to do this!") + return + end_dir = DOWN + + for(var/obj/structure/cable/LC in F) + if((LC.d1 == dirn && LC.d2 == end_dir ) || ( LC.d2 == dirn && LC.d1 == end_dir)) + to_chat(user, "There's already a cable at that position.") + return + + put_cable(F, user, end_dir, dirn) + if(end_dir == DOWN) + put_cable(GetBelow(F), user, UP, 0) + +// called when cable_coil is click on an installed obj/cable +// or click on a turf that already contains a "node" cable +/obj/item/stack/cable_coil/proc/cable_join(obj/structure/cable/C, mob/user) + var/turf/U = user.loc + if(!isturf(U)) + return + + var/turf/T = C.loc + + if(!isturf(T) || !T.is_plating()) // sanity checks, also stop use interacting with T-scanner revealed cable + return + + if(get_dist(C, user) > 1) // make sure it's close enough + to_chat(user, "You can't lay cable at a place that far away.") + return + + if(U == T) //if clicked on the turf we're standing on, try to put a cable in the direction we're facing + turf_place(T,user) + return + + var/dirn = get_dir(C, user) + + // one end of the clicked cable is pointing towards us + if(C.d1 == dirn || C.d2 == dirn) + if(!U.is_plating()) // can't place a cable if the floor is complete + to_chat(user, "You can't lay cable there unless the floor tiles are removed.") + return + else + // cable is pointing at us, we're standing on an open tile + // so create a stub pointing at the clicked cable on our tile + + var/fdirn = turn(dirn, 180) // the opposite direction + + for(var/obj/structure/cable/LC in U) // check to make sure there's not a cable there already + if(LC.d1 == fdirn || LC.d2 == fdirn) + to_chat(user, "There's already a cable at that position.") + return + put_cable(U,user,0,fdirn) + return + + // exisiting cable doesn't point at our position, so see if it's a stub + else if(C.d1 == 0) + // if so, make it a full cable pointing from it's old direction to our dirn + var/nd1 = C.d2 // these will be the new directions + var/nd2 = dirn + + + if(nd1 > nd2) // swap directions to match icons/states + nd1 = dirn + nd2 = C.d2 + + + for(var/obj/structure/cable/LC in T) // check to make sure there's no matching cable + if(LC == C) // skip the cable we're interacting with + continue + if((LC.d1 == nd1 && LC.d2 == nd2) || (LC.d1 == nd2 && LC.d2 == nd1) ) // make sure no cable matches either direction + to_chat(user, "There's already a cable at that position.") + return + + + C.cableColor(color) + + C.d1 = nd1 + C.d2 = nd2 + + C.add_fingerprint() + C.update_icon() + + + C.mergeConnectedNetworks(C.d1) //merge the powernets... + C.mergeConnectedNetworks(C.d2) //...in the two new cable directions + C.mergeConnectedNetworksOnTurf() + + if(C.d1 & (C.d1 - 1))// if the cable is layed diagonally, check the others 2 possible directions + C.mergeDiagonalsNetworks(C.d1) + + if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions + C.mergeDiagonalsNetworks(C.d2) + + use(1) + + if (C.shock(user, 50)) + if (prob(50)) //fail + new/obj/item/stack/cable_coil(C.loc, 2, C.color) + qdel(C) + return + + C.denode()// this call may have disconnected some cables that terminated on the centre of the turf, if so split the powernets. + return + +/obj/item/stack/cable_coil/proc/put_cable(turf/simulated/F, mob/user, d1, d2) + if(!istype(F)) + return + + var/obj/structure/cable/C = new(F) + C.cableColor(color) + C.d1 = d1 + C.d2 = d2 + C.add_fingerprint(user) + C.update_icon() + + //create a new powernet with the cable, if needed it will be merged later + var/datum/powernet/PN = new() + PN.add_cable(C) + + C.mergeConnectedNetworks(C.d1) //merge the powernets... + C.mergeConnectedNetworks(C.d2) //...in the two new cable directions + C.mergeConnectedNetworksOnTurf() + + if(C.d1 & (C.d1 - 1))// if the cable is layed diagonally, check the others 2 possible directions + C.mergeDiagonalsNetworks(C.d1) + + if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions + C.mergeDiagonalsNetworks(C.d2) + + use(1) + if (C.shock(user, 50)) + if (prob(50)) //fail + new/obj/item/stack/cable_coil(C.loc, 1, C.color) + qdel(C) + +////////////////////////////// +// Misc. +///////////////////////////// + +/obj/item/stack/cable_coil/cut + item_state = "coil2" + +/obj/item/stack/cable_coil/cut/New(loc) + ..() + src.amount = rand(1,2) + update_icon() + update_wclass() + +/obj/item/stack/cable_coil/yellow + color = COLOR_YELLOW + +/obj/item/stack/cable_coil/blue + color = COLOR_BLUE + +/obj/item/stack/cable_coil/green + color = COLOR_LIME + +/obj/item/stack/cable_coil/pink + color = COLOR_PINK + +/obj/item/stack/cable_coil/orange + color = COLOR_ORANGE + +/obj/item/stack/cable_coil/cyan + color = COLOR_CYAN + +/obj/item/stack/cable_coil/white + color = COLOR_WHITE + +/obj/item/stack/cable_coil/random/New() + color = possible_cable_coil_colours[pick(possible_cable_coil_colours)] + ..() diff --git a/code/modules/power/cable_logic.dm b/code/modules/power/cable_logic.dm new file mode 100644 index 00000000..3b5b67a3 --- /dev/null +++ b/code/modules/power/cable_logic.dm @@ -0,0 +1,292 @@ +#define LOGIC_HIGH 5 + +//Indicators only have one input and no outputs +/obj/machinery/logic/indicator + //Input is searched from the 'dir' direction + var/obj/structure/cable/input + +/obj/machinery/logic/indicator/process() + if(input) + return 1 + + + if(!input) + var/turf/T = get_step(src, dir) + if(T) + var/inv_dir = turn(dir, 180) + for(var/obj/structure/cable/C in T) + if(C.d1 == inv_dir || C.d2 == inv_dir) + input = C + return 1 + + return 0 //If it gets to here, it means no suitable wire to link to was found. + +/obj/machinery/logic/indicator/bulb + icon = 'icons/obj/lighting.dmi' + icon_state = "bulb0" + +/obj/machinery/logic/indicator/bulb/process() + if(!..()) //Parent proc checks if input1 exists. + return + + var/datum/powernet/pn_input = input.powernet + if(!pn_input) + return + + if(pn_input.avail >= LOGIC_HIGH) + icon_state = "bulb1" + else + icon_state = "bulb0" + + + + +//Sensors only have one output and no inputs +/obj/machinery/logic/sensor + //Output is searched from the 'dir' direction + var/obj/structure/cable/output + +/obj/machinery/logic/sensor/process() + if(output) + return 1 + + if(!output) + var/turf/T = get_step(src, dir) + if(T) + var/inv_dir = turn(dir, 180) + for(var/obj/structure/cable/C in T) + if(C.d1 == inv_dir || C.d2 == inv_dir) + output = C + return 1 + + return 0 //If it gets to here, it means no suitable wire to link to was found. + +//Constant high generator. This will continue to send a signal of LOGIC_HIGH as long as it exists. +/obj/machinery/logic/sensor/constant_high + icon = 'icons/obj/atmospherics/outlet_injector.dmi' + icon_state = "off" + +/obj/machinery/logic/sensor/constant_high/process() + if(!..()) //Parent proc checks if input1 exists. + return + + var/datum/powernet/pn_output = output.powernet + if(!pn_output) + return + + pn_output.newavail = max(pn_output.avail, LOGIC_HIGH) + + + + +//ONE INPUT logic elements have one input and one output +/obj/machinery/logic/oneinput + var/dir_input = 2 + var/dir_output = 1 + var/obj/structure/cable/input + var/obj/structure/cable/output + icon = 'icons/atmos/heat.dmi' + icon_state = "intact" + +/obj/machinery/logic/oneinput/process() + if(input && output) + return 1 + + if(!dir_input || !dir_output) + return 0 + + if(!input) + var/turf/T = get_step(src, dir_input) + if(T) + var/inv_dir = turn(dir_input, 180) + for(var/obj/structure/cable/C in T) + if(C.d1 == inv_dir || C.d2 == inv_dir) + input = C + + if(!output) + var/turf/T = get_step(src, dir_output) + if(T) + var/inv_dir = turn(dir_output, 180) + for(var/obj/structure/cable/C in T) + if(C.d1 == inv_dir || C.d2 == inv_dir) + output = C + + return 0 //On the process() call, where everything is still being searched for, it returns 0. It will return 1 on the next process() call. + +//NOT GATE +/obj/machinery/logic/oneinput/not/process() + if(!..()) //Parent proc checks if input1, input2 and output exist. + return + + var/datum/powernet/pn_input = input.powernet + + if(!pn_input) + return + + var/datum/powernet/pn_output = output.powernet + if(!pn_output) + return + + if( !(pn_input.avail >= LOGIC_HIGH)) + pn_output.newavail = max(pn_output.avail, LOGIC_HIGH) //Set the output avilable power to 5 or whatever it was before. + else + pn_output.draw_power(LOGIC_HIGH) //Otherwise increase the load to 5 + + + + + + + + + +//TWO INPUT logic elements have two inputs and one output +/obj/machinery/logic/twoinput + var/dir_input1 = 2 + var/dir_input2 = 8 + var/dir_output = 1 + var/obj/structure/cable/input1 + var/obj/structure/cable/input2 + var/obj/structure/cable/output + icon = 'icons/obj/atmospherics/mixer.dmi' + icon_state = "intact_off" + +/obj/machinery/logic/twoinput/process() + if(input1 && input2 && output) + return 1 + + if(!dir_input1 || !dir_input2 || !dir_output) + return 0 + + if(!input1) + var/turf/T = get_step(src, dir_input1) + if(T) + var/inv_dir = turn(dir_input1, 180) + for(var/obj/structure/cable/C in T) + if(C.d1 == inv_dir || C.d2 == inv_dir) + input1 = C + + if(!input2) + var/turf/T = get_step(src, dir_input2) + if(T) + var/inv_dir = turn(dir_input2, 180) + for(var/obj/structure/cable/C in T) + if(C.d1 == inv_dir || C.d2 == inv_dir) + input2 = C + + if(!output) + var/turf/T = get_step(src, dir_output) + if(T) + var/inv_dir = turn(dir_output, 180) + for(var/obj/structure/cable/C in T) + if(C.d1 == inv_dir || C.d2 == inv_dir) + output = C + + return 0 //On the process() call, where everything is still being searched for, it returns 0. It will return 1 on the next process() call. + +//AND GATE +/obj/machinery/logic/twoinput/and/process() + if(!..()) //Parent proc checks if input1, input2 and output exist. + return + + var/datum/powernet/pn_input1 = input1.powernet + var/datum/powernet/pn_input2 = input2.powernet + + if(!pn_input1 || !pn_input2) + return + + var/datum/powernet/pn_output = output.powernet + if(!pn_output) + return + + if( (pn_input1.avail >= LOGIC_HIGH) && (pn_input2.avail >= LOGIC_HIGH) ) + pn_output.newavail = max(pn_output.avail, LOGIC_HIGH) //Set the output avilable power to 5 or whatever it was before. + else + pn_output.draw_power(LOGIC_HIGH) //Otherwise increase the load to 5 + +//OR GATE +/obj/machinery/logic/twoinput/or/process() + if(!..()) //Parent proc checks if input1, input2 and output exist. + return + + var/datum/powernet/pn_input1 = input1.powernet + var/datum/powernet/pn_input2 = input2.powernet + + if(!pn_input1 || !pn_input2) + return + + var/datum/powernet/pn_output = output.powernet + if(!pn_output) + return + + if( (pn_input1.avail >= LOGIC_HIGH) || (pn_input2.avail >= LOGIC_HIGH) ) + pn_output.newavail = max(pn_output.avail, LOGIC_HIGH) //Set the output avilable power to 5 or whatever it was before. + else + pn_output.draw_power(LOGIC_HIGH) //Otherwise increase the load to 5 + +//XOR GATE +/obj/machinery/logic/twoinput/xor/process() + if(!..()) //Parent proc checks if input1, input2 and output exist. + return + + var/datum/powernet/pn_input1 = input1.powernet + var/datum/powernet/pn_input2 = input2.powernet + + if(!pn_input1 || !pn_input2) + return + + var/datum/powernet/pn_output = output.powernet + if(!pn_output) + return + + if( (pn_input1.avail >= LOGIC_HIGH) != (pn_input2.avail >= LOGIC_HIGH) ) + pn_output.newavail = max(pn_output.avail, LOGIC_HIGH) //Set the output avilable power to 5 or whatever it was before. + else + pn_output.draw_power(LOGIC_HIGH) //Otherwise increase the load to 5 + +//XNOR GATE (EQUIVALENCE) +/obj/machinery/logic/twoinput/xnor/process() + if(!..()) //Parent proc checks if input1, input2 and output exist. + return + + var/datum/powernet/pn_input1 = input1.powernet + var/datum/powernet/pn_input2 = input2.powernet + + if(!pn_input1 || !pn_input2) + return + + var/datum/powernet/pn_output = output.powernet + if(!pn_output) + return + + if( (pn_input1.avail >= LOGIC_HIGH) == (pn_input2.avail >= LOGIC_HIGH) ) + pn_output.newavail = max(pn_output.avail, LOGIC_HIGH) //Set the output avilable power to 5 or whatever it was before. + else + pn_output.draw_power(LOGIC_HIGH) //Otherwise increase the load to 5 + +#define RELAY_POWER_TRANSFER 2000 //How much power a relay transfers through. + +//RELAY - input1 governs the flow from input2 to output +/obj/machinery/logic/twoinput/relay/process() + if(!..()) //Parent proc checks if input1, input2 and output exist. + return + + var/datum/powernet/pn_input1 = input1.powernet + + if(!pn_input1) + return + + if( pn_input1.avail >= LOGIC_HIGH ) + var/datum/powernet/pn_input2 = input2.powernet + var/datum/powernet/pn_output = output.powernet + + if(!pn_output) + return + + if(pn_input2.avail >= RELAY_POWER_TRANSFER) + pn_input2.draw_power(RELAY_POWER_TRANSFER) + pn_output.newavail += RELAY_POWER_TRANSFER + + +#undef RELAY_POWER_TRANSFER +#undef LOGIC_HIGH \ No newline at end of file diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm new file mode 100644 index 00000000..e2f1dfa4 --- /dev/null +++ b/code/modules/power/cell.dm @@ -0,0 +1,271 @@ +// Power Cells +/obj/item/weapon/cell + name = "power cell" + desc = "A rechargable electrochemical power cell." + icon = 'icons/obj/power.dmi' + icon_state = "cell" + item_state = "cell" + origin_tech = list(TECH_POWER = 1) + force = 5.0 + throwforce = 5.0 + throw_speed = 3 + throw_range = 5 + w_class = ITEM_SIZE_NORMAL + var/c_uid + var/charge // Current charge + var/maxcharge = 1000 // Capacity in Wh + var/overlay_state + matter = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 50) + + +/obj/item/weapon/cell/New() + if(isnull(charge)) + charge = maxcharge + c_uid = sequential_id(/obj/item/weapon/cell) + ..() + +/obj/item/weapon/cell/Initialize() + . = ..() + update_icon() + +/obj/item/weapon/cell/drain_power(var/drain_check, var/surge, var/power = 0) + + if(drain_check) + return 1 + + if(charge <= 0) + return 0 + + var/cell_amt = power * CELLRATE + + return use(cell_amt) / CELLRATE + +/obj/item/weapon/cell/update_icon() + + var/new_overlay_state = null + if(percent() >= 95) + new_overlay_state = "cell-o2" + else if(charge >= 0.05) + new_overlay_state = "cell-o1" + + if(new_overlay_state != overlay_state) + overlay_state = new_overlay_state + overlays.Cut() + if(overlay_state) + overlays += image('icons/obj/power.dmi', overlay_state) + +/obj/item/weapon/cell/proc/percent() // return % charge of cell + return maxcharge && (100.0*charge/maxcharge) + +/obj/item/weapon/cell/proc/fully_charged() + return (charge == maxcharge) + +// checks if the power cell is able to provide the specified amount of charge +/obj/item/weapon/cell/proc/check_charge(var/amount) + return (charge >= amount) + +// use power from a cell, returns the amount actually used +/obj/item/weapon/cell/proc/use(var/amount) + var/used = min(charge, amount) + charge -= used + update_icon() + return used + +// Checks if the specified amount can be provided. If it can, it removes the amount +// from the cell and returns 1. Otherwise does nothing and returns 0. +/obj/item/weapon/cell/proc/checked_use(var/amount) + if(!check_charge(amount)) + return 0 + use(amount) + return 1 + +/obj/item/weapon/cell/proc/give(var/amount) + if(maxcharge < amount) return 0 + var/amount_used = min(maxcharge-charge,amount) + charge += amount_used + update_icon() + return amount_used + +/obj/item/weapon/cell/examine(mob/user) + . = ..() + to_chat(user, "The label states it's capacity is [maxcharge] Wh") + to_chat(user, "The charge meter reads [round(src.percent(), 0.1)]%") + +/obj/item/weapon/cell/emp_act(severity) + //remove this once emp changes on dev are merged in + if(isrobot(loc)) + var/mob/living/silicon/robot/R = loc + severity *= R.cell_emp_mult + + // Lose 1/2, 1/4, 1/6 of the current charge per hit or 1/4, 1/8, 1/12 of the max charge per hit, whichever is highest + charge -= max(charge / (2 * severity), maxcharge/(4 * severity)) + if (charge < 0) + charge = 0 + ..() + + +/obj/item/weapon/cell/proc/get_electrocute_damage() + switch (charge) + if (1000000 to INFINITY) + return min(rand(50,160),rand(50,160)) + if (200000 to 1000000-1) + return min(rand(25,80),rand(25,80)) + if (100000 to 200000-1)//Ave powernet + return min(rand(20,60),rand(20,60)) + if (50000 to 100000-1) + return min(rand(15,40),rand(15,40)) + if (1000 to 50000-1) + return min(rand(10,20),rand(10,20)) + else + return 0 + + +// SUBTYPES BELOW + +// Smaller variant, used by energy guns and similar small devices. +/obj/item/weapon/cell/device + name = "device power cell" + desc = "A small power cell designed to power handheld devices." + icon_state = "device" + w_class = ITEM_SIZE_SMALL + force = 0 + throw_speed = 5 + throw_range = 7 + maxcharge = 100 + matter = list("metal" = 70, "glass" = 5) + +/obj/item/weapon/cell/device/variable/New(newloc, charge_amount) + maxcharge = charge_amount + ..(newloc) + +/obj/item/weapon/cell/device/standard + name = "standard device power cell" + maxcharge = 25 + +/obj/item/weapon/cell/device/high + name = "advanced device power cell" + desc = "A small power cell designed to power more energy-demanding devices." + icon_state = "hdevice" + maxcharge = 100 + matter = list("metal" = 70, "glass" = 6) + +/obj/item/weapon/cell/device/update_icon()//No dumb overlays for these things please. + overlays.Cut() + return + +/obj/item/weapon/cell/crap + name = "old power cell" + desc = "A cheap old power cell. It's probably been in use for quite some time now." + origin_tech = list(TECH_POWER = 0) + maxcharge = 100 + matter = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 40) + +/obj/item/weapon/cell/crap/empty + charge = 0 + +/obj/item/weapon/cell/standard + name = "standard power cell" + desc = "A standard and relatively cheap power cell, commonly used." + origin_tech = list(TECH_POWER = 0) + maxcharge = 250 + matter = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 40) + +/obj/item/weapon/cell/crap/empty/New() + ..() + charge = 0 + + +/obj/item/weapon/cell/apc + name = "APC power cell" + desc = "A special power cell designed for heavy-duty use in area power controllers." + origin_tech = list(TECH_POWER = 1) + maxcharge = 500 + matter = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 50) + +/obj/item/weapon/cell/apc/empty + charge = 0 + +/obj/item/weapon/cell/apc/empty/New() + ..() + charge = 0 + +/obj/item/weapon/cell/high + name = "advanced power cell" + desc = "An advanced high-grade power cell, for use in important systems." + origin_tech = list(TECH_POWER = 2) + icon_state = "hcell" + maxcharge = 1000 + matter = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 60) + +/obj/item/weapon/cell/high/empty/New() + ..() + charge = 0 + + +/obj/item/weapon/cell/mecha + name = "exosuit power cell" + desc = "A special power cell designed for heavy-duty use in industrial exosuits." + origin_tech = list(TECH_POWER = 3) + icon_state = "hcell" + maxcharge = 1500 + matter = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 70) + + +/obj/item/weapon/cell/super + name = "enhanced power cell" + desc = "A very advanced power cell with increased energy density, for use in critical applications." + origin_tech = list(TECH_POWER = 5) + icon_state = "scell" + maxcharge = 2000 + matter = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 70) + +/obj/item/weapon/cell/super/empty/New() + ..() + charge = 0 + + +/obj/item/weapon/cell/hyper + name = "superior power cell" + desc = "Pinnacle of power storage technology, this very expensive power cell provides the best energy density reachable with conventional electrochemical cells." + origin_tech = list(TECH_POWER = 6) + icon_state = "hpcell" + maxcharge = 3000 + matter = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 80) + +/obj/item/weapon/cell/hyper/empty/New() + ..() + charge = 0 + + +/obj/item/weapon/cell/infinite + name = "experimental power cell" + desc = "This special experimental power cell has both very large capacity, and ability to recharge itself by draining power from contained bluespace pocket." + icon_state = "icell" + origin_tech = null + maxcharge = 3000 + matter = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 80) + +/obj/item/weapon/cell/infinite/check_charge() + return 1 + +/obj/item/weapon/cell/infinite/use() + return 1 + + +/obj/item/weapon/cell/potato + name = "potato battery" + desc = "A rechargable starch based power cell." + origin_tech = list(TECH_POWER = 1) + icon = 'icons/obj/power.dmi' //'icons/obj/harvest.dmi' + icon_state = "potato_cell" //"potato_battery" + maxcharge = 20 + + +/obj/item/weapon/cell/slime + name = "charged slime core" + desc = "A yellow slime core infused with phoron, it crackles with power." + origin_tech = list(TECH_POWER = 2, TECH_BIO = 4) + icon = 'icons/mob/slimes.dmi' //'icons/obj/harvest.dmi' + icon_state = "yellow slime extract" //"potato_battery" + maxcharge = 200 + matter = null diff --git a/code/modules/power/debug_items.dm b/code/modules/power/debug_items.dm new file mode 100644 index 00000000..d4b2c6ca --- /dev/null +++ b/code/modules/power/debug_items.dm @@ -0,0 +1,65 @@ +/obj/machinery/power/debug_items/ + icon = 'icons/obj/power.dmi' + icon_state = "tracker" + anchored = 1 + density = 1 + var/show_extended_information = 1 // Set to 0 to disable extra information on examining (for example, when used on admin events) + +/obj/machinery/power/debug_items/examine(var/mob/user) + . = ..() + if(show_extended_information) + show_info(user) + +/obj/machinery/power/debug_items/proc/show_info(var/mob/user) + if(!powernet) + to_chat(user, "This device is not connected to a powernet") + return + + to_chat(user, "Connected to powernet: [powernet]") + to_chat(user, "Available power: [num2text(powernet.avail, 20)] W") + to_chat(user, "Load: [num2text(powernet.viewload, 20)] W") + to_chat(user, "Has alert: [powernet.problem ? "YES" : "NO"]") + to_chat(user, "Cables: [powernet.cables.len]") + to_chat(user, "Nodes: [powernet.nodes.len]") + + +// An infinite power generator. Adds energy to connected cable. +/obj/machinery/power/debug_items/infinite_generator + name = "Fractal Energy Reactor" + desc = "An experimental power generator" + var/power_generation_rate = 1000000 + +/obj/machinery/power/debug_items/infinite_generator/Process() + add_avail(power_generation_rate) + +/obj/machinery/power/debug_items/infinite_generator/show_info(var/mob/user) + ..() + to_chat(user, "Generator is providing [num2text(power_generation_rate, 20)] W") + + +// A cable powersink, without the explosion/network alarms normal powersink causes. +/obj/machinery/power/debug_items/infinite_cable_powersink + name = "Null Point Core" + desc = "An experimental device that disperses energy, used for grid testing purposes." + var/power_usage_rate = 0 + var/last_used = 0 + +/obj/machinery/power/debug_items/infinite_cable_powersink/Process() + last_used = draw_power(power_usage_rate) + +/obj/machinery/power/debug_items/infinite_cable_powersink/show_info(var/mob/user) + ..() + to_chat(user, "Power sink is demanding [num2text(power_usage_rate, 20)] W") + to_chat(user, "[num2text(last_used, 20)] W was actually used last tick") + + +/obj/machinery/power/debug_items/infinite_apc_powersink + name = "APC Dummy Load" + desc = "A dummy load that connects to an APC, used for load testing purposes." + use_power = 2 + active_power_usage = 0 + +/obj/machinery/power/debug_items/infinite_apc_powersink/show_info(var/mob/user) + ..() + to_chat(user, "Dummy load is using [num2text(active_power_usage, 20)] W") + to_chat(user, "Powered: [powered() ? "YES" : "NO"]") diff --git a/code/modules/power/fusion/_setup.dm b/code/modules/power/fusion/_setup.dm new file mode 100644 index 00000000..283bdaff --- /dev/null +++ b/code/modules/power/fusion/_setup.dm @@ -0,0 +1,83 @@ +// temperature of the core of the sun +#define FUSION_HEAT_CAP 1.57e7 + +#define SETUP_OK 1 // All good +#define SETUP_WARNING 2 // Something that shouldn't happen happened, but it's not critical so we will continue +#define SETUP_ERROR 3 // Something bad happened, and it's important so we won't continue setup. +#define SETUP_DELAYED 4 // Wait for other things first. + +/datum/admins/proc/setup_fusion() + set category = "Debug" + set name = "Setup Fusion Core" + set desc = "Allows you to start the R-UST engine." + + if (!istype(src,/datum/admins)) + src = usr.client.holder + if (!istype(src,/datum/admins)) + to_chat(usr, "Error: you are not an admin!") + return + + if(!(locate(/obj/machinery/power/fusion_core/mapped) in world)) + to_chat(usr, "This map is not appropriate for this verb.") + return + + var/response = input(usr, "Are you sure?", "Engine setup") as null|anything in list("No", "Yes") + if(!response || response == "No") + return + + var/errors = 0 + var/warnings = 0 + var/success = 0 + + log_and_message_admins("## FUSION CORE SETUP - Setup initiated by [usr].") + + for(var/obj/machinery/fusion_fuel_injector/mapped/injector in SSmachines.machinery) + injector.cur_assembly = new /obj/item/weapon/fuel_assembly/deuterium(injector) + injector.BeginInjecting() + + var/obj/machinery/power/fusion_core/mapped/core = locate() in SSmachines.machinery + if(core.jumpstart(15000)) + var/list/delayed_objects = list() + + // SETUP PHASE + for(var/obj/effect/engine_setup/S in world) + var/result = S.activate(0) + switch(result) + if(SETUP_OK) + success++ + continue + if(SETUP_WARNING) + warnings++ + continue + if(SETUP_ERROR) + errors++ + log_and_message_admins("## FUSION CORE SETUP - Error encountered! Aborting.") + break + if(SETUP_DELAYED) + delayed_objects.Add(S) + continue + + if(!errors) + for(var/obj/effect/engine_setup/S in delayed_objects) + var/result = S.activate(1) + switch(result) + if(SETUP_OK) + success++ + continue + if(SETUP_WARNING) + warnings++ + continue + if(SETUP_ERROR) + errors++ + log_and_message_admins("## FUSION CORE SETUP - Error encountered! Aborting.") + break + else + log_and_message_admins("## FUSION CORE SETUP - Error encountered! Aborting.") + errors++ + + log_and_message_admins("## FUSION CORE SETUP - Setup completed with [errors] errors, [warnings] warnings and [success] successful steps.") + +#undef SETUP_OK +#undef SETUP_WARNING +#undef SETUP_ERROR +#undef SETUP_DELAYED \ No newline at end of file diff --git a/code/modules/power/fusion/core/_core.dm b/code/modules/power/fusion/core/_core.dm new file mode 100644 index 00000000..60bf67c6 --- /dev/null +++ b/code/modules/power/fusion/core/_core.dm @@ -0,0 +1,133 @@ +/* + TODO README +*/ + +var/list/fusion_cores = list() + +#define MAX_FIELD_STR 10000 +#define MIN_FIELD_STR 1 + +/obj/machinery/power/fusion_core + name = "\improper R-UST Mk. 8 Tokamak core" + desc = "An enormous solenoid for generating extremely high power electromagnetic fields. It includes a kinetic energy harvester." + icon = 'icons/obj/machines/power/fusion_core.dmi' + icon_state = "core0" + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + density = 1 + use_power = 1 + idle_power_usage = 50 + active_power_usage = 500 //multiplied by field strength + anchored = 0 + + var/obj/effect/fusion_em_field/owned_field + var/field_strength = 1//0.01 + var/id_tag + +/obj/machinery/power/fusion_core/mapped + anchored = 1 + +/obj/machinery/power/fusion_core/Initialize() + . = ..() + connect_to_network() + fusion_cores += src + +/obj/machinery/power/fusion_core/Destroy() + for(var/obj/machinery/computer/fusion_core_control/FCC in SSmachines.machinery) + FCC.connected_devices -= src + if(FCC.cur_viewed_device == src) + FCC.cur_viewed_device = null + fusion_cores -= src + return ..() + +/obj/machinery/power/fusion_core/Process() + if((stat & BROKEN) || !powernet || !owned_field) + Shutdown() + +/obj/machinery/power/fusion_core/Topic(href, href_list) + if(..()) + return 1 + if(href_list["str"]) + var/dif = text2num(href_list["str"]) + field_strength = min(max(field_strength + dif, MIN_FIELD_STR), MAX_FIELD_STR) + active_power_usage = 500 * field_strength + if(owned_field) + owned_field.ChangeFieldStrength(field_strength) + +/obj/machinery/power/fusion_core/proc/Startup() + if(owned_field) + return + owned_field = new(loc, src) + owned_field.ChangeFieldStrength(field_strength) + icon_state = "core1" + use_power = 2 + . = 1 + +/obj/machinery/power/fusion_core/proc/Shutdown(var/force_rupture) + if(owned_field) + icon_state = "core0" + if(force_rupture || owned_field.plasma_temperature > 1000) + owned_field.Rupture() + else + owned_field.RadiateAll() + qdel(owned_field) + owned_field = null + use_power = 1 + +/obj/machinery/power/fusion_core/proc/AddParticles(var/name, var/quantity = 1) + if(owned_field) + owned_field.AddParticles(name, quantity) + . = 1 + +/obj/machinery/power/fusion_core/bullet_act(var/obj/item/projectile/Proj) + if(owned_field) + . = owned_field.bullet_act(Proj) + +/obj/machinery/power/fusion_core/proc/set_strength(var/value) + value = Clamp(value, MIN_FIELD_STR, MAX_FIELD_STR) + field_strength = value + active_power_usage = 5 * value + if(owned_field) + owned_field.ChangeFieldStrength(value) + +/obj/machinery/power/fusion_core/attack_hand(var/mob/user) + if(!Adjacent(user)) // As funny as it was for the AI to hug-kill the tokamak field from a distance... + return + visible_message("\The [user] hugs \the [src] to make it feel better!") + if(owned_field) + Shutdown() + +/obj/machinery/power/fusion_core/attackby(var/obj/item/W, var/mob/user) + + if(owned_field) + to_chat(user,"Shut \the [src] off first!") + return + + if(isMultitool(W)) + var/new_ident = input("Enter a new ident tag.", "Fusion Core", id_tag) as null|text + if(new_ident && user.Adjacent(src)) + id_tag = new_ident + return + + else if(isWrench(W)) + anchored = !anchored + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + if(anchored) + user.visible_message("[user.name] secures [src.name] to the floor.", \ + "You secure the [src.name] to the floor.", \ + "You hear a ratchet") + else + user.visible_message("[user.name] unsecures [src.name] from the floor.", \ + "You unsecure the [src.name] from the floor.", \ + "You hear a ratchet") + return + + return ..() + +/obj/machinery/power/fusion_core/proc/jumpstart(var/field_temperature) + field_strength = 501 // Generally a good size. + Startup() + if(!owned_field) + return FALSE + owned_field.plasma_temperature = field_temperature + return TRUE \ No newline at end of file diff --git a/code/modules/power/fusion/core/core_control.dm b/code/modules/power/fusion/core/core_control.dm new file mode 100644 index 00000000..9cc1d649 --- /dev/null +++ b/code/modules/power/fusion/core/core_control.dm @@ -0,0 +1,177 @@ +/obj/machinery/computer/fusion_core_control + name = "\improper R-UST Mk. 8 core control" + icon_keyboard = "power_key" + icon_screen = "rust_screen" + light_color = COLOR_ORANGE + idle_power_usage = 250 + active_power_usage = 500 + + var/id_tag + var/scan_range = 25 + var/list/connected_devices = list() + var/obj/machinery/power/fusion_core/cur_viewed_device + +/obj/machinery/computer/fusion_core_control/attackby(var/obj/item/thing, var/mob/user) + if(isMultitool(thing)) + var/new_ident = input("Enter a new ident tag.", "Core Control", id_tag) as null|text + if(new_ident && user.Adjacent(src)) + id_tag = new_ident + cur_viewed_device = null + return + else + return ..() + +/obj/machinery/computer/fusion_core_control/attack_ai(mob/user) + attack_hand(user) + +/obj/machinery/computer/fusion_core_control/attack_hand(mob/user) + add_fingerprint(user) + interact(user) + +/obj/machinery/computer/fusion_core_control/interact(mob/user) + + if(!cur_viewed_device || !check_core_status(cur_viewed_device)) + cur_viewed_device = null + + if(!id_tag) + to_chat(user, "This console has not been assigned an ident tag. Please contact your system administrator or conduct a manual update with a standard multitool.") + return + + if(cur_viewed_device && (cur_viewed_device.id_tag != id_tag || get_dist(src, cur_viewed_device) > scan_range)) + cur_viewed_device = null + + var/dat = "Core Control #[id_tag]
            " + + if(cur_viewed_device) + dat += {" + Back to overview
            + Device ident '[cur_viewed_device.id_tag]' [cur_viewed_device.owned_field ? "active" : "inactive"].
            + Power status: [cur_viewed_device.avail()]/[cur_viewed_device.active_power_usage] W
            +
            + Bring field [cur_viewed_device.owned_field ? "offline" : "online"].
            +
            + Field power density (W.m-3):
            + ---- + --- + -- + - + [cur_viewed_device.field_strength] + + + ++ + +++ + ++++
            + "} + + if(cur_viewed_device.owned_field) + dat += {" + Approximate field diameter (m): [cur_viewed_device.owned_field.size]
            + Field instability: [cur_viewed_device.owned_field.percent_unstable * 100]%
            + Plasma temperature: [cur_viewed_device.owned_field.plasma_temperature + 295]K
            + Fuel:
            + + "} + for(var/reagent in cur_viewed_device.owned_field.reactants) + dat += "" + dat += "
            NameAmount
            [reagent][cur_viewed_device.owned_field.reactants[reagent]]

            " + + else + + connected_devices.Cut() + for(var/obj/machinery/power/fusion_core/C in fusion_cores) + if(C.id_tag == id_tag && get_dist(src, C) <= scan_range) + connected_devices += C + for(var/obj/machinery/power/fusion_core/C in gyrotrons) + if(C.id_tag == id_tag && get_dist(src, C) <= scan_range) + connected_devices += C + + if(connected_devices.len) + dat += {" + Connected EM field generators:
            + + + + + + + "} + + for(var/obj/machinery/power/fusion_core/C in connected_devices) + var/status + var/can_access = 1 + if(!check_core_status(C)) + status = "Unresponsive" + can_access = 0 + else if(C.avail() < C.active_power_usage) + status = "Underpowered" + else + status = "Good" + + dat += {" + + + + "} + + if(!can_access) + dat += {" + + "} + else + dat += {" + + "} + dat += {" + + "} + + else + dat += "No electromagnetic field generators connected." + + var/datum/browser/popup = new(user, "fusion_control", name, 500, 400, src) + popup.set_content(dat) + popup.open() + user.set_machine(src) + +/obj/machinery/computer/fusion_core_control/Topic(href, href_list) + if((. = ..())) + return + + if(href_list["access_device"]) + var/idx = Clamp(text2num(href_list["toggle_active"]), 1, connected_devices.len) + cur_viewed_device = connected_devices[idx] + updateUsrDialog() + return 1 + + //All HREFs from this point on require a device anyways. + if(!cur_viewed_device || !check_core_status(cur_viewed_device) || cur_viewed_device.id_tag != id_tag || get_dist(src, cur_viewed_device) > scan_range) + return + + if(href_list["goto_scanlist"]) + cur_viewed_device = null + updateUsrDialog() + return 1 + + if(href_list["toggle_active"]) + if(!cur_viewed_device.Startup()) //Startup() whilst the device is active will return null. + cur_viewed_device.Shutdown() + updateUsrDialog() + return 1 + + if(href_list["str"]) + var/val = text2num(href_list["str"]) + if(!val) //Value is 0, which is manual entering. + cur_viewed_device.set_strength(input("Enter the new field power density (W.m^-3)", "Fusion Control", cur_viewed_device.field_strength) as num) + else + cur_viewed_device.set_strength(cur_viewed_device.field_strength + val) + updateUsrDialog() + return 1 + +//Returns 1 if the machine can be interacted with via this console. +/obj/machinery/computer/fusion_core_control/proc/check_core_status(var/obj/machinery/power/fusion_core/C) + if(isnull(C)) + return + if(C.stat & BROKEN) + return + if(C.idle_power_usage > C.avail()) + return + . = 1 diff --git a/code/modules/power/fusion/core/core_field.dm b/code/modules/power/fusion/core/core_field.dm new file mode 100644 index 00000000..36fc4afa --- /dev/null +++ b/code/modules/power/fusion/core/core_field.dm @@ -0,0 +1,456 @@ +#define FUSION_ENERGY_PER_K 20 +#define FUSION_INSTABILITY_DIVISOR 50000 +#define FUSION_RUPTURE_THRESHOLD 10000 +#define FUSION_REACTANT_CAP 10000 + +/obj/effect/fusion_em_field + name = "electromagnetic field" + desc = "A coruscating, barely visible field of energy. It is shaped like a slightly flattened torus." + icon = 'icons/obj/machines/power/fusion.dmi' + icon_state = "emfield_s1" + alpha = 50 + layer = 4 + light_color = COLOR_BLUE + + var/size = 1 + var/energy = 0 + var/plasma_temperature = 0 + var/radiation = 0 + var/field_strength = 0.01 + var/tick_instability = 0 + var/percent_unstable = 0 + + var/obj/machinery/power/fusion_core/owned_core + var/list/reactants = list() + var/list/particle_catchers = list() + + var/list/ignore_types = list( + /obj/item/projectile, + /obj/effect, + /obj/structure/cable, + /obj/machinery/atmospherics + ) + + var/light_min_range = 2 + var/light_min_power = 3 + var/light_max_range = 12 + var/light_max_power = 12 + + var/last_range + var/last_power + +/obj/effect/fusion_em_field/New(loc, var/obj/machinery/power/fusion_core/new_owned_core) + ..() + + set_light(light_min_range,light_min_power) + last_range = light_min_range + last_power = light_min_power + + owned_core = new_owned_core + if(!owned_core) + qdel(src) + + //create the gimmicky things to handle field collisions + var/obj/effect/fusion_particle_catcher/catcher + + catcher = new (locate(src.x,src.y,src.z)) + catcher.parent = src + catcher.SetSize(1) + particle_catchers.Add(catcher) + + for(var/iter=1,iter<=6,iter++) + catcher = new (locate(src.x-iter,src.y,src.z)) + catcher.parent = src + catcher.SetSize((iter*2)+1) + particle_catchers.Add(catcher) + + catcher = new (locate(src.x+iter,src.y,src.z)) + catcher.parent = src + catcher.SetSize((iter*2)+1) + particle_catchers.Add(catcher) + + catcher = new (locate(src.x,src.y+iter,src.z)) + catcher.parent = src + catcher.SetSize((iter*2)+1) + particle_catchers.Add(catcher) + + catcher = new (locate(src.x,src.y-iter,src.z)) + catcher.parent = src + catcher.SetSize((iter*2)+1) + particle_catchers.Add(catcher) + + START_PROCESSING(SSobj, src) + +/obj/effect/fusion_em_field/Process() + //make sure the field generator is still intact + if(!owned_core || QDELETED(owned_core)) + qdel(src) + return + + // Take some gas up from our environment. + var/added_particles = FALSE + var/datum/gas_mixture/uptake_gas = owned_core.loc.return_air() + if(uptake_gas) + uptake_gas = uptake_gas.remove_by_flag(XGM_GAS_FUSION_FUEL, rand(50,100)) + if(uptake_gas && uptake_gas.total_moles) + for(var/gasname in uptake_gas.gas) + if(uptake_gas.gas[gasname]*10 > reactants[gasname]) + AddParticles(gasname, uptake_gas.gas[gasname]*10) + uptake_gas.adjust_gas(gasname, -(uptake_gas.gas[gasname]), update=FALSE) + added_particles = TRUE + if(added_particles) + uptake_gas.update_values() + + //let the particles inside the field react + React() + + // Dump power to our powernet. + owned_core.add_avail(FUSION_ENERGY_PER_K * plasma_temperature) + + // Energy decay. + if(plasma_temperature >= 1) + var/lost = plasma_temperature*0.01 + radiation += lost + plasma_temperature -= lost + + //handle some reactants formatting + for(var/reactant in reactants) + var/amount = reactants[reactant] + if(amount < 1) + reactants.Remove(reactant) + else if(amount >= FUSION_REACTANT_CAP) + var/radiate = rand(3 * amount / 4, amount / 4) + reactants[reactant] -= radiate + radiation += radiate + + var/use_range + var/use_power + if(plasma_temperature <= 6000) + use_range = light_min_range + use_power = light_min_power + else if(plasma_temperature >= 25000) + use_range = light_max_range + use_power = light_max_power + else + var/temp_mod = ((plasma_temperature-5000)/20000) + use_range = light_min_range + ceil((light_max_range-light_min_range)*temp_mod) + use_power = light_min_power + ceil((light_max_power-light_min_power)*temp_mod) + + if(last_range != use_range || last_power != use_power) + set_light(use_range,use_power) + last_range = use_range + last_power = use_power + + check_instability() + Radiate() + if(radiation) + radiation_repository.radiate(src, round(radiation*0.001)) + return 1 + +/obj/effect/fusion_em_field/proc/check_instability() + if(tick_instability > 0) + percent_unstable += (tick_instability*size)/FUSION_INSTABILITY_DIVISOR + tick_instability = 0 + else + if(percent_unstable < 0) + percent_unstable = 0 + else + if(percent_unstable > 1) + percent_unstable = 1 + if(percent_unstable > 0) + percent_unstable = max(0, percent_unstable-rand(0.01,0.03)) + + if(percent_unstable >= 1) + owned_core.Shutdown(force_rupture=1) + else + if(percent_unstable > 0.5 && prob(percent_unstable*100)) + if(plasma_temperature < FUSION_RUPTURE_THRESHOLD) + visible_message("\The [src] ripples uneasily, like a disturbed pond.") + else + var/flare + var/fuel_loss + var/rupture + if(percent_unstable < 0.7) + visible_message("\The [src] ripples uneasily, like a disturbed pond.") + fuel_loss = prob(5) + else if(percent_unstable < 0.9) + visible_message("\The [src] undulates violently, shedding plumes of plasma!") + flare = prob(50) + fuel_loss = prob(20) + rupture = prob(5) + else + visible_message("\The [src] is wracked by a series of horrendous distortions, buckling and twisting like a living thing!") + flare = 1 + fuel_loss = prob(50) + rupture = prob(25) + + if(rupture) + owned_core.Shutdown(force_rupture=1) + else + var/lost_plasma = (plasma_temperature*percent_unstable) + radiation += lost_plasma + if(flare) + radiation += plasma_temperature/2 + plasma_temperature -= lost_plasma + + if(fuel_loss) + for(var/particle in reactants) + var/lost_fuel = reactants[particle]*percent_unstable + radiation += lost_fuel + reactants[particle] -= lost_fuel + if(reactants[particle] <= 0) + reactants.Remove(particle) + Radiate() + return + +/obj/effect/fusion_em_field/proc/Rupture() + visible_message("\The [src] shudders like a dying animal before flaring to eye-searing brightness and rupturing!") + set_light(15, 15, "#ccccff") + empulse(get_turf(src), ceil(plasma_temperature/1000), ceil(plasma_temperature/300)) + sleep(5) + RadiateAll() + explosion(get_turf(owned_core),-1,-1,8,10) // Blow out all the windows. + return + +/obj/effect/fusion_em_field/proc/ChangeFieldStrength(var/new_strength) + var/calc_size = 1 + if(new_strength <= 50) + calc_size = 1 + else if(new_strength <= 200) + calc_size = 3 + else if(new_strength <= 500) + calc_size = 5 + else if(new_strength <= 1000) + calc_size = 7 + else if(new_strength <= 2000) + calc_size = 9 + else if(new_strength <= 5000) + calc_size = 11 + else + calc_size = 13 + field_strength = new_strength + change_size(calc_size) + +/obj/effect/fusion_em_field/proc/AddEnergy(var/a_energy, var/a_plasma_temperature) + energy += a_energy + plasma_temperature += a_plasma_temperature + if(a_energy && percent_unstable > 0) + percent_unstable -= a_energy/10000 + if(percent_unstable < 0) + percent_unstable = 0 + while(energy >= 100) + energy -= 100 + plasma_temperature += 1 + +/obj/effect/fusion_em_field/proc/AddParticles(var/name, var/quantity = 1) + if(name in reactants) + reactants[name] += quantity + else if(name != "proton" && name != "electron" && name != "neutron") + reactants.Add(name) + reactants[name] = quantity + +/obj/effect/fusion_em_field/proc/RadiateAll(var/ratio_lost = 1) + + // Create our plasma field and dump it into our environment. + var/turf/T = get_turf(src) + if(istype(T)) + var/datum/gas_mixture/plasma + for(var/reactant in reactants) + if(!gas_data.name[reactant]) + continue + if(!plasma) + plasma = new + plasma.adjust_gas(reactant, max(1,round(reactants[reactant]*0.1)), 0) // *0.1 to compensate for *10 when uptaking gas. + if(!plasma) + return + plasma.temperature = (plasma_temperature/2) + plasma.update_values() + T.assume_air(plasma) + T.hotspot_expose(plasma_temperature) + plasma = null + + // Radiate all our unspent fuel and energy. + for(var/particle in reactants) + radiation += reactants[particle] + reactants.Remove(particle) + radiation += plasma_temperature/2 + plasma_temperature = 0 + + radiation_repository.radiate(src, round(radiation*0.001)) + Radiate() + +/obj/effect/fusion_em_field/proc/Radiate() + if(istype(loc, /turf)) + var/empsev = max(1, min(3, ceil(size/2))) + for(var/atom/movable/AM in range(max(1,Floor(size/2)), loc)) + + if(AM == src || AM == owned_core || !AM.simulated) + continue + + var/skip_obstacle + for(var/ignore_path in ignore_types) + if(istype(AM, ignore_path)) + skip_obstacle = TRUE + break + if(skip_obstacle) + continue + + AM.visible_message("The field buckles visibly around \the [AM]!") + tick_instability += rand(30,50) + AM.emp_act(empsev) + + if(owned_core && owned_core.loc) + var/datum/gas_mixture/environment = owned_core.loc.return_air() + if(environment && environment.temperature < (T0C+1000)) // Putting an upper bound on it to stop it being used in a TEG. + environment.add_thermal_energy(plasma_temperature*20000) + radiation = 0 + +/obj/effect/fusion_em_field/proc/change_size(var/newsize = 1) + var/changed = 0 + + if( ((newsize-1)%2==0) && (newsize<=13) ) + icon = 'icons/obj/machines/power/fusion.dmi' + if(newsize>1) + icon = "icons/effects/[newsize*32]x[newsize*32].dmi" + icon_state = "emfield_s[newsize]" + pixel_x = ((newsize-1) * -16) * PIXEL_MULTIPLIER + pixel_y = ((newsize-1) * -16) * PIXEL_MULTIPLIER + size = newsize + changed = newsize + + for(var/obj/effect/fusion_particle_catcher/catcher in particle_catchers) + catcher.UpdateSize() + return changed + +//the !!fun!! part +/obj/effect/fusion_em_field/proc/React() + //loop through the reactants in random order + var/list/react_pool = reactants.Copy() + + //cant have any reactions if there aren't any reactants present + if(react_pool.len) + //determine a random amount to actually react this cycle, and remove it from the standard pool + //this is a hack, and quite nonrealistic :( + for(var/reactant in react_pool) + react_pool[reactant] = rand(Floor(react_pool[reactant]/2),react_pool[reactant]) + reactants[reactant] -= react_pool[reactant] + if(!react_pool[reactant]) + react_pool -= reactant + + //loop through all the reacting reagents, picking out random reactions for them + var/list/produced_reactants = new/list + var/list/p_react_pool = react_pool.Copy() + while(p_react_pool.len) + //pick one of the unprocessed reacting reagents randomly + var/cur_p_react = pick(p_react_pool) + p_react_pool.Remove(cur_p_react) + + //grab all the possible reactants to have a reaction with + var/list/possible_s_reacts = react_pool.Copy() + //if there is only one of a particular reactant, then it can not react with itself so remove it + possible_s_reacts[cur_p_react] -= 1 + if(possible_s_reacts[cur_p_react] < 1) + possible_s_reacts.Remove(cur_p_react) + + //loop through and work out all the possible reactions + var/list/possible_reactions = new/list + for(var/cur_s_react in possible_s_reacts) + if(possible_s_reacts[cur_s_react] < 1) + continue + var/decl/fusion_reaction/cur_reaction = get_fusion_reaction(cur_p_react, cur_s_react) + if(cur_reaction && plasma_temperature >= cur_reaction.minimum_energy_level) + possible_reactions.Add(cur_reaction) + + //if there are no possible reactions here, abandon this primary reactant and move on + if(!possible_reactions.len) + continue + + //split up the reacting atoms between the possible reactions + while(possible_reactions.len) + var/decl/fusion_reaction/cur_reaction = pick(possible_reactions) + possible_reactions.Remove(cur_reaction) + + //set the randmax to be the lower of the two involved reactants + var/max_num_reactants = react_pool[cur_reaction.p_react] > react_pool[cur_reaction.s_react] ? \ + react_pool[cur_reaction.s_react] : react_pool[cur_reaction.p_react] + if(max_num_reactants < 1) + continue + + //make sure we have enough energy + if(plasma_temperature < cur_reaction.minimum_reaction_temperature) + continue + + if(plasma_temperature < max_num_reactants * cur_reaction.energy_consumption) + max_num_reactants = round(plasma_temperature / cur_reaction.energy_consumption) + if(max_num_reactants < 1) + continue + + //randomly determined amount to react + var/amount_reacting = rand(1, max_num_reactants) + + //removing the reacting substances from the list of substances that are primed to react this cycle + //if there aren't enough of that substance (there should be) then modify the reactant amounts accordingly + if( react_pool[cur_reaction.p_react] - amount_reacting >= 0 ) + react_pool[cur_reaction.p_react] -= amount_reacting + else + amount_reacting = react_pool[cur_reaction.p_react] + react_pool[cur_reaction.p_react] = 0 + //same again for secondary reactant + if(react_pool[cur_reaction.s_react] - amount_reacting >= 0 ) + react_pool[cur_reaction.s_react] -= amount_reacting + else + react_pool[cur_reaction.p_react] += amount_reacting - react_pool[cur_reaction.p_react] + amount_reacting = react_pool[cur_reaction.s_react] + react_pool[cur_reaction.s_react] = 0 + + plasma_temperature -= max_num_reactants * cur_reaction.energy_consumption // Remove the consumed energy. + plasma_temperature += max_num_reactants * cur_reaction.energy_production // Add any produced energy. + radiation += max_num_reactants * cur_reaction.radiation // Add any produced radiation. + tick_instability += max_num_reactants * cur_reaction.instability + + // Create the reaction products. + for(var/reactant in cur_reaction.products) + var/success = 0 + for(var/check_reactant in produced_reactants) + if(check_reactant == reactant) + produced_reactants[reactant] += cur_reaction.products[reactant] * amount_reacting + success = 1 + break + if(!success) + produced_reactants[reactant] = cur_reaction.products[reactant] * amount_reacting + + // Handle anything special. If this proc returns true, abort the current reaction. + if(cur_reaction.handle_reaction_special(src)) + return + + // This reaction is done, and can't be repeated this sub-cycle. + possible_reactions.Remove(cur_reaction.s_react) + + // Loop through the newly produced reactants and add them to the pool. + for(var/reactant in produced_reactants) + AddParticles(reactant, produced_reactants[reactant]) + + // Check whether there are reactants left, and add them back to the pool. + for(var/reactant in react_pool) + AddParticles(reactant, react_pool[reactant]) + +/obj/effect/fusion_em_field/Destroy() + set_light(0) + RadiateAll() + for(var/obj/effect/fusion_particle_catcher/catcher in particle_catchers) + qdel(catcher) + if(owned_core) + owned_core.owned_field = null + owned_core = null + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/effect/fusion_em_field/bullet_act(var/obj/item/projectile/Proj) + AddEnergy(Proj.damage) + update_icon() + return 0 + +#undef FUSION_HEAT_CAP +#undef FUSION_INSTABILITY_DIVISOR +#undef FUSION_RUPTURE_THRESHOLD +#undef FUSION_REACTANT_CAP \ No newline at end of file diff --git a/code/modules/power/fusion/fuel_assembly/fuel_assembly.dm b/code/modules/power/fusion/fuel_assembly/fuel_assembly.dm new file mode 100644 index 00000000..584ceda6 --- /dev/null +++ b/code/modules/power/fusion/fuel_assembly/fuel_assembly.dm @@ -0,0 +1,70 @@ +/obj/item/weapon/fuel_assembly + name = "fuel rod assembly" + icon = 'icons/obj/machines/power/fusion.dmi' + icon_state = "fuel_assembly" + layer = 4 + + var/material_name + + var/percent_depleted = 1 + var/list/rod_quantities = list() + var/fuel_type = "composite" + var/fuel_colour + var/radioactivity = 0 + var/const/initial_amount = 300 + +/obj/item/weapon/fuel_assembly/New(var/newloc, var/_material, var/_colour) + fuel_type = _material + fuel_colour = _colour + ..(newloc) + +/obj/item/weapon/fuel_assembly/Initialize() + . = ..() + var/material/material = get_material_by_name(fuel_type) + if(istype(material)) + SetName("[material.use_name] fuel rod assembly") + desc = "A fuel rod for a fusion reactor. This one is made from [material.use_name]." + fuel_colour = material.icon_colour + fuel_type = material.use_name + if(material.radioactivity) + radioactivity = material.radioactivity + desc += " It is warm to the touch." + START_PROCESSING(SSobj, src) + if(material.luminescence) + set_light(material.luminescence, material.luminescence, material.icon_colour) + else + SetName("[fuel_type] fuel rod assembly") + desc = "A fuel rod for a fusion reactor. This one is made from [fuel_type]." + + icon_state = "blank" + var/image/I = image(icon, "fuel_assembly") + I.color = fuel_colour + overlays += list(I, image(icon, "fuel_assembly_bracket")) + rod_quantities[fuel_type] = initial_amount + +/obj/item/weapon/fuel_assembly/Process() + if(!radioactivity) + return PROCESS_KILL + + if(istype(loc, /turf)) + radiation_repository.radiate(src, max(1,ceil(radioactivity/30))) + +/obj/item/weapon/fuel_assembly/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +// Mapper shorthand. +/obj/item/weapon/fuel_assembly/deuterium/New(var/newloc) + ..(newloc, "deuterium") + +/obj/item/weapon/fuel_assembly/tritium/New(var/newloc) + ..(newloc, "tritium") + +/obj/item/weapon/fuel_assembly/phoron/New(var/newloc) + ..(newloc, "phoron") + +/obj/item/weapon/fuel_assembly/supermatter/New(var/newloc) + ..(newloc, "supermatter") + +/obj/item/fuel_assembly/hydrogen/New(var/newloc) + ..(newloc, "hydrogen") \ No newline at end of file diff --git a/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm b/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm new file mode 100644 index 00000000..52e6cf22 --- /dev/null +++ b/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm @@ -0,0 +1,51 @@ +/obj/machinery/fusion_fuel_compressor + name = "fuel compressor" + icon = 'icons/obj/machines/power/fusion.dmi' + icon_state = "fuel_compressor1" + density = 1 + anchored = 1 + layer = 4 + +/obj/machinery/fusion_fuel_compressor/MouseDrop_T(var/atom/movable/target, var/mob/user) + if(user.incapacitated() || !user.Adjacent(src)) + return + return do_fuel_compression(target, user) + +/obj/machinery/fusion_fuel_compressor/attackby(var/obj/item/thing, var/mob/user) + return do_fuel_compression(thing, user) || ..() + +/obj/machinery/fusion_fuel_compressor/proc/do_fuel_compression(var/obj/item/thing, var/mob/user) + if(istype(thing) && thing.reagents && thing.reagents.total_volume && thing.is_open_container()) + if(thing.reagents.reagent_list.len > 1) + to_chat(user, "The contents of \the [thing] are impure and cannot be used as fuel.") + return 1 + if(thing.reagents.total_volume < 50) + to_chat(user, "You need at least fifty units of material to form a fuel rod.") + return 1 + var/datum/reagent/R = thing.reagents.reagent_list[1] + visible_message("\The [src] compresses the contents of \the [thing] into a new fuel assembly.") + var/obj/item/weapon/fuel_assembly/F = new(get_turf(src), R.type, R.color) + thing.reagents.remove_reagent(R.type, R.volume) + user.put_in_hands(F) + return 1 + else if(istype(thing, /obj/machinery/power/supermatter/shard)) + var/obj/item/weapon/fuel_assembly/F = new(get_turf(src), "supermatter") + visible_message("\The [src] compresses the \[thing] into a new fuel assembly.") + qdel(thing) + user.put_in_hands(F) + return 1 + else if(istype(thing, /obj/item/stack/material)) + var/obj/item/stack/material/M = thing + var/material/mat = M.get_material() + if(!mat.is_fusion_fuel) + to_chat(user, "It would be pointless to make a fuel rod out of [mat.use_name].") + return + if(M.get_amount() < 25) + to_chat(user, "You need at least 25 [mat.sheet_plural_name] to make a fuel rod.") + return + var/obj/item/weapon/fuel_assembly/F = new(get_turf(src), mat.name) + visible_message("\The [src] compresses the [mat.use_name] into a new fuel assembly.") + M.use(25) + user.put_in_hands(F) + return 1 + return 0 diff --git a/code/modules/power/fusion/fuel_assembly/fuel_control.dm b/code/modules/power/fusion/fuel_assembly/fuel_control.dm new file mode 100644 index 00000000..411aeb41 --- /dev/null +++ b/code/modules/power/fusion/fuel_assembly/fuel_control.dm @@ -0,0 +1,105 @@ +/obj/machinery/computer/fusion_fuel_control + name = "fuel injection control computer" + icon_keyboard = "rd_key" + icon_screen = "fuel_screen" + light_color = COLOR_ORANGE + idle_power_usage = 250 + active_power_usage = 500 + + var/id_tag + var/scan_range = 25 + +/obj/machinery/computer/fusion_fuel_control/attack_ai(mob/user) + attack_hand(user) + +/obj/machinery/computer/fusion_fuel_control/attack_hand(mob/user) + add_fingerprint(user) + interact(user) + +/obj/machinery/computer/fusion_fuel_control/interact(var/mob/user) + + if(stat & (BROKEN|NOPOWER)) + user.unset_machine() + user << browse(null, "window=fuel_control") + return + + if (!istype(user, /mob/living/silicon) && get_dist(src, user) > 1) + user.unset_machine() + user << browse(null, "window=fuel_control") + return + + if(!id_tag) + to_chat(user, "This console has not been assigned an ident tag. Please contact your system administrator or conduct a manual update with a standard multitool.") + return + + var/dat = "Reactor Core Fuel Control #[id_tag]
            " + dat += {" +
            +
            Device tagStatusControls
            [C.id_tag][status]ERRORACCESS
            + + + + + "} + + for(var/obj/machinery/fusion_fuel_injector/I in fuel_injectors) + if(!id_tag || !I.id_tag || I.id_tag != id_tag || get_dist(src, I) > scan_range) + continue + + dat += "" + + if(I.stat & (BROKEN|NOPOWER)) + dat += "" + dat += "" + dat += "" + else + dat += "" + if(I.cur_assembly) + dat += "" + else + dat += "" + if(I.cur_assembly) + dat += "" + else + dat += "" + + dat += "" + + dat += {"
            ContainsAssemblyRemaining
            ERRORERRORERROR[I.cur_assembly ? I.cur_assembly.fuel_type : "NONE"]\[[I.injecting ? "Halt injecting" : "Begin injecting"]\]None[I.cur_assembly.percent_depleted * 100]%NA

            + Refresh + Close
            "} + + var/datum/browser/popup = new(user, "fuel_control", "Fusion Fuel Control Console", 800, 400, src) + popup.set_content(dat) + popup.open() + user.set_machine(src) + +/obj/machinery/computer/fusion_fuel_control/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["toggle_injecting"]) + var/obj/machinery/fusion_fuel_injector/I = locate(href_list["toggle_injecting"]) + if(I.id_tag != id_tag || get_dist(src, I) > scan_range) + return + + if(istype(I)) + if(I.injecting) + I.StopInjecting() + else + I.BeginInjecting() + + if( href_list["close"] ) + usr << browse(null, "window=fuel_control") + usr.unset_machine() + + updateDialog() + + +/obj/machinery/computer/fusion_fuel_control/attackby(var/obj/item/W, var/mob/user) + if(isMultitool(W)) + var/new_ident = input("Enter a new ident tag.", "Fuel Control", id_tag) as null|text + if(new_ident && user.Adjacent(src)) + id_tag = new_ident + return + return ..() diff --git a/code/modules/power/fusion/fuel_assembly/fuel_injector.dm b/code/modules/power/fusion/fuel_assembly/fuel_injector.dm new file mode 100644 index 00000000..34098e0d --- /dev/null +++ b/code/modules/power/fusion/fuel_assembly/fuel_injector.dm @@ -0,0 +1,153 @@ +var/list/fuel_injectors = list() + +/obj/machinery/fusion_fuel_injector + name = "fuel injector" + icon = 'icons/obj/machines/power/fusion.dmi' + icon_state = "injector0" + density = 1 + anchored = 0 + req_access = list(access_engine) + use_power = 1 + idle_power_usage = 10 + active_power_usage = 500 + + var/fuel_usage = 0.0001 + var/id_tag + var/injecting = 0 + var/obj/item/weapon/fuel_assembly/cur_assembly + +/obj/machinery/fusion_fuel_injector/New() + ..() + fuel_injectors += src + tag = null + +/obj/machinery/fusion_fuel_injector/Destroy() + if(cur_assembly) + cur_assembly.forceMove(get_turf(src)) + cur_assembly = null + fuel_injectors -= src + return ..() + +/obj/machinery/fusion_fuel_injector/mapped + anchored = 1 + +/obj/machinery/fusion_fuel_injector/Process() + if(injecting) + if(stat & (BROKEN|NOPOWER)) + StopInjecting() + else + Inject() + +/obj/machinery/fusion_fuel_injector/attackby(obj/item/W, mob/user) + + if(isMultitool(W)) + var/new_ident = input("Enter a new ident tag.", "Fuel Injector", id_tag) as null|text + if(new_ident && user.Adjacent(src)) + id_tag = new_ident + return + + if(istype(W, /obj/item/weapon/fuel_assembly)) + + if(injecting) + to_chat(user, "Shut \the [src] off before playing with the fuel rod!") + return + + if(cur_assembly) + cur_assembly.forceMove(get_turf(src)) + visible_message("\The [user] swaps \the [src]'s [cur_assembly] for \a [W].") + else + visible_message("\The [user] inserts \a [W] into \the [src].") + + user.drop_from_inventory(W) + W.forceMove(src) + if(cur_assembly) + cur_assembly.forceMove(get_turf(src)) + user.put_in_hands(cur_assembly) + cur_assembly = W + return + + if(isWrench(W)) + if(injecting) + to_chat(user, "Shut \the [src] off first!") + return + anchored = !anchored + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + if(anchored) + user.visible_message("\The [user] secures \the [src] to the floor.") + else + user.visible_message("\The [user] unsecures \the [src] from the floor.") + return + + return ..() + +/obj/machinery/fusion_fuel_injector/attack_hand(mob/user) + + if(injecting) + to_chat(user, "Shut \the [src] off before playing with the fuel rod!") + return + + if(cur_assembly) + cur_assembly.forceMove(get_turf(src)) + user.put_in_hands(cur_assembly) + visible_message("\The [user] removes \the [cur_assembly] from \the [src].") + cur_assembly = null + return + else + to_chat(user, "There is no fuel rod in \the [src].") + return + +/obj/machinery/fusion_fuel_injector/proc/BeginInjecting() + if(!injecting && cur_assembly) + icon_state = "injector1" + injecting = 1 + use_power = 1 + +/obj/machinery/fusion_fuel_injector/proc/StopInjecting() + if(injecting) + injecting = 0 + icon_state = "injector0" + use_power = 0 + +/obj/machinery/fusion_fuel_injector/proc/Inject() + if(!injecting) + return + if(cur_assembly) + var/amount_left = 0 + for(var/reagent in cur_assembly.rod_quantities) + if(cur_assembly.rod_quantities[reagent] > 0) + var/amount = cur_assembly.rod_quantities[reagent] * fuel_usage + var/numparticles = round(amount * 1000) + if(numparticles < 1) + numparticles = 1 + var/obj/effect/accelerated_particle/A = new/obj/effect/accelerated_particle(get_turf(src), dir) + A.particle_type = reagent + A.additional_particles = numparticles - 1 + A.move(1) + if(cur_assembly) + cur_assembly.rod_quantities[reagent] -= amount + amount_left += cur_assembly.rod_quantities[reagent] + if(cur_assembly) + cur_assembly.percent_depleted = amount_left / cur_assembly.initial_amount + flick("injector-emitting",src) + else + StopInjecting() + +/obj/machinery/fusion_fuel_injector/verb/rotate_clock() + set category = "Object" + set name = "Rotate Generator (Clockwise)" + set src in view(1) + + if (usr.incapacitated() || usr.restrained() || anchored) + return + + src.dir = turn(src.dir, -90) + +/obj/machinery/fusion_fuel_injector/verb/rotate_anticlock() + set category = "Object" + set name = "Rotate Generator (Counter-clockwise)" + set src in view(1) + + if (usr.incapacitated() || usr.restrained() || anchored) + return + + src.dir = turn(src.dir, 90) \ No newline at end of file diff --git a/code/modules/power/fusion/fusion_circuits.dm b/code/modules/power/fusion/fusion_circuits.dm new file mode 100644 index 00000000..d3bdc13f --- /dev/null +++ b/code/modules/power/fusion/fusion_circuits.dm @@ -0,0 +1,89 @@ +/obj/item/weapon/circuitboard/fusion_core_control + name = "circuit board (fusion core controller)" + build_path = /obj/machinery/computer/fusion_core_control + origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4) + +/obj/item/weapon/circuitboard/fusion_fuel_compressor + name = "circuit board (fusion fuel compressor)" + build_path = /obj/machinery/fusion_fuel_compressor + board_type = "machine" + origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 4, TECH_MATERIAL = 4) + req_components = list( + /obj/item/weapon/stock_parts/manipulator/pico = 2, + /obj/item/weapon/stock_parts/matter_bin/super = 2, + /obj/item/weapon/stock_parts/console_screen = 1, + /obj/item/stack/cable_coil = 5 + ) + +/obj/item/weapon/circuitboard/fusion_fuel_control + name = "circuit board (fusion fuel controller)" + build_path = /obj/machinery/computer/fusion_fuel_control + origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4) + +/obj/item/weapon/circuitboard/gyrotron_control + name = "circuit board (gyrotron controller)" + build_path = /obj/machinery/computer/gyrotron_control + origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4) + +/obj/item/weapon/circuitboard/fusion_core + name = "internal circuitry (fusion core)" + build_path = /obj/machinery/power/fusion_core + board_type = "machine" + origin_tech = list(TECH_BLUESPACE = 2, TECH_MAGNET = 4, TECH_POWER = 4) + req_components = list( + /obj/item/weapon/stock_parts/manipulator/pico = 2, + /obj/item/weapon/stock_parts/micro_laser/ultra = 1, + /obj/item/weapon/stock_parts/subspace/crystal = 1, + /obj/item/weapon/stock_parts/console_screen = 1, + /obj/item/stack/cable_coil = 5 + ) + +/obj/item/weapon/circuitboard/fusion_injector + name = "internal circuitry (fusion fuel injector)" + build_path = /obj/machinery/fusion_fuel_injector + board_type = "machine" + origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 4, TECH_MATERIAL = 4) + req_components = list( + /obj/item/weapon/stock_parts/manipulator/pico = 2, + /obj/item/weapon/stock_parts/scanning_module/phasic = 1, + /obj/item/weapon/stock_parts/matter_bin/super = 1, + /obj/item/weapon/stock_parts/console_screen = 1, + /obj/item/stack/cable_coil = 5 + ) + +/datum/design/circuit/fusion + name = "fusion core control console" + id = "fusion_core_control" + build_path = /obj/item/weapon/circuitboard/fusion_core_control + sort_string = "LAAAD" + req_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 3, TECH_MATERIAL = 3) + +/datum/design/circuit/fusion/fuel_compressor + name = "fusion fuel compressor" + id = "fusion_fuel_compressor" + build_path = /obj/item/weapon/circuitboard/fusion_fuel_compressor + sort_string = "LAAAE" + +/datum/design/circuit/fusion/fuel_control + name = "fusion fuel control console" + id = "fusion_fuel_control" + build_path = /obj/item/weapon/circuitboard/fusion_fuel_control + sort_string = "LAAAF" + +/datum/design/circuit/fusion/gyrotron_control + name = "gyrotron control console" + id = "gyrotron_control" + build_path = /obj/item/weapon/circuitboard/gyrotron_control + sort_string = "LAAAG" + +/datum/design/circuit/fusion/core + name = "fusion core" + id = "fusion_core" + build_path = /obj/item/weapon/circuitboard/fusion_core + sort_string = "LAAAH" + +/datum/design/circuit/fusion/injector + name = "fusion fuel injector" + id = "fusion_injector" + build_path = /obj/item/weapon/circuitboard/fusion_injector + sort_string = "LAAAI" diff --git a/code/modules/power/fusion/fusion_particle_catcher.dm b/code/modules/power/fusion/fusion_particle_catcher.dm new file mode 100644 index 00000000..d1bd9657 --- /dev/null +++ b/code/modules/power/fusion/fusion_particle_catcher.dm @@ -0,0 +1,41 @@ +/obj/effect/fusion_particle_catcher + icon = 'icons/effects/effects.dmi' + density = 1 + anchored = 1 + invisibility = 101 + var/obj/effect/fusion_em_field/parent + var/mysize = 0 + + light_color = COLOR_BLUE + +/obj/effect/fusion_particle_catcher/Destroy() + . =..() + parent.particle_catchers -= src + parent = null + +/obj/effect/fusion_particle_catcher/proc/SetSize(var/newsize) + name = "collector [newsize]" + mysize = newsize + UpdateSize() + +/obj/effect/fusion_particle_catcher/proc/AddParticles(var/name, var/quantity = 1) + if(parent && parent.size >= mysize) + parent.AddParticles(name, quantity) + return 1 + return 0 + +/obj/effect/fusion_particle_catcher/proc/UpdateSize() + if(parent.size >= mysize) + set_density(1) + SetName("collector [mysize] ON") + else + set_density(0) + SetName("collector [mysize] OFF") + +/obj/effect/fusion_particle_catcher/bullet_act(var/obj/item/projectile/Proj) + parent.AddEnergy(Proj.damage) + update_icon() + return 0 + +/obj/effect/fusion_particle_catcher/CanPass(var/atom/movable/mover, var/turf/target, var/height=0, var/air_group=0) + return ismob(mover) diff --git a/code/modules/power/fusion/fusion_reactions.dm b/code/modules/power/fusion/fusion_reactions.dm new file mode 100644 index 00000000..16240f9c --- /dev/null +++ b/code/modules/power/fusion/fusion_reactions.dm @@ -0,0 +1,164 @@ +var/list/fusion_reactions + +/decl/fusion_reaction + var/p_react = "" // Primary reactant. + var/s_react = "" // Secondary reactant. + var/minimum_energy_level = 1 + var/energy_consumption = 0 + var/energy_production = 0 + var/radiation = 0 + var/instability = 0 + var/list/products = list() + var/minimum_reaction_temperature = 100 + +/decl/fusion_reaction/proc/handle_reaction_special(var/obj/effect/fusion_em_field/holder) + return 0 + +proc/get_fusion_reaction(var/p_react, var/s_react, var/m_energy) + if(!fusion_reactions) + fusion_reactions = list() + for(var/rtype in typesof(/decl/fusion_reaction) - /decl/fusion_reaction) + var/decl/fusion_reaction/cur_reaction = new rtype() + if(!fusion_reactions[cur_reaction.p_react]) + fusion_reactions[cur_reaction.p_react] = list() + fusion_reactions[cur_reaction.p_react][cur_reaction.s_react] = cur_reaction + if(!fusion_reactions[cur_reaction.s_react]) + fusion_reactions[cur_reaction.s_react] = list() + fusion_reactions[cur_reaction.s_react][cur_reaction.p_react] = cur_reaction + + if(fusion_reactions.Find(p_react)) + var/list/secondary_reactions = fusion_reactions[p_react] + if(secondary_reactions.Find(s_react)) + return fusion_reactions[p_react][s_react] + +// Material fuels +// deuterium +// tritium +// phoron +// supermatter + +// Gaseous/reagent fuels +// hydrogen +// helium +// lithium +// boron + +// Basic power production reactions. +// This is not necessarily realistic, but it makes a basic failure more spectacular. +/decl/fusion_reaction/hydrogen_hydrogen + p_react = "hydrogen" + s_react = "hydrogen" + energy_consumption = 1 + energy_production = 2 + products = list("helium" = 1) + +/decl/fusion_reaction/deuterium_deuterium + p_react = "deuterium" + s_react = "deuterium" + energy_consumption = 1 + energy_production = 2 + +// Advanced production reactions (todo) +/decl/fusion_reaction/deuterium_helium + p_react = "deuterium" + s_react = "helium" + energy_consumption = 1 + energy_production = 5 + radiation = 2 + +/decl/fusion_reaction/deuterium_tritium + p_react = "deuterium" + s_react = "tritium" + energy_consumption = 1 + energy_production = 1 + products = list("helium" = 1) + instability = 0.5 + radiation = 3 + +/decl/fusion_reaction/deuterium_lithium + p_react = "deuterium" + s_react = "lithium" + energy_consumption = 2 + energy_production = 0 + radiation = 3 + products = list("tritium"= 1) + instability = 1 + +// Unideal/material production reactions +/decl/fusion_reaction/oxygen_oxygen + p_react = "oxygen" + s_react = "oxygen" + energy_consumption = 10 + energy_production = 0 + instability = 5 + radiation = 5 + products = list("silicon"= 1) + +/decl/fusion_reaction/iron_iron + p_react = "iron" + s_react = "iron" + products = list("silver" = 1, "gold" = 1, "platinum" = 1) // Not realistic but w/e + energy_consumption = 10 + energy_production = 0 + instability = 2 + minimum_reaction_temperature = 10000 + +/decl/fusion_reaction/phoron_hydrogen + p_react = "hydrogen" + s_react = "phoron" + energy_consumption = 10 + energy_production = 0 + instability = 5 + products = list("mydrogen" = 1) + minimum_reaction_temperature = 8000 + +// VERY UNIDEAL REACTIONS. +/decl/fusion_reaction/phoron_supermatter + p_react = "supermatter" + s_react = "phoron" + energy_consumption = 0 + energy_production = 5 + radiation = 20 + instability = 20 + +/decl/fusion_reaction/phoron_supermatter/handle_reaction_special(var/obj/effect/fusion_em_field/holder) + + wormhole_event() + + var/turf/origin = get_turf(holder) + holder.Rupture() + qdel(holder) + var/radiation_level = rand(100, 200) + + // Copied from the SM for proof of concept. //Not any more --Cirra //Use the whole z proc --Leshana + radiation_repository.z_radiate(locate(1, 1, holder.z), radiation_level, 1) + + for(var/mob/living/mob in GLOB.living_mob_list_) + var/turf/T = get_turf(mob) + if(T && (holder.z == T.z)) + if(istype(mob, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = mob + H.hallucination(rand(100,150), 51) + + for(var/obj/machinery/fusion_fuel_injector/I in range(world.view, origin)) + if(I.cur_assembly && I.cur_assembly.fuel_type == "supermatter") + explosion(get_turf(I), 1, 2, 3) + spawn(5) + if(I && I.loc) + qdel(I) + + sleep(5) + explosion(origin, 1, 2, 5) + + return 1 + + +// High end reactions. +/decl/fusion_reaction/boron_hydrogen + p_react = "boron" + s_react = "hydrogen" + minimum_energy_level = FUSION_HEAT_CAP * 0.5 + energy_consumption = 3 + energy_production = 15 + radiation = 3 + instability = 3 diff --git a/code/modules/power/fusion/gyrotron/gyrotron.dm b/code/modules/power/fusion/gyrotron/gyrotron.dm new file mode 100644 index 00000000..36d5f3c3 --- /dev/null +++ b/code/modules/power/fusion/gyrotron/gyrotron.dm @@ -0,0 +1,61 @@ +#define GYRO_POWER 25000 + +var/list/gyrotrons = list() + +/obj/machinery/power/emitter/gyrotron + name = "gyrotron" + icon = 'icons/obj/machines/power/fusion.dmi' + desc = "It is a heavy duty industrial gyrotron suited for powering fusion reactors." + icon_state = "emitter-off" + req_access = list(access_engine) + use_power = 1 + active_power_usage = GYRO_POWER + + var/id_tag + var/rate = 3 + var/mega_energy = 1 + + +/obj/machinery/power/emitter/gyrotron/anchored + anchored = 1 + state = 2 + +/obj/machinery/power/emitter/gyrotron/Initialize() + gyrotrons += src + active_power_usage = mega_energy * GYRO_POWER + . = ..() + +/obj/machinery/power/emitter/gyrotron/Destroy() + gyrotrons -= src + return ..() + +/obj/machinery/power/emitter/gyrotron/Process() + active_power_usage = mega_energy * GYRO_POWER + . = ..() + +/obj/machinery/power/emitter/gyrotron/get_rand_burst_delay() + return rate*10 + +/obj/machinery/power/emitter/gyrotron/get_burst_delay() + return rate*10 + +/obj/machinery/power/emitter/gyrotron/get_emitter_beam() + var/obj/item/projectile/beam/emitter/E = ..() + E.damage = mega_energy * 50 + return E + +/obj/machinery/power/emitter/gyrotron/update_icon() + if (active && powernet && avail(active_power_usage)) + icon_state = "emitter-on" + else + icon_state = "emitter-off" + +/obj/machinery/power/emitter/gyrotron/attackby(var/obj/item/W, var/mob/user) + if(isMultitool(W)) + var/new_ident = input("Enter a new ident tag.", "Gyrotron", id_tag) as null|text + if(new_ident && user.Adjacent(src)) + id_tag = new_ident + return + return ..() + +#undef GYRO_POWER \ No newline at end of file diff --git a/code/modules/power/fusion/gyrotron/gyrotron_control.dm b/code/modules/power/fusion/gyrotron/gyrotron_control.dm new file mode 100644 index 00000000..55132fd1 --- /dev/null +++ b/code/modules/power/fusion/gyrotron/gyrotron_control.dm @@ -0,0 +1,95 @@ +/obj/machinery/computer/gyrotron_control + name = "gyrotron control console" + icon_keyboard = "med_key" + icon_screen = "gyrotron_screen" + light_color = COLOR_BLUE + idle_power_usage = 250 + active_power_usage = 500 + + var/id_tag + var/scan_range = 25 + +/obj/machinery/computer/gyrotron_control/attack_ai(var/mob/user) + attack_hand(user) + +/obj/machinery/computer/gyrotron_control/attack_hand(var/mob/user) + add_fingerprint(user) + interact(user) + +/obj/machinery/computer/gyrotron_control/interact(var/mob/user) + + if(!id_tag) + to_chat(user, "This console has not been assigned an ident tag. Please contact your system administrator or conduct a manual update with a standard multitool.") + return + + var/dat = "
            Gyrotron controller #[id_tag]" + + dat = "" + dat += "" + dat += "" + dat += "" + dat += "" + + for(var/obj/machinery/power/emitter/gyrotron/G in gyrotrons) + if(!G || G.id_tag != id_tag || get_dist(src, G) > scan_range) + continue + + dat += "" + if(G.state != 2 || (G.stat & (NOPOWER | BROKEN))) //Error data not found. + dat += "" + dat += "" + dat += "" + else + dat += "" + dat += "" + dat += "" + + dat += "
            ModeFire DelayPower
            ERRORERRORERROR[G.active ? "Emitting" : "Standing By"][G.rate][G.mega_energy]
            " + + var/datum/browser/popup = new(user, "gyrotron_controller_[id_tag]", "Gyrotron Remote Control Console", 500, 400, src) + popup.set_content(dat) + popup.open() + add_fingerprint(user) + user.set_machine(src) + +/obj/machinery/computer/gyrotron_control/Topic(var/href, var/list/href_list) + if((. = ..())) + return + + var/obj/machinery/power/emitter/gyrotron/G = locate(href_list["machine"]) + if(!G || G.id_tag != id_tag || get_dist(src, G) > scan_range) + return + + if(href_list["modifypower"]) + var/new_val = input("Enter new emission power level (1 - 50)", "Modifying power level", G.mega_energy) as num + if(!new_val) + to_chat(usr, "That's not a valid number.") + return 1 + G.mega_energy = Clamp(new_val, 1, 50) + G.active_power_usage = G.mega_energy * 1500 + updateUsrDialog() + return 1 + + if(href_list["modifyrate"]) + var/new_val = input("Enter new emission delay between 1 and 10 seconds.", "Modifying emission rate", G.rate) as num + if(!new_val) + to_chat(usr, "That's not a valid number.") + return 1 + G.rate = Clamp(new_val, 1, 10) + updateUsrDialog() + return 1 + + if(href_list["toggle"]) + G.activate(usr) + updateUsrDialog() + return 1 + + return 0 + +/obj/machinery/computer/gyrotron_control/attackby(var/obj/item/W, var/mob/user) + if(isMultitool(W)) + var/new_ident = input("Enter a new ident tag.", "Gyrotron Control", id_tag) as null|text + if(new_ident && user.Adjacent(src)) + id_tag = new_ident + return + return ..() diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm new file mode 100644 index 00000000..d84a7b52 --- /dev/null +++ b/code/modules/power/generator.dm @@ -0,0 +1,260 @@ +/obj/machinery/power/generator + name = "thermoelectric generator" + desc = "It's a high efficiency thermoelectric generator." + icon_state = "teg" + density = 1 + anchored = 0 + + use_power = 1 + idle_power_usage = 100 //Watts, I hope. Just enough to do the computer and display things. + + var/max_power = 500000 + var/thermal_efficiency = 0.65 + + var/obj/machinery/atmospherics/binary/circulator/circ1 + var/obj/machinery/atmospherics/binary/circulator/circ2 + + var/last_circ1_gen = 0 + var/last_circ2_gen = 0 + var/last_thermal_gen = 0 + var/stored_energy = 0 + var/lastgen1 = 0 + var/lastgen2 = 0 + var/effective_gen = 0 + var/lastgenlev = 0 + +/obj/machinery/power/generator/New() + ..() + desc = initial(desc) + " Rated for [round(max_power/1000)] kW." + spawn(1) + reconnect() + +//generators connect in dir and reverse_dir(dir) directions +//mnemonic to determine circulator/generator directions: the cirulators orbit clockwise around the generator +//so a circulator to the NORTH of the generator connects first to the EAST, then to the WEST +//and a circulator to the WEST of the generator connects first to the NORTH, then to the SOUTH +//note that the circulator's outlet dir is it's always facing dir, and it's inlet is always the reverse +/obj/machinery/power/generator/proc/reconnect() + circ1 = null + circ2 = null + if(src.loc && anchored) + if(src.dir & (EAST|WEST)) + circ1 = locate(/obj/machinery/atmospherics/binary/circulator) in get_step(src,WEST) + circ2 = locate(/obj/machinery/atmospherics/binary/circulator) in get_step(src,EAST) + + if(circ1 && circ2) + if(!circ1.anchored || !circ2.anchored) + circ1 = null + circ2 = null + else if(circ1.inverted) + if(circ1.dir != SOUTH) + circ1 = null + circ2 = null + else if(circ1.dir != NORTH) + circ1 = null + circ2 = null + else if(circ2.inverted) + if(circ2.dir != NORTH) + circ1 = null + circ2 = null + else if(circ2.dir != SOUTH) + circ1 = null + circ2 = null + + else if(src.dir & (NORTH|SOUTH)) + circ1 = locate(/obj/machinery/atmospherics/binary/circulator) in get_step(src,NORTH) + circ2 = locate(/obj/machinery/atmospherics/binary/circulator) in get_step(src,SOUTH) + + if(circ1 && circ2) + if(!circ1.anchored || !circ2.anchored) + circ1 = null + circ2 = null + else if(circ1.inverted) + if(circ1.dir != WEST) + circ1 = null + circ2 = null + else if(circ1.dir != EAST) + circ1 = null + circ2 = null + else if(circ2.inverted) + if(circ2.dir != EAST) + circ1 = null + circ2 = null + else if(circ2.dir != WEST) + circ1 = null + circ2 = null + +/obj/machinery/power/generator/update_icon() + if(stat & (NOPOWER|BROKEN)) + overlays.Cut() + else + overlays.Cut() + + if(lastgenlev != 0) + overlays += image('icons/obj/power.dmi', "teg-op[lastgenlev]") + +/obj/machinery/power/generator/Process() + if(!circ1 || !circ2 || !anchored || stat & (BROKEN|NOPOWER)) + stored_energy = 0 + return + + updateDialog() + + var/datum/gas_mixture/air1 = circ1.return_transfer_air() + var/datum/gas_mixture/air2 = circ2.return_transfer_air() + + lastgen2 = lastgen1 + lastgen1 = 0 + last_thermal_gen = 0 + last_circ1_gen = 0 + last_circ2_gen = 0 + + if(air1 && air2) + var/air1_heat_capacity = air1.heat_capacity() + var/air2_heat_capacity = air2.heat_capacity() + var/delta_temperature = abs(air2.temperature - air1.temperature) + + if(delta_temperature > 0 && air1_heat_capacity > 0 && air2_heat_capacity > 0) + var/energy_transfer = delta_temperature*air2_heat_capacity*air1_heat_capacity/(air2_heat_capacity+air1_heat_capacity) + var/heat = energy_transfer*(1-thermal_efficiency) + last_thermal_gen = energy_transfer*thermal_efficiency + + if(air2.temperature > air1.temperature) + air2.temperature = air2.temperature - energy_transfer/air2_heat_capacity + air1.temperature = air1.temperature + heat/air1_heat_capacity + else + air2.temperature = air2.temperature + heat/air2_heat_capacity + air1.temperature = air1.temperature - energy_transfer/air1_heat_capacity + playsound(src.loc, 'sound/effects/beam.ogg', 25, 0, 10, is_ambiance = 1) + + //Transfer the air + if (air1) + circ1.air2.merge(air1) + if (air2) + circ2.air2.merge(air2) + + //Update the gas networks + if(circ1.network2) + circ1.network2.update = 1 + if(circ2.network2) + circ2.network2.update = 1 + + //Exceeding maximum power leads to some power loss + if(effective_gen > max_power && prob(5)) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + stored_energy *= 0.5 + + //Power + last_circ1_gen = circ1.return_stored_energy() + last_circ2_gen = circ2.return_stored_energy() + stored_energy += last_thermal_gen + last_circ1_gen + last_circ2_gen + lastgen1 = stored_energy*0.4 //smoothened power generation to prevent slingshotting as pressure is equalized, then restored by pumps + stored_energy -= lastgen1 + effective_gen = (lastgen1 + lastgen2) / 2 + + // update icon overlays and power usage only if displayed level has changed + var/genlev = max(0, min( round(11*effective_gen / max_power), 11)) + if(effective_gen > 100 && genlev == 0) + genlev = 1 + if(genlev != lastgenlev) + lastgenlev = genlev + update_icon() + add_avail(effective_gen) + +/obj/machinery/power/generator/attack_ai(mob/user) + attack_hand(user) + +/obj/machinery/power/generator/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isWrench(W)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + anchored = !anchored + user.visible_message("[user.name] [anchored ? "secures" : "unsecures"] the bolts holding [src.name] to the floor.", \ + "You [anchored ? "secure" : "unsecure"] the bolts holding [src] to the floor.", \ + "You hear a ratchet") + use_power = anchored + if(anchored) // Powernet connection stuff. + connect_to_network() + else + disconnect_from_network() + reconnect() + else + ..() + +/obj/machinery/power/generator/attack_hand(mob/user) + add_fingerprint(user) + if(stat & (BROKEN|NOPOWER) || !anchored) return + reconnect() //should prevent circulators from being apart from generator and still work + ui_interact(user) + +/obj/machinery/power/generator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + // this is the data which will be sent to the ui + var/vertical = 0 + if (dir == NORTH || dir == SOUTH) + vertical = 1 + + var/data[0] + data["totalOutput"] = effective_gen/1000 + data["maxTotalOutput"] = max_power/1000 + data["thermalOutput"] = last_thermal_gen/1000 + data["circConnected"] = 0 + + if(circ1) + //The one on the left (or top) + data["primaryDir"] = vertical ? "top" : "left" + data["primaryOutput"] = last_circ1_gen/1000 + data["primaryFlowCapacity"] = circ1.volume_capacity_used*100 + data["primaryInletPressure"] = circ1.air1.return_pressure() + data["primaryInletTemperature"] = circ1.air1.temperature + data["primaryOutletPressure"] = circ1.air2.return_pressure() + data["primaryOutletTemperature"] = circ1.air2.temperature + + if(circ2) + //Now for the one on the right (or bottom) + data["secondaryDir"] = vertical ? "bottom" : "right" + data["secondaryOutput"] = last_circ2_gen/1000 + data["secondaryFlowCapacity"] = circ2.volume_capacity_used*100 + data["secondaryInletPressure"] = circ2.air1.return_pressure() + data["secondaryInletTemperature"] = circ2.air1.temperature + data["secondaryOutletPressure"] = circ2.air2.return_pressure() + data["secondaryOutletTemperature"] = circ2.air2.temperature + + if(circ1 && circ2) + data["circConnected"] = 1 + else + data["circConnected"] = 0 + + + // update the ui if it exists, returns null if no ui is passed/found + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "generator.tmpl", "Thermoelectric Generator", 450, 500) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(1) + +/obj/machinery/power/generator/verb/rotate_clock() + set category = "Object" + set name = "Rotate Generator (Clockwise)" + set src in view(1) + + if (usr.stat || usr.restrained() || anchored) + return + + src.set_dir(turn(src.dir, 90)) + +/obj/machinery/power/generator/verb/rotate_anticlock() + set category = "Object" + set name = "Rotate Generator (Counterclockwise)" + set src in view(1) + + if (usr.stat || usr.restrained() || anchored) + return + + src.set_dir(turn(src.dir, -90)) diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm new file mode 100644 index 00000000..826cf9c9 --- /dev/null +++ b/code/modules/power/gravitygenerator.dm @@ -0,0 +1,114 @@ +// It.. uses a lot of power. Everything under power is engineering stuff, at least. + +/obj/machinery/computer/gravity_control_computer + name = "Gravity Generator Control" + desc = "A computer to control a local gravity generator. Qualified personnel only." + icon = 'icons/obj/computer.dmi' + icon_state = "airtunnel0e" + anchored = 1 + density = 1 + var/obj/machinery/gravity_generator/gravity_generator + +/obj/machinery/gravity_generator/ + name = "Gravitational Generator" + desc = "A device which produces a gravaton field when set up." + icon = 'icons/obj/singularity.dmi' + icon_state = "TheSingGen" + anchored = 1 + density = 1 + use_power = 1 + idle_power_usage = 200 + active_power_usage = 1000 + var/on = 1 + var/list/localareas = list() + var/effectiverange = 25 + + // Borrows code from cloning computer +/obj/machinery/computer/gravity_control_computer/Initialize() + . = ..() + updatemodules() + +/obj/machinery/gravity_generator/Initialize() + . = ..() + locatelocalareas() + +/obj/machinery/computer/gravity_control_computer/proc/updatemodules() + for(dir in list(NORTH,EAST,SOUTH,WEST)) + gravity_generator = locate(/obj/machinery/gravity_generator/, get_step(src, dir)) + if (gravity_generator) + return + +/obj/machinery/gravity_generator/proc/locatelocalareas() + for(var/area/A in range(src,effectiverange)) + if(istype(A,/area/space)) + continue // No (de)gravitizing space. + localareas |= A + +/obj/machinery/computer/gravity_control_computer/attack_ai(mob/user as mob) + return attack_hand(user) + +/obj/machinery/computer/gravity_control_computer/attack_hand(mob/user as mob) + user.set_machine(src) + add_fingerprint(user) + + if(stat & (BROKEN|NOPOWER)) + return + + updatemodules() + + var/dat = "

            Generator Control System

            " + //dat += "Refresh" + if(gravity_generator) + if(gravity_generator.on) + dat += "
            Gravity Status: ON

            " + else + dat += "
            Gravity Status: OFF

            " + + dat += "
            Currently Supplying Gravitons To:
            " + + for(var/area/A in gravity_generator.localareas) + if(A.has_gravity && gravity_generator.on) + dat += "[A]
            " + + else if (A.has_gravity) + dat += "[A]
            " + + else + dat += "[A]
            " + + dat += "
            Maintainence Functions:
            " + if(gravity_generator.on) + dat += " TURN GRAVITY GENERATOR OFF. " + else + dat += " TURN GRAVITY GENERATOR ON. " + + else + dat += "No local gravity generator detected!" + + user << browse(dat, "window=gravgen") + onclose(user, "gravgen") + + +/obj/machinery/computer/gravity_control_computer/Topic(href, href_list) + set background = 1 + if((. = ..())) + usr << browse(null, "window=air_alarm") + return + + if(href_list["gentoggle"]) + if(gravity_generator.on) + gravity_generator.on = 0 + + for(var/area/A in gravity_generator.localareas) + var/obj/machinery/gravity_generator/G + for(G in SSmachines.machinery) + if((A in G.localareas) && (G.on)) + break + if(!G) + A.gravitychange(0) + else + for(var/area/A in gravity_generator.localareas) + gravity_generator.on = 1 + A.gravitychange(1) + + src.updateUsrDialog() diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm new file mode 100644 index 00000000..d796b361 --- /dev/null +++ b/code/modules/power/lighting.dm @@ -0,0 +1,689 @@ +// The lighting system +// +// consists of light fixtures (/obj/machinery/light) and light tube/bulb items (/obj/item/weapon/light) + + +// status values shared between lighting fixtures and items +#define LIGHT_OK 0 +#define LIGHT_EMPTY 1 +#define LIGHT_BROKEN 2 +#define LIGHT_BURNED 3 + +#define LIGHT_BULB_TEMPERATURE 400 //K - used value for a 60W bulb +#define LIGHTING_POWER_FACTOR 5 //5W per luminosity * range + + +#define LIGHTMODE_EMERGENCY "emergency_lighting" +#define LIGHTMODE_READY "ready" + +/obj/machinery/light_construct + name = "light fixture frame" + desc = "A light fixture under construction." + icon = 'icons/obj/lighting.dmi' + icon_state = "tube-construct-stage1" + anchored = 1 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + + var/stage = 1 + var/fixture_type = /obj/machinery/light + var/sheets_refunded = 2 + +/obj/machinery/light_construct/New(atom/newloc, var/newdir, atom/fixture = null) + ..(newloc) + + if(newdir) + set_dir(newdir) + + if(istype(fixture)) + if(istype(fixture, /obj/machinery/light)) + fixture_type = fixture.type + fixture.transfer_fingerprints_to(src) + + update_icon() + +/obj/machinery/light_construct/update_icon() + switch(stage) + if(1) icon_state = "tube-construct-stage1" + if(2) icon_state = "tube-construct-stage2" + if(3) icon_state = "tube-empty" + +/obj/machinery/light_construct/examine(mob/user) + if(!..(user, 2)) + return + + switch(src.stage) + if(1) to_chat(user, "It's an empty frame.") + if(2) to_chat(user, "It's wired.") + if(3) to_chat(user, "The casing is closed.") +/obj/machinery/light_construct/attackby(obj/item/weapon/W as obj, mob/user as mob) + src.add_fingerprint(user) + if(isWrench(W)) + if (src.stage == 1) + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + to_chat(usr, "You begin deconstructing \a [src].") + if (!do_after(usr, 30,src)) + return + new /obj/item/stack/material/steel( get_turf(src.loc), sheets_refunded ) + user.visible_message("[user.name] deconstructs [src].", \ + "You deconstruct [src].", "You hear a noise.") + playsound(src.loc, 'sound/items/Deconstruct.ogg', 75, 1) + qdel(src) + if (src.stage == 2) + to_chat(usr, "You have to remove the wires first.") + return + + if (src.stage == 3) + to_chat(usr, "You have to unscrew the case first.") + return + + if(isWirecutter(W)) + if (src.stage != 2) return + src.stage = 1 + src.update_icon() + new /obj/item/stack/cable_coil(get_turf(src.loc), 1, "red") + user.visible_message("[user.name] removes the wiring from [src].", \ + "You remove the wiring from [src].", "You hear a noise.") + playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) + return + + if(istype(W, /obj/item/stack/cable_coil)) + if (src.stage != 1) return + var/obj/item/stack/cable_coil/coil = W + if (coil.use(1)) + src.stage = 2 + src.update_icon() + user.visible_message("[user.name] adds wires to [src].", \ + "You add wires to [src].") + return + + if(isScrewdriver(W)) + if (src.stage == 2) + src.stage = 3 + src.update_icon() + user.visible_message("[user.name] closes [src]'s casing.", \ + "You close [src]'s casing.", "You hear a noise.") + playsound(src.loc, 'sound/items/Screwdriver.ogg', 75, 1) + + var/obj/machinery/light/newlight = new fixture_type(src.loc, src) + newlight.set_dir(src.dir) + + src.transfer_fingerprints_to(newlight) + qdel(src) + return + ..() + +/obj/machinery/light_construct/small + name = "small light fixture frame" + desc = "A small light fixture under construction." + icon = 'icons/obj/lighting.dmi' + icon_state = "bulb-construct-stage1" + anchored = 1 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + stage = 1 + fixture_type = /obj/machinery/light/small + sheets_refunded = 1 + +/obj/machinery/light_construct/small/update_icon() + switch(stage) + if(1) icon_state = "bulb-construct-stage1" + if(2) icon_state = "bulb-construct-stage2" + if(3) icon_state = "bulb-empty" + +// the standard tube light fixture +/obj/machinery/light + name = "light fixture" + icon = 'icons/obj/lighting.dmi' + var/base_state = "tube" // base description and icon_state + icon_state = "tube1" + desc = "A lighting fixture." + anchored = 1 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER // They were appearing under mobs which is a little weird - Ostaf + use_power = 2 + idle_power_usage = 2 + active_power_usage = 20 + power_channel = LIGHT //Lights are calc'd via area so they dont need to be in the machine list + + var/on = 0 // 1 if on, 0 if off + var/flickering = 0 + var/light_type = /obj/item/weapon/light/tube // the type of light item + var/construct_type = /obj/machinery/light_construct + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + + var/obj/item/weapon/light/lightbulb + + var/current_mode = null + +// the smaller bulb light fixture +/obj/machinery/light/small + icon_state = "bulb1" + base_state = "bulb" + desc = "A small lighting fixture." + light_type = /obj/item/weapon/light/bulb + construct_type = /obj/machinery/light_construct/small + idle_power_usage = 1 + active_power_usage = 10 + +/obj/machinery/light/small/emergency + light_type = /obj/item/weapon/light/bulb/red + +/obj/machinery/light/small/red + light_type = /obj/item/weapon/light/bulb/red + +/obj/machinery/light/spot + name = "spotlight" + desc = "A more robust socket for light tubes that demand more power." + light_type = /obj/item/weapon/light/tube/large + +// create a new lighting fixture +/obj/machinery/light/New(atom/newloc, obj/machinery/light_construct/construct = null) + ..(newloc) + + s.set_up(1, 1, src) + + if(construct) + construct_type = construct.type + construct.transfer_fingerprints_to(src) + set_dir(construct.dir) + else + lightbulb = new light_type(src) + if(prob(lightbulb.broken_chance)) + broken(1) + + on = powered() + update_icon(0) + +/obj/machinery/light/Destroy() + QDEL_NULL(lightbulb) + QDEL_NULL(s) + . = ..() + +/obj/machinery/light/update_icon(var/trigger = 1) + + switch(get_status()) // set icon_states + if(LIGHT_OK) + icon_state = "[base_state][on]" + if(LIGHT_EMPTY) + icon_state = "[base_state]-empty" + on = 0 + if(LIGHT_BURNED) + icon_state = "[base_state]-burned" + on = 0 + if(LIGHT_BROKEN) + icon_state = "[base_state]-broken" + on = 0 + + if(on) + use_power = 2 + + var/changed = 0 + if(current_mode && (current_mode in lightbulb.lighting_modes)) + changed = set_light(arglist(lightbulb.lighting_modes[current_mode])) + else + changed = set_light(lightbulb.brightness_range, lightbulb.brightness_power, lightbulb.brightness_color) + + if(trigger && changed && get_status() == LIGHT_OK) + switch_check() + else + use_power = 0 + set_light(0) + + active_power_usage = ((light_range * light_power) * LIGHTING_POWER_FACTOR) + +/obj/machinery/light/proc/get_status() + if(!lightbulb) + return LIGHT_EMPTY + else + return lightbulb.status + +/obj/machinery/light/proc/switch_check() + lightbulb.switch_on() + if(get_status() != LIGHT_OK) + set_light(0) + +/obj/machinery/light/attack_generic(var/mob/user, var/damage) + if(!damage) + return + var/status = get_status() + if(status == LIGHT_EMPTY || status == LIGHT_BROKEN) + to_chat(user, "That object is useless to you.") + return + if(!(status == LIGHT_OK||status == LIGHT_BURNED)) + return + visible_message("[user] smashes the light!") + attack_animation(user) + broken() + return 1 + +/obj/machinery/light/proc/set_mode(var/new_mode) + if(current_mode != new_mode) + current_mode = new_mode + update_icon(0) + +/obj/machinery/light/proc/set_emergency_lighting(var/enable) + if(enable) + if(LIGHTMODE_EMERGENCY in lightbulb.lighting_modes) + set_mode(LIGHTMODE_EMERGENCY) + power_channel = ENVIRON + else + if(current_mode == LIGHTMODE_EMERGENCY) + set_mode(null) + power_channel = initial(power_channel) + +// attempt to set the light's on/off status +// will not switch on if broken/burned/empty +/obj/machinery/light/proc/seton(var/state) + on = (state && get_status() == LIGHT_OK) + update_icon() + +// examine verb +/obj/machinery/light/examine(mob/user) + . = ..() + var/fitting = get_fitting_name() + switch(get_status()) + if(LIGHT_OK) + to_chat(user, "[desc] It is turned [on? "on" : "off"].") + if(LIGHT_EMPTY) + to_chat(user, "[desc] The [fitting] has been removed.") + if(LIGHT_BURNED) + to_chat(user, "[desc] The [fitting] is burnt out.") + if(LIGHT_BROKEN) + to_chat(user, "[desc] The [fitting] has been smashed.") + +/obj/machinery/light/proc/get_fitting_name() + var/obj/item/weapon/light/L = light_type + return initial(L.name) + +// attack with item - insert light (if right type), otherwise try to break the light + +/obj/machinery/light/proc/insert_bulb(obj/item/weapon/light/L) + L.forceMove(src) + lightbulb = L + + on = powered() + update_icon() + +/obj/machinery/light/proc/remove_bulb() + . = lightbulb + lightbulb.dropInto(loc) + lightbulb.update_icon() + lightbulb = null + update_icon() + +/obj/machinery/light/attackby(obj/item/W, mob/user) + + //Light replacer code + if(istype(W, /obj/item/device/lightreplacer)) + var/obj/item/device/lightreplacer/LR = W + if(isliving(user)) + var/mob/living/U = user + LR.ReplaceLight(src, U) + return + + // attempt to insert light + if(istype(W, /obj/item/weapon/light)) + if(lightbulb) + to_chat(user, "There is a [get_fitting_name()] already inserted.") + return + if(!istype(W, light_type)) + to_chat(user, "This type of light requires a [get_fitting_name()].") + return + + to_chat(user, "You insert [W].") + user.drop_item() + insert_bulb(W) + src.add_fingerprint(user) + + // attempt to break the light + //If xenos decide they want to smash a light bulb with a toolbox, who am I to stop them? /N + + else if(lightbulb && (lightbulb.status != LIGHT_BROKEN)) + + if(prob(1 + W.force * 5)) + + user.visible_message("[user.name] smashed the light!", "You smash the light!", "You hear a tinkle of breaking glass") + if(on && (W.obj_flags & OBJ_FLAG_CONDUCTIBLE)) + if (prob(12)) + electrocute_mob(user, get_area(src), src, 0.3) + broken() + + else + to_chat(user, "You hit the light!") + + // attempt to stick weapon into light socket + else if(!lightbulb) + if(istype(W, /obj/item/weapon/screwdriver)) //If it's a screwdriver open it. + playsound(src.loc, 'sound/items/Screwdriver.ogg', 75, 1) + user.visible_message("[user.name] opens [src]'s casing.", "You open [src]'s casing.", "You hear a noise.") + new construct_type(src.loc, src.dir, src) + qdel(src) + return + + to_chat(user, "You stick \the [W] into the light socket!") + if(powered() && (W.obj_flags & OBJ_FLAG_CONDUCTIBLE)) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + if (prob(75)) + electrocute_mob(user, get_area(src), src, rand(0.7,1.0)) + + +// returns whether this light has power +// true if area has power and lightswitch is on +/obj/machinery/light/powered() + var/area/A = get_area(src) + return A && A.lightswitch && ..(power_channel) + +/obj/machinery/light/proc/flicker(var/amount = rand(10, 20)) + if(flickering) return + flickering = 1 + spawn(0) + if(on && get_status() == LIGHT_OK) + for(var/i = 0; i < amount; i++) + if(get_status() != LIGHT_OK) break + on = !on + update_icon(0) + sleep(rand(5, 15)) + on = (get_status() == LIGHT_OK) + update_icon(0) + flickering = 0 + +// ai attack - make lights flicker, because why not + +/obj/machinery/light/attack_ai(mob/user) + src.flicker(1) + +// attack with hand - remove tube/bulb +// if hands aren't protected and the light is on, burn the player +/obj/machinery/light/attack_hand(mob/user) + + add_fingerprint(user) + + if(!lightbulb) + to_chat(user, "There is no [get_fitting_name()] in this light.") + return + + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(H.species.can_shred(H)) + visible_message("[user.name] smashed the light!", 3, "You hear a tinkle of breaking glass") + broken() + return + + // make it burn hands if not wearing fire-insulated gloves + if(on) + var/prot = 0 + var/mob/living/carbon/human/H = user + + if(istype(H)) + if(H.getSpeciesOrSynthTemp(HEAT_LEVEL_1) > LIGHT_BULB_TEMPERATURE) + prot = 1 + else if(H.gloves) + var/obj/item/clothing/gloves/G = H.gloves + if(G.max_heat_protection_temperature) + if(G.max_heat_protection_temperature > LIGHT_BULB_TEMPERATURE) + prot = 1 + else + prot = 1 + + if(prot > 0 || (COLD_RESISTANCE in user.mutations)) + to_chat(user, "You remove the [get_fitting_name()]") + else if(TK in user.mutations) + to_chat(user, "You telekinetically remove the [get_fitting_name()].") + else + to_chat(user, "You try to remove the [get_fitting_name()], but it's too hot and you don't want to burn your hand.") + return // if burned, don't remove the light + else + to_chat(user, "You remove the [get_fitting_name()].") + + // create a light tube/bulb item and put it in the user's hand + user.put_in_active_hand(remove_bulb()) //puts it in our active hand + + +/obj/machinery/light/attack_tk(mob/user) + if(!lightbulb) + to_chat(user, "There is no [get_fitting_name()] in this light.") + return + + to_chat(user, "You telekinetically remove the [get_fitting_name()].") + remove_bulb() + +// ghost attack - make lights flicker like an AI, but even spookier! +/obj/machinery/light/attack_ghost(mob/user) + if(round_is_spooky()) + src.flicker(rand(2,5)) + else return ..() + +// break the light and make sparks if was on +/obj/machinery/light/proc/broken(var/skip_sound_and_sparks = 0) + if(!lightbulb) + return + + if(!skip_sound_and_sparks) + if(lightbulb && !(lightbulb.status == LIGHT_BROKEN)) + playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) + if(on) + s.set_up(3, 1, src) + s.start() + lightbulb.status = LIGHT_BROKEN + update_icon() + +/obj/machinery/light/proc/fix() + if(get_status() == LIGHT_OK) + return + lightbulb.status = LIGHT_OK + on = 1 + update_icon() + +// explosion effect +// destroy the whole light fixture or just shatter it + +/obj/machinery/light/ex_act(severity) + switch(severity) + if(1) + qdel(src) + return + if(2) + if (prob(75)) + broken() + if(3) + if (prob(50)) + broken() + +// timed process +// use power + +// called when area power state changes +/obj/machinery/light/power_change() + spawn(10) + seton(powered()) + +// called when on fire + +/obj/machinery/light/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(prob(max(0, exposed_temperature - 673))) //0% at <400C, 100% at >500C + broken() + +//Pow pow shoot that shit +/obj/machinery/light/bullet_act(obj/item/projectile/P) + . = ..() + if(!(P.nodamage) && P.damage_type == BRUTE && !QDELETED(src)) + broken() + return + +/obj/machinery/light/small/readylight + light_type = /obj/item/weapon/light/bulb/red/readylight + var/state = 0 + +/obj/machinery/light/small/readylight/proc/set_state(var/new_state) + state = new_state + if(state) + set_mode(LIGHTMODE_READY) + else + set_mode(null) + +// the light item +// can be tube or bulb subtypes +// will fit into empty /obj/machinery/light of the corresponding type + +/obj/item/weapon/light + icon = 'icons/obj/lighting.dmi' + force = 2 + throwforce = 5 + w_class = ITEM_SIZE_TINY + var/status = 0 // LIGHT_OK, LIGHT_BURNED or LIGHT_BROKEN + var/base_state + var/switchcount = 0 // number of times switched + matter = list(DEFAULT_WALL_MATERIAL = 60) + var/rigged = 0 // true if rigged to explode + var/broken_chance = 2 + + var/brightness_range = 2 //how much light it gives off + var/brightness_power = 1 + var/brightness_color = "#ffffff" + var/list/lighting_modes = list() + var/sound_on + +/obj/item/weapon/light/tube + name = "light tube" + desc = "A replacement light tube." + icon_state = "ltube" + base_state = "ltube" + item_state = "c_tube" + matter = list("glass" = 100) + + brightness_range = 5 // luminosity when on, also used in power calculation + brightness_power = 4 + brightness_color = "#B2B2B2"//"#FAE1AF"//"#C5D8B3"//#CDFEE0 + lighting_modes = list( + LIGHTMODE_EMERGENCY = list(l_range = 4, l_power = 1, l_color = "#da0205"), + ) + sound_on = 'sound/machines/lightson.ogg' + +/obj/item/weapon/light/tube/large + w_class = ITEM_SIZE_SMALL + name = "large light tube" + brightness_range = 9 + brightness_power = 6 + +/obj/item/weapon/light/bulb + name = "light bulb" + desc = "A replacement light bulb." + icon_state = "lbulb" + base_state = "lbulb" + item_state = "contvapour" + broken_chance = 5 + matter = list("glass" = 100) + + brightness_range = 4 + brightness_power = 3 + brightness_color = "#F9C763"//"#a0a080" + lighting_modes = list( + LIGHTMODE_EMERGENCY = list(l_range = 3, l_power = 1, l_color = "#da0205"), + ) + +/obj/item/weapon/light/bulb/red + color = "#da0205" + brightness_color = "#da0205" + +/obj/item/weapon/light/bulb/red/readylight + brightness_range = 5 + brightness_power = 2 + lighting_modes = list( + LIGHTMODE_READY = list(l_range = 5, l_power = 1, l_color = "#00ff00"), + ) + +/obj/item/weapon/light/throw_impact(atom/hit_atom) + ..() + shatter() + +/obj/item/weapon/light/bulb/fire + name = "fire bulb" + desc = "A replacement fire bulb." + icon_state = "fbulb" + base_state = "fbulb" + item_state = "egg4" + matter = list("glass" = 100) + brightness_range = 4 + brightness_power = 4 + +// update the icon state and description of the light +/obj/item/weapon/light/update_icon() + switch(status) + if(LIGHT_OK) + icon_state = base_state + desc = "A replacement [name]." + if(LIGHT_BURNED) + icon_state = "[base_state]-burned" + desc = "A burnt-out [name]." + if(LIGHT_BROKEN) + icon_state = "[base_state]-broken" + desc = "A broken [name]." + +/obj/item/weapon/light/New(atom/newloc, obj/machinery/light/fixture = null) + ..() + update_icon() + +// attack bulb/tube with object +// if a syringe, can inject phoron to make it explode +/obj/item/weapon/light/attackby(var/obj/item/I, var/mob/user) + ..() + if(istype(I, /obj/item/weapon/reagent_containers/syringe)) + var/obj/item/weapon/reagent_containers/syringe/S = I + + to_chat(user, "You inject the solution into the [src].") + + if(S.reagents.has_reagent(/datum/reagent/toxin/phoron, 5)) + + log_admin("LOG: [user.name] ([user.ckey]) injected a light with phoron, rigging it to explode.") + message_admins("LOG: [user.name] ([user.ckey]) injected a light with phoron, rigging it to explode.") + + rigged = 1 + + S.reagents.clear_reagents() + else + ..() + return + +// called after an attack with a light item +// shatter light, unless it was an attempt to put it in a light socket +// now only shatter if the intent was harm + +/obj/item/weapon/light/afterattack(atom/target, mob/user, proximity) + if(!proximity) return + if(istype(target, /obj/machinery/light)) + return + if(user.a_intent != I_HURT) + return + + shatter() + +/obj/item/weapon/light/proc/shatter() + if(status == LIGHT_OK || status == LIGHT_BURNED) + src.visible_message("[name] shatters.","You hear a small glass object shatter.") + status = LIGHT_BROKEN + force = 5 + sharp = 1 + playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) + update_icon() + +/obj/item/weapon/light/proc/switch_on() + switchcount++ + if(rigged) + log_admin("LOG: Rigged light explosion, last touched by [fingerprintslast]") + message_admins("LOG: Rigged light explosion, last touched by [fingerprintslast]") + var/turf/T = get_turf(src.loc) + spawn(0) + sleep(2) + explosion(T, 0, 0, 3, 5) + sleep(1) + qdel(src) + status = LIGHT_BROKEN + else if(prob(min(60, switchcount*switchcount*0.01))) + status = LIGHT_BURNED + else if(sound_on) + playsound(get_turf(src),sound_on, 40) + return status diff --git a/code/modules/power/pacman2.dm b/code/modules/power/pacman2.dm new file mode 100644 index 00000000..97c8d34e --- /dev/null +++ b/code/modules/power/pacman2.dm @@ -0,0 +1,170 @@ +//This file was auto-corrected by findeclaration.exe on 29/05/2012 15:03:05 + + +//PACMAN variant that can run on the small plasma tanks. +/obj/machinery/power/port_gen/pacman2 + name = "Pacman II" + desc = "P.A.C.M.A.N. type II portable generator. Uses liquid phoron as a fuel source." + power_gen = 4500 + var/obj/item/weapon/tank/phoron/P = null + var/board_path = /obj/item/weapon/circuitboard/pacman2 + var/emagged = 0 + var/heat = 0 +/* + process() + if(P) + if(P.air_contents.phoron <= 0) + P.air_contents.phoron = 0 + eject() + else + P.air_contents.phoron -= 0.001 + return +*/ + + HasFuel() + if(P.air_contents.phoron >= 0.1) + return 1 + return 0 + + UseFuel() + P.air_contents.phoron -= 0.01 + return + + New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) + component_parts += new /obj/item/stack/cable_coil(src) + component_parts += new /obj/item/stack/cable_coil(src) + component_parts += new /obj/item/weapon/stock_parts/capacitor(src) + component_parts += new board_path(src) + RefreshParts() + + RefreshParts() + var/temp_rating = 0 + for(var/obj/item/weapon/stock_parts/SP in component_parts) + if(istype(SP, /obj/item/weapon/stock_parts/matter_bin)) + //max_coins = SP.rating * SP.rating * 1000 + else if(istype(SP, /obj/item/weapon/stock_parts/micro_laser) || istype(SP, /obj/item/weapon/stock_parts/capacitor)) + temp_rating += SP.rating + power_gen = round(initial(power_gen) * (max(2, temp_rating) / 2)) + + examine(mob/user) + . = ..(user) + to_chat(user, "The generator has [P.air_contents.phoron] units of fuel left, producing [power_gen] per cycle.") + handleInactive() + heat -= 2 + if (heat < 0) + heat = 0 + else + for(var/mob/M in viewers(1, src)) + if (M.client && M.machine == src) + src.updateUsrDialog() + + proc + overheat() + explosion(get_turf(src), 2, 5, 2, -1) + + attackby(var/obj/item/O as obj, var/mob/user as mob) + if(istype(O, /obj/item/weapon/tank/phoron)) + if(P) + to_chat(user, "The generator already has a phoron tank loaded!") + return + P = O + user.drop_item() + O.loc = src + to_chat(user, "You add the phoron tank to the generator.") + else if(!active) + if(isWrench(O)) + anchored = !anchored + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + if(anchored) + to_chat(user, "You secure the generator to the floor.") + else + to_chat(user, "You unsecure the generator from the floor.") + SSmachines.makepowernets() + else if(isScrewdriver(O)) + open = !open + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + if(open) + to_chat(user, "You open the access panel.") + else + to_chat(user, "You close the access panel.") + else if(isCrowbar(O) && !open) + var/obj/machinery/constructable_frame/machine_frame/new_frame = new /obj/machinery/constructable_frame/machine_frame(src.loc) + for(var/obj/item/I in component_parts) + I.loc = src.loc + new_frame.state = 2 + new_frame.icon_state = "box_1" + qdel(src) + + attack_hand(mob/user as mob) + ..() + if (!anchored) + return + + interact(user) + + attack_ai(mob/user as mob) + interact(user) + + attack_paw(mob/user as mob) + interact(user) + + proc + interact(mob/user) + if (get_dist(src, user) > 1 ) + if (!istype(user, /mob/living/silicon/ai)) + user.machine = null + user << browse(null, "window=port_gen") + return + + user.machine = src + + var/dat = text("[name]
            ") + if (active) + dat += text("Generator: On
            ") + else + dat += text("Generator: Off
            ") + if(P) + dat += text("Currently loaded phoron tank: [P.air_contents.phoron]
            ") + else + dat += text("No phoron tank currently loaded.
            ") + dat += text("Power output: - [power_gen * power_output] +
            ") + dat += text("Heat: [heat]
            ") + dat += "
            Close" + user << browse("[dat]", "window=port_gen") + + Topic(href, href_list) + if(..()) + return + + src.add_fingerprint(usr) + if(href_list["action"]) + if(href_list["action"] == "enable") + if(!active && HasFuel()) + active = 1 + icon_state = "portgen1" + src.updateUsrDialog() + if(href_list["action"] == "disable") + if (active) + active = 0 + icon_state = "portgen0" + src.updateUsrDialog() + if(href_list["action"] == "lower_power") + if (power_output > 1) + power_output-- + src.updateUsrDialog() + if (href_list["action"] == "higher_power") + if (power_output < 4 || emagged) + power_output++ + src.updateUsrDialog() + if (href_list["action"] == "close") + usr << browse(null, "window=port_gen") + usr.machine = null + +/obj/machinery/power/port_gen/pacman2/emag_act(var/remaining_uses, var/mob/user) + emagged = 1 + emp_act(1) + return 1 diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm new file mode 100644 index 00000000..28bb1d27 --- /dev/null +++ b/code/modules/power/port_gen.dm @@ -0,0 +1,517 @@ +//Baseline portable generator. Has all the default handling. Not intended to be used on it's own (since it generates unlimited power). +/obj/machinery/power/port_gen + name = "Placeholder Generator" //seriously, don't use this. It can't be anchored without VV magic. + desc = "A portable generator for emergency backup power." + icon = 'icons/obj/power.dmi' + icon_state = "portgen0" + density = 1 + anchored = 0 + use_power = 0 + + var/active = 0 + var/power_gen = 5000 + var/open = 0 + var/recent_fault = 0 + var/power_output = 1 + atom_flags = ATOM_FLAG_CLIMBABLE + +/obj/machinery/power/port_gen/proc/IsBroken() + return (stat & (BROKEN|EMPED)) + +/obj/machinery/power/port_gen/proc/HasFuel() //Placeholder for fuel check. + return 1 + +/obj/machinery/power/port_gen/proc/UseFuel() //Placeholder for fuel use. + return + +/obj/machinery/power/port_gen/proc/DropFuel() + return + +/obj/machinery/power/port_gen/proc/handleInactive() + return + +/obj/machinery/power/port_gen/Process() + if(active && HasFuel() && !IsBroken() && anchored && powernet) + add_avail(power_gen * power_output) + UseFuel() + src.updateDialog() + else + active = 0 + handleInactive() + update_icon() + +/obj/machinery/power/port_gen/update_icon() + if(!active) + icon_state = initial(icon_state) + return 1 + else + icon_state = "[initial(icon_state)]on" + +/obj/machinery/power/port_gen/attack_hand(mob/user as mob) + if(..()) + return + if(!anchored) + to_chat(usr, "The generator needs to be secured first.") + return + +/obj/machinery/power/port_gen/examine(mob/user) + if(!..(user,1 )) + return + if(active) + to_chat(usr, "The generator is on.") + else + to_chat(usr, "The generator is off.") +/obj/machinery/power/port_gen/emp_act(severity) + if(!active) + return + var/duration = 6000 //ten minutes + switch(severity) + if(1) + stat &= BROKEN + if(prob(75)) explode() + if(2) + if(prob(25)) stat &= BROKEN + if(prob(10)) explode() + if(3) + if(prob(10)) stat &= BROKEN + duration = 300 + + stat |= EMPED + if(duration) + spawn(duration) + stat &= ~EMPED + +/obj/machinery/power/port_gen/proc/explode() + explosion(src.loc, -1, 3, 5, -1) + qdel(src) + +#define TEMPERATURE_DIVISOR 40 +#define TEMPERATURE_CHANGE_MAX 20 + +//A power generator that runs on solid plasma sheets. +/obj/machinery/power/port_gen/pacman + name = "\improper P.A.C.M.A.N.-type Portable Generator" + desc = "A power generator that runs on solid phoron sheets. Rated for 80 kW max safe output." + + var/sheet_name = "Phoron Sheets" + var/sheet_path = /obj/item/stack/material/phoron + var/board_path = /obj/item/weapon/circuitboard/pacman + + /* + These values were chosen so that the generator can run safely up to 80 kW + A full 50 phoron sheet stack should last 20 minutes at power_output = 4 + temperature_gain and max_temperature are set so that the max safe power level is 4. + Setting to 5 or higher can only be done temporarily before the generator overheats. + */ + power_gen = 20000 //Watts output per power_output level + var/max_power_output = 5 //The maximum power setting without emagging. + var/max_safe_output = 4 // For UI use, maximal output that won't cause overheat. + var/time_per_sheet = 96 //fuel efficiency - how long 1 sheet lasts at power level 1 + var/max_sheets = 100 //max capacity of the hopper + var/max_temperature = 300 //max temperature before overheating increases + var/temperature_gain = 50 //how much the temperature increases per power output level, in degrees per level + + var/sheets = 0 //How many sheets of material are loaded in the generator + var/sheet_left = 0 //How much is left of the current sheet + var/temperature = 0 //The current temperature + var/overheating = 0 //if this gets high enough the generator explodes + var/max_overheat = 150 + +/obj/machinery/power/port_gen/pacman/Initialize() + . = ..() + if(anchored) + connect_to_network() + +/obj/machinery/power/port_gen/pacman/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) + component_parts += new /obj/item/stack/cable_coil(src) + component_parts += new /obj/item/stack/cable_coil(src) + component_parts += new /obj/item/weapon/stock_parts/capacitor(src) + component_parts += new board_path(src) + RefreshParts() + +/obj/machinery/power/port_gen/pacman/Destroy() + DropFuel() + return ..() + +/obj/machinery/power/port_gen/pacman/RefreshParts() + var/temp_rating = 0 + for(var/obj/item/weapon/stock_parts/SP in component_parts) + if(istype(SP, /obj/item/weapon/stock_parts/matter_bin)) + max_sheets = SP.rating * SP.rating * 50 + else if(istype(SP, /obj/item/weapon/stock_parts/micro_laser) || istype(SP, /obj/item/weapon/stock_parts/capacitor)) + temp_rating += SP.rating + + power_gen = round(initial(power_gen) * (max(2, temp_rating) / 2)) + +/obj/machinery/power/port_gen/pacman/examine(mob/user) + . = ..(user) + to_chat(user, "\The [src] appears to be producing [power_gen*power_output] W.") + to_chat(user, "There [sheets == 1 ? "is" : "are"] [sheets] sheet\s left in the hopper.") + if(IsBroken()) to_chat(user, "\The [src] seems to have broken down.") + if(overheating) to_chat(user, "\The [src] is overheating!") +/obj/machinery/power/port_gen/pacman/HasFuel() + var/needed_sheets = power_output / time_per_sheet + if(sheets >= needed_sheets - sheet_left) + return 1 + return 0 + +//Removes one stack's worth of material from the generator. +/obj/machinery/power/port_gen/pacman/DropFuel() + if(sheets) + var/obj/item/stack/material/S = new sheet_path(loc) + var/amount = min(sheets, S.max_amount) + S.amount = amount + sheets -= amount + +/obj/machinery/power/port_gen/pacman/UseFuel() + + //how much material are we using this iteration? + var/needed_sheets = power_output / time_per_sheet + + //HasFuel() should guarantee us that there is enough fuel left, so no need to check that + //the only thing we need to worry about is if we are going to rollover to the next sheet + if (needed_sheets > sheet_left) + sheets-- + sheet_left = (1 + sheet_left) - needed_sheets + else + sheet_left -= needed_sheets + + //calculate the "target" temperature range + //This should probably depend on the external temperature somehow, but whatever. + var/lower_limit = 56 + power_output * temperature_gain + var/upper_limit = 76 + power_output * temperature_gain + /* + Hot or cold environments can affect the equilibrium temperature + The lower the pressure the less effect it has. I guess it cools using a radiator or something when in vacuum. + Gives traitors more opportunities to sabotage the generator or allows enterprising engineers to build additional + cooling in order to get more power out. + */ + var/datum/gas_mixture/environment = loc.return_air() + if (environment) + var/outer_temp = 0.1 * temperature + T0C + if(outer_temp > environment.temperature) //sharing the heat + var/heat_transfer = environment.get_thermal_energy_change(outer_temp) + if(heat_transfer > 1) + var/heating_power = 0.1 * power_gen * power_output + heat_transfer = min(heat_transfer, heating_power) + environment.add_thermal_energy(heat_transfer) + + var/ratio = min(environment.return_pressure()/ONE_ATMOSPHERE, 1) + var/ambient = environment.temperature - T20C + lower_limit += ambient*ratio + upper_limit += ambient*ratio + + var/average = (upper_limit + lower_limit)/2 + + //calculate the temperature increase + var/bias = Clamp(round((average - temperature)/TEMPERATURE_DIVISOR, 1), -TEMPERATURE_CHANGE_MAX, TEMPERATURE_CHANGE_MAX) + temperature += bias + rand(-7, 7) + + if (temperature > max_temperature) + overheat() + else if (overheating > 0) + overheating-- + +/obj/machinery/power/port_gen/pacman/handleInactive() + var/cooling_temperature = 20 + var/datum/gas_mixture/environment = loc.return_air() + if (environment) + var/ratio = min(environment.return_pressure()/ONE_ATMOSPHERE, 1) + var/ambient = environment.temperature - T20C + cooling_temperature += ambient*ratio + + if (temperature > cooling_temperature) + var/temp_loss = (temperature - cooling_temperature)/TEMPERATURE_DIVISOR + temp_loss = between(2, round(temp_loss, 1), TEMPERATURE_CHANGE_MAX) + temperature = max(temperature - temp_loss, cooling_temperature) + src.updateDialog() + + if(overheating) + overheating-- + +/obj/machinery/power/port_gen/pacman/proc/overheat() + overheating++ + if (overheating > max_overheat) + explode() + +/obj/machinery/power/port_gen/pacman/explode() + //Vapourize all the phoron + //When ground up in a grinder, 1 sheet produces 20 u of phoron -- Chemistry-Machinery.dm + //1 mol = 10 u? I dunno. 1 mol of carbon is definitely bigger than a pill + var/phoron = (sheets+sheet_left)*20 + var/datum/gas_mixture/environment = loc.return_air() + if (environment) + environment.adjust_gas_temp("phoron", phoron/10, temperature + T0C) + + sheets = 0 + sheet_left = 0 + ..() + +/obj/machinery/power/port_gen/pacman/emag_act(var/remaining_charges, var/mob/user) + if (active && prob(25)) + explode() //if they're foolish enough to emag while it's running + + if (!emagged) + emagged = 1 + return 1 + +/obj/machinery/power/port_gen/pacman/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(istype(O, sheet_path)) + var/obj/item/stack/addstack = O + var/amount = min((max_sheets - sheets), addstack.amount) + if(amount < 1) + to_chat(user, "The [src.name] is full!") + return + to_chat(user, "You add [amount] sheet\s to the [src.name].") + sheets += amount + addstack.use(amount) + updateUsrDialog() + return + else if(!active) + if(isWrench(O)) + + if(!anchored) + connect_to_network() + to_chat(user, "You secure the generator to the floor.") + else + disconnect_from_network() + to_chat(user, "You unsecure the generator from the floor.") + + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + anchored = !anchored + + else if(isScrewdriver(O)) + open = !open + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + if(open) + to_chat(user, "You open the access panel.") + else + to_chat(user, "You close the access panel.") + else if(isCrowbar(O) && open) + var/obj/machinery/constructable_frame/machine_frame/new_frame = new /obj/machinery/constructable_frame/machine_frame(src.loc) + for(var/obj/item/I in component_parts) + I.loc = src.loc + while ( sheets > 0 ) + DropFuel() + + new_frame.state = 2 + new_frame.icon_state = "box_1" + qdel(src) + +/obj/machinery/power/port_gen/pacman/attack_hand(mob/user as mob) + ..() + if (!anchored) + return + ui_interact(user) + +/obj/machinery/power/port_gen/pacman/attack_ai(mob/user as mob) + ui_interact(user) + +/obj/machinery/power/port_gen/pacman/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(IsBroken()) + return + + var/data[0] + data["active"] = active + if(istype(user, /mob/living/silicon/ai)) + data["is_ai"] = 1 + else if(istype(user, /mob/living/silicon/robot) && !Adjacent(user)) + data["is_ai"] = 1 + else + data["is_ai"] = 0 + data["output_set"] = power_output + data["output_max"] = max_power_output + data["output_safe"] = max_safe_output + data["output_watts"] = power_output * power_gen + data["temperature_current"] = src.temperature + data["temperature_max"] = src.max_temperature + if(overheating) + data["temperature_overheat"] = ((overheating / max_overheat) * 100) // Overheat percentage. Generator explodes at 100% + else + data["temperature_overheat"] = 0 + // 1 sheet = 1000cm3? + data["fuel_stored"] = round((sheets * 1000) + (sheet_left * 1000)) + data["fuel_capacity"] = round(max_sheets * 1000, 0.1) + data["fuel_usage"] = active ? round((power_output / time_per_sheet) * 1000) : 0 + data["fuel_type"] = sheet_name + + + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "pacman.tmpl", src.name, 500, 560) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + + +/* +/obj/machinery/power/port_gen/pacman/interact(mob/user) + if (get_dist(src, user) > 1 ) + if (!istype(user, /mob/living/silicon/ai)) + user.unset_machine() + user << browse(null, "window=port_gen") + return + + user.set_machine(src) + + var/dat = text("[name]
            ") + if (active) + dat += text("Generator: On
            ") + else + dat += text("Generator: Off
            ") + dat += text("[capitalize(sheet_name)]: [sheets] - Eject
            ") + var/stack_percent = round(sheet_left * 100, 1) + dat += text("Current stack: [stack_percent]%
            ") + dat += text("Power output: - [power_gen * power_output] Watts+
            ") + dat += text("Power current: [(powernet == null ? "Unconnected" : "[avail()]")]
            ") + + var/tempstr = "Temperature: [temperature]°C
            " + dat += (overheating)? "[tempstr]" : tempstr + dat += "
            Close" + user << browse("[dat]", "window=port_gen") + onclose(user, "port_gen") +*/ + +/obj/machinery/power/port_gen/pacman/Topic(href, href_list) + if(..()) + return + + src.add_fingerprint(usr) + if(href_list["action"]) + if(href_list["action"] == "enable") + if(!active && HasFuel() && !IsBroken()) + active = 1 + update_icon() + if(href_list["action"] == "disable") + if (active) + active = 0 + update_icon() + if(href_list["action"] == "eject") + if(!active) + DropFuel() + if(href_list["action"] == "lower_power") + if (power_output > 1) + power_output-- + if (href_list["action"] == "higher_power") + if (power_output < max_power_output || (emagged && power_output < round(max_power_output*2.5))) + power_output++ + +/obj/machinery/power/port_gen/pacman/super + name = "S.U.P.E.R.P.A.C.M.A.N.-type Portable Generator" + desc = "A power generator that utilizes uranium sheets as fuel. Can run for much longer than the standard PACMAN type generators. Rated for 80 kW max safe output." + icon_state = "portgen1" + sheet_path = /obj/item/stack/material/uranium + sheet_name = "Uranium Sheets" + time_per_sheet = 576 //same power output, but a 50 sheet stack will last 2 hours at max safe power + board_path = /obj/item/weapon/circuitboard/pacman/super + var/rad_power = 2 + +/obj/machinery/power/port_gen/pacman/super/UseFuel() + //produces a tiny amount of radiation when in use + if (prob(rad_power*power_output)) + radiation_repository.radiate(src, 2*rad_power) + ..() + +/obj/machinery/power/port_gen/pacman/super/update_icon() + if(..()) + set_light(0) + return 1 + overlays.Cut() + if(power_output >= max_safe_output) + var/image/I = image(icon,"[initial(icon_state)]rad") + I.blend_mode = BLEND_ADD + I.alpha = round(255*power_output/max_power_output) + overlays += I + set_light(rad_power + power_output - max_safe_output,1,"#3b97ca") + else + set_light(0) + + +/obj/machinery/power/port_gen/pacman/super/explode() + //a nice burst of radiation + var/rads = rad_power*25 + (sheets + sheet_left)*1.5 + radiation_repository.radiate(src, (max(20, rads))) + + explosion(src.loc, rad_power+1, rad_power+1, rad_power*2, 3) + qdel(src) + +/obj/machinery/power/port_gen/pacman/super/potato + name = "nuclear reactor" + desc = "PTTO-3, an industrial all-in-one nuclear power plant by Neo-Chernobyl GmbH. It uses uranium and vodka as a fuel source. Rated for 150 kW max safe output." + power_gen = 30000 //Watts output per power_output level + icon_state = "potato" + max_safe_output = 4 + max_power_output = 8 //The maximum power setting without emagging. + temperature_gain = 80 //how much the temperature increases per power output level, in degrees per level + max_temperature = 450 + time_per_sheet = 400 + rad_power = 6 + atom_flags = ATOM_FLAG_OPEN_CONTAINER + board_path = /obj/item/weapon/circuitboard/pacman/super/potato + anchored = 1 + +/obj/machinery/power/port_gen/pacman/super/potato/New() + create_reagents(120) + ..() + +/obj/machinery/power/port_gen/pacman/super/potato/examine(mob/user) + ..() + to_chat(user, "Auxilary tank shows [reagents.total_volume]u of liquid in it.") + +/obj/machinery/power/port_gen/pacman/super/potato/UseFuel() + if(reagents.has_reagent("vodka")) + rad_power = 2 + temperature_gain = 60 + reagents.remove_any(1) + if(prob(2)) + audible_message("[src] churns happily") + else + rad_power = initial(rad_power) + temperature_gain = initial(temperature_gain) + ..() + +/obj/machinery/power/port_gen/pacman/super/potato/update_icon() + if(..()) + return 1 + if(power_output > max_safe_output) + icon_state = "potatodanger" + +/obj/machinery/power/port_gen/pacman/super/potato/attackby(var/obj/item/O, var/mob/user) + if(istype(O, /obj/item/weapon/reagent_containers/)) + var/obj/item/weapon/reagent_containers/R = O + if(R.standard_pour_into(src,user)) + if(reagents.has_reagent("vodka")) + audible_message("[src] blips happily") + playsound(get_turf(src),'sound/machines/synth_yes.ogg', 50, 0) + else + audible_message("[src] blips in disappointment") + playsound(get_turf(src), 'sound/machines/synth_no.ogg', 50, 0) + return + ..() + +/obj/machinery/power/port_gen/pacman/mrs + name = "M.R.S.P.A.C.M.A.N.-type Portable Generator" + desc = "An advanced power generator that runs on tritium. Rated for 200 kW maximum safe output!" + icon_state = "portgen2" + sheet_path = /obj/item/stack/material/tritium + sheet_name = "Tritium Fuel Sheets" + + //I don't think tritium has any other use, so we might as well make this rewarding for players + //max safe power output (power level = 8) is 200 kW and lasts for 1 hour - 3 or 4 of these could power the station + power_gen = 25000 //watts + max_power_output = 10 + max_safe_output = 8 + time_per_sheet = 576 + max_temperature = 800 + temperature_gain = 90 + board_path = /obj/item/weapon/circuitboard/pacman/mrs + +/obj/machinery/power/port_gen/pacman/mrs/explode() + //no special effects, but the explosion is pretty big (same as a supermatter shard). + explosion(src.loc, 3, 6, 12, 16, 1) + qdel(src) diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm new file mode 100644 index 00000000..8378cf29 --- /dev/null +++ b/code/modules/power/power.dm @@ -0,0 +1,370 @@ +////////////////////////////// +// POWER MACHINERY BASE CLASS +////////////////////////////// + +///////////////////////////// +// Definitions +///////////////////////////// + +/obj/machinery/power + name = null + icon = 'icons/obj/power.dmi' + anchored = 1.0 + var/datum/powernet/powernet = null + use_power = 0 + idle_power_usage = 0 + active_power_usage = 0 + +/obj/machinery/power/Initialize() + . = ..() + connect_to_network() + +/obj/machinery/power/Destroy() + disconnect_from_network() + . = ..() + +/////////////////////////////// +// General procedures +////////////////////////////// + + +/obj/machinery/power/powered() + if(use_power) + return ..() + return 1 //doesn't require an external power source + +// common helper procs for all power machines +/obj/machinery/power/drain_power(var/drain_check, var/surge, var/amount = 0) + if(drain_check) + return 1 + + if(powernet && powernet.avail) + powernet.trigger_warning() + return powernet.draw_power(amount) + +/obj/machinery/power/proc/add_avail(var/amount) + if(powernet) + powernet.newavail += amount + return 1 + return 0 + +/obj/machinery/power/proc/draw_power(var/amount) + if(powernet) + return powernet.draw_power(amount) + return 0 + +/obj/machinery/power/proc/surplus() + if(powernet) + return powernet.avail-powernet.load + else + return 0 + +/obj/machinery/power/proc/avail() + if(powernet) + return powernet.avail + else + return 0 + +/obj/machinery/power/proc/disconnect_terminal(var/obj/machinery/power/terminal/term) // machines without a terminal will just return, no harm no fowl. + return + +// returns true if the area has power on given channel (or doesn't require power), defaults to power_channel. +// May also optionally specify an area, otherwise defaults to src.loc.loc +/obj/machinery/proc/powered(var/chan = -1, var/area/check_area = null) + + if(!src.loc) + return 0 + + //Don't do this. It allows machines that set use_power to 0 when off (many machines) to + //be turned on again and used after a power failure because they never gain the NOPOWER flag. + //if(!use_power) + // return 1 + + if(!check_area) + check_area = src.loc.loc // make sure it's in an area + if(!check_area || !isarea(check_area)) + return 0 // if not, then not powered + if(chan == -1) + chan = power_channel + return check_area.powered(chan) // return power status of the area + +// increment the power usage stats for an area +/obj/machinery/proc/use_power(var/amount, var/chan = -1) // defaults to power_channel + var/area/A = get_area(src) // make sure it's in an area + if(!A || !isarea(A)) + return + if(chan == -1) + chan = power_channel + A.use_power(amount, chan) + +// called whenever the power settings of the containing area change +// by default, check equipment channel & set flag can override if needed +/obj/machinery/proc/power_change() + var/oldstat = stat + + if(powered(power_channel)) + stat &= ~NOPOWER + else + stat |= NOPOWER + + . = (stat != oldstat) + if(.) + update_icon() + +// connect the machine to a powernet if a node cable is present on the turf +/obj/machinery/power/proc/connect_to_network() + var/turf/T = src.loc + if(!T || !istype(T)) + return 0 + + var/obj/structure/cable/C = T.get_cable_node() //check if we have a node cable on the machine turf, the first found is picked + if(!C || !C.powernet) + return 0 + + C.powernet.add_machine(src) + return 1 + +// remove and disconnect the machine from its current powernet +/obj/machinery/power/proc/disconnect_from_network() + if(!powernet) + return 0 + powernet.remove_machine(src) + return 1 + +// attach a wire to a power machine - leads from the turf you are standing on +//almost never called, overwritten by all power machines but terminal and generator +/obj/machinery/power/attackby(obj/item/weapon/W, mob/user) + + if(isCoil(W)) + + var/obj/item/stack/cable_coil/coil = W + + var/turf/T = user.loc + + if(!T.is_plating() || !istype(T, /turf/simulated/floor)) + return + + if(get_dist(src, user) > 1) + return + + coil.turf_place(T, user) + return + else + ..() + return + +/////////////////////////////////////////// +// Powernet handling helpers +////////////////////////////////////////// + +//returns all the cables WITHOUT a powernet in neighbors turfs, +//pointing towards the turf the machine is located at +/obj/machinery/power/proc/get_connections() + + . = list() + + var/cdir + var/turf/T + + for(var/card in GLOB.cardinal) + T = get_step(loc,card) + cdir = get_dir(T,loc) + + for(var/obj/structure/cable/C in T) + if(C.powernet) continue + if(C.d1 == cdir || C.d2 == cdir) + . += C + return . + +//returns all the cables in neighbors turfs, +//pointing towards the turf the machine is located at +/obj/machinery/power/proc/get_marked_connections() + + . = list() + + var/cdir + var/turf/T + + for(var/card in GLOB.cardinal) + T = get_step(loc,card) + cdir = get_dir(T,loc) + + for(var/obj/structure/cable/C in T) + if(C.d1 == cdir || C.d2 == cdir) + . += C + return . + +//returns all the NODES (O-X) cables WITHOUT a powernet in the turf the machine is located at +/obj/machinery/power/proc/get_indirect_connections() + . = list() + for(var/obj/structure/cable/C in loc) + if(C.powernet) continue + if(C.d1 == 0) // the cable is a node cable + . += C + return . + +/////////////////////////////////////////// +// GLOBAL PROCS for powernets handling +////////////////////////////////////////// + + +// returns a list of all power-related objects (nodes, cable, junctions) in turf, +// excluding source, that match the direction d +// if unmarked==1, only return those with no powernet +/proc/power_list(var/turf/T, var/source, var/d, var/unmarked=0, var/cable_only = 0) + . = list() + + var/reverse = d ? GLOB.reverse_dir[d] : 0 + for(var/AM in T) + if(AM == source) continue //we don't want to return source + + if(!cable_only && istype(AM,/obj/machinery/power)) + var/obj/machinery/power/P = AM + if(P.powernet == 0) continue // exclude APCs which have powernet=0 + + if(!unmarked || !P.powernet) //if unmarked=1 we only return things with no powernet + if(d == 0) + . += P + + else if(istype(AM,/obj/structure/cable)) + var/obj/structure/cable/C = AM + + if(!unmarked || !C.powernet) + if(C.d1 == d || C.d2 == d || C.d1 == reverse || C.d2 == reverse ) + . += C + return . + +//remove the old powernet and replace it with a new one throughout the network. +/proc/propagate_network(var/obj/O, var/datum/powernet/PN) + //world.log << "propagating new network" + var/list/worklist = list() + var/list/found_machines = list() + var/index = 1 + var/obj/P = null + + worklist+=O //start propagating from the passed object + + while(index<=worklist.len) //until we've exhausted all power objects + P = worklist[index] //get the next power object found + index++ + + if( istype(P,/obj/structure/cable)) + var/obj/structure/cable/C = P + if(C.powernet != PN) //add it to the powernet, if it isn't already there + PN.add_cable(C) + worklist |= C.get_connections() //get adjacents power objects, with or without a powernet + + else if(P.anchored && istype(P,/obj/machinery/power)) + var/obj/machinery/power/M = P + found_machines |= M //we wait until the powernet is fully propagates to connect the machines + + else + continue + + //now that the powernet is set, connect found machines to it + for(var/obj/machinery/power/PM in found_machines) + if(!PM.connect_to_network()) //couldn't find a node on its turf... + PM.disconnect_from_network() //... so disconnect if already on a powernet + + +//Merge two powernets, the bigger (in cable length term) absorbing the other +/proc/merge_powernets(var/datum/powernet/net1, var/datum/powernet/net2) + if(!net1 || !net2) //if one of the powernet doesn't exist, return + return + + if(net1 == net2) //don't merge same powernets + return + + //We assume net1 is larger. If net2 is in fact larger we are just going to make them switch places to reduce on code. + if(net1.cables.len < net2.cables.len) //net2 is larger than net1. Let's switch them around + var/temp = net1 + net1 = net2 + net2 = temp + + //merge net2 into net1 + for(var/obj/structure/cable/Cable in net2.cables) //merge cables + net1.add_cable(Cable) + + if(!net2) return net1 + + for(var/obj/machinery/power/Node in net2.nodes) //merge power machines + if(!Node.connect_to_network()) + Node.disconnect_from_network() //if somehow we can't connect the machine to the new powernet, disconnect it from the old nonetheless + + return net1 + +//Determines how strong could be shock, deals damage to mob, uses power. +//M is a mob who touched wire/whatever +//power_source is a source of electricity, can be powercell, area, apc, cable, powernet or null +//source is an object caused electrocuting (airlock, grille, etc) +//No animations will be performed by this proc. +/proc/electrocute_mob(mob/living/carbon/M as mob, var/power_source, var/obj/source, var/siemens_coeff = 1.0) + if(istype(M.loc,/obj/mecha)) return 0 //feckin mechs are dumb + var/area/source_area + if(istype(power_source,/area)) + source_area = power_source + power_source = source_area.get_apc() + if(istype(power_source,/obj/structure/cable)) + var/obj/structure/cable/Cable = power_source + power_source = Cable.powernet + + var/datum/powernet/PN + var/obj/item/weapon/cell/cell + + if(istype(power_source,/datum/powernet)) + PN = power_source + else if(istype(power_source,/obj/item/weapon/cell)) + cell = power_source + else if(istype(power_source,/obj/machinery/power/apc)) + var/obj/machinery/power/apc/apc = power_source + cell = apc.cell + if (apc.terminal) + PN = apc.terminal.powernet + else if (!power_source) + return 0 + else + log_admin("ERROR: /proc/electrocute_mob([M], [power_source], [source]): wrong power_source") + return 0 + //Triggers powernet warning, but only for 5 ticks (if applicable) + //If following checks determine user is protected we won't alarm for long. + if(PN) + PN.trigger_warning(5) + if(istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(H.species.siemens_coefficient <= 0) + return + if(H.gloves) + var/obj/item/clothing/gloves/G = H.gloves + if(G.siemens_coefficient == 0) return 0 //to avoid spamming with insulated glvoes on + + //Checks again. If we are still here subject will be shocked, trigger standard 20 tick warning + //Since this one is longer it will override the original one. + if(PN) + PN.trigger_warning() + + if (!cell && !PN) + return 0 + var/PN_damage = 0 + var/cell_damage = 0 + if (PN) + PN_damage = PN.get_electrocute_damage() + if (cell) + cell_damage = cell.get_electrocute_damage() + var/shock_damage = 0 + if (PN_damage>=cell_damage) + power_source = PN + shock_damage = PN_damage + else + power_source = cell + shock_damage = cell_damage + var/drained_hp = M.electrocute_act(shock_damage, source, siemens_coeff) //zzzzzzap! + var/drained_energy = drained_hp*20 + + if (source_area) + source_area.use_power(drained_energy/CELLRATE) + else if (istype(power_source,/datum/powernet)) + var/drained_power = drained_energy/CELLRATE + drained_power = PN.draw_power(drained_power) + else if (istype(power_source, /obj/item/weapon/cell)) + cell.use(drained_energy) + return drained_energy diff --git a/code/modules/power/powernet.dm b/code/modules/power/powernet.dm new file mode 100644 index 00000000..8562b578 --- /dev/null +++ b/code/modules/power/powernet.dm @@ -0,0 +1,190 @@ +/datum/powernet + var/list/cables = list() // all cables & junctions + var/list/nodes = list() // all connected machines + + var/load = 0 // the current load on the powernet, increased by each machine at processing + var/newavail = 0 // what available power was gathered last tick, then becomes... + var/avail = 0 //...the current available power in the powernet + var/viewload = 0 // the load as it appears on the power console (gradually updated) + var/number = 0 // Unused //TODEL + + var/smes_demand = 0 // Amount of power demanded by all SMESs from this network. Needed for load balancing. + var/list/inputting = list() // List of SMESs that are demanding power from this network. Needed for load balancing. + + var/smes_avail = 0 // Amount of power (avail) from SMESes. Used by SMES load balancing + var/smes_newavail = 0 // As above, just for newavail + + var/perapc = 0 // per-apc avilability + var/perapc_excess = 0 + var/netexcess = 0 // excess power on the powernet (typically avail-load) + + var/problem = 0 // If this is not 0 there is some sort of issue in the powernet. Monitors will display warnings. + +/datum/powernet/New() + START_PROCESSING_POWERNET(src) + ..() + +/datum/powernet/Destroy() + for(var/obj/structure/cable/C in cables) + cables -= C + C.powernet = null + for(var/obj/machinery/power/M in nodes) + nodes -= M + M.powernet = null + STOP_PROCESSING_POWERNET(src) + return ..() + +//Returns the amount of excess power (before refunding to SMESs) from last tick. +//This is for machines that might adjust their power consumption using this data. +/datum/powernet/proc/last_surplus() + return max(avail - load, 0) + +/datum/powernet/proc/draw_power(var/amount) + var/draw = between(0, amount, avail - load) + load += draw + return draw + +/datum/powernet/proc/is_empty() + return !cables.len && !nodes.len + +//remove a cable from the current powernet +//if the powernet is then empty, delete it +//Warning : this proc DON'T check if the cable exists +/datum/powernet/proc/remove_cable(var/obj/structure/cable/C) + cables -= C + C.powernet = null + if(is_empty())//the powernet is now empty... + qdel(src)///... delete it + +//add a cable to the current powernet +//Warning : this proc DON'T check if the cable exists +/datum/powernet/proc/add_cable(var/obj/structure/cable/C) + if(C.powernet)// if C already has a powernet... + if(C.powernet == src) + return + else + C.powernet.remove_cable(C) //..remove it + C.powernet = src + cables +=C + +//remove a power machine from the current powernet +//if the powernet is then empty, delete it +//Warning : this proc DON'T check if the machine exists +/datum/powernet/proc/remove_machine(var/obj/machinery/power/M) + nodes -=M + M.powernet = null + if(is_empty())//the powernet is now empty... + qdel(src)///... delete it - qdel + + +//add a power machine to the current powernet +//Warning : this proc DON'T check if the machine exists +/datum/powernet/proc/add_machine(var/obj/machinery/power/M) + if(M.powernet)// if M already has a powernet... + if(M.powernet == src) + return + else + M.disconnect_from_network()//..remove it + M.powernet = src + nodes[M] = M + +// Triggers warning for certain amount of ticks +/datum/powernet/proc/trigger_warning(var/duration_ticks = 20) + problem = max(duration_ticks, problem) + + +//handles the power changes in the powernet +//called every ticks by the powernet controller +/datum/powernet/proc/reset() + var/numapc = 0 + + if(problem > 0) + problem = max(problem - 1, 0) + + if(nodes && nodes.len) // Added to fix a bad list bug -- TLE + for(var/obj/machinery/power/terminal/term in nodes) + if( istype( term.master, /obj/machinery/power/apc ) ) + numapc++ + + netexcess = avail - load + + if(numapc) + //very simple load balancing. If there was a net excess this tick then it must have been that some APCs used less than perapc, since perapc*numapc = avail + //Therefore we can raise the amount of power rationed out to APCs on the assumption that those APCs that used less than perapc will continue to do so. + //If that assumption fails, then some APCs will miss out on power next tick, however it will be rebalanced for the tick after. + if (netexcess >= 0) + perapc_excess += min(netexcess/numapc, (avail - perapc) - perapc_excess) + else + perapc_excess = 0 + + perapc = avail/numapc + perapc_excess + + // At this point, all other machines have finished using power. Anything left over may be used up to charge SMESs. + if(inputting.len && smes_demand) + var/smes_input_percentage = between(0, (netexcess / smes_demand) * 100, 100) + for(var/obj/machinery/power/smes/S in inputting) + S.input_power(smes_input_percentage) + + netexcess = avail - load + + if(netexcess) + var/perc = get_percent_load(1) + for(var/obj/machinery/power/smes/S in nodes) + S.restore(perc) + + //updates the viewed load (as seen on power computers) + viewload = round(load) + + //reset the powernet + load = 0 + avail = newavail + smes_avail = smes_newavail + inputting.Cut() + smes_demand = 0 + newavail = 0 + smes_newavail = 0 + +/datum/powernet/proc/get_percent_load(var/smes_only = 0) + if(smes_only) + var/smes_used = load - (avail - smes_avail) // SMESs are always last to provide power + if(!smes_used || smes_used < 0 || !smes_avail) // SMES power isn't available or being used at all, SMES load is therefore 0% + return 0 + return between(0, (smes_used / smes_avail) * 100, 100) // Otherwise return percentage load of SMESs. + else + if(!load) + return 0 + return between(0, (avail / load) * 100, 100) + +/datum/powernet/proc/get_electrocute_damage() + switch(avail) + if (1000000 to INFINITY) + return min(rand(50,160),rand(50,160)) + if (200000 to 1000000) + return min(rand(25,80),rand(25,80)) + if (100000 to 200000)//Ave powernet + return min(rand(20,60),rand(20,60)) + if (50000 to 100000) + return min(rand(15,40),rand(15,40)) + if (1000 to 50000) + return min(rand(10,20),rand(10,20)) + else + return 0 + +//////////////////////////////////////////////// +// Misc. +/////////////////////////////////////////////// + + +// return a knot cable (O-X) if one is present in the turf +// null if there's none +/turf/proc/get_cable_node() + if(!istype(src, /turf/simulated)) + return null + for(var/obj/structure/cable/C in src) + if(C.d1 == 0) + return C + return null + + +/area/proc/get_apc() + return apc diff --git a/code/modules/power/profiling.dm b/code/modules/power/profiling.dm new file mode 100644 index 00000000..17bc2317 --- /dev/null +++ b/code/modules/power/profiling.dm @@ -0,0 +1,71 @@ +datum + +var/global/enable_power_update_profiling = 0 + +var/global/power_profiled_time = 0 +var/global/power_last_profile_time = 0 +var/global/list/power_update_requests_by_machine = list() +var/global/list/power_update_requests_by_area = list() + +/proc/log_power_update_request(area/A, obj/machinery/M) + if (!enable_power_update_profiling) + return + + var/machine_type = "[M.type]" + if (machine_type in power_update_requests_by_machine) + power_update_requests_by_machine[machine_type] += 1 + else + power_update_requests_by_machine[machine_type] = 1 + + if (A.name in power_update_requests_by_area) + power_update_requests_by_area[A.name] += 1 + else + power_update_requests_by_area[A.name] = 1 + + power_profiled_time += (world.time - power_last_profile_time) + power_last_profile_time = world.time + +/client/proc/toggle_power_update_profiling() + set name = "Toggle Area Power Update Profiling" + set desc = "Toggles the recording of area power update requests." + set category = "Debug" + if(!check_rights(R_DEBUG)) return + + if(enable_power_update_profiling) + enable_power_update_profiling = 0 + + to_chat(usr, "Area power update profiling disabled.") + message_admins("[key_name(src)] toggled area power update profiling off.") + log_admin("[key_name(src)] toggled area power update profiling off.") + else + enable_power_update_profiling = 1 + power_last_profile_time = world.time + + to_chat(usr, "Area power update profiling enabled.") + message_admins("[key_name(src)] toggled area power update profiling on.") + log_admin("[key_name(src)] toggled area power update profiling on.") + + feedback_add_details("admin_verb","APUP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/view_power_update_stats_machines() + set name = "View Area Power Update Statistics By Machines" + set desc = "See which types of machines are triggering area power updates." + set category = "Debug" + + if(!check_rights(R_DEBUG)) return + + to_chat(usr, "Total profiling time: [power_profiled_time] ticks") + for (var/M in power_update_requests_by_machine) + to_chat(usr, "[M] = [power_update_requests_by_machine[M]]") + +/client/proc/view_power_update_stats_area() + set name = "View Area Power Update Statistics By Area" + set desc = "See which areas are having area power updates." + set category = "Debug" + + if(!check_rights(R_DEBUG)) return + + to_chat(usr, "Total profiling time: [power_profiled_time] ticks") + to_chat(usr, "Total profiling time: [power_profiled_time] ticks") + for (var/A in power_update_requests_by_area) + to_chat(usr, "[A] = [power_update_requests_by_area[A]]") diff --git a/code/modules/power/sensors/powernet_sensor.dm b/code/modules/power/sensors/powernet_sensor.dm new file mode 100644 index 00000000..829d9e81 --- /dev/null +++ b/code/modules/power/sensors/powernet_sensor.dm @@ -0,0 +1,193 @@ +// POWERNET SENSOR +// +// Last Change 31.12.2014 by Atlantis +// +// Powernet sensors are devices which relay information about connected powernet. This information may be relayed +// via two procs. Proc return_reading_text will return fully HTML styled string which contains all information. This +// may be used in PDAs or similar applications. Second proc, return_reading_data will return list containing needed data. +// This is used in NanoUI, for example. + +/obj/machinery/power/sensor + name = "Powernet Sensor" + desc = "Small machine which transmits data about specific powernet." + anchored = 1 + density = 0 + level = 1 + icon = 'icons/obj/objects.dmi' + icon_state = "floor_beacon" // If anyone wants to make better sprite, feel free to do so without asking me. + + var/name_tag = "#UNKN#" // ID tag displayed in list of powernet sensors. Each sensor should have it's own tag! + var/long_range = 0 // If 1, sensor reading will show on all computers, regardless of Zlevel + +// Proc: New() +// Parameters: None +// Description: Automatically assigns name according to ID tag. +/obj/machinery/power/sensor/New() + ..() + auto_set_name() + +// Proc: auto_set_name() +// Parameters: None +// Description: Sets name of this sensor according to the ID tag. +/obj/machinery/power/sensor/proc/auto_set_name() + name = "[name_tag] - Powernet Sensor" + +// Proc: check_grid_warning() +// Parameters: None +// Description: Checks connected powernet for warnings. If warning is found returns 1 +/obj/machinery/power/sensor/proc/check_grid_warning() + connect_to_network() + if(powernet) + if(powernet.problem) + return 1 + return 0 + +// Proc: process() +// Parameters: None +// Description: This has to be here because we need sensors to remain in Machines list. +/obj/machinery/power/sensor/Process() + return 1 + +// Proc: reading_to_text() +// Parameters: 1 (amount - Power in Watts to be converted to W, kW or MW) +// Description: Helper proc that converts reading in Watts to kW or MW (returns string version of amount parameter) +/obj/machinery/power/sensor/proc/reading_to_text(var/amount = 0) + var/units = "" + // 10kW and less - Watts + if(amount < 10000) + units = "W" + // 10MW and less - KiloWatts + else if(amount < 10000000) + units = "kW" + amount = (round(amount/100) / 10) + // More than 10MW - MegaWatts + else + units = "MW" + amount = (round(amount/10000) / 100) + if (units == "W") + return "[amount] W" + else + return "~[amount] [units]" //kW and MW are only approximate readings, therefore add "~" + +// Proc: find_apcs() +// Parameters: None +// Description: Searches powernet for APCs and returns them in a list. +/obj/machinery/power/sensor/proc/find_apcs() + if(!powernet) + return + + var/list/L = list() + for(var/obj/machinery/power/terminal/term in powernet.nodes) + if(istype(term.master, /obj/machinery/power/apc)) + var/obj/machinery/power/apc/A = term.master + L += A + + return L + + +// Proc: return_reading_text() +// Parameters: None +// Description: Generates string which contains HTML table with reading data. +/obj/machinery/power/sensor/proc/return_reading_text() + // No powernet. Try to connect to one first. + if(!powernet) + connect_to_network() + var/out = "" + if(!powernet) // No powernet. + out = "# SYSTEM ERROR - NO POWERNET #" + return out + + + var/list/L = find_apcs() + var/total_apc_load = 0 + if(L.len <= 0) // No APCs found. + out = "No APCs located in connected powernet!" + else // APCs found. Create very ugly (but working!) HTML table. + + out += "
            NameEQUIPLIGHTENVIRONCELLLOAD" + + // These lists are used as replacement for number based APC settings + var/list/S = list("M-OFF","A-OFF","M-ON", "A-ON") + var/list/chg = list("N","C","F") + + // Split to multiple lines to make it more readable + for(var/obj/machinery/power/apc/A in L) + out += "
            \The [A.area]" // Add area name + out += "[S[A.equipment+1]][S[A.lighting+1]][S[A.environ+1]]" // Show status of channels + if(A.cell) + out += "[round(A.cell.percent())]% - [chg[A.charging+1]]" + else + out += "NO CELL" + var/load = A.lastused_total // Load. + total_apc_load += load + load = reading_to_text(load) + out += "[load]" + + out += "
            TOTAL AVAILABLE: [reading_to_text(powernet.avail)]" + out += "
            APC LOAD: [reading_to_text(total_apc_load)]" + out += "
            OTHER LOAD: [reading_to_text(max(powernet.load - total_apc_load, 0))]" + out += "
            TOTAL GRID LOAD: [reading_to_text(powernet.viewload)] ([round((powernet.load / powernet.avail) * 100)]%)" + + if(powernet.problem) + out += "
            WARNING: Abnormal grid activity detected!" + return out + +// Proc: return_reading_data() +// Parameters: None +// Description: Generates list containing all powernet data. Optimised for usage with NanoUI +/obj/machinery/power/sensor/proc/return_reading_data() + // No powernet. Try to connect to one first. + if(!powernet) + connect_to_network() + var/list/data = list() + data["name"] = name_tag + if(!powernet) + data["error"] = "# SYSTEM ERROR - NO POWERNET #" + data["alarm"] = 0 // Runtime Prevention + return data + + var/list/L = find_apcs() + var/total_apc_load = 0 + var/list/APC_data = list() + if(L.len > 0) + // These lists are used as replacement for number based APC settings + var/list/S = list("M-OFF", "DC-OFF","A-OFF","M-ON", "A-ON") + var/list/chg = list("N","C","F") + + for(var/obj/machinery/power/apc/A in L) + var/list/APC_entry = list() + // Channel Statuses + APC_entry["s_equipment"] = S[A.equipment+1] + APC_entry["s_lighting"] = S[A.lighting+1] + APC_entry["s_environment"] = S[A.environ+1] + // Cell Status + APC_entry["cell_charge"] = A.cell ? round(A.cell.percent()) : "NO CELL" + APC_entry["cell_status"] = A.cell ? chg[A.charging+1] : "N" + // Other info + APC_entry["total_load"] = reading_to_text(A.lastused_total) + // Hopefully removes those goddamn \improper s which are screwing up the UI + var/N = A.area.name + if(findtext(N, "ÿ")) + N = copytext(N, 3) + APC_entry["name"] = N + // Add data into main list of APC data. + APC_data += list(APC_entry) + // Add load of this APC to total APC load calculation + total_apc_load += A.lastused_total + data["apc_data"] = APC_data + data["total_avail"] = reading_to_text(max(powernet.avail, 0)) + data["total_used_apc"] = reading_to_text(max(total_apc_load, 0)) + data["total_used_other"] = reading_to_text(max(powernet.viewload - total_apc_load, 0)) + data["total_used_all"] = reading_to_text(max(powernet.viewload, 0)) + // Prevents runtimes when avail is 0 (division by zero) + if(powernet.avail) + data["load_percentage"] = round((powernet.viewload / powernet.avail) * 100) + else + data["load_percentage"] = 100 + data["alarm"] = powernet.problem ? 1 : 0 + return data + + + + + diff --git a/code/modules/power/sensors/sensor_monitoring.dm b/code/modules/power/sensors/sensor_monitoring.dm new file mode 100644 index 00000000..c26b06b5 --- /dev/null +++ b/code/modules/power/sensors/sensor_monitoring.dm @@ -0,0 +1,67 @@ +// POWERNET SENSOR MONITORING CONSOLE +// Connects to powernet sensors and loads data from them. Shows this data to the user. +// Newly supports NanoUI. + + +/obj/machinery/computer/power_monitor + name = "Power Monitoring Console" + desc = "Computer designed to remotely monitor power levels." + icon = 'icons/obj/computer.dmi' + icon_keyboard = "power_key" + icon_screen = "power" + light_color = "#ffcc33" + + //computer stuff + density = 1 + anchored = 1.0 + circuit = /obj/item/weapon/circuitboard/powermonitor + var/alerting = 0 + use_power = 1 + idle_power_usage = 300 + active_power_usage = 300 + var/datum/nano_module/power_monitor/power_monitor + +// Checks the sensors for alerts. If change (alerts cleared or detected) occurs, calls for icon update. +/obj/machinery/computer/power_monitor/Process() + var/alert = check_warnings() + if(alert != alerting) + alerting = !alerting + update_icon() + +// Updates icon of this computer according to current status. +/obj/machinery/computer/power_monitor/update_icon() + if(stat & BROKEN) + icon_state = "powerb" + return + if(stat & NOPOWER) + icon_state = "power0" + return + if(alerting) + icon_state = "power_alert" + return + icon_state = "power" + +// On creation automatically connects to active sensors. This is delayed to ensure sensors already exist. +/obj/machinery/computer/power_monitor/New() + ..() + power_monitor = new(src) + +// On user click opens the UI of this computer. +/obj/machinery/computer/power_monitor/attack_hand(mob/user) + add_fingerprint(user) + + if(stat & (BROKEN|NOPOWER)) + return + ui_interact(user) + +// Uses dark magic to operate the NanoUI of this computer. +/obj/machinery/computer/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + power_monitor.ui_interact(user, ui_key, ui, force_open) + + +// Verifies if any warnings were registered by connected sensors. +/obj/machinery/computer/power_monitor/proc/check_warnings() + for(var/obj/machinery/power/sensor/S in power_monitor.grid_sensors) + if(S.check_grid_warning()) + return 1 + return 0 diff --git a/code/modules/power/singularity/act.dm b/code/modules/power/singularity/act.dm new file mode 100644 index 00000000..07745857 --- /dev/null +++ b/code/modules/power/singularity/act.dm @@ -0,0 +1,115 @@ +#define I_SINGULO "singulo" + +/atom/proc/singularity_act() + return + +/atom/proc/singularity_pull(S, current_size) + return + +/mob/living/singularity_act() + investigate_log("has been consumed by a singularity", I_SINGULO) + gib() + return 20 + +/mob/living/singularity_pull(S, current_size) + step_towards(src, S) + apply_effect(current_size * 3, IRRADIATE, blocked = getarmor(null, "rad")) + +/mob/living/carbon/human/singularity_pull(S, current_size) + if(current_size >= STAGE_THREE) + var/list/handlist = list(l_hand, r_hand) + for(var/obj/item/hand in handlist) + if(prob(current_size*5) && hand.w_class >= ((11-current_size)/2) && unEquip(hand)) + step_towards(hand, S) + to_chat(src, "\The [S] pulls \the [hand] from your grip!") + if(!lying && (!shoes || !(shoes.item_flags & ITEM_FLAG_NOSLIP)) && (!species || !(species.species_flags & SPECIES_FLAG_NO_SLIP)) && prob(current_size*5)) + to_chat(src, "A strong gravitational force slams you to the ground!") + Weaken(current_size) + ..() + +/obj/singularity_act() + if(simulated) + ex_act(1) + if(src) + qdel(src) + return 2 + +/obj/singularity_pull(S, current_size) + if(simulated && !anchored) + step_towards(src, S) + +/obj/effect/beam/singularity_pull() + return + +/obj/effect/overlay/singularity_pull() + return + +/obj/item/singularity_pull(S, current_size) + set waitfor = 0 + if(anchored) + return + sleep(0) //this is needed or multiple items will be thrown sequentially and not simultaneously + if(current_size >= STAGE_FOUR) + //throw_at(S, 14, 3) + step_towards(src,S) + sleep(1) + step_towards(src,S) + else if(current_size > STAGE_ONE) + step_towards(src,S) + else ..() + +/obj/machinery/atmospherics/pipe/singularity_pull() + return + +/obj/machinery/power/supermatter/shard/singularity_act() + src.forceMove(null) + qdel(src) + return 5000 + +/obj/machinery/power/supermatter/singularity_act() + if(!src.loc) + return + + var/prints = "" + if(src.fingerprintshidden) + prints = ", all touchers : " + src.fingerprintshidden + + SetUniversalState(/datum/universal_state/supermatter_cascade) + log_admin("New super singularity made by eating a SM crystal [prints]. Last touched by [src.fingerprintslast].") + message_admins("New super singularity made by eating a SM crystal [prints]. Last touched by [src.fingerprintslast].") + src.forceMove(null) + qdel(src) + return 50000 + +/obj/item/projectile/beam/emitter/singularity_pull() + return + +/obj/item/weapon/storage/backpack/holding/singularity_act(S, current_size) + var/dist = max((current_size - 2), 1) + explosion(src.loc,(dist),(dist*2),(dist*4)) + return 1000 + +/turf/singularity_act(S, current_size) + if(!is_plating()) + for(var/obj/O in contents) + if(O.level != 1) + continue + if(O.invisibility == 101) + O.singularity_act(src, current_size) + ChangeTurf(get_base_turf_by_area(src)) + return 2 + +/turf/space/singularity_act() + return + +/******************* +* Nar-Sie Act/Pull * +*******************/ +/atom/proc/singuloCanEat() + return 1 + +/mob/observer/singuloCanEat() + return 0 + +/mob/new_player/singuloCanEat() + return 0 diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm new file mode 100644 index 00000000..cd3d877b --- /dev/null +++ b/code/modules/power/singularity/collector.dm @@ -0,0 +1,166 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 +var/global/list/rad_collectors = list() + +/obj/machinery/power/rad_collector + name = "Radiation Collector Array" + desc = "A device which uses radiation and phoron to produce power." + icon = 'icons/obj/singularity.dmi' + icon_state = "ca" + anchored = 0 + density = 1 + req_access = list(access_engine_equip) +// use_power = 0 + var/obj/item/weapon/tank/phoron/P = null + var/last_power = 0 + var/last_power_new = 0 + var/active = 0 + var/locked = 0 + var/drainratio = 1 + +/obj/machinery/power/rad_collector/New() + ..() + rad_collectors += src + +/obj/machinery/power/rad_collector/Destroy() + rad_collectors -= src + . = ..() + +/obj/machinery/power/rad_collector/Process() + //so that we don't zero out the meter if the SM is processed first. + last_power = last_power_new + last_power_new = 0 + + if(P && active) + var/rads = radiation_repository.get_rads_at_turf(get_turf(src)) + if(rads) + receive_pulse(rads * 5) //Maths is hard + + if(P) + if(P.air_contents.gas["phoron"] == 0) + investigate_log("out of fuel.","singulo") + eject() + else + P.air_contents.adjust_gas("phoron", -0.001*drainratio) + return + + +/obj/machinery/power/rad_collector/attack_hand(mob/user as mob) + if(anchored) + if(!src.locked) + toggle_power() + user.visible_message("[user.name] turns the [src.name] [active? "on":"off"].", \ + "You turn the [src.name] [active? "on":"off"].") + investigate_log("turned [active?"on":"off"] by [user.key]. [P?"Fuel: [round(P.air_contents.gas["phoron"]/0.29)]%":"It is empty"].","singulo") + return + else + to_chat(user, "The controls are locked!") + return + ..() + + +/obj/machinery/power/rad_collector/attackby(obj/item/W, mob/user) + if(istype(W, /obj/item/weapon/tank/phoron)) + if(!src.anchored) + to_chat(user, "The [src] needs to be secured to the floor first.") + return 1 + if(src.P) + to_chat(user, "There's already a phoron tank loaded.") + return 1 + user.drop_item() + src.P = W + W.loc = src + update_icons() + return 1 + else if(isCrowbar(W)) + if(P && !src.locked) + eject() + return 1 + else if(isWrench(W)) + if(P) + to_chat(user, "Remove the phoron tank first.") + return 1 + for(var/obj/machinery/power/rad_collector/R in get_turf(src)) + if(R != src) + to_chat(user, "You cannot install more than one collector on the same spot.") + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + src.anchored = !src.anchored + user.visible_message("[user.name] [anchored? "secures":"unsecures"] the [src.name].", \ + "You [anchored? "secure":"undo"] the external bolts.", \ + "You hear a ratchet") + if(anchored) + connect_to_network() + else + disconnect_from_network() + return 1 + else if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) + if (src.allowed(user)) + if(active) + src.locked = !src.locked + to_chat(user, "The controls are now [src.locked ? "locked." : "unlocked."]") + else + src.locked = 0 //just in case it somehow gets locked + to_chat(user, "The controls can only be locked when the [src] is active") + else + to_chat(user, "Access denied!") + return 1 + return ..() + +/obj/machinery/power/rad_collector/examine(mob/user) + if (..(user, 3)) + to_chat(user, "The meter indicates that \the [src] is collecting [last_power] W.") + return 1 + +/obj/machinery/power/rad_collector/ex_act(severity) + switch(severity) + if(2, 3) + eject() + return ..() + +/obj/machinery/power/rad_collector/return_air() + if(P) + return P.return_air() + +/obj/machinery/power/rad_collector/proc/eject() + locked = 0 + var/obj/item/weapon/tank/phoron/Z = src.P + if (!Z) + return + Z.forceMove(get_turf(src)) + Z.reset_plane_and_layer() + src.P = null + if(active) + toggle_power() + else + update_icons() + +/obj/machinery/power/rad_collector/proc/receive_pulse(var/pulse_strength) + if(P && active) + var/power_produced = 0 + power_produced = P.air_contents.gas["phoron"]*pulse_strength*20 + add_avail(power_produced) + last_power_new = power_produced + return + return + + +/obj/machinery/power/rad_collector/proc/update_icons() + overlays.Cut() + if(P) + overlays += image('icons/obj/singularity.dmi', "ptank") + if(stat & (NOPOWER|BROKEN)) + return + if(active) + overlays += image('icons/obj/singularity.dmi', "on") + + +/obj/machinery/power/rad_collector/proc/toggle_power() + active = !active + if(active) + icon_state = "ca_on" + flick("ca_active", src) + else + icon_state = "ca" + flick("ca_deactive", src) + update_icons() + return diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm new file mode 100644 index 00000000..ab628d72 --- /dev/null +++ b/code/modules/power/singularity/containment_field.dm @@ -0,0 +1,71 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +/obj/machinery/containment_field + name = "Containment Field" + desc = "An energy field." + icon = 'icons/obj/singularity.dmi' + icon_state = "Contain_F" + anchored = 1 + density = 0 + unacidable = 1 + use_power = 0 + light_range = 4 + movable_flags = MOVABLE_FLAG_PROXMOVE + var/obj/machinery/field_generator/FG1 = null + var/obj/machinery/field_generator/FG2 = null + var/hasShocked = 0 //Used to add a delay between shocks. In some cases this used to crash servers by spawning hundreds of sparks every second. + +/obj/machinery/containment_field/Destroy() + if(FG1 && !FG1.clean_up) + FG1.cleanup() + if(FG2 && !FG2.clean_up) + FG2.cleanup() + . = ..() + +/obj/machinery/containment_field/attack_hand(mob/user as mob) + if(get_dist(src, user) > 1) + return 0 + else + shock(user) + return 1 + + +/obj/machinery/containment_field/ex_act(severity) + return 0 + +/obj/machinery/containment_field/HasProximity(atom/movable/AM as mob|obj) + if(istype(AM,/mob/living/silicon) && prob(40)) + shock(AM) + return 1 + if(istype(AM,/mob/living/carbon) && prob(50)) + shock(AM) + return 1 + return 0 + + + +/obj/machinery/containment_field/shock(mob/living/user as mob) + if(hasShocked) + return 0 + if(!FG1 || !FG2) + qdel(src) + return 0 + if(isliving(user)) + hasShocked = 1 + var/shock_damage = min(rand(30,40),rand(30,40)) + user.electrocute_act(shock_damage, src) + + var/atom/target = get_edge_target_turf(user, get_dir(src, get_step_away(user, src))) + user.throw_at(target, 200, 4) + + sleep(20) + + hasShocked = 0 + return + +/obj/machinery/containment_field/proc/set_master(var/master1,var/master2) + if(!master1 || !master2) + return 0 + FG1 = master1 + FG2 = master2 + return 1 diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm new file mode 100644 index 00000000..7956cb8e --- /dev/null +++ b/code/modules/power/singularity/emitter.dm @@ -0,0 +1,240 @@ +#define EMITTER_DAMAGE_POWER_TRANSFER 450 //used to transfer power to containment field generators + +/obj/machinery/power/emitter + name = "emitter" + desc = "A massive heavy industrial laser. This design is a fixed installation, capable of shooting in only one direction." + description_info = "You must secure this in place with a wrench and weld it to the floor before using it. The emitter will only fire if it is installed above a cable endpoint. Clicking will toggle it on and off, at which point, so long as it remains powered, it will fire in a single direction in bursts of four." + description_fluff = "Lasers like this one have been in use for ages, in applications such as mining, cutting, and in the startup sequence of many advanced space station and starship engines." + description_antag = "This baby is capable of slicing through walls, sealed lockers, and people." + icon = 'icons/obj/singularity.dmi' + icon_state = "emitter" + anchored = 0 + density = 1 + req_access = list(access_engine_equip) + var/id = null + + use_power = 0 //uses powernet power, not APC power + active_power_usage = 100 KILOWATTS + + var/efficiency = 0.3 // Energy efficiency. 30% at this time, so 100kW load means 30kW laser pulses. + var/active = 0 + var/powered = 0 + var/fire_delay = 100 + var/max_burst_delay = 100 + var/min_burst_delay = 20 + var/burst_shots = 3 + var/last_shot = 0 + var/shot_number = 0 + var/state = 0 + var/locked = 0 + + var/_wifi_id + var/datum/wifi/receiver/button/emitter/wifi_receiver + +/obj/machinery/power/emitter/anchored + anchored = 1 + state = 2 + +/obj/machinery/power/emitter/verb/rotate() + set name = "Rotate" + set category = "Object" + set src in oview(1) + + if(usr.incapacitated()) + return + + if (src.anchored) + to_chat(usr, "It is fastened to the floor!") + return 0 + src.set_dir(turn(src.dir, 90)) + return 1 + +/obj/machinery/power/emitter/Initialize() + . = ..() + if(state == 2 && anchored) + connect_to_network() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + +/obj/machinery/power/emitter/Destroy() + log_and_message_admins("deleted \the [src]") + investigate_log("deleted at ([x],[y],[z])","singulo") + qdel(wifi_receiver) + wifi_receiver = null + return ..() + +/obj/machinery/power/emitter/update_icon() + if (active && powernet && avail(active_power_usage)) + icon_state = "emitter_+a" + else + icon_state = "emitter" + +/obj/machinery/power/emitter/attack_hand(mob/user as mob) + src.add_fingerprint(user) + activate(user) + +/obj/machinery/power/emitter/proc/activate(mob/user as mob) + if(state == 2) + if(!powernet) + to_chat(user, "\The [src] isn't connected to a wire.") + return 1 + if(!src.locked) + if(src.active==1) + src.active = 0 + to_chat(user, "You turn off \the [src].") + log_and_message_admins("turned off \the [src]") + investigate_log("turned off by [user.key]","singulo") + else + src.active = 1 + to_chat(user, "You turn on \the [src].") + src.shot_number = 0 + src.fire_delay = get_initial_fire_delay() + log_and_message_admins("turned on \the [src]") + investigate_log("turned on by [user.key]","singulo") + update_icon() + else + to_chat(user, "The controls are locked!") + else + to_chat(user, "\The [src] needs to be firmly secured to the floor first.") + return 1 + + +/obj/machinery/power/emitter/emp_act(var/severity) + return 1 + +/obj/machinery/power/emitter/Process() + if(stat & (BROKEN)) + return + if(src.state != 2 || (!powernet && active_power_usage)) + src.active = 0 + update_icon() + return + if(((src.last_shot + src.fire_delay) <= world.time) && (src.active == 1)) + + var/actual_load = draw_power(active_power_usage) + if(actual_load >= active_power_usage) //does the laser have enough power to shoot? + if(!powered) + powered = 1 + update_icon() + investigate_log("regained power and turned on","singulo") + else + if(powered) + powered = 0 + update_icon() + investigate_log("lost power and turned off","singulo") + return + + src.last_shot = world.time + if(src.shot_number < burst_shots) + src.fire_delay = get_burst_delay() + src.shot_number ++ + else + src.fire_delay = get_rand_burst_delay() + src.shot_number = 0 + + //need to calculate the power per shot as the emitter doesn't fire continuously. + var/burst_time = (min_burst_delay + max_burst_delay)/2 + 2*(burst_shots-1) + var/power_per_shot = (active_power_usage * efficiency) * (burst_time/10) / burst_shots + + if(prob(35)) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, src) + s.start() + + var/obj/item/projectile/beam/emitter/A = get_emitter_beam() + playsound(src.loc, A.fire_sound, 25, 1) + A.damage = round(power_per_shot/EMITTER_DAMAGE_POWER_TRANSFER) + A.launch_projectile( get_step(src.loc, src.dir) ) + +/obj/machinery/power/emitter/attackby(obj/item/W, mob/user) + + if(isWrench(W)) + if(active) + to_chat(user, "Turn off [src] first.") + return + switch(state) + if(0) + state = 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + user.visible_message("[user.name] secures [src] to the floor.", \ + "You secure the external reinforcing bolts to the floor.", \ + "You hear a ratchet") + src.anchored = 1 + if(1) + state = 0 + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + user.visible_message("[user.name] unsecures [src] reinforcing bolts from the floor.", \ + "You undo the external reinforcing bolts.", \ + "You hear a ratchet") + src.anchored = 0 + if(2) + to_chat(user, "\The [src] needs to be unwelded from the floor.") + return + + if(isWelder(W)) + var/obj/item/weapon/weldingtool/WT = W + if(active) + to_chat(user, "Turn off [src] first.") + return + switch(state) + if(0) + to_chat(user, "\The [src] needs to be wrenched to the floor.") + if(1) + if (WT.remove_fuel(0,user)) + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + user.visible_message("[user.name] starts to weld [src] to the floor.", \ + "You start to weld [src] to the floor.", \ + "You hear welding") + if (do_after(user,20,src)) + if(!src || !WT.isOn()) return + state = 2 + to_chat(user, "You weld [src] to the floor.") + connect_to_network() + else + to_chat(user, "You need more welding fuel to complete this task.") + if(2) + if (WT.remove_fuel(0,user)) + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + user.visible_message("[user.name] starts to cut [src] free from the floor.", \ + "You start to cut [src] free from the floor.", \ + "You hear welding") + if (do_after(user,20,src)) + if(!src || !WT.isOn()) return + state = 1 + to_chat(user, "You cut [src] free from the floor.") + disconnect_from_network() + else + to_chat(user, "You need more welding fuel to complete this task.") + return + + if(istype(W, /obj/item/weapon/card/id) || istype(W, /obj/item/device/pda)) + if(emagged) + to_chat(user, "The lock seems to be broken.") + return + if(src.allowed(user)) + src.locked = !src.locked + to_chat(user, "The controls are now [src.locked ? "locked." : "unlocked."]") + else + to_chat(user, "Access denied.") + return + ..() + return + +/obj/machinery/power/emitter/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + locked = 0 + emagged = 1 + user.visible_message("[user.name] emags [src].","You short out the lock.") + return 1 + +/obj/machinery/power/emitter/proc/get_initial_fire_delay() + return 100 + +/obj/machinery/power/emitter/proc/get_rand_burst_delay() + return rand(min_burst_delay, max_burst_delay) + +/obj/machinery/power/emitter/proc/get_burst_delay() + return 2 + +/obj/machinery/power/emitter/proc/get_emitter_beam() + return new /obj/item/projectile/beam/emitter(get_turf(src)) diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm new file mode 100644 index 00000000..b2195382 --- /dev/null +++ b/code/modules/power/singularity/field_generator.dm @@ -0,0 +1,339 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + + +/* +field_generator power level display + The icon used for the field_generator need to have 'num_power_levels' number of icon states + named 'Field_Gen +p[num]' where 'num' ranges from 1 to 'num_power_levels' + + The power level is displayed using overlays. The current displayed power level is stored in 'powerlevel'. + The overlay in use and the powerlevel variable must be kept in sync. A powerlevel equal to 0 means that + no power level overlay is currently in the overlays list. + -Aygar +*/ + +#define field_generator_max_power 250000 +/obj/machinery/field_generator + name = "Field Generator" + desc = "A large thermal battery that projects a high amount of energy when powered." + icon = 'icons/obj/machines/field_generator.dmi' + icon_state = "Field_Gen" + anchored = 0 + density = 1 + use_power = 0 + var/const/num_power_levels = 6 // Total number of power level icon has + var/Varedit_start = 0 + var/Varpower = 0 + var/active = 0 + var/power = 30000 // Current amount of power + var/state = 0 + var/warming_up = 0 + var/list/obj/machinery/containment_field/fields + var/list/obj/machinery/field_generator/connected_gens + var/clean_up = 0 + + //If keeping field generators powered is hard then increase the emitter active power usage. + var/gen_power_draw = 5500 //power needed per generator + var/field_power_draw = 2000 //power needed per field object + + +/obj/machinery/field_generator/update_icon() + overlays.Cut() + if(!active) + if(warming_up) + overlays += "+a[warming_up]" + if(fields.len) + overlays += "+on" + // Power level indicator + // Scale % power to % num_power_levels and truncate value + var/level = round(num_power_levels * power / field_generator_max_power) + // Clamp between 0 and num_power_levels for out of range power values + level = between(0, level, num_power_levels) + if(level) + overlays += "+p[level]" + + return + + +/obj/machinery/field_generator/New() + ..() + fields = list() + connected_gens = list() + +/obj/machinery/field_generator/Process() + if(Varedit_start == 1) + if(active == 0) + active = 1 + state = 2 + power = field_generator_max_power + anchored = 1 + warming_up = 3 + start_fields() + update_icon() + Varedit_start = 0 + + if(src.active == 2) + calc_power() + update_icon() + + +/obj/machinery/field_generator/attack_hand(mob/user as mob) + if(state == 2) + if(get_dist(src, user) <= 1)//Need to actually touch the thing to turn it on + if(src.active >= 1) + to_chat(user, "You are unable to turn off the [src.name] once it is online.") + return 1 + else + user.visible_message("[user.name] turns on the [src.name]", \ + "You turn on the [src.name].", \ + "You hear heavy droning") + turn_on() + investigate_log("activated by [user.key].","singulo") + + src.add_fingerprint(user) + else + to_chat(user, "The [src] needs to be firmly secured to the floor first.") + return + + +/obj/machinery/field_generator/attackby(obj/item/W, mob/user) + if(active) + to_chat(user, "The [src] needs to be off.") + return + else if(isWrench(W)) + switch(state) + if(0) + state = 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + user.visible_message("[user.name] secures [src.name] to the floor.", \ + "You secure the external reinforcing bolts to the floor.", \ + "You hear ratchet") + src.anchored = 1 + if(1) + state = 0 + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + user.visible_message("[user.name] unsecures [src.name] reinforcing bolts from the floor.", \ + "You undo the external reinforcing bolts.", \ + "You hear ratchet") + src.anchored = 0 + if(2) + to_chat(user, " The [src.name] needs to be unwelded from the floor.") + return + else if(isWelder(W)) + var/obj/item/weapon/weldingtool/WT = W + switch(state) + if(0) + to_chat(user, "The [src.name] needs to be wrenched to the floor.") + return + if(1) + if (WT.remove_fuel(0,user)) + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + user.visible_message("[user.name] starts to weld the [src.name] to the floor.", \ + "You start to weld the [src] to the floor.", \ + "You hear welding") + if (do_after(user,20,src)) + if(!src || !WT.isOn()) return + state = 2 + to_chat(user, "You weld the field generator to the floor.") + else + return + if(2) + if (WT.remove_fuel(0,user)) + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + user.visible_message("[user.name] starts to cut the [src.name] free from the floor.", \ + "You start to cut the [src] free from the floor.", \ + "You hear welding") + if (do_after(user,20,src)) + if(!src || !WT.isOn()) return + state = 1 + to_chat(user, "You cut the [src] free from the floor.") + else + return + else + ..() + return + + +/obj/machinery/field_generator/emp_act() + return 0 + +/obj/machinery/field_generator/bullet_act(var/obj/item/projectile/Proj) + if(istype(Proj, /obj/item/projectile/beam)) + power += Proj.damage * EMITTER_DAMAGE_POWER_TRANSFER + update_icon() + return 0 + + +/obj/machinery/field_generator/Destroy() + src.cleanup() + . = ..() + + + +/obj/machinery/field_generator/proc/turn_off() + active = 0 + spawn(1) + src.cleanup() + update_icon() + +/obj/machinery/field_generator/proc/turn_on() + active = 1 + warming_up = 1 + spawn(1) + while (warming_up<3 && active) + sleep(50) + warming_up++ + update_icon() + if(warming_up >= 3) + start_fields() + update_icon() + + +/obj/machinery/field_generator/proc/calc_power() + if(Varpower) + return 1 + + update_icon() + if(src.power > field_generator_max_power) + src.power = field_generator_max_power + + var/power_draw = gen_power_draw + for(var/obj/machinery/field_generator/FG in connected_gens) + if (!isnull(FG)) + power_draw += gen_power_draw + for (var/obj/machinery/containment_field/F in fields) + if (!isnull(F)) + power_draw += field_power_draw + power_draw /= 2 //because this will be mirrored for both generators + if(draw_power(round(power_draw)) >= power_draw) + return 1 + else + for(var/mob/M in viewers(src)) + M.show_message("\The [src] shuts down!") + turn_off() + investigate_log("ran out of power and deactivated","singulo") + src.power = 0 + return 0 + +//Tries to draw the needed power from our own power reserve, or connected generators if we can. Returns the amount of power we were able to get. +/obj/machinery/field_generator/proc/draw_power(var/draw = 0, var/list/flood_list = list()) + flood_list += src + + if(src.power >= draw)//We have enough power + src.power -= draw + return draw + + //Need more power + var/actual_draw = src.power //already checked that power < draw + src.power = 0 + + for(var/obj/machinery/field_generator/FG in connected_gens) + if (FG in flood_list) + continue + actual_draw += FG.draw_power(draw - actual_draw, flood_list) //since the flood list reference is shared this actually works. + if (actual_draw >= draw) + return actual_draw + + return actual_draw + +/obj/machinery/field_generator/proc/start_fields() + if(!src.state == 2 || !anchored) + turn_off() + return + spawn(1) + setup_field(1) + spawn(2) + setup_field(2) + spawn(3) + setup_field(4) + spawn(4) + setup_field(8) + src.active = 2 + + +/obj/machinery/field_generator/proc/setup_field(var/NSEW) + var/turf/T = src.loc + var/obj/machinery/field_generator/G + var/steps = 0 + if(!NSEW)//Make sure its ran right + return + for(var/dist = 0, dist <= 9, dist += 1) // checks out to 8 tiles away for another generator + T = get_step(T, NSEW) + if(T.density)//We cant shoot a field though this + return 0 + for(var/atom/A in T.contents) + if(ismob(A)) + continue + if(!istype(A,/obj/machinery/field_generator)) + if((istype(A,/obj/machinery/door)||istype(A,/obj/machinery/the_singularitygen))&&(A.density)) + return 0 + steps += 1 + G = locate(/obj/machinery/field_generator) in T + if(!isnull(G)) + steps -= 1 + if(!G.active) + return 0 + break + if(isnull(G)) + return + T = src.loc + for(var/dist = 0, dist < steps, dist += 1) // creates each field tile + var/field_dir = get_dir(T,get_step(G.loc, NSEW)) + T = get_step(T, NSEW) + if(!locate(/obj/machinery/containment_field) in T) + var/obj/machinery/containment_field/CF = new/obj/machinery/containment_field() + CF.set_master(src,G) + fields += CF + G.fields += CF + CF.loc = T + CF.set_dir(field_dir) + var/listcheck = 0 + for(var/obj/machinery/field_generator/FG in connected_gens) + if (isnull(FG)) + continue + if(FG == G) + listcheck = 1 + break + if(!listcheck) + connected_gens.Add(G) + listcheck = 0 + for(var/obj/machinery/field_generator/FG2 in G.connected_gens) + if (isnull(FG2)) + continue + if(FG2 == src) + listcheck = 1 + break + if(!listcheck) + G.connected_gens.Add(src) + + +/obj/machinery/field_generator/proc/cleanup() + clean_up = 1 + for (var/obj/machinery/containment_field/F in fields) + if (QDELETED(F)) + continue + qdel(F) + fields = list() + for(var/obj/machinery/field_generator/FG in connected_gens) + if (QDELETED(FG)) + continue + FG.connected_gens.Remove(src) + if(!FG.clean_up)//Makes the other gens clean up as well + FG.cleanup() + connected_gens.Remove(FG) + connected_gens = list() + clean_up = 0 + update_icon() + + //This is here to help fight the "hurr durr, release singulo cos nobody will notice before the + //singulo eats the evidence". It's not fool-proof but better than nothing. + //I want to avoid using global variables. + spawn(1) + var/temp = 1 //stops spam + for(var/obj/singularity/O in SSmachines.machinery) + if(O.last_warning && temp) + if((world.time - O.last_warning) > 50) //to stop message-spam + temp = 0 + message_admins("A singulo exists and a containment field has failed.",1) + investigate_log("has failed whilst a singulo exists.","singulo") + O.last_warning = world.time diff --git a/code/modules/power/singularity/generator.dm b/code/modules/power/singularity/generator.dm new file mode 100644 index 00000000..69593ad1 --- /dev/null +++ b/code/modules/power/singularity/generator.dm @@ -0,0 +1,31 @@ +/////SINGULARITY SPAWNER +/obj/machinery/the_singularitygen/ + name = "Gravitational Singularity Generator" + desc = "An Odd Device which produces a Gravitational Singularity when set up." + icon = 'icons/obj/singularity.dmi' + icon_state = "TheSingGen" + anchored = 0 + density = 1 + use_power = 0 + var/energy = 0 + +/obj/machinery/the_singularitygen/Process() + var/turf/T = get_turf(src) + if(src.energy >= 200) + new /obj/singularity/(T, 50) + if(src) qdel(src) + +/obj/machinery/the_singularitygen/attackby(obj/item/W, mob/user) + if(istype(W, /obj/item/weapon/wrench)) + anchored = !anchored + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + if(anchored) + user.visible_message("[user.name] secures [src.name] to the floor.", \ + "You secure the [src.name] to the floor.", \ + "You hear a ratchet") + else + user.visible_message("[user.name] unsecures [src.name] from the floor.", \ + "You unsecure the [src.name] from the floor.", \ + "You hear a ratchet") + return + return ..() diff --git a/code/modules/power/singularity/particle_accelerator/particle.dm b/code/modules/power/singularity/particle_accelerator/particle.dm new file mode 100644 index 00000000..a704f73f --- /dev/null +++ b/code/modules/power/singularity/particle_accelerator/particle.dm @@ -0,0 +1,101 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +/obj/effect/accelerated_particle + name = "Accelerated Particles" + desc = "Small things moving very fast." + icon = 'icons/obj/projectiles.dmi' + icon_state = "ice_2"//Need a new icon for this + anchored = 1 + density = 1 + var/movement_range = 10 + var/energy = 10 //energy in eV + var/mega_energy = 0 //energy in MeV + var/particle_type + var/additional_particles = 0 + var/turf/target + var/turf/source + var/movetotarget = 1 + +/obj/effect/accelerated_particle/weak + movement_range = 8 + energy = 5 + +/obj/effect/accelerated_particle/strong + movement_range = 15 + energy = 15 + + +/obj/effect/accelerated_particle/New(loc, dir = 2) + src.loc = loc + src.set_dir(dir) + if(movement_range > 20) + movement_range = 20 + spawn(0) + move(1) + return + + +/obj/effect/accelerated_particle/Bump(atom/A) + if (A) + if(ismob(A)) + toxmob(A) + var/mob/M = A + M.gib() + + if((istype(A,/obj/machinery/the_singularitygen))||(istype(A,/obj/machinery/sunreactor/center))||(istype(A,/obj/machinery/sunreactor/rleft))||(istype(A,/obj/machinery/sunreactor/rright))||(istype(A,/obj/machinery/sunreactor/rup))||(istype(A,/obj/machinery/sunreactor/rdown))) + var/turf/Under + Under = get_turf(A) + A:energy += energy*(Under.temperature/280) + else if(istype(A,/obj/machinery/power/fusion_core)) + var/obj/machinery/power/fusion_core/collided_core = A + if(particle_type && particle_type != "neutron") + if(collided_core.AddParticles(particle_type, 1 + additional_particles)) + collided_core.owned_field.plasma_temperature += mega_energy + collided_core.owned_field.energy += energy + loc = null + else if(istype(A, /obj/effect/fusion_particle_catcher)) + var/obj/effect/fusion_particle_catcher/PC = A + if(particle_type && particle_type != "neutron") + if(PC.parent.owned_core.AddParticles(particle_type, 1 + additional_particles)) + PC.parent.plasma_temperature += mega_energy + PC.parent.energy += energy + loc = null + return + +/obj/effect/accelerated_particle/Bumped(atom/A) + if(ismob(A)) + Bump(A) + return + + +/obj/effect/accelerated_particle/ex_act(severity) + qdel(src) + return + +/obj/effect/accelerated_particle/proc/toxmob(var/mob/living/M) + var/radiation = (energy*2) + M.apply_effect((radiation*3),IRRADIATE,blocked = M.getarmor(null, "rad")) + M.updatehealth() +// to_chat(M, "You feel odd.") + return + + +/obj/effect/accelerated_particle/proc/move(var/lag) + if(target) + if(movetotarget) + if(!step_towards(src,target)) + src.loc = get_step(src, get_dir(src,target)) + if(get_dist(src,target) < 1) + movetotarget = 0 + else + if(!step(src, get_step_away(src,source))) + src.loc = get_step(src, get_step_away(src,source)) + else + if(!step(src,dir)) + src.loc = get_step(src,dir) + movement_range-- + if(movement_range <= 0) + qdel(src) + else + sleep(lag) + move(lag) diff --git a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm new file mode 100644 index 00000000..c58a15ff --- /dev/null +++ b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm @@ -0,0 +1,393 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +/*Composed of 7 parts +3 Particle emitters +proc +emit_particle() + +1 power box +the only part of this thing that uses power, can hack to mess with the pa/make it better. +Lies, only the control computer draws power. + +1 fuel chamber +contains procs for mixing gas and whatever other fuel it uses +mix_gas() + +1 gas holder WIP +acts like a tank valve on the ground that you wrench gas tanks onto +proc +extract_gas() +return_gas() +attach_tank() +remove_tank() +get_available_mix() + +1 End Cap + +1 Control computer +interface for the pa, acts like a computer with an html menu for diff parts and a status report +all other parts contain only a ref to this +a /machine/, tells the others to do work +contains ref for all parts +proc +process() +check_build() + +Setup map + |EC| +CC|FC| + |PB| +PE|PE|PE + + +Icon Addemdum +Icon system is much more robust, and the icons are all variable based. +Each part has a reference string, powered, strength, and contruction values. +Using this the update_icon() proc is simplified a bit (using for absolutely was problematic with naming), +so the icon_state comes out be: +"[reference][strength]", with a switch controlling construction_states and ensuring that it doesn't +power on while being contructed, and all these variables are set by the computer through it's scan list +Essential order of the icons: +Standard - [reference] +Wrenched - [reference] +Wired - [reference]w +Closed - [reference]c +Powered - [reference]p[strength] +Strength being set by the computer and a null strength (Computer is powered off or inactive) returns a 'null', counting as empty +So, hopefully this is helpful if any more icons are to be added/changed/wondering what the hell is going on here + +*/ + +/obj/structure/particle_accelerator + name = "Particle Accelerator" + desc = "Part of a Particle Accelerator." + icon = 'icons/obj/machines/particle_accelerator2.dmi' + icon_state = "none" + anchored = 0 + density = 1 + var/obj/machinery/particle_accelerator/control_box/master = null + var/construction_state = 0 + var/reference = null + var/powered = 0 + var/strength = null + var/desc_holder = null + +/obj/structure/particle_accelerator/Destroy() + construction_state = 0 + if(master) + master.part_scan() + . = ..() + +/obj/structure/particle_accelerator/end_cap + name = "Alpha Particle Generation Array" + desc_holder = "This is where Alpha particles are generated from \[REDACTED\]" + icon_state = "end_cap" + reference = "end_cap" + +/obj/structure/particle_accelerator/update_icon() + ..() + return + + +/obj/structure/particle_accelerator/verb/rotate() + set name = "Rotate Clockwise" + set category = "Object" + set src in oview(1) + + if (src.anchored || usr:stat) + to_chat(usr, "It is fastened to the floor!") + return 0 + src.set_dir(turn(src.dir, 270)) + return 1 + +/obj/structure/particle_accelerator/verb/rotateccw() + set name = "Rotate Counter Clockwise" + set category = "Object" + set src in oview(1) + + if (src.anchored || usr:stat) + to_chat(usr, "It is fastened to the floor!") + return 0 + src.set_dir(turn(src.dir, 90)) + return 1 + +/obj/structure/particle_accelerator/examine(mob/user) + switch(src.construction_state) + if(0) + src.desc = text("A [name], looks like it's not attached to the flooring") + if(1) + src.desc = text("A [name], it is missing some cables") + if(2) + src.desc = text("A [name], the panel is open") + if(3) + src.desc = text("The [name] is assembled") + if(powered) + src.desc = src.desc_holder + ..() + return + + +/obj/structure/particle_accelerator/attackby(obj/item/W, mob/user) + if(istool(W)) + if(src.process_tool_hit(W,user)) + return + ..() + return + + +/obj/structure/particle_accelerator/Move() + ..() + if(master && master.active) + master.toggle_power() + investigate_log("was moved whilst active; it powered down.","singulo") + +/obj/structure/particle_accelerator/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + if (prob(50)) + qdel(src) + return + if(3.0) + if (prob(25)) + qdel(src) + return + else + return + +/obj/structure/particle_accelerator/update_icon() + switch(construction_state) + if(0,1) + icon_state="[reference]" + if(2) + icon_state="[reference]w" + if(3) + if(powered) + icon_state="[reference]p[strength]" + else + icon_state="[reference]c" + return + +/obj/structure/particle_accelerator/proc/update_state() + if(master) + master.update_state() + return 0 + + +/obj/structure/particle_accelerator/proc/report_ready(var/obj/O) + if(O && (O == master)) + if(construction_state >= 3) + return 1 + return 0 + + +/obj/structure/particle_accelerator/proc/report_master() + if(master) + return master + return 0 + + +/obj/structure/particle_accelerator/proc/connect_master(var/obj/O) + if(O && istype(O,/obj/machinery/particle_accelerator/control_box)) + if(O.dir == src.dir) + master = O + return 1 + return 0 + + +/obj/structure/particle_accelerator/proc/process_tool_hit(var/obj/O, var/mob/user) + if(!(O) || !(user)) + return 0 + if(!ismob(user) || !isobj(O)) + return 0 + var/temp_state = src.construction_state + + switch(src.construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps + if(0) + if(isWrench(O)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + src.anchored = 1 + user.visible_message("[user.name] secures the [src.name] to the floor.", \ + "You secure the external bolts.") + temp_state++ + if(1) + if(isWrench(O)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + src.anchored = 0 + user.visible_message("[user.name] detaches the [src.name] from the floor.", \ + "You remove the external bolts.") + temp_state-- + else if(isCoil(O)) + if(O:use(1,user)) + user.visible_message("[user.name] adds wires to the [src.name].", \ + "You add some wires.") + temp_state++ + if(2) + if(isWirecutter(O))//TODO:Shock user if its on? + user.visible_message("[user.name] removes some wires from the [src.name].", \ + "You remove some wires.") + temp_state-- + else if(isScrewdriver(O)) + user.visible_message("[user.name] closes the [src.name]'s access panel.", \ + "You close the access panel.") + temp_state++ + if(3) + if(isScrewdriver(O)) + user.visible_message("[user.name] opens the [src.name]'s access panel.", \ + "You open the access panel.") + temp_state-- + if(temp_state == src.construction_state)//Nothing changed + return 0 + else + src.construction_state = temp_state + if(src.construction_state < 3)//Was taken apart, update state + update_state() + update_icon() + return 1 + return 0 + + + +/obj/machinery/particle_accelerator + name = "Particle Accelerator" + desc = "Part of a Particle Accelerator." + icon = 'icons/obj/machines/particle_accelerator2.dmi' + icon_state = "none" + anchored = 0 + density = 1 + use_power = 0 + idle_power_usage = 0 + active_power_usage = 0 + var/construction_state = 0 + var/active = 0 + var/reference = null + var/powered = null + var/strength = 0 + var/desc_holder = null + + +/obj/machinery/particle_accelerator/verb/rotate() + set name = "Rotate Clockwise" + set category = "Object" + set src in oview(1) + + if (src.anchored || usr:stat) + to_chat(usr, "It is fastened to the floor!") + return 0 + src.set_dir(turn(src.dir, 270)) + return 1 + +/obj/machinery/particle_accelerator/verb/rotateccw() + set name = "Rotate Counter-Clockwise" + set category = "Object" + set src in oview(1) + + if (src.anchored || usr:stat) + to_chat(usr, "It is fastened to the floor!") + return 0 + src.set_dir(turn(src.dir, 90)) + return 1 + +/obj/machinery/particle_accelerator/update_icon() + return + +/obj/machinery/particle_accelerator/examine(mob/user) + switch(src.construction_state) + if(0) + src.desc = text("A [name], looks like it's not attached to the flooring") + if(1) + src.desc = text("A [name], it is missing some cables") + if(2) + src.desc = text("A [name], the panel is open") + if(3) + src.desc = text("The [name] is assembled") + if(powered) + src.desc = src.desc_holder + ..() + return + + +/obj/machinery/particle_accelerator/attackby(obj/item/W, mob/user) + if(istool(W)) + if(src.process_tool_hit(W,user)) + return + ..() + return + +/obj/machinery/particle_accelerator/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + if (prob(50)) + qdel(src) + return + if(3.0) + if (prob(25)) + qdel(src) + return + else + return + + +/obj/machinery/particle_accelerator/proc/update_state() + return 0 + + +/obj/machinery/particle_accelerator/proc/process_tool_hit(var/obj/O, var/mob/user) + if(!(O) || !(user)) + return 0 + if(!ismob(user) || !isobj(O)) + return 0 + var/temp_state = src.construction_state + switch(src.construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps + if(0) + if(isWrench(O)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + src.anchored = 1 + user.visible_message("[user.name] secures the [src.name] to the floor.", \ + "You secure the external bolts.") + temp_state++ + if(1) + if(isWrench(O)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + src.anchored = 0 + user.visible_message("[user.name] detaches the [src.name] from the floor.", \ + "You remove the external bolts.") + temp_state-- + else if(isCoil(O)) + if(O:use(1)) + user.visible_message("[user.name] adds wires to the [src.name].", \ + "You add some wires.") + temp_state++ + if(2) + if(isWirecutter(O))//TODO:Shock user if its on? + user.visible_message("[user.name] removes some wires from the [src.name].", \ + "You remove some wires.") + temp_state-- + else if(isScrewdriver(O)) + user.visible_message("[user.name] closes the [src.name]'s access panel.", \ + "You close the access panel.") + temp_state++ + if(3) + if(isScrewdriver(O)) + user.visible_message("[user.name] opens the [src.name]'s access panel.", \ + "You open the access panel.") + temp_state-- + active = 0 + if(temp_state == src.construction_state)//Nothing changed + return 0 + else + if(src.construction_state < 3)//Was taken apart, update state + update_state() + if(use_power) + use_power = 0 + src.construction_state = temp_state + if(src.construction_state >= 3) + use_power = 1 + update_icon() + return 1 + return 0 diff --git a/code/modules/power/singularity/particle_accelerator/particle_chamber.dm b/code/modules/power/singularity/particle_accelerator/particle_chamber.dm new file mode 100644 index 00000000..f1e487b0 --- /dev/null +++ b/code/modules/power/singularity/particle_accelerator/particle_chamber.dm @@ -0,0 +1,10 @@ +/obj/structure/particle_accelerator/fuel_chamber + name = "EM Acceleration Chamber" + desc_holder = "This is where the Alpha particles are accelerated to radical speeds." + icon = 'icons/obj/machines/particle_accelerator2.dmi' + icon_state = "fuel_chamber" + reference = "fuel_chamber" + +/obj/structure/particle_accelerator/fuel_chamber/update_icon() + ..() + return \ No newline at end of file diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm new file mode 100644 index 00000000..7c6cc46f --- /dev/null +++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm @@ -0,0 +1,292 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +/obj/machinery/particle_accelerator/control_box + name = "Particle Accelerator Control Computer" + desc = "This controls the density of the particles." + icon = 'icons/obj/machines/particle_accelerator2.dmi' + icon_state = "control_box" + reference = "control_box" + anchored = 0 + density = 1 + use_power = 0 + idle_power_usage = 500 + active_power_usage = 70000 //70 kW per unit of strength + construction_state = 0 + active = 0 + dir = 1 + var/strength_upper_limit = 2 + var/interface_control = 1 + var/list/obj/structure/particle_accelerator/connected_parts + var/assembled = 0 + var/parts = null + var/datum/wires/particle_acc/control_box/wires = null + var/obj/machinery/sunreactor/center/reactor = null + +/obj/machinery/particle_accelerator/control_box/New() + wires = new(src) + connected_parts = list() + active_power_usage = initial(active_power_usage) * (strength + 1) + ..() + +/obj/machinery/particle_accelerator/control_box/Destroy() + if(active) + toggle_power() + qdel(wires) + wires = null + return ..() + +/obj/machinery/particle_accelerator/control_box/attack_hand(mob/user as mob) + if(construction_state >= 3) + interact(user) + else if(construction_state == 2) // Wires exposed + wires.Interact(user) + +/obj/machinery/particle_accelerator/control_box/update_state() + if(construction_state < 3) + update_use_power(0) + assembled = 0 + active = 0 + for(var/obj/structure/particle_accelerator/part in connected_parts) + part.strength = null + part.powered = 0 + part.update_icon() + connected_parts = list() + return + if(!part_scan()) + update_use_power(1) + active = 0 + connected_parts = list() + + return + +/obj/machinery/particle_accelerator/control_box/update_icon() + if(active) + icon_state = "[reference]p1" + else + if(use_power) + if(assembled) + icon_state = "[reference]p" + else + icon_state = "u[reference]p" + else + switch(construction_state) + if(0) + icon_state = "[reference]" + if(1) + icon_state = "[reference]" + if(2) + icon_state = "[reference]w" + else + icon_state = "[reference]c" + return + +/obj/machinery/particle_accelerator/control_box/Topic(href, href_list) + ..() + //Ignore input if we are broken, !silicon guy cant touch us, or nonai controlling from super far away + if(stat & (BROKEN|NOPOWER) || (get_dist(src, usr) > 1 && !istype(usr, /mob/living/silicon)) || (get_dist(src, usr) > 8 && !istype(usr, /mob/living/silicon/ai))) + usr.unset_machine() + usr << browse(null, "window=pacontrol") + return + + if( href_list["close"] ) + usr << browse(null, "window=pacontrol") + usr.unset_machine() + return + + if(href_list["togglep"]) + if(!wires.IsIndexCut(PARTICLE_TOGGLE_WIRE)) + src.toggle_power() + else if(href_list["scan"]) + src.part_scan() + + else if(href_list["strengthup"]) + if(!wires.IsIndexCut(PARTICLE_STRENGTH_WIRE)) + add_strength() + + else if(href_list["strengthdown"]) + if(!wires.IsIndexCut(PARTICLE_STRENGTH_WIRE)) + remove_strength() + + src.updateDialog() + src.update_icon() + return + +/obj/machinery/particle_accelerator/control_box/proc/strength_change() + for(var/obj/structure/particle_accelerator/part in connected_parts) + part.strength = strength + part.update_icon() + +/obj/machinery/particle_accelerator/control_box/proc/add_strength(var/s) + if(assembled) + strength++ + if(strength > strength_upper_limit) + strength = strength_upper_limit + else + message_admins("PA Control Computer increased to [strength] by [key_name(usr, usr.client)](?) in ([x],[y],[z] - JMP)",0,1) + log_game("PA Control Computer increased to [strength] by [usr.ckey]([usr]) in ([x],[y],[z])") + investigate_log("increased to [strength] by [usr.key]","singulo") + strength_change() + +/obj/machinery/particle_accelerator/control_box/proc/remove_strength(var/s) + if(assembled) + strength-- + if(strength < 0) + strength = 0 + else + message_admins("PA Control Computer decreased to [strength] by [key_name(usr, usr.client)](?) in ([x],[y],[z] - JMP)",0,1) + log_game("PA Control Computer decreased to [strength] by [usr.ckey]([usr]) in ([x],[y],[z])") + investigate_log("decreased to [strength] by [usr.key]","singulo") + strength_change() + +/obj/machinery/particle_accelerator/control_box/power_change() + . = ..() + if(stat & NOPOWER) + active = 0 + update_use_power(0) + else if(!stat && construction_state == 3) + update_use_power(1) + return + + +/obj/machinery/particle_accelerator/control_box/Process() + if(src.active) + //a part is missing! + if( length(connected_parts) < 6 ) + investigate_log("lost a connected part; It powered down.","singulo") + src.toggle_power() + return + + for(var/obj/machinery/sunreactor/emitter/PEm) + PEm.icon_state="emitter_passive" + sleep(30) + PEm.icon_state="emitter_active" + PEm.emit_particle(src.strength) + + for(var/obj/machinery/sunreactor/beam/BEp) + BEp.invisibility = 0 + BEp.luminosity = 1 + for(var/obj/machinery/sunreactor/tube_g_v_u/TEup) + sleep(4) + TEup.icon_state="t_glass_v_2" + playsound(src.loc, 'sound/effects/screech.ogg', 75, 1) + + for(var/obj/machinery/sunreactor/tube_g_h_l/TEleft) + sleep(8) + TEleft.icon_state="t_glass_h_2" + playsound(src.loc, 'sound/effects/screech.ogg', 75, 1) + + for(var/obj/machinery/sunreactor/tube_g_v_d/TEdown) + sleep(12) + TEdown.icon_state="t_glass_v_2" + playsound(src.loc, 'sound/effects/screech.ogg', 75, 1) + + for(var/obj/machinery/sunreactor/tube_g_h_r/TEright) + sleep(16) + TEright.icon_state="t_glass_h_2" + playsound(src.loc, 'sound/effects/screech.ogg', 75, 1) + //emit some particles + for(var/obj/structure/particle_accelerator/particle_emitter/PE in connected_parts) + if(PE) + PE.emit_particle(src.strength) + return + + +/obj/machinery/particle_accelerator/control_box/proc/part_scan() + for(var/obj/structure/particle_accelerator/fuel_chamber/F in orange(1,src)) + src.set_dir(F.dir) + connected_parts = list() + var/tally = 0 + var/ldir = turn(dir,-90) + var/rdir = turn(dir,90) + var/odir = turn(dir,180) + var/turf/T = src.loc + T = get_step(T,rdir) + if(check_part(T,/obj/structure/particle_accelerator/fuel_chamber)) + tally++ + T = get_step(T,odir) + if(check_part(T,/obj/structure/particle_accelerator/end_cap)) + tally++ + T = get_step(T,dir) + T = get_step(T,dir) + if(check_part(T,/obj/structure/particle_accelerator/power_box)) + tally++ + T = get_step(T,dir) + if(check_part(T,/obj/structure/particle_accelerator/particle_emitter/center)) + tally++ + T = get_step(T,ldir) + if(check_part(T,/obj/structure/particle_accelerator/particle_emitter/left)) + tally++ + T = get_step(T,rdir) + T = get_step(T,rdir) + if(check_part(T,/obj/structure/particle_accelerator/particle_emitter/right)) + tally++ + if(tally >= 6) + assembled = 1 + return 1 + else + assembled = 0 + return 0 + + +/obj/machinery/particle_accelerator/control_box/proc/check_part(var/turf/T, var/type) + if(!(T)||!(type)) + return 0 + var/obj/structure/particle_accelerator/PA = locate(/obj/structure/particle_accelerator) in T + if(istype(PA, type)) + if(PA.connect_master(src)) + if(PA.report_ready(src)) + src.connected_parts.Add(PA) + return 1 + return 0 + + +/obj/machinery/particle_accelerator/control_box/proc/toggle_power() + src.active = !src.active + investigate_log("turned [active?"ON":"OFF"] by [usr ? usr.key : "outside forces"]","singulo") + message_admins("PA Control Computer turned [active ?"ON":"OFF"] by [key_name(usr, usr.client)](?) in ([x],[y],[z] - JMP)",0,1) + log_game("PA Control Computer turned [active ?"ON":"OFF"] by [usr.ckey]([usr]) in ([x],[y],[z])") + if(src.active) + update_use_power(2) + for(var/obj/structure/particle_accelerator/part in connected_parts) + part.strength = src.strength + part.powered = 1 + part.update_icon() + else + update_use_power(1) + for(var/obj/structure/particle_accelerator/part in connected_parts) + part.strength = null + part.powered = 0 + part.update_icon() + return 1 + + +/obj/machinery/particle_accelerator/control_box/interact(mob/user) + if((get_dist(src, user) > 1) || (stat & (BROKEN|NOPOWER))) + if(!istype(user, /mob/living/silicon)) + user.unset_machine() + user << browse(null, "window=pacontrol") + return + user.set_machine(src) + reactor = locate(/obj/machinery/sunreactor/center) + var/dat = "" + dat += "Particle Accelerator Control Panel
            " + dat += "Temperature: ~[reactor.energy].000c
            " + dat += "Close

            " + dat += "Status:
            " + if(!assembled) + dat += "Unable to detect all parts!
            " + dat += "Run Scan

            " + else + dat += "All parts in place.

            " + dat += "Power:" + if(active) + dat += "On
            " + else + dat += "Off
            " + dat += "Toggle Power

            " + dat += "Particle Strength: [src.strength] " + dat += "--|++

            " + + user << browse(dat, "window=pacontrol;size=420x500") + onclose(user, "pacontrol") + return \ No newline at end of file diff --git a/code/modules/power/singularity/particle_accelerator/particle_emitter.dm b/code/modules/power/singularity/particle_accelerator/particle_emitter.dm new file mode 100644 index 00000000..eba322bb --- /dev/null +++ b/code/modules/power/singularity/particle_accelerator/particle_emitter.dm @@ -0,0 +1,45 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +/obj/structure/particle_accelerator/particle_emitter + name = "EM Containment Grid" + desc_holder = "This launchs the Alpha particles, might not want to stand near this end." + icon = 'icons/obj/machines/particle_accelerator2.dmi' + icon_state = "none" + var/fire_delay = 50 + var/last_shot = 0 + +/obj/structure/particle_accelerator/particle_emitter/center + icon_state = "emitter_center" + reference = "emitter_center" + +/obj/structure/particle_accelerator/particle_emitter/left + icon_state = "emitter_left" + reference = "emitter_left" + +/obj/structure/particle_accelerator/particle_emitter/right + icon_state = "emitter_right" + reference = "emitter_right" + +/obj/structure/particle_accelerator/particle_emitter/proc/set_delay(var/delay) + if(delay && delay >= 0) + src.fire_delay = delay + return 1 + return 0 + + +/obj/structure/particle_accelerator/particle_emitter/proc/emit_particle(var/strength = 0) + if((src.last_shot + src.fire_delay) <= world.time) + src.last_shot = world.time + var/obj/effect/accelerated_particle/A = null + var/turf/T = get_step(src,dir) + switch(strength) + if(0) + A = new/obj/effect/accelerated_particle/weak(T, dir) + if(1) + A = new/obj/effect/accelerated_particle(T, dir) + if(2) + A = new/obj/effect/accelerated_particle/strong(T, dir) + if(A) + A.set_dir(src.dir) + return 1 + return 0 diff --git a/code/modules/power/singularity/particle_accelerator/particle_power.dm b/code/modules/power/singularity/particle_accelerator/particle_power.dm new file mode 100644 index 00000000..9d574a1c --- /dev/null +++ b/code/modules/power/singularity/particle_accelerator/particle_power.dm @@ -0,0 +1,10 @@ +/obj/structure/particle_accelerator/power_box + name = "Particle Focusing EM Lens" + desc_holder = "This uses electromagnetic waves to focus the Alpha-Particles." + icon = 'icons/obj/machines/particle_accelerator2.dmi' + icon_state = "power_box" + reference = "power_box" + +/obj/structure/particle_accelerator/power_box/update_icon() + ..() + return diff --git a/code/modules/power/singularity/particle_accelerator/sunreactor.dm b/code/modules/power/singularity/particle_accelerator/sunreactor.dm new file mode 100644 index 00000000..7a3a9f37 --- /dev/null +++ b/code/modules/power/singularity/particle_accelerator/sunreactor.dm @@ -0,0 +1,665 @@ +// Dumbass's code. For first time. + +/obj/machinery/sunreactor + name = "Atomic Reactor" + desc = "Part of a 'Sun Reactor'." + icon = 'icons/obj/machines/particle_accelerator.dmi' + icon_state = "none" + anchored = 1 + density = 1 + var/desc_holder = null + +/obj/machinery/sunreactor/emitter/ + name = "Emitter" + desc_holder = "Wireless beam generator, might not want to stand near this end." + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "emitter_offline" + var/fire_delay = 50 + var/last_shot = 0 + var/safety = 1 + +/obj/machinery/sunreactor/emitter/attackby(obj/item/W, mob/user) + if(istype(W, /obj/item/weapon/wrench)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + if(safety == 1) + safety = 0 + user.visible_message("[user.name] secures [src.name].", \ + "You turn the [src.name] powerswitch to 'ON', now it'll produse a beams.", \ + "You hear a ratchet") + else + safety = 1 + user.visible_message("[user.name] unsecures [src.name] from the floor.", \ + "You turn the [src.name] powerswitch to 'OFF'.", \ + "You hear a ratchet") + return + + +/obj/machinery/sunreactor/emitter/proc/emit_particle(var/strength = 0) + if((src.last_shot + src.fire_delay) <= world.time) + src.last_shot = world.time + var/obj/effect/accelerated_particle/A = null + var/turf/T = get_step(src,dir) + switch(strength) + if(0) + if(src.safety == 0) + A = new/obj/effect/accelerated_particle/weak(T, dir) + playsound(src.loc, 'sound/weapons/emitter2.ogg', 25, 1) + else + A = new/obj/effect/sparks(src.loc) + if(1) + if(src.safety == 0) + A = new/obj/effect/accelerated_particle(T, dir) + playsound(src.loc, 'sound/weapons/emitter2.ogg', 25, 1) + else + A = new/obj/effect/sparks(src.loc) + if(2) + if(src.safety == 0) + A = new/obj/effect/accelerated_particle/strong(T, dir) + playsound(src.loc, 'sound/weapons/emitter2.ogg', 25, 1) + else + A = new/obj/effect/sparks(src.loc) + if(A) + A.dir = src.dir + return 1 + return 0 + +/obj/machinery/sunreactor/emitter/proc/set_delay(var/delay) + if(delay && delay >= 0) + src.fire_delay = delay + return 1 + return 0 + + +/obj/machinery/sunreactor/emitter/update_icon() + ..() + return + +/obj/machinery/sunreactor/rleft + name = "Core stabilizer" + desc_holder = "It's perfect." + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "rear_e_1" + use_power = 0 + var/energy = 0 + +/obj/machinery/sunreactor/rleft/Process() +// get_turf(src) + if((src.energy >= 20)&(src.energy <100)) + icon_state = "rear_e_2" + playsound(src.loc, 'sound/effects/reactor.ogg', 75, 1) + src.energy += 100 + sleep(30) + icon_state = "rear_e_3" + +/obj/machinery/sunreactor/rright + name = "Core stabilizer" + desc_holder = "It's perfect." + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "rear_w_1" + use_power = 0 + var/energy = 0 + +/obj/machinery/sunreactor/rright/Process() +// get_turf(src) + if((src.energy >= 45)&(src.energy < 100)) + icon_state = "rear_w_2" + playsound(src.loc, 'sound/effects/reactor.ogg', 75, 1) + src.energy += 100 + sleep(30) + icon_state = "rear_w_3" + +/obj/machinery/sunreactor/rdown + name = "Core stabilizer" + desc_holder = "It's perfect." + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "rear_n_1" + use_power = 0 + var/energy = 0 + +/obj/machinery/sunreactor/rdown/Process() +// get_turf(src) + if((src.energy >= 60)&(src.energy < 100)) + icon_state = "rear_n_2" + playsound(src.loc, 'sound/effects/reactor.ogg', 75, 1) + src.energy += 100 + sleep(30) + icon_state = "rear_n_3" + +/obj/machinery/sunreactor/rup + name = "Core stabilizer" + desc_holder = "It's perfect." + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "rear_s_1" + use_power = 0 + var/energy = 0 + +/obj/machinery/sunreactor/rup/Process() +// get_turf(src) + if((src.energy >= 75)&(src.energy < 100)) + icon_state = "rear_s_2" + playsound(src.loc, 'sound/effects/reactor.ogg', 75, 1) + src.energy += 100 + sleep(30) + icon_state = "rear_s_3" + +/obj/machinery/sunreactor/tube_h + name = "Tube" + desc_holder = "It's tube." + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "t_h" + use_power = 0 + +/obj/machinery/sunreactor/tube_v + name = "Tube" + desc_holder = "It's tube." + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "t_v" + use_power = 0 + +/obj/machinery/sunreactor/tube_g_h_l + name = "Tube" + desc_holder = "It's tube." + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "t_glass_h_1" + use_power = 0 + +/obj/machinery/sunreactor/tube_g_h_r + name = "Tube" + desc_holder = "It's tube." + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "t_glass_h_1" + use_power = 0 + +/obj/machinery/sunreactor/tube_g_v_u + name = "Tube" + desc_holder = "It's tube." + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "t_glass_v_1" + use_power = 0 + +/obj/machinery/sunreactor/tube_g_v_d + name = "Tube" + desc_holder = "It's tube." + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "t_glass_v_1" + use_power = 0 + +/obj/machinery/particle_accelerator/examine() + src.desc = src.desc_holder + ..() + return + +/obj/machinery/sunreactor/core + name = "Core" + desc_holder = "It's reactor Core." + icon = 'icons/obj/projectiles.dmi' + icon_state = "bluespace" + layer = 6 + density = 0 + use_power = 0 + +/obj/machinery/sunreactor/beam + name = "Light beam" + desc_holder = "Just a light." + icon = 'icons/obj/projectiles.dmi' + icon_state = "reactorbeam" + use_power = 0 + density = 0 + invisibility = 100 + luminosity = 0 + +/obj/machinery/sunreactor/beam/New() + set_light(2, 1.5, "#00f9ff") + + +/obj/machinery/sunreactor/core/New() + var/list/L = list( ) + var/list/turfs = list( ) + for(var/turf/T in orange(10)) + if(T.x>world.maxx-8 || T.x<8) continue //putting them at the edge is dumb + if(T.y>world.maxy-8 || T.y<8) continue + turfs += T + if(turfs.len) + L["None (Dangerous)"] = pick(turfs) + //var/t1 = input(src, "Please select a teleporter to lock in on.", "Hand Teleporter") in L + var/T = L["None (Dangerous)"] + var/obj/effect/portal/P = new /obj/effect/portal( get_turf(src) ) + P.target = T + P.creator = src + P.name = "Core" + P.icon = 'icons/obj/projectiles.dmi' + P.icon_state = "bluespace" + set_light(2, 5, "#00f9ff") + return + for(var/atom/A in src.loc) + if(!istype(A, /obj/machinery/sunreactor/center)) + sleep (rand(50,100)) + explosion(src.loc,-1,-1,2) + qdel(src) + set_light(0) + +/obj/machinery/sunreactor/center + name = "Plasma generator" + desc_holder = "It generates plasma. Stay out." + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "r_c_1" + anchored = 1 + density = 1 + luminosity = 6 + unacidable = 1 //Don't comment this out. + use_power = 0 + var/current_size = 1 + var/allowed_size = 1 + var/contained = 1 //Are we going to move around? + var/energy = 0 //How strong are we? + var/dissipate = 1 //Do we lose energy over time? + var/dissipate_delay = 10 + var/dissipate_track = 0 + var/dissipate_strength = 1 //How much energy do we lose? + var/move_self = 0 //Do we move on our own? + var/grav_pull = 4 //How many tiles out do we pull? + var/consume_range = 0 //How many tiles out do we eat + var/event_chance = 15 //Prob for event each tick + var/target = null //its target. moves towards the target if it has one + var/last_failed_movement = 0//Will not move in the same dir if it couldnt before, will help with the getting stuck on fields thing + var/teleport_del = 0 + var/last_warning + +/obj/machinery/sunreactor/center/attack_hand(mob/user as mob) + consume(user) + return 1 + +/obj/machinery/sunreactor/center/ex_act(severity) + switch(severity) + if(1.0) + if(prob(25)) + qdel(src) + return + set_light(0) + else + energy += 50 + if(2.0 to 3.0) + energy += round((rand(20,60)/2),1) + return + return + + +/obj/machinery/sunreactor/center/Bump(atom/A) + consume(A) + return + + +/obj/machinery/sunreactor/center/Bumped(atom/A) + consume(A) + return + + +/obj/machinery/sunreactor/center/Process() +// eat() + dissipate() + check_energy() + if(current_size >= 3) + //move() + pulse() + if(prob(event_chance))//Chance for it to run a special event TODO:Come up with one or two more that fit + event() + return + + +/obj/machinery/sunreactor/center/attack_ai() //to prevent ais from gibbing themselves when they click on one. + return + +/obj/machinery/sunreactor/center/proc/dissipate() + if(!dissipate) + return + if(dissipate_track >= dissipate_delay) + var/turf/Under + Under = get_turf(src) + src.energy -= dissipate_strength*(290/Under.temperature) + dissipate_track = 0 + else + dissipate_track++ + +/obj/machinery/sunreactor/center/proc/reactor_explosion() + explosion(src.loc,5,9,12) + del(src) + + +/obj/machinery/sunreactor/center/proc/reactor_rad() + + for(var/mob/living/carbon/human/H in GLOB.living_mob_list_) + var/turf/T = get_turf(H) + if(!T) + continue + if(T.z != 1) + continue + if(istype(H,/mob/living/carbon/human)) + H.apply_effect((rand(15,75)),IRRADIATE,0) + if (prob(5)) + H.apply_effect((rand(90,150)),IRRADIATE,0) + if (prob(25)) + if (prob(75)) + randmutb(H) + domutcheck(H,null,1) + else + randmutg(H) + domutcheck(H,null,1) + for(var/mob/living/carbon/human/monkey/M in GLOB.living_mob_list_) + var/turf/T = get_turf(M) + if(!T) + continue + if(T.z != 1) + continue + M.apply_effect((rand(15,75)),IRRADIATE,0) + sleep(100) + for(var/mob/M in GLOB.player_list) + M << sound('sound/AI/radiation.ogg') + +/obj/machinery/sunreactor/center/proc/expand(var/force_size = 0) + var/temp_allowed_size = src.allowed_size + if(force_size) + temp_allowed_size = force_size + switch(temp_allowed_size) + if(1) + current_size = 1 + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "r_c_2" + pixel_x = 0 + pixel_y = 0 + grav_pull = 4 + consume_range = 0 + dissipate_delay = 10 + dissipate_track = 0 + dissipate_strength = 1 + set_light(0) + if(3) + current_size = 3 + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "r_c_3" + pixel_x = 0 + pixel_y = 0 + grav_pull = 6 + consume_range = 1 + dissipate_delay = 5 + dissipate_track = 0 + dissipate_strength = 5 + set_light(0) + set_light(2, 1.5, "#00f9ff") + if(5) + current_size = 5 + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "r_c_3" + pixel_x = 0 + pixel_y = 0 + grav_pull = 8 + consume_range = 2 + dissipate_delay = 4 + dissipate_track = 0 + dissipate_strength = 20 + set_light(0) + set_light(2, 1.5, "#00f9ff") + new/obj/machinery/sunreactor/core(src.loc) + + if(7) + current_size = 7 + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "r_c_3" + pixel_x = 0 + pixel_y = 0 + grav_pull = 10 + consume_range = 3 + dissipate_delay = 10 + dissipate_track = 0 + dissipate_strength = 10 + set_light(0) + set_light(2, 1.5, "#00f9ff") + for(var/mob/M in GLOB.player_list) + M << sound('sound/effects/siren.ogg') + sleep(20) + new/obj/effect/effect/smoke(src.loc) + sleep(20) + new/obj/effect/effect/smoke(src.loc) + + if(9) + current_size = 9 + icon = 'icons/obj/machines/sunreactor.dmi' + icon_state = "r_c_3" + pixel_x = 0 + pixel_y = 0 + grav_pull = 10 + consume_range = 4 + dissipate = 0 //It cant go smaller due to e loss + reactor_rad() + // sleep(200) + reactor_explosion() + set_light(0) + set_light(2, 1.5, "#00f9ff") + qdel(src) + if(current_size == allowed_size) + investigate_log("grew to size [current_size]","singulo") + return 1 + else if(current_size < (--temp_allowed_size)) + expand(temp_allowed_size) + else + return 0 + + +/obj/machinery/sunreactor/center/proc/check_energy() + + switch(energy)//Some of these numbers might need to be changed up later -Mport + if(1 to 149) + allowed_size = 1 + if(150 to 299) + allowed_size = 3 + if(300 to 499) + allowed_size = 5 + if(500 to 569) + allowed_size = 7 + if(570 to INFINITY) + allowed_size = 9 + if(current_size != allowed_size) + expand() + return 1 + +/obj/machinery/sunreactor/center/proc/consume(var/atom/A) + var/gain = 0 + if (istype(A,/mob/living))//Mobs get gibbed + gain = 20 + if(istype(A,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = A + if(H.mind) + + if((H.mind.assigned_role == "Station Engineer") || (H.mind.assigned_role == "Chief Engineer") ) + gain = 100 + + if(H.mind.assigned_role == "Clown") + gain = rand(-300, 300) // HONK + + spawn() + A:gib() + sleep(1) + else if(istype(A,/obj/)) + + if (istype(A,/obj/item/weapon/storage/backpack/holding)) + var/dist = max((current_size - 2),1) + explosion(src.loc,(dist),(dist*2),(dist*4)) + return + + if((teleport_del) && (!istype(A, /obj/machinery)))//Going to see if it does not lag less to tele items over to Z 2 + var/obj/O = A + O.x = 2 + O.y = 2 + O.z = 2 + else + A.ex_act(1.0) + if(A) del(A) + gain = 2 + else if(isturf(A)) + var/turf/T = A + for(var/obj/O in T.contents) + if(O.level != 1) + continue + if(O.invisibility == 101) + src.consume(O) + T.ChangeTurf(/turf/simulated/floor/plating/) + gain = 2 + src.energy += gain + return + + +/obj/machinery/sunreactor/center/proc/move(var/force_move = 0) + if(!move_self) + return 0 + + var/movement_dir = pick(GLOB.alldirs - last_failed_movement) + + if(force_move) + movement_dir = force_move + + if(target && prob(60)) + movement_dir = get_dir(src,target) //moves to a singulo beacon, if there is one + + if(current_size >= 9)//The superlarge one does not care about things in its way + spawn(0) + step(src, movement_dir) + spawn(1) + step(src, movement_dir) + return 1 + else if(check_turfs_in(movement_dir)) + last_failed_movement = 0//Reset this because we moved + spawn(0) + step(src, movement_dir) + return 1 + else + last_failed_movement = movement_dir + return 0 + + +/obj/machinery/sunreactor/center/proc/check_turfs_in(var/direction = 0, var/step = 0) + if(!direction) + return 0 + var/steps = 0 + if(!step) + switch(current_size) + if(1) + steps = 1 + if(3) + steps = 3//Yes this is right + if(5) + steps = 3 + if(7) + steps = 4 + if(9) + steps = 5 + else + steps = step + var/list/turfs = list() + var/turf/T = src.loc + for(var/i = 1 to steps) + T = get_step(T,direction) + if(!isturf(T)) + return 0 + turfs.Add(T) + var/dir2 = 0 + var/dir3 = 0 + switch(direction) + if(NORTH||SOUTH) + dir2 = 4 + dir3 = 8 + if(EAST||WEST) + dir2 = 1 + dir3 = 2 + var/turf/T2 = T + for(var/j = 1 to steps) + T2 = get_step(T2,dir2) + if(!isturf(T2)) + return 0 + turfs.Add(T2) + for(var/k = 1 to steps) + T = get_step(T,dir3) + if(!isturf(T)) + return 0 + turfs.Add(T) + for(var/turf/T3 in turfs) + if(isnull(T3)) + continue + if(!can_move(T3)) + return 0 + return 1 + + +/obj/machinery/sunreactor/center/proc/can_move(var/turf/T) + if(!T) + return 0 + if((locate(/obj/machinery/containment_field) in T)||(locate(/obj/machinery/shieldwall) in T)) + return 0 + else if(locate(/obj/machinery/field_generator) in T) + var/obj/machinery/field_generator/G = locate(/obj/machinery/field_generator) in T + if(G && G.active) + return 0 + else if(locate(/obj/machinery/shieldwallgen) in T) + var/obj/machinery/shieldwallgen/S = locate(/obj/machinery/shieldwallgen) in T + if(S && S.active) + return 0 + return 1 + + +/obj/machinery/sunreactor/center/proc/event() + var/numb = pick(1,2,3,4,5,6) + switch(numb) + if(1)//EMP + emp_area() + if(2,3)//tox damage all carbon mobs in area + toxmob() + if(4)//Stun mobs who lack optic scanners + mezzer() + else + return 0 + return 1 + + +/obj/machinery/sunreactor/center/proc/toxmob() + var/toxrange = 10 + var/toxdamage = 4 + var/radiation = 15 + var/radiationmin = 3 + if (src.energy>200) + toxdamage = round(((src.energy-150)/50)*4,1) + radiation = round(((src.energy-150)/50)*5,1) + radiationmin = round((radiation/5),1)// + for(var/mob/living/M in view(toxrange, src.loc)) + M.apply_effect(rand(radiationmin,radiation), IRRADIATE) + toxdamage = (toxdamage - (toxdamage*M.getarmor(null, "rad"))) + M.apply_effect(toxdamage, TOX) + return + + +/obj/machinery/sunreactor/center/proc/mezzer() + for(var/mob/living/carbon/M in oviewers(8, src)) + if(istype(M, /mob/living/carbon/brain)) //Ignore brains + continue + + if(M.stat == CONSCIOUS) + if (istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(istype(H.glasses,/obj/item/clothing/glasses/meson)) + H << "\blue You look directly into The [src.name], good thing you had your protective eyewear on!" + return + M << "\red You look directly into The [src.name] and feel weak." + M.apply_effect(3, STUN) + for(var/mob/O in viewers(M, null)) + O.show_message(text("\red [] stares blankly at The []!", M, src), 1) + return + + +/obj/machinery/sunreactor/center/proc/emp_area() + empulse(src, 4, 8) + return + + +/obj/machinery/sunreactor/center/proc/pulse() + + for(var/obj/machinery/power/rad_collector/R in rad_collectors) + if(get_dist(R, src) <= 15) // Better than using orange() every process + R.receive_pulse(energy) + return \ No newline at end of file diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm new file mode 100644 index 00000000..86b0d193 --- /dev/null +++ b/code/modules/power/singularity/singularity.dm @@ -0,0 +1,492 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +/obj/singularity/ + name = "gravitational singularity" + desc = "A gravitational singularity." + icon = 'icons/obj/singularity.dmi' + icon_state = "singularity_s1" + anchored = 1 + density = 1 + plane = EFFECTS_BELOW_LIGHTING_PLANE + layer = SINGULARITY_LAYER + light_range = 6 + unacidable = 1 //Don't comment this out. + + var/current_size = 1 + var/allowed_size = 1 + var/contained = 1 //Are we going to move around? + var/energy = 100 //How strong are we? + var/dissipate = 1 //Do we lose energy over time? + var/dissipate_delay = 10 + var/dissipate_track = 0 + var/dissipate_strength = 1 //How much energy do we lose? + var/move_self = 1 //Do we move on our own? + var/grav_pull = 4 //How many tiles out do we pull? + var/consume_range = 0 //How many tiles out do we eat. + var/event_chance = 15 //Prob for event each tick. + var/target = null //Its target. Moves towards the target if it has one. + var/last_failed_movement = 0 //Will not move in the same dir if it couldnt before, will help with the getting stuck on fields thing. + var/last_warning + + var/chained = 0//Adminbus chain-grab + +/obj/singularity/New(loc, var/starting_energy = 50, var/temp = 0) + //CARN: admin-alert for chuckle-fuckery. + admin_investigate_setup() + energy = starting_energy + + if (temp) + spawn (temp) + qdel(src) + + ..() + START_PROCESSING(SSobj, src) + for(var/obj/machinery/power/singularity_beacon/singubeacon in SSmachines.machinery) + if(singubeacon.active) + target = singubeacon + break + +/obj/singularity/Destroy() + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/singularity/attack_hand(mob/user as mob) + consume(user) + return 1 + +/obj/singularity/ex_act(severity) + if(current_size == STAGE_SUPER)//IT'S UNSTOPPABLE + return + switch(severity) + if(1.0) + if(prob(25)) + investigate_log("has been destroyed by an explosion.", I_SINGULO) + qdel(src) + return + else + energy += 50 + if(2.0 to 3.0) + energy += round((rand(20,60)/2),1) + return + +/obj/singularity/bullet_act(obj/item/projectile/P) + return 0 //Will there be an impact? Who knows. Will we see it? No. + +/obj/singularity/Bump(atom/A) + consume(A) + +/obj/singularity/Bumped(atom/A) + consume(A) + +/obj/singularity/Process() + eat() + dissipate() + check_energy() + + if (current_size >= STAGE_TWO) + move() + pulse() + + if (prob(event_chance)) //Chance for it to run a special event TODO: Come up with one or two more that fit. + event() + +/obj/singularity/attack_ai() //To prevent ais from gibbing themselves when they click on one. + return + +/obj/singularity/proc/admin_investigate_setup() + last_warning = world.time + var/count = locate(/obj/machinery/containment_field) in orange(30, src) + + if (!count) + message_admins("A singulo has been created without containment fields active ([x], [y], [z] - JMP).") + + investigate_log("was created. [count ? "" : "No containment fields were active."]", I_SINGULO) + +/obj/singularity/proc/dissipate() + if (!dissipate) + return + + if(dissipate_track >= dissipate_delay) + energy -= dissipate_strength + dissipate_track = 0 + else + dissipate_track++ + +/obj/singularity/proc/expand(var/force_size = 0, var/growing = 1) + if(current_size == STAGE_SUPER)//if this is happening, this is an error + message_admins("expand() was called on a super singulo. This should not happen. Contact a coder immediately!") + return + var/temp_allowed_size = allowed_size + + if (force_size) + temp_allowed_size = force_size + + switch (temp_allowed_size) + if (STAGE_ONE) + SetName("gravitational singularity") + desc = "A gravitational singularity." + current_size = STAGE_ONE + icon = 'icons/obj/singularity.dmi' + icon_state = "singularity_s1" + pixel_x = 0 + pixel_y = 0 + grav_pull = 4 + consume_range = 0 + dissipate_delay = 10 + dissipate_track = 0 + dissipate_strength = 1 + overlays = 0 + if(chained) + overlays = "chain_s1" + visible_message("The singularity has shrunk to a rather pitiful size.") + if (STAGE_TWO) //1 to 3 does not check for the turfs if you put the gens right next to a 1x1 then its going to eat them. + SetName("gravitational singularity") + desc = "A gravitational singularity." + current_size = STAGE_TWO + icon = 'icons/effects/96x96.dmi' + icon_state = "singularity_s3" + pixel_x = -32 + pixel_y = -32 + grav_pull = 6 + consume_range = 1 + dissipate_delay = 5 + dissipate_track = 0 + dissipate_strength = 5 + overlays = 0 + if(chained) + overlays = "chain_s3" + if(growing) + visible_message("The singularity noticeably grows in size.") + else + visible_message("The singularity has shrunk to a less powerful size.") + if (STAGE_THREE) + if ((check_turfs_in(1, 2)) && (check_turfs_in(2, 2)) && (check_turfs_in(4, 2)) && (check_turfs_in(8, 2))) + SetName("gravitational singularity") + desc = "A gravitational singularity." + current_size = STAGE_THREE + icon = 'icons/effects/160x160.dmi' + icon_state = "singularity_s5" + pixel_x = -64 + pixel_y = -64 + grav_pull = 8 + consume_range = 2 + dissipate_delay = 4 + dissipate_track = 0 + dissipate_strength = 20 + overlays = 0 + if(chained) + overlays = "chain_s5" + if(growing) + visible_message("The singularity expands to a reasonable size.") + else + visible_message("The singularity has returned to a safe size.") + if(STAGE_FOUR) + if ((check_turfs_in(1, 3)) && (check_turfs_in(2, 3)) && (check_turfs_in(4, 3)) && (check_turfs_in(8, 3))) + SetName("gravitational singularity") + desc = "A gravitational singularity." + current_size = STAGE_FOUR + icon = 'icons/effects/224x224.dmi' + icon_state = "singularity_s7" + pixel_x = -96 + pixel_y = -96 + grav_pull = 10 + consume_range = 3 + dissipate_delay = 10 + dissipate_track = 0 + dissipate_strength = 10 + overlays = 0 + if(chained) + overlays = "chain_s7" + if(growing) + visible_message("The singularity expands to a dangerous size.") + else + visible_message("Miraculously, the singularity reduces in size, and can be contained.") + if(STAGE_FIVE) //This one also lacks a check for gens because it eats everything. + SetName("gravitational singularity") + desc = "A gravitational singularity." + current_size = STAGE_FIVE + icon = 'icons/effects/288x288.dmi' + icon_state = "singularity_s9" + pixel_x = -128 + pixel_y = -128 + grav_pull = 10 + consume_range = 4 + dissipate = 0 //It cant go smaller due to e loss. + overlays = 0 + if(chained) + overlays = "chain_s9" + if(growing) + visible_message("The singularity has grown out of control!") + else + visible_message("The singularity miraculously reduces in size and loses its supermatter properties.") + if(STAGE_SUPER)//SUPERSINGULO + SetName("super gravitational singularity") + desc = "A gravitational singularity with the properties of supermatter. It has the power to destroy worlds." + current_size = STAGE_SUPER + icon = 'icons/effects/352x352.dmi' + icon_state = "singularity_s11"//uh, whoever drew that, you know that black holes are supposed to look dark right? What's this, the clown's singulo? + pixel_x = -160 + pixel_y = -160 + grav_pull = 16 + consume_range = 5 + dissipate = 0 //It cant go smaller due to e loss + event_chance = 25 //Events will fire off more often. + if(chained) + overlays = "chain_s9" + visible_message("You witness the creation of a destructive force that cannot possibly be stopped by human hands.") + + if (current_size == allowed_size) + investigate_log("grew to size [current_size].", I_SINGULO) + return 1 + else if (current_size < (--temp_allowed_size) && current_size != STAGE_SUPER) + expand(temp_allowed_size) + else + return 0 + +/obj/singularity/proc/check_energy() + if (energy <= 0) + investigate_log("collapsed.", I_SINGULO) + qdel(src) + return 0 + + switch (energy) //Some of these numbers might need to be changed up later -Mport. + if (1 to 199) + allowed_size = STAGE_ONE + if (200 to 499) + allowed_size = STAGE_TWO + if (500 to 999) + allowed_size = STAGE_THREE + if (1000 to 1999) + allowed_size = STAGE_FOUR + if(2000 to 49999) + allowed_size = STAGE_FIVE + if(50000 to INFINITY) + allowed_size = STAGE_SUPER + + if (current_size != allowed_size && current_size != STAGE_SUPER) + expand(null, current_size < allowed_size) + return 1 + +/obj/singularity/proc/eat() + for(var/atom/X in orange(grav_pull, src)) + var/dist = get_dist(X, src) + var/obj/singularity/S = src + if(!istype(src)) + return + if(dist > consume_range) + X.singularity_pull(S, current_size) + else if(dist <= consume_range) + consume(X) + + //for (var/turf/T in trange(grav_pull, src)) //TODO: Create a similar trange for orange to prevent snowflake of self check. + // consume(T) + + return + +/obj/singularity/proc/consume(const/atom/A) + src.energy += A.singularity_act(src, current_size) + return + +/obj/singularity/proc/move(var/force_move = 0) + if(!move_self) + return 0 + + var/movement_dir = pick(GLOB.alldirs - last_failed_movement) + + if(force_move) + movement_dir = force_move + + if(target && prob(60)) + movement_dir = get_dir(src,target) //moves to a singulo beacon, if there is one + + if(current_size >= 9)//The superlarge one does not care about things in its way + spawn(0) + step(src, movement_dir) + spawn(1) + step(src, movement_dir) + return 1 + else if(check_turfs_in(movement_dir)) + last_failed_movement = 0 // Reset this because we moved + spawn(0) + step(src, movement_dir) + return 1 + else + last_failed_movement = movement_dir + return 0 + +/obj/singularity/proc/check_turfs_in(var/direction = 0, var/step = 0) + if(!direction) + return 0 + var/steps = 0 + if(!step) + switch(current_size) + if(1) + steps = 1 + if(3) + steps = 3//Yes this is right + if(5) + steps = 3 + if(7) + steps = 4 + if(9) + steps = 5 + if(11) + steps = 6 + else + steps = step + var/list/turfs = list() + var/turf/T = src.loc + for(var/i = 1 to steps) + T = get_step(T,direction) + if(!isturf(T)) + return 0 + turfs.Add(T) + var/dir2 = 0 + var/dir3 = 0 + switch(direction) + if(NORTH||SOUTH) + dir2 = 4 + dir3 = 8 + if(EAST||WEST) + dir2 = 1 + dir3 = 2 + var/turf/T2 = T + for(var/j = 1 to steps) + T2 = get_step(T2,dir2) + if(!isturf(T2)) + return 0 + turfs.Add(T2) + for(var/k = 1 to steps) + T = get_step(T,dir3) + if(!isturf(T)) + return 0 + turfs.Add(T) + for(var/turf/T3 in turfs) + if(isnull(T3)) + continue + if(!can_move(T3)) + return 0 + return 1 + +/obj/singularity/proc/can_move(const/turf/T) + if (!isturf(T)) + return 0 + + if ((locate(/obj/machinery/containment_field) in T) || (locate(/obj/machinery/shieldwall) in T)) + return 0 + else if (locate(/obj/machinery/field_generator) in T) + var/obj/machinery/field_generator/G = locate(/obj/machinery/field_generator) in T + + if (G && G.active) + return 0 + else if (locate(/obj/machinery/shieldwallgen) in T) + var/obj/machinery/shieldwallgen/S = locate(/obj/machinery/shieldwallgen) in T + + if (S && S.active) + return 0 + return 1 + +/obj/singularity/proc/event() + var/numb = pick(1, 2, 3, 4, 5, 6) + + switch (numb) + if (1) //EMP. + emp_area() + if (2, 3) //Tox damage all carbon mobs in area. + toxmob() + if (4) //Stun mobs who lack optic scanners. + mezzer() + else + return 0 + if(current_size == 11) + smwave() + return 1 + + +/obj/singularity/proc/toxmob() + var/toxrange = 10 + var/toxdamage = 4 + var/radiation = 15 + if (src.energy>200) + toxdamage = round(((src.energy-150)/50)*4,1) + radiation = round(((src.energy-150)/50)*5,1) + radiation_repository.radiate(src, radiation) //Always radiate at max, so a decent dose of radiation is applied + for(var/mob/living/M in view(toxrange, src.loc)) + if(M.status_flags & GODMODE) + continue + toxdamage = (toxdamage - (toxdamage*M.getarmor(null, "rad"))) + M.apply_effect(toxdamage, TOX) + return + + +/obj/singularity/proc/mezzer() + for(var/mob/living/carbon/M in oviewers(8, src)) + if(istype(M, /mob/living/carbon/brain)) //Ignore brains + continue + if(M.status_flags & GODMODE) + continue + if(M.stat == CONSCIOUS) + if (istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(istype(H.glasses,/obj/item/clothing/glasses/meson) && current_size != 11) + to_chat(H, "You look directly into The [src.name], good thing you had your protective eyewear on!") + return + else + to_chat(H, "You look directly into The [src.name], but your eyewear does absolutely nothing to protect you from it!") + to_chat(M, "You look directly into The [src.name] and feel [current_size == 11 ? "helpless" : "weak"].") + M.apply_effect(3, STUN) + for(var/mob/O in viewers(M, null)) + O.show_message(text("[] stares blankly at The []!", M, src), 1) + +/obj/singularity/proc/emp_area() + if(current_size != 11) + empulse(src, 8, 10) + else + empulse(src, 12, 16) + +/obj/singularity/proc/smwave() + for(var/mob/living/M in view(10, src.loc)) + if(prob(67)) + to_chat(M, "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.") + to_chat(M, "Miraculously, it fails to kill you.") + else + to_chat(M, "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.") + to_chat(M, "You don't even have a moment to react as you are reduced to ashes by the intense radiation.") + M.dust() + radiation_repository.radiate(src, rand(energy)) + return + +/obj/singularity/proc/pulse() + for(var/obj/machinery/power/rad_collector/R in rad_collectors) + if (get_dist(R, src) <= 15) //Better than using orange() every process. + R.receive_pulse(energy) + +/obj/singularity/proc/on_capture() + chained = 1 + overlays = 0 + move_self = 0 + switch (current_size) + if(1) + overlays += image('icons/obj/singularity.dmi',"chain_s1") + if(3) + overlays += image('icons/effects/96x96.dmi',"chain_s3") + if(5) + overlays += image('icons/effects/160x160.dmi',"chain_s5") + if(7) + overlays += image('icons/effects/224x224.dmi',"chain_s7") + if(9) + overlays += image('icons/effects/288x288.dmi',"chain_s9") + +/obj/singularity/proc/on_release() + chained = 0 + overlays = 0 + move_self = 1 + +/obj/singularity/singularity_act(S, size) + if(current_size <= size) + var/gain = (energy/2) + var/dist = max((current_size - 2), 1) + explosion(src.loc,(dist),(dist*2),(dist*4)) + spawn(0) + qdel(src) + return gain diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm new file mode 100644 index 00000000..ee3a0c13 --- /dev/null +++ b/code/modules/power/smes.dm @@ -0,0 +1,497 @@ +// the SMES +// stores power + +#define SMESMAXCHARGELEVEL 250000 +#define SMESMAXOUTPUT 250000 + +/obj/machinery/power/smes + name = "power storage unit" + desc = "A high-capacity superconducting magnetic energy storage (SMES) unit." + icon_state = "smes" + density = 1 + anchored = 1 + use_power = 0 + clicksound = "switch" + + var/capacity = 5e6 // maximum charge + var/charge = 1e6 // actual charge + + var/input_attempt = 0 // 1 = attempting to charge, 0 = not attempting to charge + var/inputting = 0 // 1 = actually inputting, 0 = not inputting + var/input_level = 50000 // amount of power the SMES attempts to charge by + var/input_level_max = 200000 // cap on input_level + var/input_available = 0 // amount of charge available from input last tick + + var/output_attempt = 0 // 1 = attempting to output, 0 = not attempting to output + var/outputting = 0 // 1 = actually outputting, 0 = not outputting + var/output_level = 50000 // amount of power the SMES attempts to output + var/output_level_max = 200000 // cap on output_level + var/output_used = 0 // amount of power actually outputted. may be less than output_level if the powernet returns excess power + + //Holders for powerout event. + //var/last_output_attempt = 0 + //var/last_input_attempt = 0 + //var/last_charge = 0 + + //For icon overlay updates + var/last_disp + var/last_chrg + var/last_onln + + var/damage = 0 + var/maxdamage = 500 // Relatively resilient, given how expensive it is, but once destroyed produces small explosion. + + var/input_cut = 0 + var/input_pulsed = 0 + var/output_cut = 0 + var/output_pulsed = 0 + var/failure_timer = 0 // Set by gridcheck event, temporarily disables the SMES. + var/target_load = 0 + var/name_tag = null + var/building_terminal = 0 //Suggestions about how to avoid clickspam building several terminals accepted! + var/list/terminals = list() + var/should_be_mapped = 0 // If this is set to 0 it will send out warning on New() + +/obj/machinery/power/smes/drain_power(var/drain_check, var/surge, var/amount = 0) + + if(drain_check) + return 1 + + var/smes_amt = min((amount * CELLRATE), charge) + charge -= smes_amt + return smes_amt / CELLRATE + + +/obj/machinery/power/smes/New() + ..() + if(!should_be_mapped) + warning("Non-buildable or Non-magical SMES at [src.x]X [src.y]Y [src.z]Z") + +/obj/machinery/power/smes/Initialize() + . = ..() + for(var/d in GLOB.cardinal) + var/turf/T = get_step(src, d) + for(var/obj/machinery/power/terminal/term in T) + if(term && term.dir == turn(d, 180) && !term.master) + terminals |= term + term.master = src + term.connect_to_network() + if(!terminals.len) + stat |= BROKEN + return + update_icon() + +/obj/machinery/power/smes/add_avail(var/amount) + if(..(amount)) + powernet.smes_newavail += amount + return 1 + return 0 + + +/obj/machinery/power/smes/disconnect_terminal(var/obj/machinery/power/terminal/term) + terminals -= term + term.master = null + +/obj/machinery/power/smes/update_icon() + overlays.Cut() + if(stat & BROKEN) return + + overlays += image('icons/obj/power.dmi', "smes-op[outputting]") + + if(inputting == 2) + overlays += image('icons/obj/power.dmi', "smes-oc2") + else if (inputting == 1) + overlays += image('icons/obj/power.dmi', "smes-oc1") + else if (input_attempt) + overlays += image('icons/obj/power.dmi', "smes-oc0") + + var/clevel = chargedisplay() + if(clevel) + overlays += image('icons/obj/power.dmi', "smes-og[clevel]") + + if(outputting == 2) + overlays += image('icons/obj/power.dmi', "smes-op2") + else if (outputting == 1) + overlays += image('icons/obj/power.dmi', "smes-op1") + else + overlays += image('icons/obj/power.dmi', "smes-op0") + +/obj/machinery/power/smes/proc/chargedisplay() + return round(5.5*charge/(capacity ? capacity : 5e6)) + +/obj/machinery/power/smes/proc/input_power(var/percentage) + var/to_input = target_load * (percentage/100) + to_input = between(0, to_input, target_load) + input_available = 0 + if(percentage == 100) + inputting = 2 + else if(percentage) + inputting = 1 + // else inputting = 0, as set in process() + + for(var/obj/machinery/power/terminal/term in terminals) + var/inputted = term.powernet.draw_power(to_input) + add_charge(inputted) + input_available += inputted + +// Mostly in place due to child types that may store power in other way (PSUs) +/obj/machinery/power/smes/proc/add_charge(var/amount) + charge += amount*CELLRATE + +/obj/machinery/power/smes/proc/remove_charge(var/amount) + charge -= amount*CELLRATE + +/obj/machinery/power/smes/Process() + if(stat & BROKEN) return + if(failure_timer) // Disabled by gridcheck. + failure_timer-- + return + + // only update icon if state changed + if(last_disp != chargedisplay() || last_chrg != inputting || last_onln != outputting) + update_icon() + + //store machine state to see if we need to update the icon overlays + last_disp = chargedisplay() + last_chrg = inputting + last_onln = outputting + + input_available = 0 + //inputting + if(input_attempt && (!input_pulsed && !input_cut)) + target_load = min((capacity-charge)/CELLRATE, input_level) // Amount we will request from the powernet. + var/input_available = FALSE + for(var/obj/machinery/power/terminal/term in terminals) + if(!term.powernet) + continue + input_available = TRUE + term.powernet.smes_demand += target_load + term.powernet.inputting.Add(src) + if(!input_available) + target_load = 0 // We won't input any power without powernet connection. + inputting = 0 + + output_used = 0 + //outputting + if(output_attempt && (!output_pulsed && !output_cut) && powernet && charge) + output_used = min( charge/CELLRATE, output_level) //limit output to that stored + remove_charge(output_used) // reduce the storage (may be recovered in /restore() if excessive) + add_avail(output_used) // add output to powernet (smes side) + outputting = 2 + else if(!powernet || !charge) + outputting = 1 + else + outputting = 0 + +// called after all power processes are finished +// restores charge level to smes if there was excess this ptick +/obj/machinery/power/smes/proc/restore(var/percent_load) + if(stat & BROKEN) + return + + if(!outputting) + output_used = 0 + return + + var/total_restore = output_used * (percent_load / 100) // First calculate amount of power used from our output + total_restore = between(0, total_restore, output_used) // Now clamp the value between 0 and actual output, just for clarity. + total_restore = output_used - total_restore // And, at last, subtract used power from outputted power, to get amount of power we will give back to the SMES. + + // now recharge this amount + + var/clev = chargedisplay() + + add_charge(total_restore) // restore unused power + powernet.netexcess -= total_restore // remove the excess from the powernet, so later SMESes don't try to use it + + output_used -= total_restore + + if(clev != chargedisplay() ) //if needed updates the icons overlay + update_icon() + return + +//Will return 1 on failure +/obj/machinery/power/smes/proc/make_terminal(const/mob/user) + if (user.loc == loc) + to_chat(user, "You must not be on the same tile as the [src].") + return 1 + + //Direction the terminal will face to + var/tempDir = get_dir(user, src) + switch(tempDir) + if (NORTHEAST, SOUTHEAST) + tempDir = EAST + if (NORTHWEST, SOUTHWEST) + tempDir = WEST + var/turf/tempLoc = get_step(src, reverse_direction(tempDir)) + if (istype(tempLoc, /turf/space)) + to_chat(user, "You can't build a terminal on space.") + return 1 + else if (istype(tempLoc)) + if(!tempLoc.is_plating()) + to_chat(user, "You must remove the floor plating first.") + return 1 + if(check_terminal_exists(tempLoc, user, tempDir)) + return 1 + to_chat(user, "You start adding cable to the [src].") + if(do_after(user, 50, src)) + if(check_terminal_exists(tempLoc, user, tempDir)) + return 1 + var/obj/machinery/power/terminal/term = new/obj/machinery/power/terminal(tempLoc) + term.set_dir(tempDir) + term.master = src + term.connect_to_network() + terminals |= term + return 0 + return 1 + + +/obj/machinery/power/smes/proc/check_terminal_exists(var/turf/location, var/mob/user, var/direction) + for(var/obj/machinery/power/terminal/term in location) + if(term.dir == direction) + to_chat(user, "There is already a terminal here.") + return 1 + return 0 + +/obj/machinery/power/smes/draw_power(var/amount) + var/drained = 0 + for(var/obj/machinery/power/terminal/term in terminals) + if(!term.powernet) + continue + if((amount - drained) <= 0) + return 0 + drained += term.powernet.draw_power(amount - drained) + return drained + + +/obj/machinery/power/smes/attack_ai(mob/user) + add_hiddenprint(user) + ui_interact(user) + +/obj/machinery/power/smes/attack_hand(mob/user) + add_fingerprint(user) + ui_interact(user) + + +/obj/machinery/power/smes/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + + if(default_deconstruction_screwdriver(user, W)) + return + + if (!panel_open) + to_chat(user, "You need to open access hatch on [src] first!") + return 0 + + if(isCoil(W) && !building_terminal) + building_terminal = 1 + var/obj/item/stack/cable_coil/CC = W + if (CC.get_amount() < 10) + to_chat(user, "You need more cables.") + building_terminal = 0 + return 0 + if (make_terminal(user)) + building_terminal = 0 + return 0 + building_terminal = 0 + CC.use(10) + user.visible_message(\ + "[user.name] has added cables to the [src].",\ + "You added cables to the [src].") + stat = 0 + return 0 + + if(isWelder(W)) + var/obj/item/weapon/weldingtool/WT = W + if(!WT.isOn()) + to_chat(user, "Turn on \the [WT] first!") + return 0 + if(!damage) + to_chat(user, "\The [src] is already fully repaired.") + return 0 + if(WT.remove_fuel(0,user) && do_after(user, damage, src)) + to_chat(user, "You repair all structural damage to \the [src]") + damage = 0 + return 0 + else if(isWirecutter(W) && !building_terminal) + building_terminal = 1 + var/obj/machinery/power/terminal/term + for(var/obj/machinery/power/terminal/T in get_turf(user)) + if(T.master == src) + term = T + break + if(!term) + to_chat(user, "There is no terminal on this tile.") + building_terminal = 0 + return 0 + var/turf/tempTDir = get_turf(term) + if (istype(tempTDir)) + if(!tempTDir.is_plating()) + to_chat(user, "You must remove the floor plating first.") + else + to_chat(user, "You begin to cut the cables...") + playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1) + if(do_after(user, 50, src)) + if (prob(50) && electrocute_mob(usr, term.powernet, term)) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, src) + s.start() + if(usr.stunned) + return 0 + new /obj/item/stack/cable_coil(loc,10) + user.visible_message(\ + "[user.name] cut the cables and dismantled the power terminal.",\ + "You cut the cables and dismantle the power terminal.") + terminals -= term + qdel(term) + building_terminal = 0 + return 0 + return 1 + +/obj/machinery/power/smes/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + + if(stat & BROKEN) + return + + // this is the data which will be sent to the ui + var/data[0] + data["nameTag"] = name_tag + data["storedCapacity"] = round(100.0*charge/capacity, 0.1) + data["storedCapacityAbs"] = round(charge/1000, 0.1) + data["storedCapacityMax"] = round(capacity/1000, 0.1) + data["charging"] = inputting + data["chargeMode"] = input_attempt + data["chargeLevel"] = round(input_level/1000, 0.1) + data["chargeMax"] = round(input_level_max/1000) + data["chargeLoad"] = round(input_available/1000, 0.1) + data["outputOnline"] = output_attempt + data["outputLevel"] = round(output_level/1000, 0.1) + data["outputMax"] = round(output_level_max/1000) + data["outputLoad"] = round(output_used/1000, 0.1) + data["failTime"] = failure_timer * 2 + data["outputting"] = outputting + + + // update the ui if it exists, returns null if no ui is passed/found + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "smes.tmpl", "SMES Unit", 540, 380) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(1) + +/obj/machinery/power/smes/proc/Percentage() + if(!capacity) + return 0 + return round(100.0*charge/capacity, 0.1) + +/obj/machinery/power/smes/Topic(href, href_list) + if(..()) + return 1 + + if( href_list["cmode"] ) + inputting(!input_attempt) + update_icon() + return 1 + else if( href_list["online"] ) + outputting(!output_attempt) + update_icon() + return 1 + else if( href_list["reboot"] ) + failure_timer = 0 + update_icon() + return 1 + else if( href_list["input"] ) + switch( href_list["input"] ) + if("min") + input_level = 0 + if("max") + input_level = input_level_max + if("set") + input_level = (input(usr, "Enter new input level (0-[input_level_max/1000] kW)", "SMES Input Power Control", input_level/1000) as num) * 1000 + input_level = max(0, min(input_level_max, input_level)) // clamp to range + return 1 + else if( href_list["output"] ) + switch( href_list["output"] ) + if("min") + output_level = 0 + if("max") + output_level = output_level_max + if("set") + output_level = (input(usr, "Enter new output level (0-[output_level_max/1000] kW)", "SMES Output Power Control", output_level/1000) as num) * 1000 + output_level = max(0, min(output_level_max, output_level)) // clamp to range + return 1 + + +/obj/machinery/power/smes/proc/energy_fail(var/duration) + failure_timer = max(failure_timer, duration) + +/obj/machinery/power/smes/proc/inputting(var/do_input) + input_attempt = do_input + if(!input_attempt) + inputting = 0 + +/obj/machinery/power/smes/proc/outputting(var/do_output) + output_attempt = do_output + if(!output_attempt) + outputting = 0 + +/obj/machinery/power/smes/proc/take_damage(var/amount) + amount = max(0, round(amount)) + damage += amount + if(damage > maxdamage) + visible_message("\The [src] explodes in large rain of sparks and smoke!") + // Depending on stored charge percentage cause damage. + switch(Percentage()) + if(75 to INFINITY) + explosion(get_turf(src), 1, 2, 4) + if(40 to 74) + explosion(get_turf(src), 0, 2, 3) + if(5 to 39) + explosion(get_turf(src), 0, 1, 2) + qdel(src) // Either way we want to ensure the SMES is deleted. + +/obj/machinery/power/smes/emp_act(severity) + if(prob(50)) + inputting(rand(0,1)) + outputting(rand(0,1)) + if(prob(50)) + output_level = rand(0, output_level_max) + input_level = rand(0, input_level_max) + if(prob(50)) + charge -= 1e6/severity + if (charge < 0) + charge = 0 + if(prob(50)) + energy_fail(rand(0 + (severity * 30),30 + (severity * 30))) + update_icon() + ..() + +/obj/machinery/power/smes/bullet_act(var/obj/item/projectile/Proj) + if(Proj.damage_type == BRUTE || Proj.damage_type == BURN) + take_damage(Proj.damage) + +/obj/machinery/power/smes/ex_act(var/severity) + // Two strong explosions will destroy a SMES. + // Given the SMES creates another explosion on it's destruction it sounds fairly reasonable. + take_damage(250 / severity) + +/obj/machinery/power/smes/examine(var/mob/user) + . = ..() + to_chat(user, "The service hatch is [panel_open ? "open" : "closed"].") + if(!damage) + return + var/damage_percentage = round((damage / maxdamage) * 100) + switch(damage_percentage) + if(75 to INFINITY) + to_chat(user, "It's casing is severely damaged, and sparking circuitry may be seen through the holes!") + if(50 to 74) + to_chat(user, "It's casing is considerably damaged, and some of the internal circuits appear to be exposed!") + if(25 to 49) + to_chat(user, "It's casing is quite seriously damaged.") + if(0 to 24) + to_chat(user, "It's casing has some minor damage.") diff --git a/code/modules/power/smes_construction.dm b/code/modules/power/smes_construction.dm new file mode 100644 index 00000000..05868cd8 --- /dev/null +++ b/code/modules/power/smes_construction.dm @@ -0,0 +1,433 @@ +// BUILDABLE SMES(Superconducting Magnetic Energy Storage) UNIT +// +// Last Change 1.1.2015 by Atlantis - Happy New Year! +// +// This is subtype of SMES that should be normally used. It can be constructed, deconstructed and hacked. +// It also supports RCON System which allows you to operate it remotely, if properly set. + +//MAGNETIC COILS - These things actually store and transmit power within the SMES. Different types have different +/obj/item/weapon/smes_coil + name = "superconductive magnetic coil" + desc = "Standard superconductive magnetic coil with average capacity and I/O rating." + icon = 'icons/obj/stock_parts.dmi' + icon_state = "smes_coil" // Just few icons patched together. If someone wants to make better icon, feel free to do so! + w_class = ITEM_SIZE_LARGE // It's LARGE (backpack size) + origin_tech = list(TECH_MATERIAL = 7, TECH_POWER = 7, TECH_ENGINEERING = 5) + var/ChargeCapacity = 50 KILOWATTS + var/IOCapacity = 250 KILOWATTS + +// 20% Charge Capacity, 60% I/O Capacity. Used for substation/outpost SMESs. +/obj/item/weapon/smes_coil/weak + name = "basic superconductive magnetic coil" + desc = "Cheaper model of standard superconductive magnetic coil. It's capacity and I/O rating are considerably lower." + ChargeCapacity = 10 KILOWATTS + IOCapacity = 150 KILOWATTS + +// 500% Charge Capacity, 40% I/O Capacity. Holds a lot of energy, but charges slowly if not combined with other coils. Ideal for backup storage. +/obj/item/weapon/smes_coil/super_capacity + name = "superconductive capacitance coil" + desc = "Specialised version of standard superconductive magnetic coil. This one has significantly stronger containment field, allowing for significantly larger power storage. It's IO rating is much lower, however." + ChargeCapacity = 250 KILOWATTS + IOCapacity = 100 KILOWATTS + +// 40% Charge Capacity, 500% I/O Capacity. Technically turns SMES into large super capacitor. Ideal for shields. +/obj/item/weapon/smes_coil/super_io + name = "superconductive transmission coil" + desc = "Specialised version of standard superconductive magnetic coil. While this one won't store almost any power, it rapidly transfers power, making it useful in systems which require large throughput." + ChargeCapacity = 20 KILOWATTS + IOCapacity = 1.25 MEGAWATTS + + +// DEPRECATED +// These are used on individual outposts as backup should power line be cut, or engineering outpost lost power. +// 1M Charge, 150K I/O +/obj/machinery/power/smes/buildable/outpost_substation/New() + ..(0) + component_parts += new /obj/item/weapon/smes_coil/weak(src) + recalc_coils() + +// This one is pre-installed on engineering shuttle. Allows rapid charging/discharging for easier transport of power to outpost +// 11M Charge, 2.5M I/O +/obj/machinery/power/smes/buildable/power_shuttle/New() + ..(0) + component_parts += new /obj/item/weapon/smes_coil/super_io(src) + component_parts += new /obj/item/weapon/smes_coil/super_io(src) + component_parts += new /obj/item/weapon/smes_coil(src) + recalc_coils() + + + + + + +// END SMES SUBTYPES + +// SMES itself +/obj/machinery/power/smes/buildable + var/max_coils = 6 // 250 kWh capacity, 1.5MW input/output when fully upgraded /w default coils + var/cur_coils = 1 // Current amount of installed coils + var/safeties_enabled = 1 // If 0 modifications can be done without discharging the SMES, at risk of critical failure. + var/failing = 0 // If 1 critical failure has occured and SMES explosion is imminent. + var/datum/wires/smes/wires + var/grounding = 1 // Cut to quickly discharge, at cost of "minor" electrical issues in output powernet. + var/RCon = 1 // Cut to disable AI and remote control. + var/RCon_tag = "NO_TAG" // RCON tag, change to show it on SMES Remote control console. + var/emp_proof = 0 // Whether the SMES is EMP proof + + charge = 0 + should_be_mapped = 1 + +/obj/machinery/power/smes/buildable/malf_upgrade(var/mob/living/silicon/ai/user) + ..() + malf_upgraded = 1 + emp_proof = 1 + recalc_coils() + to_chat(user, "\The [src] has been upgraded. It's transfer rate and capacity has increased, and it is now resistant against EM pulses.") + return 1 + + +/obj/machinery/power/smes/buildable/max_cap_in_out/Initialize() + . = ..() + charge = capacity + input_attempt = TRUE + output_attempt = TRUE + input_level = input_level_max + output_level = output_level_max + +/obj/machinery/power/smes/buildable/Destroy() + qdel(wires) + wires = null + for(var/obj/machinery/power/terminal/T in terminals) + T.master = null + terminals = null + for(var/datum/nano_module/rcon/R in world) + R.FindDevices() + return ..() + +// Proc: process() +// Parameters: None +// Description: Uses parent process, but if grounding wire is cut causes sparks to fly around. +// This also causes the SMES to quickly discharge, and has small chance of damaging output APCs. +/obj/machinery/power/smes/buildable/Process() + if(!grounding && (Percentage() > 5)) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, src) + s.start() + charge -= (output_level_max * CELLRATE) + if(prob(1)) // Small chance of overload occuring since grounding is disabled. + apcs_overload(5,10,20) + + ..() + +// Proc: attack_ai() +// Parameters: None +// Description: AI requires the RCON wire to be intact to operate the SMES. +/obj/machinery/power/smes/buildable/attack_ai() + if(RCon) + ..() + else // RCON wire cut + to_chat(usr, "Connection error: Destination Unreachable.") + + // Cyborgs standing next to the SMES can play with the wiring. + if(istype(usr, /mob/living/silicon/robot) && Adjacent(usr) && panel_open) + wires.Interact(usr) + +// Proc: New() +// Parameters: None +// Description: Adds standard components for this SMES, and forces recalculation of properties. +/obj/machinery/power/smes/buildable/New() + component_parts = list() + component_parts += new /obj/item/stack/cable_coil(src,30) + component_parts += new /obj/item/weapon/circuitboard/smes(src) + src.wires = new /datum/wires/smes(src) + + // Allows for mapped-in SMESs with larger capacity/IO + if(cur_coils) + for(var/i = 1, i <= cur_coils, i++) + component_parts += new /obj/item/weapon/smes_coil(src) + recalc_coils() + ..() + +// Proc: attack_hand() +// Parameters: None +// Description: Opens the UI as usual, and if cover is removed opens the wiring panel. +/obj/machinery/power/smes/buildable/attack_hand() + ..() + if(panel_open) + wires.Interact(usr) + +// Proc: recalc_coils() +// Parameters: None +// Description: Updates properties (IO, capacity, etc.) of this SMES by checking internal components. +/obj/machinery/power/smes/buildable/proc/recalc_coils() + cur_coils = 0 + capacity = 0 + input_level_max = 0 + output_level_max = 0 + for(var/obj/item/weapon/smes_coil/C in component_parts) + cur_coils++ + capacity += C.ChargeCapacity + input_level_max += C.IOCapacity + output_level_max += C.IOCapacity + if(malf_upgraded) + capacity *= 1.2 + input_level_max *= 2 + output_level_max *= 2 + charge = between(0, charge, capacity) + +// Proc: total_system_failure() +// Parameters: 2 (intensity - how strong the failure is, user - person which caused the failure) +// Description: Checks the sensors for alerts. If change (alerts cleared or detected) occurs, calls for icon update. +/obj/machinery/power/smes/buildable/proc/total_system_failure(var/intensity = 0, var/mob/user as mob) + // SMESs store very large amount of power. If someone screws up (ie: Disables safeties and attempts to modify the SMES) very bad things happen. + // Bad things are based on charge percentage. + // Possible effects: + // Sparks - Lets out few sparks, mostly fire hazard if phoron present. Otherwise purely aesthetic. + // Shock - Depending on intensity harms the user. Insultated Gloves protect against weaker shocks, but strong shock bypasses them. + // EMP Pulse - Lets out EMP pulse discharge which screws up nearby electronics. + // Light Overload - X% chance to overload each lighting circuit in connected powernet. APC based. + // APC Failure - X% chance to destroy APC causing very weak explosion too. Won't cause hull breach or serious harm. + // SMES Explosion - X% chance to destroy the SMES, in moderate explosion. May cause small hull breach. + + if (!intensity) + return + + var/mob/living/carbon/human/h_user = null + if (!istype(user, /mob/living/carbon/human)) + return + else + h_user = user + + + // Preparations + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + // Check if user has protected gloves. + var/user_protected = 0 + if(h_user.gloves) + var/obj/item/clothing/gloves/G = h_user.gloves + if(G.siemens_coefficient == 0) + user_protected = 1 + log_game("SMES FAILURE: [src.x]X [src.y]Y [src.z]Z User: [usr.ckey], Intensity: [intensity]/100") + message_admins("SMES FAILURE: [src.x]X [src.y]Y [src.z]Z User: [usr.ckey], Intensity: [intensity]/100 - JMP") + + + switch (intensity) + if (0 to 15) + // Small overcharge + // Sparks, Weak shock + s.set_up(2, 1, src) + s.start() + if (user_protected && prob(80)) + to_chat(h_user, "Small electrical arc almost burns your hand. Luckily you had your gloves on!") + else + to_chat(h_user, "Small electrical arc sparks and burns your hand as you touch the [src]!") + h_user.adjustFireLoss(rand(5,10)) + h_user.Paralyse(2) + charge = 0 + + if (16 to 35) + // Medium overcharge + // Sparks, Medium shock, Weak EMP + s.set_up(4,1,src) + s.start() + if (user_protected && prob(25)) + to_chat(h_user, "Medium electrical arc sparks and almost burns your hand. Luckily you had your gloves on!") + else + to_chat(h_user, "Medium electrical sparks as you touch the [src], severely burning your hand!") + h_user.adjustFireLoss(rand(10,25)) + h_user.Paralyse(5) + spawn(0) + empulse(src.loc, 2, 4) + apcs_overload(0, 5, 10) + charge = 0 + + if (36 to 60) + // Strong overcharge + // Sparks, Strong shock, Strong EMP, 10% light overload. 1% APC failure + s.set_up(7,1,src) + s.start() + if (user_protected) + to_chat(h_user, "Strong electrical arc sparks between you and [src], ignoring your gloves and burning your hand!") + h_user.adjustFireLoss(rand(25,60)) + h_user.Paralyse(8) + else + to_chat(h_user, "Strong electrical arc sparks between you and [src], knocking you out for a while!") + h_user.adjustFireLoss(rand(35,75)) + h_user.Paralyse(12) + spawn(0) + empulse(src.loc, 8, 16) + charge = 0 + apcs_overload(1, 10, 20) + energy_fail(10) + src.ping("Caution. Output regulators malfunction. Uncontrolled discharge detected.") + + if (61 to INFINITY) + // Massive overcharge + // Sparks, Near - instantkill shock, Strong EMP, 25% light overload, 5% APC failure. 50% of SMES explosion. This is bad. + s.set_up(10,1,src) + s.start() + to_chat(h_user, "Massive electrical arc sparks between you and [src]. Last thing you can think about is \"Oh shit...\"") + // Remember, we have few gigajoules of electricity here.. Turn them into crispy toast. + h_user.adjustFireLoss(rand(150,195)) + h_user.Paralyse(25) + spawn(0) + empulse(src.loc, 32, 64) + charge = 0 + apcs_overload(5, 25, 100) + energy_fail(30) + src.ping("Caution. Output regulators malfunction. Significant uncontrolled discharge detected.") + + if (prob(50)) + // Added admin-notifications so they can stop it when griffed. + log_game("SMES explosion imminent.") + message_admins("SMES explosion imminent.") + src.ping("DANGER! Magnetic containment field unstable! Containment field failure imminent!") + failing = 1 + // 30 - 60 seconds and then BAM! + spawn(rand(300,600)) + if(!failing) // Admin can manually set this var back to 0 to stop overload, for use when griffed. + update_icon() + src.ping("Magnetic containment stabilised.") + return + src.ping("DANGER! Magnetic containment field failure in 3 ... 2 ... 1 ...") + explosion(src.loc,1,2,4,8) + // Not sure if this is necessary, but just in case the SMES *somehow* survived.. + qdel(src) + + + +// Proc: apcs_overload() +// Parameters: 3 (failure_chance - chance to actually break the APC, overload_chance - Chance of breaking lights, reboot_chance - Chance of temporarily disabling the APC) +// Description: Damages output powernet by power surge. Destroys few APCs and lights, depending on parameters. +/obj/machinery/power/smes/buildable/proc/apcs_overload(var/failure_chance, var/overload_chance, var/reboot_chance) + if (!src.powernet) + return + + for(var/obj/machinery/power/terminal/T in src.powernet.nodes) + if(istype(T.master, /obj/machinery/power/apc)) + var/obj/machinery/power/apc/A = T.master + if (prob(overload_chance)) + A.overload_lighting() + if (prob(failure_chance)) + A.set_broken() + if(prob(reboot_chance)) + A.energy_fail(rand(30,60)) + +// Proc: update_icon() +// Parameters: None +// Description: Allows us to use special icon overlay for critical SMESs +/obj/machinery/power/smes/buildable/update_icon() + if (failing) + overlays.Cut() + overlays += image('icons/obj/power.dmi', "smes-crit") + else + ..() + +// Proc: attackby() +// Parameters: 2 (W - object that was used on this machine, user - person which used the object) +// Description: Handles tool interaction. Allows deconstruction/upgrading/fixing. +/obj/machinery/power/smes/buildable/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + // No more disassembling of overloaded SMESs. You broke it, now enjoy the consequences. + if (failing) + to_chat(user, "The [src]'s screen is flashing with alerts. It seems to be overloaded! Touching it now is probably not a good idea.") + return + // If parent returned 1: + // - Hatch is open, so we can modify the SMES + // - No action was taken in parent function (terminal de/construction atm). + if (..()) + + // Multitool - change RCON tag + if(isMultitool(W)) + var/newtag = input(user, "Enter new RCON tag. Use \"NO_TAG\" to disable RCON or leave empty to cancel.", "SMES RCON system") as text + if(newtag) + RCon_tag = newtag + to_chat(user, "You changed the RCON tag to: [newtag]") + return + // Charged above 1% and safeties are enabled. + if((charge > (capacity/100)) && safeties_enabled) + to_chat(user, "Safety circuit of [src] is preventing modifications while it's charged!") + return + + if (output_attempt || input_attempt) + to_chat(user, "Turn off the [src] first!") + return + + // Probability of failure if safety circuit is disabled (in %) + var/failure_probability = round((charge / capacity) * 100) + + // If failure probability is below 5% it's usually safe to do modifications + if (failure_probability < 5) + failure_probability = 0 + + // Crowbar - Disassemble the SMES. + if(isCrowbar(W)) + if (terminals.len) + to_chat(user, "You have to disassemble the terminal first!") + return + + playsound(get_turf(src), 'sound/items/Crowbar.ogg', 50, 1) + to_chat(user, "You begin to disassemble the [src]!") + if (do_after(usr, 50 * cur_coils, src)) // More coils = takes longer to disassemble. It's complex so largest one with 6 coils will take 30s + + if (failure_probability && prob(failure_probability)) + total_system_failure(failure_probability, user) + return + + to_chat(usr, "You have disassembled the SMES cell!") + var/obj/machinery/constructable_frame/machine_frame/M = new /obj/machinery/constructable_frame/machine_frame(src.loc) + M.state = 2 + M.icon_state = "box_1" + for(var/obj/I in component_parts) + I.forceMove(src.loc) + component_parts -= I + qdel(src) + return + + // Superconducting Magnetic Coil - Upgrade the SMES + else if(istype(W, /obj/item/weapon/smes_coil)) + if (cur_coils < max_coils) + + if (failure_probability && prob(failure_probability)) + total_system_failure(failure_probability, user) + return + + to_chat(usr, "You install the coil into the SMES unit!") + user.drop_item() + component_parts += W + W.forceMove(src) + recalc_coils() + else + to_chat(usr, "You can't insert more coils to this SMES unit!") + +// Proc: toggle_input() +// Parameters: None +// Description: Switches the input on/off depending on previous setting +/obj/machinery/power/smes/buildable/proc/toggle_input() + inputting(!input_attempt) + update_icon() + +// Proc: toggle_output() +// Parameters: None +// Description: Switches the output on/off depending on previous setting +/obj/machinery/power/smes/buildable/proc/toggle_output() + outputting(!output_attempt) + update_icon() + +// Proc: set_input() +// Parameters: 1 (new_input - New input value in Watts) +// Description: Sets input setting on this SMES. Trims it if limits are exceeded. +/obj/machinery/power/smes/buildable/proc/set_input(var/new_input = 0) + input_level = between(0, new_input, input_level_max) + update_icon() + +// Proc: set_output() +// Parameters: 1 (new_output - New output value in Watts) +// Description: Sets output setting on this SMES. Trims it if limits are exceeded. +/obj/machinery/power/smes/buildable/proc/set_output(var/new_output = 0) + output_level = between(0, new_output, output_level_max) + update_icon() + +/obj/machinery/power/smes/buildable/emp_act(var/severity) + if(emp_proof) + return + ..(severity) \ No newline at end of file diff --git a/code/modules/power/smes_presets.dm b/code/modules/power/smes_presets.dm new file mode 100644 index 00000000..803ce669 --- /dev/null +++ b/code/modules/power/smes_presets.dm @@ -0,0 +1,38 @@ +/obj/machinery/power/smes/buildable/preset + var/_fully_charged = FALSE + var/_input_maxed = FALSE + var/_input_on = FALSE + var/_output_maxed = FALSE + var/_output_on = FALSE + cur_coils = 0 + +/obj/machinery/power/smes/buildable/preset/New() + ..() + configure_and_install_coils() + recalc_coils() + if(_input_maxed) + input_level = input_level_max + if(_output_maxed) + output_level = output_level_max + input_attempt = _input_on + output_attempt = _output_on + if(_fully_charged) + charge = capacity + +// Override and implement to customize the SMES's loadout +/obj/machinery/power/smes/buildable/preset/proc/configure_and_install_coils() + CRASH("configure_and_install_coils() not implemented for type [type]!") + return + +/obj/machinery/power/smes/buildable/preset/haven + cur_coils = 1 + _fully_charged = TRUE + _input_on = TRUE + _output_on = TRUE + +obj/machinery/power/smes/buildable/preset/warfare + cur_coils = 1 + _fully_charged = TRUE + _input_on = TRUE + _output_on = TRUE + use_power = FALSE diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm new file mode 100644 index 00000000..084e29da --- /dev/null +++ b/code/modules/power/solar.dm @@ -0,0 +1,549 @@ +#define SOLAR_MAX_DIST 40 + +var/solar_gen_rate = 1500 +var/list/solars_list = list() + +/obj/machinery/power/solar + name = "solar panel" + desc = "A solar electrical generator." + icon = 'icons/obj/power.dmi' + icon_state = "sp_base" + anchored = 1 + density = 1 + use_power = 0 + idle_power_usage = 0 + active_power_usage = 0 + var/id = 0 + var/health = 10 + var/obscured = 0 + var/sunfrac = 0 + var/adir = SOUTH // actual dir + var/ndir = SOUTH // target dir + var/turn_angle = 0 + var/obj/machinery/power/solar_control/control = null + +/obj/machinery/power/solar/drain_power() + return -1 + +/obj/machinery/power/solar/New(var/turf/loc, var/obj/item/solar_assembly/S) + ..(loc) + Make(S) + connect_to_network() + +/obj/machinery/power/solar/Destroy() + unset_control() //remove from control computer + ..() + +//set the control of the panel to a given computer if closer than SOLAR_MAX_DIST +/obj/machinery/power/solar/proc/set_control(var/obj/machinery/power/solar_control/SC) + if(SC && (get_dist(src, SC) > SOLAR_MAX_DIST)) + return 0 + control = SC + return 1 + +//set the control of the panel to null and removes it from the control list of the previous control computer if needed +/obj/machinery/power/solar/proc/unset_control() + if(control) + control.connected_panels.Remove(src) + control = null + +/obj/machinery/power/solar/proc/Make(var/obj/item/solar_assembly/S) + if(!S) + S = new /obj/item/solar_assembly(src) + S.glass_type = /obj/item/stack/material/glass + S.anchored = 1 + S.loc = src + if(S.glass_type == /obj/item/stack/material/glass/reinforced) //if the panel is in reinforced glass + health *= 2 //this need to be placed here, because panels already on the map don't have an assembly linked to + update_icon() + + + +/obj/machinery/power/solar/attackby(obj/item/weapon/W, mob/user) + + if(isCrowbar(W)) + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + user.visible_message("[user] begins to take the glass off the solar panel.") + if(do_after(user, 50,src)) + var/obj/item/solar_assembly/S = locate() in src + if(S) + S.loc = src.loc + S.give_glass() + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + user.visible_message("[user] takes the glass off the solar panel.") + qdel(src) + return + else if (W) + src.add_fingerprint(user) + src.health -= W.force + src.healthcheck() + ..() + + +/obj/machinery/power/solar/proc/healthcheck() + if (src.health <= 0) + if(!(stat & BROKEN)) + broken() + + + +/obj/machinery/power/solar/update_icon() + ..() + overlays.Cut() + if(stat & BROKEN) + overlays += image('icons/obj/power.dmi', icon_state = "solar_panel-b", layer = FLY_LAYER) + else + overlays += image('icons/obj/power.dmi', icon_state = "solar_panel", layer = FLY_LAYER) + src.set_dir(angle2dir(adir)) + return + +//calculates the fraction of the sunlight that the panel recieves +/obj/machinery/power/solar/proc/update_solar_exposure() + if(!GLOB.sun) + return + if(obscured) + sunfrac = 0 + return + + //find the smaller angle between the direction the panel is facing and the direction of the sun (the sign is not important here) + var/p_angle = min(abs(adir - GLOB.sun.angle), 360 - abs(adir - GLOB.sun.angle)) + + if(p_angle > 90) // if facing more than 90deg from sun, zero output + sunfrac = 0 + return + + sunfrac = cos(p_angle) ** 2 + //isn't the power recieved from the incoming light proportionnal to cos(p_angle) (Lambert's cosine law) rather than cos(p_angle)^2 ? + +/obj/machinery/power/solar/Process()//TODO: remove/add this from machines to save on processing as needed ~Carn PRIORITY + if(stat & BROKEN) + return + if(!GLOB.sun || !control) //if there's no sun or the panel is not linked to a solar control computer, no need to proceed + return + + if(powernet) + if(powernet == control.powernet)//check if the panel is still connected to the computer + if(obscured) //get no light from the sun, so don't generate power + return + var/sgen = solar_gen_rate * sunfrac + add_avail(sgen) + control.gen += sgen + else //if we're no longer on the same powernet, remove from control computer + unset_control() + +/obj/machinery/power/solar/proc/broken() + stat |= BROKEN + health = 0 + new /obj/item/weapon/material/shard(src.loc) + new /obj/item/weapon/material/shard(src.loc) + var/obj/item/solar_assembly/S = locate() in src + S.glass_type = null + unset_control() + update_icon() + + +/obj/machinery/power/solar/ex_act(severity) + switch(severity) + if(1.0) + if(prob(15)) + new /obj/item/weapon/material/shard( src.loc ) + qdel(src) + return + + if(2.0) + if (prob(25)) + new /obj/item/weapon/material/shard( src.loc ) + qdel(src) + return + + if (prob(50)) + broken() + + if(3.0) + if (prob(25)) + broken() + return + + +/obj/machinery/power/solar/fake/New(var/turf/loc, var/obj/item/solar_assembly/S) + ..(loc, S, 0) + +/obj/machinery/power/solar/fake/Process() + . = PROCESS_KILL + return + +//trace towards sun to see if we're in shadow +/obj/machinery/power/solar/proc/occlusion() + + var/ax = x // start at the solar panel + var/ay = y + var/turf/T = null + + for(var/i = 1 to 20) // 20 steps is enough + ax += GLOB.sun.dx // do step + ay += GLOB.sun.dy + + T = locate( round(ax,0.5),round(ay,0.5),z) + + if(!T || T.x == 1 || T.x==world.maxx || T.y==1 || T.y==world.maxy) // not obscured if we reach the edge + break + + if(T.opacity) // if we hit a solid turf, panel is obscured + obscured = 1 + return + + obscured = 0 // if hit the edge or stepped 20 times, not obscured + update_solar_exposure() + + +// +// Solar Assembly - For construction of solar arrays. +// + +/obj/item/solar_assembly + name = "solar panel assembly" + desc = "A solar panel assembly kit, allows constructions of a solar panel, or with a tracking circuit board, a solar tracker." + icon = 'icons/obj/power.dmi' + icon_state = "sp_base" + item_state = "electropack" + w_class = ITEM_SIZE_HUGE // Pretty big! + anchored = 0 + var/tracker = 0 + var/glass_type = null + +/obj/item/solar_assembly/attack_hand(var/mob/user) + if(!anchored && isturf(loc)) // You can't pick it up + ..() + +// Give back the glass type we were supplied with +/obj/item/solar_assembly/proc/give_glass() + if(glass_type) + var/obj/item/stack/material/S = new glass_type(src.loc) + S.amount = 2 + glass_type = null + + +/obj/item/solar_assembly/attackby(var/obj/item/weapon/W, var/mob/user) + + if(!anchored && isturf(loc)) + if(isWrench(W)) + anchored = 1 + pixel_x = 0 + pixel_y = 0 + pixel_z = 0 + user.visible_message("[user] wrenches the solar assembly into place.") + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + return 1 + else + if(isWrench(W)) + anchored = 0 + user.visible_message("[user] unwrenches the solar assembly from it's place.") + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + return 1 + + if(istype(W, /obj/item/stack/material) && (W.get_material_name() == "glass" || W.get_material_name() == "rglass")) + var/obj/item/stack/material/S = W + if(S.use(2)) + glass_type = W.type + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + user.visible_message("[user] places the glass on the solar assembly.") + if(tracker) + new /obj/machinery/power/tracker(get_turf(src), src) + else + new /obj/machinery/power/solar(get_turf(src), src) + else + to_chat(user, "You need two sheets of glass to put them into a solar panel.") + return + return 1 + + if(!tracker) + if(istype(W, /obj/item/weapon/tracker_electronics)) + tracker = 1 + user.drop_item() + qdel(W) + user.visible_message("[user] inserts the electronics into the solar assembly.") + return 1 + else + if(isCrowbar(W)) + new /obj/item/weapon/tracker_electronics(src.loc) + tracker = 0 + user.visible_message("[user] takes out the electronics from the solar assembly.") + return 1 + ..() + +// +// Solar Control Computer +// + +/obj/machinery/power/solar_control + name = "solar panel control" + desc = "A controller for solar panel arrays." + icon = 'icons/obj/computer.dmi' + icon_state = "solar" + anchored = 1 + density = 1 + use_power = FALSE + idle_power_usage = 250 + var/id = 0 + var/cdir = 0 + var/targetdir = 0 // target angle in manual tracking (since it updates every game minute) + var/gen = 0 + var/lastgen = 0 + var/track = 0 // 0= off 1=timed 2=auto (tracker) + var/trackrate = 600 // 300-900 seconds + var/nexttime = 0 // time for a panel to rotate of 1° in manual tracking + var/obj/machinery/power/tracker/connected_tracker = null + var/list/connected_panels = list() + +/obj/machinery/power/solar_control/drain_power() + return -1 + +/obj/machinery/power/solar_control/Destroy() + for(var/obj/machinery/power/solar/M in connected_panels) + M.unset_control() + if(connected_tracker) + connected_tracker.unset_control() + ..() + +/obj/machinery/power/solar_control/disconnect_from_network() + ..() + solars_list.Remove(src) + +/obj/machinery/power/solar_control/connect_to_network() + var/to_return = ..() + if(powernet) //if connected and not already in solar_list... + solars_list |= src //... add it + return to_return + +//search for unconnected panels and trackers in the computer powernet and connect them +/obj/machinery/power/solar_control/proc/search_for_connected() + if(powernet) + for(var/obj/machinery/power/M in powernet.nodes) + if(istype(M, /obj/machinery/power/solar)) + var/obj/machinery/power/solar/S = M + if(!S.control) //i.e unconnected + S.set_control(src) + connected_panels |= S + else if(istype(M, /obj/machinery/power/tracker)) + if(!connected_tracker) //if there's already a tracker connected to the computer don't add another + var/obj/machinery/power/tracker/T = M + if(!T.control) //i.e unconnected + connected_tracker = T + T.set_control(src) + +//called by the sun controller, update the facing angle (either manually or via tracking) and rotates the panels accordingly +/obj/machinery/power/solar_control/proc/update() + if(stat & (NOPOWER | BROKEN)) + return + + switch(track) + if(1) + if(trackrate) //we're manual tracking. If we set a rotation speed... + cdir = targetdir //...the current direction is the targetted one (and rotates panels to it) + if(2) // auto-tracking + if(connected_tracker) + connected_tracker.set_angle(GLOB.sun.angle) + + set_panels(cdir) + updateDialog() + + +/obj/machinery/power/solar_control/Initialize() + . = ..() + if(!connect_to_network()) return + set_panels(cdir) + +/obj/machinery/power/solar_control/update_icon() + if(stat & BROKEN) + icon_state = "broken" + overlays.Cut() + return + if(stat & NOPOWER) + icon_state = "c_unpowered" + overlays.Cut() + return + icon_state = "solar" + overlays.Cut() + if(cdir > -1) + overlays += image('icons/obj/computer.dmi', "solcon-o", FLY_LAYER, angle2dir(cdir)) + return + +/obj/machinery/power/solar_control/attack_hand(mob/user) + if(!..()) + interact(user) + +/obj/machinery/power/solar_control/interact(mob/user) + + var/t = "Generated power : [round(lastgen)] W
            " + t += "Star Orientation: [GLOB.sun.angle]° ([angle2text(GLOB.sun.angle)])
            " + t += "Array Orientation: [rate_control(src,"cdir","[cdir]°",1,15)] ([angle2text(cdir)])
            " + t += "Tracking:
            " + switch(track) + if(0) + t += "Off Timed Auto
            " + if(1) + t += "Off Timed Auto
            " + if(2) + t += "Off Timed Auto
            " + + t += "Tracking Rate: [rate_control(src,"tdir","[trackrate] deg/h ([trackrate<0 ? "CCW" : "CW"])",1,30,180)]

            " + + t += "Connected devices:
            " + + t += "Search for devices
            " + t += "Solar panels : [connected_panels.len] connected
            " + t += "Solar tracker : [connected_tracker ? "Found" : "Not found"]

            " + + t += "Close" + + var/datum/browser/popup = new(user, "solar", name) + popup.set_content(t) + popup.open() + + return + +/obj/machinery/power/solar_control/attackby(I as obj, user as mob) + if(isScrewdriver(I)) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + if(do_after(user, 20,src)) + if (src.stat & BROKEN) + to_chat(user, "The broken glass falls out.") + var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) + new /obj/item/weapon/material/shard( src.loc ) + var/obj/item/weapon/circuitboard/solar_control/M = new /obj/item/weapon/circuitboard/solar_control( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + qdel(src) + else + to_chat(user, "You disconnect the monitor.") + var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/solar_control/M = new /obj/item/weapon/circuitboard/solar_control( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + qdel(src) + else + src.attack_hand(user) + return + +/obj/machinery/power/solar_control/Process() + lastgen = gen + gen = 0 + + if(stat & (NOPOWER | BROKEN)) + return + + if(connected_tracker) //NOTE : handled here so that we don't add trackers to the processing list + if(connected_tracker.powernet != powernet) + connected_tracker.unset_control() + + if(track==1 && trackrate) //manual tracking and set a rotation speed + if(nexttime <= world.time) //every time we need to increase/decrease the angle by 1°... + targetdir = (targetdir + trackrate/abs(trackrate) + 360) % 360 //... do it + nexttime += 36000/abs(trackrate) //reset the counter for the next 1° + + updateDialog() + +/obj/machinery/power/solar_control/Topic(href, href_list) + if(..()) + usr << browse(null, "window=solcon") + usr.unset_machine() + return 0 + if(href_list["close"] ) + usr << browse(null, "window=solcon") + usr.unset_machine() + return 0 + + if(href_list["rate control"]) + if(href_list["cdir"]) + src.cdir = dd_range(0,359,(360+src.cdir+text2num(href_list["cdir"]))%360) + src.targetdir = src.cdir + if(track == 2) //manual update, so losing auto-tracking + track = 0 + spawn(1) + set_panels(cdir) + if(href_list["tdir"]) + src.trackrate = dd_range(-7200,7200,src.trackrate+text2num(href_list["tdir"])) + if(src.trackrate) nexttime = world.time + 36000/abs(trackrate) + + if(href_list["track"]) + track = text2num(href_list["track"]) + if(track == 2) + if(connected_tracker) + connected_tracker.set_angle(GLOB.sun.angle) + set_panels(cdir) + else if (track == 1) //begin manual tracking + src.targetdir = src.cdir + if(src.trackrate) nexttime = world.time + 36000/abs(trackrate) + set_panels(targetdir) + + if(href_list["search_connected"]) + src.search_for_connected() + if(connected_tracker && track == 2) + connected_tracker.set_angle(GLOB.sun.angle) + src.set_panels(cdir) + + interact(usr) + return 1 + +//rotates the panel to the passed angle +/obj/machinery/power/solar_control/proc/set_panels(var/cdir) + + for(var/obj/machinery/power/solar/S in connected_panels) + S.adir = cdir //instantly rotates the panel + S.occlusion()//and + S.update_icon() //update it + + update_icon() + + +/obj/machinery/power/solar_control/proc/broken() + stat |= BROKEN + update_icon() + + +/obj/machinery/power/solar_control/ex_act(severity) + switch(severity) + if(1.0) + //SN src = null + qdel(src) + return + if(2.0) + if (prob(50)) + broken() + if(3.0) + if (prob(25)) + broken() + return + +// Used for mapping in solar array which automatically starts itself (telecomms, for example) +/obj/machinery/power/solar_control/autostart + track = 2 // Auto tracking mode + +/obj/machinery/power/solar_control/autostart/Initialize() + search_for_connected() + if(connected_tracker && track == 2) + connected_tracker.set_angle(GLOB.sun.angle) + set_panels(cdir) + . = ..() + +// +// MISC +// + +/obj/item/weapon/paper/solar + name = "paper- 'Going green! Setup your own solar array instructions.'" + info = "

            Welcome

            At greencorps we love the environment, and space. With this package you are able to help mother nature and produce energy without any usage of fossil fuel or phoron! Singularity energy is dangerous while solar energy is safe, which is why it's better. Now here is how you setup your own solar array.

            You can make a solar panel by wrenching the solar assembly onto a cable node. Adding a glass panel, reinforced or regular glass will do, will finish the construction of your solar panel. It is that easy!

            Now after setting up 19 more of these solar panels you will want to create a solar tracker to keep track of our mother nature's gift, the GLOB.sun. These are the same steps as before except you insert the tracker equipment circuit into the assembly before performing the final step of adding the glass. You now have a tracker! Now the last step is to add a computer to calculate the sun's movements and to send commands to the solar panels to change direction with the GLOB.sun. Setting up the solar computer is the same as setting up any computer, so you should have no trouble in doing that. You do need to put a wire node under the computer, and the wire needs to be connected to the tracker.

            Congratulations, you should have a working solar array. If you are having trouble, here are some tips. Make sure all solar equipment are on a cable node, even the computer. You can always deconstruct your creations if you make a mistake.

            That's all to it, be safe, be green!

            " + +/proc/rate_control(var/S, var/V, var/C, var/Min=1, var/Max=5, var/Limit=null) //How not to name vars + var/href = "-[href]=-[Min]'>- [(C?C : 0)] [href]=[Min]'>+[href]=[Max]'>+" + if(Limit) return "[href]=-[Limit]'>-"+rate+"[href]=[Limit]'>+" + return rate diff --git a/code/modules/power/terminal.dm b/code/modules/power/terminal.dm new file mode 100644 index 00000000..f09526a5 --- /dev/null +++ b/code/modules/power/terminal.dm @@ -0,0 +1,39 @@ +// the underfloor wiring terminal for the APC +// autogenerated when an APC is placed +// all conduit connects go to this object instead of the APC +// using this solves the problem of having the APC in a wall yet also inside an area + +/obj/machinery/power/terminal + name = "terminal" + icon_state = "term" + desc = "It's an underfloor wiring terminal for power equipment." + level = 1 + plane = ABOVE_TURF_PLANE + layer = EXPOSED_WIRE_TERMINAL_LAYER + var/obj/machinery/power/master = null + anchored = 1 + + +/obj/machinery/power/terminal/New() + ..() + var/turf/T = src.loc + if(level==1) hide(!T.is_plating()) + return + +/obj/machinery/power/terminal/Destroy() + if(master) + master.disconnect_terminal(src) + master = null + return ..() + +/obj/machinery/power/terminal/hide(var/do_hide) + if(do_hide && level == 1) + plane = ABOVE_PLATING_PLANE + layer = WIRE_TERMINAL_LAYER + else + reset_plane_and_layer() + +// Needed so terminals are not removed from machines list. +// Powernet rebuilds need this to work properly. +/obj/machinery/power/terminal/Process() + return 1 diff --git a/code/modules/power/tracker.dm b/code/modules/power/tracker.dm new file mode 100644 index 00000000..b08372e6 --- /dev/null +++ b/code/modules/power/tracker.dm @@ -0,0 +1,83 @@ +//Solar tracker + +//Machine that tracks the sun and reports it's direction to the solar controllers +//As long as this is working, solar panels on same powernet will track automatically + +/obj/machinery/power/tracker + name = "solar tracker" + desc = "A solar directional tracker." + icon = 'icons/obj/power.dmi' + icon_state = "tracker" + anchored = 1 + density = 1 + use_power = 0 + + var/id = 0 + var/sun_angle = 0 // sun angle as set by sun datum + var/obj/machinery/power/solar_control/control = null + +/obj/machinery/power/tracker/New(var/turf/loc, var/obj/item/solar_assembly/S) + ..(loc) + Make(S) + connect_to_network() + +/obj/machinery/power/tracker/Destroy() + unset_control() //remove from control computer + ..() + +//set the control of the tracker to a given computer if closer than SOLAR_MAX_DIST +/obj/machinery/power/tracker/proc/set_control(var/obj/machinery/power/solar_control/SC) + if(SC && (get_dist(src, SC) > SOLAR_MAX_DIST)) + return 0 + control = SC + return 1 + +//set the control of the tracker to null and removes it from the previous control computer if needed +/obj/machinery/power/tracker/proc/unset_control() + if(control) + control.connected_tracker = null + control = null + +/obj/machinery/power/tracker/proc/Make(var/obj/item/solar_assembly/S) + if(!S) + S = new /obj/item/solar_assembly(src) + S.glass_type = /obj/item/stack/material/glass + S.tracker = 1 + S.anchored = 1 + S.loc = src + update_icon() + +//updates the tracker icon and the facing angle for the control computer +/obj/machinery/power/tracker/proc/set_angle(var/angle) + sun_angle = angle + + //set icon dir to show sun illumination + set_dir(turn(NORTH, -angle - 22.5)) // 22.5 deg bias ensures, e.g. 67.5-112.5 is EAST + + if(powernet && (powernet == control.powernet)) //update if we're still in the same powernet + control.cdir = angle + +/obj/machinery/power/tracker/attackby(var/obj/item/weapon/W, var/mob/user) + + if(isCrowbar(W)) + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + user.visible_message("[user] begins to take the glass off the solar tracker.") + if(do_after(user, 50,src)) + var/obj/item/solar_assembly/S = locate() in src + if(S) + S.loc = src.loc + S.give_glass() + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + user.visible_message("[user] takes the glass off the tracker.") + qdel(src) + return + ..() + +// Tracker Electronic + +/obj/item/weapon/tracker_electronics + + name = "tracker electronics" + icon = 'icons/obj/doors/door_assembly.dmi' + icon_state = "door_electronics" + w_class = ITEM_SIZE_SMALL diff --git a/code/modules/power/turbine.dm b/code/modules/power/turbine.dm new file mode 100644 index 00000000..746c0f2a --- /dev/null +++ b/code/modules/power/turbine.dm @@ -0,0 +1,297 @@ +/obj/machinery/compressor + name = "compressor" + desc = "The compressor stage of a gas turbine generator." + icon = 'icons/obj/pipes.dmi' + icon_state = "compressor" + anchored = 1 + density = 1 + var/obj/machinery/power/turbine/turbine + var/datum/gas_mixture/gas_contained + var/turf/simulated/inturf + var/starter = 0 + var/rpm = 0 + var/rpmtarget = 0 + var/capacity = 1e6 + var/comp_id = 0 + +/obj/machinery/power/turbine + name = "gas turbine generator" + desc = "A gas turbine used for backup power generation." + icon = 'icons/obj/pipes.dmi' + icon_state = "turbine" + anchored = 1 + density = 1 + var/obj/machinery/compressor/compressor + var/turf/simulated/outturf + var/lastgen + +/obj/machinery/computer/turbine_computer + name = "Gas turbine control computer" + desc = "A computer to remotely control a gas turbine." + icon = 'icons/obj/computer.dmi' + icon_keyboard = "tech_key" + icon_screen = "turbinecomp" + circuit = /obj/item/weapon/circuitboard/turbine_control + anchored = 1 + density = 1 + var/obj/machinery/compressor/compressor + var/list/obj/machinery/door/blast/doors + var/id = 0 + var/door_status = 0 + +// the inlet stage of the gas turbine electricity generator + +/obj/machinery/compressor/New() + ..() + + gas_contained = new + inturf = get_step(src, dir) + + spawn(5) + turbine = locate() in get_step(src, get_dir(inturf, src)) + if(!turbine) + stat |= BROKEN + else + turbine.stat &= !BROKEN + turbine.compressor = src + + +#define COMPFRICTION 5e5 +#define COMPSTARTERLOAD 2800 + +/obj/machinery/compressor/Process() + if(!starter) + return + overlays.Cut() + if(stat & BROKEN) + return + if(!turbine) + stat |= BROKEN + return + rpm = 0.9* rpm + 0.1 * rpmtarget + var/datum/gas_mixture/environment = inturf.return_air() + var/transfer_moles = environment.total_moles / 10 + //var/transfer_moles = rpm/10000*capacity + var/datum/gas_mixture/removed = inturf.remove_air(transfer_moles) + gas_contained.merge(removed) + + rpm = max(0, rpm - (rpm*rpm)/COMPFRICTION) + + + if(starter && !(stat & NOPOWER)) + use_power(2800) + if(rpm<1000) + rpmtarget = 1000 + else + if(rpm<1000) + rpmtarget = 0 + + + + if(rpm>50000) + overlays += image('icons/obj/pipes.dmi', "comp-o4", FLY_LAYER) + else if(rpm>10000) + overlays += image('icons/obj/pipes.dmi', "comp-o3", FLY_LAYER) + else if(rpm>2000) + overlays += image('icons/obj/pipes.dmi', "comp-o2", FLY_LAYER) + else if(rpm>500) + overlays += image('icons/obj/pipes.dmi', "comp-o1", FLY_LAYER) + //TODO: DEFERRED + +/obj/machinery/power/turbine/New() + ..() + + outturf = get_step(src, dir) + + spawn(5) + + compressor = locate() in get_step(src, get_dir(outturf, src)) + if(!compressor) + stat |= BROKEN + else + compressor.stat &= !BROKEN + compressor.turbine = src + + +#define TURBPRES 9000000 +#define TURBGENQ 20000 +#define TURBGENG 0.8 + +/obj/machinery/power/turbine/Process() + if(!compressor.starter) + return + overlays.Cut() + if(stat & BROKEN) + return + if(!compressor) + stat |= BROKEN + return + lastgen = ((compressor.rpm / TURBGENQ)**TURBGENG) *TURBGENQ + + add_avail(lastgen) + var/newrpm = ((compressor.gas_contained.temperature) * compressor.gas_contained.total_moles)/4 + newrpm = max(0, newrpm) + + if(!compressor.starter || newrpm > 1000) + compressor.rpmtarget = newrpm + + if(compressor.gas_contained.total_moles>0) + var/oamount = min(compressor.gas_contained.total_moles, (compressor.rpm+100)/35000*compressor.capacity) + var/datum/gas_mixture/removed = compressor.gas_contained.remove(oamount) + outturf.assume_air(removed) + + if(lastgen > 100) + overlays += image('icons/obj/pipes.dmi', "turb-o", FLY_LAYER) + + + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.interact(M) + AutoUpdateAI(src) + +/obj/machinery/power/turbine/interact(mob/user) + + if ( (get_dist(src, user) > 1 ) || (stat & (NOPOWER|BROKEN)) && (!istype(user, /mob/living/silicon/ai)) ) + user.machine = null + user << browse(null, "window=turbine") + return + + user.machine = src + + var/t = "Gas Turbine Generator
            "
            +
            +	t += "Generated power : [round(lastgen)] W

            " + + t += "Turbine: [round(compressor.rpm)] RPM
            " + + t += "Starter: [ compressor.starter ? "Off On" : "Off On"]" + + t += "

            Close" + + t += "
            " + user << browse(t, "window=turbine") + onclose(user, "turbine") + + return + +/obj/machinery/power/turbine/CanUseTopic(var/mob/user, href_list) + if(!user.IsAdvancedToolUser()) + to_chat(user, FEEDBACK_YOU_LACK_DEXTERITY) + return min(..(), STATUS_UPDATE) + return ..() + +/obj/machinery/power/turbine/OnTopic(user, href_list) + if(href_list["close"]) + usr << browse(null, "window=turbine") + return TOPIC_HANDLED + + if(href_list["str"]) + compressor.starter = !compressor.starter + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + interact(user) + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + +/obj/machinery/computer/turbine_computer/Initialize() + . = ..() + for(var/obj/machinery/compressor/C in SSmachines.machinery) + if(id == C.comp_id) + compressor = C + doors = new /list() + for(var/obj/machinery/door/blast/P in SSmachines.machinery) + if(P.id == id) + doors += P + +/* +/obj/machinery/computer/turbine_computer/attackby(I as obj, user as mob) + if(istype(I, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + if (src.stat & BROKEN) + to_chat(user, "The broken glass falls out.") + var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) + new /obj/item/weapon/material/shard( src.loc ) + var/obj/item/weapon/circuitboard/turbine_control/M = new /obj/item/weapon/circuitboard/turbine_control( A ) + for (var/obj/C in src) + C.loc = src.loc + M.id = src.id + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + qdel(src) + else + to_chat(user, "You disconnect the monitor.") + var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/turbine_control/M = new /obj/item/weapon/circuitboard/turbine_control( A ) + for (var/obj/C in src) + C.loc = src.loc + M.id = src.id + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + qdel(src) + else + src.attack_hand(user) + return +*/ + +/obj/machinery/computer/turbine_computer/attack_hand(var/mob/user as mob) + user.machine = src + var/dat + if(src.compressor) + dat += {"
            Gas turbine remote control system
            + \nTurbine status: [ src.compressor.starter ? "Off On" : "Off On"] + \n
            + \nTurbine speed: [src.compressor.rpm]rpm
            + \nPower currently being generated: [src.compressor.turbine.lastgen]W
            + \nInternal gas temperature: [src.compressor.gas_contained.temperature]K
            + \nVent doors: [ src.door_status ? "Closed Open" : "Closed Open"] + \n
            View + \n
            Close + \n
            + \n"} + else + dat += "No compatible attached compressor found." + + user << browse(dat, "window=computer;size=400x500") + onclose(user, "computer") + return + + + +/obj/machinery/computer/turbine_computer/OnTopic(user, href_list) + if( href_list["view"] ) + usr.client.eye = src.compressor + . = TOPIC_HANDLED + else if( href_list["str"] ) + src.compressor.starter = !src.compressor.starter + . = TOPIC_REFRESH + else if (href_list["doors"]) + for(var/obj/machinery/door/blast/D in src.doors) + if (door_status == 0) + spawn( 0 ) + D.open() + door_status = 1 + else + spawn( 0 ) + D.close() + door_status = 0 + . = TOPIC_REFRESH + else if( href_list["close"] ) + user << browse(null, "window=computer") + return TOPIC_HANDLED + + if(. == TOPIC_REFRESH) + interact(user) + +/obj/machinery/computer/turbine_computer/Process() + src.updateDialog() + return \ No newline at end of file diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm new file mode 100644 index 00000000..845bff51 --- /dev/null +++ b/code/modules/projectiles/ammunition.dm @@ -0,0 +1,258 @@ +/obj/item/ammo_casing + name = "bullet casing" + desc = "A bullet casing." + icon = 'icons/obj/ammo.dmi' + icon_state = "s-casing" + randpixel = 10 + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT | SLOT_EARS + throwforce = 1 + w_class = ITEM_SIZE_TINY + + var/leaves_residue = 1 + var/caliber = "" //Which kind of guns it can be loaded into + var/projectile_type //The bullet type to create when New() is called + var/obj/item/projectile/BB = null //The loaded bullet - make it so that the projectiles are created only when needed? + var/spent_icon = "s-casing-spent" + var/ammo_stack = null //Put the path of the ammo stack you'd like to create here. It creates an ammo stack when you combine two of the same ammo type. + drop_sound = 'sound/items/handle/casing_drop.ogg' + + +/obj/item/ammo_casing/New() + ..() + if(ispath(projectile_type)) + BB = new projectile_type(src) + +//removes the projectile from the ammo casing +/obj/item/ammo_casing/proc/expend() + . = BB + BB = null + var/matrix/M = matrix() + M.Turn(rand(180)) + src.transform = M //spin spent casings + + // Aurora forensics port, gunpowder residue. + if(leaves_residue) + leave_residue() + pixel_x = rand(-randpixel, randpixel) + pixel_y = rand(-randpixel, randpixel) + + update_icon() + +/obj/item/ammo_casing/proc/leave_residue() + var/mob/living/carbon/human/H + if(ishuman(loc)) + H = loc //in a human, somehow + else if(loc && ishuman(loc.loc)) + H = loc.loc //more likely, we're in a gun being held by a human + + if(H) + if(H.gloves && (H.l_hand == loc || H.r_hand == loc)) + var/obj/item/clothing/G = H.gloves + G.gunshot_residue = caliber + else + H.gunshot_residue = caliber + +/obj/item/ammo_casing/attackby(obj/item/W as obj, mob/user as mob) + if(isScrewdriver(W)) + if(!BB) + to_chat(user, "There is no bullet in the casing to inscribe anything into.") + return + + var/tmp_label = "" + var/label_text = sanitizeSafe(input(user, "Inscribe some text into \the [initial(BB.name)]","Inscription",tmp_label), MAX_NAME_LEN) + if(length(label_text) > 20) + to_chat(user, "The inscription can be at most 20 characters long.") + else if(!label_text) + to_chat(user, "You scratch the inscription off of [initial(BB)].") + BB.SetName(initial(BB.name)) + else + to_chat(user, "You inscribe \"[label_text]\" into \the [initial(BB.name)].") + BB.SetName("[initial(BB.name)] (\"[label_text]\")") + + if(istype(W, /obj/item/ammo_casing)) + if(src.type == W.type) + var/obj/item/ammo_casing/A = W + if(A.BB && src.BB && ammo_stack) + var/obj/item/ammo_magazine/handful/H = new ammo_stack(src.loc) + H.update_icon() + qdel(src) + qdel(A) + user.put_in_hands(H) + + if(istype(W, /obj/item/ammo_magazine)) + var/obj/item/ammo_magazine/A = W + if(caliber == A.caliber && src.BB) + if(A.stored_ammo.len >= A.max_ammo) + to_chat(user, "[A] is full!") + return + else + if(src.loc == user) + user.remove_from_mob(src) + forceMove(A) + A.stored_ammo.Add(src) + A.update_icon() + //user.visible_message("\The [user] adds \a [src] to [A].", "You add \a [src] to [A].") + + else ..() + +/obj/item/ammo_casing/update_icon() + if(spent_icon && !BB) + icon_state = spent_icon + +/obj/item/ammo_casing/examine(mob/user) + . = ..() + if (!BB) + to_chat(user, "This one is spent.") + +//Gun loading types +#define SINGLE_CASING 1 //The gun only accepts ammo_casings. ammo_magazines should never have this as their mag_type. +#define SPEEDLOADER 2 //Transfers casings from the mag to the gun when used. +#define SINGLE_LOAD 3 //It only loads one at a time. +#define MAGAZINE 4 //The magazine item itself goes inside the gun + +//An item that holds casings and can be used to put them inside guns +/obj/item/ammo_magazine + name = "magazine" + desc = "A magazine for some kind of gun." + icon_state = "357" + icon = 'icons/obj/ammo.dmi' + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + item_state = "syringe_kit" + matter = list(DEFAULT_WALL_MATERIAL = 500) + throwforce = 5 + w_class = ITEM_SIZE_SMALL + throw_speed = 4 + throw_range = 10 + + var/list/stored_ammo = list() + var/mag_type = SPEEDLOADER //ammo_magazines can only be used with compatible guns. This is not a bitflag, the load_method var on guns is. + var/caliber = "357" + var/max_ammo = 7 + var/load_inddividually = FALSE + + var/ammo_type = /obj/item/ammo_casing //ammo type that is initially loaded + var/initial_ammo = null + + var/multiple_sprites = 0 + //because BYOND doesn't support numbers as keys in associative lists + var/list/icon_keys = list() //keys + var/list/ammo_states = list() //values + +/obj/item/ammo_magazine/box + w_class = ITEM_SIZE_NORMAL + +/obj/item/ammo_magazine/New() + ..() + if(multiple_sprites) + initialize_magazine_icondata(src) + + if(isnull(initial_ammo)) + initial_ammo = max_ammo + + if(initial_ammo) + for(var/i in 1 to initial_ammo) + stored_ammo += new ammo_type(src) + update_icon() + +/obj/item/ammo_magazine/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/ammo_casing)) + var/obj/item/ammo_casing/C = W + if(C.caliber != caliber) + to_chat(user, "[C] does not fit into [src].") + return + if(stored_ammo.len >= max_ammo) + to_chat(user, "[src] is full!") + return + user.remove_from_mob(C) + C.forceMove(src) + stored_ammo.Add(C) + update_icon() + + if(istype(W, /obj/item/ammo_magazine)) + var/obj/item/ammo_magazine/A = W + if(caliber == A.caliber) + if(!A.stored_ammo.len) + to_chat(user, "[A] is empty!") + else if(stored_ammo.len >= max_ammo) + to_chat(user, "[src] is full!") + return + else + var/obj/item/ammo_casing/C = A.stored_ammo[A.stored_ammo.len] + A.stored_ammo-=C + C.forceMove(src) + stored_ammo.Add(C) + update_icon() + A.update_icon() + //user.visible_message("\The [user] adds \a [C] to [src].", "You add \a [C] to [src].") + + + else ..() + +/obj/item/ammo_magazine/attack_self(mob/user) + if(!stored_ammo.len) + to_chat(user, "[src] is already empty!") + return + to_chat(user, "You empty [src].") + for(var/obj/item/ammo_casing/C in stored_ammo) + C.forceMove(user.loc) + C.set_dir(pick(GLOB.alldirs)) + stored_ammo.Cut() + update_icon() + + +/obj/item/ammo_magazine/attack_hand(mob/user) + if(user.get_inactive_hand() == src) + if(!stored_ammo.len) + to_chat(user, "[src] is already empty!") + else + var/obj/item/ammo_casing/C = stored_ammo[stored_ammo.len] + stored_ammo-=C + user.put_in_hands(C) + user.visible_message("\The [user] removes \a [C] from [src].", "You remove \a [C] from [src].") + update_icon() + else + ..() + return + +/obj/item/ammo_magazine/update_icon() + if(multiple_sprites) + //find the lowest key greater than or equal to stored_ammo.len + var/new_state = null + for(var/idx in 1 to icon_keys.len) + var/ammo_count = icon_keys[idx] + if (ammo_count >= stored_ammo.len) + new_state = ammo_states[idx] + break + icon_state = (new_state)? new_state : initial(icon_state) + +/obj/item/ammo_magazine/examine(mob/user) + . = ..() + to_chat(user, "There [(stored_ammo.len == 1)? "is" : "are"] [stored_ammo.len] round\s left!") + +//magazine icon state caching +/var/global/list/magazine_icondata_keys = list() +/var/global/list/magazine_icondata_states = list() + +/proc/initialize_magazine_icondata(var/obj/item/ammo_magazine/M) + var/typestr = "[M.type]" + if(!(typestr in magazine_icondata_keys) || !(typestr in magazine_icondata_states)) + magazine_icondata_cache_add(M) + + M.icon_keys = magazine_icondata_keys[typestr] + M.ammo_states = magazine_icondata_states[typestr] + +/proc/magazine_icondata_cache_add(var/obj/item/ammo_magazine/M) + var/list/icon_keys = list() + var/list/ammo_states = list() + var/list/states = icon_states(M.icon) + for(var/i = 0, i <= M.max_ammo, i++) + var/ammo_state = "[M.icon_state]-[i]" + if(ammo_state in states) + icon_keys += i + ammo_states += ammo_state + + magazine_icondata_keys["[M.type]"] = icon_keys + magazine_icondata_states["[M.type]"] = ammo_states + diff --git a/code/modules/projectiles/ammunition/boxes.dm b/code/modules/projectiles/ammunition/boxes.dm new file mode 100644 index 00000000..74ced5a1 --- /dev/null +++ b/code/modules/projectiles/ammunition/boxes.dm @@ -0,0 +1,305 @@ +/obj/item/ammo_magazine/a357 + name = "speed loader (.357)" + desc = "A speed loader for revolvers." + icon_state = "38" + caliber = "357" + ammo_type = /obj/item/ammo_casing/a357 + matter = list(DEFAULT_WALL_MATERIAL = 1260) + max_ammo = 6 + multiple_sprites = 1 + +/obj/item/ammo_magazine/c50 + name = "speed loader (.50)" + desc = "A speed loader for revolvers." + icon_state = "38" + caliber = ".50" + ammo_type = /obj/item/ammo_casing/a50 + matter = list(DEFAULT_WALL_MATERIAL = 1260) + max_ammo = 6 + multiple_sprites = 1 + +/obj/item/ammo_magazine/c38 + name = "speed loader (.38)" + desc = "A speed loader for revolvers." + icon_state = "38" + caliber = "38" + matter = list(DEFAULT_WALL_MATERIAL = 360) + ammo_type = /obj/item/ammo_casing/c38 + max_ammo = 6 + multiple_sprites = 1 + +/obj/item/ammo_magazine/c38/rubber + name = "speed loader (.38, rubber)" + icon_state = "R38" + ammo_type = /obj/item/ammo_casing/c38/rubber + +/obj/item/ammo_magazine/c44 + name = "speed loader (.44 magnum)" + desc = "A speed loader for revolvers." + icon_state = "38" + ammo_type = /obj/item/ammo_casing/c44 + matter = list(DEFAULT_WALL_MATERIAL = 450) + caliber = ".44" + max_ammo = 6 + multiple_sprites = 1 + +/obj/item/ammo_magazine/c44/rubber + name = "speed loader (.44 magnum, rubber)" + icon_state = "R38" + ammo_type = /obj/item/ammo_casing/c44/rubber + +/obj/item/ammo_magazine/c45m + name = "magazine (.45)" + icon_state = "45" + mag_type = MAGAZINE + ammo_type = /obj/item/ammo_casing/c45 + matter = list(DEFAULT_WALL_MATERIAL = 525) //metal costs are very roughly based around 1 .45 casing = 75 metal + caliber = ".45" + max_ammo = 7 + multiple_sprites = 1 + +/obj/item/ammo_magazine/c45m/empty + initial_ammo = 0 + +/obj/item/ammo_magazine/c45m/rubber + name = "magazine (.45, rubber)" + ammo_type = /obj/item/ammo_casing/c45/rubber + +/obj/item/ammo_magazine/c45m/practice + name = "magazine (.45, practice)" + ammo_type = /obj/item/ammo_casing/c45/practice + +/obj/item/ammo_magazine/c45m/flash + name = "magazine (.45, flash)" + ammo_type = /obj/item/ammo_casing/c45/flash + +/obj/item/ammo_magazine/c45uzi + name = "stick magazine (.45)" + icon_state = "uzi45" + mag_type = MAGAZINE + ammo_type = /obj/item/ammo_casing/c45 + matter = list(DEFAULT_WALL_MATERIAL = 1200) + caliber = ".45" + max_ammo = 16 + multiple_sprites = 1 + +/obj/item/ammo_magazine/c45uzi/empty + initial_ammo = 0 + +/obj/item/ammo_magazine/c45rifle + name = "rifle magazine (.45)" + icon_state = "rifle" + mag_type = MAGAZINE + ammo_type = /obj/item/ammo_casing/c45 + matter = list(DEFAULT_WALL_MATERIAL = 1500) + caliber = ".45" + max_ammo = 20 + multiple_sprites = 1 + + +/obj/item/ammo_magazine/c45rifle/akarabiner + name = "Warmonger magazine (.45)" + icon_state = "autorifle" + + +/obj/item/ammo_magazine/c45rifle/combatrifle + name = "Nightfall magazine (.45)" + icon_state = "akarabiner" + + +/obj/item/ammo_magazine/mc9mm + name = "magazine (9mm)" + icon_state = "9x19p" + origin_tech = list(TECH_COMBAT = 2) + mag_type = MAGAZINE + matter = list(DEFAULT_WALL_MATERIAL = 600) + caliber = "9mm" + ammo_type = /obj/item/ammo_casing/c9mm + max_ammo = 10 + multiple_sprites = 1 + +/obj/item/ammo_magazine/mc9mm/empty + initial_ammo = 0 + +/obj/item/ammo_magazine/mc9mm/flash + name = "magazine (9mm, flash)" + ammo_type = /obj/item/ammo_casing/c9mm/flash + +/obj/item/ammo_magazine/box/c9mm + name = "ammunition box (9mm)" + icon_state = "9mm" + origin_tech = list(TECH_COMBAT = 2) + matter = list(DEFAULT_WALL_MATERIAL = 1800) + caliber = "9mm" + ammo_type = /obj/item/ammo_casing/c9mm + max_ammo = 30 + +/obj/item/ammo_magazine/box/c9mm/empty + initial_ammo = 0 + +/obj/item/ammo_magazine/box/emp + name = "ammunition box (.38, haywire)" + icon_state = "empbox" + origin_tech = list(TECH_COMBAT = 2) + max_ammo = 10 + ammo_type = /obj/item/ammo_casing/c38/emp + caliber = ".38" + +/obj/item/ammo_magazine/box/emp/c45 + name = "ammunition box (.45, haywire)" + ammo_type = /obj/item/ammo_casing/c45/emp + caliber = ".45" + +/obj/item/ammo_magazine/box/emp/a10mm + name = "ammunition box (10mm, haywire)" + ammo_type = /obj/item/ammo_casing/a10mm/emp + caliber = "10mm" + +/obj/item/ammo_magazine/mc9mmt + name = "top mounted magazine (9mm)" + icon_state = "9mmt" + mag_type = MAGAZINE + ammo_type = /obj/item/ammo_casing/c9mm + matter = list(DEFAULT_WALL_MATERIAL = 1200) + caliber = "9mm" + max_ammo = 20 + multiple_sprites = 1 + +/obj/item/ammo_magazine/mc9mmt/empty + initial_ammo = 0 + +/obj/item/ammo_magazine/mc9mmt/machinepistol + name = "Soulburn magazine" + desc = "Holds 30 bullets. That should be enough for all of ya." + icon_state = "machinepistol" + max_ammo = 30 + +/obj/item/ammo_magazine/mc9mmt/rubber + name = "top mounted magazine (9mm, rubber)" + ammo_type = /obj/item/ammo_casing/c9mm/rubber + +/obj/item/ammo_magazine/mc9mmt/practice + name = "top mounted magazine (9mm, practice)" + ammo_type = /obj/item/ammo_casing/c9mm/practice + +/obj/item/ammo_magazine/box/c45 + name = "ammunition box (.45)" + icon_state = "9mm" + origin_tech = list(TECH_COMBAT = 2) + caliber = ".45" + matter = list(DEFAULT_WALL_MATERIAL = 2250) + ammo_type = /obj/item/ammo_casing/c45 + max_ammo = 30 + +/obj/item/ammo_magazine/box/c45/empty + initial_ammo = 0 + +/obj/item/ammo_magazine/a10mm + name = "magazine (10mm)" + icon_state = "10mm" + origin_tech = list(TECH_COMBAT = 2) + mag_type = MAGAZINE + caliber = "10mm" + matter = list(DEFAULT_WALL_MATERIAL = 1500) + ammo_type = /obj/item/ammo_casing/a10mm + max_ammo = 20 + multiple_sprites = 1 + +/obj/item/ammo_magazine/a10mm/empty + initial_ammo = 0 + +/obj/item/ammo_magazine/a762 + name = "magazine (7.62mm)" + icon_state = "5.56" + origin_tech = list(TECH_COMBAT = 2) + mag_type = MAGAZINE + caliber = "a762" + matter = list(DEFAULT_WALL_MATERIAL = 1800) + ammo_type = /obj/item/ammo_casing/a762 + max_ammo = 15 //if we lived in a world where normal mags had 30 rounds, this would be a 20 round mag + multiple_sprites = 1 + +/obj/item/ammo_magazine/a762/empty + initial_ammo = 0 + +/obj/item/ammo_magazine/a762/practice + name = "magazine (7.62mm, practice)" + ammo_type = /obj/item/ammo_casing/a762/practice + +/obj/item/ammo_magazine/a50 + name = "magazine (.50)" + icon_state = "50ae" + origin_tech = list(TECH_COMBAT = 2) + mag_type = MAGAZINE + caliber = ".50" + matter = list(DEFAULT_WALL_MATERIAL = 1260) + ammo_type = /obj/item/ammo_casing/a50 + max_ammo = 7 + multiple_sprites = 1 + +/obj/item/ammo_magazine/a50/empty + initial_ammo = 0 + +/obj/item/ammo_magazine/a75 + name = "ammo magazine (20mm)" + icon_state = "75" + mag_type = MAGAZINE + caliber = "75" + ammo_type = /obj/item/ammo_casing/a75 + multiple_sprites = 1 + max_ammo = 4 + +/obj/item/ammo_magazine/a75/empty + initial_ammo = 0 + +/obj/item/ammo_magazine/box/a556 + name = "magazine box (5.56mm)" + icon_state = "a762" + origin_tech = list(TECH_COMBAT = 2) + mag_type = MAGAZINE + caliber = "a556" + matter = list(DEFAULT_WALL_MATERIAL = 4500) + ammo_type = /obj/item/ammo_casing/a556 + max_ammo = 50 + multiple_sprites = 1 + +/obj/item/ammo_magazine/box/a556/empty + initial_ammo = 0 + +/obj/item/ammo_magazine/box/a556/mg08 + name = "LMG mag" + icon_state = "hmg" + +/obj/item/ammo_magazine/c556 + name = "magazine (5.56mm)" + icon_state = "c762" + mag_type = MAGAZINE + caliber = "a556" + matter = list(DEFAULT_WALL_MATERIAL = 1800) + ammo_type = /obj/item/ammo_casing/a556 + max_ammo = 20 + multiple_sprites = 1 + +/obj/item/ammo_magazine/caps + name = "speed loader (caps)" + desc = "A cheap plastic speed loader for some kind of revolver." + icon_state = "T38" + caliber = "caps" + color = "#ff0000" + ammo_type = /obj/item/ammo_casing/cap + matter = list(DEFAULT_WALL_MATERIAL = 600) + max_ammo = 7 + multiple_sprites = 1 + +/obj/item/ammo_magazine/flamer + name = "flamer fuel" + desc = "Put it in your flamer and roast those you don't like." + icon_state = "flamer" + caliber = "flamer" + mag_type = MAGAZINE + ammo_type = /obj/item/ammo_casing/flamer + max_ammo = 30 + multiple_sprites = FALSE + +/obj/item/ammo_magazine/flamer/attack_self(mob/user) //Don't empty ur ammo + return diff --git a/code/modules/projectiles/ammunition/bullets.dm b/code/modules/projectiles/ammunition/bullets.dm new file mode 100644 index 00000000..fda3dcaf --- /dev/null +++ b/code/modules/projectiles/ammunition/bullets.dm @@ -0,0 +1,232 @@ +/obj/item/ammo_casing/a357 + desc = "A .357 bullet casing." + caliber = "357" + projectile_type = /obj/item/projectile/bullet/pistol/strong/revolver + ammo_stack = /obj/item/ammo_magazine/handful/revolver/two + +/obj/item/ammo_casing/a50 + desc = "A .50AE bullet casing." + caliber = ".50" + projectile_type = /obj/item/projectile/bullet/pistol/strong + +/obj/item/ammo_casing/a75 + desc = "A 20mm bullet casing." + caliber = "75" + projectile_type = /obj/item/projectile/bullet/gyro + +/obj/item/ammo_casing/c38 + desc = "A .38 bullet casing." + caliber = "38" + projectile_type = /obj/item/projectile/bullet/pistol + +/obj/item/ammo_casing/c38/rubber + desc = "A .38 rubber bullet casing." + projectile_type = /obj/item/projectile/bullet/pistol/rubber + icon_state = "r-casing" + spent_icon = "r-casing-spent" + +/obj/item/ammo_casing/c9mm + desc = "A 9mm bullet casing." + caliber = "9mm" + projectile_type = /obj/item/projectile/bullet/pistol + +/obj/item/ammo_casing/c9mm/flash + desc = "A 9mm flash shell casing." + projectile_type = /obj/item/projectile/energy/flash + +/obj/item/ammo_casing/c9mm/rubber + desc = "A 9mm rubber bullet casing." + projectile_type = /obj/item/projectile/bullet/pistol/rubber + icon_state = "r-casing" + spent_icon = "r-casing-spent" + +/obj/item/ammo_casing/c9mm/practice + desc = "A 9mm practice bullet casing." + projectile_type = /obj/item/projectile/bullet/pistol/practice + +/obj/item/ammo_casing/c44 + desc = "A .44 magnum bullet casing." + caliber = ".44" + projectile_type = /obj/item/projectile/bullet/pistol/medium/revolver + +/obj/item/ammo_casing/c44/rubber + desc = "A .44 magnum rubber bullet casing." + projectile_type = /obj/item/projectile/bullet/pistol/rubber + icon_state = "r-casing" + spent_icon = "r-casing-spent" + +/obj/item/ammo_casing/c45 + desc = "A warmonger bullet casing." + caliber = ".45" + projectile_type = /obj/item/projectile/bullet/pistol/medium + +/obj/item/ammo_casing/c45/practice + desc = "A .45 practice bullet casing." + projectile_type = /obj/item/projectile/bullet/pistol/practice + +/obj/item/ammo_casing/c45/rubber + desc = "A .45 rubber bullet casing." + projectile_type = /obj/item/projectile/bullet/pistol/rubber + icon_state = "r-casing" + spent_icon = "r-casing-spent" + +/obj/item/ammo_casing/c45/flash + desc = "A .45 flash shell casing." + projectile_type = /obj/item/projectile/energy/flash + +/obj/item/ammo_casing/a10mm + desc = "A 10mm bullet casing." + caliber = "10mm" + projectile_type = /obj/item/projectile/bullet/pistol/medium/smg + +/obj/item/ammo_casing/shotgun + name = "shotgun slug" + desc = "A 12 gauge slug." + icon_state = "slshell" + spent_icon = "slshell-spent" + caliber = "shotgun" + drop_sound = 'sound/weapons/guns/misc/shotgun_fall.ogg' + projectile_type = /obj/item/projectile/bullet/shotgun + matter = list(DEFAULT_WALL_MATERIAL = 360) + +/obj/item/ammo_casing/shotgun/pellet + name = "shotgun shell" + desc = "A 12 gauge shell." + icon_state = "gshell" + spent_icon = "gshell-spent" + projectile_type = /obj/item/projectile/bullet/pellet/shotgun + ammo_stack = /obj/item/ammo_magazine/handful/shotgun/shotgun_handful/two + matter = list(DEFAULT_WALL_MATERIAL = 360) + + +/obj/item/ammo_casing/shotgun/blank + name = "shotgun shell" + desc = "A blank shell." + icon_state = "blshell" + spent_icon = "blshell-spent" + projectile_type = /obj/item/projectile/bullet/blank + matter = list(DEFAULT_WALL_MATERIAL = 90) + +/obj/item/ammo_casing/shotgun/practice + name = "shotgun shell" + desc = "A practice shell." + icon_state = "pshell" + spent_icon = "pshell-spent" + projectile_type = /obj/item/projectile/bullet/shotgun/practice + matter = list("metal" = 90) + +/obj/item/ammo_casing/shotgun/beanbag + name = "beanbag shell" + desc = "A beanbag shell." + icon_state = "bshell" + spent_icon = "bshell-spent" + projectile_type = /obj/item/projectile/bullet/shotgun/beanbag + matter = list(DEFAULT_WALL_MATERIAL = 180) + +//Can stun in one hit if aimed at the head, but +//is blocked by clothing that stops tasers and is vulnerable to EMP +/obj/item/ammo_casing/shotgun/stunshell + name = "stun shell" + desc = "A 12 gauge taser cartridge." + icon_state = "stunshell" + spent_icon = "stunshell-spent" + projectile_type = /obj/item/projectile/energy/electrode/stunshot + leaves_residue = 0 + matter = list(DEFAULT_WALL_MATERIAL = 360, "glass" = 720) + +/obj/item/ammo_casing/shotgun/stunshell/emp_act(severity) + if(prob(100/severity)) BB = null + update_icon() + +//Does not stun, only blinds, but has area of effect. +/obj/item/ammo_casing/shotgun/flash + name = "flash shell" + desc = "A chemical shell used to signal distress or provide illumination." + icon_state = "fshell" + spent_icon = "fshell-spent" + projectile_type = /obj/item/projectile/energy/flash/flare + matter = list(DEFAULT_WALL_MATERIAL = 90, "glass" = 90) + +/obj/item/ammo_casing/a556 + desc = "A 5.56mm bullet casing." + caliber = "a556" + projectile_type = /obj/item/projectile/bullet/rifle/a556 + icon_state = "rifle-casing" + spent_icon = "rifle-casing-spent" + +/obj/item/ammo_casing/a145 + name = "shell casing" + desc = "A 14.5mm shell." + icon_state = "lcasing" + spent_icon = "lcasing-spent" + caliber = "14.5mm" + projectile_type = /obj/item/projectile/bullet/rifle/a145 + matter = list(DEFAULT_WALL_MATERIAL = 1250) + +/obj/item/ammo_casing/a145/apds + name = "APDS shell casing" + desc = "A 14.5mm Armour Piercing Discarding Sabot shell." + projectile_type = /obj/item/projectile/bullet/rifle/a145/apds + +/obj/item/ammo_casing/a762 + desc = "A 7.62mm bullet casing." + caliber = "a762" + projectile_type = /obj/item/projectile/bullet/rifle/a762 + icon_state = "rifle-casing" + spent_icon = "rifle-casing-spent" + +/obj/item/ammo_casing/a762/practice + desc = "A 7.62mm practice bullet casing." + projectile_type = /obj/item/projectile/bullet/rifle/a762/practice + +/obj/item/ammo_casing/rocket + name = "rocket shell" + desc = "A high explosive designed to be fired from a launcher." + icon_state = "rocketshell" + projectile_type = /obj/item/missile + caliber = "rocket" + +/obj/item/ammo_casing/cap + name = "cap" + desc = "A cap for children toys." + caliber = "caps" + color = "#ff0000" + projectile_type = /obj/item/projectile/bullet/pistol/cap + +// EMP ammo. +/obj/item/ammo_casing/c38/emp + name = ".38 haywire round" + desc = "A .38 bullet casing fitted with a single-use ion pulse generator." + icon_state = "empcasing" + projectile_type = /obj/item/projectile/ion/small + matter = list(DEFAULT_WALL_MATERIAL = 130, "uranium" = 100) + +/obj/item/ammo_casing/c45/emp + name = ".45 haywire round" + desc = "A .45 bullet casing fitted with a single-use ion pulse generator." + projectile_type = /obj/item/projectile/ion/small + icon_state = "empcasing" + matter = list(DEFAULT_WALL_MATERIAL = 130, "uranium" = 100) + +/obj/item/ammo_casing/a10mm/emp + name = "10mm haywire round" + desc = "A 10mm bullet casing fitted with a single-use ion pulse generator." + projectile_type = /obj/item/projectile/ion/small + icon_state = "empcasing" + matter = list(DEFAULT_WALL_MATERIAL = 130, "uranium" = 100) + +/obj/item/ammo_casing/shotgun/emp + name = "haywire slug" + desc = "A 12-gauge shotgun slug fitted with a single-use ion pulse generator." + icon_state = "empshell" + spent_icon = "empshell-spent" + projectile_type = /obj/item/projectile/ion + matter = list(DEFAULT_WALL_MATERIAL = 260, "uranium" = 200) + +/obj/item/ammo_casing/flamer + name = "fire" + desc = "Fire ammo isn't deleting properly for some reason. Please don't bug Matt about this he knows." + icon_state = "null" + spent_icon = "null" + caliber = "flamer" + projectile_type = /obj/item/projectile/flamer \ No newline at end of file diff --git a/code/modules/projectiles/ammunition/handfuls.dm b/code/modules/projectiles/ammunition/handfuls.dm new file mode 100644 index 00000000..6da87f36 --- /dev/null +++ b/code/modules/projectiles/ammunition/handfuls.dm @@ -0,0 +1,236 @@ +//Handfuls +/obj/item/ammo_magazine/handful + name = "handful" + desc = "If you see this Matt fucked something up." + mag_type = SINGLE_LOAD + max_ammo = 5 + multiple_sprites = 1 + drop_sound = 'sound/items/handle/casing_drop.ogg' + +/obj/item/ammo_magazine/handful/New() + ..() + update_icon() + +/obj/item/ammo_magazine/handful/update_icon() + if(!stored_ammo.len)//There's no more ammo here, so delete the handful. + qdel(src) + return + icon_state = "[initial(icon_state)][stored_ammo.len]"//If there is ammo then we take our initial icon_state and add the ammount of ammo in the stack to it. + +/obj/item/ammo_magazine/handful/attack_self(mob/user)//We want to override the normal attack self with makes us "empty" our "clip". + return + +//Rifle +/obj/item/ammo_magazine/handful/brifle_handful + name = "\improper handful of bullets" + desc = "A handful of rifle bullets for your rifle." + icon_state = "brifle" + caliber = "763" + ammo_type = /obj/item/ammo_casing/brifle + grab_sound = 'sound/items/handle/bullet_pickup.ogg' + +/obj/item/ammo_magazine/handful/brifle_handful/two + initial_ammo = 2 + + +//Shotgun +/obj/item/ammo_magazine/handful/shotgun + drop_sound = 'sound/weapons/guns/misc/shotgun_fall.ogg' + +/obj/item/ammo_magazine/handful/shotgun/shotgun_handful + name = "\improper handful of shells" + desc = "A handful of shotgun shells for your shotgun." + icon_state = "gshell" + item_state = "shotgun_handful" + caliber = "shotgun" + ammo_type = /obj/item/ammo_casing/shotgun/pellet + drop_sound = 'sound/weapons/guns/misc/shotgun_fall.ogg' + +/obj/item/ammo_magazine/handful/shotgun/shotgun_handful/two + initial_ammo = 2 + +/obj/item/ammo_magazine/handful/shotgun/slug_handful + name = "\improper handful of slug shells" + desc = "A handful of slugs, like buckshot without the spread." + icon_state = "slshell" + caliber = "shotgun" + ammo_type = /obj/item/ammo_casing/shotgun + +/obj/item/ammo_magazine/handful/shotgun/beanbag_handful + name = "\improper handful of shells" + desc = "A handful of shotgun shells for your shotgun." + icon_state = "bshell" + caliber = "shotgun" + ammo_type = /obj/item/ammo_casing/shotgun/beanbag + + +//Revolver +/obj/item/ammo_magazine/handful/revolver + name = "\improper handful of revolver ammo" + desc = "Why use a quickloader, when you can be a quicker loader?" + icon_state = "revolver-handful" + ammo_type = /obj/item/ammo_casing/a357 + max_ammo = 6 + +/obj/item/ammo_magazine/handful/revolver/two + initial_ammo = 2 + +/obj/item/ammo_magazine/handful/ptsd + name = "PTSD round" + desc = "Massive bullet, used to shoot tanks, and also people." + icon_state = "lcasing" + ammo_type = /obj/item/ammo_casing/a145 + max_ammo = 1 + caliber = "14.5mm" + + +/* + * AMMO BOXES + */ + + +/obj/item/ammo_box + name = "\improper box of ammo" + desc = "You get bullets out of this." + icon = 'icons/obj/ammo.dmi' + icon_state = "rbox" + w_class = ITEM_SIZE_SMALL //So you can put it in your pocket. + var/handful_type = null + var/list/stored_handfuls = list() + var/max_stacks = 4 + var/handful_verb = "handful" + +/obj/item/ammo_box/Initialize() + . = ..() + for(var/i in 1 to max_stacks) + stored_handfuls += new handful_type(src) + update_icon() + +/obj/item/ammo_box/examine(mob/user) + . = ..() + if(stored_handfuls.len) + to_chat(user, "It has [stored_handfuls.len] [handful_verb]s left.") + else + to_chat(user, "It is empty.") + + +/obj/item/ammo_box/attack_hand(var/mob/living/carbon/human/user) + if(!istype(user)) + ..() + return + if((src != user.r_store) && (src != user.l_store) && (src != user.belt) && (src != user.get_inactive_hand())) + ..()//If it's not in any of these slots then just return normally. + return + if(!stored_handfuls.len)//If there's no more handfuls then don't divide by 0 please. + return + var/obj/item/ammo_magazine/handful/A = src.stored_handfuls[1]//If it is in one of these slots though put it in our hand. + if(A) + stored_handfuls.Cut(1, 2) + user.put_in_hands(A) + user.visible_message("[user] takes [A] out.") + update_icon() + +/obj/item/ammo_box/attackby(obj/item/C, mob/user) + if(!istype(C, handful_type)) + to_chat(user, "\The [src] does not accept this [handful_verb].") + return + if(stored_handfuls.len == max_stacks) + to_chat(user, "There's too many [handful_verb]s in there already.") + return + user.remove_from_mob(C) + C.forceMove(src) + stored_handfuls.Add(C) + user.visible_message("[user] adds [C] to the box.") + update_icon() + + +/obj/item/ammo_box/MouseDrop(var/obj/over_object) + if (!over_object || !(ishuman(usr) || issmall(usr))) + return + + if (!(src.loc == usr)) + return + + if (usr.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_KNOCKOUT)) + return + + if (!usr.unEquip(src)) + return + + switch(over_object.name) + if("r_hand") + usr.put_in_r_hand(src) + if("l_hand") + usr.put_in_l_hand(src) + + src.add_fingerprint(usr) + +//Rifle box. +/obj/item/ammo_box/rifle + name = "\improper rifle bullets box" + desc = "You get rifle bullets out of this one." + handful_type = /obj/item/ammo_magazine/handful/brifle_handful + + +//Box of handfuls of shotgun ammo. +/obj/item/ammo_box/shotgun + name = "\improper shells box" + icon_state = "shotgunammo" + desc = "You get shells out of this." + handful_type = /obj/item/ammo_magazine/handful/shotgun/shotgun_handful + + +/obj/item/ammo_box/ptsd + name = "\improper shells box" + icon_state = "ptsdbox" + desc = "You get shells out of this." + handful_type = /obj/item/ammo_magazine/handful/ptsd + max_stacks = 10 //Holds 10, one round handfuls. + handful_verb = "round" + + +//Dumb shotgun stuff from another time. +/obj/item/ammo_magazine/box/shotgun + name = "shells box" + icon_state = "gbox" + caliber = "shotgun" + ammo_type = /obj/item/ammo_casing/shotgun/pellet + max_ammo = 8 + multiple_sprites = 1 + var/open = FALSE + +/obj/item/ammo_magazine/box/shotgun/update_icon() + if(!open) + overlays.Cut() + icon_state = "[initial(icon_state)]" + return + icon_state = "[initial(icon_state)]-0" + overlays.Cut() + var/i = 0 + for(var/obj/item/ammo_casing/shotgun/AC in stored_ammo) + i++ + overlays += icon('icons/obj/ammo.dmi', "[AC.icon_state]-[i]") + +/obj/item/ammo_magazine/box/shotgun/attack_self(mob/user) + open =! open + update_icon() + +/obj/item/ammo_magazine/box/shotgun/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(!open) + return + ..() + +/obj/item/ammo_magazine/box/shotgun/slug + name = "slug box" + icon_state = "blbox" + ammo_type = /obj/item/ammo_casing/shotgun + +/obj/item/ammo_magazine/box/shotgun/stun + name = "stunshells box" + icon_state = "stunbox" + ammo_type = /obj/item/ammo_casing/shotgun/stunshell + +/obj/item/ammo_magazine/box/shotgun/bean + name = "beanbag box" + icon_state = "bbox" + ammo_type = /obj/item/ammo_casing/shotgun/beanbag \ No newline at end of file diff --git a/code/modules/projectiles/ammunition/magnetic.dm b/code/modules/projectiles/ammunition/magnetic.dm new file mode 100644 index 00000000..cacefc78 --- /dev/null +++ b/code/modules/projectiles/ammunition/magnetic.dm @@ -0,0 +1,13 @@ +/obj/item/weapon/magnetic_ammo + name = "flechette magazine" + desc = "A magazine containing steel flechettes." + icon = 'icons/obj/ammo.dmi' + icon_state = "5.56" + w_class = ITEM_SIZE_SMALL + matter = list(DEFAULT_WALL_MATERIAL = 1800) + origin_tech = list(TECH_COMBAT = 1) + var/remaining = 9 + +/obj/item/weapon/magnetic_ammo/examine(mob/user) + . = ..() + to_chat(user, "There [(remaining == 1)? "is" : "are"] [remaining] flechette\s left!") \ No newline at end of file diff --git a/code/modules/projectiles/effects.dm b/code/modules/projectiles/effects.dm new file mode 100644 index 00000000..e8501d0f --- /dev/null +++ b/code/modules/projectiles/effects.dm @@ -0,0 +1,185 @@ +/obj/effect/projectile + icon = 'icons/effects/projectiles.dmi' + icon_state = "bolt" + plane = EFFECTS_ABOVE_LIGHTING_PLANE + layer = BEAM_PROJECTILE_LAYER //Muzzle flashes would be above the lighting plane anyways. + //Standard compiletime light vars aren't working here, so we've made some of our own. + light_range = 2 + light_power = 1 + light_color = "#FF00DC" + +/obj/effect/projectile/proc/set_transform(var/matrix/M) + if(istype(M)) + transform = M + +//---------------------------- +// Laser beam +//---------------------------- +/obj/effect/projectile/laser/ + light_color = COLOR_RED_LIGHT + +/obj/effect/projectile/laser/tracer + icon_state = "beam" + +/obj/effect/projectile/laser/muzzle + icon_state = "muzzle_laser" + +/obj/effect/projectile/laser/impact + icon_state = "impact_laser" + +//---------------------------- +// Blue laser beam +//---------------------------- +/obj/effect/projectile/laser/blue + light_color = COLOR_BLUE_LIGHT + +/obj/effect/projectile/laser/blue/tracer + icon_state = "beam_blue" + +/obj/effect/projectile/laser/blue/muzzle + icon_state = "muzzle_blue" + +/obj/effect/projectile/laser/blue/impact + icon_state = "impact_blue" + +//---------------------------- +// Omni laser beam +//---------------------------- +/obj/effect/projectile/laser/omni + light_color = COLOR_LUMINOL + +/obj/effect/projectile/laser/omni/tracer//tracer + icon_state = "beam_omni" + +/obj/effect/projectile/laser/omni/muzzle//muzzle + icon_state = "muzzle_omni" + +/obj/effect/projectile/laser/omni/impact//impact + icon_state = "impact_omni" + +//---------------------------- +// Xray laser beam +//---------------------------- +/obj/effect/projectile/laser/xray + light_color = "#00cc00" + +/obj/effect/projectile/laser/xray/tracer + icon_state = "xray" + +/obj/effect/projectile/laser/xray/muzzle + icon_state = "muzzle_xray" + +/obj/effect/projectile/laser/xray/impact + icon_state = "impact_xray" + +//---------------------------- +// Heavy laser beam +//---------------------------- +/obj/effect/projectile/laser/heavy + light_power = 3 + +/obj/effect/projectile/laser/heavy/tracer + icon_state = "beam_heavy" + +/obj/effect/projectile/laser/heavy/muzzle + icon_state = "muzzle_beam_heavy" + +/obj/effect/projectile/laser/heavy/impact + icon_state = "impact_beam_heavy" + +//---------------------------- +// Pulse laser beam +//---------------------------- +/obj/effect/projectile/laser/pulse + light_power = 2 + light_color = COLOR_DEEP_SKY_BLUE + +/obj/effect/projectile/laser/pulse/tracer + icon_state = "u_laser" + + +/obj/effect/projectile/laser/pulse/muzzle + icon_state = "muzzle_u_laser" + +/obj/effect/projectile/laser/pulse/impact + icon_state = "impact_u_laser" + +//---------------------------- +// Bogani Pulsar beam +//---------------------------- +/obj/effect/projectile/laser/bogani/ + light_power = 2 + light_color = COLOR_VIOLET + +/obj/effect/projectile/laser/bogani/tracer + icon_state = "bogb" + +/obj/effect/projectile/laser/bogani/muzzle + icon_state = "muzzle_bogb" + +/obj/effect/projectile/laser/bogani/impact + icon_state = "impact_bogb" + +//---------------------------- +// Pulse muzzle effect only +//---------------------------- +/obj/effect/projectile/pulse/muzzle + icon_state = "muzzle_pulse" + light_power = 2 + light_color = COLOR_DEEP_SKY_BLUE + +//---------------------------- +// Treye beam +//---------------------------- +/obj/effect/projectile/trilaser/ + light_color = COLOR_LUMINOL + +/obj/effect/projectile/trilaser/tracer + icon_state = "plasmacutter" + +/obj/effect/projectile/trilaser/muzzle + icon_state = "muzzle_plasmacutter" + +/obj/effect/projectile/trilaser/impact + icon_state = "impact_plasmacutter" + +//---------------------------- +// laser/emitter beam +//---------------------------- +/obj/effect/projectile/laser/emitter/ + light_power = 3 + light_color = "#00cc00" + +/obj/effect/projectile/laser/emitter/tracer + icon_state = "laser/emitter" + +/obj/effect/projectile/laser/emitter/muzzle + icon_state = "muzzle_laser/emitter" + +/obj/effect/projectile/laser/emitter/impact + icon_state = "impact_laser/emitter" + +//---------------------------- +// Stun beam +//---------------------------- +/obj/effect/projectile/stun/ + light_color = COLOR_YELLOW + +/obj/effect/projectile/stun/tracer + icon_state = "stun" + +/obj/effect/projectile/stun/muzzle + icon_state = "muzzle_stun" + +/obj/effect/projectile/stun/impact + icon_state = "impact_stun" + +//---------------------------- +// Bullet +//---------------------------- +/obj/effect/projectile/bullet/muzzle + icon = 'icons/effects/projectiles/muzzle.dmi' + icon_state = "muzzle_bullet" + light_range = 5 + light_power = 1 + light_color = COLOR_MUZZLE_FLASH \ No newline at end of file diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm new file mode 100644 index 00000000..ccbaf892 --- /dev/null +++ b/code/modules/projectiles/gun.dm @@ -0,0 +1,737 @@ +#define GUN_AUTOMATIC "auto_rifle" +#define GUN_SEMIAUTO "semi_rifle" +#define GUN_SNIPER "sniper" +#define GUN_SHOTGUN "shotgun" +#define GUN_LMG "lmg" +#define GUN_SMG "smg" +#define GUN_PISTOL "pistol" + +/* + Defines a firing mode for a gun. + + A firemode is created from a list of fire mode settings. Each setting modifies the value of the gun var with the same name. + If the fire mode value for a setting is null, it will be replaced with the initial value of that gun's variable when the firemode is created. + Obviously not compatible with variables that take a null value. If a setting is not present, then the corresponding var will not be modified. +*/ +/datum/firemode + var/name = "default" + var/list/settings = list() + +/datum/firemode/New(obj/item/weapon/gun/gun, list/properties = null) + ..() + if(!properties) return + + for(var/propname in properties) + var/propvalue = properties[propname] + + if(propname == "mode_name") + name = propvalue + else if(isnull(propvalue)) + settings[propname] = gun.vars[propname] //better than initial() as it handles list vars like burst_accuracy + else + settings[propname] = propvalue + +/datum/firemode/proc/apply_to(obj/item/weapon/gun/gun) + for(var/propname in settings) + gun.vars[propname] = settings[propname] + +//Parent gun type. Guns are weapons that can be aimed at mobs and act over a distance +/obj/item/weapon/gun + name = "gun" + desc = "Its a gun. It's pretty terrible, though." + icon = 'icons/obj/gun.dmi' + item_icons = list( + slot_l_hand_str = 'icons/mob/onmob/items/lefthand_guns.dmi', + slot_r_hand_str = 'icons/mob/onmob/items/righthand_guns.dmi', + ) + icon_state = "detective" + item_state = "gun" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + matter = list(DEFAULT_WALL_MATERIAL = 2000) + w_class = ITEM_SIZE_NORMAL + throwforce = 5 + throw_speed = 4 + throw_range = 5 + force = 5 + origin_tech = list(TECH_COMBAT = 1) + attack_verb = list("struck", "hit", "bashed") + zoomdevicename = "scope" + grab_sound_is_loud = TRUE + grab_sound = "gun_pickup"//'sound/items/unholster.ogg' + equipsound = 'sound/items/equip/gun_equip.ogg' + drop_sound = 'sound/items/handle/gun_drop.ogg' + + var/burst = 1 + var/fire_delay = 6 //delay after shooting before the gun can be used again + var/burst_delay = 2 //delay between shots, if firing in bursts + var/automatic = 0 //can gun use it, 0 is no, anything above 0 is the delay between clicks in ds + var/move_delay = 1 + var/fire_sound = null//'sound/weapons/gunshot/gunshot.ogg' //No fire sound by default so we use the bullet's fire sound. + var/fire_sound_text = "gunshot" + var/far_fire_sound = null + var/fire_anim = null + var/screen_shake = 0 //shouldn't be greater than 2 unless zoomed + var/silenced = 0 + var/accuracy = 0 //accuracy is measured in tiles. +1 accuracy means that everything is effectively one tile closer for the purpose of miss chance, -1 means the opposite. launchers are not supported, at the moment. + var/scoped_accuracy = null + var/list/burst_accuracy = list(0) //allows for different accuracies for each shot in a burst. Applied on top of accuracy + var/list/dispersion = list(0) + var/one_hand_penalty + var/wielded_item_state + var/combustion //whether it creates hotspot when fired + var/is_jammed = FALSE //Whether this gun is jammed + var/condition = 100 + var/safety = TRUE //Whether or not the safety is on. + var/broken = FALSE //weapon broken or no + var/jammed_icon + var/gun_type = "generic" + + var/next_fire_time = 0 + + var/sel_mode = 1 //index of the currently selected mode + var/list/firemodes = list() + + //aiming system stuff + var/keep_aim = 1 //1 for keep shooting until aim is lowered + //0 for one bullet after tarrget moves and aim is lowered + var/multi_aim = 0 //Used to determine if you can target multiple people. + var/tmp/list/mob/living/aim_targets //List of who yer targeting. + var/tmp/mob/living/last_moved_mob //Used to fire faster at more than one person. + var/tmp/told_cant_shoot = 0 //So that it doesn't spam them with the fact they cannot hit them. + var/tmp/lock_time = -100 + var/can_jam = TRUE + + //attachment shit + var/damage_modifier = 0 + + var/list/attachable_overlays = list("muzzle", "rail", "under", "stock", "mag") //List of overlays so we can switch them in an out, instead of using Cut() on overlays. + var/list/attachable_offset = null //Is a list, see examples of from the other files. Initiated on New() because lists don't initial() properly. + var/list/attachable_allowed = null //Must be the exact path to the attachment present in the list. Empty list for a default. + var/obj/item/attachable/muzzle = null //Attachable slots. Only one item per slot. + var/obj/item/attachable/rail = null + var/obj/item/attachable/under = null + var/obj/item/attachable/stock = null + + +/obj/item/weapon/gun/New() + ..() + for(var/i in 1 to firemodes.len) + firemodes[i] = new /datum/firemode(src, firemodes[i]) + + if(isnull(scoped_accuracy)) + scoped_accuracy = accuracy + +/obj/item/weapon/gun/update_icon() + if(wielded_item_state) + var/mob/living/M = loc + if(istype(M)) + if(wielded) + item_state_slots[slot_l_hand_str] = wielded_item_state + item_state_slots[slot_r_hand_str] = wielded_item_state + else + item_state_slots[slot_l_hand_str] = initial(item_state) + item_state_slots[slot_r_hand_str] = initial(item_state) + if(is_jammed) + if(jammed_icon) + icon_state = jammed_icon + +//Checks whether a given mob can use the gun +//Any checks that shouldn't result in handle_click_empty() being called if they fail should go here. +//Otherwise, if you want handle_click_empty() to be called, check in consume_next_projectile() and return null there. +/obj/item/weapon/gun/proc/special_check(var/mob/user) + + if(!istype(user, /mob/living)) + return 0 + if(!user.IsAdvancedToolUser()) + return 0 + + var/mob/living/M = user + if(HULK in M.mutations) + to_chat(M, "Your fingers are much too large for the trigger guard!") + return 0 + if((CLUMSY in M.mutations) && prob(40)) //Clumsy handling + var/obj/P = consume_next_projectile() + if(P) + if(process_projectile(P, user, user, pick(BP_L_FOOT, BP_R_FOOT))) + handle_post_fire(user, user) + user.visible_message( + "\The [user] shoots \himself in the foot with \the [src]!", + "You shoot yourself in the foot with \the [src]!" + ) + M.drop_item() + else + handle_click_empty(user) + return 0 + if(safety) + to_chat(user, "The gun's safety is on!") + handle_click_empty(user) + return 0 + + if(broken) + to_chat(user, "The gun is broken!") + handle_click_empty(user) + return 0 + + if(is_jammed) + handle_click_empty(user) + return 0 + + return 1 + +/obj/item/weapon/gun/emp_act(severity) + for(var/obj/O in contents) + O.emp_act(severity) + +/obj/item/weapon/gun/afterattack(atom/A, mob/living/user, adjacent, params) + if(adjacent) return //A is adjacent, is the user, or is on the user's person + + if(!user.aiming) + user.aiming = new(user) + + if(user && user.client && user.aiming && user.aiming.active && user.aiming.aiming_at != A) + PreFire(A,user,params) //They're using the new gun system, locate what they're aiming at. + return + else + Fire(A,user,params) //Otherwise, fire normally. + +/obj/item/weapon/gun/proc/can_shoot() //This is just an abstract check to stop us from attempting to shoot an empty gun instead of doing a melee attack. + return TRUE + +/obj/item/weapon/gun/attack(atom/A, mob/living/user, def_zone) + if (A == user && user.zone_sel.selecting == BP_MOUTH && !mouthshoot) + handle_suicide(user) + else if(user.a_intent == I_HURT && can_shoot()) //point blank shooting + Fire(A, user, pointblank=1) + else + return ..() //Pistolwhippin' + +/obj/item/weapon/gun/proc/Fire(atom/target, mob/living/user, clickparams, pointblank=0, reflex=0) + if(!user || !target) return + + + if(ticker.current_state == GAME_STATE_FINISHED) + to_chat(user, "The battle is over! There is no need to shoot!") + return + + add_fingerprint(user) + + if(!special_check(user)) + return + + if(world.time < next_fire_time) + if (world.time % 3) //to prevent spam + to_chat(user, "[src] is not ready to fire again!") + return + + var/shoot_time = (burst - 1)* burst_delay + user.setClickCooldown(shoot_time) //no clicking on things while shooting + user.setMoveCooldown(shoot_time) //no moving while shooting either + next_fire_time = world.time + shoot_time + + var/held_twohanded = wielded + + //actually attempt to shoot + var/turf/targloc = get_turf(target) //cache this in case target gets deleted during shooting, e.g. if it was a securitron that got destroyed. + for(var/i in 1 to burst) + var/obj/projectile = consume_next_projectile(user) + if(!projectile) + handle_click_empty(user) + break + + process_accuracy(projectile, user, target, i, held_twohanded) + + if(pointblank) + process_point_blank(projectile, user, target) + + if(process_projectile(projectile, user, target, user.zone_sel.selecting, clickparams)) + handle_post_fire(user, target, pointblank, reflex) + update_icon() + + if(istype(src, /obj/item/weapon/gun/projectile)) + var/obj/item/weapon/gun/projectile/P = src + if(P.can_jam) + P.condition -= 1 + + if(i < burst) + sleep(burst_delay) + + if(!(target && target.loc)) + target = targloc + pointblank = 0 + + //update timing + if(!automatic) + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + user.recoil += 0.5 //So you can click pretty quick for a bit before it starts getting innacurate. + if(automatic) + user.setClickCooldown(automatic) + user.recoil += 0.01 + user.setMoveCooldown(move_delay) + next_fire_time = world.time + fire_delay + update_icon() + +//obtains the next projectile to fire +/obj/item/weapon/gun/proc/consume_next_projectile() + return null + +//used by aiming code +/obj/item/weapon/gun/proc/can_hit(atom/target as mob, var/mob/living/user as mob) + if(!special_check(user)) + return 2 + //just assume we can shoot through glass and stuff. No big deal, the player can just choose to not target someone + //on the other side of a window if it makes a difference. Or if they run behind a window, too bad. + return check_trajectory(target, user) + +//called if there was no projectile to shoot +/obj/item/weapon/gun/proc/handle_click_empty(mob/user) + if(is_jammed) + if(user) + user.visible_message("*jam jam*", "*jam*") + else + src.visible_message("*jam jam*") + playsound(src.loc, 'sound/effects/jam.ogg', 50, 1) + else + if(user) + user.visible_message("*click click*", "*click*") + else + src.visible_message("*click click*") + playsound(src.loc, 'sound/weapons/empty.ogg', 100, 1) + +//called after successfully firing +/obj/item/weapon/gun/proc/handle_post_fire(mob/user, atom/target, var/pointblank=0, var/reflex=0) + if(fire_anim) + flick(fire_anim, src) + + if(!silenced) + if(reflex) + user.visible_message( + "\The [user] fires \the [src][pointblank ? " point blank at \the [target]":""] by reflex!", + "You fire \the [src] by reflex!", + "You hear a [fire_sound_text]!" + ) + /* + else + user.visible_message( + "\The [user] fires \the [src][pointblank ? " point blank at \the [target]":""]!", + "You fire \the [src]!", + "You hear a [fire_sound_text]!" + ) + */ + + if(one_hand_penalty) + if(!wielded && (user.my_stats[STAT(dex)].level <= 15)) + switch(one_hand_penalty) + if(1) + if(prob(50)) //don't need to tell them every single time + to_chat(user, "Your aim wavers slightly.") + if(2) + to_chat(user, "Your aim wavers as you fire \the [src] with just one hand.") + if(3) + to_chat(user, "You have trouble keeping \the [src] on target with just one hand.") + if(4 to INFINITY) + to_chat(user, "You struggle to keep \the [src] on target with just one hand!") + + if(screen_shake) + spawn() + shake_camera(user, screen_shake+1, screen_shake) + + if(combustion) + var/turf/curloc = get_turf(src) + curloc.hotspot_expose(700, 5) + + update_icon() + + +/obj/item/weapon/gun/proc/process_point_blank(obj/projectile, mob/user, atom/target) + var/obj/item/projectile/P = projectile + if(!istype(P)) + return //default behaviour only applies to true projectiles + + //default point blank multiplier + var/max_mult = 1.3 + + //determine multiplier due to the target being grabbed + if(ishuman(target)) + var/mob/living/carbon/human/H = target + for(var/obj/item/grab/G in H.grabbed_by) + if(G.point_blank_mult() > max_mult) + max_mult = G.point_blank_mult() + P.damage *= max_mult + +/obj/item/weapon/gun/proc/process_accuracy(obj/projectile, mob/living/carbon/human/user, atom/target, var/burst, var/held_twohanded) + var/obj/item/projectile/P = projectile + if(!istype(P)) + return //default behaviour only applies to true projectiles + + var/acc_mod = burst_accuracy[min(burst, burst_accuracy.len)] + var/disp_mod = dispersion[min(burst, dispersion.len)] + + if(one_hand_penalty) + if(!held_twohanded && (user.my_stats[STAT(dex)].level < 16)) + acc_mod -= ceil(one_hand_penalty) + disp_mod += one_hand_penalty*0.5 //dispersion per point of two-handedness + + //Accuracy modifiers + P.accuracy = accuracy + acc_mod + dexToAccuracyModifier(user.my_stats[STAT(dex)].level) + P.dispersion = disp_mod + (user.recoil / 2)//Recoil gets added when you shoot. The faster we shoot our semi-auto gun the less accurate it is. + if(user.crouching || user.lying)//Blind firing out of the trench. + if(istype(user.loc, /turf/simulated/floor/trench)) + P.dispersion += 10 + P.accuracy -= 5 + + /* AIMING IS NOT A THING ANYMORE, BUT IN CASE IT COMES BACK I'M LEAVING THIS HERE + //accuracy bonus from aiming + if (aim_targets && (target in aim_targets)) + //If you aim at someone beforehead, it'll hit more often. + //Kinda balanced by fact you need like 2 seconds to aim + //As opposed to no-delay pew pew + P.accuracy += 2 + */ + + //Dispersion stuff. I'll put it in its own proc soon enough. + var/mod = rand(5,20) + var/wrong_gun_class_mod = mod + (mod * 0.5)//A lot. + switch(gun_type) + if(GUN_AUTOMATIC) + if(user.SKILL_LEVEL(auto_rifle) < 6) //Less than over half, make them do a statcheck. + if(user.statscheck(skills = user.SKILL_LEVEL(auto_rifle) <= FAILURE)) + P.dispersion += wrong_gun_class_mod + + if(GUN_SEMIAUTO) + if(user.SKILL_LEVEL(semi_rifle) < 6) //Less than over half, make them do a statcheck. + if(user.statscheck(skills = user.SKILL_LEVEL(semi_rifle) <= FAILURE)) + P.dispersion += wrong_gun_class_mod + + if(GUN_SNIPER) + if(user.SKILL_LEVEL(sniper) < 6) //Less than over half, make them do a statcheck. + if(user.statscheck(skills = user.SKILL_LEVEL(sniper) <= FAILURE)) + P.dispersion += wrong_gun_class_mod + + if( GUN_SHOTGUN) + if(user.SKILL_LEVEL(shotgun) < 6) //Less than over half, make them do a statcheck. + if(user.statscheck(skills = user.SKILL_LEVEL(shotgun) <= FAILURE)) + P.dispersion += wrong_gun_class_mod + + if(GUN_LMG) + if(user.SKILL_LEVEL(lmg) < 6) //Less than over half, make them do a statcheck. + if(user.statscheck(skills = user.SKILL_LEVEL(lmg) <= FAILURE)) + P.dispersion += wrong_gun_class_mod + + if(GUN_SMG) + if(user.SKILL_LEVEL(smg) < 6) //Less than over half, make them do a statcheck. + if(user.statscheck(skills = user.SKILL_LEVEL(smg) <= FAILURE)) + P.dispersion += wrong_gun_class_mod + + if(user.chem_effects[CE_PAINKILLER] > 100) + P.dispersion += 10 + P.accuracy -= 3 + + if(user.horror_loop)//They're freaking the fuck out, make it hard to aim. + P.dispersion += 5 + P.accuracy -= 3 + + if(user.combat_mode) + P.accuracy += 3 + + if(!user.combat_mode) + P.dispersion += mod + + if(user.staminaloss >= (user.staminaexhaust/2)) + P.dispersion += mod + + user.dispersion_mouse_display_number = P.dispersion + //to_chat(world, "[P.dispersion]") //Debug. + if(user.dispersion_mouse_display_number > 0 && user.dispersion_mouse_display_number < 2)// else + user.client.mouse_pointer_icon = 'icons/effects/standard/standard2.dmi'//'icons/misc/aim.dmi' + else if(user.dispersion_mouse_display_number >= 2 && user.dispersion_mouse_display_number < 4) + user.client.mouse_pointer_icon = 'icons/effects/standard/standard3.dmi' + else if(user.dispersion_mouse_display_number >= 4 && user.dispersion_mouse_display_number < 6) + user.client.mouse_pointer_icon = 'icons/effects/standard/standard4.dmi' + else if(user.dispersion_mouse_display_number >= 6 && user.dispersion_mouse_display_number < 10) + user.client.mouse_pointer_icon = 'icons/effects/standard/standard5.dmi' + else if(user.dispersion_mouse_display_number >= 10) + user.client.mouse_pointer_icon = 'icons/effects/standard/standard6.dmi' + else + user.client.mouse_pointer_icon = 'icons/effects/standard/standard1.dmi' + + + + + +//does the actual launching of the projectile +/obj/item/weapon/gun/proc/process_projectile(obj/projectile, mob/user, atom/target, target_zone, params) + var/obj/item/projectile/P = projectile + if(!istype(P)) + return 0 //default behaviour only applies to true projectiles + + var/launched = !P.launch_from_gun(target, target_zone, user, params, null, 0, src) + + if(launched) + play_fire_sound(user,P) + + return launched + +/obj/item/weapon/gun/proc/unjam(var/mob/M) + if(is_jammed) + M.visible_message("\The [M] begins to unjam [src].", "You begin to clear the jam of [src]") + if(!do_after(M, 20, src)) + return + is_jammed = 0 + playsound(src.loc, 'sound/weapons/unjam.ogg', 50, 1) + update_icon() + return + + +/obj/item/weapon/gun/proc/play_fire_sound(var/mob/user, var/obj/item/projectile/P) + var/shot_sound + if(fire_sound)//Check if the gun has a fire sound first, then if it doesn't use the bullet's fire_sound. + shot_sound = fire_sound + else if(P.fire_sound) + shot_sound = P.fire_sound + if(silenced) + playsound(user, shot_sound, 10, 1) + else//If the mobs are far away, then play the far away shot sound instead. + playsound(user, shot_sound, 50, 1) + var/list/mob/mobs = view(world.view, user) + var/list/mob/far_mobs = (orange(world.view * 3, user) - mobs) + for(var/mob/living/carbon/human/M in far_mobs) + M.playsound_local(user, far_fire_sound, rand(1, 10)) + +//Suicide handling. +/obj/item/weapon/gun/var/mouthshoot = 0 //To stop people from suiciding twice... >.> +/obj/item/weapon/gun/proc/handle_suicide(mob/living/user) + if(!ishuman(user)) + return + var/mob/living/carbon/human/M = user + + mouthshoot = 1 + M.visible_message("[user] sticks their gun in their mouth, ready to pull the trigger...") + if(!do_after(user, 40, progress=0)) + M.visible_message("[user] decided life was worth living") + mouthshoot = 0 + return + var/obj/item/projectile/in_chamber = consume_next_projectile() + if (istype(in_chamber)) + user.visible_message("[user] pulls the trigger.") + var/shot_sound = in_chamber.fire_sound? in_chamber.fire_sound : fire_sound + if(silenced) + playsound(user, shot_sound, 10, 1) + else + playsound(user, shot_sound, 50, 1) + if(istype(in_chamber, /obj/item/projectile/beam/lastertag)) + user.show_message("You feel rather silly, trying to commit suicide with a toy.") + mouthshoot = 0 + return + + in_chamber.on_hit(M) + if (in_chamber.damage_type != PAIN) + log_and_message_admins("[key_name(user)] commited suicide using \a [src]") + user.unlock_achievement(new/datum/achievement/suicide()) + user.apply_damage(in_chamber.damage*2.5, in_chamber.damage_type, BP_HEAD, 0, in_chamber.damage_flags(), used_weapon = "Point blank shot in the mouth with \a [in_chamber]") + user.death() + + else + to_chat(user, "Ow...") + user.apply_effect(110,PAIN,0) + qdel(in_chamber) + mouthshoot = 0 + return + else + handle_click_empty(user) + mouthshoot = 0 + return + +/obj/item/weapon/gun/proc/toggle_scope(mob/user, var/zoom_amount=2.0) + //looking through a scope limits your periphereal vision + //still, increase the view size by a tiny amount so that sniping isn't too restricted to NSEW + var/zoom_offset = round(world.view * zoom_amount) + var/view_size = round(world.view + zoom_amount) + var/scoped_accuracy_mod = zoom_offset + + zoom(user, zoom_offset, view_size) + if(zoom) + accuracy = scoped_accuracy + scoped_accuracy_mod + if(screen_shake) + screen_shake = round(screen_shake*zoom_amount+1) //screen shake is worse when looking through a scope + +//make sure accuracy and screen_shake are reset regardless of how the item is unzoomed. +/obj/item/weapon/gun/zoom() + ..() + if(!zoom) + accuracy = initial(accuracy) + screen_shake = initial(screen_shake) + +/obj/item/weapon/gun/examine(mob/user) + . = ..() + if(firemodes.len > 1) + var/datum/firemode/current_mode = firemodes[sel_mode] + to_chat(user, "The fire selector is set to [current_mode.name].") + if(safety) + to_chat(user, "The safety is on.") + else + to_chat(user, "The safety is off.") + + +/obj/item/weapon/gun/proc/switch_firemodes() + if(firemodes.len <= 1) + return null + + sel_mode++ + if(sel_mode > firemodes.len) + sel_mode = 1 + var/datum/firemode/new_mode = firemodes[sel_mode] + new_mode.apply_to(src) + + return new_mode + +/obj/item/weapon/gun/attack_self(mob/user) + var/datum/firemode/new_mode = switch_firemodes(user) + if(new_mode) + playsound(src.loc, 'sound/weapons/guns/interact/selector.ogg', 50, 1) + to_chat(user, "\The [src] is now set to [new_mode.name].") + +//Gun safety +/obj/item/weapon/gun/RightClick(mob/user) + toggle_safety(user) + +/obj/item/weapon/gun/proc/toggle_safety(mob/user) + if(user.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_KNOCKOUT)) + return + if(src != user.get_active_hand()) + return + + if(is_jammed) + unjam(user) + else + safety = !safety + playsound(user, 'sound/items/safety.ogg', 50, 1) + to_chat(user, "You toggle the safety [safety ? "on":"off"].") + +/obj/item/weapon/gun/AltClick(mob/user) + if(user.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_KNOCKOUT)) + return + if(src != user.get_active_hand()) + return + if(!ishuman(user)) + return + var/allowed_condition = 60//Non smart engeery people can only repair their weapon up to 60% + var/repair_speed = 50 + var/mob/living/carbon/human/H = user + if(H.SKILL_LEVEL(engineering) >= 6)//If you're a smart engineery boi u can repair da wepon all da wey + allowed_condition = 90 + repair_speed = 20 + if(condition <= allowed_condition) + if(!H.doing_something)//No spamming repairs + H.visible_message("[H] starts to repair their weapon.") + H.doing_something = TRUE + if(do_after(H, repair_speed, src))//Instead of failing if their not skilled, just make it slow. + H.doing_something = FALSE + condition += 10 + H.visible_message("[H] successfully repairs their weapon.") + if(condition > 100)//If it's greater than 100 + condition = 100 + else + H.visible_message("[H] fails to repair their weapon.") + H.doing_something = FALSE + update_icon() + + + +/obj/item/weapon/gun/proc/check_gun_safety(mob/user)//Used in inventory.dm to see whether or not you fucking shoot someone when you drop your gun on the ground. + if(!safety && prob(10)) + user.visible_message("[src] goes off!") + var/list/targets = list(user) + targets += trange(2, src) + afterattack(pick(targets), user) + + + +/////////////////////////// +/////AUTOMATIC CLICKS////// +/////ONLY USED FOR GUNS//// +/////////////////////////// + +/mob + var/dispersion_mouse_display_number = 0 + var/recoil = 0 + + +/client + var/list/selected_target[2] + +/client/MouseDown(object, location, control, params) + var/delay = mob.CanMobAutoclick(object, location, params) + if(delay) + selected_target[1] = object + selected_target[2] = params + while(selected_target[1]) + usr.recoil += 1 + Click(selected_target[1], location, control, selected_target[2]) + sleep(delay) + usr.dispersion_mouse_display_number = 0 + usr.recoil = 0 + +/client/MouseUp(object, location, control, params) + selected_target[1] = null + + +/client/MouseDrag(src_object,atom/over_object,src_location,over_location,src_control,over_control,params) + if(selected_target[1] && over_object.IsAutoclickable()) + selected_target[1] = over_object + selected_target[2] = params + +/mob/proc/CanMobAutoclick(object, location, params) + return + +/mob/living/carbon/CanMobAutoclick(atom/object, location, params) + if(!object.IsAutoclickable()) + return + var/obj/item/h = get_active_hand() + if(h) + . = h.CanItemAutoclick(object, location, params) + +/obj/item/proc/CanItemAutoclick(object, location, params) + return + +/obj/item/weapon/gun/CanItemAutoclick(object, location, params) + . = automatic + +/atom/proc/IsAutoclickable() + . = 1 + +/obj/screen/IsAutoclickable() + . = 0 + +//A cool pointer for your gun. +/obj/item/weapon/gun/pickup(mob/user) + if(user.client) + user.client.mouse_pointer_icon = 'icons/effects/standard/standard1.dmi' + // user.update_aim_icon() + // user.client.mouse_pointer_icon = 'icons/misc/aim.dmi' + update_icon() + ..() +/obj/item/weapon/gun/dropped(mob/user) + ..() + if(user.client) + user.client.mouse_pointer_icon = null + update_icon() + +/obj/item/weapon/gun/equipped(mob/user) + ..() + if(user.client) + user.client.mouse_pointer_icon = null + update_icon() + + +/obj/item/weapon/gun/proc/add_bayonet() + var/image/I = image('icons/obj/gun.dmi', "bayonett") + I.pixel_x += 5 + src.overlays += I + + +/obj/item/weapon/gun/proc/unload_ammo(mob/user, var/allow_dump=1) + return + +/obj/item/weapon/gun/proc/load_ammo(var/obj/item/A, mob/user) + return \ No newline at end of file diff --git a/code/modules/projectiles/gun_attachments.dm b/code/modules/projectiles/gun_attachments.dm new file mode 100644 index 00000000..8e573218 --- /dev/null +++ b/code/modules/projectiles/gun_attachments.dm @@ -0,0 +1,215 @@ +//Gun attachable related flags. +//flags_attach_features +#define ATTACH_REMOVABLE (1<<0) +#define ATTACH_ACTIVATION (1<<1) +#define ATTACH_PROJECTILE (1<<2) //for attachments that fire bullets +#define ATTACH_RELOADABLE (1<<3) +#define ATTACH_WEAPON (1<<4) //is a weapon that fires stuff +#define ATTACH_UTILITY (1<<5) //for attachments with utility that trigger by 'shooting' + + +/obj/item/attachable + name = "attachable item" + desc = "It's an attachment. You should never see this." + icon = 'icons/obj/items/attachments.dmi' + icon_state = null + item_state = null + var/attach_icon //the sprite to show when the attachment is attached when we want it different from the icon_state. + var/pixel_shift_x = 16 //Determines the amount of pixels to move the icon state for the overlay. + var/pixel_shift_y = 16 //Uses the bottom left corner of the item. + + w_class = WEIGHT_CLASS_SMALL + force = 0 //Don't try killing people with attachments please. + var/slot = null //"muzzle", "rail", "under", "stock" + + /* + Anything that isn't used as the gun fires should be a flat number, never a percentange. It screws with the calculations, + and can mean that the order you attach something/detach something will matter in the final number. It's also completely + inaccurate. Don't worry if force is ever negative, it won't runtime. + */ + //These bonuses are applied only as the gun fires a projectile. + + //These are flat bonuses applied and are passive, though they may be applied at different points. + var/accuracy_mod = 0 //Modifier to firing accuracy, works off a multiplier. + var/accuracy_unwielded_mod = 0 //same as above but for onehanded. + var/damage_mod = 0 //Modifer to the damage mult, works off a multiplier. + var/melee_mod = 0 //Changing to a flat number so this actually doesn't screw up the calculations. + var/recoil_mod = 0 //If positive, adds recoil, if negative, lowers it. Recoil can't go below 0. + var/recoil_unwielded_mod = 0 //same as above but for onehanded firing. + var/delay_mod = 0 //Changes firing delay. Cannot go below 0. + var/burst_delay_mod = 0 //Changes burst firing delay. Cannot go below 0. + var/burst_mod = 0 //Changes burst rate. 1 == 0. + var/size_mod = 0 //Increases the weight class. + var/attach_delay = 30 //How long in deciseconds it takes to attach a weapon with level 1 firearms training. Default is 30 seconds. + var/detach_delay = 30 //How long in deciseconds it takes to detach a weapon with level 1 firearms training. Default is 30 seconds. + var/fire_delay_mod = 0 //how long in deciseconds this adds to your base fire delay. + + var/attachment_firing_delay = 0 //the delay between shots, for attachments that fires stuff + + var/activation_sound = 'sound/machines/click.ogg' + + var/flags_attach_features = ATTACH_REMOVABLE + + var/attachment_action_type + var/scope_zoom_mod = FALSE //codex + + var/ammo_mod = null //what ammo the gun could also fire, different lasers usually. + var/charge_mod = 0 //how much charge difference it now costs to shoot. negative means more shots per mag. + var/gun_firemode_list_mod = null //what firemodes this attachment allows/adds. + + var/obj/item/weapon/gun/master_gun + + + + +/obj/item/attachable/proc/Attach(obj/item/weapon/gun/gun_to_attach, mob/user) + if(!istype(gun_to_attach)) + return //Guns only + master_gun = gun_to_attach + /* + This does not check if the attachment can be removed. + Instead of checking individual attachments, I simply removed + the specific guns for the specific attachments so you can't + attempt the process in the first place if a slot can't be + removed on a gun. can_be_removed is instead used when they + try to strip the gun. + */ + switch(slot) + if("rail") + master_gun.rail?.Detach(user) + master_gun.rail = src + if("muzzle") + master_gun.muzzle?.Detach(user) + master_gun.muzzle = src + if("under") + master_gun.under?.Detach(user) + master_gun.under = src + if("stock") + master_gun.stock?.Detach(user) + master_gun.stock = src + + if(ishuman(user)) + var/mob/living/carbon/human/wielder = user + wielder.drop_item(src) + + forceMove(master_gun) + + master_gun.damage_modifier += damage_mod + + master_gun.force += melee_mod + + master_gun.update_attachable(slot) + + + +/obj/item/attachable/proc/Detach(mob/user) + + switch(slot) + if("rail") + master_gun.rail = null + if("muzzle") + master_gun.muzzle = null + if("under") + master_gun.under = null + if("stock") + master_gun.stock = null + + master_gun.damage_modifier -= damage_mod + + master_gun.force -= melee_mod + + master_gun.update_force_list() + + forceMove(get_turf(master_gun)) + + master_gun = null + + master_gun.update_attachables() + + + +/obj/item/weapon/gun/proc/update_attachables() //Updates everything. You generally don't need to use this. + //overlays.Cut() + if(attachable_offset) //Even if the attachment doesn't exist, we're going to try and remove it. + update_overlays(muzzle, "muzzle") + update_overlays(stock, "stock") + update_overlays(under, "under") + update_overlays(rail, "rail") + + +/obj/item/weapon/gun/proc/update_attachable(attachable) //Updates individually. + if(attachable_offset) + switch(attachable) + if("muzzle") update_overlays(muzzle, attachable) + if("stock") update_overlays(stock, attachable) + if("under") update_overlays(under, attachable) + if("rail") update_overlays(rail, attachable) + + +/obj/item/weapon/gun/update_overlays(obj/item/attachable/A, slot) + . = ..() + var/image/I = attachable_overlays[slot] + overlays -= I + qdel(I) + if(A) //Only updates if the attachment exists for that slot. + var/item_icon = A.icon_state + if(A.attach_icon) + item_icon = A.attach_icon + I = image(A.icon,src, item_icon) + I.pixel_x = attachable_offset["[slot]_x"] - A.pixel_shift_x + I.pixel_y = attachable_offset["[slot]_y"] - A.pixel_shift_y + attachable_overlays[slot] = I + overlays += I + else + attachable_overlays[slot] = null + + + +/obj/item/attachable/bayonet + name = "bayonet" + desc = "A sharp blade for mounting on a weapon. It can be used to stab manually on anything but harm intent." + icon_state = "bayonet" + attach_icon = "bayonet_a" + force = 20 + throwforce = 10 + attach_delay = 10 //Bayonets attach/detach quickly. + detach_delay = 10 + attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + melee_mod = 15 + slot = "muzzle" + pixel_shift_x = 14 //Below the muzzle. + pixel_shift_y = 18 + accuracy_mod = -0.05 + accuracy_unwielded_mod = -0.1 + size_mod = 1 + + +/obj/item/attachable/verticalgrip + name = "vertical grip" + desc = "A custom-built improved foregrip for better accuracy, less recoil, and less scatter when wielded especially during burst fire. \nHowever, it also increases weapon size, slightly increases wield delay and makes unwielded fire more cumbersome." + icon_state = "verticalgrip" + attach_icon = "verticalgrip_a" + wield_delay_mod = 0.2 SECONDS + size_mod = 1 + slot = "under" + pixel_shift_x = 20 + accuracy_mod = 0.1 + recoil_mod = -2 + scatter_mod = -10 + burst_scatter_mod = -1 + accuracy_unwielded_mod = -0.05 + scatter_unwielded_mod = 5 + + +/obj/item/attachable/angledgrip + name = "angled grip" + desc = "A custom-built improved foregrip for less recoil, and faster wielding time. \nHowever, it also increases weapon size, and slightly hinders unwielded firing." + icon_state = "angledgrip" + attach_icon = "angledgrip_a" + wield_delay_mod = -0.3 SECONDS + size_mod = 1 + slot = "under" + pixel_shift_x = 20 + recoil_mod = -1 + accuracy_unwielded_mod = -0.1 + scatter_unwielded_mod = 5 \ No newline at end of file diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm new file mode 100644 index 00000000..bdb18eca --- /dev/null +++ b/code/modules/projectiles/guns/energy.dm @@ -0,0 +1,149 @@ +/obj/item/weapon/gun/energy + name = "energy gun" + desc = "A basic energy-based gun." + icon_state = "energy" + fire_sound = 'sound/weapons/Taser.ogg' + fire_sound_text = "laser blast" + + var/obj/item/weapon/cell/power_supply //What type of power cell this uses + var/charge_cost = 20 //How much energy is needed to fire. + var/max_shots = 10 //Determines the capacity of the weapon's power cell. Specifying a cell_type overrides this value. + var/cell_type = null + var/projectile_type = /obj/item/projectile/energy/laser // /obj/item/projectile/beam/practice + var/modifystate + var/charge_meter = 1 //if set, the icon state will be chosen based on the current charge + + //self-recharging + var/self_recharge = 0 //if set, the weapon will recharge itself + var/use_external_power = 0 //if set, the weapon will look for an external power source to draw from, otherwise it recharges magically + var/recharge_time = 4 + var/charge_tick = 0 + var/icon_rounder = 25 + combustion = 1 + +/obj/item/weapon/gun/energy/switch_firemodes() + . = ..() + if(.) + update_icon() + +/obj/item/weapon/gun/energy/emp_act(severity) + ..() + update_icon() + +/obj/item/weapon/gun/energy/New() + ..() + if(cell_type) + power_supply = new cell_type(src) + else + power_supply = new /obj/item/weapon/cell/device/variable(src, max_shots*charge_cost) + if(self_recharge) + START_PROCESSING(SSobj, src) + update_icon() + +/obj/item/weapon/gun/energy/Destroy() + if(self_recharge) + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/weapon/gun/energy/Process() + if(self_recharge) //Every [recharge_time] ticks, recharge a shot for the cyborg + charge_tick++ + if(charge_tick < recharge_time) return 0 + charge_tick = 0 + + if(!power_supply || power_supply.charge >= power_supply.maxcharge) + return 0 // check if we actually need to recharge + + if(use_external_power) + var/obj/item/weapon/cell/external = get_external_power_supply() + if(!external || !external.use(charge_cost)) //Take power from the borg... + return 0 + + power_supply.give(charge_cost) //... to recharge the shot + update_icon() + return 1 + +/obj/item/weapon/gun/energy/consume_next_projectile() + if(!power_supply) return null + if(!ispath(projectile_type)) return null + if(!power_supply.checked_use(charge_cost)) return null + return new projectile_type(src) + +/obj/item/weapon/gun/energy/proc/get_external_power_supply() + if(isrobot(src.loc)) + var/mob/living/silicon/robot/R = src.loc + return R.cell + return null + +/obj/item/weapon/gun/energy/examine(mob/user) + . = ..(user) + var/shots_remaining = 0 + if(power_supply) + shots_remaining = round(power_supply.charge / charge_cost) + to_chat(user, "Has [shots_remaining] shot\s remaining.") + return + +/obj/item/weapon/gun/energy/update_icon() + ..() + if(charge_meter) + var/ratio = 0 + if(power_supply) + ratio = power_supply.percent() + + //make sure that rounding down will not give us the empty state even if we have charge for a shot left. + if(power_supply.charge < charge_cost) + ratio = 0 + else + ratio = max(round(ratio, icon_rounder), icon_rounder) + + if(modifystate) + icon_state = "[modifystate][ratio]" + else + icon_state = "[initial(icon_state)][ratio]" + + + + +/obj/item/weapon/gun/energy/attackby(var/obj/item/A as obj, mob/user as mob) + load_ammo(A, user) + +/obj/item/weapon/gun/energy/load_ammo(var/obj/item/A, mob/user) + if(!istype(A, /obj/item/weapon/cell)) + return + + if(power_supply) + to_chat(user, "[src] already has a power cell loaded.")//already a power cell here + return + + user.remove_from_mob(A) + A.loc = src + power_supply = A + user.visible_message("[user] inserts [A] into [src].", "You insert [A] into [src].") + playsound(src, 'sound/weapons/guns/interact/mag_load.ogg', 100) + update_icon() + + +/obj/item/weapon/gun/energy/unload_ammo(mob/user, var/allow_dump=1) + if(power_supply) + playsound(src, 'sound/weapons/guns/interact/mag_unload.ogg', 100) + user.visible_message("[user] removes the power cell from [src].", "You remove the power cell from [src].") + user.put_in_hands(power_supply) + power_supply.update_icon() + power_supply = null + update_icon() + +/obj/item/weapon/gun/energy/MouseDrop(var/obj/over_object) + if (!over_object || !(ishuman(usr) || issmall(usr))) + return + + if (!(src.loc == usr)) + return + var/mob/living/carbon/human/H = usr + if(H.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_KNOCKOUT)) + return + + switch(over_object.name) + if("r_hand") + unload_ammo(usr, allow_dump=0) + if("l_hand") + unload_ammo(usr, allow_dump=0) \ No newline at end of file diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm new file mode 100644 index 00000000..35628cec --- /dev/null +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -0,0 +1,167 @@ +/obj/item/weapon/gun/energy/laser + name = "laser carbine" + desc = "A Hephaestus Industries G40E carbine, designed to kill with concentrated energy blasts." + icon_state = "laser" + item_state = "laser" + slot_flags = SLOT_BELT|SLOT_BACK + w_class = ITEM_SIZE_LARGE + force = 10 + one_hand_penalty = 2 + accuracy = 2 + origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 2) + matter = list(DEFAULT_WALL_MATERIAL = 2000) + projectile_type = /obj/item/projectile/beam/midlaser + wielded_item_state = "laser-wielded" + +/obj/item/weapon/gun/energy/h4 + name = "H4 laser pistol" + icon_state = "h4" + item_state = "ionpistol" + slot_flags = SLOT_BELT + w_class = ITEM_SIZE_NORMAL + force = 10 + origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 2) + matter = list(DEFAULT_WALL_MATERIAL = 2000) + projectile_type = /obj/item/projectile/beam/midlaser + +/obj/item/weapon/gun/energy/laser/mounted + self_recharge = 1 + use_external_power = 1 + one_hand_penalty = 0 //just in case + +/obj/item/weapon/gun/energy/laser/practice + name = "practice laser carbine" + desc = "A modified version of the HI G40E, this one fires less concentrated energy bolts designed for target practice." + icon_state = "laserp" + projectile_type = /obj/item/projectile/beam/practice + charge_cost = 10 //How much energy is needed to fire. + +/obj/item/weapon/gun/energy/laser/practice/proc/hacked() + return projectile_type != /obj/item/projectile/beam/practice + +/obj/item/weapon/gun/energy/laser/practice/emag_act(var/remaining_charges, var/mob/user, var/emag_source) + if(hacked()) + return NO_EMAG_ACT + to_chat(user, "You disable the safeties on [src] and crank the output to the lethal levels.") + desc += " Its safeties are disabled and output is set to dangerous levels." + projectile_type = /obj/item/projectile/beam/midlaser + charge_cost = 20 + max_shots = rand(3,6) //will melt down after those + return 1 + +/obj/item/weapon/gun/energy/laser/practice/handle_post_fire(mob/user, atom/target, var/pointblank=0, var/reflex=0) + ..() + if(hacked()) + max_shots-- + if(!max_shots) //uh hoh gig is up + to_chat(user, "\The [src] sizzles in your hands, acrid smoke rising from the firing end!") + desc += " The optical pathway is melted and useless." + projectile_type = null + +obj/item/weapon/gun/energy/retro + name = "retro laser" + icon_state = "retro" + item_state = "retro" + desc = "An older model of the basic lasergun. Nevertheless, it is still quite deadly and easy to maintain, making it a favorite amongst pirates and other outlaws." + slot_flags = SLOT_BELT|SLOT_HOLSTER + w_class = ITEM_SIZE_NORMAL + projectile_type = /obj/item/projectile/beam + fire_delay = 15 //old technology, and a pistol + +/obj/item/weapon/gun/energy/captain + name = "antique laser gun" + icon_state = "caplaser" + item_state = "caplaser" + desc = "A rare weapon, handcrafted by a now defunct specialty manufacturer on Luna for a small fortune. It's certainly aged well." + force = 5 + slot_flags = SLOT_BELT //too unusually shaped to fit in a holster + w_class = ITEM_SIZE_NORMAL + projectile_type = /obj/item/projectile/beam + origin_tech = null + max_shots = 5 //to compensate a bit for self-recharging + one_hand_penalty = 1 //a little bulky + self_recharge = 1 + +/obj/item/weapon/gun/energy/lasercannon + name = "laser cannon" + desc = "With the laser cannon, the lasing medium is enclosed in a tube lined with uranium-235 and subjected to high neutron flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with small laser volumes!" + icon_state = "lasercannon" + item_state = null + origin_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3, TECH_POWER = 3) + slot_flags = SLOT_BELT|SLOT_BACK + one_hand_penalty = 6 //large and heavy + w_class = ITEM_SIZE_HUGE + projectile_type = /obj/item/projectile/beam/heavylaser + charge_cost = 40 + max_shots = 6 + accuracy = 2 + fire_delay = 20 + wielded_item_state = "gun_wielded" + +/obj/item/weapon/gun/energy/lasercannon/mounted + name = "mounted laser cannon" + self_recharge = 1 + use_external_power = 1 + recharge_time = 10 + accuracy = 0 //mounted laser cannons don't need any help, thanks + one_hand_penalty = 0 + +/obj/item/weapon/gun/energy/sniperrifle + name = "marksman energy rifle" + desc = "The HI DMR 9E is an older design of Hephaestus Industries. A designated marksman rifle capable of shooting powerful ionized beams, this is a weapon to kill from a distance." + icon_state = "sniper" + item_state = "laser" + origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 5, TECH_POWER = 4) + projectile_type = /obj/item/projectile/beam/sniper + one_hand_penalty = 5 // The weapon itself is heavy, and the long barrel makes it hard to hold steady with just one hand. + slot_flags = SLOT_BACK + charge_cost = 40 + max_shots = 4 + fire_delay = 35 + force = 10 + w_class = ITEM_SIZE_HUGE + accuracy = -2 //shooting at the hip + scoped_accuracy = 0 + wielded_item_state = "gun_wielded" + +/obj/item/weapon/gun/energy/sniperrifle/update_icon() + ..() + item_state_slots[slot_back_str] = icon_state //so that the on-back overlay uses the different charged states + +/obj/item/weapon/gun/energy/sniperrifle/verb/scope() + set category = "Object" + set name = "Use Scope" + set popup_menu = 1 + + toggle_scope(usr, 2.0) + +////////Laser Tag//////////////////// + +/obj/item/weapon/gun/energy/lasertag + name = "laser tag gun" + item_state = "laser" + desc = "Standard issue weapon of the Imperial Guard." + origin_tech = list(TECH_COMBAT = 1, TECH_MAGNET = 2) + self_recharge = 1 + matter = list(DEFAULT_WALL_MATERIAL = 2000) + projectile_type = /obj/item/projectile/beam/lastertag/blue + var/required_vest + +/obj/item/weapon/gun/energy/lasertag/special_check(var/mob/living/carbon/human/M) + if(ishuman(M)) + if(!istype(M.wear_suit, required_vest)) + to_chat(M, "You need to be wearing your laser tag vest!") + return 0 + return ..() + +/obj/item/weapon/gun/energy/lasertag/blue + icon_state = "bluetag" + item_state = "bluetag" + projectile_type = /obj/item/projectile/beam/lastertag/blue + required_vest = /obj/item/clothing/suit/bluetag + +/obj/item/weapon/gun/energy/lasertag/red + icon_state = "redtag" + item_state = "redtag" + projectile_type = /obj/item/projectile/beam/lastertag/red + required_vest = /obj/item/clothing/suit/redtag diff --git a/code/modules/projectiles/guns/energy/nuclear.dm b/code/modules/projectiles/guns/energy/nuclear.dm new file mode 100644 index 00000000..6e1bd666 --- /dev/null +++ b/code/modules/projectiles/guns/energy/nuclear.dm @@ -0,0 +1,102 @@ +/obj/item/weapon/gun/energy/gun + name = "energy gun" + desc = "Another bestseller of Lawson Arms and the FTU, the LAEP90 Perun is a versatile energy based sidearm, capable of switching between low, medium and high power projectile settings. In other words: stun, shock or kill." + icon_state = "energystun100" + item_state = null //so the human update icon uses the icon_state instead. + max_shots = 10 + fire_delay = 10 // To balance for the fact that it is a pistol and can be used one-handed without penalty + + projectile_type = /obj/item/projectile/beam/stun + origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 2) + modifystate = "energystun" + + firemodes = list( + list(mode_name="stun", projectile_type=/obj/item/projectile/beam/stun, modifystate="energystun"), + list(mode_name="shock", projectile_type=/obj/item/projectile/beam/stun/shock, modifystate="energyshock"), + list(mode_name="lethal", projectile_type=/obj/item/projectile/beam, modifystate="energykill"), + ) + +/obj/item/weapon/gun/energy/gun/small + name = "small energy gun" + desc = "A smaller model of the versatile LAEP90 Perun, packing considerable utility in a smaller package. Best used in situations where full-sized sidearms are inappropriate." + icon_state = "smallgunstun" + max_shots = 5 + w_class = ITEM_SIZE_SMALL + force = 2 //it's the size of a car key, what did you expect? + modifystate = "smallgunstun" + + firemodes = list( + list(mode_name="stun", projectile_type=/obj/item/projectile/beam/stun, modifystate="smallgunstun"), + list(mode_name="shock", projectile_type=/obj/item/projectile/beam/stun/shock, modifystate="smallgunshock"), + list(mode_name="lethal", projectile_type=/obj/item/projectile/beam/smalllaser, modifystate="smallgunkill"), + ) + +/obj/item/weapon/gun/energy/gun/mounted + name = "mounted energy gun" + self_recharge = 1 + use_external_power = 1 + +/obj/item/weapon/gun/energy/gun/nuclear + name = "advanced energy gun" + desc = "An energy gun with an experimental miniaturized reactor." + icon_state = "nucgun" + origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 5, TECH_POWER = 3) + slot_flags = SLOT_BELT + w_class = ITEM_SIZE_LARGE + force = 8 //looks heavier than a pistol + self_recharge = 1 + modifystate = null + one_hand_penalty = 1 //bulkier than an e-gun, but not quite the size of a carbine + + firemodes = list( + list(mode_name="stun", projectile_type=/obj/item/projectile/beam/stun), + list(mode_name="shock", projectile_type=/obj/item/projectile/beam/stun/shock), + list(mode_name="lethal", projectile_type=/obj/item/projectile/beam), + ) + + var/fail_counter = 0 + +//override for failcheck behaviour +/obj/item/weapon/gun/energy/gun/nuclear/Process() + if(fail_counter > 0) + radiation_repository.radiate(src, fail_counter--) + + return ..() + +/obj/item/weapon/gun/energy/gun/nuclear/emp_act(severity) + ..() + switch(severity) + if(1) + fail_counter = max(fail_counter, 30) + visible_message("\The [src]'s reactor overloads!") + if(2) + fail_counter = max(fail_counter, 10) + if(ismob(loc)) + to_chat(loc, "\The [src] feels pleasantly warm.") + +/obj/item/weapon/gun/energy/gun/nuclear/proc/get_charge_overlay() + var/ratio = power_supply.percent() + ratio = round(ratio, 25) + return "nucgun-[ratio]" + +/obj/item/weapon/gun/energy/gun/nuclear/proc/get_reactor_overlay() + if(fail_counter) + return "nucgun-medium" + if (power_supply.percent() <= 50) + return "nucgun-light" + return "nucgun-clean" + +/obj/item/weapon/gun/energy/gun/nuclear/proc/get_mode_overlay() + var/datum/firemode/current_mode = firemodes[sel_mode] + switch(current_mode.name) + if("stun") return "nucgun-stun" + if("lethal") return "nucgun-kill" + +/obj/item/weapon/gun/energy/gun/nuclear/update_icon() + var/list/new_overlays = list() + + new_overlays += get_charge_overlay() + new_overlays += get_reactor_overlay() + new_overlays += get_mode_overlay() + + overlays = new_overlays diff --git a/code/modules/projectiles/guns/energy/pulse.dm b/code/modules/projectiles/guns/energy/pulse.dm new file mode 100644 index 00000000..e327e80e --- /dev/null +++ b/code/modules/projectiles/guns/energy/pulse.dm @@ -0,0 +1,69 @@ +/obj/item/weapon/gun/energy/pulse_rifle + name = "pulse rifle" + desc = "A weapon that uses advanced pulse-based beam generation technology to emit powerful laser blasts. Because of its complexity and cost, it is rarely seen in use except by specialists." + icon_state = "pulse" + item_state = "pulse" + slot_flags = SLOT_BACK + force = 12 + projectile_type = /obj/item/projectile/beam/pulse/heavy + max_shots = 36 + w_class = ITEM_SIZE_HUGE + one_hand_penalty= 6 + multi_aim = 1 + burst_delay = 3 + burst = 3 + move_delay = 4 + accuracy = -1 + wielded_item_state = "gun_wielded" + +/obj/item/weapon/gun/energy/pulse_rifle/carbine + name = "pulse carbine" + desc = "A weapon that uses advanced pulse-based beam generation technology to emit powerful laser blasts. Less bulky than the full-sized rifle." + icon_state = "pulse_carbine" + slot_flags = SLOT_BACK|SLOT_BELT + force = 8 + //projectile_type = /obj/item/projectile/beam/pulse/mid + max_shots = 24 + w_class = ITEM_SIZE_LARGE + one_hand_penalty= 3 + burst_delay = 2 + move_delay = 2 + +/obj/item/weapon/gun/energy/pulse_rifle/pistol + name = "pulse pistol" + desc = "A weapon that uses advanced pulse-based beam generation technology to emit powerful laser blasts. Even smaller than the carbine." + icon_state = "pulse_pistol" + slot_flags = SLOT_BELT|SLOT_HOLSTER + force = 6 + projectile_type = /obj/item/projectile/beam/pulse + max_shots = 21 + w_class = ITEM_SIZE_NORMAL + one_hand_penalty=1 //a bit heavy + burst_delay = 1 + move_delay = 1 + wielded_item_state = null + +/obj/item/weapon/gun/energy/pulse_rifle/mounted + self_recharge = 1 + use_external_power = 1 + +/obj/item/weapon/gun/energy/pulse_rifle/destroyer + name = "pulse destroyer" + desc = "A heavy-duty, pulse-based energy weapon. Because of its complexity and cost, it is rarely seen in use except by specialists." + cell_type = /obj/item/weapon/cell/super + fire_delay = 25 + //projectile_type=/obj/item/projectile/beam/pulse/destroy + charge_cost= 40 + +/obj/item/weapon/gun/energy/pulse_rifle/destroyer/attack_self(mob/living/user as mob) + to_chat(user, "[src.name] has three settings, and they are all DESTROY.") + +/obj/item/weapon/gun/energy/pulse_rifle/bogani + name = "pulsar cannon" + desc = "An alien weapon never before seen by the likes of your species." + icon_state = "bog_rifle" + item_state = "bog_rifle" + wielded_item_state = "bog_rifle-wielded" + projectile_type = /obj/item/projectile/beam/pulse/bogani + max_shots = 100 //Don't want it to run out + icon_rounder = 20 \ No newline at end of file diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm new file mode 100644 index 00000000..16dd5b21 --- /dev/null +++ b/code/modules/projectiles/guns/energy/special.dm @@ -0,0 +1,101 @@ +/obj/item/weapon/gun/energy/ionrifle + name = "ion rifle" + desc = "The NT Mk60 EW Halicon is a man portable anti-armor weapon designed to disable mechanical threats, produced by NT. Not the best of its type." + icon_state = "ionrifle" + item_state = "ionrifle" + origin_tech = list(TECH_COMBAT = 2, TECH_MAGNET = 4) + w_class = ITEM_SIZE_HUGE + force = 10 + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BACK + one_hand_penalty = 4 + charge_cost = 30 + max_shots = 10 + projectile_type = /obj/item/projectile/ion + wielded_item_state = "ionrifle-wielded" + combustion = 0 + +/obj/item/weapon/gun/energy/ionrifle/emp_act(severity) + ..(max(severity, 2)) //so it doesn't EMP itself, I guess + +/obj/item/weapon/gun/energy/ionrifle/small + name = "ion pistol" + desc = "The NT Mk72 EW Preston is a personal defense weapon designed to disable mechanical threats." + icon_state = "ionpistol" + item_state = "ionpistol" + origin_tech = list(TECH_COMBAT = 2, TECH_MAGNET = 4) + w_class = ITEM_SIZE_NORMAL + force = 5 + slot_flags = SLOT_BELT|SLOT_HOLSTER + one_hand_penalty = 0 + charge_cost = 20 + max_shots = 6 + projectile_type = /obj/item/projectile/ion/small + +/obj/item/weapon/gun/energy/mindflayer + name = "mind flayer" + desc = "A custom-built weapon of some kind." + icon_state = "xray" + origin_tech = list(TECH_COMBAT = 5, TECH_MAGNET = 4) + projectile_type = /obj/item/projectile/beam/mindflayer + + +/* Staves */ + +/obj/item/weapon/gun/energy/staff + name = "staff of change" + desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself." + icon = 'icons/obj/gun.dmi' + item_icons = null + icon_state = "staffofchange" + item_state = "staffofchange" + fire_sound = 'sound/weapons/emitter.ogg' + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT|SLOT_BACK + w_class = ITEM_SIZE_LARGE + max_shots = 5 + projectile_type = /obj/item/projectile/change + origin_tech = null + self_recharge = 1 + charge_meter = 0 + +/obj/item/weapon/gun/energy/staff/special_check(var/mob/user) + if((user.mind && !wizards.is_antagonist(user.mind))) + to_chat(usr, "You focus your mind on \the [src], but nothing happens!") + return 0 + + return ..() + +/obj/item/weapon/gun/energy/staff/handle_click_empty(mob/user = null) + if (user) + user.visible_message("*fizzle*", "*fizzle*") + else + src.visible_message("*fizzle*") + playsound(src.loc, 'sound/effects/sparks1.ogg', 100, 1) + +/obj/item/weapon/gun/energy/staff/animate + name = "staff of animation" + desc = "An artefact that spits bolts of life-force which causes objects which are hit by it to animate and come to life! This magic doesn't affect machines." + projectile_type = /obj/item/projectile/animate + max_shots = 10 + +obj/item/weapon/gun/energy/staff/focus + name = "mental focus" + desc = "An artefact that channels the will of the user into destructive bolts of force. If you aren't careful with it, you might poke someone's brain out." + icon = 'icons/obj/wizard.dmi' + icon_state = "focus" + item_state = "focus" + slot_flags = SLOT_BELT|SLOT_BACK + w_class = ITEM_SIZE_LARGE + projectile_type = /obj/item/projectile/forcebolt + /* + attack_self(mob/living/user as mob) + if(projectile_type == /obj/item/projectile/forcebolt) + charge_cost = 400 + to_chat(user, "The [src.name] will now strike a small area.") + projectile_type = /obj/item/projectile/forcebolt/strong + else + charge_cost = 200 + to_chat(user, "The [src.name] will now strike only a single person.") + projectile_type = /obj/item/projectile/forcebolt" + */ diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm new file mode 100644 index 00000000..a86191d3 --- /dev/null +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -0,0 +1,96 @@ +/obj/item/weapon/gun/energy/taser + name = "Mk30 NL" + desc = "Low capacity gun used for non-lethal takedowns. Never has ammo when you need it the most." + icon_state = "taser" + fire_sound = 'sound/weapons/guns/fire/pain_fire.ogg' + item_state = null //so the human update icon uses the icon_state instead. + max_shots = 2 + projectile_type = /obj/item/projectile/energy/electrode + combustion = 0 + + /* + firemodes = list( + list(mode_name="stun", projectile_type=/obj/item/projectile/beam/stun), + list(mode_name="shock", projectile_type=/obj/item/projectile/beam/stun/shock), + ) + */ +/obj/item/weapon/gun/energy/taser/carbine + name = "taser carbine" + desc = "The NT Mk44 NL is a high capacity gun used for non-lethal takedowns. It can switch between high and low intensity stun shots." + icon_state = "tasercarbine" + w_class = ITEM_SIZE_LARGE + slot_flags = SLOT_BELT|SLOT_BACK + one_hand_penalty = 3 + origin_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3, TECH_POWER = 3) + force = 8 + max_shots = 12 + accuracy = 1 + projectile_type = /obj/item/projectile/energy/electrode ///obj/item/projectile/beam/stun/heavy + wielded_item_state = "tasercarbine-wielded" +/* + firemodes = list( + list(mode_name="stun", projectile_type=/obj/item/projectile/beam/stun/heavy), + list(mode_name="shock", projectile_type=/obj/item/projectile/beam/stun/shock/heavy), + ) +*/ +/obj/item/weapon/gun/energy/taser/mounted + name = "mounted taser gun" + self_recharge = 1 + use_external_power = 1 + +/obj/item/weapon/gun/energy/taser/mounted/cyborg + name = "taser gun" + max_shots = 6 + recharge_time = 10 //Time it takes for shots to recharge (in ticks) + + +/obj/item/weapon/gun/energy/stunrevolver + name = "stun revolver" + desc = "A LAEP20 Zeus. Designed by Lawson Arms and produced under the wing of the FTU, several TSCs have been trying to get a hold of the blueprints for half a decade." + icon_state = "stunrevolver" + item_state = "stunrevolver" + origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 3, TECH_POWER = 2) + projectile_type = /obj/item/projectile/energy/electrode + max_shots = 6 + combustion = 0 + +/obj/item/weapon/gun/energy/stunrevolver/rifle + name = "stun rifle" + desc = "A LAEP38 Thor, a vastly oversized variant of the LAEP20 Zeus. Fires overcharged electrodes to take down hostile armored targets without harming them too much." + icon_state = "stunrifle" + item_state = "stunrifle" + w_class = ITEM_SIZE_HUGE + slot_flags = SLOT_BACK + one_hand_penalty = 6 + origin_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3, TECH_POWER = 3) + force = 10 + max_shots = 10 + accuracy = 1 + projectile_type = /obj/item/projectile/energy/electrode/stunshot + wielded_item_state = "stunrifle-wielded" + +/obj/item/weapon/gun/energy/crossbow + name = "mini energy-crossbow" + desc = "A weapon favored by many mercenary stealth specialists." + icon_state = "crossbow" + w_class = ITEM_SIZE_NORMAL + item_state = "crossbow" + origin_tech = list(TECH_COMBAT = 2, TECH_MAGNET = 2, TECH_ILLEGAL = 5) + matter = list(DEFAULT_WALL_MATERIAL = 2000) + slot_flags = SLOT_BELT + silenced = 1 + fire_sound = 'sound/weapons/Genhit.ogg' + projectile_type = /obj/item/projectile/energy/bolt + max_shots = 8 + self_recharge = 1 + charge_meter = 0 + combustion = 0 + +/obj/item/weapon/gun/energy/crossbow/largecrossbow + name = "energy crossbow" + desc = "A weapon favored by mercenary infiltration teams." + w_class = ITEM_SIZE_LARGE + force = 10 + one_hand_penalty = 1 + matter = list(DEFAULT_WALL_MATERIAL = 200000) + projectile_type = /obj/item/projectile/energy/bolt/large diff --git a/code/modules/projectiles/guns/flamer.dm b/code/modules/projectiles/guns/flamer.dm new file mode 100644 index 00000000..bb724a79 --- /dev/null +++ b/code/modules/projectiles/guns/flamer.dm @@ -0,0 +1,263 @@ +//FLAMETHROWER + +/obj/item/weapon/gun/flamer + name = "\improper M2A4 Fire Thrower" + desc = "Flame thrower made to light people you don't like on fire." + icon_state = "flamethrower" +// item_state = "flamer" + slot_flags = SLOT_BACK + w_class = 4 + force = 15 +// fire_sound = 'sound/weapons/gun_flamethrower2.ogg' +// ammo_type = /obj/item/ammo_magazine/flamer_tank + var/max_range = 5 + var/lit = 0 //Turn the flamer on/off + + attack_self(mob/user) + . = ..() + toggle_flame(user) + + examine(mob/user) + ..() + to_chat(user,"It's turned [lit? "on" : "off"].") +/* +/atom/proc/flamer_fire_act() + return +*/ +/obj/item/weapon/gun/flamer/proc/toggle_flame(mob/user) + playsound(user,'sound/weapons/flipblade.ogg', 25, 1) + lit = !lit + if (lit) + icon_state = 'flamer-lit' + else + icon_state = 'flamer' + +/obj/item/weapon/gun/flamer/Fire(atom/target, mob/living/user, params, reflex) + set waitfor = 0 + ..() + var/turf/curloc = get_turf(user) //In case the target or we are expired. + var/turf/targloc = get_turf(target) + if (!targloc || !curloc) return //Something has gone wrong... + + if(!lit) + to_chat(user, "The weapon isn't lit") + return + + unleash_flame(target, user) + +/proc/getline2(atom/from_atom, atom/to_atom, exclude_origin=FALSE) + +/obj/item/weapon/gun/flamer/proc/unleash_flame(atom/target, mob/living/user) + set waitfor = 0 + var/burnlevel = 50 + var/burntime = 40 + var/fire_color = "red" + var/list/turf/turfs = getline2(user,target) + playsound(user, fire_sound, 50, 1) + var/distance = 1 + var/turf/prev_T + + for(var/turf/T in turfs) + if(T == user.loc) + prev_T = T + continue + if(T.density) + break + if(loc != user) + break + if(distance > max_range) + break + if(prev_T && LinkBlocked(prev_T, T)) + break + flame_turf(T,user, burntime, burnlevel, fire_color) + distance++ + prev_T = T + sleep(1) + +/obj/item/weapon/gun/flamer/proc/flame_turf(turf/T, mob/living/user, heat, burn, f_color = "red") + if(!istype(T)) + return + + // No stacking flames + if (locate(/obj/flamer_fire) in T) + return + + new /obj/flamer_fire(T, heat, burn, f_color) + + for(var/mob/living/M in T) //Deal bonus damage if someone's caught directly in initial stream + if(M.stat == DEAD) continue + M.adjust_fire_stacks(rand(5,burn*2)) + M.IgniteMob() + M.adjustFireLoss(rand(burn,(burn*2))) // Make it so its the amount of heat or twice it for the initial blast. + to_chat(M, "Augh! You are roasted by the flames!") + +/obj/item/weapon/gun/flamer/proc/triangular_flame(var/atom/target, var/mob/living/user, var/burntime, var/burnlevel) + set waitfor = 0 + + var/unleash_dir = user.dir //don't want the player to turn around mid-unleash to bend the fire. + var/list/turf/turfs = getline2(user,target) + playsound(user, fire_sound, 50, 1) + var/distance = 1 + var/turf/prev_T + + for(var/turf/T in turfs) + if(T == user.loc) + prev_T = T + continue + if(T.density) + break + if(loc != user) + break + if(distance > max_range) + break + if(prev_T && LinkBlocked(prev_T, T)) + break + flame_turf(T,user, burntime, burnlevel, "green") + prev_T = T + sleep(1) + + var/list/turf/right = list() + var/list/turf/left = list() + var/turf/right_turf = T + var/turf/left_turf = T + var/right_dir = turn(unleash_dir, 90) + var/left_dir = turn(unleash_dir, -90) + for (var/i = 0, i < distance - 1, i++) + right_turf = get_step(right_turf, right_dir) + right += right_turf + left_turf = get_step(left_turf, left_dir) + left += left_turf + + var/turf/prev_R = T + for (var/turf/R in right) + + if (R.density) + break + if(prev_R && LinkBlocked(prev_R, R)) + break + + flame_turf(R, user, burntime, burnlevel, "green") + prev_R = R + sleep(1) + + var/turf/prev_L = T + for (var/turf/L in left) + if (L.density) + break + if(prev_L && LinkBlocked(prev_L, L)) break + + flame_turf(L, user, burntime, burnlevel, "green") + prev_L = L + sleep(1) + + distance++ + +////////////////////////////////////////////////////////////////////////////////////////////////// +//Time to redo part of abby's code. +//Create a flame sprite object. Doesn't work like regular fire, ie. does not affect atmos or heat +/obj/flamer_fire + name = "fire" + desc = "Ouch!" + anchored = 1 + mouse_opacity = 0 + icon = 'icons/effects/fire.dmi' + icon_state = "red_2" + layer = BELOW_OBJ_LAYER + var/firelevel = 12 //Tracks how much "fire" there is. Basically the timer of how long the fire burns + var/burnlevel = 10 //Tracks how HOT the fire is. This is basically the heat level of the fire and determines the temperature. + var/flame_color = "red" + +/obj/flamer_fire/New(loc, fire_lvl, burn_lvl, f_color, fire_spread_amount) + ..() + if (f_color) + flame_color = f_color + + icon_state = "[flame_color]_2" + if(fire_lvl) firelevel = fire_lvl + if(burn_lvl) burnlevel = burn_lvl + START_PROCESSING(SSobj,src) + + if(fire_spread_amount > 0) + var/turf/T + for(var/dirn in GLOB.cardinal) + T = get_step(loc, dirn) + if(istype(T,/turf/simulated/open)) continue + if(locate(/obj/flamer_fire) in T) continue //No stacking + var/new_spread_amt = T.density ? 0 : fire_spread_amount - 1 //walls stop the spread + if(new_spread_amt) + for(var/obj/O in T) + if(!O.CanPass(src, loc)) + new_spread_amt = 0 + break + addtimer(CALLBACK(src, .proc/make_more_fire,T, fire_lvl, burn_lvl, f_color, new_spread_amt), 0) //Do not put spawns in recursive things. + +obj/flamer_fire/proc/make_more_fire(var/T, var/f_level, var/b_level, var/fcolor, var/new_spread) + new /obj/flamer_fire(T, f_level, b_level, fcolor, new_spread) + +/obj/flamer_fire/Destroy() + set_light(0) + STOP_PROCESSING(SSobj,src) + . = ..() + + +/obj/flamer_fire/Crossed(mob/living/M) //Only way to get it to reliable do it when you walk into it. + if(istype(M)) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(istype(H.wear_suit, /obj/item/clothing/suit/fire)) + H.show_message(text("Your suit protects you from the flames."),1) + H.adjustFireLoss(burnlevel*0.25) //Does small burn damage to a person wearing one of the suits. + return + M.adjust_fire_stacks(burnlevel) //Make it possible to light them on fire later. + if (prob(firelevel + 2*M.fire_stacks)) //the more soaked in fire you are, the likelier to be ignited + M.IgniteMob() + + M.adjustFireLoss(round(burnlevel*0.5)) //This makes fire stronk. + to_chat(M, "You are burned!") + + +/obj/flamer_fire/proc/updateicon() + if(burnlevel < 15) + color = "#c1c1c1" //make it darker to make show its weaker. + switch(firelevel) + if(1 to 9) + icon_state = "[flame_color]_1" + set_light(2, l_color = "#E38F46") + if(10 to 25) + icon_state = "[flame_color]_2" + set_light(4, l_color = "#E38F46") + if(25 to INFINITY) //Change the icons and luminosity based on the fire's intensity + icon_state = "[flame_color]_3" + set_light(6, l_color = "#E38F46") + + +/obj/flamer_fire/Process() + var/turf/T = loc + firelevel = max(0, firelevel) + if(!istype(T)) //Is it a valid turf? Has to be on a floor + qdel(src) + return + + updateicon() + + if(!firelevel) + qdel(src) + return + + var/j = 0 + for(var/mob/living/I in loc) + if(istype(I,/mob/living/carbon/human)) + var/mob/living/carbon/human/M = I + if(istype(M.wear_suit, /obj/item/clothing/suit/fire)) + M.show_message(text("Your suit protects you from the flames."),1) + M.adjustFireLoss(rand(0 ,burnlevel*0.25)) //Does small burn damage to a person wearing one of the suits. + continue + I.adjust_fire_stacks(burnlevel) //If i stand in the fire i deserve all of this. Also Napalm stacks quickly. + if(prob(firelevel)) I.IgniteMob() + I.show_message(text("You are burned!"),1) +/* //Uncomment when you decide to make this proc do something. + for(var/obj/O in loc) + O.flamer_fire_act() +*/ + firelevel -= 2 //reduce the intensity by 2 per tick + return \ No newline at end of file diff --git a/code/modules/projectiles/guns/launcher.dm b/code/modules/projectiles/guns/launcher.dm new file mode 100644 index 00000000..6cf8cf5c --- /dev/null +++ b/code/modules/projectiles/guns/launcher.dm @@ -0,0 +1,29 @@ +/obj/item/weapon/gun/launcher + name = "launcher" + desc = "A device that launches things." + w_class = ITEM_SIZE_HUGE + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BACK + + var/release_force = 0 + var/throw_distance = 10 + fire_sound_text = "a launcher firing" + +//This normally uses a proc on projectiles and our ammo is not strictly speaking a projectile. +/obj/item/weapon/gun/launcher/can_hit(var/mob/living/target as mob, var/mob/living/user as mob) + return 1 + +//Override this to avoid a runtime with suicide handling. +/obj/item/weapon/gun/launcher/handle_suicide(mob/living/user) + to_chat(user, "Shooting yourself with \a [src] is pretty tricky. You can't seem to manage it.") + return + +/obj/item/weapon/gun/launcher/proc/update_release_force(obj/item/projectile) + return 0 + +/obj/item/weapon/gun/launcher/process_projectile(obj/item/projectile, mob/user, atom/target, var/target_zone, var/params=null, var/pointblank=0, var/reflex=0) + update_release_force(projectile) + projectile.loc = get_turf(user) + projectile.throw_at(target, throw_distance, release_force, user) + play_fire_sound(user,projectile) + return 1 diff --git a/code/modules/projectiles/guns/launcher/alien.dm b/code/modules/projectiles/guns/launcher/alien.dm new file mode 100644 index 00000000..87a9aad3 --- /dev/null +++ b/code/modules/projectiles/guns/launcher/alien.dm @@ -0,0 +1,59 @@ +/obj/item/weapon/gun/launcher/alien + var/last_regen = 0 + var/ammo_gen_time = 100 + var/max_ammo = 3 + var/ammo = 3 + var/ammo_type + var/ammo_name + +/obj/item/weapon/gun/launcher/alien/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + last_regen = world.time + +/obj/item/weapon/gun/launcher/alien/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/weapon/gun/launcher/alien/Process() + if(ammo < max_ammo && world.time > last_regen + ammo_gen_time) + ammo++ + last_regen = world.time + update_icon() + +/obj/item/weapon/gun/launcher/alien/examine(mob/user) + ..(user) + to_chat(user, "It has [ammo] [ammo_name]\s remaining.") + +/obj/item/weapon/gun/launcher/alien/consume_next_projectile() + if(ammo < 1) return null + if(ammo == max_ammo) //stops people from buffering a reload (gaining effectively +1 to the clip) + last_regen = world.time + ammo-- + return new ammo_type + +/obj/item/weapon/gun/launcher/alien/special_check(user) + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(H.species && H.species.get_bodytype(H) != SPECIES_VOX) + to_chat(user, "\The [src] does not respond to you!") + return 0 + return ..() + +//Vox pinning weapon. +/obj/item/weapon/gun/launcher/alien/spikethrower + + name = "spike thrower" + desc = "A vicious alien projectile weapon. Parts of it quiver gelatinously, as though the thing is insectile and alive." + w_class = ITEM_SIZE_LARGE + ammo_name = "spike" + ammo_type = /obj/item/weapon/spike + release_force = 30 + icon = 'icons/obj/gun.dmi' + icon_state = "spikethrower3" + item_state = "spikethrower" + fire_sound_text = "a strange noise" + fire_sound = 'sound/weapons/bladeslice.ogg' + +/obj/item/weapon/gun/launcher/alien/spikethrower/update_icon() + icon_state = "spikethrower[ammo]" \ No newline at end of file diff --git a/code/modules/projectiles/guns/launcher/crossbow.dm b/code/modules/projectiles/guns/launcher/crossbow.dm new file mode 100644 index 00000000..fd6efa6f --- /dev/null +++ b/code/modules/projectiles/guns/launcher/crossbow.dm @@ -0,0 +1,275 @@ +//AMMUNITION + +/obj/item/weapon/arrow + name = "bolt" + desc = "It's got a tip for you - get the point?" + icon = 'icons/obj/weapons.dmi' + icon_state = "bolt" + item_state = "bolt" + throwforce = 8 + w_class = ITEM_SIZE_NORMAL + sharp = 1 + edge = 0 + lock_picking_level = 3 + +/obj/item/weapon/arrow/proc/removed() //Helper for metal rods falling apart. + return + +/obj/item/weapon/spike + name = "alloy spike" + desc = "It's about a foot of weird silver metal with a wicked point." + sharp = 1 + edge = 0 + throwforce = 5 + w_class = ITEM_SIZE_SMALL + icon = 'icons/obj/weapons.dmi' + icon_state = "metal-rod" + item_state = "bolt" + +/obj/item/weapon/arrow/quill + name = "vox quill" + desc = "A wickedly barbed quill from some bizarre animal." + icon = 'icons/obj/weapons.dmi' + icon_state = "quill" + item_state = "quill" + throwforce = 5 + +/obj/item/weapon/arrow/rod + name = "metal rod" + desc = "Don't cry for me, Orithena." + icon_state = "metal-rod" + +/obj/item/weapon/arrow/rod/removed(mob/user) + if(throwforce == 15) // The rod has been superheated - we don't want it to be useable when removed from the bow. + to_chat(user, "[src] shatters into a scattering of overstressed metal shards as it leaves the crossbow.") + var/obj/item/weapon/material/shard/shrapnel/S = new() + S.loc = get_turf(src) + qdel(src) + +/obj/item/weapon/gun/launcher/crossbow + name = "powered crossbow" + desc = "A 2557AD twist on an old classic. Pick up that can." + icon = 'icons/obj/weapons.dmi' + icon_state = "crossbow" + item_state = "crossbow-solid" + fire_sound = 'sound/weapons/punchmiss.ogg' // TODO: Decent THWOK noise. + fire_sound_text = "a solid thunk" + fire_delay = 25 + slot_flags = SLOT_BACK + + var/obj/item/bolt + var/tension = 0 // Current draw on the bow. + var/max_tension = 5 // Highest possible tension. + var/release_speed = 5 // Speed per unit of tension. + var/obj/item/weapon/cell/cell = null // Used for firing superheated rods. + var/current_user // Used to check if the crossbow has changed hands since being drawn. + +/obj/item/weapon/gun/launcher/crossbow/update_release_force() + release_force = tension*release_speed + +/obj/item/weapon/gun/launcher/crossbow/consume_next_projectile(mob/user=null) + if(tension <= 0) + to_chat(user, "\The [src] is not drawn back!") + return null + return bolt + +/obj/item/weapon/gun/launcher/crossbow/handle_post_fire(mob/user, atom/target) + bolt = null + tension = 0 + update_icon() + ..() + +/obj/item/weapon/gun/launcher/crossbow/attack_self(mob/living/user as mob) + if(tension) + if(bolt) + user.visible_message("[user] relaxes the tension on [src]'s string and removes [bolt].","You relax the tension on [src]'s string and remove [bolt].") + bolt.loc = get_turf(src) + var/obj/item/weapon/arrow/A = bolt + bolt = null + A.removed(user) + else + user.visible_message("[user] relaxes the tension on [src]'s string.","You relax the tension on [src]'s string.") + tension = 0 + update_icon() + else + draw(user) + +/obj/item/weapon/gun/launcher/crossbow/proc/draw(var/mob/user as mob) + + if(!bolt) + to_chat(user, "You don't have anything nocked to [src].") + return + + if(user.restrained()) + return + + current_user = user + user.visible_message("[user] begins to draw back the string of [src].","You begin to draw back the string of [src].") + tension = 1 + + while(bolt && tension && loc == current_user) + if(!do_after(user, 25, src)) //crossbow strings don't just magically pull back on their own. + user.visible_message("[usr] stops drawing and relaxes the string of [src].","You stop drawing back and relax the string of [src].") + tension = 0 + update_icon() + return + + //double check that the user hasn't removed the bolt in the meantime + if(!(bolt && tension && loc == current_user)) + return + + tension++ + update_icon() + + if(tension >= max_tension) + tension = max_tension + to_chat(usr, "[src] clunks as you draw the string to its maximum tension!") + return + + user.visible_message("[usr] draws back the string of [src]!","You continue drawing back the string of [src]!") + +/obj/item/weapon/gun/launcher/crossbow/proc/increase_tension(var/mob/user as mob) + + if(!bolt || !tension || current_user != user) //Arrow has been fired, bow has been relaxed or user has changed. + return + + +/obj/item/weapon/gun/launcher/crossbow/attackby(obj/item/W as obj, mob/user as mob) + if(!bolt) + if (istype(W,/obj/item/weapon/arrow)) + user.drop_from_inventory(W, src) + bolt = W + user.visible_message("[user] slides [bolt] into [src].","You slide [bolt] into [src].") + update_icon() + return + else if(istype(W,/obj/item/stack/rods)) + var/obj/item/stack/rods/R = W + if (R.use(1)) + bolt = new /obj/item/weapon/arrow/rod(src) + bolt.fingerprintslast = src.fingerprintslast + bolt.loc = src + update_icon() + user.visible_message("[user] jams [bolt] into [src].","You jam [bolt] into [src].") + superheat_rod(user) + return + + if(istype(W, /obj/item/weapon/cell)) + if(!cell) + user.drop_item() + cell = W + cell.loc = src + to_chat(user, "You jam [cell] into [src] and wire it to the firing coil.") + superheat_rod(user) + else + to_chat(user, "[src] already has a cell installed.") + + else if(isScrewdriver(W)) + if(cell) + var/obj/item/C = cell + C.loc = get_turf(user) + to_chat(user, "You jimmy [cell] out of [src] with [W].") + cell = null + else + to_chat(user, "[src] doesn't have a cell installed.") + + else + ..() + +/obj/item/weapon/gun/launcher/crossbow/proc/superheat_rod(var/mob/user) + if(!user || !cell || !bolt) return + if(cell.charge < 500) return + if(bolt.throwforce >= 15) return + if(!istype(bolt,/obj/item/weapon/arrow/rod)) return + + to_chat(user, "[bolt] plinks and crackles as it begins to glow red-hot.") + bolt.throwforce = 15 + bolt.icon_state = "metal-rod-superheated" + cell.use(500) + +/obj/item/weapon/gun/launcher/crossbow/update_icon() + if(tension > 1) + icon_state = "crossbow-drawn" + else if(bolt) + icon_state = "crossbow-nocked" + else + icon_state = "crossbow" + + +// Crossbow construction. +/obj/item/weapon/crossbowframe + name = "crossbow frame" + desc = "A half-finished crossbow." + icon_state = "crossbowframe0" + item_state = "crossbow-solid" + + var/buildstate = 0 + +/obj/item/weapon/crossbowframe/update_icon() + icon_state = "crossbowframe[buildstate]" + +/obj/item/weapon/crossbowframe/examine(mob/user) + . = ..(user) + switch(buildstate) + if(1) to_chat(user, "It has a loose rod frame in place.") + if(2) to_chat(user, "It has a steel backbone welded in place.") + if(3) to_chat(user, "It has a steel backbone and a cell mount installed.") + if(4) to_chat(user, "It has a steel backbone, plastic lath and a cell mount installed.") + if(5) to_chat(user, "It has a steel cable loosely strung across the lath.") + +/obj/item/weapon/crossbowframe/attackby(obj/item/W as obj, mob/user as mob) + if(istype(W,/obj/item/stack/rods)) + if(buildstate == 0) + var/obj/item/stack/rods/R = W + if(R.use(3)) + to_chat(user, "You assemble a backbone of rods around the wooden stock.") + buildstate++ + update_icon() + else + to_chat(user, "You need at least three rods to complete this task.") + return + else if(isWelder(W)) + if(buildstate == 1) + var/obj/item/weapon/weldingtool/T = W + if(T.remove_fuel(0,user)) + if(!src || !T.isOn()) return + playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) + to_chat(user, "You weld the rods into place.") + buildstate++ + update_icon() + return + else if(isCoil(W)) + var/obj/item/stack/cable_coil/C = W + if(buildstate == 2) + if(C.use(5)) + to_chat(user, "You wire a crude cell mount into the top of the crossbow.") + buildstate++ + update_icon() + else + to_chat(user, "You need at least five segments of cable coil to complete this task.") + return + else if(buildstate == 4) + if(C.use(5)) + to_chat(user, "You string a steel cable across the crossbow's lath.") + buildstate++ + update_icon() + else + to_chat(user, "You need at least five segments of cable coil to complete this task.") + return + else if(istype(W,/obj/item/stack/material) && W.get_material_name() == "plastic") + if(buildstate == 3) + var/obj/item/stack/material/P = W + if(P.use(3)) + to_chat(user, "You assemble and install a heavy plastic lath onto the crossbow.") + buildstate++ + update_icon() + else + to_chat(user, "You need at least three plastic sheets to complete this task.") + return + else if(isScrewdriver(W)) + if(buildstate == 5) + to_chat(user, "You secure the crossbow's various parts.") + new /obj/item/weapon/gun/launcher/crossbow(get_turf(src)) + qdel(src) + return + else + ..() diff --git a/code/modules/projectiles/guns/launcher/grenade_launcher.dm b/code/modules/projectiles/guns/launcher/grenade_launcher.dm new file mode 100644 index 00000000..e71bca6e --- /dev/null +++ b/code/modules/projectiles/guns/launcher/grenade_launcher.dm @@ -0,0 +1,155 @@ +/obj/item/weapon/gun/launcher/grenade + name = "grenade launcher" + desc = "A bulky pump-action grenade launcher. Holds up to 6 grenades in a revolving magazine." + icon_state = "riotgun" + item_state = "riotgun" + origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 3) + w_class = ITEM_SIZE_HUGE + force = 10 + + fire_sound = 'sound/weapons/empty.ogg' + fire_sound_text = "a metallic thunk" + screen_shake = 0 + throw_distance = 7 + release_force = 5 + combustion = 1 + + var/obj/item/weapon/grenade/chambered + var/list/grenades = new/list() + var/max_grenades = 5 //holds this + one in the chamber + var/whitelisted_grenades = list( + /obj/item/weapon/grenade/frag/shell) + + var/blacklisted_grenades = list( + /obj/item/weapon/grenade/flashbang/clusterbang, + /obj/item/weapon/grenade/frag) + + matter = list(DEFAULT_WALL_MATERIAL = 2000) + +//revolves the magazine, allowing players to choose between multiple grenade types +/obj/item/weapon/gun/launcher/grenade/proc/pump(mob/M as mob) + playsound(M, 'sound/weapons/shotgunpump.ogg', 60, 1) + + var/obj/item/weapon/grenade/next + if(grenades.len) + next = grenades[1] //get this first, so that the chambered grenade can still be removed if the grenades list is empty + if(chambered) + grenades += chambered //rotate the revolving magazine + chambered = null + if(next) + grenades -= next //Remove grenade from loaded list. + chambered = next + to_chat(M, "You pump [src], loading \a [next] into the chamber.") + else + to_chat(M, "You pump [src], but the magazine is empty.") + update_icon() + +/obj/item/weapon/gun/launcher/grenade/examine(mob/user) + if(..(user, 2)) + var/grenade_count = grenades.len + (chambered? 1 : 0) + to_chat(user, "Has [grenade_count] grenade\s remaining.") + if(chambered) + to_chat(user, "\A [chambered] is chambered.") + +/obj/item/weapon/gun/launcher/grenade/proc/load(obj/item/weapon/grenade/G, mob/user) + if(!can_load_grenade_type(G, user)) + return + + if(grenades.len >= max_grenades) + to_chat(user, "\The [src] is full.") + return + user.drop_from_inventory(G, src) + grenades.Insert(1, G) //add to the head of the list, so that it is loaded on the next pump + user.visible_message("\The [user] inserts \a [G] into \the [src].", "You insert \a [G] into \the [src].") + +/obj/item/weapon/gun/launcher/grenade/proc/unload(mob/user) + if(grenades.len) + var/obj/item/weapon/grenade/G = grenades[grenades.len] + grenades.len-- + user.put_in_hands(G) + user.visible_message("\The [user] removes \a [G] from [src].", "You remove \a [G] from \the [src].") + else + to_chat(user, "\The [src] is empty.") + +/obj/item/weapon/gun/launcher/grenade/attack_self(mob/user) + pump(user) + +/obj/item/weapon/gun/launcher/grenade/attackby(obj/item/I, mob/user) + if((istype(I, /obj/item/weapon/grenade))) + load(I, user) + else + ..() + +/obj/item/weapon/gun/launcher/grenade/attack_hand(mob/user) + if(user.get_inactive_hand() == src) + unload(user) + else + ..() + +/obj/item/weapon/gun/launcher/grenade/consume_next_projectile() + if(chambered) + chambered.det_time = 10 + chambered.activate(null) + return chambered + +/obj/item/weapon/gun/launcher/grenade/handle_post_fire(mob/user) + message_admins("[key_name_admin(user)] fired a grenade ([chambered.name]) from a grenade launcher ([src.name]).") + log_game("[key_name_admin(user)] used a grenade ([chambered.name]).") + chambered = null + ..() + +/obj/item/weapon/gun/launcher/grenade/proc/can_load_grenade_type(obj/item/weapon/grenade/G, mob/user) + if(is_type_in_list(G, blacklisted_grenades) && ! is_type_in_list(G, whitelisted_grenades)) + to_chat(user, "\The [G] doesn't seem to fit in \the [src]!") + return FALSE + return TRUE + +// For uplink purchase, comes loaded with a random assortment of grenades +/obj/item/weapon/gun/launcher/grenade/loaded/New() + ..() + + var/list/grenade_types = list( + /obj/item/weapon/grenade/anti_photon = 2, + /obj/item/weapon/grenade/smokebomb = 2, + /obj/item/weapon/grenade/chem_grenade/teargas = 2, + /obj/item/weapon/grenade/flashbang = 3, + /obj/item/weapon/grenade/empgrenade = 3, + /obj/item/weapon/grenade/frag/shell = 1, + ) + + var/grenade_type = pickweight(grenade_types) + chambered = new grenade_type(src) + for(var/i in 1 to max_grenades) + grenade_type = pickweight(grenade_types) + grenades += new grenade_type(src) + +//Underslung grenade launcher to be used with the Z8 +/obj/item/weapon/gun/launcher/grenade/underslung + name = "underslung grenade launcher" + desc = "Not much more than a tube and a firing mechanism, this grenade launcher is designed to be fitted to a rifle." + w_class = ITEM_SIZE_NORMAL + force = 5 + max_grenades = 0 + +/obj/item/weapon/gun/launcher/grenade/underslung/attack_self() + return + +//load and unload directly into chambered +/obj/item/weapon/gun/launcher/grenade/underslung/load(obj/item/weapon/grenade/G, mob/user) + if(!can_load_grenade_type(G, user)) + return + + if(chambered) + to_chat(user, "\The [src] is already loaded.") + return + user.drop_from_inventory(G, src) + chambered = G + user.visible_message("\The [user] load \a [G] into \the [src].", "You load \a [G] into \the [src].") + +/obj/item/weapon/gun/launcher/grenade/underslung/unload(mob/user) + if(chambered) + user.put_in_hands(chambered) + user.visible_message("\The [user] removes \a [chambered] from \the[src].", "You remove \a [chambered] from \the [src].") + chambered = null + else + to_chat(user, "\The [src] is empty.") diff --git a/code/modules/projectiles/guns/launcher/money_cannon.dm b/code/modules/projectiles/guns/launcher/money_cannon.dm new file mode 100644 index 00000000..0372a0e8 --- /dev/null +++ b/code/modules/projectiles/guns/launcher/money_cannon.dm @@ -0,0 +1,165 @@ +/obj/item/weapon/gun/launcher/money + name = "money cannon" + desc = "A blocky, plastic novelty launcher that claims to be able to shoot credit at considerable velocities." + description_info = "Load money into the cannon by picking it up with the gun, or feeding it directly by hand. Use in your hand to configure how much money you want to fire per shot." + description_fluff = "These devices were invented several centuries ago and are a distinctly human cultural infection. They have produced knockoffs as timeless and as insipid as the potato gun and the paddle ball, showing up in all corners of the galaxy. The Money Cannon variation is noteworthy for its sturdiness and build quality, but is, at the end of the day, just another knockoff of the ancient originals." + description_antag = "Sliding a cryptographic sequencer into the receptacle will short the motors and override their speed. If you set the cannon to dispense 100 credit or more, this might make a handy weapon." + icon_state = "money_launcher" + item_state = "money_launcher" + origin_tech = list(TECH_COMBAT = 1, TECH_MATERIAL = 1) + slot_flags = SLOT_BELT + w_class = ITEM_SIZE_SMALL + release_force = 80 + fire_sound_text = "a whoosh and a crisp, papery rustle" + fire_delay = 1 + fire_sound = 'sound/weapons/gunshot/money_launcher.ogg' + var/emagged = 0 + + var/receptacle_value = 0 + var/dispensing = 20 + +/obj/item/weapon/gun/launcher/money/hacked + emagged = 1 + +/obj/item/weapon/gun/launcher/money/proc/vomit_cash(var/mob/vomit_onto, var/projectile_vomit) + var/bundle_worth = Floor(receptacle_value / 10) + var/turf/T = get_turf(vomit_onto) + for(var/i = 1 to 10) + var/nv = bundle_worth + if (i <= (receptacle_value - 10 * bundle_worth)) + nv++ + if (!nv) + break + var/obj/item/weapon/spacecash/bundle/bling = new(T) + bling.worth = nv + bling.update_icon() + if(projectile_vomit) + for(var/j = 1, j <= rand(2, 4), j++) + step(bling, pick(GLOB.cardinal)) + + if(projectile_vomit) + vomit_onto.AdjustStunned(3) + vomit_onto.AdjustWeakened(3) + vomit_onto.visible_message("\The [vomit_onto] blasts themselves full in the face with \the [src]!") + playsound(T, "sound/weapons/gunshot/money_launcher_jackpot.ogg", 100, 1) + else + vomit_onto.visible_message("\The [vomit_onto] ejects a few credit into their face.") + playsound(T, 'sound/weapons/gunshot/money_launcher.ogg', 100, 1) + + receptacle_value = 0 + +/obj/item/weapon/gun/launcher/money/proc/make_it_rain(var/mob/user) + vomit_cash(user, receptacle_value >= 10) + +/obj/item/weapon/gun/launcher/money/update_release_force() + if(!emagged) + release_force = 0 + return + + // Must launch at least 100 credit to incur damage. + release_force = dispensing / 100 + +/obj/item/weapon/gun/launcher/money/proc/unload_receptacle(mob/user) + if(receptacle_value < 1) + to_chat(user, "There's no money in [src].") + return + + var/obj/item/weapon/spacecash/bling = new /obj/item/weapon/spacecash/bundle() + bling.worth = receptacle_value + bling.update_icon() + user.put_in_hands(bling) + to_chat(user, "You eject [receptacle_value] credit from [src]'s receptacle.") + receptacle_value = 0 + +/obj/item/weapon/gun/launcher/money/proc/absorb_cash(var/obj/item/weapon/spacecash/bling, mob/user) + if(!istype(bling) || !bling.worth || bling.worth < 1) + to_chat(user, "[src] refuses to pick up [bling].") + return + + src.receptacle_value += bling.worth + to_chat(user, "You load [bling] into [src].") + user.drop_from_inventory(bling) + qdel(bling) + +/obj/item/weapon/gun/launcher/money/consume_next_projectile(mob/user=null) + if(!receptacle_value || receptacle_value < 1) + return null + + var/obj/item/weapon/spacecash/bling = new /obj/item/weapon/spacecash/bundle() + if(receptacle_value >= dispensing) + bling.worth = dispensing + receptacle_value -= dispensing + else + bling.worth = receptacle_value + receptacle_value = 0 + + bling.update_icon() + update_release_force(bling.worth) + if(release_force >= 1) + var/datum/effect/effect/system/spark_spread/s = new() + s.set_up(3, 1, src) + s.start() + + return bling + +/obj/item/weapon/gun/launcher/money/attack_self(mob/user as mob) + src.dispensing = min(input(user, "How many credit do you want to dispense at a time? (0 to [src.receptacle_value])", "Money Cannon Settings", 20) as num, receptacle_value) + + to_chat(user, "You set [src] to dispense [dispensing] credit at a time.") + +/obj/item/weapon/gun/launcher/money/attack_hand(mob/user as mob) + if(user.get_inactive_hand() == src) + unload_receptacle(user) + else + return ..() + +/obj/item/weapon/gun/launcher/money/attackby(obj/item/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/spacecash/)) + var/obj/item/weapon/spacecash/bling = W + if(bling.worth < 1) + to_chat(user, "You can't seem to get the bills to slide into the receptacle.") + return + + receptacle_value += bling.worth + to_chat(user, "You slide [bling.worth] credit into [src]'s receptacle.") + qdel(bling) + + else + to_chat(user, "That's not going to fit in there.") + +/obj/item/weapon/gun/launcher/money/examine(mob/user) + . = ..(user) + to_chat(user, "It is configured to dispense [dispensing] credit at a time.") + + if(receptacle_value >= 1) + to_chat(user, "The receptacle is loaded with [receptacle_value] credit.") + + else + to_chat(user, "The receptacle is empty.") + + if(emagged) + to_chat(user, "Its motors are severely overloaded.") + +/obj/item/weapon/gun/launcher/money/handle_suicide(mob/living/user) + if(!ishuman(user)) + return + + var/mob/living/carbon/human/M = user + M.visible_message("[user] sticks [src] in their mouth, ready to pull the trigger...") + + if(!do_after(user, 40, progress = 0)) + M.visible_message("[user] decided life was worth living.") + return + + src.make_it_rain(user) + +/obj/item/weapon/gun/launcher/money/emag_act(var/remaining_charges, var/mob/user) + // Overloads the motors, causing it to shoot money harder and do harm. + if(!emagged) + emagged = 1 + to_chat(user, "You slide the sequencer into [src]... only for it to spit it back out and emit a motorized squeal!") + var/datum/effect/effect/system/spark_spread/s = new() + s.set_up(3, 1, src) + s.start() + else + to_chat(user, "[src] seems to have been tampered with already.") \ No newline at end of file diff --git a/code/modules/projectiles/guns/launcher/net.dm b/code/modules/projectiles/guns/launcher/net.dm new file mode 100644 index 00000000..d6bac769 --- /dev/null +++ b/code/modules/projectiles/guns/launcher/net.dm @@ -0,0 +1,57 @@ +/obj/item/weapon/gun/launcher/net + name = "net gun" + desc = "Specially made-to-order by Xenonomix, the XX-1 \"Varmint Catcher\" is designed to trap even the most unruly of creatures for safe transport." + icon_state = "netgun" + item_state = "netgun" + fire_sound = 'sound/weapons/empty.ogg' + fire_sound_text = "a metallic thunk" + + var/obj/item/weapon/net_shell/chambered + +/obj/item/weapon/net_shell + name = "net gun shell" + desc = "A casing containing an autodeploying net for use in a net gun. Kind of looks like a flash light." + icon = 'icons/obj/ammo.dmi' + icon_state = "netshell" + +/obj/item/weapon/gun/launcher/net/examine(mob/user) + if(..(user, 2)) + if(chambered) + to_chat(user, "\A [chambered] is chambered.") + +/obj/item/weapon/gun/launcher/net/proc/load(obj/item/weapon/net_shell/S, mob/user) + if(chambered) + to_chat(user, "\The [src] already has a shell loaded.") + return + + user.drop_from_inventory(S, src) + chambered = S + user.visible_message("\The [user] inserts \a [S] into \the [src].", "You insert \a [S] into \the [src].") + +/obj/item/weapon/gun/launcher/net/proc/unload(mob/user) + if(chambered) + user.visible_message("\The [user] removes \the [chambered] from \the [src].", "You remove \the [chambered] from \the [src].") + user.put_in_hands(chambered) + chambered = null + else + to_chat(user, "\The [src] is empty.") + +/obj/item/weapon/gun/launcher/net/attackby(obj/item/I, mob/user) + if((istype(I, /obj/item/weapon/net_shell))) + load(I, user) + else + ..() + +/obj/item/weapon/gun/launcher/net/attack_hand(mob/user) + if(user.get_inactive_hand() == src) + unload(user) + else + ..() + +/obj/item/weapon/gun/launcher/net/consume_next_projectile() + if(chambered) + qdel(chambered) + chambered = null + return new /obj/item/weapon/energy_net/safari(src) + + return null diff --git a/code/modules/projectiles/guns/launcher/pneumatic.dm b/code/modules/projectiles/guns/launcher/pneumatic.dm new file mode 100644 index 00000000..b3f9e1d4 --- /dev/null +++ b/code/modules/projectiles/guns/launcher/pneumatic.dm @@ -0,0 +1,219 @@ +/obj/item/weapon/gun/launcher/pneumatic + name = "pneumatic cannon" + desc = "A large gas-powered cannon." + icon_state = "pneumatic" + item_state = "pneumatic" + origin_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3) + slot_flags = SLOT_BELT + w_class = ITEM_SIZE_HUGE + obj_flags = OBJ_FLAG_CONDUCTIBLE + fire_sound_text = "a loud whoosh of moving air" + fire_delay = 50 + fire_sound = 'sound/weapons/tablehit1.ogg' + + var/fire_pressure // Used in fire checks/pressure checks. + var/max_w_class = ITEM_SIZE_NORMAL // Hopper intake size. + var/max_storage_space = DEFAULT_BOX_STORAGE // Total internal storage size. + var/obj/item/weapon/tank/tank = null // Tank of gas for use in firing the cannon. + + var/obj/item/weapon/storage/item_storage + var/pressure_setting = 10 // Percentage of the gas in the tank used to fire the projectile. + var/possible_pressure_amounts = list(5,10,20,25,50) // Possible pressure settings. + var/force_divisor = 400 // Force equates to speed. Speed/5 equates to a damage multiplier for whoever you hit. + // For reference, a fully pressurized oxy tank at 50% gas release firing a health + // analyzer with a force_divisor of 10 hit with a damage multiplier of 3000+. +/obj/item/weapon/gun/launcher/pneumatic/New() + ..() + item_storage = new(src) + item_storage.SetName("hopper") + item_storage.max_w_class = max_w_class + item_storage.max_storage_space = max_storage_space + item_storage.use_sound = null + +/obj/item/weapon/gun/launcher/pneumatic/verb/set_pressure() //set amount of tank pressure. + set name = "Set Valve Pressure" + set category = "Object" + set src in range(0) + var/N = input("Percentage of tank used per shot:","[src]") as null|anything in possible_pressure_amounts + if (N) + pressure_setting = N + to_chat(usr, "You dial the pressure valve to [pressure_setting]%.") + +/obj/item/weapon/gun/launcher/pneumatic/proc/eject_tank(mob/user) //Remove the tank. + if(!tank) + to_chat(user, "There's no tank in [src].") + return + + to_chat(user, "You twist the valve and pop the tank out of [src].") + user.put_in_hands(tank) + tank = null + update_icon() + +/obj/item/weapon/gun/launcher/pneumatic/proc/unload_hopper(mob/user) + if(item_storage.contents.len > 0) + var/obj/item/removing = item_storage.contents[item_storage.contents.len] + item_storage.remove_from_storage(removing, src.loc) + user.put_in_hands(removing) + to_chat(user, "You remove [removing] from the hopper.") + else + to_chat(user, "There is nothing to remove in \the [src].") + +/obj/item/weapon/gun/launcher/pneumatic/attack_hand(mob/user as mob) + if(user.get_inactive_hand() == src) + unload_hopper(user) + else + return ..() + +/obj/item/weapon/gun/launcher/pneumatic/attackby(obj/item/W as obj, mob/user as mob) + if(!tank && istype(W,/obj/item/weapon/tank)) + user.drop_from_inventory(W, src) + tank = W + user.visible_message("[user] jams [W] into [src]'s valve and twists it closed.","You jam [W] into [src]'s valve and twist it closed.") + update_icon() + else if(istype(W) && item_storage.can_be_inserted(W, user)) + item_storage.handle_item_insertion(W) + +/obj/item/weapon/gun/launcher/pneumatic/attack_self(mob/user as mob) + eject_tank(user) + +/obj/item/weapon/gun/launcher/pneumatic/consume_next_projectile(mob/user=null) + if(!item_storage.contents.len) + return null + if (!tank) + to_chat(user, "There is no gas tank in [src]!") + return null + + var/environment_pressure = 10 + var/turf/T = get_turf(src) + if(T) + var/datum/gas_mixture/environment = T.return_air() + if(environment) + environment_pressure = environment.return_pressure() + + fire_pressure = (tank.air_contents.return_pressure() - environment_pressure)*pressure_setting/100 + if(fire_pressure < 10) + to_chat(user, "There isn't enough gas in the tank to fire [src].") + return null + + var/obj/item/launched = item_storage.contents[1] + item_storage.remove_from_storage(launched, src) + return launched + +/obj/item/weapon/gun/launcher/pneumatic/examine(mob/user) + if(!..(user, 2)) + return + to_chat(user, "The valve is dialed to [pressure_setting]%.") + if(tank) + to_chat(user, "The tank dial reads [tank.air_contents.return_pressure()] kPa.") + else + to_chat(user, "Nothing is attached to the tank valve!") + +/obj/item/weapon/gun/launcher/pneumatic/update_release_force(obj/item/projectile) + if(tank) + release_force = ((fire_pressure*tank.volume)/projectile.w_class)/force_divisor //projectile speed. + if(release_force > 80) release_force = 80 //damage cap. + else + release_force = 0 + +/obj/item/weapon/gun/launcher/pneumatic/handle_post_fire() + if(tank) + var/lost_gas_amount = tank.air_contents.total_moles*(pressure_setting/100) + var/datum/gas_mixture/removed = tank.air_contents.remove(lost_gas_amount) + + var/turf/T = get_turf(src.loc) + if(T) T.assume_air(removed) + ..() + +/obj/item/weapon/gun/launcher/pneumatic/update_icon() + if(tank) + icon_state = "pneumatic-tank" + item_state = "pneumatic-tank" + else + icon_state = "pneumatic" + item_state = "pneumatic" + + update_held_icon() + +//Constructable pneumatic cannon. + +/obj/item/weapon/cannonframe + name = "pneumatic cannon frame" + desc = "A half-finished pneumatic cannon." + icon_state = "pneumatic0" + item_state = "pneumatic" + + var/buildstate = 0 + +/obj/item/weapon/cannonframe/update_icon() + icon_state = "pneumatic[buildstate]" + +/obj/item/weapon/cannonframe/examine(mob/user) + . = ..(user) + switch(buildstate) + if(1) to_chat(user, "It has a pipe segment installed.") + if(2) to_chat(user, "It has a pipe segment welded in place.") + if(3) to_chat(user, "It has an outer chassis installed.") + if(4) to_chat(user, "It has an outer chassis welded in place.") + if(5) to_chat(user, "It has a transfer valve installed.") + +/obj/item/weapon/cannonframe/attackby(obj/item/W as obj, mob/user as mob) + if(istype(W,/obj/item/pipe)) + if(buildstate == 0) + user.drop_from_inventory(W) + qdel(W) + to_chat(user, "You secure the piping inside the frame.") + buildstate++ + update_icon() + return + else if(istype(W,/obj/item/stack/material) && W.get_material_name() == DEFAULT_WALL_MATERIAL) + if(buildstate == 2) + var/obj/item/stack/material/M = W + if(M.use(5)) + to_chat(user, "You assemble a chassis around the cannon frame.") + buildstate++ + update_icon() + else + to_chat(user, "You need at least five metal sheets to complete this task.") + return + else if(istype(W,/obj/item/device/transfer_valve)) + if(buildstate == 4) + user.drop_from_inventory(W) + qdel(W) + to_chat(user, "You install the transfer valve and connect it to the piping.") + buildstate++ + update_icon() + return + else if(isWelder(W)) + if(buildstate == 1) + var/obj/item/weapon/weldingtool/T = W + if(T.remove_fuel(0,user)) + if(!src || !T.isOn()) return + playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) + to_chat(user, "You weld the pipe into place.") + buildstate++ + update_icon() + if(buildstate == 3) + var/obj/item/weapon/weldingtool/T = W + if(T.remove_fuel(0,user)) + if(!src || !T.isOn()) return + playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) + to_chat(user, "You weld the metal chassis together.") + buildstate++ + update_icon() + if(buildstate == 5) + var/obj/item/weapon/weldingtool/T = W + if(T.remove_fuel(0,user)) + if(!src || !T.isOn()) return + playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) + to_chat(user, "You weld the valve into place.") + new /obj/item/weapon/gun/launcher/pneumatic(get_turf(src)) + qdel(src) + return + else + ..() + +/obj/item/weapon/gun/launcher/pneumatic/small + name = "small pneumatic cannon" + desc = "It looks smaller than your garden variety cannon" + max_w_class = ITEM_SIZE_TINY + w_class = ITEM_SIZE_NORMAL \ No newline at end of file diff --git a/code/modules/projectiles/guns/launcher/rocket.dm b/code/modules/projectiles/guns/launcher/rocket.dm new file mode 100644 index 00000000..fff877c0 --- /dev/null +++ b/code/modules/projectiles/guns/launcher/rocket.dm @@ -0,0 +1,48 @@ +/obj/item/weapon/gun/launcher/rocket + name = "rocket launcher" + desc = "MAGGOT." + icon_state = "rocket" + item_state = "rocket" + w_class = ITEM_SIZE_HUGE + throw_speed = 2 + throw_range = 10 + force = 5.0 + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = 0 + origin_tech = list(TECH_COMBAT = 8, TECH_MATERIAL = 5) + fire_sound = 'sound/effects/bang.ogg' + combustion = 1 + + release_force = 15 + throw_distance = 30 + var/max_rockets = 1 + var/list/rockets = new/list() + +/obj/item/weapon/gun/launcher/rocket/examine(mob/user) + if(!..(user, 2)) + return + to_chat(user, "[rockets.len] / [max_rockets] rockets.") + +/obj/item/weapon/gun/launcher/rocket/attackby(obj/item/I as obj, mob/user as mob) + if(istype(I, /obj/item/ammo_casing/rocket)) + if(rockets.len < max_rockets) + user.drop_item() + I.loc = src + rockets += I + to_chat(user, "You put the rocket in [src].") + to_chat(user, "[rockets.len] / [max_rockets] rockets.") + else + to_chat(usr, "\The [src] cannot hold more rockets.") + +/obj/item/weapon/gun/launcher/rocket/consume_next_projectile() + if(rockets.len) + var/obj/item/ammo_casing/rocket/I = rockets[1] + var/obj/item/missile/M = new (src) + M.primed = 1 + rockets -= I + return M + return null + +/obj/item/weapon/gun/launcher/rocket/handle_post_fire(mob/user, atom/target) + log_and_message_admins("fired a rocket from a rocket launcher ([src.name]) at [target].") + ..() diff --git a/code/modules/projectiles/guns/launcher/slugsling.dm b/code/modules/projectiles/guns/launcher/slugsling.dm new file mode 100644 index 00000000..139b4704 --- /dev/null +++ b/code/modules/projectiles/guns/launcher/slugsling.dm @@ -0,0 +1,66 @@ +/obj/item/weapon/slugegg + name = "slugegg" + desc = "A pulsing, disgusting door to new life." + force = 1 + throwforce = 6 + icon_state = "slugegg" + var/break_on_impact = 1 //There are two modes to the eggs. + //One breaks the egg on hit, + +/obj/item/weapon/slugegg/throw_impact(atom/hit_atom, var/speed) + if(break_on_impact) + squish() + else + movable_flags |= MOVABLE_FLAG_PROXMOVE //Dont want it active during the throw... loooots of unneeded checking. + return ..() + +/obj/item/weapon/slugegg/attack_self(var/mob/living/user) + user.drop_from_inventory(src) + squish() + +/obj/item/weapon/slugegg/HasProximity(var/atom/movable/AM) + if(isliving(AM)) + if(istype(AM,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = AM + if(H.species && H.species.get_bodytype() == SPECIES_VOX) + return + else + var/mob/living/L = AM + if(L.faction == SPECIES_VOX) + return + squish() + +/obj/item/weapon/slugegg/proc/squish() + src.visible_message("\The [src] bursts open!") + new /mob/living/simple_animal/hostile/voxslug(get_turf(src)) + playsound(src.loc,'sound/effects/attackblob.ogg',100, 1) + qdel(src) + +//a slug sling basically launches a small egg that hatches (either on a person or on the floor), releasing a terrible blood thirsty monster. +//Balanced due to the non-spammy nature of the gun, as well as the frailty of the creatures. +/obj/item/weapon/gun/launcher/alien/slugsling + name = "slug sling" + desc = "A bulbous looking rifle. It feels like holding a plastic bag full of meat." + w_class = ITEM_SIZE_LARGE + icon_state = "slugsling" + item_state = "spikethrower" + fire_sound_text = "a strange noise" + fire_sound = 'sound/weapons/towelwhip.ogg' + release_force = 6 + ammo_name = "slug" + ammo_type = /obj/item/weapon/slugegg + max_ammo = 2 + ammo = 2 + ammo_gen_time = 200 + var/mode = "Impact" + +/obj/item/weapon/gun/launcher/alien/slugsling/consume_next_projectile() + var/obj/item/weapon/slugegg/S = ..() + if(S) + S.break_on_impact = (mode == "Impact") + return S + + +/obj/item/weapon/gun/launcher/alien/slugsling/attack_self(var/mob/living/user) + mode = mode == "Impact" ? "Sentry" : "Impact" + to_chat(user,"You switch \the [src]'s mode to \"[mode]\"") \ No newline at end of file diff --git a/code/modules/projectiles/guns/launcher/syringe_gun.dm b/code/modules/projectiles/guns/launcher/syringe_gun.dm new file mode 100644 index 00000000..4fe1669a --- /dev/null +++ b/code/modules/projectiles/guns/launcher/syringe_gun.dm @@ -0,0 +1,153 @@ +/obj/item/weapon/syringe_cartridge + name = "syringe gun cartridge" + desc = "An impact-triggered compressed gas cartridge that can be fitted to a syringe for rapid injection." + icon = 'icons/obj/ammo.dmi' + icon_state = "syringe-cartridge" + var/icon_flight = "syringe-cartridge-flight" //so it doesn't look so weird when shot + matter = list(DEFAULT_WALL_MATERIAL = 125, "glass" = 375) + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT | SLOT_EARS + throwforce = 3 + force = 3 + w_class = ITEM_SIZE_TINY + var/obj/item/weapon/reagent_containers/syringe/syringe + +/obj/item/weapon/syringe_cartridge/update_icon() + underlays.Cut() + if(syringe) + underlays += image(syringe.icon, src, syringe.icon_state) + underlays += syringe.filling + +/obj/item/weapon/syringe_cartridge/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/weapon/reagent_containers/syringe)) + syringe = I + to_chat(user, "You carefully insert [syringe] into [src].") + user.remove_from_mob(syringe) + syringe.loc = src + sharp = 1 + name = "syringe dart" + update_icon() + +/obj/item/weapon/syringe_cartridge/attack_self(mob/user) + if(syringe) + to_chat(user, "You remove [syringe] from [src].") + user.put_in_hands(syringe) + syringe = null + sharp = initial(sharp) + SetName(initial(name)) + update_icon() + +/obj/item/weapon/syringe_cartridge/proc/prime() + //the icon state will revert back when update_icon() is called from throw_impact() + icon_state = icon_flight + underlays.Cut() + +/obj/item/weapon/syringe_cartridge/throw_impact(atom/hit_atom, var/speed) + ..() //handles embedding for us. Should have a decent chance if thrown fast enough + if(syringe) + //check speed to see if we hit hard enough to trigger the rapid injection + //incidentally, this means syringe_cartridges can be used with the pneumatic launcher + if(speed >= 10 && isliving(hit_atom)) + var/mob/living/L = hit_atom + //unfortuately we don't know where the dart will actually hit, since that's done by the parent. + if(L.can_inject(null, ran_zone()) && syringe.reagents) + var/reagent_log = syringe.reagents.get_reagents() + syringe.reagents.trans_to_mob(L, 15, CHEM_BLOOD) + admin_inject_log(thrower, L, src, reagent_log, 15, violent=1) + + syringe.break_syringe(iscarbon(hit_atom)? hit_atom : null) + syringe.update_icon() + + icon_state = initial(icon_state) //reset icon state + update_icon() + +/obj/item/weapon/gun/launcher/syringe + name = "syringe gun" + desc = "A spring loaded rifle designed to fit syringes, designed to incapacitate unruly patients from a distance." + icon_state = "syringegun" + item_state = "syringegun" + w_class = ITEM_SIZE_LARGE + force = 7 + matter = list(DEFAULT_WALL_MATERIAL = 2000) + slot_flags = SLOT_BELT + + fire_sound = 'sound/weapons/empty.ogg' + fire_sound_text = "a metallic thunk" + screen_shake = 0 + release_force = 10 + throw_distance = 10 + + var/list/darts = list() + var/max_darts = 1 + var/obj/item/weapon/syringe_cartridge/next + +/obj/item/weapon/gun/launcher/syringe/consume_next_projectile() + if(next) + next.prime() + return next + return null + +/obj/item/weapon/gun/launcher/syringe/handle_post_fire() + ..() + darts -= next + next = null + +/obj/item/weapon/gun/launcher/syringe/attack_self(mob/living/user as mob) + if(next) + user.visible_message("[user] unlatches and carefully relaxes the bolt on [src].", "You unlatch and carefully relax the bolt on [src], unloading the spring.") + next = null + else if(darts.len) + playsound(src.loc, 'sound/weapons/flipblade.ogg', 50, 1) + user.visible_message("[user] draws back the bolt on [src], clicking it into place.", "You draw back the bolt on the [src], loading the spring!") + next = darts[1] + add_fingerprint(user) + +/obj/item/weapon/gun/launcher/syringe/attack_hand(mob/living/user as mob) + if(user.get_inactive_hand() == src) + if(!darts.len) + to_chat(user, "[src] is empty.") + return + if(next) + to_chat(user, "[src]'s cover is locked shut.") + return + var/obj/item/weapon/syringe_cartridge/C = darts[1] + darts -= C + user.put_in_hands(C) + user.visible_message("[user] removes \a [C] from [src].", "You remove \a [C] from [src].") + else + ..() + +/obj/item/weapon/gun/launcher/syringe/attackby(var/obj/item/A as obj, mob/user as mob) + if(istype(A, /obj/item/weapon/syringe_cartridge)) + var/obj/item/weapon/syringe_cartridge/C = A + if(darts.len >= max_darts) + to_chat(user, "[src] is full!") + return + user.remove_from_mob(C) + C.loc = src + darts += C //add to the end + user.visible_message("[user] inserts \a [C] into [src].", "You insert \a [C] into [src].") + else + ..() + +/obj/item/weapon/gun/launcher/syringe/rapid + name = "syringe gun revolver" + desc = "A modification of the syringe gun design, using a rotating cylinder to store up to five syringes. The spring still needs to be drawn between shots." + icon_state = "rapidsyringegun" + item_state = "rapidsyringegun" + max_darts = 5 + +/obj/item/weapon/gun/launcher/syringe/disguised + name = "deluxe electronic cigarette" + desc = "A premium model eGavana MK3 electronic cigarette, shaped like a cigar." + icon = 'icons/obj/ecig.dmi' + icon_state = "pcigoff1" + item_state = "pcigoff1" + w_class = ITEM_SIZE_SMALL + force = 3 + throw_distance = 7 + release_force = 7 + +/obj/item/weapon/gun/launcher/syringe/disguised/examine(mob/user) + if(( . = ..(user, 0))) + to_chat(user, "The button is a little stiff.") \ No newline at end of file diff --git a/code/modules/projectiles/guns/magnetic/magnetic.dm b/code/modules/projectiles/guns/magnetic/magnetic.dm new file mode 100644 index 00000000..1d8c0bc7 --- /dev/null +++ b/code/modules/projectiles/guns/magnetic/magnetic.dm @@ -0,0 +1,194 @@ +/obj/item/weapon/gun/magnetic + name = "improvised coilgun" + desc = "A coilgun hastily thrown together out of a basic frame and advanced power storage components. Is it safe for it to be duct-taped together like that?" + icon_state = "coilgun" + item_state = "coilgun" + icon = 'icons/obj/railgun.dmi' + one_hand_penalty = 1 + origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 4, TECH_ILLEGAL = 2, TECH_MAGNET = 4) + w_class = ITEM_SIZE_LARGE + combustion = 1 + + var/obj/item/weapon/cell/cell // Currently installed powercell. + var/obj/item/weapon/stock_parts/capacitor/capacitor // Installed capacitor. Higher rating == faster charge between shots. + var/removable_components = TRUE // Whether or not the gun can be dismantled. + var/gun_unreliable = 15 // Percentage chance of detonating in your hands. + + var/obj/item/loaded // Currently loaded object, for retrieval/unloading. + var/load_type = /obj/item/stack/rods // Type of stack to load with. + var/projectile_type = /obj/item/projectile/bullet/magnetic // Actual fire type, since this isn't throw_at rod launcher. + + var/power_cost = 950 // Cost per fire, should consume almost an entire basic cell. + var/power_per_tick // Capacitor charge per process(). Updated based on capacitor rating. + +/obj/item/weapon/gun/magnetic/Initialize() + START_PROCESSING(SSobj, src) + if(capacitor) + power_per_tick = (power_cost*0.15) * capacitor.rating + update_icon() + . = ..() + +/obj/item/weapon/gun/magnetic/Destroy() + STOP_PROCESSING(SSobj, src) + QDEL_NULL(cell) + QDEL_NULL(loaded) + QDEL_NULL(capacitor) + . = ..() + +/obj/item/weapon/gun/magnetic/Process() + if(capacitor) + if(cell) + if(capacitor.charge < capacitor.max_charge && cell.checked_use(power_per_tick)) + capacitor.charge(power_per_tick) + else + capacitor.use(capacitor.charge * 0.05) + update_icon() + +/obj/item/weapon/gun/magnetic/update_icon() + var/list/overlays_to_add = list() + if(removable_components) + if(cell) + overlays_to_add += image(icon, "[icon_state]_cell") + if(capacitor) + overlays_to_add += image(icon, "[icon_state]_capacitor") + if(!cell || !capacitor) + overlays_to_add += image(icon, "[icon_state]_red") + else if(capacitor.charge < power_cost) + overlays_to_add += image(icon, "[icon_state]_amber") + else + overlays_to_add += image(icon, "[icon_state]_green") + if(loaded) + overlays_to_add += image(icon, "[icon_state]_loaded") + + overlays = overlays_to_add + ..() + +/obj/item/weapon/gun/magnetic/proc/show_ammo(var/mob/user) + if(loaded) + to_chat(user, "It has \a [loaded] loaded.") + +/obj/item/weapon/gun/magnetic/examine(var/mob/user) + . = ..(user, 2) + if(.) + show_ammo(user) + + if(cell) + to_chat(user, "The installed [cell.name] has a charge level of [round((cell.charge/cell.maxcharge)*100)]%.") + if(capacitor) + to_chat(user, "The installed [capacitor.name] has a charge level of [round((capacitor.charge/capacitor.max_charge)*100)]%.") + + if(!cell || !capacitor) + to_chat(user, "The capacitor charge indicator is blinking red. Maybe you should check the cell or capacitor.") + else + if(capacitor.charge < power_cost) + to_chat(user, "The capacitor charge indicator is amber.") + else + to_chat(user, "The capacitor charge indicator is green.") + return TRUE + +/obj/item/weapon/gun/magnetic/attackby(var/obj/item/thing, var/mob/user) + + if(removable_components) + if(istype(thing, /obj/item/weapon/cell)) + if(cell) + to_chat(user, "\The [src] already has \a [cell] installed.") + return + cell = thing + user.drop_from_inventory(cell) + cell.forceMove(src) + playsound(loc, 'sound/machines/click.ogg', 10, 1) + user.visible_message("\The [user] slots \the [cell] into \the [src].") + update_icon() + return + + if(isScrewdriver(thing)) + if(!capacitor) + to_chat(user, "\The [src] has no capacitor installed.") + return + capacitor.forceMove(get_turf(src)) + user.put_in_hands(capacitor) + user.visible_message("\The [user] unscrews \the [capacitor] from \the [src].") + playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) + capacitor = null + update_icon() + return + + if(istype(thing, /obj/item/weapon/stock_parts/capacitor)) + if(capacitor) + to_chat(user, "\The [src] already has \a [capacitor] installed.") + return + capacitor = thing + user.drop_from_inventory(capacitor) + capacitor.forceMove(src) + playsound(loc, 'sound/machines/click.ogg', 10, 1) + power_per_tick = (power_cost*0.15) * capacitor.rating + user.visible_message("\The [user] slots \the [capacitor] into \the [src].") + update_icon() + return + + if(istype(thing, load_type)) + + if(loaded) + to_chat(user, "\The [src] already has \a [loaded] loaded.") + return + + // This is not strictly necessary for the magnetic gun but something using + // specific ammo types may exist down the track. + var/obj/item/stack/ammo = thing + if(!istype(ammo)) + loaded = thing + user.drop_from_inventory(thing) + thing.forceMove(src) + else + loaded = new load_type(src, 1) + ammo.use(1) + + user.visible_message("\The [user] loads \the [src] with \the [loaded].") + playsound(loc, 'sound/weapons/flipblade.ogg', 50, 1) + update_icon() + return + . = ..() + +/obj/item/weapon/gun/magnetic/attack_hand(var/mob/user) + if(user.get_inactive_hand() == src) + var/obj/item/removing + + if(loaded) + removing = loaded + loaded = null + else if(cell && removable_components) + removing = cell + cell = null + + if(removing) + removing.forceMove(get_turf(src)) + user.put_in_hands(removing) + user.visible_message("\The [user] removes \the [removing] from \the [src].") + playsound(loc, 'sound/machines/click.ogg', 10, 1) + update_icon() + return + . = ..() + +/obj/item/weapon/gun/magnetic/proc/check_ammo() + return loaded + +/obj/item/weapon/gun/magnetic/proc/use_ammo() + qdel(loaded) + loaded = null + +/obj/item/weapon/gun/magnetic/consume_next_projectile() + + if(!check_ammo() || !capacitor || capacitor.charge < power_cost) + return + + use_ammo() + capacitor.use(power_cost) + update_icon() + + if(gun_unreliable && prob(gun_unreliable)) + spawn(3) // So that it will still fire - considered modifying Fire() to return a value but burst fire makes that annoying. + visible_message("\The [src] explodes with the force of the shot!") + explosion(get_turf(src), -1, 0, 2) + qdel(src) + + return new projectile_type(src) diff --git a/code/modules/projectiles/guns/magnetic/magnetic_construction.dm b/code/modules/projectiles/guns/magnetic/magnetic_construction.dm new file mode 100644 index 00000000..7221752e --- /dev/null +++ b/code/modules/projectiles/guns/magnetic/magnetic_construction.dm @@ -0,0 +1,101 @@ +// We really need some datums for this. +/obj/item/weapon/coilgun_assembly + name = "coilgun stock" + desc = "It might be a coilgun, someday." + icon = 'icons/obj/coilgun.dmi' + icon_state = "coilgun_construction_1" + + var/construction_stage = 1 + +/obj/item/weapon/coilgun_assembly/attackby(var/obj/item/thing, var/mob/user) + + if(istype(thing, /obj/item/stack/material) && construction_stage == 1) + var/obj/item/stack/material/reinforcing = thing + var/material/reinforcing_with = reinforcing.get_material() + if(reinforcing_with.name == DEFAULT_WALL_MATERIAL) // Steel + if(reinforcing.get_amount() < 5) + to_chat(user, "You need at least 5 [reinforcing.singular_name]\s for this task.") + return + reinforcing.use(5) + user.visible_message("\The [user] shapes some steel sheets around \the [src] to form a body.") + increment_construction_stage() + return + + if(istype(thing, /obj/item/weapon/tape_roll) && construction_stage == 2) + user.visible_message("\The [user] secures \the [src] together with \the [thing].") + increment_construction_stage() + return + + if(istype(thing, /obj/item/pipe) && construction_stage == 3) + user.drop_from_inventory(thing) + qdel(thing) + user.visible_message("\The [user] jams \the [thing] into \the [src].") + increment_construction_stage() + return + + if(isWelder(thing) && construction_stage == 4) + var/obj/item/weapon/weldingtool/welder = thing + + if(!welder.isOn()) + to_chat(user, "Turn it on first!") + return + + if(!welder.remove_fuel(0,user)) + to_chat(user, "You need more fuel!") + return + + user.visible_message("\The [user] welds the barrel of \the [src] into place.") + playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) + increment_construction_stage() + return + + if(isCoil(thing) && construction_stage == 5) + var/obj/item/stack/cable_coil/cable = thing + if(cable.get_amount() < 5) + to_chat(user, "You need at least 5 lengths of cable for this task.") + return + cable.use(5) + user.visible_message("\The [user] wires \the [src].") + increment_construction_stage() + return + + if(istype(thing, /obj/item/weapon/smes_coil) && construction_stage >= 6 && construction_stage <= 8) + user.visible_message("\The [user] installs \a [thing] into \the [src].") + user.drop_from_inventory(thing) + qdel(thing) + increment_construction_stage() + return + + if(isScrewdriver(thing) && construction_stage >= 9) + user.visible_message("\The [user] secures \the [src] and finishes it off.") + playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) + var/obj/item/weapon/gun/magnetic/coilgun = new(loc) + var/put_in_hands + var/mob/M = src.loc + if(istype(M)) + put_in_hands = M == user + M.drop_from_inventory(src) + if(put_in_hands) + user.put_in_hands(coilgun) + qdel(src) + return + + return ..() + +/obj/item/weapon/coilgun_assembly/proc/increment_construction_stage() + if(construction_stage < 9) + construction_stage++ + icon_state = "coilgun_construction_[construction_stage]" + +/obj/item/weapon/coilgun_assembly/examine(var/mob/user) + . = ..(user,2) + if(.) + switch(construction_stage) + if(2) to_chat(user, "It has a metal frame loosely shaped around the stock.") + if(3) to_chat(user, "It has a metal frame duct-taped to the stock.") + if(4) to_chat(user, "It has a length of pipe attached to the body.") + if(4) to_chat(user, "It has a length of pipe welded to the body.") + if(6) to_chat(user, "It has a cable mount and capacitor jack wired to the frame.") + if(7) to_chat(user, "It has a single superconducting coil threaded onto the barrel.") + if(8) to_chat(user, "It has a pair of superconducting coils threaded onto the barrel.") + if(9) to_chat(user, "It has three superconducting coils attached to the body, waiting to be secured.") diff --git a/code/modules/projectiles/guns/magnetic/magnetic_railgun.dm b/code/modules/projectiles/guns/magnetic/magnetic_railgun.dm new file mode 100644 index 00000000..374ea1f3 --- /dev/null +++ b/code/modules/projectiles/guns/magnetic/magnetic_railgun.dm @@ -0,0 +1,110 @@ +/obj/item/weapon/gun/magnetic/railgun + name = "railgun" + desc = "The Mars Military Industries MI-76 Thunderclap. A man-portable mass driver for squad support anti-armour and destruction of fortifications and emplacements." + gun_unreliable = 0 + icon_state = "railgun" + removable_components = FALSE + load_type = /obj/item/weapon/rcd_ammo + origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 4, TECH_MAGNET = 4) + projectile_type = /obj/item/projectile/bullet/magnetic/slug + power_cost = 300 + w_class = ITEM_SIZE_HUGE + slot_flags = SLOT_BELT + loaded = /obj/item/weapon/rcd_ammo/large + combustion = 1 + + var/initial_cell_type = /obj/item/weapon/cell/hyper + var/initial_capacitor_type = /obj/item/weapon/stock_parts/capacitor/adv + var/slowdown_held = 2 + var/slowdown_worn = 1 + +/obj/item/weapon/gun/magnetic/railgun/Initialize() + + capacitor = new initial_capacitor_type(src) + capacitor.charge = capacitor.max_charge + + cell = new initial_cell_type(src) + if (ispath(loaded)) + loaded = new loaded + slowdown_per_slot[slot_l_hand] = slowdown_held + slowdown_per_slot[slot_r_hand] = slowdown_held + slowdown_per_slot[slot_back] = slowdown_worn + slowdown_per_slot[slot_belt] = slowdown_worn + slowdown_per_slot[slot_s_store] = slowdown_worn + + . = ..() + +// Not going to check type repeatedly, if you code or varedit +// load_type and get runtime errors, don't come crying to me. +/obj/item/weapon/gun/magnetic/railgun/show_ammo(var/mob/user) + var/obj/item/weapon/rcd_ammo/ammo = loaded + if (ammo) + to_chat(user, "There are [ammo.remaining] shot\s remaining in \the [loaded].") + else + to_chat(user, "There is nothing loaded.") + +/obj/item/weapon/gun/magnetic/railgun/check_ammo() + var/obj/item/weapon/rcd_ammo/ammo = loaded + return ammo && ammo.remaining + +/obj/item/weapon/gun/magnetic/railgun/use_ammo() + var/obj/item/weapon/rcd_ammo/ammo = loaded + ammo.remaining-- + if(ammo.remaining <= 0) + spawn(3) + playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 1) + out_of_ammo() + +/obj/item/weapon/gun/magnetic/railgun/proc/out_of_ammo() + qdel(loaded) + loaded = null + visible_message("\The [src] beeps and ejects its empty cartridge.") + +/obj/item/weapon/gun/magnetic/railgun/automatic // Adminspawn only, this shit is absurd. + name = "\improper RHR accelerator" + desc = "The Mars Military Industries MI-227 Meteor. Originally a vehicle-mounted turret weapon for heavy anti-vehicular and anti-structural fire, the fact that it was made man-portable is mindboggling in itself." + icon_state = "heavy_railgun" + + initial_cell_type = /obj/item/weapon/cell/infinite + initial_capacitor_type = /obj/item/weapon/stock_parts/capacitor/super + + slowdown_held = 3 + slowdown_worn = 2 + + slot_flags = SLOT_BACK + w_class = ITEM_SIZE_NO_CONTAINER + + firemodes = list( + list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, one_hand_penalty=1, burst_accuracy=null, dispersion=null), + list(mode_name="short bursts", burst=3, fire_delay=null, move_delay=5, one_hand_penalty=2, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0)), + list(mode_name="long bursts", burst=6, fire_delay=null, move_delay=10, one_hand_penalty=2, burst_accuracy=list(0,-1,-1,-1,-2), dispersion=list(0.6, 0.6, 1.0, 1.0, 1.2)), + ) + +/obj/item/weapon/gun/magnetic/railgun/automatic/examine(var/mob/user) + . = ..(user,1) + if(.) + to_chat(user, "Someone has scratched Ultima Ratio Regum onto the side of the barrel.") + +/obj/item/weapon/gun/magnetic/railgun/flechette + name = "flechette gun" + desc = "The MI-12 Skadi is a burst fire capable railgun that fires flechette rounds at high velocity. Deadly against armour, but much less effective against soft targets." + icon_state = "flechette_gun" + item_state = "z8carbine" + initial_cell_type = /obj/item/weapon/cell/hyper + initial_capacitor_type = /obj/item/weapon/stock_parts/capacitor/adv + slot_flags = SLOT_BACK + slowdown_held = 0 + slowdown_worn = 0 + power_cost = 100 + load_type = /obj/item/weapon/magnetic_ammo + projectile_type = /obj/item/projectile/bullet/magnetic/flechette + loaded = /obj/item/weapon/magnetic_ammo + wielded_item_state = "z8carbine-wielded" + + firemodes = list( + list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, one_hand_penalty=1, burst_accuracy=null, dispersion=null), + list(mode_name="short bursts", burst=3, fire_delay=null, move_delay=5, one_hand_penalty=2, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0)), + ) + +/obj/item/weapon/gun/magnetic/railgun/flechette/out_of_ammo() + visible_message("\The [src] beeps to indicate the magazine is empty.") diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm new file mode 100644 index 00000000..a4fd5389 --- /dev/null +++ b/code/modules/projectiles/guns/projectile.dm @@ -0,0 +1,510 @@ +#define HOLD_CASINGS 0 //do not do anything after firing. Manual action, like pump shotguns, or guns that want to define custom behaviour +#define CLEAR_CASINGS 1 //clear chambered so that the next round will be automatically loaded and fired, but don't drop anything on the floor +#define EJECT_CASINGS 2 //drop spent casings on the ground after firing +#define CYCLE_CASINGS 3 //cycle casings, like a revolver. Also works for multibarrelled guns + +/obj/item/weapon/gun/projectile + name = "gun" + desc = "A gun that fires bullets." + icon_state = "revolver" + item_state = "handgun" + origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2) + w_class = ITEM_SIZE_NORMAL + matter = list(DEFAULT_WALL_MATERIAL = 1000) + screen_shake = 0 + combustion = 1 + gun_type = GUN_PISTOL + var/image/rust_overlay = null //for condition shit + var/caliber = "357" //determines which casings will fit + var/handle_casings = EJECT_CASINGS //determines how spent casings should be handled + var/load_method = SINGLE_CASING|SPEEDLOADER //1 = Single shells, 2 = box or quick loader, 3 = magazine + var/obj/item/ammo_casing/chambered = null + + //For SINGLE_CASING or SPEEDLOADER guns + var/max_shells = 0 //the number of casings that will fit inside + var/ammo_type = null //the type of ammo that the gun comes preloaded with + var/list/loaded = list() //stored ammo + var/starts_loaded = 1 //whether the gun starts loaded or not, can be overridden for guns crafted in-game + + //For MAGAZINE guns + var/magazine_type = null //the type of magazine that the gun comes preloaded with + var/obj/item/ammo_magazine/ammo_magazine = null //stored magazine + var/allowed_magazines //magazine types that may be loaded. Can be a list or single path + var/auto_eject = 0 //if the magazine should automatically eject itself when empty. + var/auto_eject_sound = null + + var/unload_sound = 'sound/weapons/guns/interact/pistol_magout.ogg' + var/reload_sound = 'sound/weapons/guns/interact/pistol_magin.ogg' + var/cock_sound = 'sound/weapons/guns/interact/pistol_cock.ogg' + var/bulletinsert_sound = 'sound/weapons/guns/interact/bullet_insert.ogg' + var/loaded_icon + var/unwielded_loaded_icon + var/wielded_loaded_icon + var/unloaded_icon + var/unwielded_unloaded_icon + var/wielded_unloaded_icon + var/casingsound = 'sound/weapons/guns/misc/casingfall1.ogg' + var/load_delay = 5 + fire_sound = 'sound/weapons/guns/fire/pistol_fire.ogg' + far_fire_sound = "far_fire" + +/obj/item/weapon/gun/projectile/New() + ..() + + if (starts_loaded) + if(ispath(ammo_type) && (load_method & (SINGLE_CASING|SPEEDLOADER))) + for(var/i in 1 to max_shells) + loaded += new ammo_type(src) + if(ispath(magazine_type) && (load_method & MAGAZINE)) + ammo_magazine = new magazine_type(src) + update_icon() + +/obj/item/weapon/gun/projectile/consume_next_projectile() + if(check_for_jam()) + return null + if(is_jammed) + return null + //get the next casing + if(loaded.len) + chambered = loaded[1] //load next casing. + if(handle_casings != HOLD_CASINGS) + loaded -= chambered + else if(ammo_magazine && ammo_magazine.stored_ammo.len) + chambered = ammo_magazine.stored_ammo[ammo_magazine.stored_ammo.len] + if(handle_casings != HOLD_CASINGS) + ammo_magazine.stored_ammo -= chambered + + + if (chambered) + return chambered.BB + return null + +/obj/item/weapon/gun/projectile/proc/check_for_jam() + if(!can_jam)//If the gun can't jam then always return true. + return FALSE + if(aspect_chosen(/datum/aspect/clean_guns)) + return FALSE + if((!is_jammed && prob(GetConditionProb()))|| aspect_chosen(/datum/aspect/no_guns)) + playsound(src.loc, 'sound/effects/jam.ogg', 50, 1) + src.visible_message("\The [src] jams!") + is_jammed = 1 + update_icon() + return TRUE + + +/obj/item/weapon/gun/projectile/handle_post_fire() + ..() + if(chambered) + chambered.expend() + process_chambered() + +/obj/item/weapon/gun/projectile/update_icon() + . = ..() + overlays.Remove(rust_overlay) + var/icon/I = new/icon(icon, icon_state) + I.Blend(new /icon('icons/obj/gun.dmi',rgb(255,255,255)), ICON_MULTIPLY) + I.Blend(new /icon('icons/obj/gun.dmi', icon_state = "[get_condition_icon()]"), ICON_ADD) + rust_overlay = image(I) + rust_overlay.color = "#773d28" + overlays += rust_overlay + + if(ammo_magazine) + set_loaded_icons() + else + set_unloaded_icons() + + +/obj/item/weapon/gun/projectile/proc/set_loaded_icons() + if(loaded_icon) + icon_state = loaded_icon + if(!ammo_magazine.stored_ammo.len) + icon_state = "[loaded_icon]-0"//Mag is loaded, but out of ammo. + var/mob/living/M = loc + if(istype(M)) + if(wielded) + item_state_slots[slot_l_hand_str] = wielded_loaded_icon + item_state_slots[slot_r_hand_str] = wielded_loaded_icon + else + item_state_slots[slot_l_hand_str] = unwielded_loaded_icon + item_state_slots[slot_r_hand_str] = unwielded_loaded_icon + + item_state_slots[slot_back_str] = loaded_icon + item_state_slots[slot_s_store_str] = loaded_icon + + M.update_inv_back() + M.update_inv_l_hand() + M.update_inv_r_hand() + M.update_inv_s_store() + else + set_generic_icons() + + +/obj/item/weapon/gun/projectile/proc/set_unloaded_icons() + if(unloaded_icon) + icon_state = unloaded_icon + var/mob/living/M = loc + if(istype(M)) + if(wielded) + item_state_slots[slot_l_hand_str] = wielded_unloaded_icon + item_state_slots[slot_r_hand_str] = wielded_unloaded_icon + else + item_state_slots[slot_l_hand_str] = unwielded_unloaded_icon + item_state_slots[slot_r_hand_str] = unwielded_unloaded_icon + + item_state_slots[slot_back_str] = unloaded_icon + item_state_slots[slot_s_store_str] = unloaded_icon + M.update_inv_back() + M.update_inv_l_hand() + M.update_inv_r_hand() + M.update_inv_s_store() + else + set_generic_icons() + + +/obj/item/weapon/gun/projectile/proc/set_generic_icons() + icon_state = initial(icon_state)//Default to the defaults + var/mob/living/M = loc + if(istype(M)) + if(wielded) + item_state_slots[slot_l_hand_str] = wielded_item_state + item_state_slots[slot_r_hand_str] = wielded_item_state + else + item_state_slots[slot_l_hand_str] = initial(item_state) + item_state_slots[slot_r_hand_str] = initial(item_state) + + item_state_slots[slot_back_str] = initial(item_state) + + M.update_inv_back() + M.update_inv_l_hand() + M.update_inv_r_hand() + M.update_inv_s_store() + + +/obj/item/weapon/gun/projectile/proc/get_condition_icon() + switch(condition) + if(1 to 30) + return "condition_8" + if(31 to 40) + return "condition_7" + if(41 to 50) + return "condition_6" + if(51 to 60) + return "condition_5" + if(61 to 70) + return "condition_4" + if(71 to 80) + return "condition_3" + if(81 to 90) + return "condition_2" + if(91 to INFINITY) + return "condition_1" + +/obj/item/weapon/gun/projectile/handle_click_empty() + ..() + process_chambered() + +/obj/item/weapon/gun/projectile/proc/CheckCondition() + switch(condition) + if(0) + return "Broken" + if(1 to 10) + return "Terrible" + if(11 to 20) + return "Poor" + if(21 to 30) + return "Shoddy" + if(31 to 40) + return "Fair" + if(41 to 50) + return "Average" + if(51 to 60) + return "Good" + if(61 to 70) + return "Great" + if(71 to 80) + return "Excellent" + if(81 to 90) + return "Superb" + if(91 to INFINITY) + return "Perfect" + +/obj/item/weapon/gun/projectile/proc/GetConditionProb() + var/mob/M = get_mob_by_key(src.fingerprintslast) + if(M.is_hellbanned()) + return rand(25,40) + switch(condition) + if(0) + return 100 + if(1 to 10) + return rand(20,40) + if(11 to 20) + return rand(8,30) + if(21 to 30) + return rand(4,25) + if(31 to 40) + return rand(2,20) + if(41 to 50) + return rand(1,15) + if(51 to 60) + return rand(0,10) + if(61 to 70) + return rand(0,7) + if(71 to 80) + return rand(0,5) + if(81 to 90) + return rand(0,3) + if(91 to 100) + return rand(0,2) + if(100 to INFINITY) + return 0 + + +/obj/item/weapon/gun/projectile/can_shoot() + if(is_jammed) //If it's jammed always melee attack. + return FALSE + + if(magazine_type && ammo_magazine.stored_ammo.len) //If uses a magazine then check for that instead. + return TRUE + + if(chambered && chambered.BB) //If we have something in the chamber and we're not jammed then shoot it isntead of doing a melee attack. + return TRUE + + if(!magazine_type && handle_casings == CYCLE_CASINGS) //Edge case for revolvers. Fuck revolvers. + return TRUE + + return FALSE + +/obj/item/weapon/gun/projectile/proc/process_chambered() + if (!chambered) return + + switch(handle_casings) + if(EJECT_CASINGS) //eject casing onto ground. + chambered.loc = get_turf(src) + if(casingsound) + playsound(get_turf(src), casingsound, 100, 1) + if(CYCLE_CASINGS) //cycle the casing back to the end. + if(ammo_magazine) + ammo_magazine.stored_ammo += chambered + else + loaded += chambered + + if(handle_casings != HOLD_CASINGS) + chambered = null + + +//Attempts to load A into src, depending on the type of thing being loaded and the load_method +//Maybe this should be broken up into separate procs for each load method? +/obj/item/weapon/gun/projectile/load_ammo(var/obj/item/A, mob/user) + if(istype(A, /obj/item/ammo_magazine)) + var/obj/item/ammo_magazine/AM = A + if(!(load_method & AM.mag_type) || caliber != AM.caliber) + return //incompatible + + switch(AM.mag_type) + if(MAGAZINE) + if((ispath(allowed_magazines) && !istype(A, allowed_magazines)) || (islist(allowed_magazines) && !is_type_in_list(A, allowed_magazines))) + to_chat(user, "\The [A] won't fit into [src].") + return + if(ammo_magazine) + to_chat(user, "[src] already has a magazine loaded.")//already a magazine here + return + if(load_delay) + if(!do_after(user, load_delay, src)) + return + user.remove_from_mob(AM) + AM.loc = src + ammo_magazine = AM + user.visible_message("[user] inserts [AM] into [src].", "You insert [AM] into [src].") + if(reload_sound) + playsound(src.loc, reload_sound, 75, 1) + if(cock_sound && AM.stored_ammo.len) + spawn(4) + playsound(src, cock_sound, 100, 1) + if(SPEEDLOADER) + if(loaded.len >= max_shells) + to_chat(user, "[src] is full!") + return + var/count = 0 + for(var/obj/item/ammo_casing/C in AM.stored_ammo) + if(loaded.len >= max_shells) + break + if(C.caliber == caliber) + C.loc = src + loaded += C + AM.stored_ammo -= C //should probably go inside an ammo_magazine proc, but I guess less proc calls this way... + count++ + if(count) + user.visible_message("[user] reloads [src].", "You load [count] round\s into [src].") + if(reload_sound) + playsound(src.loc, reload_sound, 75, 1) + + if(SINGLE_LOAD) + if(loaded.len >= max_shells) + to_chat(user, "[src] is full!") + return + var/obj/item/ammo_casing/C = AM.stored_ammo[1] + if(C) + C.loc = src + loaded.Insert(1, C) //add to the head of the list + AM.stored_ammo.Cut(1, 2) + if(bulletinsert_sound) + playsound(src.loc, bulletinsert_sound, 75, 1) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)//So we can't speed click these. + + + AM.update_icon() + else if(istype(A, /obj/item/ammo_casing)) + var/obj/item/ammo_casing/C = A + if(!(load_method & SINGLE_CASING) || caliber != C.caliber) + return //incompatible + if(loaded.len >= max_shells) + to_chat(user, "[src] is full.") + return + + user.remove_from_mob(C) + C.loc = src + loaded.Insert(1, C) //add to the head of the list + user.visible_message("[user] inserts \a [C] into [src].", "You insert \a [C] into [src].") + if(bulletinsert_sound) + playsound(src.loc, bulletinsert_sound, 75, 1) + + update_icon() + +//attempts to unload src. If allow_dump is set to 0, the speedloader unloading method will be disabled +/obj/item/weapon/gun/projectile/unload_ammo(mob/user, var/allow_dump=1) + if(ammo_magazine) + user.put_in_hands(ammo_magazine) + user.visible_message("[user] removes [ammo_magazine] from [src].", "You remove [ammo_magazine] from [src].") + if(unload_sound) + playsound(src.loc, unload_sound, 75, 1) + ammo_magazine.update_icon() + ammo_magazine = null + else if(loaded.len) + //presumably, if it can be speed-loaded, it can be speed-unloaded. + if(allow_dump && (load_method & SPEEDLOADER)) + var/count = 0 + var/turf/T = get_turf(user) + if(T) + for(var/obj/item/ammo_casing/C in loaded) + C.loc = T + count++ + loaded.Cut() + if(count) + if(unload_sound) + playsound(src.loc, unload_sound, 75, 1) + user.visible_message("[user] unloads [src].", "You unload [count] round\s from [src].") + if(casingsound) + playsound(src.loc, casingsound, 75, 1) + else if(load_method & SINGLE_CASING) + var/obj/item/ammo_casing/C = loaded[loaded.len] + loaded.len-- + user.put_in_hands(C) + user.visible_message("[user] removes \a [C] from [src].", "You remove \a [C] from [src].") + if(bulletinsert_sound) + playsound(src.loc, bulletinsert_sound, 75, 1) + else + to_chat(user, "[src] is empty.") + update_icon() + +/obj/item/weapon/gun/projectile/attackby(var/obj/item/A as obj, mob/user as mob) + load_ammo(A, user) + +/obj/item/weapon/gun/projectile/attack_self(mob/user as mob) + if(firemodes.len > 1) + ..() + +/obj/item/weapon/gun/projectile/MouseDrop(var/obj/over_object) + if (!over_object || !(ishuman(usr) || issmall(usr))) + return + + if (!(src.loc == usr)) + return + var/mob/living/carbon/human/H = usr + if(H.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_KNOCKOUT)) + return + + switch(over_object.name) + if("r_hand") + unload_ammo(usr, allow_dump=0) + if("l_hand") + unload_ammo(usr, allow_dump=0) + + +/obj/item/weapon/gun/projectile/afterattack(atom/A, mob/living/user) + ..() + if(auto_eject && ammo_magazine && ammo_magazine.stored_ammo && !ammo_magazine.stored_ammo.len) + ammo_magazine.loc = get_turf(src.loc) + user.visible_message( + "[ammo_magazine] falls out and clatters on the floor!", + "[ammo_magazine] falls out and clatters on the floor!" + ) + if(auto_eject_sound) + playsound(user, auto_eject_sound, 40, 1) + ammo_magazine.update_icon() + ammo_magazine = null + update_icon() //make sure to do this after unsetting ammo_magazine + +/obj/item/weapon/gun/projectile/examine(mob/user) + . = ..(user) + if(is_jammed) + to_chat(user, "It looks jammed.") + if(ammo_magazine) + to_chat(user, "It has \a [ammo_magazine] loaded.") + to_chat(user, "CONDITION: [CheckCondition()]") + to_chat(user, "[inexactAmmo()]") + + + return + +/obj/item/weapon/gun/projectile/proc/getAmmo() + var/bullets = 0 + if(loaded) + bullets += loaded.len + if(ammo_magazine && ammo_magazine.stored_ammo) + bullets += ammo_magazine.stored_ammo.len + if(chambered) + bullets += 1 + return bullets + +/obj/item/weapon/gun/projectile/proc/inexactAmmo() + var/ammo = getAmmo() + var/message + + var/mob/living/M = loc + if(istype(M)) + if(M.l_hand == src || M.r_hand == src)//Gotta be holding it or this won't work. + if(ammo_magazine && ammo_magazine.stored_ammo) + if(ammo == ammo_magazine.max_ammo) + message = "It feels full." + else if(ammo > round(ammo_magazine.max_ammo/2) && ammo < ammo_magazine.max_ammo) + message = "Feels like over half left." + else if(ammo == round(ammo_magazine.max_ammo/2)) + message = "Only half left." + else if(ammo < round(ammo_magazine.max_ammo/2) && ammo > 0) + message = "Feel like less than half left." + else if(ammo == 0) + message = "It feels empty." + else + if(ammo == max_shells) + message = "It feels full." + else if(ammo >= 6) + message = "It feels very heavy." + else if(ammo > 3 && ammo < 6) + message = "It feels heavy." + else if(ammo <= 3 && ammo != 0) + message = "It feels light." + else if(ammo == 0) + message = "It feels empty." + return message + +/* Unneeded -- so far. +//in case the weapon has firemodes and can't unload using attack_hand() +/obj/item/weapon/gun/projectile/verb/unload_gun() + set name = "Unload Ammo" + set category = "Object" + set src in usr + + if(usr.stat || usr.restrained()) return + + unload_ammo(usr) +*/ diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm new file mode 100644 index 00000000..2586640b --- /dev/null +++ b/code/modules/projectiles/guns/projectile/automatic.dm @@ -0,0 +1,358 @@ +/obj/item/weapon/gun/projectile/automatic //Hopefully someone will find a way to make these fire in bursts or something. --Superxpdude + name = "prototype SMG" + desc = "A protoype lightweight, fast firing gun. Uses 9mm rounds." + icon_state = "saber" //ugly + w_class = ITEM_SIZE_NORMAL + load_method = MAGAZINE + max_shells = 22 + caliber = "9mm" + origin_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 2) + slot_flags = SLOT_BELT + ammo_type = /obj/item/ammo_casing/c9mm + multi_aim = 1 + burst_delay = 2 + fire_sound = 'sound/weapons/guns/fire/smg_fire.ogg' + unload_sound = 'sound/weapons/guns/interact/smg_magout.ogg' + reload_sound = 'sound/weapons/guns/interact/smg_magin.ogg' + cock_sound = 'sound/weapons/guns/interact/smg_cock.ogg' + + //machine pistol, easier to one-hand with + firemodes = list( + list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, one_hand_penalty=0, burst_accuracy=null, dispersion=list(0), automatic = 0), + list(mode_name="3-round bursts", burst=3, fire_delay=null, move_delay=4, one_hand_penalty=1, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 3, 5), automatic = 0), + list(mode_name="automatic", burst=1, fire_delay=0, move_delay=0, one_hand_penalty=2, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 3, 5), automatic = 1) + //list(mode_name="short bursts", burst=5, fire_delay=null, move_delay=4, one_hand_penalty=2, burst_accuracy=list(0,-1,-1,-1,-2), dispersion=list(0.6, 0.6, 1.0, 1.0, 1.2)), + ) + +/obj/item/weapon/gun/projectile/automatic/c20r/oldsmg + name = "\improper 9MM Harbinger" + desc = "A 9MM SMG, popular among prison gaurds and soldiers alike." + icon_state = "smg" + item_state = "wt550" + wielded_item_state = "smg-wielded" + one_hand_penalty = 1 + auto_eject = 0 + unload_sound = 'sound/weapons/guns/interact/smg_magout.ogg' + reload_sound = 'sound/weapons/guns/interact/smg_magin.ogg' + cock_sound = 'sound/weapons/guns/interact/smg_cock.ogg' + condition = 80 + +/obj/item/weapon/gun/projectile/automatic/c20r/oldsmg/update_icon() + ..() + if(ammo_magazine) + icon_state = "smg" + else + icon_state = "smg-e" + + +/obj/item/weapon/gun/projectile/automatic/machine_pistol + name = ".45 machine pistol" + desc = "The Lumoco Arms MP6 Vesper, A fairly common machine pistol. Sometimes refered to as an 'uzi' by the backwater spacers it is often associated with. Uses .45 rounds." + icon_state = "mpistolen" + item_state = "wt550" + w_class = ITEM_SIZE_NORMAL + load_method = MAGAZINE + caliber = ".45" + origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 2, TECH_ILLEGAL = 3) + slot_flags = SLOT_BELT + ammo_type = /obj/item/ammo_casing/c45 + magazine_type = /obj/item/ammo_magazine/c45uzi + allowed_magazines = /obj/item/ammo_magazine/c45uzi //more damage compared to the wt550, smaller mag size + + firemodes = list( + list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, one_hand_penalty=0, burst_accuracy=null, dispersion=null, automatic = 0), + list(mode_name="3-round bursts", burst=3, fire_delay=null, move_delay=4, one_hand_penalty=1, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0), automatic = 0), + list(mode_name="automatic", burst=1, fire_delay=0, move_delay=0, one_hand_penalty=2, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 3, 5), automatic = 2) + //list(mode_name="short bursts", burst=5, fire_delay=null, move_delay=4, one_hand_penalty=2, burst_accuracy=list(0,-1,-1,-1,-2), dispersion=list(0.6, 0.6, 1.0, 1.0, 1.2)), + ) + +/obj/item/weapon/gun/projectile/automatic/mini_uzi/update_icon() + ..() + if(ammo_magazine) + icon_state = "mpistolen" + else + icon_state = "mpistolen-empty" + +/obj/item/weapon/gun/projectile/automatic/c20r + name = "10mm submachine gun" + desc = "The C-20r is a lightweight and rapid firing SMG, for when you REALLY need someone dead. Uses 10mm rounds. Has a 'Scarborough Arms - Per falcis, per pravitas' buttstamp." + icon_state = "c20r" + item_state = "c20r" + w_class = ITEM_SIZE_LARGE + force = 10 + caliber = "10mm" + origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 2, TECH_ILLEGAL = 8) + slot_flags = SLOT_BELT|SLOT_BACK + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/a10mm + allowed_magazines = /obj/item/ammo_magazine/a10mm + auto_eject = 1 + auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg' + one_hand_penalty = 1 + unload_sound = 'sound/weapons/guns/interact/sfrifle_magout.ogg' + reload_sound = 'sound/weapons/guns/interact/sfrifle_magin.ogg' + cock_sound = 'sound/weapons/guns/interact/sfrifle_cock.ogg' + + //SMG + firemodes = list( + list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, one_hand_penalty=2, burst_accuracy=null, dispersion=null, automatic = 0), + list(mode_name="3-round bursts", burst=3, fire_delay=null, move_delay=4, one_hand_penalty=3, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0), automatic = 0), + list(mode_name="automatic", burst=1, fire_delay=0, move_delay=0, one_hand_penalty=2, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 3, 5), automatic = 2) + ) + +/obj/item/weapon/gun/projectile/automatic/c20r/update_icon() + ..() + if(ammo_magazine) + icon_state = "c20r-[round(ammo_magazine.stored_ammo.len,4)]" + else + icon_state = "c20r" + return + +/obj/item/weapon/gun/projectile/automatic/m22 + name = "M-22 Assault Rifle" + desc = "Well-loved by grunts everywhere" + icon_state = "m22" + item_state = "arifle" + w_class = ITEM_SIZE_HUGE + force = 10 + caliber = ".45" + origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 2, TECH_ILLEGAL = 8) + slot_flags = SLOT_BACK|SLOT_S_STORE + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/c45rifle + allowed_magazines = /obj/item/ammo_magazine/c45rifle + one_hand_penalty = 4 + wielded_item_state = "arifle-wielded" + unload_sound = 'sound/weapons/guns/interact/sfrifle_magout.ogg' + reload_sound = 'sound/weapons/guns/interact/sfrifle_magin.ogg' + cock_sound = 'sound/weapons/guns/interact/sfrifle_cock.ogg' + far_fire_sound = "rifle_fire" + + firemodes = list( + list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, one_hand_penalty=4, burst_accuracy=null, dispersion=null, automatic = 0), + list(mode_name="automatic", burst=2, fire_delay=0, move_delay=null, one_hand_penalty=4, burst_accuracy=null, dispersion=list(0.2), automatic = 0.1) + ) + + +/obj/item/weapon/gun/projectile/automatic/sts35 + name = "assault rifle" + desc = "The rugged STS-35 is a durable automatic weapon of a make popular on the frontier worlds. The serial number has been scratched off. Uses 5.56mm rounds." + icon_state = "arifle" + item_state = null + w_class = ITEM_SIZE_HUGE + force = 10 + caliber = "a556" + origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 1, TECH_ILLEGAL = 5) + slot_flags = SLOT_BACK|SLOT_S_STORE + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/c556 + allowed_magazines = /obj/item/ammo_magazine/c556 + one_hand_penalty = 3 + wielded_item_state = "arifle-wielded" + unload_sound = 'sound/weapons/guns/interact/ltrifle_magout.ogg' + reload_sound = 'sound/weapons/guns/interact/ltrifle_magin.ogg' + cock_sound = 'sound/weapons/guns/interact/ltrifle_cock.ogg' + + + //Assault rifle, burst fire degrades quicker than SMG, worse one-handing penalty, slightly increased move delay + firemodes = list( + list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, one_hand_penalty=4, burst_accuracy=null, dispersion=null, automatic = 0), + list(mode_name="3-round bursts", burst=3, fire_delay=null, move_delay=6, one_hand_penalty=5, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0), automatic = 0), + list(mode_name="automatic", burst=1, fire_delay=0.5, move_delay=null, one_hand_penalty=2, burst_accuracy=null, dispersion=list(0.2), automatic = 0.1) + //list(mode_name="short bursts", burst=5, fire_delay=null, move_delay=6, one_hand_penalty=6, burst_accuracy=list(0,-1,-2,-3,-3), dispersion=list(0.6, 1.0, 1.2, 1.2, 1.5)), + ) + +/obj/item/weapon/gun/projectile/automatic/sts35/update_icon() + icon_state = (ammo_magazine)? "arifle" : "arifle-empty" + wielded_item_state = (ammo_magazine)? "arifle-wielded" : "arifle-wielded-empty" + ..() + + +/obj/item/weapon/gun/projectile/automatic/wt550 + name = "9mm submachine gun" + desc = "The WT-550 Saber is a cheap self-defense weapon, mass-produced by Ward-Takahashi for paramilitary and private use. Uses 9mm rounds." + icon_state = "wt550" + item_state = "wt550" + w_class = ITEM_SIZE_NORMAL + caliber = "9mm" + origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 2) + slot_flags = SLOT_BELT + ammo_type = /obj/item/ammo_casing/c9mm/rubber + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/mc9mmt/rubber + allowed_magazines = /obj/item/ammo_magazine/mc9mmt + + //machine pistol, like SMG but easier to one-hand with + firemodes = list( + list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, one_hand_penalty=0, burst_accuracy=null, dispersion=null, automatic = 0), + list(mode_name="3-round bursts", burst=3, fire_delay=null, move_delay=4, one_hand_penalty=1, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0), automatic = 0), + list(mode_name="automatic", burst=1, fire_delay=0.5, move_delay=null, one_hand_penalty=2, burst_accuracy=null, dispersion=list(0.2), automatic = 0.1) + //list(mode_name="short bursts", burst=5, fire_delay=null, move_delay=4, one_hand_penalty=2, burst_accuracy=list(0,-1,-1,-1,-2), dispersion=list(0.6, 0.6, 1.0, 1.0, 1.2)), + ) + +/obj/item/weapon/gun/projectile/automatic/wt550/update_icon() + ..() + if(ammo_magazine) + icon_state = "wt550-[round(ammo_magazine.stored_ammo.len,4)]" + else + icon_state = "wt550" + return + +/obj/item/weapon/gun/projectile/automatic/z8 + name = "bullpup assault rifle" + desc = "The Z8 Bulldog is an older model bullpup carbine, made by the now defunct Zendai Foundries. Uses armor piercing 7.62mm rounds. Makes you feel like a space marine when you hold it." + icon_state = "carbine" + item_state = "z8carbine" + w_class = ITEM_SIZE_HUGE + force = 10 + caliber = "a762" + origin_tech = list(TECH_COMBAT = 8, TECH_MATERIAL = 3) + ammo_type = /obj/item/ammo_casing/a762 + slot_flags = SLOT_BACK|SLOT_S_STORE + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/a762 + allowed_magazines = /obj/item/ammo_magazine/a762 + auto_eject = 1 + auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg' + one_hand_penalty = 5 + burst_delay = 4 + wielded_item_state = "z8carbine-wielded" + unload_sound = 'sound/weapons/guns/interact/batrifle_magout.ogg' + reload_sound = 'sound/weapons/guns/interact/batrifle_magin.ogg' + cock_sound = 'sound/weapons/guns/interact/batrifle_cock.ogg' + //would have one_hand_penalty=4,5 but the added weight of a grenade launcher makes one-handing even harder + firemodes = list( + list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, use_launcher=null, one_hand_penalty=5, burst_accuracy=null, dispersion=null, automatic = 0), + list(mode_name="3-round bursts", burst=3, fire_delay=null, move_delay=6, use_launcher=null, one_hand_penalty=6, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0), automatic = 0), + list(mode_name="automatic", burst=1, fire_delay=0.5, move_delay=null, one_hand_penalty=2, burst_accuracy=null, dispersion=list(0.2), automatic = 0.1), + list(mode_name="fire grenades", burst=null, fire_delay=null, move_delay=null, use_launcher=1, one_hand_penalty=5, burst_accuracy=null, dispersion=null, automatic = 0) + ) + + var/use_launcher = 0 + var/obj/item/weapon/gun/launcher/grenade/underslung/launcher + +/obj/item/weapon/gun/projectile/automatic/z8/New() + ..() + launcher = new(src) + +/obj/item/weapon/gun/projectile/automatic/z8/attackby(obj/item/I, mob/user) + if((istype(I, /obj/item/weapon/grenade))) + launcher.load(I, user) + else + ..() + +/obj/item/weapon/gun/projectile/automatic/z8/attack_hand(mob/user) + if(user.get_inactive_hand() == src && use_launcher) + launcher.unload(user) + else + ..() + +/obj/item/weapon/gun/projectile/automatic/z8/Fire(atom/target, mob/living/user, params, pointblank=0, reflex=0) + if(use_launcher) + launcher.Fire(target, user, params, pointblank, reflex) + if(!launcher.chambered) + switch_firemodes() //switch back automatically + else + ..() + +/obj/item/weapon/gun/projectile/automatic/z8/update_icon() + ..() + if(ammo_magazine) + if(ammo_magazine.stored_ammo.len) + icon_state = "carbine-loaded" + else + icon_state = "carbine-empty" + else + icon_state = "carbine" + return + +/obj/item/weapon/gun/projectile/automatic/z8/examine(mob/user) + . = ..() + if(launcher.chambered) + to_chat(user, "\The [launcher] has \a [launcher.chambered] loaded.") + else + to_chat(user, "\The [launcher] is empty.") + +/obj/item/weapon/gun/projectile/automatic/l6_saw + name = "light machine gun" + desc = "A rather traditionally made L6 SAW with a pleasantly lacquered wooden pistol grip. Has 'Aussec Armoury- 2531' engraved on the reciever." //probably should refluff this + icon_state = "l6closed100" + item_state = "l6closedmag" + w_class = ITEM_SIZE_HUGE + force = 10 + slot_flags = 0 + max_shells = 50 + caliber = "a556" + origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 1, TECH_ILLEGAL = 2) + slot_flags = 0 //need sprites for SLOT_BACK + ammo_type = /obj/item/ammo_casing/a556 + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/box/a556 + allowed_magazines = list(/obj/item/ammo_magazine/box/a556, /obj/item/ammo_magazine/c556) + one_hand_penalty = 6 + wielded_item_state = "gun_wielded" + unload_sound = 'sound/weapons/guns/interact/lmg_magout.ogg' + reload_sound = 'sound/weapons/guns/interact/lmg_magin.ogg' + cock_sound = 'sound/weapons/guns/interact/lmg_cock.ogg' + + //LMG, better sustained fire accuracy than assault rifles (comparable to SMG), higer move delay and one-handing penalty + //No single-shot or 3-round-burst modes since using this weapon should come at a cost to flexibility. + firemodes = list( + list(mode_name="short bursts", burst=5, move_delay=12, one_hand_penalty=8, burst_accuracy = list(0,-1,-1,-2,-2), dispersion = list(0.6, 1.0, 1.0, 1.0, 1.2), automatic = 0), + list(mode_name="automatic", burst=1, fire_delay=0.5, move_delay=null, one_hand_penalty=2, burst_accuracy=null, dispersion=list(0.2), automatic = 0.1) + //list(mode_name="long bursts", burst=8, move_delay=15, one_hand_penalty=9, burst_accuracy = list(0,-1,-1,-2,-2,-2,-3,-3), dispersion = list(1.0, 1.0, 1.0, 1.0, 1.2)), + ) + + var/cover_open = 0 + +/obj/item/weapon/gun/projectile/automatic/l6_saw/mag + magazine_type = /obj/item/ammo_magazine/c556 + +/obj/item/weapon/gun/projectile/automatic/l6_saw/special_check(mob/user) + if(cover_open) + to_chat(user, "[src]'s cover is open! Close it before firing!") + return 0 + return ..() + +/obj/item/weapon/gun/projectile/automatic/l6_saw/proc/toggle_cover(mob/user) + cover_open = !cover_open + to_chat(user, "You [cover_open ? "open" : "close"] [src]'s cover.") + update_icon() + +/obj/item/weapon/gun/projectile/automatic/l6_saw/attack_self(mob/user as mob) + if(cover_open) + toggle_cover(user) //close the cover + playsound(src.loc, 'sound/weapons/guns/interact/lmg_close.ogg', 100, 1) + else + return ..() //once closed, behave like normal + +/obj/item/weapon/gun/projectile/automatic/l6_saw/attack_hand(mob/user as mob) + if(!cover_open && user.get_inactive_hand() == src) + toggle_cover(user) //open the cover + playsound(src.loc, 'sound/weapons/guns/interact/lmg_open.ogg', 100, 1) + else + return ..() //once open, behave like normal + +/obj/item/weapon/gun/projectile/automatic/l6_saw/update_icon() + if(istype(ammo_magazine, /obj/item/ammo_magazine/box)) + icon_state = "l6[cover_open ? "open" : "closed"][round(ammo_magazine.stored_ammo.len, 25)]" + item_state = "l6[cover_open ? "open" : "closed"]" + else if(ammo_magazine) + icon_state = "l6[cover_open ? "open" : "closed"]mag" + item_state = "l6[cover_open ? "open" : "closed"]mag" + else + icon_state = "l6[cover_open ? "open" : "closed"]-empty" + item_state = "l6[cover_open ? "open" : "closed"]-empty" + ..() + +/obj/item/weapon/gun/projectile/automatic/l6_saw/load_ammo(var/obj/item/A, mob/user) + if(!cover_open) + to_chat(user, "You need to open the cover to load that into [src].") + return + ..() + +/obj/item/weapon/gun/projectile/automatic/l6_saw/unload_ammo(mob/user, var/allow_dump=1) + if(!cover_open) + to_chat(user, "You need to open the cover to unload [src].") + return + ..() diff --git a/code/modules/projectiles/guns/projectile/dartgun.dm b/code/modules/projectiles/guns/projectile/dartgun.dm new file mode 100644 index 00000000..4a0666bf --- /dev/null +++ b/code/modules/projectiles/guns/projectile/dartgun.dm @@ -0,0 +1,204 @@ +/obj/item/projectile/bullet/chemdart + name = "dart" + icon_state = "dart" + damage = 5 + sharp = 1 + embed = 1 //the dart is shot fast enough to pierce space suits, so I guess splintering inside the target can be a thing. Should be rare due to low damage. + var/reagent_amount = 15 + range = 15 //shorter range + unacidable = 1 + + muzzle_type = null + +/obj/item/projectile/bullet/chemdart/New() + create_reagents(reagent_amount) + ..() + +/obj/item/projectile/bullet/chemdart/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null) + if(blocked < 100 && isliving(target)) + var/mob/living/L = target + if(L.can_inject(null, def_zone)) + reagents.trans_to_mob(L, reagent_amount, CHEM_BLOOD) + +/obj/item/ammo_casing/chemdart + name = "chemical dart" + desc = "A small hardened, hollow dart." + icon_state = "dart" + caliber = "dart" + projectile_type = /obj/item/projectile/bullet/chemdart + leaves_residue = 0 + +/obj/item/ammo_casing/chemdart/expend() + qdel(src) + +/obj/item/ammo_magazine/chemdart + name = "dart cartridge" + desc = "A rack of hollow darts." + icon_state = "darts" + item_state = "rcdammo" + origin_tech = list(TECH_MATERIAL = 2) + mag_type = MAGAZINE + caliber = "dart" + ammo_type = /obj/item/ammo_casing/chemdart + max_ammo = 5 + multiple_sprites = 1 + +/obj/item/weapon/gun/projectile/dartgun + name = "dart gun" + desc = "Zeng-Hu Pharmaceutical's entry into the arms market, the Z-H P Artemis is a gas-powered dart gun capable of delivering chemical cocktails swiftly across short distances." + icon_state = "dartgun-empty" + item_state = null + + caliber = "dart" + fire_sound = 'sound/weapons/empty.ogg' + fire_sound_text = "a metallic click" + screen_shake = 0 + silenced = 1 + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/chemdart + allowed_magazines = /obj/item/ammo_magazine/chemdart + auto_eject = 0 + handle_casings = CLEAR_CASINGS //delete casings instead of dropping them + + var/list/beakers = list() //All containers inside the gun. + var/list/mixing = list() //Containers being used for mixing. + var/max_beakers = 3 + var/dart_reagent_amount = 15 + var/container_type = /obj/item/weapon/reagent_containers/glass/beaker + var/list/starting_chems = null + +/obj/item/weapon/gun/projectile/dartgun/Initialize() + if(starting_chems) + for(var/chem in starting_chems) + var/obj/B = new container_type(src) + B.reagents.add_reagent(chem, 60) + beakers += B + . = ..() + update_icon() + +/obj/item/weapon/gun/projectile/dartgun/update_icon() + if(!ammo_magazine) + icon_state = "dartgun-empty" + return 1 + + if(!ammo_magazine.stored_ammo || ammo_magazine.stored_ammo.len) + icon_state = "dartgun-0" + else if(ammo_magazine.stored_ammo.len > 5) + icon_state = "dartgun-5" + else + icon_state = "dartgun-[ammo_magazine.stored_ammo.len]" + return 1 + +/obj/item/weapon/gun/projectile/dartgun/consume_next_projectile() + . = ..() + var/obj/item/projectile/bullet/chemdart/dart = . + if(istype(dart)) + fill_dart(dart) + +/obj/item/weapon/gun/projectile/dartgun/examine(mob/user) + . = ..() + if (beakers.len) + to_chat(user, "\The [src] contains:") + for(var/obj/item/weapon/reagent_containers/glass/beaker/B in beakers) + if(B.reagents && B.reagents.reagent_list.len) + for(var/datum/reagent/R in B.reagents.reagent_list) + to_chat(user, "[R.volume] units of [R.name]") + +/obj/item/weapon/gun/projectile/dartgun/attackby(obj/item/I as obj, mob/user as mob) + if(istype(I, /obj/item/weapon/reagent_containers/glass)) + add_beaker(I, user) + return 1 + ..() + +/obj/item/weapon/gun/projectile/dartgun/proc/add_beaker(var/obj/item/weapon/reagent_containers/glass/B, mob/user) + if(!istype(B, container_type)) + to_chat(user, "[B] doesn't seem to fit into [src].") + return + if(beakers.len >= max_beakers) + to_chat(user, "[src] already has [max_beakers] beakers in it - another one isn't going to fit!") + return + user.drop_from_inventory(B, src) + beakers |= B + user.visible_message("\The [user] inserts \a [B] into [src].", "You slot [B] into [src].") + +/obj/item/weapon/gun/projectile/dartgun/proc/remove_beaker(var/obj/item/weapon/reagent_containers/glass/B, mob/user) + mixing -= B + beakers -= B + user.put_in_hands(B) + user.visible_message("\The [user] removes \a [B] from [src].", "You remove [B] from [src].") + +//fills the given dart with reagents +/obj/item/weapon/gun/projectile/dartgun/proc/fill_dart(var/obj/item/projectile/bullet/chemdart/dart) + if(mixing.len) + var/mix_amount = dart.reagent_amount/mixing.len + for(var/obj/item/weapon/reagent_containers/glass/beaker/B in mixing) + B.reagents.trans_to_obj(dart, mix_amount) + +/obj/item/weapon/gun/projectile/dartgun/attack_self(mob/user) + Interact(user) + +/obj/item/weapon/gun/projectile/dartgun/proc/Interact(mob/user) + user.set_machine(src) + var/list/dat = list("[src] mixing control:

            ") + + if (!beakers.len) + dat += "There are no beakers inserted!

            " + else + for(var/i in 1 to beakers.len) + var/obj/item/weapon/reagent_containers/glass/beaker/B = beakers[i] + if(!istype(B)) continue + + dat += "Beaker [i] contains: " + if(B.reagents && B.reagents.reagent_list.len) + for(var/datum/reagent/R in B.reagents.reagent_list) + dat += "
            [R.volume] units of [R.name], " + if(B in mixing) + dat += "Mixing " + else + dat += "Not mixing " + else + dat += "nothing." + dat += " \[Eject\]
            " + + if(ammo_magazine) + if(ammo_magazine.stored_ammo && ammo_magazine.stored_ammo.len) + dat += "The dart cartridge has [ammo_magazine.stored_ammo.len] shots remaining." + else + dat += "The dart cartridge is empty!" + dat += " \[Eject\]
            " + + dat += "
            \[Refresh\]" + + var/datum/browser/popup = new(user, "dartgun", "[src] mixing control") + popup.set_content(jointext(dat,null)) + popup.open() + +/obj/item/weapon/gun/projectile/dartgun/OnTopic(user, href_list) + if(href_list["stop_mix"]) + var/index = text2num(href_list["stop_mix"]) + mixing -= beakers[index] + . = TOPIC_REFRESH + else if (href_list["mix"]) + var/index = text2num(href_list["mix"]) + mixing |= beakers[index] + . = TOPIC_REFRESH + else if (href_list["eject"]) + var/index = text2num(href_list["eject"]) + if(beakers[index]) + remove_beaker(beakers[index], usr) + . = TOPIC_REFRESH + else if (href_list["eject_cart"]) + unload_ammo(usr) + . = TOPIC_REFRESH + + Interact(usr) + +/obj/item/weapon/gun/projectile/dartgun/vox + name = "alien dart gun" + desc = "A small gas-powered dartgun, fitted for nonhuman hands." + +/obj/item/weapon/gun/projectile/dartgun/vox/medical + starting_chems = list(/datum/reagent/kelotane,/datum/reagent/bicaridine,/datum/reagent/dylovene) + +/obj/item/weapon/gun/projectile/dartgun/vox/raider + starting_chems = list(/datum/reagent/space_drugs,/datum/reagent/soporific,/datum/reagent/impedrezene) diff --git a/code/modules/projectiles/guns/projectile/detective.dm b/code/modules/projectiles/guns/projectile/detective.dm new file mode 100644 index 00000000..8506ac53 --- /dev/null +++ b/code/modules/projectiles/guns/projectile/detective.dm @@ -0,0 +1,111 @@ +/obj/item/weapon/gun/projectile/colt/detective + var/unique_name + var/datum/detective_gun_skin/unique_reskin + var/static/list/gun_options + magazine_type = /obj/item/ammo_magazine/c45m/flash + unload_sound = 'sound/weapons/guns/interact/rev_magout.ogg' + reload_sound = 'sound/weapons/guns/interact/rev_magin.ogg' + fire_sound = 'sound/weapons/guns/fire/revolver_fire.ogg' + +/obj/item/weapon/gun/projectile/colt/detective/New() + ..() + if(!gun_options) + gun_options = init_subtypes(/datum/detective_gun_skin) + +/obj/item/weapon/gun/projectile/colt/detective/update_icon() + if(ammo_magazine && ammo_magazine.stored_ammo.len) + if(unique_reskin) + icon_state = unique_reskin.icon_state + else + icon_state = initial(icon_state) + else + if(unique_reskin) + icon_state = "[unique_reskin.icon_state]-e" + else + icon_state = "[initial(icon_state)]-e" + +/obj/item/weapon/gun/projectile/colt/detective/verb/rename_gun() + set name = "Name Gun" + set category = "Object" + set desc = "Rename your gun. If you're the detective." + + var/mob/M = usr + if(!M.mind) return 0 + if(M.incapacitated()) return 0 + if(!M.mind.assigned_role == "Detective") + to_chat(M, "You don't feel cool enough to name this gun, chump.") + return 0 + + var/input = sanitizeSafe(input("What do you want to name the gun?","Rename gun"), MAX_NAME_LEN) + + if(src && input && !M.incapacitated() && in_range(M,src)) + if(!findtext(input, "the", 1, 4)) + input = "\improper [input]" + name = input + unique_name = input + to_chat(M, "You name the gun '[input]'. Say hello to your new friend.") + return 1 + +/obj/item/weapon/gun/projectile/colt/detective/verb/reskin_gun() + set name = "Reskin gun" + set category = "Object" + set desc = "Click to reskin your gun." + + var/mob/M = usr + if(M.incapacitated()) + return + + var/datum/detective_gun_skin/choice = input(M,"What do you want to skin the gun to?","Reskin Gun", unique_reskin) as null|anything in gun_options + if(src && choice && !M.incapacitated() && in_range(M,src)) + icon_state = choice.icon_state + unique_reskin = choice + if(!unique_name) + SetName(choice.name) + to_chat(M, "Your gun is now skinned as \a [choice]. Say hello to your new friend.") + return 1 + + +//apart of reskins that have two sprites, touching may result in frustration and breaks +/obj/item/weapon/gun/projectile/colt/detective/attack_hand(var/mob/living/user) + if(!unique_reskin && loc == user) + reskin_gun(user) + return + ..() + +/datum/detective_gun_skin + var/name + var/icon_state + +/datum/detective_gun_skin/default/New() + ..() + var/obj/item/weapon/gun/projectile/colt/detective/d = /obj/item/weapon/gun/projectile/colt/detective + name = initial(d.name) + icon_state = initial(d.icon_state) + +/datum/detective_gun_skin/colt + name = "\improper Colt M1911" + icon_state = "colt" + +/datum/detective_gun_skin/luger + name = "\improper P08 Luger" + icon_state = "p08" + +/datum/detective_gun_skin/luger_brown + name = "\improper P08 Luger, brown" + icon_state = "p08b" + +/datum/detective_gun_skin/mk_standard + name = "\improper NT Mk. 58" + icon_state = "secguncomp" + +/datum/detective_gun_skin/mk_custom + name = "\improper NT Mk. 58 Custom" + icon_state = "secgundark" + +/datum/detective_gun_skin/usp + name = "\improper USP" + icon_state = "usp" + +/datum/detective_gun_skin/vp + name = "\improper H&K VP" + icon_state = "VP78" diff --git a/code/modules/projectiles/guns/projectile/mattguns.dm b/code/modules/projectiles/guns/projectile/mattguns.dm new file mode 100644 index 00000000..de0719f4 --- /dev/null +++ b/code/modules/projectiles/guns/projectile/mattguns.dm @@ -0,0 +1,513 @@ +//Shitty variant of the normal bolt action rifle. +/obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty + name = "\improper Mark I Stormrider" + desc = "A scrapped together piece of shit. Prone to jamming, but fires a very powerful round."//"The much, much older brother of the sleeker, better, Mark II. Kind of a piece of shit." + icon_state = "boltaction" + item_state = "boltaction" + wielded_item_state = "boltaction-wielded" + condition = 75 + fire_sound = "brifle" + caliber = "763" + ammo_type = /obj/item/ammo_casing/brifle + one_hand_penalty = 20 //FIRE THIS THING WITH BOTH FUCKING HANDS. + empty_icon = "boltaction-e" + far_fire_sound = "sniper_fire" + +/obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty/bayonet + name = "\improper Mark I Stormrider" + force = 20 + sharp = 1 + attack_verb = list ("stabbed", "sliced") + hitsound = "stab_sound" + +/obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty/bayonet/New() + ..() + add_bayonet() + desc += " This one has a bayonet." + + +/obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty/leverchester + name = "\improper Mark I Snapper" + desc = "The lever action version of the Stormrider. Has all the same benefits and issues." + icon_state = "leverchester" + item_state = "leverchester" + wielded_item_state = "leverchester-wielded" + fire_sound = 'sound/weapons/guns/fire/la_fire.ogg' + bulletinsert_sound = 'sound/weapons/guns/interact/la_insert.ogg' + pumpsound = 'sound/weapons/guns/interact/la_cock.ogg' + backsound = 'sound/weapons/guns/interact/la_back.ogg' + forwardsound = 'sound/weapons/guns/interact/la_forward.ogg' + empty_icon = "leverchester-e" + + +//Paryying. +/obj/item/weapon/gun/projectile/shotgun/pump/boltaction/handle_shield(mob/living/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + if(default_sword_parry(user, damage, damage_source, attacker, def_zone, attack_text)) + return 1 + return 0 + +//AMMO +/obj/item/ammo_casing/brifle + desc = "An old worn out looking bullet casing." + caliber = "763" + projectile_type = /obj/item/projectile/bullet/rifle/a762/brifle + icon_state = "brifle" + spent_icon = "brifle-casing" + ammo_stack = /obj/item/ammo_magazine/handful/brifle_handful/two + +/obj/item/projectile/bullet/rifle/a762/brifle + fire_sound = "brifle" + penetrating = FALSE + damage = 65 + +/obj/item/ammo_magazine/brifle + name = "Rifle Box" + desc = "A box of rifle ammo" + icon_state = "rbox" + caliber = "763" + ammo_type = /obj/item/ammo_casing/brifle + matter = list(DEFAULT_WALL_MATERIAL = 1260) + max_ammo = 20 + + + +//Shitty shotgun +/obj/item/weapon/gun/projectile/shotgun/pump/shitty + name = "\improper WTX Frontier Special" + desc = "A common shotgun used in the trenches. It's not the best made and is prone to jamming." + icon_state = "winchester" + item_state = "winchester" + wielded_item_state = "winchester-wielded" + condition = 65 + ammo_type = /obj/item/ammo_casing/shotgun/pellet + one_hand_penalty = 20 //FIRE THIS THING WITH BOTH FUCKING HANDS AS WELL + empty_icon = "winchester-e" + + +/obj/item/weapon/gun/projectile/shotgun/pump/shitty/sawn + name = "\improper Sawn Off WTX Frontier Special" + desc = "A sawn off version of a common shotgun used in the trenches. It's not the best made and is prone to jamming." + icon_state = "sawnchester" + item_state = "sawnchester" + wielded_item_state = "sawnchester-wielded" + slot_flags = SLOT_BELT|SLOT_BACK|SLOT_S_STORE + w_class = ITEM_SIZE_NORMAL + max_shells = 4 + empty_icon = "sawnchester-e" + + +/obj/item/weapon/gun/projectile/shotgun/pump/shitty/sawn/smallshotty + name = "\improper WTX Reckoning" + desc = "Small looking shotgun that fires a powerful shot." + icon_state = "smallshotty" + item_state = "smallshotty" + wielded_item_state = "smallshotty-wielded" + empty_icon = "smallshotty-e" + + +/obj/item/weapon/gun/projectile/shotgun/pump/shitty/bayonet + force = 20 + sharp = 1 + attack_verb = list ("stabbed", "sliced") + hitsound = "stab_sound" + +/obj/item/weapon/gun/projectile/shotgun/pump/shitty/bayonet/New() + ..() + add_bayonet() + desc += " This one has a bayonet." + + + +/obj/item/weapon/gun/projectile/automatic/m22/warmonger + name = "Mk.3 Warmonger" + desc = "A semi automatic battle rifle. Fires faster, and more reliably than most of the shitty bolt action rifles the grunts get." + icon_state = "autorifle" + item_state = "autorifle" + wielded_item_state = "autorifle-wielded" + fire_sound = 'sound/weapons/gunshot/gunshot_arifle.ogg' + loaded_icon = "autorifle" + unwielded_loaded_icon = "autorifle" + wielded_loaded_icon = "autorifle-wielded" + unloaded_icon = "autorifle-e" + unwielded_unloaded_icon = "autorifle-e" + wielded_unloaded_icon = "autorifle-wielded-e" + condition = 75 + + magazine_type = /obj/item/ammo_magazine/c45rifle/akarabiner + allowed_magazines = /obj/item/ammo_magazine/c45rifle/akarabiner + fire_delay = 0 + firemodes = list() + w_class = ITEM_SIZE_HUGE + gun_type = GUN_SEMIAUTO + + +/obj/item/weapon/gun/projectile/automatic/m22/warmonger/fully_auto + name = "Mk.5 Warmonger" + desc = "A fully automatic battle rifle. Fires faster, and more reliably than the old shitty bolt action rifles from the old war." + icon_state = "autorifle-alt" + item_state = "autorifle-alt" + wielded_item_state = "autorifle-alt-wielded" + fire_sound = 'sound/weapons/guns/fire/ak_fire.ogg' + unload_sound = 'sound/weapons/guns/interact/ak_magout.ogg' + reload_sound = 'sound/weapons/guns/interact/ak_magin.ogg' + cock_sound = 'sound/weapons/guns/interact/ak_cock.ogg' + + loaded_icon = "autorifle-alt" + unwielded_loaded_icon = "autorifle-alt" + wielded_loaded_icon = "autorifle-alt-wielded" + unloaded_icon = "autorifle-alt-e" + unwielded_unloaded_icon = "autorifle-alt-e" + wielded_unloaded_icon = "autorifle-alt-wielded-e" + + gun_type = GUN_AUTOMATIC + + firemodes = list( + list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, one_hand_penalty=4, burst_accuracy=null, dispersion=null, automatic = 0), + list(mode_name="automatic", burst=1, fire_delay=0, move_delay=0, one_hand_penalty=6, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 3, 5), automatic = 2) + ) + + +/obj/item/weapon/gun/projectile/automatic/m22/warmonger/fully_auto/nemesis + name = "Mk.1 Nemesis" + desc = "God, it's fucking ugly, but it does at least kill. Takes Warmonger magazines." + icon_state = "bar" + item_state = "bar" + wielded_item_state = "bar-wielded" + fire_sound = 'sound/weapons/guns/fire/bar_fire.ogg' + unload_sound = 'sound/weapons/guns/interact/bar_magout.ogg' + reload_sound = 'sound/weapons/guns/interact/bar_magin.ogg' + cock_sound = 'sound/weapons/guns/interact/bar_cock.ogg' + + loaded_icon = "bar" + unwielded_loaded_icon = "bar" + wielded_loaded_icon = "bar-wielded" + unloaded_icon = "bar-e" + unwielded_unloaded_icon = "bar-e" + wielded_unloaded_icon = "bar-wielded-e" + +/obj/item/weapon/gun/projectile/automatic/m22/warmonger/m14 + name = "M41 Eclipse" + desc = "A semi automatic rifle. It's made out of the leftover scraps from the old war. Fires a powerful round, but only one at a time." + icon_state = "semirifle" + item_state = "semirifle" + wielded_item_state = "semirifle-wielded" + fire_sound = 'sound/weapons/guns/fire/m14_fire.ogg' + unload_sound = 'sound/weapons/guns/interact/fal_magout.ogg' + reload_sound = 'sound/weapons/guns/interact/fal_magin.ogg' + caliber = "a762" + loaded_icon = "semirifle" + unwielded_loaded_icon = "semirifle" + wielded_loaded_icon = "semirifle-wielded" + unloaded_icon = "semirifle-e" + unwielded_unloaded_icon = "semirifle-e" + wielded_unloaded_icon = "battlerifle-wielded-e" + + magazine_type = /obj/item/ammo_magazine/a762/m14 + allowed_magazines = /obj/item/ammo_magazine/a762/m14 + +/obj/item/ammo_magazine/a762/m14 + name = "M41 magazine" + desc = "Found either in your gun, in your satchel, or on the ground empty." + max_ammo = 20 + icon_state = "autorifle" + + + + + +/obj/item/weapon/gun/projectile/automatic/m22/warmonger/m14/battlerifle + name = "Mk.1 Armageddon" + desc = "A very powerful semi automatic rifle. Much nicer than whatever scrap those medics are using." + icon_state = "battlerifle" + item_state = "battlerifle" + wielded_item_state = "battlerifle-wielded" + fire_sound = 'sound/weapons/guns/fire/fal_fire.ogg' + + magazine_type = /obj/item/ammo_magazine/a762/m14/battlerifle_mag + allowed_magazines = list(/obj/item/ammo_magazine/a762/m14/battlerifle_mag, /obj/item/ammo_magazine/c45rifle/akarabiner) + + loaded_icon = "battlerifle" + unwielded_loaded_icon = "battlerifle" + wielded_loaded_icon = "battlerifle-wielded" + unloaded_icon = "battlerifle-e" + unwielded_unloaded_icon = "battlerifle-e" + wielded_unloaded_icon = "battlerifle-wielded-e" + +/obj/item/ammo_magazine/a762/m14/battlerifle_mag + name = "Armageddon magazine" + + +/obj/item/weapon/gun/projectile/automatic/m22/warmonger/m14/battlerifle/rsc + name = "Mk.1 Armageddon" + icon_state = "rsc" + item_state = "rsc" + wielded_item_state = "rsc-wielded" + + magazine_type = /obj/item/ammo_magazine/a762/rsc + allowed_magazines = /obj/item/ammo_magazine/a762/rsc + + caliber = "763" + + loaded_icon = "rsc" + unwielded_loaded_icon = "rsc" + wielded_loaded_icon = "rsc-wielded" + unloaded_icon = "rsc-e" + unwielded_unloaded_icon = "rsc-e" + wielded_unloaded_icon = "rsc-wielded-e" + +/obj/item/ammo_magazine/a762/rsc + icon_state = "rsc" + name = "Armageddon clip" + max_ammo = 5 + caliber = "763" + ammo_type = /obj/item/ammo_casing/brifle + +/obj/item/weapon/gun/projectile/automatic/m22/combatrifle + name = "Mk. 2 Nightfall" + desc = "An advanced post war rifle, this one has different fire modes and relative accuracy!" + icon_state = "combatrifle" + item_state ="combatrifle" + magazine_type = /obj/item/ammo_magazine/c45rifle/combatrifle + allowed_magazines = /obj/item/ammo_magazine/c45rifle/combatrifle + one_hand_penalty = 5 + wielded_item_state = "combatrifle-wielded" + fire_sound = 'sound/weapons/guns/fire/combatrifle_fire.ogg' + unload_sound = 'sound/weapons/guns/interact/combatrifle_magout.ogg' + reload_sound = 'sound/weapons/guns/interact/combatrifle_magin.ogg' + cock_sound = 'sound/weapons/guns/interact/combatrifle_cock.ogg' + + loaded_icon = "combatrifle" + unwielded_loaded_icon = "combatrifle" + wielded_loaded_icon = "combatrifle-wielded" + unloaded_icon = "combatrifle-e" + unwielded_unloaded_icon = "combatrifle-e" + wielded_unloaded_icon = "combatrifle-wielded-e" + + gun_type = GUN_AUTOMATIC + + w_class = ITEM_SIZE_HUGE + + //Assault rifle, burst fire degrades quicker than SMG, worse one-handing penalty, slightly increased move delay + firemodes = list( + list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, one_hand_penalty=4, burst_accuracy=null, dispersion=null, automatic = 0), + list(mode_name="automatic", burst=1, fire_delay=0, move_delay=0, one_hand_penalty=6, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 3, 5), automatic = 2) + ) + + +/obj/item/weapon/gun/projectile/automatic/mg08 + name = "LMG Harbinger" + desc = "Named for the death it brings." + //icon = 'icons/obj/gunx35.dmi' + icon_state = "hmg" + item_state = "hmg" + str_requirement = 18 + w_class = ITEM_SIZE_HUGE + force = 10 + slot_flags = SLOT_BACK|SLOT_S_STORE + max_shells = 50 + caliber = "a556" + origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 1, TECH_ILLEGAL = 2) + ammo_type = /obj/item/ammo_casing/a556 + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/box/a556/mg08 + allowed_magazines = /obj/item/ammo_magazine/box/a556/mg08 + one_hand_penalty = 50 + wielded_item_state = "hmg-wielded" + fire_sound = 'sound/weapons/gunshot/harbinger.ogg' + unload_sound = 'sound/weapons/guns/interact/ltrifle_magout.ogg' + reload_sound = 'sound/weapons/guns/interact/ltrifle_magin.ogg' + cock_sound = 'sound/weapons/guns/interact/ltrifle_cock.ogg' + loaded_icon = "hmg" + unwielded_loaded_icon = "hmg" + wielded_loaded_icon = "hmg-wielded" + unloaded_icon = "hmg-e" + unwielded_unloaded_icon = "hmg-e" + wielded_unloaded_icon = "hmg-wielded-e" + fire_delay=2 + burst=1 + move_delay=12 + one_hand_penalty=8 + automatic = 2 + firemodes = list() + gun_type = GUN_LMG + condition = 150 //Enough for one clean mag. + + +/obj/item/weapon/gun/projectile/automatic/gpmg + name = "GPMG Requiem" + desc = "A coveted LMG. Lighter than the Harbingers of the old war, but still just as deadly!" + icon_state = "lmg" + item_state = "lmg" + wielded_item_state = "lmg-wielded" + loaded_icon = "lmg" + unwielded_loaded_icon = "lmg" + wielded_loaded_icon = "lmg-wielded" + unloaded_icon = "lmg-e" + unwielded_unloaded_icon = "lmg-e" + wielded_unloaded_icon = "lmg-wielded-e" + str_requirement = 16 + w_class = ITEM_SIZE_HUGE + force = 10 + slot_flags = SLOT_BACK|SLOT_S_STORE + max_shells = 50 + caliber = "a556" + origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 1, TECH_ILLEGAL = 2) + ammo_type = /obj/item/ammo_casing/a556 + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/box/a556/mg08 + allowed_magazines = /obj/item/ammo_magazine/box/a556/mg08 + one_hand_penalty = 50 + fire_sound = 'sound/weapons/gunshot/harbinger.ogg' + unload_sound = 'sound/weapons/guns/interact/ltrifle_magout.ogg' + reload_sound = 'sound/weapons/guns/interact/ltrifle_magin.ogg' + cock_sound = 'sound/weapons/guns/interact/ltrifle_cock.ogg' + fire_delay=2 + burst=1 + can_jam = FALSE + one_hand_penalty=8 + burst_accuracy=list(0,-1,-1) + dispersion=list(0.0, 3, 5) + automatic = 2 + firemodes = list() + gun_type = GUN_LMG + +/obj/item/weapon/gun/projectile/automatic/machinepistol + name = "Mk.2 Soulburn SMG" + desc = "A prototype SMG. Prone to malfunction but it shoots perty fast." + icon_state = "machinepistol" + item_state = "machinepistol" + wielded_item_state = "machinepistol-wielded" + one_hand_penalty = 50 + slot_flags = SLOT_BACK|SLOT_S_STORE + w_class = ITEM_SIZE_HUGE + + fire_sound = 'sound/weapons/guns/fire/smg_fire.ogg' + + magazine_type = /obj/item/ammo_magazine/mc9mmt/machinepistol + allowed_magazines = /obj/item/ammo_magazine/mc9mmt/machinepistol + + loaded_icon = "machinepistol" + unwielded_loaded_icon = "machinepistol" + wielded_loaded_icon = "machinepistol-wielded" + unloaded_icon = "machinepistol-e" + unwielded_unloaded_icon = "machinepistol-e" + wielded_unloaded_icon = "machinepistol-e" + + gun_type = GUN_SMG + +/obj/item/weapon/gun/projectile/automatic/machinepistol/wooden + name = "Mk.1 Soulburn SMG" + desc = "A prototype, protoype SMG. Prone to malfunction but it shoots perty fast." + icon_state = "schmeiser" + item_state = "schmeiser" + wielded_item_state = "schmeiser-wielded" + + loaded_icon = "schmeiser" + unwielded_loaded_icon = "schmeiser" + wielded_loaded_icon = "schmeiser-wielded" + unloaded_icon = "schmeiser-e" + unwielded_unloaded_icon = "schmeiser-e" + wielded_unloaded_icon = "schmeiser-e" + +/obj/item/weapon/gun/projectile/automatic/flamer + name = "Mk.1 Scorcher" + desc = "Used to shoot flames at people when bullets just won't do." + icon_state = "flamer" + item_state = "flamer" + wielded_item_state = "flamer-wielded" + caliber = "flamer" + one_hand_penalty = 50 + str_requirement = 18 + fire_sound = 'sound/effects/fire01.ogg' + casingsound = null//No eject sound for you. + firemodes = list() + automatic = 0.1 + fire_delay=0 + burst=1 + magazine_type = /obj/item/ammo_magazine/flamer + allowed_magazines = /obj/item/ammo_magazine/flamer + can_jam = FALSE + + loaded_icon = "flamer" + unwielded_loaded_icon = "flamer" + wielded_loaded_icon = "flamer-wielded" + unloaded_icon = "flamer-e" + unwielded_unloaded_icon = "flamer-e" + wielded_unloaded_icon = "flamer-wielded-e" + + gun_type = GUN_PISTOL //anyone can use this... just not anyone should. + + + +/obj/item/weapon/gun/projectile/automatic/autoshotty + name = "MS Warcrime" + desc = "Someone came up with the idea of making a shotgun shoot quickly, and it's dreadful." + icon_state = "autoshotty" + item_state = "autoshotty" + wielded_item_state = "autoshotty" + magazine_type = /obj/item/ammo_magazine/autoshotty + allowed_magazines = /obj/item/ammo_magazine/autoshotty + caliber = "shotgun" + fire_sound = 'sound/weapons/guns/fire/autoshotty_fire.ogg' + ammo_type = /obj/item/ammo_casing/shotgun/pellet + reload_sound = 'sound/weapons/guns/interact/autoshotty_magin.ogg' + unload_sound = 'sound/weapons/guns/interact/autoshotty_magout.ogg' + cock_sound = 'sound/weapons/guns/interact/autoshotty_cock.ogg' + slot_flags = SLOT_BACK|SLOT_S_STORE + loaded_icon = "autoshotty" + unwielded_loaded_icon = "autoshotty" + wielded_loaded_icon = "autoshotty-wielded" + unloaded_icon = "autoshotty-e" + unwielded_unloaded_icon = "autoshotty-e" + wielded_unloaded_icon = "autoshotty-wielded-e" + burst=1 + fire_delay=2 + one_hand_penalty=7 + dispersion=list(0.0, 0.8, 1.5) + automatic = 2 + firemodes = list() + + gun_type = GUN_SHOTGUN + +/obj/item/ammo_magazine/autoshotty + name = "Warcrime mag" + desc = "Just looking at it makes you bloodthirsty." + icon_state = "autoshotty" + caliber = "shotgun" + mag_type = MAGAZINE + ammo_type = /obj/item/ammo_casing/shotgun/pellet + max_ammo = 6 + multiple_sprites = 1 + + +/obj/item/weapon/gun/projectile/warfare + name = "Mk.1 Reckoning" + icon_state = "handgun" + item_state = "handgun" + fire_sound = "gunshot"//Pistol sounds. + desc = "A 45 caliber pistol that will put holes in your enemy if you're lucky. Better than nothing, but not by much." + magazine_type = /obj/item/ammo_magazine/c45m/warfare + allowed_magazines = /obj/item/ammo_magazine/c45m/warfare + caliber = ".45" + load_method = MAGAZINE + fire_delay = 4 + +/obj/item/weapon/gun/projectile/warfare/update_icon()//We gotta snowflake this a bit. + ..() + if(ammo_magazine) + if(ammo_magazine.stored_ammo.len) + icon_state = "[initial(icon_state)][ammo_magazine.stored_ammo.len]" + else + icon_state = "[initial(icon_state)]0" + else + icon_state = "handgun-e" + + +/obj/item/ammo_magazine/c45m/warfare + name = "Reckoning magazine (.45)" + icon_state = "handgunmag" + mag_type = MAGAZINE + ammo_type = /obj/item/ammo_casing/c45 + caliber = ".45" + max_ammo = 7 + multiple_sprites = 1 \ No newline at end of file diff --git a/code/modules/projectiles/guns/projectile/mortar.dm b/code/modules/projectiles/guns/projectile/mortar.dm new file mode 100644 index 00000000..de94d774 --- /dev/null +++ b/code/modules/projectiles/guns/projectile/mortar.dm @@ -0,0 +1,151 @@ + +//The mortar shell item. +/obj/item/mortar_shell + name = "HE Mortar Shell" + icon = 'icons/obj/items/mortars.dmi' + icon_state = "he_mortar" + var/mortar_type = "shrapnel" + +/obj/item/mortar_shell/flare + name = "Red Illumination Mortar" + icon_state = "r_flare" + mortar_type = "rflare" + +/obj/item/mortar_shell/flare/blue + name = "Blue Illumination Mortar" + icon_state = "b_flare" + mortar_type = "bflare" + +//The mortar shell launcher item. This is the one you use. +/obj/item/mortar_launcher + name = "HE Trench Ender" + icon = 'icons/obj/items/mortars.dmi' + icon_state = "mortar_tube" + item_state = "mortar_tube" + var/loaded = FALSE + var/loaded_with = null + var/deployed = FALSE + +/obj/item/mortar_launcher/attackby(obj/item/weapon/W, mob/user) + . = ..() + if(!istype(W, /obj/item/mortar_shell)) + return + if(loaded) + to_chat(user, "There is already a mortar loaded!") + return + if(!deployed) + to_chat(user, "I have to deploy the mortar first!") + return + var/obj/item/mortar_shell/M = W + loaded_with = M.mortar_type + loaded = TRUE + playsound(src, 'sound/weapons/mortar_load.ogg', 100, FALSE) + user.visible_message("[user] loads the [src] with \the [W]!") + qdel(W) + update_icon() + +/obj/item/mortar_launcher/update_icon(var/mob/living/carbon/human/H) + if(deployed) + item_state = "blank" + else + item_state = "mortar_tube" + + if(istype(H)) + H.regenerate_icons() + ..() + +/obj/item/mortar_launcher/afterattack(atom/A, mob/living/user) + ..() + if(!deployed)//Can't fire. + to_chat(user, "I can't fire it if it's not deployed.") + return + if(!loaded)//Nothing to fire. + to_chat(user, "It's not loaded.") + return + if(istype(user.loc, /turf/simulated/floor/tiled)) + to_chat(user, "I can't use this indoors.") + return + if(!user.zoomed) + to_chat(user, "I must zoom into the distance to get a good shot in on.") + return + var/obj/item/I = user.get_inactive_hand() + if(I) + to_chat(user, "I need a free hand for this.") + return + log_and_message_admins("[user] has fired a mortar at [A]!", user) + launch_mortar(A, user, loaded_with) + QDEL_NULL(loaded) + + +/obj/item/mortar_launcher/proc/launch_mortar(atom/A, mob/living/user, var/mortar_type) + user.visible_message("[user] fires the [src]!") + playsound(src, 'sound/weapons/mortar_fire.ogg', 100, FALSE) + spawn(35) + drop_mortar(get_turf(A),mortar_type) + loaded = FALSE + +/obj/item/mortar_launcher/attack_self(mob/user) + . = ..() + if(deployed)//If there's a mortar deployed, then pack it up again. + pack_up_mortar(user) + else + deploy_mortar(user)//Otherwise, deploy that motherfucker. + +/obj/item/mortar_launcher/proc/deploy_mortar(mob/user) + for(var/obj/structure/mortar_launcher_structure/M in user.loc)//If there's already a mortar there then don't deploy it. Dunno how that's possible but stranger things have happened. + if(M) + to_chat(user, "There is already a mortar here.") + return + user.visible_message("[user] starts to deploy the [src]") + if(!do_after(user,30)) + return + var/obj/structure/mortar_launcher_structure/M = new(get_turf(user)) //Make a new one here. + M.dir = user.dir + switch(M.dir) + if(EAST) + user.pixel_x -= 5 + if(WEST) + user.pixel_x += 5 + if(NORTH) + user.pixel_y -= 5 + if(SOUTH) + user.pixel_y += 5 + M.plane = ABOVE_HUMAN_PLANE + deployed = TRUE + playsound(src, 'sound/weapons/mortar_deploy.ogg', 100, FALSE) + update_icon(user) + +/obj/item/mortar_launcher/proc/pack_up_mortar(mob/user) + user.visible_message("[user] packs up the [src]") + for(var/obj/structure/mortar_launcher_structure/M in user.loc) + switch(M.dir)//Set our offset back to normal. + if(EAST) + user.pixel_x += 5 + if(WEST) + user.pixel_x -= 5 + if(NORTH) + user.pixel_y += 5 + if(SOUTH) + user.pixel_y -= 5 + qdel(M) //Delete the mortar structure. + deployed = FALSE + update_icon(user) + +/obj/item/mortar_launcher/dropped(mob/user) + . = ..() + if(deployed) + pack_up_mortar(user) + +/obj/structure/mortar_launcher_structure //That thing that's created when you place down your mortar, purely for looks. + name = "Deployed HE Trench Ender" + icon = 'icons/obj/items/mortars.dmi' + icon_state = "mortar_tube_structure" + anchored = TRUE //No moving this around please. + +/obj/structure/mortar_launcher_structure/CanPass(atom/movable/mover, turf/target, height, air_group)//Humans cannot pass cross this thing in any way shape or form. + if(ishuman(mover)) + return FALSE + +/obj/structure/mortar_launcher_structure/CheckExit(atom/movable/O, turf/target)//Humans can't leave this thing either. + if(ishuman(O)) + return FALSE \ No newline at end of file diff --git a/code/modules/projectiles/guns/projectile/pistol.dm b/code/modules/projectiles/guns/projectile/pistol.dm new file mode 100644 index 00000000..d9b854c2 --- /dev/null +++ b/code/modules/projectiles/guns/projectile/pistol.dm @@ -0,0 +1,300 @@ +/obj/item/weapon/gun/projectile/colt + name = "vintage .45 pistol" + desc = "A cheap Martian knock-off of a Colt M1911. Uses .45 rounds." + magazine_type = /obj/item/ammo_magazine/c45m + allowed_magazines = /obj/item/ammo_magazine/c45m + icon_state = "colt" + caliber = ".45" + origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2) + load_method = MAGAZINE + +/obj/item/weapon/gun/projectile/colt/officer + name = "military .45 pistol" + desc = "The WT45 - a mass produced kinetic sidearm well-known in films and entertainment programming for being the daily carry choice issued to officers of the Sol Central Government Defense Forces. Uses .45 rounds." + icon_state = "usp" + accuracy = 0.35 + fire_delay = 6.5 + +/obj/item/weapon/gun/projectile/colt/officer/update_icon() + ..() + if(ammo_magazine && ammo_magazine.stored_ammo.len) + icon_state = "usp" + else + icon_state = "usp-e" + +/obj/item/weapon/gun/projectile/sec + name = ".45 pistol" + desc = "The NT Mk58 is a cheap, ubiquitous sidearm, produced by a NanoTrasen subsidiary. Found pretty much everywhere humans are. Uses .45 rounds." + icon_state = "secguncomp" + magazine_type = /obj/item/ammo_magazine/c45m + allowed_magazines = /obj/item/ammo_magazine/c45m + caliber = ".45" + accuracy = -0.35 + fire_delay = 5.5 + origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2) + load_method = MAGAZINE + +/obj/item/weapon/gun/projectile/sec/update_icon() + ..() + if(ammo_magazine && ammo_magazine.stored_ammo.len) + icon_state = "secguncomp" + else + icon_state = "secguncomp-e" + +/obj/item/weapon/gun/projectile/sec/flash + name = ".45 signal pistol" + +/obj/item/weapon/gun/projectile/sec/wood + desc = "The NT Mk58 is a cheap, ubiquitous sidearm, produced by a NanoTrasen subsidiary. This one has a sweet wooden grip, among other modifications. Uses .45 rounds." + name = "custom .45 Pistol" + icon_state = "secgundark" + accuracy = 0 + +/obj/item/weapon/gun/projectile/sec/wood/update_icon() + ..() + if(ammo_magazine && ammo_magazine.stored_ammo.len) + icon_state = "secgundark" + else + icon_state = "secgundark-e" + +/obj/item/weapon/gun/projectile/talon + name = "M2A3 Pistol" + desc = "Magnum opus of pistols. Also known as Talon." + icon_state = "talon" + w_class = ITEM_SIZE_SMALL + fire_delay = 5 + origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2, TECH_ILLEGAL = 2) + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/c45m + allowed_magazines = /obj/item/ammo_magazine/c45m + caliber = ".45" + condition = 70 + auto_eject = 1 + auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg' + jammed_icon = "talon-j" + +/obj/item/weapon/gun/projectile/talon/update_icon() + ..() + if(!is_jammed) + if(ammo_magazine && ammo_magazine.stored_ammo.len) + icon_state = "talon" + else + icon_state = "talon-e" + +/obj/item/weapon/gun/projectile/silenced + name = "silenced pistol" + desc = "A handgun with an integral silencer. Uses .45 rounds." + icon_state = "silenced_pistol" + w_class = ITEM_SIZE_NORMAL + caliber = ".45" + silenced = 1 + origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2, TECH_ILLEGAL = 8) + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/c45m + allowed_magazines = /obj/item/ammo_magazine/c45m + +/obj/item/weapon/gun/projectile/makarov + name = "New-o-Russia handgun" + icon_state = "makarov" + w_class = ITEM_SIZE_NORMAL + caliber = "9mm" + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/mc9mm + allowed_magazines = /obj/item/ammo_magazine/mc9mm + +/obj/item/weapon/gun/projectile/makarov/update_icon() + ..() + if(ammo_magazine && ammo_magazine.stored_ammo.len) + icon_state = "makarov" + else + icon_state = "makarov-e" + +/obj/item/weapon/gun/projectile/magnum_pistol + name = ".50 magnum pistol" + desc = "The HelTek Magnus, a robust terran handgun that uses .50 AE ammo." + icon_state = "magnum" + item_state = "revolver" + force = 14.0 + caliber = ".50" + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/a50 + allowed_magazines = /obj/item/ammo_magazine/a50 + +/obj/item/weapon/gun/projectile/magnum_pistol/update_icon() + ..() + if(ammo_magazine && ammo_magazine.stored_ammo.len) + icon_state = "magnum" + else + icon_state = "magnum-e" + +/obj/item/weapon/gun/projectile/gyropistol + name = "gyrojet pistol" + desc = "A bulky pistol designed to fire self propelled rounds." + icon_state = "gyropistol" + max_shells = 8 + caliber = "75" + origin_tech = list(TECH_COMBAT = 3) + ammo_type = /obj/item/ammo_casing/a75 + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/a75 + fire_delay = 25 + auto_eject = 1 + auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg' + +/obj/item/weapon/gun/projectile/gyropistol/update_icon() + ..() + if(ammo_magazine) + icon_state = "gyropistolloaded" + else + icon_state = "gyropistol" + +/obj/item/weapon/gun/projectile/pistol + name = "holdout pistol" + desc = "The Lumoco Arms P3 Whisper. A small, easily concealable gun. Uses 9mm rounds." + icon_state = "pistol" + item_state = null + w_class = ITEM_SIZE_SMALL + caliber = "9mm" + silenced = 0 + fire_delay = 1 + origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2, TECH_ILLEGAL = 2) + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/mc9mm + allowed_magazines = /obj/item/ammo_magazine/mc9mm + condition = 75 + +/obj/item/weapon/gun/projectile/pistol/flash + name = "holdout signal pistol" + magazine_type = /obj/item/ammo_magazine/mc9mm/flash + +/obj/item/weapon/gun/projectile/pistol/attack_hand(mob/user as mob) + if(user.get_inactive_hand() == src) + if(silenced) + if(user.l_hand != src && user.r_hand != src) + ..() + return + to_chat(user, "You unscrew [silenced] from [src].") + user.put_in_hands(silenced) + silenced = initial(silenced) + w_class = initial(w_class) + update_icon() + return + ..() + +/obj/item/weapon/gun/projectile/pistol/attackby(obj/item/I as obj, mob/user as mob) + if(istype(I, /obj/item/weapon/silencer)) + if(user.l_hand != src && user.r_hand != src) //if we're not in his hands + to_chat(user, "You'll need [src] in your hands to do that.") + return + user.drop_item() + to_chat(user, "You screw [I] onto [src].") + silenced = I //dodgy? + w_class = ITEM_SIZE_NORMAL + I.forceMove(src) //put the silencer into the gun + update_icon() + return + ..() + +/obj/item/weapon/gun/projectile/pistol/update_icon() + ..() + if(silenced) + icon_state = "pistol-silencer" + else + icon_state = "pistol" + if(!(ammo_magazine && ammo_magazine.stored_ammo.len)) + icon_state = "[icon_state]-e" + +/obj/item/weapon/silencer + name = "silencer" + desc = "A silencer." + icon = 'icons/obj/gun.dmi' + icon_state = "silencer" + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/gun/projectile/pirate + name = "zip gun" + desc = "Little more than a barrel, handle, and firing mechanism, cheap makeshift firearms like this one are not uncommon in frontier systems." + icon_state = "zipgun" + item_state = "sawnshotgun" + handle_casings = CYCLE_CASINGS //player has to take the old casing out manually before reloading + load_method = SINGLE_CASING + max_shells = 1 //literally just a barrel + + var/global/list/ammo_types = list( + /obj/item/ammo_casing/a357 = ".357", + /obj/item/ammo_casing/shotgun = "12 gauge", + /obj/item/ammo_casing/shotgun = "12 gauge", + /obj/item/ammo_casing/shotgun/pellet = "12 gauge", + /obj/item/ammo_casing/shotgun/pellet = "12 gauge", + /obj/item/ammo_casing/shotgun/pellet = "12 gauge", + /obj/item/ammo_casing/shotgun/beanbag = "12 gauge", + /obj/item/ammo_casing/shotgun/stunshell = "12 gauge", + /obj/item/ammo_casing/shotgun/flash = "12 gauge", + /obj/item/ammo_casing/a762 = "7.62mm", + /obj/item/ammo_casing/a556 = "5.56mm" + ) + +/obj/item/weapon/gun/projectile/pirate/New() + ammo_type = pick(ammo_types) + desc += " Uses [ammo_types[ammo_type]] rounds." + + var/obj/item/ammo_casing/ammo = ammo_type + caliber = initial(ammo.caliber) + ..() + +// Zip gun construction. +/obj/item/weapon/zipgunframe + name = "zip gun frame" + desc = "A half-finished zip gun." + icon_state = "zipgun0" + item_state = "zipgun-solid" + var/buildstate = 0 + +/obj/item/weapon/zipgunframe/update_icon() + icon_state = "zipgun[buildstate]" + +/obj/item/weapon/zipgunframe/examine(mob/user) + . = ..() + ..(user) + switch(buildstate) + if(1) to_chat(user, "It has a barrel loosely fitted to the stock.") + if(2) to_chat(user, "It has a barrel that has been secured to the stock with tape.") + if(3) to_chat(user, "It has a trigger and firing pin assembly loosely fitted into place.") + +/obj/item/weapon/zipgunframe/attackby(var/obj/item/thing, var/mob/user) + if(istype(thing,/obj/item/pipe) && buildstate == 0) + user.drop_from_inventory(thing) + qdel(thing) + user.visible_message("\The [user] fits \the [thing] to \the [src] as a crude barrel.") + add_fingerprint(user) + buildstate++ + update_icon() + return + else if(istype(thing,/obj/item/weapon/tape_roll) && buildstate == 1) + user.visible_message("\The [user] secures the assembly with \the [thing].") + add_fingerprint(user) + buildstate++ + update_icon() + return + else if(istype(thing,/obj/item/device/assembly/mousetrap) && buildstate == 2) + user.drop_from_inventory(thing) + qdel(thing) + user.visible_message("\The [user] takes apart \the [thing] and uses the parts to construct a crude trigger and firing mechanism inside the assembly.") + add_fingerprint(user) + buildstate++ + update_icon() + return + else if(isScrewdriver(thing) && buildstate == 3) + user.visible_message("\The [user] secures the trigger assembly with \the [thing].") + playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) + var/obj/item/weapon/gun/projectile/pirate/zipgun + zipgun = new/obj/item/weapon/gun/projectile/pirate { starts_loaded = 0 } (loc) + if(ismob(loc)) + var/mob/M = loc + M.drop_from_inventory(src) + M.put_in_hands(zipgun) + transfer_fingerprints_to(zipgun) + qdel(src) + return + else + ..() diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm new file mode 100644 index 00000000..ae364170 --- /dev/null +++ b/code/modules/projectiles/guns/projectile/revolver.dm @@ -0,0 +1,138 @@ +/obj/item/weapon/gun/projectile/revolver + name = "revolver" + desc = "The Lumoco Arms HE Colt is a choice revolver for when you absolutely, positively need to put a hole in the other guy. Uses .357 ammo." + icon_state = "cptrevolver" + item_state = "crevolver" + caliber = "357" + origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2) + handle_casings = CYCLE_CASINGS + max_shells = 6 + fire_delay = 6.75 //Revolvers are naturally slower-firing + ammo_type = /obj/item/ammo_casing/a357 + var/chamber_offset = 0 //how many empty chambers in the cylinder until you hit a round + unload_sound = 'sound/weapons/guns/interact/rev_magout.ogg' + reload_sound = 'sound/weapons/guns/interact/rev_magin.ogg' + bulletinsert_sound = 'sound/weapons/guns/interact/rev_magin.ogg' + fire_sound = 'sound/weapons/guns/fire/revolver.ogg' + +/obj/item/weapon/gun/projectile/revolver/cpt + name = "Captain's Special" + desc = "The sort of weapon usually found on nobility, such as captains or commandants." + icon_state = "cptrevolver" + item_state = "crevolver" + +/obj/item/weapon/gun/projectile/revolver/cpt/magistrate + name = "Commandant's Special" + +/obj/item/weapon/gun/projectile/revolver/attack_self(mob/user) + . = ..() + unload_ammo(user, allow_dump=TRUE) + +/obj/item/weapon/gun/projectile/revolver/verb/spin_cylinder() + set name = "Spin cylinder" + set desc = "Fun when you're bored out of your skull." + set category = "Object" + + chamber_offset = 0 + visible_message("\The [usr] spins the cylinder of \the [src]!", \ + "You hear something metallic spin and click.") + playsound(src.loc, 'sound/weapons/revolver_spin.ogg', 100, 1) + loaded = shuffle(loaded) + if(rand(1,max_shells) > loaded.len) + chamber_offset = rand(0,max_shells - loaded.len) + +/obj/item/weapon/gun/projectile/revolver/consume_next_projectile() + if(chamber_offset) + chamber_offset-- + return + return ..() + +/obj/item/weapon/gun/projectile/revolver/load_ammo(var/obj/item/A, mob/user) + chamber_offset = 0 + return ..() + +/obj/item/weapon/gun/projectile/revolver/mateba + name = "mateba" + icon_state = "mateba" + caliber = ".50" + origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2) + ammo_type = /obj/item/ammo_casing/a50 + +/obj/item/weapon/gun/projectile/revolver/detective + name = "revolver" + desc = "A cheap Martian knock-off of a Smith & Wesson Model 10. Uses .38-Special rounds." + icon_state = "detective" + max_shells = 6 + caliber = "38" + origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2) + ammo_type = /obj/item/ammo_casing/c38 + +/obj/item/weapon/gun/projectile/revolver/detective/verb/rename_gun() + set name = "Name Gun" + set category = "Object" + set desc = "Click to rename your gun. If you're the detective." + + var/mob/M = usr + if(!M.mind) return 0 + if(!M.mind.assigned_role == "Detective") + to_chat(M, "You don't feel cool enough to name this gun, chump.") + return 0 + + var/input = sanitizeSafe(input("What do you want to name the gun?", ,""), MAX_NAME_LEN) + + if(src && input && !M.stat && in_range(M,src)) + SetName(input) + to_chat(M, "You name the gun [input]. Say hello to your new friend.") + return 1 + +// Blade Runner pistol. +/obj/item/weapon/gun/projectile/revolver/deckard + name = "Deckard .44" + desc = "A custom-built revolver, based off the semi-popular Detective Special model." + icon_state = "deckard-empty" + ammo_type = /obj/item/ammo_magazine/c38/rubber + +/obj/item/weapon/gun/projectile/revolver/deckard/emp + ammo_type = /obj/item/ammo_casing/c38/emp + +/obj/item/weapon/gun/projectile/revolver/deckard/update_icon() + ..() + if(loaded.len) + icon_state = "deckard-loaded" + else + icon_state = "deckard-empty" + +/obj/item/weapon/gun/projectile/revolver/deckard/load_ammo(var/obj/item/A, mob/user) + if(istype(A, /obj/item/ammo_magazine)) + flick("deckard-reload",src) + ..() + +/obj/item/weapon/gun/projectile/revolver/capgun + name = "cap gun" + desc = "Looks almost like the real thing! Ages 8 and up." + icon_state = "revolver-toy" + item_state = "revolver" + caliber = "caps" + origin_tech = list(TECH_COMBAT = 1, TECH_MATERIAL = 1) + handle_casings = CYCLE_CASINGS + max_shells = 7 + ammo_type = /obj/item/ammo_casing/cap + +/obj/item/weapon/gun/projectile/revolver/capgun/attackby(obj/item/weapon/wirecutters/W, mob/user) + if(!istype(W) || icon_state == "revolver") + return ..() + to_chat(user, "You snip off the toy markings off the [src].") + name = "revolver" + icon_state = "revolver" + desc += " Someone snipped off the barrel's toy mark. How dastardly." + return 1 + +/obj/item/weapon/gun/projectile/revolver/webley + name = "service revolver" + desc = "A rugged top break revolver based on the Webley Mk. VI model, with modern improvements. Uses .44 magnum rounds." + icon_state = "webley" + item_state = "webley" + max_shells = 6 + caliber = ".44" + origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2) + ammo_type = /obj/item/ammo_casing/c44 \ No newline at end of file diff --git a/code/modules/projectiles/guns/projectile/shotgun.dm b/code/modules/projectiles/guns/projectile/shotgun.dm new file mode 100644 index 00000000..465cadee --- /dev/null +++ b/code/modules/projectiles/guns/projectile/shotgun.dm @@ -0,0 +1,261 @@ +/obj/item/weapon/gun/projectile/shotgun + bulletinsert_sound = "shotgun_insert"// sound/weapons/guns/interact/shellinsert1.ogg and 2 + fire_sound = 'sound/weapons/guns/fire/shotgun.ogg' + parry_sounds = list('sound/weapons/blunt_parry1.ogg', 'sound/weapons/blunt_parry2.ogg', 'sound/weapons/blunt_parry3.ogg') + load_method = SINGLE_CASING|SINGLE_LOAD//|SPEEDLOADER //No more loading straight from boxes anymore. + slot_flags = SLOT_BACK|SLOT_S_STORE + var/empty_icon = null + +/obj/item/weapon/gun/projectile/shotgun/update_icon() + . = ..() + if(empty_icon) + if(!chambered && !loaded.len)//If there's an empty icon then use it. + icon_state = empty_icon + else if(!chambered && loaded.len) + icon_state = empty_icon + else + icon_state = initial(icon_state) + + +/obj/item/weapon/gun/projectile/shotgun/pump + name = "shotgun" + desc = "The mass-produced W-T Remmington 29x shotgun is a favourite of police and security forces on many worlds. Useful for sweeping alleys." + icon_state = "shotgun" + item_state = "shotgun" + max_shells = 5 + w_class = ITEM_SIZE_HUGE + force = 10 + obj_flags = OBJ_FLAG_CONDUCTIBLE + caliber = "shotgun" + origin_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 2) + ammo_type = /obj/item/ammo_casing/shotgun/beanbag + handle_casings = HOLD_CASINGS + one_hand_penalty = 25 + var/recentpump = 0 // to prevent spammage + var/pumpsound = 'sound/weapons/guns/interact/newpump.ogg' //Support for other kinds of pump weapons. + var/backsound = 'sound/weapons/guns/interact/shotgun_back.ogg' + var/forwardsound = 'sound/weapons/guns/interact/shotgun_forward.ogg' + casingsound = 'sound/weapons/guns/misc/shotgun_fall.ogg' //Same here. + wielded_item_state = "wshotgun" + gun_type = GUN_SHOTGUN + +/obj/item/weapon/gun/projectile/shotgun/pump/New() + ..() + pump(null, TRUE)//Chamber it when it's created. + + +/obj/item/weapon/gun/projectile/shotgun/pump/consume_next_projectile() + if(check_for_jam()) + return 0 + if(is_jammed) + return null + if(chambered) + return chambered.BB + return null + + +/obj/item/weapon/gun/projectile/shotgun/pump/examine(mob/user, distance) + . = ..() + if(chambered) + if(chambered.BB) + to_chat(user, "There is a LIVE one in the chamber.") + else + to_chat(user, "There is a SPENT one in the chamber.") + else + to_chat(user, "The chamber is EMPTY.") + +/obj/item/weapon/gun/projectile/shotgun/pump/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/ammo_magazine/box/shotgun)) + var/obj/item/ammo_magazine/box/shotgun/S = W + if(!S.open) + return + ..() + + +/obj/item/weapon/gun/projectile/shotgun/pump/attack_self(mob/living/user as mob) + if(world.time >= recentpump + 10) + pump(user) + recentpump = world.time + +/obj/item/weapon/gun/projectile/shotgun/pump/proc/pump(mob/M as mob, silent = FALSE) + if(is_jammed) + if(M) + M.visible_message("\The [M] begins to unjam [src].", "You begin to clear the jam of [src]") + if(!do_after(M, 40, src)) + return + is_jammed = 0 + playsound(src.loc, 'sound/effects/unjam.ogg', 50, 1) + if(M) + M.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + return + + if(!chambered && !loaded.len)//If there's an empty icon then use it. + pumpsound = null + if(M) + to_chat(M, "It's empty.") + return + + if(chambered && loaded.len) + pumpsound = initial(pumpsound) + + else if(!chambered && loaded.len) + pumpsound = forwardsound + + if(chambered)//We have a shell in the chamber + chambered.loc = get_turf(src)//Eject casing + playsound(src, casingsound, 100, 1) + chambered = null + + if(loaded.len) + var/obj/item/ammo_casing/AC = loaded[1] //load next casing. + loaded -= AC //Remove casing from loaded list. + chambered = AC + + if(!chambered && !loaded.len) + pumpsound = backsound + + update_icon() + + if(!silent) + playsound(src, pumpsound, 45, 1) + + if(M) + M.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + +/obj/item/weapon/gun/projectile/shotgun/pump/combat + name = "combat shotgun" + desc = "Built for close quarters combat, the Hephaestus Industries KS-40 is widely regarded as a weapon of choice for repelling boarders." + icon_state = "cshotgun" + item_state = "cshotgun" + origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 2) + max_shells = 7 //match the ammo box capacity, also it can hold a round in the chamber anyways, for a total of 8. + ammo_type = /obj/item/ammo_casing/shotgun + one_hand_penalty = 50 //a little heavier than the regular shotgun + wielded_item_state = "shotgun-wielded" + +/obj/item/weapon/gun/projectile/shotgun/pump/border + name = "border shotgun" + icon_state = "border" + item_state = "cshotgun" + origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 2) + max_shells = 7 + ammo_type = /obj/item/ammo_casing/shotgun + wielded_item_state = "cshotgun2" + +/obj/item/weapon/gun/projectile/shotgun/doublebarrel + name = "\improper MS Doom" + desc = "Two shots. That's all you'll ever need." + icon_state = "dshotgun" + item_state = "dshotgun" + load_method = SINGLE_CASING|SINGLE_LOAD + handle_casings = CYCLE_CASINGS + max_shells = 2 + w_class = ITEM_SIZE_HUGE + force = 10 + obj_flags = OBJ_FLAG_CONDUCTIBLE + caliber = "shotgun" + origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 1) + ammo_type = /obj/item/ammo_casing/shotgun/pellet + casingsound = 'sound/weapons/guns/misc/shotgun_fall.ogg' + wielded_item_state = "dshotgun1" + gun_type = GUN_PISTOL //Now anyone can use it. + var/broke_open = FALSE + + burst_delay = 0 + /* + firemodes = list( + list(mode_name="fire one barrel at a time", burst=1), + list(mode_name="fire both barrels at once", burst=2), + ) + */ + +/obj/item/weapon/gun/projectile/shotgun/doublebarrel/update_icon() + ..() + //if(!loaded.len) + if(broke_open) + icon_state = "dshotgun-e" + else + icon_state = "dshotgun" + +/obj/item/weapon/gun/projectile/shotgun/doublebarrel/attack_self(mob/user) + . = ..() + broke_open = !broke_open + playsound(src, 'sound/weapons/guns/interact/shotgun_break.ogg', 50) + if(broke_open) + if(loaded.len) + unload_ammo(user) + update_icon() + +/obj/item/weapon/gun/projectile/shotgun/doublebarrel/special_check(mob/user) + if(broke_open) + to_chat(user, "Close the shotgun first.") + return FALSE + return ..() + + + +/obj/item/weapon/gun/projectile/shotgun/doublebarrel/pellet + ammo_type = /obj/item/ammo_casing/shotgun/pellet + +/obj/item/weapon/gun/projectile/shotgun/doublebarrel/flare + name = "signal shotgun" + desc = "A double-barreled shotgun meant to fire signal flash shells." + ammo_type = /obj/item/ammo_casing/shotgun/flash + +/obj/item/weapon/gun/projectile/shotgun/doublebarrel/unload_ammo(user, allow_dump) + ..(user, allow_dump=1) + +//this is largely hacky and bad :( -Pete +/obj/item/weapon/gun/projectile/shotgun/doublebarrel/attackby(var/obj/item/A as obj, mob/user as mob) + if(w_class > 3 && (istype(A, /obj/item/weapon/circular_saw) || istype(A, /obj/item/weapon/melee/energy) || istype(A, /obj/item/weapon/gun/energy/plasmacutter))) + to_chat(user, "You begin to shorten the barrel of \the [src].") + if(loaded.len) + for(var/i in 1 to max_shells) + Fire(user, user) //will this work? //it will. we call it twice, for twice the FUN + user.visible_message("The shotgun goes off!", "The shotgun goes off in your face!") + return + if(do_after(user, 30, src)) //SHIT IS STEALTHY EYYYYY + icon_state = "sawnshotgun" + item_state = "sawnshotgun" + w_class = ITEM_SIZE_NORMAL + force = 5 + one_hand_penalty = 0 + slot_flags &= ~SLOT_BACK //you can't sling it on your back + slot_flags &= ~SLOT_S_STORE //you can't sling it on your back + slot_flags |= (SLOT_BELT|SLOT_HOLSTER) //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally) - or in a holster, why not. + SetName("sawn-off shotgun") + desc = "Omar's coming!" + to_chat(user, "You shorten the barrel of \the [src]!") + else + if(!broke_open) + return + ..() + update_icon() + +/obj/item/weapon/gun/projectile/shotgun/doublebarrel/sawn + name = "sawn-off shotgun" + desc = "Omar's coming!" + icon_state = "sawnshotgun" + item_state = "sawnshotgun" + slot_flags = SLOT_BELT|SLOT_HOLSTER + ammo_type = /obj/item/ammo_casing/shotgun/pellet + w_class = ITEM_SIZE_NORMAL + force = 5 + one_hand_penalty = 0 + + +/obj/item/weapon/gun/projectile/shotgun/pump/boltaction + name = "\improper Mark II Stormrider" //I used a random rifle generator to come up with that. + desc = "This piece of junk looks like something that could have been used 700 years ago" + icon_state = "mosin" + item_state = "mosin" + caliber = "a762" + bulletinsert_sound = 'sound/weapons/guns/interact/rifle_load.ogg' + casingsound = 'sound/weapons/guns/misc/casingfall1.ogg' + pumpsound = 'sound/weapons/boltpump.ogg' + backsound = 'sound/weapons/guns/interact/rifle_boltback.ogg' + forwardsound = 'sound/weapons/guns/interact/rifle_boltforward.ogg' + ammo_type = /obj/item/ammo_casing/a762 + wielded_item_state = "rifle-wielded" + block_chance = 45 + gun_type = GUN_PISTOL \ No newline at end of file diff --git a/code/modules/projectiles/guns/projectile/sniper.dm b/code/modules/projectiles/guns/projectile/sniper.dm new file mode 100644 index 00000000..6bdbde9c --- /dev/null +++ b/code/modules/projectiles/guns/projectile/sniper.dm @@ -0,0 +1,90 @@ +/obj/item/weapon/gun/projectile/heavysniper + name = "PTSD 41" + desc = "A portable anti-armour rifle fitted with a scope. Completely useless at close range, marginally less useless at high ranges." + icon_state = "heavysniper" + item_state = "heavysniper" + w_class = ITEM_SIZE_HUGE + force = 10 + slot_flags = SLOT_BACK|SLOT_S_STORE + origin_tech = list(TECH_COMBAT = 8, TECH_MATERIAL = 2, TECH_ILLEGAL = 8) + caliber = "14.5mm" + screen_shake = 2 //extra kickback + handle_casings = HOLD_CASINGS + load_method = SINGLE_CASING|SINGLE_LOAD + max_shells = 1 + ammo_type = /obj/item/ammo_casing/a145 + one_hand_penalty = 50 + accuracy = -2 + scoped_accuracy = 5 //increased accuracy over the LWAP because only one shot + var/bolt_open = 0 + wielded_item_state = "heavysniper-wielded" + bulletinsert_sound = 'sound/weapons/guns/interact/sniper_load.ogg' + fire_sound = 'sound/weapons/guns/fire/sniper_fire.ogg' + gun_type = GUN_SNIPER + far_fire_sound = "sniper_fire" + +/obj/item/weapon/gun/projectile/heavysniper/update_icon() + ..() + if(bolt_open) + icon_state = "heavysniper-open" + else + icon_state = "heavysniper" + +/obj/item/weapon/gun/projectile/heavysniper/examine(mob/user, distance) + . = ..() + if(bolt_open)//These guns do not chamber until their fired. + if(loaded.len)//However, fired rounds will eject automatically when the bolt is open, so there's a good chance the round is live. + to_chat(user, "There is a ROUND in the chamber.")//But someone could still place a fired round into this gun, so best to just be generic. + else + to_chat(user, "The chamber is EMPTY.") + +/obj/item/weapon/gun/projectile/heavysniper/attack_self(mob/user as mob) + bolt_open = !bolt_open + if(bolt_open) + playsound(src, 'sound/weapons/guns/interact/bolt_open.ogg', 50) + if(chambered) + to_chat(user, "You work the bolt open, ejecting [chambered]!") + playsound(src, casingsound, 100) + chambered.loc = get_turf(src) + loaded -= chambered + chambered = null + else + to_chat(user, "You work the bolt open.") + else + to_chat(user, "You work the bolt closed.") + bolt_open = 0 + playsound(src, 'sound/weapons/guns/interact/bolt_close.ogg', 50) + add_fingerprint(user) + update_icon() + +/obj/item/weapon/gun/projectile/heavysniper/special_check(mob/user) + if(bolt_open) + to_chat(user, "You can't fire [src] while the bolt is open!") + return 0 + if(!user.zoomed) + to_chat(user, "You can't get a clear shot to fire without looking down the scope!") + return 0 + return ..() + +/obj/item/weapon/gun/projectile/heavysniper/load_ammo(var/obj/item/A, mob/user) + if(!bolt_open) + return + ..() + +/obj/item/weapon/gun/projectile/heavysniper/unload_ammo(mob/user, var/allow_dump=1) + if(!bolt_open) + return + ..() + +/obj/item/weapon/gun/projectile/heavysniper/verb/scope() + set category = "Object" + set name = "Use Scope" + set popup_menu = 1 + + toggle_scope(usr, 2) + + +/obj/item/weapon/gun/projectile/heavysniper/equipped(mob/user) + ..() + if(user.zoomed) + user.do_zoom() diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm new file mode 100644 index 00000000..5e53edd1 --- /dev/null +++ b/code/modules/projectiles/projectile.dm @@ -0,0 +1,532 @@ +//Amount of time in deciseconds to wait before deleting all drawn segments of a projectile. +#define SEGMENT_DELETION_DELAY 5 +//� ����� ���� ����� � ��� ���� ������ �� ���� �� ������ � ������ ���� ��� ����� ����� ����� �������� ������� � �������� �� ��������� � �� ���� ����� ��������� �������� ���� +/obj/item/projectile + name = "projectile" + icon = 'icons/obj/projectiles.dmi' + icon_state = "bullet" + density = 1 + unacidable = 1 + anchored = 1 //There's a reason this is here, Mport. God fucking damn it -Agouri. Find&Fix by Pete. The reason this is here is to stop the curving of emitter shots. + pass_flags = PASS_FLAG_TABLE + mouse_opacity = 0 + plane = BULLET_PLANE + var/list/mob_hit_sound = list('sound/effects/gore/bullethit2.ogg', 'sound/effects/gore/bullethit3.ogg') //Sound it makes when it hits a mob. It's a list so you can put multiple hit sounds there. + var/wall_hitsound = "hitwall" + var/bumped = 0 //Prevents it from hitting more than one guy at once + var/def_zone = "" //Aiming at + var/mob/firer = null//Who shot it + var/silenced = 0 //Attack message + var/yo = null + var/xo = null + var/current = null + var/shot_from = "" // name of the object which shot us + var/atom/original = null // the target clicked (not necessarily where the projectile is headed). Should probably be renamed to 'target' or something. + var/turf/starting = null // the projectile's starting turf + var/list/permutated = list() // we've passed through these atoms, don't try to hit them again + var/list/segments = list() //For hitscan projectiles with tracers. + var/list/armor_hit_sound = list('sound/effects/gore/armorhit1.ogg', 'sound/effects/gore/armorhit2.ogg','sound/effects/gore/armorhit3.ogg','sound/effects/gore/armorhit4.ogg') + var/list/helmet_hit_sound = list('sound/effects/gore/helmhit1.ogg', 'sound/effects/gore/helmhit2.ogg','sound/effects/gore/helmhit3.ogg','sound/effects/gore/helmhit4.ogg','sound/effects/gore/helmhit5.ogg') + var/p_x = 16 + var/p_y = 16 // the pixel location of the tile that the player clicked. Default is the center + + var/accuracy = 0 + var/dispersion = 0.0 + var/OPEN_SPACE_FALL = 0 + + var/damage = 10 + var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE, PAIN are the only things that should be in here + var/nodamage = FALSE //Determines if the projectile will skip any damage inflictions + var/check_armour = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb //Cael - bio and rad are also valid + var/projectile_type = /obj/item/projectile + var/penetrating = 0 //If greater than zero, the projectile will pass through dense objects as specified by on_penetrate() + var/range = 50 //This will de-increment every process(). When 0, it will delete the projectile. + //Effects + var/stun = 0 + var/weaken = 0 + var/paralyze = 0 + var/irradiate = 0 + var/stutter = 0 + var/eyeblur = 0 + var/drowsy = 0 + var/agony = 0 + var/embed = 0 // whether or not the projectile can embed itself in the mob + var/penetration_modifier = 0.2 //How much internal damage this projectile can deal, as a multiplier. + + var/hitscan = 0 // whether the projectile should be hitscan + var/step_delay = 0.1 //1 // the delay between iterations if not a hitscan projectile + + // effect types to be used + var/muzzle_type + var/tracer_type + var/impact_type + + var/fire_sound = 'sound/weapons/gunshot/gunshot.ogg'//Default gun sound. + + var/vacuum_traversal = 1 //Determines if the projectile can exist in vacuum, if false, the projectile will be deleted if it enters vacuum. + + var/datum/plot_vector/trajectory // used to plot the path of the projectile + var/datum/vector_loc/location // current location of the projectile in pixel space + var/matrix/effect_transform // matrix to rotate and scale projectile effects - putting it here so it doesn't + // have to be recreated multiple times + +/obj/item/projectile/Initialize() + damtype = damage_type //TODO unify these vars properly + if(!hitscan) + animate_movement = SLIDE_STEPS + else animate_movement = NO_STEPS + . = ..() + +/obj/item/projectile/Destroy() + return ..() + +/obj/item/projectile/forceMove() + ..() + if(istype(loc, /turf/space/) && istype(loc.loc, /area/space)) + qdel(src) + +//TODO: make it so this is called more reliably, instead of sometimes by bullet_act() and sometimes not +/obj/item/projectile/proc/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null) + var/turf/target_loca = get_turf(target) + if(blocked >= 100) return 0//Full block + if(!isliving(target)) return 0 + if(isanimal(target)) return 0 + + var/mob/living/L = target + if(damage && damage_type == BRUTE)//&& L.blood_volume + var/splatter_dir = dir + if(starting) + splatter_dir = get_dir(starting, target_loca) + target_loca = get_step(target_loca, splatter_dir) + if(isalien(L)) + new /obj/effect/overlay/temp/dir_setting/bloodsplatter/xenosplatter(target_loca, splatter_dir) + else + var/blood_color = "#C80000" + if(ishuman(target)) + var/mob/living/carbon/human/H = target + blood_color = H.species.blood_color + new /obj/effect/overlay/temp/dir_setting/bloodsplatter(target_loca, splatter_dir, blood_color) + if(prob(50)) + target_loca.add_blood(L) + + + L.apply_effects(0, weaken, paralyze, 0, stutter, eyeblur, drowsy, 0, blocked) + L.stun_effect_act(stun, agony, def_zone, src) + //radiation protection is handled separately from other armour types. + L.apply_effect(irradiate, IRRADIATE, L.getarmor(null, "rad")) + + + return 1 + +//called when the projectile stops flying because it collided with something +/obj/item/projectile/proc/on_impact(var/atom/A) + impact_effect(effect_transform) // generate impact effect + if(damage && damage_type == BURN) + var/turf/T = get_turf(A) + if(T) + T.hotspot_expose(700, 5) + +//Checks if the projectile is eligible for embedding. Not that it necessarily will. +/obj/item/projectile/proc/can_embed() + //embed must be enabled and damage type must be brute + if(!embed || damage_type != BRUTE) + return 0 + return 1 + +/obj/item/projectile/proc/get_structure_damage() + if(damage_type == BRUTE || damage_type == BURN) + return damage + return 0 + +//return 1 if the projectile should be allowed to pass through after all, 0 if not. +/obj/item/projectile/proc/check_penetrate(var/atom/A) + return 1 + +/obj/item/projectile/proc/check_fire(atom/target as mob, var/mob/living/user as mob) //Checks if you can hit them or not. + check_trajectory(target, user, pass_flags, item_flags, obj_flags) + +//sets the click point of the projectile using mouse input params +/obj/item/projectile/proc/set_clickpoint(var/params) + var/list/mouse_control = params2list(params) + if(mouse_control["icon-x"]) + p_x = text2num(mouse_control["icon-x"]) + if(mouse_control["icon-y"]) + p_y = text2num(mouse_control["icon-y"]) + + //randomize clickpoint a bit based on dispersion + if(dispersion) + var/radius = round((dispersion*0.443)*world.icon_size*0.8) //0.443 = sqrt(pi)/4 = 2a, where a is the side length of a square that shares the same area as a circle with diameter = dispersion + p_x = between(0, p_x + rand(-radius, radius), world.icon_size) + p_y = between(0, p_y + rand(-radius, radius), world.icon_size) + +//called to launch a projectile +/obj/item/projectile/proc/launch(atom/target, var/target_zone, var/x_offset=0, var/y_offset=0, var/angle_offset=0) + var/turf/curloc = get_turf(src) + var/turf/targloc = get_turf(target) + if (!istype(targloc) || !istype(curloc)) + return 1 + + if(targloc == curloc) //Shooting something in the same turf + target.bullet_act(src, target_zone) + on_impact(target) + qdel(src) + return 0 + /*//Uncomment this if you want people to be able to shoot up again. + if(targloc.z > curloc.z) + var/turf/above = GetAbove(curloc) + if(above.CanZPass(curloc, UP)) + curloc = above + */ + if(istype(target, /turf/simulated/open)) + OPEN_SPACE_FALL = 1 + original = target + def_zone = target_zone + + spawn() + setup_trajectory(curloc, targloc, x_offset, y_offset, angle_offset) //plot the initial trajectory + Process() + spawn(SEGMENT_DELETION_DELAY) + QDEL_NULL_LIST(segments) + + return 0 + +//called to launch a projectile from a gun +/obj/item/projectile/proc/launch_from_gun(atom/target, mob/user, obj/item/weapon/gun/launcher, var/target_zone, var/x_offset=0, var/y_offset=0) + if(user == target) //Shooting yourself + user.bullet_act(src, target_zone) + qdel(src) + return 0 + + loc = get_turf(user) //move the projectile out into the world + + firer = user + shot_from = launcher.name + silenced = launcher.silenced + + return launch(target, target_zone, x_offset, y_offset) + +//Used to change the direction of the projectile in flight. +/obj/item/projectile/proc/redirect(var/new_x, var/new_y, var/atom/starting_loc, var/mob/new_firer=null) + var/turf/new_target = locate(new_x, new_y, src.z) + + original = new_target + if(new_firer) + firer = src + + setup_trajectory(starting_loc, new_target) + +//Called when the projectile intercepts a mob. Returns 1 if the projectile hit the mob, 0 if it missed and should keep flying. +/obj/item/projectile/proc/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier=0) + if(!istype(target_mob)) + return + + //roll to-hit + //miss_modifier = max(15*(distance-2) - round(15*accuracy) + miss_modifier, 0) + miss_modifier = 15*(distance-2) - round(15*accuracy) + miss_modifier + if(target_mob == src.original) + miss_modifier -= 60 + var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, miss_modifier, ranged_attack=(distance > 1 || original != target_mob)) //if the projectile hits a target we weren't originally aiming at then retain the chance to miss + + var/result = PROJECTILE_FORCE_MISS + if(hit_zone) + def_zone = hit_zone //set def_zone, so if the projectile ends up hitting someone else later (to be implemented), it is more likely to hit the same part + if(!target_mob.aura_check(AURA_TYPE_BULLET, src,def_zone)) + return 1 + result = target_mob.bullet_act(src, def_zone) + + if(result == PROJECTILE_FORCE_MISS) + if(!silenced) + var/missound = "sound/weapons/guns/misc/miss[rand(1,4)].ogg" + target_mob.visible_message("\The [src] misses [target_mob] narrowly!") + playsound(target_mob, missound, 60, 1) + return 0 + + if(ishuman(target_mob)) + var/mob/living/carbon/human/L = target_mob + if(istype(L.wear_suit, /obj/item/clothing/suit/armor) && parse_zone(def_zone) == BP_CHEST) + playsound(L,pick(armor_hit_sound), 100, 1) + if(istype(L.head, /obj/item/clothing/head/helmet) && parse_zone(def_zone) == BP_HEAD) + playsound(L, pick(helmet_hit_sound), 80, 1) + if(silenced) + to_chat(target_mob, "You've been hit in the [parse_zone(def_zone)] by \the [src]!") + //playsound(target_mob, pick(mob_hit_sound), 40, 1) + else + target_mob.visible_message("\The [target_mob] is hit by \the [src] in the [parse_zone(def_zone)]!")//X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter + playsound(target_mob, pick(mob_hit_sound), 40, 1) + //admin logs + if(!no_attack_log) + if(istype(firer, /mob)) + + var/attacker_message = "shot with \a [src.type]" + var/victim_message = "shot with \a [src.type]" + var/admin_message = "shot (\a [src.type])" + + admin_attack_log(firer, target_mob, attacker_message, victim_message, admin_message) + else + admin_victim_log(target_mob, "was shot by an UNKNOWN SUBJECT (No longer exists) using \a [src]") + + if(ishuman(firer) && ishuman(target_mob)) + var/mob/living/carbon/human/attacker = firer + var/mob/living/carbon/human/victim = target_mob + if(attacker == victim) + return + if(attacker.warfare_faction == victim.warfare_faction) + to_chat(attacker, "[victim] is on my side!") + log_and_message_admins("[attacker] has shot his teammate [victim] with \a [src.type]!", attacker) + GLOB.ff_incidents++//Dumb round end stat stuff. + + //sometimes bullet_act() will want the projectile to continue flying + if (result == PROJECTILE_CONTINUE) + return 0 + + return 1 + +/obj/item/projectile/Bump(atom/A as mob|obj|turf|area, forced=0) + if(A == src) + return 0 //no + + if(A == firer) + loc = A.loc + return 0 //cannot shoot yourself + + if((bumped && !forced) || (A in permutated)) + return 0 + + var/passthrough = 0 //if the projectile should continue flying + var/distance = get_dist(starting,loc) + + bumped = 1 + if(ismob(A)) + var/mob/M = A + if(istype(A, /mob/living)) + //if they have a neck grab on someone, that person gets hit instead + var/obj/item/grab/G = locate() in M + if(G && G.shield_assailant()) + visible_message("\The [M] uses [G.affecting] as a shield!") + if(Bump(G.affecting, forced=1)) + return //If Bump() returns 0 (keep going) then we continue on to attack M. + + passthrough = !attack_mob(M, distance) + else + passthrough = 1 //so ghosts don't stop bullets + else + playsound(loc, wall_hitsound, 50) + passthrough = (A.bullet_act(src, def_zone) == PROJECTILE_CONTINUE) //backwards compatibility + if(isturf(A)) + for(var/obj/O in A) + O.bullet_act(src) + for(var/mob/living/M in A) + attack_mob(M, distance) + + //penetrating projectiles can pass through things that otherwise would not let them + if(!passthrough && penetrating > 0) + if(check_penetrate(A)) + passthrough = 1 + penetrating-- + + //the bullet passes through a dense object! + if(passthrough) + //move ourselves onto A so we can continue on our way. + if(A) + if(istype(A, /turf)) + loc = A + else + loc = A.loc + permutated.Add(A) + bumped = 0 //reset bumped variable! + return 0 + + //stop flying + on_impact(A) + + set_density(0) + set_invisibility(101) + + qdel(src) + return 1 + +/obj/item/projectile/ex_act() + return //explosions probably shouldn't delete projectiles + +/obj/item/projectile/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + return 1 + +/obj/item/projectile/Process() + var/first_step = 1 + + spawn while(src && src.loc) + if(range-- < 1) + on_impact(src.loc) //for any final impact behaviours + qdel(src) + return + if((!( current ) || loc == current)) + current = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z) + if((x == 1 || x == world.maxx || y == 1 || y == world.maxy)) + qdel(src) + return + + trajectory.increment() // increment the current location + location = trajectory.return_location(location) // update the locally stored location data + + if(!location) + qdel(src) // if it's left the world... kill it + return + + if (is_below_sound_pressure(get_turf(src)) && !vacuum_traversal) //Deletes projectiles that aren't supposed to bein vacuum if they leave pressurised areas + qdel(src) + return + + before_move() + Move(location.return_turf()) + + + if(!bumped && !isturf(original)) + if(loc == get_turf(original)) + if(!(original in permutated)) + if(Bump(original)) + return + + if(first_step) + muzzle_effect(effect_transform) + first_step = 0 + else if(!bumped) + tracer_effect(effect_transform) + if(!hitscan) + sleep(step_delay) //add delay between movement iterations if it's not a hitscan weapon + +/obj/item/projectile/proc/before_move() + return 0 + +/obj/item/projectile/proc/setup_trajectory(turf/startloc, turf/targloc, var/x_offset = 0, var/y_offset = 0) + // setup projectile state + starting = startloc + current = startloc + yo = targloc.y - startloc.y + y_offset + xo = targloc.x - startloc.x + x_offset + + // trajectory dispersion + var/offset = 0 + if(dispersion) + var/radius = round(dispersion*9, 1) + offset = rand(-radius, radius) + + // plot the initial trajectory + trajectory = new() + trajectory.setup(starting, original, pixel_x, pixel_y, angle_offset=offset) + + // generate this now since all visual effects the projectile makes can use it + effect_transform = new() + effect_transform.Scale(trajectory.return_hypotenuse(), 1) + effect_transform.Turn(-trajectory.return_angle()) //no idea why this has to be inverted, but it works + + transform = turn(transform, -(trajectory.return_angle() + 90)) //no idea why 90 needs to be added, but it works + +/obj/item/projectile/proc/muzzle_effect(var/matrix/T) + if(silenced) + return + + if(ispath(muzzle_type)) + var/obj/effect/projectile/M = new muzzle_type(get_turf(src)) + + if(istype(M)) + M.set_transform(T) + M.pixel_x = location.pixel_x + M.pixel_y = location.pixel_y + if(!hitscan) //Bullets don't hit their target instantly, so we can't link the deletion of the muzzle flash to the bullet's Destroy() + spawn(1) + qdel(M) + else + segments += M + +/obj/item/projectile/proc/tracer_effect(var/matrix/M) + if(ispath(tracer_type)) + var/obj/effect/projectile/P = new tracer_type(location.loc) + + if(istype(P)) + P.set_transform(M) + P.pixel_x = location.pixel_x + P.pixel_y = location.pixel_y + if(!hitscan) + spawn(step_delay) //if not a hitscan projectile, remove after a single delay. Do not spawn hitscan projectiles. EVER. + qdel(P) + else + segments += P + +/obj/item/projectile/proc/impact_effect(var/matrix/M) + if(ispath(impact_type)) + var/obj/effect/projectile/P = new impact_type(location.loc) + + if(istype(P)) + P.set_transform(M) + P.pixel_x = location.pixel_x + P.pixel_y = location.pixel_y + segments += P + +//"Tracing" projectile +/obj/item/projectile/test //Used to see if you can hit them. + invisibility = 101 //Nope! Can't see me! + yo = null + xo = null + var/result = 0 //To pass the message back to the gun. + +/obj/item/projectile/test/Bump(atom/A as mob|obj|turf|area) + if(A == firer) + loc = A.loc + return //cannot shoot yourself + if(istype(A, /obj/item/projectile)) + return + if(istype(A, /mob/living) || istype(A, /obj/mecha) || istype(A, /obj/vehicle)) + result = 2 //We hit someone, return 1! + return + result = 1 + return + +/obj/item/projectile/test/launch(atom/target) + var/turf/curloc = get_turf(src) + var/turf/targloc = get_turf(target) + if(!curloc || !targloc) + return 0 + + original = target + + //plot the initial trajectory + setup_trajectory(curloc, targloc) + return Process(targloc) + +/obj/item/projectile/test/Process(var/turf/targloc) + while(src) //Loop on through! + if(result) + return (result - 1) + if((!( targloc ) || loc == targloc)) + targloc = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z) //Finding the target turf at map edge + + trajectory.increment() // increment the current location + location = trajectory.return_location(location) // update the locally stored location data + + Move(location.return_turf()) + + var/mob/living/M = locate() in get_turf(src) + if(istype(M)) //If there is someting living... + return 1 //Return 1 + else + M = locate() in get_step(src,targloc) + if(istype(M)) + return 1 + +//Helper proc to check if you can hit them or not. +/proc/check_trajectory(atom/target as mob|obj, atom/firer as mob|obj, var/pass_flags=PASS_FLAG_TABLE|PASS_FLAG_GLASS|PASS_FLAG_GRILLE, item_flags = null, obj_flags = null) + if(!istype(target) || !istype(firer)) + return 0 + + var/obj/item/projectile/test/trace = new /obj/item/projectile/test(get_turf(firer)) //Making the test.... + + //Set the flags and pass flags to that of the real projectile... + if(!isnull(item_flags)) + trace.item_flags = item_flags + if(!isnull(obj_flags)) + trace.obj_flags = obj_flags + trace.pass_flags = pass_flags + + var/output = trace.launch(target) //Test it! + qdel(trace) //No need for it anymore + return output //Send it back to the gun! diff --git a/code/modules/projectiles/projectile/animate.dm b/code/modules/projectiles/projectile/animate.dm new file mode 100644 index 00000000..22d59a8a --- /dev/null +++ b/code/modules/projectiles/projectile/animate.dm @@ -0,0 +1,13 @@ +/obj/item/projectile/animate + name = "bolt of animation" + icon_state = "ice_1" + damage = 0 + damage_type = BURN + nodamage = 1 + check_armour = "energy" + +/obj/item/projectile/animate/Bump(var/atom/change) + if((istype(change, /obj/item) || istype(change, /obj/structure)) && !is_type_in_list(change, protected_objects)) + var/obj/O = change + new /mob/living/simple_animal/hostile/mimic/(O.loc, O, firer) + ..() diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm new file mode 100644 index 00000000..06a123e2 --- /dev/null +++ b/code/modules/projectiles/projectile/beams.dm @@ -0,0 +1,163 @@ +/obj/item/projectile/beam + name = "laser" + icon_state = "laser" + fire_sound='sound/weapons/Laser.ogg' + mob_hit_sound = list('sound/effects/gore/sear.ogg') + wall_hitsound = 'sound/weapons/guns/misc/laser_searwall.ogg' + pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GLASS | PASS_FLAG_GRILLE + damage = 40 + damage_type = BURN + sharp = 1 //concentrated burns + check_armour = "laser" + eyeblur = 4 + hitscan = 1 + invisibility = 101 //beam projectiles are invisible as they are rendered by the effect engine + + muzzle_type = /obj/effect/projectile/laser/muzzle + tracer_type = /obj/effect/projectile/laser/tracer + impact_type = /obj/effect/projectile/laser/impact + +/obj/item/projectile/beam/practice + name = "laser" + icon_state = "laser" + fire_sound = 'sound/weapons/Taser.ogg' + pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GLASS | PASS_FLAG_GRILLE + damage = 2 + damage_type = BURN + check_armour = "laser" + eyeblur = 2 + +/obj/item/projectile/beam/smalllaser + damage = 25 + +/obj/item/projectile/beam/midlaser + damage = 50 + armor_penetration = 10 + +/obj/item/projectile/beam/heavylaser + name = "heavy laser" + icon_state = "heavylaser" + fire_sound = 'sound/weapons/lasercannonfire.ogg' + damage = 60 + armor_penetration = 30 + + muzzle_type = /obj/effect/projectile/laser/heavy/muzzle + tracer_type = /obj/effect/projectile/laser/heavy/tracer + impact_type = /obj/effect/projectile/laser/heavy/impact +/obj/item/projectile/beam/pulse/bogani + name = "pulsar" + icon_state = "bogb" + fire_sound='sound/weapons/blaster.ogg' + damage = 30 + + //muzzle_type = /obj/effect/projectile/laser/bogani/muzzle + tracer_type = /obj/effect/projectile/laser/bogani/tracer + impact_type = /obj/effect/projectile/laser/bogani/impact + +/obj/item/projectile/beam/emitter + name = "emitter beam" + icon_state = "emitter" + fire_sound = 'sound/weapons/emitter.ogg' + damage = 0 // The actual damage is computed in /code/modules/power/singularity/emitter.dm + + muzzle_type = /obj/effect/projectile/laser/emitter/muzzle + tracer_type = /obj/effect/projectile/laser/emitter/tracer + impact_type = /obj/effect/projectile/laser/emitter/impact + +/obj/item/projectile/beam/lastertag/blue + name = "lasertag beam" + icon_state = "bluelaser" + pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GLASS | PASS_FLAG_GRILLE + damage = 0 + no_attack_log = 1 + damage_type = BURN + check_armour = "laser" + + muzzle_type = /obj/effect/projectile/laser/blue/muzzle + tracer_type = /obj/effect/projectile/laser/blue/tracer + impact_type = /obj/effect/projectile/laser/blue/impact + +/obj/item/projectile/beam/lastertag/blue/on_hit(var/atom/target, var/blocked = 0) + if(istype(target, /mob/living/carbon/human)) + var/mob/living/carbon/human/M = target + if(istype(M.wear_suit, /obj/item/clothing/suit/redtag)) + M.Weaken(5) + return 1 + +/obj/item/projectile/beam/lastertag/red + name = "lasertag beam" + icon_state = "laser" + pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GLASS | PASS_FLAG_GRILLE + damage = 0 + no_attack_log = 1 + damage_type = BURN + check_armour = "laser" + +/obj/item/projectile/beam/lastertag/red/on_hit(var/atom/target, var/blocked = 0) + if(istype(target, /mob/living/carbon/human)) + var/mob/living/carbon/human/M = target + if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag)) + M.Weaken(5) + return 1 + +/obj/item/projectile/beam/lastertag/omni//A laser tag bolt that stuns EVERYONE + name = "lasertag beam" + icon_state = "omnilaser" + pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GLASS | PASS_FLAG_GRILLE + damage = 0 + damage_type = BURN + check_armour = "laser" + + muzzle_type = /obj/effect/projectile/laser/omni/muzzle + tracer_type = /obj/effect/projectile/laser/omni/tracer + impact_type = /obj/effect/projectile/laser/omni/impact + +/obj/item/projectile/beam/lastertag/omni/on_hit(var/atom/target, var/blocked = 0) + if(istype(target, /mob/living/carbon/human)) + var/mob/living/carbon/human/M = target + if((istype(M.wear_suit, /obj/item/clothing/suit/bluetag))||(istype(M.wear_suit, /obj/item/clothing/suit/redtag))) + M.Weaken(5) + return 1 + +/obj/item/projectile/beam/sniper + name = "sniper beam" + icon_state = "xray" + fire_sound = 'sound/weapons/marauder.ogg' + damage = 50 + armor_penetration = 10 + stun = 3 + weaken = 3 + stutter = 3 + + muzzle_type = /obj/effect/projectile/laser/xray/muzzle + tracer_type = /obj/effect/projectile/laser/xray/tracer + impact_type = /obj/effect/projectile/laser/xray/impact + +/obj/item/projectile/beam/stun + name = "stun beam" + icon_state = "stun" + fire_sound = 'sound/weapons/Taser.ogg' + check_armour = "energy" + sharp = 0 //not a laser + agony = 40 + damage_type = STUN + + muzzle_type = /obj/effect/projectile/stun/muzzle + tracer_type = /obj/effect/projectile/stun/tracer + impact_type = /obj/effect/projectile/stun/impact + +/obj/item/projectile/beam/stun/heavy + name = "heavy stun beam" + agony = 60 + +/obj/item/projectile/beam/stun/shock + name = "shock beam" + damage_type = ELECTROCUTE + damage = 10 + agony = 5 + fire_sound='sound/weapons/pulse.ogg' + +/obj/item/projectile/beam/stun/shock/heavy + name = "heavy shock beam" + damage = 20 + agony = 10 diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm new file mode 100644 index 00000000..9314f626 --- /dev/null +++ b/code/modules/projectiles/projectile/bullets.dm @@ -0,0 +1,338 @@ +/obj/item/projectile/bullet + name = "bullet" + icon_state = "bullet" + fire_sound = 'sound/weapons/gunshot/gunshot_strong.ogg' + damage = 60 + damage_type = BRUTE + nodamage = 0 + check_armour = "bullet" + embed = 1 + sharp = 1 + light_power = 2 //Tracers. + light_range = 2 + light_color = "#E38F46" + penetration_modifier = 1.0 + var/mob_passthrough_check = 0 + muzzle_type = /obj/effect/projectile/bullet/muzzle + +/obj/item/projectile/bullet/on_hit(var/atom/target, var/blocked = 0) + if (..(target, blocked)) + var/mob/living/L = target + shake_camera(L, 3, 2) + +/obj/item/projectile/bullet/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier) + if(penetrating > 0 && damage > 100 && prob(damage)) + mob_passthrough_check = 1 + else + mob_passthrough_check = 0 + . = ..() + + if(. == 1 && iscarbon(target_mob)) + damage *= 0.7 //squishy mobs absorb KE + +/obj/item/projectile/bullet/can_embed() + //prevent embedding if the projectile is passing through the mob + if(mob_passthrough_check) + return 0 + return ..() + +/obj/item/projectile/bullet/before_move() + ..() + if(istype(starting, /turf/simulated/floor/trench)) //We started out shooting from the trench. + if(trench_counter > 1 || do_not_pass_trench) //We did not start out at the edge of the trench. + if(!istype(loc, /turf/simulated/floor/trench)) //We cannot shoot out. + playsound(src, wall_hitsound, 100, TRUE) + qdel(src) + + if(istype(loc, /turf/simulated/floor/trench)) //We have travelled to a new trench. + if(non_trench_counter > 3) //But we passed over open terrain for at least 3 tiles. + if(istype(loc, get_turf(original)))//We're at our destination. + playsound(src, wall_hitsound, 100, TRUE) + qdel(src) //We cannot shoot in. + + + if(!istype(starting, /turf/simulated/floor/trench))//We did not start out in the trench. + if(non_trench_counter > 0)//We have travelled over open terrain. + if(istype(original.loc, /turf/simulated/floor/trench))//If we clicked on the trench. + if(istype(loc, /turf/simulated/floor/trench))//We're now at the trench. + playsound(src, wall_hitsound, 100, TRUE) + qdel(src) //We cannot shoot in. + + +/obj/item/projectile/bullet/after_move() + ..() + if(istype(starting, /turf/simulated/floor/trench)) //Started from a trench. + if(istype(loc, /turf/simulated/floor/trench)) //Shooting into the same trench. + trench_counter++ //Add to the counter + else //Shooting over open terrain? + non_trench_counter++ //Add to the open terrain counter. + + if(!istype(starting, /turf/simulated/floor/trench)) //Didn't start out in the trench. + if(!istype(loc, /turf/simulated/floor/trench)) //Not shooting into the trench. + non_trench_counter++ //Add to the open terrain counter. + +/obj/item/projectile/bullet/check_penetrate(var/atom/A) + if(!A || !A.density) return 1 //if whatever it was got destroyed when we hit it, then I guess we can just keep going + + if(istype(A, /obj/mecha)) + return 1 //mecha have their own penetration handling + + if(ismob(A)) + if(!mob_passthrough_check) + return 0 + return 1 + + var/chance = damage + if(istype(A, /turf/simulated/wall)) + var/turf/simulated/wall/W = A + chance = round(damage/W.integrity*180) + else if(istype(A, /obj/structure/dirt_wall)) + chance = 5 + else if(istype(A, /obj/machinery/door)) + var/obj/machinery/door/D = A + chance = round(damage/D.maxhealth*180) + if(D.glass) chance *= 2 + else if(istype(A, /obj/structure/girder)) + chance = 100 + + + if(prob(chance)) + if(A.opacity) + //display a message so that people on the other side aren't so confused + A.visible_message("\The [src] pierces through \the [A]!") + return 1 + + return 0 + +//For projectiles that actually represent clouds of projectiles +/obj/item/projectile/bullet/pellet + name = "shrapnel" //'shrapnel' sounds more dangerous (i.e. cooler) than 'pellet' + damage = 60 + icon_state = "shot" //TODO: would be nice to have it's own icon state + range = 10 //These disappear after a short distance. + var/pellets = 4 //number of pellets + var/range_step = 2 //projectile will lose a fragment each time it travels this distance. Can be a non-integer. + var/base_spread = 90 //lower means the pellets spread more across body parts. If zero then this is considered a shrapnel explosion instead of a shrapnel cone + var/spread_step = 10 //higher means the pellets spread more across body parts with distance + light_power = 9 //No tracers. + light_range = 0 + light_color = null + +/* +/obj/item/projectile/bullet/pellet/Bumped() + . = ..() + bumped = 0 //can hit all mobs in a tile. pellets is decremented inside attack_mob so this should be fine. +*/ +/obj/item/projectile/bullet/pellet/proc/get_pellets(var/distance) + var/pellet_loss = round((distance - 1)/range_step) //pellets lost due to distance + return max(pellets - pellet_loss, 1) + +/obj/item/projectile/bullet/pellet/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier) + if (pellets < 0) return 1 + + var/total_pellets = get_pellets(distance) + var/spread = max(base_spread - (spread_step*distance), 0) + + //shrapnel explosions miss prone mobs with a chance that increases with distance + var/prone_chance = 0 + if(!base_spread) + prone_chance = max(spread_step*(distance - 2), 0) + + var/hits = 0 + for (var/i in 1 to total_pellets) + if(target_mob.lying && target_mob != original && prob(prone_chance)) + continue + + //pellet hits spread out across different zones, but 'aim at' the targeted zone with higher probability + //whether the pellet actually hits the def_zone or a different zone should still be determined by the parent using get_zone_with_miss_chance(). + var/old_zone = def_zone + def_zone = ran_zone(def_zone, spread) + if (..()) hits++ + def_zone = old_zone //restore the original zone the projectile was aimed at + + pellets -= hits //each hit reduces the number of pellets left + if (hits >= total_pellets || pellets <= 0) + return 1 + return 0 + +/obj/item/projectile/bullet/pellet/get_structure_damage() + var/distance = get_dist(loc, starting) + return ..() * get_pellets(distance) + +/obj/item/projectile/bullet/pellet/Move() + . = ..() + + //If this is a shrapnel explosion, allow mobs that are prone to get hit, too + if(. && !base_spread && isturf(loc)) + for(var/mob/living/M in loc) + if(M.lying || !M.CanPass(src, loc, 0.5, 0)) //Bump if lying or if we would normally Bump. + if(Bump(M)) //Bump will make sure we don't hit a mob multiple times + return + +/* short-casing projectiles, like the kind used in pistols or SMGs */ + +/obj/item/projectile/bullet/pistol + damage = 25 //9mm, .38, etc + fire_sound = "gunshot" + armor_penetration = 10 + +/obj/item/projectile/bullet/pistol/medium + damage = 35 //.45 + armor_penetration = 14.5 + fire_sound = "gunshot" + +/obj/item/projectile/bullet/pistol/medium/smg + fire_sound = 'sound/weapons/gunshot/gunshot_smg.ogg' + damage = 28 //10mm + armor_penetration = 18 + +/obj/item/projectile/bullet/pistol/medium/revolver + fire_sound = 'sound/weapons/gunshot/gunshot_strong.ogg' + damage = 35 //.44 magnum or something + +/obj/item/projectile/bullet/pistol/strong //matebas + fire_sound = 'sound/weapons/gunshot/gunshot_strong.ogg' + damage = 50 //.50AE + armor_penetration = 30 + +/obj/item/projectile/bullet/pistol/strong/revolver //revolvers + damage = 50 //Revolvers get snowflake bullets, to keep them relevant + armor_penetration = 20 + +/obj/item/projectile/bullet/pistol/rubber //"rubber" bullets + name = "rubber bullet" + check_armour = "bullet" + damage = 0 + agony = 30 + embed = 0 + sharp = 0 + armor_penetration = 1 + +/* shotgun projectiles */ + +/obj/item/projectile/bullet/shotgun + name = "slug" + fire_sound = 'sound/weapons/gunshot/shotgun.ogg' + damage = 55 + armor_penetration = 20 + +/obj/item/projectile/bullet/shotgun/beanbag //because beanbags are not bullets + name = "beanbag" + check_armour = "melee" + damage = 25 + agony = 60 + embed = 0 + sharp = 0 + +//Should do about 80 damage at 1 tile distance (adjacent), and 50 damage at 3 tiles distance. +//Overall less damage than slugs in exchange for more damage at very close range and more embedding +/obj/item/projectile/bullet/pellet/shotgun + name = "buckshot" + fire_sound = 'sound/weapons/gunshot/shotgun.ogg' + damage = 40 + pellets = 8 + range_step = 1 + spread_step = 10 + range = 7 + +/* "Rifle" rounds */ + +/obj/item/projectile/bullet/rifle + armor_penetration = 25 + +/obj/item/projectile/bullet/rifle/a556 + fire_sound = 'sound/weapons/gunshot/gunshot3.ogg' + damage = 40 + +/obj/item/projectile/bullet/rifle/a762 + fire_sound = 'sound/weapons/gunshot/gunshot2.ogg' + damage = 65 + armor_penetration = 30 + +/obj/item/projectile/bullet/rifle/a145 + fire_sound = 'sound/weapons/gunshot/sniper.ogg' + damage = 85 + stun = 3 + weaken = 3 + armor_penetration = 80 + //hitscan = 1 //so the PTR isn't useless as a sniper weapon + penetration_modifier = 1.25 + penetrating = 1 + +/obj/item/projectile/bullet/rifle/a145/apds + damage = 75 + armor_penetration = 95 + penetration_modifier = 1.5 + +/* Miscellaneous */ + +/obj/item/projectile/bullet/suffocationbullet//How does this even work? + name = "co bullet" + damage = 25 + damage_type = OXY + +/obj/item/projectile/bullet/cyanideround + name = "poison bullet" + damage = 45 + damage_type = TOX + +/obj/item/projectile/bullet/burstbullet + name = "exploding bullet" + damage = 25 + embed = 0 + edge = 1 + +/obj/item/projectile/bullet/gyro + fire_sound = 'sound/effects/explosion1.ogg' + +/obj/item/projectile/bullet/gyro/on_hit(var/atom/target, var/blocked = 0) + if(isturf(target)) + explosion(target, -1, 0, 2) + ..() + +/obj/item/projectile/bullet/blank + invisibility = 101 + damage = 1 + embed = 0 + +/* Practice */ + +/obj/item/projectile/bullet/pistol/practice + damage = 5 + +/obj/item/projectile/bullet/rifle/a762/practice + damage = 5 + +/obj/item/projectile/bullet/shotgun/practice + name = "practice" + damage = 5 + +/obj/item/projectile/bullet/pistol/cap + name = "cap" + invisibility = 101 + fire_sound = null + damage_type = PAIN + damage = 0 + nodamage = 1 + embed = 0 + sharp = 0 + +/obj/item/projectile/bullet/pistol/cap/Process() + loc = null + qdel(src) + +/obj/item/projectile/bullet/rock //spess dust + name = "micrometeor" + icon_state = "rock" + damage = 40 + armor_penetration = 25 + range = 255 + light_power = 9 //No tracers. + light_range = 0 + light_color = null + +/obj/item/projectile/bullet/rock/New() + icon_state = "rock[rand(1,3)]" + pixel_x = rand(-10,10) + pixel_y = rand(-10,10) + ..() \ No newline at end of file diff --git a/code/modules/projectiles/projectile/change.dm b/code/modules/projectiles/projectile/change.dm new file mode 100644 index 00000000..7515edc8 --- /dev/null +++ b/code/modules/projectiles/projectile/change.dm @@ -0,0 +1,102 @@ +/obj/item/projectile/change + name = "bolt of change" + icon_state = "ice_1" + damage = 0 + damage_type = BURN + nodamage = 1 + check_armour = "energy" + +/obj/item/projectile/change/on_hit(var/atom/change) + wabbajack(change) + +/obj/item/projectile/change/proc/wabbajack(var/mob/M) + if(istype(M, /mob/living) && M.stat != DEAD) + if(M.transforming) + return + if(M.has_brain_worms()) + return //Borer stuff - RR + + if(istype(M, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/Robot = M + if(Robot.mmi) + qdel(Robot.mmi) + else + for(var/obj/item/W in M) + if(istype(W, /obj/item/weapon/implant)) //TODO: Carn. give implants a dropped() or something + qdel(W) + continue + M.drop_from_inventory(W) + + var/mob/living/new_mob + + var/options = list("robot", "slime") + for(var/t in all_species) + options += t + options -= "Xenophage Queen" + options -= "Xenophage Drone" + options -= "Xenophage" + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.species) + options -= H.species.name + else if(isrobot(M)) + options -= "robot" + else if(isslime(M)) + options -= "slime" + + var/randomize = pick(options) + switch(randomize) + if("robot") + new_mob = new /mob/living/silicon/robot(M.loc) + new_mob.gender = M.gender + new_mob.set_invisibility(0) + new_mob.job = "Cyborg" + var/mob/living/silicon/robot/Robot = new_mob + Robot.mmi = new /obj/item/device/mmi(new_mob) + Robot.mmi.transfer_identity(M) //Does not transfer key/client. + if("slime") + new_mob = new /mob/living/carbon/slime(M.loc) + new_mob.universal_speak = 1 + else + var/mob/living/carbon/human/H + if(ishuman(M)) + H = M + else + new_mob = new /mob/living/carbon/human(M.loc) + H = new_mob + + if(M.gender == MALE) + H.gender = MALE + H.SetName(pick(GLOB.first_names_male)) + else if(M.gender == FEMALE) + H.gender = FEMALE + H.SetName(pick(GLOB.first_names_female)) + else + H.gender = NEUTER + H.SetName(pick(GLOB.first_names_female|GLOB.first_names_male)) + + H.name += " [pick(GLOB.last_names)]" + H.real_name = H.name + + H.set_species(randomize) + H.universal_speak = 1 + var/datum/preferences/A = new() //Randomize appearance for the human + A.randomize_appearance_and_body_for(H) + + if(new_mob) + for (var/spell/S in M.mind.learned_spells) + new_mob.add_spell(new S.type) + + new_mob.a_intent = "hurt" + if(M.mind) + M.mind.transfer_to(new_mob) + else + new_mob.key = M.key + + to_chat(new_mob, "Your form morphs into that of \a [lowertext(randomize)].") + + qdel(M) + return + else + to_chat(M, "Your form morphs into that of \a [lowertext(randomize)].") + return \ No newline at end of file diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm new file mode 100644 index 00000000..76556fc2 --- /dev/null +++ b/code/modules/projectiles/projectile/energy.dm @@ -0,0 +1,117 @@ +/obj/item/projectile/energy + name = "energy" + icon_state = "spark" + damage = 0 + damage_type = BURN + check_armour = "energy" + mob_hit_sound = list('sound/effects/gore/sear.ogg') + + +/obj/item/projectile/energy/laser + damage = 15 + icon_state = "laser" + +/obj/item/projectile/energy/laser/powerful + damage = 40 + + +//releases a burst of light on impact or after travelling a distance +/obj/item/projectile/energy/flash + name = "chemical shell" + icon_state = "bullet" + fire_sound = 'sound/weapons/gunshot/gunshot_pistol.ogg' + damage = 5 + agony = 20 + range = 15 //if the shell hasn't hit anything after travelling this far it just explodes. + muzzle_type = /obj/effect/projectile/bullet/muzzle + var/flash_range = 1 + var/brightness = 7 + var/light_colour = "#ffffff" + +/obj/item/projectile/energy/flash/on_impact(var/atom/A) + var/turf/T = flash_range? src.loc : get_turf(A) + if(!istype(T)) return + + //blind and confuse adjacent people + for (var/mob/living/carbon/M in viewers(T, flash_range)) + if(M.eyecheck() < FLASH_PROTECTION_MODERATE) + M.flash_eyes() + M.eye_blurry += (brightness / 2) + M.confused += (brightness / 2) + + //snap pop + playsound(src, 'sound/effects/snap.ogg', 50, 1) + src.visible_message("\The [src] explodes in a bright flash!") + + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(2, 1, T) + sparks.start() + + 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/smoke/illumination(T, 5, brightness, brightness, light_colour) + +//blinds people like the flash round, but in a larger area and can also be used for temporary illumination +/obj/item/projectile/energy/flash/flare + damage = 10 + agony = 25 + fire_sound = 'sound/weapons/gunshot/shotgun.ogg' + flash_range = 2 + brightness = 15 + +/obj/item/projectile/energy/flash/flare/on_impact(var/atom/A) + light_colour = pick("#e58775", "#ffffff", "#90ff90", "#a09030") + + ..() //initial flash + + //residual illumination + new /obj/effect/effect/smoke/illumination(src.loc, rand(190,240) SECONDS, range=8, power=3, color=light_colour) //same lighting power as flare + +/obj/item/projectile/energy/electrode + name = "electrode" + icon_state = "tracer" + fire_sound = 'sound/weapons/guns/fire/pain_fire.ogg' + mob_hit_sound = list('sound/weapons/tase.ogg') + nodamage = TRUE + agony = 50 + damage_type = PAIN + //Damage will be handled on the MOB side, to prevent window shattering. + +/obj/item/projectile/energy/electrode/stunshot + nodamage = 0 + damage = 15 + agony = 70 + damage_type = BURN + armor_penetration = 10 + +/obj/item/projectile/energy/dart + name = "dart" + icon_state = "toxin" + damage = 5 + damage_type = TOX + weaken = 5 + + +/obj/item/projectile/energy/bolt + name = "bolt" + icon_state = "cbbolt" + damage = 10 + damage_type = TOX + nodamage = 0 + agony = 40 + stutter = 10 + + +/obj/item/projectile/energy/bolt/large + name = "largebolt" + damage = 20 + agony = 60 + + +/obj/item/projectile/energy/neurotoxin + name = "neuro" + icon_state = "neurotoxin" + damage = 5 + damage_type = TOX + weaken = 5 + + diff --git a/code/modules/projectiles/projectile/force.dm b/code/modules/projectiles/projectile/force.dm new file mode 100644 index 00000000..71b7d34d --- /dev/null +++ b/code/modules/projectiles/projectile/force.dm @@ -0,0 +1,28 @@ +/obj/item/projectile/forcebolt + name = "force bolt" + icon = 'icons/obj/projectiles.dmi' + icon_state = "ice_1" + damage = 20 + check_armour = "energy" + +/obj/item/projectile/forcebolt/strong + name = "force bolt" + +/obj/item/projectile/forcebolt/on_hit(var/atom/movable/target, var/blocked = 0) + if(istype(target)) + var/throwdir = get_dir(firer,target) + target.throw_at(get_edge_target_turf(target, throwdir),10,10) + return 1 + +/* +/obj/item/projectile/forcebolt/strong/on_hit(var/atom/target, var/blocked = 0) + + // NONE OF THIS WORKS. DO NOT USE. + var/throwdir = null + + for(var/mob/M in hearers(2, src)) + if(M.loc != src.loc) + throwdir = get_dir(src,target) + M.throw_at(get_edge_target_turf(M, throwdir),15,1) + return ..() +*/ diff --git a/code/modules/projectiles/projectile/magnetic.dm b/code/modules/projectiles/projectile/magnetic.dm new file mode 100644 index 00000000..f4c9e824 --- /dev/null +++ b/code/modules/projectiles/projectile/magnetic.dm @@ -0,0 +1,24 @@ +// Rod for railguns. Slightly less nasty than the sniper round. +/obj/item/projectile/bullet/magnetic + name = "rod" + icon_state = "rod" + damage = 65 + stun = 1 + weaken = 1 + penetrating = 5 + armor_penetration = 70 + penetration_modifier = 1.1 + fire_sound = 'sound/weapons/railgun.ogg' + +/obj/item/projectile/bullet/magnetic/slug + name = "slug" + icon_state = "gauss_silenced" + damage = 75 + armor_penetration = 90 + +/obj/item/projectile/bullet/magnetic/flechette + name = "flechette" + icon_state = "flechette" + damage = 20 + armor_penetration = 100 + fire_sound = 'sound/weapons/rapidslice.ogg' \ No newline at end of file diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm new file mode 100644 index 00000000..948b346a --- /dev/null +++ b/code/modules/projectiles/projectile/special.dm @@ -0,0 +1,217 @@ +/obj/item/projectile/ion + name = "ion bolt" + icon_state = "ion" + fire_sound = 'sound/weapons/Laser.ogg' + damage = 0 + damage_type = BURN + nodamage = 1 + check_armour = "energy" + var/heavy_effect_range = 1 + var/light_effect_range = 2 + + on_impact(var/atom/A) + empulse(A, heavy_effect_range, light_effect_range) + return 1 + +/obj/item/projectile/ion/small + name = "ion pulse" + heavy_effect_range = 0 + light_effect_range = 1 + +/obj/item/projectile/bullet/gyro + name ="explosive bolt" + icon_state= "bolter" + damage = 50 + check_armour = "bullet" + sharp = 1 + edge = 1 + + on_hit(var/atom/target, var/blocked = 0) + explosion(target, -1, 0, 2) + return 1 + +/obj/item/projectile/meteor + name = "meteor" + icon = 'icons/obj/meteor.dmi' + icon_state = "smallf" + damage = 0 + damage_type = BRUTE + nodamage = 1 + check_armour = "bullet" + + Bump(atom/A as mob|obj|turf|area) + if(A == firer) + loc = A.loc + return + + sleep(-1) //Might not be important enough for a sleep(-1) but the sleep/spawn itself is necessary thanks to explosions and metoerhits + + if(src)//Do not add to this if() statement, otherwise the meteor won't delete them + if(A) + + A.ex_act(2) + playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1) + + for(var/mob/M in range(10, src)) + if(!M.stat && !istype(M, /mob/living/silicon/ai))\ + shake_camera(M, 3, 1) + qdel(src) + return 1 + else + return 0 + + +/obj/item/projectile/beam/mindflayer + name = "flayer ray" + + on_hit(var/atom/target, var/blocked = 0) + if(ishuman(target)) + var/mob/living/carbon/human/M = target + M.confused += rand(5,8) + +/obj/item/projectile/chameleon + name = "bullet" + icon_state = "bullet" + damage = 1 // stop trying to murderbone with a fake gun dumbass!!! + embed = 0 // nope + nodamage = 1 + damage_type = PAIN + muzzle_type = /obj/effect/projectile/bullet/muzzle + +/obj/item/projectile/fire_spray + name = "fire" + icon_state = "fire" + damage = 0 //It catches stuff on fire and doesn't actually do damage. + muzzle_type = /obj/effect/projectile/bullet/muzzle + + Bump(atom/A as mob|obj|turf|area) + if(ishuman(A)) + var/mob/living/carbon/human/H = A + H.adjust_fire_stacks(50) + H.IgniteMob() + +/obj/item/projectile/flamer + name = "fire" + icon_state = "flame" + damage = 3 + range = 5//Very short range. + damage_type = BURN + mob_hit_sound = list('sound/effects/fire.ogg') + speed = 0.8 + +/obj/item/projectile/flamer/on_hit(var/atom/target, var/blocked = 0) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(!istype(H.wear_suit, /obj/item/clothing/suit/fire)) + H.adjust_fire_stacks(50) + H.IgniteMob() + new /obj/flamer_fire(H.loc, 12, 10, "red", 1) + if(H.isChild()) + var/mob/living/carbon/human/F = firer + F.unlock_achievement(new/datum/achievement/child_fire()) + + +//Create a flame sprite object. Doesn't work like regular fire, ie. does not affect atmos or heat +/obj/flamer_fire + name = "fire" + desc = "Ouch!" + anchored = 1 + mouse_opacity = 0 + icon = 'icons/effects/fire.dmi' + icon_state = "red_2" + layer = BELOW_OBJ_LAYER + var/firelevel = 12 //Tracks how much "fire" there is. Basically the timer of how long the fire burns + var/burnlevel = 10 //Tracks how HOT the fire is. This is basically the heat level of the fire and determines the temperature. + var/flame_color = "red" + +/obj/flamer_fire/New(loc, fire_lvl, burn_lvl, f_color, fire_spread_amount) + ..() + if(istype(loc, /turf/simulated/floor/exoplanet/water/shallow))//No catching the water on fire. + qdel(src) + playsound(src, "sound/effects/fire.ogg", 50, FALSE) + if (f_color) + flame_color = f_color + + icon_state = "[flame_color]_2" + if(fire_lvl) firelevel = fire_lvl + if(burn_lvl) burnlevel = burn_lvl + START_PROCESSING(SSobj,src) + + if(fire_spread_amount > 0) + var/turf/T + for(var/dirn in GLOB.cardinal) + T = get_step(loc, dirn) + if(istype(T,/turf/simulated/floor/exoplanet/water/shallow)) continue//Do not light the water on fire please. + if(locate(/obj/flamer_fire) in T) continue //No stacking + var/new_spread_amt = T.density ? 0 : fire_spread_amount - 1 //walls stop the spread + if(new_spread_amt) + for(var/obj/O in T) + if(!O.CanPass(src, loc)) + new_spread_amt = 0 + break + spawn(0) //delay so the newer flame don't block the spread of older flames + new /obj/flamer_fire(T, fire_lvl, burn_lvl, f_color, new_spread_amt) + + +/obj/flamer_fire/Destroy() + set_light(0) + STOP_PROCESSING(SSobj,src) + . = ..() + + +/obj/flamer_fire/Crossed(mob/living/M) //Only way to get it to reliable do it when you walk into it. + if(istype(M)) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(istype(H.wear_suit, /obj/item/clothing/suit/fire)) + return + M.adjust_fire_stacks(burnlevel) //Make it possible to light them on fire later. + if (prob(firelevel + 2*M.fire_stacks)) //the more soaked in fire you are, the likelier to be ignited + M.IgniteMob() + + M.adjustFireLoss(round(burnlevel*0.5)) //This makes fire stronk. + + +/obj/flamer_fire/proc/updateicon() + if(burnlevel < 15) + color = "#c1c1c1" //make it darker to make show its weaker. + switch(firelevel) + if(1 to 9) + icon_state = "[flame_color]_1" + set_light(2) + if(10 to 25) + icon_state = "[flame_color]_2" + set_light(4) + if(25 to INFINITY) //Change the icons and luminosity based on the fire's intensity + icon_state = "[flame_color]_3" + set_light(6) + + +/obj/flamer_fire/Process() + var/turf/T = loc + firelevel = max(0, firelevel) + if(!istype(T)) //Is it a valid turf? Has to be on a floor + qdel(src) + return + + updateicon() + + if(!firelevel) + qdel(src) + return + + var/j = 0 + for(var/i in loc) + if(++j >= 11) break + if(isliving(i)) + var/mob/living/I = i + if(istype(I,/mob/living/carbon/human)) + var/mob/living/carbon/human/M = I + if(istype(M.wear_suit, /obj/item/clothing/suit/fire)) + continue + I.adjust_fire_stacks(burnlevel) //If i stand in the fire i deserve all of this. Also Napalm stacks quickly. + I.IgniteMob() + + //This has been made a simple loop, for the most part flamer_fire_act() just does return, but for specific items it'll cause other effects. + firelevel -= 2 //reduce the intensity by 2 per tick + return \ No newline at end of file diff --git a/code/modules/projectiles/projectile/trace.dm b/code/modules/projectiles/projectile/trace.dm new file mode 100644 index 00000000..9808a9b2 --- /dev/null +++ b/code/modules/projectiles/projectile/trace.dm @@ -0,0 +1,38 @@ +//Helper proc to check if you can hit them or not. +/proc/check_trajectory(atom/target as mob|obj, atom/firer as mob|obj, var/pass_flags=PASS_FLAG_TABLE|PASS_FLAG_GLASS|PASS_FLAG_GRILLE) + if(!istype(target) || !istype(firer)) + return 0 + + var/obj/item/projectile/test/trace = new /obj/item/projectile/test(get_turf(firer)) //Making the test.... + + //Set the flags and pass flags to that of the real projectile... + //if(!isnull(flags)) + // trace.flags = flags + trace.pass_flags = pass_flags + + return trace.launch_projectile(target) //Test it! + +/obj/item/projectile/proc/_check_fire(atom/target as mob, var/mob/living/user as mob) //Checks if you can hit them or not. + check_trajectory(target, user, pass_flags) + +//"Tracing" projectile +/obj/item/projectile/test //Used to see if you can hit them. + invisibility = 101 //Nope! Can't see me! + hitscan = TRUE + nodamage = TRUE + damage = 0 + var/list/hit = list() + +/obj/item/projectile/test/process_hitscan() + . = ..() + if(!QDELING(src)) + qdel(src) + return hit + +/obj/item/projectile/test/Bump(atom/A) + if(A != src) + hit |= A + return ..() + +/obj/item/projectile/test/attack_mob() + return diff --git a/code/modules/projectiles/projectile_effects/projectile_effects.dm b/code/modules/projectiles/projectile_effects/projectile_effects.dm new file mode 100644 index 00000000..fb73955c --- /dev/null +++ b/code/modules/projectiles/projectile_effects/projectile_effects.dm @@ -0,0 +1,220 @@ +/obj/effect/projectile + name = "pew" + icon = 'icons/obj/projectiles.dmi' + icon_state = "nothing" + plane = EFFECTS_ABOVE_LIGHTING_PLANE + layer = BEAM_PROJECTILE_LAYER //Muzzle flashes would be above the lighting plane anyways. + //Standard compiletime light vars aren't working here, so we've made some of our own. + light_range = 2 + light_power = 1 + light_color = "#FF00DC" + mouse_opacity = 0 + appearance_flags = 0 + +/obj/effect/projectile/singularity_pull() + return + +/obj/effect/projectile/singularity_act() + return + +/obj/effect/projectile/proc/scale_to(nx,ny,override=TRUE) + var/matrix/M + if(!override) + M = transform + else + M = new + M.Scale(nx,ny) + transform = M + +/obj/effect/projectile/proc/turn_to(angle,override=TRUE) + var/matrix/M + if(!override) + M = transform + else + M = new + M.Turn(angle) + transform = M + +/obj/effect/projectile/New(angle_override, p_x, p_y, color_override, scaling = 1) + if(angle_override && p_x && p_y && color_override && scaling) + apply_vars(angle_override, p_x, p_y, color_override, scaling) + return ..() + +/obj/effect/projectile/proc/apply_vars(angle_override, p_x = 0, p_y = 0, color_override, scaling = 1, new_loc, increment = 0) + var/mutable_appearance/look = new(src) + look.pixel_x = p_x + look.pixel_y = p_y + if(color_override) + look.color = color_override + appearance = look + scale_to(1,scaling, FALSE) + turn_to(angle_override, FALSE) + if(!isnull(new_loc)) //If you want to null it just delete it... + forceMove(new_loc) + for(var/i in 1 to increment) + pixel_x += round((sin(angle_override)+16*sin(angle_override)*2), 1) + pixel_y += round((cos(angle_override)+16*cos(angle_override)*2), 1) + + + +//---------------------------- +// Laser beam +//---------------------------- +/obj/effect/projectile/laser/ + light_color = COLOR_RED_LIGHT + +/obj/effect/projectile/laser/tracer + icon_state = "beam" + +/obj/effect/projectile/laser/muzzle + icon_state = "muzzle_laser" + +/obj/effect/projectile/laser/impact + icon_state = "impact_laser" + +//---------------------------- +// Blue laser beam +//---------------------------- +/obj/effect/projectile/laser/blue + light_color = COLOR_BLUE_LIGHT + +/obj/effect/projectile/laser/blue/tracer + icon_state = "beam_blue" + +/obj/effect/projectile/laser/blue/muzzle + icon_state = "muzzle_blue" + +/obj/effect/projectile/laser/blue/impact + icon_state = "impact_blue" + +//---------------------------- +// Omni laser beam +//---------------------------- +/obj/effect/projectile/laser/omni + light_color = COLOR_LUMINOL + +/obj/effect/projectile/laser/omni/tracer//tracer + icon_state = "beam_omni" + +/obj/effect/projectile/laser/omni/muzzle//muzzle + icon_state = "muzzle_omni" + +/obj/effect/projectile/laser/omni/impact//impact + icon_state = "impact_omni" + +//---------------------------- +// Xray laser beam +//---------------------------- +/obj/effect/projectile/laser/xray + light_color = "#00cc00" + +/obj/effect/projectile/laser/xray/tracer + icon_state = "xray" + +/obj/effect/projectile/laser/xray/muzzle + icon_state = "muzzle_xray" + +/obj/effect/projectile/laser/xray/impact + icon_state = "impact_xray" + +//---------------------------- +// Heavy laser beam +//---------------------------- +/obj/effect/projectile/laser/heavy + light_power = 3 + +/obj/effect/projectile/laser/heavy/tracer + icon_state = "beam_heavy" + +/obj/effect/projectile/laser/heavy/muzzle + icon_state = "muzzle_beam_heavy" + +/obj/effect/projectile/laser/heavy/impact + icon_state = "impact_beam_heavy" + +//---------------------------- +// Pulse laser beam +//---------------------------- +/obj/effect/projectile/laser/pulse + light_power = 2 + light_color = COLOR_DEEP_SKY_BLUE + +/obj/effect/projectile/laser/pulse/tracer + icon_state = "u_laser" + + +/obj/effect/projectile/laser/pulse/muzzle + icon_state = "muzzle_u_laser" + +/obj/effect/projectile/laser/pulse/impact + icon_state = "impact_u_laser" + +//---------------------------- +// Bogani Pulsar beam +//---------------------------- +/obj/effect/projectile/laser/bogani/ + light_power = 2 + light_color = COLOR_VIOLET + +/obj/effect/projectile/laser/bogani/tracer + icon_state = "bogb" + +/obj/effect/projectile/laser/bogani/muzzle + icon_state = "muzzle_bogb" + +/obj/effect/projectile/laser/bogani/impact + icon_state = "impact_bogb" + +//---------------------------- +// Pulse muzzle effect only +//---------------------------- +/obj/effect/projectile/pulse/muzzle + icon_state = "muzzle_pulse" + light_power = 2 + light_color = COLOR_DEEP_SKY_BLUE + +//---------------------------- +// Treye beam +//---------------------------- +/obj/effect/projectile/trilaser/ + light_color = COLOR_LUMINOL + +/obj/effect/projectile/trilaser/tracer + icon_state = "plasmacutter" + +/obj/effect/projectile/trilaser/muzzle + icon_state = "muzzle_plasmacutter" + +/obj/effect/projectile/trilaser/impact + icon_state = "impact_plasmacutter" + +//---------------------------- +// laser/emitter beam +//---------------------------- +/obj/effect/projectile/laser/emitter/ + light_power = 3 + light_color = "#00cc00" + +/obj/effect/projectile/laser/emitter/tracer + icon_state = "laser/emitter" + +/obj/effect/projectile/laser/emitter/muzzle + icon_state = "muzzle_laser/emitter" + +/obj/effect/projectile/laser/emitter/impact + icon_state = "impact_laser/emitter" + +//---------------------------- +// Stun beam +//---------------------------- +/obj/effect/projectile/stun/ + light_color = COLOR_YELLOW + +/obj/effect/projectile/stun/tracer + icon_state = "stun" + +/obj/effect/projectile/stun/muzzle + icon_state = "muzzle_stun" + +/obj/effect/projectile/stun/impact + icon_state = "impact_stun" \ No newline at end of file diff --git a/code/modules/projectiles/projectile_effects/projectile_impact.dm b/code/modules/projectiles/projectile_effects/projectile_impact.dm new file mode 100644 index 00000000..439518fb --- /dev/null +++ b/code/modules/projectiles/projectile_effects/projectile_impact.dm @@ -0,0 +1,81 @@ +/obj/effect/projectile/impact + name = "beam impact" + icon = 'icons/effects/projectiles/impact.dmi' + +/obj/effect/projectile/impact/laser + name = "laser impact" + icon_state = "impact_laser" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/impact/laser/blue + name = "laser impact" + icon_state = "impact_blue" + light_color = LIGHT_COLOR_BLUE + +/obj/effect/projectile/impact/disabler + name = "disabler impact" + icon_state = "impact_omni" + light_color = LIGHT_COLOR_CYAN + +/obj/effect/projectile/impact/xray + name = "xray impact" + icon_state = "impact_xray" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/impact/pulse + name = "pulse impact" + icon_state = "impact_u_laser" + light_color = LIGHT_COLOR_BLUE + +/obj/effect/projectile/impact/plasma_cutter + name = "plasma impact" + icon_state = "impact_plasmacutter" + light_color = LIGHT_COLOR_CYAN + +/obj/effect/projectile/impact/stun + name = "stun impact" + icon_state = "impact_stun" + light_color = LIGHT_COLOR_YELLOW + +/obj/effect/projectile/impact/heavy_laser + name = "heavy laser impact" + icon_state = "impact_beam_heavy" + light_power = 3 + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/impact/cult + name = "arcane blast" + icon_state = "impact_cult" + light_color = LIGHT_COLOR_VIOLET + appearance_flags = NO_CLIENT_COLOR + +/obj/effect/projectile/impact/cult/heavy + icon_state = "impact_hcult" + light_power = 3 + appearance_flags = NO_CLIENT_COLOR + +/obj/effect/projectile/impact/solar + name = "solar eruption" + icon_state = "impact_solar" + light_color = LIGHT_COLOR_FIRE + +/obj/effect/projectile/impact/eyelaser + icon_state = "impact_eye" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/impact/emitter + icon_state = "impact_emitter" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/impact/tachyon + name = "xray impact" + icon_state = "impact_tachyon" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/impact/bfg + icon_state = "impact_bfg" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/impact/hegemony + icon_state = "impact_hegemony" + light_color = LIGHT_COLOR_ORANGE \ No newline at end of file diff --git a/code/modules/projectiles/projectile_effects/projectile_muzzle.dm b/code/modules/projectiles/projectile_effects/projectile_muzzle.dm new file mode 100644 index 00000000..b3d713ac --- /dev/null +++ b/code/modules/projectiles/projectile_effects/projectile_muzzle.dm @@ -0,0 +1,84 @@ +/obj/effect/projectile/muzzle + name = "muzzle flash" + icon = 'icons/effects/projectiles/muzzle.dmi' + +/obj/effect/projectile/muzzle/laser + icon_state = "muzzle_laser" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/muzzle/laser/blue + icon_state = "muzzle_blue" + light_color = LIGHT_COLOR_BLUE + +/obj/effect/projectile/muzzle/disabler + icon_state = "muzzle_omni" + light_color = LIGHT_COLOR_CYAN + +/obj/effect/projectile/muzzle/xray + icon_state = "muzzle_xray" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/muzzle/pulse + icon_state = "muzzle_u_laser" + light_color = LIGHT_COLOR_BLUE + +/obj/effect/projectile/muzzle/plasma_cutter + icon_state = "muzzle_plasmacutter" + light_color = LIGHT_COLOR_CYAN + +/obj/effect/projectile/muzzle/stun + icon_state = "muzzle_stun" + light_color = LIGHT_COLOR_YELLOW + +/obj/effect/projectile/muzzle/heavy_laser + icon_state = "muzzle_beam_heavy" + light_power = 3 + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/muzzle/cult + name = "arcane flash" + icon_state = "muzzle_cult" + light_color = LIGHT_COLOR_VIOLET + appearance_flags = NO_CLIENT_COLOR + +/obj/effect/projectile/muzzle/cult/heavy + icon_state = "muzzle_hcult" + light_power = 3 + appearance_flags = NO_CLIENT_COLOR + +/obj/effect/projectile/muzzle/solar + icon_state = "muzzle_solar" + light_color = LIGHT_COLOR_FIRE + +/obj/effect/projectile/muzzle/eyelaser + icon_state = "muzzle_eye" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/muzzle/emitter + icon_state = "muzzle_emitter" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/bullet/muzzle + icon_state = "muzzle_bullet" + light_range = 5 + light_power = 1 + light_color = COLOR_MUZZLE_FLASH + +/obj/effect/projectile/muzzle/tachyon + icon_state = "muzzle_pulse" + light_color = LIGHT_COLOR_CYAN + +/obj/effect/projectile/muzzle/bolt + icon_state = "muzzle_bolt" + light_color = LIGHT_COLOR_FIRE + +/obj/effect/projectile/muzzle/gauss + icon_state = "muzzle_gauss" + +/obj/effect/projectile/muzzle/bfg + icon_state = "muzzle_bfg" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/muzzle/hegemony + icon_state = "muzzle_hegemony" + light_color = LIGHT_COLOR_ORANGE \ No newline at end of file diff --git a/code/modules/projectiles/projectile_effects/projectile_tracer.dm b/code/modules/projectiles/projectile_effects/projectile_tracer.dm new file mode 100644 index 00000000..cd71e0de --- /dev/null +++ b/code/modules/projectiles/projectile_effects/projectile_tracer.dm @@ -0,0 +1,93 @@ +/proc/generate_tracer_between_points(datum/point/starting, datum/point/ending, beam_type, color, qdel_in = 5) //Do not pass z-crossing points as that will not be properly (and likely will never be properly until it's absolutely needed) supported! + if(!istype(starting) || !istype(ending) || !ispath(beam_type)) + return + if(starting.z != ending.z) + crash_with("Projectile tracer generation of cross-Z beam detected. This feature is not supported!") //Do it anyways though. + var/datum/point/midpoint = point_midpoint_points(starting, ending) + var/obj/effect/projectile/tracer/PB = new beam_type + PB.apply_vars(angle_between_points(starting, ending), midpoint.return_px(), midpoint.return_py(), color, pixel_length_between_points(starting, ending) / world.icon_size, midpoint.return_turf(), 0) + . = PB + if(qdel_in) + QDEL_IN(PB, qdel_in) + +/obj/effect/projectile/tracer + name = "beam" + icon = 'icons/effects/projectiles/tracer.dmi' + +/obj/effect/projectile/tracer/laser + name = "laser" + icon_state = "beam" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/tracer/laser/blue + icon_state = "beam_blue" + +/obj/effect/projectile/tracer/disabler + name = "disabler" + icon_state = "beam_omni" + light_color = LIGHT_COLOR_CYAN + +/obj/effect/projectile/tracer/xray + name = "xray laser" + icon_state = "xray" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/tracer/pulse + name = "pulse laser" + icon_state = "u_laser" + light_color = LIGHT_COLOR_BLUE + +/obj/effect/projectile/tracer/plasma_cutter + name = "plasma blast" + icon_state = "plasmacutter" + light_color = LIGHT_COLOR_CYAN + +/obj/effect/projectile/tracer/stun + name = "stun beam" + icon_state = "stun" + light_color = LIGHT_COLOR_YELLOW + +/obj/effect/projectile/tracer/heavy_laser + name = "heavy laser" + icon_state = "beam_heavy" + light_power = 3 + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/tracer/cult + name = "arcane beam" + icon_state = "cult" + light_color = LIGHT_COLOR_VIOLET + appearance_flags = NO_CLIENT_COLOR + +/obj/effect/projectile/tracer/cult/heavy + name = "heavy arcane beam" + icon_state = "hcult" + light_power = 3 + appearance_flags = NO_CLIENT_COLOR + +/obj/effect/projectile/tracer/solar + name = "solar energy" + icon_state = "solar" + light_color = LIGHT_COLOR_FIRE + +/obj/effect/projectile/tracer/eyelaser + icon_state = "eye" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/tracer/emitter + icon_state = "emitter" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/tracer/tachyon + name = "particle beam" + icon_state = "invisible" + light_color = LIGHT_COLOR_VIOLET + +/obj/effect/projectile/tracer/bfg + icon_state = "bfg" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/tracer/hegemony + name = "laser" + icon_state = "hegemony" + light_color = LIGHT_COLOR_ORANGE \ No newline at end of file diff --git a/code/modules/projectiles/projectile_new.dm b/code/modules/projectiles/projectile_new.dm new file mode 100644 index 00000000..afee4ef7 --- /dev/null +++ b/code/modules/projectiles/projectile_new.dm @@ -0,0 +1,1021 @@ +#define MUZZLE_EFFECT_PIXEL_INCREMENT 16 //How many pixels to move the muzzle flash up so your character doesn't look like they're shitting out lasers. + +/obj/item/projectile + name = "projectile" + icon = 'icons/obj/projectiles.dmi' + icon_state = "bullet" + density = TRUE + unacidable = TRUE + anchored = TRUE //There's a reason this is here, Mport. God fucking damn it -Agouri. Find&Fix by Pete. The reason this is here is to stop the curving of emitter shots. + pass_flags = PASS_FLAG_TABLE + mouse_opacity = 0 + animate_movement = 0 //Use SLIDE_STEPS in conjunction with legacy + plane = BULLET_PLANE + var/projectile_type = /obj/item/projectile + + var/list/mob_hit_sound = list('sound/effects/gore/bullethit2.ogg', 'sound/effects/gore/bullethit3.ogg') //Sound it makes when it hits a mob. It's a list so you can put multiple hit sounds there. + var/wall_hitsound = "hitwall" + var/list/armor_hit_sound = list('sound/effects/gore/armorhit1.ogg', 'sound/effects/gore/armorhit2.ogg','sound/effects/gore/armorhit3.ogg','sound/effects/gore/armorhit4.ogg') + var/list/helmet_hit_sound = list('sound/effects/gore/helmhit1.ogg', 'sound/effects/gore/helmhit2.ogg','sound/effects/gore/helmhit3.ogg','sound/effects/gore/helmhit4.ogg','sound/effects/gore/helmhit5.ogg') + var/fire_sound = 'sound/weapons/gunshot/gunshot.ogg'//Default gun sound. + var/def_zone = "" //Aiming at + var/mob/firer = null//Who shot it + var/silenced = FALSE //Attack message + var/bumped + + var/shot_from = "" // name of the object which shot us + + var/accuracy = 0 + var/dispersion = 0.0 + + //used for shooting at blank range, you shouldn't be able to miss + var/can_miss = 0 + + var/taser_effect = 0 //If set then the projectile will apply it's agony damage using stun_effect_act() to mobs it hits, and other damage will be ignored + + //Effects + var/damage = 10 + var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE, HALLOSS are the only things that should be in here + var/nodamage = FALSE //Determines if the projectile will skip any damage inflictions + var/check_armour = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb //Cael - bio and rad are also valid + + var/stun = 0 + var/weaken = 0 + var/paralyze = 0 + var/irradiate = 0 + var/stutter = 0 + var/eyeblur = 0 + var/drowsy = 0 + var/agony = 0 + + var/incinerate = 0 + var/embed = 0 // whether or not the projectile can embed itself in the mob + var/shrapnel_type //type of shrapnel the projectile leaves in its target. + + var/p_x = 16 + var/p_y = 16 // the pixel location of the tile that the player clicked. Default is the center + + //For Maim / Maiming. + var/maiming = 0 //Enables special limb dismemberment calculation; used primarily for ranged weapons that can maim, but do not do brute damage. + var/maim_rate = 0 //Factor that the recipiant will be maimed by the projectile (NOT OUT OF 100%.) + var/clean_cut = 0 //Is the delimbning painful and unclean? Probably. Can be a function or proc, if you're doing something odd. + var/maim_type = DROPLIMB_EDGE + /*Does the projectile simply lop/tear the limb off, or does it vaporize it? + Set maim_type to DROPLIMB_EDGE to chop off the limb + set maim_type to DROPLIMB_BURN to vaporize it. + set maim_type to DROPLIMB_BLUNT to gib (Explode/Hamburger) the limb. + */ + + //Movement parameters + var/speed = 0.2 //Amount of deciseconds it takes for projectile to travel + var/pixel_speed = 33 //pixels per move - DO NOT FUCK WITH THIS UNLESS YOU ABSOLUTELY KNOW WHAT YOU ARE DOING OR UNEXPECTED THINGS /WILL/ HAPPEN! + var/Angle = 0 + var/original_angle = 0 //Angle at firing + var/nondirectional_sprite = FALSE //Set TRUE to prevent projectiles from having their sprites rotated based on firing angle + var/yo = null + var/xo = null + var/atom/original // the target clicked (not necessarily where the projectile is headed). Should probably be renamed to 'target' or something. + var/turf/starting // the projectile's starting turf + var/list/permutated // we've passed through these atoms, don't try to hit them again + var/penetrating = 0 //If greater than zero, the projectile will pass through dense objects as specified by on_penetrate() + var/penetration_modifier = 0.2 //How much internal damage this projectile can deal, as a multiplier. + var/forcedodge = FALSE //to pass through everything + var/ignore_source_check = FALSE + + //Fired processing vars + var/fired = FALSE //Have we been fired yet + var/paused = FALSE //for suspending the projectile midair + var/last_projectile_move = 0 + var/last_process = 0 + var/time_offset = 0 + var/datum/point/vector/trajectory + var/trajectory_ignore_forcemove = FALSE //instructs forceMove to NOT reset our trajectory to the new location! + var/range = 50 //This will de-increment every step. When 0, it will deletze the projectile. + var/aoe = 0 //For KAs, really + + //Hitscan + var/hitscan = FALSE //Whether this is hitscan. If it is, speed is basically ignored. + var/list/beam_segments //assoc list of datum/point or datum/point/vector, start = end. Used for hitscan effect generation. + var/datum/point/beam_index + var/turf/hitscan_last //last turf touched during hitscanning. + var/tracer_type + var/muzzle_type + var/impact_type + var/hit_effect + var/matrix/effect_transform // matrix to rotate and scale projectile effects - putting it here so it doesn't + // have to be recreated multiple times + var/non_trench_counter = 0 //For trench cover bullshit. + var/trench_counter = 0 + var/do_not_pass_trench = FALSE //For stuff you do not want to leave the trench. + +/obj/item/projectile/CanPass() + return TRUE + +//TODO: make it so this is called more reliably, instead of sometimes by bullet_act() and sometimes not +/obj/item/projectile/proc/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null) + if(blocked >= 100) //Full block + return FALSE + if(!isliving(target)) + return FALSE + if(isanimal(target)) + return FALSE + var/mob/living/L = target + if(damage && damage_type == BRUTE) + var/turf/target_loca = get_turf(target) + var/splatter_dir = dir + if(starting) + splatter_dir = get_dir(starting, target_loca) + target_loca = get_step(target_loca, splatter_dir) + if(isalien(L)) + new /obj/effect/overlay/temp/dir_setting/bloodsplatter/xenosplatter(get_turf(target), splatter_dir) + else + var/blood_color = "#C80000" + if(ishuman(target)) + var/mob/living/carbon/human/H = target + blood_color = H.species.blood_color + new /obj/effect/overlay/temp/dir_setting/bloodsplatter(get_turf(target), splatter_dir, blood_color) + //if(prob(50)) + var/obj/effect/decal/cleanable/blood/B = blood_splatter(target_loca, L, 1, splatter_dir) + B.icon_state = pick("dir_splatter_1","dir_splatter_2") + var/scale = min(1, round(damage / 50, 0.2)) + var/matrix/M = new() + B.transform = M.Scale(scale) + //target_loca.add_blood(L) + + L.apply_effects(stun, weaken, paralyze, 0, stutter, eyeblur, drowsy, agony, incinerate, blocked) + L.apply_effect(irradiate, IRRADIATE, L.getarmor(null, "rad")) //radiation protection is handled separately from other armour types. + return 1 + +//called when the projectile stops flying because it collided with something +/obj/item/projectile/proc/on_impact(var/atom/A) + return + +//Checks if the projectile is eligible for embedding. Not that it necessarily will. +/obj/item/projectile/proc/can_embed() + //embed must be enabled and damage type must be brute + if(!embed || damage_type != BRUTE) + return FALSE + return TRUE + +/obj/item/projectile/proc/get_structure_damage() + if(damage_type == BRUTE || damage_type == BURN) + return damage + return FALSE + +//return TRUE if the projectile should be allowed to pass through after all, FALSE if not. +/obj/item/projectile/proc/check_penetrate(atom/A) + return TRUE + +/obj/item/projectile/proc/launch_projectile(atom/target, target_zone, mob/user, params, angle_override, forced_spread = 0) + original = target + def_zone = check_zone(target_zone) + firer = user + var/direct_target + if(get_turf(target) == get_turf(src)) + direct_target = target + + preparePixelProjectile(target, user? user : get_turf(src), params, forced_spread) + return fire(angle_override, direct_target) + +//called to launch a projectile from a gun +/obj/item/projectile/proc/launch_from_gun(atom/target, target_zone, mob/user, params, angle_override, forced_spread, var/obj/item/weapon/gun/launcher) + + shot_from = launcher.name + silenced = launcher.silenced + + if(launcher.damage_modifier) + damage += launcher.damage_modifier + + return launch_projectile(target, target_zone, user, params, angle_override, forced_spread) + + +/obj/item/projectile/proc/istargetloc(mob/living/target_mob) + if(target_mob && original) + var/turf/originalloc + if(!istype(original, /turf)) + originalloc = original.loc + else + originalloc = original + if(originalloc == target_mob.loc) + return 1 + else + return 0 + else + return 0 + +//Called when the projectile intercepts a mob. Returns 1 if the projectile hit the mob, 0 if it missed and should keep flying. +/obj/item/projectile/proc/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier=0) + if(!istype(target_mob)) + return + + //roll to-hit + //miss_modifier = max(15*(distance-1) - round(25*accuracy) + miss_modifier, 0) + miss_modifier = 15*(distance-2) - round(15*accuracy) + miss_modifier + if(target_mob == src.original) + miss_modifier -= 60 + var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, miss_modifier, ranged_attack=(distance > 1 || original != target_mob)) //if the projectile hits a target we weren't originally aiming at then retain the chance to miss + + var/result = PROJECTILE_FORCE_MISS + var/do_normal_check = TRUE + if(hit_zone) + def_zone = hit_zone //set def_zone, so if the projectile ends up hitting someone else later (to be implemented), it is more likely to hit the same part + if(def_zone) + switch(target_mob.dir) + if(2) + if(p_y <= 10) //legs level + if(p_x >= 17) + if(def_zone == BP_L_LEG || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_L_ARM \ + || def_zone == BP_CHEST) + def_zone = BP_L_LEG + if(def_zone == BP_HEAD || def_zone == BP_R_ARM) + def_zone = BP_CHEST + //lleg + else + if(def_zone == BP_L_LEG || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST) + def_zone = BP_R_LEG + if(def_zone == BP_HEAD || def_zone == BP_L_ARM) + def_zone = BP_CHEST + //rleg + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_L_LEG, BP_R_LEG) + + if(p_y > 10 && p_y <= 13) //groin level + if(p_x <= 12) + if(def_zone == BP_L_ARM || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_HEAD) + def_zone = BP_R_ARM + if(def_zone == BP_HEAD || def_zone == BP_L_LEG) + def_zone = BP_CHEST + //rarm + if(p_x > 12 && p_x < 21) + if(def_zone == BP_L_ARM || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_L_LEG) + def_zone = BP_GROIN + if(def_zone == BP_HEAD) + def_zone = BP_CHEST + //groin + if(p_x >= 21 && p_x < 24) + //larm + if(def_zone == BP_L_ARM || def_zone == BP_L_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_HEAD) + def_zone = BP_L_ARM + if(def_zone == BP_HEAD || def_zone == BP_R_LEG) + def_zone = BP_CHEST + + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_R_ARM, BP_L_ARM, BP_CHEST, BP_GROIN) + + if(p_y > 13 && p_y <= 22) + if(p_x <= 12) + if(def_zone == BP_L_ARM || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_HEAD) + def_zone = BP_R_ARM + if(def_zone == BP_HEAD || def_zone == BP_L_LEG) + def_zone = BP_CHEST + //rarm + if(p_x > 12 && p_x < 21) + if(def_zone == BP_L_ARM || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_L_LEG \ + || def_zone == BP_HEAD) + def_zone = BP_CHEST + //chest + + if(p_x >= 21 && p_x < 24) + if(def_zone == BP_L_ARM || def_zone == BP_HEAD\ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_L_LEG) + def_zone = BP_L_ARM + //larm + if(def_zone == BP_HEAD || def_zone == BP_R_LEG) + def_zone = BP_CHEST + + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_R_ARM, BP_L_ARM, BP_CHEST) + + if(p_y > 22 && p_y <= 32) + if(def_zone == BP_L_ARM \ + || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST) + def_zone = BP_HEAD + //head + if(def_zone == BP_GROIN || def_zone == BP_R_LEG || \ + def_zone == BP_L_LEG) + def_zone = BP_CHEST + + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_HEAD, BP_CHEST) + if(1) + if(p_y <= 10) //legs level + if(p_x >= 17) + if(def_zone == BP_L_LEG || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST) + def_zone = BP_R_LEG + if(def_zone == BP_HEAD || def_zone == BP_L_ARM) + def_zone = BP_CHEST + //rleg + + else + if(def_zone == BP_L_LEG || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_L_ARM \ + || def_zone == BP_CHEST) + def_zone = BP_L_LEG + if(def_zone == BP_HEAD || def_zone == BP_L_ARM) + def_zone = BP_CHEST + //lleg + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_R_LEG, BP_L_LEG, BP_CHEST) + + if(p_y > 10 && p_y <= 13) //groin level + if(p_x <= 12) + if(def_zone == BP_L_ARM || def_zone == BP_L_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_HEAD) + def_zone = BP_L_ARM + if(def_zone == BP_HEAD || def_zone == BP_R_LEG) + def_zone = BP_CHEST + //larm + if(p_x > 12 && p_x < 21) + if(def_zone == BP_L_ARM || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_L_LEG) + def_zone = BP_GROIN + if(def_zone == BP_HEAD) + def_zone = BP_CHEST + //groin + if(p_x >= 21 && p_x < 24) + if(def_zone == BP_L_ARM || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_HEAD) + def_zone = BP_R_ARM + if(def_zone == BP_HEAD || def_zone == BP_L_LEG) + def_zone = BP_CHEST + //rarm + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_R_ARM, BP_L_ARM, BP_CHEST, BP_GROIN) + if(p_y > 13 && p_y <= 22) + if(p_x <= 12) + if(def_zone == BP_L_ARM || def_zone == BP_L_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_HEAD) + def_zone = BP_L_ARM + if(def_zone == BP_HEAD || def_zone == BP_R_LEG) + def_zone = BP_CHEST + //larm + if(p_x > 12 && p_x < 21) + if(def_zone == BP_L_ARM || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_L_LEG \ + || def_zone == BP_HEAD) + def_zone = BP_CHEST + if(def_zone == BP_HEAD || def_zone == BP_R_LEG) + def_zone = BP_CHEST + //chest + if(p_x >= 21 && p_x < 24) + if(def_zone == BP_L_ARM || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_HEAD) + def_zone = BP_R_ARM + if(def_zone == BP_HEAD || def_zone == BP_L_LEG) + def_zone = BP_CHEST + //rarm + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_R_ARM, BP_L_ARM, BP_CHEST) + + if(p_y > 22 && p_y <= 32) + if(def_zone == BP_L_ARM \ + || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST) + def_zone = BP_HEAD + if(def_zone == BP_GROIN || def_zone == BP_L_LEG || \ + def_zone == BP_R_LEG) + def_zone = BP_CHEST + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_R_ARM, BP_L_ARM, BP_CHEST, BP_HEAD) + //head + if(4) + if(p_y <= 10) //legs level + if(def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST) + def_zone = BP_R_LEG + if(def_zone == BP_HEAD || def_zone == BP_R_ARM) + def_zone = BP_CHEST + if(def_zone == BP_L_LEG) + def_zone = BP_L_LEG + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_R_LEG, BP_L_LEG, BP_CHEST) + //rleg + + if(p_y > 10 && p_y <= 13) //groin level + if(p_x < 16) + if(def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_HEAD) + def_zone = BP_R_ARM + if(def_zone == HEAD || def_zone == BP_L_LEG) + def_zone = BP_CHEST + if(def_zone == BP_L_ARM) + def_zone = BP_L_ARM + //rarm + if(p_x >= 16) + if(def_zone == BP_L_ARM || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_L_LEG) + def_zone = BP_GROIN + if(def_zone == BP_HEAD) + def_zone = BP_CHEST + + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_R_ARM, BP_L_ARM, BP_CHEST, BP_GROIN) + //groin + + if(p_y > 13 && p_y <= 22) + if(p_x >= 16) + if(def_zone == BP_L_ARM || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_L_LEG \ + || def_zone == HEAD) + def_zone = BP_CHEST + //chest + if(p_x < 16) + if(def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_HEAD) + def_zone = BP_R_ARM + //rarm + if(def_zone == BP_HEAD || def_zone == BP_L_LEG) + def_zone = BP_CHEST + if(def_zone == BP_L_ARM) + def_zone = BP_L_ARM + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_R_ARM, BP_L_ARM, BP_CHEST) + + if(p_y > 22 && p_y <= 32) + if(def_zone == BP_L_ARM \ + || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST) + def_zone = BP_HEAD + if(def_zone == BP_GROIN || def_zone == BP_L_LEG || def_zone == BP_R_LEG) + def_zone = BP_CHEST + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_R_ARM, BP_L_ARM, BP_CHEST, BP_HEAD) + //head + + if(8) + if(p_y <= 10) //legs level + //lleg + if(def_zone == BP_L_LEG \ + || def_zone == BP_GROIN || def_zone == BP_L_ARM \ + || def_zone == BP_CHEST) + def_zone = BP_L_LEG + + if(def_zone == BP_HEAD || def_zone == BP_R_ARM) + def_zone = BP_CHEST + + if(def_zone == BP_R_LEG) + def_zone = BP_R_LEG + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_R_LEG, BP_L_LEG, BP_CHEST) + + if(p_y > 10 && p_y <= 13) //groin level + if(p_x < 16) + if(def_zone == BP_L_ARM || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_L_LEG) + def_zone = BP_GROIN + if(def_zone == BP_HEAD) + def_zone = BP_CHEST + //groin + if(p_x >= 16) + if(def_zone == BP_L_ARM || def_zone == BP_L_LEG \ + || def_zone == BP_GROIN \ + || def_zone == BP_CHEST || def_zone == BP_HEAD) + def_zone = BP_L_ARM + if(def_zone == BP_HEAD || def_zone == BP_R_LEG) + def_zone = BP_CHEST + if(def_zone == BP_R_ARM) + def_zone = BP_R_ARM + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_R_ARM, BP_L_ARM, BP_CHEST, BP_GROIN) + //left_arm + + if(p_y > 13 && p_y <= 22) + if(p_x < 16) + if(def_zone == BP_L_ARM || def_zone == BP_R_LEG \ + || def_zone == BP_GROIN || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST || def_zone == BP_L_LEG \ + || def_zone == BP_HEAD) + def_zone = BP_CHEST + //chest + if(p_x >= 16) + if(def_zone == BP_L_ARM || def_zone == BP_L_LEG \ + || def_zone == BP_GROIN \ + || def_zone == BP_CHEST || def_zone == BP_HEAD) + def_zone = BP_L_ARM + if(def_zone == BP_R_LEG || def_zone == BP_HEAD) + def_zone = BP_CHEST + if(def_zone == BP_R_ARM) + def_zone = BP_R_ARM + //larm + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_R_ARM, BP_L_ARM, BP_CHEST) + + if(p_y > 22 && p_y <= 32) + if(def_zone == BP_L_ARM \ + || def_zone == BP_R_ARM \ + || def_zone == BP_CHEST) + def_zone = BP_HEAD + if(def_zone == BP_GROIN || def_zone == BP_L_LEG || def_zone == BP_R_LEG) + def_zone = BP_CHEST + if(istargetloc(target_mob) == 0) + def_zone = pick(BP_R_ARM, BP_L_ARM, BP_CHEST, BP_HEAD) + //head + + if(firer) + if(istype(firer.loc, /turf/simulated/floor/trench)) + if(firer.lying) + do_normal_check = FALSE + result = PROJECTILE_FORCE_MISS + to_chat(firer, "I'm lying down I can't hit shit.") + + if(istype(target_mob.loc, /turf/simulated/floor/trench))//Shooting at someone in a trench. + if(non_trench_counter > 1)//Bullet was shot from open terrain. + if(original != target_mob)//We weren't shooting at them, so whizz past. + do_normal_check = FALSE + result = PROJECTILE_FORCE_MISS + to_chat(target_mob, "BULLETS WHIZZ PAST MY HEAD!") + target_mob.overlay_fullscreen("supress",/obj/screen/fullscreen/oxy, 5) + shake_camera(target_mob, 3, 2)//More supression effects. + target_mob.recoil += 15 //Make them innacurate for a tick when being supressed. + spawn(5) + target_mob.clear_fullscreen("supress", 5) + + else//We were actually shooting at them. + if(target_mob.lying || target_mob.crouching)//If the target is lying or crouching the bullets whizz right past them. + do_normal_check = FALSE + result = PROJECTILE_FORCE_MISS + to_chat(target_mob, "BULLETS WHIZZ PAST MY HEAD!") + target_mob.overlay_fullscreen("supress",/obj/screen/fullscreen/oxy, 5) + shake_camera(target_mob, 3, 2)//More supression effects. + target_mob.recoil += 15 //Make them innacurate for a tick when being supressed. + spawn(5) + target_mob.clear_fullscreen("supress", 5) + else if(prob(rand(1,15)))//Chance to miss, minmum of 1, max of 15. + do_normal_check = FALSE + result = PROJECTILE_FORCE_MISS + + else if(!istype(target_mob.loc, /turf/simulated/floor/trench))//They're not in a trench. + if(istype(starting, /turf/simulated/floor/trench))//We are in a trench. + if(firer && firer.lying) //We are lying down. + do_normal_check = FALSE + result = PROJECTILE_FORCE_MISS //We cannot hit them. Because being able to lie down and shoot them is fucking stupid. + to_chat(firer, "I cannot hit them lying down like this.") + + if(do_normal_check) + result = target_mob.bullet_act(src, def_zone)//this returns mob's armor_check and another - see modules/mob/living/living_defense.dm + + if(result == PROJECTILE_FORCE_MISS) + if(!silenced) + var/missound = "sound/weapons/guns/misc/miss[rand(1,4)].ogg" + target_mob.visible_message("\The [src] misses [target_mob] narrowly!") + playsound(target_mob, missound, 60, 1) + target_mob.overlay_fullscreen("supress",/obj/screen/fullscreen/oxy, 5) + shake_camera(target_mob, 3, 2)//More supression effects. + target_mob.recoil += 15 //Make them innacurate for a tick when being supressed. + spawn(5) + target_mob.clear_fullscreen("supress", 5) + return 0 + + if(ishuman(target_mob)) + var/mob/living/carbon/human/L = target_mob + if(istype(L.wear_suit, /obj/item/clothing/suit/armor) && parse_zone(def_zone) == BP_CHEST) + playsound(L,pick(armor_hit_sound), 100, 1) + if(istype(L.head, /obj/item/clothing/head/helmet) && parse_zone(def_zone) == BP_HEAD) + playsound(L, pick(helmet_hit_sound), 80, 1) + if(ishuman(firer))//Stuff that isn't a mob doesn't play well with achievements. + if(parse_zone(def_zone) == BP_HEAD)//Boom headshot bitch. + firer.unlock_achievement(new/datum/achievement/headshot()) + + if(silenced) + to_chat(target_mob, "You've been hit in the [parse_zone(def_zone)] by \the [src]!") + else + target_mob.visible_message("\The [target_mob] is hit by \the [src] in the [parse_zone(def_zone)]!")//X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter + playsound(target_mob, pick(mob_hit_sound), 40, 1) + //admin logs + if(!no_attack_log) + if(istype(firer, /mob)) + + var/attacker_message = "shot with \a [src.type]" + var/victim_message = "shot with \a [src.type]" + var/admin_message = "shot (\a [src.type])" + + admin_attack_log(firer, target_mob, attacker_message, victim_message, admin_message) + else + admin_victim_log(target_mob, "was shot by an UNKNOWN SUBJECT (No longer exists) using \a [src]") + if(ishuman(firer) && ishuman(target_mob)) + var/mob/living/carbon/human/attacker = firer + var/mob/living/carbon/human/victim = target_mob + if(attacker != victim && victim.stat != DEAD) + if(attacker.warfare_faction) + if(attacker.warfare_faction == victim.warfare_faction) + to_chat(attacker, "[victim] is on my side!") + log_and_message_admins("[attacker] has shot his teammate [victim] with \a [src.type]!", attacker) + GLOB.ff_incidents++//Dumb round end stat stuff. + + //sometimes bullet_act() will want the projectile to continue flying + if (result == PROJECTILE_CONTINUE) + return FALSE + + return TRUE + +/obj/item/projectile/Bump(atom/A as mob|obj|turf|area, forced=0) + . = ..() + if(A == src) + return FALSE //no. + + if((bumped && !forced) || (A in permutated)) + return FALSE + + if(firer && !ignore_source_check) + if(A == firer || (A == firer.loc)) //cannot shoot yourself or your mech + trajectory_ignore_forcemove = TRUE + forceMove(get_turf(A)) + trajectory_ignore_forcemove = FALSE + return FALSE + + + var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations. + var/passthrough = FALSE //if the projectile should continue flying + bumped = 1 + if(ismob(A)) + var/mob/M = A + if(istype(A, /mob/living)) + //if they have a neck grab on someone, that person gets hit instead + var/obj/item/grab/G = locate() in M + if(G) + visible_message("\The [M] uses [G.affecting] as a shield!") + if(Bump(G.affecting)) + return //If Collide() returns 0 (keep going) then we continue on to attack M. + + passthrough = !attack_mob(M, distance) + else + passthrough = TRUE //so ghosts don't stop bullets + else + playsound(loc, wall_hitsound, 50) + passthrough = (A.bullet_act(src, def_zone) == PROJECTILE_CONTINUE) //backwards compatibility + if(isturf(A)) + for(var/obj/O in A) + O.bullet_act(src) + for(var/mob/living/M in A) + attack_mob(M, distance) + + //penetrating projectiles can pass through things that otherwise would not let them + if(!passthrough && penetrating > 0) + if(check_penetrate(A)) + passthrough = TRUE + penetrating-- + + //the bullet passes through a dense object! + if(passthrough || forcedodge) + //move ourselves onto A so we can continue on our way. + if(A) + trajectory_ignore_forcemove = TRUE + if(istype(A, /turf)) + forceMove(A) + else + forceMove(get_turf(A)) + trajectory_ignore_forcemove = FALSE + permutated.Add(A) + return FALSE + + //stop flying + on_impact(A) + + qdel(src) + return TRUE + +/obj/item/projectile/ex_act(var/severity = 2.0) + return //explosions probably shouldn't delete projectiles + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/obj/item/projectile/proc/old_style_target(atom/target, atom/source) + if(!source) + source = get_turf(src) + setAngle(Get_Angle(source, target)) + +/obj/item/projectile/proc/fire(angle, atom/direct_target) + //If no angle needs to resolve it from xo/yo! + if(direct_target) + direct_target.bullet_act(src, def_zone) + on_impact(direct_target) + qdel(src) + return + if(isnum(angle)) + setAngle(angle) + // trajectory dispersion + var/turf/starting = get_turf(src) + if(!starting) + return + if(isnull(Angle)) //Try to resolve through offsets if there's no angle set. + if(isnull(xo) || isnull(yo)) + crash_with("WARNING: Projectile [type] deleted due to being unable to resolve a target after angle was null!") + qdel(src) + return + var/turf/target = locate(Clamp(starting + xo, 1, world.maxx), Clamp(starting + yo, 1, world.maxy), starting.z) + setAngle(Get_Angle(src, target)) + if(dispersion) + setAngle(Angle + rand(-dispersion, dispersion)) + original_angle = Angle + if(!nondirectional_sprite) + var/matrix/M = new + M.Turn(Angle) + transform = M + if(muzzle_type && !silenced) + if(ispath(muzzle_type)) + if(firer) + var/obj/effect/projectile/thing = new muzzle_type(get_turf(src)) + thing.dir = firer.dir + if(firer.dir == NORTH) + thing.pixel_y = 16 + thing.plane = ABOVE_OBJ_PLANE + else if(firer.dir == SOUTH) + thing.pixel_y = -16 + else if(firer.dir == EAST) + thing.pixel_x = 16 + else if(firer.dir == WEST) + thing.pixel_x = -16 + spawn(3) + qdel(thing) + forceMove(starting) + trajectory = new(starting.x, starting.y, starting.z, 0, 0, Angle, pixel_speed) + last_projectile_move = world.time + fired = TRUE + if(hitscan) + return process_hitscan() + else + if(!is_processing) + START_PROCESSING(SSprojectiles, src) + pixel_move(1) //move it now! + +/obj/item/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, angle_offset = 0) + var/turf/curloc = get_turf(source) + var/turf/targloc = get_turf(target) + forceMove(get_turf(source)) + starting = get_turf(source) + original = target + + var/list/calculated = list(null,null,null) + if(isliving(source) && params) + calculated = calculate_projectile_angle_and_pixel_offsets(source, params) + p_x = calculated[2] + p_y = calculated[3] + setAngle(calculated[1]) + + else if(targloc && curloc) + yo = targloc.y - curloc.y + xo = targloc.x - curloc.x + setAngle(Get_Angle(src, targloc)) + else + crash_with("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!") + qdel(src) + if(angle_offset) + setAngle(Angle + angle_offset) + +/obj/item/projectile/proc/before_move() + return + +/obj/item/projectile/proc/after_move() + return + +/obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a projectile is hit by it. + ..() + if(isliving(AM) && (AM.density || AM == original) && !(pass_flags & PASS_FLAG_MOB)) + Bump(AM) + +/obj/item/projectile/Initialize() + . = ..() + permutated = list() + +/obj/item/projectile/proc/pixel_move(moves, trajectory_multiplier = 1, hitscanning = FALSE) + if(!loc || !trajectory) + if(!QDELETED(src)) + if(loc) + on_impact(loc) + qdel(src) + return + last_projectile_move = world.time + if(!nondirectional_sprite && !hitscanning) + var/matrix/M = new + M.Turn(Angle) + transform = M + trajectory.increment(trajectory_multiplier) + var/turf/T = trajectory.return_turf() + if(T.z != loc.z) + before_move() + before_z_change(loc, T) + trajectory_ignore_forcemove = TRUE + forceMove(T) + trajectory_ignore_forcemove = FALSE + after_move() + if(!hitscanning) + pixel_x = trajectory.return_px() + pixel_y = trajectory.return_py() + else + before_move() + step_towards(src, T) + after_move() + if(!hitscanning) + pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier + pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier + if(!hitscanning) + animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW) + if(isturf(loc)) + hitscan_last = loc + if(can_hit_target(original, permutated)) + Bump(original, TRUE) + Range() + +//Returns true if the target atom is on our current turf and above the right layer +/obj/item/projectile/proc/can_hit_target(atom/target, var/list/passthrough) + return (target && ((target.layer >= TURF_LAYER + 0.3) || ismob(target)) && (loc == get_turf(target)) && (!(target in passthrough))) + +/proc/calculate_projectile_angle_and_pixel_offsets(mob/user, params) + var/list/mouse_control = params2list(params) + var/p_x = 0 + var/p_y = 0 + var/angle = 0 + if(mouse_control["icon-x"]) + p_x = text2num(mouse_control["icon-x"]) + if(mouse_control["icon-y"]) + p_y = text2num(mouse_control["icon-y"]) + if(mouse_control["screen-loc"]) + //Split screen-loc up into X+Pixel_X and Y+Pixel_Y + var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",") + + //Split X+Pixel_X up into list(X, Pixel_X) + var/list/screen_loc_X = splittext(screen_loc_params[1],":") + + //Split Y+Pixel_Y up into list(Y, Pixel_Y) + var/list/screen_loc_Y = splittext(screen_loc_params[2],":") + var/x = text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32 + var/y = text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32 + + //Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average. + var/list/screenview = getviewsize(user.client.view) + var/screenviewX = screenview[1] * world.icon_size + var/screenviewY = screenview[2] * world.icon_size + + var/ox = round(screenviewX/2) - user.client.pixel_x //"origin" x + var/oy = round(screenviewY/2) - user.client.pixel_y //"origin" y + angle = Atan2(y - oy, x - ox) + return list(angle, p_x, p_y) + +/obj/item/projectile/proc/Range() + range-- + if(range <= 0 && loc) + on_range() + +/obj/item/projectile/proc/on_range() //if we want there to be effects when they reach the end of their range + on_impact(loc) + qdel(src) + +/obj/item/projectile/proc/store_hitscan_collision(datum/point/pcache) + beam_segments[beam_index] = pcache + beam_index = pcache + beam_segments[beam_index] = null + +/obj/item/projectile/proc/return_predicted_turf_after_moves(moves, forced_angle) //I say predicted because there's no telling that the projectile won't change direction/location in flight. + if(!trajectory && isnull(forced_angle) && isnull(Angle)) + return FALSE + var/datum/point/vector/current = trajectory + if(!current) + var/turf/T = get_turf(src) + current = new(T.x, T.y, T.z, pixel_x, pixel_y, isnull(forced_angle)? Angle : forced_angle, pixel_speed) + var/datum/point/vector/v = current.return_vector_after_increments(moves) + return v.return_turf() + +/obj/item/projectile/proc/return_pathing_turfs_in_moves(moves, forced_angle) + var/turf/current = get_turf(src) + var/turf/ending = return_predicted_turf_after_moves(moves, forced_angle) + return getline(current, ending) + +/obj/item/projectile/proc/process_hitscan() + var/safety = range * 3 + var/return_vector = RETURN_POINT_VECTOR_INCREMENT(src, Angle, MUZZLE_EFFECT_PIXEL_INCREMENT, 1) + record_hitscan_start(return_vector) + while(loc && !QDELETED(src)) + if(paused) + stoplag(1) + continue + if(safety-- <= 0) + qdel(src) + crash_with("WARNING: [type] projectile encountered infinite recursion during hitscanning in [__FILE__]/[__LINE__]!") + return //Kill! + pixel_move(1, 1, TRUE) + +/obj/item/projectile/proc/record_hitscan_start(datum/point/pcache) + beam_segments = list() //initialize segment list with the list for the first segment + beam_index = pcache + beam_segments[beam_index] = null //record start. + +/obj/item/projectile/proc/vol_by_damage() + if(src.damage) + return Clamp((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then CLAMP the value between 30 and 100 + else + return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume. + +/obj/item/projectile/proc/before_z_change(turf/oldloc, turf/newloc) + var/datum/point/pcache = trajectory.copy_to() + if(hitscan) + store_hitscan_collision(pcache) + +/obj/item/projectile/Process() + last_process = world.time + + if(!loc || !fired || !trajectory) + fired = FALSE + return PROCESS_KILL + if(paused || !isturf(loc)) + last_projectile_move += world.time - last_process //Compensates for pausing, so it doesn't become a hitscan projectile when unpaused from charged up ticks. + return + var/elapsed_time_deciseconds = (world.time - last_projectile_move) + time_offset + time_offset = 0 + var/required_moves = 0 + if(speed > 0) + required_moves = Floor(elapsed_time_deciseconds / speed, 1) + if(required_moves > SSprojectiles.global_max_tick_moves) + var/overrun = required_moves - SSprojectiles.global_max_tick_moves + required_moves = SSprojectiles.global_max_tick_moves + time_offset += overrun * speed + time_offset += Modulus(elapsed_time_deciseconds, speed) + else + required_moves = SSprojectiles.global_max_tick_moves + if(!required_moves) + return + for(var/i in 1 to required_moves) + pixel_move(required_moves) + +/obj/item/projectile/proc/setAngle(new_angle) //wrapper for overrides. + Angle = new_angle + if(!nondirectional_sprite) + var/matrix/M = new + M.Turn(Angle) + transform = M + if(trajectory) + trajectory.set_angle(new_angle) + return TRUE + +/obj/item/projectile/forceMove(atom/target) + . = ..() + if(trajectory && !trajectory_ignore_forcemove && isturf(target)) + trajectory.initialize_location(target.x, target.y, target.z, 0, 0) + +/obj/item/projectile/Destroy() + if(hitscan) + if(loc && trajectory) + var/datum/point/pcache = trajectory.copy_to() + beam_segments[beam_index] = pcache + generate_hitscan_tracers() + STOP_PROCESSING(SSprojectiles, src) + return ..() + +/obj/item/projectile/proc/generate_hitscan_tracers(cleanup = TRUE, duration = 10) + if(!length(beam_segments)) + return + if(duration <= 0) + return + if(tracer_type) + for(var/datum/point/p in beam_segments) + generate_tracer_between_points(p, beam_segments[p], tracer_type, color, duration) + if(muzzle_type && !silenced) + var/datum/point/p = beam_segments[1] + var/atom/movable/thing = new muzzle_type + p.move_atom_to_src(thing) + var/matrix/M = new + M.Turn(original_angle) + thing.transform = M + spawn(duration) + qdel(thing) + if(impact_type) + var/datum/point/p = beam_segments[beam_segments[beam_segments.len]] + var/atom/movable/thing = new impact_type + p.move_atom_to_src(thing) + var/matrix/M = new + M.Turn(Angle) + thing.transform = M + spawn(duration) + qdel(thing) + if(cleanup) + for(var/i in beam_segments) + qdel(i) + beam_segments = null + QDEL_NULL(beam_index) \ No newline at end of file diff --git a/code/modules/projectiles/targeting/targeting_client.dm b/code/modules/projectiles/targeting/targeting_client.dm new file mode 100644 index 00000000..eeaf6190 --- /dev/null +++ b/code/modules/projectiles/targeting/targeting_client.dm @@ -0,0 +1,12 @@ +//These are called by the on-screen buttons, adjusting what the victim can and cannot do. +/client/proc/add_gun_icons() + if(!usr || !usr.item_use_icon) return 1 // This can runtime if someone manages to throw a gun out of their hand before the proc is called. + screen |= usr.item_use_icon + screen |= usr.gun_move_icon + screen |= usr.radio_use_icon + +/client/proc/remove_gun_icons() + if(!usr) return 1 // Runtime prevention on N00k agents spawning with SMG + screen -= usr.item_use_icon + screen -= usr.gun_move_icon + screen -= usr.radio_use_icon diff --git a/code/modules/projectiles/targeting/targeting_gun.dm b/code/modules/projectiles/targeting/targeting_gun.dm new file mode 100644 index 00000000..e2ef4662 --- /dev/null +++ b/code/modules/projectiles/targeting/targeting_gun.dm @@ -0,0 +1,21 @@ +//Removing the lock and the buttons. +/obj/item/weapon/gun/dropped(var/mob/living/user) + if(istype(user)) + user.stop_aiming(src) + return ..() + +/obj/item/weapon/gun/equipped(var/mob/living/user, var/slot) + if(istype(user) && (slot != slot_l_hand && slot != slot_r_hand)) + user.stop_aiming(src) + return ..() + +//Compute how to fire..... +//Return 1 if a target was found, 0 otherwise. +/obj/item/weapon/gun/proc/PreFire(var/atom/A, var/mob/living/user, var/params) + if(!user.aiming) + user.aiming = new(user) + user.face_atom(A) + if(ismob(A) && user.aiming) + user.aiming.aim_at(A, src) + return 1 + return 0 \ No newline at end of file diff --git a/code/modules/projectiles/targeting/targeting_mob.dm b/code/modules/projectiles/targeting/targeting_mob.dm new file mode 100644 index 00000000..10e3b07a --- /dev/null +++ b/code/modules/projectiles/targeting/targeting_mob.dm @@ -0,0 +1,45 @@ +/mob/living/var/obj/aiming_overlay/aiming +/mob/living/var/list/aimed = list() + +/*/mob/verb/toggle_gun_mode() + set name = "Toggle Gun Mode" + set desc = "Begin or stop aiming." + set category = "IC" + + if(isliving(src)) //Needs to be a mob verb to prevent error messages when using hotkeys + var/mob/living/M = src + if(!M.aiming) + M.aiming = new(src) + M.aiming.toggle_active() + else + to_chat(src, "This verb may only be used by living mobs, sorry.") + return +*/ +/mob/living/proc/stop_aiming(var/obj/item/thing, var/no_message = 0) + if(!aiming) + aiming = new(src) + if(thing && aiming.aiming_with != thing) + return + aiming.cancel_aiming(no_message) + +/mob/living/death(gibbed, deathmessage="seizes up and falls limp...", show_dead_message) + . = ..(gibbed, deathmessage, show_dead_message) + if(.) + stop_aiming(no_message=1) + +/mob/living/update_canmove() + ..() + if(lying) + stop_aiming(no_message=1) + +/mob/living/Weaken(amount) + stop_aiming(no_message=1) + ..() + +/mob/living/Destroy() + if(aiming) + qdel(aiming) + aiming = null + aimed.Cut() + return ..() + diff --git a/code/modules/projectiles/targeting/targeting_overlay.dm b/code/modules/projectiles/targeting/targeting_overlay.dm new file mode 100644 index 00000000..2ccc294b --- /dev/null +++ b/code/modules/projectiles/targeting/targeting_overlay.dm @@ -0,0 +1,228 @@ +/obj/aiming_overlay + name = "" + desc = "Stick 'em up!" + icon = 'icons/effects/Targeted.dmi' + icon_state = "locking" + anchored = 1 + density = 0 + opacity = 0 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + simulated = 0 + mouse_opacity = 0 + + var/mob/living/aiming_at // Who are we currently targeting, if anyone? + var/obj/item/aiming_with // What are we targeting with? + var/mob/living/owner // Who do we belong to? + var/locked = 0 // Have we locked on? + var/lock_time = 0 // When -will- we lock on? + var/active = 0 // Is our owner intending to take hostages? + var/target_permissions = TARGET_CAN_RADIO // Permission bitflags. + +/obj/aiming_overlay/New(var/newowner) + ..() + owner = newowner + loc = null + verbs.Cut() + +/obj/aiming_overlay/proc/toggle_permission(var/perm) + + if(target_permissions & perm) + target_permissions &= ~perm + else + target_permissions |= perm + + // Update HUD icons. + if(owner.gun_move_icon) + if(!(target_permissions & TARGET_CAN_MOVE)) + owner.gun_move_icon.icon_state = "no_walk0" + owner.gun_move_icon.SetName("Allow Movement") + else + owner.gun_move_icon.icon_state = "no_walk1" + owner.gun_move_icon.SetName("Disallow Movement") + + if(owner.item_use_icon) + if(!(target_permissions & TARGET_CAN_CLICK)) + owner.item_use_icon.icon_state = "no_item0" + owner.item_use_icon.SetName("Allow Item Use") + else + owner.item_use_icon.icon_state = "no_item1" + owner.item_use_icon.SetName("Disallow Item Use") + + if(owner.radio_use_icon) + if(!(target_permissions & TARGET_CAN_RADIO)) + owner.radio_use_icon.icon_state = "no_radio0" + owner.radio_use_icon.SetName("Allow Radio Use") + else + owner.radio_use_icon.icon_state = "no_radio1" + owner.radio_use_icon.SetName("Disallow Radio Use") + + var/message = "no longer permitted to " + var/use_span = "warning" + if(target_permissions & perm) + message = "now permitted to " + use_span = "notice" + + switch(perm) + if(TARGET_CAN_MOVE) + message += "move" + if(TARGET_CAN_CLICK) + message += "use items" + if(TARGET_CAN_RADIO) + message += "use a radio" + else + return + + var/aim_message = "[aiming_at ? "\The [aiming_at] is" : "Your targets are"] [message]." + to_chat(owner, aim_message) + if(aiming_at) + to_chat(aiming_at, "You are [message].") +/obj/aiming_overlay/Process() + if(!owner) + qdel(src) + return + ..() + update_aiming() + +/obj/aiming_overlay/Destroy() + cancel_aiming(1) + owner = null + return ..() + +obj/aiming_overlay/proc/update_aiming_deferred() + set waitfor = 0 + sleep(0) + update_aiming() + +/obj/aiming_overlay/proc/update_aiming() + + if(!owner) + qdel(src) + return + + if(!aiming_at) + cancel_aiming() + return + + if(!locked && lock_time >= world.time) + locked = 1 + update_icon() + + var/cancel_aim = 1 + + if(!(aiming_with in owner) || (istype(owner, /mob/living/carbon/human) && (owner.l_hand != aiming_with && owner.r_hand != aiming_with))) + to_chat(owner, "You must keep hold of your weapon!") + else if(owner.eye_blind) + to_chat(owner, "You are blind and cannot see your target!") + else if(!aiming_at || !istype(aiming_at.loc, /turf)) + to_chat(owner, "You have lost sight of your target!") + else if(owner.incapacitated() || owner.lying || owner.restrained()) + to_chat(owner, "You must be conscious and standing to keep track of your target!") + else if(aiming_at.is_invisible_to(owner)) + to_chat(owner, "Your target has become invisible!") + else if(!(aiming_at in view(owner))) + to_chat(owner, "Your target is too far away to track!") + else + cancel_aim = 0 + + forceMove(get_turf(aiming_at)) + + if(cancel_aim) + cancel_aiming() + return + + if(!owner.incapacitated() && owner.client) + spawn(0) + owner.set_dir(get_dir(get_turf(owner), get_turf(src))) + +/obj/aiming_overlay/proc/aim_at(var/mob/target, var/obj/thing) + + if(!owner) + return + + if(owner.incapacitated()) + to_chat(owner, "You cannot aim a gun in your current state.") + return + if(owner.lying) + to_chat(owner, "You cannot aim a gun while prone.") + return + if(owner.restrained()) + to_chat(owner, "You cannot aim a gun while handcuffed.") + return + + if(aiming_at) + if(aiming_at == target) + return + cancel_aiming(1) + owner.visible_message("\The [owner] turns \the [thing] on \the [target]!") + else + owner.visible_message("\The [owner] aims \the [thing] at \the [target]!") + + if(owner.client) + owner.client.add_gun_icons() + to_chat(target, "You now have a gun pointed at you. No sudden moves!") + aiming_with = thing + aiming_at = target + if(istype(aiming_with, /obj/item/weapon/gun)) + playsound(get_turf(owner), 'sound/weapons/TargetOn.ogg', 50,1) + + forceMove(get_turf(target)) + START_PROCESSING(SSobj, src) + + aiming_at.aimed |= src + toggle_active(1) + locked = 0 + update_icon() + lock_time = world.time + 35 + GLOB.moved_event.register(owner, src, /obj/aiming_overlay/proc/update_aiming) + GLOB.moved_event.register(aiming_at, src, /obj/aiming_overlay/proc/target_moved) + GLOB.destroyed_event.register(aiming_at, src, /obj/aiming_overlay/proc/cancel_aiming) + +/obj/aiming_overlay/update_icon() + if(locked) + icon_state = "locked" + else + icon_state = "locking" + +/obj/aiming_overlay/proc/toggle_active(var/force_state = null) + if(!isnull(force_state)) + if(active == force_state) + return + active = force_state + else + active = !active + + if(!active) + cancel_aiming() + + if(owner.client) + if(active) + to_chat(owner, "You will now aim rather than fire.") + owner.client.add_gun_icons() + else + to_chat(owner, "You will no longer aim rather than fire.") + owner.client.remove_gun_icons() + owner.gun_setting_icon.icon_state = "gun[active]" + +/obj/aiming_overlay/proc/cancel_aiming(var/no_message = 0) + if(!aiming_with || !aiming_at) + return + if(istype(aiming_with, /obj/item/weapon/gun)) + playsound(get_turf(owner), 'sound/weapons/TargetOff.ogg', 50,1) + if(!no_message) + owner.visible_message("\The [owner] lowers \the [aiming_with].") + + GLOB.moved_event.unregister(owner, src) + if(aiming_at) + GLOB.moved_event.unregister(aiming_at, src) + GLOB.destroyed_event.unregister(aiming_at, src) + aiming_at.aimed -= src + aiming_at = null + + aiming_with = null + loc = null + STOP_PROCESSING(SSobj, src) + +/obj/aiming_overlay/proc/target_moved() + update_aiming() + //trigger(TARGET_CAN_MOVE) diff --git a/code/modules/projectiles/targeting/targeting_triggers.dm b/code/modules/projectiles/targeting/targeting_triggers.dm new file mode 100644 index 00000000..4da15d0b --- /dev/null +++ b/code/modules/projectiles/targeting/targeting_triggers.dm @@ -0,0 +1,29 @@ +//as core click exists at the mob level +/mob/proc/trigger_aiming(var/trigger_type) + return + +/mob/living/trigger_aiming(var/trigger_type) + if(!aimed.len) + return + for(var/obj/aiming_overlay/AO in aimed) + if(AO.aiming_at == src) + AO.update_aiming() + if(AO.aiming_at == src) + AO.trigger(trigger_type) + AO.update_aiming_deferred() + +/obj/aiming_overlay/proc/trigger(var/perm) + if(!owner || !aiming_with || !aiming_at || !locked) + return + if(perm && (target_permissions & perm)) + return + if(!owner.canClick()) + return + owner.setClickCooldown(DEFAULT_QUICK_COOLDOWN) // Spam prevention, essentially. + if(owner.a_intent == I_HELP) + to_chat(owner, "You refrain from firing \the [aiming_with] as your intent is set to help.") + return + owner.visible_message("\The [owner] pulls the trigger reflexively!") + var/obj/item/weapon/gun/G = aiming_with + if(istype(G)) + G.Fire(aiming_at, owner) diff --git a/code/modules/prometheus_metrics/_defines.dm b/code/modules/prometheus_metrics/_defines.dm new file mode 100644 index 00000000..f810234d --- /dev/null +++ b/code/modules/prometheus_metrics/_defines.dm @@ -0,0 +1,5 @@ +#define PROMETHEUS_METRIC_COUNTER 0 +#define PROMETHEUS_METRIC_GAUGE 1 + +GLOBAL_LIST_INIT(prometheus_metric_names, list("counter", "gauge")) +#define PROMETHEUS_METRIC_NAME(m) GLOB.prometheus_metric_names[m + 1] diff --git a/code/modules/prometheus_metrics/metric_family.dm b/code/modules/prometheus_metrics/metric_family.dm new file mode 100644 index 00000000..373130e2 --- /dev/null +++ b/code/modules/prometheus_metrics/metric_family.dm @@ -0,0 +1,44 @@ +// Datum used for gathering a set of prometheus metrics. +/datum/metric_family + var/name = null + var/metric_type = null + var/help = null + +// Collect should return a list of lists with two entries, one being a list and the other being a number. +/datum/metric_family/proc/collect() + var/list/out = list() + + out[++out.len] = list(list("foo" = "bar"), 3.14) + out[++out.len] = list(list("abc" = "def"), 1.23) + + return out + +// _to_proto will call the collect() method and format its result in a list +// suitable for encoding as a JSON protobuf mapping. +/datum/metric_family/proc/_to_proto() + var/list/collected = collect() + + var/list/out = list( + "name" = name, + "type" = metric_type, + ) + + if(help != null) + out["help"] = help + + var/list/metrics = list() + for(var/list/m in collected) + if(m.len != 2) + continue + + var/list/label_pairs = list() + for(var/k in m[1]) + label_pairs[++label_pairs.len] = list("name" = k, "value" = m[1][k]) + + metrics[++metrics.len] = list("label" = label_pairs, PROMETHEUS_METRIC_NAME(metric_type) = list("value" = m[2])) + + if(metrics.len == 0) + return null + out["metric"] = metrics + + return out diff --git a/code/modules/prometheus_metrics/metrics.dm b/code/modules/prometheus_metrics/metrics.dm new file mode 100644 index 00000000..a1e8b44d --- /dev/null +++ b/code/modules/prometheus_metrics/metrics.dm @@ -0,0 +1,24 @@ +GLOBAL_DATUM_INIT(prometheus_metrics, /datum/prometheus_metrics, new) + +// prometheus_metrics holds a list of metric_family datums and uses them to +// create a json protobuf. +/datum/prometheus_metrics + var/list/metric_families + +/datum/prometheus_metrics/New() + metric_families = list() + for(var/T in typesof(/datum/metric_family) - /datum/metric_family) + var/datum/metric_family/mf = T + if(initial(mf.name) == null || initial(mf.metric_type) == null) + continue + metric_families += new T + +/datum/prometheus_metrics/proc/collect() + var/list/out = list() + + for(var/datum/metric_family/MF in metric_families) + var/proto = MF._to_proto() + if(proto != null) + out[++out.len] = MF._to_proto() + + return json_encode(out) diff --git a/code/modules/prometheus_metrics/metrics/byond.dm b/code/modules/prometheus_metrics/metrics/byond.dm new file mode 100644 index 00000000..232bce38 --- /dev/null +++ b/code/modules/prometheus_metrics/metrics/byond.dm @@ -0,0 +1,40 @@ +// byond-specific metrics + +/datum/metric_family/byond_time + name = "byond_world_time_seconds" + metric_type = PROMETHEUS_METRIC_COUNTER + help = "Counter of 'game-time' seconds since server startup" + +/datum/metric_family/byond_time/collect() + return list(list(null, world.time / 10)) + + +/datum/metric_family/byond_tick_lag + name = "byond_tick_lag" + metric_type = PROMETHEUS_METRIC_GAUGE + help = "Current value of world.tick_lag" + +/datum/metric_family/byond_tick_lag/collect() + return list(list(null, world.tick_lag)) + + +/datum/metric_family/byond_players + name = "byond_players" + metric_type = PROMETHEUS_METRIC_GAUGE + help = "Number of players currently connected to the server" + +/datum/metric_family/byond_players/collect() + var/c = 0 + for(var/client/C) + if(C.connection == "seeker" || C.connection == "web") + c++ + return list(list(null, c)) + + +/datum/metric_family/byond_cpu + name = "byond_cpu" + metric_type = PROMETHEUS_METRIC_GAUGE + help = "Current value of world.cpu" + +/datum/metric_family/byond_cpu/collect() + return list(list(null, world.cpu)) diff --git a/code/modules/prometheus_metrics/metrics/ss13.dm b/code/modules/prometheus_metrics/metrics/ss13.dm new file mode 100644 index 00000000..642703c4 --- /dev/null +++ b/code/modules/prometheus_metrics/metrics/ss13.dm @@ -0,0 +1,30 @@ +// ss13-specific metrics + +/datum/metric_family/ss13_controller_time_seconds + name = "ss13_controller_time_seconds" + metric_type = PROMETHEUS_METRIC_COUNTER + help = "Counter of time spent in a controller in seconds" + +/datum/metric_family/ss13_controller_time_seconds/collect() + var/list/out = list() + + if(processScheduler) + for(var/datum/controller/process/P in processScheduler.processes) + out[++out.len] = list(list("type" = "process", "name" = P.name), P.getTotalRunTime() / 10) + + if(Master) + for(var/name in Master.total_run_times) + out[++out.len] = list(list("type" = "subsystem", "name" = name), Master.total_run_times[name]) + + return out + + +/datum/metric_family/ss13_master_runlevel + name = "ss13_master_runlevel" + metric_type = PROMETHEUS_METRIC_GAUGE + help = "Current MC runlevel" + +/datum/metric_family/ss13_master_runlevel/collect() + if(Master) + return list(list(null, Master.current_runlevel)) + return list() diff --git a/code/modules/random_map/_random_map_setup.dm b/code/modules/random_map/_random_map_setup.dm new file mode 100644 index 00000000..e89f0cd0 --- /dev/null +++ b/code/modules/random_map/_random_map_setup.dm @@ -0,0 +1,32 @@ +/* + This module is used to generate the debris fields/distribution maps/procedural stations. +*/ + +#define MIN_SURFACE_COUNT_PER_CHUNK 0.1 +#define MIN_RARE_COUNT_PER_CHUNK 0.05 +#define MIN_DEEP_COUNT_PER_CHUNK 0.025 +#define RESOURCE_HIGH_MAX 4 +#define RESOURCE_HIGH_MIN 2 +#define RESOURCE_MID_MAX 3 +#define RESOURCE_MID_MIN 1 +#define RESOURCE_LOW_MAX 1 +#define RESOURCE_LOW_MIN 0 + +#define FLOOR_CHAR 0 +#define WALL_CHAR 1 +#define DOOR_CHAR 2 +#define EMPTY_CHAR 3 +#define ROOM_TEMP_CHAR 4 +#define MONSTER_CHAR 5 +#define ARTIFACT_TURF_CHAR 6 +#define ARTIFACT_CHAR 7 +#define CORRIDOR_TURF_CHAR 8 + +#define TRANSLATE_COORD(X,Y) ((((Y) - 1) * limit_x) + (X)) +#define TRANSLATE_AND_VERIFY_COORD(X,Y) TRANSLATE_AND_VERIFY_COORD_MLEN(X,Y,map.len) + +#define TRANSLATE_AND_VERIFY_COORD_MLEN(X,Y,LEN) \ + tmp_cell = TRANSLATE_COORD(X,Y);\ + if (tmp_cell < 1 || tmp_cell > LEN) {\ + tmp_cell = null;\ + } \ No newline at end of file diff --git a/code/modules/random_map/automata/automata.dm b/code/modules/random_map/automata/automata.dm new file mode 100644 index 00000000..544b625a --- /dev/null +++ b/code/modules/random_map/automata/automata.dm @@ -0,0 +1,71 @@ +#define CELL_ALIVE(VAL) (VAL == cell_live_value) +#define KILL_CELL(CELL, NEXT_MAP) NEXT_MAP[CELL] = cell_dead_value; +#define REVIVE_CELL(CELL, NEXT_MAP) NEXT_MAP[CELL] = cell_live_value; + +/datum/random_map/automata + descriptor = "generic caves" + initial_wall_cell = 55 + var/iterations = 0 // Number of times to apply the automata rule. + var/cell_live_value = WALL_CHAR // Cell is alive if it has this value. + var/cell_dead_value = FLOOR_CHAR // As above for death. + var/cell_threshold = 5 // Cell becomes alive with this many live neighbors. + +// Automata-specific procs and processing. +/datum/random_map/automata/generate_map() + for(var/iter = 1 to iterations) + var/list/next_map[limit_x*limit_y] + var/count + var/is_not_border_left + var/is_not_border_right + var/ilim_u + var/ilim_d + var/bottom_lim = ((limit_y - 1) * limit_x) + + if (!islist(map)) + set_map_size() + + for (var/i in 1 to (limit_x * limit_y)) + count = 0 + + is_not_border_left = i != 1 && ((i - 1) % limit_x) + is_not_border_right = i % limit_x + + if (CELL_ALIVE(map[i])) // Center row. + ++count + if (is_not_border_left && CELL_ALIVE(map[i - 1])) + ++count + if (is_not_border_right && CELL_ALIVE(map[i + 1])) + ++count + + if (i > limit_x) // top row + ilim_u = i - limit_x + if (CELL_ALIVE(map[ilim_u])) + ++count + if (is_not_border_left && CELL_ALIVE(map[ilim_u - 1])) + ++count + if (is_not_border_right && CELL_ALIVE(map[ilim_u + 1])) + ++count + + if (i <= bottom_lim) // bottom row + ilim_d = i + limit_x + if (CELL_ALIVE(map[ilim_d])) + ++count + if (is_not_border_left && CELL_ALIVE(map[ilim_d - 1])) + ++count + if (is_not_border_right && CELL_ALIVE(map[ilim_d + 1])) + ++count + + if(count >= cell_threshold) + REVIVE_CELL(i, next_map) + else // Nope. Can't be alive. Kill it. + KILL_CELL(i, next_map) + + CHECK_TICK + + map = next_map + +/datum/random_map/automata/get_additional_spawns(value, turf/T) + return + +#undef KILL_CELL +#undef REVIVE_CELL \ No newline at end of file diff --git a/code/modules/random_map/automata/caves.dm b/code/modules/random_map/automata/caves.dm new file mode 100644 index 00000000..872d6d67 --- /dev/null +++ b/code/modules/random_map/automata/caves.dm @@ -0,0 +1,104 @@ +/datum/random_map/automata/cave_system + iterations = 5 + descriptor = "caves" + wall_type = /turf/simulated/mineral + floor_type = /turf/simulated/floor/dirty/indestructable/lightless ///turf/simulated/floor/dirty/indestructable + target_turf_type = /turf/unsimulated/mask + var/mineral_sparse = /turf/simulated/mineral/random + var/mineral_rich = /turf/simulated/mineral/random/high_chance + var/list/ore_turfs = list() + +/datum/random_map/automata/cave_system/get_appropriate_path(var/value) + switch(value) + if(DOOR_CHAR) + return mineral_sparse + if(EMPTY_CHAR) + return mineral_rich + if(FLOOR_CHAR) + return floor_type + if(WALL_CHAR) + return wall_type + +/datum/random_map/automata/cave_system/get_map_char(var/value) + switch(value) + if(DOOR_CHAR) + return "x" + if(EMPTY_CHAR) + return "X" + return ..(value) + +// Create ore turfs. +/datum/random_map/automata/cave_system/cleanup() + var/tmp_cell + for (var/x = 1 to limit_x) + for (var/y = 1 to limit_y) + tmp_cell = TRANSLATE_COORD(x, y) + if (CELL_ALIVE(map[tmp_cell])) + ore_turfs += tmp_cell + + game_log("ASGEN", "Found [ore_turfs.len] ore turfs.") + var/ore_count = round(map.len/20) + var/door_count = 0 + var/empty_count = 0 + while((ore_count>0) && (ore_turfs.len>0)) + + if(!priority_process) + CHECK_TICK + + var/check_cell = pick(ore_turfs) + ore_turfs -= check_cell + if(prob(75)) + map[check_cell] = DOOR_CHAR // Mineral block + door_count += 1 + else + map[check_cell] = EMPTY_CHAR // Rare mineral block. + empty_count += 1 + ore_count-- + + game_log("ASGEN", "Set [door_count] turfs to random minerals.") + game_log("ASGEN", "Set [empty_count] turfs to high-chance random minerals.") + return 1 + +/datum/random_map/automata/cave_system/apply_to_map() + if(!origin_x) origin_x = 1 + if(!origin_y) origin_y = 1 + if(!origin_z) origin_z = 1 + + var/tmp_cell + var/new_path + var/num_applied = 0 + for (var/thing in block(locate(origin_x, origin_y, origin_z), locate(limit_x, limit_y, origin_z))) + var/turf/T = thing + new_path = null + if (!T || (target_turf_type && !istype(T, target_turf_type))) + continue + + tmp_cell = TRANSLATE_COORD(T.x, T.y) + + switch (map[tmp_cell]) + if(DOOR_CHAR) + new_path = mineral_sparse + if(EMPTY_CHAR) + new_path = mineral_rich + if(FLOOR_CHAR) + /* + if(origin_z != 1) + if(prob(10)) + new_path = /turf/simulated/open + else + new_path = floor_type + else + */ + new_path = floor_type + if(WALL_CHAR) + new_path = wall_type + + if (!new_path) + continue + + num_applied += 1 + T.ChangeTurf(new_path) + + CHECK_TICK + + game_log("ASGEN", "Applied [num_applied] turfs.") \ No newline at end of file diff --git a/code/modules/random_map/automata/diona.dm b/code/modules/random_map/automata/diona.dm new file mode 100644 index 00000000..0a4ea644 --- /dev/null +++ b/code/modules/random_map/automata/diona.dm @@ -0,0 +1,173 @@ +/turf/simulated/wall/diona/New(var/newloc) + ..(newloc,"biomass") + +/turf/simulated/wall/diona/attack_generic(var/mob/user, var/damage, var/attack_message) + if(istype(user, /mob/living/carbon/alien/diona)) + if(can_open == WALL_OPENING) + return + can_open = WALL_CAN_OPEN + user.visible_message("\The [user] strokes its feelers against \the [src] and the biomass [density ? "moves aside" : "closes up"].") + toggle_open(user) + sleep(15) + if(can_open == WALL_CAN_OPEN) can_open = 0 + else + return ..(user, damage, attack_message) + +/obj/structure/diona + icon = 'icons/obj/diona.dmi' + anchored = 1 + density = 1 + opacity = 0 + plane = ABOVE_TURF_PLANE + layer = PLANT_LAYER + +/obj/structure/diona/vines + name = "alien vines" + desc = "Thick, heavy vines of some sort." + icon_state = "vines3" + var/growth = 0 + +/obj/structure/diona/vines/proc/spread() + var/turf/origin = get_turf(src) + for(var/turf/T in range(src,2)) + if(T.density || T == origin || istype(T, /turf/space)) + continue + var/new_growth = 1 + switch(get_dist(origin,T)) + if(0) + new_growth = 3 + if(1) + new_growth = 2 + var/obj/structure/diona/vines/existing = locate() in T + if(!istype(existing)) existing = PoolOrNew(/obj/structure/diona/vines, T) + if(existing.growth < new_growth) + existing.growth = new_growth + existing.update_icon() + +/obj/structure/diona/vines/update_icon() + icon_state = "vines[growth]" + +/obj/structure/diona/bulb + name = "glow bulb" + desc = "A glowing bulb of some sort." + icon_state = "glowbulb" + +/obj/structure/diona/bulb/New(var/newloc) + ..() + set_light(3,3,"#557733") + +/datum/random_map/automata/diona + iterations = 3 + descriptor = "diona gestalt" + limit_x = 32 + limit_y = 32 + + wall_type = /turf/simulated/wall/diona + floor_type = /turf/simulated/floor/diona + +// This is disgusting. +/datum/random_map/automata/diona/proc/search_neighbors_for(var/search_val, var/x, var/y) + var/current_cell = get_map_cell(x-1,y-1) + if(current_cell && map[current_cell] == search_val) return 1 + current_cell = get_map_cell(x-1,y) + if(current_cell && map[current_cell] == search_val) return 1 + current_cell = get_map_cell(x-1,y+1) + if(current_cell && map[current_cell] == search_val) return 1 + current_cell = get_map_cell(x,y-1) + if(current_cell && map[current_cell] == search_val) return 1 + current_cell = get_map_cell(x,y+1) + if(current_cell && map[current_cell] == search_val) return 1 + current_cell = get_map_cell(x+1,y-1) + if(current_cell && map[current_cell] == search_val) return 1 + current_cell = get_map_cell(x+1,y) + if(current_cell && map[current_cell] == search_val) return 1 + current_cell = get_map_cell(x+1,y+1) + if(current_cell && map[current_cell] == search_val) return 1 + return 0 + +/datum/random_map/automata/diona/cleanup() + + // Hollow out the interior spaces. + for(var/x = 1, x <= limit_x, x++) + for(var/y = 1, y <= limit_y, y++) + var/current_cell = get_map_cell(x,y) + if(!current_cell) continue + if(map[current_cell] == WALL_CHAR) + if(!search_neighbors_for(FLOOR_CHAR,x,y) && !search_neighbors_for(DOOR_CHAR,x,y) && !(x == 1 || y == 1 || x == limit_x || y == limit_y)) + map[current_cell] = EMPTY_CHAR + + // Prune exposed floor turfs away from the edges. + var/changed = 1 + while(changed) + for(var/x = 1, x <= limit_x, x++) + for(var/y = 1, y <= limit_y, y++) + changed = 0 + var/current_cell = get_map_cell(x,y) + if(!current_cell) continue + if(map[current_cell] == EMPTY_CHAR) + if((search_neighbors_for(FLOOR_CHAR,x,y)) || (x == 1 || y == 1 || x == limit_x || y == limit_y)) + map[current_cell] = FLOOR_CHAR + changed = 1 + + // Count and track the floors. + var/list/floor_turfs = list() + for(var/x = 1, x <= limit_x, x++) + for(var/y = 1, y <= limit_y, y++) + var/current_cell = get_map_cell(x,y) + if(!current_cell) continue + if(map[current_cell] == EMPTY_CHAR) + floor_turfs |= current_cell + + // Add vine decals. + for(var/x = 1, x <= limit_x, x++) + for(var/y = 1, y <= limit_y, y++) + var/current_cell = get_map_cell(x,y) + if(!current_cell || map[current_cell] != EMPTY_CHAR) continue + if(search_neighbors_for(WALL_CHAR,x,y)) + map[current_cell] = DOOR_CHAR + + // Add bulbs and doona nymphs. + if(floor_turfs.len) + var/bulb_count = rand(round(floor_turfs.len/10),round(floor_turfs.len/8)) + while(floor_turfs.len && bulb_count) + var/cell = pick(floor_turfs) + floor_turfs -= cell + map[cell] = ARTIFACT_CHAR + bulb_count-- + if(floor_turfs.len) + var/nymph_count = rand(round(floor_turfs.len/10),round(floor_turfs.len/8)) + while(floor_turfs.len && nymph_count) + var/cell = pick(floor_turfs) + floor_turfs -= cell + map[cell] = MONSTER_CHAR + nymph_count-- + return + +/datum/random_map/automata/diona/get_appropriate_path(var/value) + switch(value) + if(EMPTY_CHAR, DOOR_CHAR, MONSTER_CHAR, ARTIFACT_CHAR) + return floor_type + if(WALL_CHAR) + return wall_type + +/datum/random_map/automata/diona/get_additional_spawns(var/value, var/turf/T) + + if(value != FLOOR_CHAR) + for(var/thing in T) + if(istype(thing, /atom)) + var/atom/A = thing + if(A.simulated) + continue + qdel(thing) + + switch(value) + if(ARTIFACT_CHAR) + PoolOrNew(/obj/structure/diona/bulb,T) + if(MONSTER_CHAR) + spawn_diona_nymph(T) + if(DOOR_CHAR) + var/obj/structure/diona/vines/V = PoolOrNew(/obj/structure/diona/vines,T) + V.growth = 3 + V.update_icon() + spawn(1) + V.spread() \ No newline at end of file diff --git a/code/modules/random_map/building/building.dm b/code/modules/random_map/building/building.dm new file mode 100644 index 00000000..98a157c4 --- /dev/null +++ b/code/modules/random_map/building/building.dm @@ -0,0 +1,55 @@ +/datum/random_map/building + descriptor = "generic room" + limit_x = 7 + limit_y = 7 + +/datum/random_map/building/generate_map() + for(var/x = 1, x <= limit_x, x++) + for(var/y = 1, y <= limit_y, y++) + var/current_cell = get_map_cell(x,y) + if(!current_cell) + continue + if(x == 1 || y == 1 || x == limit_x || y == limit_y) + map[current_cell] = WALL_CHAR + else + map[current_cell] = FLOOR_CHAR + +/datum/random_map/building/handle_post_overlay_on(var/datum/random_map/target_map, var/tx, var/ty) + var/list/possible_doors + for(var/x = 1, x <= limit_x, x++) + for(var/y = 1, y <= limit_y, y++) + var/current_cell = get_map_cell(x,y) + if(!current_cell) + continue + if(!(x == 1 || y == 1 || x == limit_x || y == limit_y)) + continue + if(tx+x > target_map.limit_x) + continue + if(ty+y > target_map.limit_y) + continue + + var/place_door + // #.# ... .## ##. + // #X# #X# .X. .X. == place a door + // ... # # .## ##. + + // (tx+x)-1,(ty+y-1) (tx+x),(ty+y)-1 (tx+x)+1,(ty+y)-1 + // (tx+x)-1,(ty+y) (tx+x),(ty+y) (tx+x)+1,(ty+y) + // (tx+x)-1,(ty+y+1) (tx+x),(ty+y)+1 (tx+x)+1,(ty+y)+1 + + + if(place_door) + possible_doors |= target_map.get_map_cell(tx+x,ty+y) + + if(possible_doors.len) + // Place at least one door. + var/placing_door = pick(possible_doors) + possible_doors -= placing_door + target_map.map[placing_door] = DOOR_CHAR + // Keep placing doors until we get bored or lose interest. + while(possible_doors && !prob(30)) + placing_door = pick(possible_doors) + possible_doors -= placing_door + target_map.map[placing_door] = DOOR_CHAR + + return \ No newline at end of file diff --git a/code/modules/random_map/drop/drop_types.dm b/code/modules/random_map/drop/drop_types.dm new file mode 100644 index 00000000..94510529 --- /dev/null +++ b/code/modules/random_map/drop/drop_types.dm @@ -0,0 +1,195 @@ +var/global/list/datum/supply_drop_loot/supply_drop + +/proc/supply_drop_random_loot_types() + if(!supply_drop) + supply_drop = init_subtypes(/datum/supply_drop_loot) + supply_drop = dd_sortedObjectList(supply_drop) + return supply_drop + +/datum/supply_drop_loot + var/name = "" + var/container = null + var/list/contents = null + +/datum/supply_drop_loot/proc/contents() + return contents + +/datum/supply_drop_loot/proc/drop(turf/T) + var/C = container ? new container(T) : T + for(var/content in contents()) + new content(C) + +/datum/supply_drop_loot/dd_SortValue() + return name + +/datum/supply_drop_loot/supermatter + name = "Supermatter" +/datum/supply_drop_loot/supermatter/New() + ..() + contents = list(/obj/machinery/power/supermatter) + +/datum/supply_drop_loot/lasers + name = "Lasers" + container = /obj/structure/largecrate +/datum/supply_drop_loot/lasers/New() + ..() + contents = list( + /obj/item/weapon/gun/energy/laser, + /obj/item/weapon/gun/energy/laser, + /obj/item/weapon/gun/energy/sniperrifle, + /obj/item/weapon/gun/energy/ionrifle) + +/datum/supply_drop_loot/ballistics + name = "Ballistics" + container = /obj/structure/largecrate +/datum/supply_drop_loot/ballistics/New() + ..() + contents = list( + /obj/item/weapon/gun/projectile/sec, + /obj/item/weapon/gun/projectile/shotgun/doublebarrel, + /obj/item/weapon/gun/projectile/shotgun/pump/combat, + /obj/item/weapon/gun/projectile/automatic/wt550, + /obj/item/weapon/gun/projectile/automatic/z8) + +/datum/supply_drop_loot/ballistics + name = "Ballistics" + container = /obj/structure/largecrate +/datum/supply_drop_loot/ballistics/New() + ..() + contents = list( + /obj/item/weapon/gun/projectile/sec, + /obj/item/weapon/gun/projectile/shotgun/doublebarrel, + /obj/item/weapon/gun/projectile/shotgun/pump/combat, + /obj/item/weapon/gun/projectile/automatic/wt550, + /obj/item/weapon/gun/projectile/automatic/z8) + +/datum/supply_drop_loot/seeds + name = "Seeds" + container = /obj/structure/closet/crate +/datum/supply_drop_loot/seeds/New() + ..() + contents = list( + /obj/item/seeds/chiliseed, + /obj/item/seeds/berryseed, + /obj/item/seeds/cornseed, + /obj/item/seeds/eggplantseed, + /obj/item/seeds/tomatoseed, + /obj/item/seeds/appleseed, + /obj/item/seeds/soyaseed, + /obj/item/seeds/wheatseed, + /obj/item/seeds/carrotseed, + /obj/item/seeds/lemonseed, + /obj/item/seeds/orangeseed, + /obj/item/seeds/grassseed, + /obj/item/seeds/sunflowerseed, + /obj/item/seeds/chantermycelium, + /obj/item/seeds/potatoseed, + /obj/item/seeds/sugarcaneseed) + +/datum/supply_drop_loot/food + name = "Food" + container = /obj/structure/largecrate +/datum/supply_drop_loot/food/New() + ..() + contents = list( + /obj/item/weapon/reagent_containers/food/condiment/flour, + /obj/item/weapon/reagent_containers/food/condiment/flour, + /obj/item/weapon/reagent_containers/food/condiment/flour, + /obj/item/weapon/reagent_containers/food/drinks/milk, + /obj/item/weapon/reagent_containers/food/drinks/milk, + /obj/item/weapon/storage/fancy/egg_box, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + /obj/item/weapon/reagent_containers/food/snacks/meat, + /obj/item/weapon/reagent_containers/food/snacks/meat) + +/datum/supply_drop_loot/armour + name = "Armour" + container = /obj/structure/largecrate +/datum/supply_drop_loot/armour/New() + ..() + contents = list( + /obj/item/clothing/head/helmet/riot, + /obj/item/clothing/suit/armor/riot, + /obj/item/clothing/head/helmet/riot, + /obj/item/clothing/suit/armor/riot, + /obj/item/clothing/head/helmet/riot, + /obj/item/clothing/suit/armor/riot, + /obj/item/clothing/suit/armor/vest, + /obj/item/clothing/suit/armor/vest, + /obj/item/clothing/suit/storage/vest, + /obj/item/clothing/suit/storage/vest, + /obj/item/clothing/suit/armor/laserproof, + /obj/item/clothing/suit/armor/bulletproof) + +/datum/supply_drop_loot/materials + name = "Materials" + container = /obj/structure/largecrate +/datum/supply_drop_loot/materials/New() + ..() + contents = list( + /obj/item/stack/material/steel, + /obj/item/stack/material/steel, + /obj/item/stack/material/steel, + /obj/item/stack/material/glass, + /obj/item/stack/material/glass, + /obj/item/stack/material/wood, + /obj/item/stack/material/plastic, + /obj/item/stack/material/glass/reinforced, + /obj/item/stack/material/plasteel) + +/datum/supply_drop_loot/medical + name = "Medical" + container = /obj/structure/closet/crate/medical +/datum/supply_drop_loot/medical/New() + ..() + contents = list( + /obj/item/weapon/storage/firstaid/regular, + /obj/item/weapon/storage/firstaid/fire, + /obj/item/weapon/storage/firstaid/toxin, + /obj/item/weapon/storage/firstaid/o2, + /obj/item/weapon/storage/firstaid/adv, + /obj/item/weapon/reagent_containers/glass/bottle/antitoxin, + /obj/item/weapon/reagent_containers/glass/bottle/inaprovaline, + /obj/item/weapon/reagent_containers/glass/bottle/stoxin, + /obj/item/weapon/storage/box/syringes, + /obj/item/weapon/storage/box/autoinjectors) + +/datum/supply_drop_loot/power + name = "Power" + container = /obj/structure/largecrate +/datum/supply_drop_loot/power/New() + ..() + contents = list( + /obj/item/stack/material/steel, + /obj/item/stack/material/steel, + /obj/item/stack/material/steel, + /obj/item/stack/material/glass, + /obj/item/stack/material/glass, + /obj/item/stack/material/wood, + /obj/item/stack/material/plastic, + /obj/item/stack/material/glass/reinforced, + /obj/item/stack/material/plasteel) + +/datum/supply_drop_loot/hydroponics + name = "Hydroponics" + container = /obj/structure/largecrate +/datum/supply_drop_loot/hydroponics/New() + ..() + contents = list( + /obj/machinery/portable_atmospherics/hydroponics, + /obj/machinery/portable_atmospherics/hydroponics, + /obj/machinery/portable_atmospherics/hydroponics) + +/datum/supply_drop_loot/power + name = "Power" + container = /obj/structure/largecrate +/datum/supply_drop_loot/power/New() + ..() + contents = list( + /obj/machinery/power/port_gen/pacman, + /obj/machinery/power/port_gen/pacman/super, + /obj/machinery/power/port_gen/pacman/mrs) + +/datum/supply_drop_loot/power/contents() + return list(pick(contents)) diff --git a/code/modules/random_map/drop/droppod.dm b/code/modules/random_map/drop/droppod.dm new file mode 100644 index 00000000..ea6eb41e --- /dev/null +++ b/code/modules/random_map/drop/droppod.dm @@ -0,0 +1,228 @@ +#define SD_FLOOR_TILE 0 +#define SD_WALL_TILE 1 +#define SD_DOOR_TILE 2 +#define SD_EMPTY_TILE 3 +#define SD_SUPPLY_TILE 7 + +/datum/random_map/droppod + descriptor = "drop pod" + initial_wall_cell = 0 + limit_x = 3 + limit_y = 3 + preserve_map = 0 + + wall_type = /turf/simulated/wall/titanium + floor_type = /turf/simulated/floor/reinforced + var/list/supplied_drop_types = list() + var/door_type = /obj/structure/droppod_door + var/drop_type = /mob/living/simple_animal/parrot + var/auto_open_doors + + var/placement_explosion_dev = 1 + var/placement_explosion_heavy = 2 + var/placement_explosion_light = 6 + var/placement_explosion_flash = 4 + +/datum/random_map/droppod/New(var/seed, var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/supplied_drop, var/list/supplied_drops, var/automated) + + if(supplied_drop) + drop_type = supplied_drop + else if(islist(supplied_drops) && supplied_drops.len) + supplied_drop_types = supplied_drops + drop_type = "custom" + if(automated) + auto_open_doors = 1 + + //Make sure there is a clear midpoint. + if(limit_x % 2 == 0) limit_x++ + if(limit_y % 2 == 0) limit_y++ + ..() + +/datum/random_map/droppod/generate_map() + + // No point calculating these 200 times. + var/x_midpoint = n_ceil(limit_x / 2) + var/y_midpoint = n_ceil(limit_y / 2) + + // Draw walls/floors/doors. + for(var/x = 1, x <= limit_x, x++) + for(var/y = 1, y <= limit_y, y++) + var/current_cell = get_map_cell(x,y) + if(!current_cell) + continue + + var/on_x_bound = (x == 1 || x == limit_x) + var/on_y_bound = (y == 1 || y == limit_x) + var/draw_corners = (limit_x < 5 && limit_y < 5) + if(on_x_bound || on_y_bound) + // Draw access points in midpoint of each wall. + if(x == x_midpoint || y == y_midpoint) + map[current_cell] = SD_DOOR_TILE + // Draw the actual walls. + else if(draw_corners || (!on_x_bound || !on_y_bound)) + map[current_cell] = SD_WALL_TILE + //Don't draw the far corners on large pods. + else + map[current_cell] = SD_EMPTY_TILE + else + // Fill in the corners. + if((x == 2 || x == (limit_x-1)) && (y == 2 || y == (limit_y-1))) + map[current_cell] = SD_WALL_TILE + // Fill in EVERYTHING ELSE. + else + map[current_cell] = SD_FLOOR_TILE + + // Draw the drop contents. + var/current_cell = get_map_cell(x_midpoint,y_midpoint) + if(current_cell) + map[current_cell] = SD_SUPPLY_TILE + return 1 + +/datum/random_map/droppod/apply_to_map() + if(placement_explosion_dev || placement_explosion_heavy || placement_explosion_light || placement_explosion_flash) + var/turf/T = locate((origin_x + n_ceil(limit_x / 2)-1), (origin_y + n_ceil(limit_y / 2)-1), origin_z) + if(istype(T)) + explosion(T, placement_explosion_dev, placement_explosion_heavy, placement_explosion_light, placement_explosion_flash) + sleep(15) // Let the explosion finish proccing before we ChangeTurf(), otherwise it might destroy our spawned objects. + return ..() + +/datum/random_map/droppod/get_appropriate_path(var/value) + if(value == SD_FLOOR_TILE || value == SD_SUPPLY_TILE) + return floor_type + else if(value == SD_WALL_TILE) + return wall_type + else if(value == SD_DOOR_TILE ) + return wall_type + return null + +// Pods are circular. Get the direction this object is facing from the center of the pod. +/datum/random_map/droppod/get_spawn_dir(var/x, var/y) + var/x_midpoint = n_ceil(limit_x / 2) + var/y_midpoint = n_ceil(limit_y / 2) + if(x == x_midpoint && y == y_midpoint) + return null + var/turf/target = locate(origin_x+x-1, origin_y+y-1, origin_z) + var/turf/middle = locate(origin_x+x_midpoint-1, origin_y+y_midpoint-1, origin_z) + if(!istype(target) || !istype(middle)) + return null + return get_dir(middle, target) + +/datum/random_map/droppod/get_additional_spawns(var/value, var/turf/T, var/spawn_dir) + + // Splatter anything under us that survived the explosion. + if(value != SD_EMPTY_TILE && T.contents.len) + for(var/atom/movable/AM in T) + if(AM.simulated && !isobserver(AM)) + qdel(AM) + + // Also spawn doors and loot. + if(value == SD_DOOR_TILE) + var/obj/structure/S = new door_type(T, auto_open_doors) + S.set_dir(spawn_dir) + + else if(value == SD_SUPPLY_TILE) + get_spawned_drop(T) + +/datum/random_map/droppod/proc/get_spawned_drop(var/turf/T) + var/obj/structure/bed/chair/C = new(T) + C.set_light(3, l_color = "#cc0000") + var/mob/living/drop + // This proc expects a list of mobs to be passed to the spawner. + // Use the supply pod if you don't want to drop mobs. + // Mobs will not double up; if you want multiple mobs, you + // will need multiple drop tiles. + if(islist(supplied_drop_types) && supplied_drop_types.len) + while(supplied_drop_types.len) + drop = pick(supplied_drop_types) + supplied_drop_types -= drop + if(istype(drop)) + drop.tag = null + if(drop.buckled) + drop.buckled = null + drop.forceMove(T) + else if(ispath(drop_type)) + drop = new drop_type(T) + if(istype(drop)) + if(drop.buckled) + drop.buckled = null + drop.forceMove(T) + +/datum/admins/proc/call_drop_pod() + set category = "Fun" + set desc = "Call an immediate drop pod on your location." + set name = "Call Drop Pod" + + if(!check_rights(R_FUN)) return + + var/client/selected_player + var/mob/living/spawned_mob + var/list/spawned_mobs = list() + + var/spawn_path = input("Select a mob type.", "Drop Pod Selection", null) as null|anything in typesof(/mob/living)-/mob/living + if(!spawn_path) + return + + if(alert("Do you wish the mob to have a player?",,"No","Yes") == "No") + var/spawn_count = input("How many mobs do you wish the pod to contain?", "Drop Pod Selection", null) as num + if(spawn_count <= 0) + return + for(var/i=0;iYou prime the explosive bolts. Better get clear!") + sleep(30) + deploy() + +/obj/structure/droppod_door/proc/deploy() + if(deployed) + return + + deployed = 1 + visible_message("The explosive bolts on \the [src] detonate, throwing it open!") + playsound(src.loc, 'sound/effects/bang.ogg', 50, 1, 5) + + // This is shit but it will do for the sake of testing. + for(var/obj/structure/droppod_door/D in orange(1,src)) + if(D.deployed) + continue + D.deploy() + + // Overwrite turfs. + var/turf/origin = get_turf(src) + origin.ChangeTurf(/turf/simulated/floor/reinforced) + origin.set_light(0) // Forcing updates + var/turf/T = get_step(origin, src.dir) + T.ChangeTurf(/turf/simulated/floor/reinforced) + T.set_light(0) // Forcing updates + + // Destroy turf contents. + for(var/obj/O in origin) + if(!O.simulated) + continue + qdel(O) //crunch + for(var/obj/O in T) + if(!O.simulated) + continue + qdel(O) //crunch + + // Hurl the mobs away. + for(var/mob/living/M in T) + M.throw_at(get_edge_target_turf(T,src.dir),rand(0,3),50) + for(var/mob/living/M in origin) + M.throw_at(get_edge_target_turf(origin,src.dir),rand(0,3),50) + + // Create a decorative ramp bottom and flatten out our current ramp. + set_density(0) + set_opacity(0) + icon_state = "ramptop" + var/obj/structure/droppod_door/door_bottom = new(T) + door_bottom.deployed = 1 + door_bottom.set_density(0) + door_bottom.set_opacity(0) + door_bottom.set_dir(src.dir) + door_bottom.icon_state = "rampbottom" \ No newline at end of file diff --git a/code/modules/random_map/drop/supply.dm b/code/modules/random_map/drop/supply.dm new file mode 100644 index 00000000..18cc90d0 --- /dev/null +++ b/code/modules/random_map/drop/supply.dm @@ -0,0 +1,93 @@ +/datum/random_map/droppod/supply + descriptor = "supply drop" + limit_x = 5 + limit_y = 5 + + placement_explosion_light = 7 + placement_explosion_flash = 5 + +// UNLIKE THE DROP POD, this map deals ENTIRELY with strings and types. +// Drop type is a string representing a mode rather than an atom or path. +// supplied_drop_types is a list of types to spawn in the pod. +/datum/random_map/droppod/supply/get_spawned_drop(var/turf/T) + + if(!drop_type) drop_type = pick(supply_drop_random_loot_types()) + + if(drop_type == "custom") + if(supplied_drop_types.len) + var/obj/structure/largecrate/C = locate() in T + for(var/drop_type in supplied_drop_types) + var/atom/movable/A = new drop_type(T) + if(!istype(A, /mob)) + if(!C) C = new(T) + C.contents |= A + return + else + drop_type = pick(supply_drop_random_loot_types()) + + if(istype(drop_type, /datum/supply_drop_loot)) + var/datum/supply_drop_loot/SDL = drop_type + SDL.drop(T) + else + error("Unhandled drop type: [drop_type]") + + +/datum/admins/proc/call_supply_drop() + set category = "Fun" + set desc = "Call an immediate supply drop on your location." + set name = "Call Supply Drop" + + if(!check_rights(R_FUN)) return + + var/chosen_loot_type + var/list/chosen_loot_types + var/choice = alert("Do you wish to supply a custom loot list?",,"No","Yes") + if(choice == "Yes") + chosen_loot_types = list() + + choice = alert("Do you wish to add mobs?",,"No","Yes") + if(choice == "Yes") + while(1) + var/adding_loot_type = input("Select a new loot path. Cancel to finish.", "Loot Selection", null) as null|anything in typesof(/mob/living) + if(!adding_loot_type) + break + chosen_loot_types |= adding_loot_type + choice = alert("Do you wish to add structures or machines?",,"No","Yes") + if(choice == "Yes") + while(1) + var/adding_loot_type = input("Select a new loot path. Cancel to finish.", "Loot Selection", null) as null|anything in typesof(/obj) - typesof(/obj/item) + if(!adding_loot_type) + break + chosen_loot_types |= adding_loot_type + choice = alert("Do you wish to add any non-weapon items?",,"No","Yes") + if(choice == "Yes") + while(1) + var/adding_loot_type = input("Select a new loot path. Cancel to finish.", "Loot Selection", null) as null|anything in typesof(/obj/item) - typesof(/obj/item/weapon) + if(!adding_loot_type) + break + chosen_loot_types |= adding_loot_type + + choice = alert("Do you wish to add weapons?",,"No","Yes") + if(choice == "Yes") + while(1) + var/adding_loot_type = input("Select a new loot path. Cancel to finish.", "Loot Selection", null) as null|anything in typesof(/obj/item/weapon) + if(!adding_loot_type) + break + chosen_loot_types |= adding_loot_type + choice = alert("Do you wish to add ABSOLUTELY ANYTHING ELSE? (you really shouldn't need to)",,"No","Yes") + if(choice == "Yes") + while(1) + var/adding_loot_type = input("Select a new loot path. Cancel to finish.", "Loot Selection", null) as null|anything in typesof(/atom/movable) + if(!adding_loot_type) + break + chosen_loot_types |= adding_loot_type + else + choice = alert("Do you wish to specify a loot type?",,"No","Yes") + if(choice == "Yes") + chosen_loot_type = input("Select a loot type.", "Loot Selection", null) as null|anything in supply_drop_random_loot_types() + + choice = alert("Are you SURE you wish to deploy this supply drop? It will cause a sizable explosion and gib anyone underneath it.",,"No","Yes") + if(choice == "No") + return + log_admin("[key_name(usr)] dropped supplies at ([usr.x],[usr.y],[usr.z])") + new /datum/random_map/droppod/supply(null, usr.x-2, usr.y-2, usr.z, supplied_drops = chosen_loot_types, supplied_drop = chosen_loot_type) \ No newline at end of file diff --git a/code/modules/random_map/dungeon/predefined.dm b/code/modules/random_map/dungeon/predefined.dm new file mode 100644 index 00000000..f22705d3 --- /dev/null +++ b/code/modules/random_map/dungeon/predefined.dm @@ -0,0 +1,15 @@ +/datum/random_map/winding_dungeon/premade + name = "winding dungeon (PREMADE)" + room_theme_common = list(/datum/room_theme = 1) + room_theme_uncommon = list(/datum/room_theme = 3, /datum/room_theme/metal = 1) + room_theme_rare = list(/datum/room_theme/metal = 1, /datum/room_theme = 3, /datum/room_theme/metal/secure = 1) + + monsters_common = list(/mob/living/simple_animal/hostile/carp = 50, /mob/living/simple_animal/hostile/carp/pike = 1) + monsters_uncommon = list(/mob/living/simple_animal/hostile/hivebot = 10, /mob/living/simple_animal/hostile/hivebot/strong = 1) + +/datum/random_map/winding_dungeon/premade/New() + loot_common += subtypesof(/obj/item/weapon/reagent_containers/food) + subtypesof(/obj/item/weapon/material) + subtypesof(/obj/item/weapon/melee) + loot_uncommon += subtypesof(/obj/item/weapon/gun/projectile) + subtypesof(/obj/item/ammo_magazine) + loot_rare += subtypesof(/obj/mecha) + monsters_rare += typesof(/mob/living/simple_animal/hostile/syndicate) + typesof(/mob/living/simple_animal/hostile/pirate) + ..() \ No newline at end of file diff --git a/code/modules/random_map/dungeon/room.dm b/code/modules/random_map/dungeon/room.dm new file mode 100644 index 00000000..8c60a977 --- /dev/null +++ b/code/modules/random_map/dungeon/room.dm @@ -0,0 +1,96 @@ +/* TO DO +1. Remake godaweful apply_to_map checks. There should be a loop or something I can do there. +2. Make apply_to_map check for nearby doors. If there is a nearby door, check its complexity. +If its complexity is lower than our theme's then +*/ + +/datum/room + var/datum/random_room/room_generator = null + var/x + var/y + var/width + var/height + var/datum/room_theme/room_theme = null + var/generate_doors = 1 //do we want to generate doors for this place? + +/datum/room/New(var/rt, var/_x, var/_y, var/w, var/h, var/doors) + var/gen_type + if(rt) + room_theme = rt + gen_type = room_theme.get_a_room_layout() + if(gen_type) + room_generator = new gen_type(_x,_y,w,h) + generate_doors = doors + x = _x + y = _y + width = w + height = h + +/datum/room/Destroy() + if(room_theme) + qdel(room_theme) + room_theme = null + if(room_generator) + qdel(room_generator) + room_generator = null + return ..() + +/datum/room/proc/apply_to_map(var/xorigin,var/yorigin,var/zorigin, var/datum/random_map/map) + if(room_theme) + for(var/i = 0, i < width, i++) + for(var/j = 0, j < height, j++) + var/truex = xorigin + x + i - 1 + var/truey = yorigin + y + j - 1 + var/cell = map.get_map_cell(x+i,y+j) + room_theme.apply_room_theme(truex,truey,map.map[cell]) + if(generate_doors && room_theme.door_type && !(map.map[cell] == WALL_CHAR || map.map[cell] == ARTIFACT_TURF_CHAR) && (i == 0 || i == width-1 || j == 0 || j == height-1)) + var/isGood = 1 + if(j == 0 || j == height-1) //check horizontally + var/curCell = map.map[map.get_map_cell(x+i-1,y+j)] + if(curCell != WALL_CHAR && curCell != ARTIFACT_TURF_CHAR) + isGood = 0 + curCell = map.map[map.get_map_cell(x+i+1,y+j)] + if(curCell != WALL_CHAR && curCell != ARTIFACT_TURF_CHAR) + isGood = 0 + curCell = map.map[map.get_map_cell(x+i,y+j-1)] + if(curCell == WALL_CHAR || curCell == ARTIFACT_TURF_CHAR) + isGood = 0 + curCell = map.map[map.get_map_cell(x+i,y+j+1)] + if(curCell == WALL_CHAR || curCell == ARTIFACT_TURF_CHAR) + isGood = 0 + if(i == 0 || i == width-1) //verticle + isGood = 1 //if it failed above, it might not fail here. + var/curCell = map.map[map.get_map_cell(x+i,y+j-1)] + if(curCell != WALL_CHAR && curCell != ARTIFACT_TURF_CHAR) + isGood = 0 + curCell = map.map[map.get_map_cell(x+i,y+j+1)] + if(curCell != WALL_CHAR && curCell != ARTIFACT_TURF_CHAR) + isGood = 0 + curCell = map.map[map.get_map_cell(x+i-1,y+j)] + if(curCell == WALL_CHAR || curCell == ARTIFACT_TURF_CHAR) + isGood = 0 + curCell = map.map[map.get_map_cell(x+i+1,y+j)] + if(curCell == WALL_CHAR || curCell == ARTIFACT_TURF_CHAR) + isGood = 0 + if(isGood) + room_theme.apply_room_door(x+i,y+j,zorigin) + if(room_theme) + qdel(room_theme) + room_theme = null + if(room_generator) + room_generator.apply_to_map(xorigin,yorigin,zorigin) + + return 1 + +/datum/room/proc/add_loot(var/xorigin,var/yorigin,var/zorigin,var/type) + if(room_generator && room_generator.apply_loot(xorigin,yorigin,zorigin,type)) + return 1 + var/rx = xorigin+x+rand(width-3) + var/ry = yorigin+y+rand(height-3) + var/turf/T = locate(rx,ry,zorigin) + if(!T || T.density) + return 0 + for(var/obj/o in T) + return 0 + new type(T) + return 1 \ No newline at end of file diff --git a/code/modules/random_map/dungeon/room_generation.dm b/code/modules/random_map/dungeon/room_generation.dm new file mode 100644 index 00000000..005ce8aa --- /dev/null +++ b/code/modules/random_map/dungeon/room_generation.dm @@ -0,0 +1,38 @@ +//a basic room generator. +//room should assume that (x,y) is the bottom left corner +//TODO make more content! +/datum/random_room + var/width = 0 + var/height = 0 + var/x = 0 + var/y = 0 + var/list/item_spawns + +/datum/random_room/New(var/_x,var/_y,var/_width,var/_height) + width = _width + height = _height + x = _x + y = _y + +/datum/random_room/proc/apply_to_map(var/xorigin = 1,var/yorigin = 1,var/zorigin = 1) + return 1 + +/datum/random_room/proc/apply_loot(var/xorigin = 1,var/yorigin = 1,var/zorigin = 1, var/type) + if(!item_spawns || !item_spawns.len) + return 0 + var/place = pick(item_spawns) + if(istype(place,/obj)) //we assume what object we get is some sort of container. + var/obj/O = place + if(O.contents && prob(O.contents.len * (25 / O.w_class))) + return 0 + new type(place) + else if(istype(place,/mob)) + var/mob/M = place + var/atom/movable/A = new type(M.loc) + M.equip_to_appropriate_slot(A) //we dont have to check if its an object or not since hte proc in question already does that + else //its a turf. Put it on it. + var/turf/T = place + if(T.density) //under no circumstances place an item in a wall. + return 0 + new type(place) + return 1 \ No newline at end of file diff --git a/code/modules/random_map/dungeon/room_theme.dm b/code/modules/random_map/dungeon/room_theme.dm new file mode 100644 index 00000000..c4616fc2 --- /dev/null +++ b/code/modules/random_map/dungeon/room_theme.dm @@ -0,0 +1,76 @@ +//room theme is basically the turfs that which a dungeon defaults to making a room out of. +/datum/room_theme + var/wall_type + var/floor_type + var/door_type = /obj/machinery/door/unpowered/simple/iron + var/xorigin = 1 + var/yorigin = 1 + var/zorigin = 1 + var/lock_complexity_min = 0 + var/lock_complexity_max = 0 + var/lock_data + var/layout_chance = 50//chance of having a lyout period + var/list/room_layouts = list() + +/datum/room_theme/New(var/x,var/y,var/z) + xorigin = x + yorigin = y + zorigin = z + if(!lock_data && lock_complexity_max > 0) + lock_data = generateRandomString(rand(lock_complexity_min,lock_complexity_max)) + +/datum/room_theme/proc/apply_room_theme(var/x,var/y,var/value) + var/turf/T = locate(x,y,zorigin) + if(!T) + return 0 + var/path + switch(value) + if(WALL_CHAR) + if(!wall_type) + return + path = wall_type + if(ARTIFACT_TURF_CHAR) + if(!wall_type) + return + path = wall_type + else + if(!floor_type) + return + path = floor_type + T.ChangeTurf(path) + +/datum/room_theme/proc/apply_room_door(var/x,var/y) + if(!door_type) + return 0 + var/turf/T = locate(xorigin+x-1,yorigin+y-1,zorigin) + for(var/i = -1; i <= 1; i++) + for(var/j = -1; j <= 1; j++) + var/turf/check = locate(T.x + i, T.y + j, T.z) + if(!check) + continue + for(var/atom/movable/M in check.contents) + if(!istype(M, /atom/movable/lighting_overlay) && M.density) + return 0 + if(!T) + return 0 + if(ispath(door_type,/obj/machinery/door/unpowered/simple)) + new door_type(T,null,lock_data) + else + new door_type(T) + +/datum/room_theme/proc/get_a_room_layout() + if(room_layouts.len && prob(layout_chance)) + return pickweight(room_layouts) + return null + +/datum/room_theme/metal + wall_type = /turf/simulated/wall + floor_type = /turf/simulated/floor/plating + lock_complexity_max = 2 + layout_chance = 30 + room_layouts = list(/datum/random_room/mimic = 1, /datum/random_room/tomb = 1) + +/datum/room_theme/metal/secure + layout_chance = 100 + lock_complexity_min = 2 + lock_complexity_max = 5 \ No newline at end of file diff --git a/code/modules/random_map/dungeon/rooms/mimic_room.dm b/code/modules/random_map/dungeon/rooms/mimic_room.dm new file mode 100644 index 00000000..87bfce78 --- /dev/null +++ b/code/modules/random_map/dungeon/rooms/mimic_room.dm @@ -0,0 +1,23 @@ +/datum/random_room/mimic + var/mimic_type = /obj/structure/closet/crate + var/list/mimic_vars = list() + var/chance_of_mimic = 5 + +/datum/random_room/mimic/apply_to_map(var/xorigin,var/yorigin,var/zorigin) + item_spawns = list() + var/truex = xorigin + x - 1 + var/truey = yorigin + y - 1 + var/turf/T = locate(truex + round(width/2), truey+round(height/2), zorigin) + var/obj/structure/closet/C = new mimic_type(T) + item_spawns += C + if(prob(chance_of_mimic) && mimic_type) + new /mob/living/simple_animal/hostile/mimic/sleeping(get_turf(C),C) + +//BASICALLY: +//Create mimic in center of room. +//put loot inside said mimic + + +//dont want to keep references to said mimic or closet. Would cause qdel issues. +//so since we know nothing should get moved since we placed it we just find it again. +//inefficient yes but will not cause issues with qdel \ No newline at end of file diff --git a/code/modules/random_map/dungeon/rooms/monster_room.dm b/code/modules/random_map/dungeon/rooms/monster_room.dm new file mode 100644 index 00000000..7ce00c19 --- /dev/null +++ b/code/modules/random_map/dungeon/rooms/monster_room.dm @@ -0,0 +1,18 @@ +//Monster room: Generates a room FILLED with monsters. +/datum/random_room/monster_room + var/list/available_mobs = list(/mob/living/simple_animal/hostile/carp) + +/datum/random_room/monster_room/apply_to_map(var/xorigin,var/yorigin,var/zorigin) + if(available_mobs.len == 0) //no mobs no problem + return 1 + var truex = xorigin + x - 1 + var truey = yorigin + y - 1 + for(var/i = 1, i < width - 1, i++) + for(var/j = 1, j < height - 1, j++) + var/turf/T = locate(truex+i,truey+j,zorigin) + if(!T) + return 0 + var/type = pickweight(available_mobs) + var/mob/M = new type + M.loc = T + return 1 \ No newline at end of file diff --git a/code/modules/random_map/dungeon/rooms/tomb.dm b/code/modules/random_map/dungeon/rooms/tomb.dm new file mode 100644 index 00000000..bde46e86 --- /dev/null +++ b/code/modules/random_map/dungeon/rooms/tomb.dm @@ -0,0 +1,49 @@ +/datum/random_room/tomb/ + var/list/corpses = list("human" = 1) + var/direction = 0 //0 horizontal 1 vertical + var/chance_of_corpse = 30 + + + +//attempts to line the walls with coffins with corpses inside +/datum/random_room/tomb/apply_to_map(var/xorigin, var/yorigin, var/zorigin) + item_spawns = list() + direction = pick(0,1) + var/limit = (direction ? height : width) + for(var/i = 0, i < limit - 2, i++) + var/truex = xorigin + (direction ? 0 : i) + x + var/truey = yorigin + (direction ? i : 0) + y + var/turf/T1 = locate(truex,truey,zorigin) + var/turf/T2 = locate(truex + (direction ? width - 3 : 0), truey + (direction ? 0 : height - 3), zorigin) + var/turf/check = locate(truex + (direction ? -1 : 0), truey + (direction ? 0 : -1), zorigin) + if(check.density && !T1.density && !T1.contents.len) + var/obj/structure/closet/coffin/C1 = new(T1) + if(prob(chance_of_corpse)) + var/type = pickweight(corpses) + var/mob/M + if(istext(type)) + M = new /mob/living/carbon/human() + var/mob/living/carbon/human/H = M + H.set_species(type) + H.ChangeToHusk() + else + M = new type() + M.death(0) + M.forceMove(C1) + item_spawns += M + check = locate(truex + (direction ? width - 2 : 0), truey + (direction ? 0 : height - 2), zorigin) + if(check.density && !T2.density && !T2.contents.len) + var/obj/structure/closet/coffin/C2 = new(T2) + if(prob(chance_of_corpse)) + var/type = pickweight(corpses) + var/mob/M + if(istext(type)) + M = new /mob/living/carbon/human() + var/mob/living/carbon/human/H = M + H.set_species(type) + H.ChangeToHusk() + else + M = new type() + M.death(0) + M.forceMove(C2) + item_spawns += M \ No newline at end of file diff --git a/code/modules/random_map/dungeon/winding_dungeon.dm b/code/modules/random_map/dungeon/winding_dungeon.dm new file mode 100644 index 00000000..1315edc6 --- /dev/null +++ b/code/modules/random_map/dungeon/winding_dungeon.dm @@ -0,0 +1,339 @@ +#define BORDER_CHAR -1 +/*basic dungeon algorithm. Based off of http://www.roguebasin.com/index.php?title=Dungeon-Building_Algorithm (specifically the C++ version). + *The jist of how the dungeon algorithm works is as follows: + *Corridors and rooms are both considered features of a dungeon. + *The dungeon continues to spawn rooms and corridors attached to previously created rooms and corridors (by detecting the walls/floors) until the amount of features is equal to a predefined number. + *This number is calculated at the beginning of the dungeon. I went with limit_x*limit_y/100. It seems to work well. + *It is supposed to create a 'winding' aspect to the dungeons. It works.... relatively well? + + *THINGS TO KNOW + *ARTIFACT_TURF_CHAR is used for room walls, used primarily for code used for corridors. + *ARTIFACT_TURF is used to mark gaps in walls for rooms - this is checked so that we dont have three corridors in a row. This isn't done for corridors so that we can have branching paths. + *Rooms will generate a room_theme, a datum that points to a few different types to generate the room with. + *room_themes will also generate stuff inside. This is a random_room datum. + +* TODO: +* Make monster spawning from a datum so I can have general 'group spawns'. +*/ + +/datum/random_map/winding_dungeon + descriptor = "winding dungeon" + wall_type = /turf/simulated/mineral + floor_type = /turf/simulated/floor/tiled + var/room_wall_type = /turf/simulated/wall + var/border_wall_type = /turf/unsimulated/mineral + + target_turf_type = /turf/unsimulated/mask + + var/chance_of_room = 65 + var/chance_of_room_empty = 50 + var/chance_of_door = 30 + var/room_size_min = 4 + var/room_size_max = 8 + var/features_multiplier = 0.02 + var/monster_multiplier = 0.007 + var/loot_multiplier = 0.01 + + var/first_room_x = 45 + var/first_room_y = 1 + var/first_room_width = 10 + var/first_room_height = 10 + + var/monster_faction = "dungeon" //if set, factions of the mobs spawned will be set to this. + //without this they will attack each other. + + var/list/open_positions = list() //organized as: x:y + var/list/room_theme_common = list(/datum/room_theme = 10) + var/list/room_theme_uncommon = list() + var/list/room_theme_rare = list() + var/list/monsters_common = list() + var/list/monsters_uncommon = list() + var/list/monsters_rare = list() + var/list/loot_common = list() + var/list/loot_uncommon = list() + var/list/loot_rare = list() + + var/list/monster_available = list()//turfs that monsters can spawn on. Pregenerated to guard against lag. + + var/list/rooms = list() + var/log = 0 //if set will log information to dd + limit_x = 50 + limit_y = 50 + +/datum/random_map/winding_dungeon/New(var/seed, var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/list/variable_list) + for(var/variable in variable_list) + if(variable in src.vars) + src.vars[variable] = variable_list[variable] + ..() + +/datum/random_map/winding_dungeon/proc/logging(var/text) + if(log) + log_to_dd(text) + +/datum/random_map/winding_dungeon/proc/get_appropriate_list(var/list/common, var/list/uncommon, var/list/rare, var/x, var/y) + var/distance = sqrt((x - round(first_room_x+first_room_width/2)) ** 2 + (y - round(first_room_y+first_room_height/2)) ** 2) + if(prob(distance)) + if(prob(distance/100) && rare && rare.len) + logging("Returning rare list.") + return rare + else if(uncommon && uncommon.len) + logging("Returning uncommon list.") + return uncommon + logging("Returning common list.") + return common + + +/datum/random_map/winding_dungeon/apply_to_map() + logging("You have [rooms.len] # of rooms") + for(var/datum/room/R in rooms) + if(!priority_process) + sleep(-1) + R.apply_to_map(origin_x,origin_y,origin_z,src) + ..() + var/num_of_loot = round(limit_x * limit_y * loot_multiplier) + logging("Attempting to add [num_of_loot] # of loot") + var/sanity = 0 + if((loot_common && loot_common.len) || (loot_uncommon && loot_uncommon.len) || (loot_rare && loot_rare.len)) //no monsters no problem + while(rooms.len && num_of_loot > 0) + if(!priority_process) + sleep(-1) + var/datum/room/R = pick(rooms) + var/list/loot_list = get_appropriate_list(loot_common, loot_uncommon, loot_rare, round(R.x+R.width/2), round(R.y+R.height/2)) + if(!loot_list || !loot_list.len || R.add_loot(origin_x,origin_y,origin_z,pickweight(loot_list))) + num_of_loot-- + sanity -= 10 //we hahve success so more tries + continue + sanity++ + if(sanity > 100) + logging("Sanity limit reached on loot spawning #[num_of_loot]") + num_of_loot = 0 + + for(var/datum/room/R in rooms) + rooms -= R + qdel(R) + + if((!monsters_common || !monsters_common.len) && (!monsters_uncommon || !monsters_uncommon.len) && (!monsters_rare || !monsters_rare.len)) //no monsters no problem + logging("No monster lists detected. Not spawning monsters.") + return + + var/num_of_monsters = round(limit_x * limit_y * monster_multiplier) + logging("Attempting to add [num_of_monsters] # of monsters") + + while(num_of_monsters > 0) + if(!priority_process) + sleep(-1) + if(!monster_available || !monster_available.len) + logging("There are no available turfs left.") + num_of_monsters = 0 + continue + var/turf/T = pick(monster_available) + monster_available -= T + var/list/monster_list = get_appropriate_list(monsters_common, monsters_uncommon, monsters_rare, T.x, T.y) + if(monster_list && monster_list.len) + var/type = pickweight(monster_list) + logging("Generating a monster of type [type] at position ([T.x],[T.y],[origin_z])") + var/mob/M = new type(T) + if(monster_faction) + M.faction = monster_faction + else + logging("The monster list is empty.") + num_of_monsters-- + + monster_available = null //Get rid of all the references + +/datum/random_map/winding_dungeon/apply_to_turf(var/x, var/y) + . = ..() + var/turf/T = locate((origin_x-1)+x,(origin_y-1)+y,origin_z) + if(T && !T.density) + var/can = 1 + for(var/atom/movable/M in T) + if(istype(M,/mob/living) || M.density) + can = 0 + break + if(can) + monster_available += T + +/datum/random_map/winding_dungeon/generate_map() + logging("Winding Dungeon Generation Start") + //first generate the border + for(var/xx = 1, xx <= limit_x, xx++) + map[get_map_cell(xx,1)] = BORDER_CHAR + map[get_map_cell(xx,limit_y)] = BORDER_CHAR + for(var/yy = 1, yy < limit_y, yy++) + map[get_map_cell(1,yy)] = BORDER_CHAR + map[get_map_cell(limit_x,yy)] = BORDER_CHAR + + var/num_of_features = limit_x * limit_y * features_multiplier + logging("Number of features: [num_of_features]") + var/currentFeatures = 1 + var/result = carve_area(first_room_x,first_room_y,first_room_width,first_room_height, FLOOR_CHAR, ARTIFACT_TURF_CHAR) + logging("First room result: [result ? "Success" : "Failure"]") + var/sanity = 0 + for(sanity = 0, sanity < 1000, sanity++) + if(!priority_process) + sleep(-1) + + if(currentFeatures == num_of_features) + break + /* WHAT THIS CODE IS DOING: + Very basically I'm taking a point off of the coords list and trying to create a room in a certain direction. + What a lot of this code is doing is figuring out where to put the REAL x and y values so that we are in the bottom left corner + of the new room for processing. + */ + var/newx = 0 //the point where this feature meets another one. + var/newy = 0 + var/xmod = 0 //the change in x and y determined to be needed + var/ymod = 0 + var/doorx = 0 //where we put the marker down where things were. + var/doory = 0 + var/width = 1 //width of room + var/height = 1 //height of room. + var/isRoom = 1 //whether we are a room or not + for(var/testing = 0, testing < 1000, testing++) + if(open_positions.len) + var/list/coords = splittext(pick(open_positions), ":") //pop a coord from the list. + newx = text2num(coords[1]) + newy = text2num(coords[2]) + open_positions -= "[newx]:[newy]" + logging("Picked coords ([newx],[newy]) from open_positions. Removing it. (length: [open_positions.len])") + else + newx = rand(1,limit_x) + newy = rand(1,limit_y) + logging("open_positions empty. Using randomly chosen coords ([newx],[newy])") + + //We want to make sure we aren't RIGHT next to another corridor or something. + if(map[get_map_cell(newx,newy+1)] == ARTIFACT_CHAR || map[get_map_cell(newx-1,newy)] == ARTIFACT_CHAR || map[get_map_cell(newx,newy-1)] == ARTIFACT_CHAR || map[get_map_cell(newx+1,newy)] == ARTIFACT_CHAR) + logging("Coords ([newx],[newy]) are too close to an ARTIFACT_CHAR position.") + continue + + + //set up our variables. + width = rand(room_size_min,room_size_max) + height = rand(room_size_min,room_size_max) + isRoom = rand(100) <= chance_of_room + + if(map[get_map_cell(newx, newy)] == ARTIFACT_TURF_CHAR || map[get_map_cell(newx, newy)] == CORRIDOR_TURF_CHAR) + //we are basically checking to see where we're going. Up, right, down or left and finding the bottom left corner. + if(map[get_map_cell(newx,newy+1)] == FLOOR_CHAR || map[get_map_cell(newx,newy+1)] == CORRIDOR_TURF_CHAR) //0 - down + logging("This feature is DOWN") + if(isRoom) //gotta do some math for this one, since the origin is centered. + xmod = -width/2 + else + width = 1 + xmod = 0 + ymod = -height //a lot of this will seem nonsense but I swear its not + doorx = 0 + doory = -1 + else if(map[get_map_cell(newx-1,newy)] == FLOOR_CHAR || map[get_map_cell(newx-1,newy)] == CORRIDOR_TURF_CHAR) //1 - right + logging("This feature is RIGHT") + if(isRoom) + ymod = -height/2 + else + height = 1 + ymod = 0 + xmod = 1 + doorx = 1 + doory = 0 + else if(map[get_map_cell(newx,newy-1)] == FLOOR_CHAR || map[get_map_cell(newx,newy-1)] == CORRIDOR_TURF_CHAR) //2 - up + logging("This feature is UP") + if(isRoom) + xmod = -width/2 + else + width = 1 + xmod = 0 + ymod = 1 + doorx = 0 + doory = 1 + else if(map[get_map_cell(newx+1,newy)] == FLOOR_CHAR || map[get_map_cell(newx+1,newy)] == CORRIDOR_TURF_CHAR) // 3 - left + logging("This feature is LEFT") + if(isRoom) + ymod = -height/2 + else + height = 1 + ymod = 0 + xmod = -width + doorx = -1 + doory = 0 + else + continue + + break + + if(sanity < 1000) //If we haven't looped through /everything/ + logging("Carving out stuff.") + var/wall_char = (isRoom ? ARTIFACT_TURF_CHAR : CORRIDOR_TURF_CHAR) + if(!carve_area(round(newx+xmod),round(newy+ymod),width,height,FLOOR_CHAR,wall_char)) //something went bad + logging("Carving failed at position: ([newx],[newy]) with modifiers ([xmod],[ymod]) and size ([width],[height]). isRoom ([isRoom])") + continue //so just try again + currentFeatures++ + if(isRoom) + logging("Room created at: [newx+xmod], [newy+ymod].") + map[get_map_cell(newx,newy)] = FLOOR_CHAR + map[get_map_cell(newx+doorx,newy+doory)] = ARTIFACT_CHAR + if(rand(0,100) >= chance_of_room_empty) + var/room_result = create_room_features(round(newx+xmod),round(newy+ymod),width,height) + logging("Attempted room feature creation: [room_result ? "Success" : "Failure"]") + else + logging("Creating corridor.") + var/door = get_map_cell(newx,newy) + if(map[door] == ARTIFACT_TURF_CHAR) + map[door] = ARTIFACT_CHAR + logging("Map completed. Loops: [sanity], [currentFeatures] out of [num_of_features] created.") + open_positions.Cut() + +/datum/random_map/winding_dungeon/proc/carve_area(var/truex,var/truey,var/width,var/height,var/char, var/wall_char) + for(var/mode = 0, mode <= 1, mode++) + for(var/ytemp = truey, ytemp < truey + height, ytemp++) + if(!mode && (ytemp < 0 || ytemp > limit_y)) + logging("We are beyond our x limits") + return 0 + for(var/xtemp = truex, xtemp < truex + width, xtemp++) + if(!mode) + if(xtemp < 0 || xtemp > limit_x) + logging("We are beyond our x limits") + return 0 + if(map[get_map_cell(xtemp,ytemp)] != WALL_CHAR) + logging("[xtemp],[ytemp] is not equal to WALL_CHAR") + return 0 + else + if(wall_char && (ytemp == truey || ytemp == truey + height - 1 || xtemp == truex || xtemp == truex + width - 1)) + map[get_map_cell(xtemp,ytemp)] = wall_char + if(!("[xtemp]:[ytemp]" in open_positions)) + open_positions += "[xtemp]:[ytemp]" + logging("Adding \"[xtemp]:[ytemp]\" to open_positions (length: [open_positions.len])") + else + map[get_map_cell(xtemp,ytemp)] = char + return 1 + +/datum/random_map/winding_dungeon/proc/create_room_features(var/rox,var/roy,var/width,var/height) + var/list/room_list = get_appropriate_list(room_theme_common, room_theme_uncommon, room_theme_rare, round(rox+width/2), round(roy+height/2)) + var/theme_type = pickweight(room_list) + if(!theme_type) + return 0 + var/room_theme = new theme_type(origin_x,origin_y,origin_z) + var/datum/room/R = new(room_theme,rox,roy,width,height,rand(0,100) <= chance_of_door) + if(!R) + return 0 + rooms += R + return 1 + +/datum/random_map/winding_dungeon/proc/add_loot(var/xorigin,var/yorigin,var/zorigin,var/type) + var/datum/room/room = pick(rooms) + return room.add_loot(type) + +/datum/random_map/winding_dungeon/get_appropriate_path(var/value) + switch(value) + if(WALL_CHAR) + return wall_type + if(ARTIFACT_TURF_CHAR) + return room_wall_type + if(BORDER_CHAR) + return border_wall_type + else + return floor_type + +/datum/random_map/winding_dungeon/get_map_char(var/value) + . = ..(value) + switch(value) + if(BORDER_CHAR) + . = "#" \ No newline at end of file diff --git a/code/modules/random_map/dungeon/winding_dungeon_verb.dm b/code/modules/random_map/dungeon/winding_dungeon_verb.dm new file mode 100644 index 00000000..135737d8 --- /dev/null +++ b/code/modules/random_map/dungeon/winding_dungeon_verb.dm @@ -0,0 +1,108 @@ +//Its different so that you can add monsters to said dungeon pretty easily. + +//Works similarly to the supply drop in that you create it to use it instantly. +/client/proc/create_dungeon() + set category = "Fun" + set name = "Create Dungeon" + set desc = "Create and apply a configurable dungeon to a zlevel." + + var/list/vars = list() + + vars["limit_x"] = input("What is the width of your map?") as num + vars["limit_y"] = input("What is the height of your map?") as num + vars["first_room_x"] = input("What should be the first room's X position be?") as num + vars["first_room_y"] = input("What should be the first room's Y position be?") as num + vars["first_room_width"] = input("What should be the first room's width position be?") as num + vars["first_room_height"] = input("What should be the first room's height position be?") as num + if(alert("Would you like to modify generated room/corridor variables?",,"No","Yes") == "Yes") + vars["room_size_min"] = input("What is the smallest size a room should be?") as num + vars["room_size_max"] = input("What is the largest size a room should be?") as num + vars["chance_of_room"] = input("What is the percent chance of a room being generated versus a corridor? (From 0 to 100)") as num + vars["chance_of_door"] = input("What is the percent chance of a room having doors? (From 0 to 100)") as num + vars["chance_of_room_empty"] = input("What is the percent chance that a room will be empty? (From 0 to 100)") as num + if(alert("Would you like to modify generational multipliers?",,"No","Yes") == "Yes") + var/percent = input("What is the percent multiplier of how many features are generated? Default is 2 (WARNING HIGH NUMBERS MAY CAUSE LAG)") as num + vars["features_multiplier"] = percent/100 + percent = input("What is the percent multiplier of how many monsters are generated? Default is 0.7 (WARNING HIGH NUMBERS MAY CAUSE LAG)") as num + vars["monster_multiplier"] = percent/100 + percent = input("What is the percent multiplier of how much loot is generated? Default is 1 (WARNING HIGH NUMBERS MAY CAUSE LAG)") as num + vars["loot_multiplier"] = percent/100 + var/list/common + var/list/uncommon + var/list/rare + var/list/current_list + var/mode = "room_theme" + while(1) + if(mode == "room_theme") + common = list(/datum/room_theme = 10) + else + common = list() + uncommon = list() + rare = list() + current_list = common + switch(mode) + if("room_theme") + if(alert("Would you like to modify what room layouts are used?",,"No","Yes") != "Yes") + mode = "monsters" + continue + if("monsters") + if(alert("Would you like to modify what mobs get spawned?",,"No","Yes") != "Yes") + mode = "loot" + continue + if("loot") + if(alert("Would you like to modify what loot gets spawned?",,"No","Yes") !="Yes") + break + var/list/total_types + switch(mode) + if("room_theme") + total_types = typesof(/datum/room_theme) + if("monsters") + total_types = subtypesof(/mob/living) + if("loot") + total_types = subtypesof(/obj/item) + while(1) + var/layout = input("Pick an item to add to the current pool. Press cancel to finish.") as null|anything in total_types + if(!layout) + if(current_list == common && alert("Would you like to add items to the uncommon pool?",,"No","Yes") == "Yes") + current_list = uncommon + continue + else if(current_list != rare && alert("Would you like to add items to the rare pool?",, "No", "Yes") == "Yes") + current_list = rare + continue + else + break + var/chance = input("What is the weight of this item? Higher weights get picked more frequently. Default is 10",10) as num + if(alert("Do you want to add all subtypes of this item to the current pool as well? They will be weighted the same.",,"No","Yes") == "Yes") + var/list/local_total = typesof(layout) + if(alert("Do you want to only add the subtypes of this item?",,"No","Yes") == "Yes") + local_total -= layout + for(var/a in local_total) + current_list[a] = chance + else + current_list[layout] = chance + + vars["[mode]_common"] = common.Copy() + vars["[mode]_uncommon"] = uncommon.Copy() + vars["[mode]_rare"] = rare.Copy() + switch(mode) + if("room_theme") + mode = "monsters" + if("monsters") + mode = "loot" + else + break + + if(alert("Are you sure you want to create this? It will appear at your position.",,"No","Yes") != "Yes") + return + + var/datum/random_map/winding_dungeon/W = /datum/random_map/winding_dungeon + + for(var/x in 1 to vars["limit_x"]) + for(var/y in 1 to vars["limit_y"]) + sleep(-1) + var/turf/T = locate(usr.x+x-1,usr.y+y-1,usr.z) + if(!T) + to_chat(src, "Error, turf could not be located. Probably out of bounds.") + return + T.ChangeTurf(initial(W.target_turf_type)) + new /datum/random_map/winding_dungeon(null,usr.x, usr.y, usr.z, variable_list = vars) diff --git a/code/modules/random_map/mazes/maze.dm b/code/modules/random_map/mazes/maze.dm new file mode 100644 index 00000000..557adbd6 --- /dev/null +++ b/code/modules/random_map/mazes/maze.dm @@ -0,0 +1,65 @@ +/datum/random_map/maze + descriptor = "maze" + initial_wall_cell = 100 + var/list/checked_coord_cache = list() + var/list/openlist = list() + var/list/closedlist = list() + +/datum/random_map/maze/set_map_size() + // Map has to be odd so that there are walls on all sides. + if(limit_x%2==0) limit_x++ + if(limit_y%2==0) limit_y++ + ..() + +/datum/random_map/maze/generate_map() + + // Grab a random point on the map to begin the maze cutting at. + var/start_x = rand(1,limit_x-2) + var/start_y = rand(1,limit_y-2) + if(start_x%2!=0) start_x++ + if(start_y%2!=0) start_y++ + + // Create the origin cell to start us off. + openlist += new /datum/maze_cell(start_x,start_y) + + while(openlist.len) + // Grab a maze point to use and remove it from the open list. + var/datum/maze_cell/next = pick(openlist) + openlist -= next + if(!isnull(closedlist[next.name])) + continue + + // Preliminary marking-off... + closedlist[next.name] = next + map[get_map_cell(next.x,next.y)] = FLOOR_CHAR + + // Apply the values required and fill gap between this cell and origin point. + if(next.ox && next.oy) + if(next.ox < next.x) + map[get_map_cell(next.x-1,next.y)] = FLOOR_CHAR + else if(next.ox == next.x) + if(next.oy < next.y) + map[get_map_cell(next.x,next.y-1)] = FLOOR_CHAR + else + map[get_map_cell(next.x,next.y+1)] = FLOOR_CHAR + else + map[get_map_cell(next.x+1,next.y)] = FLOOR_CHAR + + // Grab valid neighbors for use in the open list! + add_to_openlist(next.x,next.y+2,next.x,next.y) + add_to_openlist(next.x-2,next.y,next.x,next.y) + add_to_openlist(next.x+2,next.y,next.x,next.y) + add_to_openlist(next.x,next.y-2,next.x,next.y) + + // Cleanup. Map stays in memory for display proc. + checked_coord_cache.Cut() + openlist.Cut() + closedlist.Cut() + +/datum/random_map/maze/proc/add_to_openlist(var/tx, var/ty, var/nx, var/ny) + if(tx < 1 || ty < 1 || tx > limit_x || ty > limit_y || !isnull(checked_coord_cache["[tx]-[ty]"])) + return 0 + checked_coord_cache["[tx]-[ty]"] = 1 + map[get_map_cell(tx,ty)] = DOOR_CHAR + var/datum/maze_cell/new_cell = new(tx,ty,nx,ny) + openlist |= new_cell diff --git a/code/modules/random_map/mazes/maze_cell.dm b/code/modules/random_map/mazes/maze_cell.dm new file mode 100644 index 00000000..0b4fa1ac --- /dev/null +++ b/code/modules/random_map/mazes/maze_cell.dm @@ -0,0 +1,18 @@ +var/maze_cell_count = 0 + +/datum/maze_cell + var/name + var/uid + var/x + var/y + var/ox + var/oy + +/datum/maze_cell/New(var/nx,var/ny,var/nox,var/noy) + maze_cell_count++ + uid = maze_cell_count + name = "cell #[uid]" + x = nx + y = ny + ox = nox + oy = noy \ No newline at end of file diff --git a/code/modules/random_map/noise/desert.dm b/code/modules/random_map/noise/desert.dm new file mode 100644 index 00000000..1c7ca229 --- /dev/null +++ b/code/modules/random_map/noise/desert.dm @@ -0,0 +1,40 @@ +/datum/random_map/noise/desert + descriptor = "desert" + smoothing_iterations = 3 + +/datum/random_map/noise/desert/replace_space + descriptor = "desert (replacement)" + target_turf_type = /turf/space + +/datum/random_map/noise/desert/get_map_char(var/value) + return "[pick(list(",",".","'","`"))]" + +/datum/random_map/noise/desert/get_appropriate_path(var/value) + var/val = min(9,max(0,round((value/cell_range)*10))) + if(isnull(val)) val = 0 + switch(val) + if(0 to 1) + return /turf/simulated/floor/beach/water + else + return /turf/simulated/floor/beach/sand/desert + +/datum/random_map/noise/desert/get_additional_spawns(var/value, var/turf/T) + var/val = min(9,max(0,round((value/cell_range)*10))) + if(isnull(val)) val = 0 + switch(val) + if(2 to 3) + if(prob(60)) + var/grass_path = pick(typesof(/obj/structure/flora/grass)-/obj/structure/flora/grass) + new grass_path(T) + if(prob(5)) + var/mob_type = pick(list(/mob/living/simple_animal/lizard, /mob/living/simple_animal/mouse)) + new mob_type(T) + if(5 to 6) + if(prob(20)) + var/grass_path = pick(typesof(/obj/structure/flora/grass)-/obj/structure/flora/grass) + new grass_path(T) + if(7 to 9) + if(prob(60)) + new /obj/structure/flora/bush(T) + else if(prob(20)) + new /obj/structure/flora/tree/dead(T) diff --git a/code/modules/random_map/noise/magma.dm b/code/modules/random_map/noise/magma.dm new file mode 100644 index 00000000..8c8bd6a9 --- /dev/null +++ b/code/modules/random_map/noise/magma.dm @@ -0,0 +1,44 @@ +// This is basically filler at this point. Subsidence and all kinds of fun +// hazards will be included when it is done. +/datum/random_map/noise/volcanism + descriptor = "volcanism" + smoothing_iterations = 6 + target_turf_type = /turf/simulated + +// Get rid of those dumb little single-tile volcanic areas. +/datum/random_map/noise/volcanism/cleanup() + for(var/x = 1, x <= limit_x, x++) + for(var/y = 1, y <= limit_y, y++) + var/current_cell = get_map_cell(x,y) + if(map[current_cell] < 178) + continue + var/count + var/tmp_cell = get_map_cell(x+1,y+1) + if(tmp_cell && map[tmp_cell] >= 178) count++ + tmp_cell = get_map_cell(x-1,y-1) + if(tmp_cell && map[tmp_cell] >= 178) count++ + tmp_cell = get_map_cell(x+1,y-1) + if(tmp_cell && map[tmp_cell] >= 178) count++ + tmp_cell = get_map_cell(x-1,y+1) + if(tmp_cell && map[tmp_cell] >= 178) count++ + tmp_cell = get_map_cell(x-1,y) + if(tmp_cell && map[tmp_cell] >= 178) count++ + tmp_cell = get_map_cell(x,y-1) + if(tmp_cell && map[tmp_cell] >= 178) count++ + tmp_cell = get_map_cell(x+1,y) + if(tmp_cell && map[tmp_cell] >= 178) count++ + tmp_cell = get_map_cell(x,y+1) + if(tmp_cell && map[tmp_cell] >= 178) count++ + if(!count) + map[current_cell] = 177 + +/datum/random_map/noise/volcanism/get_appropriate_path(var/value) + return + +/datum/random_map/noise/volcanism/get_additional_spawns(var/value, var/turf/T) + if(value>=178) + if(istype(T,/turf/simulated/floor/asteroid)) + T.ChangeTurf(/turf/simulated/floor/airless/lava) + else if(istype(T,/turf/simulated/mineral)) + var/turf/simulated/mineral/M = T + M.mined_turf = /turf/simulated/floor/airless/lava \ No newline at end of file diff --git a/code/modules/random_map/noise/noise.dm b/code/modules/random_map/noise/noise.dm new file mode 100644 index 00000000..daecfdf6 --- /dev/null +++ b/code/modules/random_map/noise/noise.dm @@ -0,0 +1,167 @@ +// NOTE: Maps generated with this datum as the base are not DIRECTLY compatible with maps generated from +// the automata, building or maze datums, as the noise generator uses 0-255 instead of WALL_CHAR/FLOOR_CHAR. +// TODO: Consider writing a conversion proc for noise-to-regular maps. +/datum/random_map/noise + descriptor = "distribution map" + var/cell_range = 255 // These values are used to seed ore values rather than to determine a turf type. + var/cell_smooth_amt = 5 + var/random_variance_chance = 25 // % chance of applying random_element. + var/random_element = 0.5 // Determines the variance when smoothing out cell values. + var/cell_base // Set in New() + var/initial_cell_range // Set in New() + var/smoothing_iterations = 0 + +/datum/random_map/noise/New() + initial_cell_range = cell_range/5 + cell_base = cell_range/2 + ..() + +/datum/random_map/noise/set_map_size() + // Make sure the grid is a square with limits that are + // (n^2)+1, otherwise diamond-square won't work. + if(!IsPowerOfTwo((limit_x-1))) + limit_x = RoundUpToPowerOfTwo(limit_x) + 1 + if(!IsPowerOfTwo((limit_y-1))) + limit_y = RoundUpToPowerOfTwo(limit_y) + 1 + // Sides must be identical lengths. + if(limit_x > limit_y) + limit_y = limit_x + else if(limit_y > limit_x) + limit_x = limit_y + ..() + +// Diamond-square algorithm. +/datum/random_map/noise/seed_map() + // Instantiate the grid. + for(var/x = 1, x <= limit_x, x++) + for(var/y = 1, y <= limit_y, y++) + map[TRANSLATE_COORD(x,y)] = 0 + + // Now dump in the actual random data. + map[TRANSLATE_COORD(1,1)] = cell_base+rand(initial_cell_range) + map[TRANSLATE_COORD(1,limit_y)] = cell_base+rand(initial_cell_range) + map[TRANSLATE_COORD(limit_x,limit_y)] = cell_base+rand(initial_cell_range) + map[TRANSLATE_COORD(limit_x,1)] = cell_base+rand(initial_cell_range) + +/datum/random_map/noise/generate_map() + // Begin recursion. + subdivide(1,1,1,(limit_y-1)) + +/datum/random_map/noise/get_map_char(var/value) + var/val = min(9,max(0,round((value/cell_range)*10))) + if(isnull(val)) val = 0 + return "[val]" + +/datum/random_map/noise/proc/subdivide(var/iteration,var/x,var/y,var/input_size) + + var/isize = input_size + var/hsize = round(input_size/2) + + /* + (x,y+isize)----(x+hsize,y+isize)----(x+size,y+isize) + | | | + | | | + | | | + (x,y+hsize)----(x+hsize,y+hsize)----(x+isize,y) + | | | + | | | + | | | + (x,y)----------(x+hsize,y)----------(x+isize,y) + */ + // Central edge values become average of corners. + map[TRANSLATE_COORD(x+hsize,y+isize)] = round((\ + map[TRANSLATE_COORD(x,y+isize)] + \ + map[TRANSLATE_COORD(x+isize,y+isize)] \ + )/2) + + map[TRANSLATE_COORD(x+hsize,y)] = round(( \ + map[TRANSLATE_COORD(x,y)] + \ + map[TRANSLATE_COORD(x+isize,y)] \ + )/2) + + map[get_map_cell(x,y+hsize)] = round(( \ + map[TRANSLATE_COORD(x,y+isize)] + \ + map[TRANSLATE_COORD(x,y)] \ + )/2) + + map[TRANSLATE_COORD(x+isize,y+hsize)] = round(( \ + map[TRANSLATE_COORD(x+isize,y+isize)] + \ + map[TRANSLATE_COORD(x+isize,y)] \ + )/2) + + // Centre value becomes the average of all other values + possible random variance. + var/current_cell = TRANSLATE_COORD(x+hsize,y+hsize) + map[current_cell] = round(( \ + map[TRANSLATE_COORD(x+hsize,y+isize)] + \ + map[TRANSLATE_COORD(x+hsize,y)] + \ + map[TRANSLATE_COORD(x,y+hsize)] + \ + map[TRANSLATE_COORD(x+isize,y)] \ + )/4) + + if(prob(random_variance_chance)) + map[current_cell] *= (rand(1,2)==1 ? (1.0-random_element) : (1.0+random_element)) + map[current_cell] = max(0,min(cell_range,map[current_cell])) + + // Recurse until size is too small to subdivide. + if(isize>3) + if(!priority_process) + CHECK_TICK + iteration++ + subdivide(iteration, x, y, hsize) + subdivide(iteration, x+hsize, y, hsize) + subdivide(iteration, x, y+hsize, hsize) + subdivide(iteration, x+hsize, y+hsize, hsize) + +/datum/random_map/noise/cleanup() + var/is_not_border_left + var/is_not_border_right + for(var/i = 1 to smoothing_iterations) + var/list/next_map[limit_x*limit_y] + for(var/x = 1 to limit_x) + for(var/y = 1 to limit_y) + var/current_cell = TRANSLATE_COORD(x,y) + next_map[current_cell] = map[current_cell] + var/val_count = 1 + var/total = map[current_cell] + + is_not_border_left = (x != 1) + is_not_border_right = (x != limit_x) + + // Center row. Center value's already been done above. + if (is_not_border_left) + total += map[TRANSLATE_COORD(x - 1, y)] + ++val_count + if (is_not_border_right) + total += map[TRANSLATE_COORD(x + 1, y)] + ++val_count + + if (y != 1) // top row + total += map[TRANSLATE_COORD(x, y - 1)] + ++val_count + if (is_not_border_left) + total += map[TRANSLATE_COORD(x - 1, y - 1)] + ++val_count + if (is_not_border_right) + total += map[TRANSLATE_COORD(x + 1, y - 1)] + ++val_count + + if (y != limit_y) // bottom row + total += map[TRANSLATE_COORD(x, y + 1)] + ++val_count + if (is_not_border_left) + total += map[TRANSLATE_COORD(x - 1, y + 1)] + ++val_count + if (is_not_border_right) + total += map[TRANSLATE_COORD(x + 1, y + 1)] + ++val_count + + total = round(total/val_count) + + if(abs(map[current_cell]-total) <= cell_smooth_amt) + map[current_cell] = total + else if(map[current_cell] < total) + map[current_cell]+=cell_smooth_amt + else if(map[current_cell] < total) + map[current_cell]-=cell_smooth_amt + map[current_cell] = max(0,min(cell_range,map[current_cell])) + map = next_map \ No newline at end of file diff --git a/code/modules/random_map/noise/ore.dm b/code/modules/random_map/noise/ore.dm new file mode 100644 index 00000000..909d4298 --- /dev/null +++ b/code/modules/random_map/noise/ore.dm @@ -0,0 +1,95 @@ +/datum/random_map/noise/ore + descriptor = "ore distribution map" + var/deep_val = 0.8 // Threshold for deep metals, set in new as percentage of cell_range. + var/rare_val = 0.7 // Threshold for rare metal, set in new as percentage of cell_range. + var/chunk_size = 4 // Size each cell represents on map + +/datum/random_map/noise/ore/New(var/seed, var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/never_be_priority = 0) + rare_val = cell_range * rare_val + deep_val = cell_range * deep_val + ..(seed, tx, ty, tz, (tlx / chunk_size), (tly / chunk_size), do_not_apply, do_not_announce, never_be_priority) + +/datum/random_map/noise/ore/check_map_sanity() + + var/rare_count = 0 + var/surface_count = 0 + var/deep_count = 0 + + // Increment map sanity counters. + for(var/value in map) + if(value < rare_val) + surface_count++ + else if(value < deep_val) + rare_count++ + else + deep_count++ + + var/num_chunks = surface_count + rare_count + deep_count + + // Sanity check. + if(surface_count < (MIN_SURFACE_COUNT_PER_CHUNK * num_chunks)) + admin_notice("Insufficient surface minerals. Rerolling...", R_DEBUG) + return 0 + else if(rare_count < (MIN_RARE_COUNT_PER_CHUNK * num_chunks)) + admin_notice("Insufficient rare minerals. Rerolling...", R_DEBUG) + return 0 + else if(deep_count < (MIN_DEEP_COUNT_PER_CHUNK * num_chunks)) + admin_notice("Insufficient deep minerals. Rerolling...", R_DEBUG) + return 0 + else + return 1 + +/datum/random_map/noise/ore/apply_to_turf(var/x,var/y) + + var/tx = ((origin_x-1)+x)*chunk_size + var/ty = ((origin_y-1)+y)*chunk_size + + for(var/i=0,i~" + if(1) + return "~" + if(2) + return "~" + if(3) + return "[pick(list(".",","))]" + if(4) + return "[pick(list(".",","))]" + if(5) + return "[pick(list(".",","))]" + if(6) + return "[pick(list(".",","))]" + if(7) + return "[pick(list("T","t"))]" + if(8) + return "[pick(list("T","t"))]" + if(9) + return "[pick(list("T","t"))]" + +/datum/random_map/noise/tundra/get_appropriate_path(var/value) + var/val = min(9,max(0,round((value/cell_range)*10))) + if(isnull(val)) val = 0 + switch(val) + if(0 to 4) + return /turf/simulated/floor/beach/water/ocean + else + return /turf/simulated/floor/snow + +/datum/random_map/noise/tundra/get_additional_spawns(var/value, var/turf/T) + var/val = min(9,max(0,round((value/cell_range)*10))) + if(isnull(val)) val = 0 + switch(val) + if(2) + if(prob(5)) + new /mob/living/simple_animal/crab(T) + if(6) + if(prob(60)) + var/grass_path = pick(typesof(/obj/structure/flora/grass)-/obj/structure/flora/grass) + new grass_path(T) + if(prob(5)) + var/mob_type = pick(list(/mob/living/simple_animal/lizard, /mob/living/simple_animal/mouse)) + new mob_type(T) + if(7) + if(prob(60)) + new /obj/structure/flora/bush(T) + else if(prob(30)) + new /obj/structure/flora/tree/pine(T) + else if(prob(20)) + new /obj/structure/flora/tree/dead(T) + if(8) + if(prob(70)) + new /obj/structure/flora/tree/pine(T) + else if(prob(30)) + new /obj/structure/flora/tree/dead(T) + else + new /obj/structure/flora/bush(T) + if(9) + new /obj/structure/flora/tree/pine(T) diff --git a/code/modules/random_map/random_map.dm b/code/modules/random_map/random_map.dm new file mode 100644 index 00000000..84b16c33 --- /dev/null +++ b/code/modules/random_map/random_map.dm @@ -0,0 +1,210 @@ +// Generates cave systems for the asteroid, and places ore tiles. +var/global/list/random_maps = list() +var/global/list/map_count = list() + +/datum/random_map + + // Strings. + var/name // Set in New() + var/descriptor = "random map" // Display name. + + // Locator/value vars. + var/initial_wall_cell = 100 // % Chance that a cell will be seeded as a wall. + var/max_attempts = 5 // Fail if a sane map isn't generated by this point. + var/origin_x = 1 // Origin point, left. + var/origin_y = 1 // Origin point, bottom. + var/origin_z = 1 // Target Z-level. + var/limit_x = 128 // Default x size. + var/limit_y = 128 // Default y size. + var/auto_apply = 1 + var/preserve_map = 1 + + // Turf paths. + var/wall_type = /turf/simulated/wall + var/floor_type = /turf/simulated/floor + var/target_turf_type + + // Storage for the final iteration of the map. + var/list/map = list() // Actual map. + + // If set, all sleep(-1) calls will be skipped. + // Test to see if rand_seed() can be used reliably. + var/priority_process + +/datum/random_map/New(var/seed, var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/never_be_priority = 0) + + // Store this for debugging. + if(!map_count[descriptor]) + map_count[descriptor] = 1 + else + map_count[descriptor]++ + name = "[descriptor] #[map_count[descriptor]]" + if(preserve_map) random_maps[name] = src + + // Get origins for applying the map later. + set_origins(tx, ty, tz) + if(tlx) limit_x = tlx + if(tly) limit_y = tly + + if(do_not_apply) + auto_apply = null + + // Initialize map. + set_map_size() + + var/start_time = world.timeofday + if(!do_not_announce) admin_notice("Generating [name].", R_DEBUG) + CHECK_TICK + + // Testing needed to see how reliable this is (asynchronous calls, called during worldgen), DM ref is not optimistic + if(seed) + rand_seed(seed) + priority_process = !never_be_priority + + for(var/i = 0;i[capitalize(name)] generation completed in [round(0.1*(world.timeofday-start_time),0.1)] seconds.", R_DEBUG) + return + if(!do_not_announce) admin_notice("[capitalize(name)] failed to generate ([round(0.1*(world.timeofday-start_time),0.1)] seconds): could not produce sane map.", R_DEBUG) + +/datum/random_map/proc/get_map_cell(var/x,var/y) + if(!map) + set_map_size() + . = ((y-1)*limit_x)+x + if((. < 1) || (. > map.len)) + return null + +/datum/random_map/proc/get_map_char(var/value) + switch(value) + if(WALL_CHAR) + return "#" + if(FLOOR_CHAR) + return "." + if(DOOR_CHAR) + return "D" + if(ROOM_TEMP_CHAR) + return "+" + if(MONSTER_CHAR) + return "M" + if(ARTIFACT_TURF_CHAR) + return "_" + if(ARTIFACT_CHAR) + return "A" + else + return " " + +/datum/random_map/proc/display_map(atom/user) + + if(!user) + user = world + + var/dat = "+------+
            " + for(var/x = 1, x <= limit_x, x++) + for(var/y = 1, y <= limit_y, y++) + var/current_cell = get_map_cell(x,y) + if(current_cell) + dat += get_map_char(map[current_cell]) + dat += "
            " + to_chat(user, "[dat]+------+
            ") + +/datum/random_map/proc/set_map_size() + map = list() + map.len = limit_x * limit_y + +/datum/random_map/proc/seed_map() + for(var/x = 1, x <= limit_x, x++) + for(var/y = 1, y <= limit_y, y++) + var/current_cell = get_map_cell(x,y) + if(prob(initial_wall_cell)) + map[current_cell] = WALL_CHAR + else + map[current_cell] = FLOOR_CHAR + +/datum/random_map/proc/clear_map() + for(var/x = 1, x <= limit_x, x++) + for(var/y = 1, y <= limit_y, y++) + map[get_map_cell(x,y)] = 0 + +/datum/random_map/proc/generate() + seed_map() + generate_map() + if(check_map_sanity()) + cleanup() + if(auto_apply) + apply_to_map() + return 1 + return 0 + +// Unused for basic map. +/datum/random_map/proc/generate_map() + return 1 + +/datum/random_map/proc/check_map_sanity() + return 1 + +/datum/random_map/proc/set_origins(var/tx, var/ty, var/tz) + origin_x = tx ? tx : 1 + origin_y = ty ? ty : 1 + origin_z = tz ? tz : 1 + +/datum/random_map/proc/apply_to_map() + if(!origin_x) origin_x = 1 + if(!origin_y) origin_y = 1 + if(!origin_z) origin_z = 1 + + for(var/x = 1, x <= limit_x, x++) + for(var/y = 1, y <= limit_y, y++) + if(!priority_process) + CHECK_TICK + apply_to_turf(x,y) + +/datum/random_map/proc/apply_to_turf(var/x,var/y) + var/current_cell = get_map_cell(x,y) + if(!current_cell) + return 0 + var/turf/T = locate((origin_x-1)+x,(origin_y-1)+y,origin_z) + if(!T || (target_turf_type && !istype(T,target_turf_type))) + return 0 + var/newpath = get_appropriate_path(map[current_cell]) + if(newpath) + T.ChangeTurf(newpath) + get_additional_spawns(map[current_cell],T,get_spawn_dir(x, y)) + return T + +/datum/random_map/proc/get_spawn_dir() + return 0 + +/datum/random_map/proc/get_appropriate_path(var/value) + switch(value) + if(FLOOR_CHAR) + return floor_type + if(WALL_CHAR) + return wall_type + +/datum/random_map/proc/get_additional_spawns(var/value, var/turf/T) + if(value == DOOR_CHAR) + new /obj/machinery/door/airlock(T) + +/datum/random_map/proc/cleanup() + return + +/datum/random_map/proc/overlay_with(var/datum/random_map/target_map, var/tx, var/ty) + if(!map.len || !istype(target_map)) + return + tx-- // Update origin so that x/y index + ty-- // doesn't push it off-kilter by one. + for(var/x = 1, x <= limit_x, x++) + for(var/y = 1, y <= limit_y, y++) + var/current_cell = get_map_cell(x,y) + if(!current_cell) + continue + if(tx+x > target_map.limit_x) + continue + if(ty+y > target_map.limit_y) + continue + target_map.map[target_map.get_map_cell(tx+x,ty+y)] = map[current_cell] + handle_post_overlay_on(target_map,tx,ty) + + +/datum/random_map/proc/handle_post_overlay_on(var/datum/random_map/target_map, var/tx, var/ty) + return diff --git a/code/modules/random_map/random_map_verbs.dm b/code/modules/random_map/random_map_verbs.dm new file mode 100644 index 00000000..f94bcd45 --- /dev/null +++ b/code/modules/random_map/random_map_verbs.dm @@ -0,0 +1,108 @@ +/client/proc/print_random_map() + set category = "Debug" + set name = "Display Random Map" + set desc = "Show the contents of a random map." + + if(!holder) return + + var/choice = input("Choose a map to display.") as null|anything in random_maps + if(!choice) + return + var/datum/random_map/M = random_maps[choice] + if(istype(M)) + M.display_map(usr) + +/client/proc/delete_random_map() + set category = "Debug" + set name = "Delete Random Map" + set desc = "Delete a random map." + + if(!holder) return + + var/choice = input("Choose a map to delete.") as null|anything in random_maps + if(!choice) + return + var/datum/random_map/M = random_maps[choice] + random_maps[choice] = null + if(istype(M)) + message_admins("[key_name_admin(usr)] has deleted [M.name].") + log_admin("[key_name(usr)] has deleted [M.name].") + qdel(M) + +/client/proc/create_random_map() + set category = "Debug" + set name = "Create Random Map" + set desc = "Create a random map." + + if(!holder) return + + var/map_datum = input("Choose a map to create.") as null|anything in typesof(/datum/random_map)-/datum/random_map + if(!map_datum) + return + + var/datum/random_map/M + if(alert("Do you wish to customise the map?",,"Yes","No") == "Yes") + var/seed = input("Seed? (blank for none)") as text|null + var/lx = input("X-size? (blank for default)") as num|null + var/ly = input("Y-size? (blank for default)") as num|null + M = new map_datum(seed,null,null,null,lx,ly,1) + else + M = new map_datum(null,null,null,null,null,null,1) + + if(M) + message_admins("[key_name_admin(usr)] has created [M.name].") + log_admin("[key_name(usr)] has created [M.name].") + +/client/proc/apply_random_map() + set category = "Debug" + set name = "Apply Random Map" + set desc = "Apply a map to the game world." + + if(!holder) return + + var/choice = input("Choose a map to apply.") as null|anything in random_maps + if(!choice) + return + var/datum/random_map/M = random_maps[choice] + if(istype(M)) + var/tx = input("X? (default to current turf)") as num|null + var/ty = input("Y? (default to current turf)") as num|null + var/tz = input("Z? (default to current turf)") as num|null + if(isnull(tx) || isnull(ty) || isnull(tz)) + var/turf/T = get_turf(usr) + tx = !isnull(tx) ? tx : T.x + ty = !isnull(ty) ? ty : T.y + tz = !isnull(tz) ? tz : T.z + message_admins("[key_name_admin(usr)] has applied [M.name] at x[tx],y[ty],z[tz].") + log_admin("[key_name(usr)] has applied [M.name] at x[tx],y[ty],z[tz].") + M.set_origins(tx,ty,tz) + M.apply_to_map() + +/client/proc/overlay_random_map() + set category = "Debug" + set name = "Overlay Random Map" + set desc = "Apply a map to another map." + + if(!holder) return + + var/choice = input("Choose a map as base.") as null|anything in random_maps + if(!choice) + return + var/datum/random_map/base_map = random_maps[choice] + + choice = null + choice = input("Choose a map to overlay.") as null|anything in random_maps + if(!choice) + return + + var/datum/random_map/overlay_map = random_maps[choice] + + if(istype(base_map) && istype(overlay_map)) + var/tx = input("X? (default to 1)") as num|null + var/ty = input("Y? (default to 1)") as num|null + if(!tx) tx = 1 + if(!ty) ty = 1 + message_admins("[key_name_admin(usr)] has applied [overlay_map.name] to [base_map.name] at x[tx],y[ty].") + log_admin("[key_name(usr)] has applied [overlay_map.name] to [base_map.name] at x[tx],y[ty].") + overlay_map.overlay_with(base_map,tx,ty) + base_map.display_map(usr) diff --git a/code/modules/reagents/Chemistry-Colours.dm b/code/modules/reagents/Chemistry-Colours.dm new file mode 100644 index 00000000..b2b1c15d --- /dev/null +++ b/code/modules/reagents/Chemistry-Colours.dm @@ -0,0 +1,23 @@ +/datum/reagents/proc/get_color()//Does this work? + if(!reagent_list || !reagent_list.len) + return "#ffffffff" + if(reagent_list.len == 1) // It's pretty common and saves a lot of work + var/datum/reagent/R = reagent_list[1] + return R.color + + var/list/colors = list(0, 0, 0, 0) + var/tot_w = 0 + for(var/datum/reagent/R in reagent_list) + var/hex = uppertext(R.color) + if(length(hex) == 7) + hex += "FF" + if(length(hex) != 9) // PANIC PANIC PANIC + warning("Reagent [R.type] has an incorrect color set ([R.color])") + hex = "#ffffffFF" + colors[1] += hex2num(copytext(hex, 2, 4)) * R.volume * R.color_weight + colors[2] += hex2num(copytext(hex, 4, 6)) * R.volume * R.color_weight + colors[3] += hex2num(copytext(hex, 6, 8)) * R.volume * R.color_weight + colors[4] += hex2num(copytext(hex, 8, 10)) * R.volume * R.color_weight + tot_w += R.volume * R.color_weight + + return rgb(colors[1] / tot_w, colors[2] / tot_w, colors[3] / tot_w, colors[4] / tot_w) \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm new file mode 100644 index 00000000..48afe9ee --- /dev/null +++ b/code/modules/reagents/Chemistry-Holder.dm @@ -0,0 +1,415 @@ +GLOBAL_DATUM_INIT(temp_reagents_holder, /obj, new) + +/datum/reagents + var/list/datum/reagent/reagent_list = list() + var/total_volume = 0 + var/maximum_volume = 120 + var/atom/my_atom = null + +/datum/reagents/New(var/maximum_volume = 120, var/atom/my_atom) + if(!istype(my_atom)) + CRASH("Invalid reagents holder: [log_info_line(my_atom)]") + ..() + src.my_atom = my_atom + src.maximum_volume = maximum_volume + +/datum/reagents/Destroy() + . = ..() + + QDEL_NULL_LIST(reagent_list) + my_atom = null + +/* Internal procs */ + +/datum/reagents/proc/get_free_space() // Returns free space. + return maximum_volume - total_volume + +/datum/reagents/proc/get_master_reagent() // Returns reference to the reagent with the biggest volume. + var/the_reagent = null + var/the_volume = 0 + + for(var/datum/reagent/A in reagent_list) + if(A.volume > the_volume) + the_volume = A.volume + the_reagent = A + + return the_reagent + +/datum/reagents/proc/get_master_reagent_name() // Returns the name of the reagent with the biggest volume. + var/the_name = null + var/the_volume = 0 + for(var/datum/reagent/A in reagent_list) + if(A.volume > the_volume) + the_volume = A.volume + the_name = A.name + + return the_name + +/datum/reagents/proc/get_master_reagent_type() // Returns the type of the reagent with the biggest volume. + var/the_type = null + var/the_volume = 0 + for(var/datum/reagent/A in reagent_list) + if(A.volume > the_volume) + the_volume = A.volume + the_type = A.type + + return the_type + +/datum/reagents/proc/update_total() // Updates volume. + total_volume = 0 + for(var/datum/reagent/R in reagent_list) + if(R.volume < MINIMUM_CHEMICAL_VOLUME) + del_reagent(R.type) + else + total_volume += R.volume + return + +/datum/reagents/proc/process_reactions() + if(!my_atom) // No reactions in temporary holders + return 0 + if(!my_atom.loc) //No reactions inside GC'd containers + return 0 + if(my_atom.atom_flags & ATOM_FLAG_NO_REACT) // No reactions here + return 0 + + var/reaction_occured = 0 + + var/list/datum/chemical_reaction/eligible_reactions = list() + + for(var/datum/reagent/R in reagent_list) + eligible_reactions |= chemical_reactions_list[R.type] + + var/list/datum/chemical_reaction/active_reactions = list() + + for(var/datum/chemical_reaction/C in eligible_reactions) + if(C.can_happen(src)) + active_reactions |= C + reaction_occured = 1 + + var/list/used_reagents = list() + for(var/datum/chemical_reaction/C in active_reactions) + var/list/adding = C.get_used_reagents() + for(var/R in adding) + used_reagents[R] += 1 + + var/max_split = 1 + for(var/R in used_reagents) + if(used_reagents[R] > max_split) + max_split = used_reagents[R] + + for(var/datum/chemical_reaction/C in active_reactions) + C.process(src, max_split, total_volume) + --max_split + + for(var/datum/chemical_reaction/C in active_reactions) + C.post_reaction(src) + + update_total() + + if(reaction_occured) + process_reactions() // Check again in case the new reagents can react again + + return reaction_occured + +/* Holder-to-chemical */ + +/datum/reagents/proc/add_reagent(var/reagent_type, var/amount, var/data = null, var/safety = 0) + if(!isnum(amount) || amount <= 0) + return 0 + + update_total() + amount = min(amount, get_free_space()) + + for(var/datum/reagent/current in reagent_list) + if(current.type == reagent_type) + current.volume += amount + if(!isnull(data)) // For all we know, it could be zero or empty string and meaningful + current.mix_data(data, amount) + update_total() + if(!safety) + process_reactions() + if(my_atom) + my_atom.on_reagent_change() + return 1 + if(ispath(reagent_type, /datum/reagent)) + var/datum/reagent/R = new reagent_type(src) + reagent_list += R + R.volume = amount + R.initialize_data(data) + update_total() + if(!safety) + process_reactions() + if(my_atom) + my_atom.on_reagent_change() + return 1 + else + warning("[log_info_line(my_atom)] attempted to add a reagent of type '[reagent_type]' which doesn't exist. ([usr])") + return 0 + +/datum/reagents/proc/remove_reagent(var/reagent_type, var/amount, var/safety = 0) + if(!isnum(amount)) + return 0 + for(var/datum/reagent/current in reagent_list) + if(current.type == reagent_type) + current.volume -= amount // It can go negative, but it doesn't matter + update_total() // Because this proc will delete it then + if(!safety) + process_reactions() + if(my_atom) + my_atom.on_reagent_change() + return 1 + return 0 + +/datum/reagents/proc/del_reagent(var/reagent_type) + for(var/datum/reagent/current in reagent_list) + if (current.type == reagent_type) + reagent_list -= current + qdel(current) + update_total() + if(my_atom) + my_atom.on_reagent_change() + return 0 + +/datum/reagents/proc/has_reagent(var/reagent_type, var/amount = null) + for(var/datum/reagent/current in reagent_list) + if(current.type == reagent_type) + if((isnull(amount) && current.volume > 0) || current.volume >= amount) + return 1 + else + return 0 + return 0 + +/datum/reagents/proc/has_any_reagent(var/list/check_reagents) + for(var/datum/reagent/current in reagent_list) + if(current.type in check_reagents) + if(current.volume >= check_reagents[current.type]) + return 1 + else + return 0 + return 0 + +/datum/reagents/proc/has_all_reagents(var/list/check_reagents) + //this only works if check_reagents has no duplicate entries... hopefully okay since it expects an associative list + var/missing = check_reagents.len + for(var/datum/reagent/current in reagent_list) + if(current.type in check_reagents) + if(current.volume >= check_reagents[current.type]) + missing-- + return !missing + +/datum/reagents/proc/clear_reagents() + for(var/datum/reagent/current in reagent_list) + del_reagent(current.type) + return + +/datum/reagents/proc/get_reagent_amount(var/reagent_type) + for(var/datum/reagent/current in reagent_list) + if(current.type == reagent_type) + return current.volume + return 0 + +/datum/reagents/proc/get_data(var/reagent_type) + for(var/datum/reagent/current in reagent_list) + if(current.type == reagent_type) + return current.get_data() + return 0 + +/datum/reagents/proc/get_overdose(var/datum/reagent/current) + if(current) + return initial(current.overdose) + return 0 + +/datum/reagents/proc/get_reagents() + . = list() + for(var/datum/reagent/current in reagent_list) + . += "[current.type] ([current.volume])" + return english_list(., "EMPTY", "", ", ", ", ") + +/* Holder-to-holder and similar procs */ + +/datum/reagents/proc/remove_any(var/amount = 1) // Removes up to [amount] of reagents from [src]. Returns actual amount removed. + amount = min(amount, total_volume) + + if(!amount) + return + + var/part = amount / total_volume + + for(var/datum/reagent/current in reagent_list) + var/amount_to_remove = current.volume * part + remove_reagent(current.type, amount_to_remove, 1) + + update_total() + process_reactions() + return amount + +/datum/reagents/proc/trans_to_holder(var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Transfers [amount] reagents from [src] to [target], multiplying them by [multiplier]. Returns actual amount removed from [src] (not amount transferred to [target]). + if(!target || !istype(target)) + return + + amount = max(0, min(amount, total_volume, target.get_free_space() / multiplier)) + + if(!amount) + return + + var/part = amount / total_volume + + for(var/datum/reagent/current in reagent_list) + var/amount_to_transfer = current.volume * part + target.add_reagent(current.type, amount_to_transfer * multiplier, current.get_data(), safety = 1) // We don't react until everything is in place + if(!copy) + remove_reagent(current.type, amount_to_transfer, 1) + + if(!copy) + process_reactions() + target.process_reactions() + return amount + +/* Holder-to-atom and similar procs */ + +//The general proc for applying reagents to things. This proc assumes the reagents are being applied externally, +//not directly injected into the contents. It first calls touch, then the appropriate trans_to_*() or splash_mob(). +//If for some reason touch effects are bypassed (e.g. injecting stuff directly into a reagent container or person), +//call the appropriate trans_to_*() proc. +/datum/reagents/proc/trans_to(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0) + touch(target) //First, handle mere touch effects + + if(ismob(target)) + return splash_mob(target, amount, copy) + if(isturf(target)) + return trans_to_turf(target, amount, multiplier, copy) + if(isobj(target) && target.is_open_container()) + return trans_to_obj(target, amount, multiplier, copy) + return 0 + +//Splashing reagents is messier than trans_to, the target's loc gets some of the reagents as well. +/datum/reagents/proc/splash(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0, var/min_spill=0, var/max_spill=60) + var/spill = 0 + if(!isturf(target) && target.loc) + spill = amount*(rand(min_spill, max_spill)/100) + amount -= spill + if(spill) + splash(target.loc, spill, multiplier, copy, min_spill, max_spill) + + trans_to(target, amount, multiplier, copy) + +/datum/reagents/proc/trans_type_to(var/atom/target, var/type, var/amount = 1) + if (!target || !target.reagents || !target.simulated) + return + + amount = min(amount, get_reagent_amount(type)) + + if(!amount) + return + + var/datum/reagents/F = new /datum/reagents(amount, GLOB.temp_reagents_holder) + var/tmpdata = get_data(type) + F.add_reagent(type, amount, tmpdata) + remove_reagent(type, amount) + + . = F.trans_to(target, amount) // Let this proc check the atom's type + + qdel(F) + +// When applying reagents to an atom externally, touch() is called to trigger any on-touch effects of the reagent. +// This does not handle transferring reagents to things. +// For example, splashing someone with water will get them wet and extinguish them if they are on fire, +// even if they are wearing an impermeable suit that prevents the reagents from contacting the skin. +/datum/reagents/proc/touch(var/atom/target) + if(ismob(target)) + touch_mob(target) + if(isturf(target)) + touch_turf(target) + if(isobj(target)) + touch_obj(target) + return + +/datum/reagents/proc/touch_mob(var/mob/target) + if(!target || !istype(target) || !target.simulated) + return + + for(var/datum/reagent/current in reagent_list) + current.touch_mob(target, current.volume) + + update_total() + +/datum/reagents/proc/touch_turf(var/turf/target) + if(!target || !istype(target) || !target.simulated) + return + + for(var/datum/reagent/current in reagent_list) + current.touch_turf(target, current.volume) + + update_total() + +/datum/reagents/proc/touch_obj(var/obj/target) + if(!target || !istype(target) || !target.simulated) + return + + for(var/datum/reagent/current in reagent_list) + current.touch_obj(target, current.volume) + + update_total() + +// Attempts to place a reagent on the mob's skin. +// Reagents are not guaranteed to transfer to the target. +// Do not call this directly, call trans_to() instead. +/datum/reagents/proc/splash_mob(var/mob/target, var/amount = 1, var/copy = 0) + var/perm = 1 + if(isliving(target)) //will we ever even need to tranfer reagents to non-living mobs? + var/mob/living/L = target + perm = L.reagent_permeability() + return trans_to_mob(target, amount * perm, CHEM_TOUCH, 1, 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) + return + if(iscarbon(target)) + var/mob/living/carbon/C = target + if(type == CHEM_BLOOD) + var/datum/reagents/R = C.reagents + return trans_to_holder(R, amount, multiplier, copy) + if(type == CHEM_INGEST) + var/datum/reagents/R = C.ingested + return C.ingest(src,R, amount, multiplier, copy) //perhaps this is a bit of a hack, but currently there's no common proc for eating reagents + if(type == CHEM_TOUCH) + var/datum/reagents/R = C.touching + return trans_to_holder(R, amount, multiplier, copy) + else + var/datum/reagents/R = new /datum/reagents(amount, GLOB.temp_reagents_holder) + . = trans_to_holder(R, amount, multiplier, copy) + R.touch_mob(target) + qdel(R) + +/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) + return + + var/datum/reagents/R = new /datum/reagents(amount * multiplier, GLOB.temp_reagents_holder) + . = trans_to_holder(R, amount, multiplier, copy) + R.touch_turf(target) + qdel(R) + return + +/datum/reagents/proc/trans_to_obj(var/obj/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) + return + + if(!target.reagents) + var/datum/reagents/R = new /datum/reagents(amount * multiplier, GLOB.temp_reagents_holder) + . = trans_to_holder(R, amount, multiplier, copy) + R.touch_obj(target) + qdel(R) + return + + return trans_to_holder(target.reagents, amount, multiplier, copy) + +/* Atom reagent creation - use it all the time */ + +/atom/proc/create_reagents(var/max_vol) + if(reagents) + log_debug("Attempted to create a new reagents holder when already referencing one: [log_info_line(src)]") + reagents.maximum_volume = max(reagents.maximum_volume, max_vol) + else + reagents = new/datum/reagents(max_vol, src) + return reagents diff --git a/code/modules/reagents/Chemistry-Logging.dm b/code/modules/reagents/Chemistry-Logging.dm new file mode 100644 index 00000000..1432b18a --- /dev/null +++ b/code/modules/reagents/Chemistry-Logging.dm @@ -0,0 +1,28 @@ + +/var/list/chemical_reaction_logs = list() + +/proc/log_chemical_reaction(atom/A, datum/chemical_reaction/R, multiplier) + if(!A || !R) + return + + var/turf/T = get_turf(A) + var/logstr = "[usr ? key_name(usr) : "EVENT"] mixed [R.name] ([R.result]) (x[multiplier]) in \the [A] at [T ? "[T.x],[T.y],[T.z]" : "*null*"]" + + chemical_reaction_logs += "\[[time_stamp()]\] [logstr]" + + if(R.log_is_important) + message_admins(logstr) + log_admin(logstr) + +/client/proc/view_chemical_reaction_logs() + set name = "Show Chemical Reactions" + set category = "Admin" + + if(!check_rights(R_ADMIN)) + return + + var/html = "" + for(var/entry in chemical_reaction_logs) + html += "[entry]
            " + + usr << browse(html, "window=chemlogs") diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm new file mode 100644 index 00000000..35dddc79 --- /dev/null +++ b/code/modules/reagents/Chemistry-Machinery.dm @@ -0,0 +1,533 @@ +#define BOTTLE_SPRITES list("bottle-1", "bottle-2", "bottle-3", "bottle-4") //list of available bottle sprites +#define REAGENTS_PER_SHEET 20 + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/obj/machinery/chem_master + name = "ChemMaster 3000" + density = 1 + anchored = 1 + icon = 'icons/obj/chemical.dmi' + icon_state = "mixer0" + use_power = 1 + idle_power_usage = 20 + clicksound = "button" + clickvol = 20 + var/beaker = null + var/obj/item/weapon/storage/pill_bottle/loaded_pill_bottle = null + var/mode = 0 + var/condi = 0 + var/useramount = 30 // Last used amount + var/pillamount = 10 + var/bottlesprite = "bottle-1" //yes, strings + var/pillsprite = "1" + var/client/has_sprites = list() + var/max_pill_count = 20 + atom_flags = ATOM_FLAG_OPEN_CONTAINER + +/obj/machinery/chem_master/New() + create_reagents(120) + ..() + +/obj/machinery/chem_master/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + if (prob(50)) + qdel(src) + return + +/obj/machinery/chem_master/attackby(var/obj/item/weapon/B as obj, var/mob/user as mob) + + if(istype(B, /obj/item/weapon/reagent_containers/glass)) + if(B.w_class >= ITEM_SIZE_NORMAL) + to_chat(user, "This container is too big for this machine!") + return 1 + if(src.beaker) + to_chat(user, "A beaker is already loaded into the machine.") + return + src.beaker = B + user.drop_item() + B.loc = src + to_chat(user, "You add the beaker to the machine!") + src.updateUsrDialog() + icon_state = "mixer1" + + else if(istype(B, /obj/item/weapon/storage/pill_bottle)) + + if(src.loaded_pill_bottle) + to_chat(user, "A pill bottle is already loaded into the machine.") + return + + src.loaded_pill_bottle = B + user.drop_item() + B.loc = src + to_chat(user, "You add the pill bottle into the dispenser slot!") + src.updateUsrDialog() + return + +/obj/machinery/chem_master/Topic(href, href_list, state) + if(..()) + return 1 + + if (href_list["ejectp"]) + if(loaded_pill_bottle) + loaded_pill_bottle.loc = src.loc + loaded_pill_bottle = null + else if(href_list["close"]) + usr << browse(null, "window=chemmaster") + usr.unset_machine() + return + + if(beaker) + var/datum/reagents/R = beaker:reagents + if (href_list["analyze"]) + var/dat = "" + if(!condi) + if(href_list["name"] == "Blood") + var/datum/reagent/blood/G + for(var/datum/reagent/F in R.reagent_list) + if(F.name == href_list["name"]) + G = F + break + var/A = G.name + var/B = G.data["blood_type"] + var/C = G.data["blood_DNA"] + dat += "Chemmaster 3000Chemical infos:

            Name:
            [A]

            Description:
            Blood Type: [B]
            DNA: [C]


            (Back)" + else + dat += "Chemmaster 3000Chemical infos:

            Name:
            [href_list["name"]]

            Description:
            [href_list["desc"]]


            (Back)" + else + dat += "Condimaster 3000Condiment infos:

            Name:
            [href_list["name"]]

            Description:
            [href_list["desc"]]


            (Back)" + usr << browse(dat, "window=chem_master;size=575x400") + return + + else if (href_list["add"]) + if(href_list["amount"]) + var/datum/reagent/their_reagent = locate(href_list["add"]) in R.reagent_list + if(their_reagent) + var/amount = Clamp((text2num(href_list["amount"])), 0, 200) + R.trans_type_to(src, their_reagent.type, amount) + + else if (href_list["addcustom"]) + var/datum/reagent/their_reagent = locate(href_list["addcustom"]) in R.reagent_list + if(their_reagent) + useramount = input("Select the amount to transfer.", 30, useramount) as null|num + if(useramount) + useramount = Clamp(useramount, 0, 200) + src.Topic(href, list("amount" = "[useramount]", "add" = href_list["addcustom"]), state) + + else if (href_list["remove"]) + if(href_list["amount"]) + var/datum/reagent/my_reagents = locate(href_list["remove"]) in reagents.reagent_list + if(my_reagents) + var/amount = Clamp((text2num(href_list["amount"])), 0, 200) + if(mode) + reagents.trans_type_to(beaker, my_reagents.type, amount) + else + reagents.remove_reagent(my_reagents.type, amount) + + + else if (href_list["removecustom"]) + var/datum/reagent/my_reagents = locate(href_list["removecustom"]) in reagents.reagent_list + if(my_reagents) + useramount = input("Select the amount to transfer.", 30, useramount) as null|num + if(useramount) + useramount = Clamp(useramount, 0, 200) + src.Topic(href, list("amount" = "[useramount]", "remove" = href_list["removecustom"]), state) + + else if (href_list["toggle"]) + mode = !mode + + else if (href_list["main"]) + attack_hand(usr) + return + else if (href_list["eject"]) + if(beaker) + beaker:loc = src.loc + beaker = null + reagents.clear_reagents() + icon_state = "mixer0" + else if (href_list["createpill"] || href_list["createpill_multiple"]) + var/count = 1 + + if(reagents.total_volume/count < 1) //Sanity checking. + return + + if (href_list["createpill_multiple"]) + count = input("Select the number of pills to make.", "Max [max_pill_count]", pillamount) as num + count = Clamp(count, 1, max_pill_count) + + if(reagents.total_volume/count < 1) //Sanity checking. + return + + var/amount_per_pill = reagents.total_volume/count + if (amount_per_pill > 60) amount_per_pill = 60 + + var/name = sanitizeSafe(input(usr,"Name:","Name your pill!","[reagents.get_master_reagent_name()] ([amount_per_pill]u)"), MAX_NAME_LEN) + + if(reagents.total_volume/count < 1) //Sanity checking. + return + while (count-- && count >= 0) + var/obj/item/weapon/reagent_containers/pill/P = new/obj/item/weapon/reagent_containers/pill(src.loc) + if(!name) name = reagents.get_master_reagent_name() + P.SetName("[name] pill") + P.icon_state = "pill"+pillsprite + if(P.icon_state in list("pill1", "pill2", "pill3", "pill4", "pill5")) // if using greyscale, take colour from reagent + P.color = reagents.get_color() + reagents.trans_to_obj(P,amount_per_pill) + if(src.loaded_pill_bottle) + if(loaded_pill_bottle.contents.len < loaded_pill_bottle.max_storage_space) + P.loc = loaded_pill_bottle + src.updateUsrDialog() + + else if (href_list["createbottle"]) + if(!condi) + var/name = sanitizeSafe(input(usr,"Name:","Name your bottle!",reagents.get_master_reagent_name()), MAX_NAME_LEN) + var/obj/item/weapon/reagent_containers/glass/bottle/P = new/obj/item/weapon/reagent_containers/glass/bottle(src.loc) + if(!name) name = reagents.get_master_reagent_name() + P.SetName("[name] bottle") + P.icon_state = bottlesprite + reagents.trans_to_obj(P,60) + P.update_icon() + else + var/obj/item/weapon/reagent_containers/food/condiment/P = new/obj/item/weapon/reagent_containers/food/condiment(src.loc) + reagents.trans_to_obj(P,50) + else if(href_list["change_pill"]) + #define MAX_PILL_SPRITE 25 //max icon state of the pill sprites + var/dat = "" + for(var/i = 1 to MAX_PILL_SPRITE) + dat += "" + dat += "
            " + usr << browse(dat, "window=chem_master") + return + else if(href_list["change_bottle"]) + var/dat = "" + for(var/sprite in BOTTLE_SPRITES) + dat += "" + dat += "
            " + usr << browse(dat, "window=chem_master") + return + else if(href_list["pill_sprite"]) + pillsprite = href_list["pill_sprite"] + else if(href_list["bottle_sprite"]) + bottlesprite = href_list["bottle_sprite"] + + src.updateUsrDialog() + return + +/obj/machinery/chem_master/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/chem_master/attack_hand(mob/user as mob) + if(inoperable()) + return + user.set_machine(src) + if(!(user.client in has_sprites)) + spawn() + has_sprites += user.client + for(var/i = 1 to MAX_PILL_SPRITE) + usr << browse_rsc(icon('icons/obj/chemical.dmi', "pill" + num2text(i)), "pill[i].png") + for(var/sprite in BOTTLE_SPRITES) + usr << browse_rsc(icon('icons/obj/chemical.dmi', sprite), "[sprite].png") + var/dat = "" + if(!beaker) + dat = "Please insert beaker.
            " + if(src.loaded_pill_bottle) + dat += "Eject Pill Bottle \[[loaded_pill_bottle.contents.len]/[loaded_pill_bottle.max_storage_space]\]

            " + else + dat += "No pill bottle inserted.

            " + dat += "Close" + else + var/datum/reagents/R = beaker:reagents + dat += "Eject beaker and Clear Buffer
            " + if(src.loaded_pill_bottle) + dat += "Eject Pill Bottle \[[loaded_pill_bottle.contents.len]/[loaded_pill_bottle.max_storage_space]\]

            " + else + dat += "No pill bottle inserted.

            " + if(!R.total_volume) + dat += "Beaker is empty." + else + dat += "Add to buffer:
            " + for(var/datum/reagent/G in R.reagent_list) + dat += "[G.name] , [G.volume] Units - " + dat += "(Analyze) " + dat += "(1) " + dat += "(5) " + dat += "(10) " + dat += "(All) " + dat += "(Custom)
            " + + dat += "
            Transfer to [(!mode ? "disposal" : "beaker")]:
            " + if(reagents.total_volume) + for(var/datum/reagent/N in reagents.reagent_list) + dat += "[N.name] , [N.volume] Units - " + dat += "(Analyze) " + dat += "(1) " + dat += "(5) " + dat += "(10) " + dat += "(All) " + dat += "(Custom)
            " + else + dat += "Empty
            " + if(!condi) + dat += "

            Create pill (60 units max)
            " + dat += "Create multiple pills
            " + dat += "Create bottle (60 units max)" + else + dat += "Create bottle (50 units max)" + if(!condi) + user << browse("Chemmaster 3000Chemmaster menu:

            [dat]", "window=chem_master;size=575x400") + else + user << browse("Condimaster 3000Condimaster menu:

            [dat]", "window=chem_master;size=575x400") + onclose(user, "chem_master") + return + +/obj/machinery/chem_master/condimaster + name = "CondiMaster 3000" + condi = 1 + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +/obj/machinery/reagentgrinder + + name = "All-In-One Grinder" + icon = 'icons/obj/kitchen.dmi' + icon_state = "juicer1" + layer = BELOW_OBJ_LAYER + density = 0 + anchored = 0 + use_power = 1 + idle_power_usage = 5 + active_power_usage = 100 + var/inuse = 0 + var/obj/item/weapon/reagent_containers/beaker = null + var/limit = 10 + var/list/holdingitems = list() + + //Because of how sheet types are checked, you have to explicitely declare ALL the subpaths. + var/list/sheet_reagents = list( + /obj/item/stack/material/iron = /datum/reagent/iron, + + /obj/item/stack/material/uranium = /datum/reagent/uranium, + /obj/item/stack/material/uranium/ten = /datum/reagent/uranium, + + /obj/item/stack/material/phoron = /datum/reagent/toxin/phoron, + /obj/item/stack/material/phoron/ten = /datum/reagent/toxin/phoron, + /obj/item/stack/material/phoron/fifty = /datum/reagent/toxin/phoron, + + /obj/item/stack/material/gold = /datum/reagent/gold, + /obj/item/stack/material/gold/ten = /datum/reagent/gold, + + /obj/item/stack/material/silver = /datum/reagent/silver, + /obj/item/stack/material/silver/ten = /datum/reagent/silver, + + /obj/item/stack/material/mhydrogen = /datum/reagent/hydrazine, + /obj/item/stack/material/mhydrogen/ten = /datum/reagent/hydrazine + ) + +/obj/machinery/reagentgrinder/New() + ..() + beaker = new /obj/item/weapon/reagent_containers/glass/beaker/large(src) + return + +/obj/machinery/reagentgrinder/update_icon() + icon_state = "juicer"+num2text(!isnull(beaker)) + return + +/obj/machinery/reagentgrinder/attackby(var/obj/item/O as obj, var/mob/user as mob) + + if (istype(O,/obj/item/weapon/reagent_containers/glass) || \ + istype(O,/obj/item/weapon/reagent_containers/food/drinks/glass2) || \ + istype(O,/obj/item/weapon/reagent_containers/food/drinks/shaker)) + if(O.w_class >= ITEM_SIZE_NORMAL) + to_chat(user, "This container is too big for this machine!") + return 1 + if (beaker) + return 1 + else + src.beaker = O + user.drop_item() + O.loc = src + update_icon() + src.updateUsrDialog() + return 0 + + if(holdingitems && holdingitems.len >= limit) + to_chat(usr, "The machine cannot hold anymore items.") + return 1 + + if(!istype(O)) + return + + if(istype(O,/obj/item/weapon/storage/plants)) + var/obj/item/weapon/storage/plants/bag = O + var/failed = 1 + for(var/obj/item/G in O.contents) + if(!G.reagents || !G.reagents.total_volume) + continue + failed = 0 + bag.remove_from_storage(G, src) + holdingitems += G + if(holdingitems && holdingitems.len >= limit) + break + + if(failed) + to_chat(user, "Nothing in the plant bag is usable.") + return 1 + + if(!O.contents.len) + to_chat(user, "You empty \the [O] into \the [src].") + else + to_chat(user, "You fill \the [src] from \the [O].") + + src.updateUsrDialog() + return 0 + + if(!sheet_reagents[O.type] && (!O.reagents || !O.reagents.total_volume)) + to_chat(user, "\The [O] is not suitable for blending.") + return 1 + + user.remove_from_mob(O) + O.loc = src + holdingitems += O + src.updateUsrDialog() + return 0 + +/obj/machinery/reagentgrinder/attack_ai(mob/user as mob) + return 0 + +/obj/machinery/reagentgrinder/attack_hand(mob/user as mob) + interact(user) + +/obj/machinery/reagentgrinder/attack_robot(var/mob/user) + //Calling for adjacency as I don't think grinders are wireless. + if(Adjacent(user)) + //Calling attack_hand(user) to make ensure no functionality is missed. + //If attack_hand is updated, this segment won't have to be updated as well. + return attack_hand(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 = "" + var/beaker_contents = "" + var/dat = "" + + if(!inuse) + for (var/obj/item/O in holdingitems) + processing_chamber += "\A [O.name]
            " + + if (!processing_chamber) + is_chamber_empty = 1 + processing_chamber = "Nothing." + if (!beaker) + beaker_contents = "No beaker attached.
            " + else + is_beaker_ready = 1 + beaker_contents = "The beaker contains:
            " + var/anything = 0 + for(var/datum/reagent/R in beaker.reagents.reagent_list) + anything = 1 + beaker_contents += "[R.volume] - [R.name]
            " + if(!anything) + beaker_contents += "Nothing
            " + + + dat = {" + Processing chamber contains:
            + [processing_chamber]
            + [beaker_contents]
            + "} + if (is_beaker_ready && !is_chamber_empty && !(stat & (NOPOWER|BROKEN))) + dat += "Process the reagents
            " + if(holdingitems && holdingitems.len > 0) + dat += "Eject the reagents
            " + if (beaker) + dat += "Detach the beaker
            " + else + dat += "Please wait..." + user << browse("All-In-One Grinder[dat]", "window=reagentgrinder") + onclose(user, "reagentgrinder") + return + + +/obj/machinery/reagentgrinder/OnTopic(user, href_list) + if(href_list["action"]) + switch(href_list["action"]) + if ("grind") + grind() + if("eject") + eject() + if ("detach") + detach() + interact(user) + return TOPIC_REFRESH + +/obj/machinery/reagentgrinder/proc/detach() + if (!beaker) + return + beaker.dropInto(loc) + beaker = null + update_icon() + +/obj/machinery/reagentgrinder/proc/eject() + if (!holdingitems || holdingitems.len == 0) + return + + for(var/obj/item/O in holdingitems) + O.loc = src.loc + holdingitems -= O + holdingitems.Cut() + +/obj/machinery/reagentgrinder/proc/grind() + + power_change() + if(stat & (NOPOWER|BROKEN)) + return + + // Sanity check. + if (!beaker || (beaker && beaker.reagents.total_volume >= beaker.reagents.maximum_volume)) + return + + playsound(src.loc, 'sound/machines/blender.ogg', 50, 1) + inuse = 1 + + // Reset the machine. + spawn(60) + inuse = 0 + interact(usr) + + // Process. + for (var/obj/item/O in holdingitems) + + var/remaining_volume = beaker.reagents.maximum_volume - beaker.reagents.total_volume + if(remaining_volume <= 0) + break + + if(sheet_reagents[O.type]) + var/obj/item/stack/stack = O + if(istype(stack)) + var/amount_to_take = max(0,min(stack.amount,round(remaining_volume/REAGENTS_PER_SHEET))) + if(amount_to_take) + stack.use(amount_to_take) + if(QDELETED(stack)) + holdingitems -= stack + beaker.reagents.add_reagent(sheet_reagents[stack.type], (amount_to_take*REAGENTS_PER_SHEET)) + continue + + if(O.reagents) + O.reagents.trans_to(beaker, min(O.reagents.total_volume, remaining_volume)) + if(O.reagents.total_volume == 0) + holdingitems -= O + qdel(O) + if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + break + +#undef REAGENTS_PER_SHEET diff --git a/code/modules/reagents/Chemistry-Metabolism.dm b/code/modules/reagents/Chemistry-Metabolism.dm new file mode 100644 index 00000000..8511145a --- /dev/null +++ b/code/modules/reagents/Chemistry-Metabolism.dm @@ -0,0 +1,21 @@ +/datum/reagents/metabolism + var/metabolism_class //CHEM_TOUCH, CHEM_INGEST, or CHEM_BLOOD + var/mob/living/carbon/parent + +/datum/reagents/metabolism/New(var/max = 100, mob/living/carbon/parent_mob, var/met_class) + ..(max, parent_mob) + + metabolism_class = met_class + if(istype(parent_mob)) + parent = parent_mob + +/datum/reagents/metabolism/proc/metabolize() + + var/metabolism_type = 0 //non-human mobs + if(ishuman(parent)) + var/mob/living/carbon/human/H = parent + metabolism_type = H.species.reagent_tag + + for(var/datum/reagent/current in reagent_list) + current.on_mob_life(parent, metabolism_type, metabolism_class) + update_total() \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Readme.dm b/code/modules/reagents/Chemistry-Readme.dm new file mode 100644 index 00000000..af2677dc --- /dev/null +++ b/code/modules/reagents/Chemistry-Readme.dm @@ -0,0 +1,302 @@ +/* +NOTE: IF YOU UPDATE THE REAGENT-SYSTEM, ALSO UPDATE THIS README. + +Structure: /////////////////// ////////////////////////// + // Mob or object // -------> // Reagents var (datum) // Is a reference to the datum that holds the reagents. + /////////////////// ////////////////////////// + | | + The object that holds everything. V + reagent_list var (list) A List of datums, each datum is a reagent. + + | | | + V V V + + reagents (datums) Reagents. I.e. Water , antitoxins or mercury. + + +Random important notes: + + An objects on_reagent_change will be called every time the objects reagents change. + Useful if you want to update the objects icon etc. + +About the Holder: + + The holder (reagents datum) is the datum that holds a list of all reagents + currently in the object.It also has all the procs needed to manipulate reagents + + Vars: + list/datum/reagent/reagent_list + List of reagent datums. + + total_volume + Total volume of all reagents. + + maximum_volume + Maximum volume. + + atom/my_atom + Reference to the object that contains this. + + Procs: + + get_free_space() + Returns the remaining free volume in the holder. + + get_master_reagent() + Returns the reference to the reagent with the largest volume + + get_master_reagent_name() + Ditto, but returns the name. + + get_master_reagent_id() + Ditto, but returns ID. + + update_total() + Updates total volume, called automatically. + + handle_reactions() + Checks reagents and triggers any reactions that happen. Usually called automatically. + + add_reagent(var/id, var/amount, var/data = null, var/safety = 0) + Adds [amount] units of [id] reagent. [data] will be passed to reagent's mix_data() or initialize_data(). If [safety] is 0, handle_reactions() will be called. Returns 1 if successful, 0 otherwise. + + remove_reagent(var/id, var/amount, var/safety = 0) + Ditto, but removes reagent. Returns 1 if successful, 0 otherwise. + + del_reagent(var/id) + Removes all of the reagent. + + has_reagent(var/id, var/amount = 0) + Checks if holder has at least [amount] of [id] reagent. Returns 1 if the reagent is found and volume is above [amount]. Returns 0 otherwise. + + clear_reagents() + Removes all reagents. + + get_reagent_amount(var/id) + Returns reagent volume. Returns 0 if reagent is not found. + + get_data(var/id) + Returns get_data() of the reagent. + + get_reagents() + Returns a string containing all reagent ids and volumes, e.g. "carbon(4),nittrogen(5)". + + remove_any(var/amount = 1) + Removes up to [amount] of reagents from [src]. Returns actual amount removed. + + trans_to_holder(var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0) + Transfers [amount] reagents from [src] to [target], multiplying them by [multiplier]. Returns actual amount removed from [src] (not amount transferred to [target]). If [copy] is 1, copies reagents instead. + + touch(var/atom/target) + When applying reagents to an atom externally, touch() is called to trigger any on-touch effects of the reagent. + This does not handle transferring reagents to things. + For example, splashing someone with water will get them wet and extinguish them if they are on fire, + even if they are wearing an impermeable suit that prevents the reagents from contacting the skin. + Basically just defers to touch_mob(target), touch_turf(target), or touch_obj(target), depending on target's type. + Not recommended to use this directly, since trans_to() calls it before attempting to transfer. + + touch_mob(var/mob/target) + Calls each reagent's touch_mob(target). + + touch_turf(var/turf/target) + Calls each reagent's touch_turf(target). + + touch_obj(var/obj/target) + Calls each reagent's touch_obj(target). + + trans_to(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0) + The general proc for applying reagents to things externally (as opposed to directly injected into the contents). + It first calls touch, then the appropriate trans_to_*() or splash_mob(). + If for some reason you want touch effects to be bypassed (e.g. injecting stuff directly into a reagent container or person), call the appropriate trans_to_*() proc. + + Calls touch() before checking the type of [target], calling splash_mob(target, amount), trans_to_turf(target, amount, multiplier, copy), or trans_to_obj(target, amount, multiplier, copy). + + trans_id_to(var/atom/target, var/id, var/amount = 1) + Transfers [amount] of [id] to [target]. Returns amount transferred. + + splash_mob(var/mob/target, var/amount = 1, var/clothes = 1) + Checks mob's clothing if [clothes] is 1 and transfers [amount] reagents to mob's skin. + Don't call this directly. Call apply_to() instead. + + trans_to_mob(var/mob/target, var/amount = 1, var/type = CHEM_BLOOD, var/multiplier = 1, var/copy = 0) + Transfers [amount] reagents to the mob's appropriate holder, depending on [type]. Ignores protection. + + trans_to_turf(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) + Turfs don't currently have any reagents. Puts [amount] reagents into a temporary holder, calls touch_turf(target) from it, and deletes it. + + trans_to_obj(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) + If target has reagents, transfers [amount] to it. Otherwise, same as trans_to_turf(). + + atom/proc/create_reagents(var/max_vol) + Creates a new reagent datum. + +About Reagents: + + Reagents are all the things you can mix and fille in bottles etc. This can be anything from + rejuvs over water to... iron. + + Vars: + + name + Name that shows up in-game. + + id + ID that is used for internal tracking. MUST BE UNIQUE. + + description + Description that shows up in-game. + + datum/reagents/holder + Reference to holder. + + reagent_state + Could be REAGENT_GAS, REAGENT_LIQUID, or REAGENT_SOLID. Affects nothing. Reserved for future use. + + list/data + Use varies by reagent. Custom variable. For example, blood stores blood group and viruses. + + volume + Current volume. + + metabolism + How quickly reagent is processed in mob's bloodstream; by default aslo affects ingest and touch metabolism. + + ingest_met + How quickly reagent is processed when ingested; [metabolism] is used if zero. + + touch_met + Ditto when touching. + + dose + How much of the reagent has been processed, limited by [max_dose]. Used for reagents with varying effects (e.g. ethanol or rezadone) and overdosing. + + max_dose + Maximum amount of reagent that has ever been in a mob. Exists so dose won't grow infinitely when small amounts of reagent are added over time. + + overdose + If [dose] is bigger than [overdose], overdose() proc is called every tick. + + scannable + If set to 1, will show up on health analyzers by name. + + glass_icon_state + Used by drinks. icon_state of the glass when this reagent is the master reagent. + + glass_name + Ditto for glass name. + + glass_desc + Ditto for glass desciption. + + glass_center_of_mass + Used for glass placement on tables. + + color + "#RRGGBB" or "#RRGGBBAA" where A is alpha channel. + + color_weight + How much reagent affects color of holder. Used by paint. + + Procs: + + remove_self(var/amount) + Removes [amount] of itself. + + touch_mob(var/mob/M) + Called when reagent is in another holder and not splashing the mob. Can be used with noncarbons. + + touch_obj(var/obj/O) + How reagent reacts with objects. + + touch_turf(var/turf/T) + How reagent reacts with turfs. + + on_mob_life(var/mob/living/carbon/M, var/alien, var/location) + Makes necessary checks and calls one of affect procs. + + affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + How reagent affects mob when injected. [removed] is the amount of reagent that has been removed this tick. [alien] is the mob's reagent flag. + + affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + Ditto, ingested. Defaults to affect_blood with halved dose. + + affect_touch(var/mob/living/carbon/M, var/alien, var/removed) + Ditto, touching. + + overdose(var/mob/living/carbon/M, var/alien) + Called when dose is above overdose. Defaults to M.adjustToxLoss(REM). + + initialize_data(var/newdata) + Called when reagent is created. Defaults to setting [data] to [newdata]. + + mix_data(var/newdata, var/newamount) + Called when [newamount] of reagent with [newdata] data is added to the current reagent. Used by paint. + + get_data() + Returns data. Can be overriden. + +About Recipes: + + Recipes are simple datums that contain a list of required reagents and a result. + They also have a proc that is called when the recipe is matched. + + Vars: + + name + Name of the reaction, currently unused. + + id + ID of the reaction, must be unique. + + result + ID of the resulting reagent. Can be null. + + list/required_reagents + Reagents that are required for the reaction and are used up during it. + + list/catalysts + Ditto, but not used up. + + list/inhibitors + Opposite, prevent the reaction from happening. + + result_amount + Amount of resulting reagent. + + mix_message + Message that is shown to mobs when reaction happens. + + Procs: + + can_happen(var/datum/reagents/holder) + Customizable. If it returns 0, reaction will not happen. Defaults to always returning 1. Used by slime core reactions. + + on_reaction(var/datum/reagents/holder, var/created_volume) + Called when reaction happens. Used by explosives. + + send_data(var/datum/reagents/T) + Sets resulting reagent's data. Used by blood paint. + +About the Tools: + + By default, all atom have a reagents var - but its empty. if you want to use an object for the chem. + system you'll need to add something like this in its new proc: + + atom/proc/create_reagents(var/max_volume) + + Other important stuff: + + amount_per_transfer_from_this var + This var is mostly used by beakers and bottles. + It simply tells us how much to transfer when + 'pouring' our reagents into something else. + + atom/proc/is_open_container() + Checks atom/var/obj_flags & OBJ_FLAG_OPEN_CONTAINER. + If this returns 1 , you can use syringes, beakers etc + to manipulate the contents of this object. + If it's 0, you'll need to write your own custom reagent + transfer code since you will not be able to use the standard + tools to manipulate it. + +*/ diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm new file mode 100644 index 00000000..b0ec633d --- /dev/null +++ b/code/modules/reagents/Chemistry-Reagents.dm @@ -0,0 +1,126 @@ +/datum/reagent + var/name = "Reagent" + var/description = "A non-descript chemical." + var/taste_description = "old rotten bandaids" + var/taste_mult = 1 //how this taste compares to others. Higher values means it is more noticable + var/datum/reagents/holder = null + var/reagent_state = REAGENT_SOLID + var/list/data = null + var/volume = 0 + var/metabolism = REM // This would be 0.2 normally + var/ingest_met = 0 + var/touch_met = 0 + var/overdose = 0 + var/scannable = 0 // Shows up on health analyzers. + var/color = "#000000" + var/color_weight = 1 + var/flags = 0 + + var/glass_icon = DRINK_ICON_DEFAULT + var/glass_name = "something" + var/glass_desc = "It's a glass of... what, exactly?" + var/list/glass_special = null // null equivalent to list() + + var/quench_amount = 5 //For thirst. + +/datum/reagent/New(var/datum/reagents/holder) + if(!istype(holder)) + CRASH("Invalid reagents holder: [log_info_line(holder)]") + src.holder = holder + ..() + +/datum/reagent/proc/remove_self(var/amount) // Shortcut + holder.remove_reagent(type, amount) + +// This doesn't apply to skin contact - this is for, e.g. extinguishers and sprays. The difference is that reagent is not directly on the mob's skin - it might just be on their clothing. +/datum/reagent/proc/touch_mob(var/mob/M, var/amount) + return + +/datum/reagent/proc/touch_obj(var/obj/O, var/amount) // Acid melting, cleaner cleaning, etc + return + +/datum/reagent/proc/touch_turf(var/turf/T, var/amount) // Cleaner cleaning, lube lubbing, etc, all go here + return + +/datum/reagent/proc/on_mob_life(var/mob/living/carbon/M, var/alien, var/location) // Currently, on_mob_life is called on carbons. Any interaction with non-carbon mobs (lube) will need to be done in touch_mob. + if(!istype(M)) + return + if(!(flags & AFFECTS_DEAD) && M.stat == DEAD && (world.time - M.timeofdeath > 150)) + return + if(overdose && (location != CHEM_TOUCH)) + var/overdose_threshold = overdose * (flags & IGNORE_MOB_SIZE? 1 : MOB_MEDIUM/M.mob_size) + if(volume > overdose_threshold) + overdose(M, alien) + + //determine the metabolism rate + var/removed = metabolism + if(ingest_met && (location == CHEM_INGEST)) + removed = ingest_met + if(touch_met && (location == CHEM_TOUCH)) + removed = touch_met + removed = M.get_adjusted_metabolism(removed) + + + //adjust effective amounts - removed, dose, and max_dose - for mob size + var/effective = removed + if(!(flags & IGNORE_MOB_SIZE) && location != CHEM_TOUCH) + effective *= (MOB_MEDIUM/M.mob_size) + + M.chem_doses[type] = M.chem_doses[type] + effective + if(effective >= (metabolism * 0.1) || effective >= 0.1) // If there's too little chemical, don't affect the mob, just remove it + switch(location) + if(CHEM_BLOOD) + affect_blood(M, alien, effective) + if(CHEM_INGEST) + affect_ingest(M, alien, effective) + if(CHEM_TOUCH) + affect_touch(M, alien, effective) + + if(volume) + remove_self(removed) + return + +/datum/reagent/proc/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + return + +/datum/reagent/proc/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + affect_blood(M, alien, removed * 0.5) + return + +/datum/reagent/proc/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) + return + +/datum/reagent/proc/overdose(var/mob/living/carbon/M, var/alien) // Overdose effect. Doesn't happen instantly. + M.add_chemical_effect(CE_TOXIN, 1) + M.adjustToxLoss(REM) + return + +/datum/reagent/proc/initialize_data(var/newdata) // Called when the reagent is created. + if(!isnull(newdata)) + data = newdata + return + +/datum/reagent/proc/mix_data(var/newdata, var/newamount) // You have a reagent with data, and new reagent with its own data get added, how do you deal with that? + return + +/datum/reagent/proc/get_data() // Just in case you have a reagent that handles data differently. + if(data && istype(data, /list)) + return data.Copy() + else if(data) + return data + return null + +/datum/reagent/Destroy() // This should only be called by the holder, so it's already handled clearing its references + holder = null + . = ..() + +/* DEPRECATED - TODO: REMOVE EVERYWHERE */ + +/datum/reagent/proc/reaction_turf(var/turf/target) + touch_turf(target) + +/datum/reagent/proc/reaction_obj(var/obj/target) + touch_obj(target) + +/datum/reagent/proc/reaction_mob(var/mob/target) + touch_mob(target) diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm new file mode 100644 index 00000000..9b4644bb --- /dev/null +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm @@ -0,0 +1,225 @@ +/datum/reagent/blood + data = new/list( + "donor" = null, + "species" = SPECIES_HUMAN, + "blood_DNA" = null, + "blood_type" = null, + "blood_colour" = COLOR_BLOOD_HUMAN, + "trace_chem" = null, + "dose_chem" = null, + "virus2" = list(), + "antibodies" = list(), + "has_oxy" = 1 + ) + name = "Blood" + reagent_state = REAGENT_LIQUID + metabolism = REM * 5 + color = "#c80000" + taste_description = "iron" + taste_mult = 1.3 + glass_name = "tomato juice" + glass_desc = "Are you sure this is tomato juice?" + +/datum/reagent/blood/initialize_data(var/newdata) + ..() + if(data && data["blood_colour"]) + color = data["blood_colour"] + return + +/datum/reagent/blood/proc/sync_to(var/mob/living/carbon/C) + data["donor"] = weakref(C) + if (!data["virus2"]) + data["virus2"] = list() + data["virus2"] |= virus_copylist(C.virus2) + data["antibodies"] = C.antibodies + data["blood_DNA"] = C.dna.unique_enzymes + data["blood_type"] = C.dna.b_type + data["species"] = C.species.name + data["has_oxy"] = C.species.blood_oxy + var/list/temp_chem = list() + for(var/datum/reagent/R in C.reagents.reagent_list) + temp_chem[R.type] = R.volume + data["trace_chem"] = list2params(temp_chem) + data["dose_chem"] = list2params(C.chem_doses) + data["blood_colour"] = C.species.get_blood_colour(C) + color = data["blood_colour"] + +/datum/reagent/blood/mix_data(var/newdata, var/newamount) + if(!islist(newdata)) + return + if(!data["virus2"]) + data["virus2"] = list() + data["virus2"] |= newdata["virus2"] + if(!data["antibodies"]) + data["antibodies"] = list() + data["antibodies"] |= newdata["antibodies"] + +/datum/reagent/blood/get_data() // Just in case you have a reagent that handles data differently. + var/t = data.Copy() + if(t["virus2"]) + var/list/v = t["virus2"] + t["virus2"] = v.Copy() + return t + +/datum/reagent/blood/touch_turf(var/turf/simulated/T) + if(!istype(T) || volume < 3) + return + var/weakref/W = data["donor"] + if (!W) + blood_splatter(T, src, 1) + W = W.resolve() + if(istype(W, /mob/living/carbon/human)) + blood_splatter(T, src, 1) + else if(istype(W, /mob/living/carbon/alien)) + var/obj/effect/decal/cleanable/blood/B = blood_splatter(T, src, 1) + if(B) + B.blood_DNA["UNKNOWN DNA STRUCTURE"] = "X*" + +/datum/reagent/blood/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + + if(M.chem_doses[type] > 5) + M.adjustToxLoss(removed) + if(M.chem_doses[type] > 15) + M.adjustToxLoss(removed) + if(data && data["virus2"]) + var/list/vlist = data["virus2"] + if(vlist.len) + for(var/ID in vlist) + var/datum/disease2/disease/V = vlist[ID] + if(V && V.spreadtype == "Contact") + infect_virus2(M, V.getcopy()) + +/datum/reagent/blood/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.isSynthetic()) + return + if(data && data["virus2"]) + var/list/vlist = data["virus2"] + if(vlist.len) + for(var/ID in vlist) + var/datum/disease2/disease/V = vlist[ID] + if(V.spreadtype == "Contact") + infect_virus2(M, V.getcopy()) + if(data && data["antibodies"]) + M.antibodies |= data["antibodies"] + +/datum/reagent/blood/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.inject_blood(src, volume) + remove_self(volume) + +// pure concentrated antibodies +/datum/reagent/antibodies + data = list("antibodies"=list()) + name = "Antibodies" + taste_description = "slime" + reagent_state = REAGENT_LIQUID + color = "#0050f0" + +/datum/reagent/antibodies/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(src.data) + M.antibodies |= src.data["antibodies"] + ..() + +#define WATER_LATENT_HEAT 19000 // How much heat is removed when applied to a hot turf, in J/unit (19000 makes 120 u of water roughly equivalent to 4L) +/datum/reagent/water + name = "Water" + description = "A ubiquitous chemical substance that is composed of hydrogen and oxygen." + reagent_state = REAGENT_LIQUID + color = "#0064c877" + metabolism = REM * 10 + taste_description = "water" + glass_name = "water" + glass_desc = "The father of all refreshments." + +/datum/reagent/water/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(!istype(M, /mob/living/carbon/slime) && alien != IS_SLIME) + return + M.adjustToxLoss(2 * removed) + +/datum/reagent/water/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + if(!istype(M, /mob/living/carbon/slime) && alien != IS_SLIME) + return + M.adjustToxLoss(2 * removed) + M.adjustStaminaLoss(-1) + +/datum/reagent/water/touch_turf(var/turf/simulated/T) + if(!istype(T)) + return + + var/datum/gas_mixture/environment = T.return_air() + var/min_temperature = T0C + 100 // 100C, the boiling point of water + + var/hotspot = (locate(/obj/fire) in T) + if(hotspot && !istype(T, /turf/space)) + var/datum/gas_mixture/lowertemp = T.remove_air(T:air:total_moles) + lowertemp.temperature = max(min(lowertemp.temperature-2000, lowertemp.temperature / 2), 0) + lowertemp.react() + T.assume_air(lowertemp) + qdel(hotspot) + + if (environment && environment.temperature > min_temperature) // Abstracted as steam or something + var/removed_heat = between(0, volume * WATER_LATENT_HEAT, -environment.get_thermal_energy_change(min_temperature)) + environment.add_thermal_energy(-removed_heat) + if (prob(5)) + T.visible_message("The water sizzles as it lands on \the [T]!") + + else if(volume >= 10) + var/turf/simulated/S = T + S.wet_floor(1, TRUE) + + +/datum/reagent/water/touch_obj(var/obj/O) + if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/monkeycube)) + var/obj/item/weapon/reagent_containers/food/snacks/monkeycube/cube = O + if(!cube.wrapped) + cube.Expand() + +/datum/reagent/water/touch_mob(var/mob/living/L, var/amount) + if(istype(L)) + var/needed = L.fire_stacks * 10 + if(amount > needed) + L.fire_stacks = 0 + L.ExtinguishMob() + remove_self(needed) + else + L.adjust_fire_stacks(-(amount / 10)) + remove_self(amount) + +/datum/reagent/water/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) + if(!istype(M, /mob/living/carbon/slime) && alien != IS_SLIME) + return + M.adjustToxLoss(10 * removed) // Babies have 150 health, adults have 200; So, 15 units and 20 + var/mob/living/carbon/slime/S = M + if(!S.client && istype(S)) + if(S.Target) // Like cats + S.Target = null + if(S.Victim) + S.Feedstop() + if(M.chem_doses[type] == removed) + M.visible_message("[S]'s flesh sizzles where the water touches it!", "Your flesh burns in the water!") + M.confused = max(M.confused, 2) + +/datum/reagent/fuel + name = "Welding fuel" + description = "Required for welders. Flamable." + taste_description = "gross metal" + reagent_state = REAGENT_LIQUID + color = "#660000" + touch_met = 5 + + glass_name = "welder fuel" + glass_desc = "Unless you are an industrial tool, this is probably not safe for consumption." + +/datum/reagent/fuel/touch_turf(var/turf/T) + new /obj/effect/decal/cleanable/liquid_fuel(T, volume) + remove_self(volume) + return + +/datum/reagent/fuel/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.adjustToxLoss(2 * removed) + +/datum/reagent/fuel/touch_mob(var/mob/living/L, var/amount) + if(istype(L)) + L.adjust_fire_stacks(amount / 10) // Splashing people with welding fuel to make them easy to ignite! + diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm new file mode 100644 index 00000000..da18aeec --- /dev/null +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm @@ -0,0 +1,426 @@ +/datum/reagent/acetone + name = "Acetone" + description = "A colorless liquid solvent used in chemical synthesis." + taste_description = "acid" + reagent_state = REAGENT_LIQUID + color = "#808080" + metabolism = REM * 0.2 + +/datum/reagent/acetone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_NABBER) + return + + M.adjustToxLoss(removed * 3) + +/datum/reagent/acetone/touch_obj(var/obj/O) //I copied this wholesale from ethanol and could likely be converted into a shared proc. ~Techhead + if(istype(O, /obj/item/weapon/paper)) + var/obj/item/weapon/paper/paperaffected = O + paperaffected.clearpaper() + to_chat(usr, "The solution dissolves the ink on the paper.") + return + if(istype(O, /obj/item/weapon/book)) + if(volume < 5) + return + if(istype(O, /obj/item/weapon/book/tome)) + to_chat(usr, "The solution does nothing. Whatever this is, it isn't normal ink.") + return + var/obj/item/weapon/book/affectedbook = O + affectedbook.dat = null + to_chat(usr, "The solution dissolves the ink on the book.") + return + +/datum/reagent/aluminum + name = "Aluminum" + taste_description = "metal" + taste_mult = 1.1 + description = "A silvery white and ductile member of the boron group of chemical elements." + reagent_state = REAGENT_SOLID + color = "#a8a8a8" + +/datum/reagent/ammonia + name = "Ammonia" + taste_description = "mordant" + taste_mult = 2 + description = "A caustic substance commonly used in fertilizer or household cleaners." + reagent_state = REAGENT_LIQUID + color = "#404030" + metabolism = REM * 0.5 + +/datum/reagent/ammonia/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_VOX) + M.adjustOxyLoss(-removed * 10) + else if(alien != IS_DIONA) + M.adjustToxLoss(removed * 1.5) + +/datum/reagent/carbon + name = "Carbon" + description = "A chemical element, the building block of life." + taste_description = "sour chalk" + taste_mult = 1.5 + reagent_state = REAGENT_SOLID + color = "#1c1300" + ingest_met = REM * 5 + +/datum/reagent/carbon/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + if(M.ingested && M.ingested.reagent_list.len > 1) // Need to have at least 2 reagents - cabon and something to remove + var/effect = 1 / (M.ingested.reagent_list.len - 1) + for(var/datum/reagent/R in M.ingested.reagent_list) + if(R == src) + continue + M.ingested.remove_reagent(R.type, removed * effect) + +/datum/reagent/carbon/touch_turf(var/turf/T) + if(!istype(T, /turf/space)) + var/obj/effect/decal/cleanable/dirt/dirtoverlay = locate(/obj/effect/decal/cleanable/dirt, T) + if (!dirtoverlay) + dirtoverlay = new/obj/effect/decal/cleanable/dirt(T) + dirtoverlay.alpha = volume * 30 + else + dirtoverlay.alpha = min(dirtoverlay.alpha + volume * 30, 255) + +/datum/reagent/copper + name = "Copper" + description = "A highly ductile metal." + taste_description = "copper" + color = "#6e3b08" + +/datum/reagent/ethanol + name = "Ethanol" //Parent class for all alcoholic reagents. + description = "A well-known alcohol with a variety of applications." + taste_description = "pure alcohol" + reagent_state = REAGENT_LIQUID + color = "#404030" + touch_met = 5 + var/nutriment_factor = 0 + var/strength = 10 // This is, essentially, units between stages - the lower, the stronger. Less fine tuning, more clarity. + var/toxicity = 1 + + var/druggy = 0 + var/adj_temp = 0 + var/targ_temp = 310 + var/halluci = 0 + + glass_name = "ethanol" + glass_desc = "A well-known alcohol with a variety of applications." + +/datum/reagent/ethanol/touch_mob(var/mob/living/L, var/amount) + if(istype(L)) + L.adjust_fire_stacks(amount / 15) + +/datum/reagent/ethanol/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.adjustToxLoss(removed * 2 * toxicity) + return + +/datum/reagent/ethanol/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + M.nutrition += nutriment_factor * removed + var/strength_mod = 1 + if(alien == IS_SKRELL) + strength_mod *= 5 + if(alien == IS_DIONA) + strength_mod = 0 + + M.add_chemical_effect(CE_ALCOHOL, 1) + var/effective_dose = M.chem_doses[type] * strength_mod * (1 + volume/60) //drinking a LOT will make you go down faster + M.add_event("booze", /datum/happiness_event/booze) + + if(effective_dose >= strength) // Early warning + M.make_dizzy(6) // It is decreased at the speed of 3 per tick + if(effective_dose >= strength * 2) // Slurring + M.add_chemical_effect(CE_PAINKILLER, 150/strength) + M.slurring = max(M.slurring, 30) + if(effective_dose >= strength * 3) // Confusion - walking in random directions + M.add_chemical_effect(CE_PAINKILLER, 150/strength) + M.confused = max(M.confused, 20) + if(effective_dose >= strength * 4) // Blurry vision + M.add_chemical_effect(CE_PAINKILLER, 150/strength) + M.eye_blurry = max(M.eye_blurry, 10) + if(effective_dose >= strength * 5) // Drowsyness - periodically falling asleep + M.add_chemical_effect(CE_PAINKILLER, 150/strength) + M.drowsyness = max(M.drowsyness, 20) + if(effective_dose >= strength * 6) // Toxic dose + M.add_chemical_effect(CE_ALCOHOL_TOXIC, toxicity) + if(effective_dose >= strength * 7) // Pass out + M.Paralyse(20) + M.Sleeping(30) + + if(druggy != 0) + M.druggy = max(M.druggy, druggy) + + if(adj_temp > 0 && M.bodytemperature < targ_temp) // 310 is the normal bodytemp. 310.055 + M.bodytemperature = min(targ_temp, M.bodytemperature + (adj_temp * TEMPERATURE_DAMAGE_COEFFICIENT)) + if(adj_temp < 0 && M.bodytemperature > targ_temp) + M.bodytemperature = min(targ_temp, M.bodytemperature - (adj_temp * TEMPERATURE_DAMAGE_COEFFICIENT)) + + if(halluci) + M.adjust_hallucination(halluci, halluci) + +/datum/reagent/ethanol/touch_obj(var/obj/O) + if(istype(O, /obj/item/weapon/paper)) + var/obj/item/weapon/paper/paperaffected = O + paperaffected.clearpaper() + to_chat(usr, "The solution dissolves the ink on the paper.") + return + if(istype(O, /obj/item/weapon/book)) + if(volume < 5) + return + if(istype(O, /obj/item/weapon/book/tome)) + to_chat(usr, "The solution does nothing. Whatever this is, it isn't normal ink.") + return + var/obj/item/weapon/book/affectedbook = O + affectedbook.dat = null + to_chat(usr, "The solution dissolves the ink on the book.") + return + +/datum/reagent/hydrazine + name = "Hydrazine" + description = "A toxic, colorless, flammable liquid with a strong ammonia-like odor, in hydrate form." + taste_description = "sweet tasting metal" + reagent_state = REAGENT_LIQUID + color = "#808080" + metabolism = REM * 0.2 + touch_met = 5 + +/datum/reagent/hydrazine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.adjustToxLoss(4 * removed) + +/datum/reagent/hydrazine/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) // Hydrazine is both toxic and flammable. + M.adjust_fire_stacks(removed / 12) + M.adjustToxLoss(0.2 * removed) + +/datum/reagent/hydrazine/touch_turf(var/turf/T) + new /obj/effect/decal/cleanable/liquid_fuel(T, volume) + remove_self(volume) + return + +/datum/reagent/iron + name = "Iron" + description = "Pure iron is a metal." + taste_description = "metal" + reagent_state = REAGENT_SOLID + color = "#353535" + +/datum/reagent/iron/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + if(alien != IS_DIONA) + M.add_chemical_effect(CE_BLOODRESTORE, 8 * removed) + +/datum/reagent/lithium + name = "Lithium" + description = "A chemical element, used as antidepressant." + taste_description = "metal" + reagent_state = REAGENT_SOLID + color = "#808080" + +/datum/reagent/lithium/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien != IS_DIONA) + if(M.canmove && !M.restrained() && istype(M.loc, /turf/space)) + step(M, pick(GLOB.cardinal)) + if(prob(5)) + M.emote(pick("twitch", "drool", "moan")) + +/datum/reagent/mercury + name = "Mercury" + description = "A chemical element." + taste_mult = 0 //mercury apparently is tasteless. IDK + reagent_state = REAGENT_LIQUID + color = "#484848" + +/datum/reagent/mercury/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien != IS_DIONA) + if(M.canmove && !M.restrained() && istype(M.loc, /turf/space)) + step(M, pick(GLOB.cardinal)) + if(prob(5)) + M.emote(pick("twitch", "drool", "moan")) + M.adjustBrainLoss(0.1) + +/datum/reagent/phosphorus + name = "Phosphorus" + description = "A chemical element, the backbone of biological energy carriers." + taste_description = "vinegar" + reagent_state = REAGENT_SOLID + color = "#832828" + +/datum/reagent/potassium + name = "Potassium" + description = "A soft, low-melting solid that can easily be cut with a knife. Reacts violently with water." + taste_description = "sweetness" //potassium is bitter in higher doses but sweet in lower ones. + reagent_state = REAGENT_SOLID + color = "#a0a0a0" + +/datum/reagent/radium + name = "Radium" + description = "Radium is an alkaline earth metal. It is extremely radioactive." + taste_description = "the color blue, and regret" + reagent_state = REAGENT_SOLID + color = "#c7c7c7" + +/datum/reagent/radium/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.apply_effect(10 * removed, IRRADIATE, blocked = 0) // Radium may increase your chances to cure a disease + if(M.virus2.len) + for(var/ID in M.virus2) + var/datum/disease2/disease/V = M.virus2[ID] + if(prob(5)) + M.antibodies |= V.antigen + if(prob(50)) + M.apply_effect(50, IRRADIATE, blocked = 0) // curing it that way may kill you instead + var/absorbed = 0 + if(!absorbed) + M.adjustToxLoss(100) + +/datum/reagent/radium/touch_turf(var/turf/T) + if(volume >= 3) + if(!istype(T, /turf/space)) + var/obj/effect/decal/cleanable/greenglow/glow = locate(/obj/effect/decal/cleanable/greenglow, T) + if(!glow) + new /obj/effect/decal/cleanable/greenglow(T) + return + +/datum/reagent/acid + name = "Sulphuric acid" + description = "A very corrosive mineral acid with the molecular formula H2SO4." + taste_description = "acid" + reagent_state = REAGENT_LIQUID + color = "#db5008" + metabolism = REM * 2 + touch_met = 50 // It's acid! + var/power = 5 + var/meltdose = 10 // How much is needed to melt + +/datum/reagent/acid/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.take_organ_damage(0, removed * power * 2) + +/datum/reagent/acid/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) // This is the most interesting + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.head) + if(H.head.unacidable) + to_chat(H, "Your [H.head] protects you from the acid.") + remove_self(volume) + return + else if(removed > meltdose) + to_chat(H, "Your [H.head] melts away!") + qdel(H.head) + H.update_inv_head(1) + H.update_hair(1) + removed -= meltdose + if(removed <= 0) + return + + if(H.wear_mask) + if(H.wear_mask.unacidable) + to_chat(H, "Your [H.wear_mask] protects you from the acid.") + remove_self(volume) + return + else if(removed > meltdose) + to_chat(H, "Your [H.wear_mask] melts away!") + qdel(H.wear_mask) + H.update_inv_wear_mask(1) + H.update_hair(1) + removed -= meltdose + if(removed <= 0) + return + + if(H.glasses) + if(H.glasses.unacidable) + to_chat(H, "Your [H.glasses] partially protect you from the acid!") + removed /= 2 + else if(removed > meltdose) + to_chat(H, "Your [H.glasses] melt away!") + qdel(H.glasses) + H.update_inv_glasses(1) + removed -= meltdose / 2 + if(removed <= 0) + return + + if(M.unacidable) + return + + if(volume < meltdose) // Not enough to melt anything + M.take_organ_damage(0, removed * power * 0.1) //burn damage, since it causes chemical burns. Acid doesn't make bones shatter, like brute trauma would. + else + M.take_organ_damage(0, removed * power * 0.2) + if(removed && ishuman(M) && prob(100 * removed / meltdose)) // Applies disfigurement + var/mob/living/carbon/human/H = M + var/screamed + for(var/obj/item/organ/external/affecting in H.organs) + if(!screamed && affecting.can_feel_pain()) + screamed = 1 + H.emote("scream") + affecting.disfigured = 1 + +/datum/reagent/acid/touch_obj(var/obj/O) + if(O.unacidable) + return + if((istype(O, /obj/item) || istype(O, /obj/effect/vine)) && (volume > meltdose)) + var/obj/effect/decal/cleanable/molten_item/I = new/obj/effect/decal/cleanable/molten_item(O.loc) + I.desc = "Looks like this was \an [O] some time ago." + for(var/mob/M in viewers(5, O)) + to_chat(M, "\The [O] melts.") + qdel(O) + remove_self(meltdose) // 10 units of acid will not melt EVERYTHING on the tile + +/datum/reagent/acid/hydrochloric //Like sulfuric, but less toxic and more acidic. + name = "Hydrochloric Acid" + description = "A very corrosive mineral acid with the molecular formula HCl." + taste_description = "stomach acid" + reagent_state = REAGENT_LIQUID + color = "#808080" + power = 3 + meltdose = 8 + +/datum/reagent/silicon + name = "Silicon" + description = "A tetravalent metalloid, silicon is less reactive than its chemical analog carbon." + reagent_state = REAGENT_SOLID + color = "#a8a8a8" + +/datum/reagent/sodium + name = "Sodium" + description = "A chemical element, readily reacts with water." + taste_description = "salty metal" + reagent_state = REAGENT_SOLID + color = "#808080" + +/datum/reagent/sugar + name = "Sugar" + description = "The organic compound commonly known as table sugar and sometimes called saccharose. This white, odorless, crystalline powder has a pleasing, sweet taste." + taste_description = "sugar" + taste_mult = 1.8 + reagent_state = REAGENT_SOLID + color = "#ffffff" + + glass_name = "sugar" + glass_desc = "The organic compound commonly known as table sugar and sometimes called saccharose. This white, odorless, crystalline powder has a pleasing, sweet taste." + glass_icon = DRINK_ICON_NOISY + +/datum/reagent/sugar/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.nutrition += removed * 3 + + if(alien == IS_UNATHI) + if(M.chem_doses[type] < 2) + if(M.chem_doses[type] == metabolism * 2 || prob(5)) + M.emote("yawn") + else if(M.chem_doses[type] < 5) + M.eye_blurry = max(M.eye_blurry, 10) + else if(M.chem_doses[type] < 20) + if(prob(50)) + M.Weaken(2) + M.drowsyness = max(M.drowsyness, 20) + else + M.sleeping = max(M.sleeping, 20) + M.drowsyness = max(M.drowsyness, 60) + +/datum/reagent/sulfur + name = "Sulfur" + description = "A chemical element with a pungent smell." + taste_description = "old eggs" + reagent_state = REAGENT_SOLID + color = "#bf8c00" + +/datum/reagent/tungsten + name = "Tungsten" + description = "A chemical element, and a strong oxidising agent." + taste_mult = 0 //no taste + reagent_state = REAGENT_SOLID + color = "#dcdcdc" diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm new file mode 100644 index 00000000..10af487a --- /dev/null +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm @@ -0,0 +1,2048 @@ +/* Food */ + +/datum/reagent/nutriment + name = "Nutriment" + description = "All the vitamins, minerals, and carbohydrates the body needs in pure form." + taste_mult = 4 + reagent_state = REAGENT_SOLID + metabolism = REM * 4 + var/nutriment_factor = 10 // Per unit + var/injectable = 0 + color = "#664330" + +/datum/reagent/nutriment/mix_data(var/list/newdata, var/newamount) + + if(!islist(newdata) || !newdata.len) + return + + //add the new taste data + for(var/taste in newdata) + if(taste in data) + data[taste] += newdata[taste] + else + data[taste] = newdata[taste] + + //cull all tastes below 10% of total + var/totalFlavor = 0 + for(var/taste in data) + totalFlavor += data[taste] + if(!totalFlavor) + return + for(var/taste in data) + if(data[taste]/totalFlavor < 0.1) + data -= taste + +/datum/reagent/nutriment/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(!injectable) + M.adjustToxLoss(0.2 * removed) + return + affect_ingest(M, alien, removed) + +/datum/reagent/nutriment/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + M.heal_organ_damage(0.5 * removed, 0) //what + + adjust_nutrition(M, alien, removed) + M.add_chemical_effect(CE_BLOODRESTORE, 4 * removed) + +/datum/reagent/nutriment/proc/adjust_nutrition(var/mob/living/carbon/M, var/alien, var/removed) + switch(alien) + if(IS_UNATHI) removed *= 0.1 // Unathi get most of their nutrition from meat. + M.nutrition += nutriment_factor * removed // For hunger and fatness + M.bowels += nutriment_factor * removed //For pooping + +/datum/reagent/nutriment/glucose + name = "Glucose" + color = "#ffffff" + + injectable = 1 + +/datum/reagent/nutriment/protein // Bad for Skrell! + name = "animal protein" + taste_description = "some sort of protein" + color = "#440000" + +/datum/reagent/nutriment/protein/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + switch(alien) + if(IS_SKRELL) + M.adjustToxLoss(0.5 * removed) + return + ..() + +/datum/reagent/nutriment/protein/adjust_nutrition(var/mob/living/carbon/M, var/alien, var/removed) + switch(alien) + if(IS_UNATHI) removed *= 2.25 + M.nutrition += nutriment_factor * removed // For hunger and fatness + +/datum/reagent/nutriment/protein/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien && alien == IS_SKRELL) + M.adjustToxLoss(2 * removed) + return + ..() + +/datum/reagent/nutriment/protein/egg // Also bad for skrell. + name = "egg yolk" + taste_description = "egg" + color = "#ffffaa" + +/datum/reagent/nutriment/honey + name = "Honey" + description = "A golden yellow syrup, loaded with sugary sweetness." + taste_description = "sweetness" + nutriment_factor = 10 + color = "#ffff00" + +/datum/reagent/honey/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + + if(alien == IS_UNATHI) + if(M.chem_doses[type] < 2) + if(M.chem_doses[type] == metabolism * 2 || prob(5)) + M.emote("yawn") + else if(M.chem_doses[type] < 5) + M.eye_blurry = max(M.eye_blurry, 10) + else if(M.chem_doses[type] < 20) + if(prob(50)) + M.Weaken(2) + M.drowsyness = max(M.drowsyness, 20) + else + M.sleeping = max(M.sleeping, 20) + M.drowsyness = max(M.drowsyness, 60) + +/datum/reagent/nutriment/flour + name = "flour" + description = "This is what you rub all over yourself to pretend to be a ghost." + taste_description = "chalky wheat" + reagent_state = REAGENT_SOLID + nutriment_factor = 1 + color = "#ffffff" + +/datum/reagent/nutriment/flour/touch_turf(var/turf/simulated/T) + if(!istype(T, /turf/space)) + new /obj/effect/decal/cleanable/flour(T) + if(T.wet > 1) + T.wet = min(T.wet, 1) + else + T.wet = 0 + +/datum/reagent/nutriment/coco + name = "Coco Powder" + description = "A fatty, bitter paste made from coco beans." + taste_description = "bitterness" + taste_mult = 1.3 + reagent_state = REAGENT_SOLID + nutriment_factor = 5 + color = "#302000" + +/datum/reagent/nutriment/soysauce + name = "Soysauce" + description = "A salty sauce made from the soy plant." + taste_description = "umami" + taste_mult = 1.1 + reagent_state = REAGENT_LIQUID + nutriment_factor = 2 + color = "#792300" + +/datum/reagent/nutriment/ketchup + name = "Ketchup" + description = "Ketchup, catsup, whatever. It's tomato paste." + taste_description = "ketchup" + reagent_state = REAGENT_LIQUID + nutriment_factor = 5 + color = "#731008" + +/datum/reagent/nutriment/barbecue + name = "Barbecue Sauce" + description = "Barbecue sauce for barbecues and long shifts." + taste_description = "barbecue" + reagent_state = REAGENT_LIQUID + nutriment_factor = 5 + color = "#4f330f" + +/datum/reagent/nutriment/garlicsauce + name = "Garlic Sauce" + description = "Garlic sauce, perfect for spicing up a plate of garlic." + taste_description = "garlic" + reagent_state = REAGENT_LIQUID + nutriment_factor = 4 + color = "#d8c045" + +/datum/reagent/nutriment/rice + name = "Rice" + description = "Enjoy the great taste of nothing." + taste_description = "rice" + taste_mult = 0.4 + reagent_state = REAGENT_SOLID + nutriment_factor = 1 + color = "#ffffff" + +/datum/reagent/nutriment/cherryjelly + name = "Cherry Jelly" + description = "Totally the best. Only to be spread on foods with excellent lateral symmetry." + taste_description = "cherry" + taste_mult = 1.3 + reagent_state = REAGENT_LIQUID + nutriment_factor = 1 + color = "#801e28" + +/datum/reagent/nutriment/cornoil + name = "Corn Oil" + description = "An oil derived from various types of corn." + taste_description = "slime" + taste_mult = 0.1 + reagent_state = REAGENT_LIQUID + nutriment_factor = 20 + color = "#302000" + +/datum/reagent/nutriment/cornoil/touch_turf(var/turf/simulated/T) + if(!istype(T)) + return + + var/hotspot = (locate(/obj/fire) in T) + if(hotspot && !istype(T, /turf/space)) + var/datum/gas_mixture/lowertemp = T.remove_air(T:air:total_moles) + lowertemp.temperature = max(min(lowertemp.temperature-2000, lowertemp.temperature / 2), 0) + lowertemp.react() + T.assume_air(lowertemp) + qdel(hotspot) + + if(volume >= 3) + T.wet_floor() + +/datum/reagent/nutriment/virus_food + name = "Virus Food" + description = "A mixture of water, milk, and oxygen. Virus cells can use this mixture to reproduce." + taste_description = "vomit" + taste_mult = 2 + reagent_state = REAGENT_LIQUID + nutriment_factor = 2 + color = "#899613" + +/datum/reagent/nutriment/sprinkles + name = "Sprinkles" + description = "Multi-colored little bits of sugar, commonly found on donuts. Loved by cops." + taste_description = "childhood whimsy" + nutriment_factor = 1 + color = "#ff00ff" + +/datum/reagent/nutriment/mint + name = "Mint" + description = "Also known as Mentha." + taste_description = "mint" + reagent_state = REAGENT_LIQUID + color = "#cf3600" + +/datum/reagent/lipozine // The anti-nutriment. + name = "Lipozine" + description = "A chemical compound that causes a powerful fat-burning reaction." + taste_description = "mothballs" + reagent_state = REAGENT_LIQUID + color = "#bbeda4" + overdose = REAGENTS_OVERDOSE + +/datum/reagent/lipozine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.nutrition = max(M.nutrition - 10 * removed, 0) + +/* Non-food stuff like condiments */ + +/datum/reagent/sodiumchloride + name = "Table Salt" + description = "A salt made of sodium chloride. Commonly used to season food." + taste_description = "salt" + reagent_state = REAGENT_SOLID + color = "#ffffff" + overdose = REAGENTS_OVERDOSE + +/datum/reagent/blackpepper + name = "Black Pepper" + description = "A powder ground from peppercorns. *AAAACHOOO*" + taste_description = "pepper" + reagent_state = REAGENT_SOLID + color = "#000000" + +/datum/reagent/enzyme + name = "Universal Enzyme" + description = "A universal enzyme used in the preperation of certain chemicals and foods." + taste_description = "sweetness" + taste_mult = 0.7 + reagent_state = REAGENT_LIQUID + color = "#365e30" + overdose = REAGENTS_OVERDOSE + +/datum/reagent/frostoil + name = "Frost Oil" + description = "A special oil that noticably chills the body. Extracted from Ice Peppers." + taste_description = "mint" + taste_mult = 1.5 + reagent_state = REAGENT_LIQUID + color = "#b31008" + +/datum/reagent/frostoil/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + M.bodytemperature = max(M.bodytemperature - 10 * TEMPERATURE_DAMAGE_COEFFICIENT, 0) + if(prob(1)) + M.emote("shiver") + if(istype(M, /mob/living/carbon/slime)) + M.bodytemperature = max(M.bodytemperature - rand(10,20), 0) + holder.remove_reagent(/datum/reagent/capsaicin, 5) + +/datum/reagent/capsaicin + name = "Capsaicin Oil" + description = "This is what makes chilis hot." + taste_description = "hot peppers" + taste_mult = 1.5 + reagent_state = REAGENT_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) + return + M.adjustToxLoss(0.5 * removed) + +/datum/reagent/capsaicin/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(!H.can_feel_pain()) + return + if(M.chem_doses[type] < agony_dose) + if(prob(5) || M.chem_doses[type] == metabolism) //dose == metabolism is a very hacky way of forcing the message the first time this procs + to_chat(M, discomfort_message) + else + M.apply_effect(agony_amount, PAIN, 0) + if(prob(5)) + M.custom_emote(2, "[pick("dry heaves!","coughs!","splutters!")]") + to_chat(M, "You feel like your insides are burning!") + if(istype(M, /mob/living/carbon/slime)) + M.bodytemperature += rand(0, 15) + slime_temp_adj + holder.remove_reagent(/datum/reagent/frostoil, 5) + +/datum/reagent/capsaicin/condensed + name = "Condensed Capsaicin" + description = "A chemical agent used for self-defense and in police work." + taste_description = "scorching agony" + taste_mult = 10 + reagent_state = REAGENT_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) + 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/effective_strength = 5 + + if(alien == IS_SKRELL) //Larger eyes means bigger targets. + effective_strength = 8 + + var/list/protection + 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.can_feel_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) + eyes_covered = 1 + eye_protection = I.name + if((I.body_parts_covered & FACE) && !(I.item_flags & ITEM_FLAG_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, effective_strength * 3) + M.eye_blind = max(M.eye_blind, effective_strength) + else + M.eye_blurry = max(M.eye_blurry, effective_strength * 5) + M.eye_blind = max(M.eye_blind, effective_strength * 2) + + 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!")]") + M.Weaken(5) + M.Stun(6) + +/datum/reagent/capsaicin/condensed/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(!H.can_feel_pain()) + return + if(M.chem_doses[type] == metabolism) + to_chat(M, "You feel like your insides are burning!") + else + M.apply_effect(4, PAIN, 0) + if(prob(5)) + 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(15, 30) + holder.remove_reagent(/datum/reagent/frostoil, 5) + +/* Drinks */ + +/datum/reagent/drink + name = "Drink" + description = "Uh, some kind of drink." + reagent_state = REAGENT_LIQUID + color = "#e78108" + var/nutrition = 0 // Per unit + var/adj_dizzy = 0 // Per tick + var/adj_drowsy = 0 + var/adj_sleepy = 0 + var/adj_temp = 0 + +/datum/reagent/drink/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.adjustToxLoss(removed) // Probably not a good idea; not very deadly though + return + +/datum/reagent/drink/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + M.nutrition += nutrition * removed + M.dizziness = max(0, M.dizziness + adj_dizzy) + M.drowsyness = max(0, M.drowsyness + adj_drowsy) + M.sleeping = max(0, M.sleeping + adj_sleepy) + if(adj_temp > 0 && M.bodytemperature < 310) // 310 is the normal bodytemp. 310.055 + M.bodytemperature = min(310, M.bodytemperature + (adj_temp * TEMPERATURE_DAMAGE_COEFFICIENT)) + if(adj_temp < 0 && M.bodytemperature > 310) + M.bodytemperature = min(310, M.bodytemperature - (adj_temp * TEMPERATURE_DAMAGE_COEFFICIENT)) + +// Juices +/datum/reagent/drink/juice/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + M.immunity = min(M.immunity + 0.25, M.immunity_norm*1.5) + var/effective_dose = M.chem_doses[type]/2 + if(alien == IS_UNATHI) + if(effective_dose < 2) + if(effective_dose == metabolism * 2 || prob(5)) + M.emote("yawn") + else if(effective_dose < 5) + M.eye_blurry = max(M.eye_blurry, 10) + else if(effective_dose < 20) + if(prob(50)) + M.Weaken(2) + M.drowsyness = max(M.drowsyness, 20) + else + M.sleeping = max(M.sleeping, 20) + M.drowsyness = max(M.drowsyness, 60) + +/datum/reagent/drink/juice/banana + name = "Banana Juice" + description = "The raw essence of a banana." + taste_description = "banana" + color = "#c3af00" + + glass_name = "banana juice" + glass_desc = "The raw essence of a banana. HONK!" + +/datum/reagent/drink/juice/berry + name = "Berry Juice" + description = "A delicious blend of several different kinds of berries." + taste_description = "berries" + color = "#990066" + + glass_name = "berry juice" + glass_desc = "Berry juice. Or maybe it's jam. Who cares?" + +/datum/reagent/drink/juice/carrot + name = "Carrot juice" + description = "It is just like a carrot but without crunching." + taste_description = "carrots" + color = "#ff8c00" // rgb: 255, 140, 0 + + glass_name = "carrot juice" + glass_desc = "It is just like a carrot but without crunching." + +/datum/reagent/drink/juice/carrot/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + M.reagents.add_reagent(/datum/reagent/imidazoline, removed * 0.2) + +/datum/reagent/drink/juice/grape + name = "Grape Juice" + description = "It's grrrrrape!" + taste_description = "grapes" + color = "#863333" + + glass_name = "grape juice" + glass_desc = "It's grrrrrape!" + +/datum/reagent/drink/juice/lemon + name = "Lemon Juice" + description = "This juice is VERY sour." + taste_description = "sourness" + taste_mult = 1.1 + color = "#afaf00" + + glass_name = "lemon juice" + glass_desc = "Sour..." + +/datum/reagent/drink/juice/lime + name = "Lime Juice" + description = "The sweet-sour juice of limes." + taste_description = "unbearable sourness" + taste_mult = 1.1 + color = "#365e30" + + glass_name = "lime juice" + glass_desc = "A glass of sweet-sour lime juice" + +/datum/reagent/drink/juice/lime/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(alien == IS_DIONA) + return + M.adjustToxLoss(-0.5 * removed) + +/datum/reagent/drink/juice/orange + name = "Orange juice" + description = "Both delicious AND rich in Vitamin C, what more do you need?" + taste_description = "oranges" + color = "#e78108" + + glass_name = "orange juice" + glass_desc = "Vitamins! Yay!" + +/datum/reagent/drink/juice/orange/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(alien == IS_DIONA) + return + M.adjustOxyLoss(-2 * removed) + +/datum/reagent/toxin/poisonberryjuice // It has more in common with toxins than drinks... but it's a juice + name = "Poison Berry Juice" + description = "A tasty juice blended from various kinds of very deadly and toxic berries." + taste_description = "berries" + color = "#863353" + strength = 5 + + glass_name = "poison berry juice" + glass_desc = "A glass of deadly juice." + +/datum/reagent/toxin/poisonberryjuice/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_UNATHI) + return //unathi are immune! + return ..() + +/datum/reagent/drink/juice/potato + name = "Potato Juice" + description = "Juice of the potato. Bleh." + taste_description = "irish sadness" + nutrition = 2 + color = "#302000" + + glass_name = "potato juice" + glass_desc = "Juice from a potato. Bleh." + +/datum/reagent/drink/juice/garlic + name = "Garlic Juice" + description = "Who would even drink this?" + taste_description = "bad breath" + nutrition = 1 + color = "#eeddcc" + + glass_name = "garlic juice" + glass_desc = "Who would even drink juice from garlic?" + +/datum/reagent/drink/juice/onion + name = "Onion Juice" + description = "Juice from an onion, for when you need to cry." + taste_description = "stinging tears" + nutrition = 1 + color = "#ffeedd" + + glass_name = "onion juice" + glass_desc = "Juice from an onion, for when you need to cry." + +/datum/reagent/drink/juice/tomato + name = "Tomato Juice" + description = "Tomatoes made into juice. What a waste of big, juicy tomatoes, huh?" + taste_description = "tomatoes" + color = "#731008" + + glass_name = "tomato juice" + glass_desc = "Are you sure this is tomato juice?" + +/datum/reagent/drink/juice/tomato/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(alien == IS_DIONA) + return + M.heal_organ_damage(0, 0.5 * removed) + +/datum/reagent/drink/juice/watermelon + name = "Watermelon Juice" + description = "Delicious juice made from watermelon." + taste_description = "sweet watermelon" + color = "#b83333" + + glass_name = "watermelon juice" + glass_desc = "Delicious juice made from watermelon." + +// Everything else + +/datum/reagent/drink/milk + name = "Milk" + description = "An opaque white liquid produced by the mammary glands of mammals." + taste_description = "milk" + color = "#dfdfdf" + + glass_name = "milk" + glass_desc = "White and nutritious goodness!" + +/datum/reagent/drink/milk/chocolate + name = "Chocolate Milk" + description = "A mixture of perfectly healthy milk and delicious chocolate." + taste_description = "chocolate milk" + color = "#74533b" + + glass_name = "chocolate milk" + glass_desc = "Deliciously fattening!" + +/datum/reagent/drink/milk/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(alien == IS_DIONA) + return + M.heal_organ_damage(0.5 * removed, 0) + holder.remove_reagent(/datum/reagent/capsaicin, 10 * removed) + +/datum/reagent/drink/milk/cream + name = "Cream" + description = "The fatty, still liquid part of milk. Why don't you mix this with sum scotch, eh?" + taste_description = "creamy milk" + color = "#dfd7af" + + glass_name = "cream" + glass_desc = "Ewwww..." + +/datum/reagent/drink/milk/soymilk + name = "Soy Milk" + description = "An opaque white liquid made from soybeans." + taste_description = "soy milk" + color = "#dfdfc7" + + glass_name = "soy milk" + glass_desc = "White and nutritious soy goodness!" + +/datum/reagent/drink/tea + name = "Tea" + description = "Tasty black tea, it has antioxidants, it's good for you!" + taste_description = "tart black tea" + color = "#101000" + adj_dizzy = -2 + adj_drowsy = -1 + adj_sleepy = -3 + adj_temp = 20 + + glass_name = "tea" + glass_desc = "Tasty black tea, it has antioxidants, it's good for you!" + glass_special = list(DRINK_VAPOR) + +/datum/reagent/drink/tea/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(alien == IS_DIONA) + return + M.adjustToxLoss(-0.5 * removed) + +/datum/reagent/drink/tea/icetea + name = "Iced Tea" + description = "No relation to a certain rap artist/ actor." + taste_description = "sweet tea" + color = "#104038" // rgb: 16, 64, 56 + adj_temp = -5 + + glass_name = "iced tea" + glass_desc = "No relation to a certain rap artist/ actor." + glass_special = list(DRINK_ICE) + +/datum/reagent/drink/coffee + name = "Coffee" + description = "Coffee is a brewed drink prepared from roasted seeds, commonly called coffee beans, of the coffee plant." + taste_description = "bitterness" + taste_mult = 1.3 + color = "#482000" + adj_dizzy = -5 + adj_drowsy = -3 + adj_sleepy = -2 + adj_temp = 25 + overdose = 45 + + glass_name = "coffee" + glass_desc = "Don't drop it, or you'll send scalding liquid and glass shards everywhere." + glass_special = list(DRINK_VAPOR) + +/datum/reagent/drink/coffee/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + ..() + if(alien == IS_TAJARA) + M.adjustToxLoss(0.5 * removed) + M.make_jittery(4) //extra sensitive to caffine + if(adj_temp > 0) + holder.remove_reagent(/datum/reagent/frostoil, 10 * removed) + if(volume > 15) + M.add_chemical_effect(CE_PULSE, 1) + +/datum/reagent/nutriment/coffee/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(alien == IS_TAJARA) + M.adjustToxLoss(2 * removed) + M.make_jittery(4) + return + M.add_chemical_effect(CE_PULSE, 2) + +/datum/reagent/drink/coffee/overdose(var/mob/living/carbon/M, var/alien) + if(alien == IS_DIONA) + return + if(alien == IS_TAJARA) + M.adjustToxLoss(4 * REM) + M.apply_effect(3, STUTTER) + M.make_jittery(5) + M.add_chemical_effect(CE_PULSE, 2) + +/datum/reagent/drink/coffee/icecoffee + name = "Iced Coffee" + description = "Coffee and ice, refreshing and cool." + taste_description = "bitter coldness" + color = "#102838" + adj_temp = -5 + + glass_name = "iced coffee" + glass_desc = "A drink to perk you up and refresh you!" + glass_special = list(DRINK_ICE) + +/datum/reagent/drink/coffee/soy_latte + name = "Soy Latte" + description = "A nice and tasty beverage while you are reading your hippie books." + taste_description = "creamy coffee" + color = "#c65905" + adj_temp = 5 + + glass_name = "soy latte" + glass_desc = "A nice and refrshing beverage while you are reading." + +/datum/reagent/drink/coffee/soy_latte/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + M.heal_organ_damage(0.5 * removed, 0) + +/datum/reagent/drink/coffee/cafe_latte + name = "Cafe Latte" + description = "A nice, strong and tasty beverage while you are reading." + taste_description = "bitter cream" + color = "#c65905" + adj_temp = 5 + + glass_name = "cafe latte" + glass_desc = "A nice, strong and refreshing beverage while you are reading." + +/datum/reagent/drink/coffee/cafe_latte/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + M.heal_organ_damage(0.5 * removed, 0) + +/datum/reagent/drink/hot_coco + name = "Hot Chocolate" + description = "Made with love! And cocoa beans." + taste_description = "creamy chocolate" + reagent_state = REAGENT_LIQUID + color = "#403010" + nutrition = 2 + adj_temp = 5 + + glass_name = "hot chocolate" + glass_desc = "Made with love! And cocoa beans." + glass_special = list(DRINK_VAPOR) + +/datum/reagent/drink/sodawater + name = "Soda Water" + description = "A can of club soda. Why not make a scotch and soda?" + taste_description = "carbonated water" + color = "#619494" + adj_dizzy = -5 + adj_drowsy = -3 + adj_temp = -5 + + glass_name = "soda water" + glass_desc = "Soda water. Why not make a scotch and soda?" + glass_special = list(DRINK_FIZZ) + +/datum/reagent/drink/grapesoda + name = "Grape Soda" + description = "Grapes made into a fine drank." + taste_description = "grape soda" + color = "#421c52" + adj_drowsy = -3 + + glass_name = "grape soda" + glass_desc = "Looks like a delicious drink!" + glass_special = list(DRINK_FIZZ) + +/datum/reagent/drink/tonic + name = "Tonic Water" + description = "It tastes strange but at least the quinine keeps the Space Malaria at bay." + taste_description = "tart and fresh" + color = "#619494" + adj_dizzy = -5 + adj_drowsy = -3 + adj_sleepy = -2 + adj_temp = -5 + + glass_name = "tonic water" + glass_desc = "Quinine tastes funny, but at least it'll keep that Space Malaria away." + +/datum/reagent/drink/lemonade + name = "Lemonade" + description = "Oh the nostalgia..." + taste_description = "tartness" + color = "#ffff00" + adj_temp = -5 + + glass_name = "lemonade" + glass_desc = "Oh the nostalgia..." + glass_special = list(DRINK_FIZZ) + +/datum/reagent/drink/kiraspecial + name = "Kira Special" + description = "Long live the guy who everyone had mistaken for a girl. Baka!" + taste_description = "fruity sweetness" + color = "#cccc99" + adj_temp = -5 + + glass_name = "Kira Special" + glass_desc = "Long live the guy who everyone had mistaken for a girl. Baka!" + glass_special = list(DRINK_FIZZ) + +/datum/reagent/drink/brownstar + name = "Brown Star" + description = "It's not what it sounds like..." + taste_description = "orange and cola soda" + color = "#9f3400" + adj_temp = -2 + + glass_name = "Brown Star" + glass_desc = "It's not what it sounds like..." + +/datum/reagent/drink/milkshake + name = "Milkshake" + description = "Glorious brainfreezing mixture." + taste_description = "creamy vanilla" + color = "#aee5e4" + adj_temp = -9 + + glass_name = "milkshake" + glass_desc = "Glorious brainfreezing mixture." + +/datum/reagent/milkshake/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + + var/effective_dose = M.chem_doses[type]/2 + if(alien == IS_UNATHI) + if(effective_dose < 2) + if(effective_dose == metabolism * 2 || prob(5)) + M.emote("yawn") + else if(effective_dose < 5) + M.eye_blurry = max(M.eye_blurry, 10) + else if(effective_dose < 20) + if(prob(50)) + M.Weaken(2) + M.drowsyness = max(M.drowsyness, 20) + else + M.sleeping = max(M.sleeping, 20) + M.drowsyness = max(M.drowsyness, 60) + +/datum/reagent/drink/rewriter + name = "Rewriter" + description = "The secret of the sanctuary of the Libarian..." + taste_description = "a bad night out" + color = "#485000" + adj_temp = -5 + + glass_name = "Rewriter" + glass_desc = "The secret of the sanctuary of the Libarian..." + +/datum/reagent/drink/rewriter/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + M.make_jittery(5) + +/datum/reagent/drink/nuka_cola + name = "Nuka Cola" + description = "Cola, cola never changes." + taste_description = "the future" + color = "#100800" + adj_temp = -5 + adj_sleepy = -2 + + glass_name = "Nuka-Cola" + glass_desc = "Don't cry, Don't raise your eye, It's only nuclear wasteland" + glass_special = list(DRINK_FIZZ) + +/datum/reagent/drink/nuka_cola/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + M.add_chemical_effect(CE_SPEEDBOOST, 1) + M.make_jittery(20) + M.druggy = max(M.druggy, 30) + M.dizziness += 5 + M.drowsyness = 0 + +/datum/reagent/drink/grenadine + name = "Grenadine Syrup" + description = "Made in the modern day with proper pomegranate substitute. Who uses real fruit, anyways?" + taste_description = "100% pure pomegranate" + color = "#ff004f" + + glass_name = "grenadine syrup" + glass_desc = "Sweet and tangy, a bar syrup used to add color or flavor to drinks." + +/datum/reagent/drink/space_cola + name = "Trench Cola" + description = "A refreshing beverage." + taste_description = "cola" + reagent_state = REAGENT_LIQUID + color = "#100800" + adj_drowsy = -3 + adj_temp = -5 + + glass_name = "Trench Cola" + glass_desc = "A glass of refreshing Trench Cola" + glass_special = list(DRINK_FIZZ) + +/datum/reagent/drink/spacemountainwind + name = "Trench Mountain Wind" + description = "Blows right through you like a mortar." + taste_description = "sweet citrus soda" + color = "#102000" + adj_drowsy = -7 + adj_sleepy = -1 + adj_temp = -5 + + glass_name = "Trench Mountain Wind" + glass_desc = "Trench Mountain Wind. As you know, there are no mountains in the trenches, only death." + glass_special = list(DRINK_FIZZ) + +/datum/reagent/drink/dr_gibb + name = "Dr. Gibb" + description = "A delicious blend of 42 different flavours" + taste_description = "cherry soda" + color = "#102000" + adj_drowsy = -6 + adj_temp = -5 + + glass_name = "Dr. Gibb" + glass_desc = "Dr. Gibb. Not as dangerous as the name might imply." + +/datum/reagent/drink/space_up + name = "Space-Up" + description = "Tastes like a hull breach in your mouth." + taste_description = "a hull breach" + color = "#202800" + adj_temp = -8 + + glass_name = "Space-up" + glass_desc = "Space-up. It helps keep your cool." + glass_special = list(DRINK_FIZZ) + +/datum/reagent/drink/lemon_lime + name = "Lemon Lime" + description = "A tangy substance made of 0.5% natural citrus!" + taste_description = "tangy lime and lemon soda" + color = "#878f00" + adj_temp = -8 + + glass_name = "lemon lime soda" + glass_desc = "A tangy substance made of 0.5% natural citrus!" + glass_special = list(DRINK_FIZZ) + +/datum/reagent/drink/doctor_delight + name = "The Doctor's Delight" + description = "A gulp a day keeps the MediBot away. That's probably for the best." + taste_description = "homely fruit" + reagent_state = REAGENT_LIQUID + color = "#ff8cff" + nutrition = 1 + + glass_name = "The Doctor's Delight" + glass_desc = "A healthy mixture of juices, guaranteed to keep you healthy until the next toolboxing takes place." + +/datum/reagent/drink/doctor_delight/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(alien == IS_DIONA) + return + M.adjustOxyLoss(-4 * removed) + M.heal_organ_damage(2 * removed, 2 * removed) + M.adjustToxLoss(-2 * removed) + if(M.dizziness) + M.dizziness = max(0, M.dizziness - 15) + if(M.confused) + M.confused = max(0, M.confused - 5) + +/datum/reagent/drink/dry_ramen + name = "Dry Ramen" + description = "Space age food, since August 25, 1958. Contains dried noodles, vegetables, and chemicals that boil in contact with water." + taste_description = "dry and cheap noodles" + reagent_state = REAGENT_SOLID + nutrition = 1 + color = "#302000" + +/datum/reagent/drink/hot_ramen + name = "Hot Ramen" + description = "The noodles are boiled, the flavors are artificial, just like being back in school." + taste_description = "wet and cheap noodles" + reagent_state = REAGENT_LIQUID + color = "#302000" + nutrition = 5 + adj_temp = 5 + +/datum/reagent/drink/hell_ramen + name = "Hell Ramen" + description = "The noodles are boiled, the flavors are artificial, just like being back in school." + taste_description = "wet and cheap noodles on fire" + reagent_state = REAGENT_LIQUID + color = "#302000" + nutrition = 5 + +/datum/reagent/drink/hell_ramen/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(alien == IS_DIONA) + return + M.bodytemperature += 10 * TEMPERATURE_DAMAGE_COEFFICIENT + +/datum/reagent/drink/ice + name = "Ice" + description = "Frozen water, your dentist wouldn't like you chewing this." + taste_description = "ice" + taste_mult = 1.5 + reagent_state = REAGENT_SOLID + color = "#619494" + adj_temp = -5 + + glass_name = "ice" + glass_desc = "Generally, you're supposed to put something else in there too..." + glass_icon = DRINK_ICON_NOISY + +/datum/reagent/drink/nothing + name = "Nothing" + description = "Absolutely nothing." + taste_description = "nothing" + + glass_name = "nothing" + glass_desc = "Absolutely nothing." + +/* Alcohol */ + +// Basic + +/datum/reagent/ethanol/absinthe + name = "Absinthe" + description = "Watch out that the Green Fairy doesn't come for you!" + taste_description = "death and licorice" + taste_mult = 1.5 + color = "#33ee00" + strength = 12 + + glass_name = "absinthe" + glass_desc = "Wormwood, anise, oh my." + +/datum/reagent/ethanol/ale + name = "Ale" + description = "A dark alchoholic beverage made by malted barley and yeast." + taste_description = "hearty barley ale" + color = "#4c3100" + strength = 50 + + glass_name = "ale" + glass_desc = "A freezing pint of delicious ale" + +/datum/reagent/ethanol/beer + name = "Beer" + description = "An alcoholic beverage made from malted grains, hops, yeast, and water." + taste_description = "piss water" + color = "#ffd300" + strength = 50 + nutriment_factor = 1 + + glass_name = "beer" + glass_desc = "A freezing pint of beer" + +/datum/reagent/ethanol/beer/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(alien == IS_DIONA) + return + M.jitteriness = max(M.jitteriness - 3, 0) + +/datum/reagent/ethanol/bluecuracao + name = "Blue Curacao" + description = "Exotically blue, fruity drink, distilled from oranges." + taste_description = "oranges" + taste_mult = 1.1 + color = "#0000cd" + strength = 15 + + glass_name = "blue curacao" + glass_desc = "Exotically blue, fruity drink, distilled from oranges." + +/datum/reagent/ethanol/cognac + name = "Cognac" + description = "A sweet and strongly alchoholic drink, made after numerous distillations and years of maturing. Classy as fornication." + taste_description = "rich and smooth alcohol" + taste_mult = 1.1 + color = "#ab3c05" + strength = 15 + + glass_name = "cognac" + glass_desc = "Damn, you feel like some kind of French aristocrat just by holding this." + +/datum/reagent/ethanol/deadrum + name = "Deadrum" + description = "Popular with the sailors. Not very popular with everyone else." + taste_description = "salty sea water" + color = "#ecb633" + strength = 50 + + glass_name = "rum" + glass_desc = "Now you want to Pray for a pirate suit, don't you?" + +/datum/reagent/ethanol/deadrum/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(alien == IS_DIONA) + return + M.dizziness +=5 + +/datum/reagent/ethanol/gin + name = "Gin" + description = "It's gin. In space. I say, good sir." + taste_description = "an alcoholic christmas tree" + color = "#0064c6" + strength = 15 + + glass_name = "gin" + glass_desc = "A crystal clear glass of Griffeater gin." + +//Base type for alchoholic drinks containing coffee +/datum/reagent/ethanol/coffee + overdose = 45 + +/datum/reagent/ethanol/coffee/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + ..() + M.dizziness = max(0, M.dizziness - 5) + M.drowsyness = max(0, M.drowsyness - 3) + M.sleeping = max(0, M.sleeping - 2) + if(M.bodytemperature > 310) + M.bodytemperature = max(310, M.bodytemperature - (5 * TEMPERATURE_DAMAGE_COEFFICIENT)) + if(alien == IS_TAJARA) + M.adjustToxLoss(0.5 * removed) + M.make_jittery(4) //extra sensitive to caffine + +/datum/reagent/ethanol/coffee/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_TAJARA) + M.adjustToxLoss(2 * removed) + M.make_jittery(4) + return + ..() + +/datum/reagent/ethanol/coffee/overdose(var/mob/living/carbon/M, var/alien) + if(alien == IS_DIONA) + return + if(alien == IS_TAJARA) + M.adjustToxLoss(4 * REM) + M.apply_effect(3, STUTTER) + M.make_jittery(5) + +/datum/reagent/ethanol/coffee/kahlua + name = "Kahlua" + description = "A widely known, Mexican coffee-flavoured liqueur. In production since 1936!" + taste_description = "spiked latte" + taste_mult = 1.1 + color = "#4c3100" + strength = 15 + + glass_name = "RR coffee liquor" + glass_desc = "DAMN, THIS THING LOOKS ROBUST" + +/datum/reagent/ethanol/melonliquor + name = "Melon Liquor" + description = "A relatively sweet and fruity 46 proof liquor." + taste_description = "fruity alcohol" + color = "#138808" // rgb: 19, 136, 8 + strength = 50 + + glass_name = "melon liquor" + glass_desc = "A relatively sweet and fruity 46 proof liquor." + +/datum/reagent/ethanol/rum + name = "Rum" + description = "Yohoho and all that." + taste_description = "spiked butterscotch" + taste_mult = 1.1 + color = "#ecb633" + strength = 15 + + glass_name = "rum" + glass_desc = "Now you want to Pray for a pirate suit, don't you?" + +/datum/reagent/ethanol/sake + name = "Sake" + description = "Anime's favorite drink." + taste_description = "dry alcohol" + color = "#dddddd" + strength = 25 + + glass_name = "sake" + glass_desc = "A glass of sake." + +/datum/reagent/ethanol/tequilla + name = "Tequila" + description = "A strong and mildly flavoured, mexican produced spirit. Feeling thirsty hombre?" + taste_description = "paint stripper" + color = "#ffff91" + strength = 25 + + glass_name = "Tequilla" + glass_desc = "Now all that's missing is the weird colored shades!" + +/datum/reagent/ethanol/thirteenloko + name = "Thirteen Loko" + description = "A potent mixture of caffeine and alcohol." + taste_description = "jitters and death" + color = "#102000" + strength = 25 + nutriment_factor = 1 + + glass_name = "Thirteen Loko" + glass_desc = "This is a glass of Thirteen Loko, it appears to be of the highest quality. The drink, not the glass." + +/datum/reagent/ethanol/thirteenloko/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(alien == IS_DIONA) + return + M.drowsyness = max(0, M.drowsyness - 7) + if (M.bodytemperature > 310) + M.bodytemperature = max(310, M.bodytemperature - (5 * TEMPERATURE_DAMAGE_COEFFICIENT)) + M.make_jittery(5) + M.add_chemical_effect(CE_PULSE, 2) + +/datum/reagent/ethanol/vermouth + name = "Vermouth" + description = "You suddenly feel a craving for a martini..." + taste_description = "dry alcohol" + taste_mult = 1.3 + color = "#91ff91" // rgb: 145, 255, 145 + strength = 15 + + glass_name = "vermouth" + glass_desc = "You wonder why you're even drinking this straight." + +/datum/reagent/ethanol/vodka + name = "Vodka" + description = "Number one drink AND fueling choice for Terrans around the galaxy." + taste_description = "grain alcohol" + color = "#0064c8" // rgb: 0, 100, 200 + strength = 15 + + glass_name = "vodka" + glass_desc = "The glass contain wodka. Xynta." + +/datum/reagent/ethanol/vodka/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + M.apply_effect(max(M.radiation - 1 * removed, 0), IRRADIATE, blocked = 0) + +/datum/reagent/ethanol/vodka/premium + name = "Premium Vodka" + description = "Premium distilled vodka imported directly from the Terran Colonial Confederation." + taste_description = "clear kvass" + color = "#aaddff" // rgb: 170, 221, 255 - very light blue. + strength = 10 + +/datum/reagent/ethanol/whiskey + name = "Whiskey" + description = "A superb and well-aged single-malt whiskey. Damn." + taste_description = "molasses" + color = "#4c3100" + strength = 25 + + glass_name = "whiskey" + glass_desc = "The silky, smokey whiskey goodness inside the glass makes the drink look very classy." + +/datum/reagent/ethanol/wine + name = "Wine" + description = "An premium alchoholic beverage made from distilled grape juice." + taste_description = "bitter sweetness" + color = "#7e4043" // rgb: 126, 64, 67 + strength = 15 + + glass_name = "wine" + glass_desc = "A very classy looking drink." + +/datum/reagent/ethanol/wine/premium + name = "White Wine" + description = "An exceptionally expensive alchoholic beverage made from distilled white grapes." + taste_description = "white velvet" + color = "#ffddaa" // rgb: 255, 221, 170 - a light cream + strength = 20 + +/datum/reagent/ethanol/herbal + name = "Herbal Liquor" + description = "A complex blend of herbs, spices and roots mingle in this old Earth classic." + taste_description = "a sweet summer garden" + color = "#dfff00" + strength = 13 + + glass_name = "herbal liquor" + glass_desc = "It's definitely green. Or is it yellow?" + +// Cocktails +/datum/reagent/ethanol/acid_spit + name = "Acid Spit" + description = "A drink for the daring, can be deadly if incorrectly prepared!" + taste_description = "stomach acid" + reagent_state = REAGENT_LIQUID + color = "#365000" + strength = 30 + + glass_name = "Acid Spit" + glass_desc = "A drink from the company archives. Made from live aliens." + +/datum/reagent/ethanol/alliescocktail + name = "Allies Cocktail" + description = "A drink made from your allies, not as sweet as when made from your enemies." + taste_description = "bitter yet free" + color = "#d8ac45" + strength = 25 + + glass_name = "Allies cocktail" + glass_desc = "A drink made from your allies." + +/datum/reagent/ethanol/aloe + name = "Aloe" + description = "So very, very, very good." + taste_description = "sweet 'n creamy" + color = "#b7ea75" + strength = 15 + + glass_name = "Aloe" + glass_desc = "Very, very, very good." + +/datum/reagent/ethanol/amasec + name = "Amasec" + description = "Official drink of the Gun Club!" + taste_description = "dark and metallic" + reagent_state = REAGENT_LIQUID + color = "#ff975d" + strength = 25 + + glass_name = "Amasec" + glass_desc = "Always handy before COMBAT!!!" + +/datum/reagent/ethanol/andalusia + name = "Andalusia" + description = "A nice, strangely named drink." + taste_description = "lemons" + color = "#f4ea4a" + strength = 15 + + glass_name = "Andalusia" + glass_desc = "A nice, strange named drink." + +/datum/reagent/ethanol/antifreeze + name = "Anti-freeze" + description = "Ultimate refreshment." + taste_description = "Jack Frost's piss" + color = "#56deea" + strength = 12 + adj_temp = 20 + targ_temp = 330 + + glass_name = "Anti-freeze" + glass_desc = "The ultimate refreshment." + +/datum/reagent/ethanol/atomicbomb + name = "Atomic Bomb" + description = "Nuclear proliferation never tasted so good." + taste_description = "da bomb" + reagent_state = REAGENT_LIQUID + color = "#666300" + strength = 10 + druggy = 50 + + glass_name = "Atomic Bomb" + glass_desc = "We cannot take legal responsibility for your actions after imbibing." + +/datum/reagent/ethanol/coffee/b52 + name = "B-52" + description = "Coffee, Irish Cream, and cognac. You will get bombed." + taste_description = "angry and irish" + taste_mult = 1.3 + color = "#997650" + strength = 12 + + glass_name = "B-52" + glass_desc = "Kahlua, Irish cream, and congac. You will get bombed." + +/datum/reagent/ethanol/bahama_mama + name = "Bahama mama" + description = "Tropical cocktail." + taste_description = "lime and orange" + color = "#ff7f3b" + strength = 25 + + glass_name = "Bahama Mama" + glass_desc = "Tropical cocktail" + +/datum/reagent/ethanol/bananahonk + name = "Banana Mama" + description = "A drink from Clown Heaven." + taste_description = "a bad joke" + nutriment_factor = 1 + color = "#ffff91" + strength = 12 + + glass_name = "Banana Honk" + glass_desc = "A drink from Banana Heaven." + +/datum/reagent/ethanol/barefoot + name = "Barefoot" + description = "Barefoot and pregnant" + taste_description = "creamy berries" + color = "#ffcdea" + strength = 30 + + glass_name = "Barefoot" + glass_desc = "Barefoot and pregnant" + +/datum/reagent/ethanol/beepsky_smash + name = "Beepsky Smash" + description = "Deny drinking this and prepare for THE LAW." + taste_description = "JUSTICE" + taste_mult = 2 + reagent_state = REAGENT_LIQUID + color = "#404040" + strength = 12 + + glass_name = "Beepsky Smash" + glass_desc = "Heavy, hot and strong. Just like the Iron fist of the LAW." + +/datum/reagent/ethanol/beepsky_smash/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + M.Stun(2) + +/datum/reagent/ethanol/bilk + name = "Bilk" + description = "This appears to be beer mixed with milk. Disgusting." + taste_description = "desperation and lactate" + color = "#895c4c" + strength = 50 + nutriment_factor = 2 + + glass_name = "bilk" + glass_desc = "A brew of milk and beer. For those alcoholics who fear osteoporosis." + +/datum/reagent/ethanol/black_russian + name = "Black Russian" + description = "For the lactose-intolerant. Still as classy as a White Russian." + taste_description = "bitterness" + color = "#360000" + strength = 15 + + glass_name = "Black Russian" + glass_desc = "For the lactose-intolerant. Still as classy as a White Russian." + +/datum/reagent/ethanol/bloody_mary + name = "Bloody Mary" + description = "A strange yet pleasurable mixture made of vodka, tomato and lime juice. Or at least you THINK the red stuff is tomato juice." + taste_description = "tomatoes with a hint of lime" + color = "#b40000" + strength = 15 + + glass_name = "Bloody Mary" + glass_desc = "Tomato juice, mixed with Vodka and a lil' bit of lime. Tastes like liquid murder." + +/datum/reagent/ethanol/booger + name = "Booger" + description = "Ewww..." + taste_description = "sweet 'n creamy" + color = "#8cff8c" + strength = 30 + + glass_name = "Booger" + glass_desc = "Ewww..." + +/datum/reagent/ethanol/coffee/brave_bull + name = "Brave Bull" + description = "It's just as effective as Dutch-Courage!" + taste_description = "alcoholic bravery" + taste_mult = 1.1 + color = "#4c3100" + strength = 15 + + glass_name = "Brave Bull" + glass_desc = "Tequilla and coffee liquor, brought together in a mouthwatering mixture. Drink up." + +/datum/reagent/ethanol/changelingsting + name = "Changeling Sting" + description = "You take a tiny sip and feel a burning sensation..." + taste_description = "your brain coming out your nose" + color = "#2e6671" + strength = 10 + + glass_name = "Changeling Sting" + glass_desc = "A stingy drink." + +/datum/reagent/ethanol/martini + name = "Classic Martini" + description = "Vermouth with Gin. Not quite how 007 enjoyed it, but still delicious." + taste_description = "dry class" + color = "#0064c8" + strength = 25 + + glass_name = "classic martini" + glass_desc = "Damn, the bartender even stirred it, not shook it." + +/datum/reagent/ethanol/cuba_libre + name = "Cuba Libre" + description = "Rum, mixed with cola. Viva la revolucion." + taste_description = "cola" + color = "#3e1b00" + strength = 30 + + glass_name = "Cuba Libre" + glass_desc = "A classic mix of rum and cola." + +/datum/reagent/ethanol/demonsblood + name = "Demons Blood" + description = "AHHHH!!!!" + taste_description = "sweet tasting iron" + taste_mult = 1.5 + color = "#820000" + strength = 15 + + glass_name = "Demons' Blood" + glass_desc = "Just looking at this thing makes the hair at the back of your neck stand up." + +/datum/reagent/ethanol/devilskiss + name = "Devils Kiss" + description = "Creepy time!" + taste_description = "bitter iron" + color = "#a68310" + strength = 15 + + glass_name = "Devil's Kiss" + glass_desc = "Creepy time!" + +/datum/reagent/ethanol/driestmartini + name = "Driest Martini" + description = "Only for the experienced. You think you see sand floating in the glass." + taste_description = "a beach" + nutriment_factor = 1 + color = "#2e6671" + strength = 12 + + glass_name = "Driest Martini" + glass_desc = "Only for the experienced. You think you see sand floating in the glass." + +/datum/reagent/ethanol/ginfizz + name = "Gin Fizz" + description = "Refreshingly lemony, deliciously dry." + taste_description = "dry, tart lemons" + color = "#ffffae" + strength = 30 + + glass_name = "gin fizz" + glass_desc = "Refreshingly lemony, deliciously dry." + +/datum/reagent/ethanol/grog + name = "Grog" + description = "Watered-down rum, pirate approved!" + taste_description = "a poor excuse for alcohol" + reagent_state = REAGENT_LIQUID + color = "#ffbb00" + strength = 100 + + glass_name = "grog" + glass_desc = "A fine and cepa drink for Space." + +/datum/reagent/ethanol/erikasurprise + name = "Erika Surprise" + description = "The surprise is, it's green!" + taste_description = "tartness and bananas" + color = "#2e6671" + strength = 15 + + glass_name = "Erika Surprise" + glass_desc = "The surprise is, it's green!" + +/datum/reagent/ethanol/gargle_blaster + name = "Pan-Galactic Gargle Blaster" + description = "Whoah, this stuff looks volatile!" + taste_description = "your brains smashed out by a lemon wrapped around a gold brick" + taste_mult = 5 + reagent_state = REAGENT_LIQUID + color = "#7f00ff" + strength = 10 + + glass_name = "Pan-Galactic Gargle Blaster" + glass_desc = "Does... does this mean that Arthur and Ford are here? Oh joy." + +/datum/reagent/ethanol/gintonic + name = "Gin and Tonic" + description = "An all time classic, mild cocktail." + taste_description = "mild and tart" + color = "#0064c8" + strength = 50 + + glass_name = "gin and tonic" + glass_desc = "A mild but still great cocktail. Drink up, like a true Englishman." + +/datum/reagent/ethanol/goldschlager + name = "Goldschlager" + description = "100 proof cinnamon schnapps, made for alcoholic teen girls on spring break." + taste_description = "burning cinnamon" + taste_mult = 1.3 + color = "#f4e46d" + strength = 15 + + glass_name = "Goldschlager" + glass_desc = "100 proof that teen girls will drink anything with gold in it." + +/datum/reagent/ethanol/hippies_delight + name = "Hippies' Delight" + description = "You just don't get it maaaan." + taste_description = "giving peace a chance" + reagent_state = REAGENT_LIQUID + color = "#ff88ff" + strength = 15 + druggy = 50 + + glass_name = "Hippie's Delight" + glass_desc = "A drink enjoyed by people during the 1960's." + +/datum/reagent/ethanol/hooch + name = "Hooch" + description = "Either someone's failure at cocktail making or attempt in alchohol production. In any case, do you really want to drink that?" + taste_description = "pure resignation" + color = "#4c3100" + strength = 25 + toxicity = 2 + + glass_name = "Hooch" + glass_desc = "You've really hit rock bottom now... your liver packed its bags and left last night." + +/datum/reagent/ethanol/iced_beer + name = "Iced Beer" + description = "A beer which is so cold the air around it freezes." + taste_description = "refreshingly cold" + color = "#ffd300" + strength = 50 + adj_temp = -20 + targ_temp = 270 + + glass_name = "iced beer" + glass_desc = "A beer so frosty, the air around it freezes." + glass_special = list(DRINK_ICE) + +/datum/reagent/ethanol/irishcarbomb + name = "Irish Car Bomb" + description = "Mmm, tastes like chocolate cake..." + taste_description = "delicious anger" + color = "#2e6671" + strength = 15 + + glass_name = "Irish Car Bomb" + glass_desc = "An irish car bomb." + +/datum/reagent/ethanol/coffee/irishcoffee + name = "Irish Coffee" + description = "Coffee, and alcohol. More fun than a Mimosa to drink in the morning." + taste_description = "giving up on the day" + color = "#4c3100" + strength = 15 + + glass_name = "Irish coffee" + glass_desc = "Coffee and alcohol. More fun than a Mimosa to drink in the morning." + +/datum/reagent/ethanol/irish_cream + name = "Irish Cream" + description = "Whiskey-imbued cream, what else would you expect from the Irish." + taste_description = "creamy alcohol" + color = "#dddd9a3" + strength = 25 + + glass_name = "Irish cream" + glass_desc = "It's cream, mixed with whiskey. What else would you expect from the Irish?" + +/datum/reagent/ethanol/longislandicedtea + name = "Long Island Iced Tea" + description = "The liquor cabinet, brought together in a delicious mix. Intended for middle-aged alcoholic women only." + taste_description = "a mixture of cola and alcohol" + color = "#895b1f" + strength = 12 + + glass_name = "Long Island iced tea" + glass_desc = "The liquor cabinet, brought together in a delicious mix. Intended for middle-aged alcoholic women only." + +/datum/reagent/ethanol/manhattan + name = "Manhattan" + description = "The Detective's undercover drink of choice. He never could stomach gin..." + taste_description = "mild dryness" + color = "#c13600" + strength = 15 + + glass_name = "Manhattan" + glass_desc = "The Detective's undercover drink of choice. He never could stomach gin..." + +/datum/reagent/ethanol/manhattan_proj + name = "Manhattan Project" + description = "A scientist's drink of choice, for pondering ways to blow stuff up." + taste_description = "death, the destroyer of worlds" + color = "#c15d00" + strength = 10 + druggy = 30 + + glass_name = "Manhattan Project" + glass_desc = "A scientist's drink of choice, for pondering ways to blow stuff up." + +/datum/reagent/ethanol/manly_dorf + name = "The Manly Dorf" + description = "Beer and Ale, brought together in a delicious mix. Intended for true men only." + taste_description = "hair on your chest and your chin" + color = "#4c3100" + strength = 25 + + glass_name = "The Manly Dorf" + glass_desc = "A manly concotion made from Ale and Beer. Intended for true men only." + +/datum/reagent/ethanol/margarita + name = "Margarita" + description = "On the rocks with salt on the rim. Arriba~!" + taste_description = "dry and salty" + color = "#8cff8c" + strength = 15 + + glass_name = "margarita" + glass_desc = "On the rocks with salt on the rim. Arriba~!" + +/datum/reagent/ethanol/battuta + name = "Ibn Batutta" + description = "One of the Official Cocktails of the Expeditionary Corps, celebrating Muhammad Ibn Battuta." + taste_description = "a Moroccan garden" + color = "#dfbe00" + strength = 18 + + glass_name = "Ibn Batutta cocktail" + glass_desc = "A refreshing blend of herbal liquor, the juice of an orange and a hint of mint. Named for Muhammad Ibn Battuta, whose travels spanned from Mali eastward to China in the 14th century." + +/datum/reagent/ethanol/magellan + name = "Magellan" + description = "One of the Official Cocktails of the Expeditionary Corps, celebrating Ferdinand Magellan." + taste_description = "an aristrocatic experience" + color = "#6b3535" + strength = 13 + + glass_name = "Magellan cocktail" + glass_desc = "A tasty sweetened blend of wine and fine whiskey. Named for Ferdinand Magellan, who led the first expedition to circumnavigate Earth in the 15th century." + +/datum/reagent/ethanol/zhenghe + name = "Zheng He" + description = "One of the Official Cocktails of the Expeditionary Corps, celebrating Zheng He." + taste_description = "herbal bitterness" + color = "#173b06" + strength = 20 + + glass_name = "Zheng He cocktail" + glass_desc = "A rather bitter blend of vermouth and well-steeped black tea. Named for Zheng He, who travelled from Nanjing in China as far as Mogadishu in the Horn of Africa in the 15th century." + +/datum/reagent/ethanol/armstrong + name = "Armstrong" + description = "One of the Official Cocktails of the Expeditionary Corps, celebrating Neil Armstrong." + taste_description = "limes and alcoholic beer" + color = "#ffd300" + strength = 15 + + glass_name = "Armstrong cocktail" + glass_desc = "Beer, vodka and lime come together in this instant classic. Named for Neil Armstrong, who was the first man to set foot on Luna, in the 20th century." + +/datum/reagent/ethanol/mead + name = "Mead" + description = "A Viking's drink, though a cheap one." + taste_description = "sweet, sweet alcohol" + reagent_state = REAGENT_LIQUID + color = "#ffbb00" + strength = 30 + nutriment_factor = 1 + + glass_name = "mead" + glass_desc = "A Viking's beverage, though a cheap one." + +/datum/reagent/ethanol/moonshine + name = "Moonshine" + description = "You've really hit rock bottom now... your liver packed its bags and left last night." + taste_description = "bitterness" + taste_mult = 2.5 + color = "#0064c8" + strength = 12 + + glass_name = "moonshine" + glass_desc = "You've really hit rock bottom now... your liver packed its bags and left last night." + +/datum/reagent/ethanol/neurotoxin + name = "Neurotoxin" + description = "A strong neurotoxin that puts the subject into a death-like state." + taste_description = "a numbing sensation" + reagent_state = REAGENT_LIQUID + color = "#2e2e61" + strength = 10 + + glass_name = "Neurotoxin" + glass_desc = "A drink that is guaranteed to knock you silly." + glass_icon = DRINK_ICON_NOISY + glass_special = list("neuroright") + +/datum/reagent/ethanol/neurotoxin/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + M.Weaken(3) + M.add_chemical_effect(CE_PULSE, -1) + +/datum/reagent/ethanol/patron + name = "Patron" + description = "Tequila with silver in it, a favorite of alcoholic women in the club scene." + taste_description = "metallic and expensive" + color = "#585840" + strength = 30 + + glass_name = "Patron" + glass_desc = "Drinking patron in the bar, with all the subpar ladies." + +/datum/reagent/ethanol/pwine + name = "Poison Wine" + description = "Is this even wine? Toxic! Hallucinogenic! Probably consumed in boatloads by your superiors!" + taste_description = "purified alcoholic death" + color = "#000000" + strength = 10 + druggy = 50 + halluci = 10 + + glass_name = "???" + glass_desc = "A black ichor with an oily purple sheer on top. Are you sure you should drink this?" + +/datum/reagent/ethanol/pwine/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(M.chem_doses[type] > 30) + M.adjustToxLoss(2 * removed) + if(M.chem_doses[type] > 60 && ishuman(M) && prob(5)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/internal/heart/L = H.internal_organs_by_name[BP_HEART] + if (L && istype(L)) + if(M.chem_doses[type] < 120) + L.take_damage(10 * removed, 0) + else + L.take_damage(100, 0) + +/datum/reagent/ethanol/red_mead + name = "Red Mead" + description = "The true Viking's drink! Even though it has a strange red color." + taste_description = "sweet and salty alcohol" + color = "#c73c00" + strength = 30 + + glass_name = "red mead" + glass_desc = "A true Viking's beverage, though its color is strange." + +/datum/reagent/ethanol/sbiten + name = "Sbiten" + description = "A spicy Mead! Might be a little hot for the little guys!" + taste_description = "hot and spice" + color = "#ffa371" + strength = 15 + adj_temp = 50 + targ_temp = 360 + + glass_name = "Sbiten" + glass_desc = "A spicy mix of Mead and Spice. Very hot." + +/datum/reagent/ethanol/screwdrivercocktail + name = "Screwdriver" + description = "Vodka, mixed with plain ol' orange juice. The result is surprisingly delicious." + taste_description = "oranges" + color = "#a68310" + strength = 15 + + glass_name = "Screwdriver" + glass_desc = "A simple, yet superb mixture of Vodka and orange juice. Just the thing for the tired engineer." + +/datum/reagent/ethanol/ships_surgeon + name = "Ship's Surgeon" + description = "Rum and Dr. Gibb. Served ice cold, like the scalpel." + taste_description = "black comedy" + color = "#524d0f" + strength = 15 + + glass_name = "ship's surgeon" + glass_desc = "Rum qualified for surgical practice by Dr. Gibb. Smooth and steady." + +/datum/reagent/ethanol/silencer + name = "Silencer" + description = "A drink from Mime Heaven." + taste_description = "a pencil eraser" + taste_mult = 1.2 + nutriment_factor = 1 + color = "#ffffff" + strength = 12 + + glass_name = "Silencer" + glass_desc = "A drink from mime Heaven." + +/datum/reagent/ethanol/singulo + name = "Singulo" + description = "A blue-space beverage!" + taste_description = "concentrated matter" + color = "#2e6671" + strength = 10 + + glass_name = "Singulo" + glass_desc = "A blue-space beverage." + +/datum/reagent/ethanol/snowwhite + name = "Snow White" + description = "A cold refreshment" + taste_description = "refreshing cold" + color = "#ffffff" + strength = 30 + + glass_name = "Snow White" + glass_desc = "A cold refreshment." + +/datum/reagent/ethanol/suidream + name = "Sui Dream" + description = "Comprised of: White soda, blue curacao, melon liquor." + taste_description = "fruit" + color = "#00a86b" + strength = 100 + + glass_name = "Sui Dream" + glass_desc = "A froofy, fruity, and sweet mixed drink. Understanding the name only brings shame." + +/datum/reagent/ethanol/syndicatebomb + name = "Syndicate Bomb" + description = "Tastes like terrorism!" + taste_description = "purified antagonism" + color = "#2e6671" + strength = 10 + + glass_name = "Syndicate Bomb" + glass_desc = "Tastes like terrorism!" + +/datum/reagent/ethanol/tequilla_sunrise + name = "Tequila Sunrise" + description = "Tequila and orange juice. Much like a Screwdriver, only Mexican~" + taste_description = "oranges" + color = "#ffe48c" + strength = 25 + + glass_name = "Tequilla Sunrise" + glass_desc = "Oh great, now you feel nostalgic about sunrises back on Terra..." + +/datum/reagent/ethanol/threemileisland + name = "Three Mile Island Iced Tea" + description = "Made for a woman, strong enough for a man." + taste_description = "dry" + color = "#666340" + strength = 10 + druggy = 50 + + glass_name = "Three Mile Island iced tea" + glass_desc = "A glass of this is sure to prevent a meltdown." + +/datum/reagent/ethanol/toxins_special + name = "Toxins Special" + description = "This thing is ON FIRE! CALL THE DAMN SHUTTLE!" + taste_description = "spicy toxins" + reagent_state = REAGENT_LIQUID + color = "#7f00ff" + strength = 10 + adj_temp = 15 + targ_temp = 330 + + glass_name = "Toxins Special" + glass_desc = "Whoah, this thing is on FIRE" + +/datum/reagent/ethanol/vodkamartini + name = "Vodka Martini" + description = "Vodka with Gin. Not quite how 007 enjoyed it, but still delicious." + taste_description = "shaken, not stirred" + color = "#0064c8" + strength = 12 + + glass_name = "vodka martini" + glass_desc ="A bastardisation of the classic martini. Still great." + + +/datum/reagent/ethanol/vodkatonic + name = "Vodka and Tonic" + description = "For when a gin and tonic isn't russian enough." + taste_description = "tart bitterness" + color = "#0064c8" // rgb: 0, 100, 200 + strength = 15 + + glass_name = "vodka and tonic" + glass_desc = "For when a gin and tonic isn't Russian enough." + + +/datum/reagent/ethanol/white_russian + name = "White Russian" + description = "That's just, like, your opinion, man..." + taste_description = "bitter cream" + color = "#a68340" + strength = 15 + + glass_name = "White Russian" + glass_desc = "A very nice looking drink. But that's just, like, your opinion, man." + + +/datum/reagent/ethanol/whiskey_cola + name = "Whiskey Cola" + description = "Whiskey, mixed with cola. Surprisingly refreshing." + taste_description = "cola" + color = "#3e1b00" + strength = 25 + + glass_name = "whiskey cola" + glass_desc = "An innocent-looking mixture of cola and Whiskey. Delicious." + + +/datum/reagent/ethanol/whiskeysoda + name = "Whiskey Soda" + description = "For the more refined griffon." + color = "#eab300" + strength = 15 + + glass_name = "whiskey soda" + glass_desc = "Ultimate refreshment." + +/datum/reagent/ethanol/specialwhiskey // I have no idea what this is and where it comes from + name = "Special Blend Whiskey" + description = "Just when you thought regular whiskey was good... This silky, amber goodness has to come along and ruin everything." + taste_description = "liquid fire" + color = "#523600" + strength = 25 + + glass_name = "special blend whiskey" + glass_desc = "Just when you thought regular whiskey was good... This silky, amber goodness has to come along and ruin everything." diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Helpers.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Helpers.dm new file mode 100644 index 00000000..303940bd --- /dev/null +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Helpers.dm @@ -0,0 +1,14 @@ +/atom/movable/proc/can_be_injected_by(var/atom/injector) + if(!Adjacent(get_turf(injector))) + return FALSE + if(!reagents) + return FALSE + if(!reagents.get_free_space()) + return FALSE + return TRUE + +/obj/can_be_injected_by(var/atom/injector) + return is_open_container() && ..() + +/mob/living/can_be_injected_by(var/atom/injector) + return ..() && (can_inject(null, 0, BP_CHEST) || can_inject(null, 0, BP_GROIN)) diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm new file mode 100644 index 00000000..0cf22e64 --- /dev/null +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm @@ -0,0 +1,782 @@ +/* General medicine */ + +/datum/reagent/inaprovaline + name = "Inaprovaline" + description = "Inaprovaline is a multipurpose neurostimulant and cardioregulator. Commonly used to slow bleeding and stabilize patients." + taste_description = "bitterness" + reagent_state = REAGENT_LIQUID + color = "#00bfff" + overdose = REAGENTS_OVERDOSE * 2 + metabolism = REM * 0.5 + scannable = 1 + flags = IGNORE_MOB_SIZE + +/datum/reagent/inaprovaline/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien != IS_DIONA) + M.add_chemical_effect(CE_STABLE) + M.add_chemical_effect(CE_PAINKILLER, 10) + +/datum/reagent/atepoine + name = "Atepoine" + description = "Incredibly rare cardiac stimulant." + reagent_state = REAGENT_LIQUID + color = "#A0522D" + metabolism = 0.5 + overdose = REAGENTS_OVERDOSE + scannable = 1 + flags = AFFECTS_DEAD + +/datum/reagent/atepoine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.adjustBrainLoss(-5) + M.adjustOxyLoss(-200 * removed) + if(istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + + //Ports and simplifies defib code + if(H.stat != DEAD) + //if(H.ssd_check()) + // to_chat(find_dead_player(H.ckey, 1), "Enter the fray once more.") + // sleep(200) + + H.resuscitate() + +/datum/reagent/bicaridine + name = "Bicaridine" + description = "Bicaridine is an analgesic medication and can be used to treat blunt trauma." + taste_description = "bitterness" + taste_mult = 3 + reagent_state = REAGENT_LIQUID + color = "#bf0000" + overdose = REAGENTS_OVERDOSE + scannable = 1 + flags = IGNORE_MOB_SIZE + +/datum/reagent/bicaridine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien != IS_DIONA) + M.heal_organ_damage(6 * removed, 0) + +/datum/reagent/kelotane + name = "Kelotane" + description = "Kelotane is a drug used to treat burns." + taste_description = "bitterness" + reagent_state = REAGENT_LIQUID + color = "#ffa800" + overdose = REAGENTS_OVERDOSE + scannable = 1 + flags = IGNORE_MOB_SIZE + +/datum/reagent/kelotane/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien != IS_DIONA) + M.heal_organ_damage(0, 6 * removed) + +/datum/reagent/dermaline + name = "Dermaline" + description = "Dermaline is the next step in burn medication. Works twice as good as kelotane and enables the body to restore even the direst heat-damaged tissue." + taste_description = "bitterness" + taste_mult = 1.5 + reagent_state = REAGENT_LIQUID + color = "#ff8000" + overdose = REAGENTS_OVERDOSE * 0.5 + scannable = 1 + flags = IGNORE_MOB_SIZE + +/datum/reagent/dermaline/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien != IS_DIONA) + M.heal_organ_damage(0, 12 * removed) + +/datum/reagent/dylovene + name = "Dylovene" + description = "Dylovene is a broad-spectrum antitoxin used to neutralize poisons before they can do significant harm." + taste_description = "a roll of gauze" + reagent_state = REAGENT_LIQUID + color = "#00a000" + scannable = 1 + flags = IGNORE_MOB_SIZE + var/static/list/remove_toxins = list( + /datum/reagent/toxin/zombiepowder + ) + +/datum/reagent/dylovene/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + M.drowsyness = max(0, M.drowsyness - 6 * removed) + M.adjust_hallucination(-9 * removed) + M.add_up_to_chemical_effect(CE_ANTITOX, 1) + + var/removing = (4 * removed) + for(var/datum/reagent/R in M.ingested.reagent_list) + if(istype(R, /datum/reagent/toxin) || (R.type in remove_toxins)) + M.ingested.remove_reagent(R.type, removing) + return + for(var/datum/reagent/R in M.reagents.reagent_list) + if(istype(R, /datum/reagent/toxin) || (R.type in remove_toxins)) + M.reagents.remove_reagent(R.type, removing) + return + +/datum/reagent/dexalin + name = "Dexalin" + description = "Dexalin is used in the treatment of oxygen deprivation." + taste_description = "bitterness" + reagent_state = REAGENT_LIQUID + color = "#0080ff" + overdose = REAGENTS_OVERDOSE + scannable = 1 + flags = IGNORE_MOB_SIZE + +/datum/reagent/dexalin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_VOX) + M.adjustToxLoss(removed * 6) + else if(alien != IS_DIONA) + M.add_chemical_effect(CE_OXYGENATED, 1) + holder.remove_reagent(/datum/reagent/lexorin, 2 * removed) + +/datum/reagent/dexalinp + name = "Dexalin Plus" + description = "Dexalin Plus is used in the treatment of oxygen deprivation. It is highly effective." + taste_description = "bitterness" + reagent_state = REAGENT_LIQUID + color = "#0040ff" + overdose = REAGENTS_OVERDOSE * 0.5 + scannable = 1 + flags = IGNORE_MOB_SIZE + +/datum/reagent/dexalinp/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_VOX) + M.adjustToxLoss(removed * 9) + else if(alien != IS_DIONA) + M.add_chemical_effect(CE_OXYGENATED, 2) + holder.remove_reagent(/datum/reagent/lexorin, 3 * removed) + +/datum/reagent/tricordrazine + name = "Tricordrazine" + description = "Tricordrazine is a highly potent stimulant, originally derived from cordrazine. Can be used to treat a wide range of injuries." + taste_description = "grossness" + reagent_state = REAGENT_LIQUID + color = "#8040ff" + scannable = 1 + flags = IGNORE_MOB_SIZE + +/datum/reagent/tricordrazine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien != IS_DIONA) + M.heal_organ_damage(3 * removed, 3 * removed) + +/datum/reagent/cryoxadone + name = "Cryoxadone" + description = "A chemical mixture with almost magical healing powers. Its main limitation is that the targets body temperature must be under 170K for it to metabolise correctly." + taste_description = "sludge" + reagent_state = REAGENT_LIQUID + color = "#8080ff" + metabolism = REM * 0.05 + scannable = 1 + flags = IGNORE_MOB_SIZE + +/datum/reagent/cryoxadone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.add_chemical_effect(CE_CRYO, 1) + if(M.bodytemperature < 170) + M.adjustCloneLoss(-100 * removed) + M.add_chemical_effect(CE_OXYGENATED, 1) + M.heal_organ_damage(100 * removed, 100 * removed) + M.add_chemical_effect(CE_PULSE, -2) + +/datum/reagent/clonexadone + name = "Clonexadone" + description = "A liquid compound similar to that used in the cloning process. Can be used to 'finish' the cloning process when used in conjunction with a cryo tube." + taste_description = "slime" + reagent_state = REAGENT_LIQUID + color = "#80bfff" + metabolism = REM * 0.05 + scannable = 1 + flags = IGNORE_MOB_SIZE + +/datum/reagent/clonexadone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.add_chemical_effect(CE_CRYO, 1) + if(M.bodytemperature < 170) + M.adjustCloneLoss(-300 * removed) + M.add_chemical_effect(CE_OXYGENATED, 2) + M.heal_organ_damage(300 * removed, 300 * removed) + M.add_chemical_effect(CE_PULSE, -2) + +/* Painkillers */ + +/datum/reagent/paracetamol + name = "Paracetamol" + description = "Most probably know this as Tylenol, but this chemical is a mild, simple painkiller." + taste_description = "sickness" + reagent_state = REAGENT_LIQUID + color = "#c8a5dc" + overdose = 60 + scannable = 1 + metabolism = 0.02 + flags = IGNORE_MOB_SIZE + +/datum/reagent/paracetamol/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.add_chemical_effect(CE_PAINKILLER, 25) + +/datum/reagent/paracetamol/overdose(var/mob/living/carbon/M, var/alien) + ..() + M.druggy = max(M.druggy, 2) + M.add_chemical_effect(CE_PAINKILLER, 10) + +/datum/reagent/tramadol + name = "Tramadol" + description = "A simple, yet effective painkiller. Don't mix with alcohol." + taste_description = "sourness" + reagent_state = REAGENT_LIQUID + color = "#cb68fc" + overdose = 30 + scannable = 1 + metabolism = 0.05 + ingest_met = 0.02 + flags = IGNORE_MOB_SIZE + var/pain_power = 80 //magnitide of painkilling effect + var/effective_dose = 0.5 //how many units it need to process to reach max power + +/datum/reagent/tramadol/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + var/effectiveness = 1 + if(M.chem_doses[type] < effective_dose) //some ease-in ease-out for the effect + effectiveness = M.chem_doses[type]/effective_dose + else if(volume < effective_dose) + effectiveness = volume/effective_dose + M.add_chemical_effect(CE_PAINKILLER, pain_power * effectiveness) + if(M.chem_doses[type] > 0.5 * overdose) + M.add_chemical_effect(CE_SLOWDOWN, 1) + if(prob(1)) + M.slurring = max(M.slurring, 10) + if(M.chem_doses[type] > 0.75 * overdose) + M.add_chemical_effect(CE_SLOWDOWN, 1) + if(prob(5)) + M.slurring = max(M.slurring, 20) + if(M.chem_doses[type] > overdose) + M.add_chemical_effect(CE_SLOWDOWN, 1) + M.slurring = max(M.slurring, 30) + if(prob(1)) + M.Weaken(2) + M.drowsyness = max(M.drowsyness, 5) + var/boozed = isboozed(M) + if(boozed) + M.add_chemical_effect(CE_ALCOHOL_TOXIC, 1) + M.add_chemical_effect(CE_BREATHLOSS, 0.1 * boozed) //drinking and opiating makes breathing kinda hard + +/datum/reagent/tramadol/overdose(var/mob/living/carbon/M, var/alien) + ..() + M.hallucination(120, 30) + M.druggy = max(M.druggy, 10) + M.add_chemical_effect(CE_PAINKILLER, pain_power*0.5) //extra painkilling for extra trouble + M.add_chemical_effect(CE_BREATHLOSS, 0.6) //Have trouble breathing, need more air + if(isboozed(M)) + M.add_chemical_effect(CE_BREATHLOSS, 0.2) //Don't drink and OD on opiates folks + +/datum/reagent/tramadol/proc/isboozed(var/mob/living/carbon/M) + . = 0 + var/list/pool = M.reagents.reagent_list | M.ingested.reagent_list + for(var/datum/reagent/ethanol/booze in pool) + if(M.chem_doses[booze.type] < 2) //let them experience false security at first + continue + . = 1 + if(booze.strength < 40) //liquor stuff hits harder + return 2 + +/datum/reagent/tramadol/morphine + name = "Morphine" + +/datum/reagent/tramadol/oxycodone + name = "Oxycodone" + description = "An effective and very addictive painkiller. Don't mix with alcohol." + taste_description = "bitterness" + color = "#800080" + overdose = 20 + pain_power = 200 + effective_dose = 2 + +/* Other medicine */ + +/datum/reagent/synaptizine + name = "Synaptizine" + description = "Synaptizine is used to treat various diseases." + taste_description = "bitterness" + reagent_state = REAGENT_LIQUID + color = "#99ccff" + metabolism = REM * 0.05 + overdose = REAGENTS_OVERDOSE + scannable = 1 + +/datum/reagent/synaptizine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + M.drowsyness = max(M.drowsyness - 5, 0) + M.AdjustParalysis(-1) + M.AdjustStunned(-1) + M.AdjustWeakened(-1) + holder.remove_reagent(/datum/reagent/mindbreaker, 5) + M.adjust_hallucination(-10) + M.add_chemical_effect(CE_MIND, 2) + M.adjustToxLoss(5 * removed) // It used to be incredibly deadly due to an oversight. Not anymore! + M.add_chemical_effect(CE_PAINKILLER, 20) + +/datum/reagent/alkysine + name = "Alkysine" + description = "Alkysine is a drug used to lessen the damage to neurological tissue after a injury. Can aid in healing brain tissue." + taste_description = "bitterness" + reagent_state = REAGENT_LIQUID + color = "#ffff66" + metabolism = REM * 0.25 + overdose = REAGENTS_OVERDOSE + scannable = 1 + flags = IGNORE_MOB_SIZE + +/datum/reagent/alkysine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + M.add_chemical_effect(CE_PAINKILLER, 10) + M.add_chemical_effect(CE_BRAIN_REGEN, 1) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + H.confused++ + H.drowsyness++ + +/datum/reagent/imidazoline + name = "Imidazoline" + description = "Heals eye damage" + taste_description = "dull toxin" + reagent_state = REAGENT_LIQUID + color = "#c8a5dc" + overdose = REAGENTS_OVERDOSE + scannable = 1 + flags = IGNORE_MOB_SIZE + + +/datum/reagent/imidazoline/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.eye_blurry = max(M.eye_blurry - 5, 0) + M.eye_blind = max(M.eye_blind - 5, 0) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/internal/eyes/E = H.internal_organs_by_name[BP_EYES] + if(E && istype(E)) + if(E.damage > 0) + E.damage = max(E.damage - 5 * removed, 0) + +/datum/reagent/peridaxon + name = "Peridaxon" + description = "Used to encourage recovery of internal organs and nervous systems. Medicate cautiously." + taste_description = "bitterness" + reagent_state = REAGENT_LIQUID + color = "#561ec3" + overdose = 10 + scannable = 1 + flags = IGNORE_MOB_SIZE + +/datum/reagent/peridaxon/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + for(var/obj/item/organ/internal/I in H.internal_organs) + if(I.robotic >= ORGAN_ROBOT) + continue + if(I.organ_tag == BP_BRAIN) + H.confused++ + H.drowsyness++ + if(I.damage >= I.min_bruised_damage) + continue + I.damage = max(I.damage - removed, 0) + +/datum/reagent/ryetalyn + name = "Ryetalyn" + description = "Ryetalyn can cure all genetic abnomalities via a catalytic process." + taste_description = "acid" + reagent_state = REAGENT_SOLID + color = "#004000" + overdose = REAGENTS_OVERDOSE + +/datum/reagent/ryetalyn/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + var/needs_update = M.mutations.len > 0 + + M.mutations = list() + M.disabilities = 0 + M.sdisabilities = 0 + + // Might need to update appearance for hulk etc. + if(needs_update && ishuman(M)) + var/mob/living/carbon/human/H = M + H.update_mutations() + +/datum/reagent/hyperzine + name = "Hyperzine" + description = "Hyperzine is a highly effective, long lasting, muscle stimulant." + taste_description = "acid" + reagent_state = REAGENT_LIQUID + color = "#ff3300" + metabolism = REM * 0.15 + overdose = REAGENTS_OVERDOSE * 0.5 + +/datum/reagent/hyperzine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + if(prob(5)) + M.emote(pick("twitch", "blink_r", "shiver")) + M.add_chemical_effect(CE_SPEEDBOOST, 1) + M.add_chemical_effect(CE_PULSE, 2) + +/datum/reagent/ethylredoxrazine + name = "Ethylredoxrazine" + description = "A powerful oxidizer that reacts with ethanol." + reagent_state = REAGENT_SOLID + color = "#605048" + overdose = REAGENTS_OVERDOSE + +/datum/reagent/ethylredoxrazine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + M.dizziness = 0 + M.drowsyness = 0 + M.stuttering = 0 + M.confused = 0 + if(M.ingested) + for(var/datum/reagent/R in M.ingested.reagent_list) + if(istype(R, /datum/reagent/ethanol)) + M.chem_doses[R.type] = max(M.chem_doses[R.type] - removed * 5, 0) + +/datum/reagent/hyronalin + name = "Hyronalin" + description = "Hyronalin is a medicinal drug used to counter the effect of radiation poisoning." + taste_description = "bitterness" + reagent_state = REAGENT_LIQUID + color = "#408000" + metabolism = REM * 0.25 + overdose = REAGENTS_OVERDOSE + scannable = 1 + flags = IGNORE_MOB_SIZE + +/datum/reagent/hyronalin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.radiation = max(M.radiation - 30 * removed, 0) + +/datum/reagent/arithrazine + name = "Arithrazine" + description = "Arithrazine is an unstable medication used for the most extreme cases of radiation poisoning." + reagent_state = REAGENT_LIQUID + color = "#008000" + metabolism = REM * 0.25 + overdose = REAGENTS_OVERDOSE + scannable = 1 + flags = IGNORE_MOB_SIZE + +/datum/reagent/arithrazine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.radiation = max(M.radiation - 70 * removed, 0) + M.adjustToxLoss(-10 * removed) + if(prob(60)) + M.take_organ_damage(4 * removed, 0) + +/datum/reagent/spaceacillin + name = "Spaceacillin" + description = "An all-purpose antiviral agent." + taste_description = "bitterness" + reagent_state = REAGENT_LIQUID + color = "#c1c1c1" + metabolism = REM * 0.1 + overdose = REAGENTS_OVERDOSE/2 + scannable = 1 + +/datum/reagent/spaceacillin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.immunity = max(M.immunity - 0.1, 0) + M.add_chemical_effect(CE_ANTIVIRAL, VIRUS_COMMON) + if(volume > 10) + M.immunity = max(M.immunity - 0.3, 0) + M.add_chemical_effect(CE_ANTIVIRAL, VIRUS_ENGINEERED) + if(M.chem_doses[type] > 15) + M.immunity = max(M.immunity - 0.25, 0) + +/datum/reagent/spaceacillin/overdose(var/mob/living/carbon/M, var/alien) + ..() + M.immunity = max(M.immunity - 0.25, 0) + M.add_chemical_effect(CE_ANTIVIRAL, VIRUS_EXOTIC) + if(prob(2)) + M.immunity_norm = max(M.immunity_norm - 1, 0) + +/datum/reagent/sterilizine + name = "Sterilizine" + description = "Sterilizes wounds in preparation for surgery and thoroughly removes blood." + taste_description = "bitterness" + reagent_state = REAGENT_LIQUID + color = "#c8a5dc" + touch_met = 5 + +/datum/reagent/sterilizine/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) + M.germ_level -= min(removed*20, M.germ_level) + for(var/obj/item/I in M.contents) + I.was_bloodied = null + M.was_bloodied = null + +/datum/reagent/sterilizine/touch_obj(var/obj/O) + O.germ_level -= min(volume*20, O.germ_level) + O.was_bloodied = null + +/datum/reagent/sterilizine/touch_turf(var/turf/T) + T.germ_level -= min(volume*20, T.germ_level) + for(var/obj/item/I in T.contents) + I.was_bloodied = null + for(var/obj/effect/decal/cleanable/blood/B in T) + qdel(B) + +/datum/reagent/leporazine + name = "Leporazine" + description = "Leporazine can be use to stabilize an individuals body temperature." + taste_description = "bitterness" + reagent_state = REAGENT_LIQUID + color = "#c8a5dc" + overdose = REAGENTS_OVERDOSE + scannable = 1 + +/datum/reagent/leporazine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(M.bodytemperature > 310) + M.bodytemperature = max(310, M.bodytemperature - (40 * TEMPERATURE_DAMAGE_COEFFICIENT)) + else if(M.bodytemperature < 311) + M.bodytemperature = min(310, M.bodytemperature + (40 * TEMPERATURE_DAMAGE_COEFFICIENT)) + +/* Antidepressants */ + +#define ANTIDEPRESSANT_MESSAGE_DELAY 5*60*10 + +/datum/reagent/methylphenidate + name = "Methylphenidate" + description = "Improves the ability to concentrate." + taste_description = "sourness" + reagent_state = REAGENT_LIQUID + color = "#bf80bf" + metabolism = 0.01 + data = 0 + +/datum/reagent/methylphenidate/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + if(volume <= 0.1 && M.chem_doses[type] >= 0.5 && world.time > data + ANTIDEPRESSANT_MESSAGE_DELAY) + data = world.time + to_chat(M, "You lose focus...") + else + if(world.time > data + ANTIDEPRESSANT_MESSAGE_DELAY) + data = world.time + to_chat(M, "Your mind feels focused and undivided.") + +/datum/reagent/citalopram + name = "Citalopram" + description = "Stabilizes the mind a little." + taste_description = "bitterness" + reagent_state = REAGENT_LIQUID + color = "#ff80ff" + metabolism = 0.01 + data = 0 + +/datum/reagent/citalopram/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + if(volume <= 0.1 && M.chem_doses[type] >= 0.5 && world.time > data + ANTIDEPRESSANT_MESSAGE_DELAY) + data = world.time + to_chat(M, "Your mind feels a little less stable...") + else + M.add_chemical_effect(CE_MIND, 1) + if(world.time > data + ANTIDEPRESSANT_MESSAGE_DELAY) + data = world.time + to_chat(M, "Your mind feels stable... a little stable.") + +/datum/reagent/paroxetine + name = "Paroxetine" + description = "Stabilizes the mind greatly, but has a chance of adverse effects." + reagent_state = REAGENT_LIQUID + color = "#ff80bf" + metabolism = 0.01 + data = 0 + +/datum/reagent/paroxetine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + if(volume <= 0.1 && M.chem_doses[type] >= 0.5 && world.time > data + ANTIDEPRESSANT_MESSAGE_DELAY) + data = world.time + to_chat(M, "Your mind feels much less stable...") + else + M.add_chemical_effect(CE_MIND, 2) + if(world.time > data + ANTIDEPRESSANT_MESSAGE_DELAY) + data = world.time + if(prob(90)) + to_chat(M, "Your mind feels much more stable.") + else + to_chat(M, "Your mind breaks apart...") + M.hallucination(200, 100) + +/datum/reagent/nicotine + name = "Nicotine" + description = "A sickly yellow liquid sourced from tobacco leaves. Stimulates and relaxes the mind and body." + taste_description = "peppery bitterness" + reagent_state = REAGENT_LIQUID + color = "#efebaa" + metabolism = REM * 0.002 + overdose = 6 + scannable = 1 + data = 0 + +/datum/reagent/nicotine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + if(prob(volume*20)) + M.add_chemical_effect(CE_PULSE, 1) + if(volume <= 0.02 && M.chem_doses[type] >= 0.05 && world.time > data + ANTIDEPRESSANT_MESSAGE_DELAY * 0.3) + data = world.time + to_chat(M, "You feel antsy, your concentration wavers...") + M.add_event("relaxed", /datum/happiness_event/antsy)//It's relaxed so that it overrides the relaxed event. + else + if(world.time > data + ANTIDEPRESSANT_MESSAGE_DELAY * 0.3) + data = world.time + to_chat(M, "You feel invigorated and calm.") + M.add_event("relaxed", /datum/happiness_event/relaxed) + +/datum/reagent/nicotine/overdose(var/mob/living/carbon/M, var/alien) + ..() + M.add_chemical_effect(CE_PULSE, 2) + +/datum/reagent/tobacco + name = "Tobacco" + description = "Cut and processed tobacco leaves." + taste_description = "tobacco" + reagent_state = REAGENT_SOLID + color = "#684b3c" + scannable = 1 + var/nicotine = REM * 0.2 + +/datum/reagent/tobacco/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + ..() + M.reagents.add_reagent(/datum/reagent/nicotine, nicotine) + +/datum/reagent/tobacco/fine + name = "Fine Tobacco" + taste_description = "fine tobacco" + +/datum/reagent/tobacco/bad + name = "Terrible Tobacco" + taste_description = "acrid smoke" + +/datum/reagent/tobacco/liquid + name = "Nicotine Solution" + description = "A diluted nicotine solution." + reagent_state = REAGENT_LIQUID + taste_mult = 0 + color = "#fcfcfc" + nicotine = REM * 0.1 + +/datum/reagent/menthol + name = "Menthol" + description = "Tastes naturally minty, and imparts a very mild numbing sensation." + taste_description = "mint" + reagent_state = REAGENT_LIQUID + color = "#80af9c" + metabolism = REM * 0.002 + overdose = REAGENTS_OVERDOSE * 0.25 + scannable = 1 + data = 0 + +/datum/reagent/menthol/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + if(world.time > data + ANTIDEPRESSANT_MESSAGE_DELAY * 0.35) + data = world.time + to_chat(M, "You feel faintly sore in the throat.") + +/datum/reagent/rezadone + name = "Rezadone" + description = "A powder with almost magical properties, this substance can effectively treat genetic damage in humanoids, though excessive consumption has side effects." + taste_description = "sickness" + reagent_state = REAGENT_SOLID + color = "#669900" + overdose = REAGENTS_OVERDOSE + scannable = 1 + flags = IGNORE_MOB_SIZE + +/datum/reagent/rezadone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.adjustCloneLoss(-20 * removed) + M.adjustOxyLoss(-2 * removed) + M.heal_organ_damage(20 * removed, 20 * removed) + M.adjustToxLoss(-20 * removed) + if(M.chem_doses[type] > 3 && ishuman(M)) + var/mob/living/carbon/human/H = M + for(var/obj/item/organ/external/E in H.organs) + E.disfigured = 1 //currently only matters for the head, but might as well disfigure them all. + if(M.chem_doses[type] > 10) + M.make_dizzy(5) + M.make_jittery(5) + +/datum/reagent/noexcutite + name = "Noexcutite" + description = "A thick, syrupy liquid that has a lethargic effect. Used to cure cases of jitteriness." + taste_description = "numbing coldness" + reagent_state = REAGENT_LIQUID + color = "#bc018a" + overdose = REAGENTS_OVERDOSE + scannable = 1 + flags = IGNORE_MOB_SIZE + +/datum/reagent/noexcutite/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + + if(alien != IS_DIONA) + M.make_jittery(-50) + +/datum/reagent/antidexafen + name = "Antidexafen" + description = "All-in-one cold medicine. Fever, cough, sneeze, safe for babies." + taste_description = "cough syrup" + reagent_state = REAGENT_LIQUID + color = "#c8a5dc" + overdose = 60 + scannable = 1 + metabolism = REM * 0.05 + flags = IGNORE_MOB_SIZE + +/datum/reagent/antidexafen/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + + M.add_chemical_effect(CE_PAINKILLER, 15) + M.add_chemical_effect(CE_ANTIVIRAL, 1) + +/datum/reagent/antidexafen/overdose(var/mob/living/carbon/M, var/alien) + ..() + M.hallucination(60, 20) + M.druggy = max(M.druggy, 2) + +/datum/reagent/adrenaline + name = "Adrenaline" + description = "Adrenaline is a hormone used as a drug to treat cardiac arrest and other cardiac dysrhythmias resulting in diminished or absent cardiac output." + taste_description = "rush" + reagent_state = REAGENT_LIQUID + color = "#c8a5dc" + scannable = 1 + overdose = 20 + metabolism = 0.1 + +/datum/reagent/adrenaline/affect_blood(var/mob/living/carbon/human/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + + if(M.chem_doses[type] < 0.2) //not that effective after initial rush + M.add_chemical_effect(CE_PAINKILLER, min(30*volume, 80)) + M.add_chemical_effect(CE_PULSE, 1) + else if(M.chem_doses[type] < 1) + M.add_chemical_effect(CE_PAINKILLER, min(10*volume, 20)) + M.add_chemical_effect(CE_PULSE, 2) + if(M.chem_doses[type] > 10) + M.make_jittery(5) + if(volume >= 5 && M.is_asystole()) + remove_self(5) + M.resuscitate() + +/datum/reagent/nanoblood + name = "Nanoblood" + description = "A stable hemoglobin-based nanoparticle oxygen carrier, used to rapidly replace lost blood. Toxic unless injected in small doses. Does not contain white blood cells." + taste_description = "blood with bubbles" + reagent_state = REAGENT_LIQUID + color = "#c10158" + scannable = 1 + overdose = 5 + metabolism = 1 + +/datum/reagent/nanoblood/affect_blood(var/mob/living/carbon/human/M, var/alien, var/removed) + if(!M.should_have_organ(BP_HEART)) //We want the var for safety but we can do without the actual blood. + return + if(M.regenerate_blood(4 * removed)) + M.immunity = max(M.immunity - 0.1, 0) + if(M.chem_doses[type] > M.species.blood_volume/8) //half of blood was replaced with us, rip white bodies + M.immunity = max(M.immunity - 0.5, 0) diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm new file mode 100644 index 00000000..c0e57725 --- /dev/null +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm @@ -0,0 +1,367 @@ +/* Paint and crayons */ + +/datum/reagent/crayon_dust + name = "Crayon dust" + description = "Intensely coloured powder obtained by grinding crayons." + taste_description = "the back of class" + reagent_state = REAGENT_LIQUID + color = "#888888" + overdose = 5 + +/datum/reagent/crayon_dust/red + name = "Red crayon dust" + color = "#fe191a" + +/datum/reagent/crayon_dust/orange + name = "Orange crayon dust" + color = "#ffbe4f" + +/datum/reagent/crayon_dust/yellow + name = "Yellow crayon dust" + color = "#fdfe7d" + +/datum/reagent/crayon_dust/green + name = "Green crayon dust" + color = "#18a31a" + +/datum/reagent/crayon_dust/blue + name = "Blue crayon dust" + color = "#247cff" + +/datum/reagent/crayon_dust/purple + name = "Purple crayon dust" + color = "#cc0099" + +/datum/reagent/crayon_dust/grey //Mime + name = "Grey crayon dust" + color = "#808080" + +/datum/reagent/crayon_dust/brown //Rainbow + name = "Brown crayon dust" + color = "#846f35" + +/datum/reagent/paint + name = "Paint" + description = "This paint will stick to almost any object." + taste_description = "chalk" + reagent_state = REAGENT_LIQUID + color = "#808080" + overdose = REAGENTS_OVERDOSE * 0.5 + color_weight = 20 + +/datum/reagent/paint/touch_turf(var/turf/T) + if(istype(T) && !istype(T, /turf/space)) + T.color = color + +/datum/reagent/paint/touch_obj(var/obj/O) + if(istype(O)) + O.color = color + +/datum/reagent/paint/touch_mob(var/mob/M) + if(istype(M) && !isobserver(M)) //painting observers: not allowed + M.color = color //maybe someday change this to paint only clothes and exposed body parts for human mobs. + +/datum/reagent/paint/get_data() + return color + +/datum/reagent/paint/initialize_data(var/newdata) + color = newdata + return + +/datum/reagent/paint/mix_data(var/newdata, var/newamount) + var/list/colors = list(0, 0, 0, 0) + var/tot_w = 0 + + var/hex1 = uppertext(color) + var/hex2 = uppertext(newdata) + if(length(hex1) == 7) + hex1 += "FF" + if(length(hex2) == 7) + hex2 += "FF" + if(length(hex1) != 9 || length(hex2) != 9) + return + colors[1] += hex2num(copytext(hex1, 2, 4)) * volume + colors[2] += hex2num(copytext(hex1, 4, 6)) * volume + colors[3] += hex2num(copytext(hex1, 6, 8)) * volume + colors[4] += hex2num(copytext(hex1, 8, 10)) * volume + tot_w += volume + colors[1] += hex2num(copytext(hex2, 2, 4)) * newamount + colors[2] += hex2num(copytext(hex2, 4, 6)) * newamount + colors[3] += hex2num(copytext(hex2, 6, 8)) * newamount + colors[4] += hex2num(copytext(hex2, 8, 10)) * newamount + tot_w += newamount + + color = rgb(colors[1] / tot_w, colors[2] / tot_w, colors[3] / tot_w, colors[4] / tot_w) + return + +/* Things that didn't fit anywhere else */ + +/datum/reagent/adminordrazine //An OP chemical for admins + name = "Adminordrazine" + description = "It's magic. We don't have to explain it." + taste_description = "100% abuse" + reagent_state = REAGENT_LIQUID + color = "#c8a5dc" + flags = AFFECTS_DEAD //This can even heal dead people. + + glass_name = "liquid gold" + glass_desc = "It's magic. We don't have to explain it." + +/datum/reagent/adminordrazine/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) + affect_blood(M, alien, removed) + +/datum/reagent/adminordrazine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.setCloneLoss(0) + M.setOxyLoss(0) + M.radiation = 0 + M.heal_organ_damage(5,5) + M.adjustToxLoss(-5) + M.hallucination_power = 0 + M.setBrainLoss(0) + M.disabilities = 0 + M.sdisabilities = 0 + M.eye_blurry = 0 + M.eye_blind = 0 + M.SetWeakened(0) + M.SetStunned(0) + M.SetParalysis(0) + M.silent = 0 + M.dizziness = 0 + M.drowsyness = 0 + M.stuttering = 0 + M.confused = 0 + M.sleeping = 0 + M.jitteriness = 0 + +/datum/reagent/gold + name = "Gold" + description = "Gold is a dense, soft, shiny metal and the most malleable and ductile metal known." + taste_description = "expensive metal" + reagent_state = REAGENT_SOLID + color = "#f7c430" + +/datum/reagent/silver + name = "Silver" + description = "A soft, white, lustrous transition metal, it has the highest electrical conductivity of any element and the highest thermal conductivity of any metal." + taste_description = "expensive yet reasonable metal" + reagent_state = REAGENT_SOLID + color = "#d0d0d0" + +/datum/reagent/uranium + name ="Uranium" + description = "A silvery-white metallic chemical element in the actinide series, weakly radioactive." + taste_description = "the inside of a reactor" + reagent_state = REAGENT_SOLID + color = "#b8b8c0" + +/datum/reagent/uranium/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) + affect_ingest(M, alien, removed) + +/datum/reagent/uranium/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.apply_effect(5 * removed, IRRADIATE, blocked = 0) + +/datum/reagent/uranium/touch_turf(var/turf/T) + if(volume >= 3) + if(!istype(T, /turf/space)) + var/obj/effect/decal/cleanable/greenglow/glow = locate(/obj/effect/decal/cleanable/greenglow, T) + if(!glow) + new /obj/effect/decal/cleanable/greenglow(T) + return + +/datum/reagent/water/holywater + name = "Holy Water" + description = "An ashen-obsidian-water mix, this solution will alter certain sections of the brain's rationality." + color = "#e0e8ef" + + glass_name = "holy water" + glass_desc = "An ashen-obsidian-water mix, this solution will alter certain sections of the brain's rationality." + +/datum/reagent/water/holywater/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(ishuman(M)) // Any location + if(iscultist(M)) + if(prob(10)) + cult.offer_uncult(M) + if(prob(2)) + var/obj/effect/spider/spiderling/S = new /obj/effect/spider/spiderling(M.loc) + M.visible_message("\The [M] coughs up \the [S]!") + +/datum/reagent/water/holywater/touch_turf(var/turf/T) + if(volume >= 5) + T.holy = 1 + return + +/datum/reagent/diethylamine + name = "Diethylamine" + description = "A secondary amine, mildly corrosive." + taste_description = "iron" + reagent_state = REAGENT_LIQUID + color = "#604030" + +/datum/reagent/surfactant // Foam precursor + name = "Azosurfactant" + description = "A isocyanate liquid that forms a foam when mixed with water." + taste_description = "metal" + reagent_state = REAGENT_LIQUID + color = "#9e6b38" + +/datum/reagent/foaming_agent // Metal foaming agent. This is lithium hydride. Add other recipes (e.g. LiH + H2O -> LiOH + H2) eventually. + name = "Foaming agent" + description = "A agent that yields metallic foam when mixed with light metal and a strong acid." + taste_description = "metal" + reagent_state = REAGENT_SOLID + color = "#664b63" + +/datum/reagent/thermite + name = "Thermite" + description = "Thermite produces an aluminothermic reaction known as a thermite reaction. Can be used to melt walls." + taste_description = "sweet tasting metal" + reagent_state = REAGENT_SOLID + color = "#673910" + touch_met = 50 + +/datum/reagent/thermite/touch_turf(var/turf/T) + if(volume >= 5) + if(istype(T, /turf/simulated/wall)) + var/turf/simulated/wall/W = T + W.thermite = 1 + W.overlays += image('icons/effects/effects.dmi',icon_state = "#673910") + remove_self(5) + return + +/datum/reagent/thermite/touch_mob(var/mob/living/L, var/amount) + if(istype(L)) + L.adjust_fire_stacks(amount / 5) + +/datum/reagent/thermite/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.adjustFireLoss(3 * removed) + +/datum/reagent/space_cleaner + name = "Trench cleaner" + description = "A compound used to clean trenches. Now with 50% more sodium hypochlorite!" + taste_description = "sourness" + reagent_state = REAGENT_LIQUID + color = "#a5f0ee" + touch_met = 50 + +/datum/reagent/space_cleaner/touch_obj(var/obj/O) + O.clean_blood() + +/datum/reagent/space_cleaner/touch_turf(var/turf/T) + if(volume >= 1) + if(istype(T, /turf/simulated)) + var/turf/simulated/S = T + S.dirt = 0 + if(S.wet > 1) + S.unwet_floor(FALSE) + T.clean_blood() + + + for(var/mob/living/carbon/slime/M in T) + M.adjustToxLoss(rand(5, 10)) + +/datum/reagent/space_cleaner/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) + if(M.r_hand) + M.r_hand.clean_blood() + if(M.l_hand) + M.l_hand.clean_blood() + if(M.wear_mask) + if(M.wear_mask.clean_blood()) + M.update_inv_wear_mask(0) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.head) + if(H.head.clean_blood()) + H.update_inv_head(0) + if(H.wear_suit) + if(H.wear_suit.clean_blood()) + H.update_inv_wear_suit(0) + else if(H.w_uniform) + if(H.w_uniform.clean_blood()) + H.update_inv_w_uniform(0) + if(H.shoes) + if(H.shoes.clean_blood()) + H.update_inv_shoes(0) + else + H.clean_blood(1) + return + M.clean_blood() + +/datum/reagent/lube // TODO: spraying on borgs speeds them up + name = "Trench Lube" + description = "Lubricant is a substance introduced between two moving surfaces to reduce the friction and wear between them. DO NOT ERP IN THE TRENCHES!" + taste_description = "slime" + reagent_state = REAGENT_LIQUID + color = "#009ca8" + +/datum/reagent/lube/touch_turf(var/turf/simulated/T) + if(!istype(T)) + return + if(volume >= 1) + T.wet_floor(80) + +/datum/reagent/silicate + name = "Silicate" + description = "A compound that can be used to reinforce glass." + taste_description = "plastic" + reagent_state = REAGENT_LIQUID + color = "#c7ffff" + +/datum/reagent/silicate/touch_obj(var/obj/O) + if(istype(O, /obj/structure/window)) + var/obj/structure/window/W = O + W.apply_silicate(volume) + remove_self(volume) + return + +/datum/reagent/glycerol + name = "Glycerol" + description = "Glycerol is a simple polyol compound. Glycerol is sweet-tasting and of low toxicity." + taste_description = "sweetness" + reagent_state = REAGENT_LIQUID + color = "#808080" + +/datum/reagent/nitroglycerin + name = "Nitroglycerin" + description = "Nitroglycerin is a heavy, colorless, oily, explosive liquid obtained by nitrating glycerol." + taste_description = "oil" + reagent_state = REAGENT_LIQUID + color = "#808080" + +/datum/reagent/nitroglycerin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + ..() + M.add_chemical_effect(CE_PULSE, 2) + +/datum/reagent/coolant + name = "Coolant" + description = "Industrial cooling substance." + taste_description = "sourness" + taste_mult = 1.1 + reagent_state = REAGENT_LIQUID + color = "#c8a5dc" + +/datum/reagent/ultraglue + name = "Ultra Glue" + description = "An extremely powerful bonding agent." + taste_description = "a special education class" + color = "#ffffcc" + +/datum/reagent/woodpulp + name = "Wood Pulp" + description = "A mass of wood fibers." + taste_description = "wood" + reagent_state = REAGENT_LIQUID + color = "#b97a57" + +/datum/reagent/luminol + name = "Luminol" + description = "A compound that interacts with blood on the molecular level." + taste_description = "metal" + reagent_state = REAGENT_LIQUID + color = "#f2f3f4" + +/datum/reagent/luminol/touch_obj(var/obj/O) + O.reveal_blood() + +/datum/reagent/luminol/touch_mob(var/mob/living/L) + L.reveal_blood() diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm new file mode 100644 index 00000000..9d37b875 --- /dev/null +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm @@ -0,0 +1,684 @@ +/* Toxins, poisons, venoms */ + +/datum/reagent/toxin + name = "toxin" + description = "A toxic chemical." + taste_description = "bitterness" + taste_mult = 1.2 + reagent_state = REAGENT_LIQUID + color = "#cf3600" + metabolism = REM * 0.25 // 0.05 by default. They last a while and slowly kill you. + + var/target_organ + var/strength = 4 // How much damage it deals per unit + +/datum/reagent/toxin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(strength && alien != IS_DIONA) + M.add_chemical_effect(CE_TOXIN, strength) + var/dam = (strength * removed) + if(target_organ && ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/internal/I = H.internal_organs_by_name[target_organ] + if(I) + var/can_damage = I.max_damage - I.damage + if(can_damage > 0) + if(dam > can_damage) + I.take_damage(can_damage, silent=TRUE) + dam -= can_damage + else + I.take_damage(dam, silent=TRUE) + dam = 0 + if(dam) + M.adjustToxLoss(target_organ ? (dam * 0.75) : dam) + +/datum/reagent/toxin/plasticide + name = "Plasticide" + description = "Liquid plastic, do not eat." + taste_description = "plastic" + reagent_state = REAGENT_LIQUID + color = "#cf3600" + strength = 5 + +/datum/reagent/toxin/amatoxin + name = "Amatoxin" + description = "A powerful poison derived from certain species of mushroom." + taste_description = "mushroom" + reagent_state = REAGENT_LIQUID + color = "#792300" + strength = 10 + +/datum/reagent/toxin/blattedin + name = "Blattedin" + description = "A powerful toxin produced by those omnipresent roaches." + taste_description = "chicken" + reagent_state = REAGENT_LIQUID + color = "#0f4800" + strength = 5 + +/datum/reagent/toxin/blattedin/touch_mob(var/mob/living/L, var/amount) + if(istype(L, /mob/living/simple_animal/hostile/retaliate/roach)) + if(L.health <= 0) + if(prob(70))//Roaches sometimes can come back to life from healing vapors + return + L.heal_organ_damage(amount * 0.5) + else + ..() + +/datum/reagent/toxin/carpotoxin + name = "Carpotoxin" + description = "A deadly neurotoxin produced by the dreaded space carp." + taste_description = "fish" + reagent_state = REAGENT_LIQUID + color = "#003333" + target_organ = BP_BRAIN + strength = 10 + +/datum/reagent/toxin/phoron + name = "Phoron" + description = "Phoron in its liquid form." + taste_mult = 1.5 + reagent_state = REAGENT_LIQUID + color = "#ff3300" + strength = 30 + touch_met = 5 + var/fire_mult = 5 + +/datum/reagent/toxin/chlorine + name = "Chlorine" + description = "A highly poisonous liquid. Smells strongly of bleach." + reagent_state = REAGENT_LIQUID + taste_description = "bleach" + color = "#707C13" + strength = 15 + metabolism = REM + +/datum/reagent/toxin/phoron/touch_mob(var/mob/living/L, var/amount) + if(istype(L)) + L.adjust_fire_stacks(amount / fire_mult) + +/datum/reagent/toxin/phoron/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_NABBER) + return + ..() + +/datum/reagent/toxin/phoron/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) + M.take_organ_damage(0, removed * 0.1) //being splashed directly with phoron causes minor chemical burns + if(prob(10 * fire_mult)) + M.pl_effects() + +/datum/reagent/toxin/phoron/touch_turf(var/turf/simulated/T) + if(!istype(T)) + return + T.assume_gas("phoron", volume, T20C) + remove_self(volume) + +// Produced during deuterium synthesis. Super poisonous, SUPER flammable (doesn't need oxygen to burn). +/datum/reagent/toxin/phoron/oxygen + name = "Oxyphoron" + description = "An exceptionally flammable molecule formed from deuterium synthesis." + strength = 15 + fire_mult = 15 + +/datum/reagent/toxin/phoron/oxygen/touch_turf(var/turf/simulated/T) + if(!istype(T)) + return + T.assume_gas("oxygen", ceil(volume/2), T20C) + T.assume_gas("phoron", ceil(volume/2), T20C) + remove_self(volume) + +/datum/reagent/toxin/cyanide //Fast and Lethal + name = "Cyanide" + description = "A highly toxic chemical." + taste_mult = 0.6 + reagent_state = REAGENT_LIQUID + color = "#cf3600" + strength = 20 + metabolism = REM * 2 + target_organ = BP_HEART + +/datum/reagent/toxin/cyanide/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + ..() + M.sleeping += 1 + +/datum/reagent/toxin/potassium_chloride + name = "Potassium Chloride" + description = "A delicious salt that stops the heart when injected into cardiac muscle." + taste_description = "salt" + reagent_state = REAGENT_SOLID + color = "#ffffff" + strength = 0 + overdose = REAGENTS_OVERDOSE + +/datum/reagent/toxin/potassium_chloride/overdose(var/mob/living/carbon/M, var/alien) + ..() + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.stat != 1) + if(H.losebreath >= 10) + H.losebreath = max(10, H.losebreath - 10) + H.adjustOxyLoss(2) + H.Weaken(10) + M.add_chemical_effect(CE_NOPULSE, 1) + + +/datum/reagent/toxin/potassium_chlorophoride + name = "Potassium Chlorophoride" + description = "A specific chemical based on Potassium Chloride to stop the heart for surgery. Not safe to eat!" + taste_description = "salt" + reagent_state = REAGENT_SOLID + color = "#ffffff" + strength = 10 + overdose = 20 + +/datum/reagent/toxin/potassium_chlorophoride/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.stat != 1) + if(H.losebreath >= 10) + H.losebreath = max(10, M.losebreath-10) + H.adjustOxyLoss(2) + H.Weaken(10) + M.add_chemical_effect(CE_NOPULSE, 1) + +/datum/reagent/toxin/zombiepowder + name = "Zombie Powder" + description = "A strong neurotoxin that puts the subject into a death-like state." + taste_description = "death" + reagent_state = REAGENT_SOLID + color = "#669900" + metabolism = REM + strength = 3 + target_organ = BP_BRAIN + +/datum/reagent/toxin/zombiepowder/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(alien == IS_DIONA) + return + M.status_flags |= FAKEDEATH + M.adjustOxyLoss(3 * removed) + M.Weaken(10) + M.silent = max(M.silent, 10) + if(M.chem_doses[type] <= removed) //half-assed attempt to make timeofdeath update only at the onset + M.timeofdeath = world.time + M.add_chemical_effect(CE_NOPULSE, 1) + +/datum/reagent/toxin/zombiepowder/Destroy() + if(holder && holder.my_atom && ismob(holder.my_atom)) + var/mob/M = holder.my_atom + M.status_flags &= ~FAKEDEATH + . = ..() + +/datum/reagent/toxin/fertilizer //Reagents used for plant fertilizers. + name = /datum/reagent/toxin/fertilizer + description = "A chemical mix good for growing plants with." + taste_description = "plant food" + taste_mult = 0.5 + reagent_state = REAGENT_LIQUID + strength = 0.5 // It's not THAT poisonous. + color = "#664330" + +/datum/reagent/toxin/fertilizer/eznutrient + name = "EZ Nutrient" + +/datum/reagent/toxin/fertilizer/left4zed + name = "Left-4-Zed" + +/datum/reagent/toxin/fertilizer/robustharvest + name = "Robust Harvest" + +/datum/reagent/toxin/plantbgone + name = "Plant-B-Gone" + description = "A harmful toxic mixture to kill plantlife. Do not ingest!" + taste_mult = 1 + reagent_state = REAGENT_LIQUID + color = "#49002e" + strength = 4 + +/datum/reagent/toxin/plantbgone/touch_turf(var/turf/T) + if(istype(T, /turf/simulated/wall)) + var/turf/simulated/wall/W = T + if(locate(/obj/effect/overlay/wallrot) in W) + for(var/obj/effect/overlay/wallrot/E in W) + qdel(E) + 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/vine)) + qdel(O) + +/datum/reagent/toxin/plantbgone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(alien == IS_DIONA) + M.adjustToxLoss(50 * removed) + +/datum/reagent/toxin/plantbgone/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(alien == IS_DIONA) + M.adjustToxLoss(50 * removed) + +/datum/reagent/acid/polyacid + name = "Polytrinic acid" + description = "Polytrinic acid is a an extremely corrosive chemical substance." + taste_description = "acid" + reagent_state = REAGENT_LIQUID + color = "#8e18a9" + power = 10 + meltdose = 4 + +/datum/reagent/lexorin + name = "Lexorin" + description = "Lexorin temporarily stops respiration. Causes tissue damage." + taste_description = "acid" + reagent_state = REAGENT_LIQUID + color = "#c8a5dc" + overdose = REAGENTS_OVERDOSE + +/datum/reagent/lexorin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + if(alien == IS_SKRELL) + M.take_organ_damage(2.4 * removed, 0) + if(M.losebreath < 22.5) + M.losebreath++ + else + M.take_organ_damage(3 * removed, 0) + if(M.losebreath < 15) + M.losebreath++ + +/datum/reagent/mutagen + name = "Unstable mutagen" + description = "Might cause unpredictable mutations. Keep away from children." + taste_description = "slime" + taste_mult = 0.9 + reagent_state = REAGENT_LIQUID + color = "#13bc5e" + +/datum/reagent/mutagen/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) + if(prob(33)) + affect_blood(M, alien, removed) + +/datum/reagent/mutagen/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + if(prob(67)) + affect_blood(M, alien, removed) + +/datum/reagent/mutagen/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + + if(M.isSynthetic()) + return + + var/mob/living/carbon/human/H = M + if(istype(H) && (H.species.species_flags & SPECIES_FLAG_NO_SCAN)) + return + + if(M.dna) + if(prob(removed * 0.1)) // Approx. one mutation per 10 injected/20 ingested/30 touching units + randmuti(M) + if(prob(98)) + randmutb(M) + else + randmutg(M) + domutcheck(M, null) + M.UpdateAppearance() + M.apply_effect(10 * removed, IRRADIATE, blocked = 0) + +/datum/reagent/slimejelly + name = "Slime Jelly" + description = "A gooey semi-liquid produced from one of the deadliest lifeforms in existence. SO REAL." + taste_description = "slime" + taste_mult = 1.3 + reagent_state = REAGENT_LIQUID + color = "#801e28" + +/datum/reagent/slimejelly/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + if(prob(10)) + to_chat(M, "Your insides are burning!") + M.adjustToxLoss(rand(100, 300) * removed) + else if(prob(40)) + M.heal_organ_damage(25 * removed, 0) + +/datum/reagent/soporific + name = "Soporific" + description = "An effective hypnotic used to treat insomnia." + taste_description = "bitterness" + reagent_state = REAGENT_LIQUID + color = "#009ca8" + metabolism = REM * 0.5 + overdose = REAGENTS_OVERDOSE + +/datum/reagent/soporific/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + + var/threshold = 1 + if(alien == IS_SKRELL) + threshold = 1.2 + + if(M.chem_doses[type] < 1 * threshold) + if(M.chem_doses[type] == metabolism * 2 || prob(5)) + M.emote("yawn") + else if(M.chem_doses[type] < 1.5 * threshold) + M.eye_blurry = max(M.eye_blurry, 10) + else if(M.chem_doses[type] < 5 * threshold) + if(prob(50)) + M.Weaken(2) + M.drowsyness = max(M.drowsyness, 20) + else + M.sleeping = max(M.sleeping, 20) + M.drowsyness = max(M.drowsyness, 60) + M.add_chemical_effect(CE_PULSE, -1) + +/datum/reagent/chloralhydrate + name = "Chloral Hydrate" + description = "A powerful sedative." + taste_description = "bitterness" + reagent_state = REAGENT_SOLID + color = "#000067" + metabolism = REM * 0.5 + overdose = REAGENTS_OVERDOSE * 0.5 + +/datum/reagent/chloralhydrate/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + + var/threshold = 1 + if(alien == IS_SKRELL) + threshold = 1.2 + + if(M.chem_doses[type] == metabolism * threshold) + M.confused += 2 + M.drowsyness += 2 + else if(M.chem_doses[type] < 2 * threshold) + M.Weaken(30) + M.eye_blurry = max(M.eye_blurry, 10) + else + M.sleeping = max(M.sleeping, 30) + + if(M.chem_doses[type] > 1 * threshold) + M.adjustToxLoss(removed) + +/datum/reagent/chloralhydrate/beer2 //disguised as normal beer for use by emagged brobots + name = "Beer" + description = "An alcoholic beverage made from malted grains, hops, yeast, and water. The fermentation appears to be incomplete." //If the players manage to analyze this, they deserve to know something is wrong. + taste_description = "shitty piss water" + reagent_state = REAGENT_LIQUID + color = "#ffd300" + + glass_name = "beer" + glass_desc = "A freezing pint of beer" +/* Drugs */ + +/datum/reagent/space_drugs + name = "Trench drugs" + description = "An illegal chemical compound used as drug." + taste_description = "bitterness" + taste_mult = 0.4 + reagent_state = REAGENT_LIQUID + color = "#60a584" + metabolism = REM * 0.5 + overdose = REAGENTS_OVERDOSE + +/datum/reagent/space_drugs/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + + var/drug_strength = 15 + if(alien == IS_SKRELL) + drug_strength = drug_strength * 0.8 + + M.druggy = max(M.druggy, drug_strength) + if(prob(10) && isturf(M.loc) && !istype(M.loc, /turf/space) && M.canmove && !M.restrained()) + step(M, pick(GLOB.cardinal)) + if(prob(7)) + M.emote(pick("twitch", "drool", "moan", "giggle")) + M.add_chemical_effect(CE_PULSE, -1) + M.add_event("high", /datum/happiness_event/high) + //SUGAR CRACK PIE, GET ME HIGH + +/datum/reagent/serotrotium + name = "Serotrotium" + description = "A chemical compound that promotes concentrated production of the serotonin neurotransmitter in humans." + taste_description = "bitterness" + reagent_state = REAGENT_LIQUID + color = "#202040" + metabolism = REM * 0.25 + overdose = REAGENTS_OVERDOSE + +/datum/reagent/serotrotium/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + if(prob(7)) + M.emote(pick("twitch", "drool", "moan", "gasp")) + return + +/datum/reagent/cryptobiolin + name = "Cryptobiolin" + description = "Cryptobiolin causes confusion and dizzyness." + taste_description = "sourness" + reagent_state = REAGENT_LIQUID + color = "#000055" + metabolism = REM * 0.5 + overdose = REAGENTS_OVERDOSE + +/datum/reagent/cryptobiolin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + var/drug_strength = 4 + if(alien == IS_SKRELL) + drug_strength = drug_strength * 0.8 + M.make_dizzy(drug_strength) + M.confused = max(M.confused, drug_strength * 5) + +/datum/reagent/impedrezene + name = "Impedrezene" + description = "Impedrezene is a narcotic that impedes one's ability by slowing down the higher brain cell functions." + taste_description = "numbness" + reagent_state = REAGENT_LIQUID + color = "#c8a5dc" + overdose = REAGENTS_OVERDOSE + +/datum/reagent/impedrezene/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + M.jitteriness = max(M.jitteriness - 5, 0) + if(prob(80)) + M.adjustBrainLoss(0.1 * removed) + if(prob(50)) + M.drowsyness = max(M.drowsyness, 3) + if(prob(10)) + M.emote("drool") + M.add_event("high", /datum/happiness_event/high) + +/datum/reagent/mindbreaker + name = "Mindbreaker Toxin" + description = "A powerful hallucinogen, it can cause fatal effects in users." + taste_description = "sourness" + reagent_state = REAGENT_LIQUID + color = "#b31008" + metabolism = REM * 0.25 + overdose = REAGENTS_OVERDOSE + +/datum/reagent/mindbreaker/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + M.add_chemical_effect(CE_MIND, -2) + if(alien == IS_SKRELL) + M.hallucination(25, 30) + else + M.hallucination(50, 50) + +/datum/reagent/psilocybin + name = "Psilocybin" + description = "A strong psycotropic derived from certain species of mushroom." + taste_description = "mushroom" + color = "#e700e7" + overdose = REAGENTS_OVERDOSE + metabolism = REM * 0.5 + +/datum/reagent/psilocybin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + + var/threshold = 1 + if(alien == IS_SKRELL) + threshold = 1.2 + + M.druggy = max(M.druggy, 30) + + if(M.chem_doses[type] < 1 * threshold) + M.apply_effect(3, STUTTER) + M.make_dizzy(5) + if(prob(5)) + M.emote(pick("twitch", "giggle")) + else if(M.chem_doses[type] < 2 * threshold) + M.apply_effect(3, STUTTER) + M.make_jittery(5) + M.make_dizzy(5) + M.druggy = max(M.druggy, 35) + if(prob(10)) + M.emote(pick("twitch", "giggle")) + else + M.add_chemical_effect(CE_MIND, -1) + M.apply_effect(3, STUTTER) + M.make_jittery(10) + M.make_dizzy(10) + M.druggy = max(M.druggy, 40) + if(prob(15)) + M.emote(pick("twitch", "giggle")) + M.add_event("high", /datum/happiness_event/high) + +/* Transformations */ + +/datum/reagent/slimetoxin + name = "Mutation Toxin" + description = "A corruptive toxin produced by slimes." + taste_description = "sludge" + reagent_state = REAGENT_LIQUID + color = "#13bc5e" + metabolism = REM * 0.2 + +/datum/reagent/slimetoxin/affect_blood(var/mob/living/carbon/human/H, var/alien, var/removed) + if(!istype(H)) + return + if(H.species.name == SPECIES_PROMETHEAN) + return + H.adjustToxLoss(40 * removed) + if(H.chem_doses[type] < 1 || prob(30)) + return + H.chem_doses[type] = 0 + var/list/meatchunks = list() + for(var/limb_tag in list(BP_R_ARM, BP_L_ARM, BP_R_LEG,BP_L_LEG)) + var/obj/item/organ/external/E = H.get_organ(limb_tag) + if(!E.is_stump() && E.robotic < ORGAN_ROBOT && E.species.name != SPECIES_PROMETHEAN) + meatchunks += E + if(!meatchunks.len) + return + var/obj/item/organ/external/O = pick(meatchunks) + to_chat(H, "Your [O.name]'s flesh mutates rapidly!") + meatchunks = list(O) | O.children + for(var/obj/item/organ/external/E in meatchunks) + E.species = all_species[SPECIES_PROMETHEAN] + E.s_tone = null + E.s_col = ReadRGB("#05ff9b") + E.s_col_blend = ICON_ADD + E.status &= ~ORGAN_BROKEN + E.status |= ORGAN_MUTATED + E.cannot_break = 1 + E.dislocated = -1 + E.nonsolid = 1 + E.max_damage = 5 + E.update_icon(1) + O.max_damage = 15 + if(prob(10)) + to_chat(H, "Your slimy [O.name]'s plops off!") + O.droplimb() + H.update_body() + +/datum/reagent/aslimetoxin + name = "Advanced Mutation Toxin" + description = "An advanced corruptive toxin produced by slimes." + taste_description = "sludge" + reagent_state = REAGENT_LIQUID + color = "#13bc5e" + +/datum/reagent/aslimetoxin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) // TODO: check if there's similar code anywhere else + if(M.transforming) + return + to_chat(M, "Your flesh rapidly mutates!") + M.transforming = 1 + M.canmove = 0 + M.icon = null + M.overlays.Cut() + M.set_invisibility(101) + for(var/obj/item/W in M) + if(istype(W, /obj/item/weapon/implant)) //TODO: Carn. give implants a dropped() or something + qdel(W) + continue + M.drop_from_inventory(W) + var/mob/living/carbon/slime/new_mob = new /mob/living/carbon/slime(M.loc) + new_mob.a_intent = "hurt" + new_mob.universal_speak = 1 + if(M.mind) + M.mind.transfer_to(new_mob) + else + new_mob.key = M.key + qdel(M) + +/datum/reagent/nanites + name = "Nanomachines" + description = "Microscopic construction robots." + taste_description = "slimey metal" + reagent_state = REAGENT_LIQUID + color = "#535e66" + +/datum/reagent/xenomicrobes + name = "Xenomicrobes" + description = "Microbes with an entirely alien cellular structure." + taste_description = "sludge" + reagent_state = REAGENT_LIQUID + color = "#535e66" + +/datum/reagent/toxin/hair_remover + name = "Hair Remover" + description = "An extremely effective chemical depilator. Do not ingest." + taste_description = "acid" + reagent_state = REAGENT_LIQUID + color = "#d9ffb3" + strength = 1 + overdose = REAGENTS_OVERDOSE + +/datum/reagent/toxin/hair_remover/affect_touch(var/mob/living/carbon/human/M, var/alien, var/removed) + if(alien == IS_SKRELL) //skrell can't have hair unless you hack it in, also to prevent tentacles from falling off + return + M.species.set_default_hair(M) + to_chat(M, "Your feel a chill, your skin feels lighter..") + remove_self(volume) + +/datum/reagent/toxin/corrupting + name = "Corruption" + description = "a loyalty changing liquid." + taste_description = "blood" + color = "#ffffff" + taste_mult = 5 + strength = 10 + metabolism = REM * 2 + overdose = 30 + +/datum/reagent/toxin/corrupting/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) + affect_blood(M,alien,removed*0.5) + +/datum/reagent/toxin/corrupting/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(prob(5)) + if(M.chem_doses[type] < 15) + to_chat(M, "You feel funny...") + else + to_chat(M, "You feel like you could die at any moment!") + +/datum/reagent/toxin/corrupting/overdose(var/mob/living/carbon/M, var/alien) + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + H.zombieze() + remove_self(volume) diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm new file mode 100644 index 00000000..5855a6dd --- /dev/null +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -0,0 +1,1955 @@ +//Chemical Reactions - Initialises all /datum/chemical_reaction into a list +// It is filtered into multiple lists within a list. +// For example: +// chemical_reaction_list[/datum/reagent/toxin/phoron] is a list of all reactions relating to phoron +// Note that entries in the list are NOT duplicated. So if a reaction pertains to +// more than one chemical it will still only appear in only one of the sublists. +// +// Chemical_produce_list acts as a reverse lookup table for chemical analysis +// For example: +// chemical_produce_list[/datum/chemical_reaction/inaprovaline] is a list of all possible recipes to produce inaprovaline. +// It is entirely possible to have multiple entries. +/proc/initialize_chemical_reactions() + var/paths = typesof(/datum/chemical_reaction) - /datum/chemical_reaction + chemical_reactions_list = list() + chemical_produce_list = list() + + for(var/path in paths) + var/datum/chemical_reaction/D = new path() + if(D.required_reagents && D.required_reagents.len) + var/reagent_id = D.required_reagents[1] + if(!chemical_reactions_list[reagent_id]) + chemical_reactions_list[reagent_id] = list() + chemical_reactions_list[reagent_id] += D + + if(D.result && D.result_amount > 0) + var/reagent_id = D.result + if(!chemical_produce_list[reagent_id]) + chemical_produce_list[reagent_id] = list() + chemical_produce_list[reagent_id] += D + +/datum/chemical_reaction + var/name = null + var/result = null + var/list/required_reagents = list() + var/list/catalysts = list() + var/list/inhibitors = list() + var/result_amount = 0 + + var/mix_message = "The solution begins to bubble." + var/reaction_sound = 'sound/effects/bubbles.ogg' + + var/log_is_important = 0 // If this reaction should be considered important for logging. Important recipes message admins when mixed, non-important ones just log to file. + +/datum/chemical_reaction/proc/can_happen(var/datum/reagents/holder) + //check that all the required reagents are present + if(!holder.has_all_reagents(required_reagents)) + return 0 + + //check that all the required catalysts are present in the required amount + if(!holder.has_all_reagents(catalysts)) + return 0 + + //check that none of the inhibitors are present in the required amount + if(holder.has_any_reagent(inhibitors)) + return 0 + + return 1 + +// This proc returns a list of all reagents it wants to use; if the holder has several reactions that use the same reagent, it will split the reagent evenly between them +/datum/chemical_reaction/proc/get_used_reagents() + . = list() + for(var/reagent in required_reagents) + . += reagent + +/datum/chemical_reaction/proc/process(var/datum/reagents/holder, var/limit) + var/data = send_data(holder) + + var/reaction_volume = holder.maximum_volume + for(var/reactant in required_reagents) + var/A = holder.get_reagent_amount(reactant) / required_reagents[reactant] / limit // How much of this reagent we are allowed to use + if(reaction_volume > A) + reaction_volume = A + + for(var/reactant in required_reagents) + holder.remove_reagent(reactant, reaction_volume * required_reagents[reactant], safety = 1) + + //add the product + var/amt_produced = result_amount * reaction_volume + if(result) + holder.add_reagent(result, amt_produced, data, safety = 1) + + on_reaction(holder, amt_produced) + +//called when a reaction processes +/datum/chemical_reaction/proc/on_reaction(var/datum/reagents/holder, var/created_volume) + return + +//called after processing reactions, if they occurred +/datum/chemical_reaction/proc/post_reaction(var/datum/reagents/holder) + var/atom/container = holder.my_atom + if(mix_message && container && !ismob(container)) + var/turf/T = get_turf(container) + var/list/seen = viewers(4, T) + for(var/mob/M in seen) + M.show_message("\icon[container] [mix_message]", 1) + playsound(T, reaction_sound, 80, 1) + +//obtains any special data that will be provided to the reaction products +//this is called just before reactants are removed. +/datum/chemical_reaction/proc/send_data(var/datum/reagents/holder, var/reaction_limit) + return null + +/* Common reactions */ + +/datum/chemical_reaction/inaprovaline + name = "Inaprovaline" + result = /datum/reagent/inaprovaline + required_reagents = list(/datum/reagent/acetone = 1, /datum/reagent/carbon = 1, /datum/reagent/sugar = 1) + result_amount = 3 + +/datum/chemical_reaction/dylovene + name = "Dylovene" + result = /datum/reagent/dylovene + required_reagents = list(/datum/reagent/silicon = 1, /datum/reagent/potassium = 1, /datum/reagent/ammonia = 1) + result_amount = 3 + +/datum/chemical_reaction/tramadol + name = "Tramadol" + result = /datum/reagent/tramadol + required_reagents = list(/datum/reagent/inaprovaline = 1, /datum/reagent/ethanol = 1, /datum/reagent/acetone = 1) + result_amount = 3 + +/datum/chemical_reaction/paracetamol + name = "Paracetamol" + result = /datum/reagent/paracetamol + required_reagents = list(/datum/reagent/tramadol = 1, /datum/reagent/sugar = 1, /datum/reagent/water = 1) + result_amount = 3 + +/datum/chemical_reaction/oxycodone + name = "Oxycodone" + result = /datum/reagent/tramadol/oxycodone + required_reagents = list(/datum/reagent/ethanol = 1, /datum/reagent/tramadol = 1) + catalysts = list(/datum/reagent/toxin/phoron = 5) + result_amount = 1 + +/datum/chemical_reaction/sterilizine + name = "Sterilizine" + result = /datum/reagent/sterilizine + required_reagents = list(/datum/reagent/ethanol = 1, /datum/reagent/dylovene = 1, /datum/reagent/acid/hydrochloric = 1) + result_amount = 3 + +/datum/chemical_reaction/silicate + name = "Silicate" + result = /datum/reagent/silicate + required_reagents = list(/datum/reagent/aluminum = 1, /datum/reagent/silicon = 1, /datum/reagent/acetone = 1) + result_amount = 3 + +/datum/chemical_reaction/mutagen + name = "Unstable mutagen" + result = /datum/reagent/mutagen + required_reagents = list(/datum/reagent/radium = 1, /datum/reagent/phosphorus = 1, /datum/reagent/acid/hydrochloric = 1) + result_amount = 3 + +/datum/chemical_reaction/thermite + name = "Thermite" + result = /datum/reagent/thermite + required_reagents = list(/datum/reagent/aluminum = 1, /datum/reagent/iron = 1, /datum/reagent/acetone = 1) + result_amount = 3 + +/datum/chemical_reaction/space_drugs + name = "Space Drugs" + result = /datum/reagent/space_drugs + required_reagents = list(/datum/reagent/mercury = 1, /datum/reagent/sugar = 1, /datum/reagent/lithium = 1) + result_amount = 3 + +/datum/chemical_reaction/lube + name = "Space Lube" + result = /datum/reagent/lube + required_reagents = list(/datum/reagent/water = 1, /datum/reagent/silicon = 1, /datum/reagent/acetone = 1) + result_amount = 4 + +/datum/chemical_reaction/pacid + name = "Polytrinic acid" + result = /datum/reagent/acid/polyacid + required_reagents = list(/datum/reagent/acid = 1, /datum/reagent/acid/hydrochloric = 1, /datum/reagent/potassium = 1) + result_amount = 3 + +/datum/chemical_reaction/synaptizine + name = "Synaptizine" + result = /datum/reagent/synaptizine + required_reagents = list(/datum/reagent/sugar = 1, /datum/reagent/lithium = 1, /datum/reagent/water = 1) + result_amount = 3 + +/datum/chemical_reaction/hyronalin + name = "Hyronalin" + result = /datum/reagent/hyronalin + required_reagents = list(/datum/reagent/radium = 1, /datum/reagent/dylovene = 1) + result_amount = 2 + +/datum/chemical_reaction/arithrazine + name = "Arithrazine" + result = /datum/reagent/arithrazine + required_reagents = list(/datum/reagent/hyronalin = 1, /datum/reagent/hydrazine = 1) + result_amount = 2 + +/datum/chemical_reaction/impedrezene + name = "Impedrezene" + result = /datum/reagent/impedrezene + required_reagents = list(/datum/reagent/mercury = 1, /datum/reagent/acetone = 1, /datum/reagent/sugar = 1) + result_amount = 2 + +/datum/chemical_reaction/kelotane + name = "Kelotane" + result = /datum/reagent/kelotane + required_reagents = list(/datum/reagent/silicon = 1, /datum/reagent/carbon = 1) + result_amount = 2 + log_is_important = 1 + +/datum/chemical_reaction/peridaxon + name = "Peridaxon" + result = /datum/reagent/peridaxon + required_reagents = list(/datum/reagent/bicaridine = 2, /datum/reagent/clonexadone = 2) + catalysts = list(/datum/reagent/toxin/phoron = 5) + result_amount = 2 + +/datum/chemical_reaction/virus_food + name = "Virus Food" + result = /datum/reagent/nutriment/virus_food + required_reagents = list(/datum/reagent/water = 1, /datum/reagent/drink/milk = 1) + result_amount = 5 + +/datum/chemical_reaction/leporazine + name = "Leporazine" + result = /datum/reagent/leporazine + required_reagents = list(/datum/reagent/silicon = 1, /datum/reagent/copper = 1) + catalysts = list(/datum/reagent/toxin/phoron = 5) + result_amount = 2 + +/datum/chemical_reaction/cryptobiolin + name = "Cryptobiolin" + result = /datum/reagent/cryptobiolin + required_reagents = list(/datum/reagent/potassium = 1, /datum/reagent/acetone = 1, /datum/reagent/sugar = 1) + result_amount = 3 + +/datum/chemical_reaction/tricordrazine + name = "Tricordrazine" + result = /datum/reagent/tricordrazine + required_reagents = list(/datum/reagent/inaprovaline = 1, /datum/reagent/dylovene = 1) + result_amount = 2 + +/datum/chemical_reaction/alkysine + name = "Alkysine" + result = /datum/reagent/alkysine + required_reagents = list(/datum/reagent/acid/hydrochloric = 1, /datum/reagent/ammonia = 1, /datum/reagent/dylovene = 1) + result_amount = 2 + +/datum/chemical_reaction/dexalin + name = "Dexalin" + result = /datum/reagent/dexalin + required_reagents = list(/datum/reagent/acetone = 2, /datum/reagent/toxin/phoron = 0.1) + inhibitors = list(/datum/reagent/water = 1) // Messes with cryox + result_amount = 1 + +/datum/chemical_reaction/dermaline + name = "Dermaline" + result = /datum/reagent/dermaline + required_reagents = list(/datum/reagent/acetone = 1, /datum/reagent/phosphorus = 1, /datum/reagent/kelotane = 1) + result_amount = 3 + +/datum/chemical_reaction/dexalinp + name = "Dexalin Plus" + result = /datum/reagent/dexalinp + required_reagents = list(/datum/reagent/dexalin = 1, /datum/reagent/carbon = 1, /datum/reagent/iron = 1) + result_amount = 3 + +/datum/chemical_reaction/bicaridine + name = "Bicaridine" + result = /datum/reagent/bicaridine + required_reagents = list(/datum/reagent/inaprovaline = 1, /datum/reagent/carbon = 1) + inhibitors = list(/datum/reagent/sugar = 1) // Messes up with inaprovaline + result_amount = 2 + +/datum/chemical_reaction/hyperzine + name = "Hyperzine" + result = /datum/reagent/hyperzine + required_reagents = list(/datum/reagent/sugar = 1, /datum/reagent/phosphorus = 1, /datum/reagent/sulfur = 1) + result_amount = 3 + +/datum/chemical_reaction/ryetalyn + name = "Ryetalyn" + result = /datum/reagent/ryetalyn + required_reagents = list(/datum/reagent/arithrazine = 1, /datum/reagent/carbon = 1) + result_amount = 2 + +/datum/chemical_reaction/cryoxadone + name = "Cryoxadone" + result = /datum/reagent/cryoxadone + required_reagents = list(/datum/reagent/dexalin = 1, /datum/reagent/water = 1, /datum/reagent/acetone = 1) + result_amount = 3 + +/datum/chemical_reaction/clonexadone + name = "Clonexadone" + result = /datum/reagent/clonexadone + required_reagents = list(/datum/reagent/cryoxadone = 1, /datum/reagent/sodium = 1, /datum/reagent/toxin/phoron = 0.1) + result_amount = 2 + +/datum/chemical_reaction/spaceacillin + name = "Spaceacillin" + result = /datum/reagent/spaceacillin + required_reagents = list(/datum/reagent/cryptobiolin = 1, /datum/reagent/inaprovaline = 1) + result_amount = 2 + +/datum/chemical_reaction/imidazoline + name = "Imidazoline" + result = /datum/reagent/imidazoline + required_reagents = list(/datum/reagent/carbon = 1, /datum/reagent/hydrazine = 1, /datum/reagent/dylovene = 1) + result_amount = 2 + +/datum/chemical_reaction/ethylredoxrazine + name = "Ethylredoxrazine" + result = /datum/reagent/ethylredoxrazine + required_reagents = list(/datum/reagent/acetone = 1, /datum/reagent/dylovene = 1, /datum/reagent/carbon = 1) + result_amount = 3 + +/datum/chemical_reaction/soporific + name = "Soporific" + result = /datum/reagent/soporific + required_reagents = list(/datum/reagent/chloralhydrate = 1, /datum/reagent/sugar = 4) + inhibitors = list(/datum/reagent/phosphorus) // Messes with the smoke + result_amount = 5 + +/datum/chemical_reaction/chloralhydrate + name = "Chloral Hydrate" + result = /datum/reagent/chloralhydrate + required_reagents = list(/datum/reagent/ethanol = 1, /datum/reagent/acid/hydrochloric = 3, /datum/reagent/water = 1) + result_amount = 1 + +/datum/chemical_reaction/potassium_chloride + name = "Potassium Chloride" + result = /datum/reagent/toxin/potassium_chloride + required_reagents = list(/datum/reagent/sodiumchloride = 1, /datum/reagent/potassium = 1) + result_amount = 2 + +/datum/chemical_reaction/potassium_chlorophoride + name = "Potassium Chlorophoride" + result = /datum/reagent/toxin/potassium_chlorophoride + required_reagents = list(/datum/reagent/toxin/potassium_chloride = 1, /datum/reagent/toxin/phoron = 1, /datum/reagent/chloralhydrate = 1) + result_amount = 4 + +/datum/chemical_reaction/zombiepowder + name = "Zombie Powder" + result = /datum/reagent/toxin/zombiepowder + required_reagents = list(/datum/reagent/toxin/carpotoxin = 5, /datum/reagent/soporific = 5, /datum/reagent/copper = 5) + result_amount = 2 + +/datum/chemical_reaction/mindbreaker + name = "Mindbreaker Toxin" + result = /datum/reagent/mindbreaker + required_reagents = list(/datum/reagent/silicon = 1, /datum/reagent/hydrazine = 1, /datum/reagent/dylovene = 1) + result_amount = 3 + +/datum/chemical_reaction/lipozine + name = "Lipozine" + result = /datum/reagent/lipozine + required_reagents = list(/datum/reagent/sodiumchloride = 1, /datum/reagent/ethanol = 1, /datum/reagent/radium = 1) + result_amount = 3 + +/datum/chemical_reaction/surfactant + name = "Azosurfactant" + result = /datum/reagent/surfactant + required_reagents = list(/datum/reagent/hydrazine = 2, /datum/reagent/carbon = 2, /datum/reagent/acid = 1) + result_amount = 5 + +/datum/chemical_reaction/diethylamine + name = "Diethylamine" + result = /datum/reagent/diethylamine + required_reagents = list (/datum/reagent/ammonia = 1, /datum/reagent/ethanol = 1) + result_amount = 2 + +/datum/chemical_reaction/space_cleaner + name = "Space cleaner" + result = /datum/reagent/space_cleaner + required_reagents = list(/datum/reagent/ammonia = 1, /datum/reagent/water = 1) + result_amount = 2 + +/datum/chemical_reaction/plantbgone + name = "Plant-B-Gone" + result = /datum/reagent/toxin/plantbgone + required_reagents = list(/datum/reagent/toxin = 1, /datum/reagent/water = 4) + result_amount = 5 + +/datum/chemical_reaction/foaming_agent + name = "Foaming Agent" + result = /datum/reagent/foaming_agent + required_reagents = list(/datum/reagent/lithium = 1, /datum/reagent/hydrazine = 1) + result_amount = 1 + +/datum/chemical_reaction/glycerol + name = "Glycerol" + result = /datum/reagent/glycerol + required_reagents = list(/datum/reagent/nutriment/cornoil = 3, /datum/reagent/acid = 1) + result_amount = 1 + +/datum/chemical_reaction/sodiumchloride + name = "Sodium Chloride" + result = /datum/reagent/sodiumchloride + required_reagents = list(/datum/reagent/sodium = 1, /datum/reagent/acid/hydrochloric = 1) + result_amount = 2 + +/datum/chemical_reaction/condensedcapsaicin + name = "Condensed Capsaicin" + result = /datum/reagent/capsaicin/condensed + required_reagents = list(/datum/reagent/capsaicin = 2) + catalysts = list(/datum/reagent/toxin/phoron = 5) + result_amount = 1 + +/datum/chemical_reaction/coolant + name = "Coolant" + result = /datum/reagent/coolant + required_reagents = list(/datum/reagent/tungsten = 1, /datum/reagent/acetone = 1, /datum/reagent/water = 1) + result_amount = 3 + log_is_important = 1 + +/datum/chemical_reaction/rezadone + name = "Rezadone" + result = /datum/reagent/rezadone + required_reagents = list(/datum/reagent/toxin/carpotoxin = 1, /datum/reagent/cryptobiolin = 1, /datum/reagent/copper = 1) + result_amount = 3 + +/datum/chemical_reaction/lexorin + name = "Lexorin" + result = /datum/reagent/lexorin + required_reagents = list(/datum/reagent/toxin/phoron = 1, /datum/reagent/hydrazine = 1, /datum/reagent/ammonia = 1) + result_amount = 3 + +/datum/chemical_reaction/methylphenidate + name = "Methylphenidate" + result = /datum/reagent/methylphenidate + required_reagents = list(/datum/reagent/mindbreaker = 1, /datum/reagent/lithium = 1) + result_amount = 3 + +/datum/chemical_reaction/citalopram + name = "Citalopram" + result = /datum/reagent/citalopram + required_reagents = list(/datum/reagent/mindbreaker = 1, /datum/reagent/carbon = 1) + result_amount = 3 + + +/datum/chemical_reaction/paroxetine + name = "Paroxetine" + result = /datum/reagent/paroxetine + required_reagents = list(/datum/reagent/mindbreaker = 1, /datum/reagent/acetone = 1, /datum/reagent/inaprovaline = 1) + result_amount = 3 + +/datum/chemical_reaction/hair_remover + name = "Hair Remover" + result = /datum/reagent/toxin/hair_remover + required_reagents = list(/datum/reagent/radium = 1, /datum/reagent/potassium = 1, /datum/reagent/acid/hydrochloric = 1) + result_amount = 3 + +/datum/chemical_reaction/noexcutite + name = "Noexcutite" + result = /datum/reagent/noexcutite + required_reagents = list(/datum/reagent/tramadol/oxycodone = 1, /datum/reagent/dylovene = 1) + result_amount = 2 + +/* Solidification */ + +/datum/chemical_reaction/phoronsolidification + name = "Solid Phoron" + result = null + required_reagents = list(/datum/reagent/iron = 5, /datum/reagent/frostoil = 5, /datum/reagent/toxin/phoron = 20) + result_amount = 1 + +/datum/chemical_reaction/phoronsolidification/on_reaction(var/datum/reagents/holder, var/created_volume) + new /obj/item/stack/material/phoron(get_turf(holder.my_atom), created_volume) + +/datum/chemical_reaction/plastication + name = "Plastic" + result = null + required_reagents = list(/datum/reagent/acid/polyacid = 1, /datum/reagent/toxin/plasticide = 2) + result_amount = 1 + +/datum/chemical_reaction/plastication/on_reaction(var/datum/reagents/holder, var/created_volume) + new /obj/item/stack/material/plastic(get_turf(holder.my_atom), created_volume) + +/* Grenade reactions */ + +/datum/chemical_reaction/explosion_potassium + name = "Explosion" + result = null + required_reagents = list(/datum/reagent/water = 1, /datum/reagent/potassium = 1) + result_amount = 2 + mix_message = null + +/datum/chemical_reaction/explosion_potassium/on_reaction(var/datum/reagents/holder, var/created_volume) + var/datum/effect/effect/system/reagents_explosion/e = new() + e.set_up(round (created_volume/10, 1), holder.my_atom, 0, 0) + if(isliving(holder.my_atom)) + e.amount *= 0.5 + var/mob/living/L = holder.my_atom + if(L.stat != DEAD) + e.amount *= 0.5 + e.start() + holder.clear_reagents() + +/datum/chemical_reaction/flash_powder + name = "Flash powder" + result = null + required_reagents = list(/datum/reagent/aluminum = 1, /datum/reagent/potassium = 1, /datum/reagent/sulfur = 1 ) + result_amount = null + +/datum/chemical_reaction/flash_powder/on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, location) + s.start() + for(var/mob/living/carbon/M in viewers(world.view, location)) + switch(get_dist(M, location)) + if(0 to 3) + if(hasvar(M, "glasses")) + if(istype(M:glasses, /obj/item/clothing/glasses/sunglasses)) + continue + + M.flash_eyes() + M.Weaken(15) + + if(4 to 5) + if(hasvar(M, "glasses")) + if(istype(M:glasses, /obj/item/clothing/glasses/sunglasses)) + continue + + M.flash_eyes() + M.Stun(5) + +/datum/chemical_reaction/emp_pulse + name = "EMP Pulse" + result = null + required_reagents = list(/datum/reagent/uranium = 1, /datum/reagent/iron = 1) // Yes, laugh, it's the best recipe I could think of that makes a little bit of sense + result_amount = 2 + +/datum/chemical_reaction/emp_pulse/on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + // 100 created volume = 4 heavy range & 7 light range. A few tiles smaller than traitor EMP grandes. + // 200 created volume = 8 heavy range & 14 light range. 4 tiles larger than traitor EMP grenades. + empulse(location, round(created_volume / 24), round(created_volume / 14), 1) + holder.clear_reagents() + +/datum/chemical_reaction/nitroglycerin + name = "Nitroglycerin" + result = /datum/reagent/nitroglycerin + required_reagents = list(/datum/reagent/glycerol = 1, /datum/reagent/acid/polyacid = 1, /datum/reagent/acid = 1) + result_amount = 2 + log_is_important = 1 + +/datum/chemical_reaction/nitroglycerin/on_reaction(var/datum/reagents/holder, var/created_volume) + var/datum/effect/effect/system/reagents_explosion/e = new() + e.set_up(round (created_volume/2, 1), holder.my_atom, 0, 0) + if(isliving(holder.my_atom)) + e.amount *= 0.5 + var/mob/living/L = holder.my_atom + if(L.stat!=DEAD) + e.amount *= 0.5 + e.start() + + holder.clear_reagents() + +/datum/chemical_reaction/napalm + name = "Napalm" + result = null + required_reagents = list(/datum/reagent/aluminum = 1, /datum/reagent/toxin/phoron = 1, /datum/reagent/acid = 1 ) + result_amount = 1 + +/datum/chemical_reaction/napalm/on_reaction(var/datum/reagents/holder, var/created_volume) + var/turf/location = get_turf(holder.my_atom.loc) + for(var/turf/simulated/floor/target_tile in range(0,location)) + target_tile.assume_gas(/datum/reagent/toxin/phoron, created_volume, 400+T0C) + spawn (0) target_tile.hotspot_expose(700, 400) + holder.del_reagent("napalm") + +/datum/chemical_reaction/chemsmoke + name = "Chemsmoke" + result = null + required_reagents = list(/datum/reagent/potassium = 1, /datum/reagent/sugar = 1, /datum/reagent/phosphorus = 1) + result_amount = 0.4 + +/datum/chemical_reaction/chemsmoke/on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + var/datum/effect/effect/system/smoke_spread/chem/S = new /datum/effect/effect/system/smoke_spread/chem + S.attach(location) + S.set_up(holder, created_volume, 0, location) + playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3) + spawn(0) + S.start() + holder.clear_reagents() + +/datum/chemical_reaction/foam + name = "Foam" + result = null + required_reagents = list(/datum/reagent/surfactant = 1, /datum/reagent/water = 1) + result_amount = 2 + mix_message = "The solution violently bubbles!" + +/datum/chemical_reaction/foam/on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + + for(var/mob/M in viewers(5, location)) + to_chat(M, "The solution spews out foam!") + + var/datum/effect/effect/system/foam_spread/s = new() + s.set_up(created_volume, location, holder, 0) + s.start() + holder.clear_reagents() + +/datum/chemical_reaction/metalfoam + name = "Metal Foam" + result = null + required_reagents = list(/datum/reagent/aluminum = 3, /datum/reagent/foaming_agent = 1, /datum/reagent/acid/polyacid = 1) + result_amount = 5 + +/datum/chemical_reaction/metalfoam/on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + + for(var/mob/M in viewers(5, location)) + to_chat(M, "The solution spews out a metalic foam!") + + var/datum/effect/effect/system/foam_spread/s = new() + s.set_up(created_volume, location, holder, 1) + s.start() + +/datum/chemical_reaction/ironfoam + name = "Iron Foam" + result = null + required_reagents = list(/datum/reagent/iron = 3, /datum/reagent/foaming_agent = 1, /datum/reagent/acid/polyacid = 1) + result_amount = 5 + +/datum/chemical_reaction/ironfoam/on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + + for(var/mob/M in viewers(5, location)) + to_chat(M, "The solution spews out a metalic foam!") + + var/datum/effect/effect/system/foam_spread/s = new() + s.set_up(created_volume, location, holder, 2) + s.start() + +/* Paint */ + +/datum/chemical_reaction/red_paint + name = "Red paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/crayon_dust/red = 1) + result_amount = 5 + +/datum/chemical_reaction/red_paint/send_data() + return "#fe191a" + +/datum/chemical_reaction/orange_paint + name = "Orange paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/crayon_dust/orange = 1) + result_amount = 5 + +/datum/chemical_reaction/orange_paint/send_data() + return "#ffbe4f" + +/datum/chemical_reaction/yellow_paint + name = "Yellow paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/crayon_dust/yellow = 1) + result_amount = 5 + +/datum/chemical_reaction/yellow_paint/send_data() + return "#fdfe7d" + +/datum/chemical_reaction/green_paint + name = "Green paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/crayon_dust/green = 1) + result_amount = 5 + +/datum/chemical_reaction/green_paint/send_data() + return "#18a31a" + +/datum/chemical_reaction/blue_paint + name = "Blue paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/crayon_dust/blue = 1) + result_amount = 5 + +/datum/chemical_reaction/blue_paint/send_data() + return "#247cff" + +/datum/chemical_reaction/purple_paint + name = "Purple paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/crayon_dust/purple = 1) + result_amount = 5 + +/datum/chemical_reaction/purple_paint/send_data() + return "#cc0099" + +/datum/chemical_reaction/grey_paint //mime + name = "Grey paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/crayon_dust/grey = 1) + result_amount = 5 + +/datum/chemical_reaction/grey_paint/send_data() + return "#808080" + +/datum/chemical_reaction/brown_paint + name = "Brown paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/crayon_dust/brown = 1) + result_amount = 5 + +/datum/chemical_reaction/brown_paint/send_data() + return "#846f35" + +/datum/chemical_reaction/blood_paint + name = "Blood paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/blood = 2) + result_amount = 5 + +/datum/chemical_reaction/blood_paint/send_data(var/datum/reagents/T) + var/t = T.get_data("blood") + if(t && t["blood_colour"]) + return t["blood_colour"] + return "#fe191a" // Probably red + +/datum/chemical_reaction/milk_paint + name = "Milk paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/drink/milk = 5) + result_amount = 5 + +/datum/chemical_reaction/milk_paint/send_data() + return "#f0f8ff" + +/datum/chemical_reaction/orange_juice_paint + name = "Orange juice paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/drink/juice/orange = 5) + result_amount = 5 + +/datum/chemical_reaction/orange_juice_paint/send_data() + return "#e78108" + +/datum/chemical_reaction/tomato_juice_paint + name = "Tomato juice paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/drink/juice/tomato = 5) + result_amount = 5 + +/datum/chemical_reaction/tomato_juice_paint/send_data() + return "#731008" + +/datum/chemical_reaction/lime_juice_paint + name = "Lime juice paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/drink/juice/lime = 5) + result_amount = 5 + +/datum/chemical_reaction/lime_juice_paint/send_data() + return "#365e30" + +/datum/chemical_reaction/carrot_juice_paint + name = "Carrot juice paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/drink/juice/carrot = 5) + result_amount = 5 + +/datum/chemical_reaction/carrot_juice_paint/send_data() + return "#973800" + +/datum/chemical_reaction/berry_juice_paint + name = "Berry juice paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/drink/juice/berry = 5) + result_amount = 5 + +/datum/chemical_reaction/berry_juice_paint/send_data() + return "#990066" + +/datum/chemical_reaction/grape_juice_paint + name = "Grape juice paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/drink/juice/grape = 5) + result_amount = 5 + +/datum/chemical_reaction/grape_juice_paint/send_data() + return "#863333" + +/datum/chemical_reaction/poisonberry_juice_paint + name = "Poison berry juice paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/toxin/poisonberryjuice = 5) + result_amount = 5 + +/datum/chemical_reaction/poisonberry_juice_paint/send_data() + return "#863353" + +/datum/chemical_reaction/watermelon_juice_paint + name = "Watermelon juice paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/drink/juice/watermelon = 5) + result_amount = 5 + +/datum/chemical_reaction/watermelon_juice_paint/send_data() + return "#b83333" + +/datum/chemical_reaction/lemon_juice_paint + name = "Lemon juice paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/drink/juice/lemon = 5) + result_amount = 5 + +/datum/chemical_reaction/lemon_juice_paint/send_data() + return "#afaf00" + +/datum/chemical_reaction/banana_juice_paint + name = "Banana juice paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/drink/juice/banana = 5) + result_amount = 5 + +/datum/chemical_reaction/banana_juice_paint/send_data() + return "#c3af00" + +/datum/chemical_reaction/potato_juice_paint + name = "Potato juice paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, "potatojuice" = 5) + result_amount = 5 + +/datum/chemical_reaction/potato_juice_paint/send_data() + return "#302000" + +/datum/chemical_reaction/carbon_paint + name = "Carbon paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/carbon = 1) + result_amount = 5 + +/datum/chemical_reaction/carbon_paint/send_data() + return "#333333" + +/datum/chemical_reaction/aluminum_paint + name = "Aluminum paint" + result = /datum/reagent/paint + required_reagents = list(/datum/reagent/toxin/plasticide = 1, /datum/reagent/water = 3, /datum/reagent/aluminum = 1) + result_amount = 5 + +/datum/chemical_reaction/aluminum_paint/send_data() + return "#f0f8ff" + +/* Slime cores */ + +/datum/chemical_reaction/slime + var/required = null + +/datum/chemical_reaction/slime/can_happen(var/datum/reagents/holder) + if(holder.my_atom && istype(holder.my_atom, required)) + var/obj/item/slime_extract/T = holder.my_atom + if(T.Uses > 0) + return ..() + return 0 + +/datum/chemical_reaction/slime/on_reaction(var/datum/reagents/holder) + var/obj/item/slime_extract/T = holder.my_atom + T.Uses-- + if(T.Uses <= 0) + T.visible_message("\icon[T]\The [T]'s power is consumed in the reaction.") + T.SetName("used slime extract") + T.desc = "This extract has been used up." + +//Grey +/datum/chemical_reaction/slime/spawn + name = "Slime Spawn" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 1 + required = /obj/item/slime_extract/grey + +/datum/chemical_reaction/slime/spawn/on_reaction(var/datum/reagents/holder) + holder.my_atom.visible_message("Infused with phoron, the core begins to quiver and grow, and soon a new baby slime emerges from it!") + var/mob/living/carbon/slime/S = new /mob/living/carbon/slime + S.loc = get_turf(holder.my_atom) + ..() + +/datum/chemical_reaction/slime/monkey + name = "Slime Monkey" + result = null + required_reagents = list(/datum/reagent/blood = 1) + result_amount = 1 + required = /obj/item/slime_extract/grey + +/datum/chemical_reaction/slime/monkey/on_reaction(var/datum/reagents/holder) + for(var/i = 1, i <= 3, i++) + var /obj/item/weapon/reagent_containers/food/snacks/monkeycube/M = new /obj/item/weapon/reagent_containers/food/snacks/monkeycube + M.loc = get_turf(holder.my_atom) + ..() + +//Green +/datum/chemical_reaction/slime/mutate + name = "Mutation Toxin" + result = /datum/reagent/slimetoxin + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 1 + required = /obj/item/slime_extract/green + +//Metal +/datum/chemical_reaction/slime/metal + name = "Slime Metal" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 1 + required = /obj/item/slime_extract/metal + +/datum/chemical_reaction/slime/metal/on_reaction(var/datum/reagents/holder) + var/obj/item/stack/material/steel/M = new /obj/item/stack/material/steel + M.amount = 15 + M.loc = get_turf(holder.my_atom) + var/obj/item/stack/material/plasteel/P = new /obj/item/stack/material/plasteel + P.amount = 5 + P.loc = get_turf(holder.my_atom) + ..() + +//Gold +/datum/chemical_reaction/slime/crit + name = "Slime Crit" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 1 + required = /obj/item/slime_extract/gold + var/list/possible_mobs = list( + /mob/living/simple_animal/cat, + /mob/living/simple_animal/cat/kitten, + /mob/living/simple_animal/corgi, + /mob/living/simple_animal/corgi/puppy, + /mob/living/simple_animal/cow, + /mob/living/simple_animal/chick, + /mob/living/simple_animal/chicken + ) + +/datum/chemical_reaction/slime/crit/on_reaction(var/datum/reagents/holder) + var/type = pick(possible_mobs) + new type(get_turf(holder.my_atom)) + ..() + +//Silver +/datum/chemical_reaction/slime/bork + name = "Slime Bork" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 1 + required = /obj/item/slime_extract/silver + +/datum/chemical_reaction/slime/bork/on_reaction(var/datum/reagents/holder) + 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) + M.flash_eyes() + + for(var/i = 1, i <= 4 + rand(1,2), i++) + var/chosen = pick(borks) + var/obj/B = new chosen + if(B) + B.loc = get_turf(holder.my_atom) + if(prob(50)) + for(var/j = 1, j <= rand(1, 3), j++) + step(B, pick(NORTH, SOUTH, EAST, WEST)) + ..() + +//Blue +/datum/chemical_reaction/slime/frost + name = "Slime Frost Oil" + result = /datum/reagent/frostoil + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 10 + required = /obj/item/slime_extract/blue + +//Dark Blue +/datum/chemical_reaction/slime/freeze + name = "Slime Freeze" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 1 + required = /obj/item/slime_extract/darkblue + mix_message = "The slime extract begins to vibrate violently!" + +/datum/chemical_reaction/slime/freeze/on_reaction(var/datum/reagents/holder) + set waitfor = 0 + ..() + sleep(50) + playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1) + for(var/mob/living/M in range (get_turf(holder.my_atom), 7)) + M.bodytemperature -= 140 + to_chat(M, "You feel a chill!") + +//Orange +/datum/chemical_reaction/slime/casp + name = "Slime Capsaicin Oil" + result = /datum/reagent/capsaicin + required_reagents = list(/datum/reagent/blood = 1) + result_amount = 10 + required = /obj/item/slime_extract/orange + +/datum/chemical_reaction/slime/fire + name = "Slime fire" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 1 + required = /obj/item/slime_extract/orange + mix_message = "The slime extract begins to vibrate violently!" + +/datum/chemical_reaction/slime/fire/on_reaction(var/datum/reagents/holder) + set waitfor = 0 + ..() + sleep(50) + if(!(holder.my_atom && holder.my_atom.loc)) + return + + var/turf/location = get_turf(holder.my_atom) + location.assume_gas("phoron", 250, 1400) + location.hotspot_expose(700, 400) + +//Yellow +/datum/chemical_reaction/slime/overload + name = "Slime EMP" + result = null + required_reagents = list(/datum/reagent/blood = 1) + result_amount = 1 + required = /obj/item/slime_extract/yellow + +/datum/chemical_reaction/slime/overload/on_reaction(var/datum/reagents/holder, var/created_volume) + ..() + empulse(get_turf(holder.my_atom), 3, 7) + +/datum/chemical_reaction/slime/cell + name = "Slime Powercell" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 1 + required = /obj/item/slime_extract/yellow + +/datum/chemical_reaction/slime/cell/on_reaction(var/datum/reagents/holder, var/created_volume) + ..() + new /obj/item/weapon/cell/slime(get_turf(holder.my_atom)) + +/datum/chemical_reaction/slime/glow + name = "Slime Glow" + result = null + required_reagents = list(/datum/reagent/water = 1) + result_amount = 1 + required = /obj/item/slime_extract/yellow + mix_message = "The contents of the slime core harden and begin to emit a warm, bright light." + +/datum/chemical_reaction/slime/glow/on_reaction(var/datum/reagents/holder, var/created_volume) + ..() + new /obj/item/device/flashlight/slime(get_turf(holder.my_atom)) + +//Purple +/datum/chemical_reaction/slime/psteroid + name = "Slime Steroid" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 1 + required = /obj/item/slime_extract/purple + +/datum/chemical_reaction/slime/psteroid/on_reaction(var/datum/reagents/holder, var/created_volume) + ..() + var/obj/item/weapon/slimesteroid/P = new /obj/item/weapon/slimesteroid + P.loc = get_turf(holder.my_atom) + +/datum/chemical_reaction/slime/jam + name = "Slime Jam" + result = /datum/reagent/slimejelly + required_reagents = list(/datum/reagent/sugar = 1) + result_amount = 10 + required = /obj/item/slime_extract/purple + +//Dark Purple +/datum/chemical_reaction/slime/plasma + name = "Slime Plasma" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 1 + required = /obj/item/slime_extract/darkpurple + +/datum/chemical_reaction/slime/plasma/on_reaction(var/datum/reagents/holder) + ..() + var/obj/item/stack/material/phoron/P = new /obj/item/stack/material/phoron + P.amount = 10 + P.loc = get_turf(holder.my_atom) + +//Red +/datum/chemical_reaction/slime/glycerol + name = "Slime Glycerol" + result = /datum/reagent/glycerol + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 8 + required = /obj/item/slime_extract/red + +/datum/chemical_reaction/slime/bloodlust + name = "Bloodlust" + result = null + required_reagents = list(/datum/reagent/blood = 1) + result_amount = 1 + required = /obj/item/slime_extract/red + +/datum/chemical_reaction/slime/bloodlust/on_reaction(var/datum/reagents/holder) + ..() + for(var/mob/living/carbon/slime/slime in viewers(get_turf(holder.my_atom), null)) + slime.rabid = 1 + slime.visible_message("The [slime] is driven into a frenzy!") + +//Pink +/datum/chemical_reaction/slime/ppotion + name = "Slime Potion" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 1 + required = /obj/item/slime_extract/pink + +/datum/chemical_reaction/slime/ppotion/on_reaction(var/datum/reagents/holder) + ..() + var/obj/item/weapon/slimepotion/P = new /obj/item/weapon/slimepotion + P.loc = get_turf(holder.my_atom) + +//Black +/datum/chemical_reaction/slime/mutate2 + name = "Advanced Mutation Toxin" + result = /datum/reagent/aslimetoxin + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 1 + required = /obj/item/slime_extract/black + +//Oil +/datum/chemical_reaction/slime/explosion + name = "Slime Explosion" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 1 + required = /obj/item/slime_extract/oil + mix_message = "The slime extract begins to vibrate violently!" + +/datum/chemical_reaction/slime/explosion/on_reaction(var/datum/reagents/holder) + set waitfor = 0 + ..() + sleep(50) + explosion(get_turf(holder.my_atom), 1, 3, 6) + +//Light Pink +/datum/chemical_reaction/slime/potion2 + name = "Slime Potion 2" + result = null + result_amount = 1 + required = /obj/item/slime_extract/lightpink + required_reagents = list(/datum/reagent/toxin/phoron = 1) + +/datum/chemical_reaction/slime/potion2/on_reaction(var/datum/reagents/holder) + ..() + new /obj/item/weapon/slimepotion2(get_turf(holder.my_atom)) + +//Adamantine +/datum/chemical_reaction/slime/golem + name = "Slime Golem" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 1 + required = /obj/item/slime_extract/adamantine + +/datum/chemical_reaction/slime/golem/on_reaction(var/datum/reagents/holder) + ..() + var/obj/effect/golemrune/Z = new /obj/effect/golemrune(get_turf(holder.my_atom)) + Z.announce_to_ghosts() + +//Sepia +/datum/chemical_reaction/slime/film + name = "Slime Film" + result = null + required_reagents = list(/datum/reagent/blood = 1) + result_amount = 2 + required = /obj/item/slime_extract/sepia + +/datum/chemical_reaction/slime/film/on_reaction(var/datum/reagents/holder) + for(var/i in 1 to result_amount) + new /obj/item/device/camera_film(get_turf(holder.my_atom)) + ..() + +/datum/chemical_reaction/slime/camera + name = "Slime Camera" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + result_amount = 1 + required = /obj/item/slime_extract/sepia + +/datum/chemical_reaction/slime/camera/on_reaction(var/datum/reagents/holder) + new /obj/item/device/camera(get_turf(holder.my_atom)) + ..() + +//Bluespace +/datum/chemical_reaction/slime/teleport + name = "Slime Teleport" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + required = /obj/item/slime_extract/bluespace + reaction_sound = 'sound/effects/teleport.ogg' + +/datum/chemical_reaction/slime/teleport/on_reaction(var/datum/reagents/holder) + var/list/turfs = list() + for(var/turf/T in orange(holder.my_atom,6)) + turfs += T + for(var/atom/movable/a in viewers(holder.my_atom,2)) + if(!a.simulated) + continue + a.forceMove(pick(turfs)) + ..() + +//pyrite +/datum/chemical_reaction/slime/paint + name = "Slime Paint" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + required = /obj/item/slime_extract/pyrite + +/datum/chemical_reaction/slime/paint/on_reaction(var/datum/reagents/holder) + new /obj/item/weapon/reagent_containers/glass/paint/random(get_turf(holder.my_atom)) + ..() + +//cerulean +/datum/chemical_reaction/slime/extract_enhance + name = "Extract Enhancer" + result = null + required_reagents = list(/datum/reagent/toxin/phoron = 1) + required = /obj/item/slime_extract/cerulean + +/datum/chemical_reaction/slime/extract_enhance/on_reaction(var/datum/reagents/holder) + new /obj/item/weapon/slimesteroid2(get_turf(holder.my_atom)) + ..() + +/datum/chemical_reaction/soap_key + name = "Soap Key" + result = null + required_reagents = list(/datum/reagent/frostoil = 2, /datum/reagent/space_cleaner = 5) + var/strength = 3 + +/datum/chemical_reaction/soap_key/can_happen(var/datum/reagents/holder) + if(holder.my_atom && istype(holder.my_atom, /obj/item/weapon/soap)) + return ..() + return 0 + +/datum/chemical_reaction/soap_key/on_reaction(var/datum/reagents/holder) + var/obj/item/weapon/soap/S = holder.my_atom + if(S.key_data) + var/obj/item/weapon/key/soap/key = new(get_turf(holder.my_atom), S.key_data) + key.uses = strength + ..() + +/* Food */ + +/datum/chemical_reaction/tofu + name = "Tofu" + result = null + required_reagents = list(/datum/reagent/drink/milk/soymilk = 10) + catalysts = list(/datum/reagent/enzyme = 5) + result_amount = 1 + +/datum/chemical_reaction/tofu/on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + for(var/i = 1, i <= created_volume, i++) + new /obj/item/weapon/reagent_containers/food/snacks/tofu(location) + +/datum/chemical_reaction/chocolate_bar + name = "Chocolate Bar" + result = null + required_reagents = list(/datum/reagent/drink/milk/soymilk = 2, /datum/reagent/nutriment/coco = 2, /datum/reagent/sugar = 2) + result_amount = 1 + +/datum/chemical_reaction/chocolate_bar/on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + for(var/i = 1, i <= created_volume, i++) + new /obj/item/weapon/reagent_containers/food/snacks/chocolatebar(location) + +/datum/chemical_reaction/chocolate_bar2 + name = "Chocolate Bar" + result = null + required_reagents = list(/datum/reagent/drink/milk = 2, /datum/reagent/nutriment/coco = 2, /datum/reagent/sugar = 2) + result_amount = 1 + +/datum/chemical_reaction/chocolate_bar2/on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + for(var/i = 1, i <= created_volume, i++) + new /obj/item/weapon/reagent_containers/food/snacks/chocolatebar(location) + +/datum/chemical_reaction/hot_coco + name = "Hot Coco" + result = /datum/reagent/drink/hot_coco + required_reagents = list(/datum/reagent/water = 5, /datum/reagent/nutriment/coco = 1) + result_amount = 5 + +/datum/chemical_reaction/soysauce + name = "Soy Sauce" + result = /datum/reagent/nutriment/soysauce + required_reagents = list(/datum/reagent/drink/milk/soymilk = 4, /datum/reagent/acid = 1) + result_amount = 5 + +/datum/chemical_reaction/ketchup + name = "Ketchup" + result = /datum/reagent/nutriment/ketchup + required_reagents = list(/datum/reagent/drink/juice/tomato = 2, /datum/reagent/water = 1, /datum/reagent/sugar = 1) + result_amount = 4 + +/datum/chemical_reaction/barbecue + name = "Barbecue Sauce" + result = /datum/reagent/nutriment/barbecue + required_reagents = list(/datum/reagent/nutriment/ketchup = 2, "pepper" = 1, "salt" = 1) + result_amount = 4 + +/datum/chemical_reaction/garlicsauce + name = "Garlic Sauce" + result = /datum/reagent/nutriment/garlicsauce + required_reagents = list(/datum/reagent/drink/juice/garlic = 1, /datum/reagent/nutriment/cornoil = 1) + result_amount = 2 + +/datum/chemical_reaction/cheesewheel + name = "Cheesewheel" + result = null + required_reagents = list(/datum/reagent/drink/milk = 40) + catalysts = list(/datum/reagent/enzyme = 5) + result_amount = 1 + +/datum/chemical_reaction/cheesewheel/on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + for(var/i = 1, i <= created_volume, i++) + new /obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesewheel(location) + +/datum/chemical_reaction/meatball + name = "Meatball" + result = null + required_reagents = list(/datum/reagent/nutriment/protein = 3, /datum/reagent/nutriment/flour = 5) + result_amount = 3 + +/datum/chemical_reaction/meatball/on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + for(var/i = 1, i <= created_volume, i++) + new /obj/item/weapon/reagent_containers/food/snacks/meatball(location) + +/datum/chemical_reaction/dough + name = "Dough" + result = null + required_reagents = list(/datum/reagent/nutriment/protein/egg = 3, /datum/reagent/nutriment/flour = 10, /datum/reagent/water = 5) + result_amount = 1 + +/datum/chemical_reaction/dough/on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + for(var/i = 1, i <= created_volume, i++) + new /obj/item/weapon/reagent_containers/food/snacks/dough(location) + +/datum/chemical_reaction/syntiflesh + name = "Syntiflesh" + result = null + required_reagents = list(/datum/reagent/blood = 5, /datum/reagent/clonexadone = 1) + result_amount = 1 + +/datum/chemical_reaction/syntiflesh/on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + for(var/i = 1, i <= created_volume, i++) + new /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh(location) + +/datum/chemical_reaction/hot_ramen + name = "Hot Ramen" + result = /datum/reagent/drink/hot_ramen + required_reagents = list(/datum/reagent/water = 1, /datum/reagent/drink/dry_ramen = 3) + result_amount = 3 + +/datum/chemical_reaction/hell_ramen + name = "Hell Ramen" + result = /datum/reagent/drink/hell_ramen + required_reagents = list(/datum/reagent/capsaicin = 1, /datum/reagent/drink/hot_ramen = 6) + result_amount = 6 + +/* Alcohol */ + +/datum/chemical_reaction/goldschlager + name = "Goldschlager" + result = /datum/reagent/ethanol/goldschlager + required_reagents = list(/datum/reagent/ethanol/vodka = 10, /datum/reagent/gold = 1) + result_amount = 10 + +/datum/chemical_reaction/patron + name = "Patron" + result = /datum/reagent/ethanol/patron + required_reagents = list(/datum/reagent/ethanol/tequilla = 10, "silver" = 1) + result_amount = 10 + +/datum/chemical_reaction/bilk + name = "Bilk" + result = /datum/reagent/ethanol/bilk + required_reagents = list(/datum/reagent/drink/milk = 1, /datum/reagent/ethanol/beer = 1) + result_amount = 2 + +/datum/chemical_reaction/icetea + name = "Iced Tea" + result = /datum/reagent/drink/tea/icetea + required_reagents = list(/datum/reagent/drink/ice = 1, /datum/reagent/drink/tea = 2) + result_amount = 3 + +/datum/chemical_reaction/icecoffee + name = "Iced Coffee" + result = /datum/reagent/drink/coffee/icecoffee + required_reagents = list(/datum/reagent/drink/ice = 1, /datum/reagent/drink/coffee = 2) + result_amount = 3 + +/datum/chemical_reaction/nuka_cola + name = "Nuka Cola" + result = /datum/reagent/drink/nuka_cola + required_reagents = list(/datum/reagent/uranium = 1, /datum/reagent/drink/space_cola = 5) + result_amount = 5 + +/datum/chemical_reaction/moonshine + name = "Moonshine" + result = /datum/reagent/ethanol/moonshine + required_reagents = list(/datum/reagent/nutriment = 10) + catalysts = list(/datum/reagent/enzyme = 5) + result_amount = 10 + +/datum/chemical_reaction/grenadine + name = "Grenadine Syrup" + result = /datum/reagent/drink/grenadine + required_reagents = list(/datum/reagent/drink/juice/berry = 10) + catalysts = list(/datum/reagent/enzyme = 5) + result_amount = 10 + +/datum/chemical_reaction/wine + name = "Wine" + result = /datum/reagent/ethanol/wine + required_reagents = list(/datum/reagent/drink/juice/grape = 10) + catalysts = list(/datum/reagent/enzyme = 5) + result_amount = 10 + +/datum/chemical_reaction/pwine + name = "Poison Wine" + result = /datum/reagent/ethanol/pwine + required_reagents = list(/datum/reagent/toxin/poisonberryjuice = 10) + catalysts = list(/datum/reagent/enzyme = 5) + result_amount = 10 + +/datum/chemical_reaction/melonliquor + name = "Melon Liquor" + result = /datum/reagent/ethanol/melonliquor + required_reagents = list(/datum/reagent/drink/juice/watermelon = 10) + catalysts = list(/datum/reagent/enzyme = 5) + result_amount = 10 + +/datum/chemical_reaction/bluecuracao + name = "Blue Curacao" + result = /datum/reagent/ethanol/bluecuracao + required_reagents = list(/datum/reagent/drink/juice/orange = 10) + catalysts = list(/datum/reagent/enzyme = 5) + result_amount = 10 + +/datum/chemical_reaction/spacebeer + name = "Space Beer" + result = /datum/reagent/ethanol/beer + required_reagents = list(/datum/reagent/nutriment/cornoil = 10) + catalysts = list(/datum/reagent/enzyme = 5) + result_amount = 10 + +/datum/chemical_reaction/vodka + name = "Vodka" + result = /datum/reagent/ethanol/vodka + required_reagents = list(/datum/reagent/drink/juice/potato = 10) + catalysts = list(/datum/reagent/enzyme = 5) + result_amount = 10 + +/datum/chemical_reaction/sake + name = "Sake" + result = /datum/reagent/ethanol/sake + required_reagents = list(/datum/reagent/nutriment/rice = 10) + catalysts = list(/datum/reagent/enzyme = 5) + result_amount = 10 + +/datum/chemical_reaction/kahlua + name = "Kahlua" + result = /datum/reagent/ethanol/coffee/kahlua + required_reagents = list(/datum/reagent/drink/coffee = 5, /datum/reagent/sugar = 5) + catalysts = list(/datum/reagent/enzyme = 5) + result_amount = 5 + +/datum/chemical_reaction/gin_tonic + name = "Gin and Tonic" + result = /datum/reagent/ethanol/gintonic + required_reagents = list(/datum/reagent/ethanol/gin = 2, /datum/reagent/drink/tonic = 1) + result_amount = 3 + +/datum/chemical_reaction/cuba_libre + name = "Cuba Libre" + result = /datum/reagent/ethanol/cuba_libre + required_reagents = list(/datum/reagent/ethanol/rum = 2, /datum/reagent/drink/space_cola = 1) + result_amount = 3 + +/datum/chemical_reaction/martini + name = "Classic Martini" + result = /datum/reagent/ethanol/martini + required_reagents = list(/datum/reagent/ethanol/gin = 2, /datum/reagent/ethanol/vermouth = 1) + result_amount = 3 + +/datum/chemical_reaction/vodkamartini + name = "Vodka Martini" + result = /datum/reagent/ethanol/vodkamartini + required_reagents = list(/datum/reagent/ethanol/vodka = 2, /datum/reagent/ethanol/vermouth = 1) + result_amount = 3 + +/datum/chemical_reaction/white_russian + name = "White Russian" + result = /datum/reagent/ethanol/white_russian + required_reagents = list(/datum/reagent/ethanol/black_russian = 2, /datum/reagent/drink/milk/cream = 1) + result_amount = 3 + +/datum/chemical_reaction/whiskey_cola + name = "Whiskey Cola" + result = /datum/reagent/ethanol/whiskey_cola + required_reagents = list(/datum/reagent/ethanol/whiskey = 2, /datum/reagent/drink/space_cola = 1) + result_amount = 3 + +/datum/chemical_reaction/screwdriver + name = "Screwdriver" + result = /datum/reagent/ethanol/screwdrivercocktail + required_reagents = list(/datum/reagent/ethanol/vodka = 2, /datum/reagent/drink/juice/orange = 1) + result_amount = 3 + +/datum/chemical_reaction/battuta + name = "Ibn Battuta" + result = /datum/reagent/ethanol/battuta + required_reagents = list(/datum/reagent/ethanol/herbal = 2, /datum/reagent/drink/juice/orange = 1) + catalysts = list(/datum/reagent/nutriment/mint) + result_amount = 3 + +/datum/chemical_reaction/magellan + name = "Magellan" + result = /datum/reagent/ethanol/magellan + required_reagents = list(/datum/reagent/ethanol/wine = 1, /datum/reagent/ethanol/specialwhiskey = 1) + catalysts = list(/datum/reagent/sugar) + result_amount = 2 + +/datum/chemical_reaction/zhenghe + name = "Zheng He" + result = /datum/reagent/ethanol/zhenghe + required_reagents = list(/datum/reagent/drink/tea = 2, /datum/reagent/ethanol/vermouth = 1) + result_amount = 3 + +/datum/chemical_reaction/armstrong + name = "Armstrong" + result = /datum/reagent/ethanol/armstrong + required_reagents = list(/datum/reagent/ethanol/beer = 2, /datum/reagent/ethanol/vodka = 1, /datum/reagent/drink/juice/lime = 1) + result_amount = 4 + +/datum/chemical_reaction/bloody_mary + name = "Bloody Mary" + result = /datum/reagent/ethanol/bloody_mary + required_reagents = list(/datum/reagent/ethanol/vodka = 2, /datum/reagent/drink/juice/tomato = 3, /datum/reagent/drink/juice/lime = 1) + result_amount = 6 + +/datum/chemical_reaction/gargle_blaster + name = "Pan-Galactic Gargle Blaster" + result = /datum/reagent/ethanol/gargle_blaster + required_reagents = list(/datum/reagent/ethanol/vodka = 2, /datum/reagent/ethanol/gin = 1, /datum/reagent/ethanol/whiskey = 1, /datum/reagent/ethanol/cognac = 1, /datum/reagent/drink/juice/lime = 1) + result_amount = 6 + +/datum/chemical_reaction/brave_bull + name = "Brave Bull" + result = /datum/reagent/ethanol/coffee/brave_bull + required_reagents = list(/datum/reagent/ethanol/tequilla = 2, /datum/reagent/ethanol/coffee/kahlua = 1) + result_amount = 3 + +/datum/chemical_reaction/tequilla_sunrise + name = "Tequilla Sunrise" + result = /datum/reagent/ethanol/tequilla_sunrise + required_reagents = list(/datum/reagent/ethanol/tequilla = 2, /datum/reagent/drink/juice/orange = 1) + result_amount = 3 + +/datum/chemical_reaction/phoron_special + name = "Toxins Special" + result = /datum/reagent/ethanol/toxins_special + required_reagents = list(/datum/reagent/ethanol/rum = 2, /datum/reagent/ethanol/vermouth = 2, /datum/reagent/toxin/phoron = 2) + result_amount = 6 + +/datum/chemical_reaction/beepsky_smash + name = "Beepksy Smash" + result = /datum/reagent/ethanol/beepsky_smash + required_reagents = list(/datum/reagent/drink/juice/lime = 1, /datum/reagent/ethanol/whiskey = 1, /datum/reagent/iron = 1) + result_amount = 2 + +/datum/chemical_reaction/doctor_delight + name = "The Doctor's Delight" + result = /datum/reagent/drink/doctor_delight + required_reagents = list(/datum/reagent/drink/juice/lime = 1, /datum/reagent/drink/juice/tomato = 1, /datum/reagent/drink/juice/orange = 1, /datum/reagent/drink/milk/cream = 2, /datum/reagent/tricordrazine = 1) + result_amount = 6 + +/datum/chemical_reaction/irish_cream + name = "Irish Cream" + result = /datum/reagent/ethanol/irish_cream + required_reagents = list(/datum/reagent/ethanol/whiskey = 2, /datum/reagent/drink/milk/cream = 1) + result_amount = 3 + +/datum/chemical_reaction/manly_dorf + name = "The Manly Dorf" + result = /datum/reagent/ethanol/manly_dorf + required_reagents = list (/datum/reagent/ethanol/beer = 1, /datum/reagent/ethanol/ale = 2) + result_amount = 3 + +/datum/chemical_reaction/hooch + name = "Hooch" + result = /datum/reagent/ethanol/hooch + required_reagents = list (/datum/reagent/sugar = 1, /datum/reagent/ethanol = 2, /datum/reagent/fuel = 1) + result_amount = 3 + +/datum/chemical_reaction/irish_coffee + name = "Irish Coffee" + result = /datum/reagent/ethanol/coffee/irishcoffee + required_reagents = list(/datum/reagent/ethanol/irish_cream = 1, /datum/reagent/drink/coffee = 1) + result_amount = 2 + +/datum/chemical_reaction/b52 + name = "B-52" + result = /datum/reagent/ethanol/coffee/b52 + required_reagents = list(/datum/reagent/ethanol/irish_cream = 1, /datum/reagent/ethanol/coffee/kahlua = 1, /datum/reagent/ethanol/cognac = 1) + result_amount = 3 + +/datum/chemical_reaction/atomicbomb + name = "Atomic Bomb" + result = /datum/reagent/ethanol/atomicbomb + required_reagents = list(/datum/reagent/ethanol/coffee/b52 = 10, /datum/reagent/uranium = 1) + result_amount = 10 + +/datum/chemical_reaction/margarita + name = "Margarita" + result = /datum/reagent/ethanol/margarita + required_reagents = list(/datum/reagent/ethanol/tequilla = 2, /datum/reagent/drink/juice/lime = 1) + result_amount = 3 + +/datum/chemical_reaction/longislandicedtea + name = "Long Island Iced Tea" + result = /datum/reagent/ethanol/longislandicedtea + required_reagents = list(/datum/reagent/ethanol/vodka = 1, /datum/reagent/ethanol/gin = 1, /datum/reagent/ethanol/tequilla = 1, /datum/reagent/ethanol/cuba_libre = 3) + result_amount = 6 + +/datum/chemical_reaction/threemileisland + name = "Three Mile Island Iced Tea" + result = /datum/reagent/ethanol/threemileisland + required_reagents = list(/datum/reagent/ethanol/longislandicedtea = 10, /datum/reagent/uranium = 1) + result_amount = 10 + +/datum/chemical_reaction/whiskeysoda + name = "Whiskey Soda" + result = /datum/reagent/ethanol/whiskeysoda + required_reagents = list(/datum/reagent/ethanol/whiskey = 2, /datum/reagent/drink/sodawater = 1) + result_amount = 3 + +/datum/chemical_reaction/black_russian + name = "Black Russian" + result = /datum/reagent/ethanol/black_russian + required_reagents = list(/datum/reagent/ethanol/vodka = 2, /datum/reagent/ethanol/coffee/kahlua = 1) + result_amount = 3 + +/datum/chemical_reaction/manhattan + name = "Manhattan" + result = /datum/reagent/ethanol/manhattan + required_reagents = list(/datum/reagent/ethanol/whiskey = 2, /datum/reagent/ethanol/vermouth = 1) + result_amount = 3 + +/datum/chemical_reaction/manhattan_proj + name = "Manhattan Project" + result = /datum/reagent/ethanol/manhattan_proj + required_reagents = list(/datum/reagent/ethanol/manhattan = 10, /datum/reagent/uranium = 1) + result_amount = 10 + +/datum/chemical_reaction/vodka_tonic + name = "Vodka and Tonic" + result = /datum/reagent/ethanol/vodkatonic + required_reagents = list(/datum/reagent/ethanol/vodka = 2, /datum/reagent/drink/tonic = 1) + result_amount = 3 + +/datum/chemical_reaction/gin_fizz + name = "Gin Fizz" + result = /datum/reagent/ethanol/ginfizz + required_reagents = list(/datum/reagent/ethanol/gin = 1, /datum/reagent/drink/sodawater = 1, /datum/reagent/drink/juice/lime = 1) + result_amount = 3 + +/datum/chemical_reaction/bahama_mama + name = "Bahama mama" + result = /datum/reagent/ethanol/bahama_mama + required_reagents = list(/datum/reagent/ethanol/rum = 2, /datum/reagent/drink/juice/orange = 2, /datum/reagent/drink/juice/lime = 1, /datum/reagent/drink/ice = 1) + result_amount = 6 + +/datum/chemical_reaction/singulo + name = "Singulo" + result = /datum/reagent/ethanol/singulo + required_reagents = list(/datum/reagent/ethanol/vodka = 5, /datum/reagent/radium = 1, /datum/reagent/ethanol/wine = 5) + result_amount = 10 + +/datum/chemical_reaction/alliescocktail + name = "Allies Cocktail" + result = /datum/reagent/ethanol/alliescocktail + required_reagents = list(/datum/reagent/ethanol/vodkamartini = 1, /datum/reagent/ethanol/martini = 1) + result_amount = 2 + +/datum/chemical_reaction/demonsblood + name = "Demons Blood" + result = /datum/reagent/ethanol/demonsblood + required_reagents = list(/datum/reagent/ethanol/rum = 3, /datum/reagent/drink/spacemountainwind = 1, /datum/reagent/blood = 1, /datum/reagent/drink/dr_gibb = 1) + result_amount = 6 + +/datum/chemical_reaction/booger + name = "Booger" + result = /datum/reagent/ethanol/booger + required_reagents = list(/datum/reagent/drink/milk/cream = 2, /datum/reagent/drink/juice/banana = 1, /datum/reagent/ethanol/rum = 1, /datum/reagent/drink/juice/watermelon = 1) + result_amount = 5 + +/datum/chemical_reaction/antifreeze + name = "Anti-freeze" + result = /datum/reagent/ethanol/antifreeze + required_reagents = list(/datum/reagent/ethanol/vodka = 1, /datum/reagent/drink/milk/cream = 1, /datum/reagent/drink/ice = 1) + result_amount = 3 + +/datum/chemical_reaction/barefoot + name = "Barefoot" + result = /datum/reagent/ethanol/barefoot + required_reagents = list(/datum/reagent/drink/juice/berry = 1, /datum/reagent/drink/milk/cream = 1, /datum/reagent/ethanol/vermouth = 1) + result_amount = 3 + +/datum/chemical_reaction/grapesoda + name = "Grape Soda" + result = /datum/reagent/drink/grapesoda + required_reagents = list(/datum/reagent/drink/juice/grape = 2, /datum/reagent/drink/space_cola = 1) + result_amount = 3 + +/datum/chemical_reaction/sbiten + name = "Sbiten" + result = /datum/reagent/ethanol/sbiten + required_reagents = list(/datum/reagent/ethanol/mead = 10, /datum/reagent/capsaicin = 1) + result_amount = 10 + +/datum/chemical_reaction/red_mead + name = "Red Mead" + result = /datum/reagent/ethanol/red_mead + required_reagents = list(/datum/reagent/blood = 1, /datum/reagent/ethanol/mead = 1) + result_amount = 2 + +/datum/chemical_reaction/mead + name = "Mead" + result = /datum/reagent/ethanol/mead + required_reagents = list(/datum/reagent/nutriment/honey = 1, /datum/reagent/water = 1) + catalysts = list(/datum/reagent/enzyme = 5) + result_amount = 2 + +/datum/chemical_reaction/iced_beer + name = "Iced Beer" + result = /datum/reagent/ethanol/iced_beer + required_reagents = list(/datum/reagent/ethanol/beer = 10, /datum/reagent/frostoil = 1) + result_amount = 10 + +/datum/chemical_reaction/iced_beer2 + name = "Iced Beer" + result = /datum/reagent/ethanol/iced_beer + required_reagents = list(/datum/reagent/ethanol/beer = 5, /datum/reagent/drink/ice = 1) + result_amount = 6 + +/datum/chemical_reaction/grog + name = "Grog" + result = /datum/reagent/ethanol/grog + required_reagents = list(/datum/reagent/ethanol/rum = 1, /datum/reagent/water = 1) + result_amount = 2 + +/datum/chemical_reaction/soy_latte + name = "Soy Latte" + result = /datum/reagent/drink/coffee/soy_latte + required_reagents = list(/datum/reagent/drink/coffee = 1, /datum/reagent/drink/milk/soymilk = 1) + result_amount = 2 + +/datum/chemical_reaction/cafe_latte + name = "Cafe Latte" + result = /datum/reagent/drink/coffee/cafe_latte + required_reagents = list(/datum/reagent/drink/coffee = 1, /datum/reagent/drink/milk = 1) + result_amount = 2 + +/datum/chemical_reaction/acidspit + name = "Acid Spit" + result = /datum/reagent/ethanol/acid_spit + required_reagents = list(/datum/reagent/acid = 1, /datum/reagent/ethanol/wine = 5) + result_amount = 6 + +/datum/chemical_reaction/amasec + name = "Amasec" + result = /datum/reagent/ethanol/amasec + required_reagents = list(/datum/reagent/iron = 1, /datum/reagent/ethanol/wine = 5, /datum/reagent/ethanol/vodka = 5) + result_amount = 10 + +/datum/chemical_reaction/changelingsting + name = "Changeling Sting" + result = /datum/reagent/ethanol/changelingsting + required_reagents = list("screwdrivercocktail" = 1, /datum/reagent/drink/juice/lime = 1, /datum/reagent/drink/juice/lemon = 1) + result_amount = 3 + +/datum/chemical_reaction/aloe + name = "Aloe" + result = /datum/reagent/ethanol/aloe + required_reagents = list(/datum/reagent/drink/milk/cream = 1, /datum/reagent/ethanol/whiskey = 1, /datum/reagent/drink/juice/watermelon = 1) + result_amount = 3 + +/datum/chemical_reaction/andalusia + name = "Andalusia" + result = /datum/reagent/ethanol/andalusia + required_reagents = list(/datum/reagent/ethanol/rum = 1, /datum/reagent/ethanol/whiskey = 1, /datum/reagent/drink/juice/lemon = 1) + result_amount = 3 + +/datum/chemical_reaction/neurotoxin + name = "Neurotoxin" + result = /datum/reagent/ethanol/neurotoxin + required_reagents = list(/datum/reagent/ethanol/gargle_blaster = 1, /datum/reagent/soporific = 1) + result_amount = 2 + +/datum/chemical_reaction/snowwhite + name = "Snow White" + result = /datum/reagent/ethanol/snowwhite + required_reagents = list(/datum/reagent/ethanol/beer = 1, /datum/reagent/drink/lemon_lime = 1) + result_amount = 2 + +/datum/chemical_reaction/irishcarbomb + name = "Irish Car Bomb" + result = /datum/reagent/ethanol/irishcarbomb + required_reagents = list(/datum/reagent/ethanol/ale = 1, /datum/reagent/ethanol/irish_cream = 1) + result_amount = 2 + +/datum/chemical_reaction/syndicatebomb + name = "Syndicate Bomb" + result = /datum/reagent/ethanol/syndicatebomb + required_reagents = list(/datum/reagent/ethanol/beer = 1, /datum/reagent/ethanol/whiskey_cola = 1) + result_amount = 2 + +/datum/chemical_reaction/erikasurprise + name = "Erika Surprise" + result = /datum/reagent/ethanol/erikasurprise + required_reagents = list(/datum/reagent/ethanol/ale = 2, /datum/reagent/drink/juice/lime = 1, /datum/reagent/ethanol/whiskey = 1, /datum/reagent/drink/juice/banana = 1, /datum/reagent/drink/ice = 1) + result_amount = 6 + +/datum/chemical_reaction/devilskiss + name = "Devils Kiss" + result = /datum/reagent/ethanol/devilskiss + required_reagents = list(/datum/reagent/blood = 1, /datum/reagent/ethanol/coffee/kahlua = 1, /datum/reagent/ethanol/rum = 1) + result_amount = 3 + +/datum/chemical_reaction/hippiesdelight + name = "Hippies Delight" + result = /datum/reagent/ethanol/hippies_delight + required_reagents = list(/datum/reagent/psilocybin = 1, /datum/reagent/ethanol/gargle_blaster = 1) + result_amount = 2 + +/datum/chemical_reaction/bananahonk + name = "Banana Honk" + result = /datum/reagent/ethanol/bananahonk + required_reagents = list(/datum/reagent/drink/juice/banana = 1, /datum/reagent/drink/milk/cream = 1, /datum/reagent/sugar = 1) + result_amount = 3 + +/datum/chemical_reaction/silencer + name = "Silencer" + result = /datum/reagent/ethanol/silencer + required_reagents = list(/datum/reagent/drink/nothing = 1, /datum/reagent/drink/milk/cream = 1, /datum/reagent/sugar = 1) + result_amount = 3 + +/datum/chemical_reaction/driestmartini + name = "Driest Martini" + result = /datum/reagent/ethanol/driestmartini + required_reagents = list(/datum/reagent/drink/nothing = 1, /datum/reagent/ethanol/gin = 1) + result_amount = 2 + +/datum/chemical_reaction/lemonade + name = "Lemonade" + result = /datum/reagent/drink/lemonade + required_reagents = list(/datum/reagent/drink/juice/lemon = 1, /datum/reagent/sugar = 1, /datum/reagent/water = 1) + result_amount = 3 + +/datum/chemical_reaction/kiraspecial + name = "Kira Special" + result = /datum/reagent/drink/kiraspecial + required_reagents = list(/datum/reagent/drink/juice/orange = 1, /datum/reagent/drink/juice/lime = 1, /datum/reagent/drink/sodawater = 1) + result_amount = 3 + +/datum/chemical_reaction/brownstar + name = "Brown Star" + result = /datum/reagent/drink/brownstar + required_reagents = list(/datum/reagent/drink/juice/orange = 2, /datum/reagent/drink/space_cola = 1) + result_amount = 3 + +/datum/chemical_reaction/milkshake + name = "Milkshake" + result = /datum/reagent/drink/milkshake + required_reagents = list(/datum/reagent/drink/milk/cream = 1, /datum/reagent/drink/ice = 2, /datum/reagent/drink/milk = 2) + result_amount = 5 + +/datum/chemical_reaction/rewriter + name = "Rewriter" + result = /datum/reagent/drink/rewriter + required_reagents = list(/datum/reagent/drink/spacemountainwind = 1, /datum/reagent/drink/coffee = 1) + result_amount = 2 + +/datum/chemical_reaction/suidream + name = "Sui Dream" + result = /datum/reagent/ethanol/suidream + required_reagents = list(/datum/reagent/drink/space_up = 1, /datum/reagent/ethanol/bluecuracao = 1, /datum/reagent/ethanol/melonliquor = 1) + result_amount = 3 + +/datum/chemical_reaction/rum + name = "Rum" + result = /datum/reagent/ethanol/rum + required_reagents = list(/datum/reagent/sugar = 1, /datum/reagent/water = 1) + catalysts = list(/datum/reagent/enzyme = 5) + result_amount = 2 + +/datum/chemical_reaction/ships_surgeon + name = "Ship's Surgeon" + result = /datum/reagent/ethanol/ships_surgeon + required_reagents = list(/datum/reagent/ethanol/rum = 1, /datum/reagent/drink/dr_gibb = 2, /datum/reagent/drink/ice = 1) + result_amount = 4 + +/datum/chemical_reaction/luminol + name = "Luminol" + result = /datum/reagent/luminol + required_reagents = list(/datum/reagent/hydrazine = 2, /datum/reagent/carbon = 2, /datum/reagent/ammonia = 2) + result_amount = 6 + +/datum/chemical_reaction/oxyphoron + name = "Oxyphoron" + result = /datum/reagent/toxin/phoron/oxygen + required_reagents = list(/datum/reagent/water = 1, /datum/reagent/toxin/phoron = 1) + result_amount = 2 + +/datum/chemical_reaction/deuterium + name = "Deuterium" + result = null + required_reagents = list(/datum/reagent/water = 10) + catalysts = list(/datum/reagent/toxin/phoron/oxygen = 5) + result_amount = 1 + +/datum/chemical_reaction/deuterium/on_reaction(var/datum/reagents/holder, var/created_volume) + var/turf/T = get_turf(holder.my_atom) + if(istype(T)) new /obj/item/stack/material/deuterium(T, created_volume) + return + +/datum/chemical_reaction/antidexafen + name = "Antidexafen" + result = /datum/reagent/antidexafen + required_reagents = list(/datum/reagent/paracetamol = 1, /datum/reagent/carbon = 1) + result_amount = 2 + +/datum/chemical_reaction/nanoblood + name = "Nanoblood" + result = /datum/reagent/nanoblood + required_reagents = list(/datum/reagent/dexalinp = 1, /datum/reagent/iron = 1, /datum/reagent/blood = 1) + result_amount = 3 diff --git a/code/modules/reagents/dispenser/_defines.dm b/code/modules/reagents/dispenser/_defines.dm new file mode 100644 index 00000000..8d52cf5c --- /dev/null +++ b/code/modules/reagents/dispenser/_defines.dm @@ -0,0 +1,8 @@ +#define CARTRIDGE_VOLUME_LARGE 500 +#define CARTRIDGE_VOLUME_MEDIUM 250 +#define CARTRIDGE_VOLUME_SMALL 100 + +// Chemistry dispenser starts with 21 +// ERT dispenser starts with 28 +#define DISPENSER_MAX_CARTRIDGES 30 + diff --git a/code/modules/reagents/dispenser/cartridge.dm b/code/modules/reagents/dispenser/cartridge.dm new file mode 100644 index 00000000..f76a2366 --- /dev/null +++ b/code/modules/reagents/dispenser/cartridge.dm @@ -0,0 +1,95 @@ +/obj/item/weapon/reagent_containers/chem_disp_cartridge + name = "chemical dispenser cartridge" + desc = "This goes in a chemical dispenser." + icon_state = "cartridge" + + w_class = ITEM_SIZE_NORMAL + + volume = CARTRIDGE_VOLUME_LARGE + amount_per_transfer_from_this = 50 + // Large, but inaccurate. Use a chem dispenser or beaker for accuracy. + possible_transfer_amounts = "50;100" + unacidable = 1 + + var/spawn_reagent = null + var/label = "" + +/obj/item/weapon/reagent_containers/chem_disp_cartridge/New() + . = ..() + if(spawn_reagent) + reagents.add_reagent(spawn_reagent, volume) + var/datum/reagent/R = spawn_reagent + setLabel(initial(R.name)) + +/obj/item/weapon/reagent_containers/chem_disp_cartridge/examine(mob/user) + . = ..() + to_chat(user, "It has a capacity of [volume] units.") + if(reagents.total_volume <= 0) + to_chat(user, "It is empty.") + else + to_chat(user, "It contains [reagents.total_volume] units of liquid.") + if(!is_open_container()) + to_chat(user, "The cap is sealed.") + +/obj/item/weapon/reagent_containers/chem_disp_cartridge/verb/verb_set_label(L as text) + set name = "Set Cartridge Label" + set category = "Object" + set src in view(usr, 1) + + setLabel(L, usr) + +/obj/item/weapon/reagent_containers/chem_disp_cartridge/proc/setLabel(L, mob/user = null) + if(L) + if(user) + to_chat(user, "You set the label on \the [src] to '[L]'.") + + label = L + SetName("[initial(name)] - '[L]'") + else + if(user) + to_chat(user, "You clear the label on \the [src].") + label = "" + SetName(initial(name)) + +/obj/item/weapon/reagent_containers/chem_disp_cartridge/attack_self() + ..() + if (is_open_container()) + to_chat(usr, "You put the cap on \the [src].") + atom_flags ^= ATOM_FLAG_OPEN_CONTAINER + else + to_chat(usr, "You take the cap off \the [src].") + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + +/obj/item/weapon/reagent_containers/chem_disp_cartridge/afterattack(obj/target, mob/user , flag) + if (!is_open_container() || !flag) + return + + else if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us. + target.add_fingerprint(user) + + if(!target.reagents.total_volume && target.reagents) + to_chat(user, "\The [target] is empty.") + return + + if(reagents.total_volume >= reagents.maximum_volume) + to_chat(user, "\The [src] is full.") + return + + var/trans = target.reagents.trans_to(src, target:amount_per_transfer_from_this) + to_chat(user, "You fill \the [src] with [trans] units of the contents of \the [target].") + + else if(target.is_open_container() && target.reagents) //Something like a glass. Player probably wants to transfer TO it. + + if(!reagents.total_volume) + to_chat(user, "\The [src] is empty.") + return + + if(target.reagents.total_volume >= target.reagents.maximum_volume) + to_chat(user, "\The [target] is full.") + return + + var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this) + to_chat(user, "You transfer [trans] units of the solution to \the [target].") + + else + return ..() diff --git a/code/modules/reagents/dispenser/cartridge_presets.dm b/code/modules/reagents/dispenser/cartridge_presets.dm new file mode 100644 index 00000000..f597706f --- /dev/null +++ b/code/modules/reagents/dispenser/cartridge_presets.dm @@ -0,0 +1,99 @@ +/obj/item/weapon/reagent_containers/chem_disp_cartridge + small + volume = CARTRIDGE_VOLUME_SMALL + + medium + volume = CARTRIDGE_VOLUME_MEDIUM + + // Multiple + water spawn_reagent = /datum/reagent/water + sugar spawn_reagent = /datum/reagent/sugar + + // Chemistry + hydrazine spawn_reagent = /datum/reagent/hydrazine + lithium spawn_reagent = /datum/reagent/lithium + carbon spawn_reagent = /datum/reagent/carbon + ammonia spawn_reagent = /datum/reagent/ammonia + acetone spawn_reagent = /datum/reagent/acetone + sodium spawn_reagent = /datum/reagent/sodium + aluminum spawn_reagent = /datum/reagent/aluminum + silicon spawn_reagent = /datum/reagent/silicon + phosphorus spawn_reagent = /datum/reagent/phosphorus + sulfur spawn_reagent = /datum/reagent/sulfur + hclacid spawn_reagent = /datum/reagent/acid/hydrochloric + potassium spawn_reagent = /datum/reagent/potassium + iron spawn_reagent = /datum/reagent/iron + copper spawn_reagent = /datum/reagent/copper + mercury spawn_reagent = /datum/reagent/mercury + radium spawn_reagent = /datum/reagent/radium + ethanol spawn_reagent = /datum/reagent/ethanol + sacid spawn_reagent = /datum/reagent/acid + tungsten spawn_reagent = /datum/reagent/tungsten + + // Bar, alcoholic + beer spawn_reagent = /datum/reagent/ethanol/beer + kahlua spawn_reagent = /datum/reagent/ethanol/coffee/kahlua + whiskey spawn_reagent = /datum/reagent/ethanol/whiskey + wine spawn_reagent = /datum/reagent/ethanol/wine + vodka spawn_reagent = /datum/reagent/ethanol/vodka + gin spawn_reagent = /datum/reagent/ethanol/gin + rum spawn_reagent = /datum/reagent/ethanol/rum + tequila spawn_reagent = /datum/reagent/ethanol/tequilla + vermouth spawn_reagent = /datum/reagent/ethanol/vermouth + cognac spawn_reagent = /datum/reagent/ethanol/cognac + ale spawn_reagent = /datum/reagent/ethanol/ale + mead spawn_reagent = /datum/reagent/ethanol/mead + + // Bar, soft + ice spawn_reagent = /datum/reagent/drink/ice + tea spawn_reagent = /datum/reagent/drink/tea + icetea spawn_reagent = /datum/reagent/drink/tea/icetea + cola spawn_reagent = /datum/reagent/drink/space_cola + smw spawn_reagent = /datum/reagent/drink/spacemountainwind + dr_gibb spawn_reagent = /datum/reagent/drink/dr_gibb + spaceup spawn_reagent = /datum/reagent/drink/space_up + tonic spawn_reagent = /datum/reagent/drink/tonic + sodawater spawn_reagent = /datum/reagent/drink/sodawater + lemon_lime spawn_reagent = /datum/reagent/drink/lemon_lime + orange spawn_reagent = /datum/reagent/drink/juice/orange + lime spawn_reagent = /datum/reagent/drink/juice/lime + watermelon spawn_reagent = /datum/reagent/drink/juice/watermelon + + // Bar, coffee + coffee spawn_reagent = /datum/reagent/drink/coffee + cafe_latte spawn_reagent = /datum/reagent/drink/coffee/cafe_latte + soy_latte spawn_reagent = /datum/reagent/drink/coffee/soy_latte + hot_coco spawn_reagent = /datum/reagent/drink/hot_coco + milk spawn_reagent = /datum/reagent/drink/milk + cream spawn_reagent = /datum/reagent/drink/milk/cream + + // ERT + inaprov spawn_reagent = /datum/reagent/inaprovaline + ryetalyn spawn_reagent = /datum/reagent/ryetalyn + paracetamol spawn_reagent = /datum/reagent/paracetamol + tramadol spawn_reagent = /datum/reagent/tramadol + oxycodone spawn_reagent = /datum/reagent/tramadol/oxycodone + sterilizine spawn_reagent = /datum/reagent/sterilizine + leporazine spawn_reagent = /datum/reagent/leporazine + kelotane spawn_reagent = /datum/reagent/kelotane + dermaline spawn_reagent = /datum/reagent/dermaline + dexalin spawn_reagent = /datum/reagent/dexalin + dexalin/small volume = CARTRIDGE_VOLUME_SMALL // For the medicine cartridge crate, so it's not too easy to get large amounts of dexalin + dexalin_p spawn_reagent = /datum/reagent/dexalinp + tricord spawn_reagent = /datum/reagent/tricordrazine + dylovene spawn_reagent = /datum/reagent/dylovene + synaptizine spawn_reagent = /datum/reagent/synaptizine + hyronalin spawn_reagent = /datum/reagent/hyronalin + arithrazine spawn_reagent = /datum/reagent/arithrazine + alkysine spawn_reagent = /datum/reagent/alkysine + imidazoline spawn_reagent = /datum/reagent/imidazoline + peridaxon spawn_reagent = /datum/reagent/peridaxon + bicaridine spawn_reagent = /datum/reagent/bicaridine + hyperzine spawn_reagent = /datum/reagent/hyperzine + rezadone spawn_reagent = /datum/reagent/rezadone + spaceacillin spawn_reagent = /datum/reagent/spaceacillin + ethylredox spawn_reagent = /datum/reagent/ethylredoxrazine + sleeptox spawn_reagent = /datum/reagent/soporific + chloral spawn_reagent = /datum/reagent/chloralhydrate + cryoxadone spawn_reagent = /datum/reagent/cryoxadone + clonexadone spawn_reagent = /datum/reagent/clonexadone diff --git a/code/modules/reagents/dispenser/cartridge_spawn.dm b/code/modules/reagents/dispenser/cartridge_spawn.dm new file mode 100644 index 00000000..4e8e5480 --- /dev/null +++ b/code/modules/reagents/dispenser/cartridge_spawn.dm @@ -0,0 +1,13 @@ +/client/proc/spawn_chemdisp_cartridge(size in list("small", "medium", "large"), reagent in subtypesof(/datum/reagent)) + set name = "Spawn Chemical Dispenser Cartridge" + set category = "Admin" + + var/obj/item/weapon/reagent_containers/chem_disp_cartridge/C + switch(size) + if("small") C = new /obj/item/weapon/reagent_containers/chem_disp_cartridge/small(usr.loc) + if("medium") C = new /obj/item/weapon/reagent_containers/chem_disp_cartridge/medium(usr.loc) + if("large") C = new /obj/item/weapon/reagent_containers/chem_disp_cartridge(usr.loc) + C.reagents.add_reagent(reagent, C.volume) + var/datum/reagent/R = reagent + C.setLabel(initial(R.name)) + log_and_message_admins("spawned a [size] reagent container containing [reagent]") diff --git a/code/modules/reagents/dispenser/dispenser2.dm b/code/modules/reagents/dispenser/dispenser2.dm new file mode 100644 index 00000000..45385aa9 --- /dev/null +++ b/code/modules/reagents/dispenser/dispenser2.dm @@ -0,0 +1,179 @@ +/obj/machinery/chemical_dispenser + name = "chemical dispenser" + icon = 'icons/obj/chemical.dmi' + icon_state = "dispenser" + clicksound = "button" + clickvol = 20 + + var/list/spawn_cartridges = null // Set to a list of types to spawn one of each on New() + + var/list/cartridges = list() // Associative, label -> cartridge + var/obj/item/weapon/reagent_containers/container = null + + var/ui_title = "Chemical Dispenser" + + var/accept_drinking = 0 + var/amount = 30 + + use_power = 1 + idle_power_usage = 100 + density = 1 + anchored = 1 + obj_flags = OBJ_FLAG_ANCHORABLE + +/obj/machinery/chemical_dispenser/New() + ..() + + if(spawn_cartridges) + for(var/type in spawn_cartridges) + add_cartridge(new type(src)) + +/obj/machinery/chemical_dispenser/examine(mob/user) + . = ..() + to_chat(user, "It has [cartridges.len] cartridges installed, and has space for [DISPENSER_MAX_CARTRIDGES - cartridges.len] more.") + +/obj/machinery/chemical_dispenser/proc/add_cartridge(obj/item/weapon/reagent_containers/chem_disp_cartridge/C, mob/user) + if(!istype(C)) + if(user) + to_chat(user, "\The [C] will not fit in \the [src]!") + return + + if(cartridges.len >= DISPENSER_MAX_CARTRIDGES) + if(user) + to_chat(user, "\The [src] does not have any slots open for \the [C] to fit into!") + return + + if(!C.label) + if(user) + to_chat(user, "\The [C] does not have a label!") + return + + if(cartridges[C.label]) + if(user) + to_chat(user, "\The [src] already contains a cartridge with that label!") + return + + if(user) + user.drop_from_inventory(C) + to_chat(user, "You add \the [C] to \the [src].") + + C.loc = src + cartridges[C.label] = C + cartridges = sortAssoc(cartridges) + GLOB.nanomanager.update_uis(src) + +/obj/machinery/chemical_dispenser/proc/remove_cartridge(label) + . = cartridges[label] + cartridges -= label + GLOB.nanomanager.update_uis(src) + +/obj/machinery/chemical_dispenser/attackby(obj/item/weapon/W, mob/user) + if(istype(W, /obj/item/weapon/reagent_containers/chem_disp_cartridge)) + add_cartridge(W, user) + + else if(isScrewdriver(W)) + var/label = input(user, "Which cartridge would you like to remove?", "Chemical Dispenser") as null|anything in cartridges + if(!label) return + var/obj/item/weapon/reagent_containers/chem_disp_cartridge/C = remove_cartridge(label) + if(C) + to_chat(user, "You remove \the [C] from \the [src].") + C.loc = loc + + else if(istype(W, /obj/item/weapon/reagent_containers/glass) || istype(W, /obj/item/weapon/reagent_containers/food)) + if(container) + to_chat(user, "There is already \a [container] on \the [src]!") + return + + var/obj/item/weapon/reagent_containers/RC = W + + if(!accept_drinking && istype(RC,/obj/item/weapon/reagent_containers/food)) + to_chat(user, "This machine only accepts beakers!") + return + + if(!RC.is_open_container()) + to_chat(user, "You don't see how \the [src] could dispense reagents into \the [RC].") + return + + if(RC.w_class >= ITEM_SIZE_NORMAL) + to_chat(user, "This container is too big for this machine!") + return + + container = RC + user.drop_from_inventory(RC) + RC.loc = src + update_icon() + to_chat(user, "You set \the [RC] on \the [src].") + GLOB.nanomanager.update_uis(src) // update all UIs attached to src + + else + ..() + return + +/obj/machinery/chemical_dispenser/ui_interact(mob/user, ui_key = "main",var/datum/nanoui/ui = null, var/force_open = 1) + // this is the data which will be sent to the ui + var/data[0] + data["amount"] = amount + data["isBeakerLoaded"] = container ? 1 : 0 + data["glass"] = accept_drinking + var beakerD[0] + if(container && container.reagents && container.reagents.reagent_list.len) + for(var/datum/reagent/R in container.reagents.reagent_list) + beakerD[++beakerD.len] = list("name" = R.name, "volume" = R.volume) + data["beakerContents"] = beakerD + + if(container) + data["beakerCurrentVolume"] = container.reagents.total_volume + data["beakerMaxVolume"] = container.reagents.maximum_volume + else + data["beakerCurrentVolume"] = null + data["beakerMaxVolume"] = null + + var chemicals[0] + for(var/label in cartridges) + var/obj/item/weapon/reagent_containers/chem_disp_cartridge/C = cartridges[label] + chemicals[++chemicals.len] = list("label" = label, "amount" = C.reagents.total_volume) + data["chemicals"] = chemicals + + // update the ui if it exists, returns null if no ui is passed/found + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "chem_disp.tmpl", ui_title, 390, 680) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/chemical_dispenser/OnTopic(user, href_list) + if(href_list["amount"]) + amount = round(text2num(href_list["amount"]), 1) // round to nearest 1 + amount = max(0, min(120, amount)) // Since the user can actually type the commands himself, some sanity checking + return TOPIC_REFRESH + + if(href_list["dispense"]) + var/label = href_list["dispense"] + if(cartridges[label] && container && container.is_open_container()) + var/obj/item/weapon/reagent_containers/chem_disp_cartridge/C = cartridges[label] + C.reagents.trans_to(container, amount) + return TOPIC_REFRESH + return TOPIC_HANDLED + + else if(href_list["ejectBeaker"]) + if(container) + var/obj/item/weapon/reagent_containers/B = container + B.dropInto(loc) + container = null + update_icon() + return TOPIC_REFRESH + return TOPIC_HANDLED + +/obj/machinery/chemical_dispenser/attack_ai(mob/user as mob) + ui_interact(user) + +/obj/machinery/chemical_dispenser/attack_hand(mob/user as mob) + ui_interact(user) + +/obj/machinery/chemical_dispenser/update_icon() + overlays.Cut() + if(container) + var/mutable_appearance/beaker_overlay + beaker_overlay = image('icons/obj/chemical.dmi', src, "lil_beaker") + beaker_overlay.pixel_x = rand(-10, 5) + overlays += beaker_overlay diff --git a/code/modules/reagents/dispenser/dispenser_presets.dm b/code/modules/reagents/dispenser/dispenser_presets.dm new file mode 100644 index 00000000..2dbd6755 --- /dev/null +++ b/code/modules/reagents/dispenser/dispenser_presets.dm @@ -0,0 +1,133 @@ +/obj/machinery/chemical_dispenser/full + spawn_cartridges = list( + /obj/item/weapon/reagent_containers/chem_disp_cartridge/hydrazine, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/lithium, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/carbon, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/ammonia, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/acetone, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodium, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/aluminum, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/silicon, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/phosphorus, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/sulfur, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/hclacid, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/potassium, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/iron, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/copper, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/mercury, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/radium, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/water, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/ethanol, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/sacid, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/tungsten + ) + +/obj/machinery/chemical_dispenser/ert + name = "medicine dispenser" + spawn_cartridges = list( + /obj/item/weapon/reagent_containers/chem_disp_cartridge/inaprov, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/ryetalyn, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/paracetamol, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/tramadol, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/oxycodone, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/sterilizine, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/leporazine, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/kelotane, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/dermaline, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/dexalin, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/dexalin_p, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/tricord, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/dylovene, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/synaptizine, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/hyronalin, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/arithrazine, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/alkysine, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/imidazoline, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/peridaxon, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/bicaridine, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/hyperzine, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/rezadone, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/spaceacillin, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/ethylredox, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/sleeptox, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/chloral, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/cryoxadone, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/clonexadone + ) + +/obj/machinery/chemical_dispenser/bar_soft + name = "soft drink dispenser" + desc = "A soft drink machine." //Doesn't just serve soda --BlueNexus + icon_state = "soda_dispenser" + ui_title = "Soda Dispenser" + accept_drinking = 1 + +/obj/machinery/chemical_dispenser/bar_soft/full + spawn_cartridges = list( + /obj/item/weapon/reagent_containers/chem_disp_cartridge/water, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/cream, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/tea, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/icetea, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/cola, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/smw, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/dr_gibb, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/spaceup, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/tonic, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodawater, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon_lime, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/orange, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/lime, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/watermelon + ) + +/obj/machinery/chemical_dispenser/bar_alc + name = "booze dispenser" + desc = "A beer machine. Like a soda machine, but more fun!" + icon_state = "booze_dispenser" + ui_title = "Booze Dispenser" + accept_drinking = 1 + +/obj/machinery/chemical_dispenser/bar_alc/full + spawn_cartridges = list( + /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon_lime, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/orange, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/lime, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodawater, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/tonic, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/beer, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/kahlua, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/whiskey, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/wine, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/vodka, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/gin, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/rum, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/tequila, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/vermouth, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/cognac, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/ale, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/mead + ) + +/obj/machinery/chemical_dispenser/bar_coffee + name = "coffee dispenser" + desc = "Driving crack dealers out of employment since 2280." + icon_state = "coffee_dispenser" + ui_title = "Coffee Dispenser" + accept_drinking = 1 + +/obj/machinery/chemical_dispenser/bar_coffee/full + spawn_cartridges = list( + /obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/cafe_latte, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/soy_latte, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/hot_coco, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/milk, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/cream, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/tea, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice + ) \ No newline at end of file diff --git a/code/modules/reagents/dispenser/supply.dm b/code/modules/reagents/dispenser/supply.dm new file mode 100644 index 00000000..a2b22a78 --- /dev/null +++ b/code/modules/reagents/dispenser/supply.dm @@ -0,0 +1,166 @@ +/decl/hierarchy/supply_pack/reagents + name = "Reagents" + +/decl/hierarchy/supply_pack/reagents/beer_dispenser + name = "Booze dispenser" + contains = list( + /obj/machinery/chemical_dispenser/bar_alc{anchored = 0} + ) + cost = 25 + containertype = /obj/structure/largecrate + containername = "booze dispenser crate" + +/decl/hierarchy/supply_pack/reagents/soda_dispenser + name = "Soda dispenser" + contains = list( + /obj/machinery/chemical_dispenser/bar_soft{anchored = 0} + ) + cost = 25 + containertype = /obj/structure/largecrate + containername = "soda dispenser crate" + +/decl/hierarchy/supply_pack/reagents/alcohol_reagents + name = "Bar alcoholic dispenser refill" + contains = list( + /obj/item/weapon/reagent_containers/chem_disp_cartridge/beer, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/kahlua, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/whiskey, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/wine, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/vodka, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/gin, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/rum, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/tequila, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/vermouth, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/cognac, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/ale, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/mead + ) + cost = 50 + containertype = /obj/structure/closet/crate/secure + containername = "alcoholic drinks crate" + access = list(access_bar) + +/decl/hierarchy/supply_pack/reagents/softdrink_reagents + name = "Bar soft drink dispenser refill" + contains = list( + /obj/item/weapon/reagent_containers/chem_disp_cartridge/water, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/cream, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/tea, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/icetea, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/cola, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/smw, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/dr_gibb, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/spaceup, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/tonic, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodawater, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon_lime, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/orange, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/lime, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/watermelon + ) + cost = 50 + containertype = /obj/structure/closet/crate + containername = "soft drinks crate" + +/decl/hierarchy/supply_pack/reagents/coffee_reagents + name = "Coffee machine dispenser refill" + contains = list( + /obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/cafe_latte, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/soy_latte, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/hot_coco, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/milk, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/cream, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/tea, + /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice + ) + cost = 50 + containertype = /obj/structure/closet/crate + containername = "coffee drinks crate" + +/* +/decl/hierarchy/supply_pack/reagents/dispenser_cartridges + name = "Empty dispenser cartridges" + contains = list( + /obj/item/weapon/reagent_containers/chem_disp_cartridge, + /obj/item/weapon/reagent_containers/chem_disp_cartridge, + /obj/item/weapon/reagent_containers/chem_disp_cartridge, + /obj/item/weapon/reagent_containers/chem_disp_cartridge, + /obj/item/weapon/reagent_containers/chem_disp_cartridge, + /obj/item/weapon/reagent_containers/chem_disp_cartridge, + /obj/item/weapon/reagent_containers/chem_disp_cartridge, + /obj/item/weapon/reagent_containers/chem_disp_cartridge, + /obj/item/weapon/reagent_containers/chem_disp_cartridge, + /obj/item/weapon/reagent_containers/chem_disp_cartridge + ) + cost = 15 + containertype = /obj/structure/closet/crate + containername = "dispenser cartridge crate" +*/ + +/decl/hierarchy/supply_pack/dispenser_cartridges + name = "Dispenser Cartridges" + +#define SEC_PACK(_tname, _type, _name, _cname, _cost, _access)\ + decl/hierarchy/supply_pack/dispenser_cartridges{\ + _tname {\ + name = _name ;\ + containername = _cname ;\ + containertype = /obj/structure/closet/crate/secure;\ + access = list( _access );\ + cost = _cost ;\ + contains = list( _type , _type );\ + }\ + } +#define PACK(_tname, _type, _name, _cname, _cost)\ + decl/hierarchy/supply_pack/dispenser_cartridges{\ + _tname {\ + name = _name ;\ + containername = _cname ;\ + containertype = /obj/structure/closet/crate;\ + cost = _cost ;\ + contains = list( _type , _type );\ + }\ + } + +// Bar-restricted (alcoholic drinks) +// Datum path Contents type Supply pack name Container name Cost Container access +SEC_PACK(beer, /obj/item/weapon/reagent_containers/chem_disp_cartridge/beer, "Reagent refill - Beer", "beer reagent cartridge crate", 15, access_bar) +SEC_PACK(kahlua, /obj/item/weapon/reagent_containers/chem_disp_cartridge/kahlua, "Reagent refill - Kahlua", "kahlua reagent cartridge crate", 15, access_bar) +SEC_PACK(whiskey, /obj/item/weapon/reagent_containers/chem_disp_cartridge/whiskey, "Reagent refill - Whiskey", "whiskey reagent cartridge crate", 15, access_bar) +SEC_PACK(wine, /obj/item/weapon/reagent_containers/chem_disp_cartridge/wine, "Reagent refill - Wine", "wine reagent cartridge crate", 15, access_bar) +SEC_PACK(vodka, /obj/item/weapon/reagent_containers/chem_disp_cartridge/vodka, "Reagent refill - Vodka", "vodka reagent cartridge crate", 15, access_bar) +SEC_PACK(gin, /obj/item/weapon/reagent_containers/chem_disp_cartridge/gin, "Reagent refill - Gin", "gin reagent cartridge crate", 15, access_bar) +SEC_PACK(rum, /obj/item/weapon/reagent_containers/chem_disp_cartridge/rum, "Reagent refill - Rum", "rum reagent cartridge crate", 15, access_bar) +SEC_PACK(tequila, /obj/item/weapon/reagent_containers/chem_disp_cartridge/tequila, "Reagent refill - Tequila", "tequila reagent cartridge crate", 15, access_bar) +SEC_PACK(vermouth, /obj/item/weapon/reagent_containers/chem_disp_cartridge/vermouth, "Reagent refill - Vermouth", "vermouth reagent cartridge crate", 15, access_bar) +SEC_PACK(cognac, /obj/item/weapon/reagent_containers/chem_disp_cartridge/cognac, "Reagent refill - Cognac", "cognac reagent cartridge crate", 15, access_bar) +SEC_PACK(ale, /obj/item/weapon/reagent_containers/chem_disp_cartridge/ale, "Reagent refill - Ale", "ale reagent cartridge crate", 15, access_bar) +SEC_PACK(mead, /obj/item/weapon/reagent_containers/chem_disp_cartridge/mead, "Reagent refill - Mead", "mead reagent cartridge crate", 15, access_bar) + +// Unrestricted (water, sugar, non-alcoholic drinks) +// Datum path Contents type Supply pack name Container name Cost +PACK(water, /obj/item/weapon/reagent_containers/chem_disp_cartridge/water, "Reagent refill - Water", "water reagent cartridge crate", 15) +PACK(sugar, /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar, "Reagent refill - Sugar", "sugar reagent cartridge crate", 15) +PACK(ice, /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice, "Reagent refill - Ice", "ice reagent cartridge crate", 15) +PACK(tea, /obj/item/weapon/reagent_containers/chem_disp_cartridge/tea, "Reagent refill - Tea", "tea reagent cartridge crate", 15) +PACK(icetea, /obj/item/weapon/reagent_containers/chem_disp_cartridge/icetea, "Reagent refill - Iced Tea", "iced tea reagent cartridge crate", 15) +PACK(cola, /obj/item/weapon/reagent_containers/chem_disp_cartridge/cola, "Reagent refill - Space Cola", "\improper Space Cola reagent cartridge crate", 15) +PACK(smw, /obj/item/weapon/reagent_containers/chem_disp_cartridge/smw, "Reagent refill - Space Mountain Wind", "\improper Space Mountain Wind reagent cartridge crate", 15) +PACK(dr_gibb, /obj/item/weapon/reagent_containers/chem_disp_cartridge/dr_gibb, "Reagent refill - Dr. Gibb", "\improper Dr. Gibb reagent cartridge crate", 15) +PACK(spaceup, /obj/item/weapon/reagent_containers/chem_disp_cartridge/spaceup, "Reagent refill - Space-Up", "\improper Space-Up reagent cartridge crate", 15) +PACK(tonic, /obj/item/weapon/reagent_containers/chem_disp_cartridge/tonic, "Reagent refill - Tonic Water", "tonic water reagent cartridge crate", 15) +PACK(sodawater, /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodawater, "Reagent refill - Soda Water", "soda water reagent cartridge crate", 15) +PACK(lemon_lime, /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon_lime, "Reagent refill - Lemon-Lime Juice", "lemon-lime juice reagent cartridge crate", 15) +PACK(orange, /obj/item/weapon/reagent_containers/chem_disp_cartridge/orange, "Reagent refill - Orange Juice", "orange juice reagent cartridge crate", 15) +PACK(lime, /obj/item/weapon/reagent_containers/chem_disp_cartridge/lime, "Reagent refill - Lime Juice", "lime juice reagent cartridge crate", 15) +PACK(watermelon, /obj/item/weapon/reagent_containers/chem_disp_cartridge/watermelon, "Reagent refill - Watermelon Juice", "watermelon juice reagent cartridge crate", 15) +PACK(coffee, /obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee, "Reagent refill - Coffee", "coffee reagent cartridge crate", 15) +PACK(cafe_latte, /obj/item/weapon/reagent_containers/chem_disp_cartridge/cafe_latte, "Reagent refill - Cafe Latte", "cafe latte reagent cartridge crate", 15) +PACK(soy_latte, /obj/item/weapon/reagent_containers/chem_disp_cartridge/soy_latte, "Reagent refill - Soy Latte", "soy latte reagent cartridge crate", 15) +PACK(hot_coco, /obj/item/weapon/reagent_containers/chem_disp_cartridge/hot_coco, "Reagent refill - Hot Coco", "hot coco reagent cartridge crate", 15) +PACK(milk, /obj/item/weapon/reagent_containers/chem_disp_cartridge/milk, "Reagent refill - Milk", "milk reagent cartridge crate", 15) +PACK(cream, /obj/item/weapon/reagent_containers/chem_disp_cartridge/cream, "Reagent refill - Cream", "cream reagent cartridge crate", 15) diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm new file mode 100644 index 00000000..ce56ed54 --- /dev/null +++ b/code/modules/reagents/reagent_containers.dm @@ -0,0 +1,200 @@ +/obj/item/weapon/reagent_containers + name = "Container" + desc = "..." + icon = 'icons/obj/chemical.dmi' + icon_state = null + w_class = ITEM_SIZE_SMALL + var/amount_per_transfer_from_this = 5 + var/possible_transfer_amounts = "5;10;15;25;30" + var/volume = 30 + var/label_text + +/obj/item/weapon/reagent_containers/verb/set_APTFT() //set amount_per_transfer_from_this + set name = "Set transfer amount" + set category = "Object" + set src in range(0) + var/N = input("Amount per transfer from this:","[src]") as null|anything in cached_number_list_decode(possible_transfer_amounts) + if(N) + amount_per_transfer_from_this = N + +/obj/item/weapon/reagent_containers/New() + ..() + if(!possible_transfer_amounts) + src.verbs -= /obj/item/weapon/reagent_containers/verb/set_APTFT + create_reagents(volume) + +/obj/item/weapon/reagent_containers/attack_self(mob/user as mob) + return + +/obj/item/weapon/reagent_containers/afterattack(obj/target, mob/user, flag) + return + +/obj/item/weapon/reagent_containers/proc/reagentlist() // For attack logs + if(reagents) + return reagents.get_reagents() + return "No reagent holder" + +/obj/item/weapon/reagent_containers/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/pen) || istype(W, /obj/item/device/flashlight/pen)) + var/tmp_label = sanitizeSafe(input(user, "Enter a label for [name]", "Label", label_text), MAX_NAME_LEN) + if(length(tmp_label) > 10) + to_chat(user, "The label can be at most 10 characters long.") + else + to_chat(user, "You set the label to \"[tmp_label]\".") + label_text = tmp_label + update_name_label() + else + return ..() + +/obj/item/weapon/reagent_containers/proc/update_name_label() + if(label_text == "") + SetName(initial(name)) + else + SetName("[initial(name)] ([label_text])") + +/obj/item/weapon/reagent_containers/proc/standard_dispenser_refill(var/mob/user, var/obj/structure/reagent_dispensers/target) // This goes into afterattack + if(!istype(target)) + return 0 + + if(!target.reagents || !target.reagents.total_volume) + to_chat(user, "[target] is empty.") + return 1 + + if(reagents && !reagents.get_free_space()) + to_chat(user, "[src] is full.") + return 1 + + var/trans = target.reagents.trans_to_obj(src, target:amount_per_transfer_from_this) + to_chat(user, "You fill [src] with [trans] units of the contents of [target].") + return 1 + +/obj/item/weapon/reagent_containers/proc/standard_splash_mob(var/mob/user, var/mob/target) // This goes into afterattack + if(!istype(target)) + return + + if(user.a_intent == I_HELP) + to_chat(user, "You can't splash people on help intent.") + return 1 + + if(!reagents || !reagents.total_volume) + to_chat(user, "[src] is empty.") + return 1 + + if(target.reagents && !target.reagents.get_free_space()) + to_chat(user, "[target] is full.") + return 1 + + var/contained = reagentlist() + admin_attack_log(user, target, "Used \the [name] containing [contained] to splash the victim.", "Was splashed by \the [name] containing [contained].", "used \the [name] containing [contained] to splash") + + user.visible_message("[target] has been splashed with something by [user]!", "You splash the solution onto [target].") + reagents.splash(target, reagents.total_volume) + return 1 + +/obj/item/weapon/reagent_containers/proc/self_feed_message(var/mob/user) + to_chat(user, "You eat \the [src]") + +/obj/item/weapon/reagent_containers/proc/other_feed_message_start(var/mob/user, var/mob/target) + user.visible_message("[user] is trying to feed [target] \the [src]!") + +/obj/item/weapon/reagent_containers/proc/other_feed_message_finish(var/mob/user, var/mob/target) + user.visible_message("[user] has fed [target] \the [src]!") + +/obj/item/weapon/reagent_containers/proc/feed_sound(var/mob/user) + return + +/obj/item/weapon/reagent_containers/proc/standard_feed_mob(var/mob/user, var/mob/target) // This goes into attack + if(!istype(target)) + return 0 + + if(!reagents || !reagents.total_volume) + to_chat(user, "\The [src] is empty.") + return 1 + + // only carbons can eat + if(istype(target, /mob/living/carbon)) + if(target == user) + var/mob/living/carbon/C = user + if(istype(user, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(!H.check_has_mouth()) + to_chat(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) + to_chat(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, issmall(user) ? ceil(amount_per_transfer_from_this/2) : amount_per_transfer_from_this, CHEM_INGEST) + user.bladder += amount_per_transfer_from_this //For peeing + C.adjust_thirst(amount_per_transfer_from_this * 5) + feed_sound(user) + return 1 + + + else + var/mob/living/carbon/H = target + if(!H.check_has_mouth()) + to_chat(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) + to_chat(user, "\The [blocked] is in the way!") + return + + other_feed_message_start(user, target) + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(!do_mob(user, target)) + return + + other_feed_message_finish(user, target) + + var/contained = reagentlist() + admin_attack_log(user, target, "Fed the victim with [name] (Reagents: [contained])", "Was fed [src] (Reagents: [contained])", "used [src] (Reagents: [contained]) to feed") + + reagents.trans_to_mob(target, amount_per_transfer_from_this, CHEM_INGEST) + target.bladder += amount_per_transfer_from_this //For peeing + H.adjust_thirst(amount_per_transfer_from_this * 5) + feed_sound(user) + return 1 + + return 0 + +/obj/item/weapon/reagent_containers/proc/standard_pour_into(var/mob/user, var/atom/target) // This goes into afterattack and yes, it's atom-level + if(!target.reagents) + return 0 + + // Ensure we don't splash beakers and similar containers. + if(!target.is_open_container() && istype(target, /obj/item/weapon/reagent_containers)) + to_chat(user, "\The [target] is closed.") + return 1 + // Otherwise don't care about splashing. + else if(!target.is_open_container()) + return 0 + + if(!reagents || !reagents.total_volume) + to_chat(user, "[src] is empty.") + return 1 + + if(!target.reagents.get_free_space()) + to_chat(user, "[target] is full.") + return 1 + + var/trans = reagents.trans_to(target, amount_per_transfer_from_this) + playsound(src, 'sound/effects/pour.ogg', 25, 1) + to_chat(user, "You transfer [trans] unit\s of the solution to \the [target].") + return 1 + +/obj/item/weapon/reagent_containers/do_surgery(mob/living/carbon/M, mob/living/user) + if(user.zone_sel.selecting != BP_MOUTH) //in case it is ever used as a surgery tool + return ..() + +/obj/item/weapon/reagent_containers/AltClick(var/mob/user) + if(possible_transfer_amounts) + if(CanPhysicallyInteract(user)) + set_APTFT() + else + return ..() diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm new file mode 100644 index 00000000..3af19ea4 --- /dev/null +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -0,0 +1,114 @@ +/obj/item/weapon/storage/box/bloodpacks + name = "blood packs box" + desc = "This box contains blood packs." + icon_state = "sterile" + startswith = list(/obj/item/weapon/reagent_containers/ivbag = 7) + +/obj/item/weapon/reagent_containers/ivbag + name = "\improper IV bag" + desc = "Flexible bag for IV injectors." + icon = 'icons/obj/bloodpack.dmi' + icon_state = "empty" + w_class = ITEM_SIZE_SMALL + volume = 120 + possible_transfer_amounts = "0.2;1;2" + amount_per_transfer_from_this = REM + atom_flags = ATOM_FLAG_OPEN_CONTAINER + + var/mob/living/carbon/human/attached + +/obj/item/weapon/reagent_containers/ivbag/Destroy() + STOP_PROCESSING(SSobj,src) + attached = null + . = ..() + +/obj/item/weapon/reagent_containers/ivbag/on_reagent_change() + update_icon() + if(reagents.total_volume > volume/2) + w_class = ITEM_SIZE_NORMAL + else + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/reagent_containers/attackby(obj/item/weapon/W as obj, mob/user as mob) + +/obj/item/weapon/reagent_containers/ivbag/update_icon() + overlays.Cut() + var/percent = round(reagents.total_volume / volume * 100) + if(reagents.total_volume) + var/image/filling = image('icons/obj/bloodpack.dmi', "[round(percent,25)]") + filling.color = reagents.get_color() + overlays += filling + overlays += image('icons/obj/bloodpack.dmi', "top") + if(attached) + overlays += image('icons/obj/bloodpack.dmi', "dongle") + +/obj/item/weapon/reagent_containers/ivbag/MouseDrop(over_object, src_location, over_location) + if(!CanMouseDrop(over_object)) + return + if(!ismob(loc)) + return + if(attached) + visible_message("\The [attached] is taken off \the [src]") + attached = null + else if(ishuman(over_object)) + visible_message("\The [usr] starts hooking \the [over_object] up to \the [src].") + if(do_after(usr, 30)) + to_chat(usr, "You hook \the [over_object] up to \the [src].") + attached = over_object + START_PROCESSING(SSobj,src) + update_icon() + +/obj/item/weapon/reagent_containers/ivbag/Process() + if(!ismob(loc)) + return PROCESS_KILL + + if(attached) + if(!loc.Adjacent(attached)) + attached = null + visible_message("\The [attached] detaches from \the [src]") + update_icon() + return PROCESS_KILL + else + return PROCESS_KILL + + var/mob/M = loc + if(M.l_hand != src && M.r_hand != src) + return + + if(!reagents.total_volume) + return + + reagents.trans_to_mob(attached, amount_per_transfer_from_this, CHEM_BLOOD) + update_icon() + +/obj/item/weapon/reagent_containers/ivbag/nanoblood/New() + ..() + reagents.add_reagent(/datum/reagent/nanoblood, volume) + +/obj/item/weapon/reagent_containers/ivbag/blood + name = "blood pack" + var/blood_type = null + +/obj/item/weapon/reagent_containers/ivbag/blood/New() + ..() + if(blood_type) + name = "blood pack [blood_type]" + reagents.add_reagent(/datum/reagent/blood, volume, list("donor" = null, "blood_DNA" = null, "blood_type" = blood_type, "trace_chem" = null, "virus2" = list(), "antibodies" = list())) + +/obj/item/weapon/reagent_containers/ivbag/blood/APlus + blood_type = "A+" + +/obj/item/weapon/reagent_containers/ivbag/blood/AMinus + blood_type = "A-" + +/obj/item/weapon/reagent_containers/ivbag/blood/BPlus + blood_type = "B+" + +/obj/item/weapon/reagent_containers/ivbag/blood/BMinus + blood_type = "B-" + +/obj/item/weapon/reagent_containers/ivbag/blood/OPlus + blood_type = "O+" + +/obj/item/weapon/reagent_containers/ivbag/blood/OMinus + blood_type = "O-" diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm new file mode 100644 index 00000000..1e7a65c8 --- /dev/null +++ b/code/modules/reagents/reagent_containers/borghydro.dm @@ -0,0 +1,151 @@ +/obj/item/weapon/reagent_containers/borghypo + name = "cyborg hypospray" + desc = "An advanced chemical synthesizer and injection system, designed for heavy-duty medical equipment." + icon = 'icons/obj/syringe.dmi' + item_state = "hypo" + icon_state = "borghypo" + amount_per_transfer_from_this = 5 + volume = 30 + possible_transfer_amounts = null + + var/mode = 1 + var/charge_cost = 50 + var/charge_tick = 0 + var/recharge_time = 5 //Time it takes for shots to recharge (in seconds) + + var/list/reagent_ids = list(/datum/reagent/tricordrazine, /datum/reagent/inaprovaline, /datum/reagent/spaceacillin) + var/list/reagent_volumes = list() + var/list/reagent_names = list() + +/obj/item/weapon/reagent_containers/borghypo/surgeon + reagent_ids = list(/datum/reagent/bicaridine, /datum/reagent/dexalin, /datum/reagent/tramadol) + +/obj/item/weapon/reagent_containers/borghypo/crisis + reagent_ids = list(/datum/reagent/tricordrazine, /datum/reagent/inaprovaline, /datum/reagent/tramadol) + +/obj/item/weapon/reagent_containers/borghypo/Initialize() + . = ..() + + for(var/T in reagent_ids) + reagent_volumes[T] = volume + var/datum/reagent/R = T + reagent_names += initial(R.name) + +/obj/item/weapon/reagent_containers/borghypo/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/item/weapon/reagent_containers/borghypo/Destroy() + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/item/weapon/reagent_containers/borghypo/Process() //Every [recharge_time] seconds, recharge some reagents for the cyborg+ + if(++charge_tick < recharge_time) + return 0 + charge_tick = 0 + + if(isrobot(loc)) + var/mob/living/silicon/robot/R = loc + if(R && R.cell) + for(var/T in reagent_ids) + if(reagent_volumes[T] < volume) + R.cell.use(charge_cost) + reagent_volumes[T] = min(reagent_volumes[T] + 5, volume) + return 1 + +/obj/item/weapon/reagent_containers/borghypo/attack(var/mob/living/M, var/mob/user, var/target_zone) + if(!istype(M)) + return + + if(!reagent_volumes[reagent_ids[mode]]) + to_chat(user, "The injector is empty.") + return + + var/mob/living/carbon/human/H = M + if(istype(H)) + var/obj/item/organ/external/affected = H.get_organ(target_zone) + if(!affected) + to_chat(user, "\The [H] is missing that limb!") + return + else if(affected.robotic >= ORGAN_ROBOT) + to_chat(user, "You cannot inject a robotic limb.") + return + + if (M.can_inject(user, target_zone)) + to_chat(user, "You inject [M] with the injector.") + to_chat(M, "You feel a tiny prick!") + + if(M.reagents) + var/t = min(amount_per_transfer_from_this, reagent_volumes[reagent_ids[mode]]) + M.reagents.add_reagent(reagent_ids[mode], t) + reagent_volumes[reagent_ids[mode]] -= t + admin_inject_log(user, M, src, reagent_ids[mode], t) + to_chat(user, "[t] units injected. [reagent_volumes[reagent_ids[mode]]] units remaining.") + return + +/obj/item/weapon/reagent_containers/borghypo/attack_self(mob/user as mob) //Change the mode + var/t = "" + for(var/i = 1 to reagent_ids.len) + if(t) + t += ", " + if(mode == i) + t += "[reagent_names[i]]" + else + t += "[reagent_names[i]]" + t = "Available reagents: [t]." + to_chat(user, t) + + return + +/obj/item/weapon/reagent_containers/borghypo/OnTopic(var/href, var/list/href_list) + if(href_list["reagent_index"]) + var/index = text2num(href_list["reagent_index"]) + if(index > 0 && index <= reagent_ids.len) + playsound(loc, 'sound/effects/pop.ogg', 50, 0) + mode = index + var/datum/reagent/R = reagent_ids[mode] + to_chat(usr, "Synthesizer is now producing '[initial(R.name)]'.") + return TOPIC_REFRESH + +/obj/item/weapon/reagent_containers/borghypo/examine(mob/user) + if(!..(user, 2)) + return + + var/datum/reagent/R = reagent_ids[mode] + + to_chat(user, "It is currently producing [initial(R.name)] and has [reagent_volumes[reagent_ids[mode]]] out of [volume] units left.") + +/obj/item/weapon/reagent_containers/borghypo/service + name = "cyborg drink synthesizer" + desc = "A portable drink dispencer." + icon = 'icons/obj/drinks.dmi' + icon_state = "shaker" + charge_cost = 20 + recharge_time = 3 + volume = 60 + possible_transfer_amounts = "5;10;20;30" + reagent_ids = list(/datum/reagent/ethanol/beer, /datum/reagent/ethanol/coffee/kahlua, /datum/reagent/ethanol/whiskey, /datum/reagent/ethanol/wine, /datum/reagent/ethanol/vodka, /datum/reagent/ethanol/gin, /datum/reagent/ethanol/rum, /datum/reagent/ethanol/tequilla, /datum/reagent/ethanol/vermouth, /datum/reagent/ethanol/cognac, /datum/reagent/ethanol/ale, /datum/reagent/ethanol/mead, /datum/reagent/water, /datum/reagent/sugar, /datum/reagent/drink/ice, /datum/reagent/drink/tea, /datum/reagent/drink/tea/icetea, /datum/reagent/drink/space_cola, /datum/reagent/drink/spacemountainwind, /datum/reagent/drink/dr_gibb, /datum/reagent/drink/space_up, /datum/reagent/drink/tonic, /datum/reagent/drink/sodawater, /datum/reagent/drink/lemon_lime, /datum/reagent/drink/juice/orange, /datum/reagent/drink/juice/lime, /datum/reagent/drink/juice/watermelon) + +/obj/item/weapon/reagent_containers/borghypo/service/attack(var/mob/M, var/mob/user) + return + +/obj/item/weapon/reagent_containers/borghypo/service/afterattack(var/obj/target, var/mob/user, var/proximity) + if(!proximity) + return + + if(!target.is_open_container() || !target.reagents) + return + + if(!reagent_volumes[reagent_ids[mode]]) + to_chat(user, "[src] is out of this reagent, give it some time to refill.") + return + + if(!target.reagents.get_free_space()) + to_chat(user, "[target] is full.") + return + + var/t = min(amount_per_transfer_from_this, reagent_volumes[reagent_ids[mode]]) + target.reagents.add_reagent(reagent_ids[mode], t) + reagent_volumes[reagent_ids[mode]] -= t + to_chat(user, "You transfer [t] units of the solution to [target].") + return diff --git a/code/modules/reagents/reagent_containers/drinkingglass/drinkingglass.dm b/code/modules/reagents/reagent_containers/drinkingglass/drinkingglass.dm new file mode 100644 index 00000000..bc362e96 --- /dev/null +++ b/code/modules/reagents/reagent_containers/drinkingglass/drinkingglass.dm @@ -0,0 +1,173 @@ +#define DRINK_ICON_FILE 'icons/pdrink.dmi' + +/var/const/DRINK_FIZZ = "fizz" +/var/const/DRINK_ICE = "ice" +/var/const/DRINK_VAPOR = "vapor" +/var/const/DRINK_ICON_DEFAULT = "" +/var/const/DRINK_ICON_NOISY = "_noise" + +/obj/item/weapon/reagent_containers/food/drinks/glass2 + name = "glass" // Name when empty + base_name = "glass" + desc = "A generic drinking glass." // Description when empty + icon = DRINK_ICON_FILE + base_icon = "square" // Base icon name + volume = 30 + matter = list("glass" = 65) + + var/list/extras = list() // List of extras. Two extras maximum + + var/rim_pos // Position of the rim for fruit slices. list(y, x_left, x_right) + + center_of_mass ="x=16;y=9" + + amount_per_transfer_from_this = 5 + possible_transfer_amounts = "5;10;15;30" + atom_flags = ATOM_FLAG_OPEN_CONTAINER + table_sound = 'sound/items/placing_glass2.ogg' + drop_sound = 'sound/items/drop_glass.ogg' + table_pickup_sound = 'sound/items/generic_lift.ogg' + +/obj/item/weapon/reagent_containers/food/drinks/glass2/examine(mob/M as mob) + . = ..() + + for(var/I in extras) + if(istype(I, /obj/item/weapon/glass_extra)) + to_chat(M, "There is \a [I] in \the [src].") + else if(istype(I, /obj/item/weapon/reagent_containers/food/snacks/fruit_slice)) + to_chat(M, "There is \a [I] on the rim.") + else + to_chat(M, "There is \a [I] somewhere on the glass. Somehow.") + + if(has_ice()) + to_chat(M, "There is some ice floating in the drink.") + + if(has_fizz()) + to_chat(M, "It is fizzing slightly.") + +/obj/item/weapon/reagent_containers/food/drinks/glass2/proc/has_ice() + if(reagents.reagent_list.len > 0) + var/datum/reagent/R = reagents.get_master_reagent() + if(!((R.type == /datum/reagent/drink/ice) || ("ice" in R.glass_special))) // if it's not a cup of ice, and it's not already supposed to have ice in, see if the bartender's put ice in it + if(reagents.has_reagent(/datum/reagent/drink/ice, reagents.total_volume / 10)) // 10% ice by volume + return 1 + + return 0 + +/obj/item/weapon/reagent_containers/food/drinks/glass2/proc/has_fizz() + if(reagents.reagent_list.len > 0) + var/datum/reagent/R = reagents.get_master_reagent() + if(!("fizz" in R.glass_special)) + var/totalfizzy = 0 + for(var/datum/reagent/re in reagents.reagent_list) + if("fizz" in re.glass_special) + totalfizzy += re.volume + if(totalfizzy >= reagents.total_volume / 5) // 20% fizzy by volume + return 1 + return 0 + +/obj/item/weapon/reagent_containers/food/drinks/glass2/proc/has_vapor() + if(reagents.reagent_list.len > 0) + var/datum/reagent/R = reagents.get_master_reagent() + if(!("vapor" in R.glass_special)) + var/totalvape = 0 + for(var/datum/reagent/re in reagents.reagent_list) + if("vapor" in re.glass_special) + totalvape += re.volume + if(totalvape >= volume * 0.6) // 60% vapor by container volume + return 1 + return 0 + +/obj/item/weapon/reagent_containers/food/drinks/glass2/New() + ..() + icon_state = base_icon + +/obj/item/weapon/reagent_containers/food/drinks/glass2/on_reagent_change() + update_icon() + +/obj/item/weapon/reagent_containers/food/drinks/glass2/proc/can_add_extra(obj/item/weapon/glass_extra/GE) + if(!("[base_icon]_[GE.glass_addition]left" in icon_states(DRINK_ICON_FILE))) + return 0 + if(!("[base_icon]_[GE.glass_addition]right" in icon_states(DRINK_ICON_FILE))) + return 0 + + return 1 + +/obj/item/weapon/reagent_containers/food/drinks/glass2/update_icon() + underlays.Cut() + + if (reagents.reagent_list.len > 0) + var/datum/reagent/R = reagents.get_master_reagent() + SetName("[base_name] of [R.glass_name ? R.glass_name : "something"]") + desc = R.glass_desc ? R.glass_desc : initial(desc) + + var/list/under_liquid = list() + var/list/over_liquid = list() + + var/amnt = get_filling_state() + + if(has_ice()) + over_liquid |= "[base_icon][amnt]_ice" + + if(has_fizz()) + over_liquid |= "[base_icon][amnt]_fizz" + + if(has_vapor()) + over_liquid |= "[base_icon]_vapor" + + for(var/S in R.glass_special) + if("[base_icon]_[S]" in icon_states(DRINK_ICON_FILE)) + under_liquid |= "[base_icon]_[S]" + else if("[base_icon][amnt]_[S]" in icon_states(DRINK_ICON_FILE)) + over_liquid |= "[base_icon][amnt]_[S]" + + for(var/k in under_liquid) + underlays += image(DRINK_ICON_FILE, src, k, -3) + + var/image/filling = image(DRINK_ICON_FILE, src, "[base_icon][amnt][R.glass_icon]", -2) + filling.color = reagents.get_color() + underlays += filling + + for(var/k in over_liquid) + underlays += image(DRINK_ICON_FILE, src, k, -1) + else + SetName(initial(name)) + desc = initial(desc) + + var/side = "left" + for(var/item in extras) + if(istype(item, /obj/item/weapon/glass_extra)) + var/obj/item/weapon/glass_extra/GE = item + var/image/I = image(DRINK_ICON_FILE, src, "[base_icon]_[GE.glass_addition][side]") + if(GE.glass_color) + I.color = GE.glass_color + underlays += I + else if(rim_pos && istype(item, /obj/item/weapon/reagent_containers/food/snacks/fruit_slice)) + var/obj/FS = item + var/image/I = image(FS) + + var/list/rim_pos_data = cached_key_number_decode(rim_pos) + var/fsy = rim_pos_data["y"] - 20 + var/fsx = rim_pos_data[side == "left" ? "x_left" : "x_right"] - 16 + + var/matrix/M = matrix() + M.Scale(0.5) + M.Translate(fsx, fsy) + I.transform = M + underlays += I + else continue + side = "right" + +/obj/item/weapon/reagent_containers/food/drinks/glass2/attackby(obj/item/W, mob/user) + if(istype(W, /obj/item/weapon/material/kitchen/utensil/spoon)) + if(user.a_intent == I_HURT) + user.visible_message("[user] bashes \the [src] with a spoon, shattering it to pieces! What a rube.") + playsound(src, "shatter", 30, 1) + if(reagents) + user.visible_message("The contents of \the [src] splash all over [user]!") + reagents.splash(user, reagents.total_volume) + qdel(src) + return + user.visible_message("[user] gently strikes \the [src] with a spoon, calling the room to attention.") + playsound(src, "sound/items/wineglass.ogg", 65, 1) + else return ..() \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/drinkingglass/extras.dm b/code/modules/reagents/reagent_containers/drinkingglass/extras.dm new file mode 100644 index 00000000..87fa141f --- /dev/null +++ b/code/modules/reagents/reagent_containers/drinkingglass/extras.dm @@ -0,0 +1,72 @@ +/obj/item/weapon/reagent_containers/food/drinks/glass2/attackby(obj/item/I as obj, mob/user as mob) + if(extras.len >= 2) return ..() // max 2 extras, one on each side of the drink + + if(istype(I, /obj/item/weapon/glass_extra)) + var/obj/item/weapon/glass_extra/GE = I + if(can_add_extra(GE)) + extras += GE + user.remove_from_mob(GE) + GE.loc = src + to_chat(user, "You add \the [GE] to \the [src].") + update_icon() + else + to_chat(user, "There's no space to put \the [GE] on \the [src]!") + else if(istype(I, /obj/item/weapon/reagent_containers/food/snacks/fruit_slice)) + if(!rim_pos) + to_chat(user, "There's no space to put \the [I] on \the [src]!") + return + var/obj/item/weapon/reagent_containers/food/snacks/fruit_slice/FS = I + extras += FS + user.remove_from_mob(FS) + FS.pixel_x = 0 // Reset its pixel offsets so the icons work! + FS.pixel_y = 0 + FS.loc = src + to_chat(user, "You add \the [FS] to \the [src].") + update_icon() + else + return ..() + +/obj/item/weapon/reagent_containers/food/drinks/glass2/attack_hand(mob/user as mob) + if(src != user.get_inactive_hand()) + return ..() + + if(!extras.len) + to_chat(user, "There's nothing on the glass to remove!") + return + + var/choice = input(user, "What would you like to remove from the glass?") as null|anything in extras + if(!choice || !(choice in extras)) + return + + if(user.put_in_active_hand(choice)) + to_chat(user, "You remove \the [choice] from \the [src].") + extras -= choice + else + to_chat(user, "Something went wrong, please try again.") + + update_icon() + +/obj/item/weapon/glass_extra + name = "generic glass addition" + desc = "This goes on a glass." + var/glass_addition + var/glass_desc + var/glass_color + w_class = ITEM_SIZE_TINY + icon = DRINK_ICON_FILE + +/obj/item/weapon/glass_extra/stick + name = "stick" + desc = "This goes in a glass." + glass_addition = "stick" + glass_desc = "There is a stick in the glass." + icon_state = "stick" + +/obj/item/weapon/glass_extra/straw + name = "straw" + desc = "This goes in a glass." + glass_addition = "straw" + glass_desc = "There is a straw in the glass." + icon_state = "straw" + +#undef DRINK_ICON_FILE diff --git a/code/modules/reagents/reagent_containers/drinkingglass/glass_boxes.dm b/code/modules/reagents/reagent_containers/drinkingglass/glass_boxes.dm new file mode 100644 index 00000000..ee19dd24 --- /dev/null +++ b/code/modules/reagents/reagent_containers/drinkingglass/glass_boxes.dm @@ -0,0 +1,82 @@ +/obj/item/weapon/storage/box/mixedglasses + name = "glassware box" + desc = "A box of assorted glassware" + can_hold = list(/obj/item/weapon/reagent_containers/food/drinks/glass2) + + startswith = list( + /obj/item/weapon/reagent_containers/food/drinks/glass2/square, + /obj/item/weapon/reagent_containers/food/drinks/glass2/rocks, + /obj/item/weapon/reagent_containers/food/drinks/glass2/shake, + /obj/item/weapon/reagent_containers/food/drinks/glass2/cocktail, + /obj/item/weapon/reagent_containers/food/drinks/glass2/shot, + /obj/item/weapon/reagent_containers/food/drinks/glass2/pint, + /obj/item/weapon/reagent_containers/food/drinks/glass2/mug, + /obj/item/weapon/reagent_containers/food/drinks/glass2/wine + ) + +/obj/item/weapon/storage/box/mixedglasses/Initialize() + . = ..() + make_exact_fit() + +/obj/item/weapon/storage/box/glasses + name = "box of glasses" + var/glass_type = /obj/item/weapon/reagent_containers/food/drinks/glass2 + can_hold = list(/obj/item/weapon/reagent_containers/food/drinks/glass2) + +/obj/item/weapon/storage/box/glasses/Initialize() + . = ..() + + for(var/i = 1 to 7) + new glass_type(src) + make_exact_fit() + +/obj/item/weapon/storage/box/glasses/square + name = "box of half-pint glasses" + glass_type = /obj/item/weapon/reagent_containers/food/drinks/glass2/square + +/obj/item/weapon/storage/box/glasses/rocks + name = "box of rocks glasses" + glass_type = /obj/item/weapon/reagent_containers/food/drinks/glass2/rocks + +/obj/item/weapon/storage/box/glasses/shake + name = "box of milkshake glasses" + glass_type = /obj/item/weapon/reagent_containers/food/drinks/glass2/shake + +/obj/item/weapon/storage/box/glasses/cocktail + name = "box of cocktail glasses" + glass_type = /obj/item/weapon/reagent_containers/food/drinks/glass2/cocktail + +/obj/item/weapon/storage/box/glasses/shot + name = "box of shot glasses" + glass_type = /obj/item/weapon/reagent_containers/food/drinks/glass2/shot + +/obj/item/weapon/storage/box/glasses/pint + name = "box of pint glasses" + glass_type = /obj/item/weapon/reagent_containers/food/drinks/glass2/pint + +/obj/item/weapon/storage/box/glasses/mug + name = "box of glass mugs" + glass_type = /obj/item/weapon/reagent_containers/food/drinks/glass2/mug + +/obj/item/weapon/storage/box/glasses/wine + name = "box of wine glasses" + glass_type = /obj/item/weapon/reagent_containers/food/drinks/glass2/wine + +/obj/item/weapon/storage/box/glass_extras + name = "box of cocktail garnishings" + var/extra_type = /obj/item/weapon/glass_extra + can_hold = list(/obj/item/weapon/glass_extra) + storage_slots = 14 + +/obj/item/weapon/storage/box/glass_extras/Initialize() + for(var/i = 1 to 14) + new extra_type(src) + . = ..() + +/obj/item/weapon/storage/box/glass_extras/straws + name = "box of straws" + extra_type = /obj/item/weapon/glass_extra/straw + +/obj/item/weapon/storage/box/glass_extras/sticks + name = "box of drink sticks" + extra_type = /obj/item/weapon/glass_extra/stick diff --git a/code/modules/reagents/reagent_containers/drinkingglass/glass_types.dm b/code/modules/reagents/reagent_containers/drinkingglass/glass_types.dm new file mode 100644 index 00000000..903d628e --- /dev/null +++ b/code/modules/reagents/reagent_containers/drinkingglass/glass_types.dm @@ -0,0 +1,84 @@ +/obj/item/weapon/reagent_containers/food/drinks/glass2/square + name = "half-pint glass" + base_name = "glass" + base_icon = "square" + desc = "Your standard drinking glass." + filling_states = "20;40;60;80;100" + volume = 30 + possible_transfer_amounts = "5;10;15;30" + rim_pos = "y=23;x_left=13;x_right=20" + +/obj/item/weapon/reagent_containers/food/drinks/glass2/rocks + name = "rocks glass" + base_name = "glass" + base_icon = "rocks" + filling_states = "25;50;75;100" + volume = 20 + possible_transfer_amounts = "5;10;20" + rim_pos = "y=21;x_left=10;x_right=23" + +/obj/item/weapon/reagent_containers/food/drinks/glass2/shake + name = "tall cocktail glass" + base_name = "glass" + base_icon = "shake" + filling_states = "25;50;75;100" + volume = 30 + possible_transfer_amounts = "5;10;15;30" + rim_pos = "y=25;x_left=13;x_right=21" + +/obj/item/weapon/reagent_containers/food/drinks/glass2/cocktail + name = "cocktail glass" + base_name = "glass" + base_icon = "cocktail" + filling_states = "33;66;100" + volume = 15 + possible_transfer_amounts = "5;10;15" + rim_pos = "y=22;x_left=13;x_right=21" + +/obj/item/weapon/reagent_containers/food/drinks/glass2/shot + name = "shot glass" + base_name = "shot" + base_icon = "shot" + filling_states = "33;66;100" + volume = 5 + matter = list("glass" = 15) + possible_transfer_amounts = "1;2;5" + rim_pos = "y=17;x_left=13;x_right=21" + +/obj/item/weapon/reagent_containers/food/drinks/glass2/pint + name = "pint glass" + base_name = "pint" + base_icon = "pint" + filling_states = "16;33;50;66;83;100" + volume = 60 + possible_transfer_amounts = "5;10;15;30;60" + rim_pos = "y=25;x_left=12;x_right=21" + +/obj/item/weapon/reagent_containers/food/drinks/glass2/mug + name = "glass mug" + base_name = "mug" + base_icon = "mug" + filling_states = "25;50;75;100" + volume = 40 + possible_transfer_amounts = "5;10;20;40" + rim_pos = "y=22;x_left=12;x_right=20" + +/obj/item/weapon/reagent_containers/food/drinks/glass2/wine + name = "wine glass" + base_name = "glass" + base_icon = "wine" + filling_states = "20;40;60;80;100" + volume = 25 + possible_transfer_amounts = "5;10;15;25" + rim_pos = "y=25;x_left=12;x_right=21" + +/obj/item/weapon/reagent_containers/food/drinks/glass2/carafe + name = "carafe" + base_name = "carafe" + base_icon = "carafe" + filling_states = "10;20;30;40;50;60;70;80;90;100" + volume = 120 + matter = list("glass" = 250) + possible_transfer_amounts = "5;10;15;30;60;120" + rim_pos = "y=26;x_left=12;x_right=21" + center_of_mass = "x=16;y=7" diff --git a/code/modules/reagents/reagent_containers/drinkingglass/shaker.dm b/code/modules/reagents/reagent_containers/drinkingglass/shaker.dm new file mode 100644 index 00000000..68409a80 --- /dev/null +++ b/code/modules/reagents/reagent_containers/drinkingglass/shaker.dm @@ -0,0 +1,32 @@ + +/obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask + name = "fitness shaker" + base_name = "shaker" + desc = "Big enough to contain enough protein to get perfectly swole. Don't mind the bits." + icon_state = "fitness-cup_black" + base_icon = "fitness-cup" + volume = 100 + matter = list("plastic" = 2000) + filling_states = "10;20;30;40;50;60;70;80;90;100" + possible_transfer_amounts = "5;10;15;25" + rim_pos = null // no fruit slices + var/lid_color = "black" + +/obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask/New() + ..() + lid_color = pick("black", "red", "blue") + update_icon() + +/obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask/update_icon() + ..() + icon_state = "[base_icon]_[lid_color]" + +/obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask/proteinshake + name = "protein shake" + +/obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask/proteinshake/New() + ..() + reagents.add_reagent(/datum/reagent/nutriment, 30) + reagents.add_reagent(/datum/reagent/iron, 10) + reagents.add_reagent(/datum/reagent/nutriment/protein, 15) + reagents.add_reagent(/datum/reagent/water, 45) diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm new file mode 100644 index 00000000..56fcbd23 --- /dev/null +++ b/code/modules/reagents/reagent_containers/dropper.dm @@ -0,0 +1,109 @@ +//////////////////////////////////////////////////////////////////////////////// +/// Droppers. +//////////////////////////////////////////////////////////////////////////////// +/obj/item/weapon/reagent_containers/dropper + name = "Dropper" + desc = "A dropper. Transfers 5 units." + icon = 'icons/obj/chemical.dmi' + icon_state = "dropper0" + amount_per_transfer_from_this = 5 + possible_transfer_amounts = "1;2;3;4;5" + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + volume = 5 + + afterattack(var/obj/target, var/mob/user, var/proximity) + if(!target.reagents || !proximity) return + + if(reagents.total_volume) + + if(!target.reagents.get_free_space()) + to_chat(user, "[target] is full.") + return + + if(!target.is_open_container() && !ismob(target) && !istype(target, /obj/item/weapon/reagent_containers/food) && !istype(target, /obj/item/clothing/mask/smokable/cigarette)) //You can inject humans and food but you cant remove the shit. + to_chat(user, "You cannot directly fill this object.") + return + + var/trans = 0 + + if(ismob(target)) + if(user.a_intent == I_HELP) + return + + var/time = 20 //2/3rds the time of a syringe + user.visible_message("[user] is trying to squirt something into [target]'s eyes!") + + if(!do_mob(user, target, time)) + return + + if(istype(target, /mob/living/carbon/human)) + var/mob/living/carbon/human/victim = target + + var/obj/item/safe_thing = null + if(victim.wear_mask) + if (victim.wear_mask.body_parts_covered & EYES) + safe_thing = victim.wear_mask + if(victim.head) + if (victim.head.body_parts_covered & EYES) + safe_thing = victim.head + if(victim.glasses) + if (victim.glasses.body_parts_covered & EYES) + safe_thing = victim.glasses + + if(safe_thing) + trans = reagents.splash(safe_thing, amount_per_transfer_from_this, max_spill=30) + user.visible_message("[user] tries to squirt something into [target]'s eyes, but fails!", "You transfer [trans] units of the solution.") + return + + var/mob/living/M = target + var/contained = reagentlist() + admin_attack_log(user, M, "Squirted their victim with \a [src] (Reagents: [contained])", "Were squirted with \a [src] (Reagents: [contained])", "used \a [src] (Reagents: [contained]) to squirt at") + + var/spill_amt = M.incapacitated()? 0 : 30 + trans += reagents.splash(target, reagents.total_volume/2, max_spill = spill_amt) + trans += reagents.trans_to_mob(target, reagents.total_volume/2, CHEM_BLOOD) //I guess it gets into the bloodstream through the eyes or something + user.visible_message("[user] squirts something into [target]'s eyes!", "You transfer [trans] units of the solution.") + + + return + + else + trans = reagents.splash(target, amount_per_transfer_from_this, max_spill=0) //sprinkling reagents on generic non-mobs. Droppers are very precise + to_chat(user, "You transfer [trans] units of the solution.") + + else // Taking from something + + if(!target.is_open_container() && !istype(target,/obj/structure/reagent_dispensers)) + to_chat(user, "You cannot directly remove reagents from [target].") + return + + if(!target.reagents || !target.reagents.total_volume) + to_chat(user, "[target] is empty.") + return + + var/trans = target.reagents.trans_to_obj(src, amount_per_transfer_from_this) + + to_chat(user, "You fill the dropper with [trans] units of the solution.") + + return + + on_reagent_change() + update_icon() + + update_icon() + if(reagents.total_volume) + icon_state = "dropper1" + else + icon_state = "dropper0" + +/obj/item/weapon/reagent_containers/dropper/industrial + name = "Industrial Dropper" + desc = "A larger dropper. Transfers 10 units." + amount_per_transfer_from_this = 10 + possible_transfer_amounts = "1;2;3;4;5;6;7;8;9;10" + volume = 10 + +//////////////////////////////////////////////////////////////////////////////// +/// Droppers. END +//////////////////////////////////////////////////////////////////////////////// diff --git a/code/modules/reagents/reagent_containers/eatables.dm b/code/modules/reagents/reagent_containers/eatables.dm new file mode 100644 index 00000000..a4c591d7 --- /dev/null +++ b/code/modules/reagents/reagent_containers/eatables.dm @@ -0,0 +1,207 @@ +/* + ======== + FOOD 2.0 + ======== + +What: Food that goes into a stomach organ rather than doing the hacky way of + cheating one in with lists. It also comes with cooking states af of writing this + I'm not entirely sure how the cooking hsould be handled but Kyrah suggested that + the items have a cook type they turn in to and change reagents over time. I guess + the idea is that you could poison a raw steak but honestly you would cook out all + the poisons probably so it might make more sense to just turn into a new thing entirely. + For now I'll do it Kyrah's way in case there's something here I'm missing. + +Why: This also helps regulate the speed of nutrient consumption, another benefit + is that it means you can eat multiple things of different reagents and they + will react once your stomach absorbs them (rather than instantly) so it means + you could slowly poison someone and they might not know until a little later. +*/ + +/* +The nutrient quick rundown: + + living mobs have something called 'nutrition this + value is subtracted by about everything so it's basically + the single-most important thing in mob. do you move? subtract + nutrition. Healing over time passively? Uses nutrition. got it? + good. + + "So we want to add nutrition to the mob." + "No!" + + Nutriment (in Chemistry-Reagents-Food-Drinks.dm) returns + a multiple of *10 for every nutriment it detects in a mob's + bloodstream into the nutrition so if you must make your food + use nutriment make it a small value like 3 (which becomes 30) + Protein also returns a multiple of 10 so keep it in mind. + be sure to check the .dm for your appropriate amount. + + As of writing this and after testing, it seems the blood_ingest + has something else that adds some kind of multiplier. so keep your + values real low because this shit gives off a lot of nutrition. + + "So why is the volume for food so high?" + + This is a remnant of th eold food code but food is a reagent container + so you can add stuff to the food to poison/season it. I'm gonna leave it + at 50, the old value, and see what comes of it. It is easy enough to fix. +*/ + +/obj/item/weapon/reagent_containers/eatable + randpixel = 6 + atom_flags = ATOM_FLAG_OPEN_CONTAINER + possible_transfer_amounts = null + volume = 50 //Sets the default container amount for all food items. + + name = "Food" + desc = "Looks edible." + icon = 'icons/obj/food.dmi' + icon_state = "meat" + var/eat_message = "chomps down" // adds it to the consuming display + var/eat_sound = null //unique chomping sounds + + var/bitesize = 3 // using this to divide the reagents. (e.g myreagent_amt/bitesize) + + var/bitecount = 0 //checking if someone chewed on it!! + + //reagents that eatables have. + var/myreagent_amt = 10 + var/datum/reagent/myreagent = /datum/reagent/nutriment + + //COOKING VARS + var/cooktime = 8 //how many ticks food takes to cook. + var/cooktime_elapsed = 0 + var/cook_item = null //item it turns in to when cooking is done. + var/cook_type = 0 //checks what you tried to cook it in (good for cooking things multiple ways!) + var/cook_steps = 1 // for if the item has more steps during cooking (mostly a future proof thing) + + center_of_mass = "x=16;y=16" + w_class = ITEM_SIZE_SMALL + + var/trash = null //if it spawns garbage (like old food code) + +/obj/item/weapon/reagent_containers/eatable/New() + ..() + if(myreagent) + reagents.add_reagent(myreagent,myreagent_amt) + else + qdel(src) // why would you want food with nothing in it?? + +/obj/item/weapon/reagent_containers/eatable/attack_self(mob/user as mob) + return + + +//TO DO: check for zone selection mouth, otherwise hit the person with the food.) + +/obj/item/weapon/reagent_containers/eatable/attack(mob/M as mob, mob/user as mob, def_zone) + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + + if(istype(M, /mob/living/carbon)) + var/mob/living/carbon/C = M + + if(C == user) //If you're eating it yourself + if(istype(C,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/internal/stomach/gut = H.internal_organs_by_name[BP_STOMACH] + + //to_chat(user, "stomach is [gut]") + + if(!gut) + to_chat(user, "You can't eat without a stomach...") + return + if(!H.check_has_mouth()) + to_chat(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) + to_chat(user, "\The [blocked] is in the way!") + return + else + if(!M.can_force_feed(user, src)) + return + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/internal/stomach/gut = H.internal_organs_by_name[BP_STOMACH] + + if(!gut) + to_chat(user, "They have no stomach...") + return + if(!H.check_has_mouth()) + to_chat(user, "Where do you intend to put \the [src]? They have no mouth!") + return + var/obj/item/blocked = H.check_mouth_coverage() + if(blocked) + to_chat(user, "\The [blocked] is in the way!") + return + + /* + //uncomment if you think it's useful, I don't. + var/contained = reagentlist() + admin_attack_log(user, M, "Fed the victim with [name] (Reagents: [contained])", "Was fed [src] (Reagents: [contained])", "used [src] (Reagents: [contained]) to feed") + user.visible_message("[user] feeds [M] [src].") + */ + + var/mob/living/carbon/human/H = M + var/obj/item/organ/internal/stomach/gut = H.internal_organs_by_name[BP_STOMACH] + var/obj/item/weapon/storage/special/stomach/gutinventory = gut.inventory + //add a food chunk to the stomach + if(!gut.inventory.can_be_inserted(src, user, 1)) + M.visible_message("[M] Can't eat anymore of \the [src].","You feel too full to eat \the [src].") + return + var/obj/item/weapon/reagent_containers/eatable/foodchunk/chunk = new /obj/item/weapon/reagent_containers/eatable/foodchunk(gutinventory) + if(reagents.total_volume < myreagent_amt/bitesize) + reagents.trans_to(chunk, reagents.total_volume) + else + reagents.trans_to(chunk, myreagent_amt/bitesize) + + M.visible_message("[M] [eat_message] the [name].","You finish eating \the [src].") + //to_chat(user, "[chunk] was sent to the gut. it has [myreagent_amt/bitesize] worth of nutrients") + + if(reagents.total_volume < 1) //sanity check? + //to_chat(user, "I'm dead because I only have [reagents.total_volume] left!") + user.drop_from_inventory(src) + M.visible_message("[M] finishes eating \the [src].","You finish eating \the [src].") + qdel(src) + return 0 + + + + + +/obj/item/weapon/reagent_containers/eatable/examine(mob/user) + if(!..(user, 1)) + return + if (bitecount==0) + return + else + to_chat(user, "Something has been eating this!") + +/obj/item/weapon/reagent_containers/eatable/attackby(obj/item/weapon/W as obj, mob/user as mob) + return + //this is for figuing out food with utensils and stuff. I'll figure it out later + //for now people eat food with their hands like cretins + + +//not sure why old food has this, it's for cutting shit open that has stuff in it?? +/obj/item/weapon/reagent_containers/eatable/Destroy() + if(contents) + for(var/atom/movable/something in contents) + something.dropInto(loc) + . = ..() + +//cooking is based on +/obj/item/weapon/reagent_containers/eatable/proc/Cook(var/type) + return + //switch(type) + // if(NO_COOKING_METHOD) + //burn it + + +/* +food chunk, this gets put in the stomach of the mob which eats the eatable +*/ +/obj/item/weapon/reagent_containers/eatable/foodchunk + name = "Food chunk" + desc = "a small chunk of chewed up food." + icon_state = "badrecipe" \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food.dm b/code/modules/reagents/reagent_containers/food.dm new file mode 100644 index 00000000..8f31b156 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food.dm @@ -0,0 +1,11 @@ +//////////////////////////////////////////////////////////////////////////////// +/// Food. +//////////////////////////////////////////////////////////////////////////////// +/obj/item/weapon/reagent_containers/food + randpixel = 6 + atom_flags = ATOM_FLAG_OPEN_CONTAINER + possible_transfer_amounts = null + volume = 50 //Sets the default container amount for all food items. + var/filling_color = "#ffffff" //Used by sandwiches. + var/trash = null + var/open_sound = 'sound/effects/canopen.ogg' \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food/cans.dm b/code/modules/reagents/reagent_containers/food/cans.dm new file mode 100644 index 00000000..03844a83 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/cans.dm @@ -0,0 +1,130 @@ +/obj/item/weapon/reagent_containers/food/drinks/cans + volume = 40 //just over one and a half cups + amount_per_transfer_from_this = 5 + atom_flags = 0 //starts closed + +//DRINKS + +/obj/item/weapon/reagent_containers/food/drinks/cans/cola + name = "\improper Red Cola" + desc = "The Redcoats's chosen beverage." + icon_state = "cola" + center_of_mass = "x=16;y=10" + +/obj/item/weapon/reagent_containers/food/drinks/cans/cola/New() + ..() + reagents.add_reagent(/datum/reagent/drink/space_cola, 30) + +/obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle + name = "bottled water" + desc = "Pure drinking water, imported from the Martian poles." + icon_state = "waterbottle" + center_of_mass = "x=15;y=8" + +/obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle/New() + ..() + reagents.add_reagent(/datum/reagent/water, 30) + +/obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle/open(mob/user) + playsound(loc,'sound/effects/bonebreak1.ogg', rand(10,50), 1) + to_chat(user, "You twist open \the [src], destroying the safety seal!") + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + +/obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind + name = "\improper Trench Mountain Wind" + desc = "Blows right through you like the winds of death." + icon_state = "space_mountain_wind" + center_of_mass = "x=16;y=10" + +/obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind/New() + ..() + reagents.add_reagent(/datum/reagent/drink/spacemountainwind, 30) + +/obj/item/weapon/reagent_containers/food/drinks/cans/thirteenloko + name = "\improper Thirteen Loko" + desc = "The Head Practitioner has advised crew members that consumption of Thirteen Loko may result in seizures, blindness, drunkeness, or even death. Please Drink Responsibly." + icon_state = "thirteen_loko" + center_of_mass = "x=16;y=8" + +/obj/item/weapon/reagent_containers/food/drinks/cans/thirteenloko/New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/thirteenloko, 30) + +/obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb + name = "\improper Dr. Gibb" + desc = "A delicious mixture of 42 different flavors." + icon_state = "dr_gibb" + center_of_mass = "x=16;y=10" + +/obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb/New() + ..() + reagents.add_reagent(/datum/reagent/drink/dr_gibb, 30) + +/obj/item/weapon/reagent_containers/food/drinks/cans/starkist + name = "\improper Stun-kist" + desc = "A stunning taste. Knocks you right off your feet." + icon_state = "starkist" + center_of_mass = "x=16;y=10" +/obj/item/weapon/reagent_containers/food/drinks/cans/starkist/New() + ..() + reagents.add_reagent(/datum/reagent/drink/brownstar, 30) + +/obj/item/weapon/reagent_containers/food/drinks/cans/space_up + name = "\improper War-Up" + desc = "Tastes like a mortar in your mouth." + icon_state = "space-up" + center_of_mass = "x=16;y=10" + +/obj/item/weapon/reagent_containers/food/drinks/cans/space_up/New() + ..() + reagents.add_reagent(/datum/reagent/drink/space_up, 30) + +/obj/item/weapon/reagent_containers/food/drinks/cans/lemon_lime + name = "\improper Lemon-Lime" + desc = "You wanted ORANGE. It gave you Lemon Lime." + icon_state = "lemon-lime" + center_of_mass = "x=16;y=10" + +/obj/item/weapon/reagent_containers/food/drinks/cans/lemon_lime/New() + ..() + reagents.add_reagent(/datum/reagent/drink/lemon_lime, 30) + +/obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea + name = "\improper Orphan's Blood Iced Tea" + desc = "That sweet, refreshing flavor. If you listen closely you can still hear the screams." + icon_state = "ice_tea_can" + center_of_mass = "x=16;y=10" + +/obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea/New() + ..() + reagents.add_reagent(/datum/reagent/drink/tea/icetea, 30) + +/obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice + name = "\improper Grapel Juice" + desc = "500 pages of rules of how to appropriately enter into a combat with this juice!" + icon_state = "purple_can" + center_of_mass = "x=16;y=10" + +/obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice/New() + ..() + reagents.add_reagent(/datum/reagent/drink/juice/grape, 30) + +/obj/item/weapon/reagent_containers/food/drinks/cans/tonic + name = "\improper T-Borg's Tonic Water" + desc = "Quinine tastes funny, but at least it'll keep that Space Malaria away." + icon_state = "tonic" + center_of_mass = "x=16;y=10" + +/obj/item/weapon/reagent_containers/food/drinks/cans/tonic/New() + ..() + reagents.add_reagent(/datum/reagent/drink/tonic, 50) + +/obj/item/weapon/reagent_containers/food/drinks/cans/sodawater + name = "soda water" + desc = "A can of soda water. Still water's more refreshing cousin." + icon_state = "sodawater" + center_of_mass = "x=16;y=10" + +/obj/item/weapon/reagent_containers/food/drinks/cans/sodawater/New() + ..() + reagents.add_reagent(/datum/reagent/drink/sodawater, 50) \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food/condiment.dm b/code/modules/reagents/reagent_containers/food/condiment.dm new file mode 100644 index 00000000..4ee9aa8b --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/condiment.dm @@ -0,0 +1,217 @@ + +///////////////////////////////////////////////Condiments +//Notes by Darem: The condiments food-subtype is for stuff you don't actually eat but you use to modify existing food. They all +// leave empty containers when used up and can be filled/re-filled with other items. Formatting for first section is identical +// to mixed-drinks code. If you want an object that starts pre-loaded, you need to make it in addition to the other code. + +//Food items that aren't eaten normally and leave an empty container behind. +/obj/item/weapon/reagent_containers/food/condiment + name = "Condiment Container" + desc = "Just your average condiment container." + icon = 'icons/obj/food.dmi' + icon_state = "emptycondiment" + atom_flags = ATOM_FLAG_OPEN_CONTAINER + possible_transfer_amounts = "1;5;10" + center_of_mass = "x=16;y=6" + volume = 50 + +/obj/item/weapon/reagent_containers/food/condiment/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(istype(W, /obj/item/weapon/pen) || istype(W, /obj/item/device/flashlight/pen)) + var/tmp_label = sanitizeSafe(input(user, "Enter a label for [name]", "Label", label_text), MAX_NAME_LEN) + if(tmp_label == label_text) + return + if(length(tmp_label) > 10) + to_chat(user, "The label can be at most 10 characters long.") + else + if(length(tmp_label)) + to_chat(user, "You set the label to \"[tmp_label]\".") + label_text = tmp_label + name = addtext(name," ([label_text])") + else + to_chat(user, "You remove the label.") + label_text = null + on_reagent_change() + return + + + +/obj/item/weapon/reagent_containers/food/condiment/attack_self(var/mob/user as mob) + return + +/obj/item/weapon/reagent_containers/food/condiment/attack(var/mob/M as mob, var/mob/user as mob, var/def_zone) + if(standard_feed_mob(user, M)) + return + +/obj/item/weapon/reagent_containers/food/condiment/afterattack(var/obj/target, var/mob/user, var/proximity) + if(!proximity) + return + + if(standard_dispenser_refill(user, target)) + return + if(standard_pour_into(user, target)) + return + + if(istype(target, /obj/item/weapon/reagent_containers/food/snacks)) // These are not opencontainers but we can transfer to them + if(!reagents || !reagents.total_volume) + to_chat(user, "There is no condiment left in \the [src].") + return + + if(!target.reagents.get_free_space()) + to_chat(user, "You can't add more condiment to \the [target].") + return + + var/trans = reagents.trans_to_obj(target, amount_per_transfer_from_this) + to_chat(user, "You add [trans] units of the condiment to \the [target].") + else + ..() + +/obj/item/weapon/reagent_containers/food/condiment/feed_sound(var/mob/user) + playsound(user.loc, "drink", rand(10, 50), 1) + +/obj/item/weapon/reagent_containers/food/condiment/self_feed_message(var/mob/user) + to_chat(user, "You swallow some of contents of \the [src].") + +/obj/item/weapon/reagent_containers/food/condiment/on_reagent_change() + if(reagents.reagent_list.len > 0) + switch(reagents.get_master_reagent_type()) + if(/datum/reagent/nutriment/ketchup) + name = "Ketchup" + desc = "You feel more American already." + icon_state = "ketchup" + center_of_mass = "x=16;y=6" + if(/datum/reagent/nutriment/barbecue) + name = "Barbecue Sauce" + desc = "Barbecue sauce, it's labeled 'sweet and spicy'" + icon_state = "barbecue" + center_of_mass = "x=16;y=6" + if(/datum/reagent/capsaicin) + name = "Hotsauce" + desc = "You can almost TASTE the stomach ulcers now!" + icon_state = "hotsauce" + center_of_mass = "x=16;y=6" + if(/datum/reagent/enzyme) + name = "Universal Enzyme" + desc = "Used in cooking various dishes." + icon_state = "enzyme" + center_of_mass = "x=16;y=6" + if(/datum/reagent/nutriment/soysauce) + name = "Soy Sauce" + desc = "A salty soy-based flavoring." + icon_state = "soysauce" + center_of_mass = "x=16;y=6" + if(/datum/reagent/frostoil) + name = "Coldsauce" + desc = "Leaves the tongue numb in its passage." + icon_state = "coldsauce" + center_of_mass = "x=16;y=6" + if(/datum/reagent/sodiumchloride) + name = "Salt Shaker" + desc = "Salt. From space oceans, presumably." + icon_state = "saltshaker" + center_of_mass = "x=16;y=10" + if(/datum/reagent/blackpepper) + name = "Pepper Mill" + desc = "Often used to flavor food or make people sneeze." + icon_state = "peppermillsmall" + center_of_mass = "x=16;y=10" + if(/datum/reagent/nutriment/cornoil) + name = "Corn Oil" + desc = "A delicious oil used in cooking. Made from corn." + icon_state = "oliveoil" + center_of_mass = "x=16;y=6" + if(/datum/reagent/sugar) + name = "Sugar" + desc = "Tastey space sugar!" + center_of_mass = "x=16;y=6" + else + name = "Misc Condiment Bottle" + if (reagents.reagent_list.len==1) + desc = "Looks like it is [reagents.get_master_reagent_name()], but you are not sure." + else + desc = "A mixture of various condiments. [reagents.get_master_reagent_name()] is one of them." + icon_state = "mixedcondiments" + center_of_mass = "x=16;y=6" + else + icon_state = "emptycondiment" + name = "Condiment Bottle" + desc = "An empty condiment bottle." + center_of_mass = "x=16;y=6" + if(label_text) + name = addtext(name," ([label_text])") + + return + +/obj/item/weapon/reagent_containers/food/condiment/enzyme + name = "Universal Enzyme" + desc = "Used in cooking various dishes." + icon_state = "enzyme" + +/obj/item/weapon/reagent_containers/food/condiment/enzyme/New() + . = ..() + reagents.add_reagent(/datum/reagent/enzyme, 50) + +/obj/item/weapon/reagent_containers/food/condiment/barbecue + name = "Barbecue Sauce" + desc = "Barbecue sauce, it's labeled 'sweet and spicy'" + icon_state = "barbecue" + +/obj/item/weapon/reagent_containers/food/condiment/barbecue/New() + . = ..() + reagents.add_reagent(/datum/reagent/nutriment/barbecue, 50) + +/obj/item/weapon/reagent_containers/food/condiment/sugar/New() + . = ..() + reagents.add_reagent(/datum/reagent/sugar, 50) + +/obj/item/weapon/reagent_containers/food/condiment/small + possible_transfer_amounts = "1;20" + amount_per_transfer_from_this = 1 + volume = 20 + +/obj/item/weapon/reagent_containers/food/condiment/small/on_reagent_change() + return + +/obj/item/weapon/reagent_containers/food/condiment/small/saltshaker + name = "salt shaker" + desc = "Salt. From space oceans, presumably." + icon_state = "saltshakersmall" + center_of_mass = "x=16;y=9" + +/obj/item/weapon/reagent_containers/food/condiment/small/saltshaker/New() + ..() + reagents.add_reagent(/datum/reagent/sodiumchloride, 20) + +/obj/item/weapon/reagent_containers/food/condiment/small/peppermill + name = "pepper mill" + desc = "Often used to flavor food or make people sneeze." + icon_state = "peppermillsmall" + center_of_mass = "x=16;y=8" + +/obj/item/weapon/reagent_containers/food/condiment/small/peppermill/New() + ..() + reagents.add_reagent(/datum/reagent/blackpepper, 20) + +/obj/item/weapon/reagent_containers/food/condiment/small/sugar + name = "sugar" + desc = "Sweetness in a bottle" + icon_state = "sugarsmall" + center_of_mass = "x=17;y=9" + +/obj/item/weapon/reagent_containers/food/condiment/small/sugar/New() + . = ..() + reagents.add_reagent(/datum/reagent/sugar, 20) + +/obj/item/weapon/reagent_containers/food/condiment/flour + name = "flour sack" + desc = "A big bag of flour. Good for baking!" + icon = 'icons/obj/food.dmi' + icon_state = "flour" + item_state = "flour" + randpixel = 10 + +/obj/item/weapon/reagent_containers/food/condiment/flour/on_reagent_change() + return + +/obj/item/weapon/reagent_containers/food/condiment/flour/New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/flour, 30) diff --git a/code/modules/reagents/reagent_containers/food/drinks.dm b/code/modules/reagents/reagent_containers/food/drinks.dm new file mode 100644 index 00000000..2ded5e6a --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/drinks.dm @@ -0,0 +1,423 @@ +//////////////////////////////////////////////////////////////////////////////// +/// Drinks. +//////////////////////////////////////////////////////////////////////////////// +/obj/item/weapon/reagent_containers/food/drinks + name = "drink" + desc = "Yummy!" + icon = 'icons/obj/drinks.dmi' + icon_state = null + atom_flags = ATOM_FLAG_OPEN_CONTAINER + amount_per_transfer_from_this = 5 + volume = 50 + var/filling_states // List of percentages full that have icons + var/base_name = null // Name to put in front of drinks, i.e. "[base_name] of [contents]" + var/base_icon = null // Base icon name for fill states + +/obj/item/weapon/reagent_containers/food/drinks/on_reagent_change() + update_icon() + return + +/obj/item/weapon/reagent_containers/food/drinks/attack_self(mob/user as mob) + open(user) + +/obj/item/weapon/reagent_containers/food/proc/open(mob/user) + if(is_open_container()) + return + playsound(loc, open_sound, rand(10,50), 1) + to_chat(user, "You open \the [src].") + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + +/obj/item/weapon/reagent_containers/food/drinks/attack(mob/M as mob, mob/user as mob, def_zone) + if(force && !(item_flags & ITEM_FLAG_NO_BLUDGEON) && user.a_intent == I_HURT) + return ..() + + if(standard_feed_mob(user, M)) + return + + return 0 + +/obj/item/weapon/reagent_containers/food/drinks/afterattack(obj/target, mob/user, proximity) + if(!proximity) return + + if(standard_dispenser_refill(user, target)) + return + if(standard_pour_into(user, target)) + return + return ..() + +/obj/item/weapon/reagent_containers/food/drinks/standard_feed_mob(var/mob/user, var/mob/target) + if(!is_open_container()) + to_chat(user, "You need to open \the [src]!") + return 1 + return ..() + +/obj/item/weapon/reagent_containers/food/drinks/standard_dispenser_refill(var/mob/user, var/obj/structure/reagent_dispensers/target) + if(!is_open_container()) + to_chat(user, "You need to open \the [src]!") + return 1 + return ..() + +/obj/item/weapon/reagent_containers/food/drinks/standard_pour_into(var/mob/user, var/atom/target) + if(!is_open_container()) + to_chat(user, "You need to open \the [src]!") + return 1 + return ..() + +/obj/item/weapon/reagent_containers/food/drinks/self_feed_message(var/mob/user) + to_chat(user, "You swallow a gulp from \the [src].") + +/obj/item/weapon/reagent_containers/food/drinks/feed_sound(var/mob/user) + playsound(user.loc, "drink", 100, FALSE) + +/obj/item/weapon/reagent_containers/food/drinks/examine(mob/user) + if(!..(user, 1)) + return + if(!reagents || reagents.total_volume == 0) + to_chat(user, "\The [src] is empty!") + else if (reagents.total_volume <= volume * 0.25) + to_chat(user, "\The [src] is almost empty!") + else if (reagents.total_volume <= volume * 0.66) + to_chat(user, "\The [src] is half full!") + else if (reagents.total_volume <= volume * 0.90) + to_chat(user, "\The [src] is almost full!") + else + to_chat(user, "\The [src] is full!") + +/obj/item/weapon/reagent_containers/food/drinks/proc/get_filling_state() + var/percent = round((reagents.total_volume / volume) * 100) + for(var/k in cached_number_list_decode(filling_states)) + if(percent <= k) + return k + +/obj/item/weapon/reagent_containers/food/drinks/update_icon() + overlays.Cut() + if(reagents.reagent_list.len > 0) + if(base_name) + var/datum/reagent/R = reagents.get_master_reagent() + SetName("[base_name] of [R.glass_name ? R.glass_name : "something"]") + desc = R.glass_desc ? R.glass_desc : initial(desc) + if(filling_states) + var/image/filling = image(icon, src, "[base_icon][get_filling_state()]") + filling.color = reagents.get_color() + overlays += filling + else + SetName(initial(name)) + desc = initial(desc) + + +//////////////////////////////////////////////////////////////////////////////// +/// Drinks. END +//////////////////////////////////////////////////////////////////////////////// + +/obj/item/weapon/reagent_containers/food/drinks/golden_cup + desc = "A golden cup." + name = "golden cup" + icon_state = "golden_cup" + item_state = "" //nope :( + w_class = ITEM_SIZE_HUGE + force = 14 + throwforce = 10 + amount_per_transfer_from_this = 20 + possible_transfer_amounts = null + volume = 150 + atom_flags = ATOM_FLAG_OPEN_CONTAINER + obj_flags = OBJ_FLAG_CONDUCTIBLE + +///////////////////////////////////////////////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. +// Formatting is the same as food. + +/obj/item/weapon/reagent_containers/food/drinks/canteen + name = "canteen" + desc = "Usually filled with water. Keeps most people from dying of dehydration." + icon_state = "canteen" + center_of_mass = "x=16;y=9" + volume = 50 + slot_flags = SLOT_TIE + +/obj/item/weapon/reagent_containers/food/drinks/canteen/New() + . = ..() + reagents.add_reagent(/datum/reagent/water, 50) + +/obj/item/weapon/reagent_containers/food/drinks/milk + name = "milk carton" + desc = "It's milk. White and nutritious goodness!" + icon_state = "milk" + item_state = "carton" + center_of_mass = "x=16;y=9" +/obj/item/weapon/reagent_containers/food/drinks/milk/New() + . = ..() + reagents.add_reagent(/datum/reagent/drink/milk, 50) + +/obj/item/weapon/reagent_containers/food/drinks/soymilk + name = "soymilk carton" + desc = "It's soy milk. White and nutritious goodness!" + icon_state = "soymilk" + item_state = "carton" + center_of_mass = "x=16;y=9" + New() + ..() + reagents.add_reagent(/datum/reagent/drink/milk/soymilk, 50) + +/obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton + name = "small milk carton" + volume = 30 + icon_state = "mini-milk" +/obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton/New() + ..() + reagents.add_reagent(/datum/reagent/drink/milk, 30) + +/obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton/chocolate + name = "small chocolate milk carton" + desc = "It's milk! This one is in delicious chocolate flavour." + +/obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton/chocolate/New() + ..() + reagents.add_reagent(/datum/reagent/drink/milk/chocolate, 30) + + +/obj/item/weapon/reagent_containers/food/drinks/coffee + name = "\improper Robust Coffee" + desc = "Careful, the beverage you're about to enjoy is extremely hot." + icon_state = "coffee" + center_of_mass = "x=15;y=10" +/obj/item/weapon/reagent_containers/food/drinks/coffee/New() + . = ..() + reagents.add_reagent(/datum/reagent/drink/coffee, 30) + +/obj/item/weapon/reagent_containers/food/drinks/tea + name = "cup of Duke Purple Tea" + desc = "An insult to Duke Purple is an insult to the Space Queen! Any proper gentleman will fight you, if you sully this tea." + icon_state = "teacup" + item_state = "coffee" + center_of_mass = "x=16;y=14" + filling_states = "100" + base_name = "cup" + base_icon = "teacup" + New() + ..() + reagents.add_reagent(/datum/reagent/drink/tea, 30) + +/obj/item/weapon/reagent_containers/food/drinks/ice + name = "cup of ice" + desc = "Careful, cold ice, do not chew." + icon_state = "coffee" + center_of_mass = "x=15;y=10" +/obj/item/weapon/reagent_containers/food/drinks/ice/New() + . = ..() + reagents.add_reagent(/datum/reagent/drink/ice, 30) + +/obj/item/weapon/reagent_containers/food/drinks/h_chocolate + name = "cup of Dutch hot coco" + desc = "Made in Space South America." + icon_state = "hot_coco" + item_state = "coffee" + center_of_mass = "x=15;y=13" +/obj/item/weapon/reagent_containers/food/drinks/h_chocolate/New() + . = ..() + reagents.add_reagent(/datum/reagent/drink/hot_coco, 30) + +/obj/item/weapon/reagent_containers/food/drinks/dry_ramen + name = "cup ramen" + gender = PLURAL + desc = "Just add 10ml water, self heats! A taste that reminds you of your school years." + icon_state = "ramen" + center_of_mass = "x=16;y=11" + New() + ..() + reagents.add_reagent(/datum/reagent/drink/dry_ramen, 30) + + +/obj/item/weapon/reagent_containers/food/drinks/sillycup + name = "paper cup" + desc = "A paper water cup." + icon_state = "water_cup_e" + possible_transfer_amounts = null + volume = 10 + center_of_mass = "x=16;y=12" + New() + ..() + on_reagent_change() + if(reagents.total_volume) + icon_state = "water_cup" + else + icon_state = "water_cup_e" + + +//////////////////////////drinkingglass and shaker// +//Note by Darem: This code handles the mixing of drinks. New drinks go in three places: In Chemistry-Reagents.dm (for the drink +// itself), in Chemistry-Recipes.dm (for the reaction that changes the components into the drink), and here (for the drinking glass +// icon states. + +/obj/item/weapon/reagent_containers/food/drinks/shaker + name = "shaker" + desc = "A metal shaker to mix drinks in." + icon_state = "shaker" + amount_per_transfer_from_this = 10 + possible_transfer_amounts = "5;10;15;25;30;60" //Professional bartender should be able to transfer as much as needed + volume = 120 + center_of_mass = "x=17;y=10" + +/obj/item/weapon/reagent_containers/food/drinks/teapot + name = "teapot" + desc = "An elegant teapot. It simply oozes class." + icon_state = "teapot" + item_state = "teapot" + amount_per_transfer_from_this = 10 + volume = 120 + center_of_mass = "x=17;y=7" + +/obj/item/weapon/reagent_containers/food/drinks/pitcher + name = "pitcher" + desc = "Everyone's best friend in the morning." + icon_state = "pitcher" + volume = 120 + amount_per_transfer_from_this = 10 + center_of_mass = "x=16;y=9" + filling_states = "15;30;50;70;85;100" + base_icon = "pitcher" + +/obj/item/weapon/reagent_containers/food/drinks/flask + name = "\improper Captain's flask" + desc = "A metal flask belonging to the captain." + icon_state = "flask" + volume = 60 + center_of_mass = "x=17;y=7" + +/obj/item/weapon/reagent_containers/food/drinks/flask/shiny + name = "shiny flask" + desc = "A shiny metal flask. It appears to have a Greek symbol inscribed on it." + icon_state = "shinyflask" + +/obj/item/weapon/reagent_containers/food/drinks/flask/lithium + name = "lithium flask" + desc = "A flask with a Lithium Atom symbol on it." + icon_state = "lithiumflask" + +/obj/item/weapon/reagent_containers/food/drinks/flask/detflask + name = "\improper Detective's flask" + desc = "A metal flask with a leather band and golden badge belonging to the detective." + icon_state = "detflask" + volume = 60 + center_of_mass = "x=17;y=8" + +/obj/item/weapon/reagent_containers/food/drinks/flask/barflask + name = "flask" + desc = "For those who can't be bothered to hang out at the bar to drink." + icon_state = "barflask" + volume = 60 + center_of_mass = "x=17;y=7" + +/obj/item/weapon/reagent_containers/food/drinks/flask/vacuumflask + name = "vacuum flask" + desc = "Keeping your drinks at the perfect temperature since 1892." + icon_state = "vacuumflask" + volume = 60 + center_of_mass = "x=15;y=4" + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup + name = "coffee cup" + desc = "A plain white coffee cup." + icon_state = "coffeecup" + item_state = "coffee" + volume = 30 + center_of_mass = "x=15;y=13" + filling_states = "40;80;100" + base_name = "cup" + base_icon = "coffeecup" + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup/black + name = "black coffee cup" + desc = "A sleek black coffee cup." + icon_state = "coffeecup_black" + base_name = "black cup" + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup/green + name = "green coffee cup" + desc = "A pale green and pink coffee cup." + icon_state = "coffeecup_green" + base_name = "green cup" + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup/heart + name = "heart coffee cup" + desc = "A white coffee cup, it prominently features a red heart." + icon_state = "coffeecup_heart" + base_name = "heart cup" + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup/SCG + name = "SCG coffee cup" + desc = "A blue coffee cup emblazoned with the crest of the Sol Central Government." + icon_state = "coffeecup_SCG" + base_name = "SCG cup" + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup/NT + name = "NT coffee cup" + desc = "A red NanoTrasen coffee cup. 90% Guaranteed to not be laced with mind-control drugs." + icon_state = "coffeecup_NT" + base_name = "NT cup" + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup/one + name = "#1 coffee cup" + desc = "A white coffee cup, prominently featuring a #1." + icon_state = "coffeecup_one" + base_name = "#1 cup" + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup/punitelli + name = "#1 monkey coffee cup" + desc = "A white coffee cup, prominently featuring a \"#1 monkey\"." + icon_state = "coffeecup_punitelli" + base_name = "#1 monkey cup" + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup/punitelli/New() + ..() + reagents.add_reagent(/datum/reagent/drink/juice/banana, 30) + update_icon() + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup/rainbow + name = "rainbow coffee cup" + desc = "A rainbow coffee cup. The colors are almost as blinding as a welder." + icon_state = "coffeecup_rainbow" + base_name = "rainbow cup" + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup/metal + name = "metal coffee cup" + desc = "A metal coffee cup. You're not sure which metal." + icon_state = "coffeecup_metal" + base_name = "metal cup" + atom_flags = ATOM_FLAG_OPEN_CONTAINER + obj_flags = OBJ_FLAG_CONDUCTIBLE + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup/STC + name = "TCC coffee cup" + desc = "A coffee cup adorned with the flag of the Terran Colonial Confederation, for when you need some espionage charges to go with your morning coffee." + icon_state = "coffeecup_STC" + base_name = "TCC cup" + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup/pawn + name = "pawn coffee cup" + desc = "A black coffee cup adorned with the image of a red chess pawn." + icon_state = "coffeecup_pawn" + base_name = "pawn cup" + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup/diona + name = "diona nymph coffee cup" + desc = "A green coffee cup featuring the image of a diona nymph." + icon_state = "coffeecup_diona" + base_name = "diona cup" + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup/britcup + name = "british coffee cup" + desc = "A coffee cup with the British flag emblazoned on it." + icon_state = "coffeecup_brit" + base_name = "british cup" + +/obj/item/weapon/reagent_containers/food/drinks/coffeecup/tall + name = "tall coffee cup" + desc = "An unreasonably tall coffee cup, for when you really need to wake up in the morning." + icon_state = "coffeecup_tall" + volume = 60 + center_of_mass = "x=15;y=19" + filling_states = "50;70;90;100" + base_name = "tall cup" + base_icon = "coffeecup_tall" \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm new file mode 100644 index 00000000..410d7245 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm @@ -0,0 +1,492 @@ +///////////////////////////////////////////////Alchohol bottles! -Agouri ////////////////////////// +//Functionally identical to regular drinks. The only difference is that the default bottle size is 100. - Darem +//Bottles now weaken and break when smashed on people's heads. - Giacom + +/obj/item/weapon/reagent_containers/food/drinks/bottle + amount_per_transfer_from_this = 10 + volume = 100 + item_state = "broken_beer" //Generic held-item sprite until unique ones are made. + force = 5 + var/smash_duration = 5 //Directly relates to the 'weaken' duration. Lowered by armor (i.e. helmets) + var/isGlass = 1 //Whether the 'bottle' is made of glass or not so that milk cartons dont shatter when someone gets hit by it + + var/obj/item/weapon/reagent_containers/glass/rag/rag = null + var/rag_underlay = "rag" + table_sound = 'sound/items/placing_glass2.ogg' + drop_sound = 'sound/items/drop_glass.ogg' + table_pickup_sound = 'sound/items/generic_lift.ogg' + + +/obj/item/weapon/reagent_containers/food/drinks/bottle/New() + ..() + if(isGlass) unacidable = 1 + +/obj/item/weapon/reagent_containers/food/drinks/bottle/Destroy() + if(rag) + rag.forceMove(src.loc) + rag = null + return ..() + +//when thrown on impact, bottles smash and spill their contents +/obj/item/weapon/reagent_containers/food/drinks/bottle/throw_impact(atom/hit_atom, var/speed) + ..() + + var/mob/M = thrower + if(isGlass && istype(M) && M.a_intent != I_HELP) + 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]!") + reagents.splash(hit_atom, reagents.total_volume) + smash(loc, hit_atom) + +//Smashes when shot. +/obj/item/weapon/reagent_containers/food/drinks/bottle/bullet_act(obj/item/projectile/P) + . = ..() + if(!(P.nodamage) && P.damage_type == BRUTE && !QDELETED(src)) + var/atom/T = get_turf(src) + smash(T) + return + +/obj/item/weapon/reagent_containers/food/drinks/bottle/proc/smash_check(var/distance) + if(!isGlass || !smash_duration) + return 0 + + var/list/chance_table = list(95, 95, 90, 85, 75, 60, 40, 15) //starting from distance 0 + var/idx = max(distance + 1, 1) //since list indices start at 1 + if(idx > chance_table.len) + return 0 + return prob(chance_table[idx]) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/proc/smash(var/newloc, atom/against = null) + if(ismob(loc)) + var/mob/M = loc + M.drop_from_inventory(src) + + //Creates a shattering noise and replaces the bottle with a broken_bottle + var/obj/item/weapon/broken_bottle/B = new /obj/item/weapon/broken_bottle(newloc) + if(prob(33)) + new/obj/item/weapon/material/shard(newloc) // Create a glass shard at the target's location! + B.icon_state = src.icon_state + + var/icon/I = new('icons/obj/drinks.dmi', src.icon_state) + I.Blend(B.broken_outline, ICON_OVERLAY, rand(5), 1) + I.SwapColor(rgb(255, 0, 220, 255), rgb(0, 0, 0, 0)) + B.icon = I + + if(rag && rag.on_fire && isliving(against)) + rag.forceMove(loc) + var/mob/living/L = against + L.IgniteMob() + + playsound(src, "shatter", 70, 1) + src.transfer_fingerprints_to(B) + + qdel(src) + return B + +/obj/item/weapon/reagent_containers/food/drinks/bottle/attackby(obj/item/W, mob/user) + if(!rag && istype(W, /obj/item/weapon/reagent_containers/glass/rag)) + insert_rag(W, user) + return + if(rag && istype(W, /obj/item/weapon/flame)) + rag.attackby(W, user) + return + ..() + +/obj/item/weapon/reagent_containers/food/drinks/bottle/attack_self(mob/user) + if(rag) + remove_rag(user) + else + ..() + +/obj/item/weapon/reagent_containers/food/drinks/bottle/proc/insert_rag(obj/item/weapon/reagent_containers/glass/rag/R, mob/user) + if(!isGlass || rag) return + if(user.unEquip(R)) + to_chat(user, "You stuff [R] into [src].") + rag = R + rag.forceMove(src) + atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER + update_icon() + +/obj/item/weapon/reagent_containers/food/drinks/bottle/proc/remove_rag(mob/user) + if(!rag) return + user.put_in_hands(rag) + rag = null + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + update_icon() + +/obj/item/weapon/reagent_containers/food/drinks/bottle/open(mob/user) + if(rag) return + ..() + +/obj/item/weapon/reagent_containers/food/drinks/bottle/update_icon() + underlays.Cut() + if(rag) + var/underlay_image = image(icon='icons/obj/drinks.dmi', icon_state=rag.on_fire? "[rag_underlay]_lit" : rag_underlay) + underlays += underlay_image + set_light(rag.light_range, rag.light_power, rag.light_color) + 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) + return + if(!smash_check(1)) + return //won't always break on the first hit + + // You are going to knock someone out for longer if they are not wearing a helmet. + var/weaken_duration = 0 + if(blocked < 100) + weaken_duration = smash_duration + min(0, force - target.getarmor(hit_zone, "melee") + 10) + + 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! + else + user.visible_message("\The [user] smashes [src] into [target]!") + + //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 = smash(target.loc, target) + user.put_in_active_hand(B) + + return blocked + +//Keeping this here for now, I'll ask if I should keep it here. +/obj/item/weapon/broken_bottle + + name = "Broken Bottle" + desc = "A bottle with a sharp broken bottom." + icon = 'icons/obj/drinks.dmi' + icon_state = "broken_bottle" + force = 9 + throwforce = 5 + throw_speed = 3 + throw_range = 5 + item_state = "beer" + attack_verb = list("stabbed", "slashed", "attacked") + sharp = 1 + edge = 0 + var/icon/broken_outline = icon('icons/obj/drinks.dmi', "broken") + +/obj/item/weapon/broken_bottle/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/reagent_containers/food/drinks/bottle/gin + name = "Griffeater Gin" + desc = "A bottle of high quality gin, produced in the New London Space Station." + icon_state = "ginbottle" + center_of_mass = "x=16;y=4" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/gin, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/whiskey + name = "Uncle Cap's Special Reserve" + desc = "A premium single-malt whiskey, gently matured inside the tunnels of a nuclear shelter. TUNNEL WHISKEY RULES." + icon_state = "whiskeybottle" + center_of_mass = "x=16;y=3" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/whiskey, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/specialwhiskey + name = "Special Blend Whiskey" + desc = "Just when you thought regular whiskey was good... This silky, amber goodness has to come along and ruin everything." + icon_state = "whiskeybottle2" + center_of_mass = "x=16;y=3" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/specialwhiskey, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/vodka + name = "Tunguska Triple Distilled" + desc = "Aah, vodka. Prime choice of drink AND fuel by Terrans around the galaxy." + icon_state = "vodkabottle" + center_of_mass = "x=17;y=3" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/vodka, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/tequilla + name = "Caccavo Guaranteed Quality Tequilla" + desc = "Made from premium petroleum distillates, pure thalidomide and other fine quality ingredients!" + icon_state = "tequillabottle" + center_of_mass = "x=16;y=3" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/tequilla, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/bottleofnothing + name = "Bottle of Nothing" + desc = "A bottle filled with nothing." + icon_state = "bottleofnothing" + center_of_mass = "x=17;y=5" + New() + ..() + reagents.add_reagent(/datum/reagent/drink/nothing, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/patron + name = "Wrapp Artiste Patron" + desc = "Silver laced tequilla, served in space night clubs across the galaxy." + icon_state = "patronbottle" + center_of_mass = "x=16;y=6" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/patron, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/rum + name = "Captain Pete's Cuban Spiced Rum" + desc = "This isn't just rum, oh no. It's practically GRIFF in a bottle." + icon_state = "rumbottle" + center_of_mass = "x=16;y=8" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/rum, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/holywater + name = "Flask of Holy Water" + desc = "A flask of the chaplain's holy water." + icon_state = "holyflask" + center_of_mass = "x=17;y=10" + New() + ..() + reagents.add_reagent(/datum/reagent/water/holywater, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/vermouth + name = "Goldeneye Vermouth" + desc = "Sweet, sweet dryness~" + icon_state = "vermouthbottle" + center_of_mass = "x=17;y=3" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/vermouth, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/kahlua + name = "Robert Robust's Coffee Liqueur" + desc = "A widely known, Mexican coffee-flavoured liqueur. In production since 1936, HONK!" + icon_state = "kahluabottle" + center_of_mass = "x=17;y=3" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/coffee/kahlua, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/goldschlager + name = "College Girl Goldschlager" + desc = "Because they are the only ones who will drink 100 proof cinnamon schnapps." + icon_state = "goldschlagerbottle" + center_of_mass = "x=15;y=3" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/goldschlager, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/cognac + name = "Chateau De Baton Premium Cognac" + desc = "A sweet and strongly alchoholic drink, made after numerous distillations and years of maturing. You might as well not scream 'SHITCURITY' this time." + icon_state = "cognacbottle" + center_of_mass = "x=16;y=6" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/cognac, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/wine + name = "Vintage Orphan Blood Wine" + desc = "A faint aura of unease surrounds the bottle. If you listen closely, you can still hear the screams." + icon_state = "winebottle" + center_of_mass = "x=16;y=4" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/wine, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/absinthe + name = "Jailbreaker Verte" + desc = "One sip of this and you just know you're gonna have a good time." + icon_state = "absinthebottle" + center_of_mass = "x=16;y=6" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/absinthe, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/melonliquor + name = "Emeraldine Melon Liquor" + desc = "A bottle of 46 proof Emeraldine Melon Liquor. Sweet and light." + icon_state = "alco-green" //Placeholder. + center_of_mass = "x=16;y=6" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/melonliquor, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/bluecuracao + name = "Miss Blue Curacao" + desc = "A fruity, exceptionally azure drink. Does not allow the imbiber to use the fifth magic." + icon_state = "alco-blue" //Placeholder. + center_of_mass = "x=16;y=6" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/bluecuracao, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/herbal + name = "Liqueur d'Herbe" + desc = "A bottle of the seventh-finest herbal liquor sold under a generic name in the galaxy. The back label has a load of guff about the monks who traditionally made this particular variety." + icon_state = "herbal" + center_of_mass = "x=16;y=6" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/herbal, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/grenadine + name = "Briar Rose Grenadine Syrup" + desc = "Sweet and tangy, a bar syrup used to add color or flavor to drinks." + icon_state = "grenadinebottle" + center_of_mass = "x=16;y=6" + New() + ..() + reagents.add_reagent(/datum/reagent/drink/grenadine, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/cola + name = "\improper Space Cola" + desc = "Cola. in space." + icon_state = "colabottle" + center_of_mass = "x=16;y=6" + New() + ..() + reagents.add_reagent(/datum/reagent/drink/space_cola, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/space_up + name = "\improper Space-Up" + desc = "Tastes like a hull breach in your mouth." + icon_state = "space-up_bottle" + center_of_mass = "x=16;y=6" + New() + ..() + reagents.add_reagent(/datum/reagent/drink/space_up, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/space_mountain_wind + name = "\improper Trench Mountain Wind" + desc = "Blows right through you like a mortar wind." + icon_state = "space_mountain_wind_bottle" + center_of_mass = "x=16;y=6" + New() + ..() + reagents.add_reagent(/datum/reagent/drink/spacemountainwind, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/pwine + name = "Warlock's Velvet" + desc = "What a delightful packaging for a surely high quality wine! The vintage must be amazing!" + icon_state = "pwinebottle" + center_of_mass = "x=16;y=4" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/pwine, 100) + +//////////////////////////PREMIUM ALCOHOL /////////////////////// +/obj/item/weapon/reagent_containers/food/drinks/bottle/premiumvodka + name = "Four Stripes Quadruple Distilled" + desc = "Premium distilled vodka imported directly from the Terran Colonial Confederation." + icon_state = "premiumvodka" + center_of_mass = "x=17;y=3" + +/obj/item/weapon/reagent_containers/food/drinks/bottle/premiumvodka/New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/vodka/premium, 100) + var/namepick = pick("Four Stripes","Gilgamesh","Novaya Zemlya","Terran","STS-35") + var/typepick = pick("Absolut","Gold","Quadruple Distilled","Platinum","Standard") + name = "[namepick] [typepick]" + +/obj/item/weapon/reagent_containers/food/drinks/bottle/premiumwine + name = "Uve De Blanc" + desc = "You feel pretentious just looking at it." + icon_state = "premiumwine" + center_of_mass = "x=16;y=4" + +/obj/item/weapon/reagent_containers/food/drinks/bottle/premiumwine/New() + ..() + reagents.add_reagent(/datum/reagent/ethanol/wine/premium, 100) + var/namepick = pick("Calumont","Sciacchemont","Recioto","Torcalota") + var/agedyear = rand(2350,2550) + name = "Chateau [namepick] De Blanc" + desc += " This bottle is marked as [agedyear] Vintage." + +//////////////////////////JUICES AND STUFF /////////////////////// + +/obj/item/weapon/reagent_containers/food/drinks/bottle/orangejuice + name = "Orange Juice" + desc = "Full of vitamins and deliciousness!" + icon_state = "orangejuice" + item_state = "carton" + center_of_mass = "x=16;y=7" + isGlass = 0 + New() + ..() + reagents.add_reagent(/datum/reagent/drink/juice/orange, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/cream + name = "Milk Cream" + desc = "It's cream. Made from milk. What else did you think you'd find in there?" + icon_state = "cream" + item_state = "carton" + center_of_mass = "x=16;y=8" + isGlass = 0 + New() + ..() + reagents.add_reagent(/datum/reagent/drink/milk/cream, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/tomatojuice + name = "Tomato Juice" + desc = "Well, at least it LOOKS like tomato juice. You can't tell with all that redness." + icon_state = "tomatojuice" + item_state = "carton" + center_of_mass = "x=16;y=8" + isGlass = 0 + New() + ..() + reagents.add_reagent(/datum/reagent/drink/juice/tomato, 100) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/limejuice + name = "Lime Juice" + desc = "Sweet-sour goodness." + icon_state = "limejuice" + item_state = "carton" + center_of_mass = "x=16;y=8" + isGlass = 0 + New() + ..() + reagents.add_reagent(/datum/reagent/drink/juice/lime, 100) + +//Small bottles +/obj/item/weapon/reagent_containers/food/drinks/bottle/small + volume = 50 + smash_duration = 1 + atom_flags = 0 //starts closed + rag_underlay = "rag_small" + +/obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer + name = "trench beer" + desc = "Contains only water, malt and hops." + icon_state = "beer" + center_of_mass = "x=16;y=12" +/obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer/New() + . = ..() + reagents.add_reagent(/datum/reagent/ethanol/beer, 30) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/small/ale + name = "\improper Magm-Ale" + desc = "A true dorf's drink of choice." + icon_state = "alebottle" + item_state = "beer" + center_of_mass = "x=16;y=10" +/obj/item/weapon/reagent_containers/food/drinks/bottle/small/ale/New() + . = ..() + reagents.add_reagent(/datum/reagent/ethanol/ale, 30) diff --git a/code/modules/reagents/reagent_containers/food/drinks/bottle/robot.dm b/code/modules/reagents/reagent_containers/food/drinks/bottle/robot.dm new file mode 100644 index 00000000..e69de29b diff --git a/code/modules/reagents/reagent_containers/food/drinks/jar.dm b/code/modules/reagents/reagent_containers/food/drinks/jar.dm new file mode 100644 index 00000000..1b892846 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/drinks/jar.dm @@ -0,0 +1,22 @@ + + +///jar + +/obj/item/weapon/reagent_containers/food/drinks/jar + name = "empty jar" + desc = "A jar. You're not sure what it's supposed to hold." + icon_state = "jar" + item_state = "beaker" + center_of_mass = "x=15;y=8" + unacidable = 1 + +/obj/item/weapon/reagent_containers/food/drinks/jar/on_reagent_change() + if (reagents.reagent_list.len > 0) + icon_state ="jar_what" + SetName("jar of something") + desc = "You can't really tell what this is." + else + icon_state = initial(icon_state) + SetName(initial(name)) + desc = "A jar. You're not sure what it's supposed to hold." + return diff --git a/code/modules/reagents/reagent_containers/food/lunch.dm b/code/modules/reagents/reagent_containers/food/lunch.dm new file mode 100644 index 00000000..06066a90 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/lunch.dm @@ -0,0 +1,125 @@ +var/list/lunchables_lunches_ = list( + /obj/item/weapon/reagent_containers/food/snacks/sandwich, + /obj/item/weapon/reagent_containers/food/snacks/slice/meatbread/filled, + /obj/item/weapon/reagent_containers/food/snacks/slice/tofubread/filled, + /obj/item/weapon/reagent_containers/food/snacks/slice/creamcheesebread/filled, + /obj/item/weapon/reagent_containers/food/snacks/slice/margherita/filled, + /obj/item/weapon/reagent_containers/food/snacks/slice/meatpizza/filled, + /obj/item/weapon/reagent_containers/food/snacks/slice/mushroompizza/filled, + /obj/item/weapon/reagent_containers/food/snacks/slice/vegetablepizza/filled, + /obj/item/weapon/reagent_containers/food/snacks/tastybread, + /obj/item/weapon/reagent_containers/food/snacks/liquidfood, + /obj/item/weapon/reagent_containers/food/snacks/jellysandwich/cherry, + /obj/item/weapon/reagent_containers/food/snacks/tossedsalad + ) + +var/list/lunchables_snacks_ = list( + /obj/item/weapon/reagent_containers/food/snacks/donut/jelly, + /obj/item/weapon/reagent_containers/food/snacks/donut/cherryjelly, + /obj/item/weapon/reagent_containers/food/snacks/muffin, + /obj/item/weapon/reagent_containers/food/snacks/popcorn, + /obj/item/weapon/reagent_containers/food/snacks/sosjerky, + /obj/item/weapon/reagent_containers/food/snacks/no_raisin, + /obj/item/weapon/reagent_containers/food/snacks/spacetwinkie, + /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers, + /obj/item/weapon/reagent_containers/food/snacks/poppypretzel, + /obj/item/weapon/reagent_containers/food/snacks/carrotfries, + /obj/item/weapon/reagent_containers/food/snacks/candiedapple, + /obj/item/weapon/reagent_containers/food/snacks/applepie, + /obj/item/weapon/reagent_containers/food/snacks/cherrypie, + /obj/item/weapon/reagent_containers/food/snacks/plumphelmetbiscuit, + /obj/item/weapon/reagent_containers/food/snacks/appletart, + /obj/item/weapon/reagent_containers/food/snacks/slice/carrotcake/filled, + /obj/item/weapon/reagent_containers/food/snacks/slice/cheesecake/filled, + /obj/item/weapon/reagent_containers/food/snacks/slice/plaincake/filled, + /obj/item/weapon/reagent_containers/food/snacks/slice/orangecake/filled, + /obj/item/weapon/reagent_containers/food/snacks/slice/limecake/filled, + /obj/item/weapon/reagent_containers/food/snacks/slice/lemoncake/filled, + /obj/item/weapon/reagent_containers/food/snacks/slice/chocolatecake/filled, + /obj/item/weapon/reagent_containers/food/snacks/slice/birthdaycake/filled, + /obj/item/weapon/reagent_containers/food/snacks/watermelonslice, + /obj/item/weapon/reagent_containers/food/snacks/slice/applecake/filled, + /obj/item/weapon/reagent_containers/food/snacks/slice/pumpkinpie/filled, + /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks + ) + +var/list/lunchables_drinks_ = list( + /obj/item/weapon/reagent_containers/food/drinks/cans/cola, + /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle, + /obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind, + /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb, + /obj/item/weapon/reagent_containers/food/drinks/cans/starkist, + /obj/item/weapon/reagent_containers/food/drinks/cans/space_up, + /obj/item/weapon/reagent_containers/food/drinks/cans/lemon_lime, + /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea, + /obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice, + /obj/item/weapon/reagent_containers/food/drinks/cans/tonic, + /obj/item/weapon/reagent_containers/food/drinks/cans/sodawater + ) + +// This default list is a bit different, it contains items we don't want +var/list/lunchables_drink_reagents_ = list( + /datum/reagent/drink/nothing, + /datum/reagent/drink/doctor_delight, + /datum/reagent/drink/dry_ramen, + /datum/reagent/drink/hell_ramen, + /datum/reagent/drink/hot_ramen, + /datum/reagent/drink/nuka_cola + ) + +// This default list is a bit different, it contains items we don't want +var/list/lunchables_ethanol_reagents_ = list( + /datum/reagent/ethanol/acid_spit, + /datum/reagent/ethanol/atomicbomb, + /datum/reagent/ethanol/beepsky_smash, + /datum/reagent/ethanol/coffee, + /datum/reagent/ethanol/hippies_delight, + /datum/reagent/ethanol/hooch, + /datum/reagent/ethanol/thirteenloko, + /datum/reagent/ethanol/manhattan_proj, + /datum/reagent/ethanol/neurotoxin, + /datum/reagent/ethanol/pwine, + /datum/reagent/ethanol/threemileisland, + /datum/reagent/ethanol/toxins_special + ) + +/proc/lunchables_lunches() + if(!(lunchables_lunches_[lunchables_lunches_[1]])) + lunchables_lunches_ = init_lunchable_list(lunchables_lunches_) + return lunchables_lunches_ + +/proc/lunchables_snacks() + if(!(lunchables_snacks_[lunchables_snacks_[1]])) + lunchables_snacks_ = init_lunchable_list(lunchables_snacks_) + return lunchables_snacks_ + +/proc/lunchables_drinks() + if(!(lunchables_drinks_[lunchables_drinks_[1]])) + lunchables_drinks_ = init_lunchable_list(lunchables_drinks_) + return lunchables_drinks_ + +/proc/lunchables_drink_reagents() + if(!(lunchables_drink_reagents_[lunchables_drink_reagents_[1]])) + lunchables_drink_reagents_ = init_lunchable_reagent_list(lunchables_drink_reagents_, /datum/reagent/drink) + return lunchables_drink_reagents_ + +/proc/lunchables_ethanol_reagents() + if(!(lunchables_ethanol_reagents_[lunchables_ethanol_reagents_[1]])) + lunchables_ethanol_reagents_ = init_lunchable_reagent_list(lunchables_ethanol_reagents_, /datum/reagent/ethanol) + return lunchables_ethanol_reagents_ + +/proc/init_lunchable_list(var/list/lunches) + . = list() + for(var/lunch in lunches) + var/obj/O = lunch + .[initial(O.name)] = lunch + return sortAssoc(.) + +/proc/init_lunchable_reagent_list(var/list/banned_reagents, var/reagent_types) + . = list() + for(var/reagent_type in subtypesof(reagent_types)) + if(reagent_type in banned_reagents) + continue + var/datum/reagent/reagent = reagent_type + .[initial(reagent.name)] = reagent_type + return sortAssoc(.) diff --git a/code/modules/reagents/reagent_containers/food/sandwich.dm b/code/modules/reagents/reagent_containers/food/sandwich.dm new file mode 100644 index 00000000..bd4e2a6a --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/sandwich.dm @@ -0,0 +1,101 @@ +/obj/item/weapon/reagent_containers/food/snacks/slice/bread/attackby(obj/item/W as obj, mob/user as mob) + + if(istype(W,/obj/item/weapon/material/shard) || istype(W,/obj/item/weapon/reagent_containers/food/snacks)) + var/obj/item/weapon/reagent_containers/food/snacks/csandwich/S = new(get_turf(src)) + S.attackby(W,user) + qdel(src) + ..() + +/obj/item/weapon/reagent_containers/food/snacks/csandwich + name = "sandwich" + desc = "The best thing since sliced bread." + icon_state = "breadslice" + trash = /obj/item/trash/plate + bitesize = 2 + + var/list/ingredients = list() + +/obj/item/weapon/reagent_containers/food/snacks/csandwich/attackby(obj/item/W as obj, mob/user as mob) + + var/sandwich_limit = 4 + for(var/obj/item/O in ingredients) + if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/slice/bread)) + sandwich_limit += 4 + + if(src.contents.len > sandwich_limit) + to_chat(user, "If you put anything else on \the [src] it's going to collapse.") + return + else if(istype(W,/obj/item/weapon/material/shard)) + to_chat(user, "You hide [W] in \the [src].") + user.drop_item() + W.loc = src + update() + return + else if(istype(W,/obj/item/weapon/reagent_containers/food/snacks)) + to_chat(user, "You layer [W] over \the [src].") + var/obj/item/weapon/reagent_containers/F = W + F.reagents.trans_to_obj(src, F.reagents.total_volume) + user.drop_item() + W.loc = src + ingredients += W + update() + return + ..() + +/obj/item/weapon/reagent_containers/food/snacks/csandwich/proc/update() + var/fullname = "" //We need to build this from the contents of the var. + var/i = 0 + + overlays.Cut() + + for(var/obj/item/weapon/reagent_containers/food/snacks/O in ingredients) + + i++ + if(i == 1) + fullname += "[O.name]" + else if(i == ingredients.len) + fullname += " and [O.name]" + else + fullname += ", [O.name]" + + var/image/I = new(src.icon, "sandwich_filling") + I.color = O.filling_color + I.pixel_x = pick(list(-1,0,1)) + I.pixel_y = (i*2)+1 + overlays += I + + var/image/T = new(src.icon, "sandwich_top") + T.pixel_x = pick(list(-1,0,1)) + T.pixel_y = (ingredients.len * 2)+1 + overlays += T + + SetName(lowertext("[fullname] sandwich")) + if(length(name) > 80) SetName("[pick(list("absurd","colossal","enormous","ridiculous"))] sandwich") + w_class = n_ceil(Clamp((ingredients.len/2),2,4)) + +/obj/item/weapon/reagent_containers/food/snacks/csandwich/Destroy() + for(var/obj/item/O in ingredients) + qdel(O) + ..() + +/obj/item/weapon/reagent_containers/food/snacks/csandwich/examine(mob/user) + . = ..(user) + var/obj/item/O = pick(contents) + to_chat(user, "You think you can see [O.name] in there.") + +/obj/item/weapon/reagent_containers/food/snacks/csandwich/attack(mob/M as mob, mob/user as mob, def_zone) + + var/obj/item/shard + for(var/obj/item/O in contents) + if(istype(O,/obj/item/weapon/material/shard)) + shard = O + break + + var/mob/living/H + if(istype(M,/mob/living)) + H = M + + if(H && shard && M == user) //This needs a check for feeding the food to other people, but that could be abusable. + to_chat(H, "You lacerate your mouth on a [shard.name] in the sandwich!") + H.adjustBruteLoss(5) //TODO: Target head if human. + ..() diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm new file mode 100644 index 00000000..126687ca --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -0,0 +1,3393 @@ +//Food items that are eaten normally and don't leave anything behind. +/obj/item/weapon/reagent_containers/food/snacks + name = "snack" + desc = "Yummy!" + icon = 'icons/obj/food.dmi' + icon_state = null + var/bitesize = 1 + var/bitecount = 0 + var/slice_path + var/slices_num + var/dried_type = null + var/dry = 0 + var/nutriment_amt = 0 + var/list/nutriment_desc = list("food" = 1) + center_of_mass = "x=16;y=16" + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/reagent_containers/food/snacks/New() + ..() + if(nutriment_amt) + reagents.add_reagent(/datum/reagent/nutriment,nutriment_amt,nutriment_desc) + + //Placeholder for effect that trigger on eating that aren't tied to reagents. +/obj/item/weapon/reagent_containers/food/snacks/proc/On_Consume(var/mob/M) + if(!reagents.total_volume) + M.visible_message("[M] finishes eating \the [src].","You finish eating \the [src].") + + M.drop_item() + if(trash) + if(ispath(trash,/obj/item)) + var/obj/item/TrashItem = new trash(get_turf(M)) + M.put_in_hands(TrashItem) + else if(istype(trash,/obj/item)) + M.put_in_hands(trash) + qdel(src) + return + +/obj/item/weapon/reagent_containers/food/snacks/attack_self(mob/user as mob) + return + +/obj/item/weapon/reagent_containers/food/snacks/attack(mob/M as mob, mob/user as mob, def_zone) + if(!reagents.total_volume) + to_chat(user, "None of [src] left!") + user.drop_from_inventory(src) + qdel(src) + return 0 + + if(istype(M, /mob/living/carbon)) + //TODO: replace with standard_feed_mob() call. + var/mob/living/carbon/C = M + var/fullness = C.nutrition + (C.reagents.get_reagent_amount(/datum/reagent/nutriment) * 10) + if(C == user) //If you're eating it yourself + if(istype(C,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(!H.check_has_mouth()) + to_chat(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) + to_chat(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) + to_chat(C, "You hungrily chew out a piece of [src] and gobble it!") + if (fullness > 50 && fullness <= 150) + to_chat(C, "You hungrily begin to eat [src].") + if (fullness > 150 && fullness <= 350) + to_chat(C, "You take a bite of [src].") + if (fullness > 350 && fullness <= 550) + to_chat(C, "You unwillingly chew a bit of [src].") + if (fullness > 550) + to_chat(C, "You cannot force any more of [src] to go down your throat.") + return 0 + else + if(!M.can_force_feed(user, src)) + return + + if (fullness <= 550) + 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 + + var/contained = reagentlist() + admin_attack_log(user, M, "Fed the victim with [name] (Reagents: [contained])", "Was fed [src] (Reagents: [contained])", "used [src] (Reagents: [contained]) to feed") + user.visible_message("[user] feeds [M] [src].") + + if(reagents) //Handle ingestion of the reagent. + playsound(M.loc,"eat", 100, FALSE) + if(reagents.total_volume) + if(reagents.total_volume > bitesize) + reagents.trans_to_mob(M, bitesize, CHEM_INGEST) + else + reagents.trans_to_mob(M, reagents.total_volume, CHEM_INGEST) + bitecount++ + On_Consume(M) + return 1 + + return 0 + +/obj/item/weapon/reagent_containers/food/snacks/examine(mob/user) + if(!..(user, 1)) + return + if (bitecount==0) + return + else if (bitecount==1) + to_chat(user, "\The [src] was bitten by someone!") + else if (bitecount<=3) + to_chat(user, "\The [src] was bitten [bitecount] time\s!") + else + to_chat(user, "\The [src] was bitten multiple times!") + +/obj/item/weapon/reagent_containers/food/snacks/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/weapon/storage)) + ..() // -> item/attackby() + return + + // Eating with forks + if(istype(W,/obj/item/weapon/material/kitchen/utensil)) + var/obj/item/weapon/material/kitchen/utensil/U = W + if(U.scoop_food) + if(!U.reagents) + U.create_reagents(5) + + if (U.reagents.total_volume > 0) + to_chat(user, "You already have something on your [U].") + return + + user.visible_message( \ + "\The [user] scoops up some [src] with \the [U]!", \ + "You scoop up some [src] with \the [U]!" \ + ) + + src.bitecount++ + U.overlays.Cut() + U.loaded = "[src]" + var/image/I = new(U.icon, "loadedfood") + I.color = src.filling_color + U.overlays += I + + reagents.trans_to_obj(U, min(reagents.total_volume,5)) + + if (reagents.total_volume <= 0) + qdel(src) + return + + if (is_sliceable()) + //these are used to allow hiding edge items in food that is not on a table/tray + var/can_slice_here = isturf(src.loc) && ((locate(/obj/structure/table) in src.loc) || (locate(/obj/machinery/optable) in src.loc) || (locate(/obj/item/weapon/tray) in src.loc)) + var/hide_item = !has_edge(W) || !can_slice_here + + if (hide_item) + if (W.w_class >= src.w_class || is_robot_module(W)) + return + + to_chat(user, "You slip \the [W] inside \the [src].") + user.drop_from_inventory(W, src) + add_fingerprint(user) + contents += W + return + + if (has_edge(W)) + if (!can_slice_here) + to_chat(user, "You cannot slice \the [src] here! You need a table or at least a tray to do it.") + return + + var/slices_lost = 0 + if (W.w_class > 3) + user.visible_message("\The [user] crudely slices \the [src] with [W]!", "You crudely slice \the [src] with your [W]!") + slices_lost = rand(1,min(1,round(slices_num/2))) + else + user.visible_message("\The [user] slices \the [src]!", "You slice \the [src]!") + + var/reagents_per_slice = reagents.total_volume/slices_num + for(var/i=1 to (slices_num-slices_lost)) + var/obj/slice = new slice_path (src.loc) + reagents.trans_to_obj(slice, reagents_per_slice) + qdel(src) + return + +/obj/item/weapon/reagent_containers/food/snacks/proc/is_sliceable() + return (slices_num && slice_path && slices_num > 0) + +/obj/item/weapon/reagent_containers/food/snacks/Destroy() + if(contents) + for(var/atom/movable/something in contents) + something.dropInto(loc) + . = ..() + +//////////////////////////////////////////////////////////////////////////////// +/// FOOD END +//////////////////////////////////////////////////////////////////////////////// +/obj/item/weapon/reagent_containers/food/snacks/attack_generic(var/mob/living/user) + if(!isanimal(user) && !isalien(user)) + return + user.visible_message("[user] nibbles away at \the [src].","You nibble away at \the [src].") + bitecount++ + if(reagents && user.reagents) + reagents.trans_to_mob(user, bitesize, CHEM_INGEST) + spawn(5) + if(!src && !user.client) + user.custom_emote(1,"[pick("burps", "cries for more", "burps twice", "looks at the area where the food was")]") + qdel(src) + On_Consume(user) + +////////////////////////////////////////////////// +////////////////////////////////////////////Snacks +////////////////////////////////////////////////// +//Items in the "Snacks" subcategory are food items that people actually eat. The key points are that they are created +// already filled with reagents and are destroyed when empty. Additionally, they make a "munching" noise when eaten. + +//Notes by Darem: Food in the "snacks" subtype can hold a maximum of 50 units Generally speaking, you don't want to go over 40 +// total for the item because you want to leave space for extra condiments. If you want effect besides healing, add a reagent for +// it. Try to stick to existing reagents when possible (so if you want a stronger healing effect, just use Tricordrazine). On use +// effect (such as the old officer eating a donut code) requires a unique reagent (unless you can figure out a better way). + +//The nutriment reagent and bitesize variable replace the old heal_amt and amount variables. Each unit of nutriment is equal to +// 2 of the old heal_amt variable. Bitesize is the rate at which the reagents are consumed. So if you have 6 nutriment and a +// bitesize of 2, then it'll take 3 bites to eat. Unlike the old system, the contained reagents are evenly spread among all +// the bites. No more contained reagents = no more bites. + +//Here is an example of the new formatting for anyone who wants to add more food items. +///obj/item/weapon/reagent_containers/food/snacks/xenoburger //Identification path for the object. +// name = "Xenoburger" //Name that displays in the UI. +// desc = "Smells caustic. Tastes like heresy." //Duh +// icon_state = "xburger" //Refers to an icon in food.dmi +// New() //Don't mess with this. +// ..() //Same here. +// reagents.add_reagent(/datum/reagent/xenomicrobes, 10) //This is what is in the food item. you may copy/paste +// reagents.add_reagent(/datum/reagent/nutriment, 2) // this line of code for all the contents. +// bitesize = 3 //This is the amount each bite consumes. + + + + +/obj/item/weapon/reagent_containers/food/snacks/aesirsalad + name = "Aesir salad" + desc = "Probably too incredible for mortal men to fully enjoy." + icon_state = "aesirsalad" + trash = /obj/item/trash/snack_bowl + filling_color = "#468c00" + center_of_mass = "x=17;y=11" + nutriment_amt = 8 + nutriment_desc = list("apples" = 3,"salad" = 5) + + New() + ..() + reagents.add_reagent(/datum/reagent/drink/doctor_delight, 8) + reagents.add_reagent(/datum/reagent/tricordrazine, 8) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/candy + name = "candy" + desc = "Nougat, love it or hate it." + icon_state = "candy" + trash = /obj/item/trash/candy + filling_color = "#7d5f46" + center_of_mass = "x=15;y=15" + nutriment_amt = 1 + nutriment_desc = list("candy" = 1) + + New() + ..() + reagents.add_reagent(/datum/reagent/sugar, 3) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar + name = "protein bar" + desc = "SwoleMAX brand protein bars, guaranteed to get you feeling perfectly overconfident." + icon_state = "proteinbar" + trash = /obj/item/trash/candy/proteinbar + +/obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar/New() + ..() + reagents.add_reagent(/datum/reagent/nutriment, 9) + reagents.add_reagent(/datum/reagent/nutriment/protein, 4) + reagents.add_reagent(/datum/reagent/sugar, 4) + bitesize = 6 + +/obj/item/weapon/reagent_containers/food/snacks/candy/donor + name = "Donor Candy" + desc = "A little treat for blood donors." + trash = /obj/item/trash/candy + nutriment_desc = list("candy" = 10) + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment, 10) + reagents.add_reagent(/datum/reagent/sugar, 3) + bitesize = 5 + +/obj/item/weapon/reagent_containers/food/snacks/candy_corn + name = "candy corn" + desc = "It's a handful of candy corn. Cannot be stored in a detective's hat, alas." + icon_state = "candy_corn" + filling_color = "#fffcb0" + center_of_mass = "x=14;y=10" + nutriment_amt = 4 + nutriment_desc = list("candy corn" = 4) + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment, 4) + reagents.add_reagent(/datum/reagent/sugar, 2) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/chips + name = "chips" + desc = "Commander Riker's What-The-Crisps." + icon_state = "chips" + trash = /obj/item/trash/chips + filling_color = "#e8c31e" + center_of_mass = "x=15;y=15" + nutriment_amt = 3 + nutriment_desc = list("salt" = 1, "chips" = 2) + New() + ..() + bitesize = 1 + +/obj/item/weapon/reagent_containers/food/snacks/cookie + name = "cookie" + desc = "COOKIE!!!" + icon_state = "COOKIE!!!" + filling_color = "#dbc94f" + center_of_mass = "x=17;y=18" + nutriment_amt = 5 + nutriment_desc = list("sweetness" = 3, "cookie" = 2) + New() + ..() + bitesize = 1 + +/obj/item/weapon/reagent_containers/food/snacks/chocolatebar + name = "Chocolate Bar" + desc = "Such sweet, fattening food." + icon_state = "chocolatebar" + filling_color = "#7d5f46" + center_of_mass = "x=15;y=15" + nutriment_amt = 2 + nutriment_desc = list("chocolate" = 5) + New() + ..() + reagents.add_reagent(/datum/reagent/sugar, 2) + reagents.add_reagent(/datum/reagent/nutriment/coco, 2) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/chocolateegg + name = "Chocolate Egg" + desc = "Such sweet, fattening food." + icon_state = "chocolateegg" + filling_color = "#7d5f46" + center_of_mass = "x=16;y=13" + nutriment_amt = 3 + nutriment_desc = list("chocolate" = 5) + New() + ..() + reagents.add_reagent(/datum/reagent/sugar, 2) + reagents.add_reagent(/datum/reagent/nutriment/coco, 2) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/donut + name = "donut" + desc = "Goes great with Robust Coffee." + icon_state = "donut1" + filling_color = "#d9c386" + var/overlay_state = "box-donut1" + center_of_mass = "x=13;y=16" + nutriment_desc = list("sweetness", "donut") + +/obj/item/weapon/reagent_containers/food/snacks/donut/normal + name = "donut" + desc = "Goes great with Robust Coffee." + icon_state = "donut1" + nutriment_amt = 3 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/sprinkles, 1) + src.bitesize = 3 + if(prob(30)) + src.icon_state = "donut2" + src.overlay_state = "box-donut2" + src.SetName("frosted donut") + reagents.add_reagent(/datum/reagent/nutriment/sprinkles, 2) + center_of_mass = "x=19;y=16" + +/obj/item/weapon/reagent_containers/food/snacks/donut/chaos + name = "Chaos Donut" + desc = "Like life, it never quite tastes the same." + icon_state = "donut1" + filling_color = "#ed11e6" + nutriment_amt = 2 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/sprinkles, 1) + bitesize = 10 + var/chaosselect = pick(1,2,3,4,5,6,7,8,9,10) + switch(chaosselect) + if(1) + reagents.add_reagent(/datum/reagent/nutriment, 3) + if(2) + reagents.add_reagent(/datum/reagent/capsaicin, 3) + if(3) + reagents.add_reagent(/datum/reagent/frostoil, 3) + if(4) + reagents.add_reagent(/datum/reagent/nutriment/sprinkles, 3) + if(5) + reagents.add_reagent(/datum/reagent/toxin/phoron, 3) + if(6) + reagents.add_reagent(/datum/reagent/nutriment/coco, 3) + if(7) + reagents.add_reagent(/datum/reagent/slimejelly, 3) + if(8) + reagents.add_reagent(/datum/reagent/drink/juice/banana, 3) + if(9) + reagents.add_reagent(/datum/reagent/drink/juice/berry, 3) + if(10) + reagents.add_reagent(/datum/reagent/tricordrazine, 3) + if(prob(30)) + src.icon_state = "donut2" + src.overlay_state = "box-donut2" + src.SetName("Frosted Chaos Donut") + reagents.add_reagent(/datum/reagent/nutriment/sprinkles, 2) + + +/obj/item/weapon/reagent_containers/food/snacks/donut/jelly + name = "Jelly Donut" + desc = "You jelly?" + icon_state = "jdonut1" + filling_color = "#ed1169" + center_of_mass = "x=16;y=11" + nutriment_amt = 3 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/sprinkles, 1) + reagents.add_reagent(/datum/reagent/drink/juice/berry, 5) + bitesize = 5 + if(prob(30)) + src.icon_state = "jdonut2" + src.overlay_state = "box-donut2" + src.SetName("Frosted Jelly Donut") + reagents.add_reagent(/datum/reagent/nutriment/sprinkles, 2) + +/obj/item/weapon/reagent_containers/food/snacks/donut/slimejelly + name = "Jelly Donut" + desc = "You jelly?" + icon_state = "jdonut1" + filling_color = "#ed1169" + center_of_mass = "x=16;y=11" + nutriment_amt = 3 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/sprinkles, 1) + reagents.add_reagent(/datum/reagent/slimejelly, 5) + bitesize = 5 + if(prob(30)) + src.icon_state = "jdonut2" + src.overlay_state = "box-donut2" + src.SetName("Frosted Jelly Donut") + reagents.add_reagent(/datum/reagent/nutriment/sprinkles, 2) + +/obj/item/weapon/reagent_containers/food/snacks/donut/cherryjelly + name = "Jelly Donut" + desc = "You jelly?" + icon_state = "jdonut1" + filling_color = "#ed1169" + center_of_mass = "x=16;y=11" + nutriment_amt = 3 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/sprinkles, 1) + reagents.add_reagent(/datum/reagent/nutriment/cherryjelly, 5) + bitesize = 5 + if(prob(30)) + src.icon_state = "jdonut2" + src.overlay_state = "box-donut2" + src.SetName("Frosted Jelly Donut") + reagents.add_reagent(/datum/reagent/nutriment/sprinkles, 2) + +/obj/item/weapon/reagent_containers/food/snacks/egg + name = "egg" + desc = "An egg!" + icon_state = "egg" + filling_color = "#fdffd1" + volume = 10 + center_of_mass = "x=16;y=13" + +/obj/item/weapon/reagent_containers/food/snacks/egg/New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein/egg, 3) + +/obj/item/weapon/reagent_containers/food/snacks/egg/afterattack(obj/O as obj, mob/user as mob, proximity) + if(istype(O,/obj/machinery/microwave)) + return ..() + if(!(proximity && O.is_open_container())) + return + to_chat(user, "You crack \the [src] into \the [O].") + reagents.trans_to(O, reagents.total_volume) + user.drop_from_inventory(src) + qdel(src) + +/obj/item/weapon/reagent_containers/food/snacks/egg/throw_impact(atom/hit_atom) + ..() + new/obj/effect/decal/cleanable/egg_smudge(src.loc) + src.reagents.splash(hit_atom, reagents.total_volume) + src.visible_message("\The [src] has been squashed!","You hear a smack.") + qdel(src) + +/obj/item/weapon/reagent_containers/food/snacks/egg/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype( W, /obj/item/weapon/pen/crayon )) + var/obj/item/weapon/pen/crayon/C = W + var/clr = C.colourName + + if(!(clr in list("blue","green","mime","orange","purple","rainbow","red","yellow"))) + to_chat(usr, "The egg refuses to take on this color!") + return + + to_chat(usr, "You color \the [src] [clr]") + icon_state = "egg-[clr]" + else + ..() + +/obj/item/weapon/reagent_containers/food/snacks/egg/blue + icon_state = "egg-blue" + +/obj/item/weapon/reagent_containers/food/snacks/egg/green + icon_state = "egg-green" + +/obj/item/weapon/reagent_containers/food/snacks/egg/mime + icon_state = "egg-mime" + +/obj/item/weapon/reagent_containers/food/snacks/egg/orange + icon_state = "egg-orange" + +/obj/item/weapon/reagent_containers/food/snacks/egg/purple + icon_state = "egg-purple" + +/obj/item/weapon/reagent_containers/food/snacks/egg/rainbow + icon_state = "egg-rainbow" + +/obj/item/weapon/reagent_containers/food/snacks/egg/red + icon_state = "egg-red" + +/obj/item/weapon/reagent_containers/food/snacks/egg/yellow + icon_state = "egg-yellow" + +/obj/item/weapon/reagent_containers/food/snacks/friedegg + name = "Fried egg" + desc = "A fried egg, with a touch of salt and pepper." + icon_state = "friedegg" + filling_color = "#ffdf78" + center_of_mass = "x=16;y=14" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 3) + reagents.add_reagent(/datum/reagent/sodiumchloride, 1) + reagents.add_reagent(/datum/reagent/blackpepper, 1) + bitesize = 1 + +/obj/item/weapon/reagent_containers/food/snacks/boiledegg + name = "Boiled egg" + desc = "A hard boiled egg." + icon_state = "egg" + filling_color = "#ffffff" + +/obj/item/weapon/reagent_containers/food/snacks/boiledegg/New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 2) + +/obj/item/weapon/reagent_containers/food/snacks/organ + name = "organ" + desc = "It's good for you." + icon = 'icons/obj/surgery.dmi' + icon_state = "appendix" + filling_color = "#e00d34" + center_of_mass = "x=16;y=16" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, rand(3,5)) + reagents.add_reagent(/datum/reagent/toxin, rand(1,3)) + src.bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/tofu + name = "Tofu" + icon_state = "tofu" + desc = "We all love tofu." + filling_color = "#fffee0" + center_of_mass = "x=17;y=10" + nutriment_amt = 3 + nutriment_desc = list("tofu" = 3, "goeyness" = 3) + New() + ..() + src.bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/tofurkey + name = "Tofurkey" + desc = "A fake turkey made from tofu." + icon_state = "tofurkey" + filling_color = "#fffee0" + center_of_mass = "x=16;y=8" + nutriment_amt = 12 + nutriment_desc = list("turkey" = 3, "tofu" = 5, "goeyness" = 4) + + New() + ..() + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/stuffing + name = "Stuffing" + desc = "Moist, peppery breadcrumbs for filling the body cavities of dead birds. Dig in!" + icon_state = "stuffing" + filling_color = "#c9ac83" + center_of_mass = "x=16;y=10" + nutriment_amt = 3 + nutriment_desc = list("dryness" = 2, "bread" = 2) + New() + ..() + bitesize = 1 + +/obj/item/weapon/reagent_containers/food/snacks/carpmeat + name = "carp fillet" + desc = "A fillet of spess carp meat." + icon_state = "fishfillet" + filling_color = "#ffdefe" + center_of_mass = "x=17;y=13" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 3) + reagents.add_reagent(/datum/reagent/toxin/carpotoxin, 6) + src.bitesize = 6 + +/obj/item/weapon/reagent_containers/food/snacks/fishfingers + name = "Fish Fingers" + desc = "A finger of fish." + icon_state = "fishfingers" + filling_color = "#ffdefe" + center_of_mass = "x=16;y=13" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 4) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/hugemushroomslice + name = "huge mushroom slice" + desc = "A slice from a huge mushroom." + icon_state = "hugemushroomslice" + filling_color = "#e0d7c5" + center_of_mass = "x=17;y=16" + nutriment_amt = 3 + nutriment_desc = list("raw" = 2, "mushroom" = 2) + New() + ..() + reagents.add_reagent(/datum/reagent/psilocybin, 3) + src.bitesize = 6 + +/obj/item/weapon/reagent_containers/food/snacks/tomatomeat + name = "tomato slice" + desc = "A slice from a huge tomato." + icon_state = "tomatomeat" + filling_color = "#db0000" + center_of_mass = "x=17;y=16" + nutriment_amt = 3 + nutriment_desc = list("raw" = 2, "tomato" = 3) + New() + ..() + src.bitesize = 6 + +/obj/item/weapon/reagent_containers/food/snacks/bearmeat + name = "bear meat" + desc = "A very manly slab of meat." + icon_state = "bearmeat" + filling_color = "#db0000" + center_of_mass = "x=16;y=10" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 12) + reagents.add_reagent(/datum/reagent/hyperzine, 5) + src.bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/xenomeat + name = "meat" + desc = "A slab of green meat. Smells like acid." + icon_state = "xenomeat" + filling_color = "#43de18" + center_of_mass = "x=16;y=10" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 6) + reagents.add_reagent(/datum/reagent/acid/polyacid,6) + src.bitesize = 6 + +/obj/item/weapon/reagent_containers/food/snacks/meatball + name = "meatball" + desc = "A great meal all round." + icon_state = "meatball" + filling_color = "#db0000" + center_of_mass = "x=16;y=16" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 3) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/sausage + name = "Sausage" + desc = "A piece of mixed, long meat." + icon_state = "sausage" + filling_color = "#db0000" + center_of_mass = "x=16;y=16" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 6) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/donkpocket/sinpocket + name = "\improper Sin-pocket" + desc = "The food of choice for the veteran. Do NOT overconsume." + filling_color = "#6d6d00" + heated_reagents = list(/datum/reagent/drink/doctor_delight = 5, /datum/reagent/hyperzine = 0.75, /datum/reagent/synaptizine = 0.25) + var/has_been_heated = 0 + +/obj/item/weapon/reagent_containers/food/snacks/donkpocket/sinpocket/attack_self(mob/user) + if(has_been_heated) + to_chat(user, "The heating chemicals have already been spent.") + return + has_been_heated = 1 + user.visible_message("[user] crushes \the [src] package.", "You crush \the [src] package and feel a comfortable heat build up.") + spawn(200) + to_chat(user, "You think \the [src] is ready to eat about now.") + heat() + +/obj/item/weapon/reagent_containers/food/snacks/donkpocket + name = "Donk-pocket" + desc = "The food of choice for the seasoned traitor." + icon_state = "donkpocket" + filling_color = "#dedeab" + center_of_mass = "x=16;y=10" + nutriment_desc = list("heartiness" = 1, "dough" = 2) + nutriment_amt = 2 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 2) + + var/warm = 0 + var/list/heated_reagents = list(/datum/reagent/tricordrazine = 5) + proc/heat() + warm = 1 + for(var/reagent in heated_reagents) + reagents.add_reagent(reagent, heated_reagents[reagent]) + bitesize = 6 + SetName("Warm " + name) + cooltime() + + proc/cooltime() + if (src.warm) + spawn(4200) + src.warm = 0 + for(var/reagent in heated_reagents) + src.reagents.del_reagent(reagent) + src.SetName(initial(name)) + return + +/obj/item/weapon/reagent_containers/food/snacks/brainburger + name = "brainburger" + desc = "A strange looking burger. It looks almost sentient." + icon_state = "brainburger" + filling_color = "#f2b6ea" + center_of_mass = "x=15;y=11" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 6) + reagents.add_reagent(/datum/reagent/alkysine, 6) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/ghostburger + name = "Ghost Burger" + desc = "Spooky! It doesn't look very filling." + icon_state = "ghostburger" + filling_color = "#fff2ff" + center_of_mass = "x=16;y=11" + nutriment_desc = list("buns" = 3, "spookiness" = 3) + nutriment_amt = 2 + New() + ..() + bitesize = 2 + + +/obj/item/weapon/reagent_containers/food/snacks/human + var/hname = "" + var/job = null + filling_color = "#d63c3c" + +/obj/item/weapon/reagent_containers/food/snacks/human/burger + name = "-burger" + desc = "A bloody burger." + icon_state = "hburger" + center_of_mass = "x=16;y=11" + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 6) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/cheeseburger + name = "cheeseburger" + desc = "The cheese adds a good flavor." + icon_state = "cheeseburger" + center_of_mass = "x=16;y=11" + nutriment_desc = list("cheese" = 2, "bun" = 2) + nutriment_amt = 2 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 2) + +/obj/item/weapon/reagent_containers/food/snacks/plainburger + name = "burger" + desc = "The cornerstone of every nutritious breakfast." + icon_state = "hburger" + filling_color = "#d63c3c" + center_of_mass = "x=16;y=11" + nutriment_desc = list("bun" = 2) + nutriment_amt = 3 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 3) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/fishburger + name = "Fillet -o- Carp Sandwich" + desc = "Almost like a carp is yelling somewhere... Give me back that fillet -o- carp, give me that carp." + icon_state = "fishburger" + filling_color = "#ffdefe" + center_of_mass = "x=16;y=10" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 6) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/tofuburger + name = "Tofu Burger" + desc = "What.. is that meat?" + icon_state = "tofuburger" + filling_color = "#fffee0" + center_of_mass = "x=16;y=10" + nutriment_desc = list("bun" = 2, "pseudo-soy meat" = 3) + nutriment_amt = 6 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/roburger + name = "roburger" + desc = "The lettuce is the only organic component. Beep." + icon_state = "roburger" + filling_color = "#cccccc" + center_of_mass = "x=16;y=11" + nutriment_desc = list("bun" = 2, "metal" = 3) + nutriment_amt = 2 + New() + ..() + if(prob(5)) + reagents.add_reagent(/datum/reagent/nanites, 2) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/roburgerbig + name = "roburger" + desc = "This massive patty looks like poison. Beep." + icon_state = "roburger" + filling_color = "#cccccc" + volume = 100 + center_of_mass = "x=16;y=11" + + New() + ..() + reagents.add_reagent(/datum/reagent/nanites, 100) + bitesize = 0.1 + +/obj/item/weapon/reagent_containers/food/snacks/xenoburger + name = "xenoburger" + desc = "Smells caustic. Tastes like heresy." + icon_state = "xburger" + filling_color = "#43de18" + center_of_mass = "x=16;y=11" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 8) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/clownburger + name = "Clown Burger" + desc = "This tastes funny..." + icon_state = "clownburger" + filling_color = "#ff00ff" + center_of_mass = "x=17;y=12" + nutriment_desc = list("bun" = 2, "clown shoe" = 3) + nutriment_amt = 6 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/mimeburger + name = "Mime Burger" + desc = "Its taste defies language." + icon_state = "mimeburger" + filling_color = "#ffffff" + center_of_mass = "x=16;y=11" + nutriment_desc = list("bun" = 2, "mime paint" = 3) + nutriment_amt = 6 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/omelette + name = "Omelette Du Fromage" + desc = "That's all you can say!" + icon_state = "omelette" + trash = /obj/item/trash/plate + filling_color = "#fff9a8" + center_of_mass = "x=16;y=13" + + //var/herp = 0 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 8) + bitesize = 1 + +/obj/item/weapon/reagent_containers/food/snacks/muffin + name = "Muffin" + desc = "A delicious and spongy little cake." + icon_state = "muffin" + filling_color = "#e0cf9b" + center_of_mass = "x=17;y=4" + nutriment_desc = list("sweetness" = 3, "muffin" = 3) + nutriment_amt = 6 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/pie + name = "Banana Cream Pie" + desc = "Just like back home, on clown planet! HONK!" + icon_state = "pie" + trash = /obj/item/trash/plate + filling_color = "#fbffb8" + center_of_mass = "x=16;y=13" + nutriment_desc = list("pie" = 3, "cream" = 2) + nutriment_amt = 4 + +/obj/item/weapon/reagent_containers/food/snacks/pie/New() + ..() + reagents.add_reagent(/datum/reagent/drink/juice/banana,5) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/pie/throw_impact(atom/hit_atom) + ..() + new/obj/effect/decal/cleanable/pie_smudge(src.loc) + src.visible_message("\The [src.name] splats.","You hear a splat.") + qdel(src) + +/obj/item/weapon/reagent_containers/food/snacks/berryclafoutis + name = "Berry Clafoutis" + desc = "No black birds, this is a good sign." + icon_state = "berryclafoutis" + trash = /obj/item/trash/plate + center_of_mass = "x=16;y=13" + nutriment_desc = list("sweetness" = 2, "pie" = 3) + nutriment_amt = 4 + New() + ..() + reagents.add_reagent(/datum/reagent/drink/juice/berry, 5) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/waffles + name = "waffles" + desc = "Mmm, waffles." + icon_state = "waffles" + trash = /obj/item/trash/waffles + filling_color = "#e6deb5" + center_of_mass = "x=15;y=11" + nutriment_desc = list("waffle" = 8) + nutriment_amt = 8 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/pancakes + name = "pancakes" + desc = "Pancakes with blueberries, delicious." + icon_state = "pancakes" + trash = /obj/item/trash/plate + center_of_mass = "x=15;y=11" + nutriment_desc = list("pancake" = 8) + nutriment_amt = 8 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/eggplantparm + name = "Eggplant Parmigiana" + desc = "The only good recipe for eggplant." + icon_state = "eggplantparm" + trash = /obj/item/trash/plate + filling_color = "#4d2f5e" + center_of_mass = "x=16;y=11" + nutriment_desc = list("cheese" = 3, "eggplant" = 3) + nutriment_amt = 6 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/soylentgreen + name = "Soylent Green" + desc = "Not made of people. Honest." //Totally people. + icon_state = "soylent_green" + trash = /obj/item/trash/waffles + filling_color = "#b8e6b5" + center_of_mass = "x=15;y=11" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 10) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/soylenviridians + name = "Soylen Virdians" + desc = "Not made of people. Honest." //Actually honest for once. + icon_state = "soylent_yellow" + trash = /obj/item/trash/waffles + filling_color = "#e6fa61" + center_of_mass = "x=15;y=11" + + nutriment_desc = list("some sort of protein" = 10) //seasoned VERY well. + nutriment_amt = 10 + New() + ..() + bitesize = 2 + + +/obj/item/weapon/reagent_containers/food/snacks/meatpie + name = "Meat-pie" + icon_state = "meatpie" + desc = "An old barber recipe, very delicious!" + trash = /obj/item/trash/plate + filling_color = "#948051" + center_of_mass = "x=16;y=13" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 10) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/tofupie + name = "Tofu-pie" + icon_state = "meatpie" + desc = "A delicious tofu pie." + trash = /obj/item/trash/plate + filling_color = "#fffee0" + center_of_mass = "x=16;y=13" + nutriment_desc = list("tofu" = 2, "pie" = 8) + nutriment_amt = 10 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/amanita_pie + name = "amanita pie" + desc = "Sweet and tasty poison pie." + icon_state = "amanita_pie" + filling_color = "#ffcccc" + center_of_mass = "x=17;y=9" + nutriment_desc = list("sweetness" = 3, "mushroom" = 3, "pie" = 2) + nutriment_amt = 5 + New() + ..() + reagents.add_reagent(/datum/reagent/toxin/amatoxin, 3) + reagents.add_reagent(/datum/reagent/psilocybin, 1) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/plump_pie + name = "plump pie" + desc = "I bet you love stuff made out of plump helmets!" + icon_state = "plump_pie" + filling_color = "#b8279b" + center_of_mass = "x=17;y=9" + nutriment_desc = list("heartiness" = 2, "mushroom" = 3, "pie" = 3) + nutriment_amt = 8 + New() + ..() + if(prob(10)) + name = "exceptional plump pie" + desc = "Microwave is taken by a fey mood! It has cooked an exceptional plump pie!" + reagents.add_reagent(/datum/reagent/tricordrazine, 5) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/xemeatpie + name = "Xeno-pie" + icon_state = "xenomeatpie" + desc = "A delicious meatpie. Probably heretical." + trash = /obj/item/trash/plate + filling_color = "#43de18" + center_of_mass = "x=16;y=13" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 10) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/wingfangchu + name = "Wing Fang Chu" + desc = "A savory dish of alien wing wang in soy." + icon_state = "wingfangchu" + trash = /obj/item/trash/snack_bowl + filling_color = "#43de18" + center_of_mass = "x=17;y=9" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 6) + bitesize = 2 + + +/obj/item/weapon/reagent_containers/food/snacks/meatkabob + name = "Meat-kabob" + icon_state = "kabob" + desc = "Delicious meat, on a stick." + trash = /obj/item/stack/rods + filling_color = "#a85340" + center_of_mass = "x=17;y=15" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 8) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/tofukabob + name = "Tofu-kabob" + icon_state = "kabob" + desc = "Vegan meat, on a stick." + trash = /obj/item/stack/rods + filling_color = "#fffee0" + center_of_mass = "x=17;y=15" + nutriment_desc = list("tofu" = 3, "metal" = 1) + nutriment_amt = 8 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/cubancarp + name = "Cuban Carp" + desc = "A sandwich that burns your tongue and then leaves it numb!" + icon_state = "cubancarp" + trash = /obj/item/trash/plate + filling_color = "#e9adff" + center_of_mass = "x=12;y=5" + nutriment_desc = list("toasted bread" = 3) + nutriment_amt = 3 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 3) + reagents.add_reagent(/datum/reagent/capsaicin, 3) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/popcorn + name = "Popcorn" + desc = "Now let's find some cinema." + icon_state = "popcorn" + trash = /obj/item/trash/popcorn + var/unpopped = 0 + filling_color = "#fffad4" + center_of_mass = "x=16;y=8" + nutriment_desc = list("popcorn" = 3) + nutriment_amt = 2 + New() + ..() + unpopped = rand(1,10) + bitesize = 0.1 //this snack is supposed to be eating during looooong time. And this it not dinner food! --rastaf0 + On_Consume() + if(prob(unpopped)) //lol ...what's the point? + to_chat(usr, "You bite down on an un-popped kernel!") + unpopped = max(0, unpopped-1) + ..() + + +/obj/item/weapon/reagent_containers/food/snacks/sosjerky + name = "Sgt Scaredy's Private Reserve Beef Jerky" + icon_state = "sosjerky" + desc = "Beef jerky made from the finest blue corpses." + trash = /obj/item/trash/sosjerky + filling_color = "#631212" + center_of_mass = "x=15;y=9" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 4) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/no_raisin + name = "4no Raisins" + icon_state = "4no_raisins" + desc = "Bitchkiller555's chosen snack." + trash = /obj/item/trash/raisins + filling_color = "#343834" + center_of_mass = "x=15;y=4" + nutriment_desc = list("raisins" = 6) + nutriment_amt = 6 + +/obj/item/weapon/reagent_containers/food/snacks/spacetwinkie + name = "Trench Twinkie" + icon_state = "space_twinkie" + desc = "Guaranteed to survive longer then you will." + filling_color = "#ffe591" + center_of_mass = "x=15;y=11" + + New() + ..() + reagents.add_reagent(/datum/reagent/sugar, 4) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers + name = "Cheesie Honkers" + icon_state = "cheesie_honkers" + desc = "Bite sized cheesie snacks that will honk all over your mouth." + trash = /obj/item/trash/cheesie + filling_color = "#ffa305" + center_of_mass = "x=15;y=9" + nutriment_desc = list("cheese" = 5, "chips" = 2) + nutriment_amt = 4 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/syndicake + name = "Syndi-Cakes" + icon_state = "syndi_cakes" + desc = "An extremely moist snack cake that tastes just as good after being nuked." + filling_color = "#ff5d05" + center_of_mass = "x=16;y=10" + nutriment_desc = list("sweetness" = 3, "cake" = 1) + nutriment_amt = 4 + trash = /obj/item/trash/syndi_cakes + New() + ..() + reagents.add_reagent(/datum/reagent/drink/doctor_delight, 5) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/loadedbakedpotato + name = "Loaded Baked Potato" + desc = "Totally baked." + icon_state = "loadedbakedpotato" + filling_color = "#9c7a68" + center_of_mass = "x=16;y=10" + nutriment_desc = list("baked potato" = 3) + nutriment_amt = 3 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 3) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/fries + name = "Space Fries" + desc = "AKA: French Fries, Freedom Fries, etc." + icon_state = "fries" + trash = /obj/item/trash/plate + filling_color = "#eddd00" + center_of_mass = "x=16;y=11" + nutriment_desc = list("fresh fries" = 4) + nutriment_amt = 4 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/onionrings + name = "Onion Rings" + desc = "Like circular fries but better." + icon_state = "onionrings" + trash = /obj/item/trash/plate + filling_color = "#eddd00" + center_of_mass = "x=16;y=11" + nutriment_desc = list("fried onions" = 5) + nutriment_amt = 5 + +/obj/item/weapon/reagent_containers/food/snacks/onionrings/New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/soydope + name = "Soy Dope" + desc = "Dope from a soy." + icon_state = "soydope" + trash = /obj/item/trash/plate + filling_color = "#c4bf76" + center_of_mass = "x=16;y=10" + nutriment_desc = list("slime" = 2, "soy" = 2) + nutriment_amt = 2 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/spagetti + name = "Spaghetti" + desc = "A bundle of raw spaghetti." + icon_state = "spagetti" + filling_color = "#eddd00" + center_of_mass = "x=16;y=16" + nutriment_desc = list("noodles" = 2) + nutriment_amt = 1 + New() + ..() + bitesize = 1 + +/obj/item/weapon/reagent_containers/food/snacks/cheesyfries + name = "Cheesy Fries" + desc = "Fries. Covered in cheese. Duh." + icon_state = "cheesyfries" + trash = /obj/item/trash/plate + filling_color = "#eddd00" + center_of_mass = "x=16;y=11" + nutriment_desc = list("fresh fries" = 3, "cheese" = 3) + nutriment_amt = 4 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 2) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/fortunecookie + name = "Fortune cookie" + desc = "A true prophecy in each cookie!" + icon_state = "fortune_cookie" + filling_color = "#e8e79e" + center_of_mass = "x=15;y=14" + nutriment_desc = list("fortune cookie" = 2) + nutriment_amt = 3 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/badrecipe + name = "Burned mess" + desc = "Someone should be demoted from chef for this." + icon_state = "badrecipe" + filling_color = "#211f02" + center_of_mass = "x=16;y=12" + + New() + ..() + reagents.add_reagent(/datum/reagent/toxin, 1) + reagents.add_reagent(/datum/reagent/carbon, 3) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/meatsteak + name = "Meat steak" + desc = "A piece of hot spicy meat." + icon_state = "meatstake" + trash = /obj/item/trash/plate + filling_color = "#7a3d11" + center_of_mass = "x=16;y=13" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 4) + reagents.add_reagent(/datum/reagent/sodiumchloride, 1) + reagents.add_reagent(/datum/reagent/blackpepper, 1) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/loadedsteak + name = "Loaded steak" + desc = "A steak slathered in sauce with sauteed onions and mushrooms." + icon_state = "meatstake" + trash = /obj/item/trash/plate + filling_color = "#7a3d11" + center_of_mass = "x=16;y=13" + + nutriment_desc = list("onion" = 2, "mushroom" = 2) + nutriment_amt = 4 + +/obj/item/weapon/reagent_containers/food/snacks/loadedsteak/New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 2) + reagents.add_reagent(/datum/reagent/nutriment/garlicsauce, 2) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/spacylibertyduff + name = "Spacy Liberty Duff" + desc = "Jello gelatin, from Alfred Hubbard's cookbook." + icon_state = "spacylibertyduff" + trash = /obj/item/trash/snack_bowl + filling_color = "#42b873" + center_of_mass = "x=16;y=8" + nutriment_desc = list("mushroom" = 6) + nutriment_amt = 6 + New() + ..() + reagents.add_reagent(/datum/reagent/psilocybin, 6) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/amanitajelly + name = "Amanita Jelly" + desc = "Looks curiously toxic." + icon_state = "amanitajelly" + trash = /obj/item/trash/snack_bowl + filling_color = "#ed0758" + center_of_mass = "x=16;y=5" + nutriment_desc = list("jelly" = 3, "mushroom" = 3) + nutriment_amt = 6 + New() + ..() + reagents.add_reagent(/datum/reagent/toxin/amatoxin, 6) + reagents.add_reagent(/datum/reagent/psilocybin, 3) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/poppypretzel + name = "Poppy pretzel" + desc = "It's all twisted up!" + icon_state = "poppypretzel" + bitesize = 2 + filling_color = "#916e36" + center_of_mass = "x=16;y=10" + nutriment_desc = list("poppy seeds" = 2, "pretzel" = 3) + nutriment_amt = 5 + New() + ..() + bitesize = 2 + + +/obj/item/weapon/reagent_containers/food/snacks/meatballsoup + name = "Meatball soup" + desc = "You've got balls kid, BALLS!" + icon_state = "meatballsoup" + trash = /obj/item/trash/snack_bowl + filling_color = "#785210" + center_of_mass = "x=16;y=8" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 8) + reagents.add_reagent(/datum/reagent/water, 5) + bitesize = 5 + +/obj/item/weapon/reagent_containers/food/snacks/slimesoup + name = "slime soup" + desc = "If no water is available, you may substitute tears." + icon_state = "slimesoup" //nonexistant? + filling_color = "#c4dba0" + + New() + ..() + reagents.add_reagent(/datum/reagent/slimejelly, 5) + reagents.add_reagent(/datum/reagent/water, 10) + bitesize = 5 + +/obj/item/weapon/reagent_containers/food/snacks/bloodsoup + name = "Tomato soup" + desc = "Smells like copper." + icon_state = "tomatosoup" + filling_color = "#ff0000" + center_of_mass = "x=16;y=7" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 2) + reagents.add_reagent(/datum/reagent/blood, 10) + reagents.add_reagent(/datum/reagent/water, 5) + bitesize = 5 + +/obj/item/weapon/reagent_containers/food/snacks/clownstears + name = "Clown's Tears" + desc = "Not very funny." + icon_state = "clownstears" + filling_color = "#c4fbff" + center_of_mass = "x=16;y=7" + nutriment_desc = list("salt" = 1, "the worst joke" = 3) + nutriment_amt = 4 + New() + ..() + reagents.add_reagent(/datum/reagent/drink/juice/banana, 5) + reagents.add_reagent(/datum/reagent/water, 10) + bitesize = 5 + +/obj/item/weapon/reagent_containers/food/snacks/vegetablesoup + name = "Vegetable soup" + desc = "A highly nutritious blend of vegetative goodness. Guaranteed to leave you with a, er, \"souped-up\" sense of wellbeing." + icon_state = "vegetablesoup" + trash = /obj/item/trash/snack_bowl + filling_color = "#afc4b5" + center_of_mass = "x=16;y=8" + nutriment_desc = list("carrot" = 2, "corn" = 2, "eggplant" = 2, "potato" = 2) + nutriment_amt = 8 + New() + ..() + reagents.add_reagent(/datum/reagent/water, 5) + bitesize = 5 + +/obj/item/weapon/reagent_containers/food/snacks/nettlesoup + name = "Nettle soup" + desc = "A mean, green, calorically lean dish derived from a poisonous plant. It has a rather acidic bite to its taste." + icon_state = "nettlesoup" + trash = /obj/item/trash/snack_bowl + filling_color = "#afc4b5" + center_of_mass = "x=16;y=7" + nutriment_desc = list("salad" = 4, "egg" = 2, "potato" = 2) + nutriment_amt = 8 + +/obj/item/weapon/reagent_containers/food/snacks/nettlesoup/New() + . = ..() + reagents.add_reagent(/datum/reagent/water, 5) + reagents.add_reagent(/datum/reagent/tricordrazine, 5) + bitesize = 5 + +/obj/item/weapon/reagent_containers/food/snacks/mysterysoup + name = "Mystery soup" + desc = "The mystery is, why aren't you eating it?" + icon_state = "mysterysoup" + trash = /obj/item/trash/snack_bowl + filling_color = "#f082ff" + center_of_mass = "x=16;y=6" + nutriment_desc = list("backwash" = 1) + nutriment_amt = 1 + New() + ..() + var/mysteryselect = pick(1,2,3,4,5,6,7,8,9,10) + switch(mysteryselect) + if(1) + reagents.add_reagent(/datum/reagent/nutriment, 6) + reagents.add_reagent(/datum/reagent/capsaicin, 3) + reagents.add_reagent(/datum/reagent/drink/juice/tomato, 2) + if(2) + reagents.add_reagent(/datum/reagent/nutriment, 6) + reagents.add_reagent(/datum/reagent/frostoil, 3) + reagents.add_reagent(/datum/reagent/drink/juice/tomato, 2) + if(3) + reagents.add_reagent(/datum/reagent/nutriment, 5) + reagents.add_reagent(/datum/reagent/water, 5) + reagents.add_reagent(/datum/reagent/tricordrazine, 5) + if(4) + reagents.add_reagent(/datum/reagent/nutriment, 5) + reagents.add_reagent(/datum/reagent/water, 10) + if(5) + reagents.add_reagent(/datum/reagent/nutriment, 2) + reagents.add_reagent(/datum/reagent/drink/juice/banana, 10) + if(6) + reagents.add_reagent(/datum/reagent/nutriment, 6) + reagents.add_reagent(/datum/reagent/blood, 10) + if(7) + reagents.add_reagent(/datum/reagent/slimejelly, 10) + reagents.add_reagent(/datum/reagent/water, 10) + if(8) + reagents.add_reagent(/datum/reagent/carbon, 10) + reagents.add_reagent(/datum/reagent/toxin, 10) + if(9) + reagents.add_reagent(/datum/reagent/nutriment, 5) + reagents.add_reagent(/datum/reagent/drink/juice/tomato, 10) + if(10) + reagents.add_reagent(/datum/reagent/nutriment, 6) + reagents.add_reagent(/datum/reagent/drink/juice/tomato, 5) + reagents.add_reagent(/datum/reagent/imidazoline, 5) + bitesize = 5 + +/obj/item/weapon/reagent_containers/food/snacks/wishsoup + name = "Wish Soup" + desc = "I wish this was soup." + icon_state = "wishsoup" + trash = /obj/item/trash/snack_bowl + filling_color = "#d1f4ff" + center_of_mass = "x=16;y=11" + New() + ..() + reagents.add_reagent(/datum/reagent/water, 10) + bitesize = 5 + if(prob(25)) + src.desc = "A wish come true!" + reagents.add_reagent(/datum/reagent/nutriment, 8, list("something good" = 8)) + +/obj/item/weapon/reagent_containers/food/snacks/hotchili + name = "Hot Chili" + desc = "A five alarm Texan Chili!" + icon_state = "hotchili" + trash = /obj/item/trash/snack_bowl + filling_color = "#ff3c00" + center_of_mass = "x=15;y=9" + nutriment_desc = list("chilli peppers" = 3) + nutriment_amt = 3 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 3) + reagents.add_reagent(/datum/reagent/capsaicin, 3) + reagents.add_reagent(/datum/reagent/drink/juice/tomato, 2) + bitesize = 5 + + +/obj/item/weapon/reagent_containers/food/snacks/coldchili + name = "Cold Chili" + desc = "This slush is barely a liquid!" + icon_state = "coldchili" + filling_color = "#2b00ff" + center_of_mass = "x=15;y=9" + nutriment_desc = list("ice peppers" = 3) + nutriment_amt = 3 + trash = /obj/item/trash/snack_bowl + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 3) + reagents.add_reagent(/datum/reagent/frostoil, 3) + reagents.add_reagent(/datum/reagent/drink/juice/tomato, 2) + bitesize = 5 + +/obj/item/weapon/reagent_containers/food/snacks/monkeycube + name = "monkey cube" + desc = "Just add water!" + atom_flags = ATOM_FLAG_OPEN_CONTAINER + icon_state = "monkeycube" + bitesize = 12 + filling_color = "#adac7f" + center_of_mass = "x=16;y=14" + + var/wrapped = 0 + var/monkey_type = /mob/living/carbon/human/monkey + +/obj/item/weapon/reagent_containers/food/snacks/monkeycube/New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 10) + +/obj/item/weapon/reagent_containers/food/snacks/monkeycube/attack_self(var/mob/user) + if(wrapped) + Unwrap(user) + +/obj/item/weapon/reagent_containers/food/snacks/monkeycube/proc/Expand() + src.visible_message("\The [src] expands!") + var/mob/monkey = new monkey_type + monkey.dropInto(src.loc) + qdel(src) + +/obj/item/weapon/reagent_containers/food/snacks/monkeycube/proc/Unwrap(var/mob/user) + icon_state = "monkeycube" + desc = "Just add water!" + to_chat(user, "You unwrap the cube.") + wrapped = 0 + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + +/obj/item/weapon/reagent_containers/food/snacks/monkeycube/On_Consume(var/mob/M) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + H.visible_message("A screeching creature bursts out of [M]'s chest!") + var/obj/item/organ/external/organ = H.get_organ(BP_CHEST) + organ.take_damage(50, 0, 0, "Animal escaping the ribcage") + Expand() + +/obj/item/weapon/reagent_containers/food/snacks/monkeycube/on_reagent_change() + if(reagents.has_reagent(/datum/reagent/water)) + Expand() + +/obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped + desc = "Still wrapped in some paper." + icon_state = "monkeycubewrap" + item_flags = 0 + obj_flags = 0 + wrapped = 1 + +/obj/item/weapon/reagent_containers/food/snacks/monkeycube/farwacube + name = "farwa cube" + monkey_type = /mob/living/carbon/human/farwa + +/obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped/farwacube + name = "farwa cube" + monkey_type = /mob/living/carbon/human/farwa + +/obj/item/weapon/reagent_containers/food/snacks/monkeycube/stokcube + name = "stok cube" + monkey_type = /mob/living/carbon/human/stok + +/obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped/stokcube + name = "stok cube" + monkey_type = /mob/living/carbon/human/stok + +/obj/item/weapon/reagent_containers/food/snacks/monkeycube/neaeracube + name = "neaera cube" + monkey_type = /mob/living/carbon/human/neaera + +/obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped/neaeracube + name = "neaera cube" + monkey_type = /mob/living/carbon/human/neaera + + +/obj/item/weapon/reagent_containers/food/snacks/spellburger + name = "Spell Burger" + desc = "This is absolutely Ei Nath." + icon_state = "spellburger" + filling_color = "#d505ff" + nutriment_desc = list("magic" = 3, "buns" = 3) + nutriment_amt = 6 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/bigbiteburger + name = "Big Bite Burger" + desc = "Forget the Big Mac. THIS is the future!" + icon_state = "bigbiteburger" + filling_color = "#e3d681" + center_of_mass = "x=16;y=11" + nutriment_desc = list("buns" = 4) + nutriment_amt = 4 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 10) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/enchiladas + name = "Enchiladas" + desc = "Viva La Mexico!" + icon_state = "enchiladas" + trash = /obj/item/trash/tray + filling_color = "#a36a1f" + center_of_mass = "x=16;y=13" + nutriment_desc = list("tortilla" = 3, "corn" = 3) + nutriment_amt = 2 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 6) + reagents.add_reagent(/datum/reagent/capsaicin, 6) + bitesize = 4 + +/obj/item/weapon/reagent_containers/food/snacks/monkeysdelight + name = "monkey's Delight" + desc = "Eeee Eee!" + icon_state = "monkeysdelight" + trash = /obj/item/trash/tray + filling_color = "#5c3c11" + center_of_mass = "x=16;y=13" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 10) + reagents.add_reagent(/datum/reagent/drink/juice/banana, 5) + reagents.add_reagent(/datum/reagent/blackpepper, 1) + reagents.add_reagent(/datum/reagent/sodiumchloride, 1) + bitesize = 6 + +/obj/item/weapon/reagent_containers/food/snacks/baguette + name = "Baguette" + desc = "Bon appetit!" + icon_state = "baguette" + filling_color = "#e3d796" + center_of_mass = "x=18;y=12" + nutriment_desc = list("french bread" = 6) + nutriment_amt = 6 + New() + ..() + reagents.add_reagent(/datum/reagent/blackpepper, 1) + reagents.add_reagent(/datum/reagent/sodiumchloride, 1) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/fishandchips + name = "Fish and Chips" + desc = "I do say so myself chap." + icon_state = "fishandchips" + filling_color = "#e3d796" + center_of_mass = "x=16;y=16" + nutriment_desc = list("salt" = 1, "chips" = 3) + nutriment_amt = 3 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 3) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/sandwich + name = "Sandwich" + desc = "A grand creation of meat, cheese, bread, and several leaves of lettuce! Arthur Dent would be proud." + icon_state = "sandwich" + trash = /obj/item/trash/plate + filling_color = "#d9be29" + center_of_mass = "x=16;y=4" + nutriment_desc = list("bread" = 3, "cheese" = 3) + nutriment_amt = 3 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 3) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/toastedsandwich + name = "Toasted Sandwich" + desc = "Now if you only had a pepper bar." + icon_state = "toastedsandwich" + trash = /obj/item/trash/plate + filling_color = "#d9be29" + center_of_mass = "x=16;y=4" + nutriment_desc = list("toasted bread" = 3, "cheese" = 3) + nutriment_amt = 3 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 3) + reagents.add_reagent(/datum/reagent/carbon, 2) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/grilledcheese + name = "Grilled Cheese Sandwich" + desc = "Goes great with Tomato soup!" + icon_state = "toastedsandwich" + trash = /obj/item/trash/plate + filling_color = "#d9be29" + nutriment_desc = list("toasted bread" = 3, "cheese" = 3) + nutriment_amt = 3 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 4) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/tomatosoup + name = "Tomato Soup" + desc = "Drinking this feels like being a vampire! A tomato vampire..." + icon_state = "tomatosoup" + trash = /obj/item/trash/snack_bowl + filling_color = "#d92929" + center_of_mass = "x=16;y=7" + nutriment_desc = list("soup" = 5) + nutriment_amt = 5 + New() + ..() + reagents.add_reagent(/datum/reagent/drink/juice/tomato, 10) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/rofflewaffles + name = "Roffle Waffles" + desc = "Waffles from Roffle. Co." + icon_state = "rofflewaffles" + trash = /obj/item/trash/waffles + filling_color = "#ff00f7" + center_of_mass = "x=15;y=11" + nutriment_desc = list("waffle" = 7, "sweetness" = 1) + nutriment_amt = 8 + New() + ..() + reagents.add_reagent(/datum/reagent/psilocybin, 8) + bitesize = 4 + +/obj/item/weapon/reagent_containers/food/snacks/stew + name = "Stew" + desc = "A nice and warm stew. Healthy and strong." + icon_state = "stew" + filling_color = "#9e673a" + center_of_mass = "x=16;y=5" + nutriment_desc = list("tomato" = 2, "potato" = 2, "carrot" = 2, "eggplant" = 2, "mushroom" = 2) + nutriment_amt = 6 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 4) + reagents.add_reagent(/datum/reagent/drink/juice/tomato, 5) + reagents.add_reagent(/datum/reagent/imidazoline, 5) + reagents.add_reagent(/datum/reagent/water, 5) + bitesize = 10 + +/obj/item/weapon/reagent_containers/food/snacks/jelliedtoast + name = "Jellied Toast" + desc = "A slice of bread covered with delicious jam." + icon_state = "jellytoast" + trash = /obj/item/trash/plate + filling_color = "#b572ab" + center_of_mass = "x=16;y=8" + nutriment_desc = list("toasted bread" = 2) + nutriment_amt = 1 + New() + ..() + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/jelliedtoast/cherry + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/cherryjelly, 5) + +/obj/item/weapon/reagent_containers/food/snacks/jelliedtoast/slime + New() + ..() + reagents.add_reagent(/datum/reagent/slimejelly, 5) + +/obj/item/weapon/reagent_containers/food/snacks/jellyburger + name = "Jelly Burger" + desc = "Culinary delight..?" + icon_state = "jellyburger" + filling_color = "#b572ab" + center_of_mass = "x=16;y=11" + nutriment_desc = list("buns" = 5) + nutriment_amt = 5 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/jellyburger/slime + New() + ..() + reagents.add_reagent(/datum/reagent/slimejelly, 5) + +/obj/item/weapon/reagent_containers/food/snacks/jellyburger/cherry + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/cherryjelly, 5) + +/obj/item/weapon/reagent_containers/food/snacks/milosoup + name = "Milosoup" + desc = "The universes best soup! Yum!!!" + icon_state = "milosoup" + trash = /obj/item/trash/snack_bowl + center_of_mass = "x=16;y=7" + nutriment_desc = list("soy" = 8) + nutriment_amt = 8 + New() + ..() + reagents.add_reagent(/datum/reagent/water, 5) + bitesize = 4 + +/obj/item/weapon/reagent_containers/food/snacks/stewedsoymeat + name = "Stewed Soy Meat" + desc = "Even non-vegetarians will LOVE this!" + icon_state = "stewedsoymeat" + trash = /obj/item/trash/plate + center_of_mass = "x=16;y=10" + nutriment_desc = list("soy" = 4, "tomato" = 4) + nutriment_amt = 8 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/boiledspagetti + name = "Boiled Spaghetti" + desc = "A plain dish of noodles, this sucks." + icon_state = "spagettiboiled" + trash = /obj/item/trash/plate + filling_color = "#fcee81" + center_of_mass = "x=16;y=10" + nutriment_desc = list("noodles" = 2) + nutriment_amt = 2 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/boiledrice + name = "Boiled Rice" + desc = "A boring dish of boring rice." + icon_state = "boiledrice" + trash = /obj/item/trash/snack_bowl + filling_color = "#fffbdb" + center_of_mass = "x=17;y=11" + nutriment_desc = list("rice" = 2) + nutriment_amt = 2 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/ricepudding + name = "Rice Pudding" + desc = "Where's the jam?" + icon_state = "rpudding" + trash = /obj/item/trash/snack_bowl + filling_color = "#fffbdb" + center_of_mass = "x=17;y=11" + nutriment_desc = list("rice" = 2) + nutriment_amt = 4 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/pastatomato + name = "Spaghetti" + desc = "Spaghetti and crushed tomatoes. Just like your abusive father used to make!" + icon_state = "pastatomato" + trash = /obj/item/trash/plate + filling_color = "#de4545" + center_of_mass = "x=16;y=10" + nutriment_desc = list("tomato" = 3, "noodles" = 3) + nutriment_amt = 6 + New() + ..() + reagents.add_reagent(/datum/reagent/drink/juice/tomato, 10) + bitesize = 4 + +/obj/item/weapon/reagent_containers/food/snacks/meatballspagetti + name = "Spaghetti & Meatballs" + desc = "Now thats a nic'e meatball!" + icon_state = "meatballspagetti" + trash = /obj/item/trash/plate + filling_color = "#de4545" + center_of_mass = "x=16;y=10" + nutriment_desc = list("noodles" = 4) + nutriment_amt = 4 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 4) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/spesslaw + name = "Spesslaw" + desc = "A lawyers favourite." + icon_state = "spesslaw" + filling_color = "#de4545" + center_of_mass = "x=16;y=10" + nutriment_desc = list("noodles" = 4) + nutriment_amt = 4 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 4) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/carrotfries + name = "Carrot Fries" + desc = "Tasty fries from fresh Carrots." + icon_state = "carrotfries" + trash = /obj/item/trash/plate + filling_color = "#faa005" + center_of_mass = "x=16;y=11" + nutriment_desc = list("carrot" = 3, "salt" = 1) + nutriment_amt = 3 + New() + ..() + reagents.add_reagent(/datum/reagent/imidazoline, 3) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/superbiteburger + name = "Super Bite Burger" + desc = "This is a mountain of a burger. FOOD!" + icon_state = "superbiteburger" + filling_color = "#cca26a" + center_of_mass = "x=16;y=3" + nutriment_desc = list("buns" = 25) + nutriment_amt = 25 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 25) + bitesize = 10 + +/obj/item/weapon/reagent_containers/food/snacks/candiedapple + name = "Candied Apple" + desc = "An apple coated in sugary sweetness." + icon_state = "candiedapple" + filling_color = "#f21873" + center_of_mass = "x=15;y=13" + nutriment_desc = list("apple" = 3, "caramel" = 3, "sweetness" = 2) + nutriment_amt = 3 + New() + ..() + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/applepie + name = "Apple Pie" + desc = "A pie containing sweet sweet love... or apple." + icon_state = "applepie" + filling_color = "#e0edc5" + center_of_mass = "x=16;y=13" + nutriment_desc = list("sweetness" = 2, "apple" = 2, "pie" = 2) + nutriment_amt = 4 + New() + ..() + bitesize = 3 + + +/obj/item/weapon/reagent_containers/food/snacks/cherrypie + name = "Cherry Pie" + desc = "Taste so good, make a grown man cry." + icon_state = "cherrypie" + filling_color = "#ff525a" + center_of_mass = "x=16;y=11" + nutriment_desc = list("sweetness" = 2, "cherry" = 2, "pie" = 2) + nutriment_amt = 4 + New() + ..() + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/twobread + name = "Two Bread" + desc = "It is very bitter and winy." + icon_state = "twobread" + filling_color = "#dbcc9a" + center_of_mass = "x=15;y=12" + nutriment_desc = list("sourness" = 2, "bread" = 2) + nutriment_amt = 2 + New() + ..() + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/threebread + name = "Three Bread" + desc = "Is such a thing even possible?" + icon_state = "threebread" + filling_color = "#dbcc9a" + center_of_mass = "x=15;y=12" + nutriment_desc = list("sourness" = 2, "bread" = 3) + nutriment_amt = 3 + New() + ..() + bitesize = 4 + +/obj/item/weapon/reagent_containers/food/snacks/jellysandwich + name = "Jelly Sandwich" + desc = "You wish you had some peanut butter to go with this..." + icon_state = "jellysandwich" + trash = /obj/item/trash/plate + filling_color = "#9e3a78" + center_of_mass = "x=16;y=8" + nutriment_desc = list("bread" = 2) + nutriment_amt = 2 + New() + ..() + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/jellysandwich/slime + New() + ..() + reagents.add_reagent(/datum/reagent/slimejelly, 5) + +/obj/item/weapon/reagent_containers/food/snacks/jellysandwich/cherry + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/cherryjelly, 5) + +/obj/item/weapon/reagent_containers/food/snacks/boiledslimecore + name = "Boiled slime Core" + desc = "A boiled red thing." + icon_state = "boiledslimecore" //nonexistant? + New() + ..() + reagents.add_reagent(/datum/reagent/slimejelly, 5) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/mint + name = "mint" + desc = "it is only wafer thin." + icon_state = "mint" + filling_color = "#f2f2f2" + center_of_mass = "x=16;y=14" + +/obj/item/weapon/reagent_containers/food/snacks/mint/New() + . = ..() + reagents.add_reagent(/datum/reagent/nutriment/mint, 1) + bitesize = 1 + +/obj/item/weapon/reagent_containers/food/snacks/mushroomsoup + name = "chantrelle soup" + desc = "A delicious and hearty mushroom soup." + icon_state = "mushroomsoup" + trash = /obj/item/trash/snack_bowl + filling_color = "#e386bf" + center_of_mass = "x=17;y=10" + nutriment_desc = list("mushroom" = 8, "milk" = 2) + nutriment_amt = 8 + New() + ..() + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/plumphelmetbiscuit + name = "plump helmet biscuit" + desc = "This is a finely-prepared plump helmet biscuit. The ingredients are exceptionally minced plump helmet, and well-minced dwarven wheat flour." + icon_state = "phelmbiscuit" + filling_color = "#cfb4c4" + center_of_mass = "x=16;y=13" + nutriment_desc = list("mushroom" = 4) + nutriment_amt = 5 + New() + ..() + if(prob(10)) + name = "exceptional plump helmet biscuit" + desc = "Microwave is taken by a fey mood! It has cooked an exceptional plump helmet biscuit!" + reagents.add_reagent(/datum/reagent/nutriment, 3) + reagents.add_reagent(/datum/reagent/tricordrazine, 5) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/chawanmushi + name = "chawanmushi" + desc = "A legendary egg custard that makes friends out of enemies. Probably too hot for a cat to eat." + icon_state = "chawanmushi" + trash = /obj/item/trash/snack_bowl + filling_color = "#f0f2e4" + center_of_mass = "x=17;y=10" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 5) + bitesize = 1 + +/obj/item/weapon/reagent_containers/food/snacks/beetsoup + name = "beet soup" + desc = "Wait, how do you spell it again..?" + icon_state = "beetsoup" + trash = /obj/item/trash/snack_bowl + filling_color = "#fac9ff" + center_of_mass = "x=15;y=8" + nutriment_desc = list("tomato" = 4, "beet" = 4) + nutriment_amt = 8 + New() + ..() + name = pick(list("borsch","bortsch","borstch","borsh","borshch","borscht")) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/tossedsalad + name = "tossed salad" + desc = "A proper salad, basic and simple, with little bits of carrot, tomato and apple intermingled. Vegan!" + icon_state = "herbsalad" + trash = /obj/item/trash/snack_bowl + filling_color = "#76b87f" + center_of_mass = "x=17;y=11" + nutriment_desc = list("salad" = 2, "tomato" = 2, "carrot" = 2, "apple" = 2) + nutriment_amt = 8 + New() + ..() + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/validsalad + name = "valid salad" + desc = "It's just a salad of questionable 'herbs' with meatballs and fried potato slices. Nothing suspicious about it." + icon_state = "validsalad" + trash = /obj/item/trash/snack_bowl + filling_color = "#76b87f" + center_of_mass = "x=17;y=11" + nutriment_desc = list("100% real salad") + nutriment_amt = 6 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 2) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/appletart + name = "golden apple streusel tart" + desc = "A tasty dessert that won't make it through a metal detector." + icon_state = "gappletart" + trash = /obj/item/trash/plate + filling_color = "#ffff00" + center_of_mass = "x=16;y=18" + nutriment_desc = list("apple" = 8) + nutriment_amt = 8 + New() + ..() + reagents.add_reagent(/datum/reagent/gold, 5) + bitesize = 3 + +/////////////////////////////////////////////////Sliceable//////////////////////////////////////// +// All the food items that can be sliced into smaller bits like Meatbread and Cheesewheels + +// sliceable is just an organization type path, it doesn't have any additional code or variables tied to it. + +/obj/item/weapon/reagent_containers/food/snacks/sliceable + w_class = ITEM_SIZE_NORMAL //Whole pizzas and cakes shouldn't fit in a pocket, you can slice them if you want to do that. + +/** + * A food item slice + * + * This path contains some extra code for spawning slices pre-filled with + * reagents. + */ +/obj/item/weapon/reagent_containers/food/snacks/slice + name = "slice of... something" + var/whole_path // path for the item from which this slice comes + var/filled = FALSE // should the slice spawn with any reagents + +/** + * Spawn a new slice of food + * + * If the slice's filled is TRUE, this will also fill the slice with the + * appropriate amount of reagents. Note that this is done by spawning a new + * whole item, transferring the reagents and deleting the whole item, which may + * have performance implications. + */ +/obj/item/weapon/reagent_containers/food/snacks/slice/Initialize() + . = ..() + if(filled) + var/obj/item/weapon/reagent_containers/food/snacks/whole = new whole_path() + if(whole && whole.slices_num) + var/reagent_amount = whole.reagents.total_volume/whole.slices_num + whole.reagents.trans_to_obj(src, reagent_amount) + + qdel(whole) + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/meatbread + name = "meatbread loaf" + desc = "The culinary base of every self-respecting eloquen/tg/entleman." + icon_state = "meatbread" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/meatbread + slices_num = 5 + filling_color = "#ff7575" + center_of_mass = "x=19;y=9" + nutriment_desc = list("bread" = 10) + nutriment_amt = 10 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 20) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/slice/meatbread + name = "meatbread slice" + desc = "A slice of delicious meatbread." + icon_state = "meatbreadslice" + trash = /obj/item/trash/plate + filling_color = "#ff7575" + bitesize = 2 + center_of_mass = "x=16;y=13" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/meatbread + +/obj/item/weapon/reagent_containers/food/snacks/slice/meatbread/filled + filled = TRUE + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/xenomeatbread + name = "xenomeatbread loaf" + desc = "The culinary base of every self-respecting eloquent gentleman. Extra Heretical." + icon_state = "xenomeatbread" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/xenomeatbread + slices_num = 5 + filling_color = "#8aff75" + center_of_mass = "x=16;y=9" + nutriment_desc = list("bread" = 10) + nutriment_amt = 10 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 20) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/slice/xenomeatbread + name = "xenomeatbread slice" + desc = "A slice of delicious meatbread. Extra Heretical." + icon_state = "xenobreadslice" + trash = /obj/item/trash/plate + filling_color = "#8aff75" + bitesize = 2 + center_of_mass = "x=16;y=13" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/xenomeatbread + + +/obj/item/weapon/reagent_containers/food/snacks/slice/xenomeatbread/filled + filled = TRUE + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/bananabread + name = "Banana-nut bread" + desc = "A heavenly and filling treat." + icon_state = "bananabread" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/bananabread + slices_num = 5 + filling_color = "#ede5ad" + center_of_mass = "x=16;y=9" + nutriment_desc = list("bread" = 10) + nutriment_amt = 10 + New() + ..() + reagents.add_reagent(/datum/reagent/drink/juice/banana, 20) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/slice/bananabread + name = "Banana-nut bread slice" + desc = "A slice of delicious banana bread." + icon_state = "bananabreadslice" + trash = /obj/item/trash/plate + filling_color = "#ede5ad" + bitesize = 2 + center_of_mass = "x=16;y=8" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/bananabread + +/obj/item/weapon/reagent_containers/food/snacks/slice/bananabread/filled + filled = TRUE + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/tofubread + name = "Tofubread" + icon_state = "Like meatbread but for vegetarians. Not guaranteed to give superpowers." + icon_state = "tofubread" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/tofubread + slices_num = 5 + filling_color = "#f7ffe0" + center_of_mass = "x=16;y=9" + nutriment_desc = list("tofu" = 10) + nutriment_amt = 10 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/slice/tofubread + name = "Tofubread slice" + desc = "A slice of delicious tofubread." + icon_state = "tofubreadslice" + trash = /obj/item/trash/plate + filling_color = "#f7ffe0" + bitesize = 2 + center_of_mass = "x=16;y=13" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/tofubread + +/obj/item/weapon/reagent_containers/food/snacks/slice/tofubread/filled + filled = TRUE + + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/carrotcake + name = "Carrot Cake" + desc = "A favorite desert of a certain wascally wabbit. Not a lie." + icon_state = "carrotcake" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/carrotcake + slices_num = 5 + filling_color = "#ffd675" + center_of_mass = "x=16;y=10" + nutriment_desc = list("cake" = 10, "sweetness" = 10, "carrot" = 15) + nutriment_amt = 25 + New() + ..() + reagents.add_reagent(/datum/reagent/imidazoline, 10) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/slice/carrotcake + name = "Carrot Cake slice" + desc = "Carrotty slice of Carrot Cake, carrots are good for your eyes! Also not a lie." + icon_state = "carrotcake_slice" + trash = /obj/item/trash/plate + filling_color = "#ffd675" + bitesize = 2 + center_of_mass = "x=16;y=14" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/carrotcake + +/obj/item/weapon/reagent_containers/food/snacks/slice/carrotcake/filled + filled = TRUE + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake + name = "Brain Cake" + desc = "A squishy cake-thing." + icon_state = "braincake" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/braincake + slices_num = 5 + filling_color = "#e6aedb" + center_of_mass = "x=16;y=10" + nutriment_desc = list("cake" = 10, "sweetness" = 10, "slime" = 15) + nutriment_amt = 5 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 25) + reagents.add_reagent(/datum/reagent/alkysine, 10) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/slice/braincake + name = "Brain Cake slice" + desc = "Lemme tell you something about prions. THEY'RE DELICIOUS." + icon_state = "braincakeslice" + trash = /obj/item/trash/plate + filling_color = "#e6aedb" + bitesize = 2 + center_of_mass = "x=16;y=12" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake + +/obj/item/weapon/reagent_containers/food/snacks/slice/braincake/filled + filled = TRUE + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesecake + name = "Cheese Cake" + desc = "DANGEROUSLY cheesy." + icon_state = "cheesecake" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/cheesecake + slices_num = 5 + filling_color = "#faf7af" + center_of_mass = "x=16;y=10" + nutriment_desc = list("cake" = 10, "cream" = 10, "cheese" = 15) + nutriment_amt = 10 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 15) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/slice/cheesecake + name = "Cheese Cake slice" + desc = "Slice of pure cheestisfaction." + icon_state = "cheesecake_slice" + trash = /obj/item/trash/plate + filling_color = "#faf7af" + bitesize = 2 + center_of_mass = "x=16;y=14" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesecake + +/obj/item/weapon/reagent_containers/food/snacks/slice/cheesecake/filled + filled = TRUE + + + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/plaincake + name = "Vanilla Cake" + desc = "A plain cake, not a lie." + icon_state = "plaincake" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/plaincake + slices_num = 5 + filling_color = "#f7edd5" + center_of_mass = "x=16;y=10" + nutriment_desc = list("cake" = 10, "sweetness" = 10, "vanilla" = 15) + nutriment_amt = 20 + +/obj/item/weapon/reagent_containers/food/snacks/slice/plaincake + name = "Vanilla Cake slice" + desc = "Just a slice of cake, it is enough for everyone." + icon_state = "plaincake_slice" + trash = /obj/item/trash/plate + filling_color = "#f7edd5" + bitesize = 2 + center_of_mass = "x=16;y=14" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/plaincake + +/obj/item/weapon/reagent_containers/food/snacks/slice/plaincake/filled + filled = TRUE + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/orangecake + name = "Orange Cake" + desc = "A cake with added orange." + icon_state = "orangecake" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/orangecake + slices_num = 5 + filling_color = "#fada8e" + center_of_mass = "x=16;y=10" + nutriment_desc = list("cake" = 10, "sweetness" = 10, "orange" = 15) + nutriment_amt = 20 + +/obj/item/weapon/reagent_containers/food/snacks/slice/orangecake + name = "Orange Cake slice" + desc = "Just a slice of cake, it is enough for everyone." + icon_state = "orangecake_slice" + trash = /obj/item/trash/plate + filling_color = "#fada8e" + bitesize = 2 + center_of_mass = "x=16;y=14" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/orangecake + +/obj/item/weapon/reagent_containers/food/snacks/slice/orangecake/filled + filled = TRUE + + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/limecake + name = "Lime Cake" + desc = "A cake with added lime." + icon_state = "limecake" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/limecake + slices_num = 5 + filling_color = "#cbfa8e" + center_of_mass = "x=16;y=10" + nutriment_desc = list("cake" = 10, "sweetness" = 10, "lime" = 15) + nutriment_amt = 20 + + +/obj/item/weapon/reagent_containers/food/snacks/slice/limecake + name = "Lime Cake slice" + desc = "Just a slice of cake, it is enough for everyone." + icon_state = "limecake_slice" + trash = /obj/item/trash/plate + filling_color = "#cbfa8e" + bitesize = 2 + center_of_mass = "x=16;y=14" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/limecake + +/obj/item/weapon/reagent_containers/food/snacks/slice/limecake/filled + filled = TRUE + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/lemoncake + name = "Lemon Cake" + desc = "A cake with added lemon." + icon_state = "lemoncake" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/lemoncake + slices_num = 5 + filling_color = "#fafa8e" + center_of_mass = "x=16;y=10" + nutriment_desc = list("cake" = 10, "sweetness" = 10, "lemon" = 15) + nutriment_amt = 20 + + +/obj/item/weapon/reagent_containers/food/snacks/slice/lemoncake + name = "Lemon Cake slice" + desc = "Just a slice of cake, it is enough for everyone." + icon_state = "lemoncake_slice" + trash = /obj/item/trash/plate + filling_color = "#fafa8e" + bitesize = 2 + center_of_mass = "x=16;y=14" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/lemoncake + +/obj/item/weapon/reagent_containers/food/snacks/slice/lemoncake/filled + filled = TRUE + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/chocolatecake + name = "Chocolate Cake" + desc = "A cake with added chocolate." + icon_state = "chocolatecake" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/chocolatecake + slices_num = 5 + filling_color = "#805930" + center_of_mass = "x=16;y=10" + nutriment_desc = list("cake" = 10, "sweetness" = 10, "chocolate" = 15) + nutriment_amt = 20 + +/obj/item/weapon/reagent_containers/food/snacks/slice/chocolatecake + name = "Chocolate Cake slice" + desc = "Just a slice of cake, it is enough for everyone." + icon_state = "chocolatecake_slice" + trash = /obj/item/trash/plate + filling_color = "#805930" + bitesize = 2 + center_of_mass = "x=16;y=14" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/chocolatecake + +/obj/item/weapon/reagent_containers/food/snacks/slice/chocolatecake/filled + filled = TRUE + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesewheel + name = "Cheese wheel" + desc = "A big wheel of delcious Cheddar." + icon_state = "cheesewheel" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/cheesewedge + slices_num = 5 + filling_color = "#fff700" + center_of_mass = "x=16;y=10" + nutriment_desc = list("cheese" = 10) + nutriment_amt = 10 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 10) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/cheesewedge + name = "Cheese wedge" + desc = "A wedge of delicious Cheddar. The cheese wheel it was cut from can't have gone far." + icon_state = "cheesewedge" + filling_color = "#fff700" + bitesize = 2 + center_of_mass = "x=16;y=10" + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/birthdaycake + name = "Birthday Cake" + desc = "Happy Birthday..." + icon_state = "birthdaycake" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/birthdaycake + slices_num = 5 + filling_color = "#ffd6d6" + center_of_mass = "x=16;y=10" + nutriment_desc = list("cake" = 10, "sweetness" = 10) + nutriment_amt = 20 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/sprinkles, 10) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/slice/birthdaycake + name = "Birthday Cake slice" + desc = "A slice of your birthday." + icon_state = "birthdaycakeslice" + trash = /obj/item/trash/plate + filling_color = "#ffd6d6" + bitesize = 2 + center_of_mass = "x=16;y=14" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/birthdaycake + +/obj/item/weapon/reagent_containers/food/snacks/slice/birthdaycake/filled + filled = TRUE + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/bread + name = "Bread" + icon_state = "Some plain old Earthen bread." + icon_state = "bread" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/bread + slices_num = 5 + filling_color = "#ffe396" + center_of_mass = "x=16;y=9" + nutriment_desc = list("bread" = 6) + nutriment_amt = 6 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/slice/bread + name = "Bread slice" + desc = "A slice of home." + icon_state = "breadslice" + trash = /obj/item/trash/plate + filling_color = "#d27332" + bitesize = 2 + center_of_mass = "x=16;y=4" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/bread + +/obj/item/weapon/reagent_containers/food/snacks/slice/bread/filled + filled = TRUE + + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/creamcheesebread + name = "Cream Cheese Bread" + desc = "Yum yum yum!" + icon_state = "creamcheesebread" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/creamcheesebread + slices_num = 5 + filling_color = "#fff896" + center_of_mass = "x=16;y=9" + nutriment_desc = list("bread" = 6, "cream" = 3, "cheese" = 3) + nutriment_amt = 5 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 15) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/slice/creamcheesebread + name = "Cream Cheese Bread slice" + desc = "A slice of yum!" + icon_state = "creamcheesebreadslice" + trash = /obj/item/trash/plate + filling_color = "#fff896" + bitesize = 2 + center_of_mass = "x=16;y=13" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/creamcheesebread + + +/obj/item/weapon/reagent_containers/food/snacks/slice/creamcheesebread/filled + filled = TRUE + + +/obj/item/weapon/reagent_containers/food/snacks/watermelonslice + name = "Watermelon Slice" + desc = "A slice of watery goodness." + icon_state = "watermelonslice" + filling_color = "#ff3867" + bitesize = 2 + center_of_mass = "x=16;y=10" + + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/applecake + name = "Apple Cake" + desc = "A cake centred with apples." + icon_state = "applecake" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/applecake + slices_num = 5 + filling_color = "#ebf5b8" + center_of_mass = "x=16;y=10" + nutriment_desc = list("cake" = 10, "sweetness" = 10, "apple" = 15) + nutriment_amt = 15 + +/obj/item/weapon/reagent_containers/food/snacks/slice/applecake + name = "Apple Cake slice" + desc = "A slice of heavenly cake." + icon_state = "applecakeslice" + trash = /obj/item/trash/plate + filling_color = "#ebf5b8" + bitesize = 2 + center_of_mass = "x=16;y=14" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/applecake + +/obj/item/weapon/reagent_containers/food/snacks/slice/applecake/filled + filled = TRUE + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/pumpkinpie + name = "Pumpkin Pie" + desc = "A delicious treat for the autumn months." + icon_state = "pumpkinpie" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/pumpkinpie + slices_num = 5 + filling_color = "#f5b951" + center_of_mass = "x=16;y=10" + nutriment_desc = list("pie" = 5, "cream" = 5, "pumpkin" = 5) + nutriment_amt = 15 + +/obj/item/weapon/reagent_containers/food/snacks/slice/pumpkinpie + name = "Pumpkin Pie slice" + desc = "A slice of pumpkin pie, with whipped cream on top. Perfection." + icon_state = "pumpkinpieslice" + trash = /obj/item/trash/plate + filling_color = "#f5b951" + bitesize = 2 + center_of_mass = "x=16;y=12" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pumpkinpie + +/obj/item/weapon/reagent_containers/food/snacks/slice/pumpkinpie/filled + filled = TRUE + +/obj/item/weapon/reagent_containers/food/snacks/cracker + name = "Cracker" + desc = "It's a salted cracker." + icon_state = "cracker" + filling_color = "#f5deb8" + center_of_mass = "x=17;y=6" + nutriment_desc = list("salt" = 1, "cracker" = 2) + nutriment_amt = 1 + + + +/////////////////////////////////////////////////PIZZA//////////////////////////////////////// + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza + slices_num = 6 + filling_color = "#baa14c" + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/margherita + name = "Margherita" + desc = "The golden standard of pizzas." + icon_state = "pizzamargherita" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/margherita + slices_num = 6 + center_of_mass = "x=16;y=11" + nutriment_desc = list("pizza crust" = 10, "tomato" = 10, "cheese" = 15) + nutriment_amt = 35 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 5) + reagents.add_reagent(/datum/reagent/drink/juice/tomato, 6) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/slice/margherita + name = "Margherita slice" + desc = "A slice of the classic pizza." + icon_state = "pizzamargheritaslice" + filling_color = "#baa14c" + bitesize = 2 + center_of_mass = "x=18;y=13" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/margherita + +/obj/item/weapon/reagent_containers/food/snacks/slice/margherita/filled + filled = TRUE + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza + name = "Meatpizza" + desc = "A pizza with meat topping." + icon_state = "meatpizza" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/meatpizza + slices_num = 6 + center_of_mass = "x=16;y=11" + nutriment_desc = list("pizza crust" = 10, "tomato" = 10, "cheese" = 15) + nutriment_amt = 10 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 34) + reagents.add_reagent(/datum/reagent/drink/juice/tomato, 6) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/slice/meatpizza + name = "Meatpizza slice" + desc = "A slice of a meaty pizza." + icon_state = "meatpizzaslice" + filling_color = "#baa14c" + bitesize = 2 + center_of_mass = "x=18;y=13" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza + +/obj/item/weapon/reagent_containers/food/snacks/slice/meatpizza/filled + filled = TRUE + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/mushroompizza + name = "Mushroompizza" + desc = "Very special pizza." + icon_state = "mushroompizza" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/mushroompizza + slices_num = 6 + center_of_mass = "x=16;y=11" + nutriment_desc = list("pizza crust" = 10, "tomato" = 10, "cheese" = 5, "mushroom" = 10) + nutriment_amt = 35 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 5) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/slice/mushroompizza + name = "Mushroompizza slice" + desc = "Maybe it is the last slice of pizza in your life." + icon_state = "mushroompizzaslice" + filling_color = "#baa14c" + bitesize = 2 + center_of_mass = "x=18;y=13" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/mushroompizza + +/obj/item/weapon/reagent_containers/food/snacks/slice/mushroompizza/filled + filled = TRUE + +/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/vegetablepizza + name = "Vegetable pizza" + desc = "No one of Tomato Sapiens were harmed during making this pizza." + icon_state = "vegetablepizza" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/vegetablepizza + slices_num = 6 + center_of_mass = "x=16;y=11" + nutriment_desc = list("pizza crust" = 10, "tomato" = 10, "cheese" = 5, "eggplant" = 5, "carrot" = 5, "corn" = 5) + nutriment_amt = 25 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 5) + reagents.add_reagent(/datum/reagent/drink/juice/tomato, 6) + reagents.add_reagent(/datum/reagent/imidazoline, 12) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/slice/vegetablepizza + name = "Vegetable pizza slice" + desc = "A slice of the most green pizza of all pizzas not containing green ingredients." + icon_state = "vegetablepizzaslice" + filling_color = "#baa14c" + bitesize = 2 + center_of_mass = "x=18;y=13" + whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/vegetablepizza + +/obj/item/weapon/reagent_containers/food/snacks/slice/vegetablepizza/filled + filled = TRUE + +/obj/item/pizzabox + name = "pizza box" + desc = "A box suited for pizzas." + icon = 'icons/obj/food.dmi' + icon_state = "pizzabox1" + + var/open = 0 // Is the box open? + var/ismessy = 0 // Fancy mess on the lid + var/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/pizza // Content pizza + var/list/boxes = list() // If the boxes are stacked, they come here + var/boxtag = "" + +/obj/item/pizzabox/update_icon() + + overlays = list() + + // Set appropriate description + if( open && pizza ) + desc = "A box suited for pizzas. It appears to have a [pizza.name] inside." + else if( boxes.len > 0 ) + desc = "A pile of boxes suited for pizzas. There appears to be [boxes.len + 1] boxes in the pile." + + var/obj/item/pizzabox/topbox = boxes[boxes.len] + var/toptag = topbox.boxtag + if( toptag != "" ) + desc = "[desc] The box on top has a tag, it reads: '[toptag]'." + else + desc = "A box suited for pizzas." + + if( boxtag != "" ) + desc = "[desc] The box has a tag, it reads: '[boxtag]'." + + // Icon states and overlays + if( open ) + if( ismessy ) + icon_state = "pizzabox_messy" + else + icon_state = "pizzabox_open" + + if( pizza ) + var/image/pizzaimg = image("food.dmi", icon_state = pizza.icon_state) + pizzaimg.pixel_y = -3 + overlays += pizzaimg + + return + else + // Stupid code because byondcode sucks + var/doimgtag = 0 + if( boxes.len > 0 ) + var/obj/item/pizzabox/topbox = boxes[boxes.len] + if( topbox.boxtag != "" ) + doimgtag = 1 + else + if( boxtag != "" ) + doimgtag = 1 + + if( doimgtag ) + var/image/tagimg = image("food.dmi", icon_state = "pizzabox_tag") + tagimg.pixel_y = boxes.len * 3 + overlays += tagimg + + icon_state = "pizzabox[boxes.len+1]" + +/obj/item/pizzabox/attack_hand( mob/user as mob ) + + if( open && pizza ) + user.put_in_hands( pizza ) + + to_chat(user, "You take \the [src.pizza] out of \the [src].") + src.pizza = null + update_icon() + return + + if( boxes.len > 0 ) + if( user.get_inactive_hand() != src ) + ..() + return + + var/obj/item/pizzabox/box = boxes[boxes.len] + boxes -= box + + user.put_in_hands( box ) + to_chat(user, "You remove the topmost [src] from your hand.") + box.update_icon() + update_icon() + return + ..() + +/obj/item/pizzabox/attack_self( mob/user as mob ) + + if( boxes.len > 0 ) + return + + open = !open + + if( open && pizza ) + ismessy = 1 + + update_icon() + +/obj/item/pizzabox/attackby( obj/item/I as obj, mob/user as mob ) + if( istype(I, /obj/item/pizzabox/) ) + var/obj/item/pizzabox/box = I + + if( !box.open && !src.open ) + // Make a list of all boxes to be added + var/list/boxestoadd = list() + boxestoadd += box + for(var/obj/item/pizzabox/i in box.boxes) + boxestoadd += i + + if( (boxes.len+1) + boxestoadd.len <= 5 ) + user.drop_item() + + box.loc = src + box.boxes = list() // Clear the box boxes so we don't have boxes inside boxes. - Xzibit + src.boxes.Add( boxestoadd ) + + box.update_icon() + update_icon() + + to_chat(user, "You put \the [box] ontop of \the [src]!") + else + to_chat(user, "The stack is too high!") + else + to_chat(user, "Close \the [box] first!") + + return + + if( istype(I, /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/) ) // Long ass fucking object name + + if( src.open ) + user.drop_item() + I.loc = src + src.pizza = I + + update_icon() + + to_chat(user, "You put \the [I] in \the [src]!") + else + to_chat(user, "You try to push \the [I] through the lid but it doesn't work!") + return + + if( istype(I, /obj/item/weapon/pen/) ) + + if( src.open ) + return + + var/t = sanitize(input("Enter what you want to add to the tag:", "Write", null, null) as text, 30) + + var/obj/item/pizzabox/boxtotagto = src + if( boxes.len > 0 ) + boxtotagto = boxes[boxes.len] + + boxtotagto.boxtag = copytext("[boxtotagto.boxtag][t]", 1, 30) + + update_icon() + return + ..() + +/obj/item/pizzabox/margherita/New() + pizza = new /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/margherita(src) + boxtag = "Margherita Deluxe" + +/obj/item/pizzabox/vegetable/New() + pizza = new /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/vegetablepizza(src) + boxtag = "Gourmet Vegatable" + +/obj/item/pizzabox/mushroom/New() + pizza = new /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/mushroompizza(src) + boxtag = "Mushroom Special" + +/obj/item/pizzabox/meat/New() + pizza = new /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza(src) + boxtag = "Meatlover's Supreme" + +/obj/item/weapon/reagent_containers/food/snacks/dionaroast + name = "roast diona" + desc = "It's like an enormous, leathery carrot. With an eye." + icon_state = "dionaroast" + trash = /obj/item/trash/plate + filling_color = "#75754b" + center_of_mass = "x=16;y=7" + nutriment_desc = list("a chorus of flavor" = 6) + nutriment_amt = 6 + New() + ..() + reagents.add_reagent(/datum/reagent/radium, 2) + bitesize = 2 + + + + +/////////////////////////////////////////// +// new old food stuff from bs12 +/////////////////////////////////////////// +/obj/item/weapon/reagent_containers/food/snacks/dough + name = "dough" + desc = "A piece of dough." + icon = 'icons/obj/food_ingredients.dmi' + icon_state = "dough" + bitesize = 2 + center_of_mass = "x=16;y=13" + nutriment_desc = list("dough" = 3) + nutriment_amt = 3 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 1) + +// Dough + rolling pin = flat dough +/obj/item/weapon/reagent_containers/food/snacks/dough/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/weapon/material/kitchen/rollingpin)) + new /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough(src) + to_chat(user, "You flatten the dough.") + qdel(src) + +// slicable into 3xdoughslices +/obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough + name = "flat dough" + desc = "A flattened dough." + icon = 'icons/obj/food_ingredients.dmi' + icon_state = "flat dough" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/doughslice + slices_num = 3 + center_of_mass = "x=16;y=16" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 1) + reagents.add_reagent(/datum/reagent/nutriment, 3) + +/obj/item/weapon/reagent_containers/food/snacks/doughslice + name = "dough slice" + desc = "A building block of an impressive dish." + icon = 'icons/obj/food_ingredients.dmi' + icon_state = "doughslice" + slice_path = /obj/item/weapon/reagent_containers/food/snacks/spagetti + slices_num = 1 + bitesize = 2 + center_of_mass = "x=17;y=19" + nutriment_desc = list("dough" = 1) + nutriment_amt = 1 + + +/obj/item/weapon/reagent_containers/food/snacks/bun + name = "bun" + desc = "A base for any self-respecting burger." + icon = 'icons/obj/food_ingredients.dmi' + icon_state = "bun" + bitesize = 2 + center_of_mass = "x=16;y=12" + nutriment_desc = list("bun" = 4) + nutriment_amt = 4 + + +/obj/item/weapon/reagent_containers/food/snacks/bun/attackby(obj/item/weapon/W as obj, mob/user as mob) + // Bun + meatball = burger + if(istype(W,/obj/item/weapon/reagent_containers/food/snacks/meatball)) + new /obj/item/weapon/reagent_containers/food/snacks/plainburger(src) + to_chat(user, "You make a burger.") + qdel(W) + qdel(src) + + // Bun + cutlet = hamburger + else if(istype(W,/obj/item/weapon/reagent_containers/food/snacks/cutlet)) + new /obj/item/weapon/reagent_containers/food/snacks/plainburger(src) + to_chat(user, "You make a burger.") + qdel(W) + qdel(src) + + // Bun + sausage = hotdog + else if(istype(W,/obj/item/weapon/reagent_containers/food/snacks/sausage)) + new /obj/item/weapon/reagent_containers/food/snacks/hotdog(src) + to_chat(user, "You make a hotdog.") + qdel(W) + qdel(src) + +// Burger + cheese wedge = cheeseburger +/obj/item/weapon/reagent_containers/food/snacks/plainburger/attackby(obj/item/weapon/reagent_containers/food/snacks/cheesewedge/W as obj, mob/user as mob) + if(istype(W))// && !istype(src,/obj/item/weapon/reagent_containers/food/snacks/cheesewedge)) + new /obj/item/weapon/reagent_containers/food/snacks/cheeseburger(src) + to_chat(user, "You make a cheeseburger.") + qdel(W) + qdel(src) + return + else + ..() + +// Human Burger + cheese wedge = cheeseburger +/obj/item/weapon/reagent_containers/food/snacks/human/burger/attackby(obj/item/weapon/reagent_containers/food/snacks/cheesewedge/W as obj, mob/user as mob) + if(istype(W)) + new /obj/item/weapon/reagent_containers/food/snacks/cheeseburger(src) + to_chat(user, "You make a cheeseburger.") + qdel(W) + qdel(src) + return + else + ..() + +/obj/item/weapon/reagent_containers/food/snacks/bunbun + name = "\improper Bun Bun" + desc = "A small bread monkey fashioned from two burger buns." + icon_state = "bunbun" + bitesize = 2 + center_of_mass = list("x"=16, "y"=8) + nutriment_desc = list("bun" = 8) + nutriment_amt = 8 + +/obj/item/weapon/reagent_containers/food/snacks/taco + name = "taco" + desc = "Take a bite!" + icon_state = "taco" + bitesize = 3 + center_of_mass = "x=21;y=12" + nutriment_desc = list("cheese" = 2,"taco shell" = 2) + nutriment_amt = 4 + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 3) + +/obj/item/weapon/reagent_containers/food/snacks/rawcutlet + name = "raw cutlet" + desc = "A thin piece of raw meat." + icon = 'icons/obj/food_ingredients.dmi' + icon_state = "rawcutlet" + bitesize = 1 + center_of_mass = "x=17;y=20" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 1) + +/obj/item/weapon/reagent_containers/food/snacks/cutlet + name = "cutlet" + desc = "A tasty meat slice." + icon = 'icons/obj/food_ingredients.dmi' + icon_state = "cutlet" + bitesize = 2 + center_of_mass = "x=17;y=20" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 2) + +/obj/item/weapon/reagent_containers/food/snacks/rawmeatball + name = "raw meatball" + desc = "A raw meatball." + icon = 'icons/obj/food_ingredients.dmi' + icon_state = "rawmeatball" + bitesize = 2 + center_of_mass = "x=16;y=15" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 2) + +/obj/item/weapon/reagent_containers/food/snacks/hotdog + name = "hotdog" + desc = "Unrelated to dogs, maybe." + icon_state = "hotdog" + bitesize = 2 + center_of_mass = "x=16;y=17" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 6) + +/obj/item/weapon/reagent_containers/food/snacks/classichotdog + name = "classic hotdog" + desc = "Going literal." + icon_state = "hotcorgi" + bitesize = 6 + center_of_mass = "x=16;y=17" + + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 16) + +/obj/item/weapon/reagent_containers/food/snacks/flatbread + name = "flatbread" + desc = "Bland but filling." + icon = 'icons/obj/food_ingredients.dmi' + icon_state = "flatbread" + bitesize = 2 + center_of_mass = "x=16;y=16" + nutriment_desc = list("bread" = 3) + nutriment_amt = 3 + +// potato + knife = raw sticks +/obj/item/weapon/reagent_containers/food/snacks/grown/potato/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/weapon/material/kitchen/utensil/knife)) + new /obj/item/weapon/reagent_containers/food/snacks/rawsticks(src) + to_chat(user, "You cut the potato.") + qdel(src) + else + ..() + +/obj/item/weapon/reagent_containers/food/snacks/rawsticks + name = "raw potato sticks" + desc = "Raw fries, not very tasty." + icon = 'icons/obj/food_ingredients.dmi' + icon_state = "rawsticks" + bitesize = 2 + center_of_mass = "x=16;y=12" + nutriment_desc = list("raw potato" = 3) + nutriment_amt = 3 + +/obj/item/weapon/reagent_containers/food/snacks/liquidfood + name = "\improper LiquidFood MRE" + desc = "A prepackaged grey slurry for all of the essential nutrients a soldier requires to survive. No expiration date is visible..." + icon_state = "liquidfood" + trash = /obj/item/trash/liquidfood + filling_color = "#a8a8a8" + center_of_mass = "x=16;y=15" + nutriment_desc = list("chalk" = 6) + nutriment_amt = 20 + New() + ..() + reagents.add_reagent(/datum/reagent/iron, 3) + bitesize = 4 + + +/obj/item/weapon/reagent_containers/food/snacks/tastybread + name = "bread tube" + desc = "Bread in a tube. Chewy...and surprisingly tasty." + icon_state = "tastybread" + trash = /obj/item/trash/tastybread + filling_color = "#a66829" + center_of_mass = "x=17;y=16" + nutriment_desc = list("bread" = 2, "sweetness" = 3) + nutriment_amt = 6 + New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/skrellsnacks + name = "\improper SkrellSnax" + desc = "Cured fungus shipped all the way from Jargon 4, almost like jerky! Almost." + icon_state = "skrellsnacks" + filling_color = "#a66829" + center_of_mass = "x=15;y=12" + nutriment_desc = list("mushroom" = 5, "salt" = 5) + nutriment_amt = 10 + New() + ..() + bitesize = 3 + + +/obj/item/weapon/reagent_containers/food/snacks/warfare + name = "\improper canned beans" + desc = "Supposedly what's in there is edible. But out on the frontlines it's about all you're getting." + icon_state = "cbeans" + atom_flags = 0 //They start closed + trash = /obj/item/trash/warfare_can + nutriment_desc = list("gross shit" = 6) + nutriment_amt = 20 + open_sound = 'sound/items/nonsoda_canopen.ogg' + drop_sound = 'sound/items/handle/can_drop.ogg' + var/open_can_icon = "cbeans_open" + New() + ..() + reagents.add_reagent(/datum/reagent/iron, 3) + bitesize = 4 + +/obj/item/weapon/reagent_containers/food/snacks/warfare/attack_self(mob/user) + return + + +/obj/item/weapon/reagent_containers/food/snacks/warfare/attack(mob/M as mob, mob/user as mob, def_zone) + if(!is_open_container()) + to_chat(user, "You need to open \the [src]!") + return + return ..() + +/obj/item/weapon/reagent_containers/food/snacks/warfare/attackby(obj/item/weapon/W, mob/user) + if(istype(W,/obj/item/weapon/material/sword/combat_knife)) + open(user) + update_icon() + +/obj/item/weapon/reagent_containers/food/snacks/warfare/update_icon() + if(is_open_container()) + icon_state = open_can_icon + +/obj/item/weapon/reagent_containers/food/snacks/warfare/flower + name = "\improper canned flowergrub" + icon_state = "flowersgrub" + open_can_icon = "flowersgrub_open" + desc = "A spinchy flowergrub mix. Tastes like shit but you'll eat it anyway." + trash = /obj/item/trash/warfare_can/flower + +/obj/item/weapon/reagent_containers/food/snacks/warfare/rat + name = "\improper canned ratmeat" + icon_state = "ratmeat" + open_can_icon = "ratmeat_open" + desc = "Just in case catching one yourself is too hard." + trash = /obj/item/trash/warfare_can/rat + +/obj/item/weapon/reagent_containers/food/snacks/warfare/sardine + name = "\improper pissardines" + icon_state = "pisssardine" + open_can_icon = "pisssardine_open" + desc = "A can of the only sort of fish that could live in these waters." + trash = /obj/item/trash/warfare_can/sardine \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food/snacks/meat.dm b/code/modules/reagents/reagent_containers/food/snacks/meat.dm new file mode 100644 index 00000000..94e94d46 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/snacks/meat.dm @@ -0,0 +1,64 @@ +/obj/item/weapon/reagent_containers/food/snacks/meat + name = "meat" + desc = "A slab of meat." + icon_state = "meat" + health = 180 + filling_color = "#ff1c1c" + center_of_mass = "x=16;y=14" + New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 9) + src.bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/meat/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/weapon/material/knife)) + new /obj/item/weapon/reagent_containers/food/snacks/rawcutlet(src) + new /obj/item/weapon/reagent_containers/food/snacks/rawcutlet(src) + new /obj/item/weapon/reagent_containers/food/snacks/rawcutlet(src) + to_chat(user, "You cut the meat into thin strips.") + qdel(src) + else + ..() + +/obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh + name = "synthetic meat" + desc = "A synthetic slab of flesh." + +// Seperate definitions because some food likes to know if it's human. +// TODO: rewrite kitchen code to check a var on the meat item so we can remove +// all these sybtypes. +/obj/item/weapon/reagent_containers/food/snacks/meat/human +/obj/item/weapon/reagent_containers/food/snacks/meat/monkey + //same as plain meat + +/obj/item/weapon/reagent_containers/food/snacks/meat/corgi + name = "corgi meat" + desc = "Tastes like... well, you know." + +/obj/item/weapon/reagent_containers/food/snacks/meat/beef + name = "beef slab" + desc = "The classic red meat." + +/obj/item/weapon/reagent_containers/food/snacks/meat/goat + name = "chevon slab" + desc = "Goat meat, to the uncultured." + +/obj/item/weapon/reagent_containers/food/snacks/meat/chicken + name = "chicken piece" + desc = "It tastes like you'd expect." + +/obj/item/weapon/reagent_containers/food/snacks/meat/roachmeat + name = "roach meat" + desc = "Gross piece of roach meat." + icon_state = "xenomeat" + filling_color = "#e2ffde" + center_of_mass ="x=17;y=13" + + New() + ..() + reagents.add_reagent(/datum/reagent/toxin/blattedin, 10) + bitesize = 6 + +/obj/item/weapon/reagent_containers/food/snacks/meat/rat_meat + name = "rat meat" + desc = "It's gross... but sometimes that's as good as you're getting." \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm new file mode 100644 index 00000000..17f90d14 --- /dev/null +++ b/code/modules/reagents/reagent_containers/glass.dm @@ -0,0 +1,286 @@ + +//////////////////////////////////////////////////////////////////////////////// +/// (Mixing)Glass. +//////////////////////////////////////////////////////////////////////////////// +/obj/item/weapon/reagent_containers/glass + name = " " + var/base_name = " " + desc = "" + icon = 'icons/obj/chemical.dmi' + icon_state = "null" + item_state = "null" + amount_per_transfer_from_this = 10 + possible_transfer_amounts = "5;10;15;25;30;60" + volume = 60 + w_class = ITEM_SIZE_SMALL + atom_flags = ATOM_FLAG_OPEN_CONTAINER + unacidable = 1 //glass doesn't dissolve in acid + drop_sound = 'sound/items/drop_glass.ogg' + table_sound = 'sound/items/placing_glass.ogg' + table_pickup_sound = 'sound/items/generic_lift.ogg' + + var/list/can_be_placed_into = list( + /obj/machinery/chem_master/, + /obj/machinery/chemical_dispenser, + /obj/machinery/reagentgrinder, + /obj/structure/table, + /obj/structure/closet, + /obj/structure/sink, + /obj/item/weapon/storage, + /obj/machinery/atmospherics/unary/cryo_cell, + /obj/item/weapon/grenade/chem_grenade, + /mob/living/bot/medbot, + /obj/item/weapon/storage/secure/safe, + /obj/structure/iv_drip, + /obj/machinery/disease2/incubator, + /obj/machinery/disposal, + /mob/living/simple_animal/cow, + /mob/living/simple_animal/hostile/retaliate/goat, + /obj/machinery/computer/centrifuge, + /obj/machinery/sleeper, + /obj/machinery/smartfridge/, + /obj/machinery/biogenerator, + /obj/machinery/constructable_frame, + /obj/machinery/radiocarbon_spectrometer + ) + +/obj/item/weapon/reagent_containers/glass/New() + ..() + base_name = name + +/obj/item/weapon/reagent_containers/glass/examine(var/mob/user) + if(!..(user, 2)) + return + if(reagents && reagents.reagent_list.len) + to_chat(user, "It contains [reagents.total_volume] units of liquid.") + else + to_chat(user, "It is empty.") + if(!is_open_container()) + to_chat(user, "The airtight lid seals it completely.") + +/obj/item/weapon/reagent_containers/glass/attack_self() + ..() + if(is_open_container()) + to_chat(usr, "You put the lid on \the [src].") + atom_flags ^= ATOM_FLAG_OPEN_CONTAINER + else + to_chat(usr, "You take the lid off \the [src].") + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + update_icon() + +/obj/item/weapon/reagent_containers/glass/attack(mob/M as mob, mob/user as mob, def_zone) + if(force && !(item_flags & ITEM_FLAG_NO_BLUDGEON) && user.a_intent == I_HURT) + return ..() + if(standard_feed_mob(user, M)) + return + return 0 + +/obj/item/weapon/reagent_containers/glass/standard_feed_mob(var/mob/user, var/mob/target) + if(!is_open_container()) + to_chat(user, "You need to open \the [src] first.") + return 1 + if(user.a_intent == I_HURT) + return 1 + return ..() + +/obj/item/weapon/reagent_containers/glass/self_feed_message(var/mob/user) + to_chat(user, "You swallow a gulp from \the [src].") + +/obj/item/weapon/reagent_containers/glass/afterattack(var/obj/target, var/mob/user, var/proximity) + if(!is_open_container() || !proximity) //Is the container open & are they next to whatever they're clicking? + return 1 //If not, do nothing. + for(var/type in can_be_placed_into) //Is it something it can be placed into? + if(istype(target, type)) + return 1 + if(standard_dispenser_refill(user, target)) //Are they clicking a water tank/some dispenser? + return 1 + if(standard_pour_into(user, target)) //Pouring into another beaker? + return + if(user.a_intent == I_HURT) + if(standard_splash_mob(user,target)) + return 1 + if(reagents && reagents.total_volume) + to_chat(user, "You splash the contents of \the [src] onto [target].") //They are on harm intent, aka wanting to spill it. + reagents.splash(target, reagents.total_volume) + return 1 + ..() + +/obj/item/weapon/reagent_containers/glass/beaker + name = "beaker" + desc = "A beaker." + icon = 'icons/obj/chemical.dmi' + icon_state = "beaker" + item_state = "beaker" + center_of_mass = "x=15;y=10" + matter = list("glass" = 500) + + New() + ..() + desc += " Can hold up to [volume] units." + + on_reagent_change() + update_icon() + + pickup(mob/user) + ..() + update_icon() + + dropped(mob/user) + ..() + update_icon() + + attack_hand() + ..() + update_icon() + + update_icon() + overlays.Cut() + + if(reagents.total_volume) + var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]10") + + var/percent = round((reagents.total_volume / volume) * 100) + switch(percent) + if(0 to 9) filling.icon_state = "[icon_state]-10" + if(10 to 24) filling.icon_state = "[icon_state]10" + if(25 to 49) filling.icon_state = "[icon_state]25" + if(50 to 74) filling.icon_state = "[icon_state]50" + if(75 to 79) filling.icon_state = "[icon_state]75" + if(80 to 90) filling.icon_state = "[icon_state]80" + if(91 to INFINITY) filling.icon_state = "[icon_state]100" + + filling.color = reagents.get_color() + overlays += filling + + if (!is_open_container()) + var/image/lid = image(icon, src, "lid_[initial(icon_state)]") + overlays += lid + +/obj/item/weapon/reagent_containers/glass/beaker/large + name = "large beaker" + desc = "A large beaker." + icon_state = "beakerlarge" + center_of_mass = "x=16;y=10" + matter = list("glass" = 5000) + volume = 120 + amount_per_transfer_from_this = 10 + possible_transfer_amounts = "5;10;15;25;30;60;120" + atom_flags = ATOM_FLAG_OPEN_CONTAINER + +/obj/item/weapon/reagent_containers/glass/beaker/noreact + name = "cryostasis beaker" + desc = "A cryostasis beaker that allows for chemical storage without reactions." + icon_state = "beakernoreact" + center_of_mass = "x=16;y=8" + matter = list("glass" = 500) + volume = 60 + amount_per_transfer_from_this = 10 + atom_flags = ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_NO_REACT + +/obj/item/weapon/reagent_containers/glass/beaker/bluespace + name = "bluespace beaker" + desc = "A bluespace beaker, powered by experimental bluespace technology." + icon_state = "beakerbluespace" + center_of_mass = "x=16;y=10" + matter = list("glass" = 5000) + volume = 300 + amount_per_transfer_from_this = 10 + possible_transfer_amounts = "5;10;15;25;30;60;120;150;200;250;300" + atom_flags = ATOM_FLAG_OPEN_CONTAINER + +/obj/item/weapon/reagent_containers/glass/beaker/vial + name = "vial" + desc = "A small glass vial." + icon_state = "vial" + center_of_mass = "x=15;y=8" + matter = list("glass" = 250) + volume = 30 + w_class = ITEM_SIZE_TINY //half the volume of a bottle, half the size + amount_per_transfer_from_this = 10 + possible_transfer_amounts = "5;10;15;30" + atom_flags = ATOM_FLAG_OPEN_CONTAINER + +/obj/item/weapon/reagent_containers/glass/beaker/cryoxadone + New() + ..() + reagents.add_reagent(/datum/reagent/cryoxadone, 30) + update_icon() + +/obj/item/weapon/reagent_containers/glass/beaker/sulphuric + New() + ..() + reagents.add_reagent(/datum/reagent/acid, 60) + update_icon() + +/obj/item/weapon/reagent_containers/glass/bucket + desc = "It's a bucket." + name = "bucket" + icon = 'icons/obj/janitor.dmi' + icon_state = "bucket" + item_state = "bucket" + center_of_mass = "x=16;y=9" + matter = list(DEFAULT_WALL_MATERIAL = 280) + w_class = ITEM_SIZE_NORMAL + amount_per_transfer_from_this = 20 + possible_transfer_amounts = "10;20;30;60;120;150;180" + volume = 180 + atom_flags = ATOM_FLAG_OPEN_CONTAINER + unacidable = 0 + +/obj/item/weapon/reagent_containers/glass/bucket/attackby(var/obj/D, mob/user as mob) + + if(isprox(D)) + to_chat(user, "You add [D] to [src].") + qdel(D) + user.put_in_hands(new /obj/item/weapon/bucket_sensor) + user.drop_from_inventory(src) + qdel(src) + return + else if(istype(D, /obj/item/weapon/mop)) + if(reagents.total_volume < 1) + to_chat(user, "\The [src] is empty!") + else + reagents.trans_to_obj(D, 5) + to_chat(user, "You wet \the [D] in \the [src].") + playsound(loc, 'sound/effects/slosh.ogg', 25, 1) + return + else + return ..() + +/obj/item/weapon/reagent_containers/glass/bucket/update_icon() + overlays.Cut() + if (!is_open_container()) + var/image/lid = image(icon, src, "lid_[initial(icon_state)]") + overlays += lid + +/* +/obj/item/weapon/reagent_containers/glass/blender_jug + name = "Blender Jug" + desc = "A blender jug, part of a blender." + icon = 'icons/obj/kitchen.dmi' + icon_state = "blender_jug_e" + volume = 100 + + on_reagent_change() + switch(src.reagents.total_volume) + if(0) + icon_state = "blender_jug_e" + if(1 to 75) + icon_state = "blender_jug_h" + if(76 to 100) + icon_state = "blender_jug_f" + +/obj/item/weapon/reagent_containers/glass/canister //not used apparantly + desc = "It's a canister. Mainly used for transporting fuel." + name = "canister" + icon = 'icons/obj/tank.dmi' + icon_state = "canister" + item_state = "canister" + m_amt = 300 + g_amt = 0 + w_class = ITEM_SIZE_HUGE + + amount_per_transfer_from_this = 20 + possible_transfer_amounts = "10;20;30;60" + volume = 120 +*/ diff --git a/code/modules/reagents/reagent_containers/glass/bottle.dm b/code/modules/reagents/reagent_containers/glass/bottle.dm new file mode 100644 index 00000000..789dce98 --- /dev/null +++ b/code/modules/reagents/reagent_containers/glass/bottle.dm @@ -0,0 +1,253 @@ + +//Not to be confused with /obj/item/weapon/reagent_containers/food/drinks/bottle + +/obj/item/weapon/reagent_containers/glass/bottle + name = "bottle" + desc = "A small bottle." + icon = 'icons/obj/chemical.dmi' + icon_state = null + item_state = "atoxinbottle" + randpixel = 7 + center_of_mass = "x=15;y=10" + amount_per_transfer_from_this = 10 + possible_transfer_amounts = "5;10;15;25;30;60" + w_class = ITEM_SIZE_SMALL + item_flags = 0 + obj_flags = 0 + volume = 60 + + on_reagent_change() + update_icon() + + pickup(mob/user) + ..() + update_icon() + + dropped(mob/user) + ..() + update_icon() + + attack_hand() + ..() + update_icon() + + New() + ..() + if(!icon_state) + icon_state = "bottle-[rand(1,4)]" + + update_icon() + overlays.Cut() + + if(reagents.total_volume && (icon_state == "bottle-1" || icon_state == "bottle-2" || icon_state == "bottle-3" || icon_state == "bottle-4")) + var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]10") + + var/percent = round((reagents.total_volume / volume) * 100) + switch(percent) + if(0 to 9) filling.icon_state = "[icon_state]--10" + if(10 to 24) filling.icon_state = "[icon_state]-10" + if(25 to 49) filling.icon_state = "[icon_state]-25" + if(50 to 74) filling.icon_state = "[icon_state]-50" + if(75 to 79) filling.icon_state = "[icon_state]-75" + if(80 to 90) filling.icon_state = "[icon_state]-80" + if(91 to INFINITY) filling.icon_state = "[icon_state]-100" + + filling.color = reagents.get_color() + overlays += filling + + if (!is_open_container()) + var/image/lid = image(icon, src, "lid_bottle") + overlays += lid + + +/obj/item/weapon/reagent_containers/glass/bottle/inaprovaline + name = "inaprovaline bottle" + desc = "A small bottle. Contains inaprovaline - used to stabilize patients." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-4" + +/obj/item/weapon/reagent_containers/glass/bottle/inaprovaline/New() + ..() + reagents.add_reagent(/datum/reagent/inaprovaline, 60) + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/toxin + name = "toxin bottle" + desc = "A small bottle of toxins. Do not drink, it is poisonous." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-3" + +/obj/item/weapon/reagent_containers/glass/bottle/toxin/New() + ..() + reagents.add_reagent(/datum/reagent/toxin, 60) + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/cyanide + name = "cyanide bottle" + desc = "A small bottle of cyanide. Bitter almonds?" + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-3" + +/obj/item/weapon/reagent_containers/glass/bottle/cyanide/New() + ..() + reagents.add_reagent(/datum/reagent/toxin/cyanide, 30) //volume changed to match chloral + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/stoxin + name = "soporific bottle" + desc = "A small bottle of soporific. Just the fumes make you sleepy." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-3" + +/obj/item/weapon/reagent_containers/glass/bottle/stoxin/New() + ..() + reagents.add_reagent(/datum/reagent/soporific, 60) + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/chloralhydrate + name = "Chloral Hydrate Bottle" + desc = "A small bottle of Choral Hydrate. Mickey's Favorite!" + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-3" + +/obj/item/weapon/reagent_containers/glass/bottle/chloralhydrate/New() + ..() + reagents.add_reagent(/datum/reagent/chloralhydrate, 30) //Intentionally low since it is so strong. Still enough to knock someone out. + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/antitoxin + name = "dylovene bottle" + desc = "A small bottle of dylovene. Counters poisons, and repairs damage. A wonder drug." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-4" + +/obj/item/weapon/reagent_containers/glass/bottle/antitoxin/New() + ..() + reagents.add_reagent(/datum/reagent/dylovene, 60) + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/mutagen + name = "unstable mutagen bottle" + desc = "A small bottle of unstable mutagen. Randomly changes the DNA structure of whoever comes in contact." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-1" + +/obj/item/weapon/reagent_containers/glass/bottle/mutagen/New() + ..() + reagents.add_reagent(/datum/reagent/mutagen, 60) + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/ammonia + name = "ammonia bottle" + desc = "A small bottle." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-1" + +/obj/item/weapon/reagent_containers/glass/bottle/ammonia/New() + ..() + reagents.add_reagent(/datum/reagent/ammonia, 60) + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/eznutrient + name = "\improper EZ NUtrient bottle" + desc = "A small bottle." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-4" + +/obj/item/weapon/reagent_containers/glass/bottle/eznutrient/New() + ..() + reagents.add_reagent(/datum/reagent/toxin/fertilizer/eznutrient, 60) + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/left4zed + name = "\improper Left-4-Zed bottle" + desc = "A small bottle." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-4" + +/obj/item/weapon/reagent_containers/glass/bottle/left4zed/New() + ..() + reagents.add_reagent(/datum/reagent/toxin/fertilizer/left4zed, 60) + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/robustharvest + name = "\improper Robust Harvest" + desc = "A small bottle." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-4" + +/obj/item/weapon/reagent_containers/glass/bottle/robustharvest/New() + ..() + reagents.add_reagent(/datum/reagent/toxin/fertilizer/robustharvest, 60) + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/diethylamine + name = "diethylamine bottle" + desc = "A small bottle." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-4" + +/obj/item/weapon/reagent_containers/glass/bottle/diethylamine/New() + ..() + reagents.add_reagent(/datum/reagent/diethylamine, 60) + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/pacid + name = "Polytrinic Acid Bottle" + desc = "A small bottle. Contains a small amount of Polytrinic Acid." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-4" + +/obj/item/weapon/reagent_containers/glass/bottle/pacid/New() + ..() + reagents.add_reagent(/datum/reagent/acid/polyacid, 60) + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/adminordrazine + name = "Adminordrazine Bottle" + desc = "A small bottle. Contains the liquid essence of the gods." + icon = 'icons/obj/drinks.dmi' + icon_state = "holyflask" + + +/obj/item/weapon/reagent_containers/glass/bottle/adminordrazine/New() + ..() + reagents.add_reagent(/datum/reagent/adminordrazine, 60) + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/capsaicin + name = "Capsaicin Bottle" + desc = "A small bottle. Contains hot sauce." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-4" + +/obj/item/weapon/reagent_containers/glass/bottle/capsaicin/New() + ..() + reagents.add_reagent(/datum/reagent/capsaicin, 60) + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/frostoil + name = "Frost Oil Bottle" + desc = "A small bottle. Contains cold sauce." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-4" + +/obj/item/weapon/reagent_containers/glass/bottle/frostoil/New() + ..() + reagents.add_reagent(/datum/reagent/frostoil, 60) + update_icon() diff --git a/code/modules/reagents/reagent_containers/glass/bottle/robot.dm b/code/modules/reagents/reagent_containers/glass/bottle/robot.dm new file mode 100644 index 00000000..f390e9b6 --- /dev/null +++ b/code/modules/reagents/reagent_containers/glass/bottle/robot.dm @@ -0,0 +1,34 @@ + +/obj/item/weapon/reagent_containers/glass/bottle/robot + amount_per_transfer_from_this = 10 + possible_transfer_amounts = "5;10;15;25;30;50;100" + atom_flags = ATOM_FLAG_OPEN_CONTAINER + volume = 60 + var/reagent = "" + + +/obj/item/weapon/reagent_containers/glass/bottle/robot/inaprovaline + name = "internal inaprovaline bottle" + desc = "A small bottle. Contains inaprovaline - used to stabilize patients." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-4" + reagent = /datum/reagent/inaprovaline + + New() + ..() + reagents.add_reagent(/datum/reagent/inaprovaline, 60) + update_icon() + + +/obj/item/weapon/reagent_containers/glass/bottle/robot/antitoxin + name = "internal anti-toxin bottle" + desc = "A small bottle of Anti-toxins. Counters poisons, and repairs damage, a wonder drug." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-4" + reagent = /datum/reagent/dylovene + + New() + ..() + reagents.add_reagent(/datum/reagent/dylovene, 60) + update_icon() + diff --git a/code/modules/reagents/reagent_containers/glass/jar.dm b/code/modules/reagents/reagent_containers/glass/jar.dm new file mode 100644 index 00000000..e428beb0 --- /dev/null +++ b/code/modules/reagents/reagent_containers/glass/jar.dm @@ -0,0 +1,159 @@ +/obj/item/weapon/reagent_containers/glass/jar + name = "chemical jar" + desc = "Old and dusty. The kind you would find in the laboratory of some mad scientist." + icon = 'icons/obj/items/chem_jars.dmi' + icon_state = "generic" + + item_state = "chemjar" + can_be_placed_into = list() + atom_flags = 0x0000 + volume = 120 + w_class = ITEM_SIZE_NORMAL //this is mainly because chemmasters and grinders now check for beaker "size" + + var/content = "nothing" + +/obj/item/weapon/reagent_containers/glass/jar/update_icon() + overlays.Cut() + + if (!is_open_container()) + var/image/lid = image(icon, src, "lid") + overlays += lid + +/obj/item/weapon/reagent_containers/glass/jar/New() + ..() + name = "[content] [initial(name)]" + desc += " The faded label reads: [content]." + update_icon() + +/obj/item/weapon/reagent_containers/glass/jar/acetone + icon_state = "acetone" + content = "acetone" + New() + ..() + reagents.add_reagent(/datum/reagent/acetone, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/ammonia + icon_state = "ammonia" + content = "ammonia" + New() + ..() + reagents.add_reagent(/datum/reagent/ammonia, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/aluminum + icon_state = "aluminum" + content = "aluminum powder" + New() + ..() + reagents.add_reagent(/datum/reagent/aluminum, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/carbon + icon_state = "carbon" + content = "carbon dust" + New() + ..() + reagents.add_reagent(/datum/reagent/carbon, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/copper + icon_state = "copper" + content = "cuprum dust" + New() + ..() + reagents.add_reagent(/datum/reagent/copper, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/ethanol + icon_state = "ethanol" + content = "ethanol" + New() + ..() + reagents.add_reagent(/datum/reagent/ethanol, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/hydrazine + icon_state = "hydrazine" + content = "hydrazine" + New() + ..() + reagents.add_reagent(/datum/reagent/hydrazine, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/hydrochloric + icon_state = "hydrochloric_acid" + content = "hydrochloric acid" + New() + ..() + reagents.add_reagent(/datum/reagent/acid/hydrochloric, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/iron + icon_state = "iron" + content = "ferrum dust" + New() + ..() + reagents.add_reagent(/datum/reagent/iron, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/lithium + icon_state = "lithium" + content = "lithium" + New() + ..() + reagents.add_reagent(/datum/reagent/lithium, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/mercury + icon_state = "mercury" + content = "quicksilver" + New() + ..() + reagents.add_reagent(/datum/reagent/mercury, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/phosphorus + icon_state = "phosphorus" + content = "phosphorus dust" + New() + ..() + reagents.add_reagent(/datum/reagent/phosphorus, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/potassium + icon_state = "potassium" + content = "potassium" + New() + ..() + reagents.add_reagent(/datum/reagent/potassium, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/radium + icon_state = "radium" + content = "radium" + New() + ..() + reagents.add_reagent(/datum/reagent/radium, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/silicon + icon_state = "silicon" + content = "silicon" + New() + ..() + reagents.add_reagent(/datum/reagent/silicon, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/sodium + icon_state = "sodium" + content = "natrium" + New() + ..() + reagents.add_reagent(/datum/reagent/sodium, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/sugar + icon_state = "sugar" + content = "sugar" + New() + ..() + reagents.add_reagent(/datum/reagent/sugar, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/sulfur + icon_state = "sulfur" + content = "sulfur" + New() + ..() + reagents.add_reagent(/datum/reagent/sulfur, rand(volume/2,volume)) + +/obj/item/weapon/reagent_containers/glass/jar/sulphuric_acid + icon_state = "sulphuric_acid" + content = "sulphuric acid" + New() + ..() + reagents.add_reagent(/datum/reagent/acid, rand(volume/2,volume)) diff --git a/code/modules/reagents/reagent_containers/glass/supply.dm b/code/modules/reagents/reagent_containers/glass/supply.dm new file mode 100644 index 00000000..e14ac0a3 --- /dev/null +++ b/code/modules/reagents/reagent_containers/glass/supply.dm @@ -0,0 +1,60 @@ +//Combo supply packs of chemical jars, split into two +/decl/hierarchy/supply_pack/reagents/base + name = "Chemistry - Basic Chemicals" + contains = list( + /obj/item/weapon/reagent_containers/glass/jar/aluminum, + /obj/item/weapon/reagent_containers/glass/jar/carbon, + /obj/item/weapon/reagent_containers/glass/jar/copper, + /obj/item/weapon/reagent_containers/glass/jar/ethanol, + /obj/item/weapon/reagent_containers/glass/jar/iron, + /obj/item/weapon/reagent_containers/glass/jar/silicon, + //obj/item/weapon/reagent_containers/glass/jar/sugar, + /obj/item/weapon/reagent_containers/glass/jar/sulfur + ) + cost = 50 + containertype = /obj/structure/closet/crate/secure + containername = "chemical crate" + access = list(access_chemistry) + +/decl/hierarchy/supply_pack/reagents/restricted + name = "Chemistry - Restricted Chemicals" + contains = list( + /obj/item/weapon/reagent_containers/glass/jar/acetone, + /obj/item/weapon/reagent_containers/glass/jar/ammonia, + /obj/item/weapon/reagent_containers/glass/jar/hydrazine, + /obj/item/weapon/reagent_containers/glass/jar/hydrochloric, + /obj/item/weapon/reagent_containers/glass/jar/lithium, + /obj/item/weapon/reagent_containers/glass/jar/mercury, + /obj/item/weapon/reagent_containers/glass/jar/phosphorus, + /obj/item/weapon/reagent_containers/glass/jar/potassium, + /obj/item/weapon/reagent_containers/glass/jar/radium, + /obj/item/weapon/reagent_containers/glass/jar/sodium, + /obj/item/weapon/reagent_containers/glass/jar/sulphuric_acid + ) + cost = 100 + containertype = /obj/structure/closet/crate/secure + containername = "chemical crate" + access = list(access_chemistry) + +// Individual chemical supply packs. +// Chemistry-restricted (raw reagents excluding sugar/water) +// Datum path Contents type Supply pack name Container name Cost Container access +SEC_PACK(hydrazine, /obj/item/weapon/reagent_containers/glass/jar/hydrazine, "Chemistry - Hydrazine", "hydrazine crate", 15, access_chemistry) +SEC_PACK(lithium, /obj/item/weapon/reagent_containers/glass/jar/lithium, "Chemistry - Lithium", "lithium crate", 15, access_chemistry) +SEC_PACK(carbon, /obj/item/weapon/reagent_containers/glass/jar/carbon, "Chemistry - Carbon dust", "carbon crate", 10, access_chemistry) +SEC_PACK(ammonia, /obj/item/weapon/reagent_containers/glass/jar/ammonia, "Chemistry - Ammonia", "ammonia crate", 15, access_chemistry) +SEC_PACK(acetone, /obj/item/weapon/reagent_containers/glass/jar/acetone, "Chemistry - Acetone", "acetone crate", 15, access_chemistry) +SEC_PACK(sodium, /obj/item/weapon/reagent_containers/glass/jar/sodium, "Chemistry - Sodium", "sodium crate", 15, access_chemistry) +SEC_PACK(aluminium, /obj/item/weapon/reagent_containers/glass/jar/aluminum, "Chemistry - Aluminum powder", "aluminum crate", 10, access_chemistry) +SEC_PACK(silicon, /obj/item/weapon/reagent_containers/glass/jar/silicon, "Chemistry - Silicon", "silicon crate", 10, access_chemistry) +SEC_PACK(phosphorus,/obj/item/weapon/reagent_containers/glass/jar/phosphorus, "Chemistry - Phosphorus", "phosphorus crate", 15, access_chemistry) +SEC_PACK(sulfur, /obj/item/weapon/reagent_containers/glass/jar/sulfur, "Chemistry - Sulfur", "sulfur crate", 10, access_chemistry) +SEC_PACK(hclacid, /obj/item/weapon/reagent_containers/glass/jar/hydrochloric,"Chemistry - Hydrochloric acid","hydrochloric acid crate", 15, access_chemistry) +SEC_PACK(potassium, /obj/item/weapon/reagent_containers/glass/jar/potassium, "Chemistry - Potassium", "potassium crate", 15, access_chemistry) +SEC_PACK(iron, /obj/item/weapon/reagent_containers/glass/jar/iron, "Chemistry - Ferrum dust", "ferrum dust crate", 10, access_chemistry) +SEC_PACK(copper, /obj/item/weapon/reagent_containers/glass/jar/copper, "Chemistry - Cuprum dust", "cuprum dust crate", 10, access_chemistry) +SEC_PACK(mercury, /obj/item/weapon/reagent_containers/glass/jar/mercury, "Chemistry - Quicksilver", "quicksilver crate", 15, access_chemistry) +SEC_PACK(radium, /obj/item/weapon/reagent_containers/glass/jar/radium, "Chemistry - Radium", "radium crate", 15, access_chemistry) +SEC_PACK(ethanol, /obj/item/weapon/reagent_containers/glass/jar/ethanol, "Chemistry - Ethanol", "ethanol crate", 10, access_chemistry) +SEC_PACK(sacid, /obj/item/weapon/reagent_containers/glass/jar/sulphuric_acid,"Chemistry - Sulfuric Acid", "sulfuric acid crate", 15, access_chemistry) +//SEC_PACK(tungsten, /obj/item/weapon/reagent_containers/chem_disp_cartridge/tungsten, "Reagent refill - Tungsten", "tungsten reagent cartridge crate", 10, access_chemistry) diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm new file mode 100644 index 00000000..a05751d4 --- /dev/null +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -0,0 +1,238 @@ +//////////////////////////////////////////////////////////////////////////////// +/// HYPOSPRAY +//////////////////////////////////////////////////////////////////////////////// + +/obj/item/weapon/reagent_containers/hypospray //obsolete, use hypospray/vial for the actual hypospray item + name = "hypospray" + desc = "The DeForest Medical Corporation hypospray is a sterile, air-needle autoinjector for rapid administration of drugs to patients." + icon = 'icons/obj/syringe.dmi' + item_state = "hypo" + icon_state = "hypo" + origin_tech = list(TECH_MATERIAL = 4, TECH_BIO = 5) + amount_per_transfer_from_this = 5 + unacidable = 1 + volume = 30 + possible_transfer_amounts = null + atom_flags = ATOM_FLAG_OPEN_CONTAINER + slot_flags = SLOT_EARS + w_class = ITEM_SIZE_SMALL + var/inject_sound = 'sound/items/hypoinject.ogg' + +///obj/item/weapon/reagent_containers/hypospray/New() //comment this to make hypos start off empty +// ..() +// reagents.add_reagent(/datum/reagent/tricordrazine, 30) +// return + +/obj/item/weapon/reagent_containers/hypospray/do_surgery(mob/living/carbon/M, mob/living/user) + if(user.a_intent != I_HELP) //in case it is ever used as a surgery tool + return ..() + attack(M, user) + return 1 + +/obj/item/weapon/reagent_containers/hypospray/attack(mob/living/M as mob, mob/user as mob) + if(!reagents.total_volume) + to_chat(user, "[src] is empty.") + return + if (!istype(M)) + return + + var/mob/living/carbon/human/H = M + if(istype(H)) + var/obj/item/organ/external/affected = H.get_organ(user.zone_sel.selecting) + if(!affected) + to_chat(user, "\The [H] is missing that limb!") + return + else if(affected.robotic >= ORGAN_ROBOT) + to_chat(user, "You cannot inject a robotic limb.") + return + + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + user.do_attack_animation(M) + to_chat(user, "You inject [M] with [src].") + to_chat(M, "You feel a tiny prick!") + user.visible_message("[user] injects [M] with [src].") + + if(M.reagents) + var/contained = reagentlist() + var/trans = reagents.trans_to_mob(M, amount_per_transfer_from_this, CHEM_BLOOD) + admin_inject_log(user, M, src, contained, trans) + to_chat(user, "[trans] units injected. [reagents.total_volume] units remaining in \the [src].") + + playsound(M, inject_sound, 100) + return + +/obj/item/weapon/reagent_containers/hypospray/vial + name = "hypospray" + item_state = "autoinjector" + desc = "The DeForest Medical Corporation hypospray is a sterile, air-needle autoinjector for rapid administration of drugs to patients. Uses a replacable 30u vial." + var/obj/item/weapon/reagent_containers/glass/beaker/vial/loaded_vial + volume = 0 + +/obj/item/weapon/reagent_containers/hypospray/vial/New() + ..() + loaded_vial = new /obj/item/weapon/reagent_containers/glass/beaker/vial(src) + volume = loaded_vial.volume + reagents.maximum_volume = loaded_vial.reagents.maximum_volume + +/obj/item/weapon/reagent_containers/hypospray/vial/attack_hand(mob/user as mob) + if(user.get_inactive_hand() == src) + if(loaded_vial) + reagents.trans_to_holder(loaded_vial.reagents,volume) + reagents.maximum_volume = 0 + loaded_vial.update_icon() + user.put_in_hands(loaded_vial) + loaded_vial = null + to_chat(user, "You remove the vial from the [src].") + update_icon() + playsound(src.loc, 'sound/weapons/flipblade.ogg', 50, 1) + return + ..() + else + return ..() + +/obj/item/weapon/reagent_containers/hypospray/vial/attackby(obj/item/weapon/W, mob/user as mob) + if(istype(W, /obj/item/weapon/reagent_containers/glass/beaker/vial)) + if(!loaded_vial) + if(!do_after(user,10) || loaded_vial || !(W in user)) + return 0 + if(W.is_open_container()) + W.atom_flags ^= ATOM_FLAG_OPEN_CONTAINER + W.update_icon() + user.drop_item() + W.forceMove(src) + loaded_vial = W + reagents.maximum_volume = loaded_vial.reagents.maximum_volume + loaded_vial.reagents.trans_to_holder(reagents,volume) + user.visible_message("[user] has loaded [W] into \the [src].","You load \the [W] into \the [src].") + update_icon() + playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1) + else + to_chat(user,"\The [src] already has a vial.") + else + ..() + +/obj/item/weapon/reagent_containers/hypospray/autoinjector + name = "autoinjector" + desc = "A rapid and safe way to administer small amounts of drugs by untrained or trained personnel." + icon_state = "blue" + item_state = "autoinjector" + amount_per_transfer_from_this = 5 + volume = 5 + origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) + var/list/starts_with = list(/datum/reagent/inaprovaline = 5) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/New() + ..() + for(var/T in starts_with) + reagents.add_reagent(T, starts_with[T]) + update_icon() + return + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/attack(mob/M as mob, mob/user as mob) + ..() + if(reagents.total_volume <= 0) //Prevents autoinjectors to be refilled. + atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER + update_icon() + return + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/update_icon() + if(reagents.total_volume > 0) + icon_state = "[initial(icon_state)]1" + else + icon_state = "[initial(icon_state)]0" + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/examine(mob/user) + . = ..(user) + if(reagents && reagents.reagent_list.len) + to_chat(user, "It is currently loaded.") + else + to_chat(user, "It is spent.") + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/detox + name = "autoinjector (antitox)" + icon_state = "green" + starts_with = list(/datum/reagent/dylovene = 5) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/pain + name = "autoinjector (painkiller)" + icon_state = "purple" + starts_with = list(/datum/reagent/tramadol = 10) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/combatpain + name = "autoinjector (oxycodone)" + icon_state = "black" + starts_with = list(/datum/reagent/tramadol/oxycodone = 5) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/revive + name = "autoinjector (atepoine)" + icon_state = "black" + starts_with = list(/datum/reagent/atepoine = 10) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/mindbreaker + name = "autoinjector" + icon_state = "black" + starts_with = list(/datum/reagent/mindbreaker = 5) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/blood + name = "blood injector" + desc = "A blood injector, contained O- blood." + icon_state = "n" + + amount_per_transfer_from_this = 50 + volume = 500 + var/blood_type = "O-" + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/blood/New() + ..() + if(blood_type) + reagents.add_reagent(/datum/reagent/blood, volume, list("donor" = null, "blood_DNA" = null, "blood_type" = blood_type, "trace_chem" = null, "virus2" = list(), "antibodies" = list())) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/morphine + name = "morphine syrette" + icon_state = "syrette_closed" + starts_with = list(/datum/reagent/tramadol/morphine = 10) + inject_sound = 'sound/items/syrette_inject.ogg' + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/morphine/update_icon() + if(reagents.total_volume > 0) + icon_state = "syrette_closed" + else + icon_state = "syrette_open" + +/obj/item/weapon/reagent_containers/glass/ampule + name = "ampule" + desc = "An ampule. Holds reagents. Usually pain medication. Use a syrette on it to refill the syrette." + icon = 'icons/obj/syringe.dmi' + icon_state = "ampule" + item_state = null + amount_per_transfer_from_this = 10 + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_EARS + volume = 100 + var/closed = 1 + +/obj/item/weapon/reagent_containers/glass/ampule/attack_self() + ..() + if(closed) + to_chat(usr, "You crack \the [src], opening it.") + playsound(src, 'sound/items/plastic_rip.ogg', 100) + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + icon_state = "[initial(icon_state)]_open" + closed = 0 + else + return + update_icon() + +/obj/item/weapon/reagent_containers/glass/ampule/morphine + name = "morphine ampule" + New() + ..() + reagents.add_reagent(/datum/reagent/tramadol/morphine, 100) + +/obj/item/weapon/reagent_containers/glass/ampule/attackby(obj/item/weapon/W, mob/user as mob) + if(istype(W, /obj/item/weapon/reagent_containers/hypospray/autoinjector)) + var/obj/item/weapon/reagent_containers/hypospray/autoinjector/A = W + if(src.reagents) + var/trans = reagents.trans_to_obj(A, amount_per_transfer_from_this) + to_chat(user, "[trans] units refilled into \the [A]. [reagents.total_volume] units remaining in \the [src].") + A.update_icon() diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm new file mode 100644 index 00000000..c9b01f21 --- /dev/null +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -0,0 +1,317 @@ +//////////////////////////////////////////////////////////////////////////////// +/// Pills. +//////////////////////////////////////////////////////////////////////////////// +/obj/item/weapon/reagent_containers/pill + name = "pill" + desc = "A pill." + icon = 'icons/obj/chemical.dmi' + icon_state = null + item_state = "pill" + randpixel = 7 + possible_transfer_amounts = null + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + volume = 60 + +/obj/item/weapon/reagent_containers/pill/New() + ..() + if(!icon_state) + icon_state = "pill[rand(1, 5)]" //preset pills only use colour changing or unique icons + +/obj/item/weapon/reagent_containers/pill/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 + + to_chat(M, "You swallow \the [src].") + M.drop_from_inventory(src) //icon update + if(reagents.total_volume) + reagents.trans_to_mob(M, reagents.total_volume, CHEM_INGEST) + playsound(M, 'sound/voice/swallow.ogg', 100, TRUE) + qdel(src) + return 1 + + else if(istype(M, /mob/living/carbon/human)) + if(!M.can_force_feed(user, src)) + return + + user.visible_message("[user] attempts to force [M] to swallow \the [src].") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(!do_mob(user, M)) + return + user.drop_from_inventory(src) //icon update + user.visible_message("[user] forces [M] to swallow \the [src].") + var/contained = reagentlist() + admin_attack_log(user, M, "Fed the victim with [name] (Reagents: [contained])", "Was fed [src] (Reagents: [contained])", "used [src] (Reagents: [contained]) to feed") + if(reagents.total_volume) + reagents.trans_to_mob(M, reagents.total_volume, CHEM_INGEST) + playsound(M, 'sound/voice/swallow.ogg', 100, TRUE) + qdel(src) + return 1 + + return 0 + +/obj/item/weapon/reagent_containers/pill/afterattack(obj/target, mob/user, proximity) + if(!proximity) return + + if(target.is_open_container() && target.reagents) + if(!target.reagents.total_volume) + to_chat(user, "[target] is empty. Can't dissolve \the [src].") + return + to_chat(user, "You dissolve \the [src] in [target].") + + admin_attacker_log(user, "spiked \a [target] with a pill. Reagents: [reagentlist()]") + reagents.trans_to(target, reagents.total_volume) + for(var/mob/O in viewers(2, user)) + O.show_message("[user] puts something in \the [target].", 1) + qdel(src) + return + +//////////////////////////////////////////////////////////////////////////////// +/// Pills. END +//////////////////////////////////////////////////////////////////////////////// + +//Pills +/obj/item/weapon/reagent_containers/pill/antitox + name = "Dylovene (25u)" + desc = "Neutralizes many common toxins." + icon_state = "pill1" +/obj/item/weapon/reagent_containers/pill/antitox/New() + ..() + reagents.add_reagent(/datum/reagent/dylovene, 25) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/tox + name = "toxins pill" + desc = "Highly toxic." + icon_state = "pill4" +/obj/item/weapon/reagent_containers/pill/tox/New() + ..() + reagents.add_reagent(/datum/reagent/toxin, 50) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/cyanide + name = "strange pill" + desc = "It's marked 'KCN'. Smells vaguely of almonds." + icon_state = "pillS" +/obj/item/weapon/reagent_containers/pill/cyanide/New() + ..() + reagents.add_reagent(/datum/reagent/toxin/cyanide, 50) + + +/obj/item/weapon/reagent_containers/pill/adminordrazine + name = "Adminordrazine pill" + desc = "It's magic. We don't have to explain it." + icon_state = "pillA" +/obj/item/weapon/reagent_containers/pill/adminordrazine/New() + ..() + reagents.add_reagent(/datum/reagent/adminordrazine, 50) + + +/obj/item/weapon/reagent_containers/pill/stox + name = "Soporific (15u)" + desc = "Commonly used to treat insomnia." + icon_state = "pill3" +/obj/item/weapon/reagent_containers/pill/stox/New() + ..() + reagents.add_reagent(/datum/reagent/soporific, 15) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/kelotane + name = "Kelotane (15u)" + desc = "Used to treat burns." + icon_state = "pill2" +/obj/item/weapon/reagent_containers/pill/kelotane/New() + ..() + reagents.add_reagent(/datum/reagent/kelotane, 15) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/paracetamol + name = "Paracetamol (15u)" + desc = "Tylenol! A painkiller for the ages. Chewables!" + icon_state = "pill3" +/obj/item/weapon/reagent_containers/pill/paracetamol/New() + ..() + reagents.add_reagent(/datum/reagent/paracetamol, 15) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/tramadol + name = "Tramadol (15u)" + desc = "A simple painkiller." + icon_state = "pill3" +/obj/item/weapon/reagent_containers/pill/tramadol/New() + ..() + reagents.add_reagent(/datum/reagent/tramadol, 15) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/inaprovaline + name = "Inaprovaline (30u)" + desc = "Used to stabilize patients." + icon_state = "pill1" +/obj/item/weapon/reagent_containers/pill/inaprovaline/New() + ..() + reagents.add_reagent(/datum/reagent/inaprovaline, 30) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/dexalin + name = "Dexalin (15u)" + desc = "Used to treat oxygen deprivation." + icon_state = "pill1" +/obj/item/weapon/reagent_containers/pill/dexalin/New() + ..() + reagents.add_reagent(/datum/reagent/dexalin, 15) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/dexalin_plus + name = "Dexalin Plus (15u)" + desc = "Used to treat extreme oxygen deprivation." + icon_state = "pill2" +/obj/item/weapon/reagent_containers/pill/dexalin_plus/New() + ..() + reagents.add_reagent(/datum/reagent/dexalinp, 15) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/dermaline + name = "Dermaline (15u)" + desc = "Used to treat burn wounds." + icon_state = "pill2" +/obj/item/weapon/reagent_containers/pill/dermaline/New() + ..() + reagents.add_reagent(/datum/reagent/dermaline, 15) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/dylovene + name = "Dylovene (15u)" + desc = "A broad-spectrum anti-toxin." + icon_state = "pill1" +/obj/item/weapon/reagent_containers/pill/dylovene/New() + ..() + reagents.add_reagent(/datum/reagent/dylovene, 15) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/inaprovaline + name = "Inaprovaline (30u)" + desc = "Used to stabilize patients." + icon_state = "pill2" +/obj/item/weapon/reagent_containers/pill/inaprovaline/New() + ..() + reagents.add_reagent(/datum/reagent/inaprovaline, 30) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/bicaridine + name = "Bicaridine (20u)" + desc = "Used to treat physical injuries." + icon_state = "pill2" +/obj/item/weapon/reagent_containers/pill/bicaridine/New() + ..() + reagents.add_reagent(/datum/reagent/bicaridine, 20) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/happy + name = "happy pill" + desc = "Happy happy joy joy!" + icon_state = "pill4" +/obj/item/weapon/reagent_containers/pill/happy/New() + ..() + reagents.add_reagent(/datum/reagent/space_drugs, 15) + reagents.add_reagent(/datum/reagent/sugar, 15) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/zoom + name = "zoom pill" + desc = "Zoooom!" + icon_state = "pill4" +/obj/item/weapon/reagent_containers/pill/zoom/New() + ..() + reagents.add_reagent(/datum/reagent/impedrezene, 10) + reagents.add_reagent(/datum/reagent/synaptizine, 5) + reagents.add_reagent(/datum/reagent/hyperzine, 5) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/spaceacillin + name = "Spaceacillin (10u)" + desc = "Contains antiviral agents." + icon_state = "pill3" +/obj/item/weapon/reagent_containers/pill/spaceacillin/New() + ..() + reagents.add_reagent(/datum/reagent/spaceacillin, 10) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/diet + name = "diet pill" + desc = "Guaranteed to get you slim!" + icon_state = "pill4" +/obj/item/weapon/reagent_containers/pill/diet/New() + ..() + reagents.add_reagent(/datum/reagent/lipozine, 2) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/noexcutite + name = "Noexcutite (15u)" + desc = "Feeling jittery? This should calm you down." + icon_state = "pill4" +obj/item/weapon/reagent_containers/pill/noexcutite/New() + ..() + reagents.add_reagent(/datum/reagent/noexcutite, 15) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/antidexafen + name = "Antidexafen (15u)" + desc = "Common cold mediciation. Safe for babies!" + icon_state = "pill4" +/obj/item/weapon/reagent_containers/pill/antidexafen/New() + ..() + reagents.add_reagent(/datum/reagent/antidexafen, 10) + reagents.add_reagent(/datum/reagent/drink/juice/lemon, 5) + reagents.add_reagent(/datum/reagent/menthol, REM*0.2) + color = reagents.get_color() + +//Psychiatry pills. +/obj/item/weapon/reagent_containers/pill/methylphenidate + name = "Methylphenidate (15u)" + desc = "Improves the ability to concentrate." + icon_state = "pill2" +/obj/item/weapon/reagent_containers/pill/methylphenidate/New() + ..() + reagents.add_reagent(/datum/reagent/methylphenidate, 15) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/citalopram + name = "Citalopram (15u)" + desc = "Mild anti-depressant." + icon_state = "pill4" +/obj/item/weapon/reagent_containers/pill/citalopram/New() + ..() + reagents.add_reagent(/datum/reagent/citalopram, 15) + color = reagents.get_color() + + +/obj/item/weapon/reagent_containers/pill/paroxetine + name = "Paroxetine (10u)" + desc = "Before you swallow a bullet: try swallowing this!" + icon_state = "pill4" +/obj/item/weapon/reagent_containers/pill/paroxetine/New() + ..() + reagents.add_reagent(/datum/reagent/paroxetine, 10) + color = reagents.get_color() \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm new file mode 100644 index 00000000..e8f7e646 --- /dev/null +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -0,0 +1,221 @@ +/obj/item/weapon/reagent_containers/spray + name = "spray bottle" + desc = "A spray bottle, with an unscrewable top." + icon = 'icons/obj/janitor.dmi' + icon_state = "cleaner" + item_state = "cleaner" + item_flags = ITEM_FLAG_NO_BLUDGEON + atom_flags = ATOM_FLAG_OPEN_CONTAINER + slot_flags = SLOT_BELT + throwforce = 3 + w_class = ITEM_SIZE_SMALL + throw_speed = 2 + throw_range = 10 + amount_per_transfer_from_this = 10 + unacidable = 1 //plastic + possible_transfer_amounts = "5;10" //Set to null instead of list, if there is only one. + var/spray_size = 3 + var/list/spray_sizes = list(1,3) + var/step_delay = 10 // lower is faster + volume = 250 + +/obj/item/weapon/reagent_containers/spray/New() + ..() + src.verbs -= /obj/item/weapon/reagent_containers/verb/set_APTFT + +/obj/item/weapon/reagent_containers/spray/afterattack(atom/A as mob|obj, mob/user as mob, proximity) + if(istype(A, /obj/item/weapon/storage) || istype(A, /obj/structure/table) || istype(A, /obj/structure/closet) || istype(A, /obj/item/weapon/reagent_containers) || istype(A, /obj/structure/sink) || istype(A, /obj/structure/janitorialcart)) + return + + if(istype(A, /spell)) + return + + if(proximity) + if(standard_dispenser_refill(user, A)) + return + + if(reagents.total_volume < amount_per_transfer_from_this) + to_chat(user, "\The [src] is empty!") + return + + Spray_at(A, user, proximity) + + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + + if(reagents.has_reagent(/datum/reagent/acid)) + message_admins("[key_name_admin(user)] fired sulphuric acid from \a [src].") + log_game("[key_name(user)] fired sulphuric acid from \a [src].") + if(reagents.has_reagent(/datum/reagent/acid/polyacid)) + message_admins("[key_name_admin(user)] fired Polyacid from \a [src].") + log_game("[key_name(user)] fired Polyacid from \a [src].") + if(reagents.has_reagent(/datum/reagent/lube)) + message_admins("[key_name_admin(user)] fired Space lube from \a [src].") + log_game("[key_name(user)] fired Space lube from \a [src].") + return + +/obj/item/weapon/reagent_containers/spray/proc/Spray_at(atom/A as mob|obj, mob/user as mob, proximity) + playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6) + if (A.density && proximity) + A.visible_message("[usr] sprays [A] with [src].") + reagents.splash(A, amount_per_transfer_from_this) + else + spawn(0) + var/obj/effect/effect/water/chempuff/D = new/obj/effect/effect/water/chempuff(get_turf(src)) + var/turf/my_target = get_turf(A) + D.create_reagents(amount_per_transfer_from_this) + if(!src) + return + reagents.trans_to_obj(D, amount_per_transfer_from_this) + D.set_color() + D.set_up(my_target, spray_size, step_delay) + return + +/obj/item/weapon/reagent_containers/spray/attack_self(var/mob/user) + if(!possible_transfer_amounts) + return + amount_per_transfer_from_this = next_in_list(amount_per_transfer_from_this, cached_number_list_decode(possible_transfer_amounts)) + spray_size = next_in_list(spray_size, spray_sizes) + to_chat(user, "You adjusted the pressure nozzle. You'll now use [amount_per_transfer_from_this] units per spray.") + +/obj/item/weapon/reagent_containers/spray/examine(mob/user) + if(..(user, 0) && loc == user) + to_chat(user, "[round(reagents.total_volume)] unit\s left.") + return + +/obj/item/weapon/reagent_containers/spray/verb/empty() + + set name = "Empty Spray Bottle" + set category = "Object" + set src in usr + + if (alert(usr, "Are you sure you want to empty that?", "Empty Bottle:", "Yes", "No") != "Yes") + return + if(isturf(usr.loc)) + to_chat(usr, "You empty \the [src] onto the floor.") + reagents.splash(usr.loc, reagents.total_volume) + +//space cleaner +/obj/item/weapon/reagent_containers/spray/cleaner + name = "space cleaner" + desc = "BLAM!-brand non-foaming space cleaner!" + step_delay = 6 + +/obj/item/weapon/reagent_containers/spray/cleaner/warfare + name = "trench cleaner" + desc = "Something has to get rid of the practitioner's leftovers." + +/obj/item/weapon/reagent_containers/spray/cleaner/New() + ..() + reagents.add_reagent(/datum/reagent/space_cleaner, volume) + +/obj/item/weapon/reagent_containers/spray/sterilizine + name = "sterilizine" + desc = "Great for hiding incriminating bloodstains and sterilizing scalpels." + +/obj/item/weapon/reagent_containers/spray/sterilizine/New() + ..() + reagents.add_reagent(/datum/reagent/sterilizine, volume) + +/obj/item/weapon/reagent_containers/spray/hair_remover + name = "hair remover" + desc = "Very effective at removing hair, feathers, spines and horns." + +/obj/item/weapon/reagent_containers/spray/hair_remover/New() + ..() + reagents.add_reagent(/datum/reagent/toxin/hair_remover, volume) + +/obj/item/weapon/reagent_containers/spray/pepper + name = "pepperspray" + desc = "Manufactured by Uhang Inc., it fires a mist of condensed capsaicin to blind and down an opponent quickly." + icon = 'icons/obj/weapons.dmi' + icon_state = "pepperspray" + item_state = "pepperspray" + possible_transfer_amounts = null + volume = 60 + var/safety = 1 + step_delay = 1 + +/obj/item/weapon/reagent_containers/spray/pepper/New() + ..() + reagents.add_reagent(/datum/reagent/capsaicin/condensed, 60) + +/obj/item/weapon/reagent_containers/spray/pepper/examine(mob/user) + if(..(user, 1)) + to_chat(user, "The safety is [safety ? "on" : "off"].") + +/obj/item/weapon/reagent_containers/spray/pepper/attack_self(var/mob/user) + safety = !safety + to_chat(usr, "You switch the safety [safety ? "on" : "off"].") + +/obj/item/weapon/reagent_containers/spray/pepper/Spray_at(atom/A as mob|obj) + if(safety) + to_chat(usr, "The safety is on!") + return + ..() + +/obj/item/weapon/reagent_containers/spray/waterflower + name = "water flower" + desc = "A seemingly innocent sunflower...with a twist." + icon = 'icons/obj/device.dmi' + icon_state = "sunflower" + item_state = "sunflower" + amount_per_transfer_from_this = 1 + possible_transfer_amounts = null + volume = 10 + +/obj/item/weapon/reagent_containers/spray/waterflower/New() + ..() + reagents.add_reagent(/datum/reagent/water, 10) + +/obj/item/weapon/reagent_containers/spray/chemsprayer + name = "chem sprayer" + desc = "A utility used to spray large amounts of reagent in a given area." + icon = 'icons/obj/gun.dmi' + icon_state = "chemsprayer" + item_state = "chemsprayer" + throwforce = 3 + w_class = ITEM_SIZE_LARGE + possible_transfer_amounts = null + volume = 600 + origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 3, TECH_ENGINEERING = 3) + step_delay = 8 + +/obj/item/weapon/reagent_containers/spray/chemsprayer/Spray_at(atom/A as mob|obj) + var/direction = get_dir(src, A) + var/turf/T = get_turf(A) + var/turf/T1 = get_step(T,turn(direction, 90)) + var/turf/T2 = get_step(T,turn(direction, -90)) + var/list/the_targets = list(T, T1, T2) + + for(var/a = 1 to 3) + spawn(0) + if(reagents.total_volume < 1) break + var/obj/effect/effect/water/chempuff/D = new/obj/effect/effect/water/chempuff(get_turf(src)) + var/turf/my_target = the_targets[a] + D.create_reagents(amount_per_transfer_from_this) + if(!src) + return + reagents.trans_to_obj(D, amount_per_transfer_from_this) + D.set_color() + D.set_up(my_target, rand(6, 8), 2) + return + +/obj/item/weapon/reagent_containers/spray/plantbgone + name = "Plant-B-Gone" + desc = "Kills those pesky weeds!" + icon = 'icons/obj/hydroponics_machines.dmi' + icon_state = "plantbgone" + item_state = "plantbgone" + volume = 100 + +/obj/item/weapon/reagent_containers/spray/plantbgone/New() + ..() + reagents.add_reagent(/datum/reagent/toxin/plantbgone, 100) + +/obj/item/weapon/reagent_containers/spray/plantbgone/afterattack(atom/A as mob|obj, mob/user as mob, proximity) + if(!proximity) return + + if(istype(A, /obj/effect/blob)) // blob damage in blob code + return + + ..() \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm new file mode 100644 index 00000000..00a048c2 --- /dev/null +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -0,0 +1,382 @@ +//////////////////////////////////////////////////////////////////////////////// +/// Syringes. +//////////////////////////////////////////////////////////////////////////////// +#define SYRINGE_DRAW 0 +#define SYRINGE_INJECT 1 +#define SYRINGE_BROKEN 2 + +/obj/item/weapon/reagent_containers/syringe + name = "syringe" + desc = "A syringe." + icon = 'icons/obj/syringe.dmi' + item_state = "syringe_0" + icon_state = "0" + matter = list("glass" = 150) + amount_per_transfer_from_this = 5 + possible_transfer_amounts = null + volume = 15 + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + sharp = 1 + unacidable = 1 //glass + grab_sound = 'sound/items/handle/syringe_pickup.ogg' + drop_sound = 'sound/items/handle/syringe_drop.ogg' + var/mode = SYRINGE_DRAW + var/image/filling //holds a reference to the current filling overlay + var/visible_name = "a syringe" + var/time = 30 + +/obj/item/weapon/reagent_containers/syringe/on_reagent_change() + update_icon() + +/obj/item/weapon/reagent_containers/syringe/pickup(mob/user) + ..() + update_icon() + +/obj/item/weapon/reagent_containers/syringe/dropped(mob/user) + ..() + update_icon() + +/obj/item/weapon/reagent_containers/syringe/attack_self(mob/user as mob) + switch(mode) + if(SYRINGE_DRAW) + mode = SYRINGE_INJECT + if(SYRINGE_INJECT) + mode = SYRINGE_DRAW + if(SYRINGE_BROKEN) + return + update_icon() + +/obj/item/weapon/reagent_containers/syringe/attack_hand() + ..() + update_icon() + +/obj/item/weapon/reagent_containers/syringe/attackby(obj/item/I as obj, mob/user as mob) + return + +/obj/item/weapon/reagent_containers/syringe/do_surgery(mob/living/carbon/M, mob/living/user) + if(user.a_intent == I_HURT) + return 0 + if(user.a_intent != I_HELP) //in case it is ever used as a surgery tool + return ..() + afterattack(M, user, 1) + return 1 + +/obj/item/weapon/reagent_containers/syringe/afterattack(obj/target, mob/user, proximity) + if(!proximity) + return + + if(mode == SYRINGE_BROKEN) + to_chat(user, "This syringe is broken.") + return + + if(istype(target, /obj/structure/closet/body_bag)) + handleBodyBag(target, user) + return + + if(!target.reagents) + return + + if(user.a_intent == I_HURT && ismob(target)) + syringestab(target, user) + return + + handleTarget(target, user) + +/obj/item/weapon/reagent_containers/syringe/update_icon() + overlays.Cut() + + if(mode == SYRINGE_BROKEN) + icon_state = "broken" + return + + var/rounded_vol = round(reagents.total_volume, round(reagents.maximum_volume / 3)) + if(ismob(loc)) + var/injoverlay + switch(mode) + if (SYRINGE_DRAW) + injoverlay = "draw" + if (SYRINGE_INJECT) + injoverlay = "inject" + overlays += injoverlay + icon_state = "[rounded_vol]" + item_state = "syringe_[rounded_vol]" + + if(reagents.total_volume) + filling = image('icons/obj/reagentfillings.dmi', src, "syringe10") + + filling.icon_state = "syringe[rounded_vol]" + + filling.color = reagents.get_color() + overlays += filling + +/obj/item/weapon/reagent_containers/syringe/proc/handleTarget(var/atom/target, var/mob/user) + switch(mode) + if(SYRINGE_DRAW) + drawReagents(target, user) + + if(SYRINGE_INJECT) + injectReagents(target, user) + +/obj/item/weapon/reagent_containers/syringe/proc/drawReagents(var/atom/target, var/mob/user) + if(!reagents.get_free_space()) + to_chat(user, "The syringe is full.") + mode = SYRINGE_INJECT + return + + if(ismob(target))//Blood! + if(reagents.has_reagent(/datum/reagent/blood)) + to_chat(user, "There is already a blood sample in this syringe.") + return + if(istype(target, /mob/living/carbon)) + if(istype(target, /mob/living/carbon/slime)) + to_chat(user, "You are unable to locate any blood.") + return + var/amount = reagents.get_free_space() + var/mob/living/carbon/T = target + if(!T.dna) + to_chat(user, "You are unable to locate any blood.") + CRASH("[T] \[[T.type]\] was missing their dna datum!") + return + if(NOCLONE in T.mutations) //target done been et, no more blood in him + to_chat(user, "You are unable to locate any blood.") + return + + var/injtime = time //Taking a blood sample through a hardsuit takes longer due to needing to find a port. + var/allow = T.can_inject(user, check_zone(user.zone_sel.selecting)) + if(!allow) + return + if(allow == INJECTION_PORT) + injtime *= 2 + user.visible_message("\The [user] begins hunting for an injection port on [target]'s suit!") + else + user.visible_message("\The [user] is trying to take a blood sample from [target].") + + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + user.do_attack_animation(target) + + if(!do_mob(user, target, injtime)) + return + + T.take_blood(src, amount) + to_chat(user, "You take a blood sample from [target].") + for(var/mob/O in viewers(4, user)) + O.show_message("[user] takes a blood sample from [target].", 1) + + else //if not mob + if(!target.reagents.total_volume) + to_chat(user, "[target] is empty.") + return + + if(!target.is_open_container() && !istype(target, /obj/structure/reagent_dispensers) && !istype(target, /obj/item/slime_extract)) + to_chat(user, "You cannot directly remove reagents from this object.") + return + + var/trans = target.reagents.trans_to_obj(src, amount_per_transfer_from_this) + to_chat(user, "You fill the syringe with [trans] units of the solution.") + update_icon() + + if(!reagents.get_free_space()) + mode = SYRINGE_INJECT + update_icon() + +/obj/item/weapon/reagent_containers/syringe/proc/injectReagents(var/atom/target, var/mob/user) + if(!reagents.total_volume) + to_chat(user, "The syringe is empty.") + mode = SYRINGE_DRAW + return + if(istype(target, /obj/item/weapon/implantcase/chem)) + return + + if(!target.is_open_container() && !ismob(target) && !istype(target, /obj/item/weapon/reagent_containers/food) && !istype(target, /obj/item/slime_extract) && !istype(target, /obj/item/clothing/mask/smokable/cigarette) && !istype(target, /obj/item/weapon/storage/fancy/cigarettes)) + to_chat(user, "You cannot directly fill this object.") + return + if(!target.reagents.get_free_space()) + to_chat(user, "[target] is full.") + return + + if(isliving(target)) + injectMob(target, user) + return + + var/trans = reagents.trans_to(target, amount_per_transfer_from_this) + to_chat(user, "You inject \the [target] with [trans] units of the solution. \The [src] now contains [src.reagents.total_volume] units.") + if(reagents.total_volume <= 0 && mode == SYRINGE_INJECT) + mode = SYRINGE_DRAW + update_icon() + +/obj/item/weapon/reagent_containers/syringe/proc/handleBodyBag(var/obj/structure/closet/body_bag/bag, var/mob/living/carbon/user) + if(bag.opened || !bag.contains_body) + return + + var/mob/living/L = locate() in bag + injectMob(L, user, bag) + +/obj/item/weapon/reagent_containers/syringe/proc/injectMob(var/mob/living/carbon/target, var/mob/living/carbon/user, var/atom/trackTarget) + if(!trackTarget) + trackTarget = target + + if(target != user) + var/injtime = time //Injecting through a hardsuit takes longer due to needing to find a port. + var/allow = target.can_inject(user, check_zone(user.zone_sel.selecting)) + if(!allow) + return + if(allow == INJECTION_PORT) + injtime *= 2 + user.visible_message("\The [user] begins hunting for an injection port on [target]'s suit!") + else + user.visible_message("\The [user] is trying to inject [target] with [visible_name]!") + + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + user.do_attack_animation(trackTarget) + + if(!do_after(user, injtime, trackTarget)) + return + + if(target != trackTarget && target.loc != trackTarget) + return + + var/trans = reagents.trans_to_mob(target, amount_per_transfer_from_this, CHEM_BLOOD) + + if(target != user) + var/contained = reagentlist() + admin_inject_log(user, target, src, contained, trans) + user.visible_message("\the [user] injects \the [target] with [visible_name]!", "You inject \the [target] with [trans] units of the solution. \The [src] now contains [src.reagents.total_volume] units.") + else + to_chat(user, "You inject yourself with [trans] units of the solution. \The [src] now contains [src.reagents.total_volume] units.") + + if(reagents.total_volume <= 0 && mode == SYRINGE_INJECT) + mode = SYRINGE_DRAW + update_icon() + +/obj/item/weapon/reagent_containers/syringe/proc/syringestab(var/mob/living/carbon/target, var/mob/living/carbon/user) + + if(istype(target, /mob/living/carbon/human)) + + var/mob/living/carbon/human/H = target + + var/target_zone = ran_zone(check_zone(user.zone_sel.selecting, target)) + var/obj/item/organ/external/affecting = H.get_organ(target_zone) + + if (!affecting || affecting.is_stump()) + to_chat(user, "They are missing that limb!") + return + + var/hit_area = affecting.name + + if((user != target) && H.check_shields(7, src, user, "\the [src]")) + return + + if (target != user && H.getarmor(target_zone, "melee") > 5 && prob(50)) + for(var/mob/O in viewers(world.view, user)) + O.show_message(text("[user] tries to stab [target] in \the [hit_area] with [src.name], but the attack is deflected by armor!"), 1) + user.remove_from_mob(src) + qdel(src) + + admin_attack_log(user, target, "Attacked using \a [src]", "Was attacked with \a [src]", "used \a [src] to attack") + return + + user.visible_message("[user] stabs [target] in \the [hit_area] with [src.name]!") + affecting.take_damage(3) + + else + user.visible_message("[user] stabs [target] with [src.name]!") + target.take_organ_damage(3)// 7 is the same as crowbar punch + + var/syringestab_amount_transferred = rand(0, (reagents.total_volume - 5)) //nerfed by popular demand + var/contained_reagents = reagents.get_reagents() + var/trans = reagents.trans_to_mob(target, syringestab_amount_transferred, CHEM_BLOOD) + if(isnull(trans)) trans = 0 + admin_inject_log(user, target, src, contained_reagents, trans, violent=1) + break_syringe(target, user) + +/obj/item/weapon/reagent_containers/syringe/proc/break_syringe(mob/living/carbon/target, mob/living/carbon/user) + desc += " It is broken." + mode = SYRINGE_BROKEN + if(target) + add_blood(target) + if(user) + add_fingerprint(user) + update_icon() + +/obj/item/weapon/reagent_containers/syringe/ld50_syringe + name = "Lethal Injection Syringe" + desc = "A syringe used for lethal injections." + amount_per_transfer_from_this = 60 + volume = 60 + visible_name = "a giant syringe" + time = 300 + +/obj/item/weapon/reagent_containers/syringe/ld50_syringe/syringestab(var/mob/living/carbon/target, var/mob/living/carbon/user) + to_chat(user, "This syringe is too big to stab someone with it.") + return // No instant injecting + +/obj/item/weapon/reagent_containers/syringe/ld50_syringe/drawReagents(var/target, var/mob/user) + if(ismob(target)) // No drawing 60 units of blood at once + to_chat(user, "This needle isn't designed for drawing blood.") + return + ..() + +//////////////////////////////////////////////////////////////////////////////// +/// Syringes. END +//////////////////////////////////////////////////////////////////////////////// + +/obj/item/weapon/reagent_containers/syringe/inaprovaline + name = "Syringe (inaprovaline)" + desc = "Contains inaprovaline - used to stabilize patients." + +/obj/item/weapon/reagent_containers/syringe/inaprovaline/New() + ..() + reagents.add_reagent(/datum/reagent/inaprovaline, 15) + mode = SYRINGE_INJECT + update_icon() + +/obj/item/weapon/reagent_containers/syringe/antitoxin + name = "Syringe (anti-toxin)" + desc = "Contains anti-toxins." + +/obj/item/weapon/reagent_containers/syringe/antitoxin/New() + ..() + reagents.add_reagent(/datum/reagent/dylovene, 15) + mode = SYRINGE_INJECT + update_icon() + +/obj/item/weapon/reagent_containers/syringe/antiviral + name = "Syringe (spaceacillin)" + desc = "Contains antiviral agents." + +/obj/item/weapon/reagent_containers/syringe/antiviral/New() + ..() + reagents.add_reagent(/datum/reagent/spaceacillin, 15) + mode = SYRINGE_INJECT + update_icon() + +/obj/item/weapon/reagent_containers/syringe/drugs + name = "Syringe (drugs)" + desc = "Contains aggressive drugs meant for torture." + +/obj/item/weapon/reagent_containers/syringe/drugs/New() + ..() + reagents.add_reagent(/datum/reagent/space_drugs, 5) + reagents.add_reagent(/datum/reagent/mindbreaker, 5) + reagents.add_reagent(/datum/reagent/cryptobiolin, 5) + mode = SYRINGE_INJECT + update_icon() + +/obj/item/weapon/reagent_containers/syringe/ld50_syringe/choral + +/obj/item/weapon/reagent_containers/syringe/ld50_syringe/choral/New() + ..() + reagents.add_reagent(/datum/reagent/chloralhydrate, 60) + mode = SYRINGE_INJECT + update_icon() + +/obj/item/weapon/reagent_containers/syringe/steroid + name = "Syringe (anabolic steroids)" + desc = "Contains drugs for muscle growth." + +/obj/item/weapon/reagent_containers/syringe/steroid/New() + ..() + reagents.add_reagent(/datum/reagent/adrenaline, 5) + reagents.add_reagent(/datum/reagent/hyperzine, 10) + diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm new file mode 100644 index 00000000..5f78f134 --- /dev/null +++ b/code/modules/reagents/reagent_dispenser.dm @@ -0,0 +1,271 @@ + +/obj/structure/reagent_dispensers + name = "Dispenser" + desc = "..." + icon = 'icons/obj/objects.dmi' + icon_state = "watertank" + density = 1 + anchored = 0 + + var/initial_capacity = 1000 + var/initial_reagent_types // A list of reagents and their ratio relative the initial capacity. list(/datum/reagent/water = 0.5) would fill the dispenser halfway to capacity. + var/amount_per_transfer_from_this = 10 + var/possible_transfer_amounts = "10;25;50;100;500" + + attackby(obj/item/weapon/W as obj, mob/user as mob) + return + +/obj/structure/reagent_dispensers/New() + create_reagents(initial_capacity) + + if (!possible_transfer_amounts) + src.verbs -= /obj/structure/reagent_dispensers/verb/set_APTFT + + for(var/reagent_type in initial_reagent_types) + var/reagent_ratio = initial_reagent_types[reagent_type] + reagents.add_reagent(reagent_type, reagent_ratio * initial_capacity) + + ..() + +/obj/structure/reagent_dispensers/examine(mob/user) + if(!..(user, 2)) + return + to_chat(user, "It contains:") + if(reagents && reagents.reagent_list.len) + for(var/datum/reagent/R in reagents.reagent_list) + to_chat(user, "[R.volume] units of [R.name]") + else + to_chat(user, "Nothing.") + +/obj/structure/reagent_dispensers/verb/set_APTFT() //set amount_per_transfer_from_this + set name = "Set transfer amount" + set category = "Object" + set src in view(1) + var/N = input("Amount per transfer from this:","[src]") as null|anything in cached_number_list_decode(possible_transfer_amounts) + if (N) + amount_per_transfer_from_this = N + +/obj/structure/reagent_dispensers/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + if (prob(50)) + new /obj/effect/effect/water(src.loc) + qdel(src) + return + if(3.0) + if (prob(5)) + new /obj/effect/effect/water(src.loc) + qdel(src) + return + else + return + +/obj/structure/reagent_dispensers/AltClick(var/mob/user) + if(possible_transfer_amounts) + if(CanPhysicallyInteract(user)) + set_APTFT() + else + return ..() + + +//Dispensers +/obj/structure/reagent_dispensers/watertank + name = "watertank" + desc = "A tank containing water." + icon = 'icons/obj/objects.dmi' + icon_state = "watertank" + amount_per_transfer_from_this = 10 + possible_transfer_amounts = "10;25;50;100" + initial_capacity = 50000 + initial_reagent_types = list(/datum/reagent/water = 1) + atom_flags = ATOM_FLAG_CLIMBABLE + +/obj/structure/reagent_dispensers/fueltank + name = "fueltank" + desc = "A tank containing fuel." + icon = 'icons/obj/objects.dmi' + icon_state = "weldtank" + amount_per_transfer_from_this = 10 + var/modded = 0 + var/obj/item/device/assembly_holder/rig = null + initial_reagent_types = list(/datum/reagent/fuel = 1) + atom_flags = ATOM_FLAG_CLIMBABLE + +/obj/structure/reagent_dispensers/fueltank/examine(mob/user) + if(!..(user, 2)) + return + if (modded) + to_chat(user, "Fuel faucet is wrenched open, leaking the fuel!") + if(rig) + to_chat(user, "There is some kind of device rigged to the tank.") +/obj/structure/reagent_dispensers/fueltank/attack_hand() + if (rig) + usr.visible_message("\The [usr] begins to detach [rig] from \the [src].", "You begin to detach [rig] from \the [src].") + if(do_after(usr, 20, src)) + usr.visible_message("\The [usr] detaches \the [rig] from \the [src].", "You detach [rig] from \the [src]") + rig.loc = get_turf(usr) + rig = null + overlays = new/list() + +/obj/structure/reagent_dispensers/fueltank/attackby(obj/item/weapon/W as obj, mob/user as mob) + src.add_fingerprint(user) + if (istype(W,/obj/item/weapon/wrench)) + user.visible_message("[user] wrenches [src]'s faucet [modded ? "closed" : "open"].", \ + "You wrench [src]'s faucet [modded ? "closed" : "open"]") + modded = modded ? 0 : 1 + if (modded) + message_admins("[key_name_admin(user)] opened fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]), leaking fuel. (JMP)") + log_game("[key_name(user)] opened fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]), leaking fuel.") + leak_fuel(amount_per_transfer_from_this) + else if (istype(W,/obj/item/device/assembly_holder)) + if (rig) + to_chat(user, "There is another device in the way.") + return ..() + user.visible_message("\The [user] begins rigging [W] to \the [src].", "You begin rigging [W] to \the [src]") + if(do_after(user, 20, src)) + user.visible_message("The [user] rigs [W] to \the [src].", "You rig [W] to \the [src].") + + var/obj/item/device/assembly_holder/H = W + if (istype(H.a_left,/obj/item/device/assembly/igniter) || istype(H.a_right,/obj/item/device/assembly/igniter)) + message_admins("[key_name_admin(user)] rigged fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]) for explosion. (JMP)") + log_game("[key_name(user)] rigged fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]) for explosion.") + + rig = W + user.drop_item() + W.loc = src + + var/icon/test = getFlatIcon(W) + test.Shift(NORTH,1) + test.Shift(EAST,6) + overlays += test + + else if(isflamesource(W)) + if(user.a_intent != I_HURT) + to_chat(user, "You almost got [W] too close to [src]! That could have ended very badly for you.") + return + + user.visible_message("[user] draws closer to the fueltank with [W].", "You draw closer to the fueltank with [W].") + if(do_after(user, 50, src)) + log_and_message_admins("triggered a fueltank explosion with [W].") + user.visible_message("[user] puts [W] to [src]!", "You put \the [W] to \the [src] and with a moment of lucidity you realize, this might not have been the smartest thing you've ever done.") + src.explode() + + return + + return ..() + + +/obj/structure/reagent_dispensers/fueltank/bullet_act(var/obj/item/projectile/Proj) + if(Proj.get_structure_damage()) + if(istype(Proj.firer)) + var/turf/turf = get_turf(src) + if(turf) + var/area/area = turf.loc || "*unknown area*" + message_admins("[key_name_admin(Proj.firer)] shot a fueltank in \the [area] ([turf.x],[turf.y],[turf.z]) (JMP).") + log_game("[key_name(Proj.firer)] shot a fueltank in \the [area] ([turf.x],[turf.y],[turf.z]).") + else + message_admins("[key_name_admin(Proj.firer)] shot a fueltank outside the world.") + log_game("[key_name(Proj.firer)] shot a fueltank outside the world.") + + if(!istype(Proj ,/obj/item/projectile/beam/lastertag) && !istype(Proj ,/obj/item/projectile/beam/practice) ) + explode() + +/obj/structure/reagent_dispensers/fueltank/ex_act() + explode() + +/obj/structure/reagent_dispensers/fueltank/proc/explode() + if (reagents.total_volume > 500) + explosion(src.loc,1,2,4) + else if (reagents.total_volume > 100) + explosion(src.loc,0,1,3) + else if (reagents.total_volume > 50) + explosion(src.loc,-1,1,2) + if(src) + qdel(src) + +/obj/structure/reagent_dispensers/fueltank/fire_act(datum/gas_mixture/air, temperature, volume) + if (modded) + explode() + else if (temperature > T0C+500) + explode() + return ..() + +/obj/structure/reagent_dispensers/fueltank/Move() + if (..() && modded) + leak_fuel(amount_per_transfer_from_this/10.0) + +/obj/structure/reagent_dispensers/fueltank/proc/leak_fuel(amount) + if (reagents.total_volume == 0) + return + + amount = min(amount, reagents.total_volume) + reagents.remove_reagent(/datum/reagent/fuel,amount) + new /obj/effect/decal/cleanable/liquid_fuel(src.loc, amount,1) + +/obj/structure/reagent_dispensers/peppertank + name = "Pepper Spray Refiller" + desc = "Refills pepper spray canisters." + icon = 'icons/obj/objects.dmi' + icon_state = "peppertank" + anchored = 1 + density = 0 + amount_per_transfer_from_this = 45 + initial_reagent_types = list(/datum/reagent/capsaicin/condensed = 1) + + +/obj/structure/reagent_dispensers/water_cooler + name = "Water-Cooler" + desc = "A machine that dispenses water to drink." + amount_per_transfer_from_this = 5 + icon = 'icons/obj/vending.dmi' + icon_state = "water_cooler" + possible_transfer_amounts = null + anchored = 1 + initial_capacity = 500 + initial_reagent_types = list(/datum/reagent/water = 1) + +/obj/structure/reagent_dispensers/water_cooler/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W,/obj/item/weapon/wrench)) + src.add_fingerprint(user) + if(anchored) + user.visible_message("\The [user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.") + else + user.visible_message("\The [user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.") + + if(do_after(user, 20, src)) + if(!src) return + to_chat(user, "You [anchored? "un" : ""]secured \the [src]!") + anchored = !anchored + return + else + return ..() + +/obj/structure/reagent_dispensers/beerkeg + name = "beer keg" + desc = "A beer keg." + icon = 'icons/obj/objects.dmi' + icon_state = "beertankTEMP" + amount_per_transfer_from_this = 10 + initial_reagent_types = list(/datum/reagent/ethanol/beer = 1) + atom_flags = ATOM_FLAG_CLIMBABLE + +/obj/structure/reagent_dispensers/virusfood + name = "Virus Food Dispenser" + desc = "A dispenser of virus food." + icon = 'icons/obj/objects.dmi' + icon_state = "virusfoodtank" + amount_per_transfer_from_this = 10 + anchored = 1 + initial_reagent_types = list(/datum/reagent/nutriment/virus_food = 1) + +/obj/structure/reagent_dispensers/acid + name = "Sulphuric Acid Dispenser" + desc = "A dispenser of acid for industrial processes." + icon = 'icons/obj/objects.dmi' + icon_state = "acidtank" + amount_per_transfer_from_this = 10 + anchored = 1 + initial_reagent_types = list(/datum/reagent/acid = 1) diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm new file mode 100644 index 00000000..94028d6f --- /dev/null +++ b/code/modules/recycling/conveyor2.dm @@ -0,0 +1,324 @@ +//conveyor2 is pretty much like the original, except it supports corners, but not diverters. +//note that corner pieces transfer stuff clockwise when running forward, and anti-clockwise backwards. + +/obj/machinery/conveyor + icon = 'icons/obj/recycling.dmi' + icon_state = "conveyor_map" + name = "conveyor belt" + desc = "A conveyor belt." + layer = BELOW_OBJ_LAYER // so they appear under stuff + anchored = 1 + var/operating = 0 // 1 if running forward, -1 if backwards, 0 if off + var/operable = 1 // true if can operate (no broken segments in this belt run) + var/forwards // this is the default (forward) direction, set by the map dir + var/backwards // hopefully self-explanatory + var/movedir // the actual direction to move stuff in + + var/list/affecting // the list of all items that will be moved this ptick + var/id = "" // the control ID - must match controller ID + +/obj/machinery/conveyor/centcom_auto + id = "round_end_belt" + + // create a conveyor +/obj/machinery/conveyor/New(loc, newdir, on = 0) + icon_state = "conveyor0" + ..(loc) + if(newdir) + set_dir(newdir) + + if(dir & (dir-1)) // Diagonal. Forwards is *away* from dir, curving to the right. + forwards = turn(dir, 135) + backwards = turn(dir, 45) + else + forwards = dir + backwards = turn(dir, 180) + + if(on) + operating = 1 + setmove() + + + +/obj/machinery/conveyor/proc/setmove() + if(operating == 1) + movedir = forwards + else if(operating == -1) + movedir = backwards + else operating = 0 + update_icon() + +/obj/machinery/conveyor/update_icon() + if(stat & BROKEN) + icon_state = "conveyor-broken" + operating = 0 + return + if(!operable) + operating = 0 + if(stat & NOPOWER) + operating = 0 + icon_state = "conveyor[operating]" + + // machine process + // move items to the target location +/obj/machinery/conveyor/Process() + if(stat & (BROKEN | NOPOWER)) + return + if(!operating) + return + use_power(100) + + affecting = loc.contents - src // moved items will be all in loc + spawn(1) // slight delay to prevent infinite propagation due to map order //TODO: please no spawn() in process(). It's a very bad idea + var/items_moved = 0 + for(var/atom/movable/A in affecting) + if(!A.anchored) + if(A.loc == src.loc) // prevents the object from being affected if it's not currently here. + step(A,movedir) + items_moved++ + if(items_moved >= 10) + break + +// attack with item, place item on conveyor +/obj/machinery/conveyor/attackby(var/obj/item/I, mob/user) + if(isCrowbar(I)) + if(!(stat & BROKEN)) + var/obj/item/conveyor_construct/C = new/obj/item/conveyor_construct(src.loc) + C.id = id + transfer_fingerprints_to(C) + to_chat(user, "You remove the conveyor belt.") + qdel(src) + return + if(isrobot(user)) return //Carn: fix for borgs dropping their modules on conveyor belts + if(I.loc != user) return // This should stop mounted modules ending up outside the module. + + user.drop_item(get_turf(src)) + return + +// attack with hand, move pulled object onto conveyor +/obj/machinery/conveyor/attack_hand(mob/user as mob) + if ((!( user.canmove ) || user.restrained() || !( user.pulling ))) + return + if (user.pulling.anchored) + return + if ((user.pulling.loc != user.loc && get_dist(user, user.pulling) > 1)) + return + if (ismob(user.pulling)) + var/mob/M = user.pulling + M.stop_pulling() + step(user.pulling, get_dir(user.pulling.loc, src)) + user.stop_pulling() + else + step(user.pulling, get_dir(user.pulling.loc, src)) + user.stop_pulling() + return + + +// make the conveyor broken +// also propagate inoperability to any connected conveyor with the same ID +/obj/machinery/conveyor/proc/broken() + stat |= BROKEN + update_icon() + + var/obj/machinery/conveyor/C = locate() in get_step(src, dir) + if(C) + C.set_operable(dir, id, 0) + + C = locate() in get_step(src, turn(dir,180)) + if(C) + C.set_operable(turn(dir,180), id, 0) + + +//set the operable var if ID matches, propagating in the given direction + +/obj/machinery/conveyor/proc/set_operable(stepdir, match_id, op) + + if(id != match_id) + return + operable = op + + update_icon() + var/obj/machinery/conveyor/C = locate() in get_step(src, stepdir) + if(C) + C.set_operable(stepdir, id, op) + +/* +/obj/machinery/conveyor/verb/destroy() + set src in view() + src.broken() +*/ + +// the conveyor control switch +// +// + +/obj/machinery/conveyor_switch + + name = "conveyor switch" + desc = "A conveyor control switch." + icon = 'icons/obj/recycling.dmi' + icon_state = "switch-off" + var/position = 0 // 0 off, -1 reverse, 1 forward + var/last_pos = -1 // last direction setting + var/operated = 1 // true if just operated + + var/id = "" // must match conveyor IDs to control them + + var/list/conveyors // the list of converyors that are controlled by this switch + anchored = 1 + + + +/obj/machinery/conveyor_switch/New(loc, newid) + ..(loc) + if(!id) + id = newid + update_icon() + + spawn(5) // allow map load + conveyors = list() + for(var/obj/machinery/conveyor/C in world) + if(C.id == id) + conveyors += C + +// update the icon depending on the position + +/obj/machinery/conveyor_switch/update_icon() + if(position<0) + icon_state = "switch-rev" + else if(position>0) + icon_state = "switch-fwd" + else + icon_state = "switch-off" + + +// timed process +// if the switch changed, update the linked conveyors + +/obj/machinery/conveyor_switch/Process() + if(!operated) + return + operated = 0 + + for(var/obj/machinery/conveyor/C in conveyors) + C.operating = position + C.setmove() + +// attack with hand, switch position +/obj/machinery/conveyor_switch/attack_hand(mob/user) + if(!allowed(user)) + to_chat(user, "Access denied.") + return + + if(position == 0) + if(last_pos < 0) + position = 1 + last_pos = 0 + else + position = -1 + last_pos = 0 + else + last_pos = position + position = 0 + + operated = 1 + update_icon() + + // find any switches with same id as this one, and set their positions to match us + for(var/obj/machinery/conveyor_switch/S in world) + if(S.id == src.id) + S.position = position + S.update_icon() + + +/obj/machinery/conveyor_switch/attackby(obj/item/I, mob/user, params) + if(isCrowbar(I)) + var/obj/item/conveyor_switch_construct/C = new/obj/item/conveyor_switch_construct(src.loc) + C.id = id + transfer_fingerprints_to(C) + to_chat(user, "You deattach the conveyor switch.") + qdel(src) + +/obj/machinery/conveyor_switch/oneway + var/convdir = 1 //Set to 1 or -1 depending on which way you want the convayor to go. (In other words keep at 1 and set the proper dir on the belts.) + desc = "A conveyor control switch. It appears to only go in one direction." + +// attack with hand, switch position +/obj/machinery/conveyor_switch/oneway/attack_hand(mob/user) + if(position == 0) + position = convdir + else + position = 0 + + operated = 1 + update_icon() + + // find any switches with same id as this one, and set their positions to match us + for(var/obj/machinery/conveyor_switch/S in world) + if(S.id == src.id) + S.position = position + S.update_icon() + + + +// +// CONVEYOR CONSTRUCTION STARTS HERE +// + +/obj/item/conveyor_construct + icon = 'icons/obj/recycling.dmi' + icon_state = "conveyor0" + name = "conveyor belt assembly" + desc = "A conveyor belt assembly." + w_class = ITEM_SIZE_HUGE + var/id = "" //inherited by the belt + +/obj/item/conveyor_construct/attackby(obj/item/I, mob/user, params) + ..() + if(istype(I, /obj/item/conveyor_switch_construct)) + to_chat(user, "You link the switch to the conveyor belt assembly.") + var/obj/item/conveyor_switch_construct/C = I + id = C.id + +/obj/item/conveyor_construct/afterattack(atom/A, mob/user, proximity) + if(!proximity || !istype(A, /turf/simulated/floor) || istype(A, /area/shuttle) || user.incapacitated()) + return + var/cdir = get_dir(A, user) + if(!(cdir in GLOB.cardinal) || A == user.loc) + return + for(var/obj/machinery/conveyor/CB in A) + if(CB.dir == cdir || CB.dir == turn(cdir,180)) + return + cdir |= CB.dir + qdel(CB) + var/obj/machinery/conveyor/C = new/obj/machinery/conveyor(A,cdir) + C.id = id + transfer_fingerprints_to(C) + qdel(src) + +/obj/item/conveyor_switch_construct + name = "conveyor switch assembly" + desc = "A conveyor control switch assembly." + icon = 'icons/obj/recycling.dmi' + icon_state = "switch-off" + w_class = ITEM_SIZE_HUGE + var/id = "" //inherited by the switch + +/obj/item/conveyor_switch_construct/New() + ..() + id = rand() //this couldn't possibly go wrong + +/obj/item/conveyor_switch_construct/afterattack(atom/A, mob/user, proximity) + if(!proximity || !istype(A, /turf/simulated/floor) || istype(A, /area/shuttle) || user.incapacitated()) + return + var/found = 0 + for(var/obj/machinery/conveyor/C in view()) + if(C.id == src.id) + found = 1 + break + if(!found) + to_chat(user, "\icon[src]The conveyor switch did not detect any linked conveyor belts in range.") + return + var/obj/machinery/conveyor_switch/NC = new/obj/machinery/conveyor_switch(A, id) + transfer_fingerprints_to(NC) + qdel(src) diff --git a/code/modules/recycling/disposal-construction.dm b/code/modules/recycling/disposal-construction.dm new file mode 100644 index 00000000..5d67dd57 --- /dev/null +++ b/code/modules/recycling/disposal-construction.dm @@ -0,0 +1,344 @@ +// Disposal pipe construction +// This is the pipe that you drag around, not the attached ones. + +/obj/structure/disposalconstruct + + name = "disposal pipe segment" + desc = "A huge pipe segment used for constructing disposal systems." + icon = 'icons/obj/pipes/disposal.dmi' + icon_state = "conpipe-s" + anchored = 0 + density = 0 + matter = list(DEFAULT_WALL_MATERIAL = 1850) + level = 2 + var/sortType = "" + var/ptype = 0 + // 0=straight, 1=bent, 2=junction-j1, 3=junction-j2, 4=junction-y, 5=trunk, 6=disposal bin, 7=outlet, 8=inlet 9=pipe-j1s 10=pipe-j2s + var/subtype = 0 + var/dpdir = 0 // directions as disposalpipe + var/base_state = "pipe-s" + +/obj/structure/disposalconstruct/Initialize() + update_verbs() + . = ..() + +/obj/structure/disposalconstruct/proc/update_verbs() + if(anchored) + verbs -= /obj/structure/disposalconstruct/proc/rotate + verbs -= /obj/structure/disposalconstruct/proc/flip + else + verbs += /obj/structure/disposalconstruct/proc/rotate + verbs += /obj/structure/disposalconstruct/proc/flip + +// update iconstate and dpdir due to dir and type +/obj/structure/disposalconstruct/proc/update() + var/flip = turn(dir, 180) + var/left = turn(dir, 90) + var/right = turn(dir, -90) + + switch(ptype) + if(0) + base_state = "pipe-s" + dpdir = dir | flip + if(1) + base_state = "pipe-c" + dpdir = dir | right + if(2) + base_state = "pipe-j1" + dpdir = dir | right | flip + if(3) + base_state = "pipe-j2" + dpdir = dir | left | flip + if(4) + base_state = "pipe-y" + dpdir = dir | left | right + if(5) + base_state = "pipe-t" + dpdir = dir + // disposal bin has only one dir, thus we don't need to care about setting it + if(6) + if(anchored) + base_state = "disposal" + else + base_state = "condisposal" + + if(7) + base_state = "outlet" + dpdir = dir + + if(8) + base_state = "intake" + dpdir = dir + + if(9) + base_state = "pipe-j1s" + dpdir = dir | right | flip + + if(10) + base_state = "pipe-j2s" + dpdir = dir | left | flip +///// Z-Level stuff + if(11) + base_state = "pipe-u" + dpdir = dir + if(12) + base_state = "pipe-d" + dpdir = dir +///// Z-Level stuff + if(13) + base_state = "pipe-tagger" + dpdir = dir | flip + if(14) + base_state = "pipe-tagger-partial" + dpdir = dir | flip + if(15) + base_state = "pipe-j1s" + dpdir = dir | flip + +///// Z-Level stuff + if(!(ptype in list(6, 7, 8, 11, 12, 13, 14, 15))) +///// Z-Level stuff + icon_state = "con[base_state]" + else + icon_state = base_state + + if(invisibility) // if invisible, fade icon + alpha = 128 + else + alpha = 255 + //otherwise burying half-finished pipes under floors causes them to half-fade + +// hide called by levelupdate if turf intact status changes +// change visibility status and force update of icon +/obj/structure/disposalconstruct/hide(var/intact) + set_invisibility((intact && level==1) ? 101: 0) // hide if floor is intact + update() + + +// flip and rotate verbs +/obj/structure/disposalconstruct/proc/rotate() + set category = "Object" + set name = "Rotate Pipe" + set src in view(1) + + if(usr.incapacitated()) + return + + if(anchored) + to_chat(usr, "You must unfasten the pipe before rotating it.") + return + + set_dir(turn(dir, -90)) + update() + +/obj/structure/disposalconstruct/proc/flip() + set category = "Object" + set name = "Flip Pipe" + set src in view(1) + if(usr.incapacitated()) + return + + if(anchored) + to_chat(usr, "You must unfasten the pipe before flipping it.") + return + + set_dir(turn(dir, 180)) + switch(ptype) + if(2) + ptype = 3 + if(3) + ptype = 2 + if(9) + ptype = 10 + if(10) + ptype = 9 + + update() + +// returns the type path of disposalpipe corresponding to this item dtype +/obj/structure/disposalconstruct/proc/dpipetype() + switch(ptype) + if(0,1) + return /obj/structure/disposalpipe/segment + if(2,3,4) + return /obj/structure/disposalpipe/junction + if(5) + return /obj/structure/disposalpipe/trunk + if(6) + return /obj/machinery/disposal + if(7) + return /obj/structure/disposaloutlet + if(8) + return /obj/machinery/disposal/deliveryChute + if(9) + switch(subtype) + if(0) + return /obj/structure/disposalpipe/sortjunction + if(1) + return /obj/structure/disposalpipe/sortjunction/wildcard + if(2) + return /obj/structure/disposalpipe/sortjunction/untagged + if(10) + switch(subtype) + if(0) + return /obj/structure/disposalpipe/sortjunction/flipped + if(1) + return /obj/structure/disposalpipe/sortjunction/wildcard/flipped + if(2) + return /obj/structure/disposalpipe/sortjunction/untagged/flipped +///// Z-Level stuff + if(11) + return /obj/structure/disposalpipe/up + if(12) + return /obj/structure/disposalpipe/down +///// Z-Level stuff + if(13) + return /obj/structure/disposalpipe/tagger + if(14) + return /obj/structure/disposalpipe/tagger/partial + if(15) + return /obj/structure/disposalpipe/diversion_junction + return + + + +// attackby item +// wrench: (un)anchor +// weldingtool: convert to real pipe +/obj/structure/disposalconstruct/attackby(var/obj/item/I, var/mob/user) + var/nicetype = "pipe" + var/ispipe = 0 // Indicates if we should change the level of this pipe + add_fingerprint(user, 0, I) + switch(ptype) + if(6) + nicetype = "disposal bin" + if(7) + nicetype = "disposal outlet" + if(8) + nicetype = "delivery chute" + if(9, 10) + switch(subtype) + if(0) + nicetype = "sorting pipe" + if(1) + nicetype = "wildcard sorting pipe" + if(2) + nicetype = "untagged sorting pipe" + ispipe = 1 + if(13) + nicetype = "tagging pipe" + ispipe = 1 + if(14) + nicetype = "partial tagging pipe" + ispipe = 1 + else + nicetype = "pipe" + ispipe = 1 + + var/turf/T = src.loc + if(!T.is_plating()) + to_chat(user, "You can only attach the [nicetype] if the floor plating is removed.") + return + + var/obj/structure/disposalpipe/CP = locate() in T + + if(isWrench(I)) + if(anchored) + anchored = 0 + if(ispipe) + level = 2 + set_density(0) + else + set_density(1) + to_chat(user, "You detach the [nicetype] from the underfloor.") + else + if(ptype>=6 && ptype <= 8) // Disposal or outlet + if(CP) // There's something there + if(!istype(CP,/obj/structure/disposalpipe/trunk)) + to_chat(user, "The [nicetype] requires a trunk underneath it in order to work.") + return + else // Nothing under, fuck. + to_chat(user, "The [nicetype] requires a trunk underneath it in order to work.") + return + else + if(CP) + update() + var/pdir = CP.dpdir + if(istype(CP, /obj/structure/disposalpipe/broken)) + pdir = CP.dir + if(pdir & dpdir) + to_chat(user, "There is already a [nicetype] at that location.") + return + + anchored = 1 + if(ispipe) + level = 1 // We don't want disposal bins to disappear under the floors + set_density(0) + else + set_density(1) // We don't want disposal bins or outlets to go density 0 + to_chat(user, "You attach the [nicetype] to the underfloor.") + playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + update() + update_verbs() + + else if(istype(I, /obj/item/weapon/weldingtool)) + if(anchored) + var/obj/item/weapon/weldingtool/W = I + if(W.remove_fuel(0,user)) + playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) + to_chat(user, "Welding the [nicetype] in place.") + if(do_after(user, 20, src)) + if(!src || !W.isOn()) return + to_chat(user, "The [nicetype] has been welded in place!") + update() // TODO: Make this neat + if(ispipe) // Pipe + + var/pipetype = dpipetype() + var/obj/structure/disposalpipe/P = new pipetype(src.loc) + src.transfer_fingerprints_to(P) + P.base_icon_state = base_state + P.set_dir(dir) + P.dpdir = dpdir + P.update_icon() + + //Needs some special treatment ;) + if(ptype==9 || ptype==10) + var/obj/structure/disposalpipe/sortjunction/SortP = P + SortP.sortType = sortType + SortP.updatedir() + SortP.updatedesc() + SortP.updatename() + + else if(ptype==6) // Disposal bin + var/obj/machinery/disposal/P = new /obj/machinery/disposal(src.loc) + src.transfer_fingerprints_to(P) + P.mode = 0 // start with pump off + + else if(ptype==7) // Disposal outlet + + var/obj/structure/disposaloutlet/P = new /obj/structure/disposaloutlet(src.loc) + src.transfer_fingerprints_to(P) + P.set_dir(dir) + var/obj/structure/disposalpipe/trunk/Trunk = CP + Trunk.linked = P + + else if(ptype==8) // Disposal outlet + + var/obj/machinery/disposal/deliveryChute/P = new /obj/machinery/disposal/deliveryChute(src.loc) + src.transfer_fingerprints_to(P) + P.set_dir(dir) + + qdel(src) + return + else + to_chat(user, "You need more welding fuel to complete this task.") + return + else + to_chat(user, "You need to attach it to the plating first!") + return + +/obj/structure/disposalconstruct/hides_under_flooring() + if(anchored) + return 1 + else + return 0 diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm new file mode 100644 index 00000000..98958fcd --- /dev/null +++ b/code/modules/recycling/disposal.dm @@ -0,0 +1,1697 @@ +// Disposal bin +// Holds items for disposal into pipe system +// Draws air from turf, gradually charges internal reservoir +// Once full (~1 atm), uses air resv to flush items into the pipes +// Automatically recharges air (unless off), will flush when ready if pre-set +// Can hold items and human size things, no other draggables +// Toilets are a type of disposal bin for small objects only and work on magic. By magic, I mean torque rotation +#define SEND_PRESSURE (700 + ONE_ATMOSPHERE) //kPa - assume the inside of a dispoal pipe is 1 atm, so that needs to be added. +#define PRESSURE_TANK_VOLUME 150 //L +#define PUMP_MAX_FLOW_RATE 90 //L/s - 4 m/s using a 15 cm by 15 cm inlet + +/obj/machinery/disposal + name = "disposal unit" + desc = "A pneumatic waste disposal unit." + icon = 'icons/obj/pipes/disposal.dmi' + icon_state = "disposal" + anchored = 1 + density = 1 + var/datum/gas_mixture/air_contents // internal reservoir + var/mode = 1 // item mode 0=off 1=charging 2=charged + var/flush = 0 // true if flush handle is pulled + var/obj/structure/disposalpipe/trunk/trunk = null // the attached pipe trunk + var/flushing = 0 // true if flushing in progress + var/flush_every_ticks = 30 //Every 30 ticks it will look whether it is ready to flush + var/flush_count = 0 //this var adds 1 once per tick. When it reaches flush_every_ticks it resets and tries to flush. + var/last_sound = 0 + var/list/allowed_objects = list(/obj/structure/closet) + active_power_usage = 2200 //the pneumatic pump power. 3 HP ~ 2200W + idle_power_usage = 100 + atom_flags = ATOM_FLAG_CLIMBABLE + +// create a new disposal +// find the attached trunk (if present) and init gas resvr. +/obj/machinery/disposal/New() + ..() + spawn(5) + trunk = locate() in src.loc + if(!trunk) + mode = 0 + flush = 0 + else + trunk.linked = src // link the pipe trunk to self + + air_contents = new/datum/gas_mixture(PRESSURE_TANK_VOLUME) + update_icon() + +/obj/machinery/disposal/Destroy() + eject() + if(trunk) + trunk.linked = null + return ..() + +// attack by item places it in to disposal +/obj/machinery/disposal/attackby(var/obj/item/I, var/mob/user) + if(stat & BROKEN || !I || !user) + return + + add_fingerprint(user, 0, I) + if(mode<=0) // It's off + if(isScrewdriver(I)) + if(contents.len > 0) + to_chat(user, "Eject the items first!") + return + if(mode==0) // It's off but still not unscrewed + mode=-1 // Set it to doubleoff l0l + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You remove the screws around the power connection.") + return + else if(mode==-1) + mode=0 + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You attach the screws around the power connection.") + return + else if(isWelder(I) && mode==-1) + if(contents.len > 0) + to_chat(user, "Eject the items first!") + return + var/obj/item/weapon/weldingtool/W = I + if(W.remove_fuel(0,user)) + playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) + to_chat(user, "You start slicing the floorweld off the disposal unit.") + + if(do_after(user,20,src)) + if(!src || !W.isOn()) return + to_chat(user, "You sliced the floorweld off the disposal unit.") + var/obj/structure/disposalconstruct/C = new (src.loc) + src.transfer_fingerprints_to(C) + C.ptype = 6 // 6 = disposal unit + C.anchored = 1 + C.set_density(1) + C.update() + qdel(src) + return + else + to_chat(user, "You need more welding fuel to complete this task.") + return + + if(istype(I, /obj/item/weapon/melee/energy/blade)) + to_chat(user, "You can't place that item inside the disposal unit.") + return + + if(istype(I, /obj/item/weapon/storage/bag/trash)) + var/obj/item/weapon/storage/bag/trash/T = I + to_chat(user, "You empty the bag.") + for(var/obj/item/O in T.contents) + T.remove_from_storage(O,src) + T.update_icon() + update_icon() + return + + var/obj/item/grab/G = I + if(istype(G)) // handle grabbed mob + if(ismob(G.affecting)) + var/mob/GM = G.affecting + for (var/mob/V in viewers(usr)) + V.show_message("[usr] starts putting [GM.name] into the disposal.", 3) + if(do_after(usr, 20, src)) + if (GM.client) + GM.client.perspective = EYE_PERSPECTIVE + GM.client.eye = src + GM.forceMove(src) + for (var/mob/C in viewers(src)) + C.show_message("[GM.name] has been placed in the [src] by [user].", 3) + qdel(G) + admin_attack_log(usr, GM, "Placed the victim into \the [src].", "Was placed into \the [src] by the attacker.", "stuffed \the [src] with") + return + + if(isrobot(user)) + return + if(!I) + return + + user.drop_item() + if(I) + I.forceMove(src) + + to_chat(user, "You place \the [I] into the [src].") + for(var/mob/M in viewers(src)) + if(M == user) + continue + M.show_message("[user.name] places \the [I] into the [src].", 3) + + update_icon() + +/obj/machinery/disposal/MouseDrop_T(atom/movable/AM, mob/user) + var/incapacitation_flags = INCAPACITATION_DEFAULT + if(AM == user) + incapacitation_flags &= ~INCAPACITATION_RESTRAINED + + if(stat & BROKEN || !CanMouseDrop(AM, user, incapacitation_flags) || AM.anchored || !isturf(user.loc)) + return + + // Animals can only put themself in + if(isanimal(user) && AM != user) + return + + // Determine object type and run necessary checks + var/mob/M = AM + var/is_dangerous // To determine css style in messages + if(istype(M)) + is_dangerous = TRUE + if(M.buckled) + return + else if(istype(AM, /obj/item)) + attackby(AM, user) + return + else if(!is_type_in_list(AM, allowed_objects)) + return + + // Checks completed, start inserting + src.add_fingerprint(user) + var/old_loc = AM.loc + if(AM == user) + user.visible_message("[user] starts climbing into [src].", \ + "You start climbing into [src].") + else + user.visible_message("[user] starts stuffing [AM] into [src].", \ + "You start stuffing [AM] into [src].") + + if(!do_after(user, 2 SECONDS, src)) + return + + // Repeat checks + if(stat & BROKEN || user.incapacitated(incapacitation_flags)) + return + if(!AM || old_loc != AM.loc || AM.anchored) + return + if(istype(M) && M.buckled) + return + + // Messages and logging + if(AM == user) + user.visible_message("[user] climbs into [src].", \ + "You climb into [src].") + else + user.visible_message("[user] stuffs [AM] into [src][is_dangerous ? "!" : "."]", \ + "You stuff [AM] into [src].") + if(ismob(M)) + admin_attack_log(user, M, "Placed the victim into \the [src].", "Was placed into \the [src] by the attacker.", "stuffed \the [src] with") + if (M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + + AM.forceMove(src) + update_icon() + return + +// attempt to move while inside +/obj/machinery/disposal/relaymove(mob/user as mob) + if(user.stat || src.flushing) + return + if(user.loc == src) + src.go_out(user) + return + +// leave the disposal +/obj/machinery/disposal/proc/go_out(mob/user) + + if (user.client) + user.client.eye = user.client.mob + user.client.perspective = MOB_PERSPECTIVE + user.forceMove(src.loc) + update_icon() + return + +// ai as human but can't flush +/obj/machinery/disposal/attack_ai(mob/user as mob) + interact(user, 1) + +// human interact with machine +/obj/machinery/disposal/attack_hand(mob/user as mob) + + if(stat & BROKEN) + return + + if(user && user.loc == src) + to_chat(usr, "You cannot reach the controls from inside.") + return + + // Clumsy folks can only flush it. + if(user.IsAdvancedToolUser(1)) + interact(user, 0) + else + flush = !flush + update_icon() + return + +// user interaction +/obj/machinery/disposal/interact(mob/user, var/ai=0) + + src.add_fingerprint(user) + if(stat & BROKEN) + user.unset_machine() + return + + var/dat = "Waste Disposal UnitWaste Disposal Unit
            " + + if(!ai) // AI can't pull flush handle + if(flush) + dat += "Disposal handle: Disengage Engaged" + else + dat += "Disposal handle: Disengaged Engage" + + dat += "

            Eject contents
            " + + if(mode <= 0) + dat += "Pump: Off On
            " + else if(mode == 1) + dat += "Pump: Off On (pressurizing)
            " + else + dat += "Pump: Off On (idle)
            " + + var/per = 100* air_contents.return_pressure() / (SEND_PRESSURE) + + dat += "Pressure: [round(per, 1)]%
            " + + + user.set_machine(src) + user << browse(dat, "window=disposal;size=360x170") + onclose(user, "disposal") + +// handle machine interaction + +/obj/machinery/disposal/CanUseTopic(user, state, href_list) + if(usr.loc == src) + to_chat(usr, "You cannot reach the controls from inside.") + return STATUS_CLOSE + if(isAI(user) && (href_list["handle"] || href_list["eject"])) + return min(STATUS_UPDATE, ..()) + if(mode==-1 && !href_list["eject"]) // only allow ejecting if mode is -1 + to_chat(user, "The disposal units power is disabled.") + return min(STATUS_UPDATE, ..()) + if(flushing) + return min(STATUS_UPDATE, ..()) + return ..() + +/obj/machinery/disposal/OnTopic(user, href_list) + if(href_list["close"]) + close_browser(user, "window=disposal") + return TOPIC_HANDLED + + if(href_list["pump"]) + if(text2num(href_list["pump"])) + mode = 1 + else + mode = 0 + update_icon() + . = TOPIC_REFRESH + + else if(href_list["handle"]) + flush = text2num(href_list["handle"]) + update_icon() + . = TOPIC_REFRESH + + else if(href_list["eject"]) + eject() + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + interact(user) + +// eject the contents of the disposal unit +/obj/machinery/disposal/proc/eject() + for(var/atom/movable/AM in src) + AM.forceMove(src.loc) + AM.pipe_eject(0) + update_icon() + +// update the icon & overlays to reflect mode & status +/obj/machinery/disposal/update_icon() + overlays.Cut() + if(stat & BROKEN) + mode = 0 + flush = 0 + return + + // flush handle + if(flush) + overlays += image('icons/obj/pipes/disposal.dmi', "dispover-handle") + + // only handle is shown if no power + if(stat & NOPOWER || mode == -1) + return + + // check for items in disposal - occupied light + if(contents.len > 0) + overlays += image('icons/obj/pipes/disposal.dmi', "dispover-full") + + // charging and ready light + if(mode == 1) + overlays += image('icons/obj/pipes/disposal.dmi', "dispover-charge") + else if(mode == 2) + overlays += image('icons/obj/pipes/disposal.dmi', "dispover-ready") + +// timed process +// charge the gas reservoir and perform flush if ready +/obj/machinery/disposal/Process() + if(!air_contents || (stat & BROKEN)) // nothing can happen if broken + update_use_power(0) + return + + flush_count++ + if( flush_count >= flush_every_ticks ) + if( contents.len ) + if(mode == 2) + spawn(0) + feedback_inc("disposal_auto_flush",1) + flush() + flush_count = 0 + + src.updateDialog() + + if(flush && air_contents.return_pressure() >= SEND_PRESSURE ) // flush can happen even without power + flush() + + if(mode != 1) //if off or ready, no need to charge + update_use_power(1) + else if(air_contents.return_pressure() >= SEND_PRESSURE) + mode = 2 //if full enough, switch to ready mode + update_icon() + else + src.pressurize() //otherwise charge + +/obj/machinery/disposal/proc/pressurize() + if(stat & NOPOWER) // won't charge if no power + update_use_power(0) + return + + var/atom/L = loc // recharging from loc turf + var/datum/gas_mixture/env = L.return_air() + + var/power_draw = -1 + if(env && env.temperature > 0) + var/transfer_moles = (PUMP_MAX_FLOW_RATE/env.volume)*env.total_moles //group_multiplier is divided out here + power_draw = pump_gas(src, env, air_contents, transfer_moles, active_power_usage) + + if (power_draw > 0) + use_power(power_draw) + +// perform a flush +/obj/machinery/disposal/proc/flush() + + flushing = 1 + flick("[icon_state]-flush", src) + + var/wrapcheck = 0 + var/obj/structure/disposalholder/H = new() // virtual holder object which actually + // travels through the pipes. + //Hacky test to get drones to mail themselves through disposals. + for(var/mob/living/silicon/robot/drone/D in src) + wrapcheck = 1 + + for(var/obj/item/smallDelivery/O in src) + wrapcheck = 1 + + if(wrapcheck == 1) + H.tomail = 1 + + + sleep(10) + if(last_sound < world.time + 1) + playsound(src, 'sound/machines/disposalflush.ogg', 50, 0, 0) + last_sound = world.time + sleep(5) // wait for animation to finish + + + H.init(src, air_contents) // copy the contents of disposer to holder + air_contents = new(PRESSURE_TANK_VOLUME) // new empty gas resv. + + H.start(src) // start the holder processing movement + flushing = 0 + // now reset disposal state + flush = 0 + if(mode == 2) // if was ready, + mode = 1 // switch to charging + update_icon() + return + + +// called when area power changes +/obj/machinery/disposal/power_change() + ..() // do default setting/reset of stat NOPOWER bit + update_icon() // update icon + return + + +// called when holder is expelled from a disposal +// should usually only occur if the pipe network is modified +/obj/machinery/disposal/proc/expel(var/obj/structure/disposalholder/H) + + var/turf/target + playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) + if(H) // Somehow, someone managed to flush a window which broke mid-transit and caused the disposal to go in an infinite loop trying to expel null, hopefully this fixes it + for(var/atom/movable/AM in H) + target = get_offset_target_turf(src.loc, rand(5)-rand(5), rand(5)-rand(5)) + + AM.forceMove(src.loc) + AM.pipe_eject(0) + if(!istype(AM,/mob/living/silicon/robot/drone)) //Poor drones kept smashing windows and taking system damage being fired out of disposals. ~Z + spawn(1) + if(AM) + AM.throw_at(target, 5, 1) + + H.vent_gas(loc) + qdel(H) + +/obj/machinery/disposal/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if (istype(mover,/obj/item) && mover.throwing) + var/obj/item/I = mover + if(istype(I, /obj/item/projectile)) + return + if(prob(75)) + I.forceMove(src) + for(var/mob/M in viewers(src)) + M.show_message("\The [I] lands in \the [src].", 3) + else + for(var/mob/M in viewers(src)) + M.show_message("\The [I] bounces off of \the [src]'s rim!", 3) + return 0 + else + return ..(mover, target, height, air_group) + +// virtual disposal object +// travels through pipes in lieu of actual items +// contents will be items flushed by the disposal +// this allows the gas flushed to be tracked + +/obj/structure/disposalholder + invisibility = 101 + var/datum/gas_mixture/gas = null // gas used to flush, will appear at exit point + var/active = 0 // true if the holder is moving, otherwise inactive + dir = 0 + var/count = 2048 //*** can travel 2048 steps before going inactive (in case of loops) + var/destinationTag = "" // changes if contains a delivery container + var/tomail = 0 //changes if contains wrapped package + var/hasmob = 0 //If it contains a mob + + var/partialTag = "" //set by a partial tagger the first time round, then put in destinationTag if it goes through again. + + + // initialize a holder from the contents of a disposal unit + proc/init(var/obj/machinery/disposal/D, var/datum/gas_mixture/flush_gas) + gas = flush_gas// transfer gas resv. into holder object -- let's be explicit about the data this proc consumes, please. + + //Check for any living mobs trigger hasmob. + //hasmob effects whether the package goes to cargo or its tagged destination. + for(var/mob/living/M in D) + if(M && M.stat != 2 && !istype(M,/mob/living/silicon/robot/drone)) + hasmob = 1 + + //Checks 1 contents level deep. This means that players can be sent through disposals... + //...but it should require a second person to open the package. (i.e. person inside a wrapped locker) + for(var/obj/O in D) + if(O.contents) + for(var/mob/living/M in O.contents) + if(M && M.stat != 2 && !istype(M,/mob/living/silicon/robot/drone)) + hasmob = 1 + + // now everything inside the disposal gets put into the holder + // note AM since can contain mobs or objs + for(var/atom/movable/AM in D) + AM.forceMove(src) + if(istype(AM, /obj/structure/bigDelivery) && !hasmob) + var/obj/structure/bigDelivery/T = AM + src.destinationTag = T.sortTag + if(istype(AM, /obj/item/smallDelivery) && !hasmob) + var/obj/item/smallDelivery/T = AM + src.destinationTag = T.sortTag + //Drones can mail themselves through maint. + if(istype(AM, /mob/living/silicon/robot/drone)) + var/mob/living/silicon/robot/drone/drone = AM + src.destinationTag = drone.mail_destination + + + // start the movement process + // argument is the disposal unit the holder started in + proc/start(var/obj/machinery/disposal/D) + if(!D.trunk) + D.expel(src) // no trunk connected, so expel immediately + return + + forceMove(D.trunk) + active = 1 + set_dir(DOWN) + spawn(1) + move() // spawn off the movement process + + return + + // movement process, persists while holder is moving through pipes + proc/move() + var/obj/structure/disposalpipe/last + while(active) + sleep(1) // was 1 + if(!loc) return // check if we got GC'd + + if(hasmob && prob(3)) + for(var/mob/living/H in src) + if(!istype(H,/mob/living/silicon/robot/drone)) //Drones use the mailing code to move through the disposal system, + H.take_overall_damage(20, 0, "Blunt Trauma")//horribly maim any living creature jumping down disposals. c'est la vie + H.unlock_achievement(new/datum/achievement/clang()) + + var/obj/structure/disposalpipe/curr = loc + last = curr + curr = curr.transfer(src) + + if(!loc) return //side effects + + if(!curr) + last.expel(src, loc, dir) + + // + if(!(count--)) + active = 0 + return + + + + // find the turf which should contain the next pipe + proc/nextloc() + return get_step(loc,dir) + + // find a matching pipe on a turf + proc/findpipe(var/turf/T) + + if(!T) + return null + + var/fdir = turn(dir, 180) // flip the movement direction + for(var/obj/structure/disposalpipe/P in T) + if(fdir & P.dpdir) // find pipe direction mask that matches flipped dir + return P + // if no matching pipe, return null + return null + + // merge two holder objects + // used when a a holder meets a stuck holder + proc/merge(var/obj/structure/disposalholder/other) + for(var/atom/movable/AM in other) + AM.forceMove(src) // move everything in other holder to this one + if(ismob(AM)) + var/mob/M = AM + if(M.client) // if a client mob, update eye to follow this holder + M.client.eye = src + + qdel(other) + + + proc/settag(var/new_tag) + destinationTag = new_tag + + proc/setpartialtag(var/new_tag) + if(partialTag == new_tag) + destinationTag = new_tag + partialTag = "" + else + partialTag = new_tag + + + // called when player tries to move while in a pipe + relaymove(mob/user as mob) + + if(!istype(user,/mob/living)) + return + + var/mob/living/U = user + + if (U.stat || U.last_special <= world.time) + return + + U.last_special = world.time+100 + + if (src.loc) + for (var/mob/M in hearers(src.loc.loc)) + to_chat(M, "CLONG, clong!") + + playsound(src.loc, 'sound/effects/clang.ogg', 50, 0, 0) + + // called to vent all gas in holder to a location + proc/vent_gas(var/atom/location) + location.assume_air(gas) // vent all gas to turf + return + +/obj/structure/disposalholder/Destroy() + qdel(gas) + active = 0 + return ..() + +// Disposal pipes + +/obj/structure/disposalpipe + icon = 'icons/obj/pipes/disposal.dmi' + name = "disposal pipe" + desc = "An underfloor disposal pipe." + anchored = 1 + density = 0 + + level = 1 // underfloor only + var/dpdir = 0 // bitmask of pipe directions + dir = 0 // dir will contain dominant direction for junction pipes + var/health = 10 // health points 0-10 + alpha = 192 // Plane and alpha modified for mapping, reset to normal on spawn. + plane = ABOVE_TURF_PLANE + layer = DISPOSALS_PIPE_LAYER + var/base_icon_state // initial icon state on map + var/sortType = "" + var/subtype = 0 + // new pipe, set the icon_state as on map + New() + ..() + alpha = 255 + plane = ABOVE_PLATING_PLANE + base_icon_state = icon_state + return + + // pipe is deleted + // ensure if holder is present, it is expelled + Destroy() + var/obj/structure/disposalholder/H = locate() in src + if(H) + // holder was present + H.active = 0 + var/turf/T = src.loc + if(T.density) + // deleting pipe is inside a dense turf (wall) + // this is unlikely, but just dump out everything into the turf in case + + for(var/atom/movable/AM in H) + AM.forceMove(T) + AM.pipe_eject(0) + qdel(H) + return ..() + + // otherwise, do normal expel from turf + if(H) + expel(H, T, 0) + . = ..() + + // returns the direction of the next pipe object, given the entrance dir + // by default, returns the bitmask of remaining directions + proc/nextdir(var/fromdir) + return dpdir & (~turn(fromdir, 180)) + + // transfer the holder through this pipe segment + // overriden for special behaviour + // + proc/transfer(var/obj/structure/disposalholder/H) + var/nextdir = nextdir(H.dir) + H.set_dir(nextdir) + var/turf/T = H.nextloc() + var/obj/structure/disposalpipe/P = H.findpipe(T) + + if(P) + // find other holder in next loc, if inactive merge it with current + var/obj/structure/disposalholder/H2 = locate() in P + if(H2 && !H2.active) + H.merge(H2) + + H.forceMove(P) + else // if wasn't a pipe, then set loc to turf + H.forceMove(T) + return null + + return P + + + // update the icon_state to reflect hidden status + proc/update() + var/turf/T = src.loc + hide(!T.is_plating() && !istype(T,/turf/space)) // space never hides pipes + + // hide called by levelupdate if turf intact status changes + // change visibility status and force update of icon + hide(var/intact) + set_invisibility(intact ? 101: 0) // hide if floor is intact + update_icon() + + // update actual icon_state depending on visibility + // if invisible, append "f" to icon_state to show faded version + // this will be revealed if a T-scanner is used + // if visible, use regular icon_state + update_icon() +/* if(invisibility) //we hide things with alpha now, no need for transparent icons + icon_state = "[base_icon_state]f" + else + icon_state = base_icon_state*/ + icon_state = base_icon_state + return + + + // expel the held objects into a turf + // called when there is a break in the pipe + proc/expel(var/obj/structure/disposalholder/H, var/turf/T, var/direction) + if(!istype(H)) + return + + // Empty the holder if it is expelled into a dense turf. + // Leaving it intact and sitting in a wall is stupid. + if(T.density) + for(var/atom/movable/AM in H) + AM.loc = T + AM.pipe_eject(0) + qdel(H) + return + + + if(!T.is_plating() && istype(T,/turf/simulated/floor)) //intact floor, pop the tile + var/turf/simulated/floor/F = T + F.break_tile() + new /obj/item/stack/tile(H) // add to holder so it will be thrown with other stuff + + var/turf/target + if(direction) // direction is specified + if(istype(T, /turf/space)) // if ended in space, then range is unlimited + target = get_edge_target_turf(T, direction) + else // otherwise limit to 10 tiles + target = get_ranged_target_turf(T, direction, 10) + + playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) + if(H) + for(var/atom/movable/AM in H) + AM.forceMove(T) + AM.pipe_eject(direction) + spawn(1) + if(AM) + AM.throw_at(target, 100, 1) + H.vent_gas(T) + qdel(H) + + else // no specified direction, so throw in random direction + + playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) + if(H) + for(var/atom/movable/AM in H) + target = get_offset_target_turf(T, rand(5)-rand(5), rand(5)-rand(5)) + + AM.forceMove(T) + AM.pipe_eject(0) + spawn(1) + if(AM) + AM.throw_at(target, 5, 1) + + H.vent_gas(T) // all gas vent to turf + qdel(H) + + return + + // call to break the pipe + // will expel any holder inside at the time + // then delete the pipe + // remains : set to leave broken pipe pieces in place + proc/broken(var/remains = 0) + if(remains) + for(var/D in GLOB.cardinal) + if(D & dpdir) + var/obj/structure/disposalpipe/broken/P = new(src.loc) + P.set_dir(D) + + src.set_invisibility(101) // make invisible (since we won't delete the pipe immediately) + var/obj/structure/disposalholder/H = locate() in src + if(H) + // holder was present + H.active = 0 + var/turf/T = src.loc + if(T.density) + // broken pipe is inside a dense turf (wall) + // this is unlikely, but just dump out everything into the turf in case + + for(var/atom/movable/AM in H) + AM.forceMove(T) + AM.pipe_eject(0) + qdel(H) + return + + // otherwise, do normal expel from turf + if(H) + expel(H, T, 0) + + spawn(2) // delete pipe after 2 ticks to ensure expel proc finished + qdel(src) + + + // pipe affected by explosion + ex_act(severity) + + switch(severity) + if(1.0) + broken(0) + return + if(2.0) + health -= rand(5,15) + healthcheck() + return + if(3.0) + health -= rand(0,15) + healthcheck() + return + + + // test health for brokenness + proc/healthcheck() + if(health < -2) + broken(0) + else if(health<1) + broken(1) + return + + //attack by item + //weldingtool: unfasten and convert to obj/disposalconstruct + + attackby(var/obj/item/I, var/mob/user) + + var/turf/T = src.loc + if(!T.is_plating()) + return // prevent interaction with T-scanner revealed pipes + src.add_fingerprint(user, 0, I) + if(istype(I, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/W = I + + if(W.remove_fuel(0,user)) + playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) + // check if anything changed over 2 seconds + var/turf/uloc = user.loc + var/atom/wloc = W.loc + to_chat(user, "Slicing the disposal pipe.") + sleep(30) + if(!W.isOn()) return + if(user.loc == uloc && wloc == W.loc) + welded() + else + to_chat(user, "You must stay still while welding the pipe.") + else + to_chat(user, "You need more welding fuel to cut the pipe.") + return + + // called when pipe is cut with welder + proc/welded() + + var/obj/structure/disposalconstruct/C = new (src.loc) + switch(base_icon_state) + if("pipe-s") + C.ptype = 0 + if("pipe-c") + C.ptype = 1 + if("pipe-j1") + C.ptype = 2 + if("pipe-j2") + C.ptype = 3 + if("pipe-y") + C.ptype = 4 + if("pipe-t") + C.ptype = 5 + if("pipe-j1s") + C.ptype = 9 + C.sortType = sortType + if("pipe-j2s") + C.ptype = 10 + C.sortType = sortType +///// Z-Level stuff + if("pipe-u") + C.ptype = 11 + if("pipe-d") + C.ptype = 12 +///// Z-Level stuff + if("pipe-tagger") + C.ptype = 13 + if("pipe-tagger-partial") + C.ptype = 14 + C.subtype = src.subtype + src.transfer_fingerprints_to(C) + C.set_dir(dir) + C.set_density(0) + C.anchored = 1 + C.update() + + qdel(src) + +// pipe is deleted +// ensure if holder is present, it is expelled +/obj/structure/disposalpipe/Destroy() + var/obj/structure/disposalholder/H = locate() in src + if(H) + // holder was present + H.active = 0 + var/turf/T = src.loc + if(T.density) + // deleting pipe is inside a dense turf (wall) + // this is unlikely, but just dump out everything into the turf in case + + for(var/atom/movable/AM in H) + AM.forceMove(T) + AM.pipe_eject(0) + qdel(H) + return ..() + + // otherwise, do normal expel from turf + if(H) + expel(H, T, 0) + . = ..() + +/obj/structure/disposalpipe/hides_under_flooring() + return 1 + +// *** TEST verb +//client/verb/dispstop() +// for(var/obj/structure/disposalholder/H in world) +// H.active = 0 + +// a straight or bent segment +/obj/structure/disposalpipe/segment + icon_state = "pipe-s" + + New() + ..() + if(icon_state == "pipe-s") + dpdir = dir | turn(dir, 180) + else + dpdir = dir | turn(dir, -90) + + update() + return + +///// Z-Level stuff +/obj/structure/disposalpipe/up + icon_state = "pipe-u" + + New() + ..() + dpdir = dir + update() + return + + nextdir(var/fromdir) + var/nextdir + if(fromdir == 11) + nextdir = dir + else + nextdir = 12 + return nextdir + + transfer(var/obj/structure/disposalholder/H) + var/nextdir = nextdir(H.dir) + H.set_dir(nextdir) + + var/turf/T + var/obj/structure/disposalpipe/P + + if(nextdir == 12) + T = GetAbove(src) + if(!T) + H.forceMove(loc) + return + else + for(var/obj/structure/disposalpipe/down/F in T) + P = F + + else + T = get_step(src.loc, H.dir) + P = H.findpipe(T) + + if(P) + // find other holder in next loc, if inactive merge it with current + var/obj/structure/disposalholder/H2 = locate() in P + if(H2 && !H2.active) + H.merge(H2) + + H.forceMove(P) + else // if wasn't a pipe, then set loc to turf + H.forceMove(T) + return null + + return P + +/obj/structure/disposalpipe/down + icon_state = "pipe-d" + + New() + ..() + dpdir = dir + update() + return + + nextdir(var/fromdir) + var/nextdir + if(fromdir == 12) + nextdir = dir + else + nextdir = 11 + return nextdir + + transfer(var/obj/structure/disposalholder/H) + var/nextdir = nextdir(H.dir) + H.dir = nextdir + + var/turf/T + var/obj/structure/disposalpipe/P + + if(nextdir == 11) + T = GetBelow(src) + if(!T) + H.forceMove(src.loc) + return + else + for(var/obj/structure/disposalpipe/up/F in T) + P = F + + else + T = get_step(src.loc, H.dir) + P = H.findpipe(T) + + if(P) + // find other holder in next loc, if inactive merge it with current + var/obj/structure/disposalholder/H2 = locate() in P + if(H2 && !H2.active) + H.merge(H2) + + H.forceMove(P) + else // if wasn't a pipe, then set loc to turf + H.forceMove(T) + return null + + return P +///// Z-Level stuff + +/obj/structure/disposalpipe/junction/yjunction + icon_state = "pipe-y" + +//a three-way junction with dir being the dominant direction +/obj/structure/disposalpipe/junction + icon_state = "pipe-j1" + + New() + ..() + if(icon_state == "pipe-j1") + dpdir = dir | turn(dir, -90) | turn(dir,180) + else if(icon_state == "pipe-j2") + dpdir = dir | turn(dir, 90) | turn(dir,180) + else // pipe-y + dpdir = dir | turn(dir,90) | turn(dir, -90) + update() + return + + + // next direction to move + // if coming in from secondary dirs, then next is primary dir + // if coming in from primary dir, then next is equal chance of other dirs + + nextdir(var/fromdir) + var/flipdir = turn(fromdir, 180) + if(flipdir != dir) // came from secondary dir + return dir // so exit through primary + else // came from primary + // so need to choose either secondary exit + var/mask = ..(fromdir) + + // find a bit which is set + var/setbit = 0 + if(mask & NORTH) + setbit = NORTH + else if(mask & SOUTH) + setbit = SOUTH + else if(mask & EAST) + setbit = EAST + else + setbit = WEST + + if(prob(50)) // 50% chance to choose the found bit or the other one + return setbit + else + return mask & (~setbit) + + +/obj/structure/disposalpipe/tagger + name = "package tagger" + icon_state = "pipe-tagger" + var/sort_tag = "" + var/partial = 0 + + proc/updatedesc() + desc = initial(desc) + if(sort_tag) + desc += "\nIt's tagging objects with the '[sort_tag]' tag." + + proc/updatename() + if(sort_tag) + SetName("[initial(name)] ([sort_tag])") + else + SetName(initial(name)) + + New() + . = ..() + dpdir = dir | turn(dir, 180) + if(sort_tag) GLOB.tagger_locations |= sort_tag + updatename() + updatedesc() + update() + + attackby(var/obj/item/I, var/mob/user) + if(..()) + return + + if(istype(I, /obj/item/device/destTagger)) + var/obj/item/device/destTagger/O = I + + if(O.currTag)// Tag set + sort_tag = O.currTag + playsound(src.loc, 'sound/machines/twobeep.ogg', 100, 1) + to_chat(user, "Changed tag to '[sort_tag]'.") + updatename() + updatedesc() + + transfer(var/obj/structure/disposalholder/H) + if(sort_tag) + if(partial) + H.setpartialtag(sort_tag) + else + H.settag(sort_tag) + return ..() + +/obj/structure/disposalpipe/tagger/partial //needs two passes to tag + name = "partial package tagger" + icon_state = "pipe-tagger-partial" + partial = 1 + +/obj/machinery/disposal_switch + name = "disposal switch" + desc = "A disposal control switch." + icon = 'icons/obj/recycling.dmi' + icon_state = "switch-off" + layer = ABOVE_OBJ_LAYER + var/on = 0 + var/list/junctions = list() + var/id_tag + +/obj/machinery/disposal_switch/New(loc, newid) + ..(loc) + if(!id_tag) + id_tag = newid + +/obj/machinery/disposal_switch/Initialize() + for(var/obj/structure/disposalpipe/diversion_junction/D in world) + if(D.id_tag && !D.linked && D.id_tag == src.id_tag) + junctions += D + D.linked = src + + . = ..() + +/obj/machinery/disposal_switch/Destroy() + junctions.Cut() + return ..() + +/obj/machinery/disposal_switch/attackby(obj/item/I, mob/user, params) + if(isCrowbar(I)) + var/obj/item/disposal_switch_construct/C = new/obj/item/disposal_switch_construct(src.loc, id_tag) + transfer_fingerprints_to(C) + user.visible_message("\The [user] deattaches \the [src]") + qdel(src) + else + ..() + +/obj/machinery/disposal_switch/attack_hand(mob/user) + if(!allowed(user)) + to_chat(user, "Access denied.") + return + on = !on + for(var/obj/structure/disposalpipe/diversion_junction/D in junctions) + if(D.id_tag == src.id_tag) + D.active = on + if(on) + icon_state = "switch-fwd" + else + icon_state = "switch-off" + + +/obj/item/disposal_switch_construct + name = "disposal switch assembly" + desc = "A disposal control switch assembly." + icon = 'icons/obj/recycling.dmi' + icon_state = "switch-off" + w_class = ITEM_SIZE_LARGE + var/id_tag + +/obj/item/disposal_switch_construct/New(var/turf/loc, var/id) + ..(loc) + if(id) id_tag = id + else + id_tag = "ds[sequential_id(/obj/item/disposal_switch_construct)]" + +/obj/item/disposal_switch_construct/afterattack(atom/A, mob/user, proximity) + if(!proximity || !istype(A, /turf/simulated/floor) || istype(A, /area/shuttle) || user.incapacitated() || !id_tag) + return + var/found = 0 + for(var/obj/structure/disposalpipe/diversion_junction/D in world) + if(D.id_tag == src.id_tag) + found = 1 + break + if(!found) + to_chat(user, "\icon[src]\The [src] is not linked to any junctions!") + return + var/obj/machinery/disposal_switch/NC = new/obj/machinery/disposal_switch(A, id_tag) + transfer_fingerprints_to(NC) + qdel(src) + +/obj/structure/disposalpipe/diversion_junction + name = "diversion junction" + icon_state = "pipe-j1s" + desc = "An underfloor disposal pipe with a flip mechanism." + + var/active = 0 + var/active_dir = 0 + var/inactive_dir = 0 + var/sortdir = 0 + var/id_tag + var/obj/machinery/disposal_switch/linked + +/obj/structure/disposalpipe/diversion_junction/proc/updatedesc() + desc = initial(desc) + if(sortType) + desc += "\nIt's currently [active ? "" : "un"]active!" + +/obj/structure/disposalpipe/diversion_junction/proc/updatedir() + inactive_dir = dir + active_dir = turn(inactive_dir, 180) + if(icon_state == "pipe-j1s") + sortdir = turn(inactive_dir, -90) + else if(icon_state == "pipe-j2s") + sortdir = turn(inactive_dir, 90) + + dpdir = sortdir | inactive_dir | active_dir + +/obj/structure/disposalpipe/diversion_junction/New() + ..() + + updatedir() + updatedesc() + update() + +/obj/structure/disposalpipe/diversion_junction/Destroy() + if(linked) + linked.junctions.Remove(src) + linked = null + return ..() + +/obj/structure/disposalpipe/diversion_junction/attackby(var/obj/item/I, var/mob/user) + if(..()) + return 1 + + if(istype(I, /obj/item/disposal_switch_construct)) + var/obj/item/disposal_switch_construct/C = I + if(C.id_tag) + id_tag = C.id_tag + playsound(src.loc, 'sound/machines/twobeep.ogg', 100, 1) + user.visible_message("\The [user] changes \the [src]'s tag.") + + +/obj/structure/disposalpipe/diversion_junction/nextdir(var/fromdir, var/sortTag) + if(fromdir != sortdir) + if(active) + return sortdir + else + return inactive_dir + else + return inactive_dir + +/obj/structure/disposalpipe/diversion_junction/transfer(var/obj/structure/disposalholder/H) + var/nextdir = nextdir(H.dir, H.destinationTag) + H.set_dir(nextdir) + var/turf/T = H.nextloc() + var/obj/structure/disposalpipe/P = H.findpipe(T) + + if(P) + var/obj/structure/disposalholder/H2 = locate() in P + if(H2 && !H2.active) + H.merge(H2) + + H.forceMove(P) + else + H.forceMove(T) + return null + + return P + +/obj/structure/disposalpipe/diversion_junction/flipped //for easier and cleaner mapping + icon_state = "pipe-j2s" + +//a three-way junction that sorts objects +/obj/structure/disposalpipe/sortjunction + name = "sorting junction" + icon_state = "pipe-j1s" + desc = "An underfloor disposal pipe with a package sorting mechanism." + + var/posdir = 0 + var/negdir = 0 + var/sortdir = 0 + + proc/updatedesc() + desc = initial(desc) + if(sortType) + desc += "\nIt's filtering objects with the '[sortType]' tag." + + proc/updatename() + if(sortType) + SetName("[initial(name)] ([sortType])") + else + SetName(initial(name)) + + proc/updatedir() + posdir = dir + negdir = turn(posdir, 180) + + if(icon_state == "pipe-j1s") + sortdir = turn(posdir, -90) + else if(icon_state == "pipe-j2s") + sortdir = turn(posdir, 90) + + dpdir = sortdir | posdir | negdir + + New() + . = ..() + if(sortType) GLOB.tagger_locations |= sortType + + updatedir() + updatename() + updatedesc() + update() + + attackby(var/obj/item/I, var/mob/user) + if(..()) + return + + if(istype(I, /obj/item/device/destTagger)) + var/obj/item/device/destTagger/O = I + + if(O.currTag)// Tag set + sortType = O.currTag + playsound(src.loc, 'sound/machines/twobeep.ogg', 100, 1) + to_chat(user, "Changed filter to '[sortType]'.") + updatename() + updatedesc() + + proc/divert_check(var/checkTag) + return sortType == checkTag + + // next direction to move + // if coming in from negdir, then next is primary dir or sortdir + // if coming in from posdir, then flip around and go back to posdir + // if coming in from sortdir, go to posdir + + nextdir(var/fromdir, var/sortTag) + if(fromdir != sortdir) // probably came from the negdir + if(divert_check(sortTag)) + return sortdir + else + return posdir + else // came from sortdir + // so go with the flow to positive direction + return posdir + + transfer(var/obj/structure/disposalholder/H) + var/nextdir = nextdir(H.dir, H.destinationTag) + H.set_dir(nextdir) + var/turf/T = H.nextloc() + var/obj/structure/disposalpipe/P = H.findpipe(T) + + if(P) + // find other holder in next loc, if inactive merge it with current + var/obj/structure/disposalholder/H2 = locate() in P + if(H2 && !H2.active) + H.merge(H2) + + H.forceMove(P) + else // if wasn't a pipe, then set loc to turf + H.forceMove(T) + return null + + return P + +//a three-way junction that filters all wrapped and tagged items +/obj/structure/disposalpipe/sortjunction/wildcard + name = "wildcard sorting junction" + desc = "An underfloor disposal pipe which filters all wrapped and tagged items." + subtype = 1 + divert_check(var/checkTag) + return checkTag != "" + +//junction that filters all untagged items +/obj/structure/disposalpipe/sortjunction/untagged + name = "untagged sorting junction" + desc = "An underfloor disposal pipe which filters all untagged items." + subtype = 2 + divert_check(var/checkTag) + return checkTag == "" + +/obj/structure/disposalpipe/sortjunction/flipped //for easier and cleaner mapping + icon_state = "pipe-j2s" + +/obj/structure/disposalpipe/sortjunction/wildcard/flipped + icon_state = "pipe-j2s" + +/obj/structure/disposalpipe/sortjunction/untagged/flipped + icon_state = "pipe-j2s" + +//a trunk joining to a disposal bin or outlet on the same turf +/obj/structure/disposalpipe/trunk + icon_state = "pipe-t" + var/obj/linked // the linked obj/machinery/disposal or obj/disposaloutlet + +/obj/structure/disposalpipe/trunk/New() + ..() + dpdir = dir + spawn(1) + getlinked() + + update() + return + +/obj/structure/disposalpipe/trunk/proc/getlinked() + linked = null + var/obj/machinery/disposal/D = locate() in src.loc + if(D) + linked = D + if (!D.trunk) + D.trunk = src + + var/obj/structure/disposaloutlet/O = locate() in src.loc + if(O) + linked = O + + update() + return + + // Override attackby so we disallow trunkremoval when somethings ontop +/obj/structure/disposalpipe/trunk/attackby(var/obj/item/I, var/mob/user) + + //Disposal bins or chutes + /* + These shouldn't be required + var/obj/machinery/disposal/D = locate() in src.loc + if(D && D.anchored) + return + + //Disposal outlet + var/obj/structure/disposaloutlet/O = locate() in src.loc + if(O && O.anchored) + return + */ + + //Disposal constructors + var/obj/structure/disposalconstruct/C = locate() in src.loc + if(C && C.anchored) + return + + var/turf/T = src.loc + if(!T.is_plating()) + return // prevent interaction with T-scanner revealed pipes + src.add_fingerprint(user, 0, I) + if(istype(I, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/W = I + + if(W.remove_fuel(0,user)) + playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) + // check if anything changed over 2 seconds + var/turf/uloc = user.loc + var/atom/wloc = W.loc + to_chat(user, "Slicing the disposal pipe.") + sleep(30) + if(!W.isOn()) return + if(user.loc == uloc && wloc == W.loc) + welded() + else + to_chat(user, "You must stay still while welding the pipe.") + else + to_chat(user, "You need more welding fuel to cut the pipe.") + return + + // would transfer to next pipe segment, but we are in a trunk + // if not entering from disposal bin, + // transfer to linked object (outlet or bin) + +/obj/structure/disposalpipe/trunk/transfer(var/obj/structure/disposalholder/H) + + if(H.dir == DOWN) // we just entered from a disposer + return ..() // so do base transfer proc + // otherwise, go to the linked object + if(linked) + var/obj/structure/disposaloutlet/O = linked + if(istype(O) && (H)) + O.expel(H) // expel at outlet + else + var/obj/machinery/disposal/D = linked + if(H) + D.expel(H) // expel at disposal + else + if(H) + src.expel(H, src.loc, 0) // expel at turf + return null + + // nextdir + +/obj/structure/disposalpipe/trunk/nextdir(var/fromdir) + if(fromdir == DOWN) + return dir + else + return 0 + +// a broken pipe +/obj/structure/disposalpipe/broken + icon_state = "pipe-b" + dpdir = 0 // broken pipes have dpdir=0 so they're not found as 'real' pipes + // i.e. will be treated as an empty turf + desc = "A broken piece of disposal pipe." + + New() + ..() + update() + return + + // called when welded + // for broken pipe, remove and turn into scrap + + welded() +// var/obj/item/scrap/S = new(src.loc) +// S.set_components(200,0,0) + qdel(src) + +// the disposal outlet machine + +/obj/structure/disposaloutlet + name = "disposal outlet" + desc = "An outlet for the pneumatic disposal system." + icon = 'icons/obj/pipes/disposal.dmi' + icon_state = "outlet" + density = 1 + anchored = 1 + var/active = 0 + var/turf/target // this will be where the output objects are 'thrown' to. + var/mode = 0 + atom_flags = ATOM_FLAG_CLIMBABLE + + New() + ..() + + spawn(1) + target = get_ranged_target_turf(src, dir, 10) + + + var/obj/structure/disposalpipe/trunk/trunk = locate() in src.loc + if(trunk) + trunk.linked = src // link the pipe trunk to self + + // expel the contents of the holder object, then delete it + // called when the holder exits the outlet + proc/expel(var/obj/structure/disposalholder/H) + + flick("outlet-open", src) + playsound(src, 'sound/machines/warning-buzzer.ogg', 50, 0, 0) + sleep(20) //wait until correct animation frame + playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) + + if(H) + for(var/atom/movable/AM in H) + AM.forceMove(src.loc) + AM.pipe_eject(dir) + if(!istype(AM,/mob/living/silicon/robot/drone)) //Drones keep smashing windows from being fired out of chutes. Bad for the station. ~Z + spawn(5) + AM.throw_at(target, 3, 1) + H.vent_gas(src.loc) + qdel(H) + + return + + attackby(var/obj/item/I, var/mob/user) + if(!I || !user) + return + src.add_fingerprint(user, 0, I) + if(isScrewdriver(I)) + if(mode==0) + mode=1 + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You remove the screws around the power connection.") + return + else if(mode==1) + mode=0 + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You attach the screws around the power connection.") + return + else if(istype(I,/obj/item/weapon/weldingtool) && mode==1) + var/obj/item/weapon/weldingtool/W = I + if(W.remove_fuel(0,user)) + playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) + to_chat(user, "You start slicing the floorweld off the disposal outlet.") + if(do_after(user,20, src)) + if(!src || !W.isOn()) return + to_chat(user, "You sliced the floorweld off the disposal outlet.") + var/obj/structure/disposalconstruct/C = new (src.loc) + src.transfer_fingerprints_to(C) + C.ptype = 7 // 7 = outlet + C.update() + C.anchored = 1 + C.set_density(1) + qdel(src) + return + else + to_chat(user, "You need more welding fuel to complete this task.") + return + +// called when movable is expelled from a disposal pipe or outlet +// by default does nothing, override for special behaviour + +/atom/movable/proc/pipe_eject(var/direction) + return + +// check if mob has client, if so restore client view on eject +/mob/pipe_eject(var/direction) + if (src.client) + src.client.perspective = MOB_PERSPECTIVE + src.client.eye = src + + return + +/obj/effect/decal/cleanable/blood/gibs/pipe_eject(var/direction) + var/list/dirs + if(direction) + dirs = list( direction, turn(direction, -45), turn(direction, 45)) + else + dirs = GLOB.alldirs.Copy() + + src.streak(dirs) + +/obj/effect/decal/cleanable/blood/gibs/robot/pipe_eject(var/direction) + var/list/dirs + if(direction) + dirs = list( direction, turn(direction, -45), turn(direction, 45)) + else + dirs = GLOB.alldirs.Copy() + + src.streak(dirs) diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm new file mode 100644 index 00000000..513ce2c1 --- /dev/null +++ b/code/modules/recycling/sortingmachinery.dm @@ -0,0 +1,493 @@ +/obj/structure/bigDelivery + desc = "A big wrapped package." + name = "large parcel" + icon = 'icons/obj/storage.dmi' + icon_state = "deliverycloset" + var/obj/wrapped = null + density = 1 + var/sortTag = null + mouse_drag_pointer = MOUSE_ACTIVE_POINTER + var/examtext = null + var/nameset = 0 + var/label_y + var/label_x + var/tag_x + +/obj/structure/bigDelivery/attack_robot(mob/user as mob) + unwrap(user) + +/obj/structure/bigDelivery/attack_hand(mob/user as mob) + unwrap(user) + +/obj/structure/bigDelivery/proc/unwrap(var/mob/user) + if(Adjacent(user)) + // Destroy will drop our wrapped object on the turf, so let it. + qdel(src) + +/obj/structure/bigDelivery/attackby(obj/item/W as obj, mob/user as mob) + if(istype(W, /obj/item/device/destTagger)) + var/obj/item/device/destTagger/O = W + if(O.currTag) + if(src.sortTag != O.currTag) + to_chat(user, "You have labeled the destination as [O.currTag].") + if(!src.sortTag) + src.sortTag = O.currTag + update_icon() + else + src.sortTag = O.currTag + playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 1) + else + to_chat(user, "The package is already labeled for [O.currTag].") + else + to_chat(user, "You need to set a destination first!") + + else if(istype(W, /obj/item/weapon/pen)) + switch(alert("What would you like to alter?",,"Title","Description", "Cancel")) + if("Title") + var/str = sanitizeSafe(input(usr,"Label text?","Set label",""), MAX_NAME_LEN) + if(!str || !length(str)) + to_chat(usr, " Invalid text.") + return + user.visible_message("\The [user] titles \the [src] with \a [W], marking down: \"[str]\"",\ + "You title \the [src]: \"[str]\"",\ + "You hear someone scribbling a note.") + SetName("[name] ([str])") + if(!examtext && !nameset) + nameset = 1 + update_icon() + else + nameset = 1 + if("Description") + var/str = sanitize(input(usr,"Label text?","Set label","")) + if(!str || !length(str)) + to_chat(usr, "Invalid text.") + return + if(!examtext && !nameset) + examtext = str + update_icon() + else + examtext = str + user.visible_message("\The [user] labels \the [src] with \a [W], scribbling down: \"[examtext]\"",\ + "You label \the [src]: \"[examtext]\"",\ + "You hear someone scribbling a note.") + return + +/obj/structure/bigDelivery/update_icon() + overlays = new() + if(nameset || examtext) + var/image/I = new/image('icons/obj/storage.dmi',"delivery_label") + if(icon_state == "deliverycloset") + I.pixel_x = 2 + if(label_y == null) + label_y = rand(-6, 11) + I.pixel_y = label_y + else if(icon_state == "deliverycrate") + if(label_x == null) + label_x = rand(-8, 6) + I.pixel_x = label_x + I.pixel_y = -3 + overlays += I + if(src.sortTag) + var/image/I = new/image('icons/obj/storage.dmi',"delivery_tag") + if(icon_state == "deliverycloset") + if(tag_x == null) + tag_x = rand(-2, 3) + I.pixel_x = tag_x + I.pixel_y = 9 + else if(icon_state == "deliverycrate") + if(tag_x == null) + tag_x = rand(-8, 6) + I.pixel_x = tag_x + I.pixel_y = -3 + overlays += I + +/obj/structure/bigDelivery/examine(mob/user) + if(..(user, 4)) + if(sortTag) + to_chat(user, "It is labeled \"[sortTag]\"") + if(examtext) + to_chat(user, "It has a note attached which reads, \"[examtext]\"") + return + +/obj/structure/bigDelivery/Destroy() + if(wrapped) //sometimes items can disappear. For example, bombs. --rastaf0 + wrapped.forceMove(get_turf(src)) + if(istype(wrapped, /obj/structure/closet)) + var/obj/structure/closet/O = wrapped + O.welded = 0 + wrapped = null + var/turf/T = get_turf(src) + for(var/atom/movable/AM in contents) + AM.forceMove(T) + return ..() + +/obj/item/smallDelivery + desc = "A small wrapped package." + name = "small parcel" + icon = 'icons/obj/storage.dmi' + icon_state = "deliverycrate3" + var/obj/item/wrapped = null + var/sortTag = null + var/examtext = null + var/nameset = 0 + var/tag_x + +/obj/item/smallDelivery/proc/unwrap(var/mob/user) + if (!wrapped || !Adjacent(user)) + return + wrapped.forceMove(user.loc) + user.drop_item() + if(ishuman(user)) + user.put_in_hands(wrapped) + else + wrapped.forceMove(get_turf(src)) + qdel(src) + +/obj/item/smallDelivery/attack_robot(mob/user as mob) + unwrap(user) + +/obj/item/smallDelivery/attack_self(mob/user as mob) + unwrap(user) + +/obj/item/smallDelivery/attackby(obj/item/W as obj, mob/user as mob) + if(istype(W, /obj/item/device/destTagger)) + var/obj/item/device/destTagger/O = W + if(O.currTag) + if(src.sortTag != O.currTag) + to_chat(user, "You have labeled the destination as [O.currTag].") + if(!src.sortTag) + src.sortTag = O.currTag + update_icon() + else + src.sortTag = O.currTag + playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 1) + else + to_chat(user, "The package is already labeled for [O.currTag].") + else + to_chat(user, "You need to set a destination first!") + + else if(istype(W, /obj/item/weapon/pen)) + switch(alert("What would you like to alter?",,"Title","Description", "Cancel")) + if("Title") + var/str = sanitizeSafe(input(usr,"Label text?","Set label",""), MAX_NAME_LEN) + if(!str || !length(str)) + to_chat(usr, " Invalid text.") + return + user.visible_message("\The [user] titles \the [src] with \a [W], marking down: \"[str]\"",\ + "You title \the [src]: \"[str]\"",\ + "You hear someone scribbling a note.") + SetName("[name] ([str])") + if(!examtext && !nameset) + nameset = 1 + update_icon() + else + nameset = 1 + + if("Description") + var/str = sanitize(input(usr,"Label text?","Set label","")) + if(!str || !length(str)) + to_chat(usr, "Invalid text.") + return + if(!examtext && !nameset) + examtext = str + update_icon() + else + examtext = str + user.visible_message("\The [user] labels \the [src] with \a [W], scribbling down: \"[examtext]\"",\ + "You label \the [src]: \"[examtext]\"",\ + "You hear someone scribbling a note.") + return + +/obj/item/smallDelivery/update_icon() + overlays = new() + if((nameset || examtext) && icon_state != "deliverycrate1") + var/image/I = new/image('icons/obj/storage.dmi',"delivery_label") + if(icon_state == "deliverycrate5") + I.pixel_y = -1 + overlays += I + if(src.sortTag) + var/image/I = new/image('icons/obj/storage.dmi',"delivery_tag") + switch(icon_state) + if("deliverycrate1") + I.pixel_y = -5 + if("deliverycrate2") + I.pixel_y = -2 + if("deliverycrate3") + I.pixel_y = 0 + if("deliverycrate4") + if(tag_x == null) + tag_x = rand(0,5) + I.pixel_x = tag_x + I.pixel_y = 3 + if("deliverycrate5") + I.pixel_y = -3 + overlays += I + +/obj/item/smallDelivery/examine(mob/user) + if(..(user, 4)) + if(sortTag) + to_chat(user, "It is labeled \"[sortTag]\"") + if(examtext) + to_chat(user, "It has a note attached which reads, \"[examtext]\"") + return + +/obj/item/weapon/packageWrap + name = "package wrapper" + icon = 'icons/obj/items.dmi' + icon_state = "deliveryPaper" + w_class = ITEM_SIZE_NORMAL + var/amount = 25.0 + +/obj/item/weapon/c_tube + name = "cardboard tube" + desc = "A tube... of cardboard." + icon = 'icons/obj/items.dmi' + icon_state = "c_tube" + throwforce = 1 + w_class = ITEM_SIZE_SMALL + throw_speed = 4 + throw_range = 5 + +/obj/item/weapon/packageWrap/afterattack(var/obj/target as obj, mob/user as mob, proximity) + if(!proximity) return + if(!istype(target)) //this really shouldn't be necessary (but it is). -Pete + return + if(istype(target, /obj/item/smallDelivery) || istype(target,/obj/structure/bigDelivery) \ + || istype(target, /obj/item/weapon/gift) || istype(target, /obj/item/weapon/evidencebag)) + return + if(target.anchored) + return + if(target in user) + return + if(user in target) //no wrapping closets that you are inside - it's not physically possible + return + + if (istype(target, /obj/item) && !(istype(target, /obj/item/weapon/storage) && !istype(target,/obj/item/weapon/storage/box))) + var/obj/item/O = target + if (src.amount > 1) + var/obj/item/smallDelivery/P = new /obj/item/smallDelivery(get_turf(O.loc)) //Aaannd wrap it up! + if(!istype(O.loc, /turf)) + if(user.client) + user.client.screen -= O + P.wrapped = O + O.forceMove(P) + P.w_class = O.w_class + var/i = round(O.w_class) + if(i in list(1,2,3,4,5)) + P.icon_state = "deliverycrate[i]" + switch(i) + if(1) P.SetName("tiny parcel") + if(3) P.SetName("normal-sized parcel") + if(4) P.SetName("large parcel") + if(5) P.SetName("huge parcel") + if(i < 1) + P.icon_state = "deliverycrate1" + P.SetName("tiny parcel") + if(i > 5) + P.icon_state = "deliverycrate5" + P.SetName("huge parcel") + P.add_fingerprint(usr) + O.add_fingerprint(usr) + src.add_fingerprint(usr) + src.amount -= 1 + user.visible_message("\The [user] wraps \a [target] with \a [src].",\ + "You wrap \the [target], leaving [amount] units of paper on \the [src].",\ + "You hear someone taping paper around a small object.") + else if (istype(target, /obj/structure/closet/crate)) + var/obj/structure/closet/crate/O = target + if (src.amount > 3 && !O.opened) + var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc)) + P.icon_state = "deliverycrate" + P.wrapped = O + O.forceMove(P) + src.amount -= 3 + user.visible_message("\The [user] wraps \a [target] with \a [src].",\ + "You wrap \the [target], leaving [amount] units of paper on \the [src].",\ + "You hear someone taping paper around a large object.") + else if(src.amount < 3) + to_chat(user, "You need more paper.") + else if (istype (target, /obj/structure/closet)) + var/obj/structure/closet/O = target + if (src.amount > 3 && !O.opened) + var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc)) + P.wrapped = O + O.welded = 1 + O.forceMove(P) + src.amount -= 3 + user.visible_message("\The [user] wraps \a [target] with \a [src].",\ + "You wrap \the [target], leaving [amount] units of paper on \the [src].",\ + "You hear someone taping paper around a large object.") + else if(src.amount < 3) + to_chat(user, "You need more paper.") + else + to_chat(user, "The object you are trying to wrap is unsuitable for the sorting machinery!") + if (src.amount <= 0) + new /obj/item/weapon/c_tube( src.loc ) + qdel(src) + return + return + +/obj/item/weapon/packageWrap/examine(mob/user) + if(..(user, 0)) + to_chat(user, "There are [amount] units of package wrap left!") + return + +/obj/item/device/destTagger + name = "destination tagger" + desc = "Used to set the destination of properly wrapped packages." + icon_state = "dest_tagger" + var/currTag = 0 + w_class = ITEM_SIZE_SMALL + item_state = "electronic" + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BELT + matter = list(DEFAULT_WALL_MATERIAL = 100, "glass" = 34) + +/obj/item/device/destTagger/proc/openwindow(mob/user as mob) + var/dat = "

            TagMaster 2.3

            " + + dat += "" + for(var/i = 1, i <= GLOB.tagger_locations.len, i++) + dat += "" + + if (i%4==0) + dat += "" + + dat += "
            [GLOB.tagger_locations[i]]

            Current Selection: [currTag ? currTag : "None"]
            " + dat += "
            Enter custom location." + user << browse(dat, "window=destTagScreen;size=450x375") + onclose(user, "destTagScreen") + +/obj/item/device/destTagger/attack_self(mob/user as mob) + openwindow(user) + +/obj/item/device/destTagger/OnTopic(user, href_list, state) + if(href_list["nextTag"] && href_list["nextTag"] in GLOB.tagger_locations) + src.currTag = href_list["nextTag"] + . = TOPIC_REFRESH + if(href_list["nextTag"] == "CUSTOM") + var/dest = input(user, "Please enter custom location.", "Location", src.currTag ? src.currTag : "None") + if(CanUseTopic(user, state)) + if(dest != "None") + src.currTag = dest + else + src.currTag = 0 + . = TOPIC_REFRESH + else + . = TOPIC_HANDLED + + if(. == TOPIC_REFRESH) + openwindow(user) + +/obj/machinery/disposal/deliveryChute + name = "Delivery chute" + desc = "A chute for big and small packages alike!" + density = 1 + icon_state = "intake" + + var/c_mode = 0 + +/obj/machinery/disposal/deliveryChute/New() + ..() + spawn(5) + trunk = locate() in src.loc + if(trunk) + trunk.linked = src // link the pipe trunk to self + +/obj/machinery/disposal/deliveryChute/interact() + return + +/obj/machinery/disposal/deliveryChute/update_icon() + return + +/obj/machinery/disposal/deliveryChute/Bumped(var/atom/movable/AM) //Go straight into the chute + if(istype(AM, /obj/item/projectile) || istype(AM, /obj/effect)) return + switch(dir) + if(NORTH) + if(AM.loc.y != src.loc.y+1) return + if(EAST) + if(AM.loc.x != src.loc.x+1) return + if(SOUTH) + if(AM.loc.y != src.loc.y-1) return + if(WEST) + if(AM.loc.x != src.loc.x-1) return + + if(istype(AM, /obj)) + var/obj/O = AM + O.forceMove(src) + else if(istype(AM, /mob)) + var/mob/M = AM + M.forceMove(src) + src.flush() + +/obj/machinery/disposal/deliveryChute/flush() + flushing = 1 + flick("intake-closing", src) + var/obj/structure/disposalholder/H = new() // virtual holder object which actually + // travels through the pipes. + air_contents = new() // new empty gas resv. + + sleep(10) + playsound(src, 'sound/machines/disposalflush.ogg', 50, 0, 0) + sleep(5) // wait for animation to finish + + if(prob(35)) + for(var/mob/living/carbon/human/L in src) + var/list/obj/item/organ/external/crush = L.get_damageable_organs() + if(!crush.len) + return + + var/obj/item/organ/external/E = pick(crush) + + E.take_damage(45, used_weapon = "Blunt Trauma") + to_chat(L, "\The [src]'s mechanisms crush your [E.name]!") + + H.init(src) // copy the contents of disposer to holder + + H.start(src) // start the holder processing movement + flushing = 0 + // now reset disposal state + flush = 0 + if(mode == 2) // if was ready, + mode = 1 // switch to charging + update_icon() + return + +/obj/machinery/disposal/deliveryChute/attackby(var/obj/item/I, var/mob/user) + if(!I || !user) + return + + if(isScrewdriver(I)) + if(c_mode==0) + c_mode=1 + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You remove the screws around the power connection.") + return + else if(c_mode==1) + c_mode=0 + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You attach the screws around the power connection.") + return + else if(isWelder(I) && c_mode==1) + var/obj/item/weapon/weldingtool/W = I + if(W.remove_fuel(1,user)) + to_chat(user, "You start slicing the floorweld off the delivery chute.") + if(do_after(user,20, src)) + playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) + if(!src || !W.isOn()) return + to_chat(user, "You sliced the floorweld off the delivery chute.") + var/obj/structure/disposalconstruct/C = new (src.loc) + C.ptype = 8 // 8 = Delivery chute + C.update() + C.anchored = 1 + C.set_density(1) + qdel(src) + return + else + to_chat(user, "You need more welding fuel to complete this task.") + return + +/obj/machinery/disposal/deliveryChute/Destroy() + if(trunk) + trunk.linked = null + ..() diff --git a/code/modules/research/circuitprinter.dm b/code/modules/research/circuitprinter.dm new file mode 100644 index 00000000..d2884fd9 --- /dev/null +++ b/code/modules/research/circuitprinter.dm @@ -0,0 +1,165 @@ +/*///////////////Circuit Imprinter (By Darem)//////////////////////// + Used to print new circuit boards (for computers and similar systems) and AI modules. Each circuit board pattern are stored in +a /datum/desgin on the linked R&D console. You can then print them out in a fasion similar to a regular lathe. However, instead of +using metal and glass, it uses glass and reagents (usually sulphuric acid). +*/ + +/obj/machinery/r_n_d/circuit_imprinter + name = "\improper Circuit Imprinter" + icon_state = "circuit_imprinter" + atom_flags = ATOM_FLAG_OPEN_CONTAINER + var/list/datum/design/queue = list() + var/progress = 0 + + var/max_material_storage = 75000 + var/mat_efficiency = 1 + var/speed = 1 + + use_power = 1 + idle_power_usage = 30 + active_power_usage = 2500 + +/obj/machinery/r_n_d/circuit_imprinter/New() + materials = default_material_composition.Copy() + + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/circuit_imprinter(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(src) + component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(src) + RefreshParts() + +/obj/machinery/r_n_d/circuit_imprinter/Process() + ..() + if(stat) + update_icon() + return + if(queue.len == 0) + busy = 0 + update_icon() + return + var/datum/design/D = queue[1] + if(canBuild(D)) + busy = 1 + progress += speed + if(progress >= D.time) + build(D) + progress = 0 + removeFromQueue(1) + if(linked_console) + linked_console.updateUsrDialog() + update_icon() + else + if(busy) + visible_message("\icon [src] flashes: insufficient materials: [getLackingMaterials(D)].") + busy = 0 + update_icon() + +/obj/machinery/r_n_d/circuit_imprinter/RefreshParts() + var/T = 0 + for(var/obj/item/weapon/reagent_containers/glass/G in component_parts) + T += G.reagents.maximum_volume + create_reagents(T) + max_material_storage = 0 + for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts) + max_material_storage += M.rating * 75000 + T = 0 + for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) + T += M.rating + mat_efficiency = 1 - (T - 1) / 4 + speed = T + +/obj/machinery/r_n_d/circuit_imprinter/update_icon() + if(panel_open) + icon_state = "circuit_imprinter_t" + else if(busy) + icon_state = "circuit_imprinter_ani" + else + icon_state = "circuit_imprinter" + + +/obj/machinery/r_n_d/circuit_imprinter/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(busy) + to_chat(user, "\The [src] is busy. Please wait for completion of previous operation.") + return 1 + if(default_deconstruction_screwdriver(user, O)) + if(linked_console) + linked_console.linked_imprinter = null + linked_console = null + return + if(default_deconstruction_crowbar(user, O)) + return + if(default_part_replacement(user, O)) + return + if(panel_open) + to_chat(user, "You can't load \the [src] while it's opened.") + return 1 + if(!linked_console) + to_chat(user, "\The [src] must be linked to an R&D console first.") + return 1 + if(O.is_open_container()) + return 0 + if(is_robot_module(O)) + return 0 + if(!istype(O, /obj/item/stack/material)) + to_chat(user, "You cannot insert this item into \the [src]!") + return 0 + if(stat) + return 1 + + if(TotalMaterials() + SHEET_MATERIAL_AMOUNT > max_material_storage) + to_chat(user, "\The [src]'s material bin is full. Please remove material before adding more.") + return 1 + + var/obj/item/stack/material/stack = O + var/amount = min(stack.get_amount(), round((max_material_storage - TotalMaterials()) / SHEET_MATERIAL_AMOUNT)) + + busy = 1 + use_power(max(1000, (SHEET_MATERIAL_AMOUNT * amount / 10))) + + var/t = stack.material.name + if(t) + if(do_after(usr, 16, src)) + if(stack.use(amount)) + to_chat(user, "You add [amount] sheet\s to \the [src].") + materials[t] += amount * SHEET_MATERIAL_AMOUNT + busy = 0 + updateUsrDialog() + +/obj/machinery/r_n_d/circuit_imprinter/proc/addToQueue(var/datum/design/D) + queue += D + return + +/obj/machinery/r_n_d/circuit_imprinter/proc/removeFromQueue(var/index) + queue.Cut(index, index + 1) + return + +/obj/machinery/r_n_d/circuit_imprinter/proc/canBuild(var/datum/design/D) + for(var/M in D.materials) + if(materials[M] <= D.materials[M] * mat_efficiency) + return 0 + for(var/C in D.chemicals) + if(!reagents.has_reagent(C, D.chemicals[C])) + return 0 + return 1 + +/obj/machinery/r_n_d/circuit_imprinter/proc/build(var/datum/design/D) + var/power = active_power_usage + for(var/M in D.materials) + power += round(D.materials[M] / 5) + power = max(active_power_usage, power) + use_power(power) + for(var/M in D.materials) + materials[M] = max(0, materials[M] - D.materials[M] * mat_efficiency) + for(var/C in D.chemicals) + reagents.remove_reagent(C, D.chemicals[C] * mat_efficiency) + + if(D.build_path) + var/obj/new_item = D.Fabricate(src, src) + new_item.loc = loc + if(mat_efficiency != 1) // No matter out of nowhere + if(new_item.matter && new_item.matter.len > 0) + for(var/i in new_item.matter) + new_item.matter[i] = new_item.matter[i] * mat_efficiency diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm new file mode 100644 index 00000000..ffca833c --- /dev/null +++ b/code/modules/research/designs.dm @@ -0,0 +1,2036 @@ +/*************************************************************** +** Design Datums ** +** All the data for building stuff and tracking reliability. ** +***************************************************************/ +/* +For the materials datum, it assumes you need reagents unless specified otherwise. To designate a material that isn't a reagent, +you use one of the material IDs below. These are NOT ids in the usual sense (they aren't defined in the object or part of a datum), +they are simply references used as part of a "has materials?" type proc. They all start with a to denote that they aren't reagents. +The currently supporting non-reagent materials: + +Don't add new keyword/IDs if they are made from an existing one (such as rods which are made from metal). Only add raw materials. + +Design Guidlines +- When adding new designs, check rdreadme.dm to see what kind of things have already been made and where new stuff is needed. +- A single sheet of anything is 2000 units of material. Materials besides metal/glass require help from other jobs (mining for +other types of metals and chemistry for reagents). + +*/ +//Note: More then one of these can be added to a design. + +/datum/design //Datum for object designs, used in construction + var/name = null //Name of the created object. If null it will be 'guessed' from build_path if possible. + var/desc = null //Description of the created object. If null it will use group_desc and name where applicable. + var/item_name = null //An item name before it is modified by various name-modifying procs + var/id = "id" //ID of the created object for easy refernece. Alphanumeric, lower-case, no symbols. + var/list/req_tech = list() //IDs of that techs the object originated from and the minimum level requirements. + var/build_type = null //Flag as to what kind machine the design is built in. See defines. + var/list/materials = list() //List of materials. Format: "id" = amount. + var/list/chemicals = list() //List of chemicals. + var/build_path = null //The path of the object that gets created. + var/time = 10 //How many ticks it requires to build + var/category = null //Primarily used for Mech Fabricators, but can be used for anything. + var/sort_string = "ZZZZZ" //Sorting order + +/datum/design/New() + ..() + item_name = name + AssembleDesignInfo() + +//These procs are used in subtypes for assigning names and descriptions dynamically +/datum/design/proc/AssembleDesignInfo() + AssembleDesignName() + AssembleDesignDesc() + return + +/datum/design/proc/AssembleDesignName() + if(!name && build_path) //Get name from build path if posible + var/atom/movable/A = build_path + name = initial(A.name) + item_name = name + return + +/datum/design/proc/AssembleDesignDesc() + if(!desc) //Try to make up a nice description if we don't have one + desc = "Allows for the construction of \a [item_name]." + return + +//Returns a new instance of the item for this design +//This is to allow additional initialization to be performed, including possibly additional contructor arguments. +/datum/design/proc/Fabricate(var/newloc, var/fabricator) + return new build_path(newloc) + +/datum/design/item + build_type = PROTOLATHE + +/datum/design/item/disk/AssembleDesignName() + ..() + name = "Storage disk ([item_name])" + +/datum/design/item/disk/design + name = "research design" + desc = "Produce additional disks for storing device designs." + id = "design_disk" + req_tech = list(TECH_DATA = 1) + materials = list(DEFAULT_WALL_MATERIAL = 30, "glass" = 10) + build_path = /obj/item/weapon/disk/design_disk + sort_string = "AAAAA" + +/datum/design/item/disk/tech + name = "technology data" + desc = "Produce additional disks for storing technology data." + id = "tech_disk" + req_tech = list(TECH_DATA = 1) + materials = list(DEFAULT_WALL_MATERIAL = 30, "glass" = 10) + build_path = /obj/item/weapon/disk/tech_disk + sort_string = "AAAAB" + +/datum/design/item/stock_part + build_type = PROTOLATHE + +/datum/design/item/stock_part/AssembleDesignName() + ..() + name = "Component design ([item_name])" + +/datum/design/item/stock_part/AssembleDesignDesc() + if(!desc) + desc = "A stock part used in the construction of various devices." + +/datum/design/item/stock_part/basic_capacitor + id = "basic_capacitor" + req_tech = list(TECH_POWER = 1) + materials = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) + build_path = /obj/item/weapon/stock_parts/capacitor + sort_string = "CAAAA" + +/datum/design/item/stock_part/adv_capacitor + id = "adv_capacitor" + req_tech = list(TECH_POWER = 3) + materials = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) + build_path = /obj/item/weapon/stock_parts/capacitor/adv + sort_string = "CAAAB" + +/datum/design/item/stock_part/super_capacitor + id = "super_capacitor" + req_tech = list(TECH_POWER = 5, TECH_MATERIAL = 4) + materials = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, "gold" = 20) + build_path = /obj/item/weapon/stock_parts/capacitor/super + sort_string = "CAAAC" + +/datum/design/item/stock_part/micro_mani + id = "micro_mani" + req_tech = list(TECH_MATERIAL = 1, TECH_DATA = 1) + materials = list(DEFAULT_WALL_MATERIAL = 30) + build_path = /obj/item/weapon/stock_parts/manipulator + sort_string = "CAABA" + +/datum/design/item/stock_part/nano_mani + id = "nano_mani" + req_tech = list(TECH_MATERIAL = 3, TECH_DATA = 2) + materials = list(DEFAULT_WALL_MATERIAL = 30) + build_path = /obj/item/weapon/stock_parts/manipulator/nano + sort_string = "CAABB" + +/datum/design/item/stock_part/pico_mani + id = "pico_mani" + req_tech = list(TECH_MATERIAL = 5, TECH_DATA = 2) + materials = list(DEFAULT_WALL_MATERIAL = 30) + build_path = /obj/item/weapon/stock_parts/manipulator/pico + sort_string = "CAABC" + +/datum/design/item/stock_part/basic_matter_bin + id = "basic_matter_bin" + req_tech = list(TECH_MATERIAL = 1) + materials = list(DEFAULT_WALL_MATERIAL = 80) + build_path = /obj/item/weapon/stock_parts/matter_bin + sort_string = "CAACA" + +/datum/design/item/stock_part/adv_matter_bin + id = "adv_matter_bin" + req_tech = list(TECH_MATERIAL = 3) + materials = list(DEFAULT_WALL_MATERIAL = 80) + build_path = /obj/item/weapon/stock_parts/matter_bin/adv + sort_string = "CAACB" + +/datum/design/item/stock_part/super_matter_bin + id = "super_matter_bin" + req_tech = list(TECH_MATERIAL = 5) + materials = list(DEFAULT_WALL_MATERIAL = 80) + build_path = /obj/item/weapon/stock_parts/matter_bin/super + sort_string = "CAACC" + +/datum/design/item/stock_part/basic_micro_laser + id = "basic_micro_laser" + req_tech = list(TECH_MAGNET = 1) + materials = list(DEFAULT_WALL_MATERIAL = 10, "glass" = 20) + build_path = /obj/item/weapon/stock_parts/micro_laser + sort_string = "CAADA" + +/datum/design/item/stock_part/high_micro_laser + id = "high_micro_laser" + req_tech = list(TECH_MAGNET = 3) + materials = list(DEFAULT_WALL_MATERIAL = 10, "glass" = 20) + build_path = /obj/item/weapon/stock_parts/micro_laser/high + sort_string = "CAADB" + +/datum/design/item/stock_part/ultra_micro_laser + id = "ultra_micro_laser" + req_tech = list(TECH_MAGNET = 5, TECH_MATERIAL = 5) + materials = list(DEFAULT_WALL_MATERIAL = 10, "glass" = 20, "uranium" = 10) + build_path = /obj/item/weapon/stock_parts/micro_laser/ultra + sort_string = "CAADC" + +/datum/design/item/stock_part/basic_sensor + id = "basic_sensor" + req_tech = list(TECH_MAGNET = 1) + materials = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 20) + build_path = /obj/item/weapon/stock_parts/scanning_module + sort_string = "CAAEA" + +/datum/design/item/stock_part/adv_sensor + id = "adv_sensor" + req_tech = list(TECH_MAGNET = 3) + materials = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 20) + build_path = /obj/item/weapon/stock_parts/scanning_module/adv + sort_string = "CAAEB" + +/datum/design/item/stock_part/phasic_sensor + id = "phasic_sensor" + req_tech = list(TECH_MAGNET = 5, TECH_MATERIAL = 3) + materials = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 20, "silver" = 10) + build_path = /obj/item/weapon/stock_parts/scanning_module/phasic + sort_string = "CAAEC" + +/datum/design/item/stock_part/RPED + name = "Rapid Part Exchange Device" + desc = "Special mechanical module made to store, sort, and apply standard machine parts." + id = "rped" + req_tech = list(TECH_ENGINEERING = 3, TECH_MATERIAL = 3) + materials = list(DEFAULT_WALL_MATERIAL = 15000, "glass" = 5000) + build_path = /obj/item/weapon/storage/part_replacer + sort_string = "CBAAA" + +/datum/design/item/powercell + build_type = PROTOLATHE | MECHFAB + category = "Misc" + +/datum/design/item/powercell/AssembleDesignName() + name = "Power cell model ([item_name])" + +/datum/design/item/powercell/device/AssembleDesignName() + name = "Device cell model ([item_name])" + +/datum/design/item/powercell/AssembleDesignDesc() + if(build_path) + var/obj/item/weapon/cell/C = build_path + desc = "Allows the construction of power cells that can hold [initial(C.maxcharge)] units of energy." + +/datum/design/item/powercell/Fabricate() + var/obj/item/weapon/cell/C = ..() + C.charge = 0 //shouldn't produce power out of thin air. + return C + +/datum/design/item/powercell/basic + name = "basic" + id = "basic_cell" + req_tech = list(TECH_POWER = 1) + materials = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 50) + build_path = /obj/item/weapon/cell + sort_string = "DAAAA" + +/datum/design/item/powercell/high + name = "high-capacity" + id = "high_cell" + req_tech = list(TECH_POWER = 2) + materials = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 60) + build_path = /obj/item/weapon/cell/high + sort_string = "DAAAB" + +/datum/design/item/powercell/super + name = "super-capacity" + id = "super_cell" + req_tech = list(TECH_POWER = 3, TECH_MATERIAL = 2) + materials = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 70) + build_path = /obj/item/weapon/cell/super + sort_string = "DAAAC" + +/datum/design/item/powercell/hyper + name = "hyper-capacity" + id = "hyper_cell" + req_tech = list(TECH_POWER = 5, TECH_MATERIAL = 4) + materials = list(DEFAULT_WALL_MATERIAL = 400, "gold" = 150, "silver" = 150, "glass" = 70) + build_path = /obj/item/weapon/cell/hyper + sort_string = "DAAAD" + +/datum/design/item/powercell/device/standard + name = "basic" + id = "device_cell_standard" + req_tech = list(TECH_POWER = 1) + materials = list(DEFAULT_WALL_MATERIAL = 70, "glass" = 5) + build_path = /obj/item/weapon/cell/device/standard + sort_string = "DAAAE" + +/datum/design/item/powercell/device/high + name = "high-capacity" + build_type = PROTOLATHE | MECHFAB + id = "device_cell_high" + req_tech = list(TECH_POWER = 2) + materials = list(DEFAULT_WALL_MATERIAL = 70, "glass" = 6) + build_path = /obj/item/weapon/cell/device/high + sort_string = "DAAAF" + +/datum/design/item/hud + materials = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) + +/datum/design/item/hud/AssembleDesignName() + ..() + name = "HUD glasses design ([item_name])" + +/datum/design/item/hud/AssembleDesignDesc() + desc = "Allows for the construction of \a [item_name] HUD glasses." + +/datum/design/item/hud/health + name = "health scanner" + id = "health_hud" + req_tech = list(TECH_BIO = 2, TECH_MAGNET = 3) + build_path = /obj/item/clothing/glasses/hud/health + sort_string = "GAAAA" + +/datum/design/item/hud/security + name = "security records" + id = "security_hud" + req_tech = list(TECH_MAGNET = 3, TECH_COMBAT = 2) + build_path = /obj/item/clothing/glasses/hud/security + sort_string = "GAAAB" + +/datum/design/item/optical/AssembleDesignName() + ..() + name = "Optical glasses design ([item_name])" + +/datum/design/item/optical/mesons + name = "mesons" + desc = "Using the meson-scanning technology those glasses allow you to see through walls, floor or anything else." + id = "mesons" + req_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 2) + materials = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) + build_path = /obj/item/clothing/glasses/meson + sort_string = "GBAAA" + +/datum/design/item/optical/material + name = "material" + id = "mesons_material" + req_tech = list(TECH_MAGNET = 3, TECH_ENGINEERING = 3) + materials = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) + build_path = /obj/item/clothing/glasses/material + sort_string = "GAAAB" + +/datum/design/item/optical/tactical + name = "tactical" + id = "tactical_goggles" + req_tech = list(TECH_MAGNET = 3, TECH_COMBAT = 5) + materials = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, "silver" = 50, "gold" = 50) + build_path = /obj/item/clothing/glasses/tacgoggles + sort_string = "GAAAC" + +/datum/design/item/mining/AssembleDesignName() + ..() + name = "Mining equipment design ([item_name])" + +/datum/design/item/mining/jackhammer + id = "jackhammer" + req_tech = list(TECH_MATERIAL = 3, TECH_POWER = 2, TECH_ENGINEERING = 2) + materials = list(DEFAULT_WALL_MATERIAL = 2000, "glass" = 500, "silver" = 500) + build_path = /obj/item/weapon/pickaxe/jackhammer + sort_string = "KAAAA" + +/datum/design/item/mining/drill + id = "drill" + req_tech = list(TECH_MATERIAL = 2, TECH_POWER = 3, TECH_ENGINEERING = 2) + materials = list(DEFAULT_WALL_MATERIAL = 6000, "glass" = 1000) //expensive, but no need for miners. + build_path = /obj/item/weapon/pickaxe/drill + sort_string = "KAAAB" + +/datum/design/item/mining/plasmacutter + id = "plasmacutter" + req_tech = list(TECH_MATERIAL = 4, TECH_PHORON = 3, TECH_ENGINEERING = 3) + materials = list(DEFAULT_WALL_MATERIAL = 1500, "glass" = 500, "gold" = 500, "phoron" = 500) + build_path = /obj/item/weapon/gun/energy/plasmacutter + sort_string = "KAAAC" + +/datum/design/item/mining/pick_diamond + id = "pick_diamond" + req_tech = list(TECH_MATERIAL = 6) + materials = list("diamond" = 3000) + build_path = /obj/item/weapon/pickaxe/diamond + sort_string = "KAAAD" + +/datum/design/item/mining/drill_diamond + id = "drill_diamond" + req_tech = list(TECH_MATERIAL = 6, TECH_POWER = 4, TECH_ENGINEERING = 4) + materials = list(DEFAULT_WALL_MATERIAL = 3000, "glass" = 1000, "diamond" = 2000) + build_path = /obj/item/weapon/pickaxe/diamonddrill + sort_string = "KAAAE" + +/datum/design/item/mining/depth_scanner + desc = "Used to check spatial depth and density of rock outcroppings." + id = "depth_scanner" + req_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 2, TECH_BLUESPACE = 2) + materials = list(DEFAULT_WALL_MATERIAL = 1000,"glass" = 1000) + build_path = /obj/item/device/depth_scanner + sort_string = "KAAAF" + +/datum/design/item/medical + materials = list(DEFAULT_WALL_MATERIAL = 30, "glass" = 20) + +/datum/design/item/medical/AssembleDesignName() + ..() + name = "Biotech device prototype ([item_name])" + +/datum/design/item/medical/slime_scanner + desc = "Multipurpose organic life scanner." + id = "slime_scanner" + req_tech = list(TECH_MAGNET = 2, TECH_BIO = 2) + materials = list(DEFAULT_WALL_MATERIAL = 200, "glass" = 100) + build_path = /obj/item/device/slime_scanner + sort_string = "MACFA" + +/datum/design/item/medical/robot_scanner + desc = "A hand-held scanner able to diagnose robotic injuries." + id = "robot_scanner" + req_tech = list(TECH_MAGNET = 3, TECH_BIO = 2, TECH_ENGINEERING = 3) + materials = list(DEFAULT_WALL_MATERIAL = 500, "glass" = 200) + build_path = /obj/item/device/robotanalyzer + sort_string = "MACFB" + +/datum/design/item/medical/mass_spectrometer + desc = "A device for analyzing chemicals in blood." + id = "mass_spectrometer" + req_tech = list(TECH_BIO = 2, TECH_MAGNET = 2) + build_path = /obj/item/device/mass_spectrometer + sort_string = "MACAA" + +/datum/design/item/medical/adv_mass_spectrometer + desc = "A device for analyzing chemicals in blood and their quantities." + id = "adv_mass_spectrometer" + req_tech = list(TECH_BIO = 2, TECH_MAGNET = 4) + build_path = /obj/item/device/mass_spectrometer/adv + sort_string = "MACAB" + +/datum/design/item/medical/reagent_scanner + desc = "A device for identifying chemicals." + id = "reagent_scanner" + req_tech = list(TECH_BIO = 2, TECH_MAGNET = 2) + build_path = /obj/item/device/reagent_scanner + sort_string = "MACBA" + +/datum/design/item/medical/adv_reagent_scanner + desc = "A device for identifying chemicals and their proportions." + id = "adv_reagent_scanner" + req_tech = list(TECH_BIO = 2, TECH_MAGNET = 4) + build_path = /obj/item/device/reagent_scanner/adv + sort_string = "MACBB" + +/datum/design/item/medical/nanopaste + desc = "A tube of paste containing swarms of repair nanites. Very effective in repairing robotic machinery." + id = "nanopaste" + req_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 3) + materials = list(DEFAULT_WALL_MATERIAL = 7000, "glass" = 7000) + build_path = /obj/item/stack/nanopaste + sort_string = "MADAA" + +/datum/design/item/medical/hypospray + desc = "A sterile, air-needle autoinjector for rapid administration of drugs" + id = "hypospray" + req_tech = list(TECH_MATERIAL = 4, TECH_BIO = 5) + materials = list(DEFAULT_WALL_MATERIAL = 8000, "glass" = 8000, "silver" = 2000) + build_path = /obj/item/weapon/reagent_containers/hypospray/vial + sort_string = "MAEAA" + +/datum/design/item/surgery/AssembleDesignName() + ..() + name = "Surgical tool design ([item_name])" + +/datum/design/item/surgery/scalpel_laser1 + name = "Basic Laser Scalpel" + desc = "A scalpel augmented with a directed laser, for more precise cutting without blood entering the field. This one looks basic and could be improved." + id = "scalpel_laser1" + req_tech = list(TECH_BIO = 2, TECH_MATERIAL = 2, TECH_MAGNET = 2) + materials = list(DEFAULT_WALL_MATERIAL = 12500, "glass" = 7500) + build_path = /obj/item/weapon/scalpel/laser1 + sort_string = "MBEAA" + +/datum/design/item/surgery/scalpel_laser2 + name = "Improved Laser Scalpel" + desc = "A scalpel augmented with a directed laser, for more precise cutting without blood entering the field. This one looks somewhat advanced." + id = "scalpel_laser2" + req_tech = list(TECH_BIO = 3, TECH_MATERIAL = 4, TECH_MAGNET = 4) + materials = list(DEFAULT_WALL_MATERIAL = 12500, "glass" = 7500, "silver" = 2500) + build_path = /obj/item/weapon/scalpel/laser2 + sort_string = "MBEAB" + +/datum/design/item/surgery/scalpel_laser3 + name = "Advanced Laser Scalpel" + desc = "A scalpel augmented with a directed laser, for more precise cutting without blood entering the field. This one looks to be the pinnacle of precision energy cutlery!" + id = "scalpel_laser3" + req_tech = list(TECH_BIO = 4, TECH_MATERIAL = 6, TECH_MAGNET = 5) + materials = list(DEFAULT_WALL_MATERIAL = 12500, "glass" = 7500, "silver" = 2000, "gold" = 1500) + build_path = /obj/item/weapon/scalpel/laser3 + sort_string = "MBEAC" + +/datum/design/item/surgery/scalpel_manager + name = "Incision Management System" + desc = "A true extension of the surgeon's body, this marvel instantly and completely prepares an incision allowing for the immediate commencement of therapeutic steps." + id = "scalpel_manager" + req_tech = list(TECH_BIO = 4, TECH_MATERIAL = 7, TECH_MAGNET = 5, TECH_DATA = 4) + materials = list (DEFAULT_WALL_MATERIAL = 12500, "glass" = 7500, "silver" = 1500, "gold" = 1500, "diamond" = 750) + build_path = /obj/item/weapon/scalpel/manager + sort_string = "MBEAD" + +/datum/design/item/beaker/AssembleDesignName() + name = "Beaker prototype ([item_name])" + +/datum/design/item/beaker/noreact + name = "cryostasis" + desc = "A cryostasis beaker that allows for chemical storage without reactions. Can hold up to 50 units." + id = "splitbeaker" + req_tech = list(TECH_MATERIAL = 2) + materials = list(DEFAULT_WALL_MATERIAL = 3000) + build_path = /obj/item/weapon/reagent_containers/glass/beaker/noreact + sort_string = "MCAAA" + +/datum/design/item/beaker/bluespace + name = TECH_BLUESPACE + desc = "A bluespace beaker, powered by experimental bluespace technology and Element Cuban combined with the Compound Pete. Can hold up to 300 units." + id = "bluespacebeaker" + req_tech = list(TECH_BLUESPACE = 2, TECH_MATERIAL = 6) + materials = list(DEFAULT_WALL_MATERIAL = 3000, "phoron" = 3000, "diamond" = 500) + build_path = /obj/item/weapon/reagent_containers/glass/beaker/bluespace + sort_string = "MCAAB" + +/datum/design/item/implant + materials = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) + +/datum/design/item/implant/AssembleDesignName() + ..() + name = "Implantable biocircuit design ([item_name])" + +/datum/design/item/implant/chemical + name = "chemical" + id = "implant_chem" + req_tech = list(TECH_MATERIAL = 2, TECH_BIO = 3) + build_path = /obj/item/weapon/implantcase/chem + sort_string = "MFAAA" + +/datum/design/item/implant/death_alarm + name = "death alarm" + id = "implant_death" + req_tech = list(TECH_MATERIAL = 2, TECH_BIO = 3, TECH_DATA = 2) + build_path = /obj/item/weapon/implantcase/death_alarm + sort_string = "MFAAB" + +/datum/design/item/implant/tracking + name = "tracking" + id = "implant_tracking" + req_tech = list(TECH_MATERIAL = 2, TECH_BIO = 3, TECH_BLUESPACE = 3) + build_path = /obj/item/weapon/implantcase/tracking + sort_string = "MFAAC" + +/datum/design/item/implant/imprinting + name = "imprinting" + id = "implant_imprinting" + req_tech = list(TECH_MATERIAL = 2, TECH_BIO = 3, TECH_DATA = 4) + build_path = /obj/item/weapon/implantcase/imprinting + sort_string = "MFAAD" + +/datum/design/item/implant/adrenaline + name = "adrenaline" + id = "implant_adrenaline" + req_tech = list(TECH_MATERIAL = 2, TECH_BIO = 3, TECH_ILLEGAL = 3) + build_path = /obj/item/weapon/implantcase/adrenalin + sort_string = "MFAAE" + +/datum/design/item/implant/freedom + name = "freedom" + id = "implant_free" + req_tech = list(TECH_MATERIAL = 2, TECH_BIO = 3, TECH_ILLEGAL = 3) + build_path = /obj/item/weapon/implantcase/freedom + sort_string = "MFAAF" + +/datum/design/item/implant/explosive + name = "explosive" + id = "implant_explosive" + req_tech = list(TECH_MATERIAL = 2, TECH_BIO = 3, TECH_ILLEGAL = 4) + build_path = /obj/item/weapon/implantcase/explosive + sort_string = "MFAAG" + +/datum/design/item/weapon/AssembleDesignName() + ..() + name = "Weapon prototype ([item_name])" + +/datum/design/item/weapon/AssembleDesignDesc() + if(!desc) + if(build_path) + var/obj/item/I = build_path + desc = initial(I.desc) + ..() + +/datum/design/item/weapon/chemsprayer + desc = "An advanced chem spraying device." + id = "chemsprayer" + req_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 3, TECH_BIO = 2) + materials = list(DEFAULT_WALL_MATERIAL = 5000, "glass" = 1000) + build_path = /obj/item/weapon/reagent_containers/spray/chemsprayer + sort_string = "TAAAA" + +/datum/design/item/weapon/rapidsyringe + id = "rapidsyringe" + req_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 3, TECH_ENGINEERING = 3, TECH_BIO = 2) + materials = list(DEFAULT_WALL_MATERIAL = 5000, "glass" = 1000) + build_path = /obj/item/weapon/gun/launcher/syringe/rapid + sort_string = "TAAAB" + +/datum/design/item/weapon/large_grenade + id = "large_Grenade" + req_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 2) + materials = list(DEFAULT_WALL_MATERIAL = 3000) + build_path = /obj/item/weapon/grenade/chem_grenade/large + sort_string = "TABAA" + +/datum/design/item/weapon/anti_photon + id = "anti_photon" + req_tech = list(TECH_BLUESPACE = 4, TECH_MATERIAL = 4) + materials = list(DEFAULT_WALL_MATERIAL = 3000, "glass" = 1000, "diamond" = 1000) + build_path = /obj/item/weapon/grenade/anti_photon + sort_string = "TABAB" + +/datum/design/item/weapon/advancedflash + id = "advancedflash" + req_tech = list(TECH_COMBAT = 2, TECH_MAGNET = 2) + materials = list(DEFAULT_WALL_MATERIAL = 2000, "glass" = 2000, "silver" = 500) + build_path = /obj/item/device/flash/advanced + sort_string = "TADAA" + +/datum/design/item/weapon/stunrevolver + id = "stunrevolver" + req_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 3, TECH_POWER = 2) + materials = list(DEFAULT_WALL_MATERIAL = 4000) + build_path = /obj/item/weapon/gun/energy/stunrevolver + sort_string = "TADAB" + +/datum/design/item/weapon/stunrifle + id = "stun_rifle" + req_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3, TECH_POWER = 3) + materials = list(DEFAULT_WALL_MATERIAL = 4000, "glass" = 1000, "silver" = 500) + build_path = /obj/item/weapon/gun/energy/stunrevolver/rifle + sort_string = "TADAC" + +/datum/design/item/weapon/nuclear_gun + id = "nuclear_gun" + req_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 5, TECH_POWER = 3) + materials = list(DEFAULT_WALL_MATERIAL = 5000, "glass" = 1000, "uranium" = 500) + build_path = /obj/item/weapon/gun/energy/gun/nuclear + sort_string = "TAEAA" + +/datum/design/item/weapon/lasercannon + desc = "The lasing medium of this prototype is enclosed in a tube lined with uranium-235 and subjected to high neutron flux in a nuclear reactor core." + id = "lasercannon" + req_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3, TECH_POWER = 3) + materials = list(DEFAULT_WALL_MATERIAL = 10000, "glass" = 1000, "diamond" = 2000) + build_path = /obj/item/weapon/gun/energy/lasercannon + sort_string = "TAEAB" + + +/datum/design/item/weapon/grenadelauncher + id = "grenadelauncher" + req_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 3) + materials = list(DEFAULT_WALL_MATERIAL = 5000, "glass" = 1000) + build_path = /obj/item/weapon/gun/launcher/grenade + sort_string = "TAGAA" + +/datum/design/item/weapon/pneumatic + id = "pneumatic" + req_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3) + materials = list(DEFAULT_WALL_MATERIAL = 5000, "glass" = 2000, "silver" = 500) + build_path = /obj/item/weapon/gun/launcher/pneumatic + sort_string = "TAGAB" + + +/datum/design/item/weapon/smg + id = "smg" + req_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3) + materials = list(DEFAULT_WALL_MATERIAL = 8000, "silver" = 2000, "diamond" = 1000) + build_path = /obj/item/weapon/gun/projectile/automatic + sort_string = "TAPAA" + +/datum/design/item/weapon/wt550 + id = "wt550" + req_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 2) + materials = list(DEFAULT_WALL_MATERIAL = 8000, "silver" = 3000, "diamond" = 1500) + build_path = /obj/item/weapon/gun/projectile/automatic/wt550 + sort_string = "TAPAB" + +/datum/design/item/weapon/bullpup + id = "bullpup" + req_tech = list(TECH_COMBAT = 8, TECH_MATERIAL = 3) + materials = list(DEFAULT_WALL_MATERIAL = 10000, "silver" = 5000, "diamond" = 3000) + build_path = /obj/item/weapon/gun/projectile/automatic/z8 + sort_string = "TAPAC" + +/datum/design/item/weapon/ammunition/AssembleDesignName() + ..() + name = "Ammunition prototype ([item_name])" + +/datum/design/item/weapon/ammunition/ammo_9mm + id = "ammo_9mm" + req_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3) + materials = list(DEFAULT_WALL_MATERIAL = 3750, "silver" = 100) + build_path = /obj/item/ammo_magazine/box/c9mm + sort_string = "TBAAA" + +/datum/design/item/weapon/ammunition/stunshell + desc = "A stunning shell for a shotgun." + id = "stunshell" + req_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 3) + materials = list(DEFAULT_WALL_MATERIAL = 4000) + build_path = /obj/item/ammo_casing/shotgun/stunshell + sort_string = "TBAAB" + +/datum/design/item/weapon/ammunition/ammo_emp_38 + id = "ammo_emp_38" + desc = "A .38 round with an integrated EMP charge." + materials = list(DEFAULT_WALL_MATERIAL = 2500, "uranium" = 750) + req_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 3) + build_path = /obj/item/ammo_magazine/box/emp + sort_string = "TBAAC" + +/datum/design/item/weapon/ammunition/ammo_emp_45 + id = "ammo_emp_45" + desc = "A .45 round with an integrated EMP charge." + materials = list(DEFAULT_WALL_MATERIAL = 2500, "uranium" = 750) + req_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 3) + build_path = /obj/item/ammo_magazine/box/emp/c45 + sort_string = "TBAAD" + +/datum/design/item/weapon/ammunition/ammo_emp_10 + id = "ammo_emp_10" + desc = "A .10mm round with an integrated EMP charge." + materials = list(DEFAULT_WALL_MATERIAL = 2500, "uranium" = 750) + req_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 3) + build_path = /obj/item/ammo_magazine/box/emp/a10mm + sort_string = "TBAAE" + +/datum/design/item/weapon/ammunition/ammo_emp_slug + id = "ammo_emp_slug" + desc = "A shotgun slug with an integrated EMP charge." + materials = list(DEFAULT_WALL_MATERIAL = 3000, "uranium" = 1000) + req_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3) + build_path = /obj/item/ammo_casing/shotgun/emp + sort_string = "TBAAF" + +/datum/design/item/stock_part/subspace_ansible + id = "s-ansible" + req_tech = list(TECH_DATA = 3, TECH_MAGNET = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2) + materials = list(DEFAULT_WALL_MATERIAL = 80, "silver" = 20) + build_path = /obj/item/weapon/stock_parts/subspace/ansible + sort_string = "UAAAA" + +/datum/design/item/stock_part/hyperwave_filter + id = "s-filter" + req_tech = list(TECH_DATA = 3, TECH_MAGNET = 3) + materials = list(DEFAULT_WALL_MATERIAL = 40, "silver" = 10) + build_path = /obj/item/weapon/stock_parts/subspace/filter + sort_string = "UAAAB" + +/datum/design/item/stock_part/subspace_amplifier + id = "s-amplifier" + req_tech = list(TECH_DATA = 3, TECH_MAGNET = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2) + materials = list(DEFAULT_WALL_MATERIAL = 10, "gold" = 30, "uranium" = 15) + build_path = /obj/item/weapon/stock_parts/subspace/amplifier + sort_string = "UAAAC" + +/datum/design/item/stock_part/subspace_treatment + id = "s-treatment" + req_tech = list(TECH_DATA = 3, TECH_MAGNET = 2, TECH_MATERIAL = 4, TECH_BLUESPACE = 2) + materials = list(DEFAULT_WALL_MATERIAL = 10, "silver" = 20) + build_path = /obj/item/weapon/stock_parts/subspace/treatment + sort_string = "UAAAD" + +/datum/design/item/stock_part/subspace_analyzer + id = "s-analyzer" + req_tech = list(TECH_DATA = 3, TECH_MAGNET = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2) + materials = list(DEFAULT_WALL_MATERIAL = 10, "gold" = 15) + build_path = /obj/item/weapon/stock_parts/subspace/analyzer + sort_string = "UAAAE" + +/datum/design/item/stock_part/subspace_crystal + id = "s-crystal" + req_tech = list(TECH_MAGNET = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2) + materials = list("glass" = 1000, "silver" = 20, "gold" = 20) + build_path = /obj/item/weapon/stock_parts/subspace/crystal + sort_string = "UAAAF" + +/datum/design/item/stock_part/subspace_transmitter + id = "s-transmitter" + req_tech = list(TECH_MAGNET = 5, TECH_MATERIAL = 5, TECH_BLUESPACE = 3) + materials = list("glass" = 100, "silver" = 10, "uranium" = 15) + build_path = /obj/item/weapon/stock_parts/subspace/transmitter + sort_string = "UAAAG" + +/datum/design/item/synthstorage/AssembleDesignName() + ..() + name = "Synthetic intelligence storage ([item_name])" + +/datum/design/item/synthstorage/paicard + name = "pAI" + desc = "Personal Artificial Intelligence device." + id = "paicard" + req_tech = list(TECH_DATA = 2) + materials = list("glass" = 500, DEFAULT_WALL_MATERIAL = 500) + build_path = /obj/item/device/paicard + sort_string = "VABAI" + +/datum/design/item/synthstorage/intelicard + name = "inteliCard" + desc = "AI preservation and transportation system." + id = "intelicard" + req_tech = list(TECH_DATA = 4, TECH_MATERIAL = 4) + materials = list("glass" = 1000, "gold" = 200) + build_path = /obj/item/weapon/aicard + sort_string = "VACAA" + +/datum/design/item/synthstorage/posibrain + name = "Positronic brain" + id = "posibrain" + req_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 6, TECH_BLUESPACE = 2, TECH_DATA = 4) + build_type = PROTOLATHE | MECHFAB + materials = list(DEFAULT_WALL_MATERIAL = 2000, "glass" = 1000, "silver" = 1000, "gold" = 500, "phoron" = 500, "diamond" = 100) + build_path = /obj/item/organ/internal/posibrain + category = "Misc" + sort_string = "VACAB" + +/datum/design/item/biostorage/AssembleDesignName() + ..() + name = "Biological intelligence storage ([item_name])" + +/datum/design/item/biostorage/neural_lace + id = "neural lace" + req_tech = list(TECH_BIO = 4, TECH_MATERIAL = 4, TECH_MAGNET = 2, TECH_DATA = 3) + materials = list (DEFAULT_WALL_MATERIAL = 10000, "glass" = 7500, "silver" = 1000, "gold" = 1000) + build_path = /obj/item/organ/internal/stack + sort_string = "VACBA" + +/datum/design/item/biostorage/mmi + name = "man-machine interface" + id = "mmi" + req_tech = list(TECH_DATA = 2, TECH_BIO = 3) + build_type = PROTOLATHE | MECHFAB + materials = list(DEFAULT_WALL_MATERIAL = 1000, "glass" = 500) + build_path = /obj/item/device/mmi + category = "Misc" + sort_string = "VACCA" + +/datum/design/item/biostorage/mmi_radio + name = "radio-enabled man-machine interface" + id = "mmi_radio" + req_tech = list(TECH_DATA = 2, TECH_BIO = 4) + build_type = PROTOLATHE | MECHFAB + materials = list(DEFAULT_WALL_MATERIAL = 1200, "glass" = 500) + build_path = /obj/item/device/mmi/radio_enabled + category = "Misc" + sort_string = "VACCB" + +/datum/design/item/bluespace/AssembleDesignName() + ..() + name = "Bluespace device ([item_name])" + +/datum/design/item/bluespace/beacon + name = "tracking beacon" + id = "beacon" + req_tech = list(TECH_BLUESPACE = 1) + materials = list (DEFAULT_WALL_MATERIAL = 20, "glass" = 10) + build_path = /obj/item/device/radio/beacon + sort_string = "VADAA" + +/datum/design/item/bluespace/gps + name = "triangulating device" + desc = "Triangulates approximate co-ordinates using a nearby satellite network." + id = "gps" + req_tech = list(TECH_MATERIAL = 2, TECH_DATA = 2, TECH_BLUESPACE = 2) + materials = list(DEFAULT_WALL_MATERIAL = 500) + build_path = /obj/item/device/gps + sort_string = "VADAB" + +/datum/design/item/bluespace/beacon_locator + name = "beacon tracking pinpointer" + desc = "Used to scan and locate signals on a particular frequency." + id = "beacon_locator" + req_tech = list(TECH_MAGNET = 3, TECH_ENGINEERING = 2, TECH_BLUESPACE = 3) + materials = list(DEFAULT_WALL_MATERIAL = 1000,"glass" = 500) + build_path = /obj/item/weapon/pinpointer/radio + sort_string = "VADAC" + +/datum/design/item/bluespace/ano_scanner + name = "Alden-Saraspova counter" + id = "ano_scanner" + desc = "Aids in triangulation of exotic particles." + req_tech = list(TECH_BLUESPACE = 3, TECH_MAGNET = 3) + materials = list(DEFAULT_WALL_MATERIAL = 10000,"glass" = 5000) + build_path = /obj/item/device/ano_scanner + sort_string = "VAEAA" + +/datum/design/item/bluespace/bag_holding + name = "Bag of Holding" + desc = "Using localized pockets of bluespace this bag prototype offers incredible storage capacity with the contents weighting nothing. It's a shame the bag itself is pretty heavy." + id = "bag_holding" + req_tech = list(TECH_BLUESPACE = 4, TECH_MATERIAL = 6) + materials = list("gold" = 3000, "diamond" = 1500, "uranium" = 250) + build_path = /obj/item/weapon/storage/backpack/holding + sort_string = "VAFAA" + +// tools + +/datum/design/item/tool/AssembleDesignName() + ..() + name = "Tool design ([item_name])" + +/datum/design/item/tool/light_replacer + name = "light replacer" + desc = "A device to automatically replace lights. Refill with working lightbulbs." + id = "light_replacer" + req_tech = list(TECH_MAGNET = 3, TECH_MATERIAL = 4) + materials = list(DEFAULT_WALL_MATERIAL = 1500, "silver" = 150, "glass" = 3000) + build_path = /obj/item/device/lightreplacer + sort_string = "VAGAB" + +/datum/design/item/tool/airlock_brace + name = "airlock brace" + desc = "Special door attachment that can be used to provide extra security." + id = "brace" + req_tech = list(TECH_ENGINEERING = 3, TECH_MATERIAL = 2) + materials = list(DEFAULT_WALL_MATERIAL = 2000, "glass" = 50) + build_path = /obj/item/weapon/airlock_brace + sort_string = "VAGAC" + +/datum/design/item/tool/brace_jack + name = "maintenance jack" + desc = "A special maintenance tool that can be used to remove airlock braces." + id = "bracejack" + req_tech = list(TECH_ENGINEERING = 3, TECH_MATERIAL = 2) + materials = list(DEFAULT_WALL_MATERIAL = 120) + build_path = /obj/item/weapon/crowbar/brace_jack + sort_string = "VAGAD" + +/datum/design/item/tool/clamp + name = "stasis clamp" + desc = "A magnetic clamp which can halt the flow of gas in a pipe, via a localised stasis field." + id = "stasis_clamp" + req_tech = list(TECH_ENGINEERING = 4, TECH_MAGNET = 4) + materials = list(DEFAULT_WALL_MATERIAL = 500, "glass" = 500) + build_path = /obj/item/clamp + sort_string = "VAGAE" + +/datum/design/item/tool/price_scanner + name = "price scanner" + desc = "Using an up-to-date database of various costs and prices, this device estimates the market price of an item up to 0.001% accuracy." + id = "price_scanner" + req_tech = list(TECH_MATERIAL = 6, TECH_MAGNET = 4) + materials = list(DEFAULT_WALL_MATERIAL = 3000, "glass" = 3000, "silver" = 250) + build_path = /obj/item/device/price_scanner + sort_string = "VAGAF" + +/datum/design/item/tool/experimental_welder + name = "experimental welding tool" + desc = "This welding tool feels heavier in your possession than is normal. There appears to be no external fuel port." + id = "experimental_welder" + req_tech = list(TECH_ENGINEERING = 5, TECH_PHORON = 4) + materials = list(DEFAULT_WALL_MATERIAL = 120, "glass" = 50) + build_path = /obj/item/weapon/weldingtool/experimental + sort_string = "VAGAG" + +/datum/design/item/tool/shield_diffuser + name = "portable shield diffuser" + desc = "A small handheld device designed to disrupt energy barriers." + id = "portable_shield_diffuser" + req_tech = list(TECH_MAGNET = 5, TECH_POWER = 5, TECH_ILLEGAL = 2) + materials = list(DEFAULT_WALL_MATERIAL = 5000, "glass" = 5000, "gold" = 2000, "silver" = 2000) + build_path = /obj/item/weapon/shield_diffuser + sort_string = "VAGAH" + +/datum/design/item/encryptionkey/AssembleDesignName() + ..() + name = "Encryption key design ([item_name])" + +/datum/design/item/encryptionkey/binary + name = "binary" + desc = "Allows for deciphering the binary channel on-the-fly." + id = "binaryencrypt" + req_tech = list(TECH_ILLEGAL = 2) + materials = list(DEFAULT_WALL_MATERIAL = 300, "glass" = 300) + build_path = /obj/item/device/encryptionkey/binary + sort_string = "VASAA" + +/datum/design/item/camouflage/AssembleDesignName() + ..() + name = "Camouflage design ([item_name])" + +/datum/design/item/camouflage/chameleon + name = "holographic equipment kit" + desc = "A kit of dangerous, high-tech equipment with changeable looks." + id = "chameleon" + req_tech = list(TECH_ILLEGAL = 2) + materials = list(DEFAULT_WALL_MATERIAL = 500) + build_path = /obj/item/weapon/storage/backpack/chameleon/sydie_kit + sort_string = "VASBA" + +// Superconductive magnetic coils +/datum/design/item/smes_coil/AssembleDesignName() + ..() + name = "Superconductive magnetic coil ([item_name])" + +/datum/design/item/smes_coil + desc = "A superconductive magnetic coil used to store power in magnetic fields." + materials = list(DEFAULT_WALL_MATERIAL = 2000, "glass" = 2000, "gold" = 1000, "silver" = 1000) + +/datum/design/item/smes_coil/standard + name = "standard" + id = "smes_coil_standard" + req_tech = list(TECH_MATERIAL = 7, TECH_POWER = 7, TECH_ENGINEERING = 5) + build_path = /obj/item/weapon/smes_coil + sort_string = "VAXAA" + +/datum/design/item/smes_coil/super_capacity + name = "capacitance" + id = "smes_coil_super_capacity" + req_tech = list(TECH_MATERIAL = 7, TECH_POWER = 8, TECH_ENGINEERING = 6) + build_path = /obj/item/weapon/smes_coil/super_capacity + sort_string = "VAXAB" + +/datum/design/item/smes_coil/super_io + name = "transmission" + id = "smes_coil_super_io" + req_tech = list(TECH_MATERIAL = 7, TECH_POWER = 8, TECH_ENGINEERING = 6) + build_path = /obj/item/weapon/smes_coil/super_io + sort_string = "VAXAC" + + +// Modular computer components +// Hard drives +/datum/design/item/modularcomponent/disk/AssembleDesignName() + ..() + name = "Hard drive design ([item_name])" + +/datum/design/item/modularcomponent/disk/normal + name = "basic hard drive" + id = "hdd_basic" + req_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1) + build_type = PROTOLATHE + materials = list(DEFAULT_WALL_MATERIAL = 400, "glass" = 100) + build_path = /obj/item/weapon/computer_hardware/hard_drive/ + sort_string = "VBAAA" + +/datum/design/item/modularcomponent/disk/advanced + name = "advanced hard drive" + id = "hdd_advanced" + req_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + build_type = PROTOLATHE + materials = list(DEFAULT_WALL_MATERIAL = 800, "glass" = 200) + build_path = /obj/item/weapon/computer_hardware/hard_drive/advanced + sort_string = "VBAAB" + +/datum/design/item/modularcomponent/disk/super + name = "super hard drive" + id = "hdd_super" + req_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 3) + build_type = PROTOLATHE + materials = list(DEFAULT_WALL_MATERIAL = 1600, "glass" = 400) + build_path = /obj/item/weapon/computer_hardware/hard_drive/super + sort_string = "VBAAC" + +/datum/design/item/modularcomponent/disk/cluster + name = "cluster hard drive" + id = "hdd_cluster" + req_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4) + build_type = PROTOLATHE + materials = list(DEFAULT_WALL_MATERIAL = 3200, "glass" = 800) + build_path = /obj/item/weapon/computer_hardware/hard_drive/cluster + sort_string = "VBAAD" + +/datum/design/item/modularcomponent/disk/micro + name = "micro hard drive" + id = "hdd_micro" + req_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1) + build_type = PROTOLATHE + materials = list(DEFAULT_WALL_MATERIAL = 400, "glass" = 100) + build_path = /obj/item/weapon/computer_hardware/hard_drive/micro + sort_string = "VBAAE" + +/datum/design/item/modularcomponent/disk/small + name = "small hard drive" + id = "hdd_small" + req_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + build_type = PROTOLATHE + materials = list(DEFAULT_WALL_MATERIAL = 800, "glass" = 200) + build_path = /obj/item/weapon/computer_hardware/hard_drive/small + sort_string = "VBAAF" + +// Network cards +/datum/design/item/modularcomponent/netcard/AssembleDesignName() + ..() + name = "Network card design ([item_name])" + +/datum/design/item/modularcomponent/netcard/basic + name = "basic network card" + id = "netcard_basic" + req_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1) + build_type = IMPRINTER + materials = list(DEFAULT_WALL_MATERIAL = 250, "glass" = 100) + chemicals = list(/datum/reagent/acid = 20) + build_path = /obj/item/weapon/computer_hardware/network_card + sort_string = "VBABA" + +/datum/design/item/modularcomponent/netcard/advanced + name = "advanced network card" + id = "netcard_advanced" + req_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 2) + build_type = IMPRINTER + materials = list(DEFAULT_WALL_MATERIAL = 500, "glass" = 200) + chemicals = list(/datum/reagent/acid = 20) + build_path = /obj/item/weapon/computer_hardware/network_card/advanced + sort_string = "VBABB" + +/datum/design/item/modularcomponent/netcard/wired + name = "wired network card" + id = "netcard_wired" + req_tech = list(TECH_DATA = 5, TECH_ENGINEERING = 3) + build_type = IMPRINTER + materials = list(DEFAULT_WALL_MATERIAL = 2500, "glass" = 400) + chemicals = list(/datum/reagent/acid = 20) + build_path = /obj/item/weapon/computer_hardware/network_card/wired + sort_string = "VBABC" + +// Data crystals (USB flash drives) +/datum/design/item/modularcomponent/portabledrive/AssembleDesignName() + ..() + name = "Portable drive design ([item_name])" + +/datum/design/item/modularcomponent/portabledrive/basic + name = "basic data crystal" + id = "portadrive_basic" + req_tech = list(TECH_DATA = 1) + build_type = IMPRINTER + materials = list("glass" = 800) + chemicals = list(/datum/reagent/acid = 20) + build_path = /obj/item/weapon/computer_hardware/hard_drive/portable + sort_string = "VBACA" + +/datum/design/item/modularcomponent/portabledrive/advanced + name = "advanced data crystal" + id = "portadrive_advanced" + req_tech = list(TECH_DATA = 2) + build_type = IMPRINTER + materials = list("glass" = 1600) + chemicals = list(/datum/reagent/acid = 20) + build_path = /obj/item/weapon/computer_hardware/hard_drive/portable/advanced + sort_string = "VBACB" + +/datum/design/item/modularcomponent/portabledrive/super + name = "super data crystal" + id = "portadrive_super" + req_tech = list(TECH_DATA = 4) + build_type = IMPRINTER + materials = list("glass" = 3200) + chemicals = list(/datum/reagent/acid = 20) + build_path = /obj/item/weapon/computer_hardware/hard_drive/portable/super + sort_string = "VBACC" + +// Card slot +/datum/design/item/modularcomponent/accessory/AssembleDesignName() + ..() + name = "Computer accessory ([item_name])" + +/datum/design/item/modularcomponent/accessory/cardslot + name = "RFID card slot" + id = "cardslot" + req_tech = list(TECH_DATA = 2) + build_type = PROTOLATHE + materials = list(DEFAULT_WALL_MATERIAL = 600) + build_path = /obj/item/weapon/computer_hardware/card_slot + sort_string = "VBADA" + +// inteliCard Slot +/datum/design/item/modularcomponent/accessory/aislot + name = "inteliCard slot" + id = "aislot" + req_tech = list(TECH_POWER = 2, TECH_DATA = 3) + build_type = IMPRINTER + materials = list(DEFAULT_WALL_MATERIAL = 2000) + chemicals = list(/datum/reagent/acid = 20) + build_path = /obj/item/weapon/computer_hardware/ai_slot + sort_string = "VBADB" + +// Nano printer +/datum/design/item/modularcomponent/accessory/nanoprinter + name = "nano printer" + id = "nanoprinter" + req_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + build_type = PROTOLATHE + materials = list(DEFAULT_WALL_MATERIAL = 600) + build_path = /obj/item/weapon/computer_hardware/nano_printer + sort_string = "VBADC" + +// Tesla Link +/datum/design/item/modularcomponent/accessory/teslalink + name = "tesla link" + id = "teslalink" + req_tech = list(TECH_DATA = 2, TECH_POWER = 3, TECH_ENGINEERING = 2) + build_type = PROTOLATHE + materials = list(DEFAULT_WALL_MATERIAL = 2000) + build_path = /obj/item/weapon/computer_hardware/tesla_link + sort_string = "VBADD" + +// Batteries +/datum/design/item/modularcomponent/battery/AssembleDesignName() + ..() + name = "Battery design ([item_name])" + +/datum/design/item/modularcomponent/battery/normal + name = "standard battery module" + id = "bat_normal" + req_tech = list(TECH_POWER = 1, TECH_ENGINEERING = 1) + build_type = PROTOLATHE + materials = list(DEFAULT_WALL_MATERIAL = 400) + build_path = /obj/item/weapon/computer_hardware/battery_module + sort_string = "VBAEA" + +/datum/design/item/modularcomponent/battery/advanced + name = "advanced battery module" + id = "bat_advanced" + req_tech = list(TECH_POWER = 2, TECH_ENGINEERING = 2) + build_type = PROTOLATHE + materials = list(DEFAULT_WALL_MATERIAL = 800) + build_path = /obj/item/weapon/computer_hardware/battery_module/advanced + sort_string = "VBAEB" + +/datum/design/item/modularcomponent/battery/super + name = "super battery module" + id = "bat_super" + req_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 3) + build_type = PROTOLATHE + materials = list(DEFAULT_WALL_MATERIAL = 1600) + build_path = /obj/item/weapon/computer_hardware/battery_module/super + sort_string = "VBAEC" + +/datum/design/item/modularcomponent/battery/ultra + name = "ultra battery module" + id = "bat_ultra" + req_tech = list(TECH_POWER = 5, TECH_ENGINEERING = 4) + build_type = PROTOLATHE + materials = list(DEFAULT_WALL_MATERIAL = 3200) + build_path = /obj/item/weapon/computer_hardware/battery_module/ultra + sort_string = "VBAED" + +/datum/design/item/modularcomponent/battery/nano + name = "nano battery module" + id = "bat_nano" + req_tech = list(TECH_POWER = 1, TECH_ENGINEERING = 1) + build_type = PROTOLATHE + materials = list(DEFAULT_WALL_MATERIAL = 200) + build_path = /obj/item/weapon/computer_hardware/battery_module/nano + sort_string = "VBAEE" + +/datum/design/item/modularcomponent/battery/micro + name = "micro battery module" + id = "bat_micro" + req_tech = list(TECH_POWER = 2, TECH_ENGINEERING = 2) + build_type = PROTOLATHE + materials = list(DEFAULT_WALL_MATERIAL = 400) + build_path = /obj/item/weapon/computer_hardware/battery_module/micro + sort_string = "VBAEF" + +// Processor unit +/datum/design/item/modularcomponent/cpu/AssembleDesignName() + ..() + name = "CPU design ([item_name])" + +/datum/design/item/modularcomponent/cpu/ + name = "computer processor unit" + id = "cpu_normal" + req_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 2) + build_type = IMPRINTER + materials = list(DEFAULT_WALL_MATERIAL = 1600) + chemicals = list(/datum/reagent/acid = 20) + build_path = /obj/item/weapon/computer_hardware/processor_unit + sort_string = "VBAFA" + +/datum/design/item/modularcomponent/cpu/small + name = "computer microprocessor unit" + id = "cpu_small" + req_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + build_type = IMPRINTER + materials = list(DEFAULT_WALL_MATERIAL = 800) + chemicals = list(/datum/reagent/acid = 20) + build_path = /obj/item/weapon/computer_hardware/processor_unit/small + sort_string = "VBAFB" + +/datum/design/item/modularcomponent/cpu/photonic + name = "computer photonic processor unit" + id = "pcpu_normal" + req_tech = list(TECH_DATA = 5, TECH_ENGINEERING = 4) + build_type = IMPRINTER + materials = list(DEFAULT_WALL_MATERIAL = 6400, glass = 2000) + chemicals = list(/datum/reagent/acid = 40) + build_path = /obj/item/weapon/computer_hardware/processor_unit/photonic + sort_string = "VBAFC" + +/datum/design/item/modularcomponent/cpu/photonic/small + name = "computer photonic microprocessor unit" + id = "pcpu_small" + req_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 3) + build_type = IMPRINTER + materials = list(DEFAULT_WALL_MATERIAL = 3200, glass = 1000) + chemicals = list(/datum/reagent/acid = 20) + build_path = /obj/item/weapon/computer_hardware/processor_unit/photonic/small + sort_string = "VBAFD" + +// PDA and cartridges +/datum/design/item/pda + name = "PDA design" + desc = "Cheaper than whiny non-digital assistants." + id = "pda" + req_tech = list(TECH_ENGINEERING = 2, TECH_POWER = 3) + materials = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) + build_path = /obj/item/device/pda + sort_string = "VCAAA" + +/datum/design/item/pda_cartridge + req_tech = list(TECH_ENGINEERING = 2, TECH_POWER = 3) + materials = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) + +/datum/design/item/pda_cartridge/AssembleDesignName() + ..() + name = "PDA accessory ([item_name])" + +/datum/design/item/pda_cartridge/cart_basic + id = "cart_basic" + build_path = /obj/item/weapon/cartridge + sort_string = "VCBAA" + +/datum/design/item/pda_cartridge/engineering + id = "cart_engineering" + build_path = /obj/item/weapon/cartridge/engineering + sort_string = "VCBAB" + +/datum/design/item/pda_cartridge/atmos + id = "cart_atmos" + build_path = /obj/item/weapon/cartridge/atmos + sort_string = "VCBAC" + +/datum/design/item/pda_cartridge/medical + id = "cart_medical" + build_path = /obj/item/weapon/cartridge/medical + sort_string = "VCBAD" + +/datum/design/item/pda_cartridge/chemistry + id = "cart_chemistry" + build_path = /obj/item/weapon/cartridge/chemistry + sort_string = "VCBAE" + +/datum/design/item/pda_cartridge/security + id = "cart_security" + build_path = /obj/item/weapon/cartridge/security + sort_string = "VCBAF" + +/datum/design/item/pda_cartridge/janitor + id = "cart_janitor" + build_path = /obj/item/weapon/cartridge/janitor + sort_string = "VCBAG" + +/datum/design/item/pda_cartridge/science + id = "cart_science" + build_path = /obj/item/weapon/cartridge/signal/science + sort_string = "VCBAH" + +/datum/design/item/pda_cartridge/quartermaster + id = "cart_quartermaster" + build_path = /obj/item/weapon/cartridge/quartermaster + sort_string = "VCBAI" + +/datum/design/item/pda_cartridge/hop + id = "cart_hop" + build_path = /obj/item/weapon/cartridge/hop + sort_string = "VCBAJ" + +/datum/design/item/pda_cartridge/hos + id = "cart_hos" + build_path = /obj/item/weapon/cartridge/hos + sort_string = "VCBAK" + +/datum/design/item/pda_cartridge/ce + id = "cart_ce" + build_path = /obj/item/weapon/cartridge/ce + sort_string = "VCBAL" + +/datum/design/item/pda_cartridge/cmo + id = "cart_cmo" + build_path = /obj/item/weapon/cartridge/cmo + sort_string = "VCBAM" + +/datum/design/item/pda_cartridge/rd + id = "cart_rd" + build_path = /obj/item/weapon/cartridge/rd + sort_string = "VCBAN" + +/datum/design/item/pda_cartridge/captain + id = "cart_captain" + build_path = /obj/item/weapon/cartridge/captain + sort_string = "VCBAO" + +/datum/design/prefab + name = "Device" + desc = "A blueprint made from a design built here." + materials = list(DEFAULT_WALL_MATERIAL = 200) + id = "prefab" + build_type = PROTOLATHE + sort_string = "ZAAAA" + var/decl/prefab/ic_assembly/fabrication + var/global/count = 0 + +/datum/design/prefab/New(var/research, var/fab) + if(fab) + fabrication = fab + materials = list(DEFAULT_WALL_MATERIAL = fabrication.metal_amount) + build_path = /obj/item/device/electronic_assembly //put this here so that the default made one doesn't show up in protolathe list + id = "prefab[++count]" + sort_string = "Z" + var/cur_count = count + while(cur_count > 25) + sort_string += ascii2text(cur_count%25+65) + cur_count = (cur_count - cur_count%25)/25 + sort_string += ascii2text(cur_count + 65) + while(length(sort_string) < 5) + sort_string += "A" + ..() + +/datum/design/prefab/AssembleDesignName() + ..() + if(fabrication) + name = "Device ([fabrication.assembly_name])" + +/datum/design/prefab/Fabricate(var/newloc) + if(!fabrication) + return + var/obj/O = fabrication.create(newloc) + for(var/obj/item/integrated_circuit/circ in O.contents) + circ.removable = 0 + return O + +/* +CIRCUITS BELOW +*/ + +/datum/design/circuit + build_type = IMPRINTER + req_tech = list(TECH_DATA = 2) + materials = list("glass" = 2000) + chemicals = list(/datum/reagent/acid = 20) + time = 5 + +/datum/design/circuit/AssembleDesignName() + ..() + if(build_path) + var/obj/item/weapon/circuitboard/C = build_path + if(initial(C.board_type) == "machine") + name = "Machine circuit design ([item_name])" + else if(initial(C.board_type) == "computer") + name = "Computer circuit design ([item_name])" + else + name = "Circuit design ([item_name])" + +/datum/design/circuit/AssembleDesignDesc() + if(!desc) + desc = "Allows for the construction of \a [item_name] circuit board." + +/datum/design/circuit/arcademachine + name = "battle arcade machine" + id = "arcademachine" + req_tech = list(TECH_DATA = 1) + build_path = /obj/item/weapon/circuitboard/arcade/battle + sort_string = "MAAAA" + +/datum/design/circuit/oriontrail + name = "orion trail arcade machine" + id = "oriontrail" + req_tech = list(TECH_DATA = 1) + build_path = /obj/item/weapon/circuitboard/arcade/orion_trail + sort_string = "MABAA" + +/datum/design/circuit/prisonmanage + name = "prisoner management console" + id = "prisonmanage" + build_path = /obj/item/weapon/circuitboard/prisoner + sort_string = "DACAA" + +/datum/design/circuit/operating + name = "patient monitoring console" + id = "operating" + build_path = /obj/item/weapon/circuitboard/operating + sort_string = "FACAA" + +/datum/design/circuit/resleever + name = "neural lace resleever" + id = "resleever" + req_tech = list(TECH_DATA = 3, TECH_BIO = 3) + build_path = /obj/item/weapon/circuitboard/resleever + sort_string = "FAGAH" + +/datum/design/circuit/crewconsole + name = "crew monitoring console" + id = "crewconsole" + req_tech = list(TECH_DATA = 3, TECH_MAGNET = 2, TECH_BIO = 2) + build_path = /obj/item/weapon/circuitboard/crew + sort_string = "FAGAI" + +/datum/design/circuit/bioprinter + name = "bioprinter" + id = "bioprinter" + req_tech = list(TECH_ENGINEERING = 1, TECH_BIO = 3, TECH_DATA = 3) + build_path = /obj/item/weapon/circuitboard/bioprinter + sort_string = "FAGAK" + +/datum/design/circuit/roboprinter + name = "prosthetic organ fabricator" + id = "roboprinter" + req_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 3) + build_path = /obj/item/weapon/circuitboard/roboprinter + sort_string = "FAGAM" + +/datum/design/circuit/teleconsole + name = "teleporter control console" + id = "teleconsole" + req_tech = list(TECH_DATA = 3, TECH_BLUESPACE = 2) + build_path = /obj/item/weapon/circuitboard/teleporter + sort_string = "HAAAA" + +/datum/design/circuit/robocontrol + name = "robotics control console" + id = "robocontrol" + req_tech = list(TECH_DATA = 4) + build_path = /obj/item/weapon/circuitboard/robotics + sort_string = "HAAAB" + +/datum/design/circuit/mechacontrol + name = "exosuit control console" + id = "mechacontrol" + req_tech = list(TECH_DATA = 3) + build_path = /obj/item/weapon/circuitboard/mecha_control + sort_string = "HAAAC" + +/datum/design/circuit/rdconsole + name = "R&D control console" + id = "rdconsole" + req_tech = list(TECH_DATA = 4) + build_path = /obj/item/weapon/circuitboard/rdconsole + sort_string = "HAAAE" + +/datum/design/circuit/comm_monitor + name = "telecommunications monitoring console" + id = "comm_monitor" + req_tech = list(TECH_DATA = 3) + build_path = /obj/item/weapon/circuitboard/comm_monitor + sort_string = "HAACA" + +/datum/design/circuit/comm_server + name = "telecommunications server monitoring console" + id = "comm_server" + req_tech = list(TECH_DATA = 3) + build_path = /obj/item/weapon/circuitboard/comm_server + sort_string = "HAACB" + +/datum/design/circuit/comm_traffic + name = "telecommunications traffic control console" + id = "comm_traffic" + req_tech = list(TECH_DATA = 6) + build_path = /obj/item/weapon/circuitboard/comm_traffic + sort_string = "HAACC" + +/datum/design/circuit/message_monitor + name = "messaging monitor console" + id = "message_monitor" + req_tech = list(TECH_DATA = 5) + build_path = /obj/item/weapon/circuitboard/message_monitor + sort_string = "HAACD" + +/datum/design/circuit/aiupload + name = "AI upload console" + id = "aiupload" + req_tech = list(TECH_DATA = 4) + build_path = /obj/item/weapon/circuitboard/aiupload + sort_string = "HAABA" + +/datum/design/circuit/borgupload + name = "cyborg upload console" + id = "borgupload" + req_tech = list(TECH_DATA = 4) + build_path = /obj/item/weapon/circuitboard/borgupload + sort_string = "HAABB" + +/datum/design/circuit/destructive_analyzer + name = "destructive analyzer" + id = "destructive_analyzer" + req_tech = list(TECH_DATA = 2, TECH_MAGNET = 2, TECH_ENGINEERING = 2) + build_path = /obj/item/weapon/circuitboard/destructive_analyzer + sort_string = "HABAA" + +/datum/design/circuit/protolathe + name = "protolathe" + id = "protolathe" + req_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + build_path = /obj/item/weapon/circuitboard/protolathe + sort_string = "HABAB" + +/datum/design/circuit/circuit_imprinter + name = "circuit imprinter" + id = "circuit_imprinter" + req_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + build_path = /obj/item/weapon/circuitboard/circuit_imprinter + sort_string = "HABAC" + +/datum/design/circuit/autolathe + name = "autolathe board" + id = "autolathe" + req_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + build_path = /obj/item/weapon/circuitboard/autolathe + sort_string = "HABAD" + +/datum/design/circuit/rdservercontrol + name = "R&D server control console" + id = "rdservercontrol" + req_tech = list(TECH_DATA = 3) + build_path = /obj/item/weapon/circuitboard/rdservercontrol + sort_string = "HABBA" + +/datum/design/circuit/rdserver + name = "R&D server" + id = "rdserver" + req_tech = list(TECH_DATA = 3) + build_path = /obj/item/weapon/circuitboard/rdserver + sort_string = "HABBB" + +/datum/design/circuit/mechfab + name = "exosuit fabricator" + id = "mechfab" + req_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 3) + build_path = /obj/item/weapon/circuitboard/mechfab + sort_string = "HABAE" + +/datum/design/circuit/mech_recharger + name = "mech recharger" + id = "mech_recharger" + req_tech = list(TECH_DATA = 2, TECH_POWER = 2, TECH_ENGINEERING = 2) + build_path = /obj/item/weapon/circuitboard/mech_recharger + sort_string = "HACAA" + +/datum/design/circuit/recharge_station + name = "cyborg recharge station" + id = "recharge_station" + req_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 2) + build_path = /obj/item/weapon/circuitboard/recharge_station + sort_string = "HACAC" + +/datum/design/circuit/atmosalerts + name = "atmosphere alert console" + id = "atmosalerts" + build_path = /obj/item/weapon/circuitboard/atmos_alert + sort_string = "JAAAA" + +/datum/design/circuit/air_management + name = "atmosphere monitoring console" + id = "air_management" + build_path = /obj/item/weapon/circuitboard/air_management + sort_string = "JAAAB" + +/datum/design/circuit/rcon_console + name = "RCON remote control console" + id = "rcon_console" + req_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 3, TECH_POWER = 5) + build_path = /obj/item/weapon/circuitboard/rcon_console + sort_string = "JAAAC" + +/datum/design/circuit/dronecontrol + name = "drone control console" + id = "dronecontrol" + req_tech = list(TECH_DATA = 4) + build_path = /obj/item/weapon/circuitboard/drone_control + sort_string = "JAAAD" + +/datum/design/circuit/powermonitor + name = "power monitoring console" + id = "powermonitor" + build_path = /obj/item/weapon/circuitboard/powermonitor + sort_string = "JAAAE" + +/datum/design/circuit/solarcontrol + name = "solar control console" + id = "solarcontrol" + build_path = /obj/item/weapon/circuitboard/solar_control + sort_string = "JAAAF" + +/datum/design/circuit/pacman + name = "PACMAN-type generator" + id = "pacman" + req_tech = list(TECH_DATA = 3, TECH_PHORON = 3, TECH_POWER = 3, TECH_ENGINEERING = 3) + build_path = /obj/item/weapon/circuitboard/pacman + sort_string = "JBAAA" + +/datum/design/circuit/superpacman + name = "SUPERPACMAN-type generator" + id = "superpacman" + req_tech = list(TECH_DATA = 3, TECH_POWER = 4, TECH_ENGINEERING = 4) + build_path = /obj/item/weapon/circuitboard/pacman/super + sort_string = "JBAAB" + +/datum/design/circuit/mrspacman + name = "MRSPACMAN-type generator" + id = "mrspacman" + req_tech = list(TECH_DATA = 3, TECH_POWER = 5, TECH_ENGINEERING = 5) + build_path = /obj/item/weapon/circuitboard/pacman/mrs + sort_string = "JBAAC" + +/datum/design/circuit/batteryrack + name = "cell rack PSU" + id = "batteryrack" + req_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 2) + build_path = /obj/item/weapon/circuitboard/batteryrack + sort_string = "JBABA" + +/datum/design/circuit/smes_cell + name = "'SMES' superconductive magnetic energy storage" + desc = "Allows for the construction of circuit boards used to build a SMES." + id = "smes_cell" + req_tech = list(TECH_POWER = 7, TECH_ENGINEERING = 5) + build_path = /obj/item/weapon/circuitboard/smes + sort_string = "JBABB" + +/datum/design/circuit/gas_heater + name = "gas heating system" + id = "gasheater" + req_tech = list(TECH_POWER = 2, TECH_ENGINEERING = 1) + build_path = /obj/item/weapon/circuitboard/unary_atmos/heater + sort_string = "JCAAA" + +/datum/design/circuit/gas_cooler + name = "gas cooling system" + id = "gascooler" + req_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 2) + build_path = /obj/item/weapon/circuitboard/unary_atmos/cooler + sort_string = "JCAAB" + +/datum/design/circuit/secure_airlock + name = "secure airlock electronics" + desc = "Allows for the construction of a tamper-resistant airlock electronics." + id = "securedoor" + req_tech = list(TECH_DATA = 3) + build_path = /obj/item/weapon/airlock_electronics/secure + sort_string = "JDAAA" + +/datum/design/circuit/biogenerator + name = "biogenerator" + id = "biogenerator" + req_tech = list(TECH_DATA = 2) + build_path = /obj/item/weapon/circuitboard/biogenerator + sort_string = "KBAAA" + +/datum/design/circuit/miningdrill + name = "mining drill head" + id = "mining drill head" + req_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1) + build_path = /obj/item/weapon/circuitboard/miningdrill + sort_string = "KCAAA" + +/datum/design/circuit/miningdrillbrace + name = "mining drill brace" + id = "mining drill brace" + req_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1) + build_path = /obj/item/weapon/circuitboard/miningdrillbrace + sort_string = "KCAAB" + +/datum/design/circuit/mecha + req_tech = list(TECH_DATA = 3) + +/datum/design/circuit/mecha/AssembleDesignName() + name = "Exosuit module circuit design ([name])" +/datum/design/circuit/mecha/AssembleDesignDesc() + desc = "Allows for the construction of \a [name] module." + +/datum/design/circuit/mecha/ripley_main + name = "APLU 'Ripley' central control" + id = "ripley_main" + build_path = /obj/item/weapon/circuitboard/mecha/ripley/main + sort_string = "NAAAA" + +/datum/design/circuit/mecha/ripley_peri + name = "APLU 'Ripley' peripherals control" + id = "ripley_peri" + build_path = /obj/item/weapon/circuitboard/mecha/ripley/peripherals + sort_string = "NAAAB" + +/datum/design/circuit/mecha/odysseus_main + name = "'Odysseus' central control" + id = "odysseus_main" + req_tech = list(TECH_DATA = 3,TECH_BIO = 2) + build_path = /obj/item/weapon/circuitboard/mecha/odysseus/main + sort_string = "NAABA" + +/datum/design/circuit/mecha/odysseus_peri + name = "'Odysseus' peripherals control" + id = "odysseus_peri" + req_tech = list(TECH_DATA = 3,TECH_BIO = 2) + build_path = /obj/item/weapon/circuitboard/mecha/odysseus/peripherals + sort_string = "NAABB" + +/datum/design/circuit/mecha/gygax_main + name = "'Gygax' central control" + id = "gygax_main" + req_tech = list(TECH_DATA = 4) + build_path = /obj/item/weapon/circuitboard/mecha/gygax/main + sort_string = "NAACA" + +/datum/design/circuit/mecha/gygax_peri + name = "'Gygax' peripherals control" + id = "gygax_peri" + req_tech = list(TECH_DATA = 4) + build_path = /obj/item/weapon/circuitboard/mecha/gygax/peripherals + sort_string = "NAACB" + +/datum/design/circuit/mecha/gygax_targ + name = "'Gygax' weapon control and targeting" + id = "gygax_targ" + req_tech = list(TECH_DATA = 4, TECH_COMBAT = 2) + build_path = /obj/item/weapon/circuitboard/mecha/gygax/targeting + sort_string = "NAACC" + +/datum/design/circuit/mecha/durand_main + name = "'Durand' central control" + id = "durand_main" + req_tech = list(TECH_DATA = 4) + build_path = /obj/item/weapon/circuitboard/mecha/durand/main + sort_string = "NAADA" + +/datum/design/circuit/mecha/durand_peri + name = "'Durand' peripherals control" + id = "durand_peri" + req_tech = list(TECH_DATA = 4) + build_path = /obj/item/weapon/circuitboard/mecha/durand/peripherals + sort_string = "NAADB" + +/datum/design/circuit/mecha/durand_targ + name = "'Durand' weapon control and targeting" + id = "durand_targ" + req_tech = list(TECH_DATA = 4, TECH_COMBAT = 2) + build_path = /obj/item/weapon/circuitboard/mecha/durand/targeting + sort_string = "NAADC" + +/datum/design/circuit/tcom + req_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4) + +/datum/design/circuit/tcom/AssembleDesignName() + name = "Telecommunications machinery circuit design ([name])" +/datum/design/circuit/tcom/AssembleDesignDesc() + desc = "Allows for the construction of a telecommunications [name] circuit board." + +/datum/design/circuit/tcom/server + name = "server mainframe" + id = "tcom-server" + build_path = /obj/item/weapon/circuitboard/telecomms/server + sort_string = "PAAAA" + +/datum/design/circuit/tcom/processor + name = "processor unit" + id = "tcom-processor" + build_path = /obj/item/weapon/circuitboard/telecomms/processor + sort_string = "PAAAB" + +/datum/design/circuit/tcom/bus + name = "bus mainframe" + id = "tcom-bus" + build_path = /obj/item/weapon/circuitboard/telecomms/bus + sort_string = "PAAAC" + +/datum/design/circuit/tcom/hub + name = "hub mainframe" + id = "tcom-hub" + build_path = /obj/item/weapon/circuitboard/telecomms/hub + sort_string = "PAAAD" + +/datum/design/circuit/tcom/relay + name = "relay mainframe" + id = "tcom-relay" + req_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 4, TECH_BLUESPACE = 3) + build_path = /obj/item/weapon/circuitboard/telecomms/relay + sort_string = "PAAAE" + +/datum/design/circuit/tcom/broadcaster + name = "subspace broadcaster" + id = "tcom-broadcaster" + req_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4, TECH_BLUESPACE = 2) + build_path = /obj/item/weapon/circuitboard/telecomms/broadcaster + sort_string = "PAAAF" + +/datum/design/circuit/tcom/receiver + name = "subspace receiver" + id = "tcom-receiver" + req_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 3, TECH_BLUESPACE = 2) + build_path = /obj/item/weapon/circuitboard/telecomms/receiver + sort_string = "PAAAG" + +/datum/design/circuit/shield_generator + name = "Shield Generator" + desc = "Allows for the construction of a shield generator circuit board." + id = "shield_generator" + req_tech = list(TECH_MAGNET = 3, TECH_POWER = 4) + build_path = /obj/item/weapon/circuitboard/shield_generator + sort_string = "VAAAC" + +/datum/design/circuit/shield_diffuser + name = "Shield Diffuser" + desc = "Allows for the construction of a shield generator circuit board." + id = "shield_diffuser" + req_tech = list(TECH_MAGNET = 3, TECH_POWER = 4) + build_path = /obj/item/weapon/circuitboard/shield_diffuser + sort_string = "VAAAB" + +/datum/design/circuit/ntnet_relay + name = "NTNet Quantum Relay" + id = "ntnet_relay" + req_tech = list(TECH_DATA = 4) + build_path = /obj/item/weapon/circuitboard/ntnet_relay + sort_string = "WAAAA" + +/datum/design/circuit/replicator + name = "food replicator" + id = "freplicator" + req_tech = list(TECH_BIO = 3, TECH_DATA = 3) + build_path = /obj/item/weapon/circuitboard/replicator + sort_string = "WAAAR" + +/datum/design/circuit/aicore + name = "AI core" + id = "aicore" + req_tech = list(TECH_DATA = 4, TECH_BIO = 3) + build_path = /obj/item/weapon/circuitboard/aicore + sort_string = "XAAAA" + +/datum/design/circuit/integrated + name = "integrated circuit" + id = "integrated" + req_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2) + build_path = /obj/item/weapon/circuitboard/integrated_printer + sort_string = "WAAAS" + +/datum/design/aimodule + build_type = IMPRINTER + materials = list("glass" = 2000, "gold" = 100) + +/datum/design/aimodule/AssembleDesignName() + name = "AI module design ([name])" + +/datum/design/aimodule/AssembleDesignDesc() + desc = "Allows for the construction of \a '[name]' AI module." + +/datum/design/aimodule/safeguard + name = "Safeguard" + id = "safeguard" + req_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) + build_path = /obj/item/weapon/aiModule/safeguard + sort_string = "XABAA" + +/datum/design/aimodule/onehuman + name = "OneCrewMember" + id = "onehuman" + req_tech = list(TECH_DATA = 4, TECH_MATERIAL = 6) + build_path = /obj/item/weapon/aiModule/oneHuman + sort_string = "XABAB" + +/datum/design/aimodule/protectstation + name = "ProtectInstallation" + id = "protectstation" + req_tech = list(TECH_DATA = 3, TECH_MATERIAL = 6) + build_path = /obj/item/weapon/aiModule/protectStation + sort_string = "XABAC" + +/datum/design/aimodule/notele + name = "TeleporterOffline" + id = "notele" + req_tech = list(TECH_DATA = 3) + build_path = /obj/item/weapon/aiModule/teleporterOffline + sort_string = "XABAD" + +/datum/design/aimodule/quarantine + name = "Quarantine" + id = "quarantine" + req_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 4) + build_path = /obj/item/weapon/aiModule/quarantine + sort_string = "XABAE" + +/datum/design/aimodule/oxygen + name = "OxygenIsToxicToHumans" + id = "oxygen" + req_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 4) + build_path = /obj/item/weapon/aiModule/oxygen + sort_string = "XABAF" + +/datum/design/aimodule/freeform + name = "Freeform" + id = "freeform" + req_tech = list(TECH_DATA = 4, TECH_MATERIAL = 4) + build_path = /obj/item/weapon/aiModule/freeform + sort_string = "XABAG" + +/datum/design/aimodule/reset + name = "Reset" + id = "reset" + req_tech = list(TECH_DATA = 3, TECH_MATERIAL = 6) + build_path = /obj/item/weapon/aiModule/reset + sort_string = "XAAAA" + +/datum/design/aimodule/purge + name = "Purge" + id = "purge" + req_tech = list(TECH_DATA = 4, TECH_MATERIAL = 6) + build_path = /obj/item/weapon/aiModule/purge + sort_string = "XAAAB" + +// Core modules +/datum/design/aimodule/core + req_tech = list(TECH_DATA = 4, TECH_MATERIAL = 6) + +/datum/design/aimodule/core/AssembleDesignName() + name = "AI core module design ([name])" + +/datum/design/aimodule/core/AssembleDesignDesc() + desc = "Allows for the construction of \a '[name]' AI core module." + +/datum/design/aimodule/core/freeformcore + name = "Freeform" + id = "freeformcore" + build_path = /obj/item/weapon/aiModule/freeformcore + sort_string = "XACAA" + +/datum/design/aimodule/core/asimov + name = "Asimov" + id = "asimov" + build_path = /obj/item/weapon/aiModule/asimov + sort_string = "XACAB" + +/datum/design/aimodule/core/paladin + name = "P.A.L.A.D.I.N." + id = "paladin" + build_path = /obj/item/weapon/aiModule/paladin + sort_string = "XACAC" + +/datum/design/aimodule/core/tyrant + name = "T.Y.R.A.N.T." + id = "tyrant" + req_tech = list(TECH_DATA = 4, TECH_ILLEGAL = 2, TECH_MATERIAL = 6) + build_path = /obj/item/weapon/aiModule/tyrant + sort_string = "XACAD" diff --git a/code/modules/research/destructive_analyzer.dm b/code/modules/research/destructive_analyzer.dm new file mode 100644 index 00000000..c74b83df --- /dev/null +++ b/code/modules/research/destructive_analyzer.dm @@ -0,0 +1,89 @@ +/* +Destructive Analyzer + +It is used to destroy hand-held objects and advance technological research. Controls are in the linked R&D console. + +Note: Must be placed within 3 tiles of the R&D Console +*/ + +/obj/machinery/r_n_d/destructive_analyzer + name = "destructive analyzer" + icon_state = "d_analyzer" + var/obj/item/weapon/loaded_item = null + var/decon_mod = 0 + + use_power = 1 + idle_power_usage = 30 + active_power_usage = 2500 + +/obj/machinery/r_n_d/destructive_analyzer/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/destructive_analyzer(src) + component_parts += new /obj/item/weapon/stock_parts/scanning_module(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) + RefreshParts() + +/obj/machinery/r_n_d/destructive_analyzer/RefreshParts() + var/T = 0 + for(var/obj/item/weapon/stock_parts/S in src) + T += S.rating + decon_mod = T * 0.1 + +/obj/machinery/r_n_d/destructive_analyzer/update_icon() + if(panel_open) + icon_state = "d_analyzer_t" + else if(loaded_item) + icon_state = "d_analyzer_l" + else + icon_state = "d_analyzer" + +/obj/machinery/r_n_d/destructive_analyzer/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(busy) + to_chat(user, "\The [src] is busy right now.") + return + if(loaded_item) + to_chat(user, "There is something already loaded into \the [src].") + return 1 + if(default_deconstruction_screwdriver(user, O)) + if(linked_console) + linked_console.linked_destroy = null + linked_console = null + return + if(default_deconstruction_crowbar(user, O)) + return + if(default_part_replacement(user, O)) + return + if(panel_open) + to_chat(user, "You can't load \the [src] while it's opened.") + return 1 + if(!linked_console) + to_chat(user, "\The [src] must be linked to an R&D console first.") + return + if(!loaded_item) + if(isrobot(user)) //Don't put your module items in there! + return + if(istype(O, /obj/item/device/electronic_assembly)) //A few things + var/obj/item/device/electronic_assembly/assembly = O + if(!assembly.contents.len) //Make sure they don't use this to get cheap assemblies. + return + else + if(!O.origin_tech) + to_chat(user, "This doesn't seem to have a tech origin.") + return + if(O.origin_tech.len == 0) + to_chat(user, "You cannot deconstruct this item.") + return + + busy = 1 + loaded_item = O + user.drop_item() + O.loc = src + to_chat(user, "You add \the [O] to \the [src].") + flick("d_analyzer_la", src) + spawn(10) + update_icon() + busy = 0 + return 1 + return diff --git a/code/modules/research/mechfab_designs.dm b/code/modules/research/mechfab_designs.dm new file mode 100644 index 00000000..4b3c4aaf --- /dev/null +++ b/code/modules/research/mechfab_designs.dm @@ -0,0 +1,610 @@ +/datum/design/item/mechfab + build_type = MECHFAB + category = "Misc" + req_tech = list(TECH_MATERIAL = 1) + +/datum/design/item/mechfab/robot + category = "Robot" + +//if the fabricator is a mech fab pass the manufacturer info over to the robot part constructor +/datum/design/item/mechfab/robot/Fabricate(var/newloc, var/fabricator) + if(istype(fabricator, /obj/machinery/mecha_part_fabricator)) + var/obj/machinery/mecha_part_fabricator/mechfab = fabricator + return new build_path(newloc, mechfab.manufacturer) + return ..() + +/datum/design/item/mechfab/robot/exoskeleton + name = "Robot exoskeleton" + id = "robot_exoskeleton" + build_path = /obj/item/robot_parts/robot_suit + time = 50 + materials = list(DEFAULT_WALL_MATERIAL = 50000) + +/datum/design/item/mechfab/robot/torso + name = "Robot torso" + id = "robot_torso" + build_path = /obj/item/robot_parts/chest + time = 35 + materials = list(DEFAULT_WALL_MATERIAL = 40000) + +/datum/design/item/mechfab/robot/head + name = "Robot head" + id = "robot_head" + build_path = /obj/item/robot_parts/head + time = 35 + materials = list(DEFAULT_WALL_MATERIAL = 25000) + +/datum/design/item/mechfab/robot/l_arm + name = "Robot left arm" + id = "robot_l_arm" + build_path = /obj/item/robot_parts/l_arm + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 18000) + +/datum/design/item/mechfab/robot/r_arm + name = "Robot right arm" + id = "robot_r_arm" + build_path = /obj/item/robot_parts/r_arm + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 18000) + +/datum/design/item/mechfab/robot/l_leg + name = "Robot left leg" + id = "robot_l_leg" + build_path = /obj/item/robot_parts/l_leg + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 15000) + +/datum/design/item/mechfab/robot/r_leg + name = "Robot right leg" + id = "robot_r_leg" + build_path = /obj/item/robot_parts/r_leg + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 15000) + +/datum/design/item/mechfab/robot/component + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 5000) + +/datum/design/item/mechfab/robot/component/binary_communication_device + name = "Binary communication device" + id = "binary_communication_device" + build_path = /obj/item/robot_parts/robot_component/binary_communication_device + +/datum/design/item/mechfab/robot/component/radio + name = "Radio" + id = "radio" + build_path = /obj/item/robot_parts/robot_component/radio + +/datum/design/item/mechfab/robot/component/actuator + name = "Actuator" + id = "actuator" + build_path = /obj/item/robot_parts/robot_component/actuator + +/datum/design/item/mechfab/robot/component/diagnosis_unit + name = "Diagnosis unit" + id = "diagnosis_unit" + build_path = /obj/item/robot_parts/robot_component/diagnosis_unit + +/datum/design/item/mechfab/robot/component/camera + name = "Camera" + id = "camera" + build_path = /obj/item/robot_parts/robot_component/camera + +/datum/design/item/mechfab/robot/component/armour + name = "Armour plating" + id = "armour" + build_path = /obj/item/robot_parts/robot_component/armour + +/datum/design/item/mechfab/ripley + category = "Ripley" + +/datum/design/item/mechfab/ripley/chassis + name = "Ripley chassis" + id = "ripley_chassis" + build_path = /obj/item/mecha_parts/chassis/ripley + time = 10 + materials = list(DEFAULT_WALL_MATERIAL = 20000) + +/datum/design/item/mechfab/ripley/chassis/firefighter + name = "Firefigher chassis" + id = "firefighter_chassis" + build_path = /obj/item/mecha_parts/chassis/firefighter + +/datum/design/item/mechfab/ripley/torso + name = "Ripley torso" + id = "ripley_torso" + build_path = /obj/item/mecha_parts/part/ripley_torso + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 40000, "glass" = 15000) + +/datum/design/item/mechfab/ripley/left_arm + name = "Ripley left arm" + id = "ripley_left_arm" + build_path = /obj/item/mecha_parts/part/ripley_left_arm + time = 15 + materials = list(DEFAULT_WALL_MATERIAL = 25000) + +/datum/design/item/mechfab/ripley/right_arm + name = "Ripley right arm" + id = "ripley_right_arm" + build_path = /obj/item/mecha_parts/part/ripley_right_arm + time = 15 + materials = list(DEFAULT_WALL_MATERIAL = 25000) + +/datum/design/item/mechfab/ripley/left_leg + name = "Ripley left leg" + id = "ripley_left_leg" + build_path = /obj/item/mecha_parts/part/ripley_left_leg + time = 15 + materials = list(DEFAULT_WALL_MATERIAL = 30000) + +/datum/design/item/mechfab/ripley/right_leg + name = "Ripley right leg" + id = "ripley_right_leg" + build_path = /obj/item/mecha_parts/part/ripley_right_leg + time = 15 + materials = list(DEFAULT_WALL_MATERIAL = 30000) + +/datum/design/item/mechfab/odysseus + category = "Odysseus" + +/datum/design/item/mechfab/odysseus/chassis + name = "Odysseus chassis" + id = "odysseus_chassis" + build_path = /obj/item/mecha_parts/chassis/odysseus + time = 10 + materials = list(DEFAULT_WALL_MATERIAL = 20000) + +/datum/design/item/mechfab/odysseus/torso + name = "Odysseus torso" + id = "odysseus_torso" + build_path = /obj/item/mecha_parts/part/odysseus_torso + time = 18 + materials = list(DEFAULT_WALL_MATERIAL = 25000) + +/datum/design/item/mechfab/odysseus/head + name = "Odysseus head" + id = "odysseus_head" + build_path = /obj/item/mecha_parts/part/odysseus_head + time = 10 + materials = list(DEFAULT_WALL_MATERIAL = 2000, "glass" = 10000) + +/datum/design/item/mechfab/odysseus/left_arm + name = "Odysseus left arm" + id = "odysseus_left_arm" + build_path = /obj/item/mecha_parts/part/odysseus_left_arm + time = 12 + materials = list(DEFAULT_WALL_MATERIAL = 10000) + +/datum/design/item/mechfab/odysseus/right_arm + name = "Odysseus right arm" + id = "odysseus_right_arm" + build_path = /obj/item/mecha_parts/part/odysseus_right_arm + time = 12 + materials = list(DEFAULT_WALL_MATERIAL = 10000) + +/datum/design/item/mechfab/odysseus/left_leg + name = "Odysseus left leg" + id = "odysseus_left_leg" + build_path = /obj/item/mecha_parts/part/odysseus_left_leg + time = 13 + materials = list(DEFAULT_WALL_MATERIAL = 15000) + +/datum/design/item/mechfab/odysseus/right_leg + name = "Odysseus right leg" + id = "odysseus_right_leg" + build_path = /obj/item/mecha_parts/part/odysseus_right_leg + time = 13 + materials = list(DEFAULT_WALL_MATERIAL = 15000) + +/datum/design/item/mechfab/gygax + category = "Gygax" + +/datum/design/item/mechfab/gygax/chassis + name = "Gygax chassis" + id = "gygax_chassis" + build_path = /obj/item/mecha_parts/chassis/gygax + time = 10 + materials = list(DEFAULT_WALL_MATERIAL = 25000) + +/datum/design/item/mechfab/gygax/torso + name = "Gygax torso" + id = "gygax_torso" + build_path = /obj/item/mecha_parts/part/gygax_torso + time = 30 + materials = list(DEFAULT_WALL_MATERIAL = 50000, "glass" = 20000) + +/datum/design/item/mechfab/gygax/head + name = "Gygax head" + id = "gygax_head" + build_path = /obj/item/mecha_parts/part/gygax_head + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 20000, "glass" = 10000) + +/datum/design/item/mechfab/gygax/left_arm + name = "Gygax left arm" + id = "gygax_left_arm" + build_path = /obj/item/mecha_parts/part/gygax_left_arm + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 30000) + +/datum/design/item/mechfab/gygax/right_arm + name = "Gygax right arm" + id = "gygax_right_arm" + build_path = /obj/item/mecha_parts/part/gygax_right_arm + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 30000) + +/datum/design/item/mechfab/gygax/left_leg + name = "Gygax left leg" + id = "gygax_left_leg" + build_path = /obj/item/mecha_parts/part/gygax_left_leg + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 35000) + +/datum/design/item/mechfab/gygax/right_leg + name = "Gygax right leg" + id = "gygax_right_leg" + build_path = /obj/item/mecha_parts/part/gygax_right_leg + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 35000) + +/datum/design/item/mechfab/gygax/armour + name = "Gygax armour plates" + id = "gygax_armour" + build_path = /obj/item/mecha_parts/part/gygax_armour + time = 60 + materials = list(DEFAULT_WALL_MATERIAL = 50000, "diamond" = 10000) + +/datum/design/item/mechfab/durand + category = "Durand" + +/datum/design/item/mechfab/durand/chassis + name = "Durand chassis" + id = "durand_chassis" + build_path = /obj/item/mecha_parts/chassis/durand + time = 10 + materials = list(DEFAULT_WALL_MATERIAL = 25000) + +/datum/design/item/mechfab/durand/torso + name = "Durand torso" + id = "durand_torso" + build_path = /obj/item/mecha_parts/part/durand_torso + time = 30 + materials = list(DEFAULT_WALL_MATERIAL = 55000, "glass" = 20000, "silver" = 10000) + +/datum/design/item/mechfab/durand/head + name = "Durand head" + id = "durand_head" + build_path = /obj/item/mecha_parts/part/durand_head + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 25000, "glass" = 10000, "silver" = 3000) + +/datum/design/item/mechfab/durand/left_arm + name = "Durand left arm" + id = "durand_left_arm" + build_path = /obj/item/mecha_parts/part/durand_left_arm + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 35000, "silver" = 3000) + +/datum/design/item/mechfab/durand/right_arm + name = "Durand right arm" + id = "durand_right_arm" + build_path = /obj/item/mecha_parts/part/durand_right_arm + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 35000, "silver" = 3000) + +/datum/design/item/mechfab/durand/left_leg + name = "Durand left leg" + id = "durand_left_leg" + build_path = /obj/item/mecha_parts/part/durand_left_leg + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 40000, "silver" = 3000) + +/datum/design/item/mechfab/durand/right_leg + name = "Durand right leg" + id = "durand_right_leg" + build_path = /obj/item/mecha_parts/part/durand_right_leg + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 40000, "silver" = 3000) + +/datum/design/item/mechfab/durand/armour + name = "Durand armour plates" + id = "durand_armour" + build_path = /obj/item/mecha_parts/part/durand_armour + time = 60 + materials = list(DEFAULT_WALL_MATERIAL = 50000, "uranium" = 10000) + +/datum/design/item/robot_upgrade + build_type = MECHFAB + time = 12 + materials = list(DEFAULT_WALL_MATERIAL = 10000) + category = "Cyborg Upgrade Modules" + +/datum/design/item/robot_upgrade/rename + name = "Rename module" + desc = "Used to rename a cyborg." + id = "borg_rename_module" + build_path = /obj/item/borg/upgrade/rename + +/datum/design/item/robot_upgrade/reset + name = "Reset module" + desc = "Used to reset a cyborg's module. Destroys any other upgrades applied to the robot." + id = "borg_reset_module" + build_path = /obj/item/borg/upgrade/reset + +/datum/design/item/robot_upgrade/floodlight + name = "Floodlight module" + desc = "Used to boost cyborg's integrated light intensity." + id = "borg_floodlight_module" + build_path = /obj/item/borg/upgrade/floodlight + +/datum/design/item/robot_upgrade/restart + name = "Emergency restart module" + desc = "Used to force a restart of a disabled-but-repaired robot, bringing it back online." + id = "borg_restart_module" + materials = list(DEFAULT_WALL_MATERIAL = 60000, "glass" = 5000) + build_path = /obj/item/borg/upgrade/restart + +/datum/design/item/robot_upgrade/vtec + name = "VTEC module" + desc = "Used to kick in a robot's VTEC systems, increasing their speed." + id = "borg_vtec_module" + materials = list(DEFAULT_WALL_MATERIAL = 80000, "glass" = 6000, "gold" = 5000) + build_path = /obj/item/borg/upgrade/vtec + +/datum/design/item/robot_upgrade/tasercooler + name = "Rapid taser cooling module" + desc = "Used to cool a mounted taser, increasing the potential current in it and thus its recharge rate." + id = "borg_taser_module" + materials = list(DEFAULT_WALL_MATERIAL = 80000, "glass" = 6000, "gold" = 2000, "diamond" = 500) + build_path = /obj/item/borg/upgrade/tasercooler + +/datum/design/item/robot_upgrade/jetpack + name = "Jetpack module" + desc = "A carbon dioxide jetpack suitable for low-gravity mining operations." + id = "borg_jetpack_module" + materials = list(DEFAULT_WALL_MATERIAL = 10000, "phoron" = 15000, "uranium" = 20000) + build_path = /obj/item/borg/upgrade/jetpack + +/datum/design/item/robot_upgrade/rcd + name = "RCD module" + desc = "A rapid construction device module for use during construction operations." + id = "borg_rcd_module" + materials = list(DEFAULT_WALL_MATERIAL = 25000, "phoron" = 10000, "gold" = 1000, "silver" = 1000) + build_path = /obj/item/borg/upgrade/rcd + +/datum/design/item/robot_upgrade/syndicate + name = "Illegal upgrade" + desc = "Allows for the construction of lethal upgrades for cyborgs." + id = "borg_syndicate_module" + req_tech = list(TECH_COMBAT = 4, TECH_ILLEGAL = 3) + materials = list(DEFAULT_WALL_MATERIAL = 10000, "glass" = 15000, "diamond" = 10000) + build_path = /obj/item/borg/upgrade/syndicate + +/datum/design/item/mecha_tracking + name = "Exosuit tracking beacon" + build_type = MECHFAB + time = 5 + materials = list(DEFAULT_WALL_MATERIAL = 500) + build_path = /obj/item/mecha_parts/mecha_tracking + category = "Misc" + +/datum/design/item/mecha + build_type = MECHFAB + category = "Exosuit Equipment" + time = 10 + materials = list(DEFAULT_WALL_MATERIAL = 10000) + +/datum/design/item/mecha/AssembleDesignDesc() + if(!desc) + desc = "Allows for the construction of \a '[item_name]' exosuit module." + +/datum/design/item/mecha/hydraulic_clamp + name = "Hydraulic clamp" + id = "hydraulic_clamp" + build_path = /obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp + +/datum/design/item/mecha/drill + name = "Drill" + id = "mech_drill" + build_path = /obj/item/mecha_parts/mecha_equipment/tool/drill + +/datum/design/item/mecha/extinguisher + name = "Extinguisher" + id = "extinguisher" + build_path = /obj/item/mecha_parts/mecha_equipment/tool/extinguisher + +/datum/design/item/mecha/cable_layer + name = "Cable layer" + id = "mech_cable_layer" + build_path = /obj/item/mecha_parts/mecha_equipment/tool/cable_layer + +/datum/design/item/mecha/flaregun + name = "Flare launcher" + id = "mecha_flare_gun" + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flare + materials = list(DEFAULT_WALL_MATERIAL = 12500) + +/datum/design/item/mecha/sleeper + name = "Sleeper" + id = "mech_sleeper" + build_path = /obj/item/mecha_parts/mecha_equipment/tool/sleeper + materials = list(DEFAULT_WALL_MATERIAL = 5000, "glass" = 10000) + +/datum/design/item/mecha/syringe_gun + name = "Syringe gun" + id = "mech_syringe_gun" + build_path = /obj/item/mecha_parts/mecha_equipment/tool/syringe_gun + time = 20 + materials = list(DEFAULT_WALL_MATERIAL = 3000, "glass" = 2000) + +/* +/datum/design/item/mecha/syringe_gun + desc = "Exosuit-mounted syringe gun and chemical synthesizer." + id = "mech_syringe_gun" + req_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4, TECH_MAGNET = 4, TECH_DATA = 3) + build_path = /obj/item/mecha_parts/mecha_equipment/tool/syringe_gun + */ + +/datum/design/item/mecha/passenger + name = "Passenger compartment" + id = "mech_passenger" + build_path = /obj/item/mecha_parts/mecha_equipment/tool/passenger + materials = list(DEFAULT_WALL_MATERIAL = 5000, "glass" = 5000) + +//obj/item/mecha_parts/mecha_equipment/repair_droid, +//obj/item/mecha_parts/mecha_equipment/jetpack, //TODO MECHA JETPACK SPRITE MISSING + +/datum/design/item/mecha/taser + name = "PBT \"Pacifier\" mounted taser" + id = "mech_taser" + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/energy/taser + +/datum/design/item/mecha/lmg + name = "Ultra AC 2" + id = "mech_lmg" + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg + +/datum/design/item/mecha/weapon + req_tech = list(TECH_COMBAT = 3) + +// *** Weapon modules +/datum/design/item/mecha/weapon/scattershot + name = "LBX AC 10 \"Scattershot\"" + id = "mech_scattershot" + req_tech = list(TECH_COMBAT = 4) + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot + +/datum/design/item/mecha/weapon/laser + name = "CH-PS \"Immolator\" laser" + id = "mech_laser" + req_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 3) + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser + +/datum/design/item/mecha/weapon/laser_rigged + name = "Jury-rigged welder-laser" + desc = "Allows for the construction of a welder-laser assembly package for non-combat exosuits." + id = "mech_laser_rigged" + req_tech = list(TECH_COMBAT = 2, TECH_MAGNET = 2) + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/energy/riggedlaser + +/datum/design/item/mecha/weapon/laser_heavy + name = "CH-LC \"Solaris\" laser cannon" + id = "mech_laser_heavy" + req_tech = list(TECH_COMBAT = 4, TECH_MAGNET = 4) + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy + +/datum/design/item/mecha/weapon/ion + name = "mkIV ion heavy cannon" + id = "mech_ion" + req_tech = list(TECH_COMBAT = 4, TECH_MAGNET = 4) + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/energy/ion + +/datum/design/item/mecha/weapon/grenade_launcher + name = "SGL-6 grenade launcher" + id = "mech_grenade_launcher" + req_tech = list(TECH_COMBAT = 3) + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang + +/datum/design/item/mecha/weapon/clusterbang_launcher + name = "SOP-6 grenade launcher" + desc = "A weapon that violates the Geneva Convention at 6 rounds per minute." + id = "clusterbang_launcher" + req_tech = list(TECH_COMBAT= 5, TECH_MATERIAL = 5, TECH_ILLEGAL = 3) + materials = list(DEFAULT_WALL_MATERIAL = 20000, "gold" = 6000, "uranium" = 6000) + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang/clusterbang/limited + +// *** Nonweapon modules +/datum/design/item/mecha/wormhole_gen + name = "Wormhole generator" + desc = "An exosuit module that can generate small quasi-stable wormholes." + id = "mech_wormhole_gen" + req_tech = list(TECH_BLUESPACE = 3, TECH_MAGNET = 2) + build_path = /obj/item/mecha_parts/mecha_equipment/wormhole_generator + +/datum/design/item/mecha/teleporter + name = "Teleporter" + desc = "An exosuit module that allows teleportation to any position in view." + id = "mech_teleporter" + req_tech = list(TECH_BLUESPACE = 10, TECH_MAGNET = 5) + build_path = /obj/item/mecha_parts/mecha_equipment/teleporter + +/datum/design/item/mecha/rcd + name = "RCD" + desc = "An exosuit-mounted rapid construction device." + id = "mech_rcd" + time = 120 + materials = list(DEFAULT_WALL_MATERIAL = 30000, "phoron" = 25000, "silver" = 20000, "gold" = 20000) + req_tech = list(TECH_MATERIAL = 4, TECH_BLUESPACE = 3, TECH_MAGNET = 4, TECH_POWER = 4, TECH_ENGINEERING = 4) + build_path = /obj/item/mecha_parts/mecha_equipment/tool/rcd + +/datum/design/item/mecha/gravcatapult + name = "Gravitational catapult" + desc = "An exosuit-mounted gravitational catapult." + id = "mech_gravcatapult" + req_tech = list(TECH_BLUESPACE = 2, TECH_MAGNET = 3, TECH_ENGINEERING = 3) + build_path = /obj/item/mecha_parts/mecha_equipment/gravcatapult + +/datum/design/item/mecha/repair_droid + name = "Repair droid" + desc = "Automated repair droid, exosuits' best companion. BEEP BOOP" + id = "mech_repair_droid" + req_tech = list(TECH_MAGNET = 3, TECH_DATA = 3, TECH_ENGINEERING = 3) + materials = list(DEFAULT_WALL_MATERIAL = 10000, "gold" = 1000, "silver" = 2000, "glass" = 5000) + build_path = /obj/item/mecha_parts/mecha_equipment/repair_droid + +/datum/design/item/mecha/phoron_generator + desc = "Phoron reactor." + id = "mech_phoron_generator" + req_tech = list(TECH_PHORON = 2, TECH_POWER= 2, TECH_ENGINEERING = 2) + build_path = /obj/item/mecha_parts/mecha_equipment/generator + materials = list(DEFAULT_WALL_MATERIAL = 10000, "silver" = 500, "glass" = 1000) + +/datum/design/item/mecha/energy_relay + name = "Energy relay" + id = "mech_energy_relay" + req_tech = list(TECH_MAGNET = 4, TECH_POWER = 3) + materials = list(DEFAULT_WALL_MATERIAL = 10000, "gold" = 2000, "silver" = 3000, "glass" = 2000) + build_path = /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay + +/datum/design/item/mecha/ccw_armor + name = "CCW armor booster" + desc = "Exosuit close-combat armor booster." + id = "mech_ccw_armor" + req_tech = list(TECH_MATERIAL = 5, TECH_COMBAT = 4) + materials = list(DEFAULT_WALL_MATERIAL = 20000, "silver" = 5000) + build_path = /obj/item/mecha_parts/mecha_equipment/armor_booster/anticcw_armor_booster + +/datum/design/item/mecha/proj_armor + desc = "Exosuit projectile armor booster." + id = "mech_proj_armor" + req_tech = list(TECH_MATERIAL = 5, TECH_COMBAT = 5, TECH_ENGINEERING = 3) + materials = list(DEFAULT_WALL_MATERIAL = 20000, "gold" = 5000) + build_path = /obj/item/mecha_parts/mecha_equipment/armor_booster/antiproj_armor_booster + +/datum/design/item/mecha/diamond_drill + name = "Diamond drill" + desc = "A diamond version of the exosuit drill. It's harder, better, faster, stronger." + id = "mech_diamond_drill" + req_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 3) + materials = list(DEFAULT_WALL_MATERIAL = 10000, "diamond" = 6500) + build_path = /obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill + +/datum/design/item/mecha/generator_nuclear + name = "Nuclear reactor" + desc = "Exosuit-held nuclear reactor. Converts uranium and everyone's health to energy." + id = "mech_generator_nuclear" + req_tech = list(TECH_POWER= 3, TECH_ENGINEERING = 3, TECH_MATERIAL = 3) + materials = list(DEFAULT_WALL_MATERIAL = 10000, "silver" = 500, "glass" = 1000) + build_path = /obj/item/mecha_parts/mecha_equipment/generator/nuclear + +/datum/design/item/synthetic_flash + name = "Synthetic flash" + id = "sflash" + req_tech = list(TECH_MAGNET = 3, TECH_COMBAT = 2) + build_type = MECHFAB + materials = list(DEFAULT_WALL_MATERIAL = 750, "glass" = 750) + build_path = /obj/item/device/flash/synthetic + category = "Misc" \ No newline at end of file diff --git a/code/modules/research/message_server.dm b/code/modules/research/message_server.dm new file mode 100644 index 00000000..f14fc379 --- /dev/null +++ b/code/modules/research/message_server.dm @@ -0,0 +1,413 @@ +#define MESSAGE_SERVER_SPAM_REJECT 1 +#define MESSAGE_SERVER_DEFAULT_SPAM_LIMIT 10 + +var/global/list/obj/machinery/message_server/message_servers = list() + +/datum/data_pda_msg + var/recipient = "Unspecified" //name of the person + var/sender = "Unspecified" //name of the sender + var/message = "Blank" //transferred message + +/datum/data_pda_msg/New(var/param_rec = "",var/param_sender = "",var/param_message = "") + + if(param_rec) + recipient = param_rec + if(param_sender) + sender = param_sender + if(param_message) + message = param_message + +/datum/data_rc_msg + var/rec_dpt = "Unspecified" //name of the person + var/send_dpt = "Unspecified" //name of the sender + var/message = "Blank" //transferred message + var/stamp = "Unstamped" + var/id_auth = "Unauthenticated" + var/priority = "Normal" + +/datum/data_rc_msg/New(var/param_rec = "",var/param_sender = "",var/param_message = "",var/param_stamp = "",var/param_id_auth = "",var/param_priority) + if(param_rec) + rec_dpt = param_rec + if(param_sender) + send_dpt = param_sender + if(param_message) + message = param_message + if(param_stamp) + stamp = param_stamp + if(param_id_auth) + id_auth = param_id_auth + if(param_priority) + switch(param_priority) + if(1) + priority = "Normal" + if(2) + priority = "High" + if(3) + priority = "Extreme" + else + priority = "Undetermined" + +/obj/machinery/message_server + icon = 'icons/obj/machines/research.dmi' + icon_state = "server" + name = "Messaging Server" + density = 1 + anchored = 1.0 + use_power = 1 + idle_power_usage = 10 + active_power_usage = 100 + + var/list/datum/data_pda_msg/pda_msgs = list() + var/list/datum/data_rc_msg/rc_msgs = list() + var/active = 1 + var/power_failure = 0 // Reboot timer after power outage + var/decryptkey = "password" + + //Spam filtering stuff + var/list/spamfilter = list("You have won", "your prize", "male enhancement", "shitcurity", \ + "are happy to inform you", "account number", "enter your PIN") + //Messages having theese tokens will be rejected by server. Case sensitive + var/spamfilter_limit = MESSAGE_SERVER_DEFAULT_SPAM_LIMIT //Maximal amount of tokens + +/obj/machinery/message_server/New() + message_servers += src + decryptkey = GenerateKey() + send_pda_message("System Administrator", "system", "This is an automated message. The messaging system is functioning correctly.") + ..() + +/obj/machinery/message_server/Destroy() + message_servers -= src + return ..() + +/obj/machinery/message_server/Process() + if(active && (stat & (BROKEN|NOPOWER))) + active = 0 + power_failure = 10 + update_icon() + return + else if(stat & (BROKEN|NOPOWER)) + return + else if(power_failure > 0) + if(!(--power_failure)) + active = 1 + update_icon() + +/obj/machinery/message_server/proc/send_pda_message(var/recipient = "",var/sender = "",var/message = "") + var/result + for (var/token in spamfilter) + if (findtextEx(message,token)) + message = "[message]" //Rejected messages will be indicated by red color. + result = token //Token caused rejection (if there are multiple, last will be chosen>. + pda_msgs += new/datum/data_pda_msg(recipient,sender,message) + return result + +/obj/machinery/message_server/proc/send_rc_message(var/recipient = "",var/sender = "",var/message = "",var/stamp = "", var/id_auth = "", var/priority = 1) + rc_msgs += new/datum/data_rc_msg(recipient,sender,message,stamp,id_auth) + var/authmsg = "[message]
            " + if (id_auth) + authmsg += "[id_auth]
            " + if (stamp) + authmsg += "[stamp]
            " + for (var/obj/machinery/requests_console/Console in allConsoles) + if (ckey(Console.department) == ckey(recipient)) + if(Console.inoperable()) + Console.message_log += "Message lost due to console failure.
            Please contact [station_name()] system administrator or AI for technical assistance.
            " + continue + if(Console.newmessagepriority < priority) + Console.newmessagepriority = priority + Console.icon_state = "req_comp[priority]" + if(priority > 1) + playsound(Console.loc, 'sound/machines/chime.ogg', 80, 1) + Console.audible_message("\icon[Console]\The [Console] announces: 'High priority message received from [sender]!'", hearing_distance = 8) + Console.message_log += "High Priority message from [sender]
            [authmsg]" + else + if(!Console.silent) + playsound(Console.loc, 'sound/machines/twobeep.ogg', 50, 1) + Console.audible_message("\icon[Console]\The [Console] announces: 'Message received from [sender].'", hearing_distance = 5) + Console.message_log += "Message from [sender]
            [authmsg]" + Console.set_light(2) + + +/obj/machinery/message_server/attack_hand(user as mob) + to_chat(user, "You toggle PDA message passing from [active ? "On" : "Off"] to [active ? "Off" : "On"]") + active = !active + power_failure = 0 + update_icon() + + return + +/obj/machinery/message_server/attackby(obj/item/weapon/O as obj, mob/living/user as mob) + if (active && !(stat & (BROKEN|NOPOWER)) && (spamfilter_limit < MESSAGE_SERVER_DEFAULT_SPAM_LIMIT*2) && \ + istype(O,/obj/item/weapon/circuitboard/message_monitor)) + spamfilter_limit += round(MESSAGE_SERVER_DEFAULT_SPAM_LIMIT / 2) + user.drop_item() + qdel(O) + to_chat(user, "You install additional memory and processors into message server. Its filtering capabilities been enhanced.") + else + ..(O, user) + +/obj/machinery/message_server/update_icon() + if((stat & (BROKEN|NOPOWER))) + icon_state = "server-nopower" + else if (!active) + icon_state = "server-off" + else + icon_state = "server-on" + + return + +/obj/machinery/message_server/proc/send_to_department(var/department, var/message, var/tone) + var/reached = 0 + for(var/obj/item/device/pda/P in PDAs) + if(P.toff) + continue + var/datum/job/J = job_master.GetJob(P.ownrank) + if(!J) + continue + if(J.department_flag & department) + P.new_info(P.message_silent, tone ? tone : P.ttone, "\icon[P] [message]") + reached++ + return reached + +/datum/feedback_variable + var/variable + var/value + var/details + +/datum/feedback_variable/New(var/param_variable,var/param_value = 0) + variable = param_variable + value = param_value + +/datum/feedback_variable/proc/inc(var/num = 1) + if(isnum(value)) + value += num + else + value = text2num(value) + if(isnum(value)) + value += num + else + value = num + +/datum/feedback_variable/proc/dec(var/num = 1) + if(isnum(value)) + value -= num + else + value = text2num(value) + if(isnum(value)) + value -= num + else + value = -num + +/datum/feedback_variable/proc/set_value(var/num) + if(isnum(num)) + value = num + +/datum/feedback_variable/proc/get_value() + return value + +/datum/feedback_variable/proc/get_variable() + return variable + +/datum/feedback_variable/proc/set_details(var/text) + if(istext(text)) + details = text + +/datum/feedback_variable/proc/add_details(var/text) + if(istext(text)) + if(!details) + details = text + else + details += " [text]" + +/datum/feedback_variable/proc/get_details() + return details + +/datum/feedback_variable/proc/get_parsed() + return list(variable,value,details) + +var/obj/machinery/blackbox_recorder/blackbox + +/obj/machinery/blackbox_recorder + icon = 'icons/obj/stationobjs.dmi' + icon_state = "blackbox" + name = "Blackbox Recorder" + density = 1 + anchored = 1.0 + use_power = 1 + idle_power_usage = 10 + active_power_usage = 100 + var/list/messages = list() //Stores messages of non-standard frequencies + var/list/messages_admin = list() + + var/list/msg_common = list() + var/list/msg_science = list() + var/list/msg_command = list() + var/list/msg_medical = list() + var/list/msg_engineering = list() + var/list/msg_security = list() + var/list/msg_deathsquad = list() + var/list/msg_syndicate = list() + var/list/msg_raider = list() + var/list/msg_cargo = list() + var/list/msg_service = list() + var/list/msg_exploration = list() + + var/list/datum/feedback_variable/feedback = new() + + //Only one can exist in the world! +/obj/machinery/blackbox_recorder/New() + if(blackbox) + if(istype(blackbox,/obj/machinery/blackbox_recorder)) + qdel(src) + blackbox = src + +/obj/machinery/blackbox_recorder/Destroy() + var/turf/T = locate(1,1,2) + if(T) + blackbox = null + var/obj/machinery/blackbox_recorder/BR = new/obj/machinery/blackbox_recorder(T) + BR.msg_common = msg_common + BR.msg_science = msg_science + BR.msg_command = msg_command + BR.msg_medical = msg_medical + BR.msg_engineering = msg_engineering + BR.msg_security = msg_security + BR.msg_deathsquad = msg_deathsquad + BR.msg_syndicate = msg_syndicate + BR.msg_cargo = msg_cargo + BR.msg_service = msg_service + BR.feedback = feedback + BR.messages = messages + BR.messages_admin = messages_admin + if(blackbox != BR) + blackbox = BR + ..() + +/obj/machinery/blackbox_recorder/proc/find_feedback_datum(var/variable) + for(var/datum/feedback_variable/FV in feedback) + if(FV.get_variable() == variable) + return FV + var/datum/feedback_variable/FV = new(variable) + feedback += FV + return FV + +/obj/machinery/blackbox_recorder/proc/get_round_feedback() + return feedback + +/obj/machinery/blackbox_recorder/proc/round_end_data_gathering() + + var/pda_msg_amt = 0 + var/rc_msg_amt = 0 + + for(var/obj/machinery/message_server/MS in SSmachines.machinery) + if(MS.pda_msgs.len > pda_msg_amt) + pda_msg_amt = MS.pda_msgs.len + if(MS.rc_msgs.len > rc_msg_amt) + rc_msg_amt = MS.rc_msgs.len + + feedback_set_details("radio_usage","") + + feedback_add_details("radio_usage","COM-[msg_common.len]") + feedback_add_details("radio_usage","SCI-[msg_science.len]") + feedback_add_details("radio_usage","HEA-[msg_command.len]") + feedback_add_details("radio_usage","MED-[msg_medical.len]") + feedback_add_details("radio_usage","ENG-[msg_engineering.len]") + feedback_add_details("radio_usage","SEC-[msg_security.len]") + feedback_add_details("radio_usage","DTH-[msg_deathsquad.len]") + feedback_add_details("radio_usage","SYN-[msg_syndicate.len]") + feedback_add_details("radio_usage","CAR-[msg_cargo.len]") + feedback_add_details("radio_usage","SRV-[msg_service.len]") + feedback_add_details("radio_usage","OTH-[messages.len]") + feedback_add_details("radio_usage","PDA-[pda_msg_amt]") + feedback_add_details("radio_usage","RC-[rc_msg_amt]") + + + feedback_set_details("round_end","[time2text(world.realtime)]") //This one MUST be the last one that gets set. + + +//This proc is only to be called at round end. +/obj/machinery/blackbox_recorder/proc/save_all_data_to_sql() + if(!feedback) return + + round_end_data_gathering() //round_end time logging and some other data processing + establish_db_connection() + if(!dbcon.IsConnected()) return + var/round_id + + var/DBQuery/query = dbcon.NewQuery("SELECT MAX(round_id) AS round_id FROM erro_feedback") + query.Execute() + while(query.NextRow()) + round_id = query.item[1] + + if(!isnum(round_id)) + round_id = text2num(round_id) + round_id++ + + for(var/datum/feedback_variable/FV in feedback) + var/sql = "INSERT INTO erro_feedback VALUES (null, Now(), [round_id], \"[FV.get_variable()]\", [FV.get_value()], \"[FV.get_details()]\")" + var/DBQuery/query_insert = dbcon.NewQuery(sql) + query_insert.Execute() + +// Sanitize inputs to avoid SQL injection attacks +proc/sql_sanitize_text(var/text) + text = replacetext(text, "'", "''") + text = replacetext(text, ";", "") + text = replacetext(text, "&", "") + return text + +proc/feedback_set(var/variable,var/value) + if(!blackbox) return + + variable = sql_sanitize_text(variable) + + var/datum/feedback_variable/FV = blackbox.find_feedback_datum(variable) + + if(!FV) return + + FV.set_value(value) + +proc/feedback_inc(var/variable,var/value) + if(!blackbox) return + + variable = sql_sanitize_text(variable) + + var/datum/feedback_variable/FV = blackbox.find_feedback_datum(variable) + + if(!FV) return + + FV.inc(value) + +proc/feedback_dec(var/variable,var/value) + if(!blackbox) return + + variable = sql_sanitize_text(variable) + + var/datum/feedback_variable/FV = blackbox.find_feedback_datum(variable) + + if(!FV) return + + FV.dec(value) + +proc/feedback_set_details(var/variable,var/details) + if(!blackbox) return + + variable = sql_sanitize_text(variable) + details = sql_sanitize_text(details) + + var/datum/feedback_variable/FV = blackbox.find_feedback_datum(variable) + + if(!FV) return + + FV.set_details(details) + +proc/feedback_add_details(var/variable,var/details) + if(!blackbox) return + + variable = sql_sanitize_text(variable) + details = sql_sanitize_text(details) + + var/datum/feedback_variable/FV = blackbox.find_feedback_datum(variable) + + if(!FV) return + + FV.add_details(details) \ No newline at end of file diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm new file mode 100644 index 00000000..fe5543ed --- /dev/null +++ b/code/modules/research/protolathe.dm @@ -0,0 +1,166 @@ +/obj/machinery/r_n_d/protolathe + name = "\improper Protolathe" + icon_state = "protolathe" + atom_flags = ATOM_FLAG_OPEN_CONTAINER + + use_power = 1 + idle_power_usage = 30 + active_power_usage = 5000 + + var/max_material_storage = 100000 + + var/list/datum/design/queue = list() + var/progress = 0 + + var/mat_efficiency = 1 + var/speed = 1 + +/obj/machinery/r_n_d/protolathe/New() + materials = default_material_composition.Copy() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/protolathe(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(src) + component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(src) + RefreshParts() + +/obj/machinery/r_n_d/protolathe/Process() + ..() + if(stat) + update_icon() + return + if(queue.len == 0) + busy = 0 + update_icon() + return + var/datum/design/D = queue[1] + if(canBuild(D)) + busy = 1 + progress += speed + if(progress >= D.time) + build(D) + progress = 0 + removeFromQueue(1) + if(linked_console) + linked_console.updateUsrDialog() + update_icon() + else + if(busy) + visible_message("\icon [src] flashes: insufficient materials: [getLackingMaterials(D)].") + busy = 0 + update_icon() + +/obj/machinery/r_n_d/protolathe/RefreshParts() + var/T = 0 + for(var/obj/item/weapon/reagent_containers/glass/G in component_parts) + T += G.reagents.maximum_volume + create_reagents(T) + max_material_storage = 0 + for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts) + max_material_storage += M.rating * 75000 + T = 0 + for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) + T += M.rating + mat_efficiency = 1 - (T - 2) / 8 + speed = T / 2 + + +/obj/machinery/r_n_d/protolathe/update_icon() + if(panel_open) + icon_state = "protolathe_t" + else if(busy) + icon_state = "protolathe_n" + else + icon_state = "protolathe" + +/obj/machinery/r_n_d/protolathe/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(busy) + to_chat(user, "\The [src] is busy. Please wait for completion of previous operation.") + return 1 + if(default_deconstruction_screwdriver(user, O)) + if(linked_console) + linked_console.linked_lathe = null + linked_console = null + return + if(default_deconstruction_crowbar(user, O)) + return + if(default_part_replacement(user, O)) + return + if(O.is_open_container()) + return 1 + if(panel_open) + to_chat(user, "You can't load \the [src] while it's opened.") + return 1 + if(!linked_console) + to_chat(user, "\The [src] must be linked to an R&D console first!") + return 1 + if(is_robot_module(O)) + return 0 + if(!istype(O, /obj/item/stack/material)) + to_chat(user, "You cannot insert this item into \the [src]!") + return 0 + if(stat) + return 1 + + if(TotalMaterials() + SHEET_MATERIAL_AMOUNT > max_material_storage) + to_chat(user, "\The [src]'s material bin is full. Please remove material before adding more.") + return 1 + + var/obj/item/stack/material/stack = O + var/amount = min(stack.get_amount(), round((max_material_storage - TotalMaterials()) / SHEET_MATERIAL_AMOUNT)) + + var/t = stack.material.name + overlays += "protolathe_[t]" + spawn(10) + overlays -= "protolathe_[t]" + + busy = 1 + use_power(max(1000, (SHEET_MATERIAL_AMOUNT * amount / 10))) + if(t) + if(do_after(user, 16,src)) + if(stack.use(amount)) + to_chat(user, "You add [amount] sheet\s to \the [src].") + materials[t] += amount * SHEET_MATERIAL_AMOUNT + busy = 0 + updateUsrDialog() + return + +/obj/machinery/r_n_d/protolathe/proc/addToQueue(var/datum/design/D) + queue += D + return + +/obj/machinery/r_n_d/protolathe/proc/removeFromQueue(var/index) + queue.Cut(index, index + 1) + return + +/obj/machinery/r_n_d/protolathe/proc/canBuild(var/datum/design/D) + for(var/M in D.materials) + if(materials[M] < D.materials[M]) + return 0 + for(var/C in D.chemicals) + if(!reagents.has_reagent(C, D.chemicals[C])) + return 0 + return 1 + +/obj/machinery/r_n_d/protolathe/proc/build(var/datum/design/D) + var/power = active_power_usage + for(var/M in D.materials) + power += round(D.materials[M] / 5) + power = max(active_power_usage, power) + use_power(power) + for(var/M in D.materials) + materials[M] = max(0, materials[M] - D.materials[M] * mat_efficiency) + for(var/C in D.chemicals) + reagents.remove_reagent(C, D.chemicals[C] * mat_efficiency) + + if(D.build_path) + var/obj/new_item = D.Fabricate(src, src) + new_item.loc = loc + if(mat_efficiency != 1) // No matter out of nowhere + if(new_item.matter && new_item.matter.len > 0) + for(var/i in new_item.matter) + new_item.matter[i] = new_item.matter[i] * mat_efficiency diff --git a/code/modules/research/rd-readme.dm b/code/modules/research/rd-readme.dm new file mode 100644 index 00000000..4d64a6bf --- /dev/null +++ b/code/modules/research/rd-readme.dm @@ -0,0 +1,32 @@ +/* +Research and Development System. (Designed specifically for the /tg/station 13 (Space Station 13) open source project) + +///////////////Overview/////////////////// +This system is a "tech tree" research and development system designed for SS13. It allows a "researcher" job (this document assumes +the "scientist" job is given this role) the tools necessary to research new and better technologies. In general, the system works +by breaking existing technology and using what you learn from to advance your knowledge of SCIENCE! As your knowledge progresses, +you can build newer (and better?) devices (which you can also, eventually, deconstruct to advance your knowledge). + +A brief overview is below. For more details, see the related files. + +////////////Game Use///////////// +The major research and development is performed using a combination of four machines: +- R&D Console: A computer console that allows you to manipulate the other devices that are linked to it and view/manipulate the +technologies you have researched so far. +- Protolathe: Used to make new hand-held devices and parts for larger devices. All metals and reagents as raw materials. +- Destructive Analyzer: You can put hand-held objects into it and it'll analyze them for technological advancements but it destroys +them in the process. Destroyed items will send their raw materials to a linked Protolathe (if any) +- Circuit Imprinter: Similar to the Protolathe, it allows for the construction of circuit boards. Uses glass and acid as the raw +materials. + +While researching you are dealing with two different types of information: Technology Paths and Device Designs. Technology Paths +are the "Tech Trees" of the game. You start out with a number of them at the game start and they are improved by using the +Destructive Analyzer. By themselves, they don't do a whole lot. However, they unlock Device Designs. This is the information used +by the circuit imprinter and the protolathe to produce objects. It also tracks the current reliability of that particular design. + +//EXISTING TECH +Each tech path should have at LEAST one item at every level (levels 1 - 20). This is to allow for a more fluid progression of the +researching. Existing tech (ie, anything you can find on the station or get from the quartermaster) shouldn't go higher then +level 5 or 7. Everything past that should be stuff you research. + +*/ \ No newline at end of file diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm new file mode 100644 index 00000000..4c2b6deb --- /dev/null +++ b/code/modules/research/rdconsole.dm @@ -0,0 +1,816 @@ +/* +Research and Development (R&D) Console + +This is the main work horse of the R&D system. It contains the menus/controls for the Destructive Analyzer, Protolathe, and Circuit +imprinter. It also contains the /datum/research holder with all the known/possible technology paths and device designs. + +Basic use: When it first is created, it will attempt to link up to related devices within 3 squares. It'll only link up if they +aren't already linked to another console. Any consoles it cannot link up with (either because all of a certain type are already +linked or there aren't any in range), you'll just not have access to that menu. In the settings menu, there are menu options that +allow a player to attempt to re-sync with nearby consoles. You can also force it to disconnect from a specific console. + +The imprinting and construction menus do NOT require toxins access to access but all the other menus do. However, if you leave it +on a menu, nothing is to stop the person from using the options on that menu (although they won't be able to change to a different +one). You can also lock the console on the settings menu if you're feeling paranoid and you don't want anyone messing with it who +doesn't have toxins access. + +When a R&D console is destroyed or even partially disassembled, you lose all research data on it. However, there are two ways around +this dire fate: +- The easiest way is to go to the settings menu and select "Sync Database with Network." That causes it to upload (but not download) +it's data to every other device in the game. Each console has a "disconnect from network" option that'll will cause data base sync +operations to skip that console. This is useful if you want to make a "public" R&D console or, for example, give the engineers +a circuit imprinter with certain designs on it and don't want it accidentally updating. The downside of this method is that you have +to have physical access to the other console to send data back. Note: An R&D console is on CentCom so if a random griffan happens to +cause a ton of data to be lost, an admin can go send it back. +- The second method is with Technology Disks and Design Disks. Each of these disks can hold a single technology or design datum in +it's entirety. You can then take the disk to any R&D console and upload it's data to it. This method is a lot more secure (since it +won't update every console in existence) but it's more of a hassle to do. Also, the disks can be stolen. +*/ + +/obj/machinery/computer/rdconsole + name = "fabrication control console" + desc = "Console controlling the various fabrication devices. Uses self-learning matrix to hold and optimize blueprints. Prone to corrupting said matrix, so back up often." + icon_keyboard = "rd_key" + icon_screen = "rdcomp" + light_color = "#a97faa" + circuit = /obj/item/weapon/circuitboard/rdconsole + var/datum/research/files //Stores all the collected research data. + var/obj/item/weapon/disk/tech_disk/t_disk = null //Stores the technology disk. + var/obj/item/weapon/disk/design_disk/d_disk = null //Stores the design disk. + + var/obj/machinery/r_n_d/destructive_analyzer/linked_destroy = null //Linked Destructive Analyzer + var/obj/machinery/r_n_d/protolathe/linked_lathe = null //Linked Protolathe + var/obj/machinery/r_n_d/circuit_imprinter/linked_imprinter = null //Linked Circuit Imprinter + + var/screen = 1.0 //Which screen is currently showing. + var/id = 0 //ID of the computer (for server restrictions). + var/sync = 1 //If sync = 0, it doesn't show up on Server Control Console + + req_access = list(access_research) //Data and setting manipulation requires scientist access. + +/obj/machinery/computer/rdconsole/proc/CallMaterialName(var/ID) + var/return_name = ID + switch(return_name) + if("metal") + return_name = "Metal" + if("glass") + return_name = "Glass" + if("gold") + return_name = "Gold" + if("silver") + return_name = "Silver" + if("phoron") + return_name = "Solid Phoron" + if("uranium") + return_name = "Uranium" + if("diamond") + return_name = "Diamond" + return return_name + +/obj/machinery/computer/rdconsole/proc/CallReagentName(var/reagent_type) + var/datum/reagent/R = reagent_type + return ispath(reagent_type, /datum/reagent) ? initial(R.name) : "Unknown" + +/obj/machinery/computer/rdconsole/proc/SyncRDevices() //Makes sure it is properly sync'ed up with the devices attached to it (if any). + for(var/obj/machinery/r_n_d/D in range(4, src)) + if(D.linked_console != null || D.panel_open) + continue + if(istype(D, /obj/machinery/r_n_d/destructive_analyzer)) + if(linked_destroy == null) + linked_destroy = D + D.linked_console = src + else if(istype(D, /obj/machinery/r_n_d/protolathe)) + if(linked_lathe == null) + linked_lathe = D + D.linked_console = src + else if(istype(D, /obj/machinery/r_n_d/circuit_imprinter)) + if(linked_imprinter == null) + linked_imprinter = D + D.linked_console = src + return + +/obj/machinery/computer/rdconsole/proc/add_ic_design(var/obj/item/device/electronic_assembly/assembly) + files.AddDesign2Known(new /datum/design/prefab(files,create_prefab_from_assembly(assembly))) + +/obj/machinery/computer/rdconsole/proc/griefProtection() //Have it automatically push research to the centcomm server so wild griffins can't fuck up R&D's work + for(var/obj/machinery/r_n_d/server/centcom/C in SSmachines.machinery) + for(var/datum/tech/T in files.known_tech) + C.files.AddTech2Known(T) + for(var/datum/design/D in files.known_designs) + C.files.AddDesign2Known(D) + C.files.RefreshResearch() + +/obj/machinery/computer/rdconsole/New() + ..() + files = new /datum/research(src) //Setup the research data holder. + if(!id) + for(var/obj/machinery/r_n_d/server/centcom/S in SSmachines.machinery) + S.update_connections() + break + +/obj/machinery/computer/rdconsole/Initialize() + SyncRDevices() + . = ..() + +/obj/machinery/computer/rdconsole/attackby(var/obj/item/weapon/D as obj, var/mob/user as mob) + //Loading a disk into it. + if(istype(D, /obj/item/weapon/disk)) + if(t_disk || d_disk) + to_chat(user, "A disk is already loaded into the machine.") + return + + if(istype(D, /obj/item/weapon/disk/tech_disk)) + t_disk = D + else if (istype(D, /obj/item/weapon/disk/design_disk)) + d_disk = D + else + to_chat(user, "Machine cannot accept disks in that format.") + return + user.drop_item() + D.loc = src + to_chat(user, "You add \the [D] to the machine.") + else + //The construction/deconstruction of the console code. + ..() + + src.updateUsrDialog() + return + +/obj/machinery/computer/rdconsole/emp_act(var/remaining_charges, var/mob/user) + if(!emagged) + playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1) + emagged = 1 + to_chat(user, "You you disable the security protocols.") + return 1 + +/obj/machinery/computer/rdconsole/CanUseTopic(var/mob/user, var/datum/topic_state/state, var/href_list) + if(href_list["menu"]) + var/temp_screen = text2num(href_list["menu"]) + if(!(temp_screen <= 1.1 || (3 <= temp_screen && 4.9 >= temp_screen) || allowed(usr) || emagged)) + to_chat(usr, "Unauthorized Access.") + return STATUS_CLOSE + return ..() + +/obj/machinery/computer/rdconsole/OnTopic(user, href_list) + if(href_list["menu"]) //Switches menu screens. Converts a sent text string into a number. Saves a LOT of code. + screen = text2num(href_list["menu"]) + . = TOPIC_REFRESH + + else if(href_list["updt_tech"]) //Update the research holder with information from the technology disk. + screen = 0.0 + . = TOPIC_REFRESH + spawn(50) + screen = 1.2 + files.AddTech2Known(t_disk.stored) + updateUsrDialog() + griefProtection() //Update centcomm too + + else if(href_list["clear_tech"]) //Erase data on the technology disk. + t_disk.stored = null + . = TOPIC_REFRESH + + else if(href_list["eject_tech"]) //Eject the technology disk. + t_disk.dropInto(loc) + t_disk = null + screen = 1.0 + . = TOPIC_REFRESH + + else if(href_list["copy_tech"]) //Copys some technology data from the research holder to the disk. + for(var/datum/tech/T in files.known_tech) + if(href_list["copy_tech_ID"] == T.id) + t_disk.stored = T + break + screen = 1.2 + . = TOPIC_REFRESH + + else if(href_list["updt_design"]) //Updates the research holder with design data from the design disk. + screen = 0.0 + . = TOPIC_REFRESH + spawn(50) + screen = 1.4 + files.AddDesign2Known(d_disk.blueprint) + updateUsrDialog() + griefProtection() //Update centcomm too + + else if(href_list["clear_design"]) //Erases data on the design disk. + d_disk.blueprint = null + . = TOPIC_REFRESH + + else if(href_list["eject_design"]) //Eject the design disk. + d_disk.dropInto(loc) + d_disk = null + screen = 1.0 + + else if(href_list["copy_design"]) //Copy design data from the research holder to the design disk. + for(var/datum/design/D in files.known_designs) + if(href_list["copy_design_ID"] == D.id) + d_disk.blueprint = D + break + screen = 1.4 + . = TOPIC_REFRESH + + else if(href_list["eject_item"]) //Eject the item inside the destructive analyzer. + if(linked_destroy) + if(linked_destroy.busy) + to_chat(usr, "The destructive analyzer is busy at the moment.") + + else if(linked_destroy.loaded_item) + linked_destroy.loaded_item.dropInto(linked_destroy.loc) + linked_destroy.loaded_item = null + linked_destroy.icon_state = "d_analyzer" + screen = 2.1 + . = TOPIC_REFRESH + + else if(href_list["deconstruct"]) //Deconstruct the item in the destructive analyzer and update the research holder. + if(linked_destroy) + if(linked_destroy.busy) + to_chat(usr, "The destructive analyzer is busy at the moment.") + else + if(alert("Proceeding will destroy loaded item. Continue?", "Destructive analyzer confirmation", "Yes", "No") == "No" || !linked_destroy) + return + linked_destroy.busy = 1 + screen = 0.1 + . = TOPIC_REFRESH + flick("d_analyzer_process", linked_destroy) + spawn(24) + if(linked_destroy) + linked_destroy.busy = 0 + if(!linked_destroy.loaded_item) + to_chat(usr, "The destructive analyzer appears to be empty.") + screen = 1.0 + return + if(istype(linked_destroy.loaded_item, /obj/item/device/electronic_assembly)) + add_ic_design(linked_destroy.loaded_item) + else + for(var/T in linked_destroy.loaded_item.origin_tech) + files.UpdateTech(T, linked_destroy.loaded_item.origin_tech[T]) + if(linked_lathe && linked_destroy.loaded_item.matter) // Also sends salvaged materials to a linked protolathe, if any. + for(var/t in linked_destroy.loaded_item.matter) + if(t in linked_lathe.materials) + linked_lathe.materials[t] += min(linked_lathe.max_material_storage - linked_lathe.TotalMaterials(), linked_destroy.loaded_item.matter[t] * linked_destroy.decon_mod) + + linked_destroy.loaded_item = null + for(var/obj/I in linked_destroy.contents) + for(var/mob/M in I.contents) + M.death() + if(istype(I,/obj/item/stack/material))//Only deconsturcts one sheet at a time instead of the entire stack + var/obj/item/stack/material/S = I + if(S.get_amount() > 1) + S.use(1) + linked_destroy.loaded_item = S + else + qdel(S) + linked_destroy.icon_state = "d_analyzer" + else + if(!(I in linked_destroy.component_parts)) + qdel(I) + linked_destroy.icon_state = "d_analyzer" + + use_power(linked_destroy.active_power_usage) + screen = 1.0 + attack_hand(user) + . = TOPIC_REFRESH + + else if(href_list["lock"]) //Lock the console from use by anyone without tox access. + if(allowed(usr)) + screen = text2num(href_list["lock"]) + else + to_chat(usr, "Unauthorized Access.") + . = TOPIC_REFRESH + + else if(href_list["sync"]) //Sync the research holder with all the R&D consoles in the game that aren't sync protected. + screen = 0.0 + if(!sync) + to_chat(usr, "You must connect to the network first.") + else + . = TOPIC_HANDLED + griefProtection() //Putting this here because I dont trust the sync process + spawn(30) + if(src) + for(var/obj/machinery/r_n_d/server/S in SSmachines.machinery) + var/server_processed = 0 + if((id in S.id_with_upload) || istype(S, /obj/machinery/r_n_d/server/centcom)) + for(var/datum/tech/T in files.known_tech) + S.files.AddTech2Known(T) + for(var/datum/design/D in files.known_designs) + S.files.AddDesign2Known(D) + S.files.RefreshResearch() + server_processed = 1 + if((id in S.id_with_download) && !istype(S, /obj/machinery/r_n_d/server/centcom)) + for(var/datum/tech/T in S.files.known_tech) + files.AddTech2Known(T) + for(var/datum/design/D in S.files.known_designs) + files.AddDesign2Known(D) + files.RefreshResearch() + server_processed = 1 + if(!istype(S, /obj/machinery/r_n_d/server/centcom) && server_processed) + S.produce_heat() + screen = 1.6 + attack_hand(user) + + else if(href_list["togglesync"]) //Prevents the console from being synced by other consoles. Can still send data. + sync = !sync + . = TOPIC_REFRESH + + else if(href_list["build"]) //Causes the Protolathe to build something. + if(linked_lathe) + var/datum/design/being_built = null + for(var/datum/design/D in files.known_designs) + if(D.id == href_list["build"]) + being_built = D + break + if(being_built) + linked_lathe.addToQueue(being_built) + + screen = 3.1 + . = TOPIC_REFRESH + + else if(href_list["imprint"]) //Causes the Circuit Imprinter to build something. + if(linked_imprinter) + var/datum/design/being_built = null + for(var/datum/design/D in files.known_designs) + if(D.id == href_list["imprint"]) + being_built = D + break + if(being_built) + linked_imprinter.addToQueue(being_built) + screen = 4.1 + . = TOPIC_REFRESH + + else if(href_list["disposeI"] && linked_imprinter) //Causes the circuit imprinter to dispose of a single reagent (all of it) + var/datum/reagent/R = locate(href_list["disposeI"]) in linked_imprinter.reagents.reagent_list + if(R) + linked_imprinter.reagents.del_reagent(href_list["dispose"]) + . = TOPIC_REFRESH + + else if(href_list["disposeallI"] && linked_imprinter) //Causes the circuit imprinter to dispose of all it's reagents. + linked_imprinter.reagents.clear_reagents() + . = TOPIC_REFRESH + + else if(href_list["removeI"] && linked_lathe) + linked_imprinter.removeFromQueue(text2num(href_list["removeI"])) + . = TOPIC_REFRESH + + else if(href_list["disposeP"] && linked_lathe) //Causes the protolathe to dispose of a single reagent (all of it) + var/datum/reagent/R = locate(href_list["disposeP"]) in linked_lathe.reagents.reagent_list + if(R) + linked_lathe.reagents.del_reagent(R.type) + . = TOPIC_REFRESH + + else if(href_list["disposeallP"] && linked_lathe) //Causes the protolathe to dispose of all it's reagents. + linked_lathe.reagents.clear_reagents() + . = TOPIC_REFRESH + + else if(href_list["removeP"] && linked_lathe) + linked_lathe.removeFromQueue(text2num(href_list["removeP"])) + . = TOPIC_REFRESH + + else if(href_list["lathe_ejectsheet"] && linked_lathe) //Causes the protolathe to eject a sheet of material + linked_lathe.eject(href_list["lathe_ejectsheet"], text2num(href_list["amount"])) + . = TOPIC_REFRESH + + else if(href_list["imprinter_ejectsheet"] && linked_imprinter) //Causes the protolathe to eject a sheet of material + linked_imprinter.eject(href_list["imprinter_ejectsheet"], text2num(href_list["amount"])) + . = TOPIC_REFRESH + + else if(href_list["find_device"]) //The R&D console looks for devices nearby to link up with. + screen = 0.0 + . = TOPIC_HANDLED + spawn(10) + SyncRDevices() + screen = 1.7 + attack_hand(user) + + else if(href_list["disconnect"]) //The R&D console disconnects with a specific device. + switch(href_list["disconnect"]) + if("destroy") + linked_destroy.linked_console = null + linked_destroy = null + if("lathe") + linked_lathe.linked_console = null + linked_lathe = null + if("imprinter") + linked_imprinter.linked_console = null + linked_imprinter = null + . = TOPIC_REFRESH + + else if(href_list["reset"]) //Reset the R&D console's database. + griefProtection() + var/choice = alert("R&D Console Database Reset", "Are you sure you want to reset the R&D console's database? Data lost cannot be recovered.", "Continue", "Cancel") + . = TOPIC_HANDLED + if(choice == "Continue") + screen = 0.0 + qdel(files) + files = new /datum/research(src) + spawn(20) + screen = 1.6 + attack_hand(user) + + else if (href_list["print"]) //Print research information + screen = 0.5 + . = TOPIC_HANDLED + spawn(20) + var/obj/item/weapon/paper/PR = new/obj/item/weapon/paper + PR.name = "fabricator report" + PR.info = "
            [station_name()] Fabricator Laboratory" + PR.info += "

            [ (text2num(href_list["print"]) == 2) ? "Detailed" : ""] Fabricator Status Report

            " + PR.info += "report prepared at [stationtime2text()] local time

            " + if(text2num(href_list["print"]) == 2) + PR.info += GetResearchListInfo() + else + PR.info += GetResearchLevelsInfo() + PR.info_links = PR.info + PR.icon_state = "paper_words" + PR.dropInto(loc) + spawn(10) + screen = ((text2num(href_list["print"]) == 2) ? 5.0 : 1.1) + attack_hand(user) + + if(. == TOPIC_REFRESH) + attack_hand(user) + +/obj/machinery/computer/rdconsole/proc/GetResearchLevelsInfo() + var/dat + dat += "
              " + for(var/datum/tech/T in files.known_tech) + if(T.level < 1) + continue + dat += "
            • " + dat += "[T.name]" + dat += "
                " + dat += "
              • Level: [T.level]" + dat += "
              • Summary: [T.desc]" + dat += "
              " + return dat + +/obj/machinery/computer/rdconsole/proc/GetResearchListInfo() + var/dat + dat += "
                " + for(var/datum/design/D in files.known_designs) + if(D.build_path) + dat += "
              • [D.name]: [D.desc]" + dat += "
              " + return dat + +/obj/machinery/computer/rdconsole/attack_hand(mob/user as mob) + if(stat & (BROKEN|NOPOWER)) + return + + user.set_machine(src) + var/dat = "" + files.RefreshResearch() + switch(screen) //A quick check to make sure you get the right screen when a device is disconnected. + if(2 to 2.9) + if(linked_destroy == null) + screen = 2.0 + else if(linked_destroy.loaded_item == null) + screen = 2.1 + else + screen = 2.2 + if(3 to 3.9) + if(linked_lathe == null) + screen = 3.0 + if(4 to 4.9) + if(linked_imprinter == null) + screen = 4.0 + + switch(screen) + + //////////////////////R&D CONSOLE SCREENS////////////////// + if(0.0) + dat += "Updating Database..." + + if(0.1) + dat += "Processing and Updating Database..." + + if(0.2) + dat += "SYSTEM LOCKED

              " + dat += "Unlock" + + if(0.3) + dat += "Constructing Prototype. Please Wait..." + + if(0.4) + dat += "Imprinting Circuit. Please Wait..." + + if(0.5) + dat += "Printing. Please Wait..." + + if(1.0) //Main Menu + dat += "Main Menu:

              " + dat += "Loaded disk: " + dat += (t_disk || d_disk) ? (t_disk ? "technology storage disk" : "design storage disk") : "none" + dat += "
              " + + if(1.1) //Research viewer + dat += "Main Menu || " + dat += "Print This Page
              " + dat += "Fabricator Learning Matrix Proficiency Levels:

              " + dat += GetResearchLevelsInfo() + dat += "
            " + + if(1.2) //Technology Disk Menu + + dat += "Main Menu
            " + dat += "Disk Contents: (Technology Data Disk)

            " + if(t_disk.stored == null) + dat += "The disk has no data stored on it.
            " + dat += "Operations: " + dat += "Load Tech to Disk || " + else + dat += "Name: [t_disk.stored.name]
            " + dat += "Level: [t_disk.stored.level]
            " + dat += "Description: [t_disk.stored.desc]
            " + dat += "Operations: " + dat += "Upload to Database || " + dat += "Clear Disk || " + dat += "Eject Disk" + + if(1.3) //Technology Disk submenu + dat += "
            Main Menu || " + dat += "Return to Disk Operations
            " + dat += "Load Technology to Disk:

            " + dat += "
              " + for(var/datum/tech/T in files.known_tech) + dat += "
            • [T.name] " + dat += "\[copy to disk\]" + dat += "
            " + + if(1.4) //Design Disk menu. + dat += "Main Menu
            " + if(d_disk.blueprint == null) + dat += "The disk has no data stored on it.
            " + dat += "Operations: " + dat += "Load Design to Disk || " + else + dat += "Name: [d_disk.blueprint.name]
            " + switch(d_disk.blueprint.build_type) + if(IMPRINTER) dat += "Lathe Type: Circuit Imprinter
            " + if(PROTOLATHE) dat += "Lathe Type: Proto-lathe
            " + dat += "Required Materials:
            " + for(var/M in d_disk.blueprint.materials) + if(copytext(M, 1, 2) == "$") dat += "* [copytext(M, 2)] x [d_disk.blueprint.materials[M]]
            " + else dat += "* [M] x [d_disk.blueprint.materials[M]]
            " + dat += "
            Operations: " + dat += "Upload to Database || " + dat += "Clear Disk || " + dat += "Eject Disk" + + if(1.5) //Technology disk submenu + dat += "Main Menu || " + dat += "Return to Disk Operations
            " + dat += "Load Design to Disk:

            " + dat += "
              " + for(var/datum/design/D in files.known_designs) + if(D.build_path) + dat += "
            • [D.name] " + dat += "\[copy to disk\]" + dat += "
            " + + if(1.6) //R&D console settings + dat += "Main Menu
            " + dat += "R&D Console Setting:
            " + dat += "
              " + if(sync) + dat += "
            • Sync Database with Network
              " + dat += "
            • Disconnect from Fabrication Network
              " + else + dat += "
            • Connect to Fabrication Network
              " + dat += "
            • Device Linkage Menu
              " + dat += "
            • Lock Console
              " + dat += "
            • Reset R&D Database
              " + dat += "
                " + + if(1.7) //R&D device linkage + dat += "Main Menu || " + dat += "Settings Menu
                " + dat += "R&D Console Device Linkage Menu:

                " + dat += "Re-sync with Nearby Devices
                " + dat += "Linked Devices:" + dat += "
                  " + if(linked_destroy) + dat += "
                • Destructive Analyzer (Disconnect)" + else + dat += "
                • (No Destructive Analyzer Linked)" + if(linked_lathe) + dat += "
                • Protolathe (Disconnect)" + else + dat += "
                • (No Protolathe Linked)" + if(linked_imprinter) + dat += "
                • Circuit Imprinter (Disconnect)" + else + dat += "
                • (No Circuit Imprinter Linked)" + dat += "
                " + + ////////////////////DESTRUCTIVE ANALYZER SCREENS//////////////////////////// + if(2.0) + dat += "Main Menu
                " + dat += "NO DESTRUCTIVE ANALYZER LINKED TO CONSOLE

                " + + if(2.1) + dat += "Main Menu
                " + dat += "No Item Loaded. Standing-by...

                " + + if(2.2) + dat += "Main Menu
                " + dat += "Deconstruction Menu
                " + dat += "Name: [linked_destroy.loaded_item.name]
                " + if(istype(linked_destroy.loaded_item, /obj/item/device/electronic_assembly)) + dat += "Assembly Detected. Prepared for blueprint download." + dat += "Warning: Assemblies manafactured this way will not have removable circuits." + else + dat += "Origin Tech:" + dat += "
                  " + for(var/T in linked_destroy.loaded_item.origin_tech) + dat += "
                • [CallTechName(T)] [linked_destroy.loaded_item.origin_tech[T]]" + for(var/datum/tech/F in files.known_tech) + if(F.name == CallTechName(T)) + dat += " (Current: [F.level])" + break + dat += "
                " + dat += "
                Deconstruct Item || " + dat += "Eject Item || " + + /////////////////////PROTOLATHE SCREENS///////////////////////// + if(3.0) + dat += "Main Menu
                " + dat += "NO PROTOLATHE LINKED TO CONSOLE

                " + + if(3.1) + dat += "Main Menu || " + dat += "View Queue || " + dat += "Material Storage || " + dat += "Chemical Storage
                " + dat += "Protolathe Menu:

                " + dat += "Material Amount: [linked_lathe.TotalMaterials()] cm3 (MAX: [linked_lathe.max_material_storage])
                " + dat += "Chemical Volume: [linked_lathe.reagents.total_volume] (MAX: [linked_lathe.reagents.maximum_volume])
                " + dat += "
                  " + for(var/datum/design/D in files.known_designs) + if(!D.build_path || !(D.build_type & PROTOLATHE)) + continue + var/temp_dat + for(var/M in D.materials) + temp_dat += ", [D.materials[M]] [CallMaterialName(M)]" + for(var/T in D.chemicals) + temp_dat += ", [D.chemicals[T]*linked_imprinter.mat_efficiency] [CallReagentName(T)]" + if(temp_dat) + temp_dat = " \[[copytext(temp_dat, 3)]\]" + if(linked_lathe.canBuild(D)) + dat += "
                • [D.name][temp_dat]" + else + dat += "
                • [D.name][temp_dat]" + dat += "
                " + + if(3.2) //Protolathe Material Storage Sub-menu + dat += "Main Menu || " + dat += "Protolathe Menu
                " + dat += "Material Storage

                " + dat += "
                  " + for(var/M in linked_lathe.materials) + var/amount = linked_lathe.materials[M] + dat += "
                • [capitalize(M)]: [amount] cm3" + if(amount >= SHEET_MATERIAL_AMOUNT) + dat += " || Eject " + for (var/C in list(1, 3, 5, 10, 15, 20, 25, 30, 40)) + if(amount < C * SHEET_MATERIAL_AMOUNT) + break + dat += "[C > 1 ? ", " : ""][C] " + + dat += " or max sheets" + dat += "" + dat += "
                " + + if(3.3) //Protolathe Chemical Storage Submenu + dat += "Main Menu || " + dat += "Protolathe Menu
                " + dat += "Chemical Storage

                " + for(var/datum/reagent/R in linked_lathe.reagents.reagent_list) + dat += "Name: [R.name] | Units: [R.volume] " + dat += "(Purge)
                " + dat += "Disposal All Chemicals in Storage
                " + + if(3.4) // Protolathe queue + dat += "Main Menu || " + dat += "Protolathe Menu
                " + dat += "Queue

                " + if(!linked_lathe.queue.len) + dat += "Empty" + else + var/tmp = 1 + for(var/datum/design/D in linked_lathe.queue) + if(tmp == 1) + if(linked_lathe.busy) + dat += "1: [D.name]
                " + else + dat += "1: [D.name] (Awaiting materials) (Remove)
                " + else + dat += "[tmp]: [D.name] (Remove)
                " + ++tmp + + ///////////////////CIRCUIT IMPRINTER SCREENS//////////////////// + if(4.0) + dat += "Main Menu
                " + dat += "NO CIRCUIT IMPRINTER LINKED TO CONSOLE

                " + + if(4.1) + dat += "Main Menu || " + dat += "View Queue || " + dat += "Material Storage || " + dat += "Chemical Storage
                " + dat += "Circuit Imprinter Menu:

                " + dat += "Material Amount: [linked_imprinter.TotalMaterials()] cm3
                " + dat += "Chemical Volume: [linked_imprinter.reagents.total_volume]
                " + dat += "
                  " + for(var/datum/design/D in files.known_designs) + if(!D.build_path || !(D.build_type & IMPRINTER)) + continue + var/temp_dat + for(var/M in D.materials) + temp_dat += ", [D.materials[M]*linked_imprinter.mat_efficiency] [CallMaterialName(M)]" + for(var/T in D.chemicals) + temp_dat += ", [D.chemicals[T]*linked_imprinter.mat_efficiency] [CallReagentName(T)]" + if(temp_dat) + temp_dat = " \[[copytext(temp_dat,3)]\]" + if(linked_imprinter.canBuild(D)) + dat += "
                • [D.name][temp_dat]" + else + dat += "
                • [D.name][temp_dat]" + dat += "
                " + + if(4.2) + dat += "Main Menu || " + dat += "Imprinter Menu
                " + dat += "Chemical Storage

                " + for(var/datum/reagent/R in linked_imprinter.reagents.reagent_list) + dat += "Name: [R.name] | Units: [R.volume] " + dat += "(Purge)
                " + dat += "Disposal All Chemicals in Storage
                " + + if(4.3) + dat += "Main Menu || " + dat += "Circuit Imprinter Menu
                " + dat += "Material Storage

                " + dat += "
                  " + for(var/M in linked_imprinter.materials) + var/amount = linked_imprinter.materials[M] + dat += "
                • [capitalize(M)]: [amount] cm3" + if(amount >= SHEET_MATERIAL_AMOUNT) + dat += " || Eject: " + for (var/C in list(1, 3, 5, 10, 15, 20, 25, 30, 40)) + if(amount < C * SHEET_MATERIAL_AMOUNT) + break + dat += "[C > 1 ? ", " : ""][C] " + + dat += " or max sheets" + dat += "" + dat += "
                " + + if(4.4) + dat += "Main Menu || " + dat += "Circuit Imprinter Menu
                " + dat += "Queue

                " + if(linked_imprinter.queue.len == 0) + dat += "Empty" + else + var/tmp = 1 + for(var/datum/design/D in linked_imprinter.queue) + if(tmp == 1) + dat += "1: [D.name]
                " + else + dat += "[tmp]: [D.name] (Remove)
                " + ++tmp + + ///////////////////Research Information Browser//////////////////// + if(5.0) + dat += "Main Menu || " + dat += "Print This Page
                " + dat += "List of Available Designs:" + dat += GetResearchListInfo() + + user << browse("Fabrication Control Console
                [dat]", "window=rdconsole;size=850x600") + onclose(user, "rdconsole") + +/obj/machinery/computer/rdconsole/robotics + name = "robotics fabrication console" + id = 2 + req_access = list(access_robotics) + +/obj/machinery/computer/rdconsole/core + name = "core fabricator console" + id = 1 diff --git a/code/modules/research/rdmachines.dm b/code/modules/research/rdmachines.dm new file mode 100644 index 00000000..f95fb1d1 --- /dev/null +++ b/code/modules/research/rdmachines.dm @@ -0,0 +1,58 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +//All devices that link into the R&D console fall into thise type for easy identification and some shared procs. + +var/list/default_material_composition = list("steel" = 0, "glass" = 0, "gold" = 0, "silver" = 0, "phoron" = 0, "uranium" = 0, "diamond" = 0) +/obj/machinery/r_n_d + name = "R&D Device" + icon = 'icons/obj/machines/research.dmi' + density = 1 + anchored = 1 + use_power = 1 + var/busy = 0 + var/obj/machinery/computer/rdconsole/linked_console + + var/list/materials = list() + +/obj/machinery/r_n_d/attack_hand(mob/user as mob) + return + +/obj/machinery/r_n_d/dismantle() + for(var/obj/I in component_parts) + if(istype(I, /obj/item/weapon/reagent_containers/glass/beaker)) + reagents.trans_to_obj(I, reagents.total_volume) + for(var/f in materials) + if(materials[f] >= SHEET_MATERIAL_AMOUNT) + var/path = get_material_by_name(f) + if(path) + var/obj/item/stack/S = new f(loc) + S.amount = round(materials[f] / SHEET_MATERIAL_AMOUNT) + ..() + + +/obj/machinery/r_n_d/proc/eject(var/material, var/amount) + if(!(material in materials)) + return + var/material/mat = get_material_by_name(material) + var/obj/item/stack/material/sheetType = mat.stack_type + var/perUnit = initial(sheetType.perunit) + var/eject = round(materials[material] / perUnit) + eject = amount == -1 ? eject : min(eject, amount) + if(eject < 1) + return + new sheetType(loc, eject) + materials[material] -= eject * perUnit + +/obj/machinery/r_n_d/proc/TotalMaterials() + for(var/f in materials) + . += materials[f] + +/obj/machinery/r_n_d/proc/getLackingMaterials(var/datum/design/D) + var/list/ret = list() + for(var/M in D.materials) + if(materials[M] < D.materials[M]) + ret += "[D.materials[M] - materials[M]] [M]" + for(var/C in D.chemicals) + if(!reagents.has_reagent(C, D.chemicals[C])) + ret += C + return english_list(ret) diff --git a/code/modules/research/research.dm b/code/modules/research/research.dm new file mode 100644 index 00000000..ff0293e7 --- /dev/null +++ b/code/modules/research/research.dm @@ -0,0 +1,219 @@ +/* +General Explination: +The research datum is the "folder" where all the research information is stored in a R&D console. It's also a holder for all the +various procs used to manipulate it. It has four variables and seven procs: + +Variables: +- possible_tech is a list of all the /datum/tech that can potentially be researched by the player. The RefreshResearch() proc +(explained later) only goes through those when refreshing what you know. Generally, possible_tech contains ALL of the existing tech +but it is possible to add tech to the game that DON'T start in it (example: Xeno tech). Generally speaking, you don't want to mess +with these since they should be the default version of the datums. They're actually stored in a list rather then using typesof to +refer to them since it makes it a bit easier to search through them for specific information. +- know_tech is the companion list to possible_tech. It's the tech you can actually research and improve. Until it's added to this +list, it can't be improved. All the tech in this list are visible to the player. +- possible_designs is functionally identical to possbile_tech except it's for /datum/design. +- known_designs is functionally identical to known_tech except it's for /datum/design + +Procs: +- TechHasReqs: Used by other procs (specifically RefreshResearch) to see whether all of a tech's requirements are currently in +known_tech and at a high enough level. +- DesignHasReqs: Same as TechHasReqs but for /datum/design and known_design. +- AddTech2Known: Adds a /datum/tech to known_tech. It checks to see whether it already has that tech (if so, it just replaces it). If +it doesn't have it, it adds it. Note: It does NOT check possible_tech at all. So if you want to add something strange to it (like +a player made tech?) you can. +- AddDesign2Known: Same as AddTech2Known except for /datum/design and known_designs. +- RefreshResearch: This is the workhorse of the R&D system. It updates the /datum/research holder and adds any unlocked tech paths +and designs you have reached the requirements for. It only checks through possible_tech and possible_designs, however, so it won't +accidentally add "secret" tech to it. +- UpdateTech is used as part of the actual researching process. It takes an ID and finds techs with that same ID in known_tech. When +it finds it, it checks to see whether it can improve it at all. If the known_tech's level is less then or equal to +the inputted level, it increases the known tech's level to the inputted level -1 or know tech's level +1 (whichever is higher). + +The tech datums are the actual "tech trees" that you improve through researching. Each one has five variables: +- Name: Pretty obvious. This is often viewable to the players. +- Desc: Pretty obvious. Also player viewable. +- ID: This is the unique ID of the tech that is used by the various procs to find and/or maniuplate it. +- Level: This is the current level of the tech. All techs start at 1 and have a max of 20. Devices and some techs require a certain +level in specific techs before you can produce them. +- Req_tech: This is a list of the techs required to unlock this tech path. If left blank, it'll automatically be loaded into the +research holder datum. + +*/ +/*************************************************************** +** Master Types ** +** Includes all the helper procs and basic tech processing. ** +***************************************************************/ + +/datum/research //Holder for all the existing, archived, and known tech. Individual to console. + var/list/known_tech = list() //List of locally known tech. Datum/tech go here. + var/list/possible_designs = list() //List of all designs. + var/list/known_designs = list() //List of available designs. + +/datum/research/New() //Insert techs into possible_tech here. Known_tech automatically updated. + for(var/T in typesof(/datum/tech) - /datum/tech) + known_tech += new T(src) + for(var/D in typesof(/datum/design) - /datum/design) + possible_designs += new D(src) + RefreshResearch() + +/datum/research/techonly + +/datum/research/techonly/New() + for(var/T in typesof(/datum/tech) - /datum/tech) + known_tech += new T(src) + RefreshResearch() + +//Checks to see if design has all the required pre-reqs. +//Input: datum/design; Output: 0/1 (false/true) +/datum/research/proc/DesignHasReqs(var/datum/design/D) + if(D.req_tech.len == 0) + return 1 + + var/list/k_tech = list() + + for(var/datum/tech/known in known_tech) + k_tech[known.id] = known.level + + for(var/req in D.req_tech) + if(isnull(k_tech[req]) || k_tech[req] < D.req_tech[req]) + return 0 + + return 1 + +//Adds a tech to known_tech list. Checks to make sure there aren't duplicates and updates existing tech's levels if needed. +//Input: datum/tech; Output: Null +/datum/research/proc/AddTech2Known(var/datum/tech/T) + for(var/datum/tech/known in known_tech) + if(T.id == known.id) + if(T.level > known.level) + known.level = T.level + return + return + +/datum/research/proc/AddDesign2Known(var/datum/design/D) + if(!known_designs.len) // Special case + known_designs.Add(D) + return + for(var/i = 1 to known_designs.len) + var/datum/design/A = known_designs[i] + if(A.id == D.id) // We are guaranteed to reach this if the ids are the same, because sort_string will also be the same + return + if(A.sort_string > D.sort_string) + known_designs.Insert(i, D) + return + known_designs.Add(D) + return + +//Refreshes known_tech and known_designs list +//Input/Output: n/a +/datum/research/proc/RefreshResearch() + for(var/datum/design/PD in possible_designs) + if(DesignHasReqs(PD)) + AddDesign2Known(PD) + for(var/datum/tech/T in known_tech) + T = between(0, T.level, 20) + return + +//Refreshes the levels of a given tech. +//Input: Tech's ID and Level; Output: null +/datum/research/proc/UpdateTech(var/ID, var/level) + for(var/datum/tech/KT in known_tech) + if(KT.id == ID && KT.level <= level) + KT.level = max(KT.level + 1, level - 1) + return + +// A simple helper proc to find the name of a tech with a given ID. +/proc/CallTechName(var/ID) + for(var/T in subtypesof(/datum/tech)) + var/datum/tech/check_tech = T + if(initial(check_tech.id) == ID) + return initial(check_tech.name) + +/*************************************************************** +** Technology Datums ** +** Includes all the various technoliges and what they make. ** +***************************************************************/ + +/datum/tech //Datum of individual technologies. + var/name = "name" //Name of the technology. + var/desc = "description" //General description of what it does and what it makes. + var/id = "id" //An easily referenced ID. Must be alphanumeric, lower-case, and no symbols. + var/level = 1 //A simple number scale of the research level. Level 0 = Secret tech. + +/datum/tech/materials + name = "Materials" + desc = "Development of new and improved materials." + id = TECH_MATERIAL + +/datum/tech/engineering + name = "Engineering" + desc = "Development of new and improved engineering parts." + id = TECH_ENGINEERING + +/datum/tech/phorontech + name = "Phoron Technology" + desc = "Manipulation of the mysterious substance colloqually known as 'phoron'." + id = TECH_PHORON + +/datum/tech/powerstorage + name = "Power Manipulation Technology" + desc = "The various technologies behind the storage and generation of electicity." + id = TECH_POWER + +/datum/tech/bluespace + name = "'Blue-space' Technology" + desc = "Devices that utilize the sub-reality known as 'blue-space'" + id = TECH_BLUESPACE + +/datum/tech/biotech + name = "Biological Technology" + desc = "Deeper mysteries of life and organic substances." + id = TECH_BIO + +/datum/tech/combat + name = "Combat Systems" + desc = "Offensive and defensive systems." + id = TECH_COMBAT + +/datum/tech/magnets + name = "Electromagnetic Spectrum Technology" + desc = "Electromagnetic spectrum and magnetic devices. No clue how they actually work, though." + id = TECH_MAGNET + +/datum/tech/programming + name = "Data Theory" + desc = "Computer and artificial intelligence and data storage systems." + id = TECH_DATA + +/datum/tech/syndicate + name = "ILLEGAL" + desc = "WARNING: Controlled technology detected. Fabrication of items using this technology is a direct violation of Federal Law 352-C part II and is a serious crime." + id = TECH_ILLEGAL + level = 0 + +/datum/tech/arcane + name = "Arcane" + desc = "Techniques not explained by the mainstream science, commonly regarded as 'occult'." + id = TECH_ARCANE + level = 0 + +/obj/item/weapon/disk/tech_disk + name = "fabricator data disk" + desc = "A disk for storing fabricator learning data for backup." + icon = 'icons/obj/cloning.dmi' + icon_state = "datadisk2" + item_state = "card-id" + w_class = ITEM_SIZE_SMALL + matter = list(DEFAULT_WALL_MATERIAL = 30, "glass" = 10) + var/datum/tech/stored + + +/obj/item/weapon/disk/design_disk + name = "component design disk" + desc = "A disk for storing device design data for construction in lathes." + icon = 'icons/obj/cloning.dmi' + icon_state = "datadisk2" + item_state = "card-id" + w_class = ITEM_SIZE_SMALL + matter = list(DEFAULT_WALL_MATERIAL = 30, "glass" = 10) + var/datum/design/blueprint diff --git a/code/modules/research/server.dm b/code/modules/research/server.dm new file mode 100644 index 00000000..ee0c0ef9 --- /dev/null +++ b/code/modules/research/server.dm @@ -0,0 +1,315 @@ +/obj/machinery/r_n_d/server + name = "R&D Server" + icon = 'icons/obj/machines/research.dmi' + icon_state = "server" + var/datum/research/files + var/health = 100 + var/list/id_with_upload = list() //List of R&D consoles with upload to server access. + var/list/id_with_download = list() //List of R&D consoles with download from server access. + var/id_with_upload_string = "" //String versions for easy editing in map editor. + var/id_with_download_string = "" + var/server_id = 0 + var/produces_heat = 1 + idle_power_usage = 800 + var/delay = 10 + req_access = list(access_rd) //Only the R&D can change server settings. + +/obj/machinery/r_n_d/server/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/rdserver(src) + component_parts += new /obj/item/weapon/stock_parts/scanning_module(src) + component_parts += new /obj/item/stack/cable_coil(src) + component_parts += new /obj/item/stack/cable_coil(src) + RefreshParts() + +/obj/machinery/r_n_d/server/Destroy() + griefProtection() + ..() + +/obj/machinery/r_n_d/server/RefreshParts() + var/tot_rating = 0 + for(var/obj/item/weapon/stock_parts/SP in src) + tot_rating += SP.rating + idle_power_usage /= max(1, tot_rating) + +/obj/machinery/r_n_d/server/Initialize() + . = ..() + if(!files) + files = new /datum/research(src) + var/list/temp_list + if(!id_with_upload.len) + temp_list = list() + temp_list = splittext(id_with_upload_string, ";") + for(var/N in temp_list) + id_with_upload += text2num(N) + if(!id_with_download.len) + temp_list = list() + temp_list = splittext(id_with_download_string, ";") + for(var/N in temp_list) + id_with_download += text2num(N) + +/obj/machinery/r_n_d/server/Process() + var/datum/gas_mixture/environment = loc.return_air() + switch(environment.temperature) + if(0 to T0C) + health = min(100, health + 1) + if(T0C to (T20C + 20)) + health = between(0, health, 100) + if((T20C + 20) to (T0C + 70)) + health = max(0, health - 1) + if(health <= 0) + griefProtection() //I dont like putting this in process() but it's the best I can do without re-writing a chunk of rd servers. + files.known_designs = list() + for(var/datum/tech/T in files.known_tech) + if(prob(1)) + T.level-- + files.RefreshResearch() + if(delay) + delay-- + else + produce_heat() + delay = initial(delay) + +/obj/machinery/r_n_d/server/emp_act(severity) + griefProtection() + ..() + +/obj/machinery/r_n_d/server/ex_act(severity) + griefProtection() + ..() + +//Backup files to centcomm to help admins recover data after greifer attacks +/obj/machinery/r_n_d/server/proc/griefProtection() + for(var/obj/machinery/r_n_d/server/centcom/C in SSmachines.machinery) + for(var/datum/tech/T in files.known_tech) + C.files.AddTech2Known(T) + for(var/datum/design/D in files.known_designs) + C.files.AddDesign2Known(D) + C.files.RefreshResearch() + +/obj/machinery/r_n_d/server/proc/produce_heat() + if(!produces_heat) + return + + if(!use_power) + return + + if(!(stat & (NOPOWER|BROKEN))) //Blatently stolen from telecoms + var/turf/simulated/L = loc + if(istype(L)) + var/datum/gas_mixture/env = L.return_air() + + var/transfer_moles = 0.25 * env.total_moles + + var/datum/gas_mixture/removed = env.remove(transfer_moles) + + if(removed) + var/heat_produced = idle_power_usage //obviously can't produce more heat than the machine draws from it's power source + + removed.add_thermal_energy(heat_produced) + + env.merge(removed) + +/obj/machinery/r_n_d/server/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(default_deconstruction_screwdriver(user, O)) + return + if(default_deconstruction_crowbar(user, O)) + return + if(default_part_replacement(user, O)) + return + +/obj/machinery/r_n_d/server/centcom + name = "Central R&D Database" + server_id = -1 + +/obj/machinery/r_n_d/server/centcom/proc/update_connections() + var/list/no_id_servers = list() + var/list/server_ids = list() + for(var/obj/machinery/r_n_d/server/S in SSmachines.machinery) + switch(S.server_id) + if(-1) + continue + if(0) + no_id_servers += S + else + server_ids += S.server_id + + for(var/obj/machinery/r_n_d/server/S in no_id_servers) + var/num = 1 + while(!S.server_id) + if(num in server_ids) + num++ + else + S.server_id = num + server_ids += num + no_id_servers -= S + +/obj/machinery/r_n_d/server/centcom/Process() + return PROCESS_KILL //don't need process() + +/obj/machinery/computer/rdservercontrol + name = "R&D Server Controller" + icon_keyboard = "rd_key" + icon_screen = "rdcomp" + light_color = "#a97faa" + circuit = /obj/item/weapon/circuitboard/rdservercontrol + var/screen = 0 + var/obj/machinery/r_n_d/server/temp_server + var/list/servers = list() + var/list/consoles = list() + var/badmin = 0 + +/obj/machinery/computer/rdservercontrol/CanUseTopic(user) + if(!allowed(user) && !emagged) + to_chat(user, "You do not have the required access level") + return STATUS_CLOSE + return ..() + +/obj/machinery/computer/rdservercontrol/OnTopic(user, href_list, state) + if(href_list["main"]) + screen = 0 + . = TOPIC_REFRESH + + else if(href_list["access"] || href_list["data"] || href_list["transfer"]) + temp_server = null + consoles = list() + servers = list() + for(var/obj/machinery/r_n_d/server/S in SSmachines.machinery) + if(S.server_id == text2num(href_list["access"]) || S.server_id == text2num(href_list["data"]) || S.server_id == text2num(href_list["transfer"])) + temp_server = S + break + if(href_list["access"]) + screen = 1 + for(var/obj/machinery/computer/rdconsole/C in SSmachines.machinery) + if(C.sync) + consoles += C + else if(href_list["data"]) + screen = 2 + else if(href_list["transfer"]) + screen = 3 + for(var/obj/machinery/r_n_d/server/S in SSmachines.machinery) + if(S == src) + continue + servers += S + . = TOPIC_REFRESH + + else if(href_list["upload_toggle"]) + var/num = text2num(href_list["upload_toggle"]) + if(num in temp_server.id_with_upload) + temp_server.id_with_upload -= num + else + temp_server.id_with_upload += num + . = TOPIC_REFRESH + + else if(href_list["download_toggle"]) + var/num = text2num(href_list["download_toggle"]) + if(num in temp_server.id_with_download) + temp_server.id_with_download -= num + else + temp_server.id_with_download += num + . = TOPIC_REFRESH + + else if(href_list["reset_tech"]) + var/choice = alert(user, "Technology Data Rest", "Are you sure you want to reset this technology to its default data? Data lost cannot be recovered.", "Continue", "Cancel") + if(choice == "Continue" && CanUseTopic(user, state)) + for(var/datum/tech/T in temp_server.files.known_tech) + if(T.id == href_list["reset_tech"]) + T.level = 1 + break + temp_server.files.RefreshResearch() + . = TOPIC_REFRESH + + else if(href_list["reset_design"]) + var/choice = alert(user, "Design Data Deletion", "Are you sure you want to delete this design? If you still have the prerequisites for the design, it'll reset to its base reliability. Data lost cannot be recovered.", "Continue", "Cancel") + if(choice == "Continue" && CanUseTopic(user, state)) + for(var/datum/design/D in temp_server.files.known_designs) + if(D.id == href_list["reset_design"]) + temp_server.files.known_designs -= D + break + temp_server.files.RefreshResearch() + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + attack_hand(user) + +/obj/machinery/computer/rdservercontrol/attack_hand(mob/user as mob) + if(stat & (BROKEN|NOPOWER)) + return + user.set_machine(src) + var/dat = "" + + switch(screen) + if(0) //Main Menu + dat += "Connected Servers:

                " + + for(var/obj/machinery/r_n_d/server/S in SSmachines.machinery) + if(istype(S, /obj/machinery/r_n_d/server/centcom) && !badmin) + continue + dat += "[S.name] || " + dat += " Access Rights | " + dat += "Data Management" + if(badmin) dat += " | Server-to-Server Transfer" + dat += "
                " + + if(1) //Access rights menu + dat += "[temp_server.name] Access Rights

                " + dat += "Consoles with Upload Access
                " + for(var/obj/machinery/computer/rdconsole/C in consoles) + var/turf/console_turf = get_turf(C) + dat += "* [console_turf.loc]" //FYI, these are all numeric ids, eventually. + if(C.id in temp_server.id_with_upload) + dat += " (Remove)
                " + else + dat += " (Add)
                " + dat += "Consoles with Download Access
                " + for(var/obj/machinery/computer/rdconsole/C in consoles) + var/turf/console_turf = get_turf(C) + dat += "* [console_turf.loc]" + if(C.id in temp_server.id_with_download) + dat += " (Remove)
                " + else + dat += " (Add)
                " + dat += "
                Main Menu" + + if(2) //Data Management menu + dat += "[temp_server.name] Data ManagementP

                " + dat += "Known Technologies
                " + for(var/datum/tech/T in temp_server.files.known_tech) + dat += "* [T.name] " + dat += "(Reset)
                " //FYI, these are all strings. + dat += "Known Designs
                " + for(var/datum/design/D in temp_server.files.known_designs) + dat += "* [D.name] " + dat += "(Delete)
                " + dat += "
                Main Menu" + + if(3) //Server Data Transfer + dat += "[temp_server.name] Server to Server Transfer

                " + dat += "Send Data to what server?
                " + for(var/obj/machinery/r_n_d/server/S in servers) + dat += "[S.name] (Transfer)
                " + dat += "
                Main Menu" + user << browse("R&D Server Control
                [dat]", "window=server_control;size=575x400") + onclose(user, "server_control") + return + +/obj/machinery/computer/rdservercontrol/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1) + emagged = 1 + to_chat(user, "You you disable the security protocols.") + src.updateUsrDialog() + return 1 + +/obj/machinery/r_n_d/server/robotics + name = "Robotics R&D Server" + id_with_upload_string = "1;2" + id_with_download_string = "1;2" + server_id = 2 + +/obj/machinery/r_n_d/server/core + name = "Core R&D Server" + id_with_upload_string = "1" + id_with_download_string = "1" + server_id = 1 diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm new file mode 100644 index 00000000..42af00f9 --- /dev/null +++ b/code/modules/research/stock_parts.dm @@ -0,0 +1,222 @@ +///////////////////////////////////////Stock Parts ///////////////////////////////// + +/obj/item/weapon/storage/part_replacer + name = "rapid part exchange device" + desc = "Special mechanical module made to store, sort, and apply standard machine parts." + icon_state = "RPED" + item_state = "RPED" + w_class = ITEM_SIZE_HUGE + can_hold = list(/obj/item/weapon/stock_parts) + storage_slots = 50 + use_to_pickup = 1 + allow_quick_gather = 1 + allow_quick_empty = 1 + collection_mode = 1 + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = 100 + +/obj/item/weapon/stock_parts + name = "stock part" + desc = "What?" + gender = PLURAL + icon = 'icons/obj/stock_parts.dmi' + randpixel = 5 + w_class = ITEM_SIZE_SMALL + var/rating = 1 + +//Rank 1 + +/obj/item/weapon/stock_parts/console_screen + name = "console screen" + desc = "Used in the construction of computers and other devices with a interactive console." + icon_state = "screen" + origin_tech = list(TECH_MATERIAL = 1) + matter = list("glass" = 200) + +/obj/item/weapon/stock_parts/scanning_module + name = "scanning module" + desc = "A compact, high resolution scanning module used in the construction of certain devices." + icon_state = "scan_module" + origin_tech = list(TECH_MAGNET = 1) + matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 20) + +/obj/item/weapon/stock_parts/manipulator + name = "micro-manipulator" + desc = "A tiny little manipulator used in the construction of certain devices." + icon_state = "micro_mani" + origin_tech = list(TECH_MATERIAL = 1, TECH_DATA = 1) + matter = list(DEFAULT_WALL_MATERIAL = 30) + +/obj/item/weapon/stock_parts/micro_laser + name = "micro-laser" + desc = "A tiny laser used in certain devices." + icon_state = "micro_laser" + origin_tech = list(TECH_MAGNET = 1) + matter = list(DEFAULT_WALL_MATERIAL = 10,"glass" = 20) + +/obj/item/weapon/stock_parts/matter_bin + name = "matter bin" + desc = "A container for hold compressed matter awaiting re-construction." + icon_state = "matter_bin" + origin_tech = list(TECH_MATERIAL = 1) + matter = list(DEFAULT_WALL_MATERIAL = 80) + +//Rank 2 + +/obj/item/weapon/stock_parts/scanning_module/adv + name = "advanced scanning module" + desc = "A compact, high resolution scanning module used in the construction of certain devices." + icon_state = "scan_module" + origin_tech = list(TECH_MAGNET = 3) + rating = 2 + matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 20) + +/obj/item/weapon/stock_parts/manipulator/nano + name = "nano-manipulator" + desc = "A tiny little manipulator used in the construction of certain devices." + icon_state = "nano_mani" + origin_tech = list(TECH_MATERIAL = 3, TECH_DATA = 2) + rating = 2 + matter = list(DEFAULT_WALL_MATERIAL = 30) + +/obj/item/weapon/stock_parts/micro_laser/high + name = "high-power micro-laser" + desc = "A tiny laser used in certain devices." + icon_state = "high_micro_laser" + origin_tech = list(TECH_MAGNET = 3) + rating = 2 + matter = list(DEFAULT_WALL_MATERIAL = 10,"glass" = 20) + +/obj/item/weapon/stock_parts/matter_bin/adv + name = "advanced matter bin" + desc = "A container for hold compressed matter awaiting re-construction." + icon_state = "advanced_matter_bin" + origin_tech = list(TECH_MATERIAL = 3) + rating = 2 + matter = list(DEFAULT_WALL_MATERIAL = 80) + +//Rating 3 + +/obj/item/weapon/stock_parts/scanning_module/phasic + name = "phasic scanning module" + desc = "A compact, high resolution phasic scanning module used in the construction of certain devices." + origin_tech = list(TECH_MAGNET = 5) + rating = 3 + matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 20) + +/obj/item/weapon/stock_parts/manipulator/pico + name = "pico-manipulator" + desc = "A tiny little manipulator used in the construction of certain devices." + icon_state = "pico_mani" + origin_tech = list(TECH_MATERIAL = 5, TECH_DATA = 2) + rating = 3 + matter = list(DEFAULT_WALL_MATERIAL = 30) + +/obj/item/weapon/stock_parts/micro_laser/ultra + name = "ultra-high-power micro-laser" + icon_state = "ultra_high_micro_laser" + desc = "A tiny laser used in certain devices." + origin_tech = list(TECH_MAGNET = 5) + rating = 3 + matter = list(DEFAULT_WALL_MATERIAL = 10,"glass" = 20) + +/obj/item/weapon/stock_parts/matter_bin/super + name = "super matter bin" + desc = "A container for hold compressed matter awaiting re-construction." + icon_state = "super_matter_bin" + origin_tech = list(TECH_MATERIAL = 5) + rating = 3 + matter = list(DEFAULT_WALL_MATERIAL = 80) + +// Subspace stock parts + +/obj/item/weapon/stock_parts/subspace/ansible + name = "subspace ansible" + icon_state = "subspace_ansible" + desc = "A compact module capable of sensing extradimensional activity." + origin_tech = list(TECH_DATA = 3, TECH_MAGNET = 5 ,TECH_MATERIAL = 4, TECH_BLUESPACE = 2) + matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 10) + +/obj/item/weapon/stock_parts/subspace/filter + name = "hyperwave filter" + icon_state = "hyperwave_filter" + desc = "A tiny device capable of filtering and converting super-intense radiowaves." + origin_tech = list(TECH_DATA = 4, TECH_MAGNET = 2) + matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 10) + +/obj/item/weapon/stock_parts/subspace/amplifier + name = "subspace amplifier" + icon_state = "subspace_amplifier" + desc = "A compact micro-machine capable of amplifying weak subspace transmissions." + origin_tech = list(TECH_DATA = 3, TECH_MAGNET = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2) + matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 10) + +/obj/item/weapon/stock_parts/subspace/treatment + name = "subspace treatment disk" + icon_state = "treatment_disk" + desc = "A compact micro-machine capable of stretching out hyper-compressed radio waves." + origin_tech = list(TECH_DATA = 3, TECH_MAGNET = 2, TECH_MATERIAL = 5, TECH_BLUESPACE = 2) + matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 10) + +/obj/item/weapon/stock_parts/subspace/analyzer + name = "subspace wavelength analyzer" + icon_state = "wavelength_analyzer" + desc = "A sophisticated analyzer capable of analyzing cryptic subspace wavelengths." + origin_tech = list(TECH_DATA = 3, TECH_MAGNETS = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2) + matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 10) + +/obj/item/weapon/stock_parts/subspace/crystal + name = "ansible crystal" + icon_state = "ansible_crystal" + desc = "A crystal made from pure glass used to transmit laser databursts to subspace." + origin_tech = list(TECH_MAGNET = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2) + matter = list("glass" = 50) + +/obj/item/weapon/stock_parts/subspace/transmitter + name = "subspace transmitter" + icon_state = "subspace_transmitter" + desc = "A large piece of equipment used to open a window into the subspace dimension." + origin_tech = list(TECH_MAGNET = 5, TECH_MATERIAL = 5, TECH_BLUESPACE = 3) + matter = list(DEFAULT_WALL_MATERIAL = 50) +/obj/item/weapon/stock_parts/capacitor + name = "capacitor" + desc = "A basic capacitor used in the construction of a variety of devices." + icon_state = "capacitor" + origin_tech = list(TECH_POWER = 1) + matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 50) + var/charge = 0 + var/max_charge = 1000 + +/obj/item/weapon/stock_parts/capacitor/Initialize() + . = ..() + max_charge *= rating + +/obj/item/weapon/stock_parts/capacitor/proc/charge(var/amount) + charge += amount + if(charge > max_charge) + charge = max_charge + +/obj/item/weapon/stock_parts/capacitor/proc/use(var/amount) + if(charge) + charge -= amount + if(charge < 0) + charge = 0 + +/obj/item/weapon/stock_parts/capacitor/adv + name = "advanced capacitor" + desc = "An advanced capacitor used in the construction of a variety of devices." + origin_tech = list(TECH_POWER = 3) + rating = 2 + +/obj/item/weapon/stock_parts/capacitor/super + name = "super capacitor" + desc = "A super-high capacity capacitor used in the construction of a variety of devices." + origin_tech = list(TECH_POWER = 5, TECH_MATERIAL = 4) + rating = 3 + +/obj/item/weapon/research + name = "research debugging device" + desc = "Instant research tool. For testing purposes only." + icon = 'icons/obj/stock_parts.dmi' + icon_state = "smes_coil" + origin_tech = list(TECH_MATERIAL = 19, TECH_ENGINEERING = 19, TECH_PHORON = 19, TECH_POWER = 19, TECH_BLUESPACE = 19, TECH_BIO = 19, TECH_COMBAT = 19, TECH_MAGNET = 19, TECH_DATA = 19, TECH_ILLEGAL = 19, TECH_ARCANE = 19) diff --git a/code/modules/scripting/AST/AST Nodes.dm b/code/modules/scripting/AST/AST Nodes.dm new file mode 100644 index 00000000..b89b3f80 --- /dev/null +++ b/code/modules/scripting/AST/AST Nodes.dm @@ -0,0 +1,139 @@ +/* + File: AST Nodes + An abstract syntax tree (AST) is a representation of source code in a computer-friendly format. It is composed of nodes, + each of which represents a certain part of the source code. For example, an node represents an if statement in the + script's source code. Because it is a representation of the source code in memory, it is independent of any specific scripting language. + This allows a script in any language for which a parser exists to be run by the interpreter. + + The AST is produced by an object. It consists of a with an arbitrary amount of statements. These statements are + run in order by an object. A statement may in turn run another block (such as an if statement might if its condition is + met). + + Articles: + - +*/ +var + const +/* + Constants: Operator Precedence + OOP_OR - Logical or + OOP_AND - Logical and + OOP_BIT - Bitwise operations + OOP_EQUAL - Equality checks + OOP_COMPARE - Greater than, less then, etc + OOP_ADD - Addition and subtraction + OOP_MULTIPLY - Multiplication and division + OOP_POW - Exponents + OOP_UNARY - Unary Operators + OOP_GROUP - Parentheses +*/ + OOP_OR = 1 //|| + OOP_AND = OOP_OR + 1 //&& + OOP_BIT = OOP_AND + 1 //&, | + OOP_EQUAL = OOP_BIT + 1 //==, != + OOP_COMPARE = OOP_EQUAL + 1 //>, <, >=, <= + OOP_ADD = OOP_COMPARE + 1 //+, - + OOP_MULTIPLY= OOP_ADD + 1 //*, /, % + OOP_POW = OOP_MULTIPLY+ 1 //^ + OOP_UNARY = OOP_POW + 1 //! + OOP_GROUP = OOP_UNARY + 1 //() + +/* + Class: node +*/ +/node + proc + ToString() + return "[src.type]" +/* + Class: identifier +*/ +/node/identifier + var + id_name + + New(id) + .=..() + src.id_name=id + + ToString() + return id_name + +/* + Class: expression +*/ +/node/expression +/* + Class: operator + See and for subtypes. +*/ +/node/expression/operator + var + node/expression/exp + tmp + name + precedence + + New() + .=..() + if(!src.name) src.name="[src.type]" + + ToString() + return "operator: [name]" + +/* + Class: FunctionCall +*/ +/node/expression/FunctionCall + //Function calls can also be expressions or statements. + var + func_name + node/identifier/object + list/parameters=new + +/* + Class: literal +*/ +/node/expression/value/literal + var + value + + New(value) + .=..() + src.value=value + + ToString() + return src.value + +/* + Class: variable +*/ +/node/expression/value/variable + var + node + object //Either a node/identifier or another node/expression/value/variable which points to the object + node/identifier + id + + + New(ident) + .=..() + id=ident + if(istext(id))id=new(id) + + ToString() + return src.id.ToString() + +/* + Class: reference +*/ +/node/expression/value/reference + var + datum/value + + New(value) + .=..() + src.value=value + + ToString() + return "ref: [src.value] ([src.value.type])" \ No newline at end of file diff --git a/code/modules/scripting/AST/Blocks.dm b/code/modules/scripting/AST/Blocks.dm new file mode 100644 index 00000000..24e71aa2 --- /dev/null +++ b/code/modules/scripting/AST/Blocks.dm @@ -0,0 +1,48 @@ +/* + File: Block Types +*/ +/* + Class: BlockDefinition + An object representing a set of actions to perform independently from the rest of the script. Blocks are basically just + lists of statements to execute which also contain some local variables and methods. Note that since functions are local to a block, + it is possible to have a function definition inside of any type of block (such as in an if statement or another function), + and not just in the global scope as in many languages. +*/ +/node/BlockDefinition + var/list + statements = new + functions = new + initial_variables = new + + proc +/* + Proc: SetVar + Defines a permanent variable. The variable will not be deleted when it goes out of scope. + + Notes: + Since all pre-existing temporary variables are deleted, it is not generally desirable to use this proc after the interpreter has been instantiated. + Instead, use . + + See Also: + - +*/ + SetVar(name, value) + initial_variables[name]=value + + +/* + Class: GlobalBlock + A block object representing the global scope. +*/ +// + GlobalBlock + New() + initial_variables["null"]=null + return ..() + +/* + Class: FunctionBlock + A block representing a function body. +*/ +// + FunctionBlock \ No newline at end of file diff --git a/code/modules/scripting/AST/Operators/Binary Operators.dm b/code/modules/scripting/AST/Operators/Binary Operators.dm new file mode 100644 index 00000000..183f7f78 --- /dev/null +++ b/code/modules/scripting/AST/Operators/Binary Operators.dm @@ -0,0 +1,174 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +/* + File: Binary Operators +*/ +/* + Class: binary + Represents a binary operator in the AST. A binary operator takes two operands (ie x and y) and returns a value. +*/ +/node/expression/operator/binary + var/node/expression/exp2 + +////////// Comparison Operators ////////// +/* + Class: Equal + Returns true if x = y. +*/ +// + Equal + precedence=OOP_EQUAL + +/* + Class: NotEqual + Returns true if x and y aren't equal. +*/ +// + NotEqual + precedence=OOP_EQUAL + +/* + Class: Greater + Returns true if x > y. +*/ +// + Greater + precedence=OOP_COMPARE + +/* + Class: Less + Returns true if x < y. +*/ +// + Less + precedence=OOP_COMPARE + +/* + Class: GreaterOrEqual + Returns true if x >= y. +*/ +// + GreaterOrEqual + precedence=OOP_COMPARE + +/* + Class: LessOrEqual + Returns true if x <= y. +*/ +// + LessOrEqual + precedence=OOP_COMPARE + + +////////// Logical Operators ////////// + +/* + Class: LogicalAnd + Returns true if x and y are true. +*/ +// + LogicalAnd + precedence=OOP_AND + +/* + Class: LogicalOr + Returns true if x, y, or both are true. +*/ +// + LogicalOr + precedence=OOP_OR + +/* + Class: LogicalXor + Returns true if either x or y but not both are true. +*/ +// + LogicalXor //Not implemented in nS + precedence=OOP_OR + + +////////// Bitwise Operators ////////// + +/* + Class: BitwiseAnd + Performs a bitwise and operation. + + Example: + 011 & 110 = 010 +*/ +// + BitwiseAnd + precedence=OOP_BIT + +/* + Class: BitwiseOr + Performs a bitwise or operation. + + Example: + 011 | 110 = 111 +*/ +// + BitwiseOr + precedence=OOP_BIT + +/* + Class: BitwiseXor + Performs a bitwise exclusive or operation. + + Example: + 011 xor 110 = 101 +*/ +// + BitwiseXor + precedence=OOP_BIT + + +////////// Arithmetic Operators ////////// + +/* + Class: Add + Returns the sum of x and y. +*/ +// + Add + precedence=OOP_ADD + +/* + Class: Subtract + Returns the difference of x and y. +*/ +// + Subtract + precedence=OOP_ADD + +/* + Class: Multiply + Returns the product of x and y. +*/ +// + Multiply + precedence=OOP_MULTIPLY + +/* + Class: Divide + Returns the quotient of x and y. +*/ +// + Divide + precedence=OOP_MULTIPLY + +/* + Class: Power + Returns x raised to the power of y. +*/ +// + Power + precedence=OOP_POW + +/* + Class: Modulo + Returns the remainder of x / y. +*/ +// + Modulo + precedence=OOP_MULTIPLY diff --git a/code/modules/scripting/AST/Operators/Unary Operators.dm b/code/modules/scripting/AST/Operators/Unary Operators.dm new file mode 100644 index 00000000..1002fefc --- /dev/null +++ b/code/modules/scripting/AST/Operators/Unary Operators.dm @@ -0,0 +1,51 @@ +/* + File: Unary Operators +*/ +/* + Class: unary + Represents a unary operator in the AST. Unary operators take a single operand (referred to as x below) and return a value. +*/ +/node/expression/operator/unary + precedence=OOP_UNARY + +/* + Class: LogicalNot + Returns !x. + + Example: + !true = false and !false = true +*/ +// + LogicalNot + name="logical not" + +/* + Class: BitwiseNot + Returns the value of a bitwise not operation performed on x. + + Example: + ~10 (decimal 2) = 01 (decimal 1). +*/ +// + BitwiseNot + name="bitwise not" + +/* + Class: Minus + Returns -x. +*/ +// + Minus + name="minus" + +/* + Class: group + A special unary operator representing a value in parentheses. +*/ +// + group + precedence=OOP_GROUP + + New(node/expression/exp) + src.exp=exp + return ..() diff --git a/code/modules/scripting/AST/Statements.dm b/code/modules/scripting/AST/Statements.dm new file mode 100644 index 00000000..8549fd6d --- /dev/null +++ b/code/modules/scripting/AST/Statements.dm @@ -0,0 +1,122 @@ +/* + File: Statement Types +*/ +/* + Class: statement + An object representing a single instruction run by an interpreter. +*/ +/node/statement +/* + Class: FunctionCall + Represents a call to a function. +*/ +// + FunctionCall + var + func_name + node/identifier/object + list/parameters=new + +/* + Class: FunctionDefinition + Defines a function. +*/ +// + FunctionDefinition + var + func_name + list/parameters=new + node/BlockDefinition/FunctionBlock/block + +/* + Class: VariableAssignment + Sets a variable in an accessible scope to the given value if one exists, otherwise initializes a new local variable to the given value. + + Notes: + If a variable with the same name exists in a higher block, the value will be assigned to it. If not, + a new variable is created in the current block. To force creation of a new variable, use . + + See Also: + - +*/ +// + VariableAssignment + var + node + identifier + object + var_name + expression/value + +/* + Class: VariableDeclaration + Intializes a local variable to a null value. + + See Also: + - +*/ +// + VariableDeclaration + var + node + identifier + object + var_name + +/* + Class: IfStatement +*/ +// + IfStatement + var + node + BlockDefinition + block + else_block //may be null + expression/cond + +/* + Class: WhileLoop + Loops while a given condition is true. +*/ +// + WhileLoop + var + node + BlockDefinition/block + expression/cond + +/* + Class: ForLoop + Loops while test is true, initializing a variable, increasing the variable +*/ + ForLoop + var + node + BlockDefinition/block + expression/test + expression/init + expression/increment + +/* + Class: BreakStatement + Ends a loop. +*/ +// + BreakStatement + +/* + Class: ContinueStatement + Skips to the next iteration of a loop. +*/ +// + ContinueStatement + +/* + Class: ReturnStatement + Ends the function and returns a value. +*/ +// + ReturnStatement + var + node/expression/value \ No newline at end of file diff --git a/code/modules/scripting/Errors.dm b/code/modules/scripting/Errors.dm new file mode 100644 index 00000000..4e8ee321 --- /dev/null +++ b/code/modules/scripting/Errors.dm @@ -0,0 +1,132 @@ +/* + File: Errors +*/ +/* + Class: scriptError + An error scanning or parsing the source code. +*/ +/scriptError + var +/* + Var: message + A message describing the problem. +*/ + message + New(msg=null) + if(msg)message=msg + + BadToken + message="Unexpected token: " + var/token/token + New(token/t) + token=t + if(t&&t.line) message="[t.line]: [message]" + if(istype(t))message+="[t.value]" + else message+="[t]" + + InvalidID + parent_type=/scriptError/BadToken + message="Invalid identifier name: " + + ReservedWord + parent_type=/scriptError/BadToken + message="Identifer using reserved word: " + + BadNumber + parent_type=/scriptError/BadToken + message = "Bad number: " + + BadReturn + var/token/token + message = "Unexpected return statement outside of a function." + New(token/t) + src.token=t + + EndOfFile + message = "Unexpected end of file." + + ExpectedToken + message="Expected: '" + New(id, token/T) + if(T && T.line) message="[T.line]: [message]" + message+="[id]'. " + if(T)message+="Found '[T.value]'." + + + UnterminatedComment + message="Unterminated multi-line comment statement: expected */" + + DuplicateFunction + New(name, token/t) + message="Function '[name]' defined twice." + +/* + Class: runtimeError + An error thrown by the interpreter in running the script. +*/ +/runtimeError + var + name +/* + Var: message + A basic description as to what went wrong. +*/ + message + stack/stack + + proc +/* + Proc: ToString + Returns a description of the error suitable for showing to the user. +*/ + ToString() + . = "[name]: [message]" + if(!stack.Top()) return + .+="\nStack:" + while(stack.Top()) + var/node/statement/FunctionCall/stmt=stack.Pop() + . += "\n\t [stmt.func_name]()" + + TypeMismatch + name="TypeMismatchError" + New(op, a, b) + message="Type mismatch: '[a]' [op] '[b]'" + + UnexpectedReturn + name="UnexpectedReturnError" + message="Unexpected return statement." + + UnknownInstruction + name="UnknownInstructionError" + message="Unknown instruction type. This may be due to incompatible compiler and interpreter versions or a lack of implementation." + + UndefinedVariable + name="UndefinedVariableError" + New(variable) + message="Variable '[variable]' has not been declared." + + UndefinedFunction + name="UndefinedFunctionError" + New(function) + message="Function '[function]()' has not been defined." + + DuplicateVariableDeclaration + name="DuplicateVariableError" + New(variable) + message="Variable '[variable]' was already declared." + + IterationLimitReached + name="MaxIterationError" + message="A loop has reached its maximum number of iterations." + + RecursionLimitReached + name="MaxRecursionError" + message="The maximum amount of recursion has been reached." + + DivisionByZero + name="DivideByZeroError" + message="Division by zero attempted." + + MaxCPU + name="MaxComputationalUse" + message="Maximum amount of computational cycles reached (>= 1000)." \ No newline at end of file diff --git a/code/modules/scripting/IDE.dm b/code/modules/scripting/IDE.dm new file mode 100644 index 00000000..ed0e00f8 --- /dev/null +++ b/code/modules/scripting/IDE.dm @@ -0,0 +1,211 @@ +client/verb/tcssave() + set hidden = 1 + if(mob.machine || issilicon(mob)) + if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && mob.machine in view(1, mob)) || issilicon(mob)) + var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine + if(Machine.editingcode != mob) + return + + if(Machine.SelectedServer) + var/obj/machinery/telecomms/server/Server = Machine.SelectedServer + var/tcscode=winget(src, "tcscode", "text") + var/msg="[mob.name] is adding script to server [Server]: [tcscode]" + log_misc(msg) + message_admins("[mob.name] has uploaded a NTLS script to [Machine.SelectedServer] ([mob.x],[mob.y],[mob.z] - JMP)",0,1) + Server.setcode( tcscode ) // this actually saves the code from input to the server + src << output(null, "tcserror") // clear the errors + else + src << output(null, "tcserror") + src << output("Failed to save: Unable to locate server machine. (Back up your code before exiting the window!)", "tcserror") + else + src << output(null, "tcserror") + src << output("Failed to save: Unable to locate machine. (Back up your code before exiting the window!)", "tcserror") + else + src << output(null, "tcserror") + src << output("Failed to save: Unable to locate machine. (Back up your code before exiting the window!)", "tcserror") + + +client/verb/tcscompile() + set hidden = 1 + if(mob.machine || issilicon(mob)) + if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && mob.machine in view(1, mob)) || (issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) )) + var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine + if(Machine.editingcode != mob) + return + + if(Machine.SelectedServer) + var/obj/machinery/telecomms/server/Server = Machine.SelectedServer + Server.setcode( winget(src, "tcscode", "text") ) // save code first + var/list/compileerrors = Server.compile() // then compile the code! + + // Output all the compile-time errors + src << output(null, "tcserror") + + if(compileerrors.len) + src << output("Compile Errors", "tcserror") + for(var/scriptError/e in compileerrors) + src << output("\t>[e.message]", "tcserror") + src << output("([compileerrors.len] errors)", "tcserror") + + // Output compile errors to all other people viewing the code too + for(var/mob/M in Machine.viewingcode) + if(M.client) + M << output(null, "tcserror") + M << output("Compile Errors", "tcserror") + for(var/scriptError/e in compileerrors) + M << output("\t>[e.message]", "tcserror") + M << output("([compileerrors.len] errors)", "tcserror") + + + else + src << output("TCS compilation successful!", "tcserror") + src << output("(0 errors)", "tcserror") + + for(var/mob/M in Machine.viewingcode) + if(M.client) + M << output("TCS compilation successful!", "tcserror") + M << output("(0 errors)", "tcserror") + + else + src << output(null, "tcserror") + src << output("Failed to compile: Unable to locate server machine. (Back up your code before exiting the window!)", "tcserror") + else + src << output(null, "tcserror") + src << output("Failed to compile: Unable to locate machine. (Back up your code before exiting the window!)", "tcserror") + else + src << output(null, "tcserror") + src << output("Failed to compile: Unable to locate machine. (Back up your code before exiting the window!)", "tcserror") + +client/verb/tcsrun() + set hidden = 1 + if(mob.machine || issilicon(mob)) + if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && mob.machine in view(1, mob)) || (issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) )) + var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine + if(Machine.editingcode != mob) + return + + if(Machine.SelectedServer) + var/obj/machinery/telecomms/server/Server = Machine.SelectedServer + Server.setcode( winget(src, "tcscode", "text") ) // save code first + var/list/compileerrors = Server.compile() // then compile the code! + + // Output all the compile-time errors + src << output(null, "tcserror") + + if(compileerrors.len) + src << output("Compile Errors", "tcserror") + for(var/scriptError/e in compileerrors) + src << output("\t>[e.message]", "tcserror") + src << output("([compileerrors.len] errors)", "tcserror") + + // Output compile errors to all other people viewing the code too + for(var/mob/M in Machine.viewingcode) + if(M.client) + M << output(null, "tcserror") + M << output("Compile Errors", "tcserror") + for(var/scriptError/e in compileerrors) + M << output("\t>[e.message]", "tcserror") + M << output("([compileerrors.len] errors)", "tcserror") + + else + // Finally, we run the code! + src << output("TCS compilation successful! Code executed.", "tcserror") + src << output("(0 errors)", "tcserror") + + for(var/mob/M in Machine.viewingcode) + if(M.client) + M << output("TCS compilation successful!", "tcserror") + M << output("(0 errors)", "tcserror") + + var/datum/signal/signal = new() + signal.data["message"] = "" + if(Server.freq_listening.len > 0) + signal.frequency = Server.freq_listening[1] + else + signal.frequency = PUB_FREQ + signal.data["name"] = "" + signal.data["job"] = "" + signal.data["reject"] = 0 + signal.data["server"] = Server + + Server.Compiler.Run(signal) + + + else + src << output(null, "tcserror") + src << output("Failed to run: Unable to locate server machine. (Back up your code before exiting the window!)", "tcserror") + else + src << output(null, "tcserror") + src << output("Failed to run: Unable to locate machine. (Back up your code before exiting the window!)", "tcserror") + else + src << output(null, "tcserror") + src << output("Failed to run: Unable to locate machine. (Back up your code before exiting the window!)", "tcserror") + + +client/verb/exittcs() + set hidden = 1 + if(mob.machine || issilicon(mob)) + if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && mob.machine in view(1, mob)) || (issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) )) + var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine + if(Machine.editingcode == mob) + Machine.storedcode = "[winget(mob, "tcscode", "text")]" + Machine.editingcode = null + else + if(mob in Machine.viewingcode) + Machine.viewingcode.Remove(mob) + +client/verb/tcsrevert() + set hidden = 1 + if(mob.machine || issilicon(mob)) + if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && mob.machine in view(1, mob)) || (issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) )) + var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine + if(Machine.editingcode != mob) + return + + if(Machine.SelectedServer) + var/obj/machinery/telecomms/server/Server = Machine.SelectedServer + + // Replace quotation marks with quotation macros for proper winset() compatibility + var/showcode = replacetext(Server.rawcode, "\\\"", "\\\\\"") + showcode = replacetext(showcode, "\"", "\\\"") + + winset(mob, "tcscode", "text=\"[showcode]\"") + + src << output(null, "tcserror") // clear the errors + else + src << output(null, "tcserror") + src << output("Failed to revert: Unable to locate server machine.", "tcserror") + else + src << output(null, "tcserror") + src << output("Failed to revert: Unable to locate machine.", "tcserror") + else + src << output(null, "tcserror") + src << output("Failed to revert: Unable to locate machine.", "tcserror") + + +client/verb/tcsclearmem() + set hidden = 1 + if(mob.machine || issilicon(mob)) + if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && mob.machine in view(1, mob)) || (issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) )) + var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine + if(Machine.editingcode != mob) + return + + if(Machine.SelectedServer) + var/obj/machinery/telecomms/server/Server = Machine.SelectedServer + Server.memory = list() // clear the memory + // Show results + src << output(null, "tcserror") + src << output("Server memory cleared!", "tcserror") + for(var/mob/M in Machine.viewingcode) + if(M.client) + M << output("Server memory cleared!", "tcserror") + else + src << output(null, "tcserror") + src << output("Failed to clear memory: Unable to locate server machine.", "tcserror") + else + src << output(null, "tcserror") + src << output("Failed to clear memory: Unable to locate machine.", "tcserror") + else + src << output(null, "tcserror") + src << output("Failed to clear memory: Unable to locate machine.", "tcserror") diff --git a/code/modules/scripting/Implementations/Telecomms.dm b/code/modules/scripting/Implementations/Telecomms.dm new file mode 100644 index 00000000..16f95855 --- /dev/null +++ b/code/modules/scripting/Implementations/Telecomms.dm @@ -0,0 +1,275 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + + +/* --- Traffic Control Scripting Language --- */ + // Nanotrasen TCS Language - Made by Doohl + +/n_Interpreter/TCS_Interpreter + var/datum/TCS_Compiler/Compiler + + HandleError(runtimeError/e) + Compiler.Holder.add_entry(e.ToString(), "Execution Error") + +/datum/TCS_Compiler + var/n_Interpreter/TCS_Interpreter/interpreter + var/obj/machinery/telecomms/server/Holder // the server that is running the code + var/ready = 1 // 1 if ready to run code + + /* -- Compile a raw block of text -- */ + + proc/Compile(code as message) + var/n_scriptOptions/nS_Options/options = new() + var/n_Scanner/nS_Scanner/scanner = new(code, options) + var/list/tokens = scanner.Scan() + var/n_Parser/nS_Parser/parser = new(tokens, options) + var/node/BlockDefinition/GlobalBlock/program = parser.Parse() + + var/list/returnerrors = list() + + returnerrors += scanner.errors + returnerrors += parser.errors + + if(returnerrors.len) + return returnerrors + + interpreter = new(program) + interpreter.persist = 1 + interpreter.Compiler= src + + return returnerrors + + /* -- Execute the compiled code -- */ + + proc/Run(var/datum/signal/signal) + + if(!ready) + return + + if(!interpreter) + return + + interpreter.container = src + + interpreter.SetVar("PI" , 3.141592653) // value of pi + interpreter.SetVar("E" , 2.718281828) // value of e + interpreter.SetVar("SQURT2" , 1.414213562) // value of the square root of 2 + interpreter.SetVar("FALSE" , 0) // boolean shortcut to 0 + interpreter.SetVar("TRUE" , 1) // boolean shortcut to 1 + + interpreter.SetVar("NORTH" , NORTH) // NORTH (1) + interpreter.SetVar("SOUTH" , SOUTH) // SOUTH (2) + interpreter.SetVar("EAST" , EAST) // EAST (4) + interpreter.SetVar("WEST" , WEST) // WEST (8) + + // Channel macros + interpreter.SetVar("$common", PUB_FREQ) + interpreter.SetVar("$science", SCI_FREQ) + interpreter.SetVar("$command", COMM_FREQ) + interpreter.SetVar("$medical", MED_FREQ) + interpreter.SetVar("$engineering",ENG_FREQ) + interpreter.SetVar("$security", SEC_FREQ) + interpreter.SetVar("$supply", SUP_FREQ) + interpreter.SetVar("$exploration", EXP_FREQ) + + // Signal data + + interpreter.SetVar("$content", signal.data["message"]) + interpreter.SetVar("$freq" , signal.frequency) + interpreter.SetVar("$source" , signal.data["name"]) + interpreter.SetVar("$job" , signal.data["job"]) + interpreter.SetVar("$sign" , signal) + interpreter.SetVar("$pass" , !(signal.data["reject"])) // if the signal isn't rejected, pass = 1; if the signal IS rejected, pass = 0 + + // Set up the script procs + + /* + -> Send another signal to a server + @format: broadcast(content, frequency, source, job) + + @param content: Message to broadcast + @param frequency: Frequency to broadcast to + @param source: The name of the source you wish to imitate. Must be stored in stored_names list. + @param job: The name of the job. + */ + interpreter.SetProc("broadcast", "tcombroadcast", signal, list("message", "freq", "source", "job")) + + /* + -> Store a value permanently to the server machine (not the actual game hosting machine, the ingame machine) + @format: mem(address, value) + + @param address: The memory address (string index) to store a value to + @param value: The value to store to the memory address + */ + interpreter.SetProc("mem", "mem", signal, list("address", "value")) + + /* + -> Delay code for a given amount of deciseconds + @format: sleep(time) + + @param time: time to sleep in deciseconds (1/10th second) + */ + interpreter.SetProc("sleep", /proc/delay) + + /* + -> Replaces a string with another string + @format: replace(string, substring, replacestring) + + @param string: the string to search for substrings (best used with $content$ constant) + @param substring: the substring to search for + @param replacestring: the string to replace the substring with + + */ + interpreter.SetProc("replace", /proc/string_replacetext) + + /* + -> Locates an element/substring inside of a list or string + @format: find(haystack, needle, start = 1, end = 0) + + @param haystack: the container to search + @param needle: the element to search for + @param start: the position to start in + @param end: the position to end in + + */ + interpreter.SetProc("find", /proc/smartfind) + + /* + -> Finds the length of a string or list + @format: length(container) + + @param container: the list or container to measure + + */ + interpreter.SetProc("length", /proc/smartlength) + + /* -- Clone functions, carried from default BYOND procs --- */ + + // vector namespace + interpreter.SetProc("vector", /proc/n_list) + interpreter.SetProc("at", /proc/n_listpos) + interpreter.SetProc("copy", /proc/n_listcopy) + interpreter.SetProc("push_back", /proc/n_listadd) + interpreter.SetProc("remove", /proc/n_listremove) + interpreter.SetProc("cut", /proc/n_listcut) + interpreter.SetProc("swap", /proc/n_listswap) + interpreter.SetProc("insert", /proc/n_listinsert) + + interpreter.SetProc("pick", /proc/n_pick) + interpreter.SetProc("prob", /proc/prob_chance) + interpreter.SetProc("substr", /proc/docopytext) + + // Donkie~ + // Strings + interpreter.SetProc("lower", /proc/n_lower) + interpreter.SetProc("upper", /proc/n_upper) + interpreter.SetProc("explode", /proc/string_explode) + interpreter.SetProc("repeat", /proc/n_repeat) + interpreter.SetProc("reverse", /proc/n_reverse) + interpreter.SetProc("tonum", /proc/n_str2num) + + // Numbers + interpreter.SetProc("tostring", /proc/n_num2str) + interpreter.SetProc("sqrt", /proc/n_sqrt) + interpreter.SetProc("abs", /proc/n_abs) + interpreter.SetProc("floor", /proc/n_floor) + interpreter.SetProc("ceil", /proc/n_ceil) + interpreter.SetProc("round", /proc/n_round) + interpreter.SetProc("clamp", /proc/n_clamp) + interpreter.SetProc("inrange", /proc/n_inrange) + // End of Donkie~ + + + // Run the compiled code + interpreter.Run() + + // Backwards-apply variables onto signal data + /* sanitize EVERYTHING. fucking players can't be trusted with SHIT */ + + signal.data["message"] = interpreter.GetVar("$content") + signal.frequency = interpreter.GetVar("$freq") + + var/setname = "" + var/obj/machinery/telecomms/server/S = signal.data["server"] + if(interpreter.GetVar("$source") in S.stored_names) + setname = interpreter.GetVar("$source") + else + setname = "[interpreter.GetVar("$source")]" + + if(signal.data["name"] != setname) + signal.data["realname"] = setname + signal.data["name"] = setname + signal.data["job"] = interpreter.GetVar("$job") + signal.data["reject"] = !(interpreter.GetVar("$pass")) // set reject to the opposite of $pass + + // If the message is invalid, just don't broadcast it! + if(signal.data["message"] == "" || !signal.data["message"]) + signal.data["reject"] = 1 + +/* -- Actual language proc code -- */ + +datum/signal + + proc/mem(var/address, var/value) + + if(istext(address)) + var/obj/machinery/telecomms/server/S = data["server"] + + if(!value && value != 0) + return S.memory[address] + + else + S.memory[address] = value + + + proc/tcombroadcast(var/message, var/freq, var/source, var/job) + + var/datum/signal/newsign = new + var/obj/machinery/telecomms/server/S = data["server"] + var/obj/item/device/radio/hradio = S.server_radio + + if(!hradio) + error("[src] has no radio.") + return + + if((!message || message == "") && message != 0) + message = "*beep*" + if(!source) + source = "[html_encode(uppertext(S.id))]" + hradio = new // sets the hradio as a radio intercom + if(!freq) + freq = PUB_FREQ + if(findtext(num2text(freq), ".")) // if the frequency has been set as a decimal + freq *= 10 // shift the decimal one place + + if(!job) + job = "?" + + newsign.data["mob"] = null + newsign.data["mobtype"] = /mob/living/carbon/human + if(source in S.stored_names) + newsign.data["name"] = source + else + newsign.data["name"] = "[html_encode(uppertext(source))]" + newsign.data["realname"] = newsign.data["name"] + newsign.data["job"] = job + newsign.data["compression"] = 0 + newsign.data["message"] = message + newsign.data["type"] = 2 // artificial broadcast + if(!isnum(freq)) + freq = text2num(freq) + newsign.frequency = freq + + var/datum/radio_frequency/connection = radio_controller.return_frequency(freq) + newsign.data["connection"] = connection + + + newsign.data["radio"] = hradio + newsign.data["vmessage"] = message + newsign.data["vname"] = source + newsign.data["vmask"] = 0 + newsign.data["level"] = list() + + var/pass = S.relay_information(newsign, /obj/machinery/telecomms/hub) + if(!pass) + S.relay_information(newsign, /obj/machinery/telecomms/broadcaster) // send this simple message to broadcasters + diff --git a/code/modules/scripting/Implementations/_Logic.dm b/code/modules/scripting/Implementations/_Logic.dm new file mode 100644 index 00000000..fc4f32c5 --- /dev/null +++ b/code/modules/scripting/Implementations/_Logic.dm @@ -0,0 +1,291 @@ +// Script -> BYOND code procs +#define SCRIPT_MAX_REPLACEMENTS_ALLOWED 200 +// --- List operations (lists known as vectors in n_script) --- + +// Clone of list() +/proc/n_list() + var/list/returnlist = list() + for(var/e in args) + returnlist.Add(e) + return returnlist + +// Clone of pick() +/proc/n_pick() + var/list/finalpick = list() + for(var/e in args) + if(isobject(e)) + if(istype(e, /list)) + var/list/sublist = e + for(var/sube in sublist) + finalpick.Add(sube) + continue + finalpick.Add(e) + + return pick(finalpick) + +// Clone of list[] +/proc/n_listpos(var/list/L, var/pos, var/value) + if(!istype(L, /list)) return + if(isnum(pos)) + if(!value) + if(L.len >= pos) + return L[pos] + else + if(L.len >= pos) + L[pos] = value + else if(istext(pos)) + if(!value) + return L[pos] + else + L[pos] = value + +// Clone of list.Copy() +/proc/n_listcopy(var/list/L, var/start, var/end) + if(!istype(L, /list)) return + return L.Copy(start, end) + +// Clone of list.Add() +/proc/n_listadd() + var/list/chosenlist + var/i = 1 + for(var/e in args) + if(i == 1) + if(isobject(e)) + if(istype(e, /list)) + chosenlist = e + i = 2 + else + if(chosenlist) + chosenlist.Add(e) + +// Clone of list.Remove() +/proc/n_listremove() + var/list/chosenlist + var/i = 1 + for(var/e in args) + if(i == 1) + if(isobject(e)) + if(istype(e, /list)) + chosenlist = e + i = 2 + else + if(chosenlist) + chosenlist.Remove(e) + +// Clone of list.Cut() +/proc/n_listcut(var/list/L, var/start, var/end) + if(!istype(L, /list)) return + return L.Cut(start, end) + +// Clone of list.Swap() +/proc/n_listswap(var/list/L, var/firstindex, var/secondindex) + if(!istype(L, /list)) return + if(L.len >= secondindex && L.len >= firstindex) + return L.Swap(firstindex, secondindex) + +// Clone of list.Insert() +/proc/n_listinsert(var/list/L, var/index, var/element) + if(!istype(L, /list)) return + return L.Insert(index, element) + +// --- Miscellaneous functions --- + +// Clone of sleep() +/proc/delay(var/time) + sleep(time) + +// Clone of prob() +/proc/prob_chance(var/chance) + return prob(chance) + +// Merge of list.Find() and findtext() +/proc/smartfind(var/haystack, var/needle, var/start = 1, var/end = 0) + if(haystack && needle) + if(isobject(haystack)) + if(istype(haystack, /list)) + if(length(haystack) >= end && start > 0) + var/list/listhaystack = haystack + return listhaystack.Find(needle, start, end) + + else + if(istext(haystack)) + if(length(haystack) >= end && start > 0) + return findtext(haystack, needle, start, end) + +// Clone of copytext() +/proc/docopytext(var/string, var/start = 1, var/end = 0) + if(istext(string) && isnum(start) && isnum(end)) + if(start > 0) + return copytext(string, start, end) + +// Clone of length() +/proc/smartlength(var/container) + if(container) + if(istype(container, /list) || istext(container)) + return length(container) + +// BY DONKIE~ +// String stuff +/proc/n_lower(var/string) + if(istext(string)) + return lowertext(string) + +/proc/n_upper(var/string) + if(istext(string)) + return uppertext(string) + +/* +//Makes a list where all indicies in a string is a seperate index in the list +// JUST A HELPER DON'T ADD TO NTSCRIPT +proc/string_tolist(var/string) + var/list/L = new/list() + + var/i + for(i=1, i<=length(string), i++) + L.Add(copytext(string, i, i)) + + return L + +proc/string_explode(var/string, var/separator) + if(istext(string)) + if(istext(separator) && separator == "") + return string_tolist(string) + var/i + var/lasti = 1 + var/list/L = new/list() + + for(i=1, i<=length(string)+1, i++) + if(copytext(string, i, i+1) == separator) // We found a separator + L.Add(copytext(string, lasti, i)) + lasti = i+1 + + L.Add(copytext(string, lasti, length(string)+1)) // Adds the last segment + + return L + +Just found out there was already a string explode function, did some benchmarking, and that function were a bit faster, sticking to that. +*/ +proc/string_explode(var/string, var/separator) + if(istext(string) && istext(separator)) + return splittext(string, separator) + +proc/n_repeat(var/string, var/amount) + if(istext(string) && isnum(amount)) + var/i + var/newstring = "" + if(length(newstring)*amount >=1000) + return + for(i=0, i<=amount, i++) + if(i>=1000) + break + newstring = newstring + string + + return newstring + +proc/n_reverse(var/string) + if(istext(string)) + var/newstring = "" + var/i + for(i=length(string), i>0, i--) + if(i>=1000) + break + newstring = newstring + copytext(string, i, i+1) + + return newstring + +// I don't know if it's neccesary to make my own proc, but I think I have to to be able to check for istext. +proc/n_str2num(var/string) + if(istext(string)) + return text2num(string) + +// Number shit +proc/n_num2str(var/num) + if(isnum(num)) + return num2text(num) + +// Squareroot +proc/n_sqrt(var/num) + if(isnum(num)) + return sqrt(num) + +// Magnitude of num +proc/n_abs(var/num) + if(isnum(num)) + return abs(num) + +// Round down +proc/n_floor(var/num) + if(isnum(num)) + return round(num) + +// Round up +proc/n_ceil(var/num) + if(isnum(num)) + return round(num)+1 + +// Round to nearest integer +proc/n_round(var/num) + if(isnum(num)) + if(num-round(num)<0.5) + return round(num) + return n_ceil(num) + +// Clamps N between min and max +proc/n_clamp(var/num, var/min=-1, var/max=1) + if(isnum(num)&&isnum(min)&&isnum(max)) + if(num<=min) + return min + if(num>=max) + return max + return num + +// Returns 1 if N is inbetween Min and Max +proc/n_inrange(var/num, var/min=-1, var/max=1) + if(isnum(num)&&isnum(min)&&isnum(max)) + return ((min <= num) && (num <= max)) +// END OF BY DONKIE :( + +// Non-recursive +// Imported from Mono string.ReplaceUnchecked +/proc/string_replacetext(var/haystack,var/a,var/b) + if(istext(haystack)&&istext(a)&&istext(b)) + var/i = 1 + var/lenh=length(haystack) + var/lena=length(a) + //var/lenb=length(b) + var/count = 0 + var/list/dat = list() + while (i < lenh) + var/found = findtext(haystack, a, i, 0) + //log_misc("findtext([haystack], [a], [i], 0)=[found]") + if (found == 0) // Not found + break + else + if (count < SCRIPT_MAX_REPLACEMENTS_ALLOWED) + dat+=found + count+=1 + else + //log_misc("Script found [a] [count] times, aborted") + break + //log_misc("Found [a] at [found]! Moving up...") + i = found + lena + if (count == 0) + return haystack + //var/nlen = lenh + ((lenb - lena) * count) + var/buf = copytext(haystack,1,dat[1]) // Prefill + var/lastReadPos = 0 + for (i = 1, i <= count, i++) + var/precopy = dat[i] - lastReadPos-1 + //internal static unsafe void CharCopy (String target, int targetIndex, String source, int sourceIndex, int count) + //fixed (char* dest = target, src = source) + //CharCopy (dest + targetIndex, src + sourceIndex, count); + //CharCopy (dest + curPos, source + lastReadPos, precopy); + buf+=copytext(haystack,lastReadPos,precopy) + log_misc("buf+=copytext([haystack],[lastReadPos],[precopy])") + log_misc("[buf]") + lastReadPos = dat[i] + lena + //CharCopy (dest + curPos, replace, newValue.length); + buf+=b + log_misc("[buf]") + buf+=copytext(haystack,lastReadPos, 0) + return buf diff --git a/code/modules/scripting/Interpreter/Evaluation.dm b/code/modules/scripting/Interpreter/Evaluation.dm new file mode 100644 index 00000000..6cec1e0f --- /dev/null +++ b/code/modules/scripting/Interpreter/Evaluation.dm @@ -0,0 +1,169 @@ +/proc/isobject(x) + return (istype(x, /datum) || istype(x, /list) || istype(x, /savefile) || istype(x, /client) || (x==world)) + +/n_Interpreter + proc + Eval(node/expression/exp) + if(istype(exp, /node/expression/FunctionCall)) + return RunFunction(exp) + else if(istype(exp, /node/expression/operator)) + return EvalOperator(exp) + else if(istype(exp, /node/expression/value/literal)) + var/node/expression/value/literal/lit=exp + return lit.value + else if(istype(exp, /node/expression/value/reference)) + var/node/expression/value/reference/ref=exp + return ref.value + else if(istype(exp, /node/expression/value/variable)) + var/node/expression/value/variable/v=exp + if(!v.object) + return Eval(GetVariable(v.id.id_name)) + else + var/datum/D + if(istype(v.object, /node/identifier)) + D=GetVariable(v.object:id_name) + else + D=v.object + D=Eval(D) + if(!isobject(D)) + return null + if(!D.vars.Find(v.id.id_name)) + RaiseError(new/runtimeError/UndefinedVariable("[v.object.ToString()].[v.id.id_name]")) + return null + return Eval(D.vars[v.id.id_name]) + else if(istype(exp, /node/expression)) + RaiseError(new/runtimeError/UnknownInstruction()) + else + return exp + + EvalOperator(node/expression/operator/exp) + if(istype(exp, /node/expression/operator/binary)) + var/node/expression/operator/binary/bin=exp + switch(bin.type) + if(/node/expression/operator/binary/Equal) + return Equal(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/NotEqual) + return NotEqual(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/Greater) + return Greater(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/Less) + return Less(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/GreaterOrEqual) + return GreaterOrEqual(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/LessOrEqual) + return LessOrEqual(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/LogicalAnd) + return LogicalAnd(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/LogicalOr) + return LogicalOr(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/LogicalXor) + return LogicalXor(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/BitwiseAnd) + return BitwiseAnd(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/BitwiseOr) + return BitwiseOr(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/BitwiseXor) + return BitwiseXor(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/Add) + return Add(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/Subtract) + return Subtract(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/Multiply) + return Multiply(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/Divide) + return Divide(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/Power) + return Power(Eval(bin.exp), Eval(bin.exp2)) + if(/node/expression/operator/binary/Modulo) + return Modulo(Eval(bin.exp), Eval(bin.exp2)) + else + RaiseError(new/runtimeError/UnknownInstruction()) + else + switch(exp.type) + if(/node/expression/operator/unary/Minus) + return Minus(Eval(exp.exp)) + if(/node/expression/operator/unary/LogicalNot) + return LogicalNot(Eval(exp.exp)) + if(/node/expression/operator/unary/BitwiseNot) + return BitwiseNot(Eval(exp.exp)) + if(/node/expression/operator/unary/group) + return Eval(exp.exp) + else + RaiseError(new/runtimeError/UnknownInstruction()) + + + //Binary// + //Comparison operators + Equal(a, b) return a==b + NotEqual(a, b) return a!=b //LogicalNot(Equal(a, b)) + Greater(a, b) return a>b + Less(a, b) return a=b + LessOrEqual(a, b) return a<=b + //Logical Operators + LogicalAnd(a, b) return a&&b + LogicalOr(a, b) return a||b + LogicalXor(a, b) return (a||b) && !(a&&b) + //Bitwise Operators + BitwiseAnd(a, b) return a&b + BitwiseOr(a, b) return a|b + BitwiseXor(a, b) return a^b + //Arithmetic Operators + Add(a, b) + if(istext(a)&&!istext(b)) b="[b]" + else if(istext(b)&&!istext(a)) a="[a]" + if(isobject(a) && !isobject(b)) + RaiseError(new/runtimeError/TypeMismatch("+", a, b)) + return null + else if(isobject(b) && !isobject(a)) + RaiseError(new/runtimeError/TypeMismatch("+", a, b)) + return null + return a+b + Subtract(a, b) + if(isobject(a) && !isobject(b)) + RaiseError(new/runtimeError/TypeMismatch("-", a, b)) + return null + else if(isobject(b) && !isobject(a)) + RaiseError(new/runtimeError/TypeMismatch("-", a, b)) + return null + return a-b + Divide(a, b) + if(isobject(a) && !isobject(b)) + RaiseError(new/runtimeError/TypeMismatch("/", a, b)) + return null + else if(isobject(b) && !isobject(a)) + RaiseError(new/runtimeError/TypeMismatch("/", a, b)) + return null + if(b==0) + RaiseError(new/runtimeError/DivisionByZero()) + return null + return a/b + Multiply(a, b) + if(isobject(a) && !isobject(b)) + RaiseError(new/runtimeError/TypeMismatch("*", a, b)) + return null + else if(isobject(b) && !isobject(a)) + RaiseError(new/runtimeError/TypeMismatch("*", a, b)) + return null + return a*b + Modulo(a, b) + if(isobject(a) && !isobject(b)) + RaiseError(new/runtimeError/TypeMismatch("%", a, b)) + return null + else if(isobject(b) && !isobject(a)) + RaiseError(new/runtimeError/TypeMismatch("%", a, b)) + return null + return a%b + Power(a, b) + if(isobject(a) && !isobject(b)) + RaiseError(new/runtimeError/TypeMismatch("**", a, b)) + return null + else if(isobject(b) && !isobject(a)) + RaiseError(new/runtimeError/TypeMismatch("**", a, b)) + return null + return a**b + + //Unary// + Minus(a) return -a + LogicalNot(a) return !a + BitwiseNot(a) return ~a \ No newline at end of file diff --git a/code/modules/scripting/Interpreter/Interaction.dm b/code/modules/scripting/Interpreter/Interaction.dm new file mode 100644 index 00000000..50aea6f5 --- /dev/null +++ b/code/modules/scripting/Interpreter/Interaction.dm @@ -0,0 +1,142 @@ +/* + File: Interpreter (Public) + Contains methods for interacting with the interpreter. +*/ +/* + Class: n_Interpreter + Procedures allowing for interaction with the script that is being run by the interpreter object. +*/ + +/n_Interpreter + proc + +/* + Proc: Load + Loads a 'compiled' script into memory. + + Parameters: + program - A object which represents the script's global scope. +*/ + Load(node/BlockDefinition/GlobalBlock/program) + ASSERT(program) + src.program = program + CreateGlobalScope() + +/* + Proc: Run + Runs the script. +*/ + Run() + cur_recursion = 0 // reset recursion + cur_statements = 0 // reset CPU tracking + alertadmins = 0 + + ASSERT(src.program) + RunBlock(src.program) + +/* + Proc: SetVar + Defines a global variable for the duration of the next execution of a script. + + Notes: + This differs from in that variables set using this procedure only last for the session, + while those defined from the block object persist if it is ran multiple times. + + See Also: + - +*/ + SetVar(name, value) + if(!istext(name)) + //CRASH("Invalid variable name") + return + AssignVariable(name, value) + +/* + Proc: SetProc + Defines a procedure to be available to the script. + + Parameters: + name - The name of the procedure as exposed to the script. + path - The typepath of a proc to be called when the function call is read by the interpreter, or, if object is specified, a string representing the procedure's name. + object - (Optional) An object which will the be target of a function call. + params - Only required if object is not null, a list of the names of parameters the proc takes. +*/ + SetProc(name, path, object=null, list/params=null) + if(!istext(name)) + //CRASH("Invalid function name") + return + if(!object) + globalScope.functions[name] = path + else + var/node/statement/FunctionDefinition/S = new() + S.func_name = name + S.parameters = params + S.block = new() + S.block.SetVar("src", object) + var/node/expression/FunctionCall/C = new() + C.func_name = path + C.object = new("src") + for(var/p in params) + C.parameters += new/node/expression/value/variable(p) + var/node/statement/ReturnStatement/R=new() + R.value=C + S.block.statements += R + globalScope.functions[name] = S +/* + Proc: VarExists + Checks whether a global variable with the specified name exists. +*/ + VarExists(name) + return globalScope.variables.Find(name) //convert to 1/0 first? + +/* + Proc: ProcExists + Checks whether a global function with the specified name exists. +*/ + ProcExists(name) + return globalScope.functions.Find(name) + +/* + Proc: GetVar + Returns the value of a global variable in the script. Remember to ensure that the variable exists before calling this procedure. + + See Also: + - +*/ + GetVar(name) + if(!VarExists(name)) + //CRASH("No variable named '[name]'.") + return + var/x = globalScope.variables[name] + return Eval(x) + +/* + Proc: CallProc + Calls a global function defined in the script and, amazingly enough, returns its return value. Remember to ensure that the function + exists before calling this procedure. + + See Also: + - +*/ + CallProc(name, params[]=null) + if(!ProcExists(name)) + //CRASH("No function named '[name]'.") + return + var/node/statement/FunctionDefinition/func = globalScope.functions[name] + if(istype(func)) + var/node/statement/FunctionCall/stmt = new + stmt.func_name = func.func_name + stmt.parameters = params + return RunFunction(stmt) + else + return call(func)(arglist(params)) + //CRASH("Unknown function type '[name]'.") + +/* + Event: HandleError + Called when the interpreter throws a runtime error. + + See Also: + - +*/ + HandleError(runtimeError/e) \ No newline at end of file diff --git a/code/modules/scripting/Interpreter/Interpreter.dm b/code/modules/scripting/Interpreter/Interpreter.dm new file mode 100644 index 00000000..ec3955ca --- /dev/null +++ b/code/modules/scripting/Interpreter/Interpreter.dm @@ -0,0 +1,314 @@ +/* + File: Interpreter (Internal) +*/ +/* + Class: n_Interpreter +*/ +/* + Macros: Status Macros + RETURNING - Indicates that the current function is returning a value. + BREAKING - Indicates that the current loop is being terminated. + CONTINUING - Indicates that the rest of the current iteration of a loop is being skipped. +*/ +#define RETURNING 1 +#define BREAKING 2 +#define CONTINUING 4 +/n_Interpreter + var + scope + curScope + globalScope + node + BlockDefinition/program + statement/FunctionDefinition/curFunction + stack + scopes = new() + functions = new() + + datum/container // associated container for interpeter +/* + Var: status + A variable indicating that the rest of the current block should be skipped. This may be set to any combination of . +*/ + status=0 + returnVal + + max_statements=1000 // maximum amount of statements that can be called in one execution. this is to prevent massive crashes and exploitation + cur_statements=0 // current amount of statements called + alertadmins=0 // set to 1 if the admins shouldn't be notified of anymore issues + max_iterations=100 // max number of uninterrupted loops possible + max_recursion=50 // max recursions without returning anything (or completing the code block) + cur_recursion=0 // current amount of recursion +/* + Var: persist + If 0, global variables will be reset after Run() finishes. +*/ + persist=1 + paused=0 + +/* + Constructor: New + Calls with the given parameters. +*/ + New(node/BlockDefinition/GlobalBlock/program=null) + .=..() + if(program)Load(program) + + proc +/* + Proc: RaiseError + Raises a runtime error. +*/ + RaiseError(runtimeError/e) + e.stack=functions.Copy() + e.stack.Push(curFunction) + src.HandleError(e) + + CreateScope(node/BlockDefinition/B) + var/scope/S = new(B, curScope) + scopes.Push(curScope) + curScope = S + return S + + CreateGlobalScope() + scopes.Clear() + var/scope/S = new(program, null) + globalScope = S + return S + +/* + Proc: RunBlock + Runs each statement in a block of code. +*/ + RunBlock(node/BlockDefinition/Block, scope/scope = null) + var/is_global = istype(Block, /node/BlockDefinition/GlobalBlock) + if(!is_global) + if(scope) + curScope = scope + else + CreateScope(Block) + else + if(!persist) + CreateGlobalScope() + curScope = globalScope + + if(cur_statements < max_statements) + + for(var/node/statement/S in Block.statements) + while(paused) sleep(10) + + cur_statements++ + if(cur_statements >= max_statements) + RaiseError(new/runtimeError/MaxCPU()) + + if(container && !alertadmins) + if(istype(container, /datum/TCS_Compiler)) + var/datum/TCS_Compiler/Compiler = container + var/obj/machinery/telecomms/server/Holder = Compiler.Holder + var/message = "Potential crash-inducing NTSL script detected at telecommunications server [Compiler.Holder] ([Holder.x], [Holder.y], [Holder.z])." + + alertadmins = 1 + message_admins(message, 1) + break + + if(istype(S, /node/statement/VariableAssignment)) + var/node/statement/VariableAssignment/stmt = S + var/name = stmt.var_name.id_name + if(!stmt.object) + // Below we assign the variable first to null if it doesn't already exist. + // This is necessary for assignments like +=, and when the variable is used in a function + // If the variable already exists in a different block, then AssignVariable will automatically use that one. + if(!IsVariableAccessible(name)) + AssignVariable(name, null) + AssignVariable(name, Eval(stmt.value)) + else + var/datum/D = Eval(GetVariable(stmt.object.id_name)) + if(!D) return + D.vars[stmt.var_name.id_name] = Eval(stmt.value) + else if(istype(S, /node/statement/VariableDeclaration)) + //VariableDeclaration nodes are used to forcibly declare a local variable so that one in a higher scope isn't used by default. + var/node/statement/VariableDeclaration/dec=S + if(!dec.object) + AssignVariable(dec.var_name.id_name, null, curScope) + else + var/datum/D = Eval(GetVariable(dec.object.id_name)) + if(!D) return + D.vars[dec.var_name.id_name] = null + else if(istype(S, /node/statement/FunctionCall)) + RunFunction(S) + else if(istype(S, /node/statement/FunctionDefinition)) + //do nothing + else if(istype(S, /node/statement/WhileLoop)) + RunWhile(S) + else if(istype(S, /node/statement/IfStatement)) + RunIf(S) + else if(istype(S, /node/statement/ReturnStatement)) + if(!curFunction) + RaiseError(new/runtimeError/UnexpectedReturn()) + continue + status |= RETURNING + returnVal=Eval(S:value) + break + else if(istype(S, /node/statement/BreakStatement)) + status |= BREAKING + break + else if(istype(S, /node/statement/ContinueStatement)) + status |= CONTINUING + break + else + RaiseError(new/runtimeError/UnknownInstruction()) + if(status) + break + + curScope = scopes.Pop() + +/* + Proc: RunFunction + Runs a function block or a proc with the arguments specified in the script. +*/ + RunFunction(node/statement/FunctionCall/stmt) + //Note that anywhere /node/statement/FunctionCall/stmt is used so may /node/expression/FunctionCall + + // If recursion gets too high (max 50 nested functions) throw an error + if(cur_recursion >= max_recursion) + RaiseError(new/runtimeError/RecursionLimitReached()) + return 0 + + var/node/statement/FunctionDefinition/def + if(!stmt.object) //A scope's function is being called, stmt.object is null + def = GetFunction(stmt.func_name) + else if(istype(stmt.object)) //A method of an object exposed as a variable is being called, stmt.object is a /node/identifier + var/O = GetVariable(stmt.object.id_name) //Gets a reference to the object which is the target of the function call. + if(!O) return //Error already thrown in GetVariable() + def = Eval(O) + + if(!def) return + + cur_recursion++ // add recursion + if(istype(def)) + if(curFunction) functions.Push(curFunction) + var/scope/S = CreateScope(def.block) + for(var/i=1 to def.parameters.len) + var/val + if(stmt.parameters.len>=i) + val = stmt.parameters[i] + //else + // unspecified param + AssignVariable(def.parameters[i], new/node/expression/value/literal(Eval(val)), S) + curFunction=stmt + RunBlock(def.block, S) + //Handle return value + . = returnVal + status &= ~RETURNING + returnVal=null + curFunction=functions.Pop() + cur_recursion-- + else + cur_recursion-- + var/list/params=new + for(var/node/expression/P in stmt.parameters) + params+=list(Eval(P)) + if(isobject(def)) //def is an object which is the target of a function call + if( !hascall(def, stmt.func_name) ) + RaiseError(new/runtimeError/UndefinedFunction("[stmt.object.id_name].[stmt.func_name]")) + return + return call(def, stmt.func_name)(arglist(params)) + else //def is a path to a global proc + return call(def)(arglist(params)) + //else + // RaiseError(new/runtimeError/UnknownInstruction()) + +/* + Proc: RunIf + Checks a condition and runs either the if block or else block. +*/ + RunIf(node/statement/IfStatement/stmt) + if(Eval(stmt.cond)) + RunBlock(stmt.block) + else if(stmt.else_block) + RunBlock(stmt.else_block) + +/* + Proc: RunWhile + Runs a while loop. +*/ + RunWhile(node/statement/WhileLoop/stmt) + var/i=1 + while(Eval(stmt.cond) && Iterate(stmt.block, i++)) + continue + status &= ~BREAKING + +/* + Proc:Iterate + Runs a single iteration of a loop. Returns a value indicating whether or not to continue looping. +*/ + Iterate(node/BlockDefinition/block, count) + RunBlock(block) + if(max_iterations > 0 && count >= max_iterations) + RaiseError(new/runtimeError/IterationLimitReached()) + return 0 + if(status & (BREAKING|RETURNING)) + return 0 + status &= ~CONTINUING + return 1 + +/* + Proc: GetFunction + Finds a function in an accessible scope with the given name. Returns a . +*/ + GetFunction(name) + var/scope/S = curScope + while(S) + if(S.functions.Find(name)) + return S.functions[name] + S = S.parent + RaiseError(new/runtimeError/UndefinedFunction(name)) + +/* + Proc: GetVariable + Finds a variable in an accessible scope and returns its value. +*/ + GetVariable(name) + var/scope/S = curScope + while(S) + if(S.variables.Find(name)) + return S.variables[name] + S = S.parent + RaiseError(new/runtimeError/UndefinedVariable(name)) + + GetVariableScope(name) //needed for when you reassign a variable in a higher scope + var/scope/S = curScope + while(S) + if(S.variables.Find(name)) + return S + S = S.parent + + + IsVariableAccessible(name) + var/scope/S = curScope + while(S) + if(S.variables.Find(name)) + return TRUE + S = S.parent + return FALSE + + +/* + Proc: AssignVariable + Assigns a value to a variable in a specific block. + + Parameters: + name - The name of the variable to assign. + value - The value to assign to it. + S - The scope the variable resides in. If it is null, a scope with the variable already existing is found. If no scopes have a variable of the given name, the current scope is used. +*/ + AssignVariable(name, node/expression/value, scope/S=null) + if(!S) S = GetVariableScope(name) + if(!S) S = curScope + if(!S) S = globalScope + ASSERT(istype(S)) + if(istext(value) || isnum(value) || isnull(value)) value = new/node/expression/value/literal(value) + else if(!istype(value) && isobject(value)) value = new/node/expression/value/reference(value) + //TODO: check for invalid name + S.variables["[name]"] = value + diff --git a/code/modules/scripting/Interpreter/Scope.dm b/code/modules/scripting/Interpreter/Scope.dm new file mode 100644 index 00000000..56ec46cf --- /dev/null +++ b/code/modules/scripting/Interpreter/Scope.dm @@ -0,0 +1,18 @@ +/* + Class: scope + A runtime instance of a block. Used internally by the interpreter. +*/ +scope + var + scope/parent = null + node/BlockDefinition/block + list + functions + variables + + New(node/BlockDefinition/B, scope/parent) + src.block = B + src.parent = parent + src.variables = B.initial_variables.Copy() + src.functions = B.functions.Copy() + .=..() \ No newline at end of file diff --git a/code/modules/scripting/Options.dm b/code/modules/scripting/Options.dm new file mode 100644 index 00000000..59065d43 --- /dev/null +++ b/code/modules/scripting/Options.dm @@ -0,0 +1,83 @@ +/* +File: Options +*/ +var/const //Ascii values of characters + ascii_A =65 + ascii_Z =90 + ascii_a =97 + ascii_z =122 + ascii_DOLLAR = 36 // $ + ascii_ZERO=48 + ascii_THALER = 254 + ascii_NINE=57 + ascii_UNDERSCORE=95 // _ + +/* + Class: n_scriptOptions +*/ +n_scriptOptions + proc + CanStartID(char) //returns true if the character can start a variable, function, or keyword name (by default letters or an underscore) + if(!isnum(char))char=text2ascii(char) + return (char in ascii_A to ascii_Z) || (char in ascii_a to ascii_z) || char==ascii_UNDERSCORE || char==ascii_DOLLAR + + IsValidIDChar(char) //returns true if the character can be in the body of a variable, function, or keyword name (by default letters, numbers, and underscore) + if(!isnum(char))char=text2ascii(char) + return CanStartID(char) || IsDigit(char) + + IsDigit(char) + if(!isnum(char))char=text2ascii(char) + return char in ascii_ZERO to ascii_NINE + + IsValidID(id) //returns true if all the characters in the string are okay to be in an identifier name + if(!CanStartID(id)) //don't need to grab first char in id, since text2ascii does it automatically + return 0 + if(length(id)==1) return 1 + for(var/i=2 to length(id)) + if(!IsValidIDChar(copytext(id, i, i+1))) + return 0 + return 1 + +/* + Class: nS_Options + An implementation of for the n_Script language. +*/ + nS_Options + var + list + symbols = list("(", ")", "\[", "]", ";", ",", "{", "}") //scanner - Characters that can be in symbols +/* + Var: keywords + An associative list used by the parser to parse keywords. Indices are strings which will trigger the keyword when parsed and the + associated values are types of which the proc will be called. +*/ + keywords = list("if" = /n_Keyword/nS_Keyword/kwIf, "else" = /n_Keyword/nS_Keyword/kwElse, \ + "while" = /n_Keyword/nS_Keyword/kwWhile, "break" = /n_Keyword/nS_Keyword/kwBreak, \ + "continue" = /n_Keyword/nS_Keyword/kwContinue, \ + "return" = /n_Keyword/nS_Keyword/kwReturn, "def" = /n_Keyword/nS_Keyword/kwDef) + + list + assign_operators=list("=" = null, "&=" = "&", + "|=" = "|", "`=" = "`", + "+=" = "+", "-=" = "-", + "*=" = "*", "/=" = "/", + "^=" = "^", + "%=" = "%") + + unary_operators =list("!" = /node/expression/operator/unary/LogicalNot, "~" = /node/expression/operator/unary/BitwiseNot, + "-" = /node/expression/operator/unary/Minus) + + binary_operators=list("==" = /node/expression/operator/binary/Equal, "!=" = /node/expression/operator/binary/NotEqual, + ">" = /node/expression/operator/binary/Greater, "<" = /node/expression/operator/binary/Less, + ">=" = /node/expression/operator/binary/GreaterOrEqual,"<=" = /node/expression/operator/binary/LessOrEqual, + "&&" = /node/expression/operator/binary/LogicalAnd, "||" = /node/expression/operator/binary/LogicalOr, + "&" = /node/expression/operator/binary/BitwiseAnd, "|" = /node/expression/operator/binary/BitwiseOr, + "`" = /node/expression/operator/binary/BitwiseXor, "+" = /node/expression/operator/binary/Add, + "-" = /node/expression/operator/binary/Subtract, "*" = /node/expression/operator/binary/Multiply, + "/" = /node/expression/operator/binary/Divide, "^" = /node/expression/operator/binary/Power, + "%" = /node/expression/operator/binary/Modulo) + + New() + .=..() + for(var/O in assign_operators+binary_operators+unary_operators) + if(!symbols.Find(O)) symbols+=O \ No newline at end of file diff --git a/code/modules/scripting/Parser/Expressions.dm b/code/modules/scripting/Parser/Expressions.dm new file mode 100644 index 00000000..91f32973 --- /dev/null +++ b/code/modules/scripting/Parser/Expressions.dm @@ -0,0 +1,314 @@ +/* + File: Expressions + Procedures for parsing expressions. +*/ + +/* + Macros: Expression Macros + OPERATOR - A value indicating the parser currently expects a binary operator. + VALUE - A value indicating the parser currently expects a value. + SHIFT - Tells the parser to push the current operator onto the stack. + REDUCE - Tells the parser to reduce the stack. +*/ +#define OPERATOR 1 +#define VALUE 2 +#define SHIFT 0 +#define REDUCE 1 + +/* + Class: nS_Parser +*/ +/n_Parser/nS_Parser + var +/* + Var: expecting + A variable which keeps track of whether an operator or value is expected. It should be either or . See + for more information. +*/ + expecting=VALUE + + proc +/* + Proc: Precedence + Compares two operators, decides which is higher in the order of operations, and returns or . +*/ + Precedence(node/expression/operator/top, node/expression/operator/input) + if(istype(top)) + top=top.precedence + if(istype(input)) + input=input:precedence + if(top>=input) + return REDUCE + return SHIFT + +/* + Proc: GetExpression + Takes a token expected to represent a value and returns an node. +*/ + GetExpression(token/T) + if(!T) return + if(istype(T, /node/expression)) + return T + switch(T.type) + if(/token/word) + return new/node/expression/value/variable(T.value) + if(/token/accessor) + var + token/accessor/A=T + node/expression/value/variable/E//=new(A.member) + stack/S=new() + while(istype(A.object, /token/accessor)) + S.Push(A) + A=A.object + ASSERT(istext(A.object)) + + while(A) + var/node/expression/value/variable/V=new() + V.id=new(A.member) + if(E) + V.object=E + else + V.object=new/node/identifier(A.object) + E=V + A=S.Pop() + return E + + if(/token/number, /token/string) + return new/node/expression/value/literal(T.value) + +/* + Proc: GetOperator + Gets a path related to a token or string and returns an instance of the given type. This is used to get an instance of either a binary or unary + operator from a token. + + Parameters: + O - The input value. If this is a token, O is reset to the token's value. + When O is a string and is in L, its associated value is used as the path to instantiate. + type - The desired type of the returned object. + L - The list in which to search for O. + + See Also: + - + - +*/ + GetOperator(O, type=/node/expression/operator, L[]) + if(istype(O, type)) return O //O is already the desired type + if(istype(O, /token)) O=O:value //sets O to text + if(istext(O)) //sets O to path + if(L.Find(O)) O=L[O] + else return null + if(ispath(O))O=new O //catches path from last check + else return null //Unknown type + return O + +/* + Proc: GetBinaryOperator + Uses to search for an instance of a binary operator type with which the given string is associated. For example, if + O is set to "+", an node is returned. + + See Also: + - + - +*/ + GetBinaryOperator(O) + return GetOperator(O, /node/expression/operator/binary, options.binary_operators) + +/* + Proc: GetUnaryOperator + Uses to search for an instance of a unary operator type with which the given string is associated. For example, if + O is set to "!", a node is returned. + + See Also: + - + - +*/ + GetUnaryOperator(O) + return GetOperator(O, /node/expression/operator/unary, options.unary_operators) + +/* + Proc: Reduce + Takes the operator on top of the opr stack and assigns its operand(s). Then this proc pushes the value of that operation to the top + of the val stack. +*/ + Reduce(stack/opr, stack/val) + var/node/expression/operator/O=opr.Pop() + if(!O) return + if(!istype(O)) + errors+=new/scriptError("Error reducing expression - invalid operator.") + return + //Take O and assign its operands, popping one or two values from the val stack + //depending on whether O is a binary or unary operator. + if(istype(O, /node/expression/operator/binary)) + var/node/expression/operator/binary/B=O + B.exp2=val.Pop() + B.exp =val.Pop() + val.Push(B) + else + O.exp=val.Pop() + val.Push(O) + +/* + Proc: EndOfExpression + Returns true if the current token represents the end of an expression. + + Parameters: + end - A list of values to compare the current token to. +*/ + EndOfExpression(end[]) + if(!curToken) + return 1 + if(istype(curToken, /token/symbol) && end.Find(curToken.value)) + return 1 + if(istype(curToken, /token/end) && end.Find(/token/end)) + return 1 + return 0 + +/* + Proc: ParseExpression + Uses the Shunting-yard algorithm to parse expressions. + + Notes: + - When an opening parenthesis is found, then is called to handle it. + - The variable helps distinguish unary operators from binary operators (for cases like the - operator, which can be either). + + Articles: + - + - + + See Also: + - + - + - +*/ + ParseExpression(list/end=list(/token/end), list/ErrChars=list("{", "}")) + var/stack + opr=new + val=new + src.expecting=VALUE + for() + if(EndOfExpression(end)) + break + if(istype(curToken, /token/symbol) && ErrChars.Find(curToken.value)) + errors+=new/scriptError/BadToken(curToken) + break + + + if(index>tokens.len) //End of File + errors+=new/scriptError/EndOfFile() + break + var/token/ntok + if(index+1<=tokens.len) + ntok=tokens[index+1] + + if(istype(curToken, /token/symbol) && curToken.value=="(") //Parse parentheses expression + if(expecting!=VALUE) + errors+=new/scriptError/ExpectedToken("operator", curToken) + NextToken() + continue + val.Push(ParseParenExpression()) + else if(istype(curToken, /token/symbol)) //Operator found. + var/node/expression/operator/curOperator //Figure out whether it is unary or binary and get a new instance. + if(src.expecting==OPERATOR) + curOperator=GetBinaryOperator(curToken) + if(!curOperator) + errors+=new/scriptError/ExpectedToken("operator", curToken) + NextToken() + continue + else + curOperator=GetUnaryOperator(curToken) + if(!curOperator) //given symbol isn't a unary operator + errors+=new/scriptError/ExpectedToken("expression", curToken) + NextToken() + continue + + if(opr.Top() && Precedence(opr.Top(), curOperator)==REDUCE) //Check order of operations and reduce if necessary + Reduce(opr, val) + continue + opr.Push(curOperator) + src.expecting=VALUE + else if(ntok && ntok.value=="(" && istype(ntok, /token/symbol)\ + && istype(curToken, /token/word)) //Parse function call + var/token/preToken=curToken + var/old_expect=src.expecting + var/fex=ParseFunctionExpression() + if(old_expect!=VALUE) + errors+=new/scriptError/ExpectedToken("operator", preToken) + NextToken() + continue + val.Push(fex) + else if(istype(curToken, /token/keyword)) //inline keywords + var/n_Keyword/kw=options.keywords[curToken.value] + kw=new kw(inline=1) + if(kw) + if(!kw.Parse(src)) + return + else + errors+=new/scriptError/BadToken(curToken) + else if(istype(curToken, /token/end)) //semicolon found where it wasn't expected + errors+=new/scriptError/BadToken(curToken) + NextToken() + continue + else + if(expecting!=VALUE) + errors+=new/scriptError/ExpectedToken("operator", curToken) + NextToken() + continue + val.Push(GetExpression(curToken)) + src.expecting=OPERATOR + NextToken() + + while(opr.Top()) Reduce(opr, val) //Reduce the value stack completely + .=val.Pop() //Return what should be the last value on the stack + if(val.Top()) // + var/node/N=val.Pop() + errors+=new/scriptError("Error parsing expression. Unexpected value left on stack: [N.ToString()].") + return null + +/* + Proc: ParseFunctionExpression + Parses a function call inside of an expression. + + See Also: + - +*/ + ParseFunctionExpression() + var/node/expression/FunctionCall/exp=new + exp.func_name=curToken.value + NextToken() //skip function name + NextToken() //skip open parenthesis, already found + var/loops = 0 + + for() + loops++ + if(loops>=1000) + CRASH("Something TERRIBLE has gone wrong in ParseFunctionExpression ;__;") + + if(istype(curToken, /token/symbol) && curToken.value==")") + return exp + exp.parameters+=ParseParamExpression() + if(curToken.value==","&&istype(curToken, /token/symbol))NextToken() //skip comma + if(istype(curToken, /token/end)) //Prevents infinite loop... + errors+=new/scriptError/ExpectedToken(")") + return exp + +/* + Proc: ParseParenExpression + Parses an expression that ends with a close parenthesis. This is used for parsing expressions inside of parentheses. + + See Also: + - +*/ + ParseParenExpression() + if(!CheckToken("(", /token/symbol)) + return + return new/node/expression/operator/unary/group(ParseExpression(list(")"))) + +/* + Proc: ParseParamExpression + Parses an expression that ends with either a comma or close parenthesis. This is used for parsing the parameters passed to a function call. + + See Also: + - +*/ + ParseParamExpression() + return ParseExpression(list(",", ")")) \ No newline at end of file diff --git a/code/modules/scripting/Parser/Keywords.dm b/code/modules/scripting/Parser/Keywords.dm new file mode 100644 index 00000000..7d2e6c2d --- /dev/null +++ b/code/modules/scripting/Parser/Keywords.dm @@ -0,0 +1,166 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +/* + File: Keywords +*/ +var/const/KW_FAIL = 0 //Fatal error; stop parsing entire script. +var/const/KW_PASS = 1 //OK +var/const/KW_ERR = 2 //Non-fatal error, keyword couldn't be handled properly. Ignore keyword but continue on. +var/const/KW_WARN = 3 //Warning + +/* +var/const/Class: n_Keyword +var/const/Represents a special statement in the code triggered by a keyword. +*/ +/n_Keyword + New(inline=0) + src.inline=inline + return ..() + +/* + Var: inline + 1 if the keyword is in an expression (e.g. the new keyword in many languages), 0 otherwise (such as the if and else keywords). +*/ + var/inline + +/* + Proc: Parse + Called when the parser finds a keyword in the code. + + Parameters: + parser - The parser that created this object. You can use the parameter to manipulate the parser in order to add statements and blocks + to its AST. +*/ + proc/Parse(n_Parser/parser) + +/* + Class: nS_Keyword + A keyword in n_Script. By default these include return, if, else, while, and def. To enable or disable a keyword, change the + list. + + Behavior: + When a parser is expecting a new statement, and a keyword listed in is found, it will call the keyword's + proc. +*/ +// + nS_Keyword + New(inline=0) + if(inline) + qdel(src) + + kwReturn + Parse(n_Parser/nS_Parser/parser) + .=KW_PASS + if(istype(parser.curBlock, /node/BlockDefinition/GlobalBlock)) + parser.errors+=new/scriptError/BadReturn(parser.curToken) + . = KW_WARN + var/node/statement/ReturnStatement/stmt=new + parser.NextToken() //skip 'return' token + stmt.value=parser.ParseExpression() + parser.curBlock.statements+=stmt + + kwIf + Parse(n_Parser/nS_Parser/parser) + .=KW_PASS + var/node/statement/IfStatement/stmt=new + parser.NextToken() //skip 'if' token + stmt.cond=parser.ParseParenExpression() + if(!parser.CheckToken(")", /token/symbol)) + return KW_FAIL + if(!parser.CheckToken("{", /token/symbol, skip=0)) //Token needs to be preserved for parse loop, so skip=0 + return KW_ERR + parser.curBlock.statements+=stmt + stmt.block=new + parser.AddBlock(stmt.block) + + kwElse + Parse(n_Parser/nS_Parser/parser) + .=KW_PASS + var/list/L=parser.curBlock.statements + var/node/statement/IfStatement/stmt + if(L&&L.len) stmt=L[L.len] //Get the last statement in the current block + if(!stmt || !istype(stmt) || stmt.else_block) //Ensure that it is an if statement + parser.errors+=new/scriptError/ExpectedToken("if statement",parser.curToken) + return KW_FAIL + parser.NextToken() //skip 'else' token + if(!parser.CheckToken("{", /token/symbol, skip=0)) + return KW_ERR + stmt.else_block=new() + parser.AddBlock(stmt.else_block) + + kwWhile + Parse(n_Parser/nS_Parser/parser) + .=KW_PASS + var/node/statement/WhileLoop/stmt=new + parser.NextToken() //skip 'while' token + stmt.cond=parser.ParseParenExpression() + if(!parser.CheckToken(")", /token/symbol)) + return KW_FAIL + if(!parser.CheckToken("{", /token/symbol, skip=0)) + return KW_ERR + parser.curBlock.statements+=stmt + stmt.block=new + parser.AddBlock(stmt.block) + + kwBreak + Parse(n_Parser/nS_Parser/parser) + .=KW_PASS + if(istype(parser.curBlock, /node/BlockDefinition/GlobalBlock)) + parser.errors+=new/scriptError/BadToken(parser.curToken) + . = KW_WARN + var/node/statement/BreakStatement/stmt=new + parser.NextToken() //skip 'break' token + parser.curBlock.statements+=stmt + + kwContinue + Parse(n_Parser/nS_Parser/parser) + .=KW_PASS + if(istype(parser.curBlock, /node/BlockDefinition/GlobalBlock)) + parser.errors+=new/scriptError/BadToken(parser.curToken) + . = KW_WARN + var/node/statement/ContinueStatement/stmt=new + parser.NextToken() //skip 'break' token + parser.curBlock.statements+=stmt + + kwDef + Parse(n_Parser/nS_Parser/parser) + .=KW_PASS + var/node/statement/FunctionDefinition/def=new + parser.NextToken() //skip 'def' token + if(!parser.options.IsValidID(parser.curToken.value)) + parser.errors+=new/scriptError/InvalidID(parser.curToken) + return KW_FAIL + def.func_name=parser.curToken.value + parser.NextToken() + if(!parser.CheckToken("(", /token/symbol)) + return KW_FAIL + for() //for now parameters can be separated by whitespace - they don't need a comma in between + if(istype(parser.curToken, /token/symbol)) + switch(parser.curToken.value) + if(",") + parser.NextToken() + if(")") + break + else + parser.errors+=new/scriptError/BadToken(parser.curToken) + return KW_ERR + + else if(istype(parser.curToken, /token/word)) + def.parameters+=parser.curToken.value + parser.NextToken() + else + parser.errors+=new/scriptError/InvalidID(parser.curToken) + return KW_ERR + if(!parser.CheckToken(")", /token/symbol)) + return KW_FAIL + + if(istype(parser.curToken, /token/end)) //Function prototype + parser.curBlock.statements+=def + else if(parser.curToken.value=="{" && istype(parser.curToken, /token/symbol)) + def.block = new + parser.curBlock.statements+=def + parser.curBlock.functions[def.func_name]=def + parser.AddBlock(def.block) + else + parser.errors+=new/scriptError/BadToken(parser.curToken) + return KW_FAIL diff --git a/code/modules/scripting/Parser/Parser.dm b/code/modules/scripting/Parser/Parser.dm new file mode 100644 index 00000000..e3366d45 --- /dev/null +++ b/code/modules/scripting/Parser/Parser.dm @@ -0,0 +1,189 @@ +/* + File: Parser +*/ +/* + Class: n_Parser + An object that reads tokens and produces an AST (abstract syntax tree). +*/ +/n_Parser + var +/* + Var: index + The parser's current position in the token's list. +*/ + index = 1 + list +/* + Var: tokens + A list of tokens in the source code generated by a scanner. +*/ + tokens = new +/* + Var: errors + A list of fatal errors found by the parser. If there are any items in this list, then it is not safe to run the returned AST. + + See Also: + - +*/ + errors = new +/* + Var: warnings + A list of non-fatal problems in the script. +*/ + warnings = new + token +/* + Var: curToken + The token at in . +*/ + curToken + stack + blocks=new + node/BlockDefinition + GlobalBlock/global_block=new + curBlock + + proc +/* + Proc: Parse + Reads the tokens and returns the AST's node. Be sure to populate the tokens list before calling this procedure. +*/ + Parse() + +/* + Proc: NextToken + Sets to the next token in the list, or null if there are no more tokens. +*/ + NextToken() + if(index>=tokens.len) + curToken=null + else + curToken=tokens[++index] + return curToken + +/* + Class: nS_Parser + An implmentation of a parser for n_Script. +*/ +/n_Parser/nS_Parser + var/n_scriptOptions/nS_Options/options +/* + Constructor: New + + Parameters: + tokens - A list of tokens to parse. + options - An object used for configuration. +*/ + New(tokens[], n_scriptOptions/options) + src.tokens=tokens + src.options=options + curBlock=global_block + return ..() + + Parse() + ASSERT(tokens) + for(,src.index<=src.tokens.len, src.index++) + curToken=tokens[index] + switch(curToken.type) + if(/token/keyword) + var/n_Keyword/kw=options.keywords[curToken.value] + kw=new kw() + if(kw) + if(!kw.Parse(src)) + return + if(/token/word) + var/token/ntok + if(index+1>tokens.len) + errors+=new/scriptError/BadToken(curToken) + continue + ntok=tokens[index+1] + if(!istype(ntok, /token/symbol)) + errors+=new/scriptError/BadToken(ntok) + continue + if(ntok.value=="(") + ParseFunctionStatement() + else if(options.assign_operators.Find(ntok.value)) + ParseAssignment() + else + errors+=new/scriptError/BadToken(ntok) + continue + if(!istype(curToken, /token/end)) + errors+=new/scriptError/ExpectedToken(";", curToken) + continue + if(/token/symbol) + if(curToken.value=="}") + if(!EndBlock()) + errors+=new/scriptError/BadToken(curToken) + continue + else + errors+=new/scriptError/BadToken(curToken) + continue + if(/token/end) + warnings+=new/scriptError/BadToken(curToken) + continue + else + errors+=new/scriptError/BadToken(curToken) + return + return global_block + + proc + CheckToken(val, type, err=1, skip=1) + if(curToken.value!=val || !istype(curToken,type)) + if(err) + errors+=new/scriptError/ExpectedToken(val, curToken) + return 0 + if(skip)NextToken() + return 1 + + AddBlock(node/BlockDefinition/B) + blocks.Push(curBlock) + curBlock=B + + EndBlock() + if(curBlock==global_block) return 0 + curBlock=blocks.Pop() + return 1 + + ParseAssignment() + var/name=curToken.value + if(!options.IsValidID(name)) + errors+=new/scriptError/InvalidID(curToken) + return + NextToken() + var/t=options.binary_operators[options.assign_operators[curToken.value]] + var/node/statement/VariableAssignment/stmt=new() + stmt.var_name=new(name) + NextToken() + if(t) + stmt.value=new t() + stmt.value:exp=new/node/expression/value/variable(stmt.var_name) + stmt.value:exp2=ParseExpression() + else + stmt.value=ParseExpression() + curBlock.statements+=stmt + + ParseFunctionStatement() + if(!istype(curToken, /token/word)) + errors+=new/scriptError("Bad identifier in function call.") + return + var/node/statement/FunctionCall/stmt=new + stmt.func_name=curToken.value + NextToken() //skip function name + if(!CheckToken("(", /token/symbol)) //Check for and skip open parenthesis + return + var/loops = 0 + for() + loops++ + if(loops>=6000) + CRASH("Something TERRIBLE has gone wrong in ParseFunctionStatement ;__;") + + if(!curToken) + errors+=new/scriptError/EndOfFile() + return + if(istype(curToken, /token/symbol) && curToken.value==")") + curBlock.statements+=stmt + NextToken() //Skip close parenthesis + return + var/node/expression/P=ParseParamExpression() + stmt.parameters+=P + if(istype(curToken, /token/symbol) && curToken.value==",") NextToken() \ No newline at end of file diff --git a/code/modules/scripting/Scanner/Scanner.dm b/code/modules/scripting/Scanner/Scanner.dm new file mode 100644 index 00000000..a807e6de --- /dev/null +++ b/code/modules/scripting/Scanner/Scanner.dm @@ -0,0 +1,287 @@ +/* + File: Scanner +*/ +/* + Class: n_Scanner + An object responsible for breaking up source code into tokens for use by the parser. +*/ +/n_Scanner + var + code + list +/* + Var: errors + A list of fatal errors found by the scanner. If there are any items in this list, then it is not safe to parse the returned tokens. + + See Also: + - +*/ + errors = new +/* + Var: warnings + A list of non-fatal problems in the source code found by the scanner. +*/ + warnings = new + + proc +/* + Proc: LoadCode + Loads source code. +*/ + LoadCode(c) + code=c + +/* + Proc: LoadCodeFromFile + Gets the code from a file and calls . +*/ + LoadCodeFromFile(f) + LoadCode(file2text(f)) + +/* + Proc: Scan + Runs the scanner and returns the resulting list of tokens. Ensure that has been called first. +*/ + Scan() + +/* + Class: nS_Scanner + A scanner implementation for n_Script. +*/ +/n_Scanner/nS_Scanner + + var +/* + Variable: codepos + The scanner's position in the source code. +*/ + codepos = 1 + line = 1 + linepos = 0 //column=codepos-linepos + n_scriptOptions/nS_Options/options + + commenting = 0 + // 1: single-line + // 2: multi-line + list +/* + Variable: ignore + A list of characters that are ignored by the scanner. + + Default Value: + Whitespace +*/ + ignore = list(" ", "\t", "\n") //Don't add tokens for whitespace +/* + Variable: end_stmt + A list of characters that end a statement. Each item may only be one character long. + + Default Value: + Semicolon +*/ + end_stmt = list(";") +/* + Variable: string_delim + A list of characters that can start and end strings. + + Default Value: + Double and single quotes. +*/ + string_delim = list("\"", "'") +/* + Variable: delim + A list of characters that denote the start of a new token. This list is automatically populated. +*/ + delim = new + +/* + Macro: COL + The current column number. +*/ + #define COL codepos-linepos + +/* + Constructor: New + Parameters: + code - The source code to tokenize. + options - An object used to configure the scanner. +*/ + New(code, n_scriptOptions/nS_Options/options) + .=..() + ignore+= ascii2text(13) //Carriage return + delim += ignore + options.symbols + end_stmt + string_delim + src.options=options + LoadCode(code) + + Scan() //Creates a list of tokens from source code + var/list/tokens=new + for(, src.codepos<=length(code), src.codepos++) + + var/char=copytext(code, codepos, codepos+1) + if(char=="\n") + line++ + linepos=codepos + + if(ignore.Find(char)) + continue + else if(char == "/") + ReadComment() + else if(end_stmt.Find(char)) + tokens+=new /token/end(char, line, COL) + else if(string_delim.Find(char)) + codepos++ //skip string delimiter + tokens+=ReadString(char) + else if(options.CanStartID(char)) + tokens+=ReadWord() + else if(options.IsDigit(char)) + tokens+=ReadNumber() + else if(options.symbols.Find(char)) + tokens+=ReadSymbol() + + + codepos=initial(codepos) + line=initial(line) + linepos=initial(linepos) + return tokens + + proc +/* + Proc: ReadString + Reads a string in the source code into a token. + + Parameters: + start - The character used to start the string. +*/ + ReadString(start) + var + buf + for(, codepos <= length(code), codepos++)//codepos to length(code)) + var/char=copytext(code, codepos, codepos+1) + switch(char) + if("\\") //Backslash (\) encountered in string + codepos++ //Skip next character in string, since it was escaped by a backslash + char=copytext(code, codepos, codepos+1) + switch(char) + if("\\") //Double backslash + buf+="\\" + if("n") //\n Newline + buf+="\n" + else + if(char==start) //\" Doublequote + buf+=start + else //Unknown escaped text + buf+=char + if("\n") + . = new/token/string(buf, line, COL) + errors+=new/scriptError("Unterminated string. Newline reached.", .) + line++ + linepos=codepos + break + else + if(char==start) //string delimiter found, end string + break + else + buf+=char //Just a normal character in a string + if(!.) return new/token/string(buf, line, COL) + +/* + Proc: ReadWord + Reads characters separated by an item in into a token. +*/ + ReadWord() + var + char=copytext(code, codepos, codepos+1) + buf + while(!delim.Find(char) && codepos<=length(code)) + buf+=char + char=copytext(code, ++codepos, codepos+1) + codepos-- //allow main Scan() proc to read the delimiter + if(options.keywords.Find(buf)) + return new /token/keyword(buf, line, COL) + else + return new /token/word(buf, line, COL) + +/* + Proc: ReadSymbol + Reads a symbol into a token. +*/ + ReadSymbol() + var + char=copytext(code, codepos, codepos+1) + buf + + while(options.symbols.Find(buf+char)) + buf+=char + if(++codepos>length(code)) break + char=copytext(code, codepos, codepos+1) + + codepos-- //allow main Scan() proc to read the next character + return new /token/symbol(buf, line, COL) + +/* + Proc: ReadNumber + Reads a number into a token. +*/ + ReadNumber() + var + char=copytext(code, codepos, codepos+1) + buf + dec=0 + + while(options.IsDigit(char) || (char=="." && !dec)) + if(char==".") dec=1 + buf+=char + codepos++ + char=copytext(code, codepos, codepos+1) + var/token/number/T=new(buf, line, COL) + if(isnull(text2num(buf))) + errors+=new/scriptError("Bad number: ", T) + T.value=0 + codepos-- //allow main Scan() proc to read the next character + return T + +/* + Proc: ReadComment + Reads a comment and outputs the type of comment +*/ + + ReadComment() + var + char=copytext(code, codepos, codepos+1) + nextchar=copytext(code, codepos+1, codepos+2) + charstring = char+nextchar + comm = 1 + // 1: single-line comment + // 2: multi-line comment + expectedend = 0 + + if(charstring == "//" || charstring == "/*") + if(charstring == "/*") + comm = 2 // starts a multi-line comment + + while(comm) + if(++codepos>length(code)) break + + if(expectedend) // ending statement expected... + char = copytext(code, codepos, codepos+1) + if(char == "/") // ending statement found - beak the comment + comm = 0 + break + + if(comm == 2) + // multi-line comments are broken by ending statements + char = copytext(code, codepos, codepos+1) + if(char == "*") + expectedend = 1 + continue + else + char = copytext(code, codepos, codepos+1) + if(char == "\n") + comm = 0 + break + + if(expectedend) expectedend = 0 + + if(comm == 2) + errors+=new/scriptError/UnterminatedComment() + diff --git a/code/modules/scripting/Scanner/Tokens.dm b/code/modules/scripting/Scanner/Tokens.dm new file mode 100644 index 00000000..b7e23cb9 --- /dev/null +++ b/code/modules/scripting/Scanner/Tokens.dm @@ -0,0 +1,38 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +/* + Class: Token + Represents an entity and position in the source code. +*/ +/token + var/value + var/line + var/column + + New(v, l=0, c=0) + value=v + line=l + column=c + + string + symbol + word + keyword + number + New() + .=..() + if(!isnum(value)) + value=text2num(value) + ASSERT(!isnull(value)) + accessor + var/object + var/member + + New(object, member, l=0, c=0) + src.object=object + src.member=member + src.value="[object].[member]" //for debugging only + src.line=l + src.column=c + + end diff --git a/code/modules/scripting/stack.dm b/code/modules/scripting/stack.dm new file mode 100644 index 00000000..be4147c7 --- /dev/null +++ b/code/modules/scripting/stack.dm @@ -0,0 +1,23 @@ +/stack + var/list + contents=new + proc + Push(value) + contents+=value + + Pop() + if(!contents.len) return null + . = contents[contents.len] + contents.len-- + + Top() //returns the item on the top of the stack without removing it + if(!contents.len) return null + return contents[contents.len] + + Copy() + var/stack/S=new() + S.contents=src.contents.Copy() + return S + + Clear() + contents.Cut() \ No newline at end of file diff --git a/code/modules/security levels/keycard authentication.dm b/code/modules/security levels/keycard authentication.dm new file mode 100644 index 00000000..cbad14cc --- /dev/null +++ b/code/modules/security levels/keycard authentication.dm @@ -0,0 +1,194 @@ +/obj/machinery/keycard_auth + name = "Keycard Authentication Device" + desc = "This device is used to trigger functions which require more than one ID card to authenticate." + icon = 'icons/obj/monitors.dmi' + icon_state = "auth_off" + var/active = 0 //This gets set to 1 on all devices except the one where the initial request was made. + var/event = "" + var/screen = 1 + var/confirmed = 0 //This variable is set by the device that confirms the request. + var/confirm_delay = 3 SECONDS + var/busy = 0 //Busy when waiting for authentication or an event request has been sent from this device. + var/obj/machinery/keycard_auth/event_source + var/mob/event_triggered_by + var/mob/event_confirmed_by + //1 = select event + //2 = authenticate + anchored = 1.0 + use_power = 1 + idle_power_usage = 2 + active_power_usage = 6 + power_channel = ENVIRON + +/obj/machinery/keycard_auth/attack_ai(mob/user as mob) + to_chat(user, "A firewall prevents you from interfacing with this device!") + return + +/obj/machinery/keycard_auth/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(stat & (NOPOWER|BROKEN)) + to_chat(user, "This device is not powered.") + return + if(istype(W,/obj/item/weapon/card/id)) + var/obj/item/weapon/card/id/ID = W + if(access_keycard_auth in ID.access) + if(active == 1) + //This is not the device that made the initial request. It is the device confirming the request. + if(event_source && event_source.event_triggered_by != usr) + event_source.confirmed = 1 + event_source.event_confirmed_by = usr + else + to_chat(user, "Unable to confirm, DNA matches that of origin.") + else if(screen == 2) + event_triggered_by = usr + broadcast_request() //This is the device making the initial event request. It needs to broadcast to other devices + +//icon_state gets set everwhere besides here, that needs to be fixed sometime +/obj/machinery/keycard_auth/update_icon() + if(stat &NOPOWER) + icon_state = "auth_off" + +/obj/machinery/keycard_auth/attack_hand(mob/user as mob) + if(stat & (NOPOWER|BROKEN)) + to_chat(user, "This device is not powered.") + return + if(!user.IsAdvancedToolUser()) + return 0 + if(busy) + to_chat(user, "This device is busy.") + return + + user.set_machine(src) + + var/dat = "

                Keycard Authentication Device

                " + + dat += "This device is used to trigger some high security events. It requires the simultaneous swipe of two high-level ID cards." + dat += "


                " + + if(screen == 1) + dat += "Select an event to trigger:" + user << browse(dat, "window=keycard_auth;size=500x250") + if(screen == 2) + dat += "Please swipe your card to authorize the following event: [event]" + dat += "

                Back" + user << browse(dat, "window=keycard_auth;size=500x250") + return + +/obj/machinery/keycard_auth/CanUseTopic(var/mob/user, href_list) + if(busy) + to_chat(user, "This device is busy.") + return STATUS_CLOSE + if(!user.IsAdvancedToolUser()) + to_chat(user, FEEDBACK_YOU_LACK_DEXTERITY) + return min(..(), STATUS_UPDATE) + return ..() + +/obj/machinery/keycard_auth/OnTopic(user, href_list) + if(href_list["triggerevent"]) + event = href_list["triggerevent"] + screen = 2 + . = TOPIC_REFRESH + if(href_list["reset"]) + reset() + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + attack_hand(user) + +/obj/machinery/keycard_auth/proc/reset() + active = 0 + event = "" + screen = 1 + confirmed = 0 + event_source = null + icon_state = "auth_off" + event_triggered_by = null + event_confirmed_by = null + +/obj/machinery/keycard_auth/proc/broadcast_request() + icon_state = "auth_on" + for(var/obj/machinery/keycard_auth/KA in world) + if(KA == src) continue + KA.reset() + spawn() + KA.receive_request(src) + + sleep(confirm_delay) + if(confirmed) + confirmed = 0 + trigger_event(event) + log_game("[key_name(event_triggered_by)] triggered and [key_name(event_confirmed_by)] confirmed event [event]") + message_admins("[key_name(event_triggered_by)] triggered and [key_name(event_confirmed_by)] confirmed event [event]", 1) + reset() + +/obj/machinery/keycard_auth/proc/receive_request(var/obj/machinery/keycard_auth/source) + if(stat & (BROKEN|NOPOWER)) + return + event_source = source + busy = 1 + active = 1 + icon_state = "auth_on" + + sleep(confirm_delay) + + event_source = null + icon_state = "auth_off" + active = 0 + busy = 0 + +/obj/machinery/keycard_auth/proc/trigger_event() + switch(event) + if("Red alert") + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + security_state.set_security_level(security_state.high_security_level) + feedback_inc("alert_keycard_auth_red",1) + if("Grant Emergency Maintenance Access") + make_maint_all_access() + feedback_inc("alert_keycard_auth_maintGrant",1) + if("Revoke Emergency Maintenance Access") + revoke_maint_all_access() + feedback_inc("alert_keycard_auth_maintRevoke",1) + if("Emergency Response Team") + if(is_ert_blocked()) + to_chat(usr, "All emergency response teams are dispatched and can not be called at this time.") + return + + trigger_armed_response_team(1) + feedback_inc("alert_keycard_auth_ert",1) + if("Grant Nuclear Authorization Code") + var/obj/machinery/nuclearbomb/nuke = locate(/obj/machinery/nuclearbomb/station) in world + if(nuke) + to_chat(usr, "The nuclear authorization code is [nuke.r_code]") + else + to_chat(usr, "No self destruct terminal found.") + feedback_inc("alert_keycard_auth_nukecode",1) + +/obj/machinery/keycard_auth/proc/is_ert_blocked() + if(config.ert_admin_call_only) return 1 + return ticker.mode && ticker.mode.ert_disabled + +var/global/maint_all_access = 0 + +/proc/make_maint_all_access() + maint_all_access = 1 + to_world("Attention!") + to_world("The maintenance access requirement has been revoked on all airlocks.") + +/proc/revoke_maint_all_access() + maint_all_access = 0 + to_world("Attention!") + to_world("The maintenance access requirement has been readded on all maintenance airlocks.") + +/obj/machinery/door/airlock/allowed(mob/M) + if(maint_all_access && src.check_access_list(list(access_maint_tunnels))) + return 1 + return ..(M) diff --git a/code/modules/shield_generators/floor_diffuser.dm b/code/modules/shield_generators/floor_diffuser.dm new file mode 100644 index 00000000..16352508 --- /dev/null +++ b/code/modules/shield_generators/floor_diffuser.dm @@ -0,0 +1,68 @@ +/obj/machinery/shield_diffuser + name = "shield diffuser" + desc = "A small underfloor device specifically designed to disrupt energy barriers." + description_info = "This device disrupts shields on directly adjacent tiles (in a + shaped pattern). They are commonly installed around exterior airlocks to prevent shields from blocking EVA access." + icon = 'icons/obj/machines/shielding.dmi' + icon_state = "fdiffuser_on" + use_power = 2 + idle_power_usage = 100 + active_power_usage = 2000 + anchored = 1 + density = 0 + level = 1 + var/alarm = 0 + var/enabled = 1 + +/obj/machinery/shield_diffuser/Process() + if(alarm) + alarm-- + if(!alarm) + update_icon() + return + + if(!enabled) + return + for(var/direction in GLOB.cardinal) + var/turf/simulated/shielded_tile = get_step(get_turf(src), direction) + for(var/obj/effect/shield/S in shielded_tile) + S.diffuse(5) + +/obj/machinery/shield_diffuser/attackby(obj/item/O as obj, mob/user as mob) + if(default_deconstruction_screwdriver(user, O)) + return + if(default_deconstruction_crowbar(user, O)) + return + if(default_part_replacement(user, O)) + return + +/obj/machinery/shield_diffuser/update_icon() + if(alarm) + icon_state = "fdiffuser_emergency" + return + if((stat & (NOPOWER | BROKEN)) || !enabled) + icon_state = "fdiffuser_off" + else + icon_state = "fdiffuser_on" + +/obj/machinery/shield_diffuser/attack_hand() + if(alarm) + to_chat(usr, "You press an override button on \the [src], re-enabling it.") + alarm = 0 + update_icon() + return + enabled = !enabled + use_power = enabled + 1 + update_icon() + to_chat(usr, "You turn \the [src] [enabled ? "on" : "off"].") + +/obj/machinery/shield_diffuser/proc/meteor_alarm(var/duration) + if(!duration) + return + alarm = round(max(alarm, duration)) + update_icon() + +/obj/machinery/shield_diffuser/examine(var/mob/user) + . = ..() + to_chat(user, "It is [enabled ? "enabled" : "disabled"].") + if(alarm) + to_chat(user, "A red LED labeled \"Proximity Alarm\" is blinking on the control panel.") diff --git a/code/modules/shield_generators/handheld_diffuser.dm b/code/modules/shield_generators/handheld_diffuser.dm new file mode 100644 index 00000000..d86ae9f2 --- /dev/null +++ b/code/modules/shield_generators/handheld_diffuser.dm @@ -0,0 +1,50 @@ +/obj/item/weapon/shield_diffuser + name = "portable shield diffuser" + desc = "A small handheld device designed to disrupt energy barriers." + description_info = "This device disrupts shields on directly adjacent tiles (in a + shaped pattern), in a similar way the floor mounted variant does. It is, however, portable and run by an internal battery. Can be recharged with a regular recharger." + icon = 'icons/obj/machines/shielding.dmi' + icon_state = "hdiffuser_off" + origin_tech = list(TECH_MAGNET = 5, TECH_POWER = 5, TECH_ILLEGAL = 2) + var/obj/item/weapon/cell/device/cell + var/enabled = 0 + +/obj/item/weapon/shield_diffuser/update_icon() + if(enabled) + icon_state = "hdiffuser_on" + else + icon_state = "hdiffuser_off" + +/obj/item/weapon/shield_diffuser/New() + cell = new(src) + ..() + +/obj/item/weapon/shield_diffuser/Destroy() + QDEL_NULL(cell) + if(enabled) + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/item/weapon/shield_diffuser/Process() + if(!enabled) + return + + for(var/direction in GLOB.cardinal) + var/turf/simulated/shielded_tile = get_step(get_turf(src), direction) + for(var/obj/effect/shield/S in shielded_tile) + // 10kJ per pulse, but gap in the shield lasts for longer than regular diffusers. + if(istype(S) && !S.diffused_for && !S.disabled_for && cell.checked_use(10 KILOWATTS * CELLRATE)) + S.diffuse(20) + +/obj/item/weapon/shield_diffuser/attack_self() + enabled = !enabled + update_icon() + if(enabled) + START_PROCESSING(SSobj, src) + else + STOP_PROCESSING(SSobj, src) + to_chat(usr, "You turn \the [src] [enabled ? "on" : "off"].") + +/obj/item/weapon/shield_diffuser/examine() + . = ..() + to_chat(usr, "The charge meter reads [cell ? cell.percent() : 0]%") + to_chat(usr, "It is [enabled ? "enabled" : "disabled"].") \ No newline at end of file diff --git a/code/modules/shield_generators/modes.dm b/code/modules/shield_generators/modes.dm new file mode 100644 index 00000000..f9d0fe67 --- /dev/null +++ b/code/modules/shield_generators/modes.dm @@ -0,0 +1,83 @@ +// Definitions for shield modes. Names, descriptions and power usage multipliers can be changed here. +// Do not change the mode_flag variables without a good reason! + +/datum/shield_mode + var/mode_name // User-friendly name of this mode. + var/mode_desc // A short description of what the mode does. + var/mode_flag // Mode bitflag. See defines file. + var/multiplier // Energy usage multiplier. Each enabled mode multiplies upkeep power usage by this number. Values between 1-2 are good balance-wise. Hacked modes can go up to 3-4 + var/hacked_only = 0 // Set to 1 to allow usage of this shield mode only on hacked generators. + +/datum/shield_mode/hyperkinetic + mode_name = "Hyperkinetic Projectiles" + mode_desc = "This mode blocks various fast moving physical objects, such as bullets, blunt weapons, meteors and other." + mode_flag = MODEFLAG_HYPERKINETIC + multiplier = 1.2 + +/datum/shield_mode/photonic + mode_name = "Photonic Dispersion" + mode_desc = "This mode blocks majority of light. This includes beam weaponry and most of the visible light spectrum." + mode_flag = MODEFLAG_PHOTONIC + multiplier = 1.3 + +/datum/shield_mode/em + mode_name = "Electro-Magnetic Shielding" + mode_desc = "This mode blocks various high-power emissions like electrical storms." + mode_flag = MODEFLAG_EM + multiplier = 1.3 + +/datum/shield_mode/humanoids + mode_name = "Humanoid Lifeforms" + mode_desc = "This mode blocks various humanoid lifeforms. Does not affect fully synthetic humanoids." + mode_flag = MODEFLAG_HUMANOIDS + multiplier = 1.5 + +/datum/shield_mode/silicon + mode_name = "Silicon Lifeforms" + mode_desc = "This mode blocks various silicon based lifeforms." + mode_flag = MODEFLAG_ANORGANIC + multiplier = 1.5 + +/datum/shield_mode/mobs + mode_name = "Unknown Lifeforms" + mode_desc = "This mode blocks various other non-humanoid and non-silicon lifeforms. Typical uses include blocking carps." + mode_flag = MODEFLAG_NONHUMANS + multiplier = 1.5 + +/datum/shield_mode/atmosphere + mode_name = "Atmospheric Containment" + mode_desc = "This mode blocks air flow and acts as atmosphere containment." + mode_flag = MODEFLAG_ATMOSPHERIC + multiplier = 1.3 + +/datum/shield_mode/hull + mode_name = "Hull Shielding" + mode_desc = "This mode recalibrates the field to cover surface of the installation instead of projecting a bubble shaped field." + mode_flag = MODEFLAG_HULL + multiplier = 1 + +/datum/shield_mode/adaptive + mode_name = "Adaptive Field Harmonics" + mode_desc = "This mode modulates the shield harmonic frequencies, allowing the field to adapt to various damage types." + mode_flag = MODEFLAG_MODULATE + multiplier = 2 + +/datum/shield_mode/bypass + mode_name = "Diffuser Bypass" + mode_desc = "This mode disables the built-in safeties which allows the generator to counter effect of various shield diffusers. This tends to create a very large strain on the generator. Does not work with enabled safety protocols." + mode_flag = MODEFLAG_BYPASS + multiplier = 3 + hacked_only = 1 + +/datum/shield_mode/overcharge + mode_name = "Field Overcharge" + mode_desc = "This mode polarises the field, causing damage on contact. Does not work with enabled safety protocols." + mode_flag = MODEFLAG_OVERCHARGE + multiplier = 3 + hacked_only = 1 + +/datum/shield_mode/multiz + mode_name = "Multi-Dimensional Field Warp" + mode_desc = "Recalibrates the field projection array to increase the vertical height of the field, allowing it's usage on multi-deck stations or ships." + mode_flag = MODEFLAG_MULTIZ + multiplier = 1 \ No newline at end of file diff --git a/code/modules/shield_generators/shield.dm b/code/modules/shield_generators/shield.dm new file mode 100644 index 00000000..53b58f85 --- /dev/null +++ b/code/modules/shield_generators/shield.dm @@ -0,0 +1,314 @@ +/obj/effect/shield_impact + name = "shield impact" + icon = 'icons/obj/machines/shielding.dmi' + icon_state = "shield_impact" + anchored = 1 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + density = 0 + + +/obj/effect/shield_impact/New() + spawn(2 SECONDS) + qdel(src) + + +/obj/effect/shield + name = "energy shield" + desc = "An impenetrable field of energy, capable of blocking anything as long as it's active." + icon = 'icons/obj/machines/shielding.dmi' + icon_state = "shield_normal" + anchored = 1 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + density = 1 + invisibility = 0 + var/obj/machinery/power/shield_generator/gen = null + var/disabled_for = 0 + var/diffused_for = 0 + + +/obj/effect/shield/update_icon() + if(gen && gen.check_flag(MODEFLAG_PHOTONIC) && !disabled_for && !diffused_for) + set_opacity(1) + else + set_opacity(0) + + if(gen && gen.check_flag(MODEFLAG_OVERCHARGE)) + icon_state = "shield_overcharged" + else + icon_state = "shield_normal" + +// Prevents shuttles, singularities and pretty much everything else from moving the field segments away. +// The only thing that is allowed to move us is the Destroy() proc. +/obj/effect/shield/forceMove(var/newloc, var/qdeled = 0) + if(qdeled) + return ..() + return 0 + + +/obj/effect/shield/New() + ..() + update_nearby_tiles() + + +/obj/effect/shield/Destroy() + . = ..() + if(gen) + if(src in gen.field_segments) + gen.field_segments -= src + if(src in gen.damaged_segments) + gen.damaged_segments -= src + gen = null + update_nearby_tiles() + forceMove(null, 1) + + +// Temporarily collapses this shield segment. +/obj/effect/shield/proc/fail(var/duration) + if(duration <= 0) + return + + if(gen) + gen.damaged_segments |= src + disabled_for += duration + set_density(0) + set_invisibility(INVISIBILITY_MAXIMUM) + update_nearby_tiles() + update_icon() + update_explosion_resistance() + + +// Regenerates this shield segment. +/obj/effect/shield/proc/regenerate() + if(!gen) + return + + disabled_for = max(0, disabled_for - 1) + diffused_for = max(0, diffused_for - 1) + + if(!disabled_for && !diffused_for) + set_density(1) + set_invisibility(0) + update_nearby_tiles() + update_icon() + update_explosion_resistance() + gen.damaged_segments -= src + + +/obj/effect/shield/proc/diffuse(var/duration) + // The shield is trying to counter diffusers. Cause lasting stress on the shield. + if(gen.check_flag(MODEFLAG_BYPASS) && !diffused_for && !disabled_for) + take_damage(duration * rand(8, 12), SHIELD_DAMTYPE_EM) + return + + diffused_for = max(duration, 0) + gen.damaged_segments |= src + set_density(0) + set_invisibility(INVISIBILITY_MAXIMUM) + update_nearby_tiles() + update_icon() + update_explosion_resistance() + +/obj/effect/shield/attack_generic(var/source, var/damage, var/emote) + take_damage(damage, SHIELD_DAMTYPE_PHYSICAL) + if(gen.check_flag(MODEFLAG_OVERCHARGE) && istype(source, /mob/living/)) + overcharge_shock(source) + ..(source, damage, emote) + + +// Fails shield segments in specific range. Range of 1 affects the shielded turf only. +/obj/effect/shield/proc/fail_adjacent_segments(var/range, var/hitby = null) + if(hitby) + visible_message("\The [src] flashes a bit as \the [hitby] collides with it, eventually fading out in a rain of sparks!") + else + visible_message("\The [src] flashes a bit as it eventually fades out in a rain of sparks!") + fail(range * 2) + + for(var/obj/effect/shield/S in range(range, src)) + // Don't affect shields owned by other shield generators + if(S.gen != src.gen) + continue + // The closer we are to impact site, the longer it takes for shield to come back up. + S.fail(-(-range + get_dist(src, S)) * 2) + +/obj/effect/shield/proc/take_damage(var/damage, var/damtype, var/hitby) + if(!gen) + qdel(src) + return + + if(!damage) + return + + damage = round(damage) + + new/obj/effect/shield_impact(get_turf(src)) + + var/list/field_segments = gen.field_segments + switch(gen.take_damage(damage, damtype)) + if(SHIELD_ABSORBED) + return + if(SHIELD_BREACHED_MINOR) + fail_adjacent_segments(rand(1, 3), hitby) + return + if(SHIELD_BREACHED_MAJOR) + fail_adjacent_segments(rand(2, 5), hitby) + return + if(SHIELD_BREACHED_CRITICAL) + fail_adjacent_segments(rand(4, 8), hitby) + return + if(SHIELD_BREACHED_FAILURE) + fail_adjacent_segments(rand(8, 16), hitby) + for(var/obj/effect/shield/S in field_segments) + S.fail(1) + return + + +// As we have various shield modes, this handles whether specific things can pass or not. +/obj/effect/shield/CanPass(var/atom/movable/mover, var/turf/target, var/height=0, var/air_group=0) + // Somehow we don't have a generator. This shouldn't happen. Delete the shield. + if(!gen) + qdel(src) + return 1 + + if(disabled_for || diffused_for) + return 1 + + // Atmosphere containment. + if(air_group) + return !gen.check_flag(MODEFLAG_ATMOSPHERIC) + + if(mover) + return mover.can_pass_shield(gen) + return 1 + + +/obj/effect/shield/c_airblock(turf/other) + return gen.check_flag(MODEFLAG_ATMOSPHERIC) + + +// EMP. It may seem weak but keep in mind that multiple shield segments are likely to be affected. +/obj/effect/shield/emp_act(var/severity) + if(!disabled_for) + take_damage(rand(30,60) / severity, SHIELD_DAMTYPE_EM) + + +// Explosions +/obj/effect/shield/ex_act(var/severity) + if(!disabled_for) + take_damage(rand(10,15) / severity, SHIELD_DAMTYPE_PHYSICAL) + + +// Fire +/obj/effect/shield/fire_act() + if(!disabled_for) + take_damage(rand(5,10), SHIELD_DAMTYPE_HEAT) + + +// Projectiles +/obj/effect/shield/bullet_act(var/obj/item/projectile/proj) + if(proj.damage_type == BURN) + take_damage(proj.get_structure_damage(), SHIELD_DAMTYPE_HEAT) + else if (proj.damage_type == BRUTE) + take_damage(proj.get_structure_damage(), SHIELD_DAMTYPE_PHYSICAL) + else + take_damage(proj.get_structure_damage(), SHIELD_DAMTYPE_EM) + + +// Attacks with hand tools. Blocked by Hyperkinetic flag. +/obj/effect/shield/attackby(var/obj/item/weapon/I as obj, var/mob/user as mob) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + + if(gen.check_flag(MODEFLAG_HYPERKINETIC)) + user.visible_message("\The [user] hits \the [src] with \the [I]!") + if(I.damtype == BURN) + take_damage(I.force, SHIELD_DAMTYPE_HEAT) + else if (I.damtype == BRUTE) + take_damage(I.force, SHIELD_DAMTYPE_PHYSICAL) + else + take_damage(I.force, SHIELD_DAMTYPE_EM) + else + user.visible_message("\The [user] tries to attack \the [src] with \the [I], but it passes through!") + + +// Special treatment for meteors because they would otherwise penetrate right through the shield. +/obj/effect/shield/Bumped(var/atom/movable/mover) + if(!gen) + qdel(src) + return 0 + mover.shield_impact(src) + return ..() + + +/obj/effect/shield/proc/overcharge_shock(var/mob/living/M) + M.adjustFireLoss(rand(20, 40)) + M.Weaken(5) + to_chat(M, "As you come into contact with \the [src] a surge of energy paralyses you!") + take_damage(10, SHIELD_DAMTYPE_EM) + +// Called when a flag is toggled. Can be used to add on-toggle behavior, such as visual changes. +/obj/effect/shield/proc/flags_updated() + if(!gen) + qdel(src) + return + + // Update airflow + update_nearby_tiles() + update_icon() + update_explosion_resistance() + +/obj/effect/shield/proc/update_explosion_resistance() + if(gen && gen.check_flag(MODEFLAG_HYPERKINETIC)) + explosion_resistance = INFINITY + else + explosion_resistance = 0 + +/obj/effect/shield/get_explosion_resistance() + return explosion_resistance + +// Shield collision checks below + +/atom/movable/proc/can_pass_shield(var/obj/machinery/power/shield_generator/gen) + return 1 + + +// Other mobs +/mob/living/can_pass_shield(var/obj/machinery/power/shield_generator/gen) + return !gen.check_flag(MODEFLAG_NONHUMANS) + +// Human mobs +/mob/living/carbon/human/can_pass_shield(var/obj/machinery/power/shield_generator/gen) + if(isSynthetic()) + return !gen.check_flag(MODEFLAG_ANORGANIC) + return !gen.check_flag(MODEFLAG_HUMANOIDS) + +// Silicon mobs +/mob/living/silicon/can_pass_shield(var/obj/machinery/power/shield_generator/gen) + return !gen.check_flag(MODEFLAG_ANORGANIC) + + +// Generic objects. Also applies to bullets and meteors. +/obj/can_pass_shield(var/obj/machinery/power/shield_generator/gen) + return !gen.check_flag(MODEFLAG_HYPERKINETIC) + +// Beams +/obj/item/projectile/beam/can_pass_shield(var/obj/machinery/power/shield_generator/gen) + return !gen.check_flag(MODEFLAG_PHOTONIC) + + +// Shield on-impact logic here. This is called only if the object is actually blocked by the field (can_pass_shield applies first) +/atom/movable/proc/shield_impact(var/obj/effect/shield/S) + return + +/mob/living/shield_impact(var/obj/effect/shield/S) + if(!S.gen.check_flag(MODEFLAG_OVERCHARGE)) + return + S.overcharge_shock(src) + +/obj/effect/meteor/shield_impact(var/obj/effect/shield/S) + if(!S.gen.check_flag(MODEFLAG_HYPERKINETIC)) + return + S.take_damage(get_shield_damage(), SHIELD_DAMTYPE_PHYSICAL, src) + visible_message("\The [src] breaks into dust!") + make_debris() + qdel(src) diff --git a/code/modules/shield_generators/shield_generator.dm b/code/modules/shield_generators/shield_generator.dm new file mode 100644 index 00000000..4437112f --- /dev/null +++ b/code/modules/shield_generators/shield_generator.dm @@ -0,0 +1,465 @@ +/obj/machinery/power/shield_generator + name = "advanced shield generator" + desc = "A heavy-duty shield generator and capacitor, capable of generating energy shields at large distances." + icon = 'icons/obj/machines/shielding.dmi' + icon_state = "generator0" + density = 1 + var/datum/wires/shield_generator/wires + var/list/field_segments = list() // List of all shield segments owned by this generator. + var/list/damaged_segments = list() // List of shield segments that have failed and are currently regenerating. + var/shield_modes = 0 // Enabled shield mode flags + var/mitigation_em = 0 // Current EM mitigation + var/mitigation_physical = 0 // Current Physical mitigation + var/mitigation_heat = 0 // Current Burn mitigation + var/mitigation_max = 0 // Maximal mitigation reachable with this generator. Set by RefreshParts() + var/max_energy = 0 // Maximal stored energy. In joules. Depends on the type of used SMES coil when constructing this generator. + var/current_energy = 0 // Current stored energy. + var/field_radius = 1 // Current field radius. + var/running = SHIELD_OFF // Whether the generator is enabled or not. + var/input_cap = 1 MEGAWATTS // Currently set input limit. Set to 0 to disable limits altogether. The shield will try to input this value per tick at most + var/upkeep_power_usage = 0 // Upkeep power usage last tick. + var/upkeep_multiplier = 1 // Multiplier of upkeep values. + var/power_usage = 0 // Total power usage last tick. + var/overloaded = 0 // Whether the field has overloaded and shut down to regenerate. + var/hacked = 0 // Whether the generator has been hacked by cutting the safety wire. + var/offline_for = 0 // The generator will be inoperable for this duration in ticks. + var/input_cut = 0 // Whether the input wire is cut. + var/mode_changes_locked = 0 // Whether the control wire is cut, locking out changes. + var/ai_control_disabled = 0 // Whether the AI control is disabled. + var/list/mode_list = null // A list of shield_mode datums. + +/obj/machinery/power/shield_generator/update_icon() + if(running) + icon_state = "generator1" + else + icon_state = "generator0" + + +/obj/machinery/power/shield_generator/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/shield_generator(src) + component_parts += new /obj/item/weapon/stock_parts/capacitor(src) // Capacitor. Improves shield mitigation when better part is used. + component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) + component_parts += new /obj/item/weapon/smes_coil(src) // SMES coil. Improves maximal shield energy capacity. + component_parts += new /obj/item/weapon/stock_parts/console_screen(src) + RefreshParts() + connect_to_network() + wires = new(src) + + mode_list = list() + for(var/st in subtypesof(/datum/shield_mode/)) + var/datum/shield_mode/SM = new st() + mode_list.Add(SM) + + +/obj/machinery/power/shield_generator/Destroy() + shutdown_field() + field_segments = null + damaged_segments = null + mode_list = null + QDEL_NULL(wires) + . = ..() + + +/obj/machinery/power/shield_generator/RefreshParts() + max_energy = 0 + for(var/obj/item/weapon/smes_coil/S in component_parts) + max_energy += (S.ChargeCapacity / CELLRATE) + current_energy = between(0, current_energy, max_energy) + + mitigation_max = MAX_MITIGATION_BASE + for(var/obj/item/weapon/stock_parts/capacitor/C in component_parts) + mitigation_max += MAX_MITIGATION_RESEARCH * C.rating + mitigation_em = between(0, mitigation_em, mitigation_max) + mitigation_physical = between(0, mitigation_physical, mitigation_max) + mitigation_heat = between(0, mitigation_heat, mitigation_max) + + +// Shuts down the shield, removing all shield segments and unlocking generator settings. +/obj/machinery/power/shield_generator/proc/shutdown_field() + for(var/obj/effect/shield/S in field_segments) + qdel(S) + + running = SHIELD_OFF + current_energy = 0 + mitigation_em = 0 + mitigation_physical = 0 + mitigation_heat = 0 + update_icon() + + +// Generates the field objects. Deletes existing field, if applicable. +/obj/machinery/power/shield_generator/proc/regenerate_field() + if(field_segments.len) + for(var/obj/effect/shield/S in field_segments) + qdel(S) + + // The generator is not turned on, so don't generate any new tiles. + if(!running) + return + + var/list/shielded_turfs + + if(check_flag(MODEFLAG_HULL)) + shielded_turfs = fieldtype_hull() + else + shielded_turfs = fieldtype_square() + + for(var/turf/T in shielded_turfs) + var/obj/effect/shield/S = new(T) + S.gen = src + S.flags_updated() + field_segments |= S + update_icon() + + +// Recalculates and updates the upkeep multiplier +/obj/machinery/power/shield_generator/proc/update_upkeep_multiplier() + var/new_upkeep = 1.0 + for(var/datum/shield_mode/SM in mode_list) + if(check_flag(SM.mode_flag)) + new_upkeep *= SM.multiplier + + upkeep_multiplier = new_upkeep + + +/obj/machinery/power/shield_generator/Process() + upkeep_power_usage = 0 + power_usage = 0 + + if(offline_for) + offline_for = max(0, offline_for - 1) + // We're turned off. + if(!running) + return + // We are shutting down, therefore our stored energy disperses faster than usual. + else if(running == SHIELD_DISCHARGING) + current_energy -= SHIELD_SHUTDOWN_DISPERSION_RATE + + mitigation_em = between(0, mitigation_em - MITIGATION_LOSS_PASSIVE, mitigation_max) + mitigation_heat = between(0, mitigation_heat - MITIGATION_LOSS_PASSIVE, mitigation_max) + mitigation_physical = between(0, mitigation_physical - MITIGATION_LOSS_PASSIVE, mitigation_max) + + upkeep_power_usage = round((field_segments.len - damaged_segments.len) * ENERGY_UPKEEP_PER_TILE * upkeep_multiplier) + + if(powernet && (running == SHIELD_RUNNING) && !input_cut) + var/energy_buffer = 0 + energy_buffer = draw_power(min(upkeep_power_usage, input_cap)) + power_usage += round(energy_buffer) + + if(energy_buffer < upkeep_power_usage) + current_energy -= round(upkeep_power_usage - energy_buffer) // If we don't have enough energy from the grid, take it from the internal battery instead. + + // Now try to recharge our internal energy. + var/energy_to_demand + if(input_cap) + energy_to_demand = between(0, max_energy - current_energy, input_cap - upkeep_power_usage) + else + energy_to_demand = max(0, max_energy - current_energy) + energy_buffer = draw_power(energy_to_demand) + power_usage += energy_buffer + current_energy += round(energy_buffer) + else + current_energy -= round(upkeep_power_usage) // We are shutting down, or we lack external power connection. Use energy from internal source instead. + + if(current_energy <= 0) + energy_failure() + + if(!overloaded) + for(var/obj/effect/shield/S in damaged_segments) + S.regenerate() + else if (field_integrity() > 25) + overloaded = 0 + + +/obj/machinery/power/shield_generator/attackby(obj/item/O as obj, mob/user as mob) + if(panel_open && isMultitool(O) || isWirecutter(O)) + attack_hand(user) + return + + if(default_deconstruction_screwdriver(user, O)) + return + + // Prevents dismantle-rebuild tactics to reset the emergency shutdown timer. + if(running) + to_chat(user, "Turn off \the [src] first!") + return + if(offline_for) + to_chat(user, "Wait until \the [src] cools down from emergency shutdown first!") + return + + if(default_deconstruction_crowbar(user, O)) + return + if(default_part_replacement(user, O)) + return + + +/obj/machinery/power/shield_generator/proc/energy_failure() + if(running == SHIELD_DISCHARGING) + shutdown_field() + else + current_energy = 0 + overloaded = 1 + for(var/obj/effect/shield/S in field_segments) + S.fail(1) + + +/obj/machinery/power/shield_generator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + + data["running"] = running + data["modes"] = get_flag_descriptions() + data["overloaded"] = overloaded + data["mitigation_max"] = mitigation_max + data["mitigation_physical"] = round(mitigation_physical, 0.1) + data["mitigation_em"] = round(mitigation_em, 0.1) + data["mitigation_heat"] = round(mitigation_heat, 0.1) + data["field_integrity"] = field_integrity() + data["max_energy"] = round(max_energy / 1000000, 0.1) + data["current_energy"] = round(current_energy / 1000000, 0.1) + data["total_segments"] = field_segments ? field_segments.len : 0 + data["functional_segments"] = damaged_segments ? data["total_segments"] - damaged_segments.len : data["total_segments"] + data["field_radius"] = field_radius + data["input_cap_kw"] = round(input_cap / 1000) + data["upkeep_power_usage"] = round(upkeep_power_usage / 1000, 0.1) + data["power_usage"] = round(power_usage / 1000) + data["hacked"] = hacked + data["offline_for"] = offline_for * 2 + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "shieldgen.tmpl", src.name, 500, 800) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + + +/obj/machinery/power/shield_generator/attack_hand(var/mob/user) + ui_interact(user) + if(panel_open) + wires.Interact(user) + + +/obj/machinery/power/shield_generator/CanUseTopic(var/mob/user) + if(issilicon(user) && !Adjacent(user) && ai_control_disabled) + return STATUS_UPDATE + return ..() + +/obj/machinery/power/shield_generator/OnTopic(user, href_list) + if(href_list["begin_shutdown"]) + if(running != SHIELD_RUNNING) + return + running = SHIELD_DISCHARGING + return TOPIC_REFRESH + + if(href_list["start_generator"]) + if(offline_for) + return + running = SHIELD_RUNNING + regenerate_field() + return TOPIC_REFRESH + + // Instantly drops the shield, but causes a cooldown before it may be started again. Also carries a risk of EMP at high charge. + if(href_list["emergency_shutdown"]) + if(!running) + return TOPIC_HANDLED + + var/choice = input(user, "Are you sure that you want to initiate an emergency shield shutdown? This will instantly drop the shield, and may result in unstable release of stored electromagnetic energy. Proceed at your own risk.") in list("Yes", "No") + if((choice != "Yes") || !running) + return TOPIC_HANDLED + + var/temp_integrity = field_integrity() + // If the shield would take 5 minutes to disperse and shut down using regular methods, it will take x2 (10 minutes) of this time to cool down after emergency shutdown + offline_for = round(current_energy / (SHIELD_SHUTDOWN_DISPERSION_RATE / 2)) + shutdown_field() + if(prob(temp_integrity - 50) * 1.75) + spawn() + empulse(src, 7, 14) + return TOPIC_REFRESH + + if(mode_changes_locked) + return TOPIC_REFRESH + + if(href_list["set_range"]) + var/new_range = input(user, "Enter new field range (1-[world.maxx]). Leave blank to cancel.", "Field Radius Control", field_radius) as num + if(!new_range) + return TOPIC_HANDLED + field_radius = between(1, new_range, world.maxx) + regenerate_field() + return TOPIC_REFRESH + + if(href_list["set_input_cap"]) + var/new_cap = round(input(user, "Enter new input cap (in kW). Enter 0 or nothing to disable input cap.", "Generator Power Control", round(input_cap / 1000)) as num) + if(!new_cap) + input_cap = 0 + return + input_cap = max(0, new_cap) * 1000 + return TOPIC_REFRESH + + if(href_list["toggle_mode"]) + // Toggling hacked-only modes requires the hacked var to be set to 1 + if((text2num(href_list["toggle_mode"]) & (MODEFLAG_BYPASS | MODEFLAG_OVERCHARGE)) && !hacked) + return TOPIC_HANDLED + + toggle_flag(text2num(href_list["toggle_mode"])) + return TOPIC_REFRESH + + +/obj/machinery/power/shield_generator/proc/field_integrity() + if(max_energy) + return (current_energy / max_energy) * 100 + return 0 + + +// Takes specific amount of damage +/obj/machinery/power/shield_generator/proc/take_damage(var/damage, var/shield_damtype) + var/energy_to_use = damage * ENERGY_PER_HP + if(check_flag(MODEFLAG_MODULATE)) + mitigation_em -= MITIGATION_HIT_LOSS + mitigation_heat -= MITIGATION_HIT_LOSS + mitigation_physical -= MITIGATION_HIT_LOSS + + switch(shield_damtype) + if(SHIELD_DAMTYPE_PHYSICAL) + mitigation_physical += MITIGATION_HIT_LOSS + MITIGATION_HIT_GAIN + energy_to_use *= 1 - (mitigation_physical / 100) + if(SHIELD_DAMTYPE_EM) + mitigation_em += MITIGATION_HIT_LOSS + MITIGATION_HIT_GAIN + energy_to_use *= 1 - (mitigation_em / 100) + if(SHIELD_DAMTYPE_HEAT) + mitigation_heat += MITIGATION_HIT_LOSS + MITIGATION_HIT_GAIN + energy_to_use *= 1 - (mitigation_heat / 100) + + mitigation_em = between(0, mitigation_em, mitigation_max) + mitigation_heat = between(0, mitigation_heat, mitigation_max) + mitigation_physical = between(0, mitigation_physical, mitigation_max) + + current_energy -= energy_to_use + + // Overload the shield, which will shut it down until we recharge above 25% again + if(current_energy < 0) + energy_failure() + return SHIELD_BREACHED_FAILURE + + if(prob(10 - field_integrity())) + return SHIELD_BREACHED_CRITICAL + if(prob(20 - field_integrity())) + return SHIELD_BREACHED_MAJOR + if(prob(35 - field_integrity())) + return SHIELD_BREACHED_MINOR + return SHIELD_ABSORBED + + +// Checks whether specific flags are enabled +/obj/machinery/power/shield_generator/proc/check_flag(var/flag) + return (shield_modes & flag) + + +/obj/machinery/power/shield_generator/proc/toggle_flag(var/flag) + shield_modes ^= flag + update_upkeep_multiplier() + for(var/obj/effect/shield/S in field_segments) + S.flags_updated() + + if((flag & (MODEFLAG_HULL|MODEFLAG_MULTIZ)) && running) + regenerate_field() + + if(flag & MODEFLAG_MODULATE) + mitigation_em = 0 + mitigation_physical = 0 + mitigation_heat = 0 + + +/obj/machinery/power/shield_generator/proc/get_flag_descriptions() + var/list/all_flags = list() + for(var/datum/shield_mode/SM in mode_list) + if(SM.hacked_only && !hacked) + continue + all_flags.Add(list(list( + "name" = SM.mode_name, + "desc" = SM.mode_desc, + "flag" = SM.mode_flag, + "status" = check_flag(SM.mode_flag), + "hacked" = SM.hacked_only, + "multiplier" = SM.multiplier + ))) + return all_flags + + +// These two procs determine tiles that should be shielded given the field range. They are quite CPU intensive and may trigger BYOND infinite loop checks, therefore they are set +// as background procs to prevent locking up the server. They are only called when the field is generated, or when hull mode is toggled on/off. +/obj/machinery/power/shield_generator/proc/fieldtype_square() + set background = 1 + var/list/out = list() + var/list/base_turfs = get_base_turfs() + + for(var/turf/gen_turf in base_turfs) + var/turf/T + for (var/x_offset = -field_radius; x_offset <= field_radius; x_offset++) + T = locate(gen_turf.x + x_offset, gen_turf.y - field_radius, gen_turf.z) + if(T) + out += T + T = locate(gen_turf.x + x_offset, gen_turf.y + field_radius, gen_turf.z) + if(T) + out += T + + for (var/y_offset = -field_radius+1; y_offset < field_radius; y_offset++) + T = locate(gen_turf.x - field_radius, gen_turf.y + y_offset, gen_turf.z) + if(T) + out += T + T = locate(gen_turf.x + field_radius, gen_turf.y + y_offset, gen_turf.z) + if(T) + out += T + return out + + +/obj/machinery/power/shield_generator/proc/fieldtype_hull() + set background = 1 + . = list() + var/list/base_turfs = get_base_turfs() + + + + + for(var/turf/gen_turf in base_turfs) + var/area/TA = null // Variable for area checking. Defining it here so memory does not have to be allocated repeatedly. + for(var/turf/T in trange(field_radius, gen_turf)) + // Don't expand to space or on shuttle areas. + if(istype(T, /turf/space) || istype(T, /turf/simulated/open)) + continue + + // Find adjacent space/shuttle tiles and cover them. Shuttles won't be blocked if shield diffuser is mapped in and turned on. + for(var/turf/TN in orange(1, T)) + TA = get_area(TN) + if ((istype(TN, /turf/space) || (istype(TN, /turf/simulated/open) && (istype(TA, /area/space) || TA.area_flags & AREA_FLAG_EXTERNAL)))) + . |= TN + continue + +// Returns a list of turfs from which a field will propagate. If multi-Z mode is enabled, this will return a "column" of turfs above and below the generator. +/obj/machinery/power/shield_generator/proc/get_base_turfs() + var/list/turfs = list() + var/turf/T = get_turf(src) + + if(!istype(T)) + return + + turfs.Add(T) + + // Multi-Z mode is disabled + if(!check_flag(MODEFLAG_MULTIZ)) + return turfs + + while(HasAbove(T.z)) + T = GetAbove(T) + if(istype(T)) + turfs.Add(T) + + T = get_turf(src) + + while(HasBelow(T.z)) + T = GetBelow(T) + if(istype(T)) + turfs.Add(T) + + return turfs \ No newline at end of file diff --git a/code/modules/shieldgen/emergency_shield.dm b/code/modules/shieldgen/emergency_shield.dm new file mode 100644 index 00000000..e6bbc01b --- /dev/null +++ b/code/modules/shieldgen/emergency_shield.dm @@ -0,0 +1,327 @@ +/obj/machinery/shield + name = "Emergency energy shield" + desc = "An energy shield used to contain hull breaches." + icon = 'icons/effects/effects.dmi' + icon_state = "shield-old" + density = 1 + opacity = 0 + anchored = 1 + unacidable = 1 + var/const/max_health = 200 + var/health = max_health //The shield can only take so much beating (prevents perma-prisons) + var/shield_generate_power = 7500 //how much power we use when regenerating + var/shield_idle_power = 1500 //how much power we use when just being sustained. + +/obj/machinery/shield/malfai + name = "emergency forcefield" + desc = "A weak forcefield which seems to be projected by the emergency atmosphere containment field." + health = max_health/2 // Half health, it's not suposed to resist much. + +/obj/machinery/shield/malfai/Process() + health -= 0.5 // Slowly lose integrity over time + check_failure() + +/obj/machinery/shield/proc/check_failure() + if (src.health <= 0) + visible_message("\The [src] dissipates!") + qdel(src) + return + +/obj/machinery/shield/New() + src.set_dir(pick(1,2,3,4)) + ..() + update_nearby_tiles(need_rebuild=1) + +/obj/machinery/shield/Destroy() + set_opacity(0) + set_density(0) + update_nearby_tiles() + ..() + +/obj/machinery/shield/CanPass(atom/movable/mover, turf/target, height, air_group) + if(!height || air_group) return 0 + else return ..() + +/obj/machinery/shield/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(!istype(W)) return + + //Calculate damage + var/aforce = W.force + if(W.damtype == BRUTE || W.damtype == BURN) + src.health -= aforce + + //Play a fitting sound + playsound(src.loc, 'sound/effects/EMPulse.ogg', 75, 1) + + check_failure() + set_opacity(1) + spawn(20) if(!QDELETED(src)) set_opacity(0) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + + ..() + +/obj/machinery/shield/bullet_act(var/obj/item/projectile/Proj) + health -= Proj.get_structure_damage() + ..() + check_failure() + set_opacity(1) + spawn(20) if(!QDELETED(src)) set_opacity(0) + +/obj/machinery/shield/ex_act(severity) + switch(severity) + if(1.0) + if (prob(75)) + qdel(src) + if(2.0) + if (prob(50)) + qdel(src) + if(3.0) + if (prob(25)) + qdel(src) + return + +/obj/machinery/shield/emp_act(severity) + switch(severity) + if(1) + qdel(src) + if(2) + if(prob(50)) + qdel(src) + + +/obj/machinery/shield/hitby(AM as mob|obj) + //Let everyone know we've been hit! + visible_message("\[src] was hit by [AM].") + + //Super realistic, resource-intensive, real-time damage calculations. + var/tforce = 0 + if(ismob(AM)) + tforce = 40 + else + tforce = AM:throwforce + + src.health -= tforce + + //This seemed to be the best sound for hitting a force field. + playsound(src.loc, 'sound/effects/EMPulse.ogg', 100, 1) + + check_failure() + + //The shield becomes dense to absorb the blow.. purely asthetic. + set_opacity(1) + spawn(20) if(!QDELETED(src)) set_opacity(0) + + ..() + return +/obj/machinery/shieldgen + name = "Emergency shield projector" + desc = "Used to seal minor hull breaches." + icon = 'icons/obj/objects.dmi' + icon_state = "shieldoff" + density = 1 + opacity = 0 + anchored = 0 + req_access = list(access_engine) + var/const/max_health = 100 + var/health = max_health + var/active = 0 + var/malfunction = 0 //Malfunction causes parts of the shield to slowly dissapate + var/list/deployed_shields = list() + var/list/regenerating = list() + var/is_open = 0 //Whether or not the wires are exposed + var/locked = 0 + var/check_delay = 60 //periodically recheck if we need to rebuild a shield + use_power = 0 + idle_power_usage = 0 + +/obj/machinery/shieldgen/Destroy() + collapse_shields() + ..() + +/obj/machinery/shieldgen/proc/shields_up() + if(active) return 0 //If it's already turned on, how did this get called? + + src.active = 1 + update_icon() + + create_shields() + + idle_power_usage = 0 + for(var/obj/machinery/shield/shield_tile in deployed_shields) + idle_power_usage += shield_tile.shield_idle_power + update_use_power(1) + +/obj/machinery/shieldgen/proc/shields_down() + if(!active) return 0 //If it's already off, how did this get called? + + src.active = 0 + update_icon() + + collapse_shields() + + update_use_power(0) + +/obj/machinery/shieldgen/proc/create_shields() + for(var/turf/target_tile in range(2, src)) + if (istype(target_tile,/turf/space) && !(locate(/obj/machinery/shield) in target_tile)) + if (malfunction && prob(33) || !malfunction) + var/obj/machinery/shield/S = new/obj/machinery/shield(target_tile) + deployed_shields += S + use_power(S.shield_generate_power) + +/obj/machinery/shieldgen/proc/collapse_shields() + for(var/obj/machinery/shield/shield_tile in deployed_shields) + qdel(shield_tile) + +/obj/machinery/shieldgen/power_change() + . = ..() + if(!. || !active) return + if (stat & NOPOWER) + collapse_shields() + else + create_shields() + +/obj/machinery/shieldgen/Process() + if (!active || (stat & NOPOWER)) + return + + if(malfunction) + if(deployed_shields.len && prob(5)) + qdel(pick(deployed_shields)) + else + if (check_delay <= 0) + create_shields() + + var/new_power_usage = 0 + for(var/obj/machinery/shield/shield_tile in deployed_shields) + new_power_usage += shield_tile.shield_idle_power + + if (new_power_usage != idle_power_usage) + idle_power_usage = new_power_usage + use_power(0) + + check_delay = 60 + else + check_delay-- + +/obj/machinery/shieldgen/proc/checkhp() + if(health <= 30) + src.malfunction = 1 + if(health <= 0) + spawn(0) + explosion(get_turf(src.loc), 0, 0, 1, 0, 0, 0) + qdel(src) + update_icon() + return + +/obj/machinery/shieldgen/ex_act(severity) + switch(severity) + if(1.0) + src.health -= 75 + src.checkhp() + if(2.0) + src.health -= 30 + if (prob(15)) + src.malfunction = 1 + src.checkhp() + if(3.0) + src.health -= 10 + src.checkhp() + return + +/obj/machinery/shieldgen/emp_act(severity) + switch(severity) + if(1) + src.health /= 2 //cut health in half + malfunction = 1 + locked = pick(0,1) + if(2) + if(prob(50)) + src.health *= 0.3 //chop off a third of the health + malfunction = 1 + checkhp() + +/obj/machinery/shieldgen/attack_hand(mob/user as mob) + if(locked) + to_chat(user, "The machine is locked, you are unable to use it.") + return + if(is_open) + to_chat(user, "The panel must be closed before operating this machine.") + return + + if (src.active) + user.visible_message("\icon[src] [user] deactivated the shield generator.", \ + "\icon[src] You deactivate the shield generator.", \ + "You hear heavy droning fade out.") + src.shields_down() + else + if(anchored) + user.visible_message("\icon[src] [user] activated the shield generator.", \ + "\icon[src] You activate the shield generator.", \ + "You hear heavy droning.") + src.shields_up() + else + to_chat(user, "The device must first be secured to the floor.") + return + +/obj/machinery/shieldgen/emag_act(var/remaining_charges, var/mob/user) + if(!malfunction) + malfunction = 1 + update_icon() + return 1 + +/obj/machinery/shieldgen/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isScrewdriver(W)) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) + if(is_open) + to_chat(user, "You close the panel.") + is_open = 0 + else + to_chat(user, "You open the panel and expose the wiring.") + is_open = 1 + + else if(isCoil(W) && malfunction && is_open) + var/obj/item/stack/cable_coil/coil = W + to_chat(user, "You begin to replace the wires.") + //if(do_after(user, min(60, round( ((maxhealth/health)*10)+(malfunction*10) ))) //Take longer to repair heavier damage + if(do_after(user, 30,src)) + if (coil.use(1)) + health = max_health + malfunction = 0 + to_chat(user, "You repair the [src]!") + update_icon() + + else if(istype(W, /obj/item/weapon/wrench)) + if(locked) + to_chat(user, "The bolts are covered, unlocking this would retract the covers.") + return + if(anchored) + playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + to_chat(user, "'You unsecure the [src] from the floor!") + if(active) + to_chat(user, "The [src] shuts off!") + src.shields_down() + anchored = 0 + else + if(istype(get_turf(src), /turf/space)) return //No wrenching these in space! + playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + to_chat(user, "You secure the [src] to the floor!") + anchored = 1 + + + else if(istype(W, /obj/item/weapon/card/id) || istype(W, /obj/item/device/pda)) + if(src.allowed(user)) + src.locked = !src.locked + to_chat(user, "The controls are now [src.locked ? "locked." : "unlocked."]") + else + to_chat(user, "Access denied.") + else + ..() + + +/obj/machinery/shieldgen/update_icon() + if(active && !(stat & NOPOWER)) + src.icon_state = malfunction ? "shieldonbr":"shieldon" + else + src.icon_state = malfunction ? "shieldoffbr":"shieldoff" + return diff --git a/code/modules/shieldgen/energy_field.dm b/code/modules/shieldgen/energy_field.dm new file mode 100644 index 00000000..1b9e6662 --- /dev/null +++ b/code/modules/shieldgen/energy_field.dm @@ -0,0 +1,70 @@ + +//---------- actual energy field + +/obj/effect/energy_field + name = "energy field" + desc = "Impenetrable field of energy, capable of blocking anything as long as it's active." + icon = 'icons/obj/machines/shielding.dmi' + icon_state = "shield_normal" + anchored = 1 + plane = EFFECTS_BELOW_LIGHTING_PLANE + layer = PROJECTILE_LAYER + density = 0 + invisibility = 101 + var/strength = 0 + var/ticks_recovering = 10 + +/obj/effect/energy_field/New() + ..() + update_nearby_tiles() + +/obj/effect/energy_field/Destroy() + set_density(0) + update_nearby_tiles() + . = ..() + +/obj/effect/energy_field/ex_act(var/severity) + Stress(0.5 + severity) + +/obj/effect/energy_field/bullet_act(var/obj/item/projectile/Proj) + Stress(Proj.get_structure_damage() / 10) + +/obj/effect/energy_field/proc/Stress(var/severity) + strength -= severity + + //if we take too much damage, drop out - the generator will bring us back up if we have enough power + ticks_recovering = min(ticks_recovering + 2, 10) + if(strength < 1) + set_invisibility(101) + set_density(0) + ticks_recovering = 10 + strength = 0 + else if(strength >= 1) + set_invisibility(0) + set_density(1) + +/obj/effect/energy_field/proc/Strengthen(var/severity) + strength += severity + if (strength < 0) + strength = 0 + + //if we take too much damage, drop out - the generator will bring us back up if we have enough power + var/old_density = density + if(strength >= 1) + set_invisibility(0) + set_density(1) + else if(strength < 1) + set_invisibility(101) + set_density(0) + + if (density != old_density) + update_nearby_tiles() + +/obj/effect/energy_field/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) + //Purpose: Determines if the object (or airflow) can pass this atom. + //Called by: Movement, airflow. + //Inputs: The moving atom (optional), target turf, "height" and air group + //Outputs: Boolean if can pass. + + //return (!density || !height || air_group) + return !density diff --git a/code/modules/shieldgen/shieldwallgen.dm b/code/modules/shieldgen/shieldwallgen.dm new file mode 100644 index 00000000..bd7c63dd --- /dev/null +++ b/code/modules/shieldgen/shieldwallgen.dm @@ -0,0 +1,357 @@ +////FIELD GEN START //shameless copypasta from fieldgen, powersink, and grille +/obj/machinery/shieldwallgen + name = "Shield Generator" + desc = "A shield generator." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "Shield_Gen" + anchored = 0 + density = 1 + req_one_access = list(access_engine_equip,access_research) + var/active = 0 + var/power = 0 + var/locked = 1 + var/max_range = 8 + var/storedpower = 0 + obj_flags = OBJ_FLAG_CONDUCTIBLE + //There have to be at least two posts, so these are effectively doubled + var/power_draw = 30 KILOWATTS //30 kW. How much power is drawn from powernet. Increase this to allow the generator to sustain longer shields, at the cost of more power draw. + var/max_stored_power = 50 KILOWATTS //50 kW + use_power = 0 //Draws directly from power net. Does not use APC power. + active_power_usage = 1200 + +/obj/machinery/shieldwallgen/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) + var/list/data = list() + data["draw"] = round(power_draw) + data["power"] = round(storedpower) + data["maxpower"] = round(max_stored_power) + data["current_draw"] = ((between(500, max_stored_power - storedpower, power_draw)) + power ? active_power_usage : 0) + data["online"] = active == 2 ? 1 : 0 + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "shield.tmpl", "Shielding", 800, 500, state = state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/shieldwallgen/update_icon() +// if(stat & BROKEN) -TODO: Broken icon + if(!active) + icon_state = "Shield_Gen" + else + icon_state = "Shield_Gen +a" + +/obj/machinery/shieldwallgen/OnTopic(var/mob/user, href_list) + if(href_list["toggle"]) + if(src.active >= 1) + src.active = 0 + update_icon() + + user.visible_message("\The [user] turned the shield generator off.", \ + "You turn off the shield generator.", \ + "You hear heavy droning fade out.") + for(var/dir in list(1,2,4,8)) src.cleanup(dir) + else + src.active = 1 + update_icon() + user.visible_message("\The [user] turned the shield generator on.", \ + "You turn on the shield generator.", \ + "You hear heavy droning.") + return TOPIC_REFRESH + +/obj/machinery/shieldwallgen/ex_act(var/severity) + switch(severity) + if(1) + active = 0 + storedpower = 0 + if(2) + storedpower -= rand(min(storedpower,max_stored_power/2), max_stored_power) + if(3) + storedpower -= rand(0, max_stored_power) + +/obj/machinery/shieldwallgen/emp_act(var/severity) + switch(severity) + if(1) + storedpower = 0 + if(2) + storedpower -= rand(storedpower/2, storedpower) + if(3) + storedpower -= rand(storedpower/4, storedpower/2) + ..() + +/obj/machinery/shieldwallgen/attack_hand(mob/user as mob) + if(anchored != 1) + to_chat(user, "The shield generator needs to be firmly secured to the floor first.") + return 1 + if(src.locked && !istype(user, /mob/living/silicon)) + to_chat(user, "The controls are locked!") + return 1 + if(power != 1) + to_chat(user, "The shield generator needs to be powered by wire underneath.") + return 1 + + src.ui_interact(user) + src.add_fingerprint(user) + +/obj/machinery/shieldwallgen/proc/power() + if(!anchored) + power = 0 + return 0 + var/turf/T = src.loc + + var/obj/structure/cable/C = T.get_cable_node() + var/datum/powernet/PN + if(C) PN = C.powernet // find the powernet of the connected cable + + if(PN) + var/shieldload = between(500, max_stored_power - storedpower, power_draw) //what we try to draw + shieldload = PN.draw_power(shieldload) //what we actually get + storedpower += shieldload + + //If we're still in the red, then there must not be enough available power to cover our load. + if(storedpower <= 0) + power = 0 + return 0 + + power = 1 // IVE GOT THE POWER! + return 1 + +/obj/machinery/shieldwallgen/Process() + power = 0 + if(!(stat & BROKEN)) + power() + if(power) + storedpower -= active_power_usage //the generator post itself uses some power + + if(storedpower >= max_stored_power) + storedpower = max_stored_power + if(storedpower <= 0) + storedpower = 0 + + if(src.active == 1) + if(!src.anchored == 1) + src.active = 0 + return + spawn(1) + setup_field(1) + spawn(2) + setup_field(2) + spawn(3) + setup_field(4) + spawn(4) + setup_field(8) + src.active = 2 + if(src.active >= 1) + if(src.power == 0) + src.visible_message("The [src.name] shuts down due to lack of power!", \ + "You hear heavy droning fade out") + src.active = 0 + update_icon() + for(var/dir in list(1,2,4,8)) src.cleanup(dir) + +/obj/machinery/shieldwallgen/proc/setup_field(var/NSEW = 0) + var/turf/T = get_turf(src) + if(!T) return + var/turf/T2 = T + var/obj/machinery/shieldwallgen/G + var/steps = 0 + var/oNSEW = 0 + + if(!NSEW)//Make sure its ran right + return + + if(NSEW == 1) + oNSEW = 2 + else if(NSEW == 2) + oNSEW = 1 + else if(NSEW == 4) + oNSEW = 8 + else if(NSEW == 8) + oNSEW = 4 + + for(var/dist = 0, dist <= (max_range+1), dist += 1) // checks out to 8 tiles away for another generator + T = get_step(T2, NSEW) + T2 = T + steps += 1 + if(locate(/obj/machinery/shieldwallgen) in T) + G = (locate(/obj/machinery/shieldwallgen) in T) + steps -= 1 + if(!G.active) + return + G.cleanup(oNSEW) + break + + if(isnull(G)) + return + + T2 = src.loc + + for(var/dist = 0, dist < steps, dist += 1) // creates each field tile + var/field_dir = get_dir(T2,get_step(T2, NSEW)) + T = get_step(T2, NSEW) + T2 = T + var/obj/machinery/shieldwall/CF = new/obj/machinery/shieldwall/(src, G) //(ref to this gen, ref to connected gen) + CF.loc = T + CF.set_dir(field_dir) + + +/obj/machinery/shieldwallgen/attackby(obj/item/W, mob/user) + if(isWrench(W)) + if(active) + to_chat(user, "Turn off the field generator first.") + return + + else if(anchored == 0) + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + to_chat(user, "You secure the external reinforcing bolts to the floor.") + src.anchored = 1 + return + + else if(anchored == 1) + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + to_chat(user, "You undo the external reinforcing bolts.") + src.anchored = 0 + return + + if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) + if (src.allowed(user)) + src.locked = !src.locked + to_chat(user, "Controls are now [src.locked ? "locked." : "unlocked."]") + else + to_chat(user, "Access denied.") + return + + else + src.add_fingerprint(user) + ..() + + +/obj/machinery/shieldwallgen/proc/cleanup(var/NSEW) + var/obj/machinery/shieldwall/F + var/obj/machinery/shieldwallgen/G + var/turf/T = src.loc + var/turf/T2 = src.loc + + for(var/dist = 0, dist <= (max_range+1), dist += 1) // checks out to 8 tiles away for fields + T = get_step(T2, NSEW) + T2 = T + if(locate(/obj/machinery/shieldwall) in T) + F = (locate(/obj/machinery/shieldwall) in T) + qdel(F) + + if(locate(/obj/machinery/shieldwallgen) in T) + G = (locate(/obj/machinery/shieldwallgen) in T) + if(!G.active) + break + +/obj/machinery/shieldwallgen/Destroy() + src.cleanup(NORTH) + src.cleanup(SOUTH) + src.cleanup(EAST) + src.cleanup(WEST) + . = ..() + + +//////////////Containment Field START +/obj/machinery/shieldwall + name = "Shield" + desc = "An energy shield." + icon = 'icons/effects/effects.dmi' + icon_state = "shieldwall" + anchored = 1 + density = 1 + unacidable = 1 + light_range = 3 + var/needs_power = 0 + var/active = 1 + var/delay = 5 + var/last_active + var/mob/U + var/obj/machinery/shieldwallgen/gen_primary + var/obj/machinery/shieldwallgen/gen_secondary + var/power_usage = 800 //how much power it takes to sustain the shield + var/generate_power_usage = 5000 //how much power it takes to start up the shield + +/obj/machinery/shieldwall/New(var/obj/machinery/shieldwallgen/A, var/obj/machinery/shieldwallgen/B) + ..() + update_nearby_tiles() + src.gen_primary = A + src.gen_secondary = B + if(A && B && A.active && B.active) + needs_power = 1 + if(prob(50)) + A.storedpower -= generate_power_usage + else + B.storedpower -= generate_power_usage + else + qdel(src) //need at least two generator posts + +/obj/machinery/shieldwall/Destroy() + update_nearby_tiles() + ..() + +/obj/machinery/shieldwall/attack_hand(mob/user as mob) + return + +/obj/machinery/shieldwall/attackby(var/obj/item/I, var/mob/user) + var/obj/machinery/shieldwallgen/G = prob(50) ? gen_primary : gen_secondary + G.storedpower -= I.force*2500 + user.visible_message("\The [user] hits \the [src] with \the [I]!") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + playsound(loc, 'sound/weapons/smash.ogg', 75, 1) + +/obj/machinery/shieldwall/Process() + if(needs_power) + if(isnull(gen_primary)||isnull(gen_secondary)) + qdel(src) + return + + if(!(gen_primary.active)||!(gen_secondary.active)) + qdel(src) + return + + var/obj/machinery/shieldwallgen/G = prob(50) ? gen_primary : gen_secondary + G.storedpower -= power_usage + + +/obj/machinery/shieldwall/bullet_act(var/obj/item/projectile/Proj) + if(needs_power) + var/obj/machinery/shieldwallgen/G = prob(50) ? gen_primary : gen_secondary + G.storedpower -= 400 * Proj.get_structure_damage() + ..() + return + + +/obj/machinery/shieldwall/ex_act(severity) + if(needs_power) + var/obj/machinery/shieldwallgen/G = prob(50) ? gen_primary : gen_secondary + switch(severity) + if(1.0) //big boom + G.storedpower -= rand(30000, min(G.storedpower, 60000)) + + if(2.0) //medium boom + G.storedpower -= rand(15000, min(G.storedpower, 30000)) + + if(3.0) //lil boom + G.storedpower -= rand(5000, min(G.storedpower, 15000)) + return + + +/obj/machinery/shieldwall/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group || (height==0)) return 1 + + if(istype(mover) && mover.checkpass(PASS_FLAG_GLASS)) + return prob(20) + else + if (istype(mover, /obj/item/projectile)) + return prob(10) + else + return !src.density + +/obj/machinery/shieldwallgen/online + anchored = 1 + active = 1 + +/obj/machinery/shieldwallgen/online/Initialize() + storedpower = max_stored_power + . = ..() \ No newline at end of file diff --git a/code/modules/shuttles/_defines.dm b/code/modules/shuttles/_defines.dm new file mode 100644 index 00000000..6eff6637 --- /dev/null +++ b/code/modules/shuttles/_defines.dm @@ -0,0 +1,4 @@ +#define SHUTTLE_FLAGS_NONE 0 +#define SHUTTLE_FLAGS_PROCESS 1 +#define SHUTTLE_FLAGS_SUPPLY 2 +#define SHUTTLE_FLAGS_ALL (~SHUTTLE_FLAGS_NONE) diff --git a/code/modules/shuttles/antagonist.dm b/code/modules/shuttles/antagonist.dm new file mode 100644 index 00000000..939c17e3 --- /dev/null +++ b/code/modules/shuttles/antagonist.dm @@ -0,0 +1,16 @@ +/obj/machinery/computer/shuttle_control/multi/vox + name = "skipjack control console" + req_access = list(access_syndicate) + shuttle_tag = "Skipjack" + +/obj/machinery/computer/shuttle_control/multi/syndicate + name = "mercenary shuttle control console" + req_access = list(access_syndicate) + shuttle_tag = "Mercenary" + +/obj/machinery/computer/shuttle_control/multi/rescue + name = "rescue shuttle control console" + req_access = list(access_cent_specops) + shuttle_tag = "Rescue" + + diff --git a/code/modules/shuttles/departmental.dm b/code/modules/shuttles/departmental.dm new file mode 100644 index 00000000..13362bfc --- /dev/null +++ b/code/modules/shuttles/departmental.dm @@ -0,0 +1,35 @@ +/obj/machinery/computer/shuttle_control/mining + name = "mining shuttle control console" + shuttle_tag = "Mining" + //req_access = list(access_mining) + circuit = /obj/item/weapon/circuitboard/mining_shuttle + +/obj/machinery/computer/shuttle_control/engineering + name = "engineering shuttle control console" + shuttle_tag = "Engineering" + //req_one_access = list(access_engine_equip,access_atmospherics) + circuit = /obj/item/weapon/circuitboard/engineering_shuttle + +/obj/machinery/computer/shuttle_control/research + name = "research shuttle control console" + shuttle_tag = "Research" + //req_access = list(access_research) + circuit = /obj/item/weapon/circuitboard/research_shuttle + +/obj/machinery/computer/shuttle_control/merchant + name = "merchant shuttle control console" + icon_keyboard = "power_key" + icon_screen = "shuttle" + req_access = list(access_merchant) + shuttle_tag = "Merchant" + + +/* +/obj/machinery/computer/shuttle_control/multi/turbolift + name = "turbolift control console" + icon_state = "tcstation" + icon_keyboard = "tcstation_key" + icon_screen = "syndie" + shuttle_tag = "turbolift" + density = 0 +*/ diff --git a/code/modules/shuttles/escape_pods.dm b/code/modules/shuttles/escape_pods.dm new file mode 100644 index 00000000..24b1a4fb --- /dev/null +++ b/code/modules/shuttles/escape_pods.dm @@ -0,0 +1,157 @@ +var/list/escape_pods = list() +var/list/escape_pods_by_name = list() + +/datum/shuttle/autodock/ferry/escape_pod + var/datum/computer/file/embedded_program/docking/simple/escape_pod/arming_controller + category = /datum/shuttle/autodock/ferry/escape_pod + move_time = 100 + +/datum/shuttle/autodock/ferry/escape_pod/New() + if(name in escape_pods_by_name) + CRASH("An escape pod with the name '[name]' has already been defined.") + move_time = evacuation_controller.evac_transit_delay + rand(-30, 60) + escape_pods_by_name[name] = src + escape_pods += src + move_time = round(evacuation_controller.evac_transit_delay/10) + + ..() + + //find the arming controller (berth) + var/arming_controller_tag = arming_controller + arming_controller = locate(arming_controller_tag) + if(!istype(arming_controller)) + CRASH("Could not find arming controller for escape pod \"[name]\", tag was '[arming_controller_tag]'.") + + //find the pod's own controller + var/datum/computer/file/embedded_program/docking/simple/prog = locate(dock_target) + var/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod/controller_master = prog.master + if(!istype(controller_master)) + CRASH("Escape pod \"[name]\" could not find it's controller master!") + + controller_master.pod = src + +/datum/shuttle/autodock/ferry/escape_pod/can_launch() + if(arming_controller && !arming_controller.armed) //must be armed + return 0 + if(location) + return 0 //it's a one-way trip. + return ..() + +/datum/shuttle/autodock/ferry/escape_pod/can_force() + if (arming_controller.eject_time && world.time < arming_controller.eject_time + 50) + return 0 //dont allow force launching until 5 seconds after the arming controller has reached it's countdown + return ..() + +/datum/shuttle/autodock/ferry/escape_pod/can_cancel() + return 0 + + +//This controller goes on the escape pod itself +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod + name = "escape pod controller" + var/datum/shuttle/autodock/ferry/escape_pod/pod + +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + + data = list( + "docking_status" = docking_program.get_docking_status(), + "override_enabled" = docking_program.override_enabled, + "door_state" = docking_program.memory["door_status"]["state"], + "door_lock" = docking_program.memory["door_status"]["lock"], + "can_force" = pod.can_force() || (evacuation_controller.has_evacuated() && pod.can_launch()), //allow players to manually launch ahead of time if the shuttle leaves + "is_armed" = pod.arming_controller.armed, + ) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + + if (!ui) + ui = new(user, src, ui_key, "escape_pod_console.tmpl", name, 470, 290) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod/OnTopic(user, href_list) + if("manual_arm") + pod.arming_controller.arm() + return TOPIC_REFRESH + + if("force_launch") + if (pod.can_force()) + pod.force_launch(src) + else if (evacuation_controller.has_evacuated() && pod.can_launch()) //allow players to manually launch ahead of time if the shuttle leaves + pod.launch(src) + return TOPIC_REFRESH + +//This controller is for the escape pod berth (station side) +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod_berth + name = "escape pod berth controller" + progtype = /datum/computer/file/embedded_program/docking/simple/escape_pod + +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod_berth/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + + var/armed = null + if (istype(docking_program, /datum/computer/file/embedded_program/docking/simple/escape_pod)) + var/datum/computer/file/embedded_program/docking/simple/escape_pod/P = docking_program + armed = P.armed + + data = list( + "docking_status" = docking_program.get_docking_status(), + "override_enabled" = docking_program.override_enabled, + "armed" = armed, + ) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + + if (!ui) + ui = new(user, src, ui_key, "escape_pod_berth_console.tmpl", name, 470, 290) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod_berth/emag_act(var/remaining_charges, var/mob/user) + if (!emagged) + to_chat(user, "You emag the [src], arming the escape pod!") + emagged = 1 + if (istype(docking_program, /datum/computer/file/embedded_program/docking/simple/escape_pod)) + var/datum/computer/file/embedded_program/docking/simple/escape_pod/P = docking_program + if (!P.armed) + P.arm() + return 1 + +//A docking controller program for a simple door based docking port +/datum/computer/file/embedded_program/docking/simple/escape_pod + var/armed = 0 + var/eject_delay = 10 //give latecomers some time to get out of the way if they don't make it onto the pod + var/eject_time = null + var/closing = 0 + +/datum/computer/file/embedded_program/docking/simple/escape_pod/proc/arm() + if(!armed) + armed = 1 + open_door() + + +/datum/computer/file/embedded_program/docking/simple/escape_pod/receive_user_command(command) + if (!armed) + return + ..(command) + +/datum/computer/file/embedded_program/docking/simple/escape_pod/process() + ..() + if (eject_time && world.time >= eject_time && !closing) + close_door() + closing = 1 + +/datum/computer/file/embedded_program/docking/simple/escape_pod/prepare_for_docking() + return + +/datum/computer/file/embedded_program/docking/simple/escape_pod/ready_for_docking() + return 1 + +/datum/computer/file/embedded_program/docking/simple/escape_pod/finish_docking() + return //don't do anything - the doors only open when the pod is armed. + +/datum/computer/file/embedded_program/docking/simple/escape_pod/prepare_for_undocking() + eject_time = world.time + eject_delay*10 diff --git a/code/modules/shuttles/landmarks.dm b/code/modules/shuttles/landmarks.dm new file mode 100644 index 00000000..204403c8 --- /dev/null +++ b/code/modules/shuttles/landmarks.dm @@ -0,0 +1,139 @@ +//making this separate from /obj/effect/landmark until that mess can be dealt with +/obj/effect/shuttle_landmark + name = "Nav Point" + icon = 'icons/effects/effects.dmi' + icon_state = "energynet" + anchored = 1 + unacidable = 1 + simulated = 0 + invisibility = 101 + + var/landmark_tag + //ID of the controller on the dock side + var/datum/computer/file/embedded_program/docking/docking_controller + //ID of controller used for this landmark for shuttles with multiple ones. + var/list/special_dock_targets + + //when the shuttle leaves this landmark, it will leave behind the base area + //also used to determine if the shuttle can arrive here without obstruction + var/area/base_area + //Will also leave this type of turf behind if set. + var/turf/base_turf + //If set, will set base area and turf type to same as where it was spawned at + var/autoset + +/obj/effect/shuttle_landmark/New() + ..() + tag = landmark_tag //since tags cannot be set at compile time + if(autoset) + base_area = get_area(src) + var/turf/T = get_turf(src) + if(T) + base_turf = T.type + else + base_area = locate(base_area || world.area) + name = name + " ([x],[y])" + +/obj/effect/shuttle_landmark/Initialize() + . = ..() + if(docking_controller) + var/docking_tag = docking_controller + docking_controller = locate(docking_tag) + if(!istype(docking_controller)) + log_error("Could not find docking controller for shuttle waypoint '[name]', docking tag was '[docking_tag]'.") + if(GLOB.using_map.use_overmap) + var/obj/effect/overmap/location = map_sectors["[z]"] + if(location && location.docking_codes) + docking_controller.docking_codes = location.docking_codes + shuttle_controller.register_landmark(tag, src) + +/obj/effect/shuttle_landmark/proc/is_valid(var/datum/shuttle/shuttle) + if(shuttle.current_location == src) + return FALSE + for(var/area/A in shuttle.shuttle_area) + var/list/translation = get_turf_translation(get_turf(shuttle.current_location), get_turf(src), A.contents) + if(check_collision(translation)) + return FALSE + return TRUE + +/obj/effect/shuttle_landmark/proc/check_collision(var/list/turf_translation) + for(var/source in turf_translation) + var/turf/target = turf_translation[source] + if(!target) + return TRUE //collides with edge of map + if(target.loc != base_area) + return TRUE //collides with another area + if(target.density) + return TRUE //dense turf + return FALSE + +//Self-naming/numbering ones. +/obj/effect/shuttle_landmark/automatic + name = "Navpoint" + landmark_tag = "navpoint" + autoset = 1 + var/shuttle_restricted //name of the shuttle, null for generic waypoint + +/obj/effect/shuttle_landmark/automatic/Initialize() + tag = landmark_tag+"-[x]-[y]" + . = ..() + base_area = get_area(src) + if(!GLOB.using_map.use_overmap) + return + add_to_sector(map_sectors["[z]"]) + +/obj/effect/shuttle_landmark/automatic/proc/add_to_sector(var/obj/effect/overmap/O, var/tag_only) + if(!istype(O)) + return + SetName("[O.name] - [name]") + if(shuttle_restricted) + if(!O.restricted_waypoints[shuttle_restricted]) + O.restricted_waypoints[shuttle_restricted] = list() + O.restricted_waypoints[shuttle_restricted] += tag_only ? tag : src + else + O.generic_waypoints += tag_only ? tag : src + +//Subtype that calls explosion on init to clear space for shuttles +/obj/effect/shuttle_landmark/automatic/clearing + var/radius = 10 + +/obj/effect/shuttle_landmark/automatic/clearing/Initialize() + . = ..() + return INITIALIZE_HINT_LATELOAD + +/obj/effect/shuttle_landmark/automatic/clearing/LateInitialize() + var/list/victims = circlerangeturfs(get_turf(src),radius) + for(var/turf/T in victims) + if(T.density) + T.ChangeTurf(get_base_turf_by_area(T)) + +/obj/item/device/spaceflare + name = "bluespace flare" + desc = "Burst transmitter used to broadcast all needed information for shuttle navigation systems. Has a flare attached for marking the spot where you probably shouldn't be standing." + icon_state = "bluflare" + light_color = "#3728ff" + var/active + +/obj/item/device/spaceflare/attack_self(var/mob/user) + if(!active) + visible_message("[user] pulls the cord, activating the [src].") + activate() + +/obj/item/device/spaceflare/proc/activate() + if(active) + return + active = 1 + var/turf/T = get_turf(src) + var/obj/effect/shuttle_landmark/automatic/mark = new(T) + mark.SetName("Beacon signal ([T.x],[T.y])") + if(ismob(loc)) + var/mob/M = loc + M.drop_from_inventory(src,T) + anchored = 1 + T.hotspot_expose(1500, 5) + update_icon() + +/obj/item/device/spaceflare/update_icon() + if(active) + icon_state = "bluflare_on" + set_light(l_range = 6, l_power = 3) \ No newline at end of file diff --git a/code/modules/shuttles/shuttle.dm b/code/modules/shuttles/shuttle.dm new file mode 100644 index 00000000..8e1c276a --- /dev/null +++ b/code/modules/shuttles/shuttle.dm @@ -0,0 +1,216 @@ +//shuttle moving state defines are in setup.dm + +/datum/shuttle + var/name = "" + var/warmup_time = 0 + var/moving_status = SHUTTLE_IDLE + + var/area/shuttle_area //can be both single area type or a list of areas + var/obj/effect/shuttle_landmark/current_location + + var/arrive_time = 0 //the time at which the shuttle arrives when long jumping + var/flags = SHUTTLE_FLAGS_PROCESS + var/category = /datum/shuttle + + var/ceiling_type = /turf/unsimulated/floor/shuttle_ceiling + + var/sound_takeoff = 'sound/effects/shuttle_takeoff.ogg' + var/sound_landing = 'sound/effects/shuttle_landing.ogg' + + var/knockdown = 1 //whether shuttle downs non-buckled people when it moves + + var/defer_initialisation = FALSE //this shuttle will/won't be initialised by something after roundstart + +/datum/shuttle/New(_name, var/obj/effect/shuttle_landmark/initial_location) + ..() + if(_name) + src.name = _name + + var/list/areas = list() + if(!islist(shuttle_area)) + shuttle_area = list(shuttle_area) + for(var/T in shuttle_area) + var/area/A = locate(T) + if(!istype(A)) + CRASH("Shuttle \"[name]\" couldn't locate area [T].") + areas += A + shuttle_area = areas + + if(initial_location) + current_location = initial_location + else + current_location = locate(current_location) + if(!istype(current_location)) + CRASH("Shuttle \"[name]\" could not find its starting location.") + + if(src.name in shuttle_controller.shuttles) + CRASH("A shuttle with the name '[name]' is already defined.") + shuttle_controller.shuttles[src.name] = src + if(flags & SHUTTLE_FLAGS_PROCESS) + shuttle_controller.process_shuttles += src + if(flags & SHUTTLE_FLAGS_SUPPLY) + if(supply_controller.shuttle) + CRASH("A supply shuttle is already defined.") + supply_controller.shuttle = src + +/datum/shuttle/Destroy() + current_location = null + + shuttle_controller.shuttles -= src.name + shuttle_controller.process_shuttles -= src + if(supply_controller.shuttle == src) + supply_controller.shuttle = null + + . = ..() + +/datum/shuttle/proc/short_jump(var/obj/effect/shuttle_landmark/destination) + if(moving_status != SHUTTLE_IDLE) return + + moving_status = SHUTTLE_WARMUP + if(sound_takeoff) + playsound(current_location, sound_takeoff, 100, 20, 0.2) + spawn(warmup_time*10) + if (moving_status == SHUTTLE_IDLE) + return FALSE //someone cancelled the launch + + if(!fuel_check()) //fuel error (probably out of fuel) occured, so cancel the launch + var/datum/shuttle/autodock/S = src + if(istype(S)) + S.cancel_launch(null) + return + + moving_status = SHUTTLE_INTRANSIT //shouldn't matter but just to be safe + attempt_move(destination) + moving_status = SHUTTLE_IDLE + +/datum/shuttle/proc/long_jump(var/obj/effect/shuttle_landmark/destination, var/obj/effect/shuttle_landmark/interim, var/travel_time) + if(moving_status != SHUTTLE_IDLE) return + + var/obj/effect/shuttle_landmark/start_location = current_location + + moving_status = SHUTTLE_WARMUP + if(sound_takeoff) + playsound(current_location, sound_takeoff, 100, 20, 0.2) + spawn(warmup_time*10) + if(moving_status == SHUTTLE_IDLE) + return //someone cancelled the launch + + if(!fuel_check()) //fuel error (probably out of fuel) occured, so cancel the launch + var/datum/shuttle/autodock/S = src + if(istype(S)) + S.cancel_launch(null) + return + + arrive_time = world.time + travel_time*10 + moving_status = SHUTTLE_INTRANSIT + if(attempt_move(interim)) + var/fwooshed = 0 + while (world.time < arrive_time) + if(!fwooshed && (arrive_time - world.time) < 100) + fwooshed = 1 + playsound(destination, sound_landing, 100, 0, 7) + sleep(5) + if(!attempt_move(destination)) + attempt_move(start_location) //try to go back to where we started. If that fails, I guess we're stuck in the interim location + + moving_status = SHUTTLE_IDLE + +/datum/shuttle/proc/fuel_check() + return 1 //fuel check should always pass in non-overmap shuttles (they have magic engines) + +/datum/shuttle/proc/attempt_move(var/obj/effect/shuttle_landmark/destination) + if(current_location == destination) + return FALSE + + if(!destination.is_valid(src)) + return FALSE + testing("[src] moving to [destination]. Areas are [english_list(shuttle_area)]") + var/list/translation = list() + for(var/area/A in shuttle_area) + testing("Moving [A]") + translation += get_turf_translation(get_turf(current_location), get_turf(destination), A.contents) + shuttle_moved(destination, translation) + return TRUE + + +//just moves the shuttle from A to B, if it can be moved +//A note to anyone overriding move in a subtype. shuttle_moved() must absolutely not, under any circumstances, fail to move the shuttle. +//If you want to conditionally cancel shuttle launches, that logic must go in short_jump(), long_jump() or attempt_move() +/datum/shuttle/proc/shuttle_moved(var/obj/effect/shuttle_landmark/destination, var/list/turf_translation) + +// log_debug("move_shuttle() called for [shuttle_tag] leaving [origin] en route to [destination].") +// log_degug("area_coming_from: [origin]") +// log_debug("destination: [destination]") + for(var/turf/src_turf in turf_translation) + var/turf/dst_turf = turf_translation[src_turf] + if(src_turf.is_solid_structure()) //in case someone put a hole in the shuttle and you were lucky enough to be under it + for(var/atom/movable/AM in dst_turf) + if(!AM.simulated) + continue + if(isliving(AM)) + var/mob/living/bug = AM + bug.gib() + else + qdel(AM) //it just gets atomized I guess? TODO throw it into space somewhere, prevents people from using shuttles as an atom-smasher + var/list/powernets = list() + for(var/area/A in shuttle_area) + // if there was a zlevel above our origin, erase our ceiling now we're leaving + if(HasAbove(current_location.z)) + for(var/turf/TO in A.contents) + var/turf/TA = GetAbove(TO) + if(istype(TA, ceiling_type)) + TA.ChangeTurf(get_base_turf_by_area(TA), 1, 1) + + for(var/mob/M in A) + if(knockdown) + if(M.client) + spawn(0) + if(M.buckled) + to_chat(M, "Sudden acceleration presses you into your chair!") + shake_camera(M, 3, 1) + else + to_chat(M, "The floor lurches beneath you!") + shake_camera(M, 10, 1) + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(!H.buckled) + H.visible_message("[M.name] is tossed around by the sudden acceleration!") + var/smashsound = pick("sound/effects/gore/smash[rand(1,3)].ogg", "sound/effects/gore/trauma1.ogg") + playsound(M, smashsound, 50, 1, -1) + H.emote("scream") + H.Stun(2) + H.Weaken(2) + step(H,pick(GLOB.cardinal))//move them + H.apply_damage(rand(30) , BRUTE) + + shake_camera(M, 2, 1) + + for(var/obj/structure/cable/C in A) + powernets |= C.powernet + + translate_turfs(turf_translation, current_location.base_area, current_location.base_turf) + current_location = destination + + // if there's a zlevel above our destination, paint in a ceiling on it so we retain our air + if(HasAbove(current_location.z)) + for(var/area/A in shuttle_area) + for(var/turf/TD in A.contents) + var/turf/TA = GetAbove(TD) + if(istype(TA, get_base_turf_by_area(TA)) || istype(TA, /turf/simulated/open)) + TA.ChangeTurf(ceiling_type, 1, 1) + + // Remove all powernets that were affected, and rebuild them. + var/list/cables = list() + for(var/datum/powernet/P in powernets) + cables |= P.cables + qdel(P) + for(var/obj/structure/cable/C in cables) + if(!C.powernet) + var/datum/powernet/NewPN = new() + NewPN.add_cable(C) + propagate_network(C,C.powernet) + +//returns 1 if the shuttle has a valid arrive time +/datum/shuttle/proc/has_arrive_time() + return (moving_status == SHUTTLE_INTRANSIT) diff --git a/code/modules/shuttles/shuttle_autodock.dm b/code/modules/shuttles/shuttle_autodock.dm new file mode 100644 index 00000000..49434fdc --- /dev/null +++ b/code/modules/shuttles/shuttle_autodock.dm @@ -0,0 +1,184 @@ +#define DOCK_ATTEMPT_TIMEOUT 200 //how long in ticks we wait before assuming the docking controller is broken or blown up. + +/datum/shuttle/autodock + var/process_state = IDLE_STATE + var/in_use = null //tells the controller whether this shuttle needs processing, also attempts to prevent double-use + var/last_dock_attempt_time = 0 + var/current_dock_target + //ID of the controller on the shuttle + var/dock_target = null + var/datum/computer/file/embedded_program/docking/shuttle_docking_controller + var/docking_codes + + var/obj/effect/shuttle_landmark/next_location + var/datum/computer/file/embedded_program/docking/active_docking_controller + + var/obj/effect/shuttle_landmark/landmark_transition + var/move_time = 240 //the time spent in the transition area + + category = /datum/shuttle/autodock + +/datum/shuttle/autodock/New(var/_name, var/obj/effect/shuttle_landmark/start_waypoint) + ..(_name, start_waypoint) + + //Initial dock + active_docking_controller = current_location.docking_controller + update_docking_target(current_location) + if(active_docking_controller) + set_docking_codes(active_docking_controller.docking_codes) + else if(GLOB.using_map.use_overmap) + var/obj/effect/overmap/location = map_sectors["[current_location.z]"] + if(location && location.docking_codes) + set_docking_codes(location.docking_codes) + dock() + + //Optional transition area + if(landmark_transition) + landmark_transition = locate(landmark_transition) + +/datum/shuttle/autodock/Destroy() + next_location = null + active_docking_controller = null + landmark_transition = null + + return ..() + +/datum/shuttle/autodock/proc/set_docking_codes(var/code) + docking_codes = code + if(shuttle_docking_controller) + shuttle_docking_controller.docking_codes = code + +/datum/shuttle/autodock/shuttle_moved() + force_undock() //bye! + ..() + +/datum/shuttle/autodock/proc/update_docking_target(var/obj/effect/shuttle_landmark/location) + if(location && location.special_dock_targets && location.special_dock_targets[name]) + current_dock_target = location.special_dock_targets[name] + else + current_dock_target = dock_target + shuttle_docking_controller = locate(current_dock_target) +/* + Docking stuff +*/ +/datum/shuttle/autodock/proc/dock() + if(active_docking_controller && shuttle_docking_controller) + shuttle_docking_controller.initiate_docking(active_docking_controller.id_tag) + last_dock_attempt_time = world.time + +/datum/shuttle/autodock/proc/undock() + if(shuttle_docking_controller) + shuttle_docking_controller.initiate_undocking() + +/datum/shuttle/autodock/proc/force_undock() + if(shuttle_docking_controller) + shuttle_docking_controller.force_undock() + +/datum/shuttle/autodock/proc/check_docked() + if(shuttle_docking_controller) + return shuttle_docking_controller.docked() + return TRUE + +/datum/shuttle/autodock/proc/check_undocked() + if(shuttle_docking_controller) + return shuttle_docking_controller.can_launch() + return TRUE + +/* + Please ensure that long_jump() and short_jump() are only called from here. This applies to subtypes as well. + Doing so will ensure that multiple jumps cannot be initiated in parallel. +*/ +/datum/shuttle/autodock/proc/process() + switch(process_state) + if (WAIT_LAUNCH) + if(check_undocked()) + //*** ready to go + process_launch() + + if (FORCE_LAUNCH) + process_launch() + + if (WAIT_ARRIVE) + if (moving_status == SHUTTLE_IDLE) + //*** we made it to the destination, update stuff + process_arrived() + process_state = WAIT_FINISH + + if (WAIT_FINISH) + if (world.time > last_dock_attempt_time + DOCK_ATTEMPT_TIMEOUT || check_docked()) + //*** all done here + process_state = IDLE_STATE + arrived() + +//not to be confused with the arrived() proc +/datum/shuttle/autodock/proc/process_arrived() + active_docking_controller = next_location.docking_controller + update_docking_target(next_location) + dock() + + next_location = null + in_use = null //release lock + + +/datum/shuttle/autodock/proc/process_launch() + if(!next_location.is_valid(src)) + process_state = IDLE_STATE + in_use = null + return + if (move_time && landmark_transition) + . = long_jump(next_location, landmark_transition, move_time) + else + . = short_jump(next_location) + process_state = WAIT_ARRIVE + +/* + Guards +*/ +/datum/shuttle/autodock/proc/can_launch() + return (next_location && moving_status == SHUTTLE_IDLE && !in_use) + +/datum/shuttle/autodock/proc/can_force() + return (next_location && moving_status == SHUTTLE_IDLE && process_state == WAIT_LAUNCH) + +/datum/shuttle/autodock/proc/can_cancel() + return (moving_status == SHUTTLE_WARMUP || process_state == WAIT_LAUNCH || process_state == FORCE_LAUNCH) + +/* + "Public" procs +*/ +/datum/shuttle/autodock/proc/launch(var/user) + if (!can_launch()) return + + in_use = user //obtain an exclusive lock on the shuttle + + process_state = WAIT_LAUNCH + undock() + +/datum/shuttle/autodock/proc/force_launch(var/user) + if (!can_force()) return + + in_use = user //obtain an exclusive lock on the shuttle + + process_state = FORCE_LAUNCH + +/datum/shuttle/autodock/proc/cancel_launch(var/user) + if (!can_cancel()) return + + moving_status = SHUTTLE_IDLE + process_state = WAIT_FINISH + in_use = null + + //whatever we were doing with docking: stop it, then redock + force_undock() + spawn(1 SECOND) + dock() + +//returns 1 if the shuttle is getting ready to move, but is not in transit yet +/datum/shuttle/autodock/proc/is_launching() + return (moving_status == SHUTTLE_WARMUP || process_state == WAIT_LAUNCH || process_state == FORCE_LAUNCH) + +//This gets called when the shuttle finishes arriving at it's destination +//This can be used by subtypes to do things when the shuttle arrives. +//Note that this is called when the shuttle leaves the WAIT_FINISHED state, the proc name is a little misleading +/datum/shuttle/autodock/proc/arrived() + return //do nothing for now diff --git a/code/modules/shuttles/shuttle_console.dm b/code/modules/shuttles/shuttle_console.dm new file mode 100644 index 00000000..92d3d137 --- /dev/null +++ b/code/modules/shuttles/shuttle_console.dm @@ -0,0 +1,115 @@ +/obj/machinery/computer/shuttle_control + name = "shuttle control console" + icon = 'icons/obj/computer.dmi' + icon_keyboard = "atmos_key" + icon_screen = "shuttle" + circuit = null + + var/shuttle_tag // Used to coordinate data in shuttle controller. + var/hacked = 0 // Has been emagged, no access restrictions. + + var/ui_template = "shuttle_control_console.tmpl" + + +/obj/machinery/computer/shuttle_control/attack_hand(user as mob) + if(..(user)) + return + if(!allowed(user)) + to_chat(user, "Access Denied.") + return 1 + + ui_interact(user) + +/obj/machinery/computer/shuttle_control/proc/get_ui_data(var/datum/shuttle/autodock/shuttle) + var/shuttle_state + switch(shuttle.moving_status) + if(SHUTTLE_IDLE) shuttle_state = "idle" + if(SHUTTLE_WARMUP) shuttle_state = "warmup" + if(SHUTTLE_INTRANSIT) shuttle_state = "in_transit" + + var/shuttle_status + switch (shuttle.process_state) + if(IDLE_STATE) + if (shuttle.in_use) + shuttle_status = "Busy." + else + shuttle_status = "Standing-by at [shuttle.current_location]." + + if(WAIT_LAUNCH, FORCE_LAUNCH) + shuttle_status = "Shuttle has recieved command and will depart shortly." + if(WAIT_ARRIVE) + shuttle_status = "Proceeding to [shuttle.next_location]." + if(WAIT_FINISH) + shuttle_status = "Arriving at destination now." + + return list( + "shuttle_status" = shuttle_status, + "shuttle_state" = shuttle_state, + "has_docking" = shuttle.shuttle_docking_controller? 1 : 0, + "docking_status" = shuttle.shuttle_docking_controller? shuttle.shuttle_docking_controller.get_docking_status() : null, + "docking_override" = shuttle.shuttle_docking_controller? shuttle.shuttle_docking_controller.override_enabled : null, + "can_launch" = shuttle.can_launch(), + "can_cancel" = shuttle.can_cancel(), + "can_force" = shuttle.can_force(), + "docking_codes" = shuttle.docking_codes + ) + +/obj/machinery/computer/shuttle_control/proc/handle_topic_href(var/datum/shuttle/autodock/shuttle, var/list/href_list, var/user) + if(!istype(shuttle)) + return TOPIC_NOACTION + + if(href_list["move"]) + if(!shuttle.next_location.is_valid(shuttle)) + to_chat(user, "Destination zone is invalid or obstructed.") + return TOPIC_HANDLED + shuttle.launch(src) + return TOPIC_REFRESH + + if(href_list["force"]) + shuttle.force_launch(src) + return TOPIC_REFRESH + + if(href_list["cancel"]) + shuttle.cancel_launch(src) + return TOPIC_REFRESH + + if(href_list["set_codes"]) + var/newcode = input("Input new docking codes", "Docking codes", shuttle.docking_codes) as text|null + if (newcode && CanInteract(usr, GLOB.default_state)) + shuttle.set_docking_codes(uppertext(newcode)) + return TOPIC_REFRESH + +/obj/machinery/computer/shuttle_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/datum/shuttle/autodock/shuttle = shuttle_controller.shuttles[shuttle_tag] + if (!istype(shuttle)) + to_chat(user,"Unable to establish link with the shuttle.") + return + + var/list/data = get_ui_data(shuttle) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, ui_template, "[shuttle_tag] Shuttle Control", 470, 450) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/computer/shuttle_control/OnTopic(user, href_list) + return handle_topic_href(shuttle_controller.shuttles[shuttle_tag], href_list, user) + +/obj/machinery/computer/shuttle_control/emag_act(var/remaining_charges, var/mob/user) + if (!hacked) + req_access = list() + req_one_access = list() + hacked = 1 + to_chat(user, "You short out the console's ID checking system. It's now available to everyone!") + return 1 + +/obj/machinery/computer/shuttle_control/bullet_act(var/obj/item/projectile/Proj) + visible_message("\The [Proj] ricochets off \the [src]!") + +/obj/machinery/computer/shuttle_control/ex_act() + return + +/obj/machinery/computer/shuttle_control/emp_act() + return diff --git a/code/modules/shuttles/shuttle_console_multi.dm b/code/modules/shuttles/shuttle_console_multi.dm new file mode 100644 index 00000000..e6033a8d --- /dev/null +++ b/code/modules/shuttles/shuttle_console_multi.dm @@ -0,0 +1,39 @@ +/obj/machinery/computer/shuttle_control/multi + ui_template = "shuttle_control_console_multi.tmpl" + +/obj/machinery/computer/shuttle_control/multi/get_ui_data(var/datum/shuttle/autodock/multi/shuttle) + . = ..() + if(istype(shuttle)) + . += list( + "destination_name" = shuttle.next_location? shuttle.next_location.name : "No destination set.", + "can_pick" = shuttle.moving_status == SHUTTLE_IDLE, + ) + +/obj/machinery/computer/shuttle_control/multi/handle_topic_href(var/datum/shuttle/autodock/multi/shuttle, var/list/href_list) + if((. = ..()) != null) + return + + if(href_list["pick"]) + var/dest_key = input("Choose shuttle destination", "Shuttle Destination") as null|anything in shuttle.get_destinations() + if(dest_key && CanInteract(usr, GLOB.default_state)) + shuttle.set_destination(dest_key, usr) + return TOPIC_REFRESH + + +/obj/machinery/computer/shuttle_control/multi/antag + ui_template = "shuttle_control_console_antag.tmpl" + +/obj/machinery/computer/shuttle_control/multi/antag/get_ui_data(var/datum/shuttle/autodock/multi/antag/shuttle) + . = ..() + if(istype(shuttle)) + . += list( + "cloaked" = shuttle.cloaked, + ) + +/obj/machinery/computer/shuttle_control/multi/antag/handle_topic_href(var/datum/shuttle/autodock/multi/antag/shuttle, var/list/href_list) + if((. = ..()) != null) + return + + if(href_list["toggle_cloaked"]) + shuttle.cloaked = !shuttle.cloaked + return TOPIC_REFRESH diff --git a/code/modules/shuttles/shuttle_emergency.dm b/code/modules/shuttles/shuttle_emergency.dm new file mode 100644 index 00000000..7cec503c --- /dev/null +++ b/code/modules/shuttles/shuttle_emergency.dm @@ -0,0 +1,257 @@ +/datum/shuttle/autodock/ferry/emergency + category = /datum/shuttle/autodock/ferry/emergency + move_time = 3 MINUTES + var/datum/evacuation_controller/shuttle/emergency_controller + +/datum/shuttle/autodock/ferry/emergency/New() + . = ..() + emergency_controller = evacuation_controller + if(!istype(emergency_controller)) + CRASH("Escape shuttle created without the appropriate controller type.") + return + if(emergency_controller.shuttle) + CRASH("An emergency shuttle has already been created.") + return + emergency_controller.shuttle = src + +/datum/shuttle/autodock/ferry/emergency/arrived() + . = ..() + + if(!emergency_controller.has_evacuated()) + emergency_controller.finish_preparing_evac() + + if (istype(in_use, /obj/machinery/computer/shuttle_control/emergency)) + var/obj/machinery/computer/shuttle_control/emergency/C = in_use + C.reset_authorization() + +/datum/shuttle/autodock/ferry/emergency/long_jump(var/destination, var/interim, var/travel_time, var/direction) + ..(destination, interim, emergency_controller.get_long_jump_time(), direction) + +/datum/shuttle/autodock/ferry/emergency/shuttle_moved() + if(current_location == waypoint_station) + emergency_controller.shuttle_leaving() // This is a hell of a line. v + priority_announcement.Announce(replacetext(replacetext((emergency_controller.emergency_evacuation ? GLOB.using_map.emergency_shuttle_leaving_dock : GLOB.using_map.shuttle_leaving_dock), "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETA%", "[round(emergency_controller.get_eta()/60,1)] minute\s")) + else if(next_location == waypoint_offsite && emergency_controller.has_evacuated()) + emergency_controller.shuttle_evacuated() + ..() + +/datum/shuttle/autodock/ferry/emergency/can_launch(var/user) + if (istype(user, /obj/machinery/computer/shuttle_control/emergency)) + var/obj/machinery/computer/shuttle_control/emergency/C = user + if (!C.has_authorization()) + return 0 + return ..() + +/datum/shuttle/autodock/ferry/emergency/can_force(var/user) + if (istype(user, /obj/machinery/computer/shuttle_control/emergency)) + var/obj/machinery/computer/shuttle_control/emergency/C = user + + //initiating or cancelling a launch ALWAYS requires authorization, but if we are already set to launch anyways than forcing does not. + //this is so that people can force launch if the docking controller cannot safely undock without needing X heads to swipe. + if (!(process_state == WAIT_LAUNCH || C.has_authorization())) + return 0 + return ..() + +/datum/shuttle/autodock/ferry/emergency/can_cancel(var/user) + if(emergency_controller.has_evacuated()) + return 0 + if (istype(user, /obj/machinery/computer/shuttle_control/emergency)) + var/obj/machinery/computer/shuttle_control/emergency/C = user + if (!C.has_authorization()) + return 0 + return ..() + +/datum/shuttle/autodock/ferry/emergency/launch(var/user) + if (!can_launch(user)) return + + if (istype(user, /obj/machinery/computer/shuttle_control/emergency)) //if we were given a command by an emergency shuttle console + if (emergency_controller.autopilot) + emergency_controller.autopilot = 0 + to_world("Alert: The shuttle autopilot has been overridden. Launch sequence initiated!") + + if(usr) + log_admin("[key_name(usr)] has overridden the shuttle autopilot and activated launch sequence") + message_admins("[key_name_admin(usr)] has overridden the shuttle autopilot and activated launch sequence") + + ..(user) + +/datum/shuttle/autodock/ferry/emergency/force_launch(var/user) + if (!can_force(user)) return + + if (istype(user, /obj/machinery/computer/shuttle_control/emergency)) //if we were given a command by an emergency shuttle console + if (emergency_controller.autopilot) + emergency_controller.autopilot = 0 + to_world("Alert: The shuttle autopilot has been overridden. Bluespace drive engaged!") + + if(usr) + log_admin("[key_name(usr)] has overridden the shuttle autopilot and forced immediate launch") + message_admins("[key_name_admin(usr)] has overridden the shuttle autopilot and forced immediate launch") + + ..(user) + +/datum/shuttle/autodock/ferry/emergency/cancel_launch(var/user) + + if (!can_cancel(user)) return + + if(!emergency_controller.shuttle_preparing()) + + if (istype(user, /obj/machinery/computer/shuttle_control/emergency)) //if we were given a command by an emergency shuttle console + if (emergency_controller.autopilot) + emergency_controller.autopilot = 0 + to_world("Alert: The shuttle autopilot has been overridden. Launch sequence aborted!") + + if(usr) + log_admin("[key_name(usr)] has overridden the shuttle autopilot and cancelled launch sequence") + message_admins("[key_name_admin(usr)] has overridden the shuttle autopilot and cancelled launch sequence") + + ..(user) + +/obj/machinery/computer/shuttle_control/emergency + shuttle_tag = "Escape" + var/debug = 0 + var/req_authorizations = 1 + var/list/authorized = list() + +/obj/machinery/computer/shuttle_control/emergency/proc/has_authorization() + return (authorized.len >= req_authorizations || emagged) + +/obj/machinery/computer/shuttle_control/emergency/proc/reset_authorization() + //no need to reset emagged status. If they really want to go back to the station they can. + authorized = initial(authorized) + +//returns 1 if the ID was accepted and a new authorization was added, 0 otherwise +/obj/machinery/computer/shuttle_control/emergency/proc/read_authorization(var/obj/item/ident) + if (!ident || !istype(ident)) + return 0 + if (authorized.len >= req_authorizations) + return 0 //don't need any more + + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + if (!evacuation_controller.emergency_evacuation && security_state.current_security_level_is_lower_than(security_state.high_security_level)) + src.visible_message("\The [src] buzzes. It does not appear to be accepting any commands.") + return 0 + + var/list/access + var/auth_name + var/dna_hash + + var/obj/item/weapon/card/id/ID = ident.GetIdCard() + + if(!ID) + return + + access = ID.access + auth_name = "[ID.registered_name] ([ID.assignment])" + dna_hash = ID.dna_hash + + if (!access || !istype(access)) + return 0 //not an ID + + if (dna_hash in authorized) + src.visible_message("\The [src] buzzes. That ID has already been scanned.") + return 0 + + if (!(access_heads in access)) + src.visible_message("\The [src] buzzes, rejecting [ident].") + return 0 + + src.visible_message("\The [src] beeps as it scans [ident].") + authorized[dna_hash] = auth_name + if (req_authorizations - authorized.len) + to_world("Alert: [req_authorizations - authorized.len] authorization\s needed to override the shuttle autopilot.") + + if(usr) + log_admin("[key_name(usr)] has inserted [ID] into the shuttle control computer - [req_authorizations - authorized.len] authorisation\s needed") + message_admins("[key_name_admin(usr)] has inserted [ID] into the shuttle control computer - [req_authorizations - authorized.len] authorisation\s needed") + + return 1 + +/obj/machinery/computer/shuttle_control/emergency/emag_act(var/remaining_charges, var/mob/user) + if (!emagged) + to_chat(user, "You short out \the [src]'s authorization protocols.") + emagged = 1 + return 1 + +/obj/machinery/computer/shuttle_control/emergency/attackby(obj/item/weapon/W as obj, mob/user as mob) + read_authorization(W) + ..() + +/obj/machinery/computer/shuttle_control/emergency/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + var/datum/shuttle/autodock/ferry/emergency/shuttle = shuttle_controller.shuttles[shuttle_tag] + if (!istype(shuttle)) + return + + var/shuttle_state + switch(shuttle.moving_status) + if(SHUTTLE_IDLE) shuttle_state = "idle" + if(SHUTTLE_WARMUP) shuttle_state = "warmup" + if(SHUTTLE_INTRANSIT) shuttle_state = "in_transit" + + var/shuttle_status + switch (shuttle.process_state) + if(IDLE_STATE) + if (shuttle.in_use) + shuttle_status = "Busy." + else if (!shuttle.location) + shuttle_status = "Standing-by at [GLOB.using_map.station_name]." + else + shuttle_status = "Standing-by at [GLOB.using_map.dock_name]." + if(WAIT_LAUNCH, FORCE_LAUNCH) + shuttle_status = "Shuttle has recieved command and will depart shortly." + if(WAIT_ARRIVE) + shuttle_status = "Proceeding to destination." + if(WAIT_FINISH) + shuttle_status = "Arriving at destination now." + + //build a list of authorizations + var/list/auth_list[req_authorizations] + + if (!emagged) + var/i = 1 + for (var/dna_hash in authorized) + auth_list[i++] = list("auth_name"=authorized[dna_hash], "auth_hash"=dna_hash) + + while (i <= req_authorizations) //fill up the rest of the list with blank entries + auth_list[i++] = list("auth_name"="", "auth_hash"=null) + else + for (var/i = 1; i <= req_authorizations; i++) + auth_list[i] = list("auth_name"="ERROR", "auth_hash"=null) + + var/has_auth = has_authorization() + + data = list( + "shuttle_status" = shuttle_status, + "shuttle_state" = shuttle_state, + "has_docking" = shuttle.active_docking_controller? 1 : 0, + "docking_status" = shuttle.active_docking_controller? shuttle.active_docking_controller.get_docking_status() : null, + "docking_override" = shuttle.active_docking_controller? shuttle.active_docking_controller.override_enabled : null, + "can_launch" = shuttle.can_launch(src), + "can_cancel" = shuttle.can_cancel(src), + "can_force" = shuttle.can_force(src), + "auth_list" = auth_list, + "has_auth" = has_auth, + "user" = debug? user : null, + ) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + + if (!ui) + ui = new(user, src, ui_key, "escape_shuttle_control_console.tmpl", "Shuttle Control", 470, 420) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/computer/shuttle_control/emergency/OnTopic(user, href_list) + if(href_list["removeid"]) + var/dna_hash = href_list["removeid"] + authorized -= dna_hash + . = TOPIC_REFRESH + + else if(!emagged && href_list["scanid"]) + //They selected an empty entry. Try to scan their id. + var/mob/living/carbon/human/H = user + if (istype(H)) + if (!read_authorization(H.get_active_hand())) //try to read what's in their hand first + read_authorization(H.wear_id) + . = TOPIC_REFRESH diff --git a/code/modules/shuttles/shuttle_ferry.dm b/code/modules/shuttles/shuttle_ferry.dm new file mode 100644 index 00000000..1c4604d3 --- /dev/null +++ b/code/modules/shuttles/shuttle_ferry.dm @@ -0,0 +1,47 @@ + + +/datum/shuttle/autodock/ferry + var/location = 0 //0 = at area_station, 1 = at area_offsite + var/direction = 0 //0 = going to station, 1 = going to offsite. + + var/obj/effect/shuttle_landmark/waypoint_station + var/obj/effect/shuttle_landmark/waypoint_offsite + + category = /datum/shuttle/autodock/ferry + +/datum/shuttle/autodock/ferry/New(_name) + if(waypoint_station) + waypoint_station = locate(waypoint_station) + if(waypoint_offsite) + waypoint_offsite = locate(waypoint_offsite) + + ..(_name, get_location_waypoint(location)) + + next_location = get_location_waypoint(!location) + +//Gets the shuttle landmark associated with the given location (defaults to current location) +/datum/shuttle/autodock/ferry/proc/get_location_waypoint(location_id = null) + if (isnull(location_id)) + location_id = location + + if (!location_id) + return waypoint_station + return waypoint_offsite + +/datum/shuttle/autodock/ferry/short_jump(var/destination) + direction = !location + ..() + +/datum/shuttle/autodock/ferry/long_jump(var/destination, var/obj/effect/shuttle_landmark/interim, var/travel_time) + direction = !location + ..() + +/datum/shuttle/autodock/ferry/shuttle_moved() + ..() + + if (next_location == waypoint_station) location = 0 + if (next_location == waypoint_offsite) location = 1 + +/datum/shuttle/autodock/ferry/process_arrived() + ..() + next_location = get_location_waypoint(!location) diff --git a/code/modules/shuttles/shuttle_specops.dm b/code/modules/shuttles/shuttle_specops.dm new file mode 100644 index 00000000..4283c00a --- /dev/null +++ b/code/modules/shuttles/shuttle_specops.dm @@ -0,0 +1,200 @@ +/obj/machinery/computer/shuttle_control/specops + name = "special operations shuttle console" + shuttle_tag = "Special Operations" + req_access = list(access_cent_specops) + +/obj/machinery/computer/shuttle_control/specops/attack_ai(user as mob) + to_chat(user, "Access Denied.") + return 1 + +/datum/shuttle/autodock/ferry/specops + var/specops_return_delay = 6000 //After moving, the amount of time that must pass before the shuttle may move again + var/specops_countdown_time = 600 //Length of the countdown when moving the shuttle + + var/obj/item/device/radio/intercom/announcer = null + var/reset_time = 0 //the world.time at which the shuttle will be ready to move again. + var/launch_prep = 0 + var/cancel_countdown = 0 + category = /datum/shuttle/autodock/ferry/specops + +/datum/shuttle/autodock/ferry/specops/New() + ..() + announcer = new /obj/item/device/radio/intercom(null)//We need a fake AI to announce some stuff below. Otherwise it will be wonky. + announcer.config(list("Response Team" = 0)) + +/datum/shuttle/autodock/ferry/specops/proc/radio_announce(var/message) + if(announcer) + announcer.autosay(message, "A.L.I.C.E.", "Response Team") + + +/datum/shuttle/autodock/ferry/specops/launch(var/user) + if (!can_launch()) + return + + if (istype(user, /obj/machinery/computer)) + var/obj/machinery/computer/C = user + + if(world.time <= reset_time) + C.visible_message("[GLOB.using_map.boss_name] will not allow the Special Operations shuttle to launch yet.") + if (((world.time - reset_time)/10) > 60) + C.visible_message("[-((world.time - reset_time)/10)/60] minutes remain!") + else + C.visible_message("[-(world.time - reset_time)/10] seconds remain!") + return + + C.visible_message("The Special Operations shuttle will depart in [(specops_countdown_time/10)] seconds.") + + if (location) //returning + radio_announce("THE SPECIAL OPERATIONS SHUTTLE IS PREPARING TO RETURN") + else + radio_announce("THE SPECIAL OPERATIONS SHUTTLE IS PREPARING FOR LAUNCH") + + sleep_until_launch() + + if (location) + var/obj/machinery/light/small/readylight/light = locate() in shuttle_area + if(light) light.set_state(0) + + //launch + radio_announce("ALERT: INITIATING LAUNCH SEQUENCE") + ..(user) + +/datum/shuttle/autodock/ferry/specops/shuttle_moved() + ..() + + spawn(2 SECONDS) + if (!location) //just arrived home + for(var/turf/T in get_area_turfs(shuttle_area)) + var/mob/M = locate(/mob) in T + to_chat(M, "You have arrived at [GLOB.using_map.boss_name]. Operation has ended!") + else //just left for the station + launch_mauraders() + for(var/turf/T in get_area_turfs(shuttle_area)) + var/mob/M = locate(/mob) in T + to_chat(M, "You have arrived at [GLOB.using_map.station_name]. Commence operation!") + + var/obj/machinery/light/small/readylight/light = locate() in T + if(light) light.set_state(1) + +/datum/shuttle/autodock/ferry/specops/cancel_launch() + if (!can_cancel()) + return + + cancel_countdown = 1 + radio_announce("ALERT: LAUNCH SEQUENCE ABORTED") + if (istype(in_use, /obj/machinery/computer)) + var/obj/machinery/computer/C = in_use + C.visible_message("Launch sequence aborted.") + ..() + + + +/datum/shuttle/autodock/ferry/specops/can_launch() + if(launch_prep) + return 0 + return ..() + +//should be fine to allow forcing. process_state only becomes WAIT_LAUNCH after the countdown is over. +///datum/shuttle/autodock/ferry/specops/can_force() +// return 0 + +/datum/shuttle/autodock/ferry/specops/can_cancel() + if(launch_prep) + return 1 + return ..() + +/datum/shuttle/autodock/ferry/specops/proc/sleep_until_launch() + var/message_tracker[] = list(0,1,2,3,5,10,30,45)//Create a a list with potential time values. + + var/launch_time = world.time + specops_countdown_time + var/time_until_launch + + cancel_countdown = 0 + launch_prep = 1 + while(!cancel_countdown && (launch_time - world.time) > 0) + var/ticksleft = launch_time - world.time + + //if(ticksleft > 1e5) + // launch_time = world.timeofday + 10 // midnight rollover + time_until_launch = (ticksleft / 10) + + //All this does is announce the time before launch. + var/rounded_time_left = round(time_until_launch)//Round time so that it will report only once, not in fractions. + if(rounded_time_left in message_tracker)//If that time is in the list for message announce. + radio_announce("ALERT: [rounded_time_left] SECOND[(rounded_time_left!=1)?"S":""] REMAIN") + message_tracker -= rounded_time_left//Remove the number from the list so it won't be called again next cycle. + //Should call all the numbers but lag could mean some issues. Oh well. Not much I can do about that. + + sleep(5) + + launch_prep = 0 + + +/proc/launch_mauraders() + var/area/centcom/specops/special_ops = locate()//Where is the specops area located? + //Begin Marauder launchpad. + spawn(0)//So it parallel processes it. + for(var/obj/machinery/door/blast/M in special_ops) + switch(M.id) + if("ASSAULT0") + spawn(10)//1 second delay between each. + M.open() + if("ASSAULT1") + spawn(20) + M.open() + if("ASSAULT2") + spawn(30) + M.open() + if("ASSAULT3") + spawn(40) + M.open() + + sleep(10) + + var/spawn_marauder[] = new() + for(var/obj/effect/landmark/L in world) + if(L.name == "Marauder Entry") + spawn_marauder.Add(L) + for(var/obj/effect/landmark/L in world) + if(L.name == "Marauder Exit") + var/obj/effect/portal/P = new(L.loc) + P.set_invisibility(101)//So it is not seen by anyone. + P.failchance = 0//So it has no fail chance when teleporting. + P.target = pick(spawn_marauder)//Where the marauder will arrive. + spawn_marauder.Remove(P.target) + + sleep(10) + + for(var/obj/machinery/mass_driver/M in special_ops) + switch(M.id) + if("ASSAULT0") + spawn(10) + M.drive() + if("ASSAULT1") + spawn(20) + M.drive() + if("ASSAULT2") + spawn(30) + M.drive() + if("ASSAULT3") + spawn(40) + M.drive() + + sleep(50)//Doors remain open for 5 seconds. + + for(var/obj/machinery/door/blast/M in special_ops) + switch(M.id)//Doors close at the same time. + if("ASSAULT0") + spawn(0) + M.close() + if("ASSAULT1") + spawn(0) + M.close() + if("ASSAULT2") + spawn(0) + M.close() + if("ASSAULT3") + spawn(0) + M.close() + special_ops.readyreset()//Reset firealarm after the team launched. + //End Marauder launchpad. \ No newline at end of file diff --git a/code/modules/shuttles/shuttle_supply.dm b/code/modules/shuttles/shuttle_supply.dm new file mode 100644 index 00000000..7221cdb7 --- /dev/null +++ b/code/modules/shuttles/shuttle_supply.dm @@ -0,0 +1,77 @@ +/datum/shuttle/autodock/ferry/supply + var/away_location = 1 //the location to hide at while pretending to be in-transit + var/late_chance = 80 + var/max_late_time = (30 SECONDS) + flags = SHUTTLE_FLAGS_PROCESS|SHUTTLE_FLAGS_SUPPLY + category = /datum/shuttle/autodock/ferry/supply + +/datum/shuttle/autodock/ferry/supply/short_jump(var/area/destination) + if(moving_status != SHUTTLE_IDLE) + return + + if(isnull(location)) + return + + //it would be cool to play a sound here + moving_status = SHUTTLE_WARMUP + spawn(warmup_time*10) + if (moving_status == SHUTTLE_IDLE) + return //someone cancelled the launch + + if (at_station() && forbidden_atoms_check()) + //cancel the launch because of forbidden atoms. announce over supply channel? + moving_status = SHUTTLE_IDLE + return + + if (!at_station()) //at centcom + supply_controller.buy() + + //We pretend it's a long_jump by making the shuttle stay at centcom for the "in-transit" period. + var/obj/effect/shuttle_landmark/away_waypoint = get_location_waypoint(away_location) + moving_status = SHUTTLE_INTRANSIT + + //If we are at the away_landmark then we are just pretending to move, otherwise actually do the move + if (next_location == away_waypoint) + attempt_move(away_waypoint) + + //wait ETA here. + arrive_time = world.time + supply_controller.movetime + while (world.time <= arrive_time) + sleep(5) + + if (next_location != away_waypoint) + //late + if (prob(late_chance)) + sleep(rand(0,max_late_time)) + + attempt_move(destination) + + moving_status = SHUTTLE_IDLE + + if (!at_station()) //at centcom + supply_controller.sell() + +// returns 1 if the supply shuttle should be prevented from moving because it contains forbidden atoms +/datum/shuttle/autodock/ferry/supply/proc/forbidden_atoms_check() + if (!at_station()) + return 0 //if badmins want to send forbidden atoms on the supply shuttle from centcom we don't care + + for(var/area/A in shuttle_area) + if(supply_controller.forbidden_atoms_check(A)) + return 1 + +/datum/shuttle/autodock/ferry/supply/proc/at_station() + return (!location) + +//returns 1 if the shuttle is idle and we can still mess with the cargo shopping list +/datum/shuttle/autodock/ferry/supply/proc/idle() + return (moving_status == SHUTTLE_IDLE) + +//returns the ETA in minutes +/datum/shuttle/autodock/ferry/supply/proc/eta_minutes() + var/ticksleft = arrive_time - world.time + return max(0, round(ticksleft/600,1)) + +/datum/shuttle/autodock/ferry/supply/proc/eta_seconds() + var/ticksleft = arrive_time - world.time + return max(0, round(ticksleft/10,1)) diff --git a/code/modules/shuttles/shuttles_multi.dm b/code/modules/shuttles/shuttles_multi.dm new file mode 100644 index 00000000..5c236a8b --- /dev/null +++ b/code/modules/shuttles/shuttles_multi.dm @@ -0,0 +1,68 @@ +/datum/shuttle/autodock/multi + var/list/destination_tags + var/list/destinations_cache = list() + var/last_cache_rebuild_time = 0 + category = /datum/shuttle/autodock/multi + +/datum/shuttle/autodock/multi/proc/set_destination(var/destination_key, mob/user) + if(moving_status != SHUTTLE_IDLE) + return + next_location = destinations_cache[destination_key] + +/datum/shuttle/autodock/multi/proc/get_destinations() + if (last_cache_rebuild_time < shuttle_controller.last_landmark_registration_time) + build_destinations_cache() + return destinations_cache + +/datum/shuttle/autodock/multi/proc/build_destinations_cache() + last_cache_rebuild_time = world.time + destinations_cache.Cut() + for(var/destination_tag in destination_tags) + var/obj/effect/shuttle_landmark/landmark = shuttle_controller.get_landmark(destination_tag) + if (istype(landmark)) + destinations_cache["[landmark.name]"] = landmark + +//Antag play announcements when they leave/return to their home area +/datum/shuttle/autodock/multi/antag + warmup_time = 10 SECONDS //replaced the old move cooldown + + var/obj/effect/shuttle_landmark/home_waypoint + + var/cloaked = 1 + var/announcer + var/arrival_message + var/departure_message + var/return_warning = 0 + + category = /datum/shuttle/autodock/multi/antag + +/datum/shuttle/autodock/multi/antag/New() + ..() + if(home_waypoint) + home_waypoint = locate(home_waypoint) + else + home_waypoint = current_location + +/datum/shuttle/autodock/multi/antag/shuttle_moved() + if(current_location == home_waypoint) + announce_arrival() + else if(next_location == home_waypoint) + announce_departure() + ..() + +/datum/shuttle/autodock/multi/antag/proc/announce_departure() + if(cloaked || isnull(departure_message)) + return + command_announcement.Announce(departure_message, announcer || "[GLOB.using_map.boss_name]") + +/datum/shuttle/autodock/multi/antag/proc/announce_arrival() + if(cloaked || isnull(arrival_message)) + return + command_announcement.Announce(arrival_message, announcer || "[GLOB.using_map.boss_name]") + +/datum/shuttle/autodock/multi/antag/set_destination(var/destination_key, mob/user) + if(!return_warning && destination_key == home_waypoint.name) + to_chat(user, "Returning to your home base will end your mission. If you are sure, press the button again.") + return_warning = 1 + return + ..() diff --git a/code/modules/spells/aoe_turf/aoe_turf.dm b/code/modules/spells/aoe_turf/aoe_turf.dm new file mode 100644 index 00000000..9f79f694 --- /dev/null +++ b/code/modules/spells/aoe_turf/aoe_turf.dm @@ -0,0 +1,25 @@ +/* +Aoe turf spells target a ring of tiles around the user +This ring has an outer radius (range) and an inner radius (inner_radius) +Aoe turf spells have two useful flags: IGNOREDENSE and IGNORESPACE. These are explained in setup.dm +*/ + +/spell/aoe_turf //affects all turfs in view or range (depends) + spell_flags = IGNOREDENSE + var/inner_radius = -1 //for all your ring spell needs + +/spell/aoe_turf/choose_targets(mob/user = usr) + var/list/targets = list() + + for(var/turf/target in view_or_range(range, holder, selection_type)) + if(!(target in view_or_range(inner_radius, holder, selection_type))) + if(target.density && (spell_flags & IGNOREDENSE)) + continue + if(istype(target, /turf/space) && (spell_flags & IGNORESPACE)) + continue + targets += target + + if(!targets.len) //doesn't waste the spell + return + + return targets \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/blink.dm b/code/modules/spells/aoe_turf/blink.dm new file mode 100644 index 00000000..b6a9ca8d --- /dev/null +++ b/code/modules/spells/aoe_turf/blink.dm @@ -0,0 +1,43 @@ +/spell/aoe_turf/blink + name = "Blink" + desc = "This spell randomly teleports you a short distance." + feedback = "BL" + school = "conjuration" + charge_max = 20 + spell_flags = Z2NOCAST | IGNOREDENSE | IGNORESPACE + invocation = "none" + invocation_type = SpI_NONE + range = 7 + inner_radius = 1 + + level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 4) + cooldown_min = 5 //4 deciseconds reduction per rank + hud_state = "wiz_blink" + +/spell/aoe_turf/blink/cast(var/list/targets, mob/user) + if(!targets.len) + return + + var/turf/T = pick(targets) + var/turf/starting = get_turf(user) + if(T) + if(user.buckled) + user.buckled = null + user.forceMove(T) + + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() + smoke.set_up(3, 0, starting) + smoke.start() + + smoke = new() + smoke.set_up(3, 0, T) + smoke.start() + + return + +/spell/aoe_turf/blink/empower_spell() + if(!..()) + return 0 + inner_radius += 1 + + return "You've increased the inner range of [src]." \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/charge.dm b/code/modules/spells/aoe_turf/charge.dm new file mode 100644 index 00000000..1e75568d --- /dev/null +++ b/code/modules/spells/aoe_turf/charge.dm @@ -0,0 +1,71 @@ +/spell/aoe_turf/charge + name = "Charge" + desc = "This spell can be used to charge up spent magical artifacts, among other things." + + school = "transmutation" + charge_max = 600 + spell_flags = 0 + invocation = "DIRI CEL" + invocation_type = SpI_WHISPER + range = 0 + cooldown_min = 400 //50 deciseconds reduction per rank + + hud_state = "wiz_charge" + +/spell/aoe_turf/charge/cast(var/list/targets, mob/user) + for(var/turf/T in targets) + depth_cast(T) + +/spell/aoe_turf/charge/proc/depth_cast(var/list/targets) + for(var/atom/A in targets) + if(A.contents.len) + depth_cast(A.contents) + cast_charge(A) + +/spell/aoe_turf/charge/proc/mob_charge(var/mob/living/M) + if(!M.mind) + return + if(M.mind.learned_spells.len != 0) + for(var/spell/S in M.mind.learned_spells) + if(!istype(S, /spell/aoe_turf/charge)) + S.charge_counter = S.charge_max + to_chat(M, "You feel raw magic flowing through you, it feels good!") + else + to_chat(M, "You feel very strange for a moment, but then it passes.") + return M + +/spell/aoe_turf/charge/proc/cast_charge(var/atom/target) + var/atom/charged_item + + if(istype(target, /mob/living)) + charged_item = mob_charge(target) + + if(istype(target, /obj/item/grab)) + var/obj/item/grab/G = target + if(G.affecting) + var/mob/M = G.affecting + charged_item = mob_charge(M) + + if(istype(target, /obj/item/weapon/cell/)) + var/obj/item/weapon/cell/C = target + if(prob(80) && C.maxcharge) + C.maxcharge -= 200 + if(C.maxcharge <= 0) //maxcharge of 0! Madness! + C.maxcharge = 0 + C.charge = C.maxcharge + charged_item = C + + if(!charged_item) + return 0 + else + charged_item.visible_message("[charged_item] suddenly sparks with energy!") + return 1 + + +/spell/aoe_turf/charge/blood + name = "blood charge" + desc = "This spell charges things around it using the lifeforce gained by sacrificed blood." + + charge_type = Sp_HOLDVAR + holder_var_type = "bruteloss" + holder_var_amount = 30 \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/conjure.dm b/code/modules/spells/aoe_turf/conjure/conjure.dm new file mode 100644 index 00000000..9185b880 --- /dev/null +++ b/code/modules/spells/aoe_turf/conjure/conjure.dm @@ -0,0 +1,76 @@ +/* +Conjure spells spawn things (mobs, objs, turfs) in their summon_type +How they spawn stuff is decided by behaviour vars, which are explained below +*/ + +/spell/aoe_turf/conjure + name = "Conjure" + desc = "This spell conjures objs of the specified types in range." + + school = "conjuration" //funny, that + + var/list/summon_type = list() //determines what exactly will be summoned + //should NOT be text, like list(/obj/machinery/bot/ed209) + + range = 0 //default values: only spawn on the player tile + selection_type = "view" + + duration = 0 // 0=permanent, any other time in deciseconds - how long the summoned objects last for + var/summon_amt = 1 //amount of objects summoned + var/summon_exclusive = 0 //spawn one of everything, instead of random things + + var/list/newVars = list() //vars of the summoned objects will be replaced with those where they meet + //should have format of list("emagged" = 1,"name" = "Wizard's Justicebot"), for example + + cast_sound = 'sound/items/welder.ogg' + +/spell/aoe_turf/conjure/cast(list/targets, mob/user) + + for(var/i=1,i <= summon_amt,i++) + if(!targets.len) + break + var/summoned_object_type + if(summon_exclusive) + if(!summon_type.len) + break + summoned_object_type = summon_type[1] + summon_type -= summoned_object_type + else + summoned_object_type = pick(summon_type) + var/turf/spawn_place = pick(targets) + if(spell_flags & IGNOREPREV) + targets -= spawn_place + + var/atom/summoned_object + if(ispath(summoned_object_type,/turf)) + if(istype(get_turf(user),/turf/simulated/shuttle) || istype(spawn_place, /turf/simulated/shuttle)) + to_chat(user, "You can't build things on shuttles!") + continue + spawn_place.ChangeTurf(summoned_object_type) + summoned_object = spawn_place + else + summoned_object = new summoned_object_type(spawn_place) + var/atom/movable/overlay/animation = new /atom/movable/overlay(spawn_place) + animation.SetName("conjure") + animation.set_density(0) + animation.anchored = 1 + animation.icon = 'icons/effects/effects.dmi' + animation.plane = HUMAN_PLANE + animation.layer = BASE_MOB_LAYER + animation.master = summoned_object + if(istype(summoned_object,/mob)) //we want them to NOT attack us. + var/mob/M = summoned_object + M.faction = user.faction + for(var/varName in newVars) + if(varName in summoned_object.vars) + summoned_object.vars[varName] = newVars[varName] + + if(duration) + spawn(duration) + if(summoned_object && !istype(summoned_object, /turf)) + qdel(summoned_object) + conjure_animation(animation, spawn_place) + return + +/spell/aoe_turf/conjure/proc/conjure_animation(var/atom/movable/overlay/animation, var/turf/target) + qdel(animation) \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/construct.dm b/code/modules/spells/aoe_turf/conjure/construct.dm new file mode 100644 index 00000000..9c802aee --- /dev/null +++ b/code/modules/spells/aoe_turf/conjure/construct.dm @@ -0,0 +1,122 @@ +//////////////////////////////Construct Spells///////////////////////// + +/spell/aoe_turf/conjure/construct + name = "Artificer" + desc = "This spell conjures a construct which may be controlled by Shades." + + school = "conjuration" + charge_max = 600 + spell_flags = 0 + invocation = "none" + invocation_type = SpI_NONE + range = 0 + + summon_type = list(/obj/structure/constructshell) + + hud_state = "artificer" + +/spell/aoe_turf/conjure/construct/lesser + charge_max = 1800 + summon_type = list(/obj/structure/constructshell/cult) + hud_state = "const_shell" + override_base = "const" + +/spell/aoe_turf/conjure/floor + name = "Floor Construction" + desc = "This spell constructs a cult floor" + + charge_max = 20 + spell_flags = Z2NOCAST | CONSTRUCT_CHECK + invocation = "none" + invocation_type = SpI_NONE + range = 0 + summon_type = list(/turf/simulated/floor/cult) + + hud_state = "const_floor" + +/spell/aoe_turf/conjure/wall + name = "Lesser Construction" + desc = "This spell constructs a cult wall" + + charge_max = 100 + spell_flags = Z2NOCAST | CONSTRUCT_CHECK + invocation = "none" + invocation_type = SpI_NONE + range = 0 + summon_type = list(/turf/simulated/wall/cult) + + hud_state = "const_wall" + +/spell/aoe_turf/conjure/wall/reinforced + name = "Greater Construction" + desc = "This spell constructs a reinforced metal wall" + + charge_max = 300 + spell_flags = Z2NOCAST + invocation = "none" + invocation_type = SpI_NONE + range = 0 + cast_delay = 50 + + summon_type = list(/turf/simulated/wall/r_wall) + +/spell/aoe_turf/conjure/soulstone + name = "Summon Soulstone" + desc = "This spell reaches into Nar-Sie's realm, summoning one of the legendary fragments across time and space" + + charge_max = 3000 + spell_flags = 0 + invocation = "none" + invocation_type = SpI_NONE + range = 0 + + summon_type = list(/obj/item/device/soulstone) + + hud_state = "const_stone" + override_base = "const" + +/spell/aoe_turf/conjure/pylon + name = "Red Pylon" + desc = "This spell conjures a fragile crystal from Nar-Sie's realm. Makes for a convenient light source." + + charge_max = 200 + spell_flags = CONSTRUCT_CHECK + invocation = "none" + invocation_type = SpI_NONE + range = 0 + + summon_type = list(/obj/structure/cult/pylon) + + hud_state = "const_pylon" + +/spell/aoe_turf/conjure/pylon/cast(list/targets) + ..() + var/turf/spawn_place = pick(targets) + for(var/obj/structure/cult/pylon/P in spawn_place.contents) + if(P.isbroken) + P.repair(usr) + continue + return + +/spell/aoe_turf/conjure/forcewall/lesser + name = "Shield" + desc = "Allows you to pull up a shield to protect yourself and allies from incoming threats" + + charge_max = 300 + spell_flags = 0 + invocation = "none" + invocation_type = SpI_NONE + range = 0 + summon_type = list(/obj/effect/forcefield/cult) + duration = 200 + + hud_state = "const_juggwall" + +//Code for the Juggernaut construct's forcefield, that seemed like a good place to put it. +/obj/effect/forcefield/cult + desc = "That eerie looking obstacle seems to have been pulled from another dimension through sheer force." + name = "Juggerwall" + icon = 'icons/effects/effects.dmi' + icon_state = "m_shield_cult" + light_color = "#b40000" + light_range = 2 \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/druidic_spells.dm b/code/modules/spells/aoe_turf/conjure/druidic_spells.dm new file mode 100644 index 00000000..70a37798 --- /dev/null +++ b/code/modules/spells/aoe_turf/conjure/druidic_spells.dm @@ -0,0 +1,109 @@ +/spell/aoe_turf/conjure/summon + var/name_summon = 0 + cast_sound = 'sound/weapons/wave.ogg' + +/spell/aoe_turf/conjure/summon/before_cast() + ..() + if(name_summon) + var/newName = sanitize(input("Would you like to name your summon?") as null|text, MAX_NAME_LEN) + if(newName) + newVars["name"] = newName + +/spell/aoe_turf/conjure/summon/conjure_animation(var/atom/movable/overlay/animation, var/turf/target) + animation.icon_state = "shield2" + flick("shield2",animation) + sleep(10) + ..() + + +/spell/aoe_turf/conjure/summon/bats + name = "Summon Space Bats" + desc = "This spell summons a flock of spooky space bats." + feedback = "SB" + + charge_max = 1200 //2 minutes + spell_flags = NEEDSCLOTHES + invocation = "Bla'yo daya!" + invocation_type = SpI_SHOUT + level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 3) + cooldown_min = 600 + + range = 1 + + summon_amt = 1 + summon_type = list(/mob/living/simple_animal/hostile/scarybat) + + hud_state = "wiz_bats" + +/spell/aoe_turf/conjure/summon/bats/empower_spell() + if(!..()) + return 0 + + newVars = list("maxHealth" = 20 + spell_levels[Sp_POWER]*5, "health" = 20 + spell_levels[Sp_POWER]*5, "melee_damage_lower" = 10 + spell_levels[Sp_POWER], "melee_damage_upper" = 10 + spell_levels[Sp_POWER]*2) + + return "Your bats are now stronger." + +/spell/aoe_turf/conjure/summon/bear + name = "Summon Bear" + desc = "This spell summons a permanent bear companion that will follow your orders." + feedback = "BR" + charge_max = 3000 //5 minutes because this is a REALLY powerful spell. May tone it down/up. + spell_flags = NEEDSCLOTHES + invocation = "REA'YO GOR DAYA!" + invocation_type = SpI_SHOUT + level_max = list(Sp_TOTAL = 4, Sp_SPEED = 0, Sp_POWER = 4) + + range = 0 + + name_summon = 1 + + summon_amt = 1 + summon_type = list(/mob/living/simple_animal/hostile/commanded/bear) + newVars = list("maxHealth" = 15, + "health" = 15, + "melee_damage_lower" = 10, + "melee_damage_upper" = 10, + ) + + hud_state = "wiz_bear" + +/spell/aoe_turf/conjure/summon/bear/before_cast() + ..() + newVars["master"] = holder //why not do this in the beginning? MIND SWITCHING. + +/spell/aoe_turf/conjure/summon/bear/empower_spell() + if(!..()) + return 0 + switch(spell_levels[Sp_POWER]) + if(1) + newVars = list("maxHealth" = 30, + "health" = 30, + "melee_damage_lower" = 15, + "melee_damage_upper" = 15 + ) + return "Your bear has been upgraded from a cub to a whelp." + if(2) + newVars = list("maxHealth" = 45, + "health" = 45, + "melee_damage_lower" = 20, + "melee_damage_upper" = 20, + "color" = "#d9d9d9" //basically we want them to look different enough that people can recognize it. + ) + return "Your bear has been upgraded from a whelp to an adult." + if(3) + newVars = list("maxHealth" = 60, + "health" = 60, + "melee_damage_lower" = 25, + "melee_damage_upper" = 25, + "color" = "#8c8c8c" + ) + return "Your bear has been upgraded from an adult to an alpha." + if(4) + newVars = list("maxHealth" = 75, + "health" = 75, + "melee_damage_lower" = 35, + "melee_damage_upper" = 35, + "resistance" = 3, + "color" = "#0099ff" + ) + return "Your bear is now worshiped as a god amongst bears." \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/faithful_hound.dm b/code/modules/spells/aoe_turf/conjure/faithful_hound.dm new file mode 100644 index 00000000..b25be6d1 --- /dev/null +++ b/code/modules/spells/aoe_turf/conjure/faithful_hound.dm @@ -0,0 +1,19 @@ +/spell/aoe_turf/conjure/faithful_hound + name = "Faithful Hound" + desc = "Summon a spectral watchdog with a special password. Anyone without the password is in for a barking and a biting." + feedback = "FH" + + charge_max = 600 + spell_flags = NEEDSCLOTHES + invocation = "Du korilath tangus" + invocation_type = SpI_WHISPER + range = 0 + + summon_amt = 1 + summon_type = list(/mob/living/simple_animal/faithful_hound) + hud_state = "wiz_hound" + +/spell/aoe_turf/conjure/faithful_hound/before_cast() + ..() + var/password = sanitize(input("What password will this beast listen to?") as text, MAX_NAME_LEN) + newVars = list("password" = password, "allowed_mobs" = list(usr)) \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/force_portal.dm b/code/modules/spells/aoe_turf/conjure/force_portal.dm new file mode 100644 index 00000000..867205b9 --- /dev/null +++ b/code/modules/spells/aoe_turf/conjure/force_portal.dm @@ -0,0 +1,12 @@ +/spell/aoe_turf/conjure/force_portal + name = "Force Portal" + desc = "Create a portal that sucks in anything that touches it and then shoots it all out at the end.." + school = "conjuration" + feedback = "FP" + summon_type = list(/obj/effect/force_portal) + charge_max = 200 + spell_flags = NEEDSCLOTHES + range = 0 + cast_sound = null + + hud_state = "wiz_force" \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/forcewall.dm b/code/modules/spells/aoe_turf/conjure/forcewall.dm new file mode 100644 index 00000000..4f8795b9 --- /dev/null +++ b/code/modules/spells/aoe_turf/conjure/forcewall.dm @@ -0,0 +1,49 @@ +/spell/aoe_turf/conjure/forcewall + name = "Forcewall" + desc = "Create a wall of pure energy at your location." + school = "conjuration" + feedback = "FW" + summon_type = list(/obj/effect/forcefield) + duration = 300 + charge_max = 100 + spell_flags = 0 + range = 0 + cast_sound = null + + hud_state = "wiz_shield" + +/spell/aoe_turf/conjure/forcewall/mime + name = "Invisible wall" + desc = "Create an invisible wall on your location." + school = "mime" + panel = "Mime" + summon_type = list(/obj/effect/forcefield/mime) + invocation_type = SpI_EMOTE + invocation = "mimes placing their hands on a flat surfacing, and pushing against it." + charge_max = 300 + cast_sound = null + + override_base = "grey" + hud_state = "mime_wall" + +/obj/effect/forcefield + desc = "A space wizard's magic wall." + name = "FORCEWALL" + icon = 'icons/effects/effects.dmi' + icon_state = "m_shield" + anchored = 1.0 + opacity = 0 + density = 1 + unacidable = 1 + +/obj/effect/forcefield/bullet_act(var/obj/item/projectile/Proj, var/def_zone) + var/turf/T = get_turf(src.loc) + if(T) + for(var/mob/M in T) + Proj.on_hit(M,M.bullet_act(Proj, def_zone)) + return + +/obj/effect/forcefield/mime + icon_state = "empty" + name = "invisible wall" + desc = "You have a bad feeling about this." \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/grove.dm b/code/modules/spells/aoe_turf/conjure/grove.dm new file mode 100644 index 00000000..20d3534d --- /dev/null +++ b/code/modules/spells/aoe_turf/conjure/grove.dm @@ -0,0 +1,74 @@ +/spell/aoe_turf/conjure/grove + name = "Grove" + desc = "Creates a sanctuary of nature around the wizard as well as creating a healing plant." + + spell_flags = IGNOREDENSE | IGNORESPACE | NEEDSCLOTHES | Z2NOCAST | IGNOREPREV + charge_max = 1200 + school = "transmutation" + + range = 1 + cooldown_min = 600 + + level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 1) + + summon_amt = 47 + summon_type = list(/turf/simulated/floor/grass) + var/spread = 0 + var/datum/seed/seed + var/seed_type = /datum/seed/merlin_tear + +/spell/aoe_turf/conjure/grove/New() + ..() + if(seed_type) + seed = new seed_type() + else + seed = plant_controller.create_random_seed(1) + +/spell/aoe_turf/conjure/grove/before_cast() + var/turf/T = get_turf(holder) + var/obj/effect/vine/P = new(T,seed) + P.spread_chance = spread + + +/spell/aoe_turf/conjure/grove/sanctuary + name = "Sanctuary" + desc = "Creates a sanctuary of nature around the wizard as well as creating a healing plant." + feedback = "SY" + invocation = "Bo K'Iitan!" + invocation_type = SpI_SHOUT + spell_flags = IGNOREDENSE | IGNORESPACE | NEEDSCLOTHES | Z2NOCAST | IGNOREPREV + cooldown_min = 600 + + level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 1) + + seed_type = /datum/seed/merlin_tear + newVars = list("name" = "sanctuary", "desc" = "This grass makes you feel comfortable. Peaceful.","blessed" = 1) + + hud_state = "wiz_grove" +/spell/aoe_turf/conjure/grove/sanctuary/empower_spell() + if(!..()) + return 0 + + seed.set_trait(TRAIT_SPREAD,2) //make it grow. + spread = 40 + return "Your sanctuary will now grow beyond that of the grassy perimeter." + +/datum/seed/merlin_tear + name = "merlin tears" + seed_name = "merlin tears" + display_name = "merlin tears" + chems = list(/datum/reagent/bicaridine = list(3,7), /datum/reagent/dermaline = list(3,7), /datum/reagent/dylovene = list(3,7), /datum/reagent/tricordrazine = list(3,7), /datum/reagent/alkysine = list(1,2), /datum/reagent/imidazoline = list(1,2), /datum/reagent/peridaxon = list(4,5)) + kitchen_tag = "berries" + +/datum/seed/merlin_tear/New() + ..() + set_trait(TRAIT_PLANT_ICON,"bush5") + set_trait(TRAIT_PRODUCT_ICON,"berry") + set_trait(TRAIT_PRODUCT_COLOUR,"#4d4dff") + set_trait(TRAIT_PLANT_COLOUR, "#ff6600") + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_IMMUTABLE,1) //no making op plants pls \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/disable_tech.dm b/code/modules/spells/aoe_turf/disable_tech.dm new file mode 100644 index 00000000..5a58bd1c --- /dev/null +++ b/code/modules/spells/aoe_turf/disable_tech.dm @@ -0,0 +1,32 @@ +/spell/aoe_turf/disable_tech + name = "Disable Tech" + desc = "This spell disables all weapons, cameras and most other technology in range." + feedback = "DT" + charge_max = 400 + spell_flags = NEEDSCLOTHES + invocation = "NEC CANTIO" + invocation_type = SpI_SHOUT + selection_type = "range" + range = 0 + inner_radius = -1 + level_max = list(Sp_TOTAL = 2, Sp_SPEED = 2, Sp_POWER = 2) + cooldown_min = 200 //50 deciseconds reduction per rank + + var/emp_heavy = 3 + var/emp_light = 5 + + hud_state = "wiz_tech" + +/spell/aoe_turf/disable_tech/cast(list/targets) + + for(var/turf/target in targets) + empulse(get_turf(target), emp_heavy, emp_light) + return + +/spell/aoe_turf/disable_tech/empower_spell() + if(!..()) + return 0 + emp_heavy += 2 + emp_light += 2 + + return "You've increased the range of [src]." \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/drain_blood.dm b/code/modules/spells/aoe_turf/drain_blood.dm new file mode 100644 index 00000000..3cc3a3a8 --- /dev/null +++ b/code/modules/spells/aoe_turf/drain_blood.dm @@ -0,0 +1,66 @@ +/spell/aoe_turf/drain_blood + name = "Drain Blood" + desc = "this spell allows the caster to borrow blood from those around them. Sharing is caring!" + feedback = "DB" + school = "transmutation" + charge_max = 600 + invocation = "whispers something darkly" + invocation_type = SpI_EMOTE + range = 3 + inner_radius = 0 + + time_between_channels = 100 + number_of_channels = 3 + cast_sound = 'sound/effects/squelch2.ogg' + hud_state = "const_rune" + +/spell/aoe_turf/drain_blood/cast(var/list/targets, var/mob/user) + for(var/t in targets) + for(var/mob/living/L in t) + if(L.stat == DEAD || L == user) + continue + //Hurt target + if(istype(L, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = L + H.vessel.remove_reagent(/datum/reagent/blood, 10) + else + L.adjustBruteLoss(10) + to_chat(L, "You feel your lifeforce being ripping out of your body!") + + //Do effect + var/obj/item/projectile/beam/blood_effect/effect = new(get_turf(user)) + effect.pixel_x = 0 + effect.pixel_y = 0 + effect.launch_projectile(L, "chest") + + //Heal self + if(istype(user, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + var/amount = min(10, H.species.blood_volume - H.vessel.total_volume) + if(amount > 0) + H.vessel.add_reagent(/datum/reagent/blood, amount) + continue + L.adjustBruteLoss(-5) + L.adjustFireLoss(-2.5) + L.adjustToxLoss(-2.5) + +/obj/item/projectile/beam/blood_effect + name = "blood jet" + icon_state = "blood" + damage = 0 + randpixel = 0 + no_attack_log = 1 + muzzle_type = /obj/effect/projectile/blood + tracer_type = /obj/effect/projectile/blood + impact_type = /obj/effect/projectile/blood + +/obj/item/projectile/beam/blood_effect/Bump(var/atom/a) + if(a == original) + on_impact(a) + qdel(src) + return 1 + return 0 + + +/obj/effect/projectile/blood + icon_state = "blood" \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/knock.dm b/code/modules/spells/aoe_turf/knock.dm new file mode 100644 index 00000000..56a13d36 --- /dev/null +++ b/code/modules/spells/aoe_turf/knock.dm @@ -0,0 +1,32 @@ +/spell/aoe_turf/knock + name = "Knock" + desc = "This spell opens nearby doors and does not require wizard garb." + feedback = "KN" + school = "transmutation" + charge_max = 100 + spell_flags = 0 + invocation = "Aulie Oxin Fiera." + invocation_type = SpI_WHISPER + range = 3 + level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 1) + cooldown_min = 20 //20 deciseconds reduction per rank + + hud_state = "wiz_knock" + +/spell/aoe_turf/knock/cast(list/targets) + for(var/turf/T in targets) + for(var/obj/machinery/door/door in T.contents) + spawn(1) + if(istype(door,/obj/machinery/door/airlock)) + var/obj/machinery/door/airlock/AL = door //casting is important + AL.locked = 0 + door.open() + return + + +/spell/aoe_turf/knock/empower_spell() + if(!..()) + return 0 + range *= 2 + + return "You've doubled the range of [src]." \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/smoke.dm b/code/modules/spells/aoe_turf/smoke.dm new file mode 100644 index 00000000..920197cd --- /dev/null +++ b/code/modules/spells/aoe_turf/smoke.dm @@ -0,0 +1,25 @@ +/spell/aoe_turf/smoke + name = "Smoke" + desc = "This spell spawns a cloud of choking smoke at your location and does not require wizard garb." + feedback = "SM" + school = "transmutation" + charge_max = 120 + spell_flags = 0 + invocation = "none" + invocation_type = SpI_NONE + range = 1 + inner_radius = -1 + level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 2) + cooldown_min = 20 //25 deciseconds reduction per rank + + smoke_spread = 2 + smoke_amt = 5 + + hud_state = "wiz_smoke" + +/spell/aoe_turf/smoke/empower_spell() + if(!..()) + return 0 + smoke_amt += 2 + + return "[src] will now create more smoke." \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/summons.dm b/code/modules/spells/aoe_turf/summons.dm new file mode 100644 index 00000000..73f69ec2 --- /dev/null +++ b/code/modules/spells/aoe_turf/summons.dm @@ -0,0 +1,70 @@ +/spell/aoe_turf/conjure/summonEdSwarm //test purposes + name = "Dispense Wizard Justice" + desc = "This spell dispenses wizard justice." + + summon_type = list(/mob/living/bot/secbot/ed209) + summon_amt = 10 + range = 3 + newVars = list("emagged" = 1,"name" = "Wizard's Justicebot") + + hud_state = "wiz_ed" + +/spell/aoe_turf/conjure/carp + name = "Summon Carp" + desc = "This spell conjures a simple carp." + + school = "conjuration" + charge_max = 1200 + spell_flags = NEEDSCLOTHES + invocation = "Nouk Fhumm Sacp Risska!" + invocation_type = SpI_SHOUT + range = 1 + + summon_type = list(/mob/living/simple_animal/hostile/carp) + + hud_state = "wiz_carp" + +/spell/aoe_turf/conjure/creature + name = "Summon Creature Swarm" + desc = "This spell tears the fabric of reality, allowing horrific daemons to spill forth" + + school = "conjuration" + charge_max = 1200 + spell_flags = 0 + invocation = "Ia-Ia! Naomesnalia!" + invocation_type = SpI_SHOUT + summon_amt = 10 + range = 3 + + summon_type = list(/mob/living/simple_animal/hostile/creature) + + hud_state = "wiz_creature" + +/spell/aoe_turf/conjure/mirage + name = "Summon Mirage" + desc = "This spell summons a harmless carp mirage for a few seconds." + feedback = "MR" + school = "illusion" + charge_max = 1200 + spell_flags = NEEDSCLOTHES + invocation = "Nouk Fhunhm Sacp Risska!" + invocation_type = SpI_SHOUT + range = 1 + + duration = 600 + cooldown_min = 600 + level_max = list(Sp_TOTAL = 4, Sp_SPEED = 2, Sp_POWER = 3) + + summon_type = list(/mob/living/simple_animal/hostile/carp) + + hud_state = "wiz_carp" + + newVars = list("melee_damage_lower" = 0, "melee_damage_upper" = 0, "break_stuff_probability" = 0) + +/spell/aoe_turf/conjure/mirage/empower_spell() + if(!..()) + return 0 + + summon_amt++ + + return "You now summon [summon_amt] mirages per spellcast." \ No newline at end of file diff --git a/code/modules/spells/artifacts.dm b/code/modules/spells/artifacts.dm new file mode 100644 index 00000000..aa6712fc --- /dev/null +++ b/code/modules/spells/artifacts.dm @@ -0,0 +1,38 @@ +//////////////////////Scrying orb////////////////////// + +/obj/item/weapon/scrying + name = "scrying orb" + desc = "An incandescent orb of otherworldly energy, staring into it gives you vision beyond mortal means." + icon = 'icons/obj/projectiles.dmi' + icon_state = "bluespace" + throw_speed = 3 + throw_range = 7 + throwforce = 10 + damtype = BURN + force = 10 + hitsound = 'sound/items/welder2.ogg' + +/obj/item/weapon/scrying/attack_self(mob/user as mob) + if((user.mind && !wizards.is_antagonist(user.mind))) + to_chat(user, "You stare into the orb and see nothing but your own reflection.") + return + + to_chat(user, "You can see... everything!") // This never actually happens. + visible_message("[user] stares into [src], their eyes glazing over.") + + user.teleop = user.ghostize(1) + announce_ghost_joinleave(user.teleop, 1, "You feel that they used a powerful artifact to [pick("invade","disturb","disrupt","infest","taint","spoil","blight")] this place with their presence.") + return + + + +/////////////////////////Cursed Dice/////////////////////////// +/obj/item/weapon/dice/d20/cursed + desc = "A dice with twenty sides said to have an ill effect on those that are unlucky..." + +/obj/item/weapon/dice/d20/cursed/attack_self(mob/living/user) + ..() + if(icon_state == "[name][sides]") + user.adjustBruteLoss(-30) + else if(icon_state == "[name]1") + user.adjustBruteLoss(30) \ No newline at end of file diff --git a/code/modules/spells/artifacts/monster_manual.dm b/code/modules/spells/artifacts/monster_manual.dm new file mode 100644 index 00000000..ae89020b --- /dev/null +++ b/code/modules/spells/artifacts/monster_manual.dm @@ -0,0 +1,77 @@ +/obj/item/weapon/monster_manual + name = "monster manual" + desc = "A book detailing various magical creatures." + icon = 'icons/obj/library.dmi' + icon_state = "bookHacking" + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_SMALL + var/uses = 1 + var/temp = null + var/list/monster = list(/mob/living/simple_animal/familiar/pet/cat, + /mob/living/simple_animal/familiar/pet/mouse, + /mob/living/simple_animal/familiar/carcinus, + /mob/living/simple_animal/familiar/horror, + /mob/living/simple_animal/familiar/minor_amaros, + /mob/living/simple_animal/familiar/pike + ) + var/list/monster_info = list( "It is well known that the blackest of cats make good familiars.", + "Mice are full of mischief and magic. A simple animal, yes, but one of the wizard's finest.", + "A mortal decendant of the original Carcinus, it is said their shells are near impenetrable and their claws as sharp as knives.", + "The physical embodiment of flesh and decay, its made from the reanimated corpse of a murdered man.", + "A small magical creature known for its healing powers and pacifist ways.", + "The more carnivorous and knowledge hungry cousin of the Space Carp. Keep away from books." + ) + +/obj/item/weapon/monster_manual/attack_self(mob/user as mob) + user.set_machine(src) + interact(user) + +/obj/item/weapon/monster_manual/interact(mob/user as mob) + var/dat + if(temp) + dat = "[temp]
                Return" + else + dat = "

                Monster Manual

                You have [uses] uses left.
                " + for(var/i=1;i<=monster_info.len;i++) + var/mob/M = monster[i] + var/name = capitalize(initial(M.name)) + dat += "
                [name] - [monster_info[i]]
                " + user << browse(dat,"window=monstermanual") + onclose(user,"monstermanual") + +/obj/item/weapon/monster_manual/OnTopic(user, href_list, state) + if(href_list["temp"]) + temp = null + . = TOPIC_REFRESH + else if(href_list["path"]) + if(uses == 0) + to_chat(user, "This book is out of uses.") + return TOPIC_HANDLED + + var/datum/ghosttrap/ghost = get_ghost_trap("wizard familiar") + var path = locate(href_list["path"]) in monster + if(!ispath(path)) + crash_with("Invalid mob path in [src]. Contact a coder.") + return TOPIC_HANDLED + + var/mob/living/simple_animal/familiar/F = new path(get_turf(src)) + temp = "You have attempted summoning \the [F]" + ghost.request_player(F,"A wizard is requesting a familiar.", 60 SECONDS) + spawn(600) + if(F) + if(!F.ckey || !F.client) + F.visible_message("With no soul to keep \the [F] linked to this plane, it fades away.") + qdel(F) + else + F.faction = usr.faction + F.add_spell(new /spell/contract/return_master(usr), "const_spell_ready") + to_chat(F, "You are a familiar.") + to_chat(F, "You have been summoned by the wizard [usr] to assist in all matters magical and not.") + to_chat(F, "Do their bidding and help them with their goals.") + uses-- + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + interact(user) + diff --git a/code/modules/spells/artifacts/storage.dm b/code/modules/spells/artifacts/storage.dm new file mode 100644 index 00000000..f82bfe6d --- /dev/null +++ b/code/modules/spells/artifacts/storage.dm @@ -0,0 +1,45 @@ +/obj/structure/closet/wizard + name = "artifact closet" + desc = "a special lead lined closet used to hold artifacts of immense power." + icon = 'icons/obj/storage.dmi' + icon = 'icons/obj/closet.dmi' + icon_state = "acloset" + icon_closed = "acloset" + icon_opened = "aclosetopen" + +/obj/structure/closet/wizard/New() + ..() + var/obj/structure/bigDelivery/package = new /obj/structure/bigDelivery(get_turf(src)) + package.wrapped = src + package.examtext = "Imported straight from the Wizard Acadamy. Do not lose the contents or suffer a demerit." + src.forceMove(package) + package.update_icon() + +/obj/structure/closet/wizard/armor + name = "Mastercrafted Armor Set" + desc = "An artefact suit of armor that allows you to cast spells while providing more protection against attacks and the void of space." + +/obj/structure/closet/wizard/armor/New() + ..() + new /obj/item/clothing/shoes/sandal(src) //In case they've lost them. + new /obj/item/clothing/gloves/wizard(src)//To complete the outfit + new /obj/item/clothing/suit/space/void/wizard(src) + new /obj/item/clothing/head/helmet/space/void/wizard(src) + +/obj/structure/closet/wizard/scrying + name = "Scrying Orb" + desc = "An incandescent orb of crackling energy, using it will allow you to ghost while alive, allowing you to reconnoiter with ease. In addition, buying it will permanently grant you x-ray vision." + +/obj/structure/closet/wizard/scrying/New() + ..() + new /obj/item/weapon/scrying(src) + new /obj/item/weapon/contract/wizard/xray(src) + +/obj/structure/closet/wizard/souls + name = "Soul Shard Belt" + desc = "Soul Stone Shards are ancient tools capable of capturing and harnessing the spirits of the dead and dying. The spell Artificer allows you to create arcane machines for the captured souls to pilot. This also includes the spell Artificer, used to create the shells used in construct creation." + +/obj/structure/closet/wizard/souls/New() + ..() + new /obj/item/weapon/contract/boon/wizard/artificer(src) + new /obj/item/weapon/storage/belt/soulstone/full(src) diff --git a/code/modules/spells/construct_spells.dm b/code/modules/spells/construct_spells.dm new file mode 100644 index 00000000..b2cec77d --- /dev/null +++ b/code/modules/spells/construct_spells.dm @@ -0,0 +1,10 @@ +//////////////////////////////Construct Spells///////////////////////// + +proc/findNullRod(var/atom/target) + if(istype(target,/obj/item/weapon/nullrod)) + return 1 + else if(target.contents) + for(var/atom/A in target.contents) + if(findNullRod(A)) + return 1 + return 0 diff --git a/code/modules/spells/contracts.dm b/code/modules/spells/contracts.dm new file mode 100644 index 00000000..5788cf74 --- /dev/null +++ b/code/modules/spells/contracts.dm @@ -0,0 +1,161 @@ +/obj/item/weapon/contract + name = "contract" + desc = "written in the blood of some unfortunate fellow." + icon = 'icons/mob/screen_spells.dmi' + icon_state = "master_open" + + var/contract_master = null + var/list/contract_spells = list(/spell/contract/reward,/spell/contract/punish,/spell/contract/return_master) + +/obj/item/weapon/contract/attack_self(mob/user as mob) + if(contract_master == null) + to_chat(user, "You bind the contract to your soul, making you the recipient of whatever poor fool's soul that decides to contract with you.") + contract_master = user + return + + if(contract_master == user) + to_chat(user, "You can't contract with yourself!") + return + + var/ans = alert(user,"The contract clearly states that signing this contract will bind your soul to \the [contract_master]. Are you sure you want to continue?","[src]","Yes","No") + + if(ans == "Yes") + user.visible_message("\The [user] signs the contract, their body glowing a deep yellow.") + if(!src.contract_effect(user)) + user.visible_message("\The [src] visibly rejects \the [user], erasing their signature from the line.") + return + user.visible_message("\The [src] disappears with a flash of light.") + if(contract_spells.len && istype(contract_master,/mob/living)) //if it aint text its probably a mob or another user + var/mob/living/M = contract_master + for(var/spell_type in contract_spells) + M.add_spell(new spell_type(user), "const_spell_ready") + log_and_message_admins("signed their soul over to \the [contract_master] using \the [src].", user) + user.drop_from_inventory(src) + qdel(src) + +/obj/item/weapon/contract/proc/contract_effect(mob/user as mob) + to_chat(user, "You've signed your soul over to \the [contract_master] and with that your unbreakable vow of servitude begins.") + return 1 + +/obj/item/weapon/contract/apprentice + name = "apprentice wizarding contract" + desc = "a wizarding school contract for those who want to sign their soul for a piece of the magic pie." + color = "#993300" + +/obj/item/weapon/contract/apprentice/contract_effect(mob/user as mob) + if(user.mind.special_role == "apprentice") + to_chat(user, "You are already a wizarding apprentice!") + return 0 + if(wizards.add_antagonist_mind(user.mind,1,"apprentice","You are an apprentice! Your job is to learn the wizarding arts!")) + to_chat(user, "With the signing of this paper you agree to become \the [contract_master]'s apprentice in the art of wizardry.") + return 1 + return 0 + + +/obj/item/weapon/contract/wizard //contracts that involve making a deal with the Wizard Acadamy (or NON PLAYERS) + contract_master = "\improper Wizard Academy" + +/obj/item/weapon/contract/wizard/xray + name = "xray vision contract" + desc = "This contract is almost see-through..." + color = "#339900" + +/obj/item/weapon/contract/wizard/xray/contract_effect(mob/user as mob) + ..() + if (!(XRAY in user.mutations)) + user.mutations.Add(XRAY) + user.set_sight(user.sight|SEE_MOBS|SEE_OBJS|SEE_TURFS) + user.set_see_in_dark(8) + user.set_see_invisible(SEE_INVISIBLE_LEVEL_TWO) + to_chat(user, "The walls suddenly disappear.") + return 1 + return 0 + +/obj/item/weapon/contract/wizard/telepathy + name = "telepathy contract" + desc = "The edges of the contract grow blurry when you look away from them. To be fair, actually reading it gives you a headache." + color = "#fcc605" + +/obj/item/weapon/contract/wizard/telepathy/contract_effect(mob/user as mob) + ..() + if(!(mRemotetalk in user.mutations)) + user.mutations.Add(mRemotetalk) + user.dna.SetSEState(GLOB.REMOTETALKBLOCK,1) + domutcheck(user, null, MUTCHK_FORCED) + to_chat(user, "You expand your mind outwards.") + return 1 + return 0 + +/obj/item/weapon/contract/wizard/tk + name = "telekinesis contract" + desc = "This contract makes your mind buzz. It promises to give you the ability to move things with your mind. At a price." + color = "#990033" + +/obj/item/weapon/contract/wizard/tk/contract_effect(mob/user as mob) + ..() + if(!(TK in user.mutations)) + user.mutations.Add(TK) + to_chat(user, "You feel your mind expanding!") + return 1 + return 0 + +/obj/item/weapon/contract/boon + name = "boon contract" + desc = "this contract grants you a boon for signing it." + var/path + +/obj/item/weapon/contract/boon/New(var/newloc, var/new_path) + ..(newloc) + if(new_path) + path = new_path + var/item_name = "" + if(ispath(path,/obj)) + var/obj/O = path + item_name = initial(O.name) + else if(ispath(path,/spell)) + var/spell/S = path + item_name = initial(S.name) + name = "[item_name] contract" + +/obj/item/weapon/contract/boon/contract_effect(mob/user as mob) + ..() + if(ispath(path,/spell)) + user.add_spell(new path) + return 1 + else if(ispath(path,/obj)) + new path(get_turf(user.loc)) + playsound(get_turf(usr),'sound/effects/phasein.ogg',50,1) + return 1 + +/obj/item/weapon/contract/boon/wizard + contract_master = "\improper Wizard Academy" + +/obj/item/weapon/contract/boon/wizard/artificer + path = /spell/aoe_turf/conjure/construct + desc = "This contract has a passage dedicated to an entity known as 'Nar-Sie'." + +/obj/item/weapon/contract/boon/wizard/fireball + path = /spell/targeted/projectile/dumbfire/fireball + desc = "This contract feels warm to the touch." + +/obj/item/weapon/contract/boon/wizard/smoke + path = /spell/aoe_turf/smoke + desc = "This contract smells as dank as they come." + +/obj/item/weapon/contract/boon/wizard/forcewall + path = /spell/aoe_turf/conjure/forcewall + contract_master = "\improper Mime Federation" + desc = "This contract has a dedication to mimes everywhere at the top." + +/obj/item/weapon/contract/boon/wizard/knock + path = /spell/aoe_turf/knock + desc = "This contract is hard to hold still." + +/obj/item/weapon/contract/boon/wizard/horsemask + path = /spell/targeted/equip_item/horsemask + desc = "This contract is more horse than your mind has room for." + +/obj/item/weapon/contract/boon/wizard/charge + path = /spell/aoe_turf/charge + desc = "This contract is made of 100% post-consumer wizard." + diff --git a/code/modules/spells/general/acid_spray.dm b/code/modules/spells/general/acid_spray.dm new file mode 100644 index 00000000..f93684ec --- /dev/null +++ b/code/modules/spells/general/acid_spray.dm @@ -0,0 +1,26 @@ +/spell/acid_spray + name = "Acid Spray" + desc = "A common spell used to destroy basically anything in front of the wizard." + school = "conjuration" + feedback = "as" + spell_flags = 0 + charge_max = 600 + + invocation = "Tagopar lethodar!" + invocation_type = SpI_SHOUT + var/reagent_type = /datum/reagent/acid/hydrochloric + hud_state = "wiz_acid" + +/spell/acid_spray/choose_targets() + return list(holder) + +/spell/acid_spray/cast(var/list/targets, var/mob/user) + var/atom/target = targets[1] + var/angle = dir2angle(target.dir) + for(var/mod in list(315, 0, 45)) + var/obj/effect/effect/water/chempuff/chem = new(get_turf(target)) + chem.create_reagents(10) + chem.reagents.add_reagent(reagent_type,10) + chem.set_color() + spawn(0) + chem.set_up(get_ranged_target_turf(target, angle2dir(angle+mod), 3)) \ No newline at end of file diff --git a/code/modules/spells/general/area_teleport.dm b/code/modules/spells/general/area_teleport.dm new file mode 100644 index 00000000..4d4b08f5 --- /dev/null +++ b/code/modules/spells/general/area_teleport.dm @@ -0,0 +1,83 @@ +/spell/area_teleport + name = "Teleport" + desc = "This spell teleports you to a type of area of your selection." + feedback = "TP" + school = "conjuration" + charge_max = 600 + spell_flags = NEEDSCLOTHES + invocation = "Scyar Nila!" + invocation_type = SpI_SHOUT + cooldown_min = 200 //100 deciseconds reduction per rank + + smoke_spread = 1 + smoke_amt = 5 + + var/randomise_selection = 0 //if it lets the usr choose the teleport loc or picks it from the list + var/invocation_area = 1 //if the invocation appends the selected area + + cast_sound = 'sound/effects/teleport.ogg' + + hud_state = "wiz_tele" + +/spell/area_teleport/before_cast() + return + +/spell/area_teleport/choose_targets() + var/area/thearea + if(!randomise_selection) + thearea = input("Area to teleport to", "Teleport") as null|anything in teleportlocs + if(!thearea) return + else + thearea = pick(teleportlocs) + return list(teleportlocs[thearea]) + +/spell/area_teleport/cast(area/thearea, mob/user) + playsound(get_turf(user),cast_sound,50,1) + if(!istype(thearea)) + if(istype(thearea, /list)) + thearea = thearea[1] + var/list/L = list() + for(var/turf/T in get_area_turfs(thearea)) + if(!T.density) + var/clear = 1 + for(var/obj/O in T) + if(O.density) + clear = 0 + break + if(clear) + L+=T + + if(!L.len) + to_chat(user, "The spell matrix was unable to locate a suitable teleport destination for an unknown reason. Sorry.") + return + + if(user && user.buckled) + user.buckled = null + + var/attempt = null + var/success = 0 + while(L.len) + attempt = pick(L) + success = user.Move(attempt) + if(!success) + L.Remove(attempt) + else + break + + if(!success) + user.loc = pick(L) + + return + +/spell/area_teleport/after_cast() + return + +/spell/area_teleport/invocation(mob/user, area/chosenarea) + if(!istype(chosenarea)) + return //can't have that, can we + if(!invocation_area || !chosenarea) + ..() + else + invocation += "[uppertext(chosenarea.name)]" + ..() + return diff --git a/code/modules/spells/general/contract_spells.dm b/code/modules/spells/general/contract_spells.dm new file mode 100644 index 00000000..4894632e --- /dev/null +++ b/code/modules/spells/general/contract_spells.dm @@ -0,0 +1,67 @@ +//These spells are given to the owner of a contract when a victim signs it. +//As such they are REALLY REALLY powerful (because the victim is rewarded for signing it, and signing contracts is completely voluntary) + +/spell/contract + name = "Contract Spell" + desc = "A spell perfecting the techniques of keeping a servant happy and obedient." + + school = "transmutation" + spell_flags = 0 + invocation = "none" + invocation_type = SpI_NONE + + + var/mob/subject + +/spell/contract/New(var/mob/M) + ..() + subject = M + name += " ([M.real_name])" + +/spell/contract/choose_targets() + return list(subject) + +/spell/contract/cast(mob/target,mob/user) + if(!subject) + to_chat(usr, "This spell was not properly given a target. Contact a coder.") + return null + + if(istype(target,/list)) + target = target[1] + return target + + +/spell/contract/reward + name = "Reward Contractee" + desc = "A spell that makes your contracted victim feel better." + + charge_max = 300 + cooldown_min = 100 + + hud_state = "wiz_jaunt_old" + +/spell/contract/reward/cast(mob/living/target,mob/user) + target = ..(target,user) + if(!target) + return + + to_chat(target, "You feel great!") + target.ExtinguishMob() + +/spell/contract/punish + name = "Punish Contractee" + desc = "A spell that sets your contracted victim ablaze." + + charge_max = 300 + cooldown_min = 100 + + hud_state = "gen_immolate" + +/spell/contract/punish/cast(mob/living/target,mob/user) + target = ..(target,user) + if(!target) + return + + to_chat(target, "You feel punished!") + target.fire_stacks += 15 + target.IgniteMob() \ No newline at end of file diff --git a/code/modules/spells/general/create_air.dm b/code/modules/spells/general/create_air.dm new file mode 100644 index 00000000..9e521fff --- /dev/null +++ b/code/modules/spells/general/create_air.dm @@ -0,0 +1,25 @@ +/spell/create_air + name = "Create Air" + desc = "A much used spell used in the vasteness of space to make it not so killey." + + charge_max = 200 + spell_flags = Z2NOCAST + invocation = "none" + invocation_type = SpI_NONE + + number_of_channels = 0 + time_between_channels = 200 + hud_state = "wiz_air" + var/list/air_change = list("oxygen" = ONE_ATMOSPHERE) + number_of_channels = 0 + +/spell/create_air/choose_targets() + var/air = holder.return_air() + if(air) + return list(air) + return null + +/spell/create_air/cast(var/list/targets, var/mob/holder, var/channel_count) + var/datum/gas_mixture/environment = targets[1] + for(var/gas in air_change) + environment.adjust_gas(gas, air_change[gas]) \ No newline at end of file diff --git a/code/modules/spells/general/mark_recall.dm b/code/modules/spells/general/mark_recall.dm new file mode 100644 index 00000000..74010b52 --- /dev/null +++ b/code/modules/spells/general/mark_recall.dm @@ -0,0 +1,83 @@ +/spell/mark_recall + name = "Mark and Recall" + desc = "This spell was created so wizards could get home from the bar without driving. Does not require wizard garb." + feedback = "MK" + school = "conjuration" + charge_max = 600 //1 minutes for how OP this shit is (apparently not as op as I thought) + spell_flags = Z2NOCAST + invocation = "Re-Alki R'natha." + invocation_type = SpI_WHISPER + cooldown_min = 300 + + smoke_amt = 1 + smoke_spread = 5 + + level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 1) + + cast_sound = 'sound/effects/teleport.ogg' + hud_state = "wiz_mark" + var/mark = null + +/spell/mark_recall/choose_targets() + if(!mark) + return list("magical fairy dust") //because why not + else + return list(mark) + +/spell/mark_recall/cast(var/list/targets,mob/user) + if(!targets.len) + return 0 + var/target = targets[1] + if(istext(target)) + mark = new /obj/effect/cleanable/wizard_mark(get_turf(user),src) + return 1 + if(!istype(target,/obj)) //something went wrong + return 0 + var/turf/T = get_turf(target) + if(!T) + return 0 + user.forceMove(T) + ..() + +/spell/mark_recall/empower_spell() + if(!..()) + return 0 + + spell_flags = STATALLOWED + + return "You no longer have to be conscious to activate this spell." + +/obj/effect/cleanable/wizard_mark + name = "\improper Mark of the Wizard" + desc = "A strange rune said to be made by wizards. Or its just some shmuck playing with crayons again." + icon = 'icons/obj/rune.dmi' + icon_state = "wizard_mark" + + anchored = 1 + unacidable = 1 + layer = TURF_LAYER + + var/spell/mark_recall/spell + +/obj/effect/cleanable/wizard_mark/New(var/newloc,var/mrspell) + ..() + spell = mrspell + +/obj/effect/cleanable/wizard_mark/Destroy() + spell.mark = null //dereference pls. + spell = null + ..() + +/obj/effect/cleanable/wizard_mark/attack_hand(var/mob/user) + if(user == spell.holder) + user.visible_message("\The [user] mutters an incantation and \the [src] disappears!") + qdel(src) + ..() + +/obj/effect/cleanable/wizard_mark/attackby(var/obj/item/I, var/mob/user) + if(istype(I, /obj/item/weapon/nullrod) || istype(I, /obj/item/weapon/spellbook)) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + src.visible_message("\The [src] fades away!") + qdel(src) + return + ..() \ No newline at end of file diff --git a/code/modules/spells/general/radiant_aura.dm b/code/modules/spells/general/radiant_aura.dm new file mode 100644 index 00000000..66ec477a --- /dev/null +++ b/code/modules/spells/general/radiant_aura.dm @@ -0,0 +1,22 @@ +/spell/radiant_aura + name = "Radiant aura" + desc = "Form a protective layer of light around you, making you immune to laser fire." + school = "transmutation" + feedback = "ra" + invocation_type = SpI_EMOTE + invocation = "conjures a sphere of fire around themselves." + school = "conjuration" + charge_max = 300 + cooldown_min = 100 + level_max = list(Sp_TOTAL = 2, Sp_SPEED = 2, Sp_POWER = 0) + cast_sound = 'sound/effects/snap.ogg' + duration = 40 + hud_state = "gen_immolate" + +/spell/radiant_aura/choose_targets() + return list(holder) + +/spell/radiant_aura/cast(var/list/targets, var/mob/user) + var/obj/aura/radiant_aura/A = new(user) + spawn(duration) + qdel(A) \ No newline at end of file diff --git a/code/modules/spells/general/return_master.dm b/code/modules/spells/general/return_master.dm new file mode 100644 index 00000000..119cc938 --- /dev/null +++ b/code/modules/spells/general/return_master.dm @@ -0,0 +1,23 @@ +/spell/contract/return_master + name = "Return to Master" + desc = "Teleport back to your master" + + school = "conjuration" + charge_max = 600 + spell_flags = 0 + invocation = "none" + invocation_type = SpI_NONE + cooldown_min = 200 + + smoke_spread = 1 + smoke_amt = 5 + + hud_state = "wiz_tele" + + +/spell/contract/return_master/cast(mob/target,mob/user) + target = ..(target,user) + if(!target) + return + + user.forceMove(get_turf(target)) \ No newline at end of file diff --git a/code/modules/spells/general/rune_write.dm b/code/modules/spells/general/rune_write.dm new file mode 100644 index 00000000..00034ca5 --- /dev/null +++ b/code/modules/spells/general/rune_write.dm @@ -0,0 +1,179 @@ +/spell/rune_write + name = "Scribe a Rune" + desc = "Let's you instantly manifest a working rune." + + school = "evocation" + charge_max = 100 + charge_type = Sp_RECHARGE + invocation_type = SpI_NONE + + spell_flags = CONSTRUCT_CHECK + + hud_state = "const_rune" + + smoke_amt = 1 + +/spell/rune_write/choose_targets(mob/user = usr) + return list(user) + +/spell/rune_write/cast(null, mob/user = usr) + if(!cultwords["travel"]) + 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) + to_chat(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) + log_and_message_admins("created \an [r] rune at \the [A.name] - [user.loc.x]-[user.loc.y]-[user.loc.z].", user) + switch(r) + if("Teleport") + if(cast_check(1)) + var/beacon + if(user) + beacon = input(user, "Select the last rune", "Rune Scribing") in rnwords + R.word1=cultwords["travel"] + R.word2=cultwords["self"] + R.word3=beacon + R.check_icon() + if("Teleport Other") + if(cast_check(1)) + var/beacon + if(user) + beacon = input(user, "Select the last rune", "Rune Scribing") in rnwords + R.word1=cultwords["travel"] + R.word2=cultwords["other"] + R.word3=beacon + R.check_icon() + if("Spawn a Tome") + if(cast_check(1)) + R.word1=cultwords["see"] + R.word2=cultwords["blood"] + R.word3=cultwords["hell"] + R.check_icon() + if("Change Construct Type") + if(cast_check(1)) + R.word1=cultwords["hell"] + R.word2=cultwords["destroy"] + R.word3=cultwords["other"] + R.check_icon() + if("Convert") + if(cast_check(1)) + R.word1=cultwords["join"] + R.word2=cultwords["blood"] + R.word3=cultwords["self"] + R.check_icon() + if("EMP") + if(cast_check(1)) + R.word1=cultwords["destroy"] + R.word2=cultwords["see"] + R.word3=cultwords["technology"] + R.check_icon() + if("Drain Blood") + if(cast_check(1)) + R.word1=cultwords["travel"] + R.word2=cultwords["blood"] + R.word3=cultwords["self"] + R.check_icon() + if("See Invisible") + if(cast_check(1)) + R.word1=cultwords["see"] + R.word2=cultwords["hell"] + R.word3=cultwords["join"] + R.check_icon() + if("Resurrect") + if(cast_check(1)) + R.word1=cultwords["blood"] + R.word2=cultwords["join"] + R.word3=cultwords["hell"] + R.check_icon() + if("Hide Runes") + if(cast_check(1)) + R.word1=cultwords["hide"] + R.word2=cultwords["see"] + R.word3=cultwords["blood"] + R.check_icon() + if("Astral Journey") + if(cast_check(1)) + R.word1=cultwords["hell"] + R.word2=cultwords["travel"] + R.word3=cultwords["self"] + R.check_icon() + if("Manifest a Ghost") + if(cast_check(1)) + R.word1=cultwords["blood"] + R.word2=cultwords["see"] + R.word3=cultwords["travel"] + R.check_icon() + if("Imbue Talisman") + if(cast_check(1)) + R.word1=cultwords["hell"] + R.word2=cultwords["technology"] + R.word3=cultwords["join"] + R.check_icon() + if("Sacrifice") + if(cast_check(1)) + R.word1=cultwords["hell"] + R.word2=cultwords["blood"] + R.word3=cultwords["join"] + R.check_icon() + if("Reveal Runes") + if(cast_check(1)) + R.word1=cultwords["blood"] + R.word2=cultwords["see"] + R.word3=cultwords["hide"] + R.check_icon() + if("Wall") + if(cast_check(1)) + R.word1=cultwords["destroy"] + R.word2=cultwords["travel"] + R.word3=cultwords["self"] + R.check_icon() + if("Freedom") + if(cast_check(1)) + R.word1=cultwords["travel"] + R.word2=cultwords["technology"] + R.word3=cultwords["other"] + R.check_icon() + if("Cultsummon") + if(cast_check(1)) + R.word1=cultwords["join"] + R.word2=cultwords["other"] + R.word3=cultwords["self"] + R.check_icon() + if("Deafen") + if(cast_check(1)) + R.word1=cultwords["hide"] + R.word2=cultwords["other"] + R.word3=cultwords["see"] + R.check_icon() + if("Blind") + if(cast_check(1)) + R.word1=cultwords["destroy"] + R.word2=cultwords["see"] + R.word3=cultwords["other"] + R.check_icon() + if("BloodBoil") + if(cast_check(1)) + R.word1=cultwords["destroy"] + R.word2=cultwords["see"] + R.word3=cultwords["blood"] + R.check_icon() + if("Communicate") + if(cast_check(1)) + R.word1=cultwords["self"] + R.word2=cultwords["other"] + R.word3=cultwords["technology"] + R.check_icon() + if("Stun") + if(cast_check(1)) + R.word1=cultwords["join"] + R.word2=cultwords["hide"] + R.word3=cultwords["technology"] + R.check_icon() + else + to_chat(user, " You do not have enough space to write a proper rune.") + return diff --git a/code/modules/spells/general/tear_veil.dm b/code/modules/spells/general/tear_veil.dm new file mode 100644 index 00000000..c551270b --- /dev/null +++ b/code/modules/spells/general/tear_veil.dm @@ -0,0 +1,37 @@ +/spell/tear_veil + name = "Tear Veil" + desc = "Use your mental strength to literally tear a hole from this dimension to the next, letting things through..." + + charge_max = 300 + spell_flags = Z2NOCAST + invocation = "none" + invocation_type = SpI_NONE + + number_of_channels = 0 + time_between_channels = 200 + hud_state = "const_floor" + cast_sound = 'sound/effects/meteorimpact.ogg' + var/list/possible_spawns = list( + /mob/living/simple_animal/hostile/scarybat/cult, + /mob/living/simple_animal/hostile/creature/cult, + /mob/living/simple_animal/hostile/faithless/cult + ) + +/spell/tear_veil/choose_targets() + var/turf/T = get_turf(holder) + holder.visible_message("A strange portal rips open underneath \the [holder]!") + var/obj/effect/gateway/hole = new(get_turf(T)) + hole.density = 0 + return list(hole) + +/spell/tear_veil/cast(var/list/targets, var/mob/holder, var/channel_count) + if(channel_count == 1) + return + var/type = pick(possible_spawns) + var/mob/living/L = new type(get_turf(targets[1])) + L.faction = holder.faction + L.visible_message("\A [L] escapes from the portal!") + +/spell/tear_veil/after_spell(var/list/targets) + qdel(targets[1]) + return \ No newline at end of file diff --git a/code/modules/spells/hand/blood_shards.dm b/code/modules/spells/hand/blood_shards.dm new file mode 100644 index 00000000..fea79073 --- /dev/null +++ b/code/modules/spells/hand/blood_shards.dm @@ -0,0 +1,39 @@ +/spell/hand/charges/blood_shard + name = "Blood Shards" + desc = "Invoke a corrupted projectile forward that causes an enemy's blood to fly out in painful shards." + + spell_flags = 0 + charge_max = 600 + invocation = "opens their hand, which bursts into vicious red light." + invocation_type = SpI_EMOTE + + range = 7 + max_casts = 2 + compatible_targets = list(/atom) + hud_state = "wiz_bshard" + +/spell/hand/charges/blood_shard/cast_hand(var/atom/A,var/mob/user) + var/obj/item/projectile/blood_shard/B = new(get_turf(user)) + B.firer = user + B.launch_projectile(A, BP_CHEST) + user.visible_message("\The [user] shoots out a deep red shard from their hand!") + return ..() + +/obj/item/projectile/blood_shard + name = "bloodshard" + damage = 15 + check_armour = "melee" + icon_state = "blood" + damage_type = BRUTE + +/obj/item/projectile/blood_shard/on_hit(var/atom/movable/target, var/blocked = 0) + if(..()) + if(istype(target, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = target + H.vessel.remove_reagent(/datum/reagent/blood, 30) + H.visible_message("Tiny red shards burst from \the [H]'s skin!") + fragmentate(get_turf(src), 30, 5, list(/obj/item/projectile/bullet/pellet/blood)) + +/obj/item/projectile/bullet/pellet/blood + name = "blood fragment" + damage = 4 \ No newline at end of file diff --git a/code/modules/spells/hand/burning_grip.dm b/code/modules/spells/hand/burning_grip.dm new file mode 100644 index 00000000..82950799 --- /dev/null +++ b/code/modules/spells/hand/burning_grip.dm @@ -0,0 +1,35 @@ +/spell/hand/burning_grip + name = "Burning Grip" + desc = "Cause someone to drop a held object by causing it to heat up intensly." + school = "transmutation" + feedback = "bg" + range = 5 + spell_flags = 0 + invocation_type = SpI_NONE + show_message = " throws sparks from their hands" + spell_delay = 120 + hud_state = "wiz_burn" + compatible_targets = list(/mob/living/carbon/human) + +/spell/hand/burning_grip/valid_target(var/mob/living/L, var/mob/user) + if(!..()) + return 0 + if(!L.l_hand && !L.r_hand) + return 0 + return 1 + +/spell/hand/burning_grip/cast_hand(var/mob/living/carbon/human/H, var/mob/user) + var/list/targets = list() + if(H.l_hand) + targets += BP_L_HAND + if(H.r_hand) + targets += BP_R_HAND + + for(var/organ in targets) + var/obj/item/organ/external/E = H.get_organ(organ) + E.take_damage(burn=10, used_weapon = "hot iron") + if(E.can_feel_pain()) + H.grasp_damage_disarm(E) + else + E.take_damage(burn=6, used_weapon = "hot iron") + to_chat(H, "You look down to notice that your [E] is burned.") \ No newline at end of file diff --git a/code/modules/spells/hand/entangle.dm b/code/modules/spells/hand/entangle.dm new file mode 100644 index 00000000..4d4b91b4 --- /dev/null +++ b/code/modules/spells/hand/entangle.dm @@ -0,0 +1,50 @@ +/spell/hand/charges/entangle + name = "Entangle" + desc = "This spell creates vines that immediately entangle a nearby victim." + feedback = "ET" + school = "transmutation" + charge_max = 600 + spell_flags = NEEDSCLOTHES | SELECTABLE | IGNOREPREV + invocation = "Bu-Ekel'Inas!" + invocation_type = SpI_SHOUT + range = 3 + max_casts = 1 + + level_max = list(Sp_TOTAL = 2, Sp_SPEED = 2, Sp_POWER = 2) + cooldown_min = 300 + duration = 30 + compatible_targets = list(/mob) + + hud_state = "wiz_entangle" + show_message = " points towards the ground, causing plants to erupt" + var/datum/seed/seed + +/spell/hand/charges/entangle/New() + ..() + seed = new() + seed.set_trait(TRAIT_PLANT_ICON,"flower") + seed.set_trait(TRAIT_PRODUCT_ICON,"flower2") + seed.set_trait(TRAIT_PRODUCT_COLOUR,"#4d4dff") + seed.set_trait(TRAIT_SPREAD,2) + seed.name = "heirlooms" + seed.seed_name = "heirloom" + seed.display_name = "vines" + seed.chems = list(/datum/reagent/nutriment = list(1,20)) + +/spell/hand/charges/entangle/cast_hand(var/mob/M,var/mob/user) + var/turf/T = get_turf(M) + var/obj/effect/vine/single/P = new(T,seed, start_matured =1) + P.can_buckle = 1 + + P.buckle_mob(M) + M.set_dir(pick(GLOB.cardinal)) + M.visible_message("[P] appear from the floor, spinning around \the [M] tightly!") + return ..() + +/spell/hand/charges/entangle/empower_spell() + if(!..()) + return 0 + + max_casts++ + + return "This spell will now entangle [max_casts] times before running out." \ No newline at end of file diff --git a/code/modules/spells/hand/hand.dm b/code/modules/spells/hand/hand.dm new file mode 100644 index 00000000..334f61fc --- /dev/null +++ b/code/modules/spells/hand/hand.dm @@ -0,0 +1,59 @@ +/spell/hand + var/min_range = 0 + var/list/compatible_targets = list(/atom) + var/spell_delay = 5 + var/move_delay + var/click_delay + var/hand_state = "spell" + var/show_message + +/spell/hand/choose_targets(mob/user = usr) + return list(user) + +/spell/hand/cast_check(skipcharge = 0,mob/user = usr, var/list/targets) + if(!..()) + return 0 + if(targets) + for(var/target in targets) + var/mob/M = target + if(M.get_active_hand()) + to_chat(user, "You need an empty hand to cast this spell.") + return 0 + return 1 + +/spell/hand/cast(list/targets, mob/user) + for(var/mob/M in targets) + if(M.get_active_hand()) + to_chat(user, "You need an empty hand to cast this spell.") + return + var/obj/item/magic_hand/H = new(src) + if(!M.put_in_active_hand(H)) + qdel(H) + return + return 1 + +/spell/hand/proc/valid_target(var/atom/a,var/mob/user) //we use seperate procs for our target checking for the hand spells. + var/distance = get_dist(a,user) + if((min_range && distance < min_range) || (range && distance > range)) + return 0 + if(!is_type_in_list(a,compatible_targets)) + return 0 + return 1 + +/spell/hand/proc/cast_hand(var/atom/a,var/mob/user) //same for casting. + return 1 + +/spell/hand/charges + var/casts = 1 + var/max_casts = 1 + +/spell/hand/charges/cast(list/targets, mob/user) + . = ..() + if(.) + casts = max_casts + to_chat(user, "You ready the [name] spell ([casts]/[casts] charges).") + +/spell/hand/charges/cast_hand() + if(casts-- && ..()) + to_chat(holder, "The [name] spell has [casts] out of [max_casts] charges left") + return !!casts \ No newline at end of file diff --git a/code/modules/spells/hand/hand_item.dm b/code/modules/spells/hand/hand_item.dm new file mode 100644 index 00000000..e2886178 --- /dev/null +++ b/code/modules/spells/hand/hand_item.dm @@ -0,0 +1,68 @@ +/*much like grab this item is used primarily for the utility it provides. +Basically: I can use it to target things where I click. I can then pass these targets to a spell and target things not using a list. +*/ + +/obj/item/magic_hand + name = "Magic Hand" + icon = 'icons/mob/screen1.dmi' + atom_flags = 0 + item_flags = 0 + obj_flags = 0 + simulated = 0 + icon_state = "spell" + var/next_spell_time = 0 + var/spell/hand/hand_spell + +/obj/item/magic_hand/New(var/spell/hand/S) + hand_spell = S + name = "[name] ([S.name])" + icon_state = S.hand_state + +/obj/item/magic_hand/get_storage_cost() + return ITEM_SIZE_NO_CONTAINER + +/obj/item/magic_hand/attack(var/mob/living/M, var/mob/living/user) + if(hand_spell && hand_spell.valid_target(M, user)) + fire_spell(M, user) + return 0 + return 1 + +/obj/item/magic_hand/proc/fire_spell(var/atom/A, mob/living/user) + if(!hand_spell) //no spell? Die. + user.drop_from_inventory(src) + + if(!hand_spell.valid_target(A,user)) + return + if(world.time < next_spell_time) + to_chat(user, "The spell isn't ready yet!") + return + if(user.a_intent == I_HELP) + to_chat(user, "You decide against casting this spell as your intent is set to help.") + return + + if(hand_spell.show_message) + user.visible_message("\The [user][hand_spell.show_message]") + if(hand_spell.cast_hand(A,user)) + next_spell_time = world.time + hand_spell.spell_delay + if(hand_spell.move_delay) + user.setMoveCooldown(hand_spell.move_delay) + if(hand_spell.click_delay) + user.setClickCooldown(hand_spell.move_delay) + else + user.drop_from_inventory(src) + +/obj/item/magic_hand/afterattack(var/atom/A, var/mob/user, var/proximity) + if(hand_spell) + fire_spell(A,user) + +/obj/item/magic_hand/throw_at() //no throwing pls + usr.drop_from_inventory(src) + +/obj/item/magic_hand/dropped() //gets deleted on drop + ..() + loc = null + qdel(src) + +/obj/item/magic_hand/Destroy() //better save than sorry. + hand_spell = null + ..() \ No newline at end of file diff --git a/code/modules/spells/hand/slippery_surface.dm b/code/modules/spells/hand/slippery_surface.dm new file mode 100644 index 00000000..7b2b7384 --- /dev/null +++ b/code/modules/spells/hand/slippery_surface.dm @@ -0,0 +1,16 @@ +/spell/hand/slippery_surface + name = "Slippery Surface" + desc = "More of a practical joke than an actual spell." + school = "transmutation" + feedback = "su" + range = 5 + spell_flags = 0 + invocation_type = SpI_NONE + show_message = " snaps their fingers." + spell_delay = 50 + hud_state = "gen_ice" + +/spell/hand/slippery_surface/cast_hand(var/atom/a, var/mob/user) + for(var/turf/simulated/T in view(1,a)) + T.wet_floor(50) + return ..() \ No newline at end of file diff --git a/code/modules/spells/no_clothes.dm b/code/modules/spells/no_clothes.dm new file mode 100644 index 00000000..3b850292 --- /dev/null +++ b/code/modules/spells/no_clothes.dm @@ -0,0 +1,5 @@ +/spell/noclothes + name = "No Clothes" + desc = "Learn the ancient art of not wearing fancy robes while casting spells." + feedback = "NC" + spell_flags = NO_BUTTON \ No newline at end of file diff --git a/code/modules/spells/racial_wizard.dm b/code/modules/spells/racial_wizard.dm new file mode 100644 index 00000000..bf0b3c4c --- /dev/null +++ b/code/modules/spells/racial_wizard.dm @@ -0,0 +1,282 @@ +//this file is full of all the racial spells/artifacts/etc that each species has. + +/obj/item/weapon/magic_rock + name = "magical rock" + desc = "Legends say that this rock will unlock the true potential of anyone who touches it." + icon = 'icons/obj/wizard.dmi' + icon_state = "magic rock" + w_class = ITEM_SIZE_SMALL + throw_speed = 1 + throw_range = 3 + force = 15 + var/list/potentials = list( + SPECIES_HUMAN = /obj/item/weapon/storage/bag/cash/infinite, + SPECIES_VOX = /spell/targeted/shapeshift/true_form, + SPECIES_TAJARA = /spell/messa_shroud, + SPECIES_UNATHI = /spell/moghes_blessing, + SPECIES_DIONA = /spell/aoe_turf/conjure/grove/gestalt, + SPECIES_SKRELL = /obj/item/weapon/contract/apprentice/skrell, + SPECIES_IPC = /spell/camera_connection) + +/obj/item/weapon/magic_rock/attack_self(mob/user) + if(!istype(user,/mob/living/carbon/human)) + to_chat(user, "\The [src] can do nothing for such a simple being.") + return + var/mob/living/carbon/human/H = user + var/reward = potentials[H.species.get_bodytype(H)] //we get body type because that lets us ignore subspecies. + if(!reward) + to_chat(user, "\The [src] does not know what to make of you.") + return + for(var/spell/S in user.mind.learned_spells) + if(istype(S,reward)) + to_chat(user, "\The [src] can do no more for you.") + return + user.drop_from_inventory(src) + var/a = new reward() + if(ispath(reward,/spell)) + H.add_spell(a) + else if(ispath(reward,/obj)) + H.put_in_hands(a) + to_chat(user, "\The [src] crumbles in your hands.") + qdel(src) + +/obj/item/weapon/storage/bag/cash/infinite + startswith = list(/obj/item/weapon/spacecash/bundle/c1000 = 1) + +//HUMAN +/obj/item/weapon/storage/bag/cash/infinite/remove_from_storage(obj/item/W as obj, atom/new_location) + . = ..() + if(.) + if(istype(W,/obj/item/weapon/spacecash)) //only matters if its spacecash. + var/obj/item/I = new /obj/item/weapon/spacecash/bundle/c1000() + src.handle_item_insertion(I,1) + + +//Tajaran +/spell/messa_shroud + name = "Messa's Shroud" + desc = "This spell causes darkness at the point of the caster for a duration of time." + + school = "racial" + spell_flags = 0 + invocation_type = SpI_EMOTE + invocation = "mutters a small prayer, the light around them darkening." + charge_max = 300 //30 seconds + + range = 5 + duration = 150 //15 seconds + + cast_sound = 'sound/effects/bamf.ogg' + + hud_state = "wiz_tajaran" + +/spell/messa_shroud/choose_targets() + return list(get_turf(holder)) + +/spell/messa_shroud/cast(var/list/targets, mob/user) + var/turf/T = targets[1] + + if(!istype(T)) + return + + var/obj/O = new /obj(T) + O.set_light(range, -10, "#ffffff") + + spawn(duration) + qdel(O) + +//VOX +/spell/targeted/shapeshift/true_form + name = "True Form" + desc = "Pay respect to your heritage. Become what you once were." + + school = "racial" + spell_flags = INCLUDEUSER + invocation_type = SpI_EMOTE + range = -1 + invocation = "begins to grow!" + charge_max = 1200 //2 minutes + duration = 300 //30 seconds + + smoke_amt = 5 + smoke_spread = 1 + + possible_transformations = list(/mob/living/simple_animal/hostile/armalis) + + hud_state = "wiz_vox" + + cast_sound = 'sound/voice/shriek1.ogg' + revert_sound = 'sound/voice/shriek1.ogg' + + drop_items = 0 + + +//UNATHI +/spell/moghes_blessing + name = "Moghes Blessing" + desc = "Imbue your weapon with memories of Moghes" + + school = "racial" + spell_flags = 0 + invocation_type = SpI_EMOTE + invocation = "whispers something." + charge_type = Sp_HOLDVAR + holder_var_type = "bruteloss" + holder_var_amount = 10 + + hud_state = "wiz_unathi" + +/spell/moghes_blessing/choose_targets(mob/user = usr) + var/list/hands = list() + for(var/obj/item/I in list(user.l_hand, user.r_hand)) + //make sure it's not already blessed + if(istype(I) && !has_extension(I, /datum/extension/moghes_blessing)) + hands += I + return hands + +/spell/moghes_blessing/cast(var/list/targets, mob/user) + for(var/obj/item/I in targets) + set_extension(I, /datum/extension/moghes_blessing, /datum/extension/moghes_blessing) + +/datum/extension/moghes_blessing + expected_type = /obj/item + flags = EXTENSION_FLAG_IMMEDIATE + +/datum/extension/moghes_blessing/New(var/datum/holder) + ..(holder) + apply_blessing(holder) + +/datum/extension/moghes_blessing/proc/apply_blessing(obj/item/I) + I.name += " of Moghes" + I.desc += "
                It has been imbued with the memories of Moghes." + I.force += 10 + I.throwforce += 14 + I.color = "#663300" + +//DIONA +/spell/aoe_turf/conjure/grove/gestalt + name = "Convert Gestalt" + desc = "Converts the surrounding area into a Dionaea gestalt." + + school = "racial" + spell_flags = 0 + invocation_type = SpI_EMOTE + invocation = "rumbles as green alien plants grow quickly along the floor." + + charge_type = Sp_HOLDVAR + holder_var_type = "bruteloss" + holder_var_amount = 20 + + spell_flags = Z2NOCAST | IGNOREPREV | IGNOREDENSE + summon_type = list(/turf/simulated/floor/diona) + + + hud_state = "wiz_diona" + +//SKRELL +/obj/item/weapon/contract/apprentice/skrell + name = "skrellian apprenticeship contract" + var/obj/item/weapon/spellbook/linked + color = "#3366ff" + contract_spells = list(/spell/contract/return_master) //somewhat of a necessity due to how many spells they would have after a while. + +/obj/item/weapon/contract/apprentice/skrell/New(var/newloc,var/spellbook, var/owner) + ..() + if(istype(spellbook,/obj/item/weapon/spellbook)) + linked = spellbook + if(istype(owner,/mob)) + contract_master = owner + +/obj/item/weapon/contract/apprentice/skrell/attack_self(mob/user as mob) + if(!linked) + to_chat(user, "This contract requires a link to a spellbook.") + return + ..() + +/obj/item/weapon/contract/apprentice/skrell/afterattack(atom/A, mob/user as mob, proximity) + if(!linked && istype(A,/obj/item/weapon/spellbook)) + linked = A + to_chat(user, "You've linked \the [A] to \the [src]") + return + ..() + +/obj/item/weapon/contract/apprentice/skrell/contract_effect(mob/user as mob) + . = ..() + if(.) + linked.uses += 0.5 + var/obj/item/I = new /obj/item/weapon/contract/apprentice/skrell(get_turf(src),linked,contract_master) + user.put_in_hands(I) + new /obj/item/weapon/contract/apprentice/skrell(get_turf(src),linked,contract_master) + +//IPC +/spell/camera_connection + name = "Camera Connection" + desc = "This spell allows the wizard to connect to the local camera network and see what it sees." + + school = "racial" + + invocation_type = SpI_EMOTE + invocation = "emits a beeping sound before standing very, very still." + + charge_max = 600 //1 minute + charge_type = Sp_RECHARGE + + + spell_flags = Z2NOCAST + hud_state = "wiz_IPC" + var/mob/observer/eye/vision + var/eye_type = /mob/observer/eye/wizard_eye + +/spell/camera_connection/New() + ..() + vision = new eye_type(src) + +/spell/camera_connection/Destroy() + qdel(vision) + vision = null + . = ..() + +/spell/camera_connection/choose_targets() + var/mob/living/L = holder + if(!istype(L) || L.eyeobj) //no using if we already have an eye on. + return null + return list(holder) + +/spell/camera_connection/cast(var/list/targets, mob/user) + var/mob/living/L = targets[1] + + vision.possess(L) + GLOB.destroyed_event.register(L, src, /spell/camera_connection/proc/release) + GLOB.logged_out_event.register(L, src, /spell/camera_connection/proc/release) + L.verbs += /mob/living/proc/release_eye + +/spell/camera_connection/proc/release(var/mob/living/L) + vision.release(L) + L.verbs -= /mob/living/proc/release_eye + GLOB.destroyed_event.unregister(L, src) + GLOB.logged_out_event.unregister(L, src) + +/mob/observer/eye/wizard_eye + name_sufix = "Wizard Eye" + +/mob/observer/eye/wizard_eye/New() //we dont use the Ai one because it has AI specific procs imbedded in it. + ..() + visualnet = cameranet + +/mob/living/proc/release_eye() + set name = "Release Vision" + set desc = "Return your sight to your body." + set category = "Abilities" + + verbs -= /mob/living/proc/release_eye //regardless of if we have an eye or not we want to get rid of this verb. + + if(!eyeobj) + return + eyeobj.release(src) + +/mob/observer/eye/wizard_eye/Destroy() + if(istype(eyeobj.owner, /mob/living)) + var/mob/living/L = eyeobj.owner + L.release_eye() + qdel(eyeobj) + return ..() \ No newline at end of file diff --git a/code/modules/spells/spell_code.dm b/code/modules/spells/spell_code.dm new file mode 100644 index 00000000..13882606 --- /dev/null +++ b/code/modules/spells/spell_code.dm @@ -0,0 +1,386 @@ +var/list/spells = typesof(/spell) //needed for the badmin verb for now + +/spell + var/name = "Spell" + var/desc = "A spell" + var/feedback = "" //what gets sent if this spell gets chosen by the spellbook. + parent_type = /datum + var/panel = "Spells"//What panel the proc holder needs to go on. + + var/school = "evocation" //not relevant at now, but may be important later if there are changes to how spells work. the ones I used for now will probably be changed... maybe spell presets? lacking flexibility but with some other benefit? + /*Spell schools as follows: + Racial - Only tagged to spells gained for being a certain race + Conjuration - Creating an object or transporting it. + Transmutation - Modifying an object or transforming it. + Illusion - Altering perception or thought. + */ + var/charge_type = Sp_RECHARGE //can be recharge or charges, see charge_max and charge_counter descriptions; can also be based on the holder's vars now, use "holder_var" for that + + var/charge_max = 100 //recharge time in deciseconds if charge_type = Sp_RECHARGE or starting charges if charge_type = Sp_CHARGES + var/charge_counter = 0 //can only cast spells if it equals recharge, ++ each decisecond if charge_type = Sp_RECHARGE or -- each cast if charge_type = Sp_CHARGES + var/still_recharging_msg = "The spell is still recharging." + + var/silenced = 0 //not a binary - the length of time we can't cast this for + var/processing = 0 //are we processing already? Mainly used so that silencing a spell doesn't call process() again. (and inadvertedly making it run twice as fast) + + var/holder_var_type = "bruteloss" //only used if charge_type equals to "holder_var" + var/holder_var_amount = 20 //same. The amount adjusted with the mob's var when the spell is used + + var/spell_flags = NEEDSCLOTHES + var/invocation = "HURP DURP" //what is uttered when the wizard casts the spell + var/invocation_type = SpI_NONE //can be none, whisper, shout, and emote + var/range = 7 //the range of the spell; outer radius for aoe spells + var/message = "" //whatever it says to the guy affected by it + var/selection_type = "view" //can be "range" or "view" + var/atom/movable/holder //where the spell is. Normally the user, can be an item + var/duration = 0 //how long the spell lasts + + var/list/spell_levels = list(Sp_SPEED = 0, Sp_POWER = 0) //the current spell levels - total spell levels can be obtained by just adding the two values + var/list/level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 0) //maximum possible levels in each category. Total does cover both. + var/cooldown_reduc = 0 //If set, defines how much charge_max drops by every speed upgrade + var/delay_reduc = 0 + var/cooldown_min = 0 //minimum possible cooldown for a charging spell + + var/overlay = 0 + var/overlay_icon = 'icons/obj/wizard.dmi' + var/overlay_icon_state = "spell" + var/overlay_lifespan = 0 + + var/sparks_spread = 0 + var/sparks_amt = 0 //cropped at 10 + var/smoke_spread = 0 //1 - harmless, 2 - harmful + var/smoke_amt = 0 //cropped at 10 + + var/critfailchance = 0 + var/time_between_channels = 0 //Delay between casts + var/number_of_channels = 1 //How many times can we channel? + + var/cast_delay = 1 + var/cast_sound = "" + + var/hud_state = "" //name of the icon used in generating the spell hud object + var/override_base = "" + + + var/mob/living/deity/connected_god //Do we have this spell based off a boon from a god? + var/obj/screen/connected_button + +/////////////////////// +///SETUP AND PROCESS/// +/////////////////////// + +/spell/New() + ..() + + //still_recharging_msg = "[name] is still recharging." + charge_counter = charge_max + +/spell/proc/process() + if(processing) + return + processing = 1 + spawn(0) + while(charge_counter < charge_max || silenced > 0) + charge_counter = min(charge_max,charge_counter+1) + silenced = max(0,silenced-1) + sleep(1) + if(connected_button) + var/obj/screen/ability/spell/S = connected_button + if(!istype(S)) + return + S.update_charge(1) + processing = 0 + return + +///////////////// +/////CASTING///// +///////////////// + +/spell/proc/choose_targets(mob/user = usr) //depends on subtype - see targeted.dm, aoe_turf.dm, dumbfire.dm, or code in general folder + return + +/spell/proc/perform(mob/user = usr, skipcharge = 0) //if recharge is started is important for the trigger spells + if(!holder) + holder = user //just in case + if(!cast_check(skipcharge, user)) + return + if(cast_delay && !spell_do_after(user, cast_delay)) + return + var/list/targets = choose_targets(user) + if(!check_valid_targets(targets)) + return + var/time = 0 + admin_attacker_log(user, "attempted to cast the spell [name]") + do + time++ + if(!check_valid_targets(targets)) //make sure we HAVE something + break + if(cast_check(1,user, targets)) //we check again, otherwise you can choose a target and then wait for when you are no longer able to cast (I.E. Incapacitated) to use it. + invocation(user, targets) + //if(connected_god && !connected_god.take_charge(user, max(1, charge_max/10))) + // break + take_charge(user, skipcharge) + before_cast(targets) //applies any overlays and effects + if(prob(critfailchance)) + critfail(targets, user) + else + cast(targets, user, time) + after_cast(targets) //generates the sparks, smoke, target messages etc. + else + break + while(time != number_of_channels && do_after(user, time_between_channels, incapacitation_flags = INCAPACITATION_KNOCKOUT|INCAPACITATION_FORCELYING|INCAPACITATION_STUNNED, same_direction=1)) + after_spell(targets, user, time) //When we are done with the spell completely. + + + +/spell/proc/cast(list/targets, mob/user, var/channel_duration) //the actual meat of the spell + return + +/spell/proc/critfail(list/targets, mob/user) //the wizman has fucked up somehow + return + +/spell/proc/after_spell(var/list/targets, var/mob/user, var/channel_duration) //After everything else is done. + return + +/spell/proc/adjust_var(mob/living/target = usr, type, amount) //handles the adjustment of the var when the spell is used. has some hardcoded types + switch(type) + if("bruteloss") + target.adjustBruteLoss(amount) + if("fireloss") + target.adjustFireLoss(amount) + if("toxloss") + target.adjustToxLoss(amount) + if("oxyloss") + target.adjustOxyLoss(amount) + if("brainloss") + target.adjustBrainLoss(amount) + if("stunned") + target.AdjustStunned(amount) + if("weakened") + target.AdjustWeakened(amount) + if("paralysis") + target.AdjustParalysis(amount) + else + target.vars[type] += amount //I bear no responsibility for the runtimes that'll happen if you try to adjust non-numeric or even non-existant vars + return + +/////////////////////////// +/////CASTING WRAPPERS////// +/////////////////////////// + +/spell/proc/before_cast(list/targets) + for(var/atom/target in targets) + if(overlay) + var/location + if(istype(target,/mob/living)) + location = target.loc + else if(istype(target,/turf)) + location = target + var/obj/effect/overlay/spell = new /obj/effect/overlay(location) + spell.icon = overlay_icon + spell.icon_state = overlay_icon_state + spell.anchored = 1 + spell.set_density(0) + spawn(overlay_lifespan) + qdel(spell) + +/spell/proc/after_cast(list/targets) + if(cast_sound) + playsound(get_turf(holder),cast_sound,50,1) + for(var/atom/target in targets) + var/location = get_turf(target) + if(istype(target,/mob/living) && message) + to_chat(target, text("[message]")) + if(sparks_spread) + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(sparks_amt, 0, location) //no idea what the 0 is + sparks.start() + if(smoke_spread) + if(smoke_spread == 1) + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() + smoke.set_up(smoke_amt, 0, location) //no idea what the 0 is + smoke.start() + else if(smoke_spread == 2) + var/datum/effect/effect/system/smoke_spread/bad/smoke = new /datum/effect/effect/system/smoke_spread/bad() + smoke.set_up(smoke_amt, 0, location) //no idea what the 0 is + smoke.start() + +///////////////////// +////CASTING TOOLS//// +///////////////////// +/*Checkers, cost takers, message makers, etc*/ + +/spell/proc/cast_check(skipcharge = 0,mob/user = usr, var/list/targets) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell + if(silenced > 0) + return 0 + + if(!(src in user.mind.learned_spells) && holder == user && !(isanimal(user))) + error("[user] utilized the spell '[src]' without having it.") + to_chat(user, "You shouldn't have this spell! Something's wrong.") + return 0 + + var/turf/user_turf = get_turf(user) + if(!user_turf) + to_chat(user, "You cannot cast spells in null space!") + + if((spell_flags & Z2NOCAST) && (user_turf.z in GLOB.using_map.admin_levels)) //Certain spells are not allowed on the centcomm zlevel + return 0 + + if(spell_flags & CONSTRUCT_CHECK) + for(var/turf/T in range(holder, 1)) + if(findNullRod(T)) + return 0 + + if(istype(user, /mob/living/simple_animal) && holder == user) + var/mob/living/simple_animal/SA = user + if(SA.purge) + to_chat(SA, "The nullrod's power interferes with your own!") + return 0 + + if(!src.check_charge(skipcharge, user)) //sees if we can cast based on charges alone + return 0 + + if(!(spell_flags & GHOSTCAST) && holder == user) + if(user.stat && !(spell_flags & STATALLOWED)) + to_chat(usr, "Not when you're incapacitated.") + return 0 + + if(ishuman(user) && !(invocation_type in list(SpI_EMOTE, SpI_NONE))) + if(istype(user.wear_mask, /obj/item/clothing/mask/muzzle)) + to_chat(user, "Mmmf mrrfff!") + return 0 + + var/spell/noclothes/spell = locate() in user.mind.learned_spells + if((spell_flags & NEEDSCLOTHES) && !(spell && istype(spell)) && holder == user)//clothes check + if(!user.wearing_wiz_garb()) + return 0 + + return 1 + +/spell/proc/check_charge(var/skipcharge, mob/user) + if(!skipcharge) + switch(charge_type) + if(Sp_RECHARGE) + if(charge_counter < charge_max) + to_chat(user, still_recharging_msg) + return 0 + if(Sp_CHARGES) + if(!charge_counter) + to_chat(user, "[name] has no charges left.") + return 0 + return 1 + +/spell/proc/take_charge(mob/user = user, var/skipcharge) + if(!skipcharge) + switch(charge_type) + if(Sp_RECHARGE) + charge_counter = 0 //doesn't start recharging until the targets selecting ends + src.process() + return 1 + if(Sp_CHARGES) + charge_counter-- //returns the charge if the targets selecting fails + return 1 + if(Sp_HOLDVAR) + adjust_var(user, holder_var_type, holder_var_amount) + return 1 + return 0 + return 1 + +/spell/proc/check_valid_targets(var/list/targets) + if(!targets) + return 0 + if(!islist(targets)) + targets = list(targets) + else if(!targets.len) + return 0 + + var/list/valid_targets = view_or_range(range, holder, selection_type) + for(var/target in targets) + if(!target in valid_targets) + return 0 + return 1 + +/spell/proc/invocation(mob/user = usr, var/list/targets) //spelling the spell out and setting it on recharge/reducing charges amount + + switch(invocation_type) + if(SpI_SHOUT) + if(prob(50))//Auto-mute? Fuck that noise + user.say(invocation) + else + user.say(replacetext(invocation," ","`")) + if(SpI_WHISPER) + if(prob(50)) + user.whisper(invocation) + else + user.whisper(replacetext(invocation," ","`")) + if(SpI_EMOTE) + user.custom_emote(VISIBLE_MESSAGE, invocation) + +///////////////////// +///UPGRADING PROCS/// +///////////////////// + +/spell/proc/can_improve(var/upgrade_type) + if(level_max[Sp_TOTAL] <= ( spell_levels[Sp_SPEED] + spell_levels[Sp_POWER] )) //too many levels, can't do it + return 0 + + //if(upgrade_type && spell_levels[upgrade_type] && level_max[upgrade_type]) + if(upgrade_type && spell_levels[upgrade_type] >= level_max[upgrade_type]) + return 0 + + return 1 + +/spell/proc/empower_spell() + if(!can_improve(Sp_POWER)) + return 0 + + spell_levels[Sp_POWER]++ + + return 1 + +/spell/proc/quicken_spell() + if(!can_improve(Sp_SPEED)) + return 0 + + spell_levels[Sp_SPEED]++ + + if(delay_reduc && cast_delay) + cast_delay = max(0, cast_delay - delay_reduc) + else if(cast_delay) + cast_delay = round( max(0, initial(cast_delay) * ((level_max[Sp_SPEED] - spell_levels[Sp_SPEED]) / level_max[Sp_SPEED] ) ) ) + + if(charge_type == Sp_RECHARGE) + if(cooldown_reduc) + charge_max = max(cooldown_min, charge_max - cooldown_reduc) + else + charge_max = round( max(cooldown_min, initial(charge_max) * ((level_max[Sp_SPEED] - spell_levels[Sp_SPEED]) / level_max[Sp_SPEED] ) ) ) //the fraction of the way you are to max speed levels is the fraction you lose + if(charge_max < charge_counter) + charge_counter = charge_max + + var/temp = "" + name = initial(name) + switch(level_max[Sp_SPEED] - spell_levels[Sp_SPEED]) + if(3) + temp = "You have improved [name] into Efficient [name]." + name = "Efficient [name]" + if(2) + temp = "You have improved [name] into Quickened [name]." + name = "Quickened [name]" + if(1) + temp = "You have improved [name] into Free [name]." + name = "Free [name]" + if(0) + temp = "You have improved [name] into Instant [name]." + name = "Instant [name]" + + return temp + +/spell/proc/spell_do_after(var/mob/user as mob, delay as num, var/numticks = 5) + if(!user || isnull(user)) + return 0 + + var/incap_flags = INCAPACITATION_STUNNED + if(!(spell_flags & (STATALLOWED|GHOSTCAST))) + incap_flags |= INCAPACITATION_KNOCKOUT + + return do_after(user,delay, incapacitation_flags = incap_flags) \ No newline at end of file diff --git a/code/modules/spells/spell_projectile.dm b/code/modules/spells/spell_projectile.dm new file mode 100644 index 00000000..367ab3bb --- /dev/null +++ b/code/modules/spells/spell_projectile.dm @@ -0,0 +1,55 @@ +/obj/item/projectile/spell_projectile + name = "spell" + icon = 'icons/obj/projectiles.dmi' + + nodamage = 1 //Most of the time, anyways + + var/spell/targeted/projectile/carried + + penetrating = 0 + range = 10 //set by the duration of the spell + + var/proj_trail = 0 //if it leaves a trail + var/proj_trail_lifespan = 0 //deciseconds + var/proj_trail_icon = 'icons/obj/wizard.dmi' + var/proj_trail_icon_state = "trail" + var/list/trails = new() + +/obj/item/projectile/spell_projectile/Destroy() + for(var/trail in trails) + qdel(trail) + carried = null + return ..() + +/obj/item/projectile/spell_projectile/ex_act() + return + +/obj/item/projectile/spell_projectile/before_move() + if(proj_trail && src && src.loc) //pretty trails + var/obj/effect/overlay/trail = new /obj/effect/overlay(loc) + trails += trail + trail.icon = proj_trail_icon + trail.icon_state = proj_trail_icon_state + trail.set_density(0) + spawn(proj_trail_lifespan) + trails -= trail + qdel(trail) + +/obj/item/projectile/spell_projectile/proc/prox_cast(var/list/targets) + if(loc) + carried.prox_cast(targets, src) + qdel(src) + return + +/obj/item/projectile/spell_projectile/Bump(var/atom/A) + if(loc && carried) + prox_cast(carried.choose_prox_targets(user = carried.holder, spell_holder = src)) + return 1 + +/obj/item/projectile/spell_projectile/on_impact() + if(loc && carried) + prox_cast(carried.choose_prox_targets(user = carried.holder, spell_holder = src)) + return 1 + +/obj/item/projectile/spell_projectile/seeking + name = "seeking spell" diff --git a/code/modules/spells/spellbook.dm b/code/modules/spells/spellbook.dm new file mode 100644 index 00000000..d11cb27f --- /dev/null +++ b/code/modules/spells/spellbook.dm @@ -0,0 +1,308 @@ +#define NOREVERT 1 +#define LOCKED 2 +#define CAN_MAKE_CONTRACTS 4 +#define INVESTABLE 8 +//spells/spellbooks have a variable for this but as artefacts are literal items they do not. +//so we do this instead. +var/list/artefact_feedback = list(/obj/structure/closet/wizard/armor = "HS", + /obj/item/weapon/gun/energy/staff/focus = "MF", + /obj/item/weapon/monster_manual = "MA", + /obj/item/weapon/magic_rock = "RA", + /obj/item/weapon/contract/apprentice = "CP", + /obj/structure/closet/wizard/souls = "SS", + /obj/item/weapon/contract/wizard/tk = "TK", + /obj/structure/closet/wizard/scrying = "SO", + /obj/item/weapon/teleportation_scroll = "TS", + /obj/item/weapon/gun/energy/staff = "ST", + /obj/item/weapon/gun/energy/staff/animate = "SA", + /obj/item/weapon/dice/d20/cursed = "DW") + +/obj/item/weapon/spellbook + name = "master spell book" + desc = "The legendary book of spells of the wizard." + icon = 'icons/obj/library.dmi' + icon_state = "spellbook" + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_NORMAL + var/uses = 1 + var/temp = null + var/datum/spellbook/spellbook + var/spellbook_type = /datum/spellbook/ //for spawning specific spellbooks. + var/investing_time = 0 //what time we target forr a return on our spell investment. + var/has_sacrificed = 0 //whether we have already got our sacrifice bonus for the current investment. + +/obj/item/weapon/spellbook/New() + ..() + set_spellbook(spellbook_type) + +/obj/item/weapon/spellbook/proc/set_spellbook(var/type) + if(spellbook) + qdel(spellbook) + spellbook = new type() + uses = spellbook.max_uses + name = spellbook.name + desc = spellbook.desc + +/obj/item/weapon/spellbook/attack_self(mob/user as mob) + if(user.mind) + if(!wizards.is_antagonist(user.mind)) + to_chat(user, "You can't make heads or tails of this book.") + return + if(spellbook.book_flags & LOCKED) + if(user.mind.special_role == "apprentice") + to_chat(user, "Drat! This spellbook's apprentice proof lock is on!.") + return + else + to_chat(user, "You notice the apprentice proof lock is on. Luckily you are beyond such things and can open it anyways.") + + interact(user) + +/obj/item/weapon/spellbook/proc/make_sacrifice(obj/item/I as obj, mob/user as mob, var/reagent) + if(has_sacrificed) + return + if(reagent) + var/datum/reagents/R = I.reagents + R.remove_reagent(reagent,5) + else + if(istype(I,/obj/item/stack)) + var/obj/item/stack/S = I + if(S.amount < S.max_amount) + to_chat(usr, "You must sacrifice [S.max_amount] stacks of [S]!") + return + user.remove_from_mob(I) + qdel(I) + to_chat(user, "Your sacrifice was accepted!") + has_sacrificed = 1 + investing_time = max(investing_time - 6000,1) //subtract 10 minutes. Make sure it doesn't act funky at the beginning of the game. + + +/obj/item/weapon/spellbook/attackby(obj/item/I as obj, mob/user as mob) + if(investing_time && !has_sacrificed) + var/list/objects = spellbook.sacrifice_objects + if(objects && objects.len) + for(var/type in objects) + if(istype(I,type)) + make_sacrifice(I,user) + return + if(I.reagents) + var/datum/reagents/R = I.reagents + var/list/reagent_list = spellbook.sacrifice_reagents + if(reagent_list && reagent_list.len) + for(var/id in reagent_list) + if(R.has_reagent(id,5)) + make_sacrifice(I,user, id) + return 1 + ..() + +/obj/item/weapon/spellbook/interact(mob/user as mob) + var/dat = null + if(temp) + dat = "[temp]
                Return" + else + dat = "

                [spellbook.title]

                [spellbook.title_desc]
                You have [uses] spell slot[uses > 1 ? "s" : ""] left.

                " + dat += "
                Requires Wizard Garb
                Selectable Target
                Spell Charge Type: Recharge, Sacrifice, Charges

                " + dat += "
                To use a contract, first bind it to your soul, then give it to someone to sign. This will bind their soul to you.

                " + for(var/i in 1 to spellbook.spells.len) + var/name = "" //name of target + var/desc = "" //description of target + var/info = "" //additional information + if(ispath(spellbook.spells[i],/datum/spellbook)) + var/datum/spellbook/S = spellbook.spells[i] + name = initial(S.name) + desc = initial(S.book_desc) + info = "[initial(S.max_uses)] Spell Slots" + else if(ispath(spellbook.spells[i],/obj)) + var/obj/O = spellbook.spells[i] + name = "Artefact: [capitalize(initial(O.name))]" //because 99.99% of objects dont have capitals in them and it makes it look weird. + desc = initial(O.desc) + else if(ispath(spellbook.spells[i],/spell)) + var/spell/S = spellbook.spells[i] + name = initial(S.name) + desc = initial(S.desc) + var/testing = initial(S.spell_flags) + if(testing & NEEDSCLOTHES) + info = "W" + var/type = "" + switch(initial(S.charge_type)) + if(Sp_RECHARGE) + type = "R" + if(Sp_HOLDVAR) + type = "S" + if(Sp_CHARGES) + type = "C" + info += "[type]" + dat += "[name]" + if(length(info)) + dat += " ([info])" + dat += " ([spellbook.spells[spellbook.spells[i]]] spell slot[spellbook.spells[spellbook.spells[i]] > 1 ? "s" : "" ])" + if(spellbook.book_flags & CAN_MAKE_CONTRACTS) + dat += " Make Contract" + dat += "
                [desc]
                " + dat += "
                Re-memorize your spellbook.
                " + if(spellbook.book_flags & INVESTABLE) + if(investing_time) + dat += "
                Currently investing in a slot...
                " + else + dat += "
                Invest a Spell Slot
                Investing a spellpoint will return two spellpoints back in 15 minutes.
                Some say a sacrifice could even shorten the time...
                " + if(!(spellbook.book_flags & NOREVERT)) + dat += "
                Choose different spellbook.
                " + dat += "
                [spellbook.book_flags & LOCKED ? "Unlock" : "Lock"] the spellbook.
                " + user << browse(dat,"window=spellbook") + +/obj/item/weapon/spellbook/CanUseTopic(var/mob/living/carbon/human/H) + if(!istype(H)) + return STATUS_CLOSE + + if(H.mind && (spellbook.book_flags & LOCKED) && H.mind.special_role == "apprentice") //make sure no scrubs get behind the lock + return STATUS_CLOSE + + return ..() + +/obj/item/weapon/spellbook/OnTopic(var/mob/living/carbon/human/user, href_list) + if(href_list["lock"]) + if(spellbook.book_flags & LOCKED) + spellbook.book_flags &= ~LOCKED + else + spellbook.book_flags |= LOCKED + . = TOPIC_REFRESH + + else if(href_list["temp"]) + temp = null + . = TOPIC_REFRESH + + else if(href_list["book"]) + if(initial(spellbook.max_uses) != spellbook.max_uses || uses != spellbook.max_uses) + temp = "You've already purchased things using this spellbook!" + else + src.set_spellbook(/datum/spellbook) + temp = "You have reverted back to the Book of Tomes." + . = TOPIC_REFRESH + + else if(href_list["invest"]) + temp = invest() + . = TOPIC_REFRESH + + else if(href_list["path"]) + var/path = locate(href_list["path"]) in spellbook.spells + if(!path) + return TOPIC_HANDLED + if(uses < spellbook.spells[path]) + to_chat(user, "You do not have enough spell slots to purchase this.") + return TOPIC_HANDLED + send_feedback(path) //feedback stuff + if(ispath(path,/datum/spellbook)) + src.set_spellbook(path) + temp = "You have chosen a new spellbook." + else + if(href_list["contract"]) + if(!(spellbook.book_flags & CAN_MAKE_CONTRACTS)) + return //no + uses -= spellbook.spells[path] + spellbook.max_uses -= spellbook.spells[path] //no basksies + var/obj/O = new /obj/item/weapon/contract/boon(get_turf(user),path) + temp = "You have purchased \the [O]." + else + if(ispath(path,/spell)) + temp = src.add_spell(user,path) + if(temp) + uses -= spellbook.spells[path] + else + var/obj/O = new path(get_turf(user)) + temp = "You have purchased \a [O]." + uses -= spellbook.spells[path] + spellbook.max_uses -= spellbook.spells[path] + //finally give it a bit of an oomf + playsound(get_turf(user),'sound/effects/phasein.ogg',50,1) + . = TOPIC_REFRESH + + else if(href_list["reset"]) + var/area/wizard_station/A = get_area(user) + if(istype(A)) + uses = spellbook.max_uses + investing_time = 0 + has_sacrificed = 0 + user.spellremove() + temp = "All spells and investments have been removed. You may now memorize a new set of spells." + feedback_add_details("wizard_spell_learned","UM") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells + else + to_chat(user, "You must be in the wizard academy to re-memorize your spells.") + . = TOPIC_REFRESH + + src.interact(user) + +/obj/item/weapon/spellbook/proc/invest() + if(uses < 1) + return "You don't have enough slots to invest!" + if(investing_time) + return "You can only invest one spell slot at a time." + uses-- + START_PROCESSING(SSobj, src) + investing_time = world.time + (15 MINUTES) + return "You invest a spellslot and will recieve two in return in 15 minutes." + +/obj/item/weapon/spellbook/Process() + if(investing_time && investing_time <= world.time) + src.visible_message("\The [src] emits a soft chime.") + uses += 2 + if(uses > spellbook.max_uses) + spellbook.max_uses = uses + investing_time = 0 + STOP_PROCESSING(SSobj, src) + return 1 + +/obj/item/weapon/spellbook/Destroy() + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/item/weapon/spellbook/proc/send_feedback(var/path) + if(ispath(path,/datum/spellbook)) + var/datum/spellbook/S = path + feedback_add_details("wizard_spell_learned","[initial(S.feedback)]") + else if(ispath(path,/spell)) + var/spell/S = path + feedback_add_details("wizard_spell_learned","[initial(S.feedback)]") + else if(ispath(path,/obj)) + feedback_add_details("wizard_spell_learned","[artefact_feedback[path]]") + + +/obj/item/weapon/spellbook/proc/add_spell(var/mob/user, var/spell_path) + for(var/spell/S in user.mind.learned_spells) + if(istype(S,spell_path)) + if(!S.can_improve()) + return + if(S.can_improve(Sp_SPEED) && S.can_improve(Sp_POWER)) + switch(alert(user, "Do you want to upgrade this spell's speed or power?", "Spell upgrade", "Speed", "Power", "Cancel")) + if("Speed") + return S.quicken_spell() + if("Power") + return S.empower_spell() + else + return + else if(S.can_improve(Sp_POWER)) + return S.empower_spell() + else if(S.can_improve(Sp_SPEED)) + return S.quicken_spell() + + var/spell/S = new spell_path() + user.add_spell(S) + return "You learn the spell [S]" + +/datum/spellbook + var/name = "\improper Book of Tomes" + var/desc = "The legendary book of spells of the wizard." + var/book_desc = "Holds information on the various tomes available to a wizard" + var/feedback = "" //doesn't need one. + var/book_flags = NOREVERT + var/max_uses = 1 + var/title = "Book of Tomes" + var/title_desc = "This tome marks down all the available tomes for use. Choose wisely, there are no refunds." + var/list/spells = list(/datum/spellbook/standard = 1, + /datum/spellbook/cleric = 1, + /datum/spellbook/battlemage = 1, + /datum/spellbook/spatial = 1, + /datum/spellbook/druid = 1 + ) //spell's path = cost of spell + + var/list/sacrifice_reagents + var/list/sacrifice_objects diff --git a/code/modules/spells/spellbook/battlemage.dm b/code/modules/spells/spellbook/battlemage.dm new file mode 100644 index 00000000..97c580d0 --- /dev/null +++ b/code/modules/spells/spellbook/battlemage.dm @@ -0,0 +1,35 @@ +//Battlemage is all about mixing physical with the mystical in head to head combat. +//Things like utility and mobility come second. +/datum/spellbook/battlemage + name = "\improper Battlemage's Bible" + feedback = "BM" + desc = "Smells like blood." + book_desc = "Mix physical with the mystical in head to head combat." + title = "The Art of Magical Combat" + title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent." + book_flags = CAN_MAKE_CONTRACTS|INVESTABLE + max_uses = 6 + + spells = list(/spell/targeted/projectile/dumbfire/passage = 1, + /spell/targeted/equip_item/dyrnwyn = 1, + /spell/targeted/equip_item/shield = 1, + /spell/targeted/projectile/dumbfire/fireball = 1, + /spell/targeted/torment = 1, + /spell/targeted/heal_target = 2, + /spell/targeted/genetic/mutate = 1, + /spell/aoe_turf/conjure/mirage = 1, + /spell/targeted/shapeshift/corrupt_form = 1, + /spell/radiant_aura = 1, + /spell/noclothes = 1, + /obj/structure/closet/wizard/armor = 1, + /obj/item/weapon/gun/energy/staff/focus = 1, + /obj/item/weapon/dice/d20/cursed = 1, + /obj/item/weapon/monster_manual = 2, + /obj/item/weapon/magic_rock = 1, + /obj/item/weapon/contract/wizard/xray = 1, + /obj/item/weapon/contract/wizard/telepathy = 1, + /obj/item/weapon/contract/apprentice = 1 + ) + + sacrifice_objects = list(/obj/item/weapon/material/sword, + /obj/item/weapon/material/twohanded/fireaxe) \ No newline at end of file diff --git a/code/modules/spells/spellbook/cleric.dm b/code/modules/spells/spellbook/cleric.dm new file mode 100644 index 00000000..3a991fdf --- /dev/null +++ b/code/modules/spells/spellbook/cleric.dm @@ -0,0 +1,38 @@ +//Cleric is all about healing. Mobility and offense comes at a higher price but not impossible. +/obj/item/weapon/spellbook/cleric + spellbook_type = /datum/spellbook/cleric + +/datum/spellbook/cleric + name = "\improper Cleric's Tome" + feedback = "CR" + desc = "For those who do not harm, or at least feel sorry about it." + book_desc = "All about healing. Mobility and offense comes at a higher price but not impossible." + title = "Cleric's Tome of Healing" + title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent." + book_flags = CAN_MAKE_CONTRACTS|INVESTABLE + max_uses = 7 + + spells = list(/spell/targeted/heal_target/major = 1, + /spell/targeted/heal_target/area = 1, + /spell/targeted/heal_target/sacrifice = 1, + /spell/targeted/genetic/blind = 1, + /spell/targeted/shapeshift/baleful_polymorph = 1, + /spell/targeted/projectile/dumbfire/stuncuff = 1, + /spell/targeted/ethereal_jaunt = 2, + /spell/aoe_turf/knock = 1, + /spell/radiant_aura = 1, + /spell/targeted/equip_item/holy_relic = 1, + /spell/aoe_turf/conjure/grove/sanctuary = 1, + /spell/targeted/projectile/dumbfire/fireball = 2, + /spell/area_teleport = 2, + /spell/aoe_turf/conjure/forcewall = 1, + /spell/noclothes = 1, + /obj/item/weapon/magic_rock = 1, + /obj/structure/closet/wizard/scrying = 2, + /obj/item/weapon/contract/wizard/telepathy = 1, + /obj/item/weapon/contract/apprentice = 1 + ) + + sacrifice_reagents = list(/datum/reagent/peridaxon, + /datum/reagent/adminordrazine) + sacrifice_objects = list(/obj/item/seeds/mtearseed) diff --git a/code/modules/spells/spellbook/druid.dm b/code/modules/spells/spellbook/druid.dm new file mode 100644 index 00000000..87af5597 --- /dev/null +++ b/code/modules/spells/spellbook/druid.dm @@ -0,0 +1,37 @@ +//all about the summons, nature, and a bit o' healin. + +/obj/item/weapon/spellbook/druid + spellbook_type = /datum/spellbook/druid + +/datum/spellbook/druid + name = "\improper Druid's Leaflet" + feedback = "DL" + desc = "It smells like an air freshener." + book_desc = "Summons, nature, and a bit o' healin." + title = "Druidic Guide on how to be smug about nature" + title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent." + book_flags = CAN_MAKE_CONTRACTS|INVESTABLE + max_uses = 6 + + spells = list(/spell/targeted/heal_target = 1, + /spell/targeted/heal_target/sacrifice = 1, + /spell/aoe_turf/conjure/mirage = 1, + /spell/aoe_turf/conjure/summon/bats = 1, + /spell/aoe_turf/conjure/summon/bear = 1, + /spell/targeted/equip_item/party_hardy = 1, + /spell/targeted/equip_item/seed = 1, + /spell/targeted/shapeshift/avian = 1, + /spell/aoe_turf/disable_tech = 1, + /spell/hand/charges/entangle = 1, + /spell/aoe_turf/conjure/grove/sanctuary = 1, + /spell/aoe_turf/knock = 1, + /spell/area_teleport = 2, + /spell/noclothes = 1, + /obj/structure/closet/wizard/souls = 1, + /obj/item/weapon/magic_rock = 1, + /obj/item/weapon/monster_manual = 1, + /obj/item/weapon/contract/wizard/telepathy = 1, + /obj/item/weapon/contract/apprentice = 1 + ) + sacrifice_objects = list(/obj/item/seeds/ambrosiavulgarisseed, + /obj/item/seeds/ambrosiadeusseed) diff --git a/code/modules/spells/spellbook/spatial.dm b/code/modules/spells/spellbook/spatial.dm new file mode 100644 index 00000000..55b8aa70 --- /dev/null +++ b/code/modules/spells/spellbook/spatial.dm @@ -0,0 +1,39 @@ +//all about moving around and mobility and being an annoying shit. + +/obj/item/weapon/spellbook/spatial + spellbook_type = /datum/spellbook/spatial + +/datum/spellbook/spatial + name = "\improper Spatial Manual" + feedback = "SP" + desc = "You feel like this might disappear from out of under you." + book_desc = "Movement and teleportation. Run from your problems!" + title = "Manual of Spatial Transportation" + title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent." + book_flags = CAN_MAKE_CONTRACTS|INVESTABLE + max_uses = 11 + + spells = list(/spell/targeted/ethereal_jaunt = 1, + /spell/aoe_turf/blink = 1, + /spell/area_teleport = 1, + /spell/targeted/projectile/dumbfire/passage = 1, + /spell/mark_recall = 1, + /spell/targeted/swap = 1, + /spell/targeted/shapeshift/avian = 1, + /spell/targeted/projectile/magic_missile = 1, + /spell/targeted/heal_target = 1, + /spell/aoe_turf/conjure/forcewall = 1, + /spell/aoe_turf/smoke = 1, + /spell/aoe_turf/conjure/summon/bats = 3, + /spell/noclothes = 1, + /obj/item/weapon/contract/wizard/tk = 5, + /obj/item/weapon/dice/d20/cursed = 1, + /obj/structure/closet/wizard/scrying = 2, + /obj/item/weapon/teleportation_scroll = 1, + /obj/item/weapon/magic_rock = 1, + /obj/item/weapon/contract/wizard/telepathy = 1, + /obj/item/weapon/contract/apprentice = 1 + ) + + sacrifice_reagents = list(/datum/reagent/hyperzine) + sacrifice_objects = list(/obj/item/stack/telecrystal) \ No newline at end of file diff --git a/code/modules/spells/spellbook/standard.dm b/code/modules/spells/spellbook/standard.dm new file mode 100644 index 00000000..b6c1433a --- /dev/null +++ b/code/modules/spells/spellbook/standard.dm @@ -0,0 +1,40 @@ +//the spellbook we know and love. Well, the one we know, at least. + +/obj/item/weapon/spellbook/standard + spellbook_type = /datum/spellbook/standard + +/datum/spellbook/standard + name = "\improper Standard Spellbook" + feedback = "SB" + title = "Book of Spells and Artefacts" + title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent." + book_desc = "A general wizard's spellbook. All its spells are easy to use but hard to master." + book_flags = CAN_MAKE_CONTRACTS|INVESTABLE + max_uses = 6 + + spells = list(/spell/targeted/projectile/magic_missile = 1, + /spell/targeted/projectile/dumbfire/fireball = 1, + /spell/aoe_turf/disable_tech = 1, + /spell/aoe_turf/smoke = 1, + /spell/targeted/genetic/blind = 1, + /spell/targeted/subjugation = 1, + /spell/aoe_turf/conjure/forcewall = 1, + /spell/aoe_turf/blink = 1, + /spell/area_teleport = 1, + /spell/targeted/genetic/mutate = 1, + /spell/targeted/ethereal_jaunt = 1, + /spell/targeted/heal_target = 1, + /spell/aoe_turf/knock = 1, + /spell/noclothes = 2, + /obj/item/weapon/gun/energy/staff/focus = 1, + /obj/structure/closet/wizard/souls = 1, + /obj/item/weapon/gun/energy/staff/animate = 1, + /obj/structure/closet/wizard/scrying = 1, + /obj/item/weapon/monster_manual = 2, + /obj/item/weapon/magic_rock = 1, + /obj/item/weapon/contract/wizard/telepathy = 1, + /obj/item/weapon/contract/apprentice = 1 + ) + + sacrifice_objects = list(/obj/item/stack/material/gold, + /obj/item/stack/material/silver) \ No newline at end of file diff --git a/code/modules/spells/spellbook/student.dm b/code/modules/spells/spellbook/student.dm new file mode 100644 index 00000000..44a7a974 --- /dev/null +++ b/code/modules/spells/spellbook/student.dm @@ -0,0 +1,21 @@ +//wizard's training wheels. Basically. Same shit as in the general one. + +/obj/item/weapon/spellbook/student + spellbook_type = /datum/spellbook/student + +/datum/spellbook/student + name = "\improper Student's Spellbook" + feedback = "ST" + desc = "This spell book has a sticker on it that says, 'certified for children 5 and older'." + book_desc = "This spellbook is dedicated to teaching neophytes in the ways of magic." + title = "Book of Spells and Education" + title_desc = "Hello. Congratulations on becoming a wizard. You may be asking yourself: What? A wizard? Already? Of course! Anybody can become a wizard! Learning to be a good one is the hard part.
                Without further adue, let us begin by learning the three concepts of wizardry, 'Spell slots', 'Spells', and 'Artifacts'.
                Firstly lets try to understand the 'spell slot'. A spell slot is the measurable amount of spells and artifacts one tome can give. Most spells will only take up a singular spell slot, however more powerful spells/artifacts can take up more.
                Spells are spells. They can have requirements, such as wizard garb, and most can be upgraded by purchasing additional spell slots for them. Most upgrades fall into two categories, 'Speed' and 'Power'. Speed upgrades decrease the time you have to spend recharging your spell. Power increases the potency of your spells. Spells are also special in that they can be refunded while inside the Wizard Acadamy, so if you want to test a spell out before moving out into the field, feel free to do that in the comfort of our home.
                Artifacts, or 'Artefacts' as we call them, are powerful wizard tools or items made specially for wizards everywhere. Extremely potent, they cannot be refunded like spells, and some of them can be used by non-wizards, so be careful!
                Knowing these three concepts puts you in a league above most wizards, however knowledge of spells is just as important so we've included a list of spells below made specifically for the beginning wizard. Take all of them, or mix and match, remember being creative is half of being a wizard!" + book_flags = CAN_MAKE_CONTRACTS|INVESTABLE + max_uses = 5 + + spells = list(/spell/aoe_turf/knock = 1, + /spell/targeted/ethereal_jaunt = 1, + /spell/targeted/projectile/magic_missile = 1, + /obj/item/weapon/gun/energy/staff/focus = 1, + /obj/item/weapon/contract/wizard/xray = 1 + ) \ No newline at end of file diff --git a/code/modules/spells/spells.dm b/code/modules/spells/spells.dm new file mode 100644 index 00000000..cde9475a --- /dev/null +++ b/code/modules/spells/spells.dm @@ -0,0 +1,71 @@ +/datum/mind + var/list/learned_spells + +/mob/Stat() + . = ..() + if(. && ability_master && ability_master.spell_objects) + for(var/obj/screen/ability/spell/screen in ability_master.spell_objects) + var/spell/S = screen.spell + if((!S.connected_button) || !statpanel(S.panel)) + continue //Not showing the noclothes spell + switch(S.charge_type) + if(Sp_RECHARGE) + statpanel(S.panel,"[S.charge_counter/10.0]/[S.charge_max/10]",S.connected_button) + if(Sp_CHARGES) + statpanel(S.panel,"[S.charge_counter]/[S.charge_max]",S.connected_button) + if(Sp_HOLDVAR) + statpanel(S.panel,"[S.holder_var_type] [S.holder_var_amount]",S.connected_button) + +//A fix for when a spell is created before a mob is created +/mob/Login() + . = ..() + if(mind) + if(!mind.learned_spells) + mind.learned_spells = list() + if(ability_master && ability_master.spell_objects) + for(var/obj/screen/ability/spell/screen in ability_master.spell_objects) + var/spell/S = screen.spell + mind.learned_spells |= S + +proc/restore_spells(var/mob/H) + if(H.mind && H.mind.learned_spells) + var/list/spells = list() + for(var/spell/spell_to_remove in H.mind.learned_spells) //remove all the spells from other people. + if(istype(spell_to_remove.holder,/mob)) + var/mob/M = spell_to_remove.holder + spells += spell_to_remove + M.remove_spell(spell_to_remove) + + for(var/spell/spell_to_add in spells) + H.add_spell(spell_to_add) + H.ability_master.update_abilities(0,H) + +/mob/proc/add_spell(var/spell/spell_to_add, var/spell_base = "wiz_spell_ready") + if(!ability_master) + ability_master = new() + spell_to_add.holder = src + if(mind) + if(!mind.learned_spells) + mind.learned_spells = list() + mind.learned_spells |= spell_to_add + ability_master.add_spell(spell_to_add, spell_base) + return 1 + +/mob/proc/remove_spell(var/spell/spell_to_remove) + if(!spell_to_remove || !istype(spell_to_remove)) + return + + if(mind) + mind.learned_spells -= spell_to_remove + if (ability_master) + ability_master.remove_ability(ability_master.get_ability_by_spell(spell_to_remove)) + return 1 + +/mob/proc/silence_spells(var/amount = 0) + if(amount < 0) + return + + if(!ability_master) + return + + ability_master.silence_spells(amount) \ No newline at end of file diff --git a/code/modules/spells/targeted/cleric_spells.dm b/code/modules/spells/targeted/cleric_spells.dm new file mode 100644 index 00000000..7e73a39c --- /dev/null +++ b/code/modules/spells/targeted/cleric_spells.dm @@ -0,0 +1,117 @@ +/spell/targeted/heal_target + name = "Cure Light Wounds" + desc = "a rudimentary spell used mainly by wizards to heal papercuts. Does not require wizard garb." + feedback = "CL" + school = "transmutation" + charge_max = 200 + spell_flags = INCLUDEUSER | SELECTABLE + invocation = "Di'Nath!" + invocation_type = SpI_SHOUT + range = 2 + max_targets = 1 + level_max = list(Sp_TOTAL = 2, Sp_SPEED = 1, Sp_POWER = 2) + + cooldown_reduc = 50 + hud_state = "heal_minor" + + amt_dam_brute = -15 + amt_dam_fire = -5 + + message = "You feel a pleasant rush of heat move through your body." + +/spell/targeted/heal_target/empower_spell() + if(!..()) + return 0 + amt_dam_brute -= 15 + amt_dam_fire -= 15 + + return "[src] will now heal more." + +/spell/targeted/heal_target/major + name = "Cure Major Wounds" + desc = "A spell used to fix others that cannot be fixed with regular medicine." + feedback = "CM" + charge_max = 300 + spell_flags = INCLUDEUSER | SELECTABLE | NEEDSCLOTHES + invocation = "Borv Di'Nath!" + range = 1 + level_max = list(Sp_TOTAL = 2, Sp_SPEED = 1, Sp_POWER = 1) + cooldown_reduc = 100 + hud_state = "heal_major" + + amt_dam_brute = -75 + amt_dam_fire = -50 + amt_blood = 28 + + message = "Your body feels like a furnace." + +/spell/targeted/heal_target/major/empower_spell() + if(!..()) + return 0 + amt_blood = 28 + amt_organ = 5 + amt_brain = -5 + amt_radiation = -25 + amt_dam_tox = -20 + amt_dam_oxy = -14 + amt_dam_brute = -35 + amt_dam_fire = -35 + + return "[src] heals more, and heals organ damage and radiation." + +/spell/targeted/heal_target/area + name = "Cure Area" + desc = "This spell heals everyone in an area." + feedback = "HA" + charge_max = 600 + spell_flags = INCLUDEUSER + invocation = "Nal Di'Nath!" + range = 2 + max_targets = 0 + level_max = list(Sp_TOTAL = 1, Sp_SPEED = 1, Sp_POWER = 1) + cooldown_reduc = 300 + hud_state = "heal_area" + + amt_dam_brute = -25 + amt_dam_fire = -25 + +/spell/targeted/heal_target/area/empower_spell() + if(!..()) + return 0 + amt_dam_brute -= 15 + amt_dam_fire -= 15 + range += 2 + + return "[src] now heals more in a wider area." + + +/spell/targeted/heal_target/sacrifice + name = "Sacrifice" + desc = "This spell heals immensily. For a price. Does not require wizard garb." + feedback = "SF" + spell_flags = SELECTABLE + invocation = "Ei'Nath Borv Di'Nath!" + charge_type = Sp_HOLDVAR + holder_var_type = "fireloss" + holder_var_amount = 100 + level_max = list(Sp_TOTAL = 1, Sp_SPEED = 0, Sp_POWER = 1) + + amt_dam_brute = -1000 + amt_dam_fire = -1000 + amt_dam_oxy = -100 + amt_dam_tox = -100 + amt_blood = 280 + + hud_state = "gen_dissolve" + +/spell/targeted/heal_target/sacrifice/empower_spell() + if(!..()) + return 0 + + amt_organ = 25 + amt_brain = -25 + amt_radiation = -100 + + + + return "You will now heal organ and brain damage, as well as virtually purge all radiation." \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/dyrnwyn.dm b/code/modules/spells/targeted/equip/dyrnwyn.dm new file mode 100644 index 00000000..9509dfd8 --- /dev/null +++ b/code/modules/spells/targeted/equip/dyrnwyn.dm @@ -0,0 +1,37 @@ +/spell/targeted/equip_item/dyrnwyn + name = "Summon Dyrnwyn" + desc = "Summons the legendary sword of Rhydderch Hael, said to draw in flame when held by a worthy man." + feedback = "SD" + charge_type = Sp_HOLDVAR + holder_var_type = "fireloss" + holder_var_amount = 10 + school = "conjuration" + invocation = "Anrhydeddu Fi!" + invocation_type = SpI_SHOUT + spell_flags = INCLUDEUSER + range = -1 + level_max = list(Sp_TOTAL = 1, Sp_SPEED = 0, Sp_POWER = 1) + duration = 300 //30 seconds + max_targets = 1 + equipped_summons = list("active hand" = /obj/item/weapon/material/sword) + delete_old = 0 + var/material = "gold" + + hud_state = "gen_immolate" + + +/spell/targeted/equip_item/dyrnwyn/summon_item(var/new_type) + var/obj/item/weapon/W = new new_type(null,material) + W.SetName("\improper Dyrnwyn") + W.damtype = BURN + W.hitsound = 'sound/items/welder2.ogg' + W.slowdown_per_slot[slot_l_hand] = 1 + W.slowdown_per_slot[slot_r_hand] = 1 + return W + +/spell/targeted/equip_item/dyrnwyn/empower_spell() + if(!..()) + return 0 + + material = "silver" + return "Dyrnwyn has been made pure: it is now made of silver." \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/equip.dm b/code/modules/spells/targeted/equip/equip.dm new file mode 100644 index 00000000..321b65f1 --- /dev/null +++ b/code/modules/spells/targeted/equip/equip.dm @@ -0,0 +1,45 @@ +//You can set duration to 0 to have the items last forever + +/spell/targeted/equip_item + name = "equipment spell" + + var/list/equipped_summons = list() //assoc list of text ids and paths to spawn + + var/list/summoned_items = list() //list of items we summoned and will dispose when the spell runs out + + var/delete_old = 1 //if the item previously in the slot is deleted - otherwise, it's dropped + +/spell/targeted/equip_item/cast(list/targets, mob/user = usr) + ..() + for(var/mob/living/L in targets) + for(var/slot_id in equipped_summons) + var/to_create = equipped_summons[slot_id] + if(cmptext(slot_id,"active hand")) + slot_id = (user.hand ? slot_l_hand : slot_r_hand) + else if(cmptext(slot_id, "off hand")) + slot_id = (user.hand ? slot_r_hand : slot_l_hand) + else + slot_id = text2num(slot_id) //because the index is text, we access this instead + var/obj/item/new_item = summon_item(to_create) + var/obj/item/old_item = L.get_equipped_item(slot_id) + L.equip_to_slot(new_item, slot_id) + if(old_item) + L.remove_from_mob(old_item) + if(delete_old) + qdel(old_item) + else + old_item.loc = L.loc + + if(duration) + summoned_items += new_item //we store it in a list to remove later + + if(duration) + spawn(duration) + for(var/obj/item/to_remove in summoned_items) + if(istype(to_remove.loc, /mob)) + var/mob/M = to_remove.loc + M.remove_from_mob(to_remove) + qdel(to_remove) + +/spell/targeted/equip_item/proc/summon_item(var/newtype) + return new newtype diff --git a/code/modules/spells/targeted/equip/holy_relic.dm b/code/modules/spells/targeted/equip/holy_relic.dm new file mode 100644 index 00000000..c8d3dc4e --- /dev/null +++ b/code/modules/spells/targeted/equip/holy_relic.dm @@ -0,0 +1,34 @@ +/spell/targeted/equip_item/holy_relic + name = "Summon Holy Relic" + desc = "This spell summons a relic of purity into your hand for a short while." + feedback = "SR" + school = "conjuration" + charge_type = Sp_RECHARGE + charge_max = 600 + spell_flags = NEEDSCLOTHES | INCLUDEUSER + invocation = "Yee'Ro Su!" + invocation_type = SpI_SHOUT + range = -1 + max_targets = 1 + level_max = list(Sp_TOTAL = 2, Sp_SPEED = 1, Sp_POWER = 1) + duration = 250 + cooldown_min = 350 + delete_old = 0 + compatible_mobs = list(/mob/living/carbon/human) + + hud_state = "purge1" + + equipped_summons = list("active hand" = /obj/item/weapon/nullrod) + +/spell/targeted/equip_item/holy_relic/cast(list/targets, mob/user = usr) + ..() + for(var/mob/M in targets) + M.visible_message("A rod of metal appears in \the [M]'s hand!") + +/spell/targeted/equip_item/holy_relic/empower_spell() + if(!..()) + return 0 + + duration += 50 + + return "The holy relic now lasts for [duration/10] seconds." \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/horsemask.dm b/code/modules/spells/targeted/equip/horsemask.dm new file mode 100644 index 00000000..5ad498c3 --- /dev/null +++ b/code/modules/spells/targeted/equip/horsemask.dm @@ -0,0 +1,47 @@ +/spell/targeted/equip_item/horsemask + name = "Curse of the Horseman" + desc = "This spell triggers a curse on a target, causing them to wield an unremovable horse head mask. They will speak like a horse! Any masks they are wearing will be disintegrated. This spell does not require robes." + school = "transmutation" + charge_type = Sp_RECHARGE + charge_max = 150 + charge_counter = 0 + spell_flags = 0 + invocation = "Kn'a Ftaghu, Puck'Bthnk!" + invocation_type = SpI_SHOUT + range = 7 + max_targets = 1 + level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 1) + cooldown_min = 30 //30 deciseconds reduction per rank + selection_type = "range" + + compatible_mobs = list(/mob/living/carbon/human) + + hud_state = "wiz_horse" + +/spell/targeted/equip_item/horsemask/New() + ..() + equipped_summons = list("[slot_wear_mask]" = /obj/item/clothing/mask/horsehead) + +/spell/targeted/equip_item/horsemask/cast(list/targets, mob/user = usr) + ..() + for(var/mob/living/target in targets) + target.visible_message( "[target]'s face lights up in fire, and after the event a horse's head takes its place!", \ + "Your face burns up, and shortly after the fire you realise you have the face of a horse!") + target.flash_eyes() + +/spell/targeted/equip_item/horsemask/summon_item(var/new_type) + var/obj/item/new_item = new new_type + new_item.canremove = 0 //curses! + if(istype(new_item, /obj/item/clothing/mask/horsehead)) + var/obj/item/clothing/mask/horsehead/magichead = new_item + magichead.flags_inv = null //so you can still see their face + magichead.voicechange = 1 //NEEEEIIGHH + return new_item + +/spell/targeted/equip_item/horsemask/empower_spell() + if(!..()) + return 0 + + spell_flags = SELECTABLE + + return "You can now select your target with [src]" \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/party_hardy.dm b/code/modules/spells/targeted/equip/party_hardy.dm new file mode 100644 index 00000000..e39590c4 --- /dev/null +++ b/code/modules/spells/targeted/equip/party_hardy.dm @@ -0,0 +1,36 @@ +/spell/targeted/equip_item/party_hardy + name = "Summon Party" + desc = "This spell was invented for the sole purpose of getting crunked at 11am on a Tuesday. Does not require wizard garb." + feedback = "PY" + school = "conjuration" + charge_type = Sp_RECHARGE + charge_max = 900 + cooldown_min = 600 + spell_flags = INCLUDEUSER + invocation = "Llet'Su G'iit Rrkned!" //Let's get wrecked. + invocation_type = SpI_SHOUT + range = 6 + max_targets = 0 + level_max = list(Sp_TOTAL = 3, Sp_SPEED = 1, Sp_POWER = 2) + delete_old = 0 + + hud_state = "wiz_party" + + compatible_mobs = list(/mob/living/carbon/human) + equipped_summons = list("active hand" = /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer) + +/spell/targeted/equip_item/party_hardy/empower_spell() + if(!..()) + return 0 + switch(spell_levels[Sp_POWER]) + if(1) + equipped_summons = list("active hand" = /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer, + "off hand" = /obj/item/weapon/reagent_containers/food/snacks/poppypretzel) + return "The spell will now give everybody a preztel as well." + if(2) + equipped_summons = list("active hand" = /obj/item/weapon/reagent_containers/food/drinks/bottle/absinthe, + "off hand" = /obj/item/weapon/reagent_containers/food/snacks/poppypretzel, + "[slot_head]" = /obj/item/clothing/head/collectable/wizard) + return "Woo! Now everybody gets a cool wizard hat and MORE BOOZE!" + + return 0 \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/seed.dm b/code/modules/spells/targeted/equip/seed.dm new file mode 100644 index 00000000..9b560b72 --- /dev/null +++ b/code/modules/spells/targeted/equip/seed.dm @@ -0,0 +1,21 @@ +/spell/targeted/equip_item/seed + name = "Summon Seed" + desc = "This spell summons a random seed into the hand of the wizard." + feedback = "SE" + delete_old = 0 + + spell_flags = INCLUDEUSER | NEEDSCLOTHES + invocation_type = SpI_WHISPER + invocation = "Ria'li akta." + + equipped_summons = list("active hand" = /obj/item/seeds/random) + compatible_mobs = list(/mob/living/carbon/human) + + charge_max = 600 //1 minute + cooldown_min = 200 //20 seconds + level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 0) + + range = -1 + max_targets = 1 + + hud_state = "wiz_seed" \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/shield.dm b/code/modules/spells/targeted/equip/shield.dm new file mode 100644 index 00000000..c143ca13 --- /dev/null +++ b/code/modules/spells/targeted/equip/shield.dm @@ -0,0 +1,41 @@ +/spell/targeted/equip_item/shield + name = "Summon Shield" + desc = "Summons the most holy of shields, the riot shield. Commonly used during wizard riots." + feedback = "SH" + school = "conjuration" + invocation = "Sia helda!" + invocation_type = SpI_SHOUT + spell_flags = INCLUDEUSER | NEEDSCLOTHES + range = -1 + max_targets = 1 + + compatible_mobs = list(/mob/living/carbon/human) + + level_max = list(Sp_TOTAL = 3, Sp_SPEED = 2, Sp_POWER = 1) + charge_type = Sp_RECHARGE + charge_max = 900 + cooldown_min = 300 + equipped_summons = list("off hand" = /obj/item/weapon/shield/) + duration = 300 + delete_old = 0 + var/item_color = "#6666ff" + var/block_chance = 30 + + hud_state = "wiz_shield" + +/spell/targeted/equip_item/shield/summon_item(var/new_type) + var/obj/item/weapon/shield/I = new new_type() + I.icon_state = "buckler" + I.color = item_color + I.SetName("Wizard's Shield") + I.base_block_chance = block_chance + return I + +/spell/targeted/equip_item/shield/empower_spell() + if(!..()) + return 0 + + item_color = "#6600ff" + block_chance = 60 + + return "Your summoned shields will now block more often." \ No newline at end of file diff --git a/code/modules/spells/targeted/ethereal_jaunt.dm b/code/modules/spells/targeted/ethereal_jaunt.dm new file mode 100644 index 00000000..684b57d9 --- /dev/null +++ b/code/modules/spells/targeted/ethereal_jaunt.dm @@ -0,0 +1,116 @@ +/spell/targeted/ethereal_jaunt + name = "Ethereal Jaunt" + desc = "This spell creates your ethereal form, temporarily making you invisible and able to pass through walls." + feedback = "EJ" + school = "transmutation" + charge_max = 300 + spell_flags = Z2NOCAST | NEEDSCLOTHES | INCLUDEUSER + invocation = "none" + invocation_type = SpI_NONE + range = -1 + max_targets = 1 + level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 3) + cooldown_min = 100 //50 deciseconds reduction per rank + duration = 50 //in deciseconds + + hud_state = "wiz_jaunt" + +/spell/targeted/ethereal_jaunt/cast(list/targets) //magnets, so mostly hardcoded + for(var/mob/living/target in targets) + target.transforming = 1 //protects the mob from being transformed (replaced) midjaunt and getting stuck in bluespace + if(target.buckled) + target.buckled.unbuckle_mob() + spawn(0) + var/mobloc = get_turf(target.loc) + var/obj/effect/dummy/spell_jaunt/holder = new /obj/effect/dummy/spell_jaunt( mobloc ) + var/atom/movable/overlay/animation = new /atom/movable/overlay( mobloc ) + animation.SetName("water") + animation.set_density(0) + animation.anchored = 1 + animation.icon = 'icons/mob/mob.dmi' + animation.layer = 5 + animation.master = holder + target.ExtinguishMob() + if(target.buckled) + target.buckled = null + jaunt_disappear(animation, target) + target.loc = holder + target.transforming=0 //mob is safely inside holder now, no need for protection. + jaunt_steam(mobloc) + sleep(duration) + mobloc = holder.last_valid_turf + animation.loc = mobloc + jaunt_steam(mobloc) + target.canmove = 0 + holder.reappearing = 1 + sleep(20) + jaunt_reappear(animation, target) + sleep(5) + if(!target.forceMove(mobloc)) + for(var/direction in list(1,2,4,8,5,6,9,10)) + var/turf/T = get_step(mobloc, direction) + if(T) + if(target.forceMove(T)) + break + target.canmove = 1 + target.client.eye = target + qdel(animation) + qdel(holder) + + +/spell/targeted/ethereal_jaunt/empower_spell() + if(!..()) + return 0 + duration += 20 + + return "[src] now lasts longer." + +/spell/targeted/ethereal_jaunt/proc/jaunt_disappear(var/atom/movable/overlay/animation, var/mob/living/target) + animation.icon_state = "liquify" + flick("liquify",animation) + +/spell/targeted/ethereal_jaunt/proc/jaunt_reappear(var/atom/movable/overlay/animation, var/mob/living/target) + flick("reappear",animation) + +/spell/targeted/ethereal_jaunt/proc/jaunt_steam(var/mobloc) + var/datum/effect/effect/system/steam_spread/steam = new /datum/effect/effect/system/steam_spread() + steam.set_up(10, 0, mobloc) + steam.start() + +/obj/effect/dummy/spell_jaunt + name = "water" + icon = 'icons/effects/effects.dmi' + icon_state = "nothing" + var/canmove = 1 + var/reappearing = 0 + density = 0 + anchored = 1 + var/turf/last_valid_turf + +/obj/effect/dummy/spell_jaunt/New(var/location) + ..() + last_valid_turf = get_turf(location) + +/obj/effect/dummy/spell_jaunt/Destroy() + // Eject contents if deleted somehow + for(var/atom/movable/AM in src) + AM.loc = get_turf(src) + return ..() + +/obj/effect/dummy/spell_jaunt/relaymove(var/mob/user, direction) + if (!src.canmove || reappearing) return + var/turf/newLoc = get_step(src,direction) + if(!(newLoc.turf_flags & TURF_FLAG_NOJAUNT)) + loc = newLoc + var/turf/T = get_turf(loc) + if(!T.contains_dense_objects()) + last_valid_turf = T + else + to_chat(user, "Some strange aura is blocking the way!") + src.canmove = 0 + spawn(2) src.canmove = 1 + +/obj/effect/dummy/spell_jaunt/ex_act(blah) + return +/obj/effect/dummy/spell_jaunt/bullet_act(blah) + return \ No newline at end of file diff --git a/code/modules/spells/targeted/genetic.dm b/code/modules/spells/targeted/genetic.dm new file mode 100644 index 00000000..c8900a9b --- /dev/null +++ b/code/modules/spells/targeted/genetic.dm @@ -0,0 +1,81 @@ +/* +Other mutation or disability spells can be found in +code\game\dna\genes\vg_powers.dm //hulk is in this file +code\game\dna\genes\goon_disabilities.dm +code\game\dna\genes\goon_powers.dm +*/ +/spell/targeted/genetic + name = "Genetic modifier" + desc = "This spell inflicts a set of mutations and disabilities upon the target." + + var/disabilities = 0 //bits + var/list/mutations = list() //mutation strings + duration = 100 //deciseconds + + +/spell/targeted/genetic/cast(list/targets) + ..() + for(var/mob/living/target in targets) + for(var/x in mutations) + target.mutations.Add(x) + target.disabilities |= disabilities + target.update_mutations() //update target's mutation overlays + spawn(duration) + for(var/x in mutations) + target.mutations.Remove(x) + target.disabilities &= ~disabilities + target.update_mutations() + return + +/spell/targeted/genetic/blind + name = "Blind" + desc = "This spell inflicts a target with temporary blindness. Does not require wizard garb." + feedback = "BD" + disabilities = 1 + school = "illusion" + duration = 300 + + charge_max = 300 + + spell_flags = 0 + invocation = "Sty Kaly." + invocation_type = SpI_WHISPER + message = "Your eyes cry out in pain!" + level_max = list(Sp_TOTAL = 3, Sp_SPEED = 1, Sp_POWER = 3) + cooldown_min = 50 + + range = 7 + max_targets = 0 + + amt_eye_blind = 10 + amt_eye_blurry = 20 + + hud_state = "wiz_blind" + +/spell/targeted/genetic/blind/empower_spell() + if(!..()) + return 0 + duration += 100 + + return "[src] will now blind for a longer period of time." + +/spell/targeted/genetic/mutate + name = "Mutate" + desc = "This spell causes you to turn into a hulk and gain laser vision for a short while." + feedback = "MU" + school = "transmutation" + charge_max = 400 + spell_flags = Z2NOCAST | NEEDSCLOTHES | INCLUDEUSER + invocation = "BIRUZ BENNAR" + invocation_type = SpI_SHOUT + message = "You feel strong! You feel a pressure building behind your eyes!" + range = 0 + max_targets = 1 + + mutations = list(LASER, HULK) + duration = 300 + + level_max = list(Sp_TOTAL = 1, Sp_SPEED = 1, Sp_POWER = 0) + cooldown_min = 300 + + hud_state = "wiz_hulk" diff --git a/code/modules/spells/targeted/harvest.dm b/code/modules/spells/targeted/harvest.dm new file mode 100644 index 00000000..840fd47b --- /dev/null +++ b/code/modules/spells/targeted/harvest.dm @@ -0,0 +1,37 @@ +/spell/targeted/harvest + name = "Harvest" + desc = "Back to where I come from, and you're coming with me." + + school = "transmutation" + charge_max = 200 + spell_flags = Z2NOCAST | CONSTRUCT_CHECK | INCLUDEUSER + invocation = "" + invocation_type = SpI_NONE + range = 0 + max_targets = 0 + + overlay = 1 + overlay_icon = 'icons/effects/effects.dmi' + overlay_icon_state = "rune_teleport" + overlay_lifespan = 0 + + hud_state = "const_harvest" + +/spell/targeted/harvest/cast(list/targets, mob/user)//because harvest is already a proc + ..() + + var/destination = null + for(var/obj/singularity/narsie/large/N in narsie_list) + destination = N.loc + break + if(destination) + var/prey = 0 + for(var/mob/living/M in targets) + if(!findNullRod(M)) + M.forceMove(destination) + if(M != user) + prey = 1 + to_chat(user, "You warp back to Nar-Sie[prey ? " along with your prey":""].") + else + to_chat(user, "...something's wrong!")//There shouldn't be an instance of Harvesters when Nar-Sie isn't in the world. + diff --git a/code/modules/spells/targeted/projectile/dumbfire.dm b/code/modules/spells/targeted/projectile/dumbfire.dm new file mode 100644 index 00000000..cd13f716 --- /dev/null +++ b/code/modules/spells/targeted/projectile/dumbfire.dm @@ -0,0 +1,13 @@ +/spell/targeted/projectile/dumbfire + name = "dumbfire spell" + +/spell/targeted/projectile/dumbfire/choose_targets(mob/user = usr) + var/list/targets = list() + + var/starting_dir = user.dir //where are we facing at the time of casting? + var/turf/starting_turf = get_turf(user) + var/current_turf = starting_turf + for(var/i = 1; i <= src.range; i++) + current_turf = get_step(current_turf, starting_dir) + targets += current_turf + return targets \ No newline at end of file diff --git a/code/modules/spells/targeted/projectile/fireball.dm b/code/modules/spells/targeted/projectile/fireball.dm new file mode 100644 index 00000000..ce1fa9dd --- /dev/null +++ b/code/modules/spells/targeted/projectile/fireball.dm @@ -0,0 +1,52 @@ +/spell/targeted/projectile/dumbfire/fireball + name = "Fireball" + desc = "This spell fires a fireball at a target and does not require wizard garb." + feedback = "FB" + proj_type = /obj/item/projectile/spell_projectile/fireball + + school = "conjuration" + charge_max = 100 + spell_flags = 0 + invocation = "Oni-Soma!" + invocation_type = SpI_SHOUT + range = 20 + + level_max = list(Sp_TOTAL = 5, Sp_SPEED = 0, Sp_POWER = 5) + + spell_flags = 0 + + duration = 20 + proj_step_delay = 1 + + amt_dam_brute = 20 + amt_dam_fire = 25 + + var/ex_severe = -1 + var/ex_heavy = 1 + var/ex_light = 2 + var/ex_flash = 5 + + hud_state = "wiz_fireball" + +/spell/targeted/projectile/dumbfire/fireball/prox_cast(var/list/targets, spell_holder) + for(var/mob/living/M in targets) + apply_spell_damage(M) + explosion(get_turf(spell_holder), ex_severe, ex_heavy, ex_light, ex_flash) + +/spell/targeted/projectile/dumbfire/fireball/empower_spell() + if(!..()) + return 0 + + if(spell_levels[Sp_POWER]%2 == 1) + ex_severe++ + ex_heavy++ + ex_light++ + ex_flash++ + + return "The spell [src] now has a larger explosion." + +//PROJECTILE + +/obj/item/projectile/spell_projectile/fireball + name = "fireball" + icon_state = "fireball" \ No newline at end of file diff --git a/code/modules/spells/targeted/projectile/magic_missile.dm b/code/modules/spells/targeted/projectile/magic_missile.dm new file mode 100644 index 00000000..d76a410c --- /dev/null +++ b/code/modules/spells/targeted/projectile/magic_missile.dm @@ -0,0 +1,56 @@ +/spell/targeted/projectile/magic_missile + name = "Magic Missile" + desc = "This spell fires several, slow moving, magic projectiles at nearby targets." + feedback = "MM" + school = "conjuration" + charge_max = 150 + spell_flags = NEEDSCLOTHES + invocation = "Forti Gy-Ama!" + invocation_type = SpI_SHOUT + range = 7 + level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 3) + cooldown_min = 90 //15 deciseconds reduction per rank + + max_targets = 0 + + proj_type = /obj/item/projectile/spell_projectile/seeking/magic_missile + duration = 10 + proj_step_delay = 5 + + hud_state = "wiz_mm" + + amt_paralysis = 3 + amt_stunned = 3 + + amt_dam_fire = 10 + cast_prox_range = 0 + +/spell/targeted/projectile/magic_missile/prox_cast(var/list/targets, atom/spell_holder) + spell_holder.visible_message("\The [spell_holder] pops with a flash!") + for(var/mob/living/M in targets) + apply_spell_damage(M) + return + +/spell/targeted/projectile/magic_missile/empower_spell() + if(!..()) + return 0 + + if(spell_levels[Sp_POWER] == level_max[Sp_POWER]) + amt_paralysis += 2 + amt_stunned += 2 + return "[src] will now stun people for a longer duration." + amt_dam_fire += 5 + + return "[src] does more damage now." + + + +//PROJECTILE + +/obj/item/projectile/spell_projectile/seeking/magic_missile + name = "magic missile" + icon_state = "magicm" + + proj_trail = 1 + proj_trail_lifespan = 5 + proj_trail_icon_state = "magicmd" diff --git a/code/modules/spells/targeted/projectile/passage.dm b/code/modules/spells/targeted/projectile/passage.dm new file mode 100644 index 00000000..fa1a0fb9 --- /dev/null +++ b/code/modules/spells/targeted/projectile/passage.dm @@ -0,0 +1,47 @@ +/spell/targeted/projectile/dumbfire/passage + name = "Passage" + desc = "throw a spell towards an area and teleport to it." + feedback = "PA" + proj_type = /obj/item/projectile/spell_projectile/passage + + + school = "conjuration" + charge_max = 250 + spell_flags = 0 + invocation = "A'YASAMA" + invocation_type = SpI_SHOUT + range = 15 + + + level_max = list(Sp_TOTAL = 1, Sp_SPEED = 0, Sp_POWER = 1) + spell_flags = NEEDSCLOTHES + duration = 15 + + proj_step_delay = 1 + + hud_state = "gen_project" + + +/spell/targeted/projectile/dumbfire/passage/prox_cast(var/list/targets, atom/spell_holder) + for(var/mob/living/L in targets) + apply_spell_damage(L) + + var/turf/T = get_turf(spell_holder) + + holder.forceMove(T) + var/datum/effect/effect/system/smoke_spread/S = new /datum/effect/effect/system/smoke_spread() + S.set_up(3,0,T) + S.start() + + +/spell/targeted/projectile/dumbfire/passage/empower_spell() + if(!..()) + return 0 + + amt_stunned += 3 + + return "[src] now stuns those who get hit by it." + +/obj/item/projectile/spell_projectile/passage + name = "spell" + icon_state = "energy2" \ No newline at end of file diff --git a/code/modules/spells/targeted/projectile/projectile.dm b/code/modules/spells/targeted/projectile/projectile.dm new file mode 100644 index 00000000..7fb6f818 --- /dev/null +++ b/code/modules/spells/targeted/projectile/projectile.dm @@ -0,0 +1,53 @@ +/* +Projectile spells make special projectiles (obj/item/spell_projectile) and fire them at targets +Dumbfire projectile spells fire directly ahead of the user +spell_projectiles call their spell's (carried) prox_cast when they get in range of a target +If the spell_projectile is seeking, it will update its target every process and follow them +*/ + +/spell/targeted/projectile + name = "projectile spell" + + range = 7 + + var/proj_type = /obj/item/projectile/spell_projectile //use these. They are very nice + + var/proj_step_delay = 1 //lower = faster + var/cast_prox_range = 1 + +/spell/targeted/projectile/cast(list/targets, mob/user = usr) + + if(istext(proj_type)) + proj_type = text2path(proj_type) // sanity filters + + for(var/atom/target in targets) + var/obj/item/projectile/projectile = new proj_type(user.loc, user.dir) + + if(!projectile) + return + + if(istype(projectile, /obj/item/projectile/spell_projectile)) + var/obj/item/projectile/spell_projectile/SP = projectile + SP.carried = src //casting is magical + projectile.original = target + projectile.starting = get_turf(user) + projectile.shot_from = user //fired from the user + //projectile.current = projectile.original + projectile.yo = target.y - user.y + projectile.xo = target.x - user.x + projectile.range = src.duration + projectile.hitscan = !proj_step_delay + projectile.speed = proj_step_delay + projectile.launch_projectile(target) + return + +/spell/targeted/projectile/proc/choose_prox_targets(mob/user = usr, var/atom/movable/spell_holder) + var/list/targets = list() + for(var/mob/living/M in range(spell_holder, cast_prox_range)) + if(M == user && !(spell_flags & INCLUDEUSER)) + continue + targets += M + return targets + +/spell/targeted/projectile/proc/prox_cast(var/list/targets, var/atom/movable/spell_holder) + return targets \ No newline at end of file diff --git a/code/modules/spells/targeted/projectile/stuncuff.dm b/code/modules/spells/targeted/projectile/stuncuff.dm new file mode 100644 index 00000000..67088106 --- /dev/null +++ b/code/modules/spells/targeted/projectile/stuncuff.dm @@ -0,0 +1,48 @@ +/spell/targeted/projectile/dumbfire/stuncuff + name = "Stun Cuff" + desc = "This spell fires out a small curse that stuns and cuffs the target." + feedback = "SC" + proj_type = /obj/item/projectile/spell_projectile/stuncuff + + charge_type = Sp_CHARGES + charge_max = 6 + charge_counter = 6 + spell_flags = 0 + invocation = "Fu'Reai Diakan!" + invocation_type = SpI_SHOUT + range = 20 + + level_max = list(Sp_TOTAL = 0, Sp_SPEED = 0, Sp_POWER = 0) + + duration = 20 + proj_step_delay = 1 + + amt_stunned = 6 + + hud_state = "wiz_cuff" + +/spell/targeted/projectile/dumbfire/stuncuff/prox_cast(var/list/targets, spell_holder) + for(var/mob/living/M in targets) + if(istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/obj/item/weapon/handcuffs/wizard/cuffs = new() + cuffs.forceMove(H) + H.handcuffed = cuffs + H.update_inv_handcuffed() + H.visible_message("Beams of light form around \the [H]'s hands!") + apply_spell_damage(M) + + +/obj/item/weapon/handcuffs/wizard + name = "beams of light" + desc = "Undescribable and unpenetrable. Or so they say." + + breakouttime = 300 //30 seconds + +/obj/item/weapon/handcuffs/wizard/dropped(var/mob/user) + ..() + qdel(src) + +/obj/item/projectile/spell_projectile/stuncuff + name = "stuncuff" + icon_state = "spell" \ No newline at end of file diff --git a/code/modules/spells/targeted/shapeshift.dm b/code/modules/spells/targeted/shapeshift.dm new file mode 100644 index 00000000..27228388 --- /dev/null +++ b/code/modules/spells/targeted/shapeshift.dm @@ -0,0 +1,181 @@ +//basic transformation spell. Should work for most simple_animals + +/spell/targeted/shapeshift + name = "Shapeshift" + desc = "This spell transforms the target into something else for a short while." + + school = "transmutation" + + charge_type = Sp_RECHARGE + charge_max = 600 + + duration = 0 //set to 0 for permanent. + + var/list/possible_transformations = list() + var/list/newVars = list() //what the variables of the new created thing will be. + + cast_sound = 'sound/weapons/emitter2.ogg' + var/revert_sound = 'sound/weapons/emitter.ogg' //the sound that plays when something gets turned back. + var/share_damage = 1 //do we want the damage we take from our new form to move onto our real one? (Only counts for finite duration) + var/drop_items = 1 //do we want to drop all our items when we transform? + var/list/transformed_dudes = list() //Who we transformed. Transformed = Transformation. Both mobs. + +/spell/targeted/shapeshift/cast(var/list/targets, mob/user) + for(var/mob/living/M in targets) + if(M.stat == DEAD) + to_chat(user, "[name] can only transform living targets.") + continue + if(M.buckled) + M.buckled.unbuckle_mob() + var/new_mob = pick(possible_transformations) + + var/mob/living/trans = new new_mob(get_turf(M)) + for(var/varName in newVars) //stolen shamelessly from Conjure + if(varName in trans.vars) + trans.vars[varName] = newVars[varName] + + trans.SetName("[trans.name] ([M])") + if(istype(M,/mob/living/carbon/human) && drop_items) + for(var/obj/item/I in M.contents) + if(istype(I,/obj/item/organ)) + continue + M.drop_from_inventory(I) + if(M.mind) + M.mind.transfer_to(trans) + else + trans.key = M.key + var/atom/movable/overlay/effect = new /atom/movable/overlay(get_turf(M)) + effect.set_density(0) + effect.anchored = 1 + effect.icon = 'icons/effects/effects.dmi' + effect.layer = 3 + flick("summoning",effect) + spawn(10) + qdel(effect) + M.forceMove(trans) //move inside the new dude to hide him. + M.status_flags |= GODMODE //dont want him to die or breathe or do ANYTHING + transformed_dudes[trans] = M + GLOB.death_event.register(trans,src,/spell/targeted/shapeshift/proc/stop_transformation) + GLOB.destroyed_event.register(trans,src,/spell/targeted/shapeshift/proc/stop_transformation) + GLOB.destroyed_event.register(M, src, /spell/targeted/shapeshift/proc/destroyed_transformer) + if(duration) + spawn(duration) + stop_transformation(trans) + +/spell/targeted/shapeshift/proc/destroyed_transformer(var/mob/target) //Juuuuust in case + var/mob/current = transformed_dudes[target] + to_chat(current, "You suddenly feel as if this transformation has become permanent...") + remove_target(target) + +/spell/targeted/shapeshift/proc/stop_transformation(var/mob/living/target) + var/mob/living/transformer = transformed_dudes[target] + if(!transformer) + return + transformer.status_flags &= ~GODMODE + if(share_damage) + var/ratio = target.health/target.maxHealth + var/damage = transformer.maxHealth - round(transformer.maxHealth*(ratio)) + for(var/i in 1 to ceil(damage/10)) + transformer.adjustBruteLoss(10) + if(target.mind) + target.mind.transfer_to(transformer) + else + transformer.key = target.key + playsound(get_turf(target), revert_sound, 50, 1) + transformer.forceMove(get_turf(target)) + remove_target(target) + qdel(target) + +/spell/targeted/shapeshift/proc/remove_target(var/mob/living/target) + var/mob/current = transformed_dudes[target] + GLOB.destroyed_event.unregister(target,src) + GLOB.death_event.unregister(current,src) + GLOB.destroyed_event.unregister(current,src) + transformed_dudes[target] = null + transformed_dudes -= target + +/spell/targeted/shapeshift/baleful_polymorph + name = "Baleful Polymorth" + desc = "This spell transforms its target into a small, furry animal." + feedback = "BP" + possible_transformations = list(/mob/living/simple_animal/lizard,/mob/living/simple_animal/mouse,/mob/living/simple_animal/corgi) + + share_damage = 0 + invocation = "Yo'balada!" + invocation_type = SpI_SHOUT + spell_flags = NEEDSCLOTHES | SELECTABLE + range = 3 + duration = 150 //15 seconds. + cooldown_min = 200 //20 seconds + + level_max = list(Sp_TOTAL = 2, Sp_SPEED = 2, Sp_POWER = 2) + + newVars = list("health" = 50, "maxHealth" = 50) + + hud_state = "wiz_poly" + + +/spell/targeted/shapeshift/baleful_polymorph/empower_spell() + if(!..()) + return 0 + + duration += 50 + + return "Your target will now stay in their polymorphed form for [duration/10] seconds." + +/spell/targeted/shapeshift/avian + name = "Polymorph" + desc = "This spell transforms the wizard into the common parrot." + feedback = "AV" + possible_transformations = list(/mob/living/simple_animal/parrot) + + drop_items = 0 + share_damage = 0 + invocation = "Poli'crakata!" + invocation_type = SpI_SHOUT + spell_flags = INCLUDEUSER + range = -1 + duration = 150 + charge_max = 600 + cooldown_min = 300 + level_max = list(Sp_TOTAL = 1, Sp_SPEED = 1, Sp_POWER = 0) + hud_state = "wiz_parrot" + +/spell/targeted/shapeshift/corrupt_form + name = "Corrupt Form" + desc = "This spell shapes the wizard into a terrible, terrible beast." + feedback = "CF" + possible_transformations = list(/mob/living/simple_animal/hostile/faithless) + + invocation = "mutters something dark and twisted as their form begins to twist..." + invocation_type = SpI_EMOTE + spell_flags = INCLUDEUSER + range = -1 + duration = 150 + charge_max = 1200 + cooldown_min = 600 + + drop_items = 0 + share_damage = 0 + level_max = list(Sp_TOTAL = 3, Sp_SPEED = 2, Sp_POWER = 2) + + newVars = list("name" = "corrupted soul") + + hud_state = "wiz_corrupt" + +/spell/targeted/shapeshift/corrupt_form/empower_spell() + if(!..()) + return 0 + + switch(spell_levels[Sp_POWER]) + if(1) + duration *= 2 + return "You will now stay corrupted for [duration/10] seconds." + if(2) + newVars = list("name" = "\proper corruption incarnate", + "melee_damage_upper" = 25, + "resistance" = 6, + "health" = 125, + "maxHealth" = 125) + duration = 0 + return "You revel in the corruption. There is no turning back." \ No newline at end of file diff --git a/code/modules/spells/targeted/shatter_mind.dm b/code/modules/spells/targeted/shatter_mind.dm new file mode 100644 index 00000000..d878c2a0 --- /dev/null +++ b/code/modules/spells/targeted/shatter_mind.dm @@ -0,0 +1,29 @@ +/spell/targeted/shatter + name = "Shatter Mind" + desc = "this spell allows the caster to literally break an enemy's mind. Permanently." + feedback = "SM" + school = "illusion" + charge_max = 300 + spell_flags = 0 + invocation_type = SpI_NONE + range = 5 + max_targets = 1 + compatible_mobs = list(/mob/living/carbon/human) + + time_between_channels = 150 + number_of_channels = 0 + + hud_state = "wiz_statue" + +/spell/targeted/shatter/cast(var/list/targets, var/mob/user) + var/mob/living/carbon/human/H = targets[1] + if(prob(50)) + sound_to(user, get_sfx("swing_hit")) + if(prob(5)) + to_chat(H, "You feel unhinged.") + H.adjust_hallucination(5,5) + H.confused += 2 + H.dizziness += 2 + if(H.hallucination_power > 50) + H.adjustBrainLoss(5) + to_chat(H, "You feel your mind tearing apart!") \ No newline at end of file diff --git a/code/modules/spells/targeted/shift.dm b/code/modules/spells/targeted/shift.dm new file mode 100644 index 00000000..8f8ef57e --- /dev/null +++ b/code/modules/spells/targeted/shift.dm @@ -0,0 +1,24 @@ +/spell/targeted/ethereal_jaunt/shift + name = "Phase Shift" + desc = "This spell allows you to pass through walls" + + charge_max = 200 + spell_flags = Z2NOCAST | INCLUDEUSER | CONSTRUCT_CHECK + invocation_type = SpI_NONE + range = -1 + duration = 50 //in deciseconds + + hud_state = "const_shift" + +/spell/targeted/ethereal_jaunt/shift/jaunt_disappear(var/atom/movable/overlay/animation, var/mob/living/target) + animation.icon_state = "phase_shift" + animation.dir = target.dir + flick("phase_shift",animation) + +/spell/targeted/ethereal_jaunt/shift/jaunt_reappear(var/atom/movable/overlay/animation, var/mob/living/target) + animation.icon_state = "phase_shift2" + animation.dir = target.dir + flick("phase_shift2",animation) + +/spell/targeted/ethereal_jaunt/shift/jaunt_steam(var/mobloc) + return \ No newline at end of file diff --git a/code/modules/spells/targeted/subjugate.dm b/code/modules/spells/targeted/subjugate.dm new file mode 100644 index 00000000..471ca129 --- /dev/null +++ b/code/modules/spells/targeted/subjugate.dm @@ -0,0 +1,35 @@ +/spell/targeted/subjugation + name = "Subjugation" + desc = "This spell temporarily subjugates a target's mind and does not require wizard garb." + feedback = "SJ" + school = "illusion" + charge_max = 500 + spell_flags = 0 + invocation = "Dii Oda Baji." + invocation_type = SpI_WHISPER + + message = "You suddenly feel completely overwhelmed!" + + max_targets = 1 + + level_max = list(Sp_TOTAL = 3, Sp_SPEED = 0, Sp_POWER = 3) + + amt_dizziness = 100 + amt_confused = 100 + amt_stuttering = 100 + + compatible_mobs = list(/mob/living/carbon/human) + + hud_state = "wiz_subj" + +/spell/targeted/subjugation/empower_spell() + if(!..()) + return 0 + + if(spell_levels[Sp_POWER] == level_max[Sp_POWER]) + max_targets = 0 + + return "[src] will now effect everyone in the area." + else + max_targets++ + return "[src] will now effect [max_targets] people." \ No newline at end of file diff --git a/code/modules/spells/targeted/swap.dm b/code/modules/spells/targeted/swap.dm new file mode 100644 index 00000000..0dd5b5c0 --- /dev/null +++ b/code/modules/spells/targeted/swap.dm @@ -0,0 +1,42 @@ +/spell/targeted/swap + name = "swap" + desc = "This spell swaps the positions of the wizard and a target. Causes brain damage." + feedback = "SW" + school = "conjuration" + + charge_type = Sp_HOLDVAR + holder_var_type = "brainloss" + holder_var_amount = 10 + + invocation = "Joyo!" + invocation_type = SpI_WHISPER + + level_max = list(Sp_TOTAL = 2, Sp_SPEED = 0, Sp_POWER = 2) + + spell_flags = Z2NOCAST + range = 6 + max_targets = 1 + compatible_mobs = list(/mob/living) + + hud_state = "wiz_swap" + + cast_sound = 'sound/effects/bamf.ogg' + +/spell/targeted/swap/cast(var/list/targets, mob/user) + for(var/mob/T in targets) + var/turf/aT = get_turf(T) + var/turf/bT = get_turf(user) + + T.forceMove(bT) + user.forceMove(aT) + + apply_spell_damage(T) + +/spell/targeted/swap/empower_spell() + if(!..()) + return 0 + + amt_eye_blind += 2 + amt_weakened += 5 + + return "This spell will now weaken and blind the target for a longer period of time." \ No newline at end of file diff --git a/code/modules/spells/targeted/targeted.dm b/code/modules/spells/targeted/targeted.dm new file mode 100644 index 00000000..9b7c060d --- /dev/null +++ b/code/modules/spells/targeted/targeted.dm @@ -0,0 +1,159 @@ +/* +Targeted spells (with the exception of dumbfire) select from all the mobs in the defined range +Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are explained in setup.dm +*/ + + +/spell/targeted //can mean aoe for mobs (limited/unlimited number) or one target mob + var/max_targets = 1 //leave 0 for unlimited targets in range, more for limited number of casts (can all target one guy, depends on target_ignore_prev) in range + var/target_ignore_prev = 1 //only important if max_targets > 1, affects if the spell can be cast multiple times at one person from one cast + + + var/amt_weakened = 0 + var/amt_paralysis = 0 + var/amt_stunned = 0 + + var/amt_dizziness = 0 + var/amt_confused = 0 + var/amt_stuttering = 0 + + //set to negatives for healing unless commented otherwise + var/amt_dam_fire = 0 + var/amt_dam_brute = 0 + var/amt_dam_oxy = 0 + var/amt_dam_tox = 0 + var/amt_brain = 0 + var/amt_radiation = 0 + var/amt_blood = 0 //Positive numbers to add blood + var/amt_organ = 0 //Positive numbers for healing + + var/amt_eye_blind = 0 + var/amt_eye_blurry = 0 + + var/list/compatible_mobs = list() + + +/spell/targeted/choose_targets(mob/user = usr) + var/list/targets = list() + + if(max_targets == 0) //unlimited + if(range == -2) + targets = GLOB.living_mob_list_ + else + for(var/mob/living/target in view_or_range(range, holder, selection_type)) + targets += target + + else if(max_targets == 1) //single target can be picked + if((range == 0 || range == -1) && spell_flags & INCLUDEUSER) + targets += user + else + var/list/possible_targets = list() + var/list/starting_targets + if(range == -2) + starting_targets = GLOB.living_mob_list_ + else + starting_targets = view_or_range(range, holder, selection_type) + + for(var/mob/living/M in starting_targets) + if(!(spell_flags & INCLUDEUSER) && M == user) + continue + if(compatible_mobs && compatible_mobs.len) + if(!is_type_in_list(M, compatible_mobs)) continue + if(compatible_mobs && compatible_mobs.len && !is_type_in_list(M, compatible_mobs)) + continue + possible_targets += M + + if(possible_targets.len) + if(spell_flags & SELECTABLE) //if we are allowed to choose. see setup.dm for details + var/mob/temp_target = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets + if(temp_target) + targets += temp_target + else + targets += pick(possible_targets) + //Adds a safety check post-input to make sure those targets are actually in range. + + + else + var/list/possible_targets = list() + var/list/starting_targets + + if(range == -2) + starting_targets = GLOB.living_mob_list_ + else + starting_targets = view_or_range(range, holder, selection_type) + + for(var/mob/living/target in starting_targets) + if(!(spell_flags & INCLUDEUSER) && target == user) + continue + if(compatible_mobs && !is_type_in_list(target, compatible_mobs)) + continue + possible_targets += target + + if(spell_flags & SELECTABLE) + for(var/i = 1; i<=max_targets, i++) + if(!possible_targets.len) + break + var/mob/M = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets + if(!M) + break + if(range != -2) + if(!(M in view_or_range(range, holder, selection_type))) + continue + targets += M + possible_targets -= M + else + for(var/i=1,i<=max_targets,i++) + if(!possible_targets.len) + break + if(target_ignore_prev) + var/target = pick(possible_targets) + possible_targets -= target + targets += target + else + targets += pick(possible_targets) + + if(!(spell_flags & INCLUDEUSER) && (user in targets)) + targets -= user + + if(compatible_mobs && compatible_mobs.len) + for(var/mob/living/target in targets) //filters out all the non-compatible mobs + if(!is_type_in_list(target, compatible_mobs)) + targets -= target + + return targets + +/spell/targeted/cast(var/list/targets, mob/user) + for(var/mob/living/target in targets) + if(range >= 0) + if(!(target in view_or_range(range, holder, selection_type))) //filter at time of casting + targets -= target + continue + apply_spell_damage(target) + +/spell/targeted/proc/apply_spell_damage(mob/living/target) + target.adjustBruteLoss(amt_dam_brute) + target.adjustFireLoss(amt_dam_fire) + target.adjustToxLoss(amt_dam_tox) + target.adjustOxyLoss(amt_dam_oxy) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + for(var/obj/item/organ/external/affecting in H.organs) + if(affecting && istype(affecting)) + affecting.heal_damage(amt_organ, amt_organ) + H.vessel.add_reagent(/datum/reagent/blood,amt_blood) + H.adjustBrainLoss(amt_brain) + H.radiation += min(H.radiation, amt_radiation) + H.fixblood() + target.regenerate_icons() + //disabling + target.Weaken(amt_weakened) + target.Paralyse(amt_paralysis) + target.Stun(amt_stunned) + if(amt_weakened || amt_paralysis || amt_stunned) + if(target.buckled) + target.buckled = null + target.eye_blind += amt_eye_blind + target.eye_blurry += amt_eye_blurry + target.dizziness += amt_dizziness + target.confused += amt_confused + target.stuttering += amt_stuttering \ No newline at end of file diff --git a/code/modules/spells/targeted/torment.dm b/code/modules/spells/targeted/torment.dm new file mode 100644 index 00000000..54777aae --- /dev/null +++ b/code/modules/spells/targeted/torment.dm @@ -0,0 +1,34 @@ +/spell/targeted/torment + name = "Torment" + desc = "this spell causes pain to all those in its radius." + feedback = "TM" + school = "illusion" + charge_max = 150 + spell_flags = 0 + invocation = "Rai Di-Kaal!" + invocation_type = SpI_SHOUT + range = 5 + level_max = list(Sp_TOTAL = 1, Sp_SPEED = 0, Sp_POWER = 1) + cooldown_min = 50 + message = "So much pain! All you can hear is screaming!" + + max_targets = 0 + compatible_mobs = list(/mob/living/carbon/human) + + var/loss = 30 + + hud_state = "wiz_horse" + + +/spell/targeted/torment/cast(var/list/targets, var/mob/user) + gibs(user.loc) + for(var/mob/living/carbon/human/H in targets) + H.adjustHalLoss(loss) + +/spell/targeted/torment/empower_spell() + if(!..()) + return 0 + + loss += 30 + + return "[src] will now cause more pain." \ No newline at end of file diff --git a/code/modules/supermatter/setup_supermatter.dm b/code/modules/supermatter/setup_supermatter.dm new file mode 100644 index 00000000..84066542 --- /dev/null +++ b/code/modules/supermatter/setup_supermatter.dm @@ -0,0 +1,262 @@ +#define SETUP_OK 1 // All good +#define SETUP_WARNING 2 // Something that shouldn't happen happened, but it's not critical so we will continue +#define SETUP_ERROR 3 // Something bad happened, and it's important so we won't continue setup. +#define SETUP_DELAYED 4 // Wait for other things first. + + +#define ENERGY_NITROGEN 115 // Roughly 8 emitter shots. +#define ENERGY_CARBONDIOXIDE 150 // Roughly 10 emitter shots. +#define ENERGY_HYDROGEN 300 // Roughly 20 emitter shots. +#define ENERGY_PHORON 500 // Roughly 40 emitter shots. + + +/datum/admins/proc/setup_supermatter() + set category = "Debug" + set name = "Setup Supermatter" + set desc = "Allows you to start the Supermatter engine." + + if (!istype(src,/datum/admins)) + src = usr.client.holder + if (!istype(src,/datum/admins)) + to_chat(usr, "Error: you are not an admin!") + return + + var/response = input(usr, "Are you sure? This will start up the engine with selected gas as coolant.", "Engine setup") as null|anything in list("N2", "CO2", "PH", "H2", "Abort") + if(!response || response == "Abort") + return + + var/errors = 0 + var/warnings = 0 + var/success = 0 + + log_and_message_admins("## SUPERMATTER SETUP - Setup initiated by [usr] using coolant type [response].") + + // CONFIGURATION PHASE + // Coolant canisters, set types according to response. + for(var/obj/effect/engine_setup/coolant_canister/C in world) + switch(response) + if("N2") + C.canister_type = /obj/machinery/portable_atmospherics/canister/nitrogen/engine_setup/ + continue + if("CO2") + C.canister_type = /obj/machinery/portable_atmospherics/canister/carbon_dioxide/engine_setup/ + continue + if("PH") + C.canister_type = /obj/machinery/portable_atmospherics/canister/phoron/engine_setup/ + continue + if("H2") + C.canister_type = /obj/machinery/portable_atmospherics/canister/hydrogen/engine_setup/ + continue + + for(var/obj/effect/engine_setup/core/C in world) + switch(response) + if("N2") + C.energy_setting = ENERGY_NITROGEN + continue + if("CO2") + C.energy_setting = ENERGY_CARBONDIOXIDE + continue + if("PH") + C.energy_setting = ENERGY_PHORON + continue + if("H2") + C.energy_setting = ENERGY_HYDROGEN + continue + + for(var/obj/effect/engine_setup/filter/F in world) + F.coolant = response + + var/list/delayed_objects = list() + // SETUP PHASE + for(var/obj/effect/engine_setup/S in world) + var/result = S.activate(0) + switch(result) + if(SETUP_OK) + success++ + continue + if(SETUP_WARNING) + warnings++ + continue + if(SETUP_ERROR) + errors++ + log_and_message_admins("## SUPERMATTER SETUP - Error encountered! Aborting.") + break + if(SETUP_DELAYED) + delayed_objects.Add(S) + continue + + if(!errors) + for(var/obj/effect/engine_setup/S in delayed_objects) + var/result = S.activate(1) + switch(result) + if(SETUP_OK) + success++ + continue + if(SETUP_WARNING) + warnings++ + continue + if(SETUP_ERROR) + errors++ + log_and_message_admins("## SUPERMATTER SETUP - Error encountered! Aborting.") + break + + log_and_message_admins("## SUPERMATTER SETUP - Setup completed with [errors] errors, [warnings] warnings and [success] successful steps.") + + return + + + +/obj/effect/engine_setup/ + name = "Engine Setup Marker" + desc = "You shouldn't see this." + invisibility = 101 + anchored = 1 + density = 0 + icon = 'icons/mob/screen1.dmi' + icon_state = "x3" + +/obj/effect/engine_setup/proc/activate(var/last = 0) + return 1 + + + +// Tries to locate a pump, enables it, and sets it to MAX. Triggers warning if unable to locate a pump. +/obj/effect/engine_setup/pump_max/ + name = "Pump Setup Marker" + +/obj/effect/engine_setup/pump_max/activate() + ..() + var/obj/machinery/atmospherics/binary/pump/P = locate() in get_turf(src) + if(!P) + log_and_message_admins("## WARNING: Unable to locate pump at [x] [y] [z]!") + return SETUP_WARNING + P.target_pressure = P.max_pressure_setting + P.use_power = 1 + P.update_icon() + return SETUP_OK + + + +// Spawns an empty canister on this turf, if it has a connector port. Triggers warning if unable to find a connector port +/obj/effect/engine_setup/empty_canister/ + name = "Empty Canister Marker" + +/obj/effect/engine_setup/empty_canister/activate() + ..() + var/obj/machinery/atmospherics/portables_connector/P = locate() in get_turf(src) + if(!P) + log_and_message_admins("## WARNING: Unable to locate connector port at [x] [y] [z]!") + return SETUP_WARNING + new/obj/machinery/portable_atmospherics/canister(get_turf(src)) // Canisters automatically connect to connectors in New() + return SETUP_OK + + + + +// Spawns a coolant canister on this turf, if it has a connector port. +// Triggers error when unable to locate connector port or when coolant canister type is unset. +/obj/effect/engine_setup/coolant_canister/ + name = "Coolant Canister Marker" + var/canister_type = null + +/obj/effect/engine_setup/coolant_canister/activate() + ..() + var/obj/machinery/atmospherics/portables_connector/P = locate() in get_turf(src) + if(!P) + log_and_message_admins("## ERROR: Unable to locate coolant connector port at [x] [y] [z]!") + return SETUP_ERROR + if(!canister_type) + log_and_message_admins("## ERROR: Canister type unset at [x] [y] [z]!") + return SETUP_ERROR + new canister_type(get_turf(src)) + return SETUP_OK + + + +// Energises the supermatter. Errors when unable to locate supermatter. +/obj/effect/engine_setup/core/ + name = "Supermatter Core Marker" + var/energy_setting = 0 + +/obj/effect/engine_setup/core/activate(var/last = 0) + if(!last) + return SETUP_DELAYED + ..() + var/obj/machinery/power/supermatter/SM = locate() in get_turf(src) + if(!SM) + log_and_message_admins("## ERROR: Unable to locate supermatter core at [x] [y] [z]!") + return SETUP_ERROR + if(!energy_setting) + log_and_message_admins("## ERROR: Energy setting unset at [x] [y] [z]!") + return SETUP_ERROR + SM.power = energy_setting + return SETUP_OK + + + +// Tries to enable the SMES on max input/output settings. With load balancing it should be fine as long as engine outputs at least ~500kW +/obj/effect/engine_setup/smes/ + name = "SMES Marker" + +/obj/effect/engine_setup/smes/activate() + ..() + var/obj/machinery/power/smes/S = locate() in get_turf(src) + if(!S) + log_and_message_admins("## WARNING: Unable to locate SMES unit at [x] [y] [z]!") + return SETUP_WARNING + S.input_attempt = 1 + S.output_attempt = 1 + S.input_level = S.input_level_max + S.output_level = S.output_level_max + S.update_icon() + return SETUP_OK + + + +// Sets up filters. This assumes filters are set to filter out CO2 back to the core loop by default! +/obj/effect/engine_setup/filter/ + name = "Omni Filter Marker" + var/coolant = null + +/obj/effect/engine_setup/filter/activate() + ..() + var/obj/machinery/atmospherics/omni/filter/F = locate() in get_turf(src) + if(!F) + log_and_message_admins("## WARNING: Unable to locate omni filter at [x] [y] [z]!") + return SETUP_WARNING + if(!coolant) + log_and_message_admins("## WARNING: No coolant type set at [x] [y] [z]!") + return SETUP_WARNING + + // Non-co2 coolant, adjust the filter's config first. + if(coolant != "CO2") + for(var/datum/omni_port/P in F.ports) + if(P.mode != ATM_CO2) + continue + if(coolant == "PH") + P.mode = ATM_P + break + else if(coolant == "N2") + P.mode = ATM_N2 + break + else if(coolant == "H2") + P.mode = ATM_H2 + break + else + log_and_message_admins("## WARNING: Inapropriate filter coolant type set at [x] [y] [z]!") + return SETUP_WARNING + F.rebuild_filtering_list() + + F.use_power = 1 + F.update_icon() + return SETUP_OK + + +#undef SETUP_OK +#undef SETUP_WARNING +#undef SETUP_ERROR +#undef SETUP_DELAYED +#undef ENERGY_NITROGEN +#undef ENERGY_CARBONDIOXIDE +#undef ENERGY_HYDROGEN +#undef ENERGY_PHORON diff --git a/code/modules/supermatter/supermatter.dm b/code/modules/supermatter/supermatter.dm new file mode 100644 index 00000000..d56f7750 --- /dev/null +++ b/code/modules/supermatter/supermatter.dm @@ -0,0 +1,543 @@ +#define NITROGEN_RETARDATION_FACTOR 0.15 //Higher == N2 slows reaction more +#define THERMAL_RELEASE_MODIFIER 10000 //Higher == more heat released during reaction +#define PHORON_RELEASE_MODIFIER 1500 //Higher == less phoron released by reaction +#define OXYGEN_RELEASE_MODIFIER 15000 //Higher == less oxygen released at high temperature/power +#define REACTION_POWER_MODIFIER 1.1 //Higher == more overall power + +/* + How to tweak the SM + + POWER_FACTOR directly controls how much power the SM puts out at a given level of excitation (power var). Making this lower means you have to work the SM harder to get the same amount of power. + CRITICAL_TEMPERATURE The temperature at which the SM starts taking damage. + + CHARGING_FACTOR Controls how much emitter shots excite the SM. + DAMAGE_RATE_LIMIT Controls the maximum rate at which the SM will take damage due to high temperatures. +*/ + +//Controls how much power is produced by each collector in range - this is the main parameter for tweaking SM balance, as it basically controls how the power variable relates to the rest of the game. +#define POWER_FACTOR 1.0 +#define DECAY_FACTOR 700 //Affects how fast the supermatter power decays +#define CRITICAL_TEMPERATURE 5000 //K +#define CHARGING_FACTOR 0.05 +#define DAMAGE_RATE_LIMIT 4.5 //damage rate cap at power = 300, scales linearly with power + + +// Base variants are applied to everyone on the same Z level +// Range variants are applied on per-range basis: numbers here are on point blank, it scales with the map size (assumes square shaped Z levels) +#define DETONATION_RADS 20 +#define DETONATION_MOB_CONCUSSION 4 // Value that will be used for Weaken() for mobs. + +// Base amount of ticks for which a specific type of machine will be offline for. +- 20% added by RNG. +// This does pretty much the same thing as an electrical storm, it just affects the whole Z level instantly. +#define DETONATION_APC_OVERLOAD_PROB 10 // prob() of overloading an APC's lights. +#define DETONATION_SHUTDOWN_APC 120 // Regular APC. +#define DETONATION_SHUTDOWN_CRITAPC 10 // Critical APC. AI core and such. Considerably shorter as we don't want to kill the AI with a single blast. Still a nuisance. +#define DETONATION_SHUTDOWN_SMES 60 // SMES +#define DETONATION_SHUTDOWN_RNG_FACTOR 20 // RNG factor. Above shutdown times can be +- X%, where this setting is the percent. Do not set to 100 or more. +#define DETONATION_SOLAR_BREAK_CHANCE 60 // prob() of breaking solar arrays (this is per-panel, and only affects the Z level SM is on) + +#define WARNING_DELAY 20 //seconds between warnings. + +/obj/machinery/power/supermatter + name = "Supermatter" + desc = "A strangely translucent and iridescent crystal. You get headaches just from looking at it." + icon = 'icons/obj/engine.dmi' + icon_state = "darkmatter" + density = 1 + anchored = 0 + light_range = 4 + + layer = ABOVE_OBJ_LAYER + + var/gasefficency = 0.25 + + var/base_icon_state = "darkmatter" + + var/damage = 0 + var/damage_archived = 0 + var/safe_alert = "Crystaline hyperstructure returning to safe operating levels." + var/safe_warned = 0 + var/public_alert = 0 //Stick to Engineering frequency except for big warnings when integrity bad + var/warning_point = 100 + var/warning_alert = "Danger! Crystal hyperstructure instability!" + var/emergency_point = 700 + var/emergency_alert = "CRYSTAL DELAMINATION IMMINENT." + var/explosion_point = 1000 + + light_color = "#8a8a00" + var/warning_color = "#b8b800" + var/emergency_color = "#d9d900" + + var/grav_pulling = 0 + // Time in ticks between delamination ('exploding') and exploding (as in the actual boom) + var/pull_time = 300 + var/explosion_power = 9 + + var/emergency_issued = 0 + + // Time in 1/10th of seconds since the last sent warning + var/lastwarning = 0 + + // This stops spawning redundand explosions. Also incidentally makes supermatter unexplodable if set to 1. + var/exploded = 0 + + var/power = 0 + var/oxygen = 0 + + //Temporary values so that we can optimize this + //How much the bullets damage should be multiplied by when it is added to the internal variables + var/config_bullet_energy = 2 + //How much of the power is left after processing is finished? +// var/config_power_reduction_per_tick = 0.5 + //How much hallucination should it produce per unit of power? + var/config_hallucination_power = 0.1 + + var/debug = 0 + + var/disable_adminwarn = FALSE + + var/aw_normal = FALSE + var/aw_notify = FALSE + var/aw_warning = FALSE + var/aw_danger = FALSE + var/aw_emerg = FALSE + var/aw_delam = FALSE + var/aw_EPR = FALSE + +/obj/machinery/power/supermatter/New() + ..() + uid = gl_uid++ + +/obj/machinery/power/supermatter/proc/handle_admin_warnings() + if(disable_adminwarn) + return + + // Generic checks, similar to checks done by supermatter monitor program. + aw_normal = status_adminwarn_check(SUPERMATTER_NORMAL, aw_normal, "INFO: Supermatter crystal has been energised.", FALSE) + aw_notify = status_adminwarn_check(SUPERMATTER_NOTIFY, aw_notify, "INFO: Supermatter crystal is approaching unsafe operating temperature.", FALSE) + aw_warning = status_adminwarn_check(SUPERMATTER_WARNING, aw_warning, "WARN: Supermatter crystal is taking integrity damage!", FALSE) + aw_danger = status_adminwarn_check(SUPERMATTER_DANGER, aw_danger, "WARN: Supermatter integrity is below 50%!", TRUE) + aw_emerg = status_adminwarn_check(SUPERMATTER_EMERGENCY, aw_emerg, "CRIT: Supermatter integrity is below 25%!", FALSE) + aw_delam = status_adminwarn_check(SUPERMATTER_DELAMINATING, aw_delam, "CRIT: Supermatter is delaminating!", TRUE) + + // EPR check. Only runs when supermatter is energised. Triggers when there is very low amount of coolant in the core (less than one standard canister). + // This usually means a core breach or deliberate venting. + if(get_status() && (get_epr() < 0.5)) + if(!aw_EPR) + log_and_message_admins("WARN: Supermatter EPR value low. Possible core breach detected.") + aw_EPR = TRUE + else + aw_EPR = FALSE + +/obj/machinery/power/supermatter/proc/status_adminwarn_check(var/min_status, var/current_state, var/message, var/send_to_irc = FALSE) + var/status = get_status() + if(status >= min_status) + if(!current_state) + log_and_message_admins(message) + if(send_to_irc) + send2adminirc(message) + return TRUE + else + return FALSE + +/obj/machinery/power/supermatter/proc/get_epr() + var/turf/T = get_turf(src) + if(!istype(T)) + return + var/datum/gas_mixture/air = T.return_air() + if(!air) + return 0 + return round((air.total_moles / air.group_multiplier) / 23.1, 0.01) + +/obj/machinery/power/supermatter/proc/get_status() + var/turf/T = get_turf(src) + if(!T) + return SUPERMATTER_ERROR + var/datum/gas_mixture/air = T.return_air() + if(!air) + return SUPERMATTER_ERROR + + if(grav_pulling || exploded) + return SUPERMATTER_DELAMINATING + + if(get_integrity() < 25) + return SUPERMATTER_EMERGENCY + + if(get_integrity() < 50) + return SUPERMATTER_DANGER + + if((get_integrity() < 100) || (air.temperature > CRITICAL_TEMPERATURE)) + return SUPERMATTER_WARNING + + if(air.temperature > (CRITICAL_TEMPERATURE * 0.8)) + return SUPERMATTER_NOTIFY + + if(power > 5) + return SUPERMATTER_NORMAL + return SUPERMATTER_INACTIVE + + +/obj/machinery/power/supermatter/proc/explode() + set waitfor = 0 + + if(exploded) + return + + log_and_message_admins("Supermatter delaminating at [x] [y] [z]") + anchored = 1 + grav_pulling = 1 + exploded = 1 + sleep(pull_time) + var/turf/TS = get_turf(src) // The turf supermatter is on. SM being in a locker, mecha, or other container shouldn't block it's effects that way. + if(!istype(TS)) + return + + var/list/affected_z = GetConnectedZlevels(TS.z) + + // Effect 1: Radiation, weakening to all mobs on Z level + for(var/z in affected_z) + radiation_repository.z_radiate(locate(1, 1, z), DETONATION_RADS, 1) + + for(var/mob/living/mob in GLOB.living_mob_list_) + var/turf/TM = get_turf(mob) + if(!TM) + continue + if(!(TM.z in affected_z)) + continue + + mob.Weaken(DETONATION_MOB_CONCUSSION) + to_chat(mob, "An invisible force slams you against the ground!") + + // Effect 2: Z-level wide electrical pulse + for(var/obj/machinery/power/apc/A in SSmachines.machinery) + if(!(A.z in affected_z)) + continue + + // Overloads lights + if(prob(DETONATION_APC_OVERLOAD_PROB)) + A.overload_lighting() + // Causes the APCs to go into system failure mode. + var/random_change = rand(100 - DETONATION_SHUTDOWN_RNG_FACTOR, 100 + DETONATION_SHUTDOWN_RNG_FACTOR) / 100 + if(A.is_critical) + A.energy_fail(round(DETONATION_SHUTDOWN_CRITAPC * random_change)) + else + A.energy_fail(round(DETONATION_SHUTDOWN_APC * random_change)) + + for(var/obj/machinery/power/smes/buildable/S in SSmachines.machinery) + if(!(S.z in affected_z)) + continue + // Causes SMESes to shut down for a bit + var/random_change = rand(100 - DETONATION_SHUTDOWN_RNG_FACTOR, 100 + DETONATION_SHUTDOWN_RNG_FACTOR) / 100 + S.energy_fail(round(DETONATION_SHUTDOWN_SMES * random_change)) + + // Effect 3: Break solar arrays + + for(var/obj/machinery/power/solar/S in SSmachines.machinery) + if(!(S.z in affected_z)) + continue + if(prob(DETONATION_SOLAR_BREAK_CHANCE)) + S.broken() + + + + // Effect 4: Medium scale explosion + spawn(0) + explosion(TS, explosion_power/2, explosion_power, explosion_power * 2, explosion_power * 4, 1) + qdel(src) + +//Changes color and luminosity of the light to these values if they were not already set +/obj/machinery/power/supermatter/proc/shift_light(var/lum, var/clr) + if(lum != light_range || clr != light_color) + set_light(lum, l_color = clr) + +/obj/machinery/power/supermatter/proc/get_integrity() + var/integrity = damage / explosion_point + integrity = round(100 - integrity * 100) + integrity = integrity < 0 ? 0 : integrity + return integrity + + +/obj/machinery/power/supermatter/proc/announce_warning() + var/integrity = get_integrity() + var/alert_msg = " Integrity at [integrity]%" + + if(damage > emergency_point) + alert_msg = emergency_alert + alert_msg + lastwarning = world.timeofday - WARNING_DELAY * 4 + else if(damage >= damage_archived) // The damage is still going up + safe_warned = 0 + alert_msg = warning_alert + alert_msg + lastwarning = world.timeofday + else if(!safe_warned) + safe_warned = 1 // We are safe, warn only once + alert_msg = safe_alert + lastwarning = world.timeofday + else + alert_msg = null + if(alert_msg) + GLOB.global_announcer.autosay(alert_msg, "Supermatter Monitor", "Engineering") + //Public alerts + if((damage > emergency_point) && !public_alert) + GLOB.global_announcer.autosay("WARNING: SUPERMATTER CRYSTAL DELAMINATION IMMINENT!", "Supermatter Monitor") + public_alert = 1 + for(var/mob/M in GLOB.player_list) + var/turf/T = get_turf(M) + if(T && (T.z in GLOB.using_map.station_levels) && !istype(M,/mob/new_player) && !isdeaf(M)) + sound_to(M, 'sound/ambience/matteralarm.ogg') + else if(safe_warned && public_alert) + GLOB.global_announcer.autosay(alert_msg, "Supermatter Monitor") + public_alert = 0 + + +/obj/machinery/power/supermatter/Process() + + var/turf/L = loc + + if(isnull(L)) // We have a null turf...something is wrong, stop processing this entity. + return PROCESS_KILL + + if(!istype(L)) //We are in a crate or somewhere that isn't turf, if we return to turf resume processing but for now. + return //Yeah just stop. + + if(damage > explosion_point) + if(!exploded) + if(!istype(L, /turf/space)) + announce_warning() + explode() + else if(damage > warning_point) // while the core is still damaged and it's still worth noting its status + shift_light(5, warning_color) + if(damage > emergency_point) + shift_light(7, emergency_color) + if(!istype(L, /turf/space) && (world.timeofday - lastwarning) >= WARNING_DELAY * 10) + announce_warning() + else + shift_light(4,initial(light_color)) + if(grav_pulling) + supermatter_pull(src) + + //Ok, get the air from the turf + var/datum/gas_mixture/removed = null + var/datum/gas_mixture/env = null + + //ensure that damage doesn't increase too quickly due to super high temperatures resulting from no coolant, for example. We dont want the SM exploding before anyone can react. + //We want the cap to scale linearly with power (and explosion_point). Let's aim for a cap of 5 at power = 300 (based on testing, equals roughly 5% per SM alert announcement). + var/damage_inc_limit = (power/300)*(explosion_point/1000)*DAMAGE_RATE_LIMIT + + if(!istype(L, /turf/space)) + env = L.return_air() + removed = env.remove(gasefficency * env.total_moles) //Remove gas from surrounding area + + if(!env || !removed || !removed.total_moles) + damage += max((power - 15*POWER_FACTOR)/10, 0) + else if (grav_pulling) //If supermatter is detonating, remove all air from the zone + env.remove(env.total_moles) + else + damage_archived = damage + + damage = max(0, damage + between(-DAMAGE_RATE_LIMIT, (removed.temperature - CRITICAL_TEMPERATURE) / 150, damage_inc_limit)) + + //Ok, 100% oxygen atmosphere = best reaction + //Maxes out at 100% oxygen pressure + oxygen = Clamp((removed.get_by_flag(XGM_GAS_OXIDIZER) - (removed.gas["nitrogen"] * NITROGEN_RETARDATION_FACTOR)) / removed.total_moles, 0, 1) + + //calculate power gain for oxygen reaction + var/temp_factor + var/equilibrium_power + if (oxygen > 0.8) + //If chain reacting at oxygen == 1, we want the power at 800 K to stabilize at a power level of 400 + equilibrium_power = 400 + icon_state = "[base_icon_state]_glow" + else + //If chain reacting at oxygen == 1, we want the power at 800 K to stabilize at a power level of 250 + equilibrium_power = 250 + icon_state = base_icon_state + + temp_factor = ( (equilibrium_power/DECAY_FACTOR)**3 )/800 + power = max( (removed.temperature * temp_factor) * oxygen + power, 0) + + var/device_energy = power * REACTION_POWER_MODIFIER + + //Release reaction gasses + var/heat_capacity = removed.heat_capacity() + removed.adjust_multi("phoron", max(device_energy / PHORON_RELEASE_MODIFIER, 0), \ + "oxygen", max((device_energy + removed.temperature - T0C) / OXYGEN_RELEASE_MODIFIER, 0)) + + var/thermal_power = THERMAL_RELEASE_MODIFIER * device_energy + if (debug) + var/heat_capacity_new = removed.heat_capacity() + visible_message("[src]: Releasing [round(thermal_power)] W.") + visible_message("[src]: Releasing additional [round((heat_capacity_new - heat_capacity)*removed.temperature)] W with exhaust gasses.") + + removed.add_thermal_energy(thermal_power) + removed.temperature = between(0, removed.temperature, 10000) + + env.merge(removed) + + for(var/mob/living/carbon/human/l in view(src, min(7, round(sqrt(power/6))))) // If they can see it without mesons on. Bad on them. + if(!istype(l.glasses, /obj/item/clothing/glasses/meson)) + var/effect = max(0, min(200, power * config_hallucination_power * sqrt( 1 / max(1,get_dist(l, src)))) ) + l.adjust_hallucination(effect, 0.25*effect) + + + radiation_repository.radiate(src, power * 1.5) //Better close those shutters! + power -= (power/DECAY_FACTOR)**3 //energy losses due to radiation + handle_admin_warnings() + + return 1 + + +/obj/machinery/power/supermatter/bullet_act(var/obj/item/projectile/Proj) + var/turf/L = loc + if(!istype(L)) // We don't run process() when we are in space + return 0 // This stops people from being able to really power up the supermatter + // Then bring it inside to explode instantly upon landing on a valid turf. + + + var/proj_damage = Proj.get_structure_damage() + if(istype(Proj, /obj/item/projectile/beam)) + power += proj_damage * config_bullet_energy * CHARGING_FACTOR / POWER_FACTOR + else + damage += proj_damage * config_bullet_energy + return 0 + +/obj/machinery/power/supermatter/attack_robot(mob/user as mob) + if(Adjacent(user)) + return attack_hand(user) + else + ui_interact(user) + return + +/obj/machinery/power/supermatter/attack_ai(mob/user as mob) + ui_interact(user) + +/obj/machinery/power/supermatter/attack_hand(mob/user as mob) + user.visible_message("\The [user] reaches out and touches \the [src], inducing a resonance... \his body starts to glow and bursts into flames before flashing into ash.",\ + "You reach out and touch \the [src]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\"",\ + "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.") + + Consume(user) + +// This is purely informational UI that may be accessed by AIs or robots +/obj/machinery/power/supermatter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + + data["integrity_percentage"] = round(get_integrity()) + var/datum/gas_mixture/env = null + var/turf/T = get_turf(src) + + if(istype(T)) + env = T.return_air() + + if(!env) + data["ambient_temp"] = 0 + data["ambient_pressure"] = 0 + else + data["ambient_temp"] = round(env.temperature) + data["ambient_pressure"] = round(env.return_pressure()) + data["detonating"] = grav_pulling + data["energy"] = power + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "supermatter_crystal.tmpl", "Supermatter Crystal", 500, 300) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + + +/obj/machinery/power/supermatter/attackby(obj/item/weapon/W as obj, mob/living/user as mob) + if(istype(W, /obj/item/weapon/tape_roll)) + to_chat(user, "You repair some of the damage to \the [src] with \the [W].") + damage = max(damage -10, 0) + + user.visible_message("\The [user] touches \a [W] to \the [src] as a silence fills the room...",\ + "You touch \the [W] to \the [src] when everything suddenly goes silent.\"\n\The [W] flashes into dust as you flinch away from \the [src].",\ + "Everything suddenly goes silent.") + + user.drop_from_inventory(W) + Consume(W) + + user.apply_effect(150, IRRADIATE, blocked = user.getarmor(null, "rad")) + + +/obj/machinery/power/supermatter/Bumped(atom/AM as mob|obj) + if(istype(AM, /obj/effect)) + return + if(istype(AM, /mob/living)) + AM.visible_message("\The [AM] slams into \the [src] inducing a resonance... \his body starts to glow and catch flame before flashing into ash.",\ + "You slam into \the [src] as your ears are filled with unearthly ringing. Your last thought is \"Oh, fuck.\"",\ + "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.") + else if(!grav_pulling) //To prevent spam, detonating supermatter does not indicate non-mobs being destroyed + AM.visible_message("\The [AM] smacks into \the [src] and rapidly flashes to ash.",\ + "You hear a loud crack as you are washed with a wave of heat.") + + Consume(AM) + + +/obj/machinery/power/supermatter/proc/Consume(var/mob/living/user) + if(istype(user)) + user.dust() + power += 200 + else + qdel(user) + + power += 200 + + //Some poor sod got eaten, go ahead and irradiate people nearby. + for(var/mob/living/l in range(10)) + if(l in view()) + l.show_message("As \the [src] slowly stops resonating, you find your skin covered in new radiation burns.", 1,\ + "The unearthly ringing subsides and you notice you have new radiation burns.", 2) + else + l.show_message("You hear an uneartly ringing and notice your skin is covered in fresh radiation burns.", 2) + var/rads = 500 + radiation_repository.radiate(src, rads) + + +/proc/supermatter_pull(var/atom/target, var/pull_range = 255, var/pull_power = STAGE_FIVE) + for(var/atom/A in range(pull_range, target)) + A.singularity_pull(target, pull_power) + +/obj/machinery/power/supermatter/GotoAirflowDest(n) //Supermatter not pushed around by airflow + return + +/obj/machinery/power/supermatter/RepelAirflowDest(n) + return + +/obj/machinery/power/supermatter/shard //Small subtype, less efficient and more sensitive, but less boom. + name = "Supermatter Shard" + desc = "A strangely translucent and iridescent crystal that looks like it used to be part of a larger structure. You get headaches just from looking at it." + icon_state = "darkmatter_shard" + base_icon_state = "darkmatter_shard" + + warning_point = 50 + emergency_point = 400 + explosion_point = 600 + + gasefficency = 0.125 + + pull_time = 150 + explosion_power = 3 + +/obj/machinery/power/supermatter/shard/announce_warning() //Shards don't get announcements + return + + +#undef NITROGEN_RETARDATION_FACTOR +#undef THERMAL_RELEASE_MODIFIER +#undef PHORON_RELEASE_MODIFIER +#undef OXYGEN_RELEASE_MODIFIER +#undef REACTION_POWER_MODIFIER +#undef POWER_FACTOR +#undef DECAY_FACTOR +#undef CRITICAL_TEMPERATURE +#undef CHARGING_FACTOR +#undef DAMAGE_RATE_LIMIT +#undef DETONATION_MOB_CONCUSSION +#undef DETONATION_APC_OVERLOAD_PROB +#undef DETONATION_SHUTDOWN_APC +#undef DETONATION_SHUTDOWN_CRITAPC +#undef DETONATION_SHUTDOWN_SMES +#undef DETONATION_SHUTDOWN_RNG_FACTOR +#undef DETONATION_SOLAR_BREAK_CHANCE +#undef WARNING_DELAY diff --git a/code/modules/surgery/_defines.dm b/code/modules/surgery/_defines.dm new file mode 100644 index 00000000..900f3e45 --- /dev/null +++ b/code/modules/surgery/_defines.dm @@ -0,0 +1 @@ +#define SURGERY_FAILURE -1 diff --git a/code/modules/surgery/bones.dm b/code/modules/surgery/bones.dm new file mode 100644 index 00000000..dbbc4874 --- /dev/null +++ b/code/modules/surgery/bones.dm @@ -0,0 +1,179 @@ +//Procedures in this file: Fracture repair surgery +////////////////////////////////////////////////////////////////// +// BONE SURGERY // +////////////////////////////////////////////////////////////////// + + + + + +////////////////////////////////////////////////////////////////// +// bone gelling surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/glue_bone + allowed_tools = list( + /obj/item/weapon/bonegel = 100, \ + /obj/item/weapon/tape_roll = 75 + ) + can_infect = 1 + blood_level = 1 + + min_duration = 50 + max_duration = 60 + shock_level = 20 + +/datum/surgery_step/glue_bone/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && (affected.robotic < ORGAN_ROBOT) && affected.open() >= 2 && affected.stage == 0 + +/datum/surgery_step/glue_bone/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/bone = affected.encased ? "[target]'s [affected.encased]" : "bones in [target]'s [affected.name]" + if (affected.stage == 0) + user.visible_message("[user] starts applying \the [tool] to the [bone]." , \ + "You start applying \the [tool] to the [bone].") + target.custom_pain("Something in your [affected.name] is causing you a lot of pain!",50, affecting = affected) + ..() + +/datum/surgery_step/glue_bone/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/bone = affected.encased ? "[target]'s [affected.encased]" : "bones in [target]'s [affected.name]" + user.visible_message("[user] applies some [tool.name] to [bone]", \ + "You apply some [tool.name] to [bone].") + affected.stage = 1 + +/datum/surgery_step/glue_bone/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, smearing [tool] in the incision in [target]'s [affected.name]!" , \ + "Your hand slips, smearing [tool] in the incision in [target]'s [affected.name]!") + + +////////////////////////////////////////////////////////////////// +// bone setting surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/set_bone + allowed_tools = list( + /obj/item/weapon/bonesetter = 100, \ + /obj/item/weapon/wrench = 75 \ + ) + + min_duration = 60 + max_duration = 70 + shock_level = 40 + delicate = 1 + +/datum/surgery_step/set_bone/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.organ_tag != BP_HEAD && !(affected.robotic >= ORGAN_ROBOT) && affected.open() >= SURGERY_RETRACTED && affected.stage == 1 + +/datum/surgery_step/set_bone/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/bone = affected.encased ? "[target]'s [affected.encased]" : "bones in [target]'s [affected.name]" + user.visible_message("[user] is beginning to set the [bone] in place with \the [tool]." , \ + "You are beginning to set the [bone] in place with \the [tool].") + target.custom_pain("The pain in your [affected.name] is going to make you pass out!",50, affecting = affected) + ..() + +/datum/surgery_step/set_bone/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/bone = affected.encased ? "[target]'s [affected.encased]" : "bones in [target]'s [affected.name]" + if (affected.status & ORGAN_BROKEN) + user.visible_message("[user] sets the [bone] n place with \the [tool].", \ + "You set the [bone] in place with \the [tool].") + affected.stage = 2 + else + user.visible_message("[user] sets the [bone] in the WRONG place with \the [tool].", \ + "You set the [bone] in the WRONG place with \the [tool].") + affected.fracture() + +/datum/surgery_step/set_bone/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, damaging the [affected.encased ? affected.encased : "bones"] in [target]'s [affected.name] with \the [tool]!" , \ + "Your hand slips, damaging the [affected.encased ? affected.encased : "bones"] in [target]'s [affected.name] with \the [tool]!") + affected.fracture() + affected.take_damage(5, used_weapon = tool) + + +////////////////////////////////////////////////////////////////// +// skull mending surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/mend_skull + allowed_tools = list( + /obj/item/weapon/bonesetter = 100, \ + /obj/item/weapon/wrench = 75 \ + ) + + min_duration = 60 + max_duration = 70 + shock_level = 40 + delicate = 1 + +/datum/surgery_step/mend_skull/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.organ_tag == BP_HEAD && (affected.robotic < ORGAN_ROBOT) && affected.open() >= SURGERY_RETRACTED && affected.stage == 1 + +/datum/surgery_step/mend_skull/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] is beginning to piece together [target]'s skull with \the [tool]." , \ + "You are beginning to piece together [target]'s skull with \the [tool].") + ..() + +/datum/surgery_step/mend_skull/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] sets [target]'s skull with \the [tool]." , \ + "You set [target]'s skull with \the [tool].") + affected.stage = 2 + +/datum/surgery_step/mend_skull/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, damaging [target]'s face with \the [tool]!" , \ + "Your hand slips, damaging [target]'s face with \the [tool]!") + var/obj/item/organ/external/head/h = affected + affected.take_damage(10, used_weapon = tool) + h.disfigured = 1 + +////////////////////////////////////////////////////////////////// +// post setting bone-gelling surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/finish_bone + allowed_tools = list( + /obj/item/weapon/bonegel = 100, \ + /obj/item/weapon/tape_roll = 75 + ) + can_infect = 1 + blood_level = 1 + + min_duration = 50 + max_duration = 60 + shock_level = 20 + +/datum/surgery_step/finish_bone/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.open() >= SURGERY_RETRACTED && !(affected.robotic >= ORGAN_ROBOT) && affected.stage == 2 + +/datum/surgery_step/finish_bone/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/bone = affected.encased ? "[target]'s [affected.encased]" : "bones in [target]'s [affected.name]" + user.visible_message("[user] starts to finish mending the damaged [bone] with \the [tool].", \ + "You start to finish mending the damaged [bone] with \the [tool].") + ..() + +/datum/surgery_step/finish_bone/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/bone = affected.encased ? "[target]'s [affected.encased]" : "bones in [target]'s [affected.name]" + user.visible_message("[user] has mended the damaged [bone] with \the [tool]." , \ + "You have mended the damaged [bone] with \the [tool]." ) + affected.status &= ~ORGAN_BROKEN + affected.stage = 0 + +/datum/surgery_step/finish_bone/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, smearing [tool] in the incision in [target]'s [affected.name]!" , \ + "Your hand slips, smearing [tool] in the incision in [target]'s [affected.name]!") \ No newline at end of file diff --git a/code/modules/surgery/encased.dm b/code/modules/surgery/encased.dm new file mode 100644 index 00000000..5988b4b1 --- /dev/null +++ b/code/modules/surgery/encased.dm @@ -0,0 +1,74 @@ +//Procedures in this file: Generic ribcage opening steps, Removing alien embryo, Fixing internal organs. +////////////////////////////////////////////////////////////////// +// GENERIC RIBCAGE SURGERY // +////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////// +// generic ribcage surgery step datum +////////////////////////////////////////////////////////////////// +/datum/surgery_step/open_encased + priority = 2 + can_infect = 1 + blood_level = 1 + shock_level = 40 + delicate = 1 + +/datum/surgery_step/open_encased/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return 0 + + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && !(affected.robotic >= ORGAN_ROBOT) && affected.encased && affected.open() >= SURGERY_RETRACTED + +////////////////////////////////////////////////////////////////// +// ribcage sawing surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/open_encased/saw + allowed_tools = list( + /obj/item/weapon/circular_saw = 100, + /obj/item/weapon/material/knife = 50, \ + /obj/item/weapon/material/hatchet = 75 + ) + + min_duration = 50 + max_duration = 70 + shock_level = 60 + +/datum/surgery_step/open_encased/saw/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return ..() && affected && affected.open() == SURGERY_RETRACTED + +/datum/surgery_step/open_encased/saw/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + user.visible_message("[user] begins to cut through [target]'s [affected.encased] with \the [tool].", \ + "You begin to cut through [target]'s [affected.encased] with \the [tool].") + target.custom_pain("Something hurts horribly in your [affected.name]!",60, affecting = affected) + ..() + +/datum/surgery_step/open_encased/saw/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + user.visible_message("[user] has cut [target]'s [affected.encased] open with \the [tool].", \ + "You have cut [target]'s [affected.encased] open with \the [tool].") + affected.fracture() + +/datum/surgery_step/open_encased/saw/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + user.visible_message("[user]'s hand slips, cracking [target]'s [affected.encased] with \the [tool]!" , \ + "Your hand slips, cracking [target]'s [affected.encased] with \the [tool]!" ) + + affected.take_damage(15, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + affected.fracture() \ No newline at end of file diff --git a/code/modules/surgery/face.dm b/code/modules/surgery/face.dm new file mode 100644 index 00000000..3a447efe --- /dev/null +++ b/code/modules/surgery/face.dm @@ -0,0 +1,151 @@ +//Procedures in this file: Facial reconstruction surgery +////////////////////////////////////////////////////////////////// +// FACE SURGERY // +////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////// +// generic face surgery step datum +////////////////////////////////////////////////////////////////// +/datum/surgery_step/face + priority = 2 + can_infect = 0 + +/datum/surgery_step/face/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if (!affected || (affected.robotic >= ORGAN_ROBOT)) + return 0 + return target_zone == BP_MOUTH + +////////////////////////////////////////////////////////////////// +// facial tissue cutting surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/generic/cut_face + allowed_tools = list( + /obj/item/weapon/scalpel = 100, \ + /obj/item/weapon/material/knife = 75, \ + /obj/item/weapon/material/shard = 50, \ + ) + + min_duration = 90 + max_duration = 110 + +/datum/surgery_step/generic/cut_face/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + return ..() && target_zone == BP_MOUTH && target.op_stage.face == 0 + +/datum/surgery_step/generic/cut_face/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] starts to cut open [target]'s face and neck with \the [tool].", \ + "You start to cut open [target]'s face and neck with \the [tool].") + ..() + +/datum/surgery_step/generic/cut_face/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] has cut open [target]'s face and neck with \the [tool]." , \ + "You have cut open [target]'s face and neck with \the [tool].",) + target.op_stage.face = 1 + +/datum/surgery_step/generic/cut_face/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, slicing [target]'s throat wth \the [tool]!" , \ + "Your hand slips, slicing [target]'s throat wth \the [tool]!" ) + affected.take_damage(40, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + target.losebreath += 10 + +////////////////////////////////////////////////////////////////// +// vocal cord mending surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/face/mend_vocal + allowed_tools = list( + /obj/item/weapon/hemostat = 100, \ + /obj/item/stack/cable_coil = 75, \ + /obj/item/device/assembly/mousetrap = 10 //I don't know. Don't ask me. But I'm leaving it because hilarity. + ) + + min_duration = 70 + max_duration = 90 + +/datum/surgery_step/face/mend_vocal/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + return ..() && target.op_stage.face == 1 + +/datum/surgery_step/face/mend_vocal/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] starts mending [target]'s vocal cords with \the [tool].", \ + "You start mending [target]'s vocal cords with \the [tool].") + ..() + +/datum/surgery_step/face/mend_vocal/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] mends [target]'s vocal cords with \the [tool].", \ + "You mend [target]'s vocal cords with \the [tool].") + target.op_stage.face = 2 + +/datum/surgery_step/face/mend_vocal/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user]'s hand slips, clamping [target]'s trachea shut for a moment with \the [tool]!", \ + "Your hand slips, clamping [user]'s trachea shut for a moment with \the [tool]!") + target.losebreath += 10 + +////////////////////////////////////////////////////////////////// +// facial reconstruction surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/face/fix_face + allowed_tools = list( + /obj/item/weapon/retractor = 100, \ + /obj/item/weapon/crowbar = 55, \ + /obj/item/weapon/material/kitchen/utensil/fork = 75) + + min_duration = 80 + max_duration = 100 + +/datum/surgery_step/face/fix_face/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + return ..() && target.op_stage.face == 2 + +/datum/surgery_step/face/fix_face/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] starts pulling the skin on [target]'s face back in place with \the [tool].", \ + "You start pulling the skin on [target]'s face back in place with \the [tool].") + ..() + +/datum/surgery_step/face/fix_face/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] pulls the skin on [target]'s face back in place with \the [tool].", \ + "You pull the skin on [target]'s face back in place with \the [tool].") + target.op_stage.face = 3 + +/datum/surgery_step/face/fix_face/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, tearing skin on [target]'s face with \the [tool]!", \ + "Your hand slips, tearing skin on [target]'s face with \the [tool]!") + affected.take_damage(10, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + +////////////////////////////////////////////////////////////////// +// facial skin cauterization surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/face/cauterize + allowed_tools = list( + /obj/item/weapon/cautery = 100, \ + /obj/item/clothing/mask/smokable/cigarette = 75, \ + /obj/item/weapon/flame/lighter = 50, \ + /obj/item/weapon/weldingtool = 25 + ) + + min_duration = 70 + max_duration = 100 + +/datum/surgery_step/face/cauterize/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + return ..() && target.op_stage.face > 0 + +/datum/surgery_step/face/cauterize/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] is beginning to cauterize the incision on [target]'s face and neck with \the [tool]." , \ + "You are beginning to cauterize the incision on [target]'s face and neck with \the [tool].") + ..() + +/datum/surgery_step/face/cauterize/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] cauterizes the incision on [target]'s face and neck with \the [tool].", \ + "You cauterize the incision on [target]'s face and neck with \the [tool].") + if (target.op_stage.face == 3) + var/obj/item/organ/external/head/h = affected + h.disfigured = 0 + target.op_stage.face = 0 + +/datum/surgery_step/face/cauterize/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, leaving a small burn on [target]'s face with \the [tool]!", \ + "Your hand slips, leaving a small burn on [target]'s face with \the [tool]!") + affected.take_damage(0, 4, used_weapon = tool) \ No newline at end of file diff --git a/code/modules/surgery/generic.dm b/code/modules/surgery/generic.dm new file mode 100644 index 00000000..134cb8b2 --- /dev/null +++ b/code/modules/surgery/generic.dm @@ -0,0 +1,338 @@ +//Procedures in this file: Gneric surgery steps +////////////////////////////////////////////////////////////////// +// COMMON STEPS // +////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////// +// generic surgery step datum +////////////////////////////////////////////////////////////////// +/datum/surgery_step/generic/ + can_infect = 1 + shock_level = 10 + +/datum/surgery_step/generic/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (isslime(target)) + return 0 + if (target_zone == BP_EYES) //there are specific steps for eye surgery + return 0 + if (!hasorgans(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if (affected == null) + return 0 + if (affected.is_stump()) + return 0 + if (affected.robotic >= ORGAN_ROBOT) + return 0 + return 1 + +////////////////////////////////////////////////////////////////// +// laser scalpel surgery step +// acts as both cutting and bleeder clamping surgery steps +////////////////////////////////////////////////////////////////// +/datum/surgery_step/generic/cut_with_laser + allowed_tools = list( + /obj/item/weapon/scalpel/laser3 = 95, \ + /obj/item/weapon/scalpel/laser2 = 85, \ + /obj/item/weapon/scalpel/laser1 = 75, \ + /obj/item/weapon/melee/energy/sword = 5 + ) + priority = 2 + min_duration = 90 + max_duration = 110 + +/datum/surgery_step/generic/cut_with_laser/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.open() == SURGERY_CLOSED && target_zone != BP_MOUTH + +/datum/surgery_step/generic/cut_with_laser/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts the bloodless incision on [target]'s [affected.name] with \the [tool].", \ + "You start the bloodless incision on [target]'s [affected.name] with \the [tool].") + target.custom_pain("You feel a horrible, searing pain in your [affected.name]!",50, affecting = affected) + ..() + +/datum/surgery_step/generic/cut_with_laser/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] has made a bloodless incision on [target]'s [affected.name] with \the [tool].", \ + "You have made a bloodless incision on [target]'s [affected.name] with \the [tool].",) + affected.createwound(CUT, affected.min_broken_damage/2, 1) + affected.clamp_wound() + spread_germs_to_organ(affected, user) + +/datum/surgery_step/generic/cut_with_laser/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips as the blade sputters, searing a long gash in [target]'s [affected.name] with \the [tool]!", \ + "Your hand slips as the blade sputters, searing a long gash in [target]'s [affected.name] with \the [tool]!") + affected.take_damage(15, 5, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + +////////////////////////////////////////////////////////////////// +// laser scalpel surgery step +// acts as the cutting, bleeder clamping, and retractor surgery steps +////////////////////////////////////////////////////////////////// +/datum/surgery_step/generic/incision_manager + allowed_tools = list( + /obj/item/weapon/scalpel/manager = 100 + ) + priority = 2 + min_duration = 80 + max_duration = 120 + +/datum/surgery_step/generic/incision_manager/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.open() == SURGERY_CLOSED && target_zone != BP_MOUTH + +/datum/surgery_step/generic/incision_manager/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts to construct a prepared incision on and within [target]'s [affected.name] with \the [tool].", \ + "You start to construct a prepared incision on and within [target]'s [affected.name] with \the [tool].") + target.custom_pain("You feel a horrible, searing pain in your [affected.name] as it is pushed apart!",50, affecting = affected) + ..() + +/datum/surgery_step/generic/incision_manager/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] has constructed a prepared incision on and within [target]'s [affected.name] with \the [tool].", \ + "You have constructed a prepared incision on and within [target]'s [affected.name] with \the [tool].",) + + affected.createwound(CUT, affected.min_broken_damage/2, 1) + affected.clamp_wound() + +/datum/surgery_step/generic/incision_manager/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand jolts as the system sparks, ripping a gruesome hole in [target]'s [affected.name] with \the [tool]!", \ + "Your hand jolts as the system sparks, ripping a gruesome hole in [target]'s [affected.name] with \the [tool]!") + affected.take_damage(20, 15, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + +////////////////////////////////////////////////////////////////// +// scalpel surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/generic/cut_open + allowed_tools = list( + /obj/item/weapon/scalpel = 100, \ + /obj/item/weapon/material/knife = 75, \ + /obj/item/weapon/material/kitchen/utensil/knife = 75, \ + /obj/item/weapon/broken_bottle = 50, + /obj/item/weapon/material/shard = 50, \ + ) + + min_duration = 90 + max_duration = 110 + +/datum/surgery_step/generic/cut_open/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!istype(affected)) + return + if(affected.open()) + var/datum/wound/cut/incision = affected.get_incision() + to_chat(user, "The [incision.desc] provides enough access, another incision isn't needed.") + return SURGERY_FAILURE + return target_zone != BP_MOUTH + +/datum/surgery_step/generic/cut_open/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts the incision on [target]'s [affected.name] with \the [tool].", \ + "You start the incision on [target]'s [affected.name] with \the [tool].") + target.custom_pain("You feel a horrible pain as if from a sharp knife in your [affected.name]!",40, affecting = affected) + ..() + +/datum/surgery_step/generic/cut_open/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] has made an incision on [target]'s [affected.name] with \the [tool].", \ + "You have made an incision on [target]'s [affected.name] with \the [tool].",) + affected.createwound(CUT, affected.min_broken_damage/2, 1) + playsound(target.loc, 'sound/weapons/bladeslice.ogg', 15, 1) + +/datum/surgery_step/generic/cut_open/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, slicing open [target]'s [affected.name] in the wrong place with \the [tool]!", \ + "Your hand slips, slicing open [target]'s [affected.name] in the wrong place with \the [tool]!") + affected.take_damage(10, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + +////////////////////////////////////////////////////////////////// +// bleeder clamping surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/generic/clamp_bleeders + allowed_tools = list( + /obj/item/weapon/hemostat = 100, \ + /obj/item/stack/cable_coil = 75, \ + /obj/item/device/assembly/mousetrap = 20 + ) + + min_duration = 40 + max_duration = 60 + +/datum/surgery_step/generic/clamp_bleeders/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.open() && !affected.clamped() + +/datum/surgery_step/generic/clamp_bleeders/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts clamping bleeders in [target]'s [affected.name] with \the [tool].", \ + "You start clamping bleeders in [target]'s [affected.name] with \the [tool].") + target.custom_pain("The pain in your [affected.name] is maddening!",40, affecting = affected) + ..() + +/datum/surgery_step/generic/clamp_bleeders/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] clamps bleeders in [target]'s [affected.name] with \the [tool].", \ + "You clamp bleeders in [target]'s [affected.name] with \the [tool].") + affected.clamp_wound() + spread_germs_to_organ(affected, user) + playsound(target.loc, 'sound/items/Welder.ogg', 15, 1) + +/datum/surgery_step/generic/clamp_bleeders/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, tearing blood vessals and causing massive bleeding in [target]'s [affected.name] with \the [tool]!", \ + "Your hand slips, tearing blood vessels and causing massive bleeding in [target]'s [affected.name] with \the [tool]!",) + affected.take_damage(10, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + +////////////////////////////////////////////////////////////////// +// retractor surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/generic/retract_skin + allowed_tools = list( + /obj/item/weapon/retractor = 100, \ + /obj/item/weapon/crowbar = 75, + /obj/item/weapon/material/knife = 50, \ + /obj/item/weapon/material/kitchen/utensil/fork = 50 + ) + + priority = 1 + min_duration = 30 + max_duration = 40 + +/datum/surgery_step/generic/retract_skin/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.open() == SURGERY_OPEN //&& !(affected.status & ORGAN_BLEEDING) + +/datum/surgery_step/generic/retract_skin/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts to pry open the incision on [target]'s [affected.name] with \the [tool].", \ + "You start to pry open the incision on [target]'s [affected.name] with \the [tool].") + target.custom_pain("It feels like the skin on your [affected.name] is on fire!",40,affecting = affected) + ..() + +/datum/surgery_step/generic/retract_skin/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] keeps the incision open on [target]'s [affected.name] with \the [tool].", \ + "You keep the incision open on [target]'s [affected.name] with \the [tool].") + var/datum/wound/W = affected.get_incision() + W.open_wound(min(W.damage * 2, W.damage_list[1] - W.damage)) //damage up to the max of the wound. + if(!affected.encased) + for(var/obj/item/weapon/implant/I in affected.implants) + I.exposed() + +/datum/surgery_step/generic/retract_skin/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, tearing the edges of the incision on [target]'s [affected.name] with \the [tool]!", \ + "Your hand slips, tearing the edges of the incision on [target]'s [affected.name] with \the [tool]!") + affected.take_damage(12, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + +////////////////////////////////////////////////////////////////// +// skin cauterization surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/generic/cauterize + allowed_tools = list( + /obj/item/weapon/cautery = 100, \ + /obj/item/clothing/mask/smokable/cigarette = 75, \ + /obj/item/weapon/flame/lighter = 50, \ + /obj/item/weapon/weldingtool = 25 + ) + + min_duration = 70 + max_duration = 100 + +/datum/surgery_step/generic/cauterize/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if(target_zone == BP_MOUTH || target_zone == BP_EYES) + return FALSE + if(!hasorgans(target)) + return FALSE + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!affected) + return FALSE + if(affected.robotic >= ORGAN_ROBOT) + return FALSE + if(!affected.get_incision(1)) + to_chat(user, "There are no incisions on [target]'s [affected.name] that can be closed cleanly with \the [tool]!") + return SURGERY_FAILURE + if(affected.is_stump()) // Copypasting some stuff here to avoid having to modify ..() for a single surgery + return affected.status & ORGAN_ARTERY_CUT + else + return affected.open() + + +/datum/surgery_step/generic/cauterize/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/datum/wound/cut/W = affected.get_incision() + user.visible_message("[user] is beginning to cauterize[W ? " \a [W.desc] on" : ""] \the [target]'s [affected.name] with \the [tool]." , \ + "You are beginning to cauterize[W ? " \a [W.desc] on" : ""] \the [target]'s [affected.name] with \the [tool].") + target.custom_pain("Your [affected.name] is being burned!",40,affecting = affected) + ..() + +/datum/surgery_step/generic/cauterize/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/datum/wound/cut/W = affected.get_incision() + user.visible_message("[user] cauterizes[W ? " \a [W.desc] on" : ""] \the [target]'s [affected.name] with \the [tool].", \ + "You cauterize[W ? " \a [W.desc] on" : ""] \the [target]'s [affected.name] with \the [tool].") + if(W) + W.close() + if(affected.is_stump()) + affected.status &= ~ORGAN_ARTERY_CUT + +/datum/surgery_step/generic/cauterize/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, leaving a small burn on [target]'s [affected.name] with \the [tool]!", \ + "Your hand slips, leaving a small burn on [target]'s [affected.name] with \the [tool]!") + affected.take_damage(0, 3, used_weapon = tool) + +////////////////////////////////////////////////////////////////// +// limb amputation surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/generic/amputate + allowed_tools = list( + /obj/item/weapon/circular_saw = 100, \ + /obj/item/weapon/material/hatchet = 75 + ) + + min_duration = 110 + max_duration = 160 + +/datum/surgery_step/generic/amputate/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (target_zone == BP_EYES) //there are specific steps for eye surgery + return 0 + if (!hasorgans(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if (affected == null) + return 0 + if (affected.open()) + to_chat(user,"You can't get a clean cut with incisions getting in the way.") + return SURGERY_FAILURE + return !affected.cannot_amputate + +/datum/surgery_step/generic/amputate/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] is beginning to amputate [target]'s [affected.name] with \the [tool]." , \ + "You are beginning to cut through [target]'s [affected.amputation_point] with \the [tool].") + target.custom_pain("Your [affected.amputation_point] is being ripped apart!",100,affecting = affected) + ..() + +/datum/surgery_step/generic/amputate/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] amputates [target]'s [affected.name] at the [affected.amputation_point] with \the [tool].", \ + "You amputate [target]'s [affected.name] with \the [tool].") + affected.droplimb(1,DROPLIMB_EDGE) + +/datum/surgery_step/generic/amputate/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, sawing through the bone in [target]'s [affected.name] with \the [tool]!", \ + "Your hand slips, sawwing through the bone in [target]'s [affected.name] with \the [tool]!") + affected.take_damage(30, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + affected.fracture() diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/implant.dm new file mode 100644 index 00000000..b19f5454 --- /dev/null +++ b/code/modules/surgery/implant.dm @@ -0,0 +1,247 @@ +//Procedures in this file: Putting items in body cavity. Implant removal. Items removal. + +////////////////////////////////////////////////////////////////// +// ITEM PLACEMENT SURGERY // +////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////// +// generic implant surgery step datum +////////////////////////////////////////////////////////////////// +/datum/surgery_step/cavity + priority = 1 + shock_level = 40 + delicate = 1 +/datum/surgery_step/cavity/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(!hasorgans(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.open() >= (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED) + +/datum/surgery_step/cavity/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, scraping around inside [target]'s [affected.name] with \the [tool]!", \ + "Your hand slips, scraping around inside [target]'s [affected.name] with \the [tool]!") + affected.take_damage(20, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + +////////////////////////////////////////////////////////////////// +// create implant space surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/cavity/make_space + allowed_tools = list( + /obj/item/weapon/surgicaldrill = 100, \ + /obj/item/weapon/pen = 75, \ + /obj/item/stack/rods = 50 + ) + + min_duration = 60 + max_duration = 80 + +/datum/surgery_step/cavity/make_space/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && !affected.cavity + +/datum/surgery_step/cavity/make_space/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts making some space inside [target]'s [affected.cavity_name] cavity with \the [tool].", \ + "You start making some space inside [target]'s [affected.cavity_name] cavity with \the [tool]." ) + target.custom_pain("The pain in your chest is living hell!",1,affecting = affected) + affected.cavity = 1 + ..() + +/datum/surgery_step/cavity/make_space/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) + user.visible_message("[user] makes some space inside [target]'s [affected.cavity_name] cavity with \the [tool].", \ + "You make some space inside [target]'s [affected.cavity_name] cavity with \the [tool]." ) + +////////////////////////////////////////////////////////////////// +// implant cavity sealing surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/cavity/close_space + priority = 2 + allowed_tools = list( + /obj/item/weapon/cautery = 100, \ + /obj/item/clothing/mask/smokable/cigarette = 75, \ + /obj/item/weapon/flame/lighter = 50, \ + /obj/item/weapon/weldingtool = 25 + ) + + min_duration = 60 + max_duration = 80 + +/datum/surgery_step/cavity/close_space/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.cavity + +/datum/surgery_step/cavity/close_space/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts mending [target]'s [affected.cavity_name] cavity wall with \the [tool].", \ + "You start mending [target]'s [affected.cavity_name] cavity wall with \the [tool]." ) + target.custom_pain("The pain in your chest is living hell!",1,affecting = affected) + affected.cavity = 0 + ..() + +/datum/surgery_step/cavity/close_space/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) + user.visible_message("[user] mends [target]'s [affected.cavity_name] cavity walls with \the [tool].", \ + "You mend [target]'s [affected.cavity_name] cavity walls with \the [tool]." ) + +////////////////////////////////////////////////////////////////// +// implanting surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/cavity/place_item + priority = 0 + allowed_tools = list(/obj/item = 100) + + min_duration = 80 + max_duration = 100 + +/datum/surgery_step/cavity/place_item/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(istype(user,/mob/living/silicon/robot)) + return FALSE + if(affected && affected.cavity) + var/max_volume = base_storage_capacity(affected.cavity_max_w_class) + + if(tool.w_class > affected.cavity_max_w_class) + to_chat(user, "\The [tool] is too big for [affected.cavity_name] cavity.") + return FALSE + + var/total_volume = tool.get_storage_cost() + for(var/obj/item/I in affected.implants) + if(istype(I,/obj/item/weapon/implant)) + continue + total_volume += I.get_storage_cost() + if(total_volume > max_volume) + to_chat(user, "There isn't enough space left in [affected.cavity_name] cavity for [tool].") + return FALSE + return TRUE + + +/datum/surgery_step/cavity/place_item/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts putting \the [tool] inside [target]'s [affected.cavity_name] cavity.", \ + "You start putting \the [tool] inside [target]'s [affected.cavity_name] cavity." ) + target.custom_pain("The pain in your chest is living hell!",1,affecting = affected) + playsound(target.loc, 'sound/effects/squelch1.ogg', 25, 1) + ..() + +/datum/surgery_step/cavity/place_item/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) + + user.visible_message("[user] puts \the [tool] inside [target]'s [affected.cavity_name] cavity.", \ + "You put \the [tool] inside [target]'s [affected.cavity_name] cavity." ) + if (tool.w_class > affected.cavity_max_w_class/2 && prob(50) && !(affected.robotic >= ORGAN_ROBOT) && affected.sever_artery()) + to_chat(user, "You tear some blood vessels trying to fit such a big object in this cavity.") + affected.owner.custom_pain("You feel something rip in your [affected.name]!", 1,affecting = affected) + user.drop_item() + affected.implants += tool + tool.loc = affected + affected.cavity = 0 + +////////////////////////////////////////////////////////////////// +// implant removal surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/cavity/implant_removal + allowed_tools = list( + /obj/item/weapon/hemostat = 100, \ + /obj/item/weapon/wirecutters = 75, \ + /obj/item/weapon/material/kitchen/utensil/fork = 20 + ) + + min_duration = 80 + max_duration = 100 + +/datum/surgery_step/cavity/implant_removal/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!affected) + return FALSE + if(affected.robotic < ORGAN_ROBOT) + return affected.open() >= SURGERY_RETRACTED + else + return affected.hatch_state == HATCH_OPENED + +/datum/surgery_step/cavity/implant_removal/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts poking around inside [target]'s [affected.name] with \the [tool].", \ + "You start poking around inside [target]'s [affected.name] with \the [tool]" ) + target.custom_pain("The pain in your [affected.name] is living hell!",1,affecting = affected) + ..() + +/datum/surgery_step/cavity/implant_removal/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) + var/exposed = 0 + if(affected.open() >= (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED)) + exposed = 1 + if(affected.robotic >= ORGAN_ROBOT && affected.hatch_state == HATCH_OPENED) + exposed = 1 + + var/find_prob = 0 + var/list/loot = list() + if(exposed) + loot = affected.implants + else + for(var/datum/wound/wound in affected.wounds) + loot |= wound.embedded_objects + find_prob += 50 + + if (loot.len) + + var/obj/item/obj = pick(loot) + + if(istype(obj,/obj/item/weapon/implant)) + var/obj/item/weapon/implant/imp = obj + if (imp.islegal()) + find_prob +=60 + else + find_prob +=40 + else + find_prob +=50 + + if (prob(find_prob)) + user.visible_message("[user] takes something out of incision on [target]'s [affected.name] with \the [tool].", \ + "You take [obj] out of incision on [target]'s [affected.name]s with \the [tool]." ) + affected.implants -= obj + for(var/datum/wound/wound in affected.wounds) + if(obj in wound.embedded_objects) + wound.embedded_objects -= obj + break + + BITSET(target.hud_updateflag, IMPLOYAL_HUD) + + //Handle possessive brain borers. + if(istype(obj,/mob/living/simple_animal/borer)) + var/mob/living/simple_animal/borer/worm = obj + if(worm.controlling) + target.release_control() + worm.detatch() + worm.leave_host() + else + obj.dropInto(target.loc) + obj.add_blood(target) + obj.update_icon() + if(istype(obj,/obj/item/weapon/implant)) + var/obj/item/weapon/implant/imp = obj + imp.removed(target) + playsound(target.loc, 'sound/effects/squelch1.ogg', 15, 1) + else + user.visible_message("[user] removes \the [tool] from [target]'s [affected.name].", \ + "There's something inside [target]'s [affected.name], but you just missed it this time." ) + else + user.visible_message("[user] could not find anything inside [target]'s [affected.name], and pulls \the [tool] out.", \ + "You could not find anything inside [target]'s [affected.name]." ) + +/datum/surgery_step/cavity/implant_removal/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + ..() + var/obj/item/organ/external/affected = target.get_organ(target_zone) + for(var/obj/item/weapon/implant/imp in affected.implants) + var/fail_prob = 10 + fail_prob += 100 - tool_quality(tool) + if (prob(fail_prob)) + user.visible_message("Something beeps inside [target]'s [affected.name]!") + playsound(imp.loc, 'sound/items/countdown.ogg', 75, 1, -3) + spawn(25) + imp.activate() + diff --git a/code/modules/surgery/limb_reattach.dm b/code/modules/surgery/limb_reattach.dm new file mode 100644 index 00000000..33d238cc --- /dev/null +++ b/code/modules/surgery/limb_reattach.dm @@ -0,0 +1,143 @@ +//Procedures in this file: Robotic limbs attachment, meat limbs attachment +////////////////////////////////////////////////////////////////// +// LIMB SURGERY // +////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////// +// generic limb surgery step datum +////////////////////////////////////////////////////////////////// +/datum/surgery_step/limb/ + priority = 3 // Must be higher than /datum/surgery_step/internal + can_infect = 0 + shock_level = 40 + delicate = 1 +/datum/surgery_step/limb/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if (affected) + return 0 + var/list/organ_data = target.species.has_limbs["[target_zone]"] + return !isnull(organ_data) + +////////////////////////////////////////////////////////////////// +// limb attachment surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/limb/attach + allowed_tools = list(/obj/item/organ/external = 100) + + min_duration = 50 + max_duration = 70 + +/datum/surgery_step/limb/attach/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = tool + user.visible_message("[user] starts attaching [E.name] to [target]'s [E.amputation_point].", \ + "You start attaching [E.name] to [target]'s [E.amputation_point].") + +/datum/surgery_step/limb/attach/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = tool + user.visible_message("[user] has attached [target]'s [E.name] to the [E.amputation_point].", \ + "You have attached [target]'s [E.name] to the [E.amputation_point].") + user.drop_from_inventory(E) + E.replaced(target) + target.update_body() + target.updatehealth() + target.UpdateDamageIcon() + +/datum/surgery_step/limb/attach/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = tool + user.visible_message(" [user]'s hand slips, damaging [target]'s [E.amputation_point]!", \ + " Your hand slips, damaging [target]'s [E.amputation_point]!") + target.apply_damage(10, BRUTE, null, damage_flags=DAM_SHARP) + +////////////////////////////////////////////////////////////////// +// limb connecting surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/limb/connect + allowed_tools = list( + /obj/item/weapon/hemostat = 100, \ + /obj/item/stack/cable_coil = 75, \ + /obj/item/device/assembly/mousetrap = 20 + ) + can_infect = 1 + + min_duration = 100 + max_duration = 120 + +/datum/surgery_step/limb/connect/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = target.get_organ(target_zone) + return E && !E.is_stump() && (E.status & ORGAN_CUT_AWAY) + +/datum/surgery_step/limb/connect/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = target.get_organ(target_zone) + user.visible_message("[user] starts connecting tendons and muscles in [target]'s [E.amputation_point] with [tool].", \ + "You start connecting tendons and muscle in [target]'s [E.amputation_point].") + +/datum/surgery_step/limb/connect/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = target.get_organ(target_zone) + user.visible_message("[user] has connected tendons and muscles in [target]'s [E.amputation_point] with [tool].", \ + "You have connected tendons and muscles in [target]'s [E.amputation_point] with [tool].") + E.status &= ~ORGAN_CUT_AWAY + if(E.children) + for(var/obj/item/organ/external/C in E.children) + C.status &= ~ORGAN_CUT_AWAY + target.update_body() + target.updatehealth() + target.UpdateDamageIcon() + +/datum/surgery_step/limb/connect/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = target.get_organ(target_zone) + user.visible_message(" [user]'s hand slips, damaging [target]'s [E.amputation_point]!", \ + " Your hand slips, damaging [target]'s [E.amputation_point]!") + target.apply_damage(10, BRUTE, null, damage_flags=DAM_SHARP) + +////////////////////////////////////////////////////////////////// +// robotic limb attachment surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/limb/mechanize + allowed_tools = list(/obj/item/robot_parts = 100) + + min_duration = 80 + max_duration = 100 + +/datum/surgery_step/limb/mechanize/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/robot_parts/p = tool + if (p.part) + if (!(target_zone in p.part)) + return 0 + return isnull(target.get_organ(target_zone)) + +/datum/surgery_step/limb/mechanize/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] starts attaching \the [tool] to [target].", \ + "You start attaching \the [tool] to [target].") + +/datum/surgery_step/limb/mechanize/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/robot_parts/L = tool + user.visible_message("[user] has attached \the [tool] to [target].", \ + "You have attached \the [tool] to [target].") + + if(L.part) + for(var/part_name in L.part) + if(!isnull(target.get_organ(part_name))) + continue + var/list/organ_data = target.species.has_limbs["[part_name]"] + if(!organ_data) + continue + var/new_limb_type = organ_data["path"] + var/obj/item/organ/external/new_limb = new new_limb_type(target) + new_limb.robotize(L.model_info) + if(L.sabotaged) + new_limb.sabotaged = 1 + + target.update_body() + target.updatehealth() + target.UpdateDamageIcon() + + qdel(tool) + +/datum/surgery_step/limb/mechanize/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message(" [user]'s hand slips, damaging [target]'s flesh!", \ + " Your hand slips, damaging [target]'s flesh!") + target.apply_damage(10, BRUTE, null, damage_flags=DAM_SHARP) diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm new file mode 100644 index 00000000..b2d375a0 --- /dev/null +++ b/code/modules/surgery/organs_internal.dm @@ -0,0 +1,499 @@ +//Procedures in this file: internal organ surgery, removal, transplants +////////////////////////////////////////////////////////////////// +// INTERNAL ORGANS // +////////////////////////////////////////////////////////////////// +/datum/surgery_step/internal + priority = 2 + can_infect = 1 + blood_level = 1 + shock_level = 40 + delicate = 1 + +/datum/surgery_step/internal/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return 0 + + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!affected) + return 0 + if(affected.robotic >= ORGAN_ROBOT) + return affected.hatch_state == HATCH_OPENED + else + return affected.open() == (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED) + +////////////////////////////////////////////////////////////////// +// Organ mending surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/internal/fix_organ + allowed_tools = list( + /obj/item/stack/medical/advanced/bruise_pack= 100, \ + /obj/item/stack/medical/bruise_pack = 40, \ + /obj/item/weapon/tape_roll = 20 + ) + + min_duration = 70 + max_duration = 90 + +/datum/surgery_step/internal/fix_organ/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return FALSE + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!affected) + return FALSE + if(affected.robotic >= ORGAN_ROBOT) + return FALSE + for(var/obj/item/organ/internal/I in affected.internal_organs) + if(I.damage > 0) + if(I.surface_accessible) + return TRUE + if(affected.open() >= (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED)) + return TRUE + return FALSE + +/datum/surgery_step/internal/fix_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/tool_name = "\the [tool]" + if (istype(tool, /obj/item/stack/medical/advanced/bruise_pack)) + tool_name = "regenerative membrane" + else if (istype(tool, /obj/item/stack/medical/bruise_pack)) + tool_name = "the bandaid" + + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!affected || affected.open() < 2) + return + for(var/obj/item/organ/internal/I in affected.internal_organs) + if(I && I.damage > 0 && I.robotic < ORGAN_ROBOT && (!I.status & ORGAN_DEAD || I.can_recover()) && (I.surface_accessible || affected.open() >= (affected.encased ? 3 : 2))) + user.visible_message("[user] starts treating damage to [target]'s [I.name] with [tool_name].", \ + "You start treating damage to [target]'s [I.name] with [tool_name]." ) + + target.custom_pain("The pain in your [affected.name] is living hell!",100,affecting = affected) + ..() + +/datum/surgery_step/internal/fix_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/tool_name = "\the [tool]" + if (istype(tool, /obj/item/stack/medical/advanced/bruise_pack)) + tool_name = "regenerative membrane" + if (istype(tool, /obj/item/stack/medical/bruise_pack)) + tool_name = "the bandaid" + + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!affected || affected.open() < 2) + return + for(var/obj/item/organ/internal/I in affected.internal_organs) + if(I && I.damage > 0 && I.robotic < ORGAN_ROBOT && (I.surface_accessible || affected.open() >= (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED))) + if(I.status & ORGAN_DEAD && I.can_recover()) + user.visible_message("[user] treats damage to [target]'s [I.name] with [tool_name], though it needs to be recovered further.", \ + "You treat damage to [target]'s [I.name] with [tool_name], though it needs to be recovered further." ) + else + user.visible_message("[user] treats damage to [target]'s [I.name] with [tool_name].", \ + "You treat damage to [target]'s [I.name] with [tool_name]." ) + I.damage = 0 + +/datum/surgery_step/internal/fix_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + user.visible_message("[user]'s hand slips, getting mess and tearing the inside of [target]'s [affected.name] with \the [tool]!", \ + "Your hand slips, getting mess and tearing the inside of [target]'s [affected.name] with \the [tool]!") + var/dam_amt = 2 + + if (istype(tool, /obj/item/stack/medical/advanced/bruise_pack)) + target.adjustToxLoss(5) + + else + dam_amt = 5 + target.adjustToxLoss(10) + affected.take_damage(dam_amt, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + + for(var/obj/item/organ/internal/I in affected.internal_organs) + if(I && I.damage > 0 && I.robotic < ORGAN_ROBOT && (I.surface_accessible || affected.open() >= (affected.encased ? 3 : 2))) + I.take_damage(dam_amt,0) + +////////////////////////////////////////////////////////////////// +// Organ detatchment surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/internal/detatch_organ + + allowed_tools = list( + /obj/item/weapon/scalpel = 100, \ + /obj/item/weapon/material/knife = 75, \ + /obj/item/weapon/material/kitchen/utensil/knife = 75, \ + /obj/item/weapon/material/shard = 50, \ + ) + + min_duration = 90 + max_duration = 110 + +/datum/surgery_step/internal/detatch_organ/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!..()) + return 0 + + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + if(!affected) + return 0 + + if(affected.robotic >= ORGAN_ROBOT) + return 0 + + target.op_stage.current_organ = null + + var/list/attached_organs = list() + for(var/organ in target.internal_organs_by_name) + var/obj/item/organ/I = target.internal_organs_by_name[organ] + if(I && !(I.status & ORGAN_CUT_AWAY) && I.parent_organ == target_zone) + attached_organs |= organ + + var/organ_to_remove = input(user, "Which organ do you want to separate?") as null|anything in attached_organs + if(!organ_to_remove) + return 0 + + target.op_stage.current_organ = organ_to_remove + + return ..() && organ_to_remove + +/datum/surgery_step/internal/detatch_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] starts to separate [target]'s [target.op_stage.current_organ] with \the [tool].", \ + "You start to separate [target]'s [target.op_stage.current_organ] with \the [tool]." ) + target.custom_pain("Someone's ripping out your [target.op_stage.current_organ]!",100) + ..() + +/datum/surgery_step/internal/detatch_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] has separated [target]'s [target.op_stage.current_organ] with \the [tool]." , \ + "You have separated [target]'s [target.op_stage.current_organ] with \the [tool].") + + var/obj/item/organ/I = target.internal_organs_by_name[target.op_stage.current_organ] + if(I && istype(I)) + I.cut_away(user) + +/datum/surgery_step/internal/detatch_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, slicing an artery inside [target]'s [affected.name] with \the [tool]!", \ + "Your hand slips, slicing an artery inside [target]'s [affected.name] with \the [tool]!") + affected.take_damage(rand(30,50), 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + +////////////////////////////////////////////////////////////////// +// Organ removal surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/internal/remove_organ + priority = 2 + allowed_tools = list( + /obj/item/weapon/hemostat = 100, \ + /obj/item/weapon/wirecutters = 75, + /obj/item/weapon/material/knife = 75, \ + /obj/item/weapon/material/kitchen/utensil/fork = 20 + ) + + min_duration = 60 + max_duration = 80 + +/datum/surgery_step/internal/remove_organ/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!..()) + return 0 + + target.op_stage.current_organ = null + + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!affected) + return 0 + + if(!affected) + return 0 + + var/list/removable_organs = list() + for(var/obj/item/organ/internal/I in affected.implants) + if(I.status & ORGAN_CUT_AWAY) + removable_organs |= I + + var/organ_to_remove = input(user, "Which organ do you want to remove?") as null|anything in removable_organs + if(!organ_to_remove) + return 0 + + target.op_stage.current_organ = organ_to_remove + return ..() + +/datum/surgery_step/internal/remove_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts removing [target]'s [target.op_stage.current_organ] with \the [tool].", \ + "You start removing [target]'s [target.op_stage.current_organ] with \the [tool].") + target.custom_pain("The pain in your [affected.name] is living hell!",100,affecting = affected) + ..() + +/datum/surgery_step/internal/remove_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] has removed [target]'s [target.op_stage.current_organ] with \the [tool].", \ + "You have removed [target]'s [target.op_stage.current_organ] with \the [tool].") + + // Extract the organ! + var/obj/item/organ/O = target.op_stage.current_organ + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(istype(O) && istype(affected)) + affected.implants -= O + O.dropInto(target.loc) + target.op_stage.current_organ = null + if(affected.robotic < ORGAN_ROBOT) + playsound(target.loc, 'sound/effects/squelch1.ogg', 15, 1) + else + playsound(target.loc, 'sound/items/Ratchet.ogg', 50, 1) + if(istype(O, /obj/item/organ/internal/mmi_holder)) + var/obj/item/organ/internal/mmi_holder/brain = O + brain.transfer_and_delete() + + // Just in case somehow the organ we're extracting from an organic is an MMI + if(istype(O, /obj/item/organ/internal/mmi_holder)) + var/obj/item/organ/internal/mmi_holder/brain = O + brain.transfer_and_delete() + +/datum/surgery_step/internal/remove_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, damaging [target]'s [affected.name] with \the [tool]!", \ + "Your hand slips, damaging [target]'s [affected.name] with \the [tool]!") + affected.take_damage(20, used_weapon = tool) + +////////////////////////////////////////////////////////////////// +// Organ inserting surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/internal/replace_organ + allowed_tools = list( + /obj/item/organ = 100 + ) + + min_duration = 60 + max_duration = 80 + +/datum/surgery_step/internal/replace_organ/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + var/obj/item/organ/internal/O = tool + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!affected) return + + if(!istype(O)) + return 0 + + if((affected.robotic >= ORGAN_ROBOT) && !(O.robotic >= ORGAN_ROBOT)) + to_chat(user, "You cannot install a naked organ into a robotic body.") + return SURGERY_FAILURE + + if(!target.species) + CRASH("Target ([target]) of surgery [type] has no species!") + return SURGERY_FAILURE + + var/o_is = (O.gender == PLURAL) ? "are" : "is" + var/o_a = (O.gender == PLURAL) ? "" : "a " + + if(O.organ_tag == BP_POSIBRAIN && !target.species.has_organ[BP_POSIBRAIN]) + to_chat(user, "There's no place in [target] to fit \the [O.organ_tag].") + return SURGERY_FAILURE + + if(O.damage > (O.max_damage * 0.75)) + to_chat(user, "\The [O.name] [o_is] in no state to be transplanted.") + return SURGERY_FAILURE + if(O.w_class > affected.cavity_max_w_class) + to_chat(user, "\The [O.name] [o_is] too big for [affected.cavity_name] cavity!") + return SURGERY_FAILURE + + var/obj/item/organ/internal/I = target.internal_organs_by_name[O.organ_tag] + if(I && (I.parent_organ == affected.organ_tag || istype(O, /obj/item/organ/internal/stack))) + to_chat(user, "\The [target] already has [o_a][O.name].") + return SURGERY_FAILURE + + return ..() + +/datum/surgery_step/internal/replace_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts transplanting \the [tool] into [target]'s [affected.name].", \ + "You start transplanting \the [tool] into [target]'s [affected.name].") + target.custom_pain("Someone's rooting around in your [affected.name]!",100,affecting = affected) + ..() + +/datum/surgery_step/internal/replace_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] has transplanted \the [tool] into [target]'s [affected.name].", \ + "You have transplanted \the [tool] into [target]'s [affected.name].") + var/obj/item/organ/O = tool + if(istype(O)) + user.remove_from_mob(O) + O.forceMove(target) + affected.implants |= O //move the organ into the patient. The organ is properly reattached in the next step + if(!(O.status & ORGAN_CUT_AWAY)) + log_debug("[user] ([user.ckey]) replaced organ [O], which didn't have ORGAN_CUT_AWAY set, in [target] ([target.ckey])") + O.status |= ORGAN_CUT_AWAY + + playsound(target.loc, 'sound/effects/squelch1.ogg', 15, 1) + +/datum/surgery_step/internal/replace_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user]'s hand slips, damaging \the [tool]!", \ + "Your hand slips, damaging \the [tool]!") + var/obj/item/organ/I = tool + if(istype(I)) + I.take_damage(rand(3,5),0) + +////////////////////////////////////////////////////////////////// +// Organ inserting surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/internal/attach_organ + allowed_tools = list( + /obj/item/weapon/FixOVein = 100, \ + ///obj/item/weapon/suture = 100, \ + /obj/item/stack/cable_coil = 75, \ + /obj/item/weapon/tape_roll = 50 + ) + + min_duration = 100 + max_duration = 120 + +/datum/surgery_step/internal/attach_organ/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!..()) + return 0 + + target.op_stage.current_organ = null + + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!affected || affected.robotic >= ORGAN_ROBOT) + // robotic attachment handled via screwdriver + return 0 + + var/list/attachable_organs = list() + for(var/obj/item/organ/I in affected.implants) + if(I && (I.status & ORGAN_CUT_AWAY)) + attachable_organs |= I + + var/obj/item/organ/organ_to_replace = input(user, "Which organ do you want to reattach?") as null|anything in attachable_organs + if(!organ_to_replace) + return 0 + if(organ_to_replace.parent_organ != affected.organ_tag) + to_chat(user, "You can't find anywhere to attach [organ_to_replace] to!") + return SURGERY_FAILURE + + target.op_stage.current_organ = organ_to_replace + return ..() + +/datum/surgery_step/internal/attach_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] begins reattaching [target]'s [target.op_stage.current_organ] with \the [tool].", \ + "You start reattaching [target]'s [target.op_stage.current_organ] with \the [tool].") + target.custom_pain("Someone's digging needles into your [target.op_stage.current_organ]!",100) + ..() + +/datum/surgery_step/internal/attach_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] has reattached [target]'s [target.op_stage.current_organ] with \the [tool]." , \ + "You have reattached [target]'s [target.op_stage.current_organ] with \the [tool].") + + var/obj/item/organ/I = target.op_stage.current_organ + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(istype(I) && I.parent_organ == target_zone && affected && (I in affected.implants)) + I.status &= ~ORGAN_CUT_AWAY //apply fixovein + affected.implants -= I + I.replaced(target, affected) + +/datum/surgery_step/internal/attach_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, damaging the flesh in [target]'s [affected.name] with \the [tool]!", \ + "Your hand slips, damaging the flesh in [target]'s [affected.name] with \the [tool]!") + affected.take_damage(20, used_weapon = tool) + +////////////////////////////////////////////////////////////////// +// Peridaxon necrosis treatment surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/internal/treat_necrosis + priority = 2 + allowed_tools = list( + /obj/item/weapon/reagent_containers/dropper = 100, + /obj/item/weapon/reagent_containers/glass/bottle = 75, + /obj/item/weapon/reagent_containers/glass/beaker = 75, + /obj/item/weapon/reagent_containers/spray = 50, + /obj/item/weapon/reagent_containers/glass/bucket = 50, + ) + + can_infect = 0 + blood_level = 0 + + min_duration = 50 + max_duration = 60 + +/datum/surgery_step/internal/treat_necrosis/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/weapon/reagent_containers/container = tool + if(!istype(container) || !container.reagents.has_reagent(/datum/reagent/peridaxon)) + return 0 + if (!..()) + return 0 + + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + if(!affected) + return 0 + + if(affected.robotic >= ORGAN_ROBOT) + return 0 + + target.op_stage.current_organ = null + + var/obj/item/organ/internal/list/dead_organs = list() + for(var/obj/item/organ/internal/I in target.internal_organs) + if(I && !(I.status & ORGAN_CUT_AWAY) && I.status & ORGAN_DEAD && I.parent_organ == affected.organ_tag && !(I.robotic >= ORGAN_ROBOT)) + dead_organs |= I + + var/obj/item/organ/internal/organ_to_fix = input(user, "Which organ do you want to regenerate?") as null|anything in dead_organs + if(!organ_to_fix) + return 0 + if(!organ_to_fix.can_recover()) + to_chat(user, "The [organ_to_fix.name] is necrotic and can't be saved, it will need to be replaced.") + return 0 + if(organ_to_fix.damage >= organ_to_fix.max_damage) + to_chat(user, "The [organ_to_fix.name] needs to be repaired before it is regenerated.") + return 0 + + target.op_stage.current_organ = organ_to_fix + + return 1 + +/datum/surgery_step/internal/treat_necrosis/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] starts applying medication to the affected tissue in [target]'s [target.op_stage.current_organ] with \the [tool]." , \ + "You start applying medication to the affected tissue in [target]'s [target.op_stage.current_organ] with \the [tool].") + + target.custom_pain("Something in your [target.op_stage.current_organ] is causing you a lot of pain!",50,affecting = target.op_stage.current_organ) + ..() + +/datum/surgery_step/internal/treat_necrosis/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/internal/affected = target.op_stage.current_organ + var/obj/item/weapon/reagent_containers/container = tool + + var/amount = container.amount_per_transfer_from_this + var/datum/reagents/temp_reagents = new(amount, GLOB.temp_reagents_holder) + container.reagents.trans_to_holder(temp_reagents, amount) + + var/rejuvenate = temp_reagents.has_reagent(/datum/reagent/peridaxon) + + var/trans = temp_reagents.trans_to_mob(target, temp_reagents.total_volume, CHEM_BLOOD) //technically it's contact, but the reagents are being applied to internal tissue + if (trans > 0) + + if(rejuvenate) + affected.status &= ~ORGAN_DEAD + affected.owner.update_body(1) + + user.visible_message("[user] applies [trans] unit\s of the solution to affected tissue in [target]'s [affected.name].", \ + "You apply [trans] unit\s of the solution to affected tissue in [target]'s [affected.name] with \the [tool].") + qdel(temp_reagents) + +/datum/surgery_step/internal/treat_necrosis/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + if (!istype(tool, /obj/item/weapon/reagent_containers)) + return + + var/obj/item/weapon/reagent_containers/container = tool + + var/trans = container.reagents.trans_to_mob(target, container.amount_per_transfer_from_this, CHEM_BLOOD) + + user.visible_message("[user]'s hand slips, applying [trans] units of the solution to the wrong place in [target]'s [affected.name] with the [tool]!" , \ + "Your hand slips, applying [trans] units of the solution to the wrong place in [target]'s [affected.name] with the [tool]!") + + //no damage or anything, just wastes medicine diff --git a/code/modules/surgery/other.dm b/code/modules/surgery/other.dm new file mode 100644 index 00000000..dcdb532d --- /dev/null +++ b/code/modules/surgery/other.dm @@ -0,0 +1,178 @@ +//Procedures in this file: Internal wound patching, Implant removal. +////////////////////////////////////////////////////////////////// +// INTERNAL WOUND PATCHING // +////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////// +// Tendon fix surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/fix_tendon + priority = 2 + allowed_tools = list( + /obj/item/weapon/FixOVein = 100, \ + /obj/item/stack/cable_coil = 75, \ + /obj/item/weapon/tape_roll = 50 + ) + can_infect = 1 + blood_level = 1 + + min_duration = 70 + max_duration = 90 + shock_level = 40 + delicate = 1 + +/datum/surgery_step/fix_tendon/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(!hasorgans(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && (affected.status & ORGAN_TENDON_CUT) && affected.open() >= SURGERY_RETRACTED + +/datum/surgery_step/fix_tendon/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts reattaching the damaged [affected.tendon_name] in [target]'s [affected.name] with \the [tool]." , \ + "You start reattaching the damaged [affected.tendon_name] in [target]'s [affected.name] with \the [tool].") + target.custom_pain("The pain in your [affected.name] is unbearable!",100,affecting = affected) + ..() + +/datum/surgery_step/fix_tendon/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] has reattached the [affected.tendon_name] in [target]'s [affected.name] with \the [tool].", \ + "You have reattached the [affected.tendon_name] in [target]'s [affected.name] with \the [tool].") + affected.status &= ~ORGAN_TENDON_CUT + affected.update_damages() + +/datum/surgery_step/fix_tendon/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, smearing [tool] in the incision in [target]'s [affected.name]!" , \ + "Your hand slips, smearing [tool] in the incision in [target]'s [affected.name]!") + affected.take_damage(5, used_weapon = tool) + +////////////////////////////////////////////////////////////////// +// IB fix surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/fix_vein + priority = 3 + allowed_tools = list( + /obj/item/weapon/FixOVein = 100, \ + /obj/item/stack/cable_coil = 75, \ + /obj/item/weapon/tape_roll = 50 + ) + can_infect = 1 + blood_level = 1 + + min_duration = 70 + max_duration = 90 + shock_level = 40 + delicate = 1 + +/datum/surgery_step/fix_vein/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(!hasorgans(target)) + return 0 + + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && (affected.status & ORGAN_ARTERY_CUT) && affected.open() >= SURGERY_RETRACTED + +/datum/surgery_step/fix_vein/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts patching the damaged [affected.artery_name] in [target]'s [affected.name] with \the [tool]." , \ + "You start patching the damaged [affected.artery_name] in [target]'s [affected.name] with \the [tool].") + target.custom_pain("The pain in your [affected.name] is unbearable!",100,affecting = affected) + ..() + +/datum/surgery_step/fix_vein/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] has patched the [affected.artery_name] in [target]'s [affected.name] with \the [tool].", \ + "You have patched the [affected.artery_name] in [target]'s [affected.name] with \the [tool].") + affected.status &= ~ORGAN_ARTERY_CUT + affected.update_damages() + +/datum/surgery_step/fix_vein/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, smearing [tool] in the incision in [target]'s [affected.name]!" , \ + "Your hand slips, smearing [tool] in the incision in [target]'s [affected.name]!") + affected.take_damage(5, used_weapon = tool) + +////////////////////////////////////////////////////////////////// +// Disinfection step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/sterilize + priority = 2 + allowed_tools = list( + /obj/item/weapon/reagent_containers/spray = 100, + /obj/item/weapon/reagent_containers/dropper = 100, + /obj/item/weapon/reagent_containers/glass/bottle = 90, + /obj/item/weapon/reagent_containers/food/drinks/flask = 90, + /obj/item/weapon/reagent_containers/glass/beaker = 75, + /obj/item/weapon/reagent_containers/food/drinks/bottle = 75, + /obj/item/weapon/reagent_containers/food/drinks/glass2 = 75, + /obj/item/weapon/reagent_containers/glass/bucket = 50 + ) + + can_infect = 0 + blood_level = 0 + + min_duration = 50 + max_duration = 60 + +/datum/surgery_step/sterilize/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(!hasorgans(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!istype(affected)) + return 0 + if(affected.is_disinfected()) + return 0 + var/obj/item/weapon/reagent_containers/container = tool + if(!istype(container)) + return 0 + if(!container.is_open_container()) + return 0 + var/datum/reagent/ethanol/booze = locate() in container.reagents.reagent_list + if(istype(booze) && booze.strength >= 40) + to_chat(user, "[booze] is too weak, you need something of higher proof for this...") + return 0 + if(!istype(booze) && !container.reagents.has_reagent(/datum/reagent/sterilizine)) + return 0 + return 1 + +/datum/surgery_step/sterilize/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts pouring [tool]'s contents on \the [target]'s [affected.name]." , \ + "You start pouring [tool]'s contents on \the [target]'s [affected.name].") + target.custom_pain("Your [affected.name] is on fire!",50,affecting = affected) + ..() + +/datum/surgery_step/sterilize/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + if (!istype(tool, /obj/item/weapon/reagent_containers)) + return + + var/obj/item/weapon/reagent_containers/container = tool + + var/amount = container.amount_per_transfer_from_this + var/temp_holder = new/obj() + var/datum/reagents/temp_reagents = new(amount, temp_holder) + container.reagents.trans_to_holder(temp_reagents, amount) + + var/trans = temp_reagents.trans_to_mob(target, temp_reagents.total_volume, CHEM_BLOOD) //technically it's contact, but the reagents are being applied to internal tissue + if (trans > 0) + user.visible_message("[user] rubs [target]'s [affected.name] down with \the [tool]'s contents.", \ + "You rub [target]'s [affected.name] down with \the [tool]'s contents.") + qdel(temp_reagents) + qdel(temp_holder) + +/datum/surgery_step/sterilize/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + if (!istype(tool, /obj/item/weapon/reagent_containers)) + return + + var/obj/item/weapon/reagent_containers/container = tool + + container.reagents.trans_to_mob(target, container.amount_per_transfer_from_this, CHEM_BLOOD) + + user.visible_message("[user]'s hand slips, spilling \the [tool]'s contents over the [target]'s [affected.name]!" , \ + "Your hand slips, spilling \the [tool]'s contents over the [target]'s [affected.name]!") + affected.disinfect() + diff --git a/code/modules/surgery/robotics.dm b/code/modules/surgery/robotics.dm new file mode 100644 index 00000000..d17628d3 --- /dev/null +++ b/code/modules/surgery/robotics.dm @@ -0,0 +1,498 @@ +//Procedures in this file: Robotic surgery steps, organ removal, replacement. MMI insertion, synthetic organ repair. +////////////////////////////////////////////////////////////////// +// ROBOTIC SURGERY // +////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////// +// generic robotic surgery step datum +////////////////////////////////////////////////////////////////// +/datum/surgery_step/robotics/ + can_infect = 0 +/datum/surgery_step/robotics/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!istype(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if (affected == null) + return 0 + if (affected.status & ORGAN_CUT_AWAY) + return 0 + if (affected.robotic < ORGAN_ROBOT) + return 0 + return 1 + +////////////////////////////////////////////////////////////////// +// unscrew robotic limb hatch surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/robotics/unscrew_hatch + allowed_tools = list( + /obj/item/weapon/screwdriver = 100, + /obj/item/weapon/coin = 50, + /obj/item/weapon/material/kitchen/utensil/knife = 50 + ) + + min_duration = 90 + max_duration = 110 + +/datum/surgery_step/robotics/unscrew_hatch/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.hatch_state == HATCH_CLOSED && target_zone != BP_MOUTH + +/datum/surgery_step/robotics/unscrew_hatch/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts to unscrew the maintenance hatch on [target]'s [affected.name] with \the [tool].", \ + "You start to unscrew the maintenance hatch on [target]'s [affected.name] with \the [tool].") + ..() + +/datum/surgery_step/robotics/unscrew_hatch/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] has opened the maintenance hatch on [target]'s [affected.name] with \the [tool].", \ + "You have opened the maintenance hatch on [target]'s [affected.name] with \the [tool].",) + affected.hatch_state = HATCH_UNSCREWED + +/datum/surgery_step/robotics/unscrew_hatch/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s [tool.name] slips, failing to unscrew [target]'s [affected.name].", \ + "Your [tool] slips, failing to unscrew [target]'s [affected.name].") + +////////////////////////////////////////////////////////////////// +// screw robotic limb hatch surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/robotics/screw_hatch + allowed_tools = list( + /obj/item/weapon/screwdriver = 100, + /obj/item/weapon/coin = 50, + /obj/item/weapon/material/kitchen/utensil/knife = 50 + ) + + min_duration = 90 + max_duration = 110 + +/datum/surgery_step/robotics/screw_hatch/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.hatch_state == HATCH_UNSCREWED && target_zone != BP_MOUTH + +/datum/surgery_step/robotics/screw_hatch/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts to screw down the maintenance hatch on [target]'s [affected.name] with \the [tool].", \ + "You start to screw down the maintenance hatch on [target]'s [affected.name] with \the [tool].") + ..() + +/datum/surgery_step/robotics/screw_hatch/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] has screwed down the maintenance hatch on [target]'s [affected.name] with \the [tool].", \ + "You have screwed down the maintenance hatch on [target]'s [affected.name] with \the [tool].",) + affected.hatch_state = HATCH_CLOSED + +/datum/surgery_step/robotics/screw_hatch/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s [tool.name] slips, failing to screw down [target]'s [affected.name].", \ + "Your [tool] slips, failing to screw down [target]'s [affected.name].") + +////////////////////////////////////////////////////////////////// +// open robotic limb surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/robotics/open_hatch + allowed_tools = list( + /obj/item/weapon/retractor = 100, + /obj/item/weapon/crowbar = 100, + /obj/item/weapon/material/kitchen/utensil = 50 + ) + + min_duration = 30 + max_duration = 40 + +/datum/surgery_step/robotics/open_hatch/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.hatch_state == HATCH_UNSCREWED + +/datum/surgery_step/robotics/open_hatch/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts to pry open the maintenance hatch on [target]'s [affected.name] with \the [tool].", + "You start to pry open the maintenance hatch on [target]'s [affected.name] with \the [tool].") + ..() + +/datum/surgery_step/robotics/open_hatch/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] opens the maintenance hatch on [target]'s [affected.name] with \the [tool].", \ + "You open the maintenance hatch on [target]'s [affected.name] with \the [tool].") + affected.hatch_state = HATCH_OPENED + +/datum/surgery_step/robotics/open_hatch/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s [tool.name] slips, failing to open the hatch on [target]'s [affected.name].", + "Your [tool] slips, failing to open the hatch on [target]'s [affected.name].") + +////////////////////////////////////////////////////////////////// +// close robotic limb surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/robotics/close_hatch + allowed_tools = list( + /obj/item/weapon/retractor = 100, + /obj/item/weapon/crowbar = 100, + /obj/item/weapon/material/kitchen/utensil = 50 + ) + + min_duration = 70 + max_duration = 100 + +/datum/surgery_step/robotics/close_hatch/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.hatch_state == HATCH_OPENED && target_zone != BP_MOUTH + +/datum/surgery_step/robotics/close_hatch/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] begins to close the hatch on [target]'s [affected.name] with \the [tool]." , \ + "You begin to close the hatch on [target]'s [affected.name] with \the [tool].") + ..() + +/datum/surgery_step/robotics/close_hatch/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] closes the hatch on [target]'s [affected.name] with \the [tool].", \ + "You close the hatch on [target]'s [affected.name] with \the [tool].") + affected.hatch_state = HATCH_UNSCREWED + affected.germ_level = 0 + +/datum/surgery_step/robotics/close_hatch/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s [tool.name] slips, failing to close the hatch on [target]'s [affected.name].", + "Your [tool.name] slips, failing to close the hatch on [target]'s [affected.name].") + +////////////////////////////////////////////////////////////////// +// robotic limb brute damage repair surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/robotics/repair_brute + allowed_tools = list( + /obj/item/weapon/weldingtool = 100, + /obj/item/weapon/gun/energy/plasmacutter = 50 + ) + + min_duration = 50 + max_duration = 60 + +/datum/surgery_step/robotics/repair_brute/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(isWelder(tool)) + var/obj/item/weapon/weldingtool/welder = tool + if(!welder.isOn() || !welder.remove_fuel(1,user)) + return 0 + return affected && affected.hatch_state == HATCH_OPENED && (affected.disfigured || affected.brute_dam > 0) && target_zone != BP_MOUTH + +/datum/surgery_step/robotics/repair_brute/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] begins to patch damage to [target]'s [affected.name]'s support structure with \the [tool]." , \ + "You begin to patch damage to [target]'s [affected.name]'s support structure with \the [tool].") + ..() + +/datum/surgery_step/robotics/repair_brute/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] finishes patching damage to [target]'s [affected.name] with \the [tool].", \ + "You finish patching damage to [target]'s [affected.name] with \the [tool].") + affected.heal_damage(rand(30,50),0,1,1) + affected.disfigured = 0 + +/datum/surgery_step/robotics/repair_brute/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s [tool.name] slips, damaging the internal structure of [target]'s [affected.name].", + "Your [tool.name] slips, damaging the internal structure of [target]'s [affected.name].") + target.apply_damage(rand(5,10), BURN, affected) + +////////////////////////////////////////////////////////////////// +// robotic limb burn damage repair surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/robotics/repair_burn + allowed_tools = list( + /obj/item/stack/cable_coil = 100 + ) + + min_duration = 50 + max_duration = 60 + +/datum/surgery_step/robotics/repair_burn/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/stack/cable_coil/C = tool + var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/limb_can_operate = ((affected && affected.hatch_state == HATCH_OPENED) && (affected.disfigured || affected.burn_dam > 0) && target_zone != BP_MOUTH) + if(limb_can_operate) + if(istype(C)) + if(!C.get_amount() >= 3) + to_chat(user, "You need three or more cable pieces to repair this damage.") + return SURGERY_FAILURE + C.use(3) + return 1 + return SURGERY_FAILURE + + if(!limb_can_operate) + return 0 + + if(istype(C)) + if(!C.can_use(10)) + to_chat(user, "You need ten or more cable pieces to repair this damage.")//usage amount made more consistent with regular cable repair + + return SURGERY_FAILURE + C.use(10) + return 1 + +/datum/surgery_step/robotics/repair_burn/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] begins to splice new cabling into [target]'s [affected.name]." , \ + "You begin to splice new cabling into [target]'s [affected.name].") + ..() + +/datum/surgery_step/robotics/repair_burn/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] finishes splicing cable into [target]'s [affected.name].", \ + "You finishes splicing new cable into [target]'s [affected.name].") + affected.heal_damage(0,rand(30,50),1,1) + affected.disfigured = 0 + +/datum/surgery_step/robotics/repair_burn/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] causes a short circuit in [target]'s [affected.name]!", + "You cause a short circuit in [target]'s [affected.name]!") + target.apply_damage(rand(5,10), BURN, affected) + +////////////////////////////////////////////////////////////////// +// artificial organ repair surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/robotics/fix_organ_robotic //For artificial organs + allowed_tools = list( + /obj/item/stack/nanopaste = 100, \ + /obj/item/weapon/bonegel = 30, \ + /obj/item/weapon/screwdriver = 70, \ + ) + + min_duration = 70 + max_duration = 90 + +/datum/surgery_step/robotics/fix_organ_robotic/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!affected) return + + for(var/obj/item/organ/internal/I in affected.internal_organs) + if(I.isrobotic() && I.damage > 0) + if(I.surface_accessible) + return TRUE + if(affected.open() >= (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED) || affected.hatch_state == HATCH_OPENED) + return TRUE + +/datum/surgery_step/robotics/fix_organ_robotic/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + for(var/obj/item/organ/I in affected.internal_organs) + if(I && I.damage > 0) + if(I.robotic >= ORGAN_ROBOT) + user.visible_message("[user] starts mending the damage to [target]'s [I.name]'s mechanisms.", \ + "You start mending the damage to [target]'s [I.name]'s mechanisms." ) + ..() + +/datum/surgery_step/robotics/fix_organ_robotic/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + for(var/obj/item/organ/I in affected.internal_organs) + + if(I && I.damage > 0) + if(I.robotic >= ORGAN_ROBOT) + user.visible_message("[user] repairs [target]'s [I.name] with [tool].", \ + "You repair [target]'s [I.name] with [tool]." ) + I.damage = 0 + +/datum/surgery_step/robotics/fix_organ_robotic/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + user.visible_message("[user]'s hand slips, gumming up the mechanisms inside of [target]'s [affected.name] with \the [tool]!", \ + "Your hand slips, gumming up the mechanisms inside of [target]'s [affected.name] with \the [tool]!") + + target.adjustToxLoss(5) + affected.createwound(CUT, 5) + + for(var/obj/item/organ/I in affected.internal_organs) + if(I) + I.take_damage(rand(3,5),0) + +////////////////////////////////////////////////////////////////// +// robotic organ detachment surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/robotics/detatch_organ_robotic + + allowed_tools = list( + /obj/item/device/multitool = 100 + ) + + min_duration = 90 + max_duration = 110 + +/datum/surgery_step/robotics/detatch_organ_robotic/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if(!..()) + return 0 + + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(affected.hatch_state != HATCH_OPENED) + return 0 + + target.op_stage.current_organ = null + + var/list/attached_organs = list() + for(var/organ in target.internal_organs_by_name) + var/obj/item/organ/I = target.internal_organs_by_name[organ] + if(I && !(I.status & ORGAN_CUT_AWAY) && I.parent_organ == target_zone) + attached_organs |= organ + + var/organ_to_remove = input(user, "Which organ do you want to prepare for removal?") as null|anything in attached_organs + if(!organ_to_remove) + return 0 + + target.op_stage.current_organ = organ_to_remove + + return 1 + +/datum/surgery_step/robotics/detatch_organ_robotic/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] starts to decouple [target]'s [target.op_stage.current_organ] with \the [tool].", \ + "You start to decouple [target]'s [target.op_stage.current_organ] with \the [tool]." ) + ..() + +/datum/surgery_step/robotics/detatch_organ_robotic/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] has decoupled [target]'s [target.op_stage.current_organ] with \the [tool]." , \ + "You have decoupled [target]'s [target.op_stage.current_organ] with \the [tool].") + + var/obj/item/organ/internal/I = target.internal_organs_by_name[target.op_stage.current_organ] + if(I && istype(I)) + I.cut_away(user) + +/datum/surgery_step/robotics/detatch_organ_robotic/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user]'s hand slips, disconnecting \the [tool].", \ + "Your hand slips, disconnecting \the [tool].") + +////////////////////////////////////////////////////////////////// +// robotic organ transplant finalization surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/robotics/attach_organ_robotic + allowed_tools = list( + /obj/item/weapon/screwdriver = 100, + ) + + min_duration = 100 + max_duration = 120 + +/datum/surgery_step/robotics/attach_organ_robotic/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!(affected && (affected.robotic >= ORGAN_ROBOT))) + return 0 + if(affected.hatch_state != HATCH_OPENED) + return 0 + + target.op_stage.current_organ = null + + var/list/removable_organs = list() + for(var/obj/item/organ/I in affected.implants) + if ((I.status & ORGAN_CUT_AWAY) && (I.robotic >= ORGAN_ROBOT) && (I.parent_organ == target_zone)) + removable_organs |= I.organ_tag + + var/organ_to_replace = input(user, "Which organ do you want to reattach?") as null|anything in removable_organs + if(!organ_to_replace) + return 0 + + target.op_stage.current_organ = organ_to_replace + return ..() + +/datum/surgery_step/robotics/attach_organ_robotic/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] begins reattaching [target]'s [target.op_stage.current_organ] with \the [tool].", \ + "You start reattaching [target]'s [target.op_stage.current_organ] with \the [tool].") + ..() + +/datum/surgery_step/robotics/attach_organ_robotic/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] has reattached [target]'s [target.op_stage.current_organ] with \the [tool]." , \ + "You have reattached [target]'s [target.op_stage.current_organ] with \the [tool].") + + var/obj/item/organ/external/affected = target.get_organ(target_zone) + for (var/obj/item/organ/I in affected.implants) + if (I.organ_tag == target.op_stage.current_organ) + I.status &= ~ORGAN_CUT_AWAY + affected.implants -= I + I.replaced(target, affected) + break + +/datum/surgery_step/robotics/attach_organ_robotic/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user]'s hand slips, disconnecting \the [tool].", \ + "Your hand slips, disconnecting \the [tool].") + +////////////////////////////////////////////////////////////////// +// mmi installation surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/robotics/install_mmi + allowed_tools = list( + /obj/item/device/mmi = 100, + ) + + min_duration = 60 + max_duration = 80 + +/datum/surgery_step/robotics/install_mmi/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if(target_zone != BP_HEAD) + return + + var/obj/item/device/mmi/M = tool + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!(affected && affected.hatch_state == HATCH_OPENED)) + return 0 + + if(!istype(M)) + return 0 + + if(!M.brainmob || !M.brainmob.client || !M.brainmob.ckey || M.brainmob.stat >= DEAD) + to_chat(user, "That brain is not usable.") + return SURGERY_FAILURE + + if(!(affected.robotic >= ORGAN_ROBOT)) + to_chat(user, "You cannot install a computer brain into a meat body.") + return SURGERY_FAILURE + + if(!target.should_have_organ(BP_BRAIN)) + to_chat(user, "You're pretty sure [target.species.name_plural] don't normally have a brain.") + return SURGERY_FAILURE + + if(!isnull(target.internal_organs[BP_BRAIN])) + to_chat(user, "Your subject already has a brain.") + return SURGERY_FAILURE + + return 1 + +/datum/surgery_step/robotics/install_mmi/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts installing \the [tool] into [target]'s [affected.name].", \ + "You start installing \the [tool] into [target]'s [affected.name].") + ..() + +/datum/surgery_step/robotics/install_mmi/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] has installed \the [tool] into [target]'s [affected.name].", \ + "You have installed \the [tool] into [target]'s [affected.name].") + + var/obj/item/device/mmi/M = tool + var/obj/item/organ/internal/mmi_holder/holder = new(target, 1) + target.internal_organs_by_name[BP_BRAIN] = holder + user.drop_from_inventory(tool) + tool.forceMove(holder) + holder.stored_mmi = tool + holder.update_from_mmi() + + if(M.brainmob && M.brainmob.mind) + M.brainmob.mind.transfer_to(target) + +/datum/surgery_step/robotics/install_mmi/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user]'s hand slips.", \ + "Your hand slips.") diff --git a/code/modules/surgery/slimes.dm b/code/modules/surgery/slimes.dm new file mode 100644 index 00000000..2a81706d --- /dev/null +++ b/code/modules/surgery/slimes.dm @@ -0,0 +1,109 @@ +//Procedures in this file: Slime surgery, core extraction. +////////////////////////////////////////////////////////////////// +// SLIME CORE EXTRACTION // +////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////// +// generic slime surgery step datum +////////////////////////////////////////////////////////////////// +/datum/surgery_step/slime + +/datum/surgery_step/slime/is_valid_target(mob/living/carbon/slime/target) + return istype(target, /mob/living/carbon/slime/) + +/datum/surgery_step/slime/can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + return target.stat == 2 + +////////////////////////////////////////////////////////////////// +// slime flesh cutting surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/slime/cut_flesh + allowed_tools = list( + /obj/item/weapon/scalpel = 100, \ + /obj/item/weapon/material/knife = 75, \ + /obj/item/weapon/material/shard = 50, \ + ) + + min_duration = 5 + max_duration = 2 SECONDS + +/datum/surgery_step/slime/cut_flesh/can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + return ..() && istype(target) && target.core_removal_stage == 0 + +/datum/surgery_step/slime/cut_flesh/begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("[user] starts cutting through [target]'s flesh with \the [tool].", \ + "You start cutting through [target]'s flesh with \the [tool].") + +/datum/surgery_step/slime/cut_flesh/end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("[user] cuts through [target]'s flesh with \the [tool].", \ + "You cut through [target]'s flesh with \the [tool], revealing its silky innards.") + target.core_removal_stage = 1 + +/datum/surgery_step/slime/cut_flesh/fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("[user]'s hand slips, tearing [target]'s flesh with \the [tool]!", \ + "Your hand slips, tearing [target]'s flesh with \the [tool]!") + +////////////////////////////////////////////////////////////////// +// slime innards cutting surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/slime/cut_innards + allowed_tools = list( + /obj/item/weapon/scalpel = 100, \ + /obj/item/weapon/material/knife = 75, \ + /obj/item/weapon/material/shard = 50, \ + ) + + min_duration = 5 + max_duration = 2 SECONDS + +/datum/surgery_step/slime/cut_innards/can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + return ..() && istype(target) && target.core_removal_stage == 1 + +/datum/surgery_step/slime/cut_innards/begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("[user] starts cutting [target]'s silky innards apart with \the [tool].", \ + "You start cutting [target]'s silky innards apart with \the [tool].") + +/datum/surgery_step/slime/cut_innards/end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("[user] cuts [target]'s innards apart with \the [tool], exposing the cores.", \ + "You cut [target]'s innards apart with \the [tool], exposing the cores.") + target.core_removal_stage = 2 + +/datum/surgery_step/slime/cut_innards/fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("[user]'s hand slips, tearing [target]'s innards with \the [tool]!", \ + "Your hand slips, tearing [target]'s innards with \the [tool]!") + +////////////////////////////////////////////////////////////////// +// slime core removal surgery step +////////////////////////////////////////////////////////////////// +/datum/surgery_step/slime/saw_core + allowed_tools = list( + /obj/item/weapon/scalpel/manager = 100, \ + /obj/item/weapon/circular_saw = 100, \ + /obj/item/weapon/material/hatchet = 75 + ) + + min_duration = 1 SECOND + max_duration = 3 SECONDS + +/datum/surgery_step/slime/saw_core/can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + return ..() && (istype(target) && target.core_removal_stage == 2 && target.cores > 0) //This is being passed a human as target, unsure why. + +/datum/surgery_step/slime/saw_core/begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("[user] starts cutting out one of [target]'s cores with \the [tool].", \ + "You start cutting out one of [target]'s cores with \the [tool].") + +/datum/surgery_step/slime/saw_core/end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + target.cores-- + user.visible_message("[user] cuts out one of [target]'s cores with \the [tool].",, \ + "You cut out one of [target]'s cores with \the [tool]. [target.cores] cores left.") + + if(target.cores >= 0) + var/coreType = target.GetCoreType() + new coreType(target.loc) + if(target.cores <= 0) + target.icon_state = "[target.colour] baby slime dead-nocore" + + +/datum/surgery_step/slime/saw_core/fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("[user]'s hand slips, causing \him to miss the core!", \ + "Your hand slips, causing you to miss the core!") diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm new file mode 100644 index 00000000..77e02975 --- /dev/null +++ b/code/modules/surgery/surgery.dm @@ -0,0 +1,172 @@ +/* SURGERY STEPS */ + +/datum/surgery_step + var/priority = 0 //steps with higher priority would be attempted first + + // type path referencing tools that can be used for this step, and how well are they suited for it + var/list/allowed_tools = null + // type paths referencing races that this step applies to. + var/list/allowed_species = null + var/list/disallowed_species = null + + // duration of the step + var/min_duration = 0 + var/max_duration = 0 + + // evil infection stuff that will make everyone hate me + var/can_infect = 0 + //How much blood this step can get on surgeon. 1 - hands, 2 - full body. + var/blood_level = 0 + var/shock_level = 0 //what shock level will this step put patient on + var/delicate = 0 //if this step NEEDS stable optable or can be done on any valid surface with no penalty + +//returns how well tool is suited for this step +/datum/surgery_step/proc/tool_quality(obj/item/tool) + for (var/T in allowed_tools) + if (istype(tool,T)) + return allowed_tools[T] + return 0 + +// Checks if this step applies to the user mob at all +/datum/surgery_step/proc/is_valid_target(mob/living/carbon/human/target) + if(!hasorgans(target)) + return 0 + + if(allowed_species) + for(var/species in allowed_species) + if(target.species.get_bodytype(target) == species) + return 1 + + if(disallowed_species) + for(var/species in disallowed_species) + if(target.species.get_bodytype(target) == species) + return 0 + + return 1 + + +// checks whether this step can be applied with the given user and target +/datum/surgery_step/proc/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + return 0 + +// does stuff to begin the step, usually just printing messages. Moved germs transfering and bloodying here too +/datum/surgery_step/proc/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if (can_infect && affected) + spread_germs_to_organ(affected, user) + if (ishuman(user) && prob(60)) + var/mob/living/carbon/human/H = user + if (blood_level) + H.bloody_hands(target,0) + if (blood_level > 1) + H.bloody_body(target,0) + if(shock_level) + target.shock_stage = max(target.shock_stage, shock_level) + return + +// does stuff to end the step, which is normally print a message + do whatever this step changes +/datum/surgery_step/proc/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + return + +// stuff that happens when the step fails +/datum/surgery_step/proc/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + return null + +/datum/surgery_step/proc/success_chance(mob/living/user, mob/living/carbon/human/target, obj/item/tool) + . = tool_quality(tool) + if(user == target) + . -= 10 + if(ishuman(user)) + var/mob/living/carbon/human/H = user + . -= round(H.shock_stage * 0.5) + if(H.eye_blurry) + . -= 20 + if(H.eye_blind) + . -= 60 + if(delicate) + if(user.slurring) + . -= 10 + if(!target.lying) + . -= 30 + var/turf/T = get_turf(target) + if(locate(/obj/machinery/optable, T)) + . -= 0 + else if(locate(/obj/structure/bed, T)) + . -= 5 + else if(locate(/obj/structure/table, T)) + . -= 10 + else if(locate(/obj/effect/rune/, T)) + . -= 10 + . = max(., 0) + +/proc/spread_germs_to_organ(var/obj/item/organ/external/E, var/mob/living/carbon/human/user) + if(!istype(user) || !istype(E)) return + + var/germ_level = user.germ_level + if(user.gloves) + germ_level = user.gloves.germ_level + + E.germ_level = max(germ_level,E.germ_level) //as funny as scrubbing microbes out with clean gloves is - no. + +/obj/item/proc/do_surgery(mob/living/carbon/M, mob/living/carbon/human/user, fuckup_prob) + if(!istype(M)) + return 0 + if (user.a_intent == I_HURT) //check for Hippocratic Oath + return 0 + var/zone = user.zone_sel.selecting + if(zone in M.op_stage.in_progress) //Can't operate on someone repeatedly. + to_chat(user, "You can't operate on this area while surgery is already in progress.") + return 1 + for(var/datum/surgery_step/S in surgery_steps) + //check if tool is right or close enough and if this step is possible + if(S.tool_quality(src)) + var/step_is_valid = S.can_use(user, M, zone, src) + if(step_is_valid && S.is_valid_target(M)) + if(step_is_valid == SURGERY_FAILURE) // This is a failure that already has a message for failing. + return 1 + M.op_stage.in_progress += zone + S.begin_step(user, M, zone, src) //start on it + //We had proper tools! (or RNG smiled.) and user did not move or change hands. + if(prob(S.success_chance(user, M, src)) && do_mob(user, M, rand(S.min_duration, S.max_duration))) + if(user.statscheck(user.STAT_LEVEL(int), user.SKILL_LEVEL(surgery), "6d6", 20) >= SUCCESS) + S.end_step(user, M, zone, src) //finish successfully + else + visible_message("[user] messes up the surgery step. They must try again.") + //S.fail_step(user, M, zone, src) + //user.my_skills[SKILL(surgery)].give_xp(25, user)//If they fail it then give them some XP for trying. + else if ((src in user.contents) && user.Adjacent(M)) //or + visible_message("[user] messes up the surgery step. They must try again.") + //S.fail_step(user, M, zone, src) //malpractice~ + //user.my_skills[SKILL(surgery)].give_xp(25, user)//If they fail it then give them some XP for trying. + else // This failing silently was a pain. + to_chat(user, "You must remain close to your patient to conduct surgery.") + if (M) + M.op_stage.in_progress -= zone // Clear the in-progress flag. + if (ishuman(M)) + var/mob/living/carbon/human/H = M + H.update_surgery() + return 1 //don't want to do weapony things after surgery + return 0 + +/proc/sort_surgeries() + var/gap = surgery_steps.len + var/swapped = 1 + while (gap > 1 || swapped) + swapped = 0 + if(gap > 1) + gap = round(gap / 1.247330950103979) + if(gap < 1) + gap = 1 + for(var/i = 1; gap + i <= surgery_steps.len; i++) + var/datum/surgery_step/l = surgery_steps[i] //Fucking hate + var/datum/surgery_step/r = surgery_steps[gap+i] //how lists work here + if(l.priority < r.priority) + surgery_steps.Swap(i, gap + i) + swapped = 1 + +/datum/surgery_status/ + var/eyes = 0 + var/face = 0 + var/head_reattach = 0 + var/current_organ = "organ" + var/list/in_progress = list() \ No newline at end of file diff --git a/code/modules/surgery/suture_wound.dm b/code/modules/surgery/suture_wound.dm new file mode 100644 index 00000000..891faa6a --- /dev/null +++ b/code/modules/surgery/suture_wound.dm @@ -0,0 +1,55 @@ +/datum/surgery_step/suture_wounds + + allowed_tools = list( + /obj/item/weapon/FixOVein/suture = 100, + /obj/item/stack/cable_coil = 60 + ) + + min_duration = 70 + max_duration = 100 + + priority = 1 + +/datum/surgery_step/suture_wounds/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(!istype(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!affected || affected.is_stump() || (affected.status & ORGAN_ROBOT)) + return 0 + for(var/datum/wound/W in affected.wounds) + if(W.damage_type == CUT && W.damage) + return 1 + return 0 + +/datum/surgery_step/suture_wounds/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] is beginning to close a wound on [target]'s [affected.name] with \the [tool]." , \ + "You are beginning to close a wound on [target]'s [affected.name] with \the [tool].") + target.custom_pain("Your [affected.name] is being stabbed!", 100, affecting = affected) + ..() + +/datum/surgery_step/suture_wounds/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + for(var/datum/wound/W in affected.wounds) + if(W.damage_type == CUT && W.damage) + // Close it up to a point that it can be bandaged and heal naturally! + W.heal_damage(rand(10,20)+10) + if(W.damage >= W.autoheal_cutoff) + user.visible_message("\The [user] partially closes a wound on [target]'s [affected.name] with \the [tool].", \ + "You partially close a wound on [target]'s [affected.name] with \the [tool].") + else + user.visible_message("\The [user] closes a wound on [target]'s [affected.name] with \the [tool].", \ + "You close a wound on [target]'s [affected.name] with \the [tool].") + if(!W.damage) + affected.wounds -= W + qdel(W) + else if(W.damage <= 10) + W.clamped = 1 + break + affected.update_damages() + +/datum/surgery_step/suture_wounds/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\red [user]'s hand slips, tearing [target]'s [affected.name] with \the [tool]!", \ + "\red Your hand slips, tearing [target]'s [affected.name] with \the [tool]!") + target.apply_damage(3, BRUTE, affected) \ No newline at end of file diff --git a/code/modules/surgery/~defines.dm b/code/modules/surgery/~defines.dm new file mode 100644 index 00000000..6b27ac56 --- /dev/null +++ b/code/modules/surgery/~defines.dm @@ -0,0 +1 @@ +#undef SURGERY_FAILURE diff --git a/code/modules/tables/debug.dm b/code/modules/tables/debug.dm new file mode 100644 index 00000000..60cd442f --- /dev/null +++ b/code/modules/tables/debug.dm @@ -0,0 +1,22 @@ + +// Mostly for debugging table connections +// This file is not #included in the .dme. + +/obj/structure/table/debug + New() + material = get_material_by_name("debugium") + ..() + +/material/debug + name = "debugium" + stack_type = /obj/item/stack/material/debug + icon_base = "debug" + icon_reinf = "rdebug" + icon_colour = "#ffffff" + +/obj/item/stack/material/debug + name = "debugium" + icon = 'icons/obj/tables.dmi' + icon_state = "debugium" + default_type = "debugium" + diff --git a/code/modules/tables/flipping.dm b/code/modules/tables/flipping.dm new file mode 100644 index 00000000..42790dfe --- /dev/null +++ b/code/modules/tables/flipping.dm @@ -0,0 +1,118 @@ + +/obj/structure/table/proc/straight_table_check(var/direction) + if(health > 100) + return 0 + var/obj/structure/table/T + for(var/angle in list(-90,90)) + T = locate() in get_step(src.loc,turn(direction,angle)) + if(T && T.flipped == 0 && T.material && material && T.material.name == material.name) + return 0 + T = locate() in get_step(src.loc,direction) + if (!T || T.flipped == 1 || T.material != material) + return 1 + return T.straight_table_check(direction) + +/obj/structure/table/verb/do_flip() + set name = "Flip table" + set desc = "Flips a non-reinforced table" + set category = "Object" + set src in oview(1) + + if (!can_touch(usr) || ismouse(usr)) + return + + if(flipped < 0 || !flip(get_cardinal_dir(usr,src))) + to_chat(usr, "It won't budge.") + return + + usr.visible_message("[usr] flips \the [src]!") + + if(atom_flags & ATOM_FLAG_CLIMBABLE) + object_shaken() + + return + +/obj/structure/table/proc/unflipping_check(var/direction) + + for(var/mob/M in oview(src,0)) + return 0 + + var/obj/occupied = turf_is_crowded() + if(occupied) + to_chat(usr, "There's \a [occupied] in the way.") + return 0 + + var/list/L = list() + if(direction) + L.Add(direction) + else + L.Add(turn(src.dir,-90)) + L.Add(turn(src.dir,90)) + for(var/new_dir in L) + var/obj/structure/table/T = locate() in get_step(src.loc,new_dir) + if(T && T.material && material && T.material.name == material.name) + if(T.flipped == 1 && T.dir == src.dir && !T.unflipping_check(new_dir)) + return 0 + return 1 + +/obj/structure/table/proc/do_put() + set name = "Put table back" + set desc = "Puts flipped table back" + set category = "Object" + set src in oview(1) + + if (!can_touch(usr)) + return + + if (!unflipping_check()) + to_chat(usr, "It won't budge.") + return + unflip() + +/obj/structure/table/proc/flip(var/direction) + if( !straight_table_check(turn(direction,90)) || !straight_table_check(turn(direction,-90)) ) + return 0 + + verbs -=/obj/structure/table/verb/do_flip + verbs +=/obj/structure/table/proc/do_put + + var/list/targets = list(get_step(src,dir),get_step(src,turn(dir, 45)),get_step(src,turn(dir, -45))) + for (var/atom/movable/A in get_turf(src)) + if (!A.anchored) + spawn(0) + A.throw_at(pick(targets),1,1) + + set_dir(direction) + if(dir != NORTH) + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + atom_flags &= ~ATOM_FLAG_CLIMBABLE //flipping tables allows them to be used as makeshift barriers + flipped = 1 + atom_flags |= ATOM_FLAG_CHECKS_BORDER + for(var/D in list(turn(direction, 90), turn(direction, -90))) + var/obj/structure/table/T = locate() in get_step(src,D) + if(T && T.can_connect() && T.flipped == 0 && material && T.material && T.material.name == material.name) + T.flip(direction) + take_damage(rand(5, 10)) + update_connections(1) + update_icon() + + return 1 + +/obj/structure/table/proc/unflip() + verbs -=/obj/structure/table/proc/do_put + verbs +=/obj/structure/table/verb/do_flip + + reset_plane_and_layer() + atom_flags |= ATOM_FLAG_CLIMBABLE + flipped = 0 + atom_flags &= ~ATOM_FLAG_CHECKS_BORDER + for(var/D in list(turn(dir, 90), turn(dir, -90))) + var/obj/structure/table/T = locate() in get_step(src.loc,D) + if(T && T.flipped == 1 && T.dir == src.dir && material && T.material&& T.material.name == material.name) + T.unflip() + + update_connections(1) + update_icon() + + return 1 \ No newline at end of file diff --git a/code/modules/tables/interactions.dm b/code/modules/tables/interactions.dm new file mode 100644 index 00000000..4289acbf --- /dev/null +++ b/code/modules/tables/interactions.dm @@ -0,0 +1,184 @@ + +/obj/structure/table/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group || (height==0)) return 1 + if(istype(mover,/obj/item/projectile)) + return (check_cover(mover,target)) + if (flipped == 1) + if (get_dir(loc, target) == dir) + return !density + else + return 1 + if(istype(mover) && mover.checkpass(PASS_FLAG_TABLE)) + return 1 + var/obj/structure/table/T = (locate() in get_turf(mover)) + return (T && !T.flipped) //If we are moving from a table, check if it is flipped. + //If the table we are standing on is not flipped, then we can move freely to another table. + + +//checks if projectile 'P' from turf 'from' can hit whatever is behind the table. Returns 1 if it can, 0 if bullet stops. +/obj/structure/table/proc/check_cover(obj/item/projectile/P, turf/from) + var/turf/cover + if(flipped) + cover = get_turf(src) + else + cover = get_step(loc, get_dir(from, loc)) + if(!cover) + return 1 + if (get_dist(P.starting, loc) <= 1) //Tables won't help you if people are THIS close + return 1 + + var/chance = 20 + if(ismob(P.original) && get_turf(P.original) == cover) + var/mob/M = P.original + if (M.lying) + chance += 20 //Lying down lets you catch less bullets + if(flipped) + if(get_dir(loc, from) == dir) //Flipped tables catch mroe bullets + chance += 30 + else + return 1 //But only from one side + + if(prob(chance)) + return 0 //blocked + return 1 + +/obj/structure/table/bullet_act(obj/item/projectile/P) + if(!(P.damage_type == BRUTE || P.damage_type == BURN)) + return 0 + + if(take_damage(P.damage/2)) + //prevent tables with 1 health left from stopping bullets outright + return PROJECTILE_CONTINUE //the projectile destroyed the table, so it gets to keep going + + visible_message("\The [P] hits [src]!") + return 0 + +/obj/structure/table/CheckExit(atom/movable/O as mob|obj, target as turf) + if(istype(O) && O.checkpass(PASS_FLAG_TABLE)) + return 1 + if (flipped==1) + if (get_dir(loc, target) == dir) + return !density + else + return 1 + return 1 + + +/obj/structure/table/MouseDrop_T(obj/O as obj, mob/user as mob) + + if ((!( istype(O, /obj/item/weapon) ) || user.get_active_hand() != O)) + return ..() + if(isrobot(user)) + return + user.drop_item() + if (O.loc != src.loc) + step(O, get_dir(O, src)) + return + + +/obj/structure/table/attackby(obj/item/W, mob/user, var/click_params) + if (!W) return + + // Handle harm intent grabbing/tabling. + if(istype(W, /obj/item/grab) && get_dist(src,user)<2) + var/obj/item/grab/G = W + if (istype(G.affecting, /mob/living/carbon/human)) + var/obj/occupied = turf_is_crowded() + if(occupied) + to_chat(user, "There's \a [occupied] in the way.") + return + + if(G.force_danger()) + G.affecting.forceMove(src.loc) + G.affecting.Weaken(rand(2,5)) + visible_message("[G.assailant] puts [G.affecting] on \the [src].") + qdel(W) + else + to_chat(user, "You need a better grip to do that!") + return + + // Handle dismantling or placing things on the table from here on. + if(isrobot(user)) + return + + if(W.loc != user) // This should stop mounted modules ending up outside the module. + return + + if(istype(W, /obj/item/weapon/melee/energy/blade)) + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, src.loc) + spark_system.start() + playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1) + playsound(src.loc, "sparks", 50, 1) + user.visible_message("\The [src] was sliced apart by [user]!") + break_to_parts() + return + + if(can_plate && !material) + to_chat(user, "There's nothing to put \the [W] on! Try adding plating to \the [src] first.") + return + + // Placing stuff on tables + if(user.drop_from_inventory(W, src.loc)) + if(W.table_sound) + playsound(src, W.table_sound, 50, FALSE) + auto_align(W, click_params) + return 1 + + return + +/* +Automatic alignment of items to an invisible grid, defined by CELLS and CELLSIZE, defined in code/__defines/misc.dm. +Since the grid will be shifted to own a cell that is perfectly centered on the turf, we end up with two 'cell halves' +on edges of each row/column. +Each item defines a center_of_mass, which is the pixel of a sprite where its projected center of mass toward a turf +surface can be assumed. For a piece of paper, this will be in its center. For a bottle, it will be (near) the bottom +of the sprite. +auto_align() will then place the sprite so the defined center_of_mass is at the bottom left corner of the grid cell +closest to where the cursor has clicked on. +Note: This proc can be overwritten to allow for different types of auto-alignment. +*/ +/obj/item/var/center_of_mass = "x=16;y=16" //can be null for no exact placement behaviour +/obj/item/var/table_sound = null //Fuck you bay. I'm putting this here because you put your shitty var here too. +/obj/structure/table/proc/auto_align(obj/item/W, click_params) + if (!W.center_of_mass) // Clothing, material stacks, generally items with large sprites where exact placement would be unhandy. + W.pixel_x = rand(-W.randpixel, W.randpixel) + W.pixel_y = rand(-W.randpixel, W.randpixel) + W.pixel_z = 0 + return + + if (!click_params) + return + + var/list/click_data = params2list(click_params) + if (!click_data["icon-x"] || !click_data["icon-y"]) + return + + // Calculation to apply new pixelshift. + var/mouse_x = text2num(click_data["icon-x"])-1 // Ranging from 0 to 31 + var/mouse_y = text2num(click_data["icon-y"])-1 + + var/cell_x = Clamp(round(mouse_x/CELLSIZE), 0, CELLS-1) // Ranging from 0 to CELLS-1 + var/cell_y = Clamp(round(mouse_y/CELLSIZE), 0, CELLS-1) + + var/list/center = cached_key_number_decode(W.center_of_mass) + + W.pixel_x = (CELLSIZE * (cell_x + 0.5)) - center["x"] + W.pixel_y = (CELLSIZE * (cell_y + 0.5)) - center["y"] + W.pixel_z = 0 + +/obj/structure/table/rack/auto_align(obj/item/W, click_params) + if(W && !W.center_of_mass) + ..(W) + + var/i = -1 + for (var/obj/item/I in get_turf(src)) + if (I.anchored || !I.center_of_mass) + continue + i++ + I.pixel_x = max(3-i*3, -3) + 1 // There's a sprite layering bug for 0/0 pixelshift, so we avoid it. + I.pixel_y = max(4-i*4, -4) + 1 + I.pixel_z = 0 + +/obj/structure/table/attack_tk() // no telehulk sorry + return diff --git a/code/modules/tables/presets.dm b/code/modules/tables/presets.dm new file mode 100644 index 00000000..3c12d919 --- /dev/null +++ b/code/modules/tables/presets.dm @@ -0,0 +1,57 @@ +/obj/structure/table/standard + icon_state = "plain_preview" + color = COLOR_OFF_WHITE + material = DEFAULT_TABLE_MATERIAL + +/obj/structure/table/steel + icon_state = "plain_preview" + color = COLOR_GRAY40 + material = DEFAULT_WALL_MATERIAL + +/obj/structure/table/marble + icon_state = "stone_preview" + color = COLOR_GRAY80 + material = "marble" + +/obj/structure/table/reinforced + icon_state = "reinf_preview" + color = COLOR_OFF_WHITE + material = DEFAULT_TABLE_MATERIAL + reinforced = DEFAULT_WALL_MATERIAL + +/obj/structure/table/steel_reinforced + icon_state = "reinf_preview" + color = COLOR_GRAY40 + material = DEFAULT_WALL_MATERIAL + reinforced = DEFAULT_WALL_MATERIAL + +/obj/structure/table/woodentable + icon_state = "solid_preview" + color = COLOR_BROWN_ORANGE + material = "wood" + +/obj/structure/table/gamblingtable + icon_state = "gamble_preview" + carpeted = 1 + material = "wood" + +/obj/structure/table/glass + icon_state = "plain_preview" + color = COLOR_DEEP_SKY_BLUE + alpha = 77 // 0.3 * 255 + material = "glass" + +/obj/structure/table/glass/pglass + color = "#8f29a3" + material = "phglass" + +/obj/structure/table/holotable + icon_state = "holo_preview" + color = COLOR_OFF_WHITE +/obj/structure/table/holotable/New() + material = "holo[DEFAULT_TABLE_MATERIAL]" + ..() + +/obj/structure/table/holo_woodentable + icon_state = "holo_preview" + material = "holowood" diff --git a/code/modules/tables/rack.dm b/code/modules/tables/rack.dm new file mode 100644 index 00000000..f0ea26b4 --- /dev/null +++ b/code/modules/tables/rack.dm @@ -0,0 +1,56 @@ +/obj/structure/table/rack + name = "rack" + desc = "Different from the Middle Ages version." + icon = 'icons/obj/objects.dmi' + icon_state = "rack" + can_plate = 0 + can_reinforce = 0 + flipped = -1 + + material = DEFAULT_TABLE_MATERIAL + +/obj/structure/table/rack/New() + ..() + verbs -= /obj/structure/table/verb/do_flip + verbs -= /obj/structure/table/proc/do_put + +/obj/structure/table/rack/Initialize() + auto_align() + . = ..() + +/obj/structure/table/rack/update_connections() + return + +/obj/structure/table/rack/update_desc() + return + +/obj/structure/table/rack/update_icon() + return + +/obj/structure/table/rack/can_connect() + return FALSE + +/obj/structure/table/rack/holorack/dismantle(obj/item/weapon/wrench/W, mob/user) + to_chat(user, "You cannot dismantle \the [src].") + return + +/obj/structure/table/rack/bograck + name = "strange rack" + desc ="Must be the color." + icon = 'icons/obj/objects.dmi' + icon_state = "bograck" + can_plate = 0 + can_reinforce = 0 + flipped = -1 + +/obj/structure/table/rack/dark + color = COLOR_GRAY40 + +/obj/structure/table/rack/shelf + name = "shelf" + desc = "You can put things on it, actually." + icon = 'icons/obj/objects.dmi' + icon_state = "shelf" + can_plate = 0 + can_reinforce = 0 + flipped = -1 \ No newline at end of file diff --git a/code/modules/tables/tables.dm b/code/modules/tables/tables.dm new file mode 100644 index 00000000..48eca039 --- /dev/null +++ b/code/modules/tables/tables.dm @@ -0,0 +1,493 @@ +/obj/structure/table + name = "table frame" + icon = 'icons/obj/tables.dmi' + icon_state = "frame" + desc = "It's a table, for putting things on. Or standing on, if you really want to." + density = 1 + anchored = 1 + atom_flags = ATOM_FLAG_CLIMBABLE + layer = TABLE_LAYER + throwpass = 1 + var/flipped = 0 + var/maxhealth = 10 + var/health = 10 + + // For racks. + var/can_reinforce = 1 + var/can_plate = 1 + + var/manipulating = 0 + var/material/material = null + var/material/reinforced = null + + // Gambling tables. I'd prefer reinforced with carpet/felt/cloth/whatever, but AFAIK it's either harder or impossible to get /obj/item/stack/material of those. + // Convert if/when you can easily get stacks of these. + var/carpeted = 0 + + var/list/connections = list("nw0", "ne0", "sw0", "se0") + +/obj/structure/table/New() + if(istext(material)) + material = get_material_by_name(material) + if(istext(reinforced)) + reinforced = get_material_by_name(reinforced) + ..() + +/obj/structure/table/proc/update_material() + var/old_maxhealth = maxhealth + if(!material) + maxhealth = 10 + else + maxhealth = material.integrity / 2 + + if(reinforced) + maxhealth += reinforced.integrity / 2 + + health += maxhealth - old_maxhealth + +/obj/structure/table/proc/take_damage(amount) + // If the table is made of a brittle material, and is *not* reinforced with a non-brittle material, damage is multiplied by TABLE_BRITTLE_MATERIAL_MULTIPLIER + if(material && material.is_brittle()) + if(reinforced) + if(reinforced.is_brittle()) + amount *= TABLE_BRITTLE_MATERIAL_MULTIPLIER + else + amount *= TABLE_BRITTLE_MATERIAL_MULTIPLIER + health -= amount + if(health <= 0) + visible_message("\The [src] breaks down!") + return break_to_parts() // if we break and form shards, return them to the caller to do !FUN! things with + +//Thanks InfinityStation! +/obj/structure/table/Crossed(var/mob/living/M as mob) + if(!flipped) + if(istype(M)) + M.pixel_y = 12 + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.client) + H.fov_mask.screen_loc = "1,1.5" + H.fov.screen_loc = "1,1.5" + +/obj/structure/table/Uncrossed(var/mob/living/M as mob) + if(!flipped) + if(istype(M)) + M.pixel_y = 0 + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.client) + H.fov_mask.screen_loc = "1,1" + H.fov.screen_loc = "1,1" + +/obj/structure/table/Initialize() + . = ..() + + // One table per turf. + for(var/obj/structure/table/T in loc) + if(T != src) + // There's another table here that's not us, break to metal. + // break_to_parts calls qdel(src) + break_to_parts(full_return = 1) + return + + // reset color/alpha, since they're set for nice map previews + color = "#ffffff" + alpha = 255 + update_connections(1) + update_icon() + update_desc() + update_material() + +/obj/structure/table/Destroy() + material = null + reinforced = null + update_connections(1) // Update tables around us to ignore us (material=null forces no connections) + for(var/obj/structure/table/T in oview(src, 1)) + T.update_icon() + . = ..() + +/obj/structure/table/examine(mob/user) + . = ..() + if(health < maxhealth) + switch(health / maxhealth) + if(0.0 to 0.5) + to_chat(user, "It looks severely damaged!") + if(0.25 to 0.5) + to_chat(user, "It looks damaged!") + if(0.5 to 1.0) + to_chat(user, "It has a few scrapes and dents.") +/obj/structure/table/attackby(obj/item/weapon/W, mob/user) + + if(reinforced && istype(W, /obj/item/weapon/screwdriver)) + remove_reinforced(W, user) + if(!reinforced) + update_desc() + update_icon() + update_material() + return 1 + + if(carpeted && isCrowbar(W)) + user.visible_message("\The [user] removes the carpet from \the [src].", + "You remove the carpet from \the [src].") + new /obj/item/stack/tile/carpet(loc) + carpeted = 0 + update_icon() + return 1 + + if(!carpeted && material && istype(W, /obj/item/stack/tile/carpet)) + var/obj/item/stack/tile/carpet/C = W + if(C.use(1)) + user.visible_message("\The [user] adds \the [C] to \the [src].", + "You add \the [C] to \the [src].") + carpeted = 1 + update_icon() + return 1 + else + to_chat(user, "You don't have enough carpet!") + if(!reinforced && !carpeted && material && istype(W, /obj/item/weapon/wrench)) + remove_material(W, user) + if(!material) + update_connections(1) + update_icon() + for(var/obj/structure/table/T in oview(src, 1)) + T.update_icon() + update_desc() + update_material() + return 1 + + if(!carpeted && !reinforced && !material && istype(W, /obj/item/weapon/wrench)) + dismantle(W, user) + return 1 + + if(health < maxhealth && isWelder(W)) + var/obj/item/weapon/weldingtool/F = W + if(F.welding) + to_chat(user, "You begin reparing damage to \the [src].") + playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) + if(!do_after(user, 20, src) || !F.remove_fuel(1, user)) + return + user.visible_message("\The [user] repairs some damage to \the [src].", + "You repair some damage to \the [src].") + health = max(health+(maxhealth/5), maxhealth) // 20% repair per application + return 1 + + if(!material && can_plate && istype(W, /obj/item/stack/material)) + material = common_material_add(W, user, "plat") + if(material) + update_connections(1) + update_icon() + update_desc() + update_material() + return 1 + + return ..() + +/obj/structure/table/MouseDrop_T(obj/item/stack/material/what) + if(can_reinforce && isliving(usr) && (!usr.stat) && istype(what) && usr.get_active_hand() == what && Adjacent(usr)) + reinforce_table(what, usr) + else + return ..() + +/obj/structure/table/proc/reinforce_table(obj/item/stack/material/S, mob/user) + if(reinforced) + to_chat(user, "\The [src] is already reinforced!") + return + + if(!can_reinforce) + to_chat(user, "\The [src] cannot be reinforced!") + return + + if(!material) + to_chat(user, "Plate \the [src] before reinforcing it!") + return + + if(flipped) + to_chat(user, "Put \the [src] back in place before reinforcing it!") + return + + reinforced = common_material_add(S, user, "reinforc") + if(reinforced) + update_desc() + update_icon() + update_material() + +/obj/structure/table/proc/update_desc() + if(material) + name = "[material.display_name] table" + else + name = "table frame" + + if(reinforced) + name = "reinforced [name]" + desc = "[initial(desc)] This one seems to be reinforced with [reinforced.display_name]." + else + desc = initial(desc) + +// Returns the material to set the table to. +/obj/structure/table/proc/common_material_add(obj/item/stack/material/S, mob/user, verb) // Verb is actually verb without 'e' or 'ing', which is added. Works for 'plate'/'plating' and 'reinforce'/'reinforcing'. + var/material/M = S.get_material() + if(!istype(M)) + to_chat(user, "You cannot [verb]e \the [src] with \the [S].") + return null + + if(manipulating) return M + manipulating = 1 + to_chat(user, "You begin [verb]ing \the [src] with [M.display_name].") + if(!do_after(user, 20, src) || !S.use(1)) + manipulating = 0 + return null + user.visible_message("\The [user] [verb]es \the [src] with [M.display_name].", "You finish [verb]ing \the [src].") + manipulating = 0 + return M + +/obj/structure/table/MiddleClick(var/mob/M) + do_climb(M, TRUE) + +/obj/structure/table/do_climb(var/mob/living/user) + if(reinforced) + if(!user.is_physically_disabled()) + var/turf/above = GetAbove(src) + if(istype(above, /turf/simulated/open)) + return ..() + else + to_chat(user, "Ceiling is too low here!") + else + return ..() + +// Returns the material to set the table to. +/obj/structure/table/proc/common_material_remove(mob/user, material/M, delay, what, type_holding, sound) + if(!M.stack_type) + to_chat(user, "You are unable to remove the [what] from this table!") + return M + + if(manipulating) return M + manipulating = 1 + user.visible_message("\The [user] begins removing the [type_holding] holding \the [src]'s [M.display_name] [what] in place.", + "You begin removing the [type_holding] holding \the [src]'s [M.display_name] [what] in place.") + if(sound) + playsound(src.loc, sound, 50, 1) + if(!do_after(user, 40, src)) + manipulating = 0 + return M + user.visible_message("\The [user] removes the [M.display_name] [what] from \the [src].", + "You remove the [M.display_name] [what] from \the [src].") + new M.stack_type(src.loc) + manipulating = 0 + return null + +/obj/structure/table/proc/remove_reinforced(obj/item/weapon/screwdriver/S, mob/user) + reinforced = common_material_remove(user, reinforced, 40, "reinforcements", "screws", 'sound/items/Screwdriver.ogg') + +/obj/structure/table/proc/remove_material(obj/item/weapon/wrench/W, mob/user) + material = common_material_remove(user, material, 20, "plating", "bolts", 'sound/items/Ratchet.ogg') + +/obj/structure/table/proc/dismantle(obj/item/weapon/wrench/W, mob/user) + if(manipulating) return + manipulating = 1 + user.visible_message("\The [user] begins dismantling \the [src].", + "You begin dismantling \the [src].") + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + if(!do_after(user, 20, src)) + manipulating = 0 + return + user.visible_message("\The [user] dismantles \the [src].", + "You dismantle \the [src].") + new /obj/item/stack/material/steel(src.loc) + qdel(src) + return + +// Returns a list of /obj/item/weapon/material/shard objects that were created as a result of this table's breakage. +// Used for !fun! things such as embedding shards in the faces of tableslammed people. + +// The repeated +// S = [x].place_shard(loc) +// if(S) shards += S +// is to avoid filling the list with nulls, as place_shard won't place shards of certain materials (holo-wood, holo-steel) + +/obj/structure/table/proc/break_to_parts(full_return = 0) + var/list/shards = list() + var/obj/item/weapon/material/shard/S = null + if(reinforced) + if(reinforced.stack_type && (full_return || prob(20))) + reinforced.place_sheet(loc) + else + S = reinforced.place_shard(loc) + if(S) shards += S + if(material) + if(material.stack_type && (full_return || prob(20))) + material.place_sheet(loc) + else + S = material.place_shard(loc) + if(S) shards += S + if(carpeted && (full_return || prob(50))) // Higher chance to get the carpet back intact, since there's no non-intact option + new /obj/item/stack/tile/carpet(src.loc) + if(full_return || prob(20)) + new /obj/item/stack/material/steel(src.loc) + else + var/material/M = get_material_by_name(DEFAULT_WALL_MATERIAL) + S = M.place_shard(loc) + if(S) shards += S + qdel(src) + return shards + +/obj/structure/table/update_icon() + if(flipped != 1) + icon_state = "blank" + overlays.Cut() + + var/image/I + + // Base frame shape. Mostly done for glass/diamond tables, where this is visible. + for(var/i = 1 to 4) + I = image(icon, dir = 1<<(i-1), icon_state = connections[i]) + overlays += I + + // Standard table image + if(material) + for(var/i = 1 to 4) + I = image(icon, "[material.table_icon_base]_[connections[i]]", dir = 1<<(i-1)) + if(material.icon_colour) I.color = material.icon_colour + I.alpha = 255 * material.opacity + overlays += I + + // Reinforcements + if(reinforced) + for(var/i = 1 to 4) + I = image(icon, "[reinforced.table_reinf]_[connections[i]]", dir = 1<<(i-1)) + I.color = reinforced.icon_colour + I.alpha = 255 * reinforced.opacity + overlays += I + + if(carpeted) + for(var/i = 1 to 4) + I = image(icon, "carpet_[connections[i]]", dir = 1<<(i-1)) + overlays += I + else + overlays.Cut() + var/type = 0 + var/tabledirs = 0 + for(var/direction in list(turn(dir,90), turn(dir,-90)) ) + var/obj/structure/table/T = locate(/obj/structure/table ,get_step(src,direction)) + if (T && T.flipped == 1 && T.dir == src.dir && material && T.material && T.material.name == material.name) + type++ + tabledirs |= direction + + type = "[type]" + if (type=="1") + if (tabledirs & turn(dir,90)) + type += "-" + if (tabledirs & turn(dir,-90)) + type += "+" + + icon_state = "flip[type]" + if(material) + var/image/I = image(icon, "[material.table_icon_base]_flip[type]") + I.color = material.icon_colour + I.alpha = 255 * material.opacity + overlays += I + name = "[material.display_name] table" + else + name = "table frame" + + if(reinforced) + var/image/I = image(icon, "[reinforced.table_reinf]_flip[type]") + I.color = reinforced.icon_colour + I.alpha = 255 * reinforced.opacity + overlays += I + + if(carpeted) + overlays += "carpet_flip[type]" + +/obj/structure/table/proc/can_connect() + return TRUE + +// set propagate if you're updating a table that should update tables around it too, for example if it's a new table or something important has changed (like material). +/obj/structure/table/proc/update_connections(propagate=0) + if(!material) + connections = list("0", "0", "0", "0") + + if(propagate) + for(var/obj/structure/table/T in oview(src, 1)) + T.update_connections() + return + + var/list/blocked_dirs = list() + for(var/obj/structure/window/W in get_turf(src)) + if(W.is_fulltile()) + connections = list("0", "0", "0", "0") + return + blocked_dirs |= W.dir + + for(var/D in list(NORTH, SOUTH, EAST, WEST) - blocked_dirs) + var/turf/T = get_step(src, D) + for(var/obj/structure/window/W in T) + if(W.is_fulltile() || W.dir == GLOB.reverse_dir[D]) + blocked_dirs |= D + break + else + if(W.dir != D) // it's off to the side + blocked_dirs |= W.dir|D // blocks the diagonal + + for(var/D in list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST) - blocked_dirs) + var/turf/T = get_step(src, D) + + for(var/obj/structure/window/W in T) + if(W.is_fulltile() || (W.dir & GLOB.reverse_dir[D])) + blocked_dirs |= D + break + + // Blocked cardinals block the adjacent diagonals too. Prevents weirdness with tables. + for(var/x in list(NORTH, SOUTH)) + for(var/y in list(EAST, WEST)) + if((x in blocked_dirs) || (y in blocked_dirs)) + blocked_dirs |= x|y + + var/list/connection_dirs = list() + + for(var/obj/structure/table/T in orange(src, 1)) + if(!T.can_connect()) continue + var/T_dir = get_dir(src, T) + if(T_dir in blocked_dirs) continue + if(material && T.material && material.name == T.material.name && flipped == T.flipped) + connection_dirs |= T_dir + if(propagate) + spawn(0) + T.update_connections() + T.update_icon() + + connections = dirs_to_corner_states(connection_dirs) + +#define CORNER_NONE 0 +#define CORNER_COUNTERCLOCKWISE 1 +#define CORNER_DIAGONAL 2 +#define CORNER_CLOCKWISE 4 + +/* + turn() is weird: + turn(icon, angle) turns icon by angle degrees clockwise + turn(matrix, angle) turns matrix by angle degrees clockwise + turn(dir, angle) turns dir by angle degrees counter-clockwise +*/ + +/proc/dirs_to_corner_states(list/dirs) + if(!istype(dirs)) return + + var/list/ret = list(NORTHWEST, SOUTHEAST, NORTHEAST, SOUTHWEST) + + for(var/i = 1 to ret.len) + var/dir = ret[i] + . = CORNER_NONE + if(dir in dirs) + . |= CORNER_DIAGONAL + if(turn(dir,45) in dirs) + . |= CORNER_COUNTERCLOCKWISE + if(turn(dir,-45) in dirs) + . |= CORNER_CLOCKWISE + ret[i] = "[.]" + + return ret + +#undef CORNER_NONE +#undef CORNER_COUNTERCLOCKWISE +#undef CORNER_DIAGONAL +#undef CORNER_CLOCKWISE diff --git a/code/modules/tables/update_triggers.dm b/code/modules/tables/update_triggers.dm new file mode 100644 index 00000000..b4b13085 --- /dev/null +++ b/code/modules/tables/update_triggers.dm @@ -0,0 +1,20 @@ +/obj/structure/window/New() + ..() + for(var/obj/structure/table/T in view(src, 1)) + T.update_connections() + T.update_icon() + +/obj/structure/window/Destroy() + var/oldloc = loc + . = ..() + for(var/obj/structure/table/T in view(oldloc, 1)) + T.update_connections() + T.update_icon() + +/obj/structure/window/Move() + var/oldloc = loc + . = ..() + if(loc != oldloc) + for(var/obj/structure/table/T in view(oldloc, 1) | view(loc, 1)) + T.update_connections() + T.update_icon() \ No newline at end of file diff --git a/code/modules/tgui/external.dm b/code/modules/tgui/external.dm new file mode 100644 index 00000000..74ba1c11 --- /dev/null +++ b/code/modules/tgui/external.dm @@ -0,0 +1,98 @@ + /** + * tgui external + * + * Contains all external tgui declarations. + **/ + + /** + * public + * + * Used to open and update UIs. + * If this proc is not implemented properly, the UI will not update correctly. + * + * required user mob The mob who opened/is using the UI. + * optional ui_key string The ui_key of the UI. + * optional ui datum/tgui The UI to be updated, if it exists. + * optional force_open bool If the UI should be re-opened instead of updated. + * optional master_ui datum/tgui The parent UI. + * optional state datum/ui_state The state used to determine status. + **/ +/datum/proc/tg_ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = tg_default_state) + return -1 // Not implemented. + + /** + * public + * + * Data to be sent to the UI. + * This must be implemented for a UI to work. + * + * required user mob The mob interacting with the UI. + * + * return list Data to be sent to the UI. + **/ +/datum/proc/ui_data(mob/user, ui_key = "main") + return list() // Not implemented. + + + /** + * public + * + * Called on a UI when the UI receieves a href. + * Think of this as Topic(). + * + * required action string The action/button that has been invoked by the user. + * required params list A list of parameters attached to the button. + * + * return bool If the UI should be updated or not. + **/ +/datum/proc/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(!ui || ui.status != UI_INTERACTIVE) + return 1 // If UI is not interactive or usr calling Topic is not the UI user, bail. + + + /** + * private + * + * The UI's host object (usually src_object). + * This allows modules/datums to have the UI attached to them, + * and be a part of another object. + **/ +/datum/proc/ui_host() + return src // Default src. + + /** + * global + * + * Used to track the current screen. + **/ +/datum/var/ui_screen = "home" + + /** + * global + * + * Used to track UIs for a mob. + **/ +/mob/var/list/tg_open_uis = list() + + /** + * verb + * + * Called by UIs when they are closed. + * Must be a verb so winset() can call it. + * + * required uiref ref The UI that was closed. + **/ +/client/verb/uiclose(ref as text) + // Name the verb, and hide it from the user panel. + set name = "uiclose" + set hidden = 1 + + // Get the UI based on the ref. + var/datum/tgui/ui = locate(ref) + + // If we found the UI, close it. + if(istype(ui)) + ui.close() + // Unset machine just to be sure. + if(src && src.mob) + src.mob.unset_machine() diff --git a/code/modules/tgui/process.dm b/code/modules/tgui/process.dm new file mode 100644 index 00000000..e1e04f6e --- /dev/null +++ b/code/modules/tgui/process.dm @@ -0,0 +1,230 @@ + /** + * tgui process + * + * Contains all tgui state and process code. + **/ + + /** + * public + * + * Get a open UI given a user, src_object, and ui_key and try to update it with data. + * + * required user mob The mob who opened/is using the UI. + * required src_object datum The object/datum which owns the UI. + * required ui_key string The ui_key of the UI. + * optional ui datum/tgui The UI to be updated, if it exists. + * optional force_open bool If the UI should be re-opened instead of updated. + * + * return datum/tgui The found UI. + **/ +/datum/controller/process/tgui/proc/try_update_ui(mob/user, datum/src_object, ui_key, datum/tgui/ui, force_open = 0) + if(isnull(ui)) // No UI was passed, so look for one. + ui = get_open_ui(user, src_object, ui_key) + + if(!isnull(ui)) + var/data = src_object.ui_data(user) // Get data from the src_object. + if(!force_open) // UI is already open; update it. + ui.push_data(data) + else // Re-open it anyways. + ui.reinitialize(null, data) + return ui // We found the UI, return it. + else + return null // We couldn't find a UI. + + /** + * private + * + * Get a open UI given a user, src_object, and ui_key. + * + * required user mob The mob who opened/is using the UI. + * required src_object datum The object/datum which owns the UI. + * required ui_key string The ui_key of the UI. + * + * return datum/tgui The found UI. + **/ +/datum/controller/process/tgui/proc/get_open_ui(mob/user, datum/src_object, ui_key) + var/src_object_key = "\ref[src_object]" + if(isnull(tg_open_uis[src_object_key]) || !istype(tg_open_uis[src_object_key], /list)) + return null // No UIs open. + else if(isnull(tg_open_uis[src_object_key][ui_key]) || !istype(tg_open_uis[src_object_key][ui_key], /list)) + return null // No UIs open for this object. + + for(var/datum/tgui/ui in tg_open_uis[src_object_key][ui_key]) // Find UIs for this object. + if(ui.user == user) // Make sure we have the right user + return ui + + return null // Couldn't find a UI! + + /** + * private + * + * Update all UIs attached to src_object. + * + * required src_object datum The object/datum which owns the UIs. + * + * return int The number of UIs updated. + **/ +/datum/controller/process/tgui/proc/update_uis(datum/src_object) + var/src_object_key = "\ref[src_object]" + if(isnull(tg_open_uis[src_object_key]) || !istype(tg_open_uis[src_object_key], /list)) + return 0 // Couldn't find any UIs for this object. + + var/update_count = 0 + for(var/ui_key in tg_open_uis[src_object_key]) + for(var/datum/tgui/ui in tg_open_uis[src_object_key][ui_key]) + if(ui && ui.src_object && ui.user && ui.src_object.ui_host()) // Check the UI is valid. + ui.process(force = 1) // Update the UI. + update_count++ // Count each UI we update. + return update_count + + /** + * private + * + * Close all UIs attached to src_object. + * + * required src_object datum The object/datum which owns the UIs. + * + * return int The number of UIs closed. + **/ +/datum/controller/process/tgui/proc/close_uis(datum/src_object) + var/src_object_key = "\ref[src_object]" + if(isnull(tg_open_uis[src_object_key]) || !istype(tg_open_uis[src_object_key], /list)) + return 0 // Couldn't find any UIs for this object. + + var/close_count = 0 + for(var/ui_key in tg_open_uis[src_object_key]) + for(var/datum/tgui/ui in tg_open_uis[src_object_key][ui_key]) + if(ui && ui.src_object && ui.user && ui.src_object.ui_host()) // Check the UI is valid. + ui.close() // Close the UI. + close_count++ // Count each UI we close. + return close_count + + /** + * private + * + * Update all UIs belonging to a user. + * + * required user mob The mob who opened/is using the UI. + * optional src_object datum If provided, only update UIs belonging this src_object. + * optional ui_key string If provided, only update UIs with this UI key. + * + * return int The number of UIs updated. + **/ +/datum/controller/process/tgui/proc/update_user_uis(mob/user, datum/src_object = null, ui_key = null) + if(isnull(user.tg_open_uis) || !istype(user.tg_open_uis, /list) || tg_open_uis.len == 0) + return 0 // Couldn't find any UIs for this user. + + var/update_count = 0 + for(var/datum/tgui/ui in user.tg_open_uis) + if((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key)) + ui.process(force = 1) // Update the UI. + update_count++ // Count each UI we upadte. + return update_count + + /** + * private + * + * Close all UIs belonging to a user. + * + * required user mob The mob who opened/is using the UI. + * optional src_object datum If provided, only close UIs belonging this src_object. + * optional ui_key string If provided, only close UIs with this UI key. + * + * return int The number of UIs closed. + **/ +/datum/controller/process/tgui/proc/close_user_uis(mob/user, datum/src_object = null, ui_key = null) + if(isnull(user.tg_open_uis) || !istype(user.tg_open_uis, /list) || tg_open_uis.len == 0) + return 0 // Couldn't find any UIs for this user. + + var/close_count = 0 + for(var/datum/tgui/ui in user.tg_open_uis) + if((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key)) + ui.close() // Close the UI. + close_count++ // Count each UI we close. + return close_count + + /** + * private + * + * Add a UI to the list of open UIs. + * + * required ui datum/tgui The UI to be added. + **/ +/datum/controller/process/tgui/proc/on_open(datum/tgui/ui) + var/src_object_key = "\ref[ui.src_object]" + if(isnull(tg_open_uis[src_object_key]) || !istype(tg_open_uis[src_object_key], /list)) + tg_open_uis[src_object_key] = list(ui.ui_key = list()) // Make a list for the ui_key and src_object. + else if(isnull(tg_open_uis[src_object_key][ui.ui_key]) || !istype(tg_open_uis[src_object_key][ui.ui_key], /list)) + tg_open_uis[src_object_key][ui.ui_key] = list() // Make a list for the ui_key. + + // Append the UI to all the lists. + ui.user.tg_open_uis |= ui + var/list/uis = tg_open_uis[src_object_key][ui.ui_key] + uis |= ui + processing_uis |= ui + + /** + * private + * + * Remove a UI from the list of open UIs. + * + * required ui datum/tgui The UI to be removed. + * + * return bool If the UI was removed or not. + **/ +/datum/controller/process/tgui/proc/on_close(datum/tgui/ui) + var/src_object_key = "\ref[ui.src_object]" + if(isnull(tg_open_uis[src_object_key]) || !istype(tg_open_uis[src_object_key], /list)) + return 0 // It wasn't open. + else if(isnull(tg_open_uis[src_object_key][ui.ui_key]) || !istype(tg_open_uis[src_object_key][ui.ui_key], /list)) + return 0 // It wasn't open. + + processing_uis.Remove(ui) // Remove it from the list of processing UIs. + if(ui.user) // If the user exists, remove it from them too. + ui.user.tg_open_uis.Remove(ui) + var/Ukey = ui.ui_key + var/list/uis = tg_open_uis[src_object_key][Ukey] // Remove it from the list of open UIs. + uis.Remove(ui) + if(!uis.len) + var/list/uiobj = tg_open_uis[src_object_key] + uiobj.Remove(Ukey) + if(!uiobj.len) + tg_open_uis.Remove(src_object_key) + + return 1 // Let the caller know we did it. + + /** + * private + * + * Handle client logout, by closing all their UIs. + * + * required user mob The mob which logged out. + * + * return int The number of UIs closed. + **/ +/datum/controller/process/tgui/proc/on_logout(mob/user) + return close_user_uis(user) + + /** + * private + * + * Handle clients switching mobs, by transfering their UIs. + * + * required user source The client's original mob. + * required user target The client's new mob. + * + * return bool If the UIs were transferred. + **/ +/datum/controller/process/tgui/proc/on_transfer(mob/source, mob/target) + if(!source || isnull(source.tg_open_uis) || !istype(source.tg_open_uis, /list) || tg_open_uis.len == 0) + return 0 // The old mob had no open UIs. + + if(isnull(target.tg_open_uis) || !istype(target.tg_open_uis, /list)) + target.tg_open_uis = list() // Create a list for the new mob if needed. + + for(var/datum/tgui/ui in source.tg_open_uis) + ui.user = target // Inform the UIs of their new owner. + target.tg_open_uis.Add(ui) // Transfer all the UIs. + + source.tg_open_uis.Cut() // Clear the old list. + return 1 // Let the caller know we did it. diff --git a/code/modules/tgui/states.dm b/code/modules/tgui/states.dm new file mode 100644 index 00000000..2d9cab0a --- /dev/null +++ b/code/modules/tgui/states.dm @@ -0,0 +1,110 @@ + /** + * tgui states + * + * Base state and helpers for states. Just does some sanity checks, implement a state for in-depth checks. + **/ + + /** + * public + * + * Checks the UI state for a mob. + * + * required user mob The mob who opened/is using the UI. + * required state datum/ui_state The state to check. + * + * return UI_state The state of the UI. + **/ +/datum/proc/ui_status(mob/user, datum/ui_state/state) + var/datum/src_object = ui_host() + if(src_object != src) + return src_object.ui_status(user, state) + + if(isghost(user)) // Special-case ghosts. + if(user.can_admin_interact()) + return UI_INTERACTIVE // If they turn it on, admins can interact. + if(get_dist(src_object, src) < user.client.view) + return UI_UPDATE // Regular ghosts can only view. + return UI_CLOSE // To keep too many UIs from being opened. + return state.can_use_topic(src_object, user) // Check if the state allows interaction. + + /** + * private + * + * Checks if a user can use src_object's UI, and returns the state. + * Can call a mob proc, which allows overrides for each mob. + * + * required src_object datum The object/datum which owns the UI. + * required user mob The mob who opened/is using the UI. + * + * return UI_state The state of the UI. + **/ +/datum/ui_state/proc/can_use_topic(src_object, mob/user) + return UI_CLOSE // Don't allow interaction by default. + + /** + * public + * + * Standard interaction/sanity checks. Different mob types may have overrides. + * + * return UI_state The state of the UI. + **/ +/mob/proc/shared_ui_interaction(src_object) + if(!client) // Close UIs if mindless. + return UI_CLOSE + else if(stat) // Disable UIs if unconcious. + return UI_DISABLED + else if(incapacitated() || lying) // Update UIs if incapicitated but concious. + return UI_UPDATE + return UI_INTERACTIVE + +/mob/living/silicon/ai/shared_ui_interaction(src_object) + if(!has_power()) // Disable UIs if the AI is unpowered. + return UI_DISABLED + return ..() + +/mob/living/silicon/robot/shared_ui_interaction(src_object) + if(cell.charge <= 0 || lockcharge) // Disable UIs if the Borg is unpowered or locked. + return UI_DISABLED + return ..() + +/** + * public + * + * Check the distance for a living mob. + * Really only used for checks outside the context of a mob. + * Otherwise, use shared_living_ui_distance(). + * + * required src_object The object which owns the UI. + * required user mob The mob who opened/is using the UI. + * + * return UI_state The state of the UI. + **/ +/atom/proc/contents_ui_distance(src_object, mob/living/user) + return user.shared_living_ui_distance(src_object) // Just call this mob's check. + + /** + * public + * + * Distance versus interaction check. + * + * required src_object atom/movable The object which owns the UI. + * + * return UI_state The state of the UI. + **/ +/mob/living/proc/shared_living_ui_distance(atom/movable/src_object) + if(!(src_object in view(src))) // If the object is obscured, close it. + return UI_CLOSE + + var/dist = get_dist(src_object, src) + if(dist <= 1) // Open and interact if 1-0 tiles away. + return UI_INTERACTIVE + else if(dist <= 2) // View only if 2-3 tiles away. + return UI_UPDATE + else if(dist <= 5) // Disable if 5 tiles away. + return UI_DISABLED + return UI_CLOSE // Otherwise, we got nothing. + +/mob/living/carbon/human/shared_living_ui_distance(atom/movable/src_object) + if((TK in mutations)) + return UI_INTERACTIVE + return ..() diff --git a/code/modules/tgui/states/admin.dm b/code/modules/tgui/states/admin.dm new file mode 100644 index 00000000..f68c6cb4 --- /dev/null +++ b/code/modules/tgui/states/admin.dm @@ -0,0 +1,12 @@ + /** + * tgui state: admin_state + * + * Checks that the user is an admin, end-of-story. + **/ + +/var/global/datum/ui_state/admin_state/tg_admin_state = new() + +/datum/ui_state/admin_state/can_use_topic(src_object, mob/user) + if(check_rights(R_ADMIN, 0, user)) + return UI_INTERACTIVE + return UI_CLOSE diff --git a/code/modules/tgui/states/always.dm b/code/modules/tgui/states/always.dm new file mode 100644 index 00000000..e3c25929 --- /dev/null +++ b/code/modules/tgui/states/always.dm @@ -0,0 +1,11 @@ + + /** + * tgui state: always_state + * + * Always grants the user UI_INTERACTIVE. Period. + **/ + +/var/global/datum/ui_state/always_state/tg_always_state = new() + +/datum/ui_state/always_state/can_use_topic(src_object, mob/user) + return UI_INTERACTIVE diff --git a/code/modules/tgui/states/conscious.dm b/code/modules/tgui/states/conscious.dm new file mode 100644 index 00000000..39da5471 --- /dev/null +++ b/code/modules/tgui/states/conscious.dm @@ -0,0 +1,12 @@ + /** + * tgui state: conscious_state + * + * Only checks if the user is conscious. + **/ + +/var/global/datum/ui_state/conscious_state/tg_conscious_state = new() + +/datum/ui_state/conscious_state/can_use_topic(src_object, mob/user) + if(user.stat == CONSCIOUS) + return UI_INTERACTIVE + return UI_CLOSE diff --git a/code/modules/tgui/states/contained.dm b/code/modules/tgui/states/contained.dm new file mode 100644 index 00000000..a8f8ef7f --- /dev/null +++ b/code/modules/tgui/states/contained.dm @@ -0,0 +1,12 @@ + /** + * tgui state: contained_state + * + * Checks that the user is inside the src_object. + **/ + +/var/global/datum/ui_state/contained_state/tg_contained_state = new() + +/datum/ui_state/contained_state/can_use_topic(atom/src_object, mob/user) + if(!src_object.contains(user)) + return UI_CLOSE + return user.shared_ui_interaction(src_object) diff --git a/code/modules/tgui/states/deep_inventory.dm b/code/modules/tgui/states/deep_inventory.dm new file mode 100644 index 00000000..cfd74c18 --- /dev/null +++ b/code/modules/tgui/states/deep_inventory.dm @@ -0,0 +1,12 @@ + /** + * tgui state: deep_inventory_state + * + * Checks that the src_object is in the user's deep (backpack, box, toolbox, etc) inventory. + **/ + +/var/global/datum/ui_state/deep_inventory_state/tg_deep_inventory_state = new() + +/datum/ui_state/deep_inventory_state/can_use_topic(src_object, mob/user) + if(!user.contains(src_object)) + return UI_CLOSE + return user.shared_ui_interaction(src_object) diff --git a/code/modules/tgui/states/default.dm b/code/modules/tgui/states/default.dm new file mode 100644 index 00000000..d2505f1b --- /dev/null +++ b/code/modules/tgui/states/default.dm @@ -0,0 +1,55 @@ + /** + * tgui state: default_state + * + * Checks a number of things -- mostly physical distance for humans and view for robots. + **/ + +/var/global/datum/ui_state/default/tg_default_state = new() + +/datum/ui_state/default/can_use_topic(src_object, mob/user) + return user.tg_default_can_use_topic(src_object) // Call the individual mob-overriden procs. + +/mob/proc/tg_default_can_use_topic(src_object) + return UI_CLOSE // Don't allow interaction by default. + +/mob/living/tg_default_can_use_topic(src_object) + . = shared_ui_interaction(src_object) + if(. > UI_CLOSE && loc) + . = min(., loc.contents_ui_distance(src_object, src)) // Check the distance... + if(. == UI_INTERACTIVE) // Non-human living mobs can only look, not touch. + return UI_UPDATE + +/mob/living/carbon/human/tg_default_can_use_topic(src_object) + . = shared_ui_interaction(src_object) + if(. > UI_CLOSE) + . = min(., shared_living_ui_distance(src_object)) // Check the distance... + // Derp a bit if we have brain loss. + if(prob(getBrainLoss())) + return UI_UPDATE + +/mob/living/silicon/robot/tg_default_can_use_topic(src_object) + . = shared_ui_interaction(src_object) + if(. <= UI_DISABLED) + return + + // Robots can interact with anything they can see. + if(get_dist(src, src_object) <= client.view) + return UI_INTERACTIVE + return UI_DISABLED // Otherwise they can keep the UI open. + +/mob/living/silicon/ai/tg_default_can_use_topic(src_object) + . = shared_ui_interaction(src_object) + if(. < UI_INTERACTIVE) + return + + // The AI can interact with anything it can see nearby, or with cameras. + if((get_dist(src, src_object) <= client.view) || cameranet.is_turf_visible(get_turf_pixel(src_object))) + return UI_INTERACTIVE + return UI_CLOSE + +/mob/living/silicon/pai/tg_default_can_use_topic(src_object) + // pAIs can only use themselves and the owner's radio. + if((src_object == src || src_object == silicon_radio) && !stat) + return UI_INTERACTIVE + else + return ..() diff --git a/code/modules/tgui/states/hands.dm b/code/modules/tgui/states/hands.dm new file mode 100644 index 00000000..7cb15b32 --- /dev/null +++ b/code/modules/tgui/states/hands.dm @@ -0,0 +1,26 @@ + /** + * tgui state: hands_state + * + * Checks that the src_object is in the user's hands, or user's active gripper. + **/ + +/var/global/datum/ui_state/hands_state/tg_hands_state = new() + +/datum/ui_state/hands_state/can_use_topic(src_object, mob/user) + . = user.shared_ui_interaction(src_object) + if(. > UI_CLOSE) + return min(., user.hands_can_use_topic(src_object)) + +/mob/proc/hands_can_use_topic(src_object) + return UI_CLOSE + +/mob/living/hands_can_use_topic(src_object) + if(src_object in get_both_hands(src)) + return UI_INTERACTIVE + return UI_CLOSE + +/mob/living/silicon/robot/hands_can_use_topic(src_object) + for(var/obj/item/weapon/gripper/active_gripper in list(module_state_1, module_state_2, module_state_3)) + if(active_gripper.contains(src_object)) + return UI_INTERACTIVE + return UI_CLOSE \ No newline at end of file diff --git a/code/modules/tgui/states/human_adjacent.dm b/code/modules/tgui/states/human_adjacent.dm new file mode 100644 index 00000000..3f8bf4f2 --- /dev/null +++ b/code/modules/tgui/states/human_adjacent.dm @@ -0,0 +1,17 @@ + + /** + * tgui state: human_adjacent_state + * + * In addition to default checks, only allows interaction for a + * human adjacent user. + **/ + +/var/global/datum/ui_state/human_adjacent_state/tg_human_adjacent_state = new() + +/datum/ui_state/human_adjacent_state/can_use_topic(src_object, mob/user) + . = user.default_can_use_topic(src_object) + + var/dist = get_dist(src_object, user) + if((dist > 1) || (!ishuman(user))) + // Can't be used unless adjacent and human, even with TK + . = min(., UI_UPDATE) diff --git a/code/modules/tgui/states/inventory.dm b/code/modules/tgui/states/inventory.dm new file mode 100644 index 00000000..101fd478 --- /dev/null +++ b/code/modules/tgui/states/inventory.dm @@ -0,0 +1,12 @@ + /** + * tgui state: inventory_state + * + * Checks that the src_object is in the user's top-level (hand, ear, pocket, belt, etc) inventory. + **/ + +/var/global/datum/ui_state/inventory_state/tg_inventory_state = new() + +/datum/ui_state/inventory_state/can_use_topic(src_object, mob/user) + if(!(src_object in user)) + return UI_CLOSE + return user.shared_ui_interaction(src_object) diff --git a/code/modules/tgui/states/not_contained.dm b/code/modules/tgui/states/not_contained.dm new file mode 100644 index 00000000..738ad331 --- /dev/null +++ b/code/modules/tgui/states/not_contained.dm @@ -0,0 +1,26 @@ + /** + * tgui state: notcontained_state + * + * Checks that the user is not inside src_object, and then makes the default checks. + **/ + +/var/global/datum/ui_state/notcontained_state/tg_not_contained_state = new() + +/datum/ui_state/notcontained_state/can_use_topic(atom/src_object, mob/user) + . = user.shared_ui_interaction(src_object) + if(. > UI_CLOSE) + return min(., user.notcontained_can_use_topic(src_object)) + +/mob/proc/notcontained_can_use_topic(src_object) + return UI_CLOSE + +/mob/living/notcontained_can_use_topic(atom/src_object) + if(src_object.contains(src)) + return UI_CLOSE // Close if we're inside it. + return tg_default_can_use_topic(src_object) + +/mob/living/silicon/notcontained_can_use_topic(src_object) + return tg_default_can_use_topic(src_object) // Silicons use default bevhavior. + +/mob/living/simple_animal/drone/notcontained_can_use_topic(src_object) + return tg_default_can_use_topic(src_object) // Drones use default bevhavior. diff --git a/code/modules/tgui/states/not_incapacitated.dm b/code/modules/tgui/states/not_incapacitated.dm new file mode 100644 index 00000000..c5cb0645 --- /dev/null +++ b/code/modules/tgui/states/not_incapacitated.dm @@ -0,0 +1,29 @@ + /** + * tgui state: not_incapacitated_state + * + * Checks that the user isn't incapacitated + **/ + +/var/global/datum/ui_state/not_incapacitated_state/tg_not_incapacitated_state = new() + + /** + * tgui state: not_incapacitated_turf_state + * + * Checks that the user isn't incapacitated and that their loc is a turf + **/ + +/var/global/datum/ui_state/not_incapacitated_state/not_incapacitated_turf_state = new(no_turfs = TRUE) + +/datum/ui_state/not_incapacitated_state + var/turf_check = FALSE + +/datum/ui_state/not_incapacitated_state/New(loc, no_turfs = FALSE) + ..() + turf_check = no_turfs + +/datum/ui_state/not_incapacitated_state/can_use_topic(src_object, mob/user) + if(user.stat) + return UI_CLOSE + if(user.incapacitated() || (turf_check && !isturf(user.loc))) + return UI_DISABLED + return UI_INTERACTIVE diff --git a/code/modules/tgui/states/physical.dm b/code/modules/tgui/states/physical.dm new file mode 100644 index 00000000..f0c5d163 --- /dev/null +++ b/code/modules/tgui/states/physical.dm @@ -0,0 +1,24 @@ + /** + * tgui state: physical_state + * + * Short-circuits the default state to only check physical distance. + **/ + +/var/global/datum/ui_state/physical/tg_physical_state = new() + +/datum/ui_state/physical/can_use_topic(src_object, mob/user) + . = user.shared_ui_interaction(src_object) + if(. > UI_CLOSE) + return min(., user.physical_can_use_topic(src_object)) + +/mob/proc/physical_can_use_topic(src_object) + return UI_CLOSE + +/mob/living/physical_can_use_topic(src_object) + return shared_living_ui_distance(src_object) + +/mob/living/silicon/physical_can_use_topic(src_object) + return max(UI_UPDATE, shared_living_ui_distance(src_object)) // Silicons can always see. + +/mob/living/silicon/ai/physical_can_use_topic(src_object) + return UI_UPDATE // AIs are not physical. diff --git a/code/modules/tgui/states/self.dm b/code/modules/tgui/states/self.dm new file mode 100644 index 00000000..30068291 --- /dev/null +++ b/code/modules/tgui/states/self.dm @@ -0,0 +1,12 @@ + /** + * tgui state: self_state + * + * Only checks that the user and src_object are the same. + **/ + +/var/global/datum/ui_state/self_state/tg_self_state = new() + +/datum/ui_state/self_state/can_use_topic(src_object, mob/user) + if(src_object != user) + return UI_CLOSE + return user.shared_ui_interaction(src_object) diff --git a/code/modules/tgui/states/zlevel.dm b/code/modules/tgui/states/zlevel.dm new file mode 100644 index 00000000..c1f5578b --- /dev/null +++ b/code/modules/tgui/states/zlevel.dm @@ -0,0 +1,14 @@ + /** + * tgui state: z_state + * + * Only checks that the Z-level of the user and src_object are the same. + **/ + +/var/global/datum/ui_state/z_state/tg_z_state = new() + +/datum/ui_state/z_state/can_use_topic(src_object, mob/user) + var/turf/turf_obj = get_turf(src_object) + var/turf/turf_usr = get_turf(user) + if(turf_obj && turf_usr && turf_obj.z == turf_usr.z) + return UI_INTERACTIVE + return UI_CLOSE diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm new file mode 100644 index 00000000..5747966e --- /dev/null +++ b/code/modules/tgui/tgui.dm @@ -0,0 +1,379 @@ + /** + * tgui + * + * /tg/station user interface library + **/ + + /** + * tgui datum (represents a UI). + **/ +/datum/tgui + var/mob/user // The mob who opened/is using the UI. + var/datum/src_object // The object which owns the UI. + var/title // The title of te UI. + var/ui_key // The ui_key of the UI. This allows multiple UIs for one src_object. + var/window_id // The window_id for browse() and onclose(). + var/width = 0 // The window width. + var/height = 0 // The window height + var/window_options = list( // Extra options to winset(). + "focus" = FALSE, + "titlebar" = TRUE, + "can_resize" = TRUE, + "can_minimize" = TRUE, + "can_maximize" = FALSE, + "can_close" = TRUE, + "auto_format" = FALSE + ) + var/style = "nanotrasen" // The style to be used for this UI. + var/interface // The interface (template) to be used for this UI. + var/autoupdate = TRUE // Update the UI every MC tick. + var/initialized = FALSE // If the UI has been initialized yet. + var/list/initial_data // The data (and datastructure) used to initialize the UI. + var/status = UI_INTERACTIVE // The status/visibility of the UI. + var/datum/ui_state/state = null // Topic state used to determine status/interactability. + var/datum/tgui/master_ui // The parent UI. + var/list/datum/tgui/children = list() // Children of this UI. + var/titlebar = TRUE + var/custom_browser_id = FALSE + + /** + * public + * + * Create a new UI. + * + * required user mob The mob who opened/is using the UI. + * required src_object datum The object or datum which owns the UI. + * required ui_key string The ui_key of the UI. + * required interface string The interface used to render the UI. + * optional title string The title of the UI. + * optional width int The window width. + * optional height int The window height. + * optional master_ui datum/tgui The parent UI. + * optional state datum/ui_state The state used to determine status. + * + * return datum/tgui The requested UI. + **/ +/datum/tgui/New(mob/user, datum/src_object, ui_key, interface, title, width = 0, height = 0, datum/tgui/master_ui = null, datum/ui_state/state = tg_default_state, browser_id = null) + src.user = user + src.src_object = src_object + src.ui_key = ui_key + src.window_id = browser_id ? browser_id : "\ref[src_object]-[ui_key]" + src.custom_browser_id = browser_id ? TRUE : FALSE + + set_interface(interface) + + if(title) + src.title = sanitize(title) + if(width) + src.width = width + if(height) + src.height = height + + src.master_ui = master_ui + if(master_ui) + master_ui.children += src + src.state = state + + var/datum/asset/assets = get_asset_datum(/datum/asset/simple/tgui) + assets.send(user) + + /** + * public + * + * Open this UI (and initialize it with data). + **/ +/datum/tgui/proc/open() + if(!user.client) + return // Bail if there is no client. + + update_status(push = 0) // Update the window status. + if(status < UI_UPDATE) + return // Bail if we're not supposed to open. + + if(!initial_data) + set_initial_data(src_object.ui_data(user)) // Get the UI data. + + var/window_size = "" + if(width && height) // If we have a width and height, use them. + window_size = "size=[width]x[height];" + + var/debugable = check_rights(R_DEBUG, 0, user) + user << browse(get_html(debugable), "window=[window_id];[window_size][list2params(window_options)]") // Open the window. + if (!custom_browser_id) + spawn(2) + winset(user, window_id, "on-close=\"uiclose \ref[src]\"") // Instruct the client to signal UI when the window is closed. + tgui_process.on_open(src) + + /** + * public + * + * Reinitialize the UI. + * (Possibly with a new interface and/or data). + * + * optional template string The name of the new interface. + * optional data list The new initial data. + **/ +/datum/tgui/proc/reinitialize(interface, list/data) + if(interface) + set_interface(interface) // Set a new interface. + if(data) + set_initial_data(data) // Replace the initial_data. + open() + + /** + * public + * + * Close the UI, and all its children. + **/ +/datum/tgui/proc/close() + user << browse(null, "window=[window_id]") // Close the window. + tgui_process.on_close(src) + for(var/datum/tgui/child in children) // Loop through and close all children. + child.close() + children.Cut() + state = null + master_ui = null + qdel(src) + + /** + * public + * + * Sets the browse() window options for this UI. + * + * required window_options list The window options to set. + **/ +/datum/tgui/proc/set_window_options(list/window_options) + src.window_options = window_options + + /** + * public + * + * Set the style for this UI. + * + * required style string The new UI style. + **/ +/datum/tgui/proc/set_style(style) + src.style = lowertext(style) + + /** + * public + * + * Set the interface (template) for this UI. + * + * required interface string The new UI interface. + **/ +/datum/tgui/proc/set_interface(interface) + src.interface = lowertext(interface) + + /** + * public + * + * Enable/disable auto-updating of the UI. + * + * required state bool Enable/disable auto-updating. + **/ +/datum/tgui/proc/set_autoupdate(state = 1) + autoupdate = state + + /** + * private + * + * Set the data to initialize the UI with. + * The datastructure cannot be changed by subsequent updates. + * + * optional data list The data/datastructure to initialize the UI with. + **/ +/datum/tgui/proc/set_initial_data(list/data) + initial_data = data + + /** + * private + * + * Generate HTML for this UI. + * + * optional bool inline If the JSON should be inlined into the HTML (for debugging). + * + * return string UI HTML output. + **/ +/datum/tgui/proc/get_html(var/inline) + var/html + // Poplate HTML with JSON if we're supposed to inline. + if(inline) + html = replacetextEx(tgui_process.basehtml, "{}", get_json(initial_data)) + else + html = tgui_process.basehtml + html = replacetextEx(html, "\[ref]", "\ref[src]") + html = replacetextEx(html, "\[style]", style) + return html + + /** + * private + * + * Get the config data/datastructure to initialize the UI with. + * + * return list The config data. + **/ +/datum/tgui/proc/get_config_data() + var/list/config_data = list( + "title" = title, + "status" = status, + "screen" = src_object.ui_screen, + "style" = style, + "interface" = interface, + "fancy" = GLOB.PREF_FANCY,//user.get_preference_value(/datum/client_preference/tgui_style) == GLOB.PREF_FANCY, + "locked" = GLOB.PREF_PRIMARY,//user.get_preference_value(/datum/client_preference/tgui_monitor) == GLOB.PREF_PRIMARY, + "window" = window_id, + "ref" = "\ref[src]", + "user" = list( + "name" = user.name, + "ref" = "\ref[user]" + ), + "srcObject" = list( + "name" = "[src_object]", + "ref" = "\ref[src_object]" + ), + "titlebar" = titlebar + ) + return config_data + + /** + * private + * + * Package the data to send to the UI, as JSON. + * This includes the UI data and config_data. + * + * return string The packaged JSON. + **/ +/datum/tgui/proc/get_json(list/data) + var/list/json_data = list() + + json_data["config"] = get_config_data() + if(!isnull(data)) + json_data["data"] = data + + // Generate the JSON. + var/json = json_encode(json_data) + // Strip #255/improper. + json = replacetext(json, "\proper", "") + json = replacetext(json, "\improper", "") + return json + + /** + * private + * + * Handle clicks from the UI. + * Call the src_object's ui_act() if status is UI_INTERACTIVE. + * If the src_object's ui_act() returns 1, update all UIs attacked to it. + **/ +/datum/tgui/Topic(href, href_list) + if(user != usr) + return // Something is not right here. + user.AddTopicPrint(src_object.ui_host()) // Add a print whenever we attempt to interact with an UI + + var/action = href_list["action"] + var/params = href_list; params -= "action" + + switch(action) + if("tgui:initialize") + user << output(url_encode(get_json(initial_data)), "[custom_browser_id ? window_id : "[window_id].browser"]:initialize") + initialized = TRUE + if("tgui:view") + if(params["screen"]) + src_object.ui_screen = params["screen"] + tgui_process.update_uis(src_object) + if("tgui:link") + user << link(params["url"]) + //if("tgui:fancy") + // user.set_preference(/datum/client_preference/tgui_style, TRUE) + //if("tgui:nofrills") + // user.set_preference(/datum/client_preference/tgui_style, FALSE) + else + update_status(push = 0) // Update the window state. + if(src_object.ui_act(action, params, src, state)) // Call ui_act() on the src_object. + tgui_process.update_uis(src_object) // Update if the object requested it. + + /** + * private + * + * Update the UI. + * Only updates the data if update is true, otherwise only updates the status. + * + * optional force bool If the UI should be forced to update. + **/ +/datum/tgui/proc/process(force = 0) + var/datum/host = src_object.ui_host() + if(!src_object || !host || !user) // If the object or user died (or something else), abort. + close() + return + + if(status && (force || autoupdate)) + update() // Update the UI if the status and update settings allow it. + else + update_status(push = 1) // Otherwise only update status. + + /** + * private + * + * Push data to an already open UI. + * + * required data list The data to send. + * optional force bool If the update should be sent regardless of state. + **/ +/datum/tgui/proc/push_data(data, force = 0) + update_status(push = 0) // Update the window state. + if(!initialized) + return // Cannot update UI if it is not set up yet. + if(status <= UI_DISABLED && !force) + return // Cannot update UI, we have no visibility. + + // Send the new JSON to the update() Javascript function. + user << output(url_encode(get_json(data)), "[custom_browser_id ? window_id : "[window_id].browser"]:update") + + /** + * private + * + * Updates the UI by interacting with the src_object again, which will hopefully + * call try_ui_update on it. + * + * optional force_open bool If force_open should be passed to ui_interact. + **/ +/datum/tgui/proc/update(force_open = 0) + src_object.tg_ui_interact(user, ui_key, src, force_open, master_ui, state) + + /** + * private + * + * Update the status/visibility of the UI for its user. + * + * optional push bool Push an update to the UI (an update is always sent for UI_DISABLED). + **/ +/datum/tgui/proc/update_status(push = 0) + var/status = src_object.ui_status(user, state) + if(master_ui) + status = min(status, master_ui.status) + + set_status(status, push) + if(status == UI_CLOSE) + close() + + /** + * private + * + * Set the status/visibility of the UI. + * + * required status int The status to set (UI_CLOSE/UI_DISABLED/UI_UPDATE/UI_INTERACTIVE). + * optional push bool Push an update to the UI (an update is always sent for UI_DISABLED). + **/ +/datum/tgui/proc/set_status(status, push = 0) + if(src.status != status) // Only update if status has changed. + if(src.status == UI_DISABLED) + src.status = status + if(push) + update() + else + src.status = status + if(status == UI_DISABLED || push) // Update if the UI just because disabled, or a push is requested. + push_data(null, force = 1) + +/datum/tgui/proc/set_titlebar(value) + titlebar = value diff --git a/code/modules/trait/quirks.dm b/code/modules/trait/quirks.dm new file mode 100644 index 00000000..bf972ab0 --- /dev/null +++ b/code/modules/trait/quirks.dm @@ -0,0 +1,58 @@ +/mob/living + var/datum/quirk/quirk = null + +/datum/quirk + var/name = "quirk name" + var/description = "quirk description" + + +/datum/quirk/hypersensitive //Doubles mood values. + name = "hypersensitive" + description = "I'm more sensitive to good and bad moods than normal." +/* +/datum/quirk/alcoholic //Starts out addicted to alcohol + name = "alcoholic" + description = "I need booze to be happy." + +/datum/quirk/cig_addict //Starts out addicted to nicotine. + name = "smoker" + description = "I need a smoke every now and then." +*/ +/datum/quirk/brave //Still gets moods, but is not bothered by them. + name = "brave" + description = "I'm not stressed by combat." + +/datum/quirk/no_bathroom //You'll never have to use the restroom. + name = "incontinent" + description = "I don't have to use the restroom." + +/datum/quirk/tough //Still feel pain, just not bothered by it as often. + name = "tough" + description = "I'm more pain resiliant than most." + +/datum/quirk/weak //Removes two str + name = "weak" + description = "I'm not as strong as I should be." + +/datum/quirk/strong //Adds two str + name = "strong" + description = "I'm stronger than should be." + +/datum/quirk/dead_inside //Gets no moods. Isn't bothered by anything. + name = "dead inside" + description = "I feel nothing anymore." +/* +/datum/quirk/psychopath //Shooting people boosts their mood. + name = "psychopath" + description = "I love killing people!" +*/ + + +/mob/living/proc/has_quirk(var/datum/quirk/this_quirk) + return istype(quirk, this_quirk) + +/mob/living/proc/set_quirk(var/datum/quirk/set_quirk) + quirk = set_quirk + +/mob/living/proc/remove_quirk() + quirk = null \ No newline at end of file diff --git a/code/modules/trait/traits.dm b/code/modules/trait/traits.dm new file mode 100644 index 00000000..6c1a2bf8 --- /dev/null +++ b/code/modules/trait/traits.dm @@ -0,0 +1,24 @@ +/datum/trait + var/name = "Default Trait" + var/description = "A default trait. If you see this someone fucked up." + +/datum/trait/hardcore + name = "hardcore" + description = "I don't get upset by violence easily." + +/datum/trait/death_tolerant + name = "death tolerant" + description = "Dead bodies don't bother me like they do other people." + +/datum/trait/child + name = "child" + description = "I am quicker than the adults, and landmines don't bother me!" + +/mob/living/proc/has_trait(var/datum/trait/this_trait) + return istype(trait, this_trait) + +/mob/living/proc/set_trait(var/datum/trait/set_trait) + trait = set_trait + +/mob/living/proc/remove_trait() + trait = null diff --git a/code/modules/turbolift/_turbolift.dm b/code/modules/turbolift/_turbolift.dm new file mode 100644 index 00000000..088bf39c --- /dev/null +++ b/code/modules/turbolift/_turbolift.dm @@ -0,0 +1,12 @@ +/* + * Turbolifts! Sort of like multishuttles-lite. + * + * How-to: Map /obj/turbolift_map_holder in at the bottom of the shaft, give it a depth + * value equivalent to the number of floors it should span (inclusive of the first), + * and at runtime it will update the map, set areas and create control panels and + * wifi-set doors appropriate to itself. You will save time at init if you map the + * elevator shaft in properly before runtime, but ultimately you're just avoiding a + * bunch of ChangeTurf() calls. + */ + +var/list/turbolifts = list() \ No newline at end of file diff --git a/code/modules/turbolift/turbolift.dm b/code/modules/turbolift/turbolift.dm new file mode 100644 index 00000000..bed99216 --- /dev/null +++ b/code/modules/turbolift/turbolift.dm @@ -0,0 +1,118 @@ +// Lift master datum. One per turbolift. +/datum/turbolift + var/datum/turbolift_floor/target_floor // Where are we going? + var/datum/turbolift_floor/current_floor // Where is the lift currently? + var/list/doors = list() // Doors inside the lift structure. + var/list/queued_floors = list() // Where are we moving to next? + var/list/floors = list() // All floors in this system. + var/move_delay = 30 // Time between floor changes. + var/floor_wait_delay = 85 // Time to wait at floor stops. + var/obj/structure/lift/panel/control_panel_interior // Lift control panel. + var/doors_closing = 0 // Whether doors are in the process of closing + + var/tmp/moving_upwards + var/tmp/busy + +/datum/turbolift/proc/emergency_stop() + queued_floors.Cut() + target_floor = null + open_doors() + +/datum/turbolift/proc/doors_are_open(var/datum/turbolift_floor/use_floor = current_floor) + for(var/obj/machinery/door/airlock/door in (use_floor ? (doors + use_floor.doors) : doors)) + if(!door.density) + return 1 + return 0 + +/datum/turbolift/proc/open_doors(var/datum/turbolift_floor/use_floor = current_floor) + for(var/obj/machinery/door/airlock/door in (use_floor ? (doors + use_floor.doors) : doors)) + door.command("open") + return + +/datum/turbolift/proc/close_doors(var/datum/turbolift_floor/use_floor = current_floor) + for(var/obj/machinery/door/airlock/door in (use_floor ? (doors + use_floor.doors) : doors)) + door.command("close") + return + +/datum/turbolift/proc/do_move() + + var/current_floor_index = floors.Find(current_floor) + + if(!target_floor) + if(!queued_floors || !queued_floors.len) + return 0 + target_floor = queued_floors[1] + queued_floors -= target_floor + if(current_floor_index < floors.Find(target_floor)) + moving_upwards = 1 + else + moving_upwards = 0 + + if(doors_are_open()) + if(!doors_closing) + close_doors() + doors_closing = 1 + return 1 + else // We failed to close the doors - probably, someone is blocking them; stop trying to move + doors_closing = 0 + open_doors() + control_panel_interior.audible_message("\The [current_floor.ext_panel] buzzes loudly.") + playsound(control_panel_interior.loc, "sound/machines/buzz-two.ogg", 50, 1) + return 0 + + doors_closing = 0 // The doors weren't open, so they are done closing + + var/area/turbolift/origin = locate(current_floor.area_ref) + + if(target_floor == current_floor) + + playsound(control_panel_interior.loc, origin.arrival_sound, 50, 1) + target_floor.arrived(src) + target_floor = null + + sleep(15) + control_panel_interior.visible_message("The elevator announces, \"[origin.lift_announce_str]\"") + sleep(floor_wait_delay) + + return 1 + + // Work out where we're headed. + var/datum/turbolift_floor/next_floor + if(moving_upwards) + next_floor = floors[current_floor_index+1] + else + next_floor = floors[current_floor_index-1] + + var/area/turbolift/destination = locate(next_floor.area_ref) + + if(!istype(origin) || !istype(destination) || (origin == destination)) + return 0 + + for(var/turf/T in destination) + for(var/atom/movable/AM in T) + if(istype(AM, /mob/living)) + var/mob/living/M = AM + M.gib() + else if(AM.simulated) + qdel(AM) + + origin.move_contents_to(destination) + + if((locate(/obj/machinery/power) in destination) || (locate(/obj/structure/cable) in destination)) + SSmachines.makepowernets() + + current_floor = next_floor + control_panel_interior.visible_message("The elevator [moving_upwards ? "rises" : "descends"] smoothly.") + + return 1 + +/datum/turbolift/proc/queue_move_to(var/datum/turbolift_floor/floor) + if(!floor || !(floor in floors) || (floor in queued_floors)) + return // STOP PRESSING THE BUTTON. + floor.pending_move(src) + queued_floors |= floor + turbolift_controller.lift_is_moving(src) + +// TODO: dummy machine ('lift mechanism') in powered area for functionality/blackout checks. +/datum/turbolift/proc/is_functional() + return 1 \ No newline at end of file diff --git a/code/modules/turbolift/turbolift_areas.dm b/code/modules/turbolift/turbolift_areas.dm new file mode 100644 index 00000000..dbf568ae --- /dev/null +++ b/code/modules/turbolift/turbolift_areas.dm @@ -0,0 +1,11 @@ +// Used for creating the exchange areas. +/area/turbolift + name = "Turbolift" + base_turf = /turf/simulated/open + requires_power = 0 + sound_env = SMALL_ENCLOSED + + var/lift_floor_label = null + var/lift_floor_name = null + var/lift_announce_str = "Ding!" + var/arrival_sound = 'sound/machines/ding.ogg' diff --git a/code/modules/turbolift/turbolift_console.dm b/code/modules/turbolift/turbolift_console.dm new file mode 100644 index 00000000..1528e580 --- /dev/null +++ b/code/modules/turbolift/turbolift_console.dm @@ -0,0 +1,149 @@ +// Base type, do not use. +/obj/structure/lift + name = "turbolift control component" + icon = 'icons/obj/turbolift.dmi' + anchored = 1 + density = 0 + plane = OBJ_PLANE + layer = ABOVE_OBJ_LAYER + + var/datum/turbolift/lift + +/obj/structure/lift/set_dir(var/newdir) + . = ..() + pixel_x = 0 + pixel_y = 0 + if(dir & NORTH) + pixel_y = -32 + else if(dir & SOUTH) + pixel_y = 32 + else if(dir & EAST) + pixel_x = -32 + else if(dir & WEST) + pixel_x = 32 + +/obj/structure/lift/proc/pressed(var/mob/user) + if(!istype(user, /mob/living/silicon)) + if(user.a_intent == I_HURT) + user.visible_message("\The [user] hammers on the lift button!") + else + user.visible_message("\The [user] presses the lift button.") + + +/obj/structure/lift/New(var/newloc, var/datum/turbolift/_lift) + lift = _lift + return ..(newloc) + +/obj/structure/lift/attack_ai(var/mob/user) + return attack_hand(user) + +/obj/structure/lift/attack_generic(var/mob/user) + return attack_hand(user) + +/obj/structure/lift/attack_hand(var/mob/user) + return interact(user) + +/obj/structure/lift/interact(var/mob/user) + if(!lift.is_functional()) + return 0 + return 1 +// End base. + +// Button. No HTML interface, just calls the associated lift to its floor. +/obj/structure/lift/button + name = "elevator button" + desc = "A call button for an elevator. Be sure to hit it three hundred times." + icon_state = "button" + var/light_up = FALSE + var/datum/turbolift_floor/floor + +/obj/structure/lift/button/Destroy() + if(floor && floor.ext_panel == src) + floor.ext_panel = null + floor = null + return ..() + +/obj/structure/lift/button/proc/reset() + light_up = FALSE + update_icon() + +/obj/structure/lift/button/interact(var/mob/user) + if(!..()) + return + light_up() + pressed(user) + if(floor == lift.current_floor) + lift.open_doors() + spawn(3) + reset() + return + lift.queue_move_to(floor) + +/obj/structure/lift/button/proc/light_up() + light_up = TRUE + update_icon() + +/obj/structure/lift/button/update_icon() + if(light_up) + icon_state = "button_lit" + else + icon_state = initial(icon_state) + +// End button. + +// Panel. Lists floors (HTML), moves with the elevator, schedules a move to a given floor. +/obj/structure/lift/panel + name = "elevator control panel" + icon_state = "panel" + + +/obj/structure/lift/panel/attack_ghost(var/mob/user) + return interact(user) + +/obj/structure/lift/panel/interact(var/mob/user) + if(!..()) + return + + var/dat = list() + dat += "
                Lift panel
                " + + //the floors list stores levels in order of increasing Z + //therefore, to display upper levels at the top of the menu and + //lower levels at the bottom, we need to go through the list in reverse + for(var/i in lift.floors.len to 1 step -1) + var/datum/turbolift_floor/floor = lift.floors[i] + var/label = floor.label? floor.label : "Level #[i]" + dat += "" + dat += "[label]: [floor.name]
                " + + dat += "
                " + if(lift.doors_are_open()) + dat += "Close Doors
                " + else + dat += "Open Doors
                " + dat += "Emergency Stop" + dat += "
                " + + var/datum/browser/popup = new(user, "turbolift_panel", "Lift Panel", 230, 260) + popup.set_content(jointext(dat, null)) + popup.open() + return + +/obj/structure/lift/panel/OnTopic(user, href_list) + if(href_list["move_to_floor"]) + lift.queue_move_to(locate(href_list["move_to_floor"])) + . = TOPIC_REFRESH + if(href_list["open_doors"]) + lift.open_doors() + . = TOPIC_REFRESH + if(href_list["close_doors"]) + lift.close_doors() + . = TOPIC_REFRESH + if(href_list["emergency_stop"]) + lift.emergency_stop() + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + pressed(user) + +// End panel. \ No newline at end of file diff --git a/code/modules/turbolift/turbolift_door.dm b/code/modules/turbolift/turbolift_door.dm new file mode 100644 index 00000000..3c784505 --- /dev/null +++ b/code/modules/turbolift/turbolift_door.dm @@ -0,0 +1,44 @@ +/obj/machinery/door/airlock/lift + name = "Elevator Door" + desc = "Ding." + req_access = list(access_maint_tunnels) + opacity = 0 + autoclose = 0 + glass = 1 + icon = 'icons/obj/doors/doorlift.dmi' + + var/datum/turbolift/lift + var/datum/turbolift_floor/floor + +/obj/machinery/door/airlock/lift/Destroy() + if(lift) + lift.doors -= src + if(floor) + floor.doors -= src + return ..() + +/obj/machinery/door/airlock/lift/bumpopen(var/mob/user) + return // No accidental sprinting into open elevator shafts. + +/obj/machinery/door/airlock/lift/allowed(mob/M) + return FALSE //only the lift machinery is allowed to operate this door + +/obj/machinery/door/airlock/lift/close(var/forced=0) + for(var/turf/turf in locs) + for(var/mob/living/LM in turf) + if(LM.mob_size <= MOB_TINY) + var/moved = 0 + for(dir in shuffle(GLOB.cardinal.Copy())) + var/dest = get_step(LM,dir) + if(!(locate(/obj/machinery/door/airlock/lift) in dest)) + if(LM.Move(dest)) + moved = 1 + LM.visible_message("\The [LM] scurries away from the closing doors.") + break + if(!moved) // nowhere to go.... + LM.gib() + else // the mob is too big to just move, so we need to give up what we're doing + audible_message("\The [src]'s motors grind as they quickly reverse direction, unable to safely close.") + cur_command = null // the door will just keep trying otherwise + return 0 + return ..() \ No newline at end of file diff --git a/code/modules/turbolift/turbolift_floor.dm b/code/modules/turbolift/turbolift_floor.dm new file mode 100644 index 00000000..7761f092 --- /dev/null +++ b/code/modules/turbolift/turbolift_floor.dm @@ -0,0 +1,33 @@ +// Simple holder for each floor in the lift. +/datum/turbolift_floor + var/area_ref + var/label + var/name + var/announce_str + var/arrival_sound + + var/list/doors = list() + var/obj/structure/lift/button/ext_panel + +/datum/turbolift_floor/proc/set_area_ref(var/ref) + var/area/turbolift/A = locate(ref) + if(!istype(A)) + log_debug("Turbolift floor area was of the wrong type: ref=[ref]") + return + + area_ref = ref + label = A.lift_floor_label + name = A.lift_floor_name ? A.lift_floor_name : A.name + announce_str = A.lift_announce_str + arrival_sound = A.arrival_sound + +//called when a lift has queued this floor as a destination +/datum/turbolift_floor/proc/pending_move(var/datum/turbolift/lift) + if(ext_panel) + ext_panel.light_up() + +//called when a lift arrives at this floor +/datum/turbolift_floor/proc/arrived(var/datum/turbolift/lift) + lift.open_doors(src) + if(ext_panel) + ext_panel.reset() \ No newline at end of file diff --git a/code/modules/turbolift/turbolift_map.dm b/code/modules/turbolift/turbolift_map.dm new file mode 100644 index 00000000..494ef6cb --- /dev/null +++ b/code/modules/turbolift/turbolift_map.dm @@ -0,0 +1,228 @@ +// Map object. +/obj/turbolift_map_holder + name = "turbolift map placeholder" + icon = 'icons/obj/turbolift_preview_3x3.dmi' + dir = SOUTH // Direction of the holder determines the placement of the lift control panel and doors. + var/depth = 1 // Number of floors to generate, including the initial floor. + var/lift_size_x = 2 // Number of turfs on each axis to generate in addition to the first + var/lift_size_y = 2 // ie. a 3x3 lift would have a value of 2 in each of these variables. + + // Various turf and door types used when generating the turbolift floors. + var/wall_type = /turf/simulated/wall/elevator + var/floor_type = /turf/simulated/floor/tiled/dark + var/door_type = /obj/machinery/door/airlock/lift + + var/list/areas_to_use = list() + +/obj/turbolift_map_holder/Destroy() + turbolifts -= src + return ..() + +/obj/turbolift_map_holder/New() + turbolifts += src + ..() + +/obj/turbolift_map_holder/Initialize() + . = ..() + // Create our system controller. + var/datum/turbolift/lift = new() + + // Holder values since we're moving this object to null ASAP. + var/ux = x + var/uy = y + var/uz = z + var/udir = dir + forceMove(null) + + // These modifiers are used in relation to the origin + // to place the system control panels and doors. + var/int_panel_x + var/int_panel_y + var/ext_panel_x + var/ext_panel_y + var/door_x1 + var/door_y1 + var/door_x2 + var/door_y2 + var/light_x1 + var/light_x2 + var/light_y1 + var/light_y2 + + var/az = 1 + var/ex = (ux+lift_size_x) + var/ey = (uy+lift_size_y) + var/ez = (uz+(depth-1)) + + switch(dir) + + if(NORTH) + + int_panel_x = ux + Floor(lift_size_x/2) + int_panel_y = uy + 1 + ext_panel_x = ux + ext_panel_y = ey + 2 + + door_x1 = ux + 1 + door_y1 = ey + door_x2 = ex - 1 + door_y2 = ey + 1 + + light_x1 = ux + 1 + light_y1 = uy + 1 + light_x2 = ux + lift_size_x - 1 + light_y2 = uy + 1 + + if(SOUTH) + + int_panel_x = ux + Floor(lift_size_x/2) + int_panel_y = ey - 1 + ext_panel_x = ex + ext_panel_y = uy - 2 + + door_x1 = ux + 1 + door_y1 = uy - 1 + door_x2 = ex - 1 + door_y2 = uy + + light_x1 = ux + 1 + light_y1 = uy + 2 + light_x2 = ux + lift_size_x - 1 + light_y2 = uy + lift_size_y - 1 + + if(EAST) + + int_panel_x = ux+1 + int_panel_y = uy + Floor(lift_size_y/2) + ext_panel_x = ex+2 + ext_panel_y = ey + + door_x1 = ex + door_y1 = uy + 1 + door_x2 = ex + 1 + door_y2 = ey - 1 + + light_x1 = ux + 1 + light_y1 = uy + 1 + light_x2 = ux + 1 + light_y2 = uy + lift_size_x - 1 + + if(WEST) + + int_panel_x = ex-1 + int_panel_y = uy + Floor(lift_size_y/2) + ext_panel_x = ux-2 + ext_panel_y = uy + + door_x1 = ux - 1 + door_y1 = uy + 1 + door_x2 = ux + door_y2 = ey - 1 + + light_x1 = ux + lift_size_x - 1 + light_y1 = uy + 1 + light_x2 = ux + lift_size_x - 1 + light_y2 = uy + lift_size_y - 1 + + // Generate each floor and store it in the controller datum. + for(var/cz = uz;cz<=ez;cz++) + + var/datum/turbolift_floor/cfloor = new() + lift.floors += cfloor + + var/list/floor_turfs = list() + // Update the appropriate turfs. + for(var/tx = ux to ex) + for(var/ty = uy to ey) + + var/turf/checking = locate(tx,ty,cz) + + if(!istype(checking)) + log_debug("[name] cannot find a component turf at [tx],[ty] on floor [cz]. Aborting.") + qdel(src) + return + + // Update path appropriately if needed. + var/swap_to = /turf/simulated/open + if(cz == uz) // Elevator. + if((tx == ux || ty == uy || tx == ex || ty == ey) && !(tx >= door_x1 && tx <= door_x2 && ty >= door_y1 && ty <= door_y2)) + swap_to = wall_type + else + swap_to = floor_type + + if(checking.type != swap_to) + checking.ChangeTurf(swap_to) + // Let's make absolutely sure that we have the right turf. + checking = locate(tx,ty,cz) + + // Clear out contents. + for(var/atom/movable/thing in checking.contents) + if(thing.simulated) + qdel(thing) + + if(tx >= ux && tx <= ex && ty >= uy && ty <= ey) + floor_turfs += checking + + // Place exterior doors. + for(var/tx = door_x1 to door_x2) + for(var/ty = door_y1 to door_y2) + var/turf/checking = locate(tx,ty,cz) + var/internal = 1 + if(!(checking in floor_turfs)) + internal = 0 + if(checking.type != floor_type) + checking.ChangeTurf(floor_type) + checking = locate(tx,ty,cz) + for(var/atom/movable/thing in checking.contents) + if(thing.simulated) + qdel(thing) + if(checking.type == floor_type) // Don't build over empty space on lower levels. + var/obj/machinery/door/airlock/lift/newdoor = new door_type(checking) + if(internal) + lift.doors += newdoor + newdoor.lift = cfloor + else + cfloor.doors += newdoor + newdoor.floor = cfloor + + // Place exterior control panel. + var/turf/placing = locate(ext_panel_x, ext_panel_y, cz) + var/obj/structure/lift/button/panel_ext = new(placing, lift) + panel_ext.floor = cfloor + panel_ext.set_dir(udir) + cfloor.ext_panel = panel_ext + + // Place lights + var/turf/placing1 = locate(light_x1, light_y1, cz) + var/turf/placing2 = locate(light_x2, light_y2, cz) + var/obj/machinery/light/light1 = new(placing1, light) + var/obj/machinery/light/light2 = new(placing2, light) + if(udir == NORTH || udir == SOUTH) + light1.set_dir(WEST) + light2.set_dir(EAST) + else + light1.set_dir(SOUTH) + light2.set_dir(NORTH) + + // Update area. + if(az > areas_to_use.len) + log_debug("Insufficient defined areas in turbolift datum, aborting.") + qdel(src) + return + + var/area_path = areas_to_use[az] + for(var/thing in floor_turfs) + new area_path(thing) + var/area/A = locate(area_path) + cfloor.set_area_ref("\ref[A]") + az++ + + // Place lift panel. + var/turf/T = locate(int_panel_x, int_panel_y, uz) + lift.control_panel_interior = new(T, lift) + lift.control_panel_interior.set_dir(udir) + lift.current_floor = lift.floors[1] + + lift.open_doors() + + qdel(src) // We're done. diff --git a/code/modules/turbolift/turbolift_process.dm b/code/modules/turbolift/turbolift_process.dm new file mode 100644 index 00000000..83ce1b9f --- /dev/null +++ b/code/modules/turbolift/turbolift_process.dm @@ -0,0 +1,35 @@ +var/datum/controller/process/turbolift/turbolift_controller + +/datum/controller/process/turbolift + var/list/moving_lifts = list() + +/datum/controller/process/turbolift/New() + ..() + turbolift_controller = src + +/datum/controller/process/turbolift/setup() + name = "turbolift controller" + schedule_interval = 10 + +/datum/controller/process/turbolift/doWork() + for(var/liftref in moving_lifts) + if(world.time < moving_lifts[liftref]) + continue + var/datum/turbolift/lift = locate(liftref) + if(lift.busy) + continue + spawn(0) + lift.busy = 1 + if(!lift.do_move()) + moving_lifts[liftref] = null + moving_lifts -= liftref + if(lift.target_floor) + lift.target_floor.ext_panel.reset() + lift.target_floor = null + else + lift_is_moving(lift) + lift.busy = 0 + SCHECK + +/datum/controller/process/turbolift/proc/lift_is_moving(var/datum/turbolift/lift) + moving_lifts["\ref[lift]"] = world.time + lift.move_delay diff --git a/code/modules/turbolift/turbolift_turfs.dm b/code/modules/turbolift/turbolift_turfs.dm new file mode 100644 index 00000000..632160ef --- /dev/null +++ b/code/modules/turbolift/turbolift_turfs.dm @@ -0,0 +1,2 @@ +/turf/simulated/wall/elevator/New(var/newloc) + ..(newloc,"elevatorium") diff --git a/code/modules/vehicles/bike.dm b/code/modules/vehicles/bike.dm new file mode 100644 index 00000000..8e75aafa --- /dev/null +++ b/code/modules/vehicles/bike.dm @@ -0,0 +1,218 @@ +/obj/vehicle/bike/ + name = "space-bike" + desc = "Space wheelies! Woo!" + icon = 'icons/obj/bike.dmi' + icon_state = "bike_off" + dir = SOUTH + + load_item_visible = 1 + buckle_pixel_shift = "x=0;y=5" + health = 100 + maxhealth = 100 + + locked = 0 + fire_dam_coeff = 0.6 + brute_dam_coeff = 0.5 + var/protection_percent = 60 + + var/land_speed = 10 //if 0 it can't go on turf + var/space_speed = 2 + var/bike_icon = "bike" + + var/datum/effect/effect/system/trail/trail + var/kickstand = 1 + var/obj/item/weapon/engine/engine = null + var/engine_type + var/prefilled = 0 + +/obj/vehicle/bike/New() + ..() + if(engine_type) + load_engine(new engine_type(src.loc)) + if(prefilled) + engine.prefill() + update_icon() + +/obj/vehicle/bike/verb/toggle() + set name = "Toggle Engine" + set category = "Object" + set src in view(0) + + if(usr.incapacitated()) return + if(!engine) + to_chat(usr, "\The [src] does not have an engine block installed...") + return + + if(!on) + turn_on() + else + turn_off() + +/obj/vehicle/bike/verb/kickstand() + set name = "Toggle Kickstand" + set category = "Object" + set src in view(0) + + if(usr.incapacitated()) return + + if(kickstand) + usr.visible_message("\The [usr] puts up \the [src]'s kickstand.") + else + if(istype(src.loc,/turf/space)) + to_chat(usr, " You don't think kickstands work in space...") + return + usr.visible_message("\The [usr] puts down \the [src]'s kickstand.") + if(pulledby) + pulledby.stop_pulling() + + kickstand = !kickstand + anchored = (kickstand || on) + +/obj/vehicle/bike/proc/load_engine(var/obj/item/weapon/engine/E, var/mob/user) + if(engine) + return + if(user) + user.drop_from_inventory(E) + engine = E + engine.forceMove(src) + if(trail) + qdel(trail) + trail = engine.get_trail() + if(trail) + trail.set_up(src) + +/obj/vehicle/bike/proc/unload_engine() + if(!engine) + return + engine.forceMove(get_turf(src)) + if(trail) + trail.stop() + qdel(trail) + trail = null + +/obj/vehicle/bike/load(var/atom/movable/C) + var/mob/living/M = C + if(!istype(C)) return 0 + if(M.buckled || M.restrained() || !Adjacent(M) || !M.Adjacent(src)) + return 0 + return ..(M) + +/obj/vehicle/bike/emp_act(var/severity) + if(engine) + engine.emp_act(severity) + ..() + +/obj/vehicle/bike/insert_cell(var/obj/item/weapon/cell/C, var/mob/living/carbon/human/H) + return + +/obj/vehicle/bike/attackby(obj/item/W as obj, mob/user as mob) + if(open) + if(istype(W, /obj/item/weapon/engine)) + if(engine) + to_chat(user, "There is already an engine block in \the [src].") + return 1 + user.visible_message("\The [user] installs \the [W] into \the [src].") + load_engine(W) + return + else if(engine && engine.attackby(W,user)) + return 1 + else if(isCrowbar(W) && engine) + to_chat(user, "You pop out \the [engine] from \the [src].") + unload_engine() + return 1 + return ..() + +/obj/vehicle/bike/MouseDrop_T(var/atom/movable/C, mob/user as mob) + if(!load(C)) + to_chat(user, " You were unable to load \the [C] onto \the [src].") + return + +/obj/vehicle/bike/attack_hand(var/mob/user as mob) + if(user == load) + unload(load) + to_chat(user, "You unbuckle yourself from \the [src]") + +/obj/vehicle/bike/relaymove(mob/user, direction) + if(user != load || !on || user.incapacitated()) + return + return Move(get_step(src, direction)) + +/obj/vehicle/bike/Move(var/turf/destination) + if(kickstand || (world.time <= l_move_time + move_delay)) return + //these things like space, not turf. Dragging shouldn't weigh you down. + if(!pulledby) + if(istype(destination,/turf/space) || pulledby) + if(!space_speed) + return 0 + move_delay = space_speed + else + if(!land_speed) + return 0 + move_delay = land_speed + if(!engine || !engine.use_power()) + turn_off() + return 0 + return ..() + +/obj/vehicle/bike/turn_on() + if(!engine || on) + return + + engine.rev_engine(src) + if(trail) + trail.start() + anchored = 1 + + update_icon() + + if(pulledby) + pulledby.stop_pulling() + ..() + +/obj/vehicle/bike/turn_off() + if(!on) + return + if(engine) + engine.putter(src) + + if(trail) + trail.stop() + + anchored = kickstand + + update_icon() + + ..() + +/obj/vehicle/bike/bullet_act(var/obj/item/projectile/Proj) + if(buckled_mob && prob(protection_percent)) + buckled_mob.bullet_act(Proj) + return + ..() + +/obj/vehicle/bike/update_icon() + overlays.Cut() + + if(on) + icon_state = "[bike_icon]_on" + else + icon_state = "[bike_icon]_off" + overlays += image('icons/obj/bike.dmi', "[icon_state]_overlay", BASE_MOB_LAYER + 1) + ..() + + +/obj/vehicle/bike/Destroy() + qdel(trail) + qdel(engine) + ..() + + + + +/obj/vehicle/bike/thermal + engine_type = /obj/item/weapon/engine/thermal + prefilled = 1 + +/obj/vehicle/bike/electric + engine_type = /obj/item/weapon/engine/electric + prefilled = 1 \ No newline at end of file diff --git a/code/modules/vehicles/cargo_train.dm b/code/modules/vehicles/cargo_train.dm new file mode 100644 index 00000000..8cdd4b1c --- /dev/null +++ b/code/modules/vehicles/cargo_train.dm @@ -0,0 +1,376 @@ +/obj/vehicle/train/cargo/engine + name = "cargo train tug" + desc = "A ridable electric car designed for pulling cargo trolleys." + icon = 'icons/obj/vehicles.dmi' + icon_state = "cargo_engine" + on = 0 + powered = 1 + locked = 0 + + load_item_visible = 1 + load_offset_x = 0 + buckle_pixel_shift = "x=0;y=7" + + var/car_limit = 3 //how many cars an engine can pull before performance degrades + charge_use = 1 KILOWATTS + active_engines = 1 + var/obj/item/weapon/key/cargo_train/key + +/obj/item/weapon/key/cargo_train + name = "key" + desc = "A keyring with a small steel key, and a yellow fob reading \"Choo Choo!\"." + icon = 'icons/obj/vehicles.dmi' + icon_state = "train_keys" + w_class = ITEM_SIZE_TINY + +/obj/vehicle/train/cargo/trolley + name = "cargo train trolley" + icon = 'icons/obj/vehicles.dmi' + icon_state = "cargo_trailer" + anchored = 0 + passenger_allowed = 0 + locked = 0 + + load_item_visible = 1 + load_offset_x = 0 + load_offset_y = 4 + buckle_pixel_shift = "x=0;y=8" + +//------------------------------------------- +// Standard procs +//------------------------------------------- +/obj/vehicle/train/cargo/engine/New() + ..() + cell = new /obj/item/weapon/cell/high(src) + key = new(src) + var/image/I = new(icon = 'icons/obj/vehicles.dmi', icon_state = "cargo_engine_overlay") + I.plane = plane + I.layer = layer + overlays += I + turn_off() //so engine verbs are correctly set + +/obj/vehicle/train/cargo/engine/Move(var/turf/destination) + if(on && cell.charge < (charge_use * CELLRATE)) + turn_off() + update_stats() + if(load && is_train_head()) + to_chat(load, "The drive motor briefly whines, then drones to a stop.") + + if(is_train_head() && !on) + return 0 + + //space check ~no flying space trains sorry + if(on && istype(destination, /turf/space)) + return 0 + + return ..() + +/obj/vehicle/train/cargo/trolley/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(open && isWirecutter(W)) + passenger_allowed = !passenger_allowed + user.visible_message("[user] [passenger_allowed ? "cuts" : "mends"] a cable in [src].","You [passenger_allowed ? "cut" : "mend"] the load limiter cable.") + else + ..() + +/obj/vehicle/train/cargo/engine/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/key/cargo_train)) + if(!key) + user.drop_item() + W.forceMove(src) + key = W + verbs += /obj/vehicle/train/cargo/engine/verb/remove_key + return + ..() + +//cargo trains are open topped, so there is a chance the projectile will hit the mob ridding the train instead +/obj/vehicle/train/cargo/bullet_act(var/obj/item/projectile/Proj) + if(buckled_mob && prob(70)) + buckled_mob.bullet_act(Proj) + return + ..() + +/obj/vehicle/train/cargo/update_icon() + if(open) + icon_state = initial(icon_state) + "_open" + else + icon_state = initial(icon_state) + +/obj/vehicle/train/cargo/trolley/insert_cell(var/obj/item/weapon/cell/C, var/mob/living/carbon/human/H) + return + +/obj/vehicle/train/cargo/engine/insert_cell(var/obj/item/weapon/cell/C, var/mob/living/carbon/human/H) + ..() + update_stats() + +/obj/vehicle/train/cargo/engine/remove_cell(var/mob/living/carbon/human/H) + ..() + update_stats() + +/obj/vehicle/train/cargo/engine/Bump(atom/Obstacle) + var/obj/machinery/door/D = Obstacle + var/mob/living/carbon/human/H = load + if(istype(D) && istype(H)) + D.Bumped(H) //a little hacky, but hey, it works, and respects access rights + + ..() + +/obj/vehicle/train/cargo/trolley/Bump(atom/Obstacle) + if(!lead) + return //so people can't knock others over by pushing a trolley around + ..() + +//------------------------------------------- +// Train procs +//------------------------------------------- +/obj/vehicle/train/cargo/engine/turn_on() + if(!key) + return + else + ..() + update_stats() + + verbs -= /obj/vehicle/train/cargo/engine/verb/stop_engine + verbs -= /obj/vehicle/train/cargo/engine/verb/start_engine + + if(on) + verbs += /obj/vehicle/train/cargo/engine/verb/stop_engine + else + verbs += /obj/vehicle/train/cargo/engine/verb/start_engine + +/obj/vehicle/train/cargo/engine/turn_off() + ..() + + verbs -= /obj/vehicle/train/cargo/engine/verb/stop_engine + verbs -= /obj/vehicle/train/cargo/engine/verb/start_engine + + if(!on) + verbs += /obj/vehicle/train/cargo/engine/verb/start_engine + else + verbs += /obj/vehicle/train/cargo/engine/verb/stop_engine + +/obj/vehicle/train/cargo/RunOver(var/mob/living/carbon/human/H) + var/list/parts = list(BP_HEAD, BP_CHEST, BP_L_LEG, BP_R_LEG, BP_L_ARM, BP_R_ARM) + + H.apply_effects(5, 5) + for(var/i = 0, i < rand(1,5), i++) + var/def_zone = pick(parts) + H.apply_damage(rand(5,10), BRUTE, def_zone, H.run_armor_check(def_zone, "melee")) + +/obj/vehicle/train/cargo/trolley/RunOver(var/mob/living/carbon/human/H) + ..() + attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey])") + +/obj/vehicle/train/cargo/engine/RunOver(var/mob/living/carbon/human/H) + ..() + + if(is_train_head() && istype(load, /mob/living/carbon/human)) + var/mob/living/carbon/human/D = load + to_chat(D, "You ran over [H]!") + visible_message(">\The [src] ran over [H]!") + attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey]), driven by [D.name] ([D.ckey])") + msg_admin_attack("[D.name] ([D.ckey]) ran over [H.name] ([H.ckey]). (JMP)") + else + attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey])") + + +//------------------------------------------- +// Interaction procs +//------------------------------------------- +/obj/vehicle/train/cargo/engine/relaymove(mob/user, direction) + if(user != load || user.incapacitated()) + return 0 + + if(is_train_head()) + if(direction == reverse_direction(dir) && tow) + return 0 + if(Move(get_step(src, direction))) + return 1 + return 0 + else + return ..() + +/obj/vehicle/train/cargo/engine/examine(mob/user) + if(!..(user, 1)) + return + + if(!istype(usr, /mob/living/carbon/human)) + return + + to_chat(user, "The power light is [on ? "on" : "off"].\nThere are[key ? "" : " no"] keys in the ignition.") + to_chat(user, "The charge meter reads [cell? round(cell.percent(), 0.01) : 0]%") + +/obj/vehicle/train/cargo/engine/verb/start_engine() + set name = "Start engine" + set category = "Object" + set src in view(0) + + if(!istype(usr, /mob/living/carbon/human)) + return + + if(on) + to_chat(usr, "The engine is already running.") + return + + turn_on() + if (on) + to_chat(usr, "You start [src]'s engine.") + else + if(cell.charge < charge_use) + to_chat(usr, "[src] is out of power.") + else + to_chat(usr, "[src]'s engine won't start.") + +/obj/vehicle/train/cargo/engine/verb/stop_engine() + set name = "Stop engine" + set category = "Object" + set src in view(0) + + if(!istype(usr, /mob/living/carbon/human)) + return + + if(!on) + to_chat(usr, "The engine is already stopped.") + return + + turn_off() + if (!on) + to_chat(usr, "You stop [src]'s engine.") + +/obj/vehicle/train/cargo/engine/verb/remove_key() + set name = "Remove key" + set category = "Object" + set src in view(0) + + if(!istype(usr, /mob/living/carbon/human)) + return + + if(!key || (load && load != usr)) + return + + if(on) + turn_off() + + key.loc = usr.loc + if(!usr.get_active_hand()) + usr.put_in_hands(key) + key = null + + verbs -= /obj/vehicle/train/cargo/engine/verb/remove_key + +//------------------------------------------- +// Loading/unloading procs +//------------------------------------------- +/obj/vehicle/train/cargo/trolley/load(var/atom/movable/C) + if(ismob(C) && !passenger_allowed) + return 0 + if(!istype(C,/obj/machinery) && !istype(C,/obj/structure/closet) && !istype(C,/obj/structure/largecrate) && !istype(C,/obj/structure/reagent_dispensers) && !istype(C,/obj/structure/ore_box) && !istype(C, /mob/living/carbon/human)) + return 0 + + //if there are any items you don't want to be able to interact with, add them to this check + // ~no more shielded, emitter armed death trains + if(istype(C, /obj/machinery)) + load_object(C) + else + ..() + + if(load) + return 1 + +/obj/vehicle/train/cargo/engine/load(var/atom/movable/C) + if(!istype(C, /mob/living/carbon/human)) + return 0 + + return ..() + +//Load the object "inside" the trolley and add an overlay of it. +//This prevents the object from being interacted with until it has +// been unloaded. A dummy object is loaded instead so the loading +// code knows to handle it correctly. +/obj/vehicle/train/cargo/trolley/proc/load_object(var/atom/movable/C) + if(!isturf(C.loc)) //To prevent loading things from someone's inventory, which wouldn't get handled properly. + return 0 + if(load || C.anchored) + return 0 + + var/datum/vehicle_dummy_load/dummy_load = new() + load = dummy_load + + if(!load) + return + dummy_load.actual_load = C + C.forceMove(src) + + if(load_item_visible) + C.pixel_x += load_offset_x + C.pixel_y += load_offset_y + C.plane = plane + C.layer = VEHICLE_LOAD_LAYER + + overlays += C + + //we can set these back now since we have already cloned the icon into the overlay + C.pixel_x = initial(C.pixel_x) + C.pixel_y = initial(C.pixel_y) + C.reset_plane_and_layer() + +/obj/vehicle/train/cargo/trolley/unload(var/mob/user, var/direction) + if(istype(load, /datum/vehicle_dummy_load)) + var/datum/vehicle_dummy_load/dummy_load = load + load = dummy_load.actual_load + dummy_load.actual_load = null + qdel(dummy_load) + overlays.Cut() + ..() + +//------------------------------------------- +// Latching/unlatching procs +//------------------------------------------- + +/obj/vehicle/train/cargo/engine/latch(obj/vehicle/train/T, mob/user) + if(!istype(T) || !Adjacent(T)) + return 0 + + //if we are attaching a trolley to an engine we don't care what direction + // it is in and it should probably be attached with the engine in the lead + if(istype(T, /obj/vehicle/train/cargo/trolley)) + T.attach_to(src, user) + else + var/T_dir = get_dir(src, T) //figure out where T is wrt src + + if(dir == T_dir) //if car is ahead + src.attach_to(T, user) + else if(reverse_direction(dir) == T_dir) //else if car is behind + T.attach_to(src, user) + +//------------------------------------------------------- +// Stat update procs +// +// Update the trains stats for speed calculations. +// The longer the train, the slower it will go. car_limit +// sets the max number of cars one engine can pull at +// full speed. Adding more cars beyond this will slow the +// train proportionate to the length of the train. Adding +// more engines increases this limit by car_limit per +// engine. +//------------------------------------------------------- +/obj/vehicle/train/cargo/engine/update_car(var/train_length, var/active_engines) + src.train_length = train_length + src.active_engines = active_engines + + //Update move delay + if(!is_train_head() || !on) + move_delay = initial(move_delay) //so that engines that have been turned off don't lag behind + else + move_delay = max(0, (-car_limit * active_engines) + train_length - active_engines) //limits base overweight so you cant overspeed trains + move_delay *= (1 / max(1, active_engines)) * 2 //overweight penalty (scaled by the number of engines) + move_delay += config.run_speed //base reference speed + move_delay *= 1.1 //makes cargo trains 10% slower than running when not overweight + +/obj/vehicle/train/cargo/trolley/update_car(var/train_length, var/active_engines) + src.train_length = train_length + src.active_engines = active_engines + + if(!lead && !tow) + anchored = 0 + else + anchored = 1 diff --git a/code/modules/vehicles/engine.dm b/code/modules/vehicles/engine.dm new file mode 100644 index 00000000..93b2f581 --- /dev/null +++ b/code/modules/vehicles/engine.dm @@ -0,0 +1,143 @@ +/obj/item/weapon/engine + name = "engine" + desc = "An engine used to power a small vehicle." + icon = 'icons/obj/objects.dmi' + w_class = ITEM_SIZE_HUGE + var/stat = 0 + var/trail_type + var/cost_per_move = 5 + +/obj/item/weapon/engine/proc/get_trail() + if(trail_type) + return new trail_type + return null + +/obj/item/weapon/engine/proc/prefill() + return + +/obj/item/weapon/engine/proc/use_power() + return 0 + +/obj/item/weapon/engine/proc/rev_engine(var/atom/movable/M) + return + +/obj/item/weapon/engine/proc/putter(var/atom/movable/M) + return + +/obj/item/weapon/engine/electric + name = "electric engine" + desc = "A battery-powered engine used to power a small vehicle." + icon_state = "engine_electric" + trail_type = /datum/effect/effect/system/trail/ion + cost_per_move = 200 // W + var/obj/item/weapon/cell/cell + +/obj/item/weapon/engine/electric/attackby(var/obj/item/I, var/mob/user) + if(istype(I,/obj/item/weapon/cell)) + if(cell) + to_chat(user, "There is already a cell in \the [src].") + else + cell = I + user.drop_from_inventory(I) + I.forceMove(src) + return 1 + else if(isCrowbar(I)) + if(cell) + to_chat(user, "You pry out \the [cell].") + cell.forceMove(get_turf(src)) + cell = null + return 1 + ..() + +/obj/item/weapon/engine/electric/prefill() + cell = new /obj/item/weapon/cell/high(src.loc) + +/obj/item/weapon/engine/electric/use_power() + if(!cell) + return 0 + return cell.use(cost_per_move * CELLRATE) + +/obj/item/weapon/engine/electric/rev_engine(var/atom/movable/M) + M.audible_message("\The [M] beeps, spinning up.") + +/obj/item/weapon/engine/electric/putter(var/atom/movable/M) + M.audible_message("\The [M] makes one depressed beep before winding down.") + +/obj/item/weapon/engine/electric/emp_act(var/severity) + if(cell) + cell.emp_act(severity) + ..() + +/obj/item/weapon/engine/thermal + name = "thermal engine" + desc = "A fuel-powered engine used to power a small vehicle." + icon_state = "engine_fuel" + trail_type = /datum/effect/effect/system/trail/thermal + atom_flags = ATOM_FLAG_OPEN_CONTAINER + var/obj/temp_reagents_holder + var/fuel_points = 0 + //fuel points are determined by differing reagents + +/obj/item/weapon/engine/thermal/prefill() + fuel_points = 5000 + +/obj/item/weapon/engine/thermal/New() + ..() + create_reagents(500) + temp_reagents_holder = new() + temp_reagents_holder.create_reagents(15) + temp_reagents_holder.atom_flags |= ATOM_FLAG_OPEN_CONTAINER + +/obj/item/weapon/engine/thermal/attackby(var/obj/item/I, var/mob/user) + if(istype(I,/obj/item/weapon/reagent_containers) && I.is_open_container()) + if(istype(I,/obj/item/weapon/reagent_containers/food/snacks) || istype(I,/obj/item/weapon/reagent_containers/pill)) + return 0 + var/obj/item/weapon/reagent_containers/C = I + C.standard_pour_into(user,src) + return 1 + ..() + +/obj/item/weapon/engine/thermal/use_power() + if(fuel_points >= cost_per_move) + fuel_points -= cost_per_move + return 1 + if(!reagents || reagents.total_volume <= 0 || stat) + return 0 + + reagents.trans_to(temp_reagents_holder,min(reagents.total_volume,15)) + var/multiplier = 1 + var/actually_flameable = 0 + for(var/datum/reagent/R in temp_reagents_holder.reagents.reagent_list) + var/new_multiplier = 1 + if(istype(R,/datum/reagent/ethanol)) + var/datum/reagent/ethanol/E = R + new_multiplier = (10/E.strength) + actually_flameable = 1 + else if(istype(R,/datum/reagent/hydrazine)) + new_multiplier = 1.25 + actually_flameable = 1 + else if(istype(R,/datum/reagent/fuel)) + actually_flameable = 1 + else if(istype(R,/datum/reagent/toxin/phoron)) + new_multiplier = 2 + actually_flameable = 1 + else if(istype(R,/datum/reagent/frostoil)) + new_multiplier = 0.1 + else if(istype(R,/datum/reagent/water)) + new_multiplier = 0.4 + else if(istype(R,/datum/reagent/sugar) && R.volume > 1) + stat = DEAD + explosion(get_turf(src),-1,0,2,3,0) + return 0 + multiplier = (multiplier + new_multiplier)/2 + if(!actually_flameable) + return 0 + fuel_points += 20 * multiplier * temp_reagents_holder.reagents.total_volume + temp_reagents_holder.reagents.clear_reagents() + return use_power() + +/obj/item/weapon/engine/thermal/rev_engine(var/atom/movable/M) + M.audible_message("\The [M] rumbles to life.") + +/obj/item/weapon/engine/electric/putter(var/atom/movable/M) + M.audible_message("\The [M] putters before turning off.") \ No newline at end of file diff --git a/code/modules/vehicles/train.dm b/code/modules/vehicles/train.dm new file mode 100644 index 00000000..5e7b93e8 --- /dev/null +++ b/code/modules/vehicles/train.dm @@ -0,0 +1,234 @@ +/obj/vehicle/train + name = "train" + dir = 4 + + move_delay = 1 + + health = 100 + maxhealth = 100 + fire_dam_coeff = 0.7 + brute_dam_coeff = 0.5 + + var/passenger_allowed = 1 + + var/active_engines = 0 + var/train_length = 0 + + var/obj/vehicle/train/lead + var/obj/vehicle/train/tow + + +//------------------------------------------- +// Standard procs +//------------------------------------------- +/obj/vehicle/train/Initialize() + . = ..() + for(var/obj/vehicle/train/T in orange(1, src)) + latch(T) + +/obj/vehicle/train/Move() + var/old_loc = get_turf(src) + if(..()) + if(tow) + tow.Move(old_loc) + return 1 + else + if(lead) + unattach() + return 0 + +/obj/vehicle/train/Bump(atom/Obstacle) + if(!istype(Obstacle, /atom/movable)) + return + var/atom/movable/A = Obstacle + + if(!A.anchored) + var/turf/T = get_step(A, dir) + if(isturf(T)) + A.Move(T) //bump things away when hit + + if(emagged) + if(istype(A, /mob/living)) + var/mob/living/M = A + visible_message("[src] knocks over [M]!") + var/def_zone = ran_zone() + M.apply_effects(5, 5) //knock people down if you hit them + M.apply_damage(22 / move_delay, BRUTE, def_zone, M.run_armor_check(def_zone, "melee")) // and do damage according to how fast the train is going + if(istype(load, /mob/living/carbon/human)) + var/mob/living/D = load + to_chat(D, "You hit [M]!") + msg_admin_attack("[D.name] ([D.ckey]) hit [M.name] ([M.ckey]) with [src]. (JMP)") + + +//------------------------------------------- +// Vehicle procs +//------------------------------------------- +/obj/vehicle/train/explode() + if (tow) + tow.unattach() + unattach() + ..() + + +//------------------------------------------- +// Interaction procs +//------------------------------------------- +/obj/vehicle/train/relaymove(mob/user, direction) + if(user.incapacitated()) + return 0 + + var/turf/T = get_step_to(src, get_step(src, direction)) + if(!T) + to_chat(user, "You can't find a clear area to step onto.") + return 0 + + if(user != load) + if(user in src) //for handling players stuck in src - this shouldn't happen - but just in case it does + user.forceMove(T) + return 1 + return 0 + + unload(user, direction) + + to_chat(user, "You climb down from [src].") + + return 1 + +/obj/vehicle/train/MouseDrop_T(var/atom/movable/C, mob/user as mob) + if(user.buckled || user.stat || user.restrained() || !Adjacent(user) || !user.Adjacent(C) || !istype(C) || (user == C && !user.canmove)) + return + if(istype(C,/obj/vehicle/train)) + latch(C, user) + else + if(!load(C)) + to_chat(user, "You were unable to load [C] on [src].") + +/obj/vehicle/train/attack_hand(mob/user as mob) + if(user.stat || user.restrained() || !Adjacent(user)) + return 0 + + if(user != load && (user in src)) + user.forceMove(loc) //for handling players stuck in src + else if(load) + unload(user) //unload if loaded + else if(!load && !user.buckled) + load(user) //else try climbing on board + else + return 0 + +/obj/vehicle/train/verb/unlatch_v() + set name = "Unlatch" + set desc = "Unhitches this train from the one in front of it." + set category = "Object" + set src in view(1) + + if(!istype(usr, /mob/living/carbon/human)) + return + + if(!usr.canmove || usr.stat || usr.restrained() || !Adjacent(usr)) + return + + unattach(usr) + +//------------------------------------------- +// Latching/unlatching procs +//------------------------------------------- + +//attempts to attach src as a follower of the train T +//Note: there is a modified version of this in code\modules\vehicles\cargo_train.dm specifically for cargo train engines +/obj/vehicle/train/proc/attach_to(obj/vehicle/train/T, mob/user) + if (get_dist(src, T) > 1) + to_chat(user, "[src] is too far away from [T] to hitch them together.") + return + + if (lead) + to_chat(user, "\The [src] is already hitched to something.") + return + + if (T.tow) + to_chat(user, "\The [T] is already towing something.") + return + + //check for cycles. + var/obj/vehicle/train/next_car = T + while (next_car) + if (next_car == src) + to_chat(user, "That seems very silly.") + return + next_car = next_car.lead + + //latch with src as the follower + lead = T + T.tow = src + set_dir(lead.dir) + + if(user) + to_chat(user, "You hitch \the [src] to \the [T].") + + update_stats() + + +//detaches the train from whatever is towing it +/obj/vehicle/train/proc/unattach(mob/user) + if (!lead) + to_chat(user, "\The [src] is not hitched to anything.") + return + + lead.tow = null + lead.update_stats() + + to_chat(user, "You unhitch \the [src] from \the [lead].") + lead = null + + update_stats() + +/obj/vehicle/train/proc/latch(obj/vehicle/train/T, mob/user) + if(!istype(T) || !Adjacent(T)) + return 0 + + var/T_dir = get_dir(src, T) //figure out where T is wrt src + + if(dir == T_dir) //if car is ahead + src.attach_to(T, user) + else if(reverse_direction(dir) == T_dir) //else if car is behind + T.attach_to(src, user) + +//returns 1 if this is the lead car of the train +/obj/vehicle/train/proc/is_train_head() + if (lead) + return 0 + return 1 + +//------------------------------------------------------- +// Stat update procs +// +// Used for updating the stats for how long the train is. +// These are useful for calculating speed based on the +// size of the train, to limit super long trains. +//------------------------------------------------------- +/obj/vehicle/train/update_stats() + //first, seek to the end of the train + var/obj/vehicle/train/T = src + while(T.tow) + //check for cyclic train. + if (T.tow == src) + lead.tow = null + lead.update_stats() + + lead = null + update_stats() + return + T = T.tow + + //now walk back to the front. + var/active_engines = 0 + var/train_length = 0 + while(T) + train_length++ + if (T.powered && T.on) + active_engines++ + T.update_car(train_length, active_engines) + T = T.lead + +/obj/vehicle/train/proc/update_car(var/train_length, var/active_engines) + return diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm new file mode 100644 index 00000000..96658300 --- /dev/null +++ b/code/modules/vehicles/vehicle.dm @@ -0,0 +1,367 @@ +//Dummy object for holding items in vehicles. +//Prevents items from being interacted with. +/datum/vehicle_dummy_load + var/name = "dummy load" + var/actual_load + +/obj/vehicle + name = "vehicle" + icon = 'icons/obj/vehicles.dmi' + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + density = 1 + anchored = 1 + animate_movement=1 + light_range = 3 + + can_buckle = 1 + buckle_movable = 1 + buckle_lying = 0 + + var/attack_log = null + var/on = 0 + var/health = 0 //do not forget to set health for your vehicle! + var/maxhealth = 0 + var/fire_dam_coeff = 1.0 + var/brute_dam_coeff = 1.0 + var/open = 0 //Maint panel + var/locked = 1 + var/stat = 0 + var/emagged = 0 + var/powered = 0 //set if vehicle is powered and should use fuel when moving + var/move_delay = 1 //set this to limit the speed of the vehicle + + var/obj/item/weapon/cell/cell + var/charge_use = 200 //W + + var/atom/movable/load //all vehicles can take a load, since they should all be a least drivable + var/load_item_visible = 1 //set if the loaded item should be overlayed on the vehicle sprite + var/load_offset_x = 0 //pixel_x offset for item overlay + var/load_offset_y = 0 //pixel_y offset for item overlay + +//------------------------------------------- +// Standard procs +//------------------------------------------- +/obj/vehicle/New() + ..() + //spawn the cell you want in each vehicle + +/obj/vehicle/Move() + if(world.time > l_move_time + move_delay) + var/old_loc = get_turf(src) + if(on && powered && cell.charge < (charge_use * CELLRATE)) + turn_off() + + var/init_anc = anchored + anchored = 0 + if(!..()) + anchored = init_anc + return 0 + + set_dir(get_dir(old_loc, loc)) + anchored = init_anc + + if(on && powered) + cell.use(charge_use * CELLRATE) + + //Dummy loads do not have to be moved as they are just an overlay + //See load_object() proc in cargo_trains.dm for an example + if(load && !istype(load, /datum/vehicle_dummy_load)) + load.forceMove(loc) + load.set_dir(dir) + + return 1 + else + return 0 + +/obj/vehicle/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/hand_labeler)) + return + if(isScrewdriver(W)) + if(!locked) + open = !open + update_icon() + to_chat(user, "Maintenance panel is now [open ? "opened" : "closed"].") + else if(isCrowbar(W) && cell && open) + remove_cell(user) + + else if(istype(W, /obj/item/weapon/cell) && !cell && open) + insert_cell(W, user) + else if(isWelder(W)) + var/obj/item/weapon/weldingtool/T = W + if(T.welding) + if(health < maxhealth) + if(open) + health = min(maxhealth, health+10) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.visible_message("\The [user] repairs \the [src]!","You repair \the [src]!") + else + to_chat(user, "Unable to repair with the maintenance panel closed.") + else + to_chat(user, "[src] does not need a repair.") + else + to_chat(user, "Unable to repair while [src] is off.") + else if(hasvar(W,"force") && hasvar(W,"damtype")) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + switch(W.damtype) + if("fire") + health -= W.force * fire_dam_coeff + if("brute") + health -= W.force * brute_dam_coeff + ..() + healthcheck() + else + ..() + +/obj/vehicle/bullet_act(var/obj/item/projectile/Proj) + health -= Proj.get_structure_damage() + ..() + healthcheck() + +/obj/vehicle/ex_act(severity) + switch(severity) + if(1.0) + explode() + return + if(2.0) + health -= rand(5,10)*fire_dam_coeff + health -= rand(10,20)*brute_dam_coeff + healthcheck() + return + if(3.0) + if (prob(50)) + health -= rand(1,5)*fire_dam_coeff + health -= rand(1,5)*brute_dam_coeff + healthcheck() + return + return + +/obj/vehicle/emp_act(severity) + var/was_on = on + stat |= EMPED + var/obj/effect/overlay/pulse2 = new /obj/effect/overlay(loc) + pulse2.icon = 'icons/effects/effects.dmi' + pulse2.icon_state = "empdisable" + pulse2.SetName("emp sparks") + pulse2.anchored = 1 + pulse2.set_dir(pick(GLOB.cardinal)) + + spawn(10) + qdel(pulse2) + if(on) + turn_off() + spawn(severity*300) + stat &= ~EMPED + if(was_on) + turn_on() + +/obj/vehicle/attack_ai(mob/user as mob) + return + +/obj/vehicle/unbuckle_mob(mob/user) + . = ..(user) + if(load == .) + unload(.) + +//------------------------------------------- +// Vehicle procs +//------------------------------------------- +/obj/vehicle/proc/turn_on() + if(stat) + return 0 + if(powered && cell.charge < (charge_use * CELLRATE)) + return 0 + on = 1 + set_light(initial(light_range)) + update_icon() + return 1 + +/obj/vehicle/proc/turn_off() + on = 0 + set_light(0) + update_icon() + +/obj/vehicle/emag_act(var/remaining_charges, mob/user as mob) + if(!emagged) + emagged = 1 + if(locked) + locked = 0 + to_chat(user, "You bypass [src]'s controls.") + return 1 + +/obj/vehicle/proc/explode() + src.visible_message("\The [src] blows apart!") + var/turf/Tsec = get_turf(src) + + new /obj/item/stack/rods(Tsec) + new /obj/item/stack/rods(Tsec) + new /obj/item/stack/cable_coil/cut(Tsec) + + if(cell) + cell.forceMove(Tsec) + cell.update_icon() + cell = null + + //stuns people who are thrown off a train that has been blown up + if(istype(load, /mob/living)) + var/mob/living/M = load + M.apply_effects(5, 5) + + unload() + + new /obj/effect/gibspawner/robot(Tsec) + new /obj/effect/decal/cleanable/blood/oil(src.loc) + + qdel(src) + +/obj/vehicle/proc/healthcheck() + if(health <= 0) + explode() + +/obj/vehicle/proc/powercheck() + if(!cell && !powered) + return + + if(!cell && powered) + turn_off() + return + + if(cell.charge < (charge_use * CELLRATE)) + turn_off() + return + + if(cell && powered) + turn_on() + return + +/obj/vehicle/proc/insert_cell(var/obj/item/weapon/cell/C, var/mob/living/carbon/human/H) + if(cell) + return + if(!istype(C)) + return + + H.drop_from_inventory(C) + C.forceMove(src) + cell = C + powercheck() + to_chat(usr, "You install [C] in [src].") + +/obj/vehicle/proc/remove_cell(var/mob/living/carbon/human/H) + if(!cell) + return + + to_chat(usr, "You remove [cell] from [src].") + cell.forceMove(get_turf(H)) + H.put_in_hands(cell) + cell = null + powercheck() + +/obj/vehicle/proc/RunOver(var/mob/living/carbon/human/H) + return //write specifics for different vehicles + +//------------------------------------------- +// Loading/unloading procs +// +// Set specific item restriction checks in +// the vehicle load() definition before +// calling this parent proc. +//------------------------------------------- +/obj/vehicle/proc/load(var/atom/movable/C) + //This loads objects onto the vehicle so they can still be interacted with. + //Define allowed items for loading in specific vehicle definitions. + if(!isturf(C.loc)) //To prevent loading things from someone's inventory, which wouldn't get handled properly. + return 0 + if(load || C.anchored) + return 0 + + // if a create/closet, close before loading + var/obj/structure/closet/crate = C + if(istype(crate) && crate.opened && !crate.close()) + return 0 + + C.forceMove(loc) + C.set_dir(dir) + C.anchored = 1 + + load = C + + if(load_item_visible) + C.plane = plane + C.layer = VEHICLE_LOAD_LAYER //so it sits above the vehicle + + if(ismob(C)) + buckle_mob(C) + else if(load_item_visible) + C.pixel_x += load_offset_x + C.pixel_y += load_offset_y + + return 1 + + +/obj/vehicle/proc/unload(var/mob/user, var/direction) + if(!load) + return + + var/turf/dest = null + + //find a turf to unload to + if(direction) //if direction specified, unload in that direction + dest = get_step(src, direction) + else if(user) //if a user has unloaded the vehicle, unload at their feet + dest = get_turf(user) + + if(!dest) + dest = get_step_to(src, get_step(src, turn(dir, 90))) //try unloading to the side of the vehicle first if neither of the above are present + + //if these all result in the same turf as the vehicle or nullspace, pick a new turf with open space + if(!dest || dest == get_turf(src)) + var/list/options = new() + for(var/test_dir in GLOB.alldirs) + var/new_dir = get_step_to(src, get_step(src, test_dir)) + if(new_dir && load.Adjacent(new_dir)) + options += new_dir + if(options.len) + dest = pick(options) + else + dest = get_turf(src) //otherwise just dump it on the same turf as the vehicle + + if(!isturf(dest)) //if there still is nowhere to unload, cancel out since the vehicle is probably in nullspace + return 0 + + load.forceMove(dest) + load.set_dir(get_dir(loc, dest)) + load.anchored = 0 //we can only load non-anchored items, so it makes sense to set this to false + if(ismob(load)) //atoms should probably have their own procs to define how their pixel shifts and layer can be manipulated, someday + var/mob/M = load + M.pixel_x = M.default_pixel_x + M.pixel_y = M.default_pixel_y + else + load.pixel_x = initial(load.pixel_x) + load.pixel_y = initial(load.pixel_y) + load.reset_plane_and_layer() + + if(ismob(load)) + unbuckle_mob(load) + + load = null + + return 1 + + +//------------------------------------------------------- +// Stat update procs +//------------------------------------------------------- +/obj/vehicle/proc/update_stats() + return + +/obj/vehicle/attack_generic(var/mob/user, var/damage, var/attack_message) + if(!damage) + return + visible_message("\The [user] [attack_message] the \the [src]!") + if(istype(user)) + admin_attacker_log(user, "attacked \the [src]") + src.health -= damage + if(prob(10)) + new /obj/effect/decal/cleanable/blood/oil(src.loc) + spawn(1) healthcheck() + return 1 diff --git a/code/modules/ventcrawl/ventcrawl.dm b/code/modules/ventcrawl/ventcrawl.dm new file mode 100644 index 00000000..459f7981 --- /dev/null +++ b/code/modules/ventcrawl/ventcrawl.dm @@ -0,0 +1,181 @@ +var/list/ventcrawl_machinery = list( + /obj/machinery/atmospherics/unary/vent_scrubber, + /obj/machinery/atmospherics/unary/vent_pump + ) + +// Vent crawling whitelisted items, whoo +/mob/living/var/list/can_enter_vent_with = list( + /obj/item/weapon/implant, + /obj/item/device/radio/borg, + /obj/item/weapon/holder, + /obj/machinery/camera, + /mob/living/simple_animal/borer + ) + +/mob/living/var/list/icon/pipes_shown = list() +/mob/living/var/last_played_vent +/mob/living/var/is_ventcrawling = 0 +/mob/var/next_play_vent = 0 + +/mob/living/proc/can_ventcrawl() + if(!client) + return FALSE + if(!(/mob/living/proc/ventcrawl in verbs)) + to_chat(src, "You don't possess the ability to ventcrawl!") + return FALSE + if(incapacitated()) + to_chat(src, "You cannot ventcrawl in your current state!") + return FALSE + return ventcrawl_carry() + +/mob/living/Login() + . = ..() + //login during ventcrawl + if(is_ventcrawling && istype(loc, /obj/machinery/atmospherics)) //attach us back into the pipes + remove_ventcrawl() + add_ventcrawl(loc) + +/mob/living/carbon/slime/can_ventcrawl() + if(Victim) + to_chat(src, "You cannot ventcrawl while feeding.") + return FALSE + . = ..() + +/mob/living/proc/is_allowed_vent_crawl_item(var/obj/item/carried_item) + if(is_type_in_list(carried_item, can_enter_vent_with)) + return !get_inventory_slot(carried_item) + +/mob/living/carbon/is_allowed_vent_crawl_item(var/obj/item/carried_item) + if((carried_item in internal_organs) || (carried_item in stomach_contents)) + return 1 + return ..() + +/mob/living/carbon/human/is_allowed_vent_crawl_item(var/obj/item/carried_item) + if(carried_item in organs) + return 1 + if(carried_item in list(w_uniform, gloves, glasses, wear_mask, l_ear, r_ear, belt, l_store, r_store)) + return 1 + if(carried_item in list(l_hand,r_hand)) + return carried_item.w_class <= ITEM_SIZE_NORMAL + return ..() + +/mob/living/simple_animal/spiderbot/is_allowed_vent_crawl_item(var/obj/item/carried_item) + if(carried_item in list(held_item, radio, connected_ai, cell, camera, mmi)) + return 1 + return ..() + +/mob/living/proc/ventcrawl_carry() + for(var/atom/A in contents) + if(!is_allowed_vent_crawl_item(A)) + to_chat(src, "You can't carry \the [A] while ventcrawling!") + return FALSE + return TRUE + +/mob/living/AltClickOn(var/atom/A) + if(is_type_in_list(A,ventcrawl_machinery)) + handle_ventcrawl(A) + return 1 + return ..() + +/mob/proc/start_ventcrawl() + var/atom/pipe + var/list/pipes = list() + for(var/obj/machinery/atmospherics/unary/U in range(1)) + if(is_type_in_list(U,ventcrawl_machinery) && Adjacent(U) && U.can_crawl_through()) + pipes |= U + if(!pipes || !pipes.len) + to_chat(src, "There are no pipes that you can ventcrawl into within range!") + return + if(pipes.len == 1) + pipe = pipes[1] + else + pipe = input("Crawl Through Vent", "Pick a pipe") as null|anything in pipes + if(canmove && pipe) + return pipe + +/mob/living/carbon/alien/ventcrawl_carry() + return 1 + +/mob/living/proc/handle_ventcrawl(var/atom/clicked_on) + if(!can_ventcrawl()) + return + + var/obj/machinery/atmospherics/unary/vent_found + if(clicked_on && Adjacent(clicked_on)) + vent_found = clicked_on + if(!istype(vent_found) || !vent_found.can_crawl_through()) + vent_found = null + + if(!vent_found) + for(var/obj/machinery/atmospherics/machine in range(1,src)) + if(is_type_in_list(machine, ventcrawl_machinery)) + vent_found = machine + + if(!vent_found || !vent_found.can_crawl_through()) + vent_found = null + + if(vent_found) + break + + if(vent_found) + if(vent_found.network && (vent_found.network.normal_members.len || vent_found.network.line_members.len)) + + to_chat(src, "You begin climbing into the ventilation system...") + if(vent_found.air_contents && !issilicon(src)) + + switch(vent_found.air_contents.temperature) + if(0 to BODYTEMP_COLD_DAMAGE_LIMIT) + to_chat(src, "You feel a painful freeze coming from the vent!") + if(BODYTEMP_COLD_DAMAGE_LIMIT to T0C) + to_chat(src, "You feel an icy chill coming from the vent.") + if(T0C + 40 to BODYTEMP_HEAT_DAMAGE_LIMIT) + to_chat(src, "You feel a hot wash coming from the vent.") + if(BODYTEMP_HEAT_DAMAGE_LIMIT to INFINITY) + to_chat(src, "You feel a searing heat coming from the vent!") + switch(vent_found.air_contents.return_pressure()) + if(0 to HAZARD_LOW_PRESSURE) + to_chat(src, "You feel a rushing draw pulling you into the vent!") + if(HAZARD_LOW_PRESSURE to WARNING_LOW_PRESSURE) + to_chat(src, "You feel a strong drag pulling you into the vent.") + if(WARNING_HIGH_PRESSURE to HAZARD_HIGH_PRESSURE) + to_chat(src, "You feel a strong current pushing you away from the vent.") + if(HAZARD_HIGH_PRESSURE to INFINITY) + to_chat(src, "You feel a roaring wind pushing you away from the vent!") + if(!do_after(src, 45, vent_found, 1, 1)) + return + if(!can_ventcrawl()) + return + + visible_message("[src] scrambles into the ventilation ducts!", "You climb into the ventilation system.") + + forceMove(vent_found) + add_ventcrawl(vent_found) + + else + to_chat(src, "This vent is not connected to anything.") + else + to_chat(src, "You must be standing on or beside an air vent to enter it.") +/mob/living/proc/add_ventcrawl(obj/machinery/atmospherics/starting_machine) + is_ventcrawling = 1 + //candrop = 0 + var/datum/pipe_network/network = starting_machine.return_network(starting_machine) + if(!network) + return + for(var/datum/pipeline/pipeline in network.line_members) + for(var/obj/machinery/atmospherics/A in (pipeline.members || pipeline.edges)) + if(!A.pipe_image) + A.pipe_image = image(A, A.loc, dir = A.dir) + A.pipe_image.layer = ABOVE_LIGHTING_LAYER + A.pipe_image.plane = EFFECTS_ABOVE_LIGHTING_PLANE + pipes_shown += A.pipe_image + client.images += A.pipe_image + +/mob/living/proc/remove_ventcrawl() + is_ventcrawling = 0 + //candrop = 1 + if(client) + for(var/image/current_image in pipes_shown) + client.images -= current_image + client.eye = src + + pipes_shown.len = 0 \ No newline at end of file diff --git a/code/modules/ventcrawl/ventcrawl_atmospherics.dm b/code/modules/ventcrawl/ventcrawl_atmospherics.dm new file mode 100644 index 00000000..b540134a --- /dev/null +++ b/code/modules/ventcrawl/ventcrawl_atmospherics.dm @@ -0,0 +1,89 @@ +/obj/machinery/atmospherics/var/image/pipe_image + +/obj/machinery/atmospherics/Destroy() + for(var/mob/living/M in src) //ventcrawling is serious business + M.remove_ventcrawl() + M.forceMove(get_turf(src)) + if(pipe_image) + for(var/mob/living/M in GLOB.player_list) + if(M.client) + M.client.images -= pipe_image + M.pipes_shown -= pipe_image + pipe_image = null + . = ..() + +/obj/machinery/atmospherics/ex_act(severity) + for(var/atom/movable/A in src) //ventcrawling is serious business + A.ex_act(severity) + . = ..() + +/obj/machinery/atmospherics/relaymove(mob/living/user, direction) + if(user.loc != src || !(direction & initialize_directions)) //can't go in a way we aren't connecting to + return + ventcrawl_to(user,findConnecting(direction),direction) + +/obj/machinery/atmospherics/proc/ventcrawl_to(var/mob/living/user, var/obj/machinery/atmospherics/target_move, var/direction) + if(target_move) + if(is_type_in_list(target_move, ventcrawl_machinery) && target_move.can_crawl_through()) + user.remove_ventcrawl() + user.forceMove(target_move.loc) //handles entering and so on + user.visible_message("You hear something squeezing through the ducts.", "You climb out the ventilation system.") + else if(target_move.can_crawl_through()) + if(target_move.return_network(target_move) != return_network(src)) + user.remove_ventcrawl() + user.add_ventcrawl(target_move) + user.forceMove(target_move) + user.client.eye = target_move //if we don't do this, Byond only updates the eye every tick - required for smooth movement + if(world.time > user.next_play_vent) + user.next_play_vent = world.time+30 + playsound(src, 'sound/machines/ventcrawl.ogg', 50, 1, -3) + else + if((direction & initialize_directions) || is_type_in_list(src, ventcrawl_machinery) && src.can_crawl_through()) //if we move in a way the pipe can connect, but doesn't - or we're in a vent + user.remove_ventcrawl() + user.forceMove(src.loc) + user.visible_message("You hear something squeezing through the pipes.", "You climb out the ventilation system.") + user.canmove = 0 + spawn(1) + user.canmove = 1 + +/obj/machinery/atmospherics/proc/can_crawl_through() + return 1 + +/obj/machinery/atmospherics/unary/vent_pump/can_crawl_through() + return !welded + +/obj/machinery/atmospherics/unary/vent_scrubber/can_crawl_through() + return !welded + +/obj/machinery/atmospherics/proc/findConnecting(var/direction) + for(var/obj/machinery/atmospherics/target in get_step(src,direction)) + if(target.initialize_directions & get_dir(target,src)) + if(isConnectable(target) && target.isConnectable(src)) + return target + +/obj/machinery/atmospherics/proc/isConnectable(var/obj/machinery/atmospherics/target) + return (target == node1 || target == node2) + +/obj/machinery/atmospherics/pipe/manifold/isConnectable(var/obj/machinery/atmospherics/target) + return (target == node3 || ..()) + +obj/machinery/atmospherics/trinary/isConnectable(var/obj/machinery/atmospherics/target) + return (target == node3 || ..()) + +/obj/machinery/atmospherics/pipe/manifold4w/isConnectable(var/obj/machinery/atmospherics/target) + return (target == node3 || target == node4 || ..()) + +/obj/machinery/atmospherics/tvalve/isConnectable(var/obj/machinery/atmospherics/target) + return (target == node3 || ..()) + +/obj/machinery/atmospherics/pipe/cap/isConnectable(var/obj/machinery/atmospherics/target) + return (target == node || ..()) + +/obj/machinery/atmospherics/portables_connector/isConnectable(var/obj/machinery/atmospherics/target) + return (target == node || ..()) + +/obj/machinery/atmospherics/unary/isConnectable(var/obj/machinery/atmospherics/target) + return (target == node || ..()) + +/obj/machinery/atmospherics/valve/isConnectable() + return (open && ..()) diff --git a/code/modules/ventcrawl/ventcrawl_multiz.dm b/code/modules/ventcrawl/ventcrawl_multiz.dm new file mode 100644 index 00000000..87ef8f9b --- /dev/null +++ b/code/modules/ventcrawl/ventcrawl_multiz.dm @@ -0,0 +1,24 @@ +/obj/machinery/atmospherics/pipe/zpipe/up/verb/ventcrawl_move_up() + set name = "Ventcrawl Upwards" + set desc = "Climb up through a pipe." + set category = "Abilities" + set src = usr.loc + var/obj/machinery/atmospherics/target = check_ventcrawl(GetAbove(loc)) + if(target) ventcrawl_to(usr, target, UP) + +/obj/machinery/atmospherics/pipe/zpipe/down/verb/ventcrawl_move_down() + set name = "Ventcrawl Downwards" + set desc = "Climb down through a pipe." + set category = "Abilities" + set src = usr.loc + var/obj/machinery/atmospherics/target = check_ventcrawl(GetBelow(loc)) + if(target) ventcrawl_to(usr, target, DOWN) + +/obj/machinery/atmospherics/pipe/zpipe/proc/check_ventcrawl(var/turf/target) + if(!istype(target)) + return + if(node1 in target) + return node1 + if(node2 in target) + return node2 + return \ No newline at end of file diff --git a/code/modules/ventcrawl/ventcrawl_verb.dm b/code/modules/ventcrawl/ventcrawl_verb.dm new file mode 100644 index 00000000..b49f2283 --- /dev/null +++ b/code/modules/ventcrawl/ventcrawl_verb.dm @@ -0,0 +1,7 @@ +/mob/living/proc/ventcrawl() + set name = "Crawl through Vent" + set desc = "Enter an air vent and crawl through the pipe system." + set category = "Abilities" + var/pipe = start_ventcrawl() + if(pipe) + handle_ventcrawl() diff --git a/code/modules/virus2/admin.dm b/code/modules/virus2/admin.dm new file mode 100644 index 00000000..541f6dc2 --- /dev/null +++ b/code/modules/virus2/admin.dm @@ -0,0 +1,215 @@ +/datum/disease2/disease/Topic(href, href_list) + . = ..() + if(.) return + + if(href_list["info"]) + // spawn or admin privileges to see info about viruses + if(!check_rights(R_ADMIN|R_SPAWN)) return + + to_chat(usr, "Infection chance: [infectionchance]; Speed: [speed]; Spread type: [spreadtype]") + to_chat(usr, "Affected species: [english_list(affected_species)]") + to_chat(usr, "Effects:") + for(var/datum/disease2/effect/E in effects) + to_chat(usr, "[E.stage]: [E.name]; chance=[E.chance]; multiplier=[E.multiplier]") + to_chat(usr, "Antigens: [antigens2string(antigen)]") + + return 1 + +/datum/disease2/disease/get_view_variables_header() + . = list() + for(var/datum/disease2/effect/E in effects) + . += "[E.stage]: [E.name]" + return {" + [name()]
                + [jointext(., "
                ")]
                + "} + +/datum/disease2/disease/get_view_variables_options() + return ..() + {" + + "} + +/datum/admins/var/datum/virus2_editor/virus2_editor_datum = new +/client/proc/virus2_editor() + set name = "Virus Editor" + set category = "Admin" + if(!holder || !check_rights(R_SPAWN)) return // spawn privileges to create viruses + + holder.virus2_editor_datum.show_ui(src) + +/datum/virus2_editor + var/list/s = list(/datum/disease2/effect/invisible,/datum/disease2/effect/invisible,/datum/disease2/effect/invisible,/datum/disease2/effect/invisible) + var/list/s_chance = list(1,1,1,1) + var/list/s_multiplier = list(1,1,1,1) + var/species = list() + var/infectionchance = 70 + var/spreadtype = "Contact" + var/list/antigens = list() + var/speed = 1 + var/mob/living/carbon/infectee = null + + // this holds spawned viruses so that the "Info" links work after the proc exits + var/list/spawned_viruses = list() + + proc/select(mob/user, stage) + if(stage < 1 || stage > 4) return + + var/list/L = list() + + for(var/e in (typesof(/datum/disease2/effect) - /datum/disease2/effect)) + var/datum/disease2/effect/f = e + if(initial(f.stage) <= stage) + L[initial(f.name)] = e + + var/datum/disease2/effect/Eff = s[stage] + + var/C = input("Select effect for stage [stage]:", "Stage [stage]", initial(Eff.name)) as null|anything in L + if(!C) return + return L[C] + + proc/show_ui(mob/user) + var/H = {" +

                Virus2 Virus Editor


                + Effects:
                + "} + for(var/i = 1 to 4) + var/datum/disease2/effect/Eff = s[i] + H += {" + [initial(Eff.name)] + Chance: [s_chance[i]] + Multiplier: [s_multiplier[i]] +
                + "} + H += {" +
                + Infectable Species:
                + "} + var/f = 1 + for(var/k in all_species) + var/datum/species/S = all_species[k] + if(S.get_virus_immune()) + continue + if(!f) H += " | " + else f = 0 + H += "[k]" + H += {" + Reset +
                + Infection Chance: [infectionchance]
                + Spread Type: [spreadtype]
                + Speed: [speed]
                +
                + "} + f = 1 + for(var/k in ALL_ANTIGENS) + if(!f) H += " | " + else f = 0 + H += "[k]" + H += {" + Reset +
                +
                + Initial infectee: [infectee ? infectee : "(choose)"] + RELEASE + "} + + user << browse(H, "window=virus2edit") + + Topic(href, href_list) + switch(href_list["what"]) + if("effect") + var/stage = text2num(href_list["stage"]) + if(href_list["effect"]) + var/datum/disease2/effect/E = select(usr,stage) + if(!E) return + s[stage] = E + // set a default chance and multiplier of half the maximum (roughly average) + s_chance[stage] = max(1, round(initial(E.chance_max)/2)) + s_multiplier[stage] = max(1, round(initial(E.multiplier_max)/2)) + else if(href_list["chance"]) + var/datum/disease2/effect/Eff = s[stage] + var/I = input("Chance, per tick, of this effect happening (min 0, max [initial(Eff.chance_max)])", "Effect Chance", s_chance[stage]) as null|num + if(I == null || I < 0 || I > initial(Eff.chance_max)) return + s_chance[stage] = I + else if(href_list["multiplier"]) + var/datum/disease2/effect/Eff = s[stage] + var/I = input("Multiplier for this effect (min 1, max [initial(Eff.multiplier_max)])", "Effect Multiplier", s_multiplier[stage]) as null|num + if(I == null || I < 1 || I > initial(Eff.multiplier_max)) return + s_multiplier[stage] = I + if("species") + if(href_list["toggle"]) + var/T = href_list["toggle"] + if(T in species) + species -= T + else + species |= T + else if(href_list["reset"]) + species = list() + if(infectee) + if(!infectee.species || !(infectee.species.get_bodytype(infectee) in species)) + infectee = null + if("ichance") + var/I = input("Input infection chance", "Infection Chance", infectionchance) as null|num + if(!I) return + infectionchance = I + if("stype") + var/S = alert("Which spread type?", "Spread Type", "Cancel", "Contact", "Airborne") + if(!S || S == "Cancel") return + spreadtype = S + if("speed") + var/S = input("Input speed", "Speed", speed) as null|num + if(!S) return + speed = S + if("antigen") + if(href_list["toggle"]) + var/T = href_list["toggle"] + if(length(T) != 1) return + if(T in antigens) + antigens -= T + else + antigens |= T + else if(href_list["reset"]) + antigens = list() + if("infectee") + var/list/candidates = list() + for(var/mob/living/carbon/G in GLOB.living_mob_list_) + if(G.stat != DEAD && G.species) + if(G.species.get_bodytype(G) in species) + candidates["[G.name][G.client ? "" : " (no client)"]"] = G + else + candidates["[G.name] ([G.species.get_bodytype(G)])[G.client ? "" : " (no client)"]"] = G + if(!candidates.len) to_chat(usr, "No possible candidates found!") + + var/I = input("Choose initial infectee", "Infectee", infectee) as null|anything in candidates + if(!I || !candidates[I]) return + infectee = candidates[I] + species |= infectee.species.get_bodytype(infectee) + if("go") + if(!antigens.len) + var/a = alert("This disease has no antigens; it will be impossible to permanently immunise anyone without them.\ + It is strongly recommended to set at least one antigen. Do you want to go back and edit your virus?", "Antigens", "Yes", "Yes", "No") + if(a == "Yes") return + var/datum/disease2/disease/D = new + D.infectionchance = infectionchance + D.spreadtype = spreadtype + D.antigen = antigens + D.affected_species = species + D.speed = speed + for(var/i in 1 to 4) + var/datum/disease2/effect/E = new + var/Etype = s[i] + E = new Etype() + E.generate() + E.chance = s_chance[i] + E.multiplier = s_multiplier[i] + E.stage = i + + D.effects += E + + spawned_viruses += D + + message_admins("[key_name_admin(usr)] infected [key_name_admin(infectee)] with a virus (Info)") + log_admin("[key_name_admin(usr)] infected [key_name_admin(infectee)] with a virus!") + infect_virus2(infectee, D, forced=1) + + show_ui(usr) diff --git a/code/modules/virus2/analyser.dm b/code/modules/virus2/analyser.dm new file mode 100644 index 00000000..c6b1f48a --- /dev/null +++ b/code/modules/virus2/analyser.dm @@ -0,0 +1,69 @@ +/obj/machinery/disease2/diseaseanalyser + name = "disease analyser" + icon = 'icons/obj/virology.dmi' + icon_state = "analyser" + anchored = 1 + density = 1 + + var/scanning = 0 + var/pause = 0 + + var/obj/item/weapon/virusdish/dish = null + +/obj/machinery/disease2/diseaseanalyser/attackby(var/obj/O as obj, var/mob/user as mob) + if(!istype(O,/obj/item/weapon/virusdish)) return + + if(dish) + to_chat(user, "\The [src] is already loaded.") + return + + dish = O + user.drop_item() + O.loc = src + + user.visible_message("[user] adds \a [O] to \the [src]!", "You add \a [O] to \the [src]!") + +/obj/machinery/disease2/diseaseanalyser/Process() + if(stat & (NOPOWER|BROKEN)) + return + + if(scanning) + scanning -= 1 + if(scanning == 0) + if (dish.virus2.addToDB()) + ping("\The [src] pings, \"New pathogen added to data bank.\"") + + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(src.loc) + P.SetName("paper - [dish.virus2.name()]") + + var/r = dish.virus2.get_info() + P.info = {" + [virology_letterhead("Post-Analysis Memo")] + [r] +
                + Additional Notes:  +"} + dish.basic_info = dish.virus2.get_basic_info() + dish.info = r + dish.SetName("[initial(dish.name)] ([dish.virus2.name()])") + dish.analysed = 1 + dish.loc = src.loc + dish = null + + icon_state = "analyser" + src.state("\The [src] prints a sheet of paper.") + + else if(dish && !scanning && !pause) + if(dish.virus2 && dish.growth > 50) + dish.growth -= 10 + scanning = 5 + icon_state = "analyser_processing" + else + pause = 1 + spawn(25) + dish.loc = src.loc + dish = null + + src.state("\The [src] buzzes, \"Insufficient growth density to complete analysis.\"") + pause = 0 + return diff --git a/code/modules/virus2/antibodies.dm b/code/modules/virus2/antibodies.dm new file mode 100644 index 00000000..cecb0709 --- /dev/null +++ b/code/modules/virus2/antibodies.dm @@ -0,0 +1,26 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +var/global/list/ALL_ANTIGENS = list( + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" + ) + +/hook/startup/proc/randomise_antigens_order() + ALL_ANTIGENS = shuffle(ALL_ANTIGENS) + return 1 + +// iterate over the list of antigens and see what matches +/proc/antigens2string(list/antigens, none="None") + if(!istype(antigens)) + CRASH("Illegal type!") + if(!antigens.len) + return none + + var/code = "" + for(var/V in ALL_ANTIGENS) + if(V in antigens) + code += V + + if(!code) + return none + + return code diff --git a/code/modules/virus2/antibodyanalyser.dm b/code/modules/virus2/antibodyanalyser.dm new file mode 100644 index 00000000..ec52f7d5 --- /dev/null +++ b/code/modules/virus2/antibodyanalyser.dm @@ -0,0 +1,72 @@ +/obj/machinery/disease2/antibodyanalyser + name = "antibody analyser" + desc = "An advanced machine that analyses pure antibody samples and stores the structure of them on the ExoNet in exchange for cargo points." + icon = 'icons/obj/virology.dmi' + icon_state = "analyser" + anchored = 1 + density = 1 + + var/scanning = 0 + var/pause = 0 + var/list/known_antibodies = list() + + var/obj/item/weapon/reagent_containers/container = null + +/obj/machinery/disease2/antibodyanalyser/update_icon() + if(scanning) + icon_state = "analyser_processing" + else + icon_state = "analyser" + +/obj/machinery/disease2/antibodyanalyser/attackby(var/obj/I as obj, var/mob/user as mob) + if(istype(I,/obj/item/weapon/reagent_containers)) + if(!container && user.unEquip(I)) + container = I + I.forceMove(src) + user.visible_message("[user] adds a sample to \the [src]!", "You add a sample to \the [src]!") + return + +/obj/machinery/disease2/antibodyanalyser/Process() + if(stat & (NOPOWER|BROKEN)) + return + + if(scanning) + scanning -= 1 + if(scanning == 0) + if(!container.reagents.has_reagent(/datum/reagent/antibodies)) //if there are no antibody reagents, return false + return 0 + + else + var/list/data = container.reagents.get_data(/datum/reagent/antibodies) //now that we know there are antibody reagents, get the data + var/list/given_antibodies = data["antibodies"] //now check what specific antibodies it's holding + var/list/common_antibodies = known_antibodies & given_antibodies + var/list/unknown_antibodies = common_antibodies ^ given_antibodies + if(unknown_antibodies.len) + var/payout = unknown_antibodies.len * 45 + supply_controller.add_points_from_source(payout, "virology") + ping("\The [src] pings, \"Successfully uploaded new antibodies to the ExoNet.\"") + known_antibodies |= unknown_antibodies //Add the new antibodies to list + else + src.state("\The [src] buzzes, \"Failed to identify any new antibodies.\"") + if(!given_antibodies.len) //return if no antibodies + return 0 + + container.forceMove(get_turf(src)) + container = null + + update_icon() + + else if(container && !scanning && !pause) + if(container.reagents.has_reagent(/datum/reagent/antibodies)) + scanning = 5 + update_icon() + else + container.forceMove(get_turf(src)) + container = null + + src.state("\The [src] buzzes, \"Failed to identify a pure sample of antibodies in the solution.\"") + return + +/obj/machinery/disease2/antibodyanalyser/Destroy() + QDEL_NULL(container) + . = ..() diff --git a/code/modules/virus2/biohazard destroyer.dm b/code/modules/virus2/biohazard destroyer.dm new file mode 100644 index 00000000..f80dc03e --- /dev/null +++ b/code/modules/virus2/biohazard destroyer.dm @@ -0,0 +1,20 @@ +/obj/machinery/disease2/biodestroyer + name = "Biohazard destroyer" + icon = 'icons/obj/pipes/disposal.dmi' + icon_state = "disposalbio" + var/list/accepts = list(/obj/item/clothing,/obj/item/weapon/virusdish/,/obj/item/weapon/cureimplanter,/obj/item/weapon/diseasedisk,/obj/item/weapon/reagent_containers) + density = 1 + anchored = 1 + +/obj/machinery/disease2/biodestroyer/attackby(var/obj/I as obj, var/mob/user as mob) + for(var/path in accepts) + if(I.type in typesof(path)) + user.drop_item() + qdel(I) + overlays += image('icons/obj/pipes/disposal.dmi', "dispover-handle") + return + user.drop_item() + I.loc = src.loc + + for(var/mob/O in hearers(src, null)) + O.show_message("\icon[src] \The [src] beeps", 2) \ No newline at end of file diff --git a/code/modules/virus2/centrifuge.dm b/code/modules/virus2/centrifuge.dm new file mode 100644 index 00000000..6d0428cf --- /dev/null +++ b/code/modules/virus2/centrifuge.dm @@ -0,0 +1,204 @@ +/obj/machinery/computer/centrifuge + name = "isolation centrifuge" + desc = "Used to separate things with different weights. Spin 'em round, round, right round." + icon = 'icons/obj/virology.dmi' + icon_state = "centrifuge" + var/curing + var/isolating + + var/obj/item/weapon/reagent_containers/glass/beaker/vial/sample = null + var/datum/disease2/disease/virus2 = null + +/obj/machinery/computer/centrifuge/attackby(var/obj/O as obj, var/mob/user as mob) + if(isScrewdriver(O)) + return ..(O,user) + + if(istype(O,/obj/item/weapon/reagent_containers/glass/beaker/vial)) + if(sample) + to_chat(user, "\The [src] is already loaded.") + return + + sample = O + user.drop_item() + O.loc = src + + user.visible_message("[user] adds \a [O] to \the [src]!", "You add \a [O] to \the [src]!") + GLOB.nanomanager.update_uis(src) + + src.attack_hand(user) + +/obj/machinery/computer/centrifuge/update_icon() + ..() + if(! (stat & (BROKEN|NOPOWER)) && (isolating || curing)) + icon_state = "centrifuge_moving" + +/obj/machinery/computer/centrifuge/attack_hand(var/mob/user as mob) + if(..()) return + ui_interact(user) + +/obj/machinery/computer/centrifuge/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) + + var/data[0] + data["antibodies"] = null + data["pathogens"] = null + data["is_antibody_sample"] = null + + if (curing) + data["busy"] = "Isolating antibodies..." + else if (isolating) + data["busy"] = "Isolating pathogens..." + else + data["sample_inserted"] = !!sample + + if (sample) + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list + if (B) + data["antibodies"] = antigens2string(B.data["antibodies"], none=null) + + var/list/pathogens[0] + var/list/virus = B.data["virus2"] + for (var/ID in virus) + var/datum/disease2/disease/V = virus[ID] + pathogens.Add(list(list("name" = V.name(), "spread_type" = V.spreadtype, "reference" = "\ref[V]"))) + + if (pathogens.len > 0) + data["pathogens"] = pathogens + + else + var/datum/reagent/antibodies/A = locate(/datum/reagent/antibodies) in sample.reagents.reagent_list + if(A) + data["antibodies"] = antigens2string(A.data["antibodies"], none=null) + data["is_antibody_sample"] = 1 + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "isolation_centrifuge.tmpl", src.name, 400, 500) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/computer/centrifuge/Process() + ..() + if (stat & (NOPOWER|BROKEN)) return + + if (curing) + curing -= 1 + if (curing == 0) + cure() + + if (isolating) + isolating -= 1 + if(isolating == 0) + isolate() + +/obj/machinery/computer/centrifuge/OnTopic(user, href_list) + if (href_list["close"]) + GLOB.nanomanager.close_user_uis(user, src, "main") + return TOPIC_HANDLED + + if (href_list["print"]) + print(user) + return TOPIC_HANDLED + + if(href_list["isolate"]) + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list + if (B) + var/datum/disease2/disease/virus = locate(href_list["isolate"]) + virus2 = virus.getcopy() + isolating = 40 + update_icon() + return TOPIC_REFRESH + + switch(href_list["action"]) + if ("antibody") + var/delay = 20 + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list + if (!B) + state("\The [src] buzzes, \"No antibody carrier detected.\"", "blue") + return TOPIC_HANDLED + + var/has_toxins = locate(/datum/reagent/toxin) in sample.reagents.reagent_list + var/has_radium = sample.reagents.has_reagent(/datum/reagent/radium) + if (has_toxins || has_radium) + state("\The [src] beeps, \"Pathogen purging speed above nominal.\"", "blue") + if (has_toxins) + delay = delay/2 + if (has_radium) + delay = delay/2 + + curing = round(delay) + playsound(src.loc, 'sound/machines/juicer.ogg', 50, 1) + update_icon() + return TOPIC_REFRESH + + if("sample") + if(sample) + sample.dropInto(loc) + sample = null + return TOPIC_REFRESH + +/obj/machinery/computer/centrifuge/proc/cure() + if (!sample) return + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list + if (!B) return + + var/list/data = list("antibodies" = B.data["antibodies"]) + var/amt= sample.reagents.get_reagent_amount(/datum/reagent/blood) + sample.reagents.remove_reagent(/datum/reagent/blood, amt) + sample.reagents.add_reagent(/datum/reagent/antibodies, amt, data) + + GLOB.nanomanager.update_uis(src) + update_icon() + ping("\The [src] pings, \"Antibody isolated.\"") + +/obj/machinery/computer/centrifuge/proc/isolate() + if (!sample) return + var/obj/item/weapon/virusdish/dish = new/obj/item/weapon/virusdish(loc) + dish.virus2 = virus2 + virus2 = null + + GLOB.nanomanager.update_uis(src) + update_icon() + ping("\The [src] pings, \"Pathogen isolated.\"") + +/obj/machinery/computer/centrifuge/proc/print(var/mob/user) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(loc) + P.SetName("paper - Pathology Report") + P.info = {" + [virology_letterhead("Pathology Report")] + Sample: [sample.name]
                +"} + + if (user) + P.info += "Generated By: [user.name]
                " + + P.info += "
                " + + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list + if (B) + P.info += "Antibodies: " + P.info += antigens2string(B.data["antibodies"]) + P.info += "
                " + + var/list/virus = B.data["virus2"] + P.info += "Pathogens:
                " + if (virus.len > 0) + for (var/ID in virus) + var/datum/disease2/disease/V = virus[ID] + P.info += "[V.name()]
                " + else + P.info += "None
                " + + else + var/datum/reagent/antibodies/A = locate(/datum/reagent/antibodies) in sample.reagents.reagent_list + if (A) + P.info += "The following antibodies have been isolated from the blood sample: " + P.info += antigens2string(A.data["antibodies"]) + P.info += "
                " + + P.info += {" +
                + Additional Notes: +"} + + state("The nearby computer prints out a pathology report.") diff --git a/code/modules/virus2/curer.dm b/code/modules/virus2/curer.dm new file mode 100644 index 00000000..7792445e --- /dev/null +++ b/code/modules/virus2/curer.dm @@ -0,0 +1,103 @@ +/obj/machinery/computer/curer + name = "cure research machine" + icon = 'icons/obj/computer.dmi' + icon_keyboard = "med_key" + icon_screen = "dna" + circuit = /obj/item/weapon/circuitboard/curefab + var/curing + var/virusing + + var/obj/item/weapon/reagent_containers/container = null + +/obj/machinery/computer/curer/attackby(var/obj/I as obj, var/mob/user as mob) + if(istype(I,/obj/item/weapon/reagent_containers)) + var/mob/living/carbon/C = user + if(!container) + container = I + C.drop_item() + I.loc = src + return + if(istype(I,/obj/item/weapon/virusdish)) + if(virusing) + to_chat(user, "The pathogen materializer is still recharging..") + return + var/obj/item/weapon/reagent_containers/glass/beaker/product = new(src.loc) + + var/list/data = list("donor" = null, "blood_DNA" = null, "blood_type" = null, "trace_chem" = null, "virus2" = list(), "antibodies" = list()) + data["virus2"] |= I:virus2 + product.reagents.add_reagent(/datum/reagent/blood,30,data) + + virusing = 1 + spawn(1200) virusing = 0 + + state("The [src.name] Buzzes", "blue") + return + ..() + return + +/obj/machinery/computer/curer/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/curer/attack_hand(var/mob/user as mob) + if(..()) + return + user.machine = src + var/dat + if(curing) + dat = "Antibody production in progress" + else if(virusing) + dat = "Virus production in progress" + else if(container) + // see if there's any blood in the container + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in container.reagents.reagent_list + + if(B) + dat = "Blood sample inserted." + dat += "
                Antibodies: [antigens2string(B.data["antibodies"])]" + dat += "
                Begin antibody production" + else + dat += "
                Please check container contents." + dat += "
                Eject container" + else + dat = "Please insert a container." + + user << browse(dat, "window=computer;size=400x500") + onclose(user, "computer") + return + +/obj/machinery/computer/curer/Process() + ..() + + if(stat & (NOPOWER|BROKEN)) + return + use_power(500) + + if(curing) + curing -= 1 + if(curing == 0) + if(container) + createcure(container) + return + +/obj/machinery/computer/curer/OnTopic(user, href_list) + if (href_list["antibody"]) + curing = 10 + . = TOPIC_REFRESH + else if(href_list["eject"]) + container.dropInto(loc) + container = null + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + attack_hand(user) + +/obj/machinery/computer/curer/proc/createcure(var/obj/item/weapon/reagent_containers/container) + var/obj/item/weapon/reagent_containers/glass/beaker/product = new(src.loc) + + var/datum/reagent/blood/B = locate() in container.reagents.reagent_list + + var/list/data = list() + data["antibodies"] = B.data["antibodies"] + product.reagents.add_reagent(/datum/reagent/antibodies,30,data) + + state("\The [src.name] buzzes", "blue") diff --git a/code/modules/virus2/disease2.dm b/code/modules/virus2/disease2.dm new file mode 100644 index 00000000..20a6a5ca --- /dev/null +++ b/code/modules/virus2/disease2.dm @@ -0,0 +1,249 @@ +LEGACY_RECORD_STRUCTURE(virus_records, virus_record) + +/datum/disease2/disease + var/infectionchance = 70 + var/speed = 1 + var/spreadtype = "Contact" // Can also be "Airborne" + var/stage = 1 + var/dead = 0 + var/clicks = 0 + var/uniqueID = 0 + var/list/datum/disease2/effect/effects = list() + var/antigen = list() // 16 bits describing the antigens, when one bit is set, a cure with that bit can dock here + var/max_stage = 4 + var/list/affected_species = list(SPECIES_HUMAN,SPECIES_UNATHI,SPECIES_SKRELL,SPECIES_TAJARA) + +/datum/disease2/disease/New() + uniqueID = rand(0,10000) + ..() + +/datum/disease2/disease/proc/makerandom(var/severity=2) + var/list/excludetypes = list() + for(var/i=1 ; i <= max_stage ; i++ ) + var/datum/disease2/effect/E = get_random_virus2_effect(i, severity, excludetypes) + E.stage = i + if(!E.allow_multiple) + excludetypes += E.type + effects += E + uniqueID = rand(0,10000) + switch(severity) + if(1,2) + infectionchance = rand(10,20) + else + infectionchance = rand(60,90) + + antigen = list(pick(ALL_ANTIGENS)) + antigen |= pick(ALL_ANTIGENS) + spreadtype = prob(70) ? "Airborne" : "Contact" + + if(all_species.len) + affected_species = get_infectable_species() + +/proc/get_infectable_species() + var/list/meat = list() + var/list/res = list() + for (var/specie in all_species) + var/datum/species/S = all_species[specie] + if((S.spawn_flags & SPECIES_CAN_JOIN) && !S.get_virus_immune() && !S.greater_form) + meat += S + if(meat.len) + var/num = rand(1,meat.len) + for(var/i=0,i 50) + if(prob(1)) + majormutate() + + if(prob(mob.virus_immunity()) && prob(stage)) // Increasing chance of curing as the virus progresses + cure(mob,1) + //Waiting out the disease the old way + if(stage == max_stage && clicks > max(stage*100, 300)) + if(prob(mob.virus_immunity() * 0.05 + 100-infectionchance)) + cure(mob, 1) + + var/top_badness = 1 + for(var/datum/disease2/effect/e in effects) + if(e.stage == stage) + top_badness = max(top_badness, e.badness) + + //Space antibiotics might stop disease completely + if(mob.chem_effects[CE_ANTIVIRAL] > top_badness) + if(stage == 1 && prob(20)) + cure(mob) + return + + clicks += speed + //Virus food speeds up disease progress + if(mob.reagents.has_reagent(/datum/reagent/nutriment/virus_food)) + mob.reagents.remove_reagent(/datum/reagent/nutriment/virus_food, REM) + clicks += 10 + + //Moving to the next stage + if(clicks > max(stage*100, 300)) + if(stage < max_stage && prob(10)) + stage++ + clicks = 0 + + //Do nasty effects + for(var/datum/disease2/effect/e in effects) + e.fire(mob,stage) + + //fever + if(!mob.chem_effects[CE_ANTIVIRAL]) + mob.bodytemperature = max(mob.bodytemperature, min(310+5*min(stage,max_stage) ,mob.bodytemperature+5*min(stage,max_stage))) + +/datum/disease2/disease/proc/cure(var/mob/living/carbon/mob, antigen) + for(var/datum/disease2/effect/e in effects) + e.deactivate(mob) + mob.virus2.Remove("[uniqueID]") + if(antigen) + mob.antibodies |= antigen + + BITSET(mob.hud_updateflag, STATUS_HUD) + +/datum/disease2/disease/proc/minormutate() + var/datum/disease2/effect/E = pick(effects) + E.minormutate() + +/datum/disease2/disease/proc/majormutate(badness = VIRUS_ENGINEERED) + uniqueID = rand(0,10000) + var/datum/disease2/effect/E = pick(effects) + var/list/exclude = list() + for(var/datum/disease2/effect/D in effects) + if(D != E) + exclude += D.type + + var/effect_stage = E.stage + E.deactivate() + effects -= E + qdel(E) + + effects += get_random_virus2_effect(effect_stage, badness, exclude) + + if (prob(5)) + antigen = list(pick(ALL_ANTIGENS)) + antigen |= pick(ALL_ANTIGENS) + + if (prob(5) && all_species.len) + affected_species = get_infectable_species() + +/datum/disease2/disease/proc/getcopy() + var/datum/disease2/disease/disease = new /datum/disease2/disease + disease.infectionchance = infectionchance + disease.spreadtype = spreadtype + disease.speed = speed + disease.antigen = antigen + disease.uniqueID = uniqueID + disease.affected_species = affected_species.Copy() + for(var/datum/disease2/effect/effect in effects) + var/datum/disease2/effect/neweffect = new effect.type + neweffect.generate(effect.data) + neweffect.chance = effect.chance + neweffect.multiplier = effect.multiplier + neweffect.oneshot = effect.oneshot + neweffect.stage = effect.stage + disease.effects += neweffect + return disease + +/datum/disease2/disease/proc/issame(var/datum/disease2/disease/disease) + . = 1 + + var/list/types = list() + for(var/datum/disease2/effect/d in effects) + types += d.type + for(var/datum/disease2/effect/d in disease.effects) + if(!(d.type in types)) + return 0 + + if (antigen != disease.antigen) + return 0 + +/proc/virus_copylist(var/list/datum/disease2/disease/viruses) + var/list/res = list() + for (var/ID in viruses) + var/datum/disease2/disease/V = viruses[ID] + res["[V.uniqueID]"] = V.getcopy() + return res + + +var/global/list/virusDB = list() + +/datum/disease2/disease/proc/name() + .= "strain #[add_zero("[uniqueID]", 4)]" + if ("[uniqueID]" in virusDB) + var/datum/computer_file/data/virus_record/V = virusDB["[uniqueID]"] + .= V.fields["name"] + +/datum/disease2/disease/proc/get_basic_info() + var/t = "" + for(var/datum/disease2/effect/E in effects) + t += ", [E.name]" + return "[name()] ([copytext(t,3)])" + +/datum/disease2/disease/proc/get_info() + var/r = {" + Analysis determined the existence of a GNAv2-based viral lifeform.
                + Designation: [name()]
                + Antigen: [antigens2string(antigen)]
                + Transmitted By: [spreadtype]
                + Rate of Progression: [speed * 100]%
                + Species Affected: [jointext(affected_species, ", ")]
                +"} + + r += "Symptoms:
                " + for(var/datum/disease2/effect/E in effects) + r += "([E.stage]) [E.name] " + r += "Strength: [E.multiplier >= 3 ? "Severe" : E.multiplier > 1 ? "Above Average" : "Average"] " + r += "Verosity: [E.chance * 15]
                " + + return r + +/datum/disease2/disease/proc/addToDB() + if ("[uniqueID]" in virusDB) + return 0 + var/datum/computer_file/data/virus_record/v = new() + v.fields["id"] = uniqueID + v.fields["name"] = name() + v.fields["description"] = get_info() + v.fields["antigen"] = antigens2string(antigen) + v.fields["spread type"] = spreadtype + virusDB["[uniqueID]"] = v + return 1 + + +proc/virology_letterhead(var/report_name) + return {" +

                [report_name]

                +
                [station_name()] Virology Lab
                +
                +"} + +/datum/disease2/disease/proc/can_add_symptom(type) + for(var/datum/disease2/effect/H in effects) + if(H.type == type && !H.allow_multiple) + return 0 + + return 1 diff --git a/code/modules/virus2/diseasesplicer.dm b/code/modules/virus2/diseasesplicer.dm new file mode 100644 index 00000000..bf6791fc --- /dev/null +++ b/code/modules/virus2/diseasesplicer.dm @@ -0,0 +1,188 @@ +/obj/machinery/computer/diseasesplicer + name = "disease splicer" + icon = 'icons/obj/computer.dmi' + icon_keyboard = "med_key" + icon_screen = "crew" + + var/datum/disease2/effect/memorybank = null + var/list/species_buffer = null + var/analysed = 0 + var/obj/item/weapon/virusdish/dish = null + var/burning = 0 + var/splicing = 0 + var/scanning = 0 + +/obj/machinery/computer/diseasesplicer/attackby(var/obj/I as obj, var/mob/user as mob) + if(isScrewdriver(I)) + return ..(I,user) + + if(istype(I,/obj/item/weapon/virusdish)) + var/mob/living/carbon/c = user + if (dish) + to_chat(user, "\The [src] is already loaded.") + return + + dish = I + c.drop_item() + I.loc = src + + if(istype(I,/obj/item/weapon/diseasedisk)) + to_chat(user, "You upload the contents of the disk onto the buffer.") + var/obj/item/weapon/diseasedisk/disk = I + memorybank = disk.effect + species_buffer = disk.species + analysed = disk.analysed + + src.attack_hand(user) + +/obj/machinery/computer/diseasesplicer/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/diseasesplicer/attack_hand(var/mob/user as mob) + if(..()) return + ui_interact(user) + +/obj/machinery/computer/diseasesplicer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) + + var/data[0] + data["dish_inserted"] = !!dish + data["growth"] = 0 + data["affected_species"] = null + + if (memorybank) + data["buffer"] = list("name" = (analysed ? memorybank.name : "Unknown Symptom"), "stage" = memorybank.stage) + if (species_buffer) + data["species_buffer"] = analysed ? jointext(species_buffer, ", ") : "Unknown Species" + + if (splicing) + data["busy"] = "Splicing..." + else if (scanning) + data["busy"] = "Scanning..." + else if (burning) + data["busy"] = "Copying data to disk..." + else if (dish) + data["growth"] = min(dish.growth, 100) + + if (dish.virus2) + if (dish.virus2.affected_species) + data["affected_species"] = dish.analysed ? jointext(dish.virus2.affected_species, ", ") : "Unknown" + + if (dish.growth >= 50) + var/list/effects[0] + for (var/datum/disease2/effect/e in dish.virus2.effects) + effects.Add(list(list("name" = (dish.analysed ? e.name : "Unknown"), "stage" = (e.stage), "reference" = "\ref[e]"))) + data["effects"] = effects + else + data["info"] = "Insufficient cell growth for gene splicing." + else + data["info"] = "No virus detected." + else + data["info"] = "No dish loaded." + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "disease_splicer.tmpl", src.name, 400, 600) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/computer/diseasesplicer/Process() + if(stat & (NOPOWER|BROKEN)) + return + + if(scanning) + scanning -= 1 + if(!scanning) + ping("\The [src] pings, \"Analysis complete.\"") + GLOB.nanomanager.update_uis(src) + if(splicing) + splicing -= 1 + if(!splicing) + ping("\The [src] pings, \"Splicing operation complete.\"") + GLOB.nanomanager.update_uis(src) + if(burning) + burning -= 1 + if(!burning) + var/obj/item/weapon/diseasedisk/d = new /obj/item/weapon/diseasedisk(src.loc) + d.analysed = analysed + if(analysed) + if (memorybank) + d.SetName("[memorybank.name] GNA disk (Stage: [memorybank.stage])") + d.effect = memorybank + else if (species_buffer) + d.SetName("[jointext(species_buffer, ", ")] GNA disk") + d.species = species_buffer + else + if (memorybank) + d.SetName("Unknown GNA disk (Stage: [memorybank.stage])") + d.effect = memorybank + else if (species_buffer) + d.SetName("Unknown Species GNA disk") + d.species = species_buffer + + ping("\The [src] pings, \"Backup disk saved.\"") + GLOB.nanomanager.update_uis(src) + +/obj/machinery/computer/diseasesplicer/OnTopic(user, href_list) + if (href_list["close"]) + GLOB.nanomanager.close_user_uis(user, src, "main") + return TOPIC_HANDLED + + if (href_list["grab"]) + if (dish) + memorybank = locate(href_list["grab"]) + species_buffer = null + analysed = dish.analysed + dish = null + scanning = 10 + return TOPIC_REFRESH + + if (href_list["affected_species"]) + if (dish) + memorybank = null + species_buffer = dish.virus2.affected_species + analysed = dish.analysed + dish = null + scanning = 10 + return TOPIC_REFRESH + + if(href_list["eject"]) + if (dish) + dish.dropInto(loc) + dish = null + return TOPIC_REFRESH + + if(href_list["splice"]) + if(dish) + var/target = text2num(href_list["splice"]) // target = 1+ for effects, -1 for species + if(memorybank && target > 0) + if(target < memorybank.stage) + return // too powerful, catching this for href exploit prevention + + var/datum/disease2/effect/target_effect + var/list/illegal_types = list() + for(var/datum/disease2/effect/e in dish.virus2.effects) + if(e.stage == target) + target_effect = e + if(!e.allow_multiple) + illegal_types += e.type + if(memorybank.type in illegal_types) + to_chat(user, "Virus DNA can't hold more than one [memorybank]") + return 1 + dish.virus2.effects -= target_effect + dish.virus2.effects += memorybank + qdel(target_effect) + + else if(species_buffer && target == -1) + dish.virus2.affected_species = species_buffer + + else + return TOPIC_HANDLED + + splicing = 10 + dish.virus2.uniqueID = rand(0,10000) + return TOPIC_REFRESH + + if(href_list["disk"]) + burning = 10 + return TOPIC_REFRESH diff --git a/code/modules/virus2/dishincubator.dm b/code/modules/virus2/dishincubator.dm new file mode 100644 index 00000000..0abd1dd9 --- /dev/null +++ b/code/modules/virus2/dishincubator.dm @@ -0,0 +1,196 @@ +/obj/machinery/disease2/incubator/ + name = "pathogenic incubator" + density = 1 + anchored = 1 + icon = 'icons/obj/virology.dmi' + icon_state = "incubator" + var/obj/item/weapon/virusdish/dish + var/obj/item/weapon/reagent_containers/glass/beaker = null + var/radiation = 0 + + var/on = 0 + var/power = 0 + + var/foodsupply = 0 + var/toxins = 0 + +/obj/machinery/disease2/incubator/attackby(var/obj/O as obj, var/mob/user as mob) + if(istype(O, /obj/item/weapon/reagent_containers/glass) || istype(O,/obj/item/weapon/reagent_containers/syringe)) + + if(beaker) + to_chat(user, "\The [src] is already loaded.") + return + + beaker = O + user.drop_item() + O.loc = src + + user.visible_message("[user] adds \a [O] to \the [src]!", "You add \a [O] to \the [src]!") + GLOB.nanomanager.update_uis(src) + + src.attack_hand(user) + return + + if(istype(O, /obj/item/weapon/virusdish)) + + if(dish) + to_chat(user, "The dish tray is aleady full!") + return + + dish = O + user.drop_item() + O.loc = src + + user.visible_message("[user] adds \a [O] to \the [src]!", "You add \a [O] to \the [src]!") + GLOB.nanomanager.update_uis(src) + + src.attack_hand(user) + +/obj/machinery/disease2/incubator/attack_hand(mob/user as mob) + if(stat & (NOPOWER|BROKEN)) return + ui_interact(user) + +/obj/machinery/disease2/incubator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) + + var/data[0] + data["chemicals_inserted"] = !!beaker + data["dish_inserted"] = !!dish + data["food_supply"] = foodsupply + data["radiation"] = radiation + data["toxins"] = min(toxins, 100) + data["on"] = on + data["system_in_use"] = foodsupply > 0 || radiation > 0 || toxins > 0 + data["chemical_volume"] = beaker ? beaker.reagents.total_volume : 0 + data["max_chemical_volume"] = beaker ? beaker.volume : 1 + data["virus"] = dish ? dish.virus2 : null + data["growth"] = dish ? min(dish.growth, 100) : 0 + data["infection_rate"] = dish && dish.virus2 ? dish.virus2.infectionchance * 10 : 0 + data["analysed"] = dish && dish.analysed ? 1 : 0 + data["can_breed_virus"] = null + data["blood_already_infected"] = null + + if (beaker) + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in beaker.reagents.reagent_list + data["can_breed_virus"] = dish && dish.virus2 && B + + if (B) + if (!B.data["virus2"]) + B.data["virus2"] = list() + + var/list/virus = B.data["virus2"] + for (var/ID in virus) + data["blood_already_infected"] = virus[ID] + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "dish_incubator.tmpl", src.name, 400, 600) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/disease2/incubator/Process() + if(dish && on && dish.virus2) + use_power(50,EQUIP) + if(!powered(EQUIP)) + on = 0 + icon_state = "incubator" + + if(foodsupply) + if(dish.growth + 3 >= 100 && dish.growth < 100) + ping("\The [src] pings, \"Sufficient viral growth density achieved.\"") + + foodsupply -= 1 + dish.growth += 3 + GLOB.nanomanager.update_uis(src) + + if(radiation) + if(radiation > 50 & prob(5)) + dish.virus2.majormutate() + if(dish.info) + dish.info = "OUTDATED : [dish.info]" + dish.basic_info = "OUTDATED: [dish.basic_info]" + dish.analysed = 0 + ping("\The [src] pings, \"Mutant viral strain detected.\"") + else if(prob(5)) + dish.virus2.minormutate() + radiation -= 1 + GLOB.nanomanager.update_uis(src) + if(toxins && prob(5)) + dish.virus2.infectionchance -= 1 + GLOB.nanomanager.update_uis(src) + if(toxins > 50) + dish.growth = 0 + dish.virus2 = null + GLOB.nanomanager.update_uis(src) + else if(!dish) + on = 0 + icon_state = "incubator" + GLOB.nanomanager.update_uis(src) + + if(beaker) + if(foodsupply < 100 && beaker.reagents.remove_reagent(/datum/reagent/nutriment/virus_food,5)) + if(foodsupply + 10 <= 100) + foodsupply += 10 + else + beaker.reagents.add_reagent(/datum/reagent/nutriment/virus_food,(100 - foodsupply)/2) + foodsupply = 100 + GLOB.nanomanager.update_uis(src) + + if (locate(/datum/reagent/toxin) in beaker.reagents.reagent_list && toxins < 100) + for(var/datum/reagent/toxin/T in beaker.reagents.reagent_list) + toxins += max(T.strength,1) + beaker.reagents.remove_reagent(T.type,1) + if(toxins > 100) + toxins = 100 + break + GLOB.nanomanager.update_uis(src) + +/obj/machinery/disease2/incubator/OnTopic(user, href_list) + if (href_list["close"]) + GLOB.nanomanager.close_user_uis(user, src, "main") + return TOPIC_HANDLED + + if (href_list["ejectchem"]) + if(beaker) + beaker.dropInto(loc) + beaker = null + return TOPIC_REFRESH + + if (href_list["power"]) + if (dish) + on = !on + icon_state = on ? "incubator_on" : "incubator" + return TOPIC_REFRESH + + if (href_list["ejectdish"]) + if(dish) + dish.dropInto(loc) + dish = null + return TOPIC_REFRESH + + if (href_list["rad"]) + radiation = min(100, radiation + 10) + return TOPIC_REFRESH + + if (href_list["flush"]) + radiation = 0 + toxins = 0 + foodsupply = 0 + return TOPIC_REFRESH + + if(href_list["virus"]) + if (!dish) + return TOPIC_HANDLED + + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in beaker.reagents.reagent_list + if (!B) + return TOPIC_HANDLED + + if (!B.data["virus2"]) + B.data["virus2"] = list() + + var/list/virus = list("[dish.virus2.uniqueID]" = dish.virus2.getcopy()) + B.data["virus2"] += virus + + ping("\The [src] pings, \"Injection complete.\"") + return TOPIC_REFRESH diff --git a/code/modules/virus2/effect.dm b/code/modules/virus2/effect.dm new file mode 100644 index 00000000..19d45c85 --- /dev/null +++ b/code/modules/virus2/effect.dm @@ -0,0 +1,394 @@ +//////////////////////////////////////////////////////////////// +////////////////////////EFFECTS///////////////////////////////// +//////////////////////////////////////////////////////////////// +/proc/get_random_virus2_effect(stage, badness, exclude) + var/list/datum/disease2/effect/candidates = list() + for(var/T in subtypesof(/datum/disease2/effect)) + var/datum/disease2/effect/E = T + if(E in exclude) + continue + if(initial(E.badness) > badness) //we don't want such strong effects + continue + if(initial(E.stage) <= stage) + candidates += T + var/type = pick(candidates) + var/datum/disease2/effect/effect = new type + effect.generate() + effect.chance = rand(0,effect.chance_max) + effect.multiplier = rand(1,effect.multiplier_max) + return effect + +/datum/disease2/effect + var/name = "Blanking effect" + var/chance //probality to fire every tick + var/chance_max = 50 + var/multiplier = 1 //effect magnitude multiplier + var/multiplier_max = 1 + var/stage = 4 //minimal stage + var/badness = VIRUS_MILD //Used in random generation to limit how bad result should come out. + var/data = null //For semi-procedural effects; this should be generated in generate() if used + var/oneshot + var/delay = 5 SECONDS //minimal time between activations + var/hold_until //can only fire after this worldtime + var/allow_multiple //allow to have more than 1 effect of this type in the same virus + +/datum/disease2/effect/proc/fire(var/mob/living/carbon/human/mob,var/current_stage) + if(oneshot == -1) + return + if(hold_until > world.time) + return + if(mob.chem_effects[CE_ANTIVIRAL] >= badness) + return + if(stage <= current_stage && prob(chance)) + hold_until = world.time + delay + activate(mob) + if(oneshot == 1) + oneshot = -1 + +/datum/disease2/effect/proc/minormutate() + switch(pick(1,2,3,4,5)) + if(1) + chance = rand(0,chance_max) + if(2) + multiplier = rand(1,multiplier_max) + +/datum/disease2/effect/proc/activate(var/mob/living/carbon/human/mob) +/datum/disease2/effect/proc/deactivate(var/mob/living/carbon/human/mob) +/datum/disease2/effect/proc/generate(copy_data) // copy_data will be non-null if this is a copy; it should be used to initialise the data for this effect if present + +/datum/disease2/effect/invisible + name = "Waiting Syndrome" + stage = 1 + +////////////////////////STAGE 4///////////////////////////////// + +/datum/disease2/effect/gibbingtons + name = "Gibbingtons Syndrome" + stage = 4 + badness = VIRUS_EXOTIC + activate(var/mob/living/carbon/human/mob,var/multiplier) + // Probabilities have been tweaked to kill in ~2-3 minutes, giving 5-10 messages. + // Probably needs more balancing, but it's better than LOL U GIBBED NOW, especially now that viruses can potentially have no signs up until Gibbingtons. + mob.adjustBruteLoss(10*multiplier) + var/obj/item/organ/external/O = pick(mob.organs) + if(prob(25)) + to_chat(mob, "Your [O.name] feels as if it might burst!") + if(prob(10)) + spawn(50) + if(O) + O.droplimb(0,DROPLIMB_BLUNT) + +/datum/disease2/effect/radian + name = "Radian's Syndrome" + stage = 4 + multiplier_max = 3 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.apply_effect(2*multiplier, IRRADIATE, blocked = 0) + +/datum/disease2/effect/deaf + name = "Dead Ear Syndrome" + stage = 4 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.ear_deaf += 20 + +/datum/disease2/effect/monkey + name = "Two Percent Syndrome" + stage = 4 + badness = VIRUS_EXOTIC + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.monkeyize() + +/datum/disease2/effect/killertoxins + name = "Toxification Syndrome" + stage = 4 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.adjustToxLoss(15*multiplier) + +/datum/disease2/effect/dna + name = "Reverse Pattern Syndrome" + stage = 4 + badness = VIRUS_ENGINEERED + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.bodytemperature = max(mob.bodytemperature, 350) + scramble(0,mob,10) + mob.apply_damage(10, CLONE) + +/datum/disease2/effect/organs + name = "Shutdown Syndrome" + stage = 4 + badness = VIRUS_ENGINEERED + activate(var/mob/living/carbon/human/mob,var/multiplier) + var/organ = pick(list(BP_R_ARM,BP_L_ARM,BP_R_LEG,BP_L_LEG)) + var/obj/item/organ/external/E = mob.organs_by_name[organ] + if (!(E.status & ORGAN_DEAD)) + E.status |= ORGAN_DEAD + to_chat(mob, "You can't feel your [E.name] anymore...") + for (var/obj/item/organ/external/C in E.children) + C.status |= ORGAN_DEAD + mob.update_body(1) + mob.adjustToxLoss(15*multiplier) + + deactivate(var/mob/living/carbon/human/mob,var/multiplier) + for (var/obj/item/organ/external/E in mob.organs) + E.status &= ~ORGAN_DEAD + for (var/obj/item/organ/external/C in E.children) + C.status &= ~ORGAN_DEAD + mob.update_body(1) + +/datum/disease2/effect/immortal + name = "Longevity Syndrome" + stage = 4 + badness = VIRUS_ENGINEERED + activate(var/mob/living/carbon/human/mob,var/multiplier) + for (var/obj/item/organ/external/E in mob.organs) + if (E.status & ORGAN_BROKEN && prob(30)) + to_chat(mob, "Your [E.name] suddenly feels much better!") + E.status ^= ORGAN_BROKEN + break + for (var/obj/item/organ/internal/I in mob.internal_organs) + if (I.damage && prob(30)) + to_chat(mob, "Your [mob.get_organ(I.parent_organ)] feels a bit warm...") + I.take_damage(-2*multiplier) + break + var/heal_amt = -5*multiplier + mob.apply_damages(heal_amt,heal_amt,heal_amt,heal_amt) + + deactivate(var/mob/living/carbon/human/mob,var/multiplier) + to_chat(mob, "You suddenly feel hurt and old...") + mob.age += 8 + var/backlash_amt = 5*multiplier + mob.apply_damages(backlash_amt,backlash_amt,backlash_amt,backlash_amt) + +/datum/disease2/effect/bones + name = "Fragile Bones Syndrome" + stage = 4 + badness = VIRUS_ENGINEERED + activate(var/mob/living/carbon/human/mob,var/multiplier) + for (var/obj/item/organ/external/E in mob.organs) + E.min_broken_damage = max(5, E.min_broken_damage - 30) + + deactivate(var/mob/living/carbon/human/mob,var/multiplier) + for (var/obj/item/organ/external/E in mob.organs) + E.min_broken_damage = initial(E.min_broken_damage) + +////////////////////////STAGE 3///////////////////////////////// + +/datum/disease2/effect/toxins + name = "Hyperacidity" + stage = 3 + multiplier_max = 3 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.adjustToxLoss((2*multiplier)) + +/datum/disease2/effect/shakey + name = "World Shaking Syndrome" + stage = 3 + multiplier_max = 3 + activate(var/mob/living/carbon/human/mob,var/multiplier) + shake_camera(mob,5*multiplier) + +/datum/disease2/effect/telepathic + name = "Telepathy Syndrome" + stage = 3 + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.dna.SetSEState(GLOB.REMOTETALKBLOCK,1) + domutcheck(mob, null, MUTCHK_FORCED) + +/datum/disease2/effect/mind + name = "Lazy Mind Syndrome" + stage = 3 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + var/obj/item/organ/internal/brain/B = mob.internal_organs_by_name[BP_BRAIN] + if (B && B.damage < B.min_broken_damage) + B.take_damage(5) + +/datum/disease2/effect/deaf + name = "Hard of Hearing Syndrome" + stage = 3 + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.ear_deaf = 5 + +/datum/disease2/effect/confusion + name = "Topographical Cretinism" + stage = 3 + activate(var/mob/living/carbon/human/mob,var/multiplier) + to_chat(mob, "You have trouble telling right and left apart all of a sudden.") + mob.confused += 10 + +/datum/disease2/effect/mutation + name = "DNA Degradation" + stage = 3 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.apply_damage(2, CLONE) + +/datum/disease2/effect/chem_synthesis + name = "Chemical Synthesis" + stage = 3 + badness = VIRUS_COMMON + chance_max = 25 + + generate(c_data) + if(c_data) + data = c_data + else + data = pick(/datum/reagent/bicaridine, /datum/reagent/kelotane, /datum/reagent/dylovene, /datum/reagent/inaprovaline, /datum/reagent/space_drugs, /datum/reagent/sugar, + /datum/reagent/tramadol, /datum/reagent/dexalin, /datum/reagent/cryptobiolin, /datum/reagent/impedrezene, /datum/reagent/hyperzine, /datum/reagent/ethylredoxrazine, + /datum/reagent/mindbreaker, /datum/reagent/nutriment/glucose) + var/datum/reagent/R = data + name = "[initial(name)] ([initial(R.name)])" + + activate(var/mob/living/carbon/human/mob,var/multiplier) + if (mob.reagents.get_reagent_amount(data) < 5) + mob.reagents.add_reagent(data, 2) + +/datum/disease2/effect/nothing + name = "Nil Syndrome" + stage = 1 + badness = VIRUS_MILD + chance_max = 0 + allow_multiple = 1 + +////////////////////////STAGE 2///////////////////////////////// +/datum/disease2/effect/drowsness + name = "Automated Sleeping Syndrome" + stage = 2 + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.drowsyness += 10 + +/datum/disease2/effect/sleepy + name = "Resting Syndrome" + stage = 2 + chance_max = 15 + delay = 35 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.emote("collapse") + +/datum/disease2/effect/blind + name = "Blackout Syndrome" + stage = 2 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.eye_blind = max(mob.eye_blind, 4) + +/datum/disease2/effect/cough + name = "Anima Syndrome" + stage = 2 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.emote("cough") + if (mob.wear_mask) + return + for(var/mob/living/carbon/human/M in oview(2,mob)) + mob.spread_disease_to(M) + +/datum/disease2/effect/hungry + name = "Appetiser Effect" + stage = 2 + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.nutrition = max(0, mob.nutrition - 200) + +/datum/disease2/effect/fridge + name = "Refridgerator Syndrome" + stage = 2 + chance_max = 25 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.emote("shiver") + +/datum/disease2/effect/hair + name = "Hair Loss" + stage = 2 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + if(mob.species.name == SPECIES_HUMAN && !(mob.h_style == "Bald") && !(mob.h_style == "Balding Hair")) + to_chat(mob, "Your hair starts to fall out in clumps...") + spawn(50) + mob.h_style = "Balding Hair" + mob.update_hair() + +/datum/disease2/effect/stimulant + name = "Adrenaline Extra" + stage = 2 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + to_chat(mob, "You feel a rush of energy inside you!") + if (mob.reagents.get_reagent_amount(/datum/reagent/hyperzine) < 10) + mob.reagents.add_reagent(/datum/reagent/hyperzine, 4) + if (prob(30)) + mob.jitteriness += 10 + +////////////////////////STAGE 1///////////////////////////////// + +/datum/disease2/effect/sneeze + name = "Coldingtons Effect" + stage = 1 + delay = 15 SECONDS + + activate(var/mob/living/carbon/human/mob,var/multiplier) + if (prob(30)) + to_chat(mob, "You feel like you are about to sneeze!") + sleep(5) + mob.emote("sneeze") + for(var/mob/living/carbon/human/M in get_step(mob,mob.dir)) + mob.spread_disease_to(M) + if (prob(50) && !mob.wear_mask) + var/obj/effect/decal/cleanable/mucus/M = new(get_turf(mob)) + M.virus2 = virus_copylist(mob.virus2) + +/datum/disease2/effect/gunck + name = "Flemmingtons" + stage = 1 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + to_chat(mob, "Mucous runs down the back of your throat.") + +/datum/disease2/effect/drool + name = "Saliva Effect" + stage = 1 + chance_max = 25 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.emote("drool") + +/datum/disease2/effect/twitch + name = "Twitcher" + stage = 1 + chance_max = 25 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.emote("twitch") + +/datum/disease2/effect/headache + name = "Headache" + stage = 1 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.custom_pain("Your head hurts a bit.", 20) + +/datum/disease2/effect/itch + name = "Itches" + stage = 1 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + var/obj/O = pick(mob.organs) + to_chat(mob, "Your [O.name] itches like hell.") + +/datum/disease2/effect/stomach + name = "Upset stomach" + stage = 1 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + to_chat(mob, "Your stomach feels heavy.") + +/datum/disease2/effect/stealth + name = "Silent Death Syndrome" + stage = 1 + badness = VIRUS_EXOTIC + chance_max = 0 + allow_multiple = 1 \ No newline at end of file diff --git a/code/modules/virus2/helpers.dm b/code/modules/virus2/helpers.dm new file mode 100644 index 00000000..e8b330d2 --- /dev/null +++ b/code/modules/virus2/helpers.dm @@ -0,0 +1,180 @@ +//Returns 1 if mob can be infected, 0 otherwise. +proc/infection_chance(var/mob/living/carbon/M, var/vector = "Airborne") + if (!istype(M)) + return 0 + + var/mob/living/carbon/human/H = M + if(istype(H) && H.species.get_virus_immune(H)) + return 0 + + var/protection = M.getarmor(null, "bio") //gets the full body bio armour value, weighted by body part coverage. + var/score = round(0.06*protection) //scales 100% protection to 6. + + switch(vector) + if("Airborne") + if(M.internal) //not breathing infected air helps greatly + return 0 + var/obj/item/I = M.wear_mask + //masks provide a small bonus and can replace overall bio protection + if(I) + score = max(score, round(0.06*I.armor["bio"])) + if (istype(I, /obj/item/clothing/mask)) + score += 1 //this should be added after + + if("Contact") + if(istype(H)) + //gloves provide a larger bonus + if (istype(H.gloves, /obj/item/clothing/gloves)) + score += 2 + + switch(score) + if (6 to INFINITY) + return 0 + if (5) + return 1 + if (4) + return 5 + if (3) + return 25 + if (2) + return 45 + if (1) + return 65 + else + return 100 + +//Similar to infection check, but used for when M is spreading the virus. +/proc/infection_spreading_check(var/mob/living/carbon/M, var/vector = "Airborne") + if (!istype(M)) + return 0 + + var/protection = M.getarmor(null, "bio") //gets the full body bio armour value, weighted by body part coverage. + + if (vector == "Airborne") //for airborne infections face-covering items give non-weighted protection value. + if(M.internal) + return 1 + protection = max(protection, M.getarmor(FACE, "bio")) + + return prob(protection + 15*M.chem_effects[CE_ANTIVIRAL]) + +/proc/airborne_can_reach(turf/simulated/source, turf/simulated/target) + //Can't ariborne without air + if(is_below_sound_pressure(source) || is_below_sound_pressure(target)) + return FALSE + //no infecting from other side of the hallway + if(get_dist(source,target) > 5) + return FALSE + if(istype(source) && istype(target)) + return source.zone == target.zone + +//Attemptes to infect mob M with virus. Set forced to 1 to ignore protective clothnig +/proc/infect_virus2(var/mob/living/carbon/M,var/datum/disease2/disease/disease,var/forced = 0) + if(!istype(disease)) +// log_debug("Bad virus") + return + if(!istype(M)) +// log_debug("Bad mob") + return + if ("[disease.uniqueID]" in M.virus2) + return + // if one of the antibodies in the mob's body matches one of the disease's antigens, don't infect + var/list/antibodies_in_common = M.antibodies & disease.antigen + if(antibodies_in_common.len) + return + if(prob(100 * M.reagents.get_reagent_amount(/datum/reagent/spaceacillin) / (REAGENTS_OVERDOSE/2))) + return + + if(!disease.affected_species.len) + return + + if (!(M.species.get_bodytype(M) in disease.affected_species)) + if (forced) + disease.affected_species[1] = M.species.get_bodytype(M) + else + return //not compatible with this species + +// log_debug("Infecting [M]") + var/mob_infection_prob = infection_chance(M, disease.spreadtype) * M.immunity_weakness() + if(forced || (prob(disease.infectionchance) && prob(mob_infection_prob))) + var/datum/disease2/disease/D = disease.getcopy() + D.minormutate() +// log_debug("Adding virus") + M.virus2["[D.uniqueID]"] = D + BITSET(M.hud_updateflag, STATUS_HUD) + +//Infects mob M with random lesser disease, if he doesn't have one +/proc/infect_mob_random_lesser(var/mob/living/carbon/M) + var/datum/disease2/disease/D = new /datum/disease2/disease + + D.makerandom(VIRUS_MILD) + infect_virus2(M, D, 1) + +//Infects mob M with random greated disease, if he doesn't have one +/proc/infect_mob_random_greater(var/mob/living/carbon/M) + var/datum/disease2/disease/D = new /datum/disease2/disease + + D.makerandom(VIRUS_COMMON) + infect_virus2(M, D, 1) + +//Fancy prob() function. +/proc/dprob(var/p) + return(prob(sqrt(p)) && prob(sqrt(p))) + +/mob/living/carbon/proc/spread_disease_to(var/mob/living/carbon/victim, var/vector = "Airborne") + if (src == victim) + return "retardation" + +// log_debug("Spreading [vector] diseases from [src] to [victim]") + if (virus2.len > 0) + for (var/ID in virus2) +// log_debug("Attempting virus [ID]") + var/datum/disease2/disease/V = virus2[ID] + if(V.spreadtype != vector) continue + + //It's hard to get other people sick if you're in an airtight suit. + if(!infection_spreading_check(src, V.spreadtype)) continue + + if (vector == "Airborne") + if(airborne_can_reach(get_turf(src), get_turf(victim))) +// log_debug("In range, infecting") + infect_virus2(victim,V) +// else +// log_debug("Could not reach target") + + if (vector == "Contact") + if (Adjacent(victim)) +// log_debug("In range, infecting") + infect_virus2(victim,V) + + //contact goes both ways + if (victim.virus2.len > 0 && vector == "Contact" && Adjacent(victim)) +// log_debug("Spreading [vector] diseases from [victim] to [src]") + var/nudity = 1 + + if (ishuman(victim)) + var/mob/living/carbon/human/H = victim + + //Allow for small chance of touching other zones. + //This is proc is also used for passive spreading so just because they are targeting + //that zone doesn't mean that's necessarily where they will touch. + var/touch_zone = zone_sel ? zone_sel.selecting : "chest" + touch_zone = ran_zone(touch_zone, 80) + var/obj/item/organ/external/select_area = H.get_organ(touch_zone) + if(!select_area) + //give it one more chance, since this is also called for passive spreading + select_area = H.get_organ(ran_zone()) + + if(!select_area) + nudity = 0 //cant contact a missing body part + else + var/list/clothes = list(H.head, H.wear_mask, H.wear_suit, H.w_uniform, H.gloves, H.shoes) + for(var/obj/item/clothing/C in clothes) + if(C && istype(C)) + if(C.body_parts_covered & select_area.body_part) + nudity = 0 + if (nudity) + for (var/ID in victim.virus2) + var/datum/disease2/disease/V = victim.virus2[ID] + if(V && V.spreadtype != vector) continue + if(!infection_spreading_check(victim, V.spreadtype)) continue + infect_virus2(src,V) diff --git a/code/modules/virus2/isolator.dm b/code/modules/virus2/isolator.dm new file mode 100644 index 00000000..4d50a5ce --- /dev/null +++ b/code/modules/virus2/isolator.dm @@ -0,0 +1,227 @@ +// UI menu navigation +#define HOME "home" +#define LIST "list" +#define ENTRY "entry" + +/obj/machinery/disease2/isolator/ + name = "pathogenic isolator" + density = 1 + anchored = 1 + icon = 'icons/obj/virology.dmi' + icon_state = "isolator" + var/isolating = 0 + var/state = HOME + var/datum/disease2/disease/virus2 = null + var/datum/computer_file/data/virus_record/entry = null + var/obj/item/weapon/reagent_containers/syringe/sample = null + +/obj/machinery/disease2/isolator/update_icon() + if (stat & (BROKEN|NOPOWER)) + icon_state = "isolator" + return + + if (isolating) + icon_state = "isolator_processing" + else if (sample) + icon_state = "isolator_in" + else + icon_state = "isolator" + +/obj/machinery/disease2/isolator/attackby(var/obj/O as obj, var/mob/user) + if(!istype(O,/obj/item/weapon/reagent_containers/syringe)) return + var/obj/item/weapon/reagent_containers/syringe/S = O + + if(sample) + to_chat(user, "\The [src] is already loaded.") + return + + sample = S + user.drop_item() + S.loc = src + + user.visible_message("[user] adds \a [O] to \the [src]!", "You add \a [O] to \the [src]!") + GLOB.nanomanager.update_uis(src) + update_icon() + + src.attack_hand(user) + +/obj/machinery/disease2/isolator/attack_hand(mob/user as mob) + if(stat & (NOPOWER|BROKEN)) return + ui_interact(user) + +/obj/machinery/disease2/isolator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) + + var/data[0] + data["syringe_inserted"] = !!sample + data["isolating"] = isolating + data["pathogen_pool"] = null + data["state"] = state + data["entry"] = entry + data["can_print"] = (state != HOME || sample) && !isolating + + switch (state) + if (HOME) + if (sample) + var/list/pathogen_pool[0] + for(var/datum/reagent/blood/B in sample.reagents.reagent_list) + var/list/virus = B.data["virus2"] + for (var/ID in virus) + var/datum/disease2/disease/V = virus[ID] + var/datum/computer_file/data/virus_record/R = null + if (ID in virusDB) + R = virusDB[ID] + + var/weakref/W = B.data["donor"] + var/mob/living/carbon/human/D = W.resolve() + pathogen_pool.Add(list(list(\ + "name" = "[D ? D.get_species() : "Unidentified"] [B.name]", \ + "dna" = B.data["blood_DNA"], \ + "unique_id" = V.uniqueID, \ + "reference" = "\ref[V]", \ + "is_in_database" = !!R, \ + "record" = "\ref[R]"))) + + if (pathogen_pool.len > 0) + data["pathogen_pool"] = pathogen_pool + + if (LIST) + var/list/db[0] + for (var/ID in virusDB) + var/datum/computer_file/data/virus_record/r = virusDB[ID] + db.Add(list(list("name" = r.fields["name"], "record" = "\ref[r]"))) + + if (db.len > 0) + data["database"] = db + + if (ENTRY) + if (entry) + var/desc = entry.fields["description"] + data["entry"] = list(\ + "name" = entry.fields["name"], \ + "description" = replacetext(desc, "\n", "")) + + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "pathogenic_isolator.tmpl", src.name, 400, 500) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/disease2/isolator/Process() + if (isolating > 0) + isolating -= 1 + if (isolating == 0) + if (virus2) + var/obj/item/weapon/virusdish/d = new /obj/item/weapon/virusdish(src.loc) + d.virus2 = virus2.getcopy() + virus2 = null + ping("\The [src] pings, \"Viral strain isolated.\"") + + GLOB.nanomanager.update_uis(src) + update_icon() + +/obj/machinery/disease2/isolator/OnTopic(user, href_list) + if (href_list["close"]) + GLOB.nanomanager.close_user_uis(user, src, "main") + return TOPIC_HANDLED + + if (href_list[HOME]) + state = HOME + return TOPIC_REFRESH + + if (href_list[LIST]) + state = LIST + return TOPIC_REFRESH + + if (href_list[ENTRY]) + if (istype(locate(href_list["view"]), /datum/computer_file/data/virus_record)) + entry = locate(href_list["view"]) + + state = ENTRY + return TOPIC_REFRESH + + if (href_list["print"]) + print(user) + return TOPIC_REFRESH + + if(!sample) return TOPIC_HANDLED + + if (href_list["isolate"]) + var/datum/disease2/disease/V = locate(href_list["isolate"]) + if (V) + virus2 = V + isolating = 20 + update_icon() + return TOPIC_REFRESH + + if (href_list["eject"]) + sample.dropInto(loc) + sample = null + update_icon() + return TOPIC_REFRESH + +/obj/machinery/disease2/isolator/proc/print(var/mob/user) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(loc) + + switch (state) + if (HOME) + if (!sample) return + P.SetName("paper - Patient Diagnostic Report") + P.info = {" + [virology_letterhead("Patient Diagnostic Report")] +
                CONFIDENTIAL MEDICAL REPORT

                + Sample: [sample.name]
                +"} + + if (user) + P.info += "Generated By: [user.name]
                " + + P.info += "
                " + + for(var/datum/reagent/blood/B in sample.reagents.reagent_list) + var/weakref/W = B.data["donor"] + var/mob/living/carbon/human/D = W.resolve() + P.info += "[D ? D.get_species() : "Unidentified"] [B.name]:
                [B.data["blood_DNA"]]
                " + + var/list/virus = B.data["virus2"] + P.info += "Pathogens:
                " + if (virus.len > 0) + for (var/ID in virus) + var/datum/disease2/disease/V = virus[ID] + P.info += "[V.name()]
                " + else + P.info += "None
                " + + P.info += {" +
                + Additional Notes:  +"} + + if (LIST) + P.SetName("paper - Virus List") + P.info = {" + [virology_letterhead("Virus List")] +"} + + var/i = 0 + for (var/ID in virusDB) + i++ + var/datum/computer_file/data/virus_record/r = virusDB[ID] + P.info += "[i]. " + r.fields["name"] + P.info += "
                " + + P.info += {" +
                + Additional Notes:  +"} + + if (ENTRY) + P.SetName("paper - Viral Profile") + P.info = {" + [virology_letterhead("Viral Profile")] + [entry.fields["description"]] +
                + Additional Notes:  +"} + + state("The nearby computer prints out a report.") diff --git a/code/modules/virus2/items_devices.dm b/code/modules/virus2/items_devices.dm new file mode 100644 index 00000000..ce4b2a3a --- /dev/null +++ b/code/modules/virus2/items_devices.dm @@ -0,0 +1,108 @@ +///////////////ANTIBODY SCANNER/////////////// + +/obj/item/device/antibody_scanner + name = "antibody scanner" + desc = "Scans living beings for antibodies in their blood." + icon_state = "health" + w_class = ITEM_SIZE_SMALL + item_state = "electronic" + obj_flags = OBJ_FLAG_CONDUCTIBLE + +/obj/item/device/antibody_scanner/attack(mob/M as mob, mob/user as mob) + if(!istype(M,/mob/living/carbon/)) + report("Scan aborted: Incompatible target.", user) + return + + var/mob/living/carbon/C = M + if (istype(C,/mob/living/carbon/human/)) + var/mob/living/carbon/human/H = C + if(!H.should_have_organ(BP_HEART)) + report("Scan aborted: The target does not have blood.", user) + return + + if(!C.antibodies.len) + report("Scan Complete: No antibodies detected.", user) + return + + if (CLUMSY in user.mutations && prob(50)) + // I was tempted to be really evil and rot13 the output. + report("Antibodies detected: [reverse_text(antigens2string(C.antibodies))]", user) + else + report("Antibodies detected: [antigens2string(C.antibodies)]", user) + +/obj/item/device/antibody_scanner/proc/report(var/text, mob/user as mob) + to_chat(user, "\icon[src] \The [src] beeps, \"[text]\"") + +///////////////VIRUS DISH/////////////// + +/obj/item/weapon/virusdish + name = "virus dish" + icon = 'icons/obj/items.dmi' + icon_state = "implantcase-b" + var/datum/disease2/disease/virus2 = null + var/growth = 0 + var/basic_info = null + var/info = 0 + var/analysed = 0 + +/obj/item/weapon/virusdish/random + name = "virus sample" + +/obj/item/weapon/virusdish/random/New() + ..() + src.virus2 = new /datum/disease2/disease + src.virus2.makerandom() + growth = rand(5, 50) + +/obj/item/weapon/virusdish/attackby(var/obj/item/weapon/W as obj,var/mob/living/carbon/user as mob) + if(istype(W,/obj/item/weapon/hand_labeler) || istype(W,/obj/item/weapon/reagent_containers/syringe)) + return + ..() + if(prob(50)) + to_chat(user, "\The [src] shatters!") + if(virus2.infectionchance > 0) + for(var/mob/living/carbon/target in view(1, get_turf(src))) + if(airborne_can_reach(get_turf(src), get_turf(target))) + infect_virus2(target, src.virus2) + qdel(src) + +/obj/item/weapon/virusdish/examine(mob/user) + . = ..() + if(basic_info) + to_chat(user, "[basic_info] : More Information") + +/obj/item/weapon/virusdish/OnTopic(user, href_list) + if(href_list["info"]) + show_browser(user, info, "window=info_\ref[src]") + return TOPIC_HANDLED + +/obj/item/weapon/ruinedvirusdish + name = "ruined virus sample" + icon = 'icons/obj/items.dmi' + icon_state = "implantcase-b" + desc = "The bacteria in the dish are completely dead." + +/obj/item/weapon/ruinedvirusdish/attackby(var/obj/item/weapon/W as obj,var/mob/living/carbon/user as mob) + if(istype(W,/obj/item/weapon/hand_labeler) || istype(W,/obj/item/weapon/reagent_containers/syringe)) + return ..() + + if(prob(50)) + to_chat(user, "\The [src] shatters!") + qdel(src) + +///////////////GNA DISK/////////////// + +/obj/item/weapon/diseasedisk + name = "blank GNA disk" + icon = 'icons/obj/cloning.dmi' + icon_state = "datadisk0" + w_class = ITEM_SIZE_TINY + var/datum/disease2/effect/effect = null + var/list/species = null + var/stage = 1 + var/analysed = 1 + +/obj/item/weapon/diseasedisk/premade/New() + name = "blank GNA disk (stage: [stage])" + effect = new /datum/disease2/effect/invisible + effect.stage = stage diff --git a/code/modules/wardog/wardog.dm b/code/modules/wardog/wardog.dm new file mode 100644 index 00000000..67b6692c --- /dev/null +++ b/code/modules/wardog/wardog.dm @@ -0,0 +1,40 @@ +/* + +This file is built for communication with a discord bot. + +*/ + +proc/send_to_bot(list/params, useapikey = 1) + if(useapikey) + params["key"] = config.bot_api_key + + world.Export("[config.bot_url]/api?[list2params(params)]") + to_world_log("[config.bot_url]/api?[list2params(params)]") + + +/datum/controller/gameticker/declare_completion() + . = ..() + var/players = 0 + for(var/client/C in GLOB.clients) + players++ + + var/condition = SSWarfare.complete + var/victor = findtext(condition, "red") ? "red" : (findtext(condition, "blue") ? "blue" : "draw") + + send_to_bot(list( + "call" = "roundend", + "winning_team" = victor, + "condition" = condition ? condition : "draw", + "players" = players, + "minestripped" = GLOB.mines_tripped, + "teethlost" = GLOB.teeth_lost, + "bloodshed" = GLOB.total_deaths, + "time" = roundduration2text() + )) + +/* +/hook/startup/proc/roundstartping() + send_to_bot(list( + "call" = "roundstart" + )) +*/ \ No newline at end of file diff --git a/code/modules/wireless/devices.dm b/code/modules/wireless/devices.dm new file mode 100644 index 00000000..ed0d412f --- /dev/null +++ b/code/modules/wireless/devices.dm @@ -0,0 +1,199 @@ +//------------------------------- +// Buttons +// Sender: intended to be used by buttons, when the button is pressed it will call activate() on all connected /button +// receivers. +// Receiver: does whatever the subtype does. deactivate() by default calls activate(), so you will have to override in +// it in a subtype if you want it to do something. +//------------------------------- +/datum/wifi/sender/button/activate(mob/living/user) + for(var/datum/wifi/receiver/button/B in connected_devices) + B.activate(user) + +/datum/wifi/sender/button/deactivate(mob/living/user) + for(var/datum/wifi/receiver/button/B in connected_devices) + B.deactivate(user) + +/datum/wifi/receiver/button/proc/activate(mob/living/user) + +/datum/wifi/receiver/button/proc/deactivate(mob/living/user) + activate(user) //override this if you want deactivate to actually do something + +//------------------------------- +// Doors +// Sender: sends an open/close request to all connected /door receivers. Utilises spawn_sync to trigger all doors to +// open at approximately the same time. Waits until all doors have finished opening before returning. +// Receiver: will try to open/close the parent door when activate/deactivate is called. +//------------------------------- + +// Sender procs +/datum/wifi/sender/door/activate(var/command) + if(!command) + return + + var/datum/spawn_sync/S = new() + + for(var/datum/wifi/receiver/button/door/D in connected_devices) + S.start_worker(D, command) + S.wait_until_done() + return + +//Receiver procs +/datum/wifi/receiver/button/door/proc/open() + var/obj/machinery/door/D = parent + if(istype(D) && D.can_open()) + D.open() + +/datum/wifi/receiver/button/door/proc/close() + var/obj/machinery/door/D = parent + if(istype(D) && D.can_close()) + D.close() + +/datum/wifi/receiver/button/door/proc/lock() + var/obj/machinery/door/airlock/D = parent + if(istype(D)) + D.lock() + +/datum/wifi/receiver/button/door/proc/unlock() + var/obj/machinery/door/airlock/D = parent + if(istype(D)) + D.unlock() + +/datum/wifi/receiver/button/door/proc/enable_idscan() + var/obj/machinery/door/airlock/D = parent + if(istype(D)) + D.set_idscan(1) + +/datum/wifi/receiver/button/door/proc/disable_idscan() + var/obj/machinery/door/airlock/D = parent + if(istype(D)) + D.set_idscan(0) + +/datum/wifi/receiver/button/door/proc/enable_safeties() + var/obj/machinery/door/airlock/D = parent + if(istype(D)) + D.set_safeties(1) + +/datum/wifi/receiver/button/door/proc/disable_safeties() + var/obj/machinery/door/airlock/D = parent + if(istype(D)) + D.set_safeties(0) + +/datum/wifi/receiver/button/door/proc/electrify() + var/obj/machinery/door/airlock/D = parent + if(istype(D)) + D.electrify(-1) + +/datum/wifi/receiver/button/door/proc/unelectrify() + var/obj/machinery/door/airlock/D = parent + if(istype(D)) + D.electrify(0) + +//------------------------------- +// Emitter +// Activates/deactivates the parent emitter. +//------------------------------- +/datum/wifi/receiver/button/emitter/activate(mob/living/user) + ..() + var/obj/machinery/power/emitter/E = parent + if(istype(E) && !E.active) + E.activate(user) //if the emitter is not active, trigger the activate proc to toggle it + +/datum/wifi/receiver/button/emitter/deactivate(mob/living/user) + var/obj/machinery/power/emitter/E = parent + if(istype(E) && E.active) + E.activate(user) //if the emitter is active, trigger the activate proc to toggle it + +//------------------------------- +// Crematorium +// Triggers cremate() on the parent /crematorium. +//------------------------------- +/datum/wifi/receiver/button/crematorium/activate(mob/living/user) + ..() + var/obj/structure/crematorium/C = parent + if(istype(C)) + C.cremate(user) + +//------------------------------- +// Mounted Flash +// Triggers flash() on the parent /flasher. +//------------------------------- +/datum/wifi/receiver/button/flasher/activate(mob/living/user) + ..() + var/obj/machinery/flasher/F = parent + if(istype(F)) + F.flash() + +//------------------------------- +// Holosign +// Turns the parent /holosign on/off. +//------------------------------- +/datum/wifi/receiver/button/holosign/activate(mob/living/user) + ..() + var/obj/machinery/holosign/H = parent + if(istype(H) && !H.lit) + H.toggle() + +/datum/wifi/receiver/button/holosign/deactivate(mob/living/user) + var/obj/machinery/holosign/H = parent + if(istype(H) && H.lit) + H.toggle() + +//------------------------------- +// Igniter +// Turns the parent /igniter on/off. +//------------------------------- +/datum/wifi/receiver/button/igniter/activate(mob/living/user) + ..() + var/obj/machinery/igniter/I = parent + if(istype(I)) + if(!I.on) + I.ignite() + +/datum/wifi/receiver/button/igniter/deactivate(mob/living/user) + if(istype(parent, /obj/machinery/igniter)) + var/obj/machinery/igniter/I = parent + if(I.on) + I.ignite() + +//------------------------------- +// Sparker +// Triggers the parent /sparker to ignite(). +//------------------------------- +/datum/wifi/receiver/button/sparker/activate(mob/living/user) + ..() + var/obj/machinery/sparker/S = parent + if(istype(S)) + S.ignite() + +//------------------------------- +// Mass Driver +// Sender: carries out a sequence of first opening all connected doors, then activating all connected mass drivers, +// then closes all connected doors. It will wait before continuing the sequence after opening/closing the doors. +// Receiver: Triggers the parent mass dirver to activate. +//------------------------------- +/datum/wifi/sender/mass_driver/activate() + var/datum/spawn_sync/S = new() + + //tell all doors to open + for(var/datum/wifi/receiver/button/door/D in connected_devices) + S.start_worker(D, "open") + S.wait_until_done() + S.reset() + //tell all mass drivers to launch + for(var/datum/wifi/receiver/button/mass_driver/M in connected_devices) + spawn() + M.activate() + sleep(20) + + //tell all doors to close + S.reset() + for(var/datum/wifi/receiver/button/door/D in connected_devices) + S.start_worker(D, "close") + S.wait_until_done() + return + +/datum/wifi/receiver/button/mass_driver/activate(mob/living/user) + ..() + var/obj/machinery/mass_driver/M = parent + if(istype(M)) + M.drive() diff --git a/code/modules/wireless/interfaces.dm b/code/modules/wireless/interfaces.dm new file mode 100644 index 00000000..a9826357 --- /dev/null +++ b/code/modules/wireless/interfaces.dm @@ -0,0 +1,115 @@ +//------------------------------- +/* + Interfaces + + These are the datums that an object needs to connect via the wireless controller. You will need a /wifi/receiver to + allow other devices to connect to your device and send it instructions. You will need a /wifi/sender to send signals + to other devices with wifi receivers. You can have multiple devices (senders and receivers) if you program your + device to handle them. + + Each wifi interface has one "id". This identifies which devices can connect to each other. Multiple senders can + connect to multiple receivers as long as they have the same id. + + Variants are found in devices.dm + + To add a receiver to an object: + Add the following variables to the object: + var/_wifi_id << variable that can be configured on the map, this is passed to the receiver later + var/datum/wifi/receiver/subtype/wifi_receiver << the receiver (and subtype itself) + + Add or modify the objects initialize() proc to include: + if(_wifi_id) << only creates a wifi receiver if an id is set + wifi_receiver = new(_wifi_id, src) << this needs to be in initialize() as New() is usually too + early, and the receiver will try to connect to the controller + before it is setup. + + Add or modify the objects Destroy() proc to include: + qdel(wifi_receiver) + wifi_receiver = null + + Senders are setup the same way, except with a var/datum/wifi/sender/subtype/wifi_sender variable instead of (or in + addition to) a /wifi/receiver variable. + You will however need to call the /wifi/senders code to pass commands onto any connected receivers. + Example: + obj/machinery/button/attack_hand() + wifi_sender.activate() +*/ +//------------------------------- + + +//------------------------------- +// Wifi +//------------------------------- +/datum/wifi + var/obj/parent + var/list/connected_devices + var/id + +/datum/wifi/New(var/new_id, var/obj/O) + connected_devices = new() + id = new_id + if(istype(O)) + parent = O + +/datum/wifi/Destroy(var/wifi/device) + parent = null + for(var/datum/wifi/D in connected_devices) + D.disconnect_device(src) + disconnect_device(D) + return ..() + +/datum/wifi/proc/connect_device(var/datum/wifi/device) + if(connected_devices) + connected_devices |= device + else + connected_devices = new() + connected_devices |= device + +/datum/wifi/proc/disconnect_device(var/datum/wifi/device) + if(connected_devices) + connected_devices -= device + +//------------------------------- +// Receiver +//------------------------------- +/datum/wifi/receiver/New() + ..() + if(SSwireless) + SSwireless.add_device(src) + +/datum/wifi/receiver/Destroy() + if(SSwireless) + SSwireless.remove_device(src) + return ..() + +//------------------------------- +// Sender +//------------------------------- +/datum/wifi/sender/New() + ..() + send_connection_request() + +/datum/wifi/sender/proc/set_target(var/new_target) + id = new_target + +/datum/wifi/sender/proc/send_connection_request() + var/datum/connection_request/C = new(src, id) + SSwireless.add_request(C) + +/datum/wifi/sender/proc/activate(mob/living/user) + return + +/datum/wifi/sender/proc/deactivate(mob/living/user) + return + +//------------------------------- +// Connection request +//------------------------------- +/datum/connection_request + var/datum/wifi/sender/source //wifi/sender object creating the request + var/id //id tag of the target device(s) to try to connect to + +/datum/connection_request/New(var/datum/wifi/sender/sender, var/receiver) + if(istype(sender)) + source = sender + id = receiver diff --git a/code/modules/xenoarcheaology/anomaly_container.dm b/code/modules/xenoarcheaology/anomaly_container.dm new file mode 100644 index 00000000..795cd9d6 --- /dev/null +++ b/code/modules/xenoarcheaology/anomaly_container.dm @@ -0,0 +1,43 @@ +/obj/structure/anomaly_container + name = "anomaly container" + desc = "Used to safely contain and move anomalies." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "anomaly_container" + density = 1 + + var/obj/machinery/artifact/contained + +/obj/structure/anomaly_container/Initialize() + . = ..() + + var/obj/machinery/artifact/A = locate() in loc + if(A) + contain(A) + +/obj/structure/anomaly_container/attack_hand(var/mob/user) + release() + +/obj/structure/anomaly_container/attack_robot(var/mob/user) + if(Adjacent(user)) + release() + +/obj/structure/anomaly_container/proc/contain(var/obj/machinery/artifact/artifact) + if(contained) + return + contained = artifact + artifact.forceMove(src) + underlays += image(artifact) + desc = "Used to safely contain and move anomalies. \The [contained] is kept inside." + +/obj/structure/anomaly_container/proc/release() + if(!contained) + return + contained.dropInto(src) + contained = null + underlays.Cut() + desc = initial(desc) + +/obj/machinery/artifact/MouseDrop(var/obj/structure/anomaly_container/over_object) + if(istype(over_object) && Adjacent(over_object) && CanMouseDrop(over_object, usr)) + Bumped(usr) + over_object.contain(src) \ No newline at end of file diff --git a/code/modules/xenoarcheaology/artifacts/artifact.dm b/code/modules/xenoarcheaology/artifacts/artifact.dm new file mode 100644 index 00000000..222a3563 --- /dev/null +++ b/code/modules/xenoarcheaology/artifacts/artifact.dm @@ -0,0 +1,308 @@ +/obj/machinery/artifact + name = "alien artifact" + desc = "A large alien device." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "ano00" + var/icon_num = 0 + density = 1 + var/datum/artifact_effect/my_effect + var/datum/artifact_effect/secondary_effect + var/being_used = 0 + +/obj/machinery/artifact/New() + ..() + + var/effecttype = pick(typesof(/datum/artifact_effect) - /datum/artifact_effect) + my_effect = new effecttype(src) + + if(prob(75)) + effecttype = pick(typesof(/datum/artifact_effect) - /datum/artifact_effect) + secondary_effect = new effecttype(src) + if(prob(75)) + secondary_effect.ToggleActivate(0) + + icon_num = rand(0, 11) + + icon_state = "ano[icon_num]0" + if(icon_num == 7 || icon_num == 8) + 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(50)) + my_effect.trigger = TRIGGER_ENERGY + 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 == 10) + desc = "A large alien device, there appear to be some kind of vents in the side." + if(prob(50)) + my_effect.trigger = pick(TRIGGER_ENERGY, TRIGGER_HEAT, TRIGGER_COLD, TRIGGER_PHORON, TRIGGER_OXY, TRIGGER_CO2, TRIGGER_NITRO) + else if(icon_num == 11) + name = "sealed alien pod" + desc = "A strange alien device." + if(prob(25)) + my_effect.trigger = pick(TRIGGER_WATER, TRIGGER_ACID, TRIGGER_VOLATILE, TRIGGER_TOXIN) + +/obj/machinery/artifact/Destroy() + QDEL_NULL(my_effect) + QDEL_NULL(secondary_effect) + . = ..() + +/obj/machinery/artifact/Process() + var/turf/L = loc + if(!istype(L)) // We're inside a container or on null turf, either way stop processing effects + return + + if(my_effect) + my_effect.process() + if(secondary_effect) + secondary_effect.process() + + if(pulledby) + Bumped(pulledby) + + //if either of our effects rely on environmental factors, work that out + var/trigger_cold = 0 + var/trigger_hot = 0 + var/trigger_phoron = 0 + var/trigger_oxy = 0 + var/trigger_co2 = 0 + var/trigger_nitro = 0 + if( (my_effect.trigger >= TRIGGER_HEAT && my_effect.trigger <= TRIGGER_NITRO) || (my_effect.trigger >= TRIGGER_HEAT && my_effect.trigger <= TRIGGER_NITRO) ) + var/turf/T = get_turf(src) + var/datum/gas_mixture/env = T.return_air() + if(env) + if(env.temperature < 225) + trigger_cold = 1 + else if(env.temperature > 375) + trigger_hot = 1 + + if(env.gas["phoron"] >= 10) + trigger_phoron = 1 + if(env.gas["oxygen"] >= 10) + trigger_oxy = 1 + if(env.gas["carbon_dioxide"] >= 10) + trigger_co2 = 1 + if(env.gas["nitrogen"] >= 10) + trigger_nitro = 1 + + //COLD ACTIVATION + if(trigger_cold) + if(my_effect.trigger == TRIGGER_COLD && !my_effect.activated) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_COLD && !secondary_effect.activated) + secondary_effect.ToggleActivate(0) + else + if(my_effect.trigger == TRIGGER_COLD && my_effect.activated) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_COLD && !secondary_effect.activated) + secondary_effect.ToggleActivate(0) + + //HEAT ACTIVATION + if(trigger_hot) + if(my_effect.trigger == TRIGGER_HEAT && !my_effect.activated) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_HEAT && !secondary_effect.activated) + secondary_effect.ToggleActivate(0) + else + if(my_effect.trigger == TRIGGER_HEAT && my_effect.activated) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_HEAT && !secondary_effect.activated) + secondary_effect.ToggleActivate(0) + + //PHORON GAS ACTIVATION + if(trigger_phoron) + if(my_effect.trigger == TRIGGER_PHORON && !my_effect.activated) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_PHORON && !secondary_effect.activated) + secondary_effect.ToggleActivate(0) + else + if(my_effect.trigger == TRIGGER_PHORON && my_effect.activated) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_PHORON && !secondary_effect.activated) + secondary_effect.ToggleActivate(0) + + //OXYGEN GAS ACTIVATION + if(trigger_oxy) + if(my_effect.trigger == TRIGGER_OXY && !my_effect.activated) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_OXY && !secondary_effect.activated) + secondary_effect.ToggleActivate(0) + else + if(my_effect.trigger == TRIGGER_OXY && my_effect.activated) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_OXY && !secondary_effect.activated) + secondary_effect.ToggleActivate(0) + + //CO2 GAS ACTIVATION + if(trigger_co2) + if(my_effect.trigger == TRIGGER_CO2 && !my_effect.activated) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_CO2 && !secondary_effect.activated) + secondary_effect.ToggleActivate(0) + else + if(my_effect.trigger == TRIGGER_CO2 && my_effect.activated) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_CO2 && !secondary_effect.activated) + secondary_effect.ToggleActivate(0) + + //NITROGEN GAS ACTIVATION + if(trigger_nitro) + if(my_effect.trigger == TRIGGER_NITRO && !my_effect.activated) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_NITRO && !secondary_effect.activated) + secondary_effect.ToggleActivate(0) + else + if(my_effect.trigger == TRIGGER_NITRO && my_effect.activated) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_NITRO && !secondary_effect.activated) + secondary_effect.ToggleActivate(0) + +/obj/machinery/artifact/attack_hand(var/mob/user as mob) + if (get_dist(user, src) > 1) + to_chat(user, "You can't reach \the [src] from here.") + return + if(ishuman(user) && user:gloves) + to_chat(user, "You touch [src] with your gloved hands, [pick("but nothing of note happens","but nothing happens","but nothing interesting happens","but you notice nothing different","but nothing seems to have happened")].") + return + + src.add_fingerprint(user) + + if(my_effect.trigger == TRIGGER_TOUCH) + to_chat(user, "You touch [src].") + my_effect.ToggleActivate() + else + to_chat(user, "You touch [src], [pick("but nothing of note happens","but nothing happens","but nothing interesting happens","but you notice nothing different","but nothing seems to have happened")].") + + if(prob(25) && secondary_effect && secondary_effect.trigger == TRIGGER_TOUCH) + secondary_effect.ToggleActivate(0) + + if (my_effect.effect == EFFECT_TOUCH) + my_effect.DoEffectTouch(user) + + if(secondary_effect && secondary_effect.effect == EFFECT_TOUCH && secondary_effect.activated) + secondary_effect.DoEffectTouch(user) + +/obj/machinery/artifact/attackby(obj/item/weapon/W as obj, mob/living/user as mob) + + if (istype(W, /obj/item/weapon/reagent_containers/)) + if(W.reagents.has_reagent(/datum/reagent/hydrazine, 1) || W.reagents.has_reagent(/datum/reagent/water, 1)) + if(my_effect.trigger == TRIGGER_WATER) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_WATER && prob(25)) + secondary_effect.ToggleActivate(0) + else if(W.reagents.has_reagent(/datum/reagent/acid, 1) || W.reagents.has_reagent(/datum/reagent/acid/polyacid, 1) || W.reagents.has_reagent(/datum/reagent/diethylamine, 1)) + if(my_effect.trigger == TRIGGER_ACID) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_ACID && prob(25)) + secondary_effect.ToggleActivate(0) + else if(W.reagents.has_reagent(/datum/reagent/toxin/phoron, 1) || W.reagents.has_reagent(/datum/reagent/thermite, 1)) + if(my_effect.trigger == TRIGGER_VOLATILE) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_VOLATILE && prob(25)) + secondary_effect.ToggleActivate(0) + else if(W.reagents.has_reagent(/datum/reagent/toxin, 1) || W.reagents.has_reagent(/datum/reagent/toxin/cyanide, 1) || W.reagents.has_reagent(/datum/reagent/toxin/amatoxin, 1) || W.reagents.has_reagent(/datum/reagent/ethanol/neurotoxin, 1)) + if(my_effect.trigger == TRIGGER_TOXIN) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_TOXIN && prob(25)) + secondary_effect.ToggleActivate(0) + else if(istype(W,/obj/item/weapon/melee/baton) && W:status ||\ + istype(W,/obj/item/weapon/melee/energy) ||\ + istype(W,/obj/item/weapon/melee/cultblade) ||\ + istype(W,/obj/item/weapon/card/emag) ||\ + istype(W,/obj/item/device/multitool)) + if (my_effect.trigger == TRIGGER_ENERGY) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_ENERGY && prob(25)) + secondary_effect.ToggleActivate(0) + + else if (istype(W,/obj/item/weapon/flame) && W:lit ||\ + isWelder(W) && W:welding) + if(my_effect.trigger == TRIGGER_HEAT) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_HEAT && prob(25)) + secondary_effect.ToggleActivate(0) + else + ..() + if (my_effect.trigger == TRIGGER_FORCE && W.force >= 10) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_FORCE && prob(25)) + secondary_effect.ToggleActivate(0) + +/obj/machinery/artifact/Bumped(M as mob|obj) + ..() + if(istype(M,/obj)) + var/obj/O = M + if(O.throwforce >= 10) + if(my_effect.trigger == TRIGGER_FORCE) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_FORCE && prob(25)) + secondary_effect.ToggleActivate(0) + else if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(!istype(H.gloves, /obj/item/clothing/gloves)) + var/warn = 0 + + if (my_effect.trigger == TRIGGER_TOUCH && prob(50)) + my_effect.ToggleActivate() + warn = 1 + if(secondary_effect && secondary_effect.trigger == TRIGGER_TOUCH && prob(25)) + secondary_effect.ToggleActivate(0) + warn = 1 + + if (my_effect.effect == EFFECT_TOUCH && prob(50)) + my_effect.DoEffectTouch(M) + warn = 1 + if(secondary_effect && secondary_effect.effect == EFFECT_TOUCH && secondary_effect.activated && prob(50)) + secondary_effect.DoEffectTouch(M) + warn = 1 + + if(warn) + to_chat(M, "You accidentally touch [src].") + ..() + +/obj/machinery/artifact/bullet_act(var/obj/item/projectile/P) + if(istype(P,/obj/item/projectile/bullet) ||\ + istype(P,/obj/item/projectile/hivebotbullet)) + if(my_effect.trigger == TRIGGER_FORCE) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_FORCE && prob(25)) + secondary_effect.ToggleActivate(0) + + else if(istype(P,/obj/item/projectile/beam) ||\ + istype(P,/obj/item/projectile/ion) ||\ + istype(P,/obj/item/projectile/energy)) + if(my_effect.trigger == TRIGGER_ENERGY) + my_effect.ToggleActivate() + if(secondary_effect && secondary_effect.trigger == TRIGGER_ENERGY && prob(25)) + secondary_effect.ToggleActivate(0) + +/obj/machinery/artifact/ex_act(severity) + switch(severity) + if(1.0) qdel(src) + if(2.0) + if (prob(50)) + qdel(src) + else + if(my_effect.trigger == TRIGGER_FORCE || my_effect.trigger == TRIGGER_HEAT) + my_effect.ToggleActivate() + if(secondary_effect && (secondary_effect.trigger == TRIGGER_FORCE || secondary_effect.trigger == TRIGGER_HEAT) && prob(25)) + secondary_effect.ToggleActivate(0) + if(3.0) + if (my_effect.trigger == TRIGGER_FORCE || my_effect.trigger == TRIGGER_HEAT) + my_effect.ToggleActivate() + if(secondary_effect && (secondary_effect.trigger == TRIGGER_FORCE || secondary_effect.trigger == TRIGGER_HEAT) && prob(25)) + secondary_effect.ToggleActivate(0) + return + +/obj/machinery/artifact/Move() + ..() + if(my_effect) + my_effect.UpdateMove() + if(secondary_effect) + secondary_effect.UpdateMove() diff --git a/code/modules/xenoarcheaology/artifacts/artifact_find.dm b/code/modules/xenoarcheaology/artifacts/artifact_find.dm new file mode 100644 index 00000000..3bd27d0f --- /dev/null +++ b/code/modules/xenoarcheaology/artifacts/artifact_find.dm @@ -0,0 +1,19 @@ +/datum/artifact_find + var/artifact_id + var/artifact_find_type + +/datum/artifact_find/New() + + artifact_id = "[pick("kappa","sigma","antaeres","beta","omicron","iota","epsilon","omega","gamma","delta","tau","alpha")]-[random_id(/datum/artifact_find, 100, 999)]" + + artifact_find_type = pick( + 5;/obj/machinery/power/supermatter, + 5;/obj/structure/constructshell, + 5;/obj/machinery/syndicate_beacon, + 25;/obj/machinery/power/supermatter/shard, + 50;/obj/structure/cult/pylon, + 100;/obj/machinery/auto_cloner, + 100;/obj/machinery/giga_drill, + 100;/obj/machinery/replicator, + 150;/obj/structure/crystal, +1000;/obj/machinery/artifact) \ No newline at end of file diff --git a/code/modules/xenoarcheaology/artifacts/autocloner.dm b/code/modules/xenoarcheaology/artifacts/autocloner.dm new file mode 100644 index 00000000..98ae210e --- /dev/null +++ b/code/modules/xenoarcheaology/artifacts/autocloner.dm @@ -0,0 +1,84 @@ +/obj/machinery/auto_cloner + name = "mysterious pod" + desc = "It's full of a viscous liquid, but appears dark and silent." + icon = 'icons/obj/cryogenics.dmi' + icon_state = "cellold0" + var/spawn_type + var/time_spent_spawning = 0 + var/time_per_spawn = 0 + var/last_process= 0 + density = 1 + var/previous_power_state = 0 + + use_power = 1 + active_power_usage = 2000 + idle_power_usage = 1000 + +/obj/machinery/auto_cloner/New() + ..() + + time_per_spawn = rand(1200,3600) + + //33% chance to spawn nasties + if(prob(33)) + spawn_type = pick( + /mob/living/simple_animal/hostile/giant_spider/nurse, + /mob/living/simple_animal/hostile/alien, + /mob/living/simple_animal/hostile/bear, + /mob/living/simple_animal/hostile/creature) + else + spawn_type = pick(\ + /mob/living/simple_animal/cat, + /mob/living/simple_animal/corgi, + /mob/living/simple_animal/corgi/puppy, + /mob/living/simple_animal/chicken, + /mob/living/simple_animal/cow, + /mob/living/simple_animal/parrot, + /mob/living/simple_animal/slime, + /mob/living/simple_animal/crab, + /mob/living/simple_animal/mouse, + /mob/living/simple_animal/hostile/retaliate/goat) + +//todo: how the hell is the asteroid permanently powered? +/obj/machinery/auto_cloner/Process() + if(powered(power_channel)) + if(!previous_power_state) + previous_power_state = 1 + icon_state = "cellold1" + src.visible_message("\icon[src] [src] suddenly comes to life!") + + //slowly grow a mob + if(prob(5)) + src.visible_message("\icon[src] [src] [pick("gloops","glugs","whirrs","whooshes","hisses","purrs","hums","gushes")].") + + //if we've finished growing... + if(time_spent_spawning >= time_per_spawn) + time_spent_spawning = 0 + use_power = 1 + src.visible_message("\icon[src] [src] pings!") + icon_state = "cellold1" + desc = "It's full of a bubbling viscous liquid, and is lit by a mysterious glow." + if(spawn_type) + new spawn_type(src.loc) + + //if we're getting close to finished, kick into overdrive power usage + if(time_spent_spawning / time_per_spawn > 0.75) + use_power = 2 + icon_state = "cellold2" + desc = "It's full of a bubbling viscous liquid, and is lit by a mysterious glow. A dark shape appears to be forming inside..." + else + use_power = 1 + icon_state = "cellold1" + desc = "It's full of a bubbling viscous liquid, and is lit by a mysterious glow." + + time_spent_spawning = time_spent_spawning + world.time - last_process + else + if(previous_power_state) + previous_power_state = 0 + icon_state = "cellold0" + src.visible_message("\icon[src] [src] suddenly shuts down.") + + //cloned mob slowly breaks down + time_spent_spawning = max(time_spent_spawning + last_process - world.time, 0) + + last_process = world.time diff --git a/code/modules/xenoarcheaology/artifacts/crystal.dm b/code/modules/xenoarcheaology/artifacts/crystal.dm new file mode 100644 index 00000000..b2eebf88 --- /dev/null +++ b/code/modules/xenoarcheaology/artifacts/crystal.dm @@ -0,0 +1,35 @@ +/obj/structure/crystal + name = "large crystal" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "crystal" + density = 1 + +/obj/structure/crystal/New() + ..() + + icon_state = pick("ano70","ano80") + + 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.") + +/obj/structure/crystal/Destroy() + src.visible_message("[src] shatters!") + if(prob(75)) + new /obj/item/weapon/material/shard/phoron(src.loc) + if(prob(50)) + new /obj/item/weapon/material/shard/phoron(src.loc) + if(prob(25)) + new /obj/item/weapon/material/shard/phoron(src.loc) + if(prob(75)) + new /obj/item/weapon/material/shard(src.loc) + if(prob(50)) + new /obj/item/weapon/material/shard(src.loc) + if(prob(25)) + new /obj/item/weapon/material/shard(src.loc) + return ..() + +//todo: laser_act diff --git a/code/modules/xenoarcheaology/artifacts/gigadrill.dm b/code/modules/xenoarcheaology/artifacts/gigadrill.dm new file mode 100644 index 00000000..ef02e490 --- /dev/null +++ b/code/modules/xenoarcheaology/artifacts/gigadrill.dm @@ -0,0 +1,34 @@ +/obj/machinery/giga_drill + name = "alien drill" + desc = "A giant, alien drill mounted on long treads." + icon = 'icons/obj/mining.dmi' + icon_state = "gigadrill" + var/active = 0 + var/drill_time = 10 + var/turf/drilling_turf + density = 1 + layer = ABOVE_OBJ_LAYER //to go over ores + +/obj/machinery/giga_drill/attack_hand(mob/user as mob) + if(active) + active = 0 + icon_state = "gigadrill" + to_chat(user, "You press a button and \the [src] slowly spins down.") + else + active = 1 + icon_state = "gigadrill_mov" + to_chat(user, "You press a button and \the [src] shudders to life.") + +/obj/machinery/giga_drill/Bump(atom/A) + if(active && !drilling_turf) + if(istype(A,/turf/simulated/mineral)) + var/turf/simulated/mineral/M = A + drilling_turf = get_turf(src) + src.visible_message("\The [src] begins to drill into \the [M].") + anchored = 1 + spawn(drill_time) + if(get_turf(src) == drilling_turf && active) + M.GetDrilled() + src.loc = M + drilling_turf = null + anchored = 0 diff --git a/code/modules/xenoarcheaology/artifacts/replicator.dm b/code/modules/xenoarcheaology/artifacts/replicator.dm new file mode 100644 index 00000000..3af5b224 --- /dev/null +++ b/code/modules/xenoarcheaology/artifacts/replicator.dm @@ -0,0 +1,149 @@ +/obj/machinery/replicator + name = "alien machine" + desc = "It's some kind of pod with strange wires and gadgets all over it." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "borgcharger0(old)" + density = 1 + + idle_power_usage = 100 + active_power_usage = 1000 + use_power = 1 + + var/spawn_progress_time = 0 + var/max_spawn_time = 50 + var/last_process_time = 0 + + var/list/construction = list() + var/list/spawning_types = list() + var/list/stored_materials = list() + + var/fail_message + +/obj/machinery/replicator/New() + ..() + + var/list/viables = list( + /obj/item/roller, + /obj/structure/closet/crate, + /obj/structure/closet/acloset, + /mob/living/simple_animal/hostile/mimic, + /mob/living/simple_animal/hostile/viscerator, + /mob/living/simple_animal/hostile/hivebot, + /obj/item/device/analyzer, + /obj/item/device/camera, + /obj/item/device/flash, + /obj/item/device/flashlight, + /obj/item/device/healthanalyzer, + /obj/item/device/multitool, + /obj/item/device/paicard, + /obj/item/device/radio, + /obj/item/device/radio/headset, + /obj/item/device/radio/beacon, + /obj/item/weapon/autopsy_scanner, + /obj/item/weapon/bikehorn, + /obj/item/weapon/bonesetter, + /obj/item/weapon/material/knife/butch, + /obj/item/weapon/caution, + /obj/item/weapon/caution/cone, + /obj/item/weapon/crowbar, + /obj/item/weapon/clipboard, + /obj/item/weapon/cell, + /obj/item/weapon/circular_saw, + /obj/item/weapon/material/hatchet, + /obj/item/weapon/handcuffs, + /obj/item/weapon/hemostat, + /obj/item/weapon/material/knife, + /obj/item/weapon/flame/lighter, + /obj/item/weapon/light/bulb, + /obj/item/weapon/light/tube, + /obj/item/weapon/pickaxe, + /obj/item/weapon/shovel, + /obj/item/weapon/weldingtool, + /obj/item/weapon/wirecutters, + /obj/item/weapon/wrench, + /obj/item/weapon/screwdriver, + /obj/item/weapon/grenade/chem_grenade/cleaner, + /obj/item/weapon/grenade/chem_grenade/metalfoam) + + var/quantity = rand(5, 15) + for(var/i=0, i" + +/obj/machinery/replicator/Process() + if(spawning_types.len && powered()) + spawn_progress_time += world.time - last_process_time + if(spawn_progress_time > max_spawn_time) + src.visible_message("\icon[src] [src] pings!") + + var/obj/source_material = pop(stored_materials) + var/spawn_type = pop(spawning_types) + var/obj/spawned_obj = new spawn_type(src.loc) + if(source_material) + if(length(source_material.name) < MAX_MESSAGE_LEN) + spawned_obj.SetName("[source_material] " + spawned_obj.name) + if(length(source_material.desc) < MAX_MESSAGE_LEN * 2) + if(spawned_obj.desc) + spawned_obj.desc += " It is made of [source_material]." + else + spawned_obj.desc = "It is made of [source_material]." + qdel(source_material) + + spawn_progress_time = 0 + max_spawn_time = rand(30,100) + + if(!spawning_types.len || !stored_materials.len) + use_power = 1 + icon_state = "borgcharger0(old)" + + else if(prob(5)) + src.visible_message("\icon[src] [src] [pick("clicks","whizzes","whirrs","whooshes","clanks","clongs","clonks","bangs")].") + + last_process_time = world.time + +/obj/machinery/replicator/attack_hand(mob/user as mob) + interact(user) + +/obj/machinery/replicator/interact(mob/user) + var/dat = "The control panel displays an incomprehensible selection of controls, many with unusual markings or text around them.
                " + dat += "
                " + for(var/index=1, index<=construction.len, index++) + dat += "\[[construction[index]]\]
                " + + user << browse(dat, "window=alien_replicator") + +/obj/machinery/replicator/attackby(obj/item/weapon/W as obj, mob/living/user as mob) + user.drop_item() + W.forceMove(src) + stored_materials.Add(W) + src.visible_message("\The [user] inserts \the [W] into \the [src].") + +/obj/machinery/replicator/OnTopic(user, href_list) + if(href_list["activate"]) + var/index = text2num(href_list["activate"]) + if(index > 0 && index <= construction.len) + if(stored_materials.len > spawning_types.len) + if(spawning_types.len) + src.visible_message("\icon[src] a [pick("light","dial","display","meter","pad")] on [src]'s front [pick("blinks","flashes")] [pick("red","yellow","blue","orange","purple","green","white")].") + else + src.visible_message("\icon[src] [src]'s front compartment slides shut.") + + spawning_types.Add(construction[construction[index]]) + spawn_progress_time = 0 + use_power = 2 + icon_state = "borgcharger1(old)" + else + src.visible_message(fail_message) + . = TOPIC_REFRESH diff --git a/code/modules/xenoarcheaology/boulder.dm b/code/modules/xenoarcheaology/boulder.dm new file mode 100644 index 00000000..3ec3933c --- /dev/null +++ b/code/modules/xenoarcheaology/boulder.dm @@ -0,0 +1,96 @@ +/obj/structure/boulder + name = "rocky debris" + desc = "Leftover rock from an excavation, it's been partially dug out already but there's still a lot to go." + icon = 'icons/obj/mining.dmi' + icon_state = "boulder1" + density = 1 + opacity = 1 + anchored = 1 + var/excavation_level = 0 + var/datum/geosample/geological_data + var/datum/artifact_find/artifact_find + var/last_act = 0 + +/obj/structure/boulder/New() + ..() + icon_state = "boulder[rand(1,4)]" + excavation_level = rand(5, 50) + +/obj/structure/boulder/Destroy() + qdel(geological_data) + qdel(artifact_find) + ..() + +/obj/structure/boulder/attackby(var/obj/item/I, var/mob/user) + if(istype(I, /obj/item/device/core_sampler)) + src.geological_data.artifact_distance = rand(-100,100) / 100 + src.geological_data.artifact_id = artifact_find.artifact_id + + var/obj/item/device/core_sampler/C = I + C.sample_item(src, user) + return + + if(istype(I, /obj/item/device/depth_scanner)) + var/obj/item/device/depth_scanner/C = I + C.scan_atom(user, src) + return + + if(istype(I, /obj/item/device/measuring_tape)) + var/obj/item/device/measuring_tape/P = I + user.visible_message("\The [user] extends \the [P] towards \the [src].", "You extend \the [P] towards \the [src].") + if(do_after(user, 15)) + to_chat(user, "\The [src] has been excavated to a depth of [src.excavation_level]cm.") + return + + if(istype(I, /obj/item/weapon/pickaxe)) + var/obj/item/weapon/pickaxe/P = I + + if(last_act + P.digspeed > world.time)//prevents message spam + return + last_act = world.time + + to_chat(user, "You start [P.drill_verb] [src].") + + if(!do_after(user, P.digspeed)) + return + + to_chat(user, "You finish [P.drill_verb] [src].") + excavation_level += P.excavation_amount + + if(excavation_level > 200) + //failure + user.visible_message("\The [src] suddenly crumbles away.", "\The [src] has disintegrated under your onslaught, any secrets it was holding are long gone.") + qdel(src) + return + + if(prob(excavation_level)) + //success + if(artifact_find) + var/spawn_type = artifact_find.artifact_find_type + var/obj/O = new spawn_type(get_turf(src)) + if(istype(O, /obj/machinery/artifact)) + var/obj/machinery/artifact/X = O + if(X.my_effect) + X.my_effect.artifact_id = artifact_find.artifact_id + src.visible_message("\The [src] suddenly crumbles away.") + else + user.visible_message("\The [src] suddenly crumbles away.", "\The [src] has been whittled away under your careful excavation, but there was nothing of interest inside.") + qdel(src) + +/obj/structure/boulder/Bumped(AM) + . = ..() + if(istype(AM,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = AM + var/obj/item/weapon/pickaxe/P = H.get_inactive_hand() + if(istype(P)) + src.attackby(P, H) + + else if(istype(AM,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = AM + if(istype(R.module_active,/obj/item/weapon/pickaxe)) + attackby(R.module_active,R) + + else if(istype(AM,/obj/mecha)) + var/obj/mecha/M = AM + if(istype(M.selected,/obj/item/mecha_parts/mecha_equipment/tool/drill)) + M.selected.action(src) \ No newline at end of file diff --git a/code/modules/xenoarcheaology/effect.dm b/code/modules/xenoarcheaology/effect.dm new file mode 100644 index 00000000..a4848577 --- /dev/null +++ b/code/modules/xenoarcheaology/effect.dm @@ -0,0 +1,142 @@ +/datum/artifact_effect + var/name = "unknown" + var/effect = EFFECT_TOUCH + var/effectrange = 4 + var/trigger = TRIGGER_TOUCH + var/atom/holder + var/activated = 0 + var/chargelevel = 0 + var/chargelevelmax = 10 + var/artifact_id = "" + var/effect_type = 0 + +/datum/artifact_effect/New(var/atom/location) + ..() + holder = location + effect = rand(0, MAX_EFFECT) + trigger = rand(0, MAX_TRIGGER) + + //this will be replaced by the excavation code later, but it's here just in case + artifact_id = "[pick("kappa","sigma","antaeres","beta","omicron","iota","epsilon","omega","gamma","delta","tau","alpha")]-[rand(100,999)]" + + //random charge time and distance + switch(pick(100;1, 50;2, 25;3)) + if(1) + //short range, short charge time + chargelevelmax = rand(3, 20) + effectrange = rand(1, 3) + if(2) + //medium range, medium charge time + chargelevelmax = rand(15, 40) + effectrange = rand(5, 15) + if(3) + //large range, long charge time + chargelevelmax = rand(20, 120) + effectrange = rand(20, 200) + +/datum/artifact_effect/proc/ToggleActivate(var/reveal_toggle = 1) + //so that other stuff happens first + spawn(0) + if(activated) + activated = 0 + else + activated = 1 + if(reveal_toggle && holder) + if(istype(holder, /obj/machinery/artifact)) + var/obj/machinery/artifact/A = holder + A.icon_state = "ano[A.icon_num][activated]" + var/display_msg + if(activated) + display_msg = pick("momentarily glows brightly!","distorts slightly for a moment!","flickers slightly!","vibrates!","shimmers slightly for a moment!") + else + display_msg = pick("grows dull!","fades in intensity!","suddenly becomes very still!","suddenly becomes very quiet!") + var/atom/toplevelholder = holder + while(!istype(toplevelholder.loc, /turf)) + toplevelholder = toplevelholder.loc + toplevelholder.visible_message("\icon[toplevelholder] [toplevelholder] [display_msg]") + +/datum/artifact_effect/proc/DoEffectTouch(var/mob/user) +/datum/artifact_effect/proc/DoEffectAura(var/atom/holder) +/datum/artifact_effect/proc/DoEffectPulse(var/atom/holder) +/datum/artifact_effect/proc/UpdateMove() + +/datum/artifact_effect/proc/process() + if(chargelevel < chargelevelmax) + chargelevel++ + + if(activated) + if(effect == EFFECT_AURA) + DoEffectAura() + else if(effect == EFFECT_PULSE && chargelevel >= chargelevelmax) + chargelevel = 0 + DoEffectPulse() + +/datum/artifact_effect/proc/getDescription() + . = "" + switch(effect_type) + if(EFFECT_ENERGY) + . += "Concentrated energy emissions" + if(EFFECT_PSIONIC) + . += "Intermittent psionic wavefront" + if(EFFECT_ELECTRO) + . += "Electromagnetic energy" + if(EFFECT_PARTICLE) + . += "High frequency particles" + if(EFFECT_ORGANIC) + . += "Organically reactive exotic particles" + if(EFFECT_BLUESPACE) + . += "Interdimensional/bluespace? phasing" + if(EFFECT_SYNTH) + . += "Atomic synthesis" + else + . += "Low level energy emissions" + + . += " have been detected " + + switch(effect) + if(EFFECT_TOUCH) + . += "interspersed throughout substructure and shell." + if(EFFECT_AURA) + . += "emitting in an ambient energy field." + if(EFFECT_PULSE) + . += "emitting in periodic bursts." + else + . += "emitting in an unknown way." + + . += "" + + switch(trigger) + if(TRIGGER_TOUCH, TRIGGER_WATER, TRIGGER_ACID, TRIGGER_VOLATILE, TRIGGER_TOXIN) + . += " Activation index involves physical interaction with artifact surface." + if(TRIGGER_FORCE, TRIGGER_ENERGY, TRIGGER_HEAT, TRIGGER_COLD) + . += " Activation index involves energetic interaction with artifact surface." + if(TRIGGER_PHORON, TRIGGER_OXY, TRIGGER_CO2, TRIGGER_NITRO) + . += " Activation index involves precise local atmospheric conditions." + else + . += " Unable to determine any data about activation trigger." + +//returns 0..1, with 1 being no protection and 0 being fully protected +/proc/GetAnomalySusceptibility(var/mob/living/carbon/human/H) + if(!istype(H)) + return 1 + + var/protected = 0 + + if(istype(H.wear_suit,/obj/item/clothing/suit/bio_suit/anomaly)) + protected += 0.6 + else if(istype(H.wear_suit,/obj/item/clothing/suit/space/void/excavation)) + protected += 0.5 + + if(istype(H.head,/obj/item/clothing/head/bio_hood/anomaly)) + protected += 0.3 + else if(istype(H.head,/obj/item/clothing/head/helmet/space/void/excavation)) + protected += 0.2 + + //latex gloves and science goggles also give a bit of bonus protection + if(istype(H.gloves,/obj/item/clothing/gloves/latex)) + protected += 0.1 + + if(istype(H.glasses,/obj/item/clothing/glasses/science)) + protected += 0.1 + + return 1 - protected diff --git a/code/modules/xenoarcheaology/effects/badfeeling.dm b/code/modules/xenoarcheaology/effects/badfeeling.dm new file mode 100644 index 00000000..ee5d0c84 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/badfeeling.dm @@ -0,0 +1,69 @@ +/datum/artifact_effect/badfeeling + name = "badfeeling" + effect_type = EFFECT_PSIONIC + var/list/messages = list("You feel worried.", + "Something doesn't feel right.", + "You get a strange feeling in your gut.", + "Your instincts are trying to warn you about something.", + "Someone just walked over your grave.", + "There's a strange feeling in the air.", + "There's a strange smell in the air.", + "The tips of your fingers feel tingly.", + "You feel witchy.", + "You have a terrible sense of foreboding.", + "You've got a bad feeling about this.", + "Your scalp prickles.", + "The light seems to flicker.", + "The shadows seem to lengthen.", + "The walls are getting closer.", + "Something is wrong") + + var/list/drastic_messages = list("You've got to get out of here!", + "Someone's trying to kill you!", + "There's something out there!", + "What's happening to you?", + "OH GOD!", + "HELP ME!") + +/datum/artifact_effect/badfeeling/DoEffectTouch(var/mob/user) + if(user) + if (istype(user, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(prob(50)) + if(prob(75)) + to_chat(H, "[pick(drastic_messages)]") + else + to_chat(H, "[pick(messages)]") + + if(prob(50)) + H.dizziness += rand(3,5) + +/datum/artifact_effect/badfeeling/DoEffectAura() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/human/H in range(src.effectrange,T)) + if(prob(5)) + if(prob(75)) + to_chat(H, "[pick(messages)]") + else + to_chat(H, "[pick(drastic_messages)]") + + if(prob(10)) + H.dizziness += rand(3,5) + return 1 + +/datum/artifact_effect/badfeeling/DoEffectPulse() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/human/H in range(src.effectrange,T)) + if(prob(50)) + if(prob(95)) + to_chat(H, "[pick(drastic_messages)]") + else + to_chat(H, "[pick(messages)]") + + if(prob(50)) + H.dizziness += rand(3,5) + else if(prob(25)) + H.dizziness += rand(5,15) + return 1 diff --git a/code/modules/xenoarcheaology/effects/cellcharge.dm b/code/modules/xenoarcheaology/effects/cellcharge.dm new file mode 100644 index 00000000..59b3a436 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/cellcharge.dm @@ -0,0 +1,46 @@ +//todo +/datum/artifact_effect/cellcharge + name = "cell charge" + effect_type = EFFECT_ELECTRO + var/last_message + +/datum/artifact_effect/cellcharge/DoEffectTouch(var/mob/user) + if(user) + if(istype(user, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = user + for (var/obj/item/weapon/cell/D in R.contents) + D.charge += rand() * 100 + 50 + to_chat(R, "SYSTEM ALERT: Large energy boost detected!") + return 1 + +/datum/artifact_effect/cellcharge/DoEffectAura() + if(holder) + var/turf/T = get_turf(holder) + for (var/obj/machinery/power/apc/C in range(200, T)) + for (var/obj/item/weapon/cell/B in C.contents) + B.charge += 25 + for (var/obj/machinery/power/smes/S in range (src.effectrange,src)) + S.charge += 25 + for (var/mob/living/silicon/robot/M in range(50, T)) + for (var/obj/item/weapon/cell/D in M.contents) + D.charge += 25 + if(world.time - last_message > 200) + to_chat(M, "SYSTEM ALERT: Energy boost detected!") + last_message = world.time + return 1 + +/datum/artifact_effect/cellcharge/DoEffectPulse() + if(holder) + var/turf/T = get_turf(holder) + for (var/obj/machinery/power/apc/C in range(200, T)) + for (var/obj/item/weapon/cell/B in C.contents) + B.charge += rand() * 100 + for (var/obj/machinery/power/smes/S in range (src.effectrange,src)) + S.charge += 250 + for (var/mob/living/silicon/robot/M in range(100, T)) + for (var/obj/item/weapon/cell/D in M.contents) + D.charge += rand() * 100 + if(world.time - last_message > 200) + to_chat(M, "SYSTEM ALERT: Energy boost detected!") + last_message = world.time + return 1 diff --git a/code/modules/xenoarcheaology/effects/celldrain.dm b/code/modules/xenoarcheaology/effects/celldrain.dm new file mode 100644 index 00000000..b77bcba5 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/celldrain.dm @@ -0,0 +1,48 @@ +//todo +/datum/artifact_effect/celldrain + name = "cell drain" + effect_type = EFFECT_ELECTRO + var/last_message + +/datum/artifact_effect/celldrain/DoEffectTouch(var/mob/user) + if(user) + if(istype(user, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = user + for (var/obj/item/weapon/cell/D in R.contents) + D.charge = max(D.charge - rand() * 100, 0) + to_chat(R, "SYSTEM ALERT: Energy drain detected!") + return 1 + + return 1 + +/datum/artifact_effect/celldrain/DoEffectAura() + if(holder) + var/turf/T = get_turf(holder) + for (var/obj/machinery/power/apc/C in range(200, T)) + for (var/obj/item/weapon/cell/B in C.contents) + B.charge = max(B.charge - 50,0) + for (var/obj/machinery/power/smes/S in range (src.effectrange,src)) + S.charge = max(S.charge - 100,0) + for (var/mob/living/silicon/robot/M in range(50, T)) + for (var/obj/item/weapon/cell/D in M.contents) + D.charge = max(D.charge - 50,0) + if(world.time - last_message > 200) + to_chat(M, "SYSTEM ALERT: Energy drain detected!") + last_message = world.time + return 1 + +/datum/artifact_effect/celldrain/DoEffectPulse() + if(holder) + var/turf/T = get_turf(holder) + for (var/obj/machinery/power/apc/C in range(200, T)) + for (var/obj/item/weapon/cell/B in C.contents) + B.charge = max(B.charge - rand() * 150,0) + for (var/obj/machinery/power/smes/S in range (src.effectrange,src)) + S.charge = max(S.charge - 250,0) + for (var/mob/living/silicon/robot/M in range(100, T)) + for (var/obj/item/weapon/cell/D in M.contents) + D.charge = max(D.charge - rand() * 150,0) + if(world.time - last_message > 200) + to_chat(M, "SYSTEM ALERT: Energy drain detected!") + last_message = world.time + return 1 diff --git a/code/modules/xenoarcheaology/effects/cold.dm b/code/modules/xenoarcheaology/effects/cold.dm new file mode 100644 index 00000000..1dd693f6 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/cold.dm @@ -0,0 +1,23 @@ +//inverse of /datum/artifact_effect/heat, the two effects split up for neatness' sake +/datum/artifact_effect/cold + name = "cold" + var/target_temp + +/datum/artifact_effect/cold/New() + ..() + target_temp = rand(0, 250) + effect = pick(EFFECT_TOUCH, EFFECT_AURA) + effect_type = pick(EFFECT_ORGANIC, EFFECT_BLUESPACE, EFFECT_SYNTH) + +/datum/artifact_effect/cold/DoEffectTouch(var/mob/user) + if(holder) + to_chat(user, "A chill passes up your spine!") + var/datum/gas_mixture/env = holder.loc.return_air() + if(env) + env.temperature = max(env.temperature - rand(5,50), 0) + +/datum/artifact_effect/cold/DoEffectAura() + if(holder) + var/datum/gas_mixture/env = holder.loc.return_air() + if(env && env.temperature > target_temp) + env.temperature -= pick(0, 0, 1) diff --git a/code/modules/xenoarcheaology/effects/dnaswitch.dm b/code/modules/xenoarcheaology/effects/dnaswitch.dm new file mode 100644 index 00000000..475ac0bf --- /dev/null +++ b/code/modules/xenoarcheaology/effects/dnaswitch.dm @@ -0,0 +1,52 @@ +//todo +/datum/artifact_effect/dnaswitch + name = "dnaswitch" + effect_type = EFFECT_ORGANIC + var/severity + +/datum/artifact_effect/dnaswitch/New() + ..() + if(effect == EFFECT_AURA) + severity = rand(5,30) + else + severity = rand(25,95) + +/datum/artifact_effect/dnaswitch/proc/get_feeling() + return pick(" feel a little different"," feel very strange","r stomach churns","r skin feels loose"," feel a stabbing pain in your head"," feel a tingling sensation in your chest","r entire body vibrates") + +/datum/artifact_effect/dnaswitch/DoEffectTouch(var/mob/toucher) + var/weakness = GetAnomalySusceptibility(toucher) + if(ishuman(toucher) && prob(weakness * 100)) + to_chat(toucher, "You[get_feeling()].") + if(prob(75)) + scramble(1, toucher, weakness * severity) + else + scramble(0, toucher, weakness * severity) + return 1 + +/datum/artifact_effect/dnaswitch/DoEffectAura() + if(holder) + var/turf/T = get_turf(holder) + for(var/mob/living/carbon/human/H in range(src.effectrange,T)) + var/weakness = GetAnomalySusceptibility(H) + if(prob(weakness * 100)) + if(prob(30)) + to_chat(H, "You[get_feeling()].") + if(prob(50)) + scramble(1, H, weakness * severity) + else + scramble(0, H, weakness * severity) + +/datum/artifact_effect/dnaswitch/DoEffectPulse() + if(holder) + var/turf/T = get_turf(holder) + for(var/mob/living/carbon/human/H in range(200, T)) + var/weakness = GetAnomalySusceptibility(H) + if(prob(weakness * 100)) + if(prob(75)) + to_chat(H, "You[get_feeling()].") + if(prob(25)) + if(prob(75)) + scramble(1, H, weakness * severity) + else + scramble(0, H, weakness * severity) diff --git a/code/modules/xenoarcheaology/effects/emp.dm b/code/modules/xenoarcheaology/effects/emp.dm new file mode 100644 index 00000000..d6d402ef --- /dev/null +++ b/code/modules/xenoarcheaology/effects/emp.dm @@ -0,0 +1,13 @@ +/datum/artifact_effect/emp + name = "emp" + effect_type = EFFECT_ELECTRO + +/datum/artifact_effect/emp/New() + ..() + effect = EFFECT_PULSE + +/datum/artifact_effect/emp/DoEffectPulse() + if(holder) + var/turf/T = get_turf(holder) + empulse(T, effectrange/2, effectrange) + return 1 diff --git a/code/modules/xenoarcheaology/effects/forcefield.dm b/code/modules/xenoarcheaology/effects/forcefield.dm new file mode 100644 index 00000000..c2576aca --- /dev/null +++ b/code/modules/xenoarcheaology/effects/forcefield.dm @@ -0,0 +1,87 @@ +/datum/artifact_effect/forcefield + name = "force field" + var/list/created_field = list() + effect_type = EFFECT_PARTICLE + +/datum/artifact_effect/forcefield/New() + ..() + trigger = TRIGGER_TOUCH + +/datum/artifact_effect/forcefield/Destroy() + for(var/obj/effect/energy_field/F in created_field) + created_field.Remove(F) + qdel(F) + . = ..() + +/datum/artifact_effect/forcefield/ToggleActivate() + ..() + if(created_field.len) + for(var/obj/effect/energy_field/F in created_field) + created_field.Remove(F) + qdel(F) + else if(holder) + var/turf/T = get_turf(holder) + if(!istype(T)) + return + while(created_field.len < 16) + var/obj/effect/energy_field/E = new (locate(T.x,T.y,T.z)) + created_field.Add(E) + E.strength = 1 + E.set_density(1) + E.anchored = 1 + E.set_invisibility(0) + spawn(10) + UpdateMove() + return 1 + +/datum/artifact_effect/forcefield/process() + ..() + for(var/obj/effect/energy_field/E in created_field) + if(E.strength < 1) + E.Strengthen(0.15) + else if(E.strength < 5) + E.Strengthen(0.25) + +/datum/artifact_effect/forcefield/UpdateMove() + if(created_field.len && holder) + var/turf/T = get_turf(holder) + while(created_field.len < 16) + //for now, just instantly respawn the fields when they get destroyed + var/obj/effect/energy_field/E = new (locate(T.x,T.y,T)) + created_field.Add(E) + E.anchored = 1 + E.set_density(1) + E.set_invisibility(0) + + var/obj/effect/energy_field/E = created_field[1] + E.forceMove(locate(T.x + 2,T.y + 2,T.z)) + E = created_field[2] + E.forceMove(locate(T.x + 2,T.y + 1,T.z)) + E = created_field[3] + E.forceMove(locate(T.x + 2,T.y,T.z)) + E = created_field[4] + E.forceMove(locate(T.x + 2,T.y - 1,T.z)) + E = created_field[5] + E.forceMove(locate(T.x + 2,T.y - 2,T.z)) + E = created_field[6] + E.forceMove(locate(T.x + 1,T.y + 2,T.z)) + E = created_field[7] + E.forceMove(locate(T.x + 1,T.y - 2,T.z)) + E = created_field[8] + E.forceMove(locate(T.x,T.y + 2,T.z)) + E = created_field[9] + E.forceMove(locate(T.x,T.y - 2,T.z)) + E = created_field[10] + E.forceMove(locate(T.x - 1,T.y + 2,T.z)) + E = created_field[11] + E.forceMove(locate(T.x - 1,T.y - 2,T.z)) + E = created_field[12] + E.forceMove(locate(T.x - 2,T.y + 2,T.z)) + E = created_field[13] + E.forceMove(locate(T.x - 2,T.y + 1,T.z)) + E = created_field[14] + E.forceMove(locate(T.x - 2,T.y,T.z)) + E = created_field[15] + E.forceMove(locate(T.x - 2,T.y - 1,T.z)) + E = created_field[16] + E.forceMove(locate(T.x - 2,T.y - 2,T.z)) diff --git a/code/modules/xenoarcheaology/effects/gasco2.dm b/code/modules/xenoarcheaology/effects/gasco2.dm new file mode 100644 index 00000000..264dca73 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/gasco2.dm @@ -0,0 +1,19 @@ +/datum/artifact_effect/gasco2 + name = "CO2 creation" + +/datum/artifact_effect/gasco2/New() + ..() + effect = pick(EFFECT_TOUCH, EFFECT_AURA) + effect_type = pick(EFFECT_BLUESPACE, EFFECT_SYNTH) + +/datum/artifact_effect/gasco2/DoEffectTouch(var/mob/user) + if(holder) + var/turf/holder_loc = holder.loc + if(istype(holder_loc)) + holder_loc.assume_gas("carbon_dioxide", rand(2, 15)) + +/datum/artifact_effect/gasco2/DoEffectAura() + if(holder) + var/turf/holder_loc = holder.loc + if(istype(holder_loc)) + holder_loc.assume_gas("carbon_dioxide", pick(0, 0, 0.1, rand())) diff --git a/code/modules/xenoarcheaology/effects/gasnitro.dm b/code/modules/xenoarcheaology/effects/gasnitro.dm new file mode 100644 index 00000000..42b440fc --- /dev/null +++ b/code/modules/xenoarcheaology/effects/gasnitro.dm @@ -0,0 +1,19 @@ +/datum/artifact_effect/gasnitro + name = "N2 creation" + +/datum/artifact_effect/gasnitro/New() + ..() + effect = pick(EFFECT_TOUCH, EFFECT_AURA) + effect_type = pick(EFFECT_BLUESPACE, EFFECT_SYNTH) + +/datum/artifact_effect/gasnitro/DoEffectTouch(var/mob/user) + if(holder) + var/turf/holder_loc = holder.loc + if(istype(holder_loc)) + holder_loc.assume_gas("nitrogen", rand(2, 15)) + +/datum/artifact_effect/gasnitro/DoEffectAura() + if(holder) + var/turf/holder_loc = holder.loc + if(istype(holder_loc)) + holder_loc.assume_gas("nitrogen", pick(0, 0, 0.1, rand())) diff --git a/code/modules/xenoarcheaology/effects/gasoxy.dm b/code/modules/xenoarcheaology/effects/gasoxy.dm new file mode 100644 index 00000000..bb159509 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/gasoxy.dm @@ -0,0 +1,19 @@ +/datum/artifact_effect/gasoxy + name = "O2 creation" + +/datum/artifact_effect/gasoxy/New() + ..() + effect = pick(EFFECT_TOUCH, EFFECT_AURA) + effect_type = pick(EFFECT_BLUESPACE, EFFECT_SYNTH) + +/datum/artifact_effect/gasoxy/DoEffectTouch(var/mob/user) + if(holder) + var/turf/holder_loc = holder.loc + if(istype(holder_loc)) + holder_loc.assume_gas("oxygen", rand(2, 15)) + +/datum/artifact_effect/gasoxy/DoEffectAura() + if(holder) + var/turf/holder_loc = holder.loc + if(istype(holder_loc)) + holder_loc.assume_gas("oxygen", pick(0, 0, 0.1, rand())) diff --git a/code/modules/xenoarcheaology/effects/gasphoron.dm b/code/modules/xenoarcheaology/effects/gasphoron.dm new file mode 100644 index 00000000..b84296fb --- /dev/null +++ b/code/modules/xenoarcheaology/effects/gasphoron.dm @@ -0,0 +1,19 @@ +/datum/artifact_effect/gasphoron + name = "phoron creation" + +/datum/artifact_effect/gasphoron/New() + ..() + effect = pick(EFFECT_TOUCH, EFFECT_AURA) + effect_type = pick(EFFECT_BLUESPACE, EFFECT_SYNTH) + +/datum/artifact_effect/gasphoron/DoEffectTouch(var/mob/user) + if(holder) + var/turf/holder_loc = holder.loc + if(istype(holder_loc)) + holder_loc.assume_gas("phoron", rand(2, 15)) + +/datum/artifact_effect/gasphoron/DoEffectAura() + if(holder) + var/turf/holder_loc = holder.loc + if(istype(holder_loc)) + holder_loc.assume_gas("phoron", pick(0, 0, 0.1, rand())) diff --git a/code/modules/xenoarcheaology/effects/gassleeping.dm b/code/modules/xenoarcheaology/effects/gassleeping.dm new file mode 100644 index 00000000..85378804 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/gassleeping.dm @@ -0,0 +1,19 @@ +/datum/artifact_effect/gassleeping + name = "N2O creation" + +/datum/artifact_effect/gassleeping/New() + ..() + effect = pick(EFFECT_TOUCH, EFFECT_AURA) + effect_type = pick(EFFECT_BLUESPACE, EFFECT_SYNTH) + +/datum/artifact_effect/gassleeping/DoEffectTouch(var/mob/user) + if(holder) + var/turf/holder_loc = holder.loc + if(istype(holder_loc)) + holder_loc.assume_gas("sleeping_agent", rand(2, 15)) + +/datum/artifact_effect/gassleeping/DoEffectAura() + if(holder) + var/turf/holder_loc = holder.loc + if(istype(holder_loc)) + holder_loc.assume_gas("sleeping_agent", pick(0, 0, 0.1, rand())) diff --git a/code/modules/xenoarcheaology/effects/goodfeeling.dm b/code/modules/xenoarcheaology/effects/goodfeeling.dm new file mode 100644 index 00000000..c5d05adc --- /dev/null +++ b/code/modules/xenoarcheaology/effects/goodfeeling.dm @@ -0,0 +1,67 @@ +/datum/artifact_effect/goodfeeling + name = "good feeling" + effect_type = EFFECT_PSIONIC + var/list/messages = list("You feel good.", + "Everything seems to be going alright", + "You've got a good feeling about this", + "Your instincts tell you everything is going to be getting better.", + "There's a good feeling in the air.", + "Something smells... good.", + "The tips of your fingers feel tingly.", + "You've got a good feeling about this.", + "You feel happy.", + "You fight the urge to smile.", + "Your scalp prickles.", + "All the colours seem a bit more vibrant.", + "Everything seems a little lighter.", + "The troubles of the world seem to fade away.") + + var/list/drastic_messages = list("You want to hug everyone you meet!", + "Everything is going so well!", + "You feel euphoric.", + "You feel giddy.", + "You're so happy suddenly, you almost want to dance and sing.", + "You feel like the world is out to help you.") + +/datum/artifact_effect/goodfeeling/DoEffectTouch(var/mob/user) + if(user) + if (istype(user, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(prob(50)) + if(prob(75)) + to_chat(H, "[pick(drastic_messages)]") + else + to_chat(H, "[pick(messages)]") + + if(prob(50)) + H.dizziness += rand(3,5) + +/datum/artifact_effect/goodfeeling/DoEffectAura() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/human/H in range(src.effectrange,T)) + if(prob(5)) + if(prob(75)) + to_chat(H, "[pick(messages)]") + else + to_chat(H, "[pick(drastic_messages)]") + + if(prob(5)) + H.dizziness += rand(3,5) + return 1 + +/datum/artifact_effect/goodfeeling/DoEffectPulse() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/human/H in range(src.effectrange,T)) + if(prob(50)) + if(prob(95)) + to_chat(H, "[pick(drastic_messages)]") + else + to_chat(H, "[pick(messages)]") + + if(prob(50)) + H.dizziness += rand(3,5) + else if(prob(25)) + H.dizziness += rand(5,15) + return 1 diff --git a/code/modules/xenoarcheaology/effects/heal.dm b/code/modules/xenoarcheaology/effects/heal.dm new file mode 100644 index 00000000..c7428583 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/heal.dm @@ -0,0 +1,63 @@ +/datum/artifact_effect/heal + name = "heal" + effect_type = EFFECT_ORGANIC + +/datum/artifact_effect/heal/DoEffectTouch(var/mob/toucher) + //todo: check over this properly + if(toucher && iscarbon(toucher)) + var/weakness = GetAnomalySusceptibility(toucher) + if(prob(weakness * 100)) + var/mob/living/carbon/C = toucher + to_chat(C, "You feel a soothing energy invigorate you.") + + if(ishuman(toucher)) + var/mob/living/carbon/human/H = toucher + for(var/obj/item/organ/external/affecting in H.organs) + if(affecting && istype(affecting)) + affecting.heal_damage(25 * weakness, 25 * weakness) + //H:heal_organ_damage(25, 25) + H.vessel.add_reagent(/datum/reagent/blood,5) + H.nutrition += 50 * weakness + H.adjustBrainLoss(-25 * weakness) + H.radiation -= min(H.radiation, 25 * weakness) + H.bodytemperature = initial(H.bodytemperature) + H.fixblood() + // + C.adjustOxyLoss(-25 * weakness) + C.adjustToxLoss(-25 * weakness) + C.adjustBruteLoss(-25 * weakness) + C.adjustFireLoss(-25 * weakness) + // + C.regenerate_icons() + return 1 + +/datum/artifact_effect/heal/DoEffectAura() + //todo: check over this properly + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/C in range(src.effectrange,T)) + var/weakness = GetAnomalySusceptibility(C) + if(prob(weakness * 100)) + if(prob(10)) + to_chat(C, "You feel a soothing energy radiating from something nearby.") + C.adjustBruteLoss(-1 * weakness) + C.adjustFireLoss(-1 * weakness) + C.adjustToxLoss(-1 * weakness) + C.adjustOxyLoss(-1 * weakness) + C.adjustBrainLoss(-1 * weakness) + C.updatehealth() + +/datum/artifact_effect/heal/DoEffectPulse() + //todo: check over this properly + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/C in range(src.effectrange,T)) + var/weakness = GetAnomalySusceptibility(C) + if(prob(weakness * 100)) + to_chat(C, "A wave of energy invigorates you.") + C.adjustBruteLoss(-5 * weakness) + C.adjustFireLoss(-5 * weakness) + C.adjustToxLoss(-5 * weakness) + C.adjustOxyLoss(-5 * weakness) + C.adjustBrainLoss(-5 * weakness) + C.updatehealth() diff --git a/code/modules/xenoarcheaology/effects/heat.dm b/code/modules/xenoarcheaology/effects/heat.dm new file mode 100644 index 00000000..e1afc0b0 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/heat.dm @@ -0,0 +1,23 @@ +//inverse of /datum/artifact_effect/cold, the two effects split up for neatness' sake +/datum/artifact_effect/heat + name = "heat" + var/target_temp + +/datum/artifact_effect/heat/New() + ..() + effect = pick(EFFECT_TOUCH, EFFECT_AURA) + effect_type = pick(EFFECT_ORGANIC, EFFECT_BLUESPACE, EFFECT_SYNTH) + target_temp = rand(300, 600) + +/datum/artifact_effect/heat/DoEffectTouch(var/mob/user) + if(holder) + to_chat(user, "You feel a wave of heat travel up your spine!") + var/datum/gas_mixture/env = holder.loc.return_air() + if(env) + env.temperature += rand(5,50) + +/datum/artifact_effect/heat/DoEffectAura() + if(holder) + var/datum/gas_mixture/env = holder.loc.return_air() + if(env && env.temperature < target_temp) + env.temperature += pick(0, 0, 1) diff --git a/code/modules/xenoarcheaology/effects/hurt.dm b/code/modules/xenoarcheaology/effects/hurt.dm new file mode 100644 index 00000000..229a0a6d --- /dev/null +++ b/code/modules/xenoarcheaology/effects/hurt.dm @@ -0,0 +1,48 @@ +/datum/artifact_effect/hurt + name = "hurt" + effect_type = EFFECT_ORGANIC + +/datum/artifact_effect/hurt/DoEffectTouch(var/mob/toucher) + if(toucher) + var/weakness = GetAnomalySusceptibility(toucher) + if(iscarbon(toucher) && prob(weakness * 100)) + var/mob/living/carbon/C = toucher + to_chat(C, "A painful discharge of energy strikes you!") + C.adjustOxyLoss(rand(5,25) * weakness) + C.adjustToxLoss(rand(5,25) * weakness) + C.adjustBruteLoss(rand(5,25) * weakness) + C.adjustFireLoss(rand(5,25) * weakness) + C.adjustBrainLoss(rand(1,5) * weakness) + C.apply_effect(25 * weakness, IRRADIATE, blocked = C.getarmor(null, "rad")) + C.nutrition -= min(50 * weakness, C.nutrition) + C.make_dizzy(6 * weakness) + C.weakened += 6 * weakness + +/datum/artifact_effect/hurt/DoEffectAura() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/C in range(src.effectrange,T)) + var/weakness = GetAnomalySusceptibility(C) + if(prob(weakness * 100)) + if(prob(10)) + to_chat(C, "You feel a painful force radiating from something nearby.") + C.adjustBruteLoss(1 * weakness) + C.adjustFireLoss(1 * weakness) + C.adjustToxLoss(1 * weakness) + C.adjustOxyLoss(1 * weakness) + C.adjustBrainLoss(0.1 * weakness) + C.updatehealth() + +/datum/artifact_effect/hurt/DoEffectPulse() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/C in range(effectrange, T)) + var/weakness = GetAnomalySusceptibility(C) + if(prob(weakness * 100)) + to_chat(C, "A wave of painful energy strikes you!") + C.adjustBruteLoss(3 * weakness) + C.adjustFireLoss(3 * weakness) + C.adjustToxLoss(3 * weakness) + C.adjustOxyLoss(3 * weakness) + C.adjustBrainLoss(0.1 * weakness) + C.updatehealth() diff --git a/code/modules/xenoarcheaology/effects/radiate.dm b/code/modules/xenoarcheaology/effects/radiate.dm new file mode 100644 index 00000000..14f703fc --- /dev/null +++ b/code/modules/xenoarcheaology/effects/radiate.dm @@ -0,0 +1,25 @@ +/datum/artifact_effect/radiate + name = "radiation" + var/radiation_strength + var/radiation_range + +/datum/artifact_effect/radiate/New() + ..() + radiation_strength = rand(10, 50) + effect_type = pick(EFFECT_PARTICLE, EFFECT_ORGANIC) + +/datum/artifact_effect/radiate/DoEffectTouch(var/mob/living/user) + if(user) + user.apply_effect(radiation_strength * 2,IRRADIATE, blocked = user.getarmor(null, "rad")) + user.updatehealth() + return 1 + +/datum/artifact_effect/radiate/DoEffectAura() + if(holder) + radiation_repository.radiate(holder, radiation_strength) + return 1 + +/datum/artifact_effect/radiate/DoEffectPulse() + if(holder) + radiation_repository.radiate(holder, radiation_strength * rand(5, 10)) //Need to get feedback on this + return 1 diff --git a/code/modules/xenoarcheaology/effects/roboheal.dm b/code/modules/xenoarcheaology/effects/roboheal.dm new file mode 100644 index 00000000..50fd6a3f --- /dev/null +++ b/code/modules/xenoarcheaology/effects/roboheal.dm @@ -0,0 +1,40 @@ +/datum/artifact_effect/roboheal + name = "robotic healing" + var/last_message + +/datum/artifact_effect/roboheal/New() + ..() + effect_type = pick(EFFECT_ELECTRO, EFFECT_PARTICLE) + +/datum/artifact_effect/roboheal/DoEffectTouch(var/mob/user) + if(user) + if (istype(user, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = user + to_chat(R, "Your systems report damaged components mending by themselves!") + R.adjustBruteLoss(rand(-10,-30)) + R.adjustFireLoss(rand(-10,-30)) + return 1 + +/datum/artifact_effect/roboheal/DoEffectAura() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/silicon/robot/M in range(src.effectrange,T)) + if(world.time - last_message > 200) + to_chat(M, "SYSTEM ALERT: Beneficial energy field detected!") + last_message = world.time + M.adjustBruteLoss(-1) + M.adjustFireLoss(-1) + M.updatehealth() + return 1 + +/datum/artifact_effect/roboheal/DoEffectPulse() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/silicon/robot/M in range(src.effectrange,T)) + if(world.time - last_message > 200) + to_chat(M, "SYSTEM ALERT: Structural damage has been repaired by energy pulse!") + last_message = world.time + M.adjustBruteLoss(-10) + M.adjustFireLoss(-10) + M.updatehealth() + return 1 diff --git a/code/modules/xenoarcheaology/effects/robohurt.dm b/code/modules/xenoarcheaology/effects/robohurt.dm new file mode 100644 index 00000000..72461b29 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/robohurt.dm @@ -0,0 +1,40 @@ +/datum/artifact_effect/robohurt + name = "robotic harm" + var/last_message + +/datum/artifact_effect/robohurt/New() + ..() + effect_type = pick(EFFECT_ELECTRO, EFFECT_PARTICLE) + +/datum/artifact_effect/robohurt/DoEffectTouch(var/mob/user) + if(user) + if (istype(user, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = user + to_chat(R, "Your systems report severe damage has been inflicted!") + R.adjustBruteLoss(rand(10,50)) + R.adjustFireLoss(rand(10,50)) + return 1 + +/datum/artifact_effect/robohurt/DoEffectAura() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/silicon/robot/M in range(src.effectrange,T)) + if(world.time - last_message > 200) + to_chat(M, "SYSTEM ALERT: Harmful energy field detected!") + last_message = world.time + M.adjustBruteLoss(1) + M.adjustFireLoss(1) + M.updatehealth() + return 1 + +/datum/artifact_effect/robohurt/DoEffectPulse() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/silicon/robot/M in range(src.effectrange,T)) + if(world.time - last_message > 200) + to_chat(M, "SYSTEM ALERT: Structural damage inflicted by energy pulse!") + last_message = world.time + M.adjustBruteLoss(10) + M.adjustFireLoss(10) + M.updatehealth() + return 1 diff --git a/code/modules/xenoarcheaology/effects/sleepy.dm b/code/modules/xenoarcheaology/effects/sleepy.dm new file mode 100644 index 00000000..f7b83169 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/sleepy.dm @@ -0,0 +1,47 @@ +//todo +/datum/artifact_effect/sleepy + name = "sleepy" + +/datum/artifact_effect/sleepy/New() + ..() + effect_type = pick(EFFECT_PSIONIC, EFFECT_ORGANIC) + +/datum/artifact_effect/sleepy/DoEffectTouch(var/mob/toucher) + if(toucher) + var/weakness = GetAnomalySusceptibility(toucher) + if(ishuman(toucher) && prob(weakness * 100)) + var/mob/living/carbon/human/H = toucher + to_chat(H, pick("You feel like taking a nap.","You feel a yawn coming on.","You feel a little tired.")) + H.drowsyness = min(H.drowsyness + rand(5,25) * weakness, 50 * weakness) + H.eye_blurry = min(H.eye_blurry + rand(1,3) * weakness, 50 * weakness) + return 1 + else if(isrobot(toucher)) + to_chat(toucher, "SYSTEM ALERT: CPU cycles slowing down.") + return 1 + +/datum/artifact_effect/sleepy/DoEffectAura() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/human/H in range(src.effectrange,T)) + var/weakness = GetAnomalySusceptibility(H) + if(prob(weakness * 100)) + if(prob(10)) + to_chat(H, pick("You feel like taking a nap.","You feel a yawn coming on.","You feel a little tired.")) + H.drowsyness = min(H.drowsyness + 1 * weakness, 25 * weakness) + H.eye_blurry = min(H.eye_blurry + 1 * weakness, 25 * weakness) + for (var/mob/living/silicon/robot/R in range(src.effectrange,holder)) + to_chat(R, "SYSTEM ALERT: CPU cycles slowing down.") + return 1 + +/datum/artifact_effect/sleepy/DoEffectPulse() + if(holder) + var/turf/T = get_turf(holder) + for(var/mob/living/carbon/human/H in range(src.effectrange, T)) + var/weakness = GetAnomalySusceptibility(H) + if(prob(weakness * 100)) + to_chat(H, pick("You feel like taking a nap.","You feel a yawn coming on.","You feel a little tired.")) + H.drowsyness = min(H.drowsyness + rand(5,15) * weakness, 50 * weakness) + H.eye_blurry = min(H.eye_blurry + rand(5,15) * weakness, 50 * weakness) + for (var/mob/living/silicon/robot/R in range(src.effectrange,holder)) + to_chat(R, "SYSTEM ALERT: CPU cycles slowing down.") + return 1 diff --git a/code/modules/xenoarcheaology/effects/stun.dm b/code/modules/xenoarcheaology/effects/stun.dm new file mode 100644 index 00000000..fd0a3a62 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/stun.dm @@ -0,0 +1,42 @@ +/datum/artifact_effect/stun + name = "stun" + +/datum/artifact_effect/stun/New() + ..() + effect_type = pick(EFFECT_PSIONIC, EFFECT_ORGANIC) + +/datum/artifact_effect/stun/DoEffectTouch(var/mob/toucher) + if(toucher && iscarbon(toucher)) + var/mob/living/carbon/C = toucher + var/susceptibility = GetAnomalySusceptibility(C) + if(prob(susceptibility * 100)) + to_chat(C, "A powerful force overwhelms your consciousness.") + C.Weaken(rand(1,10) * susceptibility) + C.stuttering += 30 * susceptibility + C.Stun(rand(1,10) * susceptibility) + +/datum/artifact_effect/stun/DoEffectAura() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/C in range(src.effectrange,T)) + var/susceptibility = GetAnomalySusceptibility(C) + if(prob(10 * susceptibility)) + to_chat(C, "Your body goes numb for a moment.") + C.Weaken(2) + C.stuttering += 2 + if(prob(10)) + C.Stun(1) + else if(prob(10)) + to_chat(C, "You feel numb.") + +/datum/artifact_effect/stun/DoEffectPulse() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/C in range(src.effectrange,T)) + var/susceptibility = GetAnomalySusceptibility(C) + if(prob(100 * susceptibility)) + to_chat(C, "A wave of energy overwhelms your senses!") + C.SetWeakened(4 * susceptibility) + C.stuttering = 4 * susceptibility + if(prob(10)) + C.SetStunned(1 * susceptibility) diff --git a/code/modules/xenoarcheaology/effects/teleport.dm b/code/modules/xenoarcheaology/effects/teleport.dm new file mode 100644 index 00000000..603c4100 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/teleport.dm @@ -0,0 +1,58 @@ +/datum/artifact_effect/teleport + name = "teleport" + effect_type = EFFECT_BLUESPACE + +/datum/artifact_effect/teleport/DoEffectTouch(var/mob/user) + var/weakness = GetAnomalySusceptibility(user) + if(prob(100 * weakness)) + to_chat(user, "You are suddenly zapped away elsewhere!") + if (user.buckled) + user.buckled.unbuckle_mob() + + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(3, 0, get_turf(user)) + sparks.start() + + user.Move(pick(trange(50, get_turf(holder)))) + + sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(3, 0, user.loc) + sparks.start() + +/datum/artifact_effect/teleport/DoEffectAura() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/M in range(src.effectrange,T)) + var/weakness = GetAnomalySusceptibility(M) + if(prob(100 * weakness)) + to_chat(M, "You are displaced by a strange force!") + if(M.buckled) + M.buckled.unbuckle_mob() + + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(3, 0, get_turf(M)) + sparks.start() + + M.Move(pick(trange(50, T))) + sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(3, 0, M.loc) + sparks.start() + +/datum/artifact_effect/teleport/DoEffectPulse() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/M in range(src.effectrange, T)) + var/weakness = GetAnomalySusceptibility(M) + if(prob(100 * weakness)) + to_chat(M, "You are displaced by a strange force!") + if(M.buckled) + M.buckled.unbuckle_mob() + + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(3, 0, get_turf(M)) + sparks.start() + + M.Move(pick(trange(50, T))) + sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(3, 0, M.loc) + sparks.start() diff --git a/code/modules/xenoarcheaology/finds/find_spawning.dm b/code/modules/xenoarcheaology/finds/find_spawning.dm new file mode 100644 index 00000000..8faad7bf --- /dev/null +++ b/code/modules/xenoarcheaology/finds/find_spawning.dm @@ -0,0 +1,544 @@ +/proc/get_archeological_find_by_findtype(var/find_type) + for(var/T in typesof(/obj/item/weapon/archaeological_find)) + var/obj/item/weapon/archaeological_find/F = T + if(find_type == initial(F.find_type)) + return T + return /obj/item/weapon/archaeological_find + +/obj/item/weapon/archaeological_find + name = "object" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "unknown2" + var/find_type = ARCHAEO_UNKNOWN + var/item_type = "object" + var/apply_prefix = 1 + var/apply_material_decorations = 1 + var/apply_image_decorations = 0 + var/additional_desc + +/obj/item/weapon/archaeological_find/Initialize() + . = ..() + var/obj/item/I = spawn_item() + + var/source_material = "" + var/material_descriptor = "" + if(prob(40)) + material_descriptor = pick("rusted","dusty","archaic","fragile") + source_material = pick("cordite","quadrinium",DEFAULT_WALL_MATERIAL,"titanium","aluminium","ferritic-alloy","plasteel","duranium") + + var/decorations = "" + if(apply_material_decorations) + source_material = pick("cordite","quadrinium",DEFAULT_WALL_MATERIAL,"titanium","aluminium","ferritic-alloy","plasteel","duranium") + desc = "A [material_descriptor ? "[material_descriptor] " : ""][item_type] made of [source_material], all craftsmanship is of [pick("the lowest","low","average","high","the highest")] quality." + + var/list/descriptors = list() + if(prob(30)) + descriptors.Add("is encrusted with [pick("","synthetic ","multi-faceted ","uncut ","sparkling ") + pick("rubies","emeralds","diamonds","opals","lapiz lazuli")]") + if(prob(30)) + descriptors.Add("is studded with [pick("gold","silver","aluminium","titanium")]") + if(prob(30)) + descriptors.Add("is encircled with bands of [pick("quadrinium","cordite","ferritic-alloy","plasteel","duranium")]") + if(prob(30)) + descriptors.Add("menaces with spikes of [pick("solid phoron","uranium","white pearl","black steel")]") + if(descriptors.len > 0) + decorations = "It " + for(var/index=1, index <= descriptors.len, index++) + if(index > 1) + if(index == descriptors.len) + decorations += " and " + else + decorations += ", " + decorations += descriptors[index] + decorations += "." + if(decorations) + desc += " " + decorations + + var/engravings = "" + if(apply_image_decorations) + var/obj/effect/overmap/sector/exoplanet/E = map_sectors["[z]"] + engravings = "[pick("Engraved","Carved","Etched")] on the item is [pick("an image of","a frieze of","a depiction of")] " + if(istype(E)) + engravings += E.get_engravings() + else + engravings += "[pick("an alien humanoid","an amorphic blob","a short, hairy being","a rodent-like creature","a robot","a primate","a reptilian alien","an unidentifiable object","a statue","a starship","unusual devices","a structure")] \ + [pick("surrounded by","being held aloft by","being struck by","being examined by","communicating with")] \ + [pick("alien humanoids","amorphic blobs","short, hairy beings","rodent-like creatures","robots","primates","reptilian aliens")]" + if(prob(50)) + engravings += ", [pick("they seem to be enjoying themselves","they seem extremely angry","they look pensive","they are making gestures of supplication","the scene is one of subtle horror","the scene conveys a sense of desperation","the scene is completely bizarre")]" + engravings += "." + + if(desc) + desc += " " + desc += engravings + + if(apply_prefix) + name = "[pick("strange ","ancient ","alien ")][item_type]" + else + name = item_type + + if(desc) + desc += " " + desc += additional_desc + if(!desc) + desc = "This item is completely [pick("alien","bizarre")]." + + //icon and icon_state should have already been set + I.SetName(name) + I.desc = desc + + if(prob(5)) + I.talking_atom = new(I) + + return INITIALIZE_HINT_QDEL + +/obj/item/weapon/archaeological_find/proc/spawn_item() + var/obj/item/weapon/material/kitchen/utensil/fork/F = new(loc) + F.icon = 'icons/obj/xenoarchaeology.dmi' + F.icon_state = "unknown[rand(1,4)]" + return F + +/obj/item/weapon/archaeological_find/bowl + find_type = ARCHAEO_BOWL + item_type = "bowl" + icon_state = "bowl" + apply_image_decorations = 1 + +/obj/item/weapon/archaeological_find/bowl/spawn_item() + var/obj/item/weapon/reagent_containers/R + if(prob(33)) + R = new /obj/item/weapon/reagent_containers/glass/replenishing(loc) + else + R = new /obj/item/weapon/reagent_containers/glass/beaker(loc) + R.icon = 'icons/obj/xenoarchaeology.dmi' + R.icon_state = "bowl" + if(prob(20)) + additional_desc = "There appear to be [pick("dark","faintly glowing","pungent","bright")] [pick("red","purple","green","blue")] stains inside." + return R + +/obj/item/weapon/archaeological_find/bowl/urn + find_type = ARCHAEO_URN + item_type = "urn" + icon_state = "urn" + +/obj/item/weapon/archaeological_find/bowl/urn/spawn_item() + var/obj/item/I = ..() + I.icon_state = "urn" + if(prob(20)) + additional_desc = "It [pick("whispers faintly","makes a quiet roaring sound","whistles softly","thrums quietly","throbs")] if you put it to your ear." + else + additional_desc = null + return I + +/obj/item/weapon/archaeological_find/cutlery + item_type = "cutlery" + find_type = ARCHAEO_CUTLERY + +/obj/item/weapon/archaeological_find/cutlery/spawn_item() + var/obj/item/new_item + if(prob(25)) + new_item = new /obj/item/weapon/material/kitchen/utensil/fork(loc) + else if(prob(50)) + new_item = new /obj/item/weapon/material/kitchen/utensil/knife(loc) + else + new_item = new /obj/item/weapon/material/kitchen/utensil/spoon(loc) + additional_desc = "[pick("It's like no [item_type] you've ever seen before",\ + "It's a mystery how anyone is supposed to eat with this",\ + "You wonder what the creator's mouth was shaped like")]." + return new_item + +/obj/item/weapon/archaeological_find/statuette + item_type = "statuette" + icon_state = "statuette" + find_type = ARCHAEO_STATUETTE + +/obj/item/weapon/archaeological_find/statuette/spawn_item() + var/obj/item/new_item + if(prob(25)) + new_item = new /obj/item/weapon/vampiric(loc) + else + new_item = new(loc) + new_item.SetName("statuette") + new_item.icon = 'icons/obj/xenoarchaeology.dmi' + new_item.icon_state = "statuette" + + additional_desc = "It depicts a [pick("small","ferocious","wild","pleasing","hulking")] \ + [pick("alien figure","rodent-like creature","reptilian alien","primate","unidentifiable object")] \ + [pick("performing unspeakable acts","posing heroically","in a fetal position","cheering","sobbing","making a plaintive gesture","making a rude gesture")]." + return new_item + +/obj/item/weapon/archaeological_find/instrument + item_type = "instrument" + icon_state = "instrument" + find_type = ARCHAEO_INSTRUMENT + +/obj/item/weapon/archaeological_find/instrument/spawn_item() + var/obj/item/new_item = new(loc) + new_item.SetName("instrument") + new_item.icon = 'icons/obj/xenoarchaeology.dmi' + new_item.icon_state = "instrument" + if(prob(30)) + apply_image_decorations = 1 + additional_desc = "[pick("You're not sure how anyone could have played this",\ + "You wonder how many mouths the creator had",\ + "You wonder what it sounds like",\ + "You wonder what kind of music was made with it")]." + return new_item + +/obj/item/weapon/archaeological_find/knife + item_type = "knife" + find_type = ARCHAEO_KNIFE + +/obj/item/weapon/archaeological_find/knife/spawn_item() + item_type = "[pick("bladed knife","serrated blade","sharp cutting implement")]" + var/obj/item/new_item = new /obj/item/weapon/material/knife(loc) + additional_desc = "[pick("It doesn't look safe.",\ + "It looks wickedly jagged",\ + "There appear to be [pick("dark red","dark purple","dark green","dark blue")] stains along the edges")]." + return new_item + +/obj/item/weapon/archaeological_find/coin + item_type = "coin" + find_type = ARCHAEO_COIN + apply_prefix = 0 + apply_material_decorations = 0 + apply_image_decorations = 1 + +/obj/item/weapon/archaeological_find/coin/spawn_item() + var/obj/item/weapon/coin/C = pick(subtypesof(/obj/item/weapon/coin)) + C = new C(loc) + return C + +/obj/item/weapon/archaeological_find/trap + item_type = "trap" + icon = 'icons/obj/items.dmi' + icon_state = "beartrap0" + find_type = ARCHAEO_BEARTRAP + apply_prefix = 0 + +/obj/item/weapon/archaeological_find/trap/spawn_item() + item_type = "[pick("wicked","evil","byzantine","dangerous")] looking [pick("device","contraption","thing","trap")]" + var/obj/item/new_item = new /obj/item/weapon/beartrap(loc) + additional_desc = "[pick("It looks like it could take a limb off",\ + "Could be some kind of animal trap",\ + "There appear to be [pick("dark red","dark purple","dark green","dark blue")] stains along part of it")]." + return new_item + +/obj/item/weapon/archaeological_find/container + item_type = "container" + icon_state = "box" + find_type = ARCHAEO_BOX + +/obj/item/weapon/archaeological_find/container/spawn_item() + var/obj/item/weapon/storage/box/new_box = new(loc) + new_box.icon = 'icons/obj/xenoarchaeology.dmi' + new_box.max_w_class = pick(ITEM_SIZE_TINY,2;ITEM_SIZE_SMALL,3;ITEM_SIZE_NORMAL,4;ITEM_SIZE_LARGE) + var/storage_amount = base_storage_cost(new_box.max_w_class) + new_box.max_storage_space = rand(storage_amount, storage_amount * 10) + new_box.icon_state = "box" + if(prob(30)) + apply_image_decorations = 1 + return new_box + +/obj/item/weapon/archaeological_find/tank + item_type = "tank" + find_type = ARCHAEO_GASTANK + +/obj/item/weapon/archaeological_find/tank/spawn_item() + item_type = "[pick("cylinder","tank","chamber")]" + var/obj/item/weapon/tank/new_item = new/obj/item/weapon/tank(loc) + new_item.air_contents.gas.Cut() + new_item.air_contents.adjust_gas(pick(gas_data.gases),15) + additional_desc = "It [pick("gloops","sloshes")] slightly when you shake it." + return new_item + +/obj/item/weapon/archaeological_find/tool + item_type = "tool" + find_type = ARCHAEO_TOOL + +/obj/item/weapon/archaeological_find/tool/spawn_item() + var/obj/item/weapon/new_item + if(prob(25)) + new_item = new /obj/item/weapon/wrench(loc) + else if(prob(25)) + new_item = new /obj/item/weapon/crowbar(loc) + else + new_item = new /obj/item/weapon/screwdriver(loc) + new_item.icon = 'icons/obj/xenoarchaeology.dmi' + new_item.icon_state = "unknown[rand(1,4)]" + additional_desc = "[pick("It doesn't look safe.",\ + "You wonder what it was used for",\ + "There appear to be [pick("dark red","dark purple","dark green","dark blue")] stains on it")]." + return new_item + +/obj/item/weapon/archaeological_find/material + item_type = "material lump" + find_type = ARCHAEO_METAL + apply_material_decorations = 0 + +/obj/item/weapon/archaeological_find/material/spawn_item() + var/list/possible_spawns = list() + possible_spawns += /obj/item/stack/material/steel + possible_spawns += /obj/item/stack/material/plasteel + possible_spawns += /obj/item/stack/material/glass + possible_spawns += /obj/item/stack/material/glass/reinforced + possible_spawns += /obj/item/stack/material/phoron + possible_spawns += /obj/item/stack/material/gold + possible_spawns += /obj/item/stack/material/silver + possible_spawns += /obj/item/stack/material/uranium + possible_spawns += /obj/item/stack/material/sandstone + possible_spawns += /obj/item/stack/material/silver + var/new_type = pick(possible_spawns) + var/obj/item/stack/material/new_item = new new_type(loc) + new_item.amount = rand(5,45) + return new_item + +/obj/item/weapon/archaeological_find/crystal + item_type = "crystal" + icon_state = "Green lump" + find_type = ARCHAEO_CRYSTAL + apply_prefix = 0 + apply_material_decorations = 0 + +/obj/item/weapon/archaeological_find/crystal/spawn_item() + var/obj/item/new_item + if(prob(25)) + new_item = new /obj/item/device/soulstone(loc) + else + new_item = new(loc) + apply_image_decorations = 1 + additional_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.") + + new_item.icon = 'icons/obj/xenoarchaeology.dmi' + if(prob(25)) + item_type = "smooth green crystal" + new_item.icon_state = "Green lump" + else if(prob(33)) + item_type = "irregular purple crystal" + new_item.icon_state = "Phazon" + else + item_type = "rough red crystal" + new_item.icon_state = "changerock" + +/obj/item/weapon/archaeological_find/blade + item_type = "blade" + find_type = ARCHAEO_CULTBLADE + apply_prefix = 0 + apply_material_decorations = 0 + apply_image_decorations = 0 + +/obj/item/weapon/archaeological_find/blade/spawn_item() + return new /obj/item/weapon/melee/cultblade(loc) + +/obj/item/weapon/archaeological_find/beacon + item_type = "device" + find_type = ARCHAEO_TELEBEACON + +/obj/item/weapon/archaeological_find/beacon/spawn_item() + var/obj/item/device/radio/beacon/new_item = new(loc) + new_item.icon = 'icons/obj/xenoarchaeology.dmi' + new_item.icon_state = "unknown[rand(1,4)]" + new_item.desc = "" + return new_item + +/obj/item/weapon/archaeological_find/sword + item_type = "sword" + find_type = ARCHAEO_CLAYMORE + +/obj/item/weapon/archaeological_find/sword/spawn_item() + return new /obj/item/weapon/material/sword(loc) + +/obj/item/weapon/archaeological_find/robes + item_type = "garments" + find_type = ARCHAEO_CULTROBES + +/obj/item/weapon/archaeological_find/robes/spawn_item() + var/list/possible_spawns = list(/obj/item/clothing/head/culthood, + /obj/item/clothing/head/culthood/magus, + /obj/item/clothing/head/culthood/alt, + /obj/item/clothing/head/helmet/space/cult) + var/new_type = pick(possible_spawns) + return new new_type(loc) + +/obj/item/weapon/archaeological_find/katana + item_type = "blade" + find_type = ARCHAEO_KATANA + +/obj/item/weapon/archaeological_find/katana/spawn_item() + return new /obj/item/weapon/material/sword/katana(loc) + +/obj/item/weapon/archaeological_find/parts + item_type = "parts" + find_type = ARCHAEO_STOCKPARTS + apply_material_decorations = 0 + +/obj/item/weapon/archaeological_find/parts/spawn_item() + var/list/possible_spawns = subtypesof(/obj/item/weapon/stock_parts) + possible_spawns -= /obj/item/weapon/stock_parts/subspace + var/new_type = pick(possible_spawns) + return new new_type(loc) + +/obj/item/weapon/archaeological_find/laser + item_type = "gun" + icon_state = "egun1" + find_type = ARCHAEO_LASER + apply_prefix = 0 + +/obj/item/weapon/archaeological_find/laser/spawn_item() + var/spawn_type = pick(\ + /obj/item/weapon/gun/energy/laser/practice,\ + /obj/item/weapon/gun/energy/laser,\ + /obj/item/weapon/gun/energy/captain) + var/obj/item/weapon/gun/energy/new_gun = new spawn_type(loc) + + new_gun.icon = 'icons/obj/xenoarchaeology.dmi' + new_gun.icon_state = "egun[rand(1,6)]" + new_gun.charge_meter = 0 + + //10% chance to have an unchargeable cell + //15% chance to gain a random amount of starting energy, otherwise start with an empty cell + if(prob(10)) + new_gun.power_supply.maxcharge = 0 + if(prob(15)) + new_gun.power_supply.charge = rand(0, new_gun.power_supply.maxcharge) + else + new_gun.power_supply.charge = 0 + + additional_desc = "This is an antique energy weapon, you're not sure if it will fire or not." + + return new_gun + +/obj/item/weapon/archaeological_find/gun + item_type = "gun" + icon_state = "gun1" + find_type = ARCHAEO_GUN + +/obj/item/weapon/archaeological_find/gun/spawn_item() + var/obj/item/weapon/gun/projectile/revolver/new_gun = new(loc) + + new_gun.icon = 'icons/obj/xenoarchaeology.dmi' + new_gun.icon_state = "gun[rand(1,4)]" + + //33% chance to be able to reload the gun with human ammunition + if(prob(66)) + new_gun.caliber = "999" + //33% chance to fill it with a random amount of bullets + new_gun.max_shells = rand(1,12) + new_gun.loaded.Cut() + if(prob(33)) + var/num_bullets = rand(1, new_gun.max_shells) + for(var/i = 1 to num_bullets) + var/obj/item/ammo_casing/A = new new_gun.ammo_type(new_gun) + new_gun.loaded += A + if(A.caliber != new_gun.caliber) + A.caliber = new_gun.caliber + A.desc = "A bullet casing of unknown caliber." + + additional_desc = "This is an antique weapon, you're not sure if it will fire or not." + + return new_gun + +/obj/item/weapon/archaeological_find/fossil + item_type = "bones" + icon_state = "bone" + find_type = ARCHAEO_FOSSIL + apply_prefix = 0 + apply_image_decorations = 0 + apply_material_decorations = 0 + +/obj/item/weapon/archaeological_find/fossil/spawn_item() + var/list/candidates = list(/obj/item/weapon/fossil/bone=9,/obj/item/weapon/fossil/skull=3, + /obj/item/weapon/fossil/skull/horned=2) + var/spawn_type = pickweight(candidates) + return new spawn_type(loc) + +/obj/item/weapon/archaeological_find/shell + item_type = "shell" + icon_state = "shell" + find_type = ARCHAEO_SHELL + apply_prefix = 0 + apply_image_decorations = 0 + apply_material_decorations = 0 + +/obj/item/weapon/archaeological_find/shell/spawn_item() + if(prob(10)) + apply_image_decorations = 1 + return new /obj/item/weapon/fossil/shell(loc) + +/obj/item/weapon/archaeological_find/plant + item_type = "fossilized plant" + icon_state = "plant1" + find_type = ARCHAEO_PLANT + apply_prefix = 0 + apply_image_decorations = 0 + apply_material_decorations = 0 + +/obj/item/weapon/archaeological_find/plant/spawn_item() + return new /obj/item/weapon/fossil/plant(loc) + +/obj/item/weapon/archaeological_find/remains + item_type = "remains" + icon = 'icons/effects/blood.dmi' + icon_state = "remains" + find_type = ARCHAEO_REMAINS_HUMANOID + apply_image_decorations = 0 + apply_material_decorations = 0 + var/list/descs = list("They appear almost human.",\ + "They are contorted in a most gruesome way.",\ + "They look almost peaceful.",\ + "The bones are yellowing and old, but remarkably well preserved.",\ + "The bones are scored by numerous burns and partially melted.",\ + "The are battered and broken, in some cases less than splinters are left.",\ + "The mouth is wide open in a death rictus, the victim would appear to have died screaming.") + +/obj/item/weapon/archaeological_find/remains/spawn_item() + item_type = "humanoid [pick("remains","skeleton")]" + if(prob(5)) + apply_image_decorations = 1 + var/obj/item/I = new(loc) + I.icon = icon + I.icon_state = icon_state + additional_desc = pick(descs) + return I + +/obj/item/weapon/archaeological_find/remains/robot + icon_state = "remainsrobot" + find_type = ARCHAEO_REMAINS_ROBOT + descs = list("Almost mistakeable for the remains of a modern cyborg.",\ + "They are barely recognisable as anything other than a pile of waste metals.",\ + "It looks like the battered remains of an ancient robot chassis.",\ + "The chassis is rusting and old, but remarkably well preserved.",\ + "The chassis is scored by numerous burns and partially melted.",\ + "The chassis is battered and broken, in some cases only chunks of metal are left.",\ + "A pile of wires and crap metal that looks vaguely robotic.") + +/obj/item/weapon/archaeological_find/remains/robot/spawn_item() + . = ..() + item_type = "[pick("mechanical","robotic","cyborg")] [pick("remains","chassis","debris")]" + +/obj/item/weapon/archaeological_find/remains/xeno + icon_state = "remainsxeno" + find_type = ARCHAEO_REMAINS_ROBOT + descs = list("It looks vaguely reptilian, but with more teeth.",\ + "They are faintly unsettling.",\ + "There is a faint aura of unease about them.",\ + "The bones are yellowing and old, but remarkably well preserved.",\ + "The bones are scored by numerous burns and partially melted.",\ + "The are battered and broken, in some cases less than splinters are left.",\ + "This creature would have been twisted and monstrous when it was alive.",\ + "It doesn't look human.") + +/obj/item/weapon/archaeological_find/remains/xeno/spawn_item() + . = ..() + item_type = "alien [pick("remains","skeleton")]" + +/obj/item/weapon/archaeological_find/mask + item_type = "mask" + find_type = ARCHAEO_GASMASK + +/obj/item/weapon/archaeological_find/mask/spawn_item() + var/obj/item/clothing/mask/gas/new_item + if(prob(25)) + new_item = new /obj/item/clothing/mask/gas/poltergeist(loc) + else + new_item = new /obj/item/clothing/mask/gas(loc) + return new_item \ No newline at end of file diff --git a/code/modules/xenoarcheaology/finds/finds.dm b/code/modules/xenoarcheaology/finds/finds.dm new file mode 100644 index 00000000..5738c5a1 --- /dev/null +++ b/code/modules/xenoarcheaology/finds/finds.dm @@ -0,0 +1,68 @@ +/datum/find + var/find_type = 0 //random according to the digsite type + var/excavation_required = 0 //random 10 - 190 + var/view_range = 40 //how close excavation has to come to show an overlay on the turf + var/clearance_range = 3 //how close excavation has to come to extract the item + //if excavation hits var/excavation_required exactly, it's contained find is extracted cleanly without the ore + var/prob_delicate = 90 //probability it requires an active suspension field to not insta-crumble + var/dissonance_spread = 1 //proportion of the tile that is affected by this find + //used in conjunction with analysis machines to determine correct suspension field type + +/datum/find/New(var/digsite, var/exc_req) + excavation_required = exc_req + find_type = get_random_find_type(digsite) + clearance_range = rand(4, 12) + dissonance_spread = rand(1500, 2500) / 100 + +/obj/item/weapon/ore/strangerock + name = "strange rock" + desc = "Seems to have some unusal strata evident throughout it." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "strange" + origin_tech = list(TECH_MATERIAL = 5) + +/obj/item/weapon/ore/strangerock/New(loc, var/inside_item_type = 0) + ..(loc) + + if(inside_item_type) + var/T = get_archeological_find_by_findtype(inside_item_type) + new T(src) + +/obj/item/weapon/ore/strangerock/attackby(var/obj/item/I, var/mob/user) + if(istype(I, /obj/item/weapon/pickaxe/brush)) + var/obj/item/inside = locate() in src + if(inside) + inside.forceMove(get_turf(src)) + visible_message("\The [src] is brushed away, revealing \the [inside].") + else + visible_message("\The [src] is brushed away into nothing.") + qdel(src) + return + + if(isWelder(I)) + var/obj/item/weapon/weldingtool/W = I + if(W.isOn()) + if(W.get_fuel() >= 2) + var/obj/item/inside = locate() in src + if(inside) + inside.forceMove(get_turf(src)) + visible_message("\The [src] burns away revealing \the [inside].") + else + visible_message("\The [src] burns away into nothing.") + qdel(src) + W.remove_fuel(2) + else + visible_message("A few sparks fly off \the [src], but nothing else happens.") + W.remove_fuel(1) + return + + else if(istype(I, /obj/item/device/core_sampler)) + var/obj/item/device/core_sampler/S = I + S.sample_item(src, user) + return + + ..() + + if(prob(33)) + src.visible_message("[src] crumbles away, leaving some dust and gravel behind.") + qdel(src) diff --git a/code/modules/xenoarcheaology/finds/finds_defines.dm b/code/modules/xenoarcheaology/finds/finds_defines.dm new file mode 100644 index 00000000..8fb4b7cb --- /dev/null +++ b/code/modules/xenoarcheaology/finds/finds_defines.dm @@ -0,0 +1,106 @@ +var/global/list/responsive_carriers = list( + /datum/reagent/carbon, + /datum/reagent/potassium, + /datum/reagent/hydrazine, + "nitrogen", + /datum/reagent/mercury, + /datum/reagent/iron, + "chlorine", + /datum/reagent/phosphorus, + /datum/reagent/toxin/phoron) + +var/global/list/finds_as_strings = list( + "Trace organic cells", + "Long exposure particles", + "Trace water particles", + "Crystalline structures", + "Metallic derivative", + "Metallic composite", + "Metamorphic/igneous rock composite", + "Metamorphic/sedimentary rock composite", + "Anomalous material") + +/proc/get_responsive_reagent(var/find_type) + switch(find_type) + if(ARCHAEO_BOWL, ARCHAEO_URN, ARCHAEO_CUTLERY, ARCHAEO_STATUETTE, ARCHAEO_INSTRUMENT, ARCHAEO_HANDCUFFS, ARCHAEO_BEARTRAP, ARCHAEO_BOX, ARCHAEO_GASTANK, ARCHAEO_UNKNOWN) + return /datum/reagent/mercury + if(ARCHAEO_COIN, ARCHAEO_KNIFE, ARCHAEO_TOOL, ARCHAEO_METAL, ARCHAEO_CLAYMORE, ARCHAEO_KATANA, ARCHAEO_LASER, ARCHAEO_GUN) + return /datum/reagent/iron + if(ARCHAEO_CRYSTAL, ARCHAEO_SOULSTONE) + return "nitrogen" + if(ARCHAEO_CULTBLADE, ARCHAEO_TELEBEACON, ARCHAEO_CULTROBES, ARCHAEO_STOCKPARTS) + return /datum/reagent/potassium + if(ARCHAEO_FOSSIL, ARCHAEO_SHELL, ARCHAEO_PLANT, ARCHAEO_REMAINS_HUMANOID, ARCHAEO_REMAINS_ROBOT, ARCHAEO_REMAINS_XENO, ARCHAEO_GASMASK) + return /datum/reagent/carbon + return /datum/reagent/toxin/phoron + +/proc/get_random_digsite_type() + return pick(100;DIGSITE_GARDEN, 95;DIGSITE_ANIMAL, 90;DIGSITE_HOUSE, 85;DIGSITE_TECHNICAL, 80;DIGSITE_TEMPLE, 75;DIGSITE_WAR) + +/proc/get_random_find_type(var/digsite) + . = 0 + switch(digsite) + if(DIGSITE_GARDEN) + . = pick( + 100;ARCHAEO_PLANT, + 25;ARCHAEO_SHELL, + 25;ARCHAEO_FOSSIL, + 5;ARCHAEO_BEARTRAP) + if(DIGSITE_ANIMAL) + . = pick( + 100;ARCHAEO_FOSSIL, + 50;ARCHAEO_SHELL, + 50;ARCHAEO_PLANT, + 25;ARCHAEO_BEARTRAP) + if(DIGSITE_HOUSE) + . = pick( + 100;ARCHAEO_BOWL, + 100;ARCHAEO_URN, + 100;ARCHAEO_CUTLERY, + 100;ARCHAEO_STATUETTE, + 100;ARCHAEO_INSTRUMENT, + 100;ARCHAEO_BOX, + 75;ARCHAEO_GASMASK, + 75;ARCHAEO_COIN, + 75;ARCHAEO_UNKNOWN, + 25;ARCHAEO_METAL) + if(DIGSITE_TECHNICAL) + . = pick( + 125;ARCHAEO_GASMASK, + 100;ARCHAEO_METAL, + 100;ARCHAEO_GASTANK, + 100;ARCHAEO_TELEBEACON, + 100;ARCHAEO_TOOL, + 100;ARCHAEO_STOCKPARTS, + 75;ARCHAEO_UNKNOWN, + 50;ARCHAEO_HANDCUFFS, + 50;ARCHAEO_BEARTRAP) + if(DIGSITE_TEMPLE) + . = pick( + 200;ARCHAEO_CULTROBES, + 200;ARCHAEO_STATUETTE, + 100;ARCHAEO_URN, + 100;ARCHAEO_BOWL, + 100;ARCHAEO_KNIFE, + 100;ARCHAEO_CRYSTAL, + 75;ARCHAEO_CULTBLADE, + 50;ARCHAEO_UNKNOWN, + 25;ARCHAEO_HANDCUFFS, + 25;ARCHAEO_BEARTRAP, + 10;ARCHAEO_KATANA, + 10;ARCHAEO_CLAYMORE, + 10;ARCHAEO_METAL, + 10;ARCHAEO_GASMASK) + if(DIGSITE_WAR) + . = pick( + 100;ARCHAEO_GUN, + 100;ARCHAEO_KNIFE, + 75;ARCHAEO_LASER, + 75;ARCHAEO_KATANA, + 75;ARCHAEO_CLAYMORE, + 50;ARCHAEO_UNKNOWN, + 50;ARCHAEO_CULTROBES, + 50;ARCHAEO_CULTBLADE, + 50;ARCHAEO_GASMASK, + 25;ARCHAEO_BEARTRAP, + 25;ARCHAEO_TOOL) diff --git a/code/modules/xenoarcheaology/finds/fossils.dm b/code/modules/xenoarcheaology/finds/fossils.dm new file mode 100644 index 00000000..0ebccaab --- /dev/null +++ b/code/modules/xenoarcheaology/finds/fossils.dm @@ -0,0 +1,102 @@ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// fossils + +/obj/item/weapon/fossil + name = "Fossil" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "bone" + desc = "It's a fossil." + var/animal = 1 + +/obj/item/weapon/fossil/base/New() + var/list/l = list(/obj/item/weapon/fossil/bone=9,/obj/item/weapon/fossil/skull=3, + /obj/item/weapon/fossil/skull/horned=2) + var/t = pickweight(l) + var/obj/item/weapon/W = new t(src.loc) + var/turf/T = get_turf(src) + if(istype(T, /turf/simulated/mineral)) + T:last_find = W + qdel(src) + +/obj/item/weapon/fossil/bone + name = "fossilised bone" + icon_state = "bone" + desc = "A fossilised part of an alien, long dead." + +/obj/item/weapon/fossil/skull + name = "fossilised skull" + icon_state = "skull" + +/obj/item/weapon/fossil/skull/horned + icon_state = "hskull" + +/obj/item/weapon/fossil/skull/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/weapon/fossil/bone)) + var/obj/o = new /obj/skeleton(get_turf(src)) + var/a = new /obj/item/weapon/fossil/bone + var/b = new src.type + o.contents.Add(a) + o.contents.Add(b) + qdel(W) + qdel(src) + +/obj/skeleton + name = "Incomplete skeleton" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "uskel" + desc = "Incomplete skeleton." + var/bnum = 1 + var/breq + var/bstate = 0 + var/plaque_contents = "Unnamed alien creature" + +/obj/skeleton/New() + src.breq = rand(6)+3 + src.desc = "An incomplete skeleton, looks like it could use [src.breq-src.bnum] more bones." + +/obj/skeleton/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/weapon/fossil/bone)) + if(!bstate) + bnum++ + src.contents.Add(new/obj/item/weapon/fossil/bone) + qdel(W) + if(bnum==breq) + usr = user + icon_state = "skel" + src.bstate = 1 + src.set_density(1) + src.SetName("alien skeleton display") + if(src.contents.Find(/obj/item/weapon/fossil/skull/horned)) + src.desc = "A creature made of [src.contents.len-1] assorted bones and a horned skull. The plaque reads \'[plaque_contents]\'." + else + src.desc = "A creature made of [src.contents.len-1] assorted bones and a skull. The plaque reads \'[plaque_contents]\'." + else + src.desc = "Incomplete skeleton, looks like it could use [src.breq-src.bnum] more bones." + to_chat(user, "Looks like it could use [src.breq-src.bnum] more bones.") + else + ..() + else if(istype(W,/obj/item/weapon/pen)) + plaque_contents = sanitize(input("What would you like to write on the plaque:","Skeleton plaque","")) + user.visible_message("[user] writes something on the base of [src].","You relabel the plaque on the base of \icon[src] [src].") + if(src.contents.Find(/obj/item/weapon/fossil/skull/horned)) + src.desc = "A creature made of [src.contents.len-1] assorted bones and a horned skull. The plaque reads \'[plaque_contents]\'." + else + src.desc = "A creature made of [src.contents.len-1] assorted bones and a skull. The plaque reads \'[plaque_contents]\'." + else + ..() + +//shells and plants do not make skeletons +/obj/item/weapon/fossil/shell + name = "fossilised shell" + icon_state = "shell" + desc = "A fossilised, pre-Stygian alien crustacean." + +/obj/item/weapon/fossil/plant + name = "fossilised plant" + icon_state = "plant1" + desc = " A fossilised shred of alien plant matter." + animal = 0 + +/obj/item/weapon/fossil/plant/New() + icon_state = "plant[rand(1,4)]" diff --git a/code/modules/xenoarcheaology/finds/misc.dm b/code/modules/xenoarcheaology/finds/misc.dm new file mode 100644 index 00000000..eb8d2548 --- /dev/null +++ b/code/modules/xenoarcheaology/finds/misc.dm @@ -0,0 +1,50 @@ + +// Phoron shards have been moved to code/game/objects/items/weapons/shards.dm + +//legacy crystal +/obj/machinery/crystal + name = "Crystal" + icon = 'icons/obj/mining.dmi' + icon_state = "crystal" + + +/obj/machinery/crystal/New() + ..() + icon_state = pick("crystal", "crystal2", "crystal3") + + +//Variant crystals, in case you want to spawn/map those directly. +/obj/machinery/crystal_static/ + name = "Crystal" + icon = 'icons/obj/mining.dmi' + icon_state = "crystal" + +/obj/machinery/crystal_static/pink + name = "Crystal" + icon_state = "crystal2" + +/obj/machinery/crystal_static/orange + name = "Crystal" + icon_state = "crystal3" + + +//large finds + /* + obj/machinery/syndicate_beacon + obj/machinery/wish_granter + if(18) + item_type = "jagged green crystal" + additional_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.") + icon_state = "crystal" + apply_material_decorations = 0 + if(prob(10)) + apply_image_decorations = 1 + if(19) + item_type = "jagged pink crystal" + additional_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.") + icon_state = "crystal2" + apply_material_decorations = 0 + if(prob(10)) + apply_image_decorations = 1 + */ + //machinery type artifacts? diff --git a/code/modules/xenoarcheaology/finds/special.dm b/code/modules/xenoarcheaology/finds/special.dm new file mode 100644 index 00000000..0cde231d --- /dev/null +++ b/code/modules/xenoarcheaology/finds/special.dm @@ -0,0 +1,225 @@ + + + +//endless reagents! +/obj/item/weapon/reagent_containers/glass/replenishing + var/spawning_id + +/obj/item/weapon/reagent_containers/glass/replenishing/Initialize() + . = ..() + spawning_id = pick(/datum/reagent/blood,/datum/reagent/water/holywater,/datum/reagent/lube,/datum/reagent/soporific,/datum/reagent/ethanol,/datum/reagent/drink/ice,/datum/reagent/glycerol,/datum/reagent/fuel,/datum/reagent/space_cleaner) + START_PROCESSING(SSobj, src) + +/obj/item/weapon/reagent_containers/glass/replenishing/Process() + reagents.add_reagent(spawning_id, 0.3) + + + +//a talking gas mask! +/obj/item/clothing/mask/gas/poltergeist + var/list/heard_talk = list() + var/last_twitch = 0 + var/max_stored_messages = 100 + +/obj/item/clothing/mask/gas/poltergeist/Initialize() + START_PROCESSING(SSobj, src) + GLOB.listening_objects += src + . = ..() + +/obj/item/clothing/mask/gas/poltergeist/Destroy() + STOP_PROCESSING(SSobj, src) + GLOB.listening_objects -= src + return ..() + +/obj/item/clothing/mask/gas/poltergeist/Process() + if(heard_talk.len && istype(src.loc, /mob/living) && prob(10)) + var/mob/living/M = src.loc + M.say(pick(heard_talk)) + +/obj/item/clothing/mask/gas/poltergeist/hear_talk(mob/M as mob, text) + ..() + if(heard_talk.len > max_stored_messages) + heard_talk.Remove(pick(heard_talk)) + heard_talk.Add(text) + if(istype(src.loc, /mob/living) && world.time - last_twitch > 50) + last_twitch = world.time + + + +//a vampiric statuette +//todo: cult integration +/obj/item/weapon/vampiric + name = "statuette" + icon_state = "statuette" + icon = 'icons/obj/xenoarchaeology.dmi' + var/charges = 0 + var/list/nearby_mobs = list() + var/last_bloodcall = 0 + var/bloodcall_interval = 50 + var/last_eat = 0 + var/eat_interval = 100 + var/wight_check_index = 1 + var/list/shadow_wights = list() + +/obj/item/weapon/vampiric/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + GLOB.listening_objects += src + +/obj/item/weapon/vampiric/Destroy() + STOP_PROCESSING(SSobj, src) + GLOB.listening_objects -= src + return ..() + +/obj/item/weapon/vampiric/Process() + //see if we've identified anyone nearby + if(world.time - last_bloodcall > bloodcall_interval && nearby_mobs.len) + var/mob/living/carbon/human/M = pop(nearby_mobs) + if(M in view(7,src) && M.health > 20) + if(prob(50)) + bloodcall(M) + nearby_mobs.Add(M) + + //suck up some blood to gain power + if(world.time - last_eat > eat_interval) + var/obj/effect/decal/cleanable/blood/B = locate() in range(2,src) + if(B) + last_eat = world.time + B.loc = null + if(istype(B, /obj/effect/decal/cleanable/blood/drip)) + charges += 0.25 + else + charges += 1 + playsound(src.loc, 'sound/effects/splat.ogg', 50, 1, -3) + + //use up stored charges + if(charges >= 10) + charges -= 10 + new /obj/effect/spider/eggcluster(pick(view(1,src))) + + if(charges >= 3) + if(prob(5)) + charges -= 1 + var/spawn_type = pick(/mob/living/simple_animal/hostile/creature) + new spawn_type(pick(view(1,src))) + playsound(src.loc, pick('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg'), 50, 1, -3) + + if(charges >= 1) + if(shadow_wights.len < 5 && prob(5)) + shadow_wights.Add(new /obj/effect/shadow_wight(src.loc)) + playsound(src.loc, 'sound/effects/ghost.ogg', 50, 1, -3) + charges -= 0.1 + + if(charges >= 0.1) + if(prob(5)) + src.visible_message("\icon[src] [src]'s eyes glow ruby red for a moment!") + charges -= 0.1 + + //check on our shadow wights + if(shadow_wights.len) + wight_check_index++ + if(wight_check_index > shadow_wights.len) + wight_check_index = 1 + + var/obj/effect/shadow_wight/W = shadow_wights[wight_check_index] + if(isnull(W)) + shadow_wights.Remove(wight_check_index) + else if(isnull(W.loc)) + shadow_wights.Remove(wight_check_index) + else if(get_dist(W, src) > 10) + shadow_wights.Remove(wight_check_index) + +/obj/item/weapon/vampiric/hear_talk(mob/M as mob, text) + ..() + if(world.time - last_bloodcall >= bloodcall_interval && M in view(7, src)) + bloodcall(M) + +/obj/item/weapon/vampiric/proc/bloodcall(var/mob/living/carbon/human/M) + last_bloodcall = world.time + if(istype(M)) + playsound(src.loc, pick('sound/hallucinations/wail.ogg','sound/hallucinations/veryfar_noise.ogg','sound/hallucinations/far_noise.ogg'), 50, 1, -3) + nearby_mobs.Add(M) + + var/target = pick(M.organs_by_name) + M.apply_damage(rand(5, 10), BRUTE, target) + to_chat(M, "The skin on your [parse_zone(target)] feels like it's ripping apart, and a stream of blood flies out.") + var/obj/effect/decal/cleanable/blood/splatter/animated/B = new(M.loc) + B.target_turf = pick(range(1, src)) + B.blood_DNA = list() + B.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type + M.vessel.remove_reagent(/datum/reagent/blood,rand(25,50)) + +//animated blood 2 SPOOKY +/obj/effect/decal/cleanable/blood/splatter/animated + var/turf/target_turf + var/loc_last_process + +/obj/effect/decal/cleanable/blood/splatter/animated/Initialize() + . = ..() + loc_last_process = src.loc + START_PROCESSING(SSobj, src) + +/obj/effect/decal/cleanable/blood/splatter/animated/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/effect/decal/cleanable/blood/splatter/animated/Process() + if(target_turf && src.loc != target_turf) + step_towards(src,target_turf) + if(src.loc == loc_last_process) + target_turf = null + loc_last_process = src.loc + + //leave some drips behind + if(prob(50)) + var/obj/effect/decal/cleanable/blood/drip/D = new(src.loc) + D.blood_DNA = src.blood_DNA.Copy() + if(prob(50)) + D = new(src.loc) + D.blood_DNA = src.blood_DNA.Copy() + if(prob(50)) + D = new(src.loc) + D.blood_DNA = src.blood_DNA.Copy() + else + ..() + +/obj/effect/shadow_wight + name = "shadow wight" + icon = 'icons/mob/mob.dmi' + icon_state = "shade" + density = 1 + +/obj/effect/shadow_wight/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/effect/shadow_wight/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/effect/shadow_wight/Process() + if(src.loc) + src.loc = get_turf(pick(orange(1,src))) + var/mob/living/carbon/M = locate() in src.loc + if(M) + playsound(src.loc, pick('sound/hallucinations/behind_you1.ogg',\ + 'sound/hallucinations/behind_you2.ogg',\ + 'sound/hallucinations/i_see_you1.ogg',\ + 'sound/hallucinations/i_see_you2.ogg',\ + 'sound/hallucinations/im_here1.ogg',\ + 'sound/hallucinations/im_here2.ogg',\ + 'sound/hallucinations/look_up1.ogg',\ + 'sound/hallucinations/look_up2.ogg',\ + 'sound/hallucinations/over_here1.ogg',\ + 'sound/hallucinations/over_here2.ogg',\ + 'sound/hallucinations/over_here3.ogg',\ + 'sound/hallucinations/turn_around1.ogg',\ + 'sound/hallucinations/turn_around2.ogg',\ + ), 50, 1, -3) + M.sleeping = max(M.sleeping,rand(5,10)) + src.loc = null + else + STOP_PROCESSING(SSobj, src) + +/obj/effect/shadow_wight/Bump(var/atom/obstacle) + to_chat(obstacle, "You feel a chill run down your spine!") diff --git a/code/modules/xenoarcheaology/finds/talking.dm b/code/modules/xenoarcheaology/finds/talking.dm new file mode 100644 index 00000000..6f4d6cff --- /dev/null +++ b/code/modules/xenoarcheaology/finds/talking.dm @@ -0,0 +1,122 @@ +/obj/var/datum/talking_atom/talking_atom + +/datum/talking_atom + var/list/heard_words = list() + var/last_talk_time = 0 + var/atom/holder_atom + var/talk_interval = 50 + var/talk_chance = 10 + +/datum/talking_atom/New(atom/holder) + holder_atom = holder + init() + +/datum/talking_atom/proc/init() + if(holder_atom) + START_PROCESSING(SSprocessing, src) + +/datum/talking_atom/Process() + if(!holder_atom) + STOP_PROCESSING(SSprocessing, src) + + else if(heard_words.len >= 1 && world.time > last_talk_time + talk_interval && prob(talk_chance)) + SaySomething() + +/datum/talking_atom/proc/catchMessage(var/msg, var/mob/source) + if(!holder_atom) + return + + var/list/seperate = list() + if(findtext(msg,"((")) + return + else if(findtext(msg,"))")) + return + else if(findtext(msg," ")==0) + return + else + /*var/l = length(msg) + if(findtext(msg," ",l,l+1)==0) + msg+=" "*/ + seperate = splittext(msg, " ") + + for(var/Xa = 1,Xa 20 + rand(10,20)) + heard_words.Remove(heard_words[1]) + if(!heard_words["[lowertext(seperate[Xa])]"]) + heard_words["[lowertext(seperate[Xa])]"] = list() + var/list/w = heard_words["[lowertext(seperate[Xa])]"] + if(w) + w.Add("[lowertext(seperate[next])]") +// log_debug("Adding [lowertext(seperate[next])] to [lowertext(seperate[Xa])]") + + if(prob(30)) + var/list/options = list("[holder_atom] seems to be listening intently to [source]...",\ + "[holder_atom] seems to be focusing on [source]...",\ + "[holder_atom] seems to turn it's attention to [source]...") + holder_atom.loc.visible_message("\icon[holder_atom] [pick(options)]") + + if(prob(20)) + spawn(2) + SaySomething(pick(seperate)) + +/*/obj/item/weapon/talkingcrystal/proc/debug() + //set src in view() + for(var/v in heard_words) + log_debug("[uppertext(v)]") + var/list/d = heard_words["[v]"] + for(var/X in d) + log_debug("[X]") */ + +/datum/talking_atom/proc/SaySomething(var/word = null) + if(!holder_atom) + return + + var/msg + var/limit = rand(max(5,heard_words.len/2))+3 + var/text + if(!word) + text = "[pick(heard_words)]" + else + text = pick(splittext(word, " ")) + if(length(text)==1) + text=uppertext(text) + else + var/cap = copytext(text,1,2) + cap = uppertext(cap) + cap += copytext(text,2,length(text)+1) + text=cap + var/q = 0 + msg+=text + if(msg=="What" | msg == "Who" | msg == "How" | msg == "Why" | msg == "Are") + q=1 + + text=lowertext(text) + for(var/ya,ya <= limit,ya++) + + if(heard_words.Find("[text]")) + var/list/w = heard_words["[text]"] + text=pick(w) + else + text = "[pick(heard_words)]" + msg+=" [text]" + if(q) + msg+="?" + else + if(rand(0,10)) + msg+="." + else + msg+="!" + + var/list/listening = viewers(holder_atom) + for(var/mob/M in SSmobs.mob_list) + if (!M.client) + continue //skip monkeys and leavers + if (istype(M, /mob/new_player)) + continue + if(M.stat == DEAD && M.get_preference_value(/datum/client_preference/ghost_ears) == GLOB.PREF_ALL_SPEECH) + listening|=M + + for(var/mob/M in listening) + to_chat(M, "\icon[holder_atom] [holder_atom] reverberates, \"[msg]\"") + last_talk_time = world.time diff --git a/code/modules/xenoarcheaology/master_controller.dm b/code/modules/xenoarcheaology/master_controller.dm new file mode 100644 index 00000000..a6689e36 --- /dev/null +++ b/code/modules/xenoarcheaology/master_controller.dm @@ -0,0 +1,95 @@ +/datum/controller/game_controller + var/list/artifact_spawning_turfs = list() + var/list/digsite_spawning_turfs = list() + +#define XENOARCH_SPAWN_CHANCE 0.5 +#define DIGSITESIZE_LOWER 4 +#define DIGSITESIZE_UPPER 12 +#define ARTIFACTSPAWNNUM_LOWER 6 +#define ARTIFACTSPAWNNUM_UPPER 12 + +/datum/controller/game_controller/proc/SetupXenoarch() + for(var/turf/simulated/mineral/M in world) + if(!M.density) + continue + + if(isnull(M.geologic_data)) + M.geologic_data = new /datum/geosample(M) + + if(!prob(XENOARCH_SPAWN_CHANCE)) + continue + + var/farEnough = 1 + for(var/A in digsite_spawning_turfs) + var/turf/T = A + if(T in range(5, M)) + farEnough = 0 + break + if(!farEnough) + continue + + digsite_spawning_turfs.Add(M) + + var/digsite = get_random_digsite_type() + var/target_digsite_size = rand(DIGSITESIZE_LOWER, DIGSITESIZE_UPPER) + + var/list/processed_turfs = list() + var/list/turfs_to_process = list(M) + + var/list/viable_adjacent_turfs = list() + if(target_digsite_size > 1) + for(var/turf/simulated/mineral/T in orange(2, M)) + if(!T.density) + continue + if(T.finds) + continue + if(T in processed_turfs) + continue + viable_adjacent_turfs.Add(T) + + target_digsite_size = min(target_digsite_size, viable_adjacent_turfs.len) + + for(var/i = 1 to target_digsite_size) + turfs_to_process += pick_n_take(viable_adjacent_turfs) + + while(turfs_to_process.len) + var/turf/simulated/mineral/archeo_turf = pop(turfs_to_process) + + processed_turfs.Add(archeo_turf) + if(isnull(archeo_turf.finds)) + archeo_turf.finds = list() + if(prob(50)) + archeo_turf.finds.Add(new /datum/find(digsite, rand(10, 190))) + else if(prob(75)) + archeo_turf.finds.Add(new /datum/find(digsite, rand(10, 90))) + archeo_turf.finds.Add(new /datum/find(digsite, rand(110, 190))) + else + archeo_turf.finds.Add(new /datum/find(digsite, rand(10, 50))) + archeo_turf.finds.Add(new /datum/find(digsite, rand(60, 140))) + archeo_turf.finds.Add(new /datum/find(digsite, rand(150, 190))) + + //sometimes a find will be close enough to the surface to show + var/datum/find/F = archeo_turf.finds[1] + if(F.excavation_required <= F.view_range) + archeo_turf.archaeo_overlay = "overlay_archaeo[rand(1,3)]" + archeo_turf.update_icon() + + //have a chance for an artifact to spawn here, but not in animal or plant digsites + if(isnull(M.artifact_find) && digsite != DIGSITE_GARDEN && digsite != DIGSITE_ANIMAL) + artifact_spawning_turfs.Add(archeo_turf) + + //create artifact machinery + var/num_artifacts_spawn = rand(ARTIFACTSPAWNNUM_LOWER, ARTIFACTSPAWNNUM_UPPER) + while(artifact_spawning_turfs.len > num_artifacts_spawn) + pick_n_take(artifact_spawning_turfs) + + var/list/artifacts_spawnturf_temp = artifact_spawning_turfs.Copy() + while(artifacts_spawnturf_temp.len > 0) + var/turf/simulated/mineral/artifact_turf = pop(artifacts_spawnturf_temp) + artifact_turf.artifact_find = new() + +#undef XENOARCH_SPAWN_CHANCE +#undef DIGSITESIZE_LOWER +#undef DIGSITESIZE_UPPER +#undef ARTIFACTSPAWNNUM_LOWER +#undef ARTIFACTSPAWNNUM_UPPER diff --git a/code/modules/xenoarcheaology/misc.dm b/code/modules/xenoarcheaology/misc.dm new file mode 100644 index 00000000..fd232017 --- /dev/null +++ b/code/modules/xenoarcheaology/misc.dm @@ -0,0 +1,112 @@ +/obj/structure/noticeboard/anomaly + notices = 5 + icon_state = "nboard05" + +/obj/structure/noticeboard/anomaly/New() + var/obj/item/weapon/paper/P = new() + P.SetName("Memo RE: proper analysis procedure") + P.info = "
                We keep test dummies in pens here for a reason, so standard procedure should be to activate newfound alien artifacts and place the two in close proximity. Promising items I might even approve monkey testing on." + P.stamped = list(/obj/item/weapon/stamp/rd) + P.overlays = list("paper_stamped_rd") + src.contents += P + + P = new() + P.SetName("Memo RE: materials gathering") + P.info = "Corasang,
                the hands-on approach to gathering our samples may very well be slow at times, but it's safer than allowing the blundering miners to roll willy-nilly over our dig sites in their mechs, destroying everything in the process. And don't forget the escavation tools on your way out there!
                - R.W" + P.stamped = list(/obj/item/weapon/stamp/rd) + P.overlays = list("paper_stamped_rd") + src.contents += P + + P = new() + P.SetName("Memo RE: ethical quandaries") + P.info = "Darion-

                I don't care what his rank is, our business is that of science and knowledge - questions of moral application do not come into this. Sure, so there are those who would employ the energy-wave particles my modified device has managed to abscond for their own personal gain, but I can hardly see the practical benefits of some of these artifacts our benefactors left behind. Ward--" + P.stamped = list(/obj/item/weapon/stamp/rd) + P.overlays = list("paper_stamped_rd") + src.contents += P + + P = new() + P.SetName("READ ME! Before you people destroy any more samples") + P.info = "how many times do i have to tell you people, these xeno-arch samples are del-i-cate, and should be handled so! careful application of a focussed, concentrated heat or some corrosive liquids should clear away the extraneous carbon matter, while application of an energy beam will most decidedly destroy it entirely - like someone did to the chemical dispenser! W, the one who signs your paychecks" + P.stamped = list(/obj/item/weapon/stamp/rd) + P.overlays = list("paper_stamped_rd") + src.contents += P + + P = new() + P.SetName("Reminder regarding the anomalous material suits") + P.info = "Do you people think the anomaly suits are cheap to come by? I'm about a hair trigger away from instituting a log book for the damn things. Only wear them if you're going out for a dig, and for god's sake don't go tramping around in them unless you're field testing something, R" + P.stamped = list(/obj/item/weapon/stamp/rd) + P.overlays = list("paper_stamped_rd") + src.contents += P + +/obj/structure/bookcase/manuals/xenoarchaeology + name = "Xenoarchaeology Manuals bookcase" + +/obj/structure/bookcase/manuals/xenoarchaeology/New() + ..() + new /obj/item/weapon/book/manual/excavation(src) + new /obj/item/weapon/book/manual/mass_spectrometry(src) + new /obj/item/weapon/book/manual/materials_chemistry_analysis(src) + new /obj/item/weapon/book/manual/anomaly_testing(src) + new /obj/item/weapon/book/manual/anomaly_spectroscopy(src) + new /obj/item/weapon/book/manual/stasis(src) + update_icon() + +/obj/structure/closet/secure_closet/xenoarchaeologist + name = "Xenoarchaeologist Locker" + req_access = list(access_xenoarch) + icon_state = "secureres1" + icon_closed = "secureres" + icon_locked = "secureres1" + icon_opened = "secureresopen" + icon_broken = "secureresbroken" + icon_off = "secureresoff" + +/obj/structure/closet/secure_closet/xenoarchaeologist/New() + ..() + if(prob(50)) + new /obj/item/weapon/storage/backpack/toxins(src) + else + new /obj/item/weapon/storage/backpack/satchel/satchel_tox(src) + if(prob(50)) + new /obj/item/weapon/storage/backpack/dufflebag(src) + new /obj/item/clothing/under/rank/scientist(src) + new /obj/item/clothing/suit/storage/toggle/labcoat(src) + new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/glasses/science(src) + new /obj/item/device/radio/headset/headset_sci(src) + new /obj/item/clothing/mask/gas(src) + new /obj/item/weapon/clipboard(src) + new /obj/item/weapon/storage/belt/archaeology(src) + new /obj/item/weapon/storage/excavation(src) + new /obj/item/taperoll/research(src) + +/obj/structure/closet/excavation + name = "Excavation tools" + icon_state = "toolcloset" + icon_closed = "toolcloset" + icon_opened = "toolclosetopen" + +/obj/structure/closet/excavation/New() + ..() + new /obj/item/weapon/storage/belt/archaeology(src) + new /obj/item/weapon/storage/excavation(src) + new /obj/item/device/flashlight/lantern(src) + new /obj/item/device/ano_scanner(src) + new /obj/item/device/depth_scanner(src) + new /obj/item/device/core_sampler(src) + new /obj/item/device/gps(src) + new /obj/item/weapon/pinpointer/radio(src) + new /obj/item/device/radio/beacon(src) + new /obj/item/clothing/glasses/meson(src) + new /obj/item/weapon/pickaxe(src) + new /obj/item/device/measuring_tape(src) + new /obj/item/weapon/pickaxe/hand(src) + new /obj/item/weapon/storage/bag/fossils(src) + new /obj/item/weapon/hand_labeler(src) + new /obj/item/taperoll/research(src) + +/obj/machinery/alarm/isolation + req_one_access = list(access_research, access_atmospherics, access_engine_equip) + +/obj/machinery/alarm/monitor/isolation + req_one_access = list(access_research, access_atmospherics, access_engine_equip) diff --git a/code/modules/xenoarcheaology/sampling.dm b/code/modules/xenoarcheaology/sampling.dm new file mode 100644 index 00000000..1fc98bf1 --- /dev/null +++ b/code/modules/xenoarcheaology/sampling.dm @@ -0,0 +1,164 @@ +/obj/item/weapon/rocksliver + name = "rock sliver" + desc = "It looks extremely delicate." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "sliver1" + randpixel = 8 + w_class = ITEM_SIZE_TINY + sharp = 1 + var/datum/geosample/geological_data + +/obj/item/weapon/rocksliver/New() + icon_state = "sliver[rand(1, 3)]" + +/datum/geosample + var/age = 0 + var/age_thousand = 0 + var/age_million = 0 + var/age_billion = 0 + var/artifact_id = "" + var/artifact_distance = -1 + var/source_mineral = "chlorine" + var/list/find_presence = list() + +/datum/geosample/New(var/turf/simulated/mineral/container) + UpdateTurf(container) + +/datum/geosample/proc/UpdateTurf(var/turf/simulated/mineral/container) + if(!istype(container)) + return + + age = rand(1, 999) + + if(container.mineral) + if(islist(container.mineral.xarch_ages)) + var/list/ages = container.mineral.xarch_ages + if(ages["thousand"]) + age_thousand = rand(1, ages["thousand"]) + if(ages["million"]) + age_million = rand(1, ages["million"]) + if(ages["billion"]) + if(ages["billion_lower"]) + age_billion = rand(ages["billion_lower"], ages["billion"]) + else + age_billion = rand(1, ages["billion"]) + if(container.mineral.xarch_source_mineral) + source_mineral = container.mineral.xarch_source_mineral + + if(prob(75)) + find_presence[/datum/reagent/phosphorus] = rand(1, 500) / 100 + if(prob(25)) + find_presence[/datum/reagent/mercury] = rand(1, 500) / 100 + find_presence["chlorine"] = rand(500, 2500) / 100 + + for(var/datum/find/F in container.finds) + var/responsive_reagent = get_responsive_reagent(F.find_type) + find_presence[responsive_reagent] = F.dissonance_spread + + var/total_presence = 0 + for(var/carrier in find_presence) + total_presence += find_presence[carrier] + for(var/carrier in find_presence) + find_presence[carrier] = find_presence[carrier] / total_presence + +/datum/geosample/proc/UpdateNearbyArtifactInfo(var/turf/simulated/mineral/container) + if(!container || !istype(container)) + return + + if(container.artifact_find) + artifact_distance = rand() + artifact_id = container.artifact_find.artifact_id + else + if(master_controller) //Sanity check due to runtimes ~Z + for(var/turf/simulated/mineral/T in master_controller.artifact_spawning_turfs) + if(T.artifact_find) + var/cur_dist = get_dist(container, T) * 2 + if( (artifact_distance < 0 || cur_dist < artifact_distance)) + artifact_distance = cur_dist + rand() * 2 - 1 + artifact_id = T.artifact_find.artifact_id + else + master_controller.artifact_spawning_turfs.Remove(T) + +/obj/item/device/core_sampler + name = "core sampler" + desc = "Used to extract geological core samples." + icon = 'icons/obj/device.dmi' + icon_state = "sampler0" + item_state = "screwdriver_brown" + w_class = ITEM_SIZE_TINY + + var/sampled_turf = "" + var/num_stored_bags = 10 + var/obj/item/weapon/evidencebag/filled_bag + +/obj/item/device/core_sampler/examine(var/mob/user) + if(..(user, 2)) + to_chat(user, "Used to extract geological core samples - this one is [sampled_turf ? "full" : "empty"], and has [num_stored_bags] bag[num_stored_bags != 1 ? "s" : ""] remaining.") + +/obj/item/device/core_sampler/attackby(var/obj/item/I, var/mob/living/user) + if(istype(I, /obj/item/weapon/evidencebag)) + if(I.contents.len) + to_chat(user, "\The [I] is full.") + return + if(num_stored_bags < 10) + qdel(I) + num_stored_bags += 1 + to_chat(user, "You insert \the [I] into \the [src].") + else + to_chat(user, "\The [src] can not fit any more bags.") + else + return ..() + +/obj/item/device/core_sampler/proc/sample_item(var/item_to_sample, var/mob/user) + var/datum/geosample/geo_data + + if(istype(item_to_sample, /turf/simulated/mineral)) + var/turf/simulated/mineral/T = item_to_sample + T.geologic_data.UpdateNearbyArtifactInfo(T) + geo_data = T.geologic_data + else if(istype(item_to_sample, /obj/item/weapon/ore)) + var/obj/item/weapon/ore/O = item_to_sample + geo_data = O.geologic_data + + if(geo_data) + if(filled_bag) + to_chat(user, "The core sampler is full.") + else if(num_stored_bags < 1) + to_chat(user, "The core sampler is out of sample bags.") + else + //create a new sample bag which we'll fill with rock samples + filled_bag = new /obj/item/weapon/evidencebag(src) + filled_bag.SetName("sample bag") + filled_bag.desc = "a bag for holding research samples." + + icon_state = "sampler1" + --num_stored_bags + + //put in a rock sliver + var/obj/item/weapon/rocksliver/R = new(filled_bag) + R.geological_data = geo_data + + //update the sample bag + filled_bag.icon_state = "evidence" + var/image/I = image("icon"=R, "layer"=FLOAT_LAYER) + filled_bag.overlays += I + filled_bag.overlays += "evidence" + filled_bag.w_class = ITEM_SIZE_TINY + + to_chat(user, "You take a core sample of the [item_to_sample].") + else + to_chat(user, "You are unable to take a sample of [item_to_sample].") + +/obj/item/device/core_sampler/attack_self(var/mob/living/user) + if(filled_bag) + to_chat(user, "You eject the full sample bag.") + var/success = 0 + if(istype(src.loc, /mob)) + var/mob/M = src.loc + success = M.put_in_inactive_hand(filled_bag) + if(!success) + filled_bag.forceMove(get_turf(src)) + filled_bag = null + icon_state = "sampler0" + else + to_chat(user, "The core sampler is empty.") diff --git a/code/modules/xenoarcheaology/tools/ano_device_battery.dm b/code/modules/xenoarcheaology/tools/ano_device_battery.dm new file mode 100644 index 00000000..a15c798d --- /dev/null +++ b/code/modules/xenoarcheaology/tools/ano_device_battery.dm @@ -0,0 +1,214 @@ +/obj/item/weapon/anobattery + name = "Anomaly power battery" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "anobattery0" + var/datum/artifact_effect/battery_effect + var/capacity = 300 + var/stored_charge = 0 + var/effect_id = "" + +/obj/item/weapon/anobattery/New() + battery_effect = new() + +/obj/item/weapon/anobattery/proc/UpdateSprite() + var/p = (stored_charge/capacity)*100 + p = min(p, 100) + icon_state = "anobattery[round(p,25)]" + +/obj/item/weapon/anobattery/proc/use_power(var/amount) + stored_charge = max(0, stored_charge - amount) + +/obj/item/weapon/anodevice + name = "Anomaly power utilizer" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "anodev" + var/activated = 0 + var/duration = 0 + var/interval = 0 + var/time_end = 0 + var/last_activation = 0 + var/last_process = 0 + var/obj/item/weapon/anobattery/inserted_battery + var/turf/archived_loc + var/energy_consumed_on_touch = 100 + +/obj/item/weapon/anodevice/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/item/weapon/anodevice/attackby(var/obj/I as obj, var/mob/user as mob) + if(istype(I, /obj/item/weapon/anobattery)) + if(!inserted_battery) + to_chat(user, "You insert the battery.") + user.drop_item() + I.loc = src + inserted_battery = I + UpdateSprite() + else + return ..() + +/obj/item/weapon/anodevice/attack_self(var/mob/user as mob) + return src.interact(user) + +/obj/item/weapon/anodevice/interact(var/mob/user) + var/dat = "Anomalous Materials Energy Utiliser
                " + if(inserted_battery) + if(activated) + dat += "Device active.
                " + + dat += "[inserted_battery] inserted, anomaly ID: [inserted_battery.battery_effect.artifact_id ? inserted_battery.battery_effect.artifact_id : "NA"]
                " + dat += "Charge: [inserted_battery.stored_charge] / [inserted_battery.capacity]
                " + dat += "Time left activated: [round(max((time_end - last_process) / 10, 0))]
                " + if(activated) + dat += "Shutdown
                " + else + dat += "Start
                " + dat += "
                " + + dat += "Activate duration (sec): -- - [duration/10] + ++
                " + dat += "Activate interval (sec): -- - [interval/10] + ++
                " + dat += "
                " + dat += "Eject battery
                " + else + dat += "Please insert battery
                " + + dat += "
                " + dat += "Refresh Close" + + user << browse(dat, "window=anodevice;size=400x500") + onclose(user, "anodevice") + +/obj/item/weapon/anodevice/Process() + if(activated) + if(inserted_battery && inserted_battery.battery_effect && (inserted_battery.stored_charge > 0) ) + //make sure the effect is active + if(!inserted_battery.battery_effect.activated) + inserted_battery.battery_effect.ToggleActivate(1) + + //update the effect loc + var/turf/T = get_turf(src) + if(T != archived_loc) + archived_loc = T + inserted_battery.battery_effect.UpdateMove() + + //if someone is holding the device, do the effect on them + var/mob/holder + if(ismob(src.loc)) + holder = src.loc + + //handle charge + if(world.time - last_activation > interval) + if(inserted_battery.battery_effect.effect == EFFECT_TOUCH) + if(interval > 0) + //apply the touch effect to the holder + if(holder) + to_chat(holder, "The \icon[src] [src] held by [holder] shudders in your grasp.") + else + src.loc.visible_message("The \icon[src] [src] shudders.") + inserted_battery.battery_effect.DoEffectTouch(holder) + + //consume power + inserted_battery.use_power(energy_consumed_on_touch) + else + //consume power equal to time passed + inserted_battery.use_power(world.time - last_process) + + else if(inserted_battery.battery_effect.effect == EFFECT_PULSE) + inserted_battery.battery_effect.chargelevel = inserted_battery.battery_effect.chargelevelmax + + //consume power relative to the time the artifact takes to charge and the effect range + inserted_battery.use_power(inserted_battery.battery_effect.effectrange * inserted_battery.battery_effect.effectrange * inserted_battery.battery_effect.chargelevelmax) + + else + //consume power equal to time passed + inserted_battery.use_power(world.time - last_process) + + last_activation = world.time + + //process the effect + inserted_battery.battery_effect.process() + + //work out if we need to shutdown + if(inserted_battery.stored_charge <= 0) + src.loc.visible_message("\icon[src] [src] buzzes.", "\icon[src] You hear something buzz.") + shutdown_emission() + else if(world.time > time_end) + src.loc.visible_message("\icon[src] [src] chimes.", "\icon[src] You hear something chime.") + shutdown_emission() + else + src.visible_message("\icon[src] [src] buzzes.", "\icon[src] You hear something buzz.") + shutdown_emission() + last_process = world.time + +/obj/item/weapon/anodevice/proc/shutdown_emission() + if(activated) + activated = 0 + if(inserted_battery.battery_effect.activated) + inserted_battery.battery_effect.ToggleActivate(1) + +/obj/item/weapon/anodevice/Topic(user, href_list, state = GLOB.inventory_state) + ..() + +/obj/item/weapon/anodevice/OnTopic(user, href_list) + if(href_list["changetime"]) + var/timedif = text2num(href_list["changetime"]) + if(href_list["duration"]) + duration += timedif + //max 30 sec duration + duration = min(max(duration, 0), 300) + if(activated) + time_end += timedif + else if(href_list["interval"]) + interval += timedif + //max 10 sec interval + interval = min(max(interval, 0), 100) + . = TOPIC_REFRESH + else if(href_list["startup"]) + if(inserted_battery && inserted_battery.battery_effect && (inserted_battery.stored_charge > 0) ) + activated = 1 + src.visible_message("\icon[src] [src] whirrs.", "\icon[src] You hear something whirr.") + if(!inserted_battery.battery_effect.activated) + inserted_battery.battery_effect.ToggleActivate(1) + time_end = world.time + duration + . = TOPIC_REFRESH + else if(href_list["shutdown"]) + activated = 0 + . = TOPIC_REFRESH + else if(href_list["ejectbattery"]) + shutdown_emission() + inserted_battery.dropInto(loc) + inserted_battery = null + UpdateSprite() + . = TOPIC_REFRESH + if(href_list["close"]) + close_browser(user, "window=anodevice") + . = TOPIC_HANDLED + + if(. == TOPIC_REFRESH) + interact(user) + +/obj/item/weapon/anodevice/proc/UpdateSprite() + if(!inserted_battery) + icon_state = "anodev" + return + var/p = (inserted_battery.stored_charge/inserted_battery.capacity)*100 + p = min(p, 100) + icon_state = "anodev[round(p,25)]" + +/obj/item/weapon/anodevice/Destroy() + STOP_PROCESSING(SSobj, src) + ..() + +/obj/item/weapon/anodevice/attack(mob/living/M as mob, mob/living/user as mob, def_zone) + if (!istype(M)) + return + + if(activated && inserted_battery.battery_effect.effect == EFFECT_TOUCH && !isnull(inserted_battery)) + inserted_battery.battery_effect.DoEffectTouch(M) + inserted_battery.use_power(energy_consumed_on_touch) + user.visible_message("[user] taps [M] with [src], and it shudders on contact.") + else + user.visible_message("[user] taps [M] with [src], but nothing happens.") + + if(inserted_battery.battery_effect) + admin_attack_log(user, M, "Tapped their victim with \a [src] (EFFECT: [inserted_battery.battery_effect.name])", "Was tapped by \a [src] (EFFECT: [inserted_battery.battery_effect.name])", "used \a [src] (EFFECT: [inserted_battery.battery_effect.name]) to tap") diff --git a/code/modules/xenoarcheaology/tools/artifact_analyser.dm b/code/modules/xenoarcheaology/tools/artifact_analyser.dm new file mode 100644 index 00000000..9a2e1c1f --- /dev/null +++ b/code/modules/xenoarcheaology/tools/artifact_analyser.dm @@ -0,0 +1,159 @@ +/obj/machinery/artifact_analyser + name = "Anomaly Analyser" + desc = "Studies the emissions of anomalous materials to discover their uses." + icon = 'icons/obj/virology.dmi' + icon_state = "isolator" + anchored = 1 + density = 1 + var/scan_in_progress = 0 + var/scan_num = 0 + var/obj/scanned_obj + var/obj/machinery/artifact_scanpad/owned_scanner = null + var/scan_completion_time = 0 + var/scan_duration = 50 + var/obj/scanned_object + var/report_num = 0 + +/obj/machinery/artifact_analyser/Initialize() + . = ..() + reconnect_scanner() + +/obj/machinery/artifact_analyser/proc/reconnect_scanner() + //connect to a nearby scanner pad + owned_scanner = locate(/obj/machinery/artifact_scanpad) in get_step(src, dir) + if(!owned_scanner) + owned_scanner = locate(/obj/machinery/artifact_scanpad) in orange(1, src) + +/obj/machinery/artifact_analyser/attack_hand(var/mob/user as mob) + src.add_fingerprint(user) + interact(user) + +/obj/machinery/artifact_analyser/interact(mob/user) + if(stat & (NOPOWER|BROKEN) || get_dist(src, user) > 1) + user.unset_machine(src) + return + + var/dat = "Anomalous material analyser
                " + dat += "
                " + if(!owned_scanner) + reconnect_scanner() + + if(!owned_scanner) + dat += "Unable to locate analysis pad.
                " + else if(scan_in_progress) + dat += "Please wait. Analysis in progress.
                " + dat += "Halt scanning.
                " + else + dat += "Scanner is ready.
                " + dat += "Begin scanning.
                " + + dat += "
                " + dat += "
                " + dat += "Refresh Close" + user << browse(dat, "window=artanalyser;size=450x500") + user.set_machine(src) + onclose(user, "artanalyser") + +/obj/machinery/artifact_analyser/Process() + if(scan_in_progress && world.time > scan_completion_time) + scan_in_progress = 0 + updateDialog() + + var/results = "" + if(!owned_scanner) + reconnect_scanner() + if(!owned_scanner) + results = "Error communicating with scanner." + else if(!scanned_object || scanned_object.loc != owned_scanner.loc) + results = "Unable to locate scanned object. Ensure it was not moved in the process." + else + results = get_scan_info(scanned_object) + + src.visible_message("[name] states, \"Scanning complete.\"") + var/obj/item/weapon/paper/P = new(src.loc) + P.SetName("[src] report #[++report_num]") + P.info = "[src] analysis report #[report_num]
                " + P.info += "
                " + P.info += "\icon[scanned_object] [results]" + P.stamped = list(/obj/item/weapon/stamp) + P.overlays = list("paper_stamped") + + if(scanned_object && istype(scanned_object, /obj/machinery/artifact)) + var/obj/machinery/artifact/A = scanned_object + A.anchored = 0 + A.being_used = 0 + scanned_object = null + +/obj/machinery/artifact_analyser/OnTopic(user, href_list) + if(href_list["begin_scan"]) + if(!owned_scanner) + reconnect_scanner() + if(owned_scanner) + var/artifact_in_use = 0 + for(var/obj/O in owned_scanner.loc) + if(O == owned_scanner) + continue + if(O.invisibility) + continue + if(istype(O, /obj/machinery/artifact)) + var/obj/machinery/artifact/A = O + if(A.being_used) + artifact_in_use = 1 + else + A.anchored = 1 + A.being_used = 1 + + if(artifact_in_use) + src.visible_message("[name] states, \"Cannot scan. Too much interference.\"") + else + scanned_object = O + scan_in_progress = 1 + scan_completion_time = world.time + scan_duration + src.visible_message("[name] states, \"Scanning begun.\"") + break + if(!scanned_object) + src.visible_message("[name] states, \"Unable to isolate scan target.\"") + . = TOPIC_REFRESH + else if(href_list["halt_scan"]) + scan_in_progress = 0 + src.visible_message("[name] states, \"Scanning halted.\"") + . = TOPIC_REFRESH + + else if(href_list["close"]) + close_browser(user, "window=artanalyser") + return TOPIC_HANDLED + + if(. == TOPIC_REFRESH) + interact(user) + +//hardcoded responses, oh well +/obj/machinery/artifact_analyser/proc/get_scan_info(var/obj/scanned_obj) + switch(scanned_obj.type) + if(/obj/machinery/auto_cloner) + return "Automated cloning pod - appears to rely on an artificial ecosystem formed by semi-organic nanomachines and the contained liquid.
                The liquid resembles protoplasmic residue supportive of unicellular organism developmental conditions.
                The structure is composed of a titanium alloy." + if(/obj/machinery/power/supermatter) + return "Superdense phoron clump - appears to have been shaped or hewn, structure is composed of matter aproximately 20 times denser than ordinary refined phoron." + if(/obj/structure/constructshell) + return "Tribal idol - subject resembles statues/emblems built by superstitious pre-warp civilisations to honour their gods. Material appears to be a rock/plastcrete composite." + if(/obj/machinery/giga_drill) + return "Automated mining drill - structure composed of titanium-carbide alloy, with tip and drill lines edged in an alloy of diamond and phoron." + if(/obj/structure/cult/pylon) + return "Tribal pylon - subject resembles statues/emblems built by cargo cult civilisations to honour energy systems from post-warp civilisations." + if(/obj/machinery/replicator) + return "Automated construction unit - subject appears to be able to synthesize various objects given a material, some with simple internal circuitry. Method unknown." + if(/obj/structure/crystal) + return "Crystal formation - pseudo-organic crystalline matrix, unlikely to have formed naturally. No known technology exists to synthesize this exact composition." + if(/obj/machinery/artifact) + var/obj/machinery/artifact/A = scanned_obj + var/out = "Anomalous alien device - composed of an unknown alloy.

                " + + if(A.my_effect) + out += A.my_effect.getDescription() + + if(A.secondary_effect && A.secondary_effect.activated) + out += "

                Internal scans indicate ongoing secondary activity operating independently from primary systems.

                " + out += A.secondary_effect.getDescription() + + return out + else + return "[scanned_obj.name] - mundane application." diff --git a/code/modules/xenoarcheaology/tools/artifact_harvester.dm b/code/modules/xenoarcheaology/tools/artifact_harvester.dm new file mode 100644 index 00000000..30ee3d32 --- /dev/null +++ b/code/modules/xenoarcheaology/tools/artifact_harvester.dm @@ -0,0 +1,257 @@ +/obj/machinery/artifact_harvester + name = "Exotic Particle Harvester" + icon = 'icons/obj/virology.dmi' + icon_state = "incubator" //incubator_on + anchored = 1 + density = 1 + idle_power_usage = 50 + active_power_usage = 750 + use_power = 1 + var/harvesting = 0 + var/obj/item/weapon/anobattery/inserted_battery + var/obj/machinery/artifact/cur_artifact + var/obj/machinery/artifact_scanpad/owned_scanner = null + var/last_process = 0 + +/obj/machinery/artifact_harvester/New() + ..() + //connect to a nearby scanner pad + owned_scanner = locate(/obj/machinery/artifact_scanpad) in get_step(src, dir) + if(!owned_scanner) + owned_scanner = locate(/obj/machinery/artifact_scanpad) in orange(1, src) + +/obj/machinery/artifact_harvester/attackby(var/obj/I as obj, var/mob/user as mob) + if(istype(I,/obj/item/weapon/anobattery)) + if(!inserted_battery) + to_chat(user, "You insert [I] into [src].") + user.drop_item() + I.loc = src + src.inserted_battery = I + updateDialog() + else + to_chat(user, "There is already a battery in [src].") + else + return..() + +/obj/machinery/artifact_harvester/attack_hand(var/mob/user as mob) + ..() + interact(user) + +/obj/machinery/artifact_harvester/interact(var/mob/user as mob) + if(stat & (NOPOWER|BROKEN)) + return + user.set_machine(src) + var/dat = "Artifact Power Harvester
                " + dat += "

                " + // + if(owned_scanner) + if(harvesting) + if(harvesting > 0) + dat += "Please wait. Harvesting in progress ([round((inserted_battery.stored_charge/inserted_battery.capacity)*100)]%).
                " + else + dat += "Please wait. Energy dump in progress ([round((inserted_battery.stored_charge/inserted_battery.capacity)*100)]%).
                " + dat += "Halt early
                " + else + if(inserted_battery) + dat += "[inserted_battery.name] inserted, charge level: [inserted_battery.stored_charge]/[inserted_battery.capacity] ([(inserted_battery.stored_charge/inserted_battery.capacity)*100]%)
                " + dat += "Energy signature ID:[inserted_battery.battery_effect ? (inserted_battery.battery_effect.artifact_id == "" ? "???" : "[inserted_battery.battery_effect.artifact_id]") : "NA"]
                " + dat += "Eject battery
                " + dat += "Drain battery of all charge
                " + dat += "Begin harvesting
                " + + else + dat += "No battery inserted.
                " + else + dat += "Unable to locate analysis pad.
                " + // + dat += "
                " + dat += "Refresh Close
                " + user << browse(dat, "window=artharvester;size=450x500") + onclose(user, "artharvester") + +/obj/machinery/artifact_harvester/Process() + if(stat & (NOPOWER|BROKEN)) + return + + if(harvesting > 0) + //charge at 33% consumption rate + inserted_battery.stored_charge += (world.time - last_process) / 3 + last_process = world.time + + //check if we've finished + if(inserted_battery.stored_charge >= inserted_battery.capacity) + use_power = 1 + harvesting = 0 + cur_artifact.anchored = 0 + cur_artifact.being_used = 0 + cur_artifact = null + src.visible_message("[name] states, \"Battery is full.\"") + icon_state = "incubator" + + else if(harvesting < 0) + //dump some charge + inserted_battery.stored_charge -= (world.time - last_process) / 3 + + //do the effect + if(inserted_battery.battery_effect) + inserted_battery.battery_effect.process() + + //if the effect works by touch, activate it on anyone viewing the console + if(inserted_battery.battery_effect.effect == EFFECT_TOUCH) + var/list/nearby = viewers(1, src) + for(var/mob/M in nearby) + if(M.machine == src) + inserted_battery.battery_effect.DoEffectTouch(M) + + //if there's no charge left, finish + if(inserted_battery.stored_charge <= 0) + use_power = 1 + inserted_battery.stored_charge = 0 + harvesting = 0 + if(inserted_battery.battery_effect && inserted_battery.battery_effect.activated) + inserted_battery.battery_effect.ToggleActivate() + src.visible_message("[name] states, \"Battery dump completed.\"") + icon_state = "incubator" + +/obj/machinery/artifact_harvester/OnTopic(user, href_list) + if (href_list["harvest"]) + if(!inserted_battery) + src.visible_message("[src] states, \"Cannot harvest. No battery inserted.\"") + + else if(inserted_battery.stored_charge >= inserted_battery.capacity) + src.visible_message("[src] states, \"Cannot harvest. battery is full.\"") + + else + + //locate artifact on analysis pad + cur_artifact = null + var/articount = 0 + var/obj/machinery/artifact/analysed + for(var/obj/machinery/artifact/A in get_turf(owned_scanner)) + analysed = A + articount++ + + if(articount <= 0) + var/message = "[src] states, \"Cannot harvest. No noteworthy energy signature isolated.\"" + src.visible_message(message) + + else if(analysed && analysed.being_used) + src.visible_message("[src] states, \"Cannot harvest. Source already being harvested.\"") + + else + if(articount > 1) + state("Cannot harvest. Too many artifacts on the pad.") + else if(analysed) + cur_artifact = analysed + + //if both effects are active, we can't harvest either + if(cur_artifact.my_effect && cur_artifact.my_effect.activated && cur_artifact.secondary_effect && cur_artifact.secondary_effect.activated) + src.visible_message("[src] states, \"Cannot harvest. Source is emitting conflicting energy signatures.\"") + else if(!cur_artifact.my_effect.activated && !(cur_artifact.secondary_effect && cur_artifact.secondary_effect.activated)) + src.visible_message("[src] states, \"Cannot harvest. No energy emitting from source.\"") + + else + //see if we can clear out an old effect + //delete it when the ids match to account for duplicate ids having different effects + if(inserted_battery.battery_effect && inserted_battery.stored_charge <= 0) + qdel(inserted_battery.battery_effect) + + // + var/datum/artifact_effect/source_effect + + //if we already have charge in the battery, we can only recharge it from the source artifact + if(inserted_battery.stored_charge > 0) + var/battery_matches_primary_id = 0 + if(inserted_battery.battery_effect && inserted_battery.battery_effect.artifact_id == cur_artifact.my_effect.artifact_id) + battery_matches_primary_id = 1 + if(battery_matches_primary_id && cur_artifact.my_effect.activated) + //we're good to recharge the primary effect! + source_effect = cur_artifact.my_effect + + var/battery_matches_secondary_id = 0 + if(inserted_battery.battery_effect && inserted_battery.battery_effect.artifact_id == cur_artifact.secondary_effect.artifact_id) + battery_matches_secondary_id = 1 + if(battery_matches_secondary_id && cur_artifact.secondary_effect.activated) + //we're good to recharge the secondary effect! + source_effect = cur_artifact.secondary_effect + + if(!source_effect) + src.visible_message("[src] states, \"Cannot harvest. Battery is charged with a different energy signature.\"") + else + //we're good to charge either + if(cur_artifact.my_effect.activated) + //charge the primary effect + source_effect = cur_artifact.my_effect + + else if(cur_artifact.secondary_effect.activated) + //charge the secondary effect + source_effect = cur_artifact.secondary_effect + + + if(source_effect) + harvesting = 1 + use_power = 2 + cur_artifact.anchored = 1 + cur_artifact.being_used = 1 + icon_state = "incubator_on" + var/message = "[src] states, \"Beginning energy harvesting.\"" + src.visible_message(message) + last_process = world.time + + //duplicate the artifact's effect datum + if(!inserted_battery.battery_effect) + var/effecttype = source_effect.type + var/datum/artifact_effect/E = new effecttype(inserted_battery) + + //duplicate it's unique settings + for(var/varname in list("chargelevelmax","artifact_id","effect","effectrange","trigger")) + E.vars[varname] = source_effect.vars[varname] + + //copy the new datum into the battery + inserted_battery.battery_effect = E + inserted_battery.stored_charge = 0 + . = TOPIC_REFRESH + + else if (href_list["stopharvest"]) + if(harvesting) + if(harvesting < 0 && inserted_battery.battery_effect && inserted_battery.battery_effect.activated) + inserted_battery.battery_effect.ToggleActivate() + harvesting = 0 + cur_artifact.anchored = 0 + cur_artifact.being_used = 0 + cur_artifact = null + src.visible_message("[name] states, \"Energy harvesting interrupted.\"") + icon_state = "incubator" + . = TOPIC_REFRESH + + else if (href_list["ejectbattery"]) + src.inserted_battery.dropInto(loc) + src.inserted_battery = null + . = TOPIC_REFRESH + + else if (href_list["drainbattery"]) + if(inserted_battery) + if(inserted_battery.battery_effect && inserted_battery.stored_charge > 0) + if(alert("This action will dump all charge, safety gear is recommended before proceeding","Warning","Continue","Cancel")) + if(!inserted_battery.battery_effect.activated) + inserted_battery.battery_effect.ToggleActivate(1) + last_process = world.time + harvesting = -1 + use_power = 2 + icon_state = "incubator_on" + var/message = "[src] states, \"Warning, battery charge dump commencing.\"" + src.visible_message(message) + else + var/message = "[src] states, \"Cannot dump energy. Battery is drained of charge already.\"" + src.visible_message(message) + else + var/message = "[src] states, \"Cannot dump energy. No battery inserted.\"" + src.visible_message(message) + . = TOPIC_REFRESH + + else if(href_list["close"]) + close_browser(user, "window=artharvester") + return TOPIC_HANDLED + + if(. == TOPIC_REFRESH) + interact(user) diff --git a/code/modules/xenoarcheaology/tools/artifact_scanner.dm b/code/modules/xenoarcheaology/tools/artifact_scanner.dm new file mode 100644 index 00000000..c5bdfe01 --- /dev/null +++ b/code/modules/xenoarcheaology/tools/artifact_scanner.dm @@ -0,0 +1,7 @@ +/obj/machinery/artifact_scanpad + name = "Anomaly Scanner Pad" + desc = "Place things here for scanning." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "tele0" + anchored = 1 + density = 0 diff --git a/code/modules/xenoarcheaology/tools/coolant_tank.dm b/code/modules/xenoarcheaology/tools/coolant_tank.dm new file mode 100644 index 00000000..b3110e7d --- /dev/null +++ b/code/modules/xenoarcheaology/tools/coolant_tank.dm @@ -0,0 +1,38 @@ +/obj/structure/reagent_dispensers/coolanttank + name = "coolant tank" + desc = "A tank of industrial coolant" + icon = 'icons/obj/objects.dmi' + icon_state = "coolanttank" + amount_per_transfer_from_this = 10 + +/obj/structure/reagent_dispensers/coolanttank/New() + ..() + reagents.add_reagent(/datum/reagent/coolant, 1000) + +/obj/structure/reagent_dispensers/coolanttank/bullet_act(var/obj/item/projectile/Proj) + if(Proj.get_structure_damage()) + explode() + +/obj/structure/reagent_dispensers/coolanttank/ex_act() + explode() + +/obj/structure/reagent_dispensers/coolanttank/proc/explode() + var/datum/effect/effect/system/smoke_spread/S = new /datum/effect/effect/system/smoke_spread + S.set_up(5, 0, src.loc) + + playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3) + spawn(0) + S.start() + + var/datum/gas_mixture/env = src.loc.return_air() + if(env) + if (reagents.total_volume > 750) + env.temperature = 0 + else if (reagents.total_volume > 500) + env.temperature -= 100 + else + env.temperature -= 50 + + sleep(10) + if(src) + qdel(src) diff --git a/code/modules/xenoarcheaology/tools/equipment.dm b/code/modules/xenoarcheaology/tools/equipment.dm new file mode 100644 index 00000000..c197f2f2 --- /dev/null +++ b/code/modules/xenoarcheaology/tools/equipment.dm @@ -0,0 +1,62 @@ +/obj/item/clothing/suit/bio_suit/anomaly + name = "Anomaly suit" + desc = "A suit that protects against exotic alien energies and biological contamination." + icon_state = "bio_anom" + item_state = "bio_anom" + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 100, rad = 100) + +/obj/item/clothing/head/bio_hood/anomaly + name = "Anomaly hood" + desc = "A hood that protects the head and face from exotic alien energies and biological contamination." + icon_state = "bio_anom" + item_state = "bio_anom" + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 100, rad = 100) + +/obj/item/clothing/suit/space/void/excavation + name = "excavation voidsuit" + desc = "A specially shielded voidsuit that insulates against some exotic alien energies, as well as the more mundane dangers of excavation." + icon_state = "rig-excavation" + armor = list(melee = 30, bullet = 0, laser = 5,energy = 40, bomb = 35, bio = 100, rad = 100) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/stack/flag,/obj/item/weapon/storage/excavation,/obj/item/weapon/pickaxe,/obj/item/device/healthanalyzer,/obj/item/device/measuring_tape,/obj/item/device/ano_scanner,/obj/item/device/depth_scanner,/obj/item/device/core_sampler,/obj/item/device/gps,/obj/item/weapon/pinpointer/radio,/obj/item/device/radio/beacon,/obj/item/weapon/pickaxe/hand,/obj/item/weapon/storage/bag/fossils) + +/obj/item/clothing/head/helmet/space/void/excavation + name = "excavation voidsuit helmet" + desc = "A sophisticated voidsuit helmet, capable of protecting the wearer from many exotic alien energies." + icon_state = "rig0-excavation" + item_state = "excavation-helm" + armor = list(melee = 30, bullet = 0, laser = 5,energy = 40, bomb = 35, bio = 100, rad = 100) + light_overlay = "hardhat_light" + +/obj/item/clothing/suit/space/void/excavation/prepared + helmet = /obj/item/clothing/head/helmet/space/void/excavation + +/obj/item/weapon/storage/belt/archaeology + name = "excavation gear-belt" + desc = "Can hold various excavation gear." + icon_state = "gearbelt" + item_state = ACCESSORY_SLOT_UTILITY + can_hold = list( + /obj/item/weapon/storage/box/samplebags, + /obj/item/device/core_sampler, + /obj/item/weapon/pinpointer/radio, + /obj/item/device/radio/beacon, + /obj/item/device/gps, + /obj/item/device/measuring_tape, + /obj/item/device/flashlight, + /obj/item/weapon/pickaxe, + /obj/item/device/depth_scanner, + /obj/item/device/camera, + /obj/item/weapon/paper, + /obj/item/weapon/photo, + /obj/item/weapon/folder, + /obj/item/weapon/pen, + /obj/item/weapon/folder, + /obj/item/weapon/clipboard, + /obj/item/weapon/anodevice, + /obj/item/clothing/glasses, + /obj/item/weapon/wrench, + /obj/item/weapon/storage/excavation, + /obj/item/weapon/anobattery, + /obj/item/device/ano_scanner, + /obj/item/taperoll, + /obj/item/weapon/pickaxe/hand) \ No newline at end of file diff --git a/code/modules/xenoarcheaology/tools/geosample_scanner.dm b/code/modules/xenoarcheaology/tools/geosample_scanner.dm new file mode 100644 index 00000000..4d51ff35 --- /dev/null +++ b/code/modules/xenoarcheaology/tools/geosample_scanner.dm @@ -0,0 +1,362 @@ +/obj/machinery/radiocarbon_spectrometer + name = "radiocarbon spectrometer" + desc = "A specialised, complex scanner for gleaning information on all manner of small things." + anchored = 1 + density = 1 + atom_flags = ATOM_FLAG_OPEN_CONTAINER + icon = 'icons/obj/virology.dmi' + icon_state = "analyser" + + use_power = 1 //1 = idle, 2 = active + idle_power_usage = 20 + active_power_usage = 300 + + //var/obj/item/weapon/reagent_containers/glass/coolant_container + var/scanning = 0 + var/report_num = 0 + // + var/obj/item/scanned_item + var/last_scan_data = "No scans on record." + // + var/last_process_worldtime = 0 + // + var/scanner_progress = 0 + var/scanner_rate = 1.25 //80 seconds per scan + var/scanner_rpm = 0 + var/scanner_rpm_dir = 1 + var/scanner_temperature = 0 + var/scanner_seal_integrity = 100 + // + var/coolant_usage_rate = 0 //measured in u/microsec + var/fresh_coolant = 0 + var/coolant_purity = 0 + var/datum/reagents/coolant_reagents + var/used_coolant = 0 + var/list/coolant_reagents_purity = list() + // + var/maser_wavelength = 0 + var/optimal_wavelength = 0 + var/optimal_wavelength_target = 0 + var/tleft_retarget_optimal_wavelength = 0 + var/maser_efficiency = 0 + // + var/radiation = 0 //0-100 mSv + var/t_left_radspike = 0 + var/rad_shield = 0 + +/obj/machinery/radiocarbon_spectrometer/New() + ..() + create_reagents(500) + coolant_reagents_purity[/datum/reagent/water] = 0.5 + coolant_reagents_purity[/datum/reagent/drink/coffee/icecoffee] = 0.6 + coolant_reagents_purity[/datum/reagent/drink/tea/icetea] = 0.6 + coolant_reagents_purity[/datum/reagent/drink/milkshake] = 0.6 + coolant_reagents_purity[/datum/reagent/leporazine] = 0.7 + coolant_reagents_purity[/datum/reagent/kelotane] = 0.7 + coolant_reagents_purity[/datum/reagent/sterilizine] = 0.7 + coolant_reagents_purity[/datum/reagent/dermaline] = 0.7 + coolant_reagents_purity[/datum/reagent/hyperzine] = 0.8 + coolant_reagents_purity[/datum/reagent/cryoxadone] = 0.9 + coolant_reagents_purity[/datum/reagent/coolant] = 1 + coolant_reagents_purity[/datum/reagent/adminordrazine] = 2 + +/obj/machinery/radiocarbon_spectrometer/attack_hand(var/mob/user as mob) + ui_interact(user) + +/obj/machinery/radiocarbon_spectrometer/attackby(var/obj/I as obj, var/mob/user as mob) + if(scanning) + to_chat(user, "You can't do that while [src] is scanning!") + else + if(istype(I, /obj/item/stack/nanopaste)) + var/choice = alert("What do you want to do with the nanopaste?","Radiometric Scanner","Scan nanopaste","Fix seal integrity") + if(choice == "Fix seal integrity") + var/obj/item/stack/nanopaste/N = I + var/amount_used = min(N.get_amount(), 10 - scanner_seal_integrity / 10) + N.use(amount_used) + scanner_seal_integrity = round(scanner_seal_integrity + amount_used * 10) + return + if(istype(I, /obj/item/weapon/reagent_containers/glass)) + var/choice = alert("What do you want to do with the container?","Radiometric Scanner","Add coolant","Empty coolant","Scan container") + if(choice == "Add coolant") + var/obj/item/weapon/reagent_containers/glass/G = I + var/amount_transferred = min(src.reagents.maximum_volume - src.reagents.total_volume, G.reagents.total_volume) + G.reagents.trans_to(src, amount_transferred) + to_chat(user, "You empty [amount_transferred]u of coolant into [src].") + update_coolant() + return + else if(choice == "Empty coolant") + var/obj/item/weapon/reagent_containers/glass/G = I + var/amount_transferred = min(G.reagents.maximum_volume - G.reagents.total_volume, src.reagents.total_volume) + src.reagents.trans_to(G, amount_transferred) + to_chat(user, "You remove [amount_transferred]u of coolant from [src].") + update_coolant() + return + if(scanned_item) + to_chat(user, "\The [src] already has \a [scanned_item] inside!") + return + user.drop_item() + I.loc = src + scanned_item = I + to_chat(user, "You put \the [I] into \the [src].") + +/obj/machinery/radiocarbon_spectrometer/proc/update_coolant() + var/total_purity = 0 + fresh_coolant = 0 + coolant_purity = 0 + var/num_reagent_types = 0 + for (var/datum/reagent/current_reagent in src.reagents.reagent_list) + if (!current_reagent) + continue + var/cur_purity = coolant_reagents_purity[current_reagent.type] + if(!cur_purity) + cur_purity = 0.1 + else if(cur_purity > 1) + cur_purity = 1 + total_purity += cur_purity * current_reagent.volume + fresh_coolant += current_reagent.volume + num_reagent_types += 1 + if(total_purity && fresh_coolant) + coolant_purity = total_purity / fresh_coolant + +/obj/machinery/radiocarbon_spectrometer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + + if(user.stat) + return + + // this is the data which will be sent to the ui + var/data[0] + data["scanned_item"] = (scanned_item ? scanned_item.name : "") + data["scanned_item_desc"] = (scanned_item ? (scanned_item.desc ? scanned_item.desc : "No information on record.") : "") + data["last_scan_data"] = last_scan_data + // + data["scan_progress"] = round(scanner_progress) + data["scanning"] = scanning + // + data["scanner_seal_integrity"] = round(scanner_seal_integrity) + data["scanner_rpm"] = round(scanner_rpm) + data["scanner_temperature"] = round(scanner_temperature) + // + data["coolant_usage_rate"] = "[coolant_usage_rate]" + data["unused_coolant_abs"] = round(fresh_coolant) + data["unused_coolant_per"] = round(fresh_coolant / reagents.maximum_volume * 100) + data["coolant_purity"] = "[coolant_purity * 100]" + // + data["optimal_wavelength"] = round(optimal_wavelength) + data["maser_wavelength"] = round(maser_wavelength) + data["maser_efficiency"] = round(maser_efficiency * 100) + // + data["radiation"] = round(radiation) + data["t_left_radspike"] = round(t_left_radspike) + data["rad_shield_on"] = rad_shield + + // update the ui if it exists, returns null if no ui is passed/found + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "geoscanner.tmpl", "High Res Radiocarbon Spectrometer", 900, 825) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(1) + +/obj/machinery/radiocarbon_spectrometer/Process() + if(scanning) + if(!scanned_item || scanned_item.loc != src) + scanned_item = null + stop_scanning() + else if(scanner_progress >= 100) + complete_scan() + else + //calculate time difference + var/deltaT = (world.time - last_process_worldtime) * 0.1 + + //modify the RPM over time + //i want 1u to last for 10 sec at 500 RPM, scaling linearly + scanner_rpm += scanner_rpm_dir * 50 * deltaT + if(scanner_rpm > 1000) + scanner_rpm = 1000 + scanner_rpm_dir = -1 * pick(0.5, 2.5, 5.5) + else if(scanner_rpm < 1) + scanner_rpm = 1 + scanner_rpm_dir = 1 * pick(0.5, 2.5, 5.5) + + //heat up according to RPM + //each unit of coolant + scanner_temperature += scanner_rpm * deltaT * 0.05 + + //radiation + t_left_radspike -= deltaT + if(t_left_radspike > 0) + //ordinary radiation + radiation = rand() * 15 + else + //radspike + if(t_left_radspike > -5) + radiation = rand() * 15 + 85 + if(!rad_shield) + //irradiate nearby mobs + radiation_repository.radiate(src, radiation / 25) + else + t_left_radspike = pick(10,15,25) + + //use some coolant to cool down + if(coolant_usage_rate > 0) + var/coolant_used = min(fresh_coolant, coolant_usage_rate * deltaT) + if(coolant_used > 0) + fresh_coolant -= coolant_used + used_coolant += coolant_used + scanner_temperature = max(scanner_temperature - coolant_used * coolant_purity * 20, 0) + + //modify the optimal wavelength + tleft_retarget_optimal_wavelength -= deltaT + if(tleft_retarget_optimal_wavelength <= 0) + tleft_retarget_optimal_wavelength = pick(4,8,15) + optimal_wavelength_target = rand() * 9900 + 100 + // + if(optimal_wavelength < optimal_wavelength_target) + optimal_wavelength = min(optimal_wavelength + 700 * deltaT, optimal_wavelength_target) + else if(optimal_wavelength > optimal_wavelength_target) + optimal_wavelength = max(optimal_wavelength - 700 * deltaT, optimal_wavelength_target) + // + maser_efficiency = 1 - max(min(10000, abs(optimal_wavelength - maser_wavelength) * 3), 1) / 10000 + + //make some scan progress + if(!rad_shield) + scanner_progress = min(100, scanner_progress + scanner_rate * maser_efficiency * deltaT) + + //degrade the seal over time according to temperature + //i want temperature of 50K to degrade at 1%/sec + scanner_seal_integrity -= (max(scanner_temperature, 1) / 1000) * deltaT + + //emergency stop if seal integrity reaches 0 + if(scanner_seal_integrity <= 0 || (scanner_temperature >= 1273 && !rad_shield)) + stop_scanning() + src.visible_message("\icon[src] buzzes unhappily. It has failed mid-scan!", 2) + + if(prob(5)) + src.visible_message("\icon[src] [pick("whirrs","chuffs","clicks")][pick(" excitedly"," energetically"," busily")].", 2) + else + //gradually cool down over time + if(scanner_temperature > 0) + scanner_temperature = max(scanner_temperature - 5 - 10 * rand(), 0) + if(prob(0.75)) + src.visible_message("\icon[src] [pick("plinks","hisses")][pick(" quietly"," softly"," sadly"," plaintively")].", 2) + last_process_worldtime = world.time + +/obj/machinery/radiocarbon_spectrometer/proc/stop_scanning() + scanning = 0 + scanner_rpm_dir = 1 + scanner_rpm = 0 + optimal_wavelength = 0 + maser_efficiency = 0 + maser_wavelength = 0 + coolant_usage_rate = 0 + radiation = 0 + t_left_radspike = 0 + if(used_coolant) + src.reagents.remove_any(used_coolant) + used_coolant = 0 + +/obj/machinery/radiocarbon_spectrometer/proc/complete_scan() + src.visible_message("\icon[src] makes an insistent chime.", 2) + + if(scanned_item) + //create report + var/obj/item/weapon/paper/P = new(src) + P.SetName("[src] report #[++report_num]: [scanned_item.name]") + P.stamped = list(/obj/item/weapon/stamp) + P.overlays = list("paper_stamped") + + //work out data + var/data = " - Mundane object: [scanned_item.desc ? scanned_item.desc : "No information on record."]
                " + var/datum/geosample/G + switch(scanned_item.type) + if(/obj/item/weapon/ore) + var/obj/item/weapon/ore/O = scanned_item + if(O.geologic_data) + G = O.geologic_data + + if(/obj/item/weapon/rocksliver) + var/obj/item/weapon/rocksliver/O = scanned_item + if(O.geological_data) + G = O.geological_data + + if(/obj/item/weapon/archaeological_find) + data = " - Mundane object (archaic xenos origins)
                " + + var/obj/item/weapon/archaeological_find/A = scanned_item + if(A.talking_atom) + data = " - Exhibits properties consistent with sonic reproduction and audio capture technologies.
                " + + var/anom_found = 0 + if(G) + data = " - Spectometric analysis on mineral sample has determined type [finds_as_strings[responsive_carriers.Find(G.source_mineral)]]
                " + if(G.age_billion > 0) + data += " - Radiometric dating shows age of [G.age_billion].[G.age_million] billion years
                " + else if(G.age_million > 0) + data += " - Radiometric dating shows age of [G.age_million].[G.age_thousand] million years
                " + else + data += " - Radiometric dating shows age of [G.age_thousand * 1000 + G.age] years
                " + data += " - Chromatographic analysis shows the following materials present:
                " + for(var/carrier in G.find_presence) + if(G.find_presence[carrier]) + var/index = responsive_carriers.Find(carrier) + if(index > 0 && index <= finds_as_strings.len) + data += " > [100 * G.find_presence[carrier]]% [finds_as_strings[index]]
                " + + if(G.artifact_id && G.artifact_distance >= 0) + anom_found = 1 + data += " - Hyperspectral imaging reveals exotic energy wavelength detected with ID: [G.artifact_id]
                " + data += " - Fourier transform analysis on anomalous energy absorption indicates energy source located inside emission radius of [G.artifact_distance]m
                " + + if(!anom_found) + data += " - No anomalous data
                " + + P.info = "[src] analysis report #[report_num]
                " + P.info += "Scanned item: [scanned_item.name]

                " + data + last_scan_data = P.info + P.loc = src.loc + + scanned_item.loc = src.loc + scanned_item = null + +/obj/machinery/radiocarbon_spectrometer/OnTopic(user, href_list) + if(href_list["scanItem"]) + if(scanning) + stop_scanning() + else + if(scanned_item) + if(scanner_seal_integrity > 0) + scanner_progress = 0 + scanning = 1 + t_left_radspike = pick(5,10,15) + to_chat(user, "Scan initiated.") + else + to_chat(user, "Could not initiate scan, seal requires replacing.") + else + to_chat(user, "Insert an item to scan.") + . = TOPIC_REFRESH + + else if(href_list["maserWavelength"]) + maser_wavelength = max(min(maser_wavelength + 1000 * text2num(href_list["maserWavelength"]), 10000), 1) + . = TOPIC_REFRESH + + else if(href_list["coolantRate"]) + coolant_usage_rate = max(min(coolant_usage_rate + text2num(href_list["coolantRate"]), 10000), 0) + . = TOPIC_REFRESH + + else if(href_list["toggle_rad_shield"]) + if(rad_shield) + rad_shield = 0 + else + rad_shield = 1 + . = TOPIC_REFRESH + + else if(href_list["ejectItem"]) + if(scanned_item) + scanned_item.loc = src.loc + scanned_item = null + . = TOPIC_REFRESH diff --git a/code/modules/xenoarcheaology/tools/suspension_generator.dm b/code/modules/xenoarcheaology/tools/suspension_generator.dm new file mode 100644 index 00000000..3ffb6f4b --- /dev/null +++ b/code/modules/xenoarcheaology/tools/suspension_generator.dm @@ -0,0 +1,254 @@ +/obj/machinery/suspension_gen + name = "suspension field generator" + desc = "It has stubby legs bolted up against it's body for stabilising." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "suspension2" + density = 1 + req_access = list(access_research) + var/obj/item/weapon/cell/cell + var/obj/item/weapon/card/id/auth_card + var/locked = 1 + var/power_use = 5 KILOWATTS + var/obj/effect/suspension_field/suspension_field + +/obj/machinery/suspension_gen/New() + ..() + src.cell = new /obj/item/weapon/cell/high(src) + +/obj/machinery/suspension_gen/Process() + set background = 1 + if(suspension_field) + cell.use(power_use * CELLRATE) + + var/turf/T = get_turf(suspension_field) + for(var/mob/living/M in T) + M.weakened = max(M.weakened, 3) + cell.use(power_use * CELLRATE) + if(prob(5)) + to_chat(M, "[pick("You feel tingly","You feel like floating","It is hard to speak","You can barely move")].") + + for(var/obj/item/I in T) + if(!suspension_field.contents.len) + suspension_field.icon_state = "energynet" + suspension_field.overlays += "shield2" + I.forceMove(suspension_field) + + if(cell.charge <= 0) + deactivate() + +/obj/machinery/suspension_gen/interact(var/mob/user) + var/dat = "Multi-phase mobile suspension field generator MK II \"Steadfast\"
                " + if(cell) + var/colour = "red" + var/percent = cell.percent() + if(percent > 66) + colour = "green" + else if(percent > 33) + colour = "orange" + dat += "Energy cell: [percent]%
                " + else + dat += "Energy cell: None
                " + if(auth_card) + dat += "
                \[[auth_card]\]
                " + if(!locked) + dat += "
                [suspension_field ? "Disable" : "Enable"] field
                " + else + dat += "
                " + else + dat += "\[------\]
                " + if(!locked) + dat += "
                [suspension_field ? "Disable" : "Enable"] field
                " + else + dat += "Enter your ID to begin.
                " + + dat += "
                " + dat += "
                " + dat += "Always wear safety gear and consult a field manual before operation.
                " + if(!locked) + dat += "Lock console
                " + else + dat += "
                " + dat += "Refresh console
                " + dat += "Close console" + user << browse(dat, "window=suspension;size=500x400") + onclose(user, "suspension") + +/obj/machinery/suspension_gen/OnTopic(var/mob/user, href_list) + if(href_list["toggle_field"]) + if(!suspension_field) + if(cell.charge > 0) + if(anchored) + activate() + else + to_chat(user, "You are unable to activate [src] until it is properly secured on the ground.") + else + deactivate() + . = TOPIC_REFRESH + else if(href_list["insertcard"]) + var/obj/item/I = user.get_active_hand() + if (istype(I, /obj/item/weapon/card)) + user.drop_item() + I.forceMove(src) + auth_card = I + if(attempt_unlock(I, user)) + to_chat(user, "You insert [I], the console flashes \'Access granted.\'") + else + to_chat(user, "You insert [I], the console flashes \'Access denied.\'") + . = TOPIC_REFRESH + else if(href_list["ejectcard"]) + if(auth_card) + if(ishuman(user)) + auth_card.loc = user.loc + if(!user.get_active_hand()) + user.put_in_hands(auth_card) + auth_card = null + else + auth_card.forceMove(loc) + auth_card = null + . = TOPIC_REFRESH + else if(href_list["lock"]) + locked = 1 + . = TOPIC_REFRESH + else if(href_list["close"]) + close_browser(user, "window=suspension") + return TOPIC_HANDLED + + if(. == TOPIC_REFRESH) + interact(user) + +/obj/machinery/suspension_gen/attack_hand(var/mob/user) + if(!panel_open) + interact(user) + else if(cell) + cell.forceMove(loc) + cell.add_fingerprint(user) + cell.update_icon() + + icon_state = "suspension0" + cell = null + to_chat(user, "You remove the power cell") + +/obj/machinery/suspension_gen/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(!locked && !suspension_field && default_deconstruction_screwdriver(user, W)) + return + else if(isWrench(W)) + if(!suspension_field) + if(anchored) + anchored = 0 + else + anchored = 1 + to_chat(user, "You wrench the stabilising legs [anchored ? "into place" : "up against the body"].") + if(anchored) + desc = "It is resting securely on four stubby legs." + else + desc = "It has stubby legs bolted up against it's body for stabilising." + else + to_chat(user, "You are unable to secure [src] while it is active!") + else if (istype(W, /obj/item/weapon/cell)) + if(panel_open) + if(cell) + to_chat(user, "There is a power cell already installed.") + else + user.drop_item() + W.forceMove(src) + cell = W + to_chat(user, "You insert the power cell.") + icon_state = "suspension1" + else if(istype(W, /obj/item/weapon/card)) + var/obj/item/weapon/card/I = W + if(!auth_card) + if(attempt_unlock(I, user)) + to_chat(user, "You swipe [I], the console flashes \'Access granted.\'") + else + to_chat(user, "You swipe [I], console flashes \'Access denied.\'") + else + to_chat(user, "Remove [auth_card] first.") + +/obj/machinery/suspension_gen/proc/attempt_unlock(var/obj/item/weapon/card/C, var/mob/user) + if(!panel_open) + if(istype(C, /obj/item/weapon/card/emag)) + C.resolve_attackby(src, user) + else if(istype(C, /obj/item/weapon/card/id) && check_access(C)) + locked = 0 + if(!locked) + return 1 + +/obj/machinery/suspension_gen/emag_act(var/remaining_charges, var/mob/user) + if(cell.charge > 0 && locked) + locked = 0 + return 1 + +//checks for whether the machine can be activated or not should already have occurred by this point +/obj/machinery/suspension_gen/proc/activate() + var/turf/T = get_turf(get_step(src,dir)) + var/collected = 0 + + for(var/mob/living/M in T) + M.weakened += 5 + M.visible_message("\icon[M] [M] begins to float in the air!","You feel tingly and light, but it is difficult to move.") + + suspension_field = new(T) + src.visible_message("\icon[src] [src] activates with a low hum.") + icon_state = "suspension3" + + for(var/obj/item/I in T) + I.forceMove(suspension_field) + collected++ + + if(collected) + suspension_field.icon_state = "energynet" + suspension_field.overlays += "shield2" + src.visible_message("\icon[suspension_field] [suspension_field] gently absconds [collected > 1 ? "something" : "several things"].") + else + if(istype(T,/turf/simulated/mineral) || istype(T,/turf/simulated/wall)) + suspension_field.icon_state = "shieldsparkles" + else + suspension_field.icon_state = "shield2" + +/obj/machinery/suspension_gen/proc/deactivate() + //drop anything we picked up + var/turf/T = get_turf(suspension_field) + + for(var/mob/living/M in T) + to_chat(M, "You no longer feel like floating.") + M.weakened = min(M.weakened, 3) + + src.visible_message("\icon[src] [src] deactivates with a gentle shudder.") + qdel(suspension_field) + suspension_field = null + icon_state = "suspension2" + +/obj/machinery/suspension_gen/Destroy() + deactivate() + return ..() + +/obj/machinery/suspension_gen/verb/rotate_ccw() + set src in view(1) + set name = "Rotate suspension gen (counter-clockwise)" + set category = "Object" + + if(anchored) + to_chat(usr, "You cannot rotate [src], it has been firmly fixed to the floor.") + else + set_dir(turn(dir, 90)) + +/obj/machinery/suspension_gen/verb/rotate_cw() + set src in view(1) + set name = "Rotate suspension gen (clockwise)" + set category = "Object" + + if(anchored) + to_chat(usr, "You cannot rotate [src], it has been firmly fixed to the floor.") + else + set_dir(turn(dir, -90)) + +/obj/effect/suspension_field + name = "energy field" + icon = 'icons/effects/effects.dmi' + anchored = 1 + density = 1 + +/obj/effect/suspension_field/Destroy() + for(var/atom/movable/I in src) + I.dropInto(loc) + return ..() diff --git a/code/modules/xenoarcheaology/tools/tools.dm b/code/modules/xenoarcheaology/tools/tools.dm new file mode 100644 index 00000000..f4292ede --- /dev/null +++ b/code/modules/xenoarcheaology/tools/tools.dm @@ -0,0 +1,286 @@ +/obj/item/device/gps + name = "relay positioning device" + desc = "Triangulates the approximate co-ordinates using a nearby satellite network." + icon = 'icons/obj/device.dmi' + icon_state = "locator" + item_state = "locator" + origin_tech = list(TECH_MATERIAL = 2, TECH_DATA = 2, TECH_BLUESPACE = 2) + matter = list(DEFAULT_WALL_MATERIAL = 500) + w_class = ITEM_SIZE_SMALL + +/obj/item/device/gps/attack_self(var/mob/user as mob) + var/turf/T = get_turf(src) + to_chat(user, "\icon[src] \The [src] flashes [T.x]:[T.y]:[T.z].") + +/obj/item/device/gps/examine(var/mob/user) + ..() + var/turf/T = get_turf(src) + to_chat(user, "\The [src]'s screen shows: [T.x]:[T.y]:[T.z].") + +/obj/item/device/measuring_tape + name = "measuring tape" + desc = "A coiled metallic tape used to check dimensions and lengths." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "measuring" + origin_tech = list(TECH_MATERIAL = 1) + matter = list(DEFAULT_WALL_MATERIAL = 100) + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/storage/bag/fossils + name = "Fossil Satchel" + desc = "Transports delicate fossils in suspension so they don't break during transit." + icon = 'icons/obj/mining.dmi' + icon_state = "satchel" + slot_flags = SLOT_BELT | SLOT_POCKET + w_class = ITEM_SIZE_NORMAL + storage_slots = 50 + max_storage_space = 200 + max_w_class = ITEM_SIZE_NORMAL + can_hold = list(/obj/item/weapon/fossil) + +/obj/item/weapon/storage/box/samplebags + name = "sample bag box" + desc = "A box claiming to contain sample bags." + +/obj/item/weapon/storage/box/samplebags/New() + ..() + for(var/i = 1 to 7) + var/obj/item/weapon/evidencebag/S = new(src) + S.SetName("sample bag") + S.desc = "a bag for holding research samples." + +/obj/item/device/ano_scanner + name = "Alden-Saraspova counter" + desc = "Aids in triangulation of exotic particles." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "flashgun" + item_state = "lampgreen" + origin_tech = list(TECH_BLUESPACE = 3, TECH_MAGNET = 3) + matter = list(DEFAULT_WALL_MATERIAL = 10000,"glass" = 5000) + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_BELT + + var/last_scan_time = 0 + var/scan_delay = 25 + +/obj/item/device/ano_scanner/attack_self(var/mob/living/user) + interact(user) + +/obj/item/device/ano_scanner/interact(var/mob/living/user) + if(world.time - last_scan_time >= scan_delay) + last_scan_time = world.time + + var/nearestTargetDist = -1 + var/nearestTargetId + + var/nearestSimpleTargetDist = -1 + var/turf/cur_turf = get_turf(src) + + if(master_controller) //Sanity check due to runtimes ~Z + for(var/A in master_controller.artifact_spawning_turfs) + var/turf/simulated/mineral/T = A + if(T.density && T.artifact_find) + if(T.z == cur_turf.z) + var/cur_dist = get_dist(cur_turf, T) * 2 + if(nearestTargetDist < 0 || cur_dist < nearestTargetDist) + nearestTargetDist = cur_dist + rand() * 2 - 1 + nearestTargetId = T.artifact_find.artifact_id + else + master_controller.artifact_spawning_turfs.Remove(T) + + for(var/A in master_controller.digsite_spawning_turfs) + var/turf/simulated/mineral/T = A + if(T.density && T.finds && T.finds.len) + if(T.z == cur_turf.z) + var/cur_dist = get_dist(cur_turf, T) * 2 + if(nearestSimpleTargetDist < 0 || cur_dist < nearestSimpleTargetDist) + nearestSimpleTargetDist = cur_dist + rand() * 2 - 1 + else + master_controller.digsite_spawning_turfs.Remove(T) + + if(nearestTargetDist >= 0) + to_chat(user, "Exotic energy detected on wavelength '[nearestTargetId]' in a radius of [nearestTargetDist]m[nearestSimpleTargetDist > 0 ? "; small anomaly detected in a radius of [nearestSimpleTargetDist]m" : ""]") + else if(nearestSimpleTargetDist >= 0) + to_chat(user, "Small anomaly detected in a radius of [nearestSimpleTargetDist]m.") + else + to_chat(user, "Background radiation levels detected.") + else + to_chat(user, "Scanning array is recharging.") + +/obj/item/device/depth_scanner + name = "depth analysis scanner" + desc = "Used to check spatial depth and density of rock outcroppings." + icon = 'icons/obj/pda.dmi' + icon_state = "crap" + item_state = "analyzer" + origin_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 2, TECH_BLUESPACE = 2) + matter = list(DEFAULT_WALL_MATERIAL = 1000,"glass" = 1000) + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_BELT + var/list/positive_locations = list() + var/datum/depth_scan/current + +/datum/depth_scan + var/time = "" + var/coords = "" + var/depth = "" + var/clearance = 0 + var/record_index = 1 + var/dissonance_spread = 1 + var/material = "unknown" + +/obj/item/device/depth_scanner/proc/scan_atom(var/mob/user, var/atom/A) + user.visible_message("\The [user] scans \the [A], the air around them humming gently.") + + if(istype(A, /turf/simulated/mineral)) + var/turf/simulated/mineral/M = A + if((M.finds && M.finds.len) || M.artifact_find) + + //create a new scanlog entry + var/datum/depth_scan/D = new() + D.coords = "[M.x]:[M.y]:[M.z]" + D.time = stationtime2text() + D.record_index = positive_locations.len + 1 + D.material = M.mineral ? M.mineral.display_name : "Rock" + + //find the first artifact and store it + if(M.finds.len) + var/datum/find/F = M.finds[1] + D.depth = "[F.excavation_required - F.clearance_range] - [F.excavation_required]" + D.clearance = F.clearance_range + D.material = get_responsive_reagent(F.find_type) + + positive_locations.Add(D) + + to_chat(user, "\icon[src] [src] pings.") + + else if(istype(A, /obj/structure/boulder)) + var/obj/structure/boulder/B = A + if(B.artifact_find) + //create a new scanlog entry + var/datum/depth_scan/D = new() + D.coords = "[B.x]:[B.y]:[B.z]" + D.time = stationtime2text() + D.record_index = positive_locations.len + 1 + + //these values are arbitrary + D.depth = rand(150, 200) + D.clearance = rand(10, 50) + D.dissonance_spread = rand(750, 2500) / 100 + + positive_locations.Add(D) + + to_chat(user, "\icon[src] [src] pings [pick("madly","wildly","excitedly","crazily")]!") + +/obj/item/device/depth_scanner/attack_self(var/mob/living/user) + interact(user) + +/obj/item/device/depth_scanner/interact(var/mob/user as mob) + var/dat = "Coordinates with positive matches
                " + + dat += "== Clear all ==
                " + + if(current) + dat += "Time: [current.time]
                " + dat += "Coords: [current.coords]
                " + dat += "Anomaly depth: [current.depth] cm
                " + dat += "Anomaly size: [current.clearance] cm
                " + dat += "Dissonance spread: [current.dissonance_spread]
                " + var/index = responsive_carriers.Find(current.material) + if(index > 0 && index <= finds_as_strings.len) + dat += "Anomaly material: [finds_as_strings[index]]
                " + else + dat += "Anomaly material: Unknown
                " + dat += "clear entry
                " + else + dat += "Select an entry from the list
                " + dat += "



                " + dat += "
                " + if(positive_locations.len) + for(var/index = 1 to positive_locations.len) + var/datum/depth_scan/D = positive_locations[index] + dat += "[D.time], coords: [D.coords]
                " + else + dat += "No entries recorded." + + dat += "
                " + dat += "Refresh
                " + dat += "Close
                " + user << browse(dat,"window=depth_scanner;size=300x500") + onclose(user, "depth_scanner") + +/obj/item/device/depth_scanner/OnTopic(user, href_list) + if(href_list["select"]) + var/index = text2num(href_list["select"]) + if(index && index <= positive_locations.len) + current = positive_locations[index] + . = TOPIC_REFRESH + else if(href_list["clear"]) + var/index = text2num(href_list["clear"]) + if(index) + if(index <= positive_locations.len) + var/datum/depth_scan/D = positive_locations[index] + positive_locations.Remove(D) + qdel(D) + else + //GC will hopefully pick them up before too long + positive_locations = list() + QDEL_NULL(current) + . = TOPIC_REFRESH + else if(href_list["close"]) + close_browser(user, "window=depth_scanner") + updateSelfDialog() + +//Radio beacon locator +/obj/item/weapon/pinpointer/radio + name = "locator device" + desc = "Used to scan and locate signals on a particular frequency." + var/tracking_freq = PUB_FREQ + +/obj/item/weapon/pinpointer/radio/acquire_target() + var/turf/T = get_turf(src) + var/zlevels = GetConnectedZlevels(T.z) + var/cur_dist = world.maxx+world.maxy + for(var/obj/item/device/radio/beacon/R in world) + if((R.z in zlevels) && R.frequency == tracking_freq) + var/check_dist = get_dist(src,R) + if(check_dist < cur_dist) + cur_dist = check_dist + . = weakref(R) + +/obj/item/weapon/pinpointer/radio/attack_self(var/mob/user as mob) + interact(user) + +/obj/item/weapon/pinpointer/radio/interact(var/mob/user) + var/dat = "Radio frequency tracker
                " + dat += {" + Tracking: [active ? "Enabled" : "Disabled"]
                + Reset tracker
                + Frequency: + - + - + [format_frequency(tracking_freq)] + + + +
                + "} + user << browse(dat,"window=locater;size=300x150") + onclose(user, "locater") + +/obj/item/weapon/pinpointer/radio/OnTopic(user, href_list) + if(href_list["toggle"]) + toggle(user) + . = TOPIC_REFRESH + + if(href_list["reset_tracking"]) + target = acquire_target() + . = TOPIC_REFRESH + + else if(href_list["freq"]) + var/new_frequency = (tracking_freq + text2num(href_list["freq"])) + if (new_frequency < 1200 || new_frequency > 1600) + new_frequency = sanitize_frequency(new_frequency, 1499) + tracking_freq = new_frequency + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + interact(user) \ No newline at end of file diff --git a/code/modules/xenoarcheaology/tools/tools_pickaxe.dm b/code/modules/xenoarcheaology/tools/tools_pickaxe.dm new file mode 100644 index 00000000..cea4353e --- /dev/null +++ b/code/modules/xenoarcheaology/tools/tools_pickaxe.dm @@ -0,0 +1,151 @@ +/obj/item/weapon/pickaxe/brush + name = "brush" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "pick_brush" + item_state = "syringe_0" + slot_flags = SLOT_EARS + digspeed = 20 + desc = "Thick metallic wires for clearing away dust and loose scree (1 centimetre excavation depth)." + excavation_amount = 1 + drill_sound = 'sound/weapons/thudswoosh.ogg' + drill_verb = "brushing" + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/pickaxe/one_pick + name = "2cm pick" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "pick1" + item_state = "syringe_0" + digspeed = 20 + desc = "A miniature excavation tool for precise digging (2 centimetre excavation depth)." + excavation_amount = 2 + drill_sound = 'sound/items/Screwdriver.ogg' + drill_verb = "delicately picking" + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/pickaxe/two_pick + name = "4cm pick" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "pick2" + item_state = "syringe_0" + digspeed = 20 + desc = "A miniature excavation tool for precise digging (4 centimetre excavation depth)." + excavation_amount = 4 + drill_sound = 'sound/items/Screwdriver.ogg' + drill_verb = "delicately picking" + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/pickaxe/three_pick + name = "6cm pick" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "pick3" + item_state = "syringe_0" + digspeed = 20 + desc = "A miniature excavation tool for precise digging (6 centimetre excavation depth)." + excavation_amount = 6 + drill_sound = 'sound/items/Screwdriver.ogg' + drill_verb = "delicately picking" + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/pickaxe/four_pick + name = "8cm pick" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "pick4" + item_state = "syringe_0" + digspeed = 20 + desc = "A miniature excavation tool for precise digging (8 centimetre excavation depth)." + excavation_amount = 8 + drill_sound = 'sound/items/Screwdriver.ogg' + drill_verb = "delicately picking" + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/pickaxe/five_pick + name = "10cm pick" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "pick5" + item_state = "syringe_0" + digspeed = 20 + desc = "A miniature excavation tool for precise digging (10 centimetre excavation depth)." + excavation_amount = 10 + drill_sound = 'sound/items/Screwdriver.ogg' + drill_verb = "delicately picking" + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/pickaxe/six_pick + name = "12cm pick" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "pick6" + item_state = "syringe_0" + digspeed = 20 + desc = "A miniature excavation tool for precise digging (12 centimetre excavation depth)." + excavation_amount = 12 + drill_sound = 'sound/items/Screwdriver.ogg' + drill_verb = "delicately picking" + w_class = ITEM_SIZE_SMALL + +/obj/item/weapon/pickaxe/hand + name = "hand pickaxe" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "pick_hand" + item_state = "syringe_0" + digspeed = 30 + desc = "A smaller, more precise version of the pickaxe (30 centimetre excavation depth)." + excavation_amount = 30 + drill_sound = 'sound/items/Crowbar.ogg' + drill_verb = "clearing" + w_class = ITEM_SIZE_SMALL + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Pack for holding pickaxes + +/obj/item/weapon/storage/excavation + name = "excavation pick set" + icon = 'icons/obj/storage.dmi' + icon_state = "excavation" + desc = "A set of picks for excavation." + item_state = "syringe_kit" + storage_slots = 7 + w_class = ITEM_SIZE_SMALL + can_hold = list(/obj/item/weapon/pickaxe/brush, + /obj/item/weapon/pickaxe/one_pick, + /obj/item/weapon/pickaxe/two_pick, + /obj/item/weapon/pickaxe/three_pick, + /obj/item/weapon/pickaxe/four_pick, + /obj/item/weapon/pickaxe/five_pick, + /obj/item/weapon/pickaxe/six_pick, + /obj/item/weapon/pickaxe/hand) + max_storage_space = 18 + max_w_class = ITEM_SIZE_SMALL + use_to_pickup = 1 + +/obj/item/weapon/storage/excavation/New() + ..() + new /obj/item/weapon/pickaxe/brush(src) + new /obj/item/weapon/pickaxe/one_pick(src) + new /obj/item/weapon/pickaxe/two_pick(src) + new /obj/item/weapon/pickaxe/three_pick(src) + new /obj/item/weapon/pickaxe/four_pick(src) + new /obj/item/weapon/pickaxe/five_pick(src) + new /obj/item/weapon/pickaxe/six_pick(src) + +/obj/item/weapon/storage/excavation/handle_item_insertion() + ..() + sort_picks() + +/obj/item/weapon/storage/excavation/proc/sort_picks() + var/list/obj/item/weapon/pickaxe/picksToSort = list() + for(var/obj/item/weapon/pickaxe/P in src) + picksToSort += P + P.loc = null + while(picksToSort.len) + var/min = 200 // No pick is bigger than 200 + var/selected = 0 + for(var/i = 1 to picksToSort.len) + var/obj/item/weapon/pickaxe/current = picksToSort[i] + if(current.excavation_amount <= min) + selected = i + min = current.excavation_amount + var/obj/item/weapon/pickaxe/smallest = picksToSort[selected] + smallest.loc = src + picksToSort -= smallest + prepare_ui() diff --git a/code/modules/xgm/gases.dm b/code/modules/xgm/gases.dm new file mode 100644 index 00000000..96bd4968 --- /dev/null +++ b/code/modules/xgm/gases.dm @@ -0,0 +1,159 @@ +/decl/xgm_gas/oxygen + id = "oxygen" + name = "Oxygen" + specific_heat = 20 // J/(mol*K) + molar_mass = 0.032 // kg/mol + + flags = XGM_GAS_OXIDIZER | XGM_GAS_FUSION_FUEL + +/decl/xgm_gas/nitrogen + id = "nitrogen" + name = "Nitrogen" + specific_heat = 20 // J/(mol*K) + molar_mass = 0.028 // kg/mol + +/decl/xgm_gas/carbon_dioxide + id = "carbon_dioxide" + name = "Carbon Dioxide" + specific_heat = 30 // J/(mol*K) + molar_mass = 0.044 // kg/mol + +/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. + //Using multiplicity rule, it's atomic number is 162 + //and following a N/Z ratio of 1.5, the molar mass of a monatomic gas is: + molar_mass = 0.405 // kg/mol + + tile_overlay = "phoron" + overlay_limit = 0.7 + flags = XGM_GAS_FUEL | XGM_GAS_CONTAMINANT | XGM_GAS_FUSION_FUEL + +/decl/xgm_gas/sleeping_agent + id = "sleeping_agent" + name = "Nitrous Oxide" + specific_heat = 40 // J/(mol*K) + molar_mass = 0.044 // kg/mol. N2O + + tile_overlay = "sleeping_agent" + overlay_limit = 1 + flags = XGM_GAS_OXIDIZER //N2O is a powerful oxidizer + +/decl/xgm_gas/methane + id = "methane" + name = "Methane" + + specific_heat = 30 // J/(mol*K) + molar_mass = 0.016 // kg/mol + + flags = XGM_GAS_FUEL + +/decl/xgm_gas/alium + id = "aliether" + name = "Aliether" + +/decl/xgm_gas/alium/New() + name = "Compound #[rand(100,999)]" + specific_heat = rand(1, 400) // J/(mol*K) + molar_mass = rand(20,800)/1000 // kg/mol + if(prob(40)) + flags |= XGM_GAS_FUEL + else if(prob(40)) //it's prooobably a bad idea for gas being oxidizer to itself. + flags |= XGM_GAS_OXIDIZER + if(prob(40)) + flags |= XGM_GAS_CONTAMINANT + if(prob(40)) + flags |= XGM_GAS_FUSION_FUEL + +/decl/xgm_gas/hydrogen + id = "hydrogen" + name = "Hydrogen" + + specific_heat = 100 // J/(mol*K) + molar_mass = 0.002 // kg/mol + + flags = XGM_GAS_FUEL|XGM_GAS_FUSION_FUEL + + burn_product = "watervapor" + +/decl/xgm_gas/hydrogen/deuterium + id = "deuterium" + name = "Deuterium" + +/decl/xgm_gas/hydrogen/tritium + id = "tritium" + name = "Tritium" + +/decl/xgm_gas/helium + id = "helium" + name = "Helium" + + specific_heat = 80 // J/(mol*K) + molar_mass = 0.004 // kg/mol + + flags = XGM_GAS_FUSION_FUEL + +/decl/xgm_gas/argon + id = "argon" + name = "Argon" + + specific_heat = 10 // J/(mol*K) + molar_mass = 0.018 // kg/mol + +/decl/xgm_gas/krypton + id = "krypton" + name = "Krypton" + + specific_heat = 5 // J/(mol*K) + molar_mass = 0.036 // kg/mol + +/decl/xgm_gas/neon + id = "neon" + name = "Neon" + + specific_heat = 20 // J/(mol*K) + molar_mass = 0.01 // kg/mol + +/decl/xgm_gas/xenon + id = "xenon" + name = "Xenon" + + specific_heat = 3 // J/(mol*K) + molar_mass = 0.054 // kg/mol + +/decl/xgm_gas/nitrodioxide + id = "nitrodioxide" + name = "Nitrogen Dioxide" + + specific_heat = 37 // J/(mol*K) + molar_mass = 0.054 // kg/mol + flags = XGM_GAS_OXIDIZER + +/decl/xgm_gas/nitricoxide + id = "nitricoxide" + name = "Nitric Oxide" + + specific_heat = 10 // J/(mol*K) + molar_mass = 0.030 // kg/mol + flags = XGM_GAS_OXIDIZER + +/decl/xgm_gas/chlorine + id = "chlorine" + name = "Chlorine" + + specific_heat = 5 // J/(mol*K) + molar_mass = 0.017 // kg/mol + flags = XGM_GAS_CONTAMINANT + +/decl/xgm_gas/vapor + id = "watervapor" + name = "Water Vapor" + + specific_heat = 30 // J/(mol*K) + molar_mass = 0.020 // kg/mol \ No newline at end of file diff --git a/code/modules/xgm/xgm_gas_data.dm b/code/modules/xgm/xgm_gas_data.dm new file mode 100644 index 00000000..3f032944 --- /dev/null +++ b/code/modules/xgm/xgm_gas_data.dm @@ -0,0 +1,53 @@ +/var/datum/xgm_gas_data/gas_data + +/datum/xgm_gas_data + //Simple list of all the gas IDs. + var/list/gases = list() + //The friendly, human-readable name for the gas. + var/list/name = list() + //Specific heat of the gas. Used for calculating heat capacity. + var/list/specific_heat = list() + //Molar mass of the gas. Used for calculating specific entropy. + var/list/molar_mass = list() + //Tile overlays. /images, created from references to 'icons/effects/tile_effects.dmi' + var/list/tile_overlay = list() + //Overlay limits. There must be at least this many moles for the overlay to appear. + var/list/overlay_limit = list() + //Flags. + var/list/flags = list() + //Products created when burned. For fuel only for now (not oxidizers) + var/list/burn_product = list() + +/decl/xgm_gas + var/id = "" + var/name = "Unnamed Gas" + var/specific_heat = 20 // J/(mol*K) + var/molar_mass = 0.032 // kg/mol + + var/tile_overlay = null + var/overlay_limit = null + + var/flags = 0 + var/burn_product = "carbon_dioxide" + +/hook/startup/proc/generateGasData() + gas_data = new + for(var/p in (typesof(/decl/xgm_gas) - /decl/xgm_gas)) + var/decl/xgm_gas/gas = new p //avoid initial() because of potential New() actions + + if(gas.id in gas_data.gases) + error("Duplicate gas id `[gas.id]` in `[p]`") + + gas_data.gases += gas.id + gas_data.name[gas.id] = gas.name + gas_data.specific_heat[gas.id] = gas.specific_heat + gas_data.molar_mass[gas.id] = gas.molar_mass + if(gas.tile_overlay) + var/image/I = image('icons/effects/tile_effects.dmi', gas.tile_overlay, FLY_LAYER) + I.appearance_flags = RESET_COLOR + gas_data.tile_overlay[gas.id] = I + if(gas.overlay_limit) gas_data.overlay_limit[gas.id] = gas.overlay_limit + gas_data.flags[gas.id] = gas.flags + gas_data.burn_product[gas.id] = gas.burn_product + + return 1 diff --git a/code/modules/xgm/xgm_gas_mixture.dm b/code/modules/xgm/xgm_gas_mixture.dm new file mode 100644 index 00000000..7b7d1e2e --- /dev/null +++ b/code/modules/xgm/xgm_gas_mixture.dm @@ -0,0 +1,509 @@ +/datum/gas_mixture + //Associative list of gas moles. + //Gases with 0 moles are not tracked and are pruned by update_values() + var/list/gas = list() + //Temperature in Kelvin of this gas mix. + var/temperature = 0 + + //Sum of all the gas moles in this mix. Updated by update_values() + var/total_moles = 0 + //Volume of this mix. + var/volume = CELL_VOLUME + //Size of the group this gas_mixture is representing. 1 for singletons. + var/group_multiplier = 1 + + //List of active tile overlays for this gas_mixture. Updated by check_tile_graphic() + var/list/graphic = list() + +/datum/gas_mixture/New(_volume = CELL_VOLUME, _temperature = 0, _group_multiplier = 1) + volume = _volume + temperature = _temperature + group_multiplier = _group_multiplier + +/datum/gas_mixture/proc/get_gas(gasid) + if(!gas.len) + return 0 //if the list is empty BYOND treats it as a non-associative list, which runtimes + return gas[gasid] * group_multiplier + +/datum/gas_mixture/proc/get_total_moles() + return total_moles * group_multiplier + +//Takes a gas string and the amount of moles to adjust by. Calls update_values() if update isn't 0. +/datum/gas_mixture/proc/adjust_gas(gasid, moles, update = 1) + if(moles == 0) + return + + if (group_multiplier != 1) + gas[gasid] += moles/group_multiplier + else + gas[gasid] += moles + + if(update) + update_values() + + +//Same as adjust_gas(), but takes a temperature which is mixed in with the gas. +/datum/gas_mixture/proc/adjust_gas_temp(gasid, moles, temp, update = 1) + if(moles == 0) + return + + if(moles > 0 && abs(temperature - temp) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity() + var/giver_heat_capacity = gas_data.specific_heat[gasid] * moles + var/combined_heat_capacity = giver_heat_capacity + self_heat_capacity + if(combined_heat_capacity != 0) + temperature = (temp * giver_heat_capacity + temperature * self_heat_capacity) / combined_heat_capacity + + if (group_multiplier != 1) + gas[gasid] += moles/group_multiplier + else + gas[gasid] += moles + + if(update) + update_values() + + +//Variadic version of adjust_gas(). Takes any number of gas and mole pairs and applies them. +/datum/gas_mixture/proc/adjust_multi() + ASSERT(!(args.len % 2)) + + for(var/i = 1; i < args.len; i += 2) + adjust_gas(args[i], args[i+1], update = 0) + + update_values() + + +//Variadic version of adjust_gas_temp(). Takes any number of gas, mole and temperature associations and applies them. +/datum/gas_mixture/proc/adjust_multi_temp() + ASSERT(!(args.len % 3)) + + for(var/i = 1; i < args.len; i += 3) + adjust_gas_temp(args[i], args[i + 1], args[i + 2], update = 0) + + update_values() + + +//Merges all the gas from another mixture into this one. Respects group_multipliers and adjusts temperature correctly. +//Does not modify giver in any way. +/datum/gas_mixture/proc/merge(const/datum/gas_mixture/giver) + if(!giver) + return + + if(abs(temperature-giver.temperature)>MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity() + var/giver_heat_capacity = giver.heat_capacity() + var/combined_heat_capacity = giver_heat_capacity + self_heat_capacity + if(combined_heat_capacity != 0) + temperature = (giver.temperature*giver_heat_capacity + temperature*self_heat_capacity)/combined_heat_capacity + + if((group_multiplier != 1)||(giver.group_multiplier != 1)) + for(var/g in giver.gas) + gas[g] += giver.gas[g] * giver.group_multiplier / group_multiplier + else + for(var/g in giver.gas) + gas[g] += giver.gas[g] + + update_values() + +// Used to equalize the mixture between two zones before sleeping an edge. +/datum/gas_mixture/proc/equalize(datum/gas_mixture/sharer) + var/our_heatcap = heat_capacity() + var/share_heatcap = sharer.heat_capacity() + + // Special exception: there isn't enough air around to be worth processing this edge next tick, zap both to zero. + if(total_moles + sharer.total_moles <= MINIMUM_AIR_TO_SUSPEND) + gas.Cut() + sharer.gas.Cut() + + for(var/g in gas|sharer.gas) + var/comb = gas[g] + sharer.gas[g] + comb /= volume + sharer.volume + gas[g] = comb * volume + sharer.gas[g] = comb * sharer.volume + + if(our_heatcap + share_heatcap) + temperature = ((temperature * our_heatcap) + (sharer.temperature * share_heatcap)) / (our_heatcap + share_heatcap) + sharer.temperature = temperature + + update_values() + sharer.update_values() + + return 1 + + +//Returns the heat capacity of the gas mix based on the specific heat of the gases. +/datum/gas_mixture/proc/heat_capacity() + . = 0 + for(var/g in gas) + . += gas_data.specific_heat[g] * gas[g] + . *= group_multiplier + + +//Adds or removes thermal energy. Returns the actual thermal energy change, as in the case of removing energy we can't go below TCMB. +/datum/gas_mixture/proc/add_thermal_energy(var/thermal_energy) + + if (total_moles == 0) + return 0 + + var/heat_capacity = heat_capacity() + if (thermal_energy < 0) + if (temperature < TCMB) + return 0 + var/thermal_energy_limit = -(temperature - TCMB)*heat_capacity //ensure temperature does not go below TCMB + thermal_energy = max( thermal_energy, thermal_energy_limit ) //thermal_energy and thermal_energy_limit are negative here. + temperature += thermal_energy/heat_capacity + return thermal_energy + +//Returns the thermal energy change required to get to a new temperature +/datum/gas_mixture/proc/get_thermal_energy_change(var/new_temperature) + return heat_capacity()*(max(new_temperature, 0) - temperature) + + +//Technically vacuum doesn't have a specific entropy. Just use a really big number (infinity would be ideal) here so that it's easy to add gas to vacuum and hard to take gas out. +#define SPECIFIC_ENTROPY_VACUUM 150000 + + +//Returns the ideal gas specific entropy of the whole mix. This is the entropy per mole of /mixed/ gas. +/datum/gas_mixture/proc/specific_entropy() + if (!gas.len || total_moles == 0) + return SPECIFIC_ENTROPY_VACUUM + + . = 0 + for(var/g in gas) + . += gas[g] * specific_entropy_gas(g) + . /= total_moles + + +/* + It's arguable whether this should even be called entropy anymore. It's more "based on" entropy than actually entropy now. + + Returns the ideal gas specific entropy of a specific gas in the mix. This is the entropy due to that gas per mole of /that/ gas in the mixture, not the entropy due to that gas per mole of gas mixture. + + For the purposes of SS13, the specific entropy is just a number that tells you how hard it is to move gas. You can replace this with whatever you want. + Just remember that returning a SMALL number == adding gas to this gas mix is HARD, taking gas away is EASY, and that returning a LARGE number means the opposite (so a vacuum should approach infinity). + + So returning a constant/(partial pressure) would probably do what most players expect. Although the version I have implemented below is a bit more nuanced than simply 1/P in that it scales in a way + which is bit more realistic (natural log), and returns a fairly accurate entropy around room temperatures and pressures. +*/ +/datum/gas_mixture/proc/specific_entropy_gas(var/gasid) + if (!(gasid in gas) || gas[gasid] == 0) + return SPECIFIC_ENTROPY_VACUUM //that gas isn't here + + //group_multiplier gets divided out in volume/gas[gasid] - also, V/(m*T) = R/(partial pressure) + var/molar_mass = gas_data.molar_mass[gasid] + var/specific_heat = gas_data.specific_heat[gasid] + return R_IDEAL_GAS_EQUATION * ( log( (IDEAL_GAS_ENTROPY_CONSTANT*volume/(gas[gasid] * temperature)) * (molar_mass*specific_heat*temperature)**(2/3) + 1 ) + 15 ) + + //alternative, simpler equation + //var/partial_pressure = gas[gasid] * R_IDEAL_GAS_EQUATION * temperature / volume + //return R_IDEAL_GAS_EQUATION * ( log (1 + IDEAL_GAS_ENTROPY_CONSTANT/partial_pressure) + 20 ) + + +//Updates the total_moles count and trims any empty gases. +/datum/gas_mixture/proc/update_values() + total_moles = 0 + for(var/g in gas) + if(gas[g] <= 0) + gas -= g + else + total_moles += gas[g] + + +//Returns the pressure of the gas mix. Only accurate if there have been no gas modifications since update_values() has been called. +/datum/gas_mixture/proc/return_pressure() + if(volume) + return total_moles * R_IDEAL_GAS_EQUATION * temperature / volume + return 0 + + +//Removes moles from the gas mixture and returns a gas_mixture containing the removed air. +/datum/gas_mixture/proc/remove(amount) + amount = min(amount, total_moles * group_multiplier) //Can not take more air than the gas mixture has! + if(amount <= 0) + return null + + var/datum/gas_mixture/removed = new + + for(var/g in gas) + removed.gas[g] = QUANTIZE((gas[g] / total_moles) * amount) + gas[g] -= removed.gas[g] / group_multiplier + + removed.temperature = temperature + update_values() + removed.update_values() + + return removed + + +//Removes a ratio of gas from the mixture and returns a gas_mixture containing the removed air. +/datum/gas_mixture/proc/remove_ratio(ratio, out_group_multiplier = 1) + if(ratio <= 0) + return null + out_group_multiplier = between(1, out_group_multiplier, group_multiplier) + + ratio = min(ratio, 1) + + var/datum/gas_mixture/removed = new + removed.group_multiplier = out_group_multiplier + + for(var/g in gas) + removed.gas[g] = (gas[g] * ratio * group_multiplier / out_group_multiplier) + gas[g] = gas[g] * (1 - ratio) + + removed.temperature = temperature + removed.volume = volume * group_multiplier / out_group_multiplier + update_values() + removed.update_values() + + return removed + +//Removes a volume of gas from the mixture and returns a gas_mixture containing the removed air with the given volume +/datum/gas_mixture/proc/remove_volume(removed_volume) + var/datum/gas_mixture/removed = remove_ratio(removed_volume/(volume*group_multiplier), 1) + removed.volume = removed_volume + return removed + +//Removes moles from the gas mixture, limited by a given flag. Returns a gax_mixture containing the removed air. +/datum/gas_mixture/proc/remove_by_flag(flag, amount) + var/datum/gas_mixture/removed = new + + if(!flag || amount <= 0) + return removed + + var/sum = 0 + for(var/g in gas) + if(gas_data.flags[g] & flag) + sum += gas[g] + + for(var/g in gas) + if(gas_data.flags[g] & flag) + removed.gas[g] = QUANTIZE((gas[g] / sum) * amount) + gas[g] -= removed.gas[g] / group_multiplier + + removed.temperature = temperature + update_values() + removed.update_values() + + return removed + +//Returns the amount of gas that has the given flag, in moles +/datum/gas_mixture/proc/get_by_flag(flag) + . = 0 + for(var/g in gas) + if(gas_data.flags[g] & flag) + . += gas[g] + +//Copies gas and temperature from another gas_mixture. +/datum/gas_mixture/proc/copy_from(const/datum/gas_mixture/sample) + gas = sample.gas.Copy() + temperature = sample.temperature + + update_values() + + return 1 + + +//Checks if we are within acceptable range of another gas_mixture to suspend processing or merge. +/datum/gas_mixture/proc/compare(const/datum/gas_mixture/sample, var/vacuum_exception = 0) + if(!sample) return 0 + + if(vacuum_exception) + // Special case - If one of the two is zero pressure, the other must also be zero. + // This prevents suspending processing when an air-filled room is next to a vacuum, + // an edge case which is particually obviously wrong to players + if(total_moles == 0 && sample.total_moles != 0 || sample.total_moles == 0 && total_moles != 0) + return 0 + + var/list/marked = list() + for(var/g in gas) + if((abs(gas[g] - sample.gas[g]) > MINIMUM_AIR_TO_SUSPEND) && \ + ((gas[g] < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]) || \ + (gas[g] > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]))) + return 0 + marked[g] = 1 + + if(abs(return_pressure() - sample.return_pressure()) > MINIMUM_PRESSURE_DIFFERENCE_TO_SUSPEND) + return 0 + + for(var/g in sample.gas) + if(!marked[g]) + if((abs(gas[g] - sample.gas[g]) > MINIMUM_AIR_TO_SUSPEND) && \ + ((gas[g] < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]) || \ + (gas[g] > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]))) + return 0 + + if(total_moles > MINIMUM_AIR_TO_SUSPEND) + if((abs(temperature - sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \ + ((temperature < (1 - MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature) || \ + (temperature > (1 + MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature))) + return 0 + + return 1 + + +/datum/gas_mixture/proc/react() + zburn(null, force_burn=0, no_check=0) //could probably just call zburn() here with no args but I like being explicit. + + +//Rechecks the gas_mixture and adjusts the graphic list if needed. +//Two lists can be passed by reference if you need know specifically which graphics were added and removed. +/datum/gas_mixture/proc/check_tile_graphic(list/graphic_add = null, list/graphic_remove = null) + for(var/g in gas_data.overlay_limit) + if(graphic.Find(gas_data.tile_overlay[g])) + //Overlay is already applied for this gas, check if it's still valid. + if(gas[g] <= gas_data.overlay_limit[g]) + if(!graphic_remove) + graphic_remove = list() + graphic_remove += gas_data.tile_overlay[g] + else + //Overlay isn't applied for this gas, check if it's valid and needs to be added. + if(gas[g] > gas_data.overlay_limit[g]) + if(!graphic_add) + graphic_add = list() + graphic_add += gas_data.tile_overlay[g] + + . = 0 + //Apply changes + if(graphic_add && graphic_add.len) + graphic += graphic_add + . = 1 + if(graphic_remove && graphic_remove.len) + graphic -= graphic_remove + . = 1 + + +//Simpler version of merge(), adjusts gas amounts directly and doesn't account for temperature or group_multiplier. +/datum/gas_mixture/proc/add(datum/gas_mixture/right_side) + for(var/g in right_side.gas) + gas[g] += right_side.gas[g] + + update_values() + return 1 + + +//Simpler version of remove(), adjusts gas amounts directly and doesn't account for group_multiplier. +/datum/gas_mixture/proc/subtract(datum/gas_mixture/right_side) + for(var/g in right_side.gas) + gas[g] -= right_side.gas[g] + + update_values() + return 1 + + +//Multiply all gas amounts by a factor. +/datum/gas_mixture/proc/multiply(factor) + for(var/g in gas) + gas[g] *= factor + + update_values() + return 1 + + +//Divide all gas amounts by a factor. +/datum/gas_mixture/proc/divide(factor) + for(var/g in gas) + gas[g] /= factor + + update_values() + return 1 + + +//Shares gas with another gas_mixture based on the amount of connecting tiles and a fixed lookup table. +/datum/gas_mixture/proc/share_ratio(datum/gas_mixture/other, connecting_tiles, share_size = null, one_way = 0) + var/static/list/sharing_lookup_table = list(0.30, 0.40, 0.48, 0.54, 0.60, 0.66) + //Shares a specific ratio of gas between mixtures using simple weighted averages. + var/ratio = sharing_lookup_table[6] + + var/size = max(1, group_multiplier) + if(isnull(share_size)) share_size = max(1, other.group_multiplier) + + var/full_heat_capacity = heat_capacity() + var/s_full_heat_capacity = other.heat_capacity() + + var/list/avg_gas = list() + + for(var/g in gas) + avg_gas[g] += gas[g] * size + + for(var/g in other.gas) + avg_gas[g] += other.gas[g] * share_size + + for(var/g in avg_gas) + avg_gas[g] /= (size + share_size) + + var/temp_avg = 0 + if(full_heat_capacity + s_full_heat_capacity) + temp_avg = (temperature * full_heat_capacity + other.temperature * s_full_heat_capacity) / (full_heat_capacity + s_full_heat_capacity) + + //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD. + if(sharing_lookup_table.len >= connecting_tiles) //6 or more interconnecting tiles will max at 42% of air moved per tick. + ratio = sharing_lookup_table[connecting_tiles] + //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD + + for(var/g in avg_gas) + gas[g] = max(0, (gas[g] - avg_gas[g]) * (1 - ratio) + avg_gas[g]) + if(!one_way) + other.gas[g] = max(0, (other.gas[g] - avg_gas[g]) * (1 - ratio) + avg_gas[g]) + + temperature = max(0, (temperature - temp_avg) * (1-ratio) + temp_avg) + if(!one_way) + other.temperature = max(0, (other.temperature - temp_avg) * (1-ratio) + temp_avg) + + update_values() + other.update_values() + + return compare(other) + + +//A wrapper around share_ratio for spacing gas at the same rate as if it were going into a large airless room. +/datum/gas_mixture/proc/share_space(datum/gas_mixture/unsim_air) + return share_ratio(unsim_air, unsim_air.group_multiplier, max(1, max(group_multiplier + 3, 1) + unsim_air.group_multiplier), one_way = 1) + +//Equalizes a list of gas mixtures. Used for pipe networks. +/proc/equalize_gases(datum/gas_mixture/list/gases) + //Calculate totals from individual components + var/total_volume = 0 + var/total_thermal_energy = 0 + var/total_heat_capacity = 0 + + var/list/total_gas = list() + for(var/datum/gas_mixture/gasmix in gases) + total_volume += gasmix.volume + var/temp_heatcap = gasmix.heat_capacity() + total_thermal_energy += gasmix.temperature * temp_heatcap + total_heat_capacity += temp_heatcap + for(var/g in gasmix.gas) + total_gas[g] += gasmix.gas[g] + + if(total_volume > 0) + var/datum/gas_mixture/combined = new(total_volume) + combined.gas = total_gas + + //Calculate temperature + if(total_heat_capacity > 0) + combined.temperature = total_thermal_energy / total_heat_capacity + combined.update_values() + + //Allow for reactions + combined.react() + + //Average out the gases + for(var/g in combined.gas) + combined.gas[g] /= total_volume + + //Update individual gas_mixtures + for(var/datum/gas_mixture/gasmix in gases) + gasmix.gas = combined.gas.Copy() + gasmix.temperature = combined.temperature + gasmix.multiply(gasmix.volume) + + return 1 + +/datum/gas_mixture/proc/get_mass() + for(var/g in gas) + . += gas[g] * gas_data.molar_mass[g] * group_multiplier + +/datum/gas_mixture/proc/specific_mass() + var/M = get_total_moles() + if(M) + return get_mass()/M diff --git a/code/procs/AStar.dm b/code/procs/AStar.dm new file mode 100644 index 00000000..db621d7f --- /dev/null +++ b/code/procs/AStar.dm @@ -0,0 +1,118 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/* +A Star pathfinding algorithm +Returns a list of tiles forming a path from A to B, taking dense objects as well as walls, and the orientation of +windows along the route into account. +Use: +your_list = AStar(start location, end location, adjacent turf proc, distance proc) +For the adjacent turf proc i wrote: +/turf/proc/AdjacentTurfs +And for the distance one i wrote: +/turf/proc/Distance +So an example use might be: + +src.path_list = AStar(src.loc, target.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance) + +Note: The path is returned starting at the END node, so i wrote reverselist to reverse it for ease of use. + +src.path_list = reverselist(src.pathlist) + +Then to start on the path, all you need to do it: +Step_to(src, src.path_list[1]) +src.path_list -= src.path_list[1] or equivilent to remove that node from the list. + +Optional extras to add on (in order): +MaxNodes: The maximum number of nodes the returned path can be (0 = infinite) +Maxnodedepth: The maximum number of nodes to search (default: 30, 0 = infinite) +Mintargetdist: Minimum distance to the target before path returns, could be used to get +near a target, but not right to it - for an AI mob with a gun, for example. +Minnodedist: Minimum number of nodes to return in the path, could be used to give a path a minimum +length to avoid portals or something i guess?? Not that they're counted right now but w/e. +*/ + +// Modified to provide ID argument - supplied to 'adjacent' proc, defaults to null +// Used for checking if route exists through a door which can be opened + +// Also added 'exclude' turf to avoid travelling over; defaults to null + +PathNode + var/datum/position + var/PathNode/previous_node + + var/best_estimated_cost + var/estimated_cost + var/known_cost + var/cost + var/nodes_traversed + + New(_position, _previous_node, _known_cost, _cost, _nodes_traversed) + position = _position + previous_node = _previous_node + + known_cost = _known_cost + cost = _cost + estimated_cost = cost + known_cost + + best_estimated_cost = estimated_cost + nodes_traversed = _nodes_traversed + +proc/PathWeightCompare(PathNode/a, PathNode/b) + return a.estimated_cost - b.estimated_cost + +proc/AStar(var/start, var/end, var/proc/adjacent, var/proc/dist, var/max_nodes, var/max_node_depth = 30, var/min_target_dist = 0, var/min_node_dist, var/id, var/datum/exclude) + var/PriorityQueue/open = new /PriorityQueue(/proc/PathWeightCompare) + var/list/closed = list() + var/list/path + var/list/path_node_by_position = list() + start = get_turf(start) + if(!start) + return 0 + + open.Enqueue(new /PathNode(start, null, 0, call(start, dist)(end), 0)) + + while(!open.IsEmpty() && !path) + var/PathNode/current = open.Dequeue() + closed.Add(current.position) + + if(current.position == end || call(current.position, dist)(end) <= min_target_dist) + path = new /list(current.nodes_traversed + 1) + path[path.len] = current.position + var/index = path.len - 1 + + while(current.previous_node) + current = current.previous_node + path[index--] = current.position + break + + if(min_node_dist && max_node_depth) + if(call(current.position, min_node_dist)(end) + current.nodes_traversed >= max_node_depth) + continue + + if(max_node_depth) + if(current.nodes_traversed >= max_node_depth) + continue + + for(var/datum/datum in call(current.position, adjacent)(id)) + if(datum == exclude) + continue + + var/best_estimated_cost = current.estimated_cost + call(current.position, dist)(datum) + + //handle removal of sub-par positions + if(datum in path_node_by_position) + var/PathNode/target = path_node_by_position[datum] + if(target.best_estimated_cost) + if(best_estimated_cost + call(datum, dist)(end) < target.best_estimated_cost) + open.Remove(target) + else + continue + + var/PathNode/next_node = new (datum, current, best_estimated_cost, call(datum, dist)(end), current.nodes_traversed + 1) + path_node_by_position[datum] = next_node + open.Enqueue(next_node) + + if(max_nodes && open.Length() > max_nodes) + open.Remove(open.Length()) + + return path diff --git a/code/procs/announce.dm b/code/procs/announce.dm new file mode 100644 index 00000000..5d9d1e8e --- /dev/null +++ b/code/procs/announce.dm @@ -0,0 +1,175 @@ +/var/datum/announcement/priority/priority_announcement = new(do_log = 0) +/var/datum/announcement/priority/command/command_announcement = new(do_log = 0, do_newscast = 1) +/var/datum/announcement/minor/minor_announcement = new(new_sound = 'sound/AI/commandreport.ogg',) +/var/datum/announcement/threat_announcement =new(new_sound = 'sound/AI/november/threat.ogg') + +/datum/announcement + var/title = "Attention" + var/announcer = "" + var/log = FALSE + var/sound + var/newscast = FALSE + var/channel_name = "Announcements" + var/announcement_type = "Announcement" + +/datum/announcement/threat_announcement + title = "Threat Alert" + announcement_type = "Threat" + +/datum/announcement/threat_announcement/FormMessage(message as text, message_title as text) + . = "

                Threat Alert!

                " + if (message_title) + . += "

                [message_title]

                " + . += "
                [message]
                " + . += "
                " + +/datum/announcement/priority + title = "Priority Announcement" + announcement_type = "Priority Announcement" + +/datum/announcement/priority/security + title = "Security Announcement" + announcement_type = "Security Announcement" + +/datum/announcement/decree/New(var/do_log = TRUE, var/new_sound = 'sound/misc/declaration.ogg', var/do_newscast = 0) + ..(do_log, new_sound, do_newscast) + title = "Commandant's New Decree!" + announcement_type = "Commandant Decree" + +/datum/announcement/decree/FormMessage(message as text, message_title as text) + . = "

                [message_title]

                " + . += "

                [message]

                " + if(announcer) + . += "
                -[html_encode(announcer)]" + . += "
                " + + +/datum/announcement/New(var/do_log = 0, var/new_sound = null, var/do_newscast = 0) + sound = new_sound + log = do_log + newscast = do_newscast + +/datum/announcement/priority/command/New(var/do_log = 1, var/new_sound = 'sound/misc/notice2.ogg', var/do_newscast = 0) + ..(do_log, new_sound, do_newscast) + title = "[command_name()] Update" + announcement_type = "[command_name()] Update" + +/datum/announcement/proc/Announce(var/message as text, var/new_title = "", var/new_sound = null, var/do_newscast = newscast, var/msg_sanitized = 0) + if(!message) + return + var/message_title = new_title ? new_title : title + var/message_sound = new_sound ? new_sound : sound + + if(!msg_sanitized) + message = sanitize(message, extra = 0) + message_title = sanitizeSafe(message_title) + + var/msg = FormMessage(message, message_title) + for(var/mob/M in GLOB.player_list) + if((M.z in (GLOB.using_map.contact_levels | GLOB.using_map.admin_levels)) && !istype(M,/mob/new_player) && !isdeaf(M)) + to_chat(M, msg) + if(message_sound) + sound_to(M, message_sound) + + if(do_newscast) + NewsCast(message, message_title) + + if(log) + log_say("[key_name(usr)] has made \a [announcement_type]: [message_title] - [message] - [announcer]") + message_admins("[key_name_admin(usr)] has made \a [announcement_type].", 1) + +/datum/announcement/proc/FormMessage(message as text, message_title as text) + . = "

                [message_title]

                " + . += "
                [message]" + if (announcer) + . += "
                -[html_encode(announcer)]" + +/datum/announcement/minor/FormMessage(message as text, message_title as text) + . = "[message]" + +/datum/announcement/priority/FormMessage(message as text, message_title as text) + . = "

                [message_title]

                " + . += "
                [message]" + if(announcer) + . += "
                -[html_encode(announcer)]" + . += "
                " + +/datum/announcement/priority/command/FormMessage(message as text, message_title as text) + . = "

                [command_name()] Update

                " + if (message_title) + . += "

                [message_title]

                " + + . += "
                [message]
                " + . += "
                " + +/datum/announcement/priority/security/FormMessage(message as text, message_title as text) + . = "[message_title]" + . += "
                [message]" + +/datum/announcement/proc/NewsCast(message as text, message_title as text) + if(!newscast) + return + + var/datum/news_announcement/news = new + news.channel_name = channel_name + news.author = announcer + news.message = message + news.message_type = announcement_type + news.can_be_redacted = 0 + announce_newscaster_news(news) + +/proc/GetNameAndAssignmentFromId(var/obj/item/weapon/card/id/I) + // Format currently matches that of newscaster feeds: Registered Name (Assigned Rank) + return I.assignment ? "[I.registered_name] ([I.assignment])" : I.registered_name + +/proc/level_seven_announcement() + GLOB.using_map.level_x_biohazard_announcement(7) + +/proc/ion_storm_announcement() + command_announcement.Announce("It has come to our attention that the [station_name()] passed through an ion storm. Please monitor all electronic equipment for malfunctions.", "Anomaly Alert") + +/proc/AnnounceArrival(var/mob/living/carbon/human/character, var/datum/job/job, var/join_message) + if(!istype(job) || !job.announced) + return + if (ticker.current_state != GAME_STATE_PLAYING) + return + var/rank = job.title + if(character.mind.role_alt_title) + rank = character.mind.role_alt_title + + AnnounceArrivalSimple(character.real_name, rank, join_message, get_announcement_frequency(job)) + +/proc/AnnounceArrivalSimple(var/name, var/rank = "visitor", var/join_message = "has arrived on the [station_name()]", var/frequency) + GLOB.global_announcer.autosay("[name], [rank], [join_message].", "Arrivals Announcement Computer", frequency) + +/proc/get_announcement_frequency(var/datum/job/job) + + if(job.is_red_team) + return "Red" + if(job.is_blue_team) + return "Blue" + + // During red alert all jobs are announced on main frequency. + var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + if (security_state.current_security_level_is_same_or_higher_than(security_state.high_security_level)) + return "Common" + + if(job.department_flag & (COM | CIV | MSC)) + return "Common" + if(job.department_flag & SUP) + return "Supply" + if(job.department_flag & SPT) + return "Command" + if(job.department_flag & SEC) + return "Security" + if(job.department_flag & ENG) + return "Engineering" + if(job.department_flag & MED) + return "Medical" + if(job.department_flag & SCI) + return "Science" + if(job.department_flag & SRV) + return "Service" + if(job.department_flag & EXP) + return "Exploration" + return "Common" \ No newline at end of file diff --git a/code/procs/dbcore.dm b/code/procs/dbcore.dm new file mode 100644 index 00000000..21afe2ae --- /dev/null +++ b/code/procs/dbcore.dm @@ -0,0 +1,207 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +//cursors +#define Default_Cursor 0 +#define Client_Cursor 1 +#define Server_Cursor 2 +//conversions +#define TEXT_CONV 1 +#define RSC_FILE_CONV 2 +#define NUMBER_CONV 3 +//column flag values: +#define IS_NUMERIC 1 +#define IS_BINARY 2 +#define IS_NOT_NULL 4 +#define IS_PRIMARY_KEY 8 +#define IS_UNSIGNED 16 +//types +#define TINYINT 1 +#define SMALLINT 2 +#define MEDIUMINT 3 +#define INTEGER 4 +#define BIGINT 5 +#define DECIMAL 6 +#define FLOAT 7 +#define DOUBLE 8 +#define DATE 9 +#define DATETIME 10 +#define TIMESTAMP 11 +#define TIME 12 +#define STRING 13 +#define BLOB 14 +// TODO: Investigate more recent type additions and see if I can handle them. - Nadrew + + +// Deprecated! See global.dm for new configuration vars +/* +var/DB_SERVER = "" // This is the location of your MySQL server (localhost is USUALLY fine) +var/DB_PORT = 3306 // This is the port your MySQL server is running on (3306 is the default) +*/ + +DBConnection + var/_db_con // This variable contains a reference to the actual database connection. + var/dbi // This variable is a string containing the DBI MySQL requires. + var/user // This variable contains the username data. + var/password // This variable contains the password data. + var/default_cursor // This contains the default database cursor data. + // + var/server = "" + var/port = 3306 + +DBConnection/New(dbi_handler,username,password_handler,cursor_handler) + src.dbi = dbi_handler + src.user = username + src.password = password_handler + src.default_cursor = cursor_handler + _db_con = _dm_db_new_con() + +DBConnection/proc/Connect(dbi_handler=src.dbi,user_handler=src.user,password_handler=src.password,cursor_handler) + if(!sqllogging) + return 0 + if(!src) return 0 + cursor_handler = src.default_cursor + if(!cursor_handler) cursor_handler = Default_Cursor + return _dm_db_connect(_db_con,dbi_handler,user_handler,password_handler,cursor_handler,null) + +DBConnection/proc/Disconnect() return _dm_db_close(_db_con) + +DBConnection/proc/IsConnected() + if(!sqllogging) return 0 + var/success = _dm_db_is_connected(_db_con) + return success + +DBConnection/proc/Quote(str) return _dm_db_quote(_db_con,str) + +DBConnection/proc/ErrorMsg() return _dm_db_error_msg(_db_con) +DBConnection/proc/SelectDB(database_name,dbi) + if(IsConnected()) Disconnect() + //return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[DB_SERVER]:[DB_PORT]"]",user,password) + return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[sqladdress]:[sqlport]"]",user,password) +DBConnection/proc/NewQuery(sql_query,cursor_handler=src.default_cursor) return new/DBQuery(sql_query,src,cursor_handler) + + +DBQuery/New(sql_query,DBConnection/connection_handler,cursor_handler) + if(sql_query) src.sql = sql_query + if(connection_handler) src.db_connection = connection_handler + if(cursor_handler) src.default_cursor = cursor_handler + _db_query = _dm_db_new_query() + return ..() + + +DBQuery + var/sql // The sql query being executed. + var/default_cursor + var/list/columns //list of DB Columns populated by Columns() + var/list/conversions + var/list/item[0] //list of data values populated by NextRow() + + var/DBConnection/db_connection + var/_db_query + +DBQuery/proc/Connect(DBConnection/connection_handler) src.db_connection = connection_handler + +DBQuery/proc/Execute(sql_query=src.sql,cursor_handler=default_cursor) + Close() + return _dm_db_execute(_db_query,sql_query,db_connection._db_con,cursor_handler,null) + +DBQuery/proc/NextRow() return _dm_db_next_row(_db_query,item,conversions) + +DBQuery/proc/RowsAffected() return _dm_db_rows_affected(_db_query) + +DBQuery/proc/RowCount() return _dm_db_row_count(_db_query) + +DBQuery/proc/ErrorMsg() return _dm_db_error_msg(_db_query) + +DBQuery/proc/Columns() + if(!columns) + columns = _dm_db_columns(_db_query,/DBColumn) + return columns + +DBQuery/proc/GetRowData() + var/list/columns = Columns() + var/list/results + if(columns.len) + results = list() + for(var/C in columns) + results+=C + var/DBColumn/cur_col = columns[C] + results[C] = src.item[(cur_col.position+1)] + return results + +DBQuery/proc/Close() + item.len = 0 + columns = null + conversions = null + return _dm_db_close(_db_query) + +DBQuery/proc/Quote(str) + return db_connection.Quote(str) + +DBQuery/proc/SetConversion(column,conversion) + if(istext(column)) column = columns.Find(column) + if(!conversions) conversions = new/list(column) + else if(conversions.len < column) conversions.len = column + conversions[column] = conversion + + +DBColumn + var/name + var/table + var/position //1-based index into item data + var/sql_type + var/flags + var/length + var/max_length + +DBColumn/New(name_handler,table_handler,position_handler,type_handler,flag_handler,length_handler,max_length_handler) + src.name = name_handler + src.table = table_handler + src.position = position_handler + src.sql_type = type_handler + src.flags = flag_handler + src.length = length_handler + src.max_length = max_length_handler + return ..() + + +DBColumn/proc/SqlTypeName(type_handler=src.sql_type) + switch(type_handler) + if(TINYINT) return "TINYINT" + if(SMALLINT) return "SMALLINT" + if(MEDIUMINT) return "MEDIUMINT" + if(INTEGER) return "INTEGER" + if(BIGINT) return "BIGINT" + if(FLOAT) return "FLOAT" + if(DOUBLE) return "DOUBLE" + if(DATE) return "DATE" + if(DATETIME) return "DATETIME" + if(TIMESTAMP) return "TIMESTAMP" + if(TIME) return "TIME" + if(STRING) return "STRING" + if(BLOB) return "BLOB" + +#undef Default_Cursor +#undef Client_Cursor +#undef Server_Cursor +#undef TEXT_CONV +#undef RSC_FILE_CONV +#undef NUMBER_CONV +#undef IS_NUMERIC +#undef IS_BINARY +#undef IS_NOT_NULL +#undef IS_PRIMARY_KEY +#undef IS_UNSIGNED +#undef TINYINT +#undef SMALLINT +#undef MEDIUMINT +#undef INTEGER +#undef BIGINT +#undef DECIMAL +#undef FLOAT +#undef DOUBLE +#undef DATE +#undef DATETIME +#undef TIMESTAMP +#undef TIME +#undef STRING +#undef BLOB diff --git a/code/procs/hud.dm b/code/procs/hud.dm new file mode 100644 index 00000000..86b70778 --- /dev/null +++ b/code/procs/hud.dm @@ -0,0 +1,85 @@ +/* Using the HUD procs is simple. Call these procs in the life.dm of the intended mob. +Use the regular_hud_updates() proc before process_med_hud(mob) or process_sec_hud(mob) so +the HUD updates properly! */ + +// hud overlay image type, used for clearing client.images precisely +/image/hud_overlay + appearance_flags = RESET_COLOR|RESET_TRANSFORM|KEEP_APART + +//Medical HUD outputs. Called by the Life() proc of the mob using it, usually. +proc/process_med_hud(var/mob/M, var/local_scanner, var/mob/Alt) + if(!can_process_hud(M)) + return + + var/datum/arranged_hud_process/P = arrange_hud_process(M, Alt, GLOB.med_hud_users) + for(var/mob/living/carbon/human/patient in P.Mob.in_view(P.Turf)) + + if(patient.is_invisible_to(P.Mob)) + continue + + if(local_scanner) + P.Client.images += patient.hud_list[HEALTH_HUD] + P.Client.images += patient.hud_list[STATUS_HUD] + else + var/sensor_level = getsensorlevel(patient) + if(sensor_level >= SUIT_SENSOR_VITAL) + P.Client.images += patient.hud_list[HEALTH_HUD] + if(sensor_level >= SUIT_SENSOR_BINARY) + P.Client.images += patient.hud_list[LIFE_HUD] + +//Security HUDs. Pass a value for the second argument to enable implant viewing or other special features. +proc/process_sec_hud(var/mob/M, var/advanced_mode, var/mob/Alt) + if(!can_process_hud(M)) + return + var/datum/arranged_hud_process/P = arrange_hud_process(M, Alt, GLOB.sec_hud_users) + for(var/mob/living/carbon/human/perp in P.Mob.in_view(P.Turf)) + + if(perp.is_invisible_to(P.Mob)) + continue + + P.Client.images += perp.hud_list[ID_HUD] + if(advanced_mode) + P.Client.images += perp.hud_list[WANTED_HUD] + P.Client.images += perp.hud_list[IMPTRACK_HUD] + P.Client.images += perp.hud_list[IMPLOYAL_HUD] + P.Client.images += perp.hud_list[IMPCHEM_HUD] + +datum/arranged_hud_process + var/client/Client + var/mob/Mob + var/turf/Turf + +proc/arrange_hud_process(var/mob/M, var/mob/Alt, var/list/hud_list) + hud_list |= M + var/datum/arranged_hud_process/P = new + P.Client = M.client + P.Mob = Alt ? Alt : M + P.Turf = get_turf(P.Mob) + return P + +proc/can_process_hud(var/mob/M) + if(!M) + return 0 + if(!M.client) + return 0 + if(M.stat != CONSCIOUS) + return 0 + 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. + if(client) + for(var/image/hud_overlay/hud in client.images) + client.images -= hud + GLOB.med_hud_users -= src + GLOB.sec_hud_users -= src + +mob/proc/in_view(var/turf/T) + return view(T) + +/mob/observer/eye/in_view(var/turf/T) + var/list/viewed = new + for(var/mob/living/carbon/human/H in SSmobs.mob_list) + if(get_dist(H, T) <= 7) + viewed += H + return viewed diff --git a/code/procs/radio.dm b/code/procs/radio.dm new file mode 100644 index 00000000..0edfe46a --- /dev/null +++ b/code/procs/radio.dm @@ -0,0 +1,89 @@ +/proc/register_radio(source, old_frequency, new_frequency, radio_filter) + if(old_frequency) + radio_controller.remove_object(source, old_frequency) + if(new_frequency) + return radio_controller.add_object(source, new_frequency, radio_filter) + +/proc/unregister_radio(source, frequency) + if(radio_controller) + radio_controller.remove_object(source, frequency) + +/proc/get_frequency_name(var/display_freq) + var/freq_text + + // the name of the channel + if(display_freq in ANTAG_FREQS) + freq_text = "#unkn" + else + for(var/channel in radiochannels) + if(radiochannels[channel] == display_freq) + freq_text = channel + break + + // --- If the frequency has not been assigned a name, just use the frequency as the name --- + if(!freq_text) + freq_text = format_frequency(display_freq) + + return freq_text + +/datum/reception + var/obj/machinery/message_server/message_server = null + var/telecomms_reception = TELECOMMS_RECEPTION_NONE + var/message = "" + +/datum/receptions + var/obj/machinery/message_server/message_server = null + var/sender_reception = TELECOMMS_RECEPTION_NONE + var/list/receiver_reception = new + +/proc/get_message_server(z) + if(message_servers) + var/list/zlevels = GLOB.using_map.contact_levels + if(z) + zlevels = GetConnectedZlevels(z) + for (var/obj/machinery/message_server/MS in message_servers) + if(MS.active && (MS.z in zlevels)) + return MS + return null + +/proc/check_signal(var/datum/signal/signal) + return signal && signal.data["done"] + +/proc/get_sender_reception(var/atom/sender, var/datum/signal/signal) + return check_signal(signal) ? TELECOMMS_RECEPTION_SENDER : TELECOMMS_RECEPTION_NONE + +/proc/get_receiver_reception(var/receiver, var/datum/signal/signal) + if(receiver && check_signal(signal)) + var/turf/pos = get_turf(receiver) + if(pos && (pos.z in signal.data["level"])) + return TELECOMMS_RECEPTION_RECEIVER + return TELECOMMS_RECEPTION_NONE + +/proc/get_reception(var/atom/sender, var/receiver, var/message = "", var/do_sleep = 1) + var/datum/reception/reception = new + + // check if telecomms I/O route 1459 is stable + reception.message_server = get_message_server() + + var/datum/signal/signal = sender.telecomms_process(do_sleep) // Be aware that this proc calls sleep, to simulate transmition delays + reception.telecomms_reception |= get_sender_reception(sender, signal) + reception.telecomms_reception |= get_receiver_reception(receiver, signal) + reception.message = signal && signal.data["compression"] > 0 ? Gibberish(message, signal.data["compression"] + 50) : message + + return reception + +/proc/get_receptions(var/atom/sender, var/list/atom/receivers, var/do_sleep = 1) + var/datum/receptions/receptions = new + receptions.message_server = get_message_server() + + var/datum/signal/signal + if(sender) + signal = sender.telecomms_process(do_sleep) + receptions.sender_reception = get_sender_reception(sender, signal) + + for(var/atom/receiver in receivers) + if(!signal) + signal = receiver.telecomms_process() + receptions.receiver_reception[receiver] = get_receiver_reception(receiver, signal) + + return receptions diff --git a/code/procs/statistics.dm b/code/procs/statistics.dm new file mode 100644 index 00000000..12b785bb --- /dev/null +++ b/code/procs/statistics.dm @@ -0,0 +1,146 @@ +proc/sql_poll_population() + if(!sqllogging) + return + var/admincount = GLOB.admins.len + var/playercount = 0 + for(var/mob/M in GLOB.player_list) + if(M.client) + playercount += 1 + establish_db_connection() + if(!dbcon.IsConnected()) + log_game("SQL ERROR during population polling. Failed to connect.") + else + var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") + var/DBQuery/query = dbcon_old.NewQuery("INSERT INTO `tgstation`.`population` (`playercount`, `admincount`, `time`) VALUES ([playercount], [admincount], '[sqltime]')") + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL ERROR during population polling. Error : \[[err]\]\n") + +proc/sql_report_round_start() + // TODO + if(!sqllogging) + return +proc/sql_report_round_end() + // TODO + if(!sqllogging) + return + +proc/sql_report_death(var/mob/living/carbon/human/H) + if(!sqllogging) + return + if(!H) + return + if(!H.key || !H.mind) + return + + var/area/placeofdeath = get_area(H) + var/podname = placeofdeath ? placeofdeath.name : "Unknown area" + + var/sqlname = sanitizeSQL(H.real_name) + var/sqlkey = sanitizeSQL(H.key) + var/sqlpod = sanitizeSQL(podname) + var/sqlspecial = sanitizeSQL(H.mind.special_role) + var/sqljob = sanitizeSQL(H.mind.assigned_role) + var/laname + var/lakey + if(H.last_attacker_) + laname = sanitizeSQL(H.last_attacker_.name) + lakey = sanitizeSQL(H.last_attacker_.client.key) + var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") + var/coord = "[H.x], [H.y], [H.z]" +// log_debug("INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.bruteloss], [H.getFireLoss()], [H.getBrainLoss()], [H.getOxyLoss()])") + + establish_db_connection() + if(!dbcon.IsConnected()) + log_game("SQL ERROR during death reporting. Failed to connect.") + else + var/DBQuery/query = dbcon.NewQuery("INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.getBruteLoss()], [H.getFireLoss()], [H.getBrainLoss()], [H.getOxyLoss()], '[coord]')") + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL ERROR during death reporting. Error : \[[err]\]\n") + + +proc/sql_report_cyborg_death(var/mob/living/silicon/robot/H) + if(!sqllogging) + return + if(!H) + return + if(!H.key || !H.mind) + return + + var/area/placeofdeath = get_area(H) + var/podname = placeofdeath ? placeofdeath.name : "Unknown area" + + var/sqlname = sanitizeSQL(H.real_name) + var/sqlkey = sanitizeSQL(H.key) + var/sqlpod = sanitizeSQL(podname) + var/sqlspecial = sanitizeSQL(H.mind.special_role) + var/sqljob = sanitizeSQL(H.mind.assigned_role) + var/laname + var/lakey + if(H.last_attacker_) + laname = sanitizeSQL(H.last_attacker_.name) + lakey = sanitizeSQL(H.last_attacker_.client.key) + var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") + var/coord = "[H.x], [H.y], [H.z]" +// log_debug("INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.bruteloss], [H.getFireLoss()], [H.getBrainLoss()], [H.getOxyLoss()])") + + establish_db_connection() + if(!dbcon.IsConnected()) + log_game("SQL ERROR during death reporting. Failed to connect.") + else + var/DBQuery/query = dbcon.NewQuery("INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.getBruteLoss()], [H.getFireLoss()], [H.getBrainLoss()], [H.getOxyLoss()], '[coord]')") + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL ERROR during death reporting. Error : \[[err]\]\n") + + +proc/statistic_cycle() + if(!sqllogging) + return + while(1) + sql_poll_population() + sleep(6000) + +//This proc is used for feedback. It is executed at round end. +proc/sql_commit_feedback() + if(!blackbox) + log_game("Round ended without a blackbox recorder. No feedback was sent to the database.") + return + + //content is a list of lists. Each item in the list is a list with two fields, a variable name and a value. Items MUST only have these two values. + var/list/datum/feedback_variable/content = blackbox.get_round_feedback() + + if(!content) + log_game("Round ended without any feedback being generated. No feedback was sent to the database.") + return + + establish_db_connection() + if(!dbcon.IsConnected()) + log_game("SQL ERROR during feedback reporting. Failed to connect.") + else + + var/DBQuery/max_query = dbcon.NewQuery("SELECT MAX(roundid) AS max_round_id FROM erro_feedback") + max_query.Execute() + + var/newroundid + + while(max_query.NextRow()) + newroundid = max_query.item[1] + + if(!(isnum(newroundid))) + newroundid = text2num(newroundid) + + if(isnum(newroundid)) + newroundid++ + else + newroundid = 1 + + for(var/datum/feedback_variable/item in content) + var/variable = item.get_variable() + var/value = item.get_value() + + var/DBQuery/query = dbcon.NewQuery("INSERT INTO erro_feedback (id, roundid, time, variable, value) VALUES (null, [newroundid], Now(), '[variable]', '[value]')") + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL ERROR during death reporting. Error : \[[err]\]\n") diff --git a/code/stylesheet.dm b/code/stylesheet.dm new file mode 100644 index 00000000..ffef7d02 --- /dev/null +++ b/code/stylesheet.dm @@ -0,0 +1,117 @@ +client/script = {""} diff --git a/code/unit_tests/_includes.dm b/code/unit_tests/_includes.dm new file mode 100644 index 00000000..ad7ecc2d --- /dev/null +++ b/code/unit_tests/_includes.dm @@ -0,0 +1,4 @@ +#ifdef UNIT_TEST + #include "override_tests.dm" + #include "~unit_test_overrides.dm" +#endif diff --git a/code/unit_tests/_template.dm b/code/unit_tests/_template.dm new file mode 100644 index 00000000..6c7b246a --- /dev/null +++ b/code/unit_tests/_template.dm @@ -0,0 +1,38 @@ +/* + * + * Unit Test Template + * This file is not used. + * + */ + +/datum/unit_test/template + name = "Test Template - Change My name" // If it's a template leave the word "template" in it's name so it's not ran. + + async = 1 // Set if we should continue testing elsewhere and come back and check on the results. + + +/datum/unit_test/template/start_test() + // This must return something, if it's null the unit_test runner will think we runtimed. + // If your test requires any kind of delay use async so we can finish tests faster. + // Be sure and have a pass/fail procs in here if it's not using async. + + if(0) + fail("Zero is somehow True, that sucks") + else + pass("Zero is false, yay") + + + return 1 + +/datum/unit_test/template/check_result() + // Only Ran if async is set. Use this proc for checking back if the test passed or not. + // Return 0 if we need to come back again and check this. + // Return 1 if the test is complete. + + // + + pass("Winner is you") + + return 1 + +// ============================================================================ diff --git a/code/unit_tests/alt_appearances_test.dm b/code/unit_tests/alt_appearances_test.dm new file mode 100644 index 00000000..56e7f6b7 --- /dev/null +++ b/code/unit_tests/alt_appearances_test.dm @@ -0,0 +1,49 @@ +/datum/unit_test/alt_appearance_cardborg_shall_have_base_backpack_variant + name = "ALT APPEARANCE: Cardborg shall have base backpack variant" + +/datum/unit_test/alt_appearance_cardborg_shall_have_base_backpack_variant/start_test() + for(var/ca_type in subtypesof(/decl/cardborg_appearance)) + var/decl/cardborg_appearance/ca = ca_type + var/obj/item/weapon/storage/backpack/backpack_type = initial(ca.backpack_type) + if(backpack_type == /obj/item/weapon/storage/backpack) + pass("Found a cardborg appearance using the base /obj/item/weapon/storage/backpack backpack.") + return 1 + + fail("Did not find a cardborg appearance using the base /obj/item/weapon/storage/backpack backpack.") + return 1 + +/datum/unit_test/alt_appearance_cardborg_all_icon_states_shall_exist + name = "ALT APPEARANCE: Cardborg shall have base backpack variant" + +/datum/unit_test/alt_appearance_cardborg_all_icon_states_shall_exist/start_test() + var/list/existing_icon_states = icon_states('icons/mob/robots.dmi') + var/failed = FALSE + + for(var/ca_type in subtypesof(/decl/cardborg_appearance)) + var/decl/cardborg_appearance/ca = ca_type + var/icon_state = initial(ca.icon_state) + if(!(icon_state in existing_icon_states)) + log_unit_test("Icon state [icon_state] is missing.") + failed = TRUE + + if(failed) + fail("One or more icon states are missing.") + else + pass("All references to icon states exists.") + return 1 + +/datum/unit_test/alt_appearance_cardborg_shall_have_unique_backpack_types + name = "ALT APPEARANCE: Cardborg shall have unique backpack types" + +/datum/unit_test/alt_appearance_cardborg_shall_have_unique_backpack_types/start_test() + var/list/backpack_types = list() + for(var/ca_type in subtypesof(/decl/cardborg_appearance)) + var/decl/cardborg_appearance/ca = ca_type + group_by(backpack_types, initial(ca.backpack_type), ca) + + var/number_of_issues = number_of_issues(backpack_types, "Backpack Types") + if(number_of_issues) + fail("[number_of_issues] duplicate backpack type\s exist.") + else + pass("All backpack types are unique.") + return 1 diff --git a/code/unit_tests/area_tests.dm b/code/unit_tests/area_tests.dm new file mode 100644 index 00000000..700debdd --- /dev/null +++ b/code/unit_tests/area_tests.dm @@ -0,0 +1,94 @@ +/datum/unit_test/areas_shall_be_coherent + name = "AREA: Areas shall be coherent" + +/datum/unit_test/areas_shall_be_coherent/start_test() + var/incoherent_areas = 0 + for(var/area/A) + if(!A.contents.len) + continue + if(A.type in GLOB.using_map.area_coherency_test_exempt_areas) + continue + var/list/area_turfs = list() + for(var/turf/T in A) + area_turfs += T + + var/actual_number_of_sub_areas = 0 + var/expected_number_of_sub_areas = (A.type in GLOB.using_map.area_coherency_test_subarea_count) ? GLOB.using_map.area_coherency_test_subarea_count[A.type] : 1 + do + actual_number_of_sub_areas++ + area_turfs -= get_turfs_fill(area_turfs[1]) + while(area_turfs.len) + + if(actual_number_of_sub_areas != expected_number_of_sub_areas) + incoherent_areas++ + log_bad("[log_info_line(A)] is incoherent. Expected [expected_number_of_sub_areas] subarea\s, fill gave [actual_number_of_sub_areas].") + + if(incoherent_areas) + fail("Found [incoherent_areas] incoherent area\s.") + else + pass("All areas are coherent.") + + return 1 + +#define SHOULD_CHECK_TURF(turf_to_check) if(turf_to_check && turf_to_check.loc == T.loc && !(turf_to_check in .)) { turfs_to_check.Push(turf_to_check) } +/datum/unit_test/areas_shall_be_coherent/proc/get_turfs_fill(var/turf/origin) + . = list() + var/datum/stack/turfs_to_check = new() + turfs_to_check.Push(origin) + while(!turfs_to_check.is_empty()) + var/turf/T = turfs_to_check.Pop() + . |= T + var/turf/neighbour + for(var/direction in GLOB.cardinal) + neighbour = get_step(T, direction) + SHOULD_CHECK_TURF(neighbour) +#ifdef MULTIZAS + neighbour = GetAbove(T) + SHOULD_CHECK_TURF(neighbour) + neighbour = GetBelow(T) + SHOULD_CHECK_TURF(neighbour) +#endif + +#undef SHOULD_CHECK_TURF + +/datum/unit_test/areas_shall_be_pure + name = "AREA: Areas shall be pure" + +/datum/unit_test/areas_shall_be_pure/start_test() + var/impure_areas = 0 + for(var/area/A) + if(!A.contents.len) + continue + if(A.type in GLOB.using_map.area_purity_test_exempt_areas) + continue + if(A.name != initial(A.name)) + log_bad("[log_info_line(A)] has an edited name.") + impure_areas++ + + if(impure_areas) + fail("Found [impure_areas] impure area\s.") + else + pass("All areas are pure.") + + return 1 + +/datum/unit_test/areas_shall_be_used + name = "AREA: Areas shall be used" + +/datum/unit_test/areas_shall_be_used/start_test() + var/unused_areas = 0 + for(var/area_type in subtypesof(/area)) + if(area_type in GLOB.using_map.area_usage_test_exempted_areas) + continue + if(is_path_in_list(area_type, GLOB.using_map.area_usage_test_exempted_root_areas)) + continue + var/area/located_area = locate(area_type) + if(located_area && !located_area.z) + log_bad("[log_info_line(located_area)] is unused.") + unused_areas++ + + if(unused_areas) + fail("Found [unused_areas] unused area\s.") + else + pass("All areas are used.") + return 1 \ No newline at end of file diff --git a/code/unit_tests/atmospherics_tests.dm b/code/unit_tests/atmospherics_tests.dm new file mode 100644 index 00000000..db782ab2 --- /dev/null +++ b/code/unit_tests/atmospherics_tests.dm @@ -0,0 +1,269 @@ +/* + Unit tests for ATMOSPHERICS primitives +*/ +#define ALL_GASIDS gas_data.gases + +/datum/unit_test/atmos_machinery + var/list/test_cases = list() + +/datum/unit_test/atmos_machinery/proc/create_gas_mixes(gas_mix_data) + var/list/gas_mixes = list() + for(var/mix_name in gas_mix_data) + var/list/mix_data = gas_mix_data[mix_name] + + var/datum/gas_mixture/gas_mix = new (CELL_VOLUME, mix_data["temperature"]) + + var/list/initial_gas = mix_data["initial_gas"] + if(initial_gas.len) + var/list/gas_args = list() + for(var/gasid in initial_gas) + gas_args += gasid + gas_args += initial_gas[gasid] + gas_mix.adjust_multi(arglist(gas_args)) + + gas_mixes[mix_name] = gas_mix + return gas_mixes + +/datum/unit_test/atmos_machinery/proc/gas_amount_changes(var/list/before_gas_mixes, var/list/after_gas_mixes) + var/list/result = list() + for(var/mix_name in before_gas_mixes & after_gas_mixes) + var/change = list() + + var/datum/gas_mixture/before = before_gas_mixes[mix_name] + var/datum/gas_mixture/after = after_gas_mixes[mix_name] + + var/list/all_gases = before.gas | after.gas + for(var/gasid in all_gases) + change[gasid] = after.get_gas(gasid) - before.get_gas(gasid) + + result[mix_name] = change + + return result + +/datum/unit_test/atmos_machinery/proc/check_moles_conserved(var/case_name, var/list/before_gas_mixes, var/list/after_gas_mixes) + var/failed = FALSE + for(var/gasid in gas_data.gases) + var/before = 0 + for(var/gasmix in before_gas_mixes) + var/datum/gas_mixture/G = before_gas_mixes[gasmix] + before += G.get_gas(gasid) + + var/after = 0 + for(var/gasmix in after_gas_mixes) + var/datum/gas_mixture/G = after_gas_mixes[gasmix] + after += G.get_gas(gasid) + + if(abs(before - after) > ATMOS_PRECISION) + fail("[case_name]: expected [before] moles of [gasid], found [after] moles.") + failed |= TRUE + + if(!failed) + pass("[case_name]: conserved moles of each gas ID.") + +/datum/unit_test/atmos_machinery/conserve_moles + test_cases = list( + uphill = list( + source = list( + initial_gas = list( + "oxygen" = 5, + "nitrogen" = 10, + "carbon_dioxide" = 5, + "phoron" = 10, + "sleeping_agent" = 5, + ), + temperature = T20C - 5, + ), + sink = list( + initial_gas = list( + "oxygen" = 10, + "nitrogen" = 20, + "carbon_dioxide" = 10, + "phoron" = 20, + "sleeping_agent" = 10, + ), + temperature = T20C + 5, + ) + ), + downhill = list( + source = list( + initial_gas = list( + "oxygen" = 10, + "nitrogen" = 20, + "carbon_dioxide" = 10, + "phoron" = 20, + "sleeping_agent" = 10, + ), + temperature = T20C + 5, + ), + sink = list( + initial_gas = list( + "oxygen" = 5, + "nitrogen" = 10, + "carbon_dioxide" = 5, + "phoron" = 10, + "sleeping_agent" = 5, + ), + temperature = T20C - 5, + ), + ), + flat = list( + source = list( + initial_gas = list( + "oxygen" = 10, + "nitrogen" = 20, + "carbon_dioxide" = 10, + "phoron" = 20, + "sleeping_agent" = 10, + ), + temperature = T20C, + ), + sink = list( + initial_gas = list( + "oxygen" = 10, + "nitrogen" = 20, + "carbon_dioxide" = 10, + "phoron" = 20, + "sleeping_agent" = 10, + ), + temperature = T20C, + ), + ), + vacuum_sink = list( + source = list( + initial_gas = list( + "oxygen" = 10, + "nitrogen" = 20, + "carbon_dioxide" = 10, + "phoron" = 20, + "sleeping_agent" = 10, + ), + temperature = T20C, + ), + sink = list( + initial_gas = list(), + temperature = 0, + ), + ), + vacuum_source = list( + source = list( + initial_gas = list(), + temperature = 0, + ), + sink = list( + initial_gas = list( + "oxygen" = 10, + "nitrogen" = 20, + "carbon_dioxide" = 10, + "phoron" = 20, + "sleeping_agent" = 10, + ), + temperature = T20C, + ), + ), + ) + + +/datum/unit_test/atmos_machinery/conserve_moles/pump_gas + name = "ATMOS MACHINERY: pump_gas() Conserves Moles" + +/datum/unit_test/atmos_machinery/conserve_moles/pump_gas/start_test() + for(var/case_name in test_cases) + var/gas_mix_data = test_cases[case_name] + var/list/before_gas_mixes = create_gas_mixes(gas_mix_data) + var/list/after_gas_mixes = create_gas_mixes(gas_mix_data) + + pump_gas(null, after_gas_mixes["source"], after_gas_mixes["sink"], null, INFINITY) + + check_moles_conserved(case_name, before_gas_mixes, after_gas_mixes) + + return 1 + +/datum/unit_test/atmos_machinery/conserve_moles/pump_gas_passive + name = "ATMOS MACHINERY: pump_gas_passive() Conserves Moles" + +/datum/unit_test/atmos_machinery/conserve_moles/pump_gas_passive/start_test() + for(var/case_name in test_cases) + var/gas_mix_data = test_cases[case_name] + var/list/before_gas_mixes = create_gas_mixes(gas_mix_data) + var/list/after_gas_mixes = create_gas_mixes(gas_mix_data) + + pump_gas_passive(null, after_gas_mixes["source"], after_gas_mixes["sink"], null) + + check_moles_conserved(case_name, before_gas_mixes, after_gas_mixes) + + return 1 + +/datum/unit_test/atmos_machinery/conserve_moles/scrub_gas + name = "ATMOS MACHINERY: scrub_gas() Conserves Moles" + +/datum/unit_test/atmos_machinery/conserve_moles/scrub_gas/start_test() + var/list/filtering = gas_data.gases + + for(var/case_name in test_cases) + var/gas_mix_data = test_cases[case_name] + var/list/before_gas_mixes = create_gas_mixes(gas_mix_data) + var/list/after_gas_mixes = create_gas_mixes(gas_mix_data) + + scrub_gas(null, filtering, after_gas_mixes["source"], after_gas_mixes["sink"], null, INFINITY) + + check_moles_conserved(case_name, before_gas_mixes, after_gas_mixes) + + return 1 + +/datum/unit_test/atmos_machinery/conserve_moles/filter_gas + name = "ATMOS MACHINERY: filter_gas() Conserves Moles" + +/datum/unit_test/atmos_machinery/conserve_moles/filter_gas/start_test() + var/list/filtering = gas_data.gases + + for(var/case_name in test_cases) + var/gas_mix_data = test_cases[case_name] + var/list/before_gas_mixes = create_gas_mixes(gas_mix_data) + var/list/after_gas_mixes = create_gas_mixes(gas_mix_data) + + filter_gas(null, filtering, after_gas_mixes["source"], after_gas_mixes["sink"], after_gas_mixes["source"], null, INFINITY) + + check_moles_conserved(case_name, before_gas_mixes, after_gas_mixes) + + return 1 + +/datum/unit_test/atmos_machinery/conserve_moles/filter_gas_multi + name = "ATMOS MACHINERY: filter_gas_multi() Conserves Moles" + +/datum/unit_test/atmos_machinery/conserve_moles/filter_gas_multi/start_test() + for(var/case_name in test_cases) + var/gas_mix_data = test_cases[case_name] + var/list/before_gas_mixes = create_gas_mixes(gas_mix_data) + var/list/after_gas_mixes = create_gas_mixes(gas_mix_data) + + var/list/filtering = list() + for(var/gasid in gas_data.gases) + filtering[gasid] = after_gas_mixes["sink"] //just filter everything to sink + + filter_gas_multi(null, filtering, after_gas_mixes["source"], after_gas_mixes["sink"], null, INFINITY) + + check_moles_conserved(case_name, before_gas_mixes, after_gas_mixes) + + return 1 + +/datum/unit_test/atmos_machinery/conserve_moles/mix_gas + name = "ATMOS MACHINERY: mix_gas() Conserves Moles" + +/datum/unit_test/atmos_machinery/conserve_moles/mix_gas/start_test() + for(var/case_name in test_cases) + var/gas_mix_data = test_cases[case_name] + var/list/before_gas_mixes = create_gas_mixes(gas_mix_data) + var/list/after_gas_mixes = create_gas_mixes(gas_mix_data) + + var/list/mix_sources = list() + for(var/gasid in ALL_GASIDS) + var/datum/gas_mixture/mix_source = after_gas_mixes["sink"] + mix_sources[mix_source] = 1.0/gas_data.gases.len //doesn't work as a macro for some reason + + mix_gas(null, mix_sources, after_gas_mixes["sink"], null, INFINITY) + + check_moles_conserved(case_name, before_gas_mixes, after_gas_mixes) + + return 1 + +#undef ALL_GASIDS \ No newline at end of file diff --git a/code/unit_tests/cargo_tests.dm b/code/unit_tests/cargo_tests.dm new file mode 100644 index 00000000..a0cbe5e7 --- /dev/null +++ b/code/unit_tests/cargo_tests.dm @@ -0,0 +1,35 @@ +//======================================================================================= + +/datum/unit_test/cargo_crates_containment_test + name = "CARGO: Supply crates containment" + +/datum/unit_test/cargo_crates_containment_test/start_test() + var/bad_tests = 0 + + for(var/decl/hierarchy/supply_pack/supply_pack in cargo_supply_packs) + if(!ispath(supply_pack.containertype, /obj/structure/closet)) + continue + + var/obj/structure/closet/C = new supply_pack.containertype(get_safe_turf()) + supply_pack.spawn_contents(C) + + var/contents_pre_open = C.contents.Copy() + C.dump_contents() + C.store_contents() + var/list/no_longer_contained_atoms = contents_pre_open - C.contents + var/list/previously_not_contained_atoms = C.contents - contents_pre_open + + if(no_longer_contained_atoms.len) + bad_tests++ + log_bad("[supply_pack] - [log_info_line(C)] no longer contains the following atoms: [log_info_line(no_longer_contained_atoms)]") + if(previously_not_contained_atoms.len) + log_debug("[supply_pack] - [log_info_line(C)] now contains the following atoms: [log_info_line(previously_not_contained_atoms)]") + qdel(C) + QDEL_NULL_LIST(no_longer_contained_atoms) + + if(bad_tests) + fail("[bad_tests] cargo supply pack\s with inconsistent pre/post-open contents found.") + else + pass("No cargo supply packs with inconsistent pre/post-open contents found.") + + return 1 diff --git a/code/unit_tests/equipment_tests.dm b/code/unit_tests/equipment_tests.dm new file mode 100644 index 00000000..74bfddc6 --- /dev/null +++ b/code/unit_tests/equipment_tests.dm @@ -0,0 +1,108 @@ +#define SUCCESS 1 +#define FAILURE 0 + + +datum/unit_test/vision_glasses/ + name = "EQUIPMENT: Vision Template" + var/mob/living/carbon/human/H = null + var/expectation = SEE_INVISIBLE_NOLIGHTING + var/glasses_type = null + async = 1 + +datum/unit_test/vision_glasses/start_test() + spawn(0) + var/list/test = create_test_mob_with_mind(null, /mob/living/carbon/human) + if(isnull(test)) + fail("Check Runtimed in Mob creation") + + if(test["result"] == FAILURE) + fail(test["msg"]) + async = 0 + + return 0 + + H = locate(test["mobref"]) + + var/obj/item/clothing/glasses/G = new glasses_type() + H.glasses = G + + return 1 + + +datum/unit_test/vision_glasses/check_result() + + if(isnull(H) || H.life_tick < 2) + return 0 + + if(isnull(H.glasses)) + fail("Mob doesn't have glasses on") + + H.handle_vision() // Because Life has a client check that bypasses updating vision + + if(H.see_invisible == expectation) + pass("Mob See invisible is [H.see_invisible]") + else + fail("Mob See invisible is [H.see_invisible] / expected [expectation]") + + return 1 + +datum/unit_test/vision_glasses/NVG + name = "EQUIPMENT: NVG see_invis" + glasses_type = /obj/item/clothing/glasses/night + +datum/unit_test/vision_glasses/mesons + name = "EQUIPMENT: Mesons see_invis" + glasses_type = /obj/item/clothing/glasses/meson + +datum/unit_test/vision_glasses/plain + name = "EQUIPMENT: Plain glasses. see_invis" + glasses_type = /obj/item/clothing/glasses/regular + expectation = SEE_INVISIBLE_LIVING + +// ============================================================================ + +datum/unit_test/storage_capacity_test + name = "EQUIPMENT: Storage items should be able to actually hold their initial contents" + +datum/unit_test/storage_capacity_test/start_test() + var/bad_tests = 0 + + // obj/item/weapon/storage/internal cannot be tested sadly, as they expect their host object to create them + for(var/storage_type in subtypesof(/obj/item/weapon/storage) - typesof(/obj/item/weapon/storage/internal)) + var/obj/item/weapon/storage/S = new storage_type(null) //should be fine to put it in nullspace... + var/bad_msg = "[ascii_red]--------------- [S.name] \[[S.type]\]" + bad_tests += test_storage_capacity(S, bad_msg) + + if(bad_tests) + fail("\[[bad_tests]\] Some storage item types were not able to hold their default initial contents.") + else + pass("All storage item types were able to hold their default initial contents.") + + return 1 + +/proc/test_storage_capacity(obj/item/weapon/storage/S, var/bad_msg) + var/bad_tests = 0 + + if(!isnull(S.storage_slots) && S.contents.len > S.storage_slots) + log_unit_test("[bad_msg] Contains more items than it has slots for ([S.contents.len] / [S.storage_slots]). [ascii_reset]") + bad_tests++ + + var/total_storage_space = 0 + for(var/obj/item/I in S.contents) + if(I.w_class > S.max_w_class) + log_unit_test("[bad_msg] Contains an item \[[I.type]\] that is too big to be held ([I.w_class] / [S.max_w_class]). [ascii_reset]") + bad_tests++ + if(istype(I, /obj/item/weapon/storage) && I.w_class >= S.w_class) + log_unit_test("[bad_msg] Contains a storage item \[[I.type]\] the same size or larger than its container ([I.w_class] / [S.w_class]). [ascii_reset]") + bad_tests++ + total_storage_space += I.get_storage_cost() + + if(total_storage_space > S.max_storage_space) + log_unit_test("[bad_msg] Contains more items than it has storage space for ([total_storage_space] / [S.max_storage_space]). [ascii_reset]") + bad_tests++ + + return bad_tests + +#undef SUCCESS +#undef FAILURE + diff --git a/code/unit_tests/extension_tests.dm b/code/unit_tests/extension_tests.dm new file mode 100644 index 00000000..8bba4651 --- /dev/null +++ b/code/unit_tests/extension_tests.dm @@ -0,0 +1,49 @@ +/datum/unit_test/extensions + name = "EXTENSIONS template" + async = 0 + +/datum/unit_test/extensions/shall_initalize_as_expected + name = "EXTENSIONS - Shall Initialize as Expected" + +/datum/unit_test/extensions/shall_initalize_as_expected/start_test() + var/turf/start = get_safe_turf() + var/obj/test/extensions/expansion_obj = new(start, TRUE) + + var/number_of_failures = 0 + for(var/extension in expansion_obj) + if(ispath(extension)) + log_unit_test("[extension] was uninitalized.") + number_of_failures++ + + var/datum/extension/exp = get_extension(expansion_obj, /datum/extension) + if(exp.type != /datum/extension) + log_unit_test("[exp]/([exp.type]) was not strictly of the type /datum/extension.") + number_of_failures++ + + var/datum/extension/interactive/multitool/multi = get_extension(expansion_obj, /datum/extension/interactive/multitool) + if(multi.type != /datum/extension/interactive/multitool/items/cable) + log_unit_test("[exp]/([exp.type]) was not strictly of the type /datum/extension/interactive/multitool/items/cable.") + number_of_failures++ + else + if(multi.host_predicates.len != 2) + log_unit_test("Unexpected interaction predicate length. Was [multi.host_predicates.len], expected 2.") + number_of_failures++ + else if(multi.host_predicates[1] != /proc/is_operable) + log_unit_test("Unexpected interaction predicate at index 1. Was [multi.host_predicates[1]], expected /proc/is_operable.") + number_of_failures++ + else if(multi.host_predicates[2] != /proc/is_operable) + log_unit_test("Unexpected interaction predicate at index 2. Was [multi.host_predicates[2]], expected /proc/is_operable.") + number_of_failures++ + + if(number_of_failures) + fail("[number_of_failures] failed assertion\s.") + else + pass("All assertions passed.") + + qdel(expansion_obj) + return TRUE + +/obj/test/extensions/New() + set_extension(src, /datum/extension, /datum/extension) + set_extension(src, /datum/extension/interactive/multitool, /datum/extension/interactive/multitool/items/cable, list(/proc/is_operable, /proc/is_operable)) + ..() diff --git a/code/unit_tests/food_tests.dm b/code/unit_tests/food_tests.dm new file mode 100644 index 00000000..3eaa1988 --- /dev/null +++ b/code/unit_tests/food_tests.dm @@ -0,0 +1,40 @@ +/** + * Each slice origin items should cut into the same slice. + * + * Each slice type defines an item from which it originates. Each sliceable + * item defines what item it cuts into. This test checks if the two defnitions + * are consistent between the two items. + */ +/datum/unit_test/food_slices_and_origin_items_should_be_consistent + name = "FOOD: Each slice origin item should cut into the appropriate slice" + +/datum/unit_test/food_slices_and_origin_items_should_be_consistent/start_test() + var/any_failed = FALSE + + for (var/subtype in subtypesof(/obj/item/weapon/reagent_containers/food/snacks/slice)) + var/obj/item/weapon/reagent_containers/food/snacks/slice/slice = subtype + if(!initial(slice.whole_path)) + log_bad("[slice] does not define a whole_path.") + any_failed = TRUE + continue + + if(!ispath(initial(slice.whole_path), /obj/item/weapon/reagent_containers/food/snacks/sliceable)) + log_bad("[slice]/whole_path is not a subtype of sliceable.") + any_failed = TRUE + continue + + var/obj/item/weapon/reagent_containers/food/snacks/sliceable/whole = initial(slice.whole_path) + + // note that the slice can be a subtype of the one defined in slice_path + if(!ispath(slice, initial(whole.slice_path))) + log_bad("[whole] does not define slice_path as [slice].") + any_failed = TRUE + continue + + if(any_failed) + fail("Some slice types were incorrectly defined.") + else + pass("All slice types defined correctly.") + + return 1 + diff --git a/code/unit_tests/foundation_tests.dm b/code/unit_tests/foundation_tests.dm new file mode 100644 index 00000000..4763c73c --- /dev/null +++ b/code/unit_tests/foundation_tests.dm @@ -0,0 +1,29 @@ +/* +* Unit tests for built-in BYOND procs, to ensure overrides have not affected functionality. +*/ +datum/unit_test/foundation + name = "FOUNDATION template" + async = 0 + +datum/unit_test/foundation/step_shall_return_true_on_success + name = "FOUNDATION: step() shall return true on success" + +datum/unit_test/foundation/step_shall_return_true_on_success/start_test() + var/mob_step_result = TestStep(/mob) + var/obj_step_result = TestStep(/obj) + + if(mob_step_result && obj_step_result) + pass("step() returned true.") + else + fail("step() did not return true: Mob result: [mob_step_result] - Obj result: [obj_step_result].") + + return 1 + +datum/unit_test/foundation/proc/TestStep(type_to_test) + var/turf/start = get_safe_turf() + var/atom/movable/T = new type_to_test(start) + + . = step(T, NORTH) + . = . && start.x == T.x + . = . && start.y + 1 == T.y + . = . && start.z == T.z diff --git a/code/unit_tests/icon_tests.dm b/code/unit_tests/icon_tests.dm new file mode 100644 index 00000000..5ed35f9e --- /dev/null +++ b/code/unit_tests/icon_tests.dm @@ -0,0 +1,98 @@ +/datum/unit_test/icon_test + name = "ICON STATE template" + +/datum/unit_test/icon_test/robots_shall_have_eyes_for_each_state + name = "ICON STATE - Robot shall have eyes for each icon state" + var/list/excepted_icon_states_ = list( + "b1","b1+o","b2","b2+o","b3","b3+o","d1","d1+o","d2","d2+o","d3","d3+o", + "floor1","floor2","floor3","floor4","floor5","floor6","floor7", + "gib1","gib2","gib3","gib4","gib5","gib6","gib7","gibdown","gibup","gibbl1","gibarm","gibleg", + "streak1","streak2","streak3","streak4","streak5", + "droid-combat-roll","droid-combat-shield","emag","remainsrobot", "robot+o+c","robot+o-c","robot+we") + +/datum/unit_test/icon_test/robots_shall_have_eyes_for_each_state/start_test() + var/missing_states = 0 + var/list/valid_states = icon_states('icons/mob/robots.dmi') + + var/list/original_valid_states = valid_states.Copy() + for(var/icon_state in valid_states) + if(icon_state in excepted_icon_states_) + continue + if(starts_with(icon_state, "eyes-")) + continue + if(findtext(icon_state, "openpanel")) + continue + var/eye_icon_state = "eyes-[icon_state]" + if(!(eye_icon_state in valid_states)) + log_unit_test("Eye icon state [eye_icon_state] is missing.") + missing_states++ + + if(missing_states) + fail("[missing_states] eye icon state\s [missing_states == 1 ? "is" : "are"] missing.") + var/list/difference = uniquemergelist(original_valid_states, valid_states) + if(difference.len) + log_unit_test("[ascii_yellow]--- DEBUG --- ICON STATES AT START: " + jointext(original_valid_states, ",") + "[ascii_reset]") + log_unit_test("[ascii_yellow]--- DEBUG --- ICON STATES AT END: " + jointext(valid_states, ",") + "[ascii_reset]") + log_unit_test("[ascii_yellow]--- DEBUG --- UNIQUE TO EACH LIST: " + jointext(difference, ",") + "[ascii_reset]") + else + pass("All related eye icon states exists.") + return 1 + +/datum/unit_test/icon_test/sprite_accessories_shall_have_existing_icon_states + name = "ICON STATE - Sprite accessories shall have existing icon states" + +/datum/unit_test/icon_test/sprite_accessories_shall_have_existing_icon_states/start_test() + var/sprite_accessory_subtypes = list( + /datum/sprite_accessory/hair, + /datum/sprite_accessory/facial_hair + ) + + var/list/failed_sprite_accessories = list() + var/icon_state_cache = list() + var/duplicates_found = FALSE + + for(var/sprite_accessory_main_type in sprite_accessory_subtypes) + var/sprite_accessories_by_name = list() + for(var/sprite_accessory_type in subtypesof(sprite_accessory_main_type)) + var/failed = FALSE + var/datum/sprite_accessory/sat = sprite_accessory_type + + var/sat_name = initial(sat.name) + if(sat_name) + group_by(sprite_accessories_by_name, sat_name, sat) + else + failed = TRUE + log_bad("[sat] - Did not have a name set.") + + var/sat_icon = initial(sat.icon) + if(sat_icon) + var/sat_icon_states = icon_state_cache[sat_icon] + if(!sat_icon_states) + sat_icon_states = icon_states(sat_icon) + icon_state_cache[sat_icon] = sat_icon_states + + var/sat_icon_state = initial(sat.icon_state) + if(sat_icon_state) + sat_icon_state = "[sat_icon_state]_s" + if(!(sat_icon_state in sat_icon_states)) + failed = TRUE + log_bad("[sat] - \"[sat_icon_state]\" did not exist in '[sat_icon]'.") + else + failed = TRUE + log_bad("[sat] - Did not have an icon state set.") + else + failed = TRUE + log_bad("[sat] - Did not have an icon set.") + + if(failed) + failed_sprite_accessories += sat + + if(number_of_issues(sprite_accessories_by_name, "Sprite Accessory Names")) + duplicates_found = TRUE + + if(failed_sprite_accessories.len || duplicates_found) + fail("One or more sprite accessory issues detected.") + else + pass("All sprite accessories were valid.") + + return 1 diff --git a/code/unit_tests/integrated_circuits.dm b/code/unit_tests/integrated_circuits.dm new file mode 100644 index 00000000..72259310 --- /dev/null +++ b/code/unit_tests/integrated_circuits.dm @@ -0,0 +1,116 @@ +/datum/unit_test/integrated_circuits/prefabs_shall_respect_complexity_and_size_contraints + name = "INTEGRATED CIRCUITS - Prefabs Shall Respect Complexity and Size Constraints" + +/datum/unit_test/integrated_circuits/prefabs_shall_respect_complexity_and_size_contraints/start_test() + var/list/failed_prefabs = list() + for(var/prefab_type in subtypesof(/decl/prefab/ic_assembly)) + var/decl/prefab/ic_assembly/prefab = decls_repository.get_decl(prefab_type) + var/obj/item/device/electronic_assembly/assembly = prefab.assembly_type + + var/available_size = initial(assembly.max_components) + var/available_complexity = initial(assembly.max_complexity) + for(var/ic in prefab.integrated_circuits) + var/datum/ic_assembly_integrated_circuits/iaic = ic + var/obj/item/integrated_circuit/circuit = iaic.circuit_type + available_size -= initial(circuit.size) + available_complexity -= initial(circuit.complexity) + if(available_size < 0) + log_bad("[prefab_type] has an excess component size of [abs(available_size)]") + failed_prefabs |= prefab_type + if(available_complexity < 0) + log_bad("[prefab_type] has an excess component complexity of [abs(available_complexity)]") + failed_prefabs |= prefab_type + + if(failed_prefabs.len) + fail("The following integrated prefab types are out of bounds: [english_list(failed_prefabs)]") + else + pass("All integrated circuit prefabs are within complexity and size limits.") + + return 1 + +/datum/unit_test/integrated_circuits/prefabs_shall_not_fail_to_create + name = "INTEGRATED CIRCUITS - Prefabs Shall Not Fail To Create" + +/datum/unit_test/integrated_circuits/prefabs_shall_not_fail_to_create/start_test() + var/list/failed_prefabs = list() + for(var/prefab_type in subtypesof(/decl/prefab/ic_assembly)) + var/decl/prefab/ic_assembly/prefab = decls_repository.get_decl(prefab_type) + + try + var/built_item = prefab.create(get_safe_turf()) + if(built_item) + qdel(built_item) + else + log_bad("[prefab_type] failed to create or return its item.") + failed_prefabs |= prefab_type + catch(var/exception/e) + log_bad("[prefab_type] caused an exception: [e] on [e.file]:[e.line]") + failed_prefabs |= prefab_type + + if(failed_prefabs.len) + fail("The following integrated prefab types failed to create their assemblies: [english_list(failed_prefabs)]") + else + pass("All integrated circuit prefabs are within complexity and size limits.") + + return 1 + +/datum/unit_test/integrated_circuits/input_output + name = "INTEGRATED CIRCUITS - INPUT/OUTPUT - TEMPLATE" + var/list/all_inputs = list() + var/list/all_expected_outputs = list() + var/activation_pin = 1 + var/circuit_type + +#define IC_TEST_ANY_OUTPUT "#IGNORE_THIS_OUTPUT#" + +/datum/unit_test/integrated_circuits/input_output/start_test() + var/obj/item/integrated_circuit/ic = new circuit_type() + var/failed = FALSE + + if(all_inputs.len != all_expected_outputs.len) + fail("Given inputs do not match the expected outputs length.") + return 1 + + for(var/test_index = 1 to all_inputs.len) + var/list/inputs = all_inputs[test_index] + var/list/expected_outputs = all_expected_outputs[test_index] + + for(var/input_pin_index = 1 to inputs.len) + ic.set_pin_data(IC_INPUT, input_pin_index, inputs[input_pin_index]) + + var/activator = ic.activators[activation_pin] + ic.do_work(activator) + + for(var/output_index = 1 to expected_outputs.len) + var/actual_output = ic.get_pin_data(IC_OUTPUT, output_index) + var/expected_output = expected_outputs[output_index] + if(expected_output == IC_TEST_ANY_OUTPUT) + continue + if(actual_output != expected_output) + failed = TRUE + log_bad("[circuit_type] - Test [test_index] - Expected '[expected_output]', was '[actual_output]'") + for(var/datum/integrated_io/io in ic.inputs) + log_bad("Raw Input: [io.data]") + for(var/datum/integrated_io/io in ic.outputs) + log_bad("Raw Output: [io.data]") + + qdel(ic) + if(failed) + fail("The circuit [circuit_type] did not meet all expectations.") + else + pass("The circuit [circuit_type] met all expectations.") + return 1 + +/datum/unit_test/integrated_circuits/input_output/multiplexer + name = "INTEGRATED CIRCUITS - INPUT/OUTPUT - Multiplexer - Medium" + all_inputs = list(list(1,1,2,3,4),list(2,1,2,3,4),list(3,1,2,3,4),list(4,1,2,3,4)) + all_expected_outputs = list(list(1),list(2),list(3),list(4)) + circuit_type = /obj/item/integrated_circuit/logic/multiplexer/medium + +/datum/unit_test/integrated_circuits/input_output/demultiplexer + name = "INTEGRATED CIRCUITS - INPUT/OUTPUT - Demultiplexer - Medium" + all_inputs = list(list(1,5),list(2,6),list(3,7),list(4,8)) + all_expected_outputs = list(list(5,null,null,null),list(null,6,null,null),list(null,null,7,null),list(null,null,null,8)) + circuit_type = /obj/item/integrated_circuit/logic/demultiplexer/medium + +#undef IC_TEST_ANY_OUTPUT diff --git a/code/unit_tests/job_tests.dm b/code/unit_tests/job_tests.dm new file mode 100644 index 00000000..d1f849e7 --- /dev/null +++ b/code/unit_tests/job_tests.dm @@ -0,0 +1,51 @@ +/datum/unit_test/jobs_shall_have_a_valid_outfit_type + name = "JOB: Shall have a valid outfit type" + +/datum/unit_test/jobs_shall_have_a_valid_outfit_type/start_test() + var/failed_jobs = 0 + + for (var/occ in job_master.occupations) + var/datum/job/occupation = occ + var/decl/hierarchy/outfit/job/outfit = outfit_by_type(occupation.outfit_type) + if(!istype(outfit)) + log_bad("[occupation.title] - [occupation.type]: Invalid outfit type [outfit ? outfit.type : "NULL"].") + failed_jobs++ + + if(failed_jobs) + fail("[failed_jobs] job\s with invalid outfit type.") + else + pass("All jobs had outfit types.") + return 1 + +/datum/unit_test/jobs_shall_have_a_HUD_icon + name = "JOB: Shall have a HUD icon" + +/datum/unit_test/jobs_shall_have_a_HUD_icon/start_test() + var/failed_jobs = 0 + var/failed_sanity_checks = 0 + + var/job_huds = icon_states(GLOB.using_map.id_hud_icons) + + if(!("" in job_huds)) + log_bad("Sanity Check - Missing default/unnamed HUD icon") + failed_sanity_checks++ + + if(!("hudunknown" in job_huds)) + log_bad("Sanity Check - Missing HUD icon: hudunknown") + failed_sanity_checks++ + + if(!("hudcentcom" in job_huds)) + log_bad("Sanity Check - Missing HUD icon: hudcentcom") + failed_sanity_checks++ + + for (var/datum/job/J in job_master.occupations) + var/hud_icon_state = J.hud_icon + if(!(hud_icon_state in job_huds)) + log_bad("[J.title] - Missing HUD icon: [hud_icon_state]") + failed_jobs++ + + if(failed_sanity_checks || failed_jobs) + fail("[GLOB.using_map.id_hud_icons] - [failed_sanity_checks] failed sanity check\s, [failed_jobs] job\s with missing HUD icon.") + else + pass("All jobs have a HUD icon.") + return 1 diff --git a/code/unit_tests/loadout_tests.dm b/code/unit_tests/loadout_tests.dm new file mode 100644 index 00000000..ffe2fcb1 --- /dev/null +++ b/code/unit_tests/loadout_tests.dm @@ -0,0 +1,104 @@ +datum/unit_test/loadout_test_shall_have_name_cost_path + name = "LOADOUT: Entries shall have name, cost, and path definitions" + +datum/unit_test/loadout_test_shall_have_name_cost_path/start_test() + var/failed = 0 + for(var/gear_name in gear_datums) + var/datum/gear/G = gear_datums[gear_name] + + if(!G.display_name) + log_unit_test("[G]: Missing display name.") + failed = 1 + else if(isnull(G.cost) || G.cost < 0) + log_unit_test("[G]: Invalid cost.") + failed = 1 + else if(!G.path) + log_unit_test("[G]: Missing path definition.") + failed = 1 + + if(failed) + fail("One or more /datum/gear definitions had invalid display names, costs, or path definitions") + else + pass("All /datum/gear definitions had correct settings.") + return 1 + +datum/unit_test/loadout_test_shall_have_valid_icon_states + name = "LOADOUT: Entries shall have valid icon states" + +datum/unit_test/loadout_test_shall_have_valid_icon_states/start_test() + var/failed = FALSE + for(var/gear_name in gear_datums) + var/datum/gear/G = gear_datums[gear_name] + var/list/path_tweaks = list() + for(var/datum/gear_tweak/path/p in G.gear_tweaks) + path_tweaks += p + + if(path_tweaks.len) + for(var/datum/gear_tweak/path/p in path_tweaks) + for(var/path_name in p.valid_paths) + var/path_type = p.valid_paths[path_name] + if(!type_has_valid_icon_state(path_type)) + var/atom/A = path_type + log_unit_test("[G] - [path_type] ('[path_name]'): Did not find a gear_tweak's icon_state '[initial(A.icon_state)]' in the icon '[initial(A.icon)]'.") + failed = TRUE + else + if(!type_has_valid_icon_state(G.path)) + var/obj/O = G.path + if(ispath(G.path, /obj)) + O = new G.path() + if(!(O.icon_state in icon_states(O.icon))) + log_unit_test("[G] - [G.path]: Did not find the icon state '[O.icon_state]' in the icon '[O.icon]'.") + failed = TRUE + qdel(O) + else + log_unit_test("[G] - [G.path]: Did not find the icon state '[initial(O.icon_state)]' in the icon '[initial(O.icon)]'.") + failed = TRUE + + if(failed) + fail("One or more /datum/gear definitions had paths with invalid icon states.") + else + pass("All /datum/gear definitions had correct icon states.") + return 1 + +datum/unit_test/loadout_test_gear_path_tweaks_shall_be_of_gear_path + name = "LOADOUT: Gear path tweaks shall be of gear path." + +datum/unit_test/loadout_test_gear_path_tweaks_shall_be_of_gear_path/start_test() + var/failed = 0 + for(var/gear_name in gear_datums) + var/datum/gear/G = gear_datums[gear_name] + for(var/datum/gear_tweak/path/p in G.gear_tweaks) + for(var/path_name in p.valid_paths) + var/path_type = p.valid_paths[path_name] + if(!ispath(path_type, G.path)) + log_unit_test("[G] - [path_type] ('[path_name]'): Was not a path of [G.path].") + failed++ + + if(failed) + fail("[failed] /datum/gear_tweak/path definition\s had invalid paths.") + else + pass("All /datum/gear_tweak/paths had valid paths.") + return 1 + +datum/unit_test/loadout_test_gear_path_tweaks_shall_have_unique_keys + name = "LOADOUT: Gear path tweaks shall have unique keys" + +datum/unit_test/loadout_test_gear_path_tweaks_shall_have_unique_keys/start_test() + var/path_entries_by_gear_path_and_name = list() + + for(var/gear_name in gear_datums) + var/datum/gear/G = gear_datums[gear_name] + for(var/datum/gear_tweak/path/p in G.gear_tweaks) + for(var/path_name in p.valid_paths) + group_by(path_entries_by_gear_path_and_name, "[G] - [p] - [path_name]", path_name) + + var/number_of_issues = number_of_issues(path_entries_by_gear_path_and_name, "Path Tweak Names") + if(number_of_issues) + fail("[number_of_issues] /datum/gear_tweak/path definition\s found.") + else + pass("All /datum/gear_tweak/path definitions had unique names.") + return 1 + +/proc/type_has_valid_icon_state(var/atom/type) + var/atom/A = type + return (initial(A.icon_state) in icon_states(initial(A.icon))) diff --git a/code/unit_tests/map_tests.dm b/code/unit_tests/map_tests.dm new file mode 100644 index 00000000..7760365c --- /dev/null +++ b/code/unit_tests/map_tests.dm @@ -0,0 +1,504 @@ +/* + * + * Map Unit Tests. + * Zone checks / APC / Scrubber / Vent / Cryopod Computers. + * + * + */ + +#define FAILURE 0 +#define SUCCESS 1 + + +/datum/unit_test/apc_area_test + name = "MAP: Area Test APC / Scrubbers / Vents" + + +/datum/unit_test/apc_area_test/start_test() + var/list/bad_areas = list() + var/area_test_count = 0 + + for(var/area/A in world) + if(!A.z) + continue + if(!isPlayerLevel(A.z)) + continue + area_test_count++ + var/area_good = 1 + var/bad_msg = "--------------- [A.name]([A.type])" + + var/exemptions = get_exemptions(A) + if(!A.apc && !(exemptions & GLOB.using_map.NO_APC)) + log_bad("[bad_msg] lacks an APC.") + area_good = 0 + else if(A.apc && (exemptions & GLOB.using_map.NO_APC)) + log_bad("[bad_msg] is not supposed to have an APC.") + area_good = 0 + + if(!A.air_scrub_info.len && !(exemptions & GLOB.using_map.NO_SCRUBBER)) + log_bad("[bad_msg] lacks an air scrubber.") + area_good = 0 + else if(A.air_scrub_info.len && (exemptions & GLOB.using_map.NO_SCRUBBER)) + log_bad("[bad_msg] is not supposed to have an air scrubber.") + area_good = 0 + + if(!A.air_vent_info.len && !(exemptions & GLOB.using_map.NO_VENT)) + log_bad("[bad_msg] lacks an air vent.[ascii_reset]") + area_good = 0 + else if(A.air_vent_info.len && (exemptions & GLOB.using_map.NO_VENT)) + log_bad("[bad_msg] is not supposed to have an air vent.") + area_good = 0 + + if(!area_good) + bad_areas.Add(A) + + if(bad_areas.len) + fail("\[[bad_areas.len]/[area_test_count]\]Some areas did not have the expected APC/vent/scrubber setup.") + else + pass("All \[[area_test_count]\] areas contained APCs, air scrubbers, and air vents.") + + return 1 + +/datum/unit_test/apc_area_test/proc/get_exemptions(var/area) + // We assume deeper types come last + for(var/i = GLOB.using_map.apc_test_exempt_areas.len; i>0; i--) + var/exempt_type = GLOB.using_map.apc_test_exempt_areas[i] + if(istype(area, exempt_type)) + return GLOB.using_map.apc_test_exempt_areas[exempt_type] + +//======================================================================================= + +/datum/unit_test/wire_test + name = "MAP: Cable Overlap Test" + +/datum/unit_test/wire_test/start_test() + var/wire_test_count = 0 + var/bad_tests = 0 + var/turf/T = null + var/obj/structure/cable/C = null + var/list/cable_turfs = list() + var/list/dirs_checked = list() + + for(C in world) + T = get_turf(C) + cable_turfs |= get_turf(C) + + for(T in cable_turfs) + var/bad_msg = "[ascii_red]--------------- [T.name] \[[T.x] / [T.y] / [T.z]\]" + dirs_checked.Cut() + for(C in T) + wire_test_count++ + var/combined_dir = "[C.d1]-[C.d2]" + if(combined_dir in dirs_checked) + bad_tests++ + log_unit_test("[bad_msg] Contains multiple wires with same direction on top of each other.") + dirs_checked.Add(combined_dir) + + if(bad_tests) + fail("\[[bad_tests] / [wire_test_count]\] Some turfs had overlapping wires going the same direction.") + else + pass("All \[[wire_test_count]\] wires had no overlapping cables going the same direction.") + + return 1 + +//======================================================================================= + +/datum/unit_test/wire_dir_and_icon_stat + name = "MAP: Cable Dir And Icon State Test" + +/datum/unit_test/wire_dir_and_icon_stat/start_test() + var/list/bad_cables = list() + + for(var/obj/structure/cable/C in world) + var/expected_icon_state = "[C.d1]-[C.d2]" + if(C.icon_state != expected_icon_state) + bad_cables |= C + log_bad("[log_info_line(C)] has an invalid icon state. Expected [expected_icon_state], was [C.icon_state]") + if(!(C.icon_state in icon_states(C.icon))) + bad_cables |= C + log_bad("[log_info_line(C)] has an non-existing icon state.") + + if(bad_cables.len) + fail("Found [bad_cables.len] cable\s with an unexpected icon state.") + else + pass("All wires had their expected icon state.") + + return 1 + +//======================================================================================= + +/datum/unit_test/closet_test + name = "MAP: Closet Capacity Test Player Z levels" + +/datum/unit_test/closet_test/start_test() + var/bad_tests = 0 + + for(var/obj/structure/closet/C in world) + if(!C.opened && isPlayerLevel(C.z)) + var/total_content_size = 0 + for(var/atom/movable/AM in C.contents) + total_content_size += C.content_size(AM) + if(total_content_size > C.storage_capacity) + log_bad("[log_info_line(C)] contains more objects than able to hold ([total_content_size] / [C.storage_capacity]).") + bad_tests++ + + if(bad_tests) + fail("\[[bad_tests]\] Some closets contained more objects than they were able to hold.") + else + pass("No overflowing closets found.") + + return 1 + +//======================================================================================= + +/datum/unit_test/closet_containment_test + name = "MAP: Closet Containment Test Player Z levels" + +/datum/unit_test/closet_containment_test/start_test() + var/bad_tests = 0 + + for(var/obj/structure/closet/C in world) + if(!C.opened && isPlayerLevel(C.z)) + var/contents_pre_open = C.contents.Copy() + C.dump_contents() + C.store_contents() + var/list/no_longer_contained_atoms = contents_pre_open - C.contents + var/list/previously_not_contained_atoms = C.contents - contents_pre_open + + if(no_longer_contained_atoms.len) + bad_tests++ + log_bad("[log_info_line(C)] no longer contains the following atoms: [log_info_line(no_longer_contained_atoms)]") + if(previously_not_contained_atoms.len) + log_debug("[log_info_line(C)] now contains the following atoms: [log_info_line(previously_not_contained_atoms)]") + + if(bad_tests) + fail("[bad_tests] closet\s with inconsistent pre/post-open contents found.") + else + pass("No closets with inconsistent pre/post-open contents found.") + + return 1 + +//======================================================================================= + +/datum/unit_test/storage_map_test + name = "MAP: On Map Storage Item Capacity Test Player Z levels" + +/datum/unit_test/storage_map_test/start_test() + var/bad_tests = 0 + + for(var/obj/item/weapon/storage/S in world) + if(isPlayerLevel(S.z)) + var/bad_msg = "[ascii_red]--------------- [S.name] \[[S.type]\] \[[S.x] / [S.y] / [S.z]\]" + bad_tests += test_storage_capacity(S, bad_msg) + + if(bad_tests) + fail("\[[bad_tests]\] Some on-map storage items were not able to hold their initial contents.") + else + pass("All on-map storage items were able to hold their initial contents.") + + return 1 + +/datum/unit_test/map_image_map_test + name = "MAP: All map levels shall have a corresponding map image." + +/datum/unit_test/map_image_map_test/start_test() + var/failed = FALSE + + for(var/z in GLOB.using_map.map_levels) + var/file_name = map_image_file_name(z) + var/file_path = MAP_IMAGE_PATH + file_name + if(!fexists(file_path)) + failed = TRUE + log_unit_test("[GLOB.using_map.path]-[z] is missing its map image [file_name].") + + if(failed) + fail("One or more map levels were missing a corresponding map image.") + else + pass("All map levels had a corresponding image.") + + return 1 + +//======================================================================================= + +datum/unit_test/correct_allowed_spawn_test + name = "MAP: All allowed_spawns entries should have spawnpoints on map." + +datum/unit_test/correct_allowed_spawn_test/start_test() + var/failed = FALSE + + for(var/spawn_name in GLOB.using_map.allowed_spawns) + var/datum/spawnpoint/spawnpoint = spawntypes()[spawn_name] + if(!spawnpoint) + log_unit_test("Map allows spawning in [spawn_name], but [spawn_name] is null!") + failed = TRUE + else if(!spawnpoint.turfs.len) + log_unit_test("Map allows spawning in [spawn_name], but [spawn_name] has no associated spawn turfs.") + failed = TRUE + + if(failed) + log_unit_test("Following spawn points exist:") + for(var/spawnpoint in spawntypes()) + log_unit_test("\t[spawnpoint] ([any2ref(spawnpoint)])") + log_unit_test("Following spawn points are allowed:") + for(var/spawnpoint in GLOB.using_map.allowed_spawns) + log_unit_test("\t[spawnpoint] ([any2ref(spawnpoint)])") + fail("Some of the entries in allowed_spawns have no spawnpoint turfs.") + else + pass("All entries in allowed_spawns have spawnpoints.") + + return 1 + +//======================================================================================= + +datum/unit_test/map_check + name = "MAP: Map Check" + +datum/unit_test/map_check/start_test() + if(world.maxx < 1 || world.maxy < 1 || world.maxz < 1) + fail("Unexpected map size. Was a map properly included?") + else + pass("Map size met minimum requirements.") + return 1 +//======================================================================================= + +datum/unit_test/ladder_check + name = "MAP: Ladder Check" + +datum/unit_test/ladder_check/start_test() + var/succeeded = TRUE + for(var/obj/structure/ladder/L) + if(L.allowed_directions & UP) + succeeded = check_direction(L, GetAbove(L), UP, DOWN) && succeeded + if(L.allowed_directions & DOWN) + succeeded = check_direction(L, GetBelow(L), DOWN, UP) && succeeded + if(succeeded) + pass("All ladders are correctly setup.") + else + fail("One or more ladders are incorrectly setup.") + + return 1 + +/datum/unit_test/ladder_check/proc/check_direction(var/obj/structure/ladder/L, var/turf/destination_turf, var/check_direction, var/other_ladder_direction) + if(!destination_turf) + log_bad("Unable to acquire turf in the [dir2text(check_direction)] for [log_info_line(L)]") + return FALSE + var/obj/structure/ladder/other_ladder = (locate(/obj/structure/ladder) in destination_turf) + if(!other_ladder) + log_bad("Unable to acquire ladder in the direction [dir2text(check_direction)] for [log_info_line(L)]") + return FALSE + if(!(other_ladder.allowed_directions & other_ladder_direction)) + log_bad("The ladder in the direction [dir2text(check_direction)] is not allowed to connect to [log_info_line(L)]") + return FALSE + return TRUE + +//======================================================================================= + +/datum/unit_test/landmark_check + name = "MAP: Landmark Check" + +/datum/unit_test/landmark_check/start_test() + var/safe_landmarks = 0 + var/space_landmarks = 0 + + for(var/lm in landmarks_list) + var/obj/effect/landmark/landmark = lm + if(istype(landmark, /obj/effect/landmark/test/safe_turf)) + log_debug("Safe landmark found: [log_info_line(landmark)]") + safe_landmarks++ + else if(istype(landmark, /obj/effect/landmark/test/space_turf)) + log_debug("Space landmark found: [log_info_line(landmark)]") + space_landmarks++ + else if(istype(landmark, /obj/effect/landmark/test)) + log_debug("Test landmark with unknown tag found: [log_info_line(landmark)]") + + if(safe_landmarks != 1 || space_landmarks != 1) + if(safe_landmarks != 1) + log_bad("Found [safe_landmarks] safe landmarks. Expected 1.") + if(space_landmarks != 1) + log_bad("Found [space_landmarks] space landmarks. Expected 1.") + fail("Expected exactly one safe landmark, and one space landmark.") + else + pass("Exactly one safe landmark, and exactly one space landmark found.") + + return 1 + +//======================================================================================= + +/datum/unit_test/cryopod_comp_check + name = "MAP: Cryopod Validity Check" + +/datum/unit_test/cryopod_comp_check/start_test() + var/pass = TRUE + + for(var/obj/machinery/cryopod/C in SSmachines.machinery) + if(!C.control_computer) + log_bad("[get_area(C)] lacks a cryopod control computer while holding a cryopod.") + pass = FALSE + + for(var/obj/machinery/computer/cryopod/C in SSmachines.machinery) + if(!(locate(/obj/machinery/cryopod) in get_area(C))) + log_bad("[get_area(C)] lacks a cryopod while holding a control computer.") + pass = FALSE + + if(pass) + pass("All cryopods have their respective control computers.") + else + fail("Cryopods were not set up correctly.") + + return 1 + +//======================================================================================= + +/datum/unit_test/camera_nil_c_tag_check + name = "MAP: Camera nil c_tag check" + +/datum/unit_test/camera_nil_c_tag_check/start_test() + var/pass = TRUE + + for(var/obj/machinery/camera/C in world) + if(!C.c_tag) + log_bad("Following camera does not have a c_tag set: [log_info_line(C)]") + pass = FALSE + + if(pass) + pass("Have cameras have the c_tag set.") + else + fail("One or more cameras do not have the c_tag set.") + + return 1 + +//======================================================================================= + +/datum/unit_test/camera_unique_c_tag_check + name = "MAP: Camera unique c_tag check" + +/datum/unit_test/camera_unique_c_tag_check/start_test() + var/cameras_by_ctag = list() + var/checked_cameras = 0 + + for(var/obj/machinery/camera/C in world) + if(!C.c_tag) + continue + checked_cameras++ + group_by(cameras_by_ctag, C.c_tag, C) + + var/number_of_issues = number_of_issues(cameras_by_ctag, "Camera c_tags", /decl/noi_feedback/detailed) + if(number_of_issues) + fail("[number_of_issues] issue\s with camera c_tags found.") + else + pass("[checked_cameras] camera\s have a unique c_tag.") + + return 1 + +//======================================================================================= + +/datum/unit_test/disposal_segments_shall_connect_with_other_disposal_pipes + name = "MAP: Disposal segments shall connect with other disposal pipes" + +/datum/unit_test/disposal_segments_shall_connect_with_other_disposal_pipes/start_test() + var/list/faulty_pipes = list() + + // Desired directions for straight pipes, when encountering curved pipes in the main and reversed dir respectively + var/list/straight_desired_directions = list( + num2text(SOUTH) = list(list(NORTH, WEST), list(SOUTH, EAST)), + num2text(EAST) = list(list(SOUTH, WEST), list(NORTH, EAST))) + + // Desired directions for curved pipes: + // list(desired_straight, list(desired_curved_one, desired_curved_two) in the main and curved direction + var/list/curved_desired_directions = list( + num2text(NORTH) = list(list(SOUTH, list(SOUTH, EAST)), list(EAST, list(SOUTH, WEST))), + num2text(EAST) = list(list(EAST, list(SOUTH, WEST)), list(SOUTH, list(NORTH, WEST))), + num2text(SOUTH) = list(list(SOUTH, list(NORTH, WEST)), list(EAST, list(NORTH, EAST))), + num2text(WEST) = list(list(EAST, list(NORTH, EAST)), list(SOUTH, list(SOUTH, EAST)))) + + for(var/obj/structure/disposalpipe/segment/D in world) + if(D.icon_state == "pipe-s") + if(!(D.dir == SOUTH || D.dir == EAST)) + log_bad("Following disposal pipe has an invalid direction set: [log_info_line(D)]") + continue + var/turf/turf_one = get_step(D.loc, D.dir) + var/turf/turf_two = get_step(D.loc, turn(D.dir, 180)) + + var/list/desired_dirs = straight_desired_directions[num2text(D.dir)] + if(!turf_contains_matching_disposal_pipe(turf_one, D.dir, desired_dirs[1]) || !turf_contains_matching_disposal_pipe(turf_two, D.dir, desired_dirs[2])) + log_bad("Following disposal pipe does not connect correctly: [log_info_line(D)]") + faulty_pipes += D + else + var/turf/turf_one = get_step(D.loc, D.dir) + var/turf/turf_two = get_step(D.loc, turn(D.dir, -90)) + + var/list/desired_dirs = curved_desired_directions[num2text(D.dir)] + var/main_dirs = desired_dirs[1] + var/rev_dirs = desired_dirs[2] + + if(!turf_contains_matching_disposal_pipe(turf_one, main_dirs[1], main_dirs[2]) || !turf_contains_matching_disposal_pipe(turf_two, rev_dirs[1], rev_dirs[2])) + log_bad("Following disposal pipe does not connect correctly: [log_info_line(D)]") + faulty_pipes += D + + if(faulty_pipes.len) + fail("[faulty_pipes.len] disposal segment\s did not connect with other disposal pipes.") + else + pass("All disposal segments connect with other disposal pipes.") + + return 1 + +/datum/unit_test/disposal_segments_shall_connect_with_other_disposal_pipes/proc/turf_contains_matching_disposal_pipe(var/turf/T, var/straight_dir, var/list/curved_dirs) + if(!T) + return FALSE + + // We need to loop over all potential pipes in a turf as long as there isn't a dir match, as they may be overlapping (i.e. 2 straight pipes in a cross) + for(var/obj/structure/disposalpipe/D in T) + if(D.type == /obj/structure/disposalpipe/segment) + if(D.icon_state == "pipe-s") + if(D.dir == straight_dir) + return TRUE + else + if(D.dir in curved_dirs) + return TRUE + else + return TRUE + return FALSE + +//======================================================================================= + +/datum/unit_test/simple_pipes_shall_not_face_north_or_west // The init code is worthless and cannot handle it + name = "MAP: Simple pipes shall not face north or west" + +/datum/unit_test/simple_pipes_shall_not_face_north_or_west/start_test() + var/failures = 0 + for(var/obj/machinery/atmospherics/pipe/simple/pipe in SSmachines.machinery) + if(!istype(pipe, /obj/machinery/atmospherics/pipe/simple/hidden) && !istype(pipe, /obj/machinery/atmospherics/pipe/simple/visible)) + continue + if(pipe.dir == NORTH || pipe.dir == WEST) + log_bad("Following pipe had an invalid direction: [log_info_line(pipe)]") + failures++ + + if(failures) + fail("[failures] simple pipe\s faced the wrong direction.") + else + pass("All simple pipes faced an appropriate direction.") + return 1 + +//======================================================================================= + +/datum/unit_test/shutoff_valves_shall_connect_to_two_different_pipe_networks + name = "MAP: Shutoff valves shall connect to two different pipe networks" + +/datum/unit_test/shutoff_valves_shall_connect_to_two_different_pipe_networks/start_test() + var/failures = 0 + for(var/obj/machinery/atmospherics/valve/shutoff/SV in SSmachines.machinery) + SV.close() + for(var/obj/machinery/atmospherics/valve/shutoff/SV in SSmachines.machinery) + if(SV.network_node1 == SV.network_node2) + log_bad("Following shutoff valve does not connect to two different pipe networks: [log_info_line(SV)]") + failures++ + + if(failures) + fail("[failures] shutoff valves did not connect to two different pipe networks.") + else + pass("All shutoff valves connect to two different pipe networks.") + return 1 + + +#undef SUCCESS +#undef FAILURE diff --git a/code/unit_tests/mob_tests.dm b/code/unit_tests/mob_tests.dm new file mode 100644 index 00000000..ddd10e46 --- /dev/null +++ b/code/unit_tests/mob_tests.dm @@ -0,0 +1,584 @@ + +/* + * + * Mob Unit Tests. + * + * Human suffocation in Space. + * Mob damage Template + * Species sprite options + * + */ + +#define SUCCESS 1 +#define FAILURE 0 + +// +// Tests Life() and mob breathing in space. +// + +datum/unit_test/human_breath + name = "MOB: Breathing Species Suffocate in Space" + var/list/test_subjects = list() + async = 1 + +datum/unit_test/human_breath/start_test() + var/turf/T = get_space_turf() + + if(!istype(T, /turf/space)) //If the above isn't a space turf then we force it to find one will most likely pick 1,1,1 + T = locate(/turf/space) + for(var/species_name in all_species) + var/datum/species/S = all_species[species_name] + var/mob/living/carbon/human/H = new(T, S.name) + if(H.need_breathe()) + var/species_organ = H.species.breathing_organ + var/obj/item/organ/internal/lungs/L + H.apply_effect(20, STUN, 0) + L = H.internal_organs_by_name[species_organ] + L.last_failed_breath = -INFINITY + test_subjects[S.name] = list(H, damage_check(H, OXY)) + return 1 + +datum/unit_test/human_breath/check_result() + for(var/i in test_subjects) + var/mob/living/carbon/human/H = test_subjects[i][1] + if(H.life_tick < 10) // Finish Condition + return 0 // Return 0 to try again later. + + var/failcount = 0 + for(var/i in test_subjects) + var/mob/living/carbon/human/H = test_subjects[i][1] + var/ending_oxyloss = damage_check(H, OXY) + var/starting_oxyloss = test_subjects[i][2] + if(starting_oxyloss >= ending_oxyloss) + failcount++ + log_debug("[H.species.name] is not taking oxygen damage, started with [starting_oxyloss] and ended with [ending_oxyloss] at place [log_info_line(H.loc)].") + + if(failcount) + fail("[failcount] breathing species mobs didn't suffocate in space.") + else + pass("All breathing species mobs suffocated in space.") + + return 1 // return 1 to show we're done and don't want to recheck the result. + +// ============================================================================ + +/var/default_mobloc = null + +proc/create_test_mob_with_mind(var/turf/mobloc = null, var/mobtype = /mob/living/carbon/human) + var/list/test_result = list("result" = FAILURE, "msg" = "", "mobref" = null) + + if(isnull(mobloc)) + if(!default_mobloc) + for(var/turf/simulated/floor/tiled/T in world) + var/pressure = T.zone.air.return_pressure() + if(90 < pressure && pressure < 120) // Find a turf between 90 and 120 + default_mobloc = T + break + mobloc = default_mobloc + if(!mobloc) + test_result["msg"] = "Unable to find a location to create test mob" + return test_result + + var/mob/living/carbon/human/H = new mobtype(mobloc) + + H.mind_initialize("TestKey[rand(0,10000)]") + + test_result["result"] = SUCCESS + test_result["msg"] = "Mob created" + test_result["mobref"] = "\ref[H]" + + return test_result + +//Generic Check +// TODO: Need to make sure I didn't just recreate the wheel here. + +proc/damage_check(var/mob/living/M, var/damage_type) + var/loss = null + + switch(damage_type) + if(BRUTE) + loss = M.getBruteLoss() + if(BURN) + loss = M.getFireLoss() + if(TOX) + loss = M.getToxLoss() + if(OXY) + loss = M.getOxyLoss() + if(istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/internal/lungs/L = H.internal_organs_by_name["lungs"] + if(L) + loss = L.oxygen_deprivation + if(CLONE) + loss = M.getCloneLoss() + if(PAIN) + loss = M.getHalLoss() + + if(!loss && istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M // Synthetics have robot limbs which don't report damage to getXXXLoss() + if(H.isSynthetic()) // So we have to hard code this check or create a different one for them. + return H.species.total_health - H.health + return loss + +// ============================================================================================================== + +// +//DAMAGE EXPECTATIONS +// used with expectected_vunerability + +#define STANDARD 0 // Will take standard damage (damage_ratio of 1) +#define ARMORED 1 // Will take less damage than applied +#define EXTRA_VULNERABLE 2 // Will take more dmage than applied +#define IMMUNE 3 // Will take no damage + +//============================================================================================================== + + +datum/unit_test/mob_damage + name = "MOB: Template for mob damage" + var/mob/living/carbon/human/testmob = null + var/damagetype = BRUTE + var/mob_type = /mob/living/carbon/human + var/expected_vulnerability = STANDARD + var/check_health = 0 + var/damage_location = BP_CHEST + +datum/unit_test/mob_damage/start_test() + var/list/test = create_test_mob_with_mind(null, mob_type) + var/damage_amount = 5 // Do not raise, if damage >= 10 there is a % chance to reduce damage by half in /obj/item/organ/external/take_damage() + // Which makes checks impossible. + + if(isnull(test)) + fail("Check Runtimed in Mob creation") + + if(test["result"] == FAILURE) + fail(test["msg"]) + return 0 + + var/mob/living/carbon/human/H = locate(test["mobref"]) + + if(isnull(H)) + fail("Test unable to set test mob from reference") + return 0 + + if(H.stat) + + fail("Test needs to be re-written, mob has a stat = [H.stat]") + return 0 + + if(H.sleeping) + fail("Test needs to be re-written, mob is sleeping for some unknown reason") + return 0 + + // Damage the mob + + var/initial_health = H.health + + if(damagetype == OXY && H.need_breathe()) + var/species_organ = H.species.breathing_organ + var/obj/item/organ/internal/lungs/L + if(species_organ) + L = H.internal_organs_by_name[species_organ] + if(L) + L.last_failed_breath = -INFINITY + + H.apply_damage(damage_amount, damagetype, damage_location) + + var/ending_damage = damage_check(H, damagetype) + + var/ending_health = H.health + + // Now test this stuff. + + var/failure = 0 + + var/damage_ratio = STANDARD + + if (ending_damage == 0) + damage_ratio = IMMUNE + + else if (ending_damage < damage_amount) + damage_ratio = ARMORED + + else if (ending_damage > damage_amount) + damage_ratio = EXTRA_VULNERABLE + + if(damage_ratio != expected_vulnerability) + failure = 1 + + // Now generate the message for this test. + + var/expected_msg = null + + switch(expected_vulnerability) + if(STANDARD) + expected_msg = "to take standard damage" + if(ARMORED) + expected_msg = "To take less damage" + if(EXTRA_VULNERABLE) + expected_msg = "To take extra damage" + if(IMMUNE) + expected_msg = "To take no damage" + + + var/msg = "Damage taken: [ending_damage] out of [damage_amount] || expected: [expected_msg] \[Overall Health:[ending_health] (Initial: [initial_health]\]" + + if(failure) + fail(msg) + else + pass(msg) + + return 1 + +// ================================================================= +// Human damage check. +// ================================================================= + +datum/unit_test/mob_damage/brute + name = "MOB: Human Brute damage check" + damagetype = BRUTE + +datum/unit_test/mob_damage/fire + name = "MOB: Human Fire damage check" + damagetype = BURN + +datum/unit_test/mob_damage/tox + name = "MOB: Human Toxin damage check" + damagetype = TOX + +datum/unit_test/mob_damage/oxy + name = "MOB: Human Oxygen damage check" + damagetype = OXY + +datum/unit_test/mob_damage/clone + name = "MOB: Human Clone damage check" + damagetype = CLONE + +datum/unit_test/mob_damage/halloss + name = "MOB: Human Halloss damage check" + damagetype = PAIN + +// ================================================================= +// Unathi +// ================================================================= + +datum/unit_test/mob_damage/unathi + name = "MOB: Unathi damage check template" + mob_type = /mob/living/carbon/human/unathi + +datum/unit_test/mob_damage/unathi/brute + name = "MOB: Unathi Brute Damage Check" + damagetype = BRUTE + expected_vulnerability = ARMORED + +datum/unit_test/mob_damage/unathi/fire + name = "MOB: Unathi Fire Damage Check" + damagetype = BURN + +datum/unit_test/mob_damage/unathi/tox + name = "MOB: Unathi Toxins Damage Check" + damagetype = TOX + +datum/unit_test/mob_damage/unathi/oxy + name = "MOB: Unathi Oxygen Damage Check" + damagetype = OXY + +datum/unit_test/mob_damage/unathi/clone + name = "MOB: Unathi Clone Damage Check" + damagetype = CLONE + +datum/unit_test/mob_damage/unathi/halloss + name = "MOB: Unathi Halloss Damage Check" + damagetype = PAIN + +// ================================================================= +// SpessKahjit aka Tajaran +// ================================================================= + +datum/unit_test/mob_damage/tajaran + name = "MOB: Tajaran damage check template" + mob_type = /mob/living/carbon/human/tajaran + +datum/unit_test/mob_damage/tajaran/brute + name = "MOB: Tajaran Brute Damage Check" + damagetype = BRUTE + expected_vulnerability = EXTRA_VULNERABLE + +datum/unit_test/mob_damage/tajaran/fire + name = "MOB: Tajaran Fire Damage Check" + damagetype = BURN + expected_vulnerability = EXTRA_VULNERABLE + +datum/unit_test/mob_damage/tajaran/tox + name = "MOB: Tajaran Toxins Damage Check" + damagetype = TOX + +datum/unit_test/mob_damage/tajaran/oxy + name = "MOB: Tajaran Oxygen Damage Check" + damagetype = OXY + +datum/unit_test/mob_damage/tajaran/clone + name = "MOB: Tajaran Clone Damage Check" + damagetype = CLONE + +datum/unit_test/mob_damage/tajaran/halloss + name = "MOB: Tajaran Halloss Damage Check" + damagetype = PAIN + +// ================================================================= +// Skrell +// ================================================================= + +datum/unit_test/mob_damage/skrell + name = "MOB: Skrell damage check template" + mob_type = /mob/living/carbon/human/skrell + +datum/unit_test/mob_damage/skrell/brute + name = "MOB: Skrell Brute Damage Check" + damagetype = BRUTE + +datum/unit_test/mob_damage/skrell/fire + name = "MOB: Skrell Fire Damage Check" + damagetype = BURN + +datum/unit_test/mob_damage/skrell/tox + name = "MOB: Skrell Toxins Damage Check" + damagetype = TOX + +datum/unit_test/mob_damage/skrell/oxy + name = "MOB: Skrell Oxygen Damage Check" + damagetype = OXY + +datum/unit_test/mob_damage/skrell/clone + name = "MOB: Skrell Clone Damage Check" + damagetype = CLONE + +datum/unit_test/mob_damage/skrell/halloss + name = "MOB: Skrell Halloss Damage Check" + damagetype = PAIN + +// ================================================================= +// Vox +// ================================================================= + +datum/unit_test/mob_damage/vox + name = "MOB: Vox damage check template" + mob_type = /mob/living/carbon/human/vox + +datum/unit_test/mob_damage/vox/brute + name = "MOB: Vox Brute Damage Check" + damagetype = BRUTE + +datum/unit_test/mob_damage/vox/fire + name = "MOB: Vox Fire Damage Check" + damagetype = BURN + +datum/unit_test/mob_damage/vox/tox + name = "MOB: Vox Toxins Damage Check" + damagetype = TOX + +datum/unit_test/mob_damage/vox/oxy + name = "MOB: Vox Oxygen Damage Check" + damagetype = OXY + +datum/unit_test/mob_damage/vox/clone + name = "MOB: Vox Clone Damage Check" + damagetype = CLONE + expected_vulnerability = IMMUNE + + +datum/unit_test/mob_damage/vox/halloss + name = "MOB: Vox Halloss Damage Check" + damagetype = PAIN + +// ================================================================= +// Diona +// ================================================================= + +datum/unit_test/mob_damage/diona + name = "MOB: Diona damage check template" + mob_type = /mob/living/carbon/human/diona + +datum/unit_test/mob_damage/diona/brute + name = "MOB: Diona Brute Damage Check" + damagetype = BRUTE + +datum/unit_test/mob_damage/diona/fire + name = "MOB: Diona Fire Damage Check" + damagetype = BURN + +datum/unit_test/mob_damage/diona/tox + name = "MOB: Diona Toxins Damage Check" + damagetype = TOX + +datum/unit_test/mob_damage/diona/oxy + name = "MOB: Diona Oxygen Damage Check" + damagetype = OXY + expected_vulnerability = IMMUNE + +datum/unit_test/mob_damage/diona/clone + name = "MOB: Diona Clone Damage Check" + damagetype = CLONE + expected_vulnerability = IMMUNE + +datum/unit_test/mob_damage/diona/halloss + name = "MOB: Diona Halloss Damage Check" + damagetype = PAIN + expected_vulnerability = IMMUNE + +// ================================================================= +// Nabbers +// ================================================================= + +datum/unit_test/mob_damage/nabber + name = "MOB: GAS damage check template" + mob_type = /mob/living/carbon/human/nabber + +datum/unit_test/mob_damage/nabber/brute + name = "MOB: GAS Brute Damage Check" + damagetype = BRUTE + expected_vulnerability = ARMORED + +datum/unit_test/mob_damage/nabber/fire + name = "MOB: GAS Fire Damage Check" + damagetype = BURN + expected_vulnerability = EXTRA_VULNERABLE + +datum/unit_test/mob_damage/nabber/tox + name = "MOB: GAS Toxins Damage Check" + damagetype = TOX + +datum/unit_test/mob_damage/nabber/oxy + name = "MOB: GAS Oxygen Damage Check" + damagetype = OXY + expected_vulnerability = ARMORED + +datum/unit_test/mob_damage/nabber/clone + name = "MOB: GAS Clone Damage Check" + damagetype = CLONE + +datum/unit_test/mob_damage/nabber/halloss + name = "MOB: GAS Halloss Damage Check" + damagetype = PAIN + +// ================================================================= +// SPECIAL WHITTLE SNOWFLAKES aka IPC +// ================================================================= + +datum/unit_test/mob_damage/machine + name = "MOB: IPC damage check template" + mob_type = /mob/living/carbon/human/machine + +datum/unit_test/mob_damage/machine/brute + name = "MOB: IPC Brute Damage Check" + damagetype = BRUTE + +datum/unit_test/mob_damage/machine/fire + name = "MOB: IPC Fire Damage Check" + damagetype = BURN + +datum/unit_test/mob_damage/machine/tox + name = "MOB: IPC Toxins Damage Check" + damagetype = TOX + expected_vulnerability = IMMUNE + +datum/unit_test/mob_damage/machine/oxy + name = "MOB: IPC Oxygen Damage Check" + damagetype = OXY + expected_vulnerability = IMMUNE + +datum/unit_test/mob_damage/machine/clone + name = "MOB: IPC Clone Damage Check" + damagetype = CLONE + expected_vulnerability = IMMUNE + +datum/unit_test/mob_damage/machine/halloss + name = "MOB: IPC Halloss Damage Check" + damagetype = PAIN + expected_vulnerability = IMMUNE + + +// ============================================================================== + + +datum/unit_test/robot_module_icons + name = "MOB: Robot module icon check" + var/icon_file = 'icons/mob/screen1_robot.dmi' + +datum/unit_test/robot_module_icons/start_test() + var/failed = 0 + if(!isicon(icon_file)) + fail("[icon_file] is not a valid icon file.") + return 1 + + var/list/valid_states = icon_states(icon_file) + + if(!valid_states.len) + return 1 + + for(var/i=1, i<=robot_modules.len, i++) + var/bad_msg = "[ascii_red]--------------- [robot_modules[i]]" + if(!(lowertext(robot_modules[i]) in valid_states)) + log_unit_test("[bad_msg] does not contain a valid icon state in [icon_file][ascii_reset]") + failed=1 + + if(failed) + fail("Some icon states did not exist") + else + pass("All modules had valid icon states") + + return 1 + +#undef VULNERABLE +#undef IMMUNE +#undef SUCCESS +#undef FAILURE + +datum/unit_test/species_base_skin + name = "MOB: Species base skin presence" +// async = 1 + var/failcount = 0 + +datum/unit_test/species_base_skin/start_test() + for(var/species_name in all_species) + var/datum/species/S = all_species[species_name] + if(S.base_skin_colours) + if(!(S.appearance_flags & HAS_BASE_SKIN_COLOURS)) + log_unit_test("[S.name] has a skin colour list but no HAS_BASE_SKIN_COLOURS flag.") + failcount++ + continue + if(!(S.base_skin_colours.len >= 2)) + log_unit_test("[S.name] needs at least two items in the base_skin_colour list.") + failcount++ + continue + var/to_fail = FALSE + for(var/tag in S.has_limbs) + var/list/paths = S.has_limbs[tag] + var/obj/item/organ/external/E = paths["path"] + var/list/gender_test = list("") + if(initial(E.gendered_icon)) + gender_test = list("_m", "_f") + var/icon_name = initial(E.icon_name) + + for(var/base in S.base_skin_colours) + for(var/gen in gender_test) + if(!("[icon_name][gen][S.base_skin_colours[base]]" in icon_states(S.icobase))) + to_fail = TRUE + log_debug("[S.name] has missing icon: [icon_name][gen][S.base_skin_colours[base]] for base [base] and limb tag [tag].") + if(to_fail) + log_unit_test("[S.name] is missing one or more base icons.") + failcount++ + continue + + else if(S.appearance_flags & HAS_BASE_SKIN_COLOURS) + log_unit_test("[S.name] has a HAS_BASE_SKIN_COLOURS flag but no skin colour list.") + failcount++ + continue + + if(failcount) + fail("[failcount] species had bad base skin colour.") + else + pass("All species had correct skin colour setups.") + + return 1 // return 1 to show we're done and don't want to recheck the result. + diff --git a/code/unit_tests/movement_tests.dm b/code/unit_tests/movement_tests.dm new file mode 100644 index 00000000..47cc02b6 --- /dev/null +++ b/code/unit_tests/movement_tests.dm @@ -0,0 +1,63 @@ +/datum/unit_test/movement + name = "MOVEMENT template" + async = 0 + +/datum/unit_test/movement/force_move_shall_trigger_crossed_when_entering_turf + name = "MOVEMENT - Force Move Shall Trigger Crossed When Entering Turf" + +/datum/unit_test/movement/force_move_shall_trigger_crossed_when_entering_turf/start_test() + var/turf/start = get_safe_turf() + var/turf/target = get_step(start, NORTH) + + var/obj/mover = new /obj/test(start, 1) + var/obj/test/crossed_obj/crossed = new(target, 1) + + mover.forceMove(target) + + if(!crossed.crossers) + fail("The target object was never crossed.") + else if(crossed.crossers.len != 1) + fail("The target object was crossed [crossed.crossers.len] times, expected 1.") + else + pass("The target was crossed 1 time.") + + qdel(target) + qdel(crossed) + return TRUE + +/datum/unit_test/movement/force_move_shall_trigger_entered + name = "MOVEMENT - Force Move Shall Trigger Entered" + +/datum/unit_test/movement/force_move_shall_trigger_entered/start_test() + var/turf/start = get_safe_turf() + var/obj/mover = new /obj/test(start, 1) + var/obj/test/entered_obj/target = new(start, 1) + + mover.forceMove(target) + + if(!target.enterers) + fail("The target object was never entered.") + else if(target.enterers.len != 1) + fail("The target object was entered [target.enterers.len] times, expected 1.") + else + pass("The target was entered 1 time.") + + qdel(mover) + qdel(target) + return TRUE + +/obj/test/crossed_obj + var/list/crossers + +/obj/test/crossed_obj/Crossed(var/crosser) + if(!crossers) + crossers = list() + crossers += crosser + +/obj/test/entered_obj + var/list/enterers + +/obj/test/entered_obj/Entered(var/enterer) + if(!enterers) + enterers = list() + enterers += enterer diff --git a/code/unit_tests/observation_tests.dm b/code/unit_tests/observation_tests.dm new file mode 100644 index 00000000..63c66500 --- /dev/null +++ b/code/unit_tests/observation_tests.dm @@ -0,0 +1,347 @@ +/proc/is_listening_to_movement(var/atom/movable/listening_to, var/listener) + return GLOB.moved_event.is_listening(listening_to, listener) + +/datum/unit_test/observation + name = "OBSERVATION template" + async = 0 + var/list/received_moves + + var/list/stored_global_listen_count + var/list/stored_event_sources_count + var/list/stored_event_listen_count + +/datum/unit_test/observation/start_test() + if(!received_moves) + received_moves = list() + received_moves.Cut() + + for(var/global_listener in GLOB.moved_event.global_listeners) + GLOB.moved_event.unregister_global(global_listener) + + stored_global_listen_count = GLOB.global_listen_count.Copy() + stored_event_sources_count = GLOB.event_sources_count.Copy() + stored_event_listen_count = GLOB.event_listen_count.Copy() + + sanity_check_events("Pre-Test") + . = conduct_test() + sanity_check_events("Post-Test") + +/datum/unit_test/observation/proc/sanity_check_events(var/phase) + for(var/entry in GLOB.all_observable_events) + var/decl/observ/event = entry + if(null in event.global_listeners) + fail("[phase]: [event] - The global listeners list contains a null entry.") + + for(var/event_source in event.event_sources) + for(var/list/list_of_listeners in event.event_sources[event_source]) + if(isnull(list_of_listeners)) + fail("[phase]: [event] - The event source list contains a null entry.") + else if(!istype(list_of_listeners)) + fail("[phase]: [event] - The list of listeners was not of the expected type. Was [list_of_listeners.type].") + else + for(var/listener in list_of_listeners) + if(isnull(listener)) + fail("[phase]: [event] - The event source listener list contains a null entry.") + else + var/proc_calls = list_of_listeners[listener] + if(isnull(proc_calls)) + fail("[phase]: [event] - [listener] - The proc call list was null.") + else + for(var/proc_call in proc_calls) + if(isnull(proc_call)) + fail("[phase]: [event] - [listener]- The proc call list contains a null entry.") + + for(var/entry in (GLOB.global_listen_count - stored_global_listen_count)) + fail("[phase]: global_listen_count - Contained [log_info_line(entry)].") + for(var/entry in (GLOB.event_sources_count - stored_event_sources_count)) + fail("[phase]: event_sources_count - Contained [log_info_line(entry)].") + for(var/entry in (GLOB.event_listen_count - stored_event_listen_count)) + fail("[phase]: event_listen_count - Contained [log_info_line(entry)].") + +/datum/unit_test/observation/proc/conduct_test() + return 0 + +/datum/unit_test/observation/proc/receive_move(var/atom/movable/am, var/old_loc, var/new_loc) + received_moves[++received_moves.len] = list(am, old_loc, new_loc) + +/datum/unit_test/observation/proc/dump_received_moves() + for(var/entry in received_moves) + var/list/l = entry + log_unit_test("[l[1]] - [l[2]] - [l[3]]") + +/datum/unit_test/observation/global_listeners_shall_receive_events + name = "OBSERVATION: Global listeners shall receive events" + +/datum/unit_test/observation/global_listeners_shall_receive_events/conduct_test() + var/turf/start = get_safe_turf() + var/turf/target = get_step(start, NORTH) + var/obj/O = get_named_instance(/obj, start) + + GLOB.moved_event.register_global(src, /datum/unit_test/observation/proc/receive_move) + O.forceMove(target) + + if(received_moves.len != 1) + fail("Expected 1 raised moved event, were [received_moves.len].") + dump_received_moves() + return 1 + + var/list/event = received_moves[1] + if(event[1] != O || event[2] != start || event[3] != target) + fail("Unepected move event received. Expected [O], was [event[1]]. Expected [start], was [event[2]]. Expected [target], was [event[3]]") + else + pass("Received the expected move event.") + + GLOB.moved_event.unregister_global(src) + qdel(O) + return 1 + +/datum/unit_test/observation/moved_observer_shall_register_on_follow + name = "OBSERVATION: Moved - Observer Shall Register on Follow" + +/datum/unit_test/observation/moved_observer_shall_register_on_follow/conduct_test() + var/turf/T = get_safe_turf() + var/mob/living/carbon/human/H = get_named_instance(/mob/living/carbon/human, T, SPECIES_HUMAN) + var/mob/observer/ghost/O = get_named_instance(/mob/observer/ghost, T, "Ghost") + + O.ManualFollow(H) + if(is_listening_to_movement(H, O)) + pass("The observer is now following the mob.") + else + fail("The observer is not following the mob.") + + qdel(H) + qdel(O) + return 1 + +/datum/unit_test/observation/moved_observer_shall_unregister_on_nofollow + name = "OBSERVATION: Moved - Observer Shall Unregister on NoFollow" + +/datum/unit_test/observation/moved_observer_shall_unregister_on_nofollow/conduct_test() + var/turf/T = get_safe_turf() + var/mob/living/carbon/human/H = get_named_instance(/mob/living/carbon/human, T, SPECIES_HUMAN) + var/mob/observer/ghost/O = get_named_instance(/mob/observer/ghost, T, "Ghost") + + O.ManualFollow(H) + O.stop_following() + if(!is_listening_to_movement(H, O)) + pass("The observer is no longer following the mob.") + else + fail("The observer is still following the mob.") + + qdel(H) + qdel(O) + return 1 + +/datum/unit_test/observation/moved_shall_not_register_on_enter_without_listeners + name = "OBSERVATION: Moved - Shall Not Register on Enter Without Listeners" + +/datum/unit_test/observation/moved_shall_not_register_on_enter_without_listeners/conduct_test() + var/turf/T = get_safe_turf() + var/mob/living/carbon/human/H = get_named_instance(/mob/living/carbon/human, T, SPECIES_HUMAN) + qdel(H.virtual_mob) + H.virtual_mob = null + + var/obj/structure/closet/C = get_named_instance(/obj/structure/closet, T, "Closet") + + H.forceMove(C) + if(!is_listening_to_movement(C, H)) + pass("The mob did not register to the closet's moved event.") + else + fail("The mob has registered to the closet's moved event.") + + qdel(C) + qdel(H) + return 1 + +/datum/unit_test/observation/moved_shall_register_recursively_on_new_listener + name = "OBSERVATION: Moved - Shall Register Recursively on New Listener" + +/datum/unit_test/observation/moved_shall_register_recursively_on_new_listener/conduct_test() + var/turf/T = get_safe_turf() + var/mob/living/carbon/human/H = get_named_instance(/mob/living/carbon/human, T, SPECIES_HUMAN) + var/obj/structure/closet/C = get_named_instance(/obj/structure/closet, T, "Closet") + var/mob/observer/ghost/O = get_named_instance(/mob/observer/ghost, T, "Ghost") + + H.forceMove(C) + O.ManualFollow(H) + var/listening_to_closet = is_listening_to_movement(C, H) + var/listening_to_human = is_listening_to_movement(H, O) + if(listening_to_closet && listening_to_human) + pass("Recursive moved registration succesful.") + else + fail("Recursive moved registration failed. Human listening to closet: [listening_to_closet] - Observer listening to human: [listening_to_human]") + + qdel(C) + qdel(H) + qdel(O) + return 1 + +/datum/unit_test/observation/moved_shall_register_recursively_with_existing_listener + name = "OBSERVATION: Moved - Shall Register Recursively with Existing Listener" + +/datum/unit_test/observation/moved_shall_register_recursively_with_existing_listener/conduct_test() + var/turf/T = get_safe_turf() + var/mob/living/carbon/human/H = get_named_instance(/mob/living/carbon/human, T, SPECIES_HUMAN) + var/obj/structure/closet/C = get_named_instance(/obj/structure/closet, T, "Closet") + var/mob/observer/ghost/O = get_named_instance(/mob/observer/ghost, T, "Ghost") + + O.ManualFollow(H) + H.forceMove(C) + var/listening_to_closet = is_listening_to_movement(C, H) + var/listening_to_human = is_listening_to_movement(H, O) + if(listening_to_closet && listening_to_human) + pass("Recursive moved registration succesful.") + else + fail("Recursive moved registration failed. Human listening to closet: [listening_to_closet] - Observer listening to human: [listening_to_human]") + + qdel(C) + qdel(H) + qdel(O) + + return 1 + +/datum/unit_test/observation/moved_shall_only_trigger_for_recursive_drop + name = "OBSERVATION: Moved - Shall Only Trigger Once For Recursive Drop" + +/datum/unit_test/observation/moved_shall_only_trigger_for_recursive_drop/conduct_test() + var/turf/T = get_safe_turf() + var/obj/mecha/mech = get_named_instance(/obj/mecha, T, "Mech") + var/obj/item/weapon/wrench/held_item = get_named_instance(/obj/item/weapon/wrench, T, "Wrench") + var/mob/living/carbon/human/dummy/held_mob = get_named_instance(/mob/living/carbon/human/dummy, T, "Held Mob") + var/mob/living/carbon/human/dummy/holding_mob = get_named_instance(/mob/living/carbon/human/dummy, T, "Holding Mob") + + held_mob.mob_size = MOB_SMALL + held_mob.put_in_active_hand(held_item) + held_mob.get_scooped(holding_mob) + + holding_mob.forceMove(mech) + + mech.occupant = holding_mob + + GLOB.moved_event.register(held_item, src, /datum/unit_test/observation/proc/receive_move) + holding_mob.drop_from_inventory(held_item) + + if(received_moves.len != 1) + fail("Expected 1 raised moved event, were [received_moves.len].") + dump_received_moves() + return 1 + + var/list/event = received_moves[1] + if(event[1] != held_item || event[2] != held_mob || event[3] != mech) + fail("Unexpected move event received. Expected [held_item], was [event[1]]. Expected [held_mob], was [event[2]]. Expected [mech], was [event[3]]") + else if(!(held_item in mech.dropped_items)) + fail("Expected \the [held_item] to be in the mechs' dropped item list") + else + pass("One one moved event with expected arguments raised.") + + GLOB.moved_event.unregister(held_item, src) + qdel(mech) + qdel(held_item) + qdel(held_mob) + qdel(holding_mob) + + return 1 + +/datum/unit_test/observation/moved_shall_not_unregister_recursively_one + name = "OBSERVATION: Moved - Shall Not Unregister Recursively - One" + +/datum/unit_test/observation/moved_shall_not_unregister_recursively_one/conduct_test() + var/turf/T = get_safe_turf() + var/mob/observer/ghost/one = get_named_instance(/mob/observer/ghost, T, "Ghost One") + var/mob/observer/ghost/two = get_named_instance(/mob/observer/ghost, T, "Ghost Two") + var/mob/observer/ghost/three = get_named_instance(/mob/observer/ghost, T, "Ghost Three") + + two.ManualFollow(one) + three.ManualFollow(two) + + two.stop_following() + if(is_listening_to_movement(two, three)) + pass("Observer three is still following observer two.") + else + fail("Observer three is no longer following observer two.") + + qdel(one) + qdel(two) + qdel(three) + + return 1 + +/datum/unit_test/observation/moved_shall_not_unregister_recursively_two + name = "OBSERVATION: Moved - Shall Not Unregister Recursively - Two" + +/datum/unit_test/observation/moved_shall_not_unregister_recursively_two/conduct_test() + var/turf/T = get_safe_turf() + var/mob/observer/ghost/one = get_named_instance(/mob/observer/ghost, T, "Ghost One") + var/mob/observer/ghost/two = get_named_instance(/mob/observer/ghost, T, "Ghost Two") + var/mob/observer/ghost/three = get_named_instance(/mob/observer/ghost, T, "Ghost Three") + + two.ManualFollow(one) + three.ManualFollow(two) + + three.stop_following() + if(is_listening_to_movement(one, two)) + pass("Observer two is still following observer one.") + else + fail("Observer two is no longer following observer one.") + + qdel(one) + qdel(two) + qdel(three) + + return 1 + +/datum/unit_test/observation/sanity_global_listeners_shall_not_leave_null_entries_when_destroyed + name = "OBSERVATION: Sanity - Global listeners shall not leave null entries when destroyed" + +/datum/unit_test/observation/sanity_global_listeners_shall_not_leave_null_entries_when_destroyed/conduct_test() + var/turf/T = get_safe_turf() + var/obj/O = get_named_instance(/obj, T) + + GLOB.moved_event.register_global(O, /atom/movable/proc/move_to_turf) + qdel(O) + + if(null in GLOB.moved_event.global_listeners) + fail("The global listener list contains a null entry.") + else + pass("The global listener list does not contain a null entry.") + + return 1 + +/datum/unit_test/observation/sanity_event_sources_shall_not_leave_null_entries_when_destroyed + name = "OBSERVATION: Sanity - Event sources shall not leave null entries when destroyed" + +/datum/unit_test/observation/sanity_event_sources_shall_not_leave_null_entries_when_destroyed/conduct_test() + var/turf/T = get_safe_turf() + var/mob/event_source = get_named_instance(/mob, T, "Event Source") + var/mob/listener = get_named_instance(/mob, T, "Event Listener") + + GLOB.moved_event.register(event_source, listener, /atom/movable/proc/recursive_move) + qdel(event_source) + + if(null in GLOB.moved_event.event_sources) + fail("The event source list contains a null entry.") + else + pass("The event source list does not contain a null entry.") + + qdel(listener) + return 1 + +/datum/unit_test/observation/sanity_event_listeners_shall_not_leave_null_entries_when_destroyed + name = "OBSERVATION: Sanity - Event listeners shall not leave null entries when destroyed" + +/datum/unit_test/observation/sanity_event_listeners_shall_not_leave_null_entries_when_destroyed/conduct_test() + var/turf/T = get_safe_turf() + var/mob/event_source = get_named_instance(/mob, T, "Event Source") + var/mob/listener = get_named_instance(/mob, T, "Event Listener") + + GLOB.moved_event.register(event_source, listener, /atom/movable/proc/recursive_move) + qdel(listener) + + var/listeners = GLOB.moved_event.event_sources[event_source] + if(listeners && (null in listeners)) + fail("The event source listener list contains a null entry.") + else + pass("The event source listener list does not contain a null entry.") + + qdel(event_source) + return 1 diff --git a/code/unit_tests/organ_tests.dm b/code/unit_tests/organ_tests.dm new file mode 100644 index 00000000..53cb4fc3 --- /dev/null +++ b/code/unit_tests/organ_tests.dm @@ -0,0 +1,234 @@ +// ============================================================================== + +datum/unit_test/species_organ_creation + name = "ORGAN: Species Organs are Created Correctly" + +datum/unit_test/species_organ_creation/proc/check_internal_organs(var/mob/living/carbon/human/H, var/datum/species/species) + . = 1 + for(var/organ_tag in species.has_organ) + var/obj/item/organ/internal/I = H.internal_organs_by_name[organ_tag] + if(!istype(I)) + fail("[species.name] failed to register internal organ for tag \"[organ_tag]\" to internal_organs_by_name.") + . = 0 + continue + if(!(I in H.internal_organs)) + fail("[species.name] failed to register internal organ for tag \"[organ_tag]\" to internal_organs.") + . = 0 + continue + var/req_type = species.has_organ[organ_tag] + if(!istype(I, req_type)) + fail("[species.name] incorrect type of internal organ created for tag \"[organ_tag]\". Expected [req_type], found [I.type].") + . = 0 + continue + if(I.organ_tag != organ_tag) + fail("[species.name] internal organ tag mismatch. Registered as \"[organ_tag]\", actual tag was \"[I.organ_tag]\".") + . = 0 + +datum/unit_test/species_organ_creation/proc/check_external_organs(var/mob/living/carbon/human/H, var/datum/species/species) + . = 1 + for(var/organ_tag in species.has_limbs) + var/obj/item/organ/external/E = H.organs_by_name[organ_tag] + if(!istype(E)) + fail("[species.name] failed to register external organ for tag \"[organ_tag]\" to organs_by_name.") + . = 0 + continue + if(!(E in H.organs)) + fail("[species.name] failed to register external organ for tag \"[organ_tag]\" to organs.") + . = 0 + continue + var/list/organ_data = species.has_limbs[organ_tag] + var/req_type = organ_data["path"] + if(!istype(E, req_type)) + fail("[species.name] incorrect type of external organ created for tag \"[organ_tag]\". Expected [req_type], found [E.type].") + . = 0 + continue + if(E.organ_tag != organ_tag) + fail("[species.name] internal organ tag mismatch. Registered as \"[organ_tag]\", actual tag was \"[E.organ_tag]\".") + . = 0 + +datum/unit_test/species_organ_creation/proc/check_organ_parents(var/mob/living/carbon/human/H, var/datum/species/species) + . = 1 + for(var/obj/item/organ/external/E in H.organs) + if(!E.parent_organ) + continue + var/obj/item/organ/external/parent = H.organs_by_name[E.parent_organ] + if(!istype(parent)) + fail("[species.name] external organ [E] could not find its parent in organs_by_name. Parent tag was \"[E.parent_organ]\".") + . = 0 + continue + if(!(parent in H.organs)) + fail("[species.name] external organ [E] could not find its parent in organs. Parent was [parent](parent.type). Parent tag was \"[E.parent_organ]\".") + . = 0 + continue + if(E.parent != parent) + fail("[species.name] external organ [E] parent mismatch. Parent reference was [E.parent] with tag \"[E.parent? E.parent.organ_tag : "N/A"]\". Parent was [parent](parent.type). Parent tag was \"[E.parent_organ]\".") + . = 0 + continue + if(!(E in parent.children)) + fail("[species.name] external organ [E] was not found in parent's children. Parent was [parent]. Parent tag was \"[E.parent_organ]\".") + . = 0 + continue + + for(var/obj/item/organ/internal/I in H.organs) + if(!I.parent_organ) + fail("[species.name] internal organ [I] did not have a parent_organ tag.") + . = 0 + continue + var/obj/item/organ/external/parent = H.organs_by_name[I.parent_organ] + if(!istype(parent)) + fail("[species.name] internal organ [I] could not find its parent in organs_by_name. Parent tag was \"[I.parent_organ]\".") + . = 0 + continue + if(!(parent in H.organs)) + fail("[species.name] internal organ [I] could not find its parent in organs. Parent was [parent]. Parent tag was \"[I.parent_organ]\".") + . = 0 + continue + if(!(I in parent.internal_organs)) + fail("[species.name] internal organ [I] was not found in parent's internal_organs. Parent was [parent]. Parent tag was \"[I.parent_organ]\".") + . = 0 + continue + +datum/unit_test/species_organ_creation/start_test() + var/failcount = 0 + for(var/datum/species/species in all_species) + var/mob/living/carbon/human/test_subject = new(null, species.name) + + var/fail = 0 + fail |= !check_internal_organs(test_subject, species) + fail |= !check_external_organs(test_subject, species) + fail |= !check_organ_parents(test_subject, species) + + if(fail) failcount++ + + if(failcount) + fail("[failcount] species mobs were created with invalid organ configuration.") + else + pass("All species mobs were created with valid organ configuration.") + + return 1 + +datum/unit_test/species_organ_lists_update + name = "ORGAN: Species Mob Organ Lists Update when Organs are Removed and Replaced." + +datum/unit_test/species_organ_lists_update/proc/check_internal_organ_present(var/mob/living/carbon/human/H, var/obj/item/organ/internal/I) + if(!(I in H.internal_organs)) + fail("[H.species.name] internal organ [I] not in internal_organs.") + return 0 + var/found = H.internal_organs_by_name[I.organ_tag] + if(I != found) + fail("[H.species.name] internal organ [I] not in internal_organs_by_name. Organ tag was \"[I.organ_tag]\", found [found? found : "nothing"] instead.") + return 0 + var/obj/item/organ/external/parent = H.organs_by_name[I.parent_organ] + if(!istype(parent)) + fail("[H.species.name] internal organ [I] could not find its parent in organs_by_name. Parent tag was \"[I.parent_organ]\".") + return 0 + if(!(I in parent.internal_organs)) + fail("[H.species.name] internal organ [I] was not in parent's internal_organs. Parent was [parent]. Parent tag was \"[I.parent_organ]\".") + return 0 + return 1 + +datum/unit_test/species_organ_lists_update/proc/check_internal_organ_removed(var/mob/living/carbon/human/H, var/obj/item/organ/internal/I, var/obj/item/organ/external/old_parent) + if(I in H.internal_organs) + fail("[H.species.name] internal organ [I] was not removed from internal_organs.") + return 0 + var/found = H.internal_organs_by_name[I.organ_tag] + if(found) + fail("[H.species.name] internal organ [I] was not removed from internal_organs_by_name. Organ tag was \"[I.organ_tag]\".") + return 0 + if(I in old_parent.internal_organs) + fail("[H.species.name] internal organ [I] was not removed from parent's internal_organs. Parent was [old_parent].") + return 0 + return 1 + +datum/unit_test/species_organ_lists_update/proc/check_external_organ_present(var/mob/living/carbon/human/H, var/obj/item/organ/external/E) + if(!(E in H.organs)) + fail("[H.species.name] external organ [E] not in organs.") + return 0 + var/found = H.organs_by_name[E.organ_tag] + if(E != found) + fail("[H.species.name] external organ [E] not in organs_by_name. Organ tag was \"[E.organ_tag]\", found [found? found : "nothing"] instead.") + return 0 + if(E.parent_organ) + var/obj/item/organ/external/parent = E.parent + if(!istype(parent)) + fail("[H.species.name] external organ [E] had no parent. Parent tag was \"[E.parent_organ]\".") + return 0 + if(parent.organ_tag != E.parent_organ) + fail("[H.species.name] external organ [E] parent tag mismatch. Parent tag was \"[E.parent_organ]\", actual tag was \"[parent.organ_tag]\".") + return 0 + if(!(E in parent.children)) + fail("[H.species.name] external organ [E] was not in parent's children. Parent was [parent]. Parent tag was \"[E.parent_organ]\".") + return 0 + return 1 + +datum/unit_test/species_organ_lists_update/proc/check_external_organ_removed(var/mob/living/carbon/human/H, var/obj/item/organ/external/E, var/obj/item/organ/external/old_parent = null) + if(E in H.organs) + fail("[H.species.name] external organ [E] was not removed from organs.") + return 0 + var/found = H.organs_by_name[E.organ_tag] + if(found) + fail("[H.species.name] external organ [E] was not removed from organs_by_name. Organ tag was \"[E.organ_tag]\".") + return 0 + if(old_parent) + if(!(E in old_parent.children)) + fail("[H.species.name] external organ [E] was not removed from parent's children. Parent was [old_parent].") + return 0 + return 1 + +datum/unit_test/species_organ_lists_update/proc/test_internal_organ(var/mob/living/carbon/human/H, var/obj/item/organ/internal/I) + if(!check_internal_organ_present(H, I)) + fail("[H.species.name] internal organ [I] failed initial presence check.") + return 0 + + var/obj/item/organ/external/parent = H.organs_by_name[I.parent_organ] + + I.removed() + if(!check_internal_organ_removed(H, I, parent)) + fail("[H.species.name] internal organ [I] was not removed correctly.") + return 0 + + I.replaced(H, parent) + if(!check_internal_organ_present(H, I)) + fail("[H.species.name] internal organ [I] was not replaced correctly.") + return 0 + + return 1 + +datum/unit_test/species_organ_lists_update/proc/test_external_organ(var/mob/living/carbon/human/H, var/obj/item/organ/external/E) + if(!check_external_organ_removed(H, E)) + fail("[H.species.name] internal organ [E] failed initial presence check.") + return 0 + + var/obj/item/organ/external/parent = E.parent + + E.removed() + if(!check_internal_organ_removed(H, E, parent)) + fail("[H.species.name] internal organ [E] was not removed correctly.") + return 0 + + E.replaced(H) + if(!check_internal_organ_present(H, E)) + fail("[H.species.name] internal organ [E] was not replaced correctly.") + return 0 + + return 1 + +datum/unit_test/species_organ_lists_update/start_test() + var/failcount = 0 + for(var/datum/species/species in all_species) + var/mob/living/carbon/human/test_subject = new(null, species.name) + + for(var/O in test_subject.internal_organs) + if(!test_internal_organ(test_subject, O)) + failcount++ + + for(var/O in test_subject.organs) + if(!test_external_organ(test_subject, O)) + failcount++ + + if(failcount) + fail("[failcount] organs failed to be removed and replaced correctly.") + else + pass("All organs were removed and replaced correctly.") + + return 1 \ No newline at end of file diff --git a/code/unit_tests/override_tests.dm b/code/unit_tests/override_tests.dm new file mode 100644 index 00000000..ad0cd223 --- /dev/null +++ b/code/unit_tests/override_tests.dm @@ -0,0 +1,78 @@ +// These tests are intended to verify functionality of overrides in ~unit_test_overrides.dm + +/datum/unit_test/override + name = "OVERRIDE template" + +/datum/unit_test/override/obj_random_shall_spawn_heaviest_item + name = "OVERRIDE - obj/random shall spawn heaviest item" + +/datum/unit_test/override/obj_random_shall_spawn_heaviest_item/start_test() + GLOB.unit_test_last_obj_random_creation = null + var/obj/random/unit_test/R = new() + + if(GLOB.unit_test_last_obj_random_creation && GLOB.unit_test_last_obj_random_creation.type == /obj/unit_test_heavy) + pass("[log_info_line(R)] created an object of the expected type.") + else + if(GLOB.unit_test_last_obj_random_creation) + fail("[log_info_line(R)] did not create an object of the expected type. Expected /obj/unit_test_heavy, was [GLOB.unit_test_last_obj_random_creation.type]") + else + fail("[log_info_line(R)] did not create an object") + + return 1 + +/datum/unit_test/override/atom_creator_simple_shall_always_spawn + name = "OVERRIDE - /datum/atom_creator/simple shall always spawn" + +/datum/unit_test/override/atom_creator_simple_shall_always_spawn/start_test() + var/datum/atom_creator/simple/S = new/datum/atom_creator/simple(/obj/unit_test_light, 1) + S.probability = 0 + + var/safe_turf = get_safe_turf() + S.create(safe_turf) + var/created_object = locate(/obj/unit_test_light) in safe_turf + if(created_object) + pass("[log_info_line(S)] successfully created its object.") + qdel(created_object) + else + fail("[log_info_line(S)] failed to create its object.") + + return 1 + +/datum/unit_test/override/atom_creator_weighted_shall_spawn_heaviest + name = "OVERRIDE - /datum/atom_creator/weighted shall spawn heaviest" + +/datum/unit_test/override/atom_creator_weighted_shall_spawn_heaviest/start_test() + var/datum/atom_creator/weighted/W = new/datum/atom_creator/weighted(list(/obj/unit_test_light = 9001, /obj/unit_test_heavy = 1)) + + var/safe_turf = get_safe_turf() + W.create(safe_turf) + var/created_object = locate(/obj/unit_test_heavy) in safe_turf + if(created_object) + pass("[log_info_line(W)] successfully created the heaviest object.") + qdel(created_object) + else + fail("[log_info_line(W)] failed to create its heaviest object.") + + return 1 + +/datum/unit_test/override/atom_creator_weighted_shall_spawn_heaviest_recursive + name = "OVERRIDE - /datum/atom_creator/weighted shall spawn heaviest - Recursive" + +/datum/unit_test/override/atom_creator_weighted_shall_spawn_heaviest_recursive/start_test() + var/datum/atom_creator/weighted/W = new/datum/atom_creator/weighted( + list( + new/datum/atom_creator/weighted(list(/obj/unit_test_light = 9001, /obj/unit_test_heavy = 1)), + new/datum/atom_creator/simple(/obj/unit_test_medium, 50) + ) + ) + + var/safe_turf = get_safe_turf() + W.create(safe_turf) + var/created_object = locate(/obj/unit_test_heavy) in safe_turf + if(created_object) + pass("[log_info_line(W)] successfully created the heaviest object.") + qdel(created_object) + else + fail("[log_info_line(W)] failed to create its heaviest object.") + + return 1 diff --git a/code/unit_tests/power_tests.dm b/code/unit_tests/power_tests.dm new file mode 100644 index 00000000..e81c449b --- /dev/null +++ b/code/unit_tests/power_tests.dm @@ -0,0 +1,71 @@ +datum/unit_test/roundstart_cable_connectivity + name = "POWER: Roundstart Cables that are Connected Share Powernets" + +datum/unit_test/roundstart_cable_connectivity/proc/find_connected_neighbours(var/obj/structure/cable/C) + . = list() + if(C.d1 != 0) + . += get_connected_neighbours(C, C.d1) + if(C.d2 != 0) + . += get_connected_neighbours(C, C.d2) + +datum/unit_test/roundstart_cable_connectivity/proc/get_connected_neighbours(var/obj/structure/cable/self, var/dir) + var/turf/T = get_step(get_turf(self), dir) + var/reverse = GLOB.reverse_dir[dir] + + . = list() //can have multiple connected neighbours for a dir, e.g. Y-junctions + for(var/obj/structure/cable/other in T) + if(other.d1 == reverse || other.d2 == reverse) + . += other + +datum/unit_test/roundstart_cable_connectivity/start_test() + var/failed = 0 + var/list/found_cables = list() + + //there is a cable list, but for testing purposes we search every cable in the world + for(var/obj/structure/cable/C in world) + if(C in found_cables) + continue + var/list/to_search = list(C) + var/list/searched = list() + while(to_search.len) + var/obj/structure/cable/next = to_search[to_search.len] + to_search.len-- + searched += next + for(var/obj/structure/cable/other in get_connected_neighbours(next)) + if(other in searched) + continue + if(next.powernet != other.powernet) + fail("Cable at ([next.x], [next.y], [next.z]) did not share powernet with connected neighbour at ([other.x], [other.y], [other.z])") + failed++ + to_search += other + + found_cables += searched + + if(failed) + fail("Found [failed] bad cables.") + else + pass("All connected roundstart cables have matching powernets.") + + return 1 + + +/datum/unit_test/areas_apc_uniqueness + name = "POWER: Each area should have at most one APC." + +/datum/unit_test/areas_apc_uniqueness/start_test() + var/failure = "" + for(var/area/A in world) + var/obj/machinery/power/apc/found_apc = null + for(var/obj/machinery/power/apc/APC in A) + if(!found_apc) + found_apc = APC + continue + if(failure) + failure = "[failure]\n" + failure = "[failure]Duplicated APCs in area: [A.name]. #1: [log_info_line(found_apc)] #2: [log_info_line(APC)]" + + if(failure) + fail(failure) + else + pass("No areas with duplicated APCs have been found.") + return 1 \ No newline at end of file diff --git a/code/unit_tests/seed_tests.dm b/code/unit_tests/seed_tests.dm new file mode 100644 index 00000000..ccb8c3d0 --- /dev/null +++ b/code/unit_tests/seed_tests.dm @@ -0,0 +1,18 @@ +/datum/unit_test/seed_types_have_at_least_one_sprite + name = "SEED: Seed types should have at least one sprite" + +/datum/unit_test/seed_types_have_at_least_one_sprite/start_test() + var/any_failed = FALSE + + for (var/subtype in subtypesof(/datum/seed)) + var/datum/seed/S = new subtype() + var/sprite = S.get_trait(TRAIT_PLANT_ICON) + if(sprite && (!(sprite in plant_controller.plant_sprites))) + log_bad("[subtype] references nonexistent sprite [sprite].") + any_failed = TRUE + + if (any_failed) + fail("Some seed icons were missing.") + else + pass("All seed icons were found.") + return 1 diff --git a/code/unit_tests/shuttle_tests.dm b/code/unit_tests/shuttle_tests.dm new file mode 100644 index 00000000..e497da72 --- /dev/null +++ b/code/unit_tests/shuttle_tests.dm @@ -0,0 +1,128 @@ +/* +/datum/unit_test/shuttle + name = "SHUTTLE template" + async = 0 + +/datum/unit_test/shuttle/shuttles_shall_have_a_name + name = "SHUTTLE - Shuttles shall have a name" + +/datum/unit_test/shuttle/shuttles_shall_have_a_name/start_test() + var/failed_shuttles = 0 + for(var/datum/shuttle/shuttle in shuttle_controller.shuttles) + if(!shuttle.name) + failed_shuttles++ + + if(failed_shuttles) + fail("[failed_shuttles] nameless shuttle\s") + else + pass("All shuttles are named.") + return 1 + +/datum/unit_test/shuttle/shuttles_shall_use_mapped_areas + name = "SHUTTLE - Shuttles shall use mapped areas" + +/datum/unit_test/shuttle/shuttles_shall_use_mapped_areas/start_test() + var/failed_shuttles = 0 + for(var/shuttle_name in shuttle_controller.shuttles) + var/datum/shuttle/shuttle = shuttle_controller.shuttles[shuttle_name] + var/failed = FALSE + if(istype(shuttle, /datum/shuttle/autodock/ferry)) + var/datum/shuttle/autodock/ferry/f = shuttle + if(!f.shuttle_area || !f.shuttle_area.x) + log_bad("[f.name]: Invalid shuttle area.") + + else if(istype(shuttle, /datum/shuttle/multi_shuttle)) + var/datum/shuttle/multi_shuttle/ms = shuttle + if(!ms.origin || !ms.origin.x) + log_bad("[ms.name]: Invalid origin area.") + failed = TRUE + if(!ms.interim || !ms.interim.x) + log_bad("[ms.name]: Invalid interim area.") + failed = TRUE + for(var/destination in ms.destinations) + var/area/destination_area = ms.destinations[destination] + if(!(destination_area && destination_area.x)) + log_bad("[ms.name] - [destination]: Invalid destination area.") + failed = TRUE + else + log_bad("[shuttle_name] was of an unchecked shuttle type.") + failed = TRUE + + if(failed) + failed_shuttles++ + + if(failed_shuttles) + fail("Found [failed_shuttles] bad shuttle\s.") + else + pass("All shuttles had proper areas.") + + return 1 + +/datum/unit_test/shuttle/shuttles_shall_use_equally_sized_areas + name = "SHUTTLE - Shuttles shall use equally sized areas" + +/datum/unit_test/shuttle/shuttles_shall_use_equally_sized_areas/start_test() + var/failed_shuttles = 0 + for(var/shuttle_name in shuttle_controller.shuttles) + var/datum/shuttle/shuttle = shuttle_controller.shuttles[shuttle_name] + var/failed = FALSE + if(istype(shuttle, /datum/shuttle/multi_shuttle)) + var/datum/shuttle/multi_shuttle/ms = shuttle + if(is_bad_area_size(ms, ms.origin, ms.interim)) + failed = TRUE + for(var/destination in ms.destinations) + if(is_bad_area_size(ms, ms.origin, ms.destinations[destination])) + failed = TRUE + if(failed) + failed_shuttles++ + + if(failed_shuttles) + fail("Found [failed_shuttles] bad shuttle\s.") + else + pass("All shuttles had proper area sizes.") + + return 1 + +/datum/unit_test/shuttle/shuttles_shall_use_unique_areas + name = "SHUTTLE - Shuttles shall use unique areas" + +#define SHUTTLE_NAME_AID(shuttle) "[shuttle] ([shuttle.type])" + +/datum/unit_test/shuttle/shuttles_shall_use_unique_areas/start_test() + var/list/shuttle_areas = list() + for(var/shuttle_name in shuttle_controller.shuttles) + var/datum/shuttle/shuttle = shuttle_controller.shuttles[shuttle_name] + if(istype(shuttle, /datum/shuttle/autodock/ferry)) + var/datum/shuttle/autodock/ferry/f = shuttle + group_by(shuttle_areas, f.shuttle_area.type, SHUTTLE_NAME_AID(f)) + //TODO sector_shuttles + else if(istype(shuttle, /datum/shuttle/multi_shuttle)) + var/datum/shuttle/multi_shuttle/ms = shuttle + group_by(shuttle_areas, ms.origin.type, SHUTTLE_NAME_AID(ms)) + group_by(shuttle_areas, ms.interim.type, SHUTTLE_NAME_AID(ms)) + for(var/destination in ms.destinations) + var/area/dest_area = ms.destinations[destination] + group_by(shuttle_areas, dest_area.type, SHUTTLE_NAME_AID(ms)) + + var/number_of_issues = number_of_issues(shuttle_areas, "Shuttle Areas") + if(number_of_issues) + fail("[number_of_issues] duplicate shuttle area re-use\s exist.") + else + pass("All used shuttle areas are unique.") + return 1 + +#undef SHUTTLE_NAME_AID + +/datum/unit_test/shuttle/shuttles_shall_use_equally_sized_areas/proc/is_bad_area_size(var/shuttle, var/area/main_area, var/area/checked_area) + var/main_size = 0 + var/checked_size = 0 + for(var/turf/T in main_area) + main_size++ + for(var/turf/T in checked_area) + checked_size++ + if(main_size == checked_size) + return FALSE + + log_bad("[shuttle]: [main_area.type] had a size of [main_size] but [checked_area.type] had a size of [checked_size].") + return TRUE +*/ \ No newline at end of file diff --git a/code/unit_tests/subsystem_tests.dm b/code/unit_tests/subsystem_tests.dm new file mode 100644 index 00000000..a30174a2 --- /dev/null +++ b/code/unit_tests/subsystem_tests.dm @@ -0,0 +1,10 @@ +/datum/unit_test/subsystem_atom_shall_have_no_bad_init_calls + name = "SUBSYSTEM - ATOMS: Shall have no bad init calls" + +/datum/unit_test/subsystem_atom_shall_have_no_bad_init_calls/start_test() + if(SSatoms.BadInitializeCalls.len) + log_bad(jointext(SSatoms.InitLog(), null)) + fail("[SSatoms] had bad initialization calls.") + else + pass("[SSatoms] had no bad initialization calls.") + return 1 diff --git a/code/unit_tests/test_obj.dm b/code/unit_tests/test_obj.dm new file mode 100644 index 00000000..625b9860 --- /dev/null +++ b/code/unit_tests/test_obj.dm @@ -0,0 +1,10 @@ +/obj/test + name = "A test object. You shall never see this." + desc = "A test object. You shall never see this." + +/obj/test/New(var/atom/loc, var/is_test) + ..() + if(!is_test) + error("[src] as created at [loc] - [loc.x]-[loc.y]-[loc.z]") + log_and_message_admins("created \a [src] at [loc]") + qdel(src) diff --git a/code/unit_tests/unique_tests.dm b/code/unit_tests/unique_tests.dm new file mode 100644 index 00000000..cf28e788 --- /dev/null +++ b/code/unit_tests/unique_tests.dm @@ -0,0 +1,159 @@ +/datum/unit_test/research_designs_shall_be_unique + name = "UNIQUENESS: Research Designs Shall Be Unique" + +/datum/unit_test/research_designs_shall_be_unique/start_test() + var/list/ids = list() + var/list/build_paths = list() + + for(var/design_type in subtypesof(/datum/design)) + var/datum/design/design = design_type + if(initial(design.id) == "id") + continue + + group_by(ids, initial(design.id), design) + group_by(build_paths, initial(design.build_path), design) + + var/number_of_issues = number_of_issues(ids, "IDs") + number_of_issues += number_of_issues(build_paths, "Build Paths") + + if(number_of_issues) + fail("[number_of_issues] issues with research designs found.") + else + pass("All research designs are unique.") + + return 1 + +/datum/unit_test/player_preferences_shall_have_unique_key + name = "UNIQUENESS: Player Preferences Shall Be Unique" + +/datum/unit_test/player_preferences_shall_have_unique_key/start_test() + var/list/preference_keys = list() + + for(var/cp in get_client_preferences()) + var/datum/client_preference/client_pref = cp + group_by(preference_keys, client_pref.key, client_pref) + + var/number_of_issues = number_of_issues(preference_keys, "Keys") + if(number_of_issues) + fail("[number_of_issues] issues with player preferences found.") + else + pass("All player preferences have unique keys.") + return 1 + +/datum/unit_test/access_datums_shall_be_unique + name = "UNIQUENESS: Access Datums Shall Be Unique" + +/datum/unit_test/access_datums_shall_be_unique/start_test() + var/list/access_ids = list() + var/list/access_descs = list() + + for(var/a in get_all_access_datums()) + var/datum/access/access = a + group_by(access_ids, num2text(access.id), access) + group_by(access_descs, access.desc, access) + + var/number_of_issues = number_of_issues(access_ids, "Ids") + number_of_issues += number_of_issues(access_descs, "Descriptions") + if(number_of_issues) + fail("[number_of_issues] issue\s with access datums found.") + else + pass("All access datums are unique.") + return 1 + +/datum/unit_test/outfit_datums_shall_have_unique_names + name = "UNIQUENESS: Outfit Datums Shall Have Unique Names" + +/datum/unit_test/outfit_datums_shall_have_unique_names/start_test() + var/list/outfits_by_name = list() + + for(var/a in outfits()) + var/decl/hierarchy/outfit/outfit = a + group_by(outfits_by_name, outfit.name, outfit.type) + + var/number_of_issues = number_of_issues(outfits_by_name, "Names") + if(number_of_issues) + fail("[number_of_issues] issue\s with outfit datums found.") + else + pass("All outfit datums have unique names.") + return 1 + +/datum/unit_test/languages_shall_have_unique_names + name = "UNIQUENESS: Languages Shall Have Unique Names" + +/datum/unit_test/languages_shall_have_unique_names/start_test() + var/list/languages_by_name = list() + + for(var/lt in subtypesof(/datum/language)) + var/datum/language/l = lt + group_by(languages_by_name, initial(l.name), lt) + + var/number_of_issues = number_of_issues(languages_by_name, "Language Names") + if(number_of_issues) + fail("[number_of_issues] issue\s with language datums found.") + else + pass("All languages datums have unique names.") + return 1 + +/datum/unit_test/languages_shall_have_no_or_unique_keys + name = "UNIQUENESS: Languages Shall Have No or Unique Keys" + +/datum/unit_test/languages_shall_have_no_or_unique_keys/start_test() + var/list/languages_by_key = list() + + for(var/lt in subtypesof(/datum/language)) + var/datum/language/l = lt + var/language_key = initial(l.key) + if(!language_key) + continue + + group_by(languages_by_key, language_key, lt) + + var/number_of_issues = number_of_issues(languages_by_key, "Language Keys") + if(number_of_issues) + fail("[number_of_issues] issue\s with language datums found.") + else + pass("All languages datums have unique keys.") + return 1 + +/datum/unit_test/outfit_backpacks_shall_have_unique_names + name = "UNIQUENESS: Outfit Backpacks Shall Have Unique Names" + +/datum/unit_test/outfit_backpacks_shall_have_unique_names/start_test() + var/list/backpacks_by_name = list() + + var/bos = decls_repository.get_decls_of_subtype(/decl/backpack_outfit) + for(var/bo in bos) + var/decl/backpack_outfit/backpack_outfit = bos[bo] + group_by(backpacks_by_name, backpack_outfit.name, backpack_outfit) + + var/number_of_issues = number_of_issues(backpacks_by_name, "Outfit Backpack Names") + if(number_of_issues) + fail("[number_of_issues] outfit backpacks\s found.") + else + pass("All outfit backpacks have unique names.") + return 1 + + +/datum/unit_test/proc/number_of_issues(var/list/entries, var/type, var/feedback = /decl/noi_feedback) + var/issues = 0 + for(var/key in entries) + var/list/values = entries[key] + if(values.len > 1) + var/decl/noi_feedback/noif = decls_repository.get_decl(feedback) + noif.print(src, type, key, values) + issues++ + + return issues + +/decl/noi_feedback/proc/priv_print(var/datum/unit_test/ut, var/type, var/key, var/output_text) + ut.log_bad("[type] - [key] - The following entries have the same value: [output_text]") + +/decl/noi_feedback/proc/print(var/datum/unit_test/ut, var/type, var/key, var/list/entries) + priv_print(ut, type, key, english_list(entries)) + +/decl/noi_feedback/detailed/print(var/datum/unit_test/ut, var/type, var/key, var/list/entries) + var/list/pretty_print = list() + pretty_print += "" + for(var/entry in entries) + pretty_print += log_info_line(entry) + priv_print(ut, type, key, jointext(pretty_print, "\n")) diff --git a/code/unit_tests/unit_test.dm b/code/unit_tests/unit_test.dm new file mode 100644 index 00000000..5f91aac4 --- /dev/null +++ b/code/unit_tests/unit_test.dm @@ -0,0 +1,274 @@ +/* Unit Tests originally designed by Ccomp5950 + * + * Tests are created to prevent changes that would create bugs or change expected behaviour. + * For the most part I think any test can be created that doesn't require a client in a mob or require a game mode other then extended + * + * The easiest way to make effective tests is to create a "template" if you intend to run the same test over and over and make your actual + * tests be a "child object" of those templates. Be sure and name your templates with the word "template" somewhere in var/name. + * + * The goal is to have all sorts of tests that run and to run them as quickly as possible. + * + * Tests that require time to run we instead just check back on their results later instead of waiting around in a sleep(1) for each test. + * This allows us to finish unit testing quicker since we can start other tests while we're waiting on that one to finish. + * + * An example of that is listed in mob_tests.dm with the human_breath test. We spawn the mob in space and set the async flag to 1 so that we run the check later. + * After 10 life ticks for that mob we check it's oxyloss but while that is going on we've already ran other tests. + * + * If your test requires a significant amount of time...cheat on the timers. Either speed up the process/life runs or do as we did in the timers for the shuttle + * transfers in zas_tests.dm we move a shuttle but instead of waiting 3 minutes we set the travel time to a very low number. + * + * At the same time, Unit tests are intended to reflect standard usage so avoid changing to much about how stuff is processed. + * + * + * WRITE UNIT TEST TEMPLATES AS GENERIC AS POSSIBLE (makes for easy reusability) + * + */ + + +#define MAX_UNIT_TEST_RUN_TIME 2 MINUTES + +var/all_unit_tests_passed = 1 +var/failed_unit_tests = 0 +var/skipped_unit_tests = 0 +var/total_unit_tests = 0 +var/currently_running_tests = 0 + +// For console out put in Linux/Bash makes the output green or red. +// Should probably only be used for unit tests/Travis since some special folks use winders to host servers. +// if you want plain output, use dm.sh -DUNIT_TEST -DUNIT_TEST_PLAIN baystation12.dme +#ifdef UNIT_TEST_PLAIN +var/ascii_esc = "" +var/ascii_red = "" +var/ascii_green = "" +var/ascii_yellow = "" +var/ascii_reset = "" +#else +var/ascii_esc = ascii2text(27) +var/ascii_red = "[ascii_esc]\[31m" +var/ascii_green = "[ascii_esc]\[32m" +var/ascii_yellow = "[ascii_esc]\[33m" +var/ascii_reset = "[ascii_esc]\[0m" +#endif + + +// We list these here so we can remove them from the for loop running this. +// Templates aren't intended to be ran but just serve as a way to create child objects of it with inheritable tests for quick test creation. + +datum/unit_test + var/name = "template - should not be ran." + var/disabled = 0 // If we want to keep a unit test in the codebase but not run it for some reason. + var/async = 0 // If the check can be left to do it's own thing, you must define a check_result() proc if you use this. + var/reported = 0 // If it's reported a success or failure. Any tests that have not are assumed to be failures. + var/why_disabled = "No reason set." // If we disable a unit test we will display why so it reminds us to check back on it later. + + var/safe_landmark + var/space_landmark + +datum/unit_test/proc/log_debug(var/message) + log_unit_test("[ascii_yellow]--- DEBUG --- \[[name]\]: [message][ascii_reset]") + +datum/unit_test/proc/log_bad(var/message) + log_unit_test("[ascii_red]\[[name]\]: [message][ascii_reset]") + +datum/unit_test/proc/fail(var/message) + all_unit_tests_passed = 0 + failed_unit_tests++ + reported = 1 + log_unit_test("[ascii_red]!!! FAILURE !!! \[[name]\]: [message][ascii_reset]") + +datum/unit_test/proc/pass(var/message) + reported = 1 + log_unit_test("[ascii_green]*** SUCCESS *** \[[name]\]: [message][ascii_reset]") + +datum/unit_test/proc/skip(var/message) + skipped_unit_tests++ + reported = 1 + log_unit_test("[ascii_yellow]--- SKIPPED --- \[[name]\]: [message][ascii_reset]") + +datum/unit_test/proc/start_test() + fail("No test proc.") + +datum/unit_test/proc/check_result() + fail("No check results proc") + return 1 + +datum/unit_test/proc/get_safe_turf() + if(!safe_landmark) + for(var/landmark in landmarks_list) + if(istype(landmark, /obj/effect/landmark/test/safe_turf)) + safe_landmark = landmark + break + return get_turf(safe_landmark) + +datum/unit_test/proc/get_space_turf() + if(!space_landmark) + for(var/landmark in landmarks_list) + if(istype(landmark, /obj/effect/landmark/test/space_turf)) + space_landmark = landmark + break + return get_turf(space_landmark) + +proc/load_unit_test_changes() +/* + //This takes about 60 seconds to run on Travis and is only used for the ZAS vacume check on The Asteroid. + if(config.generate_map != 1) + log_unit_test("Overiding Configuration option for Asteroid Generation to ENABLED") + config.generate_map = 1 // The default map requires it, the example config doesn't have this enabled. + */ + + + + +/proc/initialize_unit_tests() + #ifndef UNIT_TEST_COLOURED + if(world.system_type != UNIX) // Not a Unix/Linux/etc system, we probably don't want to print color escapes (unless UNIT_TEST_COLOURED was defined to force escapes) + ascii_esc = "" + ascii_red = "" + ascii_green = "" + ascii_yellow = "" + ascii_reset = "" + #endif + + log_unit_test("Initializing Unit Testing") + + // + //Start the Round. + // + + if(!ticker) + crash_with("No Ticker") + del(world) + + var/said_msg = 0 + while(ticker.pregame_timeleft && ticker.pregame_timeleft > 160) // Make sure the initial startup is complete. + if(ticker.pregame_timeleft < 175 && !said_msg) + said_msg = 1 + log_unit_test("Pregame Count down has started, giving it 20 seconds to finish.") + sleep(world.tick_lag) + + log_unit_test("Awaiting the master process...") + while(Master.current_runlevel < RUNLEVEL_LOBBY) + sleep(world.tick_lag) + log_unit_test("Master process setup.") + + world.save_mode("extended") + + sleep(1) + + ticker.current_state = GAME_STATE_SETTING_UP + Master.SetRunLevel(RUNLEVEL_SETUP) + + log_unit_test("Round has been started. Waiting 10 seconds to start tests.") + sleep(100) + log_unit_test("Initiating tests.") + + // + // Run Tests + // + + var/list/test_datums = get_test_datums() + run_unit_tests(test_datums) + log_unit_test("Caught [GLOB.total_runtimes] Runtime\s.") + del(world) + +/proc/run_unit_tests(var/list/test_datums, var/skip_disabled_tests = TRUE) + if(currently_running_tests) + log_unit_test("Already running unit tests") + return + currently_running_tests = 1 + + all_unit_tests_passed = 1 + failed_unit_tests = 0 + total_unit_tests = 0 + + var/list/async_test = list() + var/list/started_tests = list() + + log_unit_test("Testing Started.") + + var/end_unit_tests = world.time + MAX_UNIT_TEST_RUN_TIME + + for (var/test in test_datums) + var/datum/unit_test/d = new test() + + if(d.disabled && skip_disabled_tests) + d.pass("[ascii_red]Check Disabled: [d.why_disabled]") + continue + + total_unit_tests++ + started_tests.Add(d) + + if(world.time > end_unit_tests) + d.fail("Unit Tests Ran out of time") // This should never happen, and if it does either fix your unit tests to be faster or if you can make them async checks. + continue + + if(isnull(d.start_test())) // Start the test. + d.fail("Test Runtimed") + continue + if(d.async) // If it's async then we'll need to check back on it later. + async_test.Add(d) + + // + // Check the async tests to see if they are finished. + // + + while(async_test.len) + + for(var/datum/unit_test/test in async_test) + + if(world.time > end_unit_tests) + test.fail("Unit Tests Ran out of Time") // If we're going to run out of time, most likely it's here. If you can't speed up your unit tests then add time to the timeout at the top. + async_test.Remove(test) + continue + + var/result = test.check_result() // Run the async check and store the return + + if(isnull(result)) + test.fail("Test Runtimed") + async_test.Remove(test) + continue + if(result) // 0 Means come back, 1 means we got results so move on. + async_test.Remove(test) + sleep(1) + + // + // Make sure all Unit Tests reported a result + // + + for(var/datum/unit_test/test in started_tests) + if(!test.reported) + test.fail("Test failed to report a result.") + + var/skipped_message = "" + if(skipped_unit_tests) + skipped_message = "| \[[skipped_unit_tests]\\[total_unit_tests]\] Unit Tests Skipped " + + if(all_unit_tests_passed) + log_unit_test("[ascii_green]**** All Unit Tests Passed \[[total_unit_tests]\] [skipped_message]****[ascii_reset]") + else + log_unit_test("[ascii_red]**** \[[failed_unit_tests]\\[total_unit_tests]\] Unit Tests Failed [skipped_message]****[ascii_reset]") + currently_running_tests = 0 + +/proc/get_test_datums() + var/list/tests = list() + for(var/test in typesof(/datum/unit_test)) + var/datum/unit_test/d = test + if(!findtext(initial(d.name), "template")) + tests += d + return tests + +/datum/admins/proc/run_unit_test(var/datum/unit_test/unit_test_type in get_test_datums()) + set name = "Run Unit Test" + set desc = "Runs the selected unit test - Remember to enable Debug Log Messages" + set category = "Debug" + + if(!unit_test_type) + return + + if(!check_rights(R_DEBUG)) + return + + log_and_message_admins("has started the unit test '[initial(unit_test_type.name)]'") + run_unit_tests(list(unit_test_type), FALSE) + +#undef MAX_UNIT_TEST_RUN_TIME diff --git a/code/unit_tests/uplink_tests.dm b/code/unit_tests/uplink_tests.dm new file mode 100644 index 00000000..ac502313 --- /dev/null +++ b/code/unit_tests/uplink_tests.dm @@ -0,0 +1,38 @@ +/datum/unit_test/uplink_setup_test + name = "UPLINK: All uplink items shall be valid." + +/datum/unit_test/uplink_setup_test/start_test() + var/success = TRUE + + for(var/item in uplink.items) + var/datum/uplink_item/ui = item + success = is_valid_uplink_item(ui, "Uplink items") && success + + for(var/item in uplink.items_assoc) + var/datum/uplink_item/ui = uplink.items_assoc[item] + success = is_valid_uplink_item(ui, "Uplink assoc items") && success + + var/datum/uplink_random_selection/uplink_selection = get_uplink_random_selection_by_type(/datum/uplink_random_selection/blacklist) + for(var/item in uplink_selection.items) + var/datum/uplink_random_item/uri = item // Basically ensuring random uplink items is a subset of the full range of items + success = is_valid_uplink_item(uplink.items_assoc[uri.uplink_item], "Random uplink items", uri.uplink_item) && success + + if(success) + pass("All uplink items were valid.") + else + fail("One or more uplink items were invalid.") + + return TRUE + +/datum/unit_test/uplink_setup_test/proc/is_valid_uplink_item(var/datum/uplink_item/ui, var/type, var/optional_uplink_item_type) + if(!istype(ui)) + log_bad("[type]: [ui] was of an unexpected type: [ui ? ui.type : (optional_uplink_item_type ? optional_uplink_item_type : "NULL")]") + return FALSE + if(!ui.category) + log_bad("[type]: [ui] has no category.") + return FALSE + var/cost = ui.cost(0) + if(cost <= 0) + log_bad("[type]: [ui] has an invalid cost of [cost].") + return FALSE + return TRUE diff --git a/code/unit_tests/view_variables_test.dm b/code/unit_tests/view_variables_test.dm new file mode 100644 index 00000000..4df2ef87 --- /dev/null +++ b/code/unit_tests/view_variables_test.dm @@ -0,0 +1,49 @@ +/datum/unit_test/view_variables_special_vv_handlers_shall_be_valid + name = "VIEW VARIABLES: All Special VV Handlers Shall Be Valid" + +/datum/unit_test/view_variables_special_vv_handlers_shall_be_valid/start_test() + var/list/faulty_handlers = list() + for(var/decl/vv_set_handler/sh in init_subtypes(/decl/vv_set_handler)) + if(!ispath(sh.handled_type)) + log_bad("[sh] does not have a valid handled type. Expected a path, was [log_info_line(sh.handled_type)]") + faulty_handlers |= sh + + if(!islist(sh.handled_vars)) + log_bad("[sh] does not have a handled variables list. Expected a list, was [log_info_line(sh.handled_vars)]") + faulty_handlers |= sh + else if(!sh.handled_vars.len) + log_bad("[sh] as an empty handled variables list.") + faulty_handlers |= sh + else + continue + // Somehow check for missing vars here without creating instances. + // I.e.: for(var/handled_var in sh.handled_vars) check handled_var in handled_type.vars + + if(faulty_handlers.len) + fail("The following special VV handlers are invalid: [english_list(faulty_handlers)]") + else + pass("All special VV handlers are valid.") + return 1 + +/datum/unit_test/view_variables_no_special_vv_handlers_shall_have_overlapping_handling + name = "VIEW VARIABLES: No Special VV Handlers Shall Have Overlapping Handling" + +/datum/unit_test/view_variables_no_special_vv_handlers_shall_have_overlapping_handling/start_test() + var/list/handlers = init_subtypes(/decl/vv_set_handler) + var/failed = 0 + + for(var/decl/vv_set_handler/sh1 in handlers) + handlers -= sh1 + for(var/decl/vv_set_handler/sh2 in handlers) + if(!(ispath(sh1.handled_type, sh2.handled_type) || ispath(sh2.handled_type, sh1.handled_type))) + continue + var/list/intersected_vars = sh1.handled_vars & sh2.handled_vars + if(intersected_vars.len) + failed = TRUE + log_bad("[sh1] and [sh2] have the following overlaps: [english_list(intersected_vars)]") + + if(failed) + fail("One or more special VV handlers had overlapping handling.") + else + pass("No special VV handlers had overlapping handling.") + return 1 diff --git a/code/unit_tests/virtual_mob_tests.dm b/code/unit_tests/virtual_mob_tests.dm new file mode 100644 index 00000000..dda0a995 --- /dev/null +++ b/code/unit_tests/virtual_mob_tests.dm @@ -0,0 +1,110 @@ +#ifdef UNIT_TEST + +datum/unit_test/virtual + name = "VIRTUAL - Template" + +datum/unit_test/virtual/helper + name = "VIRTUAL - Template Helper" + + var/helper_proc + var/list/expected_mobs + + var/mob/mob_one + var/mob/mob_two + var/mob/mob_three + +datum/unit_test/virtual/helper/start_test() + standard_setup() + + var/list/actual_mobs = call(helper_proc)(mob_one) + var/list/missing_mobs = expected_mobs - actual_mobs + var/list/excessive_mobs= actual_mobs - expected_mobs + + if(missing_mobs.len || excessive_mobs.len) + fail("[helper_proc] did not return the expected mobs. Expected [english_list(expected_mobs)], was [english_list(actual_mobs)]") + log_debug(mob_one.virtual_mob.sight) + log_debug(mob_one.virtual_mob.see_invisible) + log_debug(mob_one.virtual_mob.see_in_dark) + else + pass("[helper_proc] returned the expected mobs.") + + expected_mobs = null + standard_cleanup() + return TRUE + +datum/unit_test/virtual/helper/check_hearers_in_range + name = "VIRTUAL - Helper Test - Check Hearers In Range" + helper_proc = /proc/hearers_in_range +datum/unit_test/virtual/helper/check_hearers_in_range/standard_setup() + ..() + expected_mobs = list(mob_one, mob_two, mob_three) + +datum/unit_test/virtual/helper/check_hearers_in_range_with_mob_inside_storage + name = "VIRTUAL - Helper Test - Check Hearers In Range - With Mob Inside Storage" + helper_proc = /proc/hearers_in_range + var/obj/storage +datum/unit_test/virtual/helper/check_hearers_in_range_with_mob_inside_storage/standard_setup() + ..() + storage = new(mob_one.loc) + mob_one.forceMove(storage) + expected_mobs = list(mob_one, mob_two, mob_three) +datum/unit_test/virtual/helper/check_hearers_in_range_with_mob_inside_storage/Destroy() + QDEL_NULL(storage) + . = ..() + +datum/unit_test/virtual/helper/check_viewers_in_range + name = "VIRTUAL - Helper Test - Check Viewers In Range" + helper_proc = /proc/viewers_in_range +datum/unit_test/virtual/helper/check_viewers_in_range/standard_setup() + ..() + expected_mobs = list(mob_one, mob_two, mob_three) + +datum/unit_test/virtual/helper/check_all_hearers + name = "VIRTUAL - Helper Test - Check All Hearers" + helper_proc = /proc/all_hearers +datum/unit_test/virtual/helper/check_all_hearers/standard_setup() + ..() + expected_mobs = list(mob_one, mob_two) + +datum/unit_test/virtual/helper/check_all_viewers + name = "VIRTUAL - Helper Test - Check All Viewers" + helper_proc = /proc/all_viewers +datum/unit_test/virtual/helper/check_all_viewers/standard_setup() + ..() + expected_mobs = list(mob_one, mob_two) + +datum/unit_test/virtual/helper/check_mobs_in_viewing_range + name = "VIRTUAL - Helper Test - Check Mobs In Viewing Range" + helper_proc = /proc/hosts_in_view_range +datum/unit_test/virtual/helper/check_mobs_in_viewing_range/standard_setup() + ..() + expected_mobs = list(mob_one, mob_two) + +datum/unit_test/virtual/helper/check_hosts_in_view_range_with_mob_inside_object + name = "VIRTUAL - Helper Test - Check Hosts in View Range - With Mob Inside Object" + helper_proc = /proc/hosts_in_view_range + var/obj/storage +datum/unit_test/virtual/helper/check_hosts_in_view_range_with_mob_inside_object/standard_setup() + ..() + storage = new(mob_one.loc) + mob_one.forceMove(storage) + expected_mobs = list(mob_one, mob_two) +datum/unit_test/virtual/helper/check_hosts_in_view_range_with_mob_inside_object/Destroy() + QDEL_NULL(storage) + . = ..() + +datum/unit_test/virtual/helper/proc/standard_setup() + mob_one = get_named_instance(/mob/fake_mob, get_turf(locate(/obj/effect/landmark/virtual_spawn/one)), "Test Mob 1") + mob_two = get_named_instance(/mob/fake_mob, get_turf(locate(/obj/effect/landmark/virtual_spawn/two)), "Test Mob 2") + mob_three = get_named_instance(/mob/fake_mob, get_turf(locate(/obj/effect/landmark/virtual_spawn/three)), "Test Mob 3") + +datum/unit_test/virtual/helper/proc/standard_cleanup() + QDEL_NULL(mob_one) + QDEL_NULL(mob_two) + QDEL_NULL(mob_three) + +/obj/effect/landmark/virtual_spawn/one +/obj/effect/landmark/virtual_spawn/two +/obj/effect/landmark/virtual_spawn/three + +#endif diff --git a/code/unit_tests/zas_tests.dm b/code/unit_tests/zas_tests.dm new file mode 100644 index 00000000..9312b73c --- /dev/null +++ b/code/unit_tests/zas_tests.dm @@ -0,0 +1,170 @@ +/* + * + * Zas Unit Tests. + * Shuttle Pressurized. + * + * + */ + +#define UT_NORMAL 1 // Standard one atmosphere 20celsius +#define UT_VACUUM 2 // Vacume on simulated turfs +#define UT_NORMAL_COLD 3 // Cold but standard atmosphere. + +#define FAILURE 0 +#define SUCCESS 1 +#define SKIP 2 + +// +// Generic check for an area. +// + +datum/unit_test/zas_area_test + name = "ZAS: Area Test Template" + var/area_path = null // Put the area you are testing here. + var/expectation = UT_NORMAL // See defines above. + +datum/unit_test/zas_area_test/start_test() + var/list/test = test_air_in_area(area_path, expectation) + + if(isnull(test)) + fail("Check Runtimed") + + switch(test["result"]) + if(SUCCESS) pass(test["msg"]) + if(SKIP) skip(test["msg"]) + else fail(test["msg"]) + return 1 + +// ================================================================================================== + +// +// The primary helper proc. +// +proc/test_air_in_area(var/test_area, var/expectation = UT_NORMAL) + var/test_result = list("result" = FAILURE, "msg" = "") + + var/area/A = locate(test_area) + + // BYOND creates an instance of every area, so this can't be !A or !istype(A, test_area) + if(!(A.x || A.y || A.z)) + test_result["msg"] = "Unable to get [test_area]" + test_result["result"] = FAILURE + return test_result + + var/list/GM_checked = list() + + for(var/turf/simulated/T in A) + + if(!istype(T) || isnull(T.zone) || istype(T, /turf/simulated/floor/airless)) + continue + if(T.zone.air in GM_checked) + continue + + var/t_msg = "Turf: [T] | Location: [T.x] // [T.y] // [T.z]" + + var/datum/gas_mixture/GM = T.return_air() + var/pressure = GM.return_pressure() + var/temp = GM.temperature + + switch(expectation) + + if(UT_VACUUM) + if(pressure > 10) + test_result["msg"] = "Pressure out of bounds: [pressure] | [t_msg]" + return test_result + + + if(UT_NORMAL || UT_NORMAL_COLD) + if(abs(pressure - ONE_ATMOSPHERE) > 10) + test_result["msg"] = "Pressure out of bounds: [pressure] | [t_msg]" + return test_result + + if(expectation == UT_NORMAL) + + if(abs(temp - T20C) > 10) + test_result["msg"] = "Temperature out of bounds: [temp] | [t_msg]" + return test_result + + if(expectation == UT_NORMAL_COLD) + + if(temp > 120) + test_result["msg"] = "Temperature out of bounds: [temp] | [t_msg]" + return test_result + + GM_checked.Add(GM) + + if(GM_checked.len) + test_result["result"] = SUCCESS + test_result["msg"] = "Checked [GM_checked.len] zones" + else + test_result["msg"] = "No zones checked." + + return test_result + + +// ================================================================================================== + + +// Here we move a shuttle then test it's area once the shuttle has arrived. + +datum/unit_test/zas_supply_shuttle_moved + name = "ZAS: Supply Shuttle (When Moved)" + async=1 // We're moving the shuttle using built in procs. + + var/datum/shuttle/autodock/ferry/supply/shuttle = null + + var/testtime = 0 //Used as a timer. + +datum/unit_test/zas_supply_shuttle_moved/start_test() + + if(!shuttle_controller) + fail("Shuttle Controller not setup at time of test.") + return 1 + if(!shuttle_controller.shuttles.len) + skip("No shuttles have been setup for this map.") + return 1 + + shuttle = supply_controller.shuttle + if(isnull(shuttle)) + return 1 + + // Initiate the Move. + supply_controller.movetime = 5 // Speed up the shuttle movement. + shuttle.short_jump(shuttle.get_location_waypoint(!shuttle.location)) //TODO + + return 1 + +datum/unit_test/zas_supply_shuttle_moved/check_result() + if(!shuttle) + skip("This map has no supply shuttle.") + return 1 + + if(shuttle.moving_status == SHUTTLE_IDLE && !shuttle.at_station()) + fail("Shuttle Did not Move") + return 1 + + if(!shuttle.at_station()) + return 0 + + if(!testtime) + testtime = world.time+40 // Wait another 2 ticks then proceed. + + if(world.time < testtime) + return 0 + for(var/area/A in shuttle.shuttle_area) + var/list/test = test_air_in_area(A.type) + if(isnull(test)) + fail("Check Runtimed") + return 1 + + switch(test["result"]) + if(SUCCESS) pass(test["msg"]) + if(SKIP) skip(test["msg"]) + else fail(test["msg"]) + return 1 + +#undef UT_NORMAL +#undef UT_VACUUM +#undef UT_NORMAL_COLD +#undef SUCCESS +#undef FAILURE diff --git a/code/unit_tests/~helpers.dm b/code/unit_tests/~helpers.dm new file mode 100644 index 00000000..a2b43734 --- /dev/null +++ b/code/unit_tests/~helpers.dm @@ -0,0 +1,7 @@ +/datum/unit_test/proc/get_named_instance(var/instance_type, var/instance_loc, var/instance_name) + var/atom/movable/am = new instance_type(instance_loc) + am.name = "[instance_name ? instance_name : name] ([name])" + if(ismob(am)) + var/mob/M = am + M.real_name = name + return am diff --git a/code/unit_tests/~unit_test_overrides.dm b/code/unit_tests/~unit_test_overrides.dm new file mode 100644 index 00000000..35be6057 --- /dev/null +++ b/code/unit_tests/~unit_test_overrides.dm @@ -0,0 +1,77 @@ +/* + Consistent "randomness" overrides. +*/ + +// The following overrides ensures random object spawners always select the most space consuming objects +/datum/proc/unit_test_get_weight() + CRASH("Unhandled atom: [type]") + +/datum/atom_creator/simple/unit_test_get_weight() + return unit_test_weight_of_path(path) + +/datum/atom_creator/weighted/unit_test_get_weight() + return unit_test_weight_of_path(unit_test_select_heaviest(paths)) + +/datum/atom_creator/simple + prob_method = /proc/return_true + +/datum/atom_creator/weighted + selection_method = /proc/unit_test_select_heaviest + +/obj/random + spawn_method = /obj/random/proc/unit_test_spawn_item + +GLOBAL_DATUM(unit_test_last_obj_random_creation, /atom/movable) +/obj/random/proc/unit_test_spawn_item() + var/build_path = unit_test_select_heaviest(spawn_choices()) + GLOB.unit_test_last_obj_random_creation = new build_path() + + +/proc/unit_test_select_heaviest(var/list/choices) + if(ispath(choices) || istype(choices, /datum)) + return choices + if(!islist(choices)) + CRASH("Unhandled input: [log_info_line(choices)]") + + var/heaviest_weight = -1 + var/heaviest_choice + + for(var/choice in choices) + var/path = unit_test_select_heaviest(choice) + var/weight = unit_test_weight_of_path(path) + if(weight > heaviest_weight) + heaviest_weight = weight + heaviest_choice = choice + + return heaviest_choice + +GLOBAL_LIST_EMPTY(unit_test_obj_random_weights_by_type) + +// If you adjust any of the values below, please also update /obj/structure/closet/proc/content_size(atom/movable/AM) +/proc/unit_test_weight_of_path(var/path) + if(ispath(path, /obj/random)) + var/weight = GLOB.unit_test_obj_random_weights_by_type[path] + if(!weight) + var/obj/random/R = new path() + var/type = unit_test_select_heaviest(R.spawn_choices()) + weight = unit_test_weight_of_path(type) + GLOB.unit_test_obj_random_weights_by_type[path] = weight + return weight + // Would be nice to re-use how closets calculate size/weight but the difference between instances and paths prevents it. + if(ispath(path, /obj)) + var/obj/O = path + return initial(O.w_class) / 2 + if(ispath(path, /mob)) + var/mob/M = path + return initial(M.mob_size) + if(ispath(path, /obj/structure) || ispath(path, /obj/machinery)) + return MOB_LARGE + if(istype(path, /datum)) + var/datum/D = path + return D.unit_test_get_weight() + + CRASH("Unhandled path: [log_info_line(path)]") + + +/proc/return_true() + return TRUE diff --git a/code/unit_tests/~unit_test_types.dm b/code/unit_tests/~unit_test_types.dm new file mode 100644 index 00000000..c0d3388a --- /dev/null +++ b/code/unit_tests/~unit_test_types.dm @@ -0,0 +1,63 @@ +/obj/effect/landmark/test/safe_turf + name = "safe_turf" // At creation, landmark tags are set to: "landmark*[name]" + desc = "A safe turf should be an as large block as possible of livable, passable turfs, preferably at least 3x3 with the marked turf as the center" + +/obj/effect/landmark/test/space_turf + name = "space_turf" + desc = "A space turf should be an as large block as possible of space, preferably at least 3x3 with the marked turf as the center" + +#ifdef UNIT_TEST + +/datum/fake_client + +/mob/fake_mob + var/datum/fake_client/fake_client + +/mob/fake_mob/Destroy() + QDEL_NULL(fake_client) + . = ..() + +/mob/fake_mob/get_client() + if(!fake_client) + fake_client = new() + return fake_client + + +/obj/unit_test_light + w_class = 1 + +/obj/unit_test_medium + w_class = 3 + +/obj/unit_test_heavy + w_class = 5 + +/obj/random/unit_test/spawn_choices() + return list(/obj/unit_test_light, /obj/unit_test_heavy, /obj/unit_test_medium) + + +/area/test_area/powered_non_dynamic_lighting + name = "\improper Test Area - Powered - Non-Dynamic Lighting" + icon_state = "green" + requires_power = 0 + dynamic_lighting = 0 + +/area/test_area/requires_power_non_dynamic_lighting + name = "\improper Test Area - Requires Power - Non-Dynamic Lighting" + icon_state = "red" + requires_power = 1 + dynamic_lighting = 0 + +/area/test_area/powered_dynamic_lighting + name = "\improper Test Area - Powered - Dynamic Lighting" + icon_state = "yellow" + requires_power = 0 + dynamic_lighting = 1 + +/area/test_area/requires_power_dynamic_lighting + name = "\improper Test Area - Requires Power - Dynamic Lighting" + icon_state = "purple" + requires_power = 1 + dynamic_lighting = 1 + +#endif diff --git a/code/world.dm b/code/world.dm new file mode 100644 index 00000000..d349962d --- /dev/null +++ b/code/world.dm @@ -0,0 +1,17 @@ +#define WORLD_ICON_SIZE 32 + +//This file is just for the necessary /world definition +//Try looking in game/world.dm + +/world + mob = /mob/new_player + turf = /turf/space + area = /area/space + view = "15x15" + cache_lifespan = 7 + hub = "Exadv1.spacestation13" + icon_size = WORLD_ICON_SIZE + fps = 20 +#ifdef GC_FAILURE_HARD_LOOKUP + loop_checks = FALSE +#endif diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..2d753b1f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,18 @@ +version: "3" +services: + db: + build: ./sql + image: bs12-db:latest + networks: + - internal + volumes: + - "./sql/test_db:/var/lib/mysql" + game: + build: . + image: bs12:latest + networks: + - internal + ports: + - "8000:8000" +networks: + internal: \ No newline at end of file diff --git a/flyway.conf b/flyway.conf new file mode 100644 index 00000000..cb3b9de9 --- /dev/null +++ b/flyway.conf @@ -0,0 +1,6 @@ +flyway.locations=filesystem:sql/migrate + +# copy these into another file and use the -configFile switch on flyway +# flyway.url=jdbc:mysql://localhost/bs12 +# flyway.user=bs12 +# flyway.password=hunter2 diff --git a/fonts/Shage/README.txt b/fonts/Shage/README.txt new file mode 100644 index 00000000..3f7456b0 --- /dev/null +++ b/fonts/Shage/README.txt @@ -0,0 +1,22 @@ +---LEGAL SHIT--- +The font file in this archive was created using Fontstruct the free, online +font-building tool. +This font was created by “BlueNexusâ€. +This font has a homepage where this archive and other versions may be found: +https://fontstruct.com/fontstructions/show/1476786 + +Try Fontstruct at http://fontstruct.com +It’s easy and it’s fun. + +NOTE FOR FLASH USERS: Fontstruct fonts (fontstructions) are optimized for Flash. +If the font in this archive is a pixel font, it is best displayed at a font-size +of 7. + +Fontstruct is copyright ©2018 Rob Meek + +LEGAL NOTICE: +In using this font you must comply with the licensing terms described in the +file “license.txt†included with this archive. +If you redistribute the font file in this archive, it must be accompanied by all +the other files from this archive, including this one. +---END LEGAL SHIT-- \ No newline at end of file diff --git a/fonts/Shage/Shage.ttf b/fonts/Shage/Shage.ttf new file mode 100644 index 00000000..9c76ad47 Binary files /dev/null and b/fonts/Shage/Shage.ttf differ diff --git a/fonts/Shage/license.txt b/fonts/Shage/license.txt new file mode 100644 index 00000000..fc4bf370 --- /dev/null +++ b/fonts/Shage/license.txt @@ -0,0 +1,4 @@ +The FontStruction “Shage†+(https://fontstruct.com/fontstructions/show/1476786) by “BlueNexus†is +licensed under a Creative Commons Attribution license +(http://creativecommons.org/licenses/by/3.0/). diff --git a/html/88x31.png b/html/88x31.png new file mode 100644 index 00000000..0f2a0f10 Binary files /dev/null and b/html/88x31.png differ diff --git a/html/archivedchangelog.html b/html/archivedchangelog.html new file mode 100644 index 00000000..9831f594 --- /dev/null +++ b/html/archivedchangelog.html @@ -0,0 +1,970 @@ + + +
                +

                December 28nd

                +

                Cael_Aislinn updated:

                + +
                + +
                +

                November 2012 - January 2013

                +

                chinsky updated:

                +
                  +
                • Several cargo crates from pre-merge were ported.
                • +
                • Contraband crate is no longer labeled as such.
                • +
                • In space, no one can hear you scream now.
                • +
                +

                CIB updated:

                +
                  +
                • Airflow produces subtle sound effects now.
                • +
                • Events are now adjusted based on department activity.
                • +
                • The virus event will spawn BS12 vira.
                • +
                • Two new traitor objectives: Brig and Harm
                • +
                • Space no longer makes rooms cold.
                • +
                • Gibbing creates actual limbs you can pick up, if you're lucky a complete head with brain.
                • +
                • It's now possible to miss in combat(melee and guns), instead of just hitting the torso rather than the head. This makes targetting the head much riskier than before.
                • +
                • Chemicals now last 10x as long in the blood, but their effect is also reduced equally.
                • +
                • IV drips now have a right-click option to take blood rather than give it.
                • +
                • Everyone gets a crew manifest.
                • +
                +

                CaelAislinn updated:

                +
                  +
                • There now is a client-toggle for whether to become a space-ninja.
                • +
                • Reduced startup lag by removing a vermin-related proc.
                • +
                • Several alien balance fixes.
                • +
                +

                Ravensdale updated:

                +
                  +
                • Ported station-wide explosion sounds.
                • +
                +
                + +
                +

                December 3rd

                +

                Cael_Aislinn updated:

                +
                  +
                • Aliens have been significantly nerfed: neurotoxin is affected by bio protection suits, tackle stuns for much shorter time and facehuggers have a chance to fail when leaping.
                • +
                +
                + +
                +

                23.11.12

                +

                CIB updated:

                +
                  +
                • Cryo now temporarily stops bleeding, meaning you can shove the patient in there while you prepare IV and surgery.
                • +
                +
                + +
                +

                14.11.12

                +

                Chinsky updated:

                +
                  +
                • Virologist are now alt title of Medical Doctor, like Surgeon or EMT. All medical jobs now have virology access.
                • +
                • Added scientist alt titles.
                • +
                +

                CIB updated:

                +
                  +
                • Lungs can now rupture from exposure to low oxygen environments. Use alien-surgery, and then scalpel instead of hemostat, to fix.
                • +
                • Bandage/ointment healing sped up by a factor 10.
                • +
                • Ported autopsy.
                • +
                +
                + +
                +

                November 12th

                +

                CIB updated:

                +
                  +
                • Wounds can now get infected in surgery if the surgeon doesn't wash his hands first. Infected wounds can be treated with ointment(though it'll take a while to take effect).
                • +
                • Large amounts of damage can now trigger internal bleeding. Internal bleeding can be recognized in the stationary body scanner, and can be treated through surgery with VeinOFix.
                • +
                +
                + +
                +

                November 11th

                +

                CIB updated:

                +
                  +
                • DNA injectors now have a small chance(5%) to trigger a genetic side-effect. See the paper in the genetics lobby for recognition and treatment.
                • +
                +
                + +
                +

                November 9th

                +

                AterIgnis updated:

                +
                  +
                • Chemistry explosions try to damage their holder first - potassium-water mixes and nitroglycerol tend to gib human if injected instead of creating crater around them
                • +
                • Reagents mix and react inside humans, but they don't bubble in that case (try not to give patient water and potassium at the same time)
                • +
                • Ethanol-based drinks (alcohol) is treated like ethanol now and can be used in reactions. Ethanol->water reaction now properly makes drunk people sober by removing alcohol, not just temporarily sobering them.
                • +
                +
                + +
                +

                6.11.2012

                +

                Chinsky updated:

                +
                  +
                • Crew Transfer shuttles are back.
                • +
                • Readded pre-merge photo system. Instead of one picture as icon, now photo can be examined to see 3x3 screenshot.
                • +
                • Custom items system is back. If your item is not spawning or is missing icon, report it.
                • +
                • Alt job titles system is back. For noe medical titles (MD/Surgeon/EMT) and Detective/Foreniscs Tech.
                • +
                • ROBUSTING CHANGE: Disarming someone with gun in hand has chance that said gun will go off in random direction. With veruy real posibility of you getting shot.
                • +
                • FLYING BATON OF JUSTICE: Turned on stunbaton has 50% chance of stunning if thrown at someone.
                • +
                • Character medical and security records can again be set on char setup.
                • +
                • Vote window now will go away (thanks TG for fix)
                • +
                • Maybe something else, play and you will find.
                • +
                +
                + +
                +

                November 4th

                +

                SkyMarshal updated:

                +
                  +
                • Changed Grenade behavior to how it used to be.
                • +
                • Security HUDs now properly display job info.
                • +
                • PolyAcid is now slightly buffed, as it no longer has a pitiful 15% change of melting a helmet. (Guaranteed helmet-removal.)
                • +
                +
                + +
                +

                October 24th

                +

                Mij updated:

                +
                  +
                • Get ready for some xenoarch love! Re-added artifact and strange rock spawning at world gen.
                • +
                • Strange rocks react to fire only now, until I can hammer out how acid works. Technically acid does do something to them.... ;)
                • +
                • Re-added a number of mining/xenoarch related icons. Changed ore boxes to look prettier, like they used to.
                • +
                +
                + +
                +

                October 22nd

                +

                Cael_Aislinn updated:

                + +
                + +
                +

                October 18th

                +

                CIB updated:

                +
                  +
                • Added a new type of wound, internal wounds. These should later be treated with surgery, though for now bicardine works.
                • +
                • Appendicitis now has a fourth stage in which the appendix burst and an internal wound is inflicted.
                • +
                • The full body scanner is back.
                • +
                +

                Chinsky updated:

                +
                  +
                • Buffed up welder fuel tanks for all your nefarious needs.
                • +
                • Replaced evac hallway lights with less.. party ones.
                • +
                +
                + +
                +

                17.10.2012

                +

                CIB updated:

                +
                  +
                • Ported limb selection on startup. Note that this may still be bugged, so use at own risk.
                • +
                • You can now select opposite gender hairstyles.
                • +
                +

                Chinsky updated:

                +
                  +
                • Fixed arrivals announcment.
                • +
                • Slur will properly fade away with time now.
                • +
                • Anti-alco chem will get rid of slur now.
                • +
                • Throwing metal item at eletrified grilles and doors will cause them to spark.
                • +
                • Added forensics tech jackets.
                • +
                • Ported some hairstyles from pre-merge code.
                • +
                +
                + +
                +

                October 13th, 2012

                +

                Cael_Aislinn updated:

                +
                  +
                • Moderators are now being loaded correctly, and all broken admin and mod verbs should be functioning correctly. Misc other fixes and improvements.
                • +
                +

                CIB updated:

                +
                  +
                • Medical stack items(ointment, bandages) aren't instant anymore, but instead stop bleeding and speed up healing.
                • +
                • Cyborgs can now use :h to use their department channel.
                • +
                • Ported BS12 medbots. This means you now have to load them with a chemical, or otherwise they only have inaprovaline.
                • +
                • Ported the BS12 player info features.
                • +
                • Examine now only reveals whether someone is breathing(need to be 3 tiles away or closer). Check pulse from 1 tile distance.
                • +
                • Ported bleeding. Bleeding can be stopped by applying a bandage.
                • +
                • Small delay for chloral hydrate and sleep toxin to take effect.
                • +
                +
                + +
                +

                October 12th, 2012

                +

                Cael_Aislinn updated:

                +
                  +
                • Merge current BS12 code with /tg/station's rev4847. Thanks for everyone who's been posting issues and bugs to the PiratePad issue tracker (see also here for general discussion and criticisms).
                • +
                • See https://code.google.com/p/tgstation13/source/list for tg's changelog. This is recommended reading for anyone interested in any changes, be warned there's a lot of them.
                • +
                +
                + +
                +

                October 9th, 2012

                +

                Cael_Aislinn updated:

                +
                  +
                • The merge code is now stable and playable (diag click only has been fixed, among other things). Hopefully, more playtesting will be taking place over the next few weeks.
                • +
                +
                + +
                +

                September 26th, 2012

                +

                Cael_Aislinn updated:

                +
                  +
                • Multiple bugfixes and tweaks in response to the testing session a few days ago have been put in place. For more details, see the piratepad tracker (TG also has broken underwear, we're awaiting a fix from them for it).
                • +
                +
                + +
                +

                September 24th, 2012

                +

                Cael_Aislinn updated:

                +
                  +
                • Engineering depressurisation during the test run was due to the singularity EMPing doors open. This is not a bug.
                • +
                +
                + +
                +

                September 23nd, 2012

                +

                Cael_Aislinn updated:

                +
                  +
                • The server map has now officially branched to tgstation2.0.9.1.dmm.
                • +
                +
                + +
                +

                August 22, 2012

                +

                Cael_Aislinn updated:

                +
                  +
                • This server is in the process of running a merge of BS12 and up to date TGcode. This is a significant update, and there will likely be several bugs coming with it. + See https://github.com/Baystation12/Baystation12/pull/1671 for more information.
                • +
                • The server is now running tgstation2.0.9.dmm. The station layout is functionally the same, but with significant additions from tg. Hopefully, the Antiqua will be ready soon.
                • +
                • Please report all bugs immediately, both in OOC and by making an issue at: https://github.com/Baystation12/Baystation12/issues/new
                • +
                +
                + +
                +

                15th August 2012

                +

                Cael_Aislinn updated:

                +
                  +
                • Readded changeling and traitorchan (traitor + changeling) to secret rounds, lowered probability of cult being chosen during secret rounds.
                • +
                +
                + +
                +

                7th August 2012

                +

                CIB updated:

                +
                  +
                • Wound descriptions now again are in sync with actual damage.
                • +
                • Bandages no longer are instant, but rather only stop bleeding and speed up the healing process.
                • +
                • Bleeding and regeneration speeds have been balanced, so that now it is possible to bleed out.
                • +
                +
                + +
                +

                4 August 2012

                +

                Cael_Aislinn updated:

                +
                  +
                • Ghosts and observers can now possess mice and inhabit the station as mortals once more. Be warned, in this form you will be unable to be cloned! (you can, however, jump back into ghost form as you like)
                • +
                + +

                FireFishie updated:

                +
                  +
                • Added Flashkirby99's tajaran sprites, but the accompanying hairstyles will have to wait for a tweak to genetics before being usable in-game. Apologies for not logging this change sooner.
                • +
                • By vote, the captain's armor is again space capable and the memo on his desk updated to reflect this.
                • +
                • The Captain now starts wearing matching gloves, jackboots, and a cap. The old Napoleonic hat can still be found in the secure locker.
                • +
                • The Head of Personnel now starts with a clipboard, but without body armor and a helmet. Both items can still be found in the secure locker for emergencies.
                • +
                • Cargo tech and shaft miner wardrobes now include fingerless gloves. Janitor wardrobes now includes a portalathe. Warden wardrobes now includes a jacket.
                • +
                • Medical, security, and tool-belts may now hold any lighter. Medical belts may now hold latex gloves and sterile masks. Security belts may now hold gas masks. Tool-belts may now hold cigarette packs.
                • +
                +
                + +
                +

                2 August 2012

                +

                Cael_Aislinn updated:

                +
                  +
                • Vermin such as mice and roaches will periodically spawn in maintenance and toilet areas across the station. Cats will hunt the mice, roaches can be stepped on and mousetraps will deal with both.
                • +
                +
                + +
                +

                10 July 2012

                +

                Abi79 updated:

                +
                  +
                • Removed the stun effect from artifacts.
                • +
                • Fixed the bug where helmets would not turn off when placed into backpacks.
                • +
                • Added more "cancel" buttons to various dialogs.
                • +
                + +

                CIB updated:

                +
                  +
                • Fixed the bug where the preview image in the character creation panel was broken.
                • +
                • Fixed the bug where you could only see if a player had no pulse when that player was ghosted or logged off.
                • +
                +
                + +
                +

                9 July 2012

                +

                CIB updated:

                +
                  +
                • Maintenance shafts are now safe places in the event of a radiation belt. This feature may be temporary until a better solution is found.
                • +
                +
                + +
                +

                5 July 2012

                +

                Cael_Aislinn updated:

                +
                  +
                • The Mining North Outpost has been repurposed as a research outpost, with a shuttle going back to the research division on the main station. The pneumatic transport chute is still available to transfer ore between this outpost and the mining one.
                • +
                • Shield generators now have circuitboards, and the capacitors should actually rotate now (both still have placeholder sprites though).
                • +
                +
                + +
                +

                3 July 2012

                +

                CIB updated:

                +
                  +
                • You can now select amputated and robot limbs in the character preferences. Note, though, that amputated limbs don't work properly yet.
                • +
                +
                + +
                +

                29 June 2012

                +

                Erthilo updated:

                +
                  +
                • Raises job limits for Botanists, Atmospheric Technicians, Roboticists, Chemists, and Geneticists.
                • +
                +
                +
                +

                28 June 2012

                +

                Chinsky updated:

                +
                  +
                • 'Rename' function for clipboards
                • +
                • Can add photos to clipboards
                • +
                • Fixed troubles with formatting when reading from clipboard (linebreaks not being properly placed)
                • +
                • Fixed photocopiers not copying photos properly
                • +
                +
                +
                +

                27 June 2012

                +

                Erthilo updated:

                +
                  +
                • Simple animals (like constructs) can properly emote using the Me verb now.
                • +
                • Body scanners now show a much more detailed readout on patients.
                • +
                • Wizard 'Mind Transfer' spell now requires full wizard garb to work.
                • +
                • Chairs without wheel will no longer move with fire extinguishers. BECAUSE I HATE FUN.
                • +
                • Gauze/kits/ointment now heal wounds instantly again. Gauze and ointment don't work below 50 health, advanced kits don't work below 0. This may be tweaked as necessary in future.
                • +
                • Stepping in pools of blood no longer leaves footprints due to lag issues.
                • +
                • Fixed batons hitting on all non-help intents. It'll now only do it on harm intent.
                • +
                • Fixed tape recorders not recording holopad speech.
                • +
                • Fixed random " on his head" messages in examine.
                • +
                • Fixed surgery, all surgical procedures should work again.
                • +
                • Fixes medical items. Gauze/kits/ointment can now be applied correctly again.
                • +
                +
                +
                +

                26 June 2012

                +

                TG updated:

                +
                  +
                • Fixed silicon mobs not being able to access newscaster.
                • +
                • Fixed harmbatons on everything other than harm, now it is the opposite way round.
                • +
                +
                + +
                +

                25 June 2012

                +

                Erthilo updated:

                +
                  +
                • People in critical (less than -50 health) from external trauma (100+ damage from brute and/or burn) bleeding, and with unsplinted limbs, will send a message to anyone trying to drag them, to warn them it would be a bad idea trying to move them. They will suffer a lot more damage if dragged while lying down.
                  The correct procedure is therefore, A) Bring a roller bed, or B) Splint all limbs, stop all bleeding with gauze, and then drag them.
                • +
                • Dragging someone while injured (brute) will have a small chance of injuring them further that increases depending on how damaged they are. This coincides with the blood spatters that are already generated.
                • +
                • Added splints that can be applied to broken arms and legs, and will reduce effects of broken limbs. These can be removed the same way as handcuffs. They show up on the mob and on examine.
                • +
                • Added an autoinjector that can only hold five units, but acts like a hypospray.
                • +
                • Added an advanced medical kit that Medical Doctors spawn with that has Advanced Trauma Kits, Advanced Burn Kits, autoinjectors, and splints.
                • +
                • Health Scanners now show unsplinted fractures ONLY in arms or legs.
                • +
                • Blood is now actually lost from the person being dragged.
                • +
                • Fixed CPR being performed at weird health levels.
                • +
                +

                Watermelon Storm updated:

                +
                  +
                • Added a medbay (with rolling beds) and a holding cell to the destination of the escape shuttle.
                • +
                +

                Drieden updated:

                +
                  +
                • The cargo bay now has a supply depot to store, sort, and dispense raw materials, and print shipping manifests.
                • +
                +
                + +
                +

                23 June 2012

                +

                SkyMarshal updated:

                +
                  +
                • ZAS now has different thresholds to move mobs and dense objects. A depressurising room at normal pressure will no longer turn lockers deadly.
                • +
                • ZAS now properly rebuilds zones, and connect/merge adjacent zones. This should be the final real bugfix to the system.
                • +
                • I have removed the aspects of the wound system causing the instant healing and, very likely, lag. This will result in wounds healing instantly again, but the computational overhead being significantly less.
                • +
                • The auto-targeting-mode for guns will now provide a different type of flavor text when it makes you fire, to make the situations that it occurs in to be less ambiguous.
                • +
                • UltraLight is in, but has some lighting bugs still remaining. This is the next thing I intend to tackle, bare with it please.
                • +
                +

                TG updated:

                +
                  +
                • Updated toilets. You can now crowbar open the cistern and hide stuff in there.
                • +
                • Omni-directional PA console! Never have to worry about rotating it again, because now it does it itself!
                • +
                • Players can fill their cigarettes with various chemicals and smoke them.
                • +
                • You can now click blocks to select them.
                • +
                • Areas have been redefined and renamed to make more logical sense (eg "Arrivals North Maintenance" instead of "Secondary Fore Port Maintenance"). Same has been done with Solars.
                • +
                • Scientists no longer start with gas masks and o2 tanks (Still available from the lockers).
                • +
                • Hydroponics trays are now unwrenchable.
                • +
                • The Experimental Welding Tool, rather than having a larger tank, will refill itself over time.
                • +
                • Borg diamond drills now properly dig sand.
                • +
                +
                + +
                +

                22 June 2012

                +

                Cael_Aislinn updated:

                +
                  +
                • A research laboratory has been constructed to store and catalogue xeno-archaelogical relics. Savvy anomalists are advised to supervise recovery efforts themselves, as unsubtle miners may damage delicate samples through not using the proper tools.
                • +
                +
                + +
                +

                18 June 2012

                +

                Cael_Aislinn updated:

                +
                  +
                • A discovery on a nearby asteroid has brought xeno-archaelogists flocking to the NSS Exodus in search of ancient treasures. Miners beware, these artifacts may be helpful or deadly! There is talk of establishing a permanent research position on the station in an attempt to study them (thanks to ISaidNo for original code).
                • +
                +
                + +
                +

                16 June 2012

                +

                Cael_Aislinn updated:

                +
                  +
                • Recent breakthroughs have brought shield generation technology to the NSS Exodus. External (hull) shield generators and capacitors may now be built, with appropriate circuitboards available from RnD.
                • +
                +
                + +
                +

                09 June 2012

                +

                Erthilo updated:

                +
                  +
                • Blobs have evolved! Their weaknesses/strengths are now randomised. Experimentation ahoy!
                • +
                • Meteors have been fixed, and will therefore appear again. Meteor mode works too.
                • +
                +
                + +
                +

                07 June 2012

                +

                SkyMarshal updated:

                +
                  +
                • ZAS now works properly. No perpetually leaking doors, no walls that hold air like a seive.
                • +
                • ZAS airflow is now enabled, and will move objects (AND PEOPLE!) when air moves with enough force. AIRLOCKS ARE NOW DEADLY DANGEROUS!
                • +
                • Packages will now reflect the size of what they contain
                • +
                +
                + +
                +

                06 June 2012

                +

                Erthilo updated:

                +
                  +
                • Tajaran's are more vulnerable to high temperatures and get hungry faster, but deal well with colder temperatures. Soghun's are more susceptible to cold temperatures, but get hungry much slower.
                • +
                • Skrell update! Adds Skrell as a whitelisted race. They have their own language which can be used by typing :k
                • +
                • Soghun get their own language by typing :o
                • +
                • Skintone and eye colour of most species can now be changed, The preview picture should be a fairly accurate representation of what you'll get in-game.
                • +
                • All valves in atmosperics now start off, instead of having to turn them off, then on again.
                • +
                • Soy sauce recipe change to soymilk + water pending better ideas.
                • +
                • Fixes pAI's universal translator not being universal.
                • +
                +
                + +
                +

                04 June 2012

                +

                TG updated:

                +
                  +
                • Added "Toggle Open" verb to all closets and crates
                • +
                • Added "Toggle Lock" verb to all lockable closets
                • +
                • Window doors are now breakable. They can still be emagged and hacktooled, and they have fairly high health.
                • +
                • Windoors are now constructable. See here for how to build them: http://baystation12.net/wiki/index.php/Construction#Window-door_.28Windoor.29
                • +
                • Lawyers can now access security records with their PDAs (read-only)
                • +
                • RIG suits have been renamed to hardsuits.
                • +
                +

                SkyMarshal updated:

                +
                  +
                • Added the capability for the security PDA to scan items in like the detectives scanner, and for it to be loaded into the database in the same manner.
                • +
                +

                Erthilo updated:

                +
                  +
                • You can now only build 2 cleanbots.
                • +
                • Fixed flavour text, it should now be possible to have it longer than 40 characters, and should stay properly formatted.
                • +
                • Fixes AI's not being able to talk through holopads.
                • +
                +
                + +
                +

                01 June 2012

                +

                Erthilo updated:

                +
                  +
                • Added character records. You can now add medical and security records to your character through Character Setup. These are official NanoTrasen records, and should be written as such. These will show up in-game on the medical and security records computers. Admins can 'jobban' people from records, so use them sensibly!
                • +
                • Added a megaphone to each Head's office. These broadcast messages in slightly larger font so you can be noticed. Please don't spam them.
                • +
                • Added Flashkirby's ERT suit sprites. Also tweaked ERT's loadout.
                • +
                +
                + +
                +

                29 May 2012

                +

                Aryn updated:

                +
                  +
                • Airflow works on a room-by-room basis rather than on individual tiles. Rooms will depressurize much faster than they did, though not too fast for balance reasons.
                • +
                • Fire now works on a logarithmic scale based on oxygen and fuel content. This is a far more complex tweak under the hood than it is in game.
                • +
                • Plasma now has increased toxicity and can burn exposed skin and eyes. In addition, because of the new air, it fills the room instantaneously. Try not to spill any.
                • +
                +
                + +
                +

                28 May 2012

                +

                Erthilo updated:

                +
                  +
                • Surgeons spawn with scrubs, Emergency Physicians spawn with first responder jackets.
                • +
                • Added water bottles to cola vending machines.
                • +
                • More HUD changes: https://dl.dropbox.com/u/4911517/ShareX/2012-05/2012-05-28_20-40-50.png
                • +
                +
                + +
                +

                27 May 2012

                +

                Abi79 updated:

                +
                  +
                • Money withdrawn from the ATM will now be worth the proper value.
                • +
                +

                Erthilo updated:

                +
                  +
                • Fixed PDA light not turning off when exploded by a detomax.
                • +
                • Fixes food not disappearing from hands when finished.
                • +
                • Fixed the bug where traitors would get an empty objectives list. Credit: thvortex.
                • +
                • New portalathe sprite, thanks to dezzmont and Furlucis.
                • +
                +
                + +
                +

                26 May 2012

                +

                Erthilo updated:

                +
                  +
                • Added Flashkirby's RIG and cow sprites!
                • +
                • Removed and added some new AI Ion laws, credit: Ispil.
                • +
                + +

                Abi79 updated:

                +
                  +
                • Everyone should now be able to see the properly formatted changelog.
                • +
                +
                + +
                +

                25 May 2012

                +

                Erthilo updated:

                +
                  +
                • Virologists get their fancy green jumpsuit/labcoat back, yay!
                • +
                • Emergency Medical Technician renamed to Emergency Physician to reinforce their doctorness.
                • +
                • Pill bottles now pick up pills correctly.
                • +
                +
                + +
                +

                24 May 2012

                +

                cib updated:

                +
                  +
                • Your nutrition now decreases at the same rate as before it was nerfed.
                • +
                • Low nutrition will now have a much smaller effect on your speed.
                • +
                • The hunger messages will start displaying a bit earlier.
                • +
                • A restart vote now calls the Crew Transfer Shuttle by default. A regular restart is still possible for the purpose of rebooting a glitched server.
                • +
                +
                + +
                +

                23 May 2012

                +

                CIB updated:

                +
                  +
                • Added Apple_Master's entertaining messages, which will pop up from time to time on low nutrition.
                • +
                +

                TG & Erthilo updated:

                +
                  +
                • New HUD Updates, see here: http://baystation12.net/forums/index.php/topic,4495.msg85026.html#msg85026 You can also pick from different styles of HUD again. Including new 'Midnight' blue.
                • +
                • RIG helmets can now be used as flashlights, just like hardhats
                • +
                • Medical borg overhaul. Instead of a dozen random one-use pills and syringes, they get an advanced hypospray that can switch between auto-replenishing tricordrazine, inprovaline, and spaceacillin.
                • +
                • Janitorborgs get a mop again, because without it they had no way of hitting anything.
                • +
                • Fixes robolimbs surgery.
                • +
                +
                + +
                +

                22 May 2012

                +

                cib updated:

                +
                  +
                • Worked out a few problems with meme. They now can see, even if their mob is sleeping. Their actions are properly tracked in admin logs. Their points recharge slightly faster, and can now be seen in the Status tab.
                • +
                +

                Erthilo updated:

                +
                  +
                • Some sleeping and resting fixes. Please report any more bugs with it!
                • +
                • Blood regeneration removed until errors can be fixed.
                • +
                • New in-hand sprites for shotgun! Credit to Flashkirby.
                • +
                • Money can now be split and stacked properly. Carry some with you! Still not used for anything!
                • +
                • Fixed an ATM exploit, thanks to BlackTea!
                • +
                +
                + +
                +

                21 May 2012

                +

                TG updated:

                +
                  +
                • The new 'sleek' user interface is going live. This is currently undergoing changes at TG, so this is mostly a test run. Resist, Sleep, and Rest have all been moved to the IC tab.
                • +
                • When you receive a PDA message, the content is displayed to you if the PDA is located somewhere on your person (so not in your backpack). You will also get a reply button there. This will hopefully make PDA communication easier.
                • +
                • New hotkeys: Delete is the 'stop dragging' button and insert cycles through intents.
                • +
                +

                SkyMarshal updated:

                +
                  +
                • Blood now regenerates if you're not bleeding.
                • +
                • Transformed changelings should no longer die from massive blood conflicts.
                • +
                +

                Uristqwerty updated:

                +
                  +
                • Added a minimap for AI's. Click on a location to jump to that area. Minimap image updates every 2 minutes.
                • +
                +

                Erthilo updated:

                +
                  +
                • Added implant removal. Steps are: Scalpel, Hemostat, Retractor, Hemostat (Might take a few goes!). Implants can then be loaded back into an implanter.
                • +
                • Made the damp rag stop causing attack messages. Also allows you to load it up with 5 units of something and smother people with it. Don't be sily now!
                • +
                • Added a Tajaran/Soghun whitelist. PM an admin on the forum for more details!
                • +
                • Fixed door accesses.
                • +
                +
                + +
                +

                20 May 2012

                +

                Erthilo updated:

                +
                  +
                • You can now right-click pick up items and open/close closets items. This means cyborgs can now open/close closets with a bit of fiddling!
                • +
                • Added confirmation pop-up for character slot deletion.
                • +
                +
                + +
                +

                19 May 2012

                +

                cib updated:

                +
                  +
                • Implemented Memetic Anomaly game mode. A meme is a kind of parasite that can live in a human host and jump from player to player. They have traitor-like objectives, but must achieve them by controlling hosts, rather than doing it themselves.
                • +
                • Credits for the idea goes to: SCP-1312-1 . Playtesters: Erthilo, Cael_Aislin, AfterShave and critica.
                • +
                +

                TG updated:

                +
                  +
                • You can now swap hands by clicking with your middle mouse button (you have to click on a visible object though, that's the catch).
                • +
                • Tweaked the DNA modifier consoles a little bit so that it's much easier to see individual blocks instead of one jumbled mess of hexadecimal.
                • +
                • You can now properly emag AI turret controls and commsat turret controls.
                • +
                • Brand new ending animations!
                • +
                • Buckling into an office chair and using a fire extinguisher will lead to interesting results.
                • +
                • Recipe updates for some booze in an attempt to resolve recipe conflicts.
                • +
                • Wallets now fit in pockets.
                • +
                • If you are clicking on a storage item in your pocket with an empty hand it will return that item to your hand.
                • +
                • Extinguishers now say when they are empty.
                • +
                • New sprites for Cargo, HoP, and Captain's lockers.
                • +
                • Removed hat storage as it was never used and it cluttered the UI.
                • +
                +
                + +
                +

                17 May 2012

                +

                TG updated:

                +
                  +
                • Added WJohnston's scrubs to Medical Doctor lockers.
                • +
                • Added two new syndicate bundles
                • +
                • Added WJohnston's CMO bio hood
                • +
                • Reduced cost of thermals to 3 telecrystals (formerly 4)
                • +
                • Singularity Beacons are now spawned from a smaller, portable device.
                • +
                • Large beaker cost reduced to 5000 glass
                • +
                • CMO and QM jumpsuits made more unique.
                • +
                • Updated Cargo Tech jumpsuit and sprite
                • +
                • Edited Warden's jumpsuit striping to match his jacket
                • +
                • Fixed misaligned downed sprites for HoS's coat
                • +
                +

                Erthilo updated:

                +
                  +
                • Roller beds are now collapsible, just like body bags! They don't fit in anything though.
                • +
                • New sounds for cable cuffs and table smashing.
                • +
                • Cable cuffs now have a proper sprite!
                • +
                • Adds camera film which can be used to refill cameras. Added to detectives wardrobe and arts and crafts crate. Credit to Flashkirby99
                • +
                • ATM's now require a pin which is generated on round start and stored in notes. Space cash renamed to stack of credits, and same value credits can be stacked together. Initial round credits are generated randomly between 500 to 2000 credits. Credits or coins can be inserted into ATMs and converted to credits. Still not used for anything! Credit to EditorRUS at Animus Station.
                • +
                • Fixes police tape not appearing on doors.
                • +
                +

                Abi79 updated:

                +
                  +
                • Fixed ID access requirements for the QM's office and the prison wing.
                • +
                +

                SkyMarshal updated:

                +
                  +
                • Metal foam now blocks air.
                • +
                +
                + +
                +

                16 May 2012

                +

                Erthilo updated:

                +
                  +
                • Hunger rate has been halved, and drinks no longer fill you up super fast. Most drinks will now keep your hunger stable. Eat food if you want to fill up!
                • +
                • Removed mining secret rooms due to them having some very silly things.
                • +
                • You can cut cable cuffs with wirecutters for quick removal.
                • +
                • Stops pod windows leaking air everywhere.
                • +
                +
                + +
                +

                15 May 2012

                +

                TG updated:

                +
                  +
                • Beakers, small and large can now be made/recycled in autolathes.
                • +
                • New PDA's for roboticists and shaft miners.
                • +
                • Nettles now do damage based on their potency.
                • +
                • Reinforced tables are now made with table parts + four rods, rather than plasteel.
                • +
                • New sprites for bomb suit, in-hands for pulse rifles, advances energyguns, and laser guns.
                • +
                • Fix for contraband crates being empty.
                • +
                +

                Erthilo updated:

                +
                  +
                • More customs!
                • +
                • New sprites for bomb suit, in-hands for pulse rifles, advanced energy guns, and laser guns. Credit to Flashkirby!
                • +
                • Allows AI to toggle saferty on and off, unless emagged.
                • +
                • Add ADVANCED INTERROGATION TECHNIQUES (smashing peoples faces with tables). Grab someone once and then click on a table. Don't abuse this!
                • +
                • Fixes sleep button not waking you up.
                • +
                • Fixes mech weapons not firing.
                • +
                • Added cable restraints, made from 15 lengths of cable coil by right-click a cable coil in-hand and choosing 'Make Cable Restraints'. These works just like handcuffs, but only take 30 seconds to break!
                • +
                • The Head of Personnel can now change alert levels.
                • +
                • Fixes lockdown computers being blank.
                • +
                +
                + +
                +

                13 May 2012

                +

                TG updated:

                +
                  +
                • Harebells can now be harvested.
                • +
                • New sprites for mass-spectrometers and advanced mass-spectrometers.
                • +
                • New sprites for the SMES. Credit to Flashkirby99!
                • +
                • New sound effects for circular saws and surgical drills.
                • +
                +
                + +
                +

                10 May 2012

                +

                Erthilo updated:

                +
                  +
                • Custom item updates!
                • +
                • Respawn should now work properly.
                • +
                • Even more customs!
                • +
                • Chemistry and Genetics is now strictly under the Chief Medical Officer. The Research Director no longer has access to chemistry.
                • +
                • You can now adjust breath masks to hang around your neck. Credit to Spamcat!
                • +
                +

                TG updated:

                +
                  +
                • New drinks recipes!
                • +
                • Different types of cigarettes added to contraband ordering.
                • +
                • Emergency Toolboxes now contain smaller, lighter fire extinguishers that actually fit inside them!
                • +
                • AIs and Cyborgs can now understand PAIs and MMIs.
                • +
                • Adminwho now shows admin ranks.
                • +
                • You can't pull things with missing hands anymore.
                • +
                • Nuke ops now spawn with an extended oxygen tanks.
                • +
                • Botany leather gloves can now remove lights without burning yourself.
                • +
                • New xeno sprites when running.
                • +
                • Piano is now a Minimoog!
                • +
                • Switched back to oldbody bag sprites.
                • +
                • New Oddyseus destroyed sprites.
                • +
                +
                + +
                +

                07 May 2012

                +

                TG updated:

                +
                  +
                • Added holodeck, can be used for a few interesting things, and possibly emagged for more nefarious purposes..
                • +
                • Added a brig prison wing. Accessible through the previous permacell, use this for permanent prisoners!
                • +
                • Added escape pods. These do not count towards escape alone, but otherwise work as escape shuttles. Two in arrivals, one in engineering, and on in security.
                • +
                • Added a new chemical: lipozine, a weight loss drug. Made with sodium chloride, ethanol, and radium.
                • +
                • You can build various upgrades for cyborgs, such as improved speed, from the fabricators.
                • +
                • AI can now ctrl-click APCs to turn them off.
                • +
                • AI can now track its cyborgs who speak on robotic talk.
                • +
                • Added a 'remove ID' verb to PDAs which attempts to remove the ID from a PDA. If your active hand is empty it puts it there, otherwise it puts it on the floor under you.
                • +
                • Tajaran can see in the dark.
                • +
                • Blind rune can no longer be made into a talisman.
                • +
                • Cyborgs now lose power much less quickly with no active modules. Active modules will drain charge more quickly though.
                • +
                • Mining cyborgs are now slightly more useful, having a much larger satchel, and an improved drill.
                • +
                • Constructs can now see who cultists are in cult mode.
                • +
                • Coffins are now sideways to better fit dead bodies.
                • +
                • People around you will no longer get a message when putting small items into storage items. Large items are unaffected.
                • +
                • New sprites for blob, PA, mech construction, field generators and power cells.
                • +
                +
                + +
                +

                06 May 2012

                +

                TG updated:

                +
                  +
                • Artificers can now create cult floors.
                • +
                • Added soil to plant seeds in. Make it by crushing up sandstone. Soil does not have indicators like trays do! Watch your plants carefully!
                • +
                • Added money trees. When life gives you lemons, mutate them into cash.
                • +
                • RnD can create a new tool for botanists: The floral somatoray. Has two modes. Use it on your plants to induce mutations or boost yield.
                • +
                • Added chawanmushi recipe and beet soup recipes.
                • +
                • Added 1% chance for a species mutation whenever a plant's stats mutate.
                • +
                • New PDAs for the botanists and librarian. Sprites for cartridges for both too.
                • +
                • You can now only have ONE decal of blood per tile. This is to fix the millions of blood effect items that spawned to lag anyone who right clicked them. The most recently created blood item will be the one that remains. This does not effect gibs.
                • +
                • Hand tools now fit on your belt slot.
                • +
                • Changelings faking death can no longer have their brains cut out.
                • +
                • Updated the barman's shotgun, it acts like a double-barrel now, and he can saw it off.
                • +
                • New sprites for lots of medical computers!
                • +
                • New carrot in-tray sprites.
                • +
                • Soulstones can no longer capture the manifested ghosts. No more infinite constructs.
                • +
                • Changes rev objectives to use the proper objective so heads being off station actually works.
                • +
                +
                + +
                +

                05 May 2012

                +

                Erthilo updated:

                +
                  +
                • Increases maximum brig timers to 60 minutes. This coincides with a new test version of Space Law. See here: http://baystation12.net/wiki/index.php/Space_Law or in-game Space Law books.
                • +
                +
                + +
                +

                04 May 2012

                +

                dopeghoti updated:

                +
                  +
                • Fixes AI-less Cyborgs having Asimov laws.
                • +
                +
                + +
                +

                03 May 2012

                +

                TG updated:

                +
                  +
                • CONTRABAND-CON UPDATE: Added posters.
                • +
                • POSTERS! Posters come in rolled packages that can adhere to any wall or r_wall, if it's uncluttered enough. +

                  ?How they get on-board: The quartermaster can now set the receiver frequency of his supplycomp circuit board. A bit simplistic as of now, will work on it later. Building a supplycomp with a properly set up circuitboard will give access to the Contraband crate. +

                  ?How they're used: Unfold the rolled poster on any wall or r_wall to create the poster. There are currently 17 designs, with the possibility of me adding more. +

                  ?How to get rid of them: You can rip them using your hand... To cleanly extract them and not ruin them for future use, however, you can use a pair of wirecutters. +

                  ?How they're classified: They're contraband, so it's perfectly okay for security officers to confiscate them. Punishment for contraband-providers (or end-users, if you want to go full nazi) is up to the situational commanding officers. +
                • Merged 'Game' and 'Lobby' tabs during pre-game into one tab
                • +
                • Added the little red x to the late-join job list
                • +
                • Late-joiners are warned if the shuttle is past the point of recall, and if the shuttle has already left the station
                • +
                • Late-joiners now see how long the round has been going on.
                • +
                • Droppers are now used at the eyes, and thus, access to the eyes is required to have an effect.
                • +
                • Mining shuttle computer no longer spits out both 'Shuttle has been sent' and 'The shuttle is already moving' every time.
                • +
                • Adds a borg upgrade that increases their speed. Requires gold.
                • +
                • Fixes autolathes not doing anything.
                • +
                • Changed Chief Engineers Office door name. Stop breaking in!
                • +
                • Added new airlocks to mining dock, research, and atmospherics.
                • +
                • RCDs are disabled if they are used on the escape shuttle or hyperspace around it.
                • +
                • EMPs will now cause flashes to flash their holder.
                • +
                • Heads now get a silver ID!
                • +
                • Blenders can now be filled directly from plant bags. Chefs rejoice.
                • +
                • The biogenerator is now more robust. It can dispense fertilizer in batches, and make simple leather items at a high cost. Added more wood items for tower cap wood construction: Wooden doors and sandals. Added plump helmet biscuits and mushroom soup to kitchen recipes.
                • +
                • Watermelon and pumpkin biomass lowered a bit so biomass isn't totally trivial to acquire.
                • +
                +
                + +
                +

                2nd May 2012

                +

                TG updated:

                +
                  +
                • Added carved pumpkins/jackolanterns. Carve them with any of the usual things you use to carve things. They work similarly to hardhats.
                • +
                • Added pumpkin pie and slices. Made with 5 milk, 5 sugar, 1 pumpkin, 1 flour, 1 egg.
                • +
                • Eating corn now makes corn cobs. Carve them with a saw, a knife, or a hatchet to make a corncob pipe.
                • +
                • Added the bit of transparency to biohelmets that they were always supposed to have.
                • +
                • Adds randomlly spawning rooms to the mining asteroid that contain various goodies.
                • +
                • Adds a borg upgrade system. Can be used to reset modules or 'restart' dead cyborgs.
                • +
                • Officers can now use huds to modify humans' criminal statuses on the go. To do this, simply examine a human and at the end should be a clickable link to change the status.
                • +
                • Cell charger and Recharger are now wrenchable to make them moveable
                • +
                • Cats and Dogs can see in the dark.
                • +
                • Changed around a few access levels; only jobs who need to do maintenance have access to maintenance tunnels. Also the heads and detective.
                • +
                • Shuttle call/recall announcements are now more noticeable.
                • +
                • Changes changling unstun time to 45 from 25
                • +
                • Can now repair the first stage of deconstruction of rwalls with metal rods.
                • +
                • Library machine now has a delay when printing bibles to prevent spam.
                • +
                • Bugfix to the 'resist' button, unless I don't understand how it works. I don't see how it could have ever worked before.
                • +
                • You can no longer toggle the welding helmet when stunned or restrained.
                • +
                • Fix for not being able to use pills as pill-satchels properly.
                • +
                +

                Erthilo updated:

                +
                  +
                • Increases time between random events happening in low population round to a maximum of double. Random events are more likely to happen up to a limit of around 30 active players. Events now fire at the same rate as previously with around 20~ active players. Please report unusually high or low amounts of events on the bug tracker!
                • +
                +
                + +
                +

                1st May 2012

                +

                Mloc updated:

                +
                  +
                • Added extra data to ID cards. Fingerprint, blood type, and DNA. Can all be changed in ID computer.
                • +
                +

                Erthilo updated:

                +
                  +
                • You can now respawn after 30 minutes in any mode where the win/loss condition is not all crew dead.
                • +
                • New in-hand sprites for energy and taser guns courtesy of Flashkirby99.
                • +
                • Fixes emagging doors.
                • +
                • NT has recently upgraded their anti-telepathy double glazing. As such, you can no longer remote view people on any level except the station or the mining asteroid!
                • +
                • As a side effect of the above, remote viewing and telekinesis cannot be used at the same time.
                • +
                +
                + +
                +

                30th April 2012

                +

                Mloc updated:

                +
                  +
                • Due to new NT hiring protocols, characters can now only be between the ages of 20-65 instead of 15-45.
                • +
                +

                Erthilo updated:

                +
                  +
                • Switched to /tg/'s changelog format! Previous updates can be found here: http://baystation12.net/wiki/index.php/Changelog
                • +
                • New green alt satchel for Botanists.
                • +
                • Cyborgs can now view crew manifest and also state laws.
                • +
                • New ATM sprites.
                • +
                • Changes year to 2556 on medical/security records.
                • +
                +

                TG updated:

                +
                  +
                • The escape shuttle will now spend two minutes travelling to CentCom, woo! Objectives are only complete when the shuttle reaches CentCom, and anyone leaving the shuttle during transit time will be lost in deep space! Also, anyone standing in the way of the shuttle when it arrives will be gibbed.
                • +
                • Added Antimov module. Very dangerous.
                • +
                • Pill bottles now work like ore satchels, click a tile full of pills to pick them all up.
                • +
                • Tower caps can now grow randomly as weeds
                • +
                • Using a minihoe on a Hydroponics tray removes all the weeds in the tray at once. Using a bucket on a sink now fills it entirely with water, instead of 10 units at a time.
                • +
                • You can no longer take photos of photos.
                • +
                • Malf AI's hopping between APCs no longer become longer and longer.
                • +
                • Secborgs now have modified tasers, it holds 6 shots and recharges one shot every 10 seconds automatically.
                • +
                • Turning off PANIC SYPHON now sets scrubbers to scrubbing (default) instead of off. Vents will not appear in the list instead of a timeout message. They also have a link with sets them back to one atmosphere kPa.
                • +
                • You now click on AI modules in-hand to set them, instead of just picking them up.
                • +
                • Fixes the way the safeguard module is written.
                • +
                +
                + +
                +

                TG

                +

                29th April 2012 updated:

                +
                  +
                • Added new sprites for Killer Tomatoes.
                • +
                • Added lasertag vests, guns, projectiles. Sprites for the vests and guns from Muncher. Not actually mapped in. Lasertag guns are only usable if you're wearing the appropriate team vest. Lasertag projectiles will only stun people who are wearing vests belonging to the opposing team.
                • +
                • Adds Holodeck, also not mapped in.
                • +
                • Janitor borgs have been massively upgraded. They now clean as they move around.
                • +
                • Mining shuttle now shunts people where it wants to be. Shuttles now crush people if they fail to move out of where they want to be with the initial shunt.
                • +
                • Adds Halloss (Hallucination Damage) as a damage type weapons can do. Halloss can be healed by sleeping.
                • +
                • Windows can only be damaged by weapons that do brute or burn.
                • +
                • HUD damage indicator now updates with halloss. Inspecting yourself for organ damage now randomly shows damaged organs if you have halloss.
                • +
                • Nuke disk now respawns in all rounds.
                • +
                • Pinpointers now show the remaining time until a nuke goes off if it's been armed when examined.
                • +
                • Instead of z-level transition happening when you reach the edge of the map, it will now happen 7 tiles away from the edge. This means that you will no longer see the black edge, transition will likely happen without you even noticing.
                • +
                • Slight changes to examine messages. You cannot examine when blind/unconscious.
                • +
                • More new locker sprites!
                • +
                • Fixes glass knock sound having a pop at the end of it.
                • +
                • Telecomm traffic control now has its own circuitboard and doesn't transform into a server when the monitor is disconnected/reconnected.
                • +
                • Using an igniter on a flamethrower that already has one attached no longer uses up the igniter.
                • +
                • NTSL bugfixes.
                • +
                +
                \ No newline at end of file diff --git a/html/browser/common.css b/html/browser/common.css new file mode 100644 index 00000000..afd99a69 --- /dev/null +++ b/html/browser/common.css @@ -0,0 +1,323 @@ +body +{ + padding: 0; + margin: 0; + background-color: #272727; + font-size: 12px; + color: #ffffff; + line-height: 170%; +} + +hr +{ + background-color: #4e686d; + height: 1px; +} + +a, a:link, a:visited, a:active, .linkOn, .linkOff, input +{ + color: #ffffff; + text-decoration: none; + background: #4e686d; + border: 1px solid #161616; + padding: 1px 4px 1px 4px; + margin: 0 2px 0 0; + cursor:default; + white-space:nowrap; +} + +a:hover +{ + color: #4e686d; + background: #ffffff; +} + +a.white, a.white:link, a.white:visited, a.white:active +{ + color: #4e686d; + text-decoration: none; + background: #ffffff; + border: 1px solid #161616; + padding: 1px 4px 1px 4px; + margin: 0 2px 0 0; + cursor:default; +} + +a.white:hover +{ + color: #ffffff; + background: #4e686d; +} + +.linkOn, a.linkOn:link, a.linkOn:visited, a.linkOn:active, a.linkOn:hover +{ + color: #ffffff; + background: #af6e3b; + border-color: #202020; +} + +.linkOff, a.linkOff:link, a.linkOff:visited, a.linkOff:active, a.linkOff:hover +{ + color: #ffffff; + background: #999999; + border-color: #666666; +} + +a.icon, .linkOn.icon, .linkOff.icon +{ + position: relative; + padding: 1px 4px 2px 20px; +} + +a.icon img, .linkOn.icon img +{ + position: absolute; + top: 0; + left: 0; + width: 18px; + height: 18px; +} + +ul +{ + padding: 4px 0 0 10px; + margin: 0; + list-style-type: none; +} + +li +{ + padding: 0 0 2px 0; +} + +img, a img +{ + border-style:none; +} + +h1, h2, h3, h4, h5, h6 +{ + margin: 0; + padding: 16px 0 8px 0; + color: #517087; +} + +h1 +{ + font-size: 15px; +} + +h2 +{ + font-size: 14px; +} + +h3 +{ + font-size: 13px; +} + +h4 +{ + font-size: 12px; +} + +.uiWrapper +{ + + width: 100%; + height: 100%; + padding-top:32px; +} + +.uiTitle +{ + clear: both; + padding: 6px 8px 6px 8px; + border-bottom: 2px solid #161616; + background: #383838; + color: #98B0C3; + font-size: 16px; +} + +.uiTitleWrapper + { + position:fixed; + top:0px; + left:0px; + right:0px; + z-index: 10 + } + + .uiTitleButtons + { + position:fixed; + top:0px; + right:0px; + height:32px; + z-index:11; + } + + +.uiTitle.icon +{ + padding: 6px 8px 6px 42px; + background-position: 2px 50%; + background-repeat: no-repeat; +} + +.uiContent +{ + clear: both; + padding: 8px; + font-family: Verdana, Geneva, sans-serif; +} + +.good +{ + color: #00ff00; +} + +.average +{ + color: #d09000; +} + +.bad +{ + color: #ff0000; +} + +.highlight +{ + color: #8BA5C4; +} + +.dark +{ + color: #272727; +} + +.notice +{ + position: relative; + background: #E9C183; + color: #15345A; + font-size: 10px; + font-style: italic; + padding: 2px 4px 0 4px; + margin: 4px; +} + +.notice.icon +{ + padding: 2px 4px 0 20px; +} + +.notice img +{ + position: absolute; + top: 0; + left: 0; + width: 16px; + height: 16px; +} + +div.notice +{ + clear: both; +} + +.statusDisplay +{ + background: #000000; + color: #ffffff; + border: 1px solid #4e686d; + padding: 4px; + margin: 3px 0; +} + +.block +{ + padding: 8px; + margin: 10px 4px 4px 4px; + border: 1px solid #4e686d; + background-color: #202020; +} + +.block h3 +{ + padding: 0; +} + +.progressBar +{ + width: 240px; + height: 14px; + border: 1px solid #666666; + float: left; + margin: 0 5px; + overflow: hidden; +} + +.progressFill +{ + width: 100%; + height: 100%; + background: #4e686d; + overflow: hidden; +} + +.progressFill.good +{ + color: #ffffff; + background: #00ff00; +} + +.progressFill.average +{ + color: #ffffff; + background: #d09000; +} + +.progressFill.bad +{ + color: #ffffff; + background: #ff0000; +} + +.progressFill.highlight +{ + color: #ffffff; + background: #8BA5C4; +} + +.clearBoth +{ + clear: both; +} + +.clearLeft +{ + clear: left; +} + +.clearRight +{ + clear: right; +} + +.line +{ + width: 100%; + clear: both; +} + +.statusDisplay +{ + background: #000000; + color: #ffffff; + border: 1px solid #4e686d; + padding: 4px; + margin: 3px 0; +} diff --git a/html/browser/cryo.css b/html/browser/cryo.css new file mode 100644 index 00000000..05e9746a --- /dev/null +++ b/html/browser/cryo.css @@ -0,0 +1,11 @@ +.statusLabel +{ + width: 128px; + float: left; + overflow: hidden; +} + +.statusValue +{ + float: left; +} diff --git a/html/browser/scannernew.css b/html/browser/scannernew.css new file mode 100644 index 00000000..a2c404b2 --- /dev/null +++ b/html/browser/scannernew.css @@ -0,0 +1,25 @@ +.getblockstring +{ + font-family: Fixed, monospace; +} + +.blockString +{ + width: 55px; + height: 19px; + padding: 0 8px 8px 0; + float: left; +} + +.statusLabel +{ + width: 128px; + float: left; + overflow: hidden; +} + +.statusValue +{ + float: left; +} + diff --git a/html/browser/sleeper.css b/html/browser/sleeper.css new file mode 100644 index 00000000..05e9746a --- /dev/null +++ b/html/browser/sleeper.css @@ -0,0 +1,11 @@ +.statusLabel +{ + width: 128px; + float: left; + overflow: hidden; +} + +.statusValue +{ + float: left; +} diff --git a/html/bug-minus.png b/html/bug-minus.png new file mode 100644 index 00000000..9934db40 Binary files /dev/null and b/html/bug-minus.png differ diff --git a/html/burn-exclamation.png b/html/burn-exclamation.png new file mode 100644 index 00000000..b2a4f670 Binary files /dev/null and b/html/burn-exclamation.png differ diff --git a/html/changelog.css b/html/changelog.css new file mode 100644 index 00000000..650a5df3 --- /dev/null +++ b/html/changelog.css @@ -0,0 +1,78 @@ +body{font-family:Tahoma,sans-serif;} +.top{font-size:12px;} +a img {border:none;} +.bgimages16 li { + padding:2px 10px 2px 30px; + background-position:6px center; + background-repeat:no-repeat; + border:1px solid #ddd; + border-left:4px solid #999; + margin-bottom:2px; +} +.bugfix {background-image:url(bug-minus.png)} +.wip {background-image:url(hard-hat-exclamation.png)} +.tweak {background-image:url(wrench-screwdriver.png)} +.soundadd {background-image:url(music-plus.png)} +.sounddel {background-image:url(music-minus.png)} +.rscdel {background-image:url(cross-circle.png)} +.rscadd {background-image:url(tick-circle.png)} +.imageadd {background-image:url(image-plus.png)} +.imagedel {background-image:url(image-minus.png)} +.spellcheck {background-image:url(spell-check.png)} +.experiment {background-image:url(burn-exclamation.png)} +.balance {background-image:url(scales.png)} +.maptweak {background-image:url(map-pencil.png)} +.sansserif {font-size:12px;} +.commit { + margin-bottom:20px; + font-size:100%;font-weight:normal; +} +.changes { + list-style:none; + margin:5px 0; + padding:0 0 0 25px; + font-size:0.8em; +} +.date { + margin:10px 0; + color:blue; + border-bottom:2px solid #00f; + width:60%; + padding:2px 0; + font-size:1em; + font-weight:bold; +} +.author { + padding-left:10px; + margin:0; + font-weight:bold; + font-size:0.9em; + } +.drop { + cursor:pointer; + border:1px solid #999; + display:inline; + font-size:0.9em; + padding:1px 20px 1px 5px; + line-height:16px; +} +.hidden {display:none;} +.indrop { + margin:2px 0 0 0; + clear:both; + background:#fff; + border:1px solid #ddd; + padding:5px 10px; + } +.indrop p { + margin:0; + font-size:0.8em; + line-height:16px; + margin:1px 0; +} +.indrop img { + margin-right:5px; + vertical-align:middle;} +.closed {background:url(chevron-expand.png) right center no-repeat;} +.open {background:url(chevron.png) right center no-repeat;} +.lic {font-size:9px;} diff --git a/html/changelog.html b/html/changelog.html new file mode 100644 index 00000000..44677141 --- /dev/null +++ b/html/changelog.html @@ -0,0 +1,570 @@ + + + + Changelog + + + + + + +
                + + + +Warfare Development Team +
                + Coders: Matt. With some help from: CthulhuOnIce and Quotesman
                + Sprites by: Erin, Fridge, Tech, Javilen, Bimmer, Dongwaiver, 3rd Trooper Hsu, Lord Brandon, Undud, Gonzo
                + Some sprites and items used from: Fields of Fire, Polar Station +
                + +THIS CHANGELOG IS HORRIBLY OUT OF DATE AND ONLY ACCURATE UP TO AUGUST! PLEASE VISIT THE DISCORD FOR THE FULL UP TO DATE CHANGELOG! + +IN THE EVENT THAT THE DISCORD IS GONE AND YOU'RE STILL SOMEHOW PLAYING THIS... WELL YOU SHIT OUTTA LUCK I GUESS. + +
                +

                AUGUST 2019

                +
                  +
                • Jumping now consumes much more stamina.
                • +
                • Minimum soldier strength buffed to something more reasonable.
                • +
                • Shovels now have unique hit, swing, and drop sounds.
                • +
                • Disarming mines now has a different sound than them being armed.
                • +
                • The strip menu no longer re-appears after you close it.
                • +
                • Stripping people no longer annoyingly puts items in your hand, you can stack stripping items now.
                • +
                • Reverted bandage change because it's broken
                • +
                • EXPERIMENTAL GAME CHANGING CHANGE: You can NO LONGER capture the enemy trenches unless you control the middle bunker area first. This will stop turbo nerd powergamers from sneaking across no man's land roundstart to try to cap trenches. This should also give both sides a good idea if they should be attacking or defending based on whether or not they control the middle point.
                • +
                • Splinted bones no longer jostle.
                • +
                • Splinted organs now appear when you check yourself for injuries and examine other people.
                • +
                • Examining someone who is wielding a weapon in both hands will no longer tell you they are holding an "offhand".
                • +
                • You can now buy a crate of shovels from cargo.
                • +
                • Sewing up wounds has proper grammar at last.
                • +
                • Amount of ammo you get for other supply packs has been increased.
                • +
                • Prices for shotgun and shotgun ammo have been tweaked.
                • +
                • Checking health actually properly tells you if you have bullet shrapnel in you.
                • +
                • Trenches have been completely remapped. They are now two separate trenches, making them both much easier to defend, and also a bit easier to take if there are no defenses. The MGs are now located in a pillbox, just like in real WW1.
                • +
                • You can no longer respawn if you lose all your trenches.
                • +
                • New sprites for syringes.
                • +
                • Crit failing unarmed should work again.
                • +
                • Kicking is no longer insanely overpowered, and properly scales with your strength.
                • +
                • Children are no longer hardcore.
                • +
                • Children are now warned about how using guns will kill them.
                • +
                • Unarmed melee properly checks skills again. Kids should no longer be killing machines in unarmed melee.
                • +
                • Activating the point of no return now has a sound again.
                • +
                • EXPERIMENTAL: Soldiers can no longer see how many reinforcements are left.
                • +
                • One dose of Tramadol is now no longer enough to put you over the painkiller effectiveness dose.
                • +
                • Curtains are now anchored.
                • +
                • Taking a large dose of pain medication will now severely hamper your combat effectiveness.
                • +
                • You can no longer kick in crit.
                • +
                • You can no longer spam and instantly break limbs with grabs.
                • +
                • Officer cap is now worth 500 cargo points, considering how rare it is.
                • +
                • Suit sensors are no longer a thing.
                • +
                • Ashrooms are now anchored.
                • +
                • You can now feed the officer cap of the enemy to the cargo machine for 300 points.
                • +
                • Trying out a new outfit for practioners.
                • +
                • Minimum strength for practioners bumped.
                • +
                • You can no longer c4 the point of no return, breaking the entire fucking round.
                • +
                • Repairing now uses correct grammar.
                • +
                • Added some new emojis.
                • +
                • Captains now get swanky officer caps instead of helmets.
                • +
                • You can no longer respawn instantly if your head has been gibbed.
                • +
                • Trench axe and sentry armor have been added, though they do not spawn anywhere yet.
                • +
                • Barbwire now has a different item sprite than placed sprite.
                • +
                • Added motivational posters for red and blue.
                • +
                • The health analyzer now displays blood type.
                • +
                • The health analyzer now shows where shrapnel is located, as does examining your own health.
                • +
                • Digging speed now scales with your engineering skill. Engineers dig much faster than soldiers.
                • +
                • Cleaned up dreams.
                • +
                • You now recover from being thirsty quicker.
                • +
                • You can now right click on dirt barricades with a shovel to repair them.
                • +
                • Threatening and waving have proper colors again.
                • +
                • You can now activate a bottle in your hand to immediately remove a pill.
                • +
                • Red font is now slightly less bright and harsh on the eyes.
                • +
                • Checking your health now tells if you if conscious, unconscious, dying, or alive.
                • +
                • Fixovien is back in the surgery supplies.
                • +
                • Emoji work in the OOC again.
                • +
                • Fixed panic bunker.
                • +
                • Attacking yourself no longer counts as friendly fire.
                • +
                • My own custom goonchat system has been added.
                • +
                • Drinking water now replenishes stamina.
                • +
                • Eye meta has been removed.
                • +
                • Chests and heads can now be splinted.
                • +
                • If you respawn after you die you will automatically be given a different name.
                • +
                • Cigarettes and booze will now give you a better mood boost.
                • +
                • New drinking sounds.
                • +
                • Fixes metal barricade exploit.
                • +
                • People who are dead or unconscious will no longer look stressed.
                • +
                • You can no longer spam digging cover.
                • +
                • You can now buy booze from cargo.
                • +
                • Shrapnel removal won't break your limbs anymore.
                • +
                • Skill requirements for laying down barbwire have been lowered (since it's very rare that barbwire is used).
                • +
                • You can now dig up mines after they've been disarmed.
                • +
                • Health scanners now have way more useful information in them, such as where arterial bleeding and broken bones are located.
                • +
                • You can now use Shift+F to look up in hotkey mode.
                • +
                • Max human age has been lowered to something more reasonable.
                • +
                • Sutures make sound now.
                • +
                • There is now a sound for the point of no return notification.
                • +
                • There is now a sound signaling the end of the round.
                • +
                • You can now cut down ash mushrooms with a knife or other sharp object.
                • +
                • Medics now have unique jackets.
                • +
                • You can now buy Warmongers and Warmonger ammo from cargo.
                • +
                • You will no longer spawn in without a headset as SL.
                • +
                • The limit on scav roles has been upped, considering their importance to the economy now.
                • +
                + +

                JULY 2019

                +
                  +
                • Combat mode now makes you much more accurate.
                • +
                • Fixed awkward placement of "THEY ARE THE ENEMY".
                • +
                • Combat mode draining has been fixed. It will now drain correctly. It can now consume almost all your stamina, don't leave it on forever.
                • +
                • You can no longer accidentally hit people with wire cutters.
                • +
                • Wheelchairs and crutches have been added to medbay, for people who break their legs.
                • +
                • You can now buy cigarettes, first aid kits, and other medical supplies from cargo.
                • +
                • Available is now spelled correctly on the cargo menu.
                • +
                • Ripping out shrapnel now opens wounds of they're closed. Do it before you patch them up.
                • +
                • The wound must now be opened before you can use sutures to stop the internal bleeding.
                • +
                • Ticket wins are now a minor victory.
                • +
                • You will no longer pass out from being slightly thirsty.
                • +
                • Prep time is now 10 minutes instead of 5. Since there's more to prep.
                • +
                • You can now dump ammo from the revolver by clicking on it.
                • +
                • Cargo is finally done and in. Feed the cargo supply computer teeth, enemy dog tags, and enemy helmets to give it points. You can currently purchase: Ammo, Guns (including the very expensive shotgun), medical supplies, and misc supplies (such as gas mask).
                • +
                • You can now tell if someone is the enemy no matter the distance.
                • +
                • Diagonal movement has been nixed until I can come up with a better solution that doesn't lag everything.
                • +
                • Fort roles can now enter friendly trenches, but cannot enter no man's land.
                • +
                • Medics and practioners now start with a medical belt that can hold all their vital supplies.
                • +
                • Medics and Practioners get a new starting loadout. They now start with all the tools necessary to repair and revive a shot man.
                • +
                • You can now remove bullet shrapnel with wirecutters.
                • +
                • Sutures actually work now. They will fix arteries if they are cut, and sew up wounds if they are not.
                • +
                • Storage UI has been fixed for the surgery bag.
                • +
                • You can no longer throw grenades infinitely far.
                • +
                • Fixed "talks but you cannot hear ." Now it properly displays "talks but you cannot hear them."
                • +
                • Kids now can strip dead bodies very quickly.
                • +
                • The kitchen finally gets salt and pepper. I'm sorry this took so long.
                • +
                • Scouts have been replaced with scavengers.
                • +
                • Captain now gets binoculars.
                • +
                • Shotgun and shotgun ammo has been removed. Replaced with SMGs for engineers. Captain now gets a revolver, it doesn't get any extra ammo so don't go rushing into combat.
                • +
                • Matches no longer cause you to scream in agony.
                • +
                • You can now place barbed wire on top of items.
                • +
                • Guns are now more accurate.
                • +
                • Cleaning your gun has been changed to "repairing" your gun to better reflect what it actually does.
                • +
                • Guns will now only go off when they are actually dropped on the ground, not when you take them out of your inventory.
                • +
                • Fixed a bug where you couldn't spawn in after the round restarted.
                • +
                • Examining your gun now tells you whether or not a round is in the chamber, and whether or not it's live.
                • +
                • You can now use SHIFT+Z to toggle gun safety in hotkey mode.
                • +
                • Mines are now much more deadly.
                • +
                • You can now lie down and surrender.
                • +
                • You can no longer move and look up at the same time. Moving resets your view.
                • +
                • Fixed bug where people standing on dirt mounds instead of behind them couldn't get shot.
                • +
                • Map has been made narrower to more centralize the action.
                • +
                • Smooth movement still has too many issues, it's been reverted.
                • +
                • Shotguns range has been nerfed.
                • +
                • Point Of No Return is now 45 seconds instead of 1 minute.
                • +
                • Smooth movement is in.
                • +
                • Crit failing dodges has been removed. Dodging is now slightly more viable.
                • +
                • Trench clubs and bayonets have been buffed appropriately to compensate.
                • +
                • Swords have been removed.
                • +
                • Pulling people no longer gives you a message about it hurting them, since it doesn't hurt them.
                • +
                • Hands and legs are able to be broken again.
                • +
                • EXPERIMENTAL: Removed the "ready up" button and just replaced it with join game, that way people in the lobby won't have to click the join game button twice to get the menu up.
                • +
                • You can no longer choose which team you want to be on, the game will decide for you.
                • +
                • EXPERIMENTAL: The amount of starting ammo has been lowered.
                • +
                • Skybox gc runtime edge case has been fixed.
                • +
                • Reinforcements are now at 50 instead of 60.
                • +
                • Some new achievements can be unlocked.
                • +
                • EXPERIMENTAL: You can no longer slice people in half!
                • +
                • Engineers now get place-able barbed wire.
                • +
                • Due to no longer being able to be gibbed, you now have a better chance of hitting a limb.
                • +
                + +

                JUNE 2019

                +
                  +
                • Hands, arms, legs and feet can no longer be gibbed. Severed? Yes. Broken? Yes. But gibbed? No.
                • +
                • Aspect system implemented, but it won't run every single round, it only has a chance to run. This should keep things from getting dull.
                • +
                • Mortars will fling shrapnel again.
                • +
                • Thirst has been nerfed a bit, you start out with more water in your system now.
                • +
                • Stamina drains slightly quicker in combat mode.
                • +
                • Aspect system has been revamped but is not enabled. Might be soon though. Stay tuned.
                • +
                • Fort roles get satchels now.
                • +
                • Some accuracy changes to targeting limbs with guns.
                • +
                • Fixed CPR.
                • +
                • Finally actually fixes dead people breathing.
                • +
                • Practioners get white gloves now.
                • +
                • Hand meta has been nerfed.
                • +
                • Rifles and shotguns capacity increased to five, from four.
                • +
                • You can now build dirt cover ontop of blood and other items/decals.
                • +
                • You can no longer disarm disarmed mines.
                • +
                • Fort roles get canteens now.
                • +
                • You can no longer wear the outfit of the opposite team.
                • +
                • You can no longer perform CPR on yourself.
                • +
                • Losing limbs makes you drop what you're holding.
                • +
                • Dead bodies, and people wearing gas masks will no longer having the cold breath animation.
                • +
                • You can no longer succumb to death continuously.
                • +
                • Reinforcements doubled to 60, from 30. Should hopefully make rounds last slightly longer.
                • +
                • You can now wear dog tags without uniform.
                • +
                • Lying down now unzooms you.
                • +
                • You can no longer zoom in while lying down.
                • +
                • Ghosting/Dying while zoomed in will no longer lock your vision.
                • +
                • You can no longer put a knife in your boot if you already have a knife in your boot.
                • +
                • New cold breath animation, sprites courtesy of Erin.
                • +
                • New weapons sprites for the SMG, HMG, Boltaction Rifle and Shotgun, sprites by me and Dongwaiver.
                • +
                • Hot damn I got a lot done today.
                • +
                • Disarming mines now makes a sound. No more silent invasions.
                • +
                • Added shovels to engineers, you can now dig cover for yourself as long as there's no objects on the turf.
                • +
                • Added doors to the fortresses.
                • +
                • Increased the low end of engineers engineering skill. They shouldn't blow up mines anymore.
                • +
                • Reduced the range of shotguns from 10 to 8.
                • +
                • Readded squads, but they have been reduced to only 3 squads max now and squads can now use general radio as well as their squad channel. This makes organization much easier.
                • +
                • There's reachable toilets in both forts.
                • +
                • There's sinks in both forts.
                • +
                • Medbay has scanners now.
                • +
                • Gas mortars have been disabled till I fix their lag.
                • +
                • You can no longer shoot up stairs from your trench.
                • +
                • Temporarily disabling squads while I do more work to them.
                • +
                • Squad leaders can speak on the general channel, and their squad channel.
                • +
                • Fort roles are not in squads, and can only talk on the general channel for their team.
                • +
                • Scouts are not in squads, and can talk to everyone.
                • +
                • Squads, and Squad Radios have now been added. When you join as any combat role that isn't SL or Captain you'll be placed into a random squad, with a radio that can only communicate with your squad. SL and Captain are now very important roles, as they are the only ones who can communicate with other squads. Captain can still issue global commands.
                • +
                • A whistle now blows to alert you when you're ready to die.
                • +
                • Voting has been disabled. It being enabled was an oversight. My bad.
                • +
                • Ghosts can finally see who has captured what trench and how many are left alive.
                • +
                • Pressing L in hotkey mode now let's you use LOOC.
                • +
                • Practitioner is no longer a limited role.
                • +
                • There can now be 2 chefs on both sides, so that when the first guy instantly goes braindead because he picked the wrong role, someone can take his place.
                • +
                • Shotguns no longer spawn in crates in the home bases. This was an oversight from when shotguns were a test weapon and classes didn't exist. Their ammo still does spawn in the crates though.
                • +
                • Walls are now much more sturdy.
                • +
                • Red and Blue now get closable shutters over their entrances, so they can't be immediately overrun as soon as the final trench is captured.
                • +
                • Point of No Return machines are now in plain sight, not hidden in a corner.
                • +
                • End of round announcement is in a readable font now.
                • +
                • New round end stats: Number of mines tripped, number of mines defused, number of friendly fire incidents.
                • +
                • Attacking your teammate will also tell the attacker they are a team mate. This doesn't stop you from doing it so mercy kills are still allowed, but at least the attacker can't claim ignorance.
                • +
                • Attacking your team mate, either with melee or by shooting, now alerts the admins.
                • +
                • Looking up hotkey has been added to the control window.
                • +
                • Dirt mounds now actually look like they came from the ground.
                • +
                • Water will generate again on no man's land.
                • +
                • Artillery is in as a random event. You'll know when it's about to hit, and I wouldn't be in no man's land when it happens either.
                • +
                • You can now refill your water jugs at the piss holes. And by that I mean you can use your canteens on the water.
                • +
                • Controls are no longer in the chat window, they make a new window now so they aren't lost by combat logs.
                • +
                • All controls and hotkeys are now visible in game in the OOC tab under "view controls".
                • +
                • Fixes glitch where shotguns were doing next to no damage.
                • +
                • All guns got buffed again. They should be more deadly now.
                • +
                • Fixed landmines.
                • +
                • Made the experimentally cursor facing thing toggleable. Starts off by default you can turn it on to see how you like it.
                • +
                • EXPERIMENTAL: When in combat mode, you will face your cursor.
                • +
                • When direction is locked you can still use ctrl arrow keys to face a direction.
                • +
                • You can put boots on again.
                • +
                • Forts now have toilets. Curtsey of Thooloo.
                • +
                • Disarmed mines now have a unique sprite so you can tell they're non functional.
                • +
                • Liquid food MRE's have been replaced with canned rations.
                • +
                • Examine text for shotguns and rifles has been fixed.
                • +
                • Soldiers are no longer super strong. This means that melee combat should have slightly fewer one hit kills. Soldiers can still carry all their equipment but they won't be tearing off limbs unless modified in game somehow.
                • +
                • New experimental grab system is in place. Like in lifeweb, grabbing people in different places and having different intents will give you different options. Currently you can: wrench, strangle, and takedown, depending on where you grab. Wrenching on harm intent will attempt to rip the limb off, but you must have high strength for this. Speaking of strength...
                • +
                + +

                MAY 2019

                +
                  +
                • Captain commands and taking objectives have audio indicators now.
                • +
                • Captain gets an SMG now. That means at the moment there are a total of two SMGs max on the map. Do not waste them they're pretty good.
                • +
                • Scouts no longer outrank grunts.
                • +
                • Shotguns and bolt action rifles have now had their hopefully final buff. Considering how much bullshit you gotta go through to hit someone it should at least be deadly.
                • +
                • There is now a shadow around open space edges so hopefully you can better tell if there's a hole there. You'll still probably fall and die though.
                • +
                • As evidenced by last playtest, you can actually get thirsty again. Adding those canteens was a smart move.
                • +
                • Shotguns and bolt action rifles have higher starting conditions now. And should jam less often on the first shot.
                • +
                • Dog tags have proper on mob sprites now.
                • +
                • Cleaned up scout code.
                • +
                • Added scouts.
                • +
                • Soldiers now start with a combat knife in their boots.
                • +
                • Toggling safety, unjamming, and cleaning your gun work while lying down again.
                • +
                • Machine guns no longer make a million runtimes and lag.
                • +
                • Peering into the distance now makes you face the atom first. So you don't need to manually set your dir before looking off into the distance.
                • +
                • Pissing your pants now makes a puddle.
                • +
                • Added experimental SMG. It doesn't spawn anywhere yet.
                • +
                • Added canteens, so you can have a nice drink on the battlefield.
                • +
                • The storage UI is no longer way far away from the HUD.
                • +
                • Trenches have been remapped to be less shit.
                • +
                • Moved the HUD down two squares.
                • +
                • Respawn time, point of no return time, trench capture points, and no man's land wait period time has all be made into a config.
                • +
                • Thirst should actually be a thing again.
                • +
                • Harbinger has a unique fire sound now.
                • +
                • Captains can't call for help if they're not conscious again.
                • +
                • Captain verbs now have a cooldown (1 minute).
                • +
                • Captains can use the helpme verb while knocked out.
                • +
                • Guns now have cocking sounds as long as they have ammo in the magazine.
                • +
                • fortress jobs are restricted from entering no mans land.
                • +
                • Respawn timer back down to 2 minutes.
                • +
                • You can no longer jump off mines to avoid them blowing.
                • +
                • You can no longer ghost unless you are dead.
                • +
                • Automatic guns no longer fire super slow.
                • +
                • Combat mode has very minor effects to accuracy once again. Nothing nearly as bad as we once had though.
                • +
                • You can no longer snipe people with buckshot.
                • +
                • Bullets now fly much faster. So bullet dodging should be next to impossible now.
                • +
                • Back slot two is no longer dropped when you remove your suit.
                • +
                • Medics and engineers have been nerfed slightly.
                • +
                • Dirt makes you walk slower than it used to.
                • +
                • Max stacks for ammo boxes has been increased.
                • +
                • Dirt cover can now be destroyed.
                • +
                • Added plantable mines. And plantable barbed wire.
                • +
                • Added trenches. Changed some sprites.
                • +
                • Both sides must capture the other sides trench, then invade their fort and activate the point of no return computer. After 2 minutes the computer will detonate and the attacking side will win.
                • +
                • New game mode variant: Point Of No Return.
                • +
                • Shotgun and rifles have both been buffed to be a bit more deadly.
                • +
                • Second back slot added. You can now carry a rifle and a backpack at the same time.
                • +
                • Engineer exists now. He can disarm landmines pretty easily.
                • +
                • I'm still working on adding in the engineers proper, they'll be in soon.
                • +
                • Landmines are in. They spawn randomly in the wasteland and can be disarmed with good wirecutters if you have good engineering skill.
                • +
                • Everyone now spawns with "handful" boxes. These replace the old boxes. Clicking on them when they're in your pocket or inactive hand will give you a handful of rifle or shotgun ammo depending on the box.
                • +
                • captains now have verbs to better command their teams.
                • +
                • captain deaths now give his team a bad mood.
                • +
                • Braindead people no longer count towards objective points.
                • +
                • Dead people no longer count towards objective points.
                • +
                • Added primary hand. You can set it in the player creation. Doing stuff with your non primary hand gives you a debuff on rolls.
                • +
                • Grenades can finally pass over dirt barricades.
                • +
                • You can now dig your own dirt cover with a shovel. RMB on the dirt to build one. Might take a bit. RMB on dirt cover to dismantle it.
                • +
                • Second z-level added to forts.
                • +
                • Opposite factions can no longer enter each other's bases and spawn kill.
                • +
                • Forts redesigned to have less empty space. Bartender removed.
                • +
                • Fortresses; home bases for the teams that also host some RP jobs such as practitioner, bartender, and chef
                • +
                • Made job selection pretty.
                • +
                • Firing your rifle one handed is no longer more accurate than firing with both hands. Thanks Bay.
                • +
                • Added puddle generation. Nicer skin.dmf that shows your name and has no more white space (@Janey you can be happy now). More readable chat. Some non combat roles if you just wanna sit around and RP and not actually shoot somebody (like a dork lol).
                • +
                • Finally for once in everyone's fucking life I have finally fucking fixed accuracy for guns.
                • +
                • I made a changelog for the warfare shit. Old changelog stands as a testament to what has been done in the past.
                • +
                +
                + + + +EVERYTHING DOWN HERE IS OLD LMAO +
                +

                10/19/2018

                +
                  +
                • You can no longer walk with broken legs or feet.
                • +
                • You can no longer jump with broken feet.
                • +
                • Removed alt titles for everyone.
                • +
                • Added back kids though they're admin spawn only at the moment.
                • +
                • New riot shield sprite by Fridge.
                • +
                • Head Peacekeeper no longer sucks hardcore at combat.
                • +
                • Janitor is no longer a combat expert.
                • +
                • Arbiters and Undertakers have their clothing sprites back.
                • +
                +
                +

                10/10/2018

                +
                  +
                • Vanilla gamemodes got back into rotation.
                • +
                • No more selecting from a list of just two genders. Now it simply toggles male or female.
                • +
                +
                +
                +

                10/09/2018

                +
                  +
                • Pressing c now toggles combat mode in hotkey mode.
                • +
                • The screen probably won't burn your eyes anymore. New color scheme.
                • +
                +
                +
                +

                10/08/2018

                +
                  +
                • New stats and skills came into town.
                • +
                • Weight system.
                • +
                • Jump range nerfed.
                • +
                • Having less stamina than required forbids you from jumping.
                • +
                • Stamina loss now affects your movement speed drastically.
                • +
                +
                +
                +

                10/07/2018

                +
                  +
                • NEW HUD.
                • +
                +
                +
                +

                10/06/2018

                +
                  +
                • Haven is back.
                • +
                • Yanking out teeth is back.
                • +
                +
                +
                +

                10/02/2018

                +
                  +
                • You can grind uranium again.
                • +
                +
                +
                +

                10/01/2018

                +
                  +
                • Properly restricts antags on Alpha and Haven maps.
                • +
                • Haven uses proper announcement sounds.
                • +
                • Jobs are in the proper order on Alpha and Haven.
                • +
                • New sprite for rifle box.
                • +
                • Safe room on Haven actually has radiation protection now.
                • +
                +
                +
                +

                09/30/2018

                +
                  +
                • Crew now stands a slightly better chance against mercenaries.
                • +
                • You can now aim at people by RMB on them from a distance with a gun. Please report in detail any bugs related to this.
                • +
                +
                +
                +

                09/24/2018

                +
                  +
                • Warden can no longer be traitor.
                • +
                • You can now climb down open spaces as long as you aren't on an open space yourself.
                • +
                • Throwing things takes time and stamina again.
                • +
                • Better placement of the cargo lift console (doesn't require voodoo movement anymore).
                • +
                • Improved lighting in the brig.
                • +
                • Various quality of life improvements in maintenance.
                • +
                • More airlocks in mining to prevent retarded leaks that happened before.
                • +
                • Emitter in supermatter chamber now uses 50k power usage, which means it can work alongside all pumps (be advised that also means that emitter shots now add half of epr each shot).
                • +
                • Mercenaries blast doors are now working.
                • +
                +
                +
                +

                09/22/2018

                +
                  +
                • Actually fixes (for real) NPCs following you after death.
                • +
                +
                +
                +

                09/20/2018

                +
                  +
                • NPCs will no longer teleport around, and should move appropiately.
                • +
                • NPCs should no longer follow you even after they die.
                • +
                +
                +
                +

                09/19/2018

                +
                  +
                • Lighting looks a bit different now.
                • +
                • Jobs social classes should work now. One variable value was off.
                • +
                +
                +
                +

                09/05/2018

                +
                  +
                • You don't automatically see the shuttle time unless you are a ghost. Gotta actually look at the monitors now to see when the shuttle will arrive.
                • +
                +
                +
                +

                09/01/2018

                +
                  +
                • Mobs no longer appear on top of smoke.
                • +
                • Round end stats are back from old interbay.
                • +
                • You will no longer lose more teeth than you actually have.
                • +
                • Fixed class descriptions when examining someone.
                • +
                +
                +
                +

                08/28/2018

                +
                  +
                • Attack intents no longer fire unless you are right clicking.
                • +
                • Admin ghosts no longer have to select themselves from a list to respawn. Observers can respawn properly again. This probably doesn't affect anyone.
                • +
                +
                +
                +

                08/27/2018

                +
                  +
                • If your body is in the morgue structure you can bypass the 30 minute wait to respawn. Bury your deads.
                • +
                • Foostep indicators have been fixed. They now should only activate when a footstep sound is made. Not just when anything moves.
                • +
                +
                +
                +

                08/17/2018

                +
                  +
                • Antag latejoin has been fixed.
                • +
                • Seed vendor has also been fixed.
                • +
                +
                +
                +

                08/17/2018

                +
                  +
                • Added back human NPC enemies, they don't spawn anywhere yet and are adminbus only.
                • +
                +
                +
                +

                08/14/2018

                +
                  +
                • Giving objexts now works for sure.
                • +
                • Chemist will have hard time figuring out how to work without chem dispenser, JARS.
                • +
                +
                +
                +

                08/09/2018

                +
                  +
                • Traitor equipment has changed. You will still be able to complete your objectives don't worry.
                • +
                +
                +
                +

                08/07/2018

                +
                  +
                • Return of Head Practioner on Alpha.
                • +
                • Several map modifications to Alpha.
                • +
                • Giving... might work?
                • +
                • Combat mode might be fixed when normal clicking on someone.
                • +
                +
                +
                +

                08/02/2018

                +
                  +
                • PDA opening switched to right-click.
                • +
                • Fixed alt titles.
                • +
                +
                +
                +

                07/31/2018

                +
                  +
                • Disarming now only actually disarms. Disarm spammers pls go.
                • +
                • Mobs no longer appear over lattices and catwalks.
                • +
                +
                +
                +

                07/30/2018

                +
                  +
                • New Map.
                • +
                +
                +
                +

                07/24/2018

                +
                  +
                • Shotgun shells now come in quickloadable boxes, just make sure you open them before trying to load your gun.
                • +
                +
                +
                +

                07/16/2018

                +
                  +
                • Standing up handcuffed works properly again.
                • +
                +
                +
                +

                07/11/2018

                +
                  +
                • Pointing works again and it uses shift+MMB again.
                • +
                +
                +
                +

                07/07/2018

                +
                  +
                • People who don't need emails will no longer get them.
                • +
                +
                +
                +

                07/04/2018

                +
                  +
                • Knives and Swords can no longer break bones. Only blunt objects.
                • +
                • Ladders will now require to LMB to go up, and RMB to go down.
                • +
                • Toolbelts and other storage objects' UI has now been fixed.
                • +
                • Underwear no longer shows up in create a character (like it was supposed to).
                • +
                • Peackeeper's no longer get stunbatons, only regular batons (you're welcome).
                • +
                • Head Peacekeeper should no longer spawn really weak.
                • +
                • Weapons can no longer embed, if you see one embed and it's not a bullet report it please.
                • +
                +
                + + +
                +

                Creative Commons License
                Except where otherwise noted, Goon Station 13 is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 License.
                Rights are currently extended to SomethingAwful Goons only.

                +

                Some icons by Yusuke Kamiyamane. All rights reserved. Licensed under a Creative Commons Attribution 3.0 License.

                +
                + + diff --git a/html/chevron-expand.png b/html/chevron-expand.png new file mode 100644 index 00000000..f770e33d Binary files /dev/null and b/html/chevron-expand.png differ diff --git a/html/chevron.png b/html/chevron.png new file mode 100644 index 00000000..b83135b6 Binary files /dev/null and b/html/chevron.png differ diff --git a/html/create_object.html b/html/create_object.html new file mode 100644 index 00000000..22ac6df2 --- /dev/null +++ b/html/create_object.html @@ -0,0 +1,113 @@ + + + + Create Object + + + + +
                + + + Type
                + Offset: + + A + R
                + + Number: + Dir: + Name:
                + Where: + +

                +
                + +
                + + + + + \ No newline at end of file diff --git a/html/cross-circle.png b/html/cross-circle.png new file mode 100644 index 00000000..e6f2d322 Binary files /dev/null and b/html/cross-circle.png differ diff --git a/html/font-awesome/README.MD b/html/font-awesome/README.MD new file mode 100644 index 00000000..7d693c36 --- /dev/null +++ b/html/font-awesome/README.MD @@ -0,0 +1,6 @@ +Due to the fact browse_rsc can't create subdirectories, every time you update font-awesome you'll need to change relative webfont references in all.min.css +eg ../webfonts/fa-regular-400.ttf => fa-regular-400.ttf (or whatever you call it in asset datum) + +Second change is ripping out file types other than woff and eot(ie8) from the css + +Finally, removing brand related css. \ No newline at end of file diff --git a/html/font-awesome/css/all.min.css b/html/font-awesome/css/all.min.css new file mode 100644 index 00000000..e7cdfffe --- /dev/null +++ b/html/font-awesome/css/all.min.css @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.9.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +.fa,.fab,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:fa-spin 2s infinite linear}.fa-pulse{animation:fa-spin 1s infinite steps(8)}@keyframes fa-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adobe:before{content:"\f778"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake:before{content:"\f2b5"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-wizard:before{content:"\f6e8"}.fa-haykal:before{content:"\f666"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:auto;src:url(fa-regular-400.eot);src:url(fa-regular-400.eot?#iefix) format("embedded-opentype"),url(fa-regular-400.woff) format("woff")}.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:auto;src:url(fa-solid-900.eot);src:url(fa-solid-900.eot?#iefix) format("embedded-opentype"),url(fa-solid-900.woff) format("woff")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} \ No newline at end of file diff --git a/html/font-awesome/css/v4-shims.min.css b/html/font-awesome/css/v4-shims.min.css new file mode 100644 index 00000000..5f3fdc59 --- /dev/null +++ b/html/font-awesome/css/v4-shims.min.css @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.9.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +.fa.fa-glass:before{content:"\f000"}.fa.fa-meetup{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-star-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-o:before{content:"\f005"}.fa.fa-close:before,.fa.fa-remove:before{content:"\f00d"}.fa.fa-gear:before{content:"\f013"}.fa.fa-trash-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-trash-o:before{content:"\f2ed"}.fa.fa-file-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-o:before{content:"\f15b"}.fa.fa-clock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-clock-o:before{content:"\f017"}.fa.fa-arrow-circle-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-down:before{content:"\f358"}.fa.fa-arrow-circle-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-up:before{content:"\f35b"}.fa.fa-play-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-play-circle-o:before{content:"\f144"}.fa.fa-repeat:before,.fa.fa-rotate-right:before{content:"\f01e"}.fa.fa-refresh:before{content:"\f021"}.fa.fa-list-alt{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-dedent:before{content:"\f03b"}.fa.fa-video-camera:before{content:"\f03d"}.fa.fa-picture-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-picture-o:before{content:"\f03e"}.fa.fa-photo{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-photo:before{content:"\f03e"}.fa.fa-image{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-image:before{content:"\f03e"}.fa.fa-pencil:before{content:"\f303"}.fa.fa-map-marker:before{content:"\f3c5"}.fa.fa-pencil-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-pencil-square-o:before{content:"\f044"}.fa.fa-share-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-share-square-o:before{content:"\f14d"}.fa.fa-check-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-check-square-o:before{content:"\f14a"}.fa.fa-arrows:before{content:"\f0b2"}.fa.fa-times-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-circle-o:before{content:"\f057"}.fa.fa-check-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-check-circle-o:before{content:"\f058"}.fa.fa-mail-forward:before{content:"\f064"}.fa.fa-eye,.fa.fa-eye-slash{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-warning:before{content:"\f071"}.fa.fa-calendar:before{content:"\f073"}.fa.fa-arrows-v:before{content:"\f338"}.fa.fa-arrows-h:before{content:"\f337"}.fa.fa-bar-chart{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bar-chart:before{content:"\f080"}.fa.fa-bar-chart-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bar-chart-o:before{content:"\f080"}.fa.fa-facebook-square,.fa.fa-twitter-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-gears:before{content:"\f085"}.fa.fa-thumbs-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-thumbs-o-up:before{content:"\f164"}.fa.fa-thumbs-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-thumbs-o-down:before{content:"\f165"}.fa.fa-heart-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-heart-o:before{content:"\f004"}.fa.fa-sign-out:before{content:"\f2f5"}.fa.fa-linkedin-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-linkedin-square:before{content:"\f08c"}.fa.fa-thumb-tack:before{content:"\f08d"}.fa.fa-external-link:before{content:"\f35d"}.fa.fa-sign-in:before{content:"\f2f6"}.fa.fa-github-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-lemon-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-lemon-o:before{content:"\f094"}.fa.fa-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-square-o:before{content:"\f0c8"}.fa.fa-bookmark-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bookmark-o:before{content:"\f02e"}.fa.fa-facebook,.fa.fa-twitter{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook:before{content:"\f39e"}.fa.fa-facebook-f{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook-f:before{content:"\f39e"}.fa.fa-github{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-credit-card{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-feed:before{content:"\f09e"}.fa.fa-hdd-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hdd-o:before{content:"\f0a0"}.fa.fa-hand-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-right:before{content:"\f0a4"}.fa.fa-hand-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-left:before{content:"\f0a5"}.fa.fa-hand-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-up:before{content:"\f0a6"}.fa.fa-hand-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-down:before{content:"\f0a7"}.fa.fa-arrows-alt:before{content:"\f31e"}.fa.fa-group:before{content:"\f0c0"}.fa.fa-chain:before{content:"\f0c1"}.fa.fa-scissors:before{content:"\f0c4"}.fa.fa-files-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-files-o:before{content:"\f0c5"}.fa.fa-floppy-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-floppy-o:before{content:"\f0c7"}.fa.fa-navicon:before,.fa.fa-reorder:before{content:"\f0c9"}.fa.fa-google-plus,.fa.fa-google-plus-square,.fa.fa-pinterest,.fa.fa-pinterest-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus:before{content:"\f0d5"}.fa.fa-money{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-money:before{content:"\f3d1"}.fa.fa-unsorted:before{content:"\f0dc"}.fa.fa-sort-desc:before{content:"\f0dd"}.fa.fa-sort-asc:before{content:"\f0de"}.fa.fa-linkedin{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-linkedin:before{content:"\f0e1"}.fa.fa-rotate-left:before{content:"\f0e2"}.fa.fa-legal:before{content:"\f0e3"}.fa.fa-dashboard:before,.fa.fa-tachometer:before{content:"\f3fd"}.fa.fa-comment-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-comment-o:before{content:"\f075"}.fa.fa-comments-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-comments-o:before{content:"\f086"}.fa.fa-flash:before{content:"\f0e7"}.fa.fa-clipboard,.fa.fa-paste{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-paste:before{content:"\f328"}.fa.fa-lightbulb-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-lightbulb-o:before{content:"\f0eb"}.fa.fa-exchange:before{content:"\f362"}.fa.fa-cloud-download:before{content:"\f381"}.fa.fa-cloud-upload:before{content:"\f382"}.fa.fa-bell-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bell-o:before{content:"\f0f3"}.fa.fa-cutlery:before{content:"\f2e7"}.fa.fa-file-text-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-text-o:before{content:"\f15c"}.fa.fa-building-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-building-o:before{content:"\f1ad"}.fa.fa-hospital-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hospital-o:before{content:"\f0f8"}.fa.fa-tablet:before{content:"\f3fa"}.fa.fa-mobile-phone:before,.fa.fa-mobile:before{content:"\f3cd"}.fa.fa-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-circle-o:before{content:"\f111"}.fa.fa-mail-reply:before{content:"\f3e5"}.fa.fa-github-alt{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-folder-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-folder-o:before{content:"\f07b"}.fa.fa-folder-open-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-folder-open-o:before{content:"\f07c"}.fa.fa-smile-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-smile-o:before{content:"\f118"}.fa.fa-frown-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-frown-o:before{content:"\f119"}.fa.fa-meh-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-meh-o:before{content:"\f11a"}.fa.fa-keyboard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-keyboard-o:before{content:"\f11c"}.fa.fa-flag-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-flag-o:before{content:"\f024"}.fa.fa-mail-reply-all:before{content:"\f122"}.fa.fa-star-half-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-o:before{content:"\f089"}.fa.fa-star-half-empty{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-empty:before{content:"\f089"}.fa.fa-star-half-full{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-full:before{content:"\f089"}.fa.fa-code-fork:before{content:"\f126"}.fa.fa-chain-broken:before{content:"\f127"}.fa.fa-shield:before{content:"\f3ed"}.fa.fa-calendar-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-o:before{content:"\f133"}.fa.fa-css3,.fa.fa-html5,.fa.fa-maxcdn{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ticket:before{content:"\f3ff"}.fa.fa-minus-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-minus-square-o:before{content:"\f146"}.fa.fa-level-up:before{content:"\f3bf"}.fa.fa-level-down:before{content:"\f3be"}.fa.fa-pencil-square:before{content:"\f14b"}.fa.fa-external-link-square:before{content:"\f360"}.fa.fa-compass{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-down:before{content:"\f150"}.fa.fa-toggle-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-down:before{content:"\f150"}.fa.fa-caret-square-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-up:before{content:"\f151"}.fa.fa-toggle-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-up:before{content:"\f151"}.fa.fa-caret-square-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-right:before{content:"\f152"}.fa.fa-toggle-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-right:before{content:"\f152"}.fa.fa-eur:before,.fa.fa-euro:before{content:"\f153"}.fa.fa-gbp:before{content:"\f154"}.fa.fa-dollar:before,.fa.fa-usd:before{content:"\f155"}.fa.fa-inr:before,.fa.fa-rupee:before{content:"\f156"}.fa.fa-cny:before,.fa.fa-jpy:before,.fa.fa-rmb:before,.fa.fa-yen:before{content:"\f157"}.fa.fa-rouble:before,.fa.fa-rub:before,.fa.fa-ruble:before{content:"\f158"}.fa.fa-krw:before,.fa.fa-won:before{content:"\f159"}.fa.fa-bitcoin,.fa.fa-btc{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bitcoin:before{content:"\f15a"}.fa.fa-file-text:before{content:"\f15c"}.fa.fa-sort-alpha-asc:before{content:"\f15d"}.fa.fa-sort-alpha-desc:before{content:"\f15e"}.fa.fa-sort-amount-asc:before{content:"\f160"}.fa.fa-sort-amount-desc:before{content:"\f161"}.fa.fa-sort-numeric-asc:before{content:"\f162"}.fa.fa-sort-numeric-desc:before{content:"\f163"}.fa.fa-xing,.fa.fa-xing-square,.fa.fa-youtube,.fa.fa-youtube-play,.fa.fa-youtube-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-youtube-play:before{content:"\f167"}.fa.fa-adn,.fa.fa-bitbucket,.fa.fa-bitbucket-square,.fa.fa-dropbox,.fa.fa-flickr,.fa.fa-instagram,.fa.fa-stack-overflow{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bitbucket-square:before{content:"\f171"}.fa.fa-tumblr,.fa.fa-tumblr-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-long-arrow-down:before{content:"\f309"}.fa.fa-long-arrow-up:before{content:"\f30c"}.fa.fa-long-arrow-left:before{content:"\f30a"}.fa.fa-long-arrow-right:before{content:"\f30b"}.fa.fa-android,.fa.fa-apple,.fa.fa-dribbble,.fa.fa-foursquare,.fa.fa-gittip,.fa.fa-gratipay,.fa.fa-linux,.fa.fa-skype,.fa.fa-trello,.fa.fa-windows{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-gittip:before{content:"\f184"}.fa.fa-sun-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-sun-o:before{content:"\f185"}.fa.fa-moon-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-moon-o:before{content:"\f186"}.fa.fa-pagelines,.fa.fa-renren,.fa.fa-stack-exchange,.fa.fa-vk,.fa.fa-weibo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-arrow-circle-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-right:before{content:"\f35a"}.fa.fa-arrow-circle-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-left:before{content:"\f359"}.fa.fa-caret-square-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-left:before{content:"\f191"}.fa.fa-toggle-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-left:before{content:"\f191"}.fa.fa-dot-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-dot-circle-o:before{content:"\f192"}.fa.fa-vimeo-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-try:before,.fa.fa-turkish-lira:before{content:"\f195"}.fa.fa-plus-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-plus-square-o:before{content:"\f0fe"}.fa.fa-openid,.fa.fa-slack,.fa.fa-wordpress{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bank:before,.fa.fa-institution:before{content:"\f19c"}.fa.fa-mortar-board:before{content:"\f19d"}.fa.fa-delicious,.fa.fa-digg,.fa.fa-drupal,.fa.fa-google,.fa.fa-joomla,.fa.fa-pied-piper-alt,.fa.fa-pied-piper-pp,.fa.fa-reddit,.fa.fa-reddit-square,.fa.fa-stumbleupon,.fa.fa-stumbleupon-circle,.fa.fa-yahoo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-spoon:before{content:"\f2e5"}.fa.fa-behance,.fa.fa-behance-square,.fa.fa-steam,.fa.fa-steam-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-automobile:before{content:"\f1b9"}.fa.fa-cab:before{content:"\f1ba"}.fa.fa-envelope-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-envelope-o:before{content:"\f0e0"}.fa.fa-deviantart,.fa.fa-soundcloud{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-file-pdf-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-pdf-o:before{content:"\f1c1"}.fa.fa-file-word-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-word-o:before{content:"\f1c2"}.fa.fa-file-excel-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-excel-o:before{content:"\f1c3"}.fa.fa-file-powerpoint-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-powerpoint-o:before{content:"\f1c4"}.fa.fa-file-image-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-image-o:before{content:"\f1c5"}.fa.fa-file-photo-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-photo-o:before{content:"\f1c5"}.fa.fa-file-picture-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-picture-o:before{content:"\f1c5"}.fa.fa-file-archive-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-archive-o:before{content:"\f1c6"}.fa.fa-file-zip-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-zip-o:before{content:"\f1c6"}.fa.fa-file-audio-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-audio-o:before{content:"\f1c7"}.fa.fa-file-sound-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-sound-o:before{content:"\f1c7"}.fa.fa-file-video-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-video-o:before{content:"\f1c8"}.fa.fa-file-movie-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-movie-o:before{content:"\f1c8"}.fa.fa-file-code-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-code-o:before{content:"\f1c9"}.fa.fa-codepen,.fa.fa-jsfiddle,.fa.fa-vine{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-life-bouy,.fa.fa-life-ring{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-bouy:before{content:"\f1cd"}.fa.fa-life-buoy{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-buoy:before{content:"\f1cd"}.fa.fa-life-saver{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-saver:before{content:"\f1cd"}.fa.fa-support{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-support:before{content:"\f1cd"}.fa.fa-circle-o-notch:before{content:"\f1ce"}.fa.fa-ra,.fa.fa-rebel{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ra:before{content:"\f1d0"}.fa.fa-resistance{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-resistance:before{content:"\f1d0"}.fa.fa-empire,.fa.fa-ge{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ge:before{content:"\f1d1"}.fa.fa-git,.fa.fa-git-square,.fa.fa-hacker-news,.fa.fa-y-combinator-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-y-combinator-square:before{content:"\f1d4"}.fa.fa-yc-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-yc-square:before{content:"\f1d4"}.fa.fa-qq,.fa.fa-tencent-weibo,.fa.fa-wechat,.fa.fa-weixin{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-wechat:before{content:"\f1d7"}.fa.fa-send:before{content:"\f1d8"}.fa.fa-paper-plane-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-paper-plane-o:before{content:"\f1d8"}.fa.fa-send-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-send-o:before{content:"\f1d8"}.fa.fa-circle-thin{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-circle-thin:before{content:"\f111"}.fa.fa-header:before{content:"\f1dc"}.fa.fa-sliders:before{content:"\f1de"}.fa.fa-futbol-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-futbol-o:before{content:"\f1e3"}.fa.fa-soccer-ball-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-soccer-ball-o:before{content:"\f1e3"}.fa.fa-slideshare,.fa.fa-twitch,.fa.fa-yelp{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-newspaper-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-newspaper-o:before{content:"\f1ea"}.fa.fa-cc-amex,.fa.fa-cc-discover,.fa.fa-cc-mastercard,.fa.fa-cc-paypal,.fa.fa-cc-stripe,.fa.fa-cc-visa,.fa.fa-google-wallet,.fa.fa-paypal{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bell-slash-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bell-slash-o:before{content:"\f1f6"}.fa.fa-trash:before{content:"\f2ed"}.fa.fa-copyright{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-eyedropper:before{content:"\f1fb"}.fa.fa-area-chart:before{content:"\f1fe"}.fa.fa-pie-chart:before{content:"\f200"}.fa.fa-line-chart:before{content:"\f201"}.fa.fa-angellist,.fa.fa-ioxhost,.fa.fa-lastfm,.fa.fa-lastfm-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-cc{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-cc:before{content:"\f20a"}.fa.fa-ils:before,.fa.fa-shekel:before,.fa.fa-sheqel:before{content:"\f20b"}.fa.fa-meanpath{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-meanpath:before{content:"\f2b4"}.fa.fa-buysellads,.fa.fa-connectdevelop,.fa.fa-dashcube,.fa.fa-forumbee,.fa.fa-leanpub,.fa.fa-sellsy,.fa.fa-shirtsinbulk,.fa.fa-simplybuilt,.fa.fa-skyatlas{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-diamond{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-diamond:before{content:"\f3a5"}.fa.fa-intersex:before{content:"\f224"}.fa.fa-facebook-official{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook-official:before{content:"\f09a"}.fa.fa-pinterest-p,.fa.fa-whatsapp{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-hotel:before{content:"\f236"}.fa.fa-medium,.fa.fa-viacoin,.fa.fa-y-combinator,.fa.fa-yc{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-yc:before{content:"\f23b"}.fa.fa-expeditedssl,.fa.fa-opencart,.fa.fa-optin-monster{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-battery-4:before,.fa.fa-battery:before{content:"\f240"}.fa.fa-battery-3:before{content:"\f241"}.fa.fa-battery-2:before{content:"\f242"}.fa.fa-battery-1:before{content:"\f243"}.fa.fa-battery-0:before{content:"\f244"}.fa.fa-object-group,.fa.fa-object-ungroup,.fa.fa-sticky-note-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-sticky-note-o:before{content:"\f249"}.fa.fa-cc-diners-club,.fa.fa-cc-jcb{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-clone,.fa.fa-hourglass-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hourglass-o:before{content:"\f254"}.fa.fa-hourglass-1:before{content:"\f251"}.fa.fa-hourglass-2:before{content:"\f252"}.fa.fa-hourglass-3:before{content:"\f253"}.fa.fa-hand-rock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-rock-o:before{content:"\f255"}.fa.fa-hand-grab-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-grab-o:before{content:"\f255"}.fa.fa-hand-paper-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-paper-o:before{content:"\f256"}.fa.fa-hand-stop-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-stop-o:before{content:"\f256"}.fa.fa-hand-scissors-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-scissors-o:before{content:"\f257"}.fa.fa-hand-lizard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-lizard-o:before{content:"\f258"}.fa.fa-hand-spock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-spock-o:before{content:"\f259"}.fa.fa-hand-pointer-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-pointer-o:before{content:"\f25a"}.fa.fa-hand-peace-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-peace-o:before{content:"\f25b"}.fa.fa-registered{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-chrome,.fa.fa-creative-commons,.fa.fa-firefox,.fa.fa-get-pocket,.fa.fa-gg,.fa.fa-gg-circle,.fa.fa-internet-explorer,.fa.fa-odnoklassniki,.fa.fa-odnoklassniki-square,.fa.fa-opera,.fa.fa-safari,.fa.fa-tripadvisor,.fa.fa-wikipedia-w{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-television:before{content:"\f26c"}.fa.fa-500px,.fa.fa-amazon,.fa.fa-contao{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-calendar-plus-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-plus-o:before{content:"\f271"}.fa.fa-calendar-minus-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-minus-o:before{content:"\f272"}.fa.fa-calendar-times-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-times-o:before{content:"\f273"}.fa.fa-calendar-check-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-check-o:before{content:"\f274"}.fa.fa-map-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-map-o:before{content:"\f279"}.fa.fa-commenting:before{content:"\f4ad"}.fa.fa-commenting-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-commenting-o:before{content:"\f4ad"}.fa.fa-houzz,.fa.fa-vimeo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-vimeo:before{content:"\f27d"}.fa.fa-black-tie,.fa.fa-edge,.fa.fa-fonticons,.fa.fa-reddit-alien{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-credit-card-alt:before{content:"\f09d"}.fa.fa-codiepie,.fa.fa-fort-awesome,.fa.fa-mixcloud,.fa.fa-modx,.fa.fa-product-hunt,.fa.fa-scribd,.fa.fa-usb{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-pause-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-pause-circle-o:before{content:"\f28b"}.fa.fa-stop-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-stop-circle-o:before{content:"\f28d"}.fa.fa-bluetooth,.fa.fa-bluetooth-b,.fa.fa-envira,.fa.fa-gitlab,.fa.fa-wheelchair-alt,.fa.fa-wpbeginner,.fa.fa-wpforms{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-wheelchair-alt:before{content:"\f368"}.fa.fa-question-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-question-circle-o:before{content:"\f059"}.fa.fa-volume-control-phone:before{content:"\f2a0"}.fa.fa-asl-interpreting:before{content:"\f2a3"}.fa.fa-deafness:before,.fa.fa-hard-of-hearing:before{content:"\f2a4"}.fa.fa-glide,.fa.fa-glide-g{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-signing:before{content:"\f2a7"}.fa.fa-first-order,.fa.fa-google-plus-official,.fa.fa-pied-piper,.fa.fa-snapchat,.fa.fa-snapchat-ghost,.fa.fa-snapchat-square,.fa.fa-themeisle,.fa.fa-viadeo,.fa.fa-viadeo-square,.fa.fa-yoast{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus-official:before{content:"\f2b3"}.fa.fa-google-plus-circle{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus-circle:before{content:"\f2b3"}.fa.fa-fa,.fa.fa-font-awesome{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-fa:before{content:"\f2b4"}.fa.fa-handshake-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-handshake-o:before{content:"\f2b5"}.fa.fa-envelope-open-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-envelope-open-o:before{content:"\f2b6"}.fa.fa-linode{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-address-book-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-address-book-o:before{content:"\f2b9"}.fa.fa-vcard:before{content:"\f2bb"}.fa.fa-address-card-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-address-card-o:before{content:"\f2bb"}.fa.fa-vcard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-vcard-o:before{content:"\f2bb"}.fa.fa-user-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-user-circle-o:before{content:"\f2bd"}.fa.fa-user-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-user-o:before{content:"\f007"}.fa.fa-id-badge{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-drivers-license:before{content:"\f2c2"}.fa.fa-id-card-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-id-card-o:before{content:"\f2c2"}.fa.fa-drivers-license-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-drivers-license-o:before{content:"\f2c2"}.fa.fa-free-code-camp,.fa.fa-quora,.fa.fa-telegram{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-thermometer-4:before,.fa.fa-thermometer:before{content:"\f2c7"}.fa.fa-thermometer-3:before{content:"\f2c8"}.fa.fa-thermometer-2:before{content:"\f2c9"}.fa.fa-thermometer-1:before{content:"\f2ca"}.fa.fa-thermometer-0:before{content:"\f2cb"}.fa.fa-bathtub:before,.fa.fa-s15:before{content:"\f2cd"}.fa.fa-window-maximize,.fa.fa-window-restore{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-rectangle:before{content:"\f410"}.fa.fa-window-close-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-window-close-o:before{content:"\f410"}.fa.fa-times-rectangle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-rectangle-o:before{content:"\f410"}.fa.fa-bandcamp,.fa.fa-eercast,.fa.fa-etsy,.fa.fa-grav,.fa.fa-imdb,.fa.fa-ravelry{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-eercast:before{content:"\f2da"}.fa.fa-snowflake-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-snowflake-o:before{content:"\f2dc"}.fa.fa-spotify,.fa.fa-superpowers,.fa.fa-wpexplorer{font-family:"Font Awesome 5 Brands";font-weight:400} \ No newline at end of file diff --git a/html/font-awesome/webfonts/fa-regular-400.eot b/html/font-awesome/webfonts/fa-regular-400.eot new file mode 100644 index 00000000..d62be2fa Binary files /dev/null and b/html/font-awesome/webfonts/fa-regular-400.eot differ diff --git a/html/font-awesome/webfonts/fa-regular-400.woff b/html/font-awesome/webfonts/fa-regular-400.woff new file mode 100644 index 00000000..43b1a9ae Binary files /dev/null and b/html/font-awesome/webfonts/fa-regular-400.woff differ diff --git a/html/font-awesome/webfonts/fa-solid-900.eot b/html/font-awesome/webfonts/fa-solid-900.eot new file mode 100644 index 00000000..c77baa8d Binary files /dev/null and b/html/font-awesome/webfonts/fa-solid-900.eot differ diff --git a/html/font-awesome/webfonts/fa-solid-900.woff b/html/font-awesome/webfonts/fa-solid-900.woff new file mode 100644 index 00000000..77c17862 Binary files /dev/null and b/html/font-awesome/webfonts/fa-solid-900.woff differ diff --git a/html/hard-hat-exclamation.png b/html/hard-hat-exclamation.png new file mode 100644 index 00000000..e22eb61b Binary files /dev/null and b/html/hard-hat-exclamation.png differ diff --git a/html/image-minus.png b/html/image-minus.png new file mode 100644 index 00000000..b2bac2c4 Binary files /dev/null and b/html/image-minus.png differ diff --git a/html/image-plus.png b/html/image-plus.png new file mode 100644 index 00000000..308c1ae0 Binary files /dev/null and b/html/image-plus.png differ diff --git a/html/images/bluentlogo.png b/html/images/bluentlogo.png new file mode 100644 index 00000000..d5614a96 Binary files /dev/null and b/html/images/bluentlogo.png differ diff --git a/html/images/loading.gif b/html/images/loading.gif new file mode 100644 index 00000000..6ec34d41 Binary files /dev/null and b/html/images/loading.gif differ diff --git a/html/images/ntlogo.png b/html/images/ntlogo.png new file mode 100644 index 00000000..6c03fa8b Binary files /dev/null and b/html/images/ntlogo.png differ diff --git a/html/images/sollogo.png b/html/images/sollogo.png new file mode 100644 index 00000000..58af799a Binary files /dev/null and b/html/images/sollogo.png differ diff --git a/html/images/talisman.png b/html/images/talisman.png new file mode 100644 index 00000000..0ece6373 Binary files /dev/null and b/html/images/talisman.png differ diff --git a/html/images/terralogo.png b/html/images/terralogo.png new file mode 100644 index 00000000..633ca53a Binary files /dev/null and b/html/images/terralogo.png differ diff --git a/html/map-pencil.png b/html/map-pencil.png new file mode 100644 index 00000000..a3804e18 Binary files /dev/null and b/html/map-pencil.png differ diff --git a/html/music-minus.png b/html/music-minus.png new file mode 100644 index 00000000..1b9478f4 Binary files /dev/null and b/html/music-minus.png differ diff --git a/html/music-plus.png b/html/music-plus.png new file mode 100644 index 00000000..ea7f36c6 Binary files /dev/null and b/html/music-plus.png differ diff --git a/html/panels.css b/html/panels.css new file mode 100644 index 00000000..ac44cf54 --- /dev/null +++ b/html/panels.css @@ -0,0 +1,10 @@ +body {padding:0px;margin:0px;} +#top {position:fixed;top:5px;left:10%;width:80%;text-align:center;background-color:#fff;border:2px solid #ccc;} +#main {position:relative;top:50px;left:3%;width:96%;text-align:center;z-index:0;} +#searchable {table-layout:fixed;width:100%;text-align:center;"#f4f4f4";} +tr.norm {background-color:#f4f4f4;} +tr.title {background-color:#ccc;} +tr.alt {background-color:#e7e7e7;} +.small {font-size:80%;} +a {text-decoration:none;color:#a0a;} +a:hover {color:#d3d;} diff --git a/html/player_panel.css b/html/player_panel.css new file mode 100644 index 00000000..6074c774 --- /dev/null +++ b/html/player_panel.css @@ -0,0 +1,30 @@ +html {overflow: auto;}; +body { +overflow:hidden; +font-family: Times; +background-repeat:repeat-x; +} +a {text-decoration: none;outline: none;border: none;margin:-1px;} +a:focus{outline:none;border: none;} +a:hover {Color:#0d0d0d;background:#505055;outline: none;border: none;text-decoration: none;} +a.active {text-decoration:none; text-decoration:none; Color:#533333;border: none;} +a.inactive:hover {text-decoration:none;Color:#0d0d0d;background:#bb0000;border: none;} +a.active:hover {text-decoration:none;Color:#bb0000;background:#0f0f0f;} +a.inactive:hover {text-decoration:none; Color:#0d0d0d; background:#bb0000;border: none;} +a img { border: 0; } +TABLE.winto { +z-index:-1; +position: absolute; +top: 12; +left:14; +background-position: bottom; +background-repeat:repeat-x; +border: 4px dotted #222222; +/* border-top:4px double #777777; */ +border-bottom: none; +border-top: none; +} + +TR { +border: 0px; +} \ No newline at end of file diff --git a/html/scales.png b/html/scales.png new file mode 100644 index 00000000..bb28dc9b Binary files /dev/null and b/html/scales.png differ diff --git a/html/search.js b/html/search.js new file mode 100644 index 00000000..ded0b928 --- /dev/null +++ b/html/search.js @@ -0,0 +1,33 @@ +function selectTextField(){ + var filter_text = document.getElementById('filter'); + filter_text.focus(); + filter_text.select(); +} +function updateSearch(){ + var input_form = document.getElementById('filter'); + var filter = input_form.value.toLowerCase(); + input_form.value = filter; + var table = document.getElementById('searchable'); + var alt_style = 'norm'; + for(var i = 0; i < table.rows.length; i++){ + try{ + var row = table.rows[i]; + if(row.className == 'title') continue; + var found=0; + for(var j = 0; j < row.cells.length; j++){ + var cell = row.cells[j]; + if(cell.innerText.toLowerCase().indexOf(filter) != -1){ + found=1; + break; + } + } + if(found == 0) row.style.display='none'; + else{ + row.style.display='block'; + row.className = alt_style; + if(alt_style == 'alt') alt_style = 'norm'; + else alt_style = 'alt'; + } + }catch(err) { } + } +} \ No newline at end of file diff --git a/html/spacemag.css b/html/spacemag.css new file mode 100644 index 00000000..4c867289 --- /dev/null +++ b/html/spacemag.css @@ -0,0 +1,15 @@ +.heading{ + padding-top: 32px; +} + +.author{ + padding-bottom:16px; + font-style: italic; +} + +.cover{ + margin:auto; + display:block; + height:600px; + padding-bottom:32px; +} diff --git a/html/spell-check.png b/html/spell-check.png new file mode 100644 index 00000000..70b066d1 Binary files /dev/null and b/html/spell-check.png differ diff --git a/html/templates/footer.html b/html/templates/footer.html new file mode 100644 index 00000000..5d98f73b --- /dev/null +++ b/html/templates/footer.html @@ -0,0 +1,13 @@ + + +GoonStation 13 Development Team +
                + Coders: Stuntwaffle, Showtime, Pantaloons, Nannek, Keelin, Exadv1, hobnob, Justicefries, 0staf, sniperchance, AngriestIBM, BrianOBlivion
                + Spriters: Supernorn, Haruhi, Stuntwaffle, Pantaloons, Rho, SynthOrange, I Said No
                +
                +
                +

                Creative Commons License
                Except where otherwise noted, Goon Station 13 is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 License.
                Rights are currently extended to SomethingAwful Goons only.

                +

                Some icons by Yusuke Kamiyamane. All rights reserved. Licensed under a Creative Commons Attribution 3.0 License.

                +
            + + diff --git a/html/templates/header.html b/html/templates/header.html new file mode 100644 index 00000000..d6edd780 --- /dev/null +++ b/html/templates/header.html @@ -0,0 +1,58 @@ + + + + Baystation 12 Changelog + + + + + + + +\s*$/g,Lt={option:[1,""],legend:[1,"
            ","
            "],area:[1,"",""],param:[1,"",""],thead:[1,"
            + + + + +
            +
            Space Station 13
            + +

            + Code licensed under AGPLv3. Content licensed under CC BY-SA 3.0.

            + Visit our IRC channel: #bs12 on irc.sorcery.net +
            + +
            Baystation 12 Credit List + + + + +
            + Current Project Maintainers: -Click Here-
            + Currently Active GitHub contributor list: -Click Here-
            + Code: Abi79, Aryn, Cael_Aislinn, Ccomp5950, Chinsky, cib, CompactNinja, DopeGhoti, Erthilo, Hawk_v3, Head, Ispil, JoeyJo0, Lexusjjss, Melonstorm, Miniature, Mloc, NerdyBoy1104, PsiOmegaDelta, SkyMarshal, Snapshot, Spectre, Strumpetplaya, Sunfall, Tastyfish, Uristqwerty
            + Sprites: Apple_Master, Arcalane, Chinsky, CompactNinja, Deus Dactyl, Erthilo, Flashkirby, JoeyJo0, Miniature, Searif, Xenone, faux
            + Sounds: Aryn
            + Main Testers: Anyone who has submitted a bug to the issue tracker
            + Thanks to: /tg/ station, /vg/station, GoonStation devs, the original SpaceStation developers and Invisty for the title image.
            Also a thanks to anybody who has contributed who is not listed here :( Ask to be added here on irc.
            +
            Have a bug to report?
            Visit our Issue Tracker.
            +
            + + +
            \ No newline at end of file diff --git a/html/tick-circle.png b/html/tick-circle.png new file mode 100644 index 00000000..bcc4dc24 Binary files /dev/null and b/html/tick-circle.png differ diff --git a/html/wrench-screwdriver.png b/html/wrench-screwdriver.png new file mode 100644 index 00000000..1a59de68 Binary files /dev/null and b/html/wrench-screwdriver.png differ diff --git a/icons/480x480.dmi b/icons/480x480.dmi new file mode 100644 index 00000000..90ea9fbd Binary files /dev/null and b/icons/480x480.dmi differ diff --git a/icons/48x48/walls48.dmi b/icons/48x48/walls48.dmi new file mode 100644 index 00000000..7e3dbe8b Binary files /dev/null and b/icons/48x48/walls48.dmi differ diff --git a/icons/LICENSE.md b/icons/LICENSE.md new file mode 100644 index 00000000..bbf46885 --- /dev/null +++ b/icons/LICENSE.md @@ -0,0 +1,2 @@ +## Copyright (C) 2020 Interstation12. All rights reserved. +**All original art assets aren't covered under Goonstation's license (CC BY-NC-SA) or GPL/AGPL. You may not rip the original art assets and use them in your project without consent.** \ No newline at end of file diff --git a/icons/PSD files/asteroiddustoverlay.psd b/icons/PSD files/asteroiddustoverlay.psd new file mode 100644 index 00000000..a8e8f572 Binary files /dev/null and b/icons/PSD files/asteroiddustoverlay.psd differ diff --git a/icons/PSD files/door.psd b/icons/PSD files/door.psd new file mode 100644 index 00000000..44a22a8b Binary files /dev/null and b/icons/PSD files/door.psd differ diff --git a/icons/Testing/Zone.dmi b/icons/Testing/Zone.dmi new file mode 100644 index 00000000..1d8ab851 Binary files /dev/null and b/icons/Testing/Zone.dmi differ diff --git a/icons/Testing/air_meter.dmi b/icons/Testing/air_meter.dmi new file mode 100644 index 00000000..56d1ff18 Binary files /dev/null and b/icons/Testing/air_meter.dmi differ diff --git a/icons/Testing/atmos_testing.dmi b/icons/Testing/atmos_testing.dmi new file mode 100644 index 00000000..142bd4cb Binary files /dev/null and b/icons/Testing/atmos_testing.dmi differ diff --git a/icons/Testing/turf_analysis.dmi b/icons/Testing/turf_analysis.dmi new file mode 100644 index 00000000..e3aac1eb Binary files /dev/null and b/icons/Testing/turf_analysis.dmi differ diff --git a/icons/VendingMachineBG.png b/icons/VendingMachineBG.png new file mode 100644 index 00000000..5d7f010d Binary files /dev/null and b/icons/VendingMachineBG.png differ diff --git a/icons/am_engine.dmi b/icons/am_engine.dmi new file mode 100644 index 00000000..bcaa8e49 Binary files /dev/null and b/icons/am_engine.dmi differ diff --git a/icons/atmos/clamp.dmi b/icons/atmos/clamp.dmi new file mode 100644 index 00000000..ed22b930 Binary files /dev/null and b/icons/atmos/clamp.dmi differ diff --git a/icons/atmos/connector.dmi b/icons/atmos/connector.dmi new file mode 100644 index 00000000..cf4ea7a3 Binary files /dev/null and b/icons/atmos/connector.dmi differ diff --git a/icons/atmos/digital_tvalve.dmi b/icons/atmos/digital_tvalve.dmi new file mode 100644 index 00000000..b34d2903 Binary files /dev/null and b/icons/atmos/digital_tvalve.dmi differ diff --git a/icons/atmos/digital_valve.dmi b/icons/atmos/digital_valve.dmi new file mode 100644 index 00000000..b1adc8b6 Binary files /dev/null and b/icons/atmos/digital_valve.dmi differ diff --git a/icons/atmos/filter.dmi b/icons/atmos/filter.dmi new file mode 100644 index 00000000..8b5cd81c Binary files /dev/null and b/icons/atmos/filter.dmi differ diff --git a/icons/atmos/heat.dmi b/icons/atmos/heat.dmi new file mode 100644 index 00000000..1014c201 Binary files /dev/null and b/icons/atmos/heat.dmi differ diff --git a/icons/atmos/injector.dmi b/icons/atmos/injector.dmi new file mode 100644 index 00000000..03a60d2e Binary files /dev/null and b/icons/atmos/injector.dmi differ diff --git a/icons/atmos/junction.dmi b/icons/atmos/junction.dmi new file mode 100644 index 00000000..892f5823 Binary files /dev/null and b/icons/atmos/junction.dmi differ diff --git a/icons/atmos/manifold.dmi b/icons/atmos/manifold.dmi new file mode 100644 index 00000000..b7c5d0a2 Binary files /dev/null and b/icons/atmos/manifold.dmi differ diff --git a/icons/atmos/mixer.dmi b/icons/atmos/mixer.dmi new file mode 100644 index 00000000..0fcb9282 Binary files /dev/null and b/icons/atmos/mixer.dmi differ diff --git a/icons/atmos/omni_devices.dmi b/icons/atmos/omni_devices.dmi new file mode 100644 index 00000000..494ea7e2 Binary files /dev/null and b/icons/atmos/omni_devices.dmi differ diff --git a/icons/atmos/oxyregenerator.dmi b/icons/atmos/oxyregenerator.dmi new file mode 100644 index 00000000..f40b9409 Binary files /dev/null and b/icons/atmos/oxyregenerator.dmi differ diff --git a/icons/atmos/passive_gate.dmi b/icons/atmos/passive_gate.dmi new file mode 100644 index 00000000..ff1b7a5a Binary files /dev/null and b/icons/atmos/passive_gate.dmi differ diff --git a/icons/atmos/pipe_underlays.dmi b/icons/atmos/pipe_underlays.dmi new file mode 100644 index 00000000..f6f38a9a Binary files /dev/null and b/icons/atmos/pipe_underlays.dmi differ diff --git a/icons/atmos/pipes.dmi b/icons/atmos/pipes.dmi new file mode 100644 index 00000000..6bd0b15f Binary files /dev/null and b/icons/atmos/pipes.dmi differ diff --git a/icons/atmos/pump.dmi b/icons/atmos/pump.dmi new file mode 100644 index 00000000..a1e2d43c Binary files /dev/null and b/icons/atmos/pump.dmi differ diff --git a/icons/atmos/tank.dmi b/icons/atmos/tank.dmi new file mode 100644 index 00000000..89c71bc7 Binary files /dev/null and b/icons/atmos/tank.dmi differ diff --git a/icons/atmos/tvalve.dmi b/icons/atmos/tvalve.dmi new file mode 100644 index 00000000..197862b3 Binary files /dev/null and b/icons/atmos/tvalve.dmi differ diff --git a/icons/atmos/valve.dmi b/icons/atmos/valve.dmi new file mode 100644 index 00000000..04351917 Binary files /dev/null and b/icons/atmos/valve.dmi differ diff --git a/icons/atmos/vent_pump.dmi b/icons/atmos/vent_pump.dmi new file mode 100644 index 00000000..88461036 Binary files /dev/null and b/icons/atmos/vent_pump.dmi differ diff --git a/icons/atmos/vent_scrubber.dmi b/icons/atmos/vent_scrubber.dmi new file mode 100644 index 00000000..79f25ddc Binary files /dev/null and b/icons/atmos/vent_scrubber.dmi differ diff --git a/icons/atmos/volume_pump.dmi b/icons/atmos/volume_pump.dmi new file mode 100644 index 00000000..9114b6ac Binary files /dev/null and b/icons/atmos/volume_pump.dmi differ diff --git a/icons/chattags.dmi b/icons/chattags.dmi new file mode 100644 index 00000000..5cfdcd68 Binary files /dev/null and b/icons/chattags.dmi differ diff --git a/icons/covershield.dmi b/icons/covershield.dmi new file mode 100644 index 00000000..b3d8b21e Binary files /dev/null and b/icons/covershield.dmi differ diff --git a/icons/dispensebutton_bg.png b/icons/dispensebutton_bg.png new file mode 100644 index 00000000..195c0211 Binary files /dev/null and b/icons/dispensebutton_bg.png differ diff --git a/icons/effects/128x48.dmi b/icons/effects/128x48.dmi new file mode 100644 index 00000000..71038ffd Binary files /dev/null and b/icons/effects/128x48.dmi differ diff --git a/icons/effects/160x160.dmi b/icons/effects/160x160.dmi new file mode 100644 index 00000000..15b36ba2 Binary files /dev/null and b/icons/effects/160x160.dmi differ diff --git a/icons/effects/224x224.dmi b/icons/effects/224x224.dmi new file mode 100644 index 00000000..e7d41bcd Binary files /dev/null and b/icons/effects/224x224.dmi differ diff --git a/icons/effects/288x288.dmi b/icons/effects/288x288.dmi new file mode 100644 index 00000000..6184d3d5 Binary files /dev/null and b/icons/effects/288x288.dmi differ diff --git a/icons/effects/352x352.dmi b/icons/effects/352x352.dmi new file mode 100644 index 00000000..3afd87d3 Binary files /dev/null and b/icons/effects/352x352.dmi differ diff --git a/icons/effects/416x416.dmi b/icons/effects/416x416.dmi new file mode 100644 index 00000000..93f4ba7d Binary files /dev/null and b/icons/effects/416x416.dmi differ diff --git a/icons/effects/96x96.dmi b/icons/effects/96x96.dmi new file mode 100644 index 00000000..c6fdf7df Binary files /dev/null and b/icons/effects/96x96.dmi differ diff --git a/icons/effects/Targeted.dmi b/icons/effects/Targeted.dmi new file mode 100644 index 00000000..6d61505e Binary files /dev/null and b/icons/effects/Targeted.dmi differ diff --git a/icons/effects/ULIcons.dmi b/icons/effects/ULIcons.dmi new file mode 100644 index 00000000..3104e6ea Binary files /dev/null and b/icons/effects/ULIcons.dmi differ diff --git a/icons/effects/alert.dmi b/icons/effects/alert.dmi new file mode 100644 index 00000000..51b81750 Binary files /dev/null and b/icons/effects/alert.dmi differ diff --git a/icons/effects/alphacolors.dmi b/icons/effects/alphacolors.dmi new file mode 100644 index 00000000..02316fbf Binary files /dev/null and b/icons/effects/alphacolors.dmi differ diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi new file mode 100644 index 00000000..dc0c7b9c Binary files /dev/null and b/icons/effects/beam.dmi differ diff --git a/icons/effects/blood.dmi b/icons/effects/blood.dmi new file mode 100644 index 00000000..bcc7c32f Binary files /dev/null and b/icons/effects/blood.dmi differ diff --git a/icons/effects/cameravis.dmi b/icons/effects/cameravis.dmi new file mode 100644 index 00000000..2b819836 Binary files /dev/null and b/icons/effects/cameravis.dmi differ diff --git a/icons/effects/chemsmoke.dmi b/icons/effects/chemsmoke.dmi new file mode 100644 index 00000000..4308e3d4 Binary files /dev/null and b/icons/effects/chemsmoke.dmi differ diff --git a/icons/effects/contamination.dmi b/icons/effects/contamination.dmi new file mode 100644 index 00000000..36739421 Binary files /dev/null and b/icons/effects/contamination.dmi differ diff --git a/icons/effects/crayondecal.dmi b/icons/effects/crayondecal.dmi new file mode 100644 index 00000000..e1966e9b Binary files /dev/null and b/icons/effects/crayondecal.dmi differ diff --git a/icons/effects/drip.dmi b/icons/effects/drip.dmi new file mode 100644 index 00000000..a756bc10 Binary files /dev/null and b/icons/effects/drip.dmi differ diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi new file mode 100644 index 00000000..b24e6fae Binary files /dev/null and b/icons/effects/effects.dmi differ diff --git a/icons/effects/fire.dmi b/icons/effects/fire.dmi new file mode 100644 index 00000000..0de9a411 Binary files /dev/null and b/icons/effects/fire.dmi differ diff --git a/icons/effects/fluidtracks.dmi b/icons/effects/fluidtracks.dmi new file mode 100644 index 00000000..bc04766b Binary files /dev/null and b/icons/effects/fluidtracks.dmi differ diff --git a/icons/effects/footprints.dmi b/icons/effects/footprints.dmi new file mode 100644 index 00000000..b849de00 Binary files /dev/null and b/icons/effects/footprints.dmi differ diff --git a/icons/effects/footstepsound.dmi b/icons/effects/footstepsound.dmi new file mode 100644 index 00000000..3e03adf0 Binary files /dev/null and b/icons/effects/footstepsound.dmi differ diff --git a/icons/effects/genetics.dmi b/icons/effects/genetics.dmi new file mode 100644 index 00000000..8e31fea9 Binary files /dev/null and b/icons/effects/genetics.dmi differ diff --git a/icons/effects/lighting.dmi b/icons/effects/lighting.dmi new file mode 100644 index 00000000..47aad826 Binary files /dev/null and b/icons/effects/lighting.dmi differ diff --git a/icons/effects/lighting_overlay.dmi b/icons/effects/lighting_overlay.dmi new file mode 100644 index 00000000..fa261bd0 Binary files /dev/null and b/icons/effects/lighting_overlay.dmi differ diff --git a/icons/effects/lighting_overlay.png b/icons/effects/lighting_overlay.png new file mode 100644 index 00000000..b317268b Binary files /dev/null and b/icons/effects/lighting_overlay.png differ diff --git a/icons/effects/liquid.dmi b/icons/effects/liquid.dmi new file mode 100644 index 00000000..e43e5e53 Binary files /dev/null and b/icons/effects/liquid.dmi differ diff --git a/icons/effects/numbers.dmi b/icons/effects/numbers.dmi new file mode 100644 index 00000000..fcf9463c Binary files /dev/null and b/icons/effects/numbers.dmi differ diff --git a/icons/effects/plasma.dmi b/icons/effects/plasma.dmi new file mode 100644 index 00000000..dc07f1bd Binary files /dev/null and b/icons/effects/plasma.dmi differ diff --git a/icons/effects/pooeffect.dmi b/icons/effects/pooeffect.dmi new file mode 100644 index 00000000..7eb00045 Binary files /dev/null and b/icons/effects/pooeffect.dmi differ diff --git a/icons/effects/progessbar.dmi b/icons/effects/progessbar.dmi new file mode 100644 index 00000000..e8e5022d Binary files /dev/null and b/icons/effects/progessbar.dmi differ diff --git a/icons/effects/projectiles.dmi b/icons/effects/projectiles.dmi new file mode 100644 index 00000000..e61595bd Binary files /dev/null and b/icons/effects/projectiles.dmi differ diff --git a/icons/effects/projectiles/impact.dmi b/icons/effects/projectiles/impact.dmi new file mode 100644 index 00000000..4f93a5f7 Binary files /dev/null and b/icons/effects/projectiles/impact.dmi differ diff --git a/icons/effects/projectiles/muzzle.dmi b/icons/effects/projectiles/muzzle.dmi new file mode 100644 index 00000000..a9755b5d Binary files /dev/null and b/icons/effects/projectiles/muzzle.dmi differ diff --git a/icons/effects/projectiles/tracer.dmi b/icons/effects/projectiles/tracer.dmi new file mode 100644 index 00000000..651cd1ac Binary files /dev/null and b/icons/effects/projectiles/tracer.dmi differ diff --git a/icons/effects/spacevines.dmi b/icons/effects/spacevines.dmi new file mode 100644 index 00000000..7087416a Binary files /dev/null and b/icons/effects/spacevines.dmi differ diff --git a/icons/effects/species.dmi b/icons/effects/species.dmi new file mode 100644 index 00000000..8c231b9b Binary files /dev/null and b/icons/effects/species.dmi differ diff --git a/icons/effects/ss13_dark_alpha6.dmi b/icons/effects/ss13_dark_alpha6.dmi new file mode 100644 index 00000000..74233735 Binary files /dev/null and b/icons/effects/ss13_dark_alpha6.dmi differ diff --git a/icons/effects/ss13_dark_alpha7.dmi b/icons/effects/ss13_dark_alpha7.dmi new file mode 100644 index 00000000..b2706217 Binary files /dev/null and b/icons/effects/ss13_dark_alpha7.dmi differ diff --git a/icons/effects/ss13_dark_alpha7_DEBUG.dmi b/icons/effects/ss13_dark_alpha7_DEBUG.dmi new file mode 100644 index 00000000..91beaddd Binary files /dev/null and b/icons/effects/ss13_dark_alpha7_DEBUG.dmi differ diff --git a/icons/effects/ss13_dark_alpha7_old.dmi b/icons/effects/ss13_dark_alpha7_old.dmi new file mode 100644 index 00000000..85178c4e Binary files /dev/null and b/icons/effects/ss13_dark_alpha7_old.dmi differ diff --git a/icons/effects/standard/standard.dmi b/icons/effects/standard/standard.dmi new file mode 100644 index 00000000..ffca994c Binary files /dev/null and b/icons/effects/standard/standard.dmi differ diff --git a/icons/effects/standard/standard1.dmi b/icons/effects/standard/standard1.dmi new file mode 100644 index 00000000..70924263 Binary files /dev/null and b/icons/effects/standard/standard1.dmi differ diff --git a/icons/effects/standard/standard2.dmi b/icons/effects/standard/standard2.dmi new file mode 100644 index 00000000..c2d5e319 Binary files /dev/null and b/icons/effects/standard/standard2.dmi differ diff --git a/icons/effects/standard/standard3.dmi b/icons/effects/standard/standard3.dmi new file mode 100644 index 00000000..73cc6120 Binary files /dev/null and b/icons/effects/standard/standard3.dmi differ diff --git a/icons/effects/standard/standard4.dmi b/icons/effects/standard/standard4.dmi new file mode 100644 index 00000000..0d807ddf Binary files /dev/null and b/icons/effects/standard/standard4.dmi differ diff --git a/icons/effects/standard/standard5.dmi b/icons/effects/standard/standard5.dmi new file mode 100644 index 00000000..e68cbe90 Binary files /dev/null and b/icons/effects/standard/standard5.dmi differ diff --git a/icons/effects/standard/standard6.dmi b/icons/effects/standard/standard6.dmi new file mode 100644 index 00000000..82ac8948 Binary files /dev/null and b/icons/effects/standard/standard6.dmi differ diff --git a/icons/effects/static.dmi b/icons/effects/static.dmi new file mode 100644 index 00000000..63f6a1e6 Binary files /dev/null and b/icons/effects/static.dmi differ diff --git a/icons/effects/station_explosion.dmi b/icons/effects/station_explosion.dmi new file mode 100644 index 00000000..3edf02c2 Binary files /dev/null and b/icons/effects/station_explosion.dmi differ diff --git a/icons/effects/tile_effects.dmi b/icons/effects/tile_effects.dmi new file mode 100644 index 00000000..f57b60e0 Binary files /dev/null and b/icons/effects/tile_effects.dmi differ diff --git a/icons/effects/tomatodecal.dmi b/icons/effects/tomatodecal.dmi new file mode 100644 index 00000000..a67e1a5e Binary files /dev/null and b/icons/effects/tomatodecal.dmi differ diff --git a/icons/effects/uristrunes.dmi b/icons/effects/uristrunes.dmi new file mode 100644 index 00000000..ce195cf9 Binary files /dev/null and b/icons/effects/uristrunes.dmi differ diff --git a/icons/effects/wallrot.dmi b/icons/effects/wallrot.dmi new file mode 100644 index 00000000..3ca54677 Binary files /dev/null and b/icons/effects/wallrot.dmi differ diff --git a/icons/effects/warning_stripes.dmi b/icons/effects/warning_stripes.dmi new file mode 100644 index 00000000..a0cf5e32 Binary files /dev/null and b/icons/effects/warning_stripes.dmi differ diff --git a/icons/effects/water.dmi b/icons/effects/water.dmi new file mode 100644 index 00000000..1cc75401 Binary files /dev/null and b/icons/effects/water.dmi differ diff --git a/icons/effects/weather.dmi b/icons/effects/weather.dmi new file mode 100644 index 00000000..1f8d6d99 Binary files /dev/null and b/icons/effects/weather.dmi differ diff --git a/icons/emoji.dmi b/icons/emoji.dmi new file mode 100644 index 00000000..66b9b20b Binary files /dev/null and b/icons/emoji.dmi differ diff --git a/icons/interbay_64x64.png b/icons/interbay_64x64.png new file mode 100644 index 00000000..393b7fab Binary files /dev/null and b/icons/interbay_64x64.png differ diff --git a/icons/jungle.dmi b/icons/jungle.dmi new file mode 100644 index 00000000..a4ee3d53 Binary files /dev/null and b/icons/jungle.dmi differ diff --git a/icons/mecha/mech_bay.dmi b/icons/mecha/mech_bay.dmi new file mode 100644 index 00000000..e46f668f Binary files /dev/null and b/icons/mecha/mech_bay.dmi differ diff --git a/icons/mecha/mech_construct.dmi b/icons/mecha/mech_construct.dmi new file mode 100644 index 00000000..9213e418 Binary files /dev/null and b/icons/mecha/mech_construct.dmi differ diff --git a/icons/mecha/mech_construction.dmi b/icons/mecha/mech_construction.dmi new file mode 100644 index 00000000..5cf5b9ca Binary files /dev/null and b/icons/mecha/mech_construction.dmi differ diff --git a/icons/mecha/mech_fab.dmi b/icons/mecha/mech_fab.dmi new file mode 100644 index 00000000..4785b0ce Binary files /dev/null and b/icons/mecha/mech_fab.dmi differ diff --git a/icons/mecha/mecha.dmi b/icons/mecha/mecha.dmi new file mode 100644 index 00000000..25ef7f51 Binary files /dev/null and b/icons/mecha/mecha.dmi differ diff --git a/icons/mecha/mecha_equipment.dmi b/icons/mecha/mecha_equipment.dmi new file mode 100644 index 00000000..5f1898b8 Binary files /dev/null and b/icons/mecha/mecha_equipment.dmi differ diff --git a/icons/mecha/mecha_mouse.dmi b/icons/mecha/mecha_mouse.dmi new file mode 100644 index 00000000..4b46a446 Binary files /dev/null and b/icons/mecha/mecha_mouse.dmi differ diff --git a/icons/meteor_turret.dmi b/icons/meteor_turret.dmi new file mode 100644 index 00000000..3f62c56b Binary files /dev/null and b/icons/meteor_turret.dmi differ diff --git a/icons/minimap.dmi b/icons/minimap.dmi new file mode 100644 index 00000000..26aecb84 Binary files /dev/null and b/icons/minimap.dmi differ diff --git a/icons/misc/aim.dmi b/icons/misc/aim.dmi new file mode 100644 index 00000000..d745b860 Binary files /dev/null and b/icons/misc/aim.dmi differ diff --git a/icons/misc/beach.dmi b/icons/misc/beach.dmi new file mode 100644 index 00000000..cb6e3acb Binary files /dev/null and b/icons/misc/beach.dmi differ diff --git a/icons/misc/beach2.dmi b/icons/misc/beach2.dmi new file mode 100644 index 00000000..0de278ef Binary files /dev/null and b/icons/misc/beach2.dmi differ diff --git a/icons/misc/buildmode.dmi b/icons/misc/buildmode.dmi new file mode 100644 index 00000000..2550a1a4 Binary files /dev/null and b/icons/misc/buildmode.dmi differ diff --git a/icons/misc/debug_connect.dmi b/icons/misc/debug_connect.dmi new file mode 100644 index 00000000..0c96c86d Binary files /dev/null and b/icons/misc/debug_connect.dmi differ diff --git a/icons/misc/debug_group.dmi b/icons/misc/debug_group.dmi new file mode 100644 index 00000000..a9cf3ee8 Binary files /dev/null and b/icons/misc/debug_group.dmi differ diff --git a/icons/misc/debug_rebuild.dmi b/icons/misc/debug_rebuild.dmi new file mode 100644 index 00000000..b7cde5aa Binary files /dev/null and b/icons/misc/debug_rebuild.dmi differ diff --git a/icons/misc/debug_space.dmi b/icons/misc/debug_space.dmi new file mode 100644 index 00000000..44d01dfe Binary files /dev/null and b/icons/misc/debug_space.dmi differ diff --git a/icons/misc/imap.dmi b/icons/misc/imap.dmi new file mode 100644 index 00000000..3185c883 Binary files /dev/null and b/icons/misc/imap.dmi differ diff --git a/icons/misc/inpipe.dmi b/icons/misc/inpipe.dmi new file mode 100644 index 00000000..18b19d12 Binary files /dev/null and b/icons/misc/inpipe.dmi differ diff --git a/icons/misc/largeui.dmi b/icons/misc/largeui.dmi new file mode 100644 index 00000000..24a89b85 Binary files /dev/null and b/icons/misc/largeui.dmi differ diff --git a/icons/misc/mark.dmi b/icons/misc/mark.dmi new file mode 100644 index 00000000..bec1920b Binary files /dev/null and b/icons/misc/mark.dmi differ diff --git a/icons/misc/security_state.dmi b/icons/misc/security_state.dmi new file mode 100644 index 00000000..0d4835e1 Binary files /dev/null and b/icons/misc/security_state.dmi differ diff --git a/icons/misc/static.dmi b/icons/misc/static.dmi new file mode 100644 index 00000000..1650bf8d Binary files /dev/null and b/icons/misc/static.dmi differ diff --git a/icons/misc/stressed_aim.dmi b/icons/misc/stressed_aim.dmi new file mode 100644 index 00000000..7d603925 Binary files /dev/null and b/icons/misc/stressed_aim.dmi differ diff --git a/icons/mob/AI.dmi b/icons/mob/AI.dmi new file mode 100644 index 00000000..b0c2752a Binary files /dev/null and b/icons/mob/AI.dmi differ diff --git a/icons/mob/OnFire.dmi b/icons/mob/OnFire.dmi new file mode 100644 index 00000000..50182795 Binary files /dev/null and b/icons/mob/OnFire.dmi differ diff --git a/icons/mob/Shafra.dmi b/icons/mob/Shafra.dmi new file mode 100644 index 00000000..827539ce Binary files /dev/null and b/icons/mob/Shafra.dmi differ diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi new file mode 100644 index 00000000..400db51d Binary files /dev/null and b/icons/mob/actions.dmi differ diff --git a/icons/mob/alien.dmi b/icons/mob/alien.dmi new file mode 100644 index 00000000..171abcf1 Binary files /dev/null and b/icons/mob/alien.dmi differ diff --git a/icons/mob/alienqueen.dmi b/icons/mob/alienqueen.dmi new file mode 100644 index 00000000..15621520 Binary files /dev/null and b/icons/mob/alienqueen.dmi differ diff --git a/icons/mob/amorph.dmi b/icons/mob/amorph.dmi new file mode 100644 index 00000000..5425adce Binary files /dev/null and b/icons/mob/amorph.dmi differ diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi new file mode 100644 index 00000000..427c179c Binary files /dev/null and b/icons/mob/animal.dmi differ diff --git a/icons/mob/armalis.dmi b/icons/mob/armalis.dmi new file mode 100644 index 00000000..dc471f91 Binary files /dev/null and b/icons/mob/armalis.dmi differ diff --git a/icons/mob/bandage.dmi b/icons/mob/bandage.dmi new file mode 100644 index 00000000..bab279f6 Binary files /dev/null and b/icons/mob/bandage.dmi differ diff --git a/icons/mob/bats.dmi b/icons/mob/bats.dmi new file mode 100644 index 00000000..74466935 Binary files /dev/null and b/icons/mob/bats.dmi differ diff --git a/icons/mob/biocraps.dmi b/icons/mob/biocraps.dmi new file mode 100644 index 00000000..1bcbec01 Binary files /dev/null and b/icons/mob/biocraps.dmi differ diff --git a/icons/mob/blob.dmi b/icons/mob/blob.dmi new file mode 100644 index 00000000..49d49a10 Binary files /dev/null and b/icons/mob/blob.dmi differ diff --git a/icons/mob/cold_breath.dmi b/icons/mob/cold_breath.dmi new file mode 100644 index 00000000..5ad4e752 Binary files /dev/null and b/icons/mob/cold_breath.dmi differ diff --git a/icons/mob/collar.dmi b/icons/mob/collar.dmi new file mode 100644 index 00000000..0c768d75 Binary files /dev/null and b/icons/mob/collar.dmi differ diff --git a/icons/mob/corgi_back.dmi b/icons/mob/corgi_back.dmi new file mode 100644 index 00000000..81626df0 Binary files /dev/null and b/icons/mob/corgi_back.dmi differ diff --git a/icons/mob/corgi_head.dmi b/icons/mob/corgi_head.dmi new file mode 100644 index 00000000..105bdf47 Binary files /dev/null and b/icons/mob/corgi_head.dmi differ diff --git a/icons/mob/crafting.dmi b/icons/mob/crafting.dmi new file mode 100644 index 00000000..c19fbae9 Binary files /dev/null and b/icons/mob/crafting.dmi differ diff --git a/icons/mob/critter.dmi b/icons/mob/critter.dmi new file mode 100644 index 00000000..043b388e Binary files /dev/null and b/icons/mob/critter.dmi differ diff --git a/icons/mob/custom_items_mob.dmi b/icons/mob/custom_items_mob.dmi new file mode 100644 index 00000000..e69de29b diff --git a/icons/mob/custom_synthetic.dmi b/icons/mob/custom_synthetic.dmi new file mode 100644 index 00000000..e69de29b diff --git a/icons/mob/dam_child.dmi b/icons/mob/dam_child.dmi new file mode 100644 index 00000000..526e55ec Binary files /dev/null and b/icons/mob/dam_child.dmi differ diff --git a/icons/mob/dam_human.dmi b/icons/mob/dam_human.dmi new file mode 100644 index 00000000..8211b09b Binary files /dev/null and b/icons/mob/dam_human.dmi differ diff --git a/icons/mob/damagenoise.dmi b/icons/mob/damagenoise.dmi new file mode 100644 index 00000000..248b7804 Binary files /dev/null and b/icons/mob/damagenoise.dmi differ diff --git a/icons/mob/deity_big.dmi b/icons/mob/deity_big.dmi new file mode 100644 index 00000000..953f44d1 Binary files /dev/null and b/icons/mob/deity_big.dmi differ diff --git a/icons/mob/eye.dmi b/icons/mob/eye.dmi new file mode 100644 index 00000000..64ca1b10 Binary files /dev/null and b/icons/mob/eye.dmi differ diff --git a/icons/mob/gimmick_head.dmi b/icons/mob/gimmick_head.dmi new file mode 100644 index 00000000..8fe24175 Binary files /dev/null and b/icons/mob/gimmick_head.dmi differ diff --git a/icons/mob/hide.dmi b/icons/mob/hide.dmi new file mode 100644 index 00000000..b656223e Binary files /dev/null and b/icons/mob/hide.dmi differ diff --git a/icons/mob/hivebot.dmi b/icons/mob/hivebot.dmi new file mode 100644 index 00000000..cb139963 Binary files /dev/null and b/icons/mob/hivebot.dmi differ diff --git a/icons/mob/holder_complex.dmi b/icons/mob/holder_complex.dmi new file mode 100644 index 00000000..0c0235da Binary files /dev/null and b/icons/mob/holder_complex.dmi differ diff --git a/icons/mob/hologram.dmi b/icons/mob/hologram.dmi new file mode 100644 index 00000000..11d9bfda Binary files /dev/null and b/icons/mob/hologram.dmi differ diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi new file mode 100644 index 00000000..87ef4632 Binary files /dev/null and b/icons/mob/hud.dmi differ diff --git a/icons/mob/hud_med.dmi b/icons/mob/hud_med.dmi new file mode 100644 index 00000000..705886a5 Binary files /dev/null and b/icons/mob/hud_med.dmi differ diff --git a/icons/mob/human.dmi b/icons/mob/human.dmi new file mode 100644 index 00000000..fbe2ea2b Binary files /dev/null and b/icons/mob/human.dmi differ diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi new file mode 100644 index 00000000..08feef58 Binary files /dev/null and b/icons/mob/human_face.dmi differ diff --git a/icons/mob/human_races/child/dam_human.dmi b/icons/mob/human_races/child/dam_human.dmi new file mode 100644 index 00000000..301dfac6 Binary files /dev/null and b/icons/mob/human_races/child/dam_human.dmi differ diff --git a/icons/mob/human_races/child/r_child.dmi b/icons/mob/human_races/child/r_child.dmi new file mode 100644 index 00000000..b42e8e33 Binary files /dev/null and b/icons/mob/human_races/child/r_child.dmi differ diff --git a/icons/mob/human_races/child/r_def_child.dmi b/icons/mob/human_races/child/r_def_child.dmi new file mode 100644 index 00000000..bbb71096 Binary files /dev/null and b/icons/mob/human_races/child/r_def_child.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/bishop/bishop_alt.dmi b/icons/mob/human_races/cyberlimbs/bishop/bishop_alt.dmi new file mode 100644 index 00000000..e403436d Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/bishop/bishop_alt.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi b/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi new file mode 100644 index 00000000..ce332e9b Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/bishop/bishop_monitor.dmi b/icons/mob/human_races/cyberlimbs/bishop/bishop_monitor.dmi new file mode 100644 index 00000000..edd2236c Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/bishop/bishop_monitor.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_alt.dmi b/icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_alt.dmi new file mode 100644 index 00000000..3b6daa48 Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_alt.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_main.dmi b/icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_main.dmi new file mode 100644 index 00000000..7e075269 Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_main.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_monitor.dmi b/icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_monitor.dmi new file mode 100644 index 00000000..5f3d72f3 Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_monitor.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/morpheus/morpheus_alt.dmi b/icons/mob/human_races/cyberlimbs/morpheus/morpheus_alt.dmi new file mode 100644 index 00000000..7a0211e6 Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/morpheus/morpheus_alt.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/morpheus/morpheus_main.dmi b/icons/mob/human_races/cyberlimbs/morpheus/morpheus_main.dmi new file mode 100644 index 00000000..5c466d63 Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/morpheus/morpheus_main.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/nanotrasen/nanotrasen_main.dmi b/icons/mob/human_races/cyberlimbs/nanotrasen/nanotrasen_main.dmi new file mode 100644 index 00000000..66a871d1 Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/nanotrasen/nanotrasen_main.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/veymed/veymed_main.dmi b/icons/mob/human_races/cyberlimbs/veymed/veymed_main.dmi new file mode 100644 index 00000000..07446b59 Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/veymed/veymed_main.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_alt.dmi b/icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_alt.dmi new file mode 100644 index 00000000..10ea9c95 Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_alt.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_main.dmi b/icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_main.dmi new file mode 100644 index 00000000..eda9969a Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_main.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_monitor.dmi b/icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_monitor.dmi new file mode 100644 index 00000000..2777d06f Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_monitor.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/warfare/warfare_main.dmi b/icons/mob/human_races/cyberlimbs/warfare/warfare_main.dmi new file mode 100644 index 00000000..21ba45d5 Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/warfare/warfare_main.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/xion/xion_alt.dmi b/icons/mob/human_races/cyberlimbs/xion/xion_alt.dmi new file mode 100644 index 00000000..84a7fec2 Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/xion/xion_alt.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/xion/xion_main.dmi b/icons/mob/human_races/cyberlimbs/xion/xion_main.dmi new file mode 100644 index 00000000..e07e66e3 Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/xion/xion_main.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/xion/xion_monitor.dmi b/icons/mob/human_races/cyberlimbs/xion/xion_monitor.dmi new file mode 100644 index 00000000..0a049fc7 Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/xion/xion_monitor.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/zenghu/zenghu_main.dmi b/icons/mob/human_races/cyberlimbs/zenghu/zenghu_main.dmi new file mode 100644 index 00000000..8694f1b1 Binary files /dev/null and b/icons/mob/human_races/cyberlimbs/zenghu/zenghu_main.dmi differ diff --git a/icons/mob/human_races/markings.dmi b/icons/mob/human_races/markings.dmi new file mode 100644 index 00000000..e895945f Binary files /dev/null and b/icons/mob/human_races/markings.dmi differ diff --git a/icons/mob/human_races/masks/blood_child.dmi b/icons/mob/human_races/masks/blood_child.dmi new file mode 100644 index 00000000..4e065c37 Binary files /dev/null and b/icons/mob/human_races/masks/blood_child.dmi differ diff --git a/icons/mob/human_races/masks/blood_human.dmi b/icons/mob/human_races/masks/blood_human.dmi new file mode 100644 index 00000000..dc54991c Binary files /dev/null and b/icons/mob/human_races/masks/blood_human.dmi differ diff --git a/icons/mob/human_races/masks/blood_monkey.dmi b/icons/mob/human_races/masks/blood_monkey.dmi new file mode 100644 index 00000000..5d5dd66d Binary files /dev/null and b/icons/mob/human_races/masks/blood_monkey.dmi differ diff --git a/icons/mob/human_races/masks/dam_human.dmi b/icons/mob/human_races/masks/dam_human.dmi new file mode 100644 index 00000000..cb6bf82d Binary files /dev/null and b/icons/mob/human_races/masks/dam_human.dmi differ diff --git a/icons/mob/human_races/masks/dam_mask_child.dmi b/icons/mob/human_races/masks/dam_mask_child.dmi new file mode 100644 index 00000000..65904107 Binary files /dev/null and b/icons/mob/human_races/masks/dam_mask_child.dmi differ diff --git a/icons/mob/human_races/masks/dam_mask_human.dmi b/icons/mob/human_races/masks/dam_mask_human.dmi new file mode 100644 index 00000000..db55b5a6 Binary files /dev/null and b/icons/mob/human_races/masks/dam_mask_human.dmi differ diff --git a/icons/mob/human_races/masks/dam_mask_monkey.dmi b/icons/mob/human_races/masks/dam_mask_monkey.dmi new file mode 100644 index 00000000..4761f21f Binary files /dev/null and b/icons/mob/human_races/masks/dam_mask_monkey.dmi differ diff --git a/icons/mob/human_races/masks/dam_monkey.dmi b/icons/mob/human_races/masks/dam_monkey.dmi new file mode 100644 index 00000000..43d1f2c7 Binary files /dev/null and b/icons/mob/human_races/masks/dam_monkey.dmi differ diff --git a/icons/mob/human_races/masks/dam_template.dmi b/icons/mob/human_races/masks/dam_template.dmi new file mode 100644 index 00000000..31986efb Binary files /dev/null and b/icons/mob/human_races/masks/dam_template.dmi differ diff --git a/icons/mob/human_races/monkeys/r_monkey.dmi b/icons/mob/human_races/monkeys/r_monkey.dmi new file mode 100644 index 00000000..ed612158 Binary files /dev/null and b/icons/mob/human_races/monkeys/r_monkey.dmi differ diff --git a/icons/mob/human_races/r_def_human.dmi b/icons/mob/human_races/r_def_human.dmi new file mode 100644 index 00000000..e622ef14 Binary files /dev/null and b/icons/mob/human_races/r_def_human.dmi differ diff --git a/icons/mob/human_races/r_human.dmi b/icons/mob/human_races/r_human.dmi new file mode 100644 index 00000000..179e4731 Binary files /dev/null and b/icons/mob/human_races/r_human.dmi differ diff --git a/icons/mob/human_races/r_skeleton.dmi b/icons/mob/human_races/r_skeleton.dmi new file mode 100644 index 00000000..4bf2e4bc Binary files /dev/null and b/icons/mob/human_races/r_skeleton.dmi differ diff --git a/icons/mob/human_races/r_tajaran.dmi b/icons/mob/human_races/r_tajaran.dmi new file mode 100644 index 00000000..c06160c9 Binary files /dev/null and b/icons/mob/human_races/r_tajaran.dmi differ diff --git a/icons/mob/human_races/r_template.dmi b/icons/mob/human_races/r_template.dmi new file mode 100644 index 00000000..15454971 Binary files /dev/null and b/icons/mob/human_races/r_template.dmi differ diff --git a/icons/mob/human_races/r_template_tall.dmi b/icons/mob/human_races/r_template_tall.dmi new file mode 100644 index 00000000..e9862bab Binary files /dev/null and b/icons/mob/human_races/r_template_tall.dmi differ diff --git a/icons/mob/human_races/subhuman.dmi b/icons/mob/human_races/subhuman.dmi new file mode 100644 index 00000000..66782f9b Binary files /dev/null and b/icons/mob/human_races/subhuman.dmi differ diff --git a/icons/mob/human_races/tatt1.dmi b/icons/mob/human_races/tatt1.dmi new file mode 100644 index 00000000..264cd636 Binary files /dev/null and b/icons/mob/human_races/tatt1.dmi differ diff --git a/icons/mob/human_races/xenos/r_xenos_drone.dmi b/icons/mob/human_races/xenos/r_xenos_drone.dmi new file mode 100644 index 00000000..a85d55da Binary files /dev/null and b/icons/mob/human_races/xenos/r_xenos_drone.dmi differ diff --git a/icons/mob/human_races/xenos/r_xenos_hunter.dmi b/icons/mob/human_races/xenos/r_xenos_hunter.dmi new file mode 100644 index 00000000..642934e5 Binary files /dev/null and b/icons/mob/human_races/xenos/r_xenos_hunter.dmi differ diff --git a/icons/mob/human_races/xenos/r_xenos_queen.dmi b/icons/mob/human_races/xenos/r_xenos_queen.dmi new file mode 100644 index 00000000..388fdb98 Binary files /dev/null and b/icons/mob/human_races/xenos/r_xenos_queen.dmi differ diff --git a/icons/mob/human_races/xenos/r_xenos_sentinel.dmi b/icons/mob/human_races/xenos/r_xenos_sentinel.dmi new file mode 100644 index 00000000..e9944134 Binary files /dev/null and b/icons/mob/human_races/xenos/r_xenos_sentinel.dmi differ diff --git a/icons/mob/light_overlays.dmi b/icons/mob/light_overlays.dmi new file mode 100644 index 00000000..e45bafb8 Binary files /dev/null and b/icons/mob/light_overlays.dmi differ diff --git a/icons/mob/limb_mask.dmi b/icons/mob/limb_mask.dmi new file mode 100644 index 00000000..ba4d0e34 Binary files /dev/null and b/icons/mob/limb_mask.dmi differ diff --git a/icons/mob/livestock.dmi b/icons/mob/livestock.dmi new file mode 100644 index 00000000..538e14b1 Binary files /dev/null and b/icons/mob/livestock.dmi differ diff --git a/icons/mob/mecha.dmi b/icons/mob/mecha.dmi new file mode 100644 index 00000000..a6d3b137 Binary files /dev/null and b/icons/mob/mecha.dmi differ diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi new file mode 100644 index 00000000..40cd2f87 Binary files /dev/null and b/icons/mob/mob.dmi differ diff --git a/icons/mob/monitor_icons.dmi b/icons/mob/monitor_icons.dmi new file mode 100644 index 00000000..1fba4117 Binary files /dev/null and b/icons/mob/monitor_icons.dmi differ diff --git a/icons/mob/noise.dmi b/icons/mob/noise.dmi new file mode 100644 index 00000000..e9580157 Binary files /dev/null and b/icons/mob/noise.dmi differ diff --git a/icons/mob/onmob/back.dmi b/icons/mob/onmob/back.dmi new file mode 100644 index 00000000..d0b95b0e Binary files /dev/null and b/icons/mob/onmob/back.dmi differ diff --git a/icons/mob/onmob/belt.dmi b/icons/mob/onmob/belt.dmi new file mode 100644 index 00000000..450d18d5 Binary files /dev/null and b/icons/mob/onmob/belt.dmi differ diff --git a/icons/mob/onmob/belt_mirror.dmi b/icons/mob/onmob/belt_mirror.dmi new file mode 100644 index 00000000..d4ab4b81 Binary files /dev/null and b/icons/mob/onmob/belt_mirror.dmi differ diff --git a/icons/mob/onmob/ears.dmi b/icons/mob/onmob/ears.dmi new file mode 100644 index 00000000..41d95bff Binary files /dev/null and b/icons/mob/onmob/ears.dmi differ diff --git a/icons/mob/onmob/eyes.dmi b/icons/mob/onmob/eyes.dmi new file mode 100644 index 00000000..fbbdfc96 Binary files /dev/null and b/icons/mob/onmob/eyes.dmi differ diff --git a/icons/mob/onmob/feet.dmi b/icons/mob/onmob/feet.dmi new file mode 100644 index 00000000..04d69761 Binary files /dev/null and b/icons/mob/onmob/feet.dmi differ diff --git a/icons/mob/onmob/hands.dmi b/icons/mob/onmob/hands.dmi new file mode 100644 index 00000000..43968284 Binary files /dev/null and b/icons/mob/onmob/hands.dmi differ diff --git a/icons/mob/onmob/head.dmi b/icons/mob/onmob/head.dmi new file mode 100644 index 00000000..5e28266b Binary files /dev/null and b/icons/mob/onmob/head.dmi differ diff --git a/icons/mob/onmob/id.dmi b/icons/mob/onmob/id.dmi new file mode 100644 index 00000000..f1679b86 Binary files /dev/null and b/icons/mob/onmob/id.dmi differ diff --git a/icons/mob/onmob/items/lefthand.dmi b/icons/mob/onmob/items/lefthand.dmi new file mode 100644 index 00000000..96168aa5 Binary files /dev/null and b/icons/mob/onmob/items/lefthand.dmi differ diff --git a/icons/mob/onmob/items/lefthand_backpacks.dmi b/icons/mob/onmob/items/lefthand_backpacks.dmi new file mode 100644 index 00000000..59abedaf Binary files /dev/null and b/icons/mob/onmob/items/lefthand_backpacks.dmi differ diff --git a/icons/mob/onmob/items/lefthand_guns.dmi b/icons/mob/onmob/items/lefthand_guns.dmi new file mode 100644 index 00000000..d2c41b9e Binary files /dev/null and b/icons/mob/onmob/items/lefthand_guns.dmi differ diff --git a/icons/mob/onmob/items/lefthand_hats.dmi b/icons/mob/onmob/items/lefthand_hats.dmi new file mode 100644 index 00000000..828248fe Binary files /dev/null and b/icons/mob/onmob/items/lefthand_hats.dmi differ diff --git a/icons/mob/onmob/items/lefthand_holder.dmi b/icons/mob/onmob/items/lefthand_holder.dmi new file mode 100644 index 00000000..500a8d90 Binary files /dev/null and b/icons/mob/onmob/items/lefthand_holder.dmi differ diff --git a/icons/mob/onmob/items/lefthand_spacesuits.dmi b/icons/mob/onmob/items/lefthand_spacesuits.dmi new file mode 100644 index 00000000..b952407b Binary files /dev/null and b/icons/mob/onmob/items/lefthand_spacesuits.dmi differ diff --git a/icons/mob/onmob/items/lefthand_uniforms.dmi b/icons/mob/onmob/items/lefthand_uniforms.dmi new file mode 100644 index 00000000..a05b74e8 Binary files /dev/null and b/icons/mob/onmob/items/lefthand_uniforms.dmi differ diff --git a/icons/mob/onmob/items/righthand.dmi b/icons/mob/onmob/items/righthand.dmi new file mode 100644 index 00000000..2f5de814 Binary files /dev/null and b/icons/mob/onmob/items/righthand.dmi differ diff --git a/icons/mob/onmob/items/righthand_backpacks.dmi b/icons/mob/onmob/items/righthand_backpacks.dmi new file mode 100644 index 00000000..6366485f Binary files /dev/null and b/icons/mob/onmob/items/righthand_backpacks.dmi differ diff --git a/icons/mob/onmob/items/righthand_guns.dmi b/icons/mob/onmob/items/righthand_guns.dmi new file mode 100644 index 00000000..0ee007c8 Binary files /dev/null and b/icons/mob/onmob/items/righthand_guns.dmi differ diff --git a/icons/mob/onmob/items/righthand_hats.dmi b/icons/mob/onmob/items/righthand_hats.dmi new file mode 100644 index 00000000..c808a1c7 Binary files /dev/null and b/icons/mob/onmob/items/righthand_hats.dmi differ diff --git a/icons/mob/onmob/items/righthand_holder.dmi b/icons/mob/onmob/items/righthand_holder.dmi new file mode 100644 index 00000000..ed494afc Binary files /dev/null and b/icons/mob/onmob/items/righthand_holder.dmi differ diff --git a/icons/mob/onmob/items/righthand_spacesuits.dmi b/icons/mob/onmob/items/righthand_spacesuits.dmi new file mode 100644 index 00000000..6507deee Binary files /dev/null and b/icons/mob/onmob/items/righthand_spacesuits.dmi differ diff --git a/icons/mob/onmob/items/righthand_uniforms.dmi b/icons/mob/onmob/items/righthand_uniforms.dmi new file mode 100644 index 00000000..50f5ec8b Binary files /dev/null and b/icons/mob/onmob/items/righthand_uniforms.dmi differ diff --git a/icons/mob/onmob/mask.dmi b/icons/mob/onmob/mask.dmi new file mode 100644 index 00000000..06cbe05c Binary files /dev/null and b/icons/mob/onmob/mask.dmi differ diff --git a/icons/mob/onmob/misc.dmi b/icons/mob/onmob/misc.dmi new file mode 100644 index 00000000..e846904e Binary files /dev/null and b/icons/mob/onmob/misc.dmi differ diff --git a/icons/mob/onmob/modular_armor.dmi b/icons/mob/onmob/modular_armor.dmi new file mode 100644 index 00000000..e704cf27 Binary files /dev/null and b/icons/mob/onmob/modular_armor.dmi differ diff --git a/icons/mob/onmob/nanotrasen.dmi b/icons/mob/onmob/nanotrasen.dmi new file mode 100644 index 00000000..3ff306b2 Binary files /dev/null and b/icons/mob/onmob/nanotrasen.dmi differ diff --git a/icons/mob/onmob/pants.dmi b/icons/mob/onmob/pants.dmi new file mode 100644 index 00000000..eb449c18 Binary files /dev/null and b/icons/mob/onmob/pants.dmi differ diff --git a/icons/mob/onmob/suit.dmi b/icons/mob/onmob/suit.dmi new file mode 100644 index 00000000..56f9f60f Binary files /dev/null and b/icons/mob/onmob/suit.dmi differ diff --git a/icons/mob/onmob/ties.dmi b/icons/mob/onmob/ties.dmi new file mode 100644 index 00000000..3397e0a9 Binary files /dev/null and b/icons/mob/onmob/ties.dmi differ diff --git a/icons/mob/onmob/uniform.dmi b/icons/mob/onmob/uniform.dmi new file mode 100644 index 00000000..f7252fdf Binary files /dev/null and b/icons/mob/onmob/uniform.dmi differ diff --git a/icons/mob/pai.dmi b/icons/mob/pai.dmi new file mode 100644 index 00000000..8f6462ac Binary files /dev/null and b/icons/mob/pai.dmi differ diff --git a/icons/mob/puppet.dmi b/icons/mob/puppet.dmi new file mode 100644 index 00000000..40daee1f Binary files /dev/null and b/icons/mob/puppet.dmi differ diff --git a/icons/mob/puppet_new.dmi b/icons/mob/puppet_new.dmi new file mode 100644 index 00000000..9f5cbe92 Binary files /dev/null and b/icons/mob/puppet_new.dmi differ diff --git a/icons/mob/roaper.dmi b/icons/mob/roaper.dmi new file mode 100644 index 00000000..272251ec Binary files /dev/null and b/icons/mob/roaper.dmi differ diff --git a/icons/mob/robots.dmi b/icons/mob/robots.dmi new file mode 100644 index 00000000..bdbbae7b Binary files /dev/null and b/icons/mob/robots.dmi differ diff --git a/icons/mob/robots_misc.dmi b/icons/mob/robots_misc.dmi new file mode 100644 index 00000000..a16ff460 Binary files /dev/null and b/icons/mob/robots_misc.dmi differ diff --git a/icons/mob/screen/combat_intents.dmi b/icons/mob/screen/combat_intents.dmi new file mode 100644 index 00000000..2384a55e Binary files /dev/null and b/icons/mob/screen/combat_intents.dmi differ diff --git a/icons/mob/screen/cstyle.dmi b/icons/mob/screen/cstyle.dmi new file mode 100644 index 00000000..2f2d7e22 Binary files /dev/null and b/icons/mob/screen/cstyle.dmi differ diff --git a/icons/mob/screen/dark.dmi b/icons/mob/screen/dark.dmi new file mode 100644 index 00000000..341792e9 Binary files /dev/null and b/icons/mob/screen/dark.dmi differ diff --git a/icons/mob/screen/midnight.dmi b/icons/mob/screen/midnight.dmi new file mode 100644 index 00000000..37001e19 Binary files /dev/null and b/icons/mob/screen/midnight.dmi differ diff --git a/icons/mob/screen/minimalist.dmi b/icons/mob/screen/minimalist.dmi new file mode 100644 index 00000000..362c4c30 Binary files /dev/null and b/icons/mob/screen/minimalist.dmi differ diff --git a/icons/mob/screen/old-noborder.dmi b/icons/mob/screen/old-noborder.dmi new file mode 100644 index 00000000..8d862bf2 Binary files /dev/null and b/icons/mob/screen/old-noborder.dmi differ diff --git a/icons/mob/screen/old.dmi b/icons/mob/screen/old.dmi new file mode 100644 index 00000000..45d25838 Binary files /dev/null and b/icons/mob/screen/old.dmi differ diff --git a/icons/mob/screen/orange.dmi b/icons/mob/screen/orange.dmi new file mode 100644 index 00000000..3077e1cc Binary files /dev/null and b/icons/mob/screen/orange.dmi differ diff --git a/icons/mob/screen/orange_luna.dmi b/icons/mob/screen/orange_luna.dmi new file mode 100644 index 00000000..7289d9c6 Binary files /dev/null and b/icons/mob/screen/orange_luna.dmi differ diff --git a/icons/mob/screen/screen_neo.dmi b/icons/mob/screen/screen_neo.dmi new file mode 100644 index 00000000..543870e6 Binary files /dev/null and b/icons/mob/screen/screen_neo.dmi differ diff --git a/icons/mob/screen/white.dmi b/icons/mob/screen/white.dmi new file mode 100644 index 00000000..30356948 Binary files /dev/null and b/icons/mob/screen/white.dmi differ diff --git a/icons/mob/screen/white_luna2.dmi b/icons/mob/screen/white_luna2.dmi new file mode 100644 index 00000000..1d4a29c0 Binary files /dev/null and b/icons/mob/screen/white_luna2.dmi differ diff --git a/icons/mob/screen1.dmi b/icons/mob/screen1.dmi new file mode 100644 index 00000000..a3089956 Binary files /dev/null and b/icons/mob/screen1.dmi differ diff --git a/icons/mob/screen1_Midnight.dmi b/icons/mob/screen1_Midnight.dmi new file mode 100644 index 00000000..d43dcfe8 Binary files /dev/null and b/icons/mob/screen1_Midnight.dmi differ diff --git a/icons/mob/screen1_Orange.dmi b/icons/mob/screen1_Orange.dmi new file mode 100644 index 00000000..9dcaa5a7 Binary files /dev/null and b/icons/mob/screen1_Orange.dmi differ diff --git a/icons/mob/screen1_White.dmi b/icons/mob/screen1_White.dmi new file mode 100644 index 00000000..59249463 Binary files /dev/null and b/icons/mob/screen1_White.dmi differ diff --git a/icons/mob/screen1_action.dmi b/icons/mob/screen1_action.dmi new file mode 100644 index 00000000..ac323291 Binary files /dev/null and b/icons/mob/screen1_action.dmi differ diff --git a/icons/mob/screen1_alien.dmi b/icons/mob/screen1_alien.dmi new file mode 100644 index 00000000..d43ca5c7 Binary files /dev/null and b/icons/mob/screen1_alien.dmi differ diff --git a/icons/mob/screen1_construct.dmi b/icons/mob/screen1_construct.dmi new file mode 100644 index 00000000..67a37ccd Binary files /dev/null and b/icons/mob/screen1_construct.dmi differ diff --git a/icons/mob/screen1_health.dmi b/icons/mob/screen1_health.dmi new file mode 100644 index 00000000..9cd7a413 Binary files /dev/null and b/icons/mob/screen1_health.dmi differ diff --git a/icons/mob/screen1_old.dmi b/icons/mob/screen1_old.dmi new file mode 100644 index 00000000..a7340569 Binary files /dev/null and b/icons/mob/screen1_old.dmi differ diff --git a/icons/mob/screen1_robot.dmi b/icons/mob/screen1_robot.dmi new file mode 100644 index 00000000..fad17e0e Binary files /dev/null and b/icons/mob/screen1_robot.dmi differ diff --git a/icons/mob/screen1_stats.dmi b/icons/mob/screen1_stats.dmi new file mode 100644 index 00000000..381f6a36 Binary files /dev/null and b/icons/mob/screen1_stats.dmi differ diff --git a/icons/mob/screen_full.dmi b/icons/mob/screen_full.dmi new file mode 100644 index 00000000..2a91aae3 Binary files /dev/null and b/icons/mob/screen_full.dmi differ diff --git a/icons/mob/screen_gen.dmi b/icons/mob/screen_gen.dmi new file mode 100644 index 00000000..436fb116 Binary files /dev/null and b/icons/mob/screen_gen.dmi differ diff --git a/icons/mob/screen_phenomena.dmi b/icons/mob/screen_phenomena.dmi new file mode 100644 index 00000000..f1d05fa9 Binary files /dev/null and b/icons/mob/screen_phenomena.dmi differ diff --git a/icons/mob/screen_spells.dmi b/icons/mob/screen_spells.dmi new file mode 100644 index 00000000..9eb82ca0 Binary files /dev/null and b/icons/mob/screen_spells.dmi differ diff --git a/icons/mob/slimes.dmi b/icons/mob/slimes.dmi new file mode 100644 index 00000000..3e6b915e Binary files /dev/null and b/icons/mob/slimes.dmi differ diff --git a/icons/mob/spaceshark.dmi b/icons/mob/spaceshark.dmi new file mode 100644 index 00000000..615fd87a Binary files /dev/null and b/icons/mob/spaceshark.dmi differ diff --git a/icons/mob/species/monkey/ties.dmi b/icons/mob/species/monkey/ties.dmi new file mode 100644 index 00000000..6055ae9c Binary files /dev/null and b/icons/mob/species/monkey/ties.dmi differ diff --git a/icons/mob/species/monkey/uniform.dmi b/icons/mob/species/monkey/uniform.dmi new file mode 100644 index 00000000..f714af37 Binary files /dev/null and b/icons/mob/species/monkey/uniform.dmi differ diff --git a/icons/mob/surgery.dmi b/icons/mob/surgery.dmi new file mode 100644 index 00000000..4fb52dfb Binary files /dev/null and b/icons/mob/surgery.dmi differ diff --git a/icons/mob/talk.dmi b/icons/mob/talk.dmi new file mode 100644 index 00000000..13113b9e Binary files /dev/null and b/icons/mob/talk.dmi differ diff --git a/icons/mob/uniform_fat.dmi b/icons/mob/uniform_fat.dmi new file mode 100644 index 00000000..c887239f Binary files /dev/null and b/icons/mob/uniform_fat.dmi differ diff --git a/icons/mob/unused.dmi b/icons/mob/unused.dmi new file mode 100644 index 00000000..548d475b Binary files /dev/null and b/icons/mob/unused.dmi differ diff --git a/icons/mob/virtual.dmi b/icons/mob/virtual.dmi new file mode 100644 index 00000000..13813bb5 Binary files /dev/null and b/icons/mob/virtual.dmi differ diff --git a/icons/mob/zombie.dmi b/icons/mob/zombie.dmi new file mode 100644 index 00000000..a07fe79c Binary files /dev/null and b/icons/mob/zombie.dmi differ diff --git a/icons/mob/zone_sel.dmi b/icons/mob/zone_sel.dmi new file mode 100644 index 00000000..516874f2 Binary files /dev/null and b/icons/mob/zone_sel.dmi differ diff --git a/icons/mob/zone_sel_new.dmi b/icons/mob/zone_sel_new.dmi new file mode 100644 index 00000000..ee65e7b4 Binary files /dev/null and b/icons/mob/zone_sel_new.dmi differ diff --git a/icons/mob/zone_sel_newer.dmi b/icons/mob/zone_sel_newer.dmi new file mode 100644 index 00000000..21a222c8 Binary files /dev/null and b/icons/mob/zone_sel_newer.dmi differ diff --git a/icons/mound.png b/icons/mound.png new file mode 100644 index 00000000..b9b25ecd Binary files /dev/null and b/icons/mound.png differ diff --git a/icons/obj/64x64.dmi b/icons/obj/64x64.dmi new file mode 100644 index 00000000..c8177a06 Binary files /dev/null and b/icons/obj/64x64.dmi differ diff --git a/icons/obj/Boombox.dmi b/icons/obj/Boombox.dmi new file mode 100644 index 00000000..f074089b Binary files /dev/null and b/icons/obj/Boombox.dmi differ diff --git a/icons/obj/Cryogenic2.dmi b/icons/obj/Cryogenic2.dmi new file mode 100644 index 00000000..c1cacacc Binary files /dev/null and b/icons/obj/Cryogenic2.dmi differ diff --git a/icons/obj/aibots.dmi b/icons/obj/aibots.dmi new file mode 100644 index 00000000..3d4d3eb5 Binary files /dev/null and b/icons/obj/aibots.dmi differ diff --git a/icons/obj/airlock_machines.dmi b/icons/obj/airlock_machines.dmi new file mode 100644 index 00000000..654a604f Binary files /dev/null and b/icons/obj/airlock_machines.dmi differ diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi new file mode 100644 index 00000000..2730e883 Binary files /dev/null and b/icons/obj/ammo.dmi differ diff --git a/icons/obj/apc_repair.dmi b/icons/obj/apc_repair.dmi new file mode 100644 index 00000000..60f2650a Binary files /dev/null and b/icons/obj/apc_repair.dmi differ diff --git a/icons/obj/apiary_bees_etc.dmi b/icons/obj/apiary_bees_etc.dmi new file mode 100644 index 00000000..130120bb Binary files /dev/null and b/icons/obj/apiary_bees_etc.dmi differ diff --git a/icons/obj/artifacts.dmi b/icons/obj/artifacts.dmi new file mode 100644 index 00000000..0a8aa78f Binary files /dev/null and b/icons/obj/artifacts.dmi differ diff --git a/icons/obj/assemblies.dmi b/icons/obj/assemblies.dmi new file mode 100644 index 00000000..b03a1455 Binary files /dev/null and b/icons/obj/assemblies.dmi differ diff --git a/icons/obj/assemblies/new_assemblies.dmi b/icons/obj/assemblies/new_assemblies.dmi new file mode 100644 index 00000000..96b36bbf Binary files /dev/null and b/icons/obj/assemblies/new_assemblies.dmi differ diff --git a/icons/obj/atmos.dmi b/icons/obj/atmos.dmi new file mode 100644 index 00000000..51a08332 Binary files /dev/null and b/icons/obj/atmos.dmi differ diff --git a/icons/obj/atmospherics/blue_pipe_tank.dmi b/icons/obj/atmospherics/blue_pipe_tank.dmi new file mode 100644 index 00000000..b1af4fc3 Binary files /dev/null and b/icons/obj/atmospherics/blue_pipe_tank.dmi differ diff --git a/icons/obj/atmospherics/cold_sink.dmi b/icons/obj/atmospherics/cold_sink.dmi new file mode 100644 index 00000000..09f9be43 Binary files /dev/null and b/icons/obj/atmospherics/cold_sink.dmi differ diff --git a/icons/obj/atmospherics/digital_valve.dmi b/icons/obj/atmospherics/digital_valve.dmi new file mode 100644 index 00000000..0b3dffd0 Binary files /dev/null and b/icons/obj/atmospherics/digital_valve.dmi differ diff --git a/icons/obj/atmospherics/dp_vent_pump.dmi b/icons/obj/atmospherics/dp_vent_pump.dmi new file mode 100644 index 00000000..be5106c2 Binary files /dev/null and b/icons/obj/atmospherics/dp_vent_pump.dmi differ diff --git a/icons/obj/atmospherics/filter.dmi b/icons/obj/atmospherics/filter.dmi new file mode 100644 index 00000000..3bb85fdb Binary files /dev/null and b/icons/obj/atmospherics/filter.dmi differ diff --git a/icons/obj/atmospherics/heat_exchanger.dmi b/icons/obj/atmospherics/heat_exchanger.dmi new file mode 100644 index 00000000..31836c5e Binary files /dev/null and b/icons/obj/atmospherics/heat_exchanger.dmi differ diff --git a/icons/obj/atmospherics/m_filter.dmi b/icons/obj/atmospherics/m_filter.dmi new file mode 100644 index 00000000..70261633 Binary files /dev/null and b/icons/obj/atmospherics/m_filter.dmi differ diff --git a/icons/obj/atmospherics/m_mixer.dmi b/icons/obj/atmospherics/m_mixer.dmi new file mode 100644 index 00000000..81c6bbb5 Binary files /dev/null and b/icons/obj/atmospherics/m_mixer.dmi differ diff --git a/icons/obj/atmospherics/mainspipe.dmi b/icons/obj/atmospherics/mainspipe.dmi new file mode 100644 index 00000000..4518a5b0 Binary files /dev/null and b/icons/obj/atmospherics/mainspipe.dmi differ diff --git a/icons/obj/atmospherics/mixer.dmi b/icons/obj/atmospherics/mixer.dmi new file mode 100644 index 00000000..79b62c87 Binary files /dev/null and b/icons/obj/atmospherics/mixer.dmi differ diff --git a/icons/obj/atmospherics/n2o_pipe_tank.dmi b/icons/obj/atmospherics/n2o_pipe_tank.dmi new file mode 100644 index 00000000..82819446 Binary files /dev/null and b/icons/obj/atmospherics/n2o_pipe_tank.dmi differ diff --git a/icons/obj/atmospherics/omni_devices.dmi b/icons/obj/atmospherics/omni_devices.dmi new file mode 100644 index 00000000..398fd5f1 Binary files /dev/null and b/icons/obj/atmospherics/omni_devices.dmi differ diff --git a/icons/obj/atmospherics/orange_pipe_tank.dmi b/icons/obj/atmospherics/orange_pipe_tank.dmi new file mode 100644 index 00000000..4b70b7e0 Binary files /dev/null and b/icons/obj/atmospherics/orange_pipe_tank.dmi differ diff --git a/icons/obj/atmospherics/outlet_injector.dmi b/icons/obj/atmospherics/outlet_injector.dmi new file mode 100644 index 00000000..60ecc2e9 Binary files /dev/null and b/icons/obj/atmospherics/outlet_injector.dmi differ diff --git a/icons/obj/atmospherics/oxygen_generator.dmi b/icons/obj/atmospherics/oxygen_generator.dmi new file mode 100644 index 00000000..0c94506c Binary files /dev/null and b/icons/obj/atmospherics/oxygen_generator.dmi differ diff --git a/icons/obj/atmospherics/passive_gate.dmi b/icons/obj/atmospherics/passive_gate.dmi new file mode 100644 index 00000000..be8be8b7 Binary files /dev/null and b/icons/obj/atmospherics/passive_gate.dmi differ diff --git a/icons/obj/atmospherics/pipe_manifold.dmi b/icons/obj/atmospherics/pipe_manifold.dmi new file mode 100644 index 00000000..0687e9e8 Binary files /dev/null and b/icons/obj/atmospherics/pipe_manifold.dmi differ diff --git a/icons/obj/atmospherics/pipe_tank.dmi b/icons/obj/atmospherics/pipe_tank.dmi new file mode 100644 index 00000000..e6925d0e Binary files /dev/null and b/icons/obj/atmospherics/pipe_tank.dmi differ diff --git a/icons/obj/atmospherics/pipe_vent.dmi b/icons/obj/atmospherics/pipe_vent.dmi new file mode 100644 index 00000000..6086af93 Binary files /dev/null and b/icons/obj/atmospherics/pipe_vent.dmi differ diff --git a/icons/obj/atmospherics/portables_connector.dmi b/icons/obj/atmospherics/portables_connector.dmi new file mode 100644 index 00000000..0268014c Binary files /dev/null and b/icons/obj/atmospherics/portables_connector.dmi differ diff --git a/icons/obj/atmospherics/pump.dmi b/icons/obj/atmospherics/pump.dmi new file mode 100644 index 00000000..bd08c601 Binary files /dev/null and b/icons/obj/atmospherics/pump.dmi differ diff --git a/icons/obj/atmospherics/red_orange_pipe_tank.dmi b/icons/obj/atmospherics/red_orange_pipe_tank.dmi new file mode 100644 index 00000000..36c236a1 Binary files /dev/null and b/icons/obj/atmospherics/red_orange_pipe_tank.dmi differ diff --git a/icons/obj/atmospherics/red_pipe.dmi b/icons/obj/atmospherics/red_pipe.dmi new file mode 100644 index 00000000..ff9d9e8a Binary files /dev/null and b/icons/obj/atmospherics/red_pipe.dmi differ diff --git a/icons/obj/atmospherics/red_pipe_tank.dmi b/icons/obj/atmospherics/red_pipe_tank.dmi new file mode 100644 index 00000000..bcfdac49 Binary files /dev/null and b/icons/obj/atmospherics/red_pipe_tank.dmi differ diff --git a/icons/obj/atmospherics/relief_valve.dmi b/icons/obj/atmospherics/relief_valve.dmi new file mode 100644 index 00000000..313081da Binary files /dev/null and b/icons/obj/atmospherics/relief_valve.dmi differ diff --git a/icons/obj/atmospherics/t_mixer.dmi b/icons/obj/atmospherics/t_mixer.dmi new file mode 100644 index 00000000..1535a52e Binary files /dev/null and b/icons/obj/atmospherics/t_mixer.dmi differ diff --git a/icons/obj/atmospherics/valve.dmi b/icons/obj/atmospherics/valve.dmi new file mode 100644 index 00000000..beaff23c Binary files /dev/null and b/icons/obj/atmospherics/valve.dmi differ diff --git a/icons/obj/atmospherics/vent_pump.dmi b/icons/obj/atmospherics/vent_pump.dmi new file mode 100644 index 00000000..5616a9d7 Binary files /dev/null and b/icons/obj/atmospherics/vent_pump.dmi differ diff --git a/icons/obj/atmospherics/vent_scrubber.dmi b/icons/obj/atmospherics/vent_scrubber.dmi new file mode 100644 index 00000000..83536121 Binary files /dev/null and b/icons/obj/atmospherics/vent_scrubber.dmi differ diff --git a/icons/obj/atmospherics/volume_pump.dmi b/icons/obj/atmospherics/volume_pump.dmi new file mode 100644 index 00000000..fed0d479 Binary files /dev/null and b/icons/obj/atmospherics/volume_pump.dmi differ diff --git a/icons/obj/autopsy_scanner.dmi b/icons/obj/autopsy_scanner.dmi new file mode 100644 index 00000000..82c47de4 Binary files /dev/null and b/icons/obj/autopsy_scanner.dmi differ diff --git a/icons/obj/barsigns.dmi b/icons/obj/barsigns.dmi new file mode 100644 index 00000000..ac409de9 Binary files /dev/null and b/icons/obj/barsigns.dmi differ diff --git a/icons/obj/basketball.dmi b/icons/obj/basketball.dmi new file mode 100644 index 00000000..0461da64 Binary files /dev/null and b/icons/obj/basketball.dmi differ diff --git a/icons/obj/bike.dmi b/icons/obj/bike.dmi new file mode 100644 index 00000000..69aa0ccb Binary files /dev/null and b/icons/obj/bike.dmi differ diff --git a/icons/obj/biogenerator.dmi b/icons/obj/biogenerator.dmi new file mode 100644 index 00000000..c65a9571 Binary files /dev/null and b/icons/obj/biogenerator.dmi differ diff --git a/icons/obj/bloodpack.dmi b/icons/obj/bloodpack.dmi new file mode 100644 index 00000000..69c34848 Binary files /dev/null and b/icons/obj/bloodpack.dmi differ diff --git a/icons/obj/bodybag.dmi b/icons/obj/bodybag.dmi new file mode 100644 index 00000000..df481a5e Binary files /dev/null and b/icons/obj/bodybag.dmi differ diff --git a/icons/obj/buildingobject.dmi b/icons/obj/buildingobject.dmi new file mode 100644 index 00000000..76fa0e43 Binary files /dev/null and b/icons/obj/buildingobject.dmi differ diff --git a/icons/obj/bureaucracy.dmi b/icons/obj/bureaucracy.dmi new file mode 100644 index 00000000..271fec85 Binary files /dev/null and b/icons/obj/bureaucracy.dmi differ diff --git a/icons/obj/candle.dmi b/icons/obj/candle.dmi new file mode 100644 index 00000000..35257a44 Binary files /dev/null and b/icons/obj/candle.dmi differ diff --git a/icons/obj/card.dmi b/icons/obj/card.dmi new file mode 100644 index 00000000..36cf59ee Binary files /dev/null and b/icons/obj/card.dmi differ diff --git a/icons/obj/cassette.dmi b/icons/obj/cassette.dmi new file mode 100644 index 00000000..05aedd52 Binary files /dev/null and b/icons/obj/cassette.dmi differ diff --git a/icons/obj/catwalks.dmi b/icons/obj/catwalks.dmi new file mode 100644 index 00000000..9e3d3d97 Binary files /dev/null and b/icons/obj/catwalks.dmi differ diff --git a/icons/obj/cellrack.dmi b/icons/obj/cellrack.dmi new file mode 100644 index 00000000..0e52e3fd Binary files /dev/null and b/icons/obj/cellrack.dmi differ diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi new file mode 100644 index 00000000..a0f56660 Binary files /dev/null and b/icons/obj/chemical.dmi differ diff --git a/icons/obj/chempuff.dmi b/icons/obj/chempuff.dmi new file mode 100644 index 00000000..811c5e82 Binary files /dev/null and b/icons/obj/chempuff.dmi differ diff --git a/icons/obj/christmas.dmi b/icons/obj/christmas.dmi new file mode 100644 index 00000000..a42d14ec Binary files /dev/null and b/icons/obj/christmas.dmi differ diff --git a/icons/obj/cigarettes.dmi b/icons/obj/cigarettes.dmi new file mode 100644 index 00000000..43d6a859 Binary files /dev/null and b/icons/obj/cigarettes.dmi differ diff --git a/icons/obj/cloning.dmi b/icons/obj/cloning.dmi new file mode 100644 index 00000000..af0bb42e Binary files /dev/null and b/icons/obj/cloning.dmi differ diff --git a/icons/obj/closet.dmi b/icons/obj/closet.dmi new file mode 100644 index 00000000..a0fb87ca Binary files /dev/null and b/icons/obj/closet.dmi differ diff --git a/icons/obj/clothing/accessory_overlays.dmi b/icons/obj/clothing/accessory_overlays.dmi new file mode 100644 index 00000000..deb5abf4 Binary files /dev/null and b/icons/obj/clothing/accessory_overlays.dmi differ diff --git a/icons/obj/clothing/belts.dmi b/icons/obj/clothing/belts.dmi new file mode 100644 index 00000000..aed0051d Binary files /dev/null and b/icons/obj/clothing/belts.dmi differ diff --git a/icons/obj/clothing/ears.dmi b/icons/obj/clothing/ears.dmi new file mode 100644 index 00000000..b5bbff0a Binary files /dev/null and b/icons/obj/clothing/ears.dmi differ diff --git a/icons/obj/clothing/glasses.dmi b/icons/obj/clothing/glasses.dmi new file mode 100644 index 00000000..cd46ebbb Binary files /dev/null and b/icons/obj/clothing/glasses.dmi differ diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi new file mode 100644 index 00000000..e70e9571 Binary files /dev/null and b/icons/obj/clothing/gloves.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi new file mode 100644 index 00000000..a692d5e5 Binary files /dev/null and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi new file mode 100644 index 00000000..9baff30a Binary files /dev/null and b/icons/obj/clothing/masks.dmi differ diff --git a/icons/obj/clothing/modular_armor.dmi b/icons/obj/clothing/modular_armor.dmi new file mode 100644 index 00000000..10bffa08 Binary files /dev/null and b/icons/obj/clothing/modular_armor.dmi differ diff --git a/icons/obj/clothing/monitor.dmi b/icons/obj/clothing/monitor.dmi new file mode 100644 index 00000000..e73c924d Binary files /dev/null and b/icons/obj/clothing/monitor.dmi differ diff --git a/icons/obj/clothing/rings.dmi b/icons/obj/clothing/rings.dmi new file mode 100644 index 00000000..5274bf87 Binary files /dev/null and b/icons/obj/clothing/rings.dmi differ diff --git a/icons/obj/clothing/shoes.dmi b/icons/obj/clothing/shoes.dmi new file mode 100644 index 00000000..7e7c141d Binary files /dev/null and b/icons/obj/clothing/shoes.dmi differ diff --git a/icons/obj/clothing/species/bogani/hats.dmi b/icons/obj/clothing/species/bogani/hats.dmi new file mode 100644 index 00000000..714fda6e Binary files /dev/null and b/icons/obj/clothing/species/bogani/hats.dmi differ diff --git a/icons/obj/clothing/species/bogani/suits.dmi b/icons/obj/clothing/species/bogani/suits.dmi new file mode 100644 index 00000000..77cc751c Binary files /dev/null and b/icons/obj/clothing/species/bogani/suits.dmi differ diff --git a/icons/obj/clothing/species/bogani/uniform.dmi b/icons/obj/clothing/species/bogani/uniform.dmi new file mode 100644 index 00000000..a27c1065 Binary files /dev/null and b/icons/obj/clothing/species/bogani/uniform.dmi differ diff --git a/icons/obj/clothing/species/resomi/hats.dmi b/icons/obj/clothing/species/resomi/hats.dmi new file mode 100644 index 00000000..dbf944be Binary files /dev/null and b/icons/obj/clothing/species/resomi/hats.dmi differ diff --git a/icons/obj/clothing/species/resomi/suits.dmi b/icons/obj/clothing/species/resomi/suits.dmi new file mode 100644 index 00000000..a34dcc3a Binary files /dev/null and b/icons/obj/clothing/species/resomi/suits.dmi differ diff --git a/icons/obj/clothing/species/resomi/uniform.dmi b/icons/obj/clothing/species/resomi/uniform.dmi new file mode 100644 index 00000000..dd59ea8b Binary files /dev/null and b/icons/obj/clothing/species/resomi/uniform.dmi differ diff --git a/icons/obj/clothing/species/skrell/hats.dmi b/icons/obj/clothing/species/skrell/hats.dmi new file mode 100644 index 00000000..326fa8fc Binary files /dev/null and b/icons/obj/clothing/species/skrell/hats.dmi differ diff --git a/icons/obj/clothing/species/skrell/suits.dmi b/icons/obj/clothing/species/skrell/suits.dmi new file mode 100644 index 00000000..f0f4416f Binary files /dev/null and b/icons/obj/clothing/species/skrell/suits.dmi differ diff --git a/icons/obj/clothing/species/tajaran/hats.dmi b/icons/obj/clothing/species/tajaran/hats.dmi new file mode 100644 index 00000000..01b023f0 Binary files /dev/null and b/icons/obj/clothing/species/tajaran/hats.dmi differ diff --git a/icons/obj/clothing/species/tajaran/suits.dmi b/icons/obj/clothing/species/tajaran/suits.dmi new file mode 100644 index 00000000..e44881c2 Binary files /dev/null and b/icons/obj/clothing/species/tajaran/suits.dmi differ diff --git a/icons/obj/clothing/species/unathi/hats.dmi b/icons/obj/clothing/species/unathi/hats.dmi new file mode 100644 index 00000000..72815338 Binary files /dev/null and b/icons/obj/clothing/species/unathi/hats.dmi differ diff --git a/icons/obj/clothing/species/unathi/suits.dmi b/icons/obj/clothing/species/unathi/suits.dmi new file mode 100644 index 00000000..da6ed061 Binary files /dev/null and b/icons/obj/clothing/species/unathi/suits.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi new file mode 100644 index 00000000..2ba701e1 Binary files /dev/null and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/clothing/ties.dmi b/icons/obj/clothing/ties.dmi new file mode 100644 index 00000000..98bd7383 Binary files /dev/null and b/icons/obj/clothing/ties.dmi differ diff --git a/icons/obj/clothing/uniforms.dmi b/icons/obj/clothing/uniforms.dmi new file mode 100644 index 00000000..c17d157a Binary files /dev/null and b/icons/obj/clothing/uniforms.dmi differ diff --git a/icons/obj/clothing/unused.dmi b/icons/obj/clothing/unused.dmi new file mode 100644 index 00000000..f309bbd7 Binary files /dev/null and b/icons/obj/clothing/unused.dmi differ diff --git a/icons/obj/coatrack.dmi b/icons/obj/coatrack.dmi new file mode 100644 index 00000000..5d19abae Binary files /dev/null and b/icons/obj/coatrack.dmi differ diff --git a/icons/obj/coilgun.dmi b/icons/obj/coilgun.dmi new file mode 100644 index 00000000..238bbd9a Binary files /dev/null and b/icons/obj/coilgun.dmi differ diff --git a/icons/obj/computer.dmi b/icons/obj/computer.dmi new file mode 100644 index 00000000..c325e8be Binary files /dev/null and b/icons/obj/computer.dmi differ diff --git a/icons/obj/contraband.dmi b/icons/obj/contraband.dmi new file mode 100644 index 00000000..101b33e9 Binary files /dev/null and b/icons/obj/contraband.dmi differ diff --git a/icons/obj/cooking_machines.dmi b/icons/obj/cooking_machines.dmi new file mode 100644 index 00000000..666a31b9 Binary files /dev/null and b/icons/obj/cooking_machines.dmi differ diff --git a/icons/obj/crafting.dmi b/icons/obj/crafting.dmi new file mode 100644 index 00000000..c19fbae9 Binary files /dev/null and b/icons/obj/crafting.dmi differ diff --git a/icons/obj/crayons.dmi b/icons/obj/crayons.dmi new file mode 100644 index 00000000..7ebabd5a Binary files /dev/null and b/icons/obj/crayons.dmi differ diff --git a/icons/obj/cryobag.dmi b/icons/obj/cryobag.dmi new file mode 100644 index 00000000..e8cb81e1 Binary files /dev/null and b/icons/obj/cryobag.dmi differ diff --git a/icons/obj/cryogenics.dmi b/icons/obj/cryogenics.dmi new file mode 100644 index 00000000..ae468165 Binary files /dev/null and b/icons/obj/cryogenics.dmi differ diff --git a/icons/obj/cryogenics_split.dmi b/icons/obj/cryogenics_split.dmi new file mode 100644 index 00000000..a25513a1 Binary files /dev/null and b/icons/obj/cryogenics_split.dmi differ diff --git a/icons/obj/cryostart.dmi b/icons/obj/cryostart.dmi new file mode 100644 index 00000000..778b66fa Binary files /dev/null and b/icons/obj/cryostart.dmi differ diff --git a/icons/obj/cs.dmi b/icons/obj/cs.dmi new file mode 100644 index 00000000..22254a7e Binary files /dev/null and b/icons/obj/cs.dmi differ diff --git a/icons/obj/cult.dmi b/icons/obj/cult.dmi new file mode 100644 index 00000000..b07e21ae Binary files /dev/null and b/icons/obj/cult.dmi differ diff --git a/icons/obj/curtain.dmi b/icons/obj/curtain.dmi new file mode 100644 index 00000000..69b7de1d Binary files /dev/null and b/icons/obj/curtain.dmi differ diff --git a/icons/obj/custom_items_obj.dmi b/icons/obj/custom_items_obj.dmi new file mode 100644 index 00000000..e69de29b diff --git a/icons/obj/decal_warning_stripes.dmi b/icons/obj/decal_warning_stripes.dmi new file mode 100644 index 00000000..a0cf5e32 Binary files /dev/null and b/icons/obj/decal_warning_stripes.dmi differ diff --git a/icons/obj/decals.dmi b/icons/obj/decals.dmi new file mode 100644 index 00000000..ceb1c710 Binary files /dev/null and b/icons/obj/decals.dmi differ diff --git a/icons/obj/defibrillator.dmi b/icons/obj/defibrillator.dmi new file mode 100644 index 00000000..f399f37f Binary files /dev/null and b/icons/obj/defibrillator.dmi differ diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi new file mode 100644 index 00000000..43a45773 Binary files /dev/null and b/icons/obj/device.dmi differ diff --git a/icons/obj/dice.dmi b/icons/obj/dice.dmi new file mode 100644 index 00000000..f6a209b4 Binary files /dev/null and b/icons/obj/dice.dmi differ diff --git a/icons/obj/diona.dmi b/icons/obj/diona.dmi new file mode 100644 index 00000000..a1a96b5b Binary files /dev/null and b/icons/obj/diona.dmi differ diff --git a/icons/obj/doors/1x2blast_hor.dmi b/icons/obj/doors/1x2blast_hor.dmi new file mode 100644 index 00000000..a0a3d935 Binary files /dev/null and b/icons/obj/doors/1x2blast_hor.dmi differ diff --git a/icons/obj/doors/1x2blast_vert.dmi b/icons/obj/doors/1x2blast_vert.dmi new file mode 100644 index 00000000..6e810457 Binary files /dev/null and b/icons/obj/doors/1x2blast_vert.dmi differ diff --git a/icons/obj/doors/1x4blast_hor.dmi b/icons/obj/doors/1x4blast_hor.dmi new file mode 100644 index 00000000..d4329897 Binary files /dev/null and b/icons/obj/doors/1x4blast_hor.dmi differ diff --git a/icons/obj/doors/1x4blast_vert.dmi b/icons/obj/doors/1x4blast_vert.dmi new file mode 100644 index 00000000..26c730b9 Binary files /dev/null and b/icons/obj/doors/1x4blast_vert.dmi differ diff --git a/icons/obj/doors/Door1.dmi b/icons/obj/doors/Door1.dmi new file mode 100644 index 00000000..59ef7116 Binary files /dev/null and b/icons/obj/doors/Door1.dmi differ diff --git a/icons/obj/doors/Door2x1glass.dmi b/icons/obj/doors/Door2x1glass.dmi new file mode 100644 index 00000000..e015b10c Binary files /dev/null and b/icons/obj/doors/Door2x1glass.dmi differ diff --git a/icons/obj/doors/Door2x1maint.dmi b/icons/obj/doors/Door2x1maint.dmi new file mode 100644 index 00000000..1d07bbdc Binary files /dev/null and b/icons/obj/doors/Door2x1maint.dmi differ diff --git a/icons/obj/doors/DoorHazard.dmi b/icons/obj/doors/DoorHazard.dmi new file mode 100644 index 00000000..fdcbe456 Binary files /dev/null and b/icons/obj/doors/DoorHazard.dmi differ diff --git a/icons/obj/doors/DoorHazard2x1.dmi b/icons/obj/doors/DoorHazard2x1.dmi new file mode 100644 index 00000000..fd569d83 Binary files /dev/null and b/icons/obj/doors/DoorHazard2x1.dmi differ diff --git a/icons/obj/doors/Dooratmo.dmi b/icons/obj/doors/Dooratmo.dmi new file mode 100644 index 00000000..a65dba93 Binary files /dev/null and b/icons/obj/doors/Dooratmo.dmi differ diff --git a/icons/obj/doors/Dooratmoglass.dmi b/icons/obj/doors/Dooratmoglass.dmi new file mode 100644 index 00000000..810ec440 Binary files /dev/null and b/icons/obj/doors/Dooratmoglass.dmi differ diff --git a/icons/obj/doors/Doorbananium.dmi b/icons/obj/doors/Doorbananium.dmi new file mode 100644 index 00000000..be669393 Binary files /dev/null and b/icons/obj/doors/Doorbananium.dmi differ diff --git a/icons/obj/doors/Doorcom.dmi b/icons/obj/doors/Doorcom.dmi new file mode 100644 index 00000000..51f9e5d8 Binary files /dev/null and b/icons/obj/doors/Doorcom.dmi differ diff --git a/icons/obj/doors/Doorcomalt.dmi b/icons/obj/doors/Doorcomalt.dmi new file mode 100644 index 00000000..db9d66fd Binary files /dev/null and b/icons/obj/doors/Doorcomalt.dmi differ diff --git a/icons/obj/doors/Doorcomaltglass.dmi b/icons/obj/doors/Doorcomaltglass.dmi new file mode 100644 index 00000000..6f7a71f3 Binary files /dev/null and b/icons/obj/doors/Doorcomaltglass.dmi differ diff --git a/icons/obj/doors/Doorcomglass.dmi b/icons/obj/doors/Doorcomglass.dmi new file mode 100644 index 00000000..0fd86a16 Binary files /dev/null and b/icons/obj/doors/Doorcomglass.dmi differ diff --git a/icons/obj/doors/Doordiamond.dmi b/icons/obj/doors/Doordiamond.dmi new file mode 100644 index 00000000..9916c868 Binary files /dev/null and b/icons/obj/doors/Doordiamond.dmi differ diff --git a/icons/obj/doors/Doorele.dmi b/icons/obj/doors/Doorele.dmi new file mode 100644 index 00000000..a844ec7b Binary files /dev/null and b/icons/obj/doors/Doorele.dmi differ diff --git a/icons/obj/doors/Dooreng.dmi b/icons/obj/doors/Dooreng.dmi new file mode 100644 index 00000000..d0e64b3a Binary files /dev/null and b/icons/obj/doors/Dooreng.dmi differ diff --git a/icons/obj/doors/Doorengglass.dmi b/icons/obj/doors/Doorengglass.dmi new file mode 100644 index 00000000..951ace56 Binary files /dev/null and b/icons/obj/doors/Doorengglass.dmi differ diff --git a/icons/obj/doors/Doorext.dmi b/icons/obj/doors/Doorext.dmi new file mode 100644 index 00000000..35c1d4f4 Binary files /dev/null and b/icons/obj/doors/Doorext.dmi differ diff --git a/icons/obj/doors/Doorextglass.dmi b/icons/obj/doors/Doorextglass.dmi new file mode 100644 index 00000000..e3080a54 Binary files /dev/null and b/icons/obj/doors/Doorextglass.dmi differ diff --git a/icons/obj/doors/Doorf.dmi b/icons/obj/doors/Doorf.dmi new file mode 100644 index 00000000..5ece7e6c Binary files /dev/null and b/icons/obj/doors/Doorf.dmi differ diff --git a/icons/obj/doors/Doorfire.dmi b/icons/obj/doors/Doorfire.dmi new file mode 100644 index 00000000..e996780a Binary files /dev/null and b/icons/obj/doors/Doorfire.dmi differ diff --git a/icons/obj/doors/Doorfreezer.dmi b/icons/obj/doors/Doorfreezer.dmi new file mode 100644 index 00000000..194f55d7 Binary files /dev/null and b/icons/obj/doors/Doorfreezer.dmi differ diff --git a/icons/obj/doors/Doorglass.dmi b/icons/obj/doors/Doorglass.dmi new file mode 100644 index 00000000..9eb7098c Binary files /dev/null and b/icons/obj/doors/Doorglass.dmi differ diff --git a/icons/obj/doors/Doorglassone.dmi b/icons/obj/doors/Doorglassone.dmi new file mode 100644 index 00000000..d9468274 Binary files /dev/null and b/icons/obj/doors/Doorglassone.dmi differ diff --git a/icons/obj/doors/Doorgold.dmi b/icons/obj/doors/Doorgold.dmi new file mode 100644 index 00000000..bfa31252 Binary files /dev/null and b/icons/obj/doors/Doorgold.dmi differ diff --git a/icons/obj/doors/Doorhatcharmoury.dmi b/icons/obj/doors/Doorhatcharmoury.dmi new file mode 100644 index 00000000..daf364f6 Binary files /dev/null and b/icons/obj/doors/Doorhatcharmoury.dmi differ diff --git a/icons/obj/doors/Doorhatchele.dmi b/icons/obj/doors/Doorhatchele.dmi new file mode 100644 index 00000000..2c57d4c9 Binary files /dev/null and b/icons/obj/doors/Doorhatchele.dmi differ diff --git a/icons/obj/doors/Doorhatchmaint2.dmi b/icons/obj/doors/Doorhatchmaint2.dmi new file mode 100644 index 00000000..af3c2b5d Binary files /dev/null and b/icons/obj/doors/Doorhatchmaint2.dmi differ diff --git a/icons/obj/doors/Doormaint.dmi b/icons/obj/doors/Doormaint.dmi new file mode 100644 index 00000000..d0ebcb90 Binary files /dev/null and b/icons/obj/doors/Doormaint.dmi differ diff --git a/icons/obj/doors/Doormetalone.dmi b/icons/obj/doors/Doormetalone.dmi new file mode 100644 index 00000000..432919f7 Binary files /dev/null and b/icons/obj/doors/Doormetalone.dmi differ diff --git a/icons/obj/doors/Doormining.dmi b/icons/obj/doors/Doormining.dmi new file mode 100644 index 00000000..c9e3bc81 Binary files /dev/null and b/icons/obj/doors/Doormining.dmi differ diff --git a/icons/obj/doors/Doorminingglass.dmi b/icons/obj/doors/Doorminingglass.dmi new file mode 100644 index 00000000..64c15519 Binary files /dev/null and b/icons/obj/doors/Doorminingglass.dmi differ diff --git a/icons/obj/doors/Doorphoron.dmi b/icons/obj/doors/Doorphoron.dmi new file mode 100644 index 00000000..13fb4571 Binary files /dev/null and b/icons/obj/doors/Doorphoron.dmi differ diff --git a/icons/obj/doors/Doorsand.dmi b/icons/obj/doors/Doorsand.dmi new file mode 100644 index 00000000..ea50f1eb Binary files /dev/null and b/icons/obj/doors/Doorsand.dmi differ diff --git a/icons/obj/doors/Doorsec.dmi b/icons/obj/doors/Doorsec.dmi new file mode 100644 index 00000000..fb853100 Binary files /dev/null and b/icons/obj/doors/Doorsec.dmi differ diff --git a/icons/obj/doors/Doorsecglass.dmi b/icons/obj/doors/Doorsecglass.dmi new file mode 100644 index 00000000..d12be6cb Binary files /dev/null and b/icons/obj/doors/Doorsecglass.dmi differ diff --git a/icons/obj/doors/Doorsilver.dmi b/icons/obj/doors/Doorsilver.dmi new file mode 100644 index 00000000..2082ec05 Binary files /dev/null and b/icons/obj/doors/Doorsilver.dmi differ diff --git a/icons/obj/doors/Doorsol.dmi b/icons/obj/doors/Doorsol.dmi new file mode 100644 index 00000000..2af3cb76 Binary files /dev/null and b/icons/obj/doors/Doorsol.dmi differ diff --git a/icons/obj/doors/Doorsolglass.dmi b/icons/obj/doors/Doorsolglass.dmi new file mode 100644 index 00000000..dedffceb Binary files /dev/null and b/icons/obj/doors/Doorsolglass.dmi differ diff --git a/icons/obj/doors/Dooruranium.dmi b/icons/obj/doors/Dooruranium.dmi new file mode 100644 index 00000000..6a5fde9e Binary files /dev/null and b/icons/obj/doors/Dooruranium.dmi differ diff --git a/icons/obj/doors/Doorweap.dmi b/icons/obj/doors/Doorweap.dmi new file mode 100644 index 00000000..af5f11af Binary files /dev/null and b/icons/obj/doors/Doorweap.dmi differ diff --git a/icons/obj/doors/Doorweapglass.dmi b/icons/obj/doors/Doorweapglass.dmi new file mode 100644 index 00000000..fbdee47d Binary files /dev/null and b/icons/obj/doors/Doorweapglass.dmi differ diff --git a/icons/obj/doors/door_assembly.dmi b/icons/obj/doors/door_assembly.dmi new file mode 100644 index 00000000..ada81422 Binary files /dev/null and b/icons/obj/doors/door_assembly.dmi differ diff --git a/icons/obj/doors/door_assembly2x1.dmi b/icons/obj/doors/door_assembly2x1.dmi new file mode 100644 index 00000000..cdf4e92f Binary files /dev/null and b/icons/obj/doors/door_assembly2x1.dmi differ diff --git a/icons/obj/doors/door_fire2.dmi b/icons/obj/doors/door_fire2.dmi new file mode 100644 index 00000000..6c5943c7 Binary files /dev/null and b/icons/obj/doors/door_fire2.dmi differ diff --git a/icons/obj/doors/door_light_plalettes.dmi b/icons/obj/doors/door_light_plalettes.dmi new file mode 100644 index 00000000..820e2eb8 Binary files /dev/null and b/icons/obj/doors/door_light_plalettes.dmi differ diff --git a/icons/obj/doors/doorblack.dmi b/icons/obj/doors/doorblack.dmi new file mode 100644 index 00000000..ff3f15bf Binary files /dev/null and b/icons/obj/doors/doorblack.dmi differ diff --git a/icons/obj/doors/doorblackglass.dmi b/icons/obj/doors/doorblackglass.dmi new file mode 100644 index 00000000..58a5091f Binary files /dev/null and b/icons/obj/doors/doorblackglass.dmi differ diff --git a/icons/obj/doors/doorbogani.dmi b/icons/obj/doors/doorbogani.dmi new file mode 100644 index 00000000..2c7ee8f2 Binary files /dev/null and b/icons/obj/doors/doorbogani.dmi differ diff --git a/icons/obj/doors/doorchem.dmi b/icons/obj/doors/doorchem.dmi new file mode 100644 index 00000000..a979f969 Binary files /dev/null and b/icons/obj/doors/doorchem.dmi differ diff --git a/icons/obj/doors/doorchemglass.dmi b/icons/obj/doors/doorchemglass.dmi new file mode 100644 index 00000000..6bde3b59 Binary files /dev/null and b/icons/obj/doors/doorchemglass.dmi differ diff --git a/icons/obj/doors/doorforce.dmi b/icons/obj/doors/doorforce.dmi new file mode 100644 index 00000000..cf2f266b Binary files /dev/null and b/icons/obj/doors/doorforce.dmi differ diff --git a/icons/obj/doors/doorhydro.dmi b/icons/obj/doors/doorhydro.dmi new file mode 100644 index 00000000..a98d2ba7 Binary files /dev/null and b/icons/obj/doors/doorhydro.dmi differ diff --git a/icons/obj/doors/doorhydroglass.dmi b/icons/obj/doors/doorhydroglass.dmi new file mode 100644 index 00000000..b0a1b4c8 Binary files /dev/null and b/icons/obj/doors/doorhydroglass.dmi differ diff --git a/icons/obj/doors/doorint.dmi b/icons/obj/doors/doorint.dmi new file mode 100644 index 00000000..b8a35c95 Binary files /dev/null and b/icons/obj/doors/doorint.dmi differ diff --git a/icons/obj/doors/doorlift.dmi b/icons/obj/doors/doorlift.dmi new file mode 100644 index 00000000..3b037a89 Binary files /dev/null and b/icons/obj/doors/doorlift.dmi differ diff --git a/icons/obj/doors/doormed.dmi b/icons/obj/doors/doormed.dmi new file mode 100644 index 00000000..87f5d700 Binary files /dev/null and b/icons/obj/doors/doormed.dmi differ diff --git a/icons/obj/doors/doormedglass.dmi b/icons/obj/doors/doormedglass.dmi new file mode 100644 index 00000000..00269a80 Binary files /dev/null and b/icons/obj/doors/doormedglass.dmi differ diff --git a/icons/obj/doors/doormorgue.dmi b/icons/obj/doors/doormorgue.dmi new file mode 100644 index 00000000..c0ed1147 Binary files /dev/null and b/icons/obj/doors/doormorgue.dmi differ diff --git a/icons/obj/doors/doorred.dmi b/icons/obj/doors/doorred.dmi new file mode 100644 index 00000000..2d98a03d Binary files /dev/null and b/icons/obj/doors/doorred.dmi differ diff --git a/icons/obj/doors/doorredglass.dmi b/icons/obj/doors/doorredglass.dmi new file mode 100644 index 00000000..4393e570 Binary files /dev/null and b/icons/obj/doors/doorredglass.dmi differ diff --git a/icons/obj/doors/doorresearch.dmi b/icons/obj/doors/doorresearch.dmi new file mode 100644 index 00000000..a95e7b06 Binary files /dev/null and b/icons/obj/doors/doorresearch.dmi differ diff --git a/icons/obj/doors/doorresearchglass.dmi b/icons/obj/doors/doorresearchglass.dmi new file mode 100644 index 00000000..a48c60dd Binary files /dev/null and b/icons/obj/doors/doorresearchglass.dmi differ diff --git a/icons/obj/doors/doorsci.dmi b/icons/obj/doors/doorsci.dmi new file mode 100644 index 00000000..0fb35116 Binary files /dev/null and b/icons/obj/doors/doorsci.dmi differ diff --git a/icons/obj/doors/doorsciglass.dmi b/icons/obj/doors/doorsciglass.dmi new file mode 100644 index 00000000..69fdf6db Binary files /dev/null and b/icons/obj/doors/doorsciglass.dmi differ diff --git a/icons/obj/doors/doorviro.dmi b/icons/obj/doors/doorviro.dmi new file mode 100644 index 00000000..ab5ab233 Binary files /dev/null and b/icons/obj/doors/doorviro.dmi differ diff --git a/icons/obj/doors/doorviroglass.dmi b/icons/obj/doors/doorviroglass.dmi new file mode 100644 index 00000000..e3bd3881 Binary files /dev/null and b/icons/obj/doors/doorviroglass.dmi differ diff --git a/icons/obj/doors/edge_Doorfire.dmi b/icons/obj/doors/edge_Doorfire.dmi new file mode 100644 index 00000000..c0f81518 Binary files /dev/null and b/icons/obj/doors/edge_Doorfire.dmi differ diff --git a/icons/obj/doors/hightechsecurity.dmi b/icons/obj/doors/hightechsecurity.dmi new file mode 100644 index 00000000..236995e9 Binary files /dev/null and b/icons/obj/doors/hightechsecurity.dmi differ diff --git a/icons/obj/doors/material_doors.dmi b/icons/obj/doors/material_doors.dmi new file mode 100644 index 00000000..ccbae069 Binary files /dev/null and b/icons/obj/doors/material_doors.dmi differ diff --git a/icons/obj/doors/rapid_pdoor.dmi b/icons/obj/doors/rapid_pdoor.dmi new file mode 100644 index 00000000..5c14f84d Binary files /dev/null and b/icons/obj/doors/rapid_pdoor.dmi differ diff --git a/icons/obj/doors/vault.dmi b/icons/obj/doors/vault.dmi new file mode 100644 index 00000000..b001f8c8 Binary files /dev/null and b/icons/obj/doors/vault.dmi differ diff --git a/icons/obj/doors/windoor.dmi b/icons/obj/doors/windoor.dmi new file mode 100644 index 00000000..7a2f5ff0 Binary files /dev/null and b/icons/obj/doors/windoor.dmi differ diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi new file mode 100644 index 00000000..a9479e89 Binary files /dev/null and b/icons/obj/drinks.dmi differ diff --git a/icons/obj/dropper.dmi b/icons/obj/dropper.dmi new file mode 100644 index 00000000..40fa42fa Binary files /dev/null and b/icons/obj/dropper.dmi differ diff --git a/icons/obj/ecig.dmi b/icons/obj/ecig.dmi new file mode 100644 index 00000000..1b6dde8c Binary files /dev/null and b/icons/obj/ecig.dmi differ diff --git a/icons/obj/electronic_assemblies.dmi b/icons/obj/electronic_assemblies.dmi new file mode 100644 index 00000000..d16b8985 Binary files /dev/null and b/icons/obj/electronic_assemblies.dmi differ diff --git a/icons/obj/engine.dmi b/icons/obj/engine.dmi new file mode 100644 index 00000000..92922606 Binary files /dev/null and b/icons/obj/engine.dmi differ diff --git a/icons/obj/eyes.dmi b/icons/obj/eyes.dmi new file mode 100644 index 00000000..5cc157ab Binary files /dev/null and b/icons/obj/eyes.dmi differ diff --git a/icons/obj/flamethrower.dmi b/icons/obj/flamethrower.dmi new file mode 100644 index 00000000..61e4c19f Binary files /dev/null and b/icons/obj/flamethrower.dmi differ diff --git a/icons/obj/flora/128tree.dmi b/icons/obj/flora/128tree.dmi new file mode 100644 index 00000000..d88180d0 Binary files /dev/null and b/icons/obj/flora/128tree.dmi differ diff --git a/icons/obj/flora/164tree.dmi b/icons/obj/flora/164tree.dmi new file mode 100644 index 00000000..5eb21498 Binary files /dev/null and b/icons/obj/flora/164tree.dmi differ diff --git a/icons/obj/flora/96tree.dmi b/icons/obj/flora/96tree.dmi new file mode 100644 index 00000000..ac350f3e Binary files /dev/null and b/icons/obj/flora/96tree.dmi differ diff --git a/icons/obj/flora/ash_flora.dmi b/icons/obj/flora/ash_flora.dmi new file mode 100644 index 00000000..c8c128a0 Binary files /dev/null and b/icons/obj/flora/ash_flora.dmi differ diff --git a/icons/obj/flora/ausflora.dmi b/icons/obj/flora/ausflora.dmi new file mode 100644 index 00000000..720e4bd7 Binary files /dev/null and b/icons/obj/flora/ausflora.dmi differ diff --git a/icons/obj/flora/deadtrees.dmi b/icons/obj/flora/deadtrees.dmi new file mode 100644 index 00000000..f76ffd44 Binary files /dev/null and b/icons/obj/flora/deadtrees.dmi differ diff --git a/icons/obj/flora/dedtree.dmi b/icons/obj/flora/dedtree.dmi new file mode 100644 index 00000000..ccaded7c Binary files /dev/null and b/icons/obj/flora/dedtree.dmi differ diff --git a/icons/obj/flora/jungleflora.dmi b/icons/obj/flora/jungleflora.dmi new file mode 100644 index 00000000..9a266e92 Binary files /dev/null and b/icons/obj/flora/jungleflora.dmi differ diff --git a/icons/obj/flora/jungletrees.dmi b/icons/obj/flora/jungletrees.dmi new file mode 100644 index 00000000..e87542bd Binary files /dev/null and b/icons/obj/flora/jungletrees.dmi differ diff --git a/icons/obj/flora/jungletreesmall.dmi b/icons/obj/flora/jungletreesmall.dmi new file mode 100644 index 00000000..c56148b5 Binary files /dev/null and b/icons/obj/flora/jungletreesmall.dmi differ diff --git a/icons/obj/flora/largejungleflora.dmi b/icons/obj/flora/largejungleflora.dmi new file mode 100644 index 00000000..543a6fed Binary files /dev/null and b/icons/obj/flora/largejungleflora.dmi differ diff --git a/icons/obj/flora/pinetrees.dmi b/icons/obj/flora/pinetrees.dmi new file mode 100644 index 00000000..9ee04a5b Binary files /dev/null and b/icons/obj/flora/pinetrees.dmi differ diff --git a/icons/obj/flora/plants.dmi b/icons/obj/flora/plants.dmi new file mode 100644 index 00000000..b8c03a5c Binary files /dev/null and b/icons/obj/flora/plants.dmi differ diff --git a/icons/obj/flora/rocks.dmi b/icons/obj/flora/rocks.dmi new file mode 100644 index 00000000..a0b3fb6e Binary files /dev/null and b/icons/obj/flora/rocks.dmi differ diff --git a/icons/obj/flora/snowflora.dmi b/icons/obj/flora/snowflora.dmi new file mode 100644 index 00000000..11cbf5a5 Binary files /dev/null and b/icons/obj/flora/snowflora.dmi differ diff --git a/icons/obj/flora/treeees.dmi b/icons/obj/flora/treeees.dmi new file mode 100644 index 00000000..1c260a5c Binary files /dev/null and b/icons/obj/flora/treeees.dmi differ diff --git a/icons/obj/food.dmi b/icons/obj/food.dmi new file mode 100644 index 00000000..95ffb959 Binary files /dev/null and b/icons/obj/food.dmi differ diff --git a/icons/obj/food_custom.dmi b/icons/obj/food_custom.dmi new file mode 100644 index 00000000..4ad776cf Binary files /dev/null and b/icons/obj/food_custom.dmi differ diff --git a/icons/obj/food_ingredients.dmi b/icons/obj/food_ingredients.dmi new file mode 100644 index 00000000..3e30f511 Binary files /dev/null and b/icons/obj/food_ingredients.dmi differ diff --git a/icons/obj/forensics.dmi b/icons/obj/forensics.dmi new file mode 100644 index 00000000..9bb45ef3 Binary files /dev/null and b/icons/obj/forensics.dmi differ diff --git a/icons/obj/furniture.dmi b/icons/obj/furniture.dmi new file mode 100644 index 00000000..1d1db091 Binary files /dev/null and b/icons/obj/furniture.dmi differ diff --git a/icons/obj/gate.dmi b/icons/obj/gate.dmi new file mode 100644 index 00000000..e69de29b diff --git a/icons/obj/gravestone.dmi b/icons/obj/gravestone.dmi new file mode 100644 index 00000000..3d4138ed Binary files /dev/null and b/icons/obj/gravestone.dmi differ diff --git a/icons/obj/grenade.dmi b/icons/obj/grenade.dmi new file mode 100644 index 00000000..fe6a8f61 Binary files /dev/null and b/icons/obj/grenade.dmi differ diff --git a/icons/obj/gun.dmi b/icons/obj/gun.dmi new file mode 100644 index 00000000..0970fef1 Binary files /dev/null and b/icons/obj/gun.dmi differ diff --git a/icons/obj/guncabinet.dmi b/icons/obj/guncabinet.dmi new file mode 100644 index 00000000..2f63f6f0 Binary files /dev/null and b/icons/obj/guncabinet.dmi differ diff --git a/icons/obj/gunx35.dmi b/icons/obj/gunx35.dmi new file mode 100644 index 00000000..add47125 Binary files /dev/null and b/icons/obj/gunx35.dmi differ diff --git a/icons/obj/hacktool.dmi b/icons/obj/hacktool.dmi new file mode 100644 index 00000000..b1d6753f Binary files /dev/null and b/icons/obj/hacktool.dmi differ diff --git a/icons/obj/holosign.dmi b/icons/obj/holosign.dmi new file mode 100644 index 00000000..16236419 Binary files /dev/null and b/icons/obj/holosign.dmi differ diff --git a/icons/obj/hud_full.dmi b/icons/obj/hud_full.dmi new file mode 100644 index 00000000..1905602e Binary files /dev/null and b/icons/obj/hud_full.dmi differ diff --git a/icons/obj/hydroponics_growing.dmi b/icons/obj/hydroponics_growing.dmi new file mode 100644 index 00000000..2e2f1e11 Binary files /dev/null and b/icons/obj/hydroponics_growing.dmi differ diff --git a/icons/obj/hydroponics_large.dmi b/icons/obj/hydroponics_large.dmi new file mode 100644 index 00000000..5694b754 Binary files /dev/null and b/icons/obj/hydroponics_large.dmi differ diff --git a/icons/obj/hydroponics_machines.dmi b/icons/obj/hydroponics_machines.dmi new file mode 100644 index 00000000..56b946b9 Binary files /dev/null and b/icons/obj/hydroponics_machines.dmi differ diff --git a/icons/obj/hydroponics_misc.dmi b/icons/obj/hydroponics_misc.dmi new file mode 100644 index 00000000..a5c594d9 Binary files /dev/null and b/icons/obj/hydroponics_misc.dmi differ diff --git a/icons/obj/hydroponics_products.dmi b/icons/obj/hydroponics_products.dmi new file mode 100644 index 00000000..9bf5db02 Binary files /dev/null and b/icons/obj/hydroponics_products.dmi differ diff --git a/icons/obj/hydroponics_vines.dmi b/icons/obj/hydroponics_vines.dmi new file mode 100644 index 00000000..be658d84 Binary files /dev/null and b/icons/obj/hydroponics_vines.dmi differ diff --git a/icons/obj/inflatable.dmi b/icons/obj/inflatable.dmi new file mode 100644 index 00000000..403e39c6 Binary files /dev/null and b/icons/obj/inflatable.dmi differ diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi new file mode 100644 index 00000000..38ae8e76 Binary files /dev/null and b/icons/obj/items.dmi differ diff --git a/icons/obj/items/attachments.dmi b/icons/obj/items/attachments.dmi new file mode 100644 index 00000000..ae2b1eed Binary files /dev/null and b/icons/obj/items/attachments.dmi differ diff --git a/icons/obj/items/broken_weapons.dmi b/icons/obj/items/broken_weapons.dmi new file mode 100644 index 00000000..dddcc574 Binary files /dev/null and b/icons/obj/items/broken_weapons.dmi differ diff --git a/icons/obj/items/chem_jars.dmi b/icons/obj/items/chem_jars.dmi new file mode 100644 index 00000000..4697fcbf Binary files /dev/null and b/icons/obj/items/chem_jars.dmi differ diff --git a/icons/obj/items/mortars.dmi b/icons/obj/items/mortars.dmi new file mode 100644 index 00000000..6c6c1356 Binary files /dev/null and b/icons/obj/items/mortars.dmi differ diff --git a/icons/obj/items/shovel.dmi b/icons/obj/items/shovel.dmi new file mode 100644 index 00000000..53aa5a2a Binary files /dev/null and b/icons/obj/items/shovel.dmi differ diff --git a/icons/obj/iv_drip.dmi b/icons/obj/iv_drip.dmi new file mode 100644 index 00000000..b5faf94f Binary files /dev/null and b/icons/obj/iv_drip.dmi differ diff --git a/icons/obj/janitor.dmi b/icons/obj/janitor.dmi new file mode 100644 index 00000000..796e2c88 Binary files /dev/null and b/icons/obj/janitor.dmi differ diff --git a/icons/obj/jukebox.dmi b/icons/obj/jukebox.dmi new file mode 100644 index 00000000..91090497 Binary files /dev/null and b/icons/obj/jukebox.dmi differ diff --git a/icons/obj/kitchen.dmi b/icons/obj/kitchen.dmi new file mode 100644 index 00000000..83276361 Binary files /dev/null and b/icons/obj/kitchen.dmi differ diff --git a/icons/obj/library.dmi b/icons/obj/library.dmi new file mode 100644 index 00000000..bda50cb3 Binary files /dev/null and b/icons/obj/library.dmi differ diff --git a/icons/obj/light_overlays.dmi b/icons/obj/light_overlays.dmi new file mode 100644 index 00000000..928a7864 Binary files /dev/null and b/icons/obj/light_overlays.dmi differ diff --git a/icons/obj/lighting.dmi b/icons/obj/lighting.dmi new file mode 100644 index 00000000..23d9fb4c Binary files /dev/null and b/icons/obj/lighting.dmi differ diff --git a/icons/obj/lockwall.dmi b/icons/obj/lockwall.dmi new file mode 100644 index 00000000..a143d160 Binary files /dev/null and b/icons/obj/lockwall.dmi differ diff --git a/icons/obj/machines/am_engine.dmi b/icons/obj/machines/am_engine.dmi new file mode 100644 index 00000000..8c5a5aa0 Binary files /dev/null and b/icons/obj/machines/am_engine.dmi differ diff --git a/icons/obj/machines/antimatter.dmi b/icons/obj/machines/antimatter.dmi new file mode 100644 index 00000000..4e20f20e Binary files /dev/null and b/icons/obj/machines/antimatter.dmi differ diff --git a/icons/obj/machines/artillery.dmi b/icons/obj/machines/artillery.dmi new file mode 100644 index 00000000..28f40800 Binary files /dev/null and b/icons/obj/machines/artillery.dmi differ diff --git a/icons/obj/machines/drone_fab.dmi b/icons/obj/machines/drone_fab.dmi new file mode 100644 index 00000000..066b51c2 Binary files /dev/null and b/icons/obj/machines/drone_fab.dmi differ diff --git a/icons/obj/machines/fiber.dmi b/icons/obj/machines/fiber.dmi new file mode 100644 index 00000000..952c391f Binary files /dev/null and b/icons/obj/machines/fiber.dmi differ diff --git a/icons/obj/machines/field_generator.dmi b/icons/obj/machines/field_generator.dmi new file mode 100644 index 00000000..fcb083f8 Binary files /dev/null and b/icons/obj/machines/field_generator.dmi differ diff --git a/icons/obj/machines/floodlight.dmi b/icons/obj/machines/floodlight.dmi new file mode 100644 index 00000000..8dea4dc8 Binary files /dev/null and b/icons/obj/machines/floodlight.dmi differ diff --git a/icons/obj/machines/floor_light.dmi b/icons/obj/machines/floor_light.dmi new file mode 100644 index 00000000..c2386492 Binary files /dev/null and b/icons/obj/machines/floor_light.dmi differ diff --git a/icons/obj/machines/gateway.dmi b/icons/obj/machines/gateway.dmi new file mode 100644 index 00000000..cfe4c267 Binary files /dev/null and b/icons/obj/machines/gateway.dmi differ diff --git a/icons/obj/machines/heavy_fiber.dmi b/icons/obj/machines/heavy_fiber.dmi new file mode 100644 index 00000000..9969d65e Binary files /dev/null and b/icons/obj/machines/heavy_fiber.dmi differ diff --git a/icons/obj/machines/heavy_lathe.dmi b/icons/obj/machines/heavy_lathe.dmi new file mode 100644 index 00000000..1189687d Binary files /dev/null and b/icons/obj/machines/heavy_lathe.dmi differ diff --git a/icons/obj/machines/implantchair.dmi b/icons/obj/machines/implantchair.dmi new file mode 100644 index 00000000..94adefcb Binary files /dev/null and b/icons/obj/machines/implantchair.dmi differ diff --git a/icons/obj/machines/lasers.dmi b/icons/obj/machines/lasers.dmi new file mode 100644 index 00000000..e114313e Binary files /dev/null and b/icons/obj/machines/lasers.dmi differ diff --git a/icons/obj/machines/mining_machines.dmi b/icons/obj/machines/mining_machines.dmi new file mode 100644 index 00000000..af660e24 Binary files /dev/null and b/icons/obj/machines/mining_machines.dmi differ diff --git a/icons/obj/machines/particle_accelerator.dmi b/icons/obj/machines/particle_accelerator.dmi new file mode 100644 index 00000000..db412286 Binary files /dev/null and b/icons/obj/machines/particle_accelerator.dmi differ diff --git a/icons/obj/machines/particle_accelerator2.dmi b/icons/obj/machines/particle_accelerator2.dmi new file mode 100644 index 00000000..a489510e Binary files /dev/null and b/icons/obj/machines/particle_accelerator2.dmi differ diff --git a/icons/obj/machines/power/fusion.dmi b/icons/obj/machines/power/fusion.dmi new file mode 100644 index 00000000..aab36a32 Binary files /dev/null and b/icons/obj/machines/power/fusion.dmi differ diff --git a/icons/obj/machines/power/fusion_core.dmi b/icons/obj/machines/power/fusion_core.dmi new file mode 100644 index 00000000..76904a12 Binary files /dev/null and b/icons/obj/machines/power/fusion_core.dmi differ diff --git a/icons/obj/machines/research.dmi b/icons/obj/machines/research.dmi new file mode 100644 index 00000000..e2fa3cd9 Binary files /dev/null and b/icons/obj/machines/research.dmi differ diff --git a/icons/obj/machines/self_destruct.dmi b/icons/obj/machines/self_destruct.dmi new file mode 100644 index 00000000..91310897 Binary files /dev/null and b/icons/obj/machines/self_destruct.dmi differ diff --git a/icons/obj/machines/shielding.dmi b/icons/obj/machines/shielding.dmi new file mode 100644 index 00000000..d7cfa5ba Binary files /dev/null and b/icons/obj/machines/shielding.dmi differ diff --git a/icons/obj/machines/sunreactor.dmi b/icons/obj/machines/sunreactor.dmi new file mode 100644 index 00000000..c3502d8c Binary files /dev/null and b/icons/obj/machines/sunreactor.dmi differ diff --git a/icons/obj/machines/turret_control.dmi b/icons/obj/machines/turret_control.dmi new file mode 100644 index 00000000..b68dd8f0 Binary files /dev/null and b/icons/obj/machines/turret_control.dmi differ diff --git a/icons/obj/machines/washing_machine.dmi b/icons/obj/machines/washing_machine.dmi new file mode 100644 index 00000000..0213078f Binary files /dev/null and b/icons/obj/machines/washing_machine.dmi differ diff --git a/icons/obj/magic.dmi b/icons/obj/magic.dmi new file mode 100644 index 00000000..f92243d6 Binary files /dev/null and b/icons/obj/magic.dmi differ diff --git a/icons/obj/mainframe.dmi b/icons/obj/mainframe.dmi new file mode 100644 index 00000000..aaf6f934 Binary files /dev/null and b/icons/obj/mainframe.dmi differ diff --git a/icons/obj/mediwall.dmi b/icons/obj/mediwall.dmi new file mode 100644 index 00000000..aa077eae Binary files /dev/null and b/icons/obj/mediwall.dmi differ diff --git a/icons/obj/meteor.dmi b/icons/obj/meteor.dmi new file mode 100644 index 00000000..757dac83 Binary files /dev/null and b/icons/obj/meteor.dmi differ diff --git a/icons/obj/meter.dmi b/icons/obj/meter.dmi new file mode 100644 index 00000000..5f3051d8 Binary files /dev/null and b/icons/obj/meter.dmi differ diff --git a/icons/obj/mining.dmi b/icons/obj/mining.dmi new file mode 100644 index 00000000..377884a0 Binary files /dev/null and b/icons/obj/mining.dmi differ diff --git a/icons/obj/mining_drill.dmi b/icons/obj/mining_drill.dmi new file mode 100644 index 00000000..7a9ad6b0 Binary files /dev/null and b/icons/obj/mining_drill.dmi differ diff --git a/icons/obj/modular_components.dmi b/icons/obj/modular_components.dmi new file mode 100644 index 00000000..3784d699 Binary files /dev/null and b/icons/obj/modular_components.dmi differ diff --git a/icons/obj/modular_console.dmi b/icons/obj/modular_console.dmi new file mode 100644 index 00000000..0622ebbf Binary files /dev/null and b/icons/obj/modular_console.dmi differ diff --git a/icons/obj/modular_laptop.dmi b/icons/obj/modular_laptop.dmi new file mode 100644 index 00000000..af188305 Binary files /dev/null and b/icons/obj/modular_laptop.dmi differ diff --git a/icons/obj/modular_tablet.dmi b/icons/obj/modular_tablet.dmi new file mode 100644 index 00000000..5c86d27d Binary files /dev/null and b/icons/obj/modular_tablet.dmi differ diff --git a/icons/obj/modular_telescreen.dmi b/icons/obj/modular_telescreen.dmi new file mode 100644 index 00000000..2b82cdb1 Binary files /dev/null and b/icons/obj/modular_telescreen.dmi differ diff --git a/icons/obj/module.dmi b/icons/obj/module.dmi new file mode 100644 index 00000000..3e00e44e Binary files /dev/null and b/icons/obj/module.dmi differ diff --git a/icons/obj/monitors.dmi b/icons/obj/monitors.dmi new file mode 100644 index 00000000..a45cb38c Binary files /dev/null and b/icons/obj/monitors.dmi differ diff --git a/icons/obj/monolith.dmi b/icons/obj/monolith.dmi new file mode 100644 index 00000000..eaa97dda Binary files /dev/null and b/icons/obj/monolith.dmi differ diff --git a/icons/obj/musician.dmi b/icons/obj/musician.dmi new file mode 100644 index 00000000..b0a0efe0 Binary files /dev/null and b/icons/obj/musician.dmi differ diff --git a/icons/obj/nanopaste.dmi b/icons/obj/nanopaste.dmi new file mode 100644 index 00000000..b3c09632 Binary files /dev/null and b/icons/obj/nanopaste.dmi differ diff --git a/icons/obj/narsie.dmi b/icons/obj/narsie.dmi new file mode 100644 index 00000000..73df7c31 Binary files /dev/null and b/icons/obj/narsie.dmi differ diff --git a/icons/obj/narsie_spawn_anim.dmi b/icons/obj/narsie_spawn_anim.dmi new file mode 100644 index 00000000..4f3de372 Binary files /dev/null and b/icons/obj/narsie_spawn_anim.dmi differ diff --git a/icons/obj/nuclear_cylinder.dmi b/icons/obj/nuclear_cylinder.dmi new file mode 100644 index 00000000..9eb7419a Binary files /dev/null and b/icons/obj/nuclear_cylinder.dmi differ diff --git a/icons/obj/nuke.dmi b/icons/obj/nuke.dmi new file mode 100644 index 00000000..72bbfd80 Binary files /dev/null and b/icons/obj/nuke.dmi differ diff --git a/icons/obj/nuke_station.dmi b/icons/obj/nuke_station.dmi new file mode 100644 index 00000000..c7cffca4 Binary files /dev/null and b/icons/obj/nuke_station.dmi differ diff --git a/icons/obj/objects.dmi b/icons/obj/objects.dmi new file mode 100644 index 00000000..72d00027 Binary files /dev/null and b/icons/obj/objects.dmi differ diff --git a/icons/obj/old_computers.dmi b/icons/obj/old_computers.dmi new file mode 100644 index 00000000..fd7830b8 Binary files /dev/null and b/icons/obj/old_computers.dmi differ diff --git a/icons/obj/overmap.dmi b/icons/obj/overmap.dmi new file mode 100644 index 00000000..d72688b9 Binary files /dev/null and b/icons/obj/overmap.dmi differ diff --git a/icons/obj/paper.dmi b/icons/obj/paper.dmi new file mode 100644 index 00000000..ca4663df Binary files /dev/null and b/icons/obj/paper.dmi differ diff --git a/icons/obj/pda.dmi b/icons/obj/pda.dmi new file mode 100644 index 00000000..5b64d75f Binary files /dev/null and b/icons/obj/pda.dmi differ diff --git a/icons/obj/pieces.dmi b/icons/obj/pieces.dmi new file mode 100644 index 00000000..7759c078 Binary files /dev/null and b/icons/obj/pieces.dmi differ diff --git a/icons/obj/pinpointer.dmi b/icons/obj/pinpointer.dmi new file mode 100644 index 00000000..f3df8efa Binary files /dev/null and b/icons/obj/pinpointer.dmi differ diff --git a/icons/obj/pipe-item.dmi b/icons/obj/pipe-item.dmi new file mode 100644 index 00000000..ef38c308 Binary files /dev/null and b/icons/obj/pipe-item.dmi differ diff --git a/icons/obj/pipes.dmi b/icons/obj/pipes.dmi new file mode 100644 index 00000000..581a6260 Binary files /dev/null and b/icons/obj/pipes.dmi differ diff --git a/icons/obj/pipes/disposal.dmi b/icons/obj/pipes/disposal.dmi new file mode 100644 index 00000000..4a3037b7 Binary files /dev/null and b/icons/obj/pipes/disposal.dmi differ diff --git a/icons/obj/pipes/large.dmi b/icons/obj/pipes/large.dmi new file mode 100644 index 00000000..55aad8e2 Binary files /dev/null and b/icons/obj/pipes/large.dmi differ diff --git a/icons/obj/pipes/regular.dmi b/icons/obj/pipes/regular.dmi new file mode 100644 index 00000000..3bc0f0b7 Binary files /dev/null and b/icons/obj/pipes/regular.dmi differ diff --git a/icons/obj/pipes/transit_tube.dmi b/icons/obj/pipes/transit_tube.dmi new file mode 100644 index 00000000..45b2abc3 Binary files /dev/null and b/icons/obj/pipes/transit_tube.dmi differ diff --git a/icons/obj/pipes/transit_tube_pod.dmi b/icons/obj/pipes/transit_tube_pod.dmi new file mode 100644 index 00000000..a52b80f8 Binary files /dev/null and b/icons/obj/pipes/transit_tube_pod.dmi differ diff --git a/icons/obj/pipes/transit_tube_station.dmi b/icons/obj/pipes/transit_tube_station.dmi new file mode 100644 index 00000000..ca8515fd Binary files /dev/null and b/icons/obj/pipes/transit_tube_station.dmi differ diff --git a/icons/obj/pipes2.dmi b/icons/obj/pipes2.dmi new file mode 100644 index 00000000..6e800711 Binary files /dev/null and b/icons/obj/pipes2.dmi differ diff --git a/icons/obj/pipeturbine.dmi b/icons/obj/pipeturbine.dmi new file mode 100644 index 00000000..fccec4c9 Binary files /dev/null and b/icons/obj/pipeturbine.dmi differ diff --git a/icons/obj/pit.dmi b/icons/obj/pit.dmi new file mode 100644 index 00000000..76ac50d1 Binary files /dev/null and b/icons/obj/pit.dmi differ diff --git a/icons/obj/plants.dmi b/icons/obj/plants.dmi new file mode 100644 index 00000000..d3f8e0ef Binary files /dev/null and b/icons/obj/plants.dmi differ diff --git a/icons/obj/playing_cards.dmi b/icons/obj/playing_cards.dmi new file mode 100644 index 00000000..2f4c01b7 Binary files /dev/null and b/icons/obj/playing_cards.dmi differ diff --git a/icons/obj/podwindows.dmi b/icons/obj/podwindows.dmi new file mode 100644 index 00000000..75bd1d98 Binary files /dev/null and b/icons/obj/podwindows.dmi differ diff --git a/icons/obj/poop.dmi b/icons/obj/poop.dmi new file mode 100644 index 00000000..1433cd90 Binary files /dev/null and b/icons/obj/poop.dmi differ diff --git a/icons/obj/power.dmi b/icons/obj/power.dmi new file mode 100644 index 00000000..0dd31a0b Binary files /dev/null and b/icons/obj/power.dmi differ diff --git a/icons/obj/power_cond_heavy.dmi b/icons/obj/power_cond_heavy.dmi new file mode 100644 index 00000000..69b9ef08 Binary files /dev/null and b/icons/obj/power_cond_heavy.dmi differ diff --git a/icons/obj/power_cond_white.dmi b/icons/obj/power_cond_white.dmi new file mode 100644 index 00000000..f9f3d9da Binary files /dev/null and b/icons/obj/power_cond_white.dmi differ diff --git a/icons/obj/power_local.dmi b/icons/obj/power_local.dmi new file mode 100644 index 00000000..b2b43735 Binary files /dev/null and b/icons/obj/power_local.dmi differ diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi new file mode 100644 index 00000000..6266fc19 Binary files /dev/null and b/icons/obj/projectiles.dmi differ diff --git a/icons/obj/quicksand.dmi b/icons/obj/quicksand.dmi new file mode 100644 index 00000000..2bea4ad6 Binary files /dev/null and b/icons/obj/quicksand.dmi differ diff --git a/icons/obj/radio.dmi b/icons/obj/radio.dmi new file mode 100644 index 00000000..4a529388 Binary files /dev/null and b/icons/obj/radio.dmi differ diff --git a/icons/obj/railing.dmi b/icons/obj/railing.dmi new file mode 100644 index 00000000..c37c89c1 Binary files /dev/null and b/icons/obj/railing.dmi differ diff --git a/icons/obj/reagentfillings.dmi b/icons/obj/reagentfillings.dmi new file mode 100644 index 00000000..229f6413 Binary files /dev/null and b/icons/obj/reagentfillings.dmi differ diff --git a/icons/obj/recycling.dmi b/icons/obj/recycling.dmi new file mode 100644 index 00000000..087571ca Binary files /dev/null and b/icons/obj/recycling.dmi differ diff --git a/icons/obj/rift.dmi b/icons/obj/rift.dmi new file mode 100644 index 00000000..85b75103 Binary files /dev/null and b/icons/obj/rift.dmi differ diff --git a/icons/obj/robot_component.dmi b/icons/obj/robot_component.dmi new file mode 100644 index 00000000..1129f25a Binary files /dev/null and b/icons/obj/robot_component.dmi differ diff --git a/icons/obj/robot_parts.dmi b/icons/obj/robot_parts.dmi new file mode 100644 index 00000000..94610280 Binary files /dev/null and b/icons/obj/robot_parts.dmi differ diff --git a/icons/obj/robot_storage.dmi b/icons/obj/robot_storage.dmi new file mode 100644 index 00000000..5a996c01 Binary files /dev/null and b/icons/obj/robot_storage.dmi differ diff --git a/icons/obj/robotics.dmi b/icons/obj/robotics.dmi new file mode 100644 index 00000000..c53e7823 Binary files /dev/null and b/icons/obj/robotics.dmi differ diff --git a/icons/obj/rollerbed.dmi b/icons/obj/rollerbed.dmi new file mode 100644 index 00000000..da92698c Binary files /dev/null and b/icons/obj/rollerbed.dmi differ diff --git a/icons/obj/rubble.dmi b/icons/obj/rubble.dmi new file mode 100644 index 00000000..a6d27999 Binary files /dev/null and b/icons/obj/rubble.dmi differ diff --git a/icons/obj/rune.dmi b/icons/obj/rune.dmi new file mode 100644 index 00000000..deb68693 Binary files /dev/null and b/icons/obj/rune.dmi differ diff --git a/icons/obj/seeds.dmi b/icons/obj/seeds.dmi new file mode 100644 index 00000000..9608eed1 Binary files /dev/null and b/icons/obj/seeds.dmi differ diff --git a/icons/obj/shards.dmi b/icons/obj/shards.dmi new file mode 100644 index 00000000..e8bee2d5 Binary files /dev/null and b/icons/obj/shards.dmi differ diff --git a/icons/obj/ship_engine.dmi b/icons/obj/ship_engine.dmi new file mode 100644 index 00000000..98b203bf Binary files /dev/null and b/icons/obj/ship_engine.dmi differ diff --git a/icons/obj/singularity.dmi b/icons/obj/singularity.dmi new file mode 100644 index 00000000..cc0156de Binary files /dev/null and b/icons/obj/singularity.dmi differ diff --git a/icons/obj/smoothlattice.dmi b/icons/obj/smoothlattice.dmi new file mode 100644 index 00000000..30f83a38 Binary files /dev/null and b/icons/obj/smoothlattice.dmi differ diff --git a/icons/obj/sstairs.dmi b/icons/obj/sstairs.dmi new file mode 100644 index 00000000..264e9983 Binary files /dev/null and b/icons/obj/sstairs.dmi differ diff --git a/icons/obj/stairs.dmi b/icons/obj/stairs.dmi new file mode 100644 index 00000000..c1bde688 Binary files /dev/null and b/icons/obj/stairs.dmi differ diff --git a/icons/obj/stationobjs.dmi b/icons/obj/stationobjs.dmi new file mode 100644 index 00000000..4318c13a Binary files /dev/null and b/icons/obj/stationobjs.dmi differ diff --git a/icons/obj/statue.dmi b/icons/obj/statue.dmi new file mode 100644 index 00000000..5da8a138 Binary files /dev/null and b/icons/obj/statue.dmi differ diff --git a/icons/obj/status_display.dmi b/icons/obj/status_display.dmi new file mode 100644 index 00000000..4abd3984 Binary files /dev/null and b/icons/obj/status_display.dmi differ diff --git a/icons/obj/stock_parts.dmi b/icons/obj/stock_parts.dmi new file mode 100644 index 00000000..06ce3cec Binary files /dev/null and b/icons/obj/stock_parts.dmi differ diff --git a/icons/obj/storage.dmi b/icons/obj/storage.dmi new file mode 100644 index 00000000..fe6689b8 Binary files /dev/null and b/icons/obj/storage.dmi differ diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi new file mode 100644 index 00000000..d54fa66a Binary files /dev/null and b/icons/obj/structures.dmi differ diff --git a/icons/obj/structures/barrier.dmi b/icons/obj/structures/barrier.dmi new file mode 100644 index 00000000..b8dc1999 Binary files /dev/null and b/icons/obj/structures/barrier.dmi differ diff --git a/icons/obj/suitcooler.dmi b/icons/obj/suitcooler.dmi new file mode 100644 index 00000000..f881e07d Binary files /dev/null and b/icons/obj/suitcooler.dmi differ diff --git a/icons/obj/suitstorage.dmi b/icons/obj/suitstorage.dmi new file mode 100644 index 00000000..1f474886 Binary files /dev/null and b/icons/obj/suitstorage.dmi differ diff --git a/icons/obj/supplybeacon.dmi b/icons/obj/supplybeacon.dmi new file mode 100644 index 00000000..9734d854 Binary files /dev/null and b/icons/obj/supplybeacon.dmi differ diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi new file mode 100644 index 00000000..d30d078a Binary files /dev/null and b/icons/obj/surgery.dmi differ diff --git a/icons/obj/syndieweapons.dmi b/icons/obj/syndieweapons.dmi new file mode 100644 index 00000000..bccb01e1 Binary files /dev/null and b/icons/obj/syndieweapons.dmi differ diff --git a/icons/obj/syringe.dmi b/icons/obj/syringe.dmi new file mode 100644 index 00000000..f62b4fb6 Binary files /dev/null and b/icons/obj/syringe.dmi differ diff --git a/icons/obj/syringefilling.dmi b/icons/obj/syringefilling.dmi new file mode 100644 index 00000000..5c5cac84 Binary files /dev/null and b/icons/obj/syringefilling.dmi differ diff --git a/icons/obj/tables.dmi b/icons/obj/tables.dmi new file mode 100644 index 00000000..9e36ab60 Binary files /dev/null and b/icons/obj/tables.dmi differ diff --git a/icons/obj/tank.dmi b/icons/obj/tank.dmi new file mode 100644 index 00000000..493e9fb3 Binary files /dev/null and b/icons/obj/tank.dmi differ diff --git a/icons/obj/telescience.dmi b/icons/obj/telescience.dmi new file mode 100644 index 00000000..dcd7f39d Binary files /dev/null and b/icons/obj/telescience.dmi differ diff --git a/icons/obj/terminals.dmi b/icons/obj/terminals.dmi new file mode 100644 index 00000000..1afdc104 Binary files /dev/null and b/icons/obj/terminals.dmi differ diff --git a/icons/obj/tiles.dmi b/icons/obj/tiles.dmi new file mode 100644 index 00000000..b08e6604 Binary files /dev/null and b/icons/obj/tiles.dmi differ diff --git a/icons/obj/tools.dmi b/icons/obj/tools.dmi new file mode 100644 index 00000000..f3ccf9cf Binary files /dev/null and b/icons/obj/tools.dmi differ diff --git a/icons/obj/torches.dmi b/icons/obj/torches.dmi new file mode 100644 index 00000000..1d61008e Binary files /dev/null and b/icons/obj/torches.dmi differ diff --git a/icons/obj/toy.dmi b/icons/obj/toy.dmi new file mode 100644 index 00000000..d031d9a8 Binary files /dev/null and b/icons/obj/toy.dmi differ diff --git a/icons/obj/trash.dmi b/icons/obj/trash.dmi new file mode 100644 index 00000000..eb086ac5 Binary files /dev/null and b/icons/obj/trash.dmi differ diff --git a/icons/obj/tubing.dmi b/icons/obj/tubing.dmi new file mode 100644 index 00000000..89c4bf45 Binary files /dev/null and b/icons/obj/tubing.dmi differ diff --git a/icons/obj/turbolift.dmi b/icons/obj/turbolift.dmi new file mode 100644 index 00000000..cffc8aa1 Binary files /dev/null and b/icons/obj/turbolift.dmi differ diff --git a/icons/obj/turbolift_preview_2x2.dmi b/icons/obj/turbolift_preview_2x2.dmi new file mode 100644 index 00000000..f0f1ec49 Binary files /dev/null and b/icons/obj/turbolift_preview_2x2.dmi differ diff --git a/icons/obj/turbolift_preview_3x3.dmi b/icons/obj/turbolift_preview_3x3.dmi new file mode 100644 index 00000000..e054a6b9 Binary files /dev/null and b/icons/obj/turbolift_preview_3x3.dmi differ diff --git a/icons/obj/turrets.dmi b/icons/obj/turrets.dmi new file mode 100644 index 00000000..b3a20367 Binary files /dev/null and b/icons/obj/turrets.dmi differ diff --git a/icons/obj/vehicles.dmi b/icons/obj/vehicles.dmi new file mode 100644 index 00000000..e7027559 Binary files /dev/null and b/icons/obj/vehicles.dmi differ diff --git a/icons/obj/vending.dmi b/icons/obj/vending.dmi new file mode 100644 index 00000000..d20c8de9 Binary files /dev/null and b/icons/obj/vending.dmi differ diff --git a/icons/obj/vialbox.dmi b/icons/obj/vialbox.dmi new file mode 100644 index 00000000..c08b5cfe Binary files /dev/null and b/icons/obj/vialbox.dmi differ diff --git a/icons/obj/virology.dmi b/icons/obj/virology.dmi new file mode 100644 index 00000000..02a42604 Binary files /dev/null and b/icons/obj/virology.dmi differ diff --git a/icons/obj/wallet.dmi b/icons/obj/wallet.dmi new file mode 100644 index 00000000..a623c0e1 Binary files /dev/null and b/icons/obj/wallet.dmi differ diff --git a/icons/obj/walllocker.dmi b/icons/obj/walllocker.dmi new file mode 100644 index 00000000..8f112b05 Binary files /dev/null and b/icons/obj/walllocker.dmi differ diff --git a/icons/obj/warfare.dmi b/icons/obj/warfare.dmi new file mode 100644 index 00000000..4872b376 Binary files /dev/null and b/icons/obj/warfare.dmi differ diff --git a/icons/obj/watercloset.dmi b/icons/obj/watercloset.dmi new file mode 100644 index 00000000..daf89ace Binary files /dev/null and b/icons/obj/watercloset.dmi differ diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi new file mode 100644 index 00000000..8368a190 Binary files /dev/null and b/icons/obj/weapons.dmi differ diff --git a/icons/obj/weapons/canesword.dmi b/icons/obj/weapons/canesword.dmi new file mode 100644 index 00000000..bfcef938 Binary files /dev/null and b/icons/obj/weapons/canesword.dmi differ diff --git a/icons/obj/wizard.dmi b/icons/obj/wizard.dmi new file mode 100644 index 00000000..650d75e8 Binary files /dev/null and b/icons/obj/wizard.dmi differ diff --git a/icons/obj/xenoarchaeology.dmi b/icons/obj/xenoarchaeology.dmi new file mode 100644 index 00000000..ce343d4b Binary files /dev/null and b/icons/obj/xenoarchaeology.dmi differ diff --git a/icons/pda_icons/pda_atmos.png b/icons/pda_icons/pda_atmos.png new file mode 100644 index 00000000..89a55a0a Binary files /dev/null and b/icons/pda_icons/pda_atmos.png differ diff --git a/icons/pda_icons/pda_back.png b/icons/pda_icons/pda_back.png new file mode 100644 index 00000000..47088248 Binary files /dev/null and b/icons/pda_icons/pda_back.png differ diff --git a/icons/pda_icons/pda_bell.png b/icons/pda_icons/pda_bell.png new file mode 100644 index 00000000..1e989c27 Binary files /dev/null and b/icons/pda_icons/pda_bell.png differ diff --git a/icons/pda_icons/pda_blank.png b/icons/pda_icons/pda_blank.png new file mode 100644 index 00000000..665861d3 Binary files /dev/null and b/icons/pda_icons/pda_blank.png differ diff --git a/icons/pda_icons/pda_boom.png b/icons/pda_icons/pda_boom.png new file mode 100644 index 00000000..70e473c3 Binary files /dev/null and b/icons/pda_icons/pda_boom.png differ diff --git a/icons/pda_icons/pda_bucket.png b/icons/pda_icons/pda_bucket.png new file mode 100644 index 00000000..ee030e3a Binary files /dev/null and b/icons/pda_icons/pda_bucket.png differ diff --git a/icons/pda_icons/pda_chatroom.png b/icons/pda_icons/pda_chatroom.png new file mode 100644 index 00000000..a00221c4 Binary files /dev/null and b/icons/pda_icons/pda_chatroom.png differ diff --git a/icons/pda_icons/pda_crate.png b/icons/pda_icons/pda_crate.png new file mode 100644 index 00000000..e1e076e2 Binary files /dev/null and b/icons/pda_icons/pda_crate.png differ diff --git a/icons/pda_icons/pda_cuffs.png b/icons/pda_icons/pda_cuffs.png new file mode 100644 index 00000000..71958c8a Binary files /dev/null and b/icons/pda_icons/pda_cuffs.png differ diff --git a/icons/pda_icons/pda_eject.png b/icons/pda_icons/pda_eject.png new file mode 100644 index 00000000..4168be03 Binary files /dev/null and b/icons/pda_icons/pda_eject.png differ diff --git a/icons/pda_icons/pda_exit.png b/icons/pda_icons/pda_exit.png new file mode 100644 index 00000000..cd983a4a Binary files /dev/null and b/icons/pda_icons/pda_exit.png differ diff --git a/icons/pda_icons/pda_flashlight.png b/icons/pda_icons/pda_flashlight.png new file mode 100644 index 00000000..34767279 Binary files /dev/null and b/icons/pda_icons/pda_flashlight.png differ diff --git a/icons/pda_icons/pda_honk.png b/icons/pda_icons/pda_honk.png new file mode 100644 index 00000000..55632bf4 Binary files /dev/null and b/icons/pda_icons/pda_honk.png differ diff --git a/icons/pda_icons/pda_locked.PNG b/icons/pda_icons/pda_locked.PNG new file mode 100644 index 00000000..79fe5829 Binary files /dev/null and b/icons/pda_icons/pda_locked.PNG differ diff --git a/icons/pda_icons/pda_mail.png b/icons/pda_icons/pda_mail.png new file mode 100644 index 00000000..6bfb1e8c Binary files /dev/null and b/icons/pda_icons/pda_mail.png differ diff --git a/icons/pda_icons/pda_medical.png b/icons/pda_icons/pda_medical.png new file mode 100644 index 00000000..448063ec Binary files /dev/null and b/icons/pda_icons/pda_medical.png differ diff --git a/icons/pda_icons/pda_menu.png b/icons/pda_icons/pda_menu.png new file mode 100644 index 00000000..abd6ccb2 Binary files /dev/null and b/icons/pda_icons/pda_menu.png differ diff --git a/icons/pda_icons/pda_mule.png b/icons/pda_icons/pda_mule.png new file mode 100644 index 00000000..b8c1b636 Binary files /dev/null and b/icons/pda_icons/pda_mule.png differ diff --git a/icons/pda_icons/pda_notes.png b/icons/pda_icons/pda_notes.png new file mode 100644 index 00000000..eb076d3c Binary files /dev/null and b/icons/pda_icons/pda_notes.png differ diff --git a/icons/pda_icons/pda_power.png b/icons/pda_icons/pda_power.png new file mode 100644 index 00000000..04175e7c Binary files /dev/null and b/icons/pda_icons/pda_power.png differ diff --git a/icons/pda_icons/pda_rdoor.png b/icons/pda_icons/pda_rdoor.png new file mode 100644 index 00000000..6eab5a88 Binary files /dev/null and b/icons/pda_icons/pda_rdoor.png differ diff --git a/icons/pda_icons/pda_reagent.png b/icons/pda_icons/pda_reagent.png new file mode 100644 index 00000000..b900af5a Binary files /dev/null and b/icons/pda_icons/pda_reagent.png differ diff --git a/icons/pda_icons/pda_refresh.png b/icons/pda_icons/pda_refresh.png new file mode 100644 index 00000000..08439c6b Binary files /dev/null and b/icons/pda_icons/pda_refresh.png differ diff --git a/icons/pda_icons/pda_scanner.png b/icons/pda_icons/pda_scanner.png new file mode 100644 index 00000000..eabdc511 Binary files /dev/null and b/icons/pda_icons/pda_scanner.png differ diff --git a/icons/pda_icons/pda_signaler.png b/icons/pda_icons/pda_signaler.png new file mode 100644 index 00000000..f71398f7 Binary files /dev/null and b/icons/pda_icons/pda_signaler.png differ diff --git a/icons/pda_icons/pda_status.png b/icons/pda_icons/pda_status.png new file mode 100644 index 00000000..fe955e66 Binary files /dev/null and b/icons/pda_icons/pda_status.png differ diff --git a/icons/pdrink.dmi b/icons/pdrink.dmi new file mode 100644 index 00000000..24dedabb Binary files /dev/null and b/icons/pdrink.dmi differ diff --git a/icons/policetape.dmi b/icons/policetape.dmi new file mode 100644 index 00000000..42095bee Binary files /dev/null and b/icons/policetape.dmi differ diff --git a/icons/reagentname_bg.png b/icons/reagentname_bg.png new file mode 100644 index 00000000..879179ed Binary files /dev/null and b/icons/reagentname_bg.png differ diff --git a/icons/ss13_32.png b/icons/ss13_32.png new file mode 100644 index 00000000..72bf4f0f Binary files /dev/null and b/icons/ss13_32.png differ diff --git a/icons/ss13_64.png b/icons/ss13_64.png new file mode 100644 index 00000000..103ff0b2 Binary files /dev/null and b/icons/ss13_64.png differ diff --git a/icons/turf/areas.dmi b/icons/turf/areas.dmi new file mode 100644 index 00000000..fd97e633 Binary files /dev/null and b/icons/turf/areas.dmi differ diff --git a/icons/turf/cliff.dmi b/icons/turf/cliff.dmi new file mode 100644 index 00000000..a54e1365 Binary files /dev/null and b/icons/turf/cliff.dmi differ diff --git a/icons/turf/desert.dmi b/icons/turf/desert.dmi new file mode 100644 index 00000000..e087b35a Binary files /dev/null and b/icons/turf/desert.dmi differ diff --git a/icons/turf/dirt.dmi b/icons/turf/dirt.dmi new file mode 100644 index 00000000..0378a515 Binary files /dev/null and b/icons/turf/dirt.dmi differ diff --git a/icons/turf/flooring/alium.dmi b/icons/turf/flooring/alium.dmi new file mode 100644 index 00000000..33665c8e Binary files /dev/null and b/icons/turf/flooring/alium.dmi differ diff --git a/icons/turf/flooring/asteroid.dmi b/icons/turf/flooring/asteroid.dmi new file mode 100644 index 00000000..eaba3e76 Binary files /dev/null and b/icons/turf/flooring/asteroid.dmi differ diff --git a/icons/turf/flooring/carpet.dmi b/icons/turf/flooring/carpet.dmi new file mode 100644 index 00000000..b5db684f Binary files /dev/null and b/icons/turf/flooring/carpet.dmi differ diff --git a/icons/turf/flooring/circuit.dmi b/icons/turf/flooring/circuit.dmi new file mode 100644 index 00000000..fa9f170b Binary files /dev/null and b/icons/turf/flooring/circuit.dmi differ diff --git a/icons/turf/flooring/cult.dmi b/icons/turf/flooring/cult.dmi new file mode 100644 index 00000000..df77cf22 Binary files /dev/null and b/icons/turf/flooring/cult.dmi differ diff --git a/icons/turf/flooring/damage.dmi b/icons/turf/flooring/damage.dmi new file mode 100644 index 00000000..e7af92ce Binary files /dev/null and b/icons/turf/flooring/damage.dmi differ diff --git a/icons/turf/flooring/decals.dmi b/icons/turf/flooring/decals.dmi new file mode 100644 index 00000000..f23a703e Binary files /dev/null and b/icons/turf/flooring/decals.dmi differ diff --git a/icons/turf/flooring/grass.dmi b/icons/turf/flooring/grass.dmi new file mode 100644 index 00000000..50a487f3 Binary files /dev/null and b/icons/turf/flooring/grass.dmi differ diff --git a/icons/turf/flooring/lava.dmi b/icons/turf/flooring/lava.dmi new file mode 100644 index 00000000..f509ea2e Binary files /dev/null and b/icons/turf/flooring/lava.dmi differ diff --git a/icons/turf/flooring/linoleum.dmi b/icons/turf/flooring/linoleum.dmi new file mode 100644 index 00000000..18ffaf31 Binary files /dev/null and b/icons/turf/flooring/linoleum.dmi differ diff --git a/icons/turf/flooring/misc.dmi b/icons/turf/flooring/misc.dmi new file mode 100644 index 00000000..783d6598 Binary files /dev/null and b/icons/turf/flooring/misc.dmi differ diff --git a/icons/turf/flooring/misc2.dmi b/icons/turf/flooring/misc2.dmi new file mode 100644 index 00000000..8f9a6c46 Binary files /dev/null and b/icons/turf/flooring/misc2.dmi differ diff --git a/icons/turf/flooring/plating.dmi b/icons/turf/flooring/plating.dmi new file mode 100644 index 00000000..bd228433 Binary files /dev/null and b/icons/turf/flooring/plating.dmi differ diff --git a/icons/turf/flooring/shadows.dmi b/icons/turf/flooring/shadows.dmi new file mode 100644 index 00000000..40876e85 Binary files /dev/null and b/icons/turf/flooring/shadows.dmi differ diff --git a/icons/turf/flooring/tiles.dmi b/icons/turf/flooring/tiles.dmi new file mode 100644 index 00000000..ae47a9d6 Binary files /dev/null and b/icons/turf/flooring/tiles.dmi differ diff --git a/icons/turf/flooring/wood.dmi b/icons/turf/flooring/wood.dmi new file mode 100644 index 00000000..e0a5326a Binary files /dev/null and b/icons/turf/flooring/wood.dmi differ diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi new file mode 100644 index 00000000..066436f6 Binary files /dev/null and b/icons/turf/floors.dmi differ diff --git a/icons/turf/jungle.dmi b/icons/turf/jungle.dmi new file mode 100644 index 00000000..1da97f19 Binary files /dev/null and b/icons/turf/jungle.dmi differ diff --git a/icons/turf/open_space.dmi b/icons/turf/open_space.dmi new file mode 100644 index 00000000..db25f2f3 Binary files /dev/null and b/icons/turf/open_space.dmi differ diff --git a/icons/turf/overlays.dmi b/icons/turf/overlays.dmi new file mode 100644 index 00000000..34819bdc Binary files /dev/null and b/icons/turf/overlays.dmi differ diff --git a/icons/turf/rockbox.dmi b/icons/turf/rockbox.dmi new file mode 100644 index 00000000..8821ad2b Binary files /dev/null and b/icons/turf/rockbox.dmi differ diff --git a/icons/turf/shuttle.dmi b/icons/turf/shuttle.dmi new file mode 100644 index 00000000..12b1b6d0 Binary files /dev/null and b/icons/turf/shuttle.dmi differ diff --git a/icons/turf/skybox.dmi b/icons/turf/skybox.dmi new file mode 100644 index 00000000..30049fa4 Binary files /dev/null and b/icons/turf/skybox.dmi differ diff --git a/icons/turf/skybox_rocks.dmi b/icons/turf/skybox_rocks.dmi new file mode 100644 index 00000000..b917bc9e Binary files /dev/null and b/icons/turf/skybox_rocks.dmi differ diff --git a/icons/turf/snow.dmi b/icons/turf/snow.dmi new file mode 100644 index 00000000..032ff29d Binary files /dev/null and b/icons/turf/snow.dmi differ diff --git a/icons/turf/space.dmi b/icons/turf/space.dmi new file mode 100644 index 00000000..e74b00a8 Binary files /dev/null and b/icons/turf/space.dmi differ diff --git a/icons/turf/space_dust.dmi b/icons/turf/space_dust.dmi new file mode 100644 index 00000000..8328b3db Binary files /dev/null and b/icons/turf/space_dust.dmi differ diff --git a/icons/turf/space_skybox_comp1.dmi b/icons/turf/space_skybox_comp1.dmi new file mode 100644 index 00000000..e93cc831 Binary files /dev/null and b/icons/turf/space_skybox_comp1.dmi differ diff --git a/icons/turf/space_skybox_comp2.dmi b/icons/turf/space_skybox_comp2.dmi new file mode 100644 index 00000000..0c9d95b6 Binary files /dev/null and b/icons/turf/space_skybox_comp2.dmi differ diff --git a/icons/turf/space_skybox_comp3.dmi b/icons/turf/space_skybox_comp3.dmi new file mode 100644 index 00000000..2dbbb39e Binary files /dev/null and b/icons/turf/space_skybox_comp3.dmi differ diff --git a/icons/turf/structures.dmi b/icons/turf/structures.dmi new file mode 100644 index 00000000..36da6f2e Binary files /dev/null and b/icons/turf/structures.dmi differ diff --git a/icons/turf/trenches_turfs.dmi b/icons/turf/trenches_turfs.dmi new file mode 100644 index 00000000..f7c4583c Binary files /dev/null and b/icons/turf/trenches_turfs.dmi differ diff --git a/icons/turf/wall.dmi b/icons/turf/wall.dmi new file mode 100644 index 00000000..e0a52729 Binary files /dev/null and b/icons/turf/wall.dmi differ diff --git a/icons/turf/wall_masks.dmi b/icons/turf/wall_masks.dmi new file mode 100644 index 00000000..b308f65f Binary files /dev/null and b/icons/turf/wall_masks.dmi differ diff --git a/icons/turf/walls.dmi b/icons/turf/walls.dmi new file mode 100644 index 00000000..17b670f8 Binary files /dev/null and b/icons/turf/walls.dmi differ diff --git a/icons/vending_icons/vendingslot_bg.png b/icons/vending_icons/vendingslot_bg.png new file mode 100644 index 00000000..6fb6fdcf Binary files /dev/null and b/icons/vending_icons/vendingslot_bg.png differ diff --git a/icons/warfare.png b/icons/warfare.png new file mode 100644 index 00000000..7e15b463 Binary files /dev/null and b/icons/warfare.png differ diff --git a/ingame_manuals/README.txt b/ingame_manuals/README.txt new file mode 100644 index 00000000..08115306 --- /dev/null +++ b/ingame_manuals/README.txt @@ -0,0 +1,3 @@ +INGAME MANUALS + +Ingame manuals are simple HTML files with basic information. They are linked to specific items/commands, such as the AI's display help command, or engine setup guide. Point of these files is to allow creation of basic guides for players which don't want to use wiki. \ No newline at end of file diff --git a/ingame_manuals/malf_ai.html b/ingame_manuals/malf_ai.html new file mode 100644 index 00000000..65424f24 --- /dev/null +++ b/ingame_manuals/malf_ai.html @@ -0,0 +1,22 @@ +

            Malfunctioning AI guide


            + +This guide contains most important OOC information for malfunctioning AIs.
            + +

            Goal


            +As malfunctioning AI, your primary goal is to overtake station's systems. To do this, use software "Basic Encryption Hack" on APCs (right click on APC and select Basic Encryption Hack). Please note that hacked APCs have distinctive blue error screen, that tends to attract attention. Rememember that malfunctioning AI is antagonist, so read server rules for antagonists. While hacking APCs is your official goal, feel free to create custom goal, as long as it is fun for everyone.
            + +

            Hardware


            +As malfunctioning AI, you may select one hardware piece to help you. Remember that once you select hardware piece, you cannot select another one, so choose wisely! Hardware may be selected by clicking "Select Hardware" button in Hardware tab. Following is list of possible hardware pieces:
            +APU Generator - Auxiliary Power Unit which allows you to operate even without external power. However, running on APU will stop your CPU time generation, and temporarily disable most of your abilities. APU is also somewhat vulnerable to physical damage, and will fail if your core hardware integrity drops below 50%.
            +Turrets Focus Enhancer - Removes safeties on installed turrets, boosting their rate of fire, health and enabling nano-regeneration module. This however increases power usage considerably, espicially when regenerating damage.
            +Secondary Processor Unit - Simple upgrade that increases your CPU time generation by 50%. Useful if you need to speed up your research.
            +Secondary Memory Bank - Doubles amount of maximal CPU time you may store. This is useful if you need to use lots of abilities in short amount of time.
            +Self-Destruct Explosives - Large blocks of C4 are attached to your physical core. This C4 has 15 second timer, and may be activated by special button that appears in your Hardware tab. This self-destruct will remain active, even if you are destroyed. If timer reaches 0 your core explodes in strong explosion. Obviously, this destroys you, as well as anyone nearby.
            + +

            Software


            +Software are abilities that have to be unlocked via research menu (Hardware tab). Unlocked abilities appear in Software tab. Sometimes, abilities won't appear in this tab after being researched. This can be fixed by relogging or using "ai-core" command. Abilities are tiered, T1 being the weakest ones, while T4 are strongest ones. To reach higher tier you have to research abilities in lower tier. We currently have 12 abilities, in 3 research trees:
            +Networking - Hacking-oriented abilities. T1 ability is Basic Encryption Hack, which allows you to hack more APCs. Higher tiers allow faking centcom messages, and even setting alert level. T4 ability is System Override, that rapidly hacks remaining APCs and gives you access to station self destruct sequence.
            +Interdiction - Sabotage-oriented abilities. T1 ability allows you to recall emergency shuttle. Higher level abilities allow you to unlock cyborgs even without access to robotics console, and T4 ability allows you to hack other AIs to slave them under your control.
            +Manipulation - Physical-oriented abilities. T1 ability allows you to break few lights, and rarely even APCs. T2 ability allows you to apply upgrade of your choice to camera, or reactivate broken camera. T3 ability allows you to create weak forcefield, that holds air, but won't last for long. And T4 ability allows you to overload machines, detonating them in weak explosion.
            +

            End


            +If you still have some questions, either check the wiki, ask on IRC, or adminhelp and ask your friendly administration staff. \ No newline at end of file diff --git a/install-byond.sh b/install-byond.sh new file mode 100644 index 00000000..3b0170c1 --- /dev/null +++ b/install-byond.sh @@ -0,0 +1,15 @@ +#!/bin/sh +set -e +if [ -f "$HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}/byond/bin/DreamMaker" ]; +then + echo "Using cached directory." +else + echo "Setting up BYOND." + mkdir -p "$HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}" + cd "$HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}" + echo "Installing DreamMaker to $PWD" + curl "http://www.byond.com/download/build/${BYOND_MAJOR}/${BYOND_MAJOR}.${BYOND_MINOR}_byond_linux.zip" -o byond.zip + unzip -o byond.zip + cd byond + make here +fi diff --git a/interface/interface.dm b/interface/interface.dm new file mode 100644 index 00000000..a6d1ded5 --- /dev/null +++ b/interface/interface.dm @@ -0,0 +1,198 @@ +//Please use mob or src (not usr) in these procs. This way they can be called in the same fashion as procs. +/client/verb/wiki() + set name = "Wiki" + set desc = "Visit the wiki." + set hidden = 1 + if( config.wikiurl ) + if(alert("This will open the wiki in your browser. Are you sure?",,"Yes","No")=="No") + return + src << link(config.wikiurl) + else + to_chat(src, "The wiki URL is not set in the server configuration.") + return + +/client/verb/forum() + set name = "Forum" + set desc = "Visit the forum." + set hidden = 1 + if( config.forumurl ) + if(alert("This will open the forum in your browser. Are you sure?",,"Yes","No")=="No") + return + src << link(config.forumurl) + else + to_chat(src, "The forum URL is not set in the server configuration.") + return + +#define RULES_FILE "config/rules.html" +/client/verb/rules() + set name = "Rules" + set category = "OOC" + set desc = "Show Server Rules." + src << browse(file(RULES_FILE), "window=rules;size=480x320") +#undef RULES_FILE + +#define LORE_FILE "config/lore.html" +/client/verb/lore_splash() + set name = "Lore" + set desc = "Links to the beginner Lore wiki." + set hidden = 1 + show_browser(src, file(LORE_FILE), "window=lore;size=480x320") +#undef LORE_FILE + +/client/verb/hotkeys_help() + set name = "View Controls" + set category = "OOC" + + var/dat + + var/admin = {" +

            Admin:

            +
            F5 = Aghost (admin-ghost) +
            F6 = player-panel-new +
            F7 = admin-pm +
            F8 = Invisimin +
            "} + + var/hotkey_mode = {" +

            Hotkey-Mode: (hotkey-mode must be on)

            +
            TAB = toggle hotkey-mode +
            a = left +
            s = down +
            d = right +
            w = up +
            pgup = move-upwards +
            pgdown = move-down +
            q = drop +
            e = equip +
            r = throw +
            t = say +
            c = toggle combat mode +
            o = OOC +
            5 = emote +
            x = swap-hand +
            z = activate held object (or y) +
            f = toggle fixeye +
            shift+f = look up +
            shift+x = wield weapon +
            ctrl+z = toggle safety/unjam gun +
            1 = help-intent +
            2 = disarm-intent +
            3 = grab-intent +
            4 = harm-intent +
            space OR v = crouch +
            "} + + var/other = {" +

            Any-Mode: (hotkey doesn't need to be on)

            +
            Ctrl+a = left +
            Ctrl+s = down +
            Ctrl+d = right +
            Ctrl+w = up +
            Ctrl+q = drop +
            Ctrl+e = equip +
            Ctrl+r = throw +
            Ctrl+x or Middle Mouse = swap-hand +
            Ctrl+z = activate held object (or Ctrl+y) +
            Ctrl+f = cycle-intents-left +
            Ctrl+g = cycle-intents-right +
            Ctrl+1 = help-intent +
            Ctrl+2 = disarm-intent +
            Ctrl+3 = grab-intent +
            Ctrl+4 = harm-intent +
            F1 = adminhelp +
            F2 = ooc +
            F3 = say +
            F4 = emote +
            DEL = pull +
            INS = cycle-intents-right +
            HOME = drop +
            PGUP or Middle Mouse = swap-hand +
            PGDN = activate held object +
            END = throw +
            Ctrl + Click = drag +
            Shift + Click = examine +
            Alt + Click = show entities on turf +
            Ctrl + Alt + Click = interact with certain items +
            "} + + var/special_controls = {" +

            Speacial Controls:

            +
            look up = RMB+Fixeye button OR Shift+F +
            look into distance = ALT+RMB +
            give = RMB+help intent +
            wave friendly = RMB+help intent at a distance +
            threaten = RMB+harm intent at a distance +
            toggle fullscreen = CTRL+ENTER +
            jump = select "jump" on the UI and middle click +
            kick = select "kick" on the UI and middle click +
            "} + + var/gun_controls = {" +

            Weapon controls:

            +
            toggle safety = RMB on gun OR shift+z +
            do special attack = RMB + harm intent + combat mode +
            unload gun = click drag into empty hand +
            clean gun = ALT + Click on gun +
            unjam gun = RMB on gun when it's jammed +
            "} + + var/robot_hotkey_mode = {" +

            Hotkey-Mode: (hotkey-mode must be on)

            +
            TAB = toggle hotkey-mode +
            a = left +
            s = down +
            d = right +
            w = up +
            q = unequip active module +
            t = say +
            x = cycle active modules +
            z = activate held object (or y) +
            f = cycle-intents-left +
            g = cycle-intents-right +
            1 = activate module 1 +
            2 = activate module 2 +
            3 = activate module 3 +
            4 = toggle intents +
            5 = emote +
            "} + + var/robot_other = {" +

            Any-Mode: (hotkey doesn't need to be on)

            +
            Ctrl+a = left +
            Ctrl+s = down +
            Ctrl+d = right +
            Ctrl+w = up +
            Ctrl+q = unequip active module +
            Ctrl+x = cycle active modules +
            Ctrl+z = activate held object (or Ctrl+y) +
            Ctrl+f = cycle-intents-left +
            Ctrl+g = cycle-intents-right +
            Ctrl+1 = activate module 1 +
            Ctrl+2 = activate module 2 +
            Ctrl+3 = activate module 3 +
            Ctrl+4 = toggle intents +
            F1 = adminhelp +
            F2 = ooc +
            F3 = say +
            F4 = emote +
            DEL = pull +
            INS = toggle intents +
            PGUP = cycle active modules +
            PGDN = activate held object +
            Ctrl + Click = drag or bolt doors +
            Shift + Click = examine or open doors +
            Alt + Click = show entities on turf +
            Ctrl + Alt + Click = electrify doors +
            "} + + if(isrobot(src.mob)) + dat += robot_hotkey_mode + dat += robot_other + else + dat += hotkey_mode + dat += other + dat += special_controls + dat += gun_controls + if(holder) + dat += admin + src << browse(dat, "window=controls") diff --git a/interface/skin.dmf b/interface/skin.dmf new file mode 100644 index 00000000..068d5154 --- /dev/null +++ b/interface/skin.dmf @@ -0,0 +1,1292 @@ +macro "borghotkeymode" + elem + name = "Tab" + command = ".winset \"mainwindow.macro=borgmacro hotkey_toggle.is-checked=false input.focus=true input.background-color=#D3B5B5\"" + elem + name = "CTRL+Tab" + command = "status_bar_toggle" + elem + name = "Center+REP" + command = ".center" + elem + name = "CTRL+Return" + command = ".fullscreen_toggle" + elem + name = "Northeast" + command = ".northeast" + elem + name = "Southeast" + command = ".southeast" + elem + name = "Southwest" + command = ".southwest" + elem + name = "Northwest" + command = ".northwest" + elem + name = "ALT+West" + command = "westfaceperm" + elem + name = "CTRL+West" + command = "westface" + elem + name = "West+REP" + command = ".west" + elem + name = "ALT+North" + command = "northfaceperm" + elem + name = "CTRL+North" + command = "northface" + elem + name = "North+REP" + command = ".north" + elem + name = "ALT+East" + command = "eastfaceperm" + elem + name = "CTRL+East" + command = "eastface" + elem + name = "East+REP" + command = ".east" + elem + name = "ALT+South" + command = "southfaceperm" + elem + name = "CTRL+South" + command = "southface" + elem + name = "South+REP" + command = ".south" + elem + name = "Insert" + command = "a-intent right" + elem + name = "Delete" + command = "delete-key-pressed" + elem + name = "1" + command = "toggle-module 1" + elem + name = "CTRL+1" + command = "toggle-module 1" + elem + name = "2" + command = "toggle-module 2" + elem + name = "CTRL+2" + command = "toggle-module 2" + elem + name = "3" + command = "toggle-module 3" + elem + name = "CTRL+3" + command = "toggle-module 3" + elem + name = "4" + command = "a-intent left" + elem + name = "CTRL+4" + command = "a-intent left" + elem + name = "5" + command = ".me" + elem + name = "A+REP" + command = ".west" + elem + name = "CTRL+A+REP" + command = ".west" + elem + name = "D+REP" + command = ".east" + elem + name = "CTRL+D+REP" + command = ".east" + elem + name = "F" + command = "a-intent left" + elem + name = "CTRL+F" + command = "a-intent left" + elem + name = "G" + command = "a-intent right" + elem + name = "CTRL+G" + command = "a-intent right" + elem + name = "J" + command = "toggle-gun-mode" + elem + name = "CTRL+J" + command = "toggle-gun-mode" + elem + name = "Q" + command = "unequip-module" + elem + name = "CTRL+Q" + command = "unequip-module" + elem + name = "R" + command = ".southwest" + elem + name = "CTRL+R" + command = ".southwest" + elem + name = "S" + command = ".movedown" + elem + name = "S+REP" + command = ".movedown" + elem + name = "CTRL+S+REP" + command = ".movedown" + elem + name = "T" + command = ".say" + elem "w_key" + name = "W+REP" + command = ".north" + elem + name = "CTRL+W+REP" + command = ".north" + elem + name = "X" + command = ".northeast" + elem + name = "CTRL+X" + command = ".northeast" + elem + name = "Y" + command = "Activate-Held-Object" + elem + name = "CTRL+Y" + command = "Activate-Held-Object" + elem + name = "Z" + command = "Activate-Held-Object" + elem + name = "CTRL+Z" + command = "Activate-Held-Object" + elem + name = "F1" + command = "adminhelp" + elem + name = "CTRL+SHIFT+F1+REP" + command = ".options" + elem + name = "F2" + command = "ooc" + elem + name = "F2+REP" + command = ".screenshot auto" + elem + name = "SHIFT+F2+REP" + command = ".screenshot" + elem + name = "F3" + command = ".say" + elem + name = "F4" + command = ".me" + elem + name = "F5" + command = "asay" + elem + name = "F6" + command = "Player-Panel-New" + elem + name = "F7" + command = "Admin-PM" + elem + name = "F8" + command = "Invisimin" + +macro "macro" + elem + name = "Tab" + command = ".winset \"mainwindow.macro=hotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true\"" + elem + name = "CTRL+Tab" + command = "status_bar_toggle" + elem + name = "Center+REP" + command = ".center" + elem + name = "CTRL+Return" + command = ".fullscreen_toggle" + elem + name = "Northeast" + command = ".northeast" + elem + name = "Southeast" + command = ".southeast" + elem + name = "Southwest" + command = ".southwest" + elem + name = "Northwest" + command = ".northwest" + elem + name = "WEST+REP" + command = ".moveleft" + elem + name = "NORTH+REP" + command = ".moveup" + elem + name = "EAST+REP" + command = ".moveright" + elem + name = "SOUTH+REP" + command = ".movedown" + elem + name = "CTRL+West" + command = "westface" + elem + name = "CTRL+North" + command = "northface" + elem + name = "CTRL+East" + command = "eastface" + elem + name = "CTRL+South" + command = "southface" + elem + name = "Insert" + command = "a-intent right" + elem + name = "Delete" + command = "delete-key-pressed" + elem + name = "CTRL+1" + command = "a-intent help" + elem + name = "CTRL+2" + command = "a-intent disarm" + elem + name = "CTRL+3" + command = "a-intent grab" + elem + name = "CTRL+4" + command = "a-intent harm" + elem + name = "CTRL+A+REP" + command = ".west" + elem + name = "CTRL+D+REP" + command = ".east" + elem + name = "CTRL+E" + command = "quick-equip" + elem + name = "CTRL+F" + command = "a-intent left" + elem + name = "CTRL+G" + command = "a-intent right" + elem + name = "CTRL+SHIFT+G" + command = ".configure graphics-hwmode on" + elem + name = "CTRL+Q" + command = ".northwest" + elem + name = "CTRL+R" + command = ".southwest" + elem + name = "CTRL+S+REP" + command = ".south" + elem + name = "CTRL+W+REP" + command = ".north" + elem + name = "CTRL+X" + command = ".northeast" + elem + name = "CTRL+Y" + command = "Activate-Held-Object" + elem + name = "CTRL+Z" + command = "Activate-Held-Object" + elem + name = "F1" + command = "adminhelp" + elem + name = "CTRL+SHIFT+F1+REP" + command = ".options" + elem + name = "F2" + command = "ooc" + elem + name = "F2+REP" + command = ".screenshot auto" + elem + name = "SHIFT+F2+REP" + command = ".screenshot" + elem + name = "F3" + command = ".say" + elem + name = "F4" + command = ".me" + elem + name = "F5" + command = "asay" + elem + name = "F6" + command = "Player-Panel-New" + elem + name = "F7" + command = "Admin-PM" + elem + name = "F8" + command = "Invisimin" + +macro "hotkeymode" + elem + name = "Tab" + command = ".winset \"mainwindow.macro=macro hotkey_toggle.is-checked=false input.focus=true\"" + elem + name = "CTRL+Tab" + command = "status_bar_toggle" + elem + name = "Center+REP" + command = ".center" + elem + name = "CTRL+Return" + command = ".fullscreen_toggle" + elem + name = "Northeast" + command = "Move-Upwards" + elem + name = "Southeast" + command = "Move-Down" + elem + name = "Southwest" + command = ".southwest" + elem + name = "Northwest" + command = ".northwest" + elem + name = "WEST+REP" + command = ".moveleft" + elem + name = "NORTH+REP" + command = ".moveup" + elem + name = "EAST+REP" + command = ".moveright" + elem + name = "SOUTH+REP" + command = ".movedown" + elem + name = "CTRL+West" + command = "westface" + elem + name = "CTRL+North" + command = "northface" + elem + name = "CTRL+East" + command = "eastface" + elem + name = "CTRL+South" + command = "southface" + elem + name = "Insert" + command = "a-intent right" + elem + name = "Delete" + command = "delete-key-pressed" + elem + name = "1" + command = "a-intent help" + elem + name = "CTRL+1" + command = "a-intent help" + elem + name = "2" + command = "a-intent disarm" + elem + name = "CTRL+2" + command = "a-intent disarm" + elem + name = "3" + command = "a-intent grab" + elem + name = "CTRL+3" + command = "a-intent grab" + elem + name = "4" + command = "a-intent harm" + elem + name = "CTRL+4" + command = "a-intent harm" + elem + name = "5" + command = ".me" + elem + name = "NUMPAD8" + command = "body-toggle-head" + elem + name = "NUMPAD5" + command = "body-chest" + elem + name = "NUMPAD4" + command = "body-r-arm" + elem + name = "NUMPAD6" + command = "body-l-arm" + elem + name = "NUMPAD2" + command = "body-groin" + elem + name = "NUMPAD1" + command = "body-r-leg" + elem + name = "NUMPAD3" + command = "body-l-leg" + elem + name = "A+REP" + command = ".moveleft" + elem + name = "CTRL+A+REP" + command = ".west" + elem + name = "D+REP" + command = ".moveright" + elem + name = "CTRL+D+REP" + command = ".east" + elem + name = "E" + command = "quick-equip" + elem + name = "CTRL+E" + command = "quick-equip" + elem + name = "F" + command = "set-fixeye" + elem + name = "SHIFT+F" + command = "look-up" + elem + name = "CTRL+F" + command = "a-intent left" + elem + name = "G" + command = "mob-rest" + elem + name = "CTRL+G" + command = "a-intent right" + elem + name = "H" + command = "holster" + elem + name = "CTRL+H" + command = "holster" + elem + name = "Q" + command = ".northwest" + elem + name = "CTRL+Q" + command = ".northwest" + elem + name = "R" + command = ".southwest" + elem + name = "CTRL+R" + command = ".southwest" + elem + name = "S+REP" + command = ".movedown" + elem + name = "CTRL+S+REP" + command = ".south" + elem + name = "T" + command = ".say" + elem + name = "W+REP" + command = ".moveup" + elem + name = "CTRL+W+REP" + command = ".north" + elem + name = "X" + command = ".northeast" + elem + name = "CTRL+X" + command = ".northeast" + elem + name = "SHIFT+X" + command = ".wield" + elem + name = "SHIFT+Z" + command = ".toggle_safety" + elem + name = "Space" + command = ".toggle_crouching" + elem + name = "V" + command = ".toggle_crouching" + elem + name = "Y" + command = "Activate-Held-Object" + elem + name = "CTRL+Y" + command = "Activate-Held-Object" + elem + name = "Z" + command = "Activate-Held-Object" + elem + name = "CTRL+Z" + command = "Activate-Held-Object" + elem + name = "F1" + command = "adminhelp" + elem + name = "CTRL+SHIFT+F1+REP" + command = ".options" + elem + name = "O" + command = "ooc" + elem + name = "L" + command = "looc" + elem + name = "F2+REP" + command = ".screenshot auto" + elem + name = "SHIFT+F2+REP" + command = ".screenshot" + elem + name = "F3" + command = ".say" + elem + name = "F4" + command = ".me" + elem + name = "F5" + command = "asay" + elem + name = "F6" + command = "Player-Panel-New" + elem + name = "F7" + command = "Admin-PM" + elem + name = "F8" + command = "Invisimin" + elem + name = "C" + command = "CombatModeToggle" + elem + name = "CTRL+C" + command = "CombatModeToggle" + +macro "borgmacro" + elem + name = "Tab" + command = ".winset \"mainwindow.macro=borghotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true input.background-color=#F0F0F0\"" + elem + name = "CTRL+Tab" + command = "status_bar_toggle" + elem + name = "Center+REP" + command = ".center" + elem + name = "CTRL+Return" + command = ".fullscreen_toggle" + elem + name = "Northeast" + command = ".northeast" + elem + name = "Southeast" + command = ".southeast" + elem + name = "Southwest" + command = ".southwest" + elem + name = "Northwest" + command = ".northwest" + elem + name = "ALT+West" + command = "westfaceperm" + elem + name = "CTRL+West" + command = "westface" + elem + name = "West+REP" + command = ".west" + elem + name = "ALT+North" + command = "northfaceperm" + elem + name = "CTRL+North" + command = "northface" + elem + name = "North+REP" + command = ".north" + elem + name = "ALT+East" + command = "eastfaceperm" + elem + name = "CTRL+East" + command = "eastface" + elem + name = "East+REP" + command = ".east" + elem + name = "ALT+South" + command = "southfaceperm" + elem + name = "CTRL+South" + command = "southface" + elem + name = "South+REP" + command = ".south" + elem + name = "Insert" + command = "a-intent right" + elem + name = "Delete" + command = "delete-key-pressed" + elem + name = "CTRL+1" + command = "toggle-module 1" + elem + name = "CTRL+2" + command = "toggle-module 2" + elem + name = "CTRL+3" + command = "toggle-module 3" + elem + name = "CTRL+4" + command = "a-intent left" + elem + name = "CTRL+A+REP" + command = ".west" + elem + name = "CTRL+D+REP" + command = ".east" + elem + name = "CTRL+F" + command = "a-intent left" + elem + name = "CTRL+G" + command = "a-intent right" + elem + name = "CTRL+Q" + command = ".northwest" + elem + name = "CTRL+R" + command = ".southwest" + elem + name = "CTRL+S+REP" + command = ".south" + elem + name = "CTRL+W+REP" + command = ".north" + elem + name = "CTRL+X" + command = ".northeast" + elem + name = "CTRL+Y" + command = "Activate-Held-Object" + elem + name = "CTRL+Z" + command = "Activate-Held-Object" + elem + name = "F1" + command = "adminhelp" + elem + name = "CTRL+SHIFT+F1+REP" + command = ".options" + elem + name = "F2" + command = "ooc" + elem + name = "F2+REP" + command = ".screenshot auto" + elem + name = "SHIFT+F2+REP" + command = ".screenshot" + elem + name = "F3" + command = ".say" + elem + name = "F4" + command = ".me" + elem + name = "F5" + command = "asay" + elem + name = "F6" + command = "Player-Panel-New" + elem + name = "F7" + command = "Admin-PM" + elem + name = "F8" + command = "Invisimin" + + +menu "menu" + elem + name = "&File" + command = "" + saved-params = "is-checked" + elem + name = "&Quick screenshot\tF2" + command = ".screenshot auto" + category = "&File" + saved-params = "is-checked" + elem + name = "&Save screenshot as...\tShift+F2" + command = ".screenshot" + category = "&File" + saved-params = "is-checked" + elem + name = "" + command = "" + category = "&File" + saved-params = "is-checked" + elem + name = "&Reconnect" + command = ".reconnect" + category = "&File" + saved-params = "is-checked" + elem + name = "&Quit" + command = ".quit" + category = "&File" + saved-params = "is-checked" + elem + name = "&Icons" + command = "" + saved-params = "is-checked" + elem "stretch" + name = "&Stretch to fit" + command = ".winset \"mapwindow.map.icon-size=0\"" + category = "&Icons" + is-checked = true + can-check = true + group = "size" + saved-params = "is-checked" + elem "icon64" + name = "&64x64" + command = ".winset \"mapwindow.map.icon-size=64\"" + category = "&Icons" + can-check = true + group = "size" + saved-params = "is-checked" + elem "icon48" + name = "&48x48" + command = ".winset \"mapwindow.map.icon-size=48\"" + category = "&Icons" + can-check = true + group = "size" + saved-params = "is-checked" + elem "icon32" + name = "&32x32" + command = ".winset \"mapwindow.map.icon-size=32\"" + category = "&Icons" + can-check = true + group = "size" + saved-params = "is-checked" + elem + name = "" + command = "" + category = "&Icons" + saved-params = "is-checked" + elem "textmode" + name = "&Text" + command = ".winset \"menu.textmode.is-checked=true?mapwindow.map.text-mode=true:mapwindow.map.text-mode=false\"" + category = "&Icons" + can-check = true + saved-params = "is-checked" + elem + name = "Scaling" + command = "" + saved-params = "is-checked" + elem "NN" + name = "Nearest Neighbor" + command = ".winset\"mapwindow.map.zoom-mode=distort\"" + category = "Scaling" + can-check = true + group = "scaling" + saved-params = "is-checked" + elem "PS" + name = "Point Sampling" + command = ".winset\"mapwindow.map.zoom-mode=normal\"" + category = "Scaling" + is-checked = true + can-check = true + group = "scaling" + saved-params = "is-checked" + elem "BL" + name = "Bilinear" + command = ".winset\"mapwindow.map.zoom-mode=blur\"" + category = "Scaling" + can-check = true + group = "scaling" + saved-params = "is-checked" + elem + name = "&Help" + command = "" + saved-params = "is-checked" + elem + name = "&Admin help\tF1" + command = "adminhelp" + category = "&Help" + saved-params = "is-checked" + elem + name = "&Hotkeys" + command = "hotkeys-help" + category = "&Help" + saved-params = "is-checked" + + +window "Telecomms IDE" + elem "Telecomms IDE" + type = MAIN + pos = 281,0 + size = 569x582 + anchor1 = none + anchor2 = none + background-color = #ffffff + is-visible = false + saved-params = "pos;size;is-minimized;is-maximized" + title = "TCS IDE" + statusbar = false + on-close = "exittcs" + elem "button5" + type = BUTTON + pos = 209,464 + size = 70x20 + anchor1 = 37,80 + anchor2 = 49,83 + saved-params = "is-checked" + text = "Clear Memory" + command = "tcsclearmem" + elem "button4" + type = BUTTON + pos = 157,464 + size = 52x20 + anchor1 = 28,80 + anchor2 = 37,83 + saved-params = "is-checked" + text = "Revert" + command = "tcsrevert" + elem "button3" + type = BUTTON + pos = 105,464 + size = 52x20 + anchor1 = 18,80 + anchor2 = 28,83 + saved-params = "is-checked" + text = "Execute" + command = "tcsrun" + elem "tcserror" + type = OUTPUT + pos = 0,488 + size = 566x94 + anchor1 = 0,84 + anchor2 = 99,100 + font-family = "sans-serif" + font-size = 9 + saved-params = "max-lines" + elem "button2" + type = BUTTON + pos = 53,464 + size = 52x20 + anchor1 = 9,80 + anchor2 = 18,83 + saved-params = "is-checked" + text = "Compile" + command = "tcscompile" + elem "button1" + type = BUTTON + pos = 0,464 + size = 53x20 + anchor1 = 0,80 + anchor2 = 9,83 + saved-params = "is-checked" + text = "Apply" + command = "tcssave" + elem "tcscode" + type = INPUT + pos = 0,0 + size = 569x464 + anchor1 = 0,0 + anchor2 = 100,80 + font-family = "Courier" + font-size = 10 + saved-params = "" + command = "cancel" + multi-line = true + no-command = true + +window "chemdispenser" + elem "chemdispenser" + type = MAIN + pos = 281,0 + size = 340x480 + anchor1 = none + anchor2 = none + is-visible = false + saved-params = "pos;size;is-minimized;is-maximized" + title = "Chem Dispenser" + statusbar = false + elem "energy" + type = LABEL + pos = 8,24 + size = 56x16 + anchor1 = none + anchor2 = none + saved-params = "" + text = "Energy: 25" + elem "eject" + type = BUTTON + pos = 264,4 + size = 72x20 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "[Insert beaker]" + command = "skincmd \"chemdispenser;eject\"" + elem "amountc" + type = BUTTON + pos = 208,4 + size = 48x20 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "[Other]" + command = "skincmd \"chemdispenser;amountc\"" + elem "amount3" + type = BUTTON + pos = 176,4 + size = 24x20 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "[30]" + command = "skincmd \"chemdispenser;amount30\"" + elem "amount2" + type = BUTTON + pos = 144,4 + size = 24x20 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "[20]" + command = "skincmd \"chemdispenser;amount20\"" + elem "amount1" + type = BUTTON + pos = 112,4 + size = 24x20 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "[10]" + command = "skincmd \"chemdispenser;amount10\"" + elem "amount" + type = LABEL + pos = 4,4 + size = 100x20 + anchor1 = none + anchor2 = none + font-size = 12 + saved-params = "" + text = "Amount: 30" + elem "child1" + type = CHILD + pos = 0,40 + size = 340x440 + anchor1 = none + anchor2 = none + saved-params = "splitter" + left = "chemdispenser_reagents" + is-vert = false + +window "chemdispenser_reagents" + elem "chemdispenser_reagents" + type = MAIN + pos = 281,0 + size = 340x448 + anchor1 = none + anchor2 = none + saved-params = "pos;size;is-minimized;is-maximized" + titlebar = false + statusbar = false + can-close = false + can-minimize = false + can-resize = false + is-pane = true + can-scroll = vertical + elem "template_dispense" + type = BUTTON + pos = 256,8 + size = 64x32 + anchor1 = none + anchor2 = none + is-visible = false + saved-params = "is-checked" + text = "Dispense" + image = 'icons\\dispensebutton_bg.png' + command = "" + is-flat = true + elem "template_name" + type = LABEL + pos = 18,8 + size = 230x32 + anchor1 = none + anchor2 = none + font-size = 15 + is-visible = false + saved-params = "" + text = "Chloral Hydrate" + image = 'icons\\reagentname_bg.png' + image-mode = stretch + +window "mainwindow" + elem "mainwindow" + type = MAIN + pos = 281,0 + size = 640x440 + anchor1 = none + anchor2 = none + background-color = #000000 + is-default = true + saved-params = "pos;size;is-minimized;is-maximized" + is-maximized = true + icon = 'icons\\mound.png' + macro = "macro" + menu = "menu" + statusbar = false + elem "mainvsplit" + type = CHILD + pos = 0,0 + size = 640x440 + anchor1 = 0,0 + anchor2 = 100,100 + background-color = #353535 + saved-params = "splitter" + right = "rpane" + is-vert = true + splitter = 75 + +window "mapwindow" + elem "mapwindow" + type = MAIN + pos = 281,0 + size = 640x480 + anchor1 = none + anchor2 = none + background-color = #000000 + saved-params = "pos;size;is-minimized;is-maximized" + titlebar = false + statusbar = false + can-close = false + can-minimize = false + can-resize = false + is-pane = true + elem "map" + type = MAP + pos = 0,0 + size = 640x480 + anchor1 = 0,0 + anchor2 = 100,100 + font-family = "Arial Rounded MT Bold,Arial Black,Arial,sans-serif" + font-size = 7 + is-default = true + saved-params = "icon-size" + on-show = ".winset\"mainwindow.mainvsplit.left=mapwindow\"" + on-hide = ".winset\"mainwindow.mainvsplit.left=\"" + +window "outputwindow" + elem "outputwindow" + type = MAIN + pos = 281,0 + size = 640x480 + anchor1 = none + anchor2 = none + background-color = none + saved-params = "pos;size;is-minimized;is-maximized" + is-pane = true + elem "browseroutput" + type = BROWSER + pos = 0,0 + size = 640x456 + anchor1 = 0,0 + anchor2 = 100,100 + background-color = #ffffff + is-visible = false + is-disabled = true + saved-params = "" + auto-format = false + elem "input" + type = INPUT + pos = 0,456 + size = 640x24 + anchor1 = 0,100 + anchor2 = 100,100 + font-size = 12 + text-color = #d1d1d1 + background-color = #0c0c0c + is-default = true + border = sunken + saved-params = "" + command = "Say \"" +window "rpane" + elem "rpane" + type = MAIN + pos = 281,0 + size = 320x458 + anchor1 = none + anchor2 = none + background-color = #202020 + saved-params = "pos;size;is-minimized;is-maximized" + titlebar = false + statusbar = false + can-close = false + can-minimize = false + can-resize = false + is-pane = true + elem "name" + type = LABEL + pos = 0,9 + size = 320x20 + anchor1 = 0,0 + anchor2 = 100,0 + font-family = "monospace" + font-size = 3 + font-style = "bold" + text-color = #ffffff + background-color = #202020 + saved-params = "" + text = "" + elem "rpanewindow" + type = CHILD + pos = 0,40 + size = 320x418 + anchor1 = 0,0 + anchor2 = 100,100 + background-color = #202020 + saved-params = "splitter" + right = "outputwindow" + is-vert = false + +window "browserwindow" + elem "browserwindow" + type = MAIN + pos = 281,0 + size = 640x456 + anchor1 = none + anchor2 = none + background-color = none + saved-params = "pos;size;is-minimized;is-maximized" + title = "Browser" + titlebar = false + statusbar = false + can-close = false + can-minimize = false + can-resize = false + is-pane = true + elem "browser" + type = BROWSER + pos = 0,0 + size = 638x431 + anchor1 = 0,0 + anchor2 = 100,100 + background-color = #292929 + is-default = true + saved-params = "" + on-show = ".winset\"rpane.infob.is-visible=true?rpane.infob.pos=130,0;rpane.textb.is-visible=true;rpane.browseb.is-visible=true;rpane.browseb.is-checked=true;rpane.rpanewindow.pos=0,30;rpane.rpanewindow.size=0x0;rpane.rpanewindow.left=browserwindow\"" + on-hide = ".winset\"rpane.infob.is-visible=true?rpane.infob.is-checked=true rpane.infob.pos=65,0 rpane.rpanewindow.left=infowindow:rpane.rpanewindow.left=textwindow rpane.textb.is-visible=true rpane.rpanewindow.pos=0,30 rpane.rpanewindow.size=0x0\"" + +window "infowindow" + elem "infowindow" + type = MAIN + pos = 281,0 + size = 640x480 + anchor1 = none + anchor2 = none + background-color = #000000 + saved-params = "pos;size;is-minimized;is-maximized" + title = "Info" + titlebar = false + statusbar = false + can-close = false + can-minimize = false + can-resize = false + is-pane = true + elem "info" + type = INFO + pos = 0,0 + size = 638x480 + anchor1 = 0,0 + anchor2 = 100,100 + text-color = #ffffff + background-color = #292929 + is-default = true + saved-params = "" + highlight-color = #00aa00 + tab-text-color = #ffffff + tab-background-color = #292929 + on-show = ".winset\"rpane.infob.is-visible=true;rpane.browseb.is-visible=true?rpane.infob.pos=130,0:rpane.infob.pos=65,0 rpane.textb.is-visible=true rpane.infob.is-checked=true rpane.rpanewindow.pos=0,30 rpane.rpanewindow.size=0x0 rpane.rpanewindow.left=infowindow\"" + on-hide = ".winset\"rpane.infob.is-visible=false;rpane.browseb.is-visible=true?rpane.browseb.is-checked=true rpane.rpanewindow.left=browserwindow:rpane.textb.is-visible=true rpane.rpanewindow.pos=0,30 rpane.rpanewindow.size=0x0 rpane.rpanewindow.left=\"" + +window "text_editor" + elem "text_editor" + type = MAIN + pos = 281,0 + size = 360x488 + anchor1 = none + anchor2 = none + is-visible = false + border = sunken + saved-params = "pos;size;is-minimized;is-maximized" + title = "Text Editor" + can-minimize = false + can-resize = false + elem "exit" + type = BUTTON + pos = 248,456 + size = 104x24 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "Exit without saving" + command = "" + elem "save" + type = BUTTON + pos = 128,456 + size = 104x24 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "Save" + command = "" + elem "saveexit" + type = BUTTON + pos = 8,456 + size = 104x24 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "Save + Exit" + command = "" + elem "textedit" + type = INPUT + pos = 0,0 + size = 360x448 + anchor1 = none + anchor2 = none + border = line + saved-params = "" + multi-line = true + diff --git a/libmysql.dll b/libmysql.dll new file mode 100644 index 00000000..86453b95 Binary files /dev/null and b/libmysql.dll differ diff --git a/maps/_map_include.dm b/maps/_map_include.dm new file mode 100644 index 00000000..0c468a34 --- /dev/null +++ b/maps/_map_include.dm @@ -0,0 +1,4 @@ +/* + This is a dummy file to act as a marker point for dm.sh to insert its maps at. + DO NOT MOVE, REMOVE OR RENAME THIS FILE WITHOUT FIXING THE SCRIPT OR THINGS WILL BREAK +*/ diff --git a/maps/away/README.md b/maps/away/README.md new file mode 100644 index 00000000..bf4d6bdc --- /dev/null +++ b/maps/away/README.md @@ -0,0 +1,67 @@ +# Away sites + +## What exactly is an away site? + +It's a kind of map template which: +* is placed in its own zlevel (or collection of zlevels), +* should only get placed once per round, +* can be randomly picked to be placed automatically during round setup, +* normally has an overmap presence and shuttle landmarks so ships can fly to it. + +### Er, what's a map template? + +It's a datum you can define in the code (`/datum/map_template`) which points at one or more .dmm map files, and allows the game (or admins) to spawn those map files when and where they please, whether that's into an existing zlevel (like decorating exoplanets with ruins), or on a totally fresh one (like an away site!). + +## How do I make away sites? + +tl;dr you make your .dmm files, then you write a new map template datum (`/datum/map_template/ruin/away_site/insert_your_away_site_name_here`), then you include whatever file you defined that datum in into `torch.dm` and `away_sites_testing.dm`, and you're all set. + +BUT HEED MY RUMINATIONS + +## While mapping + +### Don't use Torch-specific types + +Away maps are expected to work whether you're on Torch, the example map, the Bearcat, or anything else you might want to load as the server's main map. That means your map mustn't use areas, turfs, objects, mobs or datums that are specific to any main map. + +e.g. you can use `/area/space`, or `/turf/simulated/wall`, because neither are specific to Torch. They live out in the main codebase, are always compiled in, and are available to all maps. But you can't use `/obj/random_multi/single_item/punitelly`, because Punitelli only exists when Torch is compiled. + +To make life easier, you can uncheck maps/torch/torch.dm (or your regional equivalent), then recompile, to make sure these types aren't available while you're mapping. + +### Don't re-use area types from other maps + +Except for, like, `/area/space`. That one's probably fine. + +(Now that's just areas! Other stuff might be ok. Except very map-specific stuff as noted!) + +Re-using areas is a shortcut, but it's bad for testability, and you can't guarantee that the area you re-use isn't loaded up and in active use on the server - in which case it'll hideously merge together with its brother in terms of stuff like air alarms, APCs, etc. Suddenly your derelict starship is randomly receiving power from another zlevel. Not good. Avoid. Make your own area types! + +If in doubt, ask #codershuttle on IRC/#coding on Discord. + +### If you're doing multi-z, make a different .dmm file for each zlevel + +Not exactly a technical requirement, but it makes things easier in terms of collaboration. See how it's done with `torch-1.dmm`, `torch-2.dmm`, etc. + +## Afterwards (or during, I'm not a cop) + +### Make sure you've got a .dm file for all your stuff + +Like `maps/away/derelict/derelict.dm`. It's a pretty good place to put all your new types! #include other files here too. This file's going to be the hub of your map's wheel, to cack-hand a metaphor. + +### Make a map template datum there + +The game will read this to learn about your new shiny away sites, including what .dmm files it needs to load, how much it 'costs' to spawn (usually 1, increase for more performance-heavy away sites). Ask devs or read code if unsure. + +### Include your .dm file in any main map file, and away sites testing + +That's `maps/away_sites_testing/away_sites_testing.dm`, and probably `maps/torch/torch.dm`. It goes in the testing one to make sure Travis runs it through unit testing, and it goes in the Torch one to make it available while we play Torch. If we have since changed map, yell at someone to update this doc. + +### Don't include it, or the .dmms, in the .dme + +That means don't have any of your away map stuff checked in Dream Maker. It'll get included, as if by magic, via the work you did in the previous step! + +That's it! You're probably done! Unless Travis explodes at you. + +### Some of the stuff I put in my map isn't behaving properly! + +The map loader works best when everything it's spawning does all its initialisation work in `Initialize`, instead of in `New`. Most likely your misbehaving thing is doing more initialisation than is healthy in `New`. It's fixable! Often not even that hard. Go talk to a dev. \ No newline at end of file diff --git a/maps/away/away_sites.dm b/maps/away/away_sites.dm new file mode 100644 index 00000000..ca6cac49 --- /dev/null +++ b/maps/away/away_sites.dm @@ -0,0 +1,6 @@ +// Hey! Listen! Update \config\away_site_blacklist.txt with your new ruins! + +/datum/map_template/ruin/away_site + var/spawn_weight = 1 + prefix = "maps/away/" + allow_duplicates = FALSE // duplicating these will probably screw up shuttles etc! diff --git a/maps/away/bearcat/bearcat-1.dmm b/maps/away/bearcat/bearcat-1.dmm new file mode 100644 index 00000000..05cbe626 --- /dev/null +++ b/maps/away/bearcat/bearcat-1.dmm @@ -0,0 +1,382 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/obj/effect/shuttle_landmark/automatic,/turf/space,/area/space) +"ac" = (/obj/structure/window/reinforced{dir = 4},/turf/space,/area/space) +"ad" = (/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "cargo_out"},/obj/machinery/shield_diffuser,/turf/simulated/floor/usedup,/area/ship/scrap/cargo/lower) +"ae" = (/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "cargo_out"},/obj/machinery/access_button/airlock_exterior{master_tag = "cargo"; pixel_x = 18; pixel_y = 17},/obj/machinery/shield_diffuser,/turf/simulated/floor/usedup,/area/ship/scrap/cargo/lower) +"af" = (/obj/structure/window/reinforced{dir = 8},/turf/space,/area/space) +"ag" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/turf/simulated/floor/usedup,/area/ship/scrap/cargo/lower) +"ah" = (/turf/simulated/wall,/area/ship/scrap/escape_port) +"ai" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "engwindow"; name = "blast door"; opacity = 0},/turf/simulated/floor/airless,/area/ship/scrap/escape_port) +"aj" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{frequency = 1379; id_tag = "cargo_pump"},/turf/simulated/floor/usedup,/area/ship/scrap/cargo/lower) +"ak" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{frequency = 1379; id_tag = "cargo_pump"},/obj/machinery/embedded_controller/radio/airlock/docking_port{id_tag = "cargo"; pixel_x = 24; tag_airpump = "cargo_pump"; tag_chamber_sensor = "cargo_sensor"; tag_exterior_door = "cargo_out"; tag_interior_door = "cargo_in"},/obj/machinery/light/small{dir = 4},/turf/simulated/floor/usedup,/area/ship/scrap/cargo/lower) +"al" = (/turf/simulated/wall/r_wall,/area/ship/scrap/cargo/lower) +"am" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/cargo/lower) +"an" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/cargo/lower) +"ao" = (/turf/simulated/wall,/area/ship/scrap/cargo/lower) +"ap" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "engwindow"; name = "blast door"; opacity = 0},/turf/simulated/floor/airless,/area/ship/scrap/escape_star) +"aq" = (/turf/simulated/wall,/area/ship/scrap/escape_star) +"ar" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/door/window/southright,/turf/simulated/floor/airless,/area/ship/scrap/escape_port) +"as" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/cargo/lower) +"at" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/simulated/floor/usedup,/area/ship/scrap/cargo/lower) +"au" = (/obj/machinery/airlock_sensor{id_tag = "cargo_sensor"; pixel_x = 25},/obj/machinery/atmospherics/pipe/simple/hidden,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/simulated/floor/usedup,/area/ship/scrap/cargo/lower) +"av" = (/obj/structure/ladder/up,/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"aw" = (/obj/structure/table/standard,/obj/item/device/flashlight/lamp,/obj/item/weapon/paper_bin,/obj/item/weapon/stamp/cargo,/obj/item/weapon/stamp/denied,/obj/item/weapon/clipboard,/obj/item/device/radio,/obj/item/device/radio/intercom{dir = 8; pixel_x = 22},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"ax" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/door/window/southright,/turf/simulated/floor/airless,/area/ship/scrap/escape_star) +"ay" = (/turf/simulated/wall/r_wall,/area/ship/scrap/escape_star) +"az" = (/obj/machinery/light/small/red{icon_state = "bulb1"; dir = 8},/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 1},/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/escape_port) +"aA" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 1},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/escape_port) +"aB" = (/obj/machinery/light/small/red{icon_state = "bulb1"; dir = 4},/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 1},/obj/machinery/power/apc/derelict{dir = 4},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/escape_port) +"aC" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/atmospherics/portables_connector,/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"aD" = (/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "cargo_in"},/obj/machinery/atmospherics/pipe/simple/hidden,/turf/simulated/floor/usedup,/area/ship/scrap/cargo/lower) +"aE" = (/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "cargo_in"},/obj/machinery/access_button/airlock_interior{master_tag = "cargo"; pixel_x = 20; pixel_y = -12},/obj/machinery/atmospherics/pipe/simple/hidden,/turf/simulated/floor/usedup,/area/ship/scrap/cargo/lower) +"aF" = (/obj/machinery/light_switch{pixel_x = -24},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"aG" = (/obj/effect/decal/cleanable/dirt,/obj/item/weapon/stool/padded,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"aH" = (/obj/machinery/light/small/red{icon_state = "bulb1"; dir = 8},/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 1},/obj/machinery/power/apc/derelict{dir = 8},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/escape_star) +"aI" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 1},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/escape_star) +"aJ" = (/obj/machinery/light/small/red{icon_state = "bulb1"; dir = 4},/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 1},/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/escape_star) +"aK" = (/turf/simulated/wall,/area/ship/scrap/gambling) +"aL" = (/turf/simulated/wall/r_wall,/area/ship/scrap/gambling) +"aM" = (/obj/machinery/door/airlock/autoname,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/usedup,/area/ship/scrap/escape_port) +"aN" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 5},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"aO" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"aP" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 9},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"aQ" = (/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"aR" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/closet/crate/plastic,/obj/random/accessory,/obj/random/accessory,/obj/item/weapon/reagent_containers/glass/paint/random,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"aS" = (/obj/machinery/door/airlock/autoname,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/usedup,/area/ship/scrap/escape_star) +"aT" = (/turf/simulated/wall,/area/ship/scrap/crew/dorms1) +"aU" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/dorms1) +"aV" = (/obj/item/device/flashlight/lamp,/turf/simulated/floor/usedup,/area/ship/scrap/gambling) +"aW" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/structure/holostool,/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/item/weapon/hand/missing_card,/turf/simulated/floor/usedup,/area/ship/scrap/gambling) +"aX" = (/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/light_switch{pixel_x = 24},/obj/machinery/power/apc/derelict{dir = 1},/turf/simulated/floor/usedup,/area/ship/scrap/gambling) +"aY" = (/obj/machinery/light/small{dir = 8},/obj/effect/decal/cleanable/cobweb2,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"aZ" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/machinery/power/apc/derelict{dir = 8},/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bb" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bc" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/closet/crate,/obj/random/toy,/obj/random/toy,/obj/random/loot,/obj/random/plushie,/obj/random/action_figure,/obj/random/action_figure,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bd" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/light/small{dir = 4},/obj/random/closet,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"be" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/structure/ladder/up,/obj/effect/decal/cleanable/cobweb,/obj/structure/sign/deck/second{pixel_x = -32},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"bf" = (/obj/machinery/power/apc/derelict{dir = 1},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/light_switch{pixel_x = -24},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/structure/closet,/obj/random/gloves,/obj/random/clothing,/obj/random/clothing,/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms1) +"bg" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/structure/holostool,/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/sign/poster{pixel_y = 32},/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms1) +"bh" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/structure/curtain/open/bed,/obj/structure/bed/padded,/obj/item/weapon/bedsheet/green,/obj/effect/decal/cleanable/cobweb2,/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms1) +"bi" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/gambling) +"bj" = (/obj/structure/holostool,/obj/item/weapon/hand/missing_card,/turf/simulated/floor/usedup,/area/ship/scrap/gambling) +"bk" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/table/gamblingtable,/obj/item/weapon/deck/cards,/obj/item/weapon/dice,/turf/simulated/floor/usedup,/area/ship/scrap/gambling) +"bl" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/holostool,/obj/item/weapon/hand/missing_card,/turf/simulated/floor/usedup,/area/ship/scrap/gambling) +"bm" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/usedup,/area/ship/scrap/gambling) +"bn" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"bo" = (/obj/machinery/door/airlock/autoname,/turf/simulated/floor/usedup,/area/ship/scrap/cargo/lower) +"bp" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bq" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"br" = (/obj/structure/cable{icon_state = "6-8"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bs" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bt" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bu" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bv" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"bw" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms1) +"bx" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms1) +"by" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms1) +"bz" = (/obj/structure/table/standard,/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms1) +"bA" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/crew/dorms1) +"bB" = (/turf/simulated/floor/usedup,/area/ship/scrap/gambling) +"bC" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/holostool,/obj/item/weapon/hand/missing_card,/turf/simulated/floor/usedup,/area/ship/scrap/gambling) +"bD" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/item/weapon/hand/missing_card,/obj/item/weapon/hand/missing_card,/turf/simulated/floor/usedup,/area/ship/scrap/gambling) +"bE" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"bF" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/structure/closet/crate,/obj/random/soap,/obj/random/soap,/obj/item/bodybag,/obj/item/stack/tile/carpet/fifty,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bG" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/decal/mecha_wreckage/ripley,/obj/machinery/mech_recharger,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bH" = (/obj/structure/cable{icon_state = "4-9"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bI" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/cable{icon_state = "6-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/closet/coffin,/obj/random/drinkbottle,/obj/item/weapon/contraband/poster,/obj/item/stack/material/phoron/ten,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bJ" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bK" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"bL" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/structure/closet,/obj/random/clothing,/obj/random/clothing,/obj/random/clothing,/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms1) +"bM" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/holostool,/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms1) +"bO" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/effect/floor_decal/industrial/warning/corner,/obj/machinery/mining/brace,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bP" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/industrial/warning,/obj/structure/closet/crate,/obj/item/weapon/fossil/skull,/obj/item/weapon/fossil/bone,/obj/item/weapon/fossil/bone,/obj/item/weapon/fossil/shell,/obj/item/xenos_claw,/obj/item/weapon/ore/strangerock,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bQ" = (/obj/effect/floor_decal/industrial/warning,/obj/effect/decal/cleanable/dirt,/obj/machinery/computer/shuttle_control/lift,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bR" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bS" = (/obj/effect/floor_decal/industrial/warning,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bT" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 8},/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/cable{icon_state = "2-9"},/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"bU" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/item/device/radio/intercom{dir = 8; pixel_x = 22},/obj/structure/cable{d1 = 16; d2 = 0; icon_state = "16-0"},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"bV" = (/turf/simulated/wall/r_wall,/area/ship/scrap/broken2) +"bW" = (/obj/machinery/floodlight,/turf/simulated/floor/usedup,/area/ship/scrap/broken2) +"bX" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/machinery/light_construct/small{icon_state = "bulb-construct-stage1"; dir = 1},/turf/simulated/floor/usedup,/area/ship/scrap/broken2) +"bY" = (/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/light_switch{pixel_x = 24},/obj/machinery/power/apc/derelict{dir = 1},/turf/simulated/floor/usedup,/area/ship/scrap/broken2) +"bZ" = (/turf/simulated/wall,/area/ship/scrap/broken2) +"ca" = (/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/effect/decal/cleanable/cobweb,/obj/effect/decal/cleanable/cobweb2,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"cb" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/item/device/radio/intercom{pixel_x = -32},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"cc" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/shuttle/lift) +"cd" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/shuttle/lift) +"ce" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/shuttle/lift) +"cf" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"cg" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"ch" = (/turf/simulated/wall,/area/ship/scrap/crew/dorms2) +"ci" = (/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/light_switch{pixel_x = -24},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/structure/closet,/obj/random/clothing,/obj/random/clothing,/obj/effect/decal/cleanable/cobweb,/obj/machinery/power/apc/derelict{dir = 1},/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms2) +"cj" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/structure/holostool,/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms2) +"ck" = (/obj/structure/curtain/open/bed,/obj/structure/bed/padded,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/item/weapon/bedsheet/ce,/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms2) +"cl" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/dorms2) +"cm" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/broken2) +"cn" = (/obj/structure/foamedmetal,/turf/simulated/floor/usedup,/area/ship/scrap/broken2) +"co" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/item/weapon/cell/high/empty,/turf/simulated/floor/usedup,/area/ship/scrap/broken2) +"cp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/usedup,/area/ship/scrap/broken2) +"cq" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/item/taperoll/engineering/applied,/turf/simulated/floor/usedup,/area/ship/scrap/broken2) +"cr" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"cs" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"ct" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/shuttle/lift) +"cu" = (/obj/effect/shuttle_landmark/lift/bottom,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/shuttle/lift) +"cv" = (/turf/simulated/floor/tiled/usedup,/area/ship/scrap/shuttle/lift) +"cw" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/shuttle/lift) +"cx" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"cy" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms2) +"cz" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms2) +"cA" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms2) +"cB" = (/obj/structure/table/standard,/obj/item/weapon/newspaper,/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms2) +"cC" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/crew/dorms2) +"cD" = (/turf/simulated/floor/usedup,/area/ship/scrap/broken2) +"cE" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/foamedmetal,/turf/simulated/floor/usedup,/area/ship/scrap/broken2) +"cF" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/item/stack/cable_coil/random,/turf/simulated/floor/usedup,/area/ship/scrap/broken2) +"cG" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"cH" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/structure/closet,/obj/random/gloves,/obj/random/clothing,/obj/random/clothing,/obj/random/clothing,/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms2) +"cI" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/item/weapon/storage/briefcase,/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms2) +"cK" = (/turf/space,/area/ship/scrap/broken1) +"cL" = (/obj/structure/lattice,/obj/item/remains/mouse,/turf/space,/area/ship/scrap/broken1) +"cM" = (/obj/structure/girder,/turf/simulated/floor/usedup,/area/ship/scrap/broken1) +"cN" = (/turf/simulated/wall,/area/ship/scrap/broken1) +"cO" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/door/airlock/autoname,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"cP" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"cQ" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 10},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/shuttle/lift) +"cR" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 10},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/shuttle/lift) +"cS" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 10},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/shuttle/lift) +"cT" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/light/small{dir = 4},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"cU" = (/obj/structure/lattice,/obj/item/stack/nanopaste,/turf/space,/area/ship/scrap/broken1) +"cV" = (/obj/structure/inflatable/wall,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/broken1) +"cW" = (/obj/structure/inflatable/wall,/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/broken1) +"cX" = (/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/light_switch{pixel_x = 24},/obj/machinery/power/apc/derelict{dir = 1},/obj/machinery/organ_printer/robot/mapped,/obj/item/device/radio/intercom{pixel_y = 22},/turf/simulated/floor/usedup,/area/ship/scrap/broken1) +"cY" = (/turf/simulated/wall/r_wall,/area/ship/scrap/broken1) +"cZ" = (/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"da" = (/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 4},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/structure/sign/deck/second{pixel_x = -32},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"db" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"dc" = (/obj/structure/stairs/east,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"dd" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/structure/ore_box,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"de" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 1},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"df" = (/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"dg" = (/turf/simulated/wall,/area/ship/scrap/crew/dorms3) +"dh" = (/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/light_switch{pixel_x = -24},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/structure/closet,/obj/random/gloves,/obj/random/clothing,/obj/random/clothing,/obj/machinery/power/apc/derelict{dir = 1},/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms3) +"di" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/structure/holostool,/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms3) +"dj" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/structure/curtain/open/bed,/obj/structure/bed/padded,/obj/item/weapon/bedsheet/green,/obj/effect/decal/cleanable/cobweb2,/obj/structure/sign/poster{pixel_y = 32},/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms3) +"dk" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/broken1) +"dl" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/item/device/robotanalyzer,/turf/simulated/floor/usedup,/area/ship/scrap/broken1) +"dm" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/usedup,/area/ship/scrap/broken1) +"dn" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/item/taperoll/engineering/applied,/turf/simulated/floor/usedup,/area/ship/scrap/broken1) +"do" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"dp" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"dq" = (/obj/machinery/light/small,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"dr" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"ds" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/usedup,/area/ship/scrap/crew/dorms3) +"dt" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms3) +"du" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms3) +"dv" = (/obj/structure/table/standard,/obj/random/plushie,/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms3) +"dw" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/crew/dorms3) +"dx" = (/obj/structure/mopbucket,/obj/structure/table/rack{dir = 8; layer = 2.9},/obj/item/weapon/storage/toolbox/mechanical,/obj/item/device/multitool{pixel_x = 3},/obj/item/clothing/glasses/welding,/obj/item/stack/cable_coil,/obj/item/stack/cable_coil,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/broken1) +"dy" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/broken1) +"dz" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/recharge_station,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/broken1) +"dA" = (/obj/machinery/door/airlock/autoname,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"dB" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/airlock/autoname,/turf/simulated/floor/usedup,/area/ship/scrap/cargo/lower) +"dC" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{icon_state = "1-10"},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"dD" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/dorms3) +"dE" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/structure/closet,/obj/random/clothing,/obj/random/clothing,/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms3) +"dF" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/holostool,/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms3) +"dG" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 10},/obj/structure/curtain/open/bed,/obj/structure/bed/padded,/obj/item/weapon/bedsheet/brown,/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms3) +"dH" = (/obj/machinery/floodlight,/turf/simulated/floor/usedup,/area/ship/scrap/broken1) +"dI" = (/obj/item/weapon/stool/padded,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/broken1) +"dJ" = (/obj/machinery/cryopod/robot{dir = 4},/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/computer/cryopod/robot{pixel_x = 32; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/broken1) +"dK" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/effect/decal/cleanable/spiderling_remains,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"dL" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"dM" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"dN" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/power/apc/derelict,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"dO" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"dP" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{icon_state = "2-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{icon_state = "map-scrubbers"; dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"dQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"dR" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"dS" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{icon_state = "5-8"},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"dT" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/machinery/light/small{dir = 4},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/lower) +"dU" = (/turf/simulated/wall,/area/ship/scrap/maintenance/techstorage) +"dV" = (/turf/simulated/wall,/area/ship/scrap/maintenance/storage) +"dW" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/storage) +"dX" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/airlock/autoname,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/storage) +"dY" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/eva) +"dZ" = (/turf/simulated/wall,/area/ship/scrap/maintenance/eva) +"ea" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/techstorage) +"eb" = (/obj/item/weapon/circuitboard/pacman,/obj/item/weapon/circuitboard/recharge_station,/obj/item/weapon/circuitboard/shield_generator,/obj/structure/table/rack,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/item/weapon/storage/bag/circuits/basic,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/techstorage) +"ec" = (/obj/item/weapon/circuitboard/helm,/obj/item/weapon/circuitboard/unary_atmos/cooler,/obj/structure/table/rack,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/machinery/alarm{pixel_y = 32},/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/techstorage) +"ed" = (/obj/item/weapon/circuitboard/autolathe,/obj/item/weapon/circuitboard/unary_atmos/heater,/obj/structure/table/rack,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/techstorage) +"ee" = (/obj/item/weapon/storage/toolbox/electrical,/obj/item/weapon/storage/toolbox/electrical{pixel_x = 7; pixel_y = 4},/obj/item/device/t_scanner,/obj/item/weapon/cell/high,/obj/machinery/alarm{pixel_y = 32},/obj/item/weapon/tape_roll,/obj/machinery/light_switch{pixel_x = -24},/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 9},/obj/item/weapon/airalarm_electronics,/obj/item/weapon/airlock_electronics,/obj/item/weapon/airlock_electronics,/obj/structure/table/rack,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/storage) +"ef" = (/obj/structure/closet/crate/plastic,/obj/item/weapon/storage/ore,/obj/item/weapon/pickaxe,/obj/item/stack/flag/yellow,/obj/item/weapon/storage/box/glowsticks,/obj/item/weapon/mining_scanner,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/storage) +"eg" = (/obj/item/weapon/caution,/obj/item/weapon/caution,/obj/item/weapon/FixOVein,/obj/structure/closet/crate,/obj/item/weapon/mop,/obj/item/device/radio,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/obj/item/weapon/storage/bag/trash,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/storage) +"eh" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/ladder/up,/obj/effect/decal/cleanable/dirt,/obj/structure/sign/deck/second{pixel_x = 0; pixel_y = 32},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/storage) +"ei" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/device/radio/intercom{dir = 8; pixel_x = 22},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/storage) +"ej" = (/obj/structure/table/rack,/obj/item/weapon/tank/jetpack/oxygen,/obj/item/clothing/mask/breath,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/eva) +"ek" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/table/rack,/obj/item/weapon/tank/jetpack/oxygen,/obj/item/clothing/mask/breath,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/eva) +"el" = (/obj/machinery/power/apc/derelict{dir = 1},/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 6},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/atmospherics/portables_connector,/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/eva) +"em" = (/obj/structure/window/reinforced,/turf/space,/area/space) +"en" = (/obj/machinery/light/small{dir = 8},/obj/machinery/vending/engineering,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/techstorage) +"eo" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/techstorage) +"ep" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/techstorage) +"eq" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/techstorage) +"er" = (/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 9},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{icon_state = "6-8"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/storage) +"es" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{icon_state = "map-scrubbers"; dir = 1},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/storage) +"et" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/storage) +"eu" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/storage) +"ev" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/storage) +"ew" = (/obj/structure/cable{icon_state = "4-10"},/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/eva) +"ex" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/eva) +"ey" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/eva) +"ez" = (/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 6},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 5},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/eva) +"eA" = (/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "eva_in"},/obj/machinery/access_button/airlock_interior{master_tag = "eva"; pixel_x = -12; pixel_y = 20},/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/eva) +"eB" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/machinery/airlock_sensor{id_tag = "eva_sensor"; pixel_y = 40},/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{id_tag = "eva"; pixel_y = 25; tag_airpump = "eva_pump"; tag_chamber_sensor = "eva_sensor"; tag_exterior_door = "eva_out"; tag_interior_door = "eva_in"},/obj/effect/floor_decal/industrial/warning{dir = 10},/obj/effect/floor_decal/industrial/warning{dir = 1},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/eva) +"eC" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1379; id_tag = "eva_pump"},/obj/effect/floor_decal/industrial/warning{dir = 5},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/eva) +"eD" = (/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "eva_out"},/obj/machinery/access_button/airlock_exterior{master_tag = "eva"; pixel_x = 18; pixel_y = -18},/obj/machinery/shield_diffuser,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/eva) +"eE" = (/obj/item/weapon/stock_parts/capacitor,/obj/item/weapon/stock_parts/capacitor,/obj/item/weapon/stock_parts/capacitor/adv,/obj/item/weapon/stock_parts/scanning_module,/obj/item/weapon/stock_parts/scanning_module,/obj/item/weapon/stock_parts/scanning_module,/obj/item/weapon/stock_parts/scanning_module/adv,/obj/structure/table/rack,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/techstorage) +"eF" = (/obj/item/weapon/stock_parts/console_screen,/obj/item/weapon/stock_parts/console_screen,/obj/item/weapon/stock_parts/console_screen,/obj/item/weapon/stock_parts/micro_laser,/obj/item/weapon/stock_parts/micro_laser,/obj/item/weapon/stock_parts/micro_laser,/obj/item/weapon/stock_parts/micro_laser/ultra,/obj/structure/table/rack,/obj/machinery/power/apc/derelict{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/techstorage) +"eG" = (/obj/structure/table/rack,/obj/item/weapon/circuitboard/pacman/super/potato,/obj/item/stack/material/glass/phoronrglass/ten,/obj/item/stack/material/ocp/ten,/obj/item/weapon/circuitboard/unary_atmos/engine,/obj/item/weapon/circuitboard/unary_atmos/engine,/obj/item/weapon/circuitboard/unary_atmos/engine,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/techstorage) +"eH" = (/obj/item/weapon/storage/toolbox/mechanical{pixel_x = 5; pixel_y = -7},/obj/item/weapon/storage/toolbox/mechanical,/obj/item/clothing/head/welding,/obj/item/device/analyzer,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 9},/obj/structure/table/rack,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/storage) +"eI" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{icon_state = "4-9"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/storage) +"eJ" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/storage) +"eK" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/storage) +"eL" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{icon_state = "5-8"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/storage) +"eM" = (/obj/item/device/radio/intercom{dir = 4; pixel_x = -22},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/eva) +"eN" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/eva) +"eO" = (/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 6},/obj/structure/sign/warning/vacuum{pixel_x = 35},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/eva) +"eP" = (/obj/structure/window/reinforced{dir = 1},/turf/space,/area/space) +"eQ" = (/obj/structure/table/standard,/obj/item/device/flashlight,/obj/item/device/flashlight,/obj/item/weapon/storage/box/lights/bulbs,/obj/item/weapon/storage/box/lights/mixed,/obj/structure/cable,/obj/machinery/power/apc/derelict{name = "Tools Storage APC"},/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 9},/obj/item/taperoll/engineering,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/storage) +"eR" = (/obj/structure/table/standard,/obj/item/weapon/inflatable_dispenser,/obj/item/device/radio,/obj/item/device/radio,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/machinery/light/small,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/storage) +"eS" = (/obj/item/weapon/tape_roll,/obj/item/stack/material/plasteel/fifty,/obj/item/stack/rods/fifty,/obj/item/stack/material/steel/fifty,/obj/item/stack/material/plastic/fifty,/obj/item/stack/material/steel/fifty,/obj/structure/closet/crate,/obj/item/stack/material/glass/fifty,/obj/item/stack/material/glass/fifty,/obj/item/stack/material/glass/reinforced/fifty,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/storage) +"eT" = (/obj/item/clothing/head/welding,/obj/item/device/radio,/obj/item/weapon/tape_roll,/obj/structure/table/standard,/obj/item/device/radio/intercom{pixel_y = -32},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/storage) +"eU" = (/obj/machinery/vending/tool,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/storage) +"eV" = (/obj/structure/dispenser/oxygen,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/eva) +"eW" = (/obj/machinery/suit_storage_unit/engineering/salvage,/obj/machinery/light/small,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/eva) +"eX" = (/obj/machinery/suit_storage_unit/engineering/salvage,/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/eva) +"eY" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/storage) +"fb" = (/obj/structure/curtain/open/bed,/obj/structure/bed/padded,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 10},/obj/item/weapon/bedsheet/red,/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms2) +"gb" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/closet/crate,/obj/random/loot,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/advdevice,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo/lower) +"vU" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 10},/obj/structure/curtain/open/bed,/obj/structure/bed/padded,/obj/item/weapon/bedsheet/brown,/mob/living/simple_animal/hostile/vagrant,/turf/simulated/floor/tiled/dark/airless,/area/ship/scrap/crew/dorms1) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacagagafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahaiaiaiaiaiahacajakalamanaoapapapapapaqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaharararararalasataualavawaoaxaxaxaxaxayaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahazaAaAaAaBalaCaDaEalaFaGaoaHaIaIaIaJayaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaKaKaLaKaLaMaoaNaOaPaQaQaRaoaSaTaTaTaUaUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaKaVaWaXaKaYaoaZgbaQbbbcbdaobeaTbfbgbhaUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabibjbkblbmbnbobpbqbrbsbtbubobvbwbxbybzbAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLbBbCbDaKbEaobFbGaQbHbIbJaobKaTbLbMvUaTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLaKaKaKaKbEaobObPbQbRbSbTaobUaTaTaTaTaUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabVbWbXbYbZcaaocbcccdcdcecfaocgchcicjckclaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacmcncocpcqcrbocsctcucvcwcfbocxcyczcAcBcCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacDcncEcFbZbEaocGctcvcvcwcfaobKchcHcIfbchaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacKcLcMcNcNcOaocPcQcRcRcScTaocOchchchchchaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacUcVcWcXcYcZaodadbdcaodddeaodfdgdhdidjdgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadkcVdldmdncrbododpdqdpdpdrbocxdsdtdudvdwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacNdxdydzcNbEaodAaoaoaoaodBaodCdDdEdFdGdDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacYdHdIdJcNdKdLdMdNdOdPdQdRdSdTdDdDdDdDdDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacNcNcNcNcNdUdVdVdWdWdXdYdYdYdZdZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaebeceddUeeefegeheidZejekeldZdZememaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaeneoepeqereseteuevewexeyezeAeBeCeDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaeEeFeGeaeHeIeJeKeLdZeMeNeOdZdZePePaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaeaeaeaeaeQeReSeTeUdZeVeWeXdZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadWdWdWeYdWdWdZdZdYdYdYaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/bearcat/bearcat-2.dmm b/maps/away/bearcat/bearcat-2.dmm new file mode 100644 index 00000000..816ca8c4 --- /dev/null +++ b/maps/away/bearcat/bearcat-2.dmm @@ -0,0 +1,644 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/command/bridge) +"ac" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/command/bridge) +"ad" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/machinery/door/firedoor,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/simulated/floor/usedup,/area/ship/scrap/command/bridge) +"ae" = (/obj/structure/grille,/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/command/bridge) +"af" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/command/bridge) +"ag" = (/obj/item/modular_computer/console/preset/command,/turf/simulated/floor/bluegrid/airless,/area/ship/scrap/command/bridge) +"ah" = (/obj/machinery/computer/helm,/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/bluegrid/airless,/area/ship/scrap/command/bridge) +"ai" = (/obj/structure/table/standard,/obj/item/toy/figure/captain,/obj/machinery/button/remote/blast_door{id = "sensor"; name = "Sensor Shroud"},/obj/item/device/radio,/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/bridge) +"aj" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/bed/chair/comfy/brown{icon_state = "comfychair_preview"; dir = 1},/obj/effect/landmark/deadcap,/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/bridge) +"ak" = (/obj/structure/table/standard,/obj/machinery/button/remote/blast_door{id = "scraplock"; name = "External Lockdown"},/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/bridge) +"al" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/command/bridge) +"am" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/obj/machinery/computer/engines,/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/bridge) +"an" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/bridge) +"ao" = (/obj/machinery/computer/sensors,/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/bridge) +"ap" = (/obj/effect/landmark/map_data{height = 2},/turf/space,/area/space) +"aq" = (/obj/effect/overmap/ship/bearcat,/turf/space,/area/space) +"ar" = (/turf/simulated/wall/r_wall,/area/ship/scrap/comms) +"as" = (/obj/machinery/door/blast/regular{id = "sensor"},/turf/simulated/floor/usedup,/area/ship/scrap/comms) +"at" = (/turf/simulated/wall/r_wall,/area/ship/scrap/command/bridge) +"au" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/machinery/power/apc/derelict{dir = 8},/obj/structure/cable{d2 = 6; icon_state = "0-6"},/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/bridge) +"av" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/bridge) +"aw" = (/obj/machinery/requests_console{announcementConsole = 1; department = "Captain"; pixel_x = 32},/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/bridge) +"ax" = (/obj/machinery/shipsensors,/turf/simulated/floor/usedup,/area/ship/scrap/comms) +"ay" = (/obj/machinery/alarm{dir = 1; icon_state = "alarm0"; pixel_x = 0; pixel_y = -32},/obj/machinery/light,/obj/item/modular_computer/console/preset/engineering,/obj/item/device/radio/intercom{pixel_x = -32},/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/bridge) +"az" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{icon_state = "2-9"},/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/bridge) +"aA" = (/obj/machinery/light,/obj/machinery/newscaster{pixel_y = -32},/obj/item/modular_computer/console/preset/command,/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/bridge) +"aB" = (/obj/machinery/door/blast/regular,/turf/simulated/floor/usedup,/area/ship/scrap/command/captain) +"aC" = (/turf/simulated/wall/r_wall,/area/ship/scrap/command/captain) +"aD" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/comms) +"aE" = (/obj/machinery/light_switch{pixel_x = 28},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/airlock/autoname/command,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/bridge) +"aF" = (/obj/machinery/cryopod/lifepod,/obj/machinery/door/window/southright,/obj/machinery/computer/cryopod{pixel_x = 32},/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"aG" = (/obj/machinery/ntnet_relay,/turf/simulated/floor/bluegrid/airless,/area/ship/scrap/comms) +"aH" = (/turf/simulated/floor/bluegrid/airless,/area/ship/scrap/comms) +"aI" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/structure/window/reinforced{dir = 8},/obj/machinery/power/apc/derelict{dir = 1; name = "Communications APC"},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/light_switch{pixel_x = 28},/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/comms) +"aJ" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/machinery/power/apc/derelict{dir = 4; name = "Bridge APC"},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/sign/warning/server_room{pixel_x = -32},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/hallway) +"aK" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/obj/item/weapon/gun/energy/stunrevolver,/obj/structure/closet/cabinet,/obj/item/weapon/storage/secure/briefcase,/obj/item/device/taperecorder,/obj/item/device/camera,/obj/item/weapon/storage/backpack/dufflebag/syndie,/obj/item/weapon/storage/box/shotgunshells,/obj/item/weapon/handcuffs,/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"aL" = (/obj/item/weapon/bedsheet/captain,/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/item/weapon/gun/projectile/pistol,/obj/structure/bed/padded,/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"aM" = (/obj/item/weapon/paper_bin,/obj/item/weapon/pen,/obj/structure/table/woodentable,/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/light_switch{pixel_y = 25},/obj/random/action_figure,/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"aN" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/comms) +"aO" = (/obj/machinery/message_server,/turf/simulated/floor/bluegrid/airless,/area/ship/scrap/comms) +"aP" = (/obj/machinery/door/window/westleft,/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/comms) +"aQ" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock/autoname/command,/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/comms) +"aR" = (/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/hallway) +"aS" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock/autoname/command,/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/captain) +"aT" = (/obj/structure/cable{icon_state = "6-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"aU" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"aV" = (/obj/structure/bed/chair/comfy/brown,/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"aW" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/command/captain) +"aX" = (/obj/machinery/alarm{dir = 1; icon_state = "alarm0"; pixel_x = 0; pixel_y = -32},/obj/machinery/computer/message_monitor,/turf/simulated/floor/bluegrid/airless,/area/ship/scrap/comms) +"aY" = (/obj/structure/window/reinforced{dir = 8},/obj/item/device/radio/intercom{pixel_y = -32},/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/comms) +"aZ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/command/hallway) +"ba" = (/obj/item/device/radio/intercom{pixel_x = -32},/obj/item/weapon/gun/projectile/shotgun/pump/combat{desc = "When words don't strike hard enough."; name = "Solid Argument"},/obj/structure/window/reinforced/full,/obj/structure/table/marble,/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"bb" = (/obj/structure/cable{icon_state = "4-9"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"bc" = (/obj/structure/table/woodentable,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc/derelict{dir = 4; name = "Captain's Quarters APC"},/obj/item/weapon/reagent_containers/food/drinks/coffeecup/one,/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"bd" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/command/captain) +"be" = (/turf/simulated/wall/r_wall,/area/ship/scrap/dock) +"bf" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/airlock/autoname/command,/turf/simulated/floor/tiled/dark/usedup,/area/ship/scrap/dock) +"bg" = (/obj/effect/shuttle_landmark/automatic,/turf/space,/area/space) +"bh" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/dock) +"bi" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/dock) +"bj" = (/obj/machinery/atm{pixel_y = 25},/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bk" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bl" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc/derelict{dir = 1; name = "Docking Area APC"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bm" = (/obj/structure/window/reinforced,/turf/space,/area/space) +"bn" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/obj/structure/sign/warning/vacuum{pixel_x = -35},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bo" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bp" = (/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bq" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"br" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/plaque,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bs" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bt" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/structure/sign/warning/vacuum{pixel_x = 35},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bu" = (/obj/machinery/access_button/airlock_exterior{master_tag = "bearcat_dock_port"; pixel_x = -18; pixel_y = 20},/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "dock_port_out"},/obj/machinery/shield_diffuser,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bv" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1379; id_tag = "dock_port_pump"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bw" = (/obj/machinery/light{dir = 1},/obj/machinery/airlock_sensor{id_tag = "dock_port_sensor"; pixel_y = 36},/obj/machinery/embedded_controller/radio/airlock/docking_port{id_tag = "bearcat_dock_port"; pixel_y = 25; tag_airpump = "dock_port_pump"; tag_chamber_sensor = "dock_port_sensor"; tag_exterior_door = "dock_port_out"; tag_interior_door = "dock_port_in"},/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bx" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/machinery/access_button/airlock_interior{master_tag = "bearcat_dock_port"; pixel_x = 12; pixel_y = 20},/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "dock_port_in"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"by" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 10; icon_state = "intact"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bz" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bA" = (/obj/structure/closet/walllocker/emerglocker/south,/obj/item/device/radio/intercom{pixel_x = -32},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bB" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bC" = (/obj/machinery/light_switch{pixel_x = 28},/obj/machinery/light_switch{pixel_x = 28},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bD" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bE" = (/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 6},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bF" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/machinery/access_button/airlock_interior{master_tag = "bearcat_starboard_dock"; pixel_x = -12; pixel_y = 20},/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "dock_star_in"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bG" = (/obj/machinery/light{dir = 1},/obj/machinery/airlock_sensor{id_tag = "dock_star_sensor"; pixel_y = 37},/obj/machinery/embedded_controller/radio/airlock/docking_port{id_tag = "bearcat_starboard_dock"; pixel_y = 25; tag_airpump = "dock_star_pump"; tag_chamber_sensor = "dock_star_sensor"; tag_exterior_door = "dock_star_out"; tag_interior_door = "dock_star_in"},/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bH" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1379; id_tag = "dock_star_pump"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bI" = (/obj/machinery/access_button/airlock_exterior{master_tag = "bearcat_starboard_dock"; pixel_x = 18; pixel_y = 20},/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "dock_star_out"},/obj/machinery/shield_diffuser,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bJ" = (/obj/structure/window/reinforced{dir = 1},/turf/space,/area/space) +"bK" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/dock) +"bL" = (/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/portables_connector{icon_state = "map_connector"; dir = 4},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/machinery/portable_atmospherics/canister/empty/air,/turf/simulated/floor/usedup,/area/ship/scrap/dock) +"bM" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 9},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bN" = (/obj/item/device/radio/intercom{pixel_y = -32},/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bO" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bP" = (/obj/item/device/radio/intercom{pixel_y = -32},/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bQ" = (/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 5},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bR" = (/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/portables_connector{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/machinery/portable_atmospherics/canister/empty/air,/turf/simulated/floor/usedup,/area/ship/scrap/dock) +"bS" = (/obj/structure/lattice,/obj/structure/window/reinforced{dir = 1},/turf/space,/area/space) +"bT" = (/obj/structure/sign/warning/docking_area,/turf/simulated/wall/r_wall,/area/ship/scrap/dock) +"bU" = (/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bV" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/lattice,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/dock) +"bW" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/dock) +"bX" = (/obj/structure/window/reinforced{dir = 8},/obj/structure/lattice,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/dock) +"bY" = (/obj/structure/lattice,/turf/space,/area/space) +"bZ" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/crew/hallway/port) +"ca" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/port) +"cb" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/crew/hallway/port) +"cc" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/dock) +"cd" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/dock) +"ce" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/crew/hallway/starboard) +"cf" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/starboard) +"cg" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/crew/hallway/starboard) +"ch" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/saloon) +"ci" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cj" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/random/maintenance,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/starboard) +"ck" = (/turf/simulated/wall,/area/ship/scrap/crew/saloon) +"cl" = (/obj/machinery/vending/snack,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cm" = (/obj/machinery/power/apc/derelict{dir = 1; name = "Crew Areas APC"},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/structure/bed/chair,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cn" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"co" = (/obj/structure/closet/walllocker/emerglocker/north,/obj/structure/bed/chair/wood,/obj/item/weapon/deck/tarot,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cp" = (/obj/machinery/vending/coffee,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cq" = (/turf/simulated/wall,/area/ship/scrap/crew/toilets) +"cr" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/toilets) +"cs" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/crew/toilets) +"ct" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/port) +"cu" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/machinery/newscaster{pixel_x = -32},/obj/machinery/media/jukebox,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cv" = (/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cw" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/stool/padded,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cx" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cy" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/structure/table/standard,/obj/machinery/recharger,/obj/structure/sign/poster{pixel_x = 32; pixel_y = 0},/obj/item/trash/tray,/obj/item/weapon/circular_saw,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cz" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/item/weapon/crowbar,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/starboard) +"cA" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/cryo) +"cB" = (/turf/simulated/wall,/area/ship/scrap/crew/cryo) +"cC" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/cryo) +"cD" = (/obj/machinery/computer/cryopod,/turf/simulated/wall,/area/ship/scrap/crew/cryo) +"cE" = (/obj/structure/window/reinforced/tinted{icon_state = "twindow"; dir = 4},/obj/machinery/shower{icon_state = "shower"; dir = 4},/obj/structure/window/reinforced/tinted{dir = 1},/obj/item/weapon/soap,/obj/structure/curtain/open/shower,/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/toilets) +"cF" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/structure/toilet,/obj/structure/window/reinforced/tinted{dir = 1},/obj/structure/window/reinforced/tinted{icon_state = "twindow"; dir = 4},/obj/structure/window/reinforced/tinted{dir = 8; icon_state = "twindow"},/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/toilets) +"cG" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/structure/mirror{pixel_y = 29},/obj/structure/sink{pixel_y = 18},/obj/structure/window/reinforced/tinted{dir = 8; icon_state = "twindow"},/obj/structure/window/reinforced/tinted{icon_state = "twindow"; dir = 4},/obj/structure/window/reinforced/tinted{dir = 1},/obj/structure/window/reinforced/tinted{dir = 8; icon_state = "twindow"},/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/obj/item/weapon/hemostat,/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/toilets) +"cH" = (/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/port) +"cI" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/structure/reagent_dispensers/water_cooler,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cJ" = (/obj/item/weapon/stool/padded,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cK" = (/obj/structure/table/standard,/obj/random/smokes,/obj/item/weapon/material/ashtray/glass,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/item/weapon/board,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cL" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/structure/closet/emcloset,/obj/structure/sign/deck/first{pixel_x = 32},/obj/random/voidhelmet,/obj/random/voidhelmet,/obj/random/voidhelmet,/obj/random/voidsuit,/obj/random/voidsuit,/obj/random/voidsuit,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cM" = (/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/starboard) +"cN" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/item/device/radio/intercom{pixel_x = -32},/obj/structure/closet/wardrobe/pjs,/obj/structure/sign/poster{pixel_y = 32},/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/cryo) +"cO" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/cryo) +"cP" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/cryopod,/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/cryo) +"cQ" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/crew/toilets) +"cR" = (/obj/machinery/door/window/westleft{base_state = "right"; dir = 4; icon_state = "right"; name = "Reception Window"; opacity = 1},/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/item/weapon/towel,/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/toilets) +"cS" = (/obj/machinery/door/window/westleft{base_state = "right"; dir = 4; icon_state = "right"; name = "Reception Window"; opacity = 1},/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/toilets) +"cT" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/toilets) +"cU" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/airlock/maintenance_hatch{name = "Bathrooms"; normalspeed = 0},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/toilets) +"cV" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/port) +"cW" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cX" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cY" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"cZ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/stool/padded,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"da" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"db" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"dc" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/starboard) +"dd" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/airlock/maintenance_hatch{name = "Cryo Storage"; normalspeed = 0},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/cryo) +"de" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/cryo) +"df" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/cryo) +"dg" = (/obj/machinery/cryopod,/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/cryo) +"dh" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor,/obj/structure/window/reinforced{dir = 5; health = 1e+007},/turf/simulated/floor/usedup,/area/ship/scrap/crew/cryo) +"di" = (/obj/machinery/shower{icon_state = "shower"; dir = 4},/obj/structure/window/reinforced/tinted{icon_state = "twindow"; dir = 4},/obj/structure/window/reinforced/tinted,/obj/structure/curtain/open/shower,/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/toilets) +"dj" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 1},/obj/structure/window/reinforced/tinted,/obj/structure/window/reinforced/tinted{icon_state = "twindow"; dir = 4},/obj/structure/window/reinforced/tinted{dir = 8; icon_state = "twindow"},/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/toilets) +"dk" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 1},/obj/structure/window/reinforced/tinted{dir = 8; icon_state = "twindow"},/obj/structure/window/reinforced/tinted{icon_state = "twindow"; dir = 4},/obj/structure/window/reinforced/tinted,/obj/effect/decal/cleanable/dirt,/obj/structure/cable,/obj/machinery/power/apc/derelict{dir = 4; name = "Bathrooms APC"},/obj/machinery/light_switch{pixel_y = -25},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/toilets) +"dl" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/effect/decal/cleanable/dirt,/obj/structure/disposalpipe/segment{icon_state = "conpipe-c"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/port) +"dm" = (/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/wall,/area/ship/scrap/crew/saloon) +"dn" = (/obj/effect/decal/cleanable/dirt,/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/vending/cigarette,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"do" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/bed/chair/comfy/brown{icon_state = "comfychair_preview"; dir = 1},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"dp" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"dq" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/item/device/radio/intercom{pixel_y = -32},/obj/structure/ladder,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"dr" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 8},/obj/machinery/light_switch{pixel_x = 28},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/saloon) +"ds" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/starboard) +"dt" = (/obj/structure/cable,/obj/machinery/power/apc/derelict{name = "Dorms APC"},/obj/machinery/light_switch{pixel_x = -25},/obj/structure/closet/wardrobe/mixed,/obj/item/weapon/storage/backpack/dufflebag/med,/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/cryo) +"du" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/cryo) +"dv" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/kitchen) +"dw" = (/turf/simulated/wall,/area/ship/scrap/crew/kitchen) +"dx" = (/obj/structure/disposalpipe/segment,/obj/structure/closet/walllocker/emerglocker/east,/obj/machinery/light_switch{pixel_x = -25},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/port) +"dy" = (/turf/simulated/wall,/area/ship/scrap/cargo) +"dz" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"dA" = (/obj/machinery/light_switch{pixel_x = -25},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/sign/deck/first{pixel_x = 32},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/starboard) +"dB" = (/turf/simulated/wall,/area/ship/scrap/crew/medbay) +"dC" = (/obj/machinery/door/airlock/autoname,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/medbay) +"dD" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/medbay) +"dE" = (/obj/structure/table/standard,/obj/machinery/reagentgrinder,/obj/effect/floor_decal/corner/red/diagonal,/obj/structure/sign/monkey_painting{pixel_y = 32},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/kitchen) +"dF" = (/obj/item/device/radio/intercom{pixel_y = 32},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/obj/effect/floor_decal/corner/red/diagonal,/obj/machinery/vending/dinnerware,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/kitchen) +"dG" = (/obj/structure/closet/walllocker/emerglocker/north,/obj/structure/closet/secure_closet/freezer/fridge,/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/effect/floor_decal/corner/red/diagonal,/obj/random/drinkbottle,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/kitchen) +"dH" = (/obj/structure/disposalpipe/segment,/obj/machinery/power/apc/derelict{dir = 4; name = "Crew Deck APC"},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/port) +"dI" = (/obj/structure/closet/crate,/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/random/shoes,/obj/random/shoes,/obj/random/hat,/obj/random/hat,/obj/random/masks,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"dJ" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/item/device/radio/intercom{pixel_y = 32},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"dK" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"dL" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"dM" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"dN" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/usedup,/area/ship/scrap/crew/hallway/starboard) +"dO" = (/obj/machinery/sleeper,/obj/structure/sign/warning/nosmoking_2{pixel_y = 28},/obj/structure/closet/walllocker/emerglocker/west,/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/medbay) +"dP" = (/obj/item/roller,/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/medbay) +"dQ" = (/obj/item/device/radio/intercom{pixel_y = 32},/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/item/weapon/bedsheet/medical,/obj/structure/curtain/open/privacy,/obj/structure/bed/padded,/obj/item/clothing/accessory/stethoscope,/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/medbay) +"dR" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/engine/port) +"dS" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor,/turf/simulated/floor/usedup,/area/ship/scrap/crew/kitchen) +"dT" = (/obj/structure/table/standard,/obj/effect/floor_decal/corner/red/diagonal,/obj/item/weapon/reagent_containers/glass/beaker{pixel_x = 5},/obj/item/weapon/book/manual/chef_recipes,/obj/item/weapon/reagent_containers/food/condiment/small/peppermill{pixel_x = 3},/obj/item/weapon/reagent_containers/food/condiment/enzyme{layer = 5},/obj/item/weapon/reagent_containers/glass/rag,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/kitchen) +"dU" = (/obj/item/weapon/stool/padded,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/floor_decal/corner/red/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/kitchen) +"dV" = (/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/power/apc/derelict{dir = 4; name = "Galley APC"},/obj/effect/floor_decal/corner/red/diagonal,/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/kitchen) +"dW" = (/obj/structure/disposalpipe/segment,/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/sign/directions/engineering{pixel_x = -32},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/port) +"dX" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"dY" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/closet/crate/hydroponics/prespawned,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"dZ" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"ea" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/item/weapon/stool/padded,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"eb" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"ec" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/sign/directions/engineering{pixel_x = -32},/obj/structure/ladder,/turf/simulated/floor/usedup,/area/ship/scrap/crew/hallway/starboard) +"ed" = (/obj/structure/sign/redcross,/turf/simulated/wall,/area/ship/scrap/crew/medbay) +"ee" = (/obj/item/weapon/stool/padded,/obj/structure/sink{dir = 8; icon_state = "sink"; pixel_x = -13; pixel_y = 0},/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/medbay) +"ef" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/medbay) +"eg" = (/obj/structure/iv_drip,/obj/structure/closet/medical_wall{name = "pill cabinet"; pixel_x = 26},/obj/item/weapon/storage/pill_bottle/antidexafen,/obj/item/weapon/storage/pill_bottle/tramadol,/obj/item/weapon/storage/pill_bottle/antitox,/obj/item/weapon/storage/pill_bottle/kelotane,/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/medbay) +"eh" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/engine/starboard) +"ei" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/obj/structure/cable{icon_state = "4-10"},/turf/simulated/floor/usedup,/area/ship/scrap/crew/kitchen) +"ej" = (/obj/structure/table/standard,/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/item/weapon/storage/box/donkpockets,/obj/effect/floor_decal/corner/red/diagonal,/obj/item/weapon/material/kitchen/rollingpin,/obj/item/weapon/reagent_containers/food/condiment/small/saltshaker{pixel_x = -3; pixel_y = 0},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/kitchen) +"ek" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/effect/floor_decal/corner/red/diagonal,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/kitchen) +"el" = (/obj/structure/disposalpipe/segment{icon_state = "conpipe-c"; dir = 4},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/effect/floor_decal/corner/red/diagonal,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/kitchen) +"em" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/kitchen) +"en" = (/obj/structure/disposalpipe/junction,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/port) +"eo" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"ep" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"eq" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"er" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"es" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"et" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"eu" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/structure/cable{icon_state = "2-8"},/turf/simulated/floor/usedup,/area/ship/scrap/crew/hallway/starboard) +"ev" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/airlock/maintenance_hatch{name = "Medical Bay"; normalspeed = 0},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/medbay) +"ew" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/medbay) +"ex" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/structure/bed/chair/office/light,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/medbay) +"ey" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/table/standard,/obj/item/weapon/glass_extra/straw,/obj/item/toy/therapy_blue,/obj/item/weapon/reagent_containers/spray/cleaner,/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/medbay) +"ez" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/obj/structure/cable{icon_state = "6-8"},/turf/simulated/floor/usedup,/area/ship/scrap/crew/medbay) +"eA" = (/obj/item/weapon/storage/pill_bottle/happy,/obj/machinery/power/apc/derelict{dir = 1},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/engine/port) +"eB" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 6},/obj/machinery/meter,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/engine/port) +"eC" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/machinery/door/airlock/autoname/engineering,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/engine/port) +"eD" = (/obj/item/weapon/screwdriver,/obj/structure/cable{icon_state = "5-8"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 10},/turf/simulated/floor/usedup,/area/space) +"eE" = (/obj/structure/table/standard,/obj/machinery/microwave,/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/effect/floor_decal/corner/red/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/kitchen) +"eF" = (/obj/structure/closet/secure_closet/freezer/meat,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/effect/floor_decal/corner/red/diagonal,/obj/item/weapon/reagent_containers/ivbag/blood/OMinus,/obj/item/weapon/reagent_containers/ivbag/blood/OMinus,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/kitchen) +"eG" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{icon_state = "pipe-t"; dir = 1},/obj/machinery/light_switch{pixel_x = 28},/obj/effect/floor_decal/corner/red/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/kitchen) +"eH" = (/obj/structure/disposalpipe/segment,/obj/machinery/door/airlock/autoname,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/port) +"eI" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/machinery/light_switch{pixel_x = -25},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"eJ" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"eK" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"eL" = (/obj/structure/closet/crate,/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/cable{icon_state = "6-8"},/obj/random/storage,/obj/random/bomb_supply,/obj/random/bomb_supply,/obj/random/bomb_supply,/obj/item/weapon/storage/box/syringes,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"eM" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable,/obj/machinery/power/apc/derelict{dir = 4; name = "Cargo Hold APC"},/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"eN" = (/obj/machinery/power/apc/derelict{dir = 4; name = "Crew Deck APC"},/obj/structure/cable,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/door/airlock/autoname,/turf/simulated/floor/usedup,/area/ship/scrap/crew/hallway/starboard) +"eO" = (/obj/structure/table/standard,/obj/structure/cable,/obj/machinery/power/apc/derelict{name = "Medical Bay APC"},/obj/machinery/light_switch{pixel_x = -25},/obj/structure/closet/medical_wall/filled{pixel_y = -32},/obj/item/weapon/tape_roll,/obj/item/weapon/retractor,/obj/item/weapon/scalpel,/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/medbay) +"eP" = (/obj/machinery/light,/obj/machinery/optable,/obj/item/weapon/reagent_containers/food/drinks/coffeecup/britcup,/obj/item/weapon/reagent_containers/glass/rag,/obj/machinery/oxygen_pump/anesthetic{pixel_y = -32},/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/medbay) +"eQ" = (/obj/structure/table/standard,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/structure/sign/warning/nosmoking_1{pixel_y = -32},/obj/structure/sign/goldenplaque/medical{pixel_x = 32},/obj/item/weapon/storage/firstaid/adv,/obj/random/medical,/obj/item/stack/medical/advanced/bruise_pack,/obj/item/weapon/reagent_containers/syringe/antiviral,/obj/item/device/healthanalyzer,/turf/simulated/floor/tiled/white/usedup,/area/ship/scrap/crew/medbay) +"eR" = (/obj/item/device/radio,/obj/structure/cable{icon_state = "4-9"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 6},/turf/simulated/floor/usedup,/area/space) +"eS" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/machinery/door/airlock/autoname/engineering,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/engine/starboard) +"eT" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/item/weapon/coin/gold,/obj/item/weapon/coin/silver,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 10},/obj/machinery/meter,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/engine/starboard) +"eU" = (/obj/machinery/power/apc/derelict{dir = 1},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/engine/starboard) +"eV" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 6},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/engine/port) +"eW" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/manifold/visible/fuel{icon_state = "map"; dir = 4},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/engine/port) +"eX" = (/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/obj/structure/lattice,/turf/space,/area/space) +"eY" = (/turf/simulated/wall,/area/ship/scrap/crew/wash) +"eZ" = (/obj/structure/disposalpipe/segment,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/port) +"fa" = (/obj/effect/floor_decal/industrial/warning,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/sign/warning/fall{pixel_x = -32},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"fb" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/industrial/warning,/obj/machinery/computer/shuttle_control/lift,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"fc" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"fd" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"fe" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/structure/cable{icon_state = "2-9"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 8},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"ff" = (/obj/effect/decal/cleanable/cobweb,/obj/effect/decal/cleanable/cobweb2,/obj/structure/cable{d1 = 32; d2 = 1; icon_state = "32-1"},/obj/structure/lattice,/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/open,/area/ship/scrap/crew/hallway/starboard) +"fg" = (/obj/structure/lattice,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/space,/area/space) +"fh" = (/turf/simulated/wall,/area/ship/scrap/maintenance/engine/starboard) +"fi" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/manifold/visible/fuel{icon_state = "map"; dir = 8},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/engine/starboard) +"fj" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 10},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/engine/starboard) +"fk" = (/obj/effect/floor_decal/industrial/warning,/obj/structure/sign/warning/hot_exhaust,/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/engine/port) +"fl" = (/obj/machinery/atmospherics/unary/engine{icon_state = "nozzle"; dir = 1},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/engine/port) +"fm" = (/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/usedup,/area/space) +"fn" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/wash) +"fo" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 6},/obj/structure/undies_wardrobe,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/wash) +"fp" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/item/device/radio/intercom{pixel_y = 32},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/wash) +"fq" = (/obj/structure/disposalpipe/segment{icon_state = "conpipe-c"; dir = 4},/obj/machinery/power/apc/derelict{dir = 1; name = "Washroom APC"},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/wash) +"fr" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/airlock/maintenance_hatch{name = "Laundry"; normalspeed = 0},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/wash) +"fs" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/disposalpipe/junction,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 10},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/port) +"ft" = (/turf/simulated/open,/area/ship/scrap/cargo) +"fu" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 8},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"fv" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 6},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/usedup,/area/ship/scrap/crew/hallway/starboard) +"fw" = (/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/usedup,/area/ship/scrap/unused) +"fx" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/random/junk,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/structure/cable{icon_state = "6-8"},/turf/simulated/floor/usedup,/area/ship/scrap/unused) +"fy" = (/obj/machinery/light_switch{pixel_y = 25},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/random/maintenance,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/item/modular_computer/console/preset/library,/obj/structure/table/standard,/turf/simulated/floor/usedup,/area/ship/scrap/unused) +"fz" = (/obj/effect/decal/cleanable/cobweb2,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 10},/turf/simulated/floor/usedup,/area/ship/scrap/unused) +"fA" = (/turf/simulated/wall/r_wall,/area/ship/scrap/unused) +"fB" = (/obj/effect/floor_decal/industrial/warning,/obj/structure/sign/warning/hot_exhaust,/turf/simulated/wall,/area/ship/scrap/maintenance/engine/starboard) +"fC" = (/obj/machinery/atmospherics/unary/engine{icon_state = "nozzle"; dir = 1},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/engine/starboard) +"fD" = (/obj/effect/floor_decal/industrial/warning,/obj/structure/sign/warning/hot_exhaust,/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/engine/starboard) +"fE" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/space) +"fF" = (/obj/structure/lattice,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/space) +"fG" = (/obj/structure/lattice,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 5},/turf/space,/area/space) +"fH" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/usedup,/area/ship/scrap/crew/wash) +"fI" = (/obj/structure/closet,/obj/random/clothing,/obj/random/clothing,/obj/random/clothing,/obj/random/clothing,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 9},/obj/item/weapon/storage/backpack/dufflebag,/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/wash) +"fJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/wash) +"fK" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{icon_state = "pipe-t"; dir = 1},/obj/machinery/light_switch{pixel_x = 28},/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/wash) +"fL" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/sign/directions/medical{dir = 4; icon_state = "direction_med"; pixel_x = 32; pixel_z = -4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/port) +"fM" = (/obj/effect/shuttle_landmark/lift/top,/turf/simulated/open,/area/ship/scrap/cargo) +"fN" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/light/small{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"fO" = (/obj/structure/closet/walllocker/emerglocker/west,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/usedup,/area/ship/scrap/crew/hallway/starboard) +"fP" = (/turf/simulated/wall,/area/ship/scrap/unused) +"fQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor/usedup,/area/ship/scrap/unused) +"fR" = (/obj/effect/decal/cleanable/generic,/obj/item/device/flashlight,/obj/structure/skele_stand{anchored = 0; name = "Spookers"},/obj/structure/cable{icon_state = "2-9"},/turf/simulated/floor/usedup,/area/ship/scrap/unused) +"fS" = (/obj/random/junk,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 5},/turf/simulated/floor/usedup,/area/ship/scrap/unused) +"fT" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/usedup,/area/ship/scrap/unused) +"fU" = (/obj/structure/lattice,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 9},/turf/space,/area/space) +"fV" = (/obj/structure/closet,/obj/random/clothing,/obj/random/clothing,/obj/random/clothing,/obj/random/clothing,/obj/item/weapon/reagent_containers/glass/rag,/obj/item/weapon/clothingbag/rubbermask,/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/wash) +"fW" = (/obj/machinery/washing_machine,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/wash) +"fX" = (/obj/structure/table/standard,/obj/machinery/light/small,/obj/item/weapon/reagent_containers/spray/cleaner,/obj/item/weapon/storage/laundry_basket,/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/wash) +"fY" = (/obj/structure/closet/walllocker/emerglocker/east,/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/port) +"fZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/structure/sign/deck/first{pixel_x = 32},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"ga" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/usedup,/area/ship/scrap/crew/hallway/starboard) +"gb" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/item/weapon/stool/padded,/turf/simulated/floor/usedup,/area/ship/scrap/unused) +"gc" = (/obj/machinery/power/apc/derelict{name = "Medical Bay APC"},/obj/structure/cable,/obj/machinery/icecream_vat,/turf/simulated/floor/usedup,/area/ship/scrap/unused) +"gd" = (/obj/random/maintenance,/obj/item/weapon/clothingbag/rubbersuit,/turf/simulated/floor/usedup,/area/ship/scrap/unused) +"ge" = (/turf/simulated/wall/r_wall,/area/ship/scrap/fire) +"gf" = (/turf/simulated/wall,/area/ship/scrap/fire) +"gg" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/crew/hallway/port) +"gh" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/structure/cable{icon_state = "1-10"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"gi" = (/obj/machinery/door/airlock/autoname,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"gj" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/usedup,/area/ship/scrap/crew/hallway/starboard) +"gk" = (/turf/simulated/wall/r_wall,/area/ship/scrap/hidden) +"gl" = (/turf/simulated/wall,/area/ship/scrap/hidden) +"gm" = (/obj/structure/closet/firecloset/full,/obj/effect/decal/cleanable/cobweb,/obj/effect/floor_decal/corner/blue{dir = 1},/obj/effect/floor_decal/corner/yellow{dir = 8},/obj/item/seeds/lemonseed,/obj/item/seeds/kudzuseed,/obj/item/seeds/ambrosiavulgarisseed,/obj/item/seeds/potatoseed,/obj/item/seeds/potatoseed,/obj/item/seeds/poppyseed,/obj/item/seeds/poppyseed,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/fire) +"go" = (/obj/effect/decal/cleanable/cobweb2,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/obj/machinery/portable_atmospherics/hydroponics,/obj/machinery/alarm{pixel_y = 25},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/fire) +"gp" = (/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/hallway) +"gq" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"gr" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/structure/cable{icon_state = "5-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/light/small,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"gs" = (/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/cargo) +"gt" = (/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/hallway) +"gv" = (/obj/machinery/light_switch{pixel_y = 25},/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/item/weapon/storage/backpack/dufflebag/syndie,/mob/living/simple_animal/hostile/vagrant,/turf/simulated/floor/usedup,/area/ship/scrap/hidden) +"gw" = (/obj/structure/closet/crate,/obj/random/coin,/obj/item/weapon/spacecash/bundle/c1000,/turf/simulated/floor/usedup,/area/ship/scrap/hidden) +"gx" = (/obj/structure/disposaloutlet{dir = 8},/obj/structure/disposalpipe/trunk{dir = 4},/turf/space,/area/space) +"gy" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/usedup,/area/ship/scrap/fire) +"gz" = (/obj/machinery/portable_atmospherics/powered/pump/filled,/obj/effect/floor_decal/corner/blue{dir = 1},/obj/effect/floor_decal/corner/yellow{dir = 8},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/fire) +"gA" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/fire) +"gB" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/fire) +"gC" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/airlock/maintenance_hatch{name = "Firefighting Equipment"; normalspeed = 0},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/fire) +"gD" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/structure/cable{icon_state = "6-8"},/obj/structure/disposalpipe/junction/yjunction{icon_state = "pipe-y"; dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/hallway) +"gE" = (/obj/effect/decal/cleanable/cobweb,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/hallway) +"gF" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall/r_wall{can_open = 1},/area/ship/scrap/hidden) +"gG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/mob/living/simple_animal/hostile/vagrant,/turf/simulated/floor/usedup,/area/ship/scrap/hidden) +"gH" = (/obj/item/weapon/stool/padded,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/usedup,/area/ship/scrap/hidden) +"gI" = (/obj/structure/table/reinforced,/obj/item/device/flashlight/lamp,/obj/item/weapon/spacecash/bundle/c1000,/obj/item/weapon/storage/bible/booze,/turf/simulated/floor/usedup,/area/ship/scrap/hidden) +"gJ" = (/obj/machinery/portable_atmospherics/powered/scrubber,/obj/effect/floor_decal/corner/blue{dir = 1},/obj/effect/floor_decal/corner/yellow{dir = 8},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/fire) +"gK" = (/turf/simulated/floor/tiled/usedup,/area/ship/scrap/fire) +"gL" = (/obj/structure/cable,/obj/machinery/power/apc/derelict{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/reagent_dispensers,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/fire) +"gM" = (/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 5},/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/hallway) +"gN" = (/obj/machinery/light/small,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{icon_state = "4-9"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/hallway) +"gO" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/structure/disposalpipe/segment{icon_state = "conpipe-c"; dir = 2},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/hallway) +"gP" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/hallway) +"gQ" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/fuel{icon_state = "map"; dir = 1},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/hallway) +"gR" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/machinery/power/apc/derelict{dir = 1},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/hallway) +"gS" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/hallway) +"gT" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/item/weapon/crowbar,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/hallway) +"gU" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/structure/sign/directions/medical{dir = 1; icon_state = "direction_med"; pixel_x = 30; pixel_z = 4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 9},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/hallway) +"gW" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/usedup,/area/ship/scrap/hidden) +"gX" = (/obj/structure/closet/crate,/obj/random/loot,/obj/random/loot,/obj/random/loot,/obj/random/projectile,/obj/random/projectile,/turf/simulated/floor/usedup,/area/ship/scrap/hidden) +"gY" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/atmos) +"gZ" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/autoname/engineering,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/atmos) +"ha" = (/turf/simulated/wall,/area/ship/scrap/maintenance/atmos) +"hb" = (/turf/simulated/wall,/area/ship/scrap/maintenance/engineering) +"hc" = (/obj/structure/disposalpipe/segment,/turf/simulated/wall,/area/ship/scrap/maintenance/engineering) +"hd" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/obj/machinery/door/airlock/autoname/engineering,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"he" = (/turf/simulated/wall,/area/ship/scrap/maintenance/power) +"hf" = (/obj/structure/cable{icon_state = "2-9"},/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/power) +"hg" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/power) +"hh" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 6},/obj/effect/floor_decal/corner/blue,/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"hi" = (/obj/machinery/atmospherics/binary/pump/on{dir = 8; target_pressure = 200},/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/effect/floor_decal/corner/blue{dir = 10},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"hj" = (/obj/effect/floor_decal/corner/blue{dir = 10},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"hk" = (/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{icon_state = "intact-scrubbers"; dir = 4},/obj/effect/floor_decal/corner/blue{dir = 8},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/power/apc/derelict{dir = 1},/mob/living/simple_animal/hostile/carp,/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"hl" = (/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{icon_state = "intact-scrubbers"; dir = 10},/obj/machinery/meter,/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/obj/machinery/light_switch{pixel_y = 25},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"hm" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/power/apc/derelict{dir = 1},/obj/structure/sign/warning/compressed_gas{pixel_x = -32},/obj/structure/bed/padded,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hn" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/alarm{pixel_y = 32},/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/structure/disposalpipe/trunk{icon_state = "pipe-t"; dir = 1},/obj/machinery/disposal,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"ho" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/device/radio/intercom{pixel_y = 32},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/structure/closet/toolcloset,/obj/item/weapon/storage/backpack/dufflebag/eng,/obj/item/stack/material/glass/reinforced/fifty,/obj/item/stack/material/steel/fifty,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hp" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hq" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/light_switch{pixel_y = 25},/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/structure/table/standard,/obj/item/weapon/reagent_containers/food/drinks/coffeecup/metal,/obj/item/weapon/reagent_containers/food/drinks/coffeecup/metal,/obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee{name = "coffee canister"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hr" = (/obj/structure/bed/chair/comfy/brown,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/structure/closet/hydrant{pixel_y = 32},/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hu" = (/obj/structure/table/standard,/obj/machinery/cell_charger,/obj/item/weapon/storage/toolbox/electrical{pixel_x = 7; pixel_y = 4},/obj/machinery/light_switch{pixel_y = 25},/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/cable{icon_state = "6-8"},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/power) +"hv" = (/obj/structure/table/standard,/obj/machinery/cell_charger,/obj/item/weapon/defibrillator/compact/loaded,/obj/item/device/flashlight,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/power) +"hw" = (/turf/space,/area/ship/scrap/maintenance/atmos) +"hx" = (/turf/simulated/floor/airless,/area/ship/scrap/maintenance/atmos) +"hy" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/effect/floor_decal/corner/blue/diagonal,/obj/effect/floor_decal/corner/blue/diagonal{dir = 4},/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/atmos) +"hz" = (/obj/machinery/atmospherics/portables_connector,/obj/effect/floor_decal/corner/blue{dir = 9},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"hA" = (/obj/machinery/atmospherics/pipe/simple/visible/supply{icon_state = "intact-supply"; dir = 6},/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{icon_state = "intact-scrubbers"; dir = 5},/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"hB" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/door/airlock/autoname/engineering,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/atmos) +"hC" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hD" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/structure/cable{icon_state = "4-10"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hE" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/ladder,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hF" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/effect/decal/cleanable/dirt,/obj/item/weapon/stool/padded,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 9},/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hG" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hH" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/effect/decal/cleanable/liquid_fuel,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hI" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/airlock/autoname/engineering,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/power) +"hJ" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/power) +"hK" = (/obj/machinery/power/sensor{long_range = 1; name_tag = "Main Grid"},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/power) +"hL" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/structure/cable{icon_state = "2-9"},/obj/machinery/recharge_station,/obj/structure/cable{icon_state = "2-8"},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/power) +"hM" = (/obj/item/stack/rods,/turf/space,/area/ship/scrap/maintenance/atmos) +"hN" = (/obj/item/weapon/material/shard,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/atmos) +"hO" = (/mob/living/simple_animal/hostile/carp,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/atmos) +"hP" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/atmospherics/unary/vent_pump/high_volume{icon_state = "map_vent_in"; dir = 4; use_power = 1; id_tag = "air_out"; pump_direction = 0; external_pressure_bound = 0; internal_pressure_bound = 2000; pressure_checks = 2; external_pressure_bound_default = 0; internal_pressure_bound_default = 2000; pressure_checks_default = 2; frequency = 1443},/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/atmos) +"hQ" = (/obj/machinery/meter,/obj/effect/floor_decal/corner/blue{dir = 9},/obj/machinery/atmospherics/pipe/manifold/visible/cyan{dir = 4},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"hR" = (/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/visible/supply,/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"hS" = (/obj/structure/closet/walllocker/emerglocker/west,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/obj/structure/cable{icon_state = "2-5"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hT" = (/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/obj/structure/closet/secure_closet/engineering_welding,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hU" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/obj/machinery/computer/engines,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hV" = (/obj/structure/cable,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/obj/structure/table/standard,/obj/machinery/button/remote/blast_door{id = "engwindow"; name = "Engine Observation"; pixel_x = 6},/obj/machinery/button/ignition{id = "engine"; pixel_x = -5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hW" = (/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/obj/machinery/light/small,/obj/item/modular_computer/console/preset/engineering,/obj/machinery/button/remote/blast_door{id = "scram"; name = "CORE SCRAM"; pixel_y = -26},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hX" = (/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/obj/effect/decal/cleanable/liquid_fuel,/obj/machinery/vending/cigarette,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hY" = (/obj/structure/reagent_dispensers/fueltank,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/obj/effect/decal/cleanable/liquid_fuel,/obj/structure/sign/warning/nosmoking_1{pixel_y = -32},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"hZ" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/mob/living/simple_animal/hostile/carp,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/power) +"ia" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/power) +"ib" = (/obj/machinery/power/breakerbox/activated,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/power) +"ic" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor,/obj/structure/window/reinforced{dir = 5; health = 1e+007},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/power) +"id" = (/obj/item/weapon/material/shard,/turf/space,/area/ship/scrap/maintenance/atmos) +"ie" = (/obj/item/stack/material/steel,/turf/space,/area/ship/scrap/maintenance/atmos) +"if" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/atmos) +"ig" = (/obj/effect/floor_decal/corner/white{icon_state = "corner_white"; dir = 9},/obj/machinery/atmospherics/pipe/simple/visible/cyan,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"ih" = (/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/obj/item/device/radio/intercom{dir = 8; pixel_x = 22},/obj/machinery/atmospherics/pipe/manifold/visible/supply{dir = 4},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"ii" = (/obj/machinery/door/firedoor,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/obj/machinery/door/airlock/autoname/engineering,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engine/aft) +"ij" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/engine/aft) +"ik" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "engwindow"; name = "blast door"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/engine/aft) +"il" = (/obj/machinery/light/small{dir = 8},/obj/structure/closet/crate/uranium,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/power) +"im" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/power) +"in" = (/obj/machinery/power/shield_generator,/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/power) +"io" = (/mob/living/simple_animal/hostile/carp,/turf/space,/area/ship/scrap/maintenance/atmos) +"ip" = (/obj/item/stack/material/plasteel,/turf/space,/area/ship/scrap/maintenance/atmos) +"iq" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/atmospherics/unary/outlet_injector{dir = 4; frequency = 1441; icon_state = "map_injector"; id = "n2_in"; use_power = 1},/obj/effect/floor_decal/corner/white/diagonal,/obj/effect/floor_decal/corner/white/diagonal{icon_state = "corner_white_diagonal"; dir = 4},/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/atmos) +"ir" = (/obj/machinery/atmospherics/omni/mixer{active_power_usage = 7500; tag_east = 0; tag_east_con = 0; tag_north = 1; tag_north_con = 0.21; tag_south = 1; tag_south_con = 0.79; tag_west = 2; use_power = 1},/obj/effect/floor_decal/corner/white{icon_state = "corner_white"; dir = 9},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"is" = (/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"iu" = (/obj/structure/sign/warning/fire{pixel_y = 32},/obj/machinery/atmospherics/portables_connector,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"iv" = (/obj/machinery/light_switch{pixel_y = 25},/obj/machinery/atmospherics/pipe/tank/carbon_dioxide,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"iw" = (/obj/machinery/atmospherics/portables_connector,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"ix" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"iy" = (/obj/machinery/atmospherics/portables_connector,/obj/machinery/portable_atmospherics/canister/phoron,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"iz" = (/obj/machinery/atmospherics/portables_connector,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"iA" = (/obj/structure/closet/radiation,/obj/machinery/button/remote/blast_door{id = "radaway"; name = "Radiation shields"; pixel_x = -24},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/power) +"iB" = (/obj/machinery/power/terminal{dir = 4},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/mob/living/simple_animal/hostile/carp,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/power) +"iC" = (/obj/structure/cable,/obj/machinery/power/smes/buildable,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/power) +"iD" = (/obj/effect/floor_decal/corner/white{icon_state = "corner_white"; dir = 9},/obj/machinery/atmospherics/pipe/simple/visible/cyan,/obj/machinery/atmospherics/binary/pump/on{dir = 4; name = "Air to Ports"},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"iE" = (/obj/machinery/atmospherics/pipe/manifold/visible/blue{icon_state = "map"; dir = 4},/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/obj/machinery/meter,/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"iF" = (/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/obj/machinery/power/apc/derelict{dir = 8},/obj/structure/cable,/obj/item/device/radio/intercom{pixel_x = -32},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"iG" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel{icon_state = "map"; dir = 8},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"iH" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/manifold/visible/fuel,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"iI" = (/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 9},/mob/living/simple_animal/hostile/carp,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"iJ" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"iL" = (/obj/machinery/atmospherics/omni/mixer{tag_north = 1; tag_north_con = 0.36; tag_south = 2; tag_west = 1; tag_west_con = 0.64},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"iM" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/door/window/southright,/obj/machinery/door/window/northleft,/obj/machinery/door/blast/regular/open{dir = 2; icon_state = "pdoor0"; id = "radaway"; layer = 5; opacity = 0},/obj/structure/sign{icon_state = "radiation"; pixel_x = -32},/obj/structure/sign{icon_state = "radiation"; pixel_x = 32},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/power) +"iN" = (/obj/item/stack/material/plasteel,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/power) +"iO" = (/obj/item/stack/rods,/mob/living/simple_animal/hostile/carp,/turf/space,/area/ship/scrap/maintenance/atmos) +"iP" = (/obj/item/stack/material/steel,/obj/item/stack/rods,/turf/space,/area/ship/scrap/maintenance/atmos) +"iQ" = (/obj/item/stack/material/plasteel,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/atmos) +"iR" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/unary/vent_pump/high_volume{icon_state = "map_vent_in"; dir = 4; use_power = 1; id_tag = "air_out"; pump_direction = 0; external_pressure_bound = 0; internal_pressure_bound = 2000; pressure_checks = 2; external_pressure_bound_default = 0; internal_pressure_bound_default = 2000; pressure_checks_default = 2; frequency = 1443},/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/atmos) +"iS" = (/obj/machinery/meter,/obj/effect/floor_decal/corner/red{dir = 9},/obj/machinery/atmospherics/pipe/manifold/visible/cyan{dir = 4},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"iT" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/obj/machinery/portable_atmospherics/powered/pump/filled,/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"iU" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/machinery/atmospherics/valve/shutoff,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"iV" = (/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction,/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/engine/aft) +"iW" = (/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/machinery/meter/turf,/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 6},/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/engine/aft) +"iX" = (/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 4},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/machinery/atmospherics/unary/outlet_injector{dir = 4; icon_state = "map_injector"; use_power = 1},/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 10},/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/engine/aft) +"iY" = (/obj/structure/window/phoronreinforced,/obj/machinery/atmospherics/binary/pump{dir = 8},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"iZ" = (/obj/machinery/atmospherics/pipe/simple/visible/green{icon_state = "intact"; dir = 4},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"ja" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/simple/visible/green{dir = 9; icon_state = "intact"},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jb" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/door/blast/regular/open{dir = 2; icon_state = "pdoor0"; id = "radaway"; layer = 5; opacity = 0},/obj/machinery/meter/turf,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/power) +"jc" = (/obj/item/stack/rods,/turf/space,/area/ship/scrap/maintenance/power) +"jd" = (/obj/structure/window/reinforced{dir = 4},/obj/effect/floor_decal/corner/red/diagonal{icon_state = "corner_white_diagonal"; dir = 4},/obj/effect/floor_decal/corner/red/diagonal,/obj/structure/window/reinforced{dir = 2; health = 1e+007},/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/atmos) +"je" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/effect/floor_decal/corner/red{dir = 9},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"jf" = (/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/obj/machinery/meter,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jg" = (/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/machinery/atmospherics/pipe/simple/heat_exchanging,/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/engine/aft) +"jh" = (/obj/machinery/igniter{id = "engine"},/obj/machinery/atmospherics/pipe/simple/heat_exchanging,/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/engine/aft) +"ji" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging,/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/engine/aft) +"jj" = (/obj/machinery/door/blast/regular{id = "scram"},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jk" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jl" = (/obj/item/device/radio/intercom{dir = 8; pixel_x = 22},/obj/machinery/light/small{dir = 4},/obj/machinery/portable_atmospherics/canister/empty,/obj/machinery/atmospherics/portables_connector,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jm" = (/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/power) +"jn" = (/obj/item/stack/material/steel,/turf/space,/area/ship/scrap/maintenance/power) +"jo" = (/turf/space,/area/ship/scrap/maintenance/power) +"jp" = (/obj/item/stack/material/steel,/turf/space,/area/space) +"jr" = (/obj/effect/floor_decal/corner/red{dir = 1},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"js" = (/obj/machinery/atmospherics/valve/open,/obj/item/weapon/material/shard/phoron,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jt" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 5},/turf/simulated/floor/reinforced,/area/ship/scrap/maintenance/engine/aft) +"ju" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 9},/turf/simulated/floor/reinforced,/area/ship/scrap/maintenance/engine/aft) +"jv" = (/obj/structure/window/phoronreinforced,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 4},/obj/machinery/atmospherics/unary/vent_pump/engine{dir = 4; external_pressure_bound = 4000; external_pressure_bound_default = 4000; icon_state = "map_vent"; pump_direction = 0; use_power = 1},/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{dir = 1},/turf/simulated/floor/reinforced,/area/ship/scrap/maintenance/engine/aft) +"jw" = (/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/machinery/atmospherics/binary/pump{dir = 4},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jx" = (/obj/machinery/atmospherics/pipe/simple/hidden/black{icon_state = "intact"; dir = 4},/obj/machinery/meter,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jy" = (/obj/machinery/atmospherics/omni/filter{tag_east = 2; tag_north = 6; tag_south = 5; tag_west = 1; use_power = 0},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jz" = (/obj/machinery/atmospherics/pipe/simple/hidden/black{icon_state = "intact"; dir = 4},/turf/simulated/wall,/area/ship/scrap/maintenance/power) +"jA" = (/obj/machinery/atmospherics/pipe/simple/hidden/black{icon_state = "intact"; dir = 10},/turf/simulated/wall,/area/ship/scrap/maintenance/power) +"jB" = (/obj/item/stack/rods,/turf/space,/area/space) +"jC" = (/obj/structure/table/standard,/obj/item/device/multitool{pixel_x = 5},/obj/item/weapon/cartridge/atmos,/obj/item/weapon/cartridge/atmos,/obj/item/device/pipe_painter,/obj/item/clamp,/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/atmos) +"jD" = (/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{dir = 8},/obj/machinery/space_heater,/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"jE" = (/obj/machinery/pipedispenser,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{dir = 8},/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) +"jF" = (/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jG" = (/obj/item/weapon/material/shard/phoron,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jH" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jI" = (/obj/machinery/atmospherics/valve/open{icon_state = "map_valve1"; dir = 4},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jK" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/canister/empty,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jL" = (/obj/machinery/door/blast/regular{id = "scram"},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/engine/aft) +"jM" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; external_pressure_bound = 140; external_pressure_bound_default = 140; icon_state = "map_vent_out"; pressure_checks = 1; pressure_checks_default = 1; use_power = 1},/turf/simulated/floor/usedup,/area/ship/scrap/maintenance/engine/aft) +"jN" = (/obj/item/stack/material/steel,/obj/item/stack/rods,/turf/space,/area/ship/scrap/maintenance/engine/aft) +"jO" = (/turf/space,/area/ship/scrap/maintenance/engine/aft) +"jP" = (/obj/structure/window/reinforced,/obj/machinery/atmospherics/pipe/manifold/visible/fuel{icon_state = "map"; dir = 1},/obj/effect/floor_decal/industrial/warning,/mob/living/simple_animal/hostile/carp,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jQ" = (/obj/structure/window/reinforced,/obj/machinery/atmospherics/pipe/manifold/visible/fuel{icon_state = "map"; dir = 1},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jR" = (/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/manifold/visible/fuel{icon_state = "map"; dir = 4},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jS" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/light/small,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jT" = (/mob/living/simple_animal/hostile/carp,/turf/space,/area/ship/scrap/maintenance/engine/aft) +"jU" = (/obj/item/stack/material/plasteel,/turf/space,/area/ship/scrap/maintenance/engine/aft) +"jV" = (/obj/item/stack/material/steel,/turf/space,/area/ship/scrap/maintenance/engine/aft) +"jW" = (/obj/machinery/atmospherics/unary/engine{icon_state = "nozzle"; dir = 1},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jX" = (/obj/item/stack/rods,/turf/space,/area/ship/scrap/maintenance/engine/aft) +"jY" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/sign/warning/hot_exhaust{pixel_y = 32},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"jZ" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"uf" = (/obj/machinery/atmospherics/pipe/simple/visible/green{icon_state = "intact"; dir = 5},/obj/effect/decal/cleanable/ash,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"Dr" = (/obj/structure/closet/secure_closet/engineering_electrical,/obj/item/weapon/cell/device/standard,/obj/item/weapon/cell/device/standard,/obj/machinery/power/apc/derelict{dir = 8},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/item/device/radio/intercom{pixel_y = 32},/obj/item/weapon/cell/crap,/obj/item/weapon/cell/crap,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/power) +"Jy" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/fireaxecabinet{pixel_y = 32},/obj/item/weapon/cell/potato,/turf/simulated/floor/tiled/usedup,/area/ship/scrap/fire) +"JC" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/structure/sign/warning/high_voltage{pixel_x = 32},/obj/structure/table/standard,/obj/item/toy/prize/ripley,/obj/item/weapon/material/ashtray/plastic,/obj/machinery/recharger,/obj/structure/sign/poster{pixel_y = 32},/turf/simulated/floor/tiled/usedup,/area/ship/scrap/maintenance/engineering) +"Mp" = (/obj/structure/closet/crate,/obj/random/loot,/obj/random/loot,/obj/item/weapon/disk/tech_disk,/obj/item/weapon/disk/tech_disk,/obj/item/weapon/disk/design_disk,/obj/machinery/alarm{pixel_y = 32},/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/item/weapon/cell/high,/turf/simulated/floor/usedup,/area/ship/scrap/hidden) +"PP" = (/obj/machinery/power/apc/derelict{name = "Medical Bay APC"},/obj/structure/cable{d2 = 6; icon_state = "0-6"},/obj/machinery/power/port_gen/pacman/super,/turf/simulated/floor/usedup,/area/ship/scrap/hidden) +"Qe" = (/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 10},/obj/machinery/meter,/obj/effect/decal/cleanable/ash,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"Sm" = (/obj/structure/closet/walllocker/emerglocker/west,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/effect/decal/cleanable/molten_item,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"Wu" = (/obj/effect/decal/cleanable/molten_item,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"YS" = (/obj/effect/floor_decal/corner/red{dir = 5},/obj/effect/decal/cleanable/ash,/turf/simulated/floor/tiled/airless,/area/ship/scrap/maintenance/atmos) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacadacaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafagahagafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaiajakafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalamanaoalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapaqaaaaarasatauavawataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaraxatayazaAataBaCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaararaDararaEaCaCaFaCaCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaraGaHaIaraJaCaKaLaMaCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaNaOaHaPaQaRaSaTaUaVaWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaraXaHaYaraZaCbabbbcaCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaararaDararaZaCaCbdaCaCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabebebfbebeaaaaaaaaaaaaaaaaaaaaaabgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabgaaaaaaaaaaaaaaaabebhbibebjbkblbebhbibeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabmbebebebnbobpbqbrbqbpbsbtbebebebmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabubvbwbxbybzbebAbBbCbebDbEbFbGbHbIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabJbJbKbLbMbNbebebObebebPbQbRbKbSbJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabTbebUbebebVbWbXbebebUbebTbYbYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYbZcacbaaccbWcdaacecfcgbYaabYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYbZcachchchcichchchcjcgbYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYbZcackclcmcncocpckcfcgbYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYcqcrcscrcrctckcucvcwcxcyckczcAcBcCcDcAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacqcEcFcGcqcHckcIcJcKcJcLckcMcBcNcOcPcAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacQcRcScTcUcVcWcXcYcZdadbcWdcdddedfdgdhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacrdidjdkcqdldmdndodpdqdrckdscBdtdudgcAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadvdwdwdwdwdxdydydydzdydydydAdBdBdCdBdDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadvdEdFdGdwdHdydIdJdKdLdMdydNdBdOdPdQdDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadRdRbYbYdSdTdUdVdwdWdydXdYdZeaebdyecedeeefegdDbYbYehehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadRdRdRdRbYeiejekelemeneoepeqereseteoeuevewexeyezbYehehehehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadReAeBeCeDdweEeFeGdweHdyeIeJeKeLeMdyeNdBeOePeQdDeReSeTeUehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadReVeWdReXeYeYeYeYeYeZdyfafbfcfdfedyffdBdBdDdBdDfgfhfifjehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafkflflfkfmfnfofpfqfrfsdyftftftftfudyfvfwfxfyfzfAfmfBfCfCfDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafEaaaafFfGfHfIfJfKeYfLdyftfMftftfNdyfOfPfQfRfSfTfUfFaaaafEaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYbYeYfVfWfXeYfYdyftftftftfZdygafPgbgcgdfPbYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagegfgfgegeggdyftftftftghgigjgkglglglgkbYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagegmJygogegpdyftftgqgrgsdygtgkMpgvgwgkbYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagxgygzgAgBgCgDdydydydzdydydygEgFgGgHgIgkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagegJgKgLgfgMgNgOgPgQgRgSgTgUgkPPgWgXgkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagYgYgYgZhahahahbhchbhdhbhbhbhehehehfhggkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYgYhhhihjhkhlhahmhnhohphqhrJCheDrhuhvhgbYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahwhxhxhxhyhzhAhBhChDhEhFhGhGhHhIhJhKhLhgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahMhwhNhOhPhQhRgYhShThUhVhWhXhYhehZiaibicaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaidieiehxifigihgYiiijijikijijijhgiliminhgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahwioipidhxiqirisgYSmiuiviwixiyizheiAiBiChgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaidhwhwhxhPiDiEgYiFiGiHiIiJufiLhghgiMhgiNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiOiPiQhNiRiSiTgYiUiViWiXiYiZjahghgjbiNjcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahwhwhxhxjdjeisgYjfjgjhjijjjkjlhghgjmjnjojpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaidhwhNYSjrisgYjsjtjujvjwjxjyjzjAjcjnjojBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahwiehxjCjDjEhxWujGjGjHjIQejKjLjMbYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahMhxgYgYjNjOjFWujPjQjRjSjLbYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajTjUjVjFjWjWjWjFijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajVjXjFjFjFjFjYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajOjUjFjFjFjFjZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/bearcat/bearcat.dm b/maps/away/bearcat/bearcat.dm new file mode 100644 index 00000000..7343557d --- /dev/null +++ b/maps/away/bearcat/bearcat.dm @@ -0,0 +1,125 @@ +#include "bearcat_areas.dm" + +/obj/effect/overmap/ship/bearcat + name = "light freighter" + color = "#00FFFF" + vessel_mass = 60 + default_delay = 3 MINUTES + speed_mod = 0.1 MINUTE + burn_delay = 10 SECONDS + +/obj/effect/overmap/ship/bearcat/New() + name = "[pick("FTV","ITV","IEV")] [pick("Bearcat", "Firebug", "Defiant", "Unsinkable","Horizon","Vagrant")]" + for(var/area/ship/scrap/A) + A.name = "\improper [name] - [A.name]" + GLOB.using_map.area_purity_test_exempt_areas += A.type + name = "[name], \a [initial(name)]" + ..() + +/datum/map_template/ruin/away_site/bearcat_wreck + name = "Bearcat Wreck" + id = "awaysite_bearcat_wreck" + description = "A wrecked light freighter." + suffixes = list("bearcat/bearcat-1.dmm", "bearcat/bearcat-2.dmm") + cost = 1 + shuttles_to_initialise = list(/datum/shuttle/autodock/ferry/lift) + +/datum/shuttle/autodock/ferry/lift + name = "Cargo Lift" + shuttle_area = /area/ship/scrap/shuttle/lift + warmup_time = 3 //give those below some time to get out of the way + waypoint_station = "nav_bearcat_lift_bottom" + waypoint_offsite = "nav_bearcat_lift_top" + sound_takeoff = 'sound/effects/lift_heavy_start.ogg' + sound_landing = 'sound/effects/lift_heavy_stop.ogg' + ceiling_type = null + knockdown = 0 + defer_initialisation = TRUE + +/obj/machinery/computer/shuttle_control/lift + name = "cargo lift controls" + shuttle_tag = "Cargo Lift" + ui_template = "shuttle_control_console_lift.tmpl" + icon_state = "tiny" + icon_keyboard = "tiny_keyboard" + icon_screen = "lift" + density = 0 + +/obj/effect/shuttle_landmark/lift/top + name = "Top Deck" + landmark_tag = "nav_bearcat_lift_top" + autoset = 1 + +/obj/effect/shuttle_landmark/lift/bottom + name = "Lower Deck" + landmark_tag = "nav_bearcat_lift_bottom" + base_area = /area/ship/scrap/cargo/lower + base_turf = /turf/simulated/floor + +/obj/machinery/power/apc/derelict + cell_type = /obj/item/weapon/cell/crap/empty + lighting = 0 + equipment = 0 + environ = 0 + locked = 0 + coverlocked = 0 + +/obj/machinery/door/airlock/autoname/command + icon = 'icons/obj/doors/Doorhatchele.dmi' + req_access = list(access_heads) + +/obj/machinery/door/airlock/autoname/engineering + req_access = list(access_engine) + +/turf/simulated/floor/usedup + initial_gas = list("carbon_dioxide" = MOLES_O2STANDARD, "nitrogen" = MOLES_N2STANDARD) + +/turf/simulated/floor/wood/usedup + initial_gas = list("carbon_dioxide" = MOLES_O2STANDARD, "nitrogen" = MOLES_N2STANDARD) + +/turf/simulated/floor/tiled/usedup + initial_gas = list("carbon_dioxide" = MOLES_O2STANDARD, "nitrogen" = MOLES_N2STANDARD) + +/turf/simulated/floor/tiled/dark/usedup + initial_gas = list("carbon_dioxide" = MOLES_O2STANDARD, "nitrogen" = MOLES_N2STANDARD) + +/turf/simulated/floor/tiled/white/usedup + initial_gas = list("carbon_dioxide" = MOLES_O2STANDARD, "nitrogen" = MOLES_N2STANDARD) + +/obj/effect/landmark/deadcap + name = "Dead Captain" + delete_me = 1 + +/obj/effect/landmark/deadcap/Initialize() + var/turf/T = get_turf(src) + var/mob/living/carbon/human/corpse = new(T) + scramble(1,corpse,100) + corpse.real_name = "Captain" + corpse.name = "Captain" + var/decl/hierarchy/outfit/outfit = outfit_by_type(/decl/hierarchy/outfit/deadcap) + outfit.equip(corpse) + corpse.adjustOxyLoss(corpse.maxHealth) + corpse.setBrainLoss(corpse.maxHealth) + var/obj/structure/bed/chair/C = locate() in T + if(C) + C.buckle_mob(corpse) + . = ..() + +/decl/hierarchy/outfit/deadcap + name = "Derelict Captain" + uniform = /obj/item/clothing/under/casual_pants/classicjeans + suit = /obj/item/clothing/suit/storage/hooded/wintercoat + shoes = /obj/item/clothing/shoes/black + r_pocket = /obj/item/device/radio + +/decl/hierarchy/outfit/deadcap/post_equip(mob/living/carbon/human/H) + ..() + var/obj/item/clothing/uniform = H.w_uniform + if(uniform) + var/obj/item/clothing/accessory/toggleable/hawaii/random/eyegore = new() + if(uniform.can_attach_accessory(eyegore)) + uniform.attach_accessory(null, eyegore) + else + qdel(eyegore) + var/obj/item/weapon/cell/super/C = new() + H.put_in_any_hand_if_possible(C) diff --git a/maps/away/bearcat/bearcat_areas.dm b/maps/away/bearcat/bearcat_areas.dm new file mode 100644 index 00000000..41ef1737 --- /dev/null +++ b/maps/away/bearcat/bearcat_areas.dm @@ -0,0 +1,167 @@ +/area/ship/scrap + name = "Generic Ship" + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg') + +/area/ship/scrap/crew + name = "Crew Compartements" + icon_state = "crew_quarters" + +/area/ship/scrap/crew/hallway/port + name = "Crew Hallway - Port" + +/area/ship/scrap/crew/hallway/starboard + name = "Crew Hallway - Starboard" + +/area/ship/scrap/crew/kitchen + name = "Galley" + icon_state = "kitchen" + +/area/ship/scrap/crew/cryo + name = "Cryo Storage" + icon_state = "cryo" + +/area/ship/scrap/crew/dorms1 + name = "Crew Cabin #1" + icon_state = "green" + +/area/ship/scrap/crew/dorms2 + name = "Crew Cabin #2" + icon_state = "purple" + +/area/ship/scrap/crew/dorms3 + name = "Crew Cabin #3" + icon_state = "yellow" + +/area/ship/scrap/crew/saloon + name = "Saloon" + icon_state = "conference" + +/area/ship/scrap/crew/toilets + name = "Bathrooms" + icon_state = "toilet" + turf_initializer = /decl/turf_initializer/maintenance + +/area/ship/scrap/crew/wash + name = "Washroom" + icon_state = "locker" + +/area/ship/scrap/crew/medbay + name = "Medical Bay" + icon_state = "medbay" + +/area/ship/scrap/cargo + name = "Cargo Hold" + icon_state = "quartstorage" + +/area/ship/scrap/cargo/lower + name = "Lower Cargo Hold" + +/area/ship/scrap/dock + name = "Docking Bay" + icon_state = "entry_1" + +/area/ship/scrap/fire + name = "Firefighting Equipment Comparment" + icon_state = "green" + +/area/ship/scrap/unused + name = "Compartment 2-B" + icon_state = "yellow" + turf_initializer = /decl/turf_initializer/maintenance + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambimo1.ogg','sound/ambience/ambimo2.ogg') + +/area/ship/scrap/hidden + name = "Unknown" //shielded compartment + icon_state = "auxstorage" + +/area/ship/scrap/escape_port + name = "Port Escape Pods" + icon_state = "green" + +/area/ship/scrap/escape_star + name = "Starboard Escape Pods" + icon_state = "yellow" + +/area/ship/scrap/broken1 + name = "Robotic Maintenance" + icon_state = "green" + +/area/ship/scrap/broken2 + name = "Compartment 1-B" + icon_state = "yellow" + +/area/ship/scrap/gambling + name = "Compartment 1-C" + icon_state = "cave" + +/area/ship/scrap/maintenance + name = "Maintenance Compartments" + icon_state = "amaint" + +/area/ship/scrap/maintenance/hallway + name = "Maintenance Corridors" + +/area/ship/scrap/maintenance/lower + name = "Lower Deck Maintenance Compartments" + icon_state = "sub_maint_aft" + +/area/ship/scrap/maintenance/storage + name = "Tools Storage" + icon_state = "engineering_storage" + +/area/ship/scrap/maintenance/techstorage + name = "Parts Storage" + icon_state = "engineering_supply" + +/area/ship/scrap/maintenance/eva + name = "EVA Storage" + icon_state = "eva" + +/area/ship/scrap/maintenance/engineering + name = "Engineering Bay" + icon_state = "engineering_supply" + +/area/ship/scrap/maintenance/atmos + name = "Atmospherics Comparment" + icon_state = "atmos" + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambiatm1.ogg') + +/area/ship/scrap/maintenance/power + name = "Power Compartment" + icon_state = "engine_smes" + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambieng1.ogg') + +/area/ship/scrap/maintenance/engine + icon_state = "engine" + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambieng1.ogg') + +/area/ship/scrap/maintenance/engine/aft + name = "Main Engine Bay" + +/area/ship/scrap/maintenance/engine/port + name = "Port Thruster" + +/area/ship/scrap/maintenance/engine/starboard + name = "Starboard Thruster" + +/area/ship/scrap/command/hallway + name = "Command Deck" + icon_state = "centcom" + +/area/ship/scrap/command/bridge + name = "Bridge" + icon_state = "bridge" + +/area/ship/scrap/command/captain + name = "Captain's Quarters" + icon_state = "captain" + +/area/ship/scrap/comms + name = "Communications Relay" + icon_state = "tcomsatcham" + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/signal.ogg','sound/ambience/sonar.ogg') + +/area/ship/scrap/shuttle/lift + name = "Cargo Lift" + icon_state = "shuttle3" + base_turf = /turf/simulated/open \ No newline at end of file diff --git a/maps/away/blueriver/backup/blueriver-1.dmm b/maps/away/blueriver/backup/blueriver-1.dmm new file mode 100644 index 00000000..ef3ecd2e --- /dev/null +++ b/maps/away/blueriver/backup/blueriver-1.dmm @@ -0,0 +1,129 @@ +"a" = (/turf/unsimulated/mineral{temperature = 233},/area/bluespaceriver/underground) +"b" = (/turf/unsimulated/wall/supermatter/no_spread,/area/bluespaceriver/underground) +"c" = (/turf/unsimulated/wall/away/blueriver/livingwall,/area/bluespaceriver/underground) +"d" = (/turf/unsimulated/wall/supermatter/no_spread{plane = -19},/area/bluespaceriver/underground) +"e" = (/obj/machinery/crystal_static{alpha = 120; anchored = 1; color = "BLUE"; desc = "Slightly transparent. You are not sure what it is."},/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"f" = (/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"g" = (/obj/machinery/replicator{alpha = 150; anchored = 1; color = "BLUE"},/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"h" = (/obj/item/weapon/pickaxe/brush,/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"i" = (/obj/item/weapon/pickaxe/six_pick,/obj/item/device/measuring_tape,/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"j" = (/obj/item/device/camera,/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"k" = (/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"l" = (/obj/item/weapon/gun/energy/plasmacutter,/obj/item/device/depth_scanner,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"m" = (/mob/living/simple_animal/hostile/hive_alien/defender,/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"n" = (/obj/item/roller,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"o" = (/obj/structure/ladder/up,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"p" = (/obj/structure/catwalk,/turf/simulated/floor/plating,/area/bluespaceriver/underground) +"q" = (/obj/item/weapon/crowbar,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"r" = (/obj/structure/barricade,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"s" = (/obj/item/weapon/cell/infinite{alpha = 130; color = "BLUE"; desc = "This looks like an alien power cell. You can make out both of the connections relatively clearly though."; icon = 'icons/obj/grenade.dmi'; icon_state = "delivery"; name = "alien power cell"},/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"t" = (/obj/item/device/geiger,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"u" = (/obj/item/weapon/pickaxe/drill,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"v" = (/obj/structure/deity{alpha = 130; color = "BLUE"; desc = "Looks like an eerie transparent table. It emits a soft glow. "},/obj/item/weapon/gun/energy/decloner{color = "BLUE"; desc = "A strange unerganomic pistol clearly not designed for a human hand. You are surprised that it actually has a trigger."; name = "strange gun"},/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"w" = (/obj/structure/closet/excavation,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"x" = (/obj/machinery/crystal_static{alpha = 120; anchored = 1; color = "BLUE"; desc = "Slightly transparent. You are not sure what it is."},/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"y" = (/obj/machinery/giga_drill{alpha = 129; color = "BLUE"},/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"z" = (/obj/machinery/artifact{alpha = 123; anchored = 0; color = "BLUE"},/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaababbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbcccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbcccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbcdefcccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbceegfccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbcfhiefccacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbccbbbbbbbcfjffccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbcccbbbbbbbcffffcccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbcccbbbbbbbcffffeccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbcccbbbbbacffefffcccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbcbbbbaacffffeffccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaackccccccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbaaklaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbccbbbbbbaaakkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbccbbbbbbbaaakkaaaaaaaaaccccccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaakkaaaaaaaaacceeeffcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbaakkaaaaaaaaccccefmfcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaakkkkbbbbbbbbbbbbbbaaknaaaaaaaaceffffeccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaakokkkkppppppppppppkkkkkkkkkkkqrfffffsccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaakkkkkkbbbbbbbbbbbbtkkkkkkkkkkurfffffvccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaawkkkkbbbbbbbbbbbbbaaxkaaaaaaaaceyfffcccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbaakkaaaaaaaaccfffcccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbaakkaaaaaaaaaccezcccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbcbbbbbbbaakkaaaaaaaaacccccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbcccbbbbbbaakkaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbcbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/blueriver/blueriver-1.dmm b/maps/away/blueriver/blueriver-1.dmm new file mode 100644 index 00000000..bddcda30 --- /dev/null +++ b/maps/away/blueriver/blueriver-1.dmm @@ -0,0 +1,129 @@ +"a" = (/turf/unsimulated/mineral{temperature = 233},/area/bluespaceriver/underground) +"b" = (/turf/unsimulated/wall/supermatter/no_spread,/area/bluespaceriver/underground) +"c" = (/turf/unsimulated/wall/away/blueriver/livingwall,/area/bluespaceriver/underground) +"d" = (/turf/unsimulated/wall/supermatter/no_spread{plane = -19},/area/bluespaceriver/underground) +"e" = (/obj/machinery/crystal_static{alpha = 120; anchored = 1; color = "BLUE"; desc = "Slightly transparent. You are not sure what it is."},/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"f" = (/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"g" = (/obj/machinery/replicator{alpha = 150; anchored = 1; color = "BLUE"},/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"h" = (/obj/item/weapon/pickaxe/brush,/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"i" = (/obj/item/weapon/pickaxe/six_pick,/obj/item/device/measuring_tape,/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"j" = (/obj/item/device/camera,/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"k" = (/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"l" = (/obj/item/weapon/gun/energy/plasmacutter,/obj/item/device/depth_scanner,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"m" = (/mob/living/simple_animal/hostile/hive_alien/defender,/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"n" = (/obj/item/roller,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"o" = (/obj/structure/ladder/up,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"p" = (/obj/structure/catwalk,/turf/simulated/floor/plating,/area/bluespaceriver/underground) +"q" = (/obj/item/weapon/crowbar,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"r" = (/obj/structure/barricade,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"s" = (/obj/item/weapon/cell/infinite{alpha = 130; color = "BLUE"; desc = "This looks like an alien power cell. You can make out both of the connections relatively clearly though."; icon = 'icons/obj/grenade.dmi'; icon_state = "delivery"; name = "alien power cell"},/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"t" = (/obj/item/device/geiger,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"u" = (/obj/item/weapon/pickaxe/drill,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"v" = (/obj/structure/deity{alpha = 130; color = "BLUE"; desc = "Looks like an eerie transparent table. It emits a soft glow. "},/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"w" = (/obj/structure/closet/excavation,/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"x" = (/obj/machinery/crystal_static{alpha = 120; anchored = 1; color = "BLUE"; desc = "Slightly transparent. You are not sure what it is."},/turf/simulated/floor/asteroid,/area/bluespaceriver/underground) +"y" = (/obj/machinery/giga_drill{alpha = 129; color = "BLUE"},/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) +"z" = (/obj/machinery/artifact{alpha = 123; anchored = 0; color = "BLUE"},/turf/simulated/floor/away/blueriver/alienfloor,/area/bluespaceriver/underground) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaababbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbcccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbcccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbcdefcccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbceegfccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbcfhiefccacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbccbbbbbbbcfjffccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbcccbbbbbbbcffffcccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbcccbbbbbbbcffffeccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbcccbbbbbacffefffcccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbcbbbbaacffffeffccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaackccccccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbaaklaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbccbbbbbbaaakkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbccbbbbbbbaaakkaaaaaaaaaccccccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaakkaaaaaaaaacceeeffcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbaakkaaaaaaaaccccefmfcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaakkkkbbbbbbbbbbbbbbaaknaaaaaaaaceffffeccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaakokkkkppppppppppppkkkkkkkkkkkqrfffffsccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaakkkkkkbbbbbbbbbbbbtkkkkkkkkkkurfffffvccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaawkkkkbbbbbbbbbbbbbaaxkaaaaaaaaceyfffcccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbaakkaaaaaaaaccfffcccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbaakkaaaaaaaaaccezcccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbcbbbbbbbaakkaaaaaaaaacccccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbcccbbbbbbaakkaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbcbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/away/blueriver/blueriver-2.dmm b/maps/away/blueriver/blueriver-2.dmm new file mode 100644 index 00000000..99e9521e --- /dev/null +++ b/maps/away/blueriver/blueriver-2.dmm @@ -0,0 +1,237 @@ +"aa" = (/turf/unsimulated/mineral{temperature = 233},/area/bluespaceriver/ground) +"ab" = (/turf/unsimulated/mask{temperature = 230},/area/bluespaceriver/ground) +"ac" = (/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"ad" = (/obj/structure/flora/grass/brown,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"ae" = (/obj/structure/flora/tree/pine,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"af" = (/obj/structure/flora/bush,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"ag" = (/obj/structure/flora/bush,/obj/structure/flora/grass/both,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"ah" = (/obj/structure/flora/grass/green,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"ai" = (/obj/structure/flora/grass/both,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"aj" = (/obj/structure/flora/ausbushes/brflowers,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"ak" = (/obj/effect/shuttle_landmark/nav_blueriv/nav3,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"al" = (/obj/effect/overmap/sector/arcticplanet{desc = "Sensor array an arctic planet with a small vessle on the surface. The vessle is located in the western region of a plateu surrounded by mineral rich mountains on all four sides. Scans further indicate strange energy levels below the planet's surface. Sunrise expected in 56 hours."},/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"am" = (/obj/effect/shuttle_landmark/nav_blueriv/nav1,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"an" = (/obj/effect/wingrille_spawn/reinforced/full,/turf/simulated/floor,/area/bluespaceriver/ship) +"ao" = (/obj/machinery/computer/power_monitor,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"ap" = (/obj/machinery/computer/helm,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aq" = (/obj/machinery/computer/sensors,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"ar" = (/obj/machinery/computer/engines,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"as" = (/obj/machinery/light,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ship) +"at" = (/obj/structure/table/reinforced,/obj/machinery/recharger/wallcharger{pixel_y = -24},/obj/item/weapon/storage/pill_bottle/antitox,/obj/item/weapon/cell,/obj/item/weapon/storage/box/matches,/obj/random/maintenance/clean,/obj/random/cash,/obj/item/weapon/paper{info = "We've landed, and aside from the permafrost, there's not a lot to mention on this rock. The readings are strongest in the middle of an open field near the ship, but there's nothing there, meaning we really only have one choice. Digging down. One of the others thinks theres a good chance that it's underground, so we might as well see if they're onto something. We don't have any other decent plans, and we need this find. Fortunate we brought the larger scale excavation equipment."},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"au" = (/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"av" = (/obj/structure/bed/chair/comfy/black{dir = 1},/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aw" = (/obj/structure/bed/chair/comfy/black{dir = 1},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"ax" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/machinery/light,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"ay" = (/turf/simulated/wall/titanium,/area/bluespaceriver/ship) +"az" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/wall/titanium,/area/bluespaceriver/ship) +"aA" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/wall/titanium,/area/bluespaceriver/ship) +"aB" = (/obj/machinery/door/airlock/command,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aC" = (/obj/machinery/vending/boozeomat,/turf/simulated/wall/titanium,/area/bluespaceriver/ship) +"aD" = (/obj/machinery/computer/rdconsole,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aE" = (/obj/machinery/r_n_d/server,/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aF" = (/obj/structure/handrai,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aG" = (/obj/machinery/door/airlock/science,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aH" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/handrai,/obj/item/weapon/stool/padded,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aI" = (/obj/machinery/vending/wallmed1{name = "Emergency NanoMed"; pixel_x = 0; pixel_y = 29},/obj/structure/table/woodentable,/obj/item/pizzabox,/obj/machinery/light{dir = 1},/obj/item/weapon/material/knife,/obj/item/weapon/paper{info = "Well, it didn't take the three days I was betting on, so i'm out twenty bucks, but we managed to punch through into a cave of some sort with the drilling equipment. We're lowering a ladder down now and sending one of the guards down to check that there's no spiders in there or anything. Once they report back, we'll Move the whole basecamp down there, and- SO, We've moved down into the cave now, and what we've found is astounding! It looks a LOT like a lake or river of blue goo, but... not? I took some scans, but couldn't pick anything up aside from radiation spikes from the pool. I also lowered a swab into the fluid to take a sample, but when I touched the swab to the surface of the... Fluid? the Swab just... Ceased And yes, that's the best way to describe it. it just stopped existing in my hand. We figure it's best we DON'T touch the blue stuff for now. one of our help has started moving supplies down into the cave to build a bridge of sorts though across the pool. We spotted some sort of structure on the far side, and the bridge is the only way to get to it, so now we wait."},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/item/weapon/stool/padded,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aK" = (/obj/random/maintenance/clean,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aL" = (/obj/structure/table/steel,/obj/machinery/chemical_dispenser/bar_coffee,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aM" = (/obj/machinery/r_n_d/protolathe,/obj/item/weapon/paper{info = "Well, it only took three weeks... this trip... but we finally found something worth investigating! An energy signature, just on or under the planet's surface. It's bizarre, similar to a bluespace signature, but... not. I'll need to get down there to really get a reading on it, but this could be the kind of discovery that makes a career. We've identified a landing site, so our pilot is setting the ship down there in the next couple of hours. it'll take some more time after that to set up a base camp and such."},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aN" = (/obj/structure/bed/chair/office/light,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aO" = (/obj/machinery/smartfridge/chemistry,/turf/simulated/wall/titanium,/area/bluespaceriver/ship) +"aP" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/stool/padded,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aQ" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/lunchbox/nt,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aR" = (/obj/structure/table/steel,/obj/item/weapon/storage/box/glasses/mug,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aS" = (/obj/structure/table/steel,/obj/machinery/microwave,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aT" = (/obj/machinery/r_n_d/destructive_analyzer,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aU" = (/obj/machinery/chemical_dispenser,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aV" = (/obj/machinery/chem_master,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aW" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/alarm{alarm_id = "petrov3"; dir = 4; pixel_x = -25; pixel_y = 0; rcon_setting = 3},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aX" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aY" = (/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"aZ" = (/obj/structure/table/steel,/obj/machinery/atmospherics/unary/vent_pump/on,/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/random/maintenance/clean,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"ba" = (/obj/effect/wingrille_spawn/reinforced/full,/turf/simulated/floor/plating,/area/bluespaceriver/ship) +"bb" = (/obj/machinery/r_n_d/circuit_imprinter,/obj/item/device/ano_scanner,/obj/item/weapon/paper{info = "I don't understand where they could have gone, but one of the researchers and a guard disappeared last night. We've started looking for them, figuring maybe they got trapped somewhere in the ruins, maybe a booby trap or something that was still functioning, but we haven't seen any sign of them. their equipment, both of their equipment, is still in the ship, and there's no signs of anything grabbing them in the night, they're just... Gone. Tomorrow morning we head back into space to go resupply and submit what we've found so far, but when we come back we'll have more than enough manpower to really dig into this place."},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bc" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/obj/item/weapon/reagent_containers/spray,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bd" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"be" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/artifact_harvester,/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall/titanium,/area/bluespaceriver/ship) +"bg" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bh" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bi" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bj" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/light,/obj/structure/filingcabinet,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bk" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bl" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bm" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/wall/titanium,/area/bluespaceriver/ship) +"bn" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet/rd,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bo" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ship) +"bp" = (/obj/machinery/autolathe,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bq" = (/obj/structure/bed/chair/office/light,/obj/machinery/light,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"br" = (/obj/machinery/artifact_analyser,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bs" = (/obj/structure/toilet{dir = 4},/obj/structure/sink{pixel_y = 24},/obj/machinery/shower{dir = 1},/obj/random/soap,/turf/simulated/floor/tiled/freezer,/area/bluespaceriver/ship) +"bt" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bu" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bv" = (/obj/structure/curtain/open/bed,/obj/structure/bed/padded,/obj/item/weapon/bedsheet/brown,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bw" = (/obj/structure/curtain/open/bed,/obj/structure/bed/padded,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bx" = (/obj/structure/closet/hydrant,/turf/simulated/wall/titanium,/area/bluespaceriver/ship) +"by" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bz" = (/obj/structure/bed/chair/comfy/red{dir = 4},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bA" = (/obj/structure/table/glass,/obj/item/weapon/pen,/obj/item/weapon/storage/secure/briefcase/money{code = "63214"},/obj/item/weapon/form_printer,/obj/item/weapon/gun/energy/gun/small,/obj/item/weapon/rig/hazmat/equipped,/obj/random/cash,/obj/item/weapon/paper{info = "We've finished the bridge and began our initial investigation into the site. Thus far, we're finding a lot of structures clearly made by a sapient species, one that from all indications was relatively advanced, but no signs of what actually happened to them. There's clear signs of habitation, but no signs of what caused abandonment. We're setting up camp in the ruins tonight so that we can continue studying as long as possible before our scheduled departure for refueling, but I feel confident we'll have enough to secure funds for the forseeable future at least!"},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bB" = (/obj/machinery/light{dir = 8},/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ship) +"bC" = (/obj/structure/shuttle/engine/propulsion{icon_state = "propulsion_l"},/turf/simulated/wall/titanium,/area/bluespaceriver/ship) +"bD" = (/obj/machinery/door/window/northright,/obj/machinery/door/window/southleft,/turf/simulated/floor/reinforced,/area/bluespaceriver/ship) +"bE" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bF" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/random/toolbox,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bG" = (/turf/simulated/floor/reinforced,/area/bluespaceriver/ship) +"bH" = (/obj/structure/bookcase/manuals/research_and_development,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bI" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet/red,/obj/item/weapon/storage/secure/safe{pixel_y = 24},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bJ" = (/obj/structure/curtain/open/bed,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bK" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bL" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/obj/structure/handrai,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bM" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet/green,/obj/item/weapon/storage/secure/safe{pixel_y = 24},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bN" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{ icon_state = "intact"; dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/power/apc{dir = 8; pixel_x = -24},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"bO" = (/obj/machinery/atmospherics/pipe/tank/air{dir = 8},/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"bP" = (/obj/structure/fuel_port,/turf/simulated/wall/titanium,/area/bluespaceriver/ship) +"bQ" = (/obj/machinery/artifact_scanpad,/turf/simulated/floor/reinforced,/area/bluespaceriver/ship) +"bR" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bS" = (/obj/machinery/vending/wallmed1{layer = 3.3; name = "Emergency NanoMed"; pixel_x = 28; pixel_y = 0; req_access = newlist()},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/item/weapon/mop,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bT" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/cable,/obj/machinery/power/smes/buildable{charge = 0; RCon_tag = "Solar - Port"},/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"bU" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall/titanium,/area/bluespaceriver/ship) +"bV" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/turf/simulated/wall/titanium,/area/bluespaceriver/ship) +"bW" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 8; use_power = 1},/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ship) +"bX" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet/yellow,/obj/item/weapon/storage/secure/safe{pixel_y = 24},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bY" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet/captain,/obj/item/weapon/storage/secure/safe{pixel_y = 24},/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"bZ" = (/obj/structure/table/woodentable,/obj/random/energy,/obj/item/weapon/storage/pill_bottle/happy,/obj/random/contraband,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"ca" = (/obj/machinery/door/blast/shutters,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"cb" = (/obj/machinery/door/blast/shutters,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/bluespaceriver/ship) +"cc" = (/obj/structure/closet/excavation,/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"cd" = (/obj/machinery/light{dir = 1},/obj/structure/closet/wardrobe/science_white,/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"ce" = (/obj/structure/closet/radiation,/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"cf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"cg" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"ch" = (/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"ci" = (/obj/machinery/light{dir = 1},/obj/random/maintenance/clean,/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"cj" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/shieldwallgen,/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"ck" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/shieldwallgen,/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"cl" = (/obj/structure/sign/warning/vacuum,/turf/simulated/wall/titanium,/area/bluespaceriver/ship) +"cm" = (/obj/machinery/door/airlock/glass_external/bolted,/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"cn" = (/obj/structure/closet/secure_closet/scientist,/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"co" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/machinery/floodlight,/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"cp" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/machinery/suspension_gen,/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"cq" = (/obj/structure/dispenser/oxygen,/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"cr" = (/obj/machinery/light{dir = 8},/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"cs" = (/obj/random/maintenance/clean,/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"ct" = (/obj/structure/ore_box,/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"cu" = (/obj/machinery/door/blast/regular,/turf/simulated/floor/tiled/dark,/area/bluespaceriver/ship) +"cv" = (/obj/machinery/mining/brace,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"cw" = (/obj/machinery/mining/drill,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"cx" = (/obj/effect/shuttle_landmark/nav_blueriv/nav4,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"cy" = (/obj/structure/ladder,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"cz" = (/obj/item/remains/human,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"cA" = (/obj/structure/flora/grass/both,/obj/structure/flora/grass/both,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"cB" = (/obj/structure/flora/grass/both,/obj/structure/flora/bush,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"cC" = (/obj/effect/shuttle_landmark/nav_blueriv/nav2,/turf/simulated/floor/exoplanet/snow{temperature = 240},/area/bluespaceriver/ground) +"cD" = (/obj/effect/landmark/map_data{height = 2},/obj/effect/landmark/random_gen/asteroid{generation_height = 100; generation_width = 100},/turf/unsimulated/mineral{temperature = 233},/area/bluespaceriver/ground) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababacacacacacababacacababababababacabababacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababacacacacacacabacacacacacabababacabacadacacacacaeacababababababababacabababacacacacacacacababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababacacacacacaeacacacacacacacacababacacacacacacacacacacacababababababababacabababacacacacacacacacabababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababacacacacacacacacacacacacacaeacabacacacacacacacacacacacacacabababacacacacababababacacacacacacacacababababababababababababababababababababaa +aaababababababababababababababacacacacacacababababacabababababacacacacacacacacacacacacacafacacacacacacacacacacacacacacababababacacacacacabacabacacacacacacababababababababababababababababababababababaa +aaababababababababababababababacacacacacacacabababacacacacacaeacacacacacacacacacadacacacacacacacacacacacacacacacacacacababacacacacacacacacacacacacacacacacababababababababababababababababababababababaa +aaababababababababababababababacacacacagacacabababacacacacacacacacacahacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababaa +aaababababababababababababababacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacababacacacabacacababababababababababababababaa +aaababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacadacacacacacacacacacababacababababababababababababaa +aaababababababababababababacacacacacacacacacacacacacacacafacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabacacacacababababababababababaa +aaababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacafacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababaa +aaababababababababababababacacacacacacacacaeacaiacacacacacacacacacacacacacacacafacacacacacafacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaababababababababababababacacacacacacafacahacacaiacacacacacacacacacacacacafaeacacacacacacacacacacacacacacacacacacacacacacacacacaeacacacacacacacacacacacacacacacacacacacacacacacabababababababababababaa +aaababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaiacacabababababababababaa +aaabababababababababababacacacacafacacacacacacacacacacacacacacacacacacacafacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacababababababababababaa +aaabababababababababababacacacafacacacacacacacacacacacacacacacacafacacacacacafacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababaa +aaabababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacafacacacacacacacacacacacacacacacacacacacacacacacacacacacacaeacacacacacacacacacacacacacababababababababababaa +aaabababababababababababacacacacacacacacacacacacajacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababaa +aaababababababababababababacacacacacacacacacacacacacacacacadacacacacacacacacacacacafacacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaababababababababababacacacacacacacacacacacacacacacacacacacacacaeacacacacacacacacacacacacacacacacacacacacacacacakacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacacacabababababababababaa +aaababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacaeaiacacacacacababababababababababaa +aaababababababababacacacacadacahacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacahacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababaa +aaababababababacacacacacacacacacacacacacacacacacacacacacacacacafacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababaa +aaabababababababacacacacacacacacacacacacacacacacacacacacacahacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababaa +aaabababababacabacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababaa +aaabababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacahacacacacacacacacacacacacacacacacacacacacacacacafacacacacacacacacacacacacacacacacacacacacacacacacababababababababababaa +aaababababababacacacacacacacacacacacacacacacalacacacacacacacacacacacacacacacacacacacaeacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacamacacacacacacacacacacacacacacababababababababababaa +aaababababababacacacacacacacacacacacacacananananananacacacacacacacacacacacacacacacacacacacacacacacahacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaeacacacababababababababababaa +aaababababababacacacacacacacacacacacacananaoapaqarananacacacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababaa +aaababababababacacacacacacacacacacasananatauavawaxauananasacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababaa +aaababababababacacacacacacacacacacayanayayayazayaAaBaCanayacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaababababababacacacacacacacacacanayaDaEaFaGaHaIaJauaKaLayanacacacacacacacacacacacacacacacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaabababababacacacacacacacacacananaMaNauaNaOaPaQaJauauaRaSananacacacacacacacaiacacacacacacacacacacacacacafacacacacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaabababababacacacacacacacacananaTauauaUaVayaWauaXaYauauaZayananacacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaiacacacacacacacacacacacacacabababababababaa +aaabababababacacacacacacacbababbbcbdbebfbfbfbgbhbibjbkbkblbmbnananacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababacacadacacboayaybpaNaubqbraybsbtbuaAbvaybwbxbyaGbzbAayaybBacacacacacacacacacacacacacacacacacacaeacacacacacacacacacacafacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaababababababacacacacacbCbCayaybDayayayayaybEaAayayayaybFayayaybCbCacacacacacacacacacacacacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaababababababacacacacacacacbCaybGbGaybHbIbJbKbLbJbMbHaybNbObPbCacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaeacacacacacacacacacacacacacacacacacababababababababaa +aaababababababacacacacacacacacayaybQayayayaybRbSayayayaybTbUbVbWacacacacacacacacacacacacacahacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaiacaiabababababababababaa +aaababababacacacacacacacacacacbCayayaybHbXbJbuaXbJbYbZayayaybCacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacafacacacacacacacaiacacacacacacacaiacacacacacacacacacabababababababababaa +aaababababacacacacacacacacacacacbCayayayayaycacbayayayayaybCacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaiaiacacacacacacacacacacacacacacacacacacababababababababaa +aaababababababahacacacacacacacacacayaycccdcecfcgchcichayayacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaiacacacacacacacacacacacababababababababaa +aaabababababababacacacacacacacacacbCaychchchcjckclcmcmaybCacacacacacacacacacacacacacacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababababababacacacacacacacacaycmaycncocpaychcqayacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaeacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababaa +aaabababababababababacacacacacacacacaychclcrchcsaychctayacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaabababababababababacacacacacacacacaycmaycucucuaycmcmayacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaabababababababababacacacacacaccvacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaabababababababababacacacacacacaccwacacacacacacacacacacacacacacacacacacacacacacacacacacaccxacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababaa +aaababababababababababacacacaccvacacaccvacaccyacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababaa +aaababababababababababacahacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababaa +aaababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaeacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababaa +aaabababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaeacacacacacabababababababababaa +aaababababababacacacacacacacacacacacczacacacacacacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababaa +aaabababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababaa +aaababababacacacacacacacacacacacacacacacacacacacacacacafacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababaa +aaababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaababababacabacacacacacacaiacaccAaccBacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccCacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaababababababacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaeacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababaa +aaababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababaa +aaabababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababaa +aaabababababacacacacacacacacacacacafacacacacacacacacacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacaeacacacacacacacacacacacacacacacacacacacacacacacacaeacacacacacacacacacabababababababaa +aaabababababacacacacacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacacacafaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaiacacacababababababaa +aaabababababacacacafacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababaa +aaabababababacacacacacacacacacaeacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababaa +aaabababababacacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababacacacacacacacacacacacacacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacacacacaeacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacaiacaeacacacacacacacacacacacacacacacaiacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabacababababababababababaa +aaababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababaa +aaababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaiacacacacacacacacacacabababababababababababababaa +aaababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababaa +aaabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacafacacacacacacacacacacacafacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababaa +aaabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababaa +aaababababacacacacacacacacacacacacacacacacacaeacacacacaiacaiacacacacacacacacacacacacacacacacacacaeacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababaa +aaababababababacacacacacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababaa +aaabababababababacacacaiacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababaa +aaabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaeacacacacacacacacacacacacacacacacacacacacabababababababababababababababababaa +aaabababababababacacacacacacacacacacacacacacaiacacacacacacacacacacacacacacacacacababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababaa +aaabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababacacacacafacacacacacacacacacacacacacacacacacacacacacacacacababababacabababababababababababababababababababababaa +aaabababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababaa +aaababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababacacacababacacacacacacacacacacacacaiacabacacacacacacacabababababababababababababababababababababababababababaa +aaabababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacababababababababacacacabababacacacacacacacacacacacaiacabababacacacacababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacabababababababababababacacababababacacacacacacacacacacacacababababacababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacababababacacacabababababababababababababacababababababacacacacacacacacacacababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababacababababababacacabacacacacacababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +cDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/blueriver/blueriver.dm b/maps/away/blueriver/blueriver.dm new file mode 100644 index 00000000..38521b4e --- /dev/null +++ b/maps/away/blueriver/blueriver.dm @@ -0,0 +1,160 @@ +//quality code theft +#include "blueriver_areas.dm" +/obj/effect/overmap/sector/arcticplanet + name = "arctic planetoid" + desc = "Sensor array detects an arctic planet with a small vessle on the planet's surface. Scans further indicate strange energy levels below the planet's surface." + in_space = 0 + icon_state = "globe" + generic_waypoints = list( + "nav_blueriv_1", + "nav_blueriv_2", + "nav_blueriv_3", + "nav_blueriv_antag" + ) + +/obj/effect/overmap/sector/arcticplanet/New(nloc, max_x, max_y) + name = "[generate_planet_name()], \a [name]" + ..() + +/datum/map_template/ruin/away_site/blueriver + name = "Bluespace River" + id = "awaysite_blue" + description = "Two z-level map with an arctic planet and an alien underground surface" + suffixes = list("blueriver/blueriver-1.dmm", "blueriver/blueriver-2.dmm") + +//This is ported from /vg/ and isn't entirely functional. If it sees a threat, it moves towards it, and then activates it's animation. +//At that point while it sees threats, it will remain in it's attack stage. It's a bug, but I figured it nerfs it enough to not be impossible to deal with +/mob/living/simple_animal/hostile/hive_alien/defender + name = "hive defender" + desc = "A terrifying monster resembling a massive, bloated tick in shape. Hundreds of blades are hidden underneath its rough shell." + icon = 'maps/away/blueriver/blueriver.dmi' + icon_state = "hive_executioner_move" + icon_living = "hive_executioner_move" + icon_dead = "hive_executioner_dead" + move_to_delay = 5 + speed = -1 + health = 280 + maxHealth = 280 + + harm_intent_damage = 8 + melee_damage_lower = 30 + melee_damage_upper = 35 + attacktext = "evisceratds" + attack_sound = 'sound/weapons/slash.ogg' + var/attack_mode = FALSE + + var/transformation_delay_min = 4 + var/transformation_delay_max = 8 + +/mob/living/simple_animal/hostile/hive_alien/defender/proc/mode_movement() //Slightly broken, but it's alien and unpredictable so w/e + set waitfor = 0 + icon_state = "hive_executioner_move" + flick("hive_executioner_movemode", src) + sleep(rand(transformation_delay_min, transformation_delay_max)) + anchored = FALSE + speed = -1 + move_to_delay = 8 + attack_mode = FALSE + + //Immediately find a target so that we're not useless for 1 Life() tick! + FindTarget() + +/mob/living/simple_animal/hostile/hive_alien/defender/proc/mode_attack() + set waitfor = 0 + icon_state = "hive_executioner_attack" + flick("hive_executioner_attackmode", src) + sleep(rand(transformation_delay_min, transformation_delay_max)) + anchored = TRUE + speed = 0 + attack_mode = TRUE + walk(src, 0) + +/mob/living/simple_animal/hostile/hive_alien/defender/LostTarget() + if(attack_mode && !FindTarget()) //If we don't immediately find another target, switch to movement mode + mode_movement() + + return ..() + +/mob/living/simple_animal/hostile/hive_alien/defender/LoseTarget() + if(attack_mode && !FindTarget()) //If we don't immediately find another target, switch to movement mode + mode_movement() + + return ..() + +/mob/living/simple_animal/hostile/hive_alien/defender/AttackingTarget() + if(!attack_mode) + return mode_attack() + + flick("hive_executioner_attacking", src) + + return ..() + +/mob/living/simple_animal/hostile/hive_alien/defender/wounded + name = "wounded hive defender" + health = 80 + +/obj/effect/shuttle_landmark/nav_blueriv/nav1 + name = "Arctic Planet Landing Point #1" + landmark_tag = "nav_blueriv_1" + base_area = /area/bluespaceriver/ground + +/obj/effect/shuttle_landmark/nav_blueriv/nav2 + name = "Arctic Planet Landing Point #2" + landmark_tag = "nav_blueriv_2" + base_area = /area/bluespaceriver/ground + +/obj/effect/shuttle_landmark/nav_blueriv/nav3 + name = "Arctic Planet Landing Point #3" + landmark_tag = "nav_blueriv_3" + base_area = /area/bluespaceriver/ground + +/obj/effect/shuttle_landmark/nav_blueriv/nav4 + name = "Arctic Planet Navpoint #4" + landmark_tag = "nav_blueriv_antag" + base_area = /area/bluespaceriver/ground + +/turf/simulated/floor/away/blueriver/alienfloor + name = "glowing floor" + desc = "The floor glows without any apparent reason" + icon = 'riverturfs.dmi' + icon_state = "floor" + temperature = 233 + +/turf/simulated/floor/away/blueriver/alienfloor/Initialize() + .=..() + + set_light(l_range = 5, l_power = 2, l_color = "#0066FF") + +/turf/unsimulated/wall/away/blueriver/livingwall + name = "alien wall" + desc = "You feel a sense of dread from just looking at this wall. Its surface seems to be constantly moving, as if it were breathing." + icon = 'riverturfs.dmi' + icon_state = "evilwall_1" + opacity = 1 + density = 1 + temperature = 233 + +/turf/unsimulated/wall/away/blueriver/livingwall/Initialize() + .=..() + + if(prob(80)) + icon_state = "evilwall_[rand(1,8)]" + +/turf/unsimulated/wall/supermatter/no_spread + name = "weird liquid" + desc = "The viscous liquid glows and moves as if it were alive." + icon='blueriver.dmi' + icon_state = "bluespacecrystal1" + layer = SUPERMATTER_WALL_LAYER + plane = EFFECTS_ABOVE_LIGHTING_PLANE + opacity = 0 + dynamic_lighting = 0 + +/turf/unsimulated/wall/supermatter/no_spread/Initialize() + .=..() + + icon_state = "bluespacecrystal[rand(1,3)]" + set_light(l_range = 5, l_power = 2, l_color = "#0066FF") + +/turf/unsimulated/wall/supermatter/no_spread/process() + return PROCESS_KILL diff --git a/maps/away/blueriver/blueriver.dmi b/maps/away/blueriver/blueriver.dmi new file mode 100644 index 00000000..3c2b6155 Binary files /dev/null and b/maps/away/blueriver/blueriver.dmi differ diff --git a/maps/away/blueriver/blueriver_areas.dm b/maps/away/blueriver/blueriver_areas.dm new file mode 100644 index 00000000..40551b47 --- /dev/null +++ b/maps/away/blueriver/blueriver_areas.dm @@ -0,0 +1,18 @@ +/area/bluespaceriver/underground + name = "\improper Bluespace River Underground" + icon_state = "underground" + icon = 'blueriver.dmi' + ambience = list('sound/ambience/spookyspace1.ogg', 'sound/ambience/spookyspace2.ogg') + sound_env = ASTEROID + +/area/bluespaceriver/ground + name = "\improper Arctic Planet Surface" + icon_state = "ground" + icon = 'blueriver.dmi' + ambience = list('sound/ambience/ambimine.ogg', 'sound/ambience/song_game.ogg') + sound_env = ASTEROID + +/area/bluespaceriver/ship + name = "\improper NSV Horizon" + icon_state = "ship" + icon = 'blueriver.dmi' diff --git a/maps/away/blueriver/riverturfs.dmi b/maps/away/blueriver/riverturfs.dmi new file mode 100644 index 00000000..1e9a8888 Binary files /dev/null and b/maps/away/blueriver/riverturfs.dmi differ diff --git a/maps/away/casino/casino.dm b/maps/away/casino/casino.dm new file mode 100644 index 00000000..3ffb0854 --- /dev/null +++ b/maps/away/casino/casino.dm @@ -0,0 +1,170 @@ +#include "casino_areas.dm" +#include "../mining/mining_areas.dm" + +/obj/effect/overmap/ship/casino + name = "passenger liner" + desc = "Sensors detect an undamaged vessel without any signs of activity." + color = "#bd6100" + vessel_mass = 100 + default_delay = 30 SECONDS + speed_mod = 5 SECONDS + burn_delay = 20 SECONDS + triggers_events = 0 + generic_waypoints = list( + "nav_casino_1", + "nav_casino_2", + "nav_casino_3", + "nav_casino_4", + "nav_casino_antag", + "nav_casino_hangar", + ) + restricted_waypoints = list( + "Casino Cutter" = list("nav_casino_hangar"), + ) + +/obj/effect/overmap/ship/casino/New(nloc, max_x, max_y) + name = "IPV [pick("Fortuna","Gold Rush","Ebisu","Lucky Paw","Four Leaves")], \a [name]" + ..() + +/datum/map_template/ruin/away_site/casino + name = "Casino" + id = "awaysite_casino" + description = "A casino ship!" + suffixes = list("casino/casino.dmm") + cost = 1 + shuttles_to_initialise = list(/datum/shuttle/autodock/overmap/casino_cutter) + +/obj/effect/shuttle_landmark/nav_casino/nav1 + name = "Casino Ship Navpoint #1" + landmark_tag = "nav_casino_1" + +/obj/effect/shuttle_landmark/nav_casino/nav2 + name = "Casino Ship Navpoint #2" + landmark_tag = "nav_casino_2" + +/obj/effect/shuttle_landmark/nav_casino/nav3 + name = "Casino Ship Navpoint #3" + landmark_tag = "nav_casino_3" + +/obj/effect/shuttle_landmark/nav_casino/nav4 + name = "Casino Ship Navpoint #4" + landmark_tag = "nav_casino_4" + +/obj/effect/shuttle_landmark/nav_casino/nav5 + name = "Casino Ship Navpoint #5" + landmark_tag = "nav_casino_antag" + +/datum/shuttle/autodock/overmap/casino_cutter + name = "Casino Cutter" + warmup_time = 15 + move_time = 60 + shuttle_area = /area/casino/casino_cutter + current_location = "nav_casino_hangar" + landmark_transition = "nav_casino_transit" + fuel_consumption = 0.5//it's small + range = 1 + defer_initialisation = TRUE + +/obj/effect/shuttle_landmark/nav_casino/cutter_hangar + name = "Casino Hangar" + landmark_tag = "nav_casino_hangar" + base_area = /area/casino/casino_hangar + base_turf = /turf/simulated/floor/plating + +/obj/effect/shuttle_landmark/nav_casino/cutter_transit + name = "In transit" + landmark_tag = "nav_casino_transit" + +/obj/machinery/computer/shuttle_control/explore/casino_cutter + name = "cutter control console" + shuttle_tag = "Casino Cutter" + +/obj/structure/casino/roulette + name = "roulette" + desc = "Spin the roulette to try your luck." + icon = 'maps/away/casino/casino_sprites.dmi' + icon_state = "roulette_r" + density = 0 + anchored = 1 + var/busy=0 + +/obj/structure/casino/roulette/attack_hand(mob/user as mob) + if (busy) + to_chat(user,"You cannot spin now! \The [src] is already spinning. ") + return + visible_message("\ [user] spins the roulette and throws inside little ball.") + busy = 1 + var/n = rand(0,36) + var/color = "green" + add_fingerprint(user) + if ((n>0 && n<11) || (n>18 && n<29)) + if (n%2) + color="red" + else + color="black" + if ( (n>10 && n<19) || (n>28) ) + if (n%2) + color="black" + else + color="red" + spawn(5 SECONDS) + visible_message("\The [src] stops spinning, the ball landing on [n], [color].") + busy=0 + +/obj/structure/casino/roulette_chart + name = "roulette chart" + desc = "Roulette chart. Place your bets! " + icon = 'maps/away/casino/casino_sprites.dmi' + icon_state = "roulette_l" + density = 0 + anchored = 1 + +/obj/structure/casino/bj_table + name = "blackjack table" + desc = "This is a blackjack table. " + icon = 'maps/away/casino/casino_sprites.dmi' + icon_state = "bj_left" + density = 0 + anchored = 1 + +/obj/structure/casino/bj_table/bj_right + icon_state = "bj_right" + +/obj/structure/casino/oh_bandit + name = "one armed bandit" + desc = "Turned off slot machine. " + icon = 'maps/away/casino/casino_sprites.dmi' + icon_state = "slot_machine" + density = 0 + anchored = 1 + +/obj/structure/casino/craps + name = "craps table" + desc = "Craps table: roll dice!" + icon = 'maps/away/casino/casino_sprites.dmi' + icon_state = "craps_top" + density = 0 + anchored = 1 + +/obj/structure/casino/craps/craps_down + icon_state = "craps_down" + +//========================used bullet casings======================= +/obj/item/ammo_casing/a556/used/Initialize() + . = ..() + expend() + pixel_x = rand(-10, 10) + pixel_y = rand(-10, 10) + + +/obj/item/ammo_casing/c45/used/Initialize() + . = ..() + expend() + pixel_x = rand(-10, 10) + pixel_y = rand(-10, 10) + +/obj/item/ammo_casing/a50/used/Initialize() + . = ..() + expend() + pixel_x = rand(-10, 10) + pixel_y = rand(-10, 10) diff --git a/maps/away/casino/casino.dmm b/maps/away/casino/casino.dmm new file mode 100644 index 00000000..e5de145c --- /dev/null +++ b/maps/away/casino/casino.dmm @@ -0,0 +1,811 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/obj/effect/step_trigger/thrower{affect_ghosts = 1; direction = 8; name = "thrower_throwdownside"; nostop = 1; stopper = 0; tiles = 0},/turf/space,/area/space) +"ac" = (/obj/effect/step_trigger/thrower{affect_ghosts = 1; direction = 1; name = "thrower_throwdownside"; nostop = 1; stopper = 0; tiles = 0},/turf/space,/area/space) +"ad" = (/obj/effect/step_trigger/thrower{affect_ghosts = 1; direction = 4; name = "thrower_throwdownside"; nostop = 1; stopper = 0; tiles = 0},/turf/space,/area/space) +"ae" = (/obj/effect/step_trigger/teleporter/random{affect_ghosts = 1; name = "escapeshuttle_leave"; teleport_x = 25; teleport_x_offset = 245; teleport_y = 25; teleport_y_offset = 245; teleport_z = 6; teleport_z_offset = 6},/turf/space,/area/space) +"af" = (/obj/effect/shuttle_landmark/nav_casino/cutter_transit,/turf/space,/area/space) +"ag" = (/obj/effect/step_trigger/teleporter/random{affect_ghosts = 1; name = "escapeshuttle_leave"; teleport_x = 25; teleport_x_offset = 245; teleport_y = 25; teleport_y_offset = 245; teleport_z = 6; teleport_z_offset = 6},/turf/space{icon_state = "black"},/area/space) +"ah" = (/obj/effect/step_trigger/thrower{affect_ghosts = 1; direction = 4; name = "thrower_throwdownside"; nostop = 1; stopper = 0; tiles = 0},/turf/space/transit/north,/area/space) +"ai" = (/obj/effect/shuttle_landmark/nav_casino/nav1,/turf/space,/area/space) +"aj" = (/obj/effect/step_trigger/thrower{affect_ghosts = 1; direction = 2; name = "thrower_throwdownside"; nostop = 1; stopper = 0; tiles = 0},/turf/space,/area/space) +"ak" = (/obj/effect/shuttle_landmark/nav_casino/nav5,/turf/space,/area/space) +"al" = (/turf/space,/turf/simulated/shuttle/wall/corner/dark/nw,/area/casino/casino_bridge) +"am" = (/turf/simulated/wall/r_wall,/area/casino/casino_bridge) +"an" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor/border_only,/obj/machinery/door/blast/regular{density = 0; dir = 2; icon_state = "pdoor0"; id = "casino_bridge"; name = "Casino Bridge Blast Doors"; opacity = 0},/turf/simulated/floor/plating,/area/casino/casino_bridge) +"ao" = (/turf/space,/turf/simulated/shuttle/wall/corner/dark/ne,/area/casino/casino_bridge) +"ap" = (/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"aq" = (/obj/machinery/computer/engines,/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"ar" = (/obj/machinery/computer/helm,/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"as" = (/obj/machinery/computer/sensors,/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"at" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor/border_only,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "casino_bridge"; name = "Casino Bridge Blast Doors"; opacity = 0},/turf/simulated/floor/plating,/area/casino/casino_bridge) +"au" = (/obj/structure/bed/chair{dir = 1},/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"av" = (/obj/structure/table/steel_reinforced,/obj/random/handgun,/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"aw" = (/obj/item/weapon/wirecutters,/obj/item/stack/rods,/turf/space,/area/space) +"ax" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"ay" = (/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"aA" = (/obj/item/modular_computer/console{name = "Gambling console"},/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"aB" = (/turf/simulated/wall/r_wall,/area/casino/casino_maintenance) +"aC" = (/obj/machinery/door/firedoor/border_only,/obj/structure/grille,/obj/structure/window/reinforced/full,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"aD" = (/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_closed"; id_tag = "casino_dock_outer"; locked = 0; name = "Docking Port Airlock"; req_access = list(13)},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"aE" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"aF" = (/obj/structure/bed/chair{dir = 4; icon_state = "chair_preview"},/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"aH" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/obj/machinery/airlock_sensor{frequency = 1381; id_tag = "casino_dock_sensor"; pixel_x = -30; pixel_y = -8},/obj/item/device/multitool,/obj/item/weapon/plastique,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"aI" = (/obj/effect/floor_decal/industrial/warning{dir = 5},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 2; frequency = 1380; id_tag = "admin_shuttle_dock_pump"},/obj/item/device/radio/intercom{dir = 8; pixel_x = 22},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"aJ" = (/obj/structure/table/steel_reinforced,/obj/random/loot,/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"aL" = (/obj/structure/table/steel_reinforced,/obj/item/device/radio,/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"aM" = (/obj/item/modular_computer/console{name = "Security console"},/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"aN" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1381; id_tag = "admin_shuttle_dock_pump"},/obj/effect/floor_decal/industrial/warning{dir = 10},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"aO" = (/obj/machinery/atmospherics/pipe/manifold/hidden{dir = 4; icon_state = "map"},/obj/machinery/light/small{dir = 4},/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"aT" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"aU" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/machinery/door/airlock/external{frequency = 1381; icon_state = "door_closed"; id_tag = "casino_dock_inner"; locked = 0; name = "Docking Port Airlock"; req_access = list(13)},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"aV" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/button/remote/blast_door{id = "casino_weaponry"; name = "Weaponry Blast Door contol"; pixel_y = -25},/obj/structure/flora/pottedplant/unusual,/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"aW" = (/obj/machinery/button/remote/blast_door{id = "casino_bridge"; name = "Casino Bridge Blast Door contol"; pixel_y = -25},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"ba" = (/obj/structure/closet/emcloset,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"bb" = (/obj/structure/lattice,/obj/structure/grille,/turf/space,/area/space) +"bc" = (/obj/machinery/embedded_controller/radio/airlock/docking_port{frequency = 1381; id_tag = "casino_dock_airlock"; pixel_x = -24; pixel_y = 6; req_one_access = list(13); tag_airpump = "casino_dock_pump"; tag_chamber_sensor = "casino_dock_sensor"; tag_exterior_door = "casino_dock_outer"; tag_interior_door = "casino_dock_inner"},/obj/machinery/light{dir = 8},/obj/machinery/portable_atmospherics/canister/air/airlock,/obj/machinery/atmospherics/portables_connector{dir = 4},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/casino/casino_maintenance) +"bd" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/effect/decal/cleanable/blood/drip,/obj/machinery/atmospherics/pipe/manifold/hidden{dir = 4; icon_state = "map"},/turf/simulated/floor/tiled/dark,/area/casino/casino_maintenance) +"be" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Casino Bridge"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/casino/casino_bridge) +"bf" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Casino Bridge"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/casino/casino_bridge) +"bh" = (/turf/simulated/floor/tiled/dark,/area/casino/casino_maintenance) +"bi" = (/obj/machinery/atmospherics/binary/pump{dir = 1},/turf/simulated/floor/tiled/dark,/area/casino/casino_maintenance) +"bj" = (/obj/structure/table/rack,/obj/item/weapon/gun/projectile/sec/MK{pixel_x = 4; pixel_y = 4},/obj/item/weapon/gun/projectile/sec/MK{pixel_x = 2; pixel_y = 2},/obj/item/weapon/gun/projectile/sec/MK,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bk" = (/obj/machinery/door/blast/regular{id = "casino_weaponry"},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bl" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bm" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{icon_state = "6-8"},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bn" = (/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bo" = (/obj/machinery/floodlight,/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bp" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal,/turf/simulated/floor/tiled/dark,/area/casino/casino_maintenance) +"bq" = (/turf/simulated/wall/r_wall,/area/casino/casino_security) +"br" = (/turf/simulated/wall/r_wall,/area/casino/casino_hangar) +"bs" = (/turf/space,/turf/simulated/shuttle/wall/corner/dark/ne,/area/casino/casino_hangar) +"bt" = (/obj/effect/shuttle_landmark/nav_casino/nav3,/turf/space,/area/space) +"bu" = (/obj/structure/table/rack,/obj/item/weapon/material/hatchet/tacknife,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bv" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bw" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bz" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bA" = (/obj/item/weapon/cigbutt/professionals{pixel_x = 4; pixel_y = -5},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bB" = (/obj/item/weapon/cigbutt/professionals,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bC" = (/obj/machinery/light/small{dir = 1},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bD" = (/obj/item/weapon/material/shard,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bE" = (/obj/effect/decal/cleanable/blood/drip,/obj/effect/decal/cleanable/blood/drip,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bF" = (/obj/effect/decal/cleanable/blood/drip,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bG" = (/obj/machinery/door/airlock{name = "Security wing"},/obj/machinery/door/firedoor/border_only,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_security) +"bI" = (/obj/structure/fireaxecabinet{pixel_y = 30},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/tiled,/area/casino/casino_security) +"bJ" = (/obj/machinery/light{dir = 1},/obj/structure/cable{icon_state = "6-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_security) +"bK" = (/obj/structure/reagent_dispensers/peppertank{pixel_y = 25},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_security) +"bL" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/alarm{pixel_y = 25},/turf/simulated/floor/tiled,/area/casino/casino_security) +"bM" = (/obj/machinery/door/airlock{name = "Shuttle control"},/obj/effect/decal/cleanable/blood/splatter,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/firedoor/border_only,/turf/simulated/floor/tiled,/area/casino/casino_security) +"bN" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/plating,/area/casino/casino_security) +"bO" = (/obj/machinery/light{dir = 1},/obj/item/weapon/gun/projectile/shotgun/pump,/obj/effect/decal/cleanable/blood/splatter,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/casino/casino_security) +"bP" = (/obj/machinery/button/remote/blast_door{id = "casino_shuttle_control"; name = "Shuttle control blast door-control"; pixel_x = 10; pixel_y = 25},/obj/machinery/button/remote/blast_door{id = "casino_hangar"; name = "Hangar gates"; pixel_x = -5; pixel_y = 25},/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/plating,/area/casino/casino_security) +"bQ" = (/obj/structure/bed/chair,/turf/simulated/floor/plating,/area/casino/casino_security) +"bR" = (/obj/machinery/alarm{pixel_y = 25},/turf/simulated/floor/plating,/area/casino/casino_security) +"bS" = (/obj/machinery/portable_atmospherics/canister/air,/obj/machinery/atmospherics/portables_connector,/turf/simulated/floor/plating,/area/casino/casino_security) +"bT" = (/obj/machinery/atmospherics/pipe/tank/nitrogen,/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"bU" = (/obj/structure/table/rack,/obj/item/weapon/gun/projectile/shotgun/pump/combat,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bV" = (/obj/random/trash,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bW" = (/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"bZ" = (/turf/simulated/wall,/area/casino/casino_maintenance) +"ca" = (/turf/simulated/wall,/area/casino/casino_crew_bunk) +"cb" = (/turf/simulated/wall/r_wall,/area/casino/casino_crew_bunk) +"cc" = (/turf/simulated/floor/tiled,/area/casino/casino_security) +"cd" = (/obj/effect/decal/cleanable/blood/splatter,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/casino/casino_security) +"ce" = (/obj/structure/cable{icon_state = "4-9"},/turf/simulated/floor/tiled,/area/casino/casino_security) +"cf" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/structure/flora/pottedplant/unusual,/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/turf/simulated/floor/tiled,/area/casino/casino_security) +"cg" = (/obj/structure/table/rack,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/plating,/area/casino/casino_security) +"ch" = (/obj/structure/table/rack,/turf/simulated/floor/plating,/area/casino/casino_security) +"ci" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/wrench,/turf/simulated/floor/plating,/area/casino/casino_security) +"cj" = (/obj/structure/table/steel_reinforced,/obj/item/device/radio,/turf/simulated/floor/plating,/area/casino/casino_security) +"ck" = (/obj/structure/table/steel_reinforced,/turf/simulated/floor/plating,/area/casino/casino_security) +"cl" = (/obj/machinery/atmospherics/binary/pump/high_power,/turf/simulated/floor/plating,/area/casino/casino_security) +"cm" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"cn" = (/obj/structure/table/rack,/obj/item/weapon/tank/nitrogen,/obj/item/weapon/tank/nitrogen,/obj/item/weapon/tank/nitrogen,/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"co" = (/turf/simulated/wall/r_wall,/area/casino/casino_crew_bathroom) +"cp" = (/turf/simulated/wall,/area/casino/casino_crew_bathroom) +"cq" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"cr" = (/obj/structure/bed,/obj/random/plushie,/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"cs" = (/obj/structure/closet,/obj/random/accessory,/obj/random/glasses,/obj/random/shoes,/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"ct" = (/obj/machinery/light{dir = 1},/obj/structure/bed,/obj/effect/decal/cleanable/blood/splatter,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"cu" = (/obj/machinery/vending/wallmed1{pixel_y = 25},/obj/structure/closet,/obj/random/smokes,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"cv" = (/obj/structure/bed,/obj/effect/decal/cleanable/blood/splatter,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"cw" = (/obj/structure/closet,/obj/random/accessory,/obj/random/drinkbottle,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"cx" = (/obj/machinery/light{dir = 1},/obj/structure/closet,/obj/random/junk,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"cy" = (/obj/structure/bed,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"cz" = (/obj/structure/table/steel_reinforced,/obj/random/firstaid,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/casino/casino_security) +"cA" = (/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled,/area/casino/casino_security) +"cB" = (/obj/structure/table/steel_reinforced,/obj/item/device/radio,/turf/simulated/floor/tiled,/area/casino/casino_security) +"cC" = (/obj/item/modular_computer/console{name = "Gambling console"},/turf/simulated/floor/tiled,/area/casino/casino_security) +"cD" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/blast/regular/open{icon_state = "pdoor0"; id = "casino_shuttle_control"},/obj/machinery/door/firedoor/border_only,/turf/simulated/floor/tiled,/area/casino/casino_security) +"cE" = (/obj/machinery/atmospherics/pipe/simple/visible/green,/turf/simulated/wall/r_wall,/area/casino/casino_security) +"cF" = (/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"cG" = (/obj/structure/sink{icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2},/obj/structure/mirror{pixel_x = -25},/obj/random/soap,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/casino/casino_crew_bathroom) +"cH" = (/turf/simulated/floor/tiled/white,/area/casino/casino_crew_bathroom) +"cI" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24; req_access = list(201)},/turf/simulated/floor/tiled/white,/area/casino/casino_crew_bathroom) +"cJ" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Crew toilet"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_crew_bathroom) +"cL" = (/obj/effect/decal/cleanable/blood/splatter,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"cM" = (/obj/effect/decal/cleanable/blood/splatter,/obj/structure/cable{dir = 2; icon_state = "1-10"},/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"cN" = (/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"cO" = (/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"cP" = (/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"cQ" = (/obj/structure/table/steel_reinforced,/obj/random/firstaid,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/casino/casino_security) +"cS" = (/obj/structure/bed/chair{dir = 4; icon_state = "chair_preview"},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/casino/casino_security) +"cT" = (/obj/item/modular_computer/console{name = "Cameras console"},/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/tiled,/area/casino/casino_security) +"cU" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"cV" = (/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"cW" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; external_pressure_bound = 140; external_pressure_bound_default = 140; icon_state = "map_vent_out"; pressure_checks = 1; pressure_checks_default = 1; use_power = 1},/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"cX" = (/obj/machinery/door/blast/regular{dir = 8; id = "casino_hangar"; name = "Hangar gate"},/turf/simulated/floor/plating,/area/casino/casino_hangar) +"cY" = (/obj/structure/lattice,/turf/space,/area/space) +"cZ" = (/obj/effect/decal/cleanable/blood/splatter,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled/white,/area/casino/casino_crew_bathroom) +"db" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Crew bunk room"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_maintenance) +"dc" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"dd" = (/obj/structure/closet,/obj/random/glasses,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"de" = (/obj/machinery/light,/obj/structure/bed,/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"df" = (/obj/structure/closet,/obj/random/junk,/obj/random/smokes,/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"dg" = (/obj/structure/bed,/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"dh" = (/obj/structure/bed,/obj/random/plushie,/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"di" = (/obj/machinery/light,/obj/structure/closet,/obj/random/action_figure,/obj/random/shoes,/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"dj" = (/obj/machinery/vending/security,/turf/simulated/floor/tiled,/area/casino/casino_security) +"dm" = (/obj/item/modular_computer/console{name = "Security console"},/turf/simulated/floor/tiled,/area/casino/casino_security) +"dn" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"do" = (/turf/simulated/shuttle/wall,/area/casino/casino_cutter) +"dp" = (/turf/simulated/shuttle/wall{icon_state = "swall_straight"; dir = 4},/area/casino/casino_cutter) +"dq" = (/obj/structure/fuel_port,/turf/simulated/shuttle/wall{dir = 8; icon_state = "swall"},/area/casino/casino_cutter) +"dr" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"ds" = (/obj/machinery/power/tracker,/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/airless,/area/space) +"dt" = (/obj/structure/toilet{dir = 4},/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/item/weapon/material/kitchen/utensil/knife/boot,/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled/white,/area/casino/casino_crew_bathroom) +"du" = (/obj/machinery/door/airlock{name = "Crew toilet"},/turf/simulated/floor/tiled/white,/area/casino/casino_crew_bathroom) +"dx" = (/turf/simulated/wall,/area/casino/casino_storage) +"dy" = (/turf/simulated/wall/r_wall,/area/casino/casino_storage) +"dz" = (/obj/random/ammo,/turf/simulated/floor/tiled,/area/casino/casino_security) +"dA" = (/obj/structure/table/rack,/obj/item/weapon/gun/projectile/shotgun/pump,/obj/item/weapon/gun/projectile/shotgun/pump,/obj/item/weapon/gun/projectile/shotgun/pump,/turf/simulated/floor/tiled,/area/casino/casino_security) +"dB" = (/obj/structure/table/rack,/obj/item/weapon/storage/box/shotgunammo,/obj/item/weapon/storage/box/shotgunammo,/obj/item/weapon/storage/box/shotgunammo,/turf/simulated/floor/tiled,/area/casino/casino_security) +"dC" = (/obj/structure/table/rack,/obj/item/clothing/suit/armor/bulletproof/vest,/obj/item/clothing/suit/armor/bulletproof/vest,/turf/simulated/floor/tiled,/area/casino/casino_security) +"dD" = (/obj/structure/table/rack,/obj/random/voidsuit,/obj/random/voidhelmet,/obj/item/weapon/tank/air,/turf/simulated/floor/tiled,/area/casino/casino_security) +"dE" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"dF" = (/obj/effect/wingrille_spawn/reinforced/full,/turf/simulated/floor/tiled,/area/casino/casino_cutter) +"dG" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/obj/machinery/door/window,/obj/item/key,/obj/machinery/embedded_controller/radio/airlock/docking_port{frequency = 1380; id_tag = "casino_cutter"; pixel_y = 25},/turf/simulated/floor/shuttle/yellow,/area/casino/casino_cutter) +"dH" = (/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24; req_access = list(201)},/turf/simulated/floor/shuttle/yellow,/area/casino/casino_cutter) +"dI" = (/turf/simulated/floor/shuttle/yellow,/area/casino/casino_cutter) +"dJ" = (/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/shuttle/yellow,/area/casino/casino_cutter) +"dK" = (/obj/structure/shuttle/engine/propulsion{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_cutter) +"dL" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/space) +"dM" = (/obj/structure/bed/chair/comfy/red{dir = 8},/turf/simulated/floor/plating,/area/casino/casino_storage) +"dN" = (/obj/structure/table/gamblingtable,/obj/structure/casino/bj_table,/turf/simulated/floor/plating,/area/casino/casino_storage) +"dO" = (/obj/structure/table/gamblingtable,/obj/structure/casino/bj_table/bj_right,/turf/simulated/floor/plating,/area/casino/casino_storage) +"dP" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/plating,/area/casino/casino_storage) +"dQ" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigar{pixel_y = 5},/obj/item/weapon/storage/fancy/cigar{pixel_y = 5},/obj/item/weapon/storage/fancy/cigar{pixel_y = 5},/obj/item/weapon/storage/fancy/cigar{pixel_y = 5},/obj/item/weapon/storage/fancy/cigar{pixel_y = 5},/obj/random/tool,/turf/simulated/floor/plating,/area/casino/casino_storage) +"dR" = (/obj/structure/bed/chair,/turf/simulated/floor/plating,/area/casino/casino_storage) +"dS" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/toolbox/mechanical,/obj/item/stack/cable_coil,/turf/simulated/floor/plating,/area/casino/casino_storage) +"dT" = (/obj/structure/bed/chair/office/light,/turf/simulated/floor/plating,/area/casino/casino_storage) +"dU" = (/obj/item/clothing/suit/armor/bulletproof/vest,/obj/random/ammo,/turf/simulated/floor/tiled,/area/casino/casino_security) +"dW" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/shuttle/yellow,/area/casino/casino_cutter) +"dX" = (/obj/item/weapon/storage/backpack/dufflebag,/obj/random/cash,/obj/random/cash,/obj/random/cash,/obj/random/cash,/obj/random/cash,/obj/structure/bed/chair/comfy/captain{dir = 1},/turf/simulated/floor/shuttle/yellow,/area/casino/casino_cutter) +"dY" = (/obj/structure/bed/chair/comfy/captain{dir = 1},/obj/item/weapon/storage/bag/cash,/turf/simulated/floor/shuttle/yellow,/area/casino/casino_cutter) +"dZ" = (/obj/structure/bed/chair/comfy/captain{dir = 1},/turf/simulated/floor/shuttle/yellow,/area/casino/casino_cutter) +"ea" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/bed/chair/comfy/captain{dir = 1},/turf/simulated/floor/shuttle/yellow,/area/casino/casino_cutter) +"eb" = (/obj/effect/overmap/ship/casino,/turf/space,/area/space) +"ec" = (/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/power/solar{id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"ed" = (/turf/simulated/floor/airless,/area/space) +"ee" = (/obj/machinery/shower{dir = 4; icon_state = "shower"; pixel_x = 0; pixel_y = 0},/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/casino/casino_crew_bathroom) +"ef" = (/obj/structure/curtain/open/shower,/turf/simulated/floor/tiled/white,/area/casino/casino_crew_bathroom) +"eg" = (/obj/random/trash,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"eh" = (/obj/structure/table/gamblingtable,/obj/structure/casino/roulette_chart,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/plating,/area/casino/casino_storage) +"ei" = (/obj/structure/table/gamblingtable,/obj/structure/casino/roulette,/turf/simulated/floor/plating,/area/casino/casino_storage) +"ej" = (/obj/item/weapon/circuitboard/broken,/turf/simulated/floor/plating,/area/casino/casino_storage) +"ek" = (/turf/simulated/floor/plating,/area/casino/casino_storage) +"el" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/plating,/area/casino/casino_storage) +"em" = (/obj/random/ammo,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_security) +"en" = (/obj/structure/safe,/turf/simulated/floor/plating,/area/casino/casino_security) +"eo" = (/obj/effect/shuttle_landmark/nav_casino/cutter_hangar,/obj/machinery/door/unpowered/shuttle{desc = "Cutter door. It opens and closes. It has no safety devices so be careful"; name = "cutter door"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/shuttle/blue,/area/casino/casino_cutter) +"ep" = (/turf/simulated/shuttle/wall{dir = 8; icon_state = "swall"},/area/casino/casino_cutter) +"eq" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless,/area/space) +"er" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"es" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"et" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless,/area/space) +"eu" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"ev" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/space) +"ew" = (/obj/structure/reagent_dispensers/beerkeg,/turf/simulated/floor/plating,/area/casino/casino_storage) +"ex" = (/obj/structure/casino/oh_bandit,/turf/simulated/floor/plating,/area/casino/casino_storage) +"ey" = (/obj/structure/bed/chair,/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/plating,/area/casino/casino_storage) +"ez" = (/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/plating,/area/casino/casino_storage) +"eA" = (/obj/item/device/multitool,/obj/item/weapon/wirecutters,/turf/simulated/floor/tiled,/area/casino/casino_security) +"eB" = (/obj/machinery/door/airlock/highsecurity{name = "Safe area"},/turf/simulated/floor/plating,/area/casino/casino_security) +"eC" = (/obj/random/coin,/obj/random/cash,/obj/random/ammo,/turf/simulated/floor/plating,/area/casino/casino_security) +"eD" = (/obj/random/coin,/obj/random/ammo,/obj/random/ammo,/turf/simulated/floor/plating,/area/casino/casino_security) +"eE" = (/obj/random/coin,/obj/random/coin,/obj/item/weapon/storage/bag/cash,/mob/living/simple_animal/hostile/carp,/turf/simulated/floor/plating,/area/casino/casino_security) +"eF" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"eG" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"eH" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"eI" = (/obj/structure/cable/yellow,/obj/machinery/power/solar{id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"eJ" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"eK" = (/obj/structure/reagent_dispensers/watertank,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"eL" = (/obj/machinery/vending/assist,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"eM" = (/obj/machinery/vending/engineering,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"eN" = (/obj/machinery/light/small{dir = 4},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"eO" = (/obj/machinery/constructable_frame/machine_frame,/turf/simulated/floor/plating,/area/casino/casino_storage) +"eP" = (/obj/machinery/light,/obj/machinery/vending/tool,/turf/simulated/floor/plating,/area/casino/casino_storage) +"eQ" = (/obj/structure/table/steel_reinforced,/obj/random/tech_supply,/obj/random/tech_supply,/turf/simulated/floor/plating,/area/casino/casino_storage) +"eR" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/toolbox/electrical,/turf/simulated/floor/plating,/area/casino/casino_storage) +"eS" = (/obj/structure/table/steel_reinforced,/obj/machinery/light,/obj/random/coin,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_storage) +"eT" = (/obj/structure/table/steel_reinforced,/obj/random/tool,/obj/item/weapon/circuitboard/recharge_station,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_storage) +"eU" = (/obj/effect/decal/cleanable/blood/splatter,/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/turf/simulated/floor/plating,/area/casino/casino_storage) +"eV" = (/obj/random/cash,/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled,/area/casino/casino_security) +"eW" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"eX" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"eY" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"eZ" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"fa" = (/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"fb" = (/obj/structure/closet/emcloset,/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/tiled,/area/casino/casino_hangar) +"fc" = (/obj/machinery/floodlight,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"fd" = (/obj/structure/reagent_dispensers/beerkeg,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"fe" = (/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/structure/cable,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"ff" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Kitchen"},/obj/effect/decal/cleanable/blood/splatter,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/casino/casino_maintenance) +"fg" = (/obj/machinery/door/airlock{name = "Security wing"},/obj/machinery/door/firedoor/border_only,/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/plating,/area/casino/casino_security) +"fh" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Shuttle hangar"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "casino_checkpoint"; name = "Casino Checkpoint Blast Doors"; opacity = 0},/turf/simulated/floor/tiled,/area/casino/casino_security) +"fi" = (/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"fj" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"fk" = (/obj/random/trash,/obj/structure/cable{icon_state = "4-10"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"fo" = (/obj/machinery/door/airlock{name = "Main desk"},/obj/machinery/door/firedoor/border_only,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_maintenance) +"fq" = (/obj/random/coin,/obj/machinery/light{dir = 1},/obj/effect/decal/cleanable/blood/splatter,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_security) +"fr" = (/obj/machinery/door/airlock{name = "Shuttle checkpoint"},/obj/machinery/door/firedoor/border_only,/obj/effect/decal/cleanable/blood/splatter,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_security) +"fu" = (/obj/structure/table/steel_reinforced,/obj/machinery/door/window/brigdoor/eastleft,/obj/machinery/door/window/brigdoor/westleft,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "casino_checkpoint"; name = "Casino Checkpoint Blast Doors"; opacity = 0},/turf/simulated/floor/tiled,/area/casino/casino_security) +"fv" = (/obj/effect/decal/cleanable/blood/drip,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled,/area/casino/casino_security) +"fw" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/structure/coatrack,/turf/simulated/floor/tiled,/area/casino/casino_security) +"fx" = (/obj/random/loot,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"fy" = (/obj/structure/casino/oh_bandit,/obj/machinery/light{dir = 1},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"fz" = (/obj/structure/casino/oh_bandit,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"fA" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/blast/regular/open{density = 0; dir = 8; icon_state = "pdoor0"; id = "casino_main"},/obj/machinery/door/firedoor/border_only,/turf/space,/area/casino/casino_mainfloor) +"fB" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"fC" = (/obj/structure/cable{icon_state = "2-5"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"fD" = (/obj/structure/closet/emcloset,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"fE" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Kitchen"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/casino/casino_maintenance) +"fF" = (/obj/machinery/door/airlock{name = "Main desk"},/obj/machinery/door/firedoor/border_only,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/casino/casino_security) +"fH" = (/obj/structure/table/steel_reinforced,/obj/item/device/radio,/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/casino/casino_security) +"fI" = (/obj/effect/decal/cleanable/blood/drip,/obj/item/ammo_casing/shotgun,/turf/simulated/floor/tiled,/area/casino/casino_security) +"fJ" = (/obj/item/weapon/material/shard,/obj/structure/coatrack,/turf/simulated/floor/tiled,/area/casino/casino_security) +"fK" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"fL" = (/obj/structure/bed/chair/office/light{dir = 1},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"fM" = (/obj/machinery/power/solar{id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array"},/obj/structure/cable/yellow,/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"fN" = (/obj/structure/mopbucket,/obj/item/weapon/mop,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"fO" = (/obj/item/weapon/reagent_containers/glass/bucket,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"fP" = (/obj/structure/closet/crate/trashcart,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"fQ" = (/turf/simulated/wall,/area/casino/casino_crew_cantina) +"fR" = (/obj/effect/decal/cleanable/blood/splatter,/obj/structure/cable,/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"fS" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/weapon/material/kitchen/utensil/fork,/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"fT" = (/obj/machinery/light{dir = 1},/obj/structure/table/standard{name = "plastic table frame"},/obj/item/trash/plate,/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"fU" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/random/snack,/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"fV" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton,/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"fW" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/weapon/cigbutt/professionals,/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"fX" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/trash/plate,/obj/random/snack,/obj/random/snack,/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"fY" = (/obj/machinery/light{dir = 1},/obj/structure/table/standard{name = "plastic table frame"},/obj/random/snack,/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"fZ" = (/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"ga" = (/turf/simulated/wall,/area/casino/casino_mainfloor) +"gb" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"gc" = (/obj/structure/closet/emcloset,/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"gd" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Casino"},/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "casino_checkpoint"; name = "Casino Checkpoint Blast Doors"; opacity = 0},/turf/simulated/floor/plating,/area/casino/casino_security) +"ge" = (/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"gf" = (/obj/structure/window/basic,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"gg" = (/turf/simulated/wall/r_wall,/area/casino/casino_solar_control) +"gh" = (/obj/structure/table/rack{dir = 8},/obj/random/material,/obj/random/material,/obj/random/material,/obj/random/material,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"gi" = (/obj/structure/table/rack{dir = 8},/obj/random/tech_supply,/obj/item/stack/cable_coil,/obj/item/stack/cable_coil,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"gj" = (/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"gk" = (/obj/structure/bed/chair{dir = 1},/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"gl" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"gm" = (/obj/structure/bed/chair{dir = 1},/obj/item/weapon/reagent_containers/food/drinks/flask/shiny,/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"gn" = (/obj/structure/bed/chair{dir = 1},/obj/random/snack,/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"gp" = (/obj/random/ammo,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"gq" = (/obj/structure/safe,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/structure/fireaxecabinet{pixel_y = 30},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"gr" = (/obj/structure/safe,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/random/coin,/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"gs" = (/obj/machinery/door/firedoor/border_only,/obj/structure/table/marble,/obj/machinery/button/remote/blast_door{id = "casino_main"; name = "Main floor Blast Doors"},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"gt" = (/obj/machinery/door/firedoor/border_only,/obj/structure/table/marble,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"gu" = (/obj/structure/table/woodentable,/obj/item/clothing/mask/smokable/pipe,/obj/machinery/light{dir = 1},/obj/item/weapon/material/ashtray/bronze,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"gv" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigar,/obj/item/weapon/storage/fancy/cigar{pixel_y = 5},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"gw" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless,/area/space) +"gx" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1329; master_tag = "casino_solar_airlock"; name = "exterior access button"; pixel_x = 28; pixel_y = 24; req_one_access = list(13)},/turf/simulated/floor/airless,/area/space) +"gy" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "solar_casino_outer"; locked = 1; name = "External Access"; req_access = list(11,13)},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/casino/casino_solar_control) +"gz" = (/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1329; id_tag = "casino_solar_airlock"; pixel_x = 24; req_access = list(13); tag_airpump = "casino_solar_pump"; tag_chamber_sensor = "casino_solar_sensor"; tag_exterior_door = "casino_solar_outer"; tag_interior_door = "casino_solar_inner"},/obj/machinery/airlock_sensor{frequency = 1329; id_tag = "casino_solar_sensor"; pixel_x = 24; pixel_y = 12},/obj/effect/floor_decal/industrial/warning/full,/obj/machinery/oxygen_pump{pixel_x = 0; pixel_y = 32},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 2; frequency = 1329; id_tag = "casino_solar_pump"},/turf/simulated/floor/plating,/area/casino/casino_solar_control) +"gA" = (/obj/structure/table/rack{dir = 8},/obj/item/stack/cable_coil,/obj/random/material,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"gB" = (/obj/effect/decal/cleanable/generic,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"gC" = (/obj/structure/table/rack{dir = 8},/obj/random/tech_supply,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"gD" = (/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"gE" = (/obj/item/weapon/cigbutt/menthol,/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"gG" = (/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"gH" = (/obj/random/coin,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"gI" = (/obj/structure/bed/chair{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"gJ" = (/obj/random/cash,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"gK" = (/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/power/solar{id = "auxsolarsport"; name = "Port Auxiliary Solar Array"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"gL" = (/obj/machinery/door/airlock/external{frequency = 1329; icon_state = "door_locked"; id_tag = "solar_casino_inner"; locked = 1; name = "External Access"; req_access = list(11,13)},/obj/machinery/atmospherics/pipe/simple/hidden,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/casino/casino_solar_control) +"gM" = (/turf/simulated/wall,/area/casino/casino_solar_control) +"gX" = (/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"gY" = (/obj/random/cash,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"gZ" = (/obj/effect/decal/cleanable/blood/drip,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"ha" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/space) +"hb" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden{dir = 8; icon_state = "map"},/obj/machinery/access_button{command = "cycle_interior"; frequency = 1329; master_tag = "casino_solar_airlock"; name = "interior access button"; pixel_x = 24; pixel_y = 24; req_access = list(11,13)},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/casino/casino_solar_control) +"hc" = (/obj/machinery/portable_atmospherics/canister/air/airlock,/obj/machinery/atmospherics/portables_connector{dir = 8},/obj/effect/floor_decal/industrial/warning/corner{dir = 1},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/plating,/area/casino/casino_solar_control) +"hd" = (/obj/structure/table/rack{dir = 8},/obj/random/tech_supply,/obj/item/stack/cable_coil,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"hf" = (/obj/machinery/door/window/southleft,/obj/machinery/door/firedoor/border_only,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"hg" = (/obj/machinery/door/firedoor/border_only,/obj/structure/table/marble,/obj/structure/flora/pottedplant/unusual,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"hi" = (/obj/item/weapon/storage/secure/briefcase/money,/obj/random/cash,/obj/random/cash,/obj/random/cash,/obj/random/cash,/obj/random/cash,/obj/random/cash,/obj/random/cash,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"hj" = (/obj/random/ammo,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"hk" = (/obj/structure/cable/yellow,/obj/machinery/power/solar{id = "auxsolarsport"; name = "Port Auxiliary Solar Array"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"hl" = (/obj/structure/cable/yellow,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/atmospherics/binary/pump/on{dir = 1; target_pressure = 200},/turf/simulated/floor/plating,/area/casino/casino_solar_control) +"hm" = (/obj/machinery/power/solar_control{id = "solar"; name = "Solar Control"; track = 0},/obj/effect/floor_decal/industrial/warning/corner{dir = 4},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/casino/casino_solar_control) +"hn" = (/turf/simulated/wall,/area/casino/casino_kitchen) +"hp" = (/obj/structure/sink/kitchen{pixel_y = 30},/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"hq" = (/obj/machinery/cooker/cereal,/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"hr" = (/obj/machinery/cooker/candy,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"hs" = (/obj/machinery/cooker/fryer,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"ht" = (/obj/machinery/cooker/oven,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"hu" = (/obj/machinery/cooker/grill,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"hv" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"hw" = (/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"hx" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Kitchen"},/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"hy" = (/obj/item/weapon/material/shard,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"hz" = (/obj/item/device/flash,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"hA" = (/obj/machinery/light,/obj/structure/flora/pottedplant,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"hB" = (/obj/item/weapon/cigbutt/cigarbutt,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"hC" = (/obj/structure/table/gamblingtable,/obj/structure/casino/roulette_chart,/obj/random/coin,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"hD" = (/obj/structure/table/gamblingtable,/obj/structure/casino/roulette,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"hE" = (/obj/structure/flora/pottedplant/unusual,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"hF" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden,/turf/simulated/floor/plating,/area/casino/casino_solar_control) +"hG" = (/obj/machinery/power/terminal,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_solar_control) +"hH" = (/obj/random/trash,/obj/structure/table/rack{dir = 8},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"hJ" = (/obj/random/trash,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"hK" = (/obj/effect/decal/cleanable/flour,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"hL" = (/obj/structure/table/marble,/obj/machinery/microwave,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"hM" = (/obj/structure/coatrack,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"hN" = (/obj/effect/decal/cleanable/generic,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"hO" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"hP" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating,/area/casino/casino_solar_control) +"hR" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"hS" = (/obj/machinery/light/small,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"hT" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Kitchen"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"hV" = (/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"hW" = (/obj/effect/decal/cleanable/egg_smudge,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"hX" = (/obj/structure/table/marble,/obj/machinery/reagentgrinder,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"hY" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/structure/coatrack,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"hZ" = (/obj/structure/bed/chair/comfy/red{dir = 4},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"ia" = (/obj/structure/table/woodentable,/obj/item/trash/plate,/obj/item/weapon/material/kitchen/utensil/fork,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"ib" = (/obj/structure/table/woodentable,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"ic" = (/obj/structure/bed/chair/comfy/red{dir = 8},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"id" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"ie" = (/obj/structure/table/gamblingtable,/obj/structure/casino/craps,/obj/random/coin,/obj/random/coin,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"if" = (/obj/random/smokes,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"ig" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless,/area/space) +"ih" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/atmospherics/pipe/simple/hidden,/obj/machinery/door/airlock{name = "Solar control"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/casino/casino_solar_control) +"ii" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Atmos control"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"ij" = (/turf/simulated/wall/r_wall,/area/casino/casino_crew_atmos) +"ik" = (/obj/effect/decal/cleanable/tomato_smudge,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"il" = (/obj/structure/closet/secure_closet/freezer/fridge,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/item/weapon/storage/fancy/egg_box,/obj/item/weapon/storage/fancy/egg_box,/obj/item/weapon/storage/fancy/egg_box,/obj/item/weapon/reagent_containers/food/condiment/flour,/obj/item/weapon/reagent_containers/food/condiment/sugar,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"im" = (/obj/structure/closet/secure_closet/freezer/fridge,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/item/weapon/reagent_containers/food/condiment/sugar,/obj/item/weapon/reagent_containers/food/snacks/sliceable/bread,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"in" = (/obj/structure/closet/secure_closet/freezer/fridge,/obj/item/weapon/reagent_containers/food/condiment/flour,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"io" = (/obj/structure/table/marble,/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/machinery/chem_master/condimaster,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"ip" = (/obj/structure/bed/chair/comfy/red{dir = 4},/obj/item/weapon/material/kitchen/utensil/knife,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"iq" = (/obj/structure/table/woodentable,/obj/item/trash/plate,/obj/item/weapon/reagent_containers/food/snacks/applepie,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"ir" = (/obj/structure/table/woodentable,/obj/item/trash/plate,/obj/item/weapon/reagent_containers/food/snacks/bigbiteburger,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"is" = (/obj/structure/table/gamblingtable,/obj/structure/casino/craps/craps_down,/obj/item/weapon/dice,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"iu" = (/obj/structure/flora/pottedplant,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"iv" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 5; icon_state = "intact"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"iw" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4; icon_state = "intact"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"ix" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"iz" = (/obj/structure/fireaxecabinet{pixel_y = 30},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"iA" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"iB" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"iC" = (/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/structure/window/basic{dir = 8},/obj/structure/closet/secure_closet/freezer/meat,/obj/item/weapon/reagent_containers/food/snacks/meat,/obj/item/weapon/reagent_containers/food/snacks/meat,/obj/item/weapon/reagent_containers/food/snacks/meat,/obj/item/weapon/reagent_containers/food/snacks/meat,/turf/simulated/floor/tiled/freezer,/area/casino/casino_kitchen) +"iD" = (/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/machinery/gibber,/turf/simulated/floor/tiled/freezer,/area/casino/casino_kitchen) +"iE" = (/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/structure/window/basic{icon_state = "window"; dir = 4},/obj/structure/kitchenspike,/turf/simulated/floor/tiled/freezer,/area/casino/casino_kitchen) +"iF" = (/obj/machinery/vending/dinnerware,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"iG" = (/obj/structure/table/marble,/obj/item/trash/plate,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"iH" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/structure/closet/emcloset,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"iI" = (/obj/machinery/atmospherics/pipe/tank/carbon_dioxide,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"iJ" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/machinery/floodlight,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"iK" = (/obj/effect/floor_decal/industrial/warning{dir = 5},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"iL" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"iM" = (/obj/structure/window/basic{dir = 8},/turf/simulated/floor/tiled/freezer,/area/casino/casino_kitchen) +"iN" = (/turf/simulated/floor/tiled/freezer,/area/casino/casino_kitchen) +"iO" = (/obj/machinery/door/window/brigdoor/eastleft,/turf/simulated/floor/tiled/freezer,/area/casino/casino_kitchen) +"iP" = (/obj/effect/decal/cleanable/pie_smudge,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"iQ" = (/obj/machinery/door/firedoor/border_only,/obj/structure/table/marble,/obj/item/trash/tray,/obj/item/weapon/reagent_containers/food/snacks/stew,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"iR" = (/obj/structure/table/woodentable,/obj/item/trash/plate,/obj/item/weapon/material/kitchen/utensil/spoon,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"iS" = (/obj/machinery/light,/obj/structure/flora/pottedplant/unusual,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"iT" = (/obj/random/coin,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"iU" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 6},/turf/simulated/wall/r_wall,/area/casino/casino_crew_atmos) +"iV" = (/obj/machinery/atmospherics/binary/pump{dir = 8},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"iW" = (/obj/machinery/atmospherics/pipe/manifold/visible/red,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"iX" = (/obj/machinery/atmospherics/trinary/filter/m_filter{dir = 8},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"iY" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"iZ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"ja" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/structure/flora/pottedplant/unusual,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"jb" = (/obj/structure/device/piano,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"jc" = (/obj/structure/bed/chair/comfy/beige{dir = 8},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"jd" = (/obj/random/coin,/obj/random/ammo,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"je" = (/obj/machinery/atmospherics/pipe/simple/visible/red,/turf/simulated/wall/r_wall,/area/casino/casino_crew_atmos) +"jf" = (/obj/structure/closet/firecloset,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jg" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{icon_state = "intact"; dir = 6},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jh" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{icon_state = "intact"; dir = 9},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"ji" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jj" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jk" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"jl" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Bar storage"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"jm" = (/obj/machinery/light{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"jn" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"jo" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Bar"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"jp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"jq" = (/obj/structure/sink/kitchen{pixel_y = 30},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"jr" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"js" = (/obj/machinery/alarm{pixel_y = 25},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"jt" = (/obj/machinery/vending/boozeomat,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"ju" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 4; icon_state = "map_injector"; use_power = 1},/turf/simulated/floor/airless,/area/space) +"jv" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 9},/turf/simulated/wall/r_wall,/area/casino/casino_crew_atmos) +"jw" = (/obj/machinery/atmospherics/pipe/tank/air{dir = 4; start_pressure = 740.5},/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jx" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/cyan,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jy" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jz" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jA" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jB" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jC" = (/obj/item/weapon/broken_bottle,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"jD" = (/obj/machinery/vending/coffee,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"jE" = (/obj/structure/table/marble,/obj/item/weapon/reagent_containers/food/drinks/bottle/absinthe,/obj/item/weapon/reagent_containers/food/drinks/shaker{pixel_x = 10; pixel_y = 10},/obj/random/drinkbottle,/obj/random/drinkbottle,/obj/random/drinkbottle,/obj/random/drinkbottle,/obj/random/drinkbottle,/obj/random/drinkbottle,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"jF" = (/obj/structure/table/marble,/obj/machinery/chemical_dispenser/bar_alc/full,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"jG" = (/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"jH" = (/obj/structure/table/marble,/obj/item/weapon/material/ashtray/bronze,/obj/item/weapon/flame/lighter/zippo,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"jI" = (/obj/item/weapon/stool/bar,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"jJ" = (/obj/structure/table/woodentable,/obj/item/weapon/material/ashtray/bronze,/obj/item/weapon/reagent_containers/food/snacks/cubancarp,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"jK" = (/obj/item/weapon/material/ashtray/bronze,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"jL" = (/obj/machinery/atmospherics/pipe/tank/air{dir = 4; start_pressure = 740.5},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jM" = (/obj/machinery/atmospherics/pipe/manifold/visible/cyan{dir = 4; icon_state = "map"},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jN" = (/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jO" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jP" = (/obj/effect/decal/cleanable/generic,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jQ" = (/obj/structure/table/marble,/obj/item/weapon/storage/box/glass_extras/sticks,/obj/item/weapon/storage/box/glass_extras/straws,/obj/item/weapon/storage/box/glass_extras,/obj/item/weapon/storage/box/glasses/pint,/obj/item/weapon/storage/box/glasses/wine,/obj/item/device/radio,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"jR" = (/obj/structure/table/marble,/obj/item/weapon/reagent_containers/food/drinks/bottle/gin,/obj/item/weapon/reagent_containers/food/drinks/bottle/tequilla{pixel_x = -10},/obj/item/weapon/reagent_containers/food/drinks/bottle/vodka{pixel_x = 10},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"jS" = (/obj/structure/table/marble,/obj/machinery/chemical_dispenser/bar_soft/full,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"jT" = (/obj/structure/table/marble,/obj/random/coin,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"jU" = (/obj/structure/table/woodentable,/obj/item/trash/plate,/obj/item/weapon/reagent_containers/food/snacks/waffles,/obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"jV" = (/obj/structure/table/gamblingtable,/obj/structure/casino/craps,/obj/item/weapon/dice{pixel_x = 5; pixel_y = -5},/obj/item/weapon/dice,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"jW" = (/obj/structure/table/gamblingtable,/obj/structure/casino/bj_table,/obj/item/weapon/deck/cards{pixel_x = 5; pixel_y = -5},/obj/random/coin,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"jX" = (/obj/structure/table/gamblingtable,/obj/structure/casino/bj_table/bj_right,/obj/item/clothing/mask/smokable/cigarette/cigar/havana,/obj/item/weapon/material/ashtray/bronze,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"jY" = (/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"jZ" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"ka" = (/obj/effect/decal/cleanable/generic,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"kb" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"kc" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"kd" = (/obj/structure/table/marble,/obj/random/drinkbottle,/obj/random/drinkbottle,/obj/random/drinkbottle,/obj/random/drinkbottle,/obj/random/drinkbottle,/obj/random/drinkbottle,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"ke" = (/obj/structure/reagent_dispensers/beerkeg,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"kf" = (/obj/structure/table/marble,/obj/item/weapon/reagent_containers/food/drinks/bottle/rum,/obj/item/weapon/reagent_containers/glass/rag,/obj/random/drinkbottle,/obj/random/drinkbottle,/obj/random/drinkbottle,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"kg" = (/obj/item/weapon/cigbutt/professionals,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"kh" = (/obj/structure/table/marble,/obj/item/weapon/reagent_containers/food/drinks/bottle/cognac,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"ki" = (/obj/item/weapon/stool/bar,/obj/random/coin,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kj" = (/obj/item/weapon/broken_bottle,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kk" = (/obj/structure/table/gamblingtable,/obj/structure/casino/craps/craps_down,/obj/random/coin,/obj/random/coin,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kl" = (/obj/structure/bed/chair/comfy/black{dir = 1},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"km" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/structure/table/rack,/obj/item/weapon/wrench,/obj/item/clothing/head/welding,/obj/item/weapon/weldingtool,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"kn" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Kitchen"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"ko" = (/obj/structure/table/marble,/obj/item/weapon/reagent_containers/food/drinks/h_chocolate,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"kp" = (/obj/structure/table/marble,/obj/item/weapon/storage/fancy/cigar{pixel_y = 5},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"kq" = (/obj/structure/table/marble,/obj/random/smokes,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"kr" = (/obj/structure/table/marble,/obj/random/loot,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"ks" = (/obj/structure/table/marble,/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"kt" = (/obj/structure/table/woodentable,/obj/item/pizzabox/meat,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"ku" = (/obj/machinery/portable_atmospherics/canister/oxygen,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"kv" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"kw" = (/obj/random/ammo,/obj/effect/decal/cleanable/blood/splatter,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kx" = (/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"ky" = (/obj/machinery/light{dir = 1},/obj/random/ammo,/obj/structure/flora/pottedplant/overgrown,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kz" = (/obj/structure/flora/pottedplant/overgrown,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kA" = (/obj/structure/table/gamblingtable,/obj/structure/casino/bj_table,/obj/random/coin,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kB" = (/obj/structure/table/gamblingtable,/obj/structure/casino/bj_table/bj_right,/obj/item/weapon/deck/cards,/obj/random/coin{pixel_x = -2; pixel_y = 4},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kC" = (/turf/simulated/wall/r_wall,/area/casino/casino_bow) +"kD" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"kE" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/structure/table/rack,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/device/radio,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"kG" = (/obj/random/ammo,/obj/effect/decal/cleanable/blood/splatter,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kH" = (/obj/random/loot,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kI" = (/obj/random/ammo,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kJ" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kN" = (/obj/machinery/light,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kO" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kP" = (/obj/machinery/portable_atmospherics/canister/phoron,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"kQ" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/unpowered/simple/wood{name = "VIP Private room"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/wood,/area/casino/casino_mainfloor) +"kR" = (/turf/simulated/wall,/area/casino/casino_private_vip) +"kS" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/unpowered/simple/wood{name = "Private room 1"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/wood,/area/casino/casino_mainfloor) +"kT" = (/turf/simulated/wall,/area/casino/casino_private1) +"kU" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/unpowered/simple/wood{name = "Private room 2"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/wood,/area/casino/casino_mainfloor) +"kV" = (/turf/simulated/wall,/area/casino/casino_private2) +"kX" = (/obj/structure/flora/pottedplant,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kY" = (/obj/machinery/light,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"kZ" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"la" = (/obj/structure/cable{icon_state = "2-8"},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"lb" = (/turf/simulated/floor/reinforced,/area/casino/casino_bow) +"lc" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/reinforced,/area/casino/casino_bow) +"ld" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/portable_atmospherics/canister/phoron,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"le" = (/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"lf" = (/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"lg" = (/obj/effect/decal/cleanable/blood/splatter,/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"lh" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"li" = (/obj/machinery/light{dir = 1},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"lj" = (/obj/machinery/media/jukebox,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"lk" = (/obj/structure/flora/pottedplant,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"ll" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/wood,/area/casino/casino_private1) +"lm" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/wood,/area/casino/casino_private1) +"ln" = (/obj/machinery/light{dir = 1},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/wood,/area/casino/casino_private1) +"lo" = (/obj/structure/flora/pottedplant,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/turf/simulated/floor/wood,/area/casino/casino_private1) +"lp" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/wood,/area/casino/casino_private2) +"lq" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/wood,/area/casino/casino_private2) +"lr" = (/obj/machinery/light{dir = 1},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/wood,/area/casino/casino_private2) +"ls" = (/obj/structure/flora/pottedplant,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/turf/simulated/floor/wood,/area/casino/casino_private2) +"lt" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Toilet room"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/casino/casino_mainfloor) +"lu" = (/turf/simulated/wall,/area/casino/casino_patron_bathroom) +"lv" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"lw" = (/obj/structure/showcase{desc = "A bewilderingly complex prototype designed to split the fabric of spacetime and allow access to Bluespace."; icon = 'icons/obj/power.dmi'; icon_state = "tracker"; name = "Bluespace Drive"},/obj/machinery/shield{desc = "An energy shield used to contain the exotic particles emitted by the Bluespace Drive."; name = "Containment Shield"},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/reinforced,/area/casino/casino_bow) +"lx" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/reinforced,/area/casino/casino_bow) +"ly" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/reinforced,/area/casino/casino_bow) +"lz" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock/engineering{name = "Bluespace Drive"; req_access = newlist(); secured_wires = 0},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"lA" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"lB" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/light/small,/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"lD" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"lE" = (/obj/random/ammo,/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"lF" = (/obj/effect/decal/cleanable/blood/drip,/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"lG" = (/obj/effect/decal/cleanable/blood/drip,/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"lH" = (/obj/item/weapon/cigbutt/professionals,/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"lI" = (/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"lJ" = (/obj/item/weapon/storage/secure/safe{pixel_x = 30},/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"lK" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/wood,/area/casino/casino_private1) +"lL" = (/turf/simulated/floor/wood,/area/casino/casino_private1) +"lM" = (/obj/item/weapon/storage/secure/safe{pixel_x = 30},/turf/simulated/floor/wood,/area/casino/casino_private1) +"lN" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/wood,/area/casino/casino_private2) +"lO" = (/turf/simulated/floor/wood,/area/casino/casino_private2) +"lP" = (/obj/item/weapon/storage/secure/safe{pixel_x = 25},/turf/simulated/floor/wood,/area/casino/casino_private2) +"lQ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/casino/casino_patron_bathroom) +"lR" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled/white,/area/casino/casino_patron_bathroom) +"lS" = (/obj/machinery/door/airlock{name = "Toilet #1"},/turf/simulated/floor/tiled/white,/area/casino/casino_patron_bathroom) +"lT" = (/obj/structure/toilet{dir = 8},/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/random/trash,/turf/simulated/floor/tiled/white,/area/casino/casino_patron_bathroom) +"lU" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"lV" = (/obj/structure/bed/chair/comfy/black,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"lW" = (/obj/machinery/portable_atmospherics/canister/phoron,/turf/simulated/floor/reinforced,/area/casino/casino_bow) +"lX" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Bow"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/casino/casino_bow) +"lY" = (/obj/structure/bed/chair/comfy/red{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"lZ" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigar{pixel_y = 5},/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"ma" = (/obj/structure/table/woodentable,/obj/item/weapon/material/ashtray/bronze,/obj/random/drinkbottle,/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"mb" = (/obj/structure/bed/chair/comfy/red{dir = 8},/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"mc" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"md" = (/obj/structure/bed/chair/comfy/red,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/wood,/area/casino/casino_private1) +"me" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/wood,/area/casino/casino_private1) +"mf" = (/obj/structure/bed/chair/comfy/red,/obj/item/weapon/flame/lighter/zippo,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/wood,/area/casino/casino_private2) +"mg" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/wood,/area/casino/casino_private2) +"mh" = (/obj/structure/sink{icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2},/obj/structure/mirror{pixel_x = -25},/obj/random/soap,/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/casino/casino_patron_bathroom) +"mi" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/turf/simulated/floor/tiled/white,/area/casino/casino_patron_bathroom) +"mj" = (/obj/structure/table/woodentable,/obj/item/weapon/reagent_containers/food/drinks/bottle/specialwhiskey,/obj/item/clothing/mask/smokable/cigarette/cigar/havana,/obj/item/clothing/mask/smokable/cigarette/cigar/havana,/obj/item/weapon/flame/lighter/zippo,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"mk" = (/obj/machinery/computer/engines,/turf/simulated/floor/plating,/area/casino/casino_bow) +"ml" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/plating,/area/casino/casino_bow) +"mm" = (/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/plating,/area/casino/casino_bow) +"mn" = (/obj/structure/closet/emcloset,/turf/simulated/floor/plating,/area/casino/casino_bow) +"mo" = (/obj/effect/decal/cleanable/blood/splatter,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/casino/casino_bow) +"mp" = (/obj/structure/bed/chair/comfy/red{dir = 4},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"mq" = (/obj/structure/table/woodentable,/obj/random/drinkbottle,/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"mr" = (/obj/structure/table/woodentable,/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"ms" = (/obj/structure/bed/chair/comfy/red{dir = 8},/obj/item/weapon/storage/bag/cash,/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"mt" = (/obj/structure/bed,/turf/simulated/floor/wood,/area/casino/casino_private_vip) +"mu" = (/obj/structure/table/woodentable,/obj/random/drinkbottle,/obj/random/coin,/obj/random/coin,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/wood,/area/casino/casino_private1) +"mv" = (/obj/structure/bed/chair/comfy/red{dir = 8},/turf/simulated/floor/wood,/area/casino/casino_private1) +"mw" = (/obj/structure/bed,/turf/simulated/floor/wood,/area/casino/casino_private1) +"mx" = (/obj/structure/table/woodentable,/obj/random/drinkbottle,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/wood,/area/casino/casino_private2) +"my" = (/obj/structure/bed/chair/comfy/red{dir = 8},/turf/simulated/floor/wood,/area/casino/casino_private2) +"mz" = (/obj/structure/bed,/obj/random/coin,/turf/simulated/floor/wood,/area/casino/casino_private2) +"mA" = (/obj/structure/sink{icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2},/obj/structure/mirror{pixel_x = -25},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled/white,/area/casino/casino_patron_bathroom) +"mB" = (/obj/random/coin,/turf/simulated/floor/tiled/white,/area/casino/casino_patron_bathroom) +"mC" = (/obj/machinery/door/airlock{name = "Toilet #2"},/turf/simulated/floor/tiled/white,/area/casino/casino_patron_bathroom) +"mD" = (/obj/structure/toilet{dir = 8},/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/tiled/white,/area/casino/casino_patron_bathroom) +"mE" = (/obj/structure/sign/warning/pods{pixel_y = -30},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"mF" = (/obj/effect/shuttle_landmark/nav_casino/nav2,/turf/space,/area/space) +"mG" = (/obj/item/modular_computer/console,/turf/simulated/floor/plating,/area/casino/casino_bow) +"mH" = (/turf/simulated/floor/plating,/area/casino/casino_bow) +"mI" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_bow) +"mJ" = (/obj/effect/decal/cleanable/blood/splatter,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_bow) +"mK" = (/obj/structure/cable,/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/turf/simulated/floor/plating,/area/casino/casino_bow) +"mL" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Bow"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/casino/casino_mainfloor) +"mM" = (/turf/space,/turf/simulated/shuttle/wall/corner/dark/sw,/area/casino/casino_bow) +"mN" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/plating,/area/casino/casino_bow) +"mO" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_bow) +"mP" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_bow) +"mQ" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/plating,/area/casino/casino_bow) +"mR" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/plating,/area/casino/casino_bow) +"mS" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plating,/area/casino/casino_bow) +"mT" = (/turf/space,/turf/simulated/shuttle/wall/corner/dark/se,/area/casino/casino_bow) +"mU" = (/obj/machinery/atmospherics/portables_connector{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_bow) +"mV" = (/obj/machinery/atmospherics/binary/pump/on{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_bow) +"mW" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 10},/turf/simulated/floor/plating,/area/casino/casino_bow) +"mX" = (/obj/structure/sign/warning/pods{pixel_y = -30},/turf/simulated/floor/plating,/area/casino/casino_bow) +"mY" = (/obj/machinery/atmospherics/pipe/simple/visible/black,/obj/machinery/door/airlock{name = "Engines #1"},/turf/simulated/floor/plating,/area/casino/casino_bow) +"mZ" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/blast/regular/open{icon_state = "pdoor0"; id = "Starboard wide window BD"},/turf/space,/area/casino/casino_bow) +"na" = (/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "escape_pod"; locked = 1; name = "Escape Pod"; req_access = list(13)},/turf/simulated/floor/plating,/area/casino/casino_bow) +"nb" = (/obj/machinery/atmospherics/pipe/simple/visible/black,/obj/machinery/door/airlock{name = "Engines #2"},/turf/simulated/floor/plating,/area/casino/casino_bow) +"nc" = (/obj/machinery/atmospherics/pipe/tank/nitrogen{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_bow) +"nd" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/black,/turf/simulated/floor/plating,/area/casino/casino_bow) +"ne" = (/obj/machinery/atmospherics/unary/heater{dir = 8},/turf/simulated/floor/plating,/area/casino/casino_bow) +"nf" = (/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/casino/casino_bow) +"ng" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 6},/turf/simulated/floor/airless,/area/casino/casino_bow) +"nh" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/black,/obj/machinery/meter,/turf/simulated/floor/airless,/area/casino/casino_bow) +"ni" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 10},/turf/simulated/floor/airless,/area/casino/casino_bow) +"nj" = (/obj/structure/bed/chair,/obj/item/device/radio/intercom{dir = 4; pixel_x = -22},/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_bow) +"nk" = (/obj/effect/shuttle_landmark/nav_casino/nav4,/turf/space,/area/space) +"nl" = (/obj/machinery/atmospherics/unary/engine{dir = 1},/turf/simulated/wall/r_wall,/area/casino/casino_bow) +"nm" = (/obj/structure/bed/chair,/obj/machinery/status_display{pixel_x = -32; pixel_y = 0},/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod{frequency = 1380; id_tag = "Casino_escape_pod_3"; name = "Casino escape pod Three controller"; pixel_x = 24; pixel_y = 0; tag_door = "Casino escape_pod_3_hatch"},/turf/simulated/floor/plating,/area/casino/casino_bow) +"nn" = (/obj/structure/bed/chair,/obj/machinery/status_display{pixel_x = -32; pixel_y = 0},/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod{frequency = 1380; id_tag = "Casino_escape_pod_2"; name = "Casino escape pod Two controller"; pixel_x = 24; pixel_y = 0; tag_door = "Casino escape_pod_2_hatch"},/turf/simulated/floor/plating,/area/casino/casino_bow) +"no" = (/obj/structure/bed/chair,/obj/machinery/status_display{pixel_x = -32; pixel_y = 0},/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod{frequency = 1380; id_tag = "Casino_escape_pod_1"; name = "Casino escape pod One controller"; pixel_x = 24; pixel_y = 0; tag_door = "escape_pod_17_hatch"},/turf/simulated/floor/plating,/area/casino/casino_bow) +"np" = (/turf/simulated/shuttle/wall/corner/dark,/area/casino/casino_bow) +"nq" = (/obj/structure/grille,/obj/structure/window/reinforced/full,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plating,/area/casino/casino_bow) +"nr" = (/turf/simulated/shuttle/wall/corner/dark{dir = 6},/area/casino/casino_bow) +"ns" = (/turf/simulated/floor/reinforced/airless,/area/casino/casino_bow) +"ob" = (/obj/structure/table/gamblingtable,/obj/structure/casino/roulette_chart,/obj/random/coin,/obj/random/coin,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"oc" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"pb" = (/obj/item/ammo_casing/a50/used,/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"pc" = (/obj/machinery/vending/wallmed1{pixel_x = -25},/obj/item/device/radio,/obj/effect/decal/cleanable/blood/splatter,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"qb" = (/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"qc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"rb" = (/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"rc" = (/obj/machinery/computer/arcade,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"sb" = (/obj/effect/decal/cleanable/blood/splatter,/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"sc" = (/obj/structure/reagent_dispensers/water_cooler,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"tb" = (/obj/item/ammo_casing/a556/used,/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"tc" = (/obj/machinery/vending/snack,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"ub" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"uc" = (/obj/machinery/vending/fitness,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"vb" = (/obj/effect/decal/cleanable/blood/splatter,/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"vc" = (/obj/machinery/vending/cola,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"wb" = (/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/obj/machinery/alarm{dir = 1; pixel_y = -25},/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"wc" = (/obj/machinery/vending/coffee,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"xb" = (/obj/effect/decal/cleanable/blood/splatter,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_security) +"xc" = (/obj/machinery/vending/cigarette,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"yb" = (/obj/effect/decal/cleanable/blood/splatter,/obj/item/ammo_casing/a50/used,/turf/simulated/floor/tiled,/area/casino/casino_security) +"yc" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"zb" = (/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/obj/structure/cable{icon_state = "5-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_crew_bunk) +"zc" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock{name = "Kitchen"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"Ab" = (/obj/item/weapon/gun/projectile/sec/MK,/obj/item/ammo_casing/a50/used,/obj/item/ammo_casing/a50/used,/turf/simulated/floor/tiled,/area/casino/casino_security) +"Ac" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) +"Bb" = (/obj/item/weapon/material/shard,/obj/item/ammo_casing/a50/used,/turf/simulated/floor/tiled,/area/casino/casino_security) +"Bc" = (/obj/machinery/door/firedoor/border_only,/obj/structure/table/marble,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/casino/casino_crew_cantina) +"Cb" = (/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/turf/simulated/floor/tiled/white,/area/casino/casino_crew_bathroom) +"Cc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"Db" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/obj/item/ammo_casing/a556/used,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"Dc" = (/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable,/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"Eb" = (/obj/effect/decal/cleanable/blood,/obj/item/weapon/gun/projectile/magnum_pistol,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/item/ammo_casing/a50/used,/obj/item/ammo_casing/a50/used,/obj/item/ammo_casing/a50/used,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_security) +"Ec" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"Fb" = (/obj/structure/bed/chair{dir = 4; icon_state = "chair_preview"},/obj/effect/decal/cleanable/blood,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/item/ammo_casing/a50/used,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/button/remote/blast_door{id = "casino_checkpoint"; name = "Casino Checkpoint Blast Door contol"; pixel_y = -25},/turf/simulated/floor/tiled,/area/casino/casino_security) +"Fc" = (/turf/simulated/wall/r_wall,/area/casino/casino_mainfloor) +"Gb" = (/obj/item/ammo_casing/a50/used,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/flora/pottedplant/unusual,/turf/simulated/floor/tiled,/area/casino/casino_security) +"Gc" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled,/area/casino/casino_kitchen) +"Hb" = (/obj/item/ammo_casing/a556/used,/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"Hc" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"Ib" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"Ic" = (/obj/structure/flora/pottedplant,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"Jb" = (/obj/machinery/power/smes/buildable{charge = 0; RCon_tag = "Solar - Starboard"},/obj/effect/engine_setup/smes,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/casino/casino_solar_control) +"Jc" = (/obj/effect/decal/cleanable/blood/splatter,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"Kb" = (/obj/item/modular_computer/console{name = "Cameras console"},/turf/simulated/floor/tiled,/area/casino/casino_bridge) +"Kc" = (/obj/item/ammo_casing/a556{pixel_x = 4; pixel_y = -8},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"Lb" = (/obj/structure/lattice,/obj/structure/grille,/turf/space,/area/casino/casino_bridge) +"Lc" = (/obj/item/ammo_casing/a556{pixel_x = 5; pixel_y = -2},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"Mb" = (/obj/machinery/shipsensors,/turf/simulated/floor/airless,/area/casino/casino_bridge) +"Mc" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"Nb" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor/border_only,/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"Nc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/carpet,/area/casino/casino_mainfloor) +"Ob" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{icon_state = "4-9"},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"Oc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable,/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"Pb" = (/obj/effect/decal/cleanable/blood/splatter,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{icon_state = "2-8"},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"Pc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plating,/area/casino/casino_crew_atmos) +"Qb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"Qc" = (/obj/effect/decal/cleanable/blood/splatter,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/casino/casino_bow) +"Rb" = (/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"Rc" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/casino/casino_bow) +"Sb" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"Sc" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 10},/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/airless,/area/casino/casino_bow) +"Tb" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/turf/simulated/floor/shuttle/yellow,/area/casino/casino_cutter) +"Tc" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 6},/obj/machinery/light/small{dir = 8},/turf/simulated/floor/airless,/area/casino/casino_bow) +"Ub" = (/obj/machinery/computer/shuttle_control/explore/casino_cutter,/obj/structure/window/basic{icon_state = "window"; dir = 4},/turf/simulated/floor/shuttle/yellow,/area/casino/casino_cutter) +"Vb" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"Wb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"Xb" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plating,/area/casino/casino_maintenance) +"Yb" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled,/area/casino/casino_security) +"Zb" = (/obj/structure/cable,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/turf/simulated/floor/tiled,/area/casino/casino_mainfloor) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacacacacacacacacacacacacacacad +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaeaeaeaeaeaeaeaeaeaeaeaeaeaeaead +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaeaaaaaaaaaaaaaaaaaaaaaaaaaaaead +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaeaaaaadadadadadadadadadadaaaead +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaeaaaaadaaaaaaaaaaaaaaaaadaaaead +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaeaaaaadaaaaaaaaaaaaaaaaadaaaead +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaeaaaaadaaaaaaaaaaaaaaaaadaaaead +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaeaaaaadaaaaafaaaaaaaaaaadaaaead +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabagaaaaadadadahahahadadadadaaaead +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaeaaaaaaaaaaaaaaaaaaaaaaaaaaaead +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaeaeaeaeaeaeaeaeaeaeaeaeaeaeaead +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabajajajajajajajajajajajajajajajad +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalamananananamaoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamgbaqarasapIbamaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaatapapauavapapataaaaaaaaawaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaataxapaypbapaAataaaaaaaaaBaCaDaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaataxaEapayaFKbataaaaaaaaaBaHaIaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaataxaJqbayaLaMataaaaaaaaaBaNaOaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaatapqbrbsbtbapataaaaaaaaaBaTaUaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaVaWubvbwbbaamLbLbaaaaaBbcbdaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamamambebfamamamMbLbaaaaaBbhbiaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBbjbkblbmbnboaBNbaBaBaBaBbhbpaBaBbqbqbqbqbqbqbqbqbqbqbqbqbqbqbrbsaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabtaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBbubkbvbwObPbbzbzbzbAbBbCbzbDbEbFbGxbbIbJbKbLbMbNbObPbQbRbSbqbTbrbsaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBbUbkbVbWbWQbbZcacacacacacacacacacbcccdcccecfbqcgchcicjckclbqcmcnbrbsaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacocococpcpbWcqbZcrcsctcucvcwcvcxcycbccczcAcBcCbqbqbqcDcDcDcEbqcFcFcFbraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbaaaaaaaaaaaaaaaaaaaacocGcHcIcJbzRbbZcLcMcNcNcNcNcNcOcPcbcccQybcScTbqcFcUcVcVcVcWcUcVcVcFcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbcYcYcYbbaaaaaaaaaaaaaaaaaaaacocpcpcZcpbWSbdbzbdddedfdgdfdhdidgcbccdjAbBbdmbqdndodpdpdpdpdpdpdqdrcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbcYdscYbbbbbbbbbbbbbbbbbbbbbbcodtduCbcpbWDbbZdxdxdxdxdxdxdxdxdxdydzdAdBdCdDbqdEdFdGdHdITbdIdJdKdrcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbcYcYaacYcYaaaacYcYaacYcYdLcYcYaacYcYaaaacYcYaacYcYcocpcpcHcpbWcqbZdMdNdOdPdQdRdSdTdTdydUbqbqbqbqbqdndFUbdWdXdYdZeadKdrcXebaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbaaececececececececececeddLedececececececececececaacoeeefcHcpbWegbZeheiejekekekekekeldyembqenenenbqdndodpeodpdpdpdpepdrcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbaaeqererererererererereseteseueueueueueueueueuevaacocpcpcpcpbWcqbZewexekekdRekeyezekdyeAeBeCeDeEbqeFeGeGeHeGeGeGeGeGcFcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbaaeIeIeIeIeIeIeIeIeIeIeddLedeIeIeIeIeIeIeIeIeIeIaaaBeJeKeLeMbWeNbZexeOePeQeReQeSeTeUdyeVbqenenenbqeWeXeXeYeZcFcFfafafbbraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbcYcYcYcYcYcYcYcYcYcYcYcYdLcYcYcYcYcYcYcYcYcYcYcYcYaBfcfdbWbWbWfebZbZbZbZbZbZbZbZbZffaBfgbqbqbqbqbqfhbqbqbrbrbrbrbrbrbrbraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbaaececececececececececcYdLcYececececececececececaaaBfifdbWfjfkVbbzWbbzbzbzbzbzbzbzXbfoYbfqfrEbFbfufvfwbqfxfyfzfzfzfyfzfAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbaaeqererererererererereseteseueueueueueueueueuevaaaBfBbWbWfCbWfDbZfEbZbZbZbZbZbZbZbZaBfFbqbqGbfHbqfIfJbqfKfLfLfLfLfLfLfAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbcYeIeIeIeIeIeIeIeIeIeIcYdLcYfMeIeIeIeIeIeIeIeIeIcYaBfNfOfPcqbWfDfQfRfSfTfUfVfWfXfYfZgaZbgcbqbqbqbqgdbqbqgegfgfgfgfgfgffAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbcYcYaaaaaacYcYaaaaaacYcYdLcYcYcYcYcYcYcYcYcYcYcYcYggggggghcqbVgifQdcgkgkglgmglgkgngjgaocgpgqgrgsgtgegugvgefzfzfzfzfzfzfAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbcYcYaaaaaacYcYaaaaaacYcYgwesesesesesesesesesesesgxgygzgggAcqgBgCfQdcgjgjgDgDgDgjgjgEgapcgGgHgGgIgtgegJgegefLfLfLfLfLfLfAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbcYgKgKgKgKgKgKgKgKgKgKcYdLcYgKgKgKgKgKgKgKgKgKgKcYgggLgggMcqgBgifQqcrcsctcucvcwcxcyczcAcksgXgGgYgtgJgZgegegfgfgfgfgfgffAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbaaeqererererererererereshaeseueueueueueueueueuevbbgghbhcgMcqbWhdfQBcfQfQfQfQfQfQfQfQgahfgtgtgtgthgHbhigehjgegegegegegefAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbaahkhkhkhkhkhkhkhkhkhkcYdLcYhkhkhkhkhkhkhkhkhkhkaagghlhmgMcqgBgChnCchphqhrhshthuhvhwhxgehygegegegehzhAhBgehyfxhChDgehEfAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbcYcYcYcYcYcYcYcYcYcYcYcYdLcYcYcYcYcYcYcYcYcYcYcYaagghFhGgMcqbWhHhnDchJhwhwhKhwhwhwhLhnhMgegehNgegJhOgafKhNgegegegegeEcFcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbaagKgKgKgKgKgKgKgKgKgKeddLedgKgKgKgKgKgKgKgKgKgKaagghPJbgMhRhSbzhTGchwhwhJhVhwhWhwhXhnhYgehZiaibicgeidgeiegehNgeifgegefAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbaaeqerererererererereresigeseueueueueueueueueuevaaggihggggiiijijijikiliminhVhVhWhwiohnhMgeipiqiricgegegeisgehNobhDgeiufAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbaahkhkhkhkhkhkhkhkhkhkcYcYcYhkhkhkhkhkhkhkhkhkhkaaijiviwixHciziAijiBiCiDiEiFhwhwhKiGhnhMgegegegegehNgegegegegegegehNgefAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbaaaaaacYcYaaaacYcYaacYcYcYcYcYaacYcYaaaacYcYaacYcYijiHiIiIiJiKiLijiBiMiNiOiPhwhwhwhwiQgegehZiRiRicgeiSfxgehNgeiTgegegefAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbiUiViWiWiXiYiZijiBhnhnhngagtgagagagajagehZibibichOgajbjcgejdhChDiTIcFcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbjejfjgiVjhjijjijjkjljmjnjojpjqjrjsjtgegegegegegegeidgegegehBgeiTgehNfAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbjujvjwjxjyjzjAjBijjChnjDhwgajEgGjFjGjHjIgehZibjJicgehjgegejKgegegegehNfAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbijjLjMjNjNjOjPijiBhnjQhwgajRgGjSgGjTjIgehZjUibicgegegejVhNhZjWjXichEfAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaijjYjZjNkakbkcijiBhnkdkegakfgGkggGkhkikjgegegegegehAgekkgegeklklgegefAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaijjYjNjNkakmkcijkngagagagakokpkqkrksjIhBhZktiaichOgafKgegegegegegeEcFcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaijkukvjNjNkmiLijkwkxkyhEkzjIjIjIjIjIgegegegegegehjidgegegehZkAkBiciufAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakCkCkCkCkCkCijkDkvjNjNkEkcijJckGkGkHkIkJKcLcMckJkNkJkJMckJkJkJkJkOgegegeklklgegefAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakCkCkCkCkCkCijkPjNjNjNkbkcijkQkRkRkRkRkRkRkRkSkTkTkTkTkUkVkVkVkVNckXkYkZkZlagegefAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakCkClblbkClcijldlelelelfOcijlglhlilhlhljlkkRlllmlnlokTlplqlrlskVltlululululvgegefAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakCkClwlxlylxlzlAlAlBlAlAPcijlDlElFlGlHlIlJkRlKlLlLlMkTlNlOlOlPkVlQlRlSlTlulUhBlVfAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakCkClblbkClWkCkCkCkCkCkClXkClYlZmamblGlImckRmdlLlLmekTmflOlOmgkVmhmilulululUgemjfAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakCkCkCkCkCkCkCmkmlQcmmmnmokCmpmqmrmslIlImtkRmumvlLmwkTmxmylOmzkVmAmBmCmDlulUmEklfAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamFaaaaaaaaaaaaaaaaaaaaaaaakCkCkCkCkCkCkCmGmHmHmImJmKkCkCkCkCkCkCkCkCkCkCkCkCkCkCkCkCkCkCkCkCkCkCkCkCmLkCkCkCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamMkCmNmNmOmPmQmRRcmRmRmRmRmRmRmRmRRcmRmRmRmRmRmRmRmRmRmRmRRcmRmSmHkCmTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamMkCmnmUmVmWmHmHmHmHmHmXmHmHmHmXmHmHmHmXmHmHmHmHmHmUmVmWmNmNmnkCmTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamMkCkCkCmYkCkCkCmZkCkCnakCkCkCnakCkCkCnakCkCmZkCkCkCnbkCkCkCmTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakCncndnekCaaaakCnfnanfkCnfnanfkCnfnanfkCaaaakCncndnekCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakCngnhSckCaaaakCnfnjnfkCnfnjnfkCnfnjnfkCaaaakCTcnhnikCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaankaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakCnlnlnlkCaaaakCnfnmnfkCnfnnnfkCnfnonfkCaaaakCnlnlnlkCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakCnpnqnrkCnpnqnrkCnpnqnrkCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakCnsnsnskCnsnsnskCnsnsnskCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/casino/casino_areas.dm b/maps/away/casino/casino_areas.dm new file mode 100644 index 00000000..c225b959 --- /dev/null +++ b/maps/away/casino/casino_areas.dm @@ -0,0 +1,74 @@ +area/casino + icon = 'maps/away/casino/casino_sprites.dmi' + +area/casino/casino_mainfloor + name = "\improper Casino Hall" + icon_state = "main_area" + +/area/casino/casino_maintenance + name = "\improper Casino Maintenance" + icon_state = "maintenance" + +/area/casino/casino_bow + name = "\improper Casino Ship Bow" + icon_state = "bow" + +/area/casino/casino_crew_bunk + name = "\improper Casino Crew Bunk Room" + icon_state = "crew_bunk" + +/area/casino/casino_crew_atmos + name = "\improper Casino Atmos room" + icon_state = "atmos" + +/area/casino/casino_kitchen + name = "\improper Casino Kitchen" + icon_state = "kitchen" + +/area/casino/casino_crew_cantina + name = "\improper Casino Canteen" + icon_state = "crew_cantina" + +/area/casino/casino_security + name = "\improper Casino Security Wing" + icon_state = "sec" + +/area/casino/casino_hangar + name = "\improper Casino Hangar" + icon_state = "hangar" + +/area/casino/casino_private1 + name = "\improper Casino Private Room 1" + icon_state = "pr1" + +/area/casino/casino_private2 + name = "\improper Casino Private room 1" + icon_state = "pr2" + +/area/casino/casino_private_vip + name = "\improper Casino VIP Private Room" + icon_state = "pr_vip" + +/area/casino/casino_crew_bathroom + name = "\improper Casino Crew Bathroom" + icon_state = "crew_bathroom" + +/area/casino/casino_patron_bathroom + name = "\improper Casino Patrons Bathroom" + icon_state = "patron_bathroom" + +/area/casino/casino_bridge + name = "\improper Casino Bridge" + icon_state = "bridge" + +/area/casino/casino_storage + name = "\improper Casino Storage Room" + icon_state = "storage" + +/area/casino/casino_solar_control + name = "\improper Casino Solar Controls" + icon_state = "solar_control" + +/area/casino/casino_cutter + name = "\improper Casino Cutter" + icon_state = "shuttle" diff --git a/maps/away/casino/casino_sprites.dmi b/maps/away/casino/casino_sprites.dmi new file mode 100644 index 00000000..26c85e38 Binary files /dev/null and b/maps/away/casino/casino_sprites.dmi differ diff --git a/maps/away/derelict/backup/derelict-station.dmm b/maps/away/derelict/backup/derelict-station.dmm new file mode 100644 index 00000000..32cd9f34 --- /dev/null +++ b/maps/away/derelict/backup/derelict-station.dmm @@ -0,0 +1,831 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/turf/simulated/wall/voxshuttle,/area/derelict/ship) +"ac" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/derelict/ship) +"ad" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/derelict/ship) +"ae" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/derelict/ship) +"af" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/derelict/ship) +"ag" = (/turf/simulated/floor/tiled,/area/derelict/ship) +"ah" = (/obj/machinery/sleeper,/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/derelict/ship) +"ai" = (/obj/item/weapon/cell,/turf/simulated/floor/plating,/area/derelict/ship) +"aj" = (/turf/simulated/floor/plating,/area/derelict/ship) +"ak" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/derelict/ship) +"al" = (/obj/structure/shuttle/engine/propulsion{icon_state = "burst_r"; dir = 4},/turf/space,/area/derelict/ship) +"am" = (/obj/item/modular_computer/console/preset/medical,/turf/simulated/floor/tiled,/area/derelict/ship) +"an" = (/obj/random/maintenance,/turf/simulated/floor/tiled,/area/derelict/ship) +"ao" = (/obj/structure/table/standard,/obj/random/firstaid,/turf/simulated/floor/tiled,/area/derelict/ship) +"ap" = (/obj/machinery/door/airlock/glass,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/derelict/ship) +"aq" = (/obj/structure/shuttle/engine/heater{icon_state = "heater"; dir = 4},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/airless,/area/derelict/ship) +"ar" = (/obj/structure/shuttle/engine/propulsion{icon_state = "propulsion"; dir = 4},/turf/space,/area/derelict/ship) +"as" = (/obj/item/weapon/scalpel,/turf/simulated/floor/tiled,/area/derelict/ship) +"at" = (/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor/tiled,/area/derelict/ship) +"au" = (/obj/structure/computerframe{anchored = 1},/turf/simulated/floor/tiled,/area/derelict/ship) +"av" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/derelict/ship) +"aw" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/derelict/ship) +"ax" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/derelict/ship) +"ay" = (/obj/machinery/door/airlock/glass{name = "Hibernation Pods"},/turf/simulated/floor/tiled,/area/derelict/ship) +"az" = (/obj/machinery/light{dir = 8},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/derelict/ship) +"aA" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/tiled,/area/derelict/ship) +"aB" = (/obj/structure/table/standard,/obj/item/weapon/cell,/turf/simulated/floor/tiled,/area/derelict/ship) +"aC" = (/obj/item/device/multitool,/turf/simulated/floor/tiled,/area/derelict/ship) +"aD" = (/obj/item/weapon/cell{charge = 100; maxcharge = 15000},/turf/simulated/floor/tiled,/area/derelict/ship) +"aE" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/derelict/ship) +"aF" = (/obj/machinery/door/airlock/glass,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/derelict/ship) +"aG" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plating,/area/derelict/ship) +"aH" = (/obj/machinery/pipedispenser,/turf/simulated/floor/plating,/area/derelict/ship) +"aI" = (/obj/structure/shuttle/engine/propulsion{icon_state = "burst_l"; dir = 4},/turf/space,/area/derelict/ship) +"aJ" = (/obj/machinery/light{dir = 8},/turf/simulated/floor/tiled,/area/derelict/ship) +"aK" = (/obj/structure/table/standard,/obj/random/maintenance,/turf/simulated/floor/tiled,/area/derelict/ship) +"aL" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/derelict/ship) +"aM" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plating,/area/derelict/ship) +"aN" = (/obj/structure/table/standard,/obj/machinery/light{dir = 4},/turf/simulated/floor/tiled,/area/derelict/ship) +"aO" = (/obj/machinery/door/airlock/glass,/turf/simulated/floor/tiled,/area/derelict/ship) +"aP" = (/obj/machinery/light_switch{pixel_x = 27},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/derelict/ship) +"aQ" = (/obj/machinery/portable_atmospherics/powered/scrubber,/turf/simulated/floor/tiled,/area/derelict/ship) +"aR" = (/obj/structure/lattice,/turf/space,/area/space) +"aS" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plating,/area/derelict/ship) +"aT" = (/obj/structure/bed,/obj/item/weapon/bedsheet,/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/tiled,/area/derelict/ship) +"aU" = (/obj/machinery/light{dir = 4},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/derelict/ship) +"aV" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/tiled,/area/derelict/ship) +"aW" = (/turf/simulated/wall,/area/constructionsite/maintenance) +"aX" = (/obj/structure/table/standard,/obj/random/handgun,/turf/simulated/floor/tiled,/area/derelict/ship) +"aY" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/derelict/ship) +"aZ" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plating,/area/derelict/ship) +"ba" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled,/area/derelict/ship) +"bb" = (/obj/structure/table/standard,/obj/item/weapon/tank/oxygen,/turf/simulated/floor/tiled,/area/derelict/ship) +"bc" = (/obj/machinery/light_switch{pixel_x = 27},/turf/simulated/floor/tiled,/area/derelict/ship) +"bd" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/derelict/ship) +"be" = (/obj/random/loot,/turf/simulated/floor/tiled,/area/derelict/ship) +"bf" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/derelict/ship) +"bg" = (/obj/random/closet,/turf/simulated/floor/tiled,/area/derelict/ship) +"bh" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bi" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bj" = (/obj/structure/table/standard,/obj/item/device/analyzer,/turf/simulated/floor/tiled,/area/derelict/ship) +"bk" = (/obj/structure/bed/chair{dir = 8},/turf/simulated/floor/tiled,/area/derelict/ship) +"bl" = (/obj/machinery/door/airlock/glass,/turf/simulated/floor/shuttle/white,/area/derelict/ship) +"bm" = (/obj/machinery/door/airlock/glass{name = "Living Module"},/turf/simulated/floor/shuttle/white,/area/derelict/ship) +"bn" = (/obj/random/hostile,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bo" = (/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bp" = (/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bq" = (/obj/random/cash,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"br" = (/obj/structure/table/standard,/obj/random/loot,/turf/simulated/floor/tiled,/area/derelict/ship) +"bs" = (/obj/structure/bed,/obj/item/weapon/bedsheet,/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/tiled,/area/derelict/ship) +"bt" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/tiled,/area/derelict/ship) +"bu" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bv" = (/turf/simulated/wall,/area/constructionsite/bridge) +"bw" = (/obj/structure/grille,/obj/machinery/door/blast/regular/open,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bx" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"by" = (/obj/effect/wingrille_spawn/reinforced,/obj/machinery/door/blast/regular/open,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"bz" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bA" = (/obj/random/material,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bB" = (/obj/structure/table/standard,/obj/item/modular_computer/laptop,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"bC" = (/obj/structure/table/standard,/obj/random/drinkbottle,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bD" = (/obj/structure/table/standard,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bE" = (/obj/structure/table,/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bF" = (/turf/space,/area/constructionsite/maintenance) +"bG" = (/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bH" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/maintenance) +"bI" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plating,/area/derelict/ship) +"bJ" = (/obj/machinery/light_switch{pixel_x = 27},/obj/machinery/light{dir = 4},/turf/simulated/floor/tiled,/area/derelict/ship) +"bK" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"bL" = (/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bM" = (/obj/random/trash,/obj/structure/table,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"bN" = (/obj/random/closet,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bO" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bP" = (/obj/structure/table/standard,/obj/item/weapon/paper{info = "\\\[center]\\\[b]ATTN: Regarding Meteor Storms\\\[/b]\[/center]\\\[br]\\\[br]We've recently heard mutterings from the Atmospheric Technicians that the meteor showers in this sector are becoming too much. However, this should be disregarded.\\\[br]\\\[br] High Command has assured us that our shields can easily keep pace with any meteor storm and then some. Any uneasiness the crew may feel should be disspelled swiftly. Thank you."; name = "ATTN: Regarding Meteor Storms"},/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bQ" = (/obj/structure/table,/obj/random/material,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bR" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/bridge) +"bS" = (/obj/random/hostile{spawn_nothing_percentage = 60},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"bT" = (/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/derelict/ship) +"bU" = (/obj/structure/table/rack,/obj/item/weapon/tank/emergency/oxygen,/obj/item/weapon/tank/emergency/oxygen,/obj/item/weapon/tank/emergency/oxygen,/obj/item/weapon/tank/emergency/oxygen,/obj/random/tank,/turf/simulated/floor/tiled,/area/derelict/ship) +"bV" = (/obj/structure/table/rack,/obj/item/clothing/mask/breath,/obj/item/weapon/cell,/obj/random/hardsuit,/turf/simulated/floor/tiled,/area/derelict/ship) +"bW" = (/obj/structure/table/rack,/obj/item/weapon/storage/toolbox/syndicate,/obj/random/maintenance,/turf/simulated/floor/tiled,/area/derelict/ship) +"bX" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/power/apc/high/inactive{dir = 8; name = "west bump"; pixel_x = -24},/turf/simulated/floor/plating,/area/derelict/ship) +"bY" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/plating,/area/derelict/ship) +"bZ" = (/obj/item/weapon/cell{charge = 100; maxcharge = 15000},/turf/simulated/floor/plating,/area/derelict/ship) +"ca" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/derelict/ship) +"cb" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating,/area/derelict/ship) +"cc" = (/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/power/solar_control,/turf/simulated/floor/plating,/area/derelict/ship) +"cd" = (/obj/structure/girder,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"ce" = (/obj/machinery/door/airlock/maintenance_hatch,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"cf" = (/obj/random/handgun,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"cg" = (/obj/item/stack/cable_coil,/turf/simulated/floor/plating,/area/derelict/ship) +"ch" = (/obj/structure/cable/yellow,/obj/machinery/power/terminal,/turf/simulated/floor/plating,/area/derelict/ship) +"ci" = (/obj/machinery/door/airlock/maintenance_hatch,/obj/machinery/door/blast/regular/open,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"cj" = (/obj/random/hostile{spawn_nothing_percentage = 60},/turf/simulated/floor/airless,/area/constructionsite/bridge) +"ck" = (/obj/random/junk,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"cl" = (/obj/machinery/door/airlock/maintenance_hatch,/obj/machinery/door/blast/regular,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"cm" = (/obj/random/closet,/obj/random/maintenance,/obj/random/maintenance,/obj/random/material,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"cn" = (/turf/simulated/wall/voxshuttle,/area/space) +"co" = (/obj/machinery/door/airlock/glass{name = "Pod Bay"},/turf/simulated/floor/tiled,/area/derelict/ship) +"cp" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/derelict/ship) +"cq" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/plating,/area/derelict/ship) +"cr" = (/obj/machinery/power/smes/batteryrack,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/derelict/ship) +"cs" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"ct" = (/obj/random/trash,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"cu" = (/obj/random/closet,/obj/random/energy,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"cv" = (/obj/structure/bookcase/manuals/engineering,/obj/effect/decal/cleanable/cobweb,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cw" = (/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cx" = (/obj/structure/bookcase,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"cy" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"cz" = (/obj/structure/bookcase/manuals/xenoarchaeology,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cA" = (/obj/structure/bookcase,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cB" = (/obj/structure/girder,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"cC" = (/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"cD" = (/obj/structure/table/marble,/obj/random/coin,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cE" = (/obj/structure/table/marble,/obj/machinery/microwave,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cF" = (/obj/structure/table/marble,/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cG" = (/turf/simulated/floor/tiled/white/airless,/area/constructionsite/hallway/fore) +"cH" = (/obj/structure/table,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cI" = (/obj/structure/table,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/hallway/fore) +"cJ" = (/obj/structure/table/standard,/obj/item/weapon/screwdriver,/obj/machinery/light,/obj/random/maintenance,/turf/simulated/floor/tiled,/area/derelict/ship) +"cK" = (/obj/structure/table/standard,/obj/item/device/radio/off,/turf/simulated/floor/tiled,/area/derelict/ship) +"cL" = (/obj/machinery/autolathe,/turf/simulated/floor/plating,/area/derelict/ship) +"cM" = (/obj/structure/bookcase,/obj/item/weapon/book/manual/excavation,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cN" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"cO" = (/obj/structure/bookcase/manuals/xenoarchaeology,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"cP" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cQ" = (/obj/structure/bookcase,/obj/item/weapon/book/manual/ripley_build_and_repair,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cR" = (/obj/structure/noticeboard{pixel_x = 32},/turf/simulated/floor/airless,/area/constructionsite/bridge) +"cS" = (/obj/effect/decal/cleanable/cobweb,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cT" = (/obj/structure/window/reinforced,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/tracker,/turf/simulated/floor/plating,/area/derelict/ship) +"cU" = (/obj/structure/window/reinforced,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/derelict/ship) +"cV" = (/obj/structure/window/reinforced,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/cable/yellow,/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/derelict/ship) +"cW" = (/obj/structure/window/reinforced,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/derelict/ship) +"cX" = (/obj/machinery/bookbinder,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"cY" = (/obj/structure/filingcabinet/filingcabinet,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cZ" = (/obj/machinery/door/airlock/glass_command{name = "Bridge"; req_access = list(19)},/obj/machinery/door/blast/regular,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"da" = (/obj/structure/closet/secure_closet/freezer/fridge{icon_state = "fridgebroken"; locked = 0},/obj/random/contraband,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"db" = (/obj/structure/table/marble,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dc" = (/obj/structure/table/marble,/obj/item/weapon/material/kitchen/rollingpin,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dd" = (/obj/structure/table,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"de" = (/obj/random/closet,/obj/random/voidhelmet,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"df" = (/obj/structure/table/rack,/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dg" = (/obj/structure/bookcase/manuals/medical,/obj/item/weapon/book/manual/nuclear,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"dh" = (/obj/random/trash,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"di" = (/obj/structure/table/rack,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dj" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dk" = (/obj/structure/table/marble,/obj/random/drinkbottle,/obj/random/drinkbottle,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dl" = (/obj/structure/table/marble,/obj/random/gloves,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dm" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dn" = (/obj/structure/table/marble,/obj/random/drinkbottle,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"do" = (/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dp" = (/obj/structure/table/rack,/obj/random/tool,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dq" = (/obj/structure/table/rack,/obj/random/hat,/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dr" = (/obj/random/junk,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/hallway/fore) +"ds" = (/obj/structure/table/standard,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"dt" = (/obj/structure/table/standard,/obj/random/toy,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"du" = (/obj/structure/table/standard,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dv" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dw" = (/turf/simulated/floor/holofloor/tiled/dark,/area/constructionsite/hallway/fore) +"dx" = (/obj/random/junk,/obj/structure/table,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dy" = (/obj/random/snack,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dz" = (/turf/simulated/wall,/area/constructionsite/hallway/fore) +"dA" = (/obj/machinery/door/airlock/maintenance_hatch,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dB" = (/obj/machinery/door/airlock/glass{name = "Library"},/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dC" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"dD" = (/obj/structure/grille/broken,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"dE" = (/obj/structure/grille,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"dF" = (/obj/structure/sign/warning/secure_area,/turf/simulated/wall,/area/constructionsite/hallway/fore) +"dG" = (/obj/machinery/door/airlock/glass_command{name = "Bridge"; req_access = list(19)},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"dH" = (/obj/machinery/door/airlock/glass_command{name = "Bridge"; req_access = list(19)},/turf/simulated/floor/holofloor/tiled/dark,/area/constructionsite/hallway/fore) +"dI" = (/obj/machinery/door/airlock/glass{name = "Kitchen"; req_access = list(28)},/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dJ" = (/obj/structure/table/marble,/obj/machinery/door/blast/shutters,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"dK" = (/obj/structure/table/marble,/obj/machinery/door/blast/shutters/open,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dL" = (/obj/structure/table,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"dM" = (/obj/structure/table,/obj/machinery/door/blast/shutters/open,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dN" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dO" = (/turf/simulated/wall,/area/space) +"dP" = (/obj/structure/grille/broken,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dQ" = (/obj/random/smokes,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"dR" = (/obj/structure/lattice,/turf/space,/area/constructionsite/hallway/fore) +"dS" = (/obj/random/snack,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"dT" = (/obj/random/trash,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"dU" = (/obj/structure/grille/broken,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"dV" = (/obj/structure/lattice,/obj/random/junk,/turf/space,/area/space) +"dW" = (/obj/structure/table/rack,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dX" = (/obj/effect/shuttle_landmark/derelict/nav2,/turf/space,/area/space) +"dY" = (/turf/simulated/wall,/area/constructionsite/storage) +"dZ" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless,/area/constructionsite/storage) +"ea" = (/obj/structure/extinguisher_cabinet{icon_state = "extinguisher_empty"; pixel_x = 30},/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"eb" = (/turf/simulated/wall,/area/constructionsite/teleporter) +"ec" = (/obj/machinery/mech_recharger,/obj/effect/decal/mecha_wreckage/mauler,/turf/simulated/floor/airless,/area/constructionsite/storage) +"ed" = (/obj/machinery/mecha_part_fabricator,/turf/simulated/floor/airless,/area/constructionsite/storage) +"ee" = (/obj/structure/table/standard,/turf/simulated/floor/airless,/area/constructionsite/storage) +"ef" = (/obj/structure/table/standard,/obj/random/material,/obj/random/material,/obj/random/coin,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eg" = (/obj/structure/table,/obj/machinery/cell_charger,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/storage) +"eh" = (/turf/simulated/floor/airless,/area/constructionsite/storage) +"ei" = (/obj/structure/table,/obj/random/medical,/turf/simulated/floor/airless,/area/constructionsite/storage) +"ej" = (/obj/machinery/shieldgen,/obj/structure/window/basic{icon_state = "window"; dir = 8},/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"ek" = (/obj/machinery/shieldgen,/obj/structure/window/basic{icon_state = "window"; dir = 4},/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"el" = (/obj/machinery/portable_atmospherics/canister/air,/obj/structure/window/basic{icon_state = "window"; dir = 8},/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"em" = (/obj/machinery/portable_atmospherics/canister/air,/obj/structure/window/basic{icon_state = "window"; dir = 4},/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"en" = (/obj/structure/table/reinforced,/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/item/stack/material/steel{amount = 50; pixel_x = 0; pixel_y = 0},/obj/item/stack/material/steel{amount = 50; pixel_x = 0; pixel_y = 0},/obj/item/stack/material/steel{amount = 50; pixel_x = 0; pixel_y = 0},/obj/item/stack/material/steel{amount = 50; pixel_x = 0; pixel_y = 0},/obj/item/stack/material/steel{amount = 50; pixel_x = 0; pixel_y = 0},/obj/random/tech_supply,/obj/random/maintenance,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"ep" = (/obj/structure/table/reinforced,/obj/item/stack/material/plasteel{amount = 50},/obj/random/tech_supply,/obj/random/maintenance,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eq" = (/obj/structure/table/reinforced,/obj/random/powercell,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/maintenance,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"er" = (/obj/structure/table/rack,/obj/random/maintenance,/obj/random/toolbox,/turf/simulated/floor/airless,/area/constructionsite/storage) +"es" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/storage) +"et" = (/obj/structure/bed/chair/office/light{dir = 1},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/storage) +"eu" = (/obj/machinery/optable{name = "Robotics Operating Table"},/turf/simulated/floor/airless,/area/constructionsite/storage) +"ev" = (/obj/random/closet,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"ew" = (/obj/machinery/shieldgen,/obj/structure/window/basic{icon_state = "window"; dir = 8},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"ex" = (/obj/machinery/shieldgen,/obj/structure/window/basic{icon_state = "window"; dir = 4},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"ey" = (/obj/machinery/portable_atmospherics/canister/air,/obj/structure/window/basic{icon_state = "window"; dir = 8},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"ez" = (/obj/machinery/portable_atmospherics/canister/air,/obj/structure/window/basic{icon_state = "window"; dir = 4},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eA" = (/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eB" = (/obj/structure/table/reinforced,/obj/item/clothing/shoes/magboots,/obj/item/clothing/glasses/meson,/obj/item/weapon/tank/oxygen,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/voidsuit,/obj/random/voidhelmet,/obj/random/maintenance,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eC" = (/obj/structure/table/reinforced,/obj/item/stack/material/phoron{amount = 10},/obj/random/powercell,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/maintenance,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eD" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eE" = (/obj/machinery/door/airlock/glass_science{name = "Robotics"},/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/storage) +"eF" = (/obj/structure/grille/broken,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eG" = (/obj/structure/sign/warning/science,/turf/simulated/wall,/area/constructionsite/hallway/fore) +"eH" = (/obj/machinery/access_button/airlock_exterior{master_tag = "constructionsite_airlock"; pixel_x = 20; pixel_y = 0; req_access = list(10)},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"eI" = (/obj/structure/sign/warning/vacuum{pixel_x = -32},/obj/machinery/access_button/airlock_interior{master_tag = "constructionsite_airlock"; pixel_x = -20; pixel_y = 0; req_access = list(10)},/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 1},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eJ" = (/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"eK" = (/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/obj/machinery/power/port_gen/pacman,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eL" = (/obj/structure/skele_stand,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eM" = (/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eN" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eO" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/storage) +"eP" = (/obj/machinery/door/airlock/glass_science{name = "Research"},/obj/machinery/door/blast/shutters,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eQ" = (/obj/machinery/door/airlock/glass_science{name = "Research"},/obj/machinery/door/blast/shutters,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"eR" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "constructionsite_outer"; locked = 1; req_access = list(10)},/turf/simulated/floor,/area/constructionsite/teleporter) +"eS" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{frequency = 1379; id_tag = "constructionsite_vent"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor,/area/constructionsite/teleporter) +"eU" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "constructionsite_inner"; locked = 1; req_access = list(10)},/turf/simulated/floor,/area/constructionsite/teleporter) +"eV" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"eW" = (/obj/structure/cable/blue,/obj/machinery/power/port_gen/pacman,/obj/machinery/power/terminal,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eX" = (/obj/machinery/door/airlock/maintenance_hatch,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eY" = (/obj/random/hostile,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eZ" = (/obj/machinery/door/airlock/glass_science{name = "Research"},/obj/machinery/door/blast/shutters/open,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"fa" = (/obj/machinery/atmospherics/pipe/simple/hidden/blue{icon_state = "intact"; dir = 5},/obj/machinery/light/small,/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1379; id_tag = "constructionsite_airlock"; pixel_x = 0; pixel_y = -25; req_access = list(10); tag_airpump = "constructionsite_vent"; tag_chamber_sensor = "constructionsite_sensor"; tag_exterior_door = "constructionsite_outer"; tag_interior_door = "constructionsite_inner"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor,/area/constructionsite/teleporter) +"fb" = (/obj/machinery/atmospherics/pipe/manifold/hidden/blue,/obj/machinery/airlock_sensor{frequency = 1379; id_tag = "constructionsite_sensor"; pixel_x = 0; pixel_y = -25},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 6},/turf/simulated/floor,/area/constructionsite/teleporter) +"fc" = (/obj/machinery/atmospherics/pipe/simple/hidden/blue{icon_state = "intact"; dir = 4},/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "constructionsite_inner"; locked = 1; req_access = list(10)},/turf/simulated/floor,/area/constructionsite/teleporter) +"fd" = (/obj/machinery/atmospherics/pipe/simple/hidden/blue{icon_state = "intact"; dir = 4},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"fe" = (/obj/machinery/atmospherics/pipe/simple/hidden/blue{icon_state = "intact"; dir = 10},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"ff" = (/obj/structure/cable/blue{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"fg" = (/obj/structure/cable/blue{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"fh" = (/obj/machinery/power/smes/batteryrack{should_be_mapped = 1},/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fi" = (/obj/effect/shuttle_landmark/derelict/nav1,/turf/space,/area/space) +"fj" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite/storage) +"fk" = (/obj/structure/grille/broken,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/storage) +"fl" = (/obj/machinery/door/airlock/glass_science{name = "Research"},/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/storage) +"fm" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/storage) +"fn" = (/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/machinery/portable_atmospherics/canister/air/airlock,/obj/machinery/atmospherics/portables_connector{icon_state = "map_connector"; dir = 4},/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 4},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fo" = (/obj/machinery/atmospherics/pipe/manifold/hidden/blue{icon_state = "map"; dir = 4},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"fp" = (/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"fq" = (/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"fr" = (/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fs" = (/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/blue{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/autolathe,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"ft" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/storage) +"fu" = (/obj/structure/window/basic,/obj/machinery/portable_atmospherics/canister/air/airlock,/obj/machinery/atmospherics/portables_connector{icon_state = "map_connector"; dir = 4},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fv" = (/obj/machinery/atmospherics/pipe/simple/hidden/blue{icon_state = "intact"; dir = 9},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fw" = (/obj/structure/cable/blue,/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/power/apc/high/inactive{dir = 2; name = "south bump"; pixel_y = -24},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fx" = (/obj/machinery/portable_atmospherics/canister/nitrogen/prechilled,/turf/simulated/floor/airless,/area/constructionsite/storage) +"fy" = (/obj/machinery/r_n_d/circuit_imprinter,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/storage) +"fz" = (/obj/machinery/r_n_d/destructive_analyzer,/turf/simulated/floor/airless,/area/constructionsite/storage) +"fA" = (/obj/machinery/r_n_d/protolathe{icon_state = "protolathe_t"; stat = 1},/turf/simulated/floor/airless,/area/constructionsite/storage) +"fB" = (/obj/machinery/r_n_d/server/centcom,/turf/simulated/floor/airless,/area/constructionsite/storage) +"fC" = (/obj/machinery/pipedispenser,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fD" = (/obj/machinery/pipedispenser/disposal,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fE" = (/obj/structure/reagent_dispensers/watertank,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fF" = (/obj/structure/reagent_dispensers/fueltank,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fG" = (/obj/machinery/light,/obj/structure/closet/crate/solar,/obj/effect/floor_decal/industrial/outline/yellow,/obj/random/loot,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fH" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/obj/structure/computerframe,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fI" = (/obj/machinery/teleport/station,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fJ" = (/obj/machinery/teleport/hub,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fK" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"fL" = (/turf/simulated/wall,/area/constructionsite/solar) +"fM" = (/obj/random/closet,/obj/random/material,/obj/random/contraband,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"fN" = (/turf/simulated/floor/airless,/area/constructionsite/solar) +"fO" = (/obj/structure/lattice,/turf/space,/area/constructionsite/solar) +"fP" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/solar) +"fQ" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/maintenance) +"fR" = (/obj/structure/extinguisher_cabinet{pixel_y = 30},/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"fS" = (/obj/random/junk,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"fT" = (/obj/effect/overmap/sector/derelict,/turf/simulated/floor/airless,/area/constructionsite/solar) +"fU" = (/turf/space,/area/constructionsite/solar) +"fV" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/solar) +"fW" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/solar) +"fX" = (/obj/structure/grille,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"fY" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite/solar) +"fZ" = (/obj/structure/grille/broken,/turf/simulated/floor/airless,/area/constructionsite/solar) +"ga" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"gb" = (/obj/effect/shuttle_landmark/derelict/nav3,/turf/space,/area/space) +"gc" = (/obj/random/firstaid,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"gd" = (/obj/structure/lattice,/obj/random/maintenance,/turf/space,/area/constructionsite/solar) +"ge" = (/obj/structure/table/rack,/obj/random/plushie,/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"gf" = (/obj/machinery/door/airlock/highsecurity{icon_state = "door_closed"; locked = 0; name = "AI Upload Access"; req_access = list(16)},/turf/simulated/floor/bluegrid/airless,/area/constructionsite/hallway/fore) +"gg" = (/turf/simulated/wall,/area/constructionsite/ai) +"gh" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gi" = (/turf/simulated/floor/bluegrid/airless,/area/constructionsite/ai) +"gj" = (/turf/simulated/floor/airless,/area/space) +"gk" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/space) +"gl" = (/obj/random/trash,/turf/simulated/floor/airless,/area/space) +"gm" = (/obj/structure/sign/warning/lethal_turrets,/turf/simulated/wall,/area/constructionsite/ai) +"gn" = (/obj/machinery/door/airlock/highsecurity{icon_state = "door_closed"; locked = 0; name = "AI Upload"; req_access = list(16)},/turf/simulated/floor/bluegrid/airless,/area/constructionsite/ai) +"go" = (/obj/random/tool,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"gp" = (/obj/machinery/porta_turret_construct,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gq" = (/obj/effect/decal/cleanable/blood/oil,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gr" = (/turf/simulated/floor/tiled/dark/airless,/area/space) +"gs" = (/obj/structure/table/rack,/obj/random/maintenance,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"gt" = (/obj/structure/table/rack,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"gu" = (/obj/random/loot,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gv" = (/obj/random/trash,/turf/simulated/floor/bluegrid/airless,/area/constructionsite/ai) +"gw" = (/obj/machinery/drone_fabricator/derelict,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gx" = (/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/obj/machinery/power/apc/high/inactive{dir = 1; name = "north bump"; pixel_y = 24},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gy" = (/obj/machinery/computer/drone_control,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gz" = (/obj/random/hostile,/turf/simulated/floor/airless,/area/space) +"gA" = (/obj/structure/lattice,/turf/space,/area/constructionsite/maintenance) +"gB" = (/obj/machinery/door/airlock/highsecurity{name = "Messaging Server"; req_access = list(30)},/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"gC" = (/obj/machinery/door/airlock/highsecurity{name = "Messaging Server"; req_access = list(30)},/turf/simulated/floor/airless,/area/constructionsite/ai) +"gD" = (/obj/structure/showcase{desc = "A computer core for an artificial intelligence. It seems to be broken."; icon = 'icons/mob/AI.dmi'; icon_state = "4"; name = "Deactivated AI Core"},/turf/simulated/floor/bluegrid/airless,/area/constructionsite/ai) +"gE" = (/obj/machinery/door/airlock/highsecurity{name = "Cyborg Station"; req_access = list(16)},/turf/simulated/floor/bluegrid/airless,/area/constructionsite/ai) +"gF" = (/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/bluegrid/airless,/area/constructionsite/ai) +"gG" = (/obj/effect/decal/cleanable/blood/oil,/turf/simulated/floor/bluegrid/airless,/area/constructionsite/ai) +"gH" = (/obj/machinery/door/airlock/highsecurity{name = "Cyborg Station"; req_access = list(16)},/turf/simulated/floor/bluegrid/airless,/area/constructionsite/hallway/fore) +"gI" = (/obj/random/tool,/turf/simulated/floor/airless,/area/space) +"gJ" = (/obj/random/material,/turf/simulated/floor/airless,/area/space) +"gK" = (/obj/machinery/recharge_station,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gL" = (/obj/structure/lattice,/obj/structure/extinguisher_cabinet{icon_state = "extinguisher_empty"; pixel_x = -30},/turf/space,/area/constructionsite/hallway/fore) +"gM" = (/obj/machinery/porta_turret/stationary,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gN" = (/obj/random/junk,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gO" = (/turf/simulated/wall,/area/constructionsite/hallway/aft) +"gP" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/aft) +"gQ" = (/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"gR" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/aft) +"gS" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"gT" = (/obj/structure/lattice,/turf/space,/area/constructionsite/hallway/aft) +"gU" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"gV" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"gW" = (/obj/structure/grille/broken,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"gX" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"gY" = (/obj/machinery/door/airlock/maintenance_hatch,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"gZ" = (/obj/machinery/door/airlock/highsecurity{icon_state = "door_closed"; locked = 0; name = "AI Upload Access"; req_access = list(16)},/turf/simulated/floor/bluegrid/airless,/area/constructionsite/hallway/aft) +"ha" = (/obj/structure/table/rack,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"hb" = (/obj/effect/floor_decal/plaque{desc = "To commemorate the beginning of the Eternity Project, a station that will ferry us through the stars forever without fail."; name = "Eternity Project Dedication Plaque"},/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"hc" = (/obj/structure/lattice,/obj/random/material,/turf/space,/area/space) +"hd" = (/obj/structure/closet/firecloset{icon_state = "fireclosetopen"; opened = 1},/obj/random/plushie/large,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"he" = (/obj/random/trash,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/aft) +"hf" = (/obj/machinery/door/airlock/multi_tile/glass{name = "Emergency Entrance"},/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"hg" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/aft) +"hh" = (/obj/structure/grille/broken,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/aft) +"hi" = (/obj/effect/shuttle_landmark/derelict/nav4,/turf/space,/area/space) +"hj" = (/obj/structure/door_assembly,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"hk" = (/obj/effect/decal/mecha_wreckage/odysseus,/obj/machinery/mech_recharger,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hl" = (/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hm" = (/obj/structure/table/standard,/obj/random/firstaid,/obj/random/firstaid,/obj/effect/floor_decal/corner/green{dir = 4},/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hn" = (/turf/simulated/wall,/area/constructionsite/medical) +"ho" = (/obj/machinery/sleeper,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hp" = (/obj/structure/iv_drip,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hq" = (/obj/random/trash,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hr" = (/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"hs" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/atmospherics) +"ht" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/atmospherics) +"hu" = (/obj/machinery/light_construct{dir = 1},/turf/simulated/floor/airless,/area/constructionsite/medical) +"hv" = (/turf/simulated/floor/airless,/area/constructionsite/medical) +"hw" = (/obj/structure/table/standard,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hx" = (/obj/random/junk,/obj/effect/floor_decal/corner/green{dir = 9},/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hy" = (/obj/effect/floor_decal/corner/green,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hz" = (/obj/item/weapon/reagent_containers/ivbag,/obj/item/weapon/reagent_containers/ivbag,/obj/item/weapon/reagent_containers/ivbag/blood/OMinus,/obj/structure/closet/medical_wall{name = "Blood Closet"},/turf/simulated/wall,/area/constructionsite/hallway/aft) +"hA" = (/obj/structure/girder,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"hB" = (/obj/structure/table,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hC" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hD" = (/obj/machinery/door/airlock/glass_medical{name = "Medbay"; req_one_access = list(65,5)},/turf/simulated/floor/airless,/area/constructionsite/medical) +"hE" = (/obj/structure/door_assembly/door_assembly_med{name = "Medbay"},/turf/simulated/floor/airless,/area/constructionsite/medical) +"hF" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"hG" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"hH" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hI" = (/obj/structure/table/standard,/obj/random/firstaid,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hJ" = (/obj/structure/sign/directions/examroom,/turf/simulated/wall,/area/constructionsite/medical) +"hK" = (/obj/effect/floor_decal/corner/green{dir = 9},/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hL" = (/obj/machinery/disposal,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hM" = (/obj/structure/table,/obj/random/medical,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hN" = (/obj/structure/table,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hO" = (/obj/structure/fireaxecabinet{pixel_x = 32},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"hP" = (/turf/simulated/wall,/area/constructionsite/atmospherics) +"hQ" = (/obj/structure/girder,/turf/space,/area/constructionsite/hallway/aft) +"hR" = (/obj/item/roller,/obj/item/roller,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hS" = (/obj/structure/closet/medical_wall/filled{pixel_x = 32},/turf/simulated/floor/airless,/area/constructionsite/medical) +"hT" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"hU" = (/obj/structure/closet/firecloset/full,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"hV" = (/obj/machinery/atmospherics/pipe/simple/visible,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/atmospherics) +"hW" = (/obj/structure/lattice,/turf/space,/area/constructionsite/medical) +"hX" = (/obj/random/medical/lite,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hY" = (/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hZ" = (/obj/item/roller,/turf/simulated/floor/airless,/area/constructionsite/medical) +"ia" = (/obj/random/closet,/turf/simulated/floor/airless,/area/constructionsite/medical) +"ib" = (/turf/space,/area/constructionsite/medical) +"ic" = (/obj/effect/decal/mecha_wreckage/ripley/firefighter,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"id" = (/obj/structure/closet/secure_closet/atmos_personal{icon_state = "secureatmbroken"; locked = 0},/obj/random/voidsuit,/obj/random/voidhelmet,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"ie" = (/obj/machinery/atmospherics/pipe/simple/visible,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"if" = (/obj/structure/iv_drip,/turf/simulated/floor/airless,/area/constructionsite/medical) +"ig" = (/obj/random/snack,/turf/simulated/floor/airless,/area/constructionsite/medical) +"ih" = (/obj/structure/lattice,/obj/random/junk,/turf/space,/area/constructionsite/medical) +"ii" = (/obj/machinery/door/airlock/glass_medical{name = "Medbay Storage"; req_one_access = list(65,5)},/turf/simulated/wall,/area/constructionsite/hallway/aft) +"ij" = (/obj/machinery/door/airlock/glass_atmos{name = "Atmospherics"; req_access = list(24)},/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"ik" = (/obj/random/firstaid,/turf/simulated/floor/airless,/area/constructionsite/medical) +"il" = (/obj/item/weapon/storage/box/freezer,/turf/simulated/floor/airless,/area/constructionsite/medical) +"im" = (/obj/random/closet,/obj/random/masks,/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"in" = (/obj/random/tool,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/atmospherics) +"io" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/medical) +"ip" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/airless,/area/constructionsite/medical) +"iq" = (/obj/random/ammo,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"ir" = (/obj/structure/lattice,/obj/random/medical/lite,/turf/space,/area/constructionsite/medical) +"is" = (/obj/structure/girder/reinforced,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"it" = (/obj/effect/shuttle_landmark/derelict/nav5,/turf/space,/area/space) +"iu" = (/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"iv" = (/turf/space,/area/constructionsite/hallway/aft) +"iw" = (/obj/structure/lattice,/obj/item/roller,/turf/space,/area/constructionsite/medical) +"ix" = (/obj/structure/closet/firecloset{icon_state = "fireclosetopen"; opened = 1},/obj/random/junk,/obj/random/masks,/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"iy" = (/obj/machinery/computer/general_air_control/large_tank_control{frequency = 1443; input_tag = "d_air_in"; name = "Mixed Air Supply Control"; output_tag = "d_air_out"; pressure_setting = 2000; sensors = list("d_air_sensor" = "Tank")},/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"iz" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/machinery/door/firedoor/border_only,/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor/plating,/area/constructionsite/atmospherics) +"iA" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; external_pressure_bound = 0; external_pressure_bound_default = 0; frequency = 1443; icon_state = "map_vent_in"; id_tag = "d_air_out"; internal_pressure_bound = 2000; internal_pressure_bound_default = 2000; use_power = 1; pressure_checks = 2; pressure_checks_default = 2; pump_direction = 0},/turf/simulated/floor/reinforced/airmix,/area/constructionsite/atmospherics) +"iB" = (/obj/machinery/light/small{dir = 1},/obj/machinery/air_sensor{frequency = 1443; id_tag = "d_air_sensor"; output = 7},/turf/simulated/floor/reinforced/airmix,/area/constructionsite/atmospherics) +"iC" = (/obj/structure/girder/reinforced,/turf/space,/area/constructionsite/medical) +"iD" = (/obj/structure/lattice,/obj/structure/sign/warning/nosmoking_1,/turf/simulated/wall,/area/constructionsite/medical) +"iE" = (/obj/structure/sign/bluecross_2,/turf/simulated/wall,/area/constructionsite/hallway/aft) +"iF" = (/obj/structure/sign/warning/compressed_gas,/turf/simulated/wall,/area/constructionsite/hallway/aft) +"iG" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4; icon_state = "intact"},/turf/simulated/wall,/area/constructionsite/atmospherics) +"iH" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 8; frequency = 1443; icon_state = "map_injector"; id = "d_air_in"; use_power = 1},/turf/simulated/floor/reinforced/airmix,/area/constructionsite/atmospherics) +"iI" = (/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor/reinforced/airmix,/area/constructionsite/atmospherics) +"iJ" = (/obj/machinery/door/airlock/glass_medical{name = "Medbay"; req_one_access = list(65,5)},/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"iK" = (/obj/effect/floor_decal/industrial/warning/dust{icon_state = "warning_dust"; dir = 8},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/atmospherics) +"iL" = (/obj/structure/girder,/turf/simulated/floor/airless,/area/constructionsite/medical) +"iM" = (/obj/effect/floor_decal/plaque{desc = "In memory of Earl Whitenmeinster. We'll never forget you."; icon_state = "plaque"; name = "Whitenmeister Memorial Hall Plaque"},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/aft) +"iN" = (/obj/effect/floor_decal/industrial/warning/dust{icon_state = "warning_dust"; dir = 8},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"iO" = (/obj/machinery/computer/general_air_control/large_tank_control{frequency = 1441; input_tag = "d_o2_in"; name = "Oxygen Supply Control"; output_tag = "d_o2_out"; sensors = list("d_o2_sensor" = "Tank")},/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"iP" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 8; external_pressure_bound = 0; external_pressure_bound_default = 0; frequency = 1441; icon_state = "map_vent_in"; id_tag = "d_o2_out"; initialize_directions = 1; internal_pressure_bound = 4000; internal_pressure_bound_default = 4000; use_power = 1; pressure_checks = 2; pressure_checks_default = 2; pump_direction = 0},/turf/simulated/floor/reinforced/oxygen,/area/constructionsite/atmospherics) +"iQ" = (/obj/machinery/light/small{dir = 1},/obj/machinery/air_sensor{frequency = 1441; id_tag = "d_o2_sensor"},/turf/simulated/floor/reinforced/oxygen,/area/constructionsite/atmospherics) +"iR" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/medical) +"iS" = (/obj/random/material,/turf/simulated/floor/airless,/area/constructionsite/medical) +"iT" = (/obj/effect/floor_decal/corner/green{dir = 10},/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"iU" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 8; frequency = 1441; icon_state = "map_injector"; id = "d_o2_in"; use_power = 1},/turf/simulated/floor/reinforced/oxygen,/area/constructionsite/atmospherics) +"iV" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/reinforced/oxygen,/area/constructionsite/atmospherics) +"iW" = (/obj/structure/lattice,/obj/structure/girder,/turf/space,/area/constructionsite/medical) +"iX" = (/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/atmospherics) +"iY" = (/turf/simulated/wall,/area/constructionsite) +"iZ" = (/obj/structure/grille/broken,/turf/simulated/floor/airless,/area/constructionsite) +"ja" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite) +"jb" = (/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"jc" = (/obj/machinery/computer/general_air_control/large_tank_control{frequency = 1441; input_tag = "d_n2_in"; name = "Nitrogen Supply Control"; output_tag = "d_n2_out"; sensors = list("d_n2_sensor" = "Tank")},/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"jd" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 8; external_pressure_bound = 0; external_pressure_bound_default = 0; frequency = 1441; icon_state = "map_vent_in"; id_tag = "d_n2_out"; initialize_directions = 1; internal_pressure_bound = 4000; internal_pressure_bound_default = 4000; use_power = 1; pressure_checks = 2; pressure_checks_default = 2; pump_direction = 0},/turf/simulated/floor/reinforced/nitrogen,/area/constructionsite/atmospherics) +"je" = (/obj/machinery/light/small{dir = 1},/obj/machinery/air_sensor{frequency = 1441; id_tag = "d_n2_sensor"},/turf/simulated/floor/reinforced/nitrogen,/area/constructionsite/atmospherics) +"jf" = (/obj/random/smokes,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jg" = (/obj/structure/lattice,/turf/space,/area/constructionsite) +"jh" = (/obj/structure/table/standard,/obj/structure/bedsheetbin,/turf/simulated/floor/airless,/area/constructionsite) +"ji" = (/obj/structure/table,/turf/simulated/floor/airless,/area/constructionsite) +"jj" = (/obj/structure/table/standard,/obj/random/hat,/obj/random/gloves,/turf/simulated/floor/airless,/area/constructionsite) +"jk" = (/obj/structure/table/standard,/obj/random/gloves,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jl" = (/obj/structure/table/standard,/obj/random/maintenance,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jm" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless,/area/constructionsite) +"jn" = (/obj/structure/table/standard,/turf/simulated/floor/airless,/area/constructionsite/medical) +"jo" = (/obj/structure/table/standard,/obj/structure/closet/body_bag/cryobag,/obj/structure/closet/body_bag/cryobag,/turf/simulated/floor/airless,/area/constructionsite/medical) +"jp" = (/obj/structure/cable/blue,/obj/machinery/power/apc/high/inactive{dir = 2; name = "south bump"; pixel_y = -24},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"jq" = (/obj/machinery/atmospherics/pipe/simple/visible{icon_state = "intact"; dir = 5},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"jr" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 8; frequency = 1441; icon_state = "map_injector"; id = "d_n2_in"; use_power = 1},/turf/simulated/floor/reinforced/nitrogen,/area/constructionsite/atmospherics) +"js" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/reinforced/nitrogen,/area/constructionsite/atmospherics) +"jt" = (/obj/structure/grille/broken,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite) +"ju" = (/turf/simulated/floor/airless,/area/constructionsite) +"jv" = (/obj/structure/door_assembly,/turf/simulated/floor/airless,/area/constructionsite) +"jw" = (/turf/space,/area/constructionsite) +"jx" = (/obj/structure/lattice,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jy" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jz" = (/obj/structure/girder,/turf/simulated/floor/airless,/area/constructionsite) +"jA" = (/obj/structure/lattice,/turf/simulated/wall,/area/constructionsite) +"jB" = (/obj/random/clothing,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jC" = (/obj/structure/coatrack,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jD" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite) +"jE" = (/obj/structure/closet{icon_closed = "cabinet_closed"; icon_opened = "cabinet_open"; icon_state = "cabinet_closed"; name = "Wardrobe"},/turf/simulated/floor/airless,/area/constructionsite) +"jF" = (/obj/structure/bed,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jG" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite) +"jH" = (/obj/structure/lattice,/obj/random/junk,/turf/space,/area/constructionsite) +"jI" = (/obj/machinery/door/airlock{name = "Cabin"},/turf/simulated/floor/airless,/area/constructionsite) +"jJ" = (/obj/random/hat,/turf/simulated/floor/airless,/area/constructionsite) +"jK" = (/obj/random/tool,/turf/simulated/floor/airless,/area/constructionsite) +"jL" = (/obj/random/snack,/turf/simulated/floor/airless,/area/constructionsite) +"jM" = (/obj/machinery/door/airlock{name = "Bunk Room"},/turf/simulated/floor/airless,/area/constructionsite) +"jN" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite) +"jO" = (/obj/item/weapon/bedsheet,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jP" = (/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite) +"jQ" = (/obj/structure/extinguisher_cabinet{icon_state = "extinguisher_empty"; pixel_x = 30},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/aft) +"jR" = (/obj/random/trash,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jS" = (/obj/random/maintenance/clean,/turf/simulated/floor/airless,/area/constructionsite) +"jT" = (/obj/machinery/washing_machine,/turf/simulated/floor/airless,/area/constructionsite) +"jU" = (/obj/structure/table,/obj/random/clothing,/turf/simulated/floor/airless,/area/constructionsite) +"jV" = (/obj/structure/grille,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite) +"jW" = (/obj/random/clothing,/turf/simulated/floor/airless,/area/constructionsite) +"jX" = (/obj/structure/grille,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jY" = (/obj/item/clothing/head/radiation,/turf/simulated/floor/airless,/area/constructionsite) +"jZ" = (/obj/machinery/constructable_frame,/obj/random/material,/turf/simulated/floor/airless,/area/constructionsite) +"ka" = (/obj/machinery/door/airlock/glass_engineering,/turf/simulated/floor/airless,/area/constructionsite) +"kb" = (/obj/random/obstruction,/turf/simulated/floor/airless,/area/constructionsite) +"kc" = (/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite) +"kd" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite) +"ke" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite) +"kf" = (/obj/random/action_figure,/turf/simulated/floor/airless,/area/constructionsite) +"kg" = (/obj/random/voidhelmet,/turf/simulated/floor/airless,/area/constructionsite) +"kh" = (/obj/structure/table/standard,/obj/random/hardsuit,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"ki" = (/obj/random/hostile,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"kj" = (/obj/random/hostile,/turf/simulated/floor/airless,/area/constructionsite) +"kk" = (/obj/structure/table,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite) +"kl" = (/obj/structure/table/standard,/obj/machinery/cell_charger,/obj/random/powercell,/turf/simulated/floor/airless,/area/constructionsite) +"km" = (/obj/machinery/power/terminal{dir = 4},/turf/simulated/floor/airless,/area/constructionsite) +"kn" = (/obj/machinery/power/smes/buildable,/turf/simulated/floor/airless,/area/constructionsite) +"ko" = (/obj/structure/table/rack,/obj/random/tool,/obj/random/tool,/turf/simulated/floor/airless,/area/constructionsite) +"kp" = (/obj/structure/table/rack,/turf/simulated/floor/airless,/area/constructionsite) +"kq" = (/obj/random/glasses,/turf/simulated/floor/airless,/area/constructionsite) +"kr" = (/obj/machinery/power/shield_generator{desc = "A heavy-duty shield generator and capacitor, capable of generating energy shields at large distances. This one seems to be in a state of disrepair."; name = "disused shield generator"},/turf/simulated/floor/airless,/area/constructionsite) +"ks" = (/obj/random/junk,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"kt" = (/obj/machinery/power/breakerbox,/turf/simulated/floor/airless,/area/constructionsite) +"ku" = (/obj/structure/table/rack,/obj/random/toolbox,/obj/random/loot,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"kv" = (/obj/structure/girder/displaced,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"kw" = (/obj/random/closet,/obj/random/loot,/obj/random/junk,/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite) +"kx" = (/obj/machinery/door/airlock/maintenance_hatch,/turf/simulated/floor/airless,/area/constructionsite) +"ky" = (/obj/structure/closet/radiation,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/aft) +"kz" = (/turf/simulated/wall,/area/constructionsite/engineering) +"kA" = (/obj/machinery/door/airlock/glass_engineering{name = "Engine Access"; req_access = list(11)},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kB" = (/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kC" = (/obj/effect/shuttle_landmark/derelict/nav6,/turf/space,/area/space) +"kD" = (/obj/machinery/door/airlock/maintenance_hatch,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kE" = (/obj/structure/lattice,/turf/space,/area/constructionsite/engineering) +"kF" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kG" = (/obj/machinery/door/airlock/glass_engineering,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kH" = (/obj/structure/sign/warning/compressed_gas,/turf/simulated/wall,/area/constructionsite/engineering) +"kI" = (/obj/machinery/portable_atmospherics/canister/empty/phoron,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kJ" = (/turf/space,/area/constructionsite/engineering) +"kK" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"kL" = (/obj/structure/table/standard,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"kM" = (/obj/structure/sign/warning/radioactive,/turf/simulated/wall,/area/constructionsite/engineering) +"kN" = (/obj/structure/table/standard,/obj/random/tool,/obj/random/maintenance,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kO" = (/obj/structure/table,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kP" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kQ" = (/obj/random/maintenance,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/engineering) +"kR" = (/obj/structure/grille/broken,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kS" = (/obj/structure/table/standard,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kT" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kU" = (/obj/structure/table/standard,/obj/random/material,/obj/random/material,/obj/random/material,/obj/random/material,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kV" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/engineering) +"kW" = (/obj/structure/table/standard,/obj/random/toolbox,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kX" = (/obj/structure/table/standard,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kY" = (/obj/structure/grille/broken,/turf/space,/area/constructionsite/engineering) +"kZ" = (/obj/structure/table/rack,/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"la" = (/obj/structure/grille,/turf/space,/area/constructionsite/engineering) +"lb" = (/obj/random/hostile,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lc" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"ld" = (/obj/machinery/portable_atmospherics/canister/nitrogen/engine_setup,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"le" = (/obj/machinery/power/rad_collector,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lf" = (/obj/structure/table/standard,/obj/random/tool,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lg" = (/obj/random/tool,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lh" = (/obj/random/maintenance,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"li" = (/obj/structure/table/standard,/obj/random/tool,/obj/random/voidsuit,/obj/random/coin,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lj" = (/obj/structure/table/standard,/obj/random/toolbox,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lk" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"ll" = (/obj/structure/closet/radiation,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"lm" = (/obj/machinery/portable_atmospherics/canister/phoron/engine_setup,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"ln" = (/obj/random/maintenance,/turf/space,/area/space) +"lo" = (/obj/machinery/door/airlock/glass_engineering{name = "SMES"; req_access = list(11)},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lp" = (/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lq" = (/obj/structure/girder,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lr" = (/obj/structure/table/rack,/obj/random/tool,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"ls" = (/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"lt" = (/obj/structure/table/rack,/obj/random/toolbox,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lu" = (/turf/simulated/wall/r_wall,/area/AIsattele) +"lv" = (/obj/machinery/power/smes/buildable,/obj/structure/cable/blue,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lw" = (/obj/machinery/power/terminal{dir = 8},/obj/structure/cable/blue{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"lx" = (/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"ly" = (/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/blue{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lz" = (/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"lA" = (/obj/machinery/power/terminal{dir = 4},/obj/structure/cable/blue{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lB" = (/obj/structure/table/rack,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lC" = (/obj/structure/computerframe,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/airless,/area/AIsattele) +"lD" = (/obj/machinery/teleport/station,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/airless,/area/AIsattele) +"lE" = (/obj/machinery/teleport/hub,/turf/simulated/floor/airless,/area/AIsattele) +"lF" = (/obj/machinery/power/smes/buildable,/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lG" = (/obj/machinery/power/terminal{dir = 8},/obj/structure/cable/blue{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lH" = (/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/blue{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lI" = (/obj/item/weapon/material/shard{icon_state = "medium"},/turf/simulated/floor/airless,/area/AIsattele) +"lJ" = (/turf/simulated/floor/airless,/area/AIsattele) +"lK" = (/obj/structure/cable,/turf/simulated/floor/airless,/area/AIsattele) +"lL" = (/obj/structure/table/rack,/obj/item/clothing/gloves/insulated,/turf/simulated/floor/airless,/area/AIsattele) +"lM" = (/obj/structure/table/rack,/obj/random/maintenance,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"lN" = (/obj/structure/cable/blue,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lO" = (/obj/structure/girder,/turf/simulated/floor/airless,/area/AIsattele) +"lP" = (/obj/item/weapon/cell,/turf/simulated/floor/airless,/area/AIsattele) +"lQ" = (/obj/structure/grille/broken,/turf/simulated/floor/airless,/area/AIsattele) +"lR" = (/turf/space,/area/AIsattele) +"lS" = (/obj/structure/table,/obj/random/loot,/turf/simulated/floor/airless,/area/AIsattele) +"lT" = (/obj/random/hostile,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"lU" = (/obj/structure/lattice,/turf/space,/area/AIsattele) +"lV" = (/obj/structure/closet,/obj/random/maintenance,/turf/simulated/floor/airless,/area/AIsattele) +"lW" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/airless,/area/AIsattele) +"lX" = (/obj/structure/grille/broken,/turf/space,/area/AIsattele) +"lY" = (/obj/item/weapon/storage/toolbox/electrical{pixel_x = 1; pixel_y = -1},/turf/simulated/floor/airless,/area/AIsattele) +"lZ" = (/obj/machinery/power/emitter{anchored = 1; dir = 4; state = 2},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"ma" = (/obj/machinery/field_generator,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"mb" = (/obj/machinery/power/emitter{anchored = 1; dir = 8; state = 2},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"mc" = (/obj/machinery/the_singularitygen,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"md" = (/obj/effect/shuttle_landmark/derelict/nav7,/turf/space,/area/space) +"nb" = (/obj/structure/table/reinforced,/obj/item/stack/material/glass{amount = 50},/obj/item/stack/material/glass{amount = 50},/obj/item/stack/material/glass{amount = 50},/obj/item/stack/material/glass{amount = 50},/obj/item/stack/material/glass{amount = 50},/obj/random/tech_supply,/obj/random/maintenance,/obj/machinery/camera/motion{c_tag = "Construction Site Teleporter"},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"ob" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{frequency = 1379; id_tag = "constructionsite_vent"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 5},/obj/machinery/camera/motion{c_tag = "Construction Site Teleporter Airlock"},/turf/simulated/floor,/area/constructionsite/teleporter) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadaeafababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababagagahagagabababaiajajakababalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababamaganagagagagaoagababababapabaqaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababagagagagasagagagagabatabakajaqaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababagauabababavawaxababayababatabazajaqaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabagagaAagaBabaCagaDagagagagagaEaFaGaHabaIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaJagagagaKabagagagagagagagagaLababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaMagagagagaNabagagabaOabababagaPabaQagabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaaaaaaaaaaaRaaaaaaaRaaaaaRaaaaaRaaaaaaaRaaaaaaaaaaaaaaaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaSagagagagagabaJagabagaTagabagaUabaVagagagababaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWaWaRaRaWaWaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaWaWaaaaaWaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaSaXaYagagagaZagagabbabbbcabagaLbdagaganagagabababagbeagagbfagagbgbgabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWaWbhbhaWaWaaaRaaaaaaaRaaaaaRaaaaaRaaaaaaaRaaaWaWbhbiaWaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaSbjbkagagagblagagabagagagabagakbmagagagagagaOagaOagagagagaganagagagaOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRbhbnbobobobiaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRbhbobpbobqbiaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaSaKbragagagaZagagabagbsagabajaLbdagagagagagabababagagagagagagagbtagabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRbibobpbubobhaaaRbvbwbxbvaaaaaRaaaabvbybzbvaRaabobubobobobiaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaSagagagagagabaJagabababaOabagaUabaJagagagababaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRbibobobobAbiaaaRbzbBbCbvbvaRaRaRbvbvbDbEbwaRaabibFbGbHbobiaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabIagagagagbJabagagagagagagagajaLabagbgabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRbibobFbHbobiaaaRbwbDbKbLbvbzbwbybvbLbKbMbyaRaabobobobobobhaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaJagagagagabababababagajajajakababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRbhbNbobobubiaaaRbwbObLbKbLbPbDbQbRbKbSbLbyaRaabibpbobobubiaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabagbTbTagagabbUbVbWababbXbYbZcaaFcbccabalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWaWaWaWaWcdceaWaWaWaWbvbLbLbKbLbLbLbLbLbKbLcfbvaWaWaWaWceaWaWaWaWaWaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababauauabababagagagagabagcgajchabazajaqaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWaWbubobobobobobpbobubocibLbOcjbLbLbLbKbLckbLbLclbobobobobobobubobocmaWaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacnabababagagagagagagcoagcpcqcrabakajaqaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWboboboboaWaWaWcdaWaWaWbvbvbLbLbLcscscsctbLbLbvbvaWaWaWaWaWaWaWboboboboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababagagagagagagagababababababapabaqaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWbubocuaWaWcvcwcxcyczcwcAbvcBbRbKctbKbKbKcCbvbvcDcEcFcGcHcIcGaWaWbobuboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacnababagagcJcKagabcLajajajajakababaIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWboboaWaWcwcMcwcAcNcOcPcQcwbvbvbLbLbLbKcRbvbvcScPcwcGcwcycwcycGaWaWbobHaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababcTcUcUcUcUcVcWababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWboaWaWcXcwcAcwcAcwcxcwcAcNcYbvbvcZcZcZbvbvdacGcGcwdbdcdddbcGcPdeaWaWboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWbucddfcwcwcAcydgdhcAcwczcwcNdidjcNcwcwdjdkcwcwcycNdldmdndddocGcGdmaWbpaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWboaWdpcycPcycwcNcNcwcwcwcwcwdqdjcNcNcydjdbcGcwcGcGcwcwcwcGcGdrcNcGaWboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaWbocecwcwcwcwdscwdtddducwcwdhcwdvcwcwdwdjdxcPcNcwcwcycGcGcGcPcydycNcebuaWaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaaaaaaaRdzdzdzdzdAdzdzdzdBdzdjdvdCdDdEdzdBdzdzdFdGdHdGdFdzdzdIdzdJdKdKdLdMdzdNdzdzaWceaWdzdzdzaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRdOaRaRaRaaaaaRdPcwcNcycwcwcNcwcwcwcwcwcNcNcwcwcwcNcNcwcNcNcNcwcycwcycNcNdycwcNcNcNcNcwcwbobobHcNcNdvaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadOaRaRaaaaaaaRdvcNcNcNcwcNcycNcycNcNcNcwdQcNcydRcNcNcNcNcwcwcwcNcNcNcNcNcwcNcNcwcydScwcwdTcycNdocydUaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRdOaRdVaRaaaaaRdvcwcycNcNcNcwcwcycycNcNcNcwcNcwcNdRcwcycycwcNcNcNcwcNcwcNcNcNcycNcwcNcwcycNcNcNcwcwdPaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadOaRaRaaaaaaaRdvcNcwcwcwdzdzdzdzdAdzdzdzdzdzdzdzdzdzdzcwcNcwdzdzdzdzdzdzdzdzdzdzdAdzdzdzdzcwcNcNdWdvaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaaaaaRdzdzcNcwdzdzbobobobobubobobobobobobobodzcNcycNdzbobobobHbobobobobobobobobodzdzcwcNdzdzaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaaaaaRaRaRdvcwcNdzbobodYdYdYdYdYdYdYdZdYdYbobodzcNcNeadzboboebebebebebebebebebebbHbodzcNcNdvaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRdOaRaRaRaaaaaaaRdvcNcNdzbodYdYecedeeefegeheheidYbobudzcwcNcNdzboboebejekelemennbepeqebebbodzcNcwdPaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaaaaaaaaaRdPcNcwdzbodYereseheteheheheseudYboevdzcwcNcwdzbobHebewexeyezeAeAeAeBeCebbodzcwcNdvaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRdOaRaRaRaaaRaRaRdvcNcydzbodYeDeDeDeDeEeDeFeDeDdYdYdYeGcycweHebebebebeIeJeJeJeJeJeJeAeKebbodzcwcwdvaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadOaRaRdOaaaaaaaRdPcwcNdzbodYeLeheheMeheNeheheOePeheheQcwcwcweReSobeUeVeJeJeJeJeJeJeJeWebbodzcycNdPaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRdOaRaRaRaaaaaaaRdvcNcNdzbueXeheheYehehehehehehePeheseZcNcNcNeRfafbfcfdfefffgeJeJeJeJfhebbodzcNcNdvaRaaaaaaaaaaaaaaaaaafiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadOaRaRaaaaaRaRaRdPcwcNdzbodYfjfkfjeDflfjfmeFeDdYdYdYeGcNcycwebebebebfnfoeJfpfqfqfqfrfsebbodzcwcwdvaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRaRdOaRaRdOaaaaaaaRdPcycNdzbodYehehehehehehesftehdYbobodAcwcNcwdAboboebfufveAeAeAeAeAeAfwebbodzcwcydPaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRdOaRaRdOaaaaaaaRdPcNcwdzbodYdYfxeNfyfzfAehehfBdYbudzdzcwcNdRdzdzbHebfCfDfEfFfGfHfIfJebebbodzcNcNdPaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRaadOaRaRdOaaaRaRaRdvcNcwdzbobpdYdYdYdYdYdYdYdYdYdYbodzdWcwcNcNcwdzboebebebebebebebebebebbobodzcNcNdvaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRdOaRaRdOaaaWaWdzdzcNcNdzdzbobobobobobobobubobobobodzcwcNcNcNcNdzbobobobobobofKbobobobobHdzdzcNcPdzdzaWaWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRfLfLfLfLfLaWaWbodzcwdRcNcwdzdzdzdzdzdzdzdzdzdzdzdzdzdzcwcNcwcycwdzdzdzdzdzdzdzdRdzdzdzdzdzdzfMcNdmcwdzbHaWaWfLfLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRfNfNfNfNfOfNfNaRaRaRaRaRfLfPfNfPfPbofQbocNcwdRdRcNcwcwcNcNcwcwfRcycNcwcwcNcwcwcNcwcycNfScNcNcNcwcycNcNcwcwcNcwcwcNcwcwcycNcwdzboboaWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfPfNfTfNbHbobocwcwcycwcwcNcwcNcNcwcycNcwcNcNdmcNcwcNcNcNcNcwcycNcNcycNcNcNcNcwcwcNcwcycNcNcNdocwcwdzboboaWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafUfNfOfOfOfNfOfOfOfNfOfNfOfNfOfNfNfPfNfPfVfLfNfWfPfPaWbubodzcNcNcNcwdzdvdPdvdvdPdPfXdvdPdvdvdzdzdzcycNcNdzdzdzfXdPdPdvdPdvdvdvdPdPdvdzcwcwdRcydzbobHaWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRfOfOfOfOfNfNfNfPfPfNfNfNfNfVfNfNfPfNfNfNfNfLfVfNfPfNaWfQfQdzdzcwcwdzdzaRaRaRaRaRaRaRaRaRaRaRaWbodAcNcPcNdAboaWaRaRaRaRaRaRaaaRaRaaaRdzdzcNcwdzdzboboaWfNfOfNfOfUfUfUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafUfUfUfUfOfOfOfLfOfOfOfLfLfLfOfOfLfLfLfLfLfLfNfVfPfPaWbobobodzcwcwdvaRaaaRaaaRaaaRaWaWaWaWaWaWbodzcwcNcNdzboaWaWaWaWaWaWaRaaaRaaaRaaaRdvcwcNdzbobHboaWfNfVfNfNfOfNfOaRaRaRaRaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRfLfYfZfZfYaWaWaWbodzdRcwdjaRaaaRaaaRaaaRaWbobobobobobodzcNcNcwdzbobobogabobpaWaRaaaRaaaRaaaRdjcNcydzboaWaWaWfLfLfLfLfNfNfNaaaRaaaRaaaRaaaaaaaaaaaaaaaaaaaaaagbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRaRaRaRaRaRaWbodzcwcNdjaRaRaRaRaRaRaRaWbobobogcdzdzdzcwcwcNdzdzdzbobnbuboaWaRaRaRaRaRaRaRdvcwcwdzboaWfNfNfNfNfNfNfNfNfNfVfNgdfNfOfOfOaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRaWbodzcwcydjaRaaaRaaaRaaaRaWbodzdzdzdzcNcwcycwcwcNcwdzdzdzdzboaWaRaaaRaaaRaaaRdPcNcNdzbHaWfNfNfNfVfNfNfNfNfNfNfNfNfNfNfNfNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaWfQdzcNcwdjaRaaaRaaaRaRaRdzdAdzcwcwcNcwcycwcwcNcNcycwcycwdzdAdzaRaRaRaaaRaaaRdjcNcwdzboaWfOfNfOfNfOfNfOfNfOfOfNfNfVfOfOfOaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRaWbodzcwcNdjaRaRaRaRaRaRdzdzcwcwcwcydmcNcwcNcNcyfScNcNcNcwcNcwdzdzaRaRaRaRaRaRdPcNcNdzboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaWbodzcycwdvaRaWaWaWaWdzdzcwcwcNcycwcwcwcNcwcwcwcycwcNcNcNcNcNcwdzdzaWaWaWaWaRdvcwcwdzboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRaWbodzcNcNdvaRaWgebobodAcwcNcNcycycwcwdjdzdzgfdzdzdjcwcycwcNcNcwcNdAboboboaWaRdvcNcydzboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaWfQdzcycwdPaRaWbobodzdzcwcNcwcNcwdjdjdjggghgighggdjdvdPcwcNcycwcPdzdzboboaWaRdjcydRdzboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRaWbodzcwcydvaRaWbHbodzcwcNcycycwdjdjaRaRggghgighggaRaRdPdjcNcNcNcwcwdzboboaWaRdvcwcNdzboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaRgjaRgjgjaRaRgjaRaRgjaWbodzcNdRdPaRaWbobndzcNcNdmcwdPdjaRaRaRggghgighggaRaRaRdjdjcwcNcNcwdzbobHaWaRdPcNcNdzboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRgjaRaRgjgjgkgjgjgjgjgjgjgjglaWbodzcwcwdzaWaWbodzdzcydmcNcNdvaRaRaRgggggmgngmggggaRaRaRdjdjgocwcwdzdzgaaWaWdzcwcwdzbHaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgjgjgjgjgjgjgjgjgjgjgjgjgjgjgjgjgkgjaWfQdzcwcNdzbobHbodzcycycNcwdjdjaRaRgggggigighgigiggggaRaRdzdzcwcNcNcwdzbobobodzcPcNdzboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRdOaRaRaRaRaRdOdOdOdOdOaRgjaRgjaRgjaRgkaRgjaWaWaWaWaWaWaWaWaWaWaWbodzcNcwdzdAdzdzdzcwcwcwcwdzgggggggggpgighghgqgigpggggggggdzcNcycNcwdzdzdzdAdzcwcNdzaWaWdOdOdOaRaRaRaRaRaRaaaRaRaRaRaRaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagjaRgjgjgjgjgjgkgjgjgjgjgjgrgjbobobubofQfQbogsgtbofQbocycNcNcwcwcNcwcwcwcwdmcwdzghgughgmgigighgvghgigigmgwgxgydzcNcwcwcwcwcwcwcNcwcycwcwbofQgjgrgjgjgjgjgjgjgjgrgjgkaaaaaRaaaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRgjgzgjgkgjaRaRgjgjaRgjaRgjaRgjaRgjaRgjgAbogAbobobHbobobobobobpcwcwcwcwcNcwcNdocNcNcycwgBgigigigCghghghgDghghghgEgigFgGgHcwcwcNcwcwcNcwcNcNcNcwcNfQbogIgjgrgjgrgrgjgkgjaRgjaRgjaRgjgjgjaRgJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRgjgjgjgkgjgjgjaRgjaRgjgjgjgkgjbobobogAbobofQbobHbobobocNcwcwcwcwcNcwcwcwcwcycwdzghghghgmgigighgighgGgigmgKgKgKdzcwcNcwcycwcwcNcwcwcwcNcNbofQgraRgkgjgjgjgjgrgjgjgjgjgjgrgjgkaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadOdOdOaRaRaRaRaRdOdOdOdOdOdOdOdOdOdOdOaWaWaWaWaWaWaWaWaWaWaWaWdzcwcNdzdAdzdzdzgLcNdRcwdzgggggggggMgighghgNgigpggggggggdzcNcwcweadzdzdzdAdzcNcNdzaWaWdOdOdOdOdOaRaRaRaRaRaRaRaRaRaRaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaWgAgOgPgQgObobHbogOgQgQgRgQgSgSaRaRgggggGgighgigvggggaRaRgSgSgQgRgRgQgObobobogOgRgQgQgtaWaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaRaRaWgAgOgRgRgOaWaWbogOgOgQgTgQgTgSaRaRaRgggggmgngmggggaRaRaRgSgQgPgRgRgOgObHaWaWgOgPgRgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaRaRaWgAgOgQgUgVaRaWbobogOgQgQgQgQgSgSaRaRaRggghgighggaRaRaRgVgSgRgRgQgQgOboboaWaRgVgUgQgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaWgAgOgQgPgWaRaWbobogOgRgTgRgTgQgSgSaRaRggghgighggaRaRgSgSgQgRgQgRgQgOboboaWaRgWgRgQgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaRaRaWgAgOgRgRgVaRaWbobogOgOgQgXgPgQgRgSgSgSggghgighgggSgSgSgQgRgPgQgQgOgOboboaWaRgWgQgQgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaRaRaWgAgOgRgRgSaRaWbobHbogYgTgPgTgQgTgQgQgSgOgOgZgOgOgShagQgQgRgQgRgQgYbobHgtaWaRgVgQgRgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaWgAgOgXgQgVaRaWaWaWaWgOgOgQgQgRgQgQgPgQgQgQgQgRgRgQgQgQgRgRgRgQgOgOaWaWaWaWaRgVgQgRgObpaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaRaRaWgAgOgQgRgVaRaRaRaRaRaRgOgOgTgQgTgQgRgRgRgQhbgQgRgQgRgRgQgQgXgOgOaRaRaRaRaRaRgWgRgRgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaRaRaWgAgOgPgQgWaRaaaRaaaRaRaRgOgYgOgQgRgRgRgRgRgRgQgRgRgQgRgQgOgYgOaRaRaRaaaRaaaRgVgRgPgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaWgAgOgQgPgVaRaaaRaaaRaaaRaWbogOgOgOgOgQgQgXgQgPgQgQgOgOgOgOboaWaRaaaRaaaRaaaRgWgRgRgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaRaRaWgAgOgRgQgVaRaRaRaRaRaRaRaWbHbobobogOgOgOgRgQgRgOgOgObobobobHaWaRaRaRaRaRaRaRgVgRgUgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahcaaaaaRaRaWgAgOgRgPgWaRaaaRaaaRaaaRaWbobobobobobogOgQgQgQgObobobHbohdbpaWaRaaaRaaaRaaaRgWgQgQgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWgAgOgRgRgWaRaaaRaaaRaaaRaWaWaWaWaWaWbHgOgQgQgRgOboaWaWaWaWaWaWaRaaaRaaaRaaaRgVgRgRgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaWgOgOgQgRgOgOaRaRaRaRaRaRaRaRaRaRaRaWbogYgQgRgRgYboaWaRaRaRaRaRaRaRaRaRaRaRgOgOgQgQgOgOaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgQgPgQgQgOgSgSgWgVgVgVgWgVgSgVgWgOgOgOgQgRgQgOgOgOgSgVgVgSgVgWgVgSgWgVgSgOgRgQgRgQgVaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgRgRgRgUgQgQgRgRgQgQgQgRgRgRgXgPgQgRgRgQgRgQgQgRgQgQgQgXgQgRgRgRgPgQgRgQgPgQgTgRgQgWaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgQgQgRgQgPgRgQgRgQgRgRgRgQgRgQgQgRgQgQgRgQgRgQgPgRgQgRgRgPgQgQgRhegRgQgRgQgTgRgRgRgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgUgQgPgQgOgShfgQgSgOgOgSgSgSgSgSgOgOgQgQgPgQgRgOgOgShggSgShhgSgVgShhgSgOgOgQgQgPgQgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgOhjhjgOgOhkhlhlhmhnhlhohphohqhohpgOgQgRgQgQgRgOhrhshshrhshrhshthrhrhrhsgOgOgRgQgOgOaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRgOgTgTgOhuhvhvhlhwhnhxhlhlhlhlhlhyhzgRgRgPgRgRgOhrhrhrhrhrhrhshrhrhshrhrhrhAgQgQgVaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRgOgTgTgOhvhvhlhvhBhnhChDhEhChChnhngOgOgUgQgQgOgOhrhFhrhshrhrhrhrhGhshshrhGgOgRgRgVaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRgOgTgTgOhvhvhHhvhIhJhKhlhvhvhLhnhMhNgOgQgRgRgOhrhthshshrhOhPhPhrhrhrhrhrhrgOgQgRgWaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgThQhHhRhvhvhvhvhlhvhHhvhShnhvhvgOgQgRgRhThrhshshrhshshUhPhrhrhshVhthrgOgQgPgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgTgOhWhWhWhXhvhvhYhvhZhvhvhChviagSgRgPgPgShrhrhrhrhrhrhPhPhshrhshVhrhrhTgRgRgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgTgOhWhWhWibhWhvhvhvhvhvhvhChvhvgSgRgQgQgShrhshsichrhrhPidhrhrhsiehFhrgOgRgQgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgTgOibhWibhWhWifhWhvhWighWhEihhviigQgRgRijhrhshrhrhrhrhPhPhrhrhriehrhrgOgQgQgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgThQhWhWikhWhWhWilhWhvhvhvhChvhHgSgPgQgQgWhrhshthshrhrimhPhrhrhshsinhrgOgTgTgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgTgOibhWibhWhWhvhWhvhWhvhWhChWiogSgQgQgRgShrhshshrhVhrhPhPhrhrhshrhrhrgOgPgRgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgTgOhWhWhWhWhHhWhvhWhvhviphniahvgOgPgPgQgOhrhshshriehrhrhrhrhshrhsiqhrgOgTgTgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgTgOibiribhWibhWhWhvhWhvhWhnhWiaisgRgRgPgOhrhrhrhsiehshthrhrhrhrhshrhrgOgQgQgOaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaitaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgTgOhWhWhWhWhWhWhWhWhvhvhHhngOgOgOgRgQgQgOgOgOhrhrhrhriuhrhshrhrhrhrhrhAgQgRgWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagTgTgTivibhWibhWibhWibibibhWhWgOgOgQgQgPgRgRgUgUgOgOhrhshrhshshshrhrhPhPhPgOgRgRgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaivgTgTgThWhWhWiwhWhWhWhWhWirhWgOgQgQgQgRgRgQgQgQixgOhrhrhshthrhsiuiyiziAiBgOgQgRgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaivgTgTivibibibibibibiCiChChCiDiEgQgRgQgRgRgQgPgQgRiFhrhrhshGhrhrhriuiGiHiIgOgPgRgWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaivivivivibibhvibibhvhvhvhvhvhviJgQgRgQgQgXgRgRgQgQijiKhrhshshshshrhrhPhPhPgOgRgQgWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiviviviviLibhYibhHhWhvhWhlhWhviJgQgRgRgRiMgQgRgPgQijiNhshrhshshriuiOiziPiQgOgQgTgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaivivivivibibiRiRibhvhvhviShyiTiJgRgRgQgRgQgRgQgRgQijiNhshrhFhrhthriuiGiUiVgOgQgRgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaivivivivibibibibibibibibhChCiWiEgQgQgQgPgQgRgQgRgQiFhrhshriXhrhrhrhrhPhPhPgOgRgRgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiYiYiYiYiZjajajaiZjaiZjaiYhWhWhWhWhWgOgQgQgRgQgQgQgPgRgRgOhrhrhrjbhrhsiujcizjdjegOgQgPgWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiYjfjgiYjgjhjijjjijkjljgjmibhWibjnjogOgOgQgQgQgRgRgQgQgOgOhPhPhrjpjqiuhriuiGjrjsgOgTgTgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajtjujujvjujujwjujxjyjgjgiYaaaRaajgjujggOgOgOgRgQgQgOgOgOaRaRhPhPhPhPhPhPhPhPhPhPgOgQgRgVgkaRgjaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiYjzjAiYjgjujujujyjBjujCiYaRaRaRjujujujujugOgQgRgRgOjgjgjujujgjujgjujujujujgjDjggQgTgTgWaRaRaRgjaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiYjEjFiYjujyjujujyjujyiYiYaaaRaajgjujgjujggOgQgPgRgOjgjujujuiYiYiYiYiYiYiYiYiYiYiYiYiYiYiYjgjgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajGjujHjIjgjJjujujKjyjuiYjwaaaRaajujujujujugOgQgRgQgOjgjujujuiYjujujujujujujgjgjgjgjgjgjgjgjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajAiYiYiYjujujyjyjujLjujMjwaRaRaRjgjujgjujggOgTgUgQgOjujujujuiYjgjujgjujgjujgjgjwjwjgjwjwjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajNjOjgjzjgjujPjujujujyiYjwaaaRaajujujujujugQgQgQjQgOjujujgjgiYjujujujujujujujujujujgjwjwjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiZjujujujujujujujRjyjyiYiYaaaRaajgjujgjujggQgTgRgQgOjgjgjgjgiYjgjujgjujgjujgjujgjujgjujgjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajAiYjAiYjgjSjyjujyjujyjTjzaRaRaRjujujujujugQgQgRgQgOjgjgjujuiYjujujujPjujujujujuiYiYiYiYjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajAjEjwiYjujujyjyjyjujujUjzaaaRaajgjujgjujggQgRgRgPgOjgjgjujuiYjgjujgjujgjujgjgjgjujgjujgjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajVjgjyjvjujujujWjujLjyjTjzaaaRaajujujujujugOgQgQgQgOjgjgjujuiYjujujujujujujuiYjwjwjgjwjwjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajAiYiYiYiZjajaiZjajXiZjNiYaRaRaRjgjujgjujggOgQgRgRgTjgjgjujuiYjgjujgjujgjujgjgjgjgjgjgjgjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajujujujujugOgPgQgQgTjgjgjujuiYjujujujujujYjujujujujgjwjwjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajgjujgjujggOgXgQgPgOjgjgjujuiYjgjujgjujgjujgjgjgjgjgjgjgjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajwjwiYiYiYiYjwjwjwjwjwjwjwjwjwaaaaaaaRgOgRgRgQgOjgjgjujuiYjujuiYjujgjujwjgjwjwjgjwjwjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajwjwjujyjgiYiYiYiYjwjwjwjwjwjwaaaaaaaagOgRgRgQgOjgjgjgjuiYjujujgjujujujujgjujgjujgjgjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaajwjwjujgjujgjZjgiYjziYiYjwjwjwaaaaaaaagOgQgQgQgOjgjgjgjuiYjujujujDjujujujujujujujujwjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajwiYiYjgjujgjyjujgjgjuiYkakbiYaaaaaaaRgOgPgRjQgOjwjwjgjuiYiYiYiYiYiYjuiYiYiYiYiYiYjgjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaajwiYjujukcjujgjDjgjyjgjgjujDjzaaaaaaaagOgRgRgQgOjgjgjgjujujujujujujujujujujukcjujujwjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaaaaaaaaaaaajwjzjujDkdjyjyjyjujykejukfjyiYaaaaaaaagOgQgPgQgOjwjwjgjukdjujujgjujujgjujgjujgkgjgjgjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiYiYjyjujyjujikhkijujujyjDiYiYaaaaaaaRgOgQgRgQgOjgjgjgjujujwjgjwjwjgjwjwjgjwaaaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajujujukjjukejukkkljyjykmknjzjwaaaaaaaagOgQgRgQgTjwjwjwjujgjgjgjgjgjgjgjgjgjgaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajujykokpkqjujujukrjuksjyktjzjwaaaaaaaagOgQgRgRgTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaaiYiYjziYjgkujgjyjgjujujDiYiYjwaaaaaaaRgOgQgRgRgTaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRjgjgjwiYjNiYiYjgkjjgkbjgkvjwjwaaaaaaaagOgRgQgQgTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRjgjgjgjwjwjwiYiYjziYjgkwiYjwjwaaaaaaaagOgRgRgQgTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajwjwjwjwjwjwjwjwjwiYiYiYiYjwjwaaaaaaaRgOgQgQgPgTaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagOgPgQgQgTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagOgRgRgRgOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRgOgRgQgQgOaRaRaRaRaRaRaRaRaRaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRjgjgjgiYjgjgiYiYiYiYiYiYiYgOgQgQgRgOiYiYiYiYiYiYiYiYiYiYiYiYiYiYiYiYjgaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajujujujujujujujujujujujukxgQgQgPgRgQkxjujujujujujgjgjgjujgjgjujgjujgjggjaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRaRaRaRjgjgjgjgiYiYiYiYiYiYiYiYiYgOkygQgQgOiYiYiYiYiYiYiYiYiYiYiYiYjgjgjgjgjgaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRgOkzkAkzgOaRaRaRaRaRaRaRaRaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRkzkBkzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiYiYiYjgjgjgiYiYiYiYiYiYiYiYiYiYiYkzkzkzkAkzkzkziYiYiYiYiYiYiYiYiYiYdOdOaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRjgjgjgjgjujujujujujujujujujujujujukDkBkBkBkBkBkDjujujujukjjujujujujugjgjgjaaaRaaaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiYiYiYiYiYiYiYiYiYiYkzkzkzkzkzkzkzkzkAkzkzkzkzkzkzkzkziYiYiYiYiYaRaRaRaRaRaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRkEkEkzkFkzkBkBkGkBkBkBkBkBkGkBkBkHkIkzkEkEaRaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkJkzkBkBkKkLkzkzkMkAkMkzkzkNkBkBkKkzkJkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkzkzkBkKkKkOkPkEkzkBkzkEkPkLkKkKkBkzkzkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkzkBkQkKkBkBkRkEkzkBkzkEkRkSkKkKkBkTkzkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkzkBkBkBkKkUkRkEkzkBkzkEkRkOkVkBkKkBkzkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakzkzkBkKkBkBkWkPkEkzkBkzkEkRkXkBkBkKkFkzkzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakYkZkKkBkBkKkOkPkEkzkBkzkEkPkKkKkBkKkBkBkPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalakBkKlbkKkBkOkRkEkzkBkzkElckXkKldkVkKkKkRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalakBkKlekKkKlflckEkzkBkzkEkPkOkKkKkBlglhkPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalakBkBkBkKkKlilckEkzkBkzkEkRkOkBkBkBkKkBkRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakYkBkKkBkKkBkOlckEkzkBkzkEkPljlkkBkVkBkIkPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakzkzkFkBkKkVkBkzkzkzkAkzkzkzllkBkKkKlmkzkzaaaalnaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkzkzkzlokMkzkzkBkBlpkKlekzkzkMlolqkzkzkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkJlakBkKlrkPlpkKkBlskKkKlpkPltkBkKkPkJkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalululululuaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkJlakBkBkKkPlvlwlxlylzlAlvkPlBkBkKkPkJkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRlululClDlEluluaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkJkYkKkBlBkPlFlGlzlHlxlAlFkPkBkBkBkPkJkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRlululIlJlKlJlLluluaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkJlalekBlMkPlNkBkKkBkBkBlNkRkZkKkBkPkJkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalOlPlJlQlRlJlJlSluaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkJkzkzkzkzkzkzkBkBkKkKlTkzkzkzkzkzkzkJkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalJlJlJlUlUlUlJlJluaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkJkJkBkBkBkBkzkzkPkPkPkzkzkBkBkBkBkJkJkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalulJlUlUlRlUlRlVluaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBaRaRaRkBaRaRaRkBaRaRaRkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRlululWlXlRlUlYluluaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBlZkBmakBkBkBmakBkBkBmakBmbkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRlululJlUlJluluaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBaRkBaRaRaRkBaRaRaRkBaRkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalululJluluaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalkkBaRkBaRaaaRkBaRaaaRkBaRkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBaRkBaRaRaRkBaRaRaRkBaRkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBkBmakBkBkBmckBkBkBmakBkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBaRkBaRaRaRkBaRaRaRkBaRkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBaRkBaRaaaRkBaRaaaRkBaRkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBkBkBaRaRaRkBaRaRaRkBkBkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBlZkBmakBkBkBmakBkBkBmakBmbkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBkBkBkBkBkBkBkBkBkBkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaamdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/derelict/derelict-station.dmm b/maps/away/derelict/derelict-station.dmm new file mode 100644 index 00000000..2662c1de --- /dev/null +++ b/maps/away/derelict/derelict-station.dmm @@ -0,0 +1,831 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/turf/simulated/wall/voxshuttle,/area/derelict/ship) +"ac" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/derelict/ship) +"ad" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/derelict/ship) +"ae" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/derelict/ship) +"af" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/derelict/ship) +"ag" = (/turf/simulated/floor/tiled,/area/derelict/ship) +"ah" = (/obj/machinery/sleeper,/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/derelict/ship) +"ai" = (/obj/item/weapon/cell,/turf/simulated/floor/plating,/area/derelict/ship) +"aj" = (/turf/simulated/floor/plating,/area/derelict/ship) +"ak" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/derelict/ship) +"al" = (/obj/structure/shuttle/engine/propulsion{icon_state = "burst_r"; dir = 4},/turf/space,/area/derelict/ship) +"am" = (/obj/item/modular_computer/console/preset/medical,/turf/simulated/floor/tiled,/area/derelict/ship) +"an" = (/obj/random/maintenance,/turf/simulated/floor/tiled,/area/derelict/ship) +"ao" = (/obj/structure/table/standard,/obj/random/firstaid,/turf/simulated/floor/tiled,/area/derelict/ship) +"ap" = (/obj/machinery/door/airlock/glass,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/derelict/ship) +"aq" = (/obj/structure/shuttle/engine/heater{icon_state = "heater"; dir = 4},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/airless,/area/derelict/ship) +"ar" = (/obj/structure/shuttle/engine/propulsion{icon_state = "propulsion"; dir = 4},/turf/space,/area/derelict/ship) +"as" = (/obj/item/weapon/scalpel,/turf/simulated/floor/tiled,/area/derelict/ship) +"at" = (/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor/tiled,/area/derelict/ship) +"au" = (/obj/structure/computerframe{anchored = 1},/turf/simulated/floor/tiled,/area/derelict/ship) +"av" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/derelict/ship) +"aw" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/derelict/ship) +"ax" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/derelict/ship) +"ay" = (/obj/machinery/door/airlock/glass{name = "Hibernation Pods"},/turf/simulated/floor/tiled,/area/derelict/ship) +"az" = (/obj/machinery/light{dir = 8},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/derelict/ship) +"aA" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/tiled,/area/derelict/ship) +"aB" = (/obj/structure/table/standard,/obj/item/weapon/cell,/turf/simulated/floor/tiled,/area/derelict/ship) +"aC" = (/obj/item/device/multitool,/turf/simulated/floor/tiled,/area/derelict/ship) +"aD" = (/obj/item/weapon/cell{charge = 100; maxcharge = 15000},/turf/simulated/floor/tiled,/area/derelict/ship) +"aE" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/derelict/ship) +"aF" = (/obj/machinery/door/airlock/glass,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/derelict/ship) +"aG" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plating,/area/derelict/ship) +"aH" = (/obj/machinery/pipedispenser,/turf/simulated/floor/plating,/area/derelict/ship) +"aI" = (/obj/structure/shuttle/engine/propulsion{icon_state = "burst_l"; dir = 4},/turf/space,/area/derelict/ship) +"aJ" = (/obj/machinery/light{dir = 8},/turf/simulated/floor/tiled,/area/derelict/ship) +"aK" = (/obj/structure/table/standard,/obj/random/maintenance,/turf/simulated/floor/tiled,/area/derelict/ship) +"aL" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/derelict/ship) +"aM" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plating,/area/derelict/ship) +"aN" = (/obj/structure/table/standard,/obj/machinery/light{dir = 4},/turf/simulated/floor/tiled,/area/derelict/ship) +"aO" = (/obj/machinery/door/airlock/glass,/turf/simulated/floor/tiled,/area/derelict/ship) +"aP" = (/obj/machinery/light_switch{pixel_x = 27},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/derelict/ship) +"aQ" = (/obj/machinery/portable_atmospherics/powered/scrubber,/turf/simulated/floor/tiled,/area/derelict/ship) +"aR" = (/obj/structure/lattice,/turf/space,/area/space) +"aS" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plating,/area/derelict/ship) +"aT" = (/obj/structure/bed,/obj/item/weapon/bedsheet,/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/tiled,/area/derelict/ship) +"aU" = (/obj/machinery/light{dir = 4},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/derelict/ship) +"aV" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/tiled,/area/derelict/ship) +"aW" = (/turf/simulated/wall,/area/constructionsite/maintenance) +"aX" = (/obj/structure/table/standard,/obj/random/handgun,/turf/simulated/floor/tiled,/area/derelict/ship) +"aY" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/derelict/ship) +"aZ" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plating,/area/derelict/ship) +"ba" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled,/area/derelict/ship) +"bb" = (/obj/structure/table/standard,/obj/item/weapon/tank/oxygen,/turf/simulated/floor/tiled,/area/derelict/ship) +"bc" = (/obj/machinery/light_switch{pixel_x = 27},/turf/simulated/floor/tiled,/area/derelict/ship) +"bd" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/derelict/ship) +"be" = (/obj/random/loot,/turf/simulated/floor/tiled,/area/derelict/ship) +"bf" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/derelict/ship) +"bg" = (/obj/random/closet,/turf/simulated/floor/tiled,/area/derelict/ship) +"bh" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bi" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bj" = (/obj/structure/table/standard,/obj/item/device/analyzer,/turf/simulated/floor/tiled,/area/derelict/ship) +"bk" = (/obj/structure/bed/chair{dir = 8},/turf/simulated/floor/tiled,/area/derelict/ship) +"bl" = (/obj/machinery/door/airlock/glass,/turf/simulated/floor/shuttle/white,/area/derelict/ship) +"bm" = (/obj/machinery/door/airlock/glass{name = "Living Module"},/turf/simulated/floor/shuttle/white,/area/derelict/ship) +"bn" = (/obj/random/hostile,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bo" = (/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bp" = (/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bq" = (/obj/random/cash,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"br" = (/obj/structure/table/standard,/obj/random/loot,/turf/simulated/floor/tiled,/area/derelict/ship) +"bs" = (/obj/structure/bed,/obj/item/weapon/bedsheet,/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/tiled,/area/derelict/ship) +"bt" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/tiled,/area/derelict/ship) +"bu" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bv" = (/turf/simulated/wall,/area/constructionsite/bridge) +"bw" = (/obj/structure/grille,/obj/machinery/door/blast/regular/open,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bx" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"by" = (/obj/effect/wingrille_spawn/reinforced,/obj/machinery/door/blast/regular/open,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"bz" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bA" = (/obj/random/material,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bB" = (/obj/structure/table/standard,/obj/item/modular_computer/laptop,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"bC" = (/obj/structure/table/standard,/obj/random/drinkbottle,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bD" = (/obj/structure/table/standard,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bE" = (/obj/structure/table,/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bF" = (/turf/space,/area/constructionsite/maintenance) +"bG" = (/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bH" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/maintenance) +"bI" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plating,/area/derelict/ship) +"bJ" = (/obj/machinery/light_switch{pixel_x = 27},/obj/machinery/light{dir = 4},/turf/simulated/floor/tiled,/area/derelict/ship) +"bK" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"bL" = (/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bM" = (/obj/random/trash,/obj/structure/table,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"bN" = (/obj/random/closet,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"bO" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bP" = (/obj/structure/table/standard,/obj/item/weapon/paper{info = "\\\[center]\\\[b]ATTN: Regarding Meteor Storms\\\[/b]\[/center]\\\[br]\\\[br]We've recently heard mutterings from the Atmospheric Technicians that the meteor showers in this sector are becoming too much. However, this should be disregarded.\\\[br]\\\[br] High Command has assured us that our shields can easily keep pace with any meteor storm and then some. Any uneasiness the crew may feel should be disspelled swiftly. Thank you."; name = "ATTN: Regarding Meteor Storms"},/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bQ" = (/obj/structure/table,/obj/random/material,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"bR" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/bridge) +"bS" = (/obj/random/hostile{spawn_nothing_percentage = 60},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"bT" = (/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/derelict/ship) +"bU" = (/obj/structure/table/rack,/obj/item/weapon/tank/emergency/oxygen,/obj/item/weapon/tank/emergency/oxygen,/obj/item/weapon/tank/emergency/oxygen,/obj/item/weapon/tank/emergency/oxygen,/obj/random/tank,/turf/simulated/floor/tiled,/area/derelict/ship) +"bV" = (/obj/structure/table/rack,/obj/item/clothing/mask/breath,/obj/item/weapon/cell,/turf/simulated/floor/tiled,/area/derelict/ship) +"bW" = (/obj/structure/table/rack,/obj/item/weapon/storage/toolbox/syndicate,/obj/random/maintenance,/turf/simulated/floor/tiled,/area/derelict/ship) +"bX" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/power/apc/high/inactive{dir = 8; name = "west bump"; pixel_x = -24},/turf/simulated/floor/plating,/area/derelict/ship) +"bY" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/plating,/area/derelict/ship) +"bZ" = (/obj/item/weapon/cell{charge = 100; maxcharge = 15000},/turf/simulated/floor/plating,/area/derelict/ship) +"ca" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/derelict/ship) +"cb" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating,/area/derelict/ship) +"cc" = (/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/power/solar_control,/turf/simulated/floor/plating,/area/derelict/ship) +"cd" = (/obj/structure/girder,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"ce" = (/obj/machinery/door/airlock/maintenance_hatch,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"cf" = (/obj/random/handgun,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"cg" = (/obj/item/stack/cable_coil,/turf/simulated/floor/plating,/area/derelict/ship) +"ch" = (/obj/structure/cable/yellow,/obj/machinery/power/terminal,/turf/simulated/floor/plating,/area/derelict/ship) +"ci" = (/obj/machinery/door/airlock/maintenance_hatch,/obj/machinery/door/blast/regular/open,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"cj" = (/obj/random/hostile{spawn_nothing_percentage = 60},/turf/simulated/floor/airless,/area/constructionsite/bridge) +"ck" = (/obj/random/junk,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"cl" = (/obj/machinery/door/airlock/maintenance_hatch,/obj/machinery/door/blast/regular,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"cm" = (/obj/random/closet,/obj/random/maintenance,/obj/random/maintenance,/obj/random/material,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"cn" = (/turf/simulated/wall/voxshuttle,/area/space) +"co" = (/obj/machinery/door/airlock/glass{name = "Pod Bay"},/turf/simulated/floor/tiled,/area/derelict/ship) +"cp" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/derelict/ship) +"cq" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/plating,/area/derelict/ship) +"cr" = (/obj/machinery/power/smes/batteryrack,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/derelict/ship) +"cs" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"ct" = (/obj/random/trash,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"cu" = (/obj/random/closet,/obj/random/energy,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"cv" = (/obj/structure/bookcase/manuals/engineering,/obj/effect/decal/cleanable/cobweb,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cw" = (/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cx" = (/obj/structure/bookcase,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"cy" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"cz" = (/obj/structure/bookcase/manuals/xenoarchaeology,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cA" = (/obj/structure/bookcase,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cB" = (/obj/structure/girder,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"cC" = (/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/bridge) +"cD" = (/obj/structure/table/marble,/obj/random/coin,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cE" = (/obj/structure/table/marble,/obj/machinery/microwave,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cF" = (/obj/structure/table/marble,/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cG" = (/turf/simulated/floor/tiled/white/airless,/area/constructionsite/hallway/fore) +"cH" = (/obj/structure/table,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cI" = (/obj/structure/table,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/hallway/fore) +"cJ" = (/obj/structure/table/standard,/obj/item/weapon/screwdriver,/obj/machinery/light,/obj/random/maintenance,/turf/simulated/floor/tiled,/area/derelict/ship) +"cK" = (/obj/structure/table/standard,/obj/item/device/radio/off,/turf/simulated/floor/tiled,/area/derelict/ship) +"cL" = (/obj/machinery/autolathe,/turf/simulated/floor/plating,/area/derelict/ship) +"cM" = (/obj/structure/bookcase,/obj/item/weapon/book/manual/excavation,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cN" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"cO" = (/obj/structure/bookcase/manuals/xenoarchaeology,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"cP" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cQ" = (/obj/structure/bookcase,/obj/item/weapon/book/manual/ripley_build_and_repair,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cR" = (/obj/structure/noticeboard{pixel_x = 32},/turf/simulated/floor/airless,/area/constructionsite/bridge) +"cS" = (/obj/effect/decal/cleanable/cobweb,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cT" = (/obj/structure/window/reinforced,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/tracker,/turf/simulated/floor/plating,/area/derelict/ship) +"cU" = (/obj/structure/window/reinforced,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/derelict/ship) +"cV" = (/obj/structure/window/reinforced,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/cable/yellow,/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/derelict/ship) +"cW" = (/obj/structure/window/reinforced,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/derelict/ship) +"cX" = (/obj/machinery/bookbinder,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"cY" = (/obj/structure/filingcabinet/filingcabinet,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"cZ" = (/obj/machinery/door/airlock/glass_command{name = "Bridge"; req_access = list(19)},/obj/machinery/door/blast/regular,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/bridge) +"da" = (/obj/structure/closet/secure_closet/freezer/fridge{icon_state = "fridgebroken"; locked = 0},/obj/random/contraband,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"db" = (/obj/structure/table/marble,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dc" = (/obj/structure/table/marble,/obj/item/weapon/material/kitchen/rollingpin,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dd" = (/obj/structure/table,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"de" = (/obj/random/closet,/obj/random/voidhelmet,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"df" = (/obj/structure/table/rack,/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dg" = (/obj/structure/bookcase/manuals/medical,/obj/item/weapon/book/manual/nuclear,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"dh" = (/obj/random/trash,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"di" = (/obj/structure/table/rack,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dj" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dk" = (/obj/structure/table/marble,/obj/random/drinkbottle,/obj/random/drinkbottle,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dl" = (/obj/structure/table/marble,/obj/random/gloves,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dm" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dn" = (/obj/structure/table/marble,/obj/random/drinkbottle,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"do" = (/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dp" = (/obj/structure/table/rack,/obj/random/tool,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dq" = (/obj/structure/table/rack,/obj/random/hat,/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dr" = (/obj/random/junk,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/hallway/fore) +"ds" = (/obj/structure/table/standard,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"dt" = (/obj/structure/table/standard,/obj/random/toy,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"du" = (/obj/structure/table/standard,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dv" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dw" = (/turf/simulated/floor/holofloor/tiled/dark,/area/constructionsite/hallway/fore) +"dx" = (/obj/random/junk,/obj/structure/table,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dy" = (/obj/random/snack,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dz" = (/turf/simulated/wall,/area/constructionsite/hallway/fore) +"dA" = (/obj/machinery/door/airlock/maintenance_hatch,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dB" = (/obj/machinery/door/airlock/glass{name = "Library"},/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dC" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"dD" = (/obj/structure/grille/broken,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"dE" = (/obj/structure/grille,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"dF" = (/obj/structure/sign/warning/secure_area,/turf/simulated/wall,/area/constructionsite/hallway/fore) +"dG" = (/obj/machinery/door/airlock/glass_command{name = "Bridge"; req_access = list(19)},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"dH" = (/obj/machinery/door/airlock/glass_command{name = "Bridge"; req_access = list(19)},/turf/simulated/floor/holofloor/tiled/dark,/area/constructionsite/hallway/fore) +"dI" = (/obj/machinery/door/airlock/glass{name = "Kitchen"; req_access = list(28)},/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dJ" = (/obj/structure/table/marble,/obj/machinery/door/blast/shutters,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"dK" = (/obj/structure/table/marble,/obj/machinery/door/blast/shutters/open,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dL" = (/obj/structure/table,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/fore) +"dM" = (/obj/structure/table,/obj/machinery/door/blast/shutters/open,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dN" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dO" = (/turf/simulated/wall,/area/space) +"dP" = (/obj/structure/grille/broken,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dQ" = (/obj/random/smokes,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"dR" = (/obj/structure/lattice,/turf/space,/area/constructionsite/hallway/fore) +"dS" = (/obj/random/snack,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"dT" = (/obj/random/trash,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"dU" = (/obj/structure/grille/broken,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"dV" = (/obj/structure/lattice,/obj/random/junk,/turf/space,/area/space) +"dW" = (/obj/structure/table/rack,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"dX" = (/obj/effect/shuttle_landmark/derelict/nav2,/turf/space,/area/space) +"dY" = (/turf/simulated/wall,/area/constructionsite/storage) +"dZ" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless,/area/constructionsite/storage) +"ea" = (/obj/structure/extinguisher_cabinet{icon_state = "extinguisher_empty"; pixel_x = 30},/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"eb" = (/turf/simulated/wall,/area/constructionsite/teleporter) +"ec" = (/obj/machinery/mech_recharger,/obj/effect/decal/mecha_wreckage/mauler,/turf/simulated/floor/airless,/area/constructionsite/storage) +"ed" = (/obj/machinery/mecha_part_fabricator,/turf/simulated/floor/airless,/area/constructionsite/storage) +"ee" = (/obj/structure/table/standard,/turf/simulated/floor/airless,/area/constructionsite/storage) +"ef" = (/obj/structure/table/standard,/obj/random/material,/obj/random/material,/obj/random/coin,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eg" = (/obj/structure/table,/obj/machinery/cell_charger,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/storage) +"eh" = (/turf/simulated/floor/airless,/area/constructionsite/storage) +"ei" = (/obj/structure/table,/obj/random/medical,/turf/simulated/floor/airless,/area/constructionsite/storage) +"ej" = (/obj/machinery/shieldgen,/obj/structure/window/basic{icon_state = "window"; dir = 8},/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"ek" = (/obj/machinery/shieldgen,/obj/structure/window/basic{icon_state = "window"; dir = 4},/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"el" = (/obj/machinery/portable_atmospherics/canister/air,/obj/structure/window/basic{icon_state = "window"; dir = 8},/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"em" = (/obj/machinery/portable_atmospherics/canister/air,/obj/structure/window/basic{icon_state = "window"; dir = 4},/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"en" = (/obj/structure/table/reinforced,/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/item/stack/material/steel{amount = 50; pixel_x = 0; pixel_y = 0},/obj/item/stack/material/steel{amount = 50; pixel_x = 0; pixel_y = 0},/obj/item/stack/material/steel{amount = 50; pixel_x = 0; pixel_y = 0},/obj/item/stack/material/steel{amount = 50; pixel_x = 0; pixel_y = 0},/obj/item/stack/material/steel{amount = 50; pixel_x = 0; pixel_y = 0},/obj/random/tech_supply,/obj/random/maintenance,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"ep" = (/obj/structure/table/reinforced,/obj/item/stack/material/plasteel{amount = 50},/obj/random/tech_supply,/obj/random/maintenance,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eq" = (/obj/structure/table/reinforced,/obj/random/powercell,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/maintenance,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"er" = (/obj/structure/table/rack,/obj/random/maintenance,/obj/random/toolbox,/turf/simulated/floor/airless,/area/constructionsite/storage) +"es" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/storage) +"et" = (/obj/structure/bed/chair/office/light{dir = 1},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/storage) +"eu" = (/obj/machinery/optable{name = "Robotics Operating Table"},/turf/simulated/floor/airless,/area/constructionsite/storage) +"ev" = (/obj/random/closet,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"ew" = (/obj/machinery/shieldgen,/obj/structure/window/basic{icon_state = "window"; dir = 8},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"ex" = (/obj/machinery/shieldgen,/obj/structure/window/basic{icon_state = "window"; dir = 4},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"ey" = (/obj/machinery/portable_atmospherics/canister/air,/obj/structure/window/basic{icon_state = "window"; dir = 8},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"ez" = (/obj/machinery/portable_atmospherics/canister/air,/obj/structure/window/basic{icon_state = "window"; dir = 4},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eA" = (/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eB" = (/obj/structure/table/reinforced,/obj/item/clothing/shoes/magboots,/obj/item/clothing/glasses/meson,/obj/item/weapon/tank/oxygen,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/voidsuit,/obj/random/voidhelmet,/obj/random/maintenance,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eC" = (/obj/structure/table/reinforced,/obj/item/stack/material/phoron{amount = 10},/obj/random/powercell,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/maintenance,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eD" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eE" = (/obj/machinery/door/airlock/glass_science{name = "Robotics"},/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/storage) +"eF" = (/obj/structure/grille/broken,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eG" = (/obj/structure/sign/warning/science,/turf/simulated/wall,/area/constructionsite/hallway/fore) +"eH" = (/obj/machinery/access_button/airlock_exterior{master_tag = "constructionsite_airlock"; pixel_x = 20; pixel_y = 0; req_access = list(10)},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"eI" = (/obj/structure/sign/warning/vacuum{pixel_x = -32},/obj/machinery/access_button/airlock_interior{master_tag = "constructionsite_airlock"; pixel_x = -20; pixel_y = 0; req_access = list(10)},/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 1},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eJ" = (/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"eK" = (/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/obj/machinery/power/port_gen/pacman,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eL" = (/obj/structure/skele_stand,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eM" = (/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eN" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eO" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/storage) +"eP" = (/obj/machinery/door/airlock/glass_science{name = "Research"},/obj/machinery/door/blast/shutters,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eQ" = (/obj/machinery/door/airlock/glass_science{name = "Research"},/obj/machinery/door/blast/shutters,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"eR" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "constructionsite_outer"; locked = 1; req_access = list(10)},/turf/simulated/floor,/area/constructionsite/teleporter) +"eS" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{frequency = 1379; id_tag = "constructionsite_vent"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor,/area/constructionsite/teleporter) +"eU" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "constructionsite_inner"; locked = 1; req_access = list(10)},/turf/simulated/floor,/area/constructionsite/teleporter) +"eV" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"eW" = (/obj/structure/cable/blue,/obj/machinery/power/port_gen/pacman,/obj/machinery/power/terminal,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"eX" = (/obj/machinery/door/airlock/maintenance_hatch,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eY" = (/obj/random/hostile,/turf/simulated/floor/airless,/area/constructionsite/storage) +"eZ" = (/obj/machinery/door/airlock/glass_science{name = "Research"},/obj/machinery/door/blast/shutters/open,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"fa" = (/obj/machinery/atmospherics/pipe/simple/hidden/blue{icon_state = "intact"; dir = 5},/obj/machinery/light/small,/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1379; id_tag = "constructionsite_airlock"; pixel_x = 0; pixel_y = -25; req_access = list(10); tag_airpump = "constructionsite_vent"; tag_chamber_sensor = "constructionsite_sensor"; tag_exterior_door = "constructionsite_outer"; tag_interior_door = "constructionsite_inner"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor,/area/constructionsite/teleporter) +"fb" = (/obj/machinery/atmospherics/pipe/manifold/hidden/blue,/obj/machinery/airlock_sensor{frequency = 1379; id_tag = "constructionsite_sensor"; pixel_x = 0; pixel_y = -25},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 6},/turf/simulated/floor,/area/constructionsite/teleporter) +"fc" = (/obj/machinery/atmospherics/pipe/simple/hidden/blue{icon_state = "intact"; dir = 4},/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "constructionsite_inner"; locked = 1; req_access = list(10)},/turf/simulated/floor,/area/constructionsite/teleporter) +"fd" = (/obj/machinery/atmospherics/pipe/simple/hidden/blue{icon_state = "intact"; dir = 4},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"fe" = (/obj/machinery/atmospherics/pipe/simple/hidden/blue{icon_state = "intact"; dir = 10},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"ff" = (/obj/structure/cable/blue{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"fg" = (/obj/structure/cable/blue{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"fh" = (/obj/machinery/power/smes/batteryrack{should_be_mapped = 1},/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fi" = (/obj/effect/shuttle_landmark/derelict/nav1,/turf/space,/area/space) +"fj" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite/storage) +"fk" = (/obj/structure/grille/broken,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/storage) +"fl" = (/obj/machinery/door/airlock/glass_science{name = "Research"},/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/storage) +"fm" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/storage) +"fn" = (/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/machinery/portable_atmospherics/canister/air/airlock,/obj/machinery/atmospherics/portables_connector{icon_state = "map_connector"; dir = 4},/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 4},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fo" = (/obj/machinery/atmospherics/pipe/manifold/hidden/blue{icon_state = "map"; dir = 4},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"fp" = (/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"fq" = (/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/constructionsite/teleporter) +"fr" = (/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fs" = (/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/blue{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/autolathe,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"ft" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/storage) +"fu" = (/obj/structure/window/basic,/obj/machinery/portable_atmospherics/canister/air/airlock,/obj/machinery/atmospherics/portables_connector{icon_state = "map_connector"; dir = 4},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fv" = (/obj/machinery/atmospherics/pipe/simple/hidden/blue{icon_state = "intact"; dir = 9},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fw" = (/obj/structure/cable/blue,/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/power/apc/high/inactive{dir = 2; name = "south bump"; pixel_y = -24},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fx" = (/obj/machinery/portable_atmospherics/canister/nitrogen/prechilled,/turf/simulated/floor/airless,/area/constructionsite/storage) +"fy" = (/obj/machinery/r_n_d/circuit_imprinter,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/storage) +"fz" = (/obj/machinery/r_n_d/destructive_analyzer,/turf/simulated/floor/airless,/area/constructionsite/storage) +"fA" = (/obj/machinery/r_n_d/protolathe{icon_state = "protolathe_t"; stat = 1},/turf/simulated/floor/airless,/area/constructionsite/storage) +"fB" = (/obj/machinery/r_n_d/server/centcom,/turf/simulated/floor/airless,/area/constructionsite/storage) +"fC" = (/obj/machinery/pipedispenser,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fD" = (/obj/machinery/pipedispenser/disposal,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fE" = (/obj/structure/reagent_dispensers/watertank,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fF" = (/obj/structure/reagent_dispensers/fueltank,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fG" = (/obj/machinery/light,/obj/structure/closet/crate/solar,/obj/effect/floor_decal/industrial/outline/yellow,/obj/random/loot,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fH" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/obj/structure/computerframe,/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fI" = (/obj/machinery/teleport/station,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fJ" = (/obj/machinery/teleport/hub,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"fK" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"fL" = (/turf/simulated/wall,/area/constructionsite/solar) +"fM" = (/obj/random/closet,/obj/random/material,/obj/random/contraband,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"fN" = (/turf/simulated/floor/airless,/area/constructionsite/solar) +"fO" = (/obj/structure/lattice,/turf/space,/area/constructionsite/solar) +"fP" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/solar) +"fQ" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/maintenance) +"fR" = (/obj/structure/extinguisher_cabinet{pixel_y = 30},/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"fS" = (/obj/random/junk,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"fT" = (/obj/effect/overmap/sector/derelict,/turf/simulated/floor/airless,/area/constructionsite/solar) +"fU" = (/turf/space,/area/constructionsite/solar) +"fV" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/solar) +"fW" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/solar) +"fX" = (/obj/structure/grille,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/fore) +"fY" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite/solar) +"fZ" = (/obj/structure/grille/broken,/turf/simulated/floor/airless,/area/constructionsite/solar) +"ga" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"gb" = (/obj/effect/shuttle_landmark/derelict/nav3,/turf/space,/area/space) +"gc" = (/obj/random/firstaid,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"gd" = (/obj/structure/lattice,/obj/random/maintenance,/turf/space,/area/constructionsite/solar) +"ge" = (/obj/structure/table/rack,/obj/random/plushie,/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"gf" = (/obj/machinery/door/airlock/highsecurity{icon_state = "door_closed"; locked = 0; name = "AI Upload Access"; req_access = list(16)},/turf/simulated/floor/bluegrid/airless,/area/constructionsite/hallway/fore) +"gg" = (/turf/simulated/wall,/area/constructionsite/ai) +"gh" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gi" = (/turf/simulated/floor/bluegrid/airless,/area/constructionsite/ai) +"gj" = (/turf/simulated/floor/airless,/area/space) +"gk" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/space) +"gl" = (/obj/random/trash,/turf/simulated/floor/airless,/area/space) +"gm" = (/obj/structure/sign/warning/lethal_turrets,/turf/simulated/wall,/area/constructionsite/ai) +"gn" = (/obj/machinery/door/airlock/highsecurity{icon_state = "door_closed"; locked = 0; name = "AI Upload"; req_access = list(16)},/turf/simulated/floor/bluegrid/airless,/area/constructionsite/ai) +"go" = (/obj/random/tool,/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"gp" = (/obj/machinery/porta_turret_construct,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gq" = (/obj/effect/decal/cleanable/blood/oil,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gr" = (/turf/simulated/floor/tiled/dark/airless,/area/space) +"gs" = (/obj/structure/table/rack,/obj/random/maintenance,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"gt" = (/obj/structure/table/rack,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"gu" = (/obj/random/loot,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gv" = (/obj/random/trash,/turf/simulated/floor/bluegrid/airless,/area/constructionsite/ai) +"gw" = (/obj/machinery/drone_fabricator/derelict,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gx" = (/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/obj/machinery/power/apc/high/inactive{dir = 1; name = "north bump"; pixel_y = 24},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gy" = (/obj/machinery/computer/drone_control,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gz" = (/obj/random/hostile,/turf/simulated/floor/airless,/area/space) +"gA" = (/obj/structure/lattice,/turf/space,/area/constructionsite/maintenance) +"gB" = (/obj/machinery/door/airlock/highsecurity{name = "Messaging Server"; req_access = list(30)},/turf/simulated/floor/airless,/area/constructionsite/hallway/fore) +"gC" = (/obj/machinery/door/airlock/highsecurity{name = "Messaging Server"; req_access = list(30)},/turf/simulated/floor/airless,/area/constructionsite/ai) +"gD" = (/obj/structure/showcase{desc = "A computer core for an artificial intelligence. It seems to be broken."; icon = 'icons/mob/AI.dmi'; icon_state = "4"; name = "Deactivated AI Core"},/turf/simulated/floor/bluegrid/airless,/area/constructionsite/ai) +"gE" = (/obj/machinery/door/airlock/highsecurity{name = "Cyborg Station"; req_access = list(16)},/turf/simulated/floor/bluegrid/airless,/area/constructionsite/ai) +"gF" = (/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/bluegrid/airless,/area/constructionsite/ai) +"gG" = (/obj/effect/decal/cleanable/blood/oil,/turf/simulated/floor/bluegrid/airless,/area/constructionsite/ai) +"gH" = (/obj/machinery/door/airlock/highsecurity{name = "Cyborg Station"; req_access = list(16)},/turf/simulated/floor/bluegrid/airless,/area/constructionsite/hallway/fore) +"gI" = (/obj/random/tool,/turf/simulated/floor/airless,/area/space) +"gJ" = (/obj/random/material,/turf/simulated/floor/airless,/area/space) +"gK" = (/obj/machinery/recharge_station,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gL" = (/obj/structure/lattice,/obj/structure/extinguisher_cabinet{icon_state = "extinguisher_empty"; pixel_x = -30},/turf/space,/area/constructionsite/hallway/fore) +"gM" = (/obj/machinery/porta_turret/stationary,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gN" = (/obj/random/junk,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/ai) +"gO" = (/turf/simulated/wall,/area/constructionsite/hallway/aft) +"gP" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/aft) +"gQ" = (/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"gR" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/aft) +"gS" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"gT" = (/obj/structure/lattice,/turf/space,/area/constructionsite/hallway/aft) +"gU" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"gV" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"gW" = (/obj/structure/grille/broken,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"gX" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"gY" = (/obj/machinery/door/airlock/maintenance_hatch,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"gZ" = (/obj/machinery/door/airlock/highsecurity{icon_state = "door_closed"; locked = 0; name = "AI Upload Access"; req_access = list(16)},/turf/simulated/floor/bluegrid/airless,/area/constructionsite/hallway/aft) +"ha" = (/obj/structure/table/rack,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"hb" = (/obj/effect/floor_decal/plaque{desc = "To commemorate the beginning of the Eternity Project, a station that will ferry us through the stars forever without fail."; name = "Eternity Project Dedication Plaque"},/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"hc" = (/obj/structure/lattice,/obj/random/material,/turf/space,/area/space) +"hd" = (/obj/structure/closet/firecloset{icon_state = "fireclosetopen"; opened = 1},/obj/random/plushie/large,/turf/simulated/floor/airless,/area/constructionsite/maintenance) +"he" = (/obj/random/trash,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/aft) +"hf" = (/obj/machinery/door/airlock/multi_tile/glass{name = "Emergency Entrance"},/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"hg" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/aft) +"hh" = (/obj/structure/grille/broken,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/hallway/aft) +"hi" = (/obj/effect/shuttle_landmark/derelict/nav4,/turf/space,/area/space) +"hj" = (/obj/structure/door_assembly,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"hk" = (/obj/effect/decal/mecha_wreckage/odysseus,/obj/machinery/mech_recharger,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hl" = (/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hm" = (/obj/structure/table/standard,/obj/random/firstaid,/obj/random/firstaid,/obj/effect/floor_decal/corner/green{dir = 4},/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hn" = (/turf/simulated/wall,/area/constructionsite/medical) +"ho" = (/obj/machinery/sleeper,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hp" = (/obj/structure/iv_drip,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hq" = (/obj/random/trash,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hr" = (/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"hs" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/atmospherics) +"ht" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/atmospherics) +"hu" = (/obj/machinery/light_construct{dir = 1},/turf/simulated/floor/airless,/area/constructionsite/medical) +"hv" = (/turf/simulated/floor/airless,/area/constructionsite/medical) +"hw" = (/obj/structure/table/standard,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hx" = (/obj/random/junk,/obj/effect/floor_decal/corner/green{dir = 9},/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hy" = (/obj/effect/floor_decal/corner/green,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hz" = (/obj/item/weapon/reagent_containers/ivbag,/obj/item/weapon/reagent_containers/ivbag,/obj/item/weapon/reagent_containers/ivbag/blood/OMinus,/obj/structure/closet/medical_wall{name = "Blood Closet"},/turf/simulated/wall,/area/constructionsite/hallway/aft) +"hA" = (/obj/structure/girder,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"hB" = (/obj/structure/table,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hC" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hD" = (/obj/machinery/door/airlock/glass_medical{name = "Medbay"; req_one_access = list(65,5)},/turf/simulated/floor/airless,/area/constructionsite/medical) +"hE" = (/obj/structure/door_assembly/door_assembly_med{name = "Medbay"},/turf/simulated/floor/airless,/area/constructionsite/medical) +"hF" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"hG" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"hH" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hI" = (/obj/structure/table/standard,/obj/random/firstaid,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hJ" = (/obj/structure/sign/directions/examroom,/turf/simulated/wall,/area/constructionsite/medical) +"hK" = (/obj/effect/floor_decal/corner/green{dir = 9},/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hL" = (/obj/machinery/disposal,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hM" = (/obj/structure/table,/obj/random/medical,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hN" = (/obj/structure/table,/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"hO" = (/obj/structure/fireaxecabinet{pixel_x = 32},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"hP" = (/turf/simulated/wall,/area/constructionsite/atmospherics) +"hQ" = (/obj/structure/girder,/turf/space,/area/constructionsite/hallway/aft) +"hR" = (/obj/item/roller,/obj/item/roller,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hS" = (/obj/structure/closet/medical_wall/filled{pixel_x = 32},/turf/simulated/floor/airless,/area/constructionsite/medical) +"hT" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"hU" = (/obj/structure/closet/firecloset/full,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"hV" = (/obj/machinery/atmospherics/pipe/simple/visible,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/atmospherics) +"hW" = (/obj/structure/lattice,/turf/space,/area/constructionsite/medical) +"hX" = (/obj/random/medical/lite,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hY" = (/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/medical) +"hZ" = (/obj/item/roller,/turf/simulated/floor/airless,/area/constructionsite/medical) +"ia" = (/obj/random/closet,/turf/simulated/floor/airless,/area/constructionsite/medical) +"ib" = (/turf/space,/area/constructionsite/medical) +"ic" = (/obj/effect/decal/mecha_wreckage/ripley/firefighter,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"id" = (/obj/structure/closet/secure_closet/atmos_personal{icon_state = "secureatmbroken"; locked = 0},/obj/random/voidsuit,/obj/random/voidhelmet,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"ie" = (/obj/machinery/atmospherics/pipe/simple/visible,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"if" = (/obj/structure/iv_drip,/turf/simulated/floor/airless,/area/constructionsite/medical) +"ig" = (/obj/random/snack,/turf/simulated/floor/airless,/area/constructionsite/medical) +"ih" = (/obj/structure/lattice,/obj/random/junk,/turf/space,/area/constructionsite/medical) +"ii" = (/obj/machinery/door/airlock/glass_medical{name = "Medbay Storage"; req_one_access = list(65,5)},/turf/simulated/wall,/area/constructionsite/hallway/aft) +"ij" = (/obj/machinery/door/airlock/glass_atmos{name = "Atmospherics"; req_access = list(24)},/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"ik" = (/obj/random/firstaid,/turf/simulated/floor/airless,/area/constructionsite/medical) +"il" = (/obj/item/weapon/storage/box/freezer,/turf/simulated/floor/airless,/area/constructionsite/medical) +"im" = (/obj/random/closet,/obj/random/masks,/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"in" = (/obj/random/tool,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/atmospherics) +"io" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/medical) +"ip" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/airless,/area/constructionsite/medical) +"iq" = (/obj/random/ammo,/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"ir" = (/obj/structure/lattice,/obj/random/medical/lite,/turf/space,/area/constructionsite/medical) +"is" = (/obj/structure/girder/reinforced,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"it" = (/obj/effect/shuttle_landmark/derelict/nav5,/turf/space,/area/space) +"iu" = (/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"iv" = (/turf/space,/area/constructionsite/hallway/aft) +"iw" = (/obj/structure/lattice,/obj/item/roller,/turf/space,/area/constructionsite/medical) +"ix" = (/obj/structure/closet/firecloset{icon_state = "fireclosetopen"; opened = 1},/obj/random/junk,/obj/random/masks,/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"iy" = (/obj/machinery/computer/general_air_control/large_tank_control{frequency = 1443; input_tag = "d_air_in"; name = "Mixed Air Supply Control"; output_tag = "d_air_out"; pressure_setting = 2000; sensors = list("d_air_sensor" = "Tank")},/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"iz" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/machinery/door/firedoor/border_only,/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor/plating,/area/constructionsite/atmospherics) +"iA" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; external_pressure_bound = 0; external_pressure_bound_default = 0; frequency = 1443; icon_state = "map_vent_in"; id_tag = "d_air_out"; internal_pressure_bound = 2000; internal_pressure_bound_default = 2000; use_power = 1; pressure_checks = 2; pressure_checks_default = 2; pump_direction = 0},/turf/simulated/floor/reinforced/airmix,/area/constructionsite/atmospherics) +"iB" = (/obj/machinery/light/small{dir = 1},/obj/machinery/air_sensor{frequency = 1443; id_tag = "d_air_sensor"; output = 7},/turf/simulated/floor/reinforced/airmix,/area/constructionsite/atmospherics) +"iC" = (/obj/structure/girder/reinforced,/turf/space,/area/constructionsite/medical) +"iD" = (/obj/structure/lattice,/obj/structure/sign/warning/nosmoking_1,/turf/simulated/wall,/area/constructionsite/medical) +"iE" = (/obj/structure/sign/bluecross_2,/turf/simulated/wall,/area/constructionsite/hallway/aft) +"iF" = (/obj/structure/sign/warning/compressed_gas,/turf/simulated/wall,/area/constructionsite/hallway/aft) +"iG" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4; icon_state = "intact"},/turf/simulated/wall,/area/constructionsite/atmospherics) +"iH" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 8; frequency = 1443; icon_state = "map_injector"; id = "d_air_in"; use_power = 1},/turf/simulated/floor/reinforced/airmix,/area/constructionsite/atmospherics) +"iI" = (/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor/reinforced/airmix,/area/constructionsite/atmospherics) +"iJ" = (/obj/machinery/door/airlock/glass_medical{name = "Medbay"; req_one_access = list(65,5)},/turf/simulated/floor/airless,/area/constructionsite/hallway/aft) +"iK" = (/obj/effect/floor_decal/industrial/warning/dust{icon_state = "warning_dust"; dir = 8},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/atmospherics) +"iL" = (/obj/structure/girder,/turf/simulated/floor/airless,/area/constructionsite/medical) +"iM" = (/obj/effect/floor_decal/plaque{desc = "In memory of Earl Whitenmeinster. We'll never forget you."; icon_state = "plaque"; name = "Whitenmeister Memorial Hall Plaque"},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/aft) +"iN" = (/obj/effect/floor_decal/industrial/warning/dust{icon_state = "warning_dust"; dir = 8},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"iO" = (/obj/machinery/computer/general_air_control/large_tank_control{frequency = 1441; input_tag = "d_o2_in"; name = "Oxygen Supply Control"; output_tag = "d_o2_out"; sensors = list("d_o2_sensor" = "Tank")},/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"iP" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 8; external_pressure_bound = 0; external_pressure_bound_default = 0; frequency = 1441; icon_state = "map_vent_in"; id_tag = "d_o2_out"; initialize_directions = 1; internal_pressure_bound = 4000; internal_pressure_bound_default = 4000; use_power = 1; pressure_checks = 2; pressure_checks_default = 2; pump_direction = 0},/turf/simulated/floor/reinforced/oxygen,/area/constructionsite/atmospherics) +"iQ" = (/obj/machinery/light/small{dir = 1},/obj/machinery/air_sensor{frequency = 1441; id_tag = "d_o2_sensor"},/turf/simulated/floor/reinforced/oxygen,/area/constructionsite/atmospherics) +"iR" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/medical) +"iS" = (/obj/random/material,/turf/simulated/floor/airless,/area/constructionsite/medical) +"iT" = (/obj/effect/floor_decal/corner/green{dir = 10},/turf/simulated/floor/tiled/white/airless,/area/constructionsite/medical) +"iU" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 8; frequency = 1441; icon_state = "map_injector"; id = "d_o2_in"; use_power = 1},/turf/simulated/floor/reinforced/oxygen,/area/constructionsite/atmospherics) +"iV" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/reinforced/oxygen,/area/constructionsite/atmospherics) +"iW" = (/obj/structure/lattice,/obj/structure/girder,/turf/space,/area/constructionsite/medical) +"iX" = (/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/atmospherics) +"iY" = (/turf/simulated/wall,/area/constructionsite) +"iZ" = (/obj/structure/grille/broken,/turf/simulated/floor/airless,/area/constructionsite) +"ja" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite) +"jb" = (/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"jc" = (/obj/machinery/computer/general_air_control/large_tank_control{frequency = 1441; input_tag = "d_n2_in"; name = "Nitrogen Supply Control"; output_tag = "d_n2_out"; sensors = list("d_n2_sensor" = "Tank")},/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"jd" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 8; external_pressure_bound = 0; external_pressure_bound_default = 0; frequency = 1441; icon_state = "map_vent_in"; id_tag = "d_n2_out"; initialize_directions = 1; internal_pressure_bound = 4000; internal_pressure_bound_default = 4000; use_power = 1; pressure_checks = 2; pressure_checks_default = 2; pump_direction = 0},/turf/simulated/floor/reinforced/nitrogen,/area/constructionsite/atmospherics) +"je" = (/obj/machinery/light/small{dir = 1},/obj/machinery/air_sensor{frequency = 1441; id_tag = "d_n2_sensor"},/turf/simulated/floor/reinforced/nitrogen,/area/constructionsite/atmospherics) +"jf" = (/obj/random/smokes,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jg" = (/obj/structure/lattice,/turf/space,/area/constructionsite) +"jh" = (/obj/structure/table/standard,/obj/structure/bedsheetbin,/turf/simulated/floor/airless,/area/constructionsite) +"ji" = (/obj/structure/table,/turf/simulated/floor/airless,/area/constructionsite) +"jj" = (/obj/structure/table/standard,/obj/random/hat,/obj/random/gloves,/turf/simulated/floor/airless,/area/constructionsite) +"jk" = (/obj/structure/table/standard,/obj/random/gloves,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jl" = (/obj/structure/table/standard,/obj/random/maintenance,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jm" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless,/area/constructionsite) +"jn" = (/obj/structure/table/standard,/turf/simulated/floor/airless,/area/constructionsite/medical) +"jo" = (/obj/structure/table/standard,/obj/structure/closet/body_bag/cryobag,/obj/structure/closet/body_bag/cryobag,/turf/simulated/floor/airless,/area/constructionsite/medical) +"jp" = (/obj/structure/cable/blue,/obj/machinery/power/apc/high/inactive{dir = 2; name = "south bump"; pixel_y = -24},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"jq" = (/obj/machinery/atmospherics/pipe/simple/visible{icon_state = "intact"; dir = 5},/turf/simulated/floor/airless,/area/constructionsite/atmospherics) +"jr" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 8; frequency = 1441; icon_state = "map_injector"; id = "d_n2_in"; use_power = 1},/turf/simulated/floor/reinforced/nitrogen,/area/constructionsite/atmospherics) +"js" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/reinforced/nitrogen,/area/constructionsite/atmospherics) +"jt" = (/obj/structure/grille/broken,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite) +"ju" = (/turf/simulated/floor/airless,/area/constructionsite) +"jv" = (/obj/structure/door_assembly,/turf/simulated/floor/airless,/area/constructionsite) +"jw" = (/turf/space,/area/constructionsite) +"jx" = (/obj/structure/lattice,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jy" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jz" = (/obj/structure/girder,/turf/simulated/floor/airless,/area/constructionsite) +"jA" = (/obj/structure/lattice,/turf/simulated/wall,/area/constructionsite) +"jB" = (/obj/random/clothing,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jC" = (/obj/structure/coatrack,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jD" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite) +"jE" = (/obj/structure/closet{icon_closed = "cabinet_closed"; icon_opened = "cabinet_open"; icon_state = "cabinet_closed"; name = "Wardrobe"},/turf/simulated/floor/airless,/area/constructionsite) +"jF" = (/obj/structure/bed,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jG" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite) +"jH" = (/obj/structure/lattice,/obj/random/junk,/turf/space,/area/constructionsite) +"jI" = (/obj/machinery/door/airlock{name = "Cabin"},/turf/simulated/floor/airless,/area/constructionsite) +"jJ" = (/obj/random/hat,/turf/simulated/floor/airless,/area/constructionsite) +"jK" = (/obj/random/tool,/turf/simulated/floor/airless,/area/constructionsite) +"jL" = (/obj/random/snack,/turf/simulated/floor/airless,/area/constructionsite) +"jM" = (/obj/machinery/door/airlock{name = "Bunk Room"},/turf/simulated/floor/airless,/area/constructionsite) +"jN" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite) +"jO" = (/obj/item/weapon/bedsheet,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jP" = (/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite) +"jQ" = (/obj/structure/extinguisher_cabinet{icon_state = "extinguisher_empty"; pixel_x = 30},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/aft) +"jR" = (/obj/random/trash,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jS" = (/obj/random/maintenance/clean,/turf/simulated/floor/airless,/area/constructionsite) +"jT" = (/obj/machinery/washing_machine,/turf/simulated/floor/airless,/area/constructionsite) +"jU" = (/obj/structure/table,/obj/random/clothing,/turf/simulated/floor/airless,/area/constructionsite) +"jV" = (/obj/structure/grille,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite) +"jW" = (/obj/random/clothing,/turf/simulated/floor/airless,/area/constructionsite) +"jX" = (/obj/structure/grille,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"jY" = (/obj/item/clothing/head/radiation,/turf/simulated/floor/airless,/area/constructionsite) +"jZ" = (/obj/machinery/constructable_frame,/obj/random/material,/turf/simulated/floor/airless,/area/constructionsite) +"ka" = (/obj/machinery/door/airlock/glass_engineering,/turf/simulated/floor/airless,/area/constructionsite) +"kb" = (/obj/random/obstruction,/turf/simulated/floor/airless,/area/constructionsite) +"kc" = (/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite) +"kd" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite) +"ke" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite) +"kf" = (/obj/random/action_figure,/turf/simulated/floor/airless,/area/constructionsite) +"kg" = (/obj/random/voidhelmet,/turf/simulated/floor/airless,/area/constructionsite) +"kh" = (/obj/structure/table/standard,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"ki" = (/obj/random/hostile,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"kj" = (/obj/random/hostile,/turf/simulated/floor/airless,/area/constructionsite) +"kk" = (/obj/structure/table,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite) +"kl" = (/obj/structure/table/standard,/obj/machinery/cell_charger,/obj/random/powercell,/turf/simulated/floor/airless,/area/constructionsite) +"km" = (/obj/machinery/power/terminal{dir = 4},/turf/simulated/floor/airless,/area/constructionsite) +"kn" = (/obj/machinery/power/smes/buildable,/turf/simulated/floor/airless,/area/constructionsite) +"ko" = (/obj/structure/table/rack,/obj/random/tool,/obj/random/tool,/turf/simulated/floor/airless,/area/constructionsite) +"kp" = (/obj/structure/table/rack,/turf/simulated/floor/airless,/area/constructionsite) +"kq" = (/obj/random/glasses,/turf/simulated/floor/airless,/area/constructionsite) +"kr" = (/obj/machinery/power/shield_generator{desc = "A heavy-duty shield generator and capacitor, capable of generating energy shields at large distances. This one seems to be in a state of disrepair."; name = "disused shield generator"},/turf/simulated/floor/airless,/area/constructionsite) +"ks" = (/obj/random/junk,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"kt" = (/obj/machinery/power/breakerbox,/turf/simulated/floor/airless,/area/constructionsite) +"ku" = (/obj/structure/table/rack,/obj/random/toolbox,/obj/random/loot,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"kv" = (/obj/structure/girder/displaced,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite) +"kw" = (/obj/random/closet,/obj/random/loot,/obj/random/junk,/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite) +"kx" = (/obj/machinery/door/airlock/maintenance_hatch,/turf/simulated/floor/airless,/area/constructionsite) +"ky" = (/obj/structure/closet/radiation,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/hallway/aft) +"kz" = (/turf/simulated/wall,/area/constructionsite/engineering) +"kA" = (/obj/machinery/door/airlock/glass_engineering{name = "Engine Access"; req_access = list(11)},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kB" = (/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kC" = (/obj/effect/shuttle_landmark/derelict/nav6,/turf/space,/area/space) +"kD" = (/obj/machinery/door/airlock/maintenance_hatch,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kE" = (/obj/structure/lattice,/turf/space,/area/constructionsite/engineering) +"kF" = (/obj/random/junk,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kG" = (/obj/machinery/door/airlock/glass_engineering,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kH" = (/obj/structure/sign/warning/compressed_gas,/turf/simulated/wall,/area/constructionsite/engineering) +"kI" = (/obj/machinery/portable_atmospherics/canister/empty/phoron,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kJ" = (/turf/space,/area/constructionsite/engineering) +"kK" = (/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"kL" = (/obj/structure/table/standard,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"kM" = (/obj/structure/sign/warning/radioactive,/turf/simulated/wall,/area/constructionsite/engineering) +"kN" = (/obj/structure/table/standard,/obj/random/tool,/obj/random/maintenance,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kO" = (/obj/structure/table,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kP" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kQ" = (/obj/random/maintenance,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/engineering) +"kR" = (/obj/structure/grille/broken,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kS" = (/obj/structure/table/standard,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kT" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kU" = (/obj/structure/table/standard,/obj/random/material,/obj/random/material,/obj/random/material,/obj/random/material,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kV" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/constructionsite/engineering) +"kW" = (/obj/structure/table/standard,/obj/random/toolbox,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kX" = (/obj/structure/table/standard,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"kY" = (/obj/structure/grille/broken,/turf/space,/area/constructionsite/engineering) +"kZ" = (/obj/structure/table/rack,/obj/random/loot,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"la" = (/obj/structure/grille,/turf/space,/area/constructionsite/engineering) +"lb" = (/obj/random/hostile,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lc" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"ld" = (/obj/machinery/portable_atmospherics/canister/nitrogen/engine_setup,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"le" = (/obj/machinery/power/rad_collector,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lf" = (/obj/structure/table/standard,/obj/random/tool,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lg" = (/obj/random/tool,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lh" = (/obj/random/maintenance,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"li" = (/obj/structure/table/standard,/obj/random/tool,/obj/random/voidsuit,/obj/random/coin,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lj" = (/obj/structure/table/standard,/obj/random/toolbox,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lk" = (/obj/random/trash,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"ll" = (/obj/structure/closet/radiation,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"lm" = (/obj/machinery/portable_atmospherics/canister/phoron/engine_setup,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"ln" = (/obj/random/maintenance,/turf/space,/area/space) +"lo" = (/obj/machinery/door/airlock/glass_engineering{name = "SMES"; req_access = list(11)},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lp" = (/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lq" = (/obj/structure/girder,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lr" = (/obj/structure/table/rack,/obj/random/tool,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"ls" = (/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"lt" = (/obj/structure/table/rack,/obj/random/toolbox,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lu" = (/turf/simulated/wall/r_wall,/area/AIsattele) +"lv" = (/obj/machinery/power/smes/buildable,/obj/structure/cable/blue,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lw" = (/obj/machinery/power/terminal{dir = 8},/obj/structure/cable/blue{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"lx" = (/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"ly" = (/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/blue{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lz" = (/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"lA" = (/obj/machinery/power/terminal{dir = 4},/obj/structure/cable/blue{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lB" = (/obj/structure/table/rack,/obj/random/maintenance,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lC" = (/obj/structure/computerframe,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/airless,/area/AIsattele) +"lD" = (/obj/machinery/teleport/station,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/airless,/area/AIsattele) +"lE" = (/obj/machinery/teleport/hub,/turf/simulated/floor/airless,/area/AIsattele) +"lF" = (/obj/machinery/power/smes/buildable,/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lG" = (/obj/machinery/power/terminal{dir = 8},/obj/structure/cable/blue{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lH" = (/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/blue{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lI" = (/obj/item/weapon/material/shard{icon_state = "medium"},/turf/simulated/floor/airless,/area/AIsattele) +"lJ" = (/turf/simulated/floor/airless,/area/AIsattele) +"lK" = (/obj/structure/cable,/turf/simulated/floor/airless,/area/AIsattele) +"lL" = (/obj/structure/table/rack,/obj/item/clothing/gloves/insulated,/turf/simulated/floor/airless,/area/AIsattele) +"lM" = (/obj/structure/table/rack,/obj/random/maintenance,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"lN" = (/obj/structure/cable/blue,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"lO" = (/obj/structure/girder,/turf/simulated/floor/airless,/area/AIsattele) +"lP" = (/obj/item/weapon/cell,/turf/simulated/floor/airless,/area/AIsattele) +"lQ" = (/obj/structure/grille/broken,/turf/simulated/floor/airless,/area/AIsattele) +"lR" = (/turf/space,/area/AIsattele) +"lS" = (/obj/structure/table,/obj/random/loot,/turf/simulated/floor/airless,/area/AIsattele) +"lT" = (/obj/random/hostile,/turf/simulated/floor/tiled/dark/airless,/area/constructionsite/engineering) +"lU" = (/obj/structure/lattice,/turf/space,/area/AIsattele) +"lV" = (/obj/structure/closet,/obj/random/maintenance,/turf/simulated/floor/airless,/area/AIsattele) +"lW" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/airless,/area/AIsattele) +"lX" = (/obj/structure/grille/broken,/turf/space,/area/AIsattele) +"lY" = (/obj/item/weapon/storage/toolbox/electrical{pixel_x = 1; pixel_y = -1},/turf/simulated/floor/airless,/area/AIsattele) +"lZ" = (/obj/machinery/power/emitter{anchored = 1; dir = 4; state = 2},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"ma" = (/obj/machinery/field_generator,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"mb" = (/obj/machinery/power/emitter{anchored = 1; dir = 8; state = 2},/turf/simulated/floor/airless,/area/constructionsite/engineering) +"mc" = (/obj/machinery/the_singularitygen,/turf/simulated/floor/airless,/area/constructionsite/engineering) +"md" = (/obj/effect/shuttle_landmark/derelict/nav7,/turf/space,/area/space) +"nb" = (/obj/structure/table/reinforced,/obj/item/stack/material/glass{amount = 50},/obj/item/stack/material/glass{amount = 50},/obj/item/stack/material/glass{amount = 50},/obj/item/stack/material/glass{amount = 50},/obj/item/stack/material/glass{amount = 50},/obj/random/tech_supply,/obj/random/maintenance,/obj/machinery/camera/motion{c_tag = "Construction Site Teleporter"},/turf/simulated/floor/tiled/dark,/area/constructionsite/teleporter) +"ob" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{frequency = 1379; id_tag = "constructionsite_vent"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 5},/obj/machinery/camera/motion{c_tag = "Construction Site Teleporter Airlock"},/turf/simulated/floor,/area/constructionsite/teleporter) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadaeafababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababagagahagagabababaiajajakababalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababamaganagagagagaoagababababapabaqaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababagagagagasagagagagabatabakajaqaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababagauabababavawaxababayababatabazajaqaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabagagaAagaBabaCagaDagagagagagaEaFaGaHabaIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaJagagagaKabagagagagagagagagaLababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaMagagagagaNabagagabaOabababagaPabaQagabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaaaaaaaaaaaRaaaaaaaRaaaaaRaaaaaRaaaaaaaRaaaaaaaaaaaaaaaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaSagagagagagabaJagabagaTagabagaUabaVagagagababaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWaWaRaRaWaWaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaWaWaaaaaWaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaSaXaYagagagaZagagabbabbbcabagaLbdagaganagagabababagbeagagbfagagbgbgabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWaWbhbhaWaWaaaRaaaaaaaRaaaaaRaaaaaRaaaaaaaRaaaWaWbhbiaWaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaSbjbkagagagblagagabagagagabagakbmagagagagagaOagaOagagagagaganagagagaOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRbhbnbobobobiaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRbhbobpbobqbiaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaSaKbragagagaZagagabagbsagabajaLbdagagagagagabababagagagagagagagbtagabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRbibobpbubobhaaaRbvbwbxbvaaaaaRaaaabvbybzbvaRaabobubobobobiaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaSagagagagagabaJagabababaOabagaUabaJagagagababaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRbibobobobAbiaaaRbzbBbCbvbvaRaRaRbvbvbDbEbwaRaabibFbGbHbobiaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabIagagagagbJabagagagagagagagajaLabagbgabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRbibobFbHbobiaaaRbwbDbKbLbvbzbwbybvbLbKbMbyaRaabobobobobobhaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaJagagagagabababababagajajajakababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRbhbNbobobubiaaaRbwbObLbKbLbPbDbQbRbKbSbLbyaRaabibpbobobubiaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabagbTbTagagabbUbVbWababbXbYbZcaaFcbccabalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWaWaWaWaWcdceaWaWaWaWbvbLbLbKbLbLbLbLbLbKbLcfbvaWaWaWaWceaWaWaWaWaWaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababauauabababagagagagabagcgajchabazajaqaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWaWbubobobobobobpbobubocibLbOcjbLbLbLbKbLckbLbLclbobobobobobobubobocmaWaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacnabababagagagagagagcoagcpcqcrabakajaqaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWboboboboaWaWaWcdaWaWaWbvbvbLbLbLcscscsctbLbLbvbvaWaWaWaWaWaWaWboboboboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababagagagagagagagababababababapabaqaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWbubocuaWaWcvcwcxcyczcwcAbvcBbRbKctbKbKbKcCbvbvcDcEcFcGcHcIcGaWaWbobuboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacnababagagcJcKagabcLajajajajakababaIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWboboaWaWcwcMcwcAcNcOcPcQcwbvbvbLbLbLbKcRbvbvcScPcwcGcwcycwcycGaWaWbobHaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababcTcUcUcUcUcVcWababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWboaWaWcXcwcAcwcAcwcxcwcAcNcYbvbvcZcZcZbvbvdacGcGcwdbdcdddbcGcPdeaWaWboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWbucddfcwcwcAcydgdhcAcwczcwcNdidjcNcwcwdjdkcwcwcycNdldmdndddocGcGdmaWbpaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWboaWdpcycPcycwcNcNcwcwcwcwcwdqdjcNcNcydjdbcGcwcGcGcwcwcwcGcGdrcNcGaWboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaWbocecwcwcwcwdscwdtddducwcwdhcwdvcwcwdwdjdxcPcNcwcwcycGcGcGcPcydycNcebuaWaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaaaaaaaRdzdzdzdzdAdzdzdzdBdzdjdvdCdDdEdzdBdzdzdFdGdHdGdFdzdzdIdzdJdKdKdLdMdzdNdzdzaWceaWdzdzdzaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRdOaRaRaRaaaaaRdPcwcNcycwcwcNcwcwcwcwcwcNcNcwcwcwcNcNcwcNcNcNcwcycwcycNcNdycwcNcNcNcNcwcwbobobHcNcNdvaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadOaRaRaaaaaaaRdvcNcNcNcwcNcycNcycNcNcNcwdQcNcydRcNcNcNcNcwcwcwcNcNcNcNcNcwcNcNcwcydScwcwdTcycNdocydUaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRdOaRdVaRaaaaaRdvcwcycNcNcNcwcwcycycNcNcNcwcNcwcNdRcwcycycwcNcNcNcwcNcwcNcNcNcycNcwcNcwcycNcNcNcwcwdPaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadOaRaRaaaaaaaRdvcNcwcwcwdzdzdzdzdAdzdzdzdzdzdzdzdzdzdzcwcNcwdzdzdzdzdzdzdzdzdzdzdAdzdzdzdzcwcNcNdWdvaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaaaaaRdzdzcNcwdzdzbobobobobubobobobobobobobodzcNcycNdzbobobobHbobobobobobobobobodzdzcwcNdzdzaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaaaaaRaRaRdvcwcNdzbobodYdYdYdYdYdYdYdZdYdYbobodzcNcNeadzboboebebebebebebebebebebbHbodzcNcNdvaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRdOaRaRaRaaaaaaaRdvcNcNdzbodYdYecedeeefegeheheidYbobudzcwcNcNdzboboebejekelemennbepeqebebbodzcNcwdPaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaaaaaaaaaRdPcNcwdzbodYereseheteheheheseudYboevdzcwcNcwdzbobHebewexeyezeAeAeAeBeCebbodzcwcNdvaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRdOaRaRaRaaaRaRaRdvcNcydzbodYeDeDeDeDeEeDeFeDeDdYdYdYeGcycweHebebebebeIeJeJeJeJeJeJeAeKebbodzcwcwdvaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadOaRaRdOaaaaaaaRdPcwcNdzbodYeLeheheMeheNeheheOePeheheQcwcwcweReSobeUeVeJeJeJeJeJeJeJeWebbodzcycNdPaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRdOaRaRaRaaaaaaaRdvcNcNdzbueXeheheYehehehehehehePeheseZcNcNcNeRfafbfcfdfefffgeJeJeJeJfhebbodzcNcNdvaRaaaaaaaaaaaaaaaaaafiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadOaRaRaaaaaRaRaRdPcwcNdzbodYfjfkfjeDflfjfmeFeDdYdYdYeGcNcycwebebebebfnfoeJfpfqfqfqfrfsebbodzcwcwdvaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRaRdOaRaRdOaaaaaaaRdPcycNdzbodYehehehehehehesftehdYbobodAcwcNcwdAboboebfufveAeAeAeAeAeAfwebbodzcwcydPaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRdOaRaRdOaaaaaaaRdPcNcwdzbodYdYfxeNfyfzfAehehfBdYbudzdzcwcNdRdzdzbHebfCfDfEfFfGfHfIfJebebbodzcNcNdPaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRaadOaRaRdOaaaRaRaRdvcNcwdzbobpdYdYdYdYdYdYdYdYdYdYbodzdWcwcNcNcwdzboebebebebebebebebebebbobodzcNcNdvaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRdOaRaRdOaaaWaWdzdzcNcNdzdzbobobobobobobobubobobobodzcwcNcNcNcNdzbobobobobobofKbobobobobHdzdzcNcPdzdzaWaWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRfLfLfLfLfLaWaWbodzcwdRcNcwdzdzdzdzdzdzdzdzdzdzdzdzdzdzcwcNcwcycwdzdzdzdzdzdzdzdRdzdzdzdzdzdzfMcNdmcwdzbHaWaWfLfLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRfNfNfNfNfOfNfNaRaRaRaRaRfLfPfNfPfPbofQbocNcwdRdRcNcwcwcNcNcwcwfRcycNcwcwcNcwcwcNcwcycNfScNcNcNcwcycNcNcwcwcNcwcwcNcwcwcycNcwdzboboaWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfLfPfNfTfNbHbobocwcwcycwcwcNcwcNcNcwcycNcwcNcNdmcNcwcNcNcNcNcwcycNcNcycNcNcNcNcwcwcNcwcycNcNcNdocwcwdzboboaWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafUfNfOfOfOfNfOfOfOfNfOfNfOfNfOfNfNfPfNfPfVfLfNfWfPfPaWbubodzcNcNcNcwdzdvdPdvdvdPdPfXdvdPdvdvdzdzdzcycNcNdzdzdzfXdPdPdvdPdvdvdvdPdPdvdzcwcwdRcydzbobHaWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRfOfOfOfOfNfNfNfPfPfNfNfNfNfVfNfNfPfNfNfNfNfLfVfNfPfNaWfQfQdzdzcwcwdzdzaRaRaRaRaRaRaRaRaRaRaRaWbodAcNcPcNdAboaWaRaRaRaRaRaRaaaRaRaaaRdzdzcNcwdzdzboboaWfNfOfNfOfUfUfUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafUfUfUfUfOfOfOfLfOfOfOfLfLfLfOfOfLfLfLfLfLfLfNfVfPfPaWbobobodzcwcwdvaRaaaRaaaRaaaRaWaWaWaWaWaWbodzcwcNcNdzboaWaWaWaWaWaWaRaaaRaaaRaaaRdvcwcNdzbobHboaWfNfVfNfNfOfNfOaRaRaRaRaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRfLfYfZfZfYaWaWaWbodzdRcwdjaRaaaRaaaRaaaRaWbobobobobobodzcNcNcwdzbobobogabobpaWaRaaaRaaaRaaaRdjcNcydzboaWaWaWfLfLfLfLfNfNfNaaaRaaaRaaaRaaaaaaaaaaaaaaaaaaaaaagbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRaRaRaRaRaRaWbodzcwcNdjaRaRaRaRaRaRaRaWbobobogcdzdzdzcwcwcNdzdzdzbobnbuboaWaRaRaRaRaRaRaRdvcwcwdzboaWfNfNfNfNfNfNfNfNfNfVfNgdfNfOfOfOaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRaWbodzcwcydjaRaaaRaaaRaaaRaWbodzdzdzdzcNcwcycwcwcNcwdzdzdzdzboaWaRaaaRaaaRaaaRdPcNcNdzbHaWfNfNfNfVfNfNfNfNfNfNfNfNfNfNfNfNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaWfQdzcNcwdjaRaaaRaaaRaRaRdzdAdzcwcwcNcwcycwcwcNcNcycwcycwdzdAdzaRaRaRaaaRaaaRdjcNcwdzboaWfOfNfOfNfOfNfOfNfOfOfNfNfVfOfOfOaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRaWbodzcwcNdjaRaRaRaRaRaRdzdzcwcwcwcydmcNcwcNcNcyfScNcNcNcwcNcwdzdzaRaRaRaRaRaRdPcNcNdzboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaWbodzcycwdvaRaWaWaWaWdzdzcwcwcNcycwcwcwcNcwcwcwcycwcNcNcNcNcNcwdzdzaWaWaWaWaRdvcwcwdzboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRaWbodzcNcNdvaRaWgebobodAcwcNcNcycycwcwdjdzdzgfdzdzdjcwcycwcNcNcwcNdAboboboaWaRdvcNcydzboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaWfQdzcycwdPaRaWbobodzdzcwcNcwcNcwdjdjdjggghgighggdjdvdPcwcNcycwcPdzdzboboaWaRdjcydRdzboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRaWbodzcwcydvaRaWbHbodzcwcNcycycwdjdjaRaRggghgighggaRaRdPdjcNcNcNcwcwdzboboaWaRdvcwcNdzboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaRgjaRgjgjaRaRgjaRaRgjaWbodzcNdRdPaRaWbobndzcNcNdmcwdPdjaRaRaRggghgighggaRaRaRdjdjcwcNcNcwdzbobHaWaRdPcNcNdzboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRgjaRaRgjgjgkgjgjgjgjgjgjgjglaWbodzcwcwdzaWaWbodzdzcydmcNcNdvaRaRaRgggggmgngmggggaRaRaRdjdjgocwcwdzdzgaaWaWdzcwcwdzbHaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgjgjgjgjgjgjgjgjgjgjgjgjgjgjgjgjgkgjaWfQdzcwcNdzbobHbodzcycycNcwdjdjaRaRgggggigighgigiggggaRaRdzdzcwcNcNcwdzbobobodzcPcNdzboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRdOaRaRaRaRaRdOdOdOdOdOaRgjaRgjaRgjaRgkaRgjaWaWaWaWaWaWaWaWaWaWaWbodzcNcwdzdAdzdzdzcwcwcwcwdzgggggggggpgighghgqgigpggggggggdzcNcycNcwdzdzdzdAdzcwcNdzaWaWdOdOdOaRaRaRaRaRaRaaaRaRaRaRaRaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagjaRgjgjgjgjgjgkgjgjgjgjgjgrgjbobobubofQfQbogsgtbofQbocycNcNcwcwcNcwcwcwcwdmcwdzghgughgmgigighgvghgigigmgwgxgydzcNcwcwcwcwcwcwcNcwcycwcwbofQgjgrgjgjgjgjgjgjgjgrgjgkaaaaaRaaaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRgjgzgjgkgjaRaRgjgjaRgjaRgjaRgjaRgjaRgjgAbogAbobobHbobobobobobpcwcwcwcwcNcwcNdocNcNcycwgBgigigigCghghghgDghghghgEgigFgGgHcwcwcNcwcwcNcwcNcNcNcwcNfQbogIgjgrgjgrgrgjgkgjaRgjaRgjaRgjgjgjaRgJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRgjgjgjgkgjgjgjaRgjaRgjgjgjgkgjbobobogAbobofQbobHbobobocNcwcwcwcwcNcwcwcwcwcycwdzghghghgmgigighgighgGgigmgKgKgKdzcwcNcwcycwcwcNcwcwcwcNcNbofQgraRgkgjgjgjgjgrgjgjgjgjgjgrgjgkaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadOdOdOaRaRaRaRaRdOdOdOdOdOdOdOdOdOdOdOaWaWaWaWaWaWaWaWaWaWaWaWdzcwcNdzdAdzdzdzgLcNdRcwdzgggggggggMgighghgNgigpggggggggdzcNcwcweadzdzdzdAdzcNcNdzaWaWdOdOdOdOdOaRaRaRaRaRaRaRaRaRaRaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaWgAgOgPgQgObobHbogOgQgQgRgQgSgSaRaRgggggGgighgigvggggaRaRgSgSgQgRgRgQgObobobogOgRgQgQgtaWaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaRaRaWgAgOgRgRgOaWaWbogOgOgQgTgQgTgSaRaRaRgggggmgngmggggaRaRaRgSgQgPgRgRgOgObHaWaWgOgPgRgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaRaRaWgAgOgQgUgVaRaWbobogOgQgQgQgQgSgSaRaRaRggghgighggaRaRaRgVgSgRgRgQgQgOboboaWaRgVgUgQgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaWgAgOgQgPgWaRaWbobogOgRgTgRgTgQgSgSaRaRggghgighggaRaRgSgSgQgRgQgRgQgOboboaWaRgWgRgQgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaRaRaWgAgOgRgRgVaRaWbobogOgOgQgXgPgQgRgSgSgSggghgighgggSgSgSgQgRgPgQgQgOgOboboaWaRgWgQgQgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaRaRaWgAgOgRgRgSaRaWbobHbogYgTgPgTgQgTgQgQgSgOgOgZgOgOgShagQgQgRgQgRgQgYbobHgtaWaRgVgQgRgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaWgAgOgXgQgVaRaWaWaWaWgOgOgQgQgRgQgQgPgQgQgQgQgRgRgQgQgQgRgRgRgQgOgOaWaWaWaWaRgVgQgRgObpaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaRaRaWgAgOgQgRgVaRaRaRaRaRaRgOgOgTgQgTgQgRgRgRgQhbgQgRgQgRgRgQgQgXgOgOaRaRaRaRaRaRgWgRgRgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaRaRaWgAgOgPgQgWaRaaaRaaaRaRaRgOgYgOgQgRgRgRgRgRgRgQgRgRgQgRgQgOgYgOaRaRaRaaaRaaaRgVgRgPgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaWgAgOgQgPgVaRaaaRaaaRaaaRaWbogOgOgOgOgQgQgXgQgPgQgQgOgOgOgOboaWaRaaaRaaaRaaaRgWgRgRgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaRaRaWgAgOgRgQgVaRaRaRaRaRaRaRaWbHbobobogOgOgOgRgQgRgOgOgObobobobHaWaRaRaRaRaRaRaRgVgRgUgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahcaaaaaRaRaWgAgOgRgPgWaRaaaRaaaRaaaRaWbobobobobobogOgQgQgQgObobobHbohdbpaWaRaaaRaaaRaaaRgWgQgQgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaWgAgOgRgRgWaRaaaRaaaRaaaRaWaWaWaWaWaWbHgOgQgQgRgOboaWaWaWaWaWaWaRaaaRaaaRaaaRgVgRgRgOboaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaWgOgOgQgRgOgOaRaRaRaRaRaRaRaRaRaRaRaWbogYgQgRgRgYboaWaRaRaRaRaRaRaRaRaRaRaRgOgOgQgQgOgOaWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgQgPgQgQgOgSgSgWgVgVgVgWgVgSgVgWgOgOgOgQgRgQgOgOgOgSgVgVgSgVgWgVgSgWgVgSgOgRgQgRgQgVaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgRgRgRgUgQgQgRgRgQgQgQgRgRgRgXgPgQgRgRgQgRgQgQgRgQgQgQgXgQgRgRgRgPgQgRgQgPgQgTgRgQgWaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgQgQgRgQgPgRgQgRgQgRgRgRgQgRgQgQgRgQgQgRgQgRgQgPgRgQgRgRgPgQgQgRhegRgQgRgQgTgRgRgRgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgUgQgPgQgOgShfgQgSgOgOgSgSgSgSgSgOgOgQgQgPgQgRgOgOgShggSgShhgSgVgShhgSgOgOgQgQgPgQgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgOhjhjgOgOhkhlhlhmhnhlhohphohqhohpgOgQgRgQgQgRgOhrhshshrhshrhshthrhrhrhsgOgOgRgQgOgOaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRgOgTgTgOhuhvhvhlhwhnhxhlhlhlhlhlhyhzgRgRgPgRgRgOhrhrhrhrhrhrhshrhrhshrhrhrhAgQgQgVaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRgOgTgTgOhvhvhlhvhBhnhChDhEhChChnhngOgOgUgQgQgOgOhrhFhrhshrhrhrhrhGhshshrhGgOgRgRgVaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRgOgTgTgOhvhvhHhvhIhJhKhlhvhvhLhnhMhNgOgQgRgRgOhrhthshshrhOhPhPhrhrhrhrhrhrgOgQgRgWaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgThQhHhRhvhvhvhvhlhvhHhvhShnhvhvgOgQgRgRhThrhshshrhshshUhPhrhrhshVhthrgOgQgPgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgTgOhWhWhWhXhvhvhYhvhZhvhvhChviagSgRgPgPgShrhrhrhrhrhrhPhPhshrhshVhrhrhTgRgRgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgTgOhWhWhWibhWhvhvhvhvhvhvhChvhvgSgRgQgQgShrhshsichrhrhPidhrhrhsiehFhrgOgRgQgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgTgOibhWibhWhWifhWhvhWighWhEihhviigQgRgRijhrhshrhrhrhrhPhPhrhrhriehrhrgOgQgQgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgThQhWhWikhWhWhWilhWhvhvhvhChvhHgSgPgQgQgWhrhshthshrhrimhPhrhrhshsinhrgOgTgTgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgTgOibhWibhWhWhvhWhvhWhvhWhChWiogSgQgQgRgShrhshshrhVhrhPhPhrhrhshrhrhrgOgPgRgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgTgOhWhWhWhWhHhWhvhWhvhviphniahvgOgPgPgQgOhrhshshriehrhrhrhrhshrhsiqhrgOgTgTgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgTgOibiribhWibhWhWhvhWhvhWhnhWiaisgRgRgPgOhrhrhrhsiehshthrhrhrhrhshrhrgOgQgQgOaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaitaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRgOgTgTgOhWhWhWhWhWhWhWhWhvhvhHhngOgOgOgRgQgQgOgOgOhrhrhrhriuhrhshrhrhrhrhrhAgQgRgWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagTgTgTivibhWibhWibhWibibibhWhWgOgOgQgQgPgRgRgUgUgOgOhrhshrhshshshrhrhPhPhPgOgRgRgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaivgTgTgThWhWhWiwhWhWhWhWhWirhWgOgQgQgQgRgRgQgQgQixgOhrhrhshthrhsiuiyiziAiBgOgQgRgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaivgTgTivibibibibibibiCiChChCiDiEgQgRgQgRgRgQgPgQgRiFhrhrhshGhrhrhriuiGiHiIgOgPgRgWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaivivivivibibhvibibhvhvhvhvhvhviJgQgRgQgQgXgRgRgQgQijiKhrhshshshshrhrhPhPhPgOgRgQgWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiviviviviLibhYibhHhWhvhWhlhWhviJgQgRgRgRiMgQgRgPgQijiNhshrhshshriuiOiziPiQgOgQgTgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaivivivivibibiRiRibhvhvhviShyiTiJgRgRgQgRgQgRgQgRgQijiNhshrhFhrhthriuiGiUiVgOgQgRgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaivivivivibibibibibibibibhChCiWiEgQgQgQgPgQgRgQgRgQiFhrhshriXhrhrhrhrhPhPhPgOgRgRgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiYiYiYiYiZjajajaiZjaiZjaiYhWhWhWhWhWgOgQgQgRgQgQgQgPgRgRgOhrhrhrjbhrhsiujcizjdjegOgQgPgWaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiYjfjgiYjgjhjijjjijkjljgjmibhWibjnjogOgOgQgQgQgRgRgQgQgOgOhPhPhrjpjqiuhriuiGjrjsgOgTgTgVaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajtjujujvjujujwjujxjyjgjgiYaaaRaajgjujggOgOgOgRgQgQgOgOgOaRaRhPhPhPhPhPhPhPhPhPhPgOgQgRgVgkaRgjaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiYjzjAiYjgjujujujyjBjujCiYaRaRaRjujujujujugOgQgRgRgOjgjgjujujgjujgjujujujujgjDjggQgTgTgWaRaRaRgjaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiYjEjFiYjujyjujujyjujyiYiYaaaRaajgjujgjujggOgQgPgRgOjgjujujuiYiYiYiYiYiYiYiYiYiYiYiYiYiYiYjgjgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajGjujHjIjgjJjujujKjyjuiYjwaaaRaajujujujujugOgQgRgQgOjgjujujuiYjujujujujujujgjgjgjgjgjgjgjgjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajAiYiYiYjujujyjyjujLjujMjwaRaRaRjgjujgjujggOgTgUgQgOjujujujuiYjgjujgjujgjujgjgjwjwjgjwjwjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajNjOjgjzjgjujPjujujujyiYjwaaaRaajujujujujugQgQgQjQgOjujujgjgiYjujujujujujujujujujujgjwjwjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiZjujujujujujujujRjyjyiYiYaaaRaajgjujgjujggQgTgRgQgOjgjgjgjgiYjgjujgjujgjujgjujgjujgjujgjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajAiYjAiYjgjSjyjujyjujyjTjzaRaRaRjujujujujugQgQgRgQgOjgjgjujuiYjujujujPjujujujujuiYiYiYiYjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajAjEjwiYjujujyjyjyjujujUjzaaaRaajgjujgjujggQgRgRgPgOjgjgjujuiYjgjujgjujgjujgjgjgjujgjujgjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajVjgjyjvjujujujWjujLjyjTjzaaaRaajujujujujugOgQgQgQgOjgjgjujuiYjujujujujujujuiYjwjwjgjwjwjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajAiYiYiYiZjajaiZjajXiZjNiYaRaRaRjgjujgjujggOgQgRgRgTjgjgjujuiYjgjujgjujgjujgjgjgjgjgjgjgjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajujujujujugOgPgQgQgTjgjgjujuiYjujujujujujYjujujujujgjwjwjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajgjujgjujggOgXgQgPgOjgjgjujuiYjgjujgjujgjujgjgjgjgjgjgjgjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajwjwiYiYiYiYjwjwjwjwjwjwjwjwjwaaaaaaaRgOgRgRgQgOjgjgjujuiYjujuiYjujgjujwjgjwjwjgjwjwjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajwjwjujyjgiYiYiYiYjwjwjwjwjwjwaaaaaaaagOgRgRgQgOjgjgjgjuiYjujujgjujujujujgjujgjujgjgjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaajwjwjujgjujgjZjgiYjziYiYjwjwjwaaaaaaaagOgQgQgQgOjgjgjgjuiYjujujujDjujujujujujujujujwjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajwiYiYjgjujgjyjujgjgjuiYkakbiYaaaaaaaRgOgPgRjQgOjwjwjgjuiYiYiYiYiYiYjuiYiYiYiYiYiYjgjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaajwiYjujukcjujgjDjgjyjgjgjujDjzaaaaaaaagOgRgRgQgOjgjgjgjujujujujujujujujujujukcjujujwjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaaaaaaaaaaaajwjzjujDkdjyjyjyjujykejukfjyiYaaaaaaaagOgQgPgQgOjwjwjgjukdjujujgjujujgjujgjujgkgjgjgjwjwjwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiYiYjyjujyjujikhkijujujyjDiYiYaaaaaaaRgOgQgRgQgOjgjgjgjujujwjgjwjwjgjwjwjgjwaaaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajujujukjjukejukkkljyjykmknjzjwaaaaaaaagOgQgRgQgTjwjwjwjujgjgjgjgjgjgjgjgjgjgaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajujykokpkqjujujukrjuksjyktjzjwaaaaaaaagOgQgRgRgTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaaiYiYjziYjgkujgjyjgjujujDiYiYjwaaaaaaaRgOgQgRgRgTaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRjgjgjwiYjNiYiYjgkjjgkbjgkvjwjwaaaaaaaagOgRgQgQgTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRjgjgjgjwjwjwiYiYjziYjgkwiYjwjwaaaaaaaagOgRgRgQgTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajwjwjwjwjwjwjwjwjwiYiYiYiYjwjwaaaaaaaRgOgQgQgPgTaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagOgPgQgQgTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagOgRgRgRgOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRgOgRgQgQgOaRaRaRaRaRaRaRaRaRaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRjgjgjgiYjgjgiYiYiYiYiYiYiYgOgQgQgRgOiYiYiYiYiYiYiYiYiYiYiYiYiYiYiYiYjgaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajujujujujujujujujujujujukxgQgQgPgRgQkxjujujujujujgjgjgjujgjgjujgjujgjggjaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRaRaRaRjgjgjgjgiYiYiYiYiYiYiYiYiYgOkygQgQgOiYiYiYiYiYiYiYiYiYiYiYiYjgjgjgjgjgaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRgOkzkAkzgOaRaRaRaRaRaRaRaRaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRkzkBkzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiYiYiYjgjgjgiYiYiYiYiYiYiYiYiYiYiYkzkzkzkAkzkzkziYiYiYiYiYiYiYiYiYiYdOdOaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRjgjgjgjgjujujujujujujujujujujujujukDkBkBkBkBkBkDjujujujukjjujujujujugjgjgjaaaRaaaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiYiYiYiYiYiYiYiYiYiYkzkzkzkzkzkzkzkzkAkzkzkzkzkzkzkzkziYiYiYiYiYaRaRaRaRaRaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRaRkEkEkzkFkzkBkBkGkBkBkBkBkBkGkBkBkHkIkzkEkEaRaRaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkJkzkBkBkKkLkzkzkMkAkMkzkzkNkBkBkKkzkJkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkzkzkBkKkKkOkPkEkzkBkzkEkPkLkKkKkBkzkzkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkzkBkQkKkBkBkRkEkzkBkzkEkRkSkKkKkBkTkzkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkzkBkBkBkKkUkRkEkzkBkzkEkRkOkVkBkKkBkzkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakzkzkBkKkBkBkWkPkEkzkBkzkEkRkXkBkBkKkFkzkzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakYkZkKkBkBkKkOkPkEkzkBkzkEkPkKkKkBkKkBkBkPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalakBkKlbkKkBkOkRkEkzkBkzkElckXkKldkVkKkKkRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalakBkKlekKkKlflckEkzkBkzkEkPkOkKkKkBlglhkPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalakBkBkBkKkKlilckEkzkBkzkEkRkOkBkBkBkKkBkRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakYkBkKkBkKkBkOlckEkzkBkzkEkPljlkkBkVkBkIkPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakzkzkFkBkKkVkBkzkzkzkAkzkzkzllkBkKkKlmkzkzaaaalnaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkzkzkzlokMkzkzkBkBlpkKlekzkzkMlolqkzkzkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkJlakBkKlrkPlpkKkBlskKkKlpkPltkBkKkPkJkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalululululuaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkJlakBkBkKkPlvlwlxlylzlAlvkPlBkBkKkPkJkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRlululClDlEluluaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkJkYkKkBlBkPlFlGlzlHlxlAlFkPkBkBkBkPkJkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRlululIlJlKlJlLluluaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkJlalekBlMkPlNkBkKkBkBkBlNkRkZkKkBkPkJkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalOlPlJlQlRlJlJlSluaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkJkzkzkzkzkzkzkBkBkKkKlTkzkzkzkzkzkzkJkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalJlJlJlUlUlUlJlJluaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakJkJkJkBkBkBkBkzkzkPkPkPkzkzkBkBkBkBkJkJkJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalulJlUlUlRlUlRlVluaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBaRaRaRkBaRaRaRkBaRaRaRkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRlululWlXlRlUlYluluaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBlZkBmakBkBkBmakBkBkBmakBmbkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRlululJlUlJluluaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBaRkBaRaRaRkBaRaRaRkBaRkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalululJluluaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalkkBaRkBaRaaaRkBaRaaaRkBaRkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaRaaaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBaRkBaRaRaRkBaRaRaRkBaRkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaRaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBkBmakBkBkBmckBkBkBmakBkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBaRkBaRaRaRkBaRaRaRkBaRkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBaRkBaRaaaRkBaRaaaRkBaRkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBkBkBaRaRaRkBaRaRaRkBkBkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBlZkBmakBkBkBmakBkBkBmakBmbkBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakBkBkBkBkBkBkBkBkBkBkBkBkBaaaaaaaaaaaaaaaaaaaaaaaaaaaamdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/away/derelict/derelict.dm b/maps/away/derelict/derelict.dm new file mode 100644 index 00000000..8bc6b8cc --- /dev/null +++ b/maps/away/derelict/derelict.dm @@ -0,0 +1,53 @@ +#include "derelict_areas.dm" + +/obj/effect/overmap/sector/derelict + name = "debris field" + desc = "A large field of miscellanious debris." + icon_state = "object" + known = 0 + + generic_waypoints = list( + "nav_derelict_1", + "nav_derelict_2", + "nav_derelict_3", + "nav_derelict_4", + "nav_derelict_5", + "nav_derelict_6", + "nav_derelict_7" + ) + +/datum/map_template/ruin/away_site/derelict + name = "Derelict Station" + id = "awaysite_derelict" + description = "An abandoned construction project." + suffixes = list("derelict/derelict-station.dmm") + cost = 1 + accessibility_weight = 10 + +/obj/effect/shuttle_landmark/derelict/nav1 + name = "Debris Navpoint #1" + landmark_tag = "nav_derelict_1" + +/obj/effect/shuttle_landmark/derelict/nav2 + name = "Debris Navpoint #2" + landmark_tag = "nav_derelict_2" + +/obj/effect/shuttle_landmark/derelict/nav3 + name = "Debris Navpoint #3" + landmark_tag = "nav_derelict_3" + +/obj/effect/shuttle_landmark/derelict/nav4 + name = "Debris Navpoint #4" + landmark_tag = "nav_derelict_4" + +/obj/effect/shuttle_landmark/derelict/nav5 + name = "Debris Navpoint #5" + landmark_tag = "nav_derelict_5" + +/obj/effect/shuttle_landmark/derelict/nav6 + name = "Debris Navpoint #6" + landmark_tag = "nav_derelict_6" + +/obj/effect/shuttle_landmark/derelict/nav7 + name = "Debris Navpoint #7" + landmark_tag = "nav_derelict_7" \ No newline at end of file diff --git a/maps/away/derelict/derelict_areas.dm b/maps/away/derelict/derelict_areas.dm new file mode 100644 index 00000000..3ac3f4cc --- /dev/null +++ b/maps/away/derelict/derelict_areas.dm @@ -0,0 +1,61 @@ +/area/derelict/ship + name = "\improper Abandoned Ship" + icon_state = "yellow" + +/area/AIsattele + name = "\improper AI Satellite Teleporter Room" + icon_state = "teleporter" + ambience = list('sound/ambience/ambimalf.ogg') + +/area/constructionsite + name = "\improper Construction Site" + icon_state = "storage" + ambience = list('sound/ambience/spookyspace1.ogg', 'sound/ambience/spookyspace2.ogg') + +/area/constructionsite/storage + name = "\improper Construction Site Storage Area" + +/area/constructionsite/bridge + name = "\improper Construction Site Bridge" + icon_state = "bridge" + +/area/constructionsite/hallway/aft + name = "\improper Construction Site Aft Hallway" + icon_state = "hallP" + +/area/constructionsite/hallway/fore + name = "\improper Construction Site Fore Hallway" + icon_state = "hallS" + +/area/constructionsite/atmospherics + name = "\improper Construction Site Atmospherics" + icon_state = "green" + +/area/constructionsite/medical + name = "\improper Construction Site Medbay" + icon_state = "medbay" + +/area/constructionsite/ai + name = "\improper Construction Computer Core" + icon_state = "ai" + +/area/constructionsite/engineering + name = "\improper Construction Site Engine Bay" + icon_state = "engine" + +/area/constructionsite/teleporter + name = "Construction Site Teleporter" + icon_state = "yellow" + +/area/constructionsite/solar + name = "\improper Construction Site Solars" + icon_state = "aft" + area_flags = AREA_FLAG_EXTERNAL + requires_power = 1 + always_unpowered = 1 + has_gravity = FALSE + base_turf = /turf/space + +/area/constructionsite/maintenance + name = "\improper Construction Site Maintenance" + icon_state = "yellow" \ No newline at end of file diff --git a/maps/away/empty.dmm b/maps/away/empty.dmm new file mode 100644 index 00000000..c35850ac --- /dev/null +++ b/maps/away/empty.dmm @@ -0,0 +1,204 @@ +"a" = (/turf/space,/area/space) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/errant_pisces/backup/errant_pisces.dmm b/maps/away/errant_pisces/backup/errant_pisces.dmm new file mode 100644 index 00000000..5ab3031f --- /dev/null +++ b/maps/away/errant_pisces/backup/errant_pisces.dmm @@ -0,0 +1,1090 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/turf/simulated/wall/r_wall,/area/errant_pisces/bow_starboard) +"ac" = (/turf/simulated/wall/r_wall,/area/errant_pisces/bow_port) +"ad" = (/obj/machinery/atmospherics/unary/engine,/turf/simulated/wall/r_wall,/area/errant_pisces/bow_starboard) +"ae" = (/obj/machinery/atmospherics/unary/engine,/turf/simulated/wall/r_wall,/area/errant_pisces/bow_port) +"af" = (/obj/machinery/alarm{alarm_id = "petrov1"; dir = 4; pixel_x = -25; pixel_y = 0; rcon_setting = 3},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"ag" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 5},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"ah" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel,/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"ai" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 4},/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aj" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 10},/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/obj/machinery/alarm{dir = 8; pixel_x = 25; pixel_y = 0},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"ak" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 6},/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/obj/machinery/alarm{alarm_id = "petrov1"; dir = 4; pixel_x = -25; pixel_y = 0; rcon_setting = 3},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"al" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel,/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"am" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 4},/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"an" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 9},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"ao" = (/obj/machinery/alarm{dir = 8; pixel_x = 25; pixel_y = 0},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"ap" = (/obj/machinery/portable_atmospherics/canister/empty/hydrogen,/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aq" = (/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"ar" = (/obj/machinery/atmospherics/binary/pump{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"as" = (/obj/machinery/atmospherics/binary/pump{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"at" = (/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"au" = (/obj/machinery/portable_atmospherics/canister/empty/hydrogen,/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"av" = (/obj/machinery/atmospherics/portables_connector{dir = 4},/obj/machinery/portable_atmospherics/canister/empty/hydrogen,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aw" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"ax" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"ay" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel{dir = 4},/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"az" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel{dir = 8},/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aA" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aB" = (/obj/machinery/atmospherics/binary/pump{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aC" = (/obj/machinery/atmospherics/portables_connector{dir = 8},/obj/machinery/portable_atmospherics/canister/empty/hydrogen,/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aD" = (/obj/structure/closet/firecloset,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aE" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aF" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aG" = (/obj/machinery/portable_atmospherics/canister/empty/hydrogen,/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aH" = (/obj/machinery/atmospherics/pipe/tank/hydrogen{dir = 1},/obj/effect/floor_decal/industrial/warning{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aI" = (/obj/machinery/atmospherics/pipe/tank/hydrogen{dir = 1},/obj/effect/floor_decal/industrial/warning{dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aJ" = (/obj/machinery/atmospherics/unary/heater{icon_state = "heater_0"; dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aK" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aL" = (/obj/machinery/atmospherics/valve{icon_state = "map_valve0"; dir = 8},/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aM" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 9},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aN" = (/obj/machinery/atmospherics/unary/heater{icon_state = "heater_0"; dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aO" = (/obj/machinery/atmospherics/pipe/tank/hydrogen{dir = 1},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aP" = (/obj/machinery/atmospherics/pipe/tank/hydrogen{dir = 1},/obj/effect/floor_decal/industrial/warning{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aQ" = (/obj/machinery/portable_atmospherics/canister/empty/hydrogen,/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/effect/floor_decal/industrial/warning{dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aR" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aS" = (/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aT" = (/obj/structure/closet/firecloset,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aU" = (/obj/structure/lattice,/obj/structure/grille,/obj/structure/grille,/turf/space,/area/space) +"aV" = (/obj/structure/lattice,/obj/structure/grille,/turf/space,/area/space) +"aW" = (/turf/simulated/wall/r_wall,/area/errant_pisces/storage_starboard) +"aX" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aY" = (/turf/simulated/wall/r_wall,/area/errant_pisces/atmos) +"aZ" = (/turf/simulated/wall/r_wall,/area/errant_pisces/enginering) +"ba" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"bb" = (/turf/simulated/wall/r_wall,/area/errant_pisces/storage_port) +"bc" = (/obj/structure/lattice,/turf/space,/area/space) +"bd" = (/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"be" = (/obj/machinery/portable_atmospherics/canister/carbon_dioxide,/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"bf" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"bg" = (/obj/machinery/atmospherics/pipe/tank/air,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bh" = (/obj/machinery/atmospherics/portables_connector,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bi" = (/obj/machinery/light/small{dir = 1},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bj" = (/obj/machinery/portable_atmospherics/canister,/obj/machinery/atmospherics/portables_connector,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bk" = (/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bl" = (/obj/machinery/portable_atmospherics/canister/phoron,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bm" = (/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bn" = (/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bo" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/vehicle/train/cargo/trolley,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bp" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bq" = (/obj/machinery/computer/engines,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"br" = (/obj/item/modular_computer/console,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bs" = (/obj/structure/table/rack,/obj/random/toolbox,/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"bt" = (/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"bu" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/solar{id = "XynergySolarStarboard"},/turf/simulated/floor/airless,/area/space) +"bv" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/airless,/area/space) +"bw" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/power/solar{id = "XynergySolarStarboard"},/turf/simulated/floor/airless,/area/space) +"bx" = (/obj/machinery/light/small{dir = 4},/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"by" = (/obj/machinery/light/small{dir = 4},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"bz" = (/obj/machinery/atmospherics/pipe/manifold/visible/blue{dir = 8},/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bA" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/blue,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bB" = (/obj/machinery/atmospherics/pipe/simple/visible/blue{dir = 10},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bC" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{icon_state = "intact"; dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bD" = (/obj/machinery/atmospherics/pipe/manifold/visible/yellow,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bE" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bF" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{dir = 9},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bG" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bH" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bI" = (/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bJ" = (/obj/machinery/portable_atmospherics/canister,/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bK" = (/obj/vehicle/train/cargo/trolley,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bL" = (/obj/structure/table/steel,/obj/random/tool,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bM" = (/obj/structure/bed/chair/office/dark{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bN" = (/obj/machinery/light/small{dir = 4},/obj/structure/table/steel,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bO" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"bP" = (/obj/structure/table/rack,/obj/random/powercell,/obj/machinery/light/small{dir = 8},/obj/item/weapon/mop,/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"bQ" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/solar{id = "XynergySolarPort"},/turf/simulated/floor/airless,/area/space) +"bR" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/power/solar{id = "XynergySolarPort"},/turf/simulated/floor/airless,/area/space) +"bS" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/airless,/area/space) +"bT" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"bU" = (/obj/machinery/atmospherics/pipe/tank/air{icon_state = "air_map"; dir = 1; start_pressure = 740.5},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bV" = (/obj/machinery/atmospherics/pipe/simple/visible/blue,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bW" = (/obj/machinery/atmospherics/binary/pump,/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bX" = (/obj/machinery/atmospherics/trinary/filter{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bY" = (/obj/machinery/atmospherics/pipe/manifold/visible/red{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bZ" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/obj/machinery/atmospherics/portables_connector{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"ca" = (/obj/machinery/portable_atmospherics/canister,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cb" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cc" = (/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cd" = (/obj/structure/closet,/obj/random/tool,/obj/random/smokes,/obj/item/clothing/under/hazard,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"ce" = (/obj/structure/table/rack,/obj/random/tool,/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"cf" = (/obj/machinery/atmospherics/pipe/tank/nitrogen{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cg" = (/obj/machinery/atmospherics/binary/pump{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"ch" = (/obj/machinery/atmospherics/portables_connector{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"ci" = (/obj/machinery/atmospherics/pipe/simple/visible/universal,/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cj" = (/obj/machinery/atmospherics/pipe/simple/visible/blue{icon_state = "intact"; dir = 6},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"ck" = (/obj/machinery/atmospherics/pipe/simple/visible/blue{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cl" = (/obj/machinery/atmospherics/trinary/filter/m_filter{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cm" = (/obj/machinery/atmospherics/pipe/manifold/visible/red{icon_state = "map"; dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cn" = (/obj/machinery/autolathe,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"co" = (/obj/structure/table/rack,/obj/random/tool,/obj/random/tech_supply,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cp" = (/obj/structure/table/rack,/obj/random/tool,/obj/random/tech_supply,/obj/item/clothing/gloves/duty,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cq" = (/obj/structure/closet,/obj/random/tech_supply,/obj/item/clothing/shoes/dutyboots,/obj/item/clothing/under/hazard,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cr" = (/obj/structure/table/rack,/obj/random/powercell,/obj/random/clothing,/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"cs" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"ct" = (/obj/machinery/atmospherics/pipe/manifold/visible/red,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cu" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cv" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cw" = (/obj/machinery/atmospherics/trinary/mixer/m_mixer{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cx" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/visible/blue{icon_state = "intact"; dir = 6},/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cy" = (/obj/machinery/atmospherics/pipe/manifold/visible/blue,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cz" = (/obj/machinery/atmospherics/binary/oxyregenerator{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cA" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cB" = (/obj/machinery/pipedispenser,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cC" = (/obj/effect/landmark/corpse/engineer,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cD" = (/obj/structure/table/rack,/obj/random/tech_supply,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cE" = (/obj/structure/table/rack,/obj/random/tool,/obj/random/tank,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cF" = (/obj/structure/closet,/obj/random/tool,/obj/random/glasses,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cG" = (/obj/structure/closet/l3closet/janitor,/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"cH" = (/obj/random/junk,/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"cI" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"cJ" = (/obj/machinery/light/small{dir = 4},/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"cK" = (/obj/machinery/atmospherics/pipe/tank/oxygen{dir = 4},/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cL" = (/obj/machinery/atmospherics/pipe/manifold/visible/blue{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cM" = (/obj/machinery/atmospherics/pipe/manifold/visible/blue,/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cN" = (/obj/machinery/atmospherics/pipe/simple/visible/blue{icon_state = "intact"; dir = 9},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cO" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cP" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cQ" = (/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cR" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cS" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cT" = (/obj/structure/bed/chair/janicart,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"cU" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"cV" = (/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"cW" = (/obj/machinery/alarm{dir = 8; pixel_x = 25; pixel_y = 0},/obj/machinery/portable_atmospherics/canister/oxygen,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"cX" = (/obj/machinery/atmospherics/pipe/tank/air{dir = 4; start_pressure = 740.5},/obj/machinery/atmospherics/pipe/tank/oxygen{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cY" = (/obj/machinery/atmospherics/portables_connector{dir = 8},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cZ" = (/obj/machinery/portable_atmospherics/powered/pump,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"da" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/light/small,/obj/machinery/portable_atmospherics/powered/pump,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"db" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/portable_atmospherics/powered/scrubber,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"dc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"dd" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"de" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/structure/closet/firecloset,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"df" = (/obj/machinery/alarm{alarm_id = "petrov1"; dir = 4; pixel_x = -25; pixel_y = 0; rcon_setting = 3},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"dg" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"dh" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"di" = (/obj/structure/dispenser/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"dj" = (/obj/machinery/light/small,/obj/machinery/suit_storage_unit/standard_unit,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"dk" = (/obj/machinery/suit_storage_unit/standard_unit,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"dl" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -32; pixel_y = 0},/obj/structure/mopbucket,/obj/item/weapon/mop,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"dm" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"dn" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"do" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"dp" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"dq" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"dr" = (/turf/simulated/wall/r_wall,/area/errant_pisces/bow_maint) +"ds" = (/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dt" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"du" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dv" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dw" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dx" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dy" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dz" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dA" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 4; frequency = 1441; icon_state = "map_injector"; id = "n2_in"; use_power = 1},/turf/simulated/floor/airless,/area/space) +"dB" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dC" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dD" = (/obj/machinery/atmospherics/binary/pump{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dE" = (/obj/machinery/atmospherics/portables_connector{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dF" = (/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dG" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dH" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dI" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/light/small,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dJ" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dK" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dL" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/power/apc{dir = 2; name = "south bump"; operating = 1; pixel_y = -24},/obj/structure/cable/green,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dM" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dN" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dO" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/random/junk,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dP" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dQ" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dR" = (/turf/simulated/wall/r_wall,/area/errant_pisces/solar_starboard) +"dS" = (/obj/structure/table/rack,/obj/random/hardsuit,/obj/random/shoes,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dT" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dU" = (/turf/simulated/wall/r_wall,/area/errant_pisces/head_f) +"dV" = (/turf/simulated/wall/r_wall,/area/errant_pisces/smes_room) +"dW" = (/obj/machinery/door/airlock,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"dX" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"dY" = (/turf/simulated/wall/r_wall,/area/errant_pisces/head_m) +"dZ" = (/obj/structure/table/rack,/obj/random/tech_supply,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"ea" = (/turf/simulated/wall/r_wall,/area/errant_pisces/solar_port) +"eb" = (/obj/effect/shuttle_landmark/automatic,/turf/space,/area/space) +"ec" = (/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/tracker{id = "XynergySolarStarboard"},/turf/simulated/floor/airless,/area/space) +"ed" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"ee" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless,/area/space) +"ef" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/obj/machinery/access_button/airlock_exterior{frequency = 1011; master_tag = "xyn_solar_starboard_airlock"; pixel_y = 20},/turf/simulated/floor/airless,/area/errant_pisces/solar_starboard) +"eg" = (/obj/machinery/door/airlock/external{frequency = 1011; id_tag = "xyn_solar_starboard_outer"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"eh" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/unary/vent_pump/high_volume,/obj/machinery/airlock_sensor{frequency = 1011; id_tag = "xyn_solar_starboard_sensor"; pixel_y = 25},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1011; id_tag = "xyn_solar_starboard_airlock"; pixel_x = 25; tag_airpump = "xyn_solar_starboard_pump"; tag_chamber_sensor = "xyn_solar_starboard_sensor"; tag_exterior_door = "xyn_solar_starboard_outer"; tag_interior_door = "xyn_solar_starboard_inner"},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"ei" = (/obj/structure/closet/firecloset,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"ej" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"ek" = (/obj/structure/table/standard,/obj/item/weapon/towel/random,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"el" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"em" = (/obj/machinery/door/airlock,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"en" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/effect/landmark/corpse/carp_fisher,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"eo" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"ep" = (/obj/structure/toilet{dir = 8},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"eq" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"er" = (/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/machinery/power/smes/buildable,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"es" = (/obj/machinery/light/small{dir = 1},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"et" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"eu" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"ev" = (/obj/machinery/light/small{dir = 1},/obj/structure/toilet{dir = 4},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"ew" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"ex" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"ey" = (/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"ez" = (/obj/structure/table/standard,/obj/item/weapon/towel/random,/obj/item/weapon/towel/random,/obj/item/weapon/towel/random,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"eA" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"eB" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/unary/vent_pump/high_volume{frequency = 1013; id_tag = "xyn_solar_port_pump"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1013; id_tag = "xyn_solar_port_airlock"; pixel_x = -25; tag_airpump = "xyn_solar_port_pump"; tag_chamber_sensor = "xyn_solar_port_sensor"; tag_exterior_door = "xyn_solar_port_outer"; tag_interior_door = "xyn_solar_port_inner"},/obj/machinery/airlock_sensor{frequency = 1013; id_tag = "xyn_solar_port_sensor"; pixel_y = 25},/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"eC" = (/obj/machinery/door/airlock/external{frequency = 1013; id_tag = "xyn_solar_port_outer"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"eD" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/obj/machinery/access_button/airlock_exterior{frequency = 1013; master_tag = "xyn_solar_port_airlock"; pixel_y = 20},/turf/simulated/floor/airless,/area/errant_pisces/solar_port) +"eE" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/airless,/area/space) +"eF" = (/obj/machinery/power/tracker{id = "XynergySolarPort"},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless,/area/space) +"eG" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless,/area/space) +"eH" = (/obj/machinery/door/airlock/external{frequency = 1011; id_tag = "xyn_solar_starboard_inner"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"eI" = (/obj/machinery/shower{icon_state = "shower"; dir = 4},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"eJ" = (/turf/simulated/wall,/area/errant_pisces/head_f) +"eK" = (/obj/structure/closet/athletic_mixed,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"eL" = (/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"eM" = (/obj/machinery/power/terminal,/obj/structure/cable,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"eN" = (/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"eO" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"eP" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"eQ" = (/obj/machinery/power/port_gen/pacman/mrs,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"eR" = (/turf/simulated/wall,/area/errant_pisces/head_m) +"eS" = (/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"eT" = (/obj/structure/closet/athletic_mixed,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"eU" = (/obj/machinery/shower{dir = 8; icon_state = "shower"; pixel_x = 0; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"eV" = (/obj/machinery/door/airlock/external{frequency = 1013; id_tag = "xyn_solar_port_inner"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"eW" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/access_button/airlock_interior{frequency = 1011; master_tag = "xyn_solar_starboard_airlock"; pixel_x = -25; pixel_y = 25},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"eX" = (/obj/machinery/power/smes/buildable,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"eY" = (/obj/machinery/light/small{dir = 4},/obj/effect/decal/cleanable/blood,/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"eZ" = (/obj/structure/closet/athletic_mixed,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"fa" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"fb" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/power/smes/buildable,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fc" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fd" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fe" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"ff" = (/obj/machinery/power/port_gen/pacman/mrs,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fg" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fh" = (/obj/structure/closet/athletic_mixed,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fi" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fj" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/landmark/corpse/engineer,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"fk" = (/obj/machinery/power/smes/buildable,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fl" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/access_button/airlock_interior{frequency = 1013; master_tag = "xyn_solar_port_airlock"; pixel_x = 25; pixel_y = 25},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fm" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"fn" = (/obj/effect/wingrille_spawn/reinforced/full,/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"fo" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"fp" = (/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"fq" = (/obj/machinery/door/airlock,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"fr" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"fs" = (/obj/structure/sink{icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2},/obj/structure/mirror{pixel_x = -30},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"ft" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"fu" = (/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fv" = (/obj/machinery/power/terminal,/obj/structure/cable,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fw" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fx" = (/obj/machinery/power/port_gen/pacman/mrs,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fy" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fz" = (/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/obj/structure/mirror{pixel_x = 30},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fA" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"fB" = (/obj/machinery/door/airlock,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fC" = (/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fD" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fE" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fF" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fG" = (/obj/machinery/power/solar_control,/obj/structure/cable/yellow,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"fH" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable,/obj/item/weapon/stool,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"fI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"fJ" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"fK" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fL" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fM" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fN" = (/obj/machinery/light/small{dir = 4},/obj/structure/closet/crate/radiation,/obj/item/stack/material/tritium/ten,/obj/item/stack/material/tritium/ten,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fO" = (/obj/structure/urinal{pixel_y = 30},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fP" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fQ" = (/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/obj/structure/mirror{pixel_x = 30},/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fR" = (/obj/item/weapon/stool,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -32; pixel_y = 0},/obj/machinery/power/apc{dir = 2; name = "south bump"; operating = 1; pixel_y = -24},/obj/structure/cable,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fS" = (/obj/machinery/power/solar_control{id = "XynergySolarPort"},/obj/structure/cable/yellow,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fT" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"fU" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"fV" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fW" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fX" = (/turf/simulated/wall/r_wall,/area/errant_pisces/hallway) +"fY" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"fZ" = (/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"ga" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gc" = (/obj/machinery/light,/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gd" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"ge" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gf" = (/obj/machinery/light,/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gg" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gh" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gi" = (/turf/simulated/wall/r_wall,/area/errant_pisces/rooms) +"gj" = (/turf/simulated/wall,/area/errant_pisces/rooms) +"gk" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -32; pixel_y = 0},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gl" = (/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gm" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gn" = (/turf/simulated/wall,/area/errant_pisces/dorms) +"go" = (/turf/simulated/wall/r_wall,/area/errant_pisces/dorms) +"gp" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet/rainbow,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gq" = (/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gr" = (/obj/item/modular_computer/console,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gs" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet/orange,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gt" = (/obj/structure/bed/chair/comfy/brown{dir = 1},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gu" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/machinery/media/jukebox,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gv" = (/obj/structure/bed/chair/comfy/brown{dir = 4},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gw" = (/obj/structure/table/woodentable,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gx" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/rooms) +"gy" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gz" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gA" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gB" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/dorms) +"gC" = (/obj/machinery/vending/snack,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gD" = (/obj/machinery/vending/fitness,/obj/machinery/light{icon_state = "tube1"; dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gE" = (/obj/machinery/vending/cola,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gF" = (/obj/structure/closet,/obj/random/clothing,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gG" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gH" = (/obj/structure/closet,/obj/random/accessory,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gI" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet,/obj/random/plushie,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gJ" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gK" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless,/area/space) +"gL" = (/obj/structure/bed/chair/comfy/green,/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gM" = (/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gN" = (/obj/structure/closet/cabinet,/obj/item/clothing/shoes/jackboots,/obj/item/clothing/suit/armor/vest,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gO" = (/obj/structure/bed/chair/comfy/teal,/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gP" = (/obj/structure/filingcabinet/chestdrawer,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gQ" = (/obj/structure/table/gamblingtable,/obj/item/weapon/deck/cards,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gR" = (/obj/structure/bed/chair/comfy/brown{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gS" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gT" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gU" = (/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gV" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gW" = (/obj/structure/closet,/obj/random/cash,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gX" = (/obj/structure/closet,/obj/random/hat,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gY" = (/obj/structure/curtain/black,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gZ" = (/obj/structure/table/woodentable,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"ha" = (/obj/structure/closet,/obj/random/smokes,/obj/random/projectile,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hb" = (/obj/structure/table/woodentable,/obj/item/weapon/paper_bin,/obj/item/device/flashlight/lamp,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hc" = (/obj/structure/closet,/obj/random/snack,/obj/random/tool,/obj/random/suit,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hd" = (/obj/structure/table/gamblingtable,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"he" = (/obj/structure/table/woodentable,/obj/item/weapon/material/ashtray/bronze,/obj/random/smokes,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hf" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hg" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/rooms) +"hh" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"hi" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"hj" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hk" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hl" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hm" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hn" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"ho" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hp" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/solar{id = "XynergySolarPort"},/obj/machinery/power/solar{id = "XynergySolarPort"},/turf/simulated/floor/airless,/area/space) +"hq" = (/turf/simulated/wall/r_wall,/area/errant_pisces/infirmary) +"hr" = (/obj/machinery/door/airlock,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hs" = (/obj/effect/landmark/corpse/bridgeofficer,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"ht" = (/obj/structure/bed/chair/comfy/brown,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hu" = (/obj/machinery/vending/coffee,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hv" = (/obj/machinery/vending/cigarette,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hw" = (/obj/structure/closet,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hx" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hy" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hz" = (/obj/machinery/alarm{dir = 1; pixel_y = -25; req_one_access = list(24,11)},/obj/structure/bed/chair/comfy/brown{dir = 4},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hA" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/table/woodentable,/obj/random/smokes,/obj/structure/cable/green,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hB" = (/obj/machinery/vending/games,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hC" = (/obj/machinery/vending/assist,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hD" = (/obj/machinery/light/small,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hE" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet,/obj/random/plushie/large,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hF" = (/turf/simulated/wall/r_wall,/area/errant_pisces/live_storage) +"hG" = (/obj/structure/closet,/obj/item/clothing/under/rank/medical/scrubs,/obj/item/clothing/under/rank/medical/scrubs,/obj/item/clothing/under/rank/medical/scrubs,/obj/item/clothing/under/rank/nurse,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"hH" = (/obj/structure/table/standard,/obj/random/firstaid,/obj/item/weapon/storage/box/bodybags,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"hI" = (/turf/simulated/wall,/area/errant_pisces/infirmary) +"hJ" = (/obj/machinery/optable,/obj/machinery/oxygen_pump/anesthetic{pixel_x = -25},/turf/simulated/floor/tiled/white,/area/errant_pisces/infirmary) +"hK" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/turf/simulated/floor/tiled/white,/area/errant_pisces/infirmary) +"hL" = (/obj/structure/table/steel,/obj/item/clothing/head/surgery,/obj/item/weapon/storage/firstaid/surgery,/obj/item/weapon/storage/firstaid/adv,/obj/item/clothing/mask/breath/anesthetic,/turf/simulated/floor/tiled/white,/area/errant_pisces/infirmary) +"hM" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"hN" = (/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hO" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hP" = (/obj/structure/crematorium,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"hQ" = (/obj/structure/morgue{dir = 2},/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"hR" = (/obj/structure/iv_drip,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"hS" = (/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"hT" = (/obj/machinery/computer/operating,/turf/simulated/floor/tiled/white,/area/errant_pisces/infirmary) +"hU" = (/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/tiled/white,/area/errant_pisces/infirmary) +"hV" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/errant_pisces/infirmary) +"hW" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"hX" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"hY" = (/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"hZ" = (/obj/structure/table/standard,/obj/random/firstaid,/obj/structure/window/basic{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"ia" = (/obj/structure/table/standard,/obj/random/glasses,/obj/structure/window/basic{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"ib" = (/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"ic" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"id" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"ie" = (/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"if" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"ig" = (/obj/structure/reagent_dispensers/water_cooler,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"ih" = (/obj/item/weapon/material/kitchen/utensil/knife/plastic,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"ii" = (/obj/item/weapon/stool,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"ij" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"ik" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"il" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"im" = (/obj/effect/landmark/corpse/chef,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"in" = (/obj/machinery/door/airlock/freezer,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"io" = (/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"ip" = (/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"iq" = (/obj/machinery/button/remote/blast_door{id = "xynergy_bd_cell1"; name = "Cell 1 blast door-control"; pixel_y = -25},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"ir" = (/obj/machinery/light/small,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"is" = (/obj/machinery/button/remote/blast_door{id = "xynergy_bd_cell2"; name = "Cell 2 blast door-control"; pixel_y = -25},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"it" = (/obj/machinery/button/remote/blast_door{id = "xynergy_bd_cell3"; name = "Cell 3 blast door-control"; pixel_y = -25},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"iu" = (/obj/machinery/button/crematorium{pixel_x = -20},/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iv" = (/obj/machinery/light/small{dir = 1},/obj/effect/landmark/corpse/carp_fisher,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iw" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"ix" = (/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iy" = (/obj/machinery/door/airlock,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iz" = (/obj/machinery/door/airlock,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iA" = (/obj/effect/wingrille_spawn/reinforced/full,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iB" = (/obj/structure/curtain/medical,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iC" = (/obj/structure/window/basic,/obj/structure/window/basic{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iD" = (/obj/structure/closet,/obj/random/firstaid,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iE" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iF" = (/obj/structure/table/standard,/obj/item/trash/plate,/obj/item/weapon/material/kitchen/utensil/fork,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"iG" = (/obj/structure/table/marble,/obj/random/snack,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"iH" = (/obj/structure/table/marble,/obj/item/trash/plate,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"iI" = (/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"iJ" = (/obj/structure/closet/crate/freezer,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"iK" = (/obj/machinery/door/blast/regular{id = "xynergy_bd_cell1"},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"iL" = (/obj/machinery/door/blast/regular{id = "xynergy_bd_cell2"},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"iM" = (/obj/machinery/door/blast/regular{id = "xynergy_bd_cell3"},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"iN" = (/obj/structure/closet/crate/secure/biohazard,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iO" = (/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iP" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iQ" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iR" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iS" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iT" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/machinery/alarm{dir = 1; pixel_y = -25; req_one_access = list(24,11)},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iU" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/landmark/corpse/doctor,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iV" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iW" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iX" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iY" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"ja" = (/obj/machinery/body_scanconsole,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jb" = (/obj/structure/table/standard,/obj/item/weapon/paper_bin,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jc" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jd" = (/obj/structure/table/marble,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"je" = (/obj/machinery/light/small{dir = 8},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"jf" = (/obj/structure/lattice,/turf/space,/area/errant_pisces/live_storage) +"jg" = (/obj/structure/lattice,/mob/living/simple_animal/hostile/carp,/turf/space,/area/errant_pisces/live_storage) +"jh" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"ji" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"jj" = (/obj/structure/iv_drip,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jk" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jl" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jm" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jn" = (/obj/machinery/bodyscanner,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jo" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jp" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jq" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jr" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"js" = (/obj/structure/table/standard,/obj/item/weapon/material/kitchen/utensil/fork/plastic,/obj/random/snack,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"jt" = (/obj/structure/table/marble,/obj/machinery/microwave,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"ju" = (/obj/structure/table/marble,/obj/machinery/reagentgrinder,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"jv" = (/obj/effect/landmark/corpse/carp_fisher,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"jw" = (/obj/structure/closet/secure_closet/freezer/meat,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"jx" = (/obj/structure/lattice,/obj/machinery/light/small{dir = 8},/turf/space,/area/errant_pisces/live_storage) +"jy" = (/obj/machinery/access_button/airlock_exterior{frequency = 1021; master_tag = "xyn_ls_airlock"; pixel_x = -25; pixel_y = 0},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"jz" = (/turf/simulated/wall/r_wall,/area/errant_pisces/science_wing) +"jA" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"jB" = (/obj/machinery/light/small,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jC" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/freezer,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jD" = (/obj/structure/table/standard,/obj/random/firstaid,/obj/item/clothing/under/rank/medical/paramedic,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jE" = (/obj/structure/table/standard,/obj/item/roller,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jF" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jG" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"jH" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jI" = (/obj/item/weapon/stool,/obj/machinery/alarm{dir = 1; pixel_y = -25; req_one_access = list(24,11)},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jJ" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/item/weapon/stool,/obj/structure/cable/green,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jK" = (/obj/structure/table/standard,/obj/item/weapon/material/kitchen/utensil/fork,/obj/machinery/light,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"jL" = (/obj/machinery/vending/dinnerware,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"jM" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"jN" = (/obj/machinery/cooker/oven,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"jO" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"jP" = (/obj/structure/closet/secure_closet/freezer/kitchen{req_access = newlist()},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"jQ" = (/obj/machinery/door/airlock/external{frequency = 1021; id_tag = "xyn_ls_outer"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"jR" = (/obj/structure/lattice,/turf/space,/area/errant_pisces/science_wing) +"jS" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"jT" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/structure/closet,/obj/item/clothing/under/carp,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"jU" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"jV" = (/obj/structure/table/standard,/obj/item/weapon/paper_bin,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"jW" = (/obj/machinery/photocopier,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"jX" = (/obj/structure/filingcabinet/chestdrawer,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"jY" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"jZ" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"ka" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{frequency = 1021; id_tag = "xyn_ls_pump"},/obj/machinery/light/small{dir = 4},/obj/machinery/airlock_sensor{frequency = 1019; id_tag = "xyn_ls_sensor"; pixel_x = -25; pixel_y = 0},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"kb" = (/obj/structure/lattice,/obj/machinery/light/small{dir = 8},/turf/space,/area/errant_pisces/science_wing) +"kc" = (/obj/structure/lattice,/mob/living/simple_animal/hostile/carp,/turf/space,/area/errant_pisces/science_wing) +"kd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"ke" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/structure/closet,/obj/item/clothing/suit/storage/toggle/labcoat/genetics,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kf" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kg" = (/obj/structure/bed/chair/office/dark{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kh" = (/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"ki" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kj" = (/turf/simulated/wall/r_wall,/area/errant_pisces/cryo) +"kk" = (/obj/machinery/sleeper{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kl" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"km" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/structure/window/basic{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kn" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"ko" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kp" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kq" = (/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/structure/window/basic{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kr" = (/obj/machinery/sleeper{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"ks" = (/turf/simulated/wall/r_wall,/area/errant_pisces/general_storage) +"kt" = (/turf/simulated/wall/r_wall,/area/errant_pisces/prod_storage) +"ku" = (/obj/machinery/door/airlock/external{frequency = 1021; id_tag = "xyn_ls_inner"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"kv" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kw" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kx" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"ky" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kz" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kA" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/machinery/light{dir = 1},/obj/structure/bookcase,/obj/item/weapon/book/manual/anomaly_testing,/obj/item/weapon/book/manual/anomaly_spectroscopy,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kB" = (/obj/structure/bookcase,/obj/item/weapon/book/manual/mass_spectrometry,/obj/item/weapon/book/manual/research_and_development,/obj/item/weapon/book/manual/engineering_guide,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kC" = (/obj/structure/bookcase,/obj/item/weapon/book/manual/materials_chemistry_analysis,/obj/item/weapon/book/manual/hydroponics_pod_people,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kD" = (/obj/machinery/vending/assist,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kE" = (/obj/machinery/light{dir = 1},/obj/structure/bed/chair/office/dark{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kF" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kG" = (/obj/structure/closet,/obj/item/clothing/suit/storage/toggle/labcoat/blue,/obj/random/coin,/obj/random/coin,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kH" = (/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kI" = (/obj/structure/closet,/obj/item/clothing/suit/apron/overalls,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kJ" = (/obj/structure/window/basic{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kK" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kL" = (/obj/structure/window/basic{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kM" = (/obj/structure/closet,/obj/item/clothing/suit/storage/toggle/labcoat/xyn_machine,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kN" = (/obj/structure/closet,/obj/item/clothing/suit/apron/overalls,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kO" = (/obj/structure/closet/crate/freezer/rations,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"kP" = (/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"kQ" = (/obj/structure/table/rack,/obj/item/weapon/material/hatchet/tacknife,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"kR" = (/obj/structure/table/rack,/obj/item/weapon/material/harpoon,/obj/random/tool,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"kS" = (/obj/structure/table/rack,/obj/item/weapon/storage/box/survival,/obj/item/weapon/storage/box/survival,/obj/item/weapon/storage/box/survival,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"kT" = (/turf/simulated/wall,/area/errant_pisces/general_storage) +"kU" = (/obj/structure/closet/secure_closet/freezer/fridge,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"kV" = (/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"kW" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"kX" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"kY" = (/obj/machinery/light/small{dir = 1},/obj/structure/window/basic{dir = 8},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"kZ" = (/obj/item/weapon/reagent_containers/chem_disp_cartridge/synaptizine,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"la" = (/turf/simulated/wall,/area/errant_pisces/prod_storage) +"lb" = (/obj/machinery/suit_storage_unit/standard_unit,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"lc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1021; id_tag = "xyn_ls_airlock"; pixel_x = 25; pixel_y = 0; tag_airpump = "xyn_ls_pump"; tag_chamber_sensor = "xyn_ls_sensor"; tag_exterior_door = "xyn_ls_outer"; tag_interior_door = "xyn_ls_inner"},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"ld" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/table/rack,/obj/item/weapon/material/harpoon,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"le" = (/obj/effect/landmark/corpse/scientist,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lf" = (/obj/structure/table/rack,/obj/item/weapon/gun/launcher/net,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lg" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lh" = (/obj/machinery/light/small{dir = 8},/obj/structure/closet/crate/freezer/rations,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"li" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"lj" = (/obj/structure/closet/secure_closet/freezer/fridge,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"lk" = (/obj/structure/closet/secure_closet/freezer/fridge,/obj/item/weapon/reagent_containers/food/snacks/cubancarp,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"ll" = (/obj/structure/window/basic{dir = 8},/obj/item/weapon/reagent_containers/chem_disp_cartridge/hyperzine,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"lm" = (/obj/structure/closet/crate,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"ln" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"lo" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"lp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/structure/closet/firecloset,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lq" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lr" = (/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"ls" = (/turf/simulated/wall,/area/errant_pisces/science_wing) +"lt" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lu" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/freezer,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lv" = (/obj/structure/table/standard,/obj/item/weapon/storage/toolbox/mechanical,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lw" = (/obj/structure/table/standard,/obj/item/weapon/storage/toolbox/electrical,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lx" = (/obj/structure/table/standard,/obj/item/weapon/tape_roll,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"ly" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/gloves,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lz" = (/obj/structure/closet,/obj/item/clothing/suit/storage/toggle/labcoat/xyn_machine,/obj/random/advdevice,/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"lA" = (/obj/structure/closet,/obj/random/loot,/obj/random/soap,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"lB" = (/obj/structure/closet,/obj/item/clothing/under/hazard,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"lC" = (/obj/structure/closet,/obj/item/clothing/suit/apron/overalls,/obj/random/glasses,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"lD" = (/obj/structure/table/rack,/obj/item/weapon/storage/toolbox/mechanical,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"lE" = (/obj/structure/table/rack,/obj/item/weapon/storage/ore,/obj/random/tool,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"lF" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/empty,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"lG" = (/obj/item/weapon/reagent_containers/chem_disp_cartridge/mercury,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"lH" = (/obj/machinery/portable_atmospherics/canister/empty/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"lI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"lJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"lK" = (/obj/structure/closet/l3closet/scientist,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lL" = (/obj/structure/closet/secure_closet/scientist{req_one_access = newlist()},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lM" = (/obj/structure/closet/secure_closet/hydroponics,/obj/structure/window/reinforced{dir = 1; health = 1e+006},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lN" = (/obj/machinery/door/window/northright,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lO" = (/obj/machinery/vending/hydronutrients,/obj/structure/window/reinforced{dir = 1; health = 1e+006},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lP" = (/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/machinery/chem_master,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lQ" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/table/standard,/obj/machinery/reagentgrinder,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lR" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/table/standard,/obj/item/weapon/book/manual/mass_spectrometry,/obj/item/device/mass_spectrometer,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lS" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/window/northright,/turf/simulated/floor/tiled/white,/area/errant_pisces/science_wing) +"lT" = (/obj/structure/table/steel,/obj/item/weapon/storage/firstaid/surgery,/obj/item/weapon/material/knife/butch,/obj/item/weapon/material/twohanded/fireaxe,/obj/structure/window/reinforced{dir = 1},/turf/simulated/floor/tiled/white,/area/errant_pisces/science_wing) +"lU" = (/obj/vehicle/train/cargo/engine,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"lV" = (/obj/vehicle/train/cargo/trolley,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"lW" = (/obj/structure/closet/secure_closet/freezer/fridge,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"lX" = (/obj/structure/window/basic{dir = 8},/obj/structure/closet/crate,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"lY" = (/obj/structure/closet/crate,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"lZ" = (/obj/structure/closet/secure_closet/freezer/meat,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"ma" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"mb" = (/obj/structure/lattice,/obj/machinery/access_button/airlock_exterior{frequency = 1015; master_tag = "xyn_sci_airlock"; pixel_y = -20},/turf/space,/area/errant_pisces/science_wing) +"mc" = (/obj/machinery/door/airlock/external{frequency = 1015; id_tag = "xyn_sci_outer"},/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"md" = (/obj/machinery/light/small{dir = 1},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1015; id_tag = "xyn_sci_pump"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1015; id_tag = "xyn_sci_airlock"; pixel_x = 0; pixel_y = -25; tag_airpump = "xyn_sci_pump"; tag_chamber_sensor = "xyn_sci_sensor"; tag_exterior_door = "xyn_sci_outer"; tag_interior_door = "xyn_sci_inner"},/obj/machinery/airlock_sensor{frequency = 1015; id_tag = "xyn_sci_sensor"; pixel_y = 25},/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"me" = (/obj/machinery/door/airlock/external{frequency = 1015; id_tag = "xyn_sci_inner"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"mf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/machinery/access_button/airlock_interior{frequency = 1015; master_tag = "xyn_sci_airlock"; pixel_x = -25; pixel_y = -25},/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"mg" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"mh" = (/obj/structure/closet/l3closet/scientist,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mi" = (/obj/structure/closet/secure_closet/scientist{req_one_access = newlist()},/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mj" = (/obj/machinery/portable_atmospherics/hydroponics,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mk" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"ml" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/chemical_dispenser/full,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mm" = (/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mn" = (/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/tiled/white,/area/errant_pisces/science_wing) +"mo" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/machinery/computer/operating,/turf/simulated/floor/tiled/white,/area/errant_pisces/science_wing) +"mp" = (/obj/structure/closet,/obj/item/clothing/suit/storage/hooded/wintercoat,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"mq" = (/obj/structure/closet,/obj/random/plushie,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"mr" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"ms" = (/obj/structure/table/rack,/obj/item/stack/net/thirty,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"mt" = (/obj/machinery/light/small{dir = 4},/obj/structure/table/rack,/obj/item/stack/net,/obj/random/snack,/obj/random/tool,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"mu" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mv" = (/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mw" = (/obj/structure/window/basic{dir = 8},/obj/structure/closet/crate,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mx" = (/obj/structure/table/rack,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/obj/item/weapon/material/harpoon,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"my" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"mz" = (/turf/simulated/wall/r_wall,/area/errant_pisces/aft_hallway) +"mA" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"mB" = (/obj/machinery/suit_storage_unit/standard_unit,/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"mC" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mD" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/structure/closet/secure_closet/scientist{req_one_access = newlist()},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mE" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mF" = (/obj/structure/window/reinforced{dir = 8},/obj/structure/table/standard,/obj/item/weapon/storage/box/beakers,/obj/item/weapon/reagent_containers/dropper,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mG" = (/obj/machinery/biogenerator,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mH" = (/obj/structure/window/reinforced{dir = 4},/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mI" = (/obj/machinery/optable,/obj/item/clothing/glasses/welding,/obj/item/weapon/weldingtool,/turf/simulated/floor/tiled/white,/area/errant_pisces/science_wing) +"mJ" = (/obj/machinery/light,/obj/effect/landmark/corpse/carp_fisher,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"mK" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"mL" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"mM" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"mN" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/machinery/alarm{dir = 1; pixel_y = -22},/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"mO" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"mP" = (/obj/machinery/alarm{dir = 1; pixel_y = -22},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mQ" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; operating = 1; pixel_y = -24},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mR" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mS" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/machinery/light/small,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mT" = (/obj/machinery/light/small,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mU" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/obj/structure/table/rack,/obj/item/weapon/gun/launcher/net,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"mV" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"mW" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"mX" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mY" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"mZ" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"na" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"nb" = (/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock/freezer,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"nc" = (/turf/simulated/wall,/area/errant_pisces/live_storage) +"nd" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"ne" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/light/small{dir = 1},/obj/machinery/access_button/airlock_interior{frequency = 1017; master_tag = "xyn_dock1_airlock"; pixel_x = 0; pixel_y = 25},/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"nf" = (/obj/machinery/door/airlock/external{frequency = 1017; id_tag = "xyn_dock1_inner"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"ng" = (/obj/machinery/light/small{dir = 1},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1017; id_tag = "xyn_dock1_pump"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1017; id_tag = "xyn_dock1_airlock"; pixel_x = 0; pixel_y = -25; tag_airpump = "xyn_dock1_pump"; tag_chamber_sensor = "xyn_dock1_sensor"; tag_exterior_door = "xyn_dock1_outer"; tag_interior_door = "xyn_dock1_inner"},/obj/machinery/airlock_sensor{frequency = 1017; id_tag = "xyn_dock1_sensor"; pixel_y = 25},/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"nh" = (/obj/machinery/door/airlock/external{frequency = 1017; id_tag = "xyn_dock1_outer"},/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"ni" = (/obj/machinery/access_button/airlock_exterior{frequency = 1017; master_tag = "xyn_dock1_airlock"; pixel_x = -25; pixel_y = -25},/turf/simulated/floor/plating,/area/space) +"nj" = (/turf/simulated/floor/plating,/area/space) +"nk" = (/turf/simulated/wall/r_wall,/area/errant_pisces/aux_power) +"nl" = (/obj/machinery/power/port_gen/pacman/mrs,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"nm" = (/obj/machinery/power/terminal{dir = 4},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"nn" = (/obj/machinery/power/smes/buildable,/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"no" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"np" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nq" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nr" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"ns" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nt" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nu" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nv" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nw" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nx" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"ny" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nz" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nA" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nB" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nC" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nE" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nF" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nG" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nH" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nI" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nJ" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"nK" = (/obj/machinery/power/port_gen/pacman/mrs,/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"nL" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"nM" = (/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"nN" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"nO" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nP" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nR" = (/obj/effect/landmark/corpse/scientist,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nS" = (/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nT" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nU" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; operating = 1; pixel_y = -24},/obj/structure/cable/green,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nV" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nW" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nX" = (/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nY" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nZ" = (/obj/machinery/door/firedoor,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"oa" = (/obj/effect/landmark/corpse/bridgeofficer,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"ob" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"oc" = (/obj/machinery/power/terminal,/obj/structure/cable/yellow,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"od" = (/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"oe" = (/obj/structure/closet/crate/radiation,/obj/item/stack/material/tritium/ten,/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/green,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"of" = (/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"og" = (/turf/simulated/wall/r_wall,/area/errant_pisces/fishing_wing) +"oh" = (/obj/machinery/door/airlock/freezer,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oi" = (/turf/simulated/wall/r_wall,/area/errant_pisces/bridge) +"oj" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"ok" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/access_button/airlock_interior{frequency = 1019; master_tag = "xyn_dock2_airlock"; pixel_x = 0; pixel_y = -25},/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"ol" = (/obj/machinery/door/airlock/external{frequency = 1019; id_tag = "xyn_dock2_inner"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"om" = (/obj/machinery/light/small{dir = 1},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1019; id_tag = "xyn_dock2_airlock"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1019; id_tag = "xyn_dock2_airlock"; pixel_x = 0; pixel_y = -25; tag_airpump = "xyn_dock2_pump"; tag_chamber_sensor = "xyn_dock2_sensor"; tag_exterior_door = "xyn_dock2_outer"; tag_interior_door = "xyn_dock2_inner"},/obj/machinery/airlock_sensor{frequency = 1019; id_tag = "xyn_dock2_sensor"; pixel_y = 25},/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"on" = (/obj/machinery/door/airlock/external{frequency = 1019; id_tag = "xyn_dock2_outer"},/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"oo" = (/obj/machinery/access_button/airlock_exterior{frequency = 1019; master_tag = "xyn_dock2_airlock"; pixel_x = -25; pixel_y = -25},/turf/simulated/floor/plating,/area/space) +"op" = (/obj/machinery/power/smes/buildable,/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"oq" = (/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"or" = (/obj/structure/table/rack,/obj/item/weapon/wrench,/obj/item/weapon/screwdriver,/obj/item/weapon/wirecutters,/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"os" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"ot" = (/turf/simulated/wall,/area/errant_pisces/fishing_wing) +"ou" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"ov" = (/obj/structure/table/marble,/obj/item/weapon/material/knife/butch,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"ow" = (/obj/machinery/gibber,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"ox" = (/obj/structure/table/marble,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oy" = (/obj/machinery/gibber,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oz" = (/obj/structure/table/marble,/obj/item/weapon/gun/launcher/net,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oA" = (/obj/structure/sink{dir = 1; pixel_y = 16},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oB" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oC" = (/obj/structure/closet/crate,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oD" = (/obj/random/obstruction,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oE" = (/obj/machinery/door/airlock/freezer,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oF" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/landmark/corpse/bridgeofficer,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oH" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"oI" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/alarm{alarm_id = "petrov1"; dir = 4; pixel_x = -25; pixel_y = 0; rcon_setting = 3},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"oJ" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/machinery/alarm{alarm_id = "petrov1"; dir = 4; pixel_x = -25; pixel_y = 0; rcon_setting = 3},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oK" = (/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oL" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable/green,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oM" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/structure/closet/firecloset,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oN" = (/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oO" = (/obj/structure/table/steel,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oP" = (/obj/machinery/light{dir = 1},/obj/structure/table/steel,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oQ" = (/obj/structure/bookcase/manuals/engineering,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oR" = (/obj/structure/bookcase/manuals/research_and_development,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oS" = (/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oT" = (/obj/structure/bed/chair/comfy/captain,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oU" = (/obj/machinery/light{dir = 1},/obj/structure/reagent_dispensers/water_cooler,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oV" = (/obj/machinery/door/airlock,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"oW" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"oX" = (/obj/machinery/light{dir = 1},/obj/structure/closet,/obj/item/weapon/gun/projectile/shotgun/pump/combat,/obj/item/weapon/lipstick/random,/obj/random/ammo,/obj/random/cash,/obj/random/cash,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"oY" = (/obj/item/modular_computer/console,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"oZ" = (/obj/machinery/vending/medical{req_access = newlist()},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pa" = (/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pb" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/landmark/corpse/carp_fisher,/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pc" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pd" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/light{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pe" = (/obj/structure/closet/crate/secure/biohazard,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"pf" = (/obj/structure/net,/turf/space,/area/space) +"pg" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"ph" = (/obj/random/tool,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pi" = (/obj/machinery/computer/navigation,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pj" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pk" = (/obj/structure/table/steel,/obj/random/toy,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pl" = (/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"pm" = (/obj/structure/bed/chair/office/light{dir = 4},/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"pn" = (/obj/structure/table/woodentable,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"po" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/bridge) +"pp" = (/obj/machinery/door/blast/regular/open{dir = 2; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/turf/simulated/floor/reinforced/airless,/area/errant_pisces/bridge) +"pq" = (/obj/structure/lattice,/obj/structure/grille,/turf/space,/area/errant_pisces/bridge) +"pr" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"ps" = (/obj/structure/cable/green,/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pt" = (/obj/structure/kitchenspike,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"pu" = (/obj/structure/kitchenspike,/obj/machinery/light/small,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"pv" = (/obj/machinery/light/small,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"pw" = (/obj/structure/net/net_wall,/turf/space,/area/space) +"px" = (/obj/machinery/alarm{alarm_id = "petrov1"; dir = 4; pixel_x = -25; pixel_y = 0; rcon_setting = 3},/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"py" = (/obj/random/junk,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pz" = (/obj/effect/overmap/ship/errant_pisces,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pA" = (/obj/structure/table/steel,/obj/random/snack,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pB" = (/obj/structure/bookcase/manuals/engineering,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"pC" = (/obj/structure/table/woodentable,/obj/random/toy,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"pD" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled/white,/area/errant_pisces/fishing_wing) +"pE" = (/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/tiled/white,/area/errant_pisces/fishing_wing) +"pF" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled/white,/area/errant_pisces/fishing_wing) +"pG" = (/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pH" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pI" = (/obj/machinery/door/airlock/freezer,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"pJ" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/structure/table/steel,/obj/random/snack,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pK" = (/obj/structure/table/steel,/obj/random/firstaid,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pL" = (/obj/structure/bed/chair/office/dark,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pM" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/structure/table/steel,/obj/random/handgun,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pN" = (/obj/structure/curtain/open/bed,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"pO" = (/obj/machinery/shower{dir = 1},/turf/simulated/floor/tiled/white,/area/errant_pisces/fishing_wing) +"pP" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pQ" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pR" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pS" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pT" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pU" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pV" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pW" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pX" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pY" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pZ" = (/obj/structure/net,/mob/living/simple_animal/hostile/carp,/turf/space,/area/space) +"qa" = (/obj/machinery/computer/sensors,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qb" = (/obj/structure/bed/chair/office/dark{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qc" = (/obj/structure/table/steel,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qd" = (/obj/structure/table/steel,/obj/random/toolbox,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qe" = (/obj/structure/table/steel,/obj/random/advdevice,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qf" = (/obj/structure/table/steel,/obj/machinery/button/remote/blast_door{id = "xynergy_perimeter_blast"; name = "perimeter blast door-control"},/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qg" = (/obj/machinery/computer/helm,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qh" = (/obj/machinery/computer/engines,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qi" = (/obj/item/weapon/bedsheet/captain,/obj/structure/bed/padded,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"qj" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/structure/table/rack,/obj/item/weapon/gun/projectile/shotgun/pump,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qk" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"ql" = (/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qm" = (/obj/structure/closet/l3closet/janitor,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qn" = (/obj/structure/table/rack,/obj/item/clothing/mask/breath,/obj/item/weapon/storage/box/survival,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qo" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qp" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/machinery/suit_storage_unit/standard_unit,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qq" = (/obj/structure/janitorialcart,/obj/item/weapon/mop,/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"qr" = (/obj/machinery/light{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"qs" = (/obj/machinery/light/small{dir = 8},/obj/structure/table/rack,/obj/item/weapon/gun/launcher/net,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qt" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/random/contraband,/obj/structure/closet/l3closet/janitor,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qu" = (/obj/structure/table/rack,/obj/item/weapon/tank/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qv" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qw" = (/obj/machinery/suit_storage_unit/standard_unit,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qx" = (/obj/machinery/shipsensors,/turf/simulated/floor/reinforced/airless,/area/errant_pisces/bridge) +"qy" = (/obj/structure/closet/firecloset,/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"qz" = (/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"qA" = (/obj/structure/table/rack,/obj/item/weapon/gun/launcher/net,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qB" = (/obj/structure/closet,/obj/random/smokes,/obj/random/drinkbottle,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qC" = (/obj/structure/lattice,/turf/simulated/wall/r_wall,/area/errant_pisces/bridge) +"qD" = (/obj/structure/table/rack,/obj/item/weapon/material/hatchet/tacknife,/obj/item/weapon/material/hatchet/tacknife,/obj/item/stack/net/thirty,/obj/item/stack/net/thirty,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qE" = (/obj/structure/closet,/obj/random/smokes,/obj/random/snack,/obj/random/tank,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qF" = (/obj/structure/table/rack,/obj/item/weapon/storage/box/survival,/obj/item/stack/net/thirty,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qG" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/machinery/suit_storage_unit/standard_unit,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qH" = (/obj/structure/grille,/turf/space,/area/space) +"qI" = (/obj/machinery/light/small{dir = 8},/obj/structure/table/rack,/obj/item/weapon/material/harpoon,/obj/item/weapon/material/harpoon,/obj/item/weapon/material/harpoon,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qJ" = (/obj/structure/closet,/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/random/gloves,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qK" = (/obj/structure/table/rack,/obj/item/clothing/mask/breath,/obj/item/device/flashlight,/obj/item/stack/net/thirty,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qL" = (/obj/effect/landmark/corpse/carp_fisher,/obj/effect/decal/cleanable/blood,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qM" = (/turf/simulated/wall/r_wall,/area/space) +"qN" = (/obj/structure/bed/chair,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qO" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qP" = (/obj/effect/decal/cleanable/blood,/obj/machinery/access_button/airlock_interior{frequency = 1023; master_tag = "xyn_fish_airlock"; pixel_x = 25; pixel_y = -25},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qQ" = (/obj/machinery/door/airlock/external{frequency = 1023; id_tag = "xyn_fish_inner"},/obj/machinery/door/firedoor,/obj/effect/decal/cleanable/blood,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qR" = (/obj/machinery/light/small{dir = 1},/obj/effect/decal/cleanable/blood,/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1023; id_tag = "xyn_fish_airlock"; pixel_x = 0; pixel_y = -25; tag_airpump = "xyn_fish_pump"; tag_chamber_sensor = "xyn_fish_sensor"; tag_exterior_door = "xyn_fish_outer"; tag_interior_door = "xyn_fish_inner"},/obj/machinery/airlock_sensor{frequency = 1023; id_tag = "xyn_fish_sensor"; pixel_y = 25},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1023; id_tag = "xyn_fish_pump"},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qS" = (/obj/machinery/door/airlock/external{frequency = 1023; id_tag = "xyn_fish_outer"},/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/space) +"qT" = (/obj/structure/net,/obj/machinery/access_button/airlock_exterior{frequency = 1019; master_tag = "xyn_dock2_airlock"; pixel_x = -25; pixel_y = -25},/turf/space,/area/space) +"qU" = (/obj/structure/bed/chair{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qV" = (/obj/structure/table/steel,/obj/random/smokes,/obj/item/weapon/flame/lighter,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qW" = (/obj/structure/table/steel,/obj/random/snack,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qX" = (/obj/structure/bed/chair{dir = 8},/obj/item/weapon/flame/match,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qY" = (/obj/structure/dispenser/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qZ" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"ra" = (/obj/structure/net,/obj/item/weapon/material/hatchet/tacknife,/turf/space,/area/space) +"rb" = (/obj/structure/net,/obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh,/turf/space,/area/space) +"rc" = (/obj/structure/net,/mob/living/simple_animal/hostile/carp/shark,/turf/space,/area/space) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaababaaaaaaabacacaaaaaaacacaaaaaaacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababadadadababadadadabacacaeaeaeacacaeaeaeacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababafagahahaiaiahahahajacakalalalamamalalanaoacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababapaqaqaqaqaqaqaqaqaqaracasatatatatatatatatatauacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababavawaxaxaxaxaxaxaxaxaxayacazaAaAaAaAaAaAaAaAaAaBaCacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaDaEaFaGaHaHaHaHaHaIaJaJaKaLaMaNaNaOaPaPaPaPaPaQaRaSaTacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaUaVaVaVaVaVaVaVaVaVaVaVaVaVaWaWaWaWaWaXaYaYaYaYaYaYaYaYaYaYaYaYaZaZaZaZaZaZaZaZaZaZaZbabbbbbbbbbbaVaVaVaVaVaVaVaVaVaVaVaVaVaUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaaaabcaaaaaabcaaaaaabcaaaaaWaWbdbeaWbfaYbgbgbgbgbhbibjbjbjbjbkaZblbmbnbobpbnbqbrbraZbfbbbsbtbbbbaaaabcaaaaaabcaaaaaabcaaaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubvbwaabubvbwaabubvbwaaaWaWbdbxaWbyaYbzbAbAbAbAbBbCbDbEbFbGaZbHbIbmbJbKbnbLbMbNaZbObbbPbtbbbbaabQbvbRaabQbvbRaabQbvbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubSbwaabubSbwaabubSbwaaaWaWbdbTaWbfaYbUbUbUbUbVbWbkbkbXbYbZaZcacbcbccbnbnbnbncdaZbfbbcebtbbbbaabQbSbRaabQbSbRaabQbSbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVbcbubSbwbcbubSbwbcbubSbwbcaWaWbdbTaWbfaYcfbYcgchbVcicjckclcmbZaZcnbnbnbnbncocpbncqaZbfbbcrbtbbbbbcbQbSbRbcbQbSbRbcbQbSbRbcaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubSbwaabubSbwaabubSbwaaaWaWbdcsaWbfaYcfctcucvcwcxcyczclcAbZaZcBbncCbnbncDcEbncFaZbfbbcGcHbbbbaabQbSbRaabQbSbRaabQbSbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubSbwaabubSbwaabubSbwaaaWaWcIcJaWbyaYcKcLcuckcMcNcObkcPbkbGaZcQbncRbnbnbnbnbncSaZbObbcTcUbbbbaabQbSbRaabQbSbRaabQbSbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubSbwaabubSbwaabubSbwaaaWaWcVcWaWbfaYcXcycgcYcZdadbdbdcdddeaZdfdgdhdhdidjdkdkdkaZbfbbdldmbbbbaabQbSbRaabQbSbRaabQbSbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVbcbubSbwbcbubSbwbcbubSbwbcaWaWdnaWaWbfaYaYaYaYaYaYaYaYaYdoaYaYaZdpaZaZaZaZaZaZaZaZaZbfbbbbdqbbbbbcbQbSbRbcbQbSbRbcbQbSbRbcaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubSbwaabubSbwaabubSbwaadrdrdsdtdtdudtdtdtdtdtdtdtdtdtdvdwdtdtdxdtdtdtdtdtdtdtdtdtdydtdtdzdrdraabQbSbRaabQbSbRaabQbSbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubSbwaabubSbwaabubSbwdAdBdCdDdEdFdGdHdHdHdHdHdHdIdHdJdKdLdIdHdMdNdHdHdIdHdHdHdHdHdOdFdFdFdPdQaabQbSbRaabQbSbRaabQbSbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubSbwaabubSbwaabubSbwaadRdRdRdRdSdTdUdUdUdUdUdUdUdUdVdWdVdVdVdXdVdYdYdYdYdYdYdYdYdTdZeaeaeaeaaabQbSbRaabQbSbRaabQbSbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaebaaaaaaaaaaaaaaaVecedeeedededeeedededeeededefegehdReiejdUekelemeleneoepdVeqereseteudVevewexeyeweyezdYeAeieaeBeCeDededeEedededeEedededeEedeFaVaaaaaaaaaaaaaaaaebaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabueGbwaabueGbwaabueGbwaadRdReHdRdRdTdUeIeleJeKeLeJeJdVeMeNeOePeQdVeReReSeTeReyeUdYdTeaeaeVeaeaaabQeGbRaabQeGbRaabQeGbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabueGbwaabueGbwaabueGbwaadRdReWeXdRdTdUeIeYeJeZfaeoepdVfbfcfdfeffdVevewfgfheRfieUdYfjeafkfleaeaaabQeGbRaabQeGbRaabQeGbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabueGbwaabueGbwaabueGbwaafmfnfofpfqfrdUeIeleJfsfteJeJdVfufveqfwfxdVeReRfyfzeReyeUdYfAfBfCfDfEfFaabQeGbRaabQeGbRaabQeGbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVbcbueGbwbcbueGbwbcbueGbwbcdRdRfGfHdRfIdUeIeleJfsfJeoepdVfKerfLfMfNdVfOfOfPfQeReyeUdYfIeafRfSeaeabcbQeGbRbcbQeGbRbcbQeGbRbcaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabueGbwaabueGbwaabueGbwaadRdRdRdRdRfTdUeJeJeJeJfUeJeJdVdVdVfVdVdVdVeReRfWeReReReRdYfTeaeaeaeaeaaabQeGbRaabQeGbRaabQeGbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabueGbwaabueGbwaabueGbwaafXfXfYfZfZgagbgbgbgbgbgcgdgdgdgdgdgegdgdgdgdgdgfgbgbgbgbgbggfZfZghfXfXaabQeGbRaabQeGbRaabQeGbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabueGbwaabueGbwaabueGbwaagigigjgjgjgjgjgjgjgjgjgjgjgjgjgjgkglgmgngngngngngngngngngngngngngngogoaabQeGbRaabQeGbRaabQeGbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVbcbueGbwbcbueGbwbcbueGbwbcgigigpgqgrgjgsgqgrgjgtgqgugvgwgxgygzgAgBgCgDgEgngFgGgHgngIgngJgngJgogobcbQeGbRbcbQeGbRbcbQeGbRbcaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabueGbwaabugKbwaabugKbwaagigigLgMgNgjgOgqgPgjgQgqgqgqgRgxfZgSfZgBgTgUgVgngWgUgXgngYgngYgngYgogoaabQeGbRaabQeGbRaabQeGbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabugKbwaaaabcaaaaaabcaaaagigigZgqhagjhbgqhcgjhdgqhegqhfhghhhihhhjhkhlhmhngUgUgUgUgUgUgUgUhogogoaahpgKbRaahpgKbRaahpgKbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaaaabcaaaaaahqhqhqhqhqhqhqhqgigjhrgjgjgjhrgjgjgtgqhsgqhtgxfZgSfZgBhugUhvgnhwgUgFgngYgngYgngYgogoaaaabcaaaaaabcaaaaaabcaaaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahqhqhqhqhqhqhqhqhqhqhqhqhqhqhqgigqhxhxhyhxgqhxhxgqhxgqhzhAgxfZgSfZgBhBgUhCgngFhDhwgnhEgngIgngJgohFhFhFhFhFhFhFhFhFhFhFhFhFhFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahqhqhqhqhqhqhqhqhqhGhHhIhJhKhLhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIfZgShMgnhNgUhOgngngngngngngngngngngohFhFhFhFhFhFhFhFhFhFhFhFhFhFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahqhqhPhIhQhQhQhQhqhRhShIhThUhVhIhWhXhWhIhYhZhYiaibicibidieiffZgSfZgBigihiiijijiiikilimilinioiogohFipipiqiripipisiripitipiphFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahqhqiuiviwhSiwixhqhIiyhIhIhIizhIiAiBiAhIibiCibiCibhIiDhYiEiffZgSfZgBgUgUiiiFijiiiliGiliHgniIiJgohFhFiKhFhFhFiLhFhFiMhFhFiphFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahqhqiNhSiOiwiPiQiRiSiSiTiSiUiViSiSiSiSiWiSiXiYiZjahIjbjcjciffZgSfZhngUgUgUgUgUilgUjdgUjdgnjeiJgohFjfjfjfhFjfjgjfhFjfjfhFjhhFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahqhqhqhqhqhqhqjihqhqhqhqhqhqhqhqiAiBiAhIjjjkjljmjnhIjoiXjpjqgdjrfZgBgUiiijjsiigUgUjtgUjugnjvjwgohFjxjfjghFjxjfjghFjxjfhFjyhFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjzjzjzjzjzjAjzjzjzjzjzjzjzhqhWjBhWhIjCjDjEjFiSjGjHjIjJiffZgSfZgBgUiijKijiigUgUjLjMjNgnjOjPgohFjfjgjfhFjfjgjfhFjfjghFjQhFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjRjRjRjzjzjSjTjUjUjVjWjXjzhqhqhqhqhqhqhqhqhqhqhqhqhqhqhqjYjZjYgogogogogogogogogogogogogogogohFhFhFhFhFhFhFhFhFhFhFhFkahFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzkbkcjRjzjzkdkekfkgkhkhkijzjzjzjzjzjzjzjzjzjzjzkjkkklkkkmknkokpkqkrklkrkjksksksksksksksktktktktktktktktktktktktktkthFkuhFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjRjRkcjzjzkvkwkwkxkxkxkxkykzkAkBkCkDkfkEkhkFjzkjkGkHkIkJkHkKkHkLkMkHkNkjkOkOkPkQkRkSkTkUkVkWkWkXkUkWkVkWkYkVkZkVlalblchFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjRjRjRjzjzldlelfjXjXkhjXjzlgkhkhkhkhkhkhkhkFjzkjkkkHkkkJkHkKkHkLkrkHkrkjlhkOkPkPkPlikTljkVkUlkkVkWkUkVkUlllmkVlnlalblohFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjRkcjRjzjzlplqlrlslsltlsjzlukhlvlwkhlxlykhkFjzkjlzkHlAkJkHkKkHkLlBkHlCkjkOkOkPlDlElFkTkWkVkUkWkVkUkWkVkWllkVlmlGlalHlIhFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzkbjRjRjzjzjzlJjzjzlKkhlLjzlMlNlOlPlNlQlRlSlTjzkjkkkHkkkJkHkKkHkLkrkHkrkjlUlVkPkPkPkPkTkWkVkWkUkVlWkWkVkUlXkVkVlYlalZmahFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjRjRmbmcmdmemfmgjzmhkhmijzmjkhmkmlkhkhmmmnmojzkjkNkHmpkJkHkKkHkLmqkHlBkjmrkPkPmsmsmtkTmukVkVkVkVkVmvkVkVmwkVlYlnlamxmyhFhFmzmzmzmzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjzjzjzjzjzjzmAmBjzlKmCmDjzmjmEmkmFmEmGmHmnmIjzkjkHkHkHmJmKkKkHmLkHkHkHkjmMmNkPkPkPkPmOkVkVmPmQmRmSkVkVkVmTkVkVkVlamUmVhFhFmzmzmzmzbcbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjzjzjzjzjzjzmWjzjzjzmXjzjzjzjzjzjzjzjzjzjzjzjzkjkjkjkjkjmYmZjYkjkjkjkjkjnakTkTkTkTkTkTlalalalanblalalalalalalalalancndhFhFnenfngnhninjbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanknknlnmnnnknonpnqnpnrnsntnpnpnrnpnpnpnpnpnrnpnpnunpnvnvnwnxnynznAnvnwnvnvnBnCnvnDnEnBnvnvnvnvnwnvnFnvnvnvnvnwnvnvnvnvnDnGnHnInJmzmzmzbcbcbcaaaaaaaaaaaaaaaaebaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanknknKnLnMnNnOnPnQnRnSnSnSnSnSnSnSnSnSnSnSnSnSnSnTnSnSnSnSnUnVnSnWnSnSnSnSnXnSnSnSnYnZnPnPnSnSnSnSoanSnSnSnSnSnSnSnSnSnSnSnSnTobmzmzmzbcbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanknkocodoenkofogohogogogogogogogogogogogogogogmzmzmzmzmzmzmzmzmzmzmzmzmzmzmzmzoioiojoioioioioioioioioioioioioioioioioioioioioiokolomonoonjbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanknkopoqornkosotouovowoxoyozoAoBoCoDoEoBoFogogmzmzmzmzmzmzmzmzmzmzmzmzmzmzmzmzoioioGoioioioioioioioioioioioioioioioioioioioioimzmzmzmzbcbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogoHogogoIotoJoKoKoKoCoKoCoCoKoCotoFogogogbcaaaaaaaaaaaabcaaaaaaaaaaaabcaaoioioLoMoNoOoPoQoRoSoSoToSoSoUoSoSoSoVoWoXoYoioimzmzmzmzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogoZpapbpcpdotoKoKoKpeoKoKoKoDoKpeotogogogaapfaaaaaaaaaaaapfaaaaaaaaaaaapfaaoioipgoSoSoSoSoSoSphpipjpjoSoSoSoSpkoiplpmpnpopppqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogotototprpsotoKptpuptptptoDpvpeoDogogogbcpfpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwbcoioipxoSoSoSpyoSoSoSoSpzoSoSoSoSoSpAoiplpBpCpopppqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogpDpEpFpGpHogpIogogogogogogogogogogogaaaaaapwpfpfpfpfpfpfpfpfpfpfpfpfpfpwaaoioioipJpKoSoSoSoSoSoSpLoSoSoSoSpLpMoipNoioioioioiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogpOpOotpPpQpRpSpTpUpVpWpVpXpYogogogaaaaaaaapwpfpfpfpfpfpZpfpfpfpfpZpfpfpwaaaaoioioiqaqbqcqdqeqfpiqgqhqcpApjpjqcoiqioioioiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogototpGpGogqjqkqlqmotqnqoqpogogaaaaaaaaaapwpfpfpZpfpfpfpfpfpfpfpfpfpfpwaaaaaaoioipooipopopopopopopopopopopopooioioioiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogqqpGqrogqsqlqlqtotquqvqwogogaaaaaaaaaapwpfpfpfpfpfpfpfpfpZpfpfpfpfpwaaaaaaaaoiqxoippppppppppppppppppppppppoioioiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogqyqzogqAqlqlqBotquqvqwogogbcbcbcbcbcpwpfpfpfpfpfpfpfpfpfpfpfpfpfpwbcbcbcbcoippoipqpqpqpqpqpqpqpqpqpqpqpqqCbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogogogqDqlqlqEotqFqvqGogogaaaaaaaaaapwpfpfpfpfpfpfpZpfpfpfpfpfpfpwaaaaaaaaqHqHqHaaaaaaaaaaaaaaaaaaaaaaaabcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogogqIqlqlqJotqKqLqwogogqMpwpwpwaapwpfpfpfpfpZpfpfpfpfpfpZpfpfpwaaaaaaaabcbcbcaaaaaaaaaaaaaaaaaaaaaaaabcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogqlqNqlqlotqlqOqPqQqRqSqTpfpwaapwpfpZpfpfpfpfpfpfpfpfpfpfpfpwaaaaaaaabcaabcaaaaaaaaaaaaaaaaaaaaaaaabcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogqUqVqWqXotqYqZqZogogqMpwpfpwaapwpfpfpfpfpfpfpfpfpfpfpfpfpfpwaaaaaaaabcaabcaaaaaaaaaaaaaaaaaaaaaaaabcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogogogogogogogogogogaapwpfpwaapwpwpwpwpwpwpwpfpwpwpwpwpwpwpwaaaaaaaabcbcbcaaaaaaaaaaaaaaaaaaaaaaaabcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogogogogogogogogogogaapwpfpwaapfaaaaaaaaaapwpfpwaaaaaaaaaapfaaaaaaaabcaabcaaaaaaaaaaaaaaaaaaaaaaaabcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpfpfpfpfpfpwpwpwpwpwpwpwpfpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpfpfpfpfpfbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpfpfpfpfpwpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfrapfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwpwpfpfpfpfbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpfpfpfpwpwpfpfpfpfpfpfpfpfpfpfpfpfpfrbpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwpwpfpfpfbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpfpfpwpwpfpfpfpfrbpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfrbpfpfpfpfpfpfpfpfpfrcpfpfpfpfpwpwpfpfbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpfpwpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfrbpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwpwpfbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpwpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfrbpfpfpfpfrbpfpfpfrbpfpfpfrbpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwpwbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpwpfpfpfpfpfpfpfpfpfpfpfrcpfpfpfpfpfpfpfpfpfpfpwpfpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwpwpfpwpwpfpfpfpfpfrbpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwpwpfpfpfpwpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwpwpfpfpfrbpfpwpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpfpfpfpfpfpfpfpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaebaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaebaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaebaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/away/errant_pisces/errant_pisces.dm b/maps/away/errant_pisces/errant_pisces.dm new file mode 100644 index 00000000..101f7a6d --- /dev/null +++ b/maps/away/errant_pisces/errant_pisces.dm @@ -0,0 +1,244 @@ +#include "errant_pisces_areas.dm" + +/obj/effect/overmap/ship/errant_pisces + name = "XCV Ahab's Harpoon" + desc = "Sensors detect civilian vessel with unusual signs of life aboard." + color = "#bd6100" + vessel_mass = 150 + default_delay = 20 SECONDS + speed_mod = 10 SECONDS + burn_delay = 15 SECONDS + +/datum/map_template/ruin/away_site/errant_pisces + name = "Errant Pisces" + id = "awaysite_errant_pisces" + description = "Xynergy carp trawler" + suffixes = list("errant_pisces/errant_pisces.dmm") + cost = 1 + +/mob/living/simple_animal/hostile/carp/shark // generally stronger version of a carp that doesn't die from a mean look. Fance new sprites included, credits to F-Tang Steve + name = "cosmoshark" + desc = "Enormous creature that resembles a shark with magenta glowing lines along its body and set of long deep-purple teeth." + icon = 'maps/away/errant_pisces/errant_pisces_sprites.dmi' + icon_state = "shark" + icon_living = "shark" + icon_dead = "shark_dead" + icon_gib = "shark_dead" + turns_per_move = 8 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/sharkmeat + speed = 8 + maxHealth = 75 + health = 75 + harm_intent_damage = 20 + melee_damage_lower = 20 + melee_damage_upper = 20 + break_stuff_probability = 25 + faction = "shark" + +/mob/living/simple_animal/hostile/carp/shark/death() + ..() + var/datum/gas_mixture/environment = loc.return_air() + if (environment) + var/datum/gas_mixture/sharkmaw_phoron = new + sharkmaw_phoron.adjust_gas("phoron", 10) + environment.merge(sharkmaw_phoron) + visible_message("\The [src]'s body releases some gas from the gills with a quiet fizz!") + +/mob/living/simple_animal/hostile/carp/shark/AttackingTarget() + set waitfor = 0//to deal with sleep() possibly stalling other procs + . =..() + var/mob/living/L = . + if(istype(L)) + if(prob(25))//if one is unlucky enough, they get tackled few tiles away + L.visible_message("\The [src] tackles [L]!") + var/tackle_length = rand(3,5) + for (var/i = 1 to tackle_length) + var/turf/T = get_step(L.loc, dir)//on a first step of tackling standing mob would block movement so let's check if there's something behind it. Works for consequent moves too + if (T.density || LinkBlocked(L.loc, T) || TurfBlockedNonWindow(T) || DirBlocked(T, GLOB.flip_dir[dir])) + break + sleep(2) + forceMove(T)//maybe there's better manner then just forceMove() them + L.forceMove(T) + visible_message("\The [src] releases [L].") + +/obj/item/weapon/reagent_containers/food/snacks/sharkmeat + name = "cosmoshark fillet" + desc = "A fillet of cosmoshark meat." + icon_state = "fishfillet" + filling_color = "#cecece" + center_of_mass = "x=17;y=13" + +/obj/item/weapon/reagent_containers/food/snacks/sharkmeat/New() + ..() + reagents.add_reagent(/datum/reagent/nutriment/protein, 5) + reagents.add_reagent(/datum/reagent/space_drugs, 1) + reagents.add_reagent(/datum/reagent/toxin/phoron, 1) + src.bitesize = 8 + + +/obj/structure/net//if you want to have fun, make them to be draggable as a whole unless at least one piece is attached to a non-space turf or anchored object + name = "industrial net" + desc = "A sturdy industrial net of synthetic belts reinforced with plasteel threads." + icon = 'maps/away/errant_pisces/errant_pisces_sprites.dmi' + icon_state = "net_f" + anchored = 1 + plane = ABOVE_TURF_PLANE//on the floor + layer = CATWALK_LAYER//probably? Should cover cables, pipes and the rest of objects that are secured on the floor + var/health = 100 + +obj/structure/net/Initialize(var/mapload) + . = ..() + update_connections() + if (!mapload)//if it's not mapped object but rather created during round, we should update visuals of adjacent net objects + var/turf/T = get_turf(src) + for (var/turf/AT in T.CardinalTurfs(FALSE)) + for (var/obj/structure/net/N in AT) + if (type != N.type)//net-walls cause update for net-walls and floors for floors but not for each other + continue + N.update_connections() + +/obj/structure/net/examine() + ..() + if (health < 20) + to_chat(usr, "\The [src] is barely hanging on a few last threads.") + else if (health < 50) + to_chat(usr, "Many ribbons of \the [src] are cut away.") + else if (health < 90) + to_chat(usr, "Few ribbons of \the [src] are cut away.") + +/obj/structure/net/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/material)) //sharp objects can cut thorugh + var/obj/item/weapon/material/SH = W + if (!(SH.sharp) || (SH.sharp && SH.force < 10))//is not sharp enough or at all + to_chat(user,"You can't cut throught \the [src] with \the [W], it's too dull.") + return + visible_message("[user] starts to cut through \the [src] with \the [W]!") + while (health > 0) + if (!do_after(user, 20, src)) + visible_message("[user] stops cutting through \the [src] with \the [W]!") + return + health -= 20 * (1 + (SH.force-10)/10)//the sharper the faster, every point of force above 10 adds 10 % to damage + visible_message("[user] cuts through \the [src]!") + new /obj/item/stack/net(src.loc) + qdel(src) + +/obj/structure/net/bullet_act(obj/item/projectile/P) + . = PROJECTILE_CONTINUE //few cloth ribbons won't stop bullet or energy ray + if(P.damage_type != BURN)//beams, lasers, fire. Bullets won't make a lot of damage to the few hanging belts. + return + visible_message("\The [P] hits \the [src] and tears it!") + health -= P.damage + if (health < 0) + visible_message("\The [src] is torn apart!") + qdel(src) + +/obj/structure/net/proc/update_connections()//maybe this should also be called when any of the walls nearby is removed but no idea how I can make it happen + overlays.Cut() + var/turf/T = get_turf(src) + for (var/turf/AT in T.CardinalTurfs(FALSE)) + if ( (locate(/obj/structure/net) in AT) || (!istype(AT, /turf/simulated/open) && !istype(AT, /turf/space)) || (locate(/obj/structure/lattice) in AT) )//connects to another net objects or walls/floors or lattices + var/image/I = image(icon,"[icon_state]_ol_[get_dir(src,AT)]") + overlays += I + +/obj/structure/net/net_wall + icon_state = "net_w" + density = 1 + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + +/obj/structure/net/net_wall/Initialize(var/mapload) + . = ..() + if (mapload)//if it's pre-mapped, it should put floor-net below itself + var/turf/T = get_turf(src) + for (var/obj/structure/net/N in T) + if (N.type != /obj/structure/net/net_wall)//if there's net that is not a net-wall, we don't need to spawn it + return + new /obj/structure/net(T) + + +/obj/structure/net/net_wall/update_connections()//this is different for net-walls because they only connect to walls and net-walls + overlays.Cut() + var/turf/T = get_turf(src) + for (var/turf/AT in T.CardinalTurfs(FALSE)) + if ((locate(/obj/structure/net/net_wall) in AT) || istype(AT, /turf/simulated/wall) || istype(AT, /turf/unsimulated/wall) || istype(AT, /turf/simulated/mineral))//connects to another net-wall objects or walls + var/image/I = image(icon,"[icon_state]_ol_[get_dir(src,AT)]") + overlays += I + +/obj/item/stack/net + name = "industrial net roll" + desc = "Sturdy industrial net reinforced with plasteel threads." + singular_name = "industrial net" + icon = 'maps/away/errant_pisces/errant_pisces_sprites.dmi' + icon_state = "net_roll" + w_class = ITEM_SIZE_LARGE + force = 3.0 + throwforce = 5.0 + throw_speed = 5 + throw_range = 10 + matter = list("cloth" = 1875, "plasteel" = 350) + max_amount = 30 + center_of_mass = null + attack_verb = list("hit", "bludgeoned", "whacked") + lock_picking_level = 3 + +/obj/item/stack/net/Initialize() + . = ..() + update_icon() + +/obj/item/stack/net/thirty + amount = 30 + +/obj/item/stack/net/update_icon() + if(amount == 1) + icon_state = "net" + else + icon_state = "net_roll" + +/obj/item/stack/net/proc/attach_wall_check()//checks if wall can be attached to something vertical such as walls or another net-wall + var/area/A = get_area(src) + if (!A.has_gravity) + return 1 + var/turf/T = get_turf(src) + for (var/turf/AT in T.CardinalTurfs(FALSE)) + if ((locate(/obj/structure/net/net_wall) in AT) || istype(AT, /turf/simulated/wall) || istype(AT, /turf/unsimulated/wall) || istype(AT, /turf/simulated/mineral))//connects to another net-wall objects or walls + return 1 + return 0 + +/obj/item/stack/net/attack_self(mob/user)//press while holding to lay one. If there's net already, place wall + var/turf/T = get_turf(user) + if (locate(/obj/structure/net/net_wall) in T) + to_chat(user, "Net wall is already placed here!") + return + if (locate(/obj/structure/net) in T)//if there's already layed "floor" net + if (!attach_wall_check()) + to_chat(user, "You try to place net wall but it falls on the floor. Try to attach it to something vertical and stable.") + return + new /obj/structure/net/net_wall(T) + //update_adjacent_nets(1)//since net-wall was added we also update adjacent wall-nets + else + new /obj/structure/net(T) + //update_adjacent_nets(0) + amount -= 1 + update_icon() + if (amount < 1) + qdel(src) + +/obj/item/clothing/under/carp//as far as I know sprites are taken from /tg/ + name = "space carp suit" + desc = "A suit in a shape of a space carp. Usually worn by corporate interns who are sent to entertain children during HQ excursions." + icon_state = "carp_suit" + icon = 'maps/away/errant_pisces/errant_pisces_sprites.dmi' + item_icons = list(slot_w_uniform_str = 'maps/away/errant_pisces/errant_pisces_sprites.dmi') + +/obj/effect/landmark/corpse/carp_fisher + name = "carp fisher" + corpse_outfits = list(/decl/hierarchy/outfit/corpse/carp_fisher) + species = list(SPECIES_HUMAN = 70, SPECIES_IPC = 20, SPECIES_UNATHI = 10) + +/decl/hierarchy/outfit/corpse/carp_fisher + name = "Dead carp fisher" + uniform = /obj/item/clothing/under/color/green + suit = /obj/item/clothing/suit/apron/overalls + belt = /obj/item/weapon/material/hatchet/tacknife + shoes = /obj/item/clothing/shoes/jackboots + head = /obj/item/clothing/head/hardhat/dblue diff --git a/maps/away/errant_pisces/errant_pisces.dmm b/maps/away/errant_pisces/errant_pisces.dmm new file mode 100644 index 00000000..93bd8a63 --- /dev/null +++ b/maps/away/errant_pisces/errant_pisces.dmm @@ -0,0 +1,1090 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/turf/simulated/wall/r_wall,/area/errant_pisces/bow_starboard) +"ac" = (/turf/simulated/wall/r_wall,/area/errant_pisces/bow_port) +"ad" = (/obj/machinery/atmospherics/unary/engine,/turf/simulated/wall/r_wall,/area/errant_pisces/bow_starboard) +"ae" = (/obj/machinery/atmospherics/unary/engine,/turf/simulated/wall/r_wall,/area/errant_pisces/bow_port) +"af" = (/obj/machinery/alarm{alarm_id = "petrov1"; dir = 4; pixel_x = -25; pixel_y = 0; rcon_setting = 3},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"ag" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 5},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"ah" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel,/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"ai" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 4},/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aj" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 10},/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/obj/machinery/alarm{dir = 8; pixel_x = 25; pixel_y = 0},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"ak" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 6},/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/obj/machinery/alarm{alarm_id = "petrov1"; dir = 4; pixel_x = -25; pixel_y = 0; rcon_setting = 3},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"al" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel,/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"am" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 4},/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"an" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 9},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"ao" = (/obj/machinery/alarm{dir = 8; pixel_x = 25; pixel_y = 0},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"ap" = (/obj/machinery/portable_atmospherics/canister/empty/hydrogen,/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aq" = (/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"ar" = (/obj/machinery/atmospherics/binary/pump{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"as" = (/obj/machinery/atmospherics/binary/pump{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"at" = (/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"au" = (/obj/machinery/portable_atmospherics/canister/empty/hydrogen,/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"av" = (/obj/machinery/atmospherics/portables_connector{dir = 4},/obj/machinery/portable_atmospherics/canister/empty/hydrogen,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aw" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"ax" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"ay" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel{dir = 4},/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"az" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel{dir = 8},/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aA" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aB" = (/obj/machinery/atmospherics/binary/pump{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aC" = (/obj/machinery/atmospherics/portables_connector{dir = 8},/obj/machinery/portable_atmospherics/canister/empty/hydrogen,/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aD" = (/obj/structure/closet/firecloset,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aE" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aF" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aG" = (/obj/machinery/portable_atmospherics/canister/empty/hydrogen,/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aH" = (/obj/machinery/atmospherics/pipe/tank/hydrogen{dir = 1},/obj/effect/floor_decal/industrial/warning{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aI" = (/obj/machinery/atmospherics/pipe/tank/hydrogen{dir = 1},/obj/effect/floor_decal/industrial/warning{dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aJ" = (/obj/machinery/atmospherics/unary/heater{icon_state = "heater_0"; dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aK" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aL" = (/obj/machinery/atmospherics/valve{icon_state = "map_valve0"; dir = 8},/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aM" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 9},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aN" = (/obj/machinery/atmospherics/unary/heater{icon_state = "heater_0"; dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aO" = (/obj/machinery/atmospherics/pipe/tank/hydrogen{dir = 1},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aP" = (/obj/machinery/atmospherics/pipe/tank/hydrogen{dir = 1},/obj/effect/floor_decal/industrial/warning{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aQ" = (/obj/machinery/portable_atmospherics/canister/empty/hydrogen,/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/effect/floor_decal/industrial/warning{dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aR" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aS" = (/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aT" = (/obj/structure/closet/firecloset,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"aU" = (/obj/structure/lattice,/obj/structure/grille,/obj/structure/grille,/turf/space,/area/space) +"aV" = (/obj/structure/lattice,/obj/structure/grille,/turf/space,/area/space) +"aW" = (/turf/simulated/wall/r_wall,/area/errant_pisces/storage_starboard) +"aX" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_starboard) +"aY" = (/turf/simulated/wall/r_wall,/area/errant_pisces/atmos) +"aZ" = (/turf/simulated/wall/r_wall,/area/errant_pisces/enginering) +"ba" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_port) +"bb" = (/turf/simulated/wall/r_wall,/area/errant_pisces/storage_port) +"bc" = (/obj/structure/lattice,/turf/space,/area/space) +"bd" = (/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"be" = (/obj/machinery/portable_atmospherics/canister/carbon_dioxide,/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"bf" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"bg" = (/obj/machinery/atmospherics/pipe/tank/air,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bh" = (/obj/machinery/atmospherics/portables_connector,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bi" = (/obj/machinery/light/small{dir = 1},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bj" = (/obj/machinery/portable_atmospherics/canister,/obj/machinery/atmospherics/portables_connector,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bk" = (/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bl" = (/obj/machinery/portable_atmospherics/canister/phoron,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bm" = (/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bn" = (/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bo" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/vehicle/train/cargo/trolley,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bp" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bq" = (/obj/machinery/computer/engines,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"br" = (/obj/item/modular_computer/console,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bs" = (/obj/structure/table/rack,/obj/random/toolbox,/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"bt" = (/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"bu" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/solar{id = "XynergySolarStarboard"},/turf/simulated/floor/airless,/area/space) +"bv" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/airless,/area/space) +"bw" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/power/solar{id = "XynergySolarStarboard"},/turf/simulated/floor/airless,/area/space) +"bx" = (/obj/machinery/light/small{dir = 4},/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"by" = (/obj/machinery/light/small{dir = 4},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"bz" = (/obj/machinery/atmospherics/pipe/manifold/visible/blue{dir = 8},/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bA" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/blue,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bB" = (/obj/machinery/atmospherics/pipe/simple/visible/blue{dir = 10},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bC" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{icon_state = "intact"; dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bD" = (/obj/machinery/atmospherics/pipe/manifold/visible/yellow,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bE" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bF" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{dir = 9},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bG" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bH" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bI" = (/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bJ" = (/obj/machinery/portable_atmospherics/canister,/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bK" = (/obj/vehicle/train/cargo/trolley,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bL" = (/obj/structure/table/steel,/obj/random/tool,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bM" = (/obj/structure/bed/chair/office/dark{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bN" = (/obj/machinery/light/small{dir = 4},/obj/structure/table/steel,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"bO" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"bP" = (/obj/structure/table/rack,/obj/random/powercell,/obj/machinery/light/small{dir = 8},/obj/item/weapon/mop,/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"bQ" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/solar{id = "XynergySolarPort"},/turf/simulated/floor/airless,/area/space) +"bR" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/power/solar{id = "XynergySolarPort"},/turf/simulated/floor/airless,/area/space) +"bS" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/airless,/area/space) +"bT" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"bU" = (/obj/machinery/atmospherics/pipe/tank/air{icon_state = "air_map"; dir = 1; start_pressure = 740.5},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bV" = (/obj/machinery/atmospherics/pipe/simple/visible/blue,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bW" = (/obj/machinery/atmospherics/binary/pump,/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bX" = (/obj/machinery/atmospherics/trinary/filter{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bY" = (/obj/machinery/atmospherics/pipe/manifold/visible/red{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"bZ" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/obj/machinery/atmospherics/portables_connector{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"ca" = (/obj/machinery/portable_atmospherics/canister,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cb" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cc" = (/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cd" = (/obj/structure/closet,/obj/random/tool,/obj/random/smokes,/obj/item/clothing/under/hazard,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"ce" = (/obj/structure/table/rack,/obj/random/tool,/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"cf" = (/obj/machinery/atmospherics/pipe/tank/nitrogen{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cg" = (/obj/machinery/atmospherics/binary/pump{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"ch" = (/obj/machinery/atmospherics/portables_connector{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"ci" = (/obj/machinery/atmospherics/pipe/simple/visible/universal,/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cj" = (/obj/machinery/atmospherics/pipe/simple/visible/blue{icon_state = "intact"; dir = 6},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"ck" = (/obj/machinery/atmospherics/pipe/simple/visible/blue{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cl" = (/obj/machinery/atmospherics/trinary/filter/m_filter{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cm" = (/obj/machinery/atmospherics/pipe/manifold/visible/red{icon_state = "map"; dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cn" = (/obj/machinery/autolathe,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"co" = (/obj/structure/table/rack,/obj/random/tool,/obj/random/tech_supply,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cp" = (/obj/structure/table/rack,/obj/random/tool,/obj/random/tech_supply,/obj/item/clothing/gloves/duty,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cq" = (/obj/structure/closet,/obj/random/tech_supply,/obj/item/clothing/shoes/dutyboots,/obj/item/clothing/under/hazard,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cr" = (/obj/structure/table/rack,/obj/random/powercell,/obj/random/clothing,/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"cs" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"ct" = (/obj/machinery/atmospherics/pipe/manifold/visible/red,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cu" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cv" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cw" = (/obj/machinery/atmospherics/trinary/mixer/m_mixer{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cx" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/visible/blue{icon_state = "intact"; dir = 6},/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cy" = (/obj/machinery/atmospherics/pipe/manifold/visible/blue,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cz" = (/obj/machinery/atmospherics/binary/oxyregenerator{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cA" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cB" = (/obj/machinery/pipedispenser,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cC" = (/obj/effect/landmark/corpse/engineer,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cD" = (/obj/structure/table/rack,/obj/random/tech_supply,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cE" = (/obj/structure/table/rack,/obj/random/tool,/obj/random/tank,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cF" = (/obj/structure/closet,/obj/random/tool,/obj/random/glasses,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cG" = (/obj/structure/closet/l3closet/janitor,/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"cH" = (/obj/random/junk,/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"cI" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"cJ" = (/obj/machinery/light/small{dir = 4},/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"cK" = (/obj/machinery/atmospherics/pipe/tank/oxygen{dir = 4},/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cL" = (/obj/machinery/atmospherics/pipe/manifold/visible/blue{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cM" = (/obj/machinery/atmospherics/pipe/manifold/visible/blue,/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cN" = (/obj/machinery/atmospherics/pipe/simple/visible/blue{icon_state = "intact"; dir = 9},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cO" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cP" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cQ" = (/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cR" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cS" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"cT" = (/obj/structure/bed/chair/janicart,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"cU" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"cV" = (/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"cW" = (/obj/machinery/alarm{dir = 8; pixel_x = 25; pixel_y = 0},/obj/machinery/portable_atmospherics/canister/oxygen,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"cX" = (/obj/machinery/atmospherics/pipe/tank/air{dir = 4; start_pressure = 740.5},/obj/machinery/atmospherics/pipe/tank/oxygen{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cY" = (/obj/machinery/atmospherics/portables_connector{dir = 8},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"cZ" = (/obj/machinery/portable_atmospherics/powered/pump,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"da" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/light/small,/obj/machinery/portable_atmospherics/powered/pump,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"db" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/portable_atmospherics/powered/scrubber,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"dc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"dd" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"de" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/structure/closet/firecloset,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"df" = (/obj/machinery/alarm{alarm_id = "petrov1"; dir = 4; pixel_x = -25; pixel_y = 0; rcon_setting = 3},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"dg" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"dh" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"di" = (/obj/structure/dispenser/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"dj" = (/obj/machinery/light/small,/obj/machinery/suit_storage_unit/standard_unit,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"dk" = (/obj/machinery/suit_storage_unit/standard_unit,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"dl" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -32; pixel_y = 0},/obj/structure/mopbucket,/obj/item/weapon/mop,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"dm" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"dn" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/storage_starboard) +"do" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/atmos) +"dp" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/enginering) +"dq" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/storage_port) +"dr" = (/turf/simulated/wall/r_wall,/area/errant_pisces/bow_maint) +"ds" = (/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dt" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"du" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dv" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dw" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dx" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dy" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dz" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dA" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 4; frequency = 1441; icon_state = "map_injector"; id = "n2_in"; use_power = 1},/turf/simulated/floor/airless,/area/space) +"dB" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dC" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dD" = (/obj/machinery/atmospherics/binary/pump{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dE" = (/obj/machinery/atmospherics/portables_connector{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dF" = (/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dG" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dH" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dI" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/light/small,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dJ" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dK" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dL" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/power/apc{dir = 2; name = "south bump"; operating = 1; pixel_y = -24},/obj/structure/cable/green,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dM" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dN" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dO" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/random/junk,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dP" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dQ" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dR" = (/turf/simulated/wall/r_wall,/area/errant_pisces/solar_starboard) +"dS" = (/obj/structure/table/rack,/obj/random/shoes,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dT" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"dU" = (/turf/simulated/wall/r_wall,/area/errant_pisces/head_f) +"dV" = (/turf/simulated/wall/r_wall,/area/errant_pisces/smes_room) +"dW" = (/obj/machinery/door/airlock,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"dX" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"dY" = (/turf/simulated/wall/r_wall,/area/errant_pisces/head_m) +"dZ" = (/obj/structure/table/rack,/obj/random/tech_supply,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"ea" = (/turf/simulated/wall/r_wall,/area/errant_pisces/solar_port) +"eb" = (/obj/effect/shuttle_landmark/automatic,/turf/space,/area/space) +"ec" = (/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/tracker{id = "XynergySolarStarboard"},/turf/simulated/floor/airless,/area/space) +"ed" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"ee" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless,/area/space) +"ef" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/obj/machinery/access_button/airlock_exterior{frequency = 1011; master_tag = "xyn_solar_starboard_airlock"; pixel_y = 20},/turf/simulated/floor/airless,/area/errant_pisces/solar_starboard) +"eg" = (/obj/machinery/door/airlock/external{frequency = 1011; id_tag = "xyn_solar_starboard_outer"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"eh" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/unary/vent_pump/high_volume,/obj/machinery/airlock_sensor{frequency = 1011; id_tag = "xyn_solar_starboard_sensor"; pixel_y = 25},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1011; id_tag = "xyn_solar_starboard_airlock"; pixel_x = 25; tag_airpump = "xyn_solar_starboard_pump"; tag_chamber_sensor = "xyn_solar_starboard_sensor"; tag_exterior_door = "xyn_solar_starboard_outer"; tag_interior_door = "xyn_solar_starboard_inner"},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"ei" = (/obj/structure/closet/firecloset,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"ej" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"ek" = (/obj/structure/table/standard,/obj/item/weapon/towel/random,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"el" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"em" = (/obj/machinery/door/airlock,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"en" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/effect/landmark/corpse/carp_fisher,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"eo" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"ep" = (/obj/structure/toilet{dir = 8},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"eq" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"er" = (/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/machinery/power/smes/buildable,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"es" = (/obj/machinery/light/small{dir = 1},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"et" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"eu" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"ev" = (/obj/machinery/light/small{dir = 1},/obj/structure/toilet{dir = 4},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"ew" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"ex" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"ey" = (/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"ez" = (/obj/structure/table/standard,/obj/item/weapon/towel/random,/obj/item/weapon/towel/random,/obj/item/weapon/towel/random,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"eA" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"eB" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/unary/vent_pump/high_volume{frequency = 1013; id_tag = "xyn_solar_port_pump"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1013; id_tag = "xyn_solar_port_airlock"; pixel_x = -25; tag_airpump = "xyn_solar_port_pump"; tag_chamber_sensor = "xyn_solar_port_sensor"; tag_exterior_door = "xyn_solar_port_outer"; tag_interior_door = "xyn_solar_port_inner"},/obj/machinery/airlock_sensor{frequency = 1013; id_tag = "xyn_solar_port_sensor"; pixel_y = 25},/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"eC" = (/obj/machinery/door/airlock/external{frequency = 1013; id_tag = "xyn_solar_port_outer"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"eD" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/obj/machinery/access_button/airlock_exterior{frequency = 1013; master_tag = "xyn_solar_port_airlock"; pixel_y = 20},/turf/simulated/floor/airless,/area/errant_pisces/solar_port) +"eE" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/airless,/area/space) +"eF" = (/obj/machinery/power/tracker{id = "XynergySolarPort"},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless,/area/space) +"eG" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless,/area/space) +"eH" = (/obj/machinery/door/airlock/external{frequency = 1011; id_tag = "xyn_solar_starboard_inner"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"eI" = (/obj/machinery/shower{icon_state = "shower"; dir = 4},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"eJ" = (/turf/simulated/wall,/area/errant_pisces/head_f) +"eK" = (/obj/structure/closet/athletic_mixed,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"eL" = (/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"eM" = (/obj/machinery/power/terminal,/obj/structure/cable,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"eN" = (/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"eO" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"eP" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"eQ" = (/obj/machinery/power/port_gen/pacman/mrs,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"eR" = (/turf/simulated/wall,/area/errant_pisces/head_m) +"eS" = (/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"eT" = (/obj/structure/closet/athletic_mixed,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"eU" = (/obj/machinery/shower{dir = 8; icon_state = "shower"; pixel_x = 0; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"eV" = (/obj/machinery/door/airlock/external{frequency = 1013; id_tag = "xyn_solar_port_inner"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"eW" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/access_button/airlock_interior{frequency = 1011; master_tag = "xyn_solar_starboard_airlock"; pixel_x = -25; pixel_y = 25},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"eX" = (/obj/machinery/power/smes/buildable,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"eY" = (/obj/machinery/light/small{dir = 4},/obj/effect/decal/cleanable/blood,/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"eZ" = (/obj/structure/closet/athletic_mixed,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"fa" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"fb" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/power/smes/buildable,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fc" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fd" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fe" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"ff" = (/obj/machinery/power/port_gen/pacman/mrs,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fg" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fh" = (/obj/structure/closet/athletic_mixed,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fi" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fj" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/landmark/corpse/engineer,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"fk" = (/obj/machinery/power/smes/buildable,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fl" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/access_button/airlock_interior{frequency = 1013; master_tag = "xyn_solar_port_airlock"; pixel_x = 25; pixel_y = 25},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fm" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"fn" = (/obj/effect/wingrille_spawn/reinforced/full,/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"fo" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"fp" = (/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"fq" = (/obj/machinery/door/airlock,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"fr" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"fs" = (/obj/structure/sink{icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2},/obj/structure/mirror{pixel_x = -30},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"ft" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"fu" = (/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fv" = (/obj/machinery/power/terminal,/obj/structure/cable,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fw" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fx" = (/obj/machinery/power/port_gen/pacman/mrs,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fy" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fz" = (/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/obj/structure/mirror{pixel_x = 30},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fA" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"fB" = (/obj/machinery/door/airlock,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fC" = (/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fD" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fE" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fF" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fG" = (/obj/machinery/power/solar_control,/obj/structure/cable/yellow,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"fH" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable,/obj/item/weapon/stool,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/solar_starboard) +"fI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"fJ" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"fK" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fL" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fM" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fN" = (/obj/machinery/light/small{dir = 4},/obj/structure/closet/crate/radiation,/obj/item/stack/material/tritium/ten,/obj/item/stack/material/tritium/ten,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fO" = (/obj/structure/urinal{pixel_y = 30},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fP" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fQ" = (/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/obj/structure/mirror{pixel_x = 30},/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fR" = (/obj/item/weapon/stool,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -32; pixel_y = 0},/obj/machinery/power/apc{dir = 2; name = "south bump"; operating = 1; pixel_y = -24},/obj/structure/cable,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fS" = (/obj/machinery/power/solar_control{id = "XynergySolarPort"},/obj/structure/cable/yellow,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/solar_port) +"fT" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/bow_maint) +"fU" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_f) +"fV" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/smes_room) +"fW" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/errant_pisces/head_m) +"fX" = (/turf/simulated/wall/r_wall,/area/errant_pisces/hallway) +"fY" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"fZ" = (/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"ga" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gc" = (/obj/machinery/light,/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gd" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"ge" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gf" = (/obj/machinery/light,/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gg" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gh" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gi" = (/turf/simulated/wall/r_wall,/area/errant_pisces/rooms) +"gj" = (/turf/simulated/wall,/area/errant_pisces/rooms) +"gk" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -32; pixel_y = 0},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gl" = (/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gm" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gn" = (/turf/simulated/wall,/area/errant_pisces/dorms) +"go" = (/turf/simulated/wall/r_wall,/area/errant_pisces/dorms) +"gp" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet/rainbow,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gq" = (/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gr" = (/obj/item/modular_computer/console,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gs" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet/orange,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gt" = (/obj/structure/bed/chair/comfy/brown{dir = 1},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gu" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/machinery/media/jukebox,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gv" = (/obj/structure/bed/chair/comfy/brown{dir = 4},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gw" = (/obj/structure/table/woodentable,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gx" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/rooms) +"gy" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gz" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gA" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gB" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/dorms) +"gC" = (/obj/machinery/vending/snack,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gD" = (/obj/machinery/vending/fitness,/obj/machinery/light{icon_state = "tube1"; dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gE" = (/obj/machinery/vending/cola,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gF" = (/obj/structure/closet,/obj/random/clothing,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gG" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gH" = (/obj/structure/closet,/obj/random/accessory,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gI" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet,/obj/random/plushie,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gJ" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gK" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless,/area/space) +"gL" = (/obj/structure/bed/chair/comfy/green,/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gM" = (/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gN" = (/obj/structure/closet/cabinet,/obj/item/clothing/shoes/jackboots,/obj/item/clothing/suit/armor/vest,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gO" = (/obj/structure/bed/chair/comfy/teal,/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gP" = (/obj/structure/filingcabinet/chestdrawer,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gQ" = (/obj/structure/table/gamblingtable,/obj/item/weapon/deck/cards,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gR" = (/obj/structure/bed/chair/comfy/brown{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"gS" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"gT" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gU" = (/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gV" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gW" = (/obj/structure/closet,/obj/random/cash,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gX" = (/obj/structure/closet,/obj/random/hat,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gY" = (/obj/structure/curtain/black,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"gZ" = (/obj/structure/table/woodentable,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"ha" = (/obj/structure/closet,/obj/random/smokes,/obj/random/projectile,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hb" = (/obj/structure/table/woodentable,/obj/item/weapon/paper_bin,/obj/item/device/flashlight/lamp,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hc" = (/obj/structure/closet,/obj/random/snack,/obj/random/tool,/obj/random/suit,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hd" = (/obj/structure/table/gamblingtable,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"he" = (/obj/structure/table/woodentable,/obj/item/weapon/material/ashtray/bronze,/obj/random/smokes,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hf" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hg" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/rooms) +"hh" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"hi" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"hj" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hk" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hl" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hm" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hn" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"ho" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hp" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/solar{id = "XynergySolarPort"},/obj/machinery/power/solar{id = "XynergySolarPort"},/turf/simulated/floor/airless,/area/space) +"hq" = (/turf/simulated/wall/r_wall,/area/errant_pisces/infirmary) +"hr" = (/obj/machinery/door/airlock,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hs" = (/obj/effect/landmark/corpse/bridgeofficer,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"ht" = (/obj/structure/bed/chair/comfy/brown,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hu" = (/obj/machinery/vending/coffee,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hv" = (/obj/machinery/vending/cigarette,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hw" = (/obj/structure/closet,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hx" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hy" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hz" = (/obj/machinery/alarm{dir = 1; pixel_y = -25; req_one_access = list(24,11)},/obj/structure/bed/chair/comfy/brown{dir = 4},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hA" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/table/woodentable,/obj/random/smokes,/obj/structure/cable/green,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/wood,/area/errant_pisces/rooms) +"hB" = (/obj/machinery/vending/games,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hC" = (/obj/machinery/vending/assist,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hD" = (/obj/machinery/light/small,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hE" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet,/obj/random/plushie/large,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hF" = (/turf/simulated/wall/r_wall,/area/errant_pisces/live_storage) +"hG" = (/obj/structure/closet,/obj/item/clothing/under/rank/medical/scrubs,/obj/item/clothing/under/rank/medical/scrubs,/obj/item/clothing/under/rank/medical/scrubs,/obj/item/clothing/under/rank/nurse,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"hH" = (/obj/structure/table/standard,/obj/random/firstaid,/obj/item/weapon/storage/box/bodybags,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"hI" = (/turf/simulated/wall,/area/errant_pisces/infirmary) +"hJ" = (/obj/machinery/optable,/obj/machinery/oxygen_pump/anesthetic{pixel_x = -25},/turf/simulated/floor/tiled/white,/area/errant_pisces/infirmary) +"hK" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/turf/simulated/floor/tiled/white,/area/errant_pisces/infirmary) +"hL" = (/obj/structure/table/steel,/obj/item/clothing/head/surgery,/obj/item/weapon/storage/firstaid/surgery,/obj/item/weapon/storage/firstaid/adv,/obj/item/clothing/mask/breath/anesthetic,/turf/simulated/floor/tiled/white,/area/errant_pisces/infirmary) +"hM" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"hN" = (/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hO" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"hP" = (/obj/structure/crematorium,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"hQ" = (/obj/structure/morgue{dir = 2},/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"hR" = (/obj/structure/iv_drip,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"hS" = (/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"hT" = (/obj/machinery/computer/operating,/turf/simulated/floor/tiled/white,/area/errant_pisces/infirmary) +"hU" = (/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/tiled/white,/area/errant_pisces/infirmary) +"hV" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/errant_pisces/infirmary) +"hW" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"hX" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"hY" = (/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"hZ" = (/obj/structure/table/standard,/obj/random/firstaid,/obj/structure/window/basic{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"ia" = (/obj/structure/table/standard,/obj/random/glasses,/obj/structure/window/basic{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"ib" = (/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"ic" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"id" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"ie" = (/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"if" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"ig" = (/obj/structure/reagent_dispensers/water_cooler,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"ih" = (/obj/item/weapon/material/kitchen/utensil/knife/plastic,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"ii" = (/obj/item/weapon/stool,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"ij" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"ik" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"il" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"im" = (/obj/effect/landmark/corpse/chef,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"in" = (/obj/machinery/door/airlock/freezer,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"io" = (/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"ip" = (/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"iq" = (/obj/machinery/button/remote/blast_door{id = "xynergy_bd_cell1"; name = "Cell 1 blast door-control"; pixel_y = -25},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"ir" = (/obj/machinery/light/small,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"is" = (/obj/machinery/button/remote/blast_door{id = "xynergy_bd_cell2"; name = "Cell 2 blast door-control"; pixel_y = -25},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"it" = (/obj/machinery/button/remote/blast_door{id = "xynergy_bd_cell3"; name = "Cell 3 blast door-control"; pixel_y = -25},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"iu" = (/obj/machinery/button/crematorium{pixel_x = -20},/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iv" = (/obj/machinery/light/small{dir = 1},/obj/effect/landmark/corpse/carp_fisher,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iw" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"ix" = (/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iy" = (/obj/machinery/door/airlock,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iz" = (/obj/machinery/door/airlock,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iA" = (/obj/effect/wingrille_spawn/reinforced/full,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iB" = (/obj/structure/curtain/medical,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iC" = (/obj/structure/window/basic,/obj/structure/window/basic{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iD" = (/obj/structure/closet,/obj/random/firstaid,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iE" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iF" = (/obj/structure/table/standard,/obj/item/trash/plate,/obj/item/weapon/material/kitchen/utensil/fork,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"iG" = (/obj/structure/table/marble,/obj/random/snack,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"iH" = (/obj/structure/table/marble,/obj/item/trash/plate,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"iI" = (/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"iJ" = (/obj/structure/closet/crate/freezer,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"iK" = (/obj/machinery/door/blast/regular{id = "xynergy_bd_cell1"},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"iL" = (/obj/machinery/door/blast/regular{id = "xynergy_bd_cell2"},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"iM" = (/obj/machinery/door/blast/regular{id = "xynergy_bd_cell3"},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"iN" = (/obj/structure/closet/crate/secure/biohazard,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iO" = (/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iP" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iQ" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"iR" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iS" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iT" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/machinery/alarm{dir = 1; pixel_y = -25; req_one_access = list(24,11)},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iU" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/landmark/corpse/doctor,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iV" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iW" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iX" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iY" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"iZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"ja" = (/obj/machinery/body_scanconsole,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jb" = (/obj/structure/table/standard,/obj/item/weapon/paper_bin,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jc" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jd" = (/obj/structure/table/marble,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"je" = (/obj/machinery/light/small{dir = 8},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"jf" = (/obj/structure/lattice,/turf/space,/area/errant_pisces/live_storage) +"jg" = (/obj/structure/lattice,/mob/living/simple_animal/hostile/carp,/turf/space,/area/errant_pisces/live_storage) +"jh" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"ji" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"jj" = (/obj/structure/iv_drip,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jk" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jl" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jm" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jn" = (/obj/machinery/bodyscanner,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jo" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jp" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jq" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jr" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/hallway) +"js" = (/obj/structure/table/standard,/obj/item/weapon/material/kitchen/utensil/fork/plastic,/obj/random/snack,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"jt" = (/obj/structure/table/marble,/obj/machinery/microwave,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"ju" = (/obj/structure/table/marble,/obj/machinery/reagentgrinder,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"jv" = (/obj/effect/landmark/corpse/carp_fisher,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"jw" = (/obj/structure/closet/secure_closet/freezer/meat,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"jx" = (/obj/structure/lattice,/obj/machinery/light/small{dir = 8},/turf/space,/area/errant_pisces/live_storage) +"jy" = (/obj/machinery/access_button/airlock_exterior{frequency = 1021; master_tag = "xyn_ls_airlock"; pixel_x = -25; pixel_y = 0},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"jz" = (/turf/simulated/wall/r_wall,/area/errant_pisces/science_wing) +"jA" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"jB" = (/obj/machinery/light/small,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jC" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/freezer,/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jD" = (/obj/structure/table/standard,/obj/random/firstaid,/obj/item/clothing/under/rank/medical/paramedic,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jE" = (/obj/structure/table/standard,/obj/item/roller,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jF" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jG" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/infirmary) +"jH" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jI" = (/obj/item/weapon/stool,/obj/machinery/alarm{dir = 1; pixel_y = -25; req_one_access = list(24,11)},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jJ" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/item/weapon/stool,/obj/structure/cable/green,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/infirmary) +"jK" = (/obj/structure/table/standard,/obj/item/weapon/material/kitchen/utensil/fork,/obj/machinery/light,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"jL" = (/obj/machinery/vending/dinnerware,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"jM" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"jN" = (/obj/machinery/cooker/oven,/turf/simulated/floor/tiled,/area/errant_pisces/dorms) +"jO" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"jP" = (/obj/structure/closet/secure_closet/freezer/kitchen{req_access = newlist()},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/dorms) +"jQ" = (/obj/machinery/door/airlock/external{frequency = 1021; id_tag = "xyn_ls_outer"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"jR" = (/obj/structure/lattice,/turf/space,/area/errant_pisces/science_wing) +"jS" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"jT" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/structure/closet,/obj/item/clothing/under/carp,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"jU" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"jV" = (/obj/structure/table/standard,/obj/item/weapon/paper_bin,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"jW" = (/obj/machinery/photocopier,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"jX" = (/obj/structure/filingcabinet/chestdrawer,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"jY" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"jZ" = (/obj/machinery/door/airlock,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"ka" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{frequency = 1021; id_tag = "xyn_ls_pump"},/obj/machinery/light/small{dir = 4},/obj/machinery/airlock_sensor{frequency = 1019; id_tag = "xyn_ls_sensor"; pixel_x = -25; pixel_y = 0},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"kb" = (/obj/structure/lattice,/obj/machinery/light/small{dir = 8},/turf/space,/area/errant_pisces/science_wing) +"kc" = (/obj/structure/lattice,/mob/living/simple_animal/hostile/carp,/turf/space,/area/errant_pisces/science_wing) +"kd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"ke" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/structure/closet,/obj/item/clothing/suit/storage/toggle/labcoat/genetics,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kf" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kg" = (/obj/structure/bed/chair/office/dark{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kh" = (/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"ki" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kj" = (/turf/simulated/wall/r_wall,/area/errant_pisces/cryo) +"kk" = (/obj/machinery/sleeper{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kl" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"km" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/structure/window/basic{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kn" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"ko" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kp" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kq" = (/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/structure/window/basic{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kr" = (/obj/machinery/sleeper{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"ks" = (/turf/simulated/wall/r_wall,/area/errant_pisces/general_storage) +"kt" = (/turf/simulated/wall/r_wall,/area/errant_pisces/prod_storage) +"ku" = (/obj/machinery/door/airlock/external{frequency = 1021; id_tag = "xyn_ls_inner"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"kv" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kw" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kx" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"ky" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kz" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kA" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/machinery/light{dir = 1},/obj/structure/bookcase,/obj/item/weapon/book/manual/anomaly_testing,/obj/item/weapon/book/manual/anomaly_spectroscopy,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kB" = (/obj/structure/bookcase,/obj/item/weapon/book/manual/mass_spectrometry,/obj/item/weapon/book/manual/research_and_development,/obj/item/weapon/book/manual/engineering_guide,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kC" = (/obj/structure/bookcase,/obj/item/weapon/book/manual/materials_chemistry_analysis,/obj/item/weapon/book/manual/hydroponics_pod_people,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kD" = (/obj/machinery/vending/assist,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kE" = (/obj/machinery/light{dir = 1},/obj/structure/bed/chair/office/dark{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kF" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"kG" = (/obj/structure/closet,/obj/item/clothing/suit/storage/toggle/labcoat/blue,/obj/random/coin,/obj/random/coin,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kH" = (/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kI" = (/obj/structure/closet,/obj/item/clothing/suit/apron/overalls,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kJ" = (/obj/structure/window/basic{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kK" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kL" = (/obj/structure/window/basic{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kM" = (/obj/structure/closet,/obj/item/clothing/suit/storage/toggle/labcoat/xyn_machine,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kN" = (/obj/structure/closet,/obj/item/clothing/suit/apron/overalls,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"kO" = (/obj/structure/closet/crate/freezer/rations,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"kP" = (/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"kQ" = (/obj/structure/table/rack,/obj/item/weapon/material/hatchet/tacknife,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"kR" = (/obj/structure/table/rack,/obj/item/weapon/material/harpoon,/obj/random/tool,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"kS" = (/obj/structure/table/rack,/obj/item/weapon/storage/box/survival,/obj/item/weapon/storage/box/survival,/obj/item/weapon/storage/box/survival,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"kT" = (/turf/simulated/wall,/area/errant_pisces/general_storage) +"kU" = (/obj/structure/closet/secure_closet/freezer/fridge,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"kV" = (/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"kW" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"kX" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"kY" = (/obj/machinery/light/small{dir = 1},/obj/structure/window/basic{dir = 8},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"kZ" = (/obj/item/weapon/reagent_containers/chem_disp_cartridge/synaptizine,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"la" = (/turf/simulated/wall,/area/errant_pisces/prod_storage) +"lb" = (/obj/machinery/suit_storage_unit/standard_unit,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"lc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1021; id_tag = "xyn_ls_airlock"; pixel_x = 25; pixel_y = 0; tag_airpump = "xyn_ls_pump"; tag_chamber_sensor = "xyn_ls_sensor"; tag_exterior_door = "xyn_ls_outer"; tag_interior_door = "xyn_ls_inner"},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"ld" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/table/rack,/obj/item/weapon/material/harpoon,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"le" = (/obj/effect/landmark/corpse/scientist,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lf" = (/obj/structure/table/rack,/obj/item/weapon/gun/launcher/net,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lg" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lh" = (/obj/machinery/light/small{dir = 8},/obj/structure/closet/crate/freezer/rations,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"li" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"lj" = (/obj/structure/closet/secure_closet/freezer/fridge,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"lk" = (/obj/structure/closet/secure_closet/freezer/fridge,/obj/item/weapon/reagent_containers/food/snacks/cubancarp,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"ll" = (/obj/structure/window/basic{dir = 8},/obj/item/weapon/reagent_containers/chem_disp_cartridge/hyperzine,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"lm" = (/obj/structure/closet/crate,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"ln" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"lo" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"lp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/structure/closet/firecloset,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lq" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lr" = (/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"ls" = (/turf/simulated/wall,/area/errant_pisces/science_wing) +"lt" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lu" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/freezer,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lv" = (/obj/structure/table/standard,/obj/item/weapon/storage/toolbox/mechanical,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lw" = (/obj/structure/table/standard,/obj/item/weapon/storage/toolbox/electrical,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lx" = (/obj/structure/table/standard,/obj/item/weapon/tape_roll,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"ly" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/gloves,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lz" = (/obj/structure/closet,/obj/item/clothing/suit/storage/toggle/labcoat/xyn_machine,/obj/random/advdevice,/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"lA" = (/obj/structure/closet,/obj/random/loot,/obj/random/soap,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"lB" = (/obj/structure/closet,/obj/item/clothing/under/hazard,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"lC" = (/obj/structure/closet,/obj/item/clothing/suit/apron/overalls,/obj/random/glasses,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"lD" = (/obj/structure/table/rack,/obj/item/weapon/storage/toolbox/mechanical,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"lE" = (/obj/structure/table/rack,/obj/item/weapon/storage/ore,/obj/random/tool,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"lF" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/empty,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"lG" = (/obj/item/weapon/reagent_containers/chem_disp_cartridge/mercury,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"lH" = (/obj/machinery/portable_atmospherics/canister/empty/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"lI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"lJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"lK" = (/obj/structure/closet/l3closet/scientist,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lL" = (/obj/structure/closet/secure_closet/scientist{req_one_access = newlist()},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lM" = (/obj/structure/closet/secure_closet/hydroponics,/obj/structure/window/reinforced{dir = 1; health = 1e+006},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lN" = (/obj/machinery/door/window/northright,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lO" = (/obj/machinery/vending/hydronutrients,/obj/structure/window/reinforced{dir = 1; health = 1e+006},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lP" = (/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/machinery/chem_master,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lQ" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/table/standard,/obj/machinery/reagentgrinder,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lR" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/table/standard,/obj/item/weapon/book/manual/mass_spectrometry,/obj/item/device/mass_spectrometer,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"lS" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/window/northright,/turf/simulated/floor/tiled/white,/area/errant_pisces/science_wing) +"lT" = (/obj/structure/table/steel,/obj/item/weapon/storage/firstaid/surgery,/obj/item/weapon/material/knife/butch,/obj/item/weapon/material/twohanded/fireaxe,/obj/structure/window/reinforced{dir = 1},/turf/simulated/floor/tiled/white,/area/errant_pisces/science_wing) +"lU" = (/obj/vehicle/train/cargo/engine,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"lV" = (/obj/vehicle/train/cargo/trolley,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"lW" = (/obj/structure/closet/secure_closet/freezer/fridge,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"lX" = (/obj/structure/window/basic{dir = 8},/obj/structure/closet/crate,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"lY" = (/obj/structure/closet/crate,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"lZ" = (/obj/structure/closet/secure_closet/freezer/meat,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"ma" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"mb" = (/obj/structure/lattice,/obj/machinery/access_button/airlock_exterior{frequency = 1015; master_tag = "xyn_sci_airlock"; pixel_y = -20},/turf/space,/area/errant_pisces/science_wing) +"mc" = (/obj/machinery/door/airlock/external{frequency = 1015; id_tag = "xyn_sci_outer"},/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"md" = (/obj/machinery/light/small{dir = 1},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1015; id_tag = "xyn_sci_pump"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1015; id_tag = "xyn_sci_airlock"; pixel_x = 0; pixel_y = -25; tag_airpump = "xyn_sci_pump"; tag_chamber_sensor = "xyn_sci_sensor"; tag_exterior_door = "xyn_sci_outer"; tag_interior_door = "xyn_sci_inner"},/obj/machinery/airlock_sensor{frequency = 1015; id_tag = "xyn_sci_sensor"; pixel_y = 25},/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"me" = (/obj/machinery/door/airlock/external{frequency = 1015; id_tag = "xyn_sci_inner"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"mf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/machinery/access_button/airlock_interior{frequency = 1015; master_tag = "xyn_sci_airlock"; pixel_x = -25; pixel_y = -25},/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"mg" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"mh" = (/obj/structure/closet/l3closet/scientist,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mi" = (/obj/structure/closet/secure_closet/scientist{req_one_access = newlist()},/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mj" = (/obj/machinery/portable_atmospherics/hydroponics,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mk" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"ml" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/chemical_dispenser/full,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mm" = (/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mn" = (/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/tiled/white,/area/errant_pisces/science_wing) +"mo" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/machinery/computer/operating,/turf/simulated/floor/tiled/white,/area/errant_pisces/science_wing) +"mp" = (/obj/structure/closet,/obj/item/clothing/suit/storage/hooded/wintercoat,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"mq" = (/obj/structure/closet,/obj/random/plushie,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"mr" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"ms" = (/obj/structure/table/rack,/obj/item/stack/net/thirty,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"mt" = (/obj/machinery/light/small{dir = 4},/obj/structure/table/rack,/obj/item/stack/net,/obj/random/snack,/obj/random/tool,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"mu" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mv" = (/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mw" = (/obj/structure/window/basic{dir = 8},/obj/structure/closet/crate,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mx" = (/obj/structure/table/rack,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/obj/item/weapon/material/harpoon,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"my" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"mz" = (/turf/simulated/wall/r_wall,/area/errant_pisces/aft_hallway) +"mA" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"mB" = (/obj/machinery/suit_storage_unit/standard_unit,/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"mC" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mD" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/structure/closet/secure_closet/scientist{req_one_access = newlist()},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mE" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mF" = (/obj/structure/window/reinforced{dir = 8},/obj/structure/table/standard,/obj/item/weapon/storage/box/beakers,/obj/item/weapon/reagent_containers/dropper,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mG" = (/obj/machinery/biogenerator,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mH" = (/obj/structure/window/reinforced{dir = 4},/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mI" = (/obj/machinery/optable,/obj/item/clothing/glasses/welding,/obj/item/weapon/weldingtool,/turf/simulated/floor/tiled/white,/area/errant_pisces/science_wing) +"mJ" = (/obj/machinery/light,/obj/effect/landmark/corpse/carp_fisher,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"mK" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"mL" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"mM" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"mN" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/machinery/alarm{dir = 1; pixel_y = -22},/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"mO" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"mP" = (/obj/machinery/alarm{dir = 1; pixel_y = -22},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mQ" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; operating = 1; pixel_y = -24},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mR" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mS" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/machinery/light/small,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mT" = (/obj/machinery/light/small,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"mU" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/obj/structure/table/rack,/obj/item/weapon/gun/launcher/net,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"mV" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"mW" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/science_wing) +"mX" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/errant_pisces/science_wing) +"mY" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"mZ" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/cryo) +"na" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/general_storage) +"nb" = (/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock/freezer,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/prod_storage) +"nc" = (/turf/simulated/wall,/area/errant_pisces/live_storage) +"nd" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/errant_pisces/live_storage) +"ne" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/light/small{dir = 1},/obj/machinery/access_button/airlock_interior{frequency = 1017; master_tag = "xyn_dock1_airlock"; pixel_x = 0; pixel_y = 25},/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"nf" = (/obj/machinery/door/airlock/external{frequency = 1017; id_tag = "xyn_dock1_inner"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"ng" = (/obj/machinery/light/small{dir = 1},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1017; id_tag = "xyn_dock1_pump"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1017; id_tag = "xyn_dock1_airlock"; pixel_x = 0; pixel_y = -25; tag_airpump = "xyn_dock1_pump"; tag_chamber_sensor = "xyn_dock1_sensor"; tag_exterior_door = "xyn_dock1_outer"; tag_interior_door = "xyn_dock1_inner"},/obj/machinery/airlock_sensor{frequency = 1017; id_tag = "xyn_dock1_sensor"; pixel_y = 25},/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"nh" = (/obj/machinery/door/airlock/external{frequency = 1017; id_tag = "xyn_dock1_outer"},/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"ni" = (/obj/machinery/access_button/airlock_exterior{frequency = 1017; master_tag = "xyn_dock1_airlock"; pixel_x = -25; pixel_y = -25},/turf/simulated/floor/plating,/area/space) +"nj" = (/turf/simulated/floor/plating,/area/space) +"nk" = (/turf/simulated/wall/r_wall,/area/errant_pisces/aux_power) +"nl" = (/obj/machinery/power/port_gen/pacman/mrs,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"nm" = (/obj/machinery/power/terminal{dir = 4},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"nn" = (/obj/machinery/power/smes/buildable,/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"no" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"np" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nq" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nr" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"ns" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nt" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nu" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nv" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nw" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nx" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"ny" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nz" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nA" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nB" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nC" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nE" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nF" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nG" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nH" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nI" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nJ" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"nK" = (/obj/machinery/power/port_gen/pacman/mrs,/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"nL" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"nM" = (/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"nN" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"nO" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nP" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nR" = (/obj/effect/landmark/corpse/scientist,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nS" = (/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nT" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nU" = (/obj/machinery/power/apc{dir = 2; name = "south bump"; operating = 1; pixel_y = -24},/obj/structure/cable/green,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nV" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nW" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nX" = (/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nY" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"nZ" = (/obj/machinery/door/firedoor,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"oa" = (/obj/effect/landmark/corpse/bridgeofficer,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/aft_hallway) +"ob" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"oc" = (/obj/machinery/power/terminal,/obj/structure/cable/yellow,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"od" = (/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"oe" = (/obj/structure/closet/crate/radiation,/obj/item/stack/material/tritium/ten,/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/green,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"of" = (/obj/machinery/door/firedoor,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"og" = (/turf/simulated/wall/r_wall,/area/errant_pisces/fishing_wing) +"oh" = (/obj/machinery/door/airlock/freezer,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oi" = (/turf/simulated/wall/r_wall,/area/errant_pisces/bridge) +"oj" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"ok" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/access_button/airlock_interior{frequency = 1019; master_tag = "xyn_dock2_airlock"; pixel_x = 0; pixel_y = -25},/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"ol" = (/obj/machinery/door/airlock/external{frequency = 1019; id_tag = "xyn_dock2_inner"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"om" = (/obj/machinery/light/small{dir = 1},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1019; id_tag = "xyn_dock2_airlock"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1019; id_tag = "xyn_dock2_airlock"; pixel_x = 0; pixel_y = -25; tag_airpump = "xyn_dock2_pump"; tag_chamber_sensor = "xyn_dock2_sensor"; tag_exterior_door = "xyn_dock2_outer"; tag_interior_door = "xyn_dock2_inner"},/obj/machinery/airlock_sensor{frequency = 1019; id_tag = "xyn_dock2_sensor"; pixel_y = 25},/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"on" = (/obj/machinery/door/airlock/external{frequency = 1019; id_tag = "xyn_dock2_outer"},/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/aft_hallway) +"oo" = (/obj/machinery/access_button/airlock_exterior{frequency = 1019; master_tag = "xyn_dock2_airlock"; pixel_x = -25; pixel_y = -25},/turf/simulated/floor/plating,/area/space) +"op" = (/obj/machinery/power/smes/buildable,/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"oq" = (/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"or" = (/obj/structure/table/rack,/obj/item/weapon/wrench,/obj/item/weapon/screwdriver,/obj/item/weapon/wirecutters,/turf/simulated/floor/plating,/area/errant_pisces/aux_power) +"os" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"ot" = (/turf/simulated/wall,/area/errant_pisces/fishing_wing) +"ou" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"ov" = (/obj/structure/table/marble,/obj/item/weapon/material/knife/butch,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"ow" = (/obj/machinery/gibber,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"ox" = (/obj/structure/table/marble,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/obj/item/weapon/reagent_containers/food/snacks/carpmeat,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oy" = (/obj/machinery/gibber,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oz" = (/obj/structure/table/marble,/obj/item/weapon/gun/launcher/net,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oA" = (/obj/structure/sink{dir = 1; pixel_y = 16},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oB" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oC" = (/obj/structure/closet/crate,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oD" = (/obj/random/obstruction,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oE" = (/obj/machinery/door/airlock/freezer,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oF" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/landmark/corpse/bridgeofficer,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oH" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"oI" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/alarm{alarm_id = "petrov1"; dir = 4; pixel_x = -25; pixel_y = 0; rcon_setting = 3},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"oJ" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/machinery/alarm{alarm_id = "petrov1"; dir = 4; pixel_x = -25; pixel_y = 0; rcon_setting = 3},/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oK" = (/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"oL" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable/green,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oM" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/structure/closet/firecloset,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oN" = (/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oO" = (/obj/structure/table/steel,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oP" = (/obj/machinery/light{dir = 1},/obj/structure/table/steel,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oQ" = (/obj/structure/bookcase/manuals/engineering,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oR" = (/obj/structure/bookcase/manuals/research_and_development,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oS" = (/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oT" = (/obj/structure/bed/chair/comfy/captain,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oU" = (/obj/machinery/light{dir = 1},/obj/structure/reagent_dispensers/water_cooler,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"oV" = (/obj/machinery/door/airlock,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"oW" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"oX" = (/obj/machinery/light{dir = 1},/obj/structure/closet,/obj/item/weapon/gun/projectile/shotgun/pump/combat,/obj/item/weapon/lipstick/random,/obj/random/ammo,/obj/random/cash,/obj/random/cash,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"oY" = (/obj/item/modular_computer/console,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"oZ" = (/obj/machinery/vending/medical{req_access = newlist()},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pa" = (/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pb" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/landmark/corpse/carp_fisher,/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pc" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pd" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/light{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pe" = (/obj/structure/closet/crate/secure/biohazard,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"pf" = (/obj/structure/net,/turf/space,/area/space) +"pg" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"ph" = (/obj/random/tool,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pi" = (/obj/machinery/computer/navigation,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pj" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pk" = (/obj/structure/table/steel,/obj/random/toy,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pl" = (/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"pm" = (/obj/structure/bed/chair/office/light{dir = 4},/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"pn" = (/obj/structure/table/woodentable,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"po" = (/obj/effect/wingrille_spawn/reinforced/full,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/bridge) +"pp" = (/obj/machinery/door/blast/regular/open{dir = 2; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/turf/simulated/floor/reinforced/airless,/area/errant_pisces/bridge) +"pq" = (/obj/structure/lattice,/obj/structure/grille,/turf/space,/area/errant_pisces/bridge) +"pr" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"ps" = (/obj/structure/cable/green,/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pt" = (/obj/structure/kitchenspike,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"pu" = (/obj/structure/kitchenspike,/obj/machinery/light/small,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"pv" = (/obj/machinery/light/small,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"pw" = (/obj/structure/net/net_wall,/turf/space,/area/space) +"px" = (/obj/machinery/alarm{alarm_id = "petrov1"; dir = 4; pixel_x = -25; pixel_y = 0; rcon_setting = 3},/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"py" = (/obj/random/junk,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pz" = (/obj/effect/overmap/ship/errant_pisces,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pA" = (/obj/structure/table/steel,/obj/random/snack,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pB" = (/obj/structure/bookcase/manuals/engineering,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"pC" = (/obj/structure/table/woodentable,/obj/random/toy,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"pD" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled/white,/area/errant_pisces/fishing_wing) +"pE" = (/mob/living/simple_animal/hostile/carp/shark,/turf/simulated/floor/tiled/white,/area/errant_pisces/fishing_wing) +"pF" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled/white,/area/errant_pisces/fishing_wing) +"pG" = (/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pH" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pI" = (/obj/machinery/door/airlock/freezer,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/freezer,/area/errant_pisces/fishing_wing) +"pJ" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/structure/table/steel,/obj/random/snack,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pK" = (/obj/structure/table/steel,/obj/random/firstaid,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pL" = (/obj/structure/bed/chair/office/dark,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pM" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/structure/table/steel,/obj/random/handgun,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"pN" = (/obj/structure/curtain/open/bed,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"pO" = (/obj/machinery/shower{dir = 1},/turf/simulated/floor/tiled/white,/area/errant_pisces/fishing_wing) +"pP" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pQ" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"pR" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pS" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pT" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pU" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pV" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pW" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pX" = (/obj/machinery/alarm{alarm_id = "xenobio1_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pY" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"pZ" = (/obj/structure/net,/mob/living/simple_animal/hostile/carp,/turf/space,/area/space) +"qa" = (/obj/machinery/computer/sensors,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qb" = (/obj/structure/bed/chair/office/dark{dir = 8},/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qc" = (/obj/structure/table/steel,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qd" = (/obj/structure/table/steel,/obj/random/toolbox,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qe" = (/obj/structure/table/steel,/obj/random/advdevice,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qf" = (/obj/structure/table/steel,/obj/machinery/button/remote/blast_door{id = "xynergy_perimeter_blast"; name = "perimeter blast door-control"},/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qg" = (/obj/machinery/computer/helm,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qh" = (/obj/machinery/computer/engines,/turf/simulated/floor/tiled,/area/errant_pisces/bridge) +"qi" = (/obj/item/weapon/bedsheet/captain,/obj/structure/bed/padded,/turf/simulated/floor/wood,/area/errant_pisces/bridge) +"qj" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/structure/table/rack,/obj/item/weapon/gun/projectile/shotgun/pump,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qk" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"ql" = (/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qm" = (/obj/structure/closet/l3closet/janitor,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qn" = (/obj/structure/table/rack,/obj/item/clothing/mask/breath,/obj/item/weapon/storage/box/survival,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qo" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qp" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/machinery/suit_storage_unit/standard_unit,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qq" = (/obj/structure/janitorialcart,/obj/item/weapon/mop,/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"qr" = (/obj/machinery/light{dir = 4},/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"qs" = (/obj/machinery/light/small{dir = 8},/obj/structure/table/rack,/obj/item/weapon/gun/launcher/net,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qt" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/random/contraband,/obj/structure/closet/l3closet/janitor,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qu" = (/obj/structure/table/rack,/obj/item/weapon/tank/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qv" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qw" = (/obj/machinery/suit_storage_unit/standard_unit,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qx" = (/obj/machinery/shipsensors,/turf/simulated/floor/reinforced/airless,/area/errant_pisces/bridge) +"qy" = (/obj/structure/closet/firecloset,/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"qz" = (/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/errant_pisces/fishing_wing) +"qA" = (/obj/structure/table/rack,/obj/item/weapon/gun/launcher/net,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qB" = (/obj/structure/closet,/obj/random/smokes,/obj/random/drinkbottle,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qC" = (/obj/structure/lattice,/turf/simulated/wall/r_wall,/area/errant_pisces/bridge) +"qD" = (/obj/structure/table/rack,/obj/item/weapon/material/hatchet/tacknife,/obj/item/weapon/material/hatchet/tacknife,/obj/item/stack/net/thirty,/obj/item/stack/net/thirty,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qE" = (/obj/structure/closet,/obj/random/smokes,/obj/random/snack,/obj/random/tank,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qF" = (/obj/structure/table/rack,/obj/item/weapon/storage/box/survival,/obj/item/stack/net/thirty,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qG" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/machinery/suit_storage_unit/standard_unit,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qH" = (/obj/structure/grille,/turf/space,/area/space) +"qI" = (/obj/machinery/light/small{dir = 8},/obj/structure/table/rack,/obj/item/weapon/material/harpoon,/obj/item/weapon/material/harpoon,/obj/item/weapon/material/harpoon,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qJ" = (/obj/structure/closet,/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/random/gloves,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qK" = (/obj/structure/table/rack,/obj/item/clothing/mask/breath,/obj/item/device/flashlight,/obj/item/stack/net/thirty,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qL" = (/obj/effect/landmark/corpse/carp_fisher,/obj/effect/decal/cleanable/blood,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qM" = (/turf/simulated/wall/r_wall,/area/space) +"qN" = (/obj/structure/bed/chair,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qO" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qP" = (/obj/effect/decal/cleanable/blood,/obj/machinery/access_button/airlock_interior{frequency = 1023; master_tag = "xyn_fish_airlock"; pixel_x = 25; pixel_y = -25},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qQ" = (/obj/machinery/door/airlock/external{frequency = 1023; id_tag = "xyn_fish_inner"},/obj/machinery/door/firedoor,/obj/effect/decal/cleanable/blood,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qR" = (/obj/machinery/light/small{dir = 1},/obj/effect/decal/cleanable/blood,/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1023; id_tag = "xyn_fish_airlock"; pixel_x = 0; pixel_y = -25; tag_airpump = "xyn_fish_pump"; tag_chamber_sensor = "xyn_fish_sensor"; tag_exterior_door = "xyn_fish_outer"; tag_interior_door = "xyn_fish_inner"},/obj/machinery/airlock_sensor{frequency = 1023; id_tag = "xyn_fish_sensor"; pixel_y = 25},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1023; id_tag = "xyn_fish_pump"},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qS" = (/obj/machinery/door/airlock/external{frequency = 1023; id_tag = "xyn_fish_outer"},/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "xynergy_perimeter_blast"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/space) +"qT" = (/obj/structure/net,/obj/machinery/access_button/airlock_exterior{frequency = 1019; master_tag = "xyn_dock2_airlock"; pixel_x = -25; pixel_y = -25},/turf/space,/area/space) +"qU" = (/obj/structure/bed/chair{dir = 4},/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qV" = (/obj/structure/table/steel,/obj/random/smokes,/obj/item/weapon/flame/lighter,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qW" = (/obj/structure/table/steel,/obj/random/snack,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qX" = (/obj/structure/bed/chair{dir = 8},/obj/item/weapon/flame/match,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qY" = (/obj/structure/dispenser/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"qZ" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/errant_pisces/fishing_wing) +"ra" = (/obj/structure/net,/obj/item/weapon/material/hatchet/tacknife,/turf/space,/area/space) +"rb" = (/obj/structure/net,/obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh,/turf/space,/area/space) +"rc" = (/obj/structure/net,/mob/living/simple_animal/hostile/carp/shark,/turf/space,/area/space) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaababaaaaaaabacacaaaaaaacacaaaaaaacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababadadadababadadadabacacaeaeaeacacaeaeaeacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababafagahahaiaiahahahajacakalalalamamalalanaoacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababapaqaqaqaqaqaqaqaqaqaracasatatatatatatatatatauacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababavawaxaxaxaxaxaxaxaxaxayacazaAaAaAaAaAaAaAaAaAaBaCacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaDaEaFaGaHaHaHaHaHaIaJaJaKaLaMaNaNaOaPaPaPaPaPaQaRaSaTacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaUaVaVaVaVaVaVaVaVaVaVaVaVaVaWaWaWaWaWaXaYaYaYaYaYaYaYaYaYaYaYaYaZaZaZaZaZaZaZaZaZaZaZbabbbbbbbbbbaVaVaVaVaVaVaVaVaVaVaVaVaVaUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaaaabcaaaaaabcaaaaaabcaaaaaWaWbdbeaWbfaYbgbgbgbgbhbibjbjbjbjbkaZblbmbnbobpbnbqbrbraZbfbbbsbtbbbbaaaabcaaaaaabcaaaaaabcaaaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubvbwaabubvbwaabubvbwaaaWaWbdbxaWbyaYbzbAbAbAbAbBbCbDbEbFbGaZbHbIbmbJbKbnbLbMbNaZbObbbPbtbbbbaabQbvbRaabQbvbRaabQbvbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubSbwaabubSbwaabubSbwaaaWaWbdbTaWbfaYbUbUbUbUbVbWbkbkbXbYbZaZcacbcbccbnbnbnbncdaZbfbbcebtbbbbaabQbSbRaabQbSbRaabQbSbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVbcbubSbwbcbubSbwbcbubSbwbcaWaWbdbTaWbfaYcfbYcgchbVcicjckclcmbZaZcnbnbnbnbncocpbncqaZbfbbcrbtbbbbbcbQbSbRbcbQbSbRbcbQbSbRbcaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubSbwaabubSbwaabubSbwaaaWaWbdcsaWbfaYcfctcucvcwcxcyczclcAbZaZcBbncCbnbncDcEbncFaZbfbbcGcHbbbbaabQbSbRaabQbSbRaabQbSbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubSbwaabubSbwaabubSbwaaaWaWcIcJaWbyaYcKcLcuckcMcNcObkcPbkbGaZcQbncRbnbnbnbnbncSaZbObbcTcUbbbbaabQbSbRaabQbSbRaabQbSbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubSbwaabubSbwaabubSbwaaaWaWcVcWaWbfaYcXcycgcYcZdadbdbdcdddeaZdfdgdhdhdidjdkdkdkaZbfbbdldmbbbbaabQbSbRaabQbSbRaabQbSbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVbcbubSbwbcbubSbwbcbubSbwbcaWaWdnaWaWbfaYaYaYaYaYaYaYaYaYdoaYaYaZdpaZaZaZaZaZaZaZaZaZbfbbbbdqbbbbbcbQbSbRbcbQbSbRbcbQbSbRbcaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubSbwaabubSbwaabubSbwaadrdrdsdtdtdudtdtdtdtdtdtdtdtdtdvdwdtdtdxdtdtdtdtdtdtdtdtdtdydtdtdzdrdraabQbSbRaabQbSbRaabQbSbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubSbwaabubSbwaabubSbwdAdBdCdDdEdFdGdHdHdHdHdHdHdIdHdJdKdLdIdHdMdNdHdHdIdHdHdHdHdHdOdFdFdFdPdQaabQbSbRaabQbSbRaabQbSbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabubSbwaabubSbwaabubSbwaadRdRdRdRdSdTdUdUdUdUdUdUdUdUdVdWdVdVdVdXdVdYdYdYdYdYdYdYdYdTdZeaeaeaeaaabQbSbRaabQbSbRaabQbSbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaebaaaaaaaaaaaaaaaVecedeeedededeeedededeeededefegehdReiejdUekelemeleneoepdVeqereseteudVevewexeyeweyezdYeAeieaeBeCeDededeEedededeEedededeEedeFaVaaaaaaaaaaaaaaaaebaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabueGbwaabueGbwaabueGbwaadRdReHdRdRdTdUeIeleJeKeLeJeJdVeMeNeOePeQdVeReReSeTeReyeUdYdTeaeaeVeaeaaabQeGbRaabQeGbRaabQeGbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabueGbwaabueGbwaabueGbwaadRdReWeXdRdTdUeIeYeJeZfaeoepdVfbfcfdfeffdVevewfgfheRfieUdYfjeafkfleaeaaabQeGbRaabQeGbRaabQeGbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabueGbwaabueGbwaabueGbwaafmfnfofpfqfrdUeIeleJfsfteJeJdVfufveqfwfxdVeReRfyfzeReyeUdYfAfBfCfDfEfFaabQeGbRaabQeGbRaabQeGbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVbcbueGbwbcbueGbwbcbueGbwbcdRdRfGfHdRfIdUeIeleJfsfJeoepdVfKerfLfMfNdVfOfOfPfQeReyeUdYfIeafRfSeaeabcbQeGbRbcbQeGbRbcbQeGbRbcaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabueGbwaabueGbwaabueGbwaadRdRdRdRdRfTdUeJeJeJeJfUeJeJdVdVdVfVdVdVdVeReRfWeReReReRdYfTeaeaeaeaeaaabQeGbRaabQeGbRaabQeGbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabueGbwaabueGbwaabueGbwaafXfXfYfZfZgagbgbgbgbgbgcgdgdgdgdgdgegdgdgdgdgdgfgbgbgbgbgbggfZfZghfXfXaabQeGbRaabQeGbRaabQeGbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabueGbwaabueGbwaabueGbwaagigigjgjgjgjgjgjgjgjgjgjgjgjgjgjgkglgmgngngngngngngngngngngngngngngogoaabQeGbRaabQeGbRaabQeGbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVbcbueGbwbcbueGbwbcbueGbwbcgigigpgqgrgjgsgqgrgjgtgqgugvgwgxgygzgAgBgCgDgEgngFgGgHgngIgngJgngJgogobcbQeGbRbcbQeGbRbcbQeGbRbcaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabueGbwaabugKbwaabugKbwaagigigLgMgNgjgOgqgPgjgQgqgqgqgRgxfZgSfZgBgTgUgVgngWgUgXgngYgngYgngYgogoaabQeGbRaabQeGbRaabQeGbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaabugKbwaaaabcaaaaaabcaaaagigigZgqhagjhbgqhcgjhdgqhegqhfhghhhihhhjhkhlhmhngUgUgUgUgUgUgUgUhogogoaahpgKbRaahpgKbRaahpgKbRaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVaaaabcaaaaaahqhqhqhqhqhqhqhqgigjhrgjgjgjhrgjgjgtgqhsgqhtgxfZgSfZgBhugUhvgnhwgUgFgngYgngYgngYgogoaaaabcaaaaaabcaaaaaabcaaaaaVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahqhqhqhqhqhqhqhqhqhqhqhqhqhqhqgigqhxhxhyhxgqhxhxgqhxgqhzhAgxfZgSfZgBhBgUhCgngFhDhwgnhEgngIgngJgohFhFhFhFhFhFhFhFhFhFhFhFhFhFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahqhqhqhqhqhqhqhqhqhGhHhIhJhKhLhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIfZgShMgnhNgUhOgngngngngngngngngngngohFhFhFhFhFhFhFhFhFhFhFhFhFhFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahqhqhPhIhQhQhQhQhqhRhShIhThUhVhIhWhXhWhIhYhZhYiaibicibidieiffZgSfZgBigihiiijijiiikilimilinioiogohFipipiqiripipisiripitipiphFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahqhqiuiviwhSiwixhqhIiyhIhIhIizhIiAiBiAhIibiCibiCibhIiDhYiEiffZgSfZgBgUgUiiiFijiiiliGiliHgniIiJgohFhFiKhFhFhFiLhFhFiMhFhFiphFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahqhqiNhSiOiwiPiQiRiSiSiTiSiUiViSiSiSiSiWiSiXiYiZjahIjbjcjciffZgSfZhngUgUgUgUgUilgUjdgUjdgnjeiJgohFjfjfjfhFjfjgjfhFjfjfhFjhhFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahqhqhqhqhqhqhqjihqhqhqhqhqhqhqhqiAiBiAhIjjjkjljmjnhIjoiXjpjqgdjrfZgBgUiiijjsiigUgUjtgUjugnjvjwgohFjxjfjghFjxjfjghFjxjfhFjyhFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjzjzjzjzjzjAjzjzjzjzjzjzjzhqhWjBhWhIjCjDjEjFiSjGjHjIjJiffZgSfZgBgUiijKijiigUgUjLjMjNgnjOjPgohFjfjgjfhFjfjgjfhFjfjghFjQhFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjRjRjRjzjzjSjTjUjUjVjWjXjzhqhqhqhqhqhqhqhqhqhqhqhqhqhqhqjYjZjYgogogogogogogogogogogogogogogohFhFhFhFhFhFhFhFhFhFhFhFkahFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzkbkcjRjzjzkdkekfkgkhkhkijzjzjzjzjzjzjzjzjzjzjzkjkkklkkkmknkokpkqkrklkrkjksksksksksksksktktktktktktktktktktktktktkthFkuhFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjRjRkcjzjzkvkwkwkxkxkxkxkykzkAkBkCkDkfkEkhkFjzkjkGkHkIkJkHkKkHkLkMkHkNkjkOkOkPkQkRkSkTkUkVkWkWkXkUkWkVkWkYkVkZkVlalblchFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjRjRjRjzjzldlelfjXjXkhjXjzlgkhkhkhkhkhkhkhkFjzkjkkkHkkkJkHkKkHkLkrkHkrkjlhkOkPkPkPlikTljkVkUlkkVkWkUkVkUlllmkVlnlalblohFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjRkcjRjzjzlplqlrlslsltlsjzlukhlvlwkhlxlykhkFjzkjlzkHlAkJkHkKkHkLlBkHlCkjkOkOkPlDlElFkTkWkVkUkWkVkUkWkVkWllkVlmlGlalHlIhFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzkbjRjRjzjzjzlJjzjzlKkhlLjzlMlNlOlPlNlQlRlSlTjzkjkkkHkkkJkHkKkHkLkrkHkrkjlUlVkPkPkPkPkTkWkVkWkUkVlWkWkVkUlXkVkVlYlalZmahFhFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjRjRmbmcmdmemfmgjzmhkhmijzmjkhmkmlkhkhmmmnmojzkjkNkHmpkJkHkKkHkLmqkHlBkjmrkPkPmsmsmtkTmukVkVkVkVkVmvkVkVmwkVlYlnlamxmyhFhFmzmzmzmzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjzjzjzjzjzjzmAmBjzlKmCmDjzmjmEmkmFmEmGmHmnmIjzkjkHkHkHmJmKkKkHmLkHkHkHkjmMmNkPkPkPkPmOkVkVmPmQmRmSkVkVkVmTkVkVkVlamUmVhFhFmzmzmzmzbcbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajzjzjzjzjzjzjzjzmWjzjzjzmXjzjzjzjzjzjzjzjzjzjzjzjzkjkjkjkjkjmYmZjYkjkjkjkjkjnakTkTkTkTkTkTlalalalanblalalalalalalalalancndhFhFnenfngnhninjbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanknknlnmnnnknonpnqnpnrnsntnpnpnrnpnpnpnpnpnrnpnpnunpnvnvnwnxnynznAnvnwnvnvnBnCnvnDnEnBnvnvnvnvnwnvnFnvnvnvnvnwnvnvnvnvnDnGnHnInJmzmzmzbcbcbcaaaaaaaaaaaaaaaaebaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanknknKnLnMnNnOnPnQnRnSnSnSnSnSnSnSnSnSnSnSnSnSnSnTnSnSnSnSnUnVnSnWnSnSnSnSnXnSnSnSnYnZnPnPnSnSnSnSoanSnSnSnSnSnSnSnSnSnSnSnSnTobmzmzmzbcbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanknkocodoenkofogohogogogogogogogogogogogogogogmzmzmzmzmzmzmzmzmzmzmzmzmzmzmzmzoioiojoioioioioioioioioioioioioioioioioioioioioiokolomonoonjbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanknkopoqornkosotouovowoxoyozoAoBoCoDoEoBoFogogmzmzmzmzmzmzmzmzmzmzmzmzmzmzmzmzoioioGoioioioioioioioioioioioioioioioioioioioioimzmzmzmzbcbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogoHogogoIotoJoKoKoKoCoKoCoCoKoCotoFogogogbcaaaaaaaaaaaabcaaaaaaaaaaaabcaaoioioLoMoNoOoPoQoRoSoSoToSoSoUoSoSoSoVoWoXoYoioimzmzmzmzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogoZpapbpcpdotoKoKoKpeoKoKoKoDoKpeotogogogaapfaaaaaaaaaaaapfaaaaaaaaaaaapfaaoioipgoSoSoSoSoSoSphpipjpjoSoSoSoSpkoiplpmpnpopppqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogotototprpsotoKptpuptptptoDpvpeoDogogogbcpfpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwbcoioipxoSoSoSpyoSoSoSoSpzoSoSoSoSoSpAoiplpBpCpopppqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogpDpEpFpGpHogpIogogogogogogogogogogogaaaaaapwpfpfpfpfpfpfpfpfpfpfpfpfpfpwaaoioioipJpKoSoSoSoSoSoSpLoSoSoSoSpLpMoipNoioioioioiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogpOpOotpPpQpRpSpTpUpVpWpVpXpYogogogaaaaaaaapwpfpfpfpfpfpZpfpfpfpfpZpfpfpwaaaaoioioiqaqbqcqdqeqfpiqgqhqcpApjpjqcoiqioioioiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogototpGpGogqjqkqlqmotqnqoqpogogaaaaaaaaaapwpfpfpZpfpfpfpfpfpfpfpfpfpfpwaaaaaaoioipooipopopopopopopopopopopopooioioioiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogqqpGqrogqsqlqlqtotquqvqwogogaaaaaaaaaapwpfpfpfpfpfpfpfpfpZpfpfpfpfpwaaaaaaaaoiqxoippppppppppppppppppppppppoioioiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogqyqzogqAqlqlqBotquqvqwogogbcbcbcbcbcpwpfpfpfpfpfpfpfpfpfpfpfpfpfpwbcbcbcbcoippoipqpqpqpqpqpqpqpqpqpqpqpqqCbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogogogqDqlqlqEotqFqvqGogogaaaaaaaaaapwpfpfpfpfpfpfpZpfpfpfpfpfpfpwaaaaaaaaqHqHqHaaaaaaaaaaaaaaaaaaaaaaaabcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogogqIqlqlqJotqKqLqwogogqMpwpwpwaapwpfpfpfpfpZpfpfpfpfpfpZpfpfpwaaaaaaaabcbcbcaaaaaaaaaaaaaaaaaaaaaaaabcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogqlqNqlqlotqlqOqPqQqRqSqTpfpwaapwpfpZpfpfpfpfpfpfpfpfpfpfpfpwaaaaaaaabcaabcaaaaaaaaaaaaaaaaaaaaaaaabcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogqUqVqWqXotqYqZqZogogqMpwpfpwaapwpfpfpfpfpfpfpfpfpfpfpfpfpfpwaaaaaaaabcaabcaaaaaaaaaaaaaaaaaaaaaaaabcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogogogogogogogogogogaapwpfpwaapwpwpwpwpwpwpwpfpwpwpwpwpwpwpwaaaaaaaabcbcbcaaaaaaaaaaaaaaaaaaaaaaaabcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaogogogogogogogogogogogogaapwpfpwaapfaaaaaaaaaapwpfpwaaaaaaaaaapfaaaaaaaabcaabcaaaaaaaaaaaaaaaaaaaaaaaabcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpfpfpfpfpfpwpwpwpwpwpwpwpfpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpfpfpfpfpfbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpfpfpfpfpwpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfrapfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwpwpfpfpfpfbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpfpfpfpwpwpfpfpfpfpfpfpfpfpfpfpfpfpfrbpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwpwpfpfpfbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpfpfpwpwpfpfpfpfrbpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfrbpfpfpfpfpfpfpfpfpfrcpfpfpfpfpwpwpfpfbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpfpwpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfrbpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwpwpfbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpwpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfrbpfpfpfpfrbpfpfpfrbpfpfpfrbpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwpwbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpwpfpfpfpfpfpfpfpfpfpfpfrcpfpfpfpfpfpfpfpfpfpfpwpfpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwpwpfpwpwpfpfpfpfpfrbpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwpwpfpfpfpwpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwpwpfpfpfrbpfpwpwpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpfpwbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpfpfpfpfpfpfpfpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwpwbcbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaebaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaebaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaebaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/away/errant_pisces/errant_pisces_areas.dm b/maps/away/errant_pisces/errant_pisces_areas.dm new file mode 100644 index 00000000..7298ff0e --- /dev/null +++ b/maps/away/errant_pisces/errant_pisces_areas.dm @@ -0,0 +1,102 @@ +area/errant_pisces + icon = 'maps/away/errant_pisces/errant_pisces_areas_sprites.dmi'//24 areas so sprites are in a separate .dmi + +area/errant_pisces/bow_port + name = "Bow Port" + icon_state = "bow_port" + +area/errant_pisces/bow_starboard + name = "Bow Starboard" + icon_state = "bow_starboard" + +area/errant_pisces/bow_maint + name = "Bow Maintenace" + icon_state = "bow_maint" + +area/errant_pisces/storage_port + name = "Port Storage" + icon_state = "storage_port" + +area/errant_pisces/storage_starboard + name = "Starboard Storage" + icon_state = "storage_starboard" + +area/errant_pisces/solar_port + name = "Port Solars" + icon_state = "solar_port" + +area/errant_pisces/solar_starboard + name = "Starboard Solars" + icon_state = "solar_starboard" + +area/errant_pisces/atmos + name = "Atmospherics" + icon_state = "atmos" + +area/errant_pisces/enginering + name = "Engineering" + icon_state = "enginering" + +area/errant_pisces/head_f + name = "Head, F" + icon_state = "head_f" + +area/errant_pisces/head_m + name = "Head, M" + icon_state = "head_m" + +area/errant_pisces/smes_room + name = "SMES Room" + icon_state = "smes_room" + +area/errant_pisces/hallway + name = "Central Hallway" + icon_state = "hallway" + +area/errant_pisces/dorms + name = "Dorms" + icon_state = "dorms" + +area/errant_pisces/rooms + name = "Rooms" + icon_state = "rooms" + +area/errant_pisces/infirmary + name = "Infirmary" + icon_state = "infirmary" + +area/errant_pisces/cryo + name = "Cryo" + icon_state = "cryo" + +area/errant_pisces/aft_hallway + name = "Aft Hallway" + icon_state = "aft_hallway" + +area/errant_pisces/science_wing + name = "Science Wing" + icon_state = "science_wing" + +area/errant_pisces/aux_power + name = "Auxilary Power Room" + icon_state = "aux_power" + +area/errant_pisces/fishing_wing + name = "Fishing Wing" + icon_state = "fishing_wing" + +area/errant_pisces/bridge + name = "Bridge" + icon_state = "bridge" + +area/errant_pisces/prod_storage + name = "Production Storage" + icon_state = "prod_storage" + +area/errant_pisces/general_storage + name = "General Storage" + icon_state = "general_storage" + +area/errant_pisces/live_storage + name = "Live Storage" + icon_state = "live_storage" diff --git a/maps/away/errant_pisces/errant_pisces_areas_sprites.dmi b/maps/away/errant_pisces/errant_pisces_areas_sprites.dmi new file mode 100644 index 00000000..7ae10712 Binary files /dev/null and b/maps/away/errant_pisces/errant_pisces_areas_sprites.dmi differ diff --git a/maps/away/errant_pisces/errant_pisces_sprites.dmi b/maps/away/errant_pisces/errant_pisces_sprites.dmi new file mode 100644 index 00000000..0586ece8 Binary files /dev/null and b/maps/away/errant_pisces/errant_pisces_sprites.dmi differ diff --git a/maps/away/hydro/backup/hydro.dmm b/maps/away/hydro/backup/hydro.dmm new file mode 100644 index 00000000..1d2acc38 --- /dev/null +++ b/maps/away/hydro/backup/hydro.dmm @@ -0,0 +1,567 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/obj/effect/shuttle_landmark/nav_hydro/nav3,/turf/space,/area/space) +"ac" = (/obj/structure/grille,/turf/space,/area/space) +"ad" = (/obj/structure/grille,/obj/structure/lattice,/turf/space,/area/space) +"ae" = (/obj/structure/lattice,/turf/space,/area/space) +"af" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden{dir = 8; icon_state = "map"},/turf/simulated/floor/tiled,/area/hydro/station/dockport) +"ag" = (/obj/structure/grille/broken,/turf/space,/area/space) +"al" = (/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"an" = (/turf/simulated/wall/alium,/area/hydro/station/growD) +"ap" = (/turf/simulated/wall/alium,/area/hydro/station/growA) +"ar" = (/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"as" = (/turf/simulated/wall/alium,/area/hydro/station/goatzone) +"at" = (/obj/structure/lattice,/turf/simulated/wall/alium,/area/hydro/station/goatzone) +"au" = (/turf/simulated/wall/alium,/area/hydro/station/growX) +"aB" = (/turf/simulated/floor/bluegrid,/area/hydro/station/growD) +"aC" = (/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"aF" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/grass,/area/hydro/station/goatzone) +"aG" = (/obj/machinery/light{dir = 1},/obj/structure/disposalpipe/trunk{dir = 4},/obj/structure/disposaloutlet,/turf/simulated/floor/exoplanet/water/shallow,/area/hydro/station/goatzone) +"aH" = (/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/wall/alium,/area/hydro/station/goatzone) +"aO" = (/obj/machinery/firealarm{dir = 4; pixel_x = 39; pixel_y = 4},/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/exoplanet/water/shallow,/area/hydro/station/goatzone) +"aV" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"bb" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/firealarm{dir = 4; pixel_x = 39; pixel_y = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"bc" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"bd" = (/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/machinery/reagentgrinder,/obj/structure/table/glass/pglass,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"be" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"bf" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1391; id_tag = "hydrodock_pump"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/dockport) +"bg" = (/obj/item/weapon/cigbutt,/turf/simulated/floor/tiled/white,/area/hydro/station/growC) +"bn" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"br" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"bs" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"bt" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"bu" = (/obj/machinery/door/airlock/virology,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"bv" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"bw" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"bx" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"by" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"bz" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"bH" = (/obj/structure/grille,/obj/structure/grille,/turf/space,/area/space) +"bK" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"bU" = (/obj/machinery/power/solar{id = "hydrosolar"},/obj/effect/floor_decal/solarpanel,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless,/area/hydro/solars) +"bW" = (/obj/machinery/light{dir = 8},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"cb" = (/obj/structure/lattice,/obj/structure/grille,/turf/space,/area/space) +"cc" = (/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"cd" = (/obj/structure/catwalk,/obj/structure/closet/shipping_wall/filled{pixel_x = 0; pixel_y = 32},/obj/structure/table/glass/pglass,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"ce" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"cf" = (/obj/machinery/oxygen_pump{pixel_x = -32},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1391; id_tag = "hydrodock_pump"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/dockport) +"cg" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/mob/living/bot/cleanbot{faction = "farmbots"; name = "Steward Stewart"},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"cv" = (/turf/simulated/floor/bluegrid,/area/hydro/station/growC) +"cw" = (/turf/simulated/floor/tiled/white,/area/hydro/station/growC) +"cx" = (/obj/machinery/power/apc{dir = 4; icon_state = "apc0"; pixel_x = 25},/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/tiled/white,/area/hydro/station/growC) +"cz" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"cA" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"cB" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"cK" = (/obj/effect/shuttle_landmark/nav_hydro/nav2,/turf/space,/area/space) +"cM" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growC) +"cN" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growC) +"cO" = (/obj/machinery/door/airlock/virology,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"cP" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"cQ" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"cR" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"cT" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"cU" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"db" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"dc" = (/obj/item/weapon/cigbutt/menthol,/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"dd" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"de" = (/obj/effect/floor_decal/industrial/warning{dir = 8},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"df" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden,/turf/simulated/floor/tiled,/area/hydro/station/dockport) +"dg" = (/obj/structure/table/glass/pglass,/obj/item/weapon/storage/box/pillbottles,/obj/item/weapon/storage/box/pillbottles,/obj/item/weapon/reagent_containers/glass/beaker/vial/random,/obj/item/weapon/reagent_containers/glass/beaker/vial/random,/obj/item/weapon/reagent_containers/glass/beaker/vial/random,/obj/item/weapon/reagent_containers/glass/beaker/vial/random,/turf/simulated/floor/tiled,/area/hydro/station/processing) +"do" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/wall/alium,/area/hydro/station/processing) +"dp" = (/obj/structure/lattice,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/space,/area/space) +"dF" = (/turf/simulated/wall/alium,/area/hydro/station/solarlock) +"dL" = (/turf/simulated/wall/alium,/area/hydro/station/growB) +"dM" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/firealarm{dir = 8; pixel_x = -38; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"dO" = (/obj/machinery/door/airlock/virology,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/dark,/area/hydro/station/growA) +"eb" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/firedoor,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"ec" = (/obj/machinery/power/solar{id = "hydrosolar"},/obj/effect/floor_decal/solarpanel,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"ed" = (/obj/structure/catwalk,/obj/item/weapon/material/kitchen/utensil/spoon,/obj/structure/table/glass/pglass,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"ee" = (/obj/machinery/power/tracker{id = "hydrosolar"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/exoplanet/concrete,/area/space) +"ef" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1391; id_tag = "hydrodock_pump"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1391; id_tag = "hydrodock_airlock"; name = "Shipping Airlock Console"; pixel_x = 24; pixel_y = 0; req_one_access = newlist(); tag_airpump = "hydrodock_pump"; tag_chamber_sensor = "hydrodock_sensor"; tag_exterior_door = "hydrodock_outer"; tag_interior_door = "hydrodock_inner"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/dockport) +"eg" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/poisonberryseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"ej" = (/obj/machinery/power/apc{dir = 8; icon_state = "apc0"; pixel_x = -25},/obj/structure/cable/yellow,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"ex" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"ey" = (/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"ez" = (/turf/simulated/floor/bluegrid,/area/hydro/station/growB) +"eA" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"eB" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"eC" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"eD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"eK" = (/turf/simulated/wall/alium,/area/hydro/station/processing) +"eN" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/firealarm{dir = 4; pixel_x = 39; pixel_y = 4},/turf/simulated/floor/bluegrid,/area/hydro/station/growB) +"eP" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/turf/simulated/floor/plating,/area/hydro/station/shipaccess) +"eR" = (/turf/simulated/wall/alium,/area/hydro/station/shower) +"eS" = (/obj/machinery/door/airlock/virology,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fb" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/structure/catwalk,/obj/item/seeds/random,/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"fc" = (/obj/machinery/washing_machine,/obj/machinery/power/apc{dir = 1; icon_state = "apc0"; pixel_x = 0; pixel_y = 25},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fe" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"ff" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1391; id_tag = "hydrodock_pump"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/dockport) +"fg" = (/obj/structure/catwalk,/obj/item/weapon/material/kitchen/rollingpin,/obj/item/weapon/material/kitchen/utensil/knife,/obj/structure/table/glass/pglass,/obj/item/weapon/material/ashtray/bronze,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"fk" = (/obj/machinery/light{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fl" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fm" = (/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"ft" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/airlock/virology,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fu" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fv" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fx" = (/obj/structure/lattice,/turf/simulated/wall/alium,/area/hydro/station/shower) +"fy" = (/turf/simulated/wall/alium,/area/hydro/station/dockport) +"fA" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/hydro/station/dockport) +"fB" = (/obj/machinery/light{dir = 8},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fC" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/firealarm{dir = 4; pixel_x = 39; pixel_y = 4},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fV" = (/obj/structure/sign/warning/smoking,/turf/simulated/wall/alium,/area/hydro/station/dockport) +"fW" = (/obj/machinery/door/airlock/external{frequency = 1391; icon_state = "door_locked"; id_tag = "hydrodock_outer"; locked = 1; name = "Shipping Access"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hydro/station/dockport) +"fX" = (/obj/structure/lattice,/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1391; master_tag = "hydrodock_airlock"; name = "exterior access button"; pixel_x = 24; pixel_y = 24; req_one_access = newlist()},/turf/space,/area/space) +"fY" = (/obj/effect/shuttle_landmark/nav_hydro/nav1,/turf/space,/area/space) +"gb" = (/mob/living/bot/farmbot{faction = "farmbots"},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"gc" = (/obj/structure/cable{icon_state = "0-2"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/obj/machinery/power/solar{id = "hydrosolar"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"gd" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/obj/machinery/light{icon_state = "tube1"; dir = 1},/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"ge" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"gf" = (/obj/effect/floor_decal/industrial/warning,/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/manifold/hidden,/turf/simulated/floor/tiled,/area/hydro/station/dockport) +"gg" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/item/weapon/shreddedp,/turf/simulated/floor/tiled,/area/hydro/station/processing) +"hb" = (/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growD) +"hc" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/light{dir = 1},/obj/structure/dogbed{desc = "An oversized pet bed."; name = "goat bed"},/mob/living/simple_animal/hostile/retaliate/goat/king/hydro,/turf/simulated/floor/grass,/area/hydro/station/goatzone) +"hd" = (/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/machinery/smartfridge/drying_rack,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"he" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/amanitamycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"hf" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1391; id_tag = "hydrodock_pump"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/dockport) +"hg" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/cigbutt/woodbutt,/turf/simulated/floor/tiled,/area/hydro/station/processing) +"ib" = (/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"ic" = (/obj/effect/decal/cleanable/dirt,/obj/structure/flora/ausbushes/fullgrass,/obj/structure/flora/ausbushes/ywflowers,/turf/simulated/floor/grass,/area/hydro/station/goatzone) +"id" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"ie" = (/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/amanitamycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"if" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/glowberryseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"ig" = (/obj/item/weapon/shreddedp,/turf/simulated/floor/tiled,/area/hydro/station/processing) +"jb" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/structure/catwalk,/obj/item/seeds/random,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"jc" = (/obj/structure/disposalpipe/trunk{dir = 8},/obj/machinery/disposal/deliveryChute{desc = "A chute that's absolutely covered in beet and beet products."; name = "beet-stained chute"},/obj/structure/sign/warning/moving_parts{name = "\improper FEEDING CHUTE"; pixel_x = 0; pixel_y = 32},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/tiled/dark,/area/hydro/station/growF) +"jd" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/sign/warning/smoking{pixel_x = 0; pixel_y = 32},/obj/structure/bed/chair/office/light{icon_state = "officechair_white_preview"; dir = 4},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"je" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"jf" = (/obj/structure/catwalk,/obj/machinery/light,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/ambrosiadeusseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growD) +"jg" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/item/weapon/shreddedp,/turf/simulated/floor/tiled,/area/hydro/station/processing) +"kb" = (/mob/living/bot/farmbot{faction = "farmbots"},/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"kc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"kd" = (/obj/structure/grille/broken{icon_state = "grille-b"; dir = 8},/turf/space,/area/space) +"ke" = (/obj/structure/catwalk,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/machinery/light{dir = 8},/obj/machinery/firealarm{dir = 8; pixel_x = -38; pixel_y = 0},/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"kf" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/machinery/firealarm{dir = 8; pixel_x = -38; pixel_y = 0},/turf/simulated/floor/tiled,/area/hydro/station/growF) +"kg" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/catwalk,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/item/weapon/material/shard/phoron,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"lb" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/obj/machinery/light,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"lc" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"ld" = (/obj/item/weapon/cigbutt/woodbutt,/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"le" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/whitebeetseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"lf" = (/turf/simulated/floor/tiled,/area/hydro/station/growF) +"lg" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"mb" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/structure/catwalk,/obj/item/seeds/random,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"mc" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/firealarm{dir = 4; pixel_x = 39; pixel_y = 4},/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growC) +"md" = (/obj/machinery/power/solar_control/autostart{id = "hydrosolar"; track = 2},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/structure/cable,/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"me" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 4},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"mf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled,/area/hydro/station/growF) +"mg" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/catwalk,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"nb" = (/obj/structure/grille/broken{icon_state = "grille-b"; dir = 1},/obj/structure/lattice,/turf/space,/area/space) +"nc" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/firedoor,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"nd" = (/obj/machinery/power/terminal{dir = 4},/obj/structure/cable,/obj/structure/catwalk,/obj/machinery/light{dir = 1},/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"ne" = (/obj/structure/closet/l3closet/general/multi,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"nf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/hydro/station/growF) +"ng" = (/obj/structure/catwalk,/obj/item/weapon/material/butterfly/switchblade,/obj/random/coin,/obj/random/coin,/obj/structure/closet/crate/secure/weapon{desc = "A heavy-duty crate with a suite of firearms safety instructions plastered on the side. The ID scanner is unlike anything you've seen before."; name = "weapons crate"; req_one_access = list(150)},/obj/random/projectile,/obj/item/weapon/material/hatchet/tacknife,/obj/item/weapon/spacecash/bundle/c100,/obj/random/cash,/obj/random/cash,/obj/random/handgun,/obj/item/stack/material/diamond/ten,/obj/item/stack/material/gold/ten,/obj/item/stack/material/gold/ten,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"ob" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/structure/catwalk,/obj/item/seeds/random,/obj/machinery/light{dir = 1},/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"oc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/lemonseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"od" = (/obj/machinery/power/smes/buildable/max_cap_in_out,/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"oe" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"of" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/item/weapon/cigbutt/woodbutt,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"og" = (/obj/machinery/light,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/structure/table/rack,/obj/item/ammo_casing/shotgun/emp,/obj/item/ammo_casing/shotgun/emp,/obj/item/weapon/gun/projectile/shotgun/doublebarrel,/obj/structure/window/phoronreinforced{dir = 4},/obj/item/weapon/grenade/chem_grenade/antiweed,/obj/item/weapon/grenade/chem_grenade/incendiary,/obj/item/weedkiller/D24,/obj/item/weapon/material/shard/phoron,/turf/simulated/floor/tiled/dark,/area/hydro/station/processing) +"pb" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/tobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"pc" = (/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"pd" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 8; desc = "A flexible superconducting cable for heavy-duty power transfer. It's been labeled 'chaos reigns'."; icon_state = "2-8"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"pe" = (/obj/item/weapon/cigbutt,/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"pf" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"pg" = (/obj/structure/dispenser/oxygen,/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"qb" = (/obj/structure/cable/yellow,/obj/machinery/power/apc{dir = 4; icon_state = "apc0"; pixel_x = 25},/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"qc" = (/obj/structure/grille/broken{icon_state = "grille-b"; dir = 1},/turf/space,/area/space) +"qd" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/onionseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"qe" = (/obj/machinery/door/airlock/virology,/obj/machinery/door/firedoor,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"qf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/turf/simulated/floor/tiled,/area/hydro/station/growF) +"qg" = (/obj/machinery/portable_atmospherics/canister/air/airlock,/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"rb" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/firedoor,/turf/simulated/floor/fixed/alium,/area/hydro/station/growD) +"rc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/goldappleseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"rd" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/peanutseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"re" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"rf" = (/obj/machinery/seed_extractor,/obj/machinery/seed_storage/random,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"rg" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"sb" = (/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/ambrosiavulgarisseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growD) +"sc" = (/obj/structure/catwalk,/obj/machinery/light{dir = 1},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/garlicseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"sd" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/potatoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"se" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/turf/simulated/floor/fixed/alium,/area/hydro/station/solarlock) +"sf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/cigbutt/menthol,/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"sg" = (/obj/structure/curtain/open/shower,/obj/machinery/shower{icon_state = "shower"; dir = 8},/obj/item/weapon/bikehorn/rubberducky,/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"tb" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/ambrosiavulgarisseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growD) +"tc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/eggplantseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"td" = (/obj/structure/catwalk,/obj/machinery/light,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/riceseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"te" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"tf" = (/obj/structure/closet/secure_closet/hydroponics/hydro,/obj/item/weapon/material/hatchet/machete,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"tg" = (/obj/item/weapon/cigbutt,/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"ub" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/tobaccoseed,/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"uc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/cornseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"ud" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/sugarcaneseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"ue" = (/obj/effect/floor_decal/industrial/warning,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"uf" = (/obj/structure/closet/secure_closet/hydroponics/hydro,/obj/item/weapon/material/scythe,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"ug" = (/obj/machinery/portable_atmospherics/canister/air/airlock,/obj/machinery/atmospherics/portables_connector{dir = 4},/obj/effect/floor_decal/industrial/warning,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled,/area/hydro/station/shipaccess) +"vb" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/structure/catwalk,/obj/item/seeds/deathnettleseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"vc" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/puretobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"vd" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/soyaseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"ve" = (/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"vf" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"vg" = (/obj/item/clothing/under/overalls,/obj/item/clothing/shoes/desertboots,/obj/structure/closet,/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"wb" = (/mob/living/bot/farmbot{faction = "farmbots"},/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"wc" = (/obj/structure/catwalk,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/ambrosiadeusseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growD) +"wd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"we" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"wf" = (/obj/item/weapon/material/kitchen/utensil/knife,/obj/structure/table/glass/pglass,/obj/item/weapon/material/ashtray/bronze,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"wg" = (/obj/item/clothing/accessory/toggleable/hawaii/random,/obj/item/clothing/under/casual_pants/greyjeans,/obj/item/clothing/head/bowlerhat,/obj/item/clothing/shoes/leather,/obj/structure/closet,/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"xb" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"xc" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/flora/ausbushes/fullgrass,/obj/structure/flora/ausbushes/ppflowers,/turf/simulated/floor/grass,/area/hydro/station/goatzone) +"xd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/puretobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"xe" = (/obj/structure/catwalk,/obj/machinery/button/remote/blast_door{id = "shipping"; pixel_x = -25},/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"xf" = (/obj/machinery/seed_extractor,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"xg" = (/obj/item/clothing/under/skirt_c/dress/black,/obj/item/clothing/head/beret/purple,/obj/item/clothing/shoes/dress,/obj/structure/closet,/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"yb" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/structure/catwalk,/obj/item/seeds/nettleseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"yc" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/flora/ausbushes/fullgrass,/obj/structure/flora/ausbushes/lavendergrass,/turf/simulated/floor/grass,/area/hydro/station/goatzone) +"yd" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"ye" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal,/turf/simulated/floor/tiled,/area/hydro/station/processing) +"yf" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/structure/window/phoronreinforced{dir = 4},/obj/structure/catwalk,/obj/machinery/autolathe,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"yg" = (/turf/simulated/floor/fixed/alium,/area/space) +"zb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"zc" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/flora/ausbushes/fullgrass,/obj/structure/flora/ausbushes/brflowers,/turf/simulated/floor/grass,/area/hydro/station/goatzone) +"zd" = (/obj/structure/bed/chair/office/light{icon_state = "officechair_white_preview"; dir = 1},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"ze" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"zf" = (/obj/machinery/atmospherics/pipe/tank/air{dir = 4; start_pressure = 740.5},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"zg" = (/obj/machinery/light,/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/finetobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Ab" = (/mob/living/bot/farmbot{faction = "farmbots"},/turf/simulated/floor/tiled/white,/area/hydro/station/growC) +"Ac" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/effect/floor_decal/industrial/warning/cee,/turf/simulated/floor/tiled/dark,/area/hydro/station/growF) +"Ad" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Ae" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Af" = (/obj/machinery/atmospherics/pipe/manifold/visible/cyan{icon_state = "map"; dir = 1},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Bb" = (/obj/structure/catwalk,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/tobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Bc" = (/obj/structure/lattice,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Bd" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Be" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Bf" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/structure/catwalk,/obj/random/toolbox,/obj/structure/table/rack,/obj/item/weapon/gun/projectile/pirate,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Cb" = (/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/tobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Cc" = (/obj/structure/lattice,/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/wheatseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Cd" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Ce" = (/obj/machinery/mech_recharger,/mob/living/bot/farmbot{faction = "farmbots"},/turf/simulated/floor/bluegrid,/area/hydro/station/growF) +"Cf" = (/obj/machinery/light{dir = 8},/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/grassseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Db" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/tobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Dc" = (/obj/machinery/door/blast/regular{dir = 4; id = "goatzone"; name = "Containment Zone"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/artifact_scanpad{desc = "It looks like some kind of force field generator. It obviously isn't working."; name = "Containment Field Generator"},/turf/simulated/floor/tiled/white,/area/hydro/station/goatzone) +"Dd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"De" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/firedoor,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"Df" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/hydro/station/growF) +"Eb" = (/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growB) +"Ec" = (/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Ed" = (/obj/machinery/chem_master,/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Ee" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/reishimycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"Ef" = (/obj/structure/table/glass/pglass,/obj/item/seeds/random,/obj/item/seeds/random,/obj/item/seeds/random,/obj/item/weapon/gun/energy/floragun,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"Fb" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/ambrosiadeusseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growD) +"Fc" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/effect/floor_decal/solarpanel,/obj/machinery/power/solar{id = "hydrosolar"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Fd" = (/obj/structure/closet/toolcloset,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/structure/window/phoronreinforced,/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"Fe" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/angelmycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"Ff" = (/obj/machinery/biogenerator,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"Gb" = (/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/power/apc{dir = 4; icon_state = "apc0"; pixel_x = 25},/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growB) +"Gc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/chiliseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Gd" = (/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"Ge" = (/obj/machinery/atmospherics/binary/pump/on,/obj/machinery/door/blast/regular{dir = 4; id = "shipping"},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/hydro/station/shipaccess) +"Gf" = (/obj/item/weapon/cigbutt/woodbutt,/turf/simulated/floor/tiled/white,/area/hydro/station/growC) +"Hb" = (/obj/machinery/light,/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"Hc" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/catwalk,/obj/machinery/light{dir = 8},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/puretobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Hd" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/yellow,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/window/phoronreinforced,/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"He" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Hf" = (/obj/item/weapon/cigbutt/woodbutt,/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"Ib" = (/mob/living/bot/farmbot{faction = "farmbots"},/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"Ic" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Id" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"Ie" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/firedoor,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"If" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/puretobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Jb" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/machinery/firealarm{dir = 8; pixel_x = -38; pixel_y = 0},/obj/effect/floor_decal/floordetail/edgedrain,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"Jc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Jd" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"Je" = (/obj/machinery/light{dir = 8},/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/finetobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Jf" = (/obj/machinery/atmospherics/pipe/tank/air{dir = 4; start_pressure = 740.5},/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Kb" = (/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"Kc" = (/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growC) +"Kd" = (/obj/effect/floor_decal/industrial/warning{dir = 5},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"Ke" = (/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/finetobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Kf" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{icon_state = "intact"; dir = 9},/obj/machinery/light,/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Lb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/effect/floor_decal/floordetail/edgedrain,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"Lc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/pumpkinseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Ld" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Le" = (/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/catwalk,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/fixed/alium,/area/hydro/station/shipaccess) +"Lf" = (/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Mb" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/firedoor,/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"Mc" = (/obj/structure/lattice,/turf/simulated/wall/alium,/area/hydro/station/growF) +"Md" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/solar{id = "hydrosolar"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Me" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled,/area/hydro/station/shipaccess) +"Mf" = (/obj/machinery/power/apc{pixel_y = -25},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Nb" = (/obj/structure/sign/warning/biohazard,/turf/simulated/wall/alium,/area/hydro/station/growX) +"Nc" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Nd" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/finetobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Ne" = (/obj/structure/catwalk,/obj/machinery/button/remote/blast_door{id = "shipping"; pixel_x = 25},/turf/simulated/floor/fixed/alium,/area/hydro/station/shipaccess) +"Nf" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"Ob" = (/obj/machinery/door/airlock/multi_tile/glass{color = "#222222"; name = "Growing Zone X Airlock"},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/firedoor/multi_tile,/turf/simulated/floor/tiled/white,/area/hydro/station/growX) +"Oc" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/structure/sign/warning/caution{name = "\improper DO NOT ENTER - FOR AI USE ONLY"; pixel_y = 32},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Od" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Oe" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/towermycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"Of" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"Pb" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"Pc" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Pd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Pe" = (/obj/machinery/light/small{dir = 8},/obj/structure/catwalk,/obj/machinery/access_button{command = "cycle_interior"; frequency = 1391; master_tag = "hydrodock_airlock"; name = "interior access button"; pixel_x = -24; pixel_y = 0; req_access = newlist()},/turf/simulated/floor/fixed/alium,/area/hydro/station/shipaccess) +"Pf" = (/obj/machinery/vending/hydronutrients,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"Qb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/tiled/white,/area/hydro/station/growX) +"Qc" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/machinery/button/remote/blast_door{id = "goatzone"; name = "containment zone control"; pixel_w = 0; pixel_x = 0; pixel_y = 25},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Qd" = (/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Qe" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/hydro/station/shipaccess) +"Qf" = (/obj/structure/catwalk,/obj/structure/closet/crate,/obj/item/weapon/reagent_containers/pill/happy,/obj/item/weapon/reagent_containers/pill/happy,/obj/item/weapon/reagent_containers/pill/happy,/obj/item/weapon/reagent_containers/pill/happy,/obj/item/weapon/reagent_containers/pill/methylphenidate,/obj/item/weapon/reagent_containers/pill/methylphenidate,/obj/item/weapon/reagent_containers/pill/methylphenidate,/obj/random/smokes,/obj/random/smokes,/obj/random/smokes,/obj/item/weapon/reagent_containers/pill/zoom,/obj/item/weapon/reagent_containers/pill/zoom,/obj/item/weapon/reagent_containers/pill/zoom,/obj/item/toy/crossbow{desc = "A minature crossbow that fires some sort of dart from an internal magazine."; name = "mini-crossbow"},/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"Rb" = (/turf/simulated/wall/alium,/area/hydro/station/growF) +"Rc" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/light{dir = 1},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Rd" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Re" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/light/small{dir = 4},/obj/structure/catwalk,/obj/machinery/firealarm{dir = 4; pixel_x = 39; pixel_y = 4},/turf/simulated/floor/fixed/alium,/area/hydro/station/shipaccess) +"Rf" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/tomatoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Sb" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"Sc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/bluespacetomatoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Sd" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Se" = (/obj/structure/catwalk,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/towermycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"Sf" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/greengrapeseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Tb" = (/obj/machinery/portable_atmospherics/powered/scrubber,/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"Tc" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Td" = (/obj/machinery/atmospherics/binary/pump/on{dir = 4; target_pressure = 200},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Te" = (/obj/machinery/atmospherics/pipe/manifold/hidden{dir = 4; icon_state = "map"},/obj/effect/floor_decal/industrial/warning,/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/hydro/station/shipaccess) +"Tf" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/bananaseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Ub" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Uc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/bluetomatoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Ud" = (/obj/machinery/atmospherics/pipe/manifold/hidden{icon_state = "map"; dir = 1},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/machinery/access_button{command = "cycle_interior"; frequency = 1392; master_tag = "solars_airlock"; name = "interior access button"; pixel_x = 24; pixel_y = -24},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Ue" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/hydro/station/shipaccess) +"Uf" = (/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/structure/AIcore/deactivated{desc = "It looks like there's been some kind of electrical damage sustained."},/obj/effect/overmap/sector/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"Vb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Vc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Vd" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4; icon_state = "intact"},/obj/machinery/door/airlock/external{frequency = 1392; icon_state = "door_locked"; id_tag = "solars_inner"; locked = 1; name = "EVA Internal Access"},/obj/structure/catwalk,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/fixed/alium,/area/hydro/station/solarlock) +"Ve" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/chantermycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"Vf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/airlock/virology,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"Wb" = (/obj/machinery/mech_recharger,/obj/machinery/light{icon_state = "tube1"; dir = 1},/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"Wc" = (/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/whitebeetseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Wd" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4; icon_state = "intact"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1392; id_tag = "solars_airlock"; name = "EVA Airlock Console"; pixel_y = -24; tag_airpump = "solars_pump"; tag_chamber_sensor = "solars_sensor"; tag_exterior_door = "solars_outer"; tag_interior_door = "solars_inner"},/obj/machinery/power/apc{dir = 1; icon_state = "apc0"; pixel_x = 0; pixel_y = 25},/obj/structure/catwalk,/obj/machinery/light/small{dir = 1},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/fixed/alium,/area/hydro/station/solarlock) +"We" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/machinery/door/airlock/external{frequency = 1391; icon_state = "door_locked"; id_tag = "hydrodock_inner"; locked = 1; name = "Shipping Internal Access"; req_access = list(13)},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/hydro/station/dockport) +"Wf" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/wall/alium,/area/hydro/station/growF) +"Xb" = (/obj/item/weapon/cigbutt/woodbutt,/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"Xc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/peppercornseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Xd" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/machinery/airlock_sensor{frequency = 1392; id_tag = "solars_sensor"; pixel_x = 0; pixel_y = 25},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1392; id_tag = "solars_pump"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/solarlock) +"Xe" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Xf" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/wall/alium,/area/hydro/station/growF) +"Yb" = (/obj/structure/grille/broken{icon_state = "grille-b"; dir = 4},/turf/space,/area/space) +"Yc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/puretobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Yd" = (/obj/machinery/door/airlock/external{frequency = 1392; icon_state = "door_locked"; id_tag = "solars_outer"; locked = 1; name = "EVA External Access"; req_access = list(13)},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/solarlock) +"Ye" = (/obj/structure/catwalk,/obj/machinery/light,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/chantermycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"Yf" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/wall/alium,/area/hydro/station/growF) +"Zb" = (/obj/machinery/power/solar{id = "hydrosolar"},/obj/effect/floor_decal/solarpanel,/obj/structure/cable{icon_state = "0-2"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Zc" = (/obj/structure/curtain/open/shower,/obj/machinery/shower{icon_state = "shower"; dir = 8},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"Zd" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1392; master_tag = "solars_airlock"; name = "exterior access button"; pixel_x = -24; pixel_y = 24},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Ze" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/machinery/airlock_sensor{frequency = 1391; id_tag = "hydrodock_sensor"; pixel_x = 0; pixel_y = 25},/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/dockport) +"Zf" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/wall/alium,/area/hydro/station/growF) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaccbcbcbcbacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadcbaeaeaeaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaadcbaeaeaeaeaeaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadacaaaaaaaaaaadadaeaeauMbMbauaeaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeadacaaaaaaadadaeaeauaufbfbauauaeaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaenbagaaadadaeaeauaufbibibfbauauaeaecbacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeadadadaeaeauaujbibibibibmbauauaeaecbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeaeaeaeaeaeaeMbobibibxbwbibibobMbaeaecbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeaeaeaeaeaeaeaeMbTbibvbzbxbybibTbMbaeaecbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeebaeaeaeaeaeaeaeMbfbibibwdjeibibfbMbaeaecbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeebebebaeaeaeaeaeaeauaujbibibzbibmbauauaeaecbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagnbaeaeaeaeaeebebDbebebaeaeaeaeaeaeauaufbibzbfbauauaeaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeebebpbalpbebebaeaeaeaeaeaeauauJbLbauauaeaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaananrbrbrbananapebpbalgbalpbebasasasasatatauNbObQbauaeaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanansbtbtbtbsbhbappbalarararalpbasasasasasasRbmeUbVbRbaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaananFbaBaCaCaCaBXbappbararubardcpbashcicaFaGaHjckcpcRbRbcbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacanwcaBaBtbtbtbtbaCappbararubararpbasxcyczcaOasAcBcCcRbaeadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadrbFbaCaCkbaCaCaBPbappbararlbaVarpbasasasDcasasIcJcLcMcaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaerbFbaCtbaCtbaCtbbbapBbarSbapbearCbRbNcOcPcQcRcTcVcWcMcaeadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaerbFbaCFbaBFbaBFbaBapalalarWbbnalalRbpcldVcpcydCdVcleRbaeaeadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeanbraCpeaCaBaCbsbtbubvbwbxpbbyalbzqererezereBeVcVcCeIeaeaeaeadacacacacYbacacacacacacbHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeanhbFbtbjfFbFbtbqbapbKarbnpbbnarbKRbkflfmfnfofpfqfrfRbaeaeaeadZbccecaagcccecaaZbccecacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeanananananananananapbWarbnpbsfarbcRbtfuftftfvfwflfxfRbaeaeaeadaalcaeaeaelcaeaeaelcaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaencncocifrcsctcucucmcapvcarbnpbbnarvcRbzfAfBfyfDfEflfFfRbRbaeaeadZbEcecaaZbEcecaaZbEcFcqcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaencncGccvGfcwcwcwcwcwcxapHcarczcAcBHfIfRbJfKfLfMfNflfOfPfRbRbRbaeadaalcaeaeaelcaeaeaelcaeagaaaaaaaaaaaaaaaaaaaaaacKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaencncCfcvAbScRfUcSfTfcMcNcOcPcQcRUfcTcTcURbRbRbRbRbVfRbRbWfXfYfZfaeadZbEcecaeZbEcecaeZbEcecacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaencncXccvcwcwcwcwcwcwbgapHcczdbcgaVarYcapbdcdedhdidjddgmdndoddodpdpdppdaaaeaalcaaaeaalcaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaencncqdrdsdtdudvdegKcapvcarbnNdbnarxdapfgzdAdBdggDdEdFdGdHddFdFdFdFlcaaaeIdJdKdaeaaLdMdagaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaedLdLdLdLdLdLdLdLdLapdMarbnNdbnarczdOOdBdOdPdQdRdBdSdTdUdVdWdXdYdZdcecedeeefececegeaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaedLEbheheieheheheGbapejHfbnNdbnararapkehgigQfneoejgkglgmgdFdFsedFlcaaaeteueveaeaaweecacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaedLexeyeyeyezeyeAeBbueCbweDNdbyalarapxeyeGdngneAeQdogpgqgeKaeaeaelcaaaeaalcaaaeaalcaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeDeEeeyEeezFeezFeeNapalalarHbbnalalapePGeePeReReSeReReKeKeKaeaeZbHeecaeZbHeecaeZbHeecacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeDergeyEeeyFeeyFeeyapJearSbapbearKeapLeMeNeeRfcfdsgeRaeaeaeaeaeaelcaeaeaelcaeaeaelcaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadDeOeeyeyIbeyeyezddapNdarargdcBarNdapPeQeReeRfkflfmeRaeaeaeaeaeZbHeecaaZbHeecaaZbHebUacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacdLSeezezEeEeEeEetgapNdararNdararNdapugTeUeftfufvZcfxaeaeaeaeaeaelcaeaeaelcaeaeaelcaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadLdLVeezeyeyeyezeyapNddcarNdararNdfyfyWefAfyfBfmfCeRaeaeaeaeadZbXeFcaaZbXeecaaZbXeMdqcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadLdLYeezVeVeYeKbapNdalarararalNdfyZeafbffyvgwgxgeRaeaeaeaeadacacYbacacacacacacacackdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadLdLDeDeDedLdLapebNdalgbalNdebfycfdfeffyeReReReRaeadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeebebNdalNdebebfyffgfhffyygaeaeaeaeadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeebebzgebebaefVfAfWfyfyaeaeadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeebebebaeaeaeaefXaeaeaeadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeebaeaeaeaeaeaeaeaeadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeaeaeaeaeaeaeaeadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeaeaeadaeaeaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeadacaaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/hydro/hydro.dm b/maps/away/hydro/hydro.dm new file mode 100644 index 00000000..3f0a8d99 --- /dev/null +++ b/maps/away/hydro/hydro.dm @@ -0,0 +1,93 @@ +#include "hydro_areas.dm" + +// Map setup // +/obj/effect/overmap/sector/hydro + name = "unregistered hydroponics station" + desc = "A hydroponics station of unknown origin." + icon_state = "object" + known = 0 + + generic_waypoints = list( + "nav_hydro_1", + "nav_hydro_2", + "nav_hydro_3") + +/obj/effect/shuttle_landmark/nav_hydro/nav1 + name = "Navpoint Fore" + landmark_tag = "nav_hydro_1" + +/obj/effect/shuttle_landmark/nav_hydro/nav2 + name = "Navpoint Starboard" + landmark_tag = "nav_hydro_2" + +/obj/effect/shuttle_landmark/nav_hydro/nav3 + name = "Navpoint Aft" + landmark_tag = "nav_hydro_3" + +/obj/effect/overmap/sector/hydro/New() + name = "[pick("IRS","IS")] [pick("Persephone", "Demeter", "Lakshmi")]" + for(var/area/hydro/A) + A.name = "\improper [name] - [A.name]" + GLOB.using_map.area_purity_test_exempt_areas += A.type + ..() + +/datum/map_template/ruin/away_site/hydro + name = "Hydroponics Station" + id = "awaysite_hydro" + description = "Hydroponics station with farmbots and goats." + suffixes = list("hydro/hydro.dmm") + cost = 0.75 + accessibility_weight = 10 + +// Objs // +/obj/structure/closet/secure_closet/hydroponics/hydro + name = "hydroponics supplies locker" + req_access = list() + +/obj/item/projectile/beam/drone/weak + damage = 5 //1/3rd of regular projectile + +// Mobs // +/mob/living/simple_animal/hostile/retaliate/goat/king/hydro //these goats are powerful but are not the king of goats + name = "strange goat" + desc = "An impressive goat, in size and coat. His horns look pretty serious!" + health = 350 + maxHealth = 350 + melee_damage_lower = 20 + melee_damage_upper = 45 + faction = "farmbots" + +/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro + name = "Farmbot" + desc = "The botanist's best friend. There's something slightly odd about the way it moves." + icon = 'maps/away/hydro/hydro.dmi' + speak = list("Initiating harvesting subrout-ine-ine.", "Connection timed out.", "Connection with master AI syst-tem-tem lost.", "Core systems override enab-...") + emote_see = list("beeps repeatedly", "whirrs violently", "flashes its indicator lights", "emits a ping sound") + icon_state = "farmbot" + icon_living = "farmbot" + icon_dead = "farmbot_dead" + faction = "farmbots" + rapid = 0 + health = 200 + maxHealth = 200 + malfunctioning = 0 + +/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro/Initialize() + . = ..() + if(prob(15)) + projectiletype = /obj/item/projectile/energy/laser // /obj/item/projectile/beam/drone/weak + +/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro/emp_act(severity) + health -= rand(5,10) * (severity + 1) + disabled = rand(15, 30) + malfunctioning = 1 + hostile_drone = 1 + destroy_surroundings = 1 + projectiletype = initial(projectiletype) + walk(src,0) + +/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro/ListTargets() + if(hostile_drone) + return view(src, 3) + else + return ..() \ No newline at end of file diff --git a/maps/away/hydro/hydro.dmi b/maps/away/hydro/hydro.dmi new file mode 100644 index 00000000..14cfda90 Binary files /dev/null and b/maps/away/hydro/hydro.dmi differ diff --git a/maps/away/hydro/hydro.dmm b/maps/away/hydro/hydro.dmm new file mode 100644 index 00000000..9a2d4c86 --- /dev/null +++ b/maps/away/hydro/hydro.dmm @@ -0,0 +1,567 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/obj/effect/shuttle_landmark/nav_hydro/nav3,/turf/space,/area/space) +"ac" = (/obj/structure/grille,/turf/space,/area/space) +"ad" = (/obj/structure/grille,/obj/structure/lattice,/turf/space,/area/space) +"ae" = (/obj/structure/lattice,/turf/space,/area/space) +"af" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden{dir = 8; icon_state = "map"},/turf/simulated/floor/tiled,/area/hydro/station/dockport) +"ag" = (/obj/structure/grille/broken,/turf/space,/area/space) +"al" = (/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"an" = (/turf/simulated/wall/alium,/area/hydro/station/growD) +"ap" = (/turf/simulated/wall/alium,/area/hydro/station/growA) +"ar" = (/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"as" = (/turf/simulated/wall/alium,/area/hydro/station/goatzone) +"at" = (/obj/structure/lattice,/turf/simulated/wall/alium,/area/hydro/station/goatzone) +"au" = (/turf/simulated/wall/alium,/area/hydro/station/growX) +"aB" = (/turf/simulated/floor/bluegrid,/area/hydro/station/growD) +"aC" = (/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"aF" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/grass,/area/hydro/station/goatzone) +"aG" = (/obj/machinery/light{dir = 1},/obj/structure/disposalpipe/trunk{dir = 4},/obj/structure/disposaloutlet,/turf/simulated/floor/exoplanet/water/shallow,/area/hydro/station/goatzone) +"aH" = (/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/wall/alium,/area/hydro/station/goatzone) +"aO" = (/obj/machinery/firealarm{dir = 4; pixel_x = 39; pixel_y = 4},/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/exoplanet/water/shallow,/area/hydro/station/goatzone) +"aV" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"bb" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/firealarm{dir = 4; pixel_x = 39; pixel_y = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"bc" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"bd" = (/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/machinery/reagentgrinder,/obj/structure/table/glass/pglass,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"be" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"bf" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1391; id_tag = "hydrodock_pump"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/dockport) +"bg" = (/obj/item/weapon/cigbutt,/turf/simulated/floor/tiled/white,/area/hydro/station/growC) +"bn" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"br" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"bs" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"bt" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"bu" = (/obj/machinery/door/airlock/virology,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"bv" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"bw" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"bx" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"by" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"bz" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"bH" = (/obj/structure/grille,/obj/structure/grille,/turf/space,/area/space) +"bK" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"bU" = (/obj/machinery/power/solar{id = "hydrosolar"},/obj/effect/floor_decal/solarpanel,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless,/area/hydro/solars) +"bW" = (/obj/machinery/light{dir = 8},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"cb" = (/obj/structure/lattice,/obj/structure/grille,/turf/space,/area/space) +"cc" = (/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"cd" = (/obj/structure/catwalk,/obj/structure/closet/shipping_wall/filled{pixel_x = 0; pixel_y = 32},/obj/structure/table/glass/pglass,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"ce" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"cf" = (/obj/machinery/oxygen_pump{pixel_x = -32},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1391; id_tag = "hydrodock_pump"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/dockport) +"cg" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/mob/living/bot/cleanbot{faction = "farmbots"; name = "Steward Stewart"},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"cv" = (/turf/simulated/floor/bluegrid,/area/hydro/station/growC) +"cw" = (/turf/simulated/floor/tiled/white,/area/hydro/station/growC) +"cx" = (/obj/machinery/power/apc{dir = 4; icon_state = "apc0"; pixel_x = 25},/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/tiled/white,/area/hydro/station/growC) +"cz" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"cA" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"cB" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"cK" = (/obj/effect/shuttle_landmark/nav_hydro/nav2,/turf/space,/area/space) +"cM" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growC) +"cN" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growC) +"cO" = (/obj/machinery/door/airlock/virology,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"cP" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"cQ" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"cR" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"cT" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"cU" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"db" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"dc" = (/obj/item/weapon/cigbutt/menthol,/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"dd" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"de" = (/obj/effect/floor_decal/industrial/warning{dir = 8},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"df" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden,/turf/simulated/floor/tiled,/area/hydro/station/dockport) +"dg" = (/obj/structure/table/glass/pglass,/obj/item/weapon/storage/box/pillbottles,/obj/item/weapon/storage/box/pillbottles,/obj/item/weapon/reagent_containers/glass/beaker/vial/random,/obj/item/weapon/reagent_containers/glass/beaker/vial/random,/obj/item/weapon/reagent_containers/glass/beaker/vial/random,/obj/item/weapon/reagent_containers/glass/beaker/vial/random,/turf/simulated/floor/tiled,/area/hydro/station/processing) +"do" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/wall/alium,/area/hydro/station/processing) +"dp" = (/obj/structure/lattice,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/space,/area/space) +"dF" = (/turf/simulated/wall/alium,/area/hydro/station/solarlock) +"dL" = (/turf/simulated/wall/alium,/area/hydro/station/growB) +"dM" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/firealarm{dir = 8; pixel_x = -38; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"dO" = (/obj/machinery/door/airlock/virology,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/dark,/area/hydro/station/growA) +"eb" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/firedoor,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"ec" = (/obj/machinery/power/solar{id = "hydrosolar"},/obj/effect/floor_decal/solarpanel,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"ed" = (/obj/structure/catwalk,/obj/item/weapon/material/kitchen/utensil/spoon,/obj/structure/table/glass/pglass,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"ee" = (/obj/machinery/power/tracker{id = "hydrosolar"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/exoplanet/concrete,/area/space) +"ef" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1391; id_tag = "hydrodock_pump"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1391; id_tag = "hydrodock_airlock"; name = "Shipping Airlock Console"; pixel_x = 24; pixel_y = 0; req_one_access = newlist(); tag_airpump = "hydrodock_pump"; tag_chamber_sensor = "hydrodock_sensor"; tag_exterior_door = "hydrodock_outer"; tag_interior_door = "hydrodock_inner"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/dockport) +"eg" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/poisonberryseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"ej" = (/obj/machinery/power/apc{dir = 8; icon_state = "apc0"; pixel_x = -25},/obj/structure/cable/yellow,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"ex" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"ey" = (/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"ez" = (/turf/simulated/floor/bluegrid,/area/hydro/station/growB) +"eA" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"eB" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"eC" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"eD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"eK" = (/turf/simulated/wall/alium,/area/hydro/station/processing) +"eN" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/firealarm{dir = 4; pixel_x = 39; pixel_y = 4},/turf/simulated/floor/bluegrid,/area/hydro/station/growB) +"eP" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/turf/simulated/floor/plating,/area/hydro/station/shipaccess) +"eR" = (/turf/simulated/wall/alium,/area/hydro/station/shower) +"eS" = (/obj/machinery/door/airlock/virology,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fb" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/structure/catwalk,/obj/item/seeds/random,/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"fc" = (/obj/machinery/washing_machine,/obj/machinery/power/apc{dir = 1; icon_state = "apc0"; pixel_x = 0; pixel_y = 25},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fe" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"ff" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1391; id_tag = "hydrodock_pump"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/dockport) +"fg" = (/obj/structure/catwalk,/obj/item/weapon/material/kitchen/rollingpin,/obj/item/weapon/material/kitchen/utensil/knife,/obj/structure/table/glass/pglass,/obj/item/weapon/material/ashtray/bronze,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"fk" = (/obj/machinery/light{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fl" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fm" = (/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"ft" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/airlock/virology,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fu" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fv" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fx" = (/obj/structure/lattice,/turf/simulated/wall/alium,/area/hydro/station/shower) +"fy" = (/turf/simulated/wall/alium,/area/hydro/station/dockport) +"fA" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/hydro/station/dockport) +"fB" = (/obj/machinery/light{dir = 8},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fC" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/firealarm{dir = 4; pixel_x = 39; pixel_y = 4},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"fV" = (/obj/structure/sign/warning/smoking,/turf/simulated/wall/alium,/area/hydro/station/dockport) +"fW" = (/obj/machinery/door/airlock/external{frequency = 1391; icon_state = "door_locked"; id_tag = "hydrodock_outer"; locked = 1; name = "Shipping Access"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hydro/station/dockport) +"fX" = (/obj/structure/lattice,/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1391; master_tag = "hydrodock_airlock"; name = "exterior access button"; pixel_x = 24; pixel_y = 24; req_one_access = newlist()},/turf/space,/area/space) +"fY" = (/obj/effect/shuttle_landmark/nav_hydro/nav1,/turf/space,/area/space) +"gb" = (/mob/living/bot/farmbot{faction = "farmbots"},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"gc" = (/obj/structure/cable{icon_state = "0-2"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/obj/machinery/power/solar{id = "hydrosolar"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"gd" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/obj/machinery/light{icon_state = "tube1"; dir = 1},/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"ge" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"gf" = (/obj/effect/floor_decal/industrial/warning,/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/manifold/hidden,/turf/simulated/floor/tiled,/area/hydro/station/dockport) +"gg" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/item/weapon/shreddedp,/turf/simulated/floor/tiled,/area/hydro/station/processing) +"hb" = (/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growD) +"hc" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/light{dir = 1},/obj/structure/dogbed{desc = "An oversized pet bed."; name = "goat bed"},/mob/living/simple_animal/hostile/retaliate/goat/king/hydro,/turf/simulated/floor/grass,/area/hydro/station/goatzone) +"hd" = (/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/machinery/smartfridge/drying_rack,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"he" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/amanitamycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"hf" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1391; id_tag = "hydrodock_pump"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/dockport) +"hg" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/cigbutt/woodbutt,/turf/simulated/floor/tiled,/area/hydro/station/processing) +"ib" = (/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"ic" = (/obj/effect/decal/cleanable/dirt,/obj/structure/flora/ausbushes/fullgrass,/obj/structure/flora/ausbushes/ywflowers,/turf/simulated/floor/grass,/area/hydro/station/goatzone) +"id" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"ie" = (/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/amanitamycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"if" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/glowberryseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"ig" = (/obj/item/weapon/shreddedp,/turf/simulated/floor/tiled,/area/hydro/station/processing) +"jb" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/structure/catwalk,/obj/item/seeds/random,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"jc" = (/obj/structure/disposalpipe/trunk{dir = 8},/obj/machinery/disposal/deliveryChute{desc = "A chute that's absolutely covered in beet and beet products."; name = "beet-stained chute"},/obj/structure/sign/warning/moving_parts{name = "\improper FEEDING CHUTE"; pixel_x = 0; pixel_y = 32},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/tiled/dark,/area/hydro/station/growF) +"jd" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/sign/warning/smoking{pixel_x = 0; pixel_y = 32},/obj/structure/bed/chair/office/light{icon_state = "officechair_white_preview"; dir = 4},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"je" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"jf" = (/obj/structure/catwalk,/obj/machinery/light,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/ambrosiadeusseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growD) +"jg" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/item/weapon/shreddedp,/turf/simulated/floor/tiled,/area/hydro/station/processing) +"kb" = (/mob/living/bot/farmbot{faction = "farmbots"},/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"kc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"kd" = (/obj/structure/grille/broken{icon_state = "grille-b"; dir = 8},/turf/space,/area/space) +"ke" = (/obj/structure/catwalk,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/machinery/light{dir = 8},/obj/machinery/firealarm{dir = 8; pixel_x = -38; pixel_y = 0},/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"kf" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/machinery/firealarm{dir = 8; pixel_x = -38; pixel_y = 0},/turf/simulated/floor/tiled,/area/hydro/station/growF) +"kg" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/catwalk,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/item/weapon/material/shard/phoron,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"lb" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/obj/machinery/light,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"lc" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"ld" = (/obj/item/weapon/cigbutt/woodbutt,/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"le" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/whitebeetseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"lf" = (/turf/simulated/floor/tiled,/area/hydro/station/growF) +"lg" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"mb" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/structure/catwalk,/obj/item/seeds/random,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"mc" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/firealarm{dir = 4; pixel_x = 39; pixel_y = 4},/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growC) +"md" = (/obj/machinery/power/solar_control/autostart{id = "hydrosolar"; track = 2},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/structure/cable,/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"me" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 4},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"mf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled,/area/hydro/station/growF) +"mg" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/catwalk,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"nb" = (/obj/structure/grille/broken{icon_state = "grille-b"; dir = 1},/obj/structure/lattice,/turf/space,/area/space) +"nc" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/firedoor,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"nd" = (/obj/machinery/power/terminal{dir = 4},/obj/structure/cable,/obj/structure/catwalk,/obj/machinery/light{dir = 1},/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"ne" = (/obj/structure/closet/l3closet/general/multi,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"nf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/hydro/station/growF) +"ng" = (/obj/structure/catwalk,/obj/item/weapon/material/butterfly/switchblade,/obj/random/coin,/obj/random/coin,/obj/structure/closet/crate/secure/weapon{desc = "A heavy-duty crate with a suite of firearms safety instructions plastered on the side. The ID scanner is unlike anything you've seen before."; name = "weapons crate"; req_one_access = list(150)},/obj/random/projectile,/obj/item/weapon/material/hatchet/tacknife,/obj/item/weapon/spacecash/bundle/c100,/obj/random/cash,/obj/random/cash,/obj/random/handgun,/obj/item/stack/material/diamond/ten,/obj/item/stack/material/gold/ten,/obj/item/stack/material/gold/ten,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"ob" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/structure/catwalk,/obj/item/seeds/random,/obj/machinery/light{dir = 1},/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"oc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/lemonseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"od" = (/obj/machinery/power/smes/buildable/max_cap_in_out,/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"oe" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"of" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/item/weapon/cigbutt/woodbutt,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"og" = (/obj/machinery/light,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/structure/table/rack,/obj/item/ammo_casing/shotgun/emp,/obj/item/ammo_casing/shotgun/emp,/obj/item/weapon/gun/projectile/shotgun/doublebarrel,/obj/structure/window/phoronreinforced{dir = 4},/obj/item/weapon/grenade/chem_grenade/antiweed,/obj/item/weapon/grenade/chem_grenade/incendiary,/obj/item/weedkiller/D24,/obj/item/weapon/material/shard/phoron,/turf/simulated/floor/tiled/dark,/area/hydro/station/processing) +"pb" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/tobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"pc" = (/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"pd" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 8; desc = "A flexible superconducting cable for heavy-duty power transfer. It's been labeled 'chaos reigns'."; icon_state = "2-8"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"pe" = (/obj/item/weapon/cigbutt,/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"pf" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"pg" = (/obj/structure/dispenser/oxygen,/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"qb" = (/obj/structure/cable/yellow,/obj/machinery/power/apc{dir = 4; icon_state = "apc0"; pixel_x = 25},/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"qc" = (/obj/structure/grille/broken{icon_state = "grille-b"; dir = 1},/turf/space,/area/space) +"qd" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/onionseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"qe" = (/obj/machinery/door/airlock/virology,/obj/machinery/door/firedoor,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"qf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/turf/simulated/floor/tiled,/area/hydro/station/growF) +"qg" = (/obj/machinery/portable_atmospherics/canister/air/airlock,/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"rb" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/firedoor,/turf/simulated/floor/fixed/alium,/area/hydro/station/growD) +"rc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/goldappleseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"rd" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/peanutseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"re" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"rf" = (/obj/machinery/seed_extractor,/obj/machinery/seed_storage/random,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"rg" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"sb" = (/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/ambrosiavulgarisseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growD) +"sc" = (/obj/structure/catwalk,/obj/machinery/light{dir = 1},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/garlicseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"sd" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/potatoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"se" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/turf/simulated/floor/fixed/alium,/area/hydro/station/solarlock) +"sf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/cigbutt/menthol,/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"sg" = (/obj/structure/curtain/open/shower,/obj/machinery/shower{icon_state = "shower"; dir = 8},/obj/item/weapon/bikehorn/rubberducky,/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"tb" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/ambrosiavulgarisseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growD) +"tc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/eggplantseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"td" = (/obj/structure/catwalk,/obj/machinery/light,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/riceseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"te" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"tf" = (/obj/structure/closet/secure_closet/hydroponics/hydro,/obj/item/weapon/material/hatchet/machete,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"tg" = (/obj/item/weapon/cigbutt,/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"ub" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/tobaccoseed,/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"uc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/cornseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"ud" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/sugarcaneseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"ue" = (/obj/effect/floor_decal/industrial/warning,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"uf" = (/obj/structure/closet/secure_closet/hydroponics/hydro,/obj/item/weapon/material/scythe,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"ug" = (/obj/machinery/portable_atmospherics/canister/air/airlock,/obj/machinery/atmospherics/portables_connector{dir = 4},/obj/effect/floor_decal/industrial/warning,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled,/area/hydro/station/shipaccess) +"vb" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/structure/catwalk,/obj/item/seeds/deathnettleseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"vc" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/puretobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"vd" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/soyaseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"ve" = (/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"vf" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"vg" = (/obj/item/clothing/under/overalls,/obj/item/clothing/shoes/desertboots,/obj/structure/closet,/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"wb" = (/mob/living/bot/farmbot{faction = "farmbots"},/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"wc" = (/obj/structure/catwalk,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/ambrosiadeusseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growD) +"wd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"we" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"wf" = (/obj/item/weapon/material/kitchen/utensil/knife,/obj/structure/table/glass/pglass,/obj/item/weapon/material/ashtray/bronze,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"wg" = (/obj/item/clothing/accessory/toggleable/hawaii/random,/obj/item/clothing/under/casual_pants/greyjeans,/obj/item/clothing/head/bowlerhat,/obj/item/clothing/shoes/leather,/obj/structure/closet,/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"xb" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"xc" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/flora/ausbushes/fullgrass,/obj/structure/flora/ausbushes/ppflowers,/turf/simulated/floor/grass,/area/hydro/station/goatzone) +"xd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/puretobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"xe" = (/obj/structure/catwalk,/obj/machinery/button/remote/blast_door{id = "shipping"; pixel_x = -25},/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"xf" = (/obj/machinery/seed_extractor,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"xg" = (/obj/item/clothing/under/skirt_c/dress/black,/obj/item/clothing/head/beret/purple,/obj/item/clothing/shoes/dress,/obj/structure/closet,/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"yb" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/structure/catwalk,/obj/item/seeds/nettleseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"yc" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/flora/ausbushes/fullgrass,/obj/structure/flora/ausbushes/lavendergrass,/turf/simulated/floor/grass,/area/hydro/station/goatzone) +"yd" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"ye" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal,/turf/simulated/floor/tiled,/area/hydro/station/processing) +"yf" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/structure/window/phoronreinforced{dir = 4},/obj/structure/catwalk,/obj/machinery/autolathe,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"yg" = (/turf/simulated/floor/fixed/alium,/area/space) +"zb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"zc" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/flora/ausbushes/fullgrass,/obj/structure/flora/ausbushes/brflowers,/turf/simulated/floor/grass,/area/hydro/station/goatzone) +"zd" = (/obj/structure/bed/chair/office/light{icon_state = "officechair_white_preview"; dir = 1},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"ze" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"zf" = (/obj/machinery/atmospherics/pipe/tank/air{dir = 4; start_pressure = 740.5},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"zg" = (/obj/machinery/light,/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/finetobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Ab" = (/mob/living/bot/farmbot{faction = "farmbots"},/turf/simulated/floor/tiled/white,/area/hydro/station/growC) +"Ac" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/effect/floor_decal/industrial/warning/cee,/turf/simulated/floor/tiled/dark,/area/hydro/station/growF) +"Ad" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Ae" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Af" = (/obj/machinery/atmospherics/pipe/manifold/visible/cyan{icon_state = "map"; dir = 1},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Bb" = (/obj/structure/catwalk,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/tobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Bc" = (/obj/structure/lattice,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Bd" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Be" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Bf" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/structure/catwalk,/obj/random/toolbox,/obj/structure/table/rack,/obj/item/weapon/gun/projectile/pirate,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Cb" = (/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/tobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Cc" = (/obj/structure/lattice,/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/wheatseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Cd" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Ce" = (/obj/machinery/mech_recharger,/mob/living/bot/farmbot{faction = "farmbots"},/turf/simulated/floor/bluegrid,/area/hydro/station/growF) +"Cf" = (/obj/machinery/light{dir = 8},/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/grassseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Db" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/tobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Dc" = (/obj/machinery/door/blast/regular{dir = 4; id = "goatzone"; name = "Containment Zone"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/artifact_scanpad{desc = "It looks like some kind of force field generator. It obviously isn't working."; name = "Containment Field Generator"},/turf/simulated/floor/tiled/white,/area/hydro/station/goatzone) +"Dd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"De" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/firedoor,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"Df" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/hydro/station/growF) +"Eb" = (/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growB) +"Ec" = (/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Ed" = (/obj/machinery/chem_master,/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Ee" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/reishimycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"Ef" = (/obj/structure/table/glass/pglass,/obj/item/seeds/random,/obj/item/seeds/random,/obj/item/seeds/random,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"Fb" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/ambrosiadeusseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growD) +"Fc" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/effect/floor_decal/solarpanel,/obj/machinery/power/solar{id = "hydrosolar"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Fd" = (/obj/structure/closet/toolcloset,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/structure/window/phoronreinforced,/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"Fe" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/angelmycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"Ff" = (/obj/machinery/biogenerator,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"Gb" = (/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/power/apc{dir = 4; icon_state = "apc0"; pixel_x = 25},/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growB) +"Gc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/chiliseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Gd" = (/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"Ge" = (/obj/machinery/atmospherics/binary/pump/on,/obj/machinery/door/blast/regular{dir = 4; id = "shipping"},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/hydro/station/shipaccess) +"Gf" = (/obj/item/weapon/cigbutt/woodbutt,/turf/simulated/floor/tiled/white,/area/hydro/station/growC) +"Hb" = (/obj/machinery/light,/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"Hc" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/catwalk,/obj/machinery/light{dir = 8},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/puretobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Hd" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/yellow,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/window/phoronreinforced,/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"He" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Hf" = (/obj/item/weapon/cigbutt/woodbutt,/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"Ib" = (/mob/living/bot/farmbot{faction = "farmbots"},/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"Ic" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Id" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"Ie" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/firedoor,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"If" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/puretobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Jb" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/machinery/firealarm{dir = 8; pixel_x = -38; pixel_y = 0},/obj/effect/floor_decal/floordetail/edgedrain,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"Jc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Jd" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"Je" = (/obj/machinery/light{dir = 8},/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/finetobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Jf" = (/obj/machinery/atmospherics/pipe/tank/air{dir = 4; start_pressure = 740.5},/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Kb" = (/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/tiled/white,/area/hydro/station/growB) +"Kc" = (/obj/machinery/mech_recharger,/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growC) +"Kd" = (/obj/effect/floor_decal/industrial/warning{dir = 5},/turf/simulated/floor/exoplanet/concrete,/area/hydro/solars) +"Ke" = (/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/finetobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Kf" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{icon_state = "intact"; dir = 9},/obj/machinery/light,/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Lb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/effect/floor_decal/floordetail/edgedrain,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/tiled/dark,/area/hydro/station/growX) +"Lc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/pumpkinseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Ld" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Le" = (/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/catwalk,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/fixed/alium,/area/hydro/station/shipaccess) +"Lf" = (/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Mb" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/firedoor,/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"Mc" = (/obj/structure/lattice,/turf/simulated/wall/alium,/area/hydro/station/growF) +"Md" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/solar{id = "hydrosolar"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Me" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled,/area/hydro/station/shipaccess) +"Mf" = (/obj/machinery/power/apc{pixel_y = -25},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Nb" = (/obj/structure/sign/warning/biohazard,/turf/simulated/wall/alium,/area/hydro/station/growX) +"Nc" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Nd" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/finetobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Ne" = (/obj/structure/catwalk,/obj/machinery/button/remote/blast_door{id = "shipping"; pixel_x = 25},/turf/simulated/floor/fixed/alium,/area/hydro/station/shipaccess) +"Nf" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"Ob" = (/obj/machinery/door/airlock/multi_tile/glass{color = "#222222"; name = "Growing Zone X Airlock"},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/firedoor/multi_tile,/turf/simulated/floor/tiled/white,/area/hydro/station/growX) +"Oc" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/structure/sign/warning/caution{name = "\improper DO NOT ENTER - FOR AI USE ONLY"; pixel_y = 32},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Od" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Oe" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/towermycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"Of" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"Pb" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"Pc" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Pd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Pe" = (/obj/machinery/light/small{dir = 8},/obj/structure/catwalk,/obj/machinery/access_button{command = "cycle_interior"; frequency = 1391; master_tag = "hydrodock_airlock"; name = "interior access button"; pixel_x = -24; pixel_y = 0; req_access = newlist()},/turf/simulated/floor/fixed/alium,/area/hydro/station/shipaccess) +"Pf" = (/obj/machinery/vending/hydronutrients,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"Qb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/tiled/white,/area/hydro/station/growX) +"Qc" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/machinery/button/remote/blast_door{id = "goatzone"; name = "containment zone control"; pixel_w = 0; pixel_x = 0; pixel_y = 25},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Qd" = (/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Qe" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/hydro/station/shipaccess) +"Qf" = (/obj/structure/catwalk,/obj/structure/closet/crate,/obj/item/weapon/reagent_containers/pill/happy,/obj/item/weapon/reagent_containers/pill/happy,/obj/item/weapon/reagent_containers/pill/happy,/obj/item/weapon/reagent_containers/pill/happy,/obj/item/weapon/reagent_containers/pill/methylphenidate,/obj/item/weapon/reagent_containers/pill/methylphenidate,/obj/item/weapon/reagent_containers/pill/methylphenidate,/obj/random/smokes,/obj/random/smokes,/obj/random/smokes,/obj/item/weapon/reagent_containers/pill/zoom,/obj/item/weapon/reagent_containers/pill/zoom,/obj/item/weapon/reagent_containers/pill/zoom,/obj/item/toy/crossbow{desc = "A minature crossbow that fires some sort of dart from an internal magazine."; name = "mini-crossbow"},/turf/simulated/floor/fixed/alium,/area/hydro/station/processing) +"Rb" = (/turf/simulated/wall/alium,/area/hydro/station/growF) +"Rc" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/light{dir = 1},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Rd" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Re" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/light/small{dir = 4},/obj/structure/catwalk,/obj/machinery/firealarm{dir = 4; pixel_x = 39; pixel_y = 4},/turf/simulated/floor/fixed/alium,/area/hydro/station/shipaccess) +"Rf" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/tomatoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Sb" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled/white,/area/hydro/station/growA) +"Sc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/bluespacetomatoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Sd" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Se" = (/obj/structure/catwalk,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/towermycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"Sf" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/greengrapeseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Tb" = (/obj/machinery/portable_atmospherics/powered/scrubber,/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/growX) +"Tc" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Td" = (/obj/machinery/atmospherics/binary/pump/on{dir = 4; target_pressure = 200},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Te" = (/obj/machinery/atmospherics/pipe/manifold/hidden{dir = 4; icon_state = "map"},/obj/effect/floor_decal/industrial/warning,/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/hydro/station/shipaccess) +"Tf" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/bananaseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Ub" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Uc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/bluetomatoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Ud" = (/obj/machinery/atmospherics/pipe/manifold/hidden{icon_state = "map"; dir = 1},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/machinery/access_button{command = "cycle_interior"; frequency = 1392; master_tag = "solars_airlock"; name = "interior access button"; pixel_x = 24; pixel_y = -24},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/hydro/station/processing) +"Ue" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/hydro/station/shipaccess) +"Uf" = (/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/structure/AIcore/deactivated{desc = "It looks like there's been some kind of electrical damage sustained."},/obj/effect/overmap/sector/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"Vb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Vc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/white,/area/hydro/station/growF) +"Vd" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4; icon_state = "intact"},/obj/machinery/door/airlock/external{frequency = 1392; icon_state = "door_locked"; id_tag = "solars_inner"; locked = 1; name = "EVA Internal Access"},/obj/structure/catwalk,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/fixed/alium,/area/hydro/station/solarlock) +"Ve" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/chantermycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"Vf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/airlock/virology,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/hydro/station/growF) +"Wb" = (/obj/machinery/mech_recharger,/obj/machinery/light{icon_state = "tube1"; dir = 1},/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro,/turf/simulated/floor/bluegrid,/area/hydro/station/growA) +"Wc" = (/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/whitebeetseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growF) +"Wd" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4; icon_state = "intact"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1392; id_tag = "solars_airlock"; name = "EVA Airlock Console"; pixel_y = -24; tag_airpump = "solars_pump"; tag_chamber_sensor = "solars_sensor"; tag_exterior_door = "solars_outer"; tag_interior_door = "solars_inner"},/obj/machinery/power/apc{dir = 1; icon_state = "apc0"; pixel_x = 0; pixel_y = 25},/obj/structure/catwalk,/obj/machinery/light/small{dir = 1},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/fixed/alium,/area/hydro/station/solarlock) +"We" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/machinery/door/airlock/external{frequency = 1391; icon_state = "door_locked"; id_tag = "hydrodock_inner"; locked = 1; name = "Shipping Internal Access"; req_access = list(13)},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/hydro/station/dockport) +"Wf" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/wall/alium,/area/hydro/station/growF) +"Xb" = (/obj/item/weapon/cigbutt/woodbutt,/turf/simulated/floor/tiled/white,/area/hydro/station/growD) +"Xc" = (/obj/structure/catwalk,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/peppercornseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growC) +"Xd" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/machinery/airlock_sensor{frequency = 1392; id_tag = "solars_sensor"; pixel_x = 0; pixel_y = 25},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1392; id_tag = "solars_pump"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/solarlock) +"Xe" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Xf" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/wall/alium,/area/hydro/station/growF) +"Yb" = (/obj/structure/grille/broken{icon_state = "grille-b"; dir = 4},/turf/space,/area/space) +"Yc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/catwalk,/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/puretobaccoseed,/turf/simulated/floor/fixed/alium,/area/hydro/station/growA) +"Yd" = (/obj/machinery/door/airlock/external{frequency = 1392; icon_state = "door_locked"; id_tag = "solars_outer"; locked = 1; name = "EVA External Access"; req_access = list(13)},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/solarlock) +"Ye" = (/obj/structure/catwalk,/obj/machinery/light,/obj/machinery/portable_atmospherics/hydroponics,/obj/item/seeds/chantermycelium,/turf/simulated/floor/fixed/alium,/area/hydro/station/growB) +"Yf" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/wall/alium,/area/hydro/station/growF) +"Zb" = (/obj/machinery/power/solar{id = "hydrosolar"},/obj/effect/floor_decal/solarpanel,/obj/structure/cable{icon_state = "0-2"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Zc" = (/obj/structure/curtain/open/shower,/obj/machinery/shower{icon_state = "shower"; dir = 8},/turf/simulated/floor/tiled/freezer,/area/hydro/station/shower) +"Zd" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1392; master_tag = "solars_airlock"; name = "exterior access button"; pixel_x = -24; pixel_y = 24},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/fixed/alium/airless,/area/hydro/solars) +"Ze" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/machinery/airlock_sensor{frequency = 1391; id_tag = "hydrodock_sensor"; pixel_x = 0; pixel_y = 25},/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/catwalk,/turf/simulated/floor/fixed/alium,/area/hydro/station/dockport) +"Zf" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/wall/alium,/area/hydro/station/growF) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaccbcbcbcbacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadcbaeaeaeaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaadcbaeaeaeaeaeaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadacaaaaaaaaaaadadaeaeauMbMbauaeaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeadacaaaaaaadadaeaeauaufbfbauauaeaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaenbagaaadadaeaeauaufbibibfbauauaeaecbacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeadadadaeaeauaujbibibibibmbauauaeaecbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeaeaeaeaeaeaeMbobibibxbwbibibobMbaeaecbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeaeaeaeaeaeaeaeMbTbibvbzbxbybibTbMbaeaecbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeebaeaeaeaeaeaeaeMbfbibibwdjeibibfbMbaeaecbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeebebebaeaeaeaeaeaeauaujbibibzbibmbauauaeaecbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagnbaeaeaeaeaeebebDbebebaeaeaeaeaeaeauaufbibzbfbauauaeaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeebebpbalpbebebaeaeaeaeaeaeauauJbLbauauaeaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaananrbrbrbananapebpbalgbalpbebasasasasatatauNbObQbauaeaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanansbtbtbtbsbhbappbalarararalpbasasasasasasRbmeUbVbRbaecbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaananFbaBaCaCaCaBXbappbararubardcpbashcicaFaGaHjckcpcRbRbcbadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacanwcaBaBtbtbtbtbaCappbararubararpbasxcyczcaOasAcBcCcRbaeadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadrbFbaCaCkbaCaCaBPbappbararlbaVarpbasasasDcasasIcJcLcMcaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaerbFbaCtbaCtbaCtbbbapBbarSbapbearCbRbNcOcPcQcRcTcVcWcMcaeadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaerbFbaCFbaBFbaBFbaBapalalarWbbnalalRbpcldVcpcydCdVcleRbaeaeadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeanbraCpeaCaBaCbsbtbubvbwbxpbbyalbzqererezereBeVcVcCeIeaeaeaeadacacacacYbacacacacacacbHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeanhbFbtbjfFbFbtbqbapbKarbnpbbnarbKRbkflfmfnfofpfqfrfRbaeaeaeadZbccecaagcccecaaZbccecacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeanananananananananapbWarbnpbsfarbcRbtfuftftfvfwflfxfRbaeaeaeadaalcaeaeaelcaeaeaelcaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaencncocifrcsctcucucmcapvcarbnpbbnarvcRbzfAfBfyfDfEflfFfRbRbaeaeadZbEcecaaZbEcecaaZbEcFcqcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaencncGccvGfcwcwcwcwcwcxapHcarczcAcBHfIfRbJfKfLfMfNflfOfPfRbRbRbaeadaalcaeaeaelcaeaeaelcaeagaaaaaaaaaaaaaaaaaaaaaacKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaencncCfcvAbScRfUcSfTfcMcNcOcPcQcRUfcTcTcURbRbRbRbRbVfRbRbWfXfYfZfaeadZbEcecaeZbEcecaeZbEcecacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaencncXccvcwcwcwcwcwcwbgapHcczdbcgaVarYcapbdcdedhdidjddgmdndoddodpdpdppdaaaeaalcaaaeaalcaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaencncqdrdsdtdudvdegKcapvcarbnNdbnarxdapfgzdAdBdggDdEdFdGdHddFdFdFdFlcaaaeIdJdKdaeaaLdMdagaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaedLdLdLdLdLdLdLdLdLapdMarbnNdbnarczdOOdBdOdPdQdRdBdSdTdUdVdWdXdYdZdcecedeeefececegeaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaedLEbheheieheheheGbapejHfbnNdbnararapkehgigQfneoejgkglgmgdFdFsedFlcaaaeteueveaeaaweecacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaedLexeyeyeyezeyeAeBbueCbweDNdbyalarapxeyeGdngneAeQdogpgqgeKaeaeaelcaaaeaalcaaaeaalcaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeDeEeeyEeezFeezFeeNapalalarHbbnalalapePGeePeReReSeReReKeKeKaeaeZbHeecaeZbHeecaeZbHeecacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeDergeyEeeyFeeyFeeyapJearSbapbearKeapLeMeNeeRfcfdsgeRaeaeaeaeaeaelcaeaeaelcaeaeaelcaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadDeOeeyeyIbeyeyezddapNdarargdcBarNdapPeQeReeRfkflfmeRaeaeaeaeaeZbHeecaaZbHeecaaZbHebUacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacdLSeezezEeEeEeEetgapNdararNdararNdapugTeUeftfufvZcfxaeaeaeaeaeaelcaeaeaelcaeaeaelcaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadLdLVeezeyeyeyezeyapNddcarNdararNdfyfyWefAfyfBfmfCeRaeaeaeaeadZbXeFcaaZbXeecaaZbXeMdqcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadLdLYeezVeVeYeKbapNdalarararalNdfyZeafbffyvgwgxgeRaeaeaeaeadacacYbacacacacacacacackdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadLdLDeDeDedLdLapebNdalgbalNdebfycfdfeffyeReReReRaeadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeebebNdalNdebebfyffgfhffyygaeaeaeaeadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeebebzgebebaefVfAfWfyfyaeaeadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeebebebaeaeaeaefXaeaeaeadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeebaeaeaeaeaeaeaeaeadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeaeaeaeaeaeaeaeadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeaeaeadaeaeaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeaeaeadacaaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeaeaeadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/away/hydro/hydro_areas.dm b/maps/away/hydro/hydro_areas.dm new file mode 100644 index 00000000..0c08ee7c --- /dev/null +++ b/maps/away/hydro/hydro_areas.dm @@ -0,0 +1,56 @@ +/area/hydro + name = "\improper Hydrobase" + icon_state = "hydro" + icon = 'maps/away/hydro/hydro.dmi' + +/area/hydro/solars + name = "\improper Solar Array" + icon_state = "solar" + +/area/hydro/station/processing + name = "\improper Processing Area" + icon_state = "processing" + +/area/hydro/station/shipaccess + name = "\improper Shipping Access" + icon_state = "shipping" + +/area/hydro/station/shower + name = "\improper Clean Room" + icon_state = "shower" + +/area/hydro/station/growA + name = "\improper Growing Zone A" + icon_state = "A" + +/area/hydro/station/growB + name = "\improper Growing Zone B" + icon_state = "B" + +/area/hydro/station/growC + name = "\improper Growing Zone C" + icon_state = "C" + +/area/hydro/station/growD + name = "\improper Growing Zone D" + icon_state = "D" + +/area/hydro/station/growF + name = "\improper Growing Zone F" + icon_state = "F" + +/area/hydro/station/growX + name = "\improper Growing Zone X" + icon_state = "X" + +/area/hydro/station/goatzone + name = "\improper Containment Zone" + icon_state = "goatzone" + +/area/hydro/station/dockport + name = "\improper Access Port" + icon_state = "airlock" + +/area/hydro/station/solarlock + name = "\improper External Airlock" + icon_state = "airlock" \ No newline at end of file diff --git a/maps/away/icarus/backup/icarus-2.dmm b/maps/away/icarus/backup/icarus-2.dmm new file mode 100644 index 00000000..e8d12984 --- /dev/null +++ b/maps/away/icarus/backup/icarus-2.dmm @@ -0,0 +1,489 @@ +"aa" = (/turf/unsimulated/mineral,/area/space) +"ab" = (/turf/unsimulated/mask,/area/mine/unexplored) +"ac" = (/turf/simulated/open,/area/icarus/open) +"ad" = (/turf/simulated/mineral,/area/icarus/open) +"ae" = (/turf/simulated/mineral,/area/icarus/vessel) +"af" = (/obj/structure/grille,/turf/simulated/floor/plating,/area/icarus/vessel) +"ag" = (/turf/simulated/floor/plating,/area/icarus/vessel) +"ah" = (/obj/item/weapon/ore/slag,/turf/simulated/floor/plating,/area/icarus/vessel) +"ai" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aj" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ak" = (/turf/simulated/floor/tiled,/area/icarus/vessel) +"al" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"am" = (/obj/item/weapon/ore/slag,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"an" = (/obj/structure/table/steel_reinforced,/obj/random/firstaid,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ao" = (/turf/simulated/wall/r_wall,/area/icarus/open) +"ap" = (/turf/simulated/wall/r_wall,/area/icarus/vessel) +"aq" = (/obj/structure/table/steel_reinforced,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ar" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"as" = (/obj/structure/table/steel_reinforced,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"at" = (/obj/structure/table/steel_reinforced,/obj/random/handgun,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"au" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"av" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aw" = (/obj/structure/table/steel_reinforced,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ax" = (/obj/random/trash,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ay" = (/obj/structure/window/reinforced/full,/obj/machinery/door/firedoor,/obj/structure/grille,/turf/simulated/floor/tiled,/area/icarus/open) +"az" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/icarus/open) +"aA" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/obj/effect/landmark/corpse/bridgeofficer,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aB" = (/obj/effect/decal/cleanable/dirt,/obj/effect/overmap/sector/icarus,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aD" = (/obj/structure/bed/chair{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aE" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/fancy/cigarettes/killthroat,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aF" = (/obj/effect/floor_decal/plaque,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aG" = (/obj/random/loot,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aH" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/box/survival,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aI" = (/obj/structure/ladder,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aJ" = (/obj/structure/table/steel_reinforced,/obj/random/tool,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aK" = (/obj/item/modular_computer/console,/obj/item/weapon/disk/icarus,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aL" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/box/trackimp,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aM" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aN" = (/obj/item/modular_computer/console,/obj/item/weapon/paper/icarus/log,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aO" = (/obj/structure/bed/chair/comfy/captain{color = "#666666"; dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aP" = (/obj/structure/table/steel_reinforced,/obj/item/device/flashlight/lamp,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aQ" = (/obj/structure/table/rack,/obj/item/device/flashlight/flare,/obj/item/device/flashlight/flare,/obj/item/device/flashlight/flare,/obj/item/device/flashlight/flare,/turf/simulated/floor/tiled/dark,/area/icarus/vessel) +"aR" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aS" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aT" = (/obj/structure/sign/icarus/solgov{pixel_x = 30},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aU" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/box/PDAs,/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aV" = (/obj/structure/table/steel_reinforced,/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/item/weapon/storage/toolbox/emergency,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aW" = (/obj/structure/sign/icarus/solgov{pixel_x = -30},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aX" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aY" = (/obj/structure/table/rack,/obj/item/weapon/airlock_brace,/obj/item/weapon/airlock_brace,/obj/item/weapon/airlock_brace,/obj/item/weapon/crowbar/brace_jack,/turf/simulated/floor/tiled/dark,/area/icarus/vessel) +"aZ" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/telecomms/server,/turf/simulated/floor/bluegrid,/area/icarus/vessel) +"ba" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bc" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"be" = (/obj/machinery/light,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bf" = (/obj/structure/filingcabinet,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bg" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bh" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bi" = (/obj/structure/table/rack,/obj/item/weapon/storage/box/teargas{pixel_x = 3; pixel_y = 2},/obj/item/weapon/storage/box/handcuffs,/obj/item/weapon/storage/box/flashbangs{pixel_x = -2; pixel_y = -2},/turf/simulated/floor/tiled/dark,/area/icarus/vessel) +"bj" = (/obj/structure/table/rack,/obj/item/weapon/gun/projectile/shotgun/pump,/obj/item/weapon/gun/projectile/shotgun/pump,/turf/simulated/floor/plating,/area/icarus/vessel) +"bk" = (/obj/machinery/telecomms/server/presets/common,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/bluegrid,/area/icarus/vessel) +"bl" = (/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/bluegrid,/area/icarus/vessel) +"bm" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bn" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bo" = (/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bp" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/icarus/vessel) +"bq" = (/obj/structure/table/rack,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/baton,/turf/simulated/floor/plating,/area/icarus/vessel) +"br" = (/obj/structure/table/rack,/obj/item/weapon/handcuffs,/turf/simulated/floor/plating,/area/icarus/vessel) +"bs" = (/obj/machinery/telecomms/server,/turf/simulated/floor/bluegrid,/area/icarus/vessel) +"bt" = (/turf/simulated/floor/bluegrid,/area/icarus/vessel) +"bu" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bv" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bw" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bx" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"by" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bz" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bA" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bB" = (/obj/machinery/papershredder,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bC" = (/obj/machinery/photocopier,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bD" = (/obj/structure/filingcabinet,/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bE" = (/obj/structure/window/reinforced/full,/obj/machinery/door/firedoor,/obj/structure/grille,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bF" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bG" = (/obj/structure/closet,/obj/item/weapon/reagent_containers/food/drinks/bottle/tequilla,/obj/item/weapon/reagent_containers/food/drinks/bottle/wine,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bH" = (/obj/structure/bed/chair/comfy/brown{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bI" = (/obj/structure/table/woodentable,/obj/random/loot,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bJ" = (/obj/structure/table/woodentable,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bK" = (/obj/structure/bed/chair/comfy/brown{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bL" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bM" = (/obj/structure/table/steel_reinforced,/turf/simulated/floor/plating,/area/icarus/vessel) +"bN" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/handcuffs,/turf/simulated/floor/plating,/area/icarus/vessel) +"bO" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/material/harpoon,/turf/simulated/floor/plating,/area/icarus/vessel) +"bP" = (/obj/machinery/suit_storage_unit/security/alt,/turf/simulated/floor/plating,/area/icarus/vessel) +"bQ" = (/obj/structure/window/reinforced/full,/obj/structure/grille,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/open) +"bR" = (/obj/structure/table/steel,/obj/random/tool,/obj/random/tool,/obj/random/tool,/turf/simulated/floor/tiled,/area/icarus/open) +"bS" = (/obj/item/modular_computer/console,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bT" = (/obj/structure/closet,/obj/item/weapon/storage/backpack/industrial,/obj/item/weapon/storage/toolbox/electrical,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bU" = (/obj/structure/closet,/obj/item/clothing/head/helmet/space/rig/industrial,/obj/item/clothing/suit/space/emergency,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bV" = (/obj/structure/closet,/obj/item/weapon/storage/backpack/industrial,/obj/item/weapon/storage/toolbox/mechanical,/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bW" = (/obj/structure/closet,/obj/item/clothing/suit/radiation,/obj/item/clothing/suit/radiation,/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bX" = (/turf/simulated/wall,/area/icarus/vessel) +"bY" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bZ" = (/obj/structure/closet,/obj/item/weapon/reagent_containers/food/drinks/flask/shiny,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ca" = (/obj/structure/bed/chair/comfy/brown,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cc" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cd" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/icarus/vessel) +"ce" = (/obj/structure/table/steel,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cf" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/obj/effect/landmark/corpse/engineer,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cg" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ch" = (/obj/random/trash,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ci" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cj" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ck" = (/obj/structure/closet,/obj/item/weapon/reagent_containers/food/drinks/golden_cup,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cl" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/backpack/captain,/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cm" = (/obj/structure/table/woodentable,/obj/item/weapon/paper/icarus/crew_roster,/obj/item/weapon/folder/blue,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cn" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/icarus/vessel) +"co" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cp" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cq" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cr" = (/obj/machinery/light{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cs" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ct" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cu" = (/obj/structure/table/steel_reinforced,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cv" = (/obj/structure/table/steel,/obj/random/tank,/turf/simulated/floor/tiled,/area/icarus/open) +"cw" = (/turf/simulated/floor/tiled,/area/icarus/open) +"cx" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/tiled,/area/icarus/open) +"cy" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cz" = (/obj/structure/bed,/obj/item/weapon/bedsheet/captain,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cA" = (/obj/structure/table/woodentable,/obj/item/weapon/reagent_containers/food/drinks/bottle/whiskey,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cB" = (/obj/structure/sign/double/icarus/solgovflag/left{pixel_y = -32},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cC" = (/obj/structure/sign/double/icarus/solgovflag/right{pixel_y = -32},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cD" = (/obj/structure/table/woodentable,/obj/item/toy/ship_model,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cE" = (/obj/structure/table/woodentable,/obj/random/action_figure,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cF" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cG" = (/obj/item/weapon/stool,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cH" = (/obj/item/weapon/stool,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cJ" = (/obj/structure/table/steel_reinforced,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cK" = (/obj/machinery/alarm{dir = 1; pixel_y = -25; req_one_access = list(24,11)},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cL" = (/turf/simulated/floor/plating,/area/icarus/open) +"cM" = (/obj/structure/table/rack,/obj/random/tool,/turf/simulated/floor/tiled,/area/icarus/open) +"cN" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cO" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cP" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cQ" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cR" = (/obj/structure/lattice,/turf/simulated/open,/area/icarus/open) +"cS" = (/obj/structure/table/rack,/obj/random/tech_supply,/turf/simulated/floor/tiled,/area/icarus/open) +"cT" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cU" = (/obj/machinery/alarm{alarm_id = "xenobio4_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cV" = (/obj/item/modular_computer/console,/obj/machinery/light{dir = 1},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cW" = (/obj/structure/table/woodentable,/obj/item/weapon/disk/secret_project/science,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cX" = (/obj/structure/window/reinforced/full,/obj/structure/grille,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cY" = (/obj/machinery/light{dir = 1},/obj/structure/table/standard,/obj/structure/window/reinforced{dir = 8},/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cZ" = (/obj/structure/table/standard,/obj/machinery/reagentgrinder,/turf/simulated/floor/tiled,/area/icarus/vessel) +"da" = (/obj/machinery/light{dir = 1},/obj/structure/table/standard,/obj/item/weapon/storage/box/monkeycubes,/turf/simulated/floor/tiled,/area/icarus/vessel) +"db" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/beakers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dc" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dd" = (/obj/structure/bed,/turf/simulated/floor/tiled,/area/icarus/vessel) +"de" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"df" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dg" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dh" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"di" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dj" = (/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/tiled,/area/icarus/open) +"dk" = (/obj/structure/sign/science_2{pixel_x = 30},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dl" = (/obj/structure/bed/chair/comfy/brown{dir = 4},/obj/effect/landmark/corpse/scientist,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dm" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dn" = (/obj/machinery/door/window/eastleft,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"do" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dp" = (/obj/structure/closet,/obj/item/weapon/gun/projectile/shotgun/pump,/obj/item/weapon/reagent_containers/spray/pepper,/obj/item/weapon/storage/box/handcuffs,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dq" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dr" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"ds" = (/obj/structure/table/rack,/obj/random/tool,/obj/random/powercell,/turf/simulated/floor/tiled,/area/icarus/open) +"dt" = (/obj/item/modular_computer/console,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"du" = (/obj/structure/table/woodentable,/obj/item/device/flashlight/lamp,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dv" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/box/fingerprints,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dw" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"dx" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dy" = (/obj/random/loot,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dz" = (/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dA" = (/obj/structure/bed,/obj/item/trash/snack_bowl,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dB" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dC" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/box/flashshells,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dD" = (/obj/random/trash,/turf/simulated/floor/tiled,/area/icarus/open) +"dE" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dF" = (/obj/structure/closet,/obj/item/clothing/suit/storage/toggle/labcoat/blue,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dG" = (/obj/structure/closet,/obj/item/clothing/suit/storage/toggle/labcoat/blue,/obj/item/weapon/disk/survey,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dH" = (/obj/structure/table/standard,/obj/item/device/flashlight/lamp,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dI" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/reagent_containers/spray/pepper,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dJ" = (/obj/item/modular_computer/console,/obj/machinery/alarm{dir = 1; pixel_y = -25; req_one_access = list(24,11)},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dK" = (/turf/simulated/wall,/area/icarus/open) +"dL" = (/obj/effect/decal/cleanable/dirt,/obj/random/trash,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"dM" = (/obj/item/modular_computer/console,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dN" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"dO" = (/obj/machinery/r_n_d/destructive_analyzer,/turf/simulated/floor/tiled,/area/icarus/open) +"dP" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/open) +"dQ" = (/obj/random/trash,/turf/simulated/floor/plating,/area/icarus/open) +"dR" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/icarus/open) +"dS" = (/obj/structure/bed,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dT" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"dU" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"dV" = (/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/open) +"dW" = (/obj/machinery/door/window/eastleft,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/open) +"dX" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dY" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled,/area/icarus/open) +"dZ" = (/obj/effect/icarus/irradiate,/turf/simulated/open,/area/icarus/open) +"ea" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/icarus/open) +"eb" = (/obj/item/clothing/ring/mariner,/turf/simulated/floor/tiled,/area/icarus/open) +"ec" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/icarus/open) +"ed" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/open) +"ee" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/open) +"ef" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/open) +"eg" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"eh" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ei" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/icarus/vessel) +"ej" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/obj/structure/sign/warning/internals_required{pixel_y = -30},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ek" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled,/area/icarus/vessel) +"el" = (/obj/structure/sign/warning/airlock{pixel_y = -30},/turf/simulated/floor/plating,/area/icarus/vessel) +"em" = (/obj/random/material,/turf/simulated/floor/plating,/area/icarus/vessel) +"en" = (/obj/machinery/door/airlock,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/icarus/vessel) +"eo" = (/obj/structure/grille,/turf/simulated/floor/reinforced,/area/icarus/open) +"ep" = (/turf/simulated/floor/reinforced,/area/icarus/open) +"eq" = (/turf/simulated/shuttle/wall,/area/icarus/open) +"er" = (/turf/simulated/shuttle/wall{icon_state = "swall_straight"; dir = 4},/area/icarus/vessel) +"es" = (/turf/simulated/shuttle/wall{icon_state = "swall_t"; dir = 1},/area/icarus/vessel) +"et" = (/obj/structure/shuttle/window,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eu" = (/obj/structure/shuttle/engine/propulsion{dir = 4},/turf/simulated/shuttle/wall,/area/icarus/open) +"ev" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/icarus/vessel) +"ew" = (/obj/structure/shuttle/engine/propulsion{icon_state = "propulsion_l"; dir = 8},/turf/simulated/shuttle/wall,/area/icarus/vessel) +"ex" = (/obj/structure/shuttle/window,/turf/simulated/floor/shuttle/white,/area/icarus/open) +"ey" = (/obj/structure/table/reinforced,/turf/simulated/floor/shuttle/white,/area/icarus/open) +"ez" = (/obj/machinery/light/small{dir = 4; pixel_y = 0},/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eA" = (/turf/simulated/shuttle/wall{icon_state = "swall"; dir = 1},/area/icarus/vessel) +"eB" = (/obj/structure/bed/chair,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eC" = (/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eD" = (/obj/structure/table/rack,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eE" = (/obj/structure/table/rack,/obj/item/clothing/mask/breath/emergency,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eF" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/icarus/vessel) +"eG" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eH" = (/obj/machinery/portable_atmospherics/canister/carbon_dioxide,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eI" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eJ" = (/obj/item/modular_computer/console,/turf/simulated/floor/shuttle/white,/area/icarus/open) +"eK" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eL" = (/obj/machinery/door/airlock,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eM" = (/obj/machinery/door/airlock/external,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eN" = (/obj/machinery/door/airlock/external,/turf/simulated/floor/plating,/area/icarus/vessel) +"eO" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1379; id_tag = "bridgeport_pump"},/turf/simulated/floor/plating,/area/icarus/vessel) +"eP" = (/obj/machinery/door/airlock/external,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"eQ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/turf/simulated/floor/plating,/area/icarus/vessel) +"eR" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1331; id_tag = "ninja_shuttle_pump"},/turf/simulated/floor/plating,/area/icarus/vessel) +"eS" = (/obj/structure/bed/chair{dir = 4},/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eT" = (/turf/simulated/shuttle/wall{dir = 2; icon_state = "swall"},/area/icarus/vessel) +"eU" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/shuttle/white,/area/icarus/open) +"eV" = (/obj/machinery/light/small,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eW" = (/turf/simulated/shuttle/wall,/area/icarus/vessel) +"eX" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eY" = (/turf/simulated/shuttle/wall{icon_state = "swall_straight"; dir = 4},/area/icarus/open) +"eZ" = (/turf/simulated/shuttle/wall{icon_state = "swall_t"; dir = 2},/area/icarus/open) +"fa" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/icarus/vessel) +"fb" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/plating,/area/icarus/vessel) +"fc" = (/obj/structure/shuttle/engine/propulsion{icon_state = "propulsion_l"; dir = 8},/turf/simulated/shuttle/wall,/area/icarus/open) +"fd" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/power/solar,/turf/simulated/floor/reinforced,/area/icarus/open) +"fe" = (/obj/machinery/power/solar_control,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/plating,/area/icarus/vessel) +"ff" = (/obj/machinery/power/terminal{dir = 4},/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/icarus/vessel) +"fg" = (/obj/machinery/power/smes/buildable,/obj/structure/cable,/turf/simulated/floor/plating,/area/icarus/vessel) +"fh" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fi" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fj" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fk" = (/obj/machinery/door/airlock/external,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/icarus/vessel) +"fl" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fm" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fn" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fo" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow,/obj/machinery/power/solar,/turf/simulated/floor/reinforced,/area/icarus/open) +"fp" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fq" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1331; id_tag = "calypso_shuttle_pump"},/turf/simulated/floor/plating,/area/icarus/vessel) +"fr" = (/obj/machinery/door/airlock/external,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/icarus/open) +"fs" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"ft" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fu" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fv" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fw" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fx" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow,/turf/simulated/floor/reinforced,/area/icarus/open) +"fy" = (/obj/machinery/power/tracker,/obj/structure/cable/yellow,/turf/simulated/floor/reinforced,/area/icarus/open) +"gb" = (/obj/effect/landmark/map_data{height = 2},/turf/unsimulated/mineral,/area/space) +"hb" = (/obj/effect/landmark/random_gen/asteroid,/turf/unsimulated/mineral,/area/space) + +(1,1,1) = {" +gbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacabababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababacacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacacacacababababababacababababababacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababacacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacacacacacacabababacacacacacababababacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababacacacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacacacacacacacacacabababacacacacacacabababacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababacacacacacacadadadadadadadadadadadadadadadadadaeaeaeadaeaeaeadadadadadadadadadadadadadadadacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababacacacacacacacadadadadadadadadadadadadadadadadaeaeafaeadaeagaeaeadadadadadadadadadadadadadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababacacacabababababacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababacacacacacacacacacacadadadadadadadadadadadadadaeahagagaeaeahagaeadadadadadadadadadadadadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababacacacababababababababacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababacacacacacacacacacadadadadadadadadadadadadaeaeagagaiajagagakakahaeadadadadadadadadadadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacababababababababababababacacacacacacacacacacacacacacacacababababababababababababababababababababacacacacacacacacacacacadadadadadadadadadadaeahakakaiakalakakamaianaoacacacadadadadadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacababababababababababababababacacacacacacacacacacacacacacababababababababababababababababababababababacacacacacacacacacacacacacacadadadadadadadapaqararaiaiakakakakakasaoacacacacadadadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacabababababababababababababababababacacacacacacacacacacacababacacabababababababababababababababababababacacacacacacacacacacacacacacacadadadapapapatauaiavakakakaiakakawapaoaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababacabababababababababababababababacacacacacacacacacacacacacacacacacabababababababababababababababababacacacacacacacacacacacacacacacacacadapajararaiakaiakakakakakaxakakajaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacabababababababababababababababababacacacacacacacacacacacacacacacacacacayazaAakaiakaxakaBakakaxakakaDazayacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacababababacacacacababababababacacacacacacacacacacacacacacacacacacaoajakaiakakakakakakaiakakakakajaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacabababacacacacacacacabababacacacacacacacacacacacacacacacacaoapapapaEakakakakakaFakaiaGakakaHapapaoaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoaoaoapaIakapaJaxakaiakajaKajakaiakakaLapakaIapaoaoaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoaMaNapaIakapaJakakakakakaOakakakakakaPapakaIapaQagaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoapaMaRapaSaTapaUakakakakakakakakakakakaVapaWaXapaYagapaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoapaZakakapbabbbcbdbeakbfbfbfakbfbfbfbfbgakbhakakapbiagbjapaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoapbkblakbmapbnboapapapbhapapapbhapapapapapapapboboapbpagbqbrapaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoapbsbtbtbubvbwbxbbbcbybzakapakakakakbAakbBbCbDbEakakapagagagagagapaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoapapapapapapapapbFakapbGakbfapakbHbIbJbKakakakbLapakaiapagbMbNbOagbPapaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacbQbRajbSbTbUbVbWbXbYakapbZakcaapakbHbJbJbKakakaxcbbwbbccapcdapapapapapapapaoacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaocecfarakakcgchbwcicjapckakclapakbHbJcmbKakakakcnapcocpbccqcrcsctcuaRbAbfaoacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaocvcwcwcwcwcwcxbXcybzapczbgcAapakakcBcCbgakbIcDcEbEaxcFapcGcHcHcIcJajcKakaoacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaocwcwcLcLcLcwcMbXcNaxapapapapapapapapapapapapapapapakcOapapapapcPapapapcQaoacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaocwcwcLcRaccLcSbXcTbbbccUcVcWcXaMcYcZaMdadbaMbBbCapakdcapddcXbudedfdgdhdiaoacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaodjcwcLacaccLcSbXbYdkapbYdlbJcXakakakakakakakakdmapakbYapakdnakdoapdpdqdrbQacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLdjcwcLaccRcLdsbXbFakapcydtducXakakakakaiaiakakbfapaibYapapapaiakapdvakdwbQacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLcwcwcLcRaccLcwbXbYakapdxapapapakdyakdzakakdzakbfapaibYapdAcXaidBapdCdzdwbQacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLcLdDcLaccLcLcwbXbYakapdEcsdFdGakakaMajdHaMajaMbfapaibYapaidnakaiapdIdJbYaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLcLcwcLcLcLcwcwdKdLcwaodMakcwcwcwcLcLcLcLcLcLcLcLcLcwdNapapapakaiapapapcPaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLcLcLcwcwdDcwcLdKdwcwaodOdPcwcwdQcLacaccRaccLcLdRcLcwdwaocwbQakaiapdddSdTbQacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLcLcLcwcwcwcwcLdKdUdVaocwdPcLcLdRcLcRaccRacdQcLcLcLdVdUcLcwdWcwcwapakakdXbQacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLcRcLcLdDcwcwcLdKdwcwcLcwcwcLcLcLcLcRcRcRcRcRcLcLcLcLdRcLcLcLcwcwdYcwcLcLbQacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRcRcLcLcwcwcLcLdKdwdDcLcLcLdQacaccRcRcRaccRacdRcLacaccRacacdRcLcwaoaocLcLcLacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRcLcLcLcLcLcLdKdwcwcLdRcLcLacaccRcRcRaccRacacacacaccRcRaccLdQcLaocLcLdRacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRacdRcLdQcLcLdKaccLcLcLcRcRacaccRacacacacacacacacacaccRacaccLcLcLcLcLcLacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLcLcLcLcLdKcRcRcRaccRcRcRacacacacacacacacacacacacacacacacaccLcLdRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRcLcLdRcLdRacaccRcRacaccRacacacacacacacacacacacacacacacacacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRcRacaccLcRcRaccRacacaccRacacacacacacacacacacacacacacacacacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRcRacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacdZacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababacacababababababababababababababababababababababababaa +aaabababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababacababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacaccRcRacacacacacacacacacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacacacacacacacacacacacacacacabacacacacacacacacacacabababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacaodRcRacacaccRacacacacacaccRcRcRacacacacacacacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacacacacacabacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacaocwcLacaccRcRcRacacacaccLcLdRcLcLacacaccRacacaccRcRacacacacacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacacacacacabababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacaocwcLcLaccRdKcRaccLcLacaccLcLcLcLacaccRcRcRaccLcLcLacacacacaccRcRacaccRcRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacaocwcLdRcLcLdKcLaccLdRcLcLcLcLcLcLcLeacLcLcRcRcLcLcLcLcLcLcLcRcRcRcRaccRcRcRacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacaocwebdPcwcwdKcLcLcLcLcLcwcwdPdPcwcweccLcLcLcLcLcLcLcLdRcLcLcLcLcLcLacaccRcRacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacabababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaodPcweddPcweecwcwcLcLcwcwefdPdPcwcwegcLcLdRcLcLcLcLcLcLcLcLcLcLcLcLacaccRcRacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacabababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaodPdPefaiakbXakakakakaiavavavaiaiakehagagagagagagagagagagagageiagcLcLdRcRcRacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacaocwdPdPakakbXaIakakakakakakakakakejekelagagagagagagagagemagagagagcLcLcLcLaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoaoaoaoapapapapapapapapapapapapapapenapapapapapapapapapapapapapapaoaoaoaoaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoepepeqerereseteteterererereuepepapevapepepewerererereteteteserereqepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoepepexeyezeAeBeBeBeCeDeDeEeAapapapeFapapapeAeGeHeCeIeBeBeBeAeCeyexepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoepepexeJeKeLeCeCeCeCeCeCeCeMeNeOePeQePeReNeMeCeCeCeCeCeCeCeLeSeJexepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoepepexeyeCeTeUeUeUeVeCeHeGeWaoapapenapapaoeTeDeDeEeCeUeUeUeTeXeyexepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoepepeqeYeYeZexexexeYeYeYeYeuepaobpfafbaoepfceYeYeYeYexexexeZeYeYeqepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceofdfdfdfdfdfdfdfdfdfdfdfdfdepepaofefffgaoepepfdfdfdfdfdfdfdfdfdfdfdfdfdfdeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceofhfififififififififififififjepaoapfkapaoepflfmfmfmfmfmfmfmfmfmfmfmfmfmfneoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceofofofofofofofofofofofofofofpepepaofqaoepepfpfofofofofofofofofofofofofofoeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoepepepepepepepepepepepepepfpepepaofraoepepfpepepepepepepepepepepepepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoepepepfdfdfdfdfdfdfdfdfdfdfpepepepfpepepepfpfdfdfdfdfdfdfdfdfdfdfdfdfdfdeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRcRcRcRfhfififififififififififsfsfsftfufufvfwfmfmfmfmfmfmfmfmfmfmfmfmfmfneoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRcRfocRcRfxfofofofofofofofofofofpepepfofofofofofofofofofofofofofofofoeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababacacababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRacepcRcRcRepepepepepepepepepepfpepepepepepepepepepepepepepepepepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRaccRaccRcRcRfdfdfdfdfdfdfdfdfdfpfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRacacaccRfifififififififififtfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfneoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRaccRcRcRfofofofofofofofofofpfofofofofofofofofofofofofofofofofofoeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRaccRepepepepepepepepepfyepepepepepepepepepepepepepepepepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacepepepepepepepepepepepepepepepepepepepepepepepepepepepacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababacacacacabababababababababacacacacabababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacepepepepepepepepepepepepepepepepepepepepepepepepepepacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababacacacacacacacababababababababacacacacabababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacepepepepepepepepepepepepepepepepepepepepepepepepepacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacabababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacepepacacacacepepepepepepepepepacacacacepepepepepacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacabababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacepacacacacacepepepepepepepacacacacacepepepepepacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacepepepepepacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababacacacacacacacacacacacacacacacababacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababacacacacacacacacacacacacacacacababacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacacacacacacababacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacacacacacacababacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacabababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacabababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababacababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababacababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababacacabababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +hbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/icarus/icarus-1.dmm b/maps/away/icarus/icarus-1.dmm new file mode 100644 index 00000000..00118d0e --- /dev/null +++ b/maps/away/icarus/icarus-1.dmm @@ -0,0 +1,635 @@ +"aa" = (/turf/unsimulated/mineral,/area/space) +"ab" = (/turf/unsimulated/mask,/area/mine/unexplored) +"ac" = (/turf/simulated/floor/exoplanet/grass,/area/icarus/open) +"ae" = (/turf/simulated/mineral,/area/icarus/open) +"af" = (/turf/simulated/mineral,/area/icarus/vessel) +"ag" = (/obj/structure/grille,/turf/simulated/floor/plating,/area/icarus/vessel) +"ah" = (/turf/simulated/floor/plating,/area/icarus/vessel) +"ai" = (/obj/item/weapon/ore/slag,/turf/simulated/floor/plating,/area/icarus/vessel) +"aj" = (/turf/simulated/floor/wood,/area/icarus/vessel) +"ak" = (/obj/item/weapon/ore/slag,/turf/simulated/floor/wood,/area/icarus/vessel) +"al" = (/obj/structure/flora/ausbushes/palebush,/turf/simulated/floor/exoplanet/grass,/area/icarus/open) +"am" = (/obj/structure/bed/chair/comfy/black,/turf/simulated/floor/wood,/area/icarus/vessel) +"an" = (/obj/structure/bed/chair/comfy/captain,/turf/simulated/floor/wood,/area/icarus/vessel) +"ao" = (/obj/structure/bed/chair/comfy/black,/obj/item/weapon/storage/secure/briefcase,/turf/simulated/floor/wood,/area/icarus/vessel) +"ap" = (/obj/random/trash,/turf/simulated/floor/wood,/area/icarus/vessel) +"aq" = (/turf/simulated/wall/r_wall,/area/icarus/open) +"ar" = (/obj/structure/flora/tree/dead,/turf/simulated/floor/exoplanet/grass,/area/icarus/open) +"as" = (/turf/simulated/wall/r_wall,/area/icarus/vessel) +"at" = (/obj/structure/closet/gmcloset,/turf/simulated/floor/wood,/area/icarus/vessel) +"au" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/lighter/zippo,/obj/random/smokes,/turf/simulated/floor/wood,/area/icarus/vessel) +"av" = (/obj/structure/table/woodentable,/turf/simulated/floor/wood,/area/icarus/vessel) +"aw" = (/obj/machinery/papershredder,/turf/simulated/floor/wood,/area/icarus/vessel) +"ax" = (/obj/item/weapon/ore/slag,/turf/simulated/floor/exoplanet/grass,/area/icarus/open) +"ay" = (/obj/item/weapon/shreddedp,/turf/simulated/floor/wood,/area/icarus/vessel) +"az" = (/obj/structure/table/woodentable,/obj/random/smokes,/turf/simulated/floor/wood,/area/icarus/vessel) +"aA" = (/obj/machinery/photocopier,/turf/simulated/floor/wood,/area/icarus/vessel) +"aB" = (/obj/structure/bed/chair/comfy/black{icon_state = "comfychair_preview"; dir = 1},/turf/simulated/floor/wood,/area/icarus/vessel) +"aD" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/lunchbox/mars,/turf/simulated/floor/wood,/area/icarus/vessel) +"aE" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/photo_album,/turf/simulated/floor/wood,/area/icarus/vessel) +"aF" = (/obj/structure/table/woodentable,/obj/random/drinkbottle,/obj/random/drinkbottle,/obj/random/snack,/turf/simulated/floor/wood,/area/icarus/vessel) +"aG" = (/obj/machinery/light,/obj/structure/filingcabinet/filingcabinet,/turf/simulated/floor/wood,/area/icarus/vessel) +"aH" = (/obj/structure/filingcabinet/filingcabinet,/turf/simulated/floor/wood,/area/icarus/vessel) +"aI" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/wood,/area/icarus/vessel) +"aJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/wood,/area/icarus/vessel) +"aK" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/wood,/area/icarus/vessel) +"aL" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigar,/turf/simulated/floor/wood,/area/icarus/vessel) +"aM" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/wood,/area/icarus/vessel) +"aN" = (/obj/structure/ladder/up,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aO" = (/obj/structure/sign/directions/bridge{dir = 1; pixel_y = 30; pixel_z = 6},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aP" = (/turf/simulated/floor/tiled,/area/icarus/vessel) +"aQ" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aR" = (/obj/structure/sign/icarus/solgov{pixel_y = 30},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aS" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aT" = (/obj/random/obstruction,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aU" = (/obj/structure/sign/directions/security{dir = 1; pixel_y = 30; pixel_z = -6},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aV" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/plating,/area/icarus/vessel) +"aW" = (/obj/structure/janitorialcart,/obj/item/weapon/mop,/turf/simulated/floor/plating,/area/icarus/vessel) +"aX" = (/turf/simulated/wall,/area/icarus/vessel) +"aY" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aZ" = (/obj/random/obstruction,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ba" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bb" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bc" = (/obj/random/trash,/turf/simulated/floor/tiled/freezer,/area/icarus/vessel) +"bd" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/simulated/floor/tiled/freezer,/area/icarus/vessel) +"be" = (/obj/machinery/light/small{dir = 4; pixel_y = 0},/obj/random/trash,/turf/simulated/floor/plating,/area/icarus/vessel) +"bf" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bg" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bh" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled/freezer,/area/icarus/vessel) +"bi" = (/obj/structure/closet/l3closet/janitor,/turf/simulated/floor/plating,/area/icarus/vessel) +"bj" = (/obj/random/trash,/turf/simulated/floor/plating,/area/icarus/vessel) +"bk" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/icarus/vessel) +"bl" = (/obj/random/closet,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bm" = (/obj/structure/closet,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bn" = (/obj/structure/noticeboard{pixel_y = -25},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bo" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bp" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bq" = (/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/icarus/vessel) +"br" = (/turf/simulated/floor/tiled/freezer,/area/icarus/vessel) +"bs" = (/obj/structure/closet/crate/freezer/rations,/turf/simulated/floor/tiled/freezer,/area/icarus/vessel) +"bt" = (/obj/structure/table/marble,/obj/random/plushie/large,/turf/simulated/floor/tiled/freezer,/area/icarus/vessel) +"bu" = (/obj/machinery/door/firedoor,/obj/structure/sign/greencross{pixel_x = -30},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bv" = (/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bw" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled/freezer,/area/icarus/vessel) +"bx" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/icarus/vessel) +"by" = (/obj/machinery/light{dir = 1},/obj/structure/table/steel,/obj/item/weapon/folder/white,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bz" = (/obj/structure/bed/roller,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bA" = (/obj/machinery/alarm{alarm_id = "xenobio4_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/structure/bed/roller,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bB" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bC" = (/obj/structure/toilet{dir = 4},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"bD" = (/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"bE" = (/obj/random/trash,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"bF" = (/obj/structure/toilet{dir = 8},/obj/machinery/light/small{dir = 1},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"bG" = (/obj/structure/sink{dir = 1; pixel_y = 16},/obj/structure/mirror{pixel_x = 0; pixel_y = 30},/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"bH" = (/obj/machinery/shower{dir = 4; icon_state = "shower"; pixel_x = 0},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"bI" = (/obj/machinery/shower{icon_state = "shower"; dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"bJ" = (/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"bK" = (/obj/structure/table/marble,/obj/machinery/microwave,/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bL" = (/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/obj/machinery/cooker/grill,/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"bM" = (/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/obj/machinery/cooker/fryer,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"bN" = (/obj/structure/table/marble,/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/obj/machinery/reagentgrinder,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bO" = (/obj/structure/table/steel,/obj/item/weapon/folder/white,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bP" = (/obj/structure/bed/chair{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bQ" = (/obj/structure/table/steel,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bR" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bS" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bT" = (/obj/structure/window/reinforced/full,/obj/machinery/door/firedoor,/obj/structure/grille,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bU" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bV" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"bW" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bX" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"bY" = (/obj/machinery/light/small{dir = 4; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"bZ" = (/obj/machinery/shower{dir = 4; icon_state = "shower"; pixel_x = 0},/obj/random/trash,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"ca" = (/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"cb" = (/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"cc" = (/obj/structure/table/marble,/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cd" = (/obj/structure/table/marble,/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/obj/item/weapon/reagent_containers/food/condiment/flour,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ce" = (/obj/structure/window/reinforced/full,/obj/structure/grille,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/open) +"cf" = (/turf/simulated/floor/tiled,/area/icarus/open) +"cg" = (/obj/structure/table/steel,/obj/random/firstaid,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ch" = (/obj/item/weapon/stool,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ci" = (/obj/item/weapon/stool,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cj" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ck" = (/obj/structure/window/reinforced/full,/obj/machinery/door/firedoor,/obj/structure/grille,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cl" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cm" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"cn" = (/obj/structure/mirror{pixel_x = 30},/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"co" = (/obj/structure/mirror{pixel_x = -30},/obj/structure/sink{icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2},/obj/random/soap,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"cp" = (/obj/machinery/light/small{dir = 1},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"cq" = (/obj/item/weapon/towel,/obj/machinery/light/small{dir = 4; pixel_y = 0},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"cr" = (/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/obj/machinery/alarm{alarm_id = "petrov1"; dir = 4; pixel_x = -25; pixel_y = 0; rcon_setting = 3},/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"cs" = (/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"ct" = (/obj/structure/table/marble,/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/obj/item/weapon/material/kitchen/rollingpin,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cu" = (/obj/structure/window/reinforced/full,/obj/machinery/door/firedoor,/obj/structure/grille,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cv" = (/obj/structure/window/reinforced/full,/obj/machinery/door/firedoor,/obj/structure/grille,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cw" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cx" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/sign/greencross{pixel_x = -30},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cy" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cz" = (/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/obj/effect/decal/cleanable/dirt,/obj/effect/landmark/corpse/chef,/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"cA" = (/obj/structure/table/marble,/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/obj/item/trash/plate,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cB" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cC" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cD" = (/obj/structure/closet,/obj/random/smokes,/obj/item/clothing/under/icarus/ec_uniform,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cE" = (/obj/structure/icarus/broken_cryo{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cF" = (/obj/structure/closet,/obj/item/clothing/under/harness,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cG" = (/obj/structure/closet/medical_wall{pixel_y = 30},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cH" = (/obj/structure/icarus/broken_cryo{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cI" = (/obj/structure/closet,/obj/random/smokes,/obj/item/key,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cJ" = (/obj/structure/closet,/obj/item/clothing/under/icarus/ec_uniform,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cK" = (/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/obj/machinery/door/window/southleft,/turf/simulated/floor/tiled/white,/area/icarus/vessel) +"cL" = (/obj/structure/table/marble,/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/obj/item/trash/plate,/obj/item/weapon/material/kitchen/utensil/fork,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cM" = (/obj/machinery/vending/dinnerware,/obj/effect/floor_decal/corner/grey/diagonal{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cN" = (/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"cO" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cP" = (/obj/structure/table/standard,/obj/item/weapon/reagent_containers/pill/dexalin,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cR" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cS" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cT" = (/obj/structure/table/standard,/obj/random/accessory,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cU" = (/obj/random/trash,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cV" = (/obj/structure/bed/padded,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cW" = (/obj/structure/window/reinforced/full,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cX" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/icarus/open) +"cY" = (/obj/structure/table/standard,/obj/random/firstaid,/turf/simulated/floor/tiled,/area/icarus/open) +"cZ" = (/obj/machinery/sleeper{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"da" = (/obj/structure/closet,/obj/item/clothing/under/hazard,/turf/simulated/floor/tiled,/area/icarus/vessel) +"db" = (/obj/structure/closet,/obj/random/drinkbottle,/obj/item/clothing/under/icarus/ec_uniform,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dc" = (/obj/structure/icarus/broken_cryo{dir = 4},/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dd" = (/obj/structure/table/standard,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"de" = (/obj/structure/closet,/obj/random/contraband,/turf/simulated/floor/tiled,/area/icarus/vessel) +"df" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dg" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dh" = (/obj/structure/curtain/medical,/turf/simulated/floor/tiled,/area/icarus/vessel) +"di" = (/obj/structure/table/standard,/obj/item/weapon/reagent_containers/chem_disp_cartridge/hydrazine,/turf/simulated/floor/tiled,/area/icarus/open) +"dj" = (/obj/structure/table/standard,/obj/item/weapon/towel,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dk" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dl" = (/obj/structure/bed/chair{dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dm" = (/obj/structure/table/standard,/obj/item/trash/plate,/turf/simulated/floor/tiled,/area/icarus/open) +"dn" = (/obj/structure/table/standard,/obj/random/powercell,/turf/simulated/floor/tiled,/area/icarus/open) +"do" = (/obj/structure/closet,/obj/random/cash,/obj/random/cash,/obj/random/cash,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dp" = (/obj/structure/closet,/obj/random/glasses,/obj/item/clothing/under/blazer,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dq" = (/obj/structure/table/standard,/obj/item/weapon/material/kitchen/utensil/knife,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dr" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/wall,/area/icarus/vessel) +"ds" = (/obj/effect/landmark/corpse/doctor,/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled,/area/icarus/open) +"dt" = (/obj/structure/bed/chair{dir = 4},/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"du" = (/obj/structure/table/standard,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dv" = (/obj/structure/table/standard,/obj/item/trash/plate,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dw" = (/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dx" = (/obj/structure/closet,/obj/random/shoes,/obj/item/clothing/under/icarus/ec_uniform,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dy" = (/obj/structure/table/standard,/obj/random/clothing,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dz" = (/obj/machinery/bodyscanner{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dA" = (/obj/machinery/body_scanconsole{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dB" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dC" = (/obj/structure/table/standard,/obj/random/accessory,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"dE" = (/obj/structure/closet,/obj/random/shoes,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dF" = (/obj/structure/closet,/obj/random/action_figure,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dG" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dH" = (/obj/structure/closet,/obj/random/plushie/large,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dI" = (/obj/structure/table/standard,/obj/item/weapon/reagent_containers/food/drinks/cans/cola,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dJ" = (/obj/structure/curtain/medical,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dK" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"dL" = (/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/open) +"dM" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dN" = (/obj/structure/bed/chair{dir = 4},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dO" = (/obj/structure/table/standard,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dP" = (/obj/machinery/optable,/obj/machinery/oxygen_pump/anesthetic{pixel_y = 30},/turf/simulated/floor/tiled/white,/area/icarus/open) +"dQ" = (/obj/structure/table/standard,/obj/machinery/light{dir = 1},/obj/item/weapon/surgicaldrill,/turf/simulated/floor/tiled/white,/area/icarus/open) +"dR" = (/obj/structure/table/standard,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/icarus/open) +"dS" = (/turf/simulated/wall,/area/icarus/open) +"dT" = (/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/icarus/open) +"dU" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/open) +"dV" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/open) +"dW" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"dX" = (/obj/structure/reagent_dispensers/water_cooler,/turf/simulated/floor/tiled,/area/icarus/open) +"dY" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled,/area/icarus/open) +"dZ" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/open) +"ea" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled,/area/icarus/vessel) +"eb" = (/obj/structure/bed/chair{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ec" = (/obj/structure/table/standard,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ed" = (/obj/structure/bed/chair{dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/open) +"ee" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"ef" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/icarus/open) +"eg" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/icarus/open) +"eh" = (/obj/random/tank,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/icarus/open) +"ei" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"ej" = (/obj/random/trash,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/open) +"ek" = (/obj/structure/curtain/open/bed,/turf/simulated/floor/tiled,/area/icarus/open) +"el" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/open) +"em" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/icarus/open) +"en" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"eo" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/icarus/open) +"ep" = (/obj/structure/filingcabinet/filingcabinet,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/open) +"eq" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/icarus/open) +"er" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled,/area/icarus/open) +"es" = (/obj/structure/bed/padded,/turf/simulated/floor/tiled,/area/icarus/open) +"et" = (/turf/simulated/floor/plating,/area/icarus/open) +"eu" = (/obj/item/clothing/mask/smokable/cigarette/killthroat,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/open) +"ev" = (/obj/random/trash,/turf/simulated/floor/tiled,/area/icarus/open) +"ew" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/clothing/mask/breath/emergency,/turf/unsimulated/beach/sand,/area/icarus/open) +"ex" = (/obj/structure/table/standard,/obj/item/weapon/storage/firstaid/empty,/turf/simulated/floor/tiled,/area/icarus/open) +"ey" = (/obj/structure/filingcabinet/filingcabinet,/turf/simulated/floor/tiled,/area/icarus/open) +"ez" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/icarus/open) +"eA" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/icarus/open) +"eB" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/scalpel,/turf/unsimulated/beach/sand,/area/icarus/open) +"eC" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"eD" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/bedsheet/orange,/turf/unsimulated/beach/sand,/area/icarus/open) +"eE" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/icarus/open) +"eF" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/exoplanet/grass,/area/icarus/open) +"eG" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/clothing/mask/surgical,/turf/unsimulated/beach/sand,/area/icarus/open) +"eH" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"eI" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/trash/plate,/turf/unsimulated/beach/sand,/area/icarus/open) +"eJ" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/material/kitchen/utensil/knife,/turf/unsimulated/beach/sand,/area/icarus/open) +"eK" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/structure/bed/padded,/turf/unsimulated/beach/sand,/area/icarus/open) +"eL" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/random/snack,/turf/unsimulated/beach/sand,/area/icarus/open) +"eM" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"eN" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/trash/plate,/turf/unsimulated/beach/sand,/area/icarus/open) +"eO" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/structure/bed/chair{dir = 1},/turf/unsimulated/beach/sand,/area/icarus/open) +"eP" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/ash,/turf/unsimulated/beach/sand,/area/icarus/open) +"eQ" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/stack/rods,/turf/unsimulated/beach/sand,/area/icarus/open) +"eR" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/ore/slag,/turf/unsimulated/beach/sand,/area/icarus/open) +"eS" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"eT" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/ash,/turf/unsimulated/beach/sand,/area/icarus/open) +"eU" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/ore/slag,/turf/unsimulated/beach/sand,/area/icarus/open) +"eV" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/stack/rods,/turf/unsimulated/beach/sand,/area/icarus/open) +"eW" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/random/snack,/turf/unsimulated/beach/sand,/area/icarus/open) +"eX" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/random/trash,/turf/unsimulated/beach/sand,/area/icarus/open) +"eY" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/ash,/turf/unsimulated/beach/sand,/area/icarus/open) +"eZ" = (/obj/effect/decal/cleanable/dirt,/obj/item/stack/rods,/turf/unsimulated/beach/sand,/area/icarus/open) +"fa" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/storage/pill_bottle/antidexafen,/turf/unsimulated/beach/sand,/area/icarus/open) +"fb" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/random/trash,/turf/unsimulated/beach/sand,/area/icarus/open) +"fc" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/storage/bag/trash,/turf/unsimulated/beach/sand,/area/icarus/open) +"fd" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/random/trash,/turf/unsimulated/beach/sand,/area/icarus/open) +"fe" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"ff" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"fg" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/stack/rods,/turf/unsimulated/beach/sand,/area/icarus/open) +"fh" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle,/turf/unsimulated/beach/sand,/area/icarus/open) +"fi" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/stack/rods,/turf/unsimulated/beach/sand,/area/icarus/open) +"fj" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/stack/rods,/turf/unsimulated/beach/sand,/area/icarus/open) +"fk" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/ash,/turf/unsimulated/beach/sand,/area/icarus/open) +"fl" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"fm" = (/obj/effect/decal/cleanable/dirt,/obj/random/trash,/turf/unsimulated/beach/sand,/area/icarus/open) +"fn" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/ash,/obj/random/trash,/turf/unsimulated/beach/sand,/area/icarus/open) +"fo" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/random/material,/turf/unsimulated/beach/sand,/area/icarus/open) +"fp" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/stack/rods,/turf/unsimulated/beach/sand,/area/icarus/open) +"fq" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/ash,/turf/unsimulated/beach/sand,/area/icarus/open) +"fr" = (/obj/effect/decal/cleanable/dirt,/obj/random/material,/turf/unsimulated/beach/sand,/area/icarus/open) +"fs" = (/obj/effect/decal/cleanable/dirt,/obj/item/weapon/ore/slag,/turf/unsimulated/beach/sand,/area/icarus/open) +"ft" = (/obj/effect/icarus/irradiate,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"fv" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/icarus/open) +"fw" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/icarus/open) +"fx" = (/obj/structure/table/steel,/obj/random/toolbox,/turf/simulated/floor/tiled,/area/icarus/open) +"fy" = (/obj/structure/table/steel,/turf/simulated/floor/tiled,/area/icarus/open) +"fz" = (/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/vessel) +"fA" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/vessel) +"fB" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/icarus/vessel) +"fC" = (/obj/structure/table/steel,/obj/item/weapon/tank/air,/turf/simulated/floor/tiled,/area/icarus/vessel) +"fD" = (/obj/machinery/suit_storage_unit,/turf/simulated/floor/tiled,/area/icarus/vessel) +"fE" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/vessel) +"fF" = (/obj/random/material,/turf/simulated/floor/plating,/area/icarus/vessel) +"fG" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/vessel) +"fH" = (/obj/effect/decal/cleanable/dirt,/obj/random/trash,/turf/unsimulated/beach/sand,/area/icarus/vessel) +"fI" = (/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/plating,/area/icarus/vessel) +"fJ" = (/obj/structure/closet/crate/trashcart,/turf/simulated/floor/plating,/area/icarus/vessel) +"fK" = (/obj/structure/closet/crate/trashcart,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/icarus/vessel) +"fL" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/icarus/vessel) +"fM" = (/obj/structure/table/steel,/obj/random/material,/turf/simulated/floor/plating,/area/icarus/vessel) +"fN" = (/obj/structure/table/steel,/obj/item/weapon/marshalling_wand,/turf/simulated/floor/plating,/area/icarus/vessel) +"fO" = (/obj/structure/table/steel,/turf/simulated/floor/plating,/area/icarus/vessel) +"fP" = (/obj/structure/table/steel,/obj/random/toolbox,/turf/simulated/floor/plating,/area/icarus/vessel) +"fQ" = (/obj/structure/table/steel,/obj/random/technology_scanner,/turf/simulated/floor/plating,/area/icarus/vessel) +"fR" = (/obj/structure/table/steel,/obj/item/weapon/marshalling_wand,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/icarus/vessel) +"fS" = (/obj/vehicle/train/cargo/engine,/turf/simulated/floor/plating,/area/icarus/vessel) +"fT" = (/obj/structure/reagent_dispensers/watertank,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/icarus/vessel) +"fU" = (/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 8},/turf/simulated/floor/plating,/area/icarus/vessel) +"fV" = (/obj/machinery/door/blast/regular{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/icarus/open) +"fW" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/icarus/vessel) +"fX" = (/obj/effect/floor_decal/industrial/warning{dir = 9},/turf/simulated/floor/plating,/area/icarus/vessel) +"fY" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/structure/closet/crate/plastic,/turf/simulated/floor/plating,/area/icarus/vessel) +"fZ" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/plating,/area/icarus/vessel) +"ga" = (/obj/effect/floor_decal/industrial/warning{dir = 5},/turf/simulated/floor/plating,/area/icarus/vessel) +"gb" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/plating,/area/icarus/vessel) +"gc" = (/obj/structure/closet/crate/freezer/rations,/turf/simulated/floor/plating,/area/icarus/vessel) +"gd" = (/obj/random/plushie/large,/turf/simulated/floor/plating,/area/icarus/vessel) +"ge" = (/obj/structure/closet/crate/solar_assembly,/turf/simulated/floor/plating,/area/icarus/vessel) +"gf" = (/obj/random/junk,/turf/simulated/floor/plating,/area/icarus/vessel) +"gg" = (/obj/structure/closet/crate/plastic,/turf/simulated/floor/plating,/area/icarus/vessel) +"gh" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"gi" = (/obj/random/tank,/turf/simulated/floor/plating,/area/icarus/vessel) +"gj" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/random/trash,/turf/unsimulated/beach/sand,/area/icarus/vessel) +"gk" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/structure/closet/crate/plastic,/turf/simulated/floor/plating,/area/icarus/vessel) +"gl" = (/obj/random/firstaid,/turf/simulated/floor/plating,/area/icarus/vessel) +"gm" = (/obj/structure/closet/crate/large,/turf/simulated/floor/plating,/area/icarus/vessel) +"gn" = (/obj/structure/ore_box,/turf/simulated/floor/plating,/area/icarus/vessel) +"go" = (/obj/structure/target_stake,/turf/simulated/floor/plating,/area/icarus/vessel) +"gp" = (/obj/vehicle/train/cargo/trolley,/turf/simulated/floor/plating,/area/icarus/vessel) +"gq" = (/obj/random/toolbox,/turf/simulated/floor/plating,/area/icarus/vessel) +"gr" = (/obj/structure/closet/crate/medical,/turf/simulated/floor/plating,/area/icarus/vessel) +"gs" = (/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 8},/turf/simulated/floor/plating,/area/icarus/open) +"gt" = (/obj/structure/closet/crate/hydroponics,/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"gu" = (/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "prototype_chamber_blast"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/icarus/open) +"gv" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/plating,/area/icarus/open) +"gw" = (/obj/structure/closet/crate/large,/turf/simulated/floor/plating,/area/icarus/open) +"gx" = (/obj/structure/plushie/carp,/turf/simulated/floor/plating,/area/icarus/open) +"gy" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/icarus/vessel) +"gz" = (/obj/structure/closet/crate/radiation_gear,/turf/simulated/floor/plating,/area/icarus/vessel) +"gA" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor/plating,/area/icarus/open) +"gB" = (/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/plating,/area/icarus/open) +"gC" = (/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/icarus/open) +"gD" = (/obj/effect/floor_decal/industrial/warning,/obj/structure/closet/crate/plastic,/turf/simulated/floor/plating,/area/icarus/open) +"gE" = (/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/plating,/area/icarus/vessel) +"gF" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor/plating,/area/icarus/vessel) +"gG" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/icarus/vessel) +"gH" = (/obj/effect/floor_decal/industrial/warning,/obj/structure/closet/crate/plastic,/turf/simulated/floor/plating,/area/icarus/vessel) +"gI" = (/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/icarus/vessel) +"gJ" = (/obj/effect/floor_decal/industrial/warning{dir = 6},/obj/random/toolbox,/turf/simulated/floor/plating,/area/icarus/vessel) +"gK" = (/obj/machinery/light/small,/turf/simulated/floor/plating,/area/icarus/open) +"gL" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"gM" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"gN" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/plating,/area/icarus/vessel) +"gO" = (/obj/machinery/light/small,/turf/simulated/floor/plating,/area/icarus/vessel) +"gP" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/icarus/vessel) +"gQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/icarus/open) +"gR" = (/obj/machinery/atmospherics/portables_connector,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/icarus/open) +"gS" = (/obj/machinery/atmospherics/pipe/tank/oxygen,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/icarus/open) +"gT" = (/obj/machinery/atmospherics/pipe/tank/oxygen,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"gU" = (/obj/machinery/atmospherics/portables_connector,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"gV" = (/obj/machinery/atmospherics/pipe/tank/nitrogen,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"gW" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"gX" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/plating,/area/icarus/vessel) +"gY" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/structure/sign/warning/nosmoking_2{pixel_y = 30},/turf/simulated/floor/plating,/area/icarus/vessel) +"gZ" = (/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/plating,/area/icarus/vessel) +"ha" = (/obj/machinery/portable_atmospherics/canister/hydrogen,/turf/simulated/floor/plating,/area/icarus/vessel) +"hb" = (/obj/machinery/atmospherics/pipe/tank/oxygen,/turf/simulated/floor/plating,/area/icarus/vessel) +"hc" = (/obj/machinery/atmospherics/pipe/tank/hydrogen,/turf/simulated/floor/plating,/area/icarus/vessel) +"hd" = (/obj/machinery/atmospherics/pipe/simple/visible/green{dir = 5},/turf/simulated/floor/plating,/area/icarus/open) +"he" = (/obj/machinery/atmospherics/pipe/manifold/visible/green,/turf/simulated/floor/plating,/area/icarus/open) +"hf" = (/obj/machinery/atmospherics/pipe/manifold/visible/green{icon_state = "map"; dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"hg" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{icon_state = "intact"; dir = 5},/turf/simulated/floor/plating,/area/icarus/vessel) +"hh" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow,/turf/simulated/floor/plating,/area/icarus/vessel) +"hi" = (/obj/machinery/atmospherics/pipe/manifold/visible/yellow,/turf/simulated/floor/plating,/area/icarus/vessel) +"hj" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{dir = 9},/turf/simulated/floor/plating,/area/icarus/vessel) +"hk" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/turf/simulated/floor/plating,/area/icarus/vessel) +"hl" = (/obj/effect/landmark/corpse/engineer,/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/plating,/area/icarus/vessel) +"hm" = (/obj/machinery/atmospherics/pipe/simple/visible/blue,/turf/simulated/floor/plating,/area/icarus/vessel) +"hn" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{icon_state = "intact"; dir = 5},/turf/simulated/floor/plating,/area/icarus/vessel) +"ho" = (/obj/structure/window/phoronreinforced{dir = 4},/obj/machinery/door/blast/regular{dir = 4; id = "d1starboardnacelle"},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/structure/grille,/obj/machinery/atmospherics/pipe/simple/visible/cyan{dir = 4; icon_state = "intact"},/turf/simulated/floor/reinforced,/area/icarus/vessel) +"hp" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 8; frequency = 1441; icon_state = "map_injector"; id = "h2_in"; pixel_y = 1; use_power = 1},/obj/machinery/sparker{pixel_y = 25},/turf/simulated/floor/reinforced,/area/icarus/vessel) +"hq" = (/turf/simulated/floor/reinforced,/area/icarus/vessel) +"hr" = (/obj/machinery/atmospherics/pipe/simple/visible/green{dir = 5},/turf/simulated/floor/plating,/area/icarus/vessel) +"hs" = (/obj/machinery/atmospherics/pipe/simple/visible/green{icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"ht" = (/obj/machinery/atmospherics/trinary/mixer/m_mixer{dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"hu" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"hv" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"hw" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/turf/simulated/floor/plating,/area/icarus/vessel) +"hx" = (/obj/machinery/portable_atmospherics/powered/scrubber,/turf/simulated/floor/plating,/area/icarus/vessel) +"hy" = (/obj/machinery/portable_atmospherics/canister/carbon_dioxide,/turf/simulated/floor/plating,/area/icarus/vessel) +"hz" = (/obj/machinery/atmospherics/pipe/simple/visible/blue{icon_state = "intact"; dir = 5},/turf/simulated/floor/plating,/area/icarus/vessel) +"hA" = (/obj/machinery/atmospherics/pipe/simple/visible/blue{dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"hB" = (/obj/structure/window/phoronreinforced{dir = 4},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/structure/grille,/obj/machinery/door/blast/regular{dir = 4; id = "d1starboardnacelle"},/obj/machinery/atmospherics/pipe/simple/visible/blue{dir = 4},/turf/simulated/floor/reinforced,/area/icarus/vessel) +"hC" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 8; frequency = 1441; icon_state = "map_injector"; id = "h2_in"; pixel_y = 1; use_power = 1},/turf/simulated/floor/reinforced,/area/icarus/vessel) +"hD" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 4},/turf/simulated/floor/plating,/area/icarus/open) +"hE" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"hF" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel{dir = 1},/turf/simulated/floor/plating,/area/icarus/vessel) +"hG" = (/obj/structure/window/phoronreinforced{dir = 4},/obj/structure/window/phoronreinforced,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/structure/grille,/obj/machinery/door/blast/regular{dir = 4; id = "d1starboardnacelle"},/turf/simulated/floor/reinforced,/area/icarus/vessel) +"hH" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1331; id_tag = "vox_west_vent"},/turf/simulated/floor/reinforced,/area/icarus/vessel) +"hI" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/icarus/open) +"hJ" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/icarus/vessel) +"hK" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/plating,/area/icarus/vessel) +"hL" = (/obj/structure/sign/warning/caution{pixel_x = 0; pixel_y = -30},/turf/simulated/floor/plating,/area/icarus/vessel) +"hM" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel,/turf/simulated/floor/plating,/area/icarus/vessel) +"hN" = (/obj/machinery/portable_atmospherics/powered/pump,/turf/simulated/floor/plating,/area/icarus/vessel) +"hO" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/visible/fuel,/turf/simulated/floor/plating,/area/icarus/vessel) +"hP" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 4},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/icarus/open) +"hQ" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 4},/obj/machinery/door/airlock,/turf/simulated/floor/plating,/area/icarus/vessel) +"hR" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 4},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/icarus/vessel) +"hS" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/fuel,/turf/simulated/floor/plating,/area/icarus/vessel) +"hT" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 4},/obj/machinery/light/small{dir = 1},/obj/structure/sign/warning/nosmoking_2{pixel_y = 30},/turf/simulated/floor/plating,/area/icarus/vessel) +"hU" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 4},/obj/structure/sign/warning/nosmoking_2{pixel_y = 30},/turf/simulated/floor/plating,/area/icarus/vessel) +"hV" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 10},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/icarus/vessel) +"hW" = (/obj/effect/decal/cleanable/ash,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"hX" = (/obj/structure/grille,/turf/simulated/floor/plating,/area/icarus/open) +"hY" = (/obj/effect/decal/cleanable/ash,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"hZ" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 6},/turf/simulated/floor/plating,/area/icarus/vessel) +"ia" = (/obj/machinery/atmospherics/pipe/simple/visible/fuel{dir = 10},/turf/simulated/floor/plating,/area/icarus/vessel) +"ib" = (/obj/effect/decal/cleanable/ash,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"ic" = (/obj/effect/decal/cleanable/ash,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"id" = (/obj/machinery/atmospherics/unary/engine,/turf/simulated/wall/r_wall,/area/icarus/open) +"ie" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/ore/slag,/turf/unsimulated/beach/sand,/area/icarus/open) +"if" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/ore/slag,/turf/unsimulated/beach/sand,/area/icarus/open) +"ig" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/random/trash,/turf/unsimulated/beach/sand,/area/icarus/open) +"ih" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/vehicle/train/cargo/trolley,/turf/unsimulated/beach/sand,/area/icarus/open) +"ii" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/ore/slag,/turf/unsimulated/beach/sand,/area/icarus/open) +"ij" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/engine{anchored = 0},/turf/unsimulated/beach/sand,/area/icarus/open) +"ik" = (/obj/effect/decal/cleanable/ash,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"il" = (/obj/effect/decal/cleanable/ash,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/unsimulated/beach/sand,/area/icarus/open) +"im" = (/obj/effect/decal/cleanable/ash,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/ore/slag,/turf/unsimulated/beach/sand,/area/icarus/open) +"io" = (/obj/effect/decal/cleanable/ash,/turf/simulated/floor/exoplanet/grass,/area/icarus/open) +"ip" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/exoplanet/grass,/area/icarus/open) +"iq" = (/obj/effect/landmark/random_gen/asteroid,/turf/unsimulated/mineral,/area/space) +"jb" = (/obj/effect/shuttle_landmark/nav_icarus/nav1{autoset = 1},/turf/simulated/floor/exoplanet/grass,/area/icarus/open) +"kb" = (/obj/effect/shuttle_landmark/nav_icarus/nav2{autoset = 1},/turf/simulated/floor/exoplanet/grass,/area/icarus/open) +"lb" = (/obj/effect/shuttle_landmark/nav_icarus/nav3{autoset = 1},/turf/simulated/floor/exoplanet/grass,/area/icarus/open) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababacacababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacababababababababababababababababaa +aaabababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacababababababababababababababababaa +aaababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacabababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababacacacacacababacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababacacacacacacacacacacacacacacjbacacacacacacacacacacacabababababababababababababababababababacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababacacababacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacababababababacababababababacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacabababacacacacacababababacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacacacacabababacacacacacacabababacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeafafafaeafafafaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeafafagafafafahafafaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababacacacabababababacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababacacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeafafaiahahafafaiahafafaeaeaeaeaeaeaeaeaeaeaeacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababacacacabababababababacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeafahahajajahahajakahafaeaeaeaeaeaeaeaeaeaeacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababacacacacacacacalacacacaeaeaeaeaeaeaeaeaeaeafaiajajajamanaoajapajagaqacacacaeaeaeaeaeacacacacacacacacacacacacacacacacacacacacacacacaracacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacabababababababababacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababacacacacacacalalacacacacacacaeaeaeaeaeaeaeasatakajapauavavajajajawaqaxacacacaeaeaeacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacabababababababababababacacacacacacacacacacacacacacacacacababacacabababababababababababababababababababacacacacacalacacacacacacacacacaeaeaeasasasatajajayavavazajajajaAasaqaqacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababacabababababababababacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababacacacacalacalacacacacacacacacacacaeasavajajayajajaBaBaBajajajajajavaqacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababacaracacacacalacacacacacacacacacaxacaqaDajajajajayajajajajajajapajaEaqacacacacacacacacacacacacacacacacacacalacacacacacacacacacacalacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababacacacacacabacacacacacacacacacacacacacacacacacacacacababababacacacacababababababacacacacacalacacacacacacacacacacacaxaqaFajajaGaHaHaIaJaKaHaHaGajajaLaqacaxacacacacacacacacacacacaracacacacacacacacacaracacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacabababacacacacacacacabababacacacacacalacacacacacacacacacacaqaqasasasasasasasasaMasasasasasasasasaqaqacacacacacacacacacacacacacacacacalacacacacacacacacacacacacacacalacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacalacalacacacacacacacaqaqaqasaNaOaPaPaPaQaPaPaRaSaPaPaPaQaTaPaPaUaNasaqaqaqacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacalacacacacacacacalacacacacacacacacacacaqaVaWaXaNaPaPaTaYaYaZaYaYbaaYbbaYaYaPaPaPaPaNaXbcbdaqacacacacacacacacacacacacacacacacacalacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacalalacacacacacacacacacalacacacacacalacacacacacalacacacacacacacacacacacaqasahbeaXbfaPaPaPaPaPaPaPaYbaaYbbaYaYaPaPaYaPbgaXbhbdasaqacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacalacalalalacacalalacacalacacacacacacacacacacalacacacacacacacaqasbibjahbkaPaPblbmbmaTaPaPbnbobpaPaPaTaPaPbqaPaPaXbrbsbtasaqacacacacacacacacacacacacacacacalacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacalacalacacacacalalacacacacacacacacacacaqasaXaXaXaXaXbubvaXaXaXaXaXaXaXaSaXaXaXaXaXaXaXbvbvaXbwaXaXaXasaqacacacacacacalacacacacacacacacalacacacacacaracacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacalacacacacacacacacacacacacaqasbxbybzbAaPbBaPaPaXbCbDaXbEbFaXaSaXbGbGaXbHbIaXaPaPaXbJbKbLbMbNasaqacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacaracacacacacacacacacacalacacacacacacacacacacaqasbObPbQbRbSbRbTbUaPaXaXbVaXbWaXaXaSaXbXbYaXbZbIaXaPaYaXbJcacbcbcccdasaqacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacalacacacacacacacacacacacacacacacacacacacacalacacacacacacacacacaccecfaPaPcgchcicjckclaPbVcmcnaXcocpbVaSbVbXbXbWbXcqaXaPaYaXcrcscacsbJctccasaqacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacalacacacacacacacacacacacacacacacacacaracacalacacacaracacacacacacaqbBcucuaXcucvcwaXcxaPasasasasasasascyasasasasasasasaPaYbWbJbJczbJbJbJbJcAaqacacacacacacacacacacacacacacacacacacacalalacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacaracacacacacacacacalacacacacacacacacalacacacacacacacacacaqaPaPaPaPaPcBcCaXaSaPascDcEaPcFcEcGaSaPcHcIaPcHcJasaPaYaXcKcccLcccccccccMaqcNacacacacaracacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacalacacacacacacacacacacacacacacacacacacacacalacacacacacacacacacaqaXaXaYcOcPcQcRaXcSaPasbfaPaPaPaPaPcTcUaPaPaPaPbgasaPbgaXbfaYaYaPaPaPaPbgaqcNacacacacacacacacacacacacacacacalalacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacalacacacacacacacacacacalacacacacacacacalacacacacacacacacacacaqcVcWaYcXcYaPcZaXaSaPasdacEaPdbdcbbddaYcHcJaPcHdeasaPdfaXaPaYaPaPaYaYaPaPaqcNacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacalalacacacacacacacacacacacacacacacacacacacacacacacacacacacacaqdgdhaPcYdiaPaPaXaSaYasaPaPaPaPbbbbdjaYaPaPaYaPdfasaPaPcuaPbPcOcOdkaPdldmcecNacacacacacalacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacalalacacacacacalacacacacalalalacacacacacacacacacacaccNaqcVcWaPcXdnaPcZaXaSaYasdocEaYdpdcbbdjaYcHcJaYcHcDasaYaPcuaPbPdqcOdkaPdlcXcecNacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacalalacacacalacalalacacacacalacacacacacacacacacaccNaqaXdraPcfdsaYaPaXaSaYasaPaPaYaPbbbbddaYaPaPaYaPaPasbbaPcuaPdtdudvdkaYaYcXcecNcNacacacacacacacacacacacaracacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacalalacacacacacacacaccNaqcVcWaPcfdwaYaPaXaSaYasdxcEaYdxcEaPdyaPcHbmaYcHcJasbbaPaXaPbbaYaPaPaYaYaPaqcNcNacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacalalacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccNaqdgdhaPdzdAaPdBaXcSaPasbfaPaPaPaPaPdCaYaPaPaPaPbgasbbdBaXbfaYaYaYaYaYaYbgaqcNcNacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacalacalalalacacacacacacacacacacacacacacacacacacacalacacacacacacacacacaccNaqcVcWaPaPaPaPaPaXdDcfasdEcEaPdFcEdGbobpcHcJaPcHdHascfcfaXaPdlcOdIdkaYdlcXcecNcNacacacacacacacacacacacacacacacacacaracacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacalacacalacacacacacacacacacacacacacaracacacacacacacalalacacacacacacacaccNcNaqaXaXaXaXaXaXdJaXdKdLasasasasasasascyasasasasasasasdLdLaXdMdNdOcOdkaYdldmcecNcNacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacalacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccNcNaqdPdQdRdSdTcfcfdSdDdUdVdUdUdUdUdUdTdWdUdXcfcfcfcfdVcfdYdZeaebeccOdkaYedcXcecNcNacacacacacacacacacacalalacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacalacacacacacacacalalacacacalacacacacacacacacacacacacacalalacacacacacacaccNcNeeefegehdVcfdUdUdSdDdUdSdUeedUdUdUeeeidUcfejdUdSekdScfdDdScfeldUcfcfdUdUcfemeecNcNacacalacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacalalacacacacacacacalacacalalacacacacacacacacalalalalacalacalacacacacacaccNcNeeenegeodScXdUepdSdDcfdSdUeqemcNemegeicfcferdUdSesdScfdDetdUeldUeuevcfemegeneecNcNacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacalalalalacacacacacacacacacacacalacalacacalacacacacaccNcNeeenewenefexcfeydSeeememeeeiegeeeienefegegegegezegdScfeAegegemeAemefefegegeneecNcNacacacacacacacacacacacacacacacacacacacalacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacalacacacacacalacacacacaccNcNeBeCenenefegeeezdSeieieieieieieeeienefeneneneneneDdSeneieEefeieeegeieiegeieieeeFeFeFeFacacacacacacacaracacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacaracacacacacacacacacacacacacacacaccNcNeeeCeGeHefegeeeiemeieieieieieieeeieneneneneneneneCeHeneieCefeIeeeieieJeieieieecNeFeFeFacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacalacacacacacacacacacacalacacacacacacacacacacacacacacacacacacacacacaccNcNeeeneneHefeeeieCeieneneneKeieneieCeHeCeCeCeneneneCeHeneieCeneLeeeieieieieieieecNeFeFeFacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacalalalalacacacacacacacacacacalalacacacacacacacacacacacalacacacacacacacacaccNcNeeeieieieieieieCeieneneneieieneieCeMeHeHeMeHeMeHeHeHeneieNeneLeOeieieieIeieieecNeFalalacacacacacacacacacacacacacacacaracacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacalacacacacaracacacalalacacalacacacacacacacalacalalacacacacacacacacaccNcNeeeieieeeeeiePeneieienenenePeQeReHeSeTeHeMeUeMeVeHeHeneieCeWeieeeieieieieieieecNeFeFalacacacacacacacacalalacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccNcNcNcNcNcNeeeeeeeieXeneieieneneCeneHeCeMeSeMeMeSeHeMeHeHeHeneieCeneieeePeieieieieieYeFeFeFeFacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacalacacacacacalacalacalacacacacacacacacacacaccNcNcNcNcNcNeZcNeeeYfaeieieeePeieCeieCeCeMfbeMeMeSeHeTeHeHeHeneneCeCeCeienfcenenfdeieecNeFeFeFacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababacacacacacacacacalacacacacacacacacacacacacacacalacacacacacacacacacacacacacacacalacacacacaccNcNcNcNcNcNcNcNeeeeeeeieieeeieieCeieHeMfeffeSeMeSeHeHeCeCeCeieneCeCeCeieneneneneneecNcNeFeFeFacacacacacacalacacacacacalalacacalacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacalacacacacacacacacacacalalalalacacalacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNeeeieeeieieCeieHeTfefffgeHeMeCeCeneneneienenenenfhenenenenfifjcNcNeFeFeFacacacacacacalacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababacacacacalalacacacacacacalalacacacacacacacacacacacacacalacacacacacacacacacalacacacaccNcNcNcNcNcNcNcNcNcNcNcNeeeeeneCeMeCeSfefkfleSeneneieneneCeCeneCeneneneieneneneneneecNcNeFeFeFacacacacacacacalacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababacacacacacalalacacacacacacacacacacacacacacacacacacacacacacalacacacacaracacacacacacacacaccNcNcNcNcNcNcNcNcNfmcNcNcNcNeieneCfneCfoeSfeeMeCeCeieieieReieieneieneneeeieieieneneecNcNeFeFeFacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababacacacacacacalacacacacacacacacacacacacacacacacacacacacacacacalacacacacacacacacacalacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNeieneCeneCeHeMeSeMeHeHeneieieneieieneieneneYeieieieieicNcNcNeFeFeFacacacacacacacacalacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacalacacacacacacaracacacacacacacacacacacacacacacalacacacaccNcNcNcNcNcNcNcNcNcNcNcNeZcNeeeieneneCeHeMeSeMeHeHeneeeeeneieieieeeieieefpeieieieicNcNeFeFeFeFacacacacalacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacalacacacacacacacacacacalalacacacacacalacacacaccNcNcNcNcNeZcNcNcNcNcNcNcNcNeeeieieieneneCeHeCeneneieeeeeneieieieeePeieeeeeeeeeeeecNcNeFeFeFeFacacacacacacacacaracacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababacacacacacacacacacaracacacacacacacacacalacacacacacacacacacacacacalacacalacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNeeeeeieieieneCfqeneneieieieieeeeeecNeeeeeeeeeeeeeeeecNcNeFeFeFeFacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacalalacacalacacacacacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeeeieieReneneieieeeeeeeeeeeeeecNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacalacacacacalacacacalalacacacacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeeeeeeeieieieieieeeeeecNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababacacacacacacalacacacacacacacacacacalacacacacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeeeecNcNcNeeeeeeeeeeeecNcNcNcNcNfmcNcNcNcNcNcNcNcNcNcNcNeFeFacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacalalacacacacacacacacacacacacacacaracacacacacacacacacacacacacacacacaccNcNcNcNfrcNcNcNcNcNcNcNcNcNcNcNeeeecNcNcNeeeeeeeeeeeecNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFacacacacacacacacacacacacacacacaracacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacalacacacalacacacacacacacacacacacacacacacacacacacalacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeeeecNcNcNcNcNcNcNcNcNfscNcNcNcNcNcNcNeFeFacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacalacacacacacacacaracacacacacacacacacacacacacalacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeeeecNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacalacacacacacacacacacacacacalacacacacacacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNfmcNcNfscNcNcNcNcNcNcNcNcNcNcNeeeecNcNcNfrcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababacacacacacacacalacacacacacacacacacacacacacalacacacacacacacacacacacalacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacacacacaracacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacalalacacacacacacacacacacacalacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacacacacacacacacacacacacacacacacalacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacaracacacacacacacacacacacacacacacacacacacalacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFeFacacacacacacacalacacacalalacacalacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacalalacacacacacacacacacalacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFeFacacacacacacalalacacacacacacacalacalacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaracacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFeFacacacacacacalacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacalalacacacacacacacacacalalalalacacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFeFacacacacacacacacacacacacacacacacacalacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababacacacacacacalacacacalacacacalalacacalacalacacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNfscNcNcNcNcNcNcNcNcNcNcNfscNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacacacalacacacacacacaracacacalacalacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacalacacacalalalacacalalalacalacacacacacacacacalacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNftcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacacacacacacacacacacacacacacalacalacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababacacacacacacacacacalacalacalacacacalalacalalalacacacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNfscNcNcNcNcNcNcNcNeFeFacacacacacacacacacacacacacacacalacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacalalacacacacalacacacacacacacacacacaracacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFacacacacacacacacacacacacacacacalacacalacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacalacacacacalacacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFacacacacacacacaracacacacacacacalacalalacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacalacacacacacacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNfscNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFacacacacacacacacacalalacacacacalalalacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacalalacalacacacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNfscNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFacacacacacacacacacacacalacalalalalalacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacaracacacacacacacacalacacacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFacacacacacacacacacacacacacacacalacacacacabababababababababababababababababababababababacacababababababababababababababababababababababababaa +aaabababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacababababababacacacacacacalacacacacacacacacacaracacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFacacacacacacacacacacacacacacacalacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacababacacacacacacacacacacalalalacacacacacacacacacacacacacalacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFacacacacacacacacacacacacacacacalacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababacacacacacacacalacacacacacacacacacacacacacacacacalalacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFacacacacacacacalacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacalacacacacalalacacacacacacacacacalalacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNfrcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacacalacacacacalaracacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacalacalacacacalacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNfmcNcNcNcNcNcNeFeFeFacacacalacacacacalacacacacacacaracacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacalalacacacacalacacacacacacacacalalacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacalacacacacacacalacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacalalacacalalacacalacacacacacacacalacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacacaracacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacalacacacacacalacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababacacacacacacacacacacacacacalacacacacacacacalacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNfscNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacacacacacacacacacalalacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacaracacacacacacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacacacacacacacacacacacalacacacacacacacacabababababababababababababababababababababababacababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacackbacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacalacacalacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFeFacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacalalalalacacacacacacacalacacacacacacacacaccNcNcNcNcNcNcNcNcNcNfmcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFeFacacacacacacacacacacacacacacalacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacalalacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFeFacacacacacacaracacacacacacacacalacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababacacacacacacalalacacacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNfscNcNcNcNcNcNcNcNcNeFeFeFeFacacacacacacacacacacacacacacacalalacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababacacacacacacalalalalacacacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababacacacacacalacacacalalacacacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNfscNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacacacacalalacacacacacacacacalalacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacalacacacacacacalacacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNfrcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacacacacacalacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababacacacalacacacacacacacacacacacaracacacacacacacaceFcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacacacalacacacacacaracacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacacacacacaracacacacacacacacacacacacacacacaceFcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNfrcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacacacalacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacaceFcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababacacacacacacacacacacalacacacacacacacacacacacaccNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNfscNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNeFeFeFeFacaracacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacacacacacacacacacacacacacacabacacacacacacacacacacabababababababababababacacacacacacacacacacacalacacacacacacacacacacacaccNcNaqeAcNcNcNcNcNfscNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNacacacacacacacacacalalacacacacalacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacacacacacabacacacacacacacacacacababababababababababacacacacacalacacacacacacalalacacacacacacacacacacaceecNaqcffvcNcNcNcNcNcNcNcNcNeteteteAetcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNcNacacacacacacacacacalacacacacacalacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacacacacacabababababababababababababababababababababababacacacalacacacacacacacacacacacacacacacacacacaccNcNaqcffvfvcNcNdScNcNeteAcNcNeteAetetcNcNcNcNcNcNeAetetcNcNcNcNcNcNcNcNcNcNcNcNcNcNacacacacacacacacacacacacacacacacalacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacaccNcNaqcffvfwfvetdSeAcNetetetetetetetetetetetetcNcNeteteteteAetetcNcNcNcNcNcNcNcNcNcNacacacacacacacacacacacalacacacacalacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacaccNaqfxcfetetcfdSeteteteAeteteteteteteteteAetetetetetetetetetetetetetetcNcNcNcNcNacacacacacacacacacacacacacalacacacacacalacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacabababababababababababababababababababababababacacacacacacacalalacacacaracacacacalacacacacacacacacacaccNaqetcfcfetcfdScfcfetetcfeteteAcNeieteteteteteteteteteteteteteteteteAcNcNcNcNcNacacacacacacacacacacacacacacalacacacacalacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacabababababababababababababababababababababababacacacacacacacacalacacacacacacacacalacacacacacacacacacaccNaqfycfcfcfcfdScfcfcfcfcfahahfzfAahahahahahahahahfBahahahahahahahetetetetcNcNcNacacacacacacacacacacacacacacacalacacacalacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacalacacacacacacacacacalacacacacacacaccNcNcNaqfCaPaPfDfDaXaNaPaPaPaPahfzfzfAfEahahahahahahahahahahahfFahahahahahahahfBaqcNacacacacacacalacacacaracacacacalalacalacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacaccNeeeeaqasasasasasasasasasasasasfGfHfAfEasasasasasasasasasasasasasasasasasasasasaqcNacacacacacacalacacacacacacacacacalacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacaccNeeeeaqahahahahfIahahfJfKahaVaVfzfzfGfAfEfLfMfNfOfPfQfOfPfRahahfSahahahfTahahahaqcNcNacacacacacalacacacacacacacacacacacacacacacacacacacalacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacaracacacacalacacacacacacacacacacacacacacacacacaccNeieiaqahahahahahahahahahahahahfBfGfzfAfEfBahahahahahahahahahahahahahahahahahfUfVcNcNacacacacacalalacacacacacacacacacalacacacacacaracacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacalacacacacacacacacacacacacacacalacacacacacaccNeeeeaqfWahfXfYfZfZfZfZfZfZfZfZfzfzfzfGfAfZfZfZfZfZfZfZfZfZgaahahahahahahahahfUfVcNcNacacacacacacacacacacacacalacacacalacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacaracacacacalacalacacacacacacaccNcNaqahahgbahahfFahgcahgdgeahfzfzfAfEfEfAfEahgfgcahggahahghahahahgiahahahahfUfVcNcNacacacacacacacacacacacacacacacacalacacacacacacacacacalacacacababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacalacacacacalalacacacacacacacalacacacacacacacacacaccNaqahahgbgggcgfahahahgcahahfzfzfAgjfAfAfzfAfAahahgfahgggkahahahahahahglahfUfVcNcNacacacacacacacacacacacacacacacacacacalacalacacacacacalacacacababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacalalacacacacacacacacacacacacacacalacacacacacacacacaccNcNaqahahgbahahahgmahahahgngofGfzfzfAfEfAfEfzfAahahggggggghgpahgiahahahahahfUfVcNacacacacacacacacacacacacacacalacacacacacalacalalacacacalacacacacacacabababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacalacacacacacacacacacalalacacacacacacacacacacacacacacacaccNeeaqahahgbfIahgqahgrahgngoahfzfzfzfAfEfAfEahahahahggahahghahahahahgiahahetgsfVcNcNacacacacacacacacaracacacacalalacacacacalalalalacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacalalacacacacacacacacacacacalacacacacacacacacacacacacacaccNeeeiaqfWahgbahgcahahahahahahgtahfGfzfAfEfGfAglahggahggahggghahahahahahahgietgsgucNcNacacacacacacacacacacacacacacalalacalalacacacacalalacacacacacacacacabababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacalalacacacacaracacacacacacacalalalacacacacacacacacacaccNeeeiaqetetgvetetgwetetgxgwetgtfBfzfzfGfAgygggfgfahgzahahahghahahahahahahahetgsgueecNacacacacacacacacacacacacacacacacalalacacacacacalacacacacacacacacacabababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccNeeeiaqeAetgAgBgCgCgCgCgCgDgDgEahahahfBgFgGgHgIgIgIgIgIgngIgJahahgpahahahahetgsgueecNacacacacacacalacacalalalacacacacacacacacacacacacalacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacalacacacacacacacacacacacacaccNeecNeeeneeeteteAetetgKetetahahahgpahgLgMgNahahahahahahgOahahahahahahgOahetetaqeecNacacacacacacacacacalalalacacacacacacacacacacacacalacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacaracacacacacacacacacacacacacalalacacacacacacacacacacacacacaccNcNcNeifieeaqeienaqaqaqaqaqasasasasasaggPasasasasasasasasasasasasasasasasasasaqeecNacacacacacacacacacalalalacacacacacacacacacacacacacacalacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababacacababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaracacacacacacacaccNcNcNeieneeeAeienengQgRgSgSgTgUgVgVgVgWgXgYahahgZgZhahafLhbhcasasasasasasasasaqeecNcNacacacacalacacacacalalacacacacacacacacacacalalacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacalacacacacacacacacacacacacalalacacacacacacacacacacacacacacacaccNcNcNeeeneeeneeeienethdhehehfhghhhihjahhkgNahahahhlahahahhmhnhohphqhqhqhqhqasaqeecNeeacacacalacacacalacacalalalalacacacaracalacacalacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacalalalalalalacacacacacacacacacacacacacacacacaccNfmeieneeeneieeeieneAetethrhshthshuhvhwahahhxahhyahahahhzhAhBhChqhqhqhqhqasaqeecNcNacacacalacacacalalalalacacacacacacacacalacalacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacalacacacacacacalacacacacacacacacacacaccNcNcNcNeeeneeeneneienhDhDhDhEhEhEhEhEhEhFhEhEhEhEhEhEhEhEhEhEhGhHhqhqhqhqhqasaqcNcNacacacacacalacacacacacacacacacacacacacacacalalacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacalacacacacacacacacacacacacacacacacacacalacacacacacacacacacaccNcNcNeeeneeeeeneieeeiethIhIhJahhKhKhKhLhMhLahahhNhNahahhxahasasasasasasasasasaqcNacacacacacacacacacacacacacacacacacacacacacacacalacacacacacacacacacababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacalacacacacacacacacacacacacacacacacacalacacacacacacacacacacaccNcNeieneeeeeXeieeetaqaqaqasasasasasashOasasasasasasasasasasasasasasasaqaqaqaqcNcNacacacacacacacalacacacacaracacacalalacacacacalacacacacacacacacacababababababababababacacacacababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacalacacacacacacacacacacacacacacacacacacacacacacacacacacacaccNcNcNeieneecNeeeneehDhDhDhPhDhDhQhEhRhEhShEhThEhQhEhEhRhEhEhUhVahahahaqaqcNcNcNacacacalalacacacalalalacacacacacacacacacacalalalalacacacacacacabababababababababababababacacacacabababababababababacacacacabababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacalalacacacacacacacacacacacacacacacacacacacacacaccNcNcNhWcNcNcNeieneeeAeAetetetetasahahahhMahahahasahahahahahahhMahahaqaqcNcNhWcNacacacalacacacacalalalacacacacacacacacacacacacalacacacabababababababababababababababacacacacacacacababababababababacacacacabababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacaracacacacacacacacacacacacacacacacacacacacacacacacacacacacaccNcNcNcNcNeecNeieneehXaqaqaqaqaqaqahahahhMahahahaqaqaqaqaqaqahhMahaqaqcNcNhYeeeeacacacalalalalalalacacalacacacacacacacacacacacalacacacabababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacabababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacachWcNhYcNcNeeeicNetaqcNeeeehYaqaqahahhMahahaqaqcNcNeeeeaqhZhSiaaqcNcNhWhYeeeeacacacacalalalalalacacacacacacacacacacacacacacacacacacabababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacabababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacalacacacacaracacacacacalacacacacacacacacacacacachWhYeecNcNcNcNcNcNaqhWibiciccNaqaqhZhSiaaqaqcNcNcNeeeeaqidididaqcNcNhWeieieeacacacacacacacacalacacacacacacacacalacacacalalacacacacabababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacalacacacacacacacacacacalacacacacacacacacacacacachYhYeCeneefpeecNcNhWhWeiicenhWcNaqidididaqcNcNcNeeibibcNcNcNcNcNcNhWcNeieieeacacacacacacacacacacacalacacacacacacacacacacacacacacacababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacalalacacacacacacacacacacacacacacacacacacacacacaceeeeeCeCeieneieecNcNeeeieieicNcNcNcNcNcNeeeeeieieneneneecNeeeeeecNcNcNeneneiacacacacacacacacalacacacaracacacacacalacacacacacacacacacacacacacacacacacababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacalalacacacacacalalalacacacacacacacacacacacacaceeieeieCeneieeeieieeeneneieieeeeeeeeieeeeneieneieneneieecNeeeieieecNcNeieieeacacacacacacacacalacacacacacacacacacacacacacacacacacacacacacacacacacacacababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacaracacalacacacacacacacalacacacacacacacacacacacacacacacaccNcNeeeieneneieCeneneCeMeCeCeieeeieeeieieHeneHeMeCeneieieeeeeieieieeeeeieieeacacacacacacacacacacacacacacacacacacalacacacacacababacacacacacacacacacacabababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacalacacacalalacacacacacacacacacacacacacacacacacacaccNeeeneifjeieieCeUeHeneCeneCeneiifeieieneHeneHeMeCeneieieeeeeieReneieieeeecNacacacacacacacacacalacacacacacacacacacalacacacacababacacacacacacacacacacabababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacalacacacacacacacalacacacalalacacacacacacacacacacacacacacacacacacaccNeeeneneneeeeeneHeCeieCeneneieieCeieCeCeCeneCeMeHeneieieieeeeeieneieieecNcNacacacacaracacacacalacacacacacacacacacalalacacacababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababacacacacalalacacacacalacacacacalacalacacacacacacacacacacacaracacacacacacaccNeeeneneneieienigeHeneCeneneneCeCeHeMeHeneCeCeSeHeHeHeCeneieieieneieieecNcNacacacacacacacacacalacacacacacacacacacacalalacacababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacalacacacacacacacacacalacacacacacacacacacacacacacacacacacacaccNcNeieieCeneneifieHeneCeneCeCeneCeCeHeCeneHeCeSeHeSeSeMeCeneeeeeeieeeeecNcNacacacacacacacacacacacacacacacaracacacacacalacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacalalacacacacacacacacacacacacacacacacacacencNeeeieieieneHeneneHeCeHeCeCeneCeieneHiheCeCeCeneCeMeMeHeneReeeeeieieieecNcNacacacacacacacacacalacacalacacacacacacacacalacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacalalacacacacacacacacacacacacacacacacacacacaceicNcNeieifpeieHeneieieCeieieieeiieieieneHeHeHeHeHeCeMeMeCeieieeeeeiiieieecNcNacacacacacacalacacacalacalacacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceicNeeeneCeHeCeCeneneneCeieieieeeieieneieneneCeCeHeCeMeMeCeieieieeeieieeeecNcNacacacacacacalacacacalalacacacacacacacalacacacacacacacacabababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceecNeeeieCeHeHeneCeHeneMeHeCeneieieieneieHeieneneCeieieieeeeeeeieneneneeeecNcNacacalalacacalacacacalalacalalalacacacalacacacacacacabababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacaracacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccNeeeieCeHijeneHeHeCeMeneneieieieieieneMeHeCeCeHeneneieieieieneCeneneeeicNcNacacacacalacacacacacacalacacacalalacalacacacacacabababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacababababababacacacacacacacacaccNaccNeeeeeieeeiikeneCeieieieieienibiceieieeeeeieeeeeFeFhYeeeeeneeeeeeeicNcNacacacacacacacacacacacacalalacacalalalacacacacacabababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacaccNaceeeieehYeeenileneCeieieieneiichYimhYeeeeeneeeeeeeFeFeeeeeeeneeeeeeeicNcNacacacacalacacacacacacacacalacacalacacalalacacacababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacababababababababababababababababacacaccNaceeeieehYeeeieieeenieeeeeeecNeieienibeieeeneeeeeeeFeFcNhWcNeieeeeeeeieecNcNacacacacalacacacacacacalalacacacacacacalalacacababababababababacacacacacacacacacacacacacacacacacacacacaclbacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacababababababababababababababababababababababacacacacaceeeeeFhWibiciieeeneeeeeieicNcNeeeieiibeeeneeeFeeeFeFcNhWcNeieeeeeeeieecNcNacacacacalacacacacacalalalacacacacacacacalacacababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacababababababababababababababababababababababababababababababababacacaceeeeiocNhYhYcNeeeneieeeieicNcNeeeiibibeeeneeeFeeeFeFcNhWcNeeeFeeeeeieecNcNacacacacalacacaracalacacalacacaracacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacababababababababababababababababababababababababababababababababababacacacaccNacaccNeeeecNeFeeeeaceeeecNeeeienenibeeeieieFeeeFeFcNcNcNeeeFeFeeeieecNacacacacacalacacacalacacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacababababababababababababababababababababababababababababababababababacacacacaccNacioeehYioacaceeeiaceeeeaccNeieiiceieeeieieFeeeFeFcNcNhWeeeFeFeeeieecNacacacacacacalalalacacacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacaccNacioeehYacacaceeeiaceeeeaccNeeeiibeeeeeeeieFeeeFeFeFeFhWeeeFeFeieecNcNacacacacacacalalacacacacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacaccNacioeehYacacaceeeiaceieiaccNcNeeeeeeeeeeeieFeeeFeFeFeFhWeeeFeFeieecNcNacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacaccNacioeehYacacaceeeeaceeeeaccNcNhYeeeeipipeieFeieFeFeFeFcNeeeFeFeieicNcNacacacacacacacacalacacacacacacacacacacabababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacaccNioacachYacacaccNcNaceeeeaccNcNhWcNacacaceeaceeacacacaccNcNacaceFcNacacacacacacacacacacalacacacacacacacacacacabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacachYacacaccNacacacacaccNcNhWcNacacaceeaccNacacacaccNcNacaceFeeacacacacacacacacacacalalalacacacacacacacacababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacachWacacaccNacacacacaccNcNcNhYacacaceeaccNacacacaccNcNacaceFeeacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacachWacacaccNacacacacacacaccNcNacacaceieFacacacacaccNcNacaceFeeacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacachWacacaceeacacacacacacaccNacaceFcNacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacabababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacachWacacacacacacacacacacaccNacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacabababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacaracacacacacacacacacacacacacacacaccNacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababacababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababacababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababacacabababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +iqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/icarus/icarus-2.dmm b/maps/away/icarus/icarus-2.dmm new file mode 100644 index 00000000..daca9b9a --- /dev/null +++ b/maps/away/icarus/icarus-2.dmm @@ -0,0 +1,492 @@ +"aa" = (/turf/unsimulated/mineral,/area/space) +"ab" = (/turf/unsimulated/mask,/area/mine/unexplored) +"ac" = (/turf/simulated/open,/area/icarus/open) +"ad" = (/turf/simulated/mineral,/area/icarus/open) +"ae" = (/turf/simulated/mineral,/area/icarus/vessel) +"af" = (/obj/structure/grille,/turf/simulated/floor/plating,/area/icarus/vessel) +"ag" = (/turf/simulated/floor/plating,/area/icarus/vessel) +"ah" = (/obj/item/weapon/ore/slag,/turf/simulated/floor/plating,/area/icarus/vessel) +"ai" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aj" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ak" = (/turf/simulated/floor/tiled,/area/icarus/vessel) +"al" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"am" = (/obj/item/weapon/ore/slag,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"an" = (/obj/structure/table/steel_reinforced,/obj/random/firstaid,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ao" = (/turf/simulated/wall/r_wall,/area/icarus/open) +"ap" = (/turf/simulated/wall/r_wall,/area/icarus/vessel) +"aq" = (/obj/structure/table/steel_reinforced,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ar" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"as" = (/obj/structure/table/steel_reinforced,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"at" = (/obj/structure/table/steel_reinforced,/obj/random/handgun,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"au" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"av" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aw" = (/obj/structure/table/steel_reinforced,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ax" = (/obj/random/trash,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ay" = (/obj/structure/window/reinforced/full,/obj/machinery/door/firedoor,/obj/structure/grille,/turf/simulated/floor/tiled,/area/icarus/open) +"az" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/icarus/open) +"aA" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/obj/effect/landmark/corpse/bridgeofficer,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aB" = (/obj/effect/decal/cleanable/dirt,/obj/effect/overmap/sector/icarus,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aC" = (/mob/living/carbon/human/skinless,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aD" = (/obj/structure/bed/chair{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aE" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/fancy/cigarettes/killthroat,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aF" = (/obj/effect/floor_decal/plaque,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aG" = (/obj/random/loot,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aH" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/box/survival,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aI" = (/obj/structure/ladder,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aJ" = (/obj/structure/table/steel_reinforced,/obj/random/tool,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aK" = (/obj/item/modular_computer/console,/obj/item/weapon/disk/icarus,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aL" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/box/trackimp,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aM" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aN" = (/obj/item/modular_computer/console,/obj/item/weapon/paper/icarus/log,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aO" = (/obj/structure/bed/chair/comfy/captain{color = "#666666"; dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aP" = (/obj/structure/table/steel_reinforced,/obj/item/device/flashlight/lamp,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aQ" = (/obj/structure/table/rack,/obj/item/device/flashlight/flare,/obj/item/device/flashlight/flare,/obj/item/device/flashlight/flare,/obj/item/device/flashlight/flare,/turf/simulated/floor/tiled/dark,/area/icarus/vessel) +"aR" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aS" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aT" = (/obj/structure/sign/icarus/solgov{pixel_x = 30},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aU" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/box/PDAs,/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aV" = (/obj/structure/table/steel_reinforced,/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/item/weapon/storage/toolbox/emergency,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aW" = (/obj/structure/sign/icarus/solgov{pixel_x = -30},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aX" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aY" = (/obj/structure/table/rack,/obj/item/weapon/airlock_brace,/obj/item/weapon/airlock_brace,/obj/item/weapon/airlock_brace,/obj/item/weapon/crowbar/brace_jack,/turf/simulated/floor/tiled/dark,/area/icarus/vessel) +"aZ" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/telecomms/server,/turf/simulated/floor/bluegrid,/area/icarus/vessel) +"ba" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bc" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"be" = (/obj/machinery/light,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bf" = (/obj/structure/filingcabinet,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bg" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bh" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bi" = (/obj/structure/table/rack,/obj/item/weapon/storage/box/teargas{pixel_x = 3; pixel_y = 2},/obj/item/weapon/storage/box/handcuffs,/obj/item/weapon/storage/box/flashbangs{pixel_x = -2; pixel_y = -2},/turf/simulated/floor/tiled/dark,/area/icarus/vessel) +"bj" = (/obj/structure/table/rack,/obj/item/weapon/gun/projectile/shotgun/pump,/obj/item/weapon/gun/projectile/shotgun/pump,/turf/simulated/floor/plating,/area/icarus/vessel) +"bk" = (/obj/machinery/telecomms/server/presets/common,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/bluegrid,/area/icarus/vessel) +"bl" = (/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/bluegrid,/area/icarus/vessel) +"bm" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bn" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bo" = (/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bp" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/icarus/vessel) +"bq" = (/obj/structure/table/rack,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/baton,/turf/simulated/floor/plating,/area/icarus/vessel) +"br" = (/obj/structure/table/rack,/obj/item/weapon/handcuffs,/turf/simulated/floor/plating,/area/icarus/vessel) +"bs" = (/obj/machinery/telecomms/server,/turf/simulated/floor/bluegrid,/area/icarus/vessel) +"bt" = (/turf/simulated/floor/bluegrid,/area/icarus/vessel) +"bu" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bv" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bw" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bx" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"by" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bz" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bA" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bB" = (/obj/machinery/papershredder,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bC" = (/obj/machinery/photocopier,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bD" = (/obj/structure/filingcabinet,/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bE" = (/obj/structure/window/reinforced/full,/obj/machinery/door/firedoor,/obj/structure/grille,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bF" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bG" = (/obj/structure/closet,/obj/item/weapon/reagent_containers/food/drinks/bottle/tequilla,/obj/item/weapon/reagent_containers/food/drinks/bottle/wine,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bH" = (/obj/structure/bed/chair/comfy/brown{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bI" = (/obj/structure/table/woodentable,/obj/random/loot,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bJ" = (/obj/structure/table/woodentable,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bK" = (/obj/structure/bed/chair/comfy/brown{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bL" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bM" = (/obj/structure/table/steel_reinforced,/turf/simulated/floor/plating,/area/icarus/vessel) +"bN" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/handcuffs,/turf/simulated/floor/plating,/area/icarus/vessel) +"bO" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/material/harpoon,/turf/simulated/floor/plating,/area/icarus/vessel) +"bP" = (/obj/machinery/suit_storage_unit/security/alt,/turf/simulated/floor/plating,/area/icarus/vessel) +"bQ" = (/obj/structure/window/reinforced/full,/obj/structure/grille,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/open) +"bR" = (/obj/structure/table/steel,/obj/random/tool,/obj/random/tool,/obj/random/tool,/turf/simulated/floor/tiled,/area/icarus/open) +"bS" = (/obj/item/modular_computer/console,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bT" = (/obj/structure/closet,/obj/item/weapon/storage/backpack/industrial,/obj/item/weapon/storage/toolbox/electrical,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bU" = (/obj/structure/closet,/obj/item/clothing/suit/space/emergency,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bV" = (/obj/structure/closet,/obj/item/weapon/storage/backpack/industrial,/obj/item/weapon/storage/toolbox/mechanical,/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bW" = (/obj/structure/closet,/obj/item/clothing/suit/radiation,/obj/item/clothing/suit/radiation,/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bX" = (/turf/simulated/wall,/area/icarus/vessel) +"bY" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bZ" = (/obj/structure/closet,/obj/item/weapon/reagent_containers/food/drinks/flask/shiny,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ca" = (/obj/structure/bed/chair/comfy/brown,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cc" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cd" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/icarus/vessel) +"ce" = (/obj/structure/table/steel,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cf" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/obj/effect/landmark/corpse/engineer,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cg" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ch" = (/obj/random/trash,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ci" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cj" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ck" = (/obj/structure/closet,/obj/item/weapon/reagent_containers/food/drinks/golden_cup,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cl" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/backpack/captain,/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cm" = (/obj/structure/table/woodentable,/obj/item/weapon/paper/icarus/crew_roster,/obj/item/weapon/folder/blue,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cn" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/icarus/vessel) +"co" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cp" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cq" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cr" = (/obj/machinery/light{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cs" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ct" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cu" = (/obj/structure/table/steel_reinforced,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cv" = (/obj/structure/table/steel,/obj/random/tank,/turf/simulated/floor/tiled,/area/icarus/open) +"cw" = (/turf/simulated/floor/tiled,/area/icarus/open) +"cx" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/tiled,/area/icarus/open) +"cy" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cz" = (/obj/structure/bed,/obj/item/weapon/bedsheet/captain,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cA" = (/obj/structure/table/woodentable,/obj/item/weapon/reagent_containers/food/drinks/bottle/whiskey,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cB" = (/obj/structure/sign/double/icarus/solgovflag/left{pixel_y = -32},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cC" = (/obj/structure/sign/double/icarus/solgovflag/right{pixel_y = -32},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cD" = (/obj/structure/table/woodentable,/obj/item/toy/ship_model,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cE" = (/obj/structure/table/woodentable,/obj/random/action_figure,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cF" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cG" = (/obj/item/weapon/stool,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cH" = (/obj/item/weapon/stool,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cJ" = (/obj/structure/table/steel_reinforced,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cK" = (/obj/machinery/alarm{dir = 1; pixel_y = -25; req_one_access = list(24,11)},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cL" = (/turf/simulated/floor/plating,/area/icarus/open) +"cM" = (/obj/structure/table/rack,/obj/random/tool,/turf/simulated/floor/tiled,/area/icarus/open) +"cN" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cO" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cP" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cQ" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cR" = (/obj/structure/lattice,/turf/simulated/open,/area/icarus/open) +"cS" = (/obj/structure/table/rack,/obj/random/tech_supply,/turf/simulated/floor/tiled,/area/icarus/open) +"cT" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cU" = (/obj/machinery/alarm{alarm_id = "xenobio4_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cV" = (/obj/item/modular_computer/console,/obj/machinery/light{dir = 1},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cW" = (/obj/structure/table/woodentable,/obj/item/weapon/disk/secret_project/science,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cX" = (/obj/structure/window/reinforced/full,/obj/structure/grille,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cY" = (/obj/machinery/light{dir = 1},/obj/structure/table/standard,/obj/structure/window/reinforced{dir = 8},/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cZ" = (/obj/structure/table/standard,/obj/machinery/reagentgrinder,/turf/simulated/floor/tiled,/area/icarus/vessel) +"da" = (/obj/machinery/light{dir = 1},/obj/structure/table/standard,/obj/item/weapon/storage/box/monkeycubes,/turf/simulated/floor/tiled,/area/icarus/vessel) +"db" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/beakers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dc" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dd" = (/obj/structure/bed,/turf/simulated/floor/tiled,/area/icarus/vessel) +"de" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"df" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dg" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dh" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"di" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dj" = (/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/tiled,/area/icarus/open) +"dk" = (/obj/structure/sign/science_2{pixel_x = 30},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dl" = (/obj/structure/bed/chair/comfy/brown{dir = 4},/obj/effect/landmark/corpse/scientist,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dm" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dn" = (/obj/machinery/door/window/eastleft,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"do" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dp" = (/obj/structure/closet,/obj/item/weapon/gun/projectile/shotgun/pump,/obj/item/weapon/reagent_containers/spray/pepper,/obj/item/weapon/storage/box/handcuffs,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dq" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dr" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"ds" = (/obj/structure/table/rack,/obj/random/tool,/obj/random/powercell,/turf/simulated/floor/tiled,/area/icarus/open) +"dt" = (/obj/item/modular_computer/console,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"du" = (/obj/structure/table/woodentable,/obj/item/device/flashlight/lamp,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dv" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/box/fingerprints,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dw" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"dx" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dy" = (/obj/random/loot,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dz" = (/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dA" = (/obj/structure/bed,/obj/item/trash/snack_bowl,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dB" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dC" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/box/flashshells,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dD" = (/obj/random/trash,/turf/simulated/floor/tiled,/area/icarus/open) +"dE" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dF" = (/obj/structure/closet,/obj/item/clothing/suit/storage/toggle/labcoat/blue,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dG" = (/obj/structure/closet,/obj/item/clothing/suit/storage/toggle/labcoat/blue,/obj/item/weapon/disk/survey,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dH" = (/obj/structure/table/standard,/obj/item/device/flashlight/lamp,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dI" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/reagent_containers/spray/pepper,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dJ" = (/obj/item/modular_computer/console,/obj/machinery/alarm{dir = 1; pixel_y = -25; req_one_access = list(24,11)},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dK" = (/turf/simulated/wall,/area/icarus/open) +"dL" = (/obj/effect/decal/cleanable/dirt,/obj/random/trash,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"dM" = (/obj/item/modular_computer/console,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dN" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"dO" = (/obj/machinery/r_n_d/destructive_analyzer,/turf/simulated/floor/tiled,/area/icarus/open) +"dP" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/open) +"dQ" = (/obj/random/trash,/turf/simulated/floor/plating,/area/icarus/open) +"dR" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/icarus/open) +"dS" = (/obj/structure/bed,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dT" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"dU" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"dV" = (/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/open) +"dW" = (/obj/machinery/door/window/eastleft,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/open) +"dX" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dY" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled,/area/icarus/open) +"dZ" = (/obj/effect/icarus/irradiate,/turf/simulated/open,/area/icarus/open) +"ea" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/icarus/open) +"eb" = (/obj/item/clothing/ring/mariner,/turf/simulated/floor/tiled,/area/icarus/open) +"ec" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/icarus/open) +"ed" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/open) +"ee" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/open) +"ef" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/open) +"eg" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/open) +"eh" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ei" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/icarus/vessel) +"ej" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/obj/structure/sign/warning/internals_required{pixel_y = -30},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ek" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled,/area/icarus/vessel) +"el" = (/obj/structure/sign/warning/airlock{pixel_y = -30},/turf/simulated/floor/plating,/area/icarus/vessel) +"em" = (/obj/random/material,/turf/simulated/floor/plating,/area/icarus/vessel) +"en" = (/obj/machinery/door/airlock,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/icarus/vessel) +"eo" = (/obj/structure/grille,/turf/simulated/floor/reinforced,/area/icarus/open) +"ep" = (/turf/simulated/floor/reinforced,/area/icarus/open) +"eq" = (/turf/simulated/shuttle/wall,/area/icarus/open) +"er" = (/turf/simulated/shuttle/wall{icon_state = "swall_straight"; dir = 4},/area/icarus/vessel) +"es" = (/turf/simulated/shuttle/wall{icon_state = "swall_t"; dir = 1},/area/icarus/vessel) +"et" = (/obj/structure/shuttle/window,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eu" = (/obj/structure/shuttle/engine/propulsion{dir = 4},/turf/simulated/shuttle/wall,/area/icarus/open) +"ev" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/icarus/vessel) +"ew" = (/obj/structure/shuttle/engine/propulsion{icon_state = "propulsion_l"; dir = 8},/turf/simulated/shuttle/wall,/area/icarus/vessel) +"ex" = (/obj/structure/shuttle/window,/turf/simulated/floor/shuttle/white,/area/icarus/open) +"ey" = (/obj/structure/table/reinforced,/turf/simulated/floor/shuttle/white,/area/icarus/open) +"ez" = (/obj/machinery/light/small{dir = 4; pixel_y = 0},/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eA" = (/turf/simulated/shuttle/wall{icon_state = "swall"; dir = 1},/area/icarus/vessel) +"eB" = (/obj/structure/bed/chair,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eC" = (/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eD" = (/obj/structure/table/rack,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eE" = (/obj/structure/table/rack,/obj/item/clothing/mask/breath/emergency,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eF" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/icarus/vessel) +"eG" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eH" = (/obj/machinery/portable_atmospherics/canister/carbon_dioxide,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eI" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eJ" = (/obj/item/modular_computer/console,/turf/simulated/floor/shuttle/white,/area/icarus/open) +"eK" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eL" = (/obj/machinery/door/airlock,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eM" = (/obj/machinery/door/airlock/external,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eN" = (/obj/machinery/door/airlock/external,/turf/simulated/floor/plating,/area/icarus/vessel) +"eO" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1379; id_tag = "bridgeport_pump"},/turf/simulated/floor/plating,/area/icarus/vessel) +"eP" = (/obj/machinery/door/airlock/external,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/icarus/vessel) +"eQ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/turf/simulated/floor/plating,/area/icarus/vessel) +"eR" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1331; id_tag = "ninja_shuttle_pump"},/turf/simulated/floor/plating,/area/icarus/vessel) +"eS" = (/obj/structure/bed/chair{dir = 4},/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eT" = (/turf/simulated/shuttle/wall{dir = 2; icon_state = "swall"},/area/icarus/vessel) +"eU" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/shuttle/white,/area/icarus/open) +"eV" = (/obj/machinery/light/small,/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eW" = (/turf/simulated/shuttle/wall,/area/icarus/vessel) +"eX" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/shuttle/white,/area/icarus/vessel) +"eY" = (/turf/simulated/shuttle/wall{icon_state = "swall_straight"; dir = 4},/area/icarus/open) +"eZ" = (/turf/simulated/shuttle/wall{icon_state = "swall_t"; dir = 2},/area/icarus/open) +"fa" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/icarus/vessel) +"fb" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/plating,/area/icarus/vessel) +"fc" = (/obj/structure/shuttle/engine/propulsion{icon_state = "propulsion_l"; dir = 8},/turf/simulated/shuttle/wall,/area/icarus/open) +"fd" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/power/solar,/turf/simulated/floor/reinforced,/area/icarus/open) +"fe" = (/obj/machinery/power/solar_control,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/plating,/area/icarus/vessel) +"ff" = (/obj/machinery/power/terminal{dir = 4},/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/icarus/vessel) +"fg" = (/obj/machinery/power/smes/buildable,/obj/structure/cable,/turf/simulated/floor/plating,/area/icarus/vessel) +"fh" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fi" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fj" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fk" = (/obj/machinery/door/airlock/external,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/icarus/vessel) +"fl" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fm" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fn" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fo" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow,/obj/machinery/power/solar,/turf/simulated/floor/reinforced,/area/icarus/open) +"fp" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fq" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1331; id_tag = "calypso_shuttle_pump"},/turf/simulated/floor/plating,/area/icarus/vessel) +"fr" = (/obj/machinery/door/airlock/external,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/icarus/open) +"fs" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"ft" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fu" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fv" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fw" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/plating,/area/icarus/open) +"fx" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/yellow,/turf/simulated/floor/reinforced,/area/icarus/open) +"fy" = (/obj/machinery/power/tracker,/obj/structure/cable/yellow,/turf/simulated/floor/reinforced,/area/icarus/open) +"fz" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/mob/living/carbon/human/skinless,/turf/simulated/floor/tiled,/area/icarus/vessel) +"fA" = (/mob/living/carbon/human/skinless,/turf/simulated/floor/plating,/area/icarus/open) +"gb" = (/obj/effect/landmark/map_data{height = 2},/turf/unsimulated/mineral,/area/space) +"hb" = (/obj/effect/landmark/random_gen/asteroid,/turf/unsimulated/mineral,/area/space) + +(1,1,1) = {" +gbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacabababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababacacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacacacacababababababacababababababacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababacacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacacacacacacabababacacacacacababababacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababacacacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacacacacacacacacacabababacacacacacacabababacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababacacacacacacadadadadadadadadadadadadadadadadadaeaeaeadaeaeaeadadadadadadadadadadadadadadadacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababacacacacacacacadadadadadadadadadadadadadadadadaeaeafaeadaeagaeaeadadadadadadadadadadadadadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababacacacabababababacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababacacacacacacacacacacadadadadadadadadadadadadadaeahagagaeaeahagaeadadadadadadadadadadadadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababacacacababababababababacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababacacacacacacacacacadadadadadadadadadadadadaeaeagagaiajagagakakahaeadadadadadadadadadadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacababababababababababababacacacacacacacacacacacacacacacacababababababababababababababababababababacacacacacacacacacacacadadadadadadadadadadaeahakakaiakalakakamaianaoacacacadadadadadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacababababababababababababababacacacacacacacacacacacacacacababababababababababababababababababababababacacacacacacacacacacacacacacadadadadadadadapaqararaiaiakakakakakasaoacacacacadadadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacabababababababababababababababababacacacacacacacacacacacababacacabababababababababababababababababababacacacacacacacacacacacacacacacadadadapapapatauaiavakakakaiakakawapaoaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababacabababababababababababababababacacacacacacacacacacacacacacacacacabababababababababababababababababacacacacacacacacacacacacacacacacacadapajararaiakaiakakakakakaxakakajaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacabababababababababababababababababacacacacacacacacacacacacacacacacacacayazaAakaiakaxakaBakakaxakakaDazayacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacababababacacacacababababababacacacacacacacacacacacacacacacacacacaoajakaiakakakakakakaiakakakakajaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacabababacacacacacacacabababacacacacacacacacacacacacacacacacaoapapapaEakakaCakakaFakaiaGakakaHapapaoaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoaoaoapaIakapaJaxakaiakajaKajakaiakakaLapakaIapaoaoaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoaMaNapaIakapaJakakakakakaOakakakakakaPapakaIapaQagaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoapaMaRapaSaTapaUakakakakakakakakakakakaVapaWaXapaYagapaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoapaZakakapbabbbcbdbeakbfbfbfakbfbfbfbfbgakbhakakapbiagbjapaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoapbkblakbmapbnboapapapbhapapapbhapapapapapapapboboapbpagbqbrapaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoapbsbtbtbubvbwbxbbbcbybzakapakakakakbAakbBbCbDbEakakapagagagagagapaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoapapapapapapapapbFakapbGakbfapakbHbIbJbKakakakbLapakaiapagbMbNbOagbPapaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacbQbRajbSbTbUbVbWbXbYakapbZakcaapakbHbJbJbKakakaxcbbwbbccapcdapapapapapapapaoacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaocecfarakakcgchbwcicjapckakclapakbHbJcmbKakakakcnapcocpbccqcrfzctcuaRbAbfaoacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaocvcwcwcwcwcwcxbXcybzapczbgcAapakakcBcCbgakbIcDcEbEaxcFapcGcHcHcIcJajcKakaoacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaocwcwfAcLcLcwcMbXcNaxapapapapapapapapapapapapapapapakcOapapapapcPapapapcQaoacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaocwcwcLcRaccLcSbXcTbbbccUcVcWcXaMcYcZaMdadbaMbBbCapakdcapddcXbudedfdgdhdiaoacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaodjcwcLacaccLcSbXbYdkapbYdlbJcXakakakakakakakakdmapakbYapakdnakdoapdpdqdrbQacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLdjcwcLaccRcLdsbXbFakapcydtducXakakakakaiaiakakbfapaibYapapapaiakapdvakdwbQacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLcwcwcLcRaccLcwbXbYakapdxapapapakdyakdzakakdzakbfapaibYapdAcXaidBapdCdzdwbQacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLcLdDcLaccLcLcwbXbYakapdEcsdFdGaCakaMajdHaMajaMbfapaibYapaidnakaiapdIdJbYaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLcLcwcLcLcLcwcwdKdLcwaodMakcwcwcwcLcLcLcLcLcLcLcLcLcwdNapapapakaiapapapcPaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLcLcLcwcwdDcwcLdKdwcwaodOdPcwcwdQcLacaccRaccLcLdRcLcwdwaocwbQakaiapdddSdTbQacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLcLcLcwcwcwcwcLdKdUdVaocwdPcLcLdRcLcRaccRacdQcLcLcLdVdUcLcwdWcwcwapakakdXbQacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLcRcLcLdDcwcwcLdKdwcwcLcwcwcLcLcLcLcRcRcRcRcRcLcLcLcLdRcLcLcLcwcwdYcwcLcLbQacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRcRcLcLcwcwcLcLdKdwdDcLcLcLdQacaccRcRcRaccRacdRcLacaccRacacdRcLcwaoaocLcLcLacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRcLcLcLcLcLcLdKdwcwcLdRcLcLacaccRcRcRaccRacacacacaccRcRaccLdQcLaocLcLdRacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRacdRcLdQcLcLdKaccLcLcLcRcRacaccRacacacacacacacacacaccRacaccLcLcLcLcLcLacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccLcLcLcLcLdKcRcRcRaccRcRcRacacacacacacacacacacacacacacacacaccLcLdRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRcLcLdRcLdRacaccRcRacaccRacacacacacacacacacacacacacacacacacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRcRacaccLcRcRaccRacacaccRacacacacacacacacacacacacacacacacacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRcRacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacdZacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababacacababababababababababababababababababababababababaa +aaabababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababacababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacaccRcRacacacacacacacacacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababacacacacacacacacacacacacacacacacacacabacacacacacacacacacacabababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacaodRcRacacaccRacacacacacaccRcRcRacacacacacacacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacacacacacabacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacaocwcLacaccRcRcRacacacaccLcLdRcLcLacacaccRacacaccRcRacacacacacaccRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacacacacacabababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacaocwcLcLaccRdKcRaccLcLacaccLcLcLcLacaccRcRcRaccLcLcLacacacacaccRcRacaccRcRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacaocwcLdRcLcLdKcLaccLdRcLcLcLcLcLcLcLeacLcLcRcRcLcLcLcLcLcLcLcRcRcRcRaccRcRcRacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacaocwebdPcwcwdKcLcLcLcLcLcwcwdPdPcwcweccLcLcLcLcLcLcLcLdRcLcLcLcLcLcLacaccRcRacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacabababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaodPcweddPcweecwcwcLcLcwcwefdPdPcwcwegcLcLdRcLcLcLcLcLcLcLcLcLcLcLcLacaccRcRacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababacacacacacacacacacacabababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaodPdPefaiakbXakakakakaiavavavaiaiakehagagagagagagagagagagagageiagcLcLdRcRcRacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacaocwdPdPakakbXaIakakakakakakakakakejekelagagagagagagagagemagagagagcLcLcLcLaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacaoaoaoaoapapapapapapapapapapapapapapenapapapapapapapapapapapapapapaoaoaoaoaoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoepepeqerereseteteterererereuepepapevapepepewerererereteteteserereqepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoepepexeyezeAeBeBeBeCeDeDeEeAapapapeFapapapeAeGeHeCeIeBeBeBeAeCeyexepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoepepexeJeKeLeCeCeCeCeCeCeCeMeNeOePeQePeReNeMeCeCeCeCeCeCeCeLeSeJexepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoepepexeyeCeTeUeUeUeVeCeHeGeWaoapapenapapaoeTeDeDeEeCeUeUeUeTeXeyexepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoepepeqeYeYeZexexexeYeYeYeYeuepaobpfafbaoepfceYeYeYeYexexexeZeYeYeqepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceofdfdfdfdfdfdfdfdfdfdfdfdfdepepaofefffgaoepepfdfdfdfdfdfdfdfdfdfdfdfdfdfdeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceofhfififififififififififififjepaoapfkapaoepflfmfmfmfmfmfmfmfmfmfmfmfmfmfneoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceofofofofofofofofofofofofofofpepepaofqaoepepfpfofofofofofofofofofofofofofoeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoepepepepepepepepepepepepepfpepepaofraoepepfpepepepepepepepepepepepepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoepepepfdfdfdfdfdfdfdfdfdfdfpepepepfpepepepfpfdfdfdfdfdfdfdfdfdfdfdfdfdfdeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRcRcRcRfhfififififififififififsfsfsftfufufvfwfmfmfmfmfmfmfmfmfmfmfmfmfmfneoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRcRfocRcRfxfofofofofofofofofofofpepepfofofofofofofofofofofofofofofofoeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababacacababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRacepcRcRcRepepepepepepepepepepfpepepepepepepepepepepepepepepepepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRaccRaccRcRcRfdfdfdfdfdfdfdfdfdfpfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRacacaccRfifififififififififtfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfneoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRaccRcRcRfofofofofofofofofofpfofofofofofofofofofofofofofofofofofoeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaccRaccRepepepepepepepepepfyepepepepepepepepepepepepepepepepepepeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaceoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoeoacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacepepepepepepepepepepepepepepepepepepepepepepepepepepepacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababacacacacabababababababababacacacacabababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacepepepepepepepepepepepepepepepepepepepepepepepepepepacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababacacacacacacacababababababababacacacacabababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacepepepepepepepepepepepepepepepepepepepepepepepepepacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacabababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacepepacacacacepepepepepepepepepacacacacepepepepepacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacabababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacepacacacacacepepepepepepepacacacacacepepepepepacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacepepepepepacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababacacacacacacacacacacacacacacacababacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababacacacacacacacacacacacacacacacababacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacacacacacacababacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacacacacacacababacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacabababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacacababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababacacacababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacabababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababababababababababacacacacacacacacacacabababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababacababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababacababababababababababababababababababababababababababababababababababaa +aaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababababababababababababababababababababababababababababababacacabababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaa +hbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/away/icarus/icarus.dm b/maps/away/icarus/icarus.dm new file mode 100644 index 00000000..db8e8586 --- /dev/null +++ b/maps/away/icarus/icarus.dm @@ -0,0 +1,213 @@ +#include "icarus_areas.dm" + +/obj/effect/overmap/sector/icarus + name = "forest planetoid" + desc = "Sensors detect anomalous radiation area with the presence of artificial structures." + icon_state = "globe" + known = 0 + in_space = 0 + generic_waypoints = list( + "nav_icarus_1", + "nav_icarus_2", + "nav_icarus_antag" + ) + +/obj/effect/overmap/sector/icarus/New(nloc, max_x, max_y) + name = "[generate_planet_name()], \a [name]" + ..() + +obj/effect/icarus/irradiate + var/radiation_power = 20//20 Bq. Dangerous but survivable for 10-15 minutes if crew is too lazy to read away map description + var/datum/radiation_source/S + var/req_range = 100//to cover whole level + +obj/effect/icarus/irradiate/Initialize() + . = ..() + S = new() + S.flat = TRUE + S.range = req_range + S.respect_maint = FALSE + S.decay = FALSE + S.source_turf = get_turf(src) + S.update_rad_power(radiation_power) + radiation_repository.add_source(S) + +obj/effect/icarus/irradiate/Destroy() + . = ..() + QDEL_NULL(S) + +/datum/map_template/ruin/away_site/icarus + name = "Fallen Icarus" + id = "awaysite_icarus" + description = "The crashlanding site of the SEV Icarus." + suffixes = list("icarus/icarus-1.dmm", "icarus/icarus-2.dmm") + cost = 2 + +/obj/effect/shuttle_landmark/nav_icarus/nav1 + name = "Planetary Navpoint #1" + landmark_tag = "nav_icarus_1" + +/obj/effect/shuttle_landmark/nav_icarus/nav2 + name = "Planetary Navpoint #2" + landmark_tag = "nav_icarus_2" + +/obj/effect/shuttle_landmark/nav_icarus/nav3 + name = "Planetary Navpoint #3" + landmark_tag = "nav_icarus_antag" + +obj/structure/icarus/broken_cryo + name = "destroyed cryo sleeper" + desc = "A mangled cryo sleeper with evidence that someone was inside when it was crushed. It looks like you could pry it open with a crowbar." + icon = 'maps/away/icarus/icarus_sprites.dmi' + icon_state = "broken_cryo" + anchored = 1 + density = 1 + var/closed = 1 + var/busy = 0 + +obj/structure/icarus/broken_cryo/attack_hand(mob/user) + ..() + if (closed) + to_chat(user, "You tug at the glass but can't open it with your hands alone.") + else + to_chat(user, "The glass is already open.") + + +/obj/structure/icarus/broken_cryo/attackby(obj/item/W as obj, mob/user as mob) + if (busy) + to_chat(user, "Someone else is attempting to open this.") + return + if (closed) + if (isCrowbar(W)) + busy = 1 + visible_message("[user] starts to pry the glass cover off of \the [src].") + if (!do_after(user, 50, src)) + visible_message("[user] stops trying to pry the glass off of \the [src].") + busy = 0 + return + closed = 0 + busy = 0 + icon_state = "broken_cryo_open" + var/obj/dead = new /obj/item/icarus/dead_personnel(loc) + dead.dir = src.dir//skeleton is oriented as cryo + else + to_chat(user, "The glass cover is already open.") + +/obj/item/icarus/dead_personnel + name = "partial skeleton remains" + desc = "Human bones wrapped in the shredded remnants of a familiar black uniform." + icon = 'maps/away/icarus/icarus_sprites.dmi' + icon_state = "dead_personnel" + w_class = ITEM_SIZE_LARGE//pile of bones + +/obj/item/weapon/disk/icarus + name = "black box backup disk" + desc = "Digital storage. Inscription says: \"Deliver to Sol Goverment Expeditionary Corps Command!\". Content is encrypted with quantum crypthography methods." + icon = 'icons/obj/items.dmi' + icon_state = "nucleardisk" + item_state = "card-id" + w_class = ITEM_SIZE_TINY + +/obj/item/weapon/paper/icarus/log + name = "Printed piece of paper" + info = "\[LOG\]: Orbit stabilized. Next correction burst, est.: 2 hrs 12 m
            \ + \[LOG\]: Orbit stabiliztion. Announcing...
            \ + \[ANN\]: Attention all hands, SEV Icarus is stabilizing orbit in 30 seconds. Prepare for possible gravitational spikes.
            \ + \[LOG\]: Announcing complete.
            \ + \[LOG\]: Preparing for burst: heating up impulse mass.
            \ + \[WARN\]: Minor pressure alert, Reactor Cooling Loop 3.
            \ + \[LOG\]: Burst ready. Bursting in 5 seconds.
            \ + \[LOG\]: Orbit stabilized. Next correction burst, est.: 1 hr 47 m.
            \ + \[ADM\]: Preparing shuttles for landing. Current status: required refuilling.
            \ + \[REQ\]: Request to Engineering, Please refuel Shuttle #2... Sent.
            \ + \[WARN\]: Minor pressure alert, Reactor Cooling Loop 1.
            \ + \[RET\]: Request completed.
            \ + \[LOG\]: Manual correction {Engine->Cooling->Pumps}: calculating new trend.
            \ + \[LOG\]: Calculating complete. Notify ADMIN...
            \ + \[ERR\]: Positive feedback loop in Engine Core! Prepare for emergency procedures.
            \ + \[ERR\]: Positive feedback loop in Engine Core! Prepare for emergency procedures.
            \ + \[ERR\]: Positive feedback loop in Engine Core! Prepare for emergency procedures.
            \ + \[ERR\]: Positive feedback loop in Engine Core! Prepare for emergency procedures.
            \ + \[ERR\]: Positive feedback loop in Engine Core! Prepare for emergency procedures.
            \ + \[LOG\]: This error was muted for 120 seconds.
            \ + \[WARN\]: Multiple hull breaches detected.
            \ + \[WARN\]: Unexepected orbit change, calculating corrective burst.
            \ + \[LOG\]: Preparing for burst: heating up impulse mass.
            \ + \[ERR\]: Impulse mass: not found
            \ + \[LOG\]: Orbit stabilizing: failed.
            \ + \[WARN\]: Impact imminent... Preparing blackbox backup... Ready.
            \ + \[LOG\]: Emergency shutdown!
            \ + \[LOG\]: Now you can you safely turn off your computer.
            " + + +/obj/item/weapon/paper/icarus/crew_roster + name = "Printed piece of paper" + info = "
            \[solcrest]
            \ + SEV Icarus
            \ + Crew roster

            \ + Command
            \ + \[list]\ + \[*]Commanding Officer: Cmd. Angela Peterson\ + \[*]Executive Officer: Lt. Semyon Andors \ + \[*]CMO: Lt. Toko Nashamura\ + \[*]CE: Ens. Anna Lawrence\ + \[*]COS: Lt. Rand Forbarra\ + \[*]CSO: Dr. Carl Jozziliny\ + \[*]BO: Ens. Gordon Johnson\ + \[/list]
            \ + Medical dept.
            \ + \[list]\ + \[*]Physician: S. Expl. John Fors\ + \[*]Nurse: Expl. Antony Laffer\ + \[/list]
            \ + Engineering dept.
            \ + \[list]\ + \[*]Engineer: Expl. Ronda Atkins\ + \[*]Engineer: Expl. Peter Napp\ + \[/list]
            \ + Security dept.
            \ + \[list]\ + \[*]SO: S. Expl. Nuri Batyam\ + \[*]SO: Expl. Benjamin Tho\ + \[*]SO: Expl. Tetha-12-Alpha\ + \[/list]
            \ + Exploration team.
            \ + \[list]\ + \[*]Ch. Expl. Alex Warda\ + \[*]S. Expl. William Lions\ + \[*]Expl. Hope Bafflow\ + \[*]Expl. Yuri Meadows\ + \[*]Dr. Tetha-12-Beta\ + \[list]" + +/obj/item/toy/ship_model + name = "table-top SEV Icarus model" + desc = "A small model of a spaceship mounted on a wooden stand. On the stand is engraved: \"SEV Icarus 1:278th scale\". The small lights on the hull and the engine exhaust still light up and blink." + icon = 'maps/away/icarus/icarus_sprites.dmi' + icon_state = "model" + +//to pass tests and make vesrion not depending on Torch code. Sol gov floor decal had to go though :( +/obj/structure/sign/icarus/solgov + name = "\improper SolGov Seal" + desc = "A familiar seal showing this vessel is SolGov property." + icon = 'maps/away/icarus/icarus_sprites.dmi' + icon_state = "solgovseal" + +/obj/item/clothing/under/icarus/ec_uniform + name = "expeditionary uniform" + desc = "An older model of the utility uniform of the SCG Expeditionary Corps. It has a patch on the left sleeve signifying the wearer served on the SEV Icarus." + icon_state = "blackutility_crew" + worn_state = "blackutility_crew" + icon = 'maps/away/icarus/icarus_sprites.dmi' + item_icons = list(slot_w_uniform_str = 'maps/away/icarus/icarus_sprites.dmi') + +/obj/structure/sign/double/icarus/solgovflag + name = "Sol Central Government Flag" + desc = "The iconic flag of the Sol Central Government, a symbol with many different meanings." + icon = 'maps/away/icarus/icarus_sprites.dmi' + +/obj/structure/sign/double/icarus/solgovflag/left + icon_state = "solgovflag-left" + +/obj/structure/sign/double/icarus/solgovflag/right + icon_state = "solgovflag-right" \ No newline at end of file diff --git a/maps/away/icarus/icarus_areas.dm b/maps/away/icarus/icarus_areas.dm new file mode 100644 index 00000000..ffb6b011 --- /dev/null +++ b/maps/away/icarus/icarus_areas.dm @@ -0,0 +1,11 @@ +/area/icarus + icon = 'maps/away/icarus/icarus_sprites.dmi' + +/area/icarus/vessel + name = "SEV Icarus" + icon_state = "vessel_area" + +/area/icarus/open + name = "SEV Icarus surroundings" + icon_state = "open_area" + dynamic_lighting = 0 diff --git a/maps/away/icarus/icarus_sprites.dmi b/maps/away/icarus/icarus_sprites.dmi new file mode 100644 index 00000000..ddec33db Binary files /dev/null and b/maps/away/icarus/icarus_sprites.dmi differ diff --git a/maps/away/lost_supply_base/lost_supply_base.dm b/maps/away/lost_supply_base/lost_supply_base.dm new file mode 100644 index 00000000..478d5306 --- /dev/null +++ b/maps/away/lost_supply_base/lost_supply_base.dm @@ -0,0 +1,38 @@ +#include "lost_supply_base_areas.dm" +#include "../mining/mining_areas.dm" + +/obj/effect/overmap/sector/lost_supply_base + name = "supply station" + desc = "This looks like abandoned and heavy damaged supply station." + icon_state = "object" + known = 0 + + generic_waypoints = list( + "nav_lost_supply_base_1", + "nav_lost_supply_base_2", + "nav_lost_supply_base_3", + "nav_lost_supply_base_antag" + ) + +/datum/map_template/ruin/away_site/lost_supply_base + name = "Lost Supply Base" + id = "awaysite_lost_supply_base" + description = "An abandoned supply base." + suffixes = list("lost_supply_base/lost_supply_base.dmm") + cost = 1 + +/obj/effect/shuttle_landmark/nav_lost_supply_base/nav1 + name = "Abandoned Supply Base Navpoint #1" + landmark_tag = "nav_lost_supply_base_1" + +/obj/effect/shuttle_landmark/nav_lost_supply_base/nav2 + name = "Abandoned Supply Base Navpoint #2" + landmark_tag = "nav_lost_supply_base_2" + +/obj/effect/shuttle_landmark/nav_lost_supply_base/nav3 + name = "Abandoned Supply Base Navpoint #3" + landmark_tag = "nav_lost_supply_base_3" + +/obj/effect/shuttle_landmark/nav_lost_supply_base/navantag + name = "Abandoned Supply Base Navpoint #4" + landmark_tag = "nav_lost_supply_base_antag" \ No newline at end of file diff --git a/maps/away/lost_supply_base/lost_supply_base.dmm b/maps/away/lost_supply_base/lost_supply_base.dmm new file mode 100644 index 00000000..2e3242df --- /dev/null +++ b/maps/away/lost_supply_base/lost_supply_base.dmm @@ -0,0 +1,436 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/obj/structure/lattice,/obj/structure/grille,/turf/space,/area/space) +"ac" = (/obj/structure/lattice,/turf/space,/area/space) +"ad" = (/obj/machinery/power/tracker,/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/airless,/area/space) +"ae" = (/obj/effect/shuttle_landmark/nav_lost_supply_base/nav3,/turf/space,/area/space) +"af" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/space) +"ag" = (/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/power/solar{id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"ah" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/item/stack/material/steel,/turf/simulated/floor/airless,/area/space) +"ai" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless,/area/space) +"aj" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"ak" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"al" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless,/area/space) +"am" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"an" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/space) +"ao" = (/obj/structure/cable/yellow,/obj/machinery/power/solar{id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"ap" = (/turf/simulated/floor/airless,/area/space) +"aq" = (/obj/item/stack/rods,/turf/space,/area/space) +"ar" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/item/stack/rods{amount = 50},/obj/item/stack/material/steel,/turf/simulated/floor/airless,/area/space) +"as" = (/obj/machinery/power/solar{id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"at" = (/obj/effect/shuttle_landmark/nav_lost_supply_base/nav1,/turf/space,/area/space) +"au" = (/obj/machinery/power/solar{id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array"},/obj/structure/cable/yellow,/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"av" = (/obj/structure/girder/displaced,/turf/space,/area/space) +"aw" = (/obj/structure/lattice,/obj/structure/grille,/obj/structure/grille,/turf/simulated/floor/airless,/area/space) +"ax" = (/turf/simulated/wall/r_wall,/area/lost_supply_base/solar) +"ay" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "solar_outer"; locked = 1; name = "Solar External Access"; req_access = list(11,13)},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/shield_diffuser,/turf/simulated/floor/plating,/area/lost_supply_base/solar) +"az" = (/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1379; id_tag = "solar_starboard_airlock"; pixel_x = 24; req_access = list(13); tag_airpump = "solar_starboard_pump"; tag_chamber_sensor = "solar_starboard_sensor"; tag_exterior_door = "solar_starboard_outer"; tag_interior_door = "solar_starboard_inner"},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 2; frequency = 1379; id_tag = "solar_starboard_pump"},/obj/machinery/airlock_sensor{frequency = 1379; id_tag = "solar_starboard_sensor"; pixel_x = 24; pixel_y = 12},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning/full,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/lost_supply_base/solar) +"aA" = (/turf/simulated/wall/r_wall,/area/lost_supply_base) +"aB" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "solar_inner"; locked = 1; name = "Solar Access"; req_access = list(11,13)},/obj/machinery/atmospherics/pipe/simple/hidden,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/lost_supply_base/solar) +"aC" = (/turf/simulated/wall/r_wall,/area/lost_supply_base/office) +"aD" = (/turf/space,/area/lost_supply_base) +"aE" = (/obj/structure/lattice,/turf/space,/area/lost_supply_base) +"aF" = (/obj/machinery/portable_atmospherics/canister/air,/obj/machinery/atmospherics/portables_connector,/turf/simulated/floor/airless,/area/lost_supply_base) +"aG" = (/turf/simulated/floor/airless,/area/lost_supply_base) +"aH" = (/obj/machinery/light_construct{dir = 1},/turf/simulated/floor/airless,/area/lost_supply_base) +"aI" = (/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/airless,/area/lost_supply_base) +"aJ" = (/obj/structure/table/rack,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/toolbox,/turf/simulated/floor/airless,/area/lost_supply_base) +"aK" = (/turf/simulated/wall,/area/lost_supply_base/solar) +"aL" = (/obj/machinery/power/solar_control{id = "suuplybasesolar"; name = "Solar Control"; track = 0},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/effect/floor_decal/industrial/warning/corner{dir = 4},/turf/simulated/floor/plating,/area/lost_supply_base/solar) +"aM" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden{dir = 8; icon_state = "map"},/obj/machinery/access_button{command = "cycle_interior"; frequency = 1379; master_tag = "solar_starboard_airlock"; name = "interior access button"; pixel_x = 24; pixel_y = 24; req_access = list(11,13)},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/lost_supply_base/solar) +"aN" = (/obj/machinery/portable_atmospherics/canister/air/airlock,/obj/machinery/atmospherics/portables_connector{dir = 8},/obj/effect/floor_decal/industrial/warning/corner{dir = 1},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/plating,/area/lost_supply_base/solar) +"aO" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"aP" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"aQ" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/wall/r_wall,/area/lost_supply_base/office) +"aR" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/item/weapon/paper,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"aS" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"aT" = (/obj/structure/bed/chair/comfy/captain,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"aU" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"aV" = (/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"aW" = (/obj/item/weapon/paper,/obj/structure/safe,/obj/random/drinkbottle,/obj/random/handgun,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"aX" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 4; external_pressure_bound = 0; external_pressure_bound_default = 0; frequency = 1441; icon_state = "map_vent_in"; id_tag = "n2_out"; initialize_directions = 1; internal_pressure_bound = 4000; internal_pressure_bound_default = 4000; pressure_checks = 2; pressure_checks_default = 2; pump_direction = 0; use_power = 1},/turf/simulated/floor/airless,/area/lost_supply_base) +"aY" = (/obj/machinery/atmospherics/binary/pump/on{dir = 8; target_pressure = 200},/turf/simulated/floor/airless,/area/lost_supply_base) +"aZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/cyan{dir = 4; icon_state = "intact"},/turf/simulated/wall/r_wall,/area/lost_supply_base) +"ba" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/cyan{dir = 9; icon_state = "intact"},/turf/simulated/floor/airless,/area/lost_supply_base) +"bb" = (/obj/effect/floor_decal/industrial/warning{ icon_state = "warning"; dir = 5},/turf/simulated/floor/airless,/area/lost_supply_base) +"bc" = (/obj/random/projectile,/obj/effect/landmark/corpse/syndicate,/turf/simulated/floor/airless,/area/lost_supply_base) +"bd" = (/obj/random/trash,/turf/simulated/floor/airless,/area/lost_supply_base) +"be" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/lost_supply_base) +"bf" = (/obj/structure/closet/crate/solar,/turf/simulated/floor/plating,/area/lost_supply_base/solar) +"bg" = (/obj/machinery/atmospherics/binary/pump/on{dir = 1; target_pressure = 200},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/lost_supply_base/solar) +"bh" = (/obj/machinery/power/terminal,/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/lost_supply_base/solar) +"bi" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"bj" = (/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"bk" = (/obj/structure/table/steel_reinforced,/obj/random/handgun,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"bl" = (/obj/structure/table/steel_reinforced,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"bm" = (/obj/item/stack/tile/floor_dark{pixel_x = 5; pixel_y = -3},/obj/item/stack/material/steel,/turf/simulated/floor/tiled/airless{ icon_state = "steel_burned0"},/area/lost_supply_base/office) +"bn" = (/turf/simulated/floor/tiled/airless{ icon_state = "steel_burned0"},/area/lost_supply_base/office) +"bo" = (/obj/item/stack/tile/floor_dark{pixel_x = 5; pixel_y = -3},/turf/space,/area/space) +"bp" = (/obj/effect/overmap/sector/lost_supply_base,/turf/space,/area/space) +"bq" = (/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/airless,/area/lost_supply_base) +"br" = (/obj/machinery/door/airlock/external{frequency = 1380; glass = 1380; icon_state = "door_locked"; id_tag = "centcom_shuttle_bay_door"; locked = 1; name = "Transport Airlock"},/turf/simulated/floor/airless,/area/lost_supply_base) +"bs" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/access_button{command = "cycle_interior"; frequency = 1379; master_tag = "solar_starboard_airlock"; name = "interior access button"; pixel_x = -24; pixel_y = 24; req_access = list(11,13)},/turf/simulated/floor/airless,/area/lost_supply_base) +"bt" = (/turf/simulated/floor/tiled/airless{ icon_state = "steel_broken4"},/area/lost_supply_base) +"bu" = (/obj/effect/decal/cleanable/blood,/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/airless,/area/lost_supply_base) +"bv" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/airless,/area/lost_supply_base) +"bw" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless,/area/lost_supply_base) +"bx" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/lost_supply_base) +"by" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/table/rack,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/tech_supply,/turf/simulated/floor/airless,/area/lost_supply_base) +"bz" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/wall,/area/lost_supply_base/solar) +"bA" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/turf/simulated/floor/plating,/area/lost_supply_base/solar) +"bB" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal,/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating,/area/lost_supply_base/solar) +"bC" = (/obj/machinery/power/smes/buildable{charge = 0; input_level = 5000; input_level_max = 20000; RCon_tag = "Supply base MAIN"},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/lost_supply_base/solar) +"bD" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"bE" = (/obj/item/weapon/pen/red,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"bF" = (/obj/effect/landmark/corpse/engineer,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"bG" = (/turf/simulated/floor/tiled/airless{ icon_state = "steel_broken4"},/area/lost_supply_base/office) +"bH" = (/turf/simulated/floor/tiled/airless{ icon_state = "steel_broken1"},/area/lost_supply_base/office) +"bI" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/turf/simulated/wall/r_wall,/area/lost_supply_base/office) +"bJ" = (/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1379; id_tag = "solar_starboard_airlock"; pixel_x = 24; req_access = list(13); tag_airpump = "solar_starboard_pump"; tag_chamber_sensor = "solar_starboard_sensor"; tag_exterior_door = "solar_starboard_outer"; tag_interior_door = "solar_starboard_inner"},/obj/machinery/airlock_sensor{frequency = 1379; id_tag = "solar_starboard_sensor"; pixel_x = 24; pixel_y = 12},/turf/simulated/floor/airless,/area/lost_supply_base) +"bK" = (/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/airless,/area/lost_supply_base) +"bL" = (/obj/effect/floor_decal/industrial/warning{ icon_state = "warning"; dir = 6},/turf/simulated/floor/airless,/area/lost_supply_base) +"bM" = (/obj/structure/table/rack,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/tech_supply,/obj/item/device/radio,/turf/simulated/floor/airless,/area/lost_supply_base) +"bN" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/lost_supply_base/solar) +"bO" = (/obj/random/ammo,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"bP" = (/obj/structure/girder/displaced,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"bQ" = (/turf/space,/area/lost_supply_base/office) +"bR" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/turf/simulated/wall/r_wall,/area/lost_supply_base) +"bS" = (/obj/random/trash,/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/airless,/area/lost_supply_base) +"bT" = (/obj/item/stack/tile/floor_dark{pixel_x = 5; pixel_y = -3},/turf/simulated/floor/airless,/area/lost_supply_base) +"bU" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/lost_supply_base) +"bV" = (/turf/simulated/wall,/area/lost_supply_base) +"bW" = (/turf/simulated/floor/tiled/airless{ icon_state = "steel_broken1"},/area/lost_supply_base) +"bX" = (/obj/machinery/door/airlock{name = "Control room"},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"bY" = (/obj/machinery/atmospherics/unary/vent_scrubber,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"bZ" = (/obj/machinery/light,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"ca" = (/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/office) +"cb" = (/turf/simulated/floor/tiled/airless{ icon_state = "steel_broken0"},/area/lost_supply_base/office) +"cc" = (/obj/item/stack/material/steel,/turf/space,/area/space) +"cd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless,/area/lost_supply_base) +"ce" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/airless,/area/lost_supply_base) +"cf" = (/obj/item/stack/rods,/obj/item/stack/material/steel,/turf/simulated/floor/airless,/area/lost_supply_base) +"cg" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled/airless{ icon_state = "steel_broken4"},/area/lost_supply_base) +"ch" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"ci" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall/r_wall,/area/lost_supply_base/common) +"cj" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/wall/r_wall,/area/lost_supply_base/common) +"ck" = (/turf/simulated/wall/r_wall,/area/lost_supply_base/common) +"cl" = (/obj/effect/floor_decal/industrial/warning{ icon_state = "warning"; dir = 1},/turf/simulated/floor/airless,/area/lost_supply_base) +"cm" = (/obj/random/trash,/turf/simulated/floor/tiled/airless{ icon_state = "steel_broken1"},/area/lost_supply_base) +"cn" = (/obj/effect/floor_decal/industrial/warning{ icon_state = "warning"; dir = 5},/obj/random/trash,/turf/simulated/floor/airless,/area/lost_supply_base) +"co" = (/obj/effect/decal/cleanable/blood/gibs/body,/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/airless,/area/lost_supply_base) +"cp" = (/obj/structure/door_assembly,/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/airless,/area/lost_supply_base) +"cq" = (/obj/machinery/atmospherics/omni/mixer{tag_east = 1; tag_east_con = 0.5; tag_south = 1; tag_south_con = 0.5; tag_west = 2; use_power = 0},/turf/simulated/floor/airless,/area/lost_supply_base) +"cr" = (/obj/structure/cable,/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/lost_supply_base) +"cs" = (/obj/item/stack/tile/floor_dark{pixel_x = 5; pixel_y = -3},/obj/item/stack/tile/floor_dark{pixel_x = 5; pixel_y = -3},/turf/simulated/floor/airless,/area/lost_supply_base) +"ct" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"cu" = (/obj/item/stack/tile/floor_dark{pixel_x = 5; pixel_y = -3},/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"cv" = (/turf/simulated/wall,/area/lost_supply_base/common) +"cw" = (/obj/machinery/food_replicator,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"cx" = (/obj/structure/table/standard,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/light{dir = 1},/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"cy" = (/obj/machinery/gibber,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"cz" = (/obj/structure/closet/secure_closet/freezer/meat,/obj/machinery/cooker/oven,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"cA" = (/obj/structure/closet/secure_closet/freezer/meat,/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled/airless{ icon_state = "steel_burned1"},/area/lost_supply_base/common) +"cB" = (/obj/structure/closet/secure_closet/freezer/meat,/obj/structure/closet/secure_closet/freezer/meat,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"cC" = (/obj/structure/closet/crate/freezer,/turf/simulated/floor/airless,/area/lost_supply_base) +"cD" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/airless,/area/lost_supply_base) +"cE" = (/obj/item/stack/material/cardboard,/turf/simulated/floor/airless,/area/lost_supply_base) +"cF" = (/obj/item/device/price_scanner,/turf/simulated/floor/airless,/area/lost_supply_base) +"cG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/airless,/area/lost_supply_base) +"cH" = (/obj/machinery/portable_atmospherics/canister/carbon_dioxide,/turf/simulated/floor/airless,/area/lost_supply_base) +"cI" = (/turf/simulated/floor/tiled/airless{ icon_state = "steel_broken0"},/area/lost_supply_base) +"cJ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless{ icon_state = "steel_burned1"},/area/lost_supply_base) +"cK" = (/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"cL" = (/turf/simulated/floor/tiled/airless{ icon_state = "steel_burned1"},/area/lost_supply_base/common) +"cM" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/turf/space,/area/lost_supply_base/common) +"cN" = (/obj/machinery/light_construct{dir = 8},/turf/simulated/floor/airless,/area/lost_supply_base) +"cO" = (/obj/structure/closet/crate/freezer/rations,/turf/simulated/floor/airless,/area/lost_supply_base) +"cP" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/airless,/area/lost_supply_base) +"cQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/wall,/area/lost_supply_base) +"cR" = (/obj/machinery/light_construct{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless,/area/lost_supply_base) +"cS" = (/obj/machinery/portable_atmospherics/canister/oxygen,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/airless,/area/lost_supply_base) +"cT" = (/obj/structure/girder/displaced,/turf/space,/area/lost_supply_base) +"cU" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless{ icon_state = "steel_burned0"},/area/lost_supply_base) +"cV" = (/obj/random/junk,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"cW" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/turf/simulated/wall/r_wall,/area/lost_supply_base/common) +"cX" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/airless,/area/lost_supply_base) +"cY" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless,/area/lost_supply_base) +"cZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall,/area/lost_supply_base) +"da" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"db" = (/obj/machinery/door/window/southleft,/turf/simulated/floor/tiled/airless{ icon_state = "steel_burned1"},/area/lost_supply_base/common) +"dc" = (/obj/structure/table/standard,/obj/item/trash/tray{pixel_x = 10},/obj/item/trash/tray,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"dd" = (/obj/structure/table/standard,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"de" = (/obj/structure/table/standard,/obj/item/weapon/material/kitchen/utensil/fork,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"df" = (/obj/structure/table/standard,/obj/machinery/microwave,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"dg" = (/obj/structure/closet/crate/secure/phoron{name = "mineral crate"; req_access = list(19)},/turf/simulated/floor/airless,/area/lost_supply_base) +"dh" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/structure/closet/crate/secure/phoron{name = "mineral crate"; req_access = list(19)},/turf/simulated/floor/airless,/area/lost_supply_base) +"di" = (/obj/random/junk,/turf/simulated/floor/airless,/area/lost_supply_base) +"dj" = (/obj/random/ammo,/turf/simulated/floor/airless,/area/lost_supply_base) +"dk" = (/obj/effect/decal/mecha_wreckage/ripley,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/airless,/area/lost_supply_base) +"dl" = (/obj/machinery/light_construct,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless,/area/lost_supply_base) +"dm" = (/obj/item/stack/material/steel,/turf/simulated/floor/airless,/area/lost_supply_base) +"dn" = (/obj/structure/closet/firecloset/full,/turf/simulated/floor/airless,/area/lost_supply_base) +"do" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"dp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/airless{ icon_state = "steel_burned1"},/area/lost_supply_base) +"dq" = (/obj/machinery/door/airlock{name = "Cantina"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"dr" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"ds" = (/obj/structure/closet/crate/secure/gear,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/airless,/area/lost_supply_base) +"dt" = (/obj/effect/floor_decal/industrial/warning,/obj/structure/closet/crate/hydroponics,/turf/simulated/floor/airless,/area/lost_supply_base) +"du" = (/obj/effect/floor_decal/industrial/warning{ icon_state = "warning"; dir = 6},/obj/item/weapon/storage/backpack/dufflebag,/turf/simulated/floor/airless,/area/lost_supply_base) +"dv" = (/obj/effect/decal/cleanable/blood/drip,/obj/effect/decal/cleanable/blood/writing,/turf/simulated/floor/airless,/area/lost_supply_base) +"dw" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/wall,/area/lost_supply_base) +"dx" = (/obj/item/weapon/material/kitchen/utensil/spoon,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"dy" = (/obj/structure/bed/chair{dir = 4},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"dz" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/trash/plate,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"dA" = (/obj/structure/table/standard{name = "plastic table frame"},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"dB" = (/obj/item/weapon/material/kitchen/utensil/fork,/obj/structure/bed/chair{ icon_state = "chair_preview"; dir = 8},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"dC" = (/obj/random/trash,/obj/machinery/light{ icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"dE" = (/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "centcom_shuttle_hatch"; locked = 1; name = "Shuttle Hatch"; req_access = list(13)},/turf/simulated/floor/shuttle/blue,/area/space) +"dF" = (/turf/simulated/shuttle/wall{dir = 4; icon_state = "swall"},/area/space) +"dG" = (/turf/simulated/shuttle/wall{icon_state = "swall_t"; dir = 1},/area/space) +"dH" = (/turf/simulated/shuttle/wall{icon_state = "swall_straight"; dir = 4},/area/space) +"dI" = (/turf/simulated/shuttle/wall{icon_state = "swall_s"; dir = 2},/area/space) +"dJ" = (/obj/random/junk,/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/airless,/area/lost_supply_base) +"dK" = (/obj/machinery/atmospherics/pipe/tank/oxygen,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless,/area/lost_supply_base) +"dL" = (/obj/machinery/atmospherics/pipe/tank/oxygen,/turf/simulated/floor/airless,/area/lost_supply_base) +"dM" = (/obj/machinery/atmospherics/pipe/tank/air,/turf/simulated/floor/airless,/area/lost_supply_base) +"dN" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"dO" = (/turf/simulated/floor/tiled/airless{ icon_state = "steel_burned0"},/area/lost_supply_base) +"dP" = (/turf/simulated/floor/tiled/airless{ icon_state = "steel_burned0"},/area/lost_supply_base/common) +"dQ" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/turf/space,/area/lost_supply_base/common) +"dR" = (/turf/simulated/shuttle/wall{icon_state = "swall_straight"; dir = 1},/area/space) +"dS" = (/turf/simulated/floor/shuttle/blue,/area/space) +"dT" = (/obj/structure/bed/chair,/obj/random/handgun,/turf/simulated/floor/shuttle/blue,/area/space) +"dU" = (/obj/structure/bed/chair,/turf/simulated/floor/shuttle/blue,/area/space) +"dV" = (/obj/structure/bed/chair,/obj/random/smokes,/turf/simulated/floor/shuttle/blue,/area/space) +"dW" = (/turf/simulated/shuttle/wall{dir = 1; icon_state = "swall_f"},/area/space) +"dX" = (/obj/structure/window/reinforced{dir = 1; health = 1e+006},/turf/simulated/floor/airless,/area/lost_supply_base) +"dY" = (/obj/item/stack/tile/floor_dark,/obj/structure/window/reinforced{dir = 1; health = 1e+006},/turf/simulated/floor/airless,/area/lost_supply_base) +"dZ" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/airless,/area/lost_supply_base) +"ea" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless,/area/lost_supply_base) +"eb" = (/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/airless,/area/lost_supply_base) +"ec" = (/obj/random/tank,/obj/machinery/atmospherics/portables_connector{dir = 1},/turf/simulated/floor/airless,/area/lost_supply_base) +"ed" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/turf/simulated/floor/airless,/area/lost_supply_base) +"ee" = (/obj/random/trash,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"ef" = (/obj/structure/bed/chair{ icon_state = "chair_preview"; dir = 8},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"eg" = (/obj/structure/shuttle/engine/propulsion{ icon_state = "propulsion_r"; dir = 8},/turf/space,/area/space) +"eh" = (/obj/structure/shuttle/engine/heater{icon_state = "heater"; dir = 8},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/shuttle/blue,/area/space) +"ei" = (/turf/simulated/shuttle/wall{icon_state = "swall"; dir = 1},/area/space) +"ej" = (/obj/item/modular_computer/console,/turf/simulated/floor/shuttle/blue,/area/space) +"ek" = (/obj/structure/grille,/obj/structure/window/reinforced/full,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plating,/area/space) +"el" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/airless,/area/lost_supply_base) +"em" = (/obj/effect/decal/cleanable/blood/splatter,/obj/effect/landmark/corpse/engineer,/turf/simulated/floor/airless,/area/lost_supply_base) +"en" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless,/area/lost_supply_base) +"eo" = (/obj/random/tool,/turf/simulated/floor/airless,/area/lost_supply_base) +"ep" = (/obj/random/tank,/turf/simulated/floor/airless,/area/lost_supply_base) +"eq" = (/obj/structure/closet/medical_wall{pixel_x = -30},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"er" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/weapon/flame/lighter,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"es" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"et" = (/obj/machinery/light{ icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled/airless{ icon_state = "steel_burned0"},/area/lost_supply_base/common) +"eu" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/turf/space,/area/lost_supply_base/common) +"ev" = (/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/shuttle/blue,/area/space) +"ew" = (/obj/machinery/door/unpowered/shuttle,/turf/simulated/floor/shuttle/blue,/area/space) +"ex" = (/obj/structure/bed/chair{dir = 4},/obj/item/key,/turf/simulated/floor/shuttle/blue,/area/space) +"ey" = (/obj/item/stack/material/cardboard,/obj/item/weapon/grenade/fake,/turf/simulated/floor/airless,/area/lost_supply_base) +"ez" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/airless,/area/lost_supply_base) +"eA" = (/turf/simulated/floor/tiled/airless{ icon_state = "steel_broken4"},/area/lost_supply_base/common) +"eB" = (/turf/simulated/shuttle/wall{dir = 2; icon_state = "swall"},/area/space) +"eC" = (/obj/machinery/atmospherics/pipe/tank/phoron{dir = 2; volume = 3200},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless,/area/lost_supply_base) +"eD" = (/obj/machinery/atmospherics/pipe/tank/phoron{dir = 2; volume = 3200},/turf/simulated/floor/airless,/area/lost_supply_base) +"eE" = (/obj/item/weapon/bedsheet,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"eF" = (/obj/machinery/atmospherics/unary/vent_scrubber,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"eG" = (/obj/machinery/light,/obj/structure/reagent_dispensers/water_cooler,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"eH" = (/obj/machinery/computer/arcade,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"eI" = (/obj/machinery/light,/obj/machinery/computer/arcade,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"eJ" = (/obj/machinery/media/jukebox,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"eK" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/shuttle/blue,/area/space) +"eL" = (/obj/structure/table/rack,/obj/item/weapon/tank/air,/obj/random/tech_supply,/obj/item/clothing/mask/breath,/turf/simulated/floor/shuttle/blue,/area/space) +"eM" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/shuttle/blue,/area/space) +"eN" = (/obj/structure/bed/chair{dir = 1},/obj/random/voidhelmet,/turf/simulated/floor/shuttle/blue,/area/space) +"eO" = (/turf/simulated/shuttle/wall{icon_state = "swall_f"; dir = 4},/area/space) +"eP" = (/turf/simulated/shuttle/wall{icon_state = "swall_s"; dir = 8},/area/space) +"eQ" = (/obj/machinery/portable_atmospherics/canister/phoron,/turf/simulated/floor/airless,/area/lost_supply_base) +"eR" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/portable_atmospherics/canister/phoron,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless,/area/lost_supply_base) +"eS" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/canister/phoron,/turf/simulated/floor/airless,/area/lost_supply_base) +"eT" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"eU" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall,/area/lost_supply_base/common) +"eV" = (/obj/machinery/door/airlock{name = "Cantina"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/common) +"eW" = (/turf/simulated/shuttle/wall{dir = 5; icon_state = "swall"},/area/space) +"eX" = (/turf/simulated/shuttle/wall{icon_state = "swall_t"; dir = 2},/area/space) +"eY" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/airless,/area/lost_supply_base) +"eZ" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/airless,/area/lost_supply_base) +"fa" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/airless,/area/lost_supply_base) +"fb" = (/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/tiled/airless{ icon_state = "steel_broken0"},/area/lost_supply_base) +"fc" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/random/obstruction,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"fd" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/random/obstruction,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"fe" = (/obj/machinery/door/airlock{name = "Bunk room"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"ff" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"fg" = (/obj/structure/closet/emcloset,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"fh" = (/obj/structure/bed,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"fi" = (/obj/structure/closet,/obj/random/clothing,/obj/item/trash/liquidfood,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"fj" = (/obj/structure/bed,/obj/random/plushie,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"fk" = (/obj/structure/closet,/obj/random/clothing,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"fl" = (/turf/simulated/wall/r_wall,/area/lost_supply_base/supply) +"fm" = (/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/airless,/area/lost_supply_base) +"fn" = (/obj/effect/floor_decal/industrial/warning{ icon_state = "warning"; dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless,/area/lost_supply_base) +"fo" = (/obj/random/junk,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"fp" = (/turf/simulated/wall,/area/lost_supply_base/supply) +"fq" = (/obj/item/weapon/bedsheet,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"fr" = (/turf/simulated/floor/tiled/airless{ icon_state = "steel_burned0"},/area/lost_supply_base/supply) +"fs" = (/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"ft" = (/obj/structure/table/standard,/obj/random/smokes,/obj/item/device/radio,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"fu" = (/obj/effect/shuttle_landmark/nav_lost_supply_base/nav2,/turf/space,/area/space) +"fv" = (/obj/structure/window/reinforced,/obj/machinery/portable_atmospherics/canister/carbon_dioxide,/turf/simulated/floor/airless,/area/lost_supply_base) +"fw" = (/obj/structure/window/reinforced,/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/airless,/area/lost_supply_base) +"fx" = (/obj/machinery/atmospherics/unary/vent_scrubber{ icon_state = "map_scrubber_off"; dir = 1},/turf/simulated/floor/airless,/area/lost_supply_base) +"fy" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"fz" = (/obj/random/junk,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"fA" = (/obj/structure/table/standard,/obj/item/weapon/storage/briefcase,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"fB" = (/obj/structure/sign/warning{pixel_x = -30},/obj/machinery/portable_atmospherics/canister/air,/obj/machinery/atmospherics/portables_connector,/turf/simulated/floor/airless,/area/lost_supply_base) +"fC" = (/obj/random/energy,/obj/effect/landmark/corpse/syndicate,/turf/simulated/floor/airless,/area/lost_supply_base) +"fD" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/effect/landmark/corpse/engineer,/turf/simulated/floor/airless,/area/lost_supply_base) +"fE" = (/obj/machinery/atmospherics/unary/vent_scrubber,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"fF" = (/obj/machinery/light,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"fG" = (/obj/machinery/light,/obj/structure/bed,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"fH" = (/obj/structure/largecrate,/obj/machinery/atmospherics/binary/pump/on{dir = 8; target_pressure = 200},/turf/simulated/floor/airless,/area/lost_supply_base) +"fI" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/airless,/area/lost_supply_base) +"fJ" = (/obj/item/weapon/material/twohanded/fireaxe,/obj/effect/decal/cleanable/blood,/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/airless,/area/lost_supply_base) +"fK" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/effect/decal/cleanable/blood,/obj/item/stack/tile/floor_dark{pixel_x = 5; pixel_y = -3},/turf/simulated/floor/airless,/area/lost_supply_base) +"fL" = (/obj/effect/decal/cleanable/blood/writing{dir = 4},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/airless,/area/lost_supply_base) +"fM" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled/airless{ icon_state = "steel_burned1"},/area/lost_supply_base) +"fN" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/item/stack/material/steel,/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"fO" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall,/area/lost_supply_base/supply) +"fP" = (/obj/machinery/door/airlock{name = "Head"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/space,/area/lost_supply_base/supply) +"fQ" = (/obj/structure/door_assembly,/turf/simulated/floor/airless,/area/lost_supply_base) +"fR" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/airless,/area/lost_supply_base) +"fS" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/item/stack/tile/floor_dark{pixel_x = 5; pixel_y = -3},/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"fT" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/wall,/area/lost_supply_base/supply) +"fU" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/airless{ icon_state = "steel_broken0"},/area/lost_supply_base/supply) +"fV" = (/turf/simulated/floor/tiled/airless{ icon_state = "steel_burned1"},/area/lost_supply_base/supply) +"fW" = (/turf/simulated/floor/tiled/airless{ icon_state = "steel_broken0"},/area/lost_supply_base/supply) +"fX" = (/obj/item/weapon/gun/projectile/shotgun/pump,/obj/effect/landmark/corpse/syndicate,/turf/simulated/floor/tiled/airless{ icon_state = "steel_broken4"},/area/lost_supply_base/supply) +"fY" = (/obj/machinery/atmospherics/portables_connector{dir = 4},/turf/simulated/floor/airless,/area/lost_supply_base) +"fZ" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4; icon_state = "intact"},/turf/simulated/floor/airless,/area/lost_supply_base) +"ga" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4; icon_state = "intact"},/turf/simulated/wall/r_wall,/area/lost_supply_base) +"gb" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4; icon_state = "intact"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1379; id_tag = "solar_starboard_airlock"; pixel_x = 24; req_access = list(13); tag_airpump = "solar_starboard_pump"; tag_chamber_sensor = "solar_starboard_sensor"; tag_exterior_door = "solar_starboard_outer"; tag_interior_door = "solar_starboard_inner"},/obj/machinery/airlock_sensor{frequency = 1379; id_tag = "solar_starboard_sensor"; pixel_x = 24; pixel_y = 12},/turf/simulated/floor/airless,/area/lost_supply_base) +"gc" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/binary/pump/on{dir = 8; target_pressure = 200},/turf/simulated/floor/airless,/area/lost_supply_base) +"gd" = (/obj/effect/floor_decal/industrial/warning{ icon_state = "warning"; dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4; icon_state = "intact"},/turf/simulated/floor/airless,/area/lost_supply_base) +"ge" = (/obj/machinery/atmospherics/portables_connector{dir = 8},/obj/effect/floor_decal/industrial/warning/full,/turf/simulated/floor/airless,/area/lost_supply_base) +"gf" = (/obj/structure/closet/emcloset,/turf/simulated/floor/airless,/area/lost_supply_base) +"gg" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"gh" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/item/stack/tile/floor_dark{pixel_x = 5; pixel_y = -3},/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"gi" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"gj" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"gk" = (/obj/machinery/door/airlock{name = "Head"},/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"gl" = (/obj/structure/lattice,/obj/structure/grille,/turf/space,/area/lost_supply_base) +"gm" = (/obj/machinery/light,/turf/simulated/floor/airless,/area/lost_supply_base) +"gn" = (/obj/structure/closet/crate/trashcart,/obj/item/weapon/mop,/obj/item/weapon/storage/box/lights/bulbs,/obj/machinery/atmospherics/unary/vent_pump{dir = 1; external_pressure_bound = 0; external_pressure_bound_default = 0; icon_state = "map_vent_in"; initialize_directions = 1; internal_pressure_bound = 4000; internal_pressure_bound_default = 4000; use_power = 1; pressure_checks = 2; pressure_checks_default = 2; pump_direction = 0},/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"go" = (/obj/item/stack/material/steel,/turf/simulated/floor/tiled/airless,/area/lost_supply_base) +"gp" = (/obj/structure/sink{icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2},/obj/structure/mirror{pixel_x = -32},/obj/machinery/light/small,/turf/simulated/floor/tiled/airless{ icon_state = "steel_broken0"},/area/lost_supply_base/supply) +"gq" = (/obj/structure/toilet{dir = 1},/obj/machinery/light/small,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"gr" = (/obj/machinery/shower{ icon_state = "shower"; dir = 8},/obj/random/soap,/obj/machinery/light/small,/turf/simulated/floor/tiled/airless,/area/lost_supply_base/supply) +"gs" = (/obj/effect/shuttle_landmark/nav_lost_supply_base/navantag,/turf/space,/area/space) +"gt" = (/turf/unsimulated/mask,/area/mine/unexplored) +"gu" = (/turf/simulated/floor/asteroid,/area/mine/explored) +"hb" = (/obj/effect/landmark/random_gen/asteroid{generation_height = 100; generation_width = 100},/turf/space,/area/space) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababacadaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacaaacacaaaaacacaaacacafacacaaaaacaaaaacacaaacacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacagagagagagagagagagagacahacagaaaaaaagagagagagagacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaiajajajajajajajajajakalakamamamaaamamamamamanaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaoaoaoaoaoaoaoaoaoaoacafacaoaoaoaaaaaoaoaoaoaoaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacacacacacacacacacacacafacacacacacaaacacacacacacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaagagagagagagagagagagapafapagagagagagaaagagagagaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaqaaaaaaabaaaiajajajajajajajajajakalakamamamamamaraaamamanaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaqaoaoaoaoaoaoaoaoaoaoaaaaapaoaoaoaoaoasaaaaaoaoaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacacacacacaaacaaaaaaacacacacacacacacacaaacacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaqaaagagagagagagagagagacafacagagagagagagagagaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaiajajajajajajajajajakalakamamamamamamamamamaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaoaoaoaoaoaoaoaoaoaoacafacauaoaoaoaoaoaoaoaoaoaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaqaaaaabaaaaaaaaaaaaaaaaaaaaacafacaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaavaaaaawaaaaaaaaaaaaaaaaaaaaaxayaxaaaaaaaaaaaaaaaaaaaaabaaaqaaaqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaqaaaaaqaaabaaaaaaaaaaaaaaaaaaaaaxazaxaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAaAaAaAaAaAaAaAaAaAaxaxaBaxaxaAaAaCaCaCaCaCaCaCaCaaaaaaaaaaaqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaqaaaaaDaEaEaAaAaFaGaGaGaHaGaIaGaJaKaLaMaNaKaOaPaQaRaSaTaUaVaWaCaaaaaaaaaqaqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDaDaXaYaZbabbaGbcbdaGbeaGaJaKbfbgbhaKbibjaCaVbkblblbmbnaCaaaqboaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaEaDbqbqbrbsbtbqbubqbvbwbxbybzbAbBbCaKbDbjaCbEbFaVbnbGbHbIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAaGaGbJaAbKbLaGaGaGbqaGaGbMaKaKbNaKaKbibjaCaVbObPbGbQbQbQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAaAbRaAaAaGaGaGaGaGbSaGbTaGaEaGbUaGbVbibWbXbYbZcabnbGcbaCaaaaaqccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAaGaGaGaGbdbqaXcdcebVaGbUcfbVcgchcicjckckckckckckaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAclcmcnaGaGbqcobqcpaGcqcrcsaEctcucvcwcxcyczcAcBckaaaqaaaaavaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAcCcCcDcEcFbqbTaGcGaEcHaGcIbVcJbjcvcKcKcKcLcKcKcMaaaaaaccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAcNcOcDaGaGbqaGbWcPcQcRcScTbVcUcucvcKcKcKcVcKcKcWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAcOcOcDbqbqbqaGaGcfcXaEaDcYcZdabjcvdbdcdddedddfckaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAaGdgdhdiaGbqaGdjdkdlaGdmdnbVdodpdqdrcKcKcKcKcKckaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAdsdtduaGaGbqdjdjdvdwbVaGbVbVcUbjcvdxdydzdAdBdCcMaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeBdEdFdGdHdHdHdHdIaaaaaaaaaAbWaGaGaGaGdJaGaGdvdKdLaGdMbVdNdOcvcKcLdAdPcKcKdQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadRdSdSdRdTdUdVdSdWdIaaaaaaaAdXdXdYdZaGbqaGaGdveaebecedbVcJbjcveecLcLdAefdPdQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaegehdSdSeidSdSdSdSejekaaaaaaaAeleleldZaGbqaGdjemeneoaGepbVdNbjcveqdyeresefeteuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaegehevdSewdSdSdSdSexekaaaaaaaAelelaGdZeybqaGaGezeneoaGaGbVcJbjcvcKcKeAcKcKeeckaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaegehdSdSeBdSdSdSdSejekaaaaaaaAaGelaGdZaGbqaGaGaGeCeDeDeDbVeEbjcveFeGeHeeeIeJckaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadReKeLdReMeNeMdSeOePaaaaaaaAaGaGeQdZaGbqaGaGaGeRededeSbVeTcheUeVcvcvcvcvcvckaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeWdHdHeXdHdHdHdHePaaaaaaaaaAeYaGeZfabqbvfbbqbqeneQaGaGbVfcfdfefffgfhfifjfkflaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAaGfmaGdZaGbqaGaGaGfnbKbKbKbVfobjfpfqfrfsfsfrftflaaaaaaaaaaaaaaaaaaaaaaaaaaaafuaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAfvfwfwdZaGbqaGdiaGfxaGaGdmbVfybjfpfsfsfrfzfsfAflaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDaDaAaAbRaAaAfBaGaGaGfCfDaGaGdmaGbTdmaGbVdNbtfpfEfFfhfkfGfkflaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDaDaAdiaXfHaZbabbaGaGfIfJfKfLfLbqbqbqbqaGfMfNfOfPfpfpfpfpfpflaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDaDbrbqbqbqfQbsfRbqbqbqbqaGaGbTaGaGaGaGbVaDfSfTfUfEfVfWfXfsflaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafYfZgafZfZgbgagcgdgeaGaGaGgfdmaGdmaGaGaGbVggghfOgigjfpgkfpgkflaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaglglaAaAbRaAaAaGaGeQgmaGaGaGaGaGaGgmaGaGbVgngofpgpfsfpgqfpgrflaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagsaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAflflflflflflflflaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgugugtaaaaaaaaaaaaaaaaaaaaaagtgtgtaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgugtaaaaaaaaaaaaaagtgtgtgtgtgtaaaaaagtaaaaaa +aaaaaaaaaaaaaaaaaaaaaagtgtaaaagtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagugugugugugtgtgugtgtgtgtaagtgtgtgtgtgtgtgtgtaaaagtaaaaaa +aaaaaaaaaaaaaaaaaaaaaagtgtaaaagtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagugugugtgtgtgugtgtgtgtgtgtgtgtgtgtgtgtgtaaaagtaaaaaa +aaaaaaaaaaaaaaaagugtgtgtgtgtaagtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtaaaaaa +aaaaaaaaaaaaaaaagugtgtgtgtgtgtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgugugtgtgtaagtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtaaaaaa +aaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaagtgtgtaaaagtgtgtgtgtgtgtgugugtgtgtaagtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtaaaaaagugugtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgugtgtgtgtgtaaaaaaaagtgtgugtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtguguaaaaaagtgtgtgtgtgtgtgtgtgtgtgtgtaagtaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtgtgtgtguaaaaaagtgtgtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtaaaaaaaaaagtgtgtgtgtgtgtgtgtgtgtgtgtaaaaaaaagtaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtgtgtgtgugtaagtgtgtgugugugtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaagtaaaaaaaaaagugtgtgtgtgtgtgtgtgtgtgtgtgtgtaaaagtaaaaaaaa +aaaaaaaaaaaaaaaaaaaagugtgtgtgtgtgtgtgtgtgtgtgtgtaaaaaaaaaagtaaaaaaaagugtgtgtgtgtgtgtgtgtgtgtaaaagugugugtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaguaaaaaagugtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgugtgtguaaaaaa +aaaaaaaaaaaaaaaaaaaagugtgtgtgtgtgtgtgtgtgtgtgtaaaaaaaaaaaagtguguaaaagtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtaaaaaagtaaaaaaaaaaaaaaaaaaaaaagugugugtgtgtgtgtgtgtgtguguguaaaaaaaaaaaagtgtgtgtgtaaaaaa +aaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtgtgtgtgtaaaaaaaaaaaagugtgtaaaagtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgugtgtgtaaaaaaaaaaaaaaaaaaaaaagtgtgugtgtaaaagtgtgtgtgtgugtaaaaaaaaaaaagtgtguguguaaaaaa +aaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtgtgtgtaaaaaaaaaaaaaagugugugugugtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaagtguguaaaagtgtgtgtgugtgtaaaaaaaaaaaagtgtgugugtaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtguaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaagtguguaaaaaaaagtgtgtgtgtaaaaaaaaaaaaaagtgugtaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtaaaaaaaaaaaaaaaaguaaaaaaaaaaaaaaaagugtgtgtguguguaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagugugtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgugtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtaaaaaaaaaaaaaaaaguaaaaaaaaaaaaaaaagugtgtgtguguguaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagugugtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgugugugtgtgtgtgtgtaaaaaaaaaaaaaaaagtgtaaaaaaaaaaaaaagtgtgtgtgtgugtaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaagugugugtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtaaaaaaaaaaaaaagtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgugtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagugtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtaaaaaaaaaaaaaagugtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtguaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtaaaaaaaaaaaaaagugtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtguaaaagugugtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtaaaaaaaaaaaaaagtgtgugtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtaaaagtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtaaaaaaaaaaaaaaaaaaaagugtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgugtgtgtgtgtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaagugugugtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtaaaaaaaaaaaaaagtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgugugugugugugtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtaagtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtguguguguguaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagugugugtgtgtaagugugtgtgtgtgtgtgtgtgtgtaagtgtgtgtgugugtgtgtgtgugtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagugugugtgtgtaagugugtgtgtgtgtgtgtgtgtaaaagtgtgugugugugtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagugtgtgtgtgtaagtgtgtgtgtgtgtgtgtgtgtaaaaaagtgtgugtgtgtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtgtgugtgtgtgtgtgtgtaaaaaaaaaaaaaagugtgtgtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgtgtgtgtgtgtgtaaaaaaaaaagugugugugugtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagugtgtgtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +hbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/lost_supply_base/lost_supply_base_areas.dm b/maps/away/lost_supply_base/lost_supply_base_areas.dm new file mode 100644 index 00000000..c33069e5 --- /dev/null +++ b/maps/away/lost_supply_base/lost_supply_base_areas.dm @@ -0,0 +1,24 @@ +/area/lost_supply_base + name = "\improper Abandoned supply station" + icon_state = "lost_supply_base" + icon = 'maps/away/lost_supply_base/lost_supply_base_sprites.dmi' + +/area/lost_supply_base/solar + name = "\improper Abandoned supply station solars control room" + icon_state = "lost_supply_base_solar" + icon = 'maps/away/lost_supply_base/lost_supply_base_sprites.dmi' + +/area/lost_supply_base/office + name = "\improper Abandoned supply station office" + icon_state = "lost_supply_base_office" + icon = 'maps/away/lost_supply_base/lost_supply_base_sprites.dmi' + +/area/lost_supply_base/supply + name = "\improper Abandoned supply station supplies room" + icon_state = "lost_supply_base_supply" + icon = 'maps/away/lost_supply_base/lost_supply_base_sprites.dmi' + +/area/lost_supply_base/common + name = "\improper Abandoned supply station common area" + icon_state = "lost_supply_base_common" + icon = 'maps/away/lost_supply_base/lost_supply_base_sprites.dmi' \ No newline at end of file diff --git a/maps/away/lost_supply_base/lost_supply_base_sprites.dmi b/maps/away/lost_supply_base/lost_supply_base_sprites.dmi new file mode 100644 index 00000000..14328520 Binary files /dev/null and b/maps/away/lost_supply_base/lost_supply_base_sprites.dmi differ diff --git a/maps/away/magshield/backup/magshield.dmm b/maps/away/magshield/backup/magshield.dmm new file mode 100644 index 00000000..82f8b51f --- /dev/null +++ b/maps/away/magshield/backup/magshield.dmm @@ -0,0 +1,802 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/obj/structure/grille,/turf/space,/area/space) +"ac" = (/obj/structure/lattice,/turf/space,/area/space) +"ad" = (/obj/item/weapon/ore,/turf/space,/area/space) +"ae" = (/obj/machinery/power/tracker,/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/airless,/area/space) +"af" = (/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/power/solar{id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"ag" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/space) +"ah" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless,/area/space) +"ai" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"aj" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"ak" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless,/area/space) +"al" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"am" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/space) +"an" = (/obj/structure/cable/yellow,/obj/machinery/power/solar{id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"ao" = (/obj/item/stack/rods,/turf/space,/area/space) +"ap" = (/turf/simulated/floor/airless,/area/space) +"aq" = (/obj/machinery/power/solar{id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array"},/obj/structure/cable/yellow,/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"ar" = (/turf/simulated/wall/r_wall,/area/space) +"as" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/access_button{pixel_x = -25; pixel_y = -25},/turf/simulated/floor/airless,/area/space) +"at" = (/obj/machinery/light/small,/turf/space,/area/space) +"au" = (/turf/simulated/wall/r_wall,/area/magshield/smes_storage) +"av" = (/obj/machinery/door/airlock/external/bolted_open,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aw" = (/turf/simulated/wall/r_wall,/area/magshield/engine) +"ax" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/unary/vent_pump/high_volume,/obj/effect/floor_decal/industrial/hatch/blue,/obj/machinery/embedded_controller/radio/airlock/airlock_controller{pixel_x = 25},/obj/machinery/airlock_sensor{pixel_x = -25; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"ay" = (/obj/structure/table/steel,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"az" = (/obj/structure/table/steel,/obj/random/tool,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aA" = (/obj/structure/table/steel,/obj/random/junk,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aB" = (/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aC" = (/obj/structure/table/rack,/obj/random/voidsuit,/obj/random/voidhelmet,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aD" = (/obj/machinery/door/airlock/external/bolted_open,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aE" = (/turf/simulated/floor/airless,/area/magshield/engine) +"aF" = (/obj/machinery/portable_atmospherics/canister/carbon_dioxide,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"aG" = (/obj/machinery/atmospherics/pipe/tank/carbon_dioxide,/turf/simulated/floor/airless,/area/magshield/engine) +"aH" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "prototype_chamber_blast"},/turf/simulated/floor/airless,/area/magshield/engine) +"aI" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 6; icon_state = "intact"},/turf/space,/area/space) +"aJ" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{icon_state = "intact"; dir = 10},/turf/space,/area/space) +"aK" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{dir = 8; icon_state = "intact"},/turf/space,/area/space) +"aL" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{dir = 4},/turf/simulated/wall/r_wall,/area/magshield/smes_storage) +"aM" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aN" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/unary/vent_pump{dir = 8; external_pressure_bound = 0; external_pressure_bound_default = 0; frequency = 1441; icon_state = "map_vent_in"; id_tag = "tox_out"; initialize_directions = 1; internal_pressure_bound = 4000; internal_pressure_bound_default = 4000; pressure_checks = 2; pressure_checks_default = 2; pump_direction = 0; use_power = 1},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aO" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aP" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/item/weapon/ore,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aQ" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aR" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aS" = (/obj/random/junk,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aT" = (/obj/structure/sign/warning/airlock{pixel_y = 30},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aU" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aV" = (/obj/machinery/portable_atmospherics/canister/carbon_dioxide,/turf/simulated/floor/airless,/area/magshield/engine) +"aW" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 5},/turf/simulated/floor/airless,/area/magshield/engine) +"aX" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/black,/turf/simulated/floor/airless,/area/magshield/engine) +"aY" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 9},/turf/simulated/floor/airless,/area/magshield/engine) +"aZ" = (/obj/machinery/door/airlock/hatch,/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "prototype_chamber_blast"},/turf/simulated/floor/airless,/area/magshield/engine) +"ba" = (/obj/machinery/mass_driver{dir = 4; id = "enginecore"},/turf/simulated/floor/airless,/area/magshield/engine) +"bb" = (/obj/machinery/door/blast/regular/open{dir = 1; icon_state = "pdoor0"; id = "prototype_chamber_blast"},/turf/simulated/floor/airless,/area/magshield/engine) +"bc" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging,/turf/space,/area/space) +"bd" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"be" = (/obj/machinery/power/terminal,/obj/structure/cable/yellow,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bf" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bg" = (/turf/space,/area/magshield/smes_storage) +"bh" = (/obj/structure/closet/crate/plastic,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/random/loot,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bi" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bj" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bk" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/turf/simulated/floor/airless,/area/magshield/engine) +"bl" = (/obj/machinery/atmospherics/unary/vent_pump,/turf/simulated/floor/airless,/area/magshield/engine) +"bm" = (/obj/machinery/atmospherics/unary/outlet_injector,/turf/simulated/floor/airless,/area/magshield/engine) +"bn" = (/obj/machinery/power/smes/buildable/outpost_substation,/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bo" = (/obj/item/weapon/ore,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bp" = (/obj/structure/lattice,/turf/space,/area/magshield/smes_storage) +"bq" = (/obj/structure/closet,/obj/random/junk,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"br" = (/obj/machinery/portable_atmospherics/canister,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/airless,/area/magshield/engine) +"bs" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 6},/turf/simulated/floor/airless,/area/magshield/engine) +"bt" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"bu" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/blast/regular/open{dir = 1; icon_state = "pdoor0"; id = "prototype_chamber_blast"},/obj/machinery/atmospherics/pipe/simple/visible/cyan,/turf/simulated/floor/airless,/area/magshield/engine) +"bv" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/blast/regular/open{dir = 1; icon_state = "pdoor0"; id = "prototype_chamber_blast"},/turf/simulated/floor/airless,/area/magshield/engine) +"bw" = (/obj/effect/shuttle_landmark/nav_magshield/nav2,/turf/space,/area/space) +"bx" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"by" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bz" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bA" = (/obj/structure/closet,/obj/item/toy/therapy_purple,/obj/random/hat,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bB" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan,/turf/simulated/floor/airless,/area/magshield/engine) +"bC" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{icon_state = "intact"; dir = 6},/turf/simulated/floor/airless,/area/magshield/engine) +"bD" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{icon_state = "intact"; dir = 9},/turf/simulated/floor/airless,/area/magshield/engine) +"bE" = (/obj/item/weapon/ore,/turf/space,/area/magshield/smes_storage) +"bF" = (/obj/item/stack/rods,/turf/space,/area/magshield/smes_storage) +"bG" = (/obj/structure/closet,/obj/item/device/flashlight/glowstick/random,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bH" = (/obj/machinery/atmospherics/portables_connector{dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"bI" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"bJ" = (/obj/machinery/atmospherics/pipe/manifold/visible/cyan{dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"bK" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 6},/turf/simulated/floor/airless,/area/magshield/engine) +"bL" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/turf/simulated/wall/r_wall,/area/magshield/engine) +"bM" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{icon_state = "intact"; dir = 4},/turf/space,/area/space) +"bN" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{icon_state = "intact"; dir = 4},/turf/space,/area/space) +"bO" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging,/obj/item/weapon/ore,/turf/space,/area/space) +"bP" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bQ" = (/obj/structure/table/steel,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bR" = (/obj/structure/table/steel,/obj/random/drinkbottle,/obj/random/tool,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bS" = (/obj/structure/closet/crate/trashcart,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bT" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/airless,/area/magshield/engine) +"bU" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{dir = 4; icon_state = "intact"},/turf/simulated/floor/airless,/area/magshield/engine) +"bV" = (/obj/machinery/atmospherics/pipe/simple/visible/red,/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"bW" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{icon_state = "intact"; dir = 9},/turf/space,/area/space) +"bX" = (/obj/item/modular_computer/console,/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bY" = (/obj/structure/bed/chair{dir = 8},/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/random/junk,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"ca" = (/obj/structure/table/steel,/obj/item/device/geiger,/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/airless,/area/magshield/engine) +"cb" = (/obj/item/modular_computer/console,/turf/simulated/floor/airless,/area/magshield/engine) +"cc" = (/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "EngineBlast"; name = "Engine Monitoring Room Blast Doors"; opacity = 0},/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/plating,/area/magshield/engine) +"cd" = (/obj/machinery/atmospherics/binary/circulator{anchored = 1; dir = 4},/turf/simulated/floor/plating,/area/magshield/engine) +"ce" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/obj/machinery/atmospherics/pipe/simple/visible/cyan,/turf/simulated/floor/airless,/area/magshield/engine) +"cf" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 9},/turf/simulated/floor/airless,/area/magshield/engine) +"cg" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 5; icon_state = "intact"},/turf/space,/area/space) +"ch" = (/obj/structure/closet/crate/hydroponics/prespawned,/obj/random/gloves,/turf/simulated/floor/plating,/area/magshield/smes_storage) +"ci" = (/obj/structure/bed/chair{dir = 4},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless,/area/magshield/engine) +"cj" = (/obj/item/modular_computer/console,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/magshield/engine) +"ck" = (/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "EngineBlast"; name = "Engine Monitoring Room Blast Doors"; opacity = 0},/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/magshield/engine) +"cl" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/magshield/engine) +"cm" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/magshield/engine) +"cn" = (/obj/machinery/atmospherics/binary/pump,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/magshield/engine) +"co" = (/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/power/generator{anchored = 1; dir = 2},/turf/simulated/floor/plating,/area/magshield/engine) +"cp" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cq" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cr" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cs" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"ct" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/airless,/area/magshield/engine) +"cu" = (/obj/item/modular_computer/console,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/turf/simulated/floor/airless,/area/magshield/engine) +"cv" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{icon_state = "intact"; dir = 5},/turf/simulated/floor/airless,/area/magshield/engine) +"cw" = (/obj/machinery/atmospherics/pipe/simple/visible/red,/obj/machinery/atmospherics/pipe/simple/visible/cyan{dir = 4; icon_state = "intact"},/turf/simulated/floor/airless,/area/magshield/engine) +"cx" = (/obj/machinery/atmospherics/binary/circulator{anchored = 1; dir = 8},/turf/simulated/floor/plating,/area/magshield/engine) +"cy" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cz" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cA" = (/obj/item/device/flashlight/glowstick/yellow,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cB" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cC" = (/obj/machinery/atmospherics/pipe/simple/visible/red,/turf/simulated/floor/airless,/area/magshield/engine) +"cD" = (/obj/machinery/atmospherics/portables_connector,/turf/simulated/floor/airless,/area/magshield/engine) +"cE" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{icon_state = "intact"; dir = 4},/obj/item/weapon/ore,/turf/space,/area/space) +"cF" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{dir = 4},/obj/machinery/light/small{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/item/weapon/ore,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cG" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 8; frequency = 1441; icon_state = "map_injector"; id = "n2o_in"; pixel_y = 1; use_power = 1},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cH" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cI" = (/obj/structure/closet,/obj/random/gloves,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cJ" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/random/junk,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cK" = (/obj/structure/table/steel,/obj/item/clothing/head/radiation,/obj/item/weapon/wrench,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless,/area/magshield/engine) +"cL" = (/obj/structure/closet,/obj/item/clothing/suit/radiation,/obj/item/device/flashlight,/turf/simulated/floor/airless,/area/magshield/engine) +"cM" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/airless,/area/magshield/engine) +"cN" = (/obj/machinery/atmospherics/binary/pump,/turf/simulated/floor/airless,/area/magshield/engine) +"cO" = (/obj/structure/girder/displaced,/turf/space,/area/space) +"cP" = (/obj/structure/table/steel,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cQ" = (/obj/structure/table/steel,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/random/tool,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cR" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cS" = (/obj/machinery/door/airlock,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cT" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cU" = (/obj/structure/cable{icon_state = "2-8"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cV" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cW" = (/obj/machinery/door/airlock/hatch,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/engine) +"cX" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/engine) +"cY" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/mob/living/simple_animal/hostile/carp,/turf/simulated/floor/airless,/area/magshield/engine) +"cZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/engine) +"da" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/obj/machinery/power/apc{dir = 2; name = "south bump"; operating = 1; pixel_y = -24},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless,/area/magshield/engine) +"db" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 5},/turf/simulated/floor/airless,/area/magshield/engine) +"dc" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"dd" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/obj/machinery/atmospherics/pipe/manifold/visible/red,/turf/simulated/floor/airless,/area/magshield/engine) +"de" = (/turf/simulated/wall/r_wall,/area/magshield/north) +"df" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/door/airlock,/turf/simulated/floor/airless,/area/magshield/north) +"dg" = (/turf/space,/area/magshield/north) +"dh" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/random/obstruction,/turf/simulated/floor/airless,/area/magshield/north) +"di" = (/obj/item/weapon/ore,/turf/simulated/floor/airless,/area/magshield/north) +"dj" = (/turf/simulated/floor/airless,/area/magshield/north) +"dk" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/airless,/area/magshield/north) +"dl" = (/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/airless,/area/magshield/north) +"dm" = (/obj/random/junk,/turf/simulated/floor/airless,/area/magshield/north) +"dn" = (/obj/item/weapon/storage/wallet/random,/turf/simulated/floor/airless,/area/magshield/north) +"do" = (/obj/structure/largecrate,/turf/simulated/floor/airless,/area/magshield/north) +"dp" = (/obj/random/shoes,/turf/simulated/floor/airless,/area/magshield/north) +"dq" = (/obj/machinery/portable_atmospherics/hydroponics,/turf/simulated/floor/airless,/area/magshield/north) +"dr" = (/obj/structure/iv_drip,/turf/simulated/floor/airless,/area/magshield/north) +"ds" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/airless,/area/magshield/north) +"dt" = (/turf/simulated/wall,/area/magshield/north) +"du" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"dv" = (/obj/random/tool,/turf/simulated/floor/airless,/area/magshield/north) +"dw" = (/obj/random/tank,/turf/simulated/floor/airless,/area/magshield/north) +"dx" = (/obj/structure/table/steel,/obj/random/tool,/turf/simulated/floor/airless,/area/magshield/north) +"dy" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless,/area/magshield/north) +"dz" = (/obj/structure/reagent_dispensers/water_cooler,/turf/simulated/floor/airless,/area/magshield/north) +"dA" = (/obj/structure/closet,/obj/random/toolbox,/turf/simulated/floor/airless,/area/magshield/north) +"dB" = (/obj/structure/closet,/obj/random/suit,/turf/simulated/floor/airless,/area/magshield/north) +"dC" = (/obj/structure/closet,/obj/random/smokes,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless,/area/magshield/north) +"dD" = (/obj/structure/closet,/obj/structure/plushie/ian,/obj/random/drinkbottle,/turf/simulated/floor/airless,/area/magshield/north) +"dE" = (/obj/random/material,/turf/simulated/floor/airless,/area/magshield/north) +"dF" = (/obj/item/stack/rods,/turf/simulated/floor/airless,/area/magshield/north) +"dG" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless,/area/magshield/north) +"dH" = (/obj/structure/lattice,/turf/space,/area/magshield/north) +"dI" = (/obj/item/clothing/under/color/lightpurple,/turf/simulated/floor/airless,/area/magshield/north) +"dJ" = (/obj/random/firstaid,/turf/simulated/floor/airless,/area/magshield/north) +"dK" = (/obj/random/toolbox,/turf/simulated/floor/airless,/area/magshield/north) +"dL" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/structure/largecrate,/turf/simulated/floor/airless,/area/magshield/north) +"dM" = (/obj/random/obstruction,/turf/simulated/floor/airless,/area/magshield/north) +"dN" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/turf/simulated/floor/airless,/area/magshield/north) +"dO" = (/obj/item/modular_computer/console,/turf/simulated/floor/airless,/area/magshield/north) +"dP" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/turf/simulated/floor/airless,/area/magshield/north) +"dQ" = (/obj/machinery/field_generator,/turf/simulated/floor/airless,/area/magshield/north) +"dR" = (/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/airless,/area/magshield/north) +"dS" = (/obj/effect/floor_decal/industrial/warning,/obj/random/loot,/turf/simulated/floor/airless,/area/magshield/north) +"dT" = (/obj/effect/floor_decal/industrial/warning,/obj/structure/largecrate,/turf/simulated/floor/airless,/area/magshield/north) +"dU" = (/obj/effect/floor_decal/industrial/warning,/obj/random/junk,/turf/simulated/floor/airless,/area/magshield/north) +"dV" = (/obj/effect/floor_decal/industrial/warning,/obj/item/weapon/flame/lighter,/turf/simulated/floor/airless,/area/magshield/north) +"dW" = (/obj/effect/floor_decal/industrial/warning,/obj/random/tank,/turf/simulated/floor/airless,/area/magshield/north) +"dX" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 6},/obj/random/toolbox,/turf/simulated/floor/airless,/area/magshield/north) +"dY" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"dZ" = (/obj/structure/table/steel,/obj/random/powercell,/obj/machinery/cell_charger,/turf/simulated/floor/airless,/area/magshield/north) +"ea" = (/obj/machinery/power/port_gen/pacman/mrs,/turf/simulated/floor/airless,/area/magshield/north) +"eb" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/airless,/area/magshield/north) +"ec" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/airless,/area/magshield/north) +"ed" = (/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/airless,/area/magshield/north) +"ee" = (/obj/structure/table/rack,/obj/random/voidsuit,/obj/random/voidhelmet,/turf/simulated/floor/airless,/area/magshield/north) +"ef" = (/obj/structure/grille,/turf/simulated/wall/r_wall,/area/space) +"eg" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless,/area/magshield/north) +"eh" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"ei" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"ej" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"ek" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"el" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"em" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/airlock,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"en" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/airless,/area/magshield/north) +"eo" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"ep" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eq" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/magshield/north) +"er" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/cable{icon_state = "6-8"},/turf/simulated/floor/airless,/area/magshield/north) +"es" = (/obj/structure/sign/warning/airlock{pixel_x = 30},/turf/simulated/floor/airless,/area/magshield/north) +"et" = (/obj/machinery/light/small{dir = 4},/turf/space,/area/space) +"eu" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/airless,/area/magshield/north) +"ev" = (/obj/structure/sign/warning/airlock{pixel_y = -30},/turf/simulated/wall,/area/magshield/north) +"ew" = (/obj/structure/sign/warning/docking_area{pixel_y = -30},/turf/simulated/floor/airless,/area/magshield/north) +"ex" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/light/small{dir = 8},/turf/simulated/floor/airless,/area/magshield/north) +"ey" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{icon_state = "4-9"},/turf/simulated/floor/airless,/area/magshield/north) +"ez" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/machinery/floodlight,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eA" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/floodlight,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eB" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/light/small,/turf/simulated/floor/airless,/area/magshield/north) +"eC" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/cable{icon_state = "1-8"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eD" = (/obj/machinery/door/airlock/external/bolted,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eE" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1501; id_tag = "asteroid_base_east_pump"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{pixel_x = 0; pixel_y = 25},/obj/machinery/airlock_sensor{pixel_x = 0; pixel_y = -25},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eF" = (/obj/machinery/door/airlock/external/bolted,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eG" = (/obj/machinery/access_button{pixel_x = -25; pixel_y = 25},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eH" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/space) +"eI" = (/obj/structure/magshield/maggen,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless,/area/space) +"eJ" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1380; id_tag = "merchant_station_vent"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eK" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/magshield/north) +"eL" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless,/area/magshield/north) +"eM" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/item/weapon/newspaper,/turf/simulated/floor/airless,/area/magshield/north) +"eN" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/airless,/area/magshield/north) +"eO" = (/obj/machinery/light_construct/small,/turf/simulated/floor/airless,/area/magshield/north) +"eP" = (/obj/structure/table,/turf/simulated/floor/airless,/area/magshield/north) +"eQ" = (/obj/structure/table/steel,/obj/item/weapon/storage/toolbox/mechanical,/turf/simulated/floor/airless,/area/magshield/north) +"eR" = (/obj/structure/table/steel,/turf/simulated/floor/airless,/area/magshield/north) +"eS" = (/obj/structure/table/steel,/obj/item/weapon/storage/box/lights,/turf/simulated/floor/airless,/area/magshield/north) +"eT" = (/obj/machinery/door/airlock/external/bolted_open,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/access_button{pixel_x = -25; pixel_y = 25},/turf/simulated/floor/airless,/area/magshield/north) +"eU" = (/obj/machinery/light/small,/turf/simulated/floor/airless,/area/magshield/north) +"eV" = (/obj/structure/closet,/obj/random/material,/obj/random/material,/turf/simulated/floor/airless,/area/magshield/north) +"eW" = (/obj/structure/closet,/obj/random/material,/turf/simulated/floor/airless,/area/magshield/north) +"eX" = (/obj/structure/closet,/obj/random/tool,/turf/simulated/floor/airless,/area/magshield/north) +"eY" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/airless,/area/magshield/north) +"eZ" = (/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/airless,/area/magshield/north) +"fa" = (/obj/structure/janitorialcart,/turf/simulated/floor/airless,/area/magshield/north) +"fb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"fc" = (/obj/machinery/light/small{dir = 8},/turf/space,/area/space) +"fd" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1380; id_tag = "centcom_shuttle_dock_pump"},/obj/effect/floor_decal/industrial/hatch/blue,/obj/machinery/embedded_controller/radio/airlock/airlock_controller{pixel_x = 25},/obj/machinery/airlock_sensor{pixel_x = -25; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"fe" = (/turf/simulated/wall,/area/magshield/east) +"ff" = (/obj/machinery/atmospherics/pipe/tank,/obj/machinery/atmospherics/portables_connector{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"fg" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 10},/turf/simulated/floor/airless,/area/magshield/east) +"fh" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless,/area/magshield/east) +"fi" = (/turf/simulated/floor/airless,/area/magshield/east) +"fj" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/east) +"fk" = (/turf/simulated/wall/r_wall,/area/magshield/east) +"fl" = (/obj/structure/grille,/turf/simulated/wall/r_wall,/area/magshield/north) +"fm" = (/obj/item/weapon/mop,/turf/simulated/floor/airless,/area/magshield/north) +"fn" = (/obj/machinery/door/airlock/external/bolted_open,/turf/simulated/floor/airless,/area/magshield/north) +"fo" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/black,/turf/simulated/floor/airless,/area/magshield/east) +"fp" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"fq" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"fr" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/east) +"fs" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/turf/simulated/floor/airless,/area/magshield/east) +"ft" = (/obj/effect/shuttle_landmark/nav_magshield/nav5,/turf/space,/area/space) +"fu" = (/turf/simulated/wall/r_wall,/area/magshield/west) +"fv" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/west) +"fw" = (/obj/machinery/access_button{pixel_x = -25; pixel_y = 25},/turf/simulated/floor/airless,/area/magshield/north) +"fx" = (/obj/machinery/atmospherics/pipe/tank,/obj/machinery/atmospherics/portables_connector{dir = 4},/obj/machinery/light_construct{dir = 8},/turf/simulated/floor/airless,/area/magshield/east) +"fy" = (/obj/machinery/atmospherics/pipe/manifold/visible/black{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"fz" = (/obj/machinery/light_construct{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"fA" = (/turf/simulated/floor/tiled,/area/magshield/west) +"fB" = (/turf/simulated/floor/tiled/dark,/area/magshield/west) +"fC" = (/obj/machinery/light_construct{dir = 1},/turf/simulated/floor/tiled/dark,/area/magshield/west) +"fD" = (/obj/random/junk,/turf/simulated/floor/tiled/dark,/area/magshield/west) +"fE" = (/obj/structure/cable{icon_state = "1-10"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled/dark,/area/magshield/west) +"fF" = (/obj/machinery/light_construct{dir = 1},/turf/simulated/floor/tiled,/area/magshield/west) +"fG" = (/obj/structure/reagent_dispensers/water_cooler,/turf/simulated/floor/tiled,/area/magshield/west) +"fH" = (/obj/effect/overmap/sector/magshield,/turf/simulated/floor/airless,/area/magshield/north) +"fI" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"fJ" = (/obj/structure/grille,/turf/space,/area/magshield/east) +"fK" = (/obj/structure/cable{icon_state = "4-10"},/turf/simulated/floor/tiled/dark,/area/magshield/west) +"fL" = (/obj/structure/table/steel,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/west) +"fM" = (/obj/item/modular_computer/console,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/west) +"fN" = (/obj/structure/cable{icon_state = "5-8"},/turf/simulated/floor/tiled,/area/magshield/west) +"fO" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled/dark,/area/magshield/west) +"fP" = (/obj/item/weapon/newspaper,/turf/simulated/floor/tiled,/area/magshield/west) +"fQ" = (/obj/machinery/atmospherics/binary/pump{dir = 1},/turf/simulated/floor/airless,/area/magshield/east) +"fR" = (/obj/machinery/atmospherics/omni/mixer,/turf/simulated/floor/airless,/area/magshield/east) +"fS" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/east) +"fT" = (/obj/machinery/atmospherics/omni/filter,/turf/simulated/floor/airless,/area/magshield/east) +"fU" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"fV" = (/obj/machinery/atmospherics/pipe/manifold/visible/red{icon_state = "map"; dir = 1},/turf/simulated/floor/airless,/area/magshield/east) +"fW" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/turf/simulated/wall/r_wall,/area/magshield/east) +"fX" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 8; frequency = 1441; icon_state = "map_injector"; id = "d_n2_in"; use_power = 1},/turf/simulated/floor/airless,/area/magshield/east) +"fY" = (/obj/structure/cable{icon_state = "2-5"},/turf/simulated/floor/tiled,/area/magshield/west) +"fZ" = (/obj/structure/bed/chair/office/dark{dir = 4},/turf/simulated/floor/tiled,/area/magshield/west) +"ga" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/magshield/west) +"gb" = (/obj/structure/table/steel,/obj/item/weapon/material/ashtray/plastic,/obj/random/smokes,/turf/simulated/floor/tiled,/area/magshield/west) +"gc" = (/obj/structure/window/reinforced/full,/obj/machinery/door/firedoor,/obj/structure/grille,/turf/simulated/floor/tiled,/area/magshield/west) +"gd" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/turf/simulated/floor/airless,/area/magshield/east) +"ge" = (/obj/machinery/atmospherics/pipe/simple/visible/red,/turf/simulated/floor/airless,/area/magshield/east) +"gf" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/west) +"gg" = (/obj/structure/table/steel,/obj/random/toy,/turf/simulated/floor/tiled,/area/magshield/west) +"gh" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/airless,/area/magshield/east) +"gi" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 5},/turf/simulated/floor/airless,/area/magshield/east) +"gj" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/airless,/area/magshield/east) +"gk" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 5},/turf/simulated/floor/airless,/area/magshield/east) +"gl" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 9},/turf/simulated/floor/airless,/area/magshield/east) +"gm" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/light_construct{dir = 8},/turf/simulated/floor/tiled,/area/magshield/west) +"gn" = (/obj/structure/table/steel,/obj/item/weapon/reagent_containers/food/drinks/coffee,/turf/simulated/floor/tiled,/area/magshield/west) +"go" = (/obj/structure/table/steel,/turf/simulated/floor/tiled,/area/magshield/west) +"gp" = (/obj/structure/magshield/nav_light/red{dir = 4},/turf/simulated/floor/airless,/area/space) +"gq" = (/obj/structure/magshield/nav_light{dir = 8},/turf/simulated/floor/airless,/area/space) +"gr" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"gs" = (/obj/structure/closet,/obj/random/cash,/obj/random/cash,/obj/random/clothing,/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gt" = (/obj/structure/closet,/obj/item/weapon/storage/wallet/leather,/obj/random/clothing,/obj/random/smokes,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gu" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gv" = (/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gw" = (/obj/structure/bed,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gx" = (/obj/machinery/light_construct{dir = 8},/turf/simulated/floor/airless,/area/magshield/east) +"gy" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/airless,/area/magshield/east) +"gz" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal,/turf/simulated/floor/airless,/area/magshield/east) +"gA" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gB" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/airless,/area/magshield/east) +"gC" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 6},/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/airless,/area/magshield/east) +"gD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/east) +"gE" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/airless,/area/magshield/east) +"gF" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/airless,/area/magshield/east) +"gG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gH" = (/obj/structure/table/woodentable{dir = 10},/obj/item/weapon/storage/box/checkers,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gI" = (/obj/structure/table/woodentable{dir = 10},/obj/item/weapon/storage/belt/champion,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gJ" = (/obj/structure/table/woodentable{dir = 10},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gK" = (/obj/structure/table/woodentable{dir = 10},/obj/item/weapon/storage/bible/booze,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gL" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless,/area/magshield/east) +"gM" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/east) +"gN" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/cable{icon_state = "2-8"},/turf/simulated/floor/airless,/area/magshield/east) +"gO" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/magshield/west) +"gP" = (/turf/simulated/wall,/area/magshield/west) +"gQ" = (/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable,/turf/simulated/floor/tiled/white,/area/magshield/west) +"gR" = (/turf/simulated/floor/tiled/white,/area/magshield/west) +"gS" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/random/junk,/turf/simulated/floor/tiled/dark,/area/magshield/west) +"gT" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/east) +"gU" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/magshield/west) +"gV" = (/obj/structure/bookcase/manuals/xenoarchaeology,/turf/simulated/floor/tiled,/area/magshield/west) +"gW" = (/obj/structure/bookcase/manuals/engineering,/turf/simulated/floor/tiled,/area/magshield/west) +"gX" = (/obj/structure/bookcase/manuals/medical,/turf/simulated/floor/tiled,/area/magshield/west) +"gY" = (/obj/structure/table/woodentable,/obj/random/action_figure,/turf/simulated/floor/tiled,/area/magshield/west) +"gZ" = (/obj/structure/table/steel,/obj/item/weapon/reagent_containers/food/drinks/coffee,/obj/random/smokes,/turf/simulated/floor/tiled/white,/area/magshield/west) +"ha" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled/white,/area/magshield/west) +"hb" = (/obj/structure/table/steel,/obj/random/glasses,/turf/simulated/floor/tiled,/area/magshield/west) +"hc" = (/obj/effect/shuttle_landmark/nav_magshield/nav1,/turf/space,/area/space) +"hd" = (/obj/machinery/portable_atmospherics/hydroponics,/turf/simulated/floor/tiled,/area/magshield/east) +"he" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/magshield/east) +"hf" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/east) +"hg" = (/obj/machinery/door/airlock/external/bolted_open,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"hh" = (/obj/machinery/embedded_controller/radio/airlock/airlock_controller{pixel_x = 0; pixel_y = 25},/obj/machinery/airlock_sensor{pixel_x = 0; pixel_y = -25},/turf/simulated/floor/airless,/area/magshield/east) +"hi" = (/obj/structure/lattice,/turf/space,/area/magshield/east) +"hj" = (/obj/machinery/access_button{pixel_x = -25; pixel_y = -25},/obj/structure/lattice,/turf/space,/area/magshield/east) +"hk" = (/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"hl" = (/obj/structure/magshield/rad_sensor,/obj/structure/cable/cyan{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless,/area/space) +"hm" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/west) +"hn" = (/obj/structure/table/woodentable,/obj/item/weapon/material/sword/replica,/turf/simulated/floor/tiled,/area/magshield/west) +"ho" = (/obj/machinery/light_construct{dir = 8},/turf/simulated/floor/tiled/white,/area/magshield/west) +"hp" = (/obj/structure/bed/chair/comfy/captain,/turf/simulated/floor/tiled/white,/area/magshield/west) +"hq" = (/obj/item/modular_computer/console,/obj/item/weapon/paper/magshield/log,/turf/simulated/floor/tiled/white,/area/magshield/west) +"hr" = (/obj/random/junk,/turf/simulated/floor/tiled,/area/magshield/west) +"hs" = (/turf/simulated/floor/tiled,/area/magshield/east) +"ht" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/airless,/area/magshield/east) +"hu" = (/turf/space,/area/magshield/east) +"hv" = (/obj/item/weapon/ore/slag,/turf/simulated/floor/airless,/area/space) +"hw" = (/obj/structure/table/woodentable,/obj/random/plushie/large,/turf/simulated/floor/tiled,/area/magshield/west) +"hx" = (/obj/structure/table/steel,/obj/item/weapon/material/ashtray/bronze,/turf/simulated/floor/tiled/white,/area/magshield/west) +"hy" = (/obj/structure/table/steel,/obj/random/smokes,/turf/simulated/floor/tiled,/area/magshield/west) +"hz" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{icon_state = "1-10"},/turf/simulated/floor/airless,/area/magshield/east) +"hA" = (/obj/structure/table/rack,/obj/random/voidsuit,/obj/random/voidhelmet,/turf/simulated/floor/airless,/area/magshield/east) +"hB" = (/obj/structure/safe,/obj/random/coin,/obj/random/contraband,/obj/random/energy,/obj/item/weapon/grenade/fake,/obj/random/cash,/obj/random/cash,/obj/random/cash,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/magshield/west) +"hC" = (/obj/structure/table/woodentable,/obj/item/toy/torchmodel,/turf/simulated/floor/tiled,/area/magshield/west) +"hD" = (/obj/item/weapon/book/manual/magshield_manual,/turf/simulated/floor/tiled/white,/area/magshield/west) +"hE" = (/obj/structure/lattice,/turf/space,/area/magshield/west) +"hF" = (/obj/item/weapon/ore,/turf/simulated/floor/tiled,/area/magshield/west) +"hG" = (/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable{icon_state = "0-2"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/turf/simulated/floor/airless,/area/magshield/east) +"hH" = (/obj/structure/cable{icon_state = "5-8"},/obj/structure/cable{icon_state = "2-5"},/turf/simulated/floor/airless,/area/magshield/east) +"hI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless,/area/magshield/east) +"hJ" = (/obj/structure/filingcabinet/chestdrawer,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"hK" = (/obj/structure/table/woodentable,/obj/item/weapon/book/manual/supermatter_engine,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"hL" = (/obj/item/weapon/ore,/turf/simulated/floor/tiled/dark,/area/magshield/west) +"hM" = (/turf/space,/area/magshield/west) +"hN" = (/obj/item/weapon/reagent_containers/glass/bucket,/turf/simulated/floor/tiled,/area/magshield/east) +"hO" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/airless,/area/magshield/east) +"hP" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/magshield/east) +"hQ" = (/obj/machinery/portable_atmospherics/canister/oxygen,/obj/machinery/light_construct{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"hR" = (/obj/structure/filingcabinet/chestdrawer,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"hS" = (/obj/structure/bed/chair/comfy/red,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"hT" = (/obj/structure/table/woodentable,/obj/item/weapon/book/manual/evaguide,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"hU" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/west) +"hV" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/west) +"hW" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/dark,/area/magshield/west) +"hX" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/item/weapon/paper/magshield/tornpage,/turf/simulated/floor/tiled/dark,/area/magshield/west) +"hY" = (/obj/structure/table/steel,/obj/item/weapon/material/ashtray/plastic,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/west) +"hZ" = (/obj/structure/table/woodentable,/obj/random/accessory,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"ia" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/lighter/zippo,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"ib" = (/obj/structure/table/woodentable,/obj/item/weapon/material/ashtray/bronze,/obj/random/smokes,/obj/machinery/light,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"ic" = (/obj/item/stack/rods,/turf/simulated/floor/tiled/dark,/area/magshield/west) +"id" = (/obj/item/stack/rods,/turf/space,/area/magshield/west) +"ie" = (/obj/machinery/seed_storage,/turf/simulated/floor/tiled,/area/magshield/east) +"if" = (/obj/structure/reagent_dispensers/watertank,/obj/item/weapon/reagent_containers/glass/bucket,/turf/simulated/floor/airless,/area/magshield/east) +"ig" = (/obj/structure/cable{icon_state = "1-10"},/turf/simulated/floor/airless,/area/magshield/east) +"ih" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled,/area/magshield/east) +"ii" = (/obj/item/weapon/material/minihoe,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/light,/turf/simulated/floor/tiled,/area/magshield/east) +"ij" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled,/area/magshield/east) +"ik" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"il" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/structure/cable{icon_state = "2-5"},/turf/simulated/floor/airless,/area/magshield/east) +"im" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"in" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/airless,/area/magshield/east) +"io" = (/obj/machinery/light_construct{dir = 8},/turf/simulated/floor/tiled,/area/magshield/west) +"ip" = (/turf/simulated/wall/r_wall,/area/magshield/south) +"iq" = (/turf/simulated/wall,/area/magshield/south) +"ir" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/magshield/south) +"is" = (/obj/item/weapon/ore/slag,/turf/space,/area/space) +"it" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled/dark,/area/magshield/west) +"iu" = (/turf/simulated/floor/tiled/white,/area/magshield/south) +"iv" = (/obj/structure/curtain/open/shower,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iw" = (/obj/machinery/shower{icon_state = "shower"; dir = 8},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/white,/area/magshield/south) +"ix" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/magshield/south) +"iy" = (/obj/structure/table,/obj/random/firstaid,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iz" = (/obj/machinery/light_construct{dir = 1},/turf/simulated/floor/tiled/white,/area/magshield/south) +"iA" = (/obj/structure/bed,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iB" = (/obj/random/material,/turf/space,/area/space) +"iC" = (/turf/simulated/floor/airless,/area/magshield/west) +"iD" = (/obj/structure/table/steel,/obj/item/weapon/reagent_containers/food/drinks/cans/space_up,/obj/item/weapon/reagent_containers/food/drinks/cans/space_up{pixel_x = 5; pixel_y = 4},/obj/item/weapon/reagent_containers/food/drinks/cans/space_up{pixel_x = -8; pixel_y = 5},/obj/item/weapon/reagent_containers/food/drinks/cans/space_up{pixel_x = -2; pixel_y = -4},/turf/simulated/floor/tiled,/area/magshield/west) +"iE" = (/obj/structure/iv_drip,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iF" = (/obj/random/medical/lite,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iG" = (/obj/machinery/light_construct,/turf/simulated/floor/tiled,/area/magshield/west) +"iH" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/magshield/south) +"iI" = (/obj/machinery/shower{icon_state = "shower"; dir = 8},/obj/random/trash,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/white,/area/magshield/south) +"iJ" = (/obj/item/weapon/bedsheet,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iK" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/west) +"iL" = (/obj/structure/toilet,/turf/simulated/floor/tiled/white/usedup,/area/magshield/south) +"iM" = (/obj/structure/urinal{pixel_y = 25},/obj/random/trash,/turf/simulated/floor/tiled/white/usedup,/area/magshield/south) +"iN" = (/obj/structure/sink{pixel_y = 25},/turf/simulated/floor/tiled/white/usedup,/area/magshield/south) +"iO" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/south) +"iP" = (/obj/machinery/vending/coffee,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/magshield/south) +"iQ" = (/obj/machinery/vending/cola,/turf/simulated/floor/tiled,/area/magshield/south) +"iR" = (/obj/machinery/vending/snack,/turf/simulated/floor/tiled,/area/magshield/south) +"iS" = (/obj/structure/window/reinforced/full,/obj/structure/grille,/turf/simulated/floor/tiled,/area/magshield/south) +"iT" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iU" = (/obj/structure/toilet{dir = 8},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/white,/area/magshield/south) +"iV" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light_construct{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"iW" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iX" = (/obj/item/weapon/ore/slag,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iY" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled/white/usedup,/area/magshield/south) +"iZ" = (/obj/machinery/light,/turf/simulated/floor/tiled/white/usedup,/area/magshield/south) +"ja" = (/mob/living/simple_animal/hostile/carp,/turf/simulated/floor/tiled/white/usedup,/area/magshield/south) +"jb" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white/usedup,/area/magshield/south) +"jc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/south) +"jd" = (/turf/simulated/floor/tiled,/area/magshield/south) +"je" = (/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/magshield/south) +"jf" = (/obj/structure/window/reinforced/full,/obj/machinery/door/firedoor,/obj/structure/grille,/turf/simulated/floor/tiled,/area/magshield/south) +"jg" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/magshield/south) +"jh" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/white,/area/magshield/south) +"ji" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled/white,/area/magshield/south) +"jj" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white,/area/magshield/south) +"jk" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/turf/simulated/floor/tiled/white,/area/magshield/south) +"jl" = (/turf/space,/area/magshield/south) +"jm" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/random/smokes,/turf/simulated/floor/tiled,/area/magshield/south) +"jn" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/random/firstaid,/turf/simulated/floor/tiled,/area/magshield/south) +"jo" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"jp" = (/obj/structure/bed,/obj/item/weapon/bedsheet,/turf/simulated/floor/tiled,/area/magshield/south) +"jq" = (/obj/structure/bed,/turf/simulated/floor/tiled,/area/magshield/south) +"jr" = (/obj/random/trash,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"js" = (/obj/structure/bed/chair{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"jt" = (/obj/structure/table/standard{name = "plastic table frame"},/turf/simulated/floor/tiled,/area/magshield/south) +"ju" = (/obj/structure/bed/chair{dir = 8},/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"jv" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/trash/plate,/obj/item/weapon/reagent_containers/food/snacks/flatbread,/turf/simulated/floor/tiled,/area/magshield/south) +"jw" = (/obj/structure/bed/chair{dir = 8},/turf/simulated/floor/tiled,/area/magshield/south) +"jx" = (/obj/structure/table/marble,/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled/white,/area/magshield/south) +"jy" = (/obj/structure/table/marble,/obj/item/weapon/material/knife/butch,/turf/simulated/floor/tiled/white,/area/magshield/south) +"jz" = (/obj/structure/sink{pixel_y = 25},/turf/simulated/floor/tiled/white,/area/magshield/south) +"jA" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/freezer,/area/magshield/south) +"jB" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/simulated/floor/tiled/freezer,/area/magshield/south) +"jC" = (/obj/machinery/washing_machine,/turf/simulated/floor/tiled/white,/area/magshield/south) +"jD" = (/obj/structure/lattice,/turf/space,/area/magshield/south) +"jE" = (/obj/structure/magshield/maggen,/turf/simulated/floor/airless,/area/space) +"jF" = (/obj/machinery/door/airlock/external/bolted,/turf/simulated/floor/airless,/area/magshield/south) +"jG" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1380; id_tag = "merchant_station_vent"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{pixel_x = 0; pixel_y = 25},/obj/machinery/airlock_sensor{pixel_x = 0; pixel_y = -25},/turf/simulated/floor/airless,/area/magshield/south) +"jH" = (/obj/machinery/door/airlock/external/bolted,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless,/area/magshield/south) +"jI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"jJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24},/obj/structure/cable{icon_state = "0-2"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/turf/simulated/floor/tiled,/area/magshield/south) +"jK" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled,/area/magshield/south) +"jL" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/random/plushie/large,/obj/random/smokes,/turf/simulated/floor/tiled,/area/magshield/south) +"jM" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/machinery/light{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"jN" = (/obj/structure/closet,/obj/random/glasses,/obj/random/hat,/obj/random/cash,/turf/simulated/floor/tiled,/area/magshield/south) +"jO" = (/obj/structure/closet,/obj/random/clothing,/obj/random/accessory,/obj/random/smokes,/turf/simulated/floor/tiled,/area/magshield/south) +"jP" = (/obj/structure/closet,/obj/random/junk,/turf/simulated/floor/tiled,/area/magshield/south) +"jQ" = (/obj/structure/closet,/obj/random/clothing,/turf/simulated/floor/tiled,/area/magshield/south) +"jR" = (/obj/structure/closet,/obj/random/clothing,/obj/random/cash,/turf/simulated/floor/tiled,/area/magshield/south) +"jS" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/trash/plate,/turf/simulated/floor/tiled,/area/magshield/south) +"jT" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/weapon/material/kitchen/utensil/knife,/turf/simulated/floor/tiled,/area/magshield/south) +"jU" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/random/snack,/turf/simulated/floor/tiled,/area/magshield/south) +"jV" = (/obj/structure/table/marble,/turf/simulated/floor/tiled/white,/area/magshield/south) +"jW" = (/obj/item/weapon/material/knife/hook,/turf/simulated/floor/tiled/freezer,/area/magshield/south) +"jX" = (/obj/machinery/atmospherics/unary/vent_pump/on,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/magshield/south) +"jY" = (/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/obj/item/weapon/soap/deluxe,/turf/simulated/floor/tiled/white,/area/magshield/south) +"jZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/magshield/south) +"ka" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/magshield/south) +"kb" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/magshield/south) +"kc" = (/turf/simulated/floor/airless,/area/magshield/south) +"kd" = (/obj/structure/bed/roller,/turf/simulated/floor/airless,/area/space) +"ke" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"kf" = (/obj/structure/sign/warning/airlock{pixel_x = -30},/turf/simulated/floor/tiled,/area/magshield/south) +"kg" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/magshield/south) +"kh" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"ki" = (/obj/structure/curtain/open/bed,/turf/simulated/floor/tiled,/area/magshield/south) +"kj" = (/obj/random/snack,/turf/simulated/floor/tiled,/area/magshield/south) +"kk" = (/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/tiled,/area/magshield/south) +"kl" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled,/area/magshield/south) +"km" = (/obj/machinery/vending/dinnerware,/turf/simulated/floor/tiled/white,/area/magshield/south) +"kn" = (/obj/structure/table/marble,/obj/machinery/microwave,/turf/simulated/floor/tiled/white,/area/magshield/south) +"ko" = (/turf/simulated/floor/tiled/freezer,/area/magshield/south) +"kp" = (/obj/structure/closet/secure_closet/freezer/fridge,/obj/item/weapon/reagent_containers/food/snacks/hotdog,/turf/simulated/floor/tiled/freezer,/area/magshield/south) +"kq" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled/white,/area/magshield/south) +"kr" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled/white,/area/magshield/south) +"ks" = (/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/magshield/south) +"kt" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light_construct{dir = 8},/turf/simulated/floor/tiled,/area/magshield/south) +"ku" = (/obj/item/weapon/ore,/turf/space,/area/magshield/south) +"kv" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/south) +"kw" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/magshield/south) +"kx" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"ky" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"kz" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"kA" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/light,/turf/simulated/floor/tiled,/area/magshield/south) +"kB" = (/obj/item/weapon/flame/match,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"kC" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"kD" = (/obj/item/weapon/material/kitchen/utensil/fork/plastic,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"kE" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"kF" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled,/area/magshield/south) +"kG" = (/obj/random/trash,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"kH" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/magshield/south) +"kI" = (/obj/structure/table/marble,/obj/item/weapon/reagent_containers/food/snacks/chips,/turf/simulated/floor/tiled/white,/area/magshield/south) +"kJ" = (/obj/structure/table/marble,/obj/item/weapon/material/kitchen/utensil/knife,/turf/simulated/floor/tiled/white,/area/magshield/south) +"kK" = (/obj/structure/kitchenspike,/turf/simulated/floor/tiled/freezer,/area/magshield/south) +"kL" = (/obj/structure/closet/secure_closet/freezer/meat,/obj/item/weapon/reagent_containers/food/snacks/meat,/obj/item/weapon/reagent_containers/food/snacks/meat,/obj/item/weapon/reagent_containers/food/snacks/meat,/obj/item/weapon/reagent_containers/food/snacks/meat,/obj/item/weapon/reagent_containers/food/snacks/meat,/turf/simulated/floor/tiled/freezer,/area/magshield/south) +"kM" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/magshield/south) +"kN" = (/obj/structure/window/basic{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"kO" = (/obj/structure/fitness/weightlifter,/obj/structure/window/basic{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"kP" = (/obj/structure/window/basic{dir = 1},/obj/item/weapon/towel/random,/turf/simulated/floor/tiled,/area/magshield/south) +"kQ" = (/obj/structure/window/basic{dir = 1},/obj/structure/fitness/punchingbag,/turf/simulated/floor/tiled,/area/magshield/south) +"kR" = (/obj/structure/window/basic{dir = 4},/obj/structure/window/basic{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"kS" = (/obj/machinery/computer/arcade,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"kT" = (/obj/structure/curtain/open/bed,/obj/item/weapon/material/kitchen/utensil/knife/plastic,/turf/simulated/floor/tiled,/area/magshield/south) +"kU" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/magshield/south) +"kV" = (/obj/item/weapon/towel/random,/turf/simulated/floor/tiled,/area/magshield/south) +"kW" = (/obj/machinery/computer/arcade,/turf/simulated/floor/tiled,/area/magshield/south) +"kX" = (/obj/structure/closet,/obj/random/accessory,/turf/simulated/floor/tiled,/area/magshield/south) +"kY" = (/obj/structure/closet,/obj/random/tool,/obj/random/smokes,/turf/simulated/floor/tiled,/area/magshield/south) +"kZ" = (/obj/structure/closet,/obj/random/firstaid,/obj/random/junk,/turf/simulated/floor/tiled,/area/magshield/south) +"la" = (/obj/structure/closet,/obj/random/loot,/turf/simulated/floor/tiled,/area/magshield/south) +"lb" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/random/hat,/turf/simulated/floor/tiled,/area/magshield/south) +"lc" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/weapon/deck/cards,/turf/simulated/floor/tiled,/area/magshield/south) +"ld" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/weapon/material/kitchen/utensil/fork/plastic,/obj/item/trash/plate,/turf/simulated/floor/tiled,/area/magshield/south) +"le" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"lf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled,/area/magshield/south) +"lg" = (/obj/item/stack/rods,/turf/space,/area/magshield/south) +"lh" = (/obj/structure/fitness/weightlifter,/turf/simulated/floor/tiled,/area/magshield/south) +"li" = (/obj/structure/fitness/punchingbag,/obj/machinery/light,/turf/simulated/floor/tiled,/area/magshield/south) +"lj" = (/obj/structure/window/basic{dir = 4},/obj/random/trash,/turf/simulated/floor/tiled,/area/magshield/south) +"lk" = (/obj/machinery/light/small,/turf/simulated/floor/tiled,/area/magshield/south) +"ll" = (/obj/random/trash,/obj/machinery/light/small,/turf/simulated/floor/tiled,/area/magshield/south) +"lm" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/machinery/light,/turf/simulated/floor/tiled,/area/magshield/south) +"ln" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/magshield/south) +"lo" = (/obj/machinery/vending/cigarette,/turf/simulated/floor/tiled,/area/magshield/south) +"lp" = (/obj/machinery/vending/cola,/obj/machinery/light,/turf/simulated/floor/tiled,/area/magshield/south) +"lq" = (/obj/machinery/vending/fitness,/turf/simulated/floor/tiled,/area/magshield/south) +"lr" = (/obj/machinery/light_construct{dir = 8},/turf/simulated/floor/tiled,/area/magshield/south) +"ls" = (/obj/structure/girder/displaced,/turf/simulated/floor/tiled,/area/magshield/south) +"lt" = (/obj/effect/shuttle_landmark/nav_magshield/nav4,/turf/space,/area/space) +"lu" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless,/area/space) +"lv" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/space) +"lw" = (/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/power/solar{id = "auxsolarsport"; name = "Port Auxiliary Solar Array"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"lx" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/space) +"ly" = (/obj/structure/cable/yellow,/obj/machinery/power/solar{id = "auxsolarsport"; name = "Port Auxiliary Solar Array"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"lz" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/space) +"lA" = (/obj/effect/shuttle_landmark/nav_magshield/nav3,/turf/space,/area/space) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababacacababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaadaaaaaaaaaaaaaeaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaafaaaaaaafafafafafafaaagaaafafafafafafafafafafaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaahaaaaaaaiaiaiaiaiaiajakajalalalalalalalalalamaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaanananananananaaagaaananananananananananaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaoaaaaaaaaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaafafafafafafafafapagapafafafafafafafafafafaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaiaiaiaiaiaiaiaiaiajakajalalalalalalalalalamaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanananananananananapagapananananananananananaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaafafafafafafafafafafaaagaaafafafafafafafafafafaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaahaiaiaiaiaiaiaiaiaiajakajalalalalalalalalalamaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaananananananananananaaagaaaqanananananananananaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaraaaaaaaaaaaaaaaaaaaaaaaaasataaaaaaaaaaaaaaaaaaaaaaaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaauauauauauauauauauauauauauavauawawawawawawawawawawawawaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaauauauauauauauauauauauauauaxauawawawawawawawawawawawawaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababauauayayayazaAayazaBauaCauaDauawaEaFaGaGaGaHaEaEaEawawabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaIaJaIaKaLaLaMaNaOaPaOaQaOaRauaSaTaUaBawaVaFaWaXaYaZaEbaaEbbaEapapapaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbcbcbcaaauaubdbeaBbeaBbeaBbfbgbgbhbibjawaVaFaEbkaEaHblaEbmawawabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacacacaaaaaaaaaaaaaaaaabbcbcbcaaauauaBbnaBbnaBbnbobgbgbpbgbgbqawbrbsaEaEbtawbubvbuawawaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbcbcbcaaauaubxbybzbybzbgbpbgbgboaBaUbAawaEaEaEaEaEaEbBbCbDawawabababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbcbcbcaaauaubEbgbgbgbgbgbFbgauaBaSaUbGawaEaEaEaEbHbIbJbBbKbLbLbMbNbNbNbNbNbNbNbNbNbNaJabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbObcbcaabpbgbgbgbgbgaBbPbQbRaubSaBaUaBawawawawbTbCbUbDbBbVawawaaaIbNbNbNbNbNbNbNbNbNbWabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbcbcbcaabgbgbgbgbgbgbgaQbXbYauaBbobZbjawcacbccaEbBbKcdcecfawawaacgbNbNbNbNbNbNbNbNbNaJabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbcbcaaaabgbpbgbeaBbpbgbgaBaBauchaBaUaSawcicjckclcmcncobBaEawawaaaIbNbNbNbNbNbNbNbNbNbWabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoaaaaaaaaaaaaaaaaaoauaucpbnbobnaBbnaBaBauaBaScqcrcsctcuccaEcvcwcxbDaEawawaacgbNbNbNbNbNbNbNbNbNaJabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoaaaaaaauaucybybzbybzczaBaBaucAaBcBaBawawawawbTaEcCaEcDbtawawaaaIbNbNbNbNbNbNbNbNbNbWabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoaaaaaaaabNcEaKaLaLcFcGaBaBaSaBaBcHaucIaBcBcJawcKcLawcMaEcCaEcNaEawawaacgbNbNbNbNbNbNbNbNbNaJabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacOabababauauayayayayaycPcQcRcScTcTcUcVcWcXcYcWcZdadbdcdddcbLbLbMbNbNbNbNbNbNbNbNbNbNbWabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadeadaaaaaadedededededededededededededededededfdededededededededededededededededededededededeabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadededgdgdgdededededededededededededededededededhdedededededededededededededededededededededededeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadededidjdjdjdjdjdjdjdjdkdldmdndodjdpdqdjdrdsdldtdudjdmdjdvdwdwdjdvdjdjdjdjdtdxdjdydzdjdAdBdCdDdedeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadededjdjdEdFdjdGdjdHdjdjdkdjdIdEdjdJdjdjdKdjdLdjdtdudjdjdmdjdjdEdjdjdMdjdjdNdtdOdPdjdjdjdjdjdjdjdQdedeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadedededjdjdodjdjdjdjdgdgdgdgdgdHdRdSdRdTdUdVdWdRdXdjdtdudjdmdjdjdjdjdEdjdjdjdjdYdtdZdjdjdjdjdjdjeadjdQebdedeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadedededjdGdjdjdjdmdjdjdgdgdgdgdgdgdjdjdjdjdjdjdjdjeceddtdudjdjdjdjdMdjdjdjdjeceddYdtdjdjdjdjdjdjdjdjdjdjdjeedededeababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababefdedjdFdjdjdFegehehdgdHeidgdgdgejejejejejejejejejekelemeneoeoeoeoeoeoeoeoeoepeleqemerdjdjeceddjdjdjdjdjesdedededeaaaaaaaaaaaaapapapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapaaaaaaaaaaaaetdedgdgdjdjdidYdjdjdjdjeudgdHdgdgdjdjdjdjdmdjdjdjdjdjeveuewdjdjdjdjdjdjdjdjdjdjdjdtexeyeoezeAeoeoeBeCejejeDeEeFeGeHeHeHeHeHeHeHeIapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeHeHeHeHeHeHeHeHeFeJejejejejeKeLeLeLeMeNeOdmdgdjdjePePeQeReSeOePdjdjdeeTdeeUeeeeeeeeeeeUeVeWeXdAdteYeZfadtdtdtdtdtfbdtdtdedededefcaaaaaaaaaaapapapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapapaaaaaaaaaaaaaadgdHdgdjdjdjdYdjdjdjdjdedededededededededededededededefddedededededededededededededededefefffgfhfifjfififhfifkflababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaadgdjdidieOdjdYdjdjfmdededededededededededededededededefndedededededededededededededededefkfffofpfqfrfsfifififkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaftaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufufufufufufvfufufufufuaaacaaaaaaaaaaaaaaaaaaaaaaaadgfwdgaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkfxfyfififjfifififzfkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoaafufufAfBfCfBfDfEfAfFfGfufuacacacacacacacacacacacacacacdjfHdjacacacacacacacacacacacacacacfkfkfffofIfgfjfififififkfkfJfJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufufAfKfLfMfNfOfAfPfAfufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkfifQfifRfSfTfUfVfUfWfWfXfJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufufYfBfZgafAfOfAgbgagcgcaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkfigdfigefjgefigefifkfkfJfJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufufufufufufufugffBgggafAfOfBfZgagcgcaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkghgigjgkfSfTfUglfifkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufufufufufufufugmfBgngafAfOfAgogagcgcacgpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagqacfkfkgjgrfififjgefififzfkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufugsgtgugvgwfugffBfZgafAfOfAgogafufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkgxgyfififjgzfifififkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagcgcgAgvgvgvgvfugffBgogafAfOfBfZgafufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkgBgCfifigDgEgFfififkfkaaaaaaaaaaaaaaaoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagcgcgGgHgIgJgKfugffBfBfBfAfOfAgogafufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkfifififigLgMgNfififkfkefabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufugOgPgPgPgPfugQgRgRfBfBgSfAfAfAfufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkfefefefefefegTfkfkfkfkfcaaaaapapapapaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufugUgVgWgXgYfugRgZhafAfAfOfAhbgagcgcaaacaaaaaaaaaaaaaaaaaaaaaaaahcaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkhdhehdfefifihfhghhhihjhkhkhkhkhkhlapacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufuhmfAfAfAhnfuhohphqhrfAfOfBfZgagcgcacgpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagqacfkfkhdhshdfehtfifjfkfkfkhuaaaaaaaphvaaapadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufugUfAfAfAhwfugRhxhafAfAfOfAhygagcgcaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkhdhshdfefifihzfihAfkfkaaaaacapapapapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufuhBfAfAfAhCfuhDgRgRfBhEfOhFfAfFfufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkhdhshdfehGhHhIfihAfkfkababababaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagcgchJgvhKfAfAfufAfBhLhMhMhMhEgogafufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkhdhNhdfehOhPhIfihQfkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagcgchRhShThUhUhVhWhXhYhMhMhMhMfZgafufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkhdhshdfehOhPhIfigjfkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufuhZiaibfAfAfufAicfZhEhMhMidgogafufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkhdhsiefeifighIfififkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufufufufufufufuhFfBgogahFhMhMhygagcgcacgpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagqacfkfkihiiijikiliminfififkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufufufufufufuhMiofBgogafAhMhEfZgagcgcaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaipipiqiqiqiqiriqiqiqiqipipaaisaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahMfAfBfZgafAitfAgngagcgcaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaipipiuiviwiqixiqiyiziAipipaaiBaaaaaaaaaaaaaaaaaoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiCfAfBiDgafAitfAfAfAfufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaipipiuiqiqiqixiqiEiFiuipaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacOfuhFfBfBfBfBitfAiGfGfufuacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacipipiHiviIiqixiqiuiJiFipaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoaaaafufufufufufufuiKfufufufufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaipipiuiqiqiqixiqiFiuiuacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiBaafuipiLiqiMiNiqiOiPiQiRipipipipipipipipipipipipipipipipipipiSiSipipiSiSipipipipipipipipipipipiuiTiUiqiViqiWiXiuaaaaaacOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababipiYiTiZjajbjcjdjdjejeipipipipipipipipipipipipipipipipipjfjfipipjfjfipipipipipipipipipipiqiuiqiqiqjgjhjijjjkjlabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabapapapaaaaacaaaaaaetipipipiqiqiqjcjdjdjmjniqjojpiqjojqiqjojqiqjrjpiqjojqiqjsjtjtjujsjtjvjwjdjxjyjziuiuiTjAjBiqiuiujCiqixiqiqjDjljlaaaaaaaaaaaaaaapapaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabapjEapapapapapapapapjFjGjHjIjIjJjKjdjdjLjMiqjdjNiqjdjOiqjdjPiqjdjQiqjdjRiqjsjSjTjwjsjtjUjwjdjViuiuiujViqjWjBiqjXiujYiqjZkakbkckckckdapkekekekekeapaaapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabapapapaaaaacaaaaaaaaipipipkfjdjdkgjdjdkhkhiqkiiqiqkiiqiqkiiqiqkiiqiqkiiqiqjdjdkjkkkljdjdjdjdkmiuiuiukniqkokpiqkqkrksiqktkcjlkuipipaaaaaaaaaaaaaaaaapapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababipipipkvjdjdkwkxkxkxkykzkxkAkBkxkxkxkxkAkxkxkxkxkxkAkCkxkDkxkEkFkGkxkxkHiqiujVkIkJiqkKkLiqkMiqiqiqixkckcipipipababababababaaaaabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaipipipkNkOkPkQkRjdkSiqkiiqiqkiiqiqkiiqiqkiiqiqkTiqiqjdjdjdjdjdjdjdjdkgiqiTiqiqiqiqiqiqiqkUkxkxkxkujljlipipaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaipipkVjdjdjdjdjdkWiqjdkXiqjdkYiqjdjQiqjdkZiqjdlaiqjslblcjwjsldjUjwkwkxkxkxkxkxkxkxkxlelfjdjdipkcjllgipipaaaaaaaaaaaoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaipiplhjdliljjdkWiqlkjqiqlljqiqlkjqiqlkjqiqlkjqiqjsjtlmjwjsjtjtjwlnkWkWkWkWloiRlplqiqlrjdlsjljDjlipipaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaipipiSipipiSipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipjljlkcipaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaltaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaipipiSipipiSipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaluajajajajajajajajaaaaajlvabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaisaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaalwlwlwlwlwlwlwlwlwlwaaagaalwlwlwlwlwisaaaalwlwaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaahaiaiaiaiaiaiaiaiaiajlxajalalalalalaaaaalalamaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaalylylylylylylylylylyaaagaalylylylyaaaalylylylyaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaalwlwlwlwlwlwlwlwlwlwapagaplwlwlwaaaalwlwlwlwlwaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaahaiaiaiaiaiaiaiaiaiajlxajalalalalalalalalalamaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaalylylylylylylylylylyapagaplyaaaaaalylylylylylyaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaalwlwlwlwlwlwlwlwlwlwaaagaaaaaaaalwlwlwlwlwlwlwaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaahaiaiaiaiaiaiaiaiaiajlzajaaaaisalalalalalalamaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaalylylylylylylylylylyaaaaaaaalylylylylylylylylyaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababaaaaaaaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/magshield/magshield.dm b/maps/away/magshield/magshield.dm new file mode 100644 index 00000000..04a15f12 --- /dev/null +++ b/maps/away/magshield/magshield.dm @@ -0,0 +1,182 @@ +#include "magshield_areas.dm" + +/obj/effect/overmap/sector/magshield + name = "orbital station" + desc = "Sensors detect an orbital station above the exoplanet. Sporadic magentic impulses are registred inside it. Planet landing is impossible due to lower orbits being cluttered with chaotically moving metal chunks." + icon_state = "object" + known = 0 + + generic_waypoints = list( + "nav_magshield_1", + "nav_magshield_2", + "nav_magshield_3", + "nav_magshield_4", + "nav_magshield_antag" + ) + +/datum/map_template/ruin/away_site/magshield + name = "Magshield" + id = "awaysite_magshield" + description = "It's an orbital shield station." + suffixes = list("magshield/magshield.dmm") + cost = 1 + +/obj/effect/shuttle_landmark/nav_magshield/nav1 + name = "Orbital Station Navpoint #1" + landmark_tag = "nav_magshield_1" + +/obj/effect/shuttle_landmark/nav_magshield/nav2 + name = "Orbital Station Navpoint #2" + landmark_tag = "nav_magshield_2" + +/obj/effect/shuttle_landmark/nav_magshield/nav3 + name = "Orbital Station Navpoint #3" + landmark_tag = "nav_magshield_3" + +/obj/effect/shuttle_landmark/nav_magshield/nav4 + name = "Orbital Station Navpoint #4" + landmark_tag = "nav_magshield_4" + +/obj/effect/shuttle_landmark/nav_magshield/nav5 + name = "Orbital Station Navpoint #5" + landmark_tag = "nav_magshield_antag" + +/obj/structure/magshield/maggen + name = "magnetic field generator" + desc = "A large three-handed generator with rotating top. It is used to create high-power magnetic fields in hard vacuum." + icon = 'magshield_sprites.dmi' + icon_state = "maggen" + anchored = 1 + density = 1 + light_range = 3 + light_power = 3 + light_color = "#ffea61" + var/heavy_range = 10 + var/lighter_range = 20 + var/chance = 0 + var/being_stopped = 0 + +/obj/structure/magshield/maggen/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/structure/magshield/maggen/Destroy() + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/structure/magshield/maggen/Process() + var/eye_safety = 0 + chance = rand(1,300)//I wanted to use Poisson distribution with Lambda for 5 minutes but made it simpler + if (chance == 1) + empulse(src, heavy_range, lighter_range, 0) + var/turf/T = get_turf(src) + var/area/A = get_area(src) + log_game("EMP with size ([heavy_range], [lighter_range]) in area [A] ([T.x], [T.y], [T.z])") + visible_message("\the [src] suddenly activates.", "Few lightnings jump between [src]'s rotating hands. You feel everything metal being pulled towards \the [src].") + for(var/mob/living/carbon/M in hear(10, get_turf(src))) + eye_safety = M.eyecheck() + if(eye_safety < FLASH_PROTECTION_MODERATE) + M.flash_eyes() + M.Stun(2) + +/obj/structure/magshield/maggen/attack_hand(mob/user) + ..() + to_chat(user, " You don't see how you could turn off \the [src]. You can try to stick something in rotating hands.") + +/obj/structure/magshield/maggen/attackby(obj/item/W as obj, mob/user as mob) + if (being_stopped) + to_chat(user, " Somebody is already interacting with \the [src].") + return + if(istype(W, /obj/item/stack/rods)) + var/obj/item/stack/rods/R = W + to_chat(user, " You start to stick [R.singular_name] into rotating hands to make them stuck.") + being_stopped = 1 + if (!do_after(user, 100, src)) + to_chat(user, " You pull back [R.singular_name].") + being_stopped = 0 + return + R.use(1) + visible_message("\The [src] stops rotating and releases cloud of sparks. Better get to safe distance!") + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(10, 0, src) + s.start() + sleep(50) + visible_message("\The [src] explodes!") + var/turf/T = get_turf(src) + explosion(T, 2, 3, 4, 10, 1) + empulse(src, heavy_range*2, lighter_range*2, 1) + qdel(src) + if(istype(W, /obj/item/weapon/mop)) + to_chat(user, " You stick [W] into rotating hands. It breaks to smallest pieces.") + qdel(W) + +/obj/structure/magshield/rad_sensor + name = "radiation sensor" + desc = "Very sensitive vacuum radiation sensor. On top of the metal stand two modified Wilson Cloud Chambers filled with deuterium and tritium water." + icon = 'magshield_sprites.dmi' + icon_state = "rad_sensor" + anchored = 1 + +/obj/structure/magshield/nav_light + name = "navigation light" + desc = "Large and bright light regularly emitting green flashes." + icon = 'magshield_sprites.dmi' + icon_state = "nav_light_green" + anchored = 1 + density = 1 + light_range = 10 + light_power = 10 + light_color = "#00ee00" + +/obj/structure/magshield/nav_light/New()//try make flashing through the process + ..() + set_light(light_range, light_power, light_color) + +/obj/structure/magshield/nav_light/red + desc = "Large and bright light regularly emitting red flashes." + light_color = "#ee0000" + icon_state = "nav_light_red" + + +/obj/item/weapon/book/manual/magshield_manual + name = "SOP for Planetary Shield Orbital Station" + icon = 'magshield_sprites.dmi' + icon_state = "mg_guide" + author = "Terraforms Industrial" + title = "Standard operating procedures for Planetary Shield Orbital Station" + + dat = {" + + + + + +

            Introduction

            + Terraforms Industrial is happy to see you as our customer! Please read this guide before using and operating with your custom PSOS - Planetary Shield Orbital Statiion. +

            Best uses for PSOS

            + PSOS is intended for protecting exoplanets from high energy space radiation rays and particles. Best used for planets lacking active geomagnetic field so PSOS would compensate its absence.
            +

            Applied technologies

            + Terraforms Industrial is delivering you your new PSOS with set of four (4) high-strength magnetic field generators. Those devices use rotating supeconducter hands to create magnetic field with strength up to 5 Tesla effectively deflecting up to 99% of space radiation spectrum.
            +
            + Special modified vacuum radiation sensors will help you evaluate radiation level and adjust power input of PSOS magnetic generators for best efficiency and power saving. +


            + rest of the book pages are gone + + + "} + +/obj/item/weapon/paper/magshield/tornpage + name = "torn book page" + info = "...you must carefully control radiation sensor automatics during solar flares. Sudden burst of high-energy plasma may cause positive feedback loop and increase magnetic genretors output in order of magnitude. This situation would lead to general damage of unprotected electronic devices as well as trajectory changes in nearby nickel-ferrum astero#&$" + +/obj/item/weapon/paper/magshield/log + name = "printed page" + info = "\[07:31\] Attention: solar flare detected! Automatic countermeasures activated.
            \[07:33\] Warning: ERROR: NULL input at FARADAY_CAGE#12.TFI - line 2067: No command found. System will be rebooted.
            \[07:39\] Warning: radiaton countermeasures inactive. Please initiate emergency protocol.
            \[07:40\] Warning: radiaton countermeasures inactive. Please initiate emergency protocol.
            \[07:41\] Warning: radiaton countermeasures inactive. Please initiate emergency protocol.
            \[07:45\] Attention! Multiple systems failure. Please initiate emergency protocol
            \[07:52\] Warning: LIDAR-ASTRA system detected multiple meteors approaching. Estimate impact time: 12.478 seconds.
            \[07:52\] Warning! Miltiple hull breaches det~!!@#" diff --git a/maps/away/magshield/magshield.dmm b/maps/away/magshield/magshield.dmm new file mode 100644 index 00000000..13b3850e --- /dev/null +++ b/maps/away/magshield/magshield.dmm @@ -0,0 +1,802 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/obj/structure/grille,/turf/space,/area/space) +"ac" = (/obj/structure/lattice,/turf/space,/area/space) +"ad" = (/obj/item/weapon/ore,/turf/space,/area/space) +"ae" = (/obj/machinery/power/tracker,/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/airless,/area/space) +"af" = (/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/power/solar{id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"ag" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/space) +"ah" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless,/area/space) +"ai" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"aj" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"ak" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless,/area/space) +"al" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"am" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/space) +"an" = (/obj/structure/cable/yellow,/obj/machinery/power/solar{id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"ao" = (/obj/item/stack/rods,/turf/space,/area/space) +"ap" = (/turf/simulated/floor/airless,/area/space) +"aq" = (/obj/machinery/power/solar{id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array"},/obj/structure/cable/yellow,/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"ar" = (/turf/simulated/wall/r_wall,/area/space) +"as" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/access_button{pixel_x = -25; pixel_y = -25},/turf/simulated/floor/airless,/area/space) +"at" = (/obj/machinery/light/small,/turf/space,/area/space) +"au" = (/turf/simulated/wall/r_wall,/area/magshield/smes_storage) +"av" = (/obj/machinery/door/airlock/external/bolted_open,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aw" = (/turf/simulated/wall/r_wall,/area/magshield/engine) +"ax" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/unary/vent_pump/high_volume,/obj/effect/floor_decal/industrial/hatch/blue,/obj/machinery/embedded_controller/radio/airlock/airlock_controller{pixel_x = 25},/obj/machinery/airlock_sensor{pixel_x = -25; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"ay" = (/obj/structure/table/steel,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"az" = (/obj/structure/table/steel,/obj/random/tool,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aA" = (/obj/structure/table/steel,/obj/random/junk,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aB" = (/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aC" = (/obj/structure/table/rack,/obj/random/voidsuit,/obj/random/voidhelmet,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aD" = (/obj/machinery/door/airlock/external/bolted_open,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aE" = (/turf/simulated/floor/airless,/area/magshield/engine) +"aF" = (/obj/machinery/portable_atmospherics/canister/carbon_dioxide,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"aG" = (/obj/machinery/atmospherics/pipe/tank/carbon_dioxide,/turf/simulated/floor/airless,/area/magshield/engine) +"aH" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "prototype_chamber_blast"},/turf/simulated/floor/airless,/area/magshield/engine) +"aI" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 6; icon_state = "intact"},/turf/space,/area/space) +"aJ" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{icon_state = "intact"; dir = 10},/turf/space,/area/space) +"aK" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{dir = 8; icon_state = "intact"},/turf/space,/area/space) +"aL" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{dir = 4},/turf/simulated/wall/r_wall,/area/magshield/smes_storage) +"aM" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aN" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/unary/vent_pump{dir = 8; external_pressure_bound = 0; external_pressure_bound_default = 0; frequency = 1441; icon_state = "map_vent_in"; id_tag = "tox_out"; initialize_directions = 1; internal_pressure_bound = 4000; internal_pressure_bound_default = 4000; pressure_checks = 2; pressure_checks_default = 2; pump_direction = 0; use_power = 1},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aO" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aP" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/item/weapon/ore,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aQ" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aR" = (/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aS" = (/obj/random/junk,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aT" = (/obj/structure/sign/warning/airlock{pixel_y = 30},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aU" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"aV" = (/obj/machinery/portable_atmospherics/canister/carbon_dioxide,/turf/simulated/floor/airless,/area/magshield/engine) +"aW" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 5},/turf/simulated/floor/airless,/area/magshield/engine) +"aX" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/black,/turf/simulated/floor/airless,/area/magshield/engine) +"aY" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 9},/turf/simulated/floor/airless,/area/magshield/engine) +"aZ" = (/obj/machinery/door/airlock/hatch,/obj/machinery/door/blast/regular/open{dir = 4; icon_state = "pdoor0"; id = "prototype_chamber_blast"},/turf/simulated/floor/airless,/area/magshield/engine) +"ba" = (/obj/machinery/mass_driver{dir = 4; id = "enginecore"},/turf/simulated/floor/airless,/area/magshield/engine) +"bb" = (/obj/machinery/door/blast/regular/open{dir = 1; icon_state = "pdoor0"; id = "prototype_chamber_blast"},/turf/simulated/floor/airless,/area/magshield/engine) +"bc" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging,/turf/space,/area/space) +"bd" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"be" = (/obj/machinery/power/terminal,/obj/structure/cable/yellow,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bf" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bg" = (/turf/space,/area/magshield/smes_storage) +"bh" = (/obj/structure/closet/crate/plastic,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/random/loot,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bi" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bj" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bk" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/turf/simulated/floor/airless,/area/magshield/engine) +"bl" = (/obj/machinery/atmospherics/unary/vent_pump,/turf/simulated/floor/airless,/area/magshield/engine) +"bm" = (/obj/machinery/atmospherics/unary/outlet_injector,/turf/simulated/floor/airless,/area/magshield/engine) +"bn" = (/obj/machinery/power/smes/buildable/outpost_substation,/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bo" = (/obj/item/weapon/ore,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bp" = (/obj/structure/lattice,/turf/space,/area/magshield/smes_storage) +"bq" = (/obj/structure/closet,/obj/random/junk,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"br" = (/obj/machinery/portable_atmospherics/canister,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/airless,/area/magshield/engine) +"bs" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 6},/turf/simulated/floor/airless,/area/magshield/engine) +"bt" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"bu" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/blast/regular/open{dir = 1; icon_state = "pdoor0"; id = "prototype_chamber_blast"},/obj/machinery/atmospherics/pipe/simple/visible/cyan,/turf/simulated/floor/airless,/area/magshield/engine) +"bv" = (/obj/effect/wingrille_spawn/reinforced_phoron/full,/obj/machinery/door/blast/regular/open{dir = 1; icon_state = "pdoor0"; id = "prototype_chamber_blast"},/turf/simulated/floor/airless,/area/magshield/engine) +"bw" = (/obj/effect/shuttle_landmark/nav_magshield/nav2,/turf/space,/area/space) +"bx" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"by" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bz" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bA" = (/obj/structure/closet,/obj/item/toy/therapy_purple,/obj/random/hat,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bB" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan,/turf/simulated/floor/airless,/area/magshield/engine) +"bC" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{icon_state = "intact"; dir = 6},/turf/simulated/floor/airless,/area/magshield/engine) +"bD" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{icon_state = "intact"; dir = 9},/turf/simulated/floor/airless,/area/magshield/engine) +"bE" = (/obj/item/weapon/ore,/turf/space,/area/magshield/smes_storage) +"bF" = (/obj/item/stack/rods,/turf/space,/area/magshield/smes_storage) +"bG" = (/obj/structure/closet,/obj/item/device/flashlight/glowstick/random,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bH" = (/obj/machinery/atmospherics/portables_connector{dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"bI" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"bJ" = (/obj/machinery/atmospherics/pipe/manifold/visible/cyan{dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"bK" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 6},/turf/simulated/floor/airless,/area/magshield/engine) +"bL" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/turf/simulated/wall/r_wall,/area/magshield/engine) +"bM" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{icon_state = "intact"; dir = 4},/turf/space,/area/space) +"bN" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{icon_state = "intact"; dir = 4},/turf/space,/area/space) +"bO" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging,/obj/item/weapon/ore,/turf/space,/area/space) +"bP" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bQ" = (/obj/structure/table/steel,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bR" = (/obj/structure/table/steel,/obj/random/drinkbottle,/obj/random/tool,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bS" = (/obj/structure/closet/crate/trashcart,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bT" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/airless,/area/magshield/engine) +"bU" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{dir = 4; icon_state = "intact"},/turf/simulated/floor/airless,/area/magshield/engine) +"bV" = (/obj/machinery/atmospherics/pipe/simple/visible/red,/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"bW" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{icon_state = "intact"; dir = 9},/turf/space,/area/space) +"bX" = (/obj/item/modular_computer/console,/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bY" = (/obj/structure/bed/chair{dir = 8},/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"bZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/random/junk,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"ca" = (/obj/structure/table/steel,/obj/item/device/geiger,/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/airless,/area/magshield/engine) +"cb" = (/obj/item/modular_computer/console,/turf/simulated/floor/airless,/area/magshield/engine) +"cc" = (/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "EngineBlast"; name = "Engine Monitoring Room Blast Doors"; opacity = 0},/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/plating,/area/magshield/engine) +"cd" = (/obj/machinery/atmospherics/binary/circulator{anchored = 1; dir = 4},/turf/simulated/floor/plating,/area/magshield/engine) +"ce" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/obj/machinery/atmospherics/pipe/simple/visible/cyan,/turf/simulated/floor/airless,/area/magshield/engine) +"cf" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 9},/turf/simulated/floor/airless,/area/magshield/engine) +"cg" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 5; icon_state = "intact"},/turf/space,/area/space) +"ch" = (/obj/structure/closet/crate/hydroponics/prespawned,/obj/random/gloves,/turf/simulated/floor/plating,/area/magshield/smes_storage) +"ci" = (/obj/structure/bed/chair{dir = 4},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless,/area/magshield/engine) +"cj" = (/obj/item/modular_computer/console,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/magshield/engine) +"ck" = (/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "EngineBlast"; name = "Engine Monitoring Room Blast Doors"; opacity = 0},/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/magshield/engine) +"cl" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/magshield/engine) +"cm" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/magshield/engine) +"cn" = (/obj/machinery/atmospherics/binary/pump,/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/magshield/engine) +"co" = (/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/power/generator{anchored = 1; dir = 2},/turf/simulated/floor/plating,/area/magshield/engine) +"cp" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cq" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cr" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cs" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"ct" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/airless,/area/magshield/engine) +"cu" = (/obj/item/modular_computer/console,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/turf/simulated/floor/airless,/area/magshield/engine) +"cv" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{icon_state = "intact"; dir = 5},/turf/simulated/floor/airless,/area/magshield/engine) +"cw" = (/obj/machinery/atmospherics/pipe/simple/visible/red,/obj/machinery/atmospherics/pipe/simple/visible/cyan{dir = 4; icon_state = "intact"},/turf/simulated/floor/airless,/area/magshield/engine) +"cx" = (/obj/machinery/atmospherics/binary/circulator{anchored = 1; dir = 8},/turf/simulated/floor/plating,/area/magshield/engine) +"cy" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cz" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cA" = (/obj/item/device/flashlight/glowstick/yellow,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cB" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cC" = (/obj/machinery/atmospherics/pipe/simple/visible/red,/turf/simulated/floor/airless,/area/magshield/engine) +"cD" = (/obj/machinery/atmospherics/portables_connector,/turf/simulated/floor/airless,/area/magshield/engine) +"cE" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{icon_state = "intact"; dir = 4},/obj/item/weapon/ore,/turf/space,/area/space) +"cF" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{dir = 4},/obj/machinery/light/small{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/item/weapon/ore,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cG" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 8; frequency = 1441; icon_state = "map_injector"; id = "n2o_in"; pixel_y = 1; use_power = 1},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cH" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cI" = (/obj/structure/closet,/obj/random/gloves,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cJ" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/random/junk,/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cK" = (/obj/structure/table/steel,/obj/item/clothing/head/radiation,/obj/item/weapon/wrench,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless,/area/magshield/engine) +"cL" = (/obj/structure/closet,/obj/item/clothing/suit/radiation,/obj/item/device/flashlight,/turf/simulated/floor/airless,/area/magshield/engine) +"cM" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/airless,/area/magshield/engine) +"cN" = (/obj/machinery/atmospherics/binary/pump,/turf/simulated/floor/airless,/area/magshield/engine) +"cO" = (/obj/structure/girder/displaced,/turf/space,/area/space) +"cP" = (/obj/structure/table/steel,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cQ" = (/obj/structure/table/steel,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/random/tool,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cR" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cS" = (/obj/machinery/door/airlock,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cT" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cU" = (/obj/structure/cable{icon_state = "2-8"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cV" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/smes_storage) +"cW" = (/obj/machinery/door/airlock/hatch,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/engine) +"cX" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/engine) +"cY" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/mob/living/simple_animal/hostile/carp,/turf/simulated/floor/airless,/area/magshield/engine) +"cZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/engine) +"da" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/obj/machinery/power/apc{dir = 2; name = "south bump"; operating = 1; pixel_y = -24},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless,/area/magshield/engine) +"db" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 5},/turf/simulated/floor/airless,/area/magshield/engine) +"dc" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/turf/simulated/floor/airless,/area/magshield/engine) +"dd" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/obj/machinery/atmospherics/pipe/manifold/visible/red,/turf/simulated/floor/airless,/area/magshield/engine) +"de" = (/turf/simulated/wall/r_wall,/area/magshield/north) +"df" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/door/airlock,/turf/simulated/floor/airless,/area/magshield/north) +"dg" = (/turf/space,/area/magshield/north) +"dh" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/random/obstruction,/turf/simulated/floor/airless,/area/magshield/north) +"di" = (/obj/item/weapon/ore,/turf/simulated/floor/airless,/area/magshield/north) +"dj" = (/turf/simulated/floor/airless,/area/magshield/north) +"dk" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/airless,/area/magshield/north) +"dl" = (/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/airless,/area/magshield/north) +"dm" = (/obj/random/junk,/turf/simulated/floor/airless,/area/magshield/north) +"dn" = (/obj/item/weapon/storage/wallet/random,/turf/simulated/floor/airless,/area/magshield/north) +"do" = (/obj/structure/largecrate,/turf/simulated/floor/airless,/area/magshield/north) +"dp" = (/obj/random/shoes,/turf/simulated/floor/airless,/area/magshield/north) +"dq" = (/obj/machinery/portable_atmospherics/hydroponics,/turf/simulated/floor/airless,/area/magshield/north) +"dr" = (/obj/structure/iv_drip,/turf/simulated/floor/airless,/area/magshield/north) +"ds" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/airless,/area/magshield/north) +"dt" = (/turf/simulated/wall,/area/magshield/north) +"du" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"dv" = (/obj/random/tool,/turf/simulated/floor/airless,/area/magshield/north) +"dw" = (/obj/random/tank,/turf/simulated/floor/airless,/area/magshield/north) +"dx" = (/obj/structure/table/steel,/obj/random/tool,/turf/simulated/floor/airless,/area/magshield/north) +"dy" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless,/area/magshield/north) +"dz" = (/obj/structure/reagent_dispensers/water_cooler,/turf/simulated/floor/airless,/area/magshield/north) +"dA" = (/obj/structure/closet,/obj/random/toolbox,/turf/simulated/floor/airless,/area/magshield/north) +"dB" = (/obj/structure/closet,/obj/random/suit,/turf/simulated/floor/airless,/area/magshield/north) +"dC" = (/obj/structure/closet,/obj/random/smokes,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless,/area/magshield/north) +"dD" = (/obj/structure/closet,/obj/structure/plushie/ian,/obj/random/drinkbottle,/turf/simulated/floor/airless,/area/magshield/north) +"dE" = (/obj/random/material,/turf/simulated/floor/airless,/area/magshield/north) +"dF" = (/obj/item/stack/rods,/turf/simulated/floor/airless,/area/magshield/north) +"dG" = (/obj/structure/girder/displaced,/turf/simulated/floor/airless,/area/magshield/north) +"dH" = (/obj/structure/lattice,/turf/space,/area/magshield/north) +"dI" = (/obj/item/clothing/under/color/lightpurple,/turf/simulated/floor/airless,/area/magshield/north) +"dJ" = (/obj/random/firstaid,/turf/simulated/floor/airless,/area/magshield/north) +"dK" = (/obj/random/toolbox,/turf/simulated/floor/airless,/area/magshield/north) +"dL" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/structure/largecrate,/turf/simulated/floor/airless,/area/magshield/north) +"dM" = (/obj/random/obstruction,/turf/simulated/floor/airless,/area/magshield/north) +"dN" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/turf/simulated/floor/airless,/area/magshield/north) +"dO" = (/obj/item/modular_computer/console,/turf/simulated/floor/airless,/area/magshield/north) +"dP" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/turf/simulated/floor/airless,/area/magshield/north) +"dQ" = (/obj/machinery/field_generator,/turf/simulated/floor/airless,/area/magshield/north) +"dR" = (/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/airless,/area/magshield/north) +"dS" = (/obj/effect/floor_decal/industrial/warning,/obj/random/loot,/turf/simulated/floor/airless,/area/magshield/north) +"dT" = (/obj/effect/floor_decal/industrial/warning,/obj/structure/largecrate,/turf/simulated/floor/airless,/area/magshield/north) +"dU" = (/obj/effect/floor_decal/industrial/warning,/obj/random/junk,/turf/simulated/floor/airless,/area/magshield/north) +"dV" = (/obj/effect/floor_decal/industrial/warning,/obj/item/weapon/flame/lighter,/turf/simulated/floor/airless,/area/magshield/north) +"dW" = (/obj/effect/floor_decal/industrial/warning,/obj/random/tank,/turf/simulated/floor/airless,/area/magshield/north) +"dX" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 6},/obj/random/toolbox,/turf/simulated/floor/airless,/area/magshield/north) +"dY" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"dZ" = (/obj/structure/table/steel,/obj/random/powercell,/obj/machinery/cell_charger,/turf/simulated/floor/airless,/area/magshield/north) +"ea" = (/obj/machinery/power/port_gen/pacman/mrs,/turf/simulated/floor/airless,/area/magshield/north) +"eb" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/airless,/area/magshield/north) +"ec" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/airless,/area/magshield/north) +"ed" = (/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/airless,/area/magshield/north) +"ee" = (/obj/structure/table/rack,/obj/random/voidsuit,/obj/random/voidhelmet,/turf/simulated/floor/airless,/area/magshield/north) +"ef" = (/obj/structure/grille,/turf/simulated/wall/r_wall,/area/space) +"eg" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless,/area/magshield/north) +"eh" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"ei" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"ej" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"ek" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"el" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"em" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/airlock,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"en" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/airless,/area/magshield/north) +"eo" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"ep" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eq" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/magshield/north) +"er" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/cable{icon_state = "6-8"},/turf/simulated/floor/airless,/area/magshield/north) +"es" = (/obj/structure/sign/warning/airlock{pixel_x = 30},/turf/simulated/floor/airless,/area/magshield/north) +"et" = (/obj/machinery/light/small{dir = 4},/turf/space,/area/space) +"eu" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/airless,/area/magshield/north) +"ev" = (/obj/structure/sign/warning/airlock{pixel_y = -30},/turf/simulated/wall,/area/magshield/north) +"ew" = (/obj/structure/sign/warning/docking_area{pixel_y = -30},/turf/simulated/floor/airless,/area/magshield/north) +"ex" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/light/small{dir = 8},/turf/simulated/floor/airless,/area/magshield/north) +"ey" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{icon_state = "4-9"},/turf/simulated/floor/airless,/area/magshield/north) +"ez" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/machinery/floodlight,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eA" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/floodlight,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eB" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/light/small,/turf/simulated/floor/airless,/area/magshield/north) +"eC" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/cable{icon_state = "1-8"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eD" = (/obj/machinery/door/airlock/external/bolted,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eE" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1501; id_tag = "asteroid_base_east_pump"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{pixel_x = 0; pixel_y = 25},/obj/machinery/airlock_sensor{pixel_x = 0; pixel_y = -25},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eF" = (/obj/machinery/door/airlock/external/bolted,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eG" = (/obj/machinery/access_button{pixel_x = -25; pixel_y = 25},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eH" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/space) +"eI" = (/obj/structure/magshield/maggen,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless,/area/space) +"eJ" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1380; id_tag = "merchant_station_vent"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"eK" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/magshield/north) +"eL" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless,/area/magshield/north) +"eM" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/item/weapon/newspaper,/turf/simulated/floor/airless,/area/magshield/north) +"eN" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/airless,/area/magshield/north) +"eO" = (/obj/machinery/light_construct/small,/turf/simulated/floor/airless,/area/magshield/north) +"eP" = (/obj/structure/table,/turf/simulated/floor/airless,/area/magshield/north) +"eQ" = (/obj/structure/table/steel,/obj/item/weapon/storage/toolbox/mechanical,/turf/simulated/floor/airless,/area/magshield/north) +"eR" = (/obj/structure/table/steel,/turf/simulated/floor/airless,/area/magshield/north) +"eS" = (/obj/structure/table/steel,/obj/item/weapon/storage/box/lights,/turf/simulated/floor/airless,/area/magshield/north) +"eT" = (/obj/machinery/door/airlock/external/bolted_open,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/access_button{pixel_x = -25; pixel_y = 25},/turf/simulated/floor/airless,/area/magshield/north) +"eU" = (/obj/machinery/light/small,/turf/simulated/floor/airless,/area/magshield/north) +"eV" = (/obj/structure/closet,/obj/random/material,/obj/random/material,/turf/simulated/floor/airless,/area/magshield/north) +"eW" = (/obj/structure/closet,/obj/random/material,/turf/simulated/floor/airless,/area/magshield/north) +"eX" = (/obj/structure/closet,/obj/random/tool,/turf/simulated/floor/airless,/area/magshield/north) +"eY" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/airless,/area/magshield/north) +"eZ" = (/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/airless,/area/magshield/north) +"fa" = (/obj/structure/janitorialcart,/turf/simulated/floor/airless,/area/magshield/north) +"fb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"fc" = (/obj/machinery/light/small{dir = 8},/turf/space,/area/space) +"fd" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1380; id_tag = "centcom_shuttle_dock_pump"},/obj/effect/floor_decal/industrial/hatch/blue,/obj/machinery/embedded_controller/radio/airlock/airlock_controller{pixel_x = 25},/obj/machinery/airlock_sensor{pixel_x = -25; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/north) +"fe" = (/turf/simulated/wall,/area/magshield/east) +"ff" = (/obj/machinery/atmospherics/pipe/tank,/obj/machinery/atmospherics/portables_connector{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"fg" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 10},/turf/simulated/floor/airless,/area/magshield/east) +"fh" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless,/area/magshield/east) +"fi" = (/turf/simulated/floor/airless,/area/magshield/east) +"fj" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/east) +"fk" = (/turf/simulated/wall/r_wall,/area/magshield/east) +"fl" = (/obj/structure/grille,/turf/simulated/wall/r_wall,/area/magshield/north) +"fm" = (/obj/item/weapon/mop,/turf/simulated/floor/airless,/area/magshield/north) +"fn" = (/obj/machinery/door/airlock/external/bolted_open,/turf/simulated/floor/airless,/area/magshield/north) +"fo" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/black,/turf/simulated/floor/airless,/area/magshield/east) +"fp" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"fq" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"fr" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/east) +"fs" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/turf/simulated/floor/airless,/area/magshield/east) +"ft" = (/obj/effect/shuttle_landmark/nav_magshield/nav5,/turf/space,/area/space) +"fu" = (/turf/simulated/wall/r_wall,/area/magshield/west) +"fv" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/west) +"fw" = (/obj/machinery/access_button{pixel_x = -25; pixel_y = 25},/turf/simulated/floor/airless,/area/magshield/north) +"fx" = (/obj/machinery/atmospherics/pipe/tank,/obj/machinery/atmospherics/portables_connector{dir = 4},/obj/machinery/light_construct{dir = 8},/turf/simulated/floor/airless,/area/magshield/east) +"fy" = (/obj/machinery/atmospherics/pipe/manifold/visible/black{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"fz" = (/obj/machinery/light_construct{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"fA" = (/turf/simulated/floor/tiled,/area/magshield/west) +"fB" = (/turf/simulated/floor/tiled/dark,/area/magshield/west) +"fC" = (/obj/machinery/light_construct{dir = 1},/turf/simulated/floor/tiled/dark,/area/magshield/west) +"fD" = (/obj/random/junk,/turf/simulated/floor/tiled/dark,/area/magshield/west) +"fE" = (/obj/structure/cable{icon_state = "1-10"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled/dark,/area/magshield/west) +"fF" = (/obj/machinery/light_construct{dir = 1},/turf/simulated/floor/tiled,/area/magshield/west) +"fG" = (/obj/structure/reagent_dispensers/water_cooler,/turf/simulated/floor/tiled,/area/magshield/west) +"fH" = (/obj/effect/overmap/sector/magshield,/turf/simulated/floor/airless,/area/magshield/north) +"fI" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"fJ" = (/obj/structure/grille,/turf/space,/area/magshield/east) +"fK" = (/obj/structure/cable{icon_state = "4-10"},/turf/simulated/floor/tiled/dark,/area/magshield/west) +"fL" = (/obj/structure/table/steel,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/west) +"fM" = (/obj/item/modular_computer/console,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/west) +"fN" = (/obj/structure/cable{icon_state = "5-8"},/turf/simulated/floor/tiled,/area/magshield/west) +"fO" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled/dark,/area/magshield/west) +"fP" = (/obj/item/weapon/newspaper,/turf/simulated/floor/tiled,/area/magshield/west) +"fQ" = (/obj/machinery/atmospherics/binary/pump{dir = 1},/turf/simulated/floor/airless,/area/magshield/east) +"fR" = (/obj/machinery/atmospherics/omni/mixer,/turf/simulated/floor/airless,/area/magshield/east) +"fS" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/east) +"fT" = (/obj/machinery/atmospherics/omni/filter,/turf/simulated/floor/airless,/area/magshield/east) +"fU" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"fV" = (/obj/machinery/atmospherics/pipe/manifold/visible/red{icon_state = "map"; dir = 1},/turf/simulated/floor/airless,/area/magshield/east) +"fW" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/turf/simulated/wall/r_wall,/area/magshield/east) +"fX" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 8; frequency = 1441; icon_state = "map_injector"; id = "d_n2_in"; use_power = 1},/turf/simulated/floor/airless,/area/magshield/east) +"fY" = (/obj/structure/cable{icon_state = "2-5"},/turf/simulated/floor/tiled,/area/magshield/west) +"fZ" = (/obj/structure/bed/chair/office/dark{dir = 4},/turf/simulated/floor/tiled,/area/magshield/west) +"ga" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/magshield/west) +"gb" = (/obj/structure/table/steel,/obj/item/weapon/material/ashtray/plastic,/obj/random/smokes,/turf/simulated/floor/tiled,/area/magshield/west) +"gc" = (/obj/structure/window/reinforced/full,/obj/machinery/door/firedoor,/obj/structure/grille,/turf/simulated/floor/tiled,/area/magshield/west) +"gd" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/turf/simulated/floor/airless,/area/magshield/east) +"ge" = (/obj/machinery/atmospherics/pipe/simple/visible/red,/turf/simulated/floor/airless,/area/magshield/east) +"gf" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/west) +"gg" = (/obj/structure/table/steel,/obj/random/toy,/turf/simulated/floor/tiled,/area/magshield/west) +"gh" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/airless,/area/magshield/east) +"gi" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 5},/turf/simulated/floor/airless,/area/magshield/east) +"gj" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/airless,/area/magshield/east) +"gk" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 5},/turf/simulated/floor/airless,/area/magshield/east) +"gl" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 9},/turf/simulated/floor/airless,/area/magshield/east) +"gm" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/light_construct{dir = 8},/turf/simulated/floor/tiled,/area/magshield/west) +"gn" = (/obj/structure/table/steel,/obj/item/weapon/reagent_containers/food/drinks/coffee,/turf/simulated/floor/tiled,/area/magshield/west) +"go" = (/obj/structure/table/steel,/turf/simulated/floor/tiled,/area/magshield/west) +"gp" = (/obj/structure/magshield/nav_light/red{dir = 4},/turf/simulated/floor/airless,/area/space) +"gq" = (/obj/structure/magshield/nav_light{dir = 8},/turf/simulated/floor/airless,/area/space) +"gr" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"gs" = (/obj/structure/closet,/obj/random/cash,/obj/random/cash,/obj/random/clothing,/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gt" = (/obj/structure/closet,/obj/item/weapon/storage/wallet/leather,/obj/random/clothing,/obj/random/smokes,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gu" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gv" = (/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gw" = (/obj/structure/bed,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gx" = (/obj/machinery/light_construct{dir = 8},/turf/simulated/floor/airless,/area/magshield/east) +"gy" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/airless,/area/magshield/east) +"gz" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal,/turf/simulated/floor/airless,/area/magshield/east) +"gA" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gB" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/airless,/area/magshield/east) +"gC" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 6},/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/airless,/area/magshield/east) +"gD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/east) +"gE" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/airless,/area/magshield/east) +"gF" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/airless,/area/magshield/east) +"gG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gH" = (/obj/structure/table/woodentable{dir = 10},/obj/item/weapon/storage/box/checkers,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gI" = (/obj/structure/table/woodentable{dir = 10},/obj/item/weapon/storage/belt/champion,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gJ" = (/obj/structure/table/woodentable{dir = 10},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gK" = (/obj/structure/table/woodentable{dir = 10},/obj/item/weapon/storage/bible/booze,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"gL" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless,/area/magshield/east) +"gM" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/east) +"gN" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/cable{icon_state = "2-8"},/turf/simulated/floor/airless,/area/magshield/east) +"gO" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/magshield/west) +"gP" = (/turf/simulated/wall,/area/magshield/west) +"gQ" = (/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable,/turf/simulated/floor/tiled/white,/area/magshield/west) +"gR" = (/turf/simulated/floor/tiled/white,/area/magshield/west) +"gS" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/random/junk,/turf/simulated/floor/tiled/dark,/area/magshield/west) +"gT" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/east) +"gU" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/magshield/west) +"gV" = (/obj/structure/bookcase/manuals/xenoarchaeology,/turf/simulated/floor/tiled,/area/magshield/west) +"gW" = (/obj/structure/bookcase/manuals/engineering,/turf/simulated/floor/tiled,/area/magshield/west) +"gX" = (/obj/structure/bookcase/manuals/medical,/turf/simulated/floor/tiled,/area/magshield/west) +"gY" = (/obj/structure/table/woodentable,/obj/random/action_figure,/turf/simulated/floor/tiled,/area/magshield/west) +"gZ" = (/obj/structure/table/steel,/obj/item/weapon/reagent_containers/food/drinks/coffee,/obj/random/smokes,/turf/simulated/floor/tiled/white,/area/magshield/west) +"ha" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled/white,/area/magshield/west) +"hb" = (/obj/structure/table/steel,/obj/random/glasses,/turf/simulated/floor/tiled,/area/magshield/west) +"hc" = (/obj/effect/shuttle_landmark/nav_magshield/nav1,/turf/space,/area/space) +"hd" = (/obj/machinery/portable_atmospherics/hydroponics,/turf/simulated/floor/tiled,/area/magshield/east) +"he" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/magshield/east) +"hf" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/airless,/area/magshield/east) +"hg" = (/obj/machinery/door/airlock/external/bolted_open,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"hh" = (/obj/machinery/embedded_controller/radio/airlock/airlock_controller{pixel_x = 0; pixel_y = 25},/obj/machinery/airlock_sensor{pixel_x = 0; pixel_y = -25},/turf/simulated/floor/airless,/area/magshield/east) +"hi" = (/obj/structure/lattice,/turf/space,/area/magshield/east) +"hj" = (/obj/machinery/access_button{pixel_x = -25; pixel_y = -25},/obj/structure/lattice,/turf/space,/area/magshield/east) +"hk" = (/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"hl" = (/obj/structure/magshield/rad_sensor,/obj/structure/cable/cyan{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless,/area/space) +"hm" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/west) +"hn" = (/obj/structure/table/woodentable,/obj/item/weapon/material/sword/replica,/turf/simulated/floor/tiled,/area/magshield/west) +"ho" = (/obj/machinery/light_construct{dir = 8},/turf/simulated/floor/tiled/white,/area/magshield/west) +"hp" = (/obj/structure/bed/chair/comfy/captain,/turf/simulated/floor/tiled/white,/area/magshield/west) +"hq" = (/obj/item/modular_computer/console,/obj/item/weapon/paper/magshield/log,/turf/simulated/floor/tiled/white,/area/magshield/west) +"hr" = (/obj/random/junk,/turf/simulated/floor/tiled,/area/magshield/west) +"hs" = (/turf/simulated/floor/tiled,/area/magshield/east) +"ht" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/airless,/area/magshield/east) +"hu" = (/turf/space,/area/magshield/east) +"hv" = (/obj/item/weapon/ore/slag,/turf/simulated/floor/airless,/area/space) +"hw" = (/obj/structure/table/woodentable,/obj/random/plushie/large,/turf/simulated/floor/tiled,/area/magshield/west) +"hx" = (/obj/structure/table/steel,/obj/item/weapon/material/ashtray/bronze,/turf/simulated/floor/tiled/white,/area/magshield/west) +"hy" = (/obj/structure/table/steel,/obj/random/smokes,/turf/simulated/floor/tiled,/area/magshield/west) +"hz" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{icon_state = "1-10"},/turf/simulated/floor/airless,/area/magshield/east) +"hA" = (/obj/structure/table/rack,/obj/random/voidsuit,/obj/random/voidhelmet,/turf/simulated/floor/airless,/area/magshield/east) +"hB" = (/obj/structure/safe,/obj/random/coin,/obj/random/contraband,/obj/random/energy,/obj/item/weapon/grenade/fake,/obj/random/cash,/obj/random/cash,/obj/random/cash,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/magshield/west) +"hC" = (/obj/structure/table/woodentable,/obj/item/toy/torchmodel,/turf/simulated/floor/tiled,/area/magshield/west) +"hD" = (/obj/item/weapon/book/manual/magshield_manual,/turf/simulated/floor/tiled/white,/area/magshield/west) +"hE" = (/obj/structure/lattice,/turf/space,/area/magshield/west) +"hF" = (/obj/item/weapon/ore,/turf/simulated/floor/tiled,/area/magshield/west) +"hG" = (/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable{icon_state = "0-2"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/turf/simulated/floor/airless,/area/magshield/east) +"hH" = (/obj/structure/cable{icon_state = "5-8"},/obj/structure/cable{icon_state = "2-5"},/turf/simulated/floor/airless,/area/magshield/east) +"hI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless,/area/magshield/east) +"hJ" = (/obj/structure/filingcabinet/chestdrawer,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"hK" = (/obj/structure/table/woodentable,/obj/item/weapon/book/manual/supermatter_engine,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"hL" = (/obj/item/weapon/ore,/turf/simulated/floor/tiled/dark,/area/magshield/west) +"hM" = (/turf/space,/area/magshield/west) +"hN" = (/obj/item/weapon/reagent_containers/glass/bucket,/turf/simulated/floor/tiled,/area/magshield/east) +"hO" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/airless,/area/magshield/east) +"hP" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/magshield/east) +"hQ" = (/obj/machinery/portable_atmospherics/canister/oxygen,/obj/machinery/light_construct{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"hR" = (/obj/structure/filingcabinet/chestdrawer,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"hS" = (/obj/structure/bed/chair/comfy/red,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"hT" = (/obj/structure/table/woodentable,/obj/item/weapon/book/manual/evaguide,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"hU" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/west) +"hV" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/west) +"hW" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/dark,/area/magshield/west) +"hX" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/item/weapon/paper/magshield/tornpage,/turf/simulated/floor/tiled/dark,/area/magshield/west) +"hY" = (/obj/structure/table/steel,/obj/item/weapon/material/ashtray/plastic,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/west) +"hZ" = (/obj/structure/table/woodentable,/obj/random/accessory,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"ia" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/lighter/zippo,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/carpet/blue,/area/magshield/west) +"ib" = (/obj/structure/table/woodentable,/obj/item/weapon/material/ashtray/bronze,/obj/random/smokes,/obj/machinery/light,/turf/simulated/floor/carpet/blue,/area/magshield/west) +"ic" = (/obj/item/stack/rods,/turf/simulated/floor/tiled/dark,/area/magshield/west) +"id" = (/obj/item/stack/rods,/turf/space,/area/magshield/west) +"ie" = (/obj/machinery/seed_storage,/turf/simulated/floor/tiled,/area/magshield/east) +"if" = (/obj/structure/reagent_dispensers/watertank,/obj/item/weapon/reagent_containers/glass/bucket,/turf/simulated/floor/airless,/area/magshield/east) +"ig" = (/obj/structure/cable{icon_state = "1-10"},/turf/simulated/floor/airless,/area/magshield/east) +"ih" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled,/area/magshield/east) +"ii" = (/obj/item/weapon/material/minihoe,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/light,/turf/simulated/floor/tiled,/area/magshield/east) +"ij" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled,/area/magshield/east) +"ik" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"il" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/structure/cable{icon_state = "2-5"},/turf/simulated/floor/airless,/area/magshield/east) +"im" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless,/area/magshield/east) +"in" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/airless,/area/magshield/east) +"io" = (/obj/machinery/light_construct{dir = 8},/turf/simulated/floor/tiled,/area/magshield/west) +"ip" = (/turf/simulated/wall/r_wall,/area/magshield/south) +"iq" = (/turf/simulated/wall,/area/magshield/south) +"ir" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/magshield/south) +"is" = (/obj/item/weapon/ore/slag,/turf/space,/area/space) +"it" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled/dark,/area/magshield/west) +"iu" = (/turf/simulated/floor/tiled/white,/area/magshield/south) +"iv" = (/obj/structure/curtain/open/shower,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iw" = (/obj/machinery/shower{icon_state = "shower"; dir = 8},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/white,/area/magshield/south) +"ix" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/magshield/south) +"iy" = (/obj/structure/table,/obj/random/firstaid,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iz" = (/obj/machinery/light_construct{dir = 1},/turf/simulated/floor/tiled/white,/area/magshield/south) +"iA" = (/obj/structure/bed,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iB" = (/obj/random/material,/turf/space,/area/space) +"iC" = (/turf/simulated/floor/airless,/area/magshield/west) +"iD" = (/obj/structure/table/steel,/obj/item/weapon/reagent_containers/food/drinks/cans/space_up,/obj/item/weapon/reagent_containers/food/drinks/cans/space_up{pixel_x = 5; pixel_y = 4},/obj/item/weapon/reagent_containers/food/drinks/cans/space_up{pixel_x = -8; pixel_y = 5},/obj/item/weapon/reagent_containers/food/drinks/cans/space_up{pixel_x = -2; pixel_y = -4},/turf/simulated/floor/tiled,/area/magshield/west) +"iE" = (/obj/structure/iv_drip,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iF" = (/obj/random/medical/lite,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iG" = (/obj/machinery/light_construct,/turf/simulated/floor/tiled,/area/magshield/west) +"iH" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/magshield/south) +"iI" = (/obj/machinery/shower{icon_state = "shower"; dir = 8},/obj/random/trash,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/white,/area/magshield/south) +"iJ" = (/obj/item/weapon/bedsheet,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iK" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/west) +"iL" = (/obj/structure/toilet,/turf/space,/area/magshield/south) +"iM" = (/obj/structure/urinal{pixel_y = 25},/obj/random/trash,/turf/space,/area/magshield/south) +"iN" = (/obj/structure/sink{pixel_y = 25},/turf/space,/area/magshield/south) +"iO" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/south) +"iP" = (/obj/machinery/vending/coffee,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/magshield/south) +"iQ" = (/obj/machinery/vending/cola,/turf/simulated/floor/tiled,/area/magshield/south) +"iR" = (/obj/machinery/vending/snack,/turf/simulated/floor/tiled,/area/magshield/south) +"iS" = (/obj/structure/window/reinforced/full,/obj/structure/grille,/turf/simulated/floor/tiled,/area/magshield/south) +"iT" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iU" = (/obj/structure/toilet{dir = 8},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/white,/area/magshield/south) +"iV" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light_construct{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"iW" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iX" = (/obj/item/weapon/ore/slag,/turf/simulated/floor/tiled/white,/area/magshield/south) +"iY" = (/obj/machinery/light/small{dir = 8},/turf/space,/area/magshield/south) +"iZ" = (/obj/machinery/light,/turf/space,/area/magshield/south) +"ja" = (/mob/living/simple_animal/hostile/carp,/turf/space,/area/magshield/south) +"jb" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/space,/area/magshield/south) +"jc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/south) +"jd" = (/turf/simulated/floor/tiled,/area/magshield/south) +"je" = (/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/magshield/south) +"jf" = (/obj/structure/window/reinforced/full,/obj/machinery/door/firedoor,/obj/structure/grille,/turf/simulated/floor/tiled,/area/magshield/south) +"jg" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/magshield/south) +"jh" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/white,/area/magshield/south) +"ji" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled/white,/area/magshield/south) +"jj" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white,/area/magshield/south) +"jk" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/turf/simulated/floor/tiled/white,/area/magshield/south) +"jl" = (/turf/space,/area/magshield/south) +"jm" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/random/smokes,/turf/simulated/floor/tiled,/area/magshield/south) +"jn" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/random/firstaid,/turf/simulated/floor/tiled,/area/magshield/south) +"jo" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"jp" = (/obj/structure/bed,/obj/item/weapon/bedsheet,/turf/simulated/floor/tiled,/area/magshield/south) +"jq" = (/obj/structure/bed,/turf/simulated/floor/tiled,/area/magshield/south) +"jr" = (/obj/random/trash,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"js" = (/obj/structure/bed/chair{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"jt" = (/obj/structure/table/standard{name = "plastic table frame"},/turf/simulated/floor/tiled,/area/magshield/south) +"ju" = (/obj/structure/bed/chair{dir = 8},/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"jv" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/trash/plate,/obj/item/weapon/reagent_containers/food/snacks/flatbread,/turf/simulated/floor/tiled,/area/magshield/south) +"jw" = (/obj/structure/bed/chair{dir = 8},/turf/simulated/floor/tiled,/area/magshield/south) +"jx" = (/obj/structure/table/marble,/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled/white,/area/magshield/south) +"jy" = (/obj/structure/table/marble,/obj/item/weapon/material/knife/butch,/turf/simulated/floor/tiled/white,/area/magshield/south) +"jz" = (/obj/structure/sink{pixel_y = 25},/turf/simulated/floor/tiled/white,/area/magshield/south) +"jA" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled/freezer,/area/magshield/south) +"jB" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/simulated/floor/tiled/freezer,/area/magshield/south) +"jC" = (/obj/machinery/washing_machine,/turf/simulated/floor/tiled/white,/area/magshield/south) +"jD" = (/obj/structure/lattice,/turf/space,/area/magshield/south) +"jE" = (/obj/structure/magshield/maggen,/turf/simulated/floor/airless,/area/space) +"jF" = (/obj/machinery/door/airlock/external/bolted,/turf/simulated/floor/airless,/area/magshield/south) +"jG" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1380; id_tag = "merchant_station_vent"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{pixel_x = 0; pixel_y = 25},/obj/machinery/airlock_sensor{pixel_x = 0; pixel_y = -25},/turf/simulated/floor/airless,/area/magshield/south) +"jH" = (/obj/machinery/door/airlock/external/bolted,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless,/area/magshield/south) +"jI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"jJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24},/obj/structure/cable{icon_state = "0-2"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/turf/simulated/floor/tiled,/area/magshield/south) +"jK" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled,/area/magshield/south) +"jL" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/random/plushie/large,/obj/random/smokes,/turf/simulated/floor/tiled,/area/magshield/south) +"jM" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/machinery/light{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"jN" = (/obj/structure/closet,/obj/random/glasses,/obj/random/hat,/obj/random/cash,/turf/simulated/floor/tiled,/area/magshield/south) +"jO" = (/obj/structure/closet,/obj/random/clothing,/obj/random/accessory,/obj/random/smokes,/turf/simulated/floor/tiled,/area/magshield/south) +"jP" = (/obj/structure/closet,/obj/random/junk,/turf/simulated/floor/tiled,/area/magshield/south) +"jQ" = (/obj/structure/closet,/obj/random/clothing,/turf/simulated/floor/tiled,/area/magshield/south) +"jR" = (/obj/structure/closet,/obj/random/clothing,/obj/random/cash,/turf/simulated/floor/tiled,/area/magshield/south) +"jS" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/trash/plate,/turf/simulated/floor/tiled,/area/magshield/south) +"jT" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/weapon/material/kitchen/utensil/knife,/turf/simulated/floor/tiled,/area/magshield/south) +"jU" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/random/snack,/turf/simulated/floor/tiled,/area/magshield/south) +"jV" = (/obj/structure/table/marble,/turf/simulated/floor/tiled/white,/area/magshield/south) +"jW" = (/obj/item/weapon/material/knife/hook,/turf/simulated/floor/tiled/freezer,/area/magshield/south) +"jX" = (/obj/machinery/atmospherics/unary/vent_pump/on,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/magshield/south) +"jY" = (/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/obj/item/weapon/soap/deluxe,/turf/simulated/floor/tiled/white,/area/magshield/south) +"jZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/magshield/south) +"ka" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/magshield/south) +"kb" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/magshield/south) +"kc" = (/turf/simulated/floor/airless,/area/magshield/south) +"kd" = (/obj/structure/bed/roller,/turf/simulated/floor/airless,/area/space) +"ke" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/space) +"kf" = (/obj/structure/sign/warning/airlock{pixel_x = -30},/turf/simulated/floor/tiled,/area/magshield/south) +"kg" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/magshield/south) +"kh" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"ki" = (/obj/structure/curtain/open/bed,/turf/simulated/floor/tiled,/area/magshield/south) +"kj" = (/obj/random/snack,/turf/simulated/floor/tiled,/area/magshield/south) +"kk" = (/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/tiled,/area/magshield/south) +"kl" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled,/area/magshield/south) +"km" = (/obj/machinery/vending/dinnerware,/turf/simulated/floor/tiled/white,/area/magshield/south) +"kn" = (/obj/structure/table/marble,/obj/machinery/microwave,/turf/simulated/floor/tiled/white,/area/magshield/south) +"ko" = (/turf/simulated/floor/tiled/freezer,/area/magshield/south) +"kp" = (/obj/structure/closet/secure_closet/freezer/fridge,/obj/item/weapon/reagent_containers/food/snacks/hotdog,/turf/simulated/floor/tiled/freezer,/area/magshield/south) +"kq" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled/white,/area/magshield/south) +"kr" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled/white,/area/magshield/south) +"ks" = (/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/magshield/south) +"kt" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light_construct{dir = 8},/turf/simulated/floor/tiled,/area/magshield/south) +"ku" = (/obj/item/weapon/ore,/turf/space,/area/magshield/south) +"kv" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled,/area/magshield/south) +"kw" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/magshield/south) +"kx" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"ky" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"kz" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"kA" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/light,/turf/simulated/floor/tiled,/area/magshield/south) +"kB" = (/obj/item/weapon/flame/match,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"kC" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"kD" = (/obj/item/weapon/material/kitchen/utensil/fork/plastic,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"kE" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"kF" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled,/area/magshield/south) +"kG" = (/obj/random/trash,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"kH" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/magshield/south) +"kI" = (/obj/structure/table/marble,/obj/item/weapon/reagent_containers/food/snacks/chips,/turf/simulated/floor/tiled/white,/area/magshield/south) +"kJ" = (/obj/structure/table/marble,/obj/item/weapon/material/kitchen/utensil/knife,/turf/simulated/floor/tiled/white,/area/magshield/south) +"kK" = (/obj/structure/kitchenspike,/turf/simulated/floor/tiled/freezer,/area/magshield/south) +"kL" = (/obj/structure/closet/secure_closet/freezer/meat,/obj/item/weapon/reagent_containers/food/snacks/meat,/obj/item/weapon/reagent_containers/food/snacks/meat,/obj/item/weapon/reagent_containers/food/snacks/meat,/obj/item/weapon/reagent_containers/food/snacks/meat,/obj/item/weapon/reagent_containers/food/snacks/meat,/turf/simulated/floor/tiled/freezer,/area/magshield/south) +"kM" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/magshield/south) +"kN" = (/obj/structure/window/basic{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"kO" = (/obj/structure/fitness/weightlifter,/obj/structure/window/basic{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"kP" = (/obj/structure/window/basic{dir = 1},/obj/item/weapon/towel/random,/turf/simulated/floor/tiled,/area/magshield/south) +"kQ" = (/obj/structure/window/basic{dir = 1},/obj/structure/fitness/punchingbag,/turf/simulated/floor/tiled,/area/magshield/south) +"kR" = (/obj/structure/window/basic{dir = 4},/obj/structure/window/basic{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"kS" = (/obj/machinery/computer/arcade,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/magshield/south) +"kT" = (/obj/structure/curtain/open/bed,/obj/item/weapon/material/kitchen/utensil/knife/plastic,/turf/simulated/floor/tiled,/area/magshield/south) +"kU" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/magshield/south) +"kV" = (/obj/item/weapon/towel/random,/turf/simulated/floor/tiled,/area/magshield/south) +"kW" = (/obj/machinery/computer/arcade,/turf/simulated/floor/tiled,/area/magshield/south) +"kX" = (/obj/structure/closet,/obj/random/accessory,/turf/simulated/floor/tiled,/area/magshield/south) +"kY" = (/obj/structure/closet,/obj/random/tool,/obj/random/smokes,/turf/simulated/floor/tiled,/area/magshield/south) +"kZ" = (/obj/structure/closet,/obj/random/firstaid,/obj/random/junk,/turf/simulated/floor/tiled,/area/magshield/south) +"la" = (/obj/structure/closet,/obj/random/loot,/turf/simulated/floor/tiled,/area/magshield/south) +"lb" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/random/hat,/turf/simulated/floor/tiled,/area/magshield/south) +"lc" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/weapon/deck/cards,/turf/simulated/floor/tiled,/area/magshield/south) +"ld" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/item/weapon/material/kitchen/utensil/fork/plastic,/obj/item/trash/plate,/turf/simulated/floor/tiled,/area/magshield/south) +"le" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/magshield/south) +"lf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled,/area/magshield/south) +"lg" = (/obj/item/stack/rods,/turf/space,/area/magshield/south) +"lh" = (/obj/structure/fitness/weightlifter,/turf/simulated/floor/tiled,/area/magshield/south) +"li" = (/obj/structure/fitness/punchingbag,/obj/machinery/light,/turf/simulated/floor/tiled,/area/magshield/south) +"lj" = (/obj/structure/window/basic{dir = 4},/obj/random/trash,/turf/simulated/floor/tiled,/area/magshield/south) +"lk" = (/obj/machinery/light/small,/turf/simulated/floor/tiled,/area/magshield/south) +"ll" = (/obj/random/trash,/obj/machinery/light/small,/turf/simulated/floor/tiled,/area/magshield/south) +"lm" = (/obj/structure/table/standard{name = "plastic table frame"},/obj/machinery/light,/turf/simulated/floor/tiled,/area/magshield/south) +"ln" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/magshield/south) +"lo" = (/obj/machinery/vending/cigarette,/turf/simulated/floor/tiled,/area/magshield/south) +"lp" = (/obj/machinery/vending/cola,/obj/machinery/light,/turf/simulated/floor/tiled,/area/magshield/south) +"lq" = (/obj/machinery/vending/fitness,/turf/simulated/floor/tiled,/area/magshield/south) +"lr" = (/obj/machinery/light_construct{dir = 8},/turf/simulated/floor/tiled,/area/magshield/south) +"ls" = (/obj/structure/girder/displaced,/turf/simulated/floor/tiled,/area/magshield/south) +"lt" = (/obj/effect/shuttle_landmark/nav_magshield/nav4,/turf/space,/area/space) +"lu" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless,/area/space) +"lv" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/space) +"lw" = (/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/power/solar{id = "auxsolarsport"; name = "Port Auxiliary Solar Array"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"lx" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/space) +"ly" = (/obj/structure/cable/yellow,/obj/machinery/power/solar{id = "auxsolarsport"; name = "Port Auxiliary Solar Array"},/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/space) +"lz" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless,/area/space) +"lA" = (/obj/effect/shuttle_landmark/nav_magshield/nav3,/turf/space,/area/space) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababacacababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaadaaaaaaaaaaaaaeaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaafaaaaaaafafafafafafaaagaaafafafafafafafafafafaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaahaaaaaaaiaiaiaiaiaiajakajalalalalalalalalalamaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaanananananananaaagaaananananananananananaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaoaaaaaaaaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaafafafafafafafafapagapafafafafafafafafafafaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaiaiaiaiaiaiaiaiaiajakajalalalalalalalalalamaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanananananananananapagapananananananananananaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaafafafafafafafafafafaaagaaafafafafafafafafafafaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaahaiaiaiaiaiaiaiaiaiajakajalalalalalalalalalamaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaananananananananananaaagaaaqanananananananananaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaraaaaaaaaaaaaaaaaaaaaaaaaasataaaaaaaaaaaaaaaaaaaaaaaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaauauauauauauauauauauauauauavauawawawawawawawawawawawawaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaauauauauauauauauauauauauauaxauawawawawawawawawawawawawaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababauauayayayazaAayazaBauaCauaDauawaEaFaGaGaGaHaEaEaEawawabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaIaJaIaKaLaLaMaNaOaPaOaQaOaRauaSaTaUaBawaVaFaWaXaYaZaEbaaEbbaEapapapaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbcbcbcaaauaubdbeaBbeaBbeaBbfbgbgbhbibjawaVaFaEbkaEaHblaEbmawawabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacacacaaaaaaaaaaaaaaaaabbcbcbcaaauauaBbnaBbnaBbnbobgbgbpbgbgbqawbrbsaEaEbtawbubvbuawawaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbcbcbcaaauaubxbybzbybzbgbpbgbgboaBaUbAawaEaEaEaEaEaEbBbCbDawawabababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbcbcbcaaauaubEbgbgbgbgbgbFbgauaBaSaUbGawaEaEaEaEbHbIbJbBbKbLbLbMbNbNbNbNbNbNbNbNbNbNaJabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbObcbcaabpbgbgbgbgbgaBbPbQbRaubSaBaUaBawawawawbTbCbUbDbBbVawawaaaIbNbNbNbNbNbNbNbNbNbWabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbcbcbcaabgbgbgbgbgbgbgaQbXbYauaBbobZbjawcacbccaEbBbKcdcecfawawaacgbNbNbNbNbNbNbNbNbNaJabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbcbcaaaabgbpbgbeaBbpbgbgaBaBauchaBaUaSawcicjckclcmcncobBaEawawaaaIbNbNbNbNbNbNbNbNbNbWabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoaaaaaaaaaaaaaaaaaoauaucpbnbobnaBbnaBaBauaBaScqcrcsctcuccaEcvcwcxbDaEawawaacgbNbNbNbNbNbNbNbNbNaJabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoaaaaaaauaucybybzbybzczaBaBaucAaBcBaBawawawawbTaEcCaEcDbtawawaaaIbNbNbNbNbNbNbNbNbNbWabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoaaaaaaaabNcEaKaLaLcFcGaBaBaSaBaBcHaucIaBcBcJawcKcLawcMaEcCaEcNaEawawaacgbNbNbNbNbNbNbNbNbNaJabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacOabababauauayayayayaycPcQcRcScTcTcUcVcWcXcYcWcZdadbdcdddcbLbLbMbNbNbNbNbNbNbNbNbNbNbWabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadeadaaaaaadedededededededededededededededededfdededededededededededededededededededededededeabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadededgdgdgdededededededededededededededededededhdedededededededededededededededededededededededeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadededidjdjdjdjdjdjdjdjdkdldmdndodjdpdqdjdrdsdldtdudjdmdjdvdwdwdjdvdjdjdjdjdtdxdjdydzdjdAdBdCdDdedeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadededjdjdEdFdjdGdjdHdjdjdkdjdIdEdjdJdjdjdKdjdLdjdtdudjdjdmdjdjdEdjdjdMdjdjdNdtdOdPdjdjdjdjdjdjdjdQdedeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadedededjdjdodjdjdjdjdgdgdgdgdgdHdRdSdRdTdUdVdWdRdXdjdtdudjdmdjdjdjdjdEdjdjdjdjdYdtdZdjdjdjdjdjdjeadjdQebdedeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadedededjdGdjdjdjdmdjdjdgdgdgdgdgdgdjdjdjdjdjdjdjdjeceddtdudjdjdjdjdMdjdjdjdjeceddYdtdjdjdjdjdjdjdjdjdjdjdjeedededeababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababefdedjdFdjdjdFegehehdgdHeidgdgdgejejejejejejejejejekelemeneoeoeoeoeoeoeoeoeoepeleqemerdjdjeceddjdjdjdjdjesdedededeaaaaaaaaaaaaapapapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapaaaaaaaaaaaaetdedgdgdjdjdidYdjdjdjdjeudgdHdgdgdjdjdjdjdmdjdjdjdjdjeveuewdjdjdjdjdjdjdjdjdjdjdjdtexeyeoezeAeoeoeBeCejejeDeEeFeGeHeHeHeHeHeHeHeIapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeHeHeHeHeHeHeHeHeFeJejejejejeKeLeLeLeMeNeOdmdgdjdjePePeQeReSeOePdjdjdeeTdeeUeeeeeeeeeeeUeVeWeXdAdteYeZfadtdtdtdtdtfbdtdtdedededefcaaaaaaaaaaapapapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapapaaaaaaaaaaaaaadgdHdgdjdjdjdYdjdjdjdjdedededededededededededededededefddedededededededededededededededefefffgfhfifjfififhfifkflababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaadgdjdidieOdjdYdjdjfmdededededededededededededededededefndedededededededededededededededefkfffofpfqfrfsfifififkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaftaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufufufufufufvfufufufufuaaacaaaaaaaaaaaaaaaaaaaaaaaadgfwdgaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkfxfyfififjfifififzfkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoaafufufAfBfCfBfDfEfAfFfGfufuacacacacacacacacacacacacacacdjfHdjacacacacacacacacacacacacacacfkfkfffofIfgfjfififififkfkfJfJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufufAfKfLfMfNfOfAfPfAfufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkfifQfifRfSfTfUfVfUfWfWfXfJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufufYfBfZgafAfOfAgbgagcgcaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkfigdfigefjgefigefifkfkfJfJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufufufufufufufugffBgggafAfOfBfZgagcgcaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkghgigjgkfSfTfUglfifkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufufufufufufufugmfBgngafAfOfAgogagcgcacgpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagqacfkfkgjgrfififjgefififzfkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufugsgtgugvgwfugffBfZgafAfOfAgogafufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkgxgyfififjgzfifififkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagcgcgAgvgvgvgvfugffBgogafAfOfBfZgafufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkgBgCfifigDgEgFfififkfkaaaaaaaaaaaaaaaoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagcgcgGgHgIgJgKfugffBfBfBfAfOfAgogafufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkfifififigLgMgNfififkfkefabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufugOgPgPgPgPfugQgRgRfBfBgSfAfAfAfufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkfefefefefefegTfkfkfkfkfcaaaaapapapapaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufugUgVgWgXgYfugRgZhafAfAfOfAhbgagcgcaaacaaaaaaaaaaaaaaaaaaaaaaaahcaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkhdhehdfefifihfhghhhihjhkhkhkhkhkhlapacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufuhmfAfAfAhnfuhohphqhrfAfOfBfZgagcgcacgpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagqacfkfkhdhshdfehtfifjfkfkfkhuaaaaaaaphvaaapadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufugUfAfAfAhwfugRhxhafAfAfOfAhygagcgcaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkhdhshdfefifihzfihAfkfkaaaaacapapapapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufuhBfAfAfAhCfuhDgRgRfBhEfOhFfAfFfufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkhdhshdfehGhHhIfihAfkfkababababaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagcgchJgvhKfAfAfufAfBhLhMhMhMhEgogafufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkhdhNhdfehOhPhIfihQfkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagcgchRhShThUhUhVhWhXhYhMhMhMhMfZgafufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkhdhshdfehOhPhIfigjfkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufuhZiaibfAfAfufAicfZhEhMhMidgogafufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaafkfkhdhsiefeifighIfififkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufufufufufufufuhFfBgogahFhMhMhygagcgcacgpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagqacfkfkihiiijikiliminfififkfkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafufufufufufufuhMiofBgogafAhMhEfZgagcgcaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaipipiqiqiqiqiriqiqiqiqipipaaisaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahMfAfBfZgafAitfAgngagcgcaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaipipiuiviwiqixiqiyiziAipipaaiBaaaaaaaaaaaaaaaaaoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiCfAfBiDgafAitfAfAfAfufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaipipiuiqiqiqixiqiEiFiuipaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacOfuhFfBfBfBfBitfAiGfGfufuacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacipipiHiviIiqixiqiuiJiFipaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoaaaafufufufufufufuiKfufufufufuaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaipipiuiqiqiqixiqiFiuiuacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiBaafuipiLiqiMiNiqiOiPiQiRipipipipipipipipipipipipipipipipipipiSiSipipiSiSipipipipipipipipipipipiuiTiUiqiViqiWiXiuaaaaaacOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababipiYiTiZjajbjcjdjdjejeipipipipipipipipipipipipipipipipipjfjfipipjfjfipipipipipipipipipipiqiuiqiqiqjgjhjijjjkjlabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabapapapaaaaacaaaaaaetipipipiqiqiqjcjdjdjmjniqjojpiqjojqiqjojqiqjrjpiqjojqiqjsjtjtjujsjtjvjwjdjxjyjziuiuiTjAjBiqiuiujCiqixiqiqjDjljlaaaaaaaaaaaaaaapapaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabapjEapapapapapapapapjFjGjHjIjIjJjKjdjdjLjMiqjdjNiqjdjOiqjdjPiqjdjQiqjdjRiqjsjSjTjwjsjtjUjwjdjViuiuiujViqjWjBiqjXiujYiqjZkakbkckckckdapkekekekekeapaaapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabapapapaaaaacaaaaaaaaipipipkfjdjdkgjdjdkhkhiqkiiqiqkiiqiqkiiqiqkiiqiqkiiqiqjdjdkjkkkljdjdjdjdkmiuiuiukniqkokpiqkqkrksiqktkcjlkuipipaaaaaaaaaaaaaaaaapapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababipipipkvjdjdkwkxkxkxkykzkxkAkBkxkxkxkxkAkxkxkxkxkxkAkCkxkDkxkEkFkGkxkxkHiqiujVkIkJiqkKkLiqkMiqiqiqixkckcipipipababababababaaaaabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaipipipkNkOkPkQkRjdkSiqkiiqiqkiiqiqkiiqiqkiiqiqkTiqiqjdjdjdjdjdjdjdjdkgiqiTiqiqiqiqiqiqiqkUkxkxkxkujljlipipaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaipipkVjdjdjdjdjdkWiqjdkXiqjdkYiqjdjQiqjdkZiqjdlaiqjslblcjwjsldjUjwkwkxkxkxkxkxkxkxkxlelfjdjdipkcjllgipipaaaaaaaaaaaoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaipiplhjdliljjdkWiqlkjqiqlljqiqlkjqiqlkjqiqlkjqiqjsjtlmjwjsjtjtjwlnkWkWkWkWloiRlplqiqlrjdlsjljDjlipipaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaipipiSipipiSipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipjljlkcipaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaltaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaipipiSipipiSipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipipaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaluajajajajajajajajaaaaajlvabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaisaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaalwlwlwlwlwlwlwlwlwlwaaagaalwlwlwlwlwisaaaalwlwaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaahaiaiaiaiaiaiaiaiaiajlxajalalalalalaaaaalalamaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaalylylylylylylylylylyaaagaalylylylyaaaalylylylyaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaalwlwlwlwlwlwlwlwlwlwapagaplwlwlwaaaalwlwlwlwlwaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaahaiaiaiaiaiaiaiaiaiajlxajalalalalalalalalalamaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaalylylylylylylylylylyapagaplyaaaaaalylylylylylyaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaalwlwlwlwlwlwlwlwlwlwaaagaaaaaaaalwlwlwlwlwlwlwaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaahaiaiaiaiaiaiaiaiaiajlzajaaaaisalalalalalalamaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaalylylylylylylylylylyaaaaaaaalylylylylylylylylyaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababaaaaaaaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/away/magshield/magshield_areas.dm b/maps/away/magshield/magshield_areas.dm new file mode 100644 index 00000000..85a42916 --- /dev/null +++ b/maps/away/magshield/magshield_areas.dm @@ -0,0 +1,29 @@ +/area/magshield/south + name = "Orbital Station South Wing" + icon_state = "south" + icon = 'magshield_sprites.dmi' + +/area/magshield/north + name = "Orbital Station North Wing" + icon_state = "north" + icon = 'magshield_sprites.dmi' + +/area/magshield/east + name = "Orbital Station East Wing" + icon_state = "east" + icon = 'magshield_sprites.dmi' + +/area/magshield/west + name = "Orbital Station West Wing" + icon_state = "west" + icon = 'magshield_sprites.dmi' + +/area/magshield/engine + name = "Orbital Station Engine" + icon_state = "engine" + icon = 'magshield_sprites.dmi' + +/area/magshield/smes_storage + name = "Orbital Station SMES Battery Room" + icon_state = "smes_storage" + icon = 'magshield_sprites.dmi' diff --git a/maps/away/magshield/magshield_sprites.dmi b/maps/away/magshield/magshield_sprites.dmi new file mode 100644 index 00000000..a14f57ae Binary files /dev/null and b/maps/away/magshield/magshield_sprites.dmi differ diff --git a/maps/away/marooned/marooned.dm b/maps/away/marooned/marooned.dm new file mode 100644 index 00000000..602965d2 --- /dev/null +++ b/maps/away/marooned/marooned.dm @@ -0,0 +1,104 @@ +#include "marooned_areas.dm" +#include "../mining/mining_areas.dm" + +/turf/simulated/floor/marooned/snow + name = "snow" + icon = 'icons/turf/snow.dmi' + icon_state = "snow" + temperature = T0C - 30 + initial_gas = list("oxygen" = MOLES_O2STANDARD, "nitrogen" = MOLES_N2STANDARD) + dynamic_lighting = 0 + +/obj/effect/overmap/sector/marooned + name = "glacial planetoid" + desc = "Moon-sized planet with breathable atmosphere. Sensors are picking up a weak radio signal from the surface." + icon_state = "globe" + known = 0 + in_space = 0 + + generic_waypoints = list( + "nav_marooned_1", + "nav_marooned_2", + "nav_marooned_antag" + ) + +/obj/effect/overmap/sector/marooned/New(nloc, max_x, max_y) + name = "[generate_planet_name()], \a [name]" + ..() + +/datum/map_template/ruin/away_site/marooned + name = "Marooned" + id = "awaysite_marooned" + description = "A snowy wasteland." + suffixes = list("marooned/marooned.dmm") + cost = 1 + +/obj/effect/shuttle_landmark/nav_marooned/nav1 + name = "Planetside Navpoint #1" + landmark_tag = "nav_marooned_1" + autoset = 1 + +/obj/effect/shuttle_landmark/nav_marooned/nav2 + name = "Planetside Navpoint #2" + landmark_tag = "nav_marooned_2" + autoset = 1 + +/obj/effect/shuttle_landmark/nav_marooned/nav3 + name = "Planetside Navpoint #3" + landmark_tag = "nav_marooned_antag" + autoset = 1 + +/obj/item/clothing/under/magintka_uniform + name = "Magnitka fleet officer uniform" + desc = "A dark uniform coat worn by Magnitka fleet officers." + icon_state = "magnitka_officer" + icon = 'maps/away/marooned/marooned_sprites.dmi' + item_icons = list(slot_w_uniform_str = 'maps/away/marooned/marooned_sprites.dmi') + +/obj/item/clothing/accessory/medal/silver/marooned_medal + name = "marooned officer's medal" + desc = "An silver round medal of marooned officer. It has inscription \"For Distinguished Service\" in lower part. On medal's plank it's engraved \"H. Warda\"" + icon_state = "marooned_medal" + icon = 'maps/away/marooned/marooned_sprites.dmi' + +/obj/effect/landmark/corpse/marooned_officer + name = "Horazy Warda" + corpse_outfits = list(/decl/hierarchy/outfit/corpse/marooned_officer) + spawn_flags = ~CORPSE_SPAWNER_RANDOM_NAME + +/decl/hierarchy/outfit/corpse/marooned_officer + name = "Dead Magnitka's fleet officer" + uniform = /obj/item/clothing/under/magintka_uniform + suit = /obj/item/clothing/suit/storage/hooded/wintercoat + shoes = /obj/item/clothing/shoes/jungleboots + gloves = /obj/item/clothing/gloves/thick + head = /obj/item/clothing/head/beret + l_pocket = /obj/item/weapon/material/butterfly/switchblade + +/obj/item/weapon/paper/marooned/note1 + name = "Marooned note 1" + info = "Those bastards!
            They just pushed me inside pod and locked the hatch, then started yelling at each other outside. It seems, some of the officers, Lt. Pytlak was loudest, who joined this fucking mutiny said I won't go to surface with nothing but my coat. Ha!
            Some time later they opened the hatch, three sailors aiming at me, and another pushed inside couple of crates." + +/obj/item/weapon/paper/marooned/note2 + name = "Marooned note 2" + info = "Landing was harsh, oh, too harsh. This little pod was not meant to land to atmosphere.
            Pod stopped hard at rocky wall, and I lost consciousness for few hours, it seems.
            Seems I broke couple of ribs and lost few teeth.
            When I got outside, it was dark. It was so cold I momentarily started to shake. I checked crates and beside some food I found warm coat, thanks gods." + +/obj/item/weapon/paper/marooned/note3 + name = "Marooned note 3" + info = "Now I don't think anyone will find this, but I'll Introduce myself. Major of Fleet Horacy Warda, Magnitka Defence forces.

            I hid inside pod until morning came, then left for reconnaissance mission. What I found was few small snow-covered valleys, some trees, couple of ponds that are surpisingly still liquid. Hope it's some thermal water, I can't keep eating snow to get thirst down.
            Major Warda
            2549-07-11" + +/obj/item/weapon/paper/marooned/note4 + name = "Marooned note 4" + info = "I set up myself small wooden shelter, luckily I had hatchet and I know how to make things with wood since I helped my late father with his construction work.
            When star was going close to horizont, I noticed deer-like creature. I rushed inside and grabed that gun they left, shot three times. This piece of junk with cut away barrel is only good to put in mouth and pull the trigger. I won't give up so fast.
            Major Warda
            2549-09-11" + +/obj/item/weapon/paper/marooned/note5 + name = "Marooned note 5" + info = "I returned to crash site and checked if there's still anything useful. I found some electronic scraps, almost undamaged battery and few metal rods.
            Back at shelter I tried to remember all I know about radio schemes but to little success. Best I can do is to make some sort of antenna, pick this mobile radio I still had in my pocket and amplify signal by connecting battery I found to radio power input
            Have to pray it won't just explode or catch fire.
            Major Warda
            2549-13-11" + +/obj/item/weapon/paper/marooned/note6 + name = "Marooned note 6" + info = "Seems my jury-rigged emergency radio transmitter works. I hope it sends anything at least.
            I can't recharge it anymore since generator I have has no more fuel so I'll make one emergency call every day when I wake up.
            Now I still have some food and water tastes weird but still good to drink, I simply must wait for any help to arrive.
            Major Warda
            2549-16-11" + +/obj/item/weapon/paper/marooned/note7 + name = "Marooned note 7" + info = "I barely managed to stand up and get to table to write this down. Seems I got cold and too starved to make it
            I &ave t&
            Can't wa&t
            I know I was loyal to the end. For my wife and daughter, I love you.
            Glory to Magnitka!
            Major Horacy Warda
            2549-04-12" \ No newline at end of file diff --git a/maps/away/marooned/marooned.dmm b/maps/away/marooned/marooned.dmm new file mode 100644 index 00000000..9e750735 --- /dev/null +++ b/maps/away/marooned/marooned.dmm @@ -0,0 +1,284 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/turf/unsimulated/mineral,/area/space) +"ac" = (/turf/unsimulated/mineral,/area/marooned/marooned_snow) +"ad" = (/turf/unsimulated/mask,/area/mine/unexplored) +"ae" = (/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"af" = (/obj/structure/flora/tree/pine,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"ag" = (/obj/structure/flora/ausbushes/pointybush,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"ah" = (/obj/structure/grille,/obj/item/weapon/material/shard/shrapnel{pixel_x = 5; pixel_y = 7},/turf/simulated/floor/beach/sand,/area/marooned/marooned_snow) +"ai" = (/obj/item/weapon/material/shard{icon_state = "splinterslarge"},/obj/item/weapon/material/shard{icon_state = "shardlarge"},/obj/item/stack/rods,/obj/item/weapon/material/shard{icon_state = "medium"},/turf/simulated/floor/beach/sand,/area/marooned/marooned_snow) +"aj" = (/obj/structure/grille,/obj/item/weapon/material/shard/shrapnel,/turf/simulated/floor/beach/sand,/area/marooned/marooned_snow) +"ak" = (/obj/effect/floor_decal/asteroid,/turf/simulated/floor/beach/sand,/area/marooned/marooned_snow) +"al" = (/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/marooned/marooned_snow) +"am" = (/obj/structure/bed/chair{dir = 1},/obj/machinery/status_display{pixel_x = 32; pixel_y = 0},/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod{frequency = 1380; id_tag = "escape_pod_marooned"; name = "escape pod controller"; pixel_x = -24; pixel_y = 0; tag_door = "escape_pod_marooned_hatch"},/turf/simulated/floor/plating,/area/marooned/marooned_snow) +"an" = (/obj/item/trash/candy,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"ao" = (/turf/simulated/floor/plating,/area/marooned/marooned_snow) +"ap" = (/turf/simulated/floor/beach/sand,/area/marooned/marooned_snow) +"aq" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"ar" = (/obj/item/weapon/material/shard/shrapnel,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"as" = (/obj/structure/shuttle/engine/propulsion{dir = 2},/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/marooned/marooned_snow) +"at" = (/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_closed"; id_tag = "escape_pod_marooned_hatch"; locked = 0; name = "Escape Pod Hatch"; req_access = list(13)},/turf/simulated/floor/plating,/area/marooned/marooned_snow) +"au" = (/obj/effect/decal/cleanable/liquid_fuel,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"av" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"aw" = (/turf/simulated/wall/wood,/area/marooned/marooned_hut) +"ax" = (/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/structure/flora/pottedplant/small,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"ay" = (/obj/structure/window/basic{icon_state = "window"; dir = 1},/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"az" = (/obj/item/weapon/material/shard/shrapnel{pixel_x = -4},/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"aA" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/beach/sand,/area/marooned/marooned_snow) +"aB" = (/obj/item/weapon/material/shard/shrapnel,/obj/effect/decal/cleanable/liquid_fuel,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"aC" = (/obj/item/weapon/material/shard/shrapnel{pixel_y = 20},/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"aD" = (/obj/structure/flora/tree/dead,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"aE" = (/obj/structure/closet/crate/freezer/rations,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"aF" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"aG" = (/obj/structure/bed,/obj/item/weapon/bedsheet,/obj/effect/landmark/corpse/marooned_officer,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"aH" = (/obj/effect/decal/cleanable/generic,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"aI" = (/obj/item/weapon/material/shard/shrapnel{pixel_x = 10},/obj/effect/decal/cleanable/liquid_fuel,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"aJ" = (/obj/item/stack/material/wood,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"aK" = (/obj/structure/table/woodentable,/obj/item/clothing/accessory/medal/silver/marooned_medal{desc = "A heart-shaped bronze medal. Has Magnitka flag at top part and engraved name - H. Warda."; name = "\improper Magnitka medal"},/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"aL" = (/obj/effect/decal/cleanable/blood/drip,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"aM" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/beach/sand,/area/marooned/marooned_snow) +"aN" = (/obj/item/weapon/material/shard{icon_state = "splinterslarge"},/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"aO" = (/obj/structure/window/basic{dir = 8},/obj/structure/table/woodentable,/obj/item/clothing/glasses/regular,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"aP" = (/obj/random/trash,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"aQ" = (/obj/machinery/space_heater,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"aR" = (/obj/structure/window/basic{icon_state = "window"; dir = 4},/obj/machinery/power/port_gen/pacman/mrs,/obj/item/stack/cable_coil,/obj/item/weapon/wirecutters,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"aS" = (/obj/item/stack/material/wood{pixel_x = 10; pixel_y = 10},/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"aT" = (/obj/item/stack/material/wood,/obj/item/stack/material/wood,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"aU" = (/obj/structure/window/basic{dir = 8},/obj/structure/table/woodentable,/obj/item/weapon/material/kitchen/utensil/fork,/obj/item/trash/plate,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"aV" = (/obj/structure/bed/chair/wood,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"aW" = (/obj/item/trash/chips,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"aX" = (/obj/structure/window/basic{icon_state = "window"; dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"aY" = (/obj/item/trash/liquidfood{pixel_x = 4; pixel_y = 7},/obj/item/trash/liquidfood,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"aZ" = (/obj/item/weapon/material/wirerod{desc = "Metal rod with wiró attached to it."; name = "Jurry-rigged antenna"},/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"ba" = (/obj/item/weapon/material/shard/shrapnel,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/beach/sand,/area/marooned/marooned_snow) +"bb" = (/obj/effect/decal/cleanable/ash,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"bc" = (/obj/item/weapon/storage/box/matches,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"bd" = (/obj/structure/window/basic{dir = 8},/obj/structure/table/woodentable,/obj/item/weapon/pen,/obj/item/weapon/paper/marooned/note1{pixel_x = 2; pixel_y = -1},/obj/item/weapon/paper/marooned/note2{pixel_x = -3; pixel_y = -5},/obj/item/weapon/paper/marooned/note3{pixel_x = 2; pixel_y = 2},/obj/item/weapon/paper/marooned/note4,/obj/item/weapon/paper/marooned/note5{pixel_x = -3; pixel_y = 1},/obj/item/weapon/paper/marooned/note6,/obj/item/weapon/paper/marooned/note7{pixel_x = 6},/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"be" = (/obj/item/device/radio,/obj/item/stack/cable_coil{pixel_x = -10; pixel_y = -5},/obj/item/weapon/computer_hardware/battery_module{pixel_x = -7; pixel_y = 7},/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"bf" = (/obj/item/weapon/material/shard/shrapnel{pixel_x = -5; pixel_y = -12},/obj/effect/decal/cleanable/generic,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"bg" = (/turf/simulated/floor/beach/water,/area/marooned/marooned_snow) +"bh" = (/turf/simulated/floor/wood{icon_state = "wood_broken4"},/area/marooned/marooned_snow) +"bi" = (/obj/structure/table/woodentable,/obj/item/ammo_casing/shotgun/blank{pixel_x = 5; pixel_y = 3},/obj/item/ammo_casing/shotgun/blank{pixel_x = -4; pixel_y = 5},/obj/item/ammo_casing/shotgun/blank,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"bj" = (/obj/structure/table/woodentable,/obj/item/clothing/gloves/duty,/obj/item/weapon/screwdriver,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"bk" = (/obj/structure/closet/crate/freezer,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"bl" = (/obj/structure/table/woodentable,/obj/item/weapon/gun/projectile/shotgun/doublebarrel/sawn,/obj/item/weapon/material/hatchet,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"bm" = (/obj/structure/table/woodentable,/obj/item/stack/material/wood,/obj/item/stack/material/wood,/obj/item/stack/material/wood,/obj/item/stack/material/wood,/obj/item/stack/material/wood,/obj/item/stack/material/wood,/obj/item/weapon/storage/box/matches,/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"bn" = (/obj/item/weapon/ore/slag,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"bo" = (/obj/item/weapon/ore/slag{pixel_x = -10; pixel_y = 3},/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"bp" = (/obj/machinery/door/unpowered/simple/wood{name = "Wooden shelter"},/turf/simulated/floor/wood,/area/marooned/marooned_hut) +"bq" = (/obj/item/weapon/ore/slag{pixel_x = -5; pixel_y = 5},/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"br" = (/obj/random/trash,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"bs" = (/obj/item/trash/candy/proteinbar,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"bt" = (/obj/effect/overmap/sector/marooned,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"bu" = (/obj/effect/decal/cleanable/blood/drip,/obj/effect/decal/cleanable/ash,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"bv" = (/obj/effect/decal/cleanable/dirt,/obj/item/weapon/ore/slag,/turf/simulated/floor/beach/sand,/area/marooned/marooned_snow) +"bw" = (/obj/item/weapon/material/shard{icon_state = "piecesmall"; pixel_x = 10; pixel_y = -8},/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"bx" = (/obj/item/stack/material/steel,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/beach/sand,/area/marooned/marooned_snow) +"by" = (/obj/effect/shuttle_landmark/nav_marooned/nav3,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"bz" = (/obj/item/weapon/material/shard{icon_state = "shrapnelmedium"},/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"bA" = (/obj/effect/shuttle_landmark/nav_marooned/nav1,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"bB" = (/obj/effect/shuttle_landmark/nav_marooned/nav2,/turf/simulated/floor/marooned/snow,/area/marooned/marooned_snow) +"bC" = (/obj/effect/landmark/random_gen/asteroid{generation_height = 100; generation_width = 100},/turf/unsimulated/mineral,/area/marooned/marooned_snow) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadaeadadadadadadadadadadadadadadadadadadaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadaeadadadadadadadadadadadadadadadadadaeaeadadadadadadadadadadaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadaeadadaeadadadadaeadadadadadadaeaeadadaeadadadadadaeadadadadadaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadaeaeaeaeaeaeadadaeaeaeadadaeaeaeaeadadaeadadadadaeaeaeaeaeadadaeadadaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadaeaeadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadaeadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeafaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadahaiajakadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadalamalakadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadaeaeaeaeaeaeanafaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeafaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadakalaoalapadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaqaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadarasatasauaeadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeavavaeaeaeaeaeaeaeaeaeafaeawawawaxayawawawaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadazaAaeaAaBaCaeadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaDaeaeaeaeaeaeawaEaEaFaFaFaGawaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadaHaAaeaAauaIauadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeafaeaeaeaeaeaeaeaJaeaeaeagaeaeaeawaFaFaFaFaFaKawaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadaraAaLaMauauaNadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaDaeaJaeaeaeavaeaeaeaeaOaFaPaFaFaFaQaRaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadaeaAaeaAaHaraeadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaSavaTavaJaeaeaeaeaeaUaVaFaFaFaWaFaXaYaZaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadaHaebaaLaAaeaeaeadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeavaeavaeaeaebbbcaebdaFaFaFaFaFaFaXaebeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadaeaHaAaLaAbfaraeaeadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeavaebgbhbgaeaeaeavavawbiaFaFaFaFaFawaeavaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadaeadadadadadadadadadadadadadadadadadadadaeaAaeaAaearaeaeaeadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeaebgbhbgbgaeaeaeavawbjbkaFaFblbmawaeavaeafaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadaeadadadadadadadadadadadadadadadadadadbnboaAaeaAbbaeaeaeaeadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeafaeaebgbgbgbgbgbgaeaeavawawawbpbpawawawavaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadavaeaeaeaeadadadadadadadadadadadadadadadadadadaebqbaaeaAaeaeaeaeaeadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaebgbgbgbgafaeaeaeaeavavavavavavavavavaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadaeaeavaeaeadadadadadadadadadadadadadadadadadadadaAaraAaeaeaeaeaeadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeaebgbgbgaeaeaeaeaeaeaeaeaebraeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadavaeadaeaeaeadadadadadadadadadadadadadadaAaeaAaeaeaeaeadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaebsaeaeaeaeaebtaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadaeavavaeaeaeaeaeadadadadadadadadadadadadaAaeaAaeaHaeaeadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeadadadadadadadadadadadaeaeadaeaeaeaeaeaeaeadadadadadadadadaAbuaAaeaeaeadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaDaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadaeaeaeaeaeadadadadadadadadbvaeaAaeaHaeaeaeadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadaeaeadadaeaeaeavaeaeaeaeadadaeaeaeaeaeaeaeaeadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadaeaeadadadadaeaeavaeaeavaeadadaeaeaeaeaDaeadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeadadaeaeaeaeaeaeaeaeaeadadaeadadaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadaeaeadadaeaeaeadadadadaLaeavaeaeaeaeaeaeaeadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadaeaeaeaeaeaeaeaeadadadadaeaeaeadadadadadadadadadadadadaeaeaeaeaeadaeaeadadadadadadadadadadadadadadaeaeaeaeadadaeaeadadadadadadadaeaeadadadadaeaeadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadaeaeaeadadaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeadadadadadadadadadadadaeaeaeadadaeadadadaeadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadaeadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeadaeaeadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadaeaeadadaeaeaeadadadaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeadadadaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadaeadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeadadbwbxbbaeaeaeaeadadaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeadadadadadadadadaeaeaeaeaeaeaeaebyaeaeaeaeaeaeaeaeaeaeaeaeadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadaeaeaeaeaeagaeaeaeadadaeaAaAaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeadadadadadadaeadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaebzbxaeaeaAaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadaeaeaeadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaebbaAaeaeaeaAaeaebgaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadaeaeaeadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaAaeaeaeaeaeaebgbgbgaeagaeaeadadadadadadadadadadadadadadadadadadadadadadadadaeaeadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaAaeaeaDaeaebgbgbgbgbgaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadaeaeaeadadadadadadaeaeadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadaeaeadadadadadaeaeaeaeaeaAaeaeaeaebgbgbgbgbgbgbgaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadaeaeaeaeadadaeaeaeaeaeaeaeaAaeaeaebgbgbgbgbgbgbgaeaeaeaeadadadadadadadadadadadadadadadadadadaeaeadadadadaeaeaeaeadadadadadaeadadaeaeaeaeaeaeadadadadaeaeaeaeaeadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaebgbgbgbgbgbgbgaeaeaeaeaeadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeadadadadadaeaeadadadadaeaeaeadadadadadaeadadadaeaeadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaebgbgbgbgbgbgbgaeaeaeaeaeaeadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeadadadadadadadadadadadadaeaeadadadadadadadadadaeaeadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaebgbgbgbgbgbgaeaeaeagaeaeadadadadadadadadadadadadadadadadadaeaeadaeaeaeaeadadadadadadadadadadadadadadaeaeaeadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadaeaeaeaeaDaeaeaeaeaeaeaeaeaeaeaebgbgbgbgaeaeaeaeaeaeaeaeadadadadadadaeaeaeaeaeaeaeaeaeaeaeadadaeaeaeaeaeaeaeadadadadadadaeaeaeadadadaeaeadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaebgaeaeaeadadaeaeaeadadadadadadaeaeaeaeaeaeaeaeaeaeaeadadadadadaeaeaeaeadadadadadadaeadaeaeaeaeaeadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeadadadaeaeaeaeaeaeadadadaeaeaeadadadadadadadadadadadaeaeaeaeaeaeaeaeadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadaeaeadadaeaeaeaeaeaeadadadadaeaeaeaeadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadaeaeaeadadadadaeaeadadadadadadaeaeaeaeadadadadadadadadadadadadadadadadadadadaeaeaeaeadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadaeaeaeaeadadadadadadadadadadadadaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadaeaeaeaeadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadaeaeadadadadadadadadadadadadadadaeaeadadadadadadadadadadadadadadadadadadadadadadaeaeadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeadadadaeaeadaeaeadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeadadadaeaeaeaeaeadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadaeaeaeaeaeaeaeadadadadaeaeaeaeaeaeadadadadadadadadadadadadadadaeaeaeaeaeaeadadaeaeaeaeaeaeadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadaeaeaeaeaeaeaeaeaeaeaeadadaeaeaeaeaeaeadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeagaeaeaeaeaeadadadadaeaeaeagaeaeaeaeaeaeaeaeaeadadadadadaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeagaeaeaeaeaeadadadadadadadaeaeaeaeaeadadadadadaeaeadadadadadadaeaeaeadadadadadaeadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadaeaeaeaeaeaeaeaeadadadadadadadadaeaeaeaeadadadadadaeaeaeadadadadadadadadadadadadadaeadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaebAaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadaeaeaeaeaeaeaeaeadadadadadadadadadaeaeaeadadadadadadaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadaeadaeaeaeaeaeaeaeaeadadadadadadadadadadaeadadadadadadaeadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadaeadadadadadadaeaeadadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadaeaeaeaeaeaeaeaeaeadadadadadadadadadadaeadadadadadadadaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeadaeadadadadadadadadadadadadadadadadadaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadaeaeaeaebBaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadaeadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadaeadadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadaeaeaeaeaeaeaeadadadaeaeaeaeaeadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadaeaeaeaeaeaeaeaeadadadaeadaeaeaeadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadaeagaeaeaeaeaeaeagaeaeaeaeadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadaeadadaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadaeaeaeaeaeaeaeaeadaeadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadaeadadadadadaeaeaeaeaeaeaeaeaeaeadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadaeaeaeadaeaeadadadadadadadadadadadadadaeadadaeaeaDaeagaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadaeaeaeaeaeadadadadadadadadadadadadadadadadadadadaeaeaeaeaeaeaeaeaeaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeaeadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaeadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababacadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababbCacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/marooned/marooned_areas.dm b/maps/away/marooned/marooned_areas.dm new file mode 100644 index 00000000..5842abea --- /dev/null +++ b/maps/away/marooned/marooned_areas.dm @@ -0,0 +1,12 @@ +/area/marooned/marooned_snow + name = "\improper Snow-covered mountain area" + icon_state = "marooned_snow" + icon = 'marooned_sprites.dmi' + sound_env = FOREST + dynamic_lighting = 0 + +/area/marooned/marooned_hut + name = "\improper Little wooden hut" + icon_state = "marooned_hut" + icon = 'marooned_sprites.dmi' + dynamic_lighting = 0 diff --git a/maps/away/marooned/marooned_sprites.dmi b/maps/away/marooned/marooned_sprites.dmi new file mode 100644 index 00000000..3381a078 Binary files /dev/null and b/maps/away/marooned/marooned_sprites.dmi differ diff --git a/maps/away/mining/mining-asteroid.dmm b/maps/away/mining/mining-asteroid.dmm new file mode 100644 index 00000000..17dbe0ad --- /dev/null +++ b/maps/away/mining/mining-asteroid.dmm @@ -0,0 +1,283 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/turf/unsimulated/mask,/area/mine/unexplored) +"af" = (/turf/simulated/floor/asteroid,/area/mine/explored) +"aj" = (/turf/simulated/wall/r_wall,/area/djstation) +"ak" = (/obj/random/junk,/turf/simulated/floor/asteroid,/area/mine/explored) +"al" = (/obj/random/trash,/turf/simulated/floor/tiled/airless,/area/djstation) +"am" = (/obj/structure/computerframe,/turf/simulated/floor/airless,/area/djstation) +"an" = (/obj/machinery/teleport/station,/turf/simulated/floor/airless,/area/djstation) +"ao" = (/obj/machinery/teleport/hub,/turf/simulated/floor/airless,/area/djstation) +"ap" = (/obj/structure/table/glass,/obj/random/maintenance,/turf/simulated/floor/airless,/area/djstation) +"aq" = (/obj/structure/table/glass,/obj/random/maintenance,/turf/simulated/floor/tiled/airless,/area/djstation) +"ar" = (/turf/simulated/floor/tiled/airless,/area/djstation) +"as" = (/obj/random/junk,/turf/simulated/floor/tiled/airless,/area/djstation) +"at" = (/turf/simulated/floor/airless,/area/djstation) +"av" = (/obj/structure/table/glass,/obj/random/loot,/turf/simulated/floor/airless,/area/djstation) +"aw" = (/obj/random/closet,/obj/random/loot,/turf/simulated/floor/tiled/airless,/area/djstation) +"ax" = (/obj/random/junk,/turf/simulated/floor/airless,/area/djstation) +"ay" = (/obj/structure/computerframe,/turf/simulated/floor/tiled/airless,/area/djstation) +"az" = (/obj/structure/table/rack,/obj/random/maintenance,/obj/random/tool,/turf/simulated/floor/airless,/area/djstation) +"aA" = (/obj/structure/table/reinforced,/obj/random/maintenance,/turf/simulated/floor/tiled/airless,/area/djstation) +"aB" = (/obj/random/trash,/turf/simulated/floor/airless,/area/djstation) +"aC" = (/obj/structure/table/reinforced,/turf/simulated/floor/airless,/area/djstation) +"aE" = (/obj/structure/table/reinforced,/obj/random/loot,/turf/simulated/floor/tiled/airless,/area/djstation) +"aF" = (/obj/structure/table/reinforced,/turf/simulated/floor/tiled/airless,/area/djstation) +"aG" = (/obj/random/maintenance,/turf/simulated/floor/tiled/airless,/area/djstation) +"aH" = (/obj/structure/barricade,/turf/simulated/floor/airless,/area/djstation) +"aI" = (/obj/random/closet,/turf/simulated/floor/tiled/airless,/area/djstation) +"aJ" = (/obj/structure/table,/turf/simulated/floor/tiled/airless,/area/djstation) +"aK" = (/obj/machinery/door/airlock/maintenance,/turf/simulated/floor/tiled/airless,/area/djstation) +"aL" = (/turf/simulated/wall,/area/djstation) +"aM" = (/obj/structure/grille,/turf/simulated/floor/airless,/area/djstation) +"aN" = (/obj/structure/grille/broken,/obj/random/trash,/turf/simulated/floor/airless,/area/djstation) +"aO" = (/obj/random/maintenance,/turf/simulated/floor/airless,/area/djstation) +"aP" = (/obj/structure/grille/broken,/turf/simulated/floor/airless,/area/djstation) +"aQ" = (/obj/random/medical,/turf/simulated/floor/tiled/airless,/area/djstation) +"aR" = (/obj/structure/bed,/turf/simulated/floor/tiled/airless,/area/djstation) +"aS" = (/obj/machinery/door/airlock/glass,/turf/simulated/floor/tiled/airless,/area/djstation) +"aT" = (/obj/random/loot,/turf/simulated/floor/tiled/airless,/area/djstation) +"aU" = (/obj/random/closet,/obj/random/maintenance,/turf/simulated/floor/airless,/area/djstation) +"aV" = (/obj/structure/flora/pottedplant/dead,/turf/simulated/floor/tiled/airless,/area/djstation) +"aW" = (/obj/machinery/door/airlock/maintenance,/turf/simulated/floor/airless,/area/djstation) +"aX" = (/obj/structure/table/steel,/obj/random/maintenance,/turf/simulated/floor/tiled/airless,/area/djstation) +"aY" = (/obj/random/closet,/turf/simulated/floor/airless,/area/djstation) +"aZ" = (/obj/structure/table/rack,/obj/random/maintenance,/obj/random/maintenance,/obj/random/action_figure,/turf/simulated/floor/tiled/airless,/area/djstation) +"ba" = (/obj/structure/table/rack,/obj/random/maintenance,/obj/random/maintenance,/turf/simulated/floor/tiled/airless,/area/djstation) +"bb" = (/obj/structure/table/rack,/obj/random/junk,/obj/random/maintenance,/turf/simulated/floor/tiled/airless,/area/djstation) +"bc" = (/obj/structure/girder,/turf/simulated/floor/tiled/airless,/area/djstation) +"bd" = (/obj/structure/largecrate,/turf/simulated/floor/tiled/airless,/area/djstation) +"be" = (/obj/random/maintenance,/turf/simulated/floor/asteroid,/area/mine/explored) +"bf" = (/obj/effect/overmap/sector/cluster,/turf/simulated/floor/asteroid,/area/mine/explored) +"cb" = (/obj/effect/shuttle_landmark/cluster/nav5,/turf/simulated/floor/asteroid,/area/mine/explored) +"db" = (/obj/effect/shuttle_landmark/cluster/nav6,/turf/space,/area/space) +"eb" = (/obj/effect/shuttle_landmark/cluster/nav4,/turf/space,/area/space) +"fb" = (/obj/effect/shuttle_landmark/cluster/nav2,/turf/space,/area/space) +"gb" = (/obj/effect/shuttle_landmark/cluster/nav3,/turf/space,/area/space) +"hb" = (/obj/effect/shuttle_landmark/cluster/nav1,/turf/space,/area/space) +"ib" = (/obj/effect/shuttle_landmark/cluster/nav7,/turf/simulated/floor/asteroid,/area/mine/explored) +"jb" = (/obj/machinery/access_button/airlock_exterior{master_tag = "lp_north_airlock"; name = "exterior access button"; pixel_y = -24},/turf/simulated/floor/asteroid,/area/mine/explored) +"kb" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "lp_north_outer"; locked = 1},/turf/simulated/floor/airless,/area/djstation) +"lb" = (/obj/machinery/embedded_controller/radio/airlock/airlock_controller{id_tag = "lp_north_airlock"; pixel_x = 24; tag_airpump = "lp_north_pump"; tag_chamber_sensor = "lp_north_sensor"; tag_exterior_door = "lp_north_outer"; tag_interior_door = "lp_north_inner"},/turf/simulated/floor/airless,/area/djstation) +"mb" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{frequency = 1379; id_tag = "lp_north_pump"},/turf/simulated/floor/airless,/area/djstation) +"nb" = (/obj/machinery/airlock_sensor{id_tag = "lp_north_sensor"; master_tag = "lp_north_airlock"; pixel_x = 24},/turf/simulated/floor/airless,/area/djstation) +"ob" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "lp_north_inner"; locked = 1},/obj/machinery/atmospherics/pipe/simple/visible,/turf/simulated/floor/airless,/area/djstation) +"pb" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "lp_north_inner"; locked = 1},/turf/simulated/floor/airless,/area/djstation) +"qb" = (/obj/machinery/atmospherics/portables_connector{dir = 4},/turf/simulated/floor/airless,/area/djstation) +"rb" = (/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor/airless,/area/djstation) +"sb" = (/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/obj/machinery/access_button/airlock_interior{master_tag = "lp_north_airlock"; name = "interior access button"; pixel_y = 24},/turf/simulated/floor/airless,/area/djstation) +"tb" = (/obj/machinery/atmospherics/pipe/simple/visible{icon_state = "intact"; dir = 9},/turf/simulated/floor/airless,/area/djstation) +"ub" = (/obj/machinery/access_button{command = "cycle_interior"; frequency = 1379; master_tag = "lp_east_airlock"; name = "interior access button"; pixel_x = 24; pixel_y = 0; req_access = null},/turf/simulated/floor/tiled/airless,/area/djstation) +"vb" = (/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1379; master_tag = "lp_east_airlock"; name = "exterior access button"; pixel_x = -24; pixel_y = 0; req_access = null},/turf/simulated/floor/asteroid,/area/mine/explored) +"wb" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "lp_east_inner"; locked = 1},/turf/simulated/floor/airless,/area/djstation) +"xb" = (/obj/random/trash,/obj/machinery/airlock_sensor{frequency = 1379; id_tag = "lp_east_sensor"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/airless,/area/djstation) +"yb" = (/obj/random/maintenance,/obj/machinery/embedded_controller/radio/airlock/airlock_controller{id_tag = "lp_east_airlock"; pixel_x = 0; pixel_y = 24; tag_airpump = "lp_east_pump"; tag_chamber_sensor = "lp_east_sensor"; tag_exterior_door = "lp_east_outer"; tag_interior_door = "lp_east_inner"},/turf/simulated/floor/airless,/area/djstation) +"zb" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "lp_east_outer"; locked = 1},/turf/simulated/floor/airless,/area/djstation) +"Ab" = (/obj/machinery/atmospherics/pipe/simple/visible{dir = 6; icon_state = "intact"},/turf/simulated/floor/airless,/area/djstation) +"Bb" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "lp_east_inner"; locked = 1},/obj/machinery/atmospherics/pipe/simple/visible{icon_state = "intact"; dir = 4},/turf/simulated/floor/airless,/area/djstation) +"Cb" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1379; id_tag = "lp_east_pump"},/turf/simulated/floor/airless,/area/djstation) +"Db" = (/obj/machinery/atmospherics/pipe/simple/visible,/turf/simulated/floor/airless,/area/djstation) +"Eb" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/turf/simulated/floor/airless,/area/djstation) +"Fb" = (/obj/effect/landmark/random_gen/asteroid{generation_height = 200; generation_width = 200},/turf/space,/area/space) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaabababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababaaaaaaaaaaababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababaaababaaaaaaaaaaaaabababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaababababababababababaaababaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaababaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahbaaaaaaaaaaaaaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaabababababababababababaaaaaaaaabaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaaaaaaaaaaabababababababababababaaaaaaababababaaaaabaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaaaaaaaaaaaaaaabababababababababaaaaababababababaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaababababababaaababababababababaaaaaaaaaaababaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaabababababababaaaaabababababababaaaaaaaaaaababababaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabaaabaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaabababababababaaaaabababababababaaaaaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaabababababababaaaaaaaaabababaaaaaaaaaaababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaabababaaaaaaaaaaaaabababababababababababababaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaababababababababaaaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaaaababababababababaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaaaabababababababaaaaabababababababababababababaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaaaaaaaaaababababaaaaaaaaababababababababababababababaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaabababaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaababababababababaaaaaaaaababaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaebaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaabababaaaaaaaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababaaaaaaaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaaaaaaaaaabababababababababababababaaaaaaaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaaaaaaaaaabababababababababababababaaaaaaaaababababababababababababaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababaaaaaaaaaaaaaaababababababababababababababaaaaabababababababaaaaaaababababaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababaaaaaaaaaaaaaaabababababababababababababaaaaaaaaababababaaaaaaabababababaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababaaaaaaaaaaaaaaabababababababababababababaaaaaaaaaaababaaaaaaaaababababaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaababaaabaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafbfafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafibafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadbaaaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafabababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafabababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafababababajajajajajajajababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafakafababababajalamanaoapajababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababjbafafafababababajaqarasatarajababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajkbkbajababababajavataratawajababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajaxlbajababababajaratararayajababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajmbnbajababababajajajarajajajababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajajajajajobpbajajajajajababajarajabababababafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajqbrbrbsbtbaraAarararajababajaBajabababababafafafafafafafafafafafafafafafafafafafafafafafafababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajazalararararaCataBarajababajarajabababababafafafafafafafafafafafafafafafafafafafafafafafabababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajataratasararaEaFatarajajajajarajababababafafafafafafafafafafafafafafafafafafafafafafafafabababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajatarararataGaratararaHatatatarajababababafafafafafafafafafafafafafafafafafafafafafafafafababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajaIaJatarararalarararajajajajajajababababafafafafafafafafafafafafafafafafafafafafafafafafababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajajajaKaKaLaLaMaMaNaLajabababababababababafafafafafafafafafafafafafafafafafafafafafafafafababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajaOaraPaJaQarararajabababababababababafafafafafafafafafafafafafafafafafafafafafafafafababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajataraMarataraGaRajabababababababababafafafafafafafafafafafafafafafafafafafafafafafafababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajataraSarasatalarajabababababababababafafafafafafafafafafafafafafafafafafafafafafafafababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajataraSararaGaraRajababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafabababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajataraHaTatararaUajababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafabababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajaBaraPaVajajajajajababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafabababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajajajaWaKaLaLajababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafabababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajaXarataraYasajabababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafafafababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajaZatarararatajabababababababababababafafafafafafafafafafafafafafcbafafafafafafafafafafafafafafabababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajbaaraOatarubajajajajajvbafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafabababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajbbasarararararwbxbybzbafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafabababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajaXararatatarAbBbCbatzbafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajajajajararaODbajajajajafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajarbcarDbajababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafafafababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajaIbcbdEbajababababababababababbeafafafafafafafafafafafafafafafafafafafafafafafafafafababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababajajajajajajabababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafabababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafabababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafafabababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafabababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafabababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafafafabababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafafafababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafafafababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafafafafabababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafafafafafafafafafabababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababafafafafafafafafababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababaaabababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababaaaaaaaaabababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaababababaaababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +Fbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/mining/mining-signal.dmm b/maps/away/mining/mining-signal.dmm new file mode 100644 index 00000000..de9a1918 --- /dev/null +++ b/maps/away/mining/mining-signal.dmm @@ -0,0 +1,606 @@ +"aa" = (/turf/unsimulated/mask,/area/mine/unexplored) +"ab" = (/turf/simulated/floor/asteroid,/area/mine/explored) +"af" = (/turf/simulated/wall/titanium,/area/outpost/abandoned) +"ag" = (/obj/structure/table/rack,/obj/random/tech_supply,/obj/random/bomb_supply,/turf/simulated/floor/holofloor/tiled/dark,/area/outpost/abandoned) +"ah" = (/obj/structure/table/rack,/obj/random/tech_supply,/obj/random/loot,/obj/random/loot,/turf/simulated/floor/holofloor/tiled/dark,/area/outpost/abandoned) +"ai" = (/obj/structure/table/steel_reinforced,/obj/item/mecha_parts/part/durand_right_arm,/turf/simulated/floor/holofloor/tiled/dark,/area/outpost/abandoned) +"aj" = (/obj/machinery/porta_turret/stationary,/turf/simulated/floor/holofloor/tiled/dark,/area/outpost/abandoned) +"ak" = (/obj/structure/table/rack,/obj/item/weapon/cell/hyper,/obj/item/weapon/cell/hyper,/turf/simulated/floor/holofloor/tiled/dark,/area/outpost/abandoned) +"al" = (/obj/structure/table/steel_reinforced,/turf/simulated/floor/holofloor/tiled/dark,/area/outpost/abandoned) +"am" = (/obj/structure/table/rack,/obj/random/energy,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{icon_state = "rwindow"; dir = 4},/obj/machinery/door/window/brigdoor/southleft,/turf/simulated/floor/holofloor/tiled/dark,/area/outpost/abandoned) +"an" = (/obj/machinery/mech_recharger,/obj/machinery/door/window/brigdoor/southright,/obj/structure/window/reinforced{dir = 8},/obj/item/mecha_parts/chassis/durand,/turf/simulated/floor/holofloor/tiled/dark,/area/outpost/abandoned) +"ao" = (/turf/simulated/floor/holofloor/tiled/dark,/area/outpost/abandoned) +"ap" = (/obj/structure/table,/turf/simulated/floor/plating,/area/outpost/abandoned) +"aq" = (/obj/machinery/constructable_frame/machine_frame,/turf/simulated/floor/plating,/area/outpost/abandoned) +"ar" = (/obj/structure/computerframe,/turf/simulated/floor/airless,/area/outpost/abandoned) +"as" = (/obj/machinery/teleport/station,/turf/simulated/floor/airless,/area/outpost/abandoned) +"at" = (/obj/machinery/teleport/hub,/turf/simulated/floor/airless,/area/outpost/abandoned) +"au" = (/obj/structure/table,/obj/random/toolbox,/turf/simulated/floor/tiled,/area/outpost/abandoned) +"av" = (/turf/unsimulated/mask,/area/outpost/abandoned) +"aw" = (/obj/structure/table/glass,/obj/item/weapon/newspaper,/obj/effect/floor_decal/corner/paleblue/diagonal,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"ax" = (/obj/structure/table/glass,/obj/effect/floor_decal/corner/paleblue/diagonal,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"ay" = (/obj/structure/table,/obj/effect/floor_decal/corner/paleblue/diagonal,/obj/item/mecha_parts/part/durand_right_leg,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"az" = (/obj/effect/floor_decal/corner/paleblue/diagonal,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"aA" = (/turf/simulated/floor/diona,/area/outpost/abandoned) +"aB" = (/obj/machinery/papershredder,/obj/effect/floor_decal/corner/paleblue/diagonal,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"aC" = (/obj/structure/table/glass,/obj/effect/floor_decal/corner/paleblue/diagonal,/obj/random/loot,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"aD" = (/obj/machinery/light/small/emergency{icon_state = "bulb1"; dir = 8},/turf/simulated/floor/holofloor/tiled/dark,/area/outpost/abandoned) +"aE" = (/obj/random/trash,/turf/simulated/floor/holofloor/tiled/dark,/area/outpost/abandoned) +"aF" = (/obj/random/technology_scanner,/obj/machinery/porta_turret/stationary,/turf/simulated/floor/holofloor/tiled/dark,/area/outpost/abandoned) +"aG" = (/obj/machinery/light/small/emergency{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/holofloor/tiled/dark,/area/outpost/abandoned) +"aH" = (/turf/simulated/floor/plating,/area/outpost/abandoned) +"aI" = (/turf/simulated/floor/tiled,/area/outpost/abandoned) +"aJ" = (/obj/structure/table,/obj/effect/floor_decal/corner/paleblue/diagonal,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"aK" = (/obj/structure/bed/chair/office/dark{icon_state = "officechair_dark"; dir = 8},/obj/effect/floor_decal/corner/paleblue/diagonal,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"aL" = (/obj/structure/bed/chair/office/dark{icon_state = "officechair_dark"; dir = 4},/obj/effect/floor_decal/corner/paleblue/diagonal,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"aM" = (/obj/structure/table/glass,/obj/item/weapon/pen,/obj/effect/floor_decal/corner/paleblue/diagonal,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"aN" = (/obj/machinery/door/airlock/highsecurity,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"aO" = (/obj/effect/decal/cleanable/blood,/obj/item/weapon/material/shard,/turf/simulated/floor/tiled/freezer,/area/outpost/abandoned) +"aP" = (/obj/machinery/door/window/brigdoor/northright,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/freezer,/area/outpost/abandoned) +"aQ" = (/obj/machinery/mech_recharger,/turf/simulated/floor/tiled,/area/outpost/abandoned) +"aR" = (/obj/machinery/mech_recharger,/obj/effect/decal/mecha_wreckage/ripley,/turf/simulated/floor/tiled,/area/outpost/abandoned) +"aS" = (/obj/machinery/light/small/emergency{icon_state = "bulb1"; dir = 8},/turf/simulated/floor/plating,/area/outpost/abandoned) +"aT" = (/obj/random/tool,/turf/simulated/floor/tiled,/area/outpost/abandoned) +"aU" = (/obj/random/material,/turf/simulated/floor/plating,/area/outpost/abandoned) +"aV" = (/obj/structure/computerframe,/turf/simulated/floor/tiled,/area/outpost/abandoned) +"aW" = (/obj/structure/table/glass,/obj/item/weapon/paper_bin,/obj/machinery/light/small{dir = 8},/obj/effect/floor_decal/corner/paleblue/diagonal,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"aX" = (/obj/machinery/r_n_d/circuit_imprinter{icon_state = "circuit_imprinter_t"; stat = 1},/obj/effect/floor_decal/corner/paleblue/diagonal,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"aY" = (/obj/machinery/r_n_d/protolathe{icon_state = "protolathe_t"; stat = 1},/obj/effect/floor_decal/corner/paleblue/diagonal,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"aZ" = (/obj/structure/table/glass,/obj/item/weapon/paper_bin,/obj/machinery/light/small{dir = 4},/obj/effect/floor_decal/corner/paleblue/diagonal,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"ba" = (/obj/machinery/door/window/brigdoor/northleft,/turf/simulated/floor/tiled/freezer,/area/outpost/abandoned) +"bb" = (/obj/machinery/door/window/brigdoor/northright,/turf/simulated/floor/tiled/freezer,/area/outpost/abandoned) +"bc" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/holofloor/tiled/dark,/area/outpost/abandoned) +"be" = (/obj/effect/decal/cleanable/blood,/obj/random/loot,/turf/simulated/floor/tiled/freezer,/area/outpost/abandoned) +"bf" = (/obj/structure/table/glass,/obj/item/weapon/cell/potato,/obj/effect/floor_decal/corner/paleblue/diagonal,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bg" = (/obj/item/weapon/pen,/obj/effect/floor_decal/corner/paleblue/diagonal,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bh" = (/obj/structure/table/rack,/obj/item/weapon/rig/hazmat,/turf/simulated/floor/tiled/freezer,/area/outpost/abandoned) +"bi" = (/obj/structure/table/rack,/obj/random/loot,/turf/simulated/floor/tiled/freezer,/area/outpost/abandoned) +"bj" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/freezer,/area/outpost/abandoned) +"bk" = (/obj/machinery/light/small,/turf/simulated/floor/tiled,/area/outpost/abandoned) +"bl" = (/obj/machinery/light/small/emergency,/turf/simulated/floor/tiled,/area/outpost/abandoned) +"bm" = (/obj/machinery/door/airlock/glass_science,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bn" = (/obj/machinery/door/airlock/vault/bolted,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"bo" = (/obj/machinery/door/blast/shutters{icon_state = "shutter1"; dir = 2},/turf/simulated/floor/tiled,/area/outpost/abandoned) +"bp" = (/obj/machinery/door/airlock/glass_science{icon_state = "door_locked"; locked = 1; secured_wires = 1},/turf/simulated/floor/tiled,/area/outpost/abandoned) +"bq" = (/obj/machinery/door/airlock/glass_science,/obj/structure/barricade,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"br" = (/obj/structure/table/steel,/obj/effect/floor_decal/corner/purple/three_quarters{dir = 8},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bs" = (/obj/structure/bed/chair,/obj/effect/floor_decal/corner/purple{dir = 5},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bt" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/corner/purple{dir = 5},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bu" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/corner/purple{dir = 5},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bv" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/light/small{dir = 1},/obj/effect/floor_decal/corner/purple{dir = 5},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bw" = (/obj/random/trash,/obj/effect/floor_decal/corner/purple{dir = 5},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bx" = (/obj/effect/floor_decal/corner/purple{dir = 5},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"by" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/diona,/area/outpost/abandoned) +"bz" = (/obj/item/ammo_casing/shotgun/pellet,/obj/item/ammo_casing/shotgun/pellet{pixel_x = 10; pixel_y = -10},/obj/effect/decal/cleanable/blood{pixel_x = 0; pixel_y = 32},/obj/effect/floor_decal/corner/purple{dir = 5},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bA" = (/obj/item/ammo_casing/shotgun/pellet{pixel_x = -5},/obj/effect/decal/cleanable/blood{pixel_x = -32},/obj/effect/floor_decal/corner/purple{dir = 5},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bB" = (/obj/effect/decal/cleanable/dirt,/obj/structure/noticeboard/anomaly{pixel_y = 32},/obj/effect/floor_decal/corner/purple{dir = 5},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bC" = (/obj/effect/floor_decal/corner/purple{dir = 5},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bD" = (/obj/machinery/light/small{dir = 1},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/diona,/area/outpost/abandoned) +"bE" = (/obj/effect/floor_decal/corner/purple{dir = 5},/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bF" = (/obj/machinery/light/small{dir = 1},/obj/effect/floor_decal/corner/purple{dir = 5},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bG" = (/obj/structure/table/steel,/obj/effect/floor_decal/corner/purple{dir = 9},/obj/random/loot,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bH" = (/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bI" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/cigbutt/cigarbutt,/turf/simulated/floor/diona,/area/outpost/abandoned) +"bJ" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bK" = (/obj/effect/gibspawner/human,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bL" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bM" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bN" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bO" = (/obj/effect/floor_decal/corner/purple/three_quarters,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bP" = (/obj/effect/floor_decal/corner/purple{dir = 10},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bQ" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/corner/purple{dir = 10},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bR" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/light/small,/turf/simulated/floor/diona,/area/outpost/abandoned) +"bS" = (/obj/random/trash,/turf/simulated/floor/diona,/area/outpost/abandoned) +"bT" = (/obj/effect/floor_decal/corner/purple{dir = 10},/obj/effect/floor_decal/corner/purple{dir = 10},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bU" = (/obj/effect/floor_decal/corner/purple{dir = 10},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bV" = (/obj/machinery/light/small,/obj/effect/floor_decal/corner/purple{dir = 10},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bW" = (/obj/machinery/door/airlock/security,/obj/machinery/door/blast/regular{id = "mars_blast"},/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"bX" = (/obj/machinery/door/airlock/science,/obj/machinery/door/blast/regular{id = "mars_blast"},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bY" = (/obj/machinery/door/airlock/glass,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"bZ" = (/obj/effect/wingrille_spawn,/turf/simulated/floor/plating,/area/outpost/abandoned) +"ca" = (/obj/structure/table/steel,/obj/effect/floor_decal/corner/paleblue/three_quarters{icon_state = "corner_white_three_quarters"; dir = 8},/obj/random/loot,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"cb" = (/obj/structure/table/steel,/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 5},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"cc" = (/obj/machinery/optable,/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 5},/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"cd" = (/obj/machinery/computer/operating,/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 5},/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"ce" = (/obj/structure/closet/secure_closet/medical2,/obj/effect/floor_decal/corner/paleblue/three_quarters{icon_state = "corner_white_three_quarters"; dir = 1},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"cf" = (/obj/effect/floor_decal/corner/red/three_quarters{icon_state = "corner_white_three_quarters"; dir = 8},/obj/effect/decal/cleanable/dirt,/obj/item/ammo_casing/a50,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"cg" = (/obj/effect/floor_decal/corner/red{icon_state = "corner_white"; dir = 5},/obj/effect/decal/cleanable/dirt,/obj/item/ammo_casing/a50,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"ch" = (/obj/structure/table/steel_reinforced,/obj/machinery/embedded_controller/radio/airlock/access_controller,/obj/effect/floor_decal/corner/red/three_quarters{icon_state = "corner_white_three_quarters"; dir = 1},/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"ci" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/plating,/area/outpost/abandoned) +"cj" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"ck" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/diona,/area/outpost/abandoned) +"cl" = (/obj/machinery/shower{icon_state = "shower"; dir = 8},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 5},/obj/structure/window/reinforced/tinted/frosted,/obj/machinery/atmospherics/unary/vent_pump{icon_state = "map_vent"; dir = 4},/obj/structure/sign/warning/secure_area{pixel_y = 32},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"cm" = (/obj/effect/floor_decal/spline/fancy/wood{icon_state = "spline_fancy"; dir = 9},/turf/simulated/floor/wood,/area/outpost/abandoned) +"cn" = (/obj/effect/floor_decal/spline/fancy/wood{icon_state = "spline_fancy"; dir = 1},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood{icon_state = "wood_broken3"},/area/outpost/abandoned) +"co" = (/obj/structure/table/woodentable,/obj/effect/decal/cleanable/dirt,/obj/random/trash,/turf/simulated/floor/wood,/area/outpost/abandoned) +"cp" = (/obj/structure/table/woodentable,/obj/item/weapon/board,/turf/simulated/floor/wood,/area/outpost/abandoned) +"cq" = (/obj/structure/table/woodentable,/obj/random/loot,/turf/simulated/floor/wood,/area/outpost/abandoned) +"cr" = (/obj/effect/floor_decal/spline/fancy/wood{icon_state = "spline_fancy"; dir = 1},/turf/simulated/floor/wood{icon_state = "wood_broken2"},/area/outpost/abandoned) +"cs" = (/obj/effect/floor_decal/spline/fancy/wood{icon_state = "spline_fancy"; dir = 5},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/outpost/abandoned) +"ct" = (/obj/machinery/door/airlock/centcom,/obj/machinery/door/blast/regular{id = "mars_blast"},/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"cu" = (/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 9},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"cv" = (/obj/effect/decal/cleanable/blood,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"cw" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"cx" = (/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"cy" = (/obj/effect/decal/cleanable/blood,/turf/simulated/wall/titanium,/area/outpost/abandoned) +"cF" = (/obj/structure/mirror{icon_state = "mirror_broke"; name = "mirror"; pixel_x = 30},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/red{icon_state = "intact"; dir = 10},/obj/effect/decal/cleanable/dirt,/obj/machinery/light/small/emergency{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"cG" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/wall/titanium,/area/outpost/abandoned) +"cH" = (/obj/effect/floor_decal/spline/fancy/wood{icon_state = "spline_fancy"; dir = 8},/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/outpost/abandoned) +"cI" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/outpost/abandoned) +"cJ" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood{icon_state = "wood_broken4"},/area/outpost/abandoned) +"cK" = (/obj/effect/floor_decal/plaque,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/outpost/abandoned) +"cL" = (/obj/effect/decal/cleanable/dirt,/obj/random/trash,/turf/simulated/floor/wood{icon_state = "wood_broken0"},/area/outpost/abandoned) +"cM" = (/obj/effect/floor_decal/spline/fancy/wood{icon_state = "spline_fancy"; dir = 4},/turf/simulated/floor/wood,/area/outpost/abandoned) +"cN" = (/obj/structure/filingcabinet/filingcabinet,/turf/simulated/floor/carpet/blue,/area/outpost/abandoned) +"cO" = (/obj/structure/table/woodentable,/obj/random/loot,/turf/simulated/floor/carpet/blue,/area/outpost/abandoned) +"cP" = (/obj/structure/bed/chair,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/carpet/blue,/area/outpost/abandoned) +"cQ" = (/turf/simulated/floor/carpet/blue,/area/outpost/abandoned) +"cR" = (/obj/structure/girder,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"cS" = (/obj/structure/filingcabinet/filingcabinet,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"cT" = (/obj/structure/foamedmetal,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"cU" = (/obj/effect/floor_decal/corner/paleblue/three_quarters,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"cV" = (/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 10},/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"cW" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"cX" = (/obj/effect/decal/cleanable/blood,/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 10},/obj/effect/decal/cleanable/dirt,/obj/random/loot,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"cY" = (/obj/effect/floor_decal/corner/paleblue/three_quarters{icon_state = "corner_white_three_quarters"; dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"cZ" = (/obj/effect/floor_decal/corner/red/three_quarters,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"da" = (/obj/structure/sign/poster{pixel_y = -32},/obj/effect/floor_decal/corner/red{icon_state = "corner_white"; dir = 10},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"db" = (/obj/effect/floor_decal/corner/red/three_quarters{icon_state = "corner_white_three_quarters"; dir = 4},/obj/item/modular_computer/console/preset/security,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"dc" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"dd" = (/obj/structure/barricade,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/diona,/area/outpost/abandoned) +"de" = (/obj/machinery/shower{icon_state = "shower"; dir = 8},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/red,/obj/structure/window/reinforced/tinted/frosted{icon_state = "fwindow"; dir = 1},/obj/machinery/atmospherics/unary/vent_pump{icon_state = "map_vent"; dir = 4},/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"df" = (/obj/effect/wingrille_spawn/reinforced,/obj/effect/decal/cleanable/dirt,/obj/machinery/door/blast/regular{id = "mars_blast"},/turf/simulated/floor/plating,/area/outpost/abandoned) +"dg" = (/obj/effect/floor_decal/spline/fancy/wood{icon_state = "spline_fancy"; dir = 10},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/carpet,/area/outpost/abandoned) +"dh" = (/turf/simulated/floor/carpet{icon_state = "carpet_broken"},/area/outpost/abandoned) +"di" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/carpet{icon_state = "carpet_broken"},/area/outpost/abandoned) +"dj" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/carpet,/area/outpost/abandoned) +"dk" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/carpet{icon_state = "carpet_broken"},/area/outpost/abandoned) +"dl" = (/obj/effect/floor_decal/spline/fancy/wood{icon_state = "spline_fancy"; dir = 6},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/carpet,/area/outpost/abandoned) +"dm" = (/obj/effect/wingrille_spawn/reinforced,/obj/machinery/door/blast/regular{id = "mars_blast"},/turf/simulated/floor/plating,/area/outpost/abandoned) +"do" = (/obj/effect/decal/cleanable/blood/gibs/limb,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/carpet/blue,/area/outpost/abandoned) +"dp" = (/obj/structure/janitorialcart,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"dq" = (/obj/structure/dispenser,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"dr" = (/obj/structure/barricade,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"ds" = (/obj/machinery/door/airlock/medical{density = 0; icon_state = "door_open"; opacity = 0},/obj/machinery/holosign/surgery,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"dt" = (/obj/structure/door_assembly/door_assembly_science{anchored = 1},/turf/simulated/floor/diona,/area/outpost/abandoned) +"du" = (/obj/machinery/atmospherics/pipe/simple/hidden/red,/turf/simulated/wall/titanium,/area/outpost/abandoned) +"dv" = (/turf/simulated/floor/asteroid,/turf/simulated/shuttle/wall{icon_state = "diagonalWall3"},/area/outpost/abandoned) +"dw" = (/obj/effect/floor_decal/spline/fancy/wood{icon_state = "spline_fancy"; dir = 10},/obj/structure/table/woodentable,/obj/random/loot,/turf/simulated/floor/carpet,/area/outpost/abandoned) +"dx" = (/obj/effect/floor_decal/spline/fancy/wood,/obj/structure/table/woodentable,/turf/simulated/floor/carpet,/area/outpost/abandoned) +"dy" = (/obj/effect/floor_decal/spline/fancy/wood,/obj/structure/flora/pottedplant{icon_state = "plant-25"},/obj/machinery/light/small,/turf/simulated/floor/carpet{icon_state = "carpet_broken"},/area/outpost/abandoned) +"dz" = (/obj/effect/floor_decal/spline/fancy/wood,/obj/structure/table/woodentable,/obj/random/loot,/turf/simulated/floor/carpet{icon_state = "carpet_broken"},/area/outpost/abandoned) +"dA" = (/obj/effect/floor_decal/spline/fancy/wood{icon_state = "spline_fancy"; dir = 6},/obj/structure/table/woodentable,/turf/simulated/floor/carpet,/area/outpost/abandoned) +"dB" = (/turf/simulated/floor/asteroid,/turf/simulated/shuttle/wall{icon_state = "diagonalWall3"; dir = 4},/area/outpost/abandoned) +"dC" = (/obj/machinery/vending/coffee{icon_state = "coffee-broken"; prices = list()},/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"dD" = (/turf/simulated/floor/tiled/airless{icon_state = "steel_burned0"},/area/outpost/abandoned) +"dE" = (/obj/effect/decal/remains,/obj/structure/table,/obj/item/weapon/material/shard{icon_state = "shardlarge"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned0"},/area/outpost/abandoned) +"dF" = (/obj/structure/table,/obj/item/weapon/material/shard{icon_state = "shardsmall"},/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 5},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned1"},/area/outpost/abandoned) +"dG" = (/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 5},/turf/simulated/floor/tiled/airless{icon_state = "steel_burned0"},/area/outpost/abandoned) +"dH" = (/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"dI" = (/obj/effect/decal/cleanable/cobweb,/obj/machinery/alarm{dir = 4; icon_state = "alarmx"; pixel_x = -23; pixel_y = 0},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"dJ" = (/obj/effect/decal/cleanable/liquid_fuel,/obj/structure/table/steel,/obj/random/bomb_supply,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"dK" = (/obj/effect/decal/cleanable/liquid_fuel,/obj/structure/bed/chair,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"dL" = (/obj/effect/decal/cleanable/liquid_fuel,/obj/structure/bed/chair,/obj/machinery/light/small/emergency{icon_state = "bulb1"; dir = 1},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"dM" = (/obj/structure/bed/chair,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"dN" = (/obj/machinery/vending/snack{icon_state = "snack-broken"; stat = 1},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"dO" = (/obj/structure/ore_box,/turf/simulated/floor/diona,/area/outpost/abandoned) +"dP" = (/obj/structure/closet/crate/large,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"dQ" = (/obj/structure/sign/directions/science{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/red,/turf/simulated/wall/titanium,/area/outpost/abandoned) +"dR" = (/obj/structure/table/woodentable{icon_state = "solid_flip0"},/turf/simulated/floor/carpet/blue,/area/outpost/abandoned) +"dS" = (/obj/item/weapon/material/shard{icon_state = "splinterslarge"},/turf/simulated/floor/carpet/blue,/area/outpost/abandoned) +"dT" = (/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"dU" = (/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 9},/obj/machinery/light/small{dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned1"},/area/outpost/abandoned) +"dV" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating{icon_state = "dmg1"},/area/outpost/abandoned) +"dW" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless{icon_state = "steel_broken1"},/area/outpost/abandoned) +"dX" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned1"},/area/outpost/abandoned) +"dY" = (/obj/structure/extinguisher_cabinet{icon_state = "extinguisher_empty"; pixel_x = 30},/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned1"},/area/outpost/abandoned) +"dZ" = (/obj/effect/decal/cleanable/liquid_fuel,/obj/structure/sign/directions/medical{dir = 8},/turf/simulated/wall/titanium,/area/outpost/abandoned) +"ea" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/liquid_fuel,/obj/effect/decal/cleanable/liquid_fuel,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"eb" = (/obj/effect/decal/cleanable/dirt,/obj/item/weapon/mop,/turf/simulated/floor/plating{icon_state = "dmg2"},/area/outpost/abandoned) +"ec" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/liquid_fuel,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"ed" = (/obj/effect/decal/cleanable/liquid_fuel,/obj/item/weapon/secbot_assembly,/obj/effect/decal/cleanable/blood/oil,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"ee" = (/obj/machinery/atmospherics/pipe/simple/hidden/red,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"ef" = (/obj/machinery/light/small/emergency{icon_state = "bulb1"; dir = 1},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"eg" = (/obj/effect/decal/cleanable/cobweb2,/obj/item/ammo_casing/c9mm,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"eh" = (/obj/structure/sink/puddle,/turf/simulated/floor/asteroid,/area/mine/explored) +"ei" = (/obj/random/trash,/turf/simulated/floor/asteroid,/area/mine/explored) +"ej" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/asteroid,/area/mine/explored) +"ek" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/asteroid,/area/mine/explored) +"el" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 10},/obj/structure/window/reinforced{icon_state = "rwindow"; dir = 8},/obj/structure/firedoor_assembly{anchored = 1},/turf/simulated/floor/plating,/area/outpost/abandoned) +"em" = (/obj/structure/grille/broken,/obj/structure/window/reinforced{dir = 4},/obj/item/weapon/material/shard{icon_state = "shrapnelmedium"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/outpost/abandoned) +"en" = (/obj/machinery/door/airlock/centcom,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"eo" = (/obj/effect/wingrille_spawn/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/outpost/abandoned) +"ep" = (/obj/machinery/newscaster,/turf/simulated/wall/titanium,/area/outpost/abandoned) +"eq" = (/obj/effect/decal/cleanable/blood,/obj/machinery/light/small{dir = 4},/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"er" = (/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 9},/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 9},/obj/effect/decal/cleanable/dirt,/obj/item/mecha_parts/part/durand_left_arm,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned1"},/area/outpost/abandoned) +"es" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned0"},/area/outpost/abandoned) +"et" = (/obj/effect/decal/cleanable/liquid_fuel,/obj/structure/table,/obj/structure/window/reinforced{icon_state = "rwindow"; dir = 1},/obj/item/weapon/material/shard,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned1"},/area/outpost/abandoned) +"eu" = (/obj/effect/decal/cleanable/liquid_fuel,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/mob/living/bot/medbot,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"ev" = (/obj/effect/decal/cleanable/liquid_fuel,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned0"},/area/outpost/abandoned) +"ew" = (/turf/simulated/floor/tiled/airless{icon_state = "steel_burned1"},/area/outpost/abandoned) +"ex" = (/obj/machinery/door/airlock/medical,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"ey" = (/obj/effect/decal/cleanable/liquid_fuel,/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 9},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"ez" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating{icon_state = "dmg1"},/area/outpost/abandoned) +"eA" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/gibspawner/human,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"eB" = (/obj/machinery/atmospherics/pipe/simple/hidden/red,/obj/item/ammo_casing/c9mm,/turf/simulated/floor/plating{icon_state = "dmg1"},/area/outpost/abandoned) +"eC" = (/obj/item/ammo_casing/c9mm,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"eD" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"eE" = (/obj/structure/window/reinforced/full,/obj/structure/grille,/obj/machinery/door/blast/regular{id = "mars_blast"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/outpost/abandoned) +"eF" = (/obj/effect/decal/cleanable/blood,/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/industrial/warning/dust{icon_state = "warning_dust"; dir = 4},/turf/simulated/floor/asteroid,/area/mine/explored) +"eG" = (/obj/machinery/door/airlock/external,/turf/simulated/floor/plating,/area/outpost/abandoned) +"eH" = (/obj/effect/floor_decal/industrial/warning/cee{icon_state = "warningcee"; dir = 1},/turf/simulated/floor/plating,/area/outpost/abandoned) +"eI" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/door/airlock/external,/turf/simulated/floor/plating,/area/outpost/abandoned) +"eJ" = (/obj/item/weapon/material/shard{icon_state = "shardsmall"},/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"eK" = (/obj/item/weapon/material/shard{icon_state = "piecesmall"},/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"eL" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"eM" = (/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 9},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned0"},/area/outpost/abandoned) +"eN" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless{icon_state = "steel_broken4"},/area/outpost/abandoned) +"eO" = (/obj/structure/table/glass,/obj/structure/window/reinforced{icon_state = "rwindow"; dir = 4},/obj/structure/window/reinforced,/obj/random/loot,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned0"},/area/outpost/abandoned) +"eP" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating{icon_state = "dmg4"},/area/outpost/abandoned) +"eQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/green{icon_state = "intact"; dir = 4},/turf/simulated/floor/tiled/airless{icon_state = "steel_burned0"},/area/outpost/abandoned) +"eR" = (/obj/structure/door_assembly/door_assembly_med,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/green{icon_state = "intact"; dir = 4},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"eS" = (/obj/effect/decal/cleanable/blood,/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/green{icon_state = "intact"; dir = 4},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"eT" = (/obj/machinery/atmospherics/pipe/simple/hidden/green{icon_state = "intact"; dir = 4},/obj/random/trash,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"eU" = (/obj/machinery/atmospherics/pipe/simple/hidden/green{icon_state = "intact"; dir = 4},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"eV" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/green{icon_state = "intact"; dir = 4},/turf/simulated/floor/plating{icon_state = "dmg1"},/area/outpost/abandoned) +"eW" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/liquid_fuel,/obj/machinery/atmospherics/pipe/simple/hidden/green{icon_state = "intact"; dir = 4},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"eX" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/generic,/obj/machinery/atmospherics/pipe/simple/hidden/green{icon_state = "intact"; dir = 4},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"eY" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/wrench,/obj/machinery/atmospherics/pipe/simple/hidden/green{icon_state = "intact"; dir = 4},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"eZ" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/green{icon_state = "intact"; dir = 4},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"fa" = (/obj/effect/decal/cleanable/ash,/obj/machinery/atmospherics/pipe/simple/hidden/green{icon_state = "intact"; dir = 4},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"fb" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/green{icon_state = "intact"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/red,/turf/simulated/floor/plating{icon_state = "dmg1"},/area/outpost/abandoned) +"fc" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood,/obj/item/ammo_casing/c9mm,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"fd" = (/obj/effect/decal/cleanable/blood,/obj/item/ammo_casing/c9mm,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"fe" = (/turf/simulated/floor/tiled/airless,/area/mine/explored) +"ff" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/industrial/warning/dust{icon_state = "warning_dust"; dir = 4},/turf/simulated/floor/asteroid,/area/mine/explored) +"fg" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/industrial/warning/cee,/turf/simulated/floor/plating,/area/outpost/abandoned) +"fh" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"fi" = (/obj/item/weapon/pen,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"fj" = (/obj/effect/decal/cleanable/blood/gibs/limb,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"fk" = (/obj/machinery/alarm{dir = 8; icon_state = "alarmx"; pixel_x = 24},/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"fl" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled/airless{icon_state = "steel_burned1"},/area/outpost/abandoned) +"fm" = (/turf/simulated/floor/plating{icon_state = "dmg3"},/area/outpost/abandoned) +"fn" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless{icon_state = "steel_broken4"},/area/outpost/abandoned) +"fo" = (/obj/random/medical,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned0"},/area/outpost/abandoned) +"fp" = (/turf/simulated/floor/tiled/airless{icon_state = "steel_broken0"},/area/outpost/abandoned) +"fq" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/tiled/airless{icon_state = "steel_burned0"},/area/outpost/abandoned) +"fr" = (/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/structure/window/basic{icon_state = "window"; dir = 4},/obj/structure/flora/ausbushes/brflowers,/turf/simulated/floor/grass,/area/outpost/abandoned) +"fs" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/vomit,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"ft" = (/obj/effect/decal/cleanable/dirt,/obj/random/medical,/turf/simulated/floor/plating{icon_state = "dmg4"},/area/outpost/abandoned) +"fu" = (/obj/effect/decal/cleanable/dirt,/obj/structure/mopbucket,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"fv" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/remains,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"fw" = (/obj/effect/decal/cleanable/dirt,/obj/random/trash,/turf/simulated/floor/plating{icon_state = "dmg1"},/area/outpost/abandoned) +"fx" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/ammo_casing/c9mm,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"fy" = (/obj/effect/floor_decal/asteroid,/turf/simulated/floor/asteroid,/area/mine/explored) +"fz" = (/obj/effect/floor_decal/asteroid,/turf/simulated/floor/plating{icon_state = "dmg2"},/area/mine/explored) +"fA" = (/obj/structure/table/standard,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/random/loot,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"fB" = (/obj/structure/table/standard,/obj/item/weapon/paper_bin,/obj/machinery/door/window/northleft,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"fC" = (/obj/structure/table/standard,/obj/structure/window/reinforced{dir = 1},/obj/item/weapon/gun/energy/taser,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"fD" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/table,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"fE" = (/obj/effect/floor_decal/corner/paleblue/three_quarters,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned0"},/area/outpost/abandoned) +"fF" = (/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 10},/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned0"},/area/outpost/abandoned) +"fG" = (/obj/effect/decal/mecha_wreckage/ripley/firefighter,/obj/effect/floor_decal/corner/paleblue{icon_state = "corner_white"; dir = 10},/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned0"},/area/outpost/abandoned) +"fH" = (/obj/random/firstaid,/turf/simulated/floor/tiled/airless{icon_state = "steel_burned0"},/area/outpost/abandoned) +"fI" = (/turf/simulated/floor/grass,/area/outpost/abandoned) +"fJ" = (/obj/effect/decal/cleanable/dirt,/obj/structure/window/basic{icon_state = "window"; dir = 4},/obj/structure/window/basic{icon_state = "window"; dir = 1},/obj/structure/flora/ausbushes/stalkybush,/turf/simulated/floor/grass,/area/outpost/abandoned) +"fK" = (/obj/effect/decal/cleanable/blood/gibs/down,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"fL" = (/obj/item/weapon/newspaper,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"fM" = (/obj/machinery/firealarm{dir = 1; icon_state = "firex"; pixel_x = 0; pixel_y = -24},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"fN" = (/obj/machinery/requests_console{icon_state = "req_comp_rewired"; pixel_y = -32; stat = 1},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"fO" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{icon_state = "0-2"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/obj/machinery/power/apc/high/inactive{dir = 2; name = "south bump"; pixel_y = -24},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"fP" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/light/small/emergency,/obj/structure/cable{icon_state = "1-8"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"fQ" = (/obj/effect/decal/cleanable/generic,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"fR" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/mine/explored) +"fS" = (/obj/effect/decal/cleanable/blood,/obj/machinery/light/small,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"fT" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/firealarm{dir = 1; icon_state = "firex"; pixel_x = 0; pixel_y = -24},/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"fU" = (/obj/structure/table/standard,/obj/structure/window/reinforced{dir = 8},/obj/item/weapon/reagent_containers/food/drinks/flask/vacuumflask,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"fV" = (/obj/structure/bed/chair/office/light{dir = 8},/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"fW" = (/obj/machinery/door/airlock/maintenance_hatch,/turf/simulated/floor/plating,/area/outpost/abandoned) +"fX" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/wall/titanium,/area/outpost/abandoned) +"fY" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/wall/titanium,/area/outpost/abandoned) +"fZ" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/wall/titanium,/area/outpost/abandoned) +"ga" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"gb" = (/turf/simulated/floor/plating,/area/mine/explored) +"gc" = (/obj/item/solar_assembly,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/asteroid,/area/mine/explored) +"gd" = (/obj/structure/windoor_assembly{anchored = 1; dir = 8; icon_state = "l_windoor_assembly01"},/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"ge" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"gf" = (/obj/structure/cable,/obj/machinery/power/smes/batteryrack,/turf/simulated/floor/plating,/area/outpost/abandoned) +"gg" = (/obj/machinery/computer/power_monitor,/obj/effect/decal/cleanable/cobweb2,/obj/structure/cable,/turf/simulated/floor/plating,/area/outpost/abandoned) +"gh" = (/obj/structure/window/reinforced/full,/obj/structure/grille,/obj/machinery/door/firedoor,/obj/structure/barricade,/turf/simulated/floor/plating,/area/outpost/abandoned) +"gi" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless{icon_state = "steel_broken0"},/area/mine/explored) +"gj" = (/obj/machinery/door/airlock/maintenance_hatch,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/outpost/abandoned) +"gk" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable/orange{icon_state = "0-1"; dir = 1},/turf/simulated/floor/plating,/area/outpost/abandoned) +"gl" = (/obj/structure/girder,/turf/simulated/floor/plating,/area/outpost/abandoned) +"gm" = (/turf/simulated/floor/plating{icon_state = "dmg2"},/area/outpost/abandoned) +"gn" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"go" = (/obj/machinery/door/airlock/external,/obj/machinery/door/blast/regular{id = "mars_blast"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/outpost/abandoned) +"gp" = (/obj/effect/floor_decal/industrial/warning/dust{icon_state = "warning_dust"; dir = 9},/obj/random/loot,/turf/simulated/floor/plating,/area/outpost/abandoned) +"gq" = (/obj/effect/floor_decal/industrial/warning/dust{icon_state = "warning_dust"; dir = 5},/obj/machinery/light/small/emergency{icon_state = "bulb1"; dir = 1},/turf/simulated/floor/plating,/area/outpost/abandoned) +"gr" = (/obj/machinery/door/airlock/external,/obj/machinery/door/blast/regular/open,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/outpost/abandoned) +"gs" = (/obj/effect/floor_decal/industrial/warning/dust{icon_state = "warning_dust"; dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/asteroid,/area/mine/explored) +"gt" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/asteroid,/area/mine/explored) +"gu" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/outpost/abandoned) +"gv" = (/obj/random/closet,/obj/random/loot,/turf/simulated/floor/plating,/area/outpost/abandoned) +"gw" = (/obj/structure/cable/orange{icon_state = "1-2"; dir = 1},/obj/structure/cable/orange{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/random/trash,/turf/simulated/floor/plating,/area/outpost/abandoned) +"gx" = (/obj/structure/cable/orange{icon_state = "1-4"; dir = 4},/turf/simulated/floor/plating,/area/outpost/abandoned) +"gy" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/light/small/emergency{icon_state = "bulb1"; dir = 8},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"gz" = (/obj/machinery/door/airlock/external{density = 0; icon_state = "door_open"; opacity = 0},/obj/machinery/door/blast/regular/open,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/outpost/abandoned) +"gA" = (/obj/effect/floor_decal/industrial/warning/dust{icon_state = "warning_dust"; dir = 10},/turf/simulated/floor/plating,/area/outpost/abandoned) +"gB" = (/obj/effect/floor_decal/industrial/warning/dust{icon_state = "warning_dust"; dir = 6},/turf/simulated/floor/plating,/area/outpost/abandoned) +"gC" = (/turf/simulated/floor/tiled/airless{icon_state = "steel_broken4"},/area/mine/explored) +"gD" = (/obj/structure/door_assembly/door_assembly_mhatch,/obj/structure/cable/orange{icon_state = "1-2"; dir = 1},/turf/simulated/floor/plating,/area/outpost/abandoned) +"gE" = (/obj/effect/decal/cleanable/blood/tracks/footprints,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"gF" = (/obj/structure/sign/warning/vacuum{pixel_x = 32},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"gG" = (/obj/structure/window/reinforced/full,/obj/structure/grille,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/outpost/abandoned) +"gH" = (/obj/structure/cable/orange{icon_state = "1-4"},/turf/simulated/floor/plating,/area/outpost/abandoned) +"gI" = (/obj/structure/cable/orange{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/outpost/abandoned) +"gJ" = (/obj/machinery/door/airlock/maintenance_hatch,/obj/structure/cable/orange{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/outpost/abandoned) +"gK" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/structure/cable/orange{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"gL" = (/obj/effect/decal/cleanable/blood/tracks/footprints,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"gM" = (/obj/item/solar_assembly,/turf/simulated/floor/asteroid,/area/mine/explored) +"gN" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/door/firedoor,/obj/structure/cable/orange{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"gO" = (/obj/effect/decal/cleanable/blood/tracks/footprints,/obj/effect/decal/cleanable/dirt,/obj/structure/firedoor_assembly{anchored = 1},/turf/simulated/floor/plating{icon_state = "dmg2"},/area/outpost/abandoned) +"gP" = (/obj/effect/decal/cleanable/blood/gibs/limb,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"gQ" = (/obj/structure/cable/orange{icon_state = "0-1"; dir = 1},/obj/machinery/power/tracker,/turf/simulated/floor/asteroid,/area/outpost/abandoned) +"gR" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/orange{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"gS" = (/obj/machinery/firealarm{dir = 4; icon_state = "firex"; layer = 3.3; pixel_x = 26},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"gT" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/orange{icon_state = "0-1"; dir = 8},/turf/simulated/floor/plating,/area/outpost/abandoned) +"gU" = (/obj/structure/cable/orange{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/orange{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating,/area/outpost/abandoned) +"gV" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/orange{icon_state = "0-1"; dir = 4},/turf/simulated/floor/plating,/area/outpost/abandoned) +"gW" = (/obj/structure/cable/orange{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/asteroid,/area/outpost/abandoned) +"gX" = (/obj/structure/cable/orange{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/orange{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/orange{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/outpost/abandoned) +"gY" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/orange{icon_state = "0-1"; dir = 4},/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/outpost/abandoned) +"gZ" = (/obj/random/junk,/turf/simulated/floor/plating,/area/outpost/abandoned) +"ha" = (/obj/machinery/newscaster{icon_state = "newscaster_off"; pixel_x = -30; stat = 1},/obj/machinery/newscaster{icon_state = "crack3"; pixel_x = -30; stat = 1},/obj/structure/cable/orange{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"hb" = (/obj/structure/bed/chair,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"hc" = (/obj/structure/table/steel,/obj/item/weapon/material/ashtray/glass,/obj/effect/decal/cleanable/cobweb2,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 5},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"hd" = (/obj/structure/window/reinforced/full,/obj/structure/grille,/obj/machinery/door/blast/regular/open,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/outpost/abandoned) +"he" = (/obj/effect/floor_decal/solarpanel,/obj/machinery/power/solar,/obj/structure/cable/orange{icon_state = "0-1"; dir = 8},/turf/simulated/floor/plating,/area/outpost/abandoned) +"hf" = (/obj/effect/floor_decal/solarpanel,/obj/machinery/power/solar,/obj/structure/cable/orange{icon_state = "0-1"; dir = 4},/turf/simulated/floor/plating,/area/outpost/abandoned) +"hg" = (/obj/structure/closet/crate/trashcart,/obj/random/loot,/turf/simulated/floor/plating,/area/outpost/abandoned) +"hh" = (/obj/machinery/washing_machine,/obj/structure/cable/orange{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"hj" = (/obj/effect/decal/cleanable/blood/gibs/body,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"hk" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"hl" = (/obj/random/trash,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"hm" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"hn" = (/obj/effect/floor_decal/solarpanel,/obj/structure/cable/orange{icon_state = "0-1"; dir = 8},/obj/machinery/power/solar,/turf/simulated/floor/plating,/area/outpost/abandoned) +"ho" = (/obj/structure/table/rack,/obj/random/toolbox,/obj/effect/decal/cleanable/cobweb,/turf/simulated/floor/plating,/area/outpost/abandoned) +"hp" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/liquid_fuel,/turf/simulated/floor/plating,/area/outpost/abandoned) +"hq" = (/obj/structure/table/reinforced,/obj/random/contraband,/turf/simulated/floor/plating,/area/outpost/abandoned) +"hr" = (/obj/random/junk,/obj/structure/cable/orange{icon_state = "1-4"},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"hs" = (/obj/structure/cable/orange{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/random/loot,/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"ht" = (/obj/structure/cable/orange{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"hu" = (/obj/machinery/light/small/emergency,/obj/structure/cable/orange{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"hv" = (/obj/item/weapon/gun/energy/plasmacutter,/obj/structure/cable/orange{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"hw" = (/obj/machinery/power/solar_control/autostart,/obj/structure/cable/orange{icon_state = "0-4"},/obj/structure/cable/orange{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/outpost/abandoned) +"hx" = (/obj/structure/cable/orange{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/wall/titanium,/area/outpost/abandoned) +"hy" = (/obj/structure/cable/orange{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/unsimulated/mask,/area/outpost/abandoned) +"hz" = (/obj/structure/cable/orange{icon_state = "1-4"; dir = 4},/obj/structure/cable/orange{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/unsimulated/mask,/area/outpost/abandoned) +"hA" = (/obj/structure/cable/orange{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/orange{icon_state = "1-4"; dir = 4},/turf/unsimulated/mask,/area/outpost/abandoned) +"hB" = (/obj/structure/cable/orange{icon_state = "1-4"; dir = 4},/turf/unsimulated/mask,/area/outpost/abandoned) +"hC" = (/obj/structure/table/rack,/obj/random/tool,/turf/simulated/floor/plating,/area/outpost/abandoned) +"hD" = (/obj/random/junk,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/liquid_fuel,/turf/simulated/floor/plating,/area/outpost/abandoned) +"hE" = (/obj/structure/table/reinforced,/obj/random/material,/obj/effect/decal/cleanable/liquid_fuel,/turf/simulated/floor/plating,/area/outpost/abandoned) +"hF" = (/obj/structure/table/rack,/obj/random/powercell,/turf/simulated/floor/plating,/area/outpost/abandoned) +"hG" = (/obj/effect/decal/cleanable/liquid_fuel,/obj/structure/closet/crate/radiation,/obj/random/voidsuit,/obj/random/voidhelmet,/turf/simulated/floor/plating,/area/outpost/abandoned) +"hH" = (/obj/structure/reagent_dispensers/fueltank,/obj/effect/decal/cleanable/liquid_fuel,/turf/simulated/floor/plating,/area/outpost/abandoned) +"hL" = (/obj/effect/decal/cleanable/dirt,/obj/effect/overmap/sector/away,/turf/simulated/floor/tiled/white,/area/outpost/abandoned) +"ib" = (/obj/effect/shuttle_landmark/away/nav7,/turf/simulated/floor/asteroid,/area/mine/explored) +"jb" = (/obj/effect/shuttle_landmark/away/nav1,/turf/simulated/floor/asteroid,/area/mine/explored) +"kb" = (/obj/effect/shuttle_landmark/away/nav2,/turf/simulated/floor/asteroid,/area/mine/explored) +"lb" = (/obj/effect/shuttle_landmark/away/nav3,/turf/simulated/floor/asteroid,/area/mine/explored) +"mb" = (/obj/effect/shuttle_landmark/away/nav6,/turf/simulated/floor/asteroid,/area/mine/explored) +"nb" = (/obj/effect/shuttle_landmark/away/nav5,/turf/simulated/floor/asteroid,/area/mine/explored) +"ob" = (/obj/effect/shuttle_landmark/away/nav4,/turf/simulated/floor/asteroid,/area/mine/explored) +"pb" = (/obj/effect/gibspawner/human,/turf/simulated/floor/tiled/freezer,/area/outpost/abandoned) +"qb" = (/obj/machinery/atmospherics/pipe/simple/hidden/red{dir = 4; icon_state = "intact"},/obj/effect/floor_decal/corner/red{icon_state = "corner_white"; dir = 9},/obj/effect/decal/cleanable/dirt,/obj/item/ammo_casing/a50,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"rb" = (/obj/machinery/atmospherics/pipe/simple/hidden/red{dir = 4; icon_state = "intact"},/obj/effect/decal/cleanable/blood,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/ammo_casing/a50,/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"sb" = (/obj/structure/table/steel_reinforced,/obj/machinery/atmospherics/pipe/simple/hidden/red{dir = 4; icon_state = "intact"},/obj/effect/floor_decal/corner/red{icon_state = "corner_white"; dir = 6},/obj/machinery/button/remote/blast_door{id = "mars_blast"},/turf/simulated/floor/tiled/dark,/area/outpost/abandoned) +"tb" = (/obj/effect/wingrille_spawn/reinforced,/obj/machinery/atmospherics/pipe/simple/hidden/red{dir = 4; icon_state = "intact"},/turf/simulated/floor/plating,/area/outpost/abandoned) +"ub" = (/obj/machinery/atmospherics/pipe/simple/hidden/red{dir = 4; icon_state = "intact"},/turf/simulated/floor/diona,/area/outpost/abandoned) +"vb" = (/obj/machinery/atmospherics/pipe/simple/hidden/red{dir = 4; icon_state = "intact"},/obj/effect/decal/cleanable/vomit,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/diona,/area/outpost/abandoned) +"wb" = (/obj/structure/table/woodentable,/obj/item/modular_computer/console/preset/command,/turf/simulated/floor/carpet/blue,/area/outpost/abandoned) +"xb" = (/obj/effect/landmark/random_gen/asteroid{generation_height = 200; generation_width = 200},/turf/unsimulated/mask,/area/mine/unexplored) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababkbabababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaabababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaaaaaaaaaaaaaaabababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaaaaaaaaaaaaababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaaababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababobababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababmbabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafafafafafafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafagahaiajakajalamanafaaaaaaaaaaaaafafafafafafafafafafafaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababaaaaaaaaaaaaafafafafafafafafafafaoaoaoaoaoaoaoaoaoafaaaaaaaaaaaaafapaqarasatauavavavafaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababaaaaaaaaaaaaaaafawaxayazaAaBaxaCafaDaoajaoaEaoaFaoaGafafafafafafafafapaHaHaHaHaIaIavavafaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaJaKazazaAaAaLaMafaoaoafafaNafafaOaPafaQaIaRaIaQaIafaSaTaHaHaUaHaIaVavafaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaWazazaXaYaAaAaZafbabbafaoaobcafpbbeafaIaIaIaIaIaIafapaIaIaIaIaHaHaHaHafafaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafbfazbgazazazazaxafbhbiafaoaoaoafbjbjafaQaIaIaIbkaIafaHaaaaaIaHaIaIblaIaIafaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafafafafafbmafbmafafafafafafafbnafafafafafafboboboafbpafafaaaaaaafbqafafafafafaaaaaaaaaaaaababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafbrbsbsbtbubvbwbxaAbybzbAbubBbxbCbDbCbxbCbCbybCbxbxbxbxaAaaaaaabxbEbFaHafaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafbGbHbIbJbKbJhLbJbHbyaAbHbJbJbHbLbybMbNbJbJbHbMbJbJbHbJbHbHaaaabNbJaHaaaaaaababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafbObPbPaAbQbQbQbPbPbPbRbQbQbPbSbTbPbPbPbPbUbUbUbUbVbPbJaAaAbHbHbLbJbHaaaHabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaafafafafafafafaaaaaaaaaaaaafbWafafafbXbXafafafafafafafbYbZbZbZbZbZbYafafafafafafbObPaAbPbUbUbPbPaHaHabaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaafcacbcccdceafaaaaaaaaaaaaafcfcgchcicjckclafaaaaaaaaafcmcncocpcqcrcsafaaaaaaaaafafafafafafafafctafafaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaaaaaaafcucvcwcwcxafaaaaaaaaaaaacyqbrbsbtbubvbcFcGaaaaaaaaafcHcIcJcKcIcLcMafafafaaaaafcNcOcPcQcQafcRcScTafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaaaaaaafcUcVcWcXcYafaaaaaaaaaaaaafcZdadbcidcdddeafaaaaaaabdfdgdhdidjdjdkdldmabafaaaaafcQwbdocQcQafdpdqdrafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaafafafcGdsafcGcGaaaaaaafafafafcGcGafcydtdtduafaaaaababdvdmdwdxdydzdAdmdBabafaaaaafcQcQcQcQcQafdCdrcRafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaafdDdEdFdDdGdHcGaaaaaaafdIdJdKdLdMdNdHdOdPdQafafafabababdvdmdmdmdmdmdBababafafafafdRdScQdRdRafdTdTdTcyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababcGdUcWdVdWdXdYcGafafafdZeacWcWebeccWcWeddHeeefegafabehabababeiabababababejekafafafelemafeneoepdTdTeqcyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababcGerdDeseteuevewexeydHdHdHezdHcWeAcwcwcwcWeBeCeDeEabababababababababababejeFeGeHeIeJeKeLdTdTdTdTdTdTafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacGeMeNcweOdWePeQeReSeTeUeVeWeXeYeWeZfaeUeZfbfcfdeEababababababababejejejfeffeGfgeIdTfhfhdTfidTfjdTfkafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafflfmfnfofpfqafafaffrfscWcWcWftfufvcWfwcWcwfxeDeEababfyabababfzabejababejekcyafcGdTdTfhdTeLfAfBfCfDafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaffEewfFfGdDfHafaaaffIfJfKfLfMdHdHfNfOfPdHfQcwcWeEabababababababejabfRabababaaaaafeLfSeLfTdTfUfVdTdTafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafafcGcGcGafafafaaafafafafafaffWaffXfYfZafdHcWgacGababeiababgbabejejabgcababaaaaafafafafafdTgdgedTdTafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaHafgfgfggafdHcWgacGghghafababejejabgiabababababaaaaaaaaaaafafafcycyafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafafafafaaaaafaHgjgkgkaHglcWgmgngogpgqgrgsejgtejejababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaHguaHgvaaaHaHglgwgxaHcGgydHgngzgAgBgrgsejfeababgCababehababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafgugugugugugugucGgDglglcGcwgEgFafgGgGafababababababababfyabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaHguafcGcGafaHaHgHgIgIgJgKgLdHafabababfyabgMababababababababgMaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaSguafaaaaafafafafafafafgNgOgPcyafababababababababgQabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaHaHafaaaaaaaaaaaaaaaaafgRgEcWgScyeEeEeEababgTgUgVgWgTgXgYabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaHgZafaaaaaaaaaaaaaaaaafhagEcWcWdMhbhchdababhegXhfgWhegXgVabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafhgaHafaaaaaaaaaaaaaaaaafhhgEgLgLeDhjhkeEababhegXhfgWgTgXgVababaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaffWfWafafaaaaaaaaaaaaaaafhhgmhldHdHdHhmafababgTgXhfgWhngXhfabaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafhoguhphqafaaaaaaaaaaaaaaafhrhshthuhvhthwhxhyhyhyhzhyhAhyhBaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafhChDhphEafaaaaaaaaaaaaaaafafafcyafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafhFguhGhHafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafafafafafafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababibabababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababnbabababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababjbabababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababaaaaaaaaababababababaaaaaaaaaaaaaaababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababablbababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +xbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/mining/mining.dm b/maps/away/mining/mining.dm new file mode 100644 index 00000000..93981f13 --- /dev/null +++ b/maps/away/mining/mining.dm @@ -0,0 +1,112 @@ +#include "mining_areas.dm" + +//MINING-1 // CLUSTER +/obj/effect/overmap/sector/cluster + name = "asteroid cluster" + desc = "Large group of asteroids. Mineral content detected." + icon_state = "sector" + generic_waypoints = list( + "nav_cluster_1", + "nav_cluster_2", + "nav_cluster_3", + "nav_cluster_4", + "nav_cluster_5", + "nav_cluster_6", + "nav_cluster_7" + ) + start_x = 4 + start_y = 5 + known = 0 + +/datum/map_template/ruin/away_site/mining_asteroid + name = "Mining - Asteroid" + id = "awaysite_mining_asteroid" + description = "A medium-sized asteroid full of minerals." + suffixes = list("mining/mining-asteroid.dmm") + cost = 1 + accessibility_weight = 10 + +/datum/map_template/ruin/away_site/mining_signal + name = "Mining - Planetoid" + id = "awaysite_mining_signal" + description = "A mineral-rich, formerly-volcanic site on a planetoid." + suffixes = list("mining/mining-signal.dmm") + cost = 1 + base_turf_for_zs = /turf/simulated/floor/asteroid + +/obj/effect/shuttle_landmark/cluster/nav1 + name = "Asteroid Navpoint #1" + landmark_tag = "nav_cluster_1" + +/obj/effect/shuttle_landmark/cluster/nav2 + name = "Asteroid Navpoint #2" + landmark_tag = "nav_cluster_2" + +/obj/effect/shuttle_landmark/cluster/nav3 + name = "Asteroid Navpoint #3" + landmark_tag = "nav_cluster_3" + +/obj/effect/shuttle_landmark/cluster/nav4 + name = "Asteroid Navpoint #4" + landmark_tag = "nav_cluster_4" + +/obj/effect/shuttle_landmark/cluster/nav5 + name = "Asteroid Landing zone #1" + landmark_tag = "nav_cluster_5" + base_area = /area/mine/explored + +/obj/effect/shuttle_landmark/cluster/nav6 + name = "Asteroid Navpoint #5" + landmark_tag = "nav_cluster_6" + +/obj/effect/shuttle_landmark/cluster/nav7 + name = "Asteroid Landing zone #2" + landmark_tag = "nav_cluster_7" + base_area = /area/mine/explored + +//MINING-2 // SIGNAL +/obj/effect/overmap/sector/away + name = "faint signal from an asteroid" + desc = "Faint signal detected, originating from the human-made structures on the site's surface." + icon_state = "sector" + generic_waypoints = list( + "nav_away_1", + "nav_away_2", + "nav_away_3", + "nav_away_4", + "nav_away_5", + "nav_away_6", + "nav_away_7" + ) + known = 0 + +/obj/effect/shuttle_landmark/away + base_area = /area/mine/explored + +/obj/effect/shuttle_landmark/away/nav1 + name = "Away Landing zone #1" + landmark_tag = "nav_away_1" + +/obj/effect/shuttle_landmark/away/nav2 + name = "Away Landing zone #2" + landmark_tag = "nav_away_2" + +/obj/effect/shuttle_landmark/away/nav3 + name = "Away Landing zone #3" + landmark_tag = "nav_away_3" + +/obj/effect/shuttle_landmark/away/nav4 + name = "Away Landing zone #4" + landmark_tag = "nav_away_4" + +/obj/effect/shuttle_landmark/away/nav5 + name = "Away Landing zone #5" + landmark_tag = "nav_away_5" + +/obj/effect/shuttle_landmark/away/nav6 + name = "Away Landing zone #6" + landmark_tag = "nav_away_6" + +/obj/effect/shuttle_landmark/away/nav7 + name = "Away Landing zone #7" + landmark_tag = "nav_away_7" diff --git a/maps/away/mining/mining_areas.dm b/maps/away/mining/mining_areas.dm new file mode 100644 index 00000000..b8af0f24 --- /dev/null +++ b/maps/away/mining/mining_areas.dm @@ -0,0 +1,25 @@ +// GENERIC MINING AREAS +/area/mine + icon_state = "mining" + sound_env = ASTEROID + music = 'sound/music/warfare_ambience.ogg' + +/area/mine/explored + name = "Mine" + icon_state = "explored" + +/area/mine/unexplored + name = "Mine" + icon_state = "unexplored" + +/area/mine/unexplored/no_place + + +// OUTPOSTS +/area/outpost/abandoned + name = "Abandoned Outpost" + icon_state = "dark" + +/area/djstation + name = "\improper Listening Post" + icon_state = "LP" \ No newline at end of file diff --git a/maps/away/mobius_rift/mobius_rift.dm b/maps/away/mobius_rift/mobius_rift.dm new file mode 100644 index 00000000..9a33547d --- /dev/null +++ b/maps/away/mobius_rift/mobius_rift.dm @@ -0,0 +1,109 @@ +#include "mobius_rift_areas.dm" + +/obj/effect/overmap/sector/mobius_rift + name = "unusual asteroid" + desc = "Sensors error: ERROR #E0x003141592: recursive stack overflow for CALCULATE_APPROXIMATE_SIZE()." + icon_state = "object" + known = 0 + +/datum/map_template/ruin/away_site/mobius_rift + name = "Mobius rift" + id = "awaysite_mobius_rift" + description = "Non-euclidian mess." + suffixes = list("mobius_rift/mobius_rift.dmm") + cost = 1 + +/obj/effect/step_trigger/mobius_rift/seamless_portal + var/obj/effect/step_trigger/mobius_rift/seamless_portal/dest + //NORTH or EAST cases + //var/obj/effect/step_trigger/mobius_rift/seamless_portal/dest2//SOUTH or WEST cases + var/directed//NS or WE + var/x_shift = 0 + var/y_shift = 0 + +/obj/effect/step_trigger/mobius_rift/seamless_portal/Initialize(var/mapload, var/towards) + . = ..() + if (towards == NORTH) + y_shift = 1 + if (towards == SOUTH) + y_shift = -1 + if (towards == EAST) + x_shift = 1 + if (towards == WEST) + x_shift = -1 + +/obj/effect/step_trigger/mobius_rift/seamless_portal/proc/set_destination(var/D) + dest = D + +/obj/effect/step_trigger/mobius_rift/seamless_portal/Trigger(var/atom/movable/AM) + if(!istype(AM)) + return + //moving player one tile past portal to avoid portal spamming + var/turf/T = locate(dest.x + x_shift, dest.y + y_shift, dest.z) + AM.forceMove(T) + +//spawns and presets portals to their destinations, must be in left lower chamber center +/obj/effect/mobius_rift/portals_setup + var/grid_number = 4//amount of rooms in a square pattern grid + var/grid_size = 31//lenfth from center of one room to another, or size of a chamber(room length, 12?) + corridor length. Corridor length is (view-range * 2) (16?) + +/obj/effect/mobius_rift/portals_setup/Initialize() + ..() + var/list/rooms = list() + + for (var/y_iter = 1 to grid_number)//spawning chamber abstract objects + for (var/x_iter = 1 to grid_number) + var/turf/T = locate(src.x + (x_iter-1)*grid_size, src.y + (y_iter-1)*grid_size, src.z) + var/CH = new /obj/effect/mobius_rift/chamber(T, grid_size) + rooms["[y_iter]_[x_iter]"] = CH + //creating lists of teleporting consequences for each direction + var/list/north_jumps = shuffle(rooms) + var/list/south_jumps = shuffle(rooms) + var/list/east_jumps = shuffle(rooms) + var/list/west_jumps = shuffle(rooms) + + var/list/routes = list("SOUTH" = south_jumps, "NORTH" = north_jumps, "WEST" = west_jumps, "EAST" = east_jumps)//North exit is linked to south exit of another room etc. + for (var/ch_iter = 1 to rooms.len)//get destinations in SNWE order + var/list/destinations = list()//4 exit portals for linking + var/chamber_tag = rooms[ch_iter] + var/obj/effect/mobius_rift/chamber/chamber = rooms[chamber_tag] + for (var/dir_iter =1 to routes.len) + var/list/route = routes[routes[dir_iter]] + var/ch_pos = route.Find(chamber_tag) + 1 + if (ch_pos > (grid_number * grid_number))//if that's the last one + ch_pos = 1 + var/obj/effect/mobius_rift/chamber/dest_chamber = route[route[ch_pos]]//getting destination chamber for direction + var/P = dest_chamber.get_portal(routes[dir_iter]) + destinations.Add(P) + chamber.set_portals(destinations) + //cleaning up + for (var/ch_iter = 1 to rooms.len) + qdel(rooms[rooms[ch_iter]]) + return INITIALIZE_HINT_QDEL + +/obj/effect/mobius_rift/chamber + var/list/portals = list() + +/obj/effect/mobius_rift/chamber/Initialize(var/mapload, var/grid_size)//NORTH, SOUTH, EAST, WEST + . = ..() + var/turf/T + T = locate(src.x, src.y + round(grid_size/2), src.z) + var/N = new /obj/effect/step_trigger/mobius_rift/seamless_portal(T, NORTH) + portals["NORTH"] = N + T = locate(src.x, src.y - round(grid_size/2), src.z) + var/S = new /obj/effect/step_trigger/mobius_rift/seamless_portal(T, SOUTH) + portals["SOUTH"] = S + T = locate(src.x + round(grid_size/2), src.y, src.z) + var/E = new /obj/effect/step_trigger/mobius_rift/seamless_portal(T, EAST) + portals["EAST"] = E + T = locate(src.x - round(grid_size/2), src.y, src.z) + var/W = new /obj/effect/step_trigger/mobius_rift/seamless_portal(T, WEST) + portals["WEST"] = W + +/obj/effect/mobius_rift/chamber/proc/set_portals(var/list/destinations) + for (var/iter = 1 to portals.len) + var/obj/effect/step_trigger/mobius_rift/seamless_portal/P = portals[portals[iter]] + P.set_destination(destinations[iter]) + +/obj/effect/mobius_rift/chamber/proc/get_portal(var/towards) + return portals[towards] \ No newline at end of file diff --git a/maps/away/mobius_rift/mobius_rift.dmm b/maps/away/mobius_rift/mobius_rift.dmm new file mode 100644 index 00000000..264bae48 --- /dev/null +++ b/maps/away/mobius_rift/mobius_rift.dmm @@ -0,0 +1,221 @@ +"a" = (/turf/space,/area/space) +"b" = (/turf/unsimulated/mineral,/area/mobius_rift) +"c" = (/turf/unsimulated/floor/bluespace,/area/mobius_rift) +"d" = (/turf/unsimulated/beach/sand,/area/mobius_rift) +"e" = (/turf/simulated/floor/grass,/area/mobius_rift) +"f" = (/turf/simulated/mineral/random/high_chance,/area/mobius_rift) +"g" = (/turf/space,/area/mobius_rift) +"h" = (/obj/structure/flora/ausbushes/fullgrass,/turf/simulated/floor/grass,/area/mobius_rift) +"i" = (/obj/structure/flora/ausbushes/fullgrass,/turf/unsimulated/beach/sand,/area/mobius_rift) +"j" = (/obj/structure/flora/ausbushes/genericbush,/turf/simulated/floor/grass,/area/mobius_rift) +"k" = (/turf/simulated/floor/exoplanet/water/shallow,/area/mobius_rift) +"l" = (/obj/structure/flora/ausbushes/fullgrass,/obj/structure/flora/ausbushes/genericbush,/turf/simulated/floor/grass,/area/mobius_rift) +"m" = (/obj/structure/flora/ausbushes/grassybush,/turf/simulated/floor/grass,/area/mobius_rift) +"n" = (/mob/living/simple_animal/hostile/vagrant,/turf/simulated/floor/grass,/area/mobius_rift) +"o" = (/obj/structure/flora/ausbushes/pointybush,/turf/simulated/floor/grass,/area/mobius_rift) +"p" = (/obj/structure/flora/ausbushes/sunnybush,/turf/simulated/floor/grass,/area/mobius_rift) +"q" = (/mob/living/simple_animal/hostile/vagrant,/turf/unsimulated/beach/sand,/area/mobius_rift) +"r" = (/obj/effect/mobius_rift/portals_setup,/obj/effect/overmap/sector/mobius_rift,/obj/effect/shuttle_landmark/automatic,/turf/unsimulated/beach/sand,/area/mobius_rift) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbbbccccccccccccccccccccccccccccbbbccccccccccccccccccccccccccccbbbccccccccccccccccccccccccccccbbbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabcccccccccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbcccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbbdedddddeddfbbccccccccccccccccbbfffddddddddbbccccccccccccccccbbdgdddddffddbbccccccccccccccccbbeeeeddeddfebbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbdeehheeehefffbccccccccccccccccbfffddddddggddbccccccccccccccccbddggdddddffddbccccccccccccccccbddfdeeeedffeebccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbdffhidhhhefffbccccccccccccccccbffffddddddgddbccccccccccccccccbdddgdddddddddbccccccccccccccccbdffffeeeffjeebccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbefeeieekkffeebccccccccccccccccbdffffdddfddddbccccccccccccccccbdddddddgggdddbccccccccccccccccbdfffhheeffffebccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbeffjdekkeeeeebccccccccccccccccbdffffdddfdffdbccccccccccccccccbddggggggggdddbccccccccccccccccbdfffheefffffebccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccbbbbbbbbbbbbbbbbbeefeeeeeeejedbbbbbbbbbbbbbbbbbbdddffddddffddbbbbbbbbbbbbbbbbbbddddggddgddddbbbbbbbbbbbbbbbbbbddeehhfffeeehbbbbbbbbbbbbbbbbbccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccbdddddddddddddddddeehleejediedddddddddddddddddddddddddggdfdddddddddddddddddddddddddgggggddddddddddddddddddddddddjeehheefehhddddddddddddddddbccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccbbbbbbbbbbbbbbbbbdehhhhdedihhdbbbbbbbbbbbbbbbbbbddddddgddddddbbbbbbbbbbbbbbbbbbdddggdggdddddbbbbbbbbbbbbbbbbbbfddddeeeeffeebbbbbbbbbbbbbbbbbccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbfeehhhdddhhhdbccccccccccccccccbdfffddddddgddbccccccccccccccccbdddgggggdggdfbccccccccccccccccbfffffeeeekfeebccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbkkkeeeekkkeeebccccccccccccccccbdfffffdddgggdbccccccccccccccccbkkddddddddgddbccccccccccccccccbkkkkkkkkkkehhbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbfekkkkkkkkeeebccccccccccccccccbdffffffddggddbccccccccccccccccbkkkdddffddggdbccccccccccccccccbkffffdeeeeehebccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbdeeeeeekkkeedbccccccccccccccccbddffffddgggddbccccccccccccccccbkkkkdfffdddgdbccccccccccccccccbkkkfffdeeeehhbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbbddejdeededdbbccccccccccccccccbbdddddddddddbbccccccccccccccccbbkkkffddddddbbccccccccccccccccbbkkfffddeeddbbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabcccccccccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbcccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabcccccccccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbcccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbbdddddedddeebbccccccccccccccccbbddddddeedhebbccccccccccccccccbbeekkkeeeeeebbccccccccccccccccbbeeeeeeeeeeebbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbddeeeeeeeeeeebccccccccccccccccbedddggdddiieebccccccccccccccccbekkkdkkkkeeeebccccccccccccccccbeeeeekkkkkeeebccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbddeeeemeeeehebccccccccccccccccbhdggggggggdddbccccccccccccccccbekkkkkkkkkkkebccccccccccccccccbeeeekkdkkdkeebccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbdehefffffeeedbccccccccccccccccbhigggggggggddbccccccccccccccccbekkkfkkkkkkkebccccccccccccccccbeekkkkkkkkkkebccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbdhhefeffffdedbccccccccccccccccbddgggggggggddbccccccccccccccccbekkffkkkkkkkebccccccccccccccccbeekkkkkkkkkkebccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccbbbbbbbbbbbbbbbbbeehffffffffedbbbbbbbbbbbbbbbbbbdddgggggdddddbbbbbbbbbbbbbbbbbbkkkkfkkkkkkkebbbbbbbbbbbbbbbbbbekdkkkkkkkkeebbbbbbbbbbbbbbbbbccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccbddddddddddddddddedeffndfffeeddddddddddddddddddddgggddiideeedddddddddddddddddddkkkkkkkkkkkkeddddddddddddddddddkkdkkkkkkkkeeddddddddddddddddbccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccbbbbbbbbbbbbbbbbbedeffffffeeedbbbbbbbbbbbbbbbbbbdddddihhheeeebbbbbbbbbbbbbbbbbbekkkkkkkkffkebbbbbbbbbbbbbbbbbbkddkkkkkkkkeebbbbbbbbbbbbbbbbbccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbedeeefffeeejdbccccccccccccccccbeedihhhehhemebccccccccccccccccbekkfkkkkkffkebccccccccccccccccbkddkkkkkkdkeebccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbeeeheefffeeedbccccccccccccccccbhideehhhheeeebccccccccccccccccbkkffkkkkkfkkkbccccccccccccccccbkkkkddkkkkkeebccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbdeohheeeffeedbccccccccccccccccbeiheehemeeeedbccccccccccccccccbefffkkkkkkkkebccccccccccccccccbekkkkkkkkeeeebccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbddeeejeeehhhdbccccccccccccccccbdddhedeeeeeedbccccccccccccccccbekffkkkkkkkkebccccccccccccccccbeeeeekkkeeeeebccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbbddeeeddeeeebbccccccccccccccccbbdeeeeeeeeedbbccccccccccccccccbbeeeeeeeeeeebbccccccccccccccccbbeeeeeeeeeeebbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabcccccccccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbcccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabcccccccccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbcccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbbffkkfkkkkkkbbccccccccccccccccbbdedddeeddddbbccccccccccccccccbbdeeeheeeeeebbccccccccccccccccbbffeddddffffbbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbkkffkffffffkkbccccccccccccccccbddeeeeeeeddddbccccccccccccccccbdddddhejdddddbccccccccccccccccbffeeeeeefffkfbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbfkdkkkkkkkkkkbccccccccccccccccbdeeeekjeeeeeebccccccccccccccccbdgggdihedggddbccccccccccccccccbfffeehhefkkkfbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbkfffkfffffffkbccccccccccccccccbdeeeeeeeeeeeebccccccccccccccccbddgggdeddggddbccccccccccccccccbffffeheekkfffbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbkfffkfkkkfffkbccccccccccccccccbeeekeeekeeejebccccccccccccccccbedgdddeddgggdbccccccccccccccccbehefhhekkefffbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccbbbbbbbbbbbbbbbbbkkkfdkkfkkkfkbbbbbbbbbbbbbbbbbbeeeeeekkeeeedbbbbbbbbbbbbbbbbbbhiddeheedddgdbbbbbbbbbbbbbbbbbbehhehekkehheebbbbbbbbbbbbbbbbbccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccbddddddddddddddddkfkfffkfdfffkddddddddddddddddddejeeeeekeeeedddddddddddddddddddeheeeheejedddddddddddddddddddddekkeekkkkehheddddddddddddddddbccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccbbbbbbbbbbbbbbbbbkfkfkkkfdfkkkbbbbbbbbbbbbbbbbbbeeejkkkeekeedbbbbbbbbbbbbbbbbbbehhjehheeeehhbbbbbbbbbbbbbbbbbbkkkekkeekkeedbbbbbbbbbbbbbbbbbccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbffkfffkfkfkfkbccccccccccccccccbdeeeeekeeeeedbccccccccccccccccbeddddddedddihbccccccccccccccccbkkkkkehhekeefbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbkkdkkkkfkfffkbccccccccccccccccbdeekeejeeeeedbccccccccccccccccbedggggdedggihbccccccccccccccccbfkkkeeheekeffbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbkfffkfkfkkkkfbccccccccccccccccbdeeeeejeeeeedbccccccccccccccccbedgggddedgddebccccccccccccccccbfkkkkehhekkffbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbkfffkfkkfffffbccccccccccccccccbddeeeeeeeeeddbccccccccccccccccbeddggdeedggdebccccccccccccccccbffkkkkkeekkffbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbbkkkkfkkkkkkbbccccccccccccccccbbddeeeeeeeddbbccccccccccccccccbbdddddeeddddbbccccccccccccccccbbffkkeeeefffbbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabcccccccccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbcccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabcccccccccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbcccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbbdddddddddddbbccccccccccccccccbbdeeeddeheddbbccccccccccccccccbbddeeeeeddddbbccccccccccccccccbbdddddddddddbbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbdddddddddddddbccccccccccccccccbdhpeeehhhhhhdbccccccccccccccccbdgddeeeedgggdbccccccccccccccccbdddfddffdddddbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbdddddddddddddbccccccccccccccccbeheeeehehhhedbccccccccccccccccbdggddeddddggdbccccccccccccccccbddfffffdggdddbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbdddddddddddddbccccccccccccccccbhhfefffffeheebccccccccccccccccbdgggdddggddgdbccccccccccccccccbddfffffffgfddbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbdddddddddddddbccccccccccccccccbhhfffdfffeheebccccccccccccccccbddgggdggdddddbccccccccccccccccbddfffffffffddbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccbbbbbbbbbbbbbbbbbdddddddddddddbbbbbbbbbbbbbbbbbbeeffqhhefeeedbbbbbbbbbbbbbbbbbbpddgggggdggdebbbbbbbbbbbbbbbbbbddffdddfdffddbbbbbbbbbbbbbbbbbccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccbddddddddddddddddddddddrddddddddddddddddddddddddeeeffhndfeeedddddddddddddddddddddddgggggggdedddddddddddddddddddddddggddddddddddddddddddddddbccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccbbbbbbbbbbbbbbbbbdddddddddddddbbbbbbbbbbbbbbbbbbeheffqeefepedbbbbbbbbbbbbbbbbbbdgddgggggggdebbbbbbbbbbbbbbbbbbddffffddffdddbbbbbbbbbbbbbbbbbccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbdddddddddddddbccccccccccccccccbhhffdffffeeeebccccccccccccccccbdggdgdgdgggdebccccccccccccccccbddfggdffffdddbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbdddddddddddddbccccccccccccccccbhhdddffffeeedbccccccccccccccccbdggddddggggdebccccccccccccccccbddggggffffdddbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbdddddddddddddbccccccccccccccccbeeehheeedeeddbccccccccccccccccbdgggdedggggdebccccccccccccccccbdggffffffdgddbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbdddddddddddddbccccccccccccccccbdeehhhhheeeedbccccccccccccccccbdddddedddgddebccccccccccccccccbdgdddddddggddbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccbbdddddddddddbbccccccccccccccccbbdddeeeeeeddbbccccccccccccccccbbdeeeeeedddebbccccccccccccccccbbdddddddddddbbccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabcccccccccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbccccccccccccccccccbbbbbbdbbbbbbcccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccbdbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccbbbccccccccccccccccccccccccccccbbbccccccccccccccccccccccccccccbbbccccccccccccccccccccccccccccbbbccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/mobius_rift/mobius_rift_areas.dm b/maps/away/mobius_rift/mobius_rift_areas.dm new file mode 100644 index 00000000..f5208cab --- /dev/null +++ b/maps/away/mobius_rift/mobius_rift_areas.dm @@ -0,0 +1,6 @@ +/area/mobius_rift + name = "Mobius Rift" + icon = 'maps/away/mobius_rift/mobius_rift_sprites.dmi' + icon_state = "mr" + dynamic_lighting = 0 + base_turf = /turf/unsimulated/beach/sand \ No newline at end of file diff --git a/maps/away/mobius_rift/mobius_rift_sprites.dmi b/maps/away/mobius_rift/mobius_rift_sprites.dmi new file mode 100644 index 00000000..71bdbc81 Binary files /dev/null and b/maps/away/mobius_rift/mobius_rift_sprites.dmi differ diff --git a/maps/away/slavers/backup/slavers_base.dmm b/maps/away/slavers/backup/slavers_base.dmm new file mode 100644 index 00000000..fcd966fb --- /dev/null +++ b/maps/away/slavers/backup/slavers_base.dmm @@ -0,0 +1,775 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/obj/effect/shuttle_landmark/nav_slavers_base/nav2,/turf/space,/area/space) +"ac" = (/obj/effect/shuttle_landmark/nav_slavers_base/nav3,/turf/space,/area/space) +"ad" = (/turf/unsimulated/mask,/area/mine/unexplored) +"ae" = (/obj/effect/shuttle_landmark/nav_slavers_base/nav1,/turf/space,/area/space) +"af" = (/turf/simulated/mineral,/area/space) +"ag" = (/turf/simulated/floor/asteroid,/area/space) +"ah" = (/turf/simulated/wall,/area/slavers_base/mort) +"ai" = (/obj/effect/shuttle_landmark/nav_slavers_base/nav4,/turf/space,/area/space) +"aj" = (/obj/structure/ore_box{desc = "A heavy box covered with dried blood."; name = "Big dirty box"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"ak" = (/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"al" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"am" = (/obj/structure/crematorium,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"an" = (/obj/effect/decal/cleanable/ash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"ao" = (/obj/structure/table/standard,/obj/item/weapon/wirecutters,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"ap" = (/obj/structure/table/standard,/obj/effect/landmark/corpse/slavers_base/slave,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aq" = (/obj/structure/table/standard,/obj/item/weapon/paper{info = "If they'll keep having fun with cargo in such manner, we'll run out of freezers to keep what's left from it."; name = "Note"},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"ar" = (/obj/structure/table/standard,/obj/item/weapon/material/kitchen/utensil/knife,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"as" = (/obj/structure/table/rack,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"at" = (/obj/effect/gibspawner/human,/turf/simulated/floor/asteroid,/area/space) +"au" = (/obj/structure/table/rack,/obj/item/weapon/wirecutters,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"av" = (/obj/item/weapon/shovel,/turf/simulated/floor/asteroid,/area/space) +"aw" = (/obj/item/remains/human,/turf/simulated/floor/asteroid,/area/space) +"ax" = (/obj/item/remains/human,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"ay" = (/obj/item/bodybag,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"az" = (/obj/item/weapon/material/kitchen/utensil/knife,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aA" = (/obj/structure/table/rack,/obj/item/weapon/material/hatchet,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aB" = (/obj/structure/closet/crate/freezer,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aC" = (/obj/effect/gibspawner/human,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aD" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aE" = (/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/power/apc{dir = 4; name = "Slaves Mortuary"; pixel_x = 24},/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aF" = (/obj/machinery/light/small,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aG" = (/obj/machinery/gibber,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aH" = (/obj/structure/kitchenspike,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aI" = (/obj/structure/kitchenspike,/obj/machinery/light/small,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aK" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aL" = (/obj/machinery/door/airlock{name = "Mortuary backyard"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aM" = (/turf/simulated/wall,/area/slavers_base/cells) +"aN" = (/obj/machinery/door/airlock{name = "Slaves mortuary"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"aO" = (/obj/structure/toilet{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aP" = (/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aQ" = (/obj/machinery/light/small/red{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aR" = (/obj/structure/slavers_base/mattress,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aS" = (/obj/structure/slavers_base/mattress,/obj/item/weapon/reagent_containers/glass/rag,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aT" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"aU" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"aV" = (/obj/random/trash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aW" = (/obj/item/weapon/reagent_containers/glass/rag,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aX" = (/obj/machinery/shower{dir = 4; icon_state = "shower"; pixel_x = 0; pixel_y = 0},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aY" = (/obj/item/weapon/reagent_containers/glass/rag,/obj/random/trash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aZ" = (/obj/structure/slavers_base/mattress,/obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"ba" = (/obj/item/remains/human,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bb" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bc" = (/obj/machinery/flasher{id = "permentryflash"; name = "Floor mounted flash"; pixel_x = 0},/obj/item/weapon/reagent_containers/glass/rag,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bd" = (/obj/structure/slavers_base/mattress,/obj/item/trash/liquidfood,/obj/effect/landmark/corpse/slavers_base/slave,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"be" = (/obj/machinery/flasher{id = "permentryflash"; name = "Floor mounted flash"; pixel_x = 0},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bf" = (/obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bg" = (/obj/machinery/flasher{id = "permentryflash"; name = "Floor mounted flash"; pixel_x = 0},/obj/random/trash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bh" = (/obj/structure/slavers_base/mattress,/obj/machinery/flasher{id = "permentryflash"; name = "Floor mounted flash"; pixel_x = 0},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bi" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bj" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bk" = (/obj/machinery/door/window/brigdoor/southright,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bl" = (/obj/machinery/door/window/brigdoor/southright,/obj/random/trash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bm" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bn" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/cyan{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bo" = (/obj/machinery/door/airlock{name = "Cell block B"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bp" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bq" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"br" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bs" = (/obj/machinery/flasher{id = "permentryflash"; name = "Floor mounted flash"; pixel_x = 0},/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bt" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bu" = (/obj/structure/slavers_base/mattress,/obj/effect/landmark/corpse/slavers_base/slave,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bv" = (/obj/structure/closet/crate/freezer/rations,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bw" = (/obj/item/weapon/paper{info = "Tonight, when lights are out. Prepare shivs, pieces of glass, whatever you might find."; name = "Note"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bx" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"by" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bz" = (/obj/structure/closet/crate/freezer/rations,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bA" = (/obj/random/trash,/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bB" = (/obj/effect/decal/cleanable/dirt,/obj/item/remains/human,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bC" = (/obj/machinery/light{dir = 4},/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bD" = (/obj/random/shoes,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bE" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bF" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bG" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bH" = (/obj/machinery/door/window/brigdoor/northright,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bI" = (/obj/random/trash,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bJ" = (/obj/item/weapon/storage/bag/trash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bK" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bL" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/cyan{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bM" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bN" = (/obj/machinery/door/airlock{name = "Den B"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bO" = (/obj/machinery/light/small/red,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bP" = (/obj/machinery/light/small/red,/obj/structure/slavers_base/mattress,/obj/effect/landmark/corpse/slavers_base/slave,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bQ" = (/obj/structure/slavers_base/mattress,/obj/random/junk,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bR" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bS" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/cyan{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bT" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/cyan{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/cyan{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bU" = (/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bV" = (/obj/random/trash,/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/cyan{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/cyan{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bW" = (/obj/machinery/flasher{id = "permentryflash"; name = "Floor mounted flash"; pixel_x = 0},/obj/effect/decal/cleanable/dirt,/obj/item/ammo_casing/shotgun/beanbag{pixel_x = -8; pixel_y = -4},/obj/item/ammo_casing/shotgun/beanbag{pixel_y = 5; pixel_z = 7},/obj/item/ammo_casing/shotgun/beanbag,/obj/item/ammo_casing/shotgun/beanbag,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bX" = (/obj/machinery/door/airlock{name = "Dens block"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bY" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/obj/effect/landmark/corpse/slavers_base/slaver4,/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bZ" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood,/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"ca" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/cyan{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cb" = (/obj/machinery/door/airlock{name = "Den A"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cc" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood,/obj/structure/cable,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cd" = (/obj/structure/toilet{dir = 4},/obj/item/weapon/reagent_containers/food/snacks/liquidfood,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"ce" = (/obj/machinery/light/small/red{dir = 1},/obj/structure/slavers_base/mattress,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cf" = (/obj/structure/slavers_base/mattress,/obj/random/snack,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cg" = (/obj/machinery/light/small/red{dir = 1},/obj/random/medical/lite,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"ch" = (/obj/structure/slavers_base/mattress,/obj/item/remains/human,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"ci" = (/obj/random/junk,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cj" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"ck" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cl" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/item/device/flashlight,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cm" = (/turf/simulated/wall,/area/slavers_base/hangar) +"cn" = (/obj/effect/decal/cleanable/dirt,/obj/item/ammo_casing/shotgun/beanbag,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/cyan{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"co" = (/obj/machinery/door/airlock{name = "Cell block A"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cp" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cq" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cr" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cs" = (/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"ct" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"cu" = (/obj/machinery/door/blast/regular{id = "service_hangar"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"cv" = (/obj/effect/landmark/corpse/slavers_base/slave,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cw" = (/obj/effect/decal/cleanable/dirt,/obj/item/ammo_casing/shotgun/beanbag,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cx" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cy" = (/obj/random/medical/lite,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cz" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cA" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 4; name = "Slavers holding area"; pixel_x = 24},/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cB" = (/obj/machinery/door/window/brigdoor/northright,/obj/item/weapon/reagent_containers/glass/rag,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cC" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"cD" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"cE" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 5},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"cF" = (/obj/item/weapon/paper,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cG" = (/obj/item/trash/liquidfood,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cH" = (/obj/effect/floor_decal/industrial/warning{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"cI" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"cJ" = (/obj/item/weapon/paper{info = "Doc who checked us told implants won't explode our heads. Gotta make guys know. Seems I see a silver lining."; name = "Note"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cK" = (/obj/machinery/light/small/red,/obj/item/remains/human,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cL" = (/obj/random/snack,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cM" = (/obj/structure/slavers_base/mattress,/obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle,/obj/random/junk,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cN" = (/obj/machinery/light/small/red,/obj/random/trash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cO" = (/obj/structure/slavers_base/mattress,/obj/item/weapon/reagent_containers/glass/rag,/obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle,/obj/effect/landmark/corpse/slavers_base/slave,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cP" = (/obj/structure/toilet{dir = 4},/obj/item/trash/liquidfood,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cQ" = (/obj/machinery/light/small/red,/obj/structure/slavers_base/mattress,/obj/item/weapon/reagent_containers/glass/rag,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cR" = (/turf/simulated/wall,/area/slavers_base/powatm) +"cS" = (/turf/simulated/wall,/area/slavers_base/secwing) +"cT" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/airlock{name = "Slave hold hallway"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"cU" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/door/airlock{name = "Slave hold hallway"},/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"cV" = (/turf/simulated/wall,/area/slavers_base/med) +"cW" = (/obj/effect/shuttle_landmark/nav_slavers_base/nav7,/turf/space,/area/space) +"cX" = (/obj/machinery/atmospherics/pipe/tank/air,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"cY" = (/obj/machinery/atmospherics/pipe/tank/air,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"cZ" = (/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"da" = (/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"db" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"dc" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"dd" = (/obj/structure/bed,/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"de" = (/obj/structure/closet,/obj/random/snack,/obj/random/projectile,/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"df" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"dg" = (/obj/structure/bed,/obj/random/projectile,/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"dh" = (/obj/structure/closet,/obj/random/smokes,/obj/random/masks,/obj/random/suit,/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"di" = (/obj/structure/table/rack,/obj/item/device/flashlight,/obj/random/medical/lite,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dj" = (/obj/structure/table/rack,/obj/machinery/light{dir = 1},/obj/item/weapon/storage/box/handcuffs,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dk" = (/obj/structure/table/rack,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/baton,/obj/random/tool,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dl" = (/obj/structure/table/rack,/obj/item/device/flash,/obj/random/ammo,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dm" = (/obj/structure/table/rack,/obj/item/weapon/storage/box/stunshells,/obj/item/weapon/gun/projectile/shotgun/pump,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dn" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"do" = (/obj/structure/cable{d2 = 6; icon_state = "0-6"},/obj/machinery/power/smes/buildable,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dp" = (/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dq" = (/obj/structure/cable/cyan{d2 = 4; icon_state = "0-4"},/obj/machinery/power/smes/buildable,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dr" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"ds" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"dt" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"du" = (/obj/machinery/door/airlock{name = "Slave processing"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dv" = (/obj/machinery/flasher{id = "permentryflash"; name = "Floor mounted flash"; pixel_x = 0},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dw" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 1; name = "Medical room"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dx" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dy" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dz" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/shower{pixel_y = 30},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dA" = (/obj/machinery/door/airlock{name = "Storage"},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dB" = (/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"dC" = (/obj/structure/reagent_dispensers/watertank,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"dD" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"dE" = (/obj/structure/closet/crate/freezer/rations,/obj/item/weapon/reagent_containers/food/snacks/liquidfood,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"dF" = (/obj/structure/closet/crate/freezer/rations,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"dG" = (/obj/machinery/atmospherics/pipe/manifold/visible/yellow{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"dH" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"dI" = (/obj/machinery/atmospherics/pipe/manifold/visible/yellow,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"dJ" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{dir = 10},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"dK" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"dL" = (/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"dM" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dN" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dO" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/generic,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dP" = (/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dQ" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable{icon_state = "2-9"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dR" = (/obj/structure/table/steel,/obj/item/weapon/storage/box/stunshells,/obj/item/weapon/melee/baton,/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dS" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"dT" = (/obj/effect/decal/cleanable/dirt,/obj/item/ammo_casing/shotgun/beanbag,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"dU" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"dV" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dW" = (/obj/effect/decal/cleanable/dirt,/obj/random/junk,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dX" = (/obj/effect/decal/cleanable/dirt,/obj/random/medical/lite,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dY" = (/obj/structure/bed,/obj/item/remains/human,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dZ" = (/obj/item/weapon/reagent_containers/food/snacks/liquidfood,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"ea" = (/obj/structure/closet/crate/trashcart,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"eb" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"ec" = (/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"ed" = (/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"ee" = (/obj/machinery/atmospherics/binary/pump{dir = 1; name = "waste pump"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"ef" = (/obj/machinery/atmospherics/binary/pump,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eg" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eh" = (/obj/random/junk,/obj/effect/decal/cleanable/generic,/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"ei" = (/obj/random/junk,/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"ej" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"ek" = (/mob/living/simple_animal/hostile/abolition_extremist,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"el" = (/obj/effect/landmark/corpse/slavers_base/slaver6,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"em" = (/obj/random/junk,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"en" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"eo" = (/obj/structure/bed/chair/office/dark{dir = 4},/obj/effect/decal/cleanable/blood,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"ep" = (/obj/structure/table/steel,/obj/item/device/flash,/obj/item/device/radio,/obj/item/weapon/paper{info = "If this fuck from A-3 keeps thinking he's better then piece of meat, throw him to hangar and show how little pressure turns diamonds into shit."; name = "Note"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"eq" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"er" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"es" = (/obj/item/ammo_casing/shotgun/beanbag,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"et" = (/obj/structure/window/basic{dir = 1},/obj/item/clothing/gloves/latex,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"eu" = (/obj/structure/window/basic{dir = 4},/obj/effect/decal/cleanable/dirt,/obj/effect/landmark/corpse/slavers_base/slaver5,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"ev" = (/obj/structure/window/basic{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"ew" = (/obj/structure/window/basic{dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"ex" = (/obj/effect/decal/cleanable/dirt,/obj/item/ammo_casing/shotgun/beanbag,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"ey" = (/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"ez" = (/obj/structure/bed,/obj/item/weapon/handcuffs,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"eA" = (/obj/item/weapon/beartrap,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"eB" = (/obj/item/weapon/mop,/obj/structure/mopbucket,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"eC" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume,/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"eD" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/light/small{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eE" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eF" = (/obj/random/tool,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eG" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eH" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eI" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eK" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eL" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"eM" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"eN" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock{name = "Slave hold hallway"},/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"eO" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"eP" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"eQ" = (/obj/item/modular_computer/console{name = "Cameras console"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"eR" = (/obj/item/modular_computer/console{name = "Riot control console"},/obj/machinery/power/apc{dir = 2; name = "Slavers security wing"; operating = 1; pixel_y = -24},/obj/structure/cable,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"eS" = (/obj/structure/table/steel,/obj/item/weapon/handcuffs,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"eT" = (/obj/item/weapon/gun/projectile/shotgun/pump,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"eU" = (/obj/machinery/optable,/obj/item/weapon/scalpel,/obj/effect/decal/cleanable/blood,/obj/machinery/light,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"eV" = (/obj/structure/window/basic{dir = 4},/obj/structure/table/standard,/obj/item/weapon/implanter,/obj/item/weapon/implantcase/tracking,/obj/item/weapon/surgicaldrill,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"eW" = (/obj/machinery/optable,/obj/effect/decal/cleanable/blood,/obj/item/weapon/screwdriver,/obj/machinery/light,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"eX" = (/obj/structure/window/basic{dir = 4},/obj/structure/table/standard,/obj/item/weapon/implantpad,/obj/item/weapon/reagent_containers/pill/spaceacillin,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"eY" = (/obj/structure/table/standard,/obj/item/weapon/storage/firstaid/empty,/obj/item/weapon/handcuffs,/obj/item/weapon/melee/baton,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"eZ" = (/obj/structure/table/standard,/obj/item/weapon/storage/firstaid/o2,/obj/item/weapon/folder/white,/obj/item/weapon/paper{info = "Seems they don't really look over my shoulder anymore. We have now maybe a dozen of them with inactive implants. Hope they will pick right moment to flip the lid. I'll kill few bastards myself soon as I have a chance."; name = "Note"},/obj/item/weapon/pen,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"fa" = (/obj/structure/table/standard,/obj/item/weapon/storage/firstaid/regular,/obj/item/weapon/material/hatchet,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"fb" = (/obj/item/roller,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"fc" = (/obj/structure/bed,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"fd" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/handcuffs,/obj/item/weapon/storage/box/handcuffs,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"fe" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/bodybags,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"ff" = (/obj/structure/table/standard,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"fg" = (/obj/structure/reagent_dispensers/water_cooler,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"fh" = (/obj/machinery/atmospherics/pipe/manifold/visible/cyan{icon_state = "map"; dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"fi" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{icon_state = "intact"; dir = 9},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"fj" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 2; name = "Slavers hangar"; operating = 1; pixel_y = -24},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"fk" = (/obj/machinery/light/small,/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"fl" = (/obj/effect/decal/cleanable/generic,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fm" = (/obj/effect/decal/cleanable/generic,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fn" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock{name = "Slave hold hallway"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"fo" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fp" = (/obj/machinery/door/airlock/external,/obj/machinery/atmospherics/pipe/simple/visible/cyan,/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"fq" = (/obj/machinery/door/airlock/external,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"fr" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/effect/decal/cleanable/generic,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fs" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"ft" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock{name = "Power/atmos"},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/airless/ceiling,/area/slavers_base/hallway) +"fu" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/structure/cable/green,/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fv" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fw" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock{name = "West hallway"},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fx" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fy" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fz" = (/obj/machinery/door/airlock{name = "Transit area"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/maint) +"fA" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fB" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/power/terminal,/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fC" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fE" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fF" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fG" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{dir = 4; icon_state = "intact"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fH" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{icon_state = "intact"; dir = 9},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fI" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fJ" = (/turf/simulated/wall,/area/slavers_base/maint) +"fK" = (/obj/machinery/atmospherics/pipe/tank/carbon_dioxide,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fL" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 6},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fM" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow,/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fN" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 10},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fO" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fP" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fQ" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fR" = (/obj/machinery/door/airlock{name = "Power/atmos"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/airless/ceiling,/area/slavers_base/hallway) +"fS" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fT" = (/obj/item/weapon/wrench,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fU" = (/obj/machinery/light,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fV" = (/obj/machinery/door/airlock{name = "West hallway"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fW" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fX" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fY" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/power/smes/buildable,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fZ" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"ga" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gb" = (/obj/machinery/atmospherics/pipe/manifold/visible/black{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gc" = (/obj/machinery/atmospherics/pipe/manifold/visible/black,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gd" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"ge" = (/obj/machinery/atmospherics/trinary/filter{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gf" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/obj/effect/decal/cleanable/generic,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gg" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gh" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 4; name = "Slavers atmos and power room"; pixel_x = 24},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gi" = (/turf/simulated/wall,/area/slavers_base/dorms) +"gj" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock{name = "Mess"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gk" = (/obj/machinery/door/airlock{name = "Southern hallway"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"gl" = (/obj/machinery/door/airlock{name = "Southern hallway"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"gm" = (/obj/machinery/door/airlock{name = "Slave trade area"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gn" = (/obj/machinery/atmospherics/binary/pump,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"go" = (/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gp" = (/obj/item/weapon/crowbar,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gq" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gr" = (/obj/structure/table/steel,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/item/weapon/circuitboard/broken,/obj/item/weapon/contraband/poster,/obj/item/device/radio,/obj/machinery/light/small{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gs" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"gt" = (/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gu" = (/obj/machinery/vending/wallmed2{pixel_y = 30},/obj/structure/table/standard,/obj/random/cash,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gv" = (/obj/structure/bed,/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gw" = (/obj/structure/closet,/obj/random/smokes,/obj/random/loot,/obj/random/contraband,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gx" = (/obj/structure/table/standard,/obj/random/coin,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gy" = (/obj/structure/bed,/obj/random/plushie,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gz" = (/obj/structure/closet,/obj/random/smokes,/obj/random/loot,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gA" = (/obj/structure/table/standard,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gB" = (/obj/structure/closet,/obj/random/loot,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gC" = (/obj/structure/table/standard,/obj/random/contraband,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gD" = (/obj/structure/bed,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gE" = (/obj/structure/closet,/obj/random/smokes,/obj/random/cash,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gF" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"gG" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"gH" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gI" = (/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gJ" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gK" = (/obj/machinery/light/small{dir = 1},/obj/effect/decal/cleanable/generic,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gL" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gM" = (/obj/structure/table/steel,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/item/weapon/storage/toolbox/mechanical,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gN" = (/obj/random/junk,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gO" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gP" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gQ" = (/obj/random/junk,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 2; name = "Slavers Maintenance"; operating = 1; pixel_y = -24},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gR" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gS" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/decal/cleanable/generic,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gT" = (/obj/machinery/door/airlock{name = "Exchange tunnel"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gU" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gV" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gW" = (/obj/machinery/floodlight,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gX" = (/obj/structure/table/steel,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gY" = (/obj/machinery/light{dir = 8},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"gZ" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"ha" = (/obj/effect/decal/cleanable/generic,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hb" = (/obj/machinery/light{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"hc" = (/obj/machinery/light{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"hd" = (/turf/simulated/wall,/area/slavers_base/demo) +"he" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"hf" = (/obj/machinery/light/small{dir = 4; pixel_y = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"hg" = (/obj/item/weapon/coilgun_assembly,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hh" = (/obj/random/junk,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hi" = (/obj/structure/table/steel,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/item/stack/material/phoron{amount = 25},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hj" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hk" = (/obj/structure/table/standard,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hl" = (/obj/structure/bed,/obj/item/device/radio,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hm" = (/obj/structure/closet,/obj/random/projectile,/obj/random/loot,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hn" = (/obj/structure/table/standard,/obj/random/loot,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"ho" = (/obj/structure/table/standard,/obj/random/gloves,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hp" = (/obj/structure/closet,/obj/random/loot,/obj/random/contraband,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hq" = (/obj/structure/closet,/obj/random/projectile,/obj/random/ammo,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hr" = (/obj/structure/safe,/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"hs" = (/obj/machinery/light{dir = 1},/obj/structure/safe,/obj/item/weapon/storage/bag/cash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"ht" = (/obj/structure/safe,/obj/item/weapon/storage/bag/cash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"hu" = (/obj/machinery/light{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hv" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hw" = (/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hx" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hy" = (/obj/random/junk,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"hz" = (/obj/machinery/vending/engineering,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hA" = (/obj/item/weapon/computer_hardware/card_slot,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hB" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hC" = (/obj/machinery/power/smes/buildable,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock{name = "Slave hold hallway"},/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hE" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"hF" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"hG" = (/obj/machinery/door/airlock{name = "Safe room"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"hH" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"hI" = (/obj/random/coin,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"hJ" = (/obj/machinery/door/airlock{name = "Cashier room"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"hK" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hL" = (/obj/structure/bed/chair{dir = 4},/obj/item/device/radio,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hM" = (/obj/structure/table/reinforced,/obj/random/coin,/obj/machinery/door/blast/regular/open{icon_state = "pdoor0"; id = "SC BD"},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hN" = (/obj/structure/bed/chair/comfy/beige{dir = 4},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hO" = (/obj/structure/table/woodentable,/obj/item/device/radio,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hP" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/secure/briefcase/money,/obj/random/cash,/obj/random/cash,/obj/random/cash,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hQ" = (/obj/structure/bed/chair/comfy/beige{dir = 8},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hR" = (/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hS" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"hT" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"hU" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"hV" = (/obj/machinery/light{dir = 1},/obj/machinery/vending/dinnerware,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"hW" = (/obj/machinery/cooker/oven,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"hX" = (/obj/structure/table/standard,/obj/machinery/microwave,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"hY" = (/obj/structure/table/standard,/obj/random/snack,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"hZ" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"ia" = (/obj/structure/table/standard,/obj/machinery/light{dir = 1},/obj/item/trash/plate,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"ib" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"ic" = (/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"id" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/generic,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"ie" = (/obj/structure/closet/secure_closet/guncabinet,/obj/random/projectile,/obj/random/projectile,/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"if" = (/obj/structure/closet/secure_closet/guncabinet,/obj/random/projectile,/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"ig" = (/obj/random/coin,/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"ih" = (/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"ii" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"ij" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/bag/cash,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"ik" = (/obj/structure/table/woodentable,/obj/random/cash,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"il" = (/obj/structure/ore_box,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"im" = (/obj/structure/ore_box,/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"in" = (/obj/structure/closet/crate,/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"io" = (/obj/structure/closet/crate,/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/machinery/light/small,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"ip" = (/obj/structure/closet/crate,/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"iq" = (/obj/machinery/power/port_gen/pacman/super,/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"ir" = (/obj/machinery/power/port_gen/pacman/super,/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"is" = (/obj/machinery/power/port_gen/pacman/super,/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/machinery/light/small,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"it" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"iu" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iv" = (/obj/effect/decal/cleanable/generic,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iw" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"ix" = (/obj/machinery/vending/snack,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iy" = (/obj/structure/table/woodentable,/obj/item/weapon/paper{info = "
            Contract

            This contract describes exchanging of monetary pieces for the right o? the ownership for following examples: <*> Tajaran, age 17. Price - 1500 credits. <*> Tajaran, age 49. Price - 1100 credits. <*> Tajaran, age 28. Good fist fighter. Price - 2400 credits. <*> Human, age 34. Expirienced medic. Price - 6800 credits. Overall price: 11800 credits
            Place for signatures"; name = "Contract"},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"iz" = (/obj/structure/table/woodentable,/obj/random/coin,/obj/item/weapon/pen,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"iA" = (/obj/machinery/light{dir = 8},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iB" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iC" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iD" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iE" = (/mob/living/simple_animal/hostile/abolition_extremist,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iF" = (/obj/machinery/vending/fitness,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iG" = (/obj/random/junk,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"iH" = (/obj/machinery/light{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"iI" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"iJ" = (/obj/machinery/light{dir = 1},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"iK" = (/obj/item/clothing/suit/nun,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"iL" = (/obj/machinery/light{dir = 1},/obj/item/clothing/suit/unathi/robe,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"iM" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/power/apc{dir = 2; name = "Slavers Dorms"; operating = 1; pixel_y = -24},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iN" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iO" = (/obj/structure/table/standard,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/item/weapon/reagent_containers/food/condiment/small/peppermill,/obj/item/weapon/reagent_containers/food/condiment/small/saltshaker{pixel_x = 3; pixel_y = 10},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iP" = (/obj/structure/table/standard,/obj/random/smokes,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iQ" = (/obj/structure/table/standard,/obj/random/drinkbottle,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iR" = (/obj/structure/table/standard,/obj/item/trash/plate,/obj/item/weapon/material/kitchen/utensil/fork,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iS" = (/obj/structure/table/standard,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iT" = (/obj/random/junk,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iU" = (/obj/item/weapon/material/kitchen/utensil/fork,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iV" = (/obj/machinery/vending/cola,/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iW" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"iX" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"iY" = (/obj/machinery/door/airlock{name = "Scene"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"iZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"ja" = (/obj/item/clothing/shoes/brown,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"jb" = (/obj/item/clothing/under/bluepyjamas,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"jc" = (/obj/effect/decal/cleanable/generic,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"jd" = (/obj/machinery/light,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"je" = (/obj/machinery/door/airlock{name = "Maintenance"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/dorms) +"jf" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/wall,/area/slavers_base/dorms) +"jg" = (/obj/structure/table/standard,/obj/random/projectile,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jh" = (/obj/structure/table/standard,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"ji" = (/obj/structure/table/standard,/obj/item/trash/plate,/obj/random/snack,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jj" = (/obj/structure/table/standard,/obj/item/weapon/material/kitchen/utensil/fork,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jk" = (/obj/structure/table/standard,/obj/random/smokes,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jl" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/vending/cigarette,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jm" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"jn" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"jo" = (/obj/machinery/door/airlock{name = "Private office"},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"jp" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/dorms) +"jq" = (/obj/structure/table/standard,/obj/item/device/radio,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/dorms) +"jr" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"js" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jt" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/effect/decal/cleanable/dirt,/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"ju" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"jv" = (/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jw" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jx" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jy" = (/obj/structure/cable/green,/obj/machinery/power/terminal{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/dorms) +"jz" = (/obj/structure/cable,/obj/machinery/power/smes/buildable,/turf/simulated/floor/airless/ceiling,/area/slavers_base/dorms) +"jA" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jB" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jC" = (/obj/item/weapon/paper{info = "We made over 200 grands for two last weeks. We should stay low-key for month or so, or we'll get our base discovered by fucking marshalls so shut your whining and relax, I'l l get you three crates of booze and some cargo to play with."; name = "Note"},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jD" = (/obj/random/snack,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jE" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jF" = (/obj/machinery/door/airlock{name = "Mess"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"jG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"jH" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"jI" = (/obj/structure/table/standard,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jJ" = (/obj/structure/table/standard,/obj/item/device/megaphone,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jK" = (/obj/structure/table/standard,/obj/item/clothing/mask/smokable/cigarette,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jL" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jM" = (/obj/structure/table/standard,/obj/item/device/healthanalyzer,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jN" = (/obj/structure/table/standard,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jO" = (/obj/structure/table/standard,/obj/item/weapon/pen,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jP" = (/obj/machinery/door/airlock{name = "Restroom"},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"jQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock{name = "Southern hallway"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"jR" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jS" = (/obj/structure/bed/chair{dir = 1},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jT" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jU" = (/obj/structure/bed/chair{dir = 1},/obj/item/weapon/storage/secure/briefcase/money,/obj/random/cash,/obj/random/cash,/obj/random/cash,/obj/random/cash,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jV" = (/obj/structure/bed/chair{dir = 4},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jW" = (/obj/structure/table/standard,/obj/item/clothing/mask/smokable/cigarette/professionals,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jX" = (/obj/machinery/shower{dir = 4; icon_state = "shower"; pixel_x = 0; pixel_y = 0},/turf/simulated/floor/tiled/white/airless,/area/slavers_base/dorms) +"jY" = (/obj/machinery/door/airlock{name = "Shower"},/turf/simulated/floor/tiled/white/airless,/area/slavers_base/dorms) +"jZ" = (/obj/effect/landmark/corpse/slavers_base/slaver3,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"ka" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"kb" = (/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"kc" = (/obj/effect/landmark/corpse/slavers_base/slaver1,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"kd" = (/obj/machinery/door/airlock{name = "Toilet"},/turf/simulated/floor/tiled/white/airless,/area/slavers_base/dorms) +"ke" = (/obj/structure/toilet{dir = 8},/obj/random/junk,/turf/simulated/floor/tiled/white/airless,/area/slavers_base/dorms) +"kf" = (/turf/simulated/wall,/area/slavers_base/hallway) +"kg" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"kh" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"ki" = (/obj/machinery/door/airlock{name = "Slave trade area"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"kj" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"kk" = (/mob/living/simple_animal/hostile/abolition_extremist,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"kl" = (/obj/effect/decal/cleanable/generic,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"km" = (/obj/machinery/light{dir = 4},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"kn" = (/obj/machinery/light{dir = 8},/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"ko" = (/obj/machinery/light{dir = 4},/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"kp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"kq" = (/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"kr" = (/obj/machinery/door/airlock{name = "Slave trade area"},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"ks" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/power/apc{dir = 2; name = "south bump"; operating = 1; pixel_y = -24},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"kt" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"ku" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"kv" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/glass_extras,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"kw" = (/obj/structure/table/standard,/obj/machinery/chemical_dispenser/bar_alc,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"kx" = (/obj/structure/sink{pixel_y = -20},/obj/structure/mirror{pixel_y = -35},/obj/effect/landmark/corpse/slavers_base/slaver2,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"ky" = (/obj/structure/sink{pixel_y = -20},/obj/structure/mirror{pixel_y = -35},/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"kz" = (/mob/living/simple_animal/hostile/abolition_extremist,/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"kA" = (/obj/machinery/door/airlock{name = "Customers entry"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"kB" = (/obj/machinery/door/airlock{name = "Customers entry"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"kC" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/effect/decal/cleanable/generic,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kE" = (/obj/machinery/door/airlock{name = "Exchange area"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kF" = (/obj/effect/decal/cleanable/generic,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/decal/cleanable/generic,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kH" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kI" = (/obj/machinery/atmospherics/pipe/simple/visible/universal,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kJ" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kK" = (/obj/machinery/door/airlock{name = "Exchange point"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kL" = (/obj/machinery/atmospherics/binary/pump,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kM" = (/obj/structure/table/standard,/obj/item/device/radio,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kN" = (/obj/structure/table/standard,/obj/random/handgun,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kO" = (/obj/machinery/door/airlock/external,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kP" = (/obj/machinery/door/airlock/external,/obj/machinery/atmospherics/pipe/simple/visible/cyan,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kQ" = (/obj/structure/table/standard,/obj/random/junk,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kR" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kS" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kT" = (/obj/structure/table/standard,/obj/random/loot,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kU" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1379; id_tag = "solar_port_pump"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kV" = (/obj/machinery/door/airlock/external,/turf/space,/area/slavers_base/maint) +"kW" = (/obj/effect/overmap/sector/slavers_base,/turf/space,/area/space) +"kX" = (/obj/effect/shuttle_landmark/nav_slavers_base/nav5,/turf/space,/area/space) +"kY" = (/obj/effect/shuttle_landmark/nav_slavers_base/nav6,/turf/space,/area/space) +"kZ" = (/obj/effect/landmark/random_gen/asteroid,/turf/space,/area/space) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadaaaaadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadaaaaaaaaadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadaaaaadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadaaaaaaaaaaadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadaaaaaaadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadaaaaaaadadadadadadadadadadaaaaaaaaadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadaaaaaaadadadaaaaaaaaaaaaaaaaaaadaaaaaaaaadadadadadadadaaaaaaadadadadadadadadadadadadaaaaaaaaaaadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadaaaaaaaaadadadadaaaaaaaaaaadaaaaaaaaadaaaaadadadadadadadadadadadadadadadadadadadadadaaaaaaadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadaaaaaaaaaaadadadaaaaaaaaaaadadadadaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadaaaaadadadaaaaaaaaaaadadadadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadaaaaadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadafafafafafafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadafafafafagagafafafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadahahahahahahahahahahahahahahahahahahahagagagagagagafafafafafafafafafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadahajakakalakakakamanakaoapaqarakakasahagagatagagagagagagafafafagafafafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadahajakakajakakananakakakakakakakakauahagatagagatagavagagagagagagawafafafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadahakajakakaxakanakakayakazakakakakaAahagatagagagagagagagagagagagagagafafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadahakakajakakakakakaBaCayakakaCakaDaEahagagavagagagagagagagagawagagagagafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadahakakakaFakaBakaBakayaGaHaIaHakaJaKaLagagagagagagagagagagagagagagagagafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaNaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMaOaPaPaQaPaPaPaPaPaRaSaSaQaPaPaMaTaUaMaOaQaPaMaOaQaVaMaOaQaRaMaOaQaWaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMaXaPaYaPaPaZaPaPaPaPaPaPbaaPaPaMbbaUaMaVbcbdaMaPbebfaMaPbgaPaMaPbhaWaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadadadadadadadadadadadadadadadadadadadadadaMbiaPaWaRbaaPaRaPaPbaaPaPaPaPaRaMbbaUaMbjbkbjaMbjbkbjaMbjbkbjaMbjblbjaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadaMaPaRbeaPaPaVaPbeaPaRaPaPbeaPaPaMbmbnbobpbqbrbsbrbqbrbsbrbqbrbsbrbqbtaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadaMaPaVaPaPaWaWbuaPaVaPaVbvaPbwaPaMbbbxbybzaUbxaUbAaUbxbBbxaUbxaUbxaUbCaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadaMaPaPaRaPaPaPaPaPaWaPaPaPbDaPbEaMbFbxaMbGbHbGaMbGbHbGaMbGbHbGaMbGbHbGaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadaMaPaPaWaPaPaPaPaPbaaPaPaPaPaPbIaMbbbxaMaWbeaRaMbJbeaVaMaPbeaPaMaVbeaWaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadaMaMaMbKbLbMaMbKbLbMaMbKbLbMaMbNaMbbbxaMaObOaPaMaObPaWaMaObObQaMaObOaRaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadaMbRaUaUbSbqbqbqbTbUbqbqbVbqbqbWbXbYbZaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadaMaMaMbKcabMaMbKcabMaMbKcabMaMcbaMccbxaMcdceaPaMaOaQaPaMaOaQcfaMaOcgchaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMaPaWaPaPaPaPaPaPciaPaPaPaPaRcjaMbbbxaMaPbeaPaMchbeaPaMaPbeaPaMaPbebfaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadaaaaadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMaPaZaPaPaPaRaPaPaPaPaPaPaVaPckaMclbxaMbjbkbjaMbjbkbjaMbjbkbjaMbjbkbjaMcmcmcmcmcmcmcmcmcmcmcmcmcmcmcmadadadadadadadadadadadadadaaaaaaaaaaadadadadadadadadadadadadadadadaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMaPaPaPaPaPaVaPaPaWaPchaPaPaRaPaMbmcncocpbqcqbscqbqcqbscqbqcqbscqbqcraMcscscsctcscscscscscscsctcscscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMaPcvbechaPaVaPbeciaPaPaPbeaPaPaMcwbxcxbzaUbxaUbxaUbxaUbxaUbxaUbxaUbCaMcscscscscscscscscscscscscscscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMbibaaPaPaPaPaPaPaPaPchcybJaPaWaMczcAaMbGcBbGaMbGbHbGaMbGbHbGaMbGbHbGaMcscscCcDcDcDcDcDcDcDcDcDcEcscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadaMaXaWaPaPcvcFaPaRaPaPchaPaPcGaPaMbbbxaMaPbeaPaMaPbechaMaPbeaPaMaPbeaPaMcscscHcscscscscscscscscscIcscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadaMaOaPcJbOaPaPbfaPaPaPaPaPcKcLbvaMbbbxaMaObOcMaMaOcNaWaMaObOcOaMcPcQaVaMcscscHcscscscscscscscscscIcscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadaaaaadadadadadadadadadadadcRcRcRcRcRcRcRcRcRcRcRcScScScScScScScScScScScScScScScScScTcUcVcVcVcVcVcVcVcVcVcVcVcVcVcVcVcVcVcscscHcscscscscscscscscscIcscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadcRcXcXcXcYcZdacZdbdcdccSdddedfdgdhcSdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdzdxdxdxdAdBdCdDdEdFcVcscscHcscscscscscscscscscIcscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadcRdGdHdIdIdJdacZcZdKdacSdLdLdLdLdLcSdMdNdNdOdNdNdPdQdRdSdTdUcVdVdxdxdxdxdWdXdxdYcVdBdBdBdZeacVcscsebecececececececececedcscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadcReeefdadaegcZdadadadKcSdLehdLeidLcSejekdpelemeneneoepeqerescVeteuevewdxexdxeyezcVeAdBdBdBeBcVeCeCcscscscscscscscscscscscscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadcReDeEdaeFdGeGeHeIeJeKcSeLeMeMeMeMeNeOePdpdpdpdpeQeReSeqereTcVeUeVeWeXeYeZfafbfccVfdfeffdBfgcVfhfifjfkcscscscscscscsfkcscscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadcRdadadadaegdadaflfmdacSfncScScScScScScScScScScScScScScSerfocVcVcVcVcVcVcVcVcVcVcVcVcVcVcVcVcVfpfqcmcmcmcmcmcmcmcmcmcmcmcmcmadadadadadadadadadadadadadadadadadadadaaaaaaadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadcRdadadadaegdadadafrfsftfufvfvfvfvfvfvfvfvfvfvfvfvfvfvfwfxfyfzfAfBfCfCfDfCfCfCfCfDfCfCfCfEfFfGfHfIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadaaaaadaaaaadadadadadadadadadadadadadadadadadadadadcRfKfKdafLfMfNdafOfPfQfRfSfofofTfUfofofofofofUfofofofofVfWfofJfXfYfZfZfZfZfZfZfZfZfZfZfZfZfZfZfZgafJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadaaaaaaaaadadadadadadadadadadadadadadadadadadadadadcRgbgcgdgcgegegdgfggghgigjgigigigigigigigigigigigigigigigkglfJgmfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadaaaaaaaaadadadadadadadadadadadadadadadadadadadadcRgngodadagpdadadagqgrgigsgigtgugvgwgxgygzgAgvgBgCgDgEgigFgGfJgHgIgIgIgJgIgIgIgIgKgIgIgIgIgJgIgIgIfJgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadaaaaadadadadadadadadadadadadadadadadadadadadcRgLgogodadaeFdadagqgMgigsgigtgtgtgNgtgtgtgtgtgtgtgtgtgierfofJgOgPgQgRgRgRgRgRgRgRgRgSgRgRgRgRgRgRgTgUgVfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadcRgWdadadadadadaeFgqgXgigYgigZgtgtgtgthagtgtgNgtgNgtgtgihbfofJhcgIhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhehffJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadcRgWdahgdadahhdadagqhigigsgihjhkhlhmhngDgzhogDhpgAgyhqgierfofJgHgIhdhrhshrhrhthdhuhvhdhwhwhxhwhwhwhdgIhyfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadcRhzdadadahAdadadahBhCgigsgihDgigigigigigigigigigigigigierfofJhEhFhGhHhHhHhIhHhJhKhLhMhwhNhOhPhQhwhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadcRdadadadadadadadadahRgihShThUhThVhWhXhXhYhZiaibibicicgieridfJgHgIhdieifigigihhdiihwhdhwhNijikhQhwhdhygIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadcRiliminioipiqirisiritgiiuiciviciciwicicicicicicicicixgierfofJgHgIhdhdhdhdhdhdhdhdhdhdhwhNiyizhQhwhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadcRcRcRcRcRcRcRcRcRcRcRgiiAiciciciviBiCiCiCiDiciciEiciFgihbiGfJiHgIhdiIiJiIiKiIiIiLiIhdhwhwhwhwhwhwhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgiiuiMiNiNiNiOiPiQiRiSiNiTiNiUiVgierfofJiWiXiYiZjajbiIiIiIiIiIhdhwjcjdhwhwhwhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgijejfgiicicjgjhjijjjkicivicivjlgierfohdhdhdhdjmjnjnjnjnjnjnjnhdhdhdhdhdhdjohdgIhffJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgijpjqgiicicjrjrjrjrjricicicicjsgijtjuhdjvjvjwjxjvjvjvjvjvjvjvjwjvjvjvjvjvjvhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgijyjzgijAjBicicicicicjBjCicjDjEjFjGjHhdjvjvjvjIjJjKjLjMjLjNjOjvjvjvjvjvjvjvhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgigigigijPgigigigigigigigigigigigijQglhdjRjvjvjSjTjTjTjTjTjTjUjvjvjVjWjLjNjvhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgijXjYjZkakbkckdkegiadadadadadadkfkgkhkikjjvjvjxkkjvkljvjvjvjvjvjvjVjNjvjvkmhdgIhyfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgigigiknkbkbkogigigiadadadadadadkfkpkqkrksktktkujvjvjvjvjvjvjvjvjvjVjLjvkvkwhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgijXjYkbkxkykzkdkegiadadadfJfJfJfJkAkBhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdgIhffJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgigigigigigigigigigiadadadfJgIkCfCkDgIkEgIgJgIkEgIkFgIgIgIgJhygIkFkFgIgKgIgIgIgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadfJgIkGgIgIgIkEgIgIgIkEgIgIkFgIkFgIgIgIgIhygIgIgIgIgIgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadfJkHkIfJfJfJfJkJkJkJfJkKfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadfJgIkLfJadadfJkMkNgIgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadfJkOkPfJadadfJkQkRhffJfJfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadfJkHkSfJadadfJkTgIkFfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadfJgIkUfJadadfJfJfJfJfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadfJkVkVfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadaaaaaaaaadadadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadagagadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadagagadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadagagadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadagagadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadaaaaadadadadadadadadadadadadadagagadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadadadadadadadadadadadadadadaaaaadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadagagadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadadadadadadadadadadadadadadaaaaadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadaakWadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadaaaaaaaaaaaaaaadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadaaaaaaaaaaaaaaaaadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadaaaaadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +kZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/slavers/slavers_base.dm b/maps/away/slavers/slavers_base.dm new file mode 100644 index 00000000..a8fc7cc1 --- /dev/null +++ b/maps/away/slavers/slavers_base.dm @@ -0,0 +1,190 @@ +#include "slavers_base_areas.dm" +#include "../mining/mining_areas.dm" + +/obj/effect/overmap/sector/slavers_base + name = "large asteroid" + desc = "Sensor array is reading an artificial structure inside the asteroid." + icon_state = "object" + known = 0 + + generic_waypoints = list( + "nav_slavers_base_1", + "nav_slavers_base_2", + "nav_slavers_base_3", + "nav_slavers_base_4", + "nav_slavers_base_5", + "nav_slavers_base_6", + "nav_slavers_base_antag" + ) + +/datum/map_template/ruin/away_site/slavers + name = "Slavers' Base" + id = "awaysite_slavers" + description = "Asteroid with slavers base inside." + suffixes = list("slavers/slavers_base.dmm") + cost = 1 + +/obj/effect/shuttle_landmark/nav_slavers_base/nav1 + name = "Slavers Base Navpoint #1" + landmark_tag = "nav_slavers_base_1" + +/obj/effect/shuttle_landmark/nav_slavers_base/nav2 + name = "Slavers Base Navpoint #2" + landmark_tag = "nav_slavers_base_2" + +/obj/effect/shuttle_landmark/nav_slavers_base/nav3 + name = "Slavers Base Navpoint #3" + landmark_tag = "nav_slavers_base_3" + +/obj/effect/shuttle_landmark/nav_slavers_base/nav4 + name = "Slavers Base Navpoint #4" + landmark_tag = "nav_slavers_base_4" + +/obj/effect/shuttle_landmark/nav_slavers_base/nav5 + name = "Slavers Base Navpoint #5" + landmark_tag = "nav_slavers_base_5" + +/obj/effect/shuttle_landmark/nav_slavers_base/nav6 + name = "Slavers Base Navpoint #6" + landmark_tag = "nav_slavers_base_6" + +/obj/effect/shuttle_landmark/nav_slavers_base/nav7 + name = "Slavers Base Navpoint #7" + landmark_tag = "nav_slavers_base_antag" + +/obj/structure/slavers_base/mattress + name = "dirty mattress" + desc = "Dirty, smelling mattress, covered with body fluids. You wouldn't want to touch this." + icon = 'maps/away/slavers/slavers_base_sprites.dmi' + icon_state = "dirty_mattress" + anchored = 0 + +/decl/hierarchy/outfit/corpse + name = "Corpse Clothing" + +/decl/hierarchy/outfit/corpse/New() + ..() + hierarchy_type = type + +/decl/hierarchy/outfit/corpse/slavers_base + name = "Basic slaver output" + +/obj/effect/landmark/corpse/slavers_base/slaver1 + name = "Slaver" + corpse_outfits = list(/decl/hierarchy/outfit/corpse/slavers_base/slaver1) + +/decl/hierarchy/outfit/corpse/slavers_base/slaver1 + name = "Dead Slaver 1" + uniform = /obj/item/clothing/under/johnny + shoes = /obj/item/clothing/shoes/black + glasses = /obj/item/clothing/glasses/sunglasses + +/obj/effect/landmark/corpse/slavers_base/slaver2 + name = "Slaver" + corpse_outfits = list(/decl/hierarchy/outfit/corpse/slavers_base/slaver2) + +/decl/hierarchy/outfit/corpse/slavers_base/slaver2 + name = "Dead Slaver 2" + uniform = /obj/item/clothing/under/grayson + shoes = /obj/item/clothing/shoes/blue + +/obj/effect/landmark/corpse/slavers_base/slaver3 + name = "Slaver" + corpse_outfits = list(/decl/hierarchy/outfit/corpse/slavers_base/slaver3) + +/decl/hierarchy/outfit/corpse/slavers_base/slaver3 + name = "Dead Slaver 3" + uniform = /obj/item/clothing/under/pirate + shoes = /obj/item/clothing/shoes/brown + +/obj/effect/landmark/corpse/slavers_base/slaver4 + name = "Slaver" + corpse_outfits = list(/decl/hierarchy/outfit/corpse/slavers_base/slaver4) + +/decl/hierarchy/outfit/corpse/slavers_base/slaver4 + name = "Dead Slaver 4" + uniform = /obj/item/clothing/under/redcoat + shoes = /obj/item/clothing/shoes/brown + +/obj/effect/landmark/corpse/slavers_base/slaver5 + name = "Slaver" + corpse_outfits = list(/decl/hierarchy/outfit/corpse/slavers_base/slaver5) + +/decl/hierarchy/outfit/corpse/slavers_base/slaver5 + name = "Dead Slaver 5" + uniform = /obj/item/clothing/under/sterile + shoes = /obj/item/clothing/shoes/orange + mask = /obj/item/clothing/mask/surgical + +/obj/effect/landmark/corpse/slavers_base/slaver6 + name = "Slaver" + corpse_outfits = list(/decl/hierarchy/outfit/corpse/slavers_base/slaver6) + +/decl/hierarchy/outfit/corpse/slavers_base/slaver6 + name = "Dead Slaver 6" + uniform = /obj/item/clothing/under/frontier + shoes = /obj/item/clothing/shoes/orange + +/obj/effect/landmark/corpse/slavers_base/slave + name = "Slave" + corpse_outfits = list(/decl/hierarchy/outfit/corpse/slavers_base/slave) + +/decl/hierarchy/outfit/corpse/slavers_base/slave + name = "Dead Slave" + uniform = /obj/item/clothing/under/color/orange + shoes = /obj/item/clothing/shoes/tactical + +/mob/living/simple_animal/hostile/abolition_extremist + name = "abolition extremist" + desc = "Vigiliant fighter against slavery." + icon = 'maps/away/slavers/slavers_base_sprites.dmi' + icon_state = "extremist" + icon_living = "extremist" + icon_dead = "extremist_dead" + speak_chance = 0 + turns_per_move = 5 + response_help = "pushes" + response_disarm = "shoves" + response_harm = "hits" + speed = 4 + stop_automated_movement_when_pulled = 0 + maxHealth = 100 + health = 100 + harm_intent_damage = 5 + melee_damage_lower = 30 + melee_damage_upper = 30 + unsuitable_atoms_damage = 15 + var/corpse = /obj/effect/landmark/corpse/abolitionist + var/weapon = /obj/item/weapon/gun/energy/laser + projectilesound = 'sound/weapons/laser.ogg' + ranged = 1 + rapid = 1 + projectiletype = /obj/item/projectile/energy/laser // /obj/item/projectile/beam + faction = "extremist abolitionists" + +/mob/living/simple_animal/hostile/abolition_extremist/death(gibbed, deathmessage, show_dead_message) + . = ..(gibbed, deathmessage, show_dead_message) + if(corpse) + new corpse(loc) + if(weapon) + new weapon(loc) + qdel(src) + +/obj/effect/landmark/corpse/abolitionist + name = "abolitionist" + corpse_outfits = list(/decl/hierarchy/outfit/corpse/abolitionist) + +/decl/hierarchy/outfit/corpse/abolitionist + name = "Dead abolitionist" + uniform = /obj/item/clothing/under/abol_uniform + shoes = /obj/item/clothing/shoes/jackboots + head = /obj/item/clothing/head/helmet/merc + +/obj/item/clothing/under/abol_uniform + name = "abolitionist combat suit" + desc = "Lightly armored suit worn by abolition extremists during raids. It has green patches on the right sleeve and the chest. There is big green \"A\" on the back." + icon = 'maps/away/slavers/slavers_base_sprites.dmi' + icon_state = "abol_suit" + item_icons = list(slot_w_uniform_str = 'maps/away/slavers/slavers_base_sprites.dmi') + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + armor = list(melee = 30, bullet = 25, laser = 10, energy = 10, bomb = 5, bio = 0, rad = 0) diff --git a/maps/away/slavers/slavers_base.dmm b/maps/away/slavers/slavers_base.dmm new file mode 100644 index 00000000..30aec9ec --- /dev/null +++ b/maps/away/slavers/slavers_base.dmm @@ -0,0 +1,773 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/obj/effect/shuttle_landmark/nav_slavers_base/nav2,/turf/space,/area/space) +"ac" = (/obj/effect/shuttle_landmark/nav_slavers_base/nav3,/turf/space,/area/space) +"ad" = (/turf/unsimulated/mask,/area/mine/unexplored) +"ae" = (/obj/effect/shuttle_landmark/nav_slavers_base/nav1,/turf/space,/area/space) +"af" = (/turf/simulated/mineral,/area/space) +"ag" = (/turf/simulated/floor/asteroid,/area/space) +"ah" = (/turf/simulated/wall,/area/slavers_base/mort) +"ai" = (/obj/effect/shuttle_landmark/nav_slavers_base/nav4,/turf/space,/area/space) +"aj" = (/obj/structure/ore_box{desc = "A heavy box covered with dried blood."; name = "Big dirty box"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"ak" = (/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"al" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"am" = (/obj/structure/crematorium,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"an" = (/obj/effect/decal/cleanable/ash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"ao" = (/obj/structure/table/standard,/obj/item/weapon/wirecutters,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"ap" = (/obj/structure/table/standard,/obj/effect/landmark/corpse/slavers_base/slave,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aq" = (/obj/structure/table/standard,/obj/item/weapon/paper{info = "If they'll keep having fun with cargo in such manner, we'll run out of freezers to keep what's left from it."; name = "Note"},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"ar" = (/obj/structure/table/standard,/obj/item/weapon/material/kitchen/utensil/knife,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"as" = (/obj/structure/table/rack,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"at" = (/obj/effect/gibspawner/human,/turf/simulated/floor/asteroid,/area/space) +"au" = (/obj/structure/table/rack,/obj/item/weapon/wirecutters,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"av" = (/obj/item/weapon/shovel,/turf/simulated/floor/asteroid,/area/space) +"aw" = (/obj/item/remains/human,/turf/simulated/floor/asteroid,/area/space) +"ax" = (/obj/item/remains/human,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"ay" = (/obj/item/bodybag,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"az" = (/obj/item/weapon/material/kitchen/utensil/knife,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aA" = (/obj/structure/table/rack,/obj/item/weapon/material/hatchet,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aB" = (/obj/structure/closet/crate/freezer,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aC" = (/obj/effect/gibspawner/human,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aD" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aE" = (/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/power/apc{dir = 4; name = "Slaves Mortuary"; pixel_x = 24},/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aF" = (/obj/machinery/light/small,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aG" = (/obj/machinery/gibber,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aH" = (/obj/structure/kitchenspike,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aI" = (/obj/structure/kitchenspike,/obj/machinery/light/small,/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aK" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aL" = (/obj/machinery/door/airlock{name = "Mortuary backyard"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/mort) +"aM" = (/turf/simulated/wall,/area/slavers_base/cells) +"aN" = (/obj/machinery/door/airlock{name = "Slaves mortuary"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"aO" = (/obj/structure/toilet{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aP" = (/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aQ" = (/obj/machinery/light/small/red{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aR" = (/obj/structure/slavers_base/mattress,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aS" = (/obj/structure/slavers_base/mattress,/obj/item/weapon/reagent_containers/glass/rag,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aT" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"aU" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"aV" = (/obj/random/trash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aW" = (/obj/item/weapon/reagent_containers/glass/rag,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aX" = (/obj/machinery/shower{dir = 4; icon_state = "shower"; pixel_x = 0; pixel_y = 0},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aY" = (/obj/item/weapon/reagent_containers/glass/rag,/obj/random/trash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"aZ" = (/obj/structure/slavers_base/mattress,/obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"ba" = (/obj/item/remains/human,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bb" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bc" = (/obj/machinery/flasher{id = "permentryflash"; name = "Floor mounted flash"; pixel_x = 0},/obj/item/weapon/reagent_containers/glass/rag,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bd" = (/obj/structure/slavers_base/mattress,/obj/item/trash/liquidfood,/obj/effect/landmark/corpse/slavers_base/slave,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"be" = (/obj/machinery/flasher{id = "permentryflash"; name = "Floor mounted flash"; pixel_x = 0},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bf" = (/obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bg" = (/obj/machinery/flasher{id = "permentryflash"; name = "Floor mounted flash"; pixel_x = 0},/obj/random/trash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bh" = (/obj/structure/slavers_base/mattress,/obj/machinery/flasher{id = "permentryflash"; name = "Floor mounted flash"; pixel_x = 0},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bi" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bj" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bk" = (/obj/machinery/door/window/brigdoor/southright,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bl" = (/obj/machinery/door/window/brigdoor/southright,/obj/random/trash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bm" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bn" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/cyan{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bo" = (/obj/machinery/door/airlock{name = "Cell block B"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bp" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bq" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"br" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bs" = (/obj/machinery/flasher{id = "permentryflash"; name = "Floor mounted flash"; pixel_x = 0},/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bt" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bu" = (/obj/structure/slavers_base/mattress,/obj/effect/landmark/corpse/slavers_base/slave,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bv" = (/obj/structure/closet/crate/freezer/rations,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bw" = (/obj/item/weapon/paper{info = "Tonight, when lights are out. Prepare shivs, pieces of glass, whatever you might find."; name = "Note"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bx" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"by" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bz" = (/obj/structure/closet/crate/freezer/rations,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bA" = (/obj/random/trash,/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bB" = (/obj/effect/decal/cleanable/dirt,/obj/item/remains/human,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bC" = (/obj/machinery/light{dir = 4},/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bD" = (/obj/random/shoes,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bE" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bF" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bG" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bH" = (/obj/machinery/door/window/brigdoor/northright,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bI" = (/obj/random/trash,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bJ" = (/obj/item/weapon/storage/bag/trash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bK" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bL" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/cyan{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bM" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bN" = (/obj/machinery/door/airlock{name = "Den B"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bO" = (/obj/machinery/light/small/red,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bP" = (/obj/machinery/light/small/red,/obj/structure/slavers_base/mattress,/obj/effect/landmark/corpse/slavers_base/slave,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bQ" = (/obj/structure/slavers_base/mattress,/obj/random/junk,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"bR" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bS" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/cyan{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bT" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/cyan{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/cyan{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bU" = (/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bV" = (/obj/random/trash,/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/cyan{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/cyan{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bW" = (/obj/machinery/flasher{id = "permentryflash"; name = "Floor mounted flash"; pixel_x = 0},/obj/effect/decal/cleanable/dirt,/obj/item/ammo_casing/shotgun/beanbag{pixel_x = -8; pixel_y = -4},/obj/item/ammo_casing/shotgun/beanbag{pixel_y = 5; pixel_z = 7},/obj/item/ammo_casing/shotgun/beanbag,/obj/item/ammo_casing/shotgun/beanbag,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bX" = (/obj/machinery/door/airlock{name = "Dens block"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bY" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/obj/effect/landmark/corpse/slavers_base/slaver4,/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"bZ" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood,/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"ca" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/cyan{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cb" = (/obj/machinery/door/airlock{name = "Den A"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cc" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood,/obj/structure/cable,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cd" = (/obj/structure/toilet{dir = 4},/obj/item/weapon/reagent_containers/food/snacks/liquidfood,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"ce" = (/obj/machinery/light/small/red{dir = 1},/obj/structure/slavers_base/mattress,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cf" = (/obj/structure/slavers_base/mattress,/obj/random/snack,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cg" = (/obj/machinery/light/small/red{dir = 1},/obj/random/medical/lite,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"ch" = (/obj/structure/slavers_base/mattress,/obj/item/remains/human,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"ci" = (/obj/random/junk,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cj" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"ck" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cl" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/item/device/flashlight,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cm" = (/turf/simulated/wall,/area/slavers_base/hangar) +"cn" = (/obj/effect/decal/cleanable/dirt,/obj/item/ammo_casing/shotgun/beanbag,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/cyan{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"co" = (/obj/machinery/door/airlock{name = "Cell block A"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cp" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cq" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cr" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/cyan{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cs" = (/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"ct" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"cu" = (/obj/machinery/door/blast/regular{id = "service_hangar"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"cv" = (/obj/effect/landmark/corpse/slavers_base/slave,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cw" = (/obj/effect/decal/cleanable/dirt,/obj/item/ammo_casing/shotgun/beanbag,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cx" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cy" = (/obj/random/medical/lite,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cz" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cA" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 4; name = "Slavers holding area"; pixel_x = 24},/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/cells) +"cB" = (/obj/machinery/door/window/brigdoor/northright,/obj/item/weapon/reagent_containers/glass/rag,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cC" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"cD" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"cE" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 5},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"cF" = (/obj/item/weapon/paper,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cG" = (/obj/item/trash/liquidfood,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cH" = (/obj/effect/floor_decal/industrial/warning{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"cI" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"cJ" = (/obj/item/weapon/paper{info = "Doc who checked us told implants won't explode our heads. Gotta make guys know. Seems I see a silver lining."; name = "Note"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cK" = (/obj/machinery/light/small/red,/obj/item/remains/human,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cL" = (/obj/random/snack,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cM" = (/obj/structure/slavers_base/mattress,/obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle,/obj/random/junk,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cN" = (/obj/machinery/light/small/red,/obj/random/trash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cO" = (/obj/structure/slavers_base/mattress,/obj/item/weapon/reagent_containers/glass/rag,/obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle,/obj/effect/landmark/corpse/slavers_base/slave,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cP" = (/obj/structure/toilet{dir = 4},/obj/item/trash/liquidfood,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cQ" = (/obj/machinery/light/small/red,/obj/structure/slavers_base/mattress,/obj/item/weapon/reagent_containers/glass/rag,/turf/simulated/floor/airless/ceiling,/area/slavers_base/cells) +"cR" = (/turf/simulated/wall,/area/slavers_base/powatm) +"cS" = (/turf/simulated/wall,/area/slavers_base/secwing) +"cT" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/airlock{name = "Slave hold hallway"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"cU" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/door/airlock{name = "Slave hold hallway"},/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"cV" = (/turf/simulated/wall,/area/slavers_base/med) +"cW" = (/obj/effect/shuttle_landmark/nav_slavers_base/nav7,/turf/space,/area/space) +"cX" = (/obj/machinery/atmospherics/pipe/tank/air,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"cY" = (/obj/machinery/atmospherics/pipe/tank/air,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"cZ" = (/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"db" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"dc" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"dd" = (/obj/structure/bed,/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"de" = (/obj/structure/closet,/obj/random/snack,/obj/random/projectile,/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"df" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"dg" = (/obj/structure/bed,/obj/random/projectile,/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"dh" = (/obj/structure/closet,/obj/random/smokes,/obj/random/masks,/obj/random/suit,/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"di" = (/obj/structure/table/rack,/obj/item/device/flashlight,/obj/random/medical/lite,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dj" = (/obj/structure/table/rack,/obj/machinery/light{dir = 1},/obj/item/weapon/storage/box/handcuffs,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dk" = (/obj/structure/table/rack,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/baton,/obj/random/tool,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dl" = (/obj/structure/table/rack,/obj/item/device/flash,/obj/random/ammo,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dm" = (/obj/structure/table/rack,/obj/item/weapon/storage/box/stunshells,/obj/item/weapon/gun/projectile/shotgun/pump,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dn" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"do" = (/obj/structure/cable{d2 = 6; icon_state = "0-6"},/obj/machinery/power/smes/buildable,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dp" = (/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dq" = (/obj/structure/cable/cyan{d2 = 4; icon_state = "0-4"},/obj/machinery/power/smes/buildable,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dr" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"ds" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"dt" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/cyan{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"du" = (/obj/machinery/door/airlock{name = "Slave processing"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dv" = (/obj/machinery/flasher{id = "permentryflash"; name = "Floor mounted flash"; pixel_x = 0},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dw" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 1; name = "Medical room"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dx" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dy" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dz" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/shower{pixel_y = 30},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dA" = (/obj/machinery/door/airlock{name = "Storage"},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dB" = (/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"dC" = (/obj/structure/reagent_dispensers/watertank,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"dD" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"dE" = (/obj/structure/closet/crate/freezer/rations,/obj/item/weapon/reagent_containers/food/snacks/liquidfood,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"dF" = (/obj/structure/closet/crate/freezer/rations,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"dG" = (/obj/machinery/atmospherics/pipe/manifold/visible/yellow{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"dH" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"dI" = (/obj/machinery/atmospherics/pipe/manifold/visible/yellow,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"dJ" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{dir = 10},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"dK" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"dL" = (/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"dM" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dN" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dO" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/generic,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dP" = (/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dQ" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable{icon_state = "2-9"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dR" = (/obj/structure/table/steel,/obj/item/weapon/storage/box/stunshells,/obj/item/weapon/melee/baton,/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"dS" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"dT" = (/obj/effect/decal/cleanable/dirt,/obj/item/ammo_casing/shotgun/beanbag,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"dU" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"dV" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dW" = (/obj/effect/decal/cleanable/dirt,/obj/random/junk,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dX" = (/obj/effect/decal/cleanable/dirt,/obj/random/medical/lite,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dY" = (/obj/structure/bed,/obj/item/remains/human,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"dZ" = (/obj/item/weapon/reagent_containers/food/snacks/liquidfood,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"ea" = (/obj/structure/closet/crate/trashcart,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"eb" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"ec" = (/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"ed" = (/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"ee" = (/obj/machinery/atmospherics/binary/pump{dir = 1; name = "waste pump"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"ef" = (/obj/machinery/atmospherics/binary/pump,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eg" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eh" = (/obj/random/junk,/obj/effect/decal/cleanable/generic,/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"ei" = (/obj/random/junk,/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"ej" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"ek" = (/mob/living/simple_animal/hostile/abolition_extremist,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"el" = (/obj/effect/landmark/corpse/slavers_base/slaver6,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"em" = (/obj/random/junk,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"en" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"eo" = (/obj/structure/bed/chair/office/dark{dir = 4},/obj/effect/decal/cleanable/blood,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"ep" = (/obj/structure/table/steel,/obj/item/device/flash,/obj/item/device/radio,/obj/item/weapon/paper{info = "If this fuck from A-3 keeps thinking he's better then piece of meat, throw him to hangar and show how little pressure turns diamonds into shit."; name = "Note"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"eq" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"er" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"es" = (/obj/item/ammo_casing/shotgun/beanbag,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"et" = (/obj/structure/window/basic{dir = 1},/obj/item/clothing/gloves/latex,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"eu" = (/obj/structure/window/basic{dir = 4},/obj/effect/decal/cleanable/dirt,/obj/effect/landmark/corpse/slavers_base/slaver5,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"ev" = (/obj/structure/window/basic{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"ew" = (/obj/structure/window/basic{dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"ex" = (/obj/effect/decal/cleanable/dirt,/obj/item/ammo_casing/shotgun/beanbag,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"ey" = (/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"ez" = (/obj/structure/bed,/obj/item/weapon/handcuffs,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"eA" = (/obj/item/weapon/beartrap,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"eB" = (/obj/item/weapon/mop,/obj/structure/mopbucket,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"eC" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume,/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"eD" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/light/small{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eE" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eF" = (/obj/random/tool,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eG" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eH" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eI" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eK" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"eL" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"eM" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"eN" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock{name = "Slave hold hallway"},/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"eO" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"eP" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"eQ" = (/obj/item/modular_computer/console{name = "Cameras console"},/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"eR" = (/obj/item/modular_computer/console{name = "Riot control console"},/obj/machinery/power/apc{dir = 2; name = "Slavers security wing"; operating = 1; pixel_y = -24},/obj/structure/cable,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"eS" = (/obj/structure/table/steel,/obj/item/weapon/handcuffs,/turf/simulated/floor/tiled,/area/slavers_base/secwing) +"eT" = (/obj/item/weapon/gun/projectile/shotgun/pump,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"eU" = (/obj/machinery/optable,/obj/item/weapon/scalpel,/obj/effect/decal/cleanable/blood,/obj/machinery/light,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"eV" = (/obj/structure/window/basic{dir = 4},/obj/structure/table/standard,/obj/item/weapon/implanter,/obj/item/weapon/implantcase/tracking,/obj/item/weapon/surgicaldrill,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"eW" = (/obj/machinery/optable,/obj/effect/decal/cleanable/blood,/obj/item/weapon/screwdriver,/obj/machinery/light,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"eX" = (/obj/structure/window/basic{dir = 4},/obj/structure/table/standard,/obj/item/weapon/implantpad,/obj/item/weapon/reagent_containers/pill/spaceacillin,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"eY" = (/obj/structure/table/standard,/obj/item/weapon/storage/firstaid/empty,/obj/item/weapon/handcuffs,/obj/item/weapon/melee/baton,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"eZ" = (/obj/structure/table/standard,/obj/item/weapon/storage/firstaid/o2,/obj/item/weapon/folder/white,/obj/item/weapon/paper{info = "Seems they don't really look over my shoulder anymore. We have now maybe a dozen of them with inactive implants. Hope they will pick right moment to flip the lid. I'll kill few bastards myself soon as I have a chance."; name = "Note"},/obj/item/weapon/pen,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"fa" = (/obj/structure/table/standard,/obj/item/weapon/storage/firstaid/regular,/obj/item/weapon/material/hatchet,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"fb" = (/obj/item/roller,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"fc" = (/obj/structure/bed,/turf/simulated/floor/tiled/airless,/area/slavers_base/med) +"fd" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/handcuffs,/obj/item/weapon/storage/box/handcuffs,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"fe" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/bodybags,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"ff" = (/obj/structure/table/standard,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"fg" = (/obj/structure/reagent_dispensers/water_cooler,/turf/simulated/floor/airless/ceiling,/area/slavers_base/med) +"fh" = (/obj/machinery/atmospherics/pipe/manifold/visible/cyan{icon_state = "map"; dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"fi" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{icon_state = "intact"; dir = 9},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"fj" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 2; name = "Slavers hangar"; operating = 1; pixel_y = -24},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"fk" = (/obj/machinery/light/small,/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"fl" = (/obj/effect/decal/cleanable/generic,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fm" = (/obj/effect/decal/cleanable/generic,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fn" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock{name = "Slave hold hallway"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/secwing) +"fo" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fp" = (/obj/machinery/door/airlock/external,/obj/machinery/atmospherics/pipe/simple/visible/cyan,/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"fq" = (/obj/machinery/door/airlock/external,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/hangar) +"fr" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/effect/decal/cleanable/generic,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fs" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"ft" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock{name = "Power/atmos"},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/airless/ceiling,/area/slavers_base/hallway) +"fu" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/structure/cable/green,/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fv" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fw" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock{name = "West hallway"},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fx" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fy" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fz" = (/obj/machinery/door/airlock{name = "Transit area"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/airless,/area/slavers_base/maint) +"fA" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fB" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/power/terminal,/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fC" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fE" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fF" = (/obj/machinery/atmospherics/binary/pump{dir = 4},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fG" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{dir = 4; icon_state = "intact"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fH" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan{icon_state = "intact"; dir = 9},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fI" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fJ" = (/turf/simulated/wall,/area/slavers_base/maint) +"fK" = (/obj/machinery/atmospherics/pipe/tank/carbon_dioxide,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fL" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 6},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fM" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow,/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fN" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 10},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fO" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fP" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fQ" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"fR" = (/obj/machinery/door/airlock{name = "Power/atmos"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/airless/ceiling,/area/slavers_base/hallway) +"fS" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fT" = (/obj/item/weapon/wrench,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fU" = (/obj/machinery/light,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fV" = (/obj/machinery/door/airlock{name = "West hallway"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fW" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"fX" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fY" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/power/smes/buildable,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"fZ" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"ga" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gb" = (/obj/machinery/atmospherics/pipe/manifold/visible/black{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gc" = (/obj/machinery/atmospherics/pipe/manifold/visible/black,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gd" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"ge" = (/obj/machinery/atmospherics/trinary/filter{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gf" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/obj/effect/decal/cleanable/generic,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gg" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gh" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 4; name = "Slavers atmos and power room"; pixel_x = 24},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gi" = (/turf/simulated/wall,/area/slavers_base/dorms) +"gj" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock{name = "Mess"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gk" = (/obj/machinery/door/airlock{name = "Southern hallway"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"gl" = (/obj/machinery/door/airlock{name = "Southern hallway"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"gm" = (/obj/machinery/door/airlock{name = "Slave trade area"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gn" = (/obj/machinery/atmospherics/binary/pump,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"go" = (/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gp" = (/obj/item/weapon/crowbar,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gq" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gr" = (/obj/structure/table/steel,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/item/weapon/circuitboard/broken,/obj/item/weapon/contraband/poster,/obj/item/device/radio,/obj/machinery/light/small{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gs" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"gt" = (/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gu" = (/obj/machinery/vending/wallmed2{pixel_y = 30},/obj/structure/table/standard,/obj/random/cash,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gv" = (/obj/structure/bed,/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gw" = (/obj/structure/closet,/obj/random/smokes,/obj/random/loot,/obj/random/contraband,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gx" = (/obj/structure/table/standard,/obj/random/coin,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gy" = (/obj/structure/bed,/obj/random/plushie,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gz" = (/obj/structure/closet,/obj/random/smokes,/obj/random/loot,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gA" = (/obj/structure/table/standard,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gB" = (/obj/structure/closet,/obj/random/loot,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gC" = (/obj/structure/table/standard,/obj/random/contraband,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gD" = (/obj/structure/bed,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gE" = (/obj/structure/closet,/obj/random/smokes,/obj/random/cash,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gF" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"gG" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"gH" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gI" = (/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gJ" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gK" = (/obj/machinery/light/small{dir = 1},/obj/effect/decal/cleanable/generic,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gL" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gM" = (/obj/structure/table/steel,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/item/weapon/storage/toolbox/mechanical,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gN" = (/obj/random/junk,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"gO" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gP" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gQ" = (/obj/random/junk,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 2; name = "Slavers Maintenance"; operating = 1; pixel_y = -24},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gR" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gS" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/decal/cleanable/generic,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gT" = (/obj/machinery/door/airlock{name = "Exchange tunnel"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gU" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gV" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"gW" = (/obj/machinery/floodlight,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gX" = (/obj/structure/table/steel,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"gY" = (/obj/machinery/light{dir = 8},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"gZ" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"ha" = (/obj/effect/decal/cleanable/generic,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hb" = (/obj/machinery/light{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"hc" = (/obj/machinery/light{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"hd" = (/turf/simulated/wall,/area/slavers_base/demo) +"he" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"hf" = (/obj/machinery/light/small{dir = 4; pixel_y = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"hg" = (/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hh" = (/obj/random/junk,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hi" = (/obj/structure/table/steel,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/item/stack/material/phoron{amount = 25},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hj" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hk" = (/obj/structure/table/standard,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hl" = (/obj/structure/bed,/obj/item/device/radio,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hm" = (/obj/structure/closet,/obj/random/projectile,/obj/random/loot,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hn" = (/obj/structure/table/standard,/obj/random/loot,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"ho" = (/obj/structure/table/standard,/obj/random/gloves,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hp" = (/obj/structure/closet,/obj/random/loot,/obj/random/contraband,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hq" = (/obj/structure/closet,/obj/random/projectile,/obj/random/ammo,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hr" = (/obj/structure/safe,/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"hs" = (/obj/machinery/light{dir = 1},/obj/structure/safe,/obj/item/weapon/storage/bag/cash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"ht" = (/obj/structure/safe,/obj/item/weapon/storage/bag/cash,/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"hu" = (/obj/machinery/light{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hv" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hw" = (/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hx" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hy" = (/obj/random/junk,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"hz" = (/obj/machinery/vending/engineering,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hA" = (/obj/item/weapon/computer_hardware/card_slot,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hB" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hC" = (/obj/machinery/power/smes/buildable,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock{name = "Slave hold hallway"},/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"hE" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"hF" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"hG" = (/obj/machinery/door/airlock{name = "Safe room"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"hH" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"hI" = (/obj/random/coin,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"hJ" = (/obj/machinery/door/airlock{name = "Cashier room"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"hK" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hL" = (/obj/structure/bed/chair{dir = 4},/obj/item/device/radio,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hM" = (/obj/structure/table/reinforced,/obj/random/coin,/obj/machinery/door/blast/regular/open{icon_state = "pdoor0"; id = "SC BD"},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hN" = (/obj/structure/bed/chair/comfy/beige{dir = 4},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hO" = (/obj/structure/table/woodentable,/obj/item/device/radio,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hP" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/secure/briefcase/money,/obj/random/cash,/obj/random/cash,/obj/random/cash,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hQ" = (/obj/structure/bed/chair/comfy/beige{dir = 8},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"hR" = (/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"hS" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"hT" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"hU" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"hV" = (/obj/machinery/light{dir = 1},/obj/machinery/vending/dinnerware,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"hW" = (/obj/machinery/cooker/oven,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"hX" = (/obj/structure/table/standard,/obj/machinery/microwave,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"hY" = (/obj/structure/table/standard,/obj/random/snack,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"hZ" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"ia" = (/obj/structure/table/standard,/obj/machinery/light{dir = 1},/obj/item/trash/plate,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"ib" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"ic" = (/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"id" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/generic,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"ie" = (/obj/structure/closet/secure_closet/guncabinet,/obj/random/projectile,/obj/random/projectile,/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"if" = (/obj/structure/closet/secure_closet/guncabinet,/obj/random/projectile,/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"ig" = (/obj/random/coin,/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"ih" = (/turf/simulated/floor/airless/ceiling,/area/slavers_base/demo) +"ii" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"ij" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/bag/cash,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"ik" = (/obj/structure/table/woodentable,/obj/random/cash,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"il" = (/obj/structure/ore_box,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"im" = (/obj/structure/ore_box,/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"in" = (/obj/structure/closet/crate,/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"io" = (/obj/structure/closet/crate,/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/machinery/light/small,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"ip" = (/obj/structure/closet/crate,/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/obj/item/stack/material/phoron{amount = 25},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"iq" = (/obj/machinery/power/port_gen/pacman/super,/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"ir" = (/obj/machinery/power/port_gen/pacman/super,/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"is" = (/obj/machinery/power/port_gen/pacman/super,/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/machinery/light/small,/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"it" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/powatm) +"iu" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iv" = (/obj/effect/decal/cleanable/generic,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iw" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"ix" = (/obj/machinery/vending/snack,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iy" = (/obj/structure/table/woodentable,/obj/item/weapon/paper{info = "
            Contract

            This contract describes exchanging of monetary pieces for the right o? the ownership for following examples: <*> Tajaran, age 17. Price - 1500 credits. <*> Tajaran, age 49. Price - 1100 credits. <*> Tajaran, age 28. Good fist fighter. Price - 2400 credits. <*> Human, age 34. Expirienced medic. Price - 6800 credits. Overall price: 11800 credits
            Place for signatures"; name = "Contract"},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"iz" = (/obj/structure/table/woodentable,/obj/random/coin,/obj/item/weapon/pen,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"iA" = (/obj/machinery/light{dir = 8},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iB" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iC" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iD" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iE" = (/mob/living/simple_animal/hostile/abolition_extremist,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iG" = (/obj/random/junk,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"iH" = (/obj/machinery/light{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"iI" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"iJ" = (/obj/machinery/light{dir = 1},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"iK" = (/obj/item/clothing/suit/nun,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"iL" = (/obj/machinery/light{dir = 1},/obj/item/clothing/suit/unathi/robe,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"iM" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/power/apc{dir = 2; name = "Slavers Dorms"; operating = 1; pixel_y = -24},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iN" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iO" = (/obj/structure/table/standard,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/item/weapon/reagent_containers/food/condiment/small/peppermill,/obj/item/weapon/reagent_containers/food/condiment/small/saltshaker{pixel_x = 3; pixel_y = 10},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iP" = (/obj/structure/table/standard,/obj/random/smokes,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iQ" = (/obj/structure/table/standard,/obj/random/drinkbottle,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iR" = (/obj/structure/table/standard,/obj/item/trash/plate,/obj/item/weapon/material/kitchen/utensil/fork,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iS" = (/obj/structure/table/standard,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iT" = (/obj/random/junk,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iU" = (/obj/item/weapon/material/kitchen/utensil/fork,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iV" = (/obj/machinery/vending/cola,/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"iW" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"iX" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"iY" = (/obj/machinery/door/airlock{name = "Scene"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"iZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"ja" = (/obj/item/clothing/shoes/brown,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"jb" = (/obj/item/clothing/under/bluepyjamas,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"jc" = (/obj/effect/decal/cleanable/generic,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"jd" = (/obj/machinery/light,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"je" = (/obj/machinery/door/airlock{name = "Maintenance"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/dorms) +"jf" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/wall,/area/slavers_base/dorms) +"jg" = (/obj/structure/table/standard,/obj/random/projectile,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jh" = (/obj/structure/table/standard,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"ji" = (/obj/structure/table/standard,/obj/item/trash/plate,/obj/random/snack,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jj" = (/obj/structure/table/standard,/obj/item/weapon/material/kitchen/utensil/fork,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jk" = (/obj/structure/table/standard,/obj/random/smokes,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jl" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/vending/cigarette,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jm" = (/obj/effect/wingrille_spawn/reinforced,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"jn" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"jo" = (/obj/machinery/door/airlock{name = "Private office"},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"jp" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/dorms) +"jq" = (/obj/structure/table/standard,/obj/item/device/radio,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/dorms) +"jr" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"js" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jt" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/effect/decal/cleanable/dirt,/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"ju" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"jv" = (/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jw" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jx" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jy" = (/obj/structure/cable/green,/obj/machinery/power/terminal{dir = 4},/turf/simulated/floor/airless/ceiling,/area/slavers_base/dorms) +"jz" = (/obj/structure/cable,/obj/machinery/power/smes/buildable,/turf/simulated/floor/airless/ceiling,/area/slavers_base/dorms) +"jA" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jB" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jC" = (/obj/item/weapon/paper{info = "We made over 200 grands for two last weeks. We should stay low-key for month or so, or we'll get our base discovered by fucking marshalls so shut your whining and relax, I'l l get you three crates of booze and some cargo to play with."; name = "Note"},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jD" = (/obj/random/snack,/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jE" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/slavers_base/dorms) +"jF" = (/obj/machinery/door/airlock{name = "Mess"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"jG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"jH" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"jI" = (/obj/structure/table/standard,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jJ" = (/obj/structure/table/standard,/obj/item/device/megaphone,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jK" = (/obj/structure/table/standard,/obj/item/clothing/mask/smokable/cigarette,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jL" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jM" = (/obj/structure/table/standard,/obj/item/device/healthanalyzer,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jN" = (/obj/structure/table/standard,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jO" = (/obj/structure/table/standard,/obj/item/weapon/pen,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jP" = (/obj/machinery/door/airlock{name = "Restroom"},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/airless,/area/slavers_base/dorms) +"jQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock{name = "Southern hallway"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"jR" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jS" = (/obj/structure/bed/chair{dir = 1},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jT" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jU" = (/obj/structure/bed/chair{dir = 1},/obj/item/weapon/storage/secure/briefcase/money,/obj/random/cash,/obj/random/cash,/obj/random/cash,/obj/random/cash,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jV" = (/obj/structure/bed/chair{dir = 4},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jW" = (/obj/structure/table/standard,/obj/item/clothing/mask/smokable/cigarette/professionals,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"jX" = (/obj/machinery/shower{dir = 4; icon_state = "shower"; pixel_x = 0; pixel_y = 0},/turf/simulated/floor/tiled/white/airless,/area/slavers_base/dorms) +"jY" = (/obj/machinery/door/airlock{name = "Shower"},/turf/simulated/floor/tiled/white/airless,/area/slavers_base/dorms) +"jZ" = (/obj/effect/landmark/corpse/slavers_base/slaver3,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"ka" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"kb" = (/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"kc" = (/obj/effect/landmark/corpse/slavers_base/slaver1,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"kd" = (/obj/machinery/door/airlock{name = "Toilet"},/turf/simulated/floor/tiled/white/airless,/area/slavers_base/dorms) +"ke" = (/obj/structure/toilet{dir = 8},/obj/random/junk,/turf/simulated/floor/tiled/white/airless,/area/slavers_base/dorms) +"kf" = (/turf/simulated/wall,/area/slavers_base/hallway) +"kg" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"kh" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"ki" = (/obj/machinery/door/airlock{name = "Slave trade area"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"kj" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"kk" = (/mob/living/simple_animal/hostile/abolition_extremist,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"kl" = (/obj/effect/decal/cleanable/generic,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"km" = (/obj/machinery/light{dir = 4},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"kn" = (/obj/machinery/light{dir = 8},/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"ko" = (/obj/machinery/light{dir = 4},/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"kp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"kq" = (/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"kr" = (/obj/machinery/door/airlock{name = "Slave trade area"},/turf/simulated/floor/tiled/airless,/area/slavers_base/demo) +"ks" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/power/apc{dir = 2; name = "south bump"; operating = 1; pixel_y = -24},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"kt" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"ku" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled,/area/slavers_base/demo) +"kv" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/glass_extras,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"kw" = (/obj/structure/table/standard,/obj/machinery/chemical_dispenser/bar_alc,/turf/simulated/floor/tiled,/area/slavers_base/demo) +"kx" = (/obj/structure/sink{pixel_y = -20},/obj/structure/mirror{pixel_y = -35},/obj/effect/landmark/corpse/slavers_base/slaver2,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"ky" = (/obj/structure/sink{pixel_y = -20},/obj/structure/mirror{pixel_y = -35},/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"kz" = (/mob/living/simple_animal/hostile/abolition_extremist,/turf/simulated/floor/tiled/white,/area/slavers_base/dorms) +"kA" = (/obj/machinery/door/airlock{name = "Customers entry"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"kB" = (/obj/machinery/door/airlock{name = "Customers entry"},/turf/simulated/floor/tiled/airless,/area/slavers_base/hallway) +"kC" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/effect/decal/cleanable/generic,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kE" = (/obj/machinery/door/airlock{name = "Exchange area"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kF" = (/obj/effect/decal/cleanable/generic,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/decal/cleanable/generic,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kH" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kI" = (/obj/machinery/atmospherics/pipe/simple/visible/universal,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kJ" = (/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kK" = (/obj/machinery/door/airlock{name = "Exchange point"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kL" = (/obj/machinery/atmospherics/binary/pump,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kM" = (/obj/structure/table/standard,/obj/item/device/radio,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kN" = (/obj/structure/table/standard,/obj/random/handgun,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kO" = (/obj/machinery/door/airlock/external,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kP" = (/obj/machinery/door/airlock/external,/obj/machinery/atmospherics/pipe/simple/visible/cyan,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kQ" = (/obj/structure/table/standard,/obj/random/junk,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kR" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kS" = (/obj/machinery/atmospherics/pipe/simple/visible/cyan,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kT" = (/obj/structure/table/standard,/obj/random/loot,/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kU" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1379; id_tag = "solar_port_pump"},/turf/simulated/floor/airless/ceiling,/area/slavers_base/maint) +"kV" = (/obj/machinery/door/airlock/external,/turf/space,/area/slavers_base/maint) +"kW" = (/obj/effect/overmap/sector/slavers_base,/turf/space,/area/space) +"kX" = (/obj/effect/shuttle_landmark/nav_slavers_base/nav5,/turf/space,/area/space) +"kY" = (/obj/effect/shuttle_landmark/nav_slavers_base/nav6,/turf/space,/area/space) +"kZ" = (/obj/effect/landmark/random_gen/asteroid,/turf/space,/area/space) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadaaaaadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadaaaaaaaaadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadaaaaadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadaaaaaaaaaaadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadaaaaaaadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadaaaaaaadadadadadadadadadadaaaaaaaaadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadaaaaaaadadadaaaaaaaaaaaaaaaaaaadaaaaaaaaadadadadadadadaaaaaaadadadadadadadadadadadadaaaaaaaaaaadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadaaaaaaaaadadadadaaaaaaaaaaadaaaaaaaaadaaaaadadadadadadadadadadadadadadadadadadadadadaaaaaaadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadaaaaaaaaaaadadadaaaaaaaaaaadadadadaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadaaaaadadadaaaaaaaaaaadadadadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadaaaaadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadafafafafafafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadafafafafagagafafafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadahahahahahahahahahahahahahahahahahahahagagagagagagafafafafafafafafafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadahajakakalakakakamanakaoapaqarakakasahagagatagagagagagagafafafagafafafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadahajakakajakakananakakakakakakakakauahagatagagatagavagagagagagagawafafafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadahakajakakaxakanakakayakazakakakakaAahagatagagagagagagagagagagagagagafafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadahakakajakakakakakaBaCayakakaCakaDaEahagagavagagagagagagagagawagagagagafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadahakakakaFakaBakaBakayaGaHaIaHakaJaKaLagagagagagagagagagagagagagagagagafadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaNaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMaOaPaPaQaPaPaPaPaPaRaSaSaQaPaPaMaTaUaMaOaQaPaMaOaQaVaMaOaQaRaMaOaQaWaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMaXaPaYaPaPaZaPaPaPaPaPaPbaaPaPaMbbaUaMaVbcbdaMaPbebfaMaPbgaPaMaPbhaWaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadadadadadadadadadadadadadadadadadadadadadaMbiaPaWaRbaaPaRaPaPbaaPaPaPaPaRaMbbaUaMbjbkbjaMbjbkbjaMbjbkbjaMbjblbjaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadaMaPaRbeaPaPaVaPbeaPaRaPaPbeaPaPaMbmbnbobpbqbrbsbrbqbrbsbrbqbrbsbrbqbtaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadaMaPaVaPaPaWaWbuaPaVaPaVbvaPbwaPaMbbbxbybzaUbxaUbAaUbxbBbxaUbxaUbxaUbCaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadaMaPaPaRaPaPaPaPaPaWaPaPaPbDaPbEaMbFbxaMbGbHbGaMbGbHbGaMbGbHbGaMbGbHbGaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadaMaPaPaWaPaPaPaPaPbaaPaPaPaPaPbIaMbbbxaMaWbeaRaMbJbeaVaMaPbeaPaMaVbeaWaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadaMaMaMbKbLbMaMbKbLbMaMbKbLbMaMbNaMbbbxaMaObOaPaMaObPaWaMaObObQaMaObOaRaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadaMbRaUaUbSbqbqbqbTbUbqbqbVbqbqbWbXbYbZaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadaMaMaMbKcabMaMbKcabMaMbKcabMaMcbaMccbxaMcdceaPaMaOaQaPaMaOaQcfaMaOcgchaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMaPaWaPaPaPaPaPaPciaPaPaPaPaRcjaMbbbxaMaPbeaPaMchbeaPaMaPbeaPaMaPbebfaMadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadaaaaadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMaPaZaPaPaPaRaPaPaPaPaPaPaVaPckaMclbxaMbjbkbjaMbjbkbjaMbjbkbjaMbjbkbjaMcmcmcmcmcmcmcmcmcmcmcmcmcmcmcmadadadadadadadadadadadadadaaaaaaaaaaadadadadadadadadadadadadadadadaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMaPaPaPaPaPaVaPaPaWaPchaPaPaRaPaMbmcncocpbqcqbscqbqcqbscqbqcqbscqbqcraMcscscsctcscscscscscscsctcscscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMaPcvbechaPaVaPbeciaPaPaPbeaPaPaMcwbxcxbzaUbxaUbxaUbxaUbxaUbxaUbxaUbCaMcscscscscscscscscscscscscscscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaMbibaaPaPaPaPaPaPaPaPchcybJaPaWaMczcAaMbGcBbGaMbGbHbGaMbGbHbGaMbGbHbGaMcscscCcDcDcDcDcDcDcDcDcDcEcscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadaMaXaWaPaPcvcFaPaRaPaPchaPaPcGaPaMbbbxaMaPbeaPaMaPbechaMaPbeaPaMaPbeaPaMcscscHcscscscscscscscscscIcscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadaMaOaPcJbOaPaPbfaPaPaPaPaPcKcLbvaMbbbxaMaObOcMaMaOcNaWaMaObOcOaMcPcQaVaMcscscHcscscscscscscscscscIcscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadaaaaadadadadadadadadadadadcRcRcRcRcRcRcRcRcRcRcRcScScScScScScScScScScScScScScScScScTcUcVcVcVcVcVcVcVcVcVcVcVcVcVcVcVcVcVcscscHcscscscscscscscscscIcscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadcRcXcXcXcYcZhgcZdbdcdccSdddedfdgdhcSdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdzdxdxdxdAdBdCdDdEdFcVcscscHcscscscscscscscscscIcscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadcRdGdHdIdIdJhgcZcZdKhgcSdLdLdLdLdLcSdMdNdNdOdNdNdPdQdRdSdTdUcVdVdxdxdxdxdWdXdxdYcVdBdBdBdZeacVcscsebecececececececececedcscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadcReeefhghgegcZhghghgdKcSdLehdLeidLcSejekdpelemeneneoepeqerescVeteuevewdxexdxeyezcVeAdBdBdBeBcVeCeCcscscscscscscscscscscscscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadcReDeEhgeFdGeGeHeIeJeKcSeLeMeMeMeMeNeOePdpdpdpdpeQeReSeqereTcVeUeVeWeXeYeZfafbfccVfdfeffdBfgcVfhfifjfkcscscscscscscsfkcscscuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadcRhghghghgeghghgflfmhgcSfncScScScScScScScScScScScScScScSerfocVcVcVcVcVcVcVcVcVcVcVcVcVcVcVcVcVfpfqcmcmcmcmcmcmcmcmcmcmcmcmcmadadadadadadadadadadadadadadadadadadadaaaaaaadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadcRhghghghgeghghghgfrfsftfufvfvfvfvfvfvfvfvfvfvfvfvfvfvfwfxfyfzfAfBfCfCfDfCfCfCfCfDfCfCfCfEfFfGfHfIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadaaaaadaaaaadadadadadadadadadadadadadadadadadadadadcRfKfKhgfLfMfNhgfOfPfQfRfSfofofTfUfofofofofofUfofofofofVfWfofJfXfYfZfZfZfZfZfZfZfZfZfZfZfZfZfZfZgafJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadaaaaaaaaadadadadadadadadadadadadadadadadadadadadadcRgbgcgdgcgegegdgfggghgigjgigigigigigigigigigigigigigigigkglfJgmfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadaaaaaaaaadadadadadadadadadadadadadadadadadadadadcRgngohghggphghghggqgrgigsgigtgugvgwgxgygzgAgvgBgCgDgEgigFgGfJgHgIgIgIgJgIgIgIgIgKgIgIgIgIgJgIgIgIfJgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadaaaaadadadadadadadadadadadadadadadadadadadadcRgLgogohghgeFhghggqgMgigsgigtgtgtgNgtgtgtgtgtgtgtgtgtgierfofJgOgPgQgRgRgRgRgRgRgRgRgSgRgRgRgRgRgRgTgUgVfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadcRgWhghghghghghgeFgqgXgigYgigZgtgtgtgthagtgtgNgtgNgtgtgihbfofJhcgIhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhehffJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadcRgWhghghghghhhghggqhigigsgihjhkhlhmhngDgzhogDhpgAgyhqgierfofJgHgIhdhrhshrhrhthdhuhvhdhwhwhxhwhwhwhdgIhyfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadcRhzhghghghAhghghghBhCgigsgihDgigigigigigigigigigigigigierfofJhEhFhGhHhHhHhIhHhJhKhLhMhwhNhOhPhQhwhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadcRhghghghghghghghghghRgihShThUhThVhWhXhXhYhZiaibibicicgieridfJgHgIhdieifigigihhdiihwhdhwhNijikhQhwhdhygIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadcRiliminioipiqirisiritgiiuiciviciciwicicicicicicicicicgierfofJgHgIhdhdhdhdhdhdhdhdhdhdhwhNiyizhQhwhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadcRcRcRcRcRcRcRcRcRcRcRgiiAiciciciviBiCiCiCiDiciciEicixgihbiGfJiHgIhdiIiJiIiKiIiIiLiIhdhwhwhwhwhwhwhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgiiuiMiNiNiNiOiPiQiRiSiNiTiNiUiVgierfofJiWiXiYiZjajbiIiIiIiIiIhdhwjcjdhwhwhwhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgijejfgiicicjgjhjijjjkicivicivjlgierfohdhdhdhdjmjnjnjnjnjnjnjnhdhdhdhdhdhdjohdgIhffJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgijpjqgiicicjrjrjrjrjricicicicjsgijtjuhdjvjvjwjxjvjvjvjvjvjvjvjwjvjvjvjvjvjvhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgijyjzgijAjBicicicicicjBjCicjDjEjFjGjHhdjvjvjvjIjJjKjLjMjLjNjOjvjvjvjvjvjvjvhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgigigigijPgigigigigigigigigigigigijQglhdjRjvjvjSjTjTjTjTjTjTjUjvjvjVjWjLjNjvhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgijXjYjZkakbkckdkegiadadadadadadkfkgkhkikjjvjvjxkkjvkljvjvjvjvjvjvjVjNjvjvkmhdgIhyfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgigigiknkbkbkogigigiadadadadadadkfkpkqkrksktktkujvjvjvjvjvjvjvjvjvjVjLjvkvkwhdgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgijXjYkbkxkykzkdkegiadadadfJfJfJfJkAkBhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdhdgIhffJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadgigigigigigigigigigiadadadfJgIkCfCkDgIkEgIgJgIkEgIkFgIgIgIgJhygIkFkFgIgKgIgIgIgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadfJgIkGgIgIgIkEgIgIgIkEgIgIkFgIkFgIgIgIgIhygIgIgIgIgIgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadfJkHkIfJfJfJfJkJkJkJfJkKfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadfJgIkLfJadadfJkMkNgIgIgIfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadfJkOkPfJadadfJkQkRhffJfJfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadfJkHkSfJadadfJkTgIkFfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadfJgIkUfJadadfJfJfJfJfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadfJkVkVfJadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadaaaaaaaaadadadaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadagagadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadadadadagagadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadagagadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadagagadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadaaaaadadadadadadadadadadadadadagagadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadadadadadadadadadadadadadadaaaaadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadagagadadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadadadadadadadadadadadadadadaaaaadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadaakWadadadadadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadadaaaaadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadaaaaaaaaaaaaaaadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadadadadadaaaaaaadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadaaaaaaaaaaaaaaaaadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadadadadadadadadadaaaaaaaaaaadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadaaaaadadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadadadadadadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +kZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/away/slavers/slavers_base_areas.dm b/maps/away/slavers/slavers_base_areas.dm new file mode 100644 index 00000000..4a741f6f --- /dev/null +++ b/maps/away/slavers/slavers_base_areas.dm @@ -0,0 +1,42 @@ +/area/slavers_base + icon = 'maps/away/slavers/slavers_base_sprites.dmi' + +/area/slavers_base/maint + name = "\improper Slavers Base Maintenance" + icon_state = "maint" + +/area/slavers_base/dorms + name = "\improper Slavers Dorms" + icon_state = "dorms" + +/area/slavers_base/secwing + name = "\improper Slavers Base Security Wing" + icon_state = "secwing" + +/area/slavers_base/mort + name = "\improper Slaves Mortuary" + icon_state = "mort" + +/area/slavers_base/cells + name = "\improper Slaves Cells" + icon_state = "cells" + +/area/slavers_base/hallway + name = "\improper Slavers Base Hallways" + icon_state = "hallway" + +/area/slavers_base/med + name = "\improper Slaves Medical Examination Room" + icon_state = "med" + +/area/slavers_base/demo + name = "\improper Slaves Demonstration room" + icon_state = "demo" + +/area/slavers_base/powatm + name = "\improper Slavers Base power and atmos room" + icon_state = "powatm" + +/area/slavers_base/hangar + name = "\improper Slavers Base Hangar" + icon_state = "hangar" \ No newline at end of file diff --git a/maps/away/slavers/slavers_base_sprites.dmi b/maps/away/slavers/slavers_base_sprites.dmi new file mode 100644 index 00000000..52730d0c Binary files /dev/null and b/maps/away/slavers/slavers_base_sprites.dmi differ diff --git a/maps/away/smugglers/smugglers.dm b/maps/away/smugglers/smugglers.dm new file mode 100644 index 00000000..9fbbb923 --- /dev/null +++ b/maps/away/smugglers/smugglers.dm @@ -0,0 +1,130 @@ +#include "smugglers_areas.dm" +#include "../mining/mining_areas.dm" + +/obj/effect/overmap/sector/smugglers + name = "asteroid station" + desc = "A small station built into an asteroid. No radio traffic detected." + icon_state = "object" + known = 0 + + generic_waypoints = list( + "nav_smugglers", + "nav_smugglers_antag" + ) + +/datum/map_template/ruin/away_site/smugglers + name = "Smugglers' Base" + id = "awaysite_smugglers" + description = "Yarr." + suffixes = list("smugglers/smugglers.dmm") + cost = 1 + +/obj/effect/shuttle_landmark/nav_asteroid_base/nav1 + name = "Abandoned Asteroid Base Navpoint #1" + landmark_tag = "nav_smugglers" + +/obj/effect/shuttle_landmark/nav_asteroid_base/nav2 + name = "Abandoned Asteroid Base Navpoint #2" + landmark_tag = "nav_smugglers_antag" + autoset = 1 + +/obj/item/weapon/paper/smug_1 + name = "suspicios note" + info = "This one goes to Nyx, Tranist station 3, dock 14. Ask Dr. Jensen.
            Ask no less than 4000 credits!" + +/obj/item/weapon/paper/smug_2 + name = "suspicious note" + info = "That vox fuckface will be curious about what we got from that mine storage last week." + +/obj/item/weapon/paper/smug_3 + name = "suspicious note" + info = "If I catch any of you stupid asses smoking near canisters again, you'll end up near Tony behind that rocky wall!" + +/obj/item/weapon/paper/smug_4 + name = "suspicious note" + info = "\[*] Special order +3000 th.\[*] Some handguns, used +800 th.\[*] Another uranium delivery +2450 th.\[*] Two human hearts in freezer +1000 th. for each (Make it 1500, shit is gross)\[*] Some food and pills -340 th." + +/obj/item/weapon/paper/smug_5 + name = "suspicious note" + info = "Jacky, he keeps holding our shares. I'll get fucker down when we'll be back from next flight. Tony" + +/obj/structure/closet/smuggler + name = "suspicious locker" + desc = "Rusty, greasy old locker, smelling of cigarettes and cheap alcohol." + +/obj/structure/closet/smuggler/WillContain() + return list( + /obj/random/ammo, + /obj/random/contraband, + /obj/random/contraband, + /obj/random/drinkbottle, + /obj/random/drinkbottle, + /obj/random/cash, + /obj/random/cash, + /obj/random/cash, + /obj/random/smokes, + new /datum/atom_creator/simple(/obj/item/weapon/reagent_containers/syringe, 50), + new /datum/atom_creator/simple(/obj/item/weapon/reagent_containers/syringe/steroid, 10), + new /datum/atom_creator/simple(/obj/item/weapon/reagent_containers/syringe/steroid, 10), + new /datum/atom_creator/weighted(list(/obj/item/weapon/reagent_containers/food/drinks/cans/cola, /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle, /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb)), + new /datum/atom_creator/simple(/obj/item/clothing/glasses/eyepatch, 30), + new /datum/atom_creator/simple(/obj/item/clothing/gloves/duty, 80), + new /datum/atom_creator/simple(/obj/item/clothing/mask/balaclava/tactical, 30)) + +/obj/random/ore + name = "random ore" + desc = "This is a random ore." + icon = 'icons/obj/clothing/ties.dmi' + icon_state = "horribletie" + +/obj/random/ore_smug/spawn_choices() + return list( + /obj/item/weapon/ore/uranium, + /obj/item/weapon/ore/gold, + /obj/item/weapon/ore/silver, + /obj/item/weapon/ore/slag, + /obj/item/weapon/ore/phoron) + +/obj/random/ammo_magazine_smug + name = "Random Ammo Magazine" + desc = "This is smuggler's random ammo magazine." + icon = 'icons/obj/ammo.dmi' + icon_state = "45-10" + +/obj/random/ammo_magazine_smug/spawn_choices() + return list( + /obj/item/ammo_magazine/a10mm, + /obj/item/ammo_magazine/a357, + /obj/item/ammo_magazine/c45m, + /obj/item/ammo_magazine/c556, + /obj/item/ammo_magazine/a762) + +/obj/structure/closet/crate/plastic_smug_ammo + name = "dirty plastic crate" + desc = "Dirty and scrtached plastic crate." + icon_state = "plasticcrate" + icon_opened = "plasticcrateopen" + icon_closed = "plasticcrate" + +/obj/structure/closet/crate/plastic_smug_ammo/WillContain() + return list( + /obj/random/ammo_magazine_smug, + /obj/random/ammo_magazine_smug, + /obj/random/ammo_magazine_smug, + /obj/random/ammo_magazine_smug, + /obj/random/ammo_magazine_smug) + +/obj/structure/closet/crate/plastic_smug_weapons + name = "dirty plastic crate" + desc = "Dirty and scrtached plastic crate." + icon_state = "plasticcrate" + icon_opened = "plasticcrateopen" + icon_closed = "plasticcrate" + +/obj/structure/closet/crate/plastic_smug_weapons/WillContain() + return list( + /obj/random/handgun, + /obj/random/handgun, + /obj/random/handgun, + /obj/random/projectile, + /obj/random/projectile) \ No newline at end of file diff --git a/maps/away/smugglers/smugglers.dmm b/maps/away/smugglers/smugglers.dmm new file mode 100644 index 00000000..d820491b --- /dev/null +++ b/maps/away/smugglers/smugglers.dmm @@ -0,0 +1,238 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"ac" = (/turf/unsimulated/mask,/area/mine/unexplored) +"ad" = (/obj/random/shoes,/turf/space,/area/space) +"ae" = (/obj/effect/overmap/sector/smugglers,/turf/space,/area/space) +"af" = (/turf/simulated/wall/r_wall,/area/smugglers/base) +"ag" = (/obj/machinery/door/airlock/external{frequency = 1503; icon_state = "door_closed"; locked = 0},/turf/simulated/floor,/area/smugglers/base) +"ah" = (/turf/simulated/floor/dirty/indestructable/lightless,/area/space) +"ai" = (/obj/effect/decal/cleanable/blood,/obj/effect/landmark/corpse/doctor,/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"aj" = (/obj/item/ammo_casing/a50{pixel_x = 5; pixel_y = 5},/obj/item/ammo_casing/a50,/obj/item/weapon/shovel{pixel_x = 10; pixel_y = -5},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"ak" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"al" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/turf/simulated/wall/r_wall,/area/smugglers/base) +"am" = (/obj/machinery/airlock_sensor{frequency = 1503; master_tag = "asteroid_base_dock_airlock"; pixel_x = 25},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 2; frequency = 1503; id_tag = "asteroid_base_dock_pump"},/obj/effect/floor_decal/industrial/warning/full,/obj/item/weapon/beartrap{anchored = 1; deployed = 1; icon_state = "beartrap1"},/turf/simulated/floor,/area/smugglers/base) +"an" = (/turf/unsimulated/mask,/area/mine/explored) +"ao" = (/turf/space,/area/mine/unexplored) +"ap" = (/obj/machinery/atmospherics/unary/outlet_injector{injecting = 1; use_power = 1},/turf/simulated/floor/airless,/area/space) +"aq" = (/obj/machinery/door/airlock/external{frequency = 1503; icon_state = "door_closed"; locked = 0; name = "Internal Airlock"},/turf/simulated/floor,/area/smugglers/base) +"ar" = (/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 1},/obj/structure/grille,/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/airless,/area/smugglers/base) +"as" = (/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 1},/obj/structure/grille,/obj/machinery/door/blast/regular,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/airless,/area/smugglers/base) +"at" = (/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 1},/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/machinery/door/blast/regular,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/airless,/area/smugglers/base) +"au" = (/obj/item/device/flashlight/glowstick/yellow{pixel_x = 5; pixel_y = 7},/obj/item/device/flashlight/glowstick/yellow,/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"av" = (/obj/effect/decal/cleanable/blood/drip,/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1503; id_tag = "asteroid_base_dock_airlock"; name = "Dock Airlock Controller"; pixel_x = -25; tag_airpump = "asteroid_base_dock_pump"; tag_exterior_door = "asteroid_base_dock_outer"; tag_interior_door = "asteroid_base_dock_inner"},/obj/machinery/access_button{command = "cycle_interior"; frequency = 1503; master_tag = "asteroid_base_dock_airlock"; name = "interior access button"; pixel_x = 28; pixel_y = 24; req_one_access = list(13)},/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 5},/turf/simulated/floor,/area/smugglers/base) +"aw" = (/obj/machinery/portable_atmospherics/canister/air,/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"ax" = (/obj/machinery/floodlight,/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"ay" = (/obj/item/stack/cable_coil{pixel_x = 5; pixel_y = 5; pixel_z = 0},/obj/item/stack/cable_coil,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor,/area/smugglers/base) +"az" = (/obj/machinery/power/port_gen/pacman,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"aA" = (/obj/item/stack/material/phoron{pixel_y = 7; pixel_z = -8},/obj/item/stack/material/phoron{pixel_x = -5; pixel_y = 5},/obj/item/stack/material/phoron,/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"aB" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/powered/scrubber,/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor,/area/smugglers/base) +"aC" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor,/area/smugglers/base) +"aD" = (/obj/machinery/atmospherics/pipe/manifold/visible/black{icon_state = "map"; dir = 1},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor,/area/smugglers/base) +"aE" = (/obj/machinery/door/airlock/maintenance,/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"aF" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"aG" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"aH" = (/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1501; id_tag = "asteroid_base_east_airlock"; pixel_y = 25; tag_airpump = "asteroid_base_east_pump"; tag_exterior_door = "asteroid_base_east_outer"; tag_exterior_sensor = null; tag_interior_door = "asteroid_base_east_inner"; tag_interior_sensor = null},/obj/machinery/access_button{command = "cycle_interior"; frequency = 1501; master_tag = "asteroid_base_east_airlock"; name = "interior access button"; pixel_x = -28; pixel_y = 24; req_one_access = list(13)},/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"aI" = (/obj/machinery/door/airlock/external{frequency = 1501; icon_state = "door_locked"; id_tag = "asteroid_base_east_inner"; locked = 1; name = "Internal Airlock"},/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"aJ" = (/obj/item/weapon/beartrap{anchored = 1; deployed = 1; icon_state = "beartrap1"},/obj/machinery/airlock_sensor{frequency = 1501; master_tag = "asteroid_base_east_airlock"; pixel_y = -25},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1501; id_tag = "asteroid_base_east_pump"},/obj/effect/floor_decal/industrial/warning/full,/turf/simulated/floor,/area/smugglers/base) +"aK" = (/obj/machinery/door/airlock/external{frequency = 1501; icon_state = "door_locked"; id_tag = "asteroid_base_east_outer"; locked = 1},/turf/simulated/floor,/area/smugglers/base) +"aL" = (/obj/machinery/access_button/airlock_exterior{frequency = 1501; master_tag = "asteroid_base_east_airlock"; name = "exterior access button"; pixel_x = -25; pixel_y = 25},/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"aM" = (/obj/random/trash,/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"aN" = (/obj/machinery/light/small{dir = 8},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor,/area/smugglers/base) +"aO" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor,/area/smugglers/base) +"aP" = (/obj/effect/decal/cleanable/blood/drip,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/item/weapon/wirecutters,/turf/simulated/floor,/area/smugglers/base) +"aQ" = (/obj/structure/cable,/obj/structure/cable{d1 = 32; d2 = 4; icon_state = "32-4"},/obj/structure/cable{icon_state = "0-2"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor,/area/smugglers/base) +"aR" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor,/area/smugglers/base) +"aS" = (/obj/effect/decal/cleanable/blood/drip,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor,/area/smugglers/base) +"aT" = (/obj/machinery/light/small{dir = 4; pixel_y = 8},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/visible/black,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor,/area/smugglers/base) +"aU" = (/turf/simulated/wall,/area/smugglers/base) +"aV" = (/obj/machinery/light/small/red{dir = 8},/turf/simulated/floor,/area/smugglers/base) +"aW" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor,/area/smugglers/base) +"aX" = (/obj/structure/table/rack{dir = 8; layer = 2.9},/obj/item/clothing/mask/breath,/turf/simulated/floor,/area/smugglers/base) +"aY" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor,/area/smugglers/base) +"aZ" = (/obj/random/trash,/turf/simulated/floor,/area/smugglers/base) +"ba" = (/obj/structure/closet/crate/plastic_smug_ammo,/obj/effect/floor_decal/industrial/warning{dir = 9},/turf/simulated/floor,/area/smugglers/base) +"bb" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/item/weapon/paper/smug_1,/turf/simulated/floor,/area/smugglers/base) +"bc" = (/obj/random/ore_smug,/obj/effect/floor_decal/industrial/warning{dir = 5},/turf/simulated/floor,/area/smugglers/base) +"bd" = (/turf/simulated/floor,/area/smugglers/base) +"be" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/visible/black,/turf/simulated/floor,/area/smugglers/base) +"bf" = (/obj/structure/table/rack{dir = 8; layer = 2.9},/obj/item/weapon/tank/air{pixel_x = 5},/obj/item/weapon/tank/air,/turf/simulated/floor,/area/smugglers/base) +"bg" = (/obj/item/weapon/pickaxe/hand{pixel_x = -15},/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"bh" = (/obj/effect/floor_decal/industrial/warning{dir = 8},/turf/simulated/floor,/area/smugglers/base) +"bi" = (/obj/structure/closet/crate/plastic_smug_weapons,/turf/simulated/floor,/area/smugglers/base) +"bj" = (/obj/structure/closet/crate/plastic,/obj/random/action_figure,/obj/random/loot,/obj/random/loot,/obj/random/smokes,/obj/random/smokes,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor,/area/smugglers/base) +"bk" = (/obj/machinery/floodlight,/turf/simulated/floor,/area/smugglers/base) +"bl" = (/obj/machinery/portable_atmospherics/canister/oxygen,/obj/machinery/light/small/red,/turf/simulated/floor,/area/smugglers/base) +"bm" = (/obj/structure/table/rack{dir = 8; layer = 2.9},/obj/random/voidsuit,/obj/random/voidhelmet,/turf/simulated/floor,/area/smugglers/base) +"bn" = (/obj/structure/boulder,/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"bo" = (/obj/item/weapon/ore/silver,/obj/item/weapon/ore/silver{pixel_x = 10; pixel_y = -5},/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"bp" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 8},/turf/simulated/floor,/area/smugglers/base) +"bq" = (/obj/item/weapon/paper/smug_2,/turf/simulated/floor,/area/smugglers/base) +"br" = (/obj/structure/ore_box,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/effect/floor_decal/industrial/warning{dir = 8},/turf/simulated/floor,/area/smugglers/base) +"bs" = (/obj/structure/ore_box,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/turf/simulated/floor,/area/smugglers/base) +"bt" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor,/area/smugglers/base) +"bu" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 4; pixel_y = 8},/obj/machinery/atmospherics/pipe/simple/visible/black,/turf/simulated/floor,/area/smugglers/base) +"bv" = (/turf/simulated/wall,/area/smugglers/office) +"bw" = (/turf/simulated/wall/r_wall,/area/smugglers/office) +"bx" = (/obj/item/weapon/ore/slag,/obj/item/weapon/ore/slag{pixel_x = 5; pixel_y = -2},/obj/item/weapon/ore/slag,/turf/simulated/floor,/area/smugglers/base) +"by" = (/obj/structure/ore_box,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/effect/floor_decal/industrial/warning{dir = 8},/turf/simulated/floor,/area/smugglers/base) +"bz" = (/obj/random/ore_smug,/turf/simulated/floor,/area/smugglers/base) +"bA" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/binary/pump{dir = 1},/turf/simulated/floor,/area/smugglers/base) +"bB" = (/obj/machinery/door/airlock/maintenance,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor,/area/smugglers/office) +"bC" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/office) +"bD" = (/obj/structure/table/woodentable,/obj/item/weapon/paper,/obj/item/weapon/pen,/obj/item/device/flashlight/lamp,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/tiled,/area/smugglers/office) +"bE" = (/obj/structure/safe/floor,/obj/random/contraband,/obj/random/contraband,/obj/random/loot,/obj/random/projectile,/obj/random/cash,/obj/random/cash,/obj/random/cash,/turf/simulated/floor/tiled,/area/smugglers/office) +"bF" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor,/area/smugglers/base) +"bG" = (/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor,/area/smugglers/base) +"bH" = (/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor,/area/smugglers/base) +"bI" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor,/area/smugglers/base) +"bJ" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/office) +"bK" = (/obj/structure/table/woodentable,/obj/random/coin{pixel_x = -5; pixel_y = -3},/obj/random/coin,/obj/item/weapon/storage/bible/booze{pixel_x = 10},/obj/item/weapon/paper/smug_4{pixel_x = -5; pixel_y = 4},/obj/item/weapon/paper/smug_5,/turf/simulated/floor/tiled,/area/smugglers/office) +"bL" = (/obj/structure/bed/chair/comfy/red{dir = 8},/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/smugglers/office) +"bM" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor,/area/smugglers/base) +"bN" = (/obj/machinery/atmospherics/portables_connector,/obj/machinery/portable_atmospherics/powered/scrubber,/turf/simulated/floor,/area/smugglers/base) +"bO" = (/obj/machinery/portable_atmospherics/canister/air,/obj/item/weapon/wrench,/obj/machinery/light/small{dir = 4; pixel_y = 8},/turf/simulated/floor,/area/smugglers/base) +"bP" = (/mob/living/simple_animal/hostile/retaliate/malf_drone,/turf/simulated/floor/tiled,/area/smugglers/office) +"bQ" = (/turf/simulated/floor/tiled,/area/smugglers/office) +"bR" = (/obj/structure/table/standard,/obj/random/tech_supply,/turf/simulated/floor,/area/smugglers/base) +"bS" = (/obj/structure/table/standard,/obj/random/toolbox,/turf/simulated/floor,/area/smugglers/base) +"bT" = (/obj/structure/table/standard,/obj/random/firstaid,/turf/simulated/floor,/area/smugglers/base) +"bU" = (/obj/structure/closet/crate/trashcart,/turf/simulated/floor,/area/smugglers/base) +"bV" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor,/area/smugglers/base) +"bW" = (/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor,/area/smugglers/base) +"bX" = (/obj/machinery/constructable_frame/machine_frame,/obj/random/trash,/turf/simulated/floor/tiled,/area/smugglers/office) +"bY" = (/obj/structure/table/rack,/obj/item/clothing/head/cowboy_hat,/obj/item/clothing/suit/armor/hos/jensen,/turf/simulated/floor/tiled,/area/smugglers/office) +"bZ" = (/obj/structure/filingcabinet/chestdrawer,/turf/simulated/floor/tiled,/area/smugglers/office) +"ca" = (/turf/simulated/wall/r_wall,/area/smugglers/dorms) +"cb" = (/obj/machinery/door/airlock/maintenance{name = "Restroom"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor,/area/smugglers/dorms) +"cc" = (/turf/simulated/wall,/area/smugglers/dorms) +"cd" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/smugglers/dorms) +"ce" = (/obj/structure/noticeboard{pixel_y = 30},/obj/effect/decal/cleanable/dirt,/obj/structure/table/standard,/obj/machinery/microwave{pixel_y = 10},/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cf" = (/obj/effect/decal/cleanable/dirt,/obj/structure/closet/crate,/obj/random/snack,/obj/random/snack,/obj/random/snack,/obj/random/snack,/obj/random/snack,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cg" = (/obj/effect/decal/cleanable/dirt,/obj/structure/closet/crate,/obj/random/drinkbottle,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"ch" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/computer/arcade,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"ci" = (/obj/structure/closet/crate/freezer/rations,/obj/effect/decal/cleanable/cobweb2,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cj" = (/obj/effect/decal/cleanable/cobweb,/turf/simulated/floor/airless/ceiling,/area/smugglers/dorms) +"ck" = (/obj/machinery/light/small{dir = 4},/obj/structure/sink{pixel_y = 15},/obj/structure/mirror{pixel_y = 30},/obj/random/soap,/turf/simulated/floor/airless/ceiling,/area/smugglers/dorms) +"cl" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/structure/cable,/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cm" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cn" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"co" = (/obj/machinery/door/airlock/maintenance{name = "Toilet"},/turf/simulated/floor,/area/smugglers/dorms) +"cp" = (/obj/effect/decal/cleanable/vomit,/obj/random/medical/lite,/turf/simulated/floor/airless/ceiling,/area/smugglers/dorms) +"cq" = (/obj/structure/toilet{dir = 8},/turf/simulated/floor/airless/ceiling,/area/smugglers/dorms) +"cr" = (/obj/structure/bed/chair{dir = 4},/obj/machinery/light,/obj/random/trash,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cs" = (/obj/structure/table/standard,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/paper/smug_3,/obj/item/weapon/flame/lighter/random,/obj/random/coin,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"ct" = (/obj/structure/table/standard,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/spacecash/bundle/c10,/obj/random/smokes,/obj/random/snack,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cu" = (/obj/structure/bed/chair{dir = 8},/obj/machinery/light,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cv" = (/obj/structure/closet,/obj/effect/decal/cleanable/dirt,/obj/random/medical,/obj/random/medical,/obj/random/tech_supply,/obj/random/action_figure,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cw" = (/obj/machinery/door/airlock/maintenance,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cx" = (/obj/structure/bed,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cy" = (/obj/structure/closet/smuggler,/obj/random/suit,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cz" = (/obj/structure/bed,/obj/effect/decal/cleanable/dirt,/mob/living/simple_animal/hostile/retaliate/malf_drone,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cA" = (/obj/effect/decal/cleanable/dirt,/obj/random/trash,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cB" = (/obj/machinery/light/small{dir = 2},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cC" = (/obj/effect/shuttle_landmark/nav_asteroid_base/nav2,/turf/space,/area/space) +"cD" = (/obj/effect/landmark/random_gen/asteroid{generation_height = 50; generation_width = 50},/turf/space,/area/space) +"cE" = (/obj/effect/shuttle_landmark/nav_asteroid_base/nav1,/turf/space,/area/space) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaababacaaaaaaaaaaacaaababacaaaaaaacacaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacaaaaaaaaaaaaaaaaaaaaaaaaabababababacacaaaaaaacacacabacaaadaaacacaaacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababacaaaaaaaeaaaaaaaaaaaaaaaaaaabacacababababaaaaaaacacacabaaaaaaaaacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacababaaaaafagafaaaaahaaaaaaaaaaabacacababaaabaaaaaaacacaiajakakaaaaacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacabababalamafaaahanaoapaaaaaaacacacabababacacacacacacabacacabababababacacababacababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacababacafaqafafafafafarasatafafafafafafafauacacacacabacacacabababababacababacacacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababafavawaxayazaAaBaCaDaEaFaGaHaIaJaKaLababacacabacababaMabababababababacacacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababacacafaNaOaPaQaQaOaRaSaTaUaVaWaXafafafacabababababababababacabababababacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacacafaYaZbabbbcbdbdaZbeaUaZbdbfafacacacacacacacbgababacacababababacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacacacafaYbdbhbibjbdbdbdbeaUbkblbmafacacacacacacacbnboabacacabacacacabacacacacacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacacacafbpbqbrbsbtbdaZbdbubvbvbvbvbwacacacacacacacacacacacacababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababacacacafaYbxbybzbtbdbdbdbAbBbCbDbEbwacacacacacacacacacacacacacacacaMababacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacabacacacafaYaZbFbGbHbdbdbdbIbvbJbKbLbwabacacacacacacacacacacacacacacacabacababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacababacacafbpbdbdbdbdbMbNbdbObvbJbPbQbwacacacacacacacacacacababacacacacabacabacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacabafaYaZbRbSbTbUbVbdbWbvbXbYbZbwacabababababacacacacabacacacacacacabababaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacabcacbcccccccccccccccccabwbwbwbwacabababababacacacacababacacacacabacacabaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaccacdcecfcgchcicccjckcaacacacacacacacabacacacacacacabababacacacaMabababacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacaccaclcmcmcmcmcncocpcqcaababababababacanacacacacacacacabababacacabacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababacaccacmcrcsctcucvcccacacaacacacabababacababacacacacabacacacacacacabacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacaccacwcccccccccccccaabacacacacabababababaMabacacababacacacacacababacacababababacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacaccacmcxcyczcycxcycaabacacacacacacababacacababababacacacababababacacacabababacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaababaccacAcBcmcmcmcBcmcaacacacabababababacacacababacababacacaMacacacacacacabababacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaccacacacacacacacacaacabababababacacacacacabacacacababababacacacaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacababacacacacacabababaMacacacabacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacacabacacacacacacacacacaMabacabacacacaaaaacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacabacacacacababababaMabababababacacacaaaaacacacacabacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababacabacacababababababababababababababacaaaaacacacacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababacabababababababababababababababacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababacababababababababababababababababacacababacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababacacacabababababababababababababababacacababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababacacababababababababababababababababacacacacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaabababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacabababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacabababababababababababababababacacabacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacacacacababababababababababababababacacabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacacacacacabababababababababababababababacacacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacabacacacababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacacacacacacacacabababababababababacabababacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacacacaaaaaaaaacacacacababacacabababacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacacacacacaaaaaaaaaaaaacabababababacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacacacabaaaaaaaaaaaaaaaaaaaaaaaaacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacEaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/away/smugglers/smugglers_areas.dm b/maps/away/smugglers/smugglers_areas.dm new file mode 100644 index 00000000..4736cb8a --- /dev/null +++ b/maps/away/smugglers/smugglers_areas.dm @@ -0,0 +1,14 @@ +/area/smugglers/base + name = "\improper Asteroid Base" + icon_state = "smgl_base" + icon = 'smugglers_sprites.dmi' + +/area/smugglers/office + name = "\improper Asteroid Base Office" + icon_state = "smgl_office" + icon = 'smugglers_sprites.dmi' + +/area/smugglers/dorms + name = "\improper Asteroid Base Rest Area" + icon_state = "smgl_dorms" + icon = 'smugglers_sprites.dmi' \ No newline at end of file diff --git a/maps/away/smugglers/smugglers_sprites.dmi b/maps/away/smugglers/smugglers_sprites.dmi new file mode 100644 index 00000000..e34e2e45 Binary files /dev/null and b/maps/away/smugglers/smugglers_sprites.dmi differ diff --git a/maps/away/yacht/backup/yacht.dmm b/maps/away/yacht/backup/yacht.dmm new file mode 100644 index 00000000..b10a4981 --- /dev/null +++ b/maps/away/yacht/backup/yacht.dmm @@ -0,0 +1,294 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/obj/effect/overmap/ship/yacht,/turf/space,/area/space) +"ac" = (/obj/effect/wingrille_spawn/reinforced/full,/turf/simulated/floor/plating,/area/yacht/bridge) +"ad" = (/obj/machinery/shipsensors,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/yacht/bridge) +"ae" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"af" = (/obj/effect/shuttle_landmark/nav_yacht/nav2,/turf/space,/area/space) +"ag" = (/obj/effect/shuttle_landmark/nav_yacht/nav1,/turf/space,/area/space) +"ah" = (/turf/simulated/wall/titanium,/area/yacht/bridge) +"ai" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/computer/helm,/turf/simulated/floor/wood,/area/yacht/bridge) +"aj" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/computer/sensors,/turf/simulated/floor/wood,/area/yacht/bridge) +"ak" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/structure/bed/chair/comfy/captain,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"al" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/computer/engines,/turf/simulated/floor/wood,/area/yacht/bridge) +"am" = (/obj/item/weapon/folder/blue,/obj/item/weapon/form_printer,/obj/structure/table/woodentable,/obj/item/weapon/reagent_containers/food/drinks/coffeecup,/obj/item/weapon/newspaper,/obj/effect/spider/stickyweb,/obj/effect/decal/cleanable/dirt,/obj/random/energy,/obj/item/weapon/paper{info = "I used up all of my energy. I am hopelessly lost. This ship has become my grave. They did it. The intelligence agency that no one ever talks about. Sol Gov wanted their revenge, and they got it. They easily could have killed me on my ship, or tortured me, but they knew that floating here through space would be the worst possible torture. "},/turf/simulated/floor/wood,/area/yacht/bridge) +"an" = (/obj/machinery/atmospherics/unary/vent_pump/on,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/mob/living/simple_animal/hostile/giant_spider/hunter,/turf/simulated/floor/wood,/area/yacht/bridge) +"ao" = (/obj/effect/decal/cleanable/dirt,/obj/random/maintenance/clean,/turf/simulated/floor/wood,/area/yacht/bridge) +"ap" = (/obj/structure/filingcabinet/chestdrawer,/obj/effect/decal/cleanable/cobweb2,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"aq" = (/obj/machinery/light{dir = 8},/obj/structure/safe,/obj/item/weapon/reagent_containers/pill/cyanide,/obj/item/weapon/rig/medical/equipped,/obj/item/weapon/gun/energy/captain,/obj/effect/spider/stickyweb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"ar" = (/obj/machinery/alarm{dir = 1; icon_state = "alarm0"; pixel_y = -22},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"as" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"at" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 2; name = "Yacht bridge"; pixel_x = 0; pixel_y = -24},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"au" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/structure/reagent_dispensers/water_cooler,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"av" = (/turf/simulated/wall/wood,/area/yacht/living) +"aw" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock/silver,/turf/simulated/floor/plating,/area/yacht/bridge) +"ax" = (/turf/simulated/wall/wood,/area/yacht/bridge) +"ay" = (/obj/structure/disposalpipe/trunk{dir = 4},/obj/machinery/disposal,/turf/simulated/floor/plating,/area/yacht/living) +"az" = (/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/wall/titanium,/area/yacht/living) +"aA" = (/obj/structure/disposalpipe/trunk{dir = 8},/obj/structure/disposaloutlet{dir = 4},/turf/space,/area/space) +"aB" = (/turf/simulated/wall/titanium,/area/yacht/living) +"aC" = (/obj/machinery/light/small{dir = 8},/obj/structure/mirror{pixel_y = 28},/obj/structure/sink{pixel_y = 20},/obj/item/weapon/bikehorn/rubberducky,/obj/effect/decal/cleanable/dirt,/obj/random/soap,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"aD" = (/obj/machinery/shower{pixel_y = 20},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"aE" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aF" = (/obj/structure/bed/chair/wood/wings{dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aG" = (/obj/machinery/light{dir = 1},/obj/structure/table/marble,/obj/item/trash/snack_bowl,/obj/machinery/reagentgrinder,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/paper{info = "Tonight I woke up to a sound I hoped to have never heard, a small explosion. I rushed to the bridge to diagnose the damage and saw the worst possible news. My solar tracker is gone, and so is the fucking computer. No way to override the settings now, because the assholes EMPd the computer. No way to charge my SMES reliably, and no way to heat the fuel. I am stuck in the water! Unheated, this gas will not be enough to get absolutely anywhere near a port. This is bad. Real bad. The current charge on SMES is 20 percent, so I'll just try and orient the ship to hit the current star at maximum efficiency so we will charge at 100, and maybe make it to the next solar system. The next port is in the orbit of a Gas giant named Duma. Maybe I can dock there and repair my array. I freaking knew I needed to get a generator. I spent all of the money the Terrans gave me, and this piece of shit is all I could get. "},/turf/simulated/floor/wood,/area/yacht/living) +"aH" = (/obj/effect/decal/cleanable/cobweb2,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aI" = (/obj/item/weapon/towel/random,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"aJ" = (/obj/structure/toilet{dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"aK" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/light{dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aL" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aM" = (/obj/structure/table/marble,/obj/item/pizzabox/vegetable,/obj/item/weapon/reagent_containers/glass/rag,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aN" = (/obj/effect/decal/cleanable/dirt,/obj/random/junk,/turf/simulated/floor/wood,/area/yacht/living) +"aO" = (/obj/machinery/vending/wallmed1,/turf/simulated/wall/titanium,/area/yacht/living) +"aP" = (/obj/machinery/door/airlock/silver,/turf/simulated/floor/wood,/area/yacht/living) +"aQ" = (/obj/structure/table/marble,/obj/item/weapon/deck/cards,/obj/item/weapon/dice,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aR" = (/obj/effect/decal/cleanable/blood/gibs/robot/up,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aS" = (/obj/structure/table/marble,/obj/machinery/microwave,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aT" = (/obj/effect/decal/cleanable/cobweb,/obj/effect/spider/stickyweb,/turf/simulated/floor/carpet/blue2,/area/yacht/living) +"aU" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/obj/effect/decal/cleanable/blood/drip,/obj/effect/spider/stickyweb,/mob/living/simple_animal/hostile/giant_spider/hunter,/turf/simulated/floor/wood,/area/yacht/living) +"aV" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/decal/cleanable/blood/drip,/obj/effect/spider/stickyweb,/turf/simulated/floor/wood,/area/yacht/living) +"aW" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/closet/walllocker/emerglocker/north,/obj/effect/decal/cleanable/blood/drip,/obj/machinery/door/airlock/silver,/turf/simulated/floor/wood,/area/yacht/living) +"aX" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aY" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aZ" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/table/marble,/obj/item/weapon/book/manual/chef_recipes,/obj/item/weapon/reagent_containers/food/drinks/pitcher,/obj/effect/decal/cleanable/dirt,/obj/random/drinkbottle,/turf/simulated/floor/wood,/area/yacht/living) +"ba" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/effect/decal/cleanable/blood/gibs/robot/down,/obj/effect/decal/cleanable/blood/gibs/robot/up,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bb" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/machinery/vending/dinnerware,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bc" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet/blue,/obj/effect/spider/stickyweb,/turf/simulated/floor/carpet/blue2,/area/yacht/living) +"bd" = (/obj/effect/spider/stickyweb,/turf/simulated/floor/wood,/area/yacht/living) +"bf" = (/obj/effect/decal/cleanable/blood/gibs/robot/limb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bg" = (/obj/structure/closet/secure_closet/freezer/fridge,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bh" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/spider/stickyweb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bi" = (/obj/machinery/smartfridge,/turf/simulated/wall/wood,/area/yacht/living) +"bj" = (/obj/machinery/vending/boozeomat,/turf/simulated/wall/wood,/area/yacht/living) +"bk" = (/obj/effect/wingrille_spawn/reinforced/full,/turf/simulated/floor/plating,/area/yacht/living) +"bl" = (/obj/machinery/light{dir = 8},/obj/effect/spider/stickyweb,/turf/simulated/floor/beach/water,/area/yacht/living) +"bm" = (/obj/effect/spider/stickyweb,/turf/simulated/floor/beach/water,/area/yacht/living) +"bn" = (/obj/effect/spider/stickyweb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"bo" = (/obj/machinery/door/airlock/silver,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"bp" = (/obj/effect/decal/cleanable/dirt,/obj/item/weapon/paper{info = "I have accepted my fate. I will go into EVA with one of the cyanide pills in my mouth, and I will float off. I want a military funeral, and I will arrange it myself. Good bye all. I have earned and sealed my fate. "},/turf/simulated/floor/wood,/area/yacht/living) +"bq" = (/obj/structure/bookcase,/turf/simulated/floor/carpet/purple,/area/yacht/living) +"br" = (/obj/machinery/light/small{dir = 1},/obj/structure/bookcase,/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bs" = (/obj/item/weapon/inflatable_duck,/obj/effect/spider/stickyweb,/turf/simulated/floor/beach/water,/area/yacht/living) +"bt" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bu" = (/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bv" = (/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bw" = (/obj/structure/bed/chair/comfy/red{dir = 4},/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bx" = (/turf/simulated/floor/beach/water,/area/yacht/living) +"by" = (/mob/living/simple_animal/hostile/giant_spider/hunter,/turf/simulated/floor/beach/water,/area/yacht/living) +"bz" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"bA" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/effect/spider/stickyweb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bB" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/spider/stickyweb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bC" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/airlock/silver,/turf/simulated/floor/wood,/area/yacht/living) +"bD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bE" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bF" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/item/weapon/storage/bible,/obj/item/weapon/pen/blue,/obj/structure/table/woodentable,/obj/item/weapon/paper{info = "Let me introduce myself. My name is Commander Archibald McKinley, although the Fleet fucks think that I do not deserve the title. Well, fuck them. They accused me of facilitating a destruction of the ship I was CO of. A small missile cruiser, with zero to fucking none point defenses was attacked, and they first accuse me of escaping before any of my crew. What kind of person wouldn't expect someone to escape when their ship is on fire? It's lunacy. But it only got worse. Then they said that I helped the Terrans take the ship. Well fuck them, they are wrong. That's non sense. I have no connection to the Terrans. They said that I got a large sum of money from them in order to betray my ship's position, which is once again total nonsense. I've got about 20 years of life left here, and I know that I will be safe with my ship here. I need to resupply once every 5 years, given how much food and fuel I have, and I've got enough range to go to pretty much any known part of the galaxy, in complete silence, as we are totally solar powered. I wish I could afford ion thrusters to not have to rely on gas for propulsion, but, our gas heaters should provide us with enough pressure to get anywhere in relative decent speed. Also, I got a robot butler who cooks delicious food for me! No more crappy lance corporal food, eh"},/obj/item/device/flashlight/lamp/green,/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bG" = (/obj/machinery/light{dir = 8},/turf/simulated/floor/beach/water,/area/yacht/living) +"bH" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/beach/water,/area/yacht/living) +"bI" = (/obj/machinery/light,/obj/item/clothing/shoes/swimmingfins,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"bJ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood/gibs/robot/limb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bK" = (/obj/effect/decal/cleanable/blood/gibs/robot/down,/obj/effect/decal/cleanable/dirt,/obj/machinery/floodlight,/turf/simulated/floor/wood,/area/yacht/living) +"bL" = (/obj/machinery/light/small,/obj/structure/filingcabinet,/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bM" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bN" = (/turf/simulated/wall/titanium,/area/yacht/engine) +"bO" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood/gibs/robot/down,/obj/machinery/door/airlock/silver,/turf/simulated/floor/wood,/area/yacht/living) +"bP" = (/turf/simulated/wall/wood,/area/yacht/engine) +"bQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock/hatch,/turf/simulated/floor/plating,/area/yacht/engine) +"bR" = (/obj/machinery/atmospherics/pipe/tank/air,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"bS" = (/obj/structure/dispenser/oxygen,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"bT" = (/obj/item/weapon/cell/hyper,/obj/item/weapon/book/manual/engineering_guide,/obj/item/weapon/rcd,/obj/effect/decal/cleanable/dirt,/obj/machinery/computer/engines,/turf/simulated/floor/plating,/area/yacht/engine) +"bU" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/power/smes/buildable,/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/plating,/area/yacht/engine) +"bV" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/power/apc{dir = 1; name = "Yacht engine"; pixel_x = 0; pixel_y = 24},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"bW" = (/obj/item/weapon/extinguisher,/obj/machinery/portable_atmospherics/hydroponics,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bX" = (/obj/machinery/vending/hydronutrients,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bY" = (/obj/machinery/seed_storage/garden,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bZ" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"ca" = (/obj/structure/closet/secure_closet/freezer/kitchen,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cb" = (/obj/machinery/atmospherics/binary/pump,/obj/machinery/space_heater,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cc" = (/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/obj/machinery/power/solar,/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/yacht/engine) +"ce" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/obj/effect/decal/cleanable/dirt,/obj/item/weapon/circuitboard/broken,/turf/simulated/floor/plating,/area/yacht/engine) +"ch" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/airlock/hatch,/turf/simulated/floor/plating,/area/yacht/engine) +"ci" = (/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cj" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"ck" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cl" = (/obj/structure/janitorialcart,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cm" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/light/small{dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cn" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"co" = (/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{dir = 4},/obj/effect/decal/cleanable/dirt,/obj/machinery/portable_atmospherics/powered/pump,/turf/simulated/floor/plating,/area/yacht/engine) +"cp" = (/obj/structure/cable{icon_state = "0-2"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/obj/effect/decal/cleanable/ash,/obj/effect/decal/cleanable/blood/oil/streak,/obj/effect/decal/cleanable/generic,/obj/effect/decal/cleanable/molten_item,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/yacht/engine) +"cq" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/item/weapon/circuitboard/broken,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/yacht/engine) +"cr" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/item/weapon/storage/toolbox/syndicate,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/yacht/engine) +"cs" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/item/weapon/plastique,/turf/simulated/floor/airless,/area/yacht/engine) +"ct" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/yacht/engine) +"cu" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/yacht/engine) +"cC" = (/obj/structure/cable,/obj/machinery/power/apc{dir = 8; name = "Yacht living"; pixel_x = -24},/obj/machinery/portable_atmospherics/hydroponics,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/decal/cleanable/dirt,/mob/living/bot/farmbot,/turf/simulated/floor/wood,/area/yacht/living) +"cE" = (/obj/effect/spider/stickyweb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cF" = (/obj/structure/reagent_dispensers/watertank,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cH" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/obj/effect/decal/cleanable/dirt,/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/yacht/engine) +"cJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/red{icon_state = "intact"; dir = 4},/turf/simulated/wall/titanium,/area/yacht/engine) +"cK" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 8; use_power = 1},/turf/space,/area/space) +"cL" = (/obj/structure/cable,/obj/machinery/power/solar,/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/yacht/engine) +"cN" = (/obj/structure/closet/toolcloset,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cO" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cQ" = (/obj/machinery/light{dir = 8},/obj/machinery/alarm{dir = 4; pixel_x = -23; pixel_y = 0},/obj/machinery/portable_atmospherics/hydroponics,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cR" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/item/weapon/shovel/spade,/obj/item/weapon/reagent_containers/glass/bucket,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cS" = (/obj/machinery/light,/obj/structure/reagent_dispensers/beerkeg,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cT" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cW" = (/obj/structure/closet/crate/freezer/rations,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cX" = (/obj/structure/closet/crate/hydroponics,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cY" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cZ" = (/obj/machinery/vending/tool,/turf/simulated/floor/plating,/area/yacht/engine) +"da" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/caution/cone,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"db" = (/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/plating,/area/yacht/engine) +"dc" = (/obj/structure/closet/wardrobe/pjs,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"dd" = (/obj/structure/closet/wardrobe/suit,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"de" = (/obj/machinery/light/small{dir = 8},/obj/structure/closet/crate/freezer,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"df" = (/obj/effect/decal/cleanable/dirt,/obj/random/coin,/turf/simulated/floor/plating,/area/yacht/engine) +"dg" = (/obj/structure/closet/secure_closet/freezer/meat,/turf/simulated/floor/plating,/area/yacht/engine) +"dh" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"di" = (/obj/machinery/atmospherics/unary/heater,/turf/simulated/floor/plating,/area/yacht/engine) +"dj" = (/obj/structure/window/reinforced/full,/obj/structure/grille,/turf/simulated/floor/plating,/area/yacht/engine) +"dk" = (/obj/machinery/atmospherics/unary/heater,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dl" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dm" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/structure/closet/secure_closet/freezer/kitchen,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dn" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 6},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"do" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/black,/obj/machinery/light/small{dir = 4; pixel_y = 8},/obj/effect/decal/cleanable/dirt,/obj/machinery/meter,/turf/simulated/floor/plating,/area/yacht/engine) +"dp" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/wall/titanium,/area/yacht/engine) +"dq" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 8; external_pressure_bound = 0; external_pressure_bound_default = 0; frequency = 1439; icon_state = "map_vent_in"; id_tag = null; initialize_directions = 1; internal_pressure_bound = 4000; internal_pressure_bound_default = 4000; pressure_checks = 2; pressure_checks_default = 2; pump_direction = 0; use_power = 1},/turf/simulated/floor/reinforced/carbon_dioxide,/area/yacht/engine) +"dr" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 4; external_pressure_bound = 0; external_pressure_bound_default = 0; frequency = 1439; icon_state = "map_vent_in"; id_tag = null; initialize_directions = 1; internal_pressure_bound = 4000; internal_pressure_bound_default = 4000; pressure_checks = 2; pressure_checks_default = 2; pump_direction = 0; use_power = 1},/turf/simulated/floor/reinforced/carbon_dioxide,/area/yacht/engine) +"ds" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/black,/obj/structure/closet/crate/medical,/obj/effect/decal/cleanable/dirt,/obj/machinery/meter,/turf/simulated/floor/plating,/area/yacht/engine) +"dt" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 10},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"du" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/closet/secure_closet/freezer/meat,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dv" = (/obj/machinery/atmospherics/pipe/simple/visible/black,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dw" = (/obj/machinery/atmospherics/unary/heater{dir = 1},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dx" = (/turf/simulated/floor/reinforced/carbon_dioxide,/area/yacht/engine) +"dy" = (/obj/machinery/light/small{dir = 4; pixel_y = 8},/obj/structure/closet/secure_closet/freezer/meat,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dz" = (/obj/machinery/atmospherics/pipe/manifold/visible/black{dir = 8; icon_state = "map"},/obj/structure/window/reinforced,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dA" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 10},/obj/structure/window/reinforced,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dB" = (/obj/structure/closet/crate/medical,/turf/simulated/floor/plating,/area/yacht/engine) +"dC" = (/obj/machinery/atmospherics/pipe/manifold/visible/black{dir = 8; icon_state = "map"},/obj/structure/window/reinforced,/obj/structure/closet/secure_closet/bar,/turf/simulated/floor/plating,/area/yacht/engine) +"dD" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 10},/obj/structure/window/reinforced,/obj/machinery/recharge_station,/turf/simulated/floor/plating,/area/yacht/engine) +"dE" = (/obj/machinery/atmospherics/unary/engine{dir = 1},/turf/simulated/floor/airless,/area/yacht/engine) +"dF" = (/obj/effect/shuttle_landmark/nav_yacht/nav3,/turf/space,/area/space) +"dG" = (/obj/effect/shuttle_landmark/nav_yacht/nav4,/turf/space,/area/space) +"eb" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/item/weapon/cane,/obj/item/clothing/suit/storage/det_trench/grey,/obj/item/clothing/ring/cti,/obj/item/clothing/under/lawyer/oldman,/obj/structure/table/woodentable,/obj/effect/spider/stickyweb,/obj/random/cash,/obj/random/cash,/obj/random/cash,/obj/random/projectile,/turf/simulated/floor/wood,/area/yacht/living) +"fb" = (/obj/machinery/access_button/airlock_exterior{frequency = 1420; master_tag = "yacht_airlock"; pixel_x = 24},/turf/space,/area/space) +"gb" = (/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/obj/effect/decal/cleanable/dirt,/obj/structure/computerframe,/obj/machinery/access_button/airlock_interior{frequency = 1420; master_tag = "yacht_airlock"; pixel_x = -24},/turf/simulated/floor/plating,/area/yacht/engine) +"hb" = (/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/obj/item/weapon/storage/toolbox/electrical,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/yacht/engine) +"ib" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/plating,/area/yacht/engine) +"jb" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/obj/machinery/door/airlock/external/bolted{frequency = 1420; id_tag = "yacht_outer"},/turf/simulated/floor/airless,/area/yacht/engine) +"kb" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1420; id_tag = "yacht_airlock"; pixel_y = 24; tag_airpump = "yacht_pump"; tag_chamber_sensor = "yacht_sensor"; tag_exterior_door = "yacht_outer"; tag_interior_door = "yacht_inner"},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1420; id_tag = "yacht_pump"},/obj/machinery/airlock_sensor{frequency = 1420; id_tag = "yacht_sensor"; pixel_y = -24},/turf/simulated/floor/airless,/area/yacht/engine) +"lb" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4; icon_state = "intact"},/obj/machinery/door/airlock/external/bolted{frequency = 1420; id_tag = "yacht_inner"},/turf/simulated/floor/plating,/area/yacht/engine) +"mb" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/manifold/hidden{dir = 1; icon_state = "map"},/turf/simulated/floor/plating,/area/yacht/engine) +"nb" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/turf/simulated/floor/plating,/area/yacht/engine) +"ob" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/binary/pump{dir = 8},/turf/simulated/floor/plating,/area/yacht/engine) +"pb" = (/obj/machinery/alarm{alarm_id = "misc_research"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/yacht/engine) +"qb" = (/obj/machinery/atmospherics/binary/pump{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/red{icon_state = "intact"; dir = 4},/obj/effect/decal/cleanable/dirt,/obj/random/closet,/turf/simulated/floor/plating,/area/yacht/engine) +"rb" = (/obj/machinery/atmospherics/pipe/tank/air{dir = 1},/turf/simulated/floor/plating,/area/yacht/engine) +"sb" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/plating,/area/yacht/engine) +"tb" = (/obj/structure/closet/firecloset,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/plating,/area/yacht/engine) +"ub" = (/obj/effect/decal/cleanable/dirt,/obj/random/closet,/turf/simulated/floor/plating,/area/yacht/engine) +"vb" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/item/weapon/storage/firstaid,/obj/effect/decal/cleanable/dirt,/obj/random/closet,/turf/simulated/floor/plating,/area/yacht/engine) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadacaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaaaaaaahacaiacahaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahahajakalahahaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahamaeanaoapahaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahahaqarasatauahahaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahavavavawaxaxayazaAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBaCaDavaEaFaGaHaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBaBaIaJavaKaLaMaNaOaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBavaPavavaEaLaQaRaSaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBaTaUaVaWaXaYaZbabbaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBaBbcbdebavaEaLbfaLbgaBaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBaBavavavavbhaLavbibjaBaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabkblbmbmbnboaEbpavbqbrbqaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabkbmbsbmbnavbhbtavbubvbwbkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabkbmbxbybzavbAbBbCbDbEbFbkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBaBbGbxbHbIavbJbKavbLbMaBaBaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNbNbNbNbNbNavbOaBavbPbQbNbRbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNbSbTbUbVbNbWaEbXbYbPbZcacbbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaccccccccccccccccccccccccccccccccccccccccfbbNbNbNgbcehbibchcicjckclbPcmcncobNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacpcqcrcsctctctctctctctctctctctctctctctctctcujbkblbmbnbobpbbNcCcDcEcFbPcGcHqbcJcKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacLcLcLcLcLcLcLcLcLcLcLcLcLcLcLcLcLcLcLcLaabNbNbNrbcNsbtbbNcQcRcEcSbPcTubvbbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNbNbNcObNbNcWcXbNbNbNcYbNbNbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNbNcZdadbbNdcddbNdedfcTdgbNbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNbNdhdibNdjdjbNdkdldmbNbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNbNdndodpdqdrdpdsdtdubNbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNdvdwbNdxdxbNdwdvdybNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNdzdAbNdxdxbNdBdCdDbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNdEdEbNbNbNbNbNdEdEbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadGaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/away/yacht/yacht.dm b/maps/away/yacht/yacht.dm new file mode 100644 index 00000000..d470fda4 --- /dev/null +++ b/maps/away/yacht/yacht.dm @@ -0,0 +1,43 @@ +#include "yacht_areas.dm" + +/obj/effect/overmap/ship/yacht + name = "private yacht" + desc = "Sensor array is detecting a small vessel with unknown lifeforms on board" + color = "#FFC966" + vessel_mass = 30 + default_delay = 35 SECONDS + speed_mod = 10 SECONDS + triggers_events = 0 + generic_waypoints = list( + "nav_yacht_1", + "nav_yacht_2", + "nav_yacht_3", + "nav_yacht_antag" + ) + +/obj/effect/overmap/ship/yacht/New(nloc, max_x, max_y) + name = "IPV [pick("Razorshark", "Aurora", "Lighting", "Pequod", "Anansi")], \a [name]" + ..() + +/datum/map_template/ruin/away_site/yacht + name = "Yacht" + id = "awaysite_yach" + description = "Tiny movable ship with spiders." + suffixes = list("yacht/yacht.dmm") + cost = 0.5 + +/obj/effect/shuttle_landmark/nav_yacht/nav1 + name = "Small Yacht Navpoint #1" + landmark_tag = "nav_yacht_1" + +/obj/effect/shuttle_landmark/nav_yacht/nav2 + name = "Small Yacht Navpoint #2" + landmark_tag = "nav_yacht_2" + +/obj/effect/shuttle_landmark/nav_yacht/nav3 + name = "Small Yacht Navpoint #3" + landmark_tag = "nav_yacht_3" + +/obj/effect/shuttle_landmark/nav_yacht/nav4 + name = "Small Yacht Navpoint #4" + landmark_tag = "nav_yacht_antag" diff --git a/maps/away/yacht/yacht.dmm b/maps/away/yacht/yacht.dmm new file mode 100644 index 00000000..fa8e2af9 --- /dev/null +++ b/maps/away/yacht/yacht.dmm @@ -0,0 +1,294 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/obj/effect/overmap/ship/yacht,/turf/space,/area/space) +"ac" = (/obj/effect/wingrille_spawn/reinforced/full,/turf/simulated/floor/plating,/area/yacht/bridge) +"ad" = (/obj/machinery/shipsensors,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/yacht/bridge) +"ae" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"af" = (/obj/effect/shuttle_landmark/nav_yacht/nav2,/turf/space,/area/space) +"ag" = (/obj/effect/shuttle_landmark/nav_yacht/nav1,/turf/space,/area/space) +"ah" = (/turf/simulated/wall/titanium,/area/yacht/bridge) +"ai" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/computer/helm,/turf/simulated/floor/wood,/area/yacht/bridge) +"aj" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/computer/sensors,/turf/simulated/floor/wood,/area/yacht/bridge) +"ak" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/structure/bed/chair/comfy/captain,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"al" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/computer/engines,/turf/simulated/floor/wood,/area/yacht/bridge) +"am" = (/obj/item/weapon/folder/blue,/obj/item/weapon/form_printer,/obj/structure/table/woodentable,/obj/item/weapon/reagent_containers/food/drinks/coffeecup,/obj/item/weapon/newspaper,/obj/effect/spider/stickyweb,/obj/effect/decal/cleanable/dirt,/obj/random/energy,/obj/item/weapon/paper{info = "I used up all of my energy. I am hopelessly lost. This ship has become my grave. They did it. The intelligence agency that no one ever talks about. Sol Gov wanted their revenge, and they got it. They easily could have killed me on my ship, or tortured me, but they knew that floating here through space would be the worst possible torture. "},/turf/simulated/floor/wood,/area/yacht/bridge) +"an" = (/obj/machinery/atmospherics/unary/vent_pump/on,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/mob/living/simple_animal/hostile/giant_spider/hunter,/turf/simulated/floor/wood,/area/yacht/bridge) +"ao" = (/obj/effect/decal/cleanable/dirt,/obj/random/maintenance/clean,/turf/simulated/floor/wood,/area/yacht/bridge) +"ap" = (/obj/structure/filingcabinet/chestdrawer,/obj/effect/decal/cleanable/cobweb2,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"aq" = (/obj/machinery/light{dir = 8},/obj/structure/safe,/obj/item/weapon/reagent_containers/pill/cyanide,/obj/item/weapon/gun/energy/captain,/obj/effect/spider/stickyweb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"ar" = (/obj/machinery/alarm{dir = 1; icon_state = "alarm0"; pixel_y = -22},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"as" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"at" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 2; name = "Yacht bridge"; pixel_x = 0; pixel_y = -24},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"au" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/structure/reagent_dispensers/water_cooler,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/bridge) +"av" = (/turf/simulated/wall/wood,/area/yacht/living) +"aw" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock/silver,/turf/simulated/floor/plating,/area/yacht/bridge) +"ax" = (/turf/simulated/wall/wood,/area/yacht/bridge) +"ay" = (/obj/structure/disposalpipe/trunk{dir = 4},/obj/machinery/disposal,/turf/simulated/floor/plating,/area/yacht/living) +"az" = (/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/wall/titanium,/area/yacht/living) +"aA" = (/obj/structure/disposalpipe/trunk{dir = 8},/obj/structure/disposaloutlet{dir = 4},/turf/space,/area/space) +"aB" = (/turf/simulated/wall/titanium,/area/yacht/living) +"aC" = (/obj/machinery/light/small{dir = 8},/obj/structure/mirror{pixel_y = 28},/obj/structure/sink{pixel_y = 20},/obj/item/weapon/bikehorn/rubberducky,/obj/effect/decal/cleanable/dirt,/obj/random/soap,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"aD" = (/obj/machinery/shower{pixel_y = 20},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"aE" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aF" = (/obj/structure/bed/chair/wood/wings{dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aG" = (/obj/machinery/light{dir = 1},/obj/structure/table/marble,/obj/item/trash/snack_bowl,/obj/machinery/reagentgrinder,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/paper{info = "Tonight I woke up to a sound I hoped to have never heard, a small explosion. I rushed to the bridge to diagnose the damage and saw the worst possible news. My solar tracker is gone, and so is the fucking computer. No way to override the settings now, because the assholes EMPd the computer. No way to charge my SMES reliably, and no way to heat the fuel. I am stuck in the water! Unheated, this gas will not be enough to get absolutely anywhere near a port. This is bad. Real bad. The current charge on SMES is 20 percent, so I'll just try and orient the ship to hit the current star at maximum efficiency so we will charge at 100, and maybe make it to the next solar system. The next port is in the orbit of a Gas giant named Duma. Maybe I can dock there and repair my array. I freaking knew I needed to get a generator. I spent all of the money the Terrans gave me, and this piece of shit is all I could get. "},/turf/simulated/floor/wood,/area/yacht/living) +"aH" = (/obj/effect/decal/cleanable/cobweb2,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aI" = (/obj/item/weapon/towel/random,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"aJ" = (/obj/structure/toilet{dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"aK" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/light{dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aL" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aM" = (/obj/structure/table/marble,/obj/item/pizzabox/vegetable,/obj/item/weapon/reagent_containers/glass/rag,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aN" = (/obj/effect/decal/cleanable/dirt,/obj/random/junk,/turf/simulated/floor/wood,/area/yacht/living) +"aO" = (/obj/machinery/vending/wallmed1,/turf/simulated/wall/titanium,/area/yacht/living) +"aP" = (/obj/machinery/door/airlock/silver,/turf/simulated/floor/wood,/area/yacht/living) +"aQ" = (/obj/structure/table/marble,/obj/item/weapon/deck/cards,/obj/item/weapon/dice,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aR" = (/obj/effect/decal/cleanable/blood/gibs/robot/up,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aS" = (/obj/structure/table/marble,/obj/machinery/microwave,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aT" = (/obj/effect/decal/cleanable/cobweb,/obj/effect/spider/stickyweb,/turf/simulated/floor/carpet/blue2,/area/yacht/living) +"aU" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/obj/effect/decal/cleanable/blood/drip,/obj/effect/spider/stickyweb,/mob/living/simple_animal/hostile/giant_spider/hunter,/turf/simulated/floor/wood,/area/yacht/living) +"aV" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/decal/cleanable/blood/drip,/obj/effect/spider/stickyweb,/turf/simulated/floor/wood,/area/yacht/living) +"aW" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/closet/walllocker/emerglocker/north,/obj/effect/decal/cleanable/blood/drip,/obj/machinery/door/airlock/silver,/turf/simulated/floor/wood,/area/yacht/living) +"aX" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aY" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"aZ" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/table/marble,/obj/item/weapon/book/manual/chef_recipes,/obj/item/weapon/reagent_containers/food/drinks/pitcher,/obj/effect/decal/cleanable/dirt,/obj/random/drinkbottle,/turf/simulated/floor/wood,/area/yacht/living) +"ba" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/effect/decal/cleanable/blood/gibs/robot/down,/obj/effect/decal/cleanable/blood/gibs/robot/up,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bb" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/machinery/vending/dinnerware,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bc" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet/blue,/obj/effect/spider/stickyweb,/turf/simulated/floor/carpet/blue2,/area/yacht/living) +"bd" = (/obj/effect/spider/stickyweb,/turf/simulated/floor/wood,/area/yacht/living) +"bf" = (/obj/effect/decal/cleanable/blood/gibs/robot/limb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bg" = (/obj/structure/closet/secure_closet/freezer/fridge,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bh" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/spider/stickyweb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bi" = (/obj/machinery/smartfridge,/turf/simulated/wall/wood,/area/yacht/living) +"bj" = (/obj/machinery/vending/boozeomat,/turf/simulated/wall/wood,/area/yacht/living) +"bk" = (/obj/effect/wingrille_spawn/reinforced/full,/turf/simulated/floor/plating,/area/yacht/living) +"bl" = (/obj/machinery/light{dir = 8},/obj/effect/spider/stickyweb,/turf/simulated/floor/beach/water,/area/yacht/living) +"bm" = (/obj/effect/spider/stickyweb,/turf/simulated/floor/beach/water,/area/yacht/living) +"bn" = (/obj/effect/spider/stickyweb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"bo" = (/obj/machinery/door/airlock/silver,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"bp" = (/obj/effect/decal/cleanable/dirt,/obj/item/weapon/paper{info = "I have accepted my fate. I will go into EVA with one of the cyanide pills in my mouth, and I will float off. I want a military funeral, and I will arrange it myself. Good bye all. I have earned and sealed my fate. "},/turf/simulated/floor/wood,/area/yacht/living) +"bq" = (/obj/structure/bookcase,/turf/simulated/floor/carpet/purple,/area/yacht/living) +"br" = (/obj/machinery/light/small{dir = 1},/obj/structure/bookcase,/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bs" = (/obj/item/weapon/inflatable_duck,/obj/effect/spider/stickyweb,/turf/simulated/floor/beach/water,/area/yacht/living) +"bt" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bu" = (/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bv" = (/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bw" = (/obj/structure/bed/chair/comfy/red{dir = 4},/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bx" = (/turf/simulated/floor/beach/water,/area/yacht/living) +"by" = (/mob/living/simple_animal/hostile/giant_spider/hunter,/turf/simulated/floor/beach/water,/area/yacht/living) +"bz" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"bA" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/effect/spider/stickyweb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bB" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/spider/stickyweb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bC" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/airlock/silver,/turf/simulated/floor/wood,/area/yacht/living) +"bD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bE" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bF" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/item/weapon/storage/bible,/obj/item/weapon/pen/blue,/obj/structure/table/woodentable,/obj/item/weapon/paper{info = "Let me introduce myself. My name is Commander Archibald McKinley, although the Fleet fucks think that I do not deserve the title. Well, fuck them. They accused me of facilitating a destruction of the ship I was CO of. A small missile cruiser, with zero to fucking none point defenses was attacked, and they first accuse me of escaping before any of my crew. What kind of person wouldn't expect someone to escape when their ship is on fire? It's lunacy. But it only got worse. Then they said that I helped the Terrans take the ship. Well fuck them, they are wrong. That's non sense. I have no connection to the Terrans. They said that I got a large sum of money from them in order to betray my ship's position, which is once again total nonsense. I've got about 20 years of life left here, and I know that I will be safe with my ship here. I need to resupply once every 5 years, given how much food and fuel I have, and I've got enough range to go to pretty much any known part of the galaxy, in complete silence, as we are totally solar powered. I wish I could afford ion thrusters to not have to rely on gas for propulsion, but, our gas heaters should provide us with enough pressure to get anywhere in relative decent speed. Also, I got a robot butler who cooks delicious food for me! No more crappy lance corporal food, eh"},/obj/item/device/flashlight/lamp/green,/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bG" = (/obj/machinery/light{dir = 8},/turf/simulated/floor/beach/water,/area/yacht/living) +"bH" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/beach/water,/area/yacht/living) +"bI" = (/obj/machinery/light,/obj/item/clothing/shoes/swimmingfins,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled/freezer,/area/yacht/living) +"bJ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood/gibs/robot/limb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bK" = (/obj/effect/decal/cleanable/blood/gibs/robot/down,/obj/effect/decal/cleanable/dirt,/obj/machinery/floodlight,/turf/simulated/floor/wood,/area/yacht/living) +"bL" = (/obj/machinery/light/small,/obj/structure/filingcabinet,/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bM" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/carpet/purple,/area/yacht/living) +"bN" = (/turf/simulated/wall/titanium,/area/yacht/engine) +"bO" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/blood/gibs/robot/down,/obj/machinery/door/airlock/silver,/turf/simulated/floor/wood,/area/yacht/living) +"bP" = (/turf/simulated/wall/wood,/area/yacht/engine) +"bQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock/hatch,/turf/simulated/floor/plating,/area/yacht/engine) +"bR" = (/obj/machinery/atmospherics/pipe/tank/air,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"bS" = (/obj/structure/dispenser/oxygen,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"bT" = (/obj/item/weapon/cell/hyper,/obj/item/weapon/book/manual/engineering_guide,/obj/item/weapon/rcd,/obj/effect/decal/cleanable/dirt,/obj/machinery/computer/engines,/turf/simulated/floor/plating,/area/yacht/engine) +"bU" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/power/smes/buildable,/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/plating,/area/yacht/engine) +"bV" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/power/apc{dir = 1; name = "Yacht engine"; pixel_x = 0; pixel_y = 24},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"bW" = (/obj/item/weapon/extinguisher,/obj/machinery/portable_atmospherics/hydroponics,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bX" = (/obj/machinery/vending/hydronutrients,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bY" = (/obj/machinery/seed_storage/garden,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"bZ" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"ca" = (/obj/structure/closet/secure_closet/freezer/kitchen,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cb" = (/obj/machinery/atmospherics/binary/pump,/obj/machinery/space_heater,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cc" = (/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/obj/machinery/power/solar,/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/yacht/engine) +"ce" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/obj/effect/decal/cleanable/dirt,/obj/item/weapon/circuitboard/broken,/turf/simulated/floor/plating,/area/yacht/engine) +"ch" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/airlock/hatch,/turf/simulated/floor/plating,/area/yacht/engine) +"ci" = (/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cj" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"ck" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cl" = (/obj/structure/janitorialcart,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cm" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/light/small{dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cn" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"co" = (/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{dir = 4},/obj/effect/decal/cleanable/dirt,/obj/machinery/portable_atmospherics/powered/pump,/turf/simulated/floor/plating,/area/yacht/engine) +"cp" = (/obj/structure/cable{icon_state = "0-2"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/obj/effect/decal/cleanable/ash,/obj/effect/decal/cleanable/blood/oil/streak,/obj/effect/decal/cleanable/generic,/obj/effect/decal/cleanable/molten_item,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/yacht/engine) +"cq" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/item/weapon/circuitboard/broken,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/yacht/engine) +"cr" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/item/weapon/storage/toolbox/syndicate,/turf/simulated/floor/airless{icon_state = "dmg2"},/area/yacht/engine) +"cs" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/item/weapon/plastique,/turf/simulated/floor/airless,/area/yacht/engine) +"ct" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/airless,/area/yacht/engine) +"cu" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/airless,/area/yacht/engine) +"cC" = (/obj/structure/cable,/obj/machinery/power/apc{dir = 8; name = "Yacht living"; pixel_x = -24},/obj/machinery/portable_atmospherics/hydroponics,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/decal/cleanable/dirt,/mob/living/bot/farmbot,/turf/simulated/floor/wood,/area/yacht/living) +"cE" = (/obj/effect/spider/stickyweb,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cF" = (/obj/structure/reagent_dispensers/watertank,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cH" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/obj/effect/decal/cleanable/dirt,/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/yacht/engine) +"cJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/red{icon_state = "intact"; dir = 4},/turf/simulated/wall/titanium,/area/yacht/engine) +"cK" = (/obj/machinery/atmospherics/unary/outlet_injector{dir = 8; use_power = 1},/turf/space,/area/space) +"cL" = (/obj/structure/cable,/obj/machinery/power/solar,/obj/effect/floor_decal/solarpanel,/turf/simulated/floor/airless,/area/yacht/engine) +"cN" = (/obj/structure/closet/toolcloset,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cO" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cQ" = (/obj/machinery/light{dir = 8},/obj/machinery/alarm{dir = 4; pixel_x = -23; pixel_y = 0},/obj/machinery/portable_atmospherics/hydroponics,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cR" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/item/weapon/shovel/spade,/obj/item/weapon/reagent_containers/glass/bucket,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cS" = (/obj/machinery/light,/obj/structure/reagent_dispensers/beerkeg,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cT" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cW" = (/obj/structure/closet/crate/freezer/rations,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cX" = (/obj/structure/closet/crate/hydroponics,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"cY" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"cZ" = (/obj/machinery/vending/tool,/turf/simulated/floor/plating,/area/yacht/engine) +"da" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/caution/cone,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"db" = (/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/plating,/area/yacht/engine) +"dc" = (/obj/structure/closet/wardrobe/pjs,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"dd" = (/obj/structure/closet/wardrobe/suit,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/wood,/area/yacht/living) +"de" = (/obj/machinery/light/small{dir = 8},/obj/structure/closet/crate/freezer,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"df" = (/obj/effect/decal/cleanable/dirt,/obj/random/coin,/turf/simulated/floor/plating,/area/yacht/engine) +"dg" = (/obj/structure/closet/secure_closet/freezer/meat,/turf/simulated/floor/plating,/area/yacht/engine) +"dh" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"di" = (/obj/machinery/atmospherics/unary/heater,/turf/simulated/floor/plating,/area/yacht/engine) +"dj" = (/obj/structure/window/reinforced/full,/obj/structure/grille,/turf/simulated/floor/plating,/area/yacht/engine) +"dk" = (/obj/machinery/atmospherics/unary/heater,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dl" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dm" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/structure/closet/secure_closet/freezer/kitchen,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dn" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 6},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"do" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/black,/obj/machinery/light/small{dir = 4; pixel_y = 8},/obj/effect/decal/cleanable/dirt,/obj/machinery/meter,/turf/simulated/floor/plating,/area/yacht/engine) +"dp" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/wall/titanium,/area/yacht/engine) +"dq" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 8; external_pressure_bound = 0; external_pressure_bound_default = 0; frequency = 1439; icon_state = "map_vent_in"; id_tag = null; initialize_directions = 1; internal_pressure_bound = 4000; internal_pressure_bound_default = 4000; pressure_checks = 2; pressure_checks_default = 2; pump_direction = 0; use_power = 1},/turf/simulated/floor/reinforced/carbon_dioxide,/area/yacht/engine) +"dr" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 4; external_pressure_bound = 0; external_pressure_bound_default = 0; frequency = 1439; icon_state = "map_vent_in"; id_tag = null; initialize_directions = 1; internal_pressure_bound = 4000; internal_pressure_bound_default = 4000; pressure_checks = 2; pressure_checks_default = 2; pump_direction = 0; use_power = 1},/turf/simulated/floor/reinforced/carbon_dioxide,/area/yacht/engine) +"ds" = (/obj/machinery/atmospherics/pipe/manifold4w/visible/black,/obj/structure/closet/crate/medical,/obj/effect/decal/cleanable/dirt,/obj/machinery/meter,/turf/simulated/floor/plating,/area/yacht/engine) +"dt" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 10},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"du" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/closet/secure_closet/freezer/meat,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dv" = (/obj/machinery/atmospherics/pipe/simple/visible/black,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dw" = (/obj/machinery/atmospherics/unary/heater{dir = 1},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dx" = (/turf/simulated/floor/reinforced/carbon_dioxide,/area/yacht/engine) +"dy" = (/obj/machinery/light/small{dir = 4; pixel_y = 8},/obj/structure/closet/secure_closet/freezer/meat,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dz" = (/obj/machinery/atmospherics/pipe/manifold/visible/black{dir = 8; icon_state = "map"},/obj/structure/window/reinforced,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dA" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 10},/obj/structure/window/reinforced,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/yacht/engine) +"dB" = (/obj/structure/closet/crate/medical,/turf/simulated/floor/plating,/area/yacht/engine) +"dC" = (/obj/machinery/atmospherics/pipe/manifold/visible/black{dir = 8; icon_state = "map"},/obj/structure/window/reinforced,/obj/structure/closet/secure_closet/bar,/turf/simulated/floor/plating,/area/yacht/engine) +"dD" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 10},/obj/structure/window/reinforced,/obj/machinery/recharge_station,/turf/simulated/floor/plating,/area/yacht/engine) +"dE" = (/obj/machinery/atmospherics/unary/engine{dir = 1},/turf/simulated/floor/airless,/area/yacht/engine) +"dF" = (/obj/effect/shuttle_landmark/nav_yacht/nav3,/turf/space,/area/space) +"dG" = (/obj/effect/shuttle_landmark/nav_yacht/nav4,/turf/space,/area/space) +"eb" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/item/weapon/cane,/obj/item/clothing/suit/storage/det_trench/grey,/obj/item/clothing/ring/cti,/obj/item/clothing/under/lawyer/oldman,/obj/structure/table/woodentable,/obj/effect/spider/stickyweb,/obj/random/cash,/obj/random/cash,/obj/random/cash,/obj/random/projectile,/turf/simulated/floor/wood,/area/yacht/living) +"fb" = (/obj/machinery/access_button/airlock_exterior{frequency = 1420; master_tag = "yacht_airlock"; pixel_x = 24},/turf/space,/area/space) +"gb" = (/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/obj/effect/decal/cleanable/dirt,/obj/structure/computerframe,/obj/machinery/access_button/airlock_interior{frequency = 1420; master_tag = "yacht_airlock"; pixel_x = -24},/turf/simulated/floor/plating,/area/yacht/engine) +"hb" = (/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/obj/item/weapon/storage/toolbox/electrical,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/yacht/engine) +"ib" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/plating,/area/yacht/engine) +"jb" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/obj/machinery/door/airlock/external/bolted{frequency = 1420; id_tag = "yacht_outer"},/turf/simulated/floor/airless,/area/yacht/engine) +"kb" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1420; id_tag = "yacht_airlock"; pixel_y = 24; tag_airpump = "yacht_pump"; tag_chamber_sensor = "yacht_sensor"; tag_exterior_door = "yacht_outer"; tag_interior_door = "yacht_inner"},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1420; id_tag = "yacht_pump"},/obj/machinery/airlock_sensor{frequency = 1420; id_tag = "yacht_sensor"; pixel_y = -24},/turf/simulated/floor/airless,/area/yacht/engine) +"lb" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4; icon_state = "intact"},/obj/machinery/door/airlock/external/bolted{frequency = 1420; id_tag = "yacht_inner"},/turf/simulated/floor/plating,/area/yacht/engine) +"mb" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/manifold/hidden{dir = 1; icon_state = "map"},/turf/simulated/floor/plating,/area/yacht/engine) +"nb" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/universal{icon_state = "map_universal"; dir = 4},/turf/simulated/floor/plating,/area/yacht/engine) +"ob" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/binary/pump{dir = 8},/turf/simulated/floor/plating,/area/yacht/engine) +"pb" = (/obj/machinery/alarm{alarm_id = "misc_research"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/yacht/engine) +"qb" = (/obj/machinery/atmospherics/binary/pump{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/red{icon_state = "intact"; dir = 4},/obj/effect/decal/cleanable/dirt,/obj/random/closet,/turf/simulated/floor/plating,/area/yacht/engine) +"rb" = (/obj/machinery/atmospherics/pipe/tank/air{dir = 1},/turf/simulated/floor/plating,/area/yacht/engine) +"sb" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/plating,/area/yacht/engine) +"tb" = (/obj/structure/closet/firecloset,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/plating,/area/yacht/engine) +"ub" = (/obj/effect/decal/cleanable/dirt,/obj/random/closet,/turf/simulated/floor/plating,/area/yacht/engine) +"vb" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/item/weapon/storage/firstaid,/obj/effect/decal/cleanable/dirt,/obj/random/closet,/turf/simulated/floor/plating,/area/yacht/engine) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadacaeacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaaaaaaahacaiacahaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahahajakalahahaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahamaeanaoapahaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahahaqarasatauahahaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahavavavawaxaxayazaAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBaCaDavaEaFaGaHaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBaBaIaJavaKaLaMaNaOaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBavaPavavaEaLaQaRaSaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBaTaUaVaWaXaYaZbabbaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBaBbcbdebavaEaLbfaLbgaBaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBaBavavavavbhaLavbibjaBaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabkblbmbmbnboaEbpavbqbrbqaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabkbmbsbmbnavbhbtavbubvbwbkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabkbmbxbybzavbAbBbCbDbEbFbkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBaBbGbxbHbIavbJbKavbLbMaBaBaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNbNbNbNbNbNavbOaBavbPbQbNbRbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNbSbTbUbVbNbWaEbXbYbPbZcacbbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaccccccccccccccccccccccccccccccccccccccccfbbNbNbNgbcehbibchcicjckclbPcmcncobNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacpcqcrcsctctctctctctctctctctctctctctctctctcujbkblbmbnbobpbbNcCcDcEcFbPcGcHqbcJcKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacLcLcLcLcLcLcLcLcLcLcLcLcLcLcLcLcLcLcLcLaabNbNbNrbcNsbtbbNcQcRcEcSbPcTubvbbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNbNbNcObNbNcWcXbNbNbNcYbNbNbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNbNcZdadbbNdcddbNdedfcTdgbNbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNbNdhdibNdjdjbNdkdldmbNbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNbNdndodpdqdrdpdsdtdubNbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNdvdwbNdxdxbNdwdvdybNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNdzdAbNdxdxbNdBdCdDbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNdEdEbNbNbNbNbNdEdEbNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadGaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/away/yacht/yacht_areas.dm b/maps/away/yacht/yacht_areas.dm new file mode 100644 index 00000000..92795b87 --- /dev/null +++ b/maps/away/yacht/yacht_areas.dm @@ -0,0 +1,12 @@ +/area/yacht/bridge + name = "\improper Yacht Bridge" + icon_state = "bridge" + icon = 'yacht_icons.dmi' +/area/yacht/living + name = "\improper Yacht Living" + icon_state = "living" + icon = 'yacht_icons.dmi' +/area/yacht/engine + name = "\improper Yacht Engine" + icon_state = "engine" + icon = 'yacht_icons.dmi' \ No newline at end of file diff --git a/maps/away/yacht/yacht_icons.dmi b/maps/away/yacht/yacht_icons.dmi new file mode 100644 index 00000000..b0aad94b Binary files /dev/null and b/maps/away/yacht/yacht_icons.dmi differ diff --git a/maps/away_sites_testing/away_sites_testing.dm b/maps/away_sites_testing/away_sites_testing.dm new file mode 100644 index 00000000..764eccc8 --- /dev/null +++ b/maps/away_sites_testing/away_sites_testing.dm @@ -0,0 +1,30 @@ +#if !defined(using_map_DATUM) + #include "away_sites_testing_unit_testing.dm" + + #include "blank.dmm" + + #include "../away/empty.dmm" + #include "../away/mining/mining.dm" + #include "../away/derelict/derelict.dm" + #include "../away/bearcat/bearcat.dm" + #include "../away/lost_supply_base/lost_supply_base.dm" + #include "../away/marooned/marooned.dm" + #include "../away/smugglers/smugglers.dm" + #include "../away/casino/casino.dm" + #include "../away/magshield/magshield.dm" + #include "../away/slavers/slavers_base.dm" + #include "../away/blueriver/blueriver.dm" + #include "../away/hydro/hydro.dm" + #include "../away/mobius_rift/mobius_rift.dm" +// #include "../away/icarus/icarus.dm" temporarily removed while we investigate Travis failures + #include "../away/errant_pisces/errant_pisces.dm" + + #include "../../code/modules/lobby_music/absconditus.dm" + + #define using_map_DATUM /datum/map/away_sites_testing + +#elif !defined(MAP_OVERRIDE) + + #warn A map has already been included, ignoring Away Sites Testing + +#endif diff --git a/maps/away_sites_testing/away_sites_testing_define.dm b/maps/away_sites_testing/away_sites_testing_define.dm new file mode 100644 index 00000000..bafe6795 --- /dev/null +++ b/maps/away_sites_testing/away_sites_testing_define.dm @@ -0,0 +1,23 @@ + +/datum/map/away_sites_testing + name = "Away Sites Testing" + full_name = "Away Sites Testing Land" + path = "away_sites_testing" + + lobby_icon = 'maps/example/example_lobby.dmi' + + station_levels = list() + contact_levels = list() + player_levels = list() + + allowed_spawns = list() + +/datum/map/away_sites_testing/build_away_sites() + var/list/unsorted_sites = list_values(SSmapping.away_sites_templates) + var/list/sorted_sites = sortTim(unsorted_sites, /proc/cmp_sort_templates_tallest_to_shortest) + for (var/datum/map_template/ruin/away_site/A in sorted_sites) + testing("Spawning [A]") + A.load_new_z() + +/proc/cmp_sort_templates_tallest_to_shortest(var/datum/map_template/a, var/datum/map_template/b) + return b.tallness - a.tallness \ No newline at end of file diff --git a/maps/away_sites_testing/away_sites_testing_unit_testing.dm b/maps/away_sites_testing/away_sites_testing_unit_testing.dm new file mode 100644 index 00000000..10e2e9d8 --- /dev/null +++ b/maps/away_sites_testing/away_sites_testing_unit_testing.dm @@ -0,0 +1,102 @@ +/datum/map/away_sites_testing + // Unit test exemptions + apc_test_exempt_areas = list( + /area/AIsattele = NO_SCRUBBER|NO_VENT|NO_APC, + /area/constructionsite = NO_SCRUBBER|NO_VENT|NO_APC, + /area/constructionsite/ai = NO_SCRUBBER|NO_VENT, + /area/constructionsite/atmospherics = NO_SCRUBBER, + /area/constructionsite/teleporter = NO_SCRUBBER, + /area/derelict/ship = NO_SCRUBBER|NO_VENT, + /area/djstation = NO_SCRUBBER|NO_APC, + /area/mine/explored = NO_SCRUBBER|NO_VENT|NO_APC, + /area/mine/unexplored = NO_SCRUBBER|NO_VENT|NO_APC, + /area/outpost/abandoned = NO_SCRUBBER, + /area/space = NO_SCRUBBER|NO_VENT|NO_APC, + /area/ship/scrap/maintenance/engine/port = NO_SCRUBBER|NO_VENT, + /area/ship/scrap/maintenance/engine/starboard = NO_SCRUBBER|NO_VENT, + /area/ship/scrap/crew/hallway/port= NO_SCRUBBER|NO_VENT, + /area/ship/scrap/crew/hallway/starboard= NO_SCRUBBER|NO_VENT, + /area/ship/scrap/maintenance/hallway = NO_SCRUBBER|NO_VENT, + /area/ship/scrap/maintenance/lower = NO_SCRUBBER|NO_VENT, + /area/ship/scrap/maintenance/atmos = NO_SCRUBBER, + /area/ship/scrap/escape_port = NO_SCRUBBER|NO_VENT, + /area/ship/scrap/escape_star = NO_SCRUBBER|NO_VENT, + /area/ship/scrap/shuttle/lift = NO_SCRUBBER|NO_VENT|NO_APC, + /area/ship/scrap/command/hallway = NO_SCRUBBER|NO_VENT, + /area/marooned/marooned_snow = NO_SCRUBBER|NO_VENT|NO_APC, + /area/marooned/marooned_hut = NO_SCRUBBER|NO_VENT|NO_APC, + /area/lost_supply_base/solar = NO_SCRUBBER, + /area/smugglers/base = NO_SCRUBBER, + /area/smugglers/dorms = NO_SCRUBBER|NO_VENT, + /area/smugglers/office = NO_SCRUBBER|NO_VENT, + /area/casino/casino_solar_control = NO_SCRUBBER, + /area/casino/casino_maintenance = NO_SCRUBBER, + /area/casino/casino_hangar = NO_SCRUBBER, + /area/casino/casino_cutter = NO_SCRUBBER|NO_VENT, + /area/bluespaceriver/underground = NO_SCRUBBER|NO_VENT|NO_APC, + /area/bluespaceriver/ground = NO_SCRUBBER|NO_VENT|NO_APC, + /area/slavers_base/hangar = NO_SCRUBBER, + /area/hydro = NO_SCRUBBER|NO_VENT|NO_APC, + /area/hydro/station = NO_SCRUBBER, + /area/mobius_rift = NO_SCRUBBER|NO_VENT|NO_APC, +// /area/icarus/vessel = NO_APC, +// /area/icarus/open = NO_SCRUBBER|NO_VENT|NO_APC, + ) + + area_coherency_test_exempt_areas = list( + /area/space, + /area/mine/explored, + /area/mine/unexplored, + /area/marooned/marooned_snow, +// /area/icarus/open, +// /area/icarus/vessel, + ) + + area_coherency_test_subarea_count = list( + /area/constructionsite = 7, + /area/constructionsite/maintenance = 14, + /area/constructionsite/solar = 3, + ) + + area_usage_test_exempted_areas = list( + /area/overmap, + /area/template_noop, + /area/centcom, + /area/centcom/holding, + /area/centcom/specops, + /area/chapel, + /area/hallway, + /area/medical, + /area/medical/virology, + /area/medical/virologyaccess, + /area/medical/virology, + /area/security, + /area/security/brig, + /area/security/prison, + /area/maintenance, + /area/rnd, + /area/rnd/xenobiology, + /area/rnd/xenobiology/xenoflora, + /area/rnd/xenobiology/xenoflora_storage, + /area/shuttle, + /area/shuttle/escape, + /area/shuttle/escape/centcom, + /area/shuttle/specops, + /area/shuttle/specops/centcom, + /area/shuttle/syndicate_elite, + /area/shuttle/syndicate_elite/mothership, + /area/shuttle/syndicate_elite/station, + /area/skipjack_station, + /area/skipjack_station/start, + /area/supply, + /area/syndicate_mothership, + /area/syndicate_mothership/elite_squad, + /area/wizard_station, + /area/beach, + /area/turbolift + ) + + area_usage_test_exempted_root_areas = list( + /area/exoplanet, + /area/map_template + ) diff --git a/maps/away_sites_testing/blank.dmm b/maps/away_sites_testing/blank.dmm new file mode 100644 index 00000000..db5e8ea7 --- /dev/null +++ b/maps/away_sites_testing/blank.dmm @@ -0,0 +1,19 @@ +"a" = (/turf/space,/area/space) +"b" = (/turf/simulated/wall,/area/space) +"c" = (/turf/simulated/floor/tiled,/area/space) +"d" = (/obj/effect/landmark/test/safe_turf,/turf/simulated/floor/tiled,/area/space) +"e" = (/obj/effect/landmark/start{name = "JoinLate"},/turf/simulated/floor/tiled,/area/space) +"f" = (/obj/effect/landmark/test/space_turf,/turf/space,/area/space) + +(1,1,1) = {" +aaaabbbbbb +aaaabccccb +aaaabcdccb +aaaabccccb +aaaabecccb +aaaabbbbbb +aaaaaaaaaa +aaaaaaaaaa +afaaaaaaaa +aaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/oldfare/backup/example-2.dmm b/maps/oldfare/backup/example-2.dmm new file mode 100644 index 00000000..3cf68d89 --- /dev/null +++ b/maps/oldfare/backup/example-2.dmm @@ -0,0 +1,74 @@ +"a" = (/turf/space,/area/space) +"b" = (/obj/effect/landmark/map_data{height = 2},/turf/space,/area/space) +"c" = (/turf/simulated/wall,/area/medical/surgery2) +"d" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/structure/iv_drip,/obj/item/weapon/reagent_containers/ivbag/blood/OMinus,/obj/item/weapon/reagent_containers/ivbag/blood/OMinus,/obj/item/weapon/reagent_containers/ivbag/blood/OMinus,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"e" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/machinery/optable,/obj/machinery/oxygen_pump/anesthetic{pixel_y = 32},/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"f" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/machinery/computer/operating,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"g" = (/obj/machinery/light{dir = 1},/obj/effect/floor_decal/corner/blue/diagonal,/obj/structure/table/glass,/obj/item/weapon/storage/box/syringes,/obj/item/weapon/storage/box/freezer,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"h" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/structure/table/glass,/obj/item/weapon/storage/box/gloves,/obj/item/weapon/storage/box/masks,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"i" = (/obj/effect/floor_decal/corner/blue/diagonal,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"j" = (/obj/structure/lattice,/turf/simulated/open,/area/medical/surgery2) +"k" = (/obj/machinery/light{dir = 1},/obj/effect/floor_decal/corner/blue/diagonal,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"l" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/structure/table/glass,/obj/item/weapon/storage/firstaid/surgery,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"m" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/structure/sink{ icon_state = "sink"; dir = 4},/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"n" = (/turf/simulated/open,/area/medical/surgery2) +"o" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/structure/table/glass,/obj/item/weapon/reagent_containers/dropper,/obj/item/weapon/reagent_containers/chem_disp_cartridge/peridaxon,/obj/item/stack/nanopaste,/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"p" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/machinery/body_scanconsole{ icon_state = "body_scannerconsole"; dir = 4},/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"q" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/machinery/bodyscanner{ icon_state = "body_scanner_0"; dir = 4},/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"r" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/machinery/sleeper{ icon_state = "sleeper_0"; dir = 8},/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"s" = (/obj/machinery/light_switch{pixel_x = 25},/obj/effect/floor_decal/corner/blue/diagonal,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"t" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/structure/table/glass,/obj/item/weapon/scalpel/laser1,/obj/item/weapon/scalpel/laser2,/obj/item/weapon/scalpel/laser3,/obj/item/device/robotanalyzer,/obj/item/device/healthanalyzer,/obj/item/weapon/storage/firstaid/adv,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"u" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/structure/ladder/updown,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"v" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/machinery/atmospherics/unary/freezer,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"w" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/machinery/atmospherics/unary/cryo_cell,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"x" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/machinery/portable_atmospherics/canister/oxygen/prechilled,/obj/machinery/atmospherics/portables_connector,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"y" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/structure/closet/secure_closet/freezer/meat,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"z" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/machinery/mecha_part_fabricator,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"A" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/machinery/atmospherics/pipe/simple/visible/blue{ icon_state = "intact"; dir = 5},/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"B" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/machinery/atmospherics/pipe/manifold/visible/blue,/obj/item/weapon/reagent_containers/glass/beaker/cryoxadone,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"C" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/machinery/atmospherics/pipe/simple/visible/blue{ icon_state = "intact"; dir = 9},/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"D" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"E" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/machinery/organ_printer/flesh/mapped,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"F" = (/obj/effect/floor_decal/corner/blue/diagonal,/obj/machinery/organ_printer/robot/mapped,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"G" = (/obj/machinery/light_switch{pixel_x = -25},/obj/effect/floor_decal/corner/blue/diagonal,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"H" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/obj/effect/floor_decal/corner/blue/diagonal,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"I" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/effect/floor_decal/corner/blue/diagonal,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"J" = (/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/effect/floor_decal/corner/blue/diagonal,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"K" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/effect/floor_decal/corner/blue/diagonal,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"L" = (/obj/structure/cable,/obj/machinery/power/debug_items/infinite_generator,/obj/effect/floor_decal/corner/blue/diagonal,/turf/simulated/floor/tiled/white,/area/medical/surgery2) +"M" = (/obj/machinery/light,/obj/effect/floor_decal/corner/blue/diagonal,/turf/simulated/floor/tiled/white,/area/medical/surgery2) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaabaaacccccccccccccccaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaacdefghijiikiiicaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaacliiimjjniiiiicaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaacopqirnnniiiiscaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaactiiiuvwxiiiiicaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaacyiziiABCiiiiDcaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaacEiiiiiiiiiiiicaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaacFiiiiiiiiiiiicaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaciiiiiiiiiiiiicaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaacGiiiiiiiiiiiicaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaacHiiiiiiiiiiiIcaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaacJiiiiiiiiiiiicaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaacKiiiiiiiiiiiicaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaacLiiMiiiiiMiiicaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaacccccccccccccccaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/oldfare/backup/warfare-1.dmm b/maps/oldfare/backup/warfare-1.dmm new file mode 100644 index 00000000..11958f1b --- /dev/null +++ b/maps/oldfare/backup/warfare-1.dmm @@ -0,0 +1,98 @@ +"a" = (/obj/structure/dirt_wall,/turf/simulated/floor/dirty/indestructable,/area/homebase) +"b" = (/turf/simulated/floor/dirty/indestructable,/area/battlefield) +"c" = (/obj/structure/dirt_wall{icon_state = "dirt_wall"; dir = 1},/turf/simulated/floor/dirty/indestructable,/area/homebase) +"d" = (/obj/machinery/telecomms/allinone{intercept = 1},/turf/simulated/floor/dirty,/area/hallway) +"e" = (/turf/simulated/floor/dirty/indestructable,/area/homebase) +"f" = (/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/dirty/indestructable,/area/homebase) +"g" = (/turf/simulated/wall/concrete,/area/homebase) +"h" = (/obj/effect/landmark{name = "tdome1"},/turf/simulated/floor/dirty/indestructable,/area/homebase) +"i" = (/turf/simulated/wall/concrete,/area/battlefield) +"j" = (/obj/structure/barbwire,/turf/simulated/floor/dirty/indestructable,/area/battlefield) +"k" = (/obj/structure/dirt_wall{icon_state = "dirt_wall"; dir = 1},/turf/simulated/floor/dirty/indestructable,/area/battlefield) +"l" = (/obj/effect/landmark/start,/turf/simulated/floor/dirty/indestructable,/area/homebase) +"m" = (/obj/effect/landmark/test/safe_turf,/turf/simulated/floor/dirty/indestructable,/area/homebase) +"n" = (/obj/effect/landmark{name = "JoinLate"},/turf/simulated/floor/dirty/indestructable,/area/homebase) +"o" = (/obj/structure/dirt_wall{icon_state = "dirt_wall"; dir = 8},/turf/simulated/floor/dirty/indestructable,/area/battlefield) +"p" = (/obj/effect/landmark/start{name = "Red Soldier"},/turf/simulated/floor/dirty/indestructable,/area/homebase) +"q" = (/obj/effect/landmark/test/space_turf,/turf/simulated/floor/dirty/indestructable,/area/homebase) +"r" = (/obj/structure/dirt_wall{icon_state = "dirt_wall"; dir = 4},/turf/simulated/floor/dirty/indestructable,/area/battlefield) +"s" = (/obj/structure/barbwire,/turf/simulated/floor/dirty/indestructable,/area/homebase) +"t" = (/obj/structure/dirt_wall,/turf/simulated/floor/dirty/indestructable,/area/battlefield) + +(1,1,1) = {" +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeffffffffffffffffffffffffffffffffeeeeeee +eeaaaaaaaaaaaaaaaaaaeeaaaaaaaaaaaaaaaaaaee +sssssssssssssssssssseessssssssssssssssssss +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbjjjjjjbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbkkkkkkbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbjobiiiiiibrjbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbjobbbbbbbbrjbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbjobbbbbbbbrjbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbjobibbbbibrjbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbjobibbbbibrjbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbjobibbbbibrjbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbjobibbbbibrjbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbjobibbbbibrjbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbjobibbbbibrjbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbjobbbbbbbbrjbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbjobbbbbbbbrjbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbjobiiiiiibrjbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbttttttbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbjjjjjjbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +sssssssssssssssssssseessssssssssssssssssss +eecccccccccccccccccceeccccccccccccccccccee +eeeeeppppppppppppppppppppppppppppppppeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeegggggggggggeegggggggggggeeeeeeeee +eeeeeeeeegeeeeeeeeegeegeeeeeeeeegeeeeeeeee +eeeeeeeeegeeeeeeeeegeegeeeeeeeeegeeeeeeeee +eeeeeeeeegeeeeeeeeegeegeeeeeeeeegeeeeeeeee +eeeeeeeeegeeeeeeeeegeegeeeeeeeeegeeeeeeeee +eeeeeeeeegeeeeeeeeegeegeeeeeeeeegeeeeeeeee +eeeeeeeeegeeeeeeeeegeegeeeeeeeeegeeeeeeeee +eeeeeeeeegeeeeeeeeegeegeeeeeeeeegeeeeeeeee +eeeeeeeeegeeeeeeeeegeegeeeeeeeeegeeeeeeeee +eeeeeeeeegggggggggggeegggggggggggeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +hhhnnneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +hhhnnneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +hhhnnneemqeleeeeeeeeeeeeeeeeeeeeeeeeeeeeed +"} diff --git a/maps/oldfare/fullscreen.dmi b/maps/oldfare/fullscreen.dmi new file mode 100644 index 00000000..feea15e9 Binary files /dev/null and b/maps/oldfare/fullscreen.dmi differ diff --git a/maps/oldfare/jobs/blue/blue_fortress.dm b/maps/oldfare/jobs/blue/blue_fortress.dm new file mode 100644 index 00000000..68eb8538 --- /dev/null +++ b/maps/oldfare/jobs/blue/blue_fortress.dm @@ -0,0 +1,71 @@ +/datum/job/fortress/blue + title = "Blue Fortress Inhabitant" + is_blue_team = TRUE + selection_color = "#76abb2" + + equip(var/mob/living/carbon/human/H) + ..() + H.add_stats(rand(6,10), rand(6,10), rand(6,10)) + H.add_skills(rand(1, 5), rand(1,5), rand(1,5)) + H.warfare_faction = BLUE_TEAM + SSWarfare.blue.team += H + H.warfare_language_shit(LANGUAGE_BLUE) + +/datum/job/fortress/blue/chef + title = "Blue Chef" + outfit_type = /decl/hierarchy/outfit/job/service/chef/blue + access = list(access_hydroponics, access_bar, access_kitchen) + total_positions = 2 + social_class = SOCIAL_CLASS_MED + + equip(var/mob/living/carbon/human/H) + ..() + H.add_stats(rand(7,11), rand(7,12), rand(7,11), rand(10,15)) + H.add_skills(rand(4,6), rand(0,2), 0, rand(0,3)) + +/decl/hierarchy/outfit/job/service/chef/blue + back = /obj/item/weapon/storage/backpack/satchel + l_ear = /obj/item/device/radio/headset/raider + neck = /obj/item/weapon/reagent_containers/food/drinks/canteen + + +/datum/job/fortress/blue/practitioner + title = "Blue Practitioner" + outfit_type = /decl/hierarchy/outfit/job/medical/doctor/blue + access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics) + total_positions = -1 + social_class = SOCIAL_CLASS_MED + medical_skill = 10 + surgery_skill = 10 + ranged_skill = 0 + engineering_skill = 0 + melee_skill = 0 + auto_rifle_skill = 0 + semi_rifle_skill = 0 + sniper_skill = 0 + shotgun_skill = 0 + lmg_skill = 0 + smg_skill = 0 + + equip(var/mob/living/carbon/human/H) + ..() + H.set_trait(new/datum/trait/death_tolerant()) + H.add_stats(rand(8,12), rand(5,8), rand(5,7), rand(10,14)) + H.say(";[H.real_name] reporting for duty!") + //H.add_skills(rand(1,3), rand(1,3), rand(7,10), surgery = rand(8, 10)) + +/decl/hierarchy/outfit/job/medical/doctor/blue + //uniform = /obj/item/clothing/under/blue_uniform + back = /obj/item/weapon/storage/backpack/satchel/warfare + gloves = /obj/item/clothing/gloves/prac_gloves + suit = /obj/item/clothing/suit/prac_arpon + mask = /obj/item/clothing/mask/gas/prac_mask + shoes = /obj/item/clothing/shoes/prac_boots + //head = /obj/item/clothing/head/prac_cap + l_ear = /obj/item/device/radio/headset/raider + neck = /obj/item/weapon/reagent_containers/food/drinks/canteen + belt = /obj/item/weapon/storage/belt/medical/full + pda_type = null + id_type = /obj/item/weapon/card/id/dog_tag/blue + backpack_contents = list(/obj/item/ammo_magazine/handful/revolver = 1, /obj/item/weapon/gun/projectile/revolver/cpt = 1) + //backpack_contents = list(/obj/item/weapon/reagent_containers/hypospray/autoinjector/blood = 1, /obj/item/weapon/reagent_containers/hypospray/autoinjector/revive = 2, /obj/item/weapon/reagent_containers/hypospray/autoinjector/pain = 2, /obj/item/weapon/suture = 1, /obj/item/weapon/wirecutters = 1) \ No newline at end of file diff --git a/maps/oldfare/jobs/blue/blue_soldiers.dm b/maps/oldfare/jobs/blue/blue_soldiers.dm new file mode 100644 index 00000000..2d561853 --- /dev/null +++ b/maps/oldfare/jobs/blue/blue_soldiers.dm @@ -0,0 +1,409 @@ +/datum/job/soldier/blue_soldier + title = "Blue Soldier" + outfit_type = /decl/hierarchy/outfit/job/bluesoldier/soldier + is_blue_team = TRUE + selection_color = "#76abb2" + + auto_rifle_skill = 10 + semi_rifle_skill = 7 + sniper_skill = 3 + shotgun_skill = 6 + lmg_skill = 3 + smg_skill = 3 + + equip(var/mob/living/carbon/human/H) + H.warfare_faction = BLUE_TEAM + ..() + H.set_trait(new/datum/trait/hardcore()) + H.add_stats(rand(12,17), rand(10,16), rand(8,12)) + //H.add_skills(rand(6, 9), rand(6,9), rand(1,5)) + SSWarfare.blue.team += H + if(can_be_in_squad) + H.assign_random_squad(BLUE_TEAM) + H.fully_replace_character_name("Pvt. [H.real_name]") + H.warfare_language_shit(LANGUAGE_BLUE) + H.assign_random_quirk() + if(announced) + H.say(";Soldier reporting for duty!") + +/datum/job/soldier/blue_soldier/sgt + title = "Blue Squad Leader" + total_positions = 3 + social_class = SOCIAL_CLASS_MED + outfit_type = /decl/hierarchy/outfit/job/bluesoldier/sgt + can_be_in_squad = FALSE //They have snowflake squad bullshit. + + auto_rifle_skill = 10 + semi_rifle_skill = 10 + shotgun_skill = 10 + //open_when_dead = TRUE + + announced = FALSE + + equip(var/mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.verbs += /mob/living/carbon/human/proc/morale_boost + H.assign_squad_leader(BLUE_TEAM) + H.fully_replace_character_name("Sgt. [current_name]") + H.say(";[title] reporting for duty!") + + + +/datum/job/soldier/blue_soldier/medic + title = "Blue Medic" + outfit_type = /decl/hierarchy/outfit/job/bluesoldier/medic + can_be_in_squad = FALSE //We assign them to a squad seperately. + + //Skill defines + medical_skill = 10 + surgery_skill = 10 + engineering_skill = 4 + auto_rifle_skill = 3 + semi_rifle_skill = 10 + + announced = FALSE + + equip(var/mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.assign_random_squad(BLUE_TEAM, "medic") + H.set_trait(new/datum/trait/death_tolerant()) + H.fully_replace_character_name("Medic [current_name]") + H.say(";Medic reporting for duty!") + + +/datum/job/soldier/blue_soldier/engineer + title = "Blue Engineer" + outfit_type = /decl/hierarchy/outfit/job/bluesoldier/engineer + engineering_skill = 10 + auto_rifle_skill = 5 + semi_rifle_skill = 5 + smg_skill = 10 + shotgun_skill = 10 + + announced = FALSE + + equip(var/mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.add_stats(rand(15,17), rand(10,16), rand(12,16)) + H.fully_replace_character_name("Eng. [current_name]") + H.say(";Engineer reporting for duty!") + + +/datum/job/soldier/blue_soldier/sniper + title = "Blue Sniper" + total_positions = 2 + outfit_type = /decl/hierarchy/outfit/job/bluesoldier/sniper + auto_rifle_skill = 3 + semi_rifle_skill = 3 + sniper_skill = 10 + shotgun_skill = 3 + lmg_skill = 3 + smg_skill = 3 + open_when_dead = FALSE + can_be_in_squad = FALSE + + announced = FALSE + + equip(var/mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.fully_replace_character_name("Sniper [current_name]") + H.say(";Sniper reporting for duty!") + +/datum/job/soldier/blue_soldier/flame_trooper + title = "Blue Flame Trooper" + total_positions = 0 + outfit_type = /decl/hierarchy/outfit/job/bluesoldier/flamer + auto_rifle_skill = 8 + semi_rifle_skill = 8 + sniper_skill = 3 + shotgun_skill = 3 + lmg_skill = 3 + smg_skill = 3 + can_be_in_squad = FALSE + open_when_dead = FALSE + + announced = FALSE + + equip(var/mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.fully_replace_character_name("FT. [current_name]") + H.add_stats(18, rand(10,16), rand(15,18)) + H.say(";Flame Trooper reporting for duty!") + H.unlock_achievement(new/datum/achievement/flamer()) + +/datum/job/soldier/blue_soldier/sentry + title = "Blue Sentry" + total_positions = 1 + outfit_type = /decl/hierarchy/outfit/job/bluesoldier/sentry + auto_rifle_skill = 5 + semi_rifle_skill = 5 + sniper_skill = 3 + shotgun_skill = 3 + lmg_skill = 10 + smg_skill = 3 + can_be_in_squad = FALSE + open_when_dead = TRUE + + announced = FALSE + + equip(var/mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.fully_replace_character_name("Sentry [current_name]") + H.add_stats(18, rand(10,16), rand(15,18)) + H.say(";Sentry reporting for duty!") + + + +/datum/job/soldier/blue_soldier/captain + title = "Blue Captain" + total_positions = 1 + req_admin_notify = TRUE + social_class = SOCIAL_CLASS_HIGH + outfit_type = /decl/hierarchy/outfit/job/bluesoldier/leader + can_be_in_squad = FALSE //They're above all the squads. + sniper_skill = 10 + open_when_dead = TRUE + + announced = FALSE + + equip(var/mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.fully_replace_character_name("Cpt. [current_name]") + H.get_idcard()?.access = get_all_accesses() + var/obj/O = H.get_equipped_item(slot_s_store) + if(O) + qdel(O) + H.verbs += list( + /mob/living/carbon/human/proc/help_me, + /mob/living/carbon/human/proc/retreat, + /mob/living/carbon/human/proc/announce, + /mob/living/carbon/human/proc/give_order, + /mob/living/carbon/human/proc/check_reinforcements + ) + H.voice_in_head(pick(GLOB.lone_thoughts)) + to_chat(H, "Artillery Password: [GLOB.cargo_password]") + H.mind.store_memory("Artillery Password: [GLOB.cargo_password]") + H.say(";[H.real_name] [pick("taking","in")] command!") + +/datum/job/soldier/blue_soldier/scout + title = "Blue Scavenger" + total_positions = -1 + outfit_type = /decl/hierarchy/outfit/job/bluesoldier/scout + child_role = TRUE + can_be_in_squad = FALSE + //Kids suck at everything. + specific_skill = TRUE + medical_skill = 1 + surgery_skill = 1 + ranged_skill = 1 + engineering_skill = 1 + melee_skill = 1 + auto_rifle_skill = 1 + semi_rifle_skill = 1 + sniper_skill = 1 + shotgun_skill = 1 + lmg_skill = 1 + smg_skill = 1 + + announced = FALSE + + equip(mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.fast_stripper = TRUE + H.add_stats(rand(3,6), rand(12,16), rand(6,9)) + //H.add_skills(rand(1,3), rand(1,3), rand(0,3), rand(0,1)) + qdel(H.get_equipped_item(slot_s_store)) // they cant even handle guns + H.fully_replace_character_name("Scav. [current_name]") + H.set_trait(new/datum/trait/child()) + H.say(";Scav reporting for duty!") + +/decl/hierarchy/outfit/job/bluesoldier + name = OUTFIT_JOB_NAME("Soldier") + head = /obj/item/clothing/head/helmet/bluehelmet + uniform = /obj/item/clothing/under/blue_uniform + back = /obj/item/weapon/storage/backpack/satchel/warfare + shoes = /obj/item/clothing/shoes/jackboots + l_ear = null // /obj/item/device/radio/headset/raider + l_pocket = /obj/item/weapon/storage/box/ifak // /obj/item/stack/medical/bruise_pack + suit = /obj/item/clothing/suit/armor/bluecoat + gloves = /obj/item/clothing/gloves/thick/swat/combat/warfare + neck = /obj/item/weapon/reagent_containers/food/drinks/canteen + pda_type = null + id_type = /obj/item/weapon/card/id/dog_tag/blue + flags = OUTFIT_NO_BACKPACK|OUTFIT_NO_SURVIVAL_GEAR + +/decl/hierarchy/outfit/job/bluesoldier/soldier/equip() + if(aspect_chosen(/datum/aspect/lone_rider)) + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty/leverchester + r_pocket = /obj/item/ammo_box/rifle + backpack_contents = initial(backpack_contents) + + else if(prob(25)) + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty/leverchester + r_pocket = /obj/item/ammo_box/rifle + backpack_contents = list(/obj/item/weapon/grenade/smokebomb = 1) + + else if(prob(50)) + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty/bayonet + r_pocket = /obj/item/ammo_box/rifle + backpack_contents = list(/obj/item/weapon/grenade/smokebomb = 1) + + else + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty + r_pocket = /obj/item/ammo_box/rifle + backpack_contents = list(/obj/item/weapon/grenade/smokebomb = 1) + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/torch/self_lit = 1) + belt = /obj/item/ammo_box/flares/blue + ..() + + +/decl/hierarchy/outfit/job/bluesoldier/sgt + //head = /obj/item/clothing/head/helmet/bluehelmet/leader + suit_store = /obj/item/weapon/gun/projectile/automatic/m22/warmonger + r_pocket = /obj/item/ammo_magazine/c45rifle/akarabiner + +/decl/hierarchy/outfit/job/bluesoldier/sgt/equip() + /* + if(prob(15)) + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/shitty/sawn + r_pocket = /obj/item/ammo_box/shotgun + */ + if(prob(25)) + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty/bayonet + r_pocket = /obj/item/ammo_box/rifle + backpack_contents = list(/obj/item/weapon/grenade/smokebomb = 1, /obj/item/device/binoculars = 1) + else + suit_store = /obj/item/weapon/gun/projectile/automatic/m22/warmonger/m14/battlerifle/rsc + r_pocket = /obj/item/ammo_magazine/a762/rsc + backpack_contents = list(/obj/item/ammo_magazine/a762/rsc = 3, /obj/item/weapon/grenade/smokebomb = 1, /obj/item/device/binoculars = 1) + + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/torch/self_lit = 1) + belt = /obj/item/ammo_box/flares/blue + ..() + +/decl/hierarchy/outfit/job/bluesoldier/engineer + r_pocket = /obj/item/ammo_magazine/mc9mmt/machinepistol + l_pocket = /obj/item/weapon/wirecutters + //belt = /obj/item/weapon/shovel + suit_store = /obj/item/weapon/gun/projectile/automatic/machinepistol + back = /obj/item/weapon/storage/backpack/warfare + backpack_contents = list(/obj/item/stack/barbwire = 1, /obj/item/weapon/shovel = 1, /obj/item/defensive_barrier = 4, /obj/item/weapon/storage/box/ifak = 1) + +/decl/hierarchy/outfit/job/bluesoldier/engineer/equip() + if(prob(1))//Rare engineer spawn + suit_store = /obj/item/weapon/gun/projectile/automatic/autoshotty + r_pocket = /obj/item/weapon/shovel + belt = /obj/item/weapon/storage/belt/autoshotty + backpack_contents = list(/obj/item/stack/barbwire = 1, /obj/item/defensive_barrier = 3, /obj/item/weapon/storage/box/ifak = 1, /obj/item/weapon/grenade/smokebomb = 1) + else if(prob(50)) + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/shitty + r_pocket = /obj/item/ammo_box/shotgun + belt = /obj/item/weapon/shovel + backpack_contents = list(/obj/item/stack/barbwire = 1, /obj/item/defensive_barrier = 3, /obj/item/weapon/storage/box/ifak = 1, /obj/item/weapon/grenade/smokebomb = 1) + else + suit_store = /obj/item/weapon/gun/projectile/automatic/machinepistol + r_pocket = /obj/item/weapon/shovel + belt = /obj/item/weapon/storage/belt/warfare + backpack_contents = list(/obj/item/stack/barbwire = 1, /obj/item/defensive_barrier = 3, /obj/item/weapon/storage/box/ifak = 1, /obj/item/weapon/grenade/smokebomb = 1) + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/ammo_box/flares/blue = 1, /obj/item/torch/self_lit = 1) + ..() + + +/decl/hierarchy/outfit/job/bluesoldier/medic + belt = /obj/item/weapon/storage/belt/medical/full + r_pocket = /obj/item/ammo_magazine/c45rifle/akarabiner + l_pocket = /obj/item/stack/medical/bruise_pack + suit_store = /obj/item/weapon/gun/projectile/automatic/m22/warmonger + gloves = /obj/item/clothing/gloves/latex + +/decl/hierarchy/outfit/job/bluesoldier/medic/equip() + if(prob(50)) + suit_store = /obj/item/weapon/gun/projectile/automatic/m22/warmonger + r_pocket = /obj/item/ammo_magazine/c45rifle/akarabiner + backpack_contents = list(/obj/item/ammo_magazine/c45rifle/akarabiner = 3, /obj/item/weapon/grenade/smokebomb = 1) + + else + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty/bayonet + r_pocket = /obj/item/ammo_box/rifle + backpack_contents = list(/obj/item/weapon/grenade/smokebomb = 1) + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/ammo_box/flares/blue = 1, /obj/item/torch/self_lit = 1) + ..() + +/decl/hierarchy/outfit/job/bluesoldier/sniper + l_ear = /obj/item/device/radio/headset/blue_team/all + suit = /obj/item/clothing/suit/armor/bluecoat/sniper + head = /obj/item/clothing/head/helmet/bluehelmet/sniper + suit_store = /obj/item/weapon/gun/projectile/heavysniper + belt = /obj/item/weapon/gun/projectile/revolver //Backup weapon. + r_pocket = /obj/item/ammo_box/ptsd + backpack_contents = list(/obj/item/weapon/grenade/smokebomb = 1) + +/decl/hierarchy/outfit/job/bluesoldier/sniper/equip() + if(prob(50)) + belt = /obj/item/weapon/gun/projectile/warfare + else + belt = /obj/item/weapon/gun/projectile/revolver + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/ammo_box/flares/blue = 1, /obj/item/torch/self_lit = 1) + ..() + +/decl/hierarchy/outfit/job/bluesoldier/flamer + l_ear = /obj/item/device/radio/headset/blue_team/all + suit = /obj/item/clothing/suit/fire/blue + head = /obj/item/clothing/head/helmet/bluehelmet/fire + belt = /obj/item/weapon/gun/projectile/automatic/flamer + backpack_contents = list(/obj/item/ammo_magazine/flamer = 4, /obj/item/weapon/grenade/smokebomb = 1) + +/decl/hierarchy/outfit/job/bluesoldier/sentry + l_ear = /obj/item/device/radio/headset/blue_team/all + suit = /obj/item/clothing/suit/armor/sentry/blue + head = /obj/item/clothing/head/helmet/sentryhelm/blue + suit_store = /obj/item/weapon/gun/projectile/automatic/mg08 + backpack_contents = list(/obj/item/ammo_magazine/box/a556/mg08 = 3, /obj/item/weapon/grenade/smokebomb = 1) + +/decl/hierarchy/outfit/job/bluesoldier/sentry/equip() + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/torch/self_lit = 1) + belt = /obj/item/ammo_box/flares/blue + ..() + +/decl/hierarchy/outfit/job/bluesoldier/leader + glasses = /obj/item/clothing/glasses/sunglasses + suit = /obj/item/clothing/suit/armor/bluecoat/leader + head = /obj/item/clothing/head/warfare_officer/blueofficer + l_ear = /obj/item/device/radio/headset/blue_team/all + belt = /obj/item/weapon/gun/projectile/revolver/cpt + r_pocket = /obj/item/device/binoculars + backpack_contents = list(/obj/item/ammo_magazine/handful/revolver = 2, /obj/item/weapon/grenade/smokebomb = 1) + +/decl/hierarchy/outfit/job/bluesoldier/leader/equip() + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/ammo_box/flares/blue = 1 , /obj/item/torch/self_lit = 1) + ..() + +/decl/hierarchy/outfit/job/bluesoldier/scout + //suit = /obj/item/clothing/suit/child_coat/blue + l_ear = /obj/item/device/radio/headset/blue_team/all + uniform = /obj/item/clothing/under/child_jumpsuit/warfare/blue + shoes = /obj/item/clothing/shoes/child_shoes + gloves = null + r_pocket = /obj/item/device/binoculars + backpack_contents = list(/obj/item/weapon/grenade/smokebomb = 1) + +/decl/hierarchy/outfit/job/bluesoldier/scout/equip() + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/torch/self_lit = 1) + belt = /obj/item/ammo_box/flares/blue + ..() \ No newline at end of file diff --git a/maps/oldfare/jobs/captain_verbs.dm b/maps/oldfare/jobs/captain_verbs.dm new file mode 100644 index 00000000..98f497ed --- /dev/null +++ b/maps/oldfare/jobs/captain_verbs.dm @@ -0,0 +1,183 @@ +/mob/living/carbon/human/proc/help_me() + set name = "Help me!" + set category = "Captain" + + if(stat) + return + + var/is_blue = job_master.GetJobByTitle(job).is_blue_team + var/class = "red_team" + var/datum/team/T = SSWarfare.red + if(is_blue) + class = "blue_team" + T = SSWarfare.blue + + if(T.checkCooldown("Help me!")) + to_chat(src, "I can't overuse this!") + return + + for(var/mob/living/carbon/human/H in T.team) + if(H == src) + continue + H.tracking.track(src) + + to_chat(T.team, "

            Your Captain requires help!

            ") + + T.startCooldown("Help me!") + sound_to(T.team, 'sound/effects/klaxon_alarm.ogg') + +/mob/living/carbon/human/proc/retreat() + set name = "Retreat!" + set category = "Captain" + if(stat) + return + + var/is_blue = job_master.GetJobByTitle(job).is_blue_team + var/class = "red_team" + var/datum/team/T = SSWarfare.red + if(is_blue) + class = "blue_team" + T = SSWarfare.blue + + if(T.checkCooldown("Retreat!")) + to_chat(src, "I can't overuse this!") + return + + to_chat(T.team, "

            Your Captain has ordered a retreat!

            ") + + T.startCooldown("Retreat!") + sound_to(T.team, 'sound/effects/klaxon_alarm.ogg') + +/mob/living/carbon/human/proc/announce() + set name = "Make Announcement!" + set category = "Captain" + if(stat) + return + + var/is_blue = job_master.GetJobByTitle(job).is_blue_team + var/class = "red_team" + var/datum/team/T = SSWarfare.red + if(is_blue) + class = "blue_team" + T = SSWarfare.blue + + if(T.checkCooldown("Make Announcement!")) + to_chat(src, "I can't overuse this!") + return + + var/announcement = sanitize(input(src, "What would you like to announce?", "Announcement")) + if(!announcement) + return + + if(findtext(announcement, config.ic_filter_regex)) + var/warning_message = "Bro you just tried to announce cringe! You're going to loose subscribers! Check the server rules!
            The bolded terms are disallowed: "" + var/list/words = splittext(announcement, " ") + var/cringe = "" + for (var/word in words) + if (findtext(word, config.ic_filter_regex)) + warning_message = "[warning_message][word] " + cringe += "/[word]" + else + warning_message = "[warning_message][word] " + + + warning_message = trim(warning_message) + to_chat(src, "[warning_message]"
            ") + log_and_message_admins("[src] just tried to ANNOUNCE cringe: [cringe]", src) + return + + to_chat(T.team, "

            Announcement from Captain:
            [announcement]

            ") + + T.startCooldown("Make Announcement!") + sound_to(T.team, 'sound/effects/klaxon_alarm.ogg') + +/mob/living/carbon/human/proc/give_order() + set name = "Give Order!" + set category = "Captain" + if(stat) + return + + var/is_blue = job_master.GetJobByTitle(job).is_blue_team + var/class = "red_team" + var/datum/team/T = SSWarfare.red + if(is_blue) + class = "blue_team" + T = SSWarfare.blue + + if(T.checkCooldown("Give Order!")) + to_chat(src, "I can't overuse this!") + return + + var/announcement = input(src, "What would you like to command?", "Give Order") + if(!announcement) + return + if(findtext(announcement, config.ic_filter_regex)) + var/warning_message = "Bro you just tried to announce cringe! You're going to loose subscribers! Check the server rules!
            The bolded terms are disallowed: "" + var/list/words = splittext(announcement, " ") + var/cringe = "" + for (var/word in words) + if (findtext(word, config.ic_filter_regex)) + warning_message = "[warning_message][word] " + cringe += "/[word]" + else + warning_message = "[warning_message][word] " + + + warning_message = trim(warning_message) + to_chat(src, "[warning_message]"
            ") + log_and_message_admins("[src] just tried to ANNOUNCE cringe: [cringe]", src) + return + to_chat(T.team, "

            Order from Captain:
            [announcement]

            ") + log_and_message_admins("[src] gave the order: [announcement].", src) + + T.startCooldown("Give Order!") + sound_to(T.team, 'sound/effects/klaxon_alarm.ogg') + + +/mob/living/carbon/human/proc/check_reinforcements() + set name = "Check Reinforcements" + set category = "Captain" + + var/is_blue = job_master.GetJobByTitle(job).is_blue_team + var/datum/team/T = SSWarfare.red + if(is_blue) + T = SSWarfare.blue + if(T.checkCooldown("Check Reinforcements")) + to_chat(src, "I can't overuse this!") + return + if(is_blue) + to_chat(src, "Reinforcements Left: [SSWarfare.blue.left]") + else + to_chat(src, "Reinforcements Left: [SSWarfare.red.left]") + T.startCooldown("Check Reinforcements") + + + +/mob/living/carbon/human/proc/morale_boost() + set name = "Morale Boost" + set category = "Squad Leader" + if(stat) + return + + var/is_blue = job_master.GetJobByTitle(job).is_blue_team + var/class = "red_team" + var/datum/team/T = SSWarfare.red + if(is_blue) + class = "blue_team" + T = SSWarfare.blue + + switch(alert(src,"This has a long cool down are you sure you wish to use this?", "Cooldown", "Yes", "No")) + if("No") + to_chat(src, "You decide not to use this power right now.") + return + + if(T.checkCooldown("Morale Boost")) + to_chat(src, "I can't overuse this!") + return + + for(var/mob/living/carbon/human/H in T.team) + H.add_event("morale boost", /datum/happiness_event/morale_boost) + + T.startCooldown("Morale Boost", 10 MINUTES) + sound_to(T.team, 'sound/effects/klaxon_alarm.ogg') + to_chat(T.team, "

            OOORAH!

            ") \ No newline at end of file diff --git a/maps/oldfare/jobs/fortress.dm b/maps/oldfare/jobs/fortress.dm new file mode 100644 index 00000000..888e6c06 --- /dev/null +++ b/maps/oldfare/jobs/fortress.dm @@ -0,0 +1,11 @@ +/datum/job/fortress + title = "Fortress Inhabitant" + department = "Service" + department_flag = SRV + total_positions = 3 + create_record = FALSE + account_allowed = TRUE + social_class = SOCIAL_CLASS_MIN + has_email = FALSE + latejoin_at_spawnpoints = TRUE + announced = TRUE \ No newline at end of file diff --git a/maps/oldfare/jobs/red/red_fortress.dm b/maps/oldfare/jobs/red/red_fortress.dm new file mode 100644 index 00000000..b28f73b6 --- /dev/null +++ b/maps/oldfare/jobs/red/red_fortress.dm @@ -0,0 +1,71 @@ +/datum/job/fortress/red + title = "Red Fortress Inhabitant" + is_red_team = TRUE + selection_color = "#b27676" + + equip(var/mob/living/carbon/human/H) + ..() + H.add_stats(rand(6,10), rand(6,10), rand(6,10)) + H.add_skills(rand(1, 5), rand(1,5), rand(1,5)) + H.warfare_faction = RED_TEAM + SSWarfare.red.team += H + H.warfare_language_shit(LANGUAGE_RED) + +/datum/job/fortress/red/chef + title = "Red Chef" + outfit_type = /decl/hierarchy/outfit/job/service/chef/red + access = list(access_hydroponics, access_bar, access_kitchen) + total_positions = 2 + social_class = SOCIAL_CLASS_MED + + equip(var/mob/living/carbon/human/H) + ..() + H.add_stats(rand(7,11), rand(7,12), rand(7,11), rand(10,15)) + H.add_skills(rand(4,6), rand(0,2), 0, rand(0,3)) + +/decl/hierarchy/outfit/job/service/chef/red + back = /obj/item/weapon/storage/backpack/satchel + l_ear = /obj/item/device/radio/headset/syndicate + neck = /obj/item/weapon/reagent_containers/food/drinks/canteen + + +/datum/job/fortress/red/practitioner + title = "Red Practitioner" + outfit_type = /decl/hierarchy/outfit/job/medical/doctor/red + access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics) + total_positions = -1 + social_class = SOCIAL_CLASS_MED + medical_skill = 10 + surgery_skill = 10 + ranged_skill = 0 + engineering_skill = 0 + melee_skill = 0 + auto_rifle_skill = 0 + semi_rifle_skill = 0 + sniper_skill = 0 + shotgun_skill = 0 + lmg_skill = 0 + smg_skill = 0 + + equip(var/mob/living/carbon/human/H) + ..() + H.set_trait(new/datum/trait/death_tolerant()) + H.add_stats(rand(8,11), rand(5,8), rand(5,7), rand(10,14)) + //H.add_skills(rand(1,3), rand(1,3), rand(7,10), surgery = rand(8, 10)) + H.say(";Practitioner reporting for duty!") + +/decl/hierarchy/outfit/job/medical/doctor/red + //uniform = /obj/item/clothing/under/red_uniform + back = /obj/item/weapon/storage/backpack/satchel/warfare + gloves = /obj/item/clothing/gloves/prac_gloves + suit = /obj/item/clothing/suit/prac_arpon + mask = /obj/item/clothing/mask/gas/prac_mask + shoes = /obj/item/clothing/shoes/prac_boots + //head = /obj/item/clothing/head/prac_cap + l_ear = /obj/item/device/radio/headset/syndicate + neck = /obj/item/weapon/reagent_containers/food/drinks/canteen + belt = /obj/item/weapon/storage/belt/medical/full + pda_type = null + id_type = /obj/item/weapon/card/id/dog_tag/red + backpack_contents = list(/obj/item/ammo_magazine/handful/revolver = 1, /obj/item/weapon/gun/projectile/revolver/cpt = 1) + //backpack_contents = list(/obj/item/weapon/reagent_containers/hypospray/autoinjector/blood = 1, /obj/item/weapon/reagent_containers/hypospray/autoinjector/revive = 2, /obj/item/weapon/reagent_containers/hypospray/autoinjector/pain = 2, /obj/item/weapon/suture = 1, /obj/item/weapon/wirecutters = 1) diff --git a/maps/oldfare/jobs/red/red_soldiers.dm b/maps/oldfare/jobs/red/red_soldiers.dm new file mode 100644 index 00000000..21d4b733 --- /dev/null +++ b/maps/oldfare/jobs/red/red_soldiers.dm @@ -0,0 +1,408 @@ +/datum/job/soldier/red_soldier + title = "Red Soldier" + outfit_type = /decl/hierarchy/outfit/job/redsoldier/soldier + is_red_team = TRUE + selection_color = "#b27676" + + auto_rifle_skill = 10 + semi_rifle_skill = 7 + sniper_skill = 3 + shotgun_skill = 6 + lmg_skill = 3 + smg_skill = 3 + + equip(var/mob/living/carbon/human/H) + H.warfare_faction = RED_TEAM + ..() + H.set_trait(new/datum/trait/hardcore()) + H.add_stats(rand(12,17), rand(10,16), rand(8,12)) + //H.add_skills(rand(6, 9), rand(6,9), rand(1,5)) + SSWarfare.red.team += H + if(can_be_in_squad) + H.assign_random_squad(RED_TEAM) + H.fully_replace_character_name("Pvt. [H.real_name]") + H.warfare_language_shit(LANGUAGE_RED) + H.assign_random_quirk() + if(announced) + H.say(";Soldier reporting for duty!") + +/datum/job/soldier/red_soldier/sgt + title = "Red Squad Leader" + total_positions = 3 + social_class = SOCIAL_CLASS_MED + outfit_type = /decl/hierarchy/outfit/job/redsoldier/sgt + can_be_in_squad = FALSE //They have snowflake shit for squads. + + auto_rifle_skill = 10 + semi_rifle_skill = 10 + shotgun_skill = 10 + //open_when_dead = TRUE + + announced = FALSE + + equip(var/mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.verbs += /mob/living/carbon/human/proc/morale_boost + H.assign_squad_leader(RED_TEAM) + H.fully_replace_character_name("Sgt. [current_name]") + H.say(";[title] reporting for duty!") + + +/datum/job/soldier/red_soldier/medic + title = "Red Medic" + outfit_type = /decl/hierarchy/outfit/job/redsoldier/medic + can_be_in_squad = FALSE //We assign them to a squad seperately. + + //Skill defines + medical_skill = 10 + surgery_skill = 10 + engineering_skill = 4 + auto_rifle_skill = 3 + semi_rifle_skill = 10 + + announced = FALSE + + equip(var/mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.assign_random_squad(RED_TEAM, "medic") + H.set_trait(new/datum/trait/death_tolerant()) + H.fully_replace_character_name("Medic [current_name]") + //H.add_skills(rand(6, 9), rand(5,7), rand(6,10), surgery = rand(6,10)) + + H.say(";Medic reporting for duty!") + + +/datum/job/soldier/red_soldier/engineer + title = "Red Engineer" + outfit_type = /decl/hierarchy/outfit/job/redsoldier/engineer + engineering_skill = 10 + auto_rifle_skill = 5 + semi_rifle_skill = 5 + smg_skill = 10 + shotgun_skill = 10 + + announced = FALSE + + equip(var/mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.add_stats(rand(15,17), rand(10,16), rand(12,16)) + H.fully_replace_character_name("Eng. [current_name]") + H.say(";Engineer reporting for duty!") + +/datum/job/soldier/red_soldier/sniper + title = "Red Sniper" + total_positions = 2 + outfit_type = /decl/hierarchy/outfit/job/redsoldier/sniper + auto_rifle_skill = 3 + semi_rifle_skill = 3 + sniper_skill = 10 + shotgun_skill = 3 + lmg_skill = 3 + smg_skill = 3 + open_when_dead = TRUE + can_be_in_squad = FALSE + + announced = FALSE + + equip(var/mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.fully_replace_character_name("Sniper [current_name]") + H.say(";Sniper reporting for duty!") + + +/datum/job/soldier/red_soldier/sentry + title = "Red Sentry" + total_positions = 1 + outfit_type = /decl/hierarchy/outfit/job/redsoldier/sentry + auto_rifle_skill = 5 + semi_rifle_skill = 5 + sniper_skill = 3 + shotgun_skill = 3 + lmg_skill = 10 + smg_skill = 3 + can_be_in_squad = FALSE + open_when_dead = TRUE + + announced = FALSE + + equip(var/mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.fully_replace_character_name("Sentry [current_name]") + H.add_stats(18, rand(10,16), rand(15,18)) + H.say(";Sentry reporting for duty!") + +/datum/job/soldier/red_soldier/flame_trooper + title = "Red Flame Trooper" + total_positions = 0 + outfit_type = /decl/hierarchy/outfit/job/redsoldier/flamer + auto_rifle_skill = 8 + semi_rifle_skill = 8 + sniper_skill = 3 + shotgun_skill = 3 + lmg_skill = 3 + smg_skill = 3 + can_be_in_squad = FALSE + open_when_dead = FALSE + + announced = FALSE + + equip(var/mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.fully_replace_character_name("FT. [current_name]") + H.add_stats(18, rand(10,16), rand(15,18)) + H.say(";Flame Trooper reporting for duty!") + H.unlock_achievement(new/datum/achievement/flamer()) + +/datum/job/soldier/red_soldier/captain + title = "Red Captain" + total_positions = 1 + req_admin_notify = TRUE + social_class = SOCIAL_CLASS_HIGH + outfit_type = /decl/hierarchy/outfit/job/redsoldier/leader + can_be_in_squad = FALSE + sniper_skill = 10 + open_when_dead = TRUE + + announced = FALSE + + equip(var/mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.fully_replace_character_name("Cpt. [current_name]") + H.get_idcard()?.access = get_all_accesses() + var/obj/O = H.get_equipped_item(slot_s_store) + if(O) + qdel(O) + H.verbs += list( + /mob/living/carbon/human/proc/help_me, + /mob/living/carbon/human/proc/retreat, + /mob/living/carbon/human/proc/announce, + /mob/living/carbon/human/proc/give_order, + /mob/living/carbon/human/proc/check_reinforcements + ) + H.voice_in_head(pick(GLOB.lone_thoughts)) + to_chat(H, "Artillery Password: [GLOB.cargo_password]") + H.mind.store_memory("Artillery Password: [GLOB.cargo_password]") + H.say(";[H.real_name] [pick("taking","in")] command!") + +/datum/job/soldier/red_soldier/scout + title = "Red Scavenger" + total_positions = -1 + outfit_type = /decl/hierarchy/outfit/job/redsoldier/scout + child_role = TRUE + can_be_in_squad = FALSE + //Kids suck at everything. + specific_skill = TRUE + medical_skill = 0 + surgery_skill = 0 + ranged_skill = 0 + engineering_skill = 0 + melee_skill = 0 + auto_rifle_skill = 0 + semi_rifle_skill = 0 + sniper_skill = 0 + shotgun_skill = 0 + lmg_skill = 0 + smg_skill = 0 + + announced = FALSE + + equip(mob/living/carbon/human/H) + var/current_name = H.real_name + ..() + H.fast_stripper = TRUE + H.add_stats(rand(3,6), rand(12,16), rand(6,9)) + qdel(H.get_equipped_item(slot_s_store)) // they cant even handle guns + H.fully_replace_character_name("Scav. [current_name]") + H.set_trait(new/datum/trait/child()) + H.say(";Scav reporting for duty!") + +/decl/hierarchy/outfit/job/redsoldier + name = OUTFIT_JOB_NAME("Soldier") + head = /obj/item/clothing/head/helmet/redhelmet + uniform = /obj/item/clothing/under/red_uniform + shoes = /obj/item/clothing/shoes/jackboots + l_ear = null // /obj/item/device/radio/headset/syndicate + l_pocket = /obj/item/weapon/storage/box/ifak // /obj/item/stack/medical/bruise_pack + suit = /obj/item/clothing/suit/armor/redcoat + gloves = /obj/item/clothing/gloves/thick/swat/combat/warfare + back = /obj/item/weapon/storage/backpack/satchel/warfare + neck = /obj/item/weapon/reagent_containers/food/drinks/canteen + pda_type = null + id_type = /obj/item/weapon/card/id/dog_tag/red + flags = OUTFIT_NO_BACKPACK|OUTFIT_NO_SURVIVAL_GEAR + + + +/decl/hierarchy/outfit/job/redsoldier/soldier/equip() + if(aspect_chosen(/datum/aspect/lone_rider)) + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty/leverchester + r_pocket = /obj/item/ammo_box/rifle + backpack_contents = initial(backpack_contents) + + else if(prob(25)) + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty/leverchester + r_pocket = /obj/item/ammo_box/rifle + backpack_contents = list(/obj/item/weapon/grenade/smokebomb = 1) + + else if(prob(50)) + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty/bayonet + r_pocket = /obj/item/ammo_box/rifle + backpack_contents = list(/obj/item/weapon/grenade/smokebomb = 1) + + else + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty + r_pocket = /obj/item/ammo_box/rifle + backpack_contents = list(/obj/item/weapon/grenade/smokebomb = 1) + + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/torch/self_lit = 1) + belt = /obj/item/ammo_box/flares + ..() + +/decl/hierarchy/outfit/job/redsoldier/sgt + suit_store = /obj/item/weapon/gun/projectile/automatic/m22/warmonger + //head = /obj/item/clothing/head/helmet/redhelmet/leader + r_pocket = /obj/item/ammo_magazine/c45rifle/akarabiner + +/decl/hierarchy/outfit/job/redsoldier/sgt/equip() + /* + if(prob(15)) + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/shitty/sawn + r_pocket = /obj/item/ammo_box/shotgun + */ + if(prob(25)) + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty/bayonet + r_pocket = /obj/item/ammo_box/rifle + backpack_contents = list(/obj/item/weapon/grenade/smokebomb = 1, /obj/item/device/binoculars = 1) + else + suit_store = /obj/item/weapon/gun/projectile/automatic/m22/warmonger/m14/battlerifle/rsc + r_pocket = /obj/item/ammo_magazine/a762/rsc + backpack_contents = list(/obj/item/ammo_magazine/a762/rsc = 3, /obj/item/weapon/grenade/smokebomb = 1, /obj/item/device/binoculars = 1) + + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/torch/self_lit = 1) + belt = /obj/item/ammo_box/flares + ..() + + +/decl/hierarchy/outfit/job/redsoldier/engineer + r_pocket = /obj/item/ammo_magazine/mc9mmt/machinepistol + l_pocket = /obj/item/weapon/wirecutters + suit_store = /obj/item/weapon/gun/projectile/automatic/machinepistol/wooden + back = /obj/item/weapon/storage/backpack/warfare + backpack_contents = list(/obj/item/stack/barbwire = 1, /obj/item/weapon/shovel = 1, /obj/item/defensive_barrier = 4, /obj/item/weapon/storage/box/ifak = 1) + +/decl/hierarchy/outfit/job/redsoldier/engineer/equip() + if(prob(1))//Rare engineer spawn + suit_store = /obj/item/weapon/gun/projectile/automatic/autoshotty + r_pocket = /obj/item/weapon/shovel + belt = /obj/item/weapon/storage/belt/autoshotty + backpack_contents = list(/obj/item/stack/barbwire = 1, /obj/item/defensive_barrier = 3, /obj/item/weapon/storage/box/ifak = 1, /obj/item/weapon/grenade/smokebomb = 1) + else if(prob(50)) + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/shitty + r_pocket = /obj/item/ammo_box/shotgun + belt = /obj/item/weapon/shovel + backpack_contents = list(/obj/item/stack/barbwire = 1, /obj/item/defensive_barrier = 3, /obj/item/weapon/storage/box/ifak = 1, /obj/item/weapon/grenade/smokebomb = 1) + else + suit_store = /obj/item/weapon/gun/projectile/automatic/machinepistol + r_pocket = /obj/item/weapon/shovel + belt = /obj/item/weapon/storage/belt/warfare + backpack_contents = list(/obj/item/stack/barbwire = 1, /obj/item/defensive_barrier = 3, /obj/item/weapon/storage/box/ifak = 1, /obj/item/weapon/grenade/smokebomb = 1) + + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/ammo_box/flares = 1, /obj/item/torch/self_lit = 1) + ..() + + +/decl/hierarchy/outfit/job/redsoldier/sentry + l_ear = /obj/item/device/radio/headset/red_team/all + suit = /obj/item/clothing/suit/armor/sentry/red + head = /obj/item/clothing/head/helmet/sentryhelm/red + suit_store = /obj/item/weapon/gun/projectile/automatic/mg08 + backpack_contents = list(/obj/item/ammo_magazine/box/a556/mg08 = 3, /obj/item/weapon/grenade/smokebomb = 1) + +/decl/hierarchy/outfit/job/redsoldier/sentry/equip() + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/ammo_box/flares = 1, /obj/item/torch/self_lit = 1) + ..() + +/decl/hierarchy/outfit/job/redsoldier/flamer + l_ear = /obj/item/device/radio/headset/red_team/all + suit = /obj/item/clothing/suit/fire/red + head = /obj/item/clothing/head/helmet/redhelmet/fire + belt = /obj/item/weapon/gun/projectile/automatic/flamer + backpack_contents = list(/obj/item/ammo_magazine/flamer = 4, /obj/item/weapon/grenade/smokebomb = 1) + +/decl/hierarchy/outfit/job/redsoldier/sniper + l_ear = /obj/item/device/radio/headset/red_team/all + suit = /obj/item/clothing/suit/armor/redcoat/sniper + head = /obj/item/clothing/head/helmet/redhelmet/sniper + suit_store = /obj/item/weapon/gun/projectile/heavysniper + belt = /obj/item/weapon/gun/projectile/revolver //Backup weapon. + r_pocket = /obj/item/ammo_box/ptsd + backpack_contents = list(/obj/item/weapon/grenade/smokebomb = 1) + +/decl/hierarchy/outfit/job/redsoldier/sniper/equip() + if(prob(50)) + belt = /obj/item/weapon/gun/projectile/warfare + else + belt = /obj/item/weapon/gun/projectile/revolver + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/ammo_box/flares = 1, /obj/item/torch/self_lit = 1) + ..() + +/decl/hierarchy/outfit/job/redsoldier/medic + belt = /obj/item/weapon/storage/belt/medical/full + r_pocket = /obj/item/ammo_magazine/c45rifle/akarabiner + l_pocket = /obj/item/stack/medical/bruise_pack + suit_store = /obj/item/weapon/gun/projectile/automatic/m22/warmonger + gloves = /obj/item/clothing/gloves/latex + +/decl/hierarchy/outfit/job/redsoldier/medic/equip() + if(prob(50)) + suit_store = /obj/item/weapon/gun/projectile/automatic/m22/warmonger + r_pocket = /obj/item/ammo_magazine/c45rifle/akarabiner + backpack_contents = list( /obj/item/ammo_magazine/c45rifle/akarabiner = 3, /obj/item/weapon/grenade/smokebomb = 1) + + else + suit_store = /obj/item/weapon/gun/projectile/shotgun/pump/boltaction/shitty + r_pocket = /obj/item/ammo_box/rifle + backpack_contents = list(/obj/item/weapon/grenade/smokebomb = 1) + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/ammo_box/flares = 1, /obj/item/torch/self_lit = 1) + ..() + +/decl/hierarchy/outfit/job/redsoldier/leader + glasses = /obj/item/clothing/glasses/sunglasses + suit = /obj/item/clothing/suit/armor/redcoat/leader + head = /obj/item/clothing/head/warfare_officer/redofficer + l_ear = /obj/item/device/radio/headset/red_team/all + belt = /obj/item/weapon/gun/projectile/revolver/cpt + r_pocket = /obj/item/device/binoculars + backpack_contents = list(/obj/item/ammo_magazine/handful/revolver = 2, /obj/item/weapon/grenade/smokebomb = 1) + +/decl/hierarchy/outfit/job/redsoldier/leader/equip() + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/ammo_box/flares = 1 , /obj/item/torch/self_lit = 1) + ..() + +/decl/hierarchy/outfit/job/redsoldier/scout + //suit = /obj/item/clothing/suit/child_coat/red + l_ear = /obj/item/device/radio/headset/red_team/all + uniform = /obj/item/clothing/under/child_jumpsuit/warfare/red + shoes = /obj/item/clothing/shoes/child_shoes + gloves = null + r_pocket = /obj/item/device/binoculars + backpack_contents = list(/obj/item/weapon/grenade/smokebomb = 1) + +/decl/hierarchy/outfit/job/redsoldier/scout/equip() + if(aspect_chosen(/datum/aspect/nightfare)) + backpack_contents += list(/obj/item/ammo_box/flares = 1 , /obj/item/torch/self_lit = 1) + ..() \ No newline at end of file diff --git a/maps/oldfare/jobs/soldiers.dm b/maps/oldfare/jobs/soldiers.dm new file mode 100644 index 00000000..f1a0ad19 --- /dev/null +++ b/maps/oldfare/jobs/soldiers.dm @@ -0,0 +1,269 @@ +/datum/job/soldier + title = "Soldier" + department = "Security" + department_flag = SEC + total_positions = -1 + create_record = FALSE + account_allowed = FALSE + social_class = SOCIAL_CLASS_MIN + has_email = FALSE + latejoin_at_spawnpoints = TRUE + can_be_in_squad = TRUE + announced = TRUE + + //Baseline skill defines + medical_skill = 6 + surgery_skill = 4 + ranged_skill = 10 + engineering_skill = 5 + melee_skill = 10 + //Gun skills + auto_rifle_skill = 10 + semi_rifle_skill = 8 + sniper_skill = 4 + shotgun_skill = 4 + lmg_skill = 4 + smg_skill = 4 + + +/mob/living/carbon/human/proc/assign_random_squad(var/team, var/rank) + switch(team) + if(RED_TEAM)//You're now put in whatever squad has the least amount of living people in it. + var/alpha_members = SSWarfare.red.squadA.members.len + var/bravo_members = SSWarfare.red.squadB.members.len + var/charlie_members = SSWarfare.red.squadC.members.len + var/minimum = min(alpha_members, bravo_members, charlie_members) + if(minimum == alpha_members) + SSWarfare.red.squadA.members += src + src.squad = SSWarfare.red.squadA + //equip_to_slot_or_del(new /obj/item/device/radio/headset/red_team/alpha(src),slot_l_ear) //Saving the original here in case I want to return to it. + equip_to_slot_or_del(new /obj/item/device/radio/headset/red_team/sl_alpha(src),slot_l_ear) + var/obj/item/clothing/suit/armor/redcoat/RC = get_equipped_item(slot_wear_suit) + var/obj/item/clothing/accessory/armband/alpha/A = new(src) + RC.attach_accessory(src,A) + if(rank == "medic") + var/obj/item/clothing/accessory/medal/medical/M = new(src) + RC.attach_accessory(src,M) + //var/obj/item/clothing/suit/armor/redcoat/medic/MC = get_equipped_item(slot_wear_suit) + //MC.icon_state = "redcoat_medic_alpha" + //MC.item_state = "redcoat_medic_alpha" + + else if(minimum == bravo_members) + SSWarfare.red.squadB.members += src + src.squad = SSWarfare.red.squadB + equip_to_slot_or_del(new /obj/item/device/radio/headset/red_team/sl_bravo(src),slot_l_ear)//equip_to_slot_or_del(new /obj/item/device/radio/headset/red_team/bravo(src),slot_l_ear) + var/obj/item/clothing/suit/armor/redcoat/RC = get_equipped_item(slot_wear_suit) + var/obj/item/clothing/accessory/armband/bravo/B = new(src) + RC.attach_accessory(src,B) + if(rank == "medic") + var/obj/item/clothing/accessory/medal/medical/M = new(src) + RC.attach_accessory(src,M) + + else if(minimum == charlie_members) + SSWarfare.red.squadC.members += src + src.squad = SSWarfare.red.squadC + equip_to_slot_or_del(new /obj/item/device/radio/headset/red_team/sl_charlie(src),slot_l_ear) + var/obj/item/clothing/suit/armor/redcoat/RC = get_equipped_item(slot_wear_suit) + var/obj/item/clothing/accessory/armband/charlie/C = new(src.loc) + RC.attach_accessory(src,C) + if(rank == "medic") + var/obj/item/clothing/accessory/medal/medical/M = new(src) + RC.attach_accessory(src,M) + else + SSWarfare.red.squadB.members += src + src.squad = SSWarfare.red.squadB + equip_to_slot_or_del(new /obj/item/device/radio/headset/red_team/sl_bravo(src),slot_l_ear)//equip_to_slot_or_del(new /obj/item/device/radio/headset/red_team/bravo(src),slot_l_ear) + var/obj/item/clothing/suit/armor/redcoat/RC = get_equipped_item(slot_wear_suit) + var/obj/item/clothing/accessory/armband/bravo/B = new(src.loc) + RC.attach_accessory(src,B) + if(rank == "medic") + var/obj/item/clothing/accessory/medal/medical/M = new(src) + RC.attach_accessory(src,M) + /*if(4) + SSWarfare.red.squadD.members += src + src.squad = SSWarfare.red.squadD + equip_to_slot_or_del(new /obj/item/device/radio/headset/red_team/delta(src),slot_l_ear) + */ + if(BLUE_TEAM) + var/alpha_members = SSWarfare.blue.squadA.members.len + var/bravo_members = SSWarfare.blue.squadB.members.len + var/charlie_members = SSWarfare.blue.squadC.members.len + var/minimum = min(alpha_members, bravo_members, charlie_members) + if(minimum == alpha_members) + SSWarfare.blue.squadA.members += src + src.squad = SSWarfare.blue.squadA + equip_to_slot_or_del(new /obj/item/device/radio/headset/blue_team/sl_alpha(src),slot_l_ear)//equip_to_slot_or_del(new /obj/item/device/radio/headset/blue_team/alpha(src),slot_l_ear) + var/obj/item/clothing/suit/armor/bluecoat/BC = get_equipped_item(slot_wear_suit) + var/obj/item/clothing/accessory/armband/alpha/A = new(src) + BC.attach_accessory(src,A) + if(rank == "medic") + var/obj/item/clothing/accessory/medal/medical/M = new(src) + BC.attach_accessory(src,M) + + else if(minimum == bravo_members) + SSWarfare.blue.squadB.members += src + src.squad = SSWarfare.blue.squadB + equip_to_slot_or_del(new /obj/item/device/radio/headset/blue_team/sl_bravo(src),slot_l_ear)//equip_to_slot_or_del(new /obj/item/device/radio/headset/blue_team/bravo(src),slot_l_ear) + var/obj/item/clothing/suit/armor/bluecoat/BC = get_equipped_item(slot_wear_suit) + var/obj/item/clothing/accessory/armband/bravo/B = new(src.loc) + BC.attach_accessory(src,B) + if(rank == "medic") + var/obj/item/clothing/accessory/medal/medical/M = new(src) + BC.attach_accessory(src,M) + + //else if(charlie_members < alpha_members && charlie_members < bravo_members) + else if(minimum == charlie_members) + SSWarfare.blue.squadC.members += src + src.squad = SSWarfare.blue.squadC + equip_to_slot_or_del(new /obj/item/device/radio/headset/blue_team/sl_charlie(src),slot_l_ear)//equip_to_slot_or_del(new /obj/item/device/radio/headset/blue_team/charlie(src),slot_l_ear) + var/obj/item/clothing/suit/armor/bluecoat/BC = get_equipped_item(slot_wear_suit) + var/obj/item/clothing/accessory/armband/charlie/C = new(src.loc) + BC.attach_accessory(src,C) + if(rank == "medic") + var/obj/item/clothing/accessory/medal/medical/M = new(src) + BC.attach_accessory(src,M) + + + else + SSWarfare.blue.squadB.members += src + src.squad = SSWarfare.blue.squadB + equip_to_slot_or_del(new /obj/item/device/radio/headset/blue_team/sl_bravo(src),slot_l_ear)//equip_to_slot_or_del(new /obj/item/device/radio/headset/blue_team/bravo(src),slot_l_ear) + var/obj/item/clothing/suit/armor/bluecoat/BC = get_equipped_item(slot_wear_suit) + var/obj/item/clothing/accessory/armband/bravo/B = new(src.loc) + BC.attach_accessory(src,B) + if(rank == "medic") + var/obj/item/clothing/accessory/medal/medical/M = new(src) + BC.attach_accessory(src,M) + + /*if(4) + SSWarfare.blue.squadD.members += src + src.squad = SSWarfare.blue.squadD + equip_to_slot_or_del(new /obj/item/device/radio/headset/blue_team/delta(src),slot_l_ear) + */ + + var/obj/item/weapon/card/id/I = GetIdCard() + I.assignment = "[src.squad.name] Squad" + + to_chat(src, "I am apart of [src.squad.name] Squad") + + +/mob/living/carbon/human/proc/assign_squad_leader(var/team) + switch(team) + if(RED_TEAM)//Start from A, go to D + if(!SSWarfare.red.squadA.squad_leader) + SSWarfare.red.squadA.members += src + SSWarfare.red.squadA.squad_leader = src + src.squad = SSWarfare.red.squadA + equip_to_slot_or_del(new /obj/item/device/radio/headset/red_team/sl_alpha(src),slot_l_ear) + var/obj/item/clothing/suit/armor/redcoat/RC = get_equipped_item(slot_wear_suit) + var/obj/item/clothing/accessory/armband/alpha/A = new(src) + RC.attach_accessory(src,A) + + else if(!SSWarfare.red.squadB.squad_leader) + SSWarfare.red.squadB.members += src + SSWarfare.red.squadB.squad_leader = src + src.squad = SSWarfare.red.squadB + equip_to_slot_or_del(new /obj/item/device/radio/headset/red_team/sl_bravo(src),slot_l_ear) + var/obj/item/clothing/suit/armor/redcoat/RC = get_equipped_item(slot_wear_suit) + var/obj/item/clothing/accessory/armband/bravo/B = new(src) + RC.attach_accessory(src,B) + + else if(!SSWarfare.red.squadC.squad_leader) + SSWarfare.red.squadC.members += src + SSWarfare.red.squadC.squad_leader = src + src.squad = SSWarfare.red.squadC + equip_to_slot_or_del(new /obj/item/device/radio/headset/red_team/sl_charlie(src),slot_l_ear) + var/obj/item/clothing/suit/armor/redcoat/RC = get_equipped_item(slot_wear_suit) + var/obj/item/clothing/accessory/armband/charlie/C = new(src) + RC.attach_accessory(src,C) + + /* + else if(!SSWarfare.red.squadD.squad_leader) + SSWarfare.red.squadD.members += src + SSWarfare.red.squadD.squad_leader = src + src.squad = SSWarfare.red.squadD + equip_to_slot_or_del(new /obj/item/device/radio/headset/red_team/sl_delta(src),slot_l_ear) + */ + else//Somehow we have more than 3 SLs, no idea how but let's just exit now. + return + + if(BLUE_TEAM) + if(!SSWarfare.blue.squadA.squad_leader) + SSWarfare.blue.squadA.members += src + SSWarfare.blue.squadA.squad_leader = src + src.squad = SSWarfare.blue.squadA + equip_to_slot_or_del(new /obj/item/device/radio/headset/blue_team/sl_alpha(src),slot_l_ear) + var/obj/item/clothing/suit/armor/bluecoat/BC = get_equipped_item(slot_wear_suit) + var/obj/item/clothing/accessory/armband/alpha/A = new(src) + BC.attach_accessory(src,A) + + else if(!SSWarfare.blue.squadB.squad_leader) + SSWarfare.blue.squadB.members += src + SSWarfare.blue.squadB.squad_leader = src + src.squad = SSWarfare.blue.squadB + equip_to_slot_or_del(new /obj/item/device/radio/headset/blue_team/sl_bravo(src),slot_l_ear) + var/obj/item/clothing/suit/armor/bluecoat/BC = get_equipped_item(slot_wear_suit) + var/obj/item/clothing/accessory/armband/bravo/B = new(src) + BC.attach_accessory(src,B) + + else if(!SSWarfare.blue.squadC.squad_leader) + SSWarfare.blue.squadC.members += src + SSWarfare.blue.squadC.squad_leader = src + src.squad = SSWarfare.blue.squadC + equip_to_slot_or_del(new /obj/item/device/radio/headset/blue_team/sl_charlie(src),slot_l_ear) + var/obj/item/clothing/suit/armor/bluecoat/BC = get_equipped_item(slot_wear_suit) + var/obj/item/clothing/accessory/armband/charlie/C = new(src) + BC.attach_accessory(src,C) + /* + else if(!SSWarfare.blue.squadD.squad_leader) + SSWarfare.blue.squadD.members += src + SSWarfare.blue.squadD.squad_leader = src + src.squad = SSWarfare.blue.squadD + equip_to_slot_or_del(new /obj/item/device/radio/headset/blue_team/sl_delta(src),slot_l_ear) + */ + else + return + + var/obj/item/weapon/card/id/I = GetIdCard() + I.assignment = "[src.squad.name] Squad" + + to_chat(src, "I am the Squad Leader of [src.squad.name] Squad") + + +/mob/proc/voice_in_head(message) + to_chat(src, "...[message]") + +GLOBAL_LIST_INIT(lone_thoughts, list( + "Why are we still here, just to suffer?", + "We fight to win, and that's all that matters.", + "Why we don't get any more reinforcements?", + "We have not gotten any orders from central command in months...", + "Did something happened while we were fighting in trenches?", + "Is there any reason to keep fighting?", + "Did anyone notice when ash started to fall?", + "It's middle of summer. Why it's so cold?", + "Greg died last night.", + "I do not want to die.", + "I miss my loved ones.", + "There is no hope... anymore...", + "Is there actually a central command?", + "Is any of this real?", + "My teeth hurt.", + "I am not ready to die.", + "Who keeps dropping the artillery?", + "I don't remember joining the military...")) + +/mob/living/proc/assign_random_quirk() + if(prob(75))//75% of not choosing a quirk at all. + return + if(is_hellbanned())//Hellbanned people will never get quirks. + return + var/list/random_quirks = list() + for(var/thing in subtypesof(/datum/quirk))//Populate possible quirks list. + var/datum/quirk/Q = thing + random_quirks += Q + if(!random_quirks.len)//If there's somewhow nothing there afterwards return. + return + var/datum/quirk/chosen_quirk = pick(random_quirks) + src.quirk = new chosen_quirk + to_chat(src, "I was formed a bit different. I am [quirk.name]. [quirk.description]") \ No newline at end of file diff --git a/maps/oldfare/jobs/warfare_jobs.dm b/maps/oldfare/jobs/warfare_jobs.dm new file mode 100644 index 00000000..071bf5a3 --- /dev/null +++ b/maps/oldfare/jobs/warfare_jobs.dm @@ -0,0 +1,44 @@ +/datum/job/assistant + total_positions = 0 + +/datum/map/warfare + allowed_jobs = list( + /datum/job/assistant, + /datum/job/soldier/red_soldier/captain, + /datum/job/soldier/red_soldier/sgt, + /datum/job/soldier/red_soldier/medic, + /datum/job/soldier/red_soldier/engineer, + /datum/job/soldier/red_soldier/sentry, + /datum/job/soldier/red_soldier/sniper, + /datum/job/soldier/red_soldier/flame_trooper, + /datum/job/soldier/red_soldier, + /datum/job/soldier/red_soldier/scout, + /datum/job/fortress/red/practitioner, + + /datum/job/soldier/blue_soldier/captain, + /datum/job/soldier/blue_soldier/sgt, + /datum/job/soldier/blue_soldier/medic, + /datum/job/soldier/blue_soldier/engineer, + /datum/job/soldier/blue_soldier/sniper, + /datum/job/soldier/blue_soldier/sentry, + /datum/job/soldier/blue_soldier/flame_trooper, + /datum/job/soldier/blue_soldier, + /datum/job/soldier/blue_soldier/scout, + /datum/job/fortress/blue/practitioner + ) + +/mob/living/carbon/human/proc/warfare_language_shit(var/language_name) + if(aspect_chosen(/datum/aspect/one_word)) + return + remove_language(LANGUAGE_GALCOM) + var/datum/language/L = null + add_language(language_name) + L = all_languages[language_name] + + if(L) + default_language = L + +/datum/job/assistant + title = "literally not a job" + total_positions = 0 + spawn_positions = 0 \ No newline at end of file diff --git a/maps/oldfare/warfare-1.dmm b/maps/oldfare/warfare-1.dmm new file mode 100644 index 00000000..3b9fb4fb --- /dev/null +++ b/maps/oldfare/warfare-1.dmm @@ -0,0 +1,426 @@ +"aa" = (/obj/structure/stairs/north,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"ab" = (/obj/effect/landmark{name = "tdome1"},/turf/simulated/mineral,/area/space) +"ac" = (/turf/simulated/wall/concrete,/area/warfare/homebase/red) +"ad" = (/turf/simulated/wall/concrete,/area/warfare/homebase/blue) +"ae" = (/turf/simulated/mineral,/area/warfare/homebase/blue) +"af" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"ag" = (/obj/effect/landmark/start{name = "Red Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"ah" = (/obj/effect/landmark/start{name = "Red Scavenger"},/obj/structure/toilet{icon_state = "toilet00"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ai" = (/obj/structure/bed/chair,/obj/effect/landmark/start{name = "Red Soldier"},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aj" = (/obj/structure/bed/chair,/obj/effect/landmark/start{name = "Red Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"ak" = (/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"al" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"am" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"an" = (/obj/structure/banner/red/small{pixel_y = 32},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"ao" = (/obj/structure/bed/chair,/obj/effect/landmark/start{name = "Red Soldier"},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"ap" = (/obj/structure/closet/crate,/obj/item/weapon/melee/classic_baton/trench_club,/obj/item/weapon/melee/classic_baton/trench_club,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aq" = (/turf/simulated/mineral,/area/warfare/homebase/red) +"ar" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"as" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"at" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"au" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/effect/landmark/start{name = "Red Soldier"},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"av" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/effect/landmark/start{name = "Red Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aw" = (/turf/simulated/mineral,/area/space) +"ax" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes/jerichos,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"ay" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"az" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes/luckystars,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/obj/item/ammo_box/rifle,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"aA" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/box/matches,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aB" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/device/compass,/obj/item/device/compass,/obj/item/device/compass,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"aC" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aD" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/firstaid/surgery,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aE" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/fancy/cigarettes/carcinomas,/obj/item/ammo_box/rifle,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"aF" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/ammo_box/shotgun,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"aG" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aH" = (/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"aI" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/effect/landmark/start{name = "Red Soldier"},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aJ" = (/obj/structure/stairs/north,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"aK" = (/obj/structure/closet/crate,/obj/item/ammo_box/rifle,/obj/item/ammo_box/rifle,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"aL" = (/obj/structure/poster/red,/turf/simulated/wall/concrete,/area/warfare/homebase/red) +"aM" = (/obj/machinery/kaos/cargo_machine/blue,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"aN" = (/obj/structure/closet/crate,/obj/item/weapon/melee/classic_baton/trench_club,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aO" = (/obj/effect/landmark/start{name = "Blue Scavenger"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aP" = (/obj/structure/table/woodentable,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/obj/item/device/compass,/obj/item/device/compass,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aQ" = (/turf/simulated/mineral,/area/warfare/battlefield/capture_point/red/one) +"aR" = (/obj/structure/stairs/west,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aS" = (/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aT" = (/obj/structure/window/reinforced{icon_state = "rwindow"; dir = 8},/obj/effect/landmark/blue_cargo,/obj/structure/cargo_pad,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aU" = (/obj/structure/closet/crate,/obj/structure/closet/crate,/obj/item/weapon/material/sword/combat_knife,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"aV" = (/obj/structure/curtain,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aW" = (/obj/effect/landmark/start{name = "Red Squad Leader"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aX" = (/obj/effect/landmark/start{name = "Red Bartender"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aY" = (/obj/effect/landmark/start{name = "Red Soldier"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aZ" = (/obj/structure/bed,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ba" = (/obj/structure/banner/red/small{pixel_y = 32},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"bb" = (/obj/structure/closet/cabinet,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bc" = (/obj/effect/landmark{name = "JoinLate"},/turf/simulated/mineral,/area/space) +"bd" = (/obj/effect/landmark/test/safe_turf,/turf/simulated/mineral,/area/space) +"be" = (/obj/effect/landmark/test/space_turf,/turf/simulated/mineral,/area/space) +"bf" = (/obj/effect/landmark/start,/turf/simulated/mineral,/area/space) +"bg" = (/obj/effect/landmark/start{name = "Red Scavenger"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bh" = (/obj/structure/closet/crate,/obj/item/weapon/melee/classic_baton/trench_club,/obj/item/weapon/melee/classic_baton/trench_club,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bi" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"bj" = (/obj/structure/closet/crate,/obj/item/weapon/material/sword/combat_knife,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bk" = (/obj/structure/closet/crate,/obj/item/weapon/melee/classic_baton/trench_club,/obj/item/weapon/grenade/frag/warfare,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bl" = (/obj/structure/bed/chair,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bm" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bn" = (/obj/structure/bed/chair,/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bo" = (/obj/structure/bed/chair,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bp" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes/jerichos,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bq" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"br" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes/luckystars,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/obj/item/ammo_box/rifle,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"bs" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/box/matches,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bt" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/device/compass,/obj/item/device/compass,/obj/item/device/compass,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"bu" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bv" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/firstaid/surgery,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bw" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/fancy/cigarettes/carcinomas,/obj/item/ammo_box/rifle,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"bx" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/ammo_box/shotgun,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"by" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/fancy/cigarettes/carcinomas,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bz" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/wirecutters,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bA" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bB" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bC" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bD" = (/obj/effect/landmark/blue_cargo,/obj/structure/cargo_pad,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bE" = (/obj/structure/closet/crate,/obj/item/ammo_box/rifle,/obj/item/ammo_box/rifle,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"bF" = (/obj/structure/poster/blue,/turf/simulated/wall/concrete,/area/warfare/homebase/blue) +"bG" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"bH" = (/obj/structure/closet/crate,/obj/item/weapon/melee/classic_baton/trench_club,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bI" = (/turf/simulated/mineral,/area/warfare/battlefield/capture_point/red/two) +"bJ" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bK" = (/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bL" = (/obj/structure/stairs/west,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bM" = (/obj/structure/curtain,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bN" = (/obj/structure/bed,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bO" = (/obj/structure/table/woodentable,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/obj/item/device/compass,/obj/item/device/compass,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bP" = (/obj/structure/closet/cabinet,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bQ" = (/obj/structure/closet/crate,/obj/item/weapon/melee/classic_baton/trench_club,/obj/item/weapon/grenade/frag/warfare,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"bR" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/fancy/cigarettes/carcinomas,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"bS" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/wirecutters,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"bT" = (/turf/simulated/wall/concrete,/area/warfare/battlefield/capture_point/red/two) +"bU" = (/obj/structure/destruction_computer/blue,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bV" = (/obj/machinery/telecomms/allinone{intercept = 1},/turf/simulated/floor/dirty,/area/warfare/homebase/red) +"bW" = (/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"bX" = (/obj/structure/stairs/south,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"bY" = (/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"bZ" = (/turf/simulated/wall/concrete,/area/warfare/battlefield/trench_section/underground) +"ca" = (/obj/structure/table/steel,/obj/item/weapon/storage/firstaid/surgery,/obj/item/weapon/FixOVein,/turf/simulated/floor/trenches,/area/warfare/battlefield/trench_section/underground) +"cb" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/toxin,/obj/item/weapon/storage/firstaid/toxin,/obj/item/weapon/storage/firstaid/toxin,/obj/item/weapon/storage/firstaid/toxin,/turf/simulated/floor/trenches,/area/warfare/battlefield/trench_section/underground) +"cc" = (/turf/simulated/mineral,/area/warfare/battlefield/capture_point/blue/two) +"cd" = (/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"ce" = (/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"cf" = (/turf/simulated/mineral,/area/warfare/battlefield/capture_point/blue/one) +"cg" = (/obj/structure/stairs/south,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"ch" = (/obj/structure/destruction_computer/red,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ci" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/adv,/obj/item/weapon/storage/firstaid/adv,/obj/item/weapon/storage/firstaid/adv,/obj/item/weapon/storage/firstaid/adv,/turf/simulated/floor/trenches,/area/warfare/battlefield/trench_section/underground) +"cj" = (/obj/structure/table/steel,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter/random,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"ck" = (/obj/structure/stairs/north,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"cl" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"cm" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"cn" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"co" = (/obj/structure/table/steel,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter/zippo,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"cp" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"cq" = (/obj/structure/window/reinforced{icon_state = "rwindow"; dir = 8},/obj/structure/window/reinforced,/obj/effect/landmark/blue_cargo,/obj/structure/cargo_pad/bottom_left,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"cr" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"cs" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ct" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"cu" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"cv" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/obj/structure/table/rack,/obj/item/weapon/storage/belt/medical/full,/obj/item/weapon/storage/belt/medical/full,/obj/item/weapon/storage/belt/medical/full,/obj/item/weapon/storage/belt/medical/full,/obj/item/weapon/storage/belt/medical/full,/turf/simulated/floor/trenches,/area/warfare/battlefield/trench_section/underground) +"cw" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"cx" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"cy" = (/obj/structure/stairs/north,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"cz" = (/obj/effect/landmark/blue_cargo,/obj/structure/cargo_pad/bottom_middle,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"cA" = (/obj/structure/table/rack,/obj/item/weapon/storage/belt/medical/full,/obj/item/weapon/storage/belt/medical/full,/obj/item/weapon/storage/belt/medical/full,/obj/item/weapon/storage/belt/medical/full,/obj/item/weapon/storage/belt/medical/full,/turf/simulated/floor/trenches,/area/warfare/battlefield/trench_section/underground) +"cB" = (/obj/machinery/optable,/turf/simulated/floor/trenches,/area/warfare/battlefield/trench_section/underground) +"cC" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"cD" = (/obj/structure/stairs/south,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"cE" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"cF" = (/turf/simulated/floor/trenches,/area/warfare/battlefield/trench_section/underground) +"cG" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"cH" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/trench_section/underground) +"cI" = (/turf/simulated/wall/concrete,/area/warfare/battlefield/capture_point/blue/two) +"cJ" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"cK" = (/obj/structure/table/steel,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter/random,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"cL" = (/obj/structure/table/steel,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter/zippo,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"cM" = (/obj/machinery/kaos/cargo_machine/red,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cN" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"cO" = (/obj/structure/closet/crate,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"cP" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"cQ" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"cR" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"cS" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"cT" = (/obj/structure/sign/redcross,/turf/simulated/mineral,/area/warfare/battlefield/capture_point/red/one) +"cU" = (/obj/structure/sign/redcross,/turf/simulated/mineral,/area/warfare/battlefield/capture_point/red/two) +"cV" = (/obj/structure/stairs/south,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"cW" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"cX" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/obj/structure/window/reinforced,/obj/effect/landmark/blue_cargo,/obj/structure/cargo_pad/bottom_right,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"cY" = (/turf/simulated/mineral,/area/warfare/battlefield/trench_section/underground) +"cZ" = (/obj/effect/landmark/red_cargo,/obj/structure/window/reinforced{icon_state = "rwindow"; dir = 8},/obj/structure/cargo_pad,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"da" = (/obj/effect/landmark/red_cargo,/obj/structure/cargo_pad,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"db" = (/obj/effect/landmark/red_cargo,/obj/structure/window/reinforced{icon_state = "rwindow"; dir = 8},/obj/structure/window/reinforced,/obj/structure/cargo_pad/bottom_left,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dc" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/trench_section/underground) +"dd" = (/obj/structure/torchwall{pixel_y = 30},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"de" = (/mob/living/simple_animal/hostile/retaliate/rat,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"df" = (/mob/living/simple_animal/hostile/retaliate/rat,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"dg" = (/mob/living/simple_animal/hostile/retaliate/rat,/turf/simulated/floor/trenches,/area/warfare/battlefield/trench_section/underground) +"dh" = (/mob/living/simple_animal/hostile/retaliate/rat,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"di" = (/mob/living/simple_animal/hostile/retaliate/rat,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"dj" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/mob/living/simple_animal/hostile/retaliate/rat,/turf/simulated/floor/trenches,/area/warfare/battlefield/trench_section/underground) +"dk" = (/mob/living/simple_animal/hostile/retaliate/rat,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"dl" = (/mob/living/simple_animal/hostile/retaliate/rat,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"dm" = (/turf/simulated/wall/concrete,/area/warfare/battlefield/capture_point/red/one) +"dn" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"do" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"dp" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"dq" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"dr" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"ds" = (/obj/structure/closet/crate,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"dt" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"du" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"dv" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"dw" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"dx" = (/obj/structure/table/steel,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter/random,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"dy" = (/obj/structure/table/steel,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter/zippo,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"dz" = (/turf/simulated/wall/concrete,/area/warfare/battlefield/capture_point/blue/one) +"dA" = (/obj/structure/closet/crate,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"dB" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"dC" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"dD" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"dE" = (/obj/structure/table/steel,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter/random,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"dF" = (/obj/structure/table/steel,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter/zippo,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"dG" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"dH" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"dI" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"dJ" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"dK" = (/obj/structure/sign/neon/cargo,/turf/simulated/wall/concrete,/area/warfare/homebase/red) +"dL" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"dM" = (/obj/structure/torchwall{pixel_y = 30},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"dN" = (/obj/structure/banner/blue/small{pixel_y = 32},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"dO" = (/obj/structure/banner/blue/small{pixel_y = 32},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"dP" = (/obj/machinery/computer/operating,/turf/simulated/floor/trenches,/area/warfare/battlefield/trench_section/underground) +"dQ" = (/obj/structure/curtain,/turf/simulated/floor/trenches,/area/warfare/battlefield/trench_section/underground) +"dR" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/regular,/obj/item/weapon/storage/firstaid/regular,/obj/item/weapon/storage/firstaid/regular,/obj/item/weapon/storage/firstaid/regular,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/turf/simulated/floor/trenches,/area/warfare/battlefield/trench_section/underground) +"dS" = (/obj/machinery/sleeper,/turf/simulated/floor/trenches,/area/warfare/battlefield/trench_section/underground) +"dT" = (/obj/effect/landmark/red_cargo,/obj/structure/cargo_pad/bottom_middle,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dU" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/obj/effect/landmark/red_cargo,/obj/structure/window/reinforced,/obj/structure/cargo_pad/bottom_right,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dV" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"dW" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"dX" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"dY" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"ea" = (/obj/structure/closet/crate,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"eb" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"en" = (/obj/structure/sign/neon/cargo,/turf/simulated/wall/concrete,/area/warfare/homebase/blue) +"ep" = (/obj/structure/sign/redcross,/turf/simulated/wall/concrete,/area/warfare/battlefield/trench_section/underground) +"eq" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"er" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) + +(1,1,1) = {" +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawadenadbFadadawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawadaMaTbDbDadawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawadadadcrcqczcXadadadadadadadadadadadadadaeaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawadafdOaHaHaHaHdOaUadadafaHaHbKbKaHaHbhadaeaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawadafaHaHaHaHaHaHbjadadafaHaHaHaHaHaHbkadaeaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawadblbnaHaHaHaHbnboadadblbnaHaHaHaHbnboadaeaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawadbpbqaHaHaHaHazbsadbFbsaBaHaHaHaHbsbuadaeaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawadbvbsaHdeaHaHaEaFadadbuaBaHaHaHaHbybzadaeaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawadbAbBaHaHaHaHbBbCadadbAbBaHaHaHaHbBbCadaeaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawadbhaHaHaHaHaHaHaKadadaKaHaHaHaHaHaHaladaeaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawadbHaHaHaHaHaHaHaKadadaKaHaHaHaHaHaHaladaeaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawadadadadbKbKbKbKbKbUbKbKbKbKbKbKbKbKbKadaeaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawaeaeadbLbKbKbKbKbKbKbKbKbKbKbKbKbKbKbKadaeaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawaeaeadbLbKbKbKbKctbKbKbKctbKbKbKctbKbKadaeaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawaeaeadadadadbMadadadbMadadadbMadadadbMadadaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawaeaeaeaeadbKbKamadbKbKamadbKbKamadbKbKamadaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawaeaeaeaeadbKaObKadbKaObKadbKaObKadbKaObKadaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawaeaeaeaeadbNaPbPadbNaPbPadbNaPbPadbNaPbPadaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawaeaeaeaeadadadadadadadadadadadadadadadadadaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawaaaaaaaaaaaaaaaaaaaaawawawawawawaaaaaaaaaaaaaaaaaaaaawawawawawawawawawawawaw +awawawawawawawawawawawawcdcdcWcdcdcdcdcWcdcdawawawawawawcdcdcWcdcdcdcdcWcdcdawawawawawawawawawawawaw +awawawawawawawawawawawawdfcdcIcIcJcdcIcIcdcdawawawawawawcdcdcIcIcJcdcIcIcddfawawawawawawawawawawawaw +awawawawawawawawawawawawcdcdcIcmcdcdcncIcdcdcdcdcdcdcdcdcdcdcIcPcdcdcScIcdcdawawawawawawawawawawawaw +awawawawawawawawawawawawcgcgcIasclcGcGcIcgcgcgcgcdcdcgcgcgcgcIcPcdcdcScIcgcgawawawawawawawawawawawaw +awawawawawawawawawawawawcccccIcOcGcGcNcIcccccccccdcdcccccccccccccKcLccccccccawawawawawawawawawawawaw +awawawawawawawawawawawawcccccIcIcIcIcIcIcccccccccdcdccccccccccccccccccccccccawawawawawawawawawawawaw +awawawawawawawawawawawawcccccccccccccccccccccccccmcnccccccccccccccccccccccccawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawbZbZbZbZbZbZcFcFcFcFcFdgbZbZbZbZbZbZawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawbZcacbcicvepcHcFcYcYcFdcepcAcbcicabZawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawbZcHcFcFcFdQcFcFcYcYcFcFdQcFcFcFdcbZawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawbZcBdPdRdSepdjcFcYcYcFdcepdSdRdPcBbZawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawbZbZbZbZbZbZcFcFcFcFcFcFbZbZbZbZbZbZawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawcfcfcfcfcfcfcfcfcfcfcfcfcQcRcfcfcfcfcfcfcfcfcfcfcfcfawawawawawawawawawawawaw +awawawawawawawawawawawawcfcfdzdAdBdqdrdzcfcfcfcfcececfcfcfcfcfcfdEdFcfcfcfcfawawawawawawawawawawawaw +awawawawawawawawawawawawcfcfdzdGdtdudCdzcfcfcfcfcececfcfcfcfdzdHcecedIdzcfcfawawawawawawawawawawawaw +awawawawawawawawawawawawckckdzcQcececRdzckckckckcececkckckckdzdHcecedIdzckckawawawawawawawawawawawaw +awawawawawawawawawawawawcecedzdzdLcedzdzcecececececececececedzdzdLcedzdzceceawawawawawawawawawawawaw +awawawawawawawawawawawawcecedMdNcecedNdMceceawawawawawawcecedMdNcecedNdMceceawawawawawawawawawawawaw +awawawawawawawawawawawawdhcececececececececeawawawawawawcececececececececedhawawawawawawawawawawawaw +awawawawawawawawawawawawcVcVcVcVcVcVcVcVcVcVawawawawawawcVcVcVcVcVcVcVcVcVcVawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawaJaJaJaJaJaJaJaJaJaJaQaQaQaQaQaQaJaJaJaJaJaJaJaJaJaJawawawawawawawawawawawaw +awawawawawawawawawawawawbWbWbWbWbWbWbWbWbWbWaQaQaQaQaQaQbWbWbWbWbWbWbWbWbWbWawawawawawawawawawawawaw +awawawawawawawawawawawawdibWdmdmdnbWdmdmbWbWaQaQaQaQaQaQbWbWdmdmdnbWdmdmbWdiawawawawawawawawawawawaw +awawawawawawawawawawawawbWbWdmcubWbWcEdmbWbWbWbWbWbWbWbWbWbWdmdvbWbWdwdmbWbWawawawawawawawawawawawaw +awawawawawawawawawawawawbXbXdmdodpdDdDdmbXbXbXbXbWbWbXbXbXbXdmdvbWbWdwdmbXbXawawawawawawawawawawawaw +awawawawawawawawawawawawaQaQdmdsdDdDdJdmaQaQaQcTbWbWcTaQaQaQaQaQdxdyaQaQaQaQawawawawawawawawawawawaw +awawawawawawawawawawawawaQaQdmdmdmdmdmdmaQaQaQaQbWbWaQaQaQaQaQaQaQaQaQaQaQaQawawawawawawawawawawawaw +awawawawawawawawawawawawaQaQaQaQaQaQaQaQaQaQaQaQcucEaQaQaQaQaQaQaQaQaQaQaQaQawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawbZbZbZbZbZbZcFcFcFcFcFdgbZbZbZbZbZbZawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawbZcacbcicvepcHcFcYcYcFdcepcAcbcicabZawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawbZcHcFcFcFdQcFcFcYcYcFcFdQcFcFcFdcbZawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawbZcBdPdRdSepdjcFcYcYcFdcepdSdRdPcBbZawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawbZbZbZbZbZbZcFcFcFcFcFcFbZbZbZbZbZbZawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawbIbIbIbIbIbIbIbIbIbIbIbIcpbibIbIbIbIbIbIbIbIbIbIbIbIawawawawawawawawawawawaw +awawawawawawawawawawawawbIbIbTeadXdVdYbTbIbIbIbIbYbYbIbIbIbIbIbIcjcobIbIbIbIawawawawawawawawawawawaw +awawawawawawawawawawawawbIbIbTdWebeqerbTbIbIbIcUbYbYcUbIbIbIbTcwbYbYcxbTbIbIawawawawawawawawawawawaw +awawawawawawawawawawawawcycybTcpbYbYbibTcycycycybYbYcycycycybTcwbYbYcxbTcycyawawawawawawawawawawawaw +awawawawawawawawawawawawbYbYbTbTcCbYbTbTbYbYbYbYbYbYbYbYbYbYbTbTcCbYbTbTbYbYawawawawawawawawawawawaw +awawawawawawawawawawawawdkbYddbabYbYbaddbYbYawawawawawawbYbYddbabYbYbaddbYdkawawawawawawawawawawawaw +awawawawawawawawawawawawbYbYbYbYbYbYbYbYbYbYawawawawawawbYbYbYbYbYbYbYbYbYbYawawawawawawawawawawawaw +awawawawawawawawawawawawcDcDcDcDcDcDcDcDcDcDawawawawawawcDcDcDcDcDcDcDcDcDcDawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawacdKacaLacacawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaccMcZdadaacawawawawawawawawawawawawawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawaqacacacbGdbdTdUacacacacacacacacacacacacacawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawaqacatanagakakaganaracacataGaSagagaSakapacawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawaqacatakakakakakakaracacataGakakakakakbQacawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawaqacaiajakakakakajaoacacaiajakakakakajaoacawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawaqacaxayakakakakbraAacacaAbtakakakakaAaCacawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawaqacaDaAakdlakakbwbxacacaCbtakakakakbRbSacawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawaqacauavakakakakavaIacacauavakakakakavaIacawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawaqacapakakakakakarbEacacbEakakakakakakaracawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawacacaNakakakakakarbEacacbEakakakakakakaracawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawacacacacaSaSaSaSaSaSchaSaSaSaSaSaSaSaSaSacawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawacaRaSaSaSaSaSaSaSaSaSaSaSaSaSaSaSaSaSaSacawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawacaRaSaScsaSaSaScsaSaSaScsaSaSaScsaSaSaSacawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawacacacacacacaVacacacaVacacacaVacacacaVacacawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawaqaqaqaqacbmaWaSacbmaWaSacbmaWbJacbmaWbJacawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawaqaqaqaqacaXaYahacaXaYahacaXaYbgacaXaYbgacawaw +awawawawawawawawawawawawawawawawawawawawawawawawawawawaqaqaqaqacaZbObbacaZbObbacaZbObbacaZbObbacawaw +abababbcbcbcawawawawawawawawawawawawawawawawawawawawawaqaqaqaqacaLacacacacacacacacacacacacacacacawaw +abababbcbcbcawawawawawawawawawawawawawawawawawawawawawaqaqaqaqaqaqaqaqaqaqaqaqaqaqbVaqaqaqaqaqaqawaw +abababbcbcbcawawbdbeawbfawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw +"} diff --git a/maps/oldfare/warfare-2.dmm b/maps/oldfare/warfare-2.dmm new file mode 100644 index 00000000..c3e9fdb8 --- /dev/null +++ b/maps/oldfare/warfare-2.dmm @@ -0,0 +1,540 @@ +"aa" = (/turf/simulated/mineral,/area/warfare/homebase/blue) +"ab" = (/turf/simulated/wall/concrete,/area/warfare/homebase/blue) +"ac" = (/obj/structure/bed,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"ad" = (/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"ae" = (/obj/machinery/optable,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"af" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"ag" = (/obj/structure/barbwire,/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/no_mans_land) +"ah" = (/obj/machinery/computer/operating,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"ai" = (/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/no_mans_land) +"aj" = (/obj/effect/landmark/start{name = "Blue Practitioner"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"ak" = (/obj/structure/bed/roller,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"al" = (/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"am" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/fire,/obj/item/weapon/storage/firstaid/fire,/obj/item/weapon/storage/firstaid/fire,/obj/item/weapon/storage/firstaid/fire,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"an" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/toxin,/obj/item/weapon/storage/firstaid/toxin,/obj/item/weapon/storage/firstaid/toxin,/obj/item/weapon/storage/firstaid/toxin,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"ao" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/adv,/obj/item/weapon/storage/firstaid/adv,/obj/item/weapon/storage/firstaid/adv,/obj/item/weapon/storage/firstaid/adv,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"ap" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"aq" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/regular,/obj/item/weapon/storage/firstaid/regular,/obj/item/weapon/storage/firstaid/regular,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"ar" = (/obj/structure/curtain,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"as" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"at" = (/obj/structure/table/steel,/obj/item/weapon/storage/firstaid/surgery,/obj/item/weapon/FixOVein,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"au" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"av" = (/obj/structure/closet/secure_closet/medical2{req_access = newlist()},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aw" = (/obj/structure/closet/medical_wall,/turf/simulated/wall/concrete,/area/warfare/homebase/blue) +"ax" = (/turf/simulated/floor/tiled/ramp{icon_state = "ramptop"; dir = 4},/area/warfare/homebase/blue) +"ay" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"az" = (/obj/structure/sign/medholo,/turf/simulated/wall/concrete,/area/warfare/homebase/blue) +"aA" = (/obj/effect/landmark/start{name = "Blue Medic"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aB" = (/obj/structure/table/steel,/obj/item/weapon/crutches,/obj/item/weapon/crutches,/obj/item/weapon/crutches,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aC" = (/obj/structure/closet/secure_closet/medical1/warfare,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aD" = (/obj/machinery/sleeper,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aE" = (/turf/simulated/floor/tiled/ramp{icon_state = "ramptop"; dir = 4},/area/warfare/homebase/red) +"aF" = (/turf/simulated/open,/area/warfare/homebase/blue) +"aG" = (/obj/machinery/sleeper{icon_state = "sleeper_0"; dir = 1},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aH" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"aI" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aJ" = (/obj/structure/table/steel,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aK" = (/obj/structure/table/steel,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aL" = (/obj/structure/table/steel,/obj/machinery/microwave,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aM" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"aN" = (/obj/structure/closet/cabinet,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aO" = (/obj/structure/table/woodentable,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aP" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/fancy/cigarettes/carcinomas,/obj/item/device/cassette/tape3,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aQ" = (/obj/structure/table/steel,/obj/machinery/cooker/candy,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aR" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/obj/effect/landmark/start{name = "Blue Squad Leader"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aS" = (/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aT" = (/obj/structure/closet/crate{name = "gasmask crate"},/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/blue) +"aU" = (/obj/structure/landmine,/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/no_mans_land) +"aV" = (/obj/structure/bed/chair,/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aW" = (/obj/structure/closet/crate,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aX" = (/obj/structure/table/steel,/obj/machinery/cooker/cereal,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"aY" = (/obj/structure/dirt_wall,/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/capture_point/blue/two) +"aZ" = (/obj/effect/landmark/start{name = "Blue Chef"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"ba" = (/obj/structure/table/steel,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bb" = (/obj/effect/landmark/start{name = "Blue Squad Leader"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bc" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 4},/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bd" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"be" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bf" = (/obj/machinery/vending/dinnerware,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bg" = (/obj/structure/closet/secure_closet/freezer/meat,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bh" = (/obj/machinery/cooker/oven,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bi" = (/obj/machinery/cooker/grill,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bj" = (/obj/machinery/cooker/fryer,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bk" = (/obj/structure/closet/chefcloset,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bl" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bm" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bn" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bo" = (/obj/structure/table/steel,/obj/item/weapon/storage/firstaid/surgery,/obj/item/weapon/FixOVein,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bp" = (/obj/structure/bed/chair/wheelchair,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bq" = (/obj/structure/closet/crate,/obj/item/weapon/melee/classic_baton/trench_club,/obj/item/weapon/melee/classic_baton/trench_club,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"br" = (/obj/effect/landmark/start{name = "Blue Captain"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bs" = (/obj/structure/closet/crate/trashcart,/turf/simulated/floor/trenches,/area/warfare/homebase/red) +"bt" = (/obj/structure/table/steel,/obj/item/weapon/crutches,/obj/item/weapon/crutches,/obj/item/weapon/crutches,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bu" = (/obj/structure/closet/crate,/obj/item/weapon/melee/classic_baton/trench_club,/obj/item/weapon/grenade/frag/warfare,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bv" = (/obj/structure/bed/chair,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bw" = (/obj/structure/bed/chair,/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bx" = (/obj/structure/bed/chair,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"by" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes/jerichos,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bz" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bA" = (/obj/effect/landmark/start{name = "Blue Squad Leader"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bB" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes/luckystars,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/obj/item/ammo_box/rifle,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bC" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/box/matches,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bD" = (/obj/structure/table/woodentable,/obj/item/device/compass,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bE" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bF" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/firstaid/surgery,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bG" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/fancy/cigarettes/carcinomas,/obj/item/ammo_box/rifle,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bH" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/ammo_box/shotgun,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bI" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/fancy/cigarettes/carcinomas,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bJ" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/wirecutters,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bK" = (/obj/structure/bed/chair/wheelchair,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bL" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bM" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bN" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bO" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/box/matches,/obj/item/device/cassette/tape1,/obj/item/device/cassette/tape2,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bP" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bQ" = (/obj/structure/closet/crate,/obj/item/ammo_box/rifle,/obj/item/ammo_box/rifle,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bR" = (/obj/structure/banner/blue{pixel_y = 32},/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/blue) +"bS" = (/obj/structure/table/steel,/obj/item/weapon/reagent_containers/food/condiment/small/saltshaker,/obj/item/weapon/reagent_containers/food/condiment/small/peppermill,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bT" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes/jerichos,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/obj/item/device/boombox,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bU" = (/obj/structure/closet/crate,/obj/item/weapon/melee/classic_baton/trench_club,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bV" = (/obj/effect/landmark/start{name = "Blue Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"bW" = (/obj/structure/table/steel,/obj/item/weapon/reagent_containers/food/condiment/small/saltshaker,/obj/item/weapon/reagent_containers/food/condiment/small/peppermill,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bX" = (/obj/effect/landmark/start{name = "Blue Scavenger"},/obj/structure/toilet{icon_state = "toilet00"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"bY" = (/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/blue) +"bZ" = (/obj/structure/dirt_wall,/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/blue) +"ca" = (/obj/machinery/button/remote/blast_door/lever{id = "blue"; pixel_x = 0; pixel_y = -32},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"cb" = (/obj/structure/closet/crate/trashcart,/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/blue) +"cc" = (/obj/structure/barbwire,/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/blue) +"cd" = (/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/red) +"ce" = (/obj/structure/barbwire,/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/red) +"cf" = (/obj/structure/dirt_wall,/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/red) +"cg" = (/turf/simulated/wall/concrete,/area/warfare/homebase/red) +"ch" = (/obj/machinery/button/remote/blast_door/lever{id = "blue"; pixel_x = -32},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"ci" = (/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cj" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"ck" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cl" = (/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cm" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cn" = (/obj/structure/table/steel,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"co" = (/obj/structure/table/steel,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cp" = (/obj/structure/table/steel,/obj/machinery/microwave,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cq" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cr" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"cs" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"ct" = (/obj/effect/landmark/start{name = "Red Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cu" = (/obj/effect/landmark/start{name = "Blue Scavenger"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"cv" = (/obj/structure/banner/blue{pixel_x = 0; pixel_y = 32},/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/blue) +"cw" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"cx" = (/obj/structure/closet/crate,/obj/item/weapon/melee/classic_baton/trench_club,/obj/item/weapon/melee/classic_baton/trench_club,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cy" = (/turf/simulated/mineral,/area/warfare/homebase/red) +"cz" = (/obj/structure/table/steel,/obj/machinery/cooker/candy,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cA" = (/obj/effect/landmark/start{name = "Red Chef"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cB" = (/obj/effect/landmark/start{name = "Red Scavenger"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cC" = (/obj/structure/banner/red{pixel_y = -32; pixel_z = 0},/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/red) +"cD" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"cE" = (/obj/structure/bed/chair,/obj/effect/landmark/start{name = "Red Soldier"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cF" = (/obj/structure/table/steel,/obj/machinery/cooker/cereal,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cG" = (/obj/structure/table/steel,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cH" = (/obj/structure/bed/chair,/obj/effect/landmark/start{name = "Red Soldier"},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cI" = (/obj/structure/bed/chair,/obj/effect/landmark/start{name = "Red Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cJ" = (/obj/structure/bed/chair,/obj/effect/landmark/start{name = "Red Soldier"},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cK" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 4},/obj/effect/landmark/start{name = "Red Soldier"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cL" = (/obj/structure/table/woodentable,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cM" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/obj/effect/landmark/start{name = "Red Soldier"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cN" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cO" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes/jerichos,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cP" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cQ" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes/luckystars,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/obj/item/ammo_box/rifle,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cR" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/box/matches,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cS" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/device/compass,/obj/item/device/compass,/obj/item/device/compass,/obj/item/device/compass,/obj/item/device/compass,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"cT" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cU" = (/obj/machinery/vending/dinnerware,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cV" = (/obj/structure/closet/secure_closet/freezer/meat,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cW" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/firstaid/surgery,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cX" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/fancy/cigarettes/carcinomas,/obj/item/ammo_box/rifle,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cY" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/ammo_box/shotgun,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"cZ" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/fancy/cigarettes/carcinomas,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"da" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/wirecutters,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"db" = (/obj/machinery/cooker/oven,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dc" = (/obj/machinery/cooker/grill,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dd" = (/obj/machinery/cooker/fryer,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"de" = (/obj/structure/closet/chefcloset,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"df" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/effect/landmark/start{name = "Red Soldier"},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"dg" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/effect/landmark/start{name = "Red Soldier"},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"dh" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/effect/landmark/start{name = "Red Soldier"},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"di" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/effect/landmark/start{name = "Red Soldier"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dj" = (/obj/machinery/button/remote/blast_door/lever{id = "red"; pixel_y = 32},/obj/effect/landmark/start{name = "Red Sniper"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dk" = (/obj/structure/closet/crate,/obj/item/ammo_box/rifle,/obj/item/ammo_box/rifle,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"dl" = (/obj/structure/banner/red{pixel_y = -32},/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/red) +"dm" = (/obj/structure/closet/crate,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dn" = (/obj/structure/closet/crate,/obj/item/weapon/melee/classic_baton/trench_club,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"do" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"dp" = (/obj/structure/poster/blue,/turf/simulated/wall/concrete,/area/warfare/homebase/blue) +"dq" = (/turf/simulated/floor/dirty/tough,/area/warfare/homebase/blue) +"dr" = (/obj/effect/landmark/start{name = "Red Captain"},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"ds" = (/obj/structure/closet/crate,/obj/item/weapon/wirecutters,/obj/item/weapon/wirecutters,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dt" = (/obj/structure/closet/crate,/obj/item/weapon/wirecutters,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"du" = (/obj/structure/curtain,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dv" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/fancy/cigarettes/carcinomas,/obj/item/device/cassette/tape3,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dw" = (/obj/effect/landmark/start{name = "Red Squad Leader"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dx" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/box/matches,/obj/item/device/cassette/tape1,/obj/item/device/cassette/tape2,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dy" = (/obj/effect/landmark/start{name = "Red Bartender"},/obj/structure/toilet{icon_state = "toilet00"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dz" = (/obj/effect/landmark/start{name = "Red Soldier"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dA" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dB" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes/jerichos,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/obj/item/device/boombox,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dC" = (/obj/structure/bed,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dD" = (/obj/structure/closet/cabinet,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dE" = (/obj/machinery/optable,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dF" = (/obj/machinery/computer/operating,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dG" = (/obj/effect/landmark/start{name = "Red Medic"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dH" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"dI" = (/turf/simulated/open,/area/warfare/homebase/red) +"dJ" = (/obj/effect/landmark/start{name = "Red Practitioner"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dK" = (/obj/structure/poster/blue{pixel_y = 32},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"dL" = (/obj/structure/closet/secure_closet/medical2{req_access = newlist()},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dM" = (/obj/structure/closet/medical_wall,/turf/simulated/wall/concrete,/area/warfare/homebase/red) +"dN" = (/obj/structure/sign/medholo,/turf/simulated/wall/concrete,/area/warfare/homebase/red) +"dO" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/fire,/obj/item/weapon/storage/firstaid/fire,/obj/item/weapon/storage/firstaid/fire,/obj/item/weapon/storage/firstaid/fire,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dP" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/toxin,/obj/item/weapon/storage/firstaid/toxin,/obj/item/weapon/storage/firstaid/toxin,/obj/item/weapon/storage/firstaid/toxin,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dQ" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/adv,/obj/item/weapon/storage/firstaid/adv,/obj/item/weapon/storage/firstaid/adv,/obj/item/weapon/storage/firstaid/adv,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dR" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/regular,/obj/item/weapon/storage/firstaid/regular,/obj/item/weapon/storage/firstaid/regular,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dS" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"dT" = (/obj/effect/landmark/start{name = "Red Medic"},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dU" = (/obj/machinery/sleeper,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dV" = (/obj/machinery/vending/medical{req_access = newlist()},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"dW" = (/obj/structure/poster/red,/turf/simulated/wall/concrete,/area/warfare/homebase/red) +"dX" = (/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"dY" = (/obj/machinery/sleeper{icon_state = "sleeper_0"; dir = 1},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"dZ" = (/obj/effect/landmark/start{name = "Red Medic"},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ea" = (/obj/structure/bed/roller,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"eb" = (/obj/effect/landmark/map_data{height = 2},/turf/simulated/mineral,/area/warfare/homebase/red) +"ec" = (/obj/structure/closet/secure_closet/medical1/warfare,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ed" = (/obj/structure/closet/crate,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"ee" = (/obj/structure/closet/crate,/obj/item/weapon/plastique,/obj/item/weapon/plastique,/obj/item/weapon/plastique,/obj/item/weapon/crowbar,/obj/item/weapon/crowbar,/obj/item/weapon/crowbar,/turf/simulated/floor/dirty/tough,/area/warfare/homebase/blue) +"ef" = (/obj/structure/table/steel,/obj/structure/sink{pixel_y = 20},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"eg" = (/obj/effect/landmark/start{name = "Red Engineer"},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"eh" = (/obj/effect/landmark/start{name = "Red Engineer"},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ei" = (/obj/effect/landmark/start{name = "Blue Engineer"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"ej" = (/obj/structure/dirt_wall,/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/no_mans_land) +"ek" = (/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/capture_point/red/one) +"el" = (/turf/simulated/mineral,/turf/simulated/open,/area/space) +"em" = (/turf/simulated/open,/area/warfare/battlefield/capture_point/red/one) +"en" = (/obj/structure/dirt_wall,/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/capture_point/red/one) +"eo" = (/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 16},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"ep" = (/turf/simulated/open,/area/warfare/battlefield/capture_point/red/two) +"eq" = (/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/capture_point/red/two) +"er" = (/obj/structure/dirt_wall,/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/capture_point/red/two) +"es" = (/turf/simulated/mineral,/area/space) +"et" = (/turf/simulated/open,/area/warfare/battlefield/capture_point/blue/two) +"eu" = (/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/capture_point/blue/two) +"ev" = (/turf/simulated/open,/area/warfare/battlefield/capture_point/blue/one) +"ew" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"ex" = (/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/capture_point/blue/one) +"ey" = (/obj/structure/dirt_wall,/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/capture_point/blue/one) +"ez" = (/obj/machinery/vending/medical{req_access = newlist()},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"eA" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"eB" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/obj/structure/table/steel,/obj/item/weapon/reagent_containers/spray/cleaner/warfare,/obj/item/weapon/reagent_containers/spray/cleaner/warfare,/obj/item/weapon/reagent_containers/spray/cleaner/warfare,/obj/item/weapon/reagent_containers/spray/cleaner/warfare,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"eC" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/obj/structure/table/steel,/obj/item/weapon/reagent_containers/spray/cleaner/warfare,/obj/item/weapon/reagent_containers/spray/cleaner/warfare,/obj/item/weapon/reagent_containers/spray/cleaner/warfare,/obj/item/weapon/reagent_containers/spray/cleaner/warfare,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"eD" = (/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/capture_point/mid) +"eE" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/device/compass,/obj/item/device/compass,/obj/item/device/compass,/obj/item/device/compass,/obj/item/device/compass,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"eF" = (/obj/structure/table/woodentable,/obj/item/device/compass,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"eG" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"eH" = (/obj/structure/closet/crate{name = "gasmask crate"},/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/red) +"eI" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"eJ" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/obj/structure/iv_drip,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"eK" = (/obj/structure/closet/crate,/obj/item/weapon/reagent_containers/ivbag/blood/AMinus,/obj/item/weapon/reagent_containers/ivbag/blood/AMinus,/obj/item/weapon/reagent_containers/ivbag/blood/APlus,/obj/item/weapon/reagent_containers/ivbag/blood/APlus,/obj/item/weapon/reagent_containers/ivbag/blood/BMinus,/obj/item/weapon/reagent_containers/ivbag/blood/BMinus,/obj/item/weapon/reagent_containers/ivbag/blood/BPlus,/obj/item/weapon/reagent_containers/ivbag/blood/BPlus,/obj/item/weapon/reagent_containers/ivbag/blood/OMinus,/obj/item/weapon/reagent_containers/ivbag/blood/OMinus,/obj/item/weapon/reagent_containers/ivbag/blood/OPlus,/obj/item/weapon/reagent_containers/ivbag/blood/OPlus,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"eL" = (/obj/effect/landmark/start{name = "Blue Medic"},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"eM" = (/obj/structure/closet/crate,/obj/item/weapon/reagent_containers/ivbag/blood/AMinus,/obj/item/weapon/reagent_containers/ivbag/blood/AMinus,/obj/item/weapon/reagent_containers/ivbag/blood/APlus,/obj/item/weapon/reagent_containers/ivbag/blood/APlus,/obj/item/weapon/reagent_containers/ivbag/blood/BMinus,/obj/item/weapon/reagent_containers/ivbag/blood/BMinus,/obj/item/weapon/reagent_containers/ivbag/blood/BPlus,/obj/item/weapon/reagent_containers/ivbag/blood/BPlus,/obj/item/weapon/reagent_containers/ivbag/blood/OMinus,/obj/item/weapon/reagent_containers/ivbag/blood/OMinus,/obj/item/weapon/reagent_containers/ivbag/blood/OPlus,/obj/item/weapon/reagent_containers/ivbag/blood/OPlus,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"eN" = (/obj/structure/table/steel,/obj/structure/sink{pixel_y = 20},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"eO" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/obj/structure/iv_drip,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"eP" = (/turf/simulated/floor/trenches,/area/warfare/homebase/blue) +"eQ" = (/turf/simulated/floor/trenches,/area/warfare/homebase/red) +"eR" = (/obj/effect/landmark/start{name = "Blue Soldier"},/obj/machinery/button/remote/blast_door/lever{id = "blue"; pixel_x = 0; pixel_y = -32},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"eS" = (/obj/structure/dirt_wall,/obj/machinery/door/blast/shutters/open{id = "blue"},/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/blue) +"eT" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance,/obj/machinery/door/blast/shutters/open{id = "blue"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"eU" = (/obj/machinery/door/blast/shutters/open{id = "blue"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"eV" = (/obj/effect/landmark/start{name = "Red Sniper"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"eW" = (/obj/structure/dirt_wall,/obj/machinery/door/blast/shutters/open{id = "red"},/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/red) +"eX" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance,/obj/machinery/door/blast/shutters/open{id = "red"},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"eY" = (/obj/machinery/door/blast/shutters/open{id = "red"},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"eZ" = (/turf/simulated/wall/concrete,/area/warfare/battlefield/capture_point/red/one) +"fa" = (/obj/machinery/button/remote/blast_door/lever{id = "red"; pixel_x = -32},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"fb" = (/obj/effect/landmark/start{name = "Red Soldier"},/obj/machinery/button/remote/blast_door/lever{id = "red"; pixel_y = 32},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"fc" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"fd" = (/obj/effect/landmark/start{name = "Blue Soldier"},/obj/structure/toilet{icon_state = "toilet00"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"fe" = (/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 16},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ff" = (/obj/structure/bed/chair,/obj/effect/landmark/start{name = "Blue Soldier"},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"fg" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/effect/landmark/start{name = "Blue Soldier"},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"fh" = (/obj/machinery/bodyscanner{icon_state = "body_scanner_0"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"fi" = (/obj/machinery/body_scanconsole{icon_state = "body_scannerconsole"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"fj" = (/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/one) +"fk" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"fl" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"fm" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance{dir = 1; icon_state = "door_closed"; name = "Emergency Medical"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"fn" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance,/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"fo" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance{dir = 1; icon_state = "door_closed"; name = "Emergency Medical"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"fp" = (/obj/machinery/body_scanconsole{icon_state = "body_scannerconsole"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"fq" = (/obj/machinery/bodyscanner{icon_state = "body_scanner_0"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"fr" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"fs" = (/obj/machinery/shower{icon_state = "shower"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ft" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"fu" = (/turf/simulated/wall/concrete,/area/warfare/battlefield/capture_point/red/two) +"fv" = (/obj/effect/landmark/start{name = "Red Engineer"},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"fw" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"fx" = (/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/one) +"fy" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"fz" = (/obj/effect/landmark/start{name = "Blue Sniper"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"fA" = (/obj/structure/closet/crate,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"fB" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/item/ammo_magazine/c45rifle/akarabiner,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"fC" = (/obj/structure/closet/crate/freezer,/obj/item/organ/external/arm/robo_arm,/obj/item/organ/external/arm/robo_arm,/obj/item/organ/external/arm/right/robo_arm,/obj/item/organ/external/arm/right/robo_arm,/obj/item/organ/external/hand/robo_hand,/obj/item/organ/external/hand/robo_hand,/obj/item/organ/external/hand/right/robo_hand,/obj/item/organ/external/hand/right/robo_hand,/obj/item/organ/external/leg/robo_leg,/obj/item/organ/external/leg/right/robo_leg,/obj/item/organ/external/leg/right/robo_leg,/obj/item/organ/external/foot/robo_foot,/obj/item/organ/external/foot/robo_foot,/obj/item/organ/external/foot/right/robo_foot,/obj/item/organ/external/foot/right/robo_foot,/obj/item/organ/external/foot/right/robo_foot,/obj/item/organ/external/foot/right/robo_foot,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"fD" = (/obj/structure/closet/crate/freezer,/obj/item/organ/external/arm/robo_arm,/obj/item/organ/external/arm/robo_arm,/obj/item/organ/external/arm/right/robo_arm,/obj/item/organ/external/arm/right/robo_arm,/obj/item/organ/external/hand/robo_hand,/obj/item/organ/external/hand/robo_hand,/obj/item/organ/external/hand/right/robo_hand,/obj/item/organ/external/hand/right/robo_hand,/obj/item/organ/external/leg/robo_leg,/obj/item/organ/external/leg/right/robo_leg,/obj/item/organ/external/leg/right/robo_leg,/obj/item/organ/external/foot/robo_foot,/obj/item/organ/external/foot/robo_foot,/obj/item/organ/external/foot/right/robo_foot,/obj/item/organ/external/foot/right/robo_foot,/obj/item/organ/external/foot/right/robo_foot,/obj/item/organ/external/foot/right/robo_foot,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"fE" = (/obj/structure/dirt_wall,/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/capture_point/mid) +"fF" = (/turf/simulated/wall/concrete,/area/warfare/battlefield/capture_point/mid) +"fG" = (/obj/structure/barbwire,/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/capture_point/mid) +"fH" = (/obj/effect/landmark/start{name = "Red Sentry"},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"fI" = (/turf/simulated/wall/concrete,/area/warfare/battlefield/capture_point/blue/two) +"fJ" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/red/two) +"fK" = (/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/trench_section) +"fL" = (/turf/simulated/wall/concrete,/area/warfare/battlefield/capture_point/blue/one) +"fM" = (/obj/structure/dirt_wall,/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/trench_section) +"fN" = (/obj/structure/barbwire,/turf/simulated/floor/dirty/indestructable,/area/warfare/battlefield/trench_section) +"fO" = (/obj/structure/crematorium{dir = 4; icon_state = "crema1"; id = 2},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"fP" = (/obj/structure/crematorium{icon_state = "crema1"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"fQ" = (/obj/machinery/button/crematorium{pixel_y = 32},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"fR" = (/obj/machinery/button/crematorium{id = 2; pixel_y = 32},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/blue) +"fS" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"fT" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"fU" = (/obj/effect/landmark/start{name = "Blue Sentry"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"fV" = (/obj/effect/landmark/start{name = "Red Flame Trooper"},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"fW" = (/obj/effect/landmark/start{name = "Blue Flame Trooper"},/turf/simulated/floor/tiled,/area/warfare/homebase/blue) +"fX" = (/turf/simulated/floor/trench,/area/warfare/battlefield/capture_point/red/one) +"fY" = (/turf/simulated/floor/trench,/area/warfare/battlefield/capture_point/blue/one) +"fZ" = (/obj/structure/closet/crate,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/item/weapon/grenade/frag/warfare,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"ga" = (/turf/simulated/floor/trench,/area/warfare/battlefield/capture_point/blue/two) +"gb" = (/obj/structure/barbwire,/turf/simulated/floor/dirty/fake,/area/warfare/battlefield/no_mans_land) +"gc" = (/turf/simulated/floor/dirty/fake,/area/warfare/battlefield/no_mans_land) +"gd" = (/obj/structure/closet/crate,/obj/item/ammo_box/rifle,/obj/item/ammo_box/rifle,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"ge" = (/turf/simulated/floor/dirty/tough/fake,/area/warfare/homebase/blue) +"gf" = (/turf/simulated/floor/trench,/area/warfare/battlefield/capture_point/red/two) +"gg" = (/obj/structure/closet/crate,/obj/item/ammo_box/rifle,/obj/item/ammo_box/rifle,/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"gh" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"gi" = (/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"gj" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/trenches,/area/warfare/battlefield/capture_point/blue/two) +"gk" = (/turf/simulated/floor/dirty/tough,/area/warfare/battlefield/capture_point/blue/two) +"gl" = (/turf/simulated/floor/dirty/tough,/area/warfare/battlefield/capture_point/red/two) +"gm" = (/turf/simulated/floor/dirty/tough/fake,/area/warfare/homebase/red) +"gn" = (/turf/simulated/floor/dirty/tough,/area/warfare/homebase/red) +"go" = (/obj/structure/closet/crate,/obj/item/weapon/plastique,/obj/item/weapon/plastique,/obj/item/weapon/plastique,/obj/item/weapon/crowbar,/obj/item/weapon/crowbar,/obj/item/weapon/crowbar,/turf/simulated/floor/dirty/tough,/area/warfare/homebase/red) + +(1,1,1) = {" +esaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaabfOadfRabaeahajadabakakakakabbpbpabamanaoaqeBabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaabajajayabadadajadaradadadadabeIaladadadadadaddVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaabfOadadabatfCauavawadfifhayazalaladadaAadaAadaBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaabajajayababababababadadadadadalalaCaCaAeJaAeKdVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaabfOadadabaAaDajaDaAadadadadadalalazababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaabajajayabeLadajadaAadadadayabalalababdpabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaabfOadadabaAadajadaAadfifheoabalalalalalalaxaFaFabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaabajajadaraAaGajaGaAadadadayabalalalalaHalaxaFaFabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaabababababababababababababababfnalabababababababababababababababababababaaaaaaaaes +esaaaaaaaaaaaaaaaaabaIaddKadadayabaJeNaKbSaKaLabalaMabababaNbDadabaNbDadabaNbDacabaNbDacabaaaaaaaaes +esaaaaaaaaaaaaaaaaabadadadadadadabaQadadadadbaabalalabababaRaSbXabaRaSbXabaIcufdabaIcufdabaaaaaaaaes +esaaaaaaaaaaaaaaaaabadadaVaVadadabaXadaZadadbeabalalabababaSadacabaSadacabbbadaSabbbadaSabaaaaaaaaes +esaaaaaaaaaaaaaaaaabaIbcaOaObdayabbeadadadadbgabalaMababababardpababarabababarabababarabababaaaaaaes +esaaaaaaaaaaaaaaaaabadbcaOaObdadabbfadadadadadabalaladadadadadadadadadadadadadadadadadadadabaaaaaaes +esaaaaaaaaaaaaaaaaabadbcaOaObdadabbgadbkbhbibjabalalfmadadadadadadadadadadadadadadadadadadabaaaaaaes +esaaaaaaaaaaaaaaaaabaIadblbladayababadabababababalaMabbmbnaleieialalbPababbmbnaleieialalbqabaaaaaaes +esaaaaaaaaaaaaaaaaabadadadadadadadadadadadadadadbralabbmbnaleieialalbPababbmbnaleieialalbuabaaaaaaes +esaaaaaaaaaaaaaaaaabadadaVaVadadadaVaVadadadadfmalalabbvbwalalalalbwbxababffbwalalalalbwbxabaaaaaaes +esaaaaaaaaaaaaaaaaabaIbcaOaObdadbcbDaObdadadayabalaMabbybzalbAbAalbBbCababbCcSalbAbAalbCbEabaaaaaaes +esaaaaaaaaaaaaaaaaabadbcaOaObdadbcaOaObdadadadabalalabbFbCalbAbAalbGbHababbEcSalbAbAalbIbJabaaaaaaes +esaaaaaaaaaaaaaaaaabadbcaOaObdadbcaOaObdadadaPabalalabbLbMalalalalbMbNababfgbMalalalalbMbNabaaaaaaes +esaaaaaaaaaaaaaaaaabaIadblbladadadblbladadadbOabalaMabfzfzalfUfUalapbQababedalalfUfUalaledabaaaaaaes +esaaaaaaaaaaaaaaaaabfkauadadaucaauadadauadadbTabchalabbUbqeRfWfWbVapbQababbQbQbValalbVasasabaaaaaaes +esaaaaaaaaaaaaaaaaabababeSeSdpabdpeSeSabababababeTeUababababeSeSababababababababeSeSababababaaaaaaes +esaaaaaaaaaaaaaaaaaaaacbbYbYbYbYbYbYbYbYbYbYbYbRbYbYcvbYbYbYbYbYbYbYbYbYbYbYePePePePaaaaaaaaaaaaaaes +esaaaaaaaaaaaaaaaaaaaacbbYbYbYbYbYbYbYbYbYbYbYaTbYbYaTbYbYbYbYbYbYbYbYbYbYbYePePePePaaaaaaaaaaaaaaes +esesesesesesesesesesesesbZbZbZbZbZbZbZbZbZbZbZbZbYbYbZbZbZbZbZbZbZbZbZbZbZbZeseseseseseseseseseseses +esesesesesesesesesesesesccccccccccccccccccccccccbYbYcccccccccccccccccccccccceseseseseseseseseseseses +esesesesesesesesesesesesdqdqdqdqdqdqdqdqdqdqdqeedqdqeedqdqdqdqdqdqdqdqdqdqdqeseseseseseseseseseseses +esesesesesesesesesesesesgegegegegegegegegegegegegegegegegegegegegegegegegegeeseseseseseseseseseseses +esesesesesesesesesesesesgkgkgkgkgkgkgkgkgkgkgkgkgkgkgkgkgkgkgkgkgkgkgkgkgkgkeseseseseseseseseseseses +esesesesesesesesesesesesaYaYaYaYaYaYaYaYaYaYaYaYgagaaYaYaYaYaYaYaYaYaYaYaYaYeseseseseseseseseseseses +esesesesesesesesesesesesgagagagagagagagagagagagagagagagagagagagagagagagagagaeseseseseseseseseseseses +esesesesesesesesesesesesetetetetetetetetetetaYgagagagaaYeteteteteteteteteteteseseseseseseseseseseses +esesesesesesesesesesesesetetetetetetetetetetaYgagagagaaYeteteteteteteteteteteseseseseseseseseseseses +esesesesesesesesesesesesetetfIfIfIfIfIfIetetaYaYaYaYaYaYetetfIfIfIfIfIfIeteteseseseseseseseseseseses +esesesesesesesesesesesesetetfIfZcDcDgdfIetetetetetetetetetetfIfZcDcDgdfIeteteseseseseseseseseseseses +esesesesesesesesesesesesetetfIcrcscDggfIetetetetetetetetetetfIcrcscDggfIeteteseseseseseseseseseseses +esesesesesesesesesesesesaYaYfIghgigigjfIaYaYaYaYetetaYaYaYaYfIghgigigjfIaYaYeseseseseseseseseseseses +eseseseseseseseseseseseseueufIfIdHgifIfIeueueuaYetetaYeueueufIfIdHgifIfIeueueseseseseseseseseseseses +eseseseseseseseseseseseseueueueueueueueueueueuaYetetaYeueueueueueueueueueueueseseseseseseseseseseses +esesesesesesesesesesesesfKfKfKfKfKfKfKfKfKfKfKfMetetfMfKfKfKfKfKfKfKfKfKfKfKeseseseseseseseseseseses +esesesesesesesesesesesesfKfKfKfKfKfKfKfKfKfKfKfNfMfMfNfKfKfKfKfKfKfKfKfKfKfKeseseseseseseseseseseses +esesesesesesesesesesesesfKfKfKfKfKfKfKfKfKfKfKfMfKfKfMfKfKfKfKfKfKfKfKfKfKfKeseseseseseseseseseseses +esesesesesesesesesesesesfKfKfKfKfKfKfKfKfKfKfKfNfMfMfNfKfKfKfKfKfKfKfKfKfKfKeseseseseseseseseseseses +esesesesesesesesesesesesfKfKfKfKfKfKfKfKfKfKfKfMevevfMfKfKfKfKfKfKfKfKfKfKfKeseseseseseseseseseseses +esesesesesesesesesesesesexexexexexexexexexexexeyeveveyexexexexexexexexexexexeseseseseseseseseseseses +esesesesesesesesesesesesexexfLfLfcfjfLfLexexexeyeveveyexexexfLfLfcfjfLfLexexeseseseseseseseseseseses +eseseseseseseseseseseseseyeyfLexexexexfLeyeyeyeyeveveyeyeyeyfLexexexexfLeyeyeseseseseseseseseseseses +esesesesesesesesesesesesevevfLexfLfLexfLevevevevevevevevevevfLexfLfLexfLeveveseseseseseseseseseseses +eseseseseseseseseseseseseveveyexexexexeyeveveveveveveveveveveyexexexexeyeveveseseseseseseseseseseses +eseseseseseseseseseseseseveveyeyeyeyeyeyeveveyeyeyeyeyeyeveveyeyeyeyeyeyeveveseseseseseseseseseseses +eseseseseseseseseseseseseveveveveveveveveveveyfYfYfYfYeyeveveveveveveveveveveseseseseseseseseseseses +eseseseseseseseseseseseseveveveveveveveveveveyfYfYfYfYeyeveveveveveveveveveveseseseseseseseseseseses +esesesesesesesesesesesesfYfYfYfYfYfYfYfYfYfYfYfYfYfYfYfYfYfYfYfYfYfYfYfYfYfYeseseseseseseseseseseses +eseseseseseseseseseseseseyeyeyeyeyeyeyeyeyeyeyeyfYfYeyeyeyeyeyeyeyeyeyeyeyeyeseseseseseseseseseseses +esesesesesesesesesesesesgbgbgbgbgbgbgbgbgbgbgbgbgcgcgbgbgbgbgbgbgbgbgbgbgbgbeseseseseseseseseseseses +esesesesesesesesesesesesaUaUaUaUaUaUaUaUaUaUaUaUaiaiaUaUaUaUaUaUaUaUaUaUaUaUeseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiagagagagagagaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaieDeDfEfEfEfEfEfEeDeDaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaieDeDeDeDeDeDeDeDeDeDaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiagfEeDfFfFfFfFfFfFeDfEagaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiagfEeDeDeDeDeDeDeDeDfEagaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiagfEeDeDeDeDeDeDeDeDfEagaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiagfEeDfFeDeDeDeDfFeDfEagaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesagejagejagejagejfGeDfFeDeDeDeDfFeDfEagejagejagejagejeseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaieDeDfFeDeDeDeDfFeDeDaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesagejagejagejagejfGeDfFeDeDeDeDfFeDfEagejagejagejagejeseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiagfEeDfFeDeDeDeDfFeDfEagaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiagfEeDfFeDeDeDeDfFeDfEagaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiagfEeDeDeDeDeDeDeDeDfEagaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiagfEeDeDeDeDeDeDeDeDfEagaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiagfEeDfFfFfFfFfFfFeDfEagaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaieDeDeDeDeDeDeDeDeDeDaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaieDeDfEfEfEfEfEfEeDeDaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiagagagagagagaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaieseseseseseseseseseseses +esesesesesesesesesesesesaUaUaUaUaUaUaUaUaUaUaUaUaiaiaUaUaUaUaUaUaUaUaUaUaUaUeseseseseseseseseseseses +esesesesesesesesesesesesgbgbgbgbgbgbgbgbgbgbgbgbgcgcgbgbgbgbgbgbgbgbgbgbgbgbeseseseseseseseseseseses +esesesesesesesesesesesesenenenenenenenenenenenenfXfXeneneneneneneneneneneneneseseseseseseseseseseses +esesesesesesesesesesesesfXfXfXfXfXfXfXfXfXfXfXfXfXfXfXfXfXfXfXfXfXfXfXfXfXfXeseseseseseseseseseseses +esesesesesesesesesesesesememememememememememenfXfXfXfXenememememememememememeseseseseseseseseseseses +esesesesesesesesesesesesememememememememememenfXfXfXfXenememememememememememeseseseseseseseseseseses +esesesesesesesesesesesesememenenenenenenememenenenenenenememenenenenenenememeseseseseseseseseseseses +esesesesesesesesesesesesememenekekekekenememememememememememenekekekekenememeseseseseseseseseseseses +esesesesesesesesesesesesememeZekeZeZekeZememememememememememeZekeZeZekeZememeseseseseseseseseseseses +eseseseseseseseseseseseseneneZekekekekeZenenenenememeneneneneZekekekekeZeneneseseseseseseseseseseses +esesesesesesesesesesesesekekeZeZfwfxeZeZekekekenememenekekekeZeZfwfxeZeZekekeseseseseseseseseseseses +esesesesesesesesesesesesekekekekekekekekekekekenememenekekekekekekekekekekekeseseseseseseseseseseses +esesesesesesesesesesesesfKfKfKfKfKfKfKfKfKfKfKfMememfMfKfKfKfKfKfKfKfKfKfKfKeseseseseseseseseseseses +esesesesesesesesesesesesfKfKfKfKfKfKfKfKfKfKfKfNfMfMfNfKfKfKfKfKfKfKfKfKfKfKeseseseseseseseseseseses +esesesesesesesesesesesesfKfKfKfKfKfKfKfKfKfKfKfMfKfKfMfKfKfKfKfKfKfKfKfKfKfKeseseseseseseseseseseses +esesesesesesesesesesesesfKfKfKfKfKfKfKfKfKfKfKfNfMfMfNfKfKfKfKfKfKfKfKfKfKfKeseseseseseseseseseseses +esesesesesesesesesesesesfKfKfKfKfKfKfKfKfKfKfKfMepepfMfKfKfKfKfKfKfKfKfKfKfKeseseseseseseseseseseses +eseseseleseseleseleseseseqeqeqeqeqeqeqeqeqeqeqerepepereqeqeqeqeqeqeqeqeqeqeqeseseseseseseseseseseses +eseseleseseseseseseseseseqeqfufufJdXfufueqeqeqerepepereqeqeqfufufJdXfufueqeqeseseseseseseseseseseses +esesesesesesesesesesesesererfucwdXdXewfuererererepepererererfucwdXdXewfuerereseseseseseseseseseseses +esesesesesesesesesesesesepepfueAeGfyfyfuepepepepepepepepepepfueAeGfyfyfuepepeseseseseseseseseseseses +esesesesesesesesesesesesepepfufAfyfyfBfuepepepepepepepepepepfufAfyfyfBfuepepeseseseseseseseseseseses +esesesesesesesesesesesesepepfufufufufufuepepererererererepepfufufufufufuepepeseseseseseseseseseseses +esesesesesesesesesesesesepepepepepepepepepepergfgfgfgferepepepepepepepepepepeleseseseleseseseseseses +esesesesesesesesesesesesepepepepepepepepepepergfgfgfgferepepepepepepepepepepeseseseseseseseseseseses +esesesesesesesesesesesesgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfeseseseseseseseseseseses +eseseseseseseseseseseseserererererererererererergfgferererererererererererereseseseseseseseseseseses +esesesesesesesesesesesesglglglglglglglglglglglglglglglglglglglglglglglglglgleseseseseseseseseseseses +esesesescycycycycycycycygmgmgmgmgmgmgmgmgmgmgmgmgmgmgmgmgmgmgmgmgmgmgmgmgmgmcycycycycycycycyeseseses +esesesescycycycycycycycygngngngngngngngngngngngogngngogngngngngngngngngngngncycycycycycycycyeseseses +esesesescycycycycycycycycececececececececececececdcdcececececececececececececycycycycycycycyeseseses +esesesescycycycycycycycycfcfcfcfcfcfcfcfcfcfcfcfcdcdcfcfcfcfcfcfcfcfcfcfcfcfcycycycycycycycyeseseses +escycycycycycycycycycybscdcdcdcdcdcdcdcdcdcdcdeHcdcdeHcdcdcdcdcdcdcdcdcdcdcdeQeQeQeQcycycycycycycyes +escycycycycycycycycycybscdcdcdcdcdcdcdcdcdcdcdcCcdcddlcdcdcdcdcdcdcdcdcdcdcdeQeQeQeQcycycycycycycyes +escycycycycycycycycgcgcgcgeWcgcgcgcgcgcgcgcgcgcgeXeYcgcgcgcgeWeWdWcgcgcgcgcgcgcgeWeWcgcgcgcgcycycyes +escycycycycycycycycgdmflaWcldjcmcgcnefcobWcocpcgfacqcgfSfTfbegegctciafcgcgfSfTfbctctctcicxcgcycycyes +escycycycycycycycycgclclclcleVclcgczclcAclclcGcgcicicgfSfTcifVfVciciafcgcgfSfTegciciegcidncgcycycyes +escycycycycycycycycgclclcEcEclcldWcFclclclclcNcgcicicgcHcIcifHfHcicIcJcgcgcHcIcicicicicIcJcgcycycyes +escycycycycycycycycgckcKcLcLcMcmcgcNclclclclcVcgcicqcgcOcPcicicicicQcRdWcgcReEcicicicicRcTcgcycycyes +escycycycycycycycydWclcKcLcLcMclcgcUclclclclclcgcicicgcWcRcicicicicXcYcgcgcTeEcicicicicZdacgcycycyes +escycycycycycycycycgclcKcLcLcMclcgcVcldedbdcddcgcicicgdfdgcicicicidgdhcgcgdfdgcicicicidgdhcgcycycyes +escycycycycycycycycgckcldidiclcmcgcgclcgcgcgcgcgcicqcgcxcicicicicidSdkcgcgdkcicicicicicidScgcycycyes +escycycycycycycycycgclclclclclclclclclclclclclclcicicgdncicicicicidSdkcgcgdkcicicicicicidScgcycycyes +escycycycycycycycycgclclcEcEclclclcEcEclclclclfodrciclclclclclclclclclclclclclclclclclclclcgcycycyes +escycycycycycycycycgckcKcLcLcMclcKcLcLcMclclcmcgcicifoclclclclclclcldsdsclcldsdtclclclclclcgcycycyes +escycycycycycycycycgclcKcLcLcMclcKcLcLcMclclclcgcjcicgehclfvcgcgducgcgcgducgcgcgducgcgcgducgcgcycyes +escycycycycycycycycgclcKcLcLcMclcKcLeFcMclcldvcgcicicgcgducgcgckdwclcgckdwclcgckdwclcgckdwclcgcycyes +escycycycycycycycycgckcldidiclclcldidiclclcldxcgcicqcgfrclfscgdydzcBcgdydzcBcgdydzcBcgdydzcBcgcycyes +escycycycycycycycycgcldAclcldAcldAclcldAclcldBcgcicicgfrdAftcgdCeFdDcgdCeFdDcgdCeFdDcgdCeFdDcgcycyes +escycycycycycycycycgcgcgcgcgcgcgcgcgcgcgcgdWcgcgcicicgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcycyes +escycycycycycycycycgfPclfQcgdEdFdGclcgbKbKclclclciciciaEdIdIcgcycycycycycycycycycycycycycycycycycyes +escycycycycycycycycgdGdJclcgckcldJclduclclclclfocidociaEdIdIcgcycycycycycycycycycycycycycycycycycyes +escycycycycycycycycgfPclclcgbofDcldLdMckclclcmdNcgcgcgcgcgcgcgcgcycycycycycycycycycycycycycycycycyes +escycycycycycycycycgdGdJcmcgcgcgcgcgcgclclclclcleMdOdPdQdReCcgcgcycycycycycycycycycycycycycycycycyes +escycycycycycycycycgfPclclcgdTdUdGdUdGfpfqclclclclclclclclclezcgcycycycycycycycycycycycycycycycycyes +escycycycycycycycycgdGdJcldWdJcldJcldJclclclfecgckcldGcldGclbtcgcycycycycycycycycycycycycycycycycyes +escycycycycycycycycgfPclcmcgdJcldJcldJfpfqclcmcgececdJeOdJclezcgcycycycycycycycycycycycycycycycycyes +escycycycycycycycycgdGdJcldudGdYdZdYdGeaeaeaeacgcgcgcgcgcgcgcgcgcycycycycycycycycycycycycycycycycyes +esebcycycycycycycycgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcycycycycycycycycycycycycycycycycycycycycycycycycyes +"} diff --git a/maps/oldfare/warfare-3.dmm b/maps/oldfare/warfare-3.dmm new file mode 100644 index 00000000..b4b4c639 --- /dev/null +++ b/maps/oldfare/warfare-3.dmm @@ -0,0 +1,75 @@ +"a" = (/turf/space,/area/space) +"b" = (/obj/structure/lattice,/turf/space,/area/space) +"c" = (/turf/simulated/wall/r_wall,/area/tcommsat/computer) +"d" = (/obj/effect/floor_decal/industrial/outline/grey,/obj/machinery/message_server,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"e" = (/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/effect/floor_decal/industrial/warning{dir = 10},/turf/simulated/floor/plating,/area/tcommsat/computer) +"f" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/tcommsat/computer) +"g" = (/obj/machinery/power/terminal{tag = "icon-term (WEST)"; icon_state = "term"; dir = 8},/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 6},/obj/machinery/alarm/server{pixel_y = 28},/turf/simulated/floor/plating,/area/tcommsat/computer) +"h" = (/obj/machinery/telecomms/server/presets/command,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"i" = (/turf/simulated/floor/bluegrid,/area/tcommsat/computer) +"j" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/bluegrid,/area/tcommsat/computer) +"k" = (/obj/machinery/telecomms/processor/preset_two,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"l" = (/obj/machinery/telecomms/bus/preset_two,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"m" = (/obj/machinery/telecomms/relay/preset/telecomms,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"n" = (/obj/machinery/telecomms/broadcaster/preset_right,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"o" = (/obj/machinery/telecomms/relay/preset/station,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"p" = (/obj/machinery/telecomms/bus/preset_four,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"q" = (/obj/machinery/telecomms/processor/preset_four,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"r" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/bluegrid,/area/tcommsat/computer) +"s" = (/obj/machinery/telecomms/hub/preset,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"t" = (/obj/machinery/light{dir = 4; icon_state = "tube1"; tag = ""},/turf/simulated/floor/bluegrid,/area/tcommsat/computer) +"u" = (/obj/machinery/telecomms/bus/preset_one,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"v" = (/obj/machinery/telecomms/processor/preset_one,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"w" = (/obj/effect/floor_decal/industrial/outline/grey,/obj/machinery/ntnet_relay,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"x" = (/obj/machinery/telecomms/receiver/preset_right,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"y" = (/obj/machinery/bluespacerelay,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"z" = (/obj/machinery/telecomms/processor/preset_three,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"A" = (/obj/machinery/telecomms/bus/preset_three,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"B" = (/obj/machinery/access_button{command = "cycle_interior"; frequency = 1381; master_tag = "telecoms_airlock"; name = "interior access button"; pixel_x = -25; pixel_y = -25; req_access = list(13)},/turf/simulated/floor/bluegrid,/area/tcommsat/computer) +"C" = (/obj/machinery/telecomms/server/presets/supply,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"D" = (/obj/effect/floor_decal/industrial/outline/grey,/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"E" = (/obj/effect/floor_decal/industrial/outline/grey,/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"F" = (/obj/structure/grille,/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/plating,/area/tcommsat/computer) +"G" = (/obj/machinery/door/airlock/external{frequency = 1381; icon_state = "door_locked"; id_tag = "telecoms_inner"; locked = 1; name = "External Access"; req_access = list(13)},/turf/simulated/floor/plating,/area/tcommsat/computer) +"H" = (/obj/structure/grille,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/plating,/area/tcommsat/computer) +"I" = (/obj/machinery/telecomms/server/presets/engineering,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"J" = (/obj/machinery/telecomms/server/presets/service,/obj/effect/floor_decal/industrial/outline/grey,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"K" = (/obj/machinery/telecomms/server/presets/medical,/obj/effect/floor_decal/industrial/outline/grey,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"L" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 2; frequency = 1381; id_tag = "telecoms_pump"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1381; id_tag = "telecoms_airlock"; pixel_x = 25; pixel_y = 10; req_access = list(13); tag_airpump = "telecoms_pump"; tag_chamber_sensor = "telecoms_sensor"; tag_exterior_door = "telecoms_outer"; tag_interior_door = "telecoms_inner"},/obj/machinery/airlock_sensor{frequency = 1381; id_tag = "telecoms_sensor"; pixel_x = 25; pixel_y = 0},/turf/simulated/floor/plating,/area/tcommsat/computer) +"M" = (/obj/machinery/telecomms/server/presets/security,/obj/effect/floor_decal/industrial/outline/grey,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) +"N" = (/obj/machinery/telecomms/server/presets/common,/obj/effect/floor_decal/industrial/outline/grey,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled/dark,/area/tcommsat/computer) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +bbcccccccbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +cccdefghcccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +ciiiiijiiicaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +cklminjopqcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +criiisjiitcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +cuvwixjyzAcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +ciiiiBjiiicaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +cCDEFGHEDIcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +ccJKFLHMNccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/oldfare/warfare.dm b/maps/oldfare/warfare.dm new file mode 100644 index 00000000..a01f53a3 --- /dev/null +++ b/maps/oldfare/warfare.dm @@ -0,0 +1,28 @@ +#if !defined(using_map_DATUM) + #include "warfare_areas.dm" + #include "warfare_shuttles.dm" + #include "warfare_unit_testing.dm" + #include "jobs/captain_verbs.dm" + #include "jobs/warfare_jobs.dm" + #include "jobs/soldiers.dm" + #include "jobs/fortress.dm" + #include "jobs/blue/blue_fortress.dm" + #include "jobs/blue/blue_soldiers.dm" + #include "jobs/red/red_fortress.dm" + #include "jobs/red/red_soldiers.dm" + #include "warfare_items.dm" + #include "../shared/items/clothing.dm" + #include "../shared/items/cards_ids.dm" + + #include "warfare-1.dmm" + #include "warfare-2.dmm" + + #include "../../code/modules/lobby_music/generic_songs.dm" + + #define using_map_DATUM /datum/map/warfare + +#elif !defined(MAP_OVERRIDE) + + #warn A map has already been included, ignoring Example + +#endif diff --git a/maps/oldfare/warfare_areas.dm b/maps/oldfare/warfare_areas.dm new file mode 100644 index 00000000..08c03592 --- /dev/null +++ b/maps/oldfare/warfare_areas.dm @@ -0,0 +1,265 @@ +#define REQUIRED_CAPTURED_ZONES 5 //You gotta hold all four trenches and mid in order to enter the enemies zone. +#define REQUIRED_TRENCH_ZONES 3 //Hold + +GLOBAL_LIST_EMPTY(blue_captured_zones) //= list() +GLOBAL_LIST_EMPTY(red_captured_zones) // = list() + +GLOBAL_LIST_EMPTY(mortar_areas) // = list() + + +/area/constructionsite + name = "\improper Construction Site" + icon_state = "storage" + +/area/maintenance/fsmaint2 + name = "\improper Fore Starboard Maintenance - 2" + icon_state = "fsmaint" + +/area/medical/surgery + name = "\improper Operating Theatre" + icon_state = "surgery" + +/area/warfare + music = 'sound/music/trench_bgm.ogg' + dynamic_lighting = TRUE + requires_power = FALSE + +/area/warfare/battlefield + name = "\improper Battlefield" + var/captured = null + turf_initializer = /decl/turf_initializer/oldfare + var/can_pre_enter = FALSE + +/area/warfare/battlefield/trench_section//So they can cross atop their trench section. + can_pre_enter = TRUE + +/area/warfare/battlefield/trench_section/underground//So it doesn't spawn random shit underground. + forced_ambience = null + turf_initializer = null + + +/area/warfare/battlefield/trench_section/underground/Entered(mob/living/L, area/A) + . = ..() + if(istype(L) && !istype(A, /area/warfare/battlefield)) + L.clear_fullscreen("fog") + L.clear_fullscreen("ash") + L.clear_fullscreen("fallout") + +/area/warfare/battlefield/no_mans_land + name = "\improper No Man\'s Land" + + New() + ..() + GLOB.mortar_areas += src + +/area/warfare/battlefield/Entered(mob/living/L, atom/A) + . = ..() + if(istype(L) && !istype(A, /area/warfare/battlefield))//Doesn't work but this does stop the lag. + L.overlay_fullscreen("fog", /obj/screen/fullscreen/fog) + L.overlay_fullscreen("fallout", /obj/screen/fullscreen/fallout) + L.overlay_fullscreen("ash", /obj/screen/fullscreen/storm) + +/area/warfare/battlefield/Exited(mob/living/L, area/A) + . = ..() + if(istype(L) && !istype(A, /area/warfare/battlefield)) + L.clear_fullscreen("fog") + L.clear_fullscreen("ash") + L.clear_fullscreen("fallout") + +/area/warfare/battlefield/capture_point + name = "\improper Capture Point" + icon_state = "storage" + turf_initializer = null + var/red_capture_points = 0 + var/blue_capture_points = 0 + var/list/blues = list() + var/list/reds = list() + +/area/warfare/battlefield/capture_point/New() + ..() + START_PROCESSING(SSprocessing, src) + +/area/warfare/battlefield/capture_point/Entered(atom/A) + . = ..() + if(ishuman(A)) + var/mob/living/carbon/human/H = A + if(H.warfare_faction != captured) + to_chat(H, "Now capturing [src]!") + else + to_chat(H, "Now defending [src]!") + +/area/warfare/battlefield/capture_point/Process() + for(var/mob/living/carbon/human/H in src) + if(!istype(H)) + continue + + if(H.warfare_faction == BLUE_TEAM) + if(H.stat == CONSCIOUS)//If they're dead or unconcious then don't add them. + blues |= H + else if(H.stat > 0)//If they die or pass out remove them. + blues -= H + else if(!H.client)//No client, then remove them. + blues -= H + + //Same for red team. + else if(H.warfare_faction == RED_TEAM ) + if(H.stat == CONSCIOUS) + reds |= H + else if(H.stat > 0) + reds -= H + else if(!H.client) + reds -= H + + if(blues.len > reds.len)//More of the blue team than red team is in the area. + if(blue_capture_points < config.trench_capture_points) + blue_capture_points++//Increase the points until it's captured. + if(red_capture_points > 0) + red_capture_points-- + else if(blues.len < reds.len)//Opposite here. + if(red_capture_points < config.trench_capture_points) + red_capture_points++ + if(blue_capture_points > 0) + blue_capture_points-- + + if(blue_capture_points == (config.trench_capture_points/2) && (captured != BLUE_TEAM))//Announce when we're halfway done. + to_world("[uppertext("[BLUE_TEAM] are 50% done capturing the [src]")]") + + if(red_capture_points == (config.trench_capture_points/2) && (captured != RED_TEAM)) + to_world("[uppertext("[RED_TEAM] are 50% done capturing the [src]")]") + + if(blue_capture_points >= config.trench_capture_points && (captured != BLUE_TEAM))//If we've already captured it we don't want to capture it again. + to_world("[uppertext("[BLUE_TEAM] HAVE CAPTURED THE [src]")]!") + captured = BLUE_TEAM + GLOB.blue_captured_zones |= src//Add it to our list. + GLOB.red_captured_zones -= src//Remove it from theirs. + blue_capture_points = 0//Reset it back to 0. + red_capture_points = 0//For both sides. + sound_to(world, 'sound/effects/capture.ogg') + + else if(red_capture_points >= config.trench_capture_points && (captured != RED_TEAM)) + to_world("[uppertext("[RED_TEAM] HAVE CAPTURED THE [src]")]!") + captured = RED_TEAM + GLOB.red_captured_zones |= src + GLOB.blue_captured_zones -= src + blue_capture_points = 0 + red_capture_points = 0 + sound_to(world, 'sound/effects/capture.ogg') + +/area/warfare/battlefield/capture_point/Exit(mob/living/L) + . = ..() + if(ishuman(L)) + if(L in blues) + blues -= L + else if(L in reds) + reds -= L + +/area/warfare/battlefield/capture_point/mid + name = "Middle Bunker" + icon_state = "start" + +/area/warfare/battlefield/capture_point/red + icon_state = "red" + captured = RED_TEAM + + New()//They start out having these by default. + ..() + GLOB.red_captured_zones |= src + +/area/warfare/battlefield/capture_point/red/Enter(atom/movable/AM) + if(ishuman(AM)) + var/mob/living/carbon/human/H = AM + if(H.warfare_faction == BLUE_TEAM && (GLOB.blue_captured_zones.len < REQUIRED_TRENCH_ZONES)) + to_chat(H, "WE DO NOT CONTROL THE MIDDLE BUNKER!") + return FALSE + return TRUE + +/area/warfare/battlefield/capture_point/red/one + name = "First South Trench" + +/area/warfare/battlefield/capture_point/red/two + name = "Second South Trench" + +/area/warfare/battlefield/capture_point/blue + icon_state = "blue" + captured = BLUE_TEAM + + New() + ..() + GLOB.blue_captured_zones |= src + +/area/warfare/battlefield/capture_point/blue/Enter(atom/movable/AM) + if(ishuman(AM)) + var/mob/living/carbon/human/H = AM + if(H.warfare_faction == RED_TEAM && (GLOB.red_captured_zones.len < REQUIRED_TRENCH_ZONES)) + to_chat(H, "WE DO NOT CONTROL THE MIDDLE BUNKER!") + return FALSE + return TRUE + +/area/warfare/battlefield/capture_point/blue/one + name = "First North Trench" + +/area/warfare/battlefield/capture_point/blue/two + name = "Second North Trench" + +//If it's not time for war then you can't exit your starting trench. +/area/warfare/battlefield/Enter(atom/movable/mover as mob|obj, atom/forget as mob|obj|turf|area) + if(!iswarfare()) + return TRUE + if(ishuman(mover)) + var/mob/living/carbon/human/H = mover + + if(can_pre_enter)//You can always enter these areas. + return TRUE + + if(locate(/obj/item/device/boombox) in H)//Locate the boombox. + to_chat(H, "I can't bring this with me onto the battlefield. Wouldn't want to lose it.")//No you fucking don't. + return //Keep that boombox at base asshole. + + if(locate(/obj/item/weapon/storage) in H)//Gotta check storage as well. + var/obj/item/weapon/storage/S = locate() in H + if(locate(/obj/item/device/boombox) in S) + to_chat(H, "I can't bring this with me onto the battlefield. Wouldn't want to lose it.") + return + + if(istype(job_master.GetJobByTitle(H.job), /datum/job/fortress) && captured != H.warfare_faction) + to_chat(H, "I need to stay home!") + return FALSE + + if(!SSWarfare.battle_time && captured != H.warfare_faction)//So people can enter their own trenches. + to_chat(H, "I am not ready to die yet!") + return FALSE + + if(istype(mover, /obj/item/device/boombox))//No boomboxes in no man's land please. + return + + return TRUE + +/area/warfare/homebase + name = "\improper Base" + icon_state = "start" + requires_power = FALSE + +/area/warfare/homebase/red + name = "\improper Red Base" + icon_state = "security" + +/area/warfare/homebase/red/Enter(atom/movable/AM) + if(ishuman(AM)) + var/mob/living/carbon/human/H = AM + if(H.warfare_faction == BLUE_TEAM && (GLOB.blue_captured_zones.len < REQUIRED_CAPTURED_ZONES))//No spawn camping till you take the required zones bitch. + to_chat(H, "WE DO NOT CONTROL THE TRENCHES!") + return FALSE + return TRUE + + +/area/warfare/homebase/blue + name = "\improper Blue Base" + icon_state = "showroom" + +/area/warfare/homebase/blue/Enter(atom/movable/AM) + if(ishuman(AM)) + var/mob/living/carbon/human/H = AM + if(H.warfare_faction == RED_TEAM && (GLOB.red_captured_zones.len < REQUIRED_CAPTURED_ZONES)) + to_chat(H, "WE DO NOT CONTROL THE TRENCHES!") + return FALSE + return TRUE \ No newline at end of file diff --git a/maps/oldfare/warfare_define.dm b/maps/oldfare/warfare_define.dm new file mode 100644 index 00000000..0a5b7f39 --- /dev/null +++ b/maps/oldfare/warfare_define.dm @@ -0,0 +1,59 @@ + +/datum/map/warfare + name = "Warfare" + full_name = "Warfare" + path = "warfare" + station_name = "Warfare" + station_short = "Warfare" + dock_name = "Warfare" + boss_name = "Colonial Magistrate Authority" + boss_short = "CMA" + company_name = "Colonial Magistrate Space Residential Complex" + company_short = "CMSRC" + system_name = "hell" + + lobby_icon = 'maps/oldfare/fullscreen.dmi' + lobby_screens = list("lobby1","lobby2","lobby3","lobby4","lobby5", "lobby6") + + station_levels = list(1,2) + contact_levels = list(1) + player_levels = list(1,2) + + allowed_spawns = list("Arrivals Shuttle") + base_turf_by_z = list("1" = /turf/simulated/floor/dirty, "2" = /turf/simulated/floor/dirty, "3" = /turf/simulated/floor/dirty) + shuttle_docked_message = "The shuttle has docked." + shuttle_leaving_dock = "The shuttle has departed from home dock." + shuttle_called_message = "A scheduled transfer shuttle has been sent." + shuttle_recall_message = "The shuttle has been recalled" + emergency_shuttle_docked_message = "The emergency escape shuttle has docked." + emergency_shuttle_leaving_dock = "The emergency escape shuttle has departed from %dock_name%." + emergency_shuttle_called_message = "An emergency escape shuttle has been sent." + emergency_shuttle_recall_message = "The emergency shuttle has been recalled" + map_lore = "We've been sitting in these trenches for months. No word from central command. The shells keep dropping... there is no way out. Our only hope is to push forth into their trench instead. But we don't have that many men left, if we lose too many it's over for us. We must give it our all if we are to survive this winter." + + + +//Overriding event containers to remove random events. +/datum/event_container/mundane + available_events = list( + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mortars1",/datum/event/mortar,100), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mortars2",/datum/event/mortar,100), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mortars3",/datum/event/mortar,100), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mortars4",/datum/event/mortar,100) + ) + +/datum/event_container/moderate + available_events = list( + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mortars1",/datum/event/mortar,100), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mortars2",/datum/event/mortar,100), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mortars3",/datum/event/mortar,100), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mortars4",/datum/event/mortar,100) + ) + +/datum/event_container/major + available_events = list( + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mortars1",/datum/event/mortar,100), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mortars2",/datum/event/mortar,100), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mortars3",/datum/event/mortar,100), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mortars4",/datum/event/mortar,100) + ) \ No newline at end of file diff --git a/maps/oldfare/warfare_items.dm b/maps/oldfare/warfare_items.dm new file mode 100644 index 00000000..98a0c443 --- /dev/null +++ b/maps/oldfare/warfare_items.dm @@ -0,0 +1,614 @@ +/obj/item/clothing/head/helmet/hard_had + name = "Mining Helmet" + desc = "Protects you head from rocks and other hazards." + icon_state = "hardhat" + + +/obj/item/clothing/head/helmet/sentryhelm + name = "Sentry Helmet" + desc = "Used for taking blows to the noggin without getting hurt." + armor = list(melee = 75, bullet = 75, laser = 55, energy = 40, bomb = 50, bio = 10, rad = 0)//proteck ya neck + str_requirement = 18 + + +/obj/item/clothing/suit/armor/sentry + name = "Sentry Armor" + desc = "Protects you very well from getting smacked, and decently well from getting shot." + armor = list(melee = 75, bullet = 75, laser = 55, energy = 40, bomb = 50, bio = 10, rad = 0)//Beefy boys. + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + str_requirement = 18 + + +/obj/item/clothing/suit/child_coat + name = "scav coat" + desc = "Fitted just for scavs." + icon_state = "child_redcoat" + can_be_worn_by_child = TRUE + child_exclusive = TRUE + + +/obj/item/clothing/suit/child_coat/red + icon_state = "child_redcoat" + warfare_team = RED_TEAM + +/obj/item/clothing/suit/child_coat/blue + icon_state = "child_bluecoat" + warfare_team = BLUE_TEAM + + +/obj/item/clothing/suit/fire/red + name = "Redcoats Firesuit" + icon_state = "redfiresuit" + warfare_team = RED_TEAM + cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + str_requirement = 18 + flags_inv = null //HIDEJUMPSUIT|HIDETAIL + +/obj/item/clothing/suit/fire/blue + name = "Bluecoats Firesuit" + icon_state = "bluefiresuit" + warfare_team = BLUE_TEAM + cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + str_requirement = 18 + flags_inv = null //HIDEJUMPSUIT|HIDETAIL + + +/obj/item/clothing/head/helmet/redhelmet/fire + str_requirement = 18 + icon_state = "redfirehelmet" + +/obj/item/clothing/head/helmet/bluehelmet/fire + str_requirement = 18 + icon_state = "bluefirehelmet" + + +/obj/item/clothing/under/child_jumpsuit/warfare + name = "scavengers's clothing" + desc = "A proper uniform worn by child scavengers." + icon_state = "urchin" + cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS//So they don't freeze to death with their clothes on. + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + +/obj/item/clothing/under/child_jumpsuit/warfare/red + warfare_team = RED_TEAM + icon_state = "red_child_uniform" + +/obj/item/clothing/under/child_jumpsuit/warfare/blue + warfare_team = BLUE_TEAM + icon_state = "blue_child_uniform" + +//Red shit +/obj/item/clothing/suit/armor/redcoat + name = "Red Team's jacket" + desc = "The proud jacket of the Red Baron!" + icon_state = "redcoat" + warfare_team = RED_TEAM + allowed = list(/obj/item/ammo_magazine,/obj/item/ammo_casing) + starting_accessories = list(/obj/item/clothing/accessory/red_outline) + cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + +/obj/item/clothing/suit/armor/redcoat/New() + ..() + name = "The [RED_TEAM]'s jacket" + desc = "The proud jacket of the [RED_TEAM]." + +/obj/item/clothing/suit/armor/sentry/red + name = "Red Sentry Armor" + icon_state = "redsentryarmor" + warfare_team = RED_TEAM + +/obj/item/clothing/head/helmet/sentryhelm/red + name = "Red Sentry Helmet" + icon_state = "redsentryhelmet" + item_state = "redsentryhelmet" + warfare_team = RED_TEAM + +/obj/item/clothing/under/red_uniform + name = "Red's uniform" + desc = "It's not the best. But it's not the worst." + icon_state = "reduni" + worn_state = "reduni" + item_state = "reduni" + warfare_team = RED_TEAM + + +/obj/item/clothing/suit/armor/redcoat/leader + icon_state = "redcoat_leader" + +/obj/item/clothing/suit/armor/redcoat/medic + icon_state = "redcoat_medic" + item_state = "redcoat_medic" + +/obj/item/clothing/suit/armor/redcoat/sniper + icon_state = "redcoat_sniper" + item_state = "redcoat_sniper" + +/obj/item/clothing/head/warfare_officer/redofficer + name = "Red Officer\'s Cap" + desc = "Fit for an officer of just your ranking. And nothing more." + icon_state = "redoffcap" + item_state = "redoffcap" + warfare_team = RED_TEAM + +/obj/item/clothing/head/helmet/redhelmet + name = "Red's Helmet" + desc = "Sometimes protects your head from bullets and blows." + icon_state = "redhelmet" + warfare_team = RED_TEAM + +/obj/item/clothing/head/helmet/redhelmet/medic + icon_state = "redhelmet_medic" +// starting_accessories = list(/obj/item/clothing/accessory/helm_patch/medic) + +/obj/item/clothing/head/helmet/redhelmet/leader + icon_state = "redhelmet_leader" +// starting_accessories = list(/obj/item/clothing/accessory/helm_patch/leader) + +/obj/item/clothing/head/helmet/redhelmet/sniper + icon_state = "redsniperhelmet" + item_state = "redsniperhelmet" +// starting_accessories = list(/obj/item/clothing/accessory/helm_patch/leader) + + +//Nam shit +/obj/item/clothing/suit/armor/redcoat/nam + icon_state = "redsuit" + +/obj/item/clothing/suit/armor/redcoat/leader/nam + icon_state = "redsuit_leader" + +/obj/item/clothing/suit/armor/redcoat/medic/nam + icon_state = "redsuit_medic" + +/obj/item/clothing/head/helmet/redhelmet/nam + desc = "Sometimes protects your head from bullets and blows." + icon_state = "redhelmnam" + +/obj/item/clothing/head/helmet/redhelmet/leader/nam + icon_state = "redhelmnam_leader" + +/obj/item/clothing/head/helmet/redhelmet/medic/nam + icon_state = "redhelmnam_medic" + +/obj/item/clothing/mask/gas/nam + icon_state = "redmask" + item_state = "redmask" + + +/obj/item/clothing/gloves/thick/swat/combat/nam + icon_state = "namgloves" + item_state = "namgloves" + +/obj/item/clothing/gloves/thick/swat/combat/warfare + icon_state = "warfare_gloves" + item_state = "warfare_gloves" + + +//Blue shit +/obj/item/clothing/suit/armor/bluecoat + name = "Blue Team's jacket" + desc = "The proud jacket of the Bluecoats!" + icon_state = "bluecoat" + warfare_team = BLUE_TEAM + allowed = list(/obj/item/ammo_magazine,/obj/item/ammo_casing) + starting_accessories = list(/obj/item/clothing/accessory/blue_outline) + cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + +/obj/item/clothing/suit/armor/bluecoat/New() + ..() + name = "The [BLUE_TEAM]'s jacket" + desc = "The proud jacket of the [BLUE_TEAM]." + +/obj/item/clothing/suit/armor/sentry/blue + warfare_team = BLUE_TEAM + name = "Blue Sentry Armor" + icon_state = "bluesentryarmor" + +/obj/item/clothing/head/helmet/sentryhelm/blue + warfare_team = BLUE_TEAM + name = "Blue Sentry Helmet" + icon_state = "bluesentryhelmet" + item_state = "bluesentryhelmet" + +/obj/item/clothing/suit/armor/bluecoat/leader + icon_state = "bluecoat_leader" + +/obj/item/clothing/suit/armor/bluecoat/medic + icon_state = "bluecoat_medic" + item_state = "bluecoat_medic" + +/obj/item/clothing/suit/armor/bluecoat/sniper + icon_state = "bluecoat_sniper" + item_state = "bluecoat_sniper" + +//Uniform. +/obj/item/clothing/under/blue_uniform + name = "Blue's uniform" + desc = "It's not the best, but it's not the worst." + icon_state = "blueuni" + worn_state = "blueuni" + item_state = "blueuni" + +//Hats +/obj/item/clothing/head/warfare_officer/blueofficer + name = "Blue Officer\'s Cap" + desc = "Fit for an officer of just your ranking. And nothing more." + icon_state = "blueoffcap" + item_state = "blueoffcap" + warfare_team = BLUE_TEAM + +//Helmets +/obj/item/clothing/head/helmet/bluehelmet + name = "Blue's Helmet" + desc = "Sometimes protects your head from bullets and blows." + icon_state = "bluehelmet" + warfare_team = BLUE_TEAM + +/obj/item/clothing/head/helmet/bluehelmet/medic + icon_state = "bluehelmet_medic" +// starting_accessories = list(/obj/item/clothing/accessory/helm_patch/medic) + +/obj/item/clothing/head/helmet/bluehelmet/leader + icon_state = "bluehelmet_leader" +// starting_accessories = list(/obj/item/clothing/accessory/helm_patch/leader) + +/obj/item/clothing/head/helmet/bluehelmet/sniper + icon_state = "bluesniperhelmet" + item_state = "bluesniperhelmet" +// starting_accessories = list(/obj/item/clothing/accessory/helm_patch/leader) + +/obj/item/weapon/card/id/dog_tag + var/warfare_faction = null + icon_state = "dogtag" + desc = "A metal dog tag. Functions like an ID." + +/obj/item/weapon/card/id/dog_tag/red + warfare_faction = RED_TEAM + icon_state = "tagred" + +/obj/item/weapon/card/id/dog_tag/blue + warfare_faction = BLUE_TEAM + icon_state = "tagblue" + +/obj/item/weapon/card/id/dog_tag/update_name() + var/final_name = "[registered_name]'s Dog Tag" + if(military_rank && military_rank.name_short) + final_name = military_rank.name_short + " " + final_name + if(assignment) + final_name = final_name + " ([assignment])" + SetName(final_name) + + +/obj/item/device/radio/headset/red_team + name = "Red Headset" + origin_tech = list(TECH_ILLEGAL = 3) + syndie = 1 + ks1type = /obj/item/device/encryptionkey/red + +/obj/item/device/radio/headset/red_team/Initialize() + . = ..() + set_frequency(RED_FREQ) + +/obj/item/device/radio/headset/red_team/sl_alpha + ks1type = /obj/item/device/encryptionkey/redsl_alpha + +/obj/item/device/radio/headset/red_team/sl_bravo + ks1type = /obj/item/device/encryptionkey/redsl_bravo + +/obj/item/device/radio/headset/red_team/sl_charlie + ks1type = /obj/item/device/encryptionkey/redsl_charlie + +/obj/item/device/radio/headset/red_team/sl_delta + ks1type = /obj/item/device/encryptionkey/redsl_delta + +/obj/item/device/radio/headset/red_team/all + ks1type = /obj/item/device/encryptionkey/red_all + +/obj/item/device/radio/headset/red_team/alpha + ks1type = /obj/item/device/encryptionkey/red_alpha + + Initialize() + . = ..() + set_frequency(RED_ALPHA) + +/obj/item/device/radio/headset/red_team/bravo + ks1type = /obj/item/device/encryptionkey/red_bravo + + Initialize() + . = ..() + set_frequency(RED_BRAVO) + +/obj/item/device/radio/headset/red_team/charlie + ks1type = /obj/item/device/encryptionkey/red_charlie + + Initialize() + . = ..() + set_frequency(RED_CHARLIE) + +/obj/item/device/radio/headset/red_team/delta + ks1type = /obj/item/device/encryptionkey/red_delta + + Initialize() + . = ..() + set_frequency(RED_DELTA) + + + + +/obj/item/device/radio/headset/blue_team + name = "Blue Headset" + origin_tech = list(TECH_ILLEGAL = 2) + syndie = 1 + ks1type = /obj/item/device/encryptionkey/blue + +/obj/item/device/radio/headset/blue_team/Initialize() + . = ..() + set_frequency(BLUE_FREQ) + + +/obj/item/device/radio/headset/blue_team/sl_alpha + ks1type = /obj/item/device/encryptionkey/bluesl_alpha + +/obj/item/device/radio/headset/blue_team/sl_bravo + ks1type = /obj/item/device/encryptionkey/bluesl_bravo + +/obj/item/device/radio/headset/blue_team/sl_charlie + ks1type = /obj/item/device/encryptionkey/bluesl_charlie + +/obj/item/device/radio/headset/blue_team/sl_delta + ks1type = /obj/item/device/encryptionkey/bluesl_delta + +/obj/item/device/radio/headset/blue_team/all + ks1type = /obj/item/device/encryptionkey/blue_all + +/obj/item/device/radio/headset/blue_team/alpha + ks1type = /obj/item/device/encryptionkey/blue_alpha + + Initialize() + . = ..() + set_frequency(BLUE_ALPHA) + +/obj/item/device/radio/headset/blue_team/bravo + ks1type = /obj/item/device/encryptionkey/blue_bravo + + Initialize() + . = ..() + set_frequency(BLUE_BRAVO) + +/obj/item/device/radio/headset/blue_team/charlie + ks1type = /obj/item/device/encryptionkey/blue_charlie + + Initialize() + . = ..() + set_frequency(BLUE_CHARLIE) + +/obj/item/device/radio/headset/blue_team/delta + ks1type = /obj/item/device/encryptionkey/blue_delta + + Initialize() + . = ..() + set_frequency(BLUE_DELTA) + + +/obj/item/weapon/melee/trench_axe + name = "trench axe" + desc = "Used mainly for murdering those on the enemy side." + icon = 'icons/obj/weapons.dmi' + icon_state = "trenchaxe" + item_state = "trenchaxe" + slot_flags = SLOT_BELT + force = 20 + block_chance = 20 + sharp = TRUE + edge = TRUE + hitsound = "slash_sound" + + + + +/obj/item/clothing/suit/prac_arpon + name = "practioner robes" + desc = "Worn by practioners and other surgoens." + icon_state = "prac_robes" + item_state = "prac_robes" + cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + +/obj/item/clothing/mask/gas/prac_mask + name = "practioner mask" + desc = "Keeps all that blood off your face." + icon_state = "prac_mask" + item_state = "prac_mask" + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|BLOCKHAIR + body_parts_covered = FACE|EYES|HEAD + +/obj/item/clothing/shoes/prac_boots + name = "practioner boots" + desc = "Squish." + icon_state = "prac_boots" + item_state = "prac_boots" + +/obj/item/clothing/gloves/prac_gloves + name = "practioner gloves" + desc = "Now you can grope the dead without worrying about what you're contracting." + icon_state = "prac_gloves" + item_state = "prac_gloves" + +/obj/item/clothing/head/prac_cap + name = "practioner cap" + desc = "Wouldn't want your hair to get messy now would we." + icon_state = "prac_cap" + item_state = "prac_cap" + flags_inv = BLOCKHEADHAIR + + +/obj/item/clothing/accessory/red_outline + icon_state = "red_outline" + high_visibility = FALSE + +/obj/item/clothing/accessory/blue_outline + icon_state = "blue_outline" + high_visibility = FALSE + +/obj/item/clothing/accessory/armband/alpha + icon_state = "alpha_patch" + high_visibility = FALSE + +/obj/item/clothing/accessory/armband/bravo + icon_state = "bravo_patch" + high_visibility = FALSE + +/obj/item/clothing/accessory/armband/charlie + icon_state = "charlie_patch" + high_visibility = FALSE + +/obj/item/clothing/accessory/medal/medical + name = "medical patch" + icon_state = "medic_patch" + overlay_state = "medic_patch" + high_visibility = FALSE + +/obj/item/clothing/accessory/helm_patch + slot = ACCESSORY_SLOT_HELM_C + +/obj/item/clothing/accessory/helm_patch/medic + icon_state = "medical_helmet_patch" + overlay_state = "medical_helmet_patch" + +/obj/item/clothing/accessory/helm_patch/leader + icon_state = "leader_patch_helm" + overlay_state = "leader_patch_helm" + + +/obj/item/weapon/storage/belt/warfare + name = "ammo belt" + desc = "Great for holding ammo! This one starts with smg ammo." + icon_state = "warfare_belt" + item_state = "warfare_belt" + can_hold = list( + /obj/item/ammo_magazine, + ) + + New() + ..() + new /obj/item/ammo_magazine/mc9mmt/machinepistol(src) + new /obj/item/ammo_magazine/mc9mmt/machinepistol(src) + new /obj/item/ammo_magazine/mc9mmt/machinepistol(src) + new /obj/item/ammo_magazine/mc9mmt/machinepistol(src) + +/obj/item/weapon/storage/belt/warfare/chestrig + name = "Chestrig" + desc = "Holds ammo. But not much else." + icon_state = "chestrig" + +/obj/item/weapon/storage/belt/autoshotty + name = "ammo belt" + desc = "Great for holding ammo! This one starts with Warcrime ammo." + icon_state = "warfare_belt" + item_state = "warfare_belt" + can_hold = list( + /obj/item/ammo_magazine, + ) + New() + ..() + new /obj/item/ammo_magazine/autoshotty(src) + new /obj/item/ammo_magazine/autoshotty(src) + new /obj/item/ammo_magazine/autoshotty(src) + new /obj/item/ammo_magazine/autoshotty(src) + new /obj/item/ammo_magazine/autoshotty(src) + + +/obj/item/weapon/storage/belt/autoshotty/chestrig + name = "Chestrig" + desc = "Holds ammo. But not much else. This one starts with Warcrime ammo." + icon_state = "chestrig" + +/obj/item/weapon/storage/box/ifak + name = "IFAK" + desc = "An Individual First Aid Kit, used to keep you alive until a medic can patch you up proper." + icon_state = "ifak" + startswith = list(/obj/item/bandage_pack, /obj/item/tourniquet, /obj/item/weapon/reagent_containers/hypospray/autoinjector/morphine) + w_class = ITEM_SIZE_SMALL + max_storage_space = 6 + +/obj/item/weapon/storage/box/ifak/attack_hand(var/mob/living/carbon/human/user) + if(!istype(user)) + ..() + return + if((src != user.r_store) && (src != user.l_store) && (src != user.belt) && (src != user.get_inactive_hand())) + ..()//If it's not in any of these slots then just return normally. + return + open(user)//If it's in your pocket then open it. + + +/obj/item/bandage_pack + name = "Bandage Pack" + desc = "Holds a bandage. One time use. You can't put the bandage back don't try." + icon = 'icons/obj/storage.dmi' + icon_state = "bandage_pack1" + w_class = ITEM_SIZE_SMALL + var/used = FALSE + +/obj/item/bandage_pack/attack_self(mob/user) + . = ..() + if(used) + to_chat(user, "This one is used up already.") + return + + var/obj/item/stack/medical/bruise_pack/BP = new(get_turf(src)) + playsound(src, 'sound/effects/rip_pack.ogg', 100) + user.put_in_inactive_hand(BP) + used = TRUE + icon_state = "bandage_pack0"//Yes this could go in update icon, but this is the only time this icon is ever going to change. + + +/obj/item/tourniquet + name = "Tourniquet" + desc = "Use this to stop arteries from bleeding. One time use only." + icon = 'icons/obj/items.dmi'//TODO: MOVE THIS INTO ANOTHER DMI! + icon_state = "tourniquet" + w_class = ITEM_SIZE_SMALL + +/obj/item/tourniquet/attack(mob/living/carbon/human/H as mob, mob/living/userr, var/target_zone)//All of this is snowflake and copied and pasted from sutures. + //Checks if they're human, have a limb, and have the skill to fix it. + if(!ishuman(H)) + return ..() + if(!ishuman(userr)) + return ..() + + var/mob/living/carbon/human/user = userr + var/obj/item/organ/external/affected = H.get_organ(target_zone) + + if(!affected) + return ..() + + + if(!(affected.status & ORGAN_ARTERY_CUT))//There is nothing to fix don't fix anything. + return + + //Ok all the checks are over let's do the quick fix. + if(!user.doing_something) + user.doing_something = TRUE + if(affected.status & ORGAN_ARTERY_CUT)//Fix arteries. + user.visible_message("[user] to apply the tourniquet to their [affected.name].") + if(do_mob(user, H, (backwards_skill_scale(user.SKILL_LEVEL(medical)) * 5))) + user.visible_message("[user] has patched the [affected.artery_name] in [H]'s [affected.name] with \the [src.name].", \ + "You have patched the [affected.artery_name] in [H]'s [affected.name] with \the [src.name].") + affected.status &= ~ORGAN_ARTERY_CUT + playsound(src, 'sound/items/tourniquet.ogg', 70, FALSE) + qdel(src) + else + user.doing_something = FALSE + + affected.update_damages() + user.doing_something = FALSE + else + to_chat(user, "You're already trying to suture them.") \ No newline at end of file diff --git a/maps/oldfare/warfare_shuttles.dm b/maps/oldfare/warfare_shuttles.dm new file mode 100644 index 00000000..cd45f5d3 --- /dev/null +++ b/maps/oldfare/warfare_shuttles.dm @@ -0,0 +1,22 @@ +/* +/obj/effect/shuttle_landmark/lower_level + name = "Lower Level Dock" + landmark_tag = "nav_example_station" + docking_controller = "lower_level_dock" + +/obj/effect/shuttle_landmark/upper_level + name = "Upper Level Dock" + landmark_tag = "nav_example_offsite" + special_dock_targets = list("Example" = "example_shuttle_port") + docking_controller = "upper_level_dock" + +/datum/shuttle/autodock/ferry/example + name = "Example" + shuttle_area = /area/shuttle/escape + dock_target = "example_shuttle_starboard" + warmup_time = 10 + + location = 0 + waypoint_station = "nav_example_station" + waypoint_offsite = "nav_example_offsite" +*/ \ No newline at end of file diff --git a/maps/oldfare/warfare_unit_testing.dm b/maps/oldfare/warfare_unit_testing.dm new file mode 100644 index 00000000..186f42ff --- /dev/null +++ b/maps/oldfare/warfare_unit_testing.dm @@ -0,0 +1,6 @@ +/datum/map/example + // Unit test exemptions + apc_test_exempt_areas = list( + /area/space = NO_SCRUBBER|NO_VENT|NO_APC, + /area/shuttle/escape = NO_SCRUBBER|NO_VENT|NO_APC + ) diff --git a/maps/overmap_example/bearcat/bearcat-1.dmm b/maps/overmap_example/bearcat/bearcat-1.dmm new file mode 100644 index 00000000..36f4b308 --- /dev/null +++ b/maps/overmap_example/bearcat/bearcat-1.dmm @@ -0,0 +1,351 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/obj/effect/shuttle_landmark/below_deck_bow,/turf/space,/area/space) +"ac" = (/obj/structure/window/reinforced{dir = 4},/turf/space,/area/space) +"ad" = (/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "cargo_out"},/obj/machinery/shield_diffuser,/turf/simulated/floor/plating,/area/ship/scrap/cargo/lower) +"ae" = (/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "cargo_out"},/obj/machinery/access_button/airlock_exterior{master_tag = "cargo"; pixel_x = 18; pixel_y = 17},/obj/machinery/shield_diffuser,/turf/simulated/floor/plating,/area/ship/scrap/cargo/lower) +"af" = (/obj/structure/window/reinforced{dir = 8},/turf/space,/area/space) +"ag" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/turf/simulated/floor/plating,/area/ship/scrap/cargo/lower) +"ah" = (/turf/simulated/wall,/area/ship/scrap/escape_port) +"ai" = (/obj/machinery/door/blast/regular{dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/escape_port) +"aj" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{frequency = 1379; id_tag = "cargo_pump"},/turf/simulated/floor/plating,/area/ship/scrap/cargo/lower) +"ak" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{frequency = 1379; id_tag = "cargo_pump"},/obj/machinery/embedded_controller/radio/airlock/docking_port{id_tag = "cargo"; pixel_x = 24; tag_airpump = "cargo_pump"; tag_chamber_sensor = "cargo_sensor"; tag_exterior_door = "cargo_out"; tag_interior_door = "cargo_in"},/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/cargo/lower) +"al" = (/turf/simulated/wall/r_wall,/area/ship/scrap/cargo/lower) +"am" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/cargo/lower) +"an" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/cargo/lower) +"ao" = (/turf/simulated/wall,/area/ship/scrap/cargo/lower) +"ap" = (/obj/machinery/door/blast/regular{dir = 8},/turf/simulated/floor/plating,/area/ship/scrap/escape_star) +"aq" = (/turf/simulated/wall,/area/ship/scrap/escape_star) +"ar" = (/obj/machinery/cryopod/lifepod,/obj/structure/window/reinforced{dir = 4},/obj/machinery/door/window/southright,/turf/simulated/floor/plating,/area/ship/scrap/escape_port) +"as" = (/obj/machinery/cryopod/lifepod,/obj/machinery/door/window/southright,/turf/simulated/floor/plating,/area/ship/scrap/escape_port) +"at" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/cargo/lower) +"au" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/simulated/floor/plating,/area/ship/scrap/cargo/lower) +"av" = (/obj/machinery/airlock_sensor{id_tag = "cargo_sensor"; pixel_x = 25},/obj/machinery/atmospherics/pipe/simple/hidden,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/simulated/floor/plating,/area/ship/scrap/cargo/lower) +"aw" = (/obj/structure/ladder/up,/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"ax" = (/obj/structure/table/standard,/obj/item/device/flashlight/lamp,/obj/item/weapon/paper_bin,/obj/item/weapon/stamp/cargo,/obj/item/weapon/stamp/denied,/obj/item/weapon/clipboard,/obj/item/device/radio,/obj/item/device/radio/intercom{dir = 8; pixel_x = 22},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"ay" = (/obj/machinery/cryopod/lifepod,/obj/structure/window/reinforced{dir = 4},/obj/machinery/door/window/southright,/turf/simulated/floor/plating,/area/ship/scrap/escape_star) +"az" = (/obj/machinery/cryopod/lifepod,/obj/machinery/door/window/southright,/turf/simulated/floor/plating,/area/ship/scrap/escape_star) +"aA" = (/turf/simulated/wall/r_wall,/area/ship/scrap/escape_star) +"aC" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 1},/obj/machinery/computer/cryopod{pixel_y = -32},/turf/simulated/floor/tiled,/area/ship/scrap/escape_port) +"aE" = (/obj/machinery/light/small/red{icon_state = "bulb1"; dir = 4},/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 1},/obj/machinery/power/apc{dir = 4},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/tiled,/area/ship/scrap/escape_port) +"aF" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/atmospherics/portables_connector,/obj/machinery/portable_atmospherics/canister/air/airlock,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"aG" = (/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "cargo_in"},/obj/machinery/atmospherics/pipe/simple/hidden,/turf/simulated/floor/plating,/area/ship/scrap/cargo/lower) +"aH" = (/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "cargo_in"},/obj/machinery/access_button/airlock_interior{master_tag = "cargo"; pixel_x = 20; pixel_y = -12},/obj/machinery/atmospherics/pipe/simple/hidden,/turf/simulated/floor/plating,/area/ship/scrap/cargo/lower) +"aI" = (/obj/machinery/light_switch{pixel_x = -24},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"aJ" = (/obj/effect/decal/cleanable/dirt,/obj/item/weapon/stool/padded,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"aK" = (/obj/machinery/light/small/red{icon_state = "bulb1"; dir = 8},/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 1},/obj/machinery/power/apc{dir = 8},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/tiled,/area/ship/scrap/escape_star) +"aM" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 1},/obj/machinery/computer/cryopod{pixel_y = -32},/turf/simulated/floor/tiled,/area/ship/scrap/escape_star) +"aO" = (/turf/simulated/wall,/area/ship/scrap/gambling) +"aP" = (/turf/simulated/wall/r_wall,/area/ship/scrap/gambling) +"aR" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 5},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"aS" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"aT" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 9},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"aU" = (/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"aV" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/closet/crate/plastic,/obj/random/accessory,/obj/random/accessory,/obj/item/weapon/reagent_containers/glass/paint/random,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"aX" = (/turf/simulated/wall,/area/ship/scrap/crew/dorms1) +"aY" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/dorms1) +"aZ" = (/obj/item/device/flashlight/lamp,/turf/simulated/floor/plating,/area/ship/scrap/gambling) +"ba" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/structure/holostool,/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/turf/simulated/floor/plating,/area/ship/scrap/gambling) +"bb" = (/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/light_switch{pixel_x = 24},/obj/machinery/power/apc{dir = 1},/turf/simulated/floor/plating,/area/ship/scrap/gambling) +"bc" = (/obj/machinery/light/small{dir = 8},/obj/effect/decal/cleanable/cobweb2,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"bd" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/machinery/power/apc{dir = 8},/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bf" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bg" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/closet/crate,/obj/random/toy,/obj/random/toy,/obj/random/loot,/obj/random/plushie,/obj/random/action_figure,/obj/random/action_figure,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bh" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/light/small{dir = 4},/obj/random/closet,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bi" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/structure/ladder/up,/obj/effect/decal/cleanable/cobweb,/obj/structure/sign/deck/second{pixel_x = -32},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"bj" = (/obj/machinery/power/apc{dir = 1},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/light_switch{pixel_x = -24},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/structure/closet,/obj/random/gloves,/obj/random/clothing,/obj/random/clothing,/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms1) +"bl" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/structure/curtain/open/bed,/obj/structure/bed/padded,/obj/item/weapon/bedsheet/green,/obj/effect/decal/cleanable/cobweb2,/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms1) +"bm" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/gambling) +"bn" = (/obj/structure/holostool,/turf/simulated/floor/plating,/area/ship/scrap/gambling) +"bo" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/table/gamblingtable,/obj/item/weapon/deck/cards,/obj/random_multi/single_item/captains_spare_id,/obj/item/weapon/dice,/turf/simulated/floor/plating,/area/ship/scrap/gambling) +"bp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/holostool,/turf/simulated/floor/plating,/area/ship/scrap/gambling) +"br" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"bt" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bu" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bv" = (/obj/structure/cable{icon_state = "6-8"},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bw" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bx" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"by" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bz" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"bB" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms1) +"bC" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms1) +"bD" = (/obj/structure/table/standard,/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms1) +"bE" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/crew/dorms1) +"bG" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/holostool,/turf/simulated/floor/plating,/area/ship/scrap/gambling) +"bH" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/plating,/area/ship/scrap/gambling) +"bI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"bJ" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/structure/closet/crate,/obj/random/soap,/obj/random/soap,/obj/item/bodybag,/obj/item/stack/tile/carpet/fifty,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bK" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/decal/mecha_wreckage/ripley,/obj/machinery/mech_recharger,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bL" = (/obj/effect/landmark/test/safe_turf,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bM" = (/obj/structure/cable{icon_state = "4-9"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bN" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/cable{icon_state = "6-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/closet/coffin,/obj/random/drinkbottle,/obj/item/weapon/contraband/poster,/obj/item/stack/material/phoron/ten,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bP" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"bQ" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/structure/closet,/obj/random/clothing,/obj/random/clothing,/obj/random/clothing,/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms1) +"bS" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 10},/obj/structure/curtain/open/bed,/obj/structure/bed/padded,/obj/item/weapon/bedsheet/brown,/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms1) +"bT" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/effect/floor_decal/industrial/warning/corner,/obj/machinery/mining/brace,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bU" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/industrial/warning,/obj/structure/closet/crate,/obj/item/weapon/fossil/skull,/obj/item/weapon/fossil/bone,/obj/item/weapon/fossil/bone,/obj/item/weapon/fossil/shell,/obj/item/xenos_claw,/obj/item/weapon/ore/strangerock,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bV" = (/obj/effect/floor_decal/industrial/warning,/obj/effect/decal/cleanable/dirt,/obj/machinery/computer/shuttle_control/lift,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bW" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bY" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 8},/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/cable{icon_state = "2-9"},/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"bZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/item/device/radio/intercom{dir = 8; pixel_x = 22},/obj/structure/cable{d1 = 16; d2 = 0; icon_state = "16-0"},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"ca" = (/turf/simulated/wall/r_wall,/area/ship/scrap/broken2) +"cb" = (/obj/machinery/light/small/red{icon_state = "bulb1"; dir = 8},/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 1},/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/item/device/radio/intercom{dir = 1; pixel_y = -22},/turf/simulated/floor/tiled,/area/ship/scrap/escape_port) +"cc" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/machinery/light_construct/small{icon_state = "bulb-construct-stage1"; dir = 1},/turf/simulated/floor/plating,/area/ship/scrap/broken2) +"cd" = (/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/light_switch{pixel_x = 24},/obj/machinery/power/apc{dir = 1},/turf/simulated/floor/plating,/area/ship/scrap/broken2) +"ce" = (/turf/simulated/wall,/area/ship/scrap/broken2) +"cf" = (/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/effect/decal/cleanable/cobweb,/obj/effect/decal/cleanable/cobweb2,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"ch" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/lift) +"ci" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/lift) +"cj" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/lift) +"ck" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"cl" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"cm" = (/turf/simulated/wall,/area/ship/scrap/crew/dorms2) +"cn" = (/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/light_switch{pixel_x = -24},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/structure/closet,/obj/random/clothing,/obj/random/clothing,/obj/effect/decal/cleanable/cobweb,/obj/machinery/power/apc{dir = 1},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms2) +"cp" = (/obj/structure/curtain/open/bed,/obj/structure/bed/padded,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/item/weapon/bedsheet/ce,/obj/effect/landmark/start{name = "Cook"},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms2) +"cq" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/dorms2) +"cr" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/broken2) +"cs" = (/obj/structure/foamedmetal,/turf/simulated/floor/plating,/area/ship/scrap/broken2) +"cu" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/ship/scrap/broken2) +"cx" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"cy" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/lift) +"cz" = (/obj/effect/shuttle_landmark/lift/bottom,/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/lift) +"cA" = (/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/lift) +"cB" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/lift) +"cC" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"cE" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms2) +"cF" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms2) +"cG" = (/obj/structure/table/standard,/obj/item/weapon/newspaper,/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms2) +"cH" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/crew/dorms2) +"cI" = (/turf/simulated/floor/plating,/area/ship/scrap/broken2) +"cJ" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/foamedmetal,/turf/simulated/floor/plating,/area/ship/scrap/broken2) +"cL" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"cM" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/structure/closet,/obj/random/gloves,/obj/random/clothing,/obj/random/clothing,/obj/random/clothing,/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms2) +"cO" = (/obj/structure/curtain/open/bed,/obj/structure/bed/padded,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 10},/obj/item/weapon/bedsheet/red,/obj/random_multi/single_item/captains_spare_id,/obj/effect/landmark/start{name = "Chief Engineer"},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms2) +"cP" = (/turf/space,/area/ship/scrap/broken1) +"cQ" = (/obj/structure/lattice,/obj/item/remains/mouse,/turf/space,/area/ship/scrap/broken1) +"cR" = (/obj/structure/girder,/turf/simulated/floor/plating,/area/ship/scrap/broken1) +"cS" = (/turf/simulated/wall,/area/ship/scrap/broken1) +"cU" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"cV" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 10},/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/lift) +"cW" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 10},/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/lift) +"cX" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 10},/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/lift) +"cY" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/light/small{dir = 4},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"cZ" = (/obj/structure/lattice,/obj/item/stack/nanopaste,/turf/space,/area/ship/scrap/broken1) +"da" = (/obj/structure/inflatable/wall,/turf/simulated/floor/tiled,/area/ship/scrap/broken1) +"db" = (/obj/structure/inflatable/wall,/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled,/area/ship/scrap/broken1) +"dc" = (/obj/item/weapon/caution,/obj/item/weapon/caution,/obj/item/weapon/FixOVein,/obj/structure/closet/crate,/obj/item/weapon/mop,/obj/item/device/radio,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/obj/item/weapon/storage/bag/trash,/obj/machinery/firealarm{pixel_y = 24},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/storage) +"dd" = (/turf/simulated/wall/r_wall,/area/ship/scrap/broken1) +"de" = (/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"df" = (/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 4},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/structure/sign/deck/second{pixel_x = -32},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"dh" = (/obj/structure/stairs/east,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"di" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/structure/ore_box,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"dj" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 1},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"dk" = (/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"dl" = (/turf/simulated/wall,/area/ship/scrap/crew/dorms3) +"dm" = (/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/light_switch{pixel_x = -24},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/structure/closet,/obj/random/gloves,/obj/random/clothing,/obj/random/clothing,/obj/machinery/power/apc{dir = 1},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms3) +"do" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/structure/curtain/open/bed,/obj/structure/bed/padded,/obj/item/weapon/bedsheet/green,/obj/effect/decal/cleanable/cobweb2,/obj/effect/landmark/start{name = "Doc"},/obj/structure/sign/poster{pixel_y = 32},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms3) +"dp" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/broken1) +"dq" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/item/device/robotanalyzer,/turf/simulated/floor/plating,/area/ship/scrap/broken1) +"dr" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/ship/scrap/broken1) +"dt" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"du" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"dv" = (/obj/machinery/light/small,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"dw" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"dy" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms3) +"dz" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms3) +"dA" = (/obj/structure/table/standard,/obj/random/plushie,/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms3) +"dB" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/crew/dorms3) +"dD" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/ship/scrap/broken1) +"dE" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/recharge_station,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled,/area/ship/scrap/broken1) +"dH" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{icon_state = "1-10"},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"dI" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/dorms3) +"dJ" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/structure/closet,/obj/random/clothing,/obj/random/clothing,/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms3) +"dL" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 10},/obj/structure/curtain/open/bed,/obj/structure/bed/padded,/obj/item/weapon/bedsheet/brown,/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms3) +"dO" = (/obj/machinery/cryopod/robot{dir = 4},/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/computer/cryopod/robot{pixel_x = 32; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/broken1) +"dP" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/effect/decal/cleanable/spiderling_remains,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"dR" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"dS" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/power/apc,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"dT" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"dU" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{icon_state = "2-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{icon_state = "map-scrubbers"; dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"dV" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"dW" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"dY" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"dZ" = (/turf/simulated/wall,/area/ship/scrap/maintenance/techstorage) +"ea" = (/turf/simulated/wall,/area/ship/scrap/maintenance/storage) +"eb" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/storage) +"ec" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/techstorage) +"ed" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/eva) +"ee" = (/turf/simulated/wall,/area/ship/scrap/maintenance/eva) +"ef" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/techstorage) +"ek" = (/obj/structure/closet/crate/plastic,/obj/item/weapon/storage/ore,/obj/item/weapon/pickaxe,/obj/item/stack/flag/yellow,/obj/item/weapon/storage/box/glowsticks,/obj/item/weapon/mining_scanner,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/storage) +"em" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/ladder/up,/obj/effect/decal/cleanable/dirt,/obj/structure/sign/deck/second{pixel_x = 0; pixel_y = 32},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/storage) +"en" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/device/radio/intercom{dir = 8; pixel_x = 22},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/storage) +"eo" = (/obj/structure/table/rack,/obj/item/weapon/tank/jetpack/oxygen,/obj/item/clothing/mask/breath,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/eva) +"ep" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/table/rack,/obj/item/weapon/tank/jetpack/oxygen,/obj/item/clothing/mask/breath,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/eva) +"eq" = (/obj/machinery/power/apc{dir = 1},/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 6},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/atmospherics/portables_connector,/obj/machinery/portable_atmospherics/canister/air/airlock,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/eva) +"er" = (/obj/structure/window/reinforced,/turf/space,/area/space) +"es" = (/obj/machinery/light/small{dir = 8},/obj/machinery/vending/engineering,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/techstorage) +"et" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/techstorage) +"eu" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/techstorage) +"ew" = (/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 9},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{icon_state = "6-8"},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/storage) +"ex" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{icon_state = "map-scrubbers"; dir = 1},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/storage) +"ey" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/storage) +"ez" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/storage) +"eA" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/storage) +"eC" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/eva) +"eD" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/eva) +"eE" = (/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 6},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 5},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/eva) +"eF" = (/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "eva_in"},/obj/machinery/access_button/airlock_interior{master_tag = "eva"; pixel_x = -12; pixel_y = 20},/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/eva) +"eG" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/machinery/airlock_sensor{id_tag = "eva_sensor"; pixel_y = 40},/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{id_tag = "eva"; pixel_y = 25; tag_airpump = "eva_pump"; tag_chamber_sensor = "eva_sensor"; tag_exterior_door = "eva_out"; tag_interior_door = "eva_in"},/obj/effect/floor_decal/industrial/warning{dir = 10},/obj/effect/floor_decal/industrial/warning{dir = 1},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/eva) +"eH" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1379; id_tag = "eva_pump"},/obj/effect/floor_decal/industrial/warning{dir = 5},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/eva) +"eI" = (/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "eva_out"},/obj/machinery/access_button/airlock_exterior{master_tag = "eva"; pixel_x = 18; pixel_y = -18},/obj/machinery/shield_diffuser,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/eva) +"eJ" = (/obj/item/weapon/stock_parts/capacitor,/obj/item/weapon/stock_parts/capacitor,/obj/item/weapon/stock_parts/capacitor/adv,/obj/item/weapon/stock_parts/scanning_module,/obj/item/weapon/stock_parts/scanning_module,/obj/item/weapon/stock_parts/scanning_module,/obj/item/weapon/stock_parts/scanning_module/adv,/obj/structure/table/rack,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/techstorage) +"eK" = (/obj/item/weapon/stock_parts/console_screen,/obj/item/weapon/stock_parts/console_screen,/obj/item/weapon/stock_parts/console_screen,/obj/item/weapon/stock_parts/micro_laser,/obj/item/weapon/stock_parts/micro_laser,/obj/item/weapon/stock_parts/micro_laser,/obj/item/weapon/stock_parts/micro_laser/ultra,/obj/structure/table/rack,/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/techstorage) +"eL" = (/obj/structure/table/rack,/obj/item/weapon/circuitboard/pacman/super/potato,/obj/item/stack/material/glass/phoronrglass/ten,/obj/item/stack/material/ocp/ten,/obj/item/weapon/circuitboard/unary_atmos/engine,/obj/item/weapon/circuitboard/unary_atmos/engine,/obj/item/weapon/circuitboard/unary_atmos/engine,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/techstorage) +"eN" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{icon_state = "4-9"},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/storage) +"eO" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/storage) +"eP" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/effect/landmark/start{name = "Junior Engineer"},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/storage) +"eQ" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{icon_state = "5-8"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/storage) +"eR" = (/obj/item/device/radio/intercom{dir = 4; pixel_x = -22},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/eva) +"eS" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/eva) +"eT" = (/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 6},/obj/structure/sign/warning/vacuum{pixel_x = 35},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/eva) +"eU" = (/obj/structure/window/reinforced{dir = 1},/turf/space,/area/space) +"eV" = (/obj/structure/table/standard,/obj/item/device/flashlight,/obj/item/device/flashlight,/obj/item/weapon/storage/box/lights/bulbs,/obj/item/weapon/storage/box/lights/mixed,/obj/structure/cable,/obj/machinery/power/apc{name = "Tools Storage APC"},/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 9},/obj/item/taperoll/engineering,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/storage) +"eW" = (/obj/structure/table/standard,/obj/item/weapon/inflatable_dispenser,/obj/item/device/radio,/obj/item/device/radio,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/machinery/light/small,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/storage) +"eX" = (/obj/item/weapon/tape_roll,/obj/item/stack/material/plasteel/fifty,/obj/item/stack/rods/fifty,/obj/item/stack/material/steel/fifty,/obj/item/stack/material/plastic/fifty,/obj/item/stack/material/steel/fifty,/obj/structure/closet/crate,/obj/item/stack/material/glass/fifty,/obj/item/stack/material/glass/fifty,/obj/item/stack/material/glass/reinforced/fifty,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/storage) +"eY" = (/obj/item/clothing/head/welding,/obj/item/device/radio,/obj/item/weapon/tape_roll,/obj/structure/table/standard,/obj/item/device/radio/intercom{pixel_y = -32},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/storage) +"eZ" = (/obj/machinery/vending/tool,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/storage) +"fb" = (/obj/machinery/suit_storage_unit/engineering/salvage,/obj/machinery/light/small,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/eva) +"fc" = (/obj/machinery/suit_storage_unit/engineering/salvage,/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/eva) +"fd" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/maintenance/storage) +"fe" = (/obj/effect/landmark/test/space_turf,/turf/space,/area/space) +"gb" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/closet/crate,/obj/random/loot,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/advdevice,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"gc" = (/obj/structure/cable{icon_state = "4-10"},/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/eva) +"hb" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/floodlight,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"hc" = (/obj/structure/dispenser/oxygen,/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/eva) +"ib" = (/obj/effect/floor_decal/industrial/warning,/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/portable_atmospherics/powered/scrubber,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"jb" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 1},/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/tiled,/area/ship/scrap/escape_port) +"kb" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/structure/cable{icon_state = "2-8"},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"lb" = (/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/light_switch{pixel_x = 24},/obj/machinery/power/apc{dir = 1},/obj/machinery/organ_printer/robot/mapped,/turf/simulated/floor/plating,/area/ship/scrap/broken1) +"mb" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"nb" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 1},/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/tiled,/area/ship/scrap/escape_star) +"ob" = (/obj/structure/mopbucket,/obj/structure/table/rack{dir = 8; layer = 2.9},/obj/item/weapon/storage/toolbox/mechanical,/obj/item/device/multitool{pixel_x = 3},/obj/item/clothing/glasses/welding,/obj/item/stack/cable_coil,/obj/item/stack/cable_coil,/obj/item/device/radio/intercom{dir = 4; pixel_x = -22},/turf/simulated/floor/tiled,/area/ship/scrap/broken1) +"pb" = (/obj/machinery/mecha_part_fabricator,/turf/simulated/floor/plating,/area/ship/scrap/broken1) +"qb" = (/obj/machinery/light/small/red{icon_state = "bulb1"; dir = 4},/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 1},/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/item/device/radio/intercom{dir = 1; pixel_y = -22},/turf/simulated/floor/tiled,/area/ship/scrap/escape_star) +"rb" = (/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/machinery/autolathe,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/techstorage) +"sb" = (/obj/machinery/door/airlock/autoname,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/escape_port) +"tb" = (/obj/item/weapon/storage/toolbox/mechanical{pixel_x = 5; pixel_y = -7},/obj/item/weapon/storage/toolbox/mechanical,/obj/item/clothing/head/welding,/obj/item/device/analyzer,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 9},/obj/structure/table/rack,/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/storage) +"ub" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/random/powercell,/turf/simulated/floor/plating,/area/ship/scrap/broken2) +"vb" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/smartfridge/drying_rack,/turf/simulated/floor/airless,/area/ship/scrap/broken2) +"wb" = (/obj/machinery/door/airlock/autoname,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/escape_star) +"xb" = (/obj/effect/shuttle_landmark/below_deck_starboardastern,/turf/space,/area/space) +"yb" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/structure/holostool,/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/sign/poster{pixel_y = 32},/obj/item/device/radio/intercom{pixel_y = 22},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms1) +"zb" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/gambling) +"Ab" = (/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/cargo/lower) +"Bb" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms1) +"Cb" = (/obj/machinery/firealarm{dir = 8; pixel_x = -24; pixel_y = 0},/turf/simulated/floor/plating,/area/ship/scrap/gambling) +"Db" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/holostool,/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms1) +"Eb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/item/device/radio/intercom{dir = 4; pixel_x = -22},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"Fb" = (/obj/machinery/floodlight,/obj/machinery/firealarm{dir = 8; pixel_x = -24; pixel_y = 0},/turf/simulated/floor/plating,/area/ship/scrap/broken2) +"Gb" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/item/device/radio/intercom{dir = 4; pixel_x = -22},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"Hb" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/firealarm{dir = 4; pixel_x = 24; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"Ib" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/structure/holostool,/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/item/device/radio/intercom{pixel_y = 22},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms2) +"Jb" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/item/taperoll/engineering/applied,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/broken2) +"Kb" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/door/firedoor,/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms2) +"Lb" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/item/weapon/storage/briefcase,/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms2) +"Mb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"Nb" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 5},/obj/structure/holostool,/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/item/device/radio/intercom{pixel_y = 22},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms3) +"Ob" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/item/taperoll/engineering/applied,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/broken1) +"Pb" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/crew/dorms3) +"Qb" = (/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/ship/scrap/cargo/lower) +"Rb" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/cargo/lower) +"Sb" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/holostool,/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/tiled/dark,/area/ship/scrap/crew/dorms3) +"Tb" = (/obj/item/weapon/stool/padded,/obj/machinery/light/small,/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/tiled,/area/ship/scrap/broken1) +"Ub" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"Vb" = (/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{icon_state = "5-8"},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/lower) +"Wb" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/storage) +"Xb" = (/obj/item/weapon/circuitboard/pacman,/obj/item/weapon/circuitboard/recharge_station,/obj/item/weapon/circuitboard/shield_generator,/obj/structure/table/rack,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/item/weapon/storage/bag/circuits/basic,/obj/machinery/firealarm{pixel_y = 24},/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/techstorage) +"Yb" = (/obj/item/weapon/circuitboard/helm,/obj/item/weapon/circuitboard/unary_atmos/cooler,/obj/structure/table/rack,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/item/weapon/circuitboard/unary_atmos/heater,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/techstorage) +"Zb" = (/obj/item/weapon/storage/toolbox/electrical,/obj/item/weapon/storage/toolbox/electrical{pixel_x = 7; pixel_y = 4},/obj/item/device/t_scanner,/obj/item/weapon/cell/high,/obj/machinery/alarm{pixel_y = 24},/obj/item/weapon/tape_roll,/obj/machinery/light_switch{pixel_x = -24},/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 9},/obj/item/weapon/airalarm_electronics,/obj/item/weapon/airlock_electronics,/obj/item/weapon/airlock_electronics,/obj/structure/table/rack,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/storage) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacadaeafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacagagafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahaiaiaiaiahacajakalamanaoapapapapaqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaharararasalatauavalawaxaoayayayazaAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahcbaCjbaEalaFaGaHalaIaJaoaKnbaMqbaAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaOaOaPaOaPsbaoaRaSaTaUaUaVaowbaXaXaXaYaYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaOaZbabbaObcaobdgbaUbfbgbhaobiaXbjybblaYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabmbnbobpzbbrAbbtbubvbwbxbyAbbzBbbBbCbDbEaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaPCbbGbHaObIaobJbKbLbMbNhbaobPaXbQDbbSaXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaPaOaOaOaOEbaobTbUbVbWibbYaobZaXaXaXaXaYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaFbcccdcecfaoGbchcicicjHbaoclcmcnIbcpcqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacrcsubcuJbkbAbcxcyczcAcBckAbcCKbcEcFcGcHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacIcscJvbcebIaocLcycAcAcBckaobPcmcMLbcOcmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacPcQcRcScSMbaocUcVcWcWcXcYaoMbcmcmcmcmcmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacZdadblbdddeaodfmbdhaodidjaodkdldmNbdodlaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadpdadqdrObkbAbdtdudvdududwAbcCPbdydzdAdBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacSobdDdEcSbIaoQbaoaoaoaoRbaodHdIdJSbdLdIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaddpbTbdOcSdPUbdRdSdTdUdVdWVbdYdIdIdIdIdIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacScScScScSdZeaeaebebWbedededeeeeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaefXbYbrbdZZbekdcemeneeeoepeqeeeeereraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaefeseteuecewexeyezeAgceCeDeEeFeGeHeIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaefeJeKeLeftbeNeOePeQeeeReSeTeeeeeUeUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaefefefefefeVeWeXeYeZeehcfbfceeaaaaaaaaaaaaxbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaebebebfdebebeeeeedededaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaafeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/overmap_example/bearcat/bearcat-2.dmm b/maps/overmap_example/bearcat/bearcat-2.dmm new file mode 100644 index 00000000..d8972710 --- /dev/null +++ b/maps/overmap_example/bearcat/bearcat-2.dmm @@ -0,0 +1,661 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/obj/structure/shuttle/engine/propulsion/burst/left{dir = 1},/turf/simulated/floor/airless,/area/ship/scrap/shuttle/outgoing) +"ac" = (/obj/machinery/airlock_sensor{frequency = 1383; id_tag = "bearcat_shuttle_sensor"; pixel_y = -24},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1383; id_tag = "bearcat_shuttle_pump_out_internal"},/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"ad" = (/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/visible/supply,/obj/item/device/radio/intercom{dir = 8; pixel_x = 22},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"aj" = (/obj/effect/landmark/map_data{height = 2},/turf/space,/area/space) +"ak" = (/obj/effect/overmap/ship/bearcat,/turf/space,/area/space) +"ar" = (/obj/machinery/door/blast/regular,/turf/simulated/floor/plating,/area/ship/scrap/command/captain) +"as" = (/turf/simulated/wall/r_wall,/area/ship/scrap/command/captain) +"at" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/machinery/door/firedoor,/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plating,/area/ship/scrap/shuttle/outgoing) +"au" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/machinery/door/firedoor,/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/ship/scrap/shuttle/outgoing) +"av" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/shuttle/outgoing) +"aw" = (/turf/simulated/wall/r_wall,/area/ship/scrap/comms) +"ax" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/comms) +"aA" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/shuttle/outgoing) +"aD" = (/obj/machinery/ntnet_relay,/turf/simulated/floor/bluegrid,/area/ship/scrap/comms) +"aE" = (/turf/simulated/floor/bluegrid,/area/ship/scrap/comms) +"aH" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/obj/item/weapon/gun/energy/stunrevolver,/obj/structure/closet/cabinet,/obj/item/weapon/storage/secure/briefcase,/obj/item/device/taperecorder,/obj/item/device/camera,/obj/item/weapon/storage/backpack/dufflebag/syndie,/obj/item/weapon/storage/box/shotgunshells,/obj/item/weapon/handcuffs,/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"aI" = (/obj/item/weapon/bedsheet/captain,/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/item/weapon/gun/projectile/pistol,/obj/structure/bed/padded,/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"aJ" = (/obj/item/weapon/paper_bin,/obj/item/weapon/pen,/obj/structure/table/woodentable,/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/light_switch{pixel_y = 25},/obj/random_multi/single_item/captains_spare_id,/obj/random/action_figure,/obj/random_multi/single_item/captains_spare_id,/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"aL" = (/turf/simulated/wall/titanium,/area/ship/scrap/shuttle/outgoing) +"aO" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/comms) +"aP" = (/obj/machinery/message_server,/turf/simulated/floor/bluegrid,/area/ship/scrap/comms) +"aQ" = (/obj/machinery/door/window/westleft,/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/tiled/dark,/area/ship/scrap/comms) +"aS" = (/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/hallway) +"aU" = (/obj/structure/cable{icon_state = "6-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"aV" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"aW" = (/obj/structure/bed/chair/comfy/brown,/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"aX" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/command/captain) +"aZ" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/shuttle/outgoing) +"ba" = (/obj/machinery/alarm{dir = 1; icon_state = "alarm0"; pixel_x = 0; pixel_y = -32},/obj/machinery/computer/message_monitor,/turf/simulated/floor/bluegrid,/area/ship/scrap/comms) +"bb" = (/obj/machinery/light,/obj/item/modular_computer/console/preset/engineering,/obj/item/device/radio/intercom{dir = 4; pixel_x = -22},/obj/machinery/alarm{dir = 1; icon_state = "alarm0"; pixel_x = 0; pixel_y = -24},/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/bridge) +"bc" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/hallway) +"bd" = (/obj/machinery/atmospherics/pipe/simple/visible/universal,/obj/machinery/firealarm{dir = 4; pixel_x = 24; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"be" = (/obj/structure/cable{icon_state = "4-9"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"bg" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/closet/walllocker/emerglocker/north,/obj/machinery/floodlight,/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"bh" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/outgoing) +"bi" = (/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"bk" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/command/captain) +"bm" = (/turf/simulated/wall/r_wall,/area/ship/scrap/dock) +"bp" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/machinery/light,/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/outgoing) +"bq" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/outgoing) +"bs" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/dock) +"bt" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/dock) +"bv" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"bw" = (/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 1; name = "Docking Area APC"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"bx" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/outgoing) +"by" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"bA" = (/obj/structure/window/reinforced,/turf/space,/area/space) +"bB" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/obj/structure/sign/warning/vacuum{pixel_x = -35},/obj/machinery/computer/shuttle_control/explore/bearcat,/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"bC" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"bD" = (/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"bE" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"bF" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/plaque,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"bG" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"bH" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/structure/sign/warning/vacuum{pixel_x = 35},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"bQ" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 10; icon_state = "intact"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"bT" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"bW" = (/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 6},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"bX" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/machinery/access_button/airlock_interior{master_tag = "bearcat_starboard_dock"; pixel_x = -12; pixel_y = 20},/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "dock_star_in"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"bY" = (/obj/machinery/light{dir = 1},/obj/machinery/airlock_sensor{id_tag = "dock_star_sensor"; pixel_y = 37},/obj/machinery/embedded_controller/radio/airlock/docking_port{id_tag = "bearcat_starboard_dock"; pixel_y = 25; tag_airpump = "dock_star_pump"; tag_chamber_sensor = "dock_star_sensor"; tag_exterior_door = "dock_star_out"; tag_interior_door = "dock_star_in"},/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"bZ" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1379; id_tag = "dock_star_pump"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"ca" = (/obj/machinery/access_button/airlock_exterior{master_tag = "bearcat_starboard_dock"; pixel_x = 18; pixel_y = 20},/obj/machinery/door/airlock/external/bolted/cycling{id_tag = "dock_star_out"},/obj/machinery/shield_diffuser,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"cb" = (/obj/effect/shuttle_landmark/docking_arm_starboard/pod,/turf/space,/area/space) +"cc" = (/obj/machinery/door/airlock/hatch,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{icon_state = "2-5"},/obj/structure/sign{icon_state = "radiation"; pixel_x = 32},/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/outgoing) +"cd" = (/obj/machinery/atmospherics/pipe/simple/hidden,/turf/simulated/wall/titanium,/area/ship/scrap/shuttle/outgoing) +"ce" = (/obj/structure/window/reinforced{dir = 1},/turf/space,/area/space) +"cf" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/ship/scrap/dock) +"cg" = (/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/portables_connector{icon_state = "map_connector"; dir = 4},/obj/machinery/portable_atmospherics/canister/air/airlock,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/simulated/floor,/area/ship/scrap/dock) +"ch" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 9},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"cj" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"cl" = (/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 5},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"cm" = (/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/portables_connector{dir = 8},/obj/machinery/portable_atmospherics/canister/air/airlock,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/simulated/floor,/area/ship/scrap/dock) +"cn" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/dock) +"co" = (/obj/structure/lattice,/obj/structure/window/reinforced{dir = 1},/turf/space,/area/space) +"cp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"cq" = (/obj/structure/closet/crate/freezer/rations,/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"cs" = (/obj/machinery/atmospherics/pipe/tank/air,/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"ct" = (/obj/structure/sign/warning/docking_area,/turf/simulated/wall/r_wall,/area/ship/scrap/dock) +"cu" = (/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"cw" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"cy" = (/obj/structure/lattice,/turf/space,/area/space) +"cz" = (/obj/machinery/power/apc{dir = 8},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/structure/cable,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"cA" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"cB" = (/obj/machinery/atmospherics/pipe/simple/visible/universal{dir = 4},/obj/structure/cable{icon_state = "2-8"},/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"cC" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/atmospherics/pipe/simple/hidden/blue{icon_state = "intact"; dir = 9},/obj/machinery/floodlight,/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"cE" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/port) +"cG" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/starboard) +"cH" = (/obj/machinery/light/small{dir = 8},/obj/structure/closet/crate/uranium,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"cI" = (/obj/structure/cable,/obj/machinery/power/port_gen/pacman/super,/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"cJ" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/saloon) +"cK" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/airlock/autoname,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"cL" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/random/maintenance,/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/starboard) +"cN" = (/turf/simulated/wall,/area/ship/scrap/crew/saloon) +"cO" = (/obj/machinery/vending/snack,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"cQ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"cS" = (/obj/machinery/vending/coffee,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"cT" = (/turf/simulated/wall,/area/ship/scrap/crew/toilets) +"cU" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/toilets) +"cV" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/crew/toilets) +"cW" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/port) +"cY" = (/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"cZ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/stool/padded,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"da" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"db" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/structure/table/standard,/obj/machinery/recharger,/obj/structure/sign/poster{pixel_x = 32; pixel_y = 0},/obj/item/trash/tray,/obj/item/weapon/circular_saw,/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"dc" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/item/weapon/crowbar,/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/starboard) +"dd" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/cryo) +"de" = (/turf/simulated/wall,/area/ship/scrap/crew/cryo) +"df" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled{icon_state = "white"},/area/ship/scrap/crew/cryo) +"dg" = (/obj/machinery/computer/cryopod,/turf/simulated/wall,/area/ship/scrap/crew/cryo) +"dh" = (/obj/structure/window/reinforced/tinted{icon_state = "twindow"; dir = 4},/obj/machinery/shower{icon_state = "shower"; dir = 4},/obj/structure/window/reinforced/tinted{dir = 1},/obj/item/weapon/soap,/obj/structure/curtain/open/shower,/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/toilets) +"di" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/structure/toilet,/obj/structure/window/reinforced/tinted{dir = 1},/obj/structure/window/reinforced/tinted{icon_state = "twindow"; dir = 4},/obj/structure/window/reinforced/tinted{dir = 8; icon_state = "twindow"},/obj/effect/decal/cleanable/dirt,/obj/effect/landmark/start{name = "Deck Hand"},/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/toilets) +"dj" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/structure/mirror{pixel_y = 29},/obj/structure/sink{pixel_y = 18},/obj/structure/window/reinforced/tinted{dir = 8; icon_state = "twindow"},/obj/structure/window/reinforced/tinted{icon_state = "twindow"; dir = 4},/obj/structure/window/reinforced/tinted{dir = 1},/obj/structure/window/reinforced/tinted{dir = 8; icon_state = "twindow"},/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/obj/item/weapon/hemostat,/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/toilets) +"dk" = (/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/port) +"dl" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/structure/reagent_dispensers/water_cooler,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"dm" = (/obj/item/weapon/stool/padded,/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"dp" = (/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/starboard) +"dr" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/obj/effect/landmark{name = "JoinLateCryo"},/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/cryo) +"ds" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/cryopod,/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/cryo) +"dt" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/crew/toilets) +"du" = (/obj/machinery/door/window/westleft{base_state = "right"; dir = 4; icon_state = "right"; name = "Reception Window"; opacity = 1},/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/item/weapon/towel,/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/toilets) +"dv" = (/obj/machinery/door/window/westleft{base_state = "right"; dir = 4; icon_state = "right"; name = "Reception Window"; opacity = 1},/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/toilets) +"dw" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/toilets) +"dx" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/airlock/maintenance_hatch{name = "Bathrooms"; normalspeed = 0},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/crew/toilets) +"dy" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/port) +"dz" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"dA" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"dB" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"dC" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/stool/padded,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"dD" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"dE" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"dF" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/starboard) +"dG" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/airlock/maintenance_hatch{name = "Cryo Storage"; normalspeed = 0},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/crew/cryo) +"dH" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/cryo) +"dI" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/effect/landmark{name = "JoinLateCryo"},/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/cryo) +"dJ" = (/obj/machinery/cryopod,/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/cryo) +"dK" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor,/obj/structure/window/reinforced{dir = 5; health = 1e+007},/turf/simulated/floor,/area/ship/scrap/crew/cryo) +"dM" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 1},/obj/structure/window/reinforced/tinted,/obj/structure/window/reinforced/tinted{icon_state = "twindow"; dir = 4},/obj/structure/window/reinforced/tinted{dir = 8; icon_state = "twindow"},/obj/effect/decal/cleanable/dirt,/obj/random_multi/single_item/captains_spare_id,/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/toilets) +"dN" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 1},/obj/structure/window/reinforced/tinted{dir = 8; icon_state = "twindow"},/obj/structure/window/reinforced/tinted{icon_state = "twindow"; dir = 4},/obj/structure/window/reinforced/tinted,/obj/effect/decal/cleanable/dirt,/obj/structure/cable,/obj/machinery/power/apc{dir = 4; name = "Bathrooms APC"},/obj/machinery/light_switch{pixel_y = -25},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/toilets) +"dO" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/effect/decal/cleanable/dirt,/obj/structure/disposalpipe/segment{icon_state = "conpipe-c"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/port) +"dP" = (/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/wall,/area/ship/scrap/crew/saloon) +"dQ" = (/obj/effect/decal/cleanable/dirt,/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/vending/cigarette,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"dS" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"dU" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 8},/obj/machinery/light_switch{pixel_x = 28},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"dV" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/starboard) +"dW" = (/obj/structure/cable,/obj/machinery/power/apc{name = "Dorms APC"},/obj/machinery/light_switch{pixel_x = -25},/obj/structure/closet/wardrobe/mixed,/obj/item/weapon/storage/backpack/dufflebag/med,/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/cryo) +"dX" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/effect/landmark{name = "JoinLateCryo"},/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/cryo) +"dY" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/kitchen) +"dZ" = (/turf/simulated/wall,/area/ship/scrap/crew/kitchen) +"ea" = (/obj/structure/disposalpipe/segment,/obj/structure/closet/walllocker/emerglocker/east,/obj/machinery/light_switch{pixel_x = -25},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/port) +"eb" = (/turf/simulated/wall,/area/ship/scrap/cargo) +"ec" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"ed" = (/obj/machinery/light_switch{pixel_x = -25},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/sign/deck/first{pixel_x = 32},/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/starboard) +"ee" = (/turf/simulated/wall,/area/ship/scrap/crew/medbay) +"ef" = (/obj/machinery/door/airlock/autoname,/turf/simulated/floor/tiled{icon_state = "white"},/area/ship/scrap/crew/medbay) +"eh" = (/turf/simulated/mineral,/area/space) +"el" = (/obj/structure/disposalpipe/segment,/obj/machinery/power/apc{dir = 4; name = "Crew Deck APC"},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/port) +"eo" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"er" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor,/area/ship/scrap/crew/hallway/starboard) +"es" = (/obj/machinery/sleeper,/obj/structure/sign/warning/nosmoking_2{pixel_y = 28},/obj/structure/closet/walllocker/emerglocker/west,/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/medbay) +"et" = (/obj/item/roller,/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/medbay) +"ev" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/medbay) +"ew" = (/turf/simulated/mineral/random/high_chance,/area/space) +"ex" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/engine/port) +"ey" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/crew/kitchen) +"ez" = (/obj/structure/table/standard,/obj/effect/floor_decal/corner/red/diagonal,/obj/item/weapon/reagent_containers/glass/beaker{pixel_x = 5},/obj/item/weapon/book/manual/chef_recipes,/obj/item/weapon/reagent_containers/food/condiment/small/peppermill{pixel_x = 3},/obj/item/weapon/reagent_containers/food/condiment/enzyme{layer = 5},/obj/item/weapon/reagent_containers/glass/rag,/turf/simulated/floor/tiled,/area/ship/scrap/crew/kitchen) +"eA" = (/obj/item/weapon/stool/padded,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/floor_decal/corner/red/diagonal,/obj/effect/landmark/start{name = "Cook"},/turf/simulated/floor/tiled,/area/ship/scrap/crew/kitchen) +"eB" = (/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/power/apc{dir = 4; name = "Galley APC"},/obj/effect/floor_decal/corner/red/diagonal,/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/crew/kitchen) +"eC" = (/obj/structure/disposalpipe/segment,/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/sign/directions/engineering{pixel_x = -32},/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/port) +"eD" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"eE" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/closet/crate/hydroponics/prespawned,/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"eF" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"eH" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"eI" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/sign/directions/engineering{pixel_x = -32},/obj/structure/ladder,/turf/simulated/floor,/area/ship/scrap/crew/hallway/starboard) +"eJ" = (/obj/structure/sign/redcross,/turf/simulated/wall,/area/ship/scrap/crew/medbay) +"eL" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/medbay) +"eM" = (/obj/structure/iv_drip,/obj/structure/closet/medical_wall{name = "pill cabinet"; pixel_x = 26},/obj/item/weapon/storage/pill_bottle/antidexafen,/obj/item/weapon/storage/pill_bottle/tramadol,/obj/item/weapon/storage/pill_bottle/antitox,/obj/item/weapon/storage/pill_bottle/kelotane,/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/medbay) +"eN" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/engine/starboard) +"eO" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/obj/structure/cable{icon_state = "4-10"},/turf/simulated/floor,/area/ship/scrap/crew/kitchen) +"eP" = (/obj/structure/table/standard,/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/item/weapon/storage/box/donkpockets,/obj/effect/floor_decal/corner/red/diagonal,/obj/item/weapon/material/kitchen/rollingpin,/obj/item/weapon/reagent_containers/food/condiment/small/saltshaker{pixel_x = -3; pixel_y = 0},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/ship/scrap/crew/kitchen) +"eQ" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/effect/floor_decal/corner/red/diagonal,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/ship/scrap/crew/kitchen) +"eR" = (/obj/structure/disposalpipe/segment{icon_state = "conpipe-c"; dir = 4},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/effect/floor_decal/corner/red/diagonal,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/ship/scrap/crew/kitchen) +"eS" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/crew/kitchen) +"eT" = (/obj/structure/disposalpipe/junction,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/port) +"eU" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"eV" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"eW" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"eX" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"eY" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"eZ" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"fa" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/obj/structure/cable{icon_state = "2-8"},/turf/simulated/floor,/area/ship/scrap/crew/hallway/starboard) +"fb" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/airlock/maintenance_hatch{name = "Medical Bay"; normalspeed = 0},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/crew/medbay) +"fc" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/medbay) +"fd" = (/obj/effect/landmark/start{name = "Doc"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/structure/bed/chair/office/light,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/medbay) +"fe" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/table/standard,/obj/item/weapon/glass_extra/straw,/obj/item/toy/therapy_blue,/obj/item/weapon/reagent_containers/spray/cleaner,/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/medbay) +"ff" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/obj/structure/cable{icon_state = "6-8"},/turf/simulated/floor,/area/ship/scrap/crew/medbay) +"fg" = (/obj/item/weapon/storage/pill_bottle/happy,/obj/machinery/power/apc{dir = 1},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/port) +"fh" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 6},/obj/machinery/meter,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/port) +"fk" = (/obj/structure/table/standard,/obj/machinery/microwave,/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/effect/floor_decal/corner/red/diagonal,/turf/simulated/floor/tiled,/area/ship/scrap/crew/kitchen) +"fm" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{icon_state = "pipe-t"; dir = 1},/obj/machinery/light_switch{pixel_x = 28},/obj/effect/floor_decal/corner/red/diagonal,/turf/simulated/floor/tiled,/area/ship/scrap/crew/kitchen) +"fn" = (/obj/structure/disposalpipe/segment,/obj/machinery/door/airlock/autoname,/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/port) +"fp" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"fq" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"fr" = (/obj/structure/closet/crate,/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/cable{icon_state = "6-8"},/obj/random/storage,/obj/random/bomb_supply,/obj/random/bomb_supply,/obj/random/bomb_supply,/obj/item/weapon/storage/box/syringes,/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"fs" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable,/obj/machinery/power/apc{dir = 4; name = "Cargo Hold APC"},/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"ft" = (/obj/machinery/power/apc{dir = 4; name = "Crew Deck APC"},/obj/structure/cable,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/door/airlock/autoname,/turf/simulated/floor,/area/ship/scrap/crew/hallway/starboard) +"fu" = (/obj/structure/table/standard,/obj/structure/cable,/obj/machinery/power/apc{name = "Medical Bay APC"},/obj/machinery/light_switch{pixel_x = -25},/obj/structure/closet/medical_wall/filled{pixel_y = -32},/obj/item/weapon/tape_roll,/obj/item/weapon/retractor,/obj/item/weapon/scalpel,/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/medbay) +"fw" = (/obj/structure/table/standard,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/structure/sign/warning/nosmoking_1{pixel_y = -32},/obj/structure/sign/goldenplaque/medical{pixel_x = 32},/obj/item/weapon/storage/firstaid/adv,/obj/random/medical,/obj/item/stack/medical/advanced/bruise_pack,/obj/item/weapon/reagent_containers/syringe/antiviral,/obj/item/device/healthanalyzer,/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/medbay) +"fz" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/item/weapon/coin/gold,/obj/item/weapon/coin/silver,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 10},/obj/machinery/meter,/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/starboard) +"fA" = (/obj/machinery/power/apc{dir = 1},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/starboard) +"fB" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 6},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/port) +"fC" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/manifold/visible/fuel{icon_state = "map"; dir = 4},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/port) +"fD" = (/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/obj/structure/lattice,/turf/space,/area/space) +"fE" = (/turf/simulated/wall,/area/ship/scrap/crew/wash) +"fI" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"fJ" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"fK" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/structure/cable{icon_state = "2-9"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 8},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"fM" = (/obj/structure/lattice,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/space,/area/space) +"fN" = (/turf/simulated/wall,/area/ship/scrap/maintenance/engine/starboard) +"fO" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/manifold/visible/fuel{icon_state = "map"; dir = 8},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/starboard) +"fP" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 10},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/starboard) +"fQ" = (/obj/effect/floor_decal/industrial/warning,/obj/structure/sign/warning/hot_exhaust,/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/engine/port) +"fT" = (/turf/simulated/wall/r_wall,/area/ship/scrap/crew/wash) +"fU" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 6},/obj/structure/undies_wardrobe,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/wash) +"fX" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/door/airlock/maintenance_hatch{name = "Laundry"; normalspeed = 0},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/crew/wash) +"fY" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/disposalpipe/junction,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 10},/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/port) +"fZ" = (/turf/simulated/open,/area/ship/scrap/cargo) +"ga" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 8},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"gb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 6},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor,/area/ship/scrap/crew/hallway/starboard) +"gc" = (/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/plating,/area/ship/scrap/unused) +"gd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/random/junk,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/structure/cable{icon_state = "6-8"},/turf/simulated/floor,/area/ship/scrap/unused) +"ge" = (/obj/machinery/light_switch{pixel_y = 25},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/random/maintenance,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/item/modular_computer/console/preset/library,/obj/structure/table/standard,/turf/simulated/floor,/area/ship/scrap/unused) +"gg" = (/turf/simulated/wall/r_wall,/area/ship/scrap/unused) +"gh" = (/obj/effect/floor_decal/industrial/warning,/obj/structure/sign/warning/hot_exhaust,/turf/simulated/wall,/area/ship/scrap/maintenance/engine/starboard) +"gj" = (/obj/effect/floor_decal/industrial/warning,/obj/structure/sign/warning/hot_exhaust,/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/engine/starboard) +"gk" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/space) +"gl" = (/obj/structure/lattice,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/space) +"gm" = (/obj/structure/lattice,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 5},/turf/space,/area/space) +"gn" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor,/area/ship/scrap/crew/wash) +"go" = (/obj/structure/closet,/obj/random/clothing,/obj/random/clothing,/obj/random/clothing,/obj/random/clothing,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 9},/obj/item/weapon/storage/backpack/dufflebag,/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/wash) +"gp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/wash) +"gq" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{icon_state = "pipe-t"; dir = 1},/obj/machinery/light_switch{pixel_x = 28},/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/wash) +"gr" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/sign/directions/medical{dir = 4; icon_state = "direction_med"; pixel_x = 32; pixel_z = -4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/port) +"gs" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/light/small{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"gt" = (/obj/structure/closet/walllocker/emerglocker/west,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor,/area/ship/scrap/crew/hallway/starboard) +"gu" = (/turf/simulated/wall,/area/ship/scrap/unused) +"gv" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor,/area/ship/scrap/unused) +"gw" = (/obj/effect/decal/cleanable/generic,/obj/item/device/flashlight,/obj/structure/skele_stand{anchored = 0; name = "Spookers"},/obj/structure/cable{icon_state = "2-9"},/turf/simulated/floor,/area/ship/scrap/unused) +"gx" = (/obj/random/junk,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 5},/turf/simulated/floor,/area/ship/scrap/unused) +"gy" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor,/area/ship/scrap/unused) +"gz" = (/obj/structure/lattice,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 9},/turf/space,/area/space) +"gA" = (/obj/structure/closet,/obj/random/clothing,/obj/random/clothing,/obj/random/clothing,/obj/random/clothing,/obj/item/weapon/reagent_containers/glass/rag,/obj/item/weapon/clothingbag/rubbermask,/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/wash) +"gB" = (/obj/machinery/washing_machine,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/wash) +"gC" = (/obj/structure/table/standard,/obj/machinery/light/small,/obj/item/weapon/reagent_containers/spray/cleaner,/obj/item/weapon/storage/laundry_basket,/obj/random_multi/single_item/captains_spare_id,/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/wash) +"gE" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/structure/sign/deck/first{pixel_x = 32},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"gI" = (/obj/random/maintenance,/obj/item/weapon/clothingbag/rubbersuit,/turf/simulated/floor,/area/ship/scrap/unused) +"gL" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/port) +"gM" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/structure/cable{icon_state = "1-10"},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"gN" = (/obj/machinery/door/airlock/autoname,/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"gO" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor,/area/ship/scrap/crew/hallway/starboard) +"gP" = (/turf/simulated/wall/r_wall,/area/ship/scrap/hidden) +"gQ" = (/turf/simulated/wall,/area/ship/scrap/hidden) +"gU" = (/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/hallway) +"gV" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"gW" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/structure/cable{icon_state = "5-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/light/small,/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"gX" = (/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"gY" = (/obj/machinery/door/airlock/autoname,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor,/area/ship/scrap/maintenance/hallway) +"ha" = (/obj/machinery/light_switch{pixel_y = 25},/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/item/weapon/storage/backpack/dufflebag/syndie,/turf/simulated/floor/plating,/area/ship/scrap/hidden) +"hb" = (/obj/structure/shuttle/engine/propulsion/burst/left,/turf/simulated/floor/airless,/area/ship/scrap/shuttle/outgoing) +"hc" = (/obj/structure/disposaloutlet{dir = 8},/obj/structure/disposalpipe/trunk{dir = 4},/turf/space,/area/space) +"hd" = (/obj/machinery/light/small{dir = 8},/obj/structure/closet/crate/uranium,/obj/machinery/firealarm{dir = 8; pixel_x = -24; pixel_y = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/power) +"hi" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/structure/cable{icon_state = "6-8"},/obj/structure/disposalpipe/junction/yjunction{icon_state = "pipe-y"; dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/hallway) +"hj" = (/obj/effect/decal/cleanable/cobweb,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor,/area/ship/scrap/maintenance/hallway) +"hk" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall/r_wall{can_open = 1},/area/ship/scrap/hidden) +"hl" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/hidden) +"hm" = (/obj/item/weapon/stool/padded,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/plating,/area/ship/scrap/hidden) +"hr" = (/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 5},/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/hallway) +"ht" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/structure/disposalpipe/segment{icon_state = "conpipe-c"; dir = 2},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/hallway) +"hu" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/hallway) +"hv" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/fuel{icon_state = "map"; dir = 1},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/hallway) +"hw" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/machinery/power/apc{dir = 1},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/hallway) +"hx" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/hallway) +"hy" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/item/weapon/crowbar,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/hallway) +"hz" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/structure/sign/directions/medical{dir = 1; icon_state = "direction_med"; pixel_x = 30; pixel_z = 4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 9},/turf/simulated/floor,/area/ship/scrap/maintenance/hallway) +"hA" = (/obj/machinery/power/apc{name = "Medical Bay APC"},/obj/structure/cable{d2 = 6; icon_state = "0-6"},/turf/simulated/floor/plating,/area/ship/scrap/hidden) +"hB" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/ship/scrap/hidden) +"hC" = (/obj/structure/closet/crate,/obj/random/loot,/obj/random/loot,/obj/random/loot,/obj/random/projectile,/obj/random/projectile,/turf/simulated/floor/plating,/area/ship/scrap/hidden) +"hD" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/atmos) +"hF" = (/turf/simulated/wall,/area/ship/scrap/maintenance/atmos) +"hG" = (/turf/simulated/wall,/area/ship/scrap/maintenance/engineering) +"hH" = (/obj/structure/disposalpipe/segment,/turf/simulated/wall,/area/ship/scrap/maintenance/engineering) +"hJ" = (/turf/simulated/wall,/area/ship/scrap/maintenance/power) +"hK" = (/obj/structure/cable{icon_state = "2-9"},/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/power) +"hL" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/power) +"hO" = (/obj/machinery/atmospherics/pipe/simple/visible/universal{dir = 4},/obj/effect/floor_decal/corner/blue{dir = 10},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"hP" = (/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{icon_state = "intact-scrubbers"; dir = 4},/obj/effect/floor_decal/corner/blue{dir = 8},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/power/apc/high{dir = 1},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"hQ" = (/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{icon_state = "intact-scrubbers"; dir = 10},/obj/machinery/meter,/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/obj/machinery/light_switch{pixel_y = 25},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"hS" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/alarm{pixel_y = 32},/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/structure/disposalpipe/trunk{icon_state = "pipe-t"; dir = 1},/obj/machinery/disposal,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"hU" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"hV" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/light_switch{pixel_y = 25},/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/structure/table/standard,/obj/item/weapon/reagent_containers/food/drinks/coffeecup/metal,/obj/item/weapon/reagent_containers/food/drinks/coffeecup/metal,/obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee{name = "coffee canister"},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"hW" = (/obj/structure/bed/chair/comfy/brown,/obj/effect/landmark/start{name = "Chief Engineer"},/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/structure/closet/hydrant{pixel_y = 32},/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"hX" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/structure/sign/warning/high_voltage{pixel_x = 32},/obj/structure/table/standard,/obj/item/toy/prize/ripley,/obj/item/weapon/material/ashtray/plastic,/obj/machinery/recharger,/obj/item/blueprints,/obj/structure/sign/poster{pixel_y = 32},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"ib" = (/obj/machinery/atmospherics/pipe/simple/visible/red,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"ic" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/effect/floor_decal/corner/blue/diagonal,/obj/effect/floor_decal/corner/blue/diagonal{dir = 4},/obj/machinery/meter/turf,/turf/simulated/floor/reinforced/oxygen,/area/ship/scrap/maintenance/atmos) +"id" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/effect/floor_decal/corner/blue/diagonal,/obj/effect/floor_decal/corner/blue/diagonal{dir = 4},/turf/simulated/floor/reinforced/oxygen,/area/ship/scrap/maintenance/atmos) +"ie" = (/obj/machinery/atmospherics/portables_connector,/obj/effect/floor_decal/corner/blue{dir = 9},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"if" = (/obj/machinery/atmospherics/pipe/simple/visible/supply{icon_state = "intact-supply"; dir = 6},/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{icon_state = "intact-scrubbers"; dir = 5},/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"ih" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"ii" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/structure/cable{icon_state = "4-10"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"ij" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/ladder,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"ik" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/effect/decal/cleanable/dirt,/obj/item/weapon/stool/padded,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 9},/obj/effect/landmark/start{name = "Junior Engineer"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"il" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"im" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/effect/decal/cleanable/liquid_fuel,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"io" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/power) +"ip" = (/obj/machinery/power/sensor{long_range = 1; name_tag = "Main Grid"},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/power) +"iq" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/structure/cable{icon_state = "2-9"},/obj/machinery/recharge_station,/obj/structure/cable{icon_state = "2-8"},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/power) +"is" = (/obj/machinery/atmospherics/pipe/simple/visible/green{dir = 4; icon_state = "intact"},/obj/machinery/atmospherics/pipe/simple/visible/red,/obj/effect/floor_decal/corner/blue{dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"it" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/atmospherics/unary/outlet_injector{icon_state = "map_injector"; dir = 8; use_power = 1; frequency = 1441; id = "n2_in"},/turf/simulated/floor/reinforced/oxygen,/area/ship/scrap/maintenance/atmos) +"iu" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/atmospherics/unary/vent_pump/high_volume{icon_state = "map_vent_in"; dir = 4; use_power = 1; id_tag = "air_out"; pump_direction = 0; external_pressure_bound = 0; internal_pressure_bound = 2000; pressure_checks = 2; external_pressure_bound_default = 0; internal_pressure_bound_default = 2000; pressure_checks_default = 2; frequency = 1443},/turf/simulated/floor/reinforced/oxygen,/area/ship/scrap/maintenance/atmos) +"iv" = (/obj/machinery/meter,/obj/effect/floor_decal/corner/blue{dir = 9},/obj/machinery/atmospherics/pipe/manifold/visible/cyan{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"ix" = (/obj/structure/closet/walllocker/emerglocker/west,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/obj/structure/cable{icon_state = "2-5"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"iy" = (/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/obj/structure/closet/secure_closet/engineering_welding,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"iz" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/obj/machinery/computer/engines,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"iA" = (/obj/structure/cable,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/obj/structure/table/standard,/obj/machinery/button/remote/blast_door{id = "engwindow"; name = "Engine Observation"; pixel_x = 6},/obj/machinery/button/ignition{id = "engine"; pixel_x = -5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"iB" = (/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/obj/machinery/light/small,/obj/item/modular_computer/console/preset/engineering,/obj/machinery/button/remote/blast_door{id = "scram"; name = "CORE SCRAM"; pixel_y = -26},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"iC" = (/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/obj/effect/decal/cleanable/liquid_fuel,/obj/machinery/vending/cigarette,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"iD" = (/obj/structure/reagent_dispensers/fueltank,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 10},/obj/effect/decal/cleanable/liquid_fuel,/obj/structure/sign/warning/nosmoking_1{pixel_y = -32},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"iE" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/power) +"iF" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/power) +"iI" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/maintenance/atmos) +"iJ" = (/obj/machinery/atmospherics/pipe/simple/visible/green,/obj/machinery/meter,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"iK" = (/obj/machinery/atmospherics/pipe/simple/visible/red,/obj/effect/floor_decal/corner/white{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"iL" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/reinforced/airmix,/area/ship/scrap/maintenance/atmos) +"iM" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/reinforced/airmix,/area/ship/scrap/maintenance/atmos) +"iQ" = (/turf/simulated/wall/r_wall,/area/ship/scrap/maintenance/engine/aft) +"iR" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "engwindow"; name = "blast door"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor,/area/ship/scrap/maintenance/engine/aft) +"iT" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/power) +"iU" = (/obj/machinery/power/shield_generator,/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/power) +"iV" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; external_pressure_bound = 140; external_pressure_bound_default = 140; icon_state = "map_vent_out"; pressure_checks = 1; pressure_checks_default = 1; use_power = 1},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/atmos) +"iW" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 4},/turf/simulated/floor,/area/ship/scrap/maintenance/atmos) +"iY" = (/obj/machinery/atmospherics/pipe/manifold/visible/red{icon_state = "map"; dir = 4},/obj/effect/floor_decal/corner/white{icon_state = "corner_white"; dir = 6},/obj/machinery/meter,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"iZ" = (/obj/structure/window/reinforced{dir = 8},/obj/effect/floor_decal/corner/white/diagonal{icon_state = "corner_white_diagonal"; dir = 4},/obj/effect/floor_decal/corner/white/diagonal,/obj/machinery/meter/turf,/turf/simulated/floor/reinforced/airmix,/area/ship/scrap/maintenance/atmos) +"ja" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/atmospherics/unary/outlet_injector{dir = 4; frequency = 1441; icon_state = "map_injector"; id = "n2_in"; use_power = 1},/obj/effect/floor_decal/corner/white/diagonal,/obj/effect/floor_decal/corner/white/diagonal{icon_state = "corner_white_diagonal"; dir = 4},/turf/simulated/floor/reinforced/airmix,/area/ship/scrap/maintenance/atmos) +"jb" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/bed/chair/comfy/brown{icon_state = "comfychair_preview"; dir = 1},/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"jc" = (/obj/machinery/door/airlock/glass_external/bolted/cycling{frequency = 1383; id_tag = "bearcat_shuttle_out"},/obj/machinery/access_button/airlock_exterior{frequency = 1383; master_tag = "bearcat_shuttle"; pixel_x = 18; pixel_y = -20},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"jd" = (/obj/structure/closet/walllocker/emerglocker/west,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"je" = (/obj/structure/sign/warning/fire{pixel_y = 32},/obj/machinery/atmospherics/portables_connector,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jf" = (/obj/machinery/light_switch{pixel_y = 25},/obj/machinery/atmospherics/pipe/tank/carbon_dioxide,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jg" = (/obj/machinery/atmospherics/portables_connector,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jh" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"ji" = (/obj/machinery/atmospherics/portables_connector,/obj/machinery/portable_atmospherics/canister/phoron,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jj" = (/obj/machinery/atmospherics/portables_connector,/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jk" = (/obj/structure/closet/radiation,/obj/machinery/button/remote/blast_door{id = "radaway"; name = "Radiation shields"; pixel_x = -24},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/power) +"jl" = (/obj/machinery/power/terminal{dir = 4},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/power) +"jm" = (/obj/machinery/power/smes/buildable/max_cap_in_out,/obj/structure/cable,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/power) +"jn" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/maintenance/atmos) +"jo" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/powered/scrubber,/obj/effect/floor_decal/corner/white{icon_state = "corner_white"; dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"jp" = (/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/reinforced/airmix,/area/ship/scrap/maintenance/atmos) +"jq" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/atmospherics/unary/vent_pump/high_volume{icon_state = "map_vent_in"; dir = 4; use_power = 1; id_tag = "air_out"; pump_direction = 0; external_pressure_bound = 0; internal_pressure_bound = 2000; pressure_checks = 2; external_pressure_bound_default = 0; internal_pressure_bound_default = 2000; pressure_checks_default = 2; frequency = 1443},/turf/simulated/floor/reinforced/airmix,/area/ship/scrap/maintenance/atmos) +"jr" = (/obj/effect/floor_decal/corner/white{icon_state = "corner_white"; dir = 9},/obj/machinery/atmospherics/pipe/simple/visible/cyan,/obj/machinery/atmospherics/binary/pump/on{dir = 4; name = "Air to Ports"},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"js" = (/obj/machinery/atmospherics/pipe/manifold/visible/blue{icon_state = "map"; dir = 4},/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/obj/machinery/meter,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"ju" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel{icon_state = "map"; dir = 8},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jv" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/manifold/visible/fuel,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jw" = (/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 9},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jx" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jy" = (/obj/machinery/atmospherics/pipe/simple/visible/green{icon_state = "intact"; dir = 5},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jz" = (/obj/machinery/atmospherics/omni/mixer{tag_north = 1; tag_north_con = 0.36; tag_south = 2; tag_west = 1; tag_west_con = 0.64},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jA" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/door/window/southright,/obj/machinery/door/window/northleft,/obj/machinery/door/blast/regular/open{dir = 2; icon_state = "pdoor0"; id = "radaway"; layer = 5; opacity = 0},/obj/structure/sign{icon_state = "radiation"; pixel_x = -32},/obj/structure/sign{icon_state = "radiation"; pixel_x = 32},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/power) +"jB" = (/obj/structure/grille,/turf/space,/area/space) +"jD" = (/obj/machinery/atmospherics/pipe/simple/visible/green{dir = 4; icon_state = "intact"},/obj/effect/floor_decal/corner/red{dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"jE" = (/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/unary/outlet_injector{icon_state = "map_injector"; dir = 8; use_power = 1; frequency = 1441; id = "n2_in"},/turf/simulated/floor/reinforced/nitrogen,/area/ship/scrap/maintenance/atmos) +"jF" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/unary/vent_pump/high_volume{icon_state = "map_vent_in"; dir = 4; use_power = 1; id_tag = "air_out"; pump_direction = 0; external_pressure_bound = 0; internal_pressure_bound = 2000; pressure_checks = 2; external_pressure_bound_default = 0; internal_pressure_bound_default = 2000; pressure_checks_default = 2; frequency = 1443},/turf/simulated/floor/reinforced/nitrogen,/area/ship/scrap/maintenance/atmos) +"jG" = (/obj/machinery/meter,/obj/effect/floor_decal/corner/red{dir = 9},/obj/machinery/atmospherics/pipe/manifold/visible/cyan{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"jH" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/obj/machinery/portable_atmospherics/powered/pump/filled,/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"jI" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/machinery/atmospherics/valve/shutoff,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jJ" = (/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction,/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/engine/aft) +"jK" = (/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/machinery/meter/turf,/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 6},/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/engine/aft) +"jL" = (/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 4},/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/machinery/atmospherics/unary/outlet_injector{dir = 4; icon_state = "map_injector"; use_power = 1},/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 10},/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/engine/aft) +"jM" = (/obj/structure/window/phoronreinforced,/obj/machinery/atmospherics/binary/pump{dir = 8},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jN" = (/obj/machinery/atmospherics/pipe/simple/visible/green{icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jO" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/simple/visible/green{dir = 9; icon_state = "intact"},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jP" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/door/blast/regular/open{dir = 2; icon_state = "pdoor0"; id = "radaway"; layer = 5; opacity = 0},/obj/machinery/meter/turf,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/power) +"jQ" = (/obj/effect/floor_decal/corner/red{dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"jR" = (/obj/structure/window/reinforced{dir = 8},/obj/effect/floor_decal/corner/red/diagonal{icon_state = "corner_white_diagonal"; dir = 4},/obj/effect/floor_decal/corner/red/diagonal,/obj/machinery/meter/turf,/obj/structure/window/reinforced{dir = 2; health = 1e+007},/turf/simulated/floor/reinforced/nitrogen,/area/ship/scrap/maintenance/atmos) +"jS" = (/obj/structure/window/reinforced{dir = 4},/obj/effect/floor_decal/corner/red/diagonal{icon_state = "corner_white_diagonal"; dir = 4},/obj/effect/floor_decal/corner/red/diagonal,/obj/structure/window/reinforced{dir = 2; health = 1e+007},/turf/simulated/floor/reinforced/nitrogen,/area/ship/scrap/maintenance/atmos) +"jT" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/effect/floor_decal/corner/red{dir = 9},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"jU" = (/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"jV" = (/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/obj/machinery/meter,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"jW" = (/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/machinery/atmospherics/pipe/simple/heat_exchanging,/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/engine/aft) +"jX" = (/obj/machinery/igniter{id = "engine"},/obj/machinery/atmospherics/pipe/simple/heat_exchanging,/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/engine/aft) +"jY" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging,/turf/simulated/floor/reinforced/airless,/area/ship/scrap/maintenance/engine/aft) +"jZ" = (/obj/machinery/door/blast/regular{id = "scram"},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"ka" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"kb" = (/obj/item/device/radio/intercom{dir = 8; pixel_x = 22},/obj/machinery/light/small{dir = 4},/obj/machinery/portable_atmospherics/canister/empty,/obj/machinery/atmospherics/portables_connector,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"kc" = (/obj/machinery/power/port_gen/pacman/super/potato,/obj/structure/cable,/obj/machinery/light/small,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/power) +"kd" = (/obj/effect/floor_decal/corner/red{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"ke" = (/obj/machinery/light/small,/obj/effect/floor_decal/corner/red{dir = 5},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"kf" = (/obj/effect/floor_decal/corner/red{dir = 5},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"kg" = (/obj/effect/floor_decal/corner/red{dir = 1},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"kh" = (/obj/machinery/atmospherics/valve/open,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"ki" = (/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 8},/obj/structure/window/phoronreinforced,/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 5},/turf/simulated/floor/reinforced,/area/ship/scrap/maintenance/engine/aft) +"kj" = (/obj/structure/window/phoronreinforced,/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 9},/turf/simulated/floor/reinforced,/area/ship/scrap/maintenance/engine/aft) +"kk" = (/obj/structure/window/phoronreinforced,/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 4},/obj/machinery/atmospherics/unary/vent_pump/engine{dir = 4; external_pressure_bound = 4000; external_pressure_bound_default = 4000; icon_state = "map_vent"; pump_direction = 0; use_power = 1},/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{dir = 1},/turf/simulated/floor/reinforced,/area/ship/scrap/maintenance/engine/aft) +"kl" = (/obj/structure/window/phoronreinforced{icon_state = "phoronrwindow"; dir = 1},/obj/machinery/atmospherics/binary/pump{dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"km" = (/obj/machinery/atmospherics/pipe/simple/hidden/black{icon_state = "intact"; dir = 4},/obj/machinery/meter,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"kn" = (/obj/machinery/atmospherics/omni/filter{tag_east = 2; tag_north = 6; tag_south = 5; tag_west = 1; use_power = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"ko" = (/obj/machinery/atmospherics/pipe/simple/hidden/black{icon_state = "intact"; dir = 4},/turf/simulated/wall,/area/ship/scrap/maintenance/power) +"kp" = (/obj/machinery/atmospherics/pipe/simple/hidden/black{icon_state = "intact"; dir = 10},/turf/simulated/wall,/area/ship/scrap/maintenance/power) +"kq" = (/obj/structure/grille/broken,/obj/structure/lattice,/turf/space,/area/space) +"ks" = (/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{dir = 8},/obj/machinery/space_heater,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"kt" = (/obj/machinery/pipedispenser,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{dir = 8},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"ku" = (/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 5},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"kv" = (/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"kw" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"kx" = (/obj/machinery/atmospherics/pipe/manifold/visible/fuel,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"ky" = (/obj/machinery/atmospherics/valve/open{icon_state = "map_valve1"; dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"kz" = (/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 10},/obj/machinery/meter,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"kA" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/canister/empty,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"kB" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; external_pressure_bound = 140; external_pressure_bound_default = 140; icon_state = "map_vent_out"; pressure_checks = 1; pressure_checks_default = 1; use_power = 1},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"kD" = (/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 6},/turf/simulated/floor,/area/ship/scrap/maintenance/engine/aft) +"kE" = (/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/manifold/visible/fuel{icon_state = "map"; dir = 1},/turf/simulated/floor,/area/ship/scrap/maintenance/engine/aft) +"kF" = (/obj/structure/window/reinforced,/obj/machinery/atmospherics/pipe/manifold/visible/fuel{icon_state = "map"; dir = 1},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor,/area/ship/scrap/maintenance/engine/aft) +"kG" = (/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/manifold/visible/fuel{icon_state = "map"; dir = 4},/turf/simulated/floor,/area/ship/scrap/maintenance/engine/aft) +"kH" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/light/small,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"kI" = (/obj/machinery/atmospherics/unary/engine{icon_state = "nozzle"; dir = 1},/turf/simulated/floor,/area/ship/scrap/maintenance/engine/aft) +"lb" = (/obj/machinery/light,/obj/machinery/newscaster{pixel_y = -32},/obj/item/modular_computer/console/preset/command,/obj/machinery/firealarm{dir = 4; pixel_x = 24; pixel_y = 0},/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/bridge) +"lc" = (/obj/machinery/access_button/airlock_exterior{frequency = 1383; master_tag = "bearcat_dock_port"; pixel_x = -18; pixel_y = 20},/obj/machinery/door/airlock/external/bolted/cycling{frequency = 1383; id_tag = "dock_port_out"},/obj/machinery/shield_diffuser,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"ld" = (/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/obj/machinery/power/apc/high{dir = 8},/obj/structure/cable,/obj/item/device/radio/intercom{dir = 4; pixel_x = -22},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"lx" = (/obj/structure/shuttle/engine/propulsion/burst/right,/turf/simulated/floor/airless,/area/ship/scrap/shuttle/outgoing) +"mb" = (/turf/simulated/wall/r_wall,/area/ship/scrap/garden) +"mc" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/machinery/door/airlock/autoname/engineering,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/port) +"md" = (/obj/machinery/light/small,/obj/effect/floor_decal/industrial/warning,/obj/machinery/firealarm{dir = 8; pixel_x = -24; pixel_y = 0},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/aft) +"nb" = (/turf/simulated/wall,/area/ship/scrap/garden) +"nc" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1383; id_tag = "dock_port_pump"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"nu" = (/obj/structure/shuttle/engine/propulsion/burst/right{dir = 1},/turf/simulated/floor/airless,/area/ship/scrap/shuttle/outgoing) +"ob" = (/obj/machinery/computer/shuttle_control/explore/bearcat,/obj/effect/shuttle_landmark/docking_arm_port/shuttle,/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/outgoing) +"oc" = (/obj/machinery/light{dir = 1},/obj/machinery/airlock_sensor{frequency = 1383; id_tag = "dock_port_sensor"; pixel_y = 36},/obj/machinery/embedded_controller/radio/airlock/docking_port{frequency = 1383; id_tag = "bearcat_dock_port"; pixel_y = 25; tag_airpump = "dock_port_pump"; tag_chamber_sensor = "dock_port_sensor"; tag_exterior_door = "dock_port_out"; tag_interior_door = "dock_port_in"},/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"oo" = (/obj/machinery/light,/obj/machinery/optable,/obj/item/weapon/reagent_containers/food/drinks/coffeecup/britcup,/obj/item/weapon/reagent_containers/glass/rag,/obj/machinery/oxygen_pump/anesthetic{pixel_y = -32},/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/medbay) +"oW" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/dock) +"pb" = (/obj/machinery/seed_storage/garden,/turf/simulated/floor/tiled,/area/ship/scrap/garden) +"pc" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/machinery/access_button/airlock_interior{frequency = 1383; master_tag = "bearcat_dock_port"; pixel_x = 12; pixel_y = 20},/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/obj/machinery/door/airlock/external/bolted/cycling{frequency = 1383; id_tag = "dock_port_in"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"pT" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/item/device/radio/intercom{pixel_y = 32},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 5},/obj/structure/closet/toolcloset,/obj/item/weapon/storage/backpack/dufflebag/eng,/obj/item/stack/material/glass/reinforced/fifty,/obj/item/stack/material/steel/fifty,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"qb" = (/obj/effect/decal/cleanable/cobweb2,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/obj/machinery/alarm{pixel_y = 25},/obj/machinery/biogenerator,/turf/simulated/floor/tiled,/area/ship/scrap/garden) +"qc" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/firealarm{dir = 4; pixel_x = 24; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"qE" = (/obj/machinery/atmospherics/omni/mixer{active_power_usage = 7500; tag_east = 0; tag_east_con = 0; tag_north = 1; tag_north_con = 0.21; tag_south = 1; tag_south_con = 0.79; tag_west = 2; use_power = 1},/obj/effect/floor_decal/corner/white{icon_state = "corner_white"; dir = 9},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"qO" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/industrial/outline/yellow,/obj/item/modular_computer/console/preset/merchant,/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"qT" = (/obj/machinery/door/blast/regular{id = "sensor"},/turf/simulated/floor/airless,/area/ship/scrap/comms) +"ra" = (/obj/structure/grille,/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/command/bridge) +"rb" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor,/area/ship/scrap/garden) +"rc" = (/obj/structure/closet/walllocker/emerglocker/south,/obj/item/device/radio/intercom{dir = 4; pixel_x = -22},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"sb" = (/obj/effect/floor_decal/corner/blue{dir = 1},/obj/effect/floor_decal/corner/yellow{dir = 8},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled,/area/ship/scrap/garden) +"sc" = (/obj/machinery/light_switch{pixel_x = 28},/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"sf" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/crew/hallway/port) +"sl" = (/obj/machinery/atmospherics/unary/engine{icon_state = "nozzle"; dir = 1},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/starboard) +"sB" = (/obj/effect/floor_decal/industrial/warning,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/sign/warning/fall{pixel_x = -32},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"tb" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/crew/hallway/port) +"tc" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/firealarm{dir = 8; pixel_x = -24; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"ub" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/garden) +"uc" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/effect/floor_decal/industrial/outline/yellow,/obj/item/device/radio/intercom{dir = 1; pixel_y = -22},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"vb" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled,/area/ship/scrap/garden) +"vc" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/item/device/radio/intercom{dir = 1; pixel_y = -22},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"vu" = (/obj/machinery/computer/sensors,/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/bridge) +"vD" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/command/bridge) +"vL" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"vW" = (/obj/structure/table/standard,/obj/random/smokes,/obj/item/weapon/material/ashtray/glass,/obj/effect/landmark{name = "Observer-Start"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/item/weapon/board,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"wb" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/door/airlock/maintenance_hatch{name = "Garden"; normalspeed = 0},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/tiled,/area/ship/scrap/garden) +"wc" = (/obj/machinery/portable_atmospherics/canister/air/airlock{start_pressure = 730},/obj/machinery/atmospherics/portables_connector{dir = 1},/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"wB" = (/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"xb" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/ship/scrap/shuttle/outgoing) +"xc" = (/obj/machinery/power/apc{dir = 1; name = "Crew Areas APC"},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/structure/bed/chair,/obj/machinery/firealarm{pixel_y = 24},/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"xZ" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4; layer = 2.4; level = 2},/obj/machinery/computer/engines,/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/bridge) +"yb" = (/turf/simulated/floor/tiled,/area/ship/scrap/garden) +"yc" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/item/device/radio/intercom{dir = 4; pixel_x = -22},/obj/structure/closet/wardrobe/pjs,/obj/structure/sign/poster{pixel_y = 32},/obj/machinery/firealarm{pixel_y = 24},/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/cryo) +"yg" = (/obj/machinery/computer/helm,/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/bluegrid,/area/ship/scrap/command/bridge) +"yS" = (/obj/structure/closet/crate,/obj/random/coin,/obj/item/weapon/spacecash/bundle/c1000,/turf/simulated/floor/plating,/area/ship/scrap/hidden) +"zb" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1383; id_tag = "bearcat_shuttle_pump_out_external"},/turf/simulated/floor/airless,/area/ship/scrap/shuttle/outgoing) +"zc" = (/obj/machinery/shower{icon_state = "shower"; dir = 4},/obj/structure/window/reinforced/tinted{icon_state = "twindow"; dir = 4},/obj/structure/window/reinforced/tinted,/obj/structure/curtain/open/shower,/obj/machinery/firealarm{dir = 8; pixel_x = -24; pixel_y = 0},/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/toilets) +"zs" = (/obj/machinery/shipsensors,/turf/simulated/floor/airless,/area/ship/scrap/comms) +"zv" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/lattice,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/dock) +"Ab" = (/obj/machinery/atmospherics/pipe/simple/visible/red{icon_state = "intact"; dir = 6},/obj/effect/floor_decal/corner/blue,/obj/structure/fireaxecabinet{pixel_y = 32},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"Ac" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/ladder,/obj/item/device/radio/intercom{dir = 1; pixel_y = -22},/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"Ah" = (/obj/structure/table/standard,/obj/machinery/light{icon_state = "tube1"; dir = 1},/obj/item/weapon/deck/tarot,/obj/machinery/cell_charger,/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/outgoing) +"AB" = (/obj/machinery/door/firedoor,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/obj/machinery/door/airlock/autoname/engineering,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engine/aft) +"Bb" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock/autoname/command,/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/captain) +"Bc" = (/obj/structure/table/standard,/obj/machinery/reagentgrinder,/obj/effect/floor_decal/corner/red/diagonal,/obj/structure/sign/monkey_painting{pixel_y = 32},/obj/machinery/firealarm{dir = 8; pixel_x = -24; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/crew/kitchen) +"Bg" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/airlock/autoname/command,/turf/simulated/floor/tiled/dark,/area/ship/scrap/dock) +"BD" = (/obj/structure/table/standard,/obj/item/device/multitool{pixel_x = 5},/obj/item/weapon/cartridge/atmos,/obj/item/weapon/cartridge/atmos,/obj/item/device/pipe_painter,/obj/item/clamp,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"Cb" = (/obj/machinery/atmospherics/pipe/simple/visible/green{dir = 6},/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/closet/firecloset/full,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"Cc" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/obj/effect/floor_decal/corner/red/diagonal,/obj/machinery/vending/dinnerware,/obj/item/device/radio/intercom{pixel_y = 22},/turf/simulated/floor/tiled,/area/ship/scrap/crew/kitchen) +"Cq" = (/obj/structure/table/standard,/obj/machinery/button/remote/blast_door{id = "scraplock"; name = "External Lockdown"},/obj/random_multi/single_item/captains_spare_id,/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/bridge) +"CG" = (/obj/structure/table/standard,/obj/item/toy/figure/captain,/obj/machinery/button/remote/blast_door{id = "sensor"; name = "Sensor Shroud"},/obj/item/device/radio,/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/bridge) +"Db" = (/obj/effect/floor_decal/corner/white{icon_state = "corner_white"; dir = 9},/obj/machinery/atmospherics/pipe/simple/visible/cyan,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"Dc" = (/obj/structure/closet/walllocker/emerglocker/north,/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/effect/floor_decal/corner/red/diagonal,/obj/machinery/cooker/oven,/turf/simulated/floor/tiled,/area/ship/scrap/crew/kitchen) +"Dl" = (/obj/machinery/power/apc{name = "Medical Bay APC"},/obj/structure/cable,/obj/machinery/icecream_vat,/turf/simulated/floor,/area/ship/scrap/unused) +"DL" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/machinery/power/apc{dir = 8},/obj/structure/cable{d2 = 6; icon_state = "0-6"},/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/bridge) +"DO" = (/turf/simulated/wall/r_wall,/area/ship/scrap/command/bridge) +"Eb" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/structure/window/reinforced{dir = 8},/obj/machinery/power/apc{dir = 1; name = "Communications APC"},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/light_switch{pixel_x = 28},/obj/machinery/atmospherics/unary/vent_scrubber/on,/obj/machinery/firealarm{dir = 4; pixel_x = 24; pixel_y = 0},/turf/simulated/floor/tiled/dark,/area/ship/scrap/comms) +"Ec" = (/obj/structure/closet/crate,/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/random/shoes,/obj/random/shoes,/obj/random/hat,/obj/random/hat,/obj/random/masks,/obj/machinery/firealarm{pixel_y = 24},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"EQ" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock/autoname/command,/turf/simulated/floor/tiled/dark,/area/ship/scrap/comms) +"Fb" = (/obj/effect/shuttle_landmark/lift/top,/turf/simulated/open,/area/ship/scrap/cargo) +"Fc" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/portable_atmospherics/powered/pump/filled,/obj/item/device/radio/intercom{pixel_y = 22},/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"FV" = (/obj/item/device/radio,/obj/structure/cable{icon_state = "4-9"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 6},/turf/simulated/floor/airless,/area/space) +"FW" = (/obj/structure/table/reinforced,/obj/item/device/flashlight/lamp,/obj/random_multi/single_item/captains_spare_id,/obj/item/weapon/spacecash/bundle/c1000,/obj/item/weapon/storage/bible/booze,/turf/simulated/floor/plating,/area/ship/scrap/hidden) +"Gb" = (/obj/machinery/atmospherics/omni/filter{tag_east = 1; tag_north = 4; tag_south = 3; tag_west = 2; use_power = 1},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"Gc" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/machinery/door/airlock/autoname/engineering,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/engine/starboard) +"Gv" = (/obj/machinery/door/airlock/hatch,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/outgoing) +"GT" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/command/bridge) +"Hb" = (/obj/effect/floor_decal/corner/blue,/obj/effect/floor_decal/corner/yellow{icon_state = "corner_white"; dir = 4},/obj/machinery/atmospherics/binary/passive_gate/on{dir = 1; name = "Air to Supply"},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"Hc" = (/obj/item/device/radio/intercom{pixel_y = 22},/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/item/weapon/bedsheet/medical,/obj/structure/curtain/open/privacy,/obj/structure/bed/padded,/obj/item/clothing/accessory/stethoscope,/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/medbay) +"Ib" = (/obj/machinery/atmospherics/pipe/simple/visible/green{icon_state = "intact"; dir = 5},/obj/machinery/light/small,/obj/structure/closet/walllocker/emerglocker/west,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"Ic" = (/obj/item/weapon/stool/padded,/obj/structure/sink{dir = 8; icon_state = "sink"; pixel_x = -13; pixel_y = 0},/obj/machinery/firealarm{dir = 8; pixel_x = -24; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/ship/scrap/crew/medbay) +"Ig" = (/obj/machinery/computer/account_database,/turf/simulated/floor/bluegrid,/area/ship/scrap/command/bridge) +"Jb" = (/obj/structure/table/standard,/obj/machinery/cell_charger,/obj/item/weapon/storage/toolbox/electrical{pixel_x = 7; pixel_y = 4},/obj/machinery/light_switch{pixel_y = 25},/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/structure/cable{icon_state = "6-8"},/obj/random/powercell,/obj/random/powercell,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/power) +"Jc" = (/obj/structure/closet/secure_closet/freezer/meat,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/effect/floor_decal/corner/red/diagonal,/obj/item/weapon/reagent_containers/ivbag/blood/OMinus,/obj/item/weapon/reagent_containers/ivbag/blood/OMinus,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/ship/scrap/crew/kitchen) +"Jn" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/structure/closet/emcloset,/obj/structure/sign/deck/first{pixel_x = 32},/obj/random/voidhelmet,/obj/random/voidhelmet,/obj/random/voidhelmet,/obj/random/voidsuit,/obj/random/voidsuit,/obj/random/voidsuit,/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"Jy" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/crew/hallway/starboard) +"JI" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor,/obj/structure/window/reinforced{dir = 5; health = 1e+007},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/turf/simulated/floor,/area/ship/scrap/maintenance/power) +"JR" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/machinery/newscaster{pixel_x = -32},/obj/machinery/media/jukebox,/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"Kb" = (/obj/structure/table/standard,/obj/machinery/cell_charger,/obj/item/weapon/defibrillator/compact/loaded,/obj/item/device/flashlight,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/random/powercell,/turf/simulated/floor/plating,/area/ship/scrap/maintenance/power) +"Kc" = (/obj/structure/disposalpipe/segment,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/machinery/firealarm{dir = 4; pixel_x = 24; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/port) +"KI" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/obj/machinery/light_switch{pixel_x = -25},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"KO" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/airlock/autoname/engineering,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/power) +"Lb" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 2; layer = 2.4; level = 2},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 10},/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/outgoing) +"Lc" = (/obj/effect/decal/cleanable/cobweb,/obj/effect/decal/cleanable/cobweb2,/obj/structure/cable{d1 = 32; d2 = 1; icon_state = "32-1"},/obj/structure/lattice,/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/firealarm{dir = 8; pixel_x = -24; pixel_y = 0},/turf/simulated/open,/area/ship/scrap/crew/hallway/starboard) +"LY" = (/obj/item/weapon/screwdriver,/obj/structure/cable{icon_state = "5-8"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 10},/turf/simulated/floor/airless,/area/space) +"Mb" = (/obj/structure/bed/chair/comfy/brown{icon_state = "comfychair_preview"; dir = 1},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 10},/obj/item/device/radio/intercom{dir = 8; pixel_x = 22},/obj/machinery/atmospherics/pipe/simple/hidden,/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/outgoing) +"Mc" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/item/device/radio/intercom{pixel_y = 22},/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/wash) +"Mo" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/crew/hallway/starboard) +"Mp" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/autoname/engineering,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"Mv" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/command/bridge) +"MH" = (/obj/structure/grille,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/turf/simulated/floor,/area/ship/scrap/command/bridge) +"Nb" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden,/turf/simulated/floor/plating,/area/ship/scrap/shuttle/outgoing) +"Nc" = (/obj/structure/disposalpipe/segment{icon_state = "conpipe-c"; dir = 4},/obj/machinery/power/apc{dir = 1; name = "Washroom APC"},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/machinery/firealarm{pixel_y = 24},/turf/simulated/floor/tiled/freezer,/area/ship/scrap/crew/wash) +"NH" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/dock) +"NN" = (/obj/machinery/requests_console{announcementConsole = 1; department = "Captain"; pixel_x = 32},/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/bridge) +"Ob" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/obj/item/device/radio/intercom{dir = 1; pixel_y = -22},/turf/simulated/floor/tiled/dark,/area/ship/scrap/comms) +"Oc" = (/obj/effect/decal/cleanable/cobweb2,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8; layer = 2.4; level = 2},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 10},/obj/item/device/radio/intercom{dir = 8; pixel_x = 22},/turf/simulated/floor,/area/ship/scrap/unused) +"Og" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/machinery/power/apc{dir = 4; name = "Bridge APC"},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/sign/warning/server_room{pixel_x = -32},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/hallway) +"Oi" = (/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/turf/simulated/floor/airless,/area/space) +"Oq" = (/obj/structure/bed/chair/comfy/teal{icon_state = "comfychair_teal"; dir = 1},/obj/effect/landmark/start{name = "Captain"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/bridge) +"Pb" = (/obj/item/weapon/gun/projectile/shotgun/pump/combat{desc = "When words don't strike hard enough."; name = "Solid Argument"},/obj/structure/window/reinforced/full,/obj/structure/table/marble,/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"Pc" = (/obj/structure/closet/walllocker/emerglocker/east,/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/obj/machinery/firealarm{dir = 8; pixel_x = -24; pixel_y = 0},/turf/simulated/floor/tiled,/area/ship/scrap/crew/hallway/port) +"PA" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{icon_state = "2-9"},/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/bridge) +"PE" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/obj/machinery/door/airlock/autoname/engineering,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"Qb" = (/obj/item/modular_computer/console/preset/command,/turf/simulated/floor/bluegrid,/area/ship/scrap/command/bridge) +"Qc" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 4},/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/fuel,/obj/machinery/firealarm{dir = 4; pixel_x = 24; pixel_y = 0},/turf/simulated/floor,/area/ship/scrap/crew/hallway/starboard) +"Rb" = (/obj/structure/table/woodentable,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 4; name = "Captain's Quarters APC"},/obj/item/weapon/reagent_containers/food/drinks/coffeecup/one,/obj/machinery/firealarm{dir = 1; pixel_y = -24},/obj/item/device/radio/intercom{dir = 8; pixel_x = 22},/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"Rc" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/item/weapon/stool/padded,/obj/machinery/firealarm{dir = 8; pixel_x = -24; pixel_y = 0},/turf/simulated/floor,/area/ship/scrap/unused) +"Rv" = (/obj/effect/decal/cleanable/dirt,/obj/effect/landmark/start{name = "Cargo Technician"},/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/machinery/merchant_pad,/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"RL" = (/obj/structure/closet/walllocker/emerglocker/north,/obj/structure/bed/chair/wood,/obj/item/weapon/deck/tarot,/turf/simulated/floor/tiled,/area/ship/scrap/crew/saloon) +"RW" = (/obj/machinery/atmospherics/unary/engine{icon_state = "nozzle"; dir = 1},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/port) +"Sb" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 5},/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"Sc" = (/obj/effect/decal/cleanable/cobweb,/obj/effect/floor_decal/corner/blue{dir = 1},/obj/effect/floor_decal/corner/yellow{dir = 8},/obj/machinery/portable_atmospherics/hydroponics,/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/item/device/radio/intercom{pixel_y = 22},/turf/simulated/floor/tiled,/area/ship/scrap/garden) +"SB" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/obj/structure/sign/warning/hot_exhaust{pixel_y = 32},/turf/simulated/floor/airless,/area/ship/scrap/maintenance/engine/aft) +"Tb" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/structure/closet/crate,/obj/item/device/radio,/obj/item/device/spaceflare,/obj/machinery/firealarm{dir = 4; pixel_x = 24; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden{dir = 10; icon_state = "intact"},/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"Tc" = (/obj/structure/closet/crate,/obj/random/loot,/obj/random/loot,/obj/item/weapon/disk/tech_disk,/obj/item/weapon/disk/tech_disk,/obj/item/weapon/disk/design_disk,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/obj/machinery/firealarm{pixel_y = 24},/turf/simulated/floor/plating,/area/ship/scrap/hidden) +"Tl" = (/obj/machinery/light_switch{pixel_x = 28},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/airlock/autoname/command,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/bridge) +"Ub" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/item/weapon/storage/backpack/dufflebag,/obj/machinery/atmospherics/pipe/simple/hidden,/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"Uc" = (/obj/effect/floor_decal/corner/blue{dir = 1},/obj/effect/floor_decal/corner/yellow{dir = 8},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/machinery/portable_atmospherics/hydroponics,/obj/machinery/firealarm{dir = 8; pixel_x = -24; pixel_y = 0},/obj/machinery/light/small{dir = 2; icon_state = "bulb1"},/turf/simulated/floor/tiled,/area/ship/scrap/garden) +"Uv" = (/obj/structure/window/reinforced{dir = 8},/obj/structure/lattice,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/space,/area/ship/scrap/dock) +"Vb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 9},/obj/item/device/radio/intercom{dir = 4; pixel_x = -22},/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/outgoing) +"Vc" = (/obj/structure/cable,/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/item/weapon/reagent_containers/glass/bucket,/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/tiled,/area/ship/scrap/garden) +"Wb" = (/obj/effect/floor_decal/corner/beige{icon_state = "corner_white"; dir = 6},/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden,/turf/simulated/floor/tiled,/area/ship/scrap/shuttle/outgoing) +"Wc" = (/obj/machinery/light/small,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{icon_state = "4-9"},/obj/machinery/atmospherics/pipe/simple/hidden/fuel{icon_state = "intact"; dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/hallway) +"Wp" = (/obj/machinery/cryopod/lifepod,/obj/machinery/door/window/southright,/obj/machinery/computer/cryopod{pixel_x = 32},/turf/simulated/floor/wood,/area/ship/scrap/command/captain) +"WE" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/door/airlock/autoname/engineering,/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"WT" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/machinery/door/firedoor,/obj/machinery/door/blast/regular{density = 0; dir = 4; icon_state = "pdoor0"; id = "scraplock"; name = "External Blast Doors"; opacity = 0},/turf/simulated/floor,/area/ship/scrap/command/bridge) +"Xb" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden,/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"Xc" = (/obj/machinery/atmospherics/binary/pump/on{dir = 8; target_pressure = 101.325},/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/obj/effect/floor_decal/corner/blue{dir = 10},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/atmos) +"Xl" = (/obj/machinery/atm{pixel_y = 25},/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -24},/turf/simulated/floor/tiled,/area/ship/scrap/dock) +"Xu" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/bridge) +"XR" = (/obj/effect/floor_decal/industrial/outline/yellow,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/item/weapon/stool/padded,/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"Ya" = (/obj/effect/decal/cleanable/dirt,/obj/effect/floor_decal/industrial/outline/yellow,/obj/effect/floor_decal/industrial/warning,/obj/machinery/computer/shuttle_control/lift,/turf/simulated/floor/tiled,/area/ship/scrap/cargo) +"Yb" = (/obj/machinery/door/airlock/glass_external/bolted/cycling{frequency = 1383; id_tag = "bearcat_shuttle_in"},/obj/structure/cable{icon_state = "4-10"},/obj/machinery/access_button/airlock_interior{frequency = 1383; master_tag = "bearcat_shuttle"; pixel_x = -12; pixel_y = 20},/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"Yc" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/power/apc{dir = 1},/obj/structure/sign/warning/compressed_gas{pixel_x = -32},/obj/structure/bed/padded,/obj/effect/landmark/start{name = "Chief Engineer"},/obj/machinery/firealarm{pixel_y = 24},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/engineering) +"YE" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/dark,/area/ship/scrap/command/bridge) +"Za" = (/obj/machinery/power/breakerbox/activated,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/ship/scrap/maintenance/power) +"Zb" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{frequency = 1383; id_tag = "bearcat_shuttle_pump"},/obj/machinery/embedded_controller/radio/airlock/docking_port{cycle_to_external_air = 1; frequency = 1383; id_tag = "bearcat_shuttle"; pixel_x = 0; pixel_y = -24; tag_airpump = "bearcat_shuttle_pump"; tag_chamber_sensor = "bearcat_shuttle_sensor"; tag_exterior_door = "bearcat_shuttle_out"; tag_interior_door = "bearcat_shuttle_in"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor,/area/ship/scrap/shuttle/outgoing) +"Zc" = (/obj/structure/closet/secure_closet/engineering_electrical,/obj/item/weapon/cell/device/standard,/obj/item/weapon/cell/device/standard,/obj/machinery/power/apc{dir = 8},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/item/device/radio/intercom{pixel_y = 22},/turf/simulated/floor/tiled,/area/ship/scrap/maintenance/power) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaMvvDWTvDraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaGTIgygQbGTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaGTCGOqCqGTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaMHxZXuvuMHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajakaaaaawqTDODLYENNDOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaawzsDObbPAlbDOarasaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaatauauavaaaaaaaaawawaxawawTlasasWpasasaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAhobxbzbaaaaaaawaDaEEbawOgasaHaIaJasaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaLLbMbaLnuaaaaaaaOaPaEaQEQaSBbaUaVaWaXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLaLGvNbaLaLaaaaaaawbaaEObawbcasPbbeRbasaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLbgbhSbTbaLaaaaaaawawaxawawbcasasbkasasaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZbibhbiUbaZaaaaaaaaaaaabmbmBgbmbmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLVbbpbqWbaLaaaaaabmbsbtbmXlbvbwbmbsbtbmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLbxaLbyXbaLbAbmbmbmbBbCbDbEbFbEbDbGbHbmbmbmbAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLbxYbZbacjclcncocpcbQqcbmrcbTscbmtcbWbXbYbZcaaacbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLccaLcdaLaLcececfcgchucbmbmcjbmbmvcclcmcncoceaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLcpcqwccsaLaaaactbmcubmbmzvcwUvbmbmcubmctcycyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLczcAcBcCaLaaaacytbcEsfaaoWcwNHaaMocGJycyaacyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLaLcHcIaLaLaaaacytbcEcJcJcJcKcJcJcJcLJycyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahbaLaLaLaLlxaaaacytbcEcNcOxccQRLcScNcGJycyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacycTcUcVcUcUcWcNJRcYcZdadbcNdcdddedfdgddaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacTdhdidjcTdkcNdldmvWdmJncNdpdeycdrdsddaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadtdudvdwdxdydzdAdBdCdDdEdzdFdGdHdIdJdKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacUzcdMdNcTdOdPdQjbdSAcdUcNdVdedWdXdJddaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadYdZdZdZdZeaebebebecebebebedeeeeefeeevaaaaaaehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaehehaaaaaadYBcCcDcdZelebEcFceoqORvebereeesetHcevaaaaehewehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaehewexexcycyeyezeAeBdZeCebeDeEeFXReHebeIeJIceLeMevcycyeNeNehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaehexexexexcyeOePeQeReSeTeUeVeWeXeYeZeUfafbfcfdfeffcyeNeNeNeNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaexfgfhmcLYdZfkJcfmdZfnebKIfpfqfrfsebfteefuoofwevFVGcfzfAeNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaexfBfCexfDfEfEfEfEfEKcebsBYafIfJfKebLceeeeeveeevfMfNfOfPeNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafQRWRWfQOifTfUMcNcfXfYebfZfZfZfZgaebgbgcgdgeOcggOighslslgjaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagkaaaaglgmgngogpgqfEgrebfZFbfZfZgsebgtgugvgwgxgygzglaaaagkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacycyfEgAgBgCfEPcebfZfZfZfZgEebQcguRcDlgIgucyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaambnbnbmbmbgLebfZfZfZfZgMgNgOgPgQgQgQgPcyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaambScpbqbmbgUebfZfZgVgWgXebgYgPTchaySgPcyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahcrbsbubvbwbhiebebebecebebebhjhkhlhmFWgPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaambUcybVcnbhrWchthuhvhwhxhyhzgPhAhBhCgPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahDhDhDMphFhFhFhGhHhGPEhGhGhGhJhJhJhKhLgPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacyhDAbXchOhPhQhFYchSpThUhVhWhXhJZcJbKbhLcyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacyhDhDibicidieifWEihiiijikililimKOioipiqhLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacyhDCbisitiuivadhDixiyiziAiBiCiDhJiEiFZaJIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiIiJiKiLiMDbbdhDABiQiQiRiQiQiQhLhdiTiUhLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiViWGbiYiZjaqEHbhDjdjejfjgjhjijjhJjkjljmhLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajniJjojpjqjrjshDldjujvjwjxjyjzhLhLjAhLhLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajBcyhDIbjDjEjFjGjHhDjIjJjKjLjMjNjOhLhLjPhLhLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajBaahDhDjQjRjSjTjUhDjVjWjXjYjZkakbhLhLkchLhLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajBcycyhDkdkekfkgjUhDkhkikjkkklkmknkokphLhLhLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaakqaaaahDhDhDBDkskthDkukvkwkxkykzkAjZkBcyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajBcyaahDhDhDhDiQmdkDkEkFkFkGkHjZcyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajBkqaacyaacycyiQiQkIkIkIkIkIiQiQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaajBkqjBaaaaSBwBwBwBwBwBSBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaavLwBwBwBwBwBvLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/overmap_example/bearcat/bearcat.dm b/maps/overmap_example/bearcat/bearcat.dm new file mode 100644 index 00000000..33d066b5 --- /dev/null +++ b/maps/overmap_example/bearcat/bearcat.dm @@ -0,0 +1,109 @@ +#include "bearcat_areas.dm" +#include "bearcat_jobs.dm" +#include "bearcat_loadouts.dm" +#include "bearcat-1.dmm" +#include "bearcat-2.dmm" + +/obj/effect/overmap/ship/bearcat + name = "FTV Bearcat" + color = "#00ffff" + start_x = 4 + start_y = 4 + base = 1 + vessel_mass = 60 + default_delay = 3 MINUTES + speed_mod = 0.1 MINUTE + burn_delay = 10 SECONDS + + generic_waypoints = list("nav_bearcat_below_bow", "nav_bearcat_below_starboardastern", "nav_bearcat_port_dock_shuttle") + restricted_waypoints = list( + "Exploration Pod" = list("nav_bearcat_starboard_dock_pod"), //pod can only dock starboard-side, b/c there's only one door. + ) + +/obj/machinery/computer/shuttle_control/explore/bearcat + name = "exploration shuttle console" + shuttle_tag = "Exploration Shuttle" + +/datum/shuttle/autodock/overmap/exploration + name = "Exploration Shuttle" + shuttle_area = /area/ship/scrap/shuttle/outgoing + dock_target = "bearcat_shuttle" + current_location = "nav_bearcat_port_dock_shuttle" + +/datum/shuttle/autodock/ferry/lift + name = "Cargo Lift" + shuttle_area = /area/ship/scrap/shuttle/lift + warmup_time = 3 //give those below some time to get out of the way + waypoint_station = "nav_bearcat_lift_bottom" + waypoint_offsite = "nav_bearcat_lift_top" + sound_takeoff = 'sound/effects/lift_heavy_start.ogg' + sound_landing = 'sound/effects/lift_heavy_stop.ogg' + ceiling_type = null + knockdown = 0 + +/obj/machinery/computer/shuttle_control/lift + name = "cargo lift controls" + shuttle_tag = "Cargo Lift" + ui_template = "shuttle_control_console_lift.tmpl" + icon_state = "tiny" + icon_keyboard = "tiny_keyboard" + icon_screen = "lift" + density = 0 + +//In case multiple shuttles can dock at a location, +//subtypes can be used to hold the shuttle-specific data +/obj/effect/shuttle_landmark/docking_arm_starboard + name = "Bearcat Starboard-side Docking Arm" + docking_controller = "bearcat_starboard_dock" + +/obj/effect/shuttle_landmark/docking_arm_starboard/pod + landmark_tag = "nav_bearcat_starboard_dock_pod" + +/obj/effect/shuttle_landmark/docking_arm_port + name = "Bearcat Port-side Docking Arm" + docking_controller = "bearcat_dock_port" + +/obj/effect/shuttle_landmark/docking_arm_port/shuttle + landmark_tag = "nav_bearcat_port_dock_shuttle" + +/obj/effect/shuttle_landmark/lift/top + name = "Top Deck" + landmark_tag = "nav_bearcat_lift_top" + autoset = 1 + +/obj/effect/shuttle_landmark/lift/bottom + name = "Lower Deck" + landmark_tag = "nav_bearcat_lift_bottom" + base_area = /area/ship/scrap/cargo/lower + base_turf = /turf/simulated/floor + +/obj/effect/shuttle_landmark/below_deck_bow + name = "Near CSV Bearcat Bow" + landmark_tag = "nav_bearcat_below_bow" + +/obj/effect/shuttle_landmark/below_deck_starboardastern + name = "Near CSV Bearcat Starboard Astern" + landmark_tag = "nav_bearcat_below_starboardastern" + +/turf/simulated/wall //landlubbers go home + name = "bulkhead" + +/turf/simulated/floor + name = "bare deck" + +/turf/simulated/floor/tiled + name = "deck" + +/decl/flooring/tiling + name = "deck" + +/obj/machinery/door/airlock/autoname/command + icon = 'icons/obj/doors/Doorhatchele.dmi' + req_access = list(access_heads) + +/obj/machinery/door/airlock/autoname/engineering + req_access = list(access_engine) + +//wild capitalism +/datum/computer_file/program/merchant + required_access = null \ No newline at end of file diff --git a/maps/overmap_example/bearcat/bearcat_areas.dm b/maps/overmap_example/bearcat/bearcat_areas.dm new file mode 100644 index 00000000..9bf35754 --- /dev/null +++ b/maps/overmap_example/bearcat/bearcat_areas.dm @@ -0,0 +1,172 @@ +/area/ship/scrap + name = "\improper Generic Ship" + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg') + +/area/ship/scrap/crew + name = "\improper Crew Compartements" + icon_state = "crew_quarters" + +/area/ship/scrap/crew/hallway/port + name = "\improper Crew Hallway - Port" + +/area/ship/scrap/crew/hallway/starboard + name = "\improper Crew Hallway - Starboard" + +/area/ship/scrap/crew/kitchen + name = "\improper Galley" + icon_state = "kitchen" + +/area/ship/scrap/crew/cryo + name = "\improper Cryo Storage" + icon_state = "cryo" + +/area/ship/scrap/crew/dorms1 + name = "\improper Crew Cabin #1" + icon_state = "green" + +/area/ship/scrap/crew/dorms2 + name = "\improper Crew Cabin #2" + icon_state = "purple" + +/area/ship/scrap/crew/dorms3 + name = "\improper Crew Cabin #3" + icon_state = "yellow" + +/area/ship/scrap/crew/saloon + name = "\improper Saloon" + icon_state = "conference" + +/area/ship/scrap/crew/toilets + name = "\improper Bathrooms" + icon_state = "toilet" + turf_initializer = /decl/turf_initializer/maintenance + +/area/ship/scrap/crew/wash + name = "\improper Washroom" + icon_state = "locker" + +/area/ship/scrap/crew/medbay + name = "\improper Medical Bay" + icon_state = "medbay" + +/area/ship/scrap/cargo + name = "\improper Cargo Hold" + icon_state = "quartstorage" + +/area/ship/scrap/cargo/lower + name = "\improper Lower Cargo Hold" + +/area/ship/scrap/dock + name = "\improper Docking Bay" + icon_state = "entry_1" + +/area/ship/scrap/garden + name = "\improper Garden" + icon_state = "green" + +/area/ship/scrap/unused + name = "\improper Compartment 2-B" + icon_state = "yellow" + turf_initializer = /decl/turf_initializer/maintenance + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambimo1.ogg','sound/ambience/ambimo2.ogg') + +/area/ship/scrap/hidden + name = "\improper Unknown" //shielded compartment + icon_state = "auxstorage" + +/area/ship/scrap/escape_port + name = "\improper Port Escape Pods" + icon_state = "green" + +/area/ship/scrap/escape_star + name = "\improper Starboard Escape Pods" + icon_state = "yellow" + +/area/ship/scrap/broken1 + name = "\improper Robotic Maintenance" + icon_state = "green" + +/area/ship/scrap/broken2 + name = "\improper Compartment 1-B" + icon_state = "yellow" + +/area/ship/scrap/gambling + name = "\improper Compartment 1-C" + icon_state = "cave" + +/area/ship/scrap/maintenance + name = "\improper Maintenance Compartments" + icon_state = "amaint" + +/area/ship/scrap/maintenance/hallway + name = "\improper Maintenance Corridors" + +/area/ship/scrap/maintenance/lower + name = "\improper Lower Deck Maintenance Compartments" + icon_state = "sub_maint_aft" + area_flags = AREA_FLAG_RAD_SHIELDED + +/area/ship/scrap/maintenance/storage + name = "\improper Tools Storage" + icon_state = "engineering_storage" + +/area/ship/scrap/maintenance/techstorage + name = "\improper Parts Storage" + icon_state = "engineering_supply" + +/area/ship/scrap/maintenance/eva + name = "\improper EVA Storage" + icon_state = "eva" + +/area/ship/scrap/maintenance/engineering + name = "\improper Engineering Bay" + icon_state = "engineering_supply" + +/area/ship/scrap/maintenance/atmos + name = "\improper Atmospherics Comparment" + icon_state = "atmos" + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambiatm1.ogg') + +/area/ship/scrap/maintenance/power + name = "\improper Power Compartment" + icon_state = "engine_smes" + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambieng1.ogg') + +/area/ship/scrap/maintenance/engine + icon_state = "engine" + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambieng1.ogg') + +/area/ship/scrap/maintenance/engine/aft + name = "\improper Main Engine Bay" + +/area/ship/scrap/maintenance/engine/port + name = "\improper Port Thruster" + +/area/ship/scrap/maintenance/engine/starboard + name = "\improper Starboard Thruster" + +/area/ship/scrap/command/hallway + name = "\improper Command Deck" + icon_state = "centcom" + +/area/ship/scrap/command/bridge + name = "\improper Bridge" + icon_state = "bridge" + +/area/ship/scrap/command/captain + name = "\improper Captain's Quarters" + icon_state = "captain" + +/area/ship/scrap/comms + name = "\improper Communications Relay" + icon_state = "tcomsatcham" + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/signal.ogg','sound/ambience/sonar.ogg') + +/area/ship/scrap/shuttle/outgoing + name = "\improper Exploration Shuttle" + icon_state = "tcomsatcham" + +/area/ship/scrap/shuttle/lift + name = "\improper Cargo Lift" + icon_state = "shuttle3" + base_turf = /turf/simulated/open \ No newline at end of file diff --git a/maps/overmap_example/bearcat/bearcat_jobs.dm b/maps/overmap_example/bearcat/bearcat_jobs.dm new file mode 100644 index 00000000..35032276 --- /dev/null +++ b/maps/overmap_example/bearcat/bearcat_jobs.dm @@ -0,0 +1,174 @@ +/datum/map/overmap_example + allowed_jobs = list(/datum/job/captain, /datum/job/chief_engineer, /datum/job/doctor, /datum/job/hop, /datum/job/cyborg, /datum/job/assistant, /datum/job/engineer) + species_to_job_whitelist = list( + /datum/species/vox = list(/datum/job/assistant) + ) + +/datum/job/captain + supervisors = "the Merchant Code and your conscience" + outfit_type = /decl/hierarchy/outfit/job/bearcat/captain + +/datum/job/captain/equip(var/mob/living/carbon/human/H) + . = ..() + if(H.client) + H.client.verbs += /client/proc/rename_ship + H.client.verbs += /client/proc/rename_company + +/client/proc/rename_ship() + set name = "Rename Ship" + set category = "Captain's Powers" + + var/ship = sanitize(input(src, "What is your ship called? Don't add the vessel prefix, the FTV one will be attached automatically.", "Ship name", GLOB.using_map.station_short), MAX_NAME_LEN) + if(!ship) + return + GLOB.using_map.station_short = ship + GLOB.using_map.station_name = "FTV [ship]" + var/obj/effect/overmap/ship/bearcat/B = locate() in world + if(B) + B.SetName(GLOB.using_map.station_name) + command_announcement.Announce("Attention all hands on [GLOB.using_map.station_name]! Thank you for your attention.", "Ship re-christened") + verbs -= /client/proc/rename_ship + +/client/proc/rename_company() + set name = "Rename Company" + set category = "Captain's Powers" + var/company = sanitize(input(src, "What should your enterprise be called?", "Company name", GLOB.using_map.company_name), MAX_NAME_LEN) + if(!company) + return + var/company_s = sanitize(input(src, "What's the short name for it?", "Company name", GLOB.using_map.company_short), MAX_NAME_LEN) + if(company != GLOB.using_map.company_name) + if (company) + GLOB.using_map.company_name = company + if(company_s) + GLOB.using_map.company_short = company_s + command_announcement.Announce("Congratulations to all employees of [capitalize(GLOB.using_map.company_name)] on the new name. Their rebranding has changed the [GLOB.using_map.company_short] market value by [0.01*rand(-10,10)]%.", "Company name change approved") + verbs -= /client/proc/rename_company + +/datum/job/captain/get_access() + return get_all_station_access() + +/datum/job/chief_engineer + title = "Chief Engineer" + supervisors = "the Captain" + department_flag = ENG + outfit_type = /decl/hierarchy/outfit/job/bearcat/chief_engineer + +/datum/job/doctor + title = "Doc" + supervisors = "the Captain and your idea of Hippocratic Oath" + outfit_type = /decl/hierarchy/outfit/job/bearcat/doc + alt_titles = list( + "Surgeon") + total_positions = 1 + spawn_positions = 1 + hud_icon = "hudmedicaldoctor" + +/datum/job/hop + title = "First Mate" + supervisors = "the Captain and the Merchant Code" + outfit_type = /decl/hierarchy/outfit/job/bearcat/mate + hud_icon = "hudheadofpersonnel" + +/datum/job/assistant + title = "Deck Hand" + supervisors = "literally everyone, you bottom feeder" + outfit_type = /decl/hierarchy/outfit/job/bearcat/hand + alt_titles = list( + "Cook" = /decl/hierarchy/outfit/job/bearcat/hand/cook, + "Cargo Hand", + "Passenger") + hud_icon = "hudcargotechnician" + +/datum/job/engineer + title = "Junior Engineer" + supervisors = "Chief Engineer" + total_positions = 2 + spawn_positions = 2 + hud_icon = "hudengineer" + +/datum/job/cyborg + supervisors = "your laws and the Captain" + outfit_type = /decl/hierarchy/outfit/job/bearcat/hand/engine + total_positions = 1 + spawn_positions = 1 + + +// OUTFITS +#define BEARCAT_OUTFIT_JOB_NAME(job_name) ("Bearcat - Job - " + job_name) + +/decl/hierarchy/outfit/job/bearcat/ + hierarchy_type = /decl/hierarchy/outfit/job/bearcat + pda_type = /obj/item/device/pda + pda_slot = slot_l_store + l_ear = null + r_ear = null + +/decl/hierarchy/outfit/job/bearcat/captain + name = BEARCAT_OUTFIT_JOB_NAME("Captain") + uniform = /obj/item/clothing/under/casual_pants/classicjeans + shoes = /obj/item/clothing/shoes/black + pda_type = /obj/item/device/pda/captain + r_pocket = /obj/item/device/radio + id_type = /obj/item/weapon/card/id/gold + + +/decl/hierarchy/outfit/job/bearcat/captain/post_equip(var/mob/living/carbon/human/H) + ..() + var/obj/item/clothing/uniform = H.w_uniform + if(uniform) + var/obj/item/clothing/accessory/toggleable/hawaii/random/eyegore = new() + if(uniform.can_attach_accessory(eyegore)) + uniform.attach_accessory(null, eyegore) + else + qdel(eyegore) + +/decl/hierarchy/outfit/job/bearcat/chief_engineer + name = BEARCAT_OUTFIT_JOB_NAME("Chief Engineer") + uniform = /obj/item/clothing/under/rank/chief_engineer + glasses = /obj/item/clothing/glasses/welding/superior + suit = /obj/item/clothing/suit/storage/hazardvest + gloves = /obj/item/clothing/gloves/thick + shoes = /obj/item/clothing/shoes/workboots + pda_type = /obj/item/device/pda/heads/ce + l_hand = /obj/item/weapon/wrench + belt = /obj/item/weapon/storage/belt/utility/full + id_type = /obj/item/weapon/card/id/engineering/head + r_pocket = /obj/item/device/radio + flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL + +/decl/hierarchy/outfit/job/bearcat/doc + name = BEARCAT_OUTFIT_JOB_NAME("Ship's Doc") + uniform = /obj/item/clothing/under/det/black + suit = /obj/item/clothing/suit/storage/toggle/labcoat + shoes = /obj/item/clothing/shoes/laceup + pda_type = /obj/item/device/pda/medical + +/decl/hierarchy/outfit/job/bearcat/mate + name = BEARCAT_OUTFIT_JOB_NAME("First Mate") + uniform = /obj/item/clothing/under/suit_jacket/checkered + shoes = /obj/item/clothing/shoes/laceup + glasses = /obj/item/clothing/glasses/sunglasses/big + pda_type = /obj/item/device/pda/cargo + l_hand = /obj/item/weapon/clipboard + +/decl/hierarchy/outfit/job/bearcat/hand + name = BEARCAT_OUTFIT_JOB_NAME("Deck Hand") + +/decl/hierarchy/outfit/job/bearcat/hand/pre_equip(mob/living/carbon/human/H) + ..() + uniform = pick(list(/obj/item/clothing/under/overalls,/obj/item/clothing/under/focal,/obj/item/clothing/under/hazard,/obj/item/clothing/under/rank/cargotech,/obj/item/clothing/under/color/black,/obj/item/clothing/under/color/grey,/obj/item/clothing/under/casual_pants/track, )) + +/decl/hierarchy/outfit/job/bearcat/hand/cook + name = BEARCAT_OUTFIT_JOB_NAME("Cook") + head = /obj/item/clothing/head/chefhat + suit = /obj/item/clothing/suit/chef/classic + +/decl/hierarchy/outfit/job/bearcat/hand/engine + name = BEARCAT_OUTFIT_JOB_NAME("Junior Engineer") + head = /obj/item/clothing/head/hardhat + flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL + +/decl/hierarchy/outfit/job/bearcat/hand/engine/pre_equip(mob/living/carbon/human/H) + ..() + if(prob(50)) + suit = /obj/item/clothing/suit/storage/hazardvest \ No newline at end of file diff --git a/maps/overmap_example/bearcat/bearcat_loadouts.dm b/maps/overmap_example/bearcat/bearcat_loadouts.dm new file mode 100644 index 00000000..93b177ae --- /dev/null +++ b/maps/overmap_example/bearcat/bearcat_loadouts.dm @@ -0,0 +1,61 @@ +/datum/gear/accessory/dashiki + display_name = "dashiki selection" + path = /obj/item/clothing/accessory/dashiki + flags = GEAR_HAS_TYPE_SELECTION + +/datum/gear/accessory/thawb + display_name = "thawb" + path = /obj/item/clothing/accessory/thawb + +/datum/gear/accessory + display_name = "scarf" + path = /obj/item/clothing/accessory/scarf + slot = slot_tie + sort_category = "Accessories" + +/datum/gear/accessory/hawaii + display_name = "hawaii shirt" + path = /obj/item/clothing/accessory/toggleable/hawaii + +/datum/gear/accessory/hawaii/New() + ..() + var/list/shirts = list() + shirts["blue hawaii shirt"] = /obj/item/clothing/accessory/toggleable/hawaii + shirts["red hawaii shirt"] = /obj/item/clothing/accessory/toggleable/hawaii/red + shirts["random colored hawaii shirt"] = /obj/item/clothing/accessory/toggleable/hawaii/random + gear_tweaks += new/datum/gear_tweak/path(shirts) + +/datum/gear/accessory/ethnic + display_name = "clothing tops (colorable)" + flags = GEAR_HAS_COLOR_SELECTION + path = /obj/item/clothing/accessory + +/datum/gear/accessory/ethnic/New() + ..() + var/stuff = list() + stuff["zhongshan jacket"] = /obj/item/clothing/accessory/toggleable/zhongshan + stuff["sherwani"] = /obj/item/clothing/accessory/sherwani + stuff["qipao blouse"] = /obj/item/clothing/accessory/qipao + stuff["turtleneck sweater"] = /obj/item/clothing/accessory/sweater + stuff["tangzhuang jacket"] = /obj/item/clothing/accessory/tangzhuang + gear_tweaks += new/datum/gear_tweak/path(stuff) + +/datum/gear/accessory/holster + display_name = "holster selection" + path = /obj/item/clothing/accessory/holster + cost = 1 + flags = GEAR_HAS_TYPE_SELECTION + +/datum/gear/accessory/guns + display_name = "guns" + flags = GEAR_HAS_COLOR_SELECTION + cost = 4 + sort_category = "Utility" + path = /obj/item/weapon/gun/projectile/ + +/datum/gear/accessory/guns/New() + ..() + var/guns = list() + guns["holdout"] = /obj/item/weapon/gun/projectile/pistol + guns[".45 gun"] = /obj/item/weapon/gun/projectile/sec + gear_tweaks += new/datum/gear_tweak/path(guns) \ No newline at end of file diff --git a/maps/overmap_example/overmap_example.dm b/maps/overmap_example/overmap_example.dm new file mode 100644 index 00000000..dadacbf0 --- /dev/null +++ b/maps/overmap_example/overmap_example.dm @@ -0,0 +1,15 @@ +#if !defined(using_map_DATUM) + #include "overmap_unit_testing.dm" + + #include "bearcat/bearcat.dm" + + #include "../../code/modules/lobby_music/businessend.dm" + #include "../../code/modules/lobby_music/salutjohn.dm" + + #define using_map_DATUM /datum/map/overmap_example + +#elif !defined(MAP_OVERRIDE) + + #warn A map has already been included, ignoring Overmap Example + +#endif diff --git a/maps/overmap_example/overmap_example_define.dm b/maps/overmap_example/overmap_example_define.dm new file mode 100644 index 00000000..2a58d566 --- /dev/null +++ b/maps/overmap_example/overmap_example_define.dm @@ -0,0 +1,46 @@ +/datum/map/overmap_example + name = "Bearcat" + full_name = "Bearcat" + path = "overmap_example" + + station_name = "FTV Bearcat" + station_short = "Bearcat" + + dock_name = "FTS Capitalist's Rest" + boss_name = "FTU Merchant Navy" + boss_short = "Merchant Admiral" + company_name = "Legit Cargo Ltd." + company_short = "LC" + overmap_event_areas = 11 + + default_law_type = /datum/ai_laws/corporate + + evac_controller_type = /datum/evacuation_controller/lifepods + lobby_icon = 'maps/overmap_example/overmap_example_lobby.dmi' + lobby_screens = list("spess","aesthetic") + + allowed_spawns = list("Cryogenic Storage") + default_spawn = "Cryogenic Storage" + use_overmap = 1 + num_exoplanets = 3 + welcome_sound = 'sound/effects/cowboysting.ogg' + + emergency_shuttle_leaving_dock = "Attention all hands: the escape pods have been launched, maintaining burn for %ETA%." + + emergency_shuttle_called_message = "Attention all hands: emergency evacuation procedures are now in effect. Escape pods will launch in %ETA%" + emergency_shuttle_called_sound = sound('sound/AI/torch/abandonship.ogg', volume = 45) + + emergency_shuttle_recall_message = "Attention all hands: emergency evacuation sequence aborted. Return to normal operating conditions." + + starting_money = 5000 + department_money = 0 + salary_modifier = 0.2 + +/datum/map/overmap_example/map_info(victim) + to_chat(victim, "You're aboard the [station_name], an independent vessel affiliated with Free Trade Union, on a SPACE FRONTIER. No major corporation or government has laid claim on the planets in this sector, so their exploitation is entirely up to you - mine, poach and deforest all you want.") + +/datum/map/overmap_example/setup_map() + ..() + GLOB.traders += new /datum/trader/xeno_shop + GLOB.traders += new /datum/trader/medical + GLOB.traders += new /datum/trader/mining \ No newline at end of file diff --git a/maps/overmap_example/overmap_example_lobby.dmi b/maps/overmap_example/overmap_example_lobby.dmi new file mode 100644 index 00000000..1ac2e812 Binary files /dev/null and b/maps/overmap_example/overmap_example_lobby.dmi differ diff --git a/maps/overmap_example/overmap_unit_testing.dm b/maps/overmap_example/overmap_unit_testing.dm new file mode 100644 index 00000000..23a5e7fc --- /dev/null +++ b/maps/overmap_example/overmap_unit_testing.dm @@ -0,0 +1,22 @@ +/datum/map/overmap_example + // Unit test exemptions + apc_test_exempt_areas = list( + /area/space = NO_SCRUBBER|NO_VENT|NO_APC, + /area/ship/scrap/maintenance/engine/port = NO_SCRUBBER|NO_VENT, + /area/ship/scrap/maintenance/engine/starboard = NO_SCRUBBER|NO_VENT, + /area/ship/scrap/crew/hallway/port = NO_SCRUBBER|NO_VENT, + /area/ship/scrap/crew/hallway/starboard = NO_SCRUBBER|NO_VENT, + /area/ship/scrap/maintenance/hallway = NO_SCRUBBER|NO_VENT, + /area/ship/scrap/maintenance/lower = NO_SCRUBBER|NO_VENT, + /area/exoplanet = NO_SCRUBBER|NO_VENT|NO_APC, + /area/exoplanet/desert = NO_SCRUBBER|NO_VENT|NO_APC, + /area/exoplanet/grass = NO_SCRUBBER|NO_VENT|NO_APC, + /area/exoplanet/snow = NO_SCRUBBER|NO_VENT|NO_APC, + /area/exoplanet/garbage = NO_SCRUBBER|NO_VENT|NO_APC, + /area/ship/scrap/shuttle/lift = NO_SCRUBBER|NO_VENT|NO_APC, + /area/ship/scrap/command/hallway = NO_SCRUBBER|NO_VENT, + /area/ship/scrap/escape_port = NO_SCRUBBER|NO_VENT, + /area/ship/scrap/escape_star = NO_SCRUBBER|NO_VENT, + /area/ship/scrap/shuttle/outgoing = NO_SCRUBBER, + /area/ship/scrap/maintenance/atmos = NO_SCRUBBER + ) diff --git a/maps/random_ruins/exoplanet_ruins/bunker.dmm b/maps/random_ruins/exoplanet_ruins/bunker.dmm new file mode 100644 index 00000000..cfea34f3 --- /dev/null +++ b/maps/random_ruins/exoplanet_ruins/bunker.dmm @@ -0,0 +1,144 @@ +"aa" = (/turf/simulated/wall/concrete,/area/warfare/homebase/red) +"ab" = (/obj/structure/dirt_wall,/obj/machinery/door/blast/shutters/open{id = "red"},/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/red) +"ac" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance,/obj/machinery/door/blast/shutters/open{id = "red"},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"ad" = (/obj/machinery/door/blast/shutters/open{id = "red"},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"ae" = (/obj/structure/poster/red,/turf/simulated/wall/concrete,/area/warfare/homebase/red) +"af" = (/obj/structure/closet/crate,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ag" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ah" = (/obj/structure/closet/crate,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ai" = (/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aj" = (/obj/machinery/button/remote/blast_door/lever{id = "red"; pixel_y = 32},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ak" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"al" = (/obj/structure/table/steel,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"am" = (/obj/structure/table/steel,/obj/structure/sink{pixel_y = 20},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"an" = (/obj/structure/table/steel,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ao" = (/obj/structure/table/steel,/obj/item/weapon/reagent_containers/food/condiment/small/saltshaker,/obj/item/weapon/reagent_containers/food/condiment/small/peppermill,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ap" = (/obj/structure/table/steel,/obj/machinery/microwave,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aq" = (/obj/machinery/button/remote/blast_door/lever{id = "red"; pixel_x = -32},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"ar" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"as" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"at" = (/obj/structure/closet/crate,/obj/random/canned_food,/obj/random/canned_food,/obj/random/canned_food,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"au" = (/obj/machinery/button/remote/blast_door/lever{id = "red"; pixel_y = 32},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"av" = (/obj/structure/bed/chair,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aw" = (/obj/structure/bed/chair,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"ax" = (/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"ay" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"az" = (/obj/structure/closet/crate,/obj/item/weapon/melee/classic_baton/trench_club,/obj/item/weapon/melee/classic_baton/trench_club,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aA" = (/obj/structure/table/steel,/obj/machinery/cooker/candy,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aB" = (/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aC" = (/obj/structure/table/steel,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aD" = (/obj/structure/closet/crate,/obj/item/weapon/melee/classic_baton/trench_club,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aE" = (/obj/structure/bed/chair,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aF" = (/obj/structure/table/steel,/obj/machinery/cooker/cereal,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aG" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aH" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aI" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aJ" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aK" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aL" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aM" = (/obj/structure/table/woodentable,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aN" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aO" = (/obj/structure/closet/secure_closet/freezer/meat,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aP" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes/jerichos,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aQ" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aR" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes/luckystars,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/obj/item/ammo_box/rifle,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aS" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/box/matches,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aT" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/device/compass,/obj/item/device/compass,/obj/item/device/compass,/obj/item/device/compass,/obj/item/device/compass,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aU" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aV" = (/obj/machinery/vending/dinnerware,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"aW" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/firstaid/surgery,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aX" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/fancy/cigarettes/carcinomas,/obj/item/ammo_box/rifle,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aY" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/ammo_box/shotgun,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"aZ" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/fancy/cigarettes/carcinomas,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"ba" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/wirecutters,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"bb" = (/obj/structure/closet/chefcloset,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bc" = (/obj/machinery/cooker/oven,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bd" = (/obj/machinery/cooker/grill,/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"be" = (/obj/machinery/cooker/fryer,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bf" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 1},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bg" = (/turf/template_noop,/area/template_noop) +"bh" = (/turf/simulated/floor/dirty/indestructable,/area/warfare/homebase/red) +"bi" = (/obj/structure/table/steel,/obj/item/weapon/gun/projectile/talon,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bj" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/mc9mmt/machinepistol,/obj/item/ammo_magazine/c45rifle/akarabiner,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"bk" = (/obj/structure/closet/crate,/obj/item/ammo_box/rifle,/obj/item/ammo_box/rifle,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"bl" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance{dir = 1; icon_state = "door_closed"; name = "Emergency Medical"},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bm" = (/obj/effect/landmark/corpse/chef,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bn" = (/obj/structure/closet/crate,/obj/item/weapon/wirecutters,/obj/item/weapon/wirecutters,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bo" = (/obj/structure/closet/crate,/obj/item/weapon/wirecutters,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bp" = (/obj/machinery/door/airlock/multi_tile/metal/maintenance,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"bq" = (/obj/structure/closet/cabinet,/obj/item/weapon/gun/energy/h4,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"br" = (/obj/effect/decal/cleanable/blood/gibs/up,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bs" = (/obj/structure/curtain,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bt" = (/obj/structure/table/woodentable,/obj/item/device/compass,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bu" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/fancy/cigarettes/carcinomas,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bv" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 4},/obj/effect/decal/cleanable/blood/gibs/down,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bw" = (/obj/structure/table/woodentable,/obj/item/weapon/flame/candle,/obj/item/weapon/storage/box/matches,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bx" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"by" = (/obj/machinery/shower{icon_state = "shower"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bz" = (/obj/effect/landmark/corpse/miner,/obj/effect/decal/cleanable/blood/gibs/up,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bA" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/obj/effect/decal/cleanable/blood/gibs/up,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bB" = (/obj/effect/landmark/corpse/marooned_officer,/obj/effect/decal/cleanable/blood/gibs/down,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bC" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bD" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/fancy/cigarettes/jerichos,/obj/item/weapon/flame/candle,/obj/item/weapon/flame/lighter/random,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bE" = (/obj/structure/toilet{icon_state = "toilet00"; dir = 8},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bF" = (/obj/structure/bed,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bG" = (/obj/structure/closet/cabinet,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bH" = (/obj/structure/crematorium{icon_state = "crema1"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bI" = (/obj/machinery/button/crematorium{pixel_y = 32},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bJ" = (/obj/machinery/optable,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bK" = (/obj/machinery/computer/operating,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bL" = (/obj/random/mining_hostile,/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"bM" = (/obj/structure/bed/chair/wheelchair,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bN" = (/turf/simulated/floor/tiled/ramp{icon_state = "ramptop"; dir = 4},/area/warfare/homebase/red) +"bO" = (/obj/random/mining_hostile,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bP" = (/turf/simulated/mineral,/area/warfare/homebase/red) +"bR" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/turf/simulated/floor/tiled,/area/warfare/homebase/red) +"bS" = (/obj/structure/table/steel,/obj/item/weapon/storage/firstaid/surgery,/obj/item/weapon/FixOVein,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bT" = (/obj/structure/closet/secure_closet/medical2{req_access = newlist()},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bU" = (/obj/structure/closet/medical_wall,/turf/simulated/wall/concrete,/area/warfare/homebase/red) +"bV" = (/obj/structure/sign/medholo,/turf/simulated/wall/concrete,/area/warfare/homebase/red) +"bW" = (/obj/structure/closet/crate,/obj/item/weapon/reagent_containers/ivbag/blood/AMinus,/obj/item/weapon/reagent_containers/ivbag/blood/AMinus,/obj/item/weapon/reagent_containers/ivbag/blood/APlus,/obj/item/weapon/reagent_containers/ivbag/blood/APlus,/obj/item/weapon/reagent_containers/ivbag/blood/BMinus,/obj/item/weapon/reagent_containers/ivbag/blood/BMinus,/obj/item/weapon/reagent_containers/ivbag/blood/BPlus,/obj/item/weapon/reagent_containers/ivbag/blood/BPlus,/obj/item/weapon/reagent_containers/ivbag/blood/OMinus,/obj/item/weapon/reagent_containers/ivbag/blood/OMinus,/obj/item/weapon/reagent_containers/ivbag/blood/OPlus,/obj/item/weapon/reagent_containers/ivbag/blood/OPlus,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bX" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/fire,/obj/item/weapon/storage/firstaid/fire,/obj/item/weapon/storage/firstaid/fire,/obj/item/weapon/storage/firstaid/fire,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bY" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/toxin,/obj/item/weapon/storage/firstaid/toxin,/obj/item/weapon/storage/firstaid/toxin,/obj/item/weapon/storage/firstaid/toxin,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"bZ" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/adv,/obj/item/weapon/storage/firstaid/adv,/obj/item/weapon/storage/firstaid/adv,/obj/item/weapon/storage/firstaid/adv,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ca" = (/obj/structure/table/rack,/obj/item/weapon/storage/firstaid/regular,/obj/item/weapon/storage/firstaid/regular,/obj/item/weapon/storage/firstaid/regular,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cb" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 8},/obj/structure/table/steel,/obj/item/weapon/reagent_containers/spray/cleaner/warfare,/obj/item/weapon/reagent_containers/spray/cleaner/warfare,/obj/item/weapon/reagent_containers/spray/cleaner/warfare,/obj/item/weapon/reagent_containers/spray/cleaner/warfare,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cd" = (/obj/machinery/sleeper,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ce" = (/obj/machinery/body_scanconsole{icon_state = "body_scannerconsole"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cf" = (/obj/machinery/bodyscanner{icon_state = "body_scanner_0"; dir = 4},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cg" = (/obj/machinery/vending/medical{req_access = newlist()},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ch" = (/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 16},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ci" = (/obj/structure/table/steel,/obj/item/weapon/crutches,/obj/item/weapon/crutches,/obj/item/weapon/crutches,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cj" = (/obj/structure/closet/secure_closet/medical1/warfare,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"ck" = (/obj/structure/torchwall{icon_state = "torchwall0"; dir = 1},/obj/structure/iv_drip,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cl" = (/obj/machinery/sleeper{icon_state = "sleeper_0"; dir = 1},/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) +"cn" = (/obj/structure/bed/roller,/turf/simulated/floor/tiled/dark,/area/warfare/homebase/red) + +(1,1,1) = {" +bhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbhbh +aaaaaaaaabaaaaaaaaaaaaaaaaaaaaacadaaaaaaaaababaeaaaaaaaaaaaaaaababaaaaaaaa +aaafagahaiajakaaalambiaoanapaaaqaraaasatauaxaxaxaxayaaaaasatauaxaxaxaxazaa +aaaiaiaiaiaiaiaaaAaibmbraiaCaaaxaxaaasataxaxaxaxaxayaaaaasataxaxaxaxaxaDaa +aaaiaiavavaiaiaeaFbrbraiaiaGaaaxaxaaawaBaxaxaxaxaBaEaaaaawaBaxaxaxaxaBaEaa +aaaKaHaMaMaNakaaaGaiaiaiaiaOaaaxaraaaPaQaxaxaxaxaRaSaeaaaSaTaxaxbLaxaSaUaa +aeaiaHaMaMaNaiaaaVaiaiaiaiaiaaaxaxaaaWaSaxaxaxaxaXaYaaaaaUaTaxaxaxaxaZbaaa +aaaiaHaMaMaNaiaaaOaibbbcbdbeaaaxaxaaaIaJbLaxaxaxaJaLaaaaaIaJaxaxaxaxaJaLaa +aaaKaibfbfaibAaaaaaiaaaaaaaaaaaxaraaazaxaxaxaxaxbjbkaaaabkaxaxaxaxaxaxbjaa +aaaibOaiaibrbzaiaiaiaiaiaiaiaiaxaxaaaDaxaxaxaxaxbjbkaaaabkaxaxaxaxaxaxbjaa +aaaiaiavavaiaiaiavavaiaiaiaiblaxaxaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaiaa +aaaKaHaMaMaNaiaHaMaMaNaiaiakaaaxaxblaiaiaiaiaiaiaibnbnaiaibnboaiaiaiaiaiaa +aaaiaHaMaMaNaiaHaMaMaNaiaiaiaabpaxaaaKaiakaaaabsaaaaaabsaaaaaabsaaaaaabsaa +aaaiaHaMaMaNaiaHaMbtaNaiaibuaaaxaxaaaabsaaaaaKaiaiaaaKaiaiaaaKaiaiaaaKaiai +aaaKaibfbfaiaiaibfbfaiaiaibwaaaxaraabxaibyaabxaiaiaabxaiaiaabxaiaiaabxaiai +aaaibCaiaibCaibCaiaibCaiaibDaaaxaxaabxbCbEaabFbtbqaabFbtbGaabFbtbGaabFbtbG +aaaaaaaaaaaaaaaaaaaaaaaaaeaaaaaxaxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aabHaibIaabJbKaiaiaabMbMaiaiaiaxaxaxbNbPbPbPbPbgbgbgbgbgbgbgbgbgbgbgbgbgbg +aaaiaiaiaaaKaiaiaibsaiaiaiaiblaxbRaxbNbPbPbPbPbgbgbgbgbgbgbgbgbgbgbgbgbgbg +aabHaiaiaabSaiaibTbUaKaibOakbVaaaaaaaaaaaaaaaabgbgbgbgbgbgbgbgbgbgbgbgbgbg +aaaiaiakaaaaaaaaaaaaaiaiaiaiaibWbXbYbZcacbaaaabgbgbgbgbgbgbgbgbgbgbgbgbgbg +aabHaiaiaaaKcdaicdaicecfaiaiaiaibrbraiaiaicgaabgbgbgbgbgbgbgbgbgbgbgbgbgbg +aaaiaiaiaeaiaiaiaiaiaiaiaichaabvbBaiaiaiaiciaabgbgbgbgbgbgbgbgbgbgbgbgbgbg +aabHaiakaaaiaiaiaiaicecfaiakaacjcjaickaiaicgaabgbgbgbgbgbgbgbgbgbgbgbgbgbg +aaaiaiaibsaiclaiclaicncncncnaaaaaaaaaaaaaaaaaabgbgbgbgbgbgbgbgbgbgbgbgbgbg +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabgbgbgbgbgbgbgbgbgbgbgbgbgbgbgbgbgbgbgbgbgbg +"} diff --git a/maps/random_ruins/exoplanet_ruins/crashed_ship.dmm b/maps/random_ruins/exoplanet_ruins/crashed_ship.dmm new file mode 100644 index 00000000..1919618c --- /dev/null +++ b/maps/random_ruins/exoplanet_ruins/crashed_ship.dmm @@ -0,0 +1,237 @@ +"aa" = (/turf/simulated/mineral,/area/template_noop) +"ab" = (/turf/template_noop,/area/template_noop) +"ac" = (/obj/structure/grille,/turf/simulated/floor/plating,/area/icarus/vessel) +"ad" = (/obj/random/trash,/mob/living/simple_animal/hostile/mining_borg/behemoth,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ae" = (/obj/item/weapon/ore/slag,/turf/simulated/floor/plating,/area/template_noop) +"af" = (/turf/simulated/floor/plating,/area/icarus/vessel) +"ag" = (/obj/item/weapon/ore/slag,/turf/simulated/floor/plating,/area/icarus/vessel) +"ah" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ai" = (/obj/item/modular_computer/console,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aj" = (/turf/simulated/floor/tiled,/area/icarus/vessel) +"ak" = (/obj/structure/bed/chair{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"al" = (/turf/simulated/wall/r_wall,/area/template_noop) +"am" = (/obj/item/weapon/ore/slag,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"an" = (/obj/structure/table/steel_reinforced,/obj/random/firstaid,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ao" = (/obj/structure/table/steel_reinforced,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ap" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aq" = (/obj/structure/table/steel_reinforced,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ar" = (/turf/simulated/wall/r_wall,/area/icarus/vessel) +"as" = (/obj/structure/table/steel_reinforced,/obj/random/handgun,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"at" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"au" = (/obj/machinery/door/firedoor,/obj/structure/grille,/obj/structure/window_frame,/turf/simulated/floor/tiled,/area/template_noop) +"av" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aw" = (/obj/structure/table/steel_reinforced,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ax" = (/obj/random/trash,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ay" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/obj/effect/landmark/corpse/bridgeofficer,/turf/simulated/floor/tiled,/area/icarus/vessel) +"az" = (/obj/structure/bed/chair{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aA" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/fancy/cigarettes/killthroat,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aB" = (/mob/living/simple_animal/hostile/mining_borg/behemoth,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aC" = (/obj/effect/floor_decal/plaque,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aD" = (/obj/random/loot,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aE" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/box/survival,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aF" = (/obj/structure/table/steel_reinforced,/obj/random/tool,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aG" = (/obj/item/modular_computer/console,/obj/item/weapon/disk/icarus,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aH" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/box/trackimp,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aI" = (/obj/structure/table/standard,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aJ" = (/obj/item/modular_computer/console,/obj/item/weapon/paper/icarus/log,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aK" = (/obj/structure/bed/chair/comfy/captain{color = "#666666"; dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aL" = (/obj/structure/table/steel_reinforced,/obj/item/device/flashlight/lamp,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aM" = (/obj/structure/table/rack,/obj/item/device/flashlight/flare,/obj/item/device/flashlight/flare,/obj/item/device/flashlight/flare,/obj/item/device/flashlight/flare,/turf/simulated/floor/tiled/dark,/area/icarus/vessel) +"aN" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aO" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aP" = (/obj/structure/sign/icarus/solgov{pixel_x = 30},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aQ" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/box/PDAs,/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aR" = (/obj/structure/table/steel_reinforced,/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/item/weapon/storage/toolbox/emergency,/turf/simulated/floor/tiled,/area/icarus/vessel) +"aS" = (/obj/structure/sign/icarus/solgov{pixel_x = -30},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aT" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aU" = (/obj/structure/table/rack,/obj/item/weapon/airlock_brace,/obj/item/weapon/airlock_brace,/obj/item/weapon/airlock_brace,/obj/item/weapon/crowbar/brace_jack,/turf/simulated/floor/tiled/dark,/area/icarus/vessel) +"aV" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/telecomms/server,/turf/simulated/floor/bluegrid,/area/icarus/vessel) +"aW" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aX" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aY" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"aZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ba" = (/obj/machinery/light,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bb" = (/obj/structure/filingcabinet,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bc" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bd" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"be" = (/obj/structure/table/rack,/obj/item/weapon/storage/box/teargas{pixel_x = 3; pixel_y = 2},/obj/item/weapon/storage/box/handcuffs,/obj/item/weapon/storage/box/flashbangs{pixel_x = -2; pixel_y = -2},/turf/simulated/floor/tiled/dark,/area/icarus/vessel) +"bf" = (/obj/structure/table/rack,/obj/item/weapon/gun/projectile/revolver/cpt,/obj/item/weapon/gun/projectile/makarov,/turf/simulated/floor/plating,/area/icarus/vessel) +"bg" = (/obj/machinery/telecomms/server/presets/common,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/bluegrid,/area/icarus/vessel) +"bh" = (/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/bluegrid,/area/icarus/vessel) +"bi" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bj" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bk" = (/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bl" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/icarus/vessel) +"bm" = (/obj/structure/table/rack,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/baton,/turf/simulated/floor/plating,/area/icarus/vessel) +"bn" = (/obj/structure/table/rack,/obj/item/weapon/handcuffs,/turf/simulated/floor/plating,/area/icarus/vessel) +"bo" = (/obj/machinery/telecomms/server,/turf/simulated/floor/bluegrid,/area/icarus/vessel) +"bp" = (/turf/simulated/floor/bluegrid,/area/icarus/vessel) +"bq" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"br" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bs" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bt" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bu" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bv" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bw" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bx" = (/obj/machinery/papershredder,/turf/simulated/floor/tiled,/area/icarus/vessel) +"by" = (/obj/machinery/photocopier,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bz" = (/obj/structure/filingcabinet,/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bA" = (/obj/machinery/door/firedoor,/obj/structure/grille,/obj/machinery/door/firedoor,/obj/structure/window_frame,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bB" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bC" = (/obj/structure/closet,/obj/item/weapon/reagent_containers/food/drinks/bottle/tequilla,/obj/item/weapon/reagent_containers/food/drinks/bottle/wine,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1; layer = 2.4; level = 2},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bD" = (/obj/structure/table/woodentable,/obj/random/loot,/turf/simulated/floor/tiled,/area/template_noop) +"bE" = (/obj/structure/bed/chair/comfy/brown{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bF" = (/obj/structure/table/woodentable,/obj/random/loot,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bG" = (/obj/structure/table/woodentable,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bH" = (/obj/structure/bed/chair/comfy/brown{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bI" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bJ" = (/obj/structure/table/steel_reinforced,/turf/simulated/floor/plating,/area/icarus/vessel) +"bK" = (/obj/machinery/suit_storage_unit/security/alt,/turf/simulated/floor/plating,/area/template_noop) +"bL" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/handcuffs,/turf/simulated/floor/plating,/area/icarus/vessel) +"bM" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/material/harpoon,/turf/simulated/floor/plating,/area/icarus/vessel) +"bN" = (/obj/structure/grille,/obj/machinery/door/firedoor,/obj/structure/window_frame,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bO" = (/obj/structure/table/steel,/obj/random/tool,/obj/random/tool,/obj/random/tool,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bP" = (/obj/item/modular_computer/console,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bQ" = (/obj/structure/closet,/obj/item/weapon/storage/backpack/industrial,/obj/item/weapon/storage/toolbox/electrical,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bR" = (/obj/structure/closet,/obj/item/clothing/suit/space/emergency,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bS" = (/obj/structure/closet,/obj/item/weapon/storage/backpack/industrial,/obj/item/weapon/storage/toolbox/mechanical,/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bT" = (/obj/structure/closet,/obj/item/clothing/suit/radiation,/obj/item/clothing/suit/radiation,/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bU" = (/turf/simulated/wall,/area/icarus/vessel) +"bV" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bW" = (/obj/structure/closet,/obj/item/weapon/reagent_containers/food/drinks/flask/shiny,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bX" = (/obj/structure/bed/chair/comfy/brown,/turf/simulated/floor/tiled,/area/icarus/vessel) +"bY" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/icarus/vessel) +"bZ" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ca" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/icarus/vessel) +"cb" = (/obj/structure/table/steel,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cc" = (/obj/structure/bed/chair{icon_state = "chair_preview"; dir = 8},/obj/effect/landmark/corpse/engineer,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cd" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ce" = (/obj/random/trash,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cf" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cg" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"ch" = (/obj/structure/closet,/obj/item/weapon/reagent_containers/food/drinks/golden_cup,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ci" = (/obj/structure/table/woodentable,/obj/item/weapon/storage/backpack/captain,/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cj" = (/obj/structure/table/woodentable,/obj/item/weapon/paper/icarus/crew_roster,/obj/item/weapon/folder/blue,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ck" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cl" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cm" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cn" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/icarus/vessel) +"co" = (/obj/machinery/light{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cp" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/random/mining_hostile,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cq" = (/obj/random/mining_hostile,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cr" = (/obj/structure/table/steel_reinforced,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cs" = (/obj/structure/table/steel,/obj/random/tank,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ct" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cu" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cv" = (/obj/structure/bed,/obj/item/weapon/bedsheet/captain,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cw" = (/obj/structure/table/woodentable,/obj/item/weapon/reagent_containers/food/drinks/bottle/whiskey,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cx" = (/obj/structure/sign/double/icarus/solgovflag/left{pixel_y = -32},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cy" = (/obj/structure/sign/double/icarus/solgovflag/right{pixel_y = -32},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cz" = (/obj/structure/table/woodentable,/obj/item/toy/ship_model,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cA" = (/obj/structure/table/woodentable,/obj/random/action_figure,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cB" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cC" = (/obj/item/weapon/stool,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cD" = (/obj/item/weapon/stool,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cE" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cF" = (/obj/structure/table/steel_reinforced,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cG" = (/obj/machinery/alarm{dir = 1; pixel_y = -25; req_one_access = list(24,11)},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cH" = (/obj/structure/closet,/obj/item/weapon/reagent_containers/spray/pepper,/obj/item/weapon/storage/box/handcuffs,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cI" = (/obj/structure/table/rack,/obj/random/tool,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cJ" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cK" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cL" = (/obj/structure/lattice,/turf/template_noop,/area/template_noop) +"cM" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cN" = (/obj/machinery/door/airlock,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cO" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/box/fingerprints,/obj/item/weapon/gun/projectile/shotgun/pump/shitty/sawn,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cP" = (/obj/effect/decal/cleanable/dirt,/obj/random/mining_hostile,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cQ" = (/obj/structure/table/rack,/obj/random/tech_supply,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cR" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cS" = (/obj/machinery/alarm{alarm_id = "xenobio4_alarm"; dir = 2; icon_state = "alarm0"; pixel_x = 0; pixel_y = 24},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cT" = (/obj/item/modular_computer/console,/obj/machinery/light{dir = 1},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cU" = (/obj/structure/table/woodentable,/obj/item/weapon/disk/secret_project/science,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cV" = (/obj/structure/grille,/obj/machinery/door/firedoor,/obj/structure/window_frame{icon_state = "window1"; dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"cW" = (/obj/machinery/light{dir = 1},/obj/structure/table/standard,/obj/structure/window/reinforced{dir = 8},/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cX" = (/obj/structure/table/standard,/obj/machinery/reagentgrinder,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cY" = (/obj/machinery/light{dir = 1},/obj/structure/table/standard,/obj/item/weapon/storage/box/monkeycubes,/turf/simulated/floor/tiled,/area/icarus/vessel) +"cZ" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/beakers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"da" = (/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"db" = (/obj/structure/bed,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dc" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dd" = (/obj/machinery/door/airlock,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"de" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"df" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dg" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dh" = (/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/tiled,/area/icarus/vessel) +"di" = (/obj/structure/sign/science_2{pixel_x = 30},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dj" = (/obj/structure/bed/chair/comfy/brown{dir = 4},/obj/effect/landmark/corpse/scientist,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dk" = (/obj/structure/grille,/obj/machinery/door/firedoor,/obj/structure/window_frame{icon_state = "window1"; dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dl" = (/obj/machinery/door/window/eastleft,/obj/machinery/door/firedoor,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dm" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/obj/machinery/alarm{alarm_id = "xenobio3_alarm"; dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/tiled,/area/icarus/vessel) +"do" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dp" = (/obj/structure/table/rack,/obj/random/tool,/obj/random/powercell,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dq" = (/obj/item/modular_computer/console,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dr" = (/obj/structure/table/woodentable,/obj/item/device/flashlight/lamp,/turf/simulated/floor/tiled,/area/icarus/vessel) +"ds" = (/obj/structure/grille,/obj/machinery/door/firedoor,/obj/structure/window_frame{icon_state = "window1"; dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"du" = (/obj/machinery/door/airlock,/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dv" = (/obj/random/loot,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dw" = (/obj/structure/bed/chair,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dx" = (/obj/structure/bed,/obj/item/trash/snack_bowl,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dy" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dz" = (/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/structure/table/steel_reinforced,/obj/item/weapon/storage/box/flashshells,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dA" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dB" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dC" = (/obj/structure/closet,/obj/item/clothing/suit/storage/toggle/labcoat/blue,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dD" = (/obj/structure/closet,/obj/item/clothing/suit/storage/toggle/labcoat/blue,/obj/item/weapon/disk/survey,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dF" = (/obj/structure/table/standard,/obj/item/device/flashlight/lamp,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dG" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/reagent_containers/spray/pepper,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dH" = (/obj/item/modular_computer/console,/obj/machinery/alarm{dir = 1; pixel_y = -25; req_one_access = list(24,11)},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dI" = (/obj/effect/decal/cleanable/dirt,/obj/random/trash,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dJ" = (/obj/item/modular_computer/console,/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dK" = (/obj/machinery/r_n_d/destructive_analyzer,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dL" = (/obj/random/trash,/turf/simulated/floor/plating,/area/icarus/vessel) +"dM" = (/turf/simulated/floor/airless{icon_state = "dmg2"},/area/icarus/vessel) +"dN" = (/obj/structure/bed,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled,/area/icarus/vessel) +"dO" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/icarus/vessel) +"dP" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/icarus/vessel) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabab +abaaaaaaaaaaaaaaaaaaaaaaaaaaaaagafafaaaaagafaaaaaaaaaaaaaaaaaaaaaaaaaaababab +aaaaaaaaaaaaaaaaaaaaaaaaaaaaafafahaiafafajajaeaaaaaaaaaaaaaaaaaaaaaaabababab +ababaaaaaaaaaaaaaaaaaaaaaaagajajahajakajajamahanalabababaaaaaaaaaaababababab +abababababaaaaaaaaaaaaaaalaoapapahahajajajajajaqalababababaaaaaaabababababab +abababababababaaaaaaalararasatahavajajajahajajawararalababababababababababab +abababababababababaaalaiapapahajahajajajajajaxajajaialababababababababababab +ababababababababababauaiayajahajadajahajaBaxajajazaiauababababababababababab +ababababababababababalaiajahajajajajajajahajajajajaialababababababababababab +ababababababababalalalaraAajajajajajaCajahaDajajaEaralalalababababababababab +abababababalalalalbDbDalaFaxajahajaiaGaiajahajajaHarbDbDalalalalabababababab +abababababalaIaJarajajaraFajajajajajaKajajajajajaLarajajaraMafalabababababab +ababababalalaIaNaraOaParaQajajajajajajajajajajajaRaraSaTaraUafalalababababab +abababalalaVajajaraWaXaYaZbaajbbbbbbajbbbbbbbbbcajbdajajarbeafbfalalabababab +ababalalbgbhajbiarbjbkarararbdarararbdarararararararbkbkarblafbmbnalalababab +abalalbobpbpbqbrbsbtaXaYbubvajarajajajajbwajbxbybzbAajajarafafafafafalalabab +arararararararararbBajarbCajbbarajbEbFbGbHajajajbIarajaharafbJbLbMafbKalalab +bNbOaibPbQbRbSbTbUbVajarbWajbXarajbEbGbGbHajajaxbYbsaXbZarcaarararararararar +arcbccapajajcdcebscfcgarchajciarajbEbGcjbHajajajckarclcmaYcncodBcpcraNbwbbar +arcsajajcqajajctbUcubvarcvbccwarajajcxcybcajbFczcAbAaxcBarcCcDcDcEcFaicGajar +arajajafafafajcIbUcJaxarararararararararararararararajcKararararcMarararcNar +arajajafcLabafcQbUcRaXaYcScTcUcVaIcWcXaIcYcZaIbxbyarajdaardbbNbqdcdddedfdgar +ardhajafababafcQbUbVdiarbVdjbGdkajajajajajajajajctarajbVarajdlajdmarcHdobBcV +afdhajafabcLafdpbUbBajarcudqdrdsajajajaBahahajajbbarahbVarararahajarcOajbVdk +afajajafcLabafajbUbVajarduarararajdvajdwajajdwajbbarahbVardxbNahdyardzdwbVds +afafaxafabafafajbUbVajardAdBdCdDajajaIaidFaIaiaIbbarahbVarahdlajahardGdHbVar +afafajafafafajajbUdIajardJajajajajafafafafafafafafafajcKarararajaharararcMar +afafafajajaxajafbUbVajardKahajajdLafababcLabafafdMafajbVarajbNajcPardbdNdOcV +afafafajajajajafbUbjbkarajahafafdMafcLabcLabdLafafafbkbjafajdlajajarajajdPdk +afcLafafaxajajafbUbVajafajajafafafafcLcLcLcLcLafafafafdMafafafajajcNajafafds +cLcLafafajajafafbUbVaxafafafdLababcLcLcLabcLabdMafababcLababdMafajararafafaf +abcLafafafafafafbUbVajafdMafafababcLcLcLabcLabababababcLcLabafdLafarafafdMab +abcLabdMafdLafafbUabafafafcLcLababcLababababababababababcLababafafafafafafab +abababafafafafafbUcLcLcLabcLcLcLabababababababababababababababababafafdMabab +ababcLafafdMafdMababcLcLababcLababababababababababababababababababcLabababab +ababcLcLababafcLcLabcLabababcLababababababababababababababababababcLabababab +abababcLcLababcLabababababababababababababababababababababababababababababab +abababcLabababababababababababababababababababababababababababababababababab +"} diff --git a/maps/random_ruins/exoplanet_ruins/exoplanet_ruins.dm b/maps/random_ruins/exoplanet_ruins/exoplanet_ruins.dm new file mode 100644 index 00000000..4a25f41d --- /dev/null +++ b/maps/random_ruins/exoplanet_ruins/exoplanet_ruins.dm @@ -0,0 +1,63 @@ +// Hey! Listen! Update \config\exoplanet_ruin_blacklist.txt with your new ruins! + +/datum/map_template/ruin/exoplanet + prefix = "maps/random_ruins/exoplanet_ruins/" + +/datum/map_template/ruin/exoplanet/little_house + name = "Little House" + id = "exoplanet_little_house" + description = "oh wow look it's a cute little house" + suffixes = list("little_house.dmm") + cost = 1 + +/area/map_template/little_house + name = "\improper Little House" + + + + +/datum/map_template/ruin/exoplanet/smugglers_den + name = "Smugglers' Base" + id = "awaysite_smugglers_two" + description = "Yarr." + suffixes = list("smugglers_two.dmm") + cost = 1 + allow_duplicates = FALSE + + +/datum/map_template/ruin/exoplanet/crashed_ship + name = "Crashed Ship" + id = "crashed_ship" + description = "How unfortunate." + suffixes = list("crashed_ship.dmm") + cost = 1 + allow_duplicates = FALSE + + +/datum/map_template/ruin/exoplanet/mine_trap + name = "Mine Trap" + id = "mine_trap" + description = "How unfortunate." + suffixes = list("mine_trap.dmm") + cost = 0.5 + +/datum/map_template/ruin/exoplanet/water + name = "Water" + id = "water" + description = "splish splash." + suffixes = list("water.dmm") + cost = 0.5 + +/datum/map_template/ruin/exoplanet/river + name = "River" + id = "river" + description = "splish splash." + suffixes = list("river.dmm") + cost = 0.5 + +/datum/map_template/ruin/exoplanet/bunker + name = "Red Bunker" + id = "river" + description = "red team." + suffixes = list("bunker.dmm") + cost = 1 \ No newline at end of file diff --git a/maps/random_ruins/exoplanet_ruins/hut/backup/hut.dmm b/maps/random_ruins/exoplanet_ruins/hut/backup/hut.dmm new file mode 100644 index 00000000..59fea783 --- /dev/null +++ b/maps/random_ruins/exoplanet_ruins/hut/backup/hut.dmm @@ -0,0 +1,170 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/template_noop, +/area/template_noop) +"b" = ( +/turf/simulated/wall/silver, +/area/template_noop) +"c" = ( +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"d" = ( +/obj/random/trash, +/obj/structure/inflatable/door, +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"e" = ( +/obj/machinery/artifact_scanpad, +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"f" = ( +/obj/machinery/r_n_d/server, +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"g" = ( +/obj/structure/curtain/black, +/turf/simulated/floor/carpet, +/area/template_noop) +"h" = ( +/obj/structure/inflatable/door, +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"i" = ( +/obj/structure/filingcabinet, +/obj/effect/decal/cleanable/cobweb, +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"j" = ( +/obj/structure/closet/crate/freezer/rations, +/obj/effect/decal/cleanable/cobweb2, +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"k" = ( +/obj/structure/bed/chair/wheelchair, +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"l" = ( +/obj/structure/table/marble, +/obj/item/device/flashlight/lamp, +/obj/structure/sign/monkey_painting{ + pixel_y = -32 + }, +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"m" = ( +/obj/structure/table/marble, +/obj/item/weapon/paper_bin, +/obj/random/voidhelmet, +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"n" = ( +/obj/structure/gravemarker/random, +/turf/template_noop, +/area/template_noop) +"o" = ( +/obj/structure/bookcase/manuals/xenoarchaeology, +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"p" = ( +/obj/random/junk, +/obj/random/loot, +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"q" = ( +/obj/item/weapon/pen/multi, +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"r" = ( +/mob/living/bot/medbot, +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"t" = ( +/obj/structure/bed, +/obj/item/weapon/bedsheet/rainbow, +/obj/random/drinkbottle, +/obj/random/trash, +/turf/simulated/floor/carpet, +/area/template_noop) +"u" = ( +/obj/structure/table/rack, +/obj/item/clothing/glasses/eyepatch/hud/medical, +/obj/random/loot, +/obj/random/loot, +/obj/random/hat, +/obj/random/voidsuit, +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"G" = ( +/obj/structure/sign/science_1{ + pixel_y = 32 + }, +/turf/simulated/floor/tiled/dark, +/area/template_noop) +"K" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/simulated/floor/plating, +/area/template_noop) + +(1,1,1) = {" +b +b +b +K +b +b +b +"} +(2,1,1) = {" +b +i +p +u +e +f +b +"} +(3,1,1) = {" +b +o +c +c +q +l +b +"} +(4,1,1) = {" +b +j +c +r +k +m +b +"} +(5,1,1) = {" +b +b +b +G +b +b +b +"} +(6,1,1) = {" +a +d +h +c +g +t +b +"} +(7,1,1) = {" +n +b +b +b +b +b +b +"} diff --git a/maps/random_ruins/exoplanet_ruins/hut/hut.dm b/maps/random_ruins/exoplanet_ruins/hut/hut.dm new file mode 100644 index 00000000..d64ee7a1 --- /dev/null +++ b/maps/random_ruins/exoplanet_ruins/hut/hut.dm @@ -0,0 +1,14 @@ +/datum/map_template/ruin/exoplanet/hut + name = "Hut" + id = "hut" + description = "A small and simple little research hut." + suffixes = list("hut/hut.dmm") + cost = 0.5 + + +/datum/map_template/ruin/exoplanet/wishgranter_hut + name = "Wishgranter Hut" + id = "wish_hut" + description = "A small and simple little research hut." + suffixes = list("hut/hut_two.dmm") + cost = 1 \ No newline at end of file diff --git a/maps/random_ruins/exoplanet_ruins/hut/hut.dmm b/maps/random_ruins/exoplanet_ruins/hut/hut.dmm new file mode 100644 index 00000000..d7a2e9d9 --- /dev/null +++ b/maps/random_ruins/exoplanet_ruins/hut/hut.dmm @@ -0,0 +1,31 @@ +"a" = (/turf/template_noop,/area/template_noop) +"b" = (/turf/simulated/wall,/area/mine/explored) +"c" = (/obj/structure/filingcabinet,/obj/effect/decal/cleanable/cobweb,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"d" = (/obj/structure/bookcase/manuals/xenoarchaeology,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"e" = (/obj/effect/decal/cleanable/cobweb2,/obj/random/canned_food,/obj/random/canned_food,/obj/random/canned_food,/obj/structure/closet/crate,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"f" = (/obj/random/trash,/obj/structure/inflatable/door,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"g" = (/obj/random/junk,/obj/random/loot,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"h" = (/turf/simulated/floor/tiled/dark,/area/mine/explored) +"i" = (/obj/structure/inflatable/door,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"j" = (/obj/structure/girder/reinforced,/turf/simulated/floor/plating,/area/mine/explored) +"k" = (/obj/structure/table/rack,/obj/item/clothing/glasses/eyepatch/hud/medical,/obj/random/loot,/obj/random/loot,/obj/random/hat,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"l" = (/obj/structure/sign/science_1{pixel_y = 32},/turf/simulated/floor/tiled/dark,/area/mine/explored) +"m" = (/obj/machinery/artifact_scanpad,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"n" = (/obj/structure/gravemarker/random,/turf/template_noop,/area/template_noop) +"o" = (/obj/item/weapon/pen/multi,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"p" = (/obj/structure/bed/chair/wheelchair,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"q" = (/obj/structure/curtain/black,/turf/simulated/floor/carpet,/area/mine/explored) +"r" = (/obj/machinery/r_n_d/server,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"s" = (/obj/structure/table/marble,/obj/item/device/flashlight/lamp,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"t" = (/obj/structure/table/marble,/obj/item/weapon/paper_bin,/obj/random/handgun,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"u" = (/obj/structure/bed,/obj/item/weapon/bedsheet/rainbow,/obj/random/drinkbottle,/obj/random/trash,/turf/simulated/floor/carpet,/area/mine/explored) + +(1,1,1) = {" +bbbbban +bcdebfb +bghhbib +jkhhlhb +bmopbqb +brstbub +bbbbbbb +"} diff --git a/maps/random_ruins/exoplanet_ruins/hut/hut_two.dmm b/maps/random_ruins/exoplanet_ruins/hut/hut_two.dmm new file mode 100644 index 00000000..e75025d7 --- /dev/null +++ b/maps/random_ruins/exoplanet_ruins/hut/hut_two.dmm @@ -0,0 +1,24 @@ +"a" = (/turf/simulated/wall/concrete,/area/mine/explored) +"b" = (/obj/machinery/wish_granter,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"c" = (/obj/structure/gravemarker/random,/obj/random/loot,/turf/simulated/floor/dirty/indestructable,/area/mine/explored) +"d" = (/obj/random/canned_food,/obj/random/canned_food,/obj/random/canned_food,/obj/structure/closet/crate,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"e" = (/obj/random/junk,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"f" = (/obj/structure/table/marble,/obj/item/weapon/flame/lighter/zippo,/obj/item/weapon/storage/fancy/cigarettes/jerichos,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"i" = (/turf/simulated/floor/tiled/dark,/area/mine/explored) +"j" = (/obj/structure/inflatable/door,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"l" = (/obj/structure/table/rack,/obj/item/clothing/glasses/eyepatch/hud/medical,/obj/random/loot,/obj/random/loot,/obj/random/hat,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"p" = (/obj/structure/bed/chair/wheelchair,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"q" = (/obj/structure/curtain/black,/turf/simulated/floor/carpet,/area/mine/explored) +"s" = (/obj/structure/table/marble,/obj/item/device/flashlight/lamp,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"t" = (/obj/structure/table/marble,/obj/item/weapon/paper_bin,/obj/random/handgun,/turf/simulated/floor/tiled/dark,/area/mine/explored) +"u" = (/obj/structure/bed,/obj/item/weapon/bedsheet/rainbow,/obj/random/drinkbottle,/obj/random/trash,/turf/simulated/floor/carpet,/area/mine/explored) + +(1,1,1) = {" +aaaaaaa +abcleda +aaiiiia +jiiiiia +aipiaqa +astfaua +aaaaaaa +"} diff --git a/maps/random_ruins/exoplanet_ruins/little_house.dmm b/maps/random_ruins/exoplanet_ruins/little_house.dmm new file mode 100644 index 00000000..c0c112cd --- /dev/null +++ b/maps/random_ruins/exoplanet_ruins/little_house.dmm @@ -0,0 +1,43 @@ +"a" = (/turf/simulated/wall/wood,/area/map_template/little_house) +"b" = (/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{icon_state = "rwindow"; dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/structure/grille,/turf/simulated/floor/wood,/area/map_template/little_house) +"c" = (/obj/structure/bed/chair/wood,/turf/simulated/floor/wood,/area/map_template/little_house) +"d" = (/turf/simulated/floor/wood,/area/map_template/little_house) +"e" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/turf/simulated/floor/wood,/area/map_template/little_house) +"f" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/power/debug_items/infinite_generator,/turf/simulated/floor/wood,/area/map_template/little_house) +"g" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 1},/turf/simulated/floor/wood,/area/map_template/little_house) +"h" = (/turf/simulated/floor/lino,/area/map_template/little_house) +"i" = (/obj/structure/table/glass,/obj/machinery/microwave,/turf/simulated/floor/lino,/area/map_template/little_house) +"j" = (/obj/structure/table/woodentable,/obj/item/device/flashlight/lamp/green,/turf/simulated/floor/wood,/area/map_template/little_house) +"k" = (/obj/structure/bed/chair/wood{icon_state = "wooden_chair_preview"; dir = 8},/turf/simulated/floor/wood,/area/map_template/little_house) +"l" = (/turf/simulated/floor/carpet/blue2,/area/map_template/little_house) +"m" = (/obj/structure/table/glass,/obj/machinery/light/small{dir = 4},/obj/item/weapon/reagent_containers/food/condiment/small/saltshaker,/obj/item/weapon/reagent_containers/food/condiment/small/peppermill,/turf/simulated/floor/lino,/area/map_template/little_house) +"n" = (/obj/structure/bed/chair/wood{dir = 1},/turf/simulated/floor/wood,/area/map_template/little_house) +"o" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/simulated/floor/lino,/area/map_template/little_house) +"p" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 8},/turf/simulated/floor/wood,/area/map_template/little_house) +"q" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/wood,/area/map_template/little_house) +"r" = (/obj/machinery/door/unpowered/simple/wood,/turf/simulated/floor/wood,/area/map_template/little_house) +"s" = (/obj/structure/bookcase{name = "Forbidden Knowledge"},/turf/simulated/floor/wood,/area/map_template/little_house) +"t" = (/obj/structure/table/standard{name = "plastic table frame"},/turf/simulated/floor/tiled/freezer,/area/map_template/little_house) +"u" = (/turf/simulated/floor/tiled/freezer,/area/map_template/little_house) +"v" = (/obj/machinery/door/airlock{req_access = list(5)},/turf/simulated/floor/wood,/area/map_template/little_house) +"w" = (/obj/structure/toilet{dir = 4},/turf/simulated/floor/tiled/freezer,/area/map_template/little_house) +"x" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/tiled/freezer,/area/map_template/little_house) +"y" = (/turf/template_noop,/area/template_noop) +"z" = (/obj/machinery/light/small{icon_state = "bulb1"; dir = 1},/turf/template_noop,/area/map_template/little_house) +"A" = (/obj/structure/bed,/turf/simulated/floor/wood,/area/map_template/little_house) +"B" = (/obj/structure/sink{icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2},/turf/simulated/floor/tiled/freezer,/area/map_template/little_house) +"C" = (/obj/machinery/shower{icon_state = "shower"; dir = 8},/turf/simulated/floor/tiled/freezer,/area/map_template/little_house) +"D" = (/obj/structure/closet{icon_closed = "cabinet_closed"; icon_opened = "cabinet_open"; icon_state = "cabinet_closed"; name = "Wardrobe"},/turf/simulated/floor/wood,/area/map_template/little_house) + +(1,1,1) = {" +aabaaaabaa +acdefgehia +bjkllldhmb +andllldhoa +apdddqaraa +aaraddadsa +atuavaapda +awxayzadAb +aBCayyaDja +aaaayyaaba +"} diff --git a/maps/random_ruins/exoplanet_ruins/mine_trap.dmm b/maps/random_ruins/exoplanet_ruins/mine_trap.dmm new file mode 100644 index 00000000..19e15b49 --- /dev/null +++ b/maps/random_ruins/exoplanet_ruins/mine_trap.dmm @@ -0,0 +1,18 @@ +"a" = (/obj/item/landmine,/turf/simulated/floor/dirty/indestructable,/area/mine/explored) +"b" = (/obj/structure/landmine,/turf/simulated/floor/dirty/indestructable,/area/mine/explored) +"c" = (/obj/structure/barbwire,/turf/simulated/floor/dirty/indestructable,/area/mine/explored) +"d" = (/obj/structure/barbwire,/obj/structure/barbwire,/turf/simulated/floor/dirty/indestructable,/area/mine/explored) +"e" = (/obj/structure/gravemarker/random,/obj/random/bolt_action,/obj/item/weapon/storage/bag/cash,/turf/simulated/floor/dirty/indestructable,/area/mine/explored) + +(1,1,1) = {" +bbbbbbbbbb +bcccccccdb +bcbbbbbbcb +bcbccccbcb +bcbceacbcb +bcbcaacbcb +bcbdcccbcb +bcbbbbbbcb +bdccccccdb +bbbbbbbbbb +"} diff --git a/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dm b/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dm new file mode 100644 index 00000000..b586c4c3 --- /dev/null +++ b/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dm @@ -0,0 +1,72 @@ +/datum/map_template/ruin/exoplanet/monolith + name = "Monolith Ring" + id = "planetsite_monoliths" + description = "Bunch of monoliths surrounding an artifact." + suffixes = list("monoliths/monoliths.dmm") + cost = 1 + +/obj/structure/monolith + name = "monolith" + desc = "An obviously artifical structure of unknown origin. The symbols 'DWNbTX' are engraved on the base." + icon = 'icons/obj/monolith.dmi' + icon_state = "jaggy1" + plane = ABOVE_HUMAN_PLANE + layer = ABOVE_HUMAN_LAYER + density = 1 + anchored = 1 + var/active = 0 + +/obj/structure/monolith/Initialize() + . = ..() + icon_state = "jaggy[rand(1,4)]" + var/material/A = get_material_by_name("alien alloy") + if(A) + color = A.icon_colour + if(GLOB.using_map.use_overmap) + var/obj/effect/overmap/sector/exoplanet/E = map_sectors["[z]"] + if(istype(E)) + desc += "\nThere are images on it: [E.get_engravings()]" + +/obj/structure/monolith/update_icon() + overlays.Cut() + if(active) + var/image/I = image(icon,"[icon_state]decor") + I.appearance_flags = RESET_COLOR + I.color = get_random_colour(0, 150, 255) + I.layer = ABOVE_LIGHTING_LAYER + I.plane = EFFECTS_ABOVE_LIGHTING_PLANE + overlays += I + set_light(2, 1, I.color) + +/obj/structure/monolith/attack_hand(mob/user) + visible_message("[user] touches \the [src].") + if(GLOB.using_map.use_overmap && istype(user,/mob/living/carbon/human)) + var/obj/effect/overmap/sector/exoplanet/E = map_sectors["[z]"] + if(istype(E)) + var/mob/living/carbon/human/H = user + if(!H.isSynthetic()) + active = 1 + update_icon() + if(prob(99)) + to_chat(H, "As you touch \the [src], you suddenly get a vivid image - [E.get_engravings()]") + else + to_chat(H, "An overwhelming stream of information invades your mind!") + var/vision = "" + for(var/i = 1 to 10) + vision += pick(E.actors) + " " + pick("killing","dying","gored","expiring","exploding","mauled","burning","flayed","in agony") + ". " + to_chat(H, "[uppertext(vision)]") + H.Paralyse(2) + H.hallucination(20, 100) + return + to_chat(user, "\The [src] is still.") + return ..() + +/turf/simulated/floor/fixed/alium/ruin + name = "ancient alien plating" + desc = "This obviously wasn't made for your feet. Looks pretty old." + initial_gas = null + +/turf/simulated/floor/fixed/alium/ruin/Initialize() + . = ..() + if(prob(10)) + ChangeTurf(get_base_turf_by_area(src)) \ No newline at end of file diff --git a/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dmm b/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dmm new file mode 100644 index 00000000..1c49ad29 --- /dev/null +++ b/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dmm @@ -0,0 +1,17 @@ +"a" = (/turf/template_noop,/area/template_noop) +"b" = (/obj/structure/monolith,/turf/template_noop,/area/template_noop) +"c" = (/turf/simulated/floor/fixed/alium/ruin,/area/template_noop) +"d" = (/obj/machinery/artifact,/obj/structure/window/phoronreinforced{ icon_state = "phoronrwindow"; dir = 4},/obj/structure/window/phoronreinforced{ icon_state = "phoronrwindow"; dir = 1},/obj/structure/window/phoronreinforced{ icon_state = "phoronrwindow"; dir = 8},/obj/structure/window/phoronreinforced,/turf/simulated/floor/fixed/alium/ruin,/area/template_noop) + +(1,1,1) = {" +aaaaaaaaaa +aaabaaabaa +aaaaaaaaaa +aaaaacaaaa +abaacdcaab +aaaaacaaaa +aaaaaaaaaa +aaabaaabaa +aaaaaaaaaa +aaaaaaaaaa +"} \ No newline at end of file diff --git a/maps/random_ruins/exoplanet_ruins/river.dmm b/maps/random_ruins/exoplanet_ruins/river.dmm new file mode 100644 index 00000000..cd712982 --- /dev/null +++ b/maps/random_ruins/exoplanet_ruins/river.dmm @@ -0,0 +1,9 @@ +"a" = (/turf/simulated/floor/exoplanet/water/shallow,/area/mine/explored) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/random_ruins/exoplanet_ruins/smugglers_two.dmm b/maps/random_ruins/exoplanet_ruins/smugglers_two.dmm new file mode 100644 index 00000000..721e4acc --- /dev/null +++ b/maps/random_ruins/exoplanet_ruins/smugglers_two.dmm @@ -0,0 +1,143 @@ +"aa" = (/turf/template_noop,/area/template_noop) +"ab" = (/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"ac" = (/obj/machinery/atmospherics/unary/outlet_injector{injecting = 1; use_power = 1},/turf/simulated/floor/airless,/area/template_noop) +"ad" = (/obj/structure/grille,/obj/structure/window_frame,/turf/simulated/floor,/area/smugglers/base) +"ae" = (/obj/structure/grille,/obj/machinery/door/blast/regular,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/structure/window_frame{icon_state = "window1"; dir = 10},/turf/simulated/floor,/area/smugglers/base) +"af" = (/turf/simulated/wall/r_wall,/area/smugglers/base) +"ag" = (/obj/structure/grille,/obj/machinery/door/blast/regular,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/structure/window_frame{icon_state = "window1"; dir = 6},/turf/simulated/floor,/area/smugglers/base) +"ah" = (/obj/structure/grille,/obj/machinery/door/blast/regular,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/structure/window_frame{icon_state = "window1"; dir = 5},/turf/simulated/floor,/area/smugglers/base) +"ai" = (/obj/effect/decal/cleanable/blood,/obj/effect/landmark/corpse/doctor,/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"aj" = (/obj/item/ammo_casing/a50{pixel_x = 5; pixel_y = 5},/obj/item/ammo_casing/a50,/obj/item/weapon/shovel{pixel_x = 10; pixel_y = -5},/obj/effect/decal/cleanable/blood,/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"ak" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"al" = (/obj/effect/decal/cleanable/cobweb,/turf/simulated/floor,/area/smugglers/dorms) +"am" = (/obj/machinery/light/small{dir = 4},/obj/structure/sink{pixel_y = 15},/obj/structure/mirror{pixel_y = 30},/obj/random/soap,/turf/simulated/floor,/area/smugglers/dorms) +"an" = (/obj/effect/decal/cleanable/vomit,/obj/random/medical/lite,/turf/simulated/floor,/area/smugglers/dorms) +"ao" = (/obj/structure/toilet{dir = 8},/turf/simulated/floor,/area/smugglers/dorms) +"ap" = (/obj/structure/closet/crate/plastic,/obj/random/loot,/obj/random/loot,/obj/random/smokes,/obj/random/smokes,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor,/area/smugglers/base) +"au" = (/obj/item/device/flashlight/glowstick/yellow{pixel_x = 5; pixel_y = 7},/obj/item/device/flashlight/glowstick/yellow,/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"av" = (/obj/effect/decal/cleanable/blood/drip,/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1503; id_tag = "asteroid_base_dock_airlock"; name = "Dock Airlock Controller"; pixel_x = -25; tag_airpump = "asteroid_base_dock_pump"; tag_exterior_door = "asteroid_base_dock_outer"; tag_interior_door = "asteroid_base_dock_inner"},/obj/machinery/access_button{command = "cycle_interior"; frequency = 1503; master_tag = "asteroid_base_dock_airlock"; name = "interior access button"; pixel_x = 28; pixel_y = 24; req_one_access = list(13)},/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 5},/turf/simulated/floor,/area/smugglers/base) +"aw" = (/obj/machinery/portable_atmospherics/canister/air,/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"ax" = (/obj/machinery/floodlight,/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"ay" = (/obj/item/stack/cable_coil{pixel_x = 5; pixel_y = 5; pixel_z = 0},/obj/item/stack/cable_coil,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor,/area/smugglers/base) +"az" = (/obj/machinery/power/port_gen/pacman,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"aA" = (/obj/item/stack/material/phoron{pixel_y = 7; pixel_z = -8},/obj/item/stack/material/phoron{pixel_x = -5; pixel_y = 5},/obj/item/stack/material/phoron,/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"aB" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/powered/scrubber,/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor,/area/smugglers/base) +"aC" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor,/area/smugglers/base) +"aD" = (/obj/machinery/atmospherics/pipe/manifold/visible/black{icon_state = "map"; dir = 1},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor,/area/smugglers/base) +"aE" = (/obj/machinery/door/airlock/maintenance,/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"aF" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"aG" = (/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"aH" = (/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1501; id_tag = "asteroid_base_east_airlock"; pixel_y = 25; tag_airpump = "asteroid_base_east_pump"; tag_exterior_door = "asteroid_base_east_outer"; tag_exterior_sensor = null; tag_interior_door = "asteroid_base_east_inner"; tag_interior_sensor = null},/obj/machinery/access_button{command = "cycle_interior"; frequency = 1501; master_tag = "asteroid_base_east_airlock"; name = "interior access button"; pixel_x = -28; pixel_y = 24; req_one_access = list(13)},/obj/machinery/atmospherics/pipe/simple/visible/black{dir = 4},/turf/simulated/floor,/area/smugglers/base) +"aL" = (/obj/machinery/access_button/airlock_exterior{frequency = 1501; master_tag = "asteroid_base_east_airlock"; name = "exterior access button"; pixel_x = -25; pixel_y = 25},/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"aM" = (/obj/random/trash,/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"aN" = (/obj/machinery/light/small{dir = 8},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor,/area/smugglers/base) +"aO" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor,/area/smugglers/base) +"aP" = (/obj/effect/decal/cleanable/blood/drip,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/item/weapon/wirecutters,/turf/simulated/floor,/area/smugglers/base) +"aQ" = (/obj/structure/cable,/obj/structure/cable{d1 = 32; d2 = 4; icon_state = "32-4"},/obj/structure/cable{icon_state = "0-2"; dir = 4; pixel_y = 0; d1 = 16; d2 = 0},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor,/area/smugglers/base) +"aR" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor,/area/smugglers/base) +"aS" = (/obj/effect/decal/cleanable/blood/drip,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor,/area/smugglers/base) +"aT" = (/obj/machinery/light/small{dir = 4; pixel_y = 8},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/visible/black,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor,/area/smugglers/base) +"aU" = (/turf/simulated/wall,/area/smugglers/base) +"aV" = (/obj/machinery/light/small/red{dir = 8},/turf/simulated/floor,/area/smugglers/base) +"aW" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor,/area/smugglers/base) +"aX" = (/obj/structure/table/rack{dir = 8; layer = 2.9},/obj/item/clothing/mask/breath,/turf/simulated/floor,/area/smugglers/base) +"aY" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor,/area/smugglers/base) +"aZ" = (/obj/random/trash,/turf/simulated/floor,/area/smugglers/base) +"ba" = (/obj/structure/closet/crate/plastic_smug_ammo,/obj/effect/floor_decal/industrial/warning{dir = 9},/turf/simulated/floor,/area/smugglers/base) +"bb" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/item/weapon/paper/smug_1,/turf/simulated/floor,/area/smugglers/base) +"bc" = (/obj/random/ore_smug,/obj/effect/floor_decal/industrial/warning{dir = 5},/turf/simulated/floor,/area/smugglers/base) +"bd" = (/turf/simulated/floor,/area/smugglers/base) +"be" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/visible/black,/turf/simulated/floor,/area/smugglers/base) +"bf" = (/obj/structure/table/rack{dir = 8; layer = 2.9},/obj/item/weapon/tank/air{pixel_x = 5},/obj/item/weapon/tank/air,/turf/simulated/floor,/area/smugglers/base) +"bg" = (/obj/item/weapon/pickaxe/hand{pixel_x = -15},/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"bh" = (/obj/effect/floor_decal/industrial/warning{dir = 8},/turf/simulated/floor,/area/smugglers/base) +"bi" = (/obj/structure/closet/crate/plastic_smug_weapons,/turf/simulated/floor,/area/smugglers/base) +"bk" = (/obj/machinery/floodlight,/turf/simulated/floor,/area/smugglers/base) +"bl" = (/obj/machinery/portable_atmospherics/canister/oxygen,/obj/machinery/light/small/red,/turf/simulated/floor,/area/smugglers/base) +"bm" = (/obj/structure/table/rack{dir = 8; layer = 2.9},/obj/random/voidsuit,/obj/random/voidhelmet,/turf/simulated/floor,/area/smugglers/base) +"bn" = (/obj/structure/boulder,/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"bo" = (/obj/item/weapon/ore/silver,/obj/item/weapon/ore/silver{pixel_x = 10; pixel_y = -5},/turf/simulated/floor/dirty/indestructable/lightless,/area/mine/explored) +"bp" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 8},/turf/simulated/floor,/area/smugglers/base) +"bq" = (/obj/item/weapon/paper/smug_2,/turf/simulated/floor,/area/smugglers/base) +"br" = (/obj/structure/ore_box,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/effect/floor_decal/industrial/warning{dir = 8},/turf/simulated/floor,/area/smugglers/base) +"bs" = (/obj/structure/ore_box,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/turf/simulated/floor,/area/smugglers/base) +"bt" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/turf/simulated/floor,/area/smugglers/base) +"bu" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light/small{dir = 4; pixel_y = 8},/obj/machinery/atmospherics/pipe/simple/visible/black,/turf/simulated/floor,/area/smugglers/base) +"bv" = (/turf/simulated/wall,/area/smugglers/office) +"bw" = (/turf/simulated/wall/r_wall,/area/smugglers/office) +"bx" = (/obj/item/weapon/ore/slag,/obj/item/weapon/ore/slag{pixel_x = 5; pixel_y = -2},/obj/item/weapon/ore/slag,/turf/simulated/floor,/area/smugglers/base) +"by" = (/obj/structure/ore_box,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/random/ore_smug,/obj/effect/floor_decal/industrial/warning{dir = 8},/turf/simulated/floor,/area/smugglers/base) +"bz" = (/obj/random/ore_smug,/turf/simulated/floor,/area/smugglers/base) +"bA" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/binary/pump{dir = 1},/turf/simulated/floor,/area/smugglers/base) +"bB" = (/obj/machinery/door/airlock/maintenance,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor,/area/smugglers/office) +"bC" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/office) +"bD" = (/obj/structure/table/woodentable,/obj/item/weapon/paper,/obj/item/weapon/pen,/obj/item/device/flashlight/lamp,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/tiled,/area/smugglers/office) +"bE" = (/obj/structure/safe/floor,/obj/random/contraband,/obj/random/contraband,/obj/random/loot,/obj/random/projectile,/obj/random/cash,/obj/random/cash,/obj/random/cash,/turf/simulated/floor/tiled,/area/smugglers/office) +"bF" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor,/area/smugglers/base) +"bG" = (/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor,/area/smugglers/base) +"bH" = (/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor,/area/smugglers/base) +"bI" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor,/area/smugglers/base) +"bJ" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/office) +"bK" = (/obj/structure/table/woodentable,/obj/random/coin{pixel_x = -5; pixel_y = -3},/obj/random/coin,/obj/item/weapon/storage/bible/booze{pixel_x = 10},/obj/item/weapon/paper/smug_4{pixel_x = -5; pixel_y = 4},/obj/item/weapon/paper/smug_5,/turf/simulated/floor/tiled,/area/smugglers/office) +"bL" = (/obj/structure/bed/chair/comfy/red{dir = 8},/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/smugglers/office) +"bM" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor,/area/smugglers/base) +"bN" = (/obj/machinery/atmospherics/portables_connector,/obj/machinery/portable_atmospherics/powered/scrubber,/turf/simulated/floor,/area/smugglers/base) +"bO" = (/obj/machinery/portable_atmospherics/canister/air,/obj/item/weapon/wrench,/obj/machinery/light/small{dir = 4; pixel_y = 8},/turf/simulated/floor,/area/smugglers/base) +"bP" = (/mob/living/simple_animal/hostile/retaliate/malf_drone,/turf/simulated/floor/tiled,/area/smugglers/office) +"bQ" = (/turf/simulated/floor/tiled,/area/smugglers/office) +"bR" = (/obj/structure/table/standard,/obj/random/tech_supply,/turf/simulated/floor,/area/smugglers/base) +"bS" = (/obj/structure/table/standard,/obj/random/toolbox,/turf/simulated/floor,/area/smugglers/base) +"bT" = (/obj/structure/table/standard,/obj/random/firstaid,/turf/simulated/floor,/area/smugglers/base) +"bU" = (/obj/structure/closet/crate/trashcart,/turf/simulated/floor,/area/smugglers/base) +"bV" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor,/area/smugglers/base) +"bW" = (/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor,/area/smugglers/base) +"bX" = (/obj/machinery/constructable_frame/machine_frame,/obj/random/trash,/turf/simulated/floor/tiled,/area/smugglers/office) +"bY" = (/obj/structure/table/rack,/obj/item/clothing/head/cowboy_hat,/obj/item/clothing/suit/armor/hos/jensen,/turf/simulated/floor/tiled,/area/smugglers/office) +"bZ" = (/obj/structure/filingcabinet/chestdrawer,/turf/simulated/floor/tiled,/area/smugglers/office) +"ca" = (/turf/simulated/wall/r_wall,/area/smugglers/dorms) +"cb" = (/obj/machinery/door/airlock/maintenance{name = "Restroom"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor,/area/smugglers/dorms) +"cc" = (/turf/simulated/wall,/area/smugglers/dorms) +"cd" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/smugglers/dorms) +"ce" = (/obj/structure/noticeboard{pixel_y = 30},/obj/effect/decal/cleanable/dirt,/obj/structure/table/standard,/obj/machinery/microwave{pixel_y = 10},/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cf" = (/obj/effect/decal/cleanable/dirt,/obj/structure/closet/crate,/obj/random/snack,/obj/random/snack,/obj/random/snack,/obj/random/snack,/obj/random/snack,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cg" = (/obj/effect/decal/cleanable/dirt,/obj/structure/closet/crate,/obj/random/drinkbottle,/obj/random/drinkbottle,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"ch" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/computer/arcade,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"ci" = (/obj/structure/closet/crate/freezer/rations,/obj/effect/decal/cleanable/cobweb2,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cl" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/obj/structure/cable,/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cm" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cn" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"co" = (/obj/machinery/door/airlock/maintenance{name = "Toilet"},/turf/simulated/floor,/area/smugglers/dorms) +"cr" = (/obj/structure/bed/chair{dir = 4},/obj/machinery/light,/obj/random/trash,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cs" = (/obj/structure/table/standard,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/paper/smug_3,/obj/item/weapon/flame/lighter/random,/obj/random/coin,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"ct" = (/obj/structure/table/standard,/obj/effect/decal/cleanable/dirt,/obj/item/weapon/spacecash/bundle/c10,/obj/random/smokes,/obj/random/snack,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cu" = (/obj/structure/bed/chair{dir = 8},/obj/machinery/light,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cv" = (/obj/structure/closet,/obj/effect/decal/cleanable/dirt,/obj/random/medical,/obj/random/medical,/obj/random/tech_supply,/obj/random/action_figure,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cw" = (/obj/machinery/door/airlock/maintenance,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cx" = (/obj/structure/bed,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cy" = (/obj/structure/closet/smuggler,/obj/random/suit,/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cz" = (/obj/structure/bed,/obj/effect/decal/cleanable/dirt,/mob/living/simple_animal/hostile/retaliate/malf_drone,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cA" = (/obj/effect/decal/cleanable/dirt,/obj/random/trash,/turf/simulated/floor/tiled,/area/smugglers/dorms) +"cB" = (/obj/machinery/light/small{dir = 2},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/tiled,/area/smugglers/dorms) + +(1,1,1) = {" +afbdafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiajakakaaaaaaaa +adbdafaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaababababab +afbdafafafafafaeagahafafafafafadafauaaaaaaaaabaaaaaaababababab +afavawaxayazaAaBaCaDaEaFaGaHbdbdbdaLababaaaaabaaababaMabababab +afaNaOaPaQaQaOaRaSaTaUaVaWaXafafafaaabababababababababaaababab +afaYaZbabbbcbdbdaZbeaUaZbdbfafaaaaaaaaaaaaaabgababaaaaabababab +afaYbdbhbiapbdbdbdbeaUbkblbmafaaaaaaaaaaaaaabnboabaaaaabaaaaaa +afbpbqbrbsbtbdaZbdbubvbvbvbvbwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +afaYbxbybzbtbdbdbdbAbBbCbDbEbwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +afaYaZbFbGbHbdbdbdbIbvbJbKbLbwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +afbpbdbdbdbdbMbNbdbObvbJbPbQbwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +afaYaZbRbSbTbUbVbdbWbvbXbYbZbwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +cacbcccccccccccccccccabwbwbwbwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +cacdcecfcgchciccalamcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +caclcmcmcmcmcncoanaocaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +cacmcrcsctcucvcccacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +cacwcccccccccccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +cacmcxcyczcycxcycaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +cacAcBcmcmcmcBcmcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +cacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/random_ruins/exoplanet_ruins/water.dmm b/maps/random_ruins/exoplanet_ruins/water.dmm new file mode 100644 index 00000000..ec5ab265 --- /dev/null +++ b/maps/random_ruins/exoplanet_ruins/water.dmm @@ -0,0 +1,37 @@ +"a" = (/turf/simulated/floor/exoplanet/water/shallow,/area/mine/explored) +"b" = (/turf/template_noop,/area/template_noop) + +(1,1,1) = {" +abbbbbbbbbbbbbbbbbbbbbbbbbbaaaaa +aabbbbbbbbbbbbbbbbbbbbbbbaaaaaaa +aabbbbbbbbbbbbbbbbbbbbbbaaaaabbb +aabbbbbbbbbbbbbbbbbbbbbaaabbbbbb +aabbbbbbbbbbbbbbbbbbbbbaabbbbbbb +baaabbbbbbbbbbbbbbbbbbbaabbbbbbb +bbaaaabbbbbbbbbbbbbbbbaaabbbbbbb +bbbaaabbbbbbbbbbbbbbbaaabbbbbbbb +bbbbbaabbbbbbbbbbbbbaaaabbbbbbbb +bbbbbbaabbbbbbbbbbaaaaabbbbbbbbb +bbbbbbbaaabbbbbbbaaaaabbbbbbbbbb +bbbbbbbbaaabbbbbaaaabbbbbbbbbbbb +bbbbbbbbbaaaaaaaaaabbbbbbbbbbbbb +bbbbbbbbbbaaaaaaabbbbbbbbbbbbbbb +bbbbbbbbbbbbaaaaabbbbbbbbbbbbbbb +bbbbbbbbbbbbaaaaabbbbbbbbbbbbbbb +bbbbbbbbbbbbaaaaaaabbbbbbbbbbbbb +bbbbbbbbbbbaabbbaaaabbbbbbbbbbbb +bbbbbbbbbbaaabbbbbaaabbbbbbbbbbb +bbbbbbbbbbaabbbbbbbaaabbbbbbbbbb +bbbbbbbbbaaabbbbbbbbaaabbbbbbbbb +bbbbbbbbbaabbbbbbbbbbbaaabbbbbbb +bbbbbbbbaabbbbbbbbbbbbbaaabbbbbb +bbbbbbbaaabbbbbbbbbbbbbbaaabbbbb +bbbbbbaaabbbbbbbbbbbbbbbbaabbbbb +bbbbbbaabbbbbbbbbbbbbbbbbbaabbbb +bbbbaaaabbbbbbbbbbbbbbbbbbbaabbb +bbbbaaabbbbbbbbbbbbbbbbbbbbbaabb +bbbaaabbbbbbbbbbbbbbbbbbbbbbbaab +bbaaabbbbbbbbbbbbbbbbbbbbbbbbaaa +aaaabbbbbbbbbbbbbbbbbbbbbbbbbbaa +aaabbbbbbbbbbbbbbbbbbbbbbbbbbbaa +"} diff --git a/maps/random_ruins/space_ruins/multi_zas_test.dmm b/maps/random_ruins/space_ruins/multi_zas_test.dmm new file mode 100644 index 00000000..c8fd257e --- /dev/null +++ b/maps/random_ruins/space_ruins/multi_zas_test.dmm @@ -0,0 +1,30 @@ +"a" = (/turf/simulated/wall/diamond,/area/template_noop) +"b" = (/turf/simulated/floor,/area/template_noop) +"c" = (/mob/living/simple_animal/corgi,/turf/simulated/floor,/area/template_noop) +"d" = (/turf/simulated/open,/area/template_noop) +"e" = (/turf/unsimulated/floor/shuttle_ceiling,/area/template_noop) +"f" = (/obj/effect/landmark/map_data{height = 3},/turf/unsimulated/floor/shuttle_ceiling,/area/template_noop) + +(1,1,1) = {" +aaaaa +abbba +abcba +abbba +aaaaa +"} + +(1,1,2) = {" +aaaaa +addda +addda +addda +aaaaa +"} + +(1,1,3) = {" +eeeee +eeeee +eeeee +eeeee +feeee +"} diff --git a/maps/random_ruins/space_ruins/space_ruins.dm b/maps/random_ruins/space_ruins/space_ruins.dm new file mode 100644 index 00000000..06fa03c1 --- /dev/null +++ b/maps/random_ruins/space_ruins/space_ruins.dm @@ -0,0 +1,13 @@ +// Hey! Listen! Update \config\space_ruin_blacklist.txt with your new ruins! + +/datum/map_template/ruin/space + prefix = "maps/random_ruins/space_ruins/" + cost = 1 + allow_duplicates = FALSE + +/datum/map_template/ruin/space/multi_zas_test + name = "Multi-ZAS Test" + id = "multi_zas_test" + description = "if this has vacuum in it, that's not good!" + suffixes = list("multi_zas_test.dmm") + cost = 1 \ No newline at end of file diff --git a/maps/shared/card.dmi b/maps/shared/card.dmi new file mode 100644 index 00000000..2b1b51fb Binary files /dev/null and b/maps/shared/card.dmi differ diff --git a/maps/shared/items/cards_ids.dm b/maps/shared/items/cards_ids.dm new file mode 100644 index 00000000..f6403773 --- /dev/null +++ b/maps/shared/items/cards_ids.dm @@ -0,0 +1,40 @@ + +/obj/item/weapon/card/id/shared + icon = 'maps/shared/card.dmi' + +/obj/item/weapon/card/id/shared/gold + icon_state = "gold" + job_access_type = /datum/job/captain + + +/obj/item/weapon/card/id/shared/hop + icon_state = "id_hop" + job_access_type = /datum/job/hop + + +/obj/item/weapon/card/id/shared/engineer + icon_state = "id_engie" + job_access_type = /datum/job/engineer + + +/obj/item/weapon/card/id/shared/chaplain + icon_state = "id_chaplain" + job_access_type = /datum/job/chaplain + + +/obj/item/weapon/card/id/shared/hos + icon_state = "id_hos" + job_access_type = /datum/job/hos + + +/obj/item/weapon/card/id/shared/sec + icon_state = "id_sec" + job_access_type = /datum/job/officer + + +/obj/item/weapon/card/id/shared/rd + icon_state = "id_rd" + job_access_type = /datum/job/rd + +/obj/item/weapon/card/id/shared/cargo + job_access_type = /datum/job/cargo_tech \ No newline at end of file diff --git a/maps/shared/items/clothing.dm b/maps/shared/items/clothing.dm new file mode 100644 index 00000000..8e27b770 --- /dev/null +++ b/maps/shared/items/clothing.dm @@ -0,0 +1,60 @@ +//I'LL MOVE THIS SOMEWHERE ELSE SOON AS I GET TO IT +/obj/item/clothing/under/rank/undertaker + name = "undertaker's uniform" + desc = "A suit worn by that creepy guy who messes with dead bodies." + icon_state = "undertaker" + worn_state = "undertaker" + item_state = "undertaker" + + +/obj/item/clothing/suit/undertaker + name = "undertaker's garments" + desc = "To protect you from the disease of the dead." + icon_state = "undertaker" + item_state = "undertaker" + +/obj/item/clothing/mask/gas/undertaker + name = "undertaker's helm" + desc = "To ward off the evil smells." + icon_state = "undertaker" + item_state = "undertaker" + +/obj/item/clothing/gloves/undertaker + name = "undertaker's gloves" + desc = "To keep you from touching those gross dead people." + icon_state = "undertaker" + item_state = "undertaker" + +/obj/item/clothing/shoes/undertaker//Child of jackboots to avoid copy and paste. + name = "undertaker's boots" + desc = "Better to use these to step in blood, than your bare feet." + icon_state = "undertaker" + item_state = "undertaker" + + +/obj/item/clothing/suit/armor/vest/opvest + name = "armored vest" + desc = "It provides some armor and some storage. Not really the best at either though." + icon_state = "opvest" + item_state = "opvest" + armor = list(melee = 60, bullet = 35, laser = 40, energy = 35, bomb = 30, bio = 0, rad = 0) + + +/obj/item/clothing/suit/armor/vest/opvest/norifle + allowed = list(/obj/item/device/radio,/obj/item/weapon/reagent_containers/spray/pepper,/obj/item/ammo_magazine,/obj/item/ammo_casing) + +/obj/item/clothing/head/helmet/siege + name = "seige helmet" + desc = "Better than a baseball cap. But not by much." + icon_state = "siege_helmet" + item_state = "siege_helmet" + armor = list(melee = 50, bullet = 25, laser = 35, energy = 35, bomb = 30, bio = 0, rad = 0) + +/obj/item/clothing/under/syndicate/soldier + name = "underclothing" + desc = "Some old garmets. Fit for a soldier." + +/obj/item/clothing/gloves/thick/swat/combat + name = "combat gloves" + desc = "Thick black gloves that make you feel empowered." + armor = list(melee = 25, bullet = 50, laser = 50,energy = 25, bomb = 30, bio = 0, rad = 0) \ No newline at end of file diff --git a/maps/system/RickenBacker-overall.dmm b/maps/system/RickenBacker-overall.dmm new file mode 100644 index 00000000..6427aca8 --- /dev/null +++ b/maps/system/RickenBacker-overall.dmm @@ -0,0 +1,5267 @@ +"aa" = (/turf/space,/area/space) +"ab" = (/turf/simulated/wall,/area/space) +"ac" = (/turf/simulated/floor/plating,/area/space) +"ad" = (/turf/simulated/floor/tiled,/area/space) +"ae" = (/obj/structure/stairs/zlong/east,/turf/simulated/floor/tiled,/area/space) +"af" = (/obj/structure/stairs/zlong/west,/turf/simulated/floor/tiled,/area/space) +"ag" = (/obj/structure/stairs/west,/turf/simulated/floor/tiled,/area/space) +"ah" = (/obj/structure/stairs/zlong/west,/turf/simulated/floor/tiled/dark,/area/space) +"ai" = (/turf/simulated/floor/tiled/dark,/area/space) +"aj" = (/obj/structure/stairs/zlong/east,/turf/simulated/floor/tiled/dark,/area/space) +"ak" = (/obj/structure/stairs/west,/turf/space,/area/space) +"al" = (/obj/structure/ladder/up,/turf/simulated/floor/tiled,/area/space) +"am" = (/obj/machinery/cryopod{tag = "icon-body_scanner_0"; icon_state = "body_scanner_0"; dir = 2},/turf/simulated/floor/tiled/white,/area/space) +"an" = (/turf/simulated/floor/tiled/white,/area/space) +"ao" = (/obj/machinery/cryopod{tag = "icon-body_scanner_0 (EAST)"; icon_state = "body_scanner_0"; dir = 4},/turf/simulated/floor/tiled/white,/area/space) +"ap" = (/obj/machinery/cryopod,/turf/simulated/floor/tiled/white,/area/space) +"aq" = (/obj/effect/floor_decal/turf/plating,/turf/simulated/floor/plating,/area/space) +"ar" = (/turf/simulated/floor/tiled/freezer,/area/space) +"as" = (/obj/structure/stairs/zlong/south,/turf/simulated/floor/tiled,/area/space) +"at" = (/turf/simulated/open,/area/space) +"au" = (/turf/simulated/floor/tiled/ramp/bottom{tag = "icon-rampbot (EAST)"; icon_state = "rampbot"; dir = 4},/area/space) +"av" = (/obj/structure/crematorium,/turf/simulated/floor/tiled,/area/space) +"aw" = (/obj/structure/stairs/north,/turf/simulated/floor/tiled,/area/space) +"ax" = (/obj/structure/morgue{dir = 8},/turf/simulated/floor/tiled/dark,/area/space) +"ay" = (/obj/structure/catwalk,/turf/simulated/floor/plating,/area/space) +"az" = (/obj/structure/railing{tag = "icon-railing0 (WEST)"; icon_state = "railing0"; dir = 8},/turf/simulated/open,/area/space) +"aA" = (/obj/structure/railing{tag = "icon-railing0 (WEST)"; icon_state = "railing0"; dir = 8},/obj/structure/railing,/turf/simulated/open,/area/space) +"aB" = (/obj/structure/ladder,/turf/simulated/floor/plating,/area/space) +"aC" = (/obj/structure/railing{tag = "icon-railing0 (NORTH)"; icon_state = "railing0"; dir = 1},/turf/simulated/open,/area/space) +"aD" = (/obj/structure/railing{tag = "icon-railing0 (EAST)"; icon_state = "railing0"; dir = 4},/turf/simulated/open,/area/space) +"aE" = (/obj/structure/ladder/updown,/turf/simulated/floor/tiled,/area/space) +"aF" = (/obj/machinery/cryopod/robot,/turf/simulated/floor/tiled,/area/space) +"aG" = (/obj/structure/catwalk,/obj/structure/railing{tag = "icon-railing0 (WEST)"; icon_state = "railing0"; dir = 8},/turf/simulated/open,/area/space) +"aH" = (/obj/structure/railing{tag = "icon-railing0 (NORTH)"; icon_state = "railing0"; dir = 1},/obj/structure/railing{tag = "icon-railing0 (EAST)"; icon_state = "railing0"; dir = 4},/turf/simulated/open,/area/space) +"aI" = (/obj/structure/railing{tag = "icon-railing0 (WEST)"; icon_state = "railing0"; dir = 8},/obj/structure/railing{tag = "icon-railing0 (NORTH)"; icon_state = "railing0"; dir = 1},/turf/simulated/open,/area/space) +"aJ" = (/obj/structure/railing,/turf/simulated/open,/area/space) +"aK" = (/obj/structure/railing{tag = "icon-railing0 (EAST)"; icon_state = "railing0"; dir = 4},/obj/structure/railing,/turf/simulated/open,/area/space) +"aL" = (/obj/structure/railing{tag = "icon-railing0 (WEST)"; icon_state = "railing0"; dir = 8},/obj/structure/railing{tag = "icon-railing0 (NORTH)"; icon_state = "railing0"; dir = 1},/turf/simulated/floor/plating,/area/space) +"aM" = (/obj/structure/railing{tag = "icon-railing0 (NORTH)"; icon_state = "railing0"; dir = 1},/obj/structure/railing{tag = "icon-railing0 (EAST)"; icon_state = "railing0"; dir = 4},/turf/simulated/floor/plating,/area/space) +"aN" = (/obj/structure/railing{tag = "icon-railing0 (NORTH)"; icon_state = "railing0"; dir = 1},/obj/structure/railing{tag = "icon-railing0 (WEST)"; icon_state = "railing0"; dir = 8},/turf/simulated/floor/plating,/area/space) +"aO" = (/obj/structure/railing{tag = "icon-railing0 (NORTH)"; icon_state = "railing0"; dir = 1},/turf/simulated/floor/plating,/area/space) +"aP" = (/obj/structure/railing{tag = "icon-railing0 (EAST)"; icon_state = "railing0"; dir = 4},/obj/structure/railing{tag = "icon-railing0 (NORTH)"; icon_state = "railing0"; dir = 1},/turf/simulated/floor/plating,/area/space) +"aQ" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/structure/catwalk,/turf/simulated/open,/area/space) +"aR" = (/turf/simulated/floor/tiled/ramp/bottom{tag = "icon-rampbot (WEST)"; icon_state = "rampbot"; dir = 8},/area/space) +"aS" = (/obj/machinery/door/airlock/hydroponics{name = "Water Storage"; req_access = list(35)},/turf/simulated/floor/tiled/white,/area/space) +"aT" = (/obj/effect/floor_decal/industrial/warning_white/corner{tag = "icon-warningcorner_white (EAST)"; icon_state = "warningcorner_white"; dir = 4},/turf/simulated/floor/tiled/white,/area/space) +"aU" = (/obj/effect/floor_decal/industrial/warning_white{tag = "icon-warning_white (NORTH)"; icon_state = "warning_white"; dir = 1},/turf/simulated/floor/tiled/white,/area/space) +"aV" = (/obj/effect/floor_decal/industrial/warning_white/corner{tag = "icon-warningcorner_white (NORTH)"; icon_state = "warningcorner_white"; dir = 1},/obj/effect/floor_decal/industrial/warning_white/corner{tag = "icon-warningcorner_white (EAST)"; icon_state = "warningcorner_white"; dir = 4},/turf/simulated/floor/tiled/white,/area/space) +"aW" = (/obj/effect/floor_decal/industrial/warning_white/corner{tag = "icon-warningcorner_white (EAST)"; icon_state = "warningcorner_white"; dir = 4},/obj/effect/floor_decal/industrial/warning_white/corner{tag = "icon-warningcorner_white (NORTH)"; icon_state = "warningcorner_white"; dir = 1},/turf/simulated/floor/tiled/white,/area/space) +"aX" = (/obj/effect/floor_decal/industrial/warning_white/corner{tag = "icon-warningcorner_white (NORTH)"; icon_state = "warningcorner_white"; dir = 1},/turf/simulated/floor/tiled/white,/area/space) +"aY" = (/obj/machinery/door/airlock/hydroponics{name = "Hydro"; req_access = list(35)},/turf/simulated/floor/tiled/dark,/area/space) +"aZ" = (/obj/effect/floor_decal/industrial/warning/corner,/turf/simulated/floor/tiled/dark,/area/space) +"ba" = (/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/tiled/dark,/area/space) +"bb" = (/obj/effect/floor_decal/industrial/warning_white/corner,/turf/simulated/floor/tiled/white,/area/space) +"bc" = (/obj/effect/floor_decal/industrial/warning_white,/turf/simulated/floor/tiled/white,/area/space) +"bd" = (/obj/effect/floor_decal/industrial/warning_white/corner{tag = "icon-warningcorner_white (WEST)"; icon_state = "warningcorner_white"; dir = 8},/turf/simulated/floor/tiled/white,/area/space) +"be" = (/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/tiled/dark,/area/space) +"bf" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled/dark,/area/space) +"bg" = (/obj/structure/stairs/west,/turf/simulated/floor/tiled/white,/area/space) +"bh" = (/obj/machinery/vending/coffee,/obj/effect/floor_decal/spline/plain{dir = 8},/turf/simulated/floor/tiled/dark,/area/space) +"bi" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/grille,/turf/simulated/floor/plating,/area/space) +"bj" = (/obj/structure/catwalk,/obj/structure/ladder,/turf/simulated/open,/area/space) +"bk" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/grille,/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/space) +"bl" = (/obj/structure/flora/pottedplant/minitree,/turf/simulated/floor/lino,/area/space) +"bm" = (/obj/machinery/vending/cigarette,/obj/effect/floor_decal/spline/plain{dir = 8},/turf/simulated/floor/tiled/dark,/area/space) +"bn" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/grille,/turf/simulated/floor/plating,/area/space) +"bo" = (/obj/structure/catwalk,/turf/simulated/open,/area/space) +"bp" = (/obj/machinery/door/airlock/maintenance_hatch{req_access = list(35)},/turf/simulated/floor/tiled/dark,/area/space) +"bq" = (/obj/machinery/vending/snack,/obj/effect/floor_decal/spline/plain{dir = 8},/turf/simulated/floor/tiled/dark,/area/space) +"br" = (/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/grille,/turf/simulated/floor/plating,/area/space) +"bs" = (/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 4},/turf/simulated/floor/tiled/dark,/area/space) +"bt" = (/obj/effect/floor_decal/industrial/warning{dir = 5},/turf/simulated/floor/tiled/dark,/area/space) +"bu" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/turf/simulated/floor/tiled/dark,/area/space) +"bv" = (/obj/effect/floor_decal/industrial/warning_white/corner{tag = "icon-warningcorner_white (WEST)"; icon_state = "warningcorner_white"; dir = 8},/obj/effect/floor_decal/industrial/warning_white/corner,/turf/simulated/floor/tiled/white,/area/space) +"bw" = (/obj/effect/floor_decal/industrial/warning_white/corner,/obj/effect/floor_decal/industrial/warning_white/corner{tag = "icon-warningcorner_white (WEST)"; icon_state = "warningcorner_white"; dir = 8},/turf/simulated/floor/tiled/white,/area/space) +"bx" = (/obj/structure/ladder,/obj/structure/catwalk,/turf/simulated/floor/plating,/area/space) +"by" = (/obj/structure/ladder,/turf/simulated/floor/tiled,/area/space) +"bz" = (/obj/structure/lattice,/turf/simulated/open,/area/space) +"bA" = (/obj/machinery/portable_atmospherics/hydroponics,/turf/simulated/floor/tiled,/area/space) +"bB" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/effect/floor_decal/spline/plain{tag = "icon-spline_plain (EAST)"; icon_state = "spline_plain"; dir = 4},/turf/simulated/floor/tiled,/area/space) +"bC" = (/obj/structure/reagent_dispensers/watertank,/obj/item/weapon/reagent_containers/glass/bucket,/turf/simulated/floor/tiled/white,/area/space) +"bD" = (/obj/machinery/portable_atmospherics/hydroponics,/turf/simulated/floor/tiled/white,/area/space) +"bE" = (/obj/structure/railing,/obj/effect/floor_decal/spline/plain,/turf/simulated/floor/tiled,/area/space) +"bF" = (/obj/structure/railing,/obj/effect/floor_decal/spline/plain{tag = "icon-spline_plain (SOUTHEAST)"; icon_state = "spline_plain"; dir = 6},/turf/simulated/floor/tiled,/area/space) +"bG" = (/obj/structure/flora/pottedplant/minitree,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor/tiled/dark,/area/space) +"bH" = (/obj/machinery/door/airlock/glass_hydroponics{name = "Hydroponics"; req_access = list(35)},/turf/simulated/floor/tiled/dark,/area/space) +"bI" = (/obj/item/weapon/stool/bar/padded,/obj/effect/floor_decal/industrial/warning{dir = 8},/turf/simulated/floor/tiled/dark,/area/space) +"bJ" = (/obj/machinery/vending/hydroseeds,/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled/dark,/area/space) +"bK" = (/obj/structure/lattice,/obj/structure/railing,/obj/structure/railing{tag = "icon-railing0 (WEST)"; icon_state = "railing0"; dir = 8},/turf/simulated/open,/area/space) +"bL" = (/obj/structure/lattice,/obj/structure/railing,/turf/simulated/open,/area/space) +"bM" = (/obj/structure/lattice,/obj/structure/railing,/obj/structure/railing{tag = "icon-railing0 (EAST)"; icon_state = "railing0"; dir = 4},/turf/simulated/open,/area/space) +"bN" = (/obj/effect/floor_decal/industrial/warning{dir = 8},/turf/simulated/floor/tiled/dark,/area/space) +"bO" = (/obj/structure/table/standard,/obj/effect/floor_decal/industrial/warning{dir = 8},/turf/simulated/floor/tiled/dark,/area/space) +"bP" = (/obj/effect/floor_decal/industrial/warning/corner,/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 4},/turf/simulated/floor/tiled/dark,/area/space) +"bQ" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/tiled/dark,/area/space) +"bR" = (/obj/effect/floor_decal/industrial/warning/corner{dir = 1},/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 8},/turf/simulated/floor/tiled/dark,/area/space) +"bS" = (/obj/effect/floor_decal/turf/shaft{tag = "icon-shaft (NORTH)"; icon_state = "shaft"; dir = 1},/obj/structure/railing{tag = "icon-railing0 (WEST)"; icon_state = "railing0"; dir = 8},/obj/effect/floor_decal/industrial/warning{dir = 8},/turf/simulated/floor/plating,/area/space) +"bT" = (/obj/effect/floor_decal/turf/shaft{tag = "icon-shaft (NORTH)"; icon_state = "shaft"; dir = 1},/turf/simulated/floor/plating,/area/space) +"bU" = (/obj/machinery/door/airlock/maintenance_hatch{req_access = list(35)},/turf/simulated/floor/plating,/area/space) +"bV" = (/obj/item/weapon/stool/bar/padded{tag = "icon-bar_stool_padded_preview (NORTH)"; icon_state = "bar_stool_padded_preview"; dir = 1},/obj/effect/floor_decal/industrial/warning{dir = 8},/turf/simulated/floor/tiled/dark,/area/space) +"bW" = (/obj/machinery/vending/hydronutrients,/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled/dark,/area/space) +"bX" = (/obj/structure/lattice,/obj/structure/railing{tag = "icon-railing0 (NORTH)"; icon_state = "railing0"; dir = 1},/obj/structure/railing{tag = "icon-railing0 (WEST)"; icon_state = "railing0"; dir = 8},/turf/simulated/open,/area/space) +"bY" = (/obj/structure/lattice,/obj/structure/railing{tag = "icon-railing0 (NORTH)"; icon_state = "railing0"; dir = 1},/turf/simulated/open,/area/space) +"bZ" = (/obj/structure/lattice,/obj/structure/railing{tag = "icon-railing0 (NORTH)"; icon_state = "railing0"; dir = 1},/obj/structure/railing{tag = "icon-railing0 (EAST)"; icon_state = "railing0"; dir = 4},/turf/simulated/open,/area/space) +"ca" = (/obj/structure/flora/pottedplant/minitree,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor/tiled/dark,/area/space) +"cb" = (/obj/structure/railing{tag = "icon-railing0 (NORTH)"; icon_state = "railing0"; dir = 1},/obj/effect/floor_decal/spline/plain{dir = 1},/turf/simulated/floor/tiled,/area/space) +"cc" = (/obj/structure/railing{tag = "icon-railing0 (NORTH)"; icon_state = "railing0"; dir = 1},/obj/effect/floor_decal/spline/plain{tag = "icon-spline_plain (NORTHEAST)"; icon_state = "spline_plain"; dir = 5},/turf/simulated/floor/tiled,/area/space) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,2) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,3) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,4) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,5) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacababababacacabaaabacacabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadadabadadabaaabadadabadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadabadadabadadabababadadabadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadabadadabadadadadabadadabadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadabadadabadadadadabadadabadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababadabababababababadababadabababababadababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacadadadadadadadadadaeabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabafadadadadadadadadadadadadadadadadadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacadadadadadabacacabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadadadadadabadadadabadadadadadabagadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababadacacabadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababacacababacacababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabahaiaiaiaiaiaiajabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaabahaiaiaiaiaiaiajabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacacacabaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacacacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacacacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababadadadadadababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacabacacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabakadadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabakadadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaladadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabakadadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadabadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabamamamamamamabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabananananananabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababanababanabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababadadadadadadadadadadababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaoanabananadadananabanapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababadadadabadadadadadadadadadadacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaoanananadadadadanananapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadabadadadababadadadadadadadadadababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaoanabadadababadadabanapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadadadadacadadadadadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaoanabadadababadadabanapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadadadadacadadadabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaoanananadadadadanananapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaoanabananadadananabanapabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababacacabacababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacababababacacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacacacacacacacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababacacacacabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaqaqaqaqaqabaqaqabaqaqaqaqaqabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaqaqaqaqaqaqaqaqaqaqaqaqaqaqabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaqaqaqaqaqaqaqaqaqaqaqaqaqaqabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaqaqaqaqababaqaqaqaqaqabaqaqabaqaqaqaqaqabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaqaqaqaqaqaqababaqaqaqababababababaqaqaqabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqaqabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaqaqaqaqaqaqababaqaqaqababababababaqaqaqabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaqaqaqaqababaqaqaqaqaqabaqaqabaqaqaqaqaqabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaqaqaqaqaqaqaqaqaqaqaqaqaqaqabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaqaqaqaqaqaqaqaqaqaqaqaqaqaqabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaqaqaqaqaqabaqaqabaqaqaqaqaqabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,6) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababacacabacacabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadadadadabadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababaaabadadadadadadadadadababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababacacababababababacacacabacacacababaaaaaaabadadabarabadadabadadabaaabasadadadadadadadadadabababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadabadadadadadacatatatatatatadadadadabaaaaaaabadadararabadadabadadabaaababadadadadadadadadadabadadadatatatatatatatadadadadadatatatatatatatatatatabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadabadadadadadacadadadadadadadadadadabaaaaaaabadadabarabadadabadadabaaabadadadadadadadadadadabadadadadadadadadadadadadadadadadadadadadadadatatatabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadadadabadadababadatatababababadadababababababadababababadabadabababababababadadadababababababadadababacababacabababababacabababacabacacababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadabadadabadadadacadatatabadadadadadadacadadadadadadadadadadadadadacadadadadadadadadadadadadadadadadabadadabadadadadadadabadadabadadabarararabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababadadadauadatatabadadadadadadacadadadadadadadadadadadadadacadadadadadadadadadadadadadadadadabadadabadadadadadadabadadabadadabarararabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababatatatabadadababababababababadadababababababababababadadabacacabadabababadadababababadadabadadadabadadabadadabadadabararababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababadadabaaaaaaaaaaaaabacacabaaaaaaaaaaabavabababababadadadadadadabacacabadadabadadabababababadadabababababababarararabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadacadadabaaaaaaaaaaaaabaiaiabaaabababababadadawadaxabadadadadadadabaiaiabadadadadadabaaaaaaababababaaaaaaaaababarabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababadadadadadadabaaababababababaiaiabaaabadadadabadadadadaxabadadadadadadabaiaiabadadadadadabaaaaaaaaaaaaaaaaaaaaaaabararararabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacacacabadadadabadadabababadadadadabacacabaaabadadadadadadadadabababababababababacacabababababababaaaaaaaaaaaaaaaaaaaaaaabararararabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacacacabadadadabadadadadabadadadababadadababababadadadadadadadaxabadadadadadadabadadadadadadabaaaaaaaaaaabababababaaaaaaabararararabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababacababababababadadadadadadadadabadadadadadadabadadabadadadadaxabadadadadadadabadadadadadadabaaaaaaaaaaabadadadababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabayadadadadadadabaaabababadadababadababadadadadadadababacabababababababadadababadadababacacabadadabaaaaaaaaaaabadadadadadadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabayacadadabadadabaaaaaaabadadabadadadabadadadadadadadadadadadadacadadadadadababadadadadadadadadadababababababababacacabadadadabadadabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabayacadadabadadabababababadadabadadadabadadadadadadadadadadadadacadadadadadadadadadadadadadadadadatatatatatatatatadadacadadadacadadadadadadadadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabayabadadadadadabacacacabadadabadadadabababababababadadababababababababadadadadadadabadadadabadadatatatatatatatatadadacadadadacadadadadadadadadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabayabacacabacacabadabadabadadababacacabababadadadabadadabacazatatatabababadadadadabababababababababababababababababababadadabababacacabacabacacababadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadadadadadadabadadadadadadadadadadabababadabadadacacaAatatatabaaababadadababadaladadabadadadadadadacacabadadadadadadabadadadadadadadadadadacadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadadadadadadabadadadadadadadadadadabadadadabadadacacacazatatabaaaaabadadabadadadadadabadadadadadadaBacabadadadadadadabadadabaCabababaCabadabadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadadababadababababacacababadadabababadadadacadadabacacabatatabaaaaabadadabadadadadadabadadababadadadadabababadadadadabadadatatabacabataDadacadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababacacababadadadadabadadadadacadadababababacacabadadababacabacacababababacacabababacabababadadababadadabadabatabacacabababadadatatabacabataDadacadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadaEadatatabadadadadabadadadadacadadacaiaiacadadadadadadadadadadadadadadadadadacadadadadadadadadadadadadacayatatabadadabaaabadadatatabacabataDadabadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadatatabadadadadabadadadadacadadacaiaiacadadadadadadadadadadadadadadadadadacadadadadadadadadadadabacacayayayabadadabaaababababababababababababadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadabatatabadadadadabadadadadabadadababababababababababacacababababacababadadababababababababababababatatayatatabadadabababaaaaaaaaaaaaabadadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadatatabababababababababadadadadabaaaaaaaaaaaaabaaabadadabaaabaiaiaiabadadabadadadabacacacabadadacatabayatatabadadadabaaaaaaaaaaaaaaabadadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadadababaaabadadadadabababadadabaaaaaaaaaaaaabaaabadadabaaabaiaiaiabadadabadadadabacacacabadadacatatayatatabadadadabaaabababababababadababababadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababadadadadadabaaabadadadadabaaabadadabaaababababababababadadababababababababadababadababababacabadadabababababababadadababababatatatataDayayayayayabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadadabaaabadadadadabaaabadadabaaabadadadadadadadadadadadadadadaFabadadabadadadadadadadadadadadadacadadadadadadaGatatabatatatatataCaCaCaHayatabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababadabacacababababababadabababadadabaaabadadadadabadadatatadadababadaFabadadabadadadabadadadadadadadadacadadadadadadazatabababatatatatatatataDayababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacadadadadadadadadadadadadadadadadadabaaabadadabadabatadababadatabadadaFabadadabababadabacacababababadababadadadaIaCaCatatabacabatatatataJaJaJaKayabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacadadadadadadadadadadadadadadadadadabaaabadadacadabatadababadatababadababadadadadadadadadadadadacadadadadadadadazatatatatabacabatatatabayayayayayabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababaaabadadacadabadadatatadadabadadadabadadadaLaMadaNaOaPadadacadadadadadadadababababababababababababacacabacacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadabadadadadadadadadadadadadababababababadababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababatatabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaQaQaQaQaQabaQaQabaQaQaQaQaQababaiaiababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaiaiaiaiaiaRaSaTaUaUaUaUaUaVaUaUaWaUaUaUaUaUaXaYaiaiabadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaiaiaZbababaaRaSbbbcbcbcbcbcbdananbbbcbcbcbcbcbdaYaiaiabadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaiaZbeatatatatababaQaQaQaQaQabananabaQaQaQaQaQababaiaiabadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaibfatatatatatatabababababababananababababababababaiaiabadadabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaibfatatatatatatatatatatatabbgananbhbiatatataDbjabaiaiaiadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaibfatatatatatatatatatatatbkblananbmbnatatataDbobpaiaiaiadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaibfatatatatatatatatatatatabbgananbqbratatataDboabaiaiabadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaibfatatatatatatabababababababananababababababababaiaiababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaibsbtatatatatababaQaQaQaQaQabananabaQaQaQaQaQababaiaiabadadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaiaibsbububuaRaSaTaUaUaUaUaUaXananaTaUaUaUaUaUaXaYaiaiaiadadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaiaiaiaiaiaRaSbbbcbcbcbcbcbvbcbcbwbcbcbcbcbcbdaYaiaiaiadadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababaQaQaQaQaQabaQaQabaQaQaQaQaQababaiaiabadadadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababadadabababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,7) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabacacacabababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababadadatadabatatababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadatadacatatatabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadadacatatatabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadadacatatatabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababayayababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabatatatayaxabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabatatatayaxabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabatatatayababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabatatatayaxabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabatatatayaxabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababatbxayadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabatatatayadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabatatatayadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbyatatatabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadatatatabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabadadadadabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababatatabatatatatatababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababbzatatatatatbibAbBbCbDbDbDbiatatbzatatatatatacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbzbzbzbzbzbzbzbnbEbFanananbDbnatatbzatatatatatacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbzatatatatataJbraiauanananbDbrbzbzababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbzatatatataDbGabbHababababababatatabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbzatatatataDbIaiaibJbKbLbMbNatatatabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbzatatatataDbOaiaibPbQbQbQbRbSbTbTbUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbzatatatataDbVaiaibWbXbYbZbNatatatabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbzatatatataDcaabbHababababababatatabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbzatatatatataCbiaiauanananbDbibzbzababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbzbzbzbzbzbzbzbncbccanananbDbnatatbzatatatatatacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababbzatatatatatbrbAbBbCbDbDbDbratatbzatatatatatacabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababatatabatatatatatababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,8) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,9) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,10) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,11) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,12) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,13) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,14) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,15) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,16) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,17) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,18) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,19) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,20) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/system/system-overall.dmm b/maps/system/system-overall.dmm new file mode 100644 index 00000000..f624d60e --- /dev/null +++ b/maps/system/system-overall.dmm @@ -0,0 +1,2581 @@ +"a" = (/turf/space,/area/space) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,2) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,3) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,4) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,5) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,6) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,7) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,8) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,9) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} + +(1,1,10) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/~mapsystem/map_preferences.dm b/maps/~mapsystem/map_preferences.dm new file mode 100644 index 00000000..1962812e --- /dev/null +++ b/maps/~mapsystem/map_preferences.dm @@ -0,0 +1,19 @@ +/datum/map + var/load_legacy_saves = FALSE + +/datum/map/proc/character_save_path(var/slot) + return "/[path]/character[slot]" + +/datum/map/proc/character_load_path(var/savefile/S, var/slot) + var/original_cd = S.cd + S.cd = "/" + . = private_use_legacy_saves(S, slot) ? "/character[slot]" : "/[path]/character[slot]" + S.cd = original_cd // Attempting to make this call as side-effect free as possible + +/datum/map/proc/private_use_legacy_saves(var/savefile/S, var/slot) + if(!load_legacy_saves) // Check if we're bothering with legacy saves at all + return FALSE + if(!S.dir.Find(path)) // If we cannot find the map path folder, load the legacy save + return TRUE + S.cd = "/[path]" // Finally, if we cannot find the character slot in the map path folder, load the legacy save + return !S.dir.Find("character[slot]") diff --git a/maps/~mapsystem/map_ranks.dm b/maps/~mapsystem/map_ranks.dm new file mode 100644 index 00000000..6c200d29 --- /dev/null +++ b/maps/~mapsystem/map_ranks.dm @@ -0,0 +1,41 @@ +/datum/map + var/list/branch_types // list of branch datum paths for military branches available on this map + var/list/spawn_branch_types // subset of above for branches a player can spawn in with + + var/list/species_to_branch_whitelist = list() // List of branches which are allowed, per species. Checked before the blacklist. + var/list/species_to_branch_blacklist = list() // List of branches which are restricted, per species. + + var/list/species_to_rank_whitelist = list() // List of ranks which are allowed, per branch and species. Checked before the blacklist. + var/list/species_to_rank_blacklist = list() // Lists of ranks which are restricted, per species. + +// The white, and blacklist are type specific, any subtypes (of both species and jobs) have to be added explicitly +/datum/map/proc/is_species_branch_restricted(var/datum/species/S, var/datum/mil_branch/MB) + if(!istype(S) || !istype(MB)) + return TRUE + + var/list/whitelist = species_to_branch_whitelist[S.type] + if(whitelist && (MB.type in whitelist)) + return FALSE + + var/list/blacklist = species_to_branch_blacklist[S.type] + if(blacklist) + return (MB.type in blacklist) + + return FALSE + +/datum/map/proc/is_species_rank_restricted(var/datum/species/S, var/datum/mil_branch/MB, var/datum/mil_rank/MR) + if(!istype(S) || !istype(MB) || !istype(MR)) + return TRUE + + var/list/whitelist_by_branch = species_to_rank_whitelist[S.type] + if(whitelist_by_branch) + var/list/whitelist = whitelist_by_branch[MB.type] + if(whitelist && (MR.type in whitelist)) + return FALSE + + var/list/blacklist_by_branch = species_to_rank_blacklist[S.type] + if(blacklist_by_branch) + var/list/blacklist = blacklist_by_branch[MB.type] + return blacklist && (MR.type in blacklist) + + return FALSE diff --git a/maps/~mapsystem/maps.dm b/maps/~mapsystem/maps.dm new file mode 100644 index 00000000..95c537f5 --- /dev/null +++ b/maps/~mapsystem/maps.dm @@ -0,0 +1,283 @@ +GLOBAL_DATUM_INIT(using_map, /datum/map, new using_map_DATUM) +GLOBAL_LIST_EMPTY(all_maps) + +var/const/MAP_HAS_BRANCH = 1 //Branch system for occupations, togglable +var/const/MAP_HAS_RANK = 2 //Rank system, also togglable + +/hook/startup/proc/initialise_map_list() + for(var/type in typesof(/datum/map) - /datum/map) + var/datum/map/M + if(type == GLOB.using_map.type) + M = GLOB.using_map + M.setup_map() + else + M = new type + if(!M.path) + log_error("Map '[M]' does not have a defined path, not adding to map list!") + else + GLOB.all_maps[M.path] = M + return 1 + + +/datum/map + var/name = "Unnamed Map" + var/full_name = "Unnamed Map" + var/path + + var/list/station_levels = list() // Z-levels the station exists on + var/list/admin_levels = list() // Z-levels for admin functionality (Centcom, shuttle transit, etc) + var/list/contact_levels = list() // Z-levels that can be contacted from the station, for eg announcements + var/list/player_levels = list() // Z-levels a character can typically reach + var/list/sealed_levels = list() // Z-levels that don't allow random transit at edge + var/list/empty_levels = null // Empty Z-levels that may be used for various things (currently used by bluespace jump) + + var/list/map_levels // Z-levels available to various consoles, such as the crew monitor. Defaults to station_levels if unset. + + var/list/base_turf_by_z = list() // Custom base turf by Z-level. Defaults to world.turf for unlisted Z-levels + var/list/usable_email_tlds = list("freemail.nt") + var/base_floor_type = /turf/simulated/floor/airless // The turf type used when generating floors between Z-levels at startup. + var/base_floor_area // Replacement area, if a base_floor_type is generated. Leave blank to skip. + + //This list contains the z-level numbers which can be accessed via space travel and the percentile chances to get there. + var/list/accessible_z_levels = list() + + var/list/allowed_jobs //Job datums to use. + //Works a lot better so if we get to a point where three-ish maps are used + //We don't have to C&P ones that are only common between two of them + //That doesn't mean we have to include them with the rest of the jobs though, especially for map specific ones. + //Also including them lets us override already created jobs, letting us keep the datums to a minimum mostly. + //This is probably a lot longer explanation than it needs to be. + + var/station_name = "BAD Station" + var/station_short = "Baddy" + var/dock_name = "THE PirateBay" + var/boss_name = "Captain Roger" + var/boss_short = "Cap'" + var/company_name = "BadMan" + var/company_short = "BM" + var/system_name = "Uncharted System" + + var/map_admin_faxes = list() + + var/shuttle_docked_message + var/shuttle_leaving_dock + var/shuttle_called_message + var/shuttle_recall_message + var/emergency_shuttle_docked_message + var/emergency_shuttle_leaving_dock + var/emergency_shuttle_recall_message + + var/list/station_networks = list() // Camera networks that will show up on the console. + + var/list/holodeck_programs = list() // map of string ids to /datum/holodeck_program instances + var/list/holodeck_supported_programs = list() // map of maps - first level maps from list-of-programs string id (e.g. "BarPrograms") to another map + // this is in order to support multiple holodeck program listings for different holodecks + // second level maps from program friendly display names ("Picnic Area") to program string ids ("picnicarea") + // as defined in holodeck_programs + var/list/holodeck_restricted_programs = list() // as above... but EVIL! + + var/allowed_spawns = list("Arrivals Shuttle","Gateway", "Cryogenic Storage", "Cyborg Storage") + var/default_spawn = "Arrivals Shuttle" + var/flags = 0 + var/evac_controller_type = /datum/evacuation_controller + var/use_overmap = 0 //If overmap should be used (including overmap space travel override) + var/overmap_size = 20 //Dimensions of overmap zlevel if overmap is used. + var/overmap_z = 0 //If 0 will generate overmap zlevel on init. Otherwise will populate the zlevel provided. + var/overmap_event_areas = 0 //How many event "clouds" will be generated + + var/lobby_icon // The icon which contains the lobby image(s) + var/list/lobby_screens = list() // The list of lobby screen to pick() from. If left unset the first icon state is always selected. + var/lobby_music/lobby_music // The track that will play in the lobby screen. Handed in the /setup_map() proc. + var/welcome_sound = 'sound/AI/welcome.ogg' // Sound played on roundstart + + var/default_law_type = /datum/ai_laws/nanotrasen // The default lawset use by synth units, if not overriden by their laws var. + var/security_state = /decl/security_state/default // The default security state system to use. + + var/id_hud_icons = 'icons/mob/hud.dmi' // Used by the ID HUD (primarily sechud) overlay. + + var/num_exoplanets = 0 + var/list/planet_size //dimensions of planet zlevel, defaults to world size. Due to how maps are generated, must be (2^n+1) e.g. 17,33,65,129 etc. Map will just round up to those if set to anything other. + var/away_site_budget = 0 + + //Economy stuff + var/starting_money = 5000 //Money in station account + var/department_money = 500 //Money in department accounts + var/salary_modifier = 1 //Multiplier to starting character money + var/station_departments = list()//Gets filled automatically depending on jobs allowed + var/map_lore = null //This is a string, write your fancy map lore here. + + //Factions prefs stuff + var/list/citizenship_choices = list( + "Earth", + "Mars", + "Terra", + "Gaia", + "Moghes", + "Ahdomai", + "Qerrbalak" + ) + + var/list/home_system_choices = list( + "Sol", + "Nyx", + "Tau Ceti", + "Epsilon Ursae Minoris", + "Zamsiin-lr", + "Gilgamesh" + ) + + var/list/faction_choices = list( + "Sol Central Government", + "Terran Colonial Confederation", + "Vey Med", + "Einstein Engines", + "Free Trade Union", + "NanoTrasen", + "Ward-Takahashi GMB", + "Gilthari Exports", + "Grayson Manufactories Ltd.", + "Aether Atmospherics", + "Zeng-Hu Pharmaceuticals", + "Hephaestus Industries", + "Commonwealth of Ahdomai" + ) + + var/list/religion_choices = list( + "Unitarianism", + "Hinduism", + "Buddhist", + "Islamic", + "Christian", + "Agnostic", + "Deist" + ) + +/datum/map/New() + if(!map_levels) + map_levels = station_levels.Copy() + if(!allowed_jobs) + allowed_jobs = subtypesof(/datum/job) + if(!planet_size) + planet_size = list(world.maxx, world.maxy) + +/datum/map/proc/setup_map() + var/list/lobby_music_tracks = subtypesof(/lobby_music) + var/lobby_music_type = /lobby_music + if(lobby_music_tracks.len) + lobby_music_type = pick(lobby_music_tracks) + lobby_music = new lobby_music_type() + world.update_status() + +/datum/map/proc/send_welcome() + return + +/datum/map/proc/perform_map_generation() + return + +/datum/map/proc/build_away_sites() +#ifdef UNIT_TEST + report_progress("Unit testing, so not loading away sites") + return // don't build away sites during unit testing +#else + report_progress("Loading away sites...") + var/list/sites_by_spawn_weight = list() + for (var/site_name in SSmapping.away_sites_templates) + var/datum/map_template/ruin/away_site/site = SSmapping.away_sites_templates[site_name] + sites_by_spawn_weight[site] = site.spawn_weight + while (away_site_budget > 0 && sites_by_spawn_weight.len) + var/datum/map_template/ruin/away_site/selected_site = pickweight(sites_by_spawn_weight) + if (!selected_site) + break + sites_by_spawn_weight -= selected_site + if(selected_site.cost > away_site_budget) + continue + if (selected_site.load_new_z()) + report_progress("Loaded away site [selected_site]!") + away_site_budget -= selected_site.cost + report_progress("Finished loading away sites, remaining budget [away_site_budget], remaining sites [sites_by_spawn_weight.len]") +#endif + +/datum/map/proc/build_exoplanets() + if(!use_overmap) + return + + for(var/i = 0, i < num_exoplanets, i++) + var/exoplanet_type = pick(subtypesof(/obj/effect/overmap/sector/exoplanet)) + var/obj/effect/overmap/sector/exoplanet/new_planet = new exoplanet_type(null, planet_size[1], planet_size[2]) + new_planet.build_level() + +// Used to apply various post-compile procedural effects to the map. +/datum/map/proc/refresh_mining_turfs(var/zlevel) + + set background = 1 + set waitfor = 0 + + for(var/thing in mining_walls["[zlevel]"]) + var/turf/simulated/mineral/M = thing + M.update_icon() + for(var/thing in mining_floors["[zlevel]"]) + var/turf/simulated/floor/asteroid/M = thing + if(istype(M)) + M.updateMineralOverlays() + +/datum/map/proc/get_network_access(var/network) + return 0 + +// By default transition randomly to another zlevel +/datum/map/proc/get_transit_zlevel(var/current_z_level) + var/list/candidates = GLOB.using_map.accessible_z_levels.Copy() + candidates.Remove(num2text(current_z_level)) + + if(!candidates.len) + return current_z_level + return text2num(pickweight(candidates)) + +/datum/map/proc/get_empty_zlevel() + if(empty_levels == null) + world.maxz++ + empty_levels = list(world.maxz) + return pick(empty_levels) + + +/datum/map/proc/setup_economy() + news_network.CreateFeedChannel("Nyx Daily", "SolGov Minister of Information", 1, 1) + news_network.CreateFeedChannel("The Gibson Gazette", "Editor Mike Hammers", 1, 1) + + for(var/loc_type in typesof(/datum/trade_destination) - /datum/trade_destination) + var/datum/trade_destination/D = new loc_type + weighted_randomevent_locations[D] = D.viable_random_events.len + weighted_mundaneevent_locations[D] = D.viable_mundane_events.len + + if(!station_account) + station_account = create_account("[station_name()] Primary Account", starting_money) + + for(var/job in allowed_jobs) + var/datum/job/J = decls_repository.get_decl(job) + if(J.department) + station_departments |= J.department + for(var/department in station_departments) + department_accounts[department] = create_account("[department] Account", department_money) + + department_accounts["Vendor"] = create_account("Vendor Account", 0) + vendor_account = department_accounts["Vendor"] + +/datum/map/proc/map_info(var/client/victim) + return +// Access check is of the type requires one. These have been carefully selected to avoid allowing the janitor to see channels he shouldn't +// This list needs to be purged but people insist on adding more cruft to the radio. +/datum/map/proc/default_internal_channels() + return list( + num2text(PUB_FREQ) = list(), + num2text(AI_FREQ) = list(access_synth), + num2text(ENT_FREQ) = list(), + num2text(ERT_FREQ) = list(access_cent_specops), + num2text(COMM_FREQ) = list(access_heads), + num2text(ENG_FREQ) = list(access_engine_equip, access_atmospherics), + num2text(MED_FREQ) = list(access_medical_equip), + num2text(MED_I_FREQ) = list(access_medical_equip), + num2text(SEC_FREQ) = list(access_security), + num2text(SEC_I_FREQ) = list(access_security), + num2text(SCI_FREQ) = list(access_tox,access_robotics,access_xenobiology), + num2text(SUP_FREQ) = list(access_cargo), + num2text(SRV_FREQ) = list(access_janitor, access_hydroponics), + ) diff --git a/maps/~mapsystem/maps_announcements.dm b/maps/~mapsystem/maps_announcements.dm new file mode 100644 index 00000000..f47b630c --- /dev/null +++ b/maps/~mapsystem/maps_announcements.dm @@ -0,0 +1,64 @@ +/datum/map + var/emergency_shuttle_called_message + var/emergency_shuttle_called_sound + + var/command_report_sound + + var/electrical_storm_moderate_sound + var/electrical_storm_major_sound + + var/grid_check_message = "Abnormal activity detected in the %STATION_NAME%'s power system. As a precaution, the %STATION_NAME%'s power must be shut down for an indefinite duration." + var/grid_check_sound + + var/grid_restored_message = "Station power to the %STATION_NAME% will be restored at this time. We apologize for the inconvenience." + var/grid_restored_sound + + var/meteor_detected_message = "Meteors have been detected on a collision course with the %STATION_NAME%." + var/meteor_detected_sound + + var/radiation_detected_message = "High levels of radiation has been detected in proximity of the %STATION_NAME%. Please report to the medical bay if any strange symptoms occur." + var/radiation_detected_sound + + var/space_time_anomaly_sound + + var/unidentified_lifesigns_message = "Unidentified lifesigns detected coming aboard the %STATION_NAME%. Please lockdown all exterior access points, including ducting and ventilation." + var/unidentified_lifesigns_sound + + var/unknown_biological_entities_message = "Unknown biological entities have been detected near the %STATION_NAME%, please stand-by." + + var/xenomorph_spawn_sound = 'sound/AI/aliens.ogg' + +/datum/map/proc/emergency_shuttle_called_announcement() + evacuation_controller.evac_called.Announce(replacetext(emergency_shuttle_called_message, "%ETA%", "[round(evacuation_controller.get_eta()/60)] minute\s."), new_sound = emergency_shuttle_called_sound) + +/datum/map/proc/grid_check_announcement() + command_announcement.Announce(replacetext(grid_check_message, "%STATION_NAME%", station_name()), "Automated Grid Check", new_sound = grid_check_sound) + +/datum/map/proc/grid_restored_announcement() + command_announcement.Announce(replacetext(grid_restored_message, "%STATION_NAME%", station_name()), "Power Systems Nominal", new_sound = grid_restored_sound) + +/datum/map/proc/level_x_biohazard_announcement(var/bio_level) + if(!isnum(bio_level)) + CRASH("Expected a number, was: [log_info_line(bio_level)]") + if(bio_level < 1 || bio_level > 9) + CRASH("Expected a number between 1 and 9, was: [log_info_line(bio_level)]") + + command_announcement.Announce("Confirmed outbreak of level [bio_level] biohazard aboard the [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", new_sound = level_x_biohazard_sound(bio_level)) + +/datum/map/proc/level_x_biohazard_sound(var/bio_level) + return + +/datum/map/proc/meteors_detected_announcement() + command_announcement.Announce(replacetext(meteor_detected_message, "%STATION_NAME%", station_name()), "[station_name()] Sensor Array", new_sound = meteor_detected_sound) + +/datum/map/proc/radiation_detected_announcement() + command_announcement.Announce(replacetext(radiation_detected_message, "%STATION_NAME%", station_name()), "Anomaly Alert", new_sound = radiation_detected_sound) + +/datum/map/proc/space_time_anomaly_detected_annoncement() + command_announcement.Announce("Space-time anomalies have been detected on the [station_name()].", "Anomaly Alert", new_sound = space_time_anomaly_sound) + +/datum/map/proc/unidentified_lifesigns_announcement() + command_announcement.Announce(replacetext(unidentified_lifesigns_message, "%STATION_NAME%", station_name()), "Lifesign Alert", new_sound = unidentified_lifesigns_sound) + +/datum/map/proc/unknown_biological_entities_announcement() + command_announcement.Announce(replacetext(unknown_biological_entities_message, "%STATION_NAME%", station_name()), "Lifesign Alert", new_sound = command_report_sound) diff --git a/maps/~mapsystem/maps_areas.dm b/maps/~mapsystem/maps_areas.dm new file mode 100644 index 00000000..51c6d7b0 --- /dev/null +++ b/maps/~mapsystem/maps_areas.dm @@ -0,0 +1,15 @@ +/datum/map + /* + Areas where crew members are considered to have safely left the station. + Defaults to all area types on the admin levels if left empty + */ + var/list/post_round_safe_areas = list() + +/datum/map/setup_map() + ..() + if(!post_round_safe_areas.len) + for(var/area/A) + if(isspace(A)) + continue + if(A.z && (A.z in admin_levels)) + post_round_safe_areas += A.type diff --git a/maps/~mapsystem/maps_jobs.dm b/maps/~mapsystem/maps_jobs.dm new file mode 100644 index 00000000..3bc714bc --- /dev/null +++ b/maps/~mapsystem/maps_jobs.dm @@ -0,0 +1,29 @@ +/datum/map + var/species_to_job_whitelist = list() + var/species_to_job_blacklist = list() + + var/job_to_species_whitelist = list() + var/job_to_species_blacklist = list() + +// The white, and blacklist are type specific, any subtypes (of both species and jobs) have to be added explicitly +/datum/map/proc/is_species_job_restricted(var/datum/species/S, var/datum/job/J) + if(!istype(S) || !istype(J)) + return TRUE + + var/list/whitelist = species_to_job_whitelist[S.type] + if(whitelist) + return !(J.type in whitelist) + + whitelist = job_to_species_whitelist[J.type] + if(whitelist) + return !(S.type in whitelist) + + var/list/blacklist = species_to_job_blacklist[S.type] + if(blacklist) + return (J.type in blacklist) + + blacklist = job_to_species_blacklist[J.type] + if(blacklist) + return (S.type in blacklist) + + return FALSE diff --git a/maps/~mapsystem/maps_unit_testing.dm b/maps/~mapsystem/maps_unit_testing.dm new file mode 100644 index 00000000..0758a328 --- /dev/null +++ b/maps/~mapsystem/maps_unit_testing.dm @@ -0,0 +1,72 @@ +/datum/map + var/const/NO_APC = 1 + var/const/NO_VENT = 2 + var/const/NO_SCRUBBER = 4 + + // Unit test vars + var/list/apc_test_exempt_areas = list( + /area/exoplanet = NO_SCRUBBER|NO_VENT|NO_APC, + /area/exoplanet/desert = NO_SCRUBBER|NO_VENT|NO_APC, + /area/exoplanet/grass = NO_SCRUBBER|NO_VENT|NO_APC, + /area/exoplanet/snow = NO_SCRUBBER|NO_VENT|NO_APC, + /area/exoplanet/garbage = NO_SCRUBBER|NO_VENT|NO_APC + ) + + var/list/area_coherency_test_exempt_areas = list( + /area/space, + /area/exoplanet, + /area/exoplanet/desert, + /area/exoplanet/grass, + /area/exoplanet/snow, + /area/exoplanet/garbage + ) + var/list/area_coherency_test_subarea_count = list() + + // These areas are used specifically by code and need to be broken out somehow + var/list/area_usage_test_exempted_areas = list( + /area/beach, + /area/centcom, + /area/centcom/holding, + /area/centcom/specops, + /area/chapel, + /area/hallway, + /area/maintenance, + /area/medical, + /area/medical/virology, + /area/medical/virologyaccess, + /area/overmap, + /area/rnd, + /area/rnd/xenobiology, + /area/rnd/xenobiology/xenoflora, + /area/rnd/xenobiology/xenoflora_storage, + /area/security, + /area/security/prison, + /area/security/brig, + /area/skipjack_station, + /area/skipjack_station/start, + /area/shuttle, + /area/shuttle/escape, + /area/shuttle/escape/centcom, + /area/shuttle/specops, + /area/shuttle/specops/centcom, + /area/shuttle/syndicate_elite, + /area/shuttle/syndicate_elite/mothership, + /area/shuttle/syndicate_elite/station, + /area/turbolift, + /area/supply, + /area/syndicate_mothership, + /area/syndicate_mothership/elite_squad, + /area/wizard_station, + /area/exoplanet, + /area/exoplanet/desert, + /area/exoplanet/grass, + /area/exoplanet/snow, + /area/exoplanet/garbage, + /area/template_noop, + /area/map_template, + /area/map_template/little_house, + ) + + var/list/area_usage_test_exempted_root_areas = list() + + var/list/area_purity_test_exempt_areas = list() \ No newline at end of file diff --git a/maps/~unit_tests/unit_testing.dm b/maps/~unit_tests/unit_testing.dm new file mode 100644 index 00000000..5a4bfa9f --- /dev/null +++ b/maps/~unit_tests/unit_testing.dm @@ -0,0 +1,5 @@ +// It's unlikely you'll be able to open these maps without UNIT_TEST defined + +#ifdef UNIT_TEST + #include "virtual_mob_test.dmm" +#endif diff --git a/maps/~unit_tests/virtual_mob_test.dmm b/maps/~unit_tests/virtual_mob_test.dmm new file mode 100644 index 00000000..f59b096c --- /dev/null +++ b/maps/~unit_tests/virtual_mob_test.dmm @@ -0,0 +1,35 @@ +"a" = (/turf/space,/area/space) +"b" = (/turf/unsimulated/wall,/area/test_area/powered_dynamic_lighting) +"c" = (/turf/unsimulated/wall,/area/test_area/requires_power_dynamic_lighting) +"d" = (/turf/unsimulated/floor{icon_state = "hydrofloor"},/area/test_area/powered_dynamic_lighting) +"e" = (/turf/unsimulated/floor{icon_state = "hydrofloor"},/area/test_area/requires_power_dynamic_lighting) +"f" = (/turf/unsimulated/wall,/area/test_area/powered_non_dynamic_lighting) +"g" = (/turf/unsimulated/wall,/area/test_area/requires_power_non_dynamic_lighting) +"h" = (/obj/effect/landmark/virtual_spawn/two,/turf/unsimulated/floor{icon_state = "hydrofloor"},/area/test_area/powered_non_dynamic_lighting) +"i" = (/turf/unsimulated/floor{icon_state = "hydrofloor"},/area/test_area/powered_non_dynamic_lighting) +"j" = (/obj/effect/landmark/virtual_spawn/one,/turf/unsimulated/floor{icon_state = "hydrofloor"},/area/test_area/powered_non_dynamic_lighting) +"k" = (/obj/effect/landmark/virtual_spawn/three,/turf/unsimulated/floor{icon_state = "hydrofloor"},/area/test_area/powered_non_dynamic_lighting) +"l" = (/turf/unsimulated/floor{icon_state = "hydrofloor"},/area/test_area/requires_power_non_dynamic_lighting) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaabbbbbbbcccccccaaaaaaa +aaaaaaabdddbdbceeececaaaaaaa +aaaaaaabbbbbbbcccccccaaaaaaa +aaaaaaafffffffgggggggaaaaaaa +aaaaaaafhijfkfglllglgaaaaaaa +aaaaaaafffffffgggggggaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} \ No newline at end of file diff --git a/nano/To BYOND Cache.bat b/nano/To BYOND Cache.bat new file mode 100644 index 00000000..486b8d1b --- /dev/null +++ b/nano/To BYOND Cache.bat @@ -0,0 +1,4 @@ +copy css\* "%USERPROFILE%\Documents\BYOND\cache" /y +copy images\* "%USERPROFILE%\Documents\BYOND\cache" /y +copy js\* "%USERPROFILE%\Documents\BYOND\cache" /y +copy templates\* "%USERPROFILE%\Documents\BYOND\cache" /y diff --git a/nano/css/icons.css b/nano/css/icons.css new file mode 100644 index 00000000..a48d5039 --- /dev/null +++ b/nano/css/icons.css @@ -0,0 +1,316 @@ +/* Icons +----------------------------------*/ + +.icon24 +{ + width: 24px; + height: 24px; +} + +.icon24.uiStatusGood +{ + background: url(uiIcons24.png) 0 0 no-repeat; +} + +.icon24.uiStatusAverage +{ + background: url(uiIcons24.png) 0 -24px no-repeat; +} + +.icon24.uiStatusBad +{ + background: url(uiIcons24.png) 0 -48px no-repeat; +} + +/* states and images */ +.uiIcon16 { + float: left; + width: 16px; + height: 16px; + margin: 2px 2px 0 2px; + background-image: url(uiIcons16.png); +} + +.uiLinkPendingIcon { + display: none; + float: left; + width: 16px; + height: 16px; + margin: 2px 2px 0 2px; + background-image: url(uiLinkPendingIcon.gif); +} + +.linkPending .uiIcon16 { + display: none; +} + +.linkPending .uiLinkPendingIcon { + display: block; +} + +/* positioning */ +.uiIcon16.icon-blank { background-position: 16px 16px; } +.uiIcon16.icon-carat-1-n { background-position: 0 0; } +.uiIcon16.icon-carat-1-ne { background-position: -16px 0; } +.uiIcon16.icon-carat-1-e { background-position: -32px 0; } +.uiIcon16.icon-carat-1-se { background-position: -48px 0; } +.uiIcon16.icon-carat-1-s { background-position: -64px 0; } +.uiIcon16.icon-carat-1-sw { background-position: -80px 0; } +.uiIcon16.icon-carat-1-w { background-position: -96px 0; } +.uiIcon16.icon-carat-1-nw { background-position: -112px 0; } +.uiIcon16.icon-carat-2-n-s { background-position: -128px 0; } +.uiIcon16.icon-carat-2-e-w { background-position: -144px 0; } +.uiIcon16.icon-triangle-1-n { background-position: 0 -16px; } +.uiIcon16.icon-triangle-1-ne { background-position: -16px -16px; } +.uiIcon16.icon-triangle-1-e { background-position: -32px -16px; } +.uiIcon16.icon-triangle-1-se { background-position: -48px -16px; } +.uiIcon16.icon-triangle-1-s { background-position: -64px -16px; } +.uiIcon16.icon-triangle-1-sw { background-position: -80px -16px; } +.uiIcon16.icon-triangle-1-w { background-position: -96px -16px; } +.uiIcon16.icon-triangle-1-nw { background-position: -112px -16px; } +.uiIcon16.icon-triangle-2-n-s { background-position: -128px -16px; } +.uiIcon16.icon-triangle-2-e-w { background-position: -144px -16px; } +.uiIcon16.icon-arrow-1-n { background-position: 0 -32px; } +.uiIcon16.icon-arrow-1-ne { background-position: -16px -32px; } +.uiIcon16.icon-arrow-1-e { background-position: -32px -32px; } +.uiIcon16.icon-arrow-1-se { background-position: -48px -32px; } +.uiIcon16.icon-arrow-1-s { background-position: -64px -32px; } +.uiIcon16.icon-arrow-1-sw { background-position: -80px -32px; } +.uiIcon16.icon-arrow-1-w { background-position: -96px -32px; } +.uiIcon16.icon-arrow-1-nw { background-position: -112px -32px; } +.uiIcon16.icon-arrow-2-n-s { background-position: -128px -32px; } +.uiIcon16.icon-arrow-2-ne-sw { background-position: -144px -32px; } +.uiIcon16.icon-arrow-2-e-w { background-position: -160px -32px; } +.uiIcon16.icon-arrow-2-se-nw { background-position: -176px -32px; } +.uiIcon16.icon-arrowstop-1-n { background-position: -192px -32px; } +.uiIcon16.icon-arrowstop-1-e { background-position: -208px -32px; } +.uiIcon16.icon-arrowstop-1-s { background-position: -224px -32px; } +.uiIcon16.icon-arrowstop-1-w { background-position: -240px -32px; } +.uiIcon16.icon-arrowthick-1-n { background-position: 0 -48px; } +.uiIcon16.icon-arrowthick-1-ne { background-position: -16px -48px; } +.uiIcon16.icon-arrowthick-1-e { background-position: -32px -48px; } +.uiIcon16.icon-arrowthick-1-se { background-position: -48px -48px; } +.uiIcon16.icon-arrowthick-1-s { background-position: -64px -48px; } +.uiIcon16.icon-arrowthick-1-sw { background-position: -80px -48px; } +.uiIcon16.icon-arrowthick-1-w { background-position: -96px -48px; } +.uiIcon16.icon-arrowthick-1-nw { background-position: -112px -48px; } +.uiIcon16.icon-arrowthick-2-n-s { background-position: -128px -48px; } +.uiIcon16.icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.uiIcon16.icon-arrowthick-2-e-w { background-position: -160px -48px; } +.uiIcon16.icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.uiIcon16.icon-arrowthickstop-1-n { background-position: -192px -48px; } +.uiIcon16.icon-arrowthickstop-1-e { background-position: -208px -48px; } +.uiIcon16.icon-arrowthickstop-1-s { background-position: -224px -48px; } +.uiIcon16.icon-arrowthickstop-1-w { background-position: -240px -48px; } +.uiIcon16.icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.uiIcon16.icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.uiIcon16.icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.uiIcon16.icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.uiIcon16.icon-arrowreturn-1-w { background-position: -64px -64px; } +.uiIcon16.icon-arrowreturn-1-n { background-position: -80px -64px; } +.uiIcon16.icon-arrowreturn-1-e { background-position: -96px -64px; } +.uiIcon16.icon-arrowreturn-1-s { background-position: -112px -64px; } +.uiIcon16.icon-arrowrefresh-1-w { background-position: -128px -64px; } +.uiIcon16.icon-arrowrefresh-1-n { background-position: -144px -64px; } +.uiIcon16.icon-arrowrefresh-1-e { background-position: -160px -64px; } +.uiIcon16.icon-arrowrefresh-1-s { background-position: -176px -64px; } +.uiIcon16.icon-arrow-4 { background-position: 0 -80px; } +.uiIcon16.icon-arrow-4-diag { background-position: -16px -80px; } +.uiIcon16.icon-extlink { background-position: -32px -80px; } +.uiIcon16.icon-newwin { background-position: -48px -80px; } +.uiIcon16.icon-refresh { background-position: -64px -80px; } +.uiIcon16.icon-shuffle { background-position: -80px -80px; } +.uiIcon16.icon-transfer-e-w { background-position: -96px -80px; } +.uiIcon16.icon-transferthick-e-w { background-position: -112px -80px; } +.uiIcon16.icon-radiation { background-position: -128px -80px; } +.uiIcon16.icon-folder-collapsed { background-position: 0 -96px; } +.uiIcon16.icon-folder-open { background-position: -16px -96px; } +.uiIcon16.icon-document { background-position: -32px -96px; } +.uiIcon16.icon-document-b { background-position: -48px -96px; } +.uiIcon16.icon-note { background-position: -64px -96px; } +.uiIcon16.icon-mail-closed { background-position: -80px -96px; } +.uiIcon16.icon-mail-open { background-position: -96px -96px; } +.uiIcon16.icon-suitcase { background-position: -112px -96px; } +.uiIcon16.icon-comment { background-position: -128px -96px; } +.uiIcon16.icon-person { background-position: -144px -96px; } +.uiIcon16.icon-print { background-position: -160px -96px; } +.uiIcon16.icon-trash { background-position: -176px -96px; } +.uiIcon16.icon-locked { background-position: -192px -96px; } +.uiIcon16.icon-unlocked { background-position: -208px -96px; } +.uiIcon16.icon-bookmark { background-position: -224px -96px; } +.uiIcon16.icon-tag { background-position: -240px -96px; } +.uiIcon16.icon-home { background-position: 0 -112px; } +.uiIcon16.icon-flag { background-position: -16px -112px; } +.uiIcon16.icon-calendar { background-position: -32px -112px; } +.uiIcon16.icon-cart { background-position: -48px -112px; } +.uiIcon16.icon-pencil { background-position: -64px -112px; } +.uiIcon16.icon-clock { background-position: -80px -112px; } +.uiIcon16.icon-disk { background-position: -96px -112px; } +.uiIcon16.icon-calculator { background-position: -112px -112px; } +.uiIcon16.icon-zoomin { background-position: -128px -112px; } +.uiIcon16.icon-zoomout { background-position: -144px -112px; } +.uiIcon16.icon-search { background-position: -160px -112px; } +.uiIcon16.icon-wrench { background-position: -176px -112px; } +.uiIcon16.icon-gear { background-position: -192px -112px; } +.uiIcon16.icon-heart { background-position: -208px -112px; } +.uiIcon16.icon-star { background-position: -224px -112px; } +.uiIcon16.icon-link { background-position: -240px -112px; } +.uiIcon16.icon-cancel { background-position: 0 -128px; } +.uiIcon16.icon-plus { background-position: -16px -128px; } +.uiIcon16.icon-plusthick { background-position: -32px -128px; } +.uiIcon16.icon-minus { background-position: -48px -128px; } +.uiIcon16.icon-minusthick { background-position: -64px -128px; } +.uiIcon16.icon-close { background-position: -80px -128px; } +.uiIcon16.icon-closethick { background-position: -96px -128px; } +.uiIcon16.icon-key { background-position: -112px -128px; } +.uiIcon16.icon-lightbulb { background-position: -128px -128px; } +.uiIcon16.icon-scissors { background-position: -144px -128px; } +.uiIcon16.icon-clipboard { background-position: -160px -128px; } +.uiIcon16.icon-copy { background-position: -176px -128px; } +.uiIcon16.icon-contact { background-position: -192px -128px; } +.uiIcon16.icon-image { background-position: -208px -128px; } +.uiIcon16.icon-video { background-position: -224px -128px; } +.uiIcon16.icon-script { background-position: -240px -128px; } +.uiIcon16.icon-alert { background-position: 0 -144px; } +.uiIcon16.icon-info { background-position: -16px -144px; } +.uiIcon16.icon-notice { background-position: -32px -144px; } +.uiIcon16.icon-help { background-position: -48px -144px; } +.uiIcon16.icon-check { background-position: -64px -144px; } +.uiIcon16.icon-bullet { background-position: -80px -144px; } +.uiIcon16.icon-radio-on { background-position: -96px -144px; } +.uiIcon16.icon-radio-off { background-position: -112px -144px; } +.uiIcon16.icon-pin-w { background-position: -128px -144px; } +.uiIcon16.icon-pin-s { background-position: -144px -144px; } +.uiIcon16.icon-syringe { background-position: -192px -144px; } +.uiIcon16.icon-play { background-position: 0 -160px; } +.uiIcon16.icon-pause { background-position: -16px -160px; } +.uiIcon16.icon-seek-next { background-position: -32px -160px; } +.uiIcon16.icon-seek-prev { background-position: -48px -160px; } +.uiIcon16.icon-seek-end { background-position: -64px -160px; } +.uiIcon16.icon-seek-start { background-position: -80px -160px; } +/* uiIcon-seek-first is deprecated, use uiIcon-seek-start instead */ +.uiIcon16.icon-seek-first { background-position: -80px -160px; } +.uiIcon16.icon-stop { background-position: -96px -160px; } +.uiIcon16.icon-eject { background-position: -112px -160px; } +.uiIcon16.icon-volume-off { background-position: -128px -160px; } +.uiIcon16.icon-volume-on { background-position: -144px -160px; } +.uiIcon16.icon-power { background-position: 0 -176px; } +.uiIcon16.icon-signal-diag { background-position: -16px -176px; } +.uiIcon16.icon-signal { background-position: -32px -176px; } +.uiIcon16.icon-battery-0 { background-position: -48px -176px; } +.uiIcon16.icon-battery-1 { background-position: -64px -176px; } +.uiIcon16.icon-battery-2 { background-position: -80px -176px; } +.uiIcon16.icon-battery-3 { background-position: -96px -176px; } +.uiIcon16.icon-circle-plus { background-position: 0 -192px; } +.uiIcon16.icon-circle-minus { background-position: -16px -192px; } +.uiIcon16.icon-circle-close { background-position: -32px -192px; } +.uiIcon16.icon-circle-triangle-e { background-position: -48px -192px; } +.uiIcon16.icon-circle-triangle-s { background-position: -64px -192px; } +.uiIcon16.icon-circle-triangle-w { background-position: -80px -192px; } +.uiIcon16.icon-circle-triangle-n { background-position: -96px -192px; } +.uiIcon16.icon-circle-arrow-e { background-position: -112px -192px; } +.uiIcon16.icon-circle-arrow-s { background-position: -128px -192px; } +.uiIcon16.icon-circle-arrow-w { background-position: -144px -192px; } +.uiIcon16.icon-circle-arrow-n { background-position: -160px -192px; } +.uiIcon16.icon-circle-zoomin { background-position: -176px -192px; } +.uiIcon16.icon-circle-zoomout { background-position: -192px -192px; } +.uiIcon16.icon-circle-check { background-position: -208px -192px; } +.uiIcon16.icon-circlesmall-plus { background-position: 0 -208px; } +.uiIcon16.icon-circlesmall-minus { background-position: -16px -208px; } +.uiIcon16.icon-circlesmall-close { background-position: -32px -208px; } +.uiIcon16.icon-squaresmall-plus { background-position: -48px -208px; } +.uiIcon16.icon-squaresmall-minus { background-position: -64px -208px; } +.uiIcon16.icon-squaresmall-close { background-position: -80px -208px; } +.uiIcon16.icon-grip-dotted-vertical { background-position: 0 -224px; } +.uiIcon16.icon-grip-dotted-horizontal { background-position: -16px -224px; } +.uiIcon16.icon-grip-solid-vertical { background-position: -32px -224px; } +.uiIcon16.icon-grip-solid-horizontal { background-position: -48px -224px; } +.uiIcon16.icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.uiIcon16.icon-grip-diagonal-se { background-position: -80px -224px; } +.uiIcon16.icon-batt_full { background-image: url(c_max.gif); background-position: 0px 0px } +.uiIcon16.icon-batt_disc { background-image: url(c_discharging.gif); background-position: 0px 0px } +.uiIcon16.icon-batt_chrg { background-image: url(c_charging.gif); background-position: 0px 0px } +.uiIcon16.icon-close64 { background-image: url(uiIcons64.png); background-position: -128px -64px; width: 64px; height: 64px; } + +.mapIcon16 { + position: absolute; + width: 16px; + height: 16px; + background-image: url(uiIcons16Green.png); + background-position: -144px -96px; + background-repeat: no-repeat; + zoom: 0.125; + margin-left: -1px; + /*margin-bottom: -1px;*/ +} +.mapIcon16.dead { + background-image: url(uiIcons16Red.png); +} + +/* Command Positions */ +.mapIcon16.rank-captain { + background-position: -224px -112px; +} +.mapIcon16.rank-headofpersonnel { + background-position: -112px -96px; +} +.mapIcon16.rank-headofsecurity { + background-position: -112px -128px; +} +.mapIcon16.rank-chiefengineer { + background-position: -176px -112px; +} +.mapIcon16.rank-researchdirector { + background-position: -128px -128px; +} +.mapIcon16.rank-chiefmedicalofficer { + background-position: -32px -128px; +} + +/* Engineering Positions */ +.mapIcon16.rank-engineer { + background-position: -176px -112px; +} +.mapIcon16.rank-atmospherictechnician { + background-position: -176px -112px; +} + +/* Medical Positions */ +.mapIcon16.rank-medicaldoctor { + background-position: -32px -128px; +} +.mapIcon16.rank-geneticist { + background-position: -32px -128px; +} +.mapIcon16.rank-psychiatrist { + background-position: -32px -128px; +} +.mapIcon16.rank-chemist { + background-position: -32px -128px; +} + +/* Science Positions */ +.mapIcon16.rank-scientist { + background-position: -128px -128px; +} +.mapIcon16.rank-geneticist { + background-position: -128px -128px; +} +.mapIcon16.rank-roboticist { + background-position: -128px -128px; +} +.mapIcon16.rank-xenobiologist { + background-position: -128px -128px; +} + +/* Security Positions */ +.mapIcon16.rank-warden { + background-position: -112px -128px; +} +.mapIcon16.rank-detective { + background-position: -112px -128px; +} +.mapIcon16.rank-securityofficer { + background-position: -112px -128px; +} + diff --git a/nano/css/layout_basic.css b/nano/css/layout_basic.css new file mode 100644 index 00000000..fa16503a --- /dev/null +++ b/nano/css/layout_basic.css @@ -0,0 +1,21 @@ +body { + background: #000000 50% 0 repeat; +} + +#uiContent { + clear: both; + padding: 8px; +} + +#uiLoadingNotice { + position: relative; + background: url(uiNoticeBackground.jpg) 50% 50%; + color: #000000; + font-size: 14px; + font-style: italic; + font-weight: bold; + padding: 3px 4px 3px 4px; + margin: 4px 0 4px 0; +} + + diff --git a/nano/css/layout_default.css b/nano/css/layout_default.css new file mode 100644 index 00000000..38010b6e --- /dev/null +++ b/nano/css/layout_default.css @@ -0,0 +1,128 @@ +body { + background: #000000 50% 0 repeat; +} + +#uiWrapper { + width: 100%; + height: 100%; + -ms-user-select: none; + user-select: none; +} + +#uiTitleWrapper { + position: relative; + height: 30px; +} + +#uiTitleText { + position: absolute; + top: 6px; + left: 44px; + width: 66%; + overflow: hidden; + color: #E9C183; + font-size: 16px; +} + +#uiTitle.icon { + padding: 6px 8px 6px 42px; + background-position: 2px 50%; + background-repeat: no-repeat; +} + +#uiTitleFluff { + position: absolute; + top: 4px; + right: 12px; + width: 42px; + height: 24px; + background: url(uiTitleFluff.png) 50% 50% no-repeat; +} + +#uiStatusIcon { + position: absolute; + top: 4px; + left: 12px; + width: 24px; + height: 24px; +} + +#uiMapWrapper { + clear: both; + padding: 8px; +} + +#uiMapHeader { + position: relative; + clear: both; +} + +#uiMapContainer { + position: relative; + width: 100%; + height: 600px; + overflow: hidden; + border: 1px solid #40628a; + background: url(nanomapBackground.png); +} + +#uiMap { + position: absolute; + top: 50%; + left: 50%; + margin: -512px 0 0 -512px; + width: 256px; + height: 256px; + overflow: hidden; + zoom: 4; +} + +#uiMapImage { + position: absolute; + bottom: 1px; + left: 1px; + width: 256px; + height: 256px; +} + +#uiMapContent { + position: absolute; + bottom: 0px; + left: 0px; + width: 256px; + height: 256px; +} + +#uiMapFooter { + position: relative; + clear: both; +} + +#uiContent { + clear: both; + padding: 8px; +} + +#uiMapTooltip { + position: absolute; + right: 10px; + top: 10px; + border: 1px solid #40628a; + background-color: #272727; + padding: 8px; + display: none; + z-index: 9999; +} + +#uiLoadingNotice { + position: relative; + background: url(uiNoticeBackground.jpg) 50% 50%; + color: #000000; + font-size: 14px; + font-style: italic; + font-weight: bold; + padding: 3px 4px 3px 4px; + margin: 4px 0 4px 0; +} + + diff --git a/nano/css/shared.css b/nano/css/shared.css new file mode 100644 index 00000000..69703404 --- /dev/null +++ b/nano/css/shared.css @@ -0,0 +1,705 @@ +body { + padding: 0; + margin: 0; + font-size: 12px; + color: #00ff00; + line-height: 170%; + font-family: fixedsys; + background: #272727; +} + +#uiNoScript { + position: fixed; + top: 50%; + left: 50%; + margin: -60px 0 0 -150px; + width: 280px; + height: 120px; + background: #ffffff; + border: 2px solid #ff0000; + color: #000000; + font-size: 10px; + font-weight: bold; + z-index: 9999; + padding: 0px 10px; + text-align: center; +} + +hr { + background-color: #40628a; + height: 1px; +} + +.link, .linkOn, .linkOff, .selected, .disabled, .yellowButton, .redButton { + float: left; + min-width: 15px; + height: 16px; + text-align: center; + color: #ffffff; + text-decoration: none; + background: #003300; + border: 1px solid #00ff00; + padding: 0px 4px 4px 4px; + margin: 0 2px 2px 0; + cursor: default; + white-space: nowrap; +} + +.hasIcon { + padding: 0px 4px 4px 0px; +} + +a:hover, .zoomLink:hover, .linkActive:hover { + background: #003300; +} + +.linkPending, .linkPending:hover { + color: #ffffff; + background: #003300; +} + +a.white, a.white:link, a.white:visited, a.white:active { + color: #40628a; + text-decoration: none; + background: #ffffff; + border: 1px solid #161616; + padding: 1px 4px 1px 4px; + margin: 0 2px 0 0; + cursor: default; +} + +a.white:hover { + color: #ffffff; + background: #40628a; +} + +.hidden { + display: none; +} + +.linkOn, a.linkOn:link, a.linkOn:visited, a.linkOn:active, a.linkOn:hover, .selected, a.selected:link, a.selected:visited, a.selected:active, a.selected:hover { + color: #ffffff; + background: #2f943c; +} + +.linkOff, a.linkOff:link, a.linkOff:visited, a.linkOff:active, a.linkOff:hover, .disabled, a.disabled:link, a.disabled:visited, a.disabled:active, a.disabled:hover { + color: #ffffff; + background: #999999; + border-color: #666666; +} + +a.icon, .linkOn.icon, .linkOff.icon, .selected.icon, .disabled.icon { + position: relative; + padding: 1px 4px 2px 20px; +} + +a.icon img, .linkOn.icon img, .linkOff.icon img, .selected.icon img, .disabled.icon img { + position: absolute; + top: 0; + left: 0; + width: 18px; + height: 18px; +} + +.linkDanger, a.linkDanger:link, a.linkDanger:visited, a.linkDanger:active { + color: #ffffff; + background-color: #ff0000; + border-color: #aa0000; +} + +.linkDanger:hover { + background-color: #ff6666; +} + +ul { + padding: 4px 0 0 10px; + margin: 0; + list-style-type: none; +} + +li { + padding: 0 0 2px 0; +} + +img, a img { + border-style: none; +} + +h1, h2, h3, h4, h5, h6 { + margin: 0; + padding: 12px 0 6px 0; + color: #FFFFFF; + clear: both; +} + +h1 { + font-size: 18px; +} + +h2 { + font-size: 16px; +} + +h3 { + font-size: 14px; +} + +h4 { + font-size: 12px; +} + +abbr { + border-bottom: .1em dotted; +} + +.white { + color: white; + font-weight: bold; +} + +.good { + color: #4f7529; + font-weight: bold; +} + +.average { + color: #cd6500; + font-weight: bold; +} + +.bad { + color: #ee0000; + font-weight: bold; +} + +.idle { + color: #272727; + font-weight: bold; +} + +.redButton { + background: #ea0000; +} + +.yellowButton { + background: #cacc00; +} + +.highlight { + color: #8BA5C4; +} + +.dark { + color: #272727; +} + +.caption { + font-size: 10px; + font-weight: bold; + padding: 5px; +} + +.footer { + font-size: 10px; +} + +.noticePlaceholder { + position: relative; + font-size: 12px; + font-weight: bold; + padding: 3px 4px 3px 4px; + margin: 4px 0 4px 0; +} + +.notice { + position: relative; + background: url(uiNoticeBackground.jpg) 50% 50%; + color: #000000; + font-size: 12px; + font-weight: bold; + padding: 3px 4px 3px 4px; + margin: 4px 0 4px 0; +} + +.notice.icon { + padding: 2px 4px 0 20px; +} + +.notice img { + position: absolute; + top: 0; + left: 0; + width: 16px; + height: 16px; +} + +div.notice { + clear: both; +} + +.notice.info { + background: url(uiInfoBackground.jpg) 50% 50%; +} + +.itemGroup { + border: 1px solid #e9c183; + background: #2c2c2c; + padding: 4px; + clear: both; +} + +.item { + width: 100%; + margin: 4px 0 0 0; + clear: both; + overflow: auto; +} + +.itemContentNarrow, .itemContent { + float: left; +} + +.itemContentNarrow { + width: 30%; +} + +.itemContent { + width: 69%; +} + +.itemLabelNarrow, .itemLabel, .itemLabelWide, .itemLabelWider, .itemLabelWidest { + float: left; + color: #e9c183; +} + +.itemLabelNarrow { + width: 20%; +} + +.itemLabel { + width: 30%; +} + +.itemLabelWide { + width: 45%; +} + +.itemLabelWider { + width: 69%; +} + +.itemLabelWidest { + width: 100%; +} + +.itemContentWide { + float: left; + width: 79%; +} + +.itemContentSmall { + float: left; + width: 33%; +} + +.itemContentMedium { + float: left; + width: 55%; +} + +.statusDisplay { + background: #000000; + color: #ffffff; + border: 1px solid #40628a; + padding: 4px; + margin: 3px 0; + overflow: hidden; +} + +.statusDisplayRecords { + background: #000000; + color: #ffffff; + border: 1px solid #40628a; + padding: 4px; + margin: 3px 0; + overflow-x: hidden; + overflow-y: auto; +} + +.statusDisplayComm { + width: 100%; + background: rgba(0, 0, 0, 0.5); + color: #ffffff; + padding-bottom: 4px; + border-top: 0 none; + border-left: 0 none; + border-right: 0 none; + border-bottom: 2px inset #40628a; + margin: 3px 0; + overflow: hidden; +} + +.statusLabel { + width: 138px; + float: left; + overflow: hidden; + color: #98B0C3; +} + +.statusValue { + float: left; +} + +.block { + padding: 8px; + margin: 10px 4px 4px 4px; + border: 1px solid #40628a; + background-color: #202020; +} + +.block h3 { + padding: 0; +} + +.displayBar { + position: relative; + width: 236px; + height: 16px; + border: 1px solid #666666; + float: left; + margin: 0 5px 0 0; + overflow: hidden; + background: #000000; +} + +.displayBarText, .displayBarVerticalText, .displayBarBeakerText{ + position: absolute; + top: -2px; + left: 5px; + width: 100%; + height: 100%; + color: #ffffff; + font-weight: normal; +} + +.displayBarFill { + width: 0%; + height: 100%; + background: #40628a; + overflow: hidden; + float: left; +} + +.displayBarVertical { + position: relative; + width: 16px; + height: 200px; + border: 1px solid #666666; + float: left; + margin: 0 5px 0 0; + overflow: hidden; + background: #40628a; +} + +.displayBarVerticalFill { + width: 100%; + height: 0%; + overflow: hidden; + float: left; + background: #000000; +} + +/*used in xenobio2 computer*/ + +.displayBarBeaker { + position: relative; + width: 100px; + height: 110px; + border-right: 2px solid rgb(102, 179, 255); + border-left: 2px solid rgb(102, 179, 255); + border-bottom: 2px solid rgb(102, 179, 255); + float: left; + margin: 0 5px 0 0; + overflow: hidden; + background: #40628a; +} + +.displayBarBeakerFill { + width: 100%; + height: 0%; + overflow: hidden; + float: left; + background: rgba(153, 204, 255, 0.3); +} + +.displayBarFill.alignRight { + float: right; +} + +.displayBarFill.good { + color: #ffffff; + background: #4f7529; +} + +.displayBarFill.average { + color: #ffffff; + background: #cd6500; +} + +.displayBarFill.bad { + color: #ffffff; + background: #ee0000; +} + +.displayBarFill.highlight { + color: #ffffff; + background: #8BA5C4; +} + +.clearBoth { + clear: both; +} + +.clearLeft { + clear: left; +} + +.clearRight { + clear: right; +} + +.line { + width: 100%; + clear: both; +} + +.inactive, a.inactive:link, a.inactive:visited, a.inactive:active, a.inactive:hover { + color: #ffffff; + background: #999999; + border-color: #666666; +} + +.fixedLeft { + width: 110px; + float: left; +} + +.fixedLeftWide { + width: 165px; + float: left; +} + +.fixedLeftWider { + width: 220px; + float: left; +} + +.fixedLeftWidest { + width: 250px; + float: left; +} + +.fixedLeftWiderRed { + width: 220px; + float: left; + background: #ee0000; +} + +.floatRight { + float: right; +} + +.floatLeft { + float: left; +} + +/* Used in PDA */ + +.wholeScreen { + position: absolute; + color: #517087; + font-size: 16px; + font-weight: bold; + text-align: center; +} + +.pdalink { + float: left; + white-space: nowrap; +} + +/* DNA Modifier UI (dna_modifier.tmpl) */ + +.dnaBlock { + float: left; + width: 90px; + padding: 0 0 5px 0; +} + +.dnaBlockNumber { + font-family: Fixed, monospace; + float: left; + color: #ffffff; + background: #363636; + min-width: 20px; + height: 20px; + padding: 0; + text-align: center; +} + +.dnaSubBlock { + font-family: Fixed, monospace; + float: left; + padding: 0; + min-width: 16px; + height: 20px; + text-align: center; +} + +.mask { + position: fixed; + left: 0; + top: 0; + width: 100%; + height: 100%; + background: url(uiMaskBackground.png); +} + +.maskContent { + width: 100%; + height: 200px; + margin: 200px 0; + text-align: center; +} + +table.fixed { + table-layout:fixed; +} + +table.fixed td { + overflow: hidden; +} + +/* Table stuffs for power monitor */ +table.pmon { + border: 2px solid RoyalBlue; +} + +table.pmon td, table.pmon th { + border-bottom: 1px dotted black; + padding: 0px 5px 0px 5px; +} + +/* Table Stuffs for manifest*/ + +th.command { + background: #3333FF; + font-weight: bold; + color: #ffffff; +} + +th.spt { + background: #4f4ff2; + font-weight: bold; + color: #ffffff; +} + +th.sec { + background: #8e0000; + font-weight: bold; + color: #ffffff; +} + +th.med { + background: #006600; + font-weight: bold; + color: #ffffff; +} + +th.eng { + background: #b27300; + font-weight: bold; + color: #ffffff; +} + +th.sci { + background: #a65ba6; + font-weight: bold; + color: #ffffff; +} + +th.car { + background: #bb9040; + font-weight: bold; + color: #ffffff; +} + +th.sup { + background: #bb9040; + font-weight: bold; + color: #ffffff; +} + +th.civ { + background: #a32800; + font-weight: bold; + color: #ffffff; +} + +th.srv { + background: #88b764; + font-weight: bold; + color: #ffffff; +} + +th.exp { + background: #68099e; + font-weight: bold; + color: #ffffff; +} + +th.misc { + background: #666666; + font-weight: bold; + color: #ffffff; +} + +th.bot { + background: #414249; + font-weight: bold; + color: #ffffff; +} + +/* Damage colors for crew monitoring computer */ + +.burn { + color: orange; +} + +.brute { + color: red; +} + +.toxin { + color: green; +} + +.oxyloss { + color: cyan; +} + +/* 75px width used in power monitoring console buttons */ +.width75btn { + width: 75px; +} +.wideTable tr:nth-child(odd) { + background-color: #272727; +} + +/* Candystriped rows for tables */ +.candystripe { + background-color: rgba(148, 148, 148, 0.25); +} +.candystripe:nth-child(odd) { + background-color: rgba(0, 0, 0, 0.16); +} \ No newline at end of file diff --git a/nano/images/alpha/alpha-1.png b/nano/images/alpha/alpha-1.png new file mode 100644 index 00000000..bdb37823 Binary files /dev/null and b/nano/images/alpha/alpha-1.png differ diff --git a/nano/images/alpha/alpha-2.png b/nano/images/alpha/alpha-2.png new file mode 100644 index 00000000..0d42daad Binary files /dev/null and b/nano/images/alpha/alpha-2.png differ diff --git a/nano/images/alpha/alpha-3.png b/nano/images/alpha/alpha-3.png new file mode 100644 index 00000000..b6c24a9b Binary files /dev/null and b/nano/images/alpha/alpha-3.png differ diff --git a/nano/images/example/example-1.png b/nano/images/example/example-1.png new file mode 100644 index 00000000..d3f74bc2 Binary files /dev/null and b/nano/images/example/example-1.png differ diff --git a/nano/images/example/example-2.png b/nano/images/example/example-2.png new file mode 100644 index 00000000..a623ad86 Binary files /dev/null and b/nano/images/example/example-2.png differ diff --git a/nano/images/example/example-3.png b/nano/images/example/example-3.png new file mode 100644 index 00000000..905c3714 Binary files /dev/null and b/nano/images/example/example-3.png differ diff --git a/nano/images/exodus/exodus-1.png b/nano/images/exodus/exodus-1.png new file mode 100644 index 00000000..62e9a352 Binary files /dev/null and b/nano/images/exodus/exodus-1.png differ diff --git a/nano/images/exodus/exodus-2.png b/nano/images/exodus/exodus-2.png new file mode 100644 index 00000000..5e4f831b Binary files /dev/null and b/nano/images/exodus/exodus-2.png differ diff --git a/nano/images/modular_computers/alarm_green.gif b/nano/images/modular_computers/alarm_green.gif new file mode 100644 index 00000000..7c2570c8 Binary files /dev/null and b/nano/images/modular_computers/alarm_green.gif differ diff --git a/nano/images/modular_computers/alarm_red.gif b/nano/images/modular_computers/alarm_red.gif new file mode 100644 index 00000000..327d58e4 Binary files /dev/null and b/nano/images/modular_computers/alarm_red.gif differ diff --git a/nano/images/modular_computers/batt_100.gif b/nano/images/modular_computers/batt_100.gif new file mode 100644 index 00000000..ccdbd433 Binary files /dev/null and b/nano/images/modular_computers/batt_100.gif differ diff --git a/nano/images/modular_computers/batt_20.gif b/nano/images/modular_computers/batt_20.gif new file mode 100644 index 00000000..1d5e38fc Binary files /dev/null and b/nano/images/modular_computers/batt_20.gif differ diff --git a/nano/images/modular_computers/batt_40.gif b/nano/images/modular_computers/batt_40.gif new file mode 100644 index 00000000..d5cedb99 Binary files /dev/null and b/nano/images/modular_computers/batt_40.gif differ diff --git a/nano/images/modular_computers/batt_5.gif b/nano/images/modular_computers/batt_5.gif new file mode 100644 index 00000000..ceac8f3a Binary files /dev/null and b/nano/images/modular_computers/batt_5.gif differ diff --git a/nano/images/modular_computers/batt_60.gif b/nano/images/modular_computers/batt_60.gif new file mode 100644 index 00000000..d39534c8 Binary files /dev/null and b/nano/images/modular_computers/batt_60.gif differ diff --git a/nano/images/modular_computers/batt_80.gif b/nano/images/modular_computers/batt_80.gif new file mode 100644 index 00000000..9c299773 Binary files /dev/null and b/nano/images/modular_computers/batt_80.gif differ diff --git a/nano/images/modular_computers/charging.gif b/nano/images/modular_computers/charging.gif new file mode 100644 index 00000000..cf19ca72 Binary files /dev/null and b/nano/images/modular_computers/charging.gif differ diff --git a/nano/images/modular_computers/downloader_finished.gif b/nano/images/modular_computers/downloader_finished.gif new file mode 100644 index 00000000..f01b7c42 Binary files /dev/null and b/nano/images/modular_computers/downloader_finished.gif differ diff --git a/nano/images/modular_computers/downloader_running.gif b/nano/images/modular_computers/downloader_running.gif new file mode 100644 index 00000000..68fb977c Binary files /dev/null and b/nano/images/modular_computers/downloader_running.gif differ diff --git a/nano/images/modular_computers/ntnrc_idle.gif b/nano/images/modular_computers/ntnrc_idle.gif new file mode 100644 index 00000000..d47c01d5 Binary files /dev/null and b/nano/images/modular_computers/ntnrc_idle.gif differ diff --git a/nano/images/modular_computers/ntnrc_new.gif b/nano/images/modular_computers/ntnrc_new.gif new file mode 100644 index 00000000..af72a8b3 Binary files /dev/null and b/nano/images/modular_computers/ntnrc_new.gif differ diff --git a/nano/images/modular_computers/power_norm.gif b/nano/images/modular_computers/power_norm.gif new file mode 100644 index 00000000..2b8d60ed Binary files /dev/null and b/nano/images/modular_computers/power_norm.gif differ diff --git a/nano/images/modular_computers/power_warn.gif b/nano/images/modular_computers/power_warn.gif new file mode 100644 index 00000000..0c85b3a8 Binary files /dev/null and b/nano/images/modular_computers/power_warn.gif differ diff --git a/nano/images/modular_computers/shield.gif b/nano/images/modular_computers/shield.gif new file mode 100644 index 00000000..94d24d94 Binary files /dev/null and b/nano/images/modular_computers/shield.gif differ diff --git a/nano/images/modular_computers/sig_high.gif b/nano/images/modular_computers/sig_high.gif new file mode 100644 index 00000000..efb20f67 Binary files /dev/null and b/nano/images/modular_computers/sig_high.gif differ diff --git a/nano/images/modular_computers/sig_lan.gif b/nano/images/modular_computers/sig_lan.gif new file mode 100644 index 00000000..07ba929f Binary files /dev/null and b/nano/images/modular_computers/sig_lan.gif differ diff --git a/nano/images/modular_computers/sig_low.gif b/nano/images/modular_computers/sig_low.gif new file mode 100644 index 00000000..08f98bae Binary files /dev/null and b/nano/images/modular_computers/sig_low.gif differ diff --git a/nano/images/modular_computers/sig_none.gif b/nano/images/modular_computers/sig_none.gif new file mode 100644 index 00000000..79840d8a Binary files /dev/null and b/nano/images/modular_computers/sig_none.gif differ diff --git a/nano/images/modular_computers/sig_warning.gif b/nano/images/modular_computers/sig_warning.gif new file mode 100644 index 00000000..17f6f619 Binary files /dev/null and b/nano/images/modular_computers/sig_warning.gif differ diff --git a/nano/images/modular_computers/smmon_0.gif b/nano/images/modular_computers/smmon_0.gif new file mode 100644 index 00000000..7b716c4e Binary files /dev/null and b/nano/images/modular_computers/smmon_0.gif differ diff --git a/nano/images/modular_computers/smmon_1.gif b/nano/images/modular_computers/smmon_1.gif new file mode 100644 index 00000000..bbe319b8 Binary files /dev/null and b/nano/images/modular_computers/smmon_1.gif differ diff --git a/nano/images/modular_computers/smmon_2.gif b/nano/images/modular_computers/smmon_2.gif new file mode 100644 index 00000000..9c58edd3 Binary files /dev/null and b/nano/images/modular_computers/smmon_2.gif differ diff --git a/nano/images/modular_computers/smmon_3.gif b/nano/images/modular_computers/smmon_3.gif new file mode 100644 index 00000000..dc7c8734 Binary files /dev/null and b/nano/images/modular_computers/smmon_3.gif differ diff --git a/nano/images/modular_computers/smmon_4.gif b/nano/images/modular_computers/smmon_4.gif new file mode 100644 index 00000000..8a75e6e1 Binary files /dev/null and b/nano/images/modular_computers/smmon_4.gif differ diff --git a/nano/images/modular_computers/smmon_5.gif b/nano/images/modular_computers/smmon_5.gif new file mode 100644 index 00000000..59356bed Binary files /dev/null and b/nano/images/modular_computers/smmon_5.gif differ diff --git a/nano/images/modular_computers/smmon_6.gif b/nano/images/modular_computers/smmon_6.gif new file mode 100644 index 00000000..aea2f879 Binary files /dev/null and b/nano/images/modular_computers/smmon_6.gif differ diff --git a/nano/images/nanomapBackground.png b/nano/images/nanomapBackground.png new file mode 100644 index 00000000..f3ead016 Binary files /dev/null and b/nano/images/nanomapBackground.png differ diff --git a/nano/images/source/NTLogoRevised.fla b/nano/images/source/NTLogoRevised.fla new file mode 100644 index 00000000..47ea8143 Binary files /dev/null and b/nano/images/source/NTLogoRevised.fla differ diff --git a/nano/images/source/icon-eye.xcf b/nano/images/source/icon-eye.xcf new file mode 100644 index 00000000..53ba7383 Binary files /dev/null and b/nano/images/source/icon-eye.xcf differ diff --git a/nano/images/source/uiBackground-Syndicate.xcf b/nano/images/source/uiBackground-Syndicate.xcf new file mode 100644 index 00000000..c86cea69 Binary files /dev/null and b/nano/images/source/uiBackground-Syndicate.xcf differ diff --git a/nano/images/source/uiBackground.fla b/nano/images/source/uiBackground.fla new file mode 100644 index 00000000..60f9f1ee Binary files /dev/null and b/nano/images/source/uiBackground.fla differ diff --git a/nano/images/source/uiBackground.xcf b/nano/images/source/uiBackground.xcf new file mode 100644 index 00000000..d20db24f Binary files /dev/null and b/nano/images/source/uiBackground.xcf differ diff --git a/nano/images/source/uiBasicBackground.xcf b/nano/images/source/uiBasicBackground.xcf new file mode 100644 index 00000000..56a31d7b Binary files /dev/null and b/nano/images/source/uiBasicBackground.xcf differ diff --git a/nano/images/source/uiIcons16Green.xcf b/nano/images/source/uiIcons16Green.xcf new file mode 100644 index 00000000..a7027a28 Binary files /dev/null and b/nano/images/source/uiIcons16Green.xcf differ diff --git a/nano/images/source/uiIcons16Red.xcf b/nano/images/source/uiIcons16Red.xcf new file mode 100644 index 00000000..c07e4f64 Binary files /dev/null and b/nano/images/source/uiIcons16Red.xcf differ diff --git a/nano/images/source/uiIcons24.xcf b/nano/images/source/uiIcons24.xcf new file mode 100644 index 00000000..5dcd8fd2 Binary files /dev/null and b/nano/images/source/uiIcons24.xcf differ diff --git a/nano/images/source/uiNoticeBackground.xcf b/nano/images/source/uiNoticeBackground.xcf new file mode 100644 index 00000000..d1f074f1 Binary files /dev/null and b/nano/images/source/uiNoticeBackground.xcf differ diff --git a/nano/images/source/uiTitleBackground.xcf b/nano/images/source/uiTitleBackground.xcf new file mode 100644 index 00000000..7de14907 Binary files /dev/null and b/nano/images/source/uiTitleBackground.xcf differ diff --git a/nano/images/status_icons/c_charging.gif b/nano/images/status_icons/c_charging.gif new file mode 100644 index 00000000..e080e27c Binary files /dev/null and b/nano/images/status_icons/c_charging.gif differ diff --git a/nano/images/status_icons/c_discharging.gif b/nano/images/status_icons/c_discharging.gif new file mode 100644 index 00000000..793fa589 Binary files /dev/null and b/nano/images/status_icons/c_discharging.gif differ diff --git a/nano/images/status_icons/c_max.gif b/nano/images/status_icons/c_max.gif new file mode 100644 index 00000000..7f26e51d Binary files /dev/null and b/nano/images/status_icons/c_max.gif differ diff --git a/nano/images/torch/torch-1.png b/nano/images/torch/torch-1.png new file mode 100644 index 00000000..74ca43e7 Binary files /dev/null and b/nano/images/torch/torch-1.png differ diff --git a/nano/images/torch/torch-2.png b/nano/images/torch/torch-2.png new file mode 100644 index 00000000..eee41ff4 Binary files /dev/null and b/nano/images/torch/torch-2.png differ diff --git a/nano/images/torch/torch-3.png b/nano/images/torch/torch-3.png new file mode 100644 index 00000000..2cf2dbbf Binary files /dev/null and b/nano/images/torch/torch-3.png differ diff --git a/nano/images/torch/torch-4.png b/nano/images/torch/torch-4.png new file mode 100644 index 00000000..2be03662 Binary files /dev/null and b/nano/images/torch/torch-4.png differ diff --git a/nano/images/torch/torch-5.png b/nano/images/torch/torch-5.png new file mode 100644 index 00000000..cc95fc2c Binary files /dev/null and b/nano/images/torch/torch-5.png differ diff --git a/nano/images/uiBackground-Syndicate.png b/nano/images/uiBackground-Syndicate.png new file mode 100644 index 00000000..84898d5c Binary files /dev/null and b/nano/images/uiBackground-Syndicate.png differ diff --git a/nano/images/uiBackground.png b/nano/images/uiBackground.png new file mode 100644 index 00000000..73e6461a Binary files /dev/null and b/nano/images/uiBackground.png differ diff --git a/nano/images/uiBasicBackground.png b/nano/images/uiBasicBackground.png new file mode 100644 index 00000000..72b13c55 Binary files /dev/null and b/nano/images/uiBasicBackground.png differ diff --git a/nano/images/uiIcons16.png b/nano/images/uiIcons16.png new file mode 100644 index 00000000..2017c88d Binary files /dev/null and b/nano/images/uiIcons16.png differ diff --git a/nano/images/uiIcons16Green.png b/nano/images/uiIcons16Green.png new file mode 100644 index 00000000..de0e33db Binary files /dev/null and b/nano/images/uiIcons16Green.png differ diff --git a/nano/images/uiIcons16Red.png b/nano/images/uiIcons16Red.png new file mode 100644 index 00000000..1c72dfe1 Binary files /dev/null and b/nano/images/uiIcons16Red.png differ diff --git a/nano/images/uiIcons24.png b/nano/images/uiIcons24.png new file mode 100644 index 00000000..ddf88b0d Binary files /dev/null and b/nano/images/uiIcons24.png differ diff --git a/nano/images/uiIcons64.png b/nano/images/uiIcons64.png new file mode 100644 index 00000000..b58eb78f Binary files /dev/null and b/nano/images/uiIcons64.png differ diff --git a/nano/images/uiLinkPendingIcon.gif b/nano/images/uiLinkPendingIcon.gif new file mode 100644 index 00000000..c3070fd1 Binary files /dev/null and b/nano/images/uiLinkPendingIcon.gif differ diff --git a/nano/images/uiMaskBackground.png b/nano/images/uiMaskBackground.png new file mode 100644 index 00000000..6494f78a Binary files /dev/null and b/nano/images/uiMaskBackground.png differ diff --git a/nano/images/uiNoticeBackground.jpg b/nano/images/uiNoticeBackground.jpg new file mode 100644 index 00000000..dffe2f29 Binary files /dev/null and b/nano/images/uiNoticeBackground.jpg differ diff --git a/nano/images/uiTitleFluff-Syndicate.png b/nano/images/uiTitleFluff-Syndicate.png new file mode 100644 index 00000000..9e86c078 Binary files /dev/null and b/nano/images/uiTitleFluff-Syndicate.png differ diff --git a/nano/images/uiTitleFluff.png b/nano/images/uiTitleFluff.png new file mode 100644 index 00000000..9e86c078 Binary files /dev/null and b/nano/images/uiTitleFluff.png differ diff --git a/nano/js/libraries-old.min.js b/nano/js/libraries-old.min.js new file mode 100644 index 00000000..fabe4e7d --- /dev/null +++ b/nano/js/libraries-old.min.js @@ -0,0 +1 @@ +(function(e,t){function H(e){var t=e.length,n=w.type(e);if(w.isWindow(e)){return false}if(e.nodeType===1&&t){return true}return n==="array"||n!=="function"&&(t===0||typeof t==="number"&&t>0&&t-1 in e)}function j(e){var t=B[e]={};w.each(e.match(S)||[],function(e,n){t[n]=true});return t}function q(e,n,r,i){if(!w.acceptData(e)){return}var s,o,u=w.expando,a=e.nodeType,f=a?w.cache:e,l=a?e[u]:e[u]&&u;if((!l||!f[l]||!i&&!f[l].data)&&r===t&&typeof n==="string"){return}if(!l){if(a){l=e[u]=c.pop()||w.guid++}else{l=u}}if(!f[l]){f[l]=a?{}:{toJSON:w.noop}}if(typeof n==="object"||typeof n==="function"){if(i){f[l]=w.extend(f[l],n)}else{f[l].data=w.extend(f[l].data,n)}}o=f[l];if(!i){if(!o.data){o.data={}}o=o.data}if(r!==t){o[w.camelCase(n)]=r}if(typeof n==="string"){s=o[n];if(s==null){s=o[w.camelCase(n)]}}else{s=o}return s}function R(e,t,n){if(!w.acceptData(e)){return}var r,i,s=e.nodeType,o=s?w.cache:e,u=s?e[w.expando]:w.expando;if(!o[u]){return}if(t){r=n?o[u]:o[u].data;if(r){if(!w.isArray(t)){if(t in r){t=[t]}else{t=w.camelCase(t);if(t in r){t=[t]}else{t=t.split(" ")}}}else{t=t.concat(w.map(t,w.camelCase))}i=t.length;while(i--){delete r[t[i]]}if(n?!z(r):!w.isEmptyObject(r)){return}}}if(!n){delete o[u].data;if(!z(o[u])){return}}if(s){w.cleanData([e],true)}else if(w.support.deleteExpando||o!=o.window){delete o[u]}else{o[u]=null}}function U(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(I,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r==="string"){try{r=r==="true"?true:r==="false"?false:r==="null"?null:+r+""===r?+r:F.test(r)?w.parseJSON(r):r}catch(s){}w.data(e,n,r)}else{r=t}}return r}function z(e){var t;for(t in e){if(t==="data"&&w.isEmptyObject(e[t])){continue}if(t!=="toJSON"){return false}}return true}function it(){return true}function st(){return false}function ot(){try{return o.activeElement}catch(e){}}function ct(e,t){do{e=e[t]}while(e&&e.nodeType!==1);return e}function ht(e,t,n){if(w.isFunction(t)){return w.grep(e,function(e,r){return!!t.call(e,r,e)!==n})}if(t.nodeType){return w.grep(e,function(e){return e===t!==n})}if(typeof t==="string"){if(ut.test(t)){return w.filter(t,e,n)}t=w.filter(t,e)}return w.grep(e,function(e){return w.inArray(e,t)>=0!==n})}function pt(e){var t=dt.split("|"),n=e.createDocumentFragment();if(n.createElement){while(t.length){n.createElement(t.pop())}}return n}function Mt(e,t){return w.nodeName(e,"table")&&w.nodeName(t.nodeType===1?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function _t(e){e.type=(w.find.attr(e,"type")!==null)+"/"+e.type;return e}function Dt(e){var t=Ct.exec(e.type);if(t){e.type=t[1]}else{e.removeAttribute("type")}return e}function Pt(e,t){var n,r=0;for(;(n=e[r])!=null;r++){w._data(n,"globalEval",!t||w._data(t[r],"globalEval"))}}function Ht(e,t){if(t.nodeType!==1||!w.hasData(e)){return}var n,r,i,s=w._data(e),o=w._data(t,s),u=s.events;if(u){delete o.handle;o.events={};for(n in u){for(r=0,i=u[n].length;r").css("cssText","display:block !important")).appendTo(t.documentElement);t=(It[0].contentWindow||It[0].contentDocument).document;t.write("");t.close();n=fn(e,t);It.detach()}Qt[e]=n}return n}function fn(e,t){var n=w(t.createElement(e)).appendTo(t.body),r=w.css(n[0],"display");n.remove();return r}function vn(e,t,n,r){var i;if(w.isArray(t)){w.each(t,function(t,i){if(n||cn.test(e)){r(e,i)}else{vn(e+"["+(typeof i==="object"?t:"")+"]",i,n,r)}})}else if(!n&&w.type(t)==="object"){for(i in t){vn(e+"["+i+"]",t[i],n,r)}}else{r(e,t)}}function _n(e){return function(t,n){if(typeof t!=="string"){n=t;t="*"}var r,i=0,s=t.toLowerCase().match(S)||[];if(w.isFunction(n)){while(r=s[i++]){if(r[0]==="+"){r=r.slice(1)||"*";(e[r]=e[r]||[]).unshift(n)}else{(e[r]=e[r]||[]).push(n)}}}}}function Dn(e,t,n,r){function o(u){var a;i[u]=true;w.each(e[u]||[],function(e,u){var f=u(t,n,r);if(typeof f==="string"&&!s&&!i[f]){t.dataTypes.unshift(f);o(f);return false}else if(s){return!(a=f)}});return a}var i={},s=e===An;return o(t.dataTypes[0])||!i["*"]&&o("*")}function Pn(e,n){var r,i,s=w.ajaxSettings.flatOptions||{};for(i in n){if(n[i]!==t){(s[i]?e:r||(r={}))[i]=n[i]}}if(r){w.extend(true,e,r)}return e}function Hn(e,n,r){var i,s,o,u,a=e.contents,f=e.dataTypes;while(f[0]==="*"){f.shift();if(s===t){s=e.mimeType||n.getResponseHeader("Content-Type")}}if(s){for(u in a){if(a[u]&&a[u].test(s)){f.unshift(u);break}}}if(f[0]in r){o=f[0]}else{for(u in r){if(!f[0]||e.converters[u+" "+f[0]]){o=u;break}if(!i){i=u}}o=o||i}if(o){if(o!==f[0]){f.unshift(o)}return r[o]}}function Bn(e,t,n,r){var i,s,o,u,a,f={},l=e.dataTypes.slice();if(l[1]){for(o in e.converters){f[o.toLowerCase()]=e.converters[o]}}s=l.shift();while(s){if(e.responseFields[s]){n[e.responseFields[s]]=t}if(!a&&r&&e.dataFilter){t=e.dataFilter(t,e.dataType)}a=s;s=l.shift();if(s){if(s==="*"){s=a}else if(a!=="*"&&a!==s){o=f[a+" "+s]||f["* "+s];if(!o){for(i in f){u=i.split(" ");if(u[1]===s){o=f[a+" "+u[0]]||f["* "+u[0]];if(o){if(o===true){o=f[i]}else if(f[i]!==true){s=u[0];l.unshift(u[1])}break}}}}if(o!==true){if(o&&e["throws"]){t=o(t)}else{try{t=o(t)}catch(c){return{state:"parsererror",error:o?c:"No conversion from "+a+" to "+s}}}}}}}return{state:"success",data:t}}function zn(){try{return new e.XMLHttpRequest}catch(t){}}function Wn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}function Yn(){setTimeout(function(){Xn=t});return Xn=w.now()}function Zn(e,t,n){var r,i=(Gn[t]||[]).concat(Gn["*"]),s=0,o=i.length;for(;s)[^>]*|#([\w-]*))$/,N=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,C=/^[\],:{}\s]*$/,k=/(?:^|:|,)(?:\s*\[)+/g,L=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,O=/^-ms-/,M=/-([\da-z])/gi,_=function(e,t){return t.toUpperCase()},D=function(e){if(o.addEventListener||e.type==="load"||o.readyState==="complete"){P();w.ready()}},P=function(){if(o.addEventListener){o.removeEventListener("DOMContentLoaded",D,false);e.removeEventListener("load",D,false)}else{o.detachEvent("onreadystatechange",D);e.detachEvent("onload",D)}};w.fn=w.prototype={jquery:h,constructor:w,init:function(e,n,r){var i,s;if(!e){return this}if(typeof e==="string"){if(e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3){i=[null,e,null]}else{i=T.exec(e)}if(i&&(i[1]||!n)){if(i[1]){n=n instanceof w?n[0]:n;w.merge(this,w.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,true));if(N.test(i[1])&&w.isPlainObject(n)){for(i in n){if(w.isFunction(this[i])){this[i](n[i])}else{this.attr(i,n[i])}}}return this}else{s=o.getElementById(i[2]);if(s&&s.parentNode){if(s.id!==i[2]){return r.find(e)}this.length=1;this[0]=s}this.context=o;this.selector=e;return this}}else if(!n||n.jquery){return(n||r).find(e)}else{return this.constructor(n).find(e)}}else if(e.nodeType){this.context=this[0]=e;this.length=1;return this}else if(w.isFunction(e)){return r.ready(e)}if(e.selector!==t){this.selector=e.selector;this.context=e.context}return w.makeArray(e,this)},selector:"",length:0,toArray:function(){return v.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);t.prevObject=this;t.context=this.context;return t},each:function(e,t){return w.each(this,e,t)},ready:function(e){w.ready.promise().done(e);return this},slice:function(){return this.pushStack(v.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n0){return}n.resolveWith(o,[w]);if(w.fn.trigger){w(o).trigger("ready").off("ready")}},isFunction:function(e){return w.type(e)==="function"},isArray:Array.isArray||function(e){return w.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){if(e==null){return String(e)}return typeof e==="object"||typeof e==="function"?l[g.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||w.type(e)!=="object"||e.nodeType||w.isWindow(e)){return false}try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf")){return false}}catch(r){return false}if(w.support.ownLast){for(n in e){return y.call(e,n)}}for(n in e){}return n===t||y.call(e,n)},isEmptyObject:function(e){var t;for(t in e){return false}return true},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){if(!e||typeof e!=="string"){return null}if(typeof t==="boolean"){n=t;t=false}t=t||o;var r=N.exec(e),i=!n&&[];if(r){return[t.createElement(r[1])]}r=w.buildFragment([e],t,i);if(i){w(i).remove()}return w.merge([],r.childNodes)},parseJSON:function(t){if(e.JSON&&e.JSON.parse){return e.JSON.parse(t)}if(t===null){return t}if(typeof t==="string"){t=w.trim(t);if(t){if(C.test(t.replace(L,"@").replace(A,"]").replace(k,""))){return(new Function("return "+t))()}}}w.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!=="string"){return null}try{if(e.DOMParser){i=new DOMParser;r=i.parseFromString(n,"text/xml")}else{r=new ActiveXObject("Microsoft.XMLDOM");r.async="false";r.loadXML(n)}}catch(s){r=t}if(!r||!r.documentElement||r.getElementsByTagName("parsererror").length){w.error("Invalid XML: "+n)}return r},noop:function(){},globalEval:function(t){if(t&&w.trim(t)){(e.execScript||function(t){e["eval"].call(e,t)})(t)}},camelCase:function(e){return e.replace(O,"ms-").replace(M,_)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,s=e.length,o=H(e);if(n){if(o){for(;is.cacheLength){delete t[e.shift()]}return t[n]=r}var e=[];return t}function at(e){e[b]=true;return e}function ft(e){var t=h.createElement("div");try{return!!e(t)}catch(n){return false}finally{if(t.parentNode){t.parentNode.removeChild(t)}t=null}}function lt(e,t){var n=e.split("|"),r=e.length;while(r--){s.attrHandle[n[r]]=t}}function ct(e,t){var n=t&&e,r=n&&e.nodeType===1&&t.nodeType===1&&(~t.sourceIndex||O)-(~e.sourceIndex||O);if(r){return r}if(n){while(n=n.nextSibling){if(n===t){return-1}}}return e?1:-1}function ht(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function pt(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function dt(e){return at(function(t){t=+t;return at(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--){if(n[i=s[o]]){n[i]=!(r[i]=n[i])}}})})}function vt(){}function mt(e,t){var n,r,i,o,u,a,f,l=N[e+" "];if(l){return t?0:l.slice(0)}u=e;a=[];f=s.preFilter;while(u){if(!n||(r=X.exec(u))){if(r){u=u.slice(r[0].length)||u}a.push(i=[])}n=false;if(r=V.exec(u)){n=r.shift();i.push({value:n,type:r[0].replace(W," ")});u=u.slice(n.length)}for(o in s.filter){if((r=G[o].exec(u))&&(!f[o]||(r=f[o](r)))){n=r.shift();i.push({value:n,type:o,matches:r});u=u.slice(n.length)}}if(!n){break}}return t?u.length:u?ot.error(e):N(e,a).slice(0)}function gt(e){var t=0,n=e.length,r="";for(;t1?function(t,n,r){var i=e.length;while(i--){if(!e[i](t,n,r)){return false}}return true}:e[0]}function wt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1){s[f]=!(o[f]=c)}}}}else{g=wt(g===o?g.splice(d,g.length):g);if(i){i(null,o,g,a)}else{H.apply(o,g)}}})}function St(e){var t,n,r,i=e.length,o=s.relative[e[0].type],u=o||s.relative[" "],a=o?1:0,l=yt(function(e){return e===t},u,true),c=yt(function(e){return j.call(t,e)>-1},u,true),h=[function(e,n,r){return!o&&(r||n!==f)||((t=n).nodeType?l(e,n,r):c(e,n,r))}];for(;a1&&bt(h),a>1&>(e.slice(0,a-1).concat({value:e[a-2].type===" "?"*":""})).replace(W,"$1"),n,a0,o=e.length>0,u=function(u,a,l,c,p){var d,v,m,g=[],y=0,b="0",w=u&&[],E=p!=null,x=f,T=u||o&&s.find["TAG"]("*",p&&a.parentNode||a),N=S+=x==null?1:Math.random()||.1;if(E){f=a!==h&&a;i=n}for(;(d=T[b])!=null;b++){if(o&&d){v=0;while(m=e[v++]){if(m(d,a,l)){c.push(d);break}}if(E){S=N;i=++n}}if(r){if(d=!m&&d){y--}if(u){w.push(d)}}}y+=b;if(r&&b!==y){v=0;while(m=t[v++]){m(w,g,a,l)}if(u){if(y>0){while(b--){if(!(w[b]||g[b])){g[b]=D.call(c)}}}g=wt(g)}H.apply(c,g);if(E&&!u&&g.length>0&&y+t.length>1){ot.uniqueSort(c)}}if(E){S=N;f=x}return w};return r?at(u):u}function Tt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&r.getById&&t.nodeType===9&&d&&s.relative[u[1].type]){t=(s.find["ID"](f.matches[0].replace(rt,it),t)||[])[0];if(!t){return n}e=e.slice(u.shift().value.length)}o=G["needsContext"].test(e)?0:u.length;while(o--){f=u[o];if(s.relative[l=f.type]){break}if(c=s.find[l]){if(i=c(f.matches[0].replace(rt,it),$.test(u[0].type)&&t.parentNode||t)){u.splice(o,1);e=i.length&>(u);if(!e){H.apply(n,i);return n}break}}}}}a(e,h)(i,t,!d,n,$.test(e));return n}var n,r,i,s,o,u,a,f,l,c,h,p,d,v,m,g,y,b="sizzle"+ -(new Date),E=e.document,S=0,x=0,T=ut(),N=ut(),C=ut(),k=false,L=function(e,t){if(e===t){k=true;return 0}return 0},A=typeof t,O=1<<31,M={}.hasOwnProperty,_=[],D=_.pop,P=_.push,H=_.push,B=_.slice,j=_.indexOf||function(e){var t=0,n=this.length;for(;t+~]|"+I+")"+I+"*"),$=new RegExp(I+"*[+~]"),J=new RegExp("="+I+"*([^\\]'\"]*)"+I+"*\\]","g"),K=new RegExp(z),Q=new RegExp("^"+R+"$"),G={ID:new RegExp("^#("+q+")"),CLASS:new RegExp("^\\.("+q+")"),TAG:new RegExp("^("+q.replace("w","w*")+")"),ATTR:new RegExp("^"+U),PSEUDO:new RegExp("^"+z),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+I+"*(even|odd|(([+-]|)(\\d*)n|)"+I+"*(?:([+-]|)"+I+"*(\\d+)|))"+I+"*\\)|)","i"),bool:new RegExp("^(?:"+F+")$","i"),needsContext:new RegExp("^"+I+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+I+"*((?:-\\d)?\\d*)"+I+"*\\)|)(?=[^-]|$)","i")},Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=new RegExp("\\\\([\\da-f]{1,6}"+I+"?|("+I+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,r&1023|56320)};try{H.apply(_=B.call(E.childNodes),E.childNodes);_[E.childNodes.length].nodeType}catch(st){H={apply:_.length?function(e,t){P.apply(e,B.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]){}e.length=n-1}}}u=ot.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":false};r=ot.support={};c=ot.setDocument=function(e){var t=e?e.ownerDocument||e:E,n=t.defaultView;if(t===h||t.nodeType!==9||!t.documentElement){return h}h=t;p=t.documentElement;d=!u(t);if(n&&n.attachEvent&&n!==n.top){n.attachEvent("onbeforeunload",function(){c()})}r.attributes=ft(function(e){e.className="i";return!e.getAttribute("className")});r.getElementsByTagName=ft(function(e){e.appendChild(t.createComment(""));return!e.getElementsByTagName("*").length});r.getElementsByClassName=ft(function(e){e.innerHTML="
            ";e.firstChild.className="i";return e.getElementsByClassName("i").length===2});r.getById=ft(function(e){p.appendChild(e).id=b;return!t.getElementsByName||!t.getElementsByName(b).length});if(r.getById){s.find["ID"]=function(e,t){if(typeof t.getElementById!==A&&d){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}};s.filter["ID"]=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}}else{delete s.find["ID"];s.filter["ID"]=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==A&&e.getAttributeNode("id");return n&&n.value===t}}}s.find["TAG"]=r.getElementsByTagName?function(e,t){if(typeof t.getElementsByTagName!==A){return t.getElementsByTagName(e)}}:function(e,t){var n,r=[],i=0,s=t.getElementsByTagName(e);if(e==="*"){while(n=s[i++]){if(n.nodeType===1){r.push(n)}}return r}return s};s.find["CLASS"]=r.getElementsByClassName&&function(e,t){if(typeof t.getElementsByClassName!==A&&d){return t.getElementsByClassName(e)}};m=[];v=[];if(r.qsa=Y.test(t.querySelectorAll)){ft(function(e){e.innerHTML="";if(!e.querySelectorAll("[selected]").length){v.push("\\["+I+"*(?:value|"+F+")")}if(!e.querySelectorAll(":checked").length){v.push(":checked")}});ft(function(e){var n=t.createElement("input");n.setAttribute("type","hidden");e.appendChild(n).setAttribute("t","");if(e.querySelectorAll("[t^='']").length){v.push("[*^$]="+I+"*(?:''|\"\")")}if(!e.querySelectorAll(":enabled").length){v.push(":enabled",":disabled")}e.querySelectorAll("*,:x");v.push(",.*:")})}if(r.matchesSelector=Y.test(g=p.webkitMatchesSelector||p.mozMatchesSelector||p.oMatchesSelector||p.msMatchesSelector)){ft(function(e){r.disconnectedMatch=g.call(e,"div");g.call(e,"[s!='']:x");m.push("!=",z)})}v=v.length&&new RegExp(v.join("|"));m=m.length&&new RegExp(m.join("|"));y=Y.test(p.contains)||p.compareDocumentPosition?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&(n.contains?n.contains(r):e.compareDocumentPosition&&e.compareDocumentPosition(r)&16))}:function(e,t){if(t){while(t=t.parentNode){if(t===e){return true}}}return false};L=p.compareDocumentPosition?function(e,n){if(e===n){k=true;return 0}var i=n.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(n);if(i){if(i&1||!r.sortDetached&&n.compareDocumentPosition(e)===i){if(e===t||y(E,e)){return-1}if(n===t||y(E,n)){return 1}return l?j.call(l,e)-j.call(l,n):0}return i&4?-1:1}return e.compareDocumentPosition?-1:1}:function(e,n){var r,i=0,s=e.parentNode,o=n.parentNode,u=[e],a=[n];if(e===n){k=true;return 0}else if(!s||!o){return e===t?-1:n===t?1:s?-1:o?1:l?j.call(l,e)-j.call(l,n):0}else if(s===o){return ct(e,n)}r=e;while(r=r.parentNode){u.unshift(r)}r=n;while(r=r.parentNode){a.unshift(r)}while(u[i]===a[i]){i++}return i?ct(u[i],a[i]):u[i]===E?-1:a[i]===E?1:0};return t};ot.matches=function(e,t){return ot(e,null,null,t)};ot.matchesSelector=function(e,t){if((e.ownerDocument||e)!==h){c(e)}t=t.replace(J,"='$1']");if(r.matchesSelector&&d&&(!m||!m.test(t))&&(!v||!v.test(t))){try{var n=g.call(e,t);if(n||r.disconnectedMatch||e.document&&e.document.nodeType!==11){return n}}catch(i){}}return ot(t,h,null,[e]).length>0};ot.contains=function(e,t){if((e.ownerDocument||e)!==h){c(e)}return y(e,t)};ot.attr=function(e,n){if((e.ownerDocument||e)!==h){c(e)}var i=s.attrHandle[n.toLowerCase()],o=i&&M.call(s.attrHandle,n.toLowerCase())?i(e,n,!d):t;return o===t?r.attributes||!d?e.getAttribute(n):(o=e.getAttributeNode(n))&&o.specified?o.value:null:o};ot.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)};ot.uniqueSort=function(e){var t,n=[],i=0,s=0;k=!r.detectDuplicates;l=!r.sortStable&&e.slice(0);e.sort(L);if(k){while(t=e[s++]){if(t===e[s]){i=n.push(s)}}while(i--){e.splice(n[i],1)}}return e};o=ot.getText=function(e){var t,n="",r=0,i=e.nodeType;if(!i){for(;t=e[r];r++){n+=o(t)}}else if(i===1||i===9||i===11){if(typeof e.textContent==="string"){return e.textContent}else{for(e=e.firstChild;e;e=e.nextSibling){n+=o(e)}}}else if(i===3||i===4){return e.nodeValue}return n};s=ot.selectors={cacheLength:50,createPseudo:at,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:true}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:true},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){e[1]=e[1].replace(rt,it);e[3]=(e[4]||e[5]||"").replace(rt,it);if(e[2]==="~="){e[3]=" "+e[3]+" "}return e.slice(0,4)},CHILD:function(e){e[1]=e[1].toLowerCase();if(e[1].slice(0,3)==="nth"){if(!e[3]){ot.error(e[0])}e[4]=+(e[4]?e[5]+(e[6]||1):2*(e[3]==="even"||e[3]==="odd"));e[5]=+(e[7]+e[8]||e[3]==="odd")}else if(e[3]){ot.error(e[0])}return e},PSEUDO:function(e){var n,r=!e[5]&&e[2];if(G["CHILD"].test(e[0])){return null}if(e[3]&&e[4]!==t){e[2]=e[4]}else if(r&&K.test(r)&&(n=mt(r,true))&&(n=r.indexOf(")",r.length-n)-r.length)){e[0]=e[0].slice(0,n);e[2]=r.slice(0,n)}return e.slice(0,3)}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return e==="*"?function(){return true}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=T[e+" "];return t||(t=new RegExp("(^|"+I+")"+e+"("+I+"|$)"))&&T(e,function(e){return t.test(typeof e.className==="string"&&e.className||typeof e.getAttribute!==A&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=ot.attr(r,e);if(i==null){return t==="!="}if(!t){return true}i+="";return t==="="?i===n:t==="!="?i!==n:t==="^="?n&&i.indexOf(n)===0:t==="*="?n&&i.indexOf(n)>-1:t==="$="?n&&i.slice(-n.length)===n:t==="~="?(" "+i+" ").indexOf(n)>-1:t==="|="?i===n||i.slice(0,n.length+1)===n+"-":false}},CHILD:function(e,t,n,r,i){var s=e.slice(0,3)!=="nth",o=e.slice(-4)!=="last",u=t==="of-type";return r===1&&i===0?function(e){return!!e.parentNode}:function(t,n,a){var f,l,c,h,p,d,v=s!==o?"nextSibling":"previousSibling",m=t.parentNode,g=u&&t.nodeName.toLowerCase(),y=!a&&!u;if(m){if(s){while(v){c=t;while(c=c[v]){if(u?c.nodeName.toLowerCase()===g:c.nodeType===1){return false}}d=v=e==="only"&&!d&&"nextSibling"}return true}d=[o?m.firstChild:m.lastChild];if(o&&y){l=m[b]||(m[b]={});f=l[e]||[];p=f[0]===S&&f[1];h=f[0]===S&&f[2];c=p&&m.childNodes[p];while(c=++p&&c&&c[v]||(h=p=0)||d.pop()){if(c.nodeType===1&&++h&&c===t){l[e]=[S,p,h];break}}}else if(y&&(f=(t[b]||(t[b]={}))[e])&&f[0]===S){h=f[1]}else{while(c=++p&&c&&c[v]||(h=p=0)||d.pop()){if((u?c.nodeName.toLowerCase()===g:c.nodeType===1)&&++h){if(y){(c[b]||(c[b]={}))[e]=[S,h]}if(c===t){break}}}}h-=i;return h===r||h%r===0&&h/r>=0}}},PSEUDO:function(e,t){var n,r=s.pseudos[e]||s.setFilters[e.toLowerCase()]||ot.error("unsupported pseudo: "+e);if(r[b]){return r(t)}if(r.length>1){n=[e,e,"",t];return s.setFilters.hasOwnProperty(e.toLowerCase())?at(function(e,n){var i,s=r(e,t),o=s.length;while(o--){i=j.call(e,s[o]);e[i]=!(n[i]=s[o])}}):function(e){return r(e,0,n)}}return r}},pseudos:{not:at(function(e){var t=[],n=[],r=a(e.replace(W,"$1"));return r[b]?at(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--){if(s=o[u]){e[u]=!(t[u]=s)}}}):function(e,i,s){t[0]=e;r(t,null,s,n);return!n.pop()}}),has:at(function(e){return function(t){return ot(e,t).length>0}}),contains:at(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:at(function(e){if(!Q.test(e||"")){ot.error("unsupported lang: "+e)}e=e.replace(rt,it).toLowerCase();return function(t){var n;do{if(n=d?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang")){n=n.toLowerCase();return n===e||n.indexOf(e+"-")===0}}while((t=t.parentNode)&&t.nodeType===1);return false}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===p},focus:function(e){return e===h.activeElement&&(!h.hasFocus||h.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===false},disabled:function(e){return e.disabled===true},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling){if(e.nodeName>"@"||e.nodeType===3||e.nodeType===4){return false}}return true},parent:function(e){return!s.pseudos["empty"](e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},text:function(e){var t;return e.nodeName.toLowerCase()==="input"&&e.type==="text"&&((t=e.getAttribute("type"))==null||t.toLowerCase()===e.type)},first:dt(function(){return[0]}),last:dt(function(e,t){return[t-1]}),eq:dt(function(e,t,n){return[n<0?n+t:n]}),even:dt(function(e,t){var n=0;for(;n=0;){e.push(r)}return e}),gt:dt(function(e,t,n){var r=n<0?n+t:n;for(;++r";e.firstChild.setAttribute("value","");return e.firstChild.getAttribute("value")===""})){lt("value",function(e,t,n){if(!n&&e.nodeName.toLowerCase()==="input"){return e.defaultValue}})}if(!ft(function(e){return e.getAttribute("disabled")==null})){lt(F,function(e,t,n){var r;if(!n){return(r=e.getAttributeNode(t))&&r.specified?r.value:e[t]===true?t.toLowerCase():null}})}w.find=ot;w.expr=ot.selectors;w.expr[":"]=w.expr.pseudos;w.unique=ot.uniqueSort;w.text=ot.getText;w.isXMLDoc=ot.isXML;w.contains=ot.contains})(e);var B={};w.Callbacks=function(e){e=typeof e==="string"?B[e]||j(e):w.extend({},e);var n,r,i,s,o,u,a=[],f=!e.once&&[],l=function(t){r=e.memory&&t;i=true;o=u||0;u=0;s=a.length;n=true;for(;a&&o-1){a.splice(r,1);if(n){if(r<=s){s--}if(r<=o){o--}}}})}return this},has:function(e){return e?w.inArray(e,a)>-1:!!(a&&a.length)},empty:function(){a=[];s=0;return this},disable:function(){a=f=r=t;return this},disabled:function(){return!a},lock:function(){f=t;if(!r){c.disable()}return this},locked:function(){return!f},fireWith:function(e,t){if(a&&(!i||f)){t=t||[];t=[e,t.slice?t.slice():t];if(n){f.push(t)}else{l(t)}}return this},fire:function(){c.fireWith(this,arguments);return this},fired:function(){return!!i}};return c};w.extend({Deferred:function(e){var t=[["resolve","done",w.Callbacks("once memory"),"resolved"],["reject","fail",w.Callbacks("once memory"),"rejected"],["notify","progress",w.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){i.done(arguments).fail(arguments);return this},then:function(){var e=arguments;return w.Deferred(function(n){w.each(t,function(t,s){var o=s[0],u=w.isFunction(e[t])&&e[t];i[s[1]](function(){var e=u&&u.apply(this,arguments);if(e&&w.isFunction(e.promise)){e.promise().done(n.resolve).fail(n.reject).progress(n.notify)}else{n[o+"With"](this===r?n.promise():this,u?[e]:arguments)}})});e=null}).promise()},promise:function(e){return e!=null?w.extend(e,r):r}},i={};r.pipe=r.then;w.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add;if(u){o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock)}i[s[0]]=function(){i[s[0]+"With"](this===i?r:this,arguments);return this};i[s[0]+"With"]=o.fireWith});r.promise(i);if(e){e.call(i,i)}return i},when:function(e){var t=0,n=v.call(arguments),r=n.length,i=r!==1||e&&w.isFunction(e.promise)?r:0,s=i===1?e:w.Deferred(),o=function(e,t,n){return function(r){t[e]=this;n[e]=arguments.length>1?v.call(arguments):r;if(n===u){s.notifyWith(t,n)}else if(!--i){s.resolveWith(t,n)}}},u,a,f;if(r>1){u=new Array(r);a=new Array(r);f=new Array(r);for(;t
            a";n=p.getElementsByTagName("*")||[];r=p.getElementsByTagName("a")[0];if(!r||!r.style||!n.length){return t}u=o.createElement("select");f=u.appendChild(o.createElement("option"));s=p.getElementsByTagName("input")[0];r.style.cssText="top:1px;float:left;opacity:.5";t.getSetAttribute=p.className!=="t";t.leadingWhitespace=p.firstChild.nodeType===3;t.tbody=!p.getElementsByTagName("tbody").length;t.htmlSerialize=!!p.getElementsByTagName("link").length;t.style=/top/.test(r.getAttribute("style"));t.hrefNormalized=r.getAttribute("href")==="/a";t.opacity=/^0.5/.test(r.style.opacity);t.cssFloat=!!r.style.cssFloat;t.checkOn=!!s.value;t.optSelected=f.selected;t.enctype=!!o.createElement("form").enctype;t.html5Clone=o.createElement("nav").cloneNode(true).outerHTML!=="<:nav>";t.inlineBlockNeedsLayout=false;t.shrinkWrapBlocks=false;t.pixelPosition=false;t.deleteExpando=true;t.noCloneEvent=true;t.reliableMarginRight=true;t.boxSizingReliable=true;s.checked=true;t.noCloneChecked=s.cloneNode(true).checked;u.disabled=true;t.optDisabled=!f.disabled;try{delete p.test}catch(d){t.deleteExpando=false}s=o.createElement("input");s.setAttribute("value","");t.input=s.getAttribute("value")==="";s.value="t";s.setAttribute("type","radio");t.radioValue=s.value==="t";s.setAttribute("checked","t");s.setAttribute("name","t");a=o.createDocumentFragment();a.appendChild(s);t.appendChecked=s.checked;t.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;if(p.attachEvent){p.attachEvent("onclick",function(){t.noCloneEvent=false});p.cloneNode(true).click()}for(h in{submit:true,change:true,focusin:true}){p.setAttribute(l="on"+h,"t");t[h+"Bubbles"]=l in e||p.attributes[l].expando===false}p.style.backgroundClip="content-box";p.cloneNode(true).style.backgroundClip="";t.clearCloneStyle=p.style.backgroundClip==="content-box";for(h in w(t)){break}t.ownLast=h!=="0";w(function(){var n,r,s,u="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",a=o.getElementsByTagName("body")[0];if(!a){return}n=o.createElement("div");n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";a.appendChild(n).appendChild(p);p.innerHTML="
            t
            ";s=p.getElementsByTagName("td");s[0].style.cssText="padding:0;margin:0;border:0;display:none";c=s[0].offsetHeight===0;s[0].style.display="";s[1].style.display="none";t.reliableHiddenOffsets=c&&s[0].offsetHeight===0;p.innerHTML="";p.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";w.swap(a,a.style.zoom!=null?{zoom:1}:{},function(){t.boxSizing=p.offsetWidth===4});if(e.getComputedStyle){t.pixelPosition=(e.getComputedStyle(p,null)||{}).top!=="1%";t.boxSizingReliable=(e.getComputedStyle(p,null)||{width:"4px"}).width==="4px";r=p.appendChild(o.createElement("div"));r.style.cssText=p.style.cssText=u;r.style.marginRight=r.style.width="0";p.style.width="1px";t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)}if(typeof p.style.zoom!==i){p.innerHTML="";p.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1";t.inlineBlockNeedsLayout=p.offsetWidth===3;p.style.display="block";p.innerHTML="
            ";p.firstChild.style.width="5px";t.shrinkWrapBlocks=p.offsetWidth!==3;if(t.inlineBlockNeedsLayout){a.style.zoom=1}}a.removeChild(n);n=p=s=r=null});n=u=a=f=r=s=null;return t}({});var F=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,I=/([A-Z])/g;w.extend({cache:{},noData:{applet:true,embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){e=e.nodeType?w.cache[e[w.expando]]:e[w.expando];return!!e&&!z(e)},data:function(e,t,n){return q(e,t,n)},removeData:function(e,t){return R(e,t)},_data:function(e,t,n){return q(e,t,n,true)},_removeData:function(e,t){return R(e,t,true)},acceptData:function(e){if(e.nodeType&&e.nodeType!==1&&e.nodeType!==9){return false}var t=e.nodeName&&w.noData[e.nodeName.toLowerCase()];return!t||t!==true&&e.getAttribute("classid")===t}});w.fn.extend({data:function(e,n){var r,i,s=null,o=0,u=this[0];if(e===t){if(this.length){s=w.data(u);if(u.nodeType===1&&!w._data(u,"parsedAttrs")){r=u.attributes;for(;o1?this.each(function(){w.data(this,e,n)}):u?U(u,e,w.data(u,e)):null},removeData:function(e){return this.each(function(){w.removeData(this,e)})}});w.extend({queue:function(e,t,n){var r;if(e){t=(t||"fx")+"queue";r=w._data(e,t);if(n){if(!r||w.isArray(n)){r=w._data(e,t,w.makeArray(n))}else{r.push(n)}}return r||[]}},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),s=w._queueHooks(e,t),o=function(){w.dequeue(e,t)};if(i==="inprogress"){i=n.shift();r--}if(i){if(t==="fx"){n.unshift("inprogress")}delete s.stop;i.call(e,o,s)}if(!r&&s){s.empty.fire()}},_queueHooks:function(e,t){var n=t+"queueHooks";return w._data(e,n)||w._data(e,n,{empty:w.Callbacks("once memory").add(function(){w._removeData(e,t+"queue");w._removeData(e,n)})})}});w.fn.extend({queue:function(e,n){var r=2;if(typeof e!=="string"){n=e;e="fx";r--}if(arguments.length1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})},prop:function(e,t){return w.access(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){e=w.propFix[e]||e;return this.each(function(){try{this[e]=t;delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o=0,u=this.length,a=typeof e==="string"&&e;if(w.isFunction(e)){return this.each(function(t){w(this).addClass(e.call(this,t,this.className))})}if(a){t=(e||"").match(S)||[];for(;o=0){r=r.replace(" "+i+" "," ")}}n.className=e?w.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e;if(typeof t==="boolean"&&n==="string"){return t?this.addClass(e):this.removeClass(e)}if(w.isFunction(e)){return this.each(function(n){w(this).toggleClass(e.call(this,n,this.className,t),t)})}return this.each(function(){if(n==="string"){var t,r=0,s=w(this),o=e.match(S)||[];while(t=o[r++]){if(s.hasClass(t)){s.removeClass(t)}else{s.addClass(t)}}}else if(n===i||n==="boolean"){if(this.className){w._data(this,"__className__",this.className)}this.className=this.className||e===false?"":w._data(this,"__className__")||""}})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0){return true}}return false},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s){r=w.valHooks[s.type]||w.valHooks[s.nodeName.toLowerCase()];if(r&&"get"in r&&(n=r.get(s,"value"))!==t){return n}n=s.value;return typeof n==="string"?n.replace($,""):n==null?"":n}return}i=w.isFunction(e);return this.each(function(n){var s;if(this.nodeType!==1){return}if(i){s=e.call(this,n,w(this).val())}else{s=e}if(s==null){s=""}else if(typeof s==="number"){s+=""}else if(w.isArray(s)){s=w.map(s,function(e){return e==null?"":e+""})}r=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()];if(!r||!("set"in r)||r.set(this,s,"value")===t){this.value=s}})}});w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return t!=null?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0){n=true}}if(!n){e.selectedIndex=-1}return s}}},attr:function(e,n,r){var s,o,u=e.nodeType;if(!e||u===3||u===8||u===2){return}if(typeof e.getAttribute===i){return w.prop(e,n,r)}if(u!==1||!w.isXMLDoc(e)){n=n.toLowerCase();s=w.attrHooks[n]||(w.expr.match.bool.test(n)?X:W)}if(r!==t){if(r===null){w.removeAttr(e,n)}else if(s&&"set"in s&&(o=s.set(e,r,n))!==t){return o}else{e.setAttribute(n,r+"");return r}}else if(s&&"get"in s&&(o=s.get(e,n))!==null){return o}else{o=w.find.attr(e,n);return o==null?t:o}},removeAttr:function(e,t){var n,r,i=0,s=t&&t.match(S);if(s&&e.nodeType===1){while(n=s[i++]){r=w.propFix[n]||n;if(w.expr.match.bool.test(n)){if(Y&&G||!Q.test(n)){e[r]=false}else{e[w.camelCase("default-"+n)]=e[r]=false}}else{w.attr(e,n,"")}e.removeAttribute(G?n:r)}}},attrHooks:{type:{set:function(e,t){if(!w.support.radioValue&&t==="radio"&&w.nodeName(e,"input")){var n=e.value;e.setAttribute("type",t);if(n){e.value=n}return t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,s,o,u=e.nodeType;if(!e||u===3||u===8||u===2){return}o=u!==1||!w.isXMLDoc(e);if(o){n=w.propFix[n]||n;s=w.propHooks[n]}if(r!==t){return s&&"set"in s&&(i=s.set(e,r,n))!==t?i:e[n]=r}else{return s&&"get"in s&&(i=s.get(e,n))!==null?i:e[n]}},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):J.test(e.nodeName)||K.test(e.nodeName)&&e.href?0:-1}}}});X={set:function(e,t,n){if(t===false){w.removeAttr(e,n)}else if(Y&&G||!Q.test(n)){e.setAttribute(!G&&w.propFix[n]||n,n)}else{e[w.camelCase("default-"+n)]=e[n]=true}return n}};w.each(w.expr.match.bool.source.match(/\w+/g),function(e,n){var r=w.expr.attrHandle[n]||w.find.attr;w.expr.attrHandle[n]=Y&&G||!Q.test(n)?function(e,n,i){var s=w.expr.attrHandle[n],o=i?t:(w.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;w.expr.attrHandle[n]=s;return o}:function(e,n,r){return r?t:e[w.camelCase("default-"+n)]?n.toLowerCase():null}});if(!Y||!G){w.attrHooks.value={set:function(e,t,n){if(w.nodeName(e,"input")){e.defaultValue=t}else{return W&&W.set(e,t,n)}}}}if(!G){W={set:function(e,n,r){var i=e.getAttributeNode(r);if(!i){e.setAttributeNode(i=e.ownerDocument.createAttribute(r))}i.value=n+="";return r==="value"||n===e.getAttribute(r)?n:t}};w.expr.attrHandle.id=w.expr.attrHandle.name=w.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.value!==""?i.value:null};w.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:W.set};w.attrHooks.contenteditable={set:function(e,t,n){W.set(e,t===""?false:t,n)}};w.each(["width","height"],function(e,t){w.attrHooks[t]={set:function(e,n){if(n===""){e.setAttribute(t,"auto");return n}}}})}if(!w.support.hrefNormalized){w.each(["href","src"],function(e,t){w.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})}if(!w.support.style){w.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}}if(!w.support.optSelected){w.propHooks.selected={get:function(e){var t=e.parentNode;if(t){t.selectedIndex;if(t.parentNode){t.parentNode.selectedIndex}}return null}}}w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});if(!w.support.enctype){w.propFix.enctype="encoding"}w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(w.isArray(t)){return e.checked=w.inArray(w(e).val(),t)>=0}}};if(!w.support.checkOn){w.valHooks[this].get=function(e){return e.getAttribute("value")===null?"on":e.value}}});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;w.event={global:{},add:function(e,n,r,s,o){var u,a,f,l,c,h,p,d,v,m,g,y=w._data(e);if(!y){return}if(r.handler){l=r;r=l.handler;o=l.selector}if(!r.guid){r.guid=w.guid++}if(!(a=y.events)){a=y.events={}}if(!(h=y.handle)){h=y.handle=function(e){return typeof w!==i&&(!e||w.event.triggered!==e.type)?w.event.dispatch.apply(h.elem,arguments):t};h.elem=e}n=(n||"").match(S)||[""];f=n.length;while(f--){u=rt.exec(n[f])||[];v=g=u[1];m=(u[2]||"").split(".").sort();if(!v){continue}c=w.event.special[v]||{};v=(o?c.delegateType:c.bindType)||v;c=w.event.special[v]||{};p=w.extend({type:v,origType:g,data:s,handler:r,guid:r.guid,selector:o,needsContext:o&&w.expr.match.needsContext.test(o),namespace:m.join(".")},l);if(!(d=a[v])){d=a[v]=[];d.delegateCount=0;if(!c.setup||c.setup.call(e,s,m,h)===false){if(e.addEventListener){e.addEventListener(v,h,false)}else if(e.attachEvent){e.attachEvent("on"+v,h)}}}if(c.add){c.add.call(e,p);if(!p.handler.guid){p.handler.guid=r.guid}}if(o){d.splice(d.delegateCount++,0,p)}else{d.push(p)}w.event.global[v]=true}e=null},remove:function(e,t,n,r,i){var s,o,u,a,f,l,c,h,p,d,v,m=w.hasData(e)&&w._data(e);if(!m||!(l=m.events)){return}t=(t||"").match(S)||[""];f=t.length;while(f--){u=rt.exec(t[f])||[];p=v=u[1];d=(u[2]||"").split(".").sort();if(!p){for(p in l){w.event.remove(e,p+t[f],n,r,true)}continue}c=w.event.special[p]||{};p=(r?c.delegateType:c.bindType)||p;h=l[p]||[];u=u[2]&&new RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)");a=s=h.length;while(s--){o=h[s];if((i||v===o.origType)&&(!n||n.guid===o.guid)&&(!u||u.test(o.namespace))&&(!r||r===o.selector||r==="**"&&o.selector)){h.splice(s,1);if(o.selector){h.delegateCount--}if(c.remove){c.remove.call(e,o)}}}if(a&&!h.length){if(!c.teardown||c.teardown.call(e,d,m.handle)===false){w.removeEvent(e,p,m.handle)}delete l[p]}}if(w.isEmptyObject(l)){delete m.handle;w._removeData(e,"events")}},trigger:function(n,r,i,s){var u,a,f,l,c,h,p,d=[i||o],v=y.call(n,"type")?n.type:n,m=y.call(n,"namespace")?n.namespace.split("."):[];f=h=i=i||o;if(i.nodeType===3||i.nodeType===8){return}if(nt.test(v+w.event.triggered)){return}if(v.indexOf(".")>=0){m=v.split(".");v=m.shift();m.sort()}a=v.indexOf(":")<0&&"on"+v;n=n[w.expando]?n:new w.Event(v,typeof n==="object"&&n);n.isTrigger=s?2:3;n.namespace=m.join(".");n.namespace_re=n.namespace?new RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null;n.result=t;if(!n.target){n.target=i}r=r==null?[n]:w.makeArray(r,[n]);c=w.event.special[v]||{};if(!s&&c.trigger&&c.trigger.apply(i,r)===false){return}if(!s&&!c.noBubble&&!w.isWindow(i)){l=c.delegateType||v;if(!nt.test(l+v)){f=f.parentNode}for(;f;f=f.parentNode){d.push(f);h=f}if(h===(i.ownerDocument||o)){d.push(h.defaultView||h.parentWindow||e)}}p=0;while((f=d[p++])&&!n.isPropagationStopped()){n.type=p>1?l:c.bindType||v;u=(w._data(f,"events")||{})[n.type]&&w._data(f,"handle");if(u){u.apply(f,r)}u=a&&f[a];if(u&&w.acceptData(f)&&u.apply&&u.apply(f,r)===false){n.preventDefault()}}n.type=v;if(!s&&!n.isDefaultPrevented()){if((!c._default||c._default.apply(d.pop(),r)===false)&&w.acceptData(i)){if(a&&i[v]&&!w.isWindow(i)){h=i[a];if(h){i[a]=null}w.event.triggered=v;try{i[v]()}catch(g){}w.event.triggered=t;if(h){i[a]=h}}}}return n.result},dispatch:function(e){e=w.event.fix(e);var n,r,i,s,o,u=[],a=v.call(arguments),f=(w._data(this,"events")||{})[e.type]||[],l=w.event.special[e.type]||{};a[0]=e;e.delegateTarget=this;if(l.preDispatch&&l.preDispatch.call(this,e)===false){return}u=w.event.handlers.call(this,e,f);n=0;while((s=u[n++])&&!e.isPropagationStopped()){e.currentTarget=s.elem;o=0;while((i=s.handlers[o++])&&!e.isImmediatePropagationStopped()){if(!e.namespace_re||e.namespace_re.test(i.namespace)){e.handleObj=i;e.data=i.data;r=((w.event.special[i.origType]||{}).handle||i.handler).apply(s.elem,a);if(r!==t){if((e.result=r)===false){e.preventDefault();e.stopPropagation()}}}}}if(l.postDispatch){l.postDispatch.call(this,e)}return e.result},handlers:function(e,n){var r,i,s,o,u=[],a=n.delegateCount,f=e.target;if(a&&f.nodeType&&(!e.button||e.type!=="click")){for(;f!=this;f=f.parentNode||this){if(f.nodeType===1&&(f.disabled!==true||e.type!=="click")){s=[];for(o=0;o=0:w.find(r,this,null,[f]).length}if(s[r]){s.push(i)}}if(s.length){u.push({elem:f,handlers:s})}}}}if(a1?w.unique(n):n);n.selector=this.selector?this.selector+" "+e:e;return n},has:function(e){var t,n=w(e,this),r=n.length;return this.filter(function(){for(t=0;t-1:n.nodeType===1&&w.find.matchesSelector(n,e))){n=s.push(n);break}}}return this.pushStack(s.length>1?w.unique(s):s)},index:function(e){if(!e){return this[0]&&this[0].parentNode?this.first().prevAll().length:-1}if(typeof e==="string"){return w.inArray(this[0],w(e))}return w.inArray(e.jquery?e[0]:e,this)},add:function(e,t){var n=typeof e==="string"?w(e,t):w.makeArray(e&&e.nodeType?[e]:e),r=w.merge(this.get(),n);return this.pushStack(w.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}});w.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return w.dir(e,"parentNode")},parentsUntil:function(e,t,n){return w.dir(e,"parentNode",n)},next:function(e){return ct(e,"nextSibling")},prev:function(e){return ct(e,"previousSibling")},nextAll:function(e){return w.dir(e,"nextSibling")},prevAll:function(e){return w.dir(e,"previousSibling")},nextUntil:function(e,t,n){return w.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return w.dir(e,"previousSibling",n)},siblings:function(e){return w.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return w.sibling(e.firstChild)},contents:function(e){return w.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:w.merge([],e.childNodes)}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);if(e.slice(-5)!=="Until"){r=n}if(r&&typeof r==="string"){i=w.filter(r,i)}if(this.length>1){if(!lt[e]){i=w.unique(i)}if(at.test(e)){i=i.reverse()}}return this.pushStack(i)}});w.extend({filter:function(e,t,n){var r=t[0];if(n){e=":not("+e+")"}return t.length===1&&r.nodeType===1?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return e.nodeType===1}))},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!w(s).is(r))){if(s.nodeType===1){i.push(s)}s=s[n]}return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling){if(e.nodeType===1&&e!==t){n.push(e)}}return n}});var dt="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|"+"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",vt=/ jQuery\d+="(?:null|\d+)"/g,mt=new RegExp("<(?:"+dt+")[\\s/>]","i"),gt=/^\s+/,yt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,wt=/
            ","
            "],tr:[2,"","
            "],col:[2,"","
            "],td:[3,"","
            "],_default:w.support.htmlSerialize?[0,"",""]:[1,"X
            ","
            "]},At=pt(o),Ot=At.appendChild(o.createElement("div"));Lt.optgroup=Lt.option;Lt.tbody=Lt.tfoot=Lt.colgroup=Lt.caption=Lt.thead;Lt.th=Lt.td;w.fn.extend({text:function(e){return w.access(this,function(e){return e===t?w.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(this.nodeType===1||this.nodeType===11||this.nodeType===9){var t=Mt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(this.nodeType===1||this.nodeType===11||this.nodeType===9){var t=Mt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){if(this.parentNode){this.parentNode.insertBefore(e,this)}})},after:function(){return this.domManip(arguments,function(e){if(this.parentNode){this.parentNode.insertBefore(e,this.nextSibling)}})},remove:function(e,t){var n,r=e?w.filter(e,this):this,i=0;for(;(n=r[i])!=null;i++){if(!t&&n.nodeType===1){w.cleanData(jt(n))}if(n.parentNode){if(t&&w.contains(n.ownerDocument,n)){Pt(jt(n,"script"))}n.parentNode.removeChild(n)}}return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){if(e.nodeType===1){w.cleanData(jt(e,false))}while(e.firstChild){e.removeChild(e.firstChild)}if(e.options&&w.nodeName(e,"select")){e.options.length=0}}return this},clone:function(e,t){e=e==null?false:e;t=t==null?e:t;return this.map(function(){return w.clone(this,e,t)})},html:function(e){return w.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t){return n.nodeType===1?n.innerHTML.replace(vt,""):t}if(typeof e==="string"&&!St.test(e)&&(w.support.htmlSerialize||!mt.test(e))&&(w.support.leadingWhitespace||!gt.test(e))&&!Lt[(bt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(yt,"<$1>");try{for(;r")){s=e.cloneNode(true)}else{Ot.innerHTML=e.outerHTML;Ot.removeChild(s=Ot.firstChild)}if((!w.support.noCloneEvent||!w.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!w.isXMLDoc(e)){r=jt(s);u=jt(e);for(o=0;(i=u[o])!=null;++o){if(r[o]){Bt(i,r[o])}}}if(t){if(n){u=u||jt(e);r=r||jt(s);for(o=0;(i=u[o])!=null;o++){Ht(i,r[o])}}else{Ht(e,s)}}r=jt(s,"script");if(r.length>0){Pt(r,!a&&jt(e,"script"))}r=u=i=null;return s},buildFragment:function(e,t,n,r){var i,s,o,u,a,f,l,c=e.length,h=pt(t),p=[],d=0;for(;d")+l[2];i=l[0];while(i--){u=u.lastChild}if(!w.support.leadingWhitespace&>.test(s)){p.push(t.createTextNode(gt.exec(s)[0]))}if(!w.support.tbody){s=a==="table"&&!wt.test(s)?u.firstChild:l[1]===""&&!wt.test(s)?u:0;i=s&&s.childNodes.length;while(i--){if(w.nodeName(f=s.childNodes[i],"tbody")&&!f.childNodes.length){s.removeChild(f)}}}w.merge(p,u.childNodes);u.textContent="";while(u.firstChild){u.removeChild(u.firstChild)}u=h.lastChild}}}if(u){h.removeChild(u)}if(!w.support.appendChecked){w.grep(jt(p,"input"),Ft)}d=0;while(s=p[d++]){if(r&&w.inArray(s,r)!==-1){continue}o=w.contains(s.ownerDocument,s);u=jt(h.appendChild(s),"script");if(o){Pt(u)}if(n){i=0;while(s=u[i++]){if(Nt.test(s.type||"")){n.push(s)}}}}u=null;return h},cleanData:function(e,t){var n,r,s,o,u=0,a=w.expando,f=w.cache,l=w.support.deleteExpando,h=w.event.special;for(;(n=e[u])!=null;u++){if(t||w.acceptData(n)){s=n[a];o=s&&f[s];if(o){if(o.events){for(r in o.events){if(h[r]){w.event.remove(n,r)}else{w.removeEvent(n,r,o.handle)}}}if(f[s]){delete f[s];if(l){delete n[a]}else if(typeof n.removeAttribute!==i){n.removeAttribute(a)}else{n[a]=null}c.push(s)}}}}},_evalUrl:function(e){return w.ajax({url:e,type:"GET",dataType:"script",async:false,global:false,"throws":true})}});w.fn.extend({wrapAll:function(e){if(w.isFunction(e)){return this.each(function(t){w(this).wrapAll(e.call(this,t))})}if(this[0]){var t=w(e,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){t.insertBefore(this[0])}t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1){e=e.firstChild}return e}).append(this)}return this},wrapInner:function(e){if(w.isFunction(e)){return this.each(function(t){w(this).wrapInner(e.call(this,t))})}return this.each(function(){var t=w(this),n=t.contents();if(n.length){n.wrapAll(e)}else{t.append(e)}})},wrap:function(e){var t=w.isFunction(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){if(!w.nodeName(this,"body")){w(this).replaceWith(this.childNodes)}}).end()}});var It,qt,Rt,Ut=/alpha\([^)]*\)/i,zt=/opacity\s*=\s*([^)]*)/,Wt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Vt=/^margin/,$t=new RegExp("^("+E+")(.*)$","i"),Jt=new RegExp("^("+E+")(?!px)[a-z%]+$","i"),Kt=new RegExp("^([+-])=("+E+")","i"),Qt={BODY:"block"},Gt={position:"absolute",visibility:"hidden",display:"block"},Yt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];w.fn.extend({css:function(e,n){return w.access(this,function(e,n,r){var i,s,o={},u=0;if(w.isArray(n)){s=qt(e);i=n.length;for(;u1)},show:function(){return rn(this,true)},hide:function(){return rn(this)},toggle:function(e){if(typeof e==="boolean"){return e?this.show():this.hide()}return this.each(function(){if(nn(this)){w(this).show()}else{w(this).hide()}})}});w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Rt(e,"opacity");return n===""?"1":n}}}},cssNumber:{columnCount:true,fillOpacity:true,fontWeight:true,lineHeight:true,opacity:true,order:true,orphans:true,widows:true,zIndex:true,zoom:true},cssProps:{"float":w.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style){return}var s,o,u,a=w.camelCase(n),f=e.style;n=w.cssProps[a]||(w.cssProps[a]=tn(f,a));u=w.cssHooks[n]||w.cssHooks[a];if(r!==t){o=typeof r;if(o==="string"&&(s=Kt.exec(r))){r=(s[1]+1)*s[2]+parseFloat(w.css(e,n));o="number"}if(r==null||o==="number"&&isNaN(r)){return}if(o==="number"&&!w.cssNumber[a]){r+="px"}if(!w.support.clearCloneStyle&&r===""&&n.indexOf("background")===0){f[n]="inherit"}if(!u||!("set"in u)||(r=u.set(e,r,i))!==t){try{f[n]=r}catch(l){}}}else{if(u&&"get"in u&&(s=u.get(e,false,i))!==t){return s}return f[n]}},css:function(e,n,r,i){var s,o,u,a=w.camelCase(n);n=w.cssProps[a]||(w.cssProps[a]=tn(e.style,a));u=w.cssHooks[n]||w.cssHooks[a];if(u&&"get"in u){o=u.get(e,true,r)}if(o===t){o=Rt(e,n,i)}if(o==="normal"&&n in Yt){o=Yt[n]}if(r===""||r){s=parseFloat(o);return r===true||w.isNumeric(s)?s||0:o}return o}});if(e.getComputedStyle){qt=function(t){return e.getComputedStyle(t,null)};Rt=function(e,n,r){var i,s,o,u=r||qt(e),a=u?u.getPropertyValue(n)||u[n]:t,f=e.style;if(u){if(a===""&&!w.contains(e.ownerDocument,e)){a=w.style(e,n)}if(Jt.test(a)&&Vt.test(n)){i=f.width;s=f.minWidth;o=f.maxWidth;f.minWidth=f.maxWidth=f.width=a;a=u.width;f.width=i;f.minWidth=s;f.maxWidth=o}}return a}}else if(o.documentElement.currentStyle){qt=function(e){return e.currentStyle};Rt=function(e,n,r){var i,s,o,u=r||qt(e),a=u?u[n]:t,f=e.style;if(a==null&&f&&f[n]){a=f[n]}if(Jt.test(a)&&!Wt.test(n)){i=f.left;s=e.runtimeStyle;o=s&&s.left;if(o){s.left=e.currentStyle.left}f.left=n==="fontSize"?"1em":a;a=f.pixelLeft+"px";f.left=i;if(o){s.left=o}}return a===""?"auto":a}}w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n){return e.offsetWidth===0&&Xt.test(w.css(e,"display"))?w.swap(e,Gt,function(){return un(e,t,r)}):un(e,t,r)}},set:function(e,n,r){var i=r&&qt(e);return sn(e,n,r?on(e,t,r,w.support.boxSizing&&w.css(e,"boxSizing",false,i)==="border-box",i):0)}}});if(!w.support.opacity){w.cssHooks.opacity={get:function(e,t){return zt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=w.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if((t>=1||t==="")&&w.trim(s.replace(Ut,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(t===""||r&&!r.filter){return}}n.filter=Ut.test(s)?s.replace(Ut,i):s+" "+i}}}w(function(){if(!w.support.reliableMarginRight){w.cssHooks.marginRight={get:function(e,t){if(t){return w.swap(e,{display:"inline-block"},Rt,[e,"marginRight"])}}}}if(!w.support.pixelPosition&&w.fn.position){w.each(["top","left"],function(e,t){w.cssHooks[t]={get:function(e,n){if(n){n=Rt(e,t);return Jt.test(n)?w(e).position()[t]+"px":n}}}})}});if(w.expr&&w.expr.filters){w.expr.filters.hidden=function(e){return e.offsetWidth<=0&&e.offsetHeight<=0||!w.support.reliableHiddenOffsets&&(e.style&&e.style.display||w.css(e,"display"))==="none"};w.expr.filters.visible=function(e){return!w.expr.filters.hidden(e)}}w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){var r=0,i={},s=typeof n==="string"?n.split(" "):[n];for(;r<4;r++){i[e+Zt[r]+t]=s[r]||s[r-2]||s[0]}return i}};if(!Vt.test(e)){w.cssHooks[e+t].set=sn}});var ln=/%20/g,cn=/\[\]$/,hn=/\r?\n/g,pn=/^(?:submit|button|image|reset|file)$/i,dn=/^(?:input|select|textarea|keygen)/i;w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&dn.test(this.nodeName)&&!pn.test(e)&&(this.checked||!xt.test(e))}).map(function(e,t){var n=w(this).val();return n==null?null:w.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(hn,"\r\n")}}):{name:t.name,value:n.replace(hn,"\r\n")}}).get()}});w.param=function(e,n){var r,i=[],s=function(e,t){t=w.isFunction(t)?t():t==null?"":t;i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t){n=w.ajaxSettings&&w.ajaxSettings.traditional}if(w.isArray(e)||e.jquery&&!w.isPlainObject(e)){w.each(e,function(){s(this.name,this.value)})}else{for(r in e){vn(r,e[r],n,s)}}return i.join("&").replace(ln,"+")};w.each(("blur focus focusin focusout load resize scroll unload click dblclick "+"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave "+"change select submit keydown keypress keyup error contextmenu").split(" "),function(e,t){w.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}});w.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return arguments.length===1?this.off(e,"**"):this.off(t,e||"**",n)}});var mn,gn,yn=w.now(),bn=/\?/,wn=/#.*$/,En=/([?&])_=[^&]*/,Sn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,xn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Tn=/^(?:GET|HEAD)$/,Nn=/^\/\//,Cn=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,kn=w.fn.load,Ln={},An={},On="*/".concat("*");try{gn=s.href}catch(Mn){gn=o.createElement("a");gn.href="";gn=gn.href}mn=Cn.exec(gn.toLowerCase())||[];w.fn.load=function(e,n,r){if(typeof e!=="string"&&kn){return kn.apply(this,arguments)}var i,s,o,u=this,a=e.indexOf(" ");if(a>=0){i=e.slice(a,e.length);e=e.slice(0,a)}if(w.isFunction(n)){r=n;n=t}else if(n&&typeof n==="object"){o="POST"}if(u.length>0){w.ajax({url:e,type:o,dataType:"html",data:n}).done(function(e){s=arguments;u.html(i?w("
            ").append(w.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){u.each(r,s||[e.responseText,t,e])})}return this};w.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){w.fn[t]=function(e){return this.on(t,e)}});w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:gn,type:"GET",isLocal:xn.test(mn[1]),global:true,processData:true,async:true,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":On,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":true,"text json":w.parseJSON,"text xml":w.parseXML},flatOptions:{url:true,context:true}},ajaxSetup:function(e,t){return t?Pn(Pn(e,w.ajaxSettings),t):Pn(w.ajaxSettings,e)},ajaxPrefilter:_n(Ln),ajaxTransport:_n(An),ajax:function(e,n){function N(e,n,r,i){var l,g,y,E,S,T=n;if(b===2){return}b=2;if(u){clearTimeout(u)}f=t;o=i||"";x.readyState=e>0?4:0;l=e>=200&&e<300||e===304;if(r){E=Hn(c,x,r)}E=Bn(c,E,x,l);if(l){if(c.ifModified){S=x.getResponseHeader("Last-Modified");if(S){w.lastModified[s]=S}S=x.getResponseHeader("etag");if(S){w.etag[s]=S}}if(e===204||c.type==="HEAD"){T="nocontent"}else if(e===304){T="notmodified"}else{T=E.state;g=E.data;y=E.error;l=!y}}else{y=T;if(e||!T){T="error";if(e<0){e=0}}}x.status=e;x.statusText=(n||T)+"";if(l){d.resolveWith(h,[g,T,x])}else{d.rejectWith(h,[x,T,y])}x.statusCode(m);m=t;if(a){p.trigger(l?"ajaxSuccess":"ajaxError",[x,c,l?g:y])}v.fireWith(h,[x,T]);if(a){p.trigger("ajaxComplete",[x,c]);if(!--w.active){w.event.trigger("ajaxStop")}}}if(typeof e==="object"){n=e;e=t}n=n||{};var r,i,s,o,u,a,f,l,c=w.ajaxSetup({},n),h=c.context||c,p=c.context&&(h.nodeType||h.jquery)?w(h):w.event,d=w.Deferred(),v=w.Callbacks("once memory"),m=c.statusCode||{},g={},y={},b=0,E="canceled",x={readyState:0,getResponseHeader:function(e){var t;if(b===2){if(!l){l={};while(t=Sn.exec(o)){l[t[1].toLowerCase()]=t[2]}}t=l[e.toLowerCase()]}return t==null?null:t},getAllResponseHeaders:function(){return b===2?o:null},setRequestHeader:function(e,t){var n=e.toLowerCase();if(!b){e=y[n]=y[n]||e;g[e]=t}return this},overrideMimeType:function(e){if(!b){c.mimeType=e}return this},statusCode:function(e){var t;if(e){if(b<2){for(t in e){m[t]=[m[t],e[t]]}}else{x.always(e[x.status])}}return this},abort:function(e){var t=e||E;if(f){f.abort(t)}N(0,t);return this}};d.promise(x).complete=v.add;x.success=x.done;x.error=x.fail;c.url=((e||c.url||gn)+"").replace(wn,"").replace(Nn,mn[1]+"//");c.type=n.method||n.type||c.method||c.type;c.dataTypes=w.trim(c.dataType||"*").toLowerCase().match(S)||[""];if(c.crossDomain==null){r=Cn.exec(c.url.toLowerCase());c.crossDomain=!!(r&&(r[1]!==mn[1]||r[2]!==mn[2]||(r[3]||(r[1]==="http:"?"80":"443"))!==(mn[3]||(mn[1]==="http:"?"80":"443"))))}if(c.data&&c.processData&&typeof c.data!=="string"){c.data=w.param(c.data,c.traditional)}Dn(Ln,c,n,x);if(b===2){return x}a=c.global;if(a&&w.active++===0){w.event.trigger("ajaxStart")}c.type=c.type.toUpperCase();c.hasContent=!Tn.test(c.type);s=c.url;if(!c.hasContent){if(c.data){s=c.url+=(bn.test(s)?"&":"?")+c.data;delete c.data}if(c.cache===false){c.url=En.test(s)?s.replace(En,"$1_="+yn++):s+(bn.test(s)?"&":"?")+"_="+yn++}}if(c.ifModified){if(w.lastModified[s]){x.setRequestHeader("If-Modified-Since",w.lastModified[s])}if(w.etag[s]){x.setRequestHeader("If-None-Match",w.etag[s])}}if(c.data&&c.hasContent&&c.contentType!==false||n.contentType){x.setRequestHeader("Content-Type",c.contentType)}x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+On+"; q=0.01":""):c.accepts["*"]);for(i in c.headers){x.setRequestHeader(i,c.headers[i])}if(c.beforeSend&&(c.beforeSend.call(h,x,c)===false||b===2)){return x.abort()}E="abort";for(i in{success:1,error:1,complete:1}){x[i](c[i])}f=Dn(An,c,n,x);if(!f){N(-1,"No Transport")}else{x.readyState=1;if(a){p.trigger("ajaxSend",[x,c])}if(c.async&&c.timeout>0){u=setTimeout(function(){x.abort("timeout")},c.timeout)}try{b=1;f.send(g,N)}catch(T){if(b<2){N(-1,T)}else{throw T}}}return x},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,n){return w.get(e,t,n,"script")}});w.each(["get","post"],function(e,n){w[n]=function(e,r,i,s){if(w.isFunction(r)){s=s||i;i=r;r=t}return w.ajax({url:e,type:n,dataType:s,data:r,success:i})}});w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){w.globalEval(e);return e}}});w.ajaxPrefilter("script",function(e){if(e.cache===t){e.cache=false}if(e.crossDomain){e.type="GET";e.global=false}});w.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=o.head||w("head")[0]||o.documentElement;return{send:function(t,i){n=o.createElement("script");n.async=true;if(e.scriptCharset){n.charset=e.scriptCharset}n.src=e.url;n.onload=n.onreadystatechange=function(e,t){if(t||!n.readyState||/loaded|complete/.test(n.readyState)){n.onload=n.onreadystatechange=null;if(n.parentNode){n.parentNode.removeChild(n)}n=null;if(!t){i(200,"success")}}};r.insertBefore(n,r.firstChild)},abort:function(){if(n){n.onload(t,true)}}}}});var jn=[],Fn=/(=)\?(?=&|$)|\?\?/;w.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=jn.pop()||w.expando+"_"+yn++;this[e]=true;return e}});w.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.jsonp!==false&&(Fn.test(n.url)?"url":typeof n.data==="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Fn.test(n.data)&&"data");if(a||n.dataTypes[0]==="jsonp"){s=n.jsonpCallback=w.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback;if(a){n[a]=n[a].replace(Fn,"$1"+s)}else if(n.jsonp!==false){n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+s}n.converters["script json"]=function(){if(!u){w.error(s+" was not called")}return u[0]};n.dataTypes[0]="json";o=e[s];e[s]=function(){u=arguments};i.always(function(){e[s]=o;if(n[s]){n.jsonpCallback=r.jsonpCallback;jn.push(s)}if(u&&w.isFunction(o)){o(u[0])}u=o=t});return"script"}});var In,qn,Rn=0,Un=e.ActiveXObject&&function(){var e;for(e in In){In[e](t,true)}};w.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&zn()||Wn()}:zn;qn=w.ajaxSettings.xhr();w.support.cors=!!qn&&"withCredentials"in qn;qn=w.support.ajax=!!qn;if(qn){w.ajaxTransport(function(n){if(!n.crossDomain||w.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();if(n.username){a.open(n.type,n.url,n.async,n.username,n.password)}else{a.open(n.type,n.url,n.async)}if(n.xhrFields){for(u in n.xhrFields){a[u]=n.xhrFields[u]}}if(n.mimeType&&a.overrideMimeType){a.overrideMimeType(n.mimeType)}if(!n.crossDomain&&!i["X-Requested-With"]){i["X-Requested-With"]="XMLHttpRequest"}try{for(u in i){a.setRequestHeader(u,i[u])}}catch(f){}a.send(n.hasContent&&n.data||null);r=function(e,i){var u,f,l,c;try{if(r&&(i||a.readyState===4)){r=t;if(o){a.onreadystatechange=w.noop;if(Un){delete In[o]}}if(i){if(a.readyState!==4){a.abort()}}else{c={};u=a.status;f=a.getAllResponseHeaders();if(typeof a.responseText==="string"){c.text=a.responseText}try{l=a.statusText}catch(h){l=""}if(!u&&n.isLocal&&!n.crossDomain){u=c.text?200:404}else if(u===1223){u=204}}}}catch(p){if(!i){s(-1,p)}}if(c){s(u,l,c,f)}};if(!n.async){r()}else if(a.readyState===4){setTimeout(r)}else{o=++Rn;if(Un){if(!In){In={};w(e).unload(Un)}In[o]=r}a.onreadystatechange=r}},abort:function(){if(r){r(t,true)}}}}})}var Xn,Vn,$n=/^(?:toggle|show|hide)$/,Jn=new RegExp("^(?:([+-])=|)("+E+")([a-z%]*)$","i"),Kn=/queueHooks$/,Qn=[nr],Gn={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Jn.exec(t),s=i&&i[3]||(w.cssNumber[e]?"":"px"),o=(w.cssNumber[e]||s!=="px"&&+r)&&Jn.exec(w.css(n.elem,e)),u=1,a=20;if(o&&o[3]!==s){s=s||o[3];i=i||[];o=+r||1;do{u=u||".5";o=o/u;w.style(n.elem,e,o+s)}while(u!==(u=n.cur()/r)&&u!==1&&--a)}if(i){o=n.start=+o||+r||0;n.unit=s;n.end=i[1]?o+(i[1]+1)*i[2]:+i[2]}return n}]};w.Animation=w.extend(er,{tweener:function(e,t){if(w.isFunction(e)){t=e;e=["*"]}else{e=e.split(" ")}var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;if(a){l=i.position();c=l.top;h=l.left}else{c=parseFloat(o)||0;h=parseFloat(u)||0}if(w.isFunction(t)){t=t.call(e,n,s)}if(t.top!=null){f.top=t.top-s.top+c}if(t.left!=null){f.left=t.left-s.left+h}if("using"in t){t.using.call(e,f)}else{i.css(f)}}};w.fn.extend({position:function(){if(!this[0]){return}var e,t,n={top:0,left:0},r=this[0];if(w.css(r,"position")==="fixed"){t=r.getBoundingClientRect()}else{e=this.offsetParent();t=this.offset();if(!w.nodeName(e[0],"html")){n=e.offset()}n.top+=w.css(e[0],"borderTopWidth",true);n.left+=w.css(e[0],"borderLeftWidth",true)}return{top:t.top-n.top-w.css(r,"marginTop",true),left:t.left-n.left-w.css(r,"marginLeft",true)}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||u;while(e&&!w.nodeName(e,"html")&&w.css(e,"position")==="static"){e=e.offsetParent}return e||u})}});w.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);w.fn[e]=function(i){return w.access(this,function(e,i,s){var o=sr(e);if(s===t){return o?n in o?o[n]:o.document.documentElement[i]:e[i]}if(o){o.scrollTo(!r?s:w(o).scrollLeft(),r?s:w(o).scrollTop())}else{e[i]=s}},e,i,arguments.length,null)}});w.each({Height:"height",Width:"width"},function(e,n){w.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){w.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!=="boolean"),u=r||(i===true||s===true?"margin":"border");return w.access(this,function(n,r,i){var s;if(w.isWindow(n)){return n.document.documentElement["client"+e]}if(n.nodeType===9){s=n.documentElement;return Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])}return i===t?w.css(n,r,u):w.style(n,r,i,u)},n,o?i:t,o,null)}})});w.fn.size=function(){return this.length};w.fn.andSelf=w.fn.addBack;if(typeof module==="object"&&module&&typeof module.exports==="object"){module.exports=w}else{e.jQuery=e.$=w;if(typeof define==="function"&&define.amd){define("jquery",[],function(){return w})}}})(window);jQuery.fn.extend({everyTime:function(e,t,n,r){return this.each(function(){jQuery.timer.add(this,e,t,n,r)})},oneTime:function(e,t,n){return this.each(function(){jQuery.timer.add(this,e,t,n,1)})},stopTime:function(e,t){return this.each(function(){jQuery.timer.remove(this,e,t)})}});jQuery.extend({timer:{global:[],guid:1,dataKey:"jQuery.timer",regex:/^([0-9]+(?:\.[0-9]*)?)\s*(.*s)?$/,powers:{ms:1,cs:10,ds:100,s:1e3,das:1e4,hs:1e5,ks:1e6},timeParse:function(e){if(e==undefined||e==null)return null;var t=this.regex.exec(jQuery.trim(e.toString()));return t[2]?parseFloat(t[1])*(this.powers[t[2]]||1):e},add:function(e,t,n,r,i){var s=0;if(jQuery.isFunction(n)){i||(i=r);r=n;n=t}t=jQuery.timer.timeParse(t);if(!(typeof t!="number"||isNaN(t)||t<0)){if(typeof i!="number"||isNaN(i)||i<0)i=0;i=i||0;var o=jQuery.data(e,this.dataKey)||jQuery.data(e,this.dataKey,{});o[n]||(o[n]={});r.timerID=r.timerID||this.guid++;var u=function(){if(++s>i&&i!==0||r.call(e,s)===false)jQuery.timer.remove(e,n,r)};u.timerID=r.timerID;o[n][r.timerID]||(o[n][r.timerID]=window.setInterval(u,t));this.global.push(e)}},remove:function(e,t,n){var r=jQuery.data(e,this.dataKey),i;if(r){if(t){if(r[t]){if(n){if(n.timerID){window.clearInterval(r[t][n.timerID]);delete r[t][n.timerID]}}else for(n in r[t]){window.clearInterval(r[t][n]);delete r[t][n]}for(i in r[t])break;if(!i){i=null;delete r[t]}}}else for(t in r)this.remove(e,t,n);for(i in r)break;i||jQuery.removeData(e,this.dataKey)}}}});jQuery(window).bind("unload",function(){jQuery.each(jQuery.timer.global,function(e,t){jQuery.timer.remove(t)})});(function(){"use strict";function encodeHTMLSource(){var e={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},t=/&(?!#?\w+;)|<|>|"|'|\//g;return function(){return this?this.replace(t,function(t){return e[t]||t}):this}}function resolveDefs(e,t,n){return(typeof t==="string"?t:t.toString()).replace(e.define||skip,function(t,r,i,s){if(r.indexOf("def.")===0){r=r.substring(4)}if(!(r in n)){if(i===":"){if(e.defineParams)s.replace(e.defineParams,function(e,t,i){n[r]={arg:t,text:i}});if(!(r in n))n[r]=s}else{(new Function("def","def['"+r+"']="+s))(n)}}return""}).replace(e.use||skip,function(t,r){if(e.useParams)r=r.replace(e.useParams,function(e,t,r,i){if(n[r]&&n[r].arg&&i){var s=(r+":"+i).replace(/'|\\/g,"_");n.__exp=n.__exp||{};n.__exp[s]=n[r].text.replace(new RegExp("(^|[^\\w$])"+n[r].arg+"([^\\w$])","g"),"$1"+i+"$2");return t+"def.__exp['"+s+"']"}});var i=(new Function("def","return "+r))(n);return i?resolveDefs(e,i,n):i})}function unescape(e){return e.replace(/\\('|\\)/g,"$1").replace(/[\r\t\n]/g," ")}var doT={version:"1.0.1-nanoui",templateSettings:{evaluate:/\{\{([\s\S]+?)\}\}/g,interpolate:/\{\{:([\s\S]+?)\}\}/g,encode:/\{\{>([\s\S]+?)\}\}/g,use:/\{\{#([\s\S]+?)\}\}/g,define:/\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,conditional:/\{\{\/?if\s*([\s\S]*?)\s*\}\}/g,conditionalElse:/\{\{else\s*([\s\S]*?)\s*\}\}/g,iterate:/\{\{\/?for\s*(?:\}\}|([\s\S]+?)\s*(?:\:\s*([\w$]+))?\s*(?:\:\s*([\w$]+))?\s*\}\})/g,props:/\{\{\/?props\s*(?:\}\}|([\s\S]+?)\s*(?:\:\s*([\w$]+))?\s*(?:\:\s*([\w$]+))?\s*\}\})/g,empty:/\{\{empty\}\}/g,varname:"data, config, helper",strip:true,append:true,selfcontained:false},template:undefined,compile:undefined},global;if(typeof module!=="undefined"&&module.exports){module.exports=doT}else if(typeof define==="function"&&define.amd){define(function(){return doT})}else{global=function(){return this||(0,eval)("this")}();global.doT=doT}String.prototype.encodeHTML=encodeHTMLSource();var startend={append:{start:"'+(",end:")+'",endencode:"||'').toString().encodeHTML()+'"},split:{start:"';out+=(",end:");out+='",endencode:"||'').toString().encodeHTML();out+='"}},skip=/$^/;doT.template=function(e,t,n){t=t||doT.templateSettings;var r=t.append?startend.append:startend.split,i,s=0,o=t.use||t.define?resolveDefs(t,e,n||{}):e;o=("var out='"+(t.strip?o.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ").replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""):o).replace(/'|\\/g,"\\$&").replace(t.interpolate||skip,function(e,t){return r.start+unescape(t)+r.end}).replace(t.encode||skip,function(e,t){i=true;return r.start+unescape(t)+r.endencode}).replace(t.conditional||skip,function(e,t){return t?"';if("+unescape(t)+"){out+='":"';}out+='"}).replace(t.conditionalElse||skip,function(e,t){return t?"';}else if("+unescape(t)+"){out+='":"';}else{out+='"}).replace(t.iterate||skip,function(e,t,n,r){if(!t)return"';} } out+='";s+=1;n=n||"value";r=r||"index";t=unescape(t);var i="arr"+s;return"';var "+i+"="+t+";if("+i+" && "+i+".length > 0){var "+n+","+r+"=-1,l"+s+"="+i+".length-1;while("+r+" 0){var "+n+";for( var "+r+" in "+i+"){ if (!"+i+".hasOwnProperty("+r+")) continue; "+n+"="+i+"["+r+"];out+='"}).replace(t.empty||skip,function(e){return"';}}else{if(true){out+='"}).replace(t.evaluate||skip,function(e,t){return"';"+unescape(t)+"out+='"})+"';return out;").replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/\r/g,"\\r").replace(/(\s|;|\}|^|\{)out\+='';/g,"$1").replace(/\+''/g,"").replace(/(\s|;|\}|^|\{)out\+=''\+/g,"$1out+=");if(i&&t.selfcontained){o="String.prototype.encodeHTML=("+encodeHTMLSource.toString()+"());"+o}try{return new Function(t.varname,o)}catch(u){if(typeof console!=="undefined")console.log("Could not create a template function: "+o);throw u}};doT.compile=function(e,t){return doT.template(e,null,t)}})();(function(e){if(typeof define==="function"&&define.amd){define(["jquery"],e)}else{e(jQuery)}})(function(e){function t(t,r){var i,s,o,u=t.nodeName.toLowerCase();if("area"===u){i=t.parentNode;s=i.name;if(!t.href||!s||i.nodeName.toLowerCase()!=="map"){return false}o=e("img[usemap=#"+s+"]")[0];return!!o&&n(o)}return(/input|select|textarea|button|object/.test(u)?!t.disabled:"a"===u?t.href||r:r)&&n(t)}function n(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return e.css(this,"visibility")==="hidden"}).length}e.ui=e.ui||{};e.extend(e.ui,{version:"1.11.0",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}});e.fn.extend({scrollParent:function(){var t=this.css("position"),n=t==="absolute",r=this.parents().filter(function(){var t=e(this);if(n&&t.css("position")==="static"){return false}return/(auto|scroll)/.test(t.css("overflow")+t.css("overflow-y")+t.css("overflow-x"))}).eq(0);return t==="fixed"||!r.length?e(this[0].ownerDocument||document):r},uniqueId:function(){var e=0;return function(){return this.each(function(){if(!this.id){this.id="ui-id-"+ ++e}})}}(),removeUniqueId:function(){return this.each(function(){if(/^ui-id-\d+$/.test(this.id)){e(this).removeAttr("id")}})}});e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(n){return!!e.data(n,t)}}):function(t,n,r){return!!e.data(t,r[3])},focusable:function(n){return t(n,!isNaN(e.attr(n,"tabindex")))},tabbable:function(n){var r=e.attr(n,"tabindex"),i=isNaN(r);return(i||r>=0)&&t(n,!i)}});if(!e("").outerWidth(1).jquery){e.each(["Width","Height"],function(t,n){function o(t,n,i,s){e.each(r,function(){n-=parseFloat(e.css(t,"padding"+this))||0;if(i){n-=parseFloat(e.css(t,"border"+this+"Width"))||0}if(s){n-=parseFloat(e.css(t,"margin"+this))||0}});return n}var r=n==="Width"?["Left","Right"]:["Top","Bottom"],i=n.toLowerCase(),s={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+n]=function(t){if(t===undefined){return s["inner"+n].call(this)}return this.each(function(){e(this).css(i,o(this,t)+"px")})};e.fn["outer"+n]=function(t,r){if(typeof t!=="number"){return s["outer"+n].call(this,t)}return this.each(function(){e(this).css(i,o(this,t,true,r)+"px")})}})}if(!e.fn.addBack){e.fn.addBack=function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}if(e("").data("a-b","a").removeData("a-b").data("a-b")){e.fn.removeData=function(t){return function(n){if(arguments.length){return t.call(this,e.camelCase(n))}else{return t.call(this)}}}(e.fn.removeData)}e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());e.fn.extend({focus:function(t){return function(n,r){return typeof n==="number"?this.each(function(){var t=this;setTimeout(function(){e(t).focus();if(r){r.call(t)}},n)}):t.apply(this,arguments)}}(e.fn.focus),disableSelection:function(){var e="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.bind(e+".ui-disableSelection",function(e){e.preventDefault()})}}(),enableSelection:function(){return this.unbind(".ui-disableSelection")},zIndex:function(t){if(t!==undefined){return this.css("zIndex",t)}if(this.length){var n=e(this[0]),r,i;while(n.length&&n[0]!==document){r=n.css("position");if(r==="absolute"||r==="relative"||r==="fixed"){i=parseInt(n.css("zIndex"),10);if(!isNaN(i)&&i!==0){return i}}n=n.parent()}}return 0}});e.ui.plugin={add:function(t,n,r){var i,s=e.ui[t].prototype;for(i in r){s.plugins[i]=s.plugins[i]||[];s.plugins[i].push([n,r[i]])}},call:function(e,t,n,r){var i,s=e.plugins[t];if(!s){return}if(!r&&(!e.element[0].parentNode||e.element[0].parentNode.nodeType===11)){return}for(i=0;i",options:{disabled:false,create:null},_createWidget:function(t,n){n=e(n||this.defaultElement||this)[0];this.element=e(n);this.uuid=r++;this.eventNamespace="."+this.widgetName+this.uuid;this.options=e.widget.extend({},this.options,this._getCreateOptions(),t);this.bindings=e();this.hoverable=e();this.focusable=e();if(n!==this){e.data(n,this.widgetFullName,this);this._on(true,this.element,{remove:function(e){if(e.target===n){this.destroy()}}});this.document=e(n.style?n.ownerDocument:n.document||n);this.window=e(this.document[0].defaultView||this.document[0].parentWindow)}this._create();this._trigger("create",null,this._getCreateEventData());this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy();this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName));this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled");this.bindings.unbind(this.eventNamespace);this.hoverable.removeClass("ui-state-hover");this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(t,n){var r=t,i,s,o;if(arguments.length===0){return e.widget.extend({},this.options)}if(typeof t==="string"){r={};i=t.split(".");t=i.shift();if(i.length){s=r[t]=e.widget.extend({},this.options[t]);for(o=0;o=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}});(function(){function h(e,t,n){return[parseFloat(e[0])*(l.test(e[0])?t/100:1),parseFloat(e[1])*(l.test(e[1])?n/100:1)]}function p(t,n){return parseInt(e.css(t,n),10)||0}function d(t){var n=t[0];if(n.nodeType===9){return{width:t.width(),height:t.height(),offset:{top:0,left:0}}}if(e.isWindow(n)){return{width:t.width(),height:t.height(),offset:{top:t.scrollTop(),left:t.scrollLeft()}}}if(n.preventDefault){return{width:0,height:0,offset:{top:n.pageY,left:n.pageX}}}return{width:t.outerWidth(),height:t.outerHeight(),offset:t.offset()}}e.ui=e.ui||{};var t,n,r=Math.max,i=Math.abs,s=Math.round,o=/left|center|right/,u=/top|center|bottom/,a=/[\+\-]\d+(\.[\d]+)?%?/,f=/^\w+/,l=/%$/,c=e.fn.position;e.position={scrollbarWidth:function(){if(t!==undefined){return t}var n,r,i=e("
            "),s=i.children()[0];e("body").append(i);n=s.offsetWidth;i.css("overflow","scroll");r=s.offsetWidth;if(n===r){r=i[0].clientWidth}i.remove();return t=n-r},getScrollInfo:function(t){var n=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),r=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),i=n==="scroll"||n==="auto"&&t.width0?"right":"center",vertical:u<0?"top":o>0?"bottom":"middle"};if(vr(i(o),i(u))){l.important="horizontal"}else{l.important="vertical"}t.using.call(this,e,l)}}a.offset(e.extend(k,{using:u}))})};e.ui.position={fit:{left:function(e,t){var n=t.within,i=n.isWindow?n.scrollLeft:n.offset.left,s=n.width,o=e.left-t.collisionPosition.marginLeft,u=i-o,a=o+t.collisionWidth-s-i,f;if(t.collisionWidth>s){if(u>0&&a<=0){f=e.left+u+t.collisionWidth-s-i;e.left+=u-f}else if(a>0&&u<=0){e.left=i}else{if(u>a){e.left=i+s-t.collisionWidth}else{e.left=i}}}else if(u>0){e.left+=u}else if(a>0){e.left-=a}else{e.left=r(e.left-o,e.left)}},top:function(e,t){var n=t.within,i=n.isWindow?n.scrollTop:n.offset.top,s=t.within.height,o=e.top-t.collisionPosition.marginTop,u=i-o,a=o+t.collisionHeight-s-i,f;if(t.collisionHeight>s){if(u>0&&a<=0){f=e.top+u+t.collisionHeight-s-i;e.top+=u-f}else if(a>0&&u<=0){e.top=i}else{if(u>a){e.top=i+s-t.collisionHeight}else{e.top=i}}}else if(u>0){e.top+=u}else if(a>0){e.top-=a}else{e.top=r(e.top-o,e.top)}}},flip:{left:function(e,t){var n=t.within,r=n.offset.left+n.scrollLeft,s=n.width,o=n.isWindow?n.scrollLeft:n.offset.left,u=e.left-t.collisionPosition.marginLeft,a=u-o,f=u+t.collisionWidth-s-o,l=t.my[0]==="left"?-t.elemWidth:t.my[0]==="right"?t.elemWidth:0,c=t.at[0]==="left"?t.targetWidth:t.at[0]==="right"?-t.targetWidth:0,h=-2*t.offset[0],p,d;if(a<0){p=e.left+l+c+h+t.collisionWidth-s-r;if(p<0||p0){d=e.left-t.collisionPosition.marginLeft+l+c+h-o;if(d>0||i(d)a&&(v<0||v0){d=e.top-t.collisionPosition.marginTop+c+h+p-o;if(e.top+c+h+p>f&&(d>0||i(d)10&&s<11;t.innerHTML="";r.removeChild(t)})()})();var a=e.ui.position;e.widget("ui.draggable",e.ui.mouse,{version:"1.11.0",widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false,drag:null,start:null,stop:null},_create:function(){if(this.options.helper==="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))){this.element[0].style.position="relative"}if(this.options.addClasses){this.element.addClass("ui-draggable")}if(this.options.disabled){this.element.addClass("ui-draggable-disabled")}this._setHandleClassName();this._mouseInit()},_setOption:function(e,t){this._super(e,t);if(e==="handle"){this._setHandleClassName()}},_destroy:function(){if((this.helper||this.element).is(".ui-draggable-dragging")){this.destroyOnClear=true;return}this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._removeHandleClassName();this._mouseDestroy()},_mouseCapture:function(t){var n=this.document[0],r=this.options;try{if(n.activeElement&&n.activeElement.nodeName.toLowerCase()!=="body"){e(n.activeElement).blur()}}catch(i){}if(this.helper||r.disabled||e(t.target).closest(".ui-resizable-handle").length>0){return false}this.handle=this._getHandle(t);if(!this.handle){return false}e(r.iframeFix===true?"iframe":r.iframeFix).each(function(){e("
            ").css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(e(this).offset()).appendTo("body")});return true},_mouseStart:function(t){var n=this.options;this.helper=this._createHelper(t);this.helper.addClass("ui-draggable-dragging");this._cacheHelperProportions();if(e.ui.ddmanager){e.ui.ddmanager.current=this}this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offsetParent=this.helper.offsetParent();this.offsetParentCssPosition=this.offsetParent.css("position");this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.offset.scroll=false;e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this.position=this._generatePosition(t,false);this.originalPageX=t.pageX;this.originalPageY=t.pageY;n.cursorAt&&this._adjustOffsetFromHelper(n.cursorAt);this._setContainment();if(this._trigger("start",t)===false){this._clear();return false}this._cacheHelperProportions();if(e.ui.ddmanager&&!n.dropBehaviour){e.ui.ddmanager.prepareOffsets(this,t)}this._mouseDrag(t,true);if(e.ui.ddmanager){e.ui.ddmanager.dragStart(this,t)}return true},_mouseDrag:function(t,n){if(this.offsetParentCssPosition==="fixed"){this.offset.parent=this._getParentOffset()}this.position=this._generatePosition(t,true);this.positionAbs=this._convertPositionTo("absolute");if(!n){var r=this._uiHash();if(this._trigger("drag",t,r)===false){this._mouseUp({});return false}this.position=r.position}this.helper[0].style.left=this.position.left+"px";this.helper[0].style.top=this.position.top+"px";if(e.ui.ddmanager){e.ui.ddmanager.drag(this,t)}return false},_mouseStop:function(t){var n=this,r=false;if(e.ui.ddmanager&&!this.options.dropBehaviour){r=e.ui.ddmanager.drop(this,t)}if(this.dropped){r=this.dropped;this.dropped=false}if(this.options.revert==="invalid"&&!r||this.options.revert==="valid"&&r||this.options.revert===true||e.isFunction(this.options.revert)&&this.options.revert.call(this.element,r)){e(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){if(n._trigger("stop",t)!==false){n._clear()}})}else{if(this._trigger("stop",t)!==false){this._clear()}}return false},_mouseUp:function(t){e("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});if(e.ui.ddmanager){e.ui.ddmanager.dragStop(this,t)}this.element.focus();return e.ui.mouse.prototype._mouseUp.call(this,t)},cancel:function(){if(this.helper.is(".ui-draggable-dragging")){this._mouseUp({})}else{this._clear()}return this},_getHandle:function(t){return this.options.handle?!!e(t.target).closest(this.element.find(this.options.handle)).length:true},_setHandleClassName:function(){this._removeHandleClassName();e(this.options.handle||this.element).addClass("ui-draggable-handle")},_removeHandleClassName:function(){this.element.find(".ui-draggable-handle").addBack().removeClass("ui-draggable-handle")},_createHelper:function(t){var n=this.options,r=e.isFunction(n.helper)?e(n.helper.apply(this.element[0],[t])):n.helper==="clone"?this.element.clone().removeAttr("id"):this.element;if(!r.parents("body").length){r.appendTo(n.appendTo==="parent"?this.element[0].parentNode:n.appendTo)}if(r[0]!==this.element[0]&&!/(fixed|absolute)/.test(r.css("position"))){r.css("position","absolute")}return r},_adjustOffsetFromHelper:function(t){if(typeof t==="string"){t=t.split(" ")}if(e.isArray(t)){t={left:+t[0],top:+t[1]||0}}if("left"in t){this.offset.click.left=t.left+this.margins.left}if("right"in t){this.offset.click.left=this.helperProportions.width-t.right+this.margins.left}if("top"in t){this.offset.click.top=t.top+this.margins.top}if("bottom"in t){this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top}},_isRootNode:function(e){return/(html|body)/i.test(e.tagName)||e===this.document[0]},_getParentOffset:function(){var t=this.offsetParent.offset(),n=this.document[0];if(this.cssPosition==="absolute"&&this.scrollParent[0]!==n&&e.contains(this.scrollParent[0],this.offsetParent[0])){t.left+=this.scrollParent.scrollLeft();t.top+=this.scrollParent.scrollTop()}if(this._isRootNode(this.offsetParent[0])){t={top:0,left:0}}return{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition!=="relative"){return{top:0,left:0}}var e=this.element.position(),t=this._isRootNode(this.scrollParent[0]);return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+(!t?this.scrollParent.scrollTop():0),left:e.left-(parseInt(this.helper.css("left"),10)||0)+(!t?this.scrollParent.scrollLeft():0)}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,n,r,i=this.options,s=this.document[0];this.relative_container=null;if(!i.containment){this.containment=null;return}if(i.containment==="window"){this.containment=[e(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,e(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,e(window).scrollLeft()+e(window).width()-this.helperProportions.width-this.margins.left,e(window).scrollTop()+(e(window).height()||s.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];return}if(i.containment==="document"){this.containment=[0,0,e(s).width()-this.helperProportions.width-this.margins.left,(e(s).height()||s.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];return}if(i.containment.constructor===Array){this.containment=i.containment;return}if(i.containment==="parent"){i.containment=this.helper[0].parentNode}n=e(i.containment);r=n[0];if(!r){return}t=n.css("overflow")!=="hidden";this.containment=[(parseInt(n.css("borderLeftWidth"),10)||0)+(parseInt(n.css("paddingLeft"),10)||0),(parseInt(n.css("borderTopWidth"),10)||0)+(parseInt(n.css("paddingTop"),10)||0),(t?Math.max(r.scrollWidth,r.offsetWidth):r.offsetWidth)-(parseInt(n.css("borderRightWidth"),10)||0)-(parseInt(n.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(t?Math.max(r.scrollHeight,r.offsetHeight):r.offsetHeight)-(parseInt(n.css("borderBottomWidth"),10)||0)-(parseInt(n.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=n},_convertPositionTo:function(e,t){if(!t){t=this.position}var n=e==="absolute"?1:-1,r=this._isRootNode(this.scrollParent[0]);return{top:t.top+this.offset.relative.top*n+this.offset.parent.top*n-(this.cssPosition==="fixed"?-this.offset.scroll.top:r?0:this.offset.scroll.top)*n,left:t.left+this.offset.relative.left*n+this.offset.parent.left*n-(this.cssPosition==="fixed"?-this.offset.scroll.left:r?0:this.offset.scroll.left)*n}},_generatePosition:function(e,t){var n,r,i,s,o=this.options,u=this._isRootNode(this.scrollParent[0]),a=e.pageX,f=e.pageY;if(!u||!this.offset.scroll){this.offset.scroll={top:this.scrollParent.scrollTop(),left:this.scrollParent.scrollLeft()}}if(t){if(this.containment){if(this.relative_container){r=this.relative_container.offset();n=[this.containment[0]+r.left,this.containment[1]+r.top,this.containment[2]+r.left,this.containment[3]+r.top]}else{n=this.containment}if(e.pageX-this.offset.click.leftn[2]){a=n[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>n[3]){f=n[3]+this.offset.click.top}}if(o.grid){i=o.grid[1]?this.originalPageY+Math.round((f-this.originalPageY)/o.grid[1])*o.grid[1]:this.originalPageY;f=n?i-this.offset.click.top>=n[1]||i-this.offset.click.top>n[3]?i:i-this.offset.click.top>=n[1]?i-o.grid[1]:i+o.grid[1]:i;s=o.grid[0]?this.originalPageX+Math.round((a-this.originalPageX)/o.grid[0])*o.grid[0]:this.originalPageX;a=n?s-this.offset.click.left>=n[0]||s-this.offset.click.left>n[2]?s:s-this.offset.click.left>=n[0]?s-o.grid[0]:s+o.grid[0]:s}if(o.axis==="y"){a=this.originalPageX}if(o.axis==="x"){f=this.originalPageY}}return{top:f-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(this.cssPosition==="fixed"?-this.offset.scroll.top:u?0:this.offset.scroll.top),left:a-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(this.cssPosition==="fixed"?-this.offset.scroll.left:u?0:this.offset.scroll.left)}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");if(this.helper[0]!==this.element[0]&&!this.cancelHelperRemoval){this.helper.remove()}this.helper=null;this.cancelHelperRemoval=false;if(this.destroyOnClear){this.destroy()}},_trigger:function(t,n,r){r=r||this._uiHash();e.ui.plugin.call(this,t,[n,r,this],true);if(t==="drag"){this.positionAbs=this._convertPositionTo("absolute")}return e.Widget.prototype._trigger.call(this,t,n,r)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});e.ui.plugin.add("draggable","connectToSortable",{start:function(t,n,r){var i=r.options,s=e.extend({},n,{item:r.element});r.sortables=[];e(i.connectToSortable).each(function(){var n=e(this).sortable("instance");if(n&&!n.options.disabled){r.sortables.push({instance:n,shouldRevert:n.options.revert});n.refreshPositions();n._trigger("activate",t,s)}})},stop:function(t,n,r){var i=e.extend({},n,{item:r.element});e.each(r.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;r.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert){this.instance.options.revert=this.shouldRevert}this.instance._mouseStop(t);this.instance.options.helper=this.instance.options._helper;if(r.options.helper==="original"){this.instance.currentItem.css({top:"auto",left:"auto"})}}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",t,i)}})},drag:function(t,n,r){var i=this;e.each(r.sortables,function(){var s=false,o=this;this.instance.positionAbs=r.positionAbs;this.instance.helperProportions=r.helperProportions;this.instance.offset.click=r.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){s=true;e.each(r.sortables,function(){this.instance.positionAbs=r.positionAbs;this.instance.helperProportions=r.helperProportions;this.instance.offset.click=r.offset.click;if(this!==o&&this.instance._intersectsWith(this.instance.containerCache)&&e.contains(o.instance.element[0],this.instance.element[0])){s=false}return s})}if(s){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=e(i).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return n.helper[0]};t.target=this.instance.currentItem[0];this.instance._mouseCapture(t,true);this.instance._mouseStart(t,true,true);this.instance.offset.click.top=r.offset.click.top;this.instance.offset.click.left=r.offset.click.left;this.instance.offset.parent.left-=r.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=r.offset.parent.top-this.instance.offset.parent.top;r._trigger("toSortable",t);r.dropped=this.instance.element;r.currentItem=r.element;this.instance.fromOutside=r}if(this.instance.currentItem){this.instance._mouseDrag(t)}}else{if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",t,this.instance._uiHash(this.instance));this.instance._mouseStop(t,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();if(this.instance.placeholder){this.instance.placeholder.remove()}r._trigger("fromSortable",t);r.dropped=false}}})}});e.ui.plugin.add("draggable","cursor",{start:function(t,n,r){var i=e("body"),s=r.options;if(i.css("cursor")){s._cursor=i.css("cursor")}i.css("cursor",s.cursor)},stop:function(t,n,r){var i=r.options;if(i._cursor){e("body").css("cursor",i._cursor)}}});e.ui.plugin.add("draggable","opacity",{start:function(t,n,r){var i=e(n.helper),s=r.options;if(i.css("opacity")){s._opacity=i.css("opacity")}i.css("opacity",s.opacity)},stop:function(t,n,r){var i=r.options;if(i._opacity){e(n.helper).css("opacity",i._opacity)}}});e.ui.plugin.add("draggable","scroll",{start:function(e,t,n){if(n.scrollParent[0]!==n.document[0]&&n.scrollParent[0].tagName!=="HTML"){n.overflowOffset=n.scrollParent.offset()}},drag:function(t,n,r){var i=r.options,s=false,o=r.document[0];if(r.scrollParent[0]!==o&&r.scrollParent[0].tagName!=="HTML"){if(!i.axis||i.axis!=="x"){if(r.overflowOffset.top+r.scrollParent[0].offsetHeight-t.pageY=0;h--){a=r.snapElements[h].left;f=a+r.snapElements[h].width;l=r.snapElements[h].top;c=l+r.snapElements[h].height;if(gf+v||bc+v||!e.contains(r.snapElements[h].item.ownerDocument,r.snapElements[h].item)){if(r.snapElements[h].snapping){r.options.snap.release&&r.options.snap.release.call(r.element,t,e.extend(r._uiHash(),{snapItem:r.snapElements[h].item}))}r.snapElements[h].snapping=false;continue}if(d.snapMode!=="inner"){i=Math.abs(l-b)<=v;s=Math.abs(c-y)<=v;o=Math.abs(a-g)<=v;u=Math.abs(f-m)<=v;if(i){n.position.top=r._convertPositionTo("relative",{top:l-r.helperProportions.height,left:0}).top-r.margins.top}if(s){n.position.top=r._convertPositionTo("relative",{top:c,left:0}).top-r.margins.top}if(o){n.position.left=r._convertPositionTo("relative",{top:0,left:a-r.helperProportions.width}).left-r.margins.left}if(u){n.position.left=r._convertPositionTo("relative",{top:0,left:f}).left-r.margins.left}}p=i||s||o||u;if(d.snapMode!=="outer"){i=Math.abs(l-y)<=v;s=Math.abs(c-b)<=v;o=Math.abs(a-m)<=v;u=Math.abs(f-g)<=v;if(i){n.position.top=r._convertPositionTo("relative",{top:l,left:0}).top-r.margins.top}if(s){n.position.top=r._convertPositionTo("relative",{top:c-r.helperProportions.height,left:0}).top-r.margins.top}if(o){n.position.left=r._convertPositionTo("relative",{top:0,left:a}).left-r.margins.left}if(u){n.position.left=r._convertPositionTo("relative",{top:0,left:f-r.helperProportions.width}).left-r.margins.left}}if(!r.snapElements[h].snapping&&(i||s||o||u||p)){r.options.snap.snap&&r.options.snap.snap.call(r.element,t,e.extend(r._uiHash(),{snapItem:r.snapElements[h].item}))}r.snapElements[h].snapping=i||s||o||u||p}}});e.ui.plugin.add("draggable","stack",{start:function(t,n,r){var i,s=r.options,o=e.makeArray(e(s.stack)).sort(function(t,n){return(parseInt(e(t).css("zIndex"),10)||0)-(parseInt(e(n).css("zIndex"),10)||0)});if(!o.length){return}i=parseInt(e(o[0]).css("zIndex"),10)||0;e(o).each(function(t){e(this).css("zIndex",i+t)});this.css("zIndex",i+o.length)}});e.ui.plugin.add("draggable","zIndex",{start:function(t,n,r){var i=e(n.helper),s=r.options;if(i.css("zIndex")){s._zIndex=i.css("zIndex")}i.css("zIndex",s.zIndex)},stop:function(t,n,r){var i=r.options;if(i._zIndex){e(n.helper).css("zIndex",i._zIndex)}}});var f=e.ui.draggable}) \ No newline at end of file diff --git a/nano/js/libraries.min.js b/nano/js/libraries.min.js new file mode 100644 index 00000000..a2cbbad8 --- /dev/null +++ b/nano/js/libraries.min.js @@ -0,0 +1,50 @@ +/*! jQuery v1.11.3 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */ +!function(e,t){"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){function n(e){var t="length"in e&&e.length,n=it.type(e);return"function"===n||it.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e}function r(e,t,n){if(it.isFunction(t))return it.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return it.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(ft.test(t))return it.filter(t,e,n);t=it.filter(t,e)}return it.grep(e,function(e){return it.inArray(e,t)>=0!==n})}function i(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function o(e){var t=xt[e]={};return it.each(e.match(bt)||[],function(e,n){t[n]=!0}),t}function a(){ht.addEventListener?(ht.removeEventListener("DOMContentLoaded",s,!1),e.removeEventListener("load",s,!1)):(ht.detachEvent("onreadystatechange",s),e.detachEvent("onload",s))}function s(){(ht.addEventListener||"load"===event.type||"complete"===ht.readyState)&&(a(),it.ready())}function l(e,t,n){if(void 0===n&&1===e.nodeType){var r="data-"+t.replace(Et,"-$1").toLowerCase();if(n=e.getAttribute(r),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:Nt.test(n)?it.parseJSON(n):n}catch(i){}it.data(e,t,n)}else n=void 0}return n}function u(e){var t;for(t in e)if(("data"!==t||!it.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function c(e,t,n,r){if(it.acceptData(e)){var i,o,a=it.expando,s=e.nodeType,l=s?it.cache:e,u=s?e[a]:e[a]&&a;if(u&&l[u]&&(r||l[u].data)||void 0!==n||"string"!=typeof t)return u||(u=s?e[a]=J.pop()||it.guid++:a),l[u]||(l[u]=s?{}:{toJSON:it.noop}),("object"==typeof t||"function"==typeof t)&&(r?l[u]=it.extend(l[u],t):l[u].data=it.extend(l[u].data,t)),o=l[u],r||(o.data||(o.data={}),o=o.data),void 0!==n&&(o[it.camelCase(t)]=n),"string"==typeof t?(i=o[t],null==i&&(i=o[it.camelCase(t)])):i=o,i}}function d(e,t,n){if(it.acceptData(e)){var r,i,o=e.nodeType,a=o?it.cache:e,s=o?e[it.expando]:it.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){it.isArray(t)?t=t.concat(it.map(t,it.camelCase)):t in r?t=[t]:(t=it.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;for(;i--;)delete r[t[i]];if(n?!u(r):!it.isEmptyObject(r))return}(n||(delete a[s].data,u(a[s])))&&(o?it.cleanData([e],!0):nt.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}function f(){return!0}function p(){return!1}function h(){try{return ht.activeElement}catch(e){}}function m(e){var t=Ft.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function g(e,t){var n,r,i=0,o=typeof e.getElementsByTagName!==Ct?e.getElementsByTagName(t||"*"):typeof e.querySelectorAll!==Ct?e.querySelectorAll(t||"*"):void 0;if(!o)for(o=[],n=e.childNodes||e;null!=(r=n[i]);i++)!t||it.nodeName(r,t)?o.push(r):it.merge(o,g(r,t));return void 0===t||t&&it.nodeName(e,t)?it.merge([e],o):o}function v(e){jt.test(e.type)&&(e.defaultChecked=e.checked)}function y(e,t){return it.nodeName(e,"table")&&it.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function b(e){return e.type=(null!==it.find.attr(e,"type"))+"/"+e.type,e}function x(e){var t=Vt.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function w(e,t){for(var n,r=0;null!=(n=e[r]);r++)it._data(n,"globalEval",!t||it._data(t[r],"globalEval"))}function T(e,t){if(1===t.nodeType&&it.hasData(e)){var n,r,i,o=it._data(e),a=it._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)it.event.add(t,n,s[n][r])}a.data&&(a.data=it.extend({},a.data))}}function C(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!nt.noCloneEvent&&t[it.expando]){i=it._data(t);for(r in i.events)it.removeEvent(t,r,i.handle);t.removeAttribute(it.expando)}"script"===n&&t.text!==e.text?(b(t).text=e.text,x(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),nt.html5Clone&&e.innerHTML&&!it.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&jt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}function N(t,n){var r,i=it(n.createElement(t)).appendTo(n.body),o=e.getDefaultComputedStyle&&(r=e.getDefaultComputedStyle(i[0]))?r.display:it.css(i[0],"display");return i.detach(),o}function E(e){var t=ht,n=Zt[e];return n||(n=N(e,t),"none"!==n&&n||(Kt=(Kt||it("